summaryrefslogtreecommitdiffstats
path: root/qemu/hw
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/hw')
-rw-r--r--qemu/hw/9pfs/9p-handle.c709
-rw-r--r--qemu/hw/9pfs/9p-local.c1282
-rw-r--r--qemu/hw/9pfs/9p-posix-acl.c184
-rw-r--r--qemu/hw/9pfs/9p-proxy.c1220
-rw-r--r--qemu/hw/9pfs/9p-proxy.h95
-rw-r--r--qemu/hw/9pfs/9p-synth.c574
-rw-r--r--qemu/hw/9pfs/9p-synth.h51
-rw-r--r--qemu/hw/9pfs/9p-xattr-user.c127
-rw-r--r--qemu/hw/9pfs/9p-xattr.c164
-rw-r--r--qemu/hw/9pfs/9p-xattr.h120
-rw-r--r--qemu/hw/9pfs/9p.c3380
-rw-r--r--qemu/hw/9pfs/9p.h324
-rw-r--r--qemu/hw/9pfs/Makefile.objs9
-rw-r--r--qemu/hw/9pfs/codir.c169
-rw-r--r--qemu/hw/9pfs/cofile.c276
-rw-r--r--qemu/hw/9pfs/cofs.c365
-rw-r--r--qemu/hw/9pfs/coth.c42
-rw-r--r--qemu/hw/9pfs/coth.h99
-rw-r--r--qemu/hw/9pfs/coxattr.c108
-rw-r--r--qemu/hw/9pfs/virtio-9p-device.c211
-rw-r--r--qemu/hw/9pfs/virtio-9p.h31
-rw-r--r--qemu/hw/Makefile.objs38
-rw-r--r--qemu/hw/acpi/Makefile.objs8
-rw-r--r--qemu/hw/acpi/acpi_interface.c16
-rw-r--r--qemu/hw/acpi/aml-build.c1565
-rw-r--r--qemu/hw/acpi/bios-linker-loader.c240
-rw-r--r--qemu/hw/acpi/core.c717
-rw-r--r--qemu/hw/acpi/cpu_hotplug.c79
-rw-r--r--qemu/hw/acpi/cpu_hotplug_acpi_table.c136
-rw-r--r--qemu/hw/acpi/ich9.c477
-rw-r--r--qemu/hw/acpi/memory_hotplug.c312
-rw-r--r--qemu/hw/acpi/memory_hotplug_acpi_table.c262
-rw-r--r--qemu/hw/acpi/nvdimm.c706
-rw-r--r--qemu/hw/acpi/pcihp.c336
-rw-r--r--qemu/hw/acpi/piix4.c645
-rw-r--r--qemu/hw/acpi/tco.c265
-rw-r--r--qemu/hw/alpha/Makefile.objs1
-rw-r--r--qemu/hw/alpha/alpha_sys.h21
-rw-r--r--qemu/hw/alpha/dp264.c184
-rw-r--r--qemu/hw/alpha/pci.c94
-rw-r--r--qemu/hw/alpha/typhoon.c959
-rw-r--r--qemu/hw/arm/Makefile.objs19
-rw-r--r--qemu/hw/arm/allwinner-a10.c142
-rw-r--r--qemu/hw/arm/armv7m.c265
-rw-r--r--qemu/hw/arm/ast2400.c140
-rw-r--r--qemu/hw/arm/bcm2835_peripherals.c312
-rw-r--r--qemu/hw/arm/bcm2836.c184
-rw-r--r--qemu/hw/arm/boot.c994
-rw-r--r--qemu/hw/arm/collie.c68
-rw-r--r--qemu/hw/arm/cubieboard.c86
-rw-r--r--qemu/hw/arm/digic.c123
-rw-r--r--qemu/hw/arm/digic_boards.c160
-rw-r--r--qemu/hw/arm/exynos4210.c378
-rw-r--r--qemu/hw/arm/exynos4_boards.c186
-rw-r--r--qemu/hw/arm/fsl-imx25.c313
-rw-r--r--qemu/hw/arm/fsl-imx31.c287
-rw-r--r--qemu/hw/arm/gumstix.c159
-rw-r--r--qemu/hw/arm/highbank.c441
-rw-r--r--qemu/hw/arm/imx25_pdk.c153
-rw-r--r--qemu/hw/arm/integratorcp.c674
-rw-r--r--qemu/hw/arm/kzm.c147
-rw-r--r--qemu/hw/arm/mainstone.c199
-rw-r--r--qemu/hw/arm/musicpal.c1751
-rw-r--r--qemu/hw/arm/netduino2.c49
-rw-r--r--qemu/hw/arm/nseries.c1454
-rw-r--r--qemu/hw/arm/omap1.c4086
-rw-r--r--qemu/hw/arm/omap2.c2691
-rw-r--r--qemu/hw/arm/omap_sx1.c256
-rw-r--r--qemu/hw/arm/palm.c280
-rw-r--r--qemu/hw/arm/palmetto-bmc.c68
-rw-r--r--qemu/hw/arm/pxa2xx.c2358
-rw-r--r--qemu/hw/arm/pxa2xx_gpio.c357
-rw-r--r--qemu/hw/arm/pxa2xx_pic.c340
-rw-r--r--qemu/hw/arm/raspi.c172
-rw-r--r--qemu/hw/arm/realview.c463
-rw-r--r--qemu/hw/arm/spitz.c1178
-rw-r--r--qemu/hw/arm/stellaris.c1475
-rw-r--r--qemu/hw/arm/stm32f205_soc.c165
-rw-r--r--qemu/hw/arm/strongarm.c1662
-rw-r--r--qemu/hw/arm/strongarm.h68
-rw-r--r--qemu/hw/arm/sysbus-fdt.c542
-rw-r--r--qemu/hw/arm/tosa.c303
-rw-r--r--qemu/hw/arm/versatilepb.c448
-rw-r--r--qemu/hw/arm/vexpress.c806
-rw-r--r--qemu/hw/arm/virt-acpi-build.c755
-rw-r--r--qemu/hw/arm/virt.c1435
-rw-r--r--qemu/hw/arm/xilinx_zynq.c318
-rw-r--r--qemu/hw/arm/xlnx-ep108.c115
-rw-r--r--qemu/hw/arm/xlnx-zynqmp.c403
-rw-r--r--qemu/hw/arm/z2.c382
-rw-r--r--qemu/hw/audio/Makefile.objs18
-rw-r--r--qemu/hw/audio/ac97.c1431
-rw-r--r--qemu/hw/audio/adlib.c386
-rw-r--r--qemu/hw/audio/cs4231.c187
-rw-r--r--qemu/hw/audio/cs4231a.c715
-rw-r--r--qemu/hw/audio/es1370.c1080
-rw-r--r--qemu/hw/audio/fmopl.c1391
-rw-r--r--qemu/hw/audio/fmopl.h174
-rw-r--r--qemu/hw/audio/gus.c321
-rw-r--r--qemu/hw/audio/gusemu.h104
-rw-r--r--qemu/hw/audio/gusemu_hal.c555
-rw-r--r--qemu/hw/audio/gusemu_mixer.c241
-rw-r--r--qemu/hw/audio/gustate.h132
-rw-r--r--qemu/hw/audio/hda-codec-common.h456
-rw-r--r--qemu/hw/audio/hda-codec.c732
-rw-r--r--qemu/hw/audio/intel-hda-defs.h717
-rw-r--r--qemu/hw/audio/intel-hda.c1344
-rw-r--r--qemu/hw/audio/intel-hda.h72
-rw-r--r--qemu/hw/audio/lm4549.c335
-rw-r--r--qemu/hw/audio/lm4549.h43
-rw-r--r--qemu/hw/audio/marvell_88w8618.c307
-rw-r--r--qemu/hw/audio/milkymist-ac97.c349
-rw-r--r--qemu/hw/audio/pcspk.c214
-rw-r--r--qemu/hw/audio/pl041.c650
-rw-r--r--qemu/hw/audio/pl041.h135
-rw-r--r--qemu/hw/audio/pl041.hx81
-rw-r--r--qemu/hw/audio/sb16.c1436
-rw-r--r--qemu/hw/audio/wm8750.c723
-rw-r--r--qemu/hw/block/Makefile.objs15
-rw-r--r--qemu/hw/block/block.c93
-rw-r--r--qemu/hw/block/cdrom.c156
-rw-r--r--qemu/hw/block/dataplane/Makefile.objs1
-rw-r--r--qemu/hw/block/dataplane/virtio-blk.c290
-rw-r--r--qemu/hw/block/dataplane/virtio-blk.h31
-rw-r--r--qemu/hw/block/ecc.c91
-rw-r--r--qemu/hw/block/fdc.c2738
-rw-r--r--qemu/hw/block/hd-geometry.c166
-rw-r--r--qemu/hw/block/m25p80.c1005
-rw-r--r--qemu/hw/block/nand.c801
-rw-r--r--qemu/hw/block/nvme.c942
-rw-r--r--qemu/hw/block/nvme.h713
-rw-r--r--qemu/hw/block/onenand.c850
-rw-r--r--qemu/hw/block/pflash_cfi01.c970
-rw-r--r--qemu/hw/block/pflash_cfi02.c797
-rw-r--r--qemu/hw/block/tc58128.c181
-rw-r--r--qemu/hw/block/virtio-blk.c980
-rw-r--r--qemu/hw/block/xen_blkif.h119
-rw-r--r--qemu/hw/block/xen_disk.c1121
-rw-r--r--qemu/hw/bt/Makefile.objs3
-rw-r--r--qemu/hw/bt/core.c145
-rw-r--r--qemu/hw/bt/hci-csr.c455
-rw-r--r--qemu/hw/bt/hci.c2272
-rw-r--r--qemu/hw/bt/hid.c554
-rw-r--r--qemu/hw/bt/l2cap.c1366
-rw-r--r--qemu/hw/bt/sdp.c979
-rw-r--r--qemu/hw/char/Makefile.objs30
-rw-r--r--qemu/hw/char/bcm2835_aux.c316
-rw-r--r--qemu/hw/char/cadence_uart.c540
-rw-r--r--qemu/hw/char/debugcon.c142
-rw-r--r--qemu/hw/char/digic-uart.c198
-rw-r--r--qemu/hw/char/escc.c1056
-rw-r--r--qemu/hw/char/etraxfs_ser.c254
-rw-r--r--qemu/hw/char/exynos4210_uart.c678
-rw-r--r--qemu/hw/char/grlib_apbuart.c299
-rw-r--r--qemu/hw/char/imx_serial.c367
-rw-r--r--qemu/hw/char/ipoctal232.c604
-rw-r--r--qemu/hw/char/lm32_juart.c165
-rw-r--r--qemu/hw/char/lm32_uart.c305
-rw-r--r--qemu/hw/char/mcf_uart.c308
-rw-r--r--qemu/hw/char/milkymist-uart.c256
-rw-r--r--qemu/hw/char/omap_uart.c188
-rw-r--r--qemu/hw/char/parallel.c645
-rw-r--r--qemu/hw/char/pl011.c343
-rw-r--r--qemu/hw/char/sclpconsole-lm.c384
-rw-r--r--qemu/hw/char/sclpconsole.c286
-rw-r--r--qemu/hw/char/serial-isa.c147
-rw-r--r--qemu/hw/char/serial-pci.c276
-rw-r--r--qemu/hw/char/serial.c966
-rw-r--r--qemu/hw/char/sh_serial.c409
-rw-r--r--qemu/hw/char/spapr_vty.c249
-rw-r--r--qemu/hw/char/stm32f2xx_usart.c233
-rw-r--r--qemu/hw/char/virtio-console.c218
-rw-r--r--qemu/hw/char/virtio-serial-bus.c1149
-rw-r--r--qemu/hw/char/xen_console.c297
-rw-r--r--qemu/hw/char/xilinx_uartlite.c249
-rw-r--r--qemu/hw/core/Makefile.objs17
-rw-r--r--qemu/hw/core/empty_slot.c103
-rw-r--r--qemu/hw/core/fw-path-provider.c53
-rw-r--r--qemu/hw/core/hotplug.c60
-rw-r--r--qemu/hw/core/irq.c159
-rw-r--r--qemu/hw/core/loader.c1190
-rw-r--r--qemu/hw/core/machine.c570
-rw-r--r--qemu/hw/core/nmi.c106
-rw-r--r--qemu/hw/core/null-machine.c30
-rw-r--r--qemu/hw/core/platform-bus.c252
-rw-r--r--qemu/hw/core/ptimer.c232
-rw-r--r--qemu/hw/core/qdev-properties-system.c415
-rw-r--r--qemu/hw/core/qdev-properties.c1131
-rw-r--r--qemu/hw/core/qdev.c1370
-rw-r--r--qemu/hw/core/stream.c33
-rw-r--r--qemu/hw/core/sysbus.c370
-rw-r--r--qemu/hw/core/uboot_image.h158
-rw-r--r--qemu/hw/cpu/Makefile.objs5
-rw-r--r--qemu/hw/cpu/a15mpcore.c158
-rw-r--r--qemu/hw/cpu/a9mpcore.c192
-rw-r--r--qemu/hw/cpu/arm11mpcore.c174
-rw-r--r--qemu/hw/cpu/realview_mpcore.c141
-rw-r--r--qemu/hw/cris/Makefile.objs2
-rw-r--r--qemu/hw/cris/axis_dev88.c365
-rw-r--r--qemu/hw/cris/boot.c102
-rw-r--r--qemu/hw/cris/boot.h15
-rw-r--r--qemu/hw/display/Makefile.objs45
-rw-r--r--qemu/hw/display/ads7846.c178
-rw-r--r--qemu/hw/display/bcm2835_fb.c425
-rw-r--r--qemu/hw/display/blizzard.c987
-rw-r--r--qemu/hw/display/blizzard_template.h146
-rw-r--r--qemu/hw/display/cg3.c399
-rw-r--r--qemu/hw/display/cirrus_vga.c3091
-rw-r--r--qemu/hw/display/cirrus_vga_rop.h207
-rw-r--r--qemu/hw/display/cirrus_vga_rop2.h281
-rw-r--r--qemu/hw/display/exynos4210_fimd.c1952
-rw-r--r--qemu/hw/display/framebuffer.c125
-rw-r--r--qemu/hw/display/framebuffer.h65
-rw-r--r--qemu/hw/display/g364fb.c559
-rw-r--r--qemu/hw/display/jazz_led.c314
-rw-r--r--qemu/hw/display/milkymist-tmu2.c495
-rw-r--r--qemu/hw/display/milkymist-vgafb.c354
-rw-r--r--qemu/hw/display/milkymist-vgafb_template.h74
-rw-r--r--qemu/hw/display/omap_dss.c1091
-rw-r--r--qemu/hw/display/omap_lcd_template.h175
-rw-r--r--qemu/hw/display/omap_lcdc.c420
-rw-r--r--qemu/hw/display/pl110.c539
-rw-r--r--qemu/hw/display/pl110_template.h399
-rw-r--r--qemu/hw/display/pxa2xx_lcd.c1065
-rw-r--r--qemu/hw/display/pxa2xx_template.h447
-rw-r--r--qemu/hw/display/qxl-logger.c276
-rw-r--r--qemu/hw/display/qxl-render.c298
-rw-r--r--qemu/hw/display/qxl.c2359
-rw-r--r--qemu/hw/display/qxl.h174
-rw-r--r--qemu/hw/display/sm501.c1458
-rw-r--r--qemu/hw/display/sm501_template.h145
-rw-r--r--qemu/hw/display/ssd0303.c331
-rw-r--r--qemu/hw/display/ssd0323.c402
-rw-r--r--qemu/hw/display/tc6393xb.c598
-rw-r--r--qemu/hw/display/tc6393xb_template.h72
-rw-r--r--qemu/hw/display/tcx.c1106
-rw-r--r--qemu/hw/display/vga-helpers.h439
-rw-r--r--qemu/hw/display/vga-isa-mm.c143
-rw-r--r--qemu/hw/display/vga-isa.c106
-rw-r--r--qemu/hw/display/vga-pci.c387
-rw-r--r--qemu/hw/display/vga.c2289
-rw-r--r--qemu/hw/display/vga.h159
-rw-r--r--qemu/hw/display/vga_int.h227
-rw-r--r--qemu/hw/display/virtio-gpu-3d.c606
-rw-r--r--qemu/hw/display/virtio-gpu-pci.c77
-rw-r--r--qemu/hw/display/virtio-gpu.c1087
-rw-r--r--qemu/hw/display/virtio-vga.c193
-rw-r--r--qemu/hw/display/vmware_vga.c1370
-rw-r--r--qemu/hw/display/xenfb.c1004
-rw-r--r--qemu/hw/dma/Makefile.objs14
-rw-r--r--qemu/hw/dma/bcm2835_dma.c409
-rw-r--r--qemu/hw/dma/etraxfs_dma.c783
-rw-r--r--qemu/hw/dma/i82374.c156
-rw-r--r--qemu/hw/dma/i8257.c643
-rw-r--r--qemu/hw/dma/omap_dma.c2103
-rw-r--r--qemu/hw/dma/pl080.c423
-rw-r--r--qemu/hw/dma/pl330.c1668
-rw-r--r--qemu/hw/dma/puv3_dma.c114
-rw-r--r--qemu/hw/dma/pxa2xx_dma.c576
-rw-r--r--qemu/hw/dma/rc4030.c842
-rw-r--r--qemu/hw/dma/soc_dma.c362
-rw-r--r--qemu/hw/dma/sparc32_dma.c323
-rw-r--r--qemu/hw/dma/sun4m_iommu.c393
-rw-r--r--qemu/hw/dma/xilinx_axidma.c666
-rw-r--r--qemu/hw/gpio/Makefile.objs9
-rw-r--r--qemu/hw/gpio/gpio_key.c104
-rw-r--r--qemu/hw/gpio/imx_gpio.c350
-rw-r--r--qemu/hw/gpio/max7310.c218
-rw-r--r--qemu/hw/gpio/mpc8xxx.c218
-rw-r--r--qemu/hw/gpio/omap_gpio.c822
-rw-r--r--qemu/hw/gpio/pl061.c403
-rw-r--r--qemu/hw/gpio/puv3_gpio.c146
-rw-r--r--qemu/hw/gpio/zaurus.c302
-rw-r--r--qemu/hw/i2c/Makefile.objs8
-rw-r--r--qemu/hw/i2c/bitbang_i2c.c253
-rw-r--r--qemu/hw/i2c/bitbang_i2c.h14
-rw-r--r--qemu/hw/i2c/core.c246
-rw-r--r--qemu/hw/i2c/exynos4210_i2c.c337
-rw-r--r--qemu/hw/i2c/imx_i2c.c337
-rw-r--r--qemu/hw/i2c/omap_i2c.c509
-rw-r--r--qemu/hw/i2c/pm_smbus.c228
-rw-r--r--qemu/hw/i2c/smbus.c362
-rw-r--r--qemu/hw/i2c/smbus_eeprom.c159
-rw-r--r--qemu/hw/i2c/smbus_ich9.c130
-rw-r--r--qemu/hw/i2c/versatile_i2c.c114
-rw-r--r--qemu/hw/i386/Makefile.objs10
-rw-r--r--qemu/hw/i386/acpi-build.c2950
-rw-r--r--qemu/hw/i386/acpi-build.h7
-rw-r--r--qemu/hw/i386/intel_iommu.c2057
-rw-r--r--qemu/hw/i386/intel_iommu_internal.h391
-rw-r--r--qemu/hw/i386/kvm/Makefile.objs1
-rw-r--r--qemu/hw/i386/kvm/apic.c219
-rw-r--r--qemu/hw/i386/kvm/clock.c196
-rw-r--r--qemu/hw/i386/kvm/i8254.c337
-rw-r--r--qemu/hw/i386/kvm/i8259.c163
-rw-r--r--qemu/hw/i386/kvm/ioapic.c179
-rw-r--r--qemu/hw/i386/kvm/pci-assign.c1898
-rw-r--r--qemu/hw/i386/kvmvapic.c866
-rw-r--r--qemu/hw/i386/multiboot.c375
-rw-r--r--qemu/hw/i386/multiboot.h14
-rw-r--r--qemu/hw/i386/pc.c2017
-rw-r--r--qemu/hw/i386/pc_piix.c1062
-rw-r--r--qemu/hw/i386/pc_q35.c318
-rw-r--r--qemu/hw/i386/pc_sysfw.c253
-rw-r--r--qemu/hw/i386/pci-assign-load-rom.c85
-rw-r--r--qemu/hw/i386/xen/Makefile.objs1
-rw-r--r--qemu/hw/i386/xen/xen_apic.c95
-rw-r--r--qemu/hw/i386/xen/xen_platform.c455
-rw-r--r--qemu/hw/i386/xen/xen_pvdevice.c137
-rw-r--r--qemu/hw/ide/Makefile.objs12
-rw-r--r--qemu/hw/ide/ahci.c1832
-rw-r--r--qemu/hw/ide/ahci.h405
-rw-r--r--qemu/hw/ide/atapi.c1367
-rw-r--r--qemu/hw/ide/cmd646.c435
-rw-r--r--qemu/hw/ide/core.c2842
-rw-r--r--qemu/hw/ide/ich.c191
-rw-r--r--qemu/hw/ide/internal.h635
-rw-r--r--qemu/hw/ide/isa.c135
-rw-r--r--qemu/hw/ide/macio.c642
-rw-r--r--qemu/hw/ide/microdrive.c638
-rw-r--r--qemu/hw/ide/mmio.c184
-rw-r--r--qemu/hw/ide/pci.c468
-rw-r--r--qemu/hw/ide/pci.h76
-rw-r--r--qemu/hw/ide/piix.c295
-rw-r--r--qemu/hw/ide/qdev.c370
-rw-r--r--qemu/hw/ide/via.c236
-rw-r--r--qemu/hw/input/Makefile.objs19
-rw-r--r--qemu/hw/input/adb.c598
-rw-r--r--qemu/hw/input/hid.c618
-rw-r--r--qemu/hw/input/lm832x.c525
-rw-r--r--qemu/hw/input/milkymist-softusb.c319
-rw-r--r--qemu/hw/input/pckbd.c595
-rw-r--r--qemu/hw/input/pl050.c206
-rw-r--r--qemu/hw/input/ps2.c813
-rw-r--r--qemu/hw/input/pxa2xx_keypad.c335
-rw-r--r--qemu/hw/input/stellaris_input.c88
-rw-r--r--qemu/hw/input/tsc2005.c595
-rw-r--r--qemu/hw/input/tsc210x.c1273
-rw-r--r--qemu/hw/input/virtio-input-hid.c525
-rw-r--r--qemu/hw/input/virtio-input-host.c257
-rw-r--r--qemu/hw/input/virtio-input.c343
-rw-r--r--qemu/hw/input/vmmouse.c304
-rw-r--r--qemu/hw/intc/Makefile.objs34
-rw-r--r--qemu/hw/intc/allwinner-a10-pic.c213
-rw-r--r--qemu/hw/intc/apic.c906
-rw-r--r--qemu/hw/intc/apic_common.c451
-rw-r--r--qemu/hw/intc/arm_gic.c1385
-rw-r--r--qemu/hw/intc/arm_gic_common.c290
-rw-r--r--qemu/hw/intc/arm_gic_kvm.c607
-rw-r--r--qemu/hw/intc/arm_gicv2m.c194
-rw-r--r--qemu/hw/intc/arm_gicv3_common.c142
-rw-r--r--qemu/hw/intc/arm_gicv3_kvm.c151
-rw-r--r--qemu/hw/intc/armv7m_nvic.c581
-rw-r--r--qemu/hw/intc/aspeed_vic.c339
-rw-r--r--qemu/hw/intc/bcm2835_ic.c237
-rw-r--r--qemu/hw/intc/bcm2836_control.c304
-rw-r--r--qemu/hw/intc/etraxfs_pic.c194
-rw-r--r--qemu/hw/intc/exynos4210_combiner.c459
-rw-r--r--qemu/hw/intc/exynos4210_gic.c472
-rw-r--r--qemu/hw/intc/gic_internal.h103
-rw-r--r--qemu/hw/intc/grlib_irqmp.c375
-rw-r--r--qemu/hw/intc/heathrow_pic.c214
-rw-r--r--qemu/hw/intc/i8259.c524
-rw-r--r--qemu/hw/intc/i8259_common.c163
-rw-r--r--qemu/hw/intc/imx_avic.c363
-rw-r--r--qemu/hw/intc/ioapic.c338
-rw-r--r--qemu/hw/intc/ioapic_common.c180
-rw-r--r--qemu/hw/intc/lm32_pic.c203
-rw-r--r--qemu/hw/intc/omap_intc.c672
-rw-r--r--qemu/hw/intc/openpic.c1664
-rw-r--r--qemu/hw/intc/openpic_kvm.c296
-rw-r--r--qemu/hw/intc/pl190.c293
-rw-r--r--qemu/hw/intc/puv3_intc.c141
-rw-r--r--qemu/hw/intc/realview_gic.c89
-rw-r--r--qemu/hw/intc/s390_flic.c100
-rw-r--r--qemu/hw/intc/s390_flic_kvm.c435
-rw-r--r--qemu/hw/intc/sh_intc.c515
-rw-r--r--qemu/hw/intc/slavio_intctl.c472
-rw-r--r--qemu/hw/intc/vgic_common.h35
-rw-r--r--qemu/hw/intc/xics.c1093
-rw-r--r--qemu/hw/intc/xics_kvm.c512
-rw-r--r--qemu/hw/intc/xilinx_intc.c202
-rw-r--r--qemu/hw/ipack/Makefile.objs2
-rw-r--r--qemu/hw/ipack/ipack.c121
-rw-r--r--qemu/hw/ipack/tpci200.c656
-rw-r--r--qemu/hw/ipmi/Makefile.objs5
-rw-r--r--qemu/hw/ipmi/ipmi.c151
-rw-r--r--qemu/hw/ipmi/ipmi_bmc_extern.c519
-rw-r--r--qemu/hw/ipmi/ipmi_bmc_sim.c1810
-rw-r--r--qemu/hw/ipmi/isa_ipmi_bt.c530
-rw-r--r--qemu/hw/ipmi/isa_ipmi_kcs.c495
-rw-r--r--qemu/hw/isa/Makefile.objs8
-rw-r--r--qemu/hw/isa/apm.c103
-rw-r--r--qemu/hw/isa/i82378.c148
-rw-r--r--qemu/hw/isa/isa-bus.c310
-rw-r--r--qemu/hw/isa/lpc_ich9.c752
-rw-r--r--qemu/hw/isa/pc87312.c404
-rw-r--r--qemu/hw/isa/piix4.c142
-rw-r--r--qemu/hw/isa/vt82c686.c515
-rw-r--r--qemu/hw/lm32/Makefile.objs3
-rw-r--r--qemu/hw/lm32/lm32.h29
-rw-r--r--qemu/hw/lm32/lm32_boards.c334
-rw-r--r--qemu/hw/lm32/lm32_hwsetup.h180
-rw-r--r--qemu/hw/lm32/milkymist-hw.h208
-rw-r--r--qemu/hw/lm32/milkymist.c223
-rw-r--r--qemu/hw/m68k/Makefile.objs4
-rw-r--r--qemu/hw/m68k/an5206.c104
-rw-r--r--qemu/hw/m68k/dummy_m68k.c84
-rw-r--r--qemu/hw/m68k/mcf5206.c551
-rw-r--r--qemu/hw/m68k/mcf5208.c308
-rw-r--r--qemu/hw/m68k/mcf_intc.c171
-rw-r--r--qemu/hw/mem/Makefile.objs2
-rw-r--r--qemu/hw/mem/nvdimm.c47
-rw-r--r--qemu/hw/mem/pc-dimm.c447
-rw-r--r--qemu/hw/microblaze/Makefile.objs3
-rw-r--r--qemu/hw/microblaze/boot.c215
-rw-r--r--qemu/hw/microblaze/boot.h12
-rw-r--r--qemu/hw/microblaze/petalogix_ml605_mmu.c221
-rw-r--r--qemu/hw/microblaze/petalogix_s3adsp1800_mmu.c139
-rw-r--r--qemu/hw/mips/Makefile.objs6
-rw-r--r--qemu/hw/mips/addr.c40
-rw-r--r--qemu/hw/mips/cps.c180
-rw-r--r--qemu/hw/mips/cputimer.c163
-rw-r--r--qemu/hw/mips/gt64xxx_pci.c1259
-rw-r--r--qemu/hw/mips/mips_fulong2e.c392
-rw-r--r--qemu/hw/mips/mips_int.c79
-rw-r--r--qemu/hw/mips/mips_jazz.c391
-rw-r--r--qemu/hw/mips/mips_malta.c1270
-rw-r--r--qemu/hw/mips/mips_mipssim.c244
-rw-r--r--qemu/hw/mips/mips_r4k.c311
-rw-r--r--qemu/hw/misc/Makefile.objs52
-rw-r--r--qemu/hw/misc/a9scu.c153
-rw-r--r--qemu/hw/misc/applesmc.c280
-rw-r--r--qemu/hw/misc/arm11scu.c101
-rw-r--r--qemu/hw/misc/arm_integrator_debug.c100
-rw-r--r--qemu/hw/misc/arm_l2x0.c199
-rw-r--r--qemu/hw/misc/arm_sysctl.c658
-rw-r--r--qemu/hw/misc/bcm2835_mbox.c335
-rw-r--r--qemu/hw/misc/bcm2835_property.c424
-rw-r--r--qemu/hw/misc/cbus.c619
-rw-r--r--qemu/hw/misc/debugexit.c77
-rw-r--r--qemu/hw/misc/eccmemctl.c345
-rw-r--r--qemu/hw/misc/edu.c407
-rw-r--r--qemu/hw/misc/exynos4210_pmu.c503
-rw-r--r--qemu/hw/misc/hyperv_testdev.c168
-rw-r--r--qemu/hw/misc/imx25_ccm.c317
-rw-r--r--qemu/hw/misc/imx31_ccm.c344
-rw-r--r--qemu/hw/misc/imx6_ccm.c774
-rw-r--r--qemu/hw/misc/imx_ccm.c85
-rw-r--r--qemu/hw/misc/ivshmem.c1323
-rw-r--r--qemu/hw/misc/macio/Makefile.objs3
-rw-r--r--qemu/hw/misc/macio/cuda.c964
-rw-r--r--qemu/hw/misc/macio/mac_dbdma.c820
-rw-r--r--qemu/hw/misc/macio/macio.c449
-rw-r--r--qemu/hw/misc/max111x.c215
-rw-r--r--qemu/hw/misc/milkymist-hpdmc.c175
-rw-r--r--qemu/hw/misc/milkymist-pfpu.c549
-rw-r--r--qemu/hw/misc/mips_cmgcr.c160
-rw-r--r--qemu/hw/misc/mips_cpc.c177
-rw-r--r--qemu/hw/misc/mips_itu.c521
-rw-r--r--qemu/hw/misc/mst_fpga.c267
-rw-r--r--qemu/hw/misc/omap_clk.c1265
-rw-r--r--qemu/hw/misc/omap_gpmc.c897
-rw-r--r--qemu/hw/misc/omap_l4.c164
-rw-r--r--qemu/hw/misc/omap_sdrc.c169
-rw-r--r--qemu/hw/misc/omap_tap.c118
-rw-r--r--qemu/hw/misc/pc-testdev.c207
-rw-r--r--qemu/hw/misc/pci-testdev.c335
-rw-r--r--qemu/hw/misc/puv3_pm.c154
-rw-r--r--qemu/hw/misc/pvpanic.c144
-rw-r--r--qemu/hw/misc/sga.c68
-rw-r--r--qemu/hw/misc/slavio_misc.c518
-rw-r--r--qemu/hw/misc/stm32f2xx_syscfg.c161
-rw-r--r--qemu/hw/misc/tmp105.c274
-rw-r--r--qemu/hw/misc/tmp105.h47
-rw-r--r--qemu/hw/misc/vmport.c182
-rw-r--r--qemu/hw/misc/zynq-xadc.c303
-rw-r--r--qemu/hw/misc/zynq_slcr.c459
-rw-r--r--qemu/hw/moxie/Makefile.objs2
-rw-r--r--qemu/hw/moxie/moxiesim.c161
-rw-r--r--qemu/hw/net/Makefile.objs43
-rw-r--r--qemu/hw/net/allwinner_emac.c534
-rw-r--r--qemu/hw/net/cadence_gem.c1267
-rw-r--r--qemu/hw/net/dp8393x.c912
-rw-r--r--qemu/hw/net/e1000.c1959
-rw-r--r--qemu/hw/net/e1000_regs.h908
-rw-r--r--qemu/hw/net/eepro100.c2114
-rw-r--r--qemu/hw/net/etraxfs_eth.c648
-rw-r--r--qemu/hw/net/fsl_etsec/etsec.c457
-rw-r--r--qemu/hw/net/fsl_etsec/etsec.h176
-rw-r--r--qemu/hw/net/fsl_etsec/miim.c147
-rw-r--r--qemu/hw/net/fsl_etsec/registers.c296
-rw-r--r--qemu/hw/net/fsl_etsec/registers.h319
-rw-r--r--qemu/hw/net/fsl_etsec/rings.c654
-rw-r--r--qemu/hw/net/imx_fec.c711
-rw-r--r--qemu/hw/net/lan9118.c1399
-rw-r--r--qemu/hw/net/lance.c184
-rw-r--r--qemu/hw/net/mcf_fec.c535
-rw-r--r--qemu/hw/net/milkymist-minimac2.c544
-rw-r--r--qemu/hw/net/mipsnet.c287
-rw-r--r--qemu/hw/net/ne2000-isa.c155
-rw-r--r--qemu/hw/net/ne2000.c796
-rw-r--r--qemu/hw/net/ne2000.h39
-rw-r--r--qemu/hw/net/opencores_eth.c765
-rw-r--r--qemu/hw/net/pcnet-pci.c375
-rw-r--r--qemu/hw/net/pcnet.c1761
-rw-r--r--qemu/hw/net/pcnet.h67
-rw-r--r--qemu/hw/net/rocker/qmp-norocker.c51
-rw-r--r--qemu/hw/net/rocker/rocker.c1584
-rw-r--r--qemu/hw/net/rocker/rocker.h84
-rw-r--r--qemu/hw/net/rocker/rocker_desc.c374
-rw-r--r--qemu/hw/net/rocker/rocker_desc.h53
-rw-r--r--qemu/hw/net/rocker/rocker_fp.c269
-rw-r--r--qemu/hw/net/rocker/rocker_fp.h54
-rw-r--r--qemu/hw/net/rocker/rocker_hw.h493
-rw-r--r--qemu/hw/net/rocker/rocker_of_dpa.c2627
-rw-r--r--qemu/hw/net/rocker/rocker_of_dpa.h22
-rw-r--r--qemu/hw/net/rocker/rocker_tlv.h244
-rw-r--r--qemu/hw/net/rocker/rocker_world.c102
-rw-r--r--qemu/hw/net/rocker/rocker_world.h61
-rw-r--r--qemu/hw/net/rtl8139.c3509
-rw-r--r--qemu/hw/net/smc91c111.c825
-rw-r--r--qemu/hw/net/spapr_llan.c820
-rw-r--r--qemu/hw/net/stellaris_enet.c514
-rw-r--r--qemu/hw/net/vhost_net.c473
-rw-r--r--qemu/hw/net/virtio-net.c1950
-rw-r--r--qemu/hw/net/vmware_utils.h140
-rw-r--r--qemu/hw/net/vmxnet3.c2723
-rw-r--r--qemu/hw/net/vmxnet3.h759
-rw-r--r--qemu/hw/net/vmxnet_debug.h148
-rw-r--r--qemu/hw/net/vmxnet_rx_pkt.c187
-rw-r--r--qemu/hw/net/vmxnet_rx_pkt.h174
-rw-r--r--qemu/hw/net/vmxnet_tx_pkt.c581
-rw-r--r--qemu/hw/net/vmxnet_tx_pkt.h146
-rw-r--r--qemu/hw/net/xen_nic.c412
-rw-r--r--qemu/hw/net/xgmac.c433
-rw-r--r--qemu/hw/net/xilinx_axienet.c1084
-rw-r--r--qemu/hw/net/xilinx_ethlite.c276
-rw-r--r--qemu/hw/nvram/Makefile.objs5
-rw-r--r--qemu/hw/nvram/ds1225y.c170
-rw-r--r--qemu/hw/nvram/eeprom93xx.c337
-rw-r--r--qemu/hw/nvram/fw_cfg.c1099
-rw-r--r--qemu/hw/nvram/mac_nvram.c218
-rw-r--r--qemu/hw/nvram/spapr_nvram.c252
-rw-r--r--qemu/hw/openrisc/Makefile.objs2
-rw-r--r--qemu/hw/openrisc/cputimer.c112
-rw-r--r--qemu/hw/openrisc/openrisc_sim.c148
-rw-r--r--qemu/hw/openrisc/pic_cpu.c61
-rw-r--r--qemu/hw/pci-bridge/Makefile.objs7
-rw-r--r--qemu/hw/pci-bridge/dec.c162
-rw-r--r--qemu/hw/pci-bridge/dec.h10
-rw-r--r--qemu/hw/pci-bridge/i82801b11.c116
-rw-r--r--qemu/hw/pci-bridge/ioh3420.c218
-rw-r--r--qemu/hw/pci-bridge/ioh3420.h6
-rw-r--r--qemu/hw/pci-bridge/pci_bridge_dev.c257
-rw-r--r--qemu/hw/pci-bridge/pci_expander_bridge.c363
-rw-r--r--qemu/hw/pci-bridge/xio3130_downstream.c206
-rw-r--r--qemu/hw/pci-bridge/xio3130_downstream.h11
-rw-r--r--qemu/hw/pci-bridge/xio3130_upstream.c179
-rw-r--r--qemu/hw/pci-bridge/xio3130_upstream.h10
-rw-r--r--qemu/hw/pci-host/Makefile.objs18
-rw-r--r--qemu/hw/pci-host/apb.c871
-rw-r--r--qemu/hw/pci-host/bonito.c858
-rw-r--r--qemu/hw/pci-host/gpex.c155
-rw-r--r--qemu/hw/pci-host/grackle.c169
-rw-r--r--qemu/hw/pci-host/pam.c70
-rw-r--r--qemu/hw/pci-host/piix.c888
-rw-r--r--qemu/hw/pci-host/ppce500.c551
-rw-r--r--qemu/hw/pci-host/prep.c406
-rw-r--r--qemu/hw/pci-host/q35.c560
-rw-r--r--qemu/hw/pci-host/uninorth.c533
-rw-r--r--qemu/hw/pci-host/versatile.c549
-rw-r--r--qemu/hw/pci/Makefile.objs9
-rw-r--r--qemu/hw/pci/msi.c421
-rw-r--r--qemu/hw/pci/msix.c621
-rw-r--r--qemu/hw/pci/pci-stub.c37
-rw-r--r--qemu/hw/pci/pci.c2517
-rw-r--r--qemu/hw/pci/pci_bridge.c419
-rw-r--r--qemu/hw/pci/pci_host.c207
-rw-r--r--qemu/hw/pci/pcie.c649
-rw-r--r--qemu/hw/pci/pcie_aer.c1039
-rw-r--r--qemu/hw/pci/pcie_host.c147
-rw-r--r--qemu/hw/pci/pcie_port.c179
-rw-r--r--qemu/hw/pci/shpc.c721
-rw-r--r--qemu/hw/pci/slotid_cap.c46
-rw-r--r--qemu/hw/pcmcia/Makefile.objs2
-rw-r--r--qemu/hw/pcmcia/pcmcia.c25
-rw-r--r--qemu/hw/pcmcia/pxa2xx.c265
-rw-r--r--qemu/hw/ppc/Makefile.objs23
-rw-r--r--qemu/hw/ppc/e500-ccsr.h17
-rw-r--r--qemu/hw/ppc/e500.c1082
-rw-r--r--qemu/hw/ppc/e500.h29
-rw-r--r--qemu/hw/ppc/e500plat.c68
-rw-r--r--qemu/hw/ppc/mac.h187
-rw-r--r--qemu/hw/ppc/mac_newworld.c535
-rw-r--r--qemu/hw/ppc/mac_oldworld.c379
-rw-r--r--qemu/hw/ppc/mpc8544_guts.c143
-rw-r--r--qemu/hw/ppc/mpc8544ds.c60
-rw-r--r--qemu/hw/ppc/ppc.c1345
-rw-r--r--qemu/hw/ppc/ppc405.h81
-rw-r--r--qemu/hw/ppc/ppc405_boards.c664
-rw-r--r--qemu/hw/ppc/ppc405_uc.c2555
-rw-r--r--qemu/hw/ppc/ppc440_bamboo.c300
-rw-r--r--qemu/hw/ppc/ppc4xx_devs.c735
-rw-r--r--qemu/hw/ppc/ppc4xx_pci.c393
-rw-r--r--qemu/hw/ppc/ppc_booke.c368
-rw-r--r--qemu/hw/ppc/ppce500_spin.c225
-rw-r--r--qemu/hw/ppc/prep.c679
-rw-r--r--qemu/hw/ppc/spapr.c2485
-rw-r--r--qemu/hw/ppc/spapr_drc.c843
-rw-r--r--qemu/hw/ppc/spapr_events.c610
-rw-r--r--qemu/hw/ppc/spapr_hcall.c1117
-rw-r--r--qemu/hw/ppc/spapr_iommu.c512
-rw-r--r--qemu/hw/ppc/spapr_pci.c1919
-rw-r--r--qemu/hw/ppc/spapr_pci_vfio.c239
-rw-r--r--qemu/hw/ppc/spapr_rng.c191
-rw-r--r--qemu/hw/ppc/spapr_rtas.c785
-rw-r--r--qemu/hw/ppc/spapr_rtc.c212
-rw-r--r--qemu/hw/ppc/spapr_vio.c706
-rw-r--r--qemu/hw/ppc/virtex_ml507.c308
-rw-r--r--qemu/hw/s390x/Makefile.objs13
-rw-r--r--qemu/hw/s390x/css.c1646
-rw-r--r--qemu/hw/s390x/css.h126
-rw-r--r--qemu/hw/s390x/event-facility.c449
-rw-r--r--qemu/hw/s390x/ipl.c298
-rw-r--r--qemu/hw/s390x/ipl.h53
-rw-r--r--qemu/hw/s390x/s390-pci-bus.c621
-rw-r--r--qemu/hw/s390x/s390-pci-bus.h256
-rw-r--r--qemu/hw/s390x/s390-pci-inst.c846
-rw-r--r--qemu/hw/s390x/s390-pci-inst.h289
-rw-r--r--qemu/hw/s390x/s390-skeys-kvm.c76
-rw-r--r--qemu/hw/s390x/s390-skeys.c415
-rw-r--r--qemu/hw/s390x/s390-virtio-ccw.c381
-rw-r--r--qemu/hw/s390x/s390-virtio-hcall.c41
-rw-r--r--qemu/hw/s390x/s390-virtio.c210
-rw-r--r--qemu/hw/s390x/s390-virtio.h32
-rw-r--r--qemu/hw/s390x/sclp.c618
-rw-r--r--qemu/hw/s390x/sclpcpu.c101
-rw-r--r--qemu/hw/s390x/sclpquiesce.c143
-rw-r--r--qemu/hw/s390x/virtio-ccw.c1928
-rw-r--r--qemu/hw/s390x/virtio-ccw.h211
-rw-r--r--qemu/hw/scsi/Makefile.objs14
-rw-r--r--qemu/hw/scsi/esp-pci.c531
-rw-r--r--qemu/hw/scsi/esp.c745
-rw-r--r--qemu/hw/scsi/lsi53c895a.c2163
-rw-r--r--qemu/hw/scsi/megasas.c2548
-rw-r--r--qemu/hw/scsi/mfi.h1272
-rw-r--r--qemu/hw/scsi/mpi.h1153
-rw-r--r--qemu/hw/scsi/mptconfig.c905
-rw-r--r--qemu/hw/scsi/mptendian.c204
-rw-r--r--qemu/hw/scsi/mptsas.c1442
-rw-r--r--qemu/hw/scsi/mptsas.h100
-rw-r--r--qemu/hw/scsi/scsi-bus.c2062
-rw-r--r--qemu/hw/scsi/scsi-disk.c2828
-rw-r--r--qemu/hw/scsi/scsi-generic.c616
-rw-r--r--qemu/hw/scsi/spapr_vscsi.c1304
-rw-r--r--qemu/hw/scsi/srp.h247
-rw-r--r--qemu/hw/scsi/vhost-scsi.c352
-rw-r--r--qemu/hw/scsi/viosrp.h216
-rw-r--r--qemu/hw/scsi/virtio-scsi-dataplane.c208
-rw-r--r--qemu/hw/scsi/virtio-scsi.c1054
-rw-r--r--qemu/hw/scsi/vmw_pvscsi.c1305
-rw-r--r--qemu/hw/scsi/vmw_pvscsi.h434
-rw-r--r--qemu/hw/sd/Makefile.objs8
-rw-r--r--qemu/hw/sd/core.c146
-rw-r--r--qemu/hw/sd/milkymist-memcard.c317
-rw-r--r--qemu/hw/sd/omap_mmc.c647
-rw-r--r--qemu/hw/sd/pl181.c528
-rw-r--r--qemu/hw/sd/pxa2xx_mmci.c598
-rw-r--r--qemu/hw/sd/sd.c1979
-rw-r--r--qemu/hw/sd/sdhci-internal.h232
-rw-r--r--qemu/hw/sd/sdhci.c1394
-rw-r--r--qemu/hw/sd/ssi-sd.c290
-rw-r--r--qemu/hw/sh4/Makefile.objs4
-rw-r--r--qemu/hw/sh4/r2d.c367
-rw-r--r--qemu/hw/sh4/sh7750.c842
-rw-r--r--qemu/hw/sh4/sh7750_regnames.c98
-rw-r--r--qemu/hw/sh4/sh7750_regnames.h6
-rw-r--r--qemu/hw/sh4/sh7750_regs.h1277
-rw-r--r--qemu/hw/sh4/sh_pci.c204
-rw-r--r--qemu/hw/sh4/shix.c101
-rw-r--r--qemu/hw/smbios/Makefile.objs1
-rw-r--r--qemu/hw/smbios/smbios.c1112
-rw-r--r--qemu/hw/sparc/Makefile.objs1
-rw-r--r--qemu/hw/sparc/leon3.c229
-rw-r--r--qemu/hw/sparc/sun4m.c1572
-rw-r--r--qemu/hw/sparc64/Makefile.objs1
-rw-r--r--qemu/hw/sparc64/sun4u.c1010
-rw-r--r--qemu/hw/ssi/Makefile.objs6
-rw-r--r--qemu/hw/ssi/omap_spi.c374
-rw-r--r--qemu/hw/ssi/pl022.c327
-rw-r--r--qemu/hw/ssi/ssi.c175
-rw-r--r--qemu/hw/ssi/xilinx_spi.c391
-rw-r--r--qemu/hw/ssi/xilinx_spips.c734
-rw-r--r--qemu/hw/timer/Makefile.objs35
-rw-r--r--qemu/hw/timer/a9gtimer.c372
-rw-r--r--qemu/hw/timer/allwinner-a10-pit.c296
-rw-r--r--qemu/hw/timer/arm_mptimer.c303
-rw-r--r--qemu/hw/timer/arm_timer.c409
-rw-r--r--qemu/hw/timer/aspeed_timer.c449
-rw-r--r--qemu/hw/timer/cadence_ttc.c492
-rw-r--r--qemu/hw/timer/digic-timer.c163
-rw-r--r--qemu/hw/timer/ds1338.c243
-rw-r--r--qemu/hw/timer/etraxfs_timer.c358
-rw-r--r--qemu/hw/timer/exynos4210_mct.c1480
-rw-r--r--qemu/hw/timer/exynos4210_pwm.c424
-rw-r--r--qemu/hw/timer/exynos4210_rtc.c595
-rw-r--r--qemu/hw/timer/grlib_gptimer.c412
-rw-r--r--qemu/hw/timer/hpet.c789
-rw-r--r--qemu/hw/timer/i8254.c384
-rw-r--r--qemu/hw/timer/i8254_common.c307
-rw-r--r--qemu/hw/timer/imx_epit.c344
-rw-r--r--qemu/hw/timer/imx_gpt.c467
-rw-r--r--qemu/hw/timer/lm32_timer.c236
-rw-r--r--qemu/hw/timer/m48t59.c947
-rw-r--r--qemu/hw/timer/mc146818rtc.c971
-rw-r--r--qemu/hw/timer/milkymist-sysctl.c342
-rw-r--r--qemu/hw/timer/omap_gptimer.c488
-rw-r--r--qemu/hw/timer/omap_synctimer.c104
-rw-r--r--qemu/hw/timer/pl031.c270
-rw-r--r--qemu/hw/timer/puv3_ost.c157
-rw-r--r--qemu/hw/timer/pxa2xx_timer.c605
-rw-r--r--qemu/hw/timer/sh_timer.c335
-rw-r--r--qemu/hw/timer/slavio_timer.c435
-rw-r--r--qemu/hw/timer/stm32f2xx_timer.c329
-rw-r--r--qemu/hw/timer/twl92230.c889
-rw-r--r--qemu/hw/timer/xilinx_timer.c266
-rw-r--r--qemu/hw/tpm/Makefile.objs2
-rw-r--r--qemu/hw/tpm/tpm_int.h75
-rw-r--r--qemu/hw/tpm/tpm_passthrough.c566
-rw-r--r--qemu/hw/tpm/tpm_tis.c1101
-rw-r--r--qemu/hw/tpm/tpm_tis.h70
-rw-r--r--qemu/hw/tpm/tpm_util.c127
-rw-r--r--qemu/hw/tpm/tpm_util.h28
-rw-r--r--qemu/hw/tricore/Makefile.objs1
-rw-r--r--qemu/hw/tricore/tricore_testboard.c129
-rw-r--r--qemu/hw/unicore32/Makefile.objs4
-rw-r--r--qemu/hw/unicore32/puv3.c148
-rw-r--r--qemu/hw/usb/Makefile.objs40
-rw-r--r--qemu/hw/usb/bus.c763
-rw-r--r--qemu/hw/usb/ccid-card-emulated.c606
-rw-r--r--qemu/hw/usb/ccid-card-passthru.c416
-rw-r--r--qemu/hw/usb/ccid.h65
-rw-r--r--qemu/hw/usb/combined-packet.c188
-rw-r--r--qemu/hw/usb/core.c795
-rw-r--r--qemu/hw/usb/desc-msos.c239
-rw-r--r--qemu/hw/usb/desc.c804
-rw-r--r--qemu/hw/usb/desc.h244
-rw-r--r--qemu/hw/usb/dev-audio.c703
-rw-r--r--qemu/hw/usb/dev-bluetooth.c580
-rw-r--r--qemu/hw/usb/dev-hid.c883
-rw-r--r--qemu/hw/usb/dev-hub.c596
-rw-r--r--qemu/hw/usb/dev-mtp.c1414
-rw-r--r--qemu/hw/usb/dev-network.c1455
-rw-r--r--qemu/hw/usb/dev-serial.c652
-rw-r--r--qemu/hw/usb/dev-smartcard-reader.c1507
-rw-r--r--qemu/hw/usb/dev-storage.c872
-rw-r--r--qemu/hw/usb/dev-uas.c961
-rw-r--r--qemu/hw/usb/dev-wacom.c386
-rw-r--r--qemu/hw/usb/hcd-ehci-pci.c272
-rw-r--r--qemu/hw/usb/hcd-ehci-sysbus.c230
-rw-r--r--qemu/hw/usb/hcd-ehci.c2549
-rw-r--r--qemu/hw/usb/hcd-ehci.h383
-rw-r--r--qemu/hw/usb/hcd-musb.c1553
-rw-r--r--qemu/hw/usb/hcd-ohci.c2164
-rw-r--r--qemu/hw/usb/hcd-uhci.c1435
-rw-r--r--qemu/hw/usb/hcd-xhci.c3917
-rw-r--r--qemu/hw/usb/host-legacy.c144
-rw-r--r--qemu/hw/usb/host-libusb.c1688
-rw-r--r--qemu/hw/usb/host-stub.c48
-rw-r--r--qemu/hw/usb/host.h44
-rw-r--r--qemu/hw/usb/libhw.c71
-rw-r--r--qemu/hw/usb/quirks-ftdi-ids.h1255
-rw-r--r--qemu/hw/usb/quirks-pl2303-ids.h150
-rw-r--r--qemu/hw/usb/quirks.c54
-rw-r--r--qemu/hw/usb/quirks.h910
-rw-r--r--qemu/hw/usb/redirect.c2526
-rw-r--r--qemu/hw/usb/tusb6010.c817
-rw-r--r--qemu/hw/vfio/Makefile.objs7
-rw-r--r--qemu/hw/vfio/amd-xgbe.c56
-rw-r--r--qemu/hw/vfio/calxeda-xgmac.c56
-rw-r--r--qemu/hw/vfio/common.c1192
-rw-r--r--qemu/hw/vfio/pci-quirks.c1205
-rw-r--r--qemu/hw/vfio/pci.c2734
-rw-r--r--qemu/hw/vfio/pci.h162
-rw-r--r--qemu/hw/vfio/platform.c705
-rw-r--r--qemu/hw/virtio/Makefile.objs7
-rw-r--r--qemu/hw/virtio/vhost-backend.c212
-rw-r--r--qemu/hw/virtio/vhost-user.c657
-rw-r--r--qemu/hw/virtio/vhost.c1301
-rw-r--r--qemu/hw/virtio/virtio-balloon.c535
-rw-r--r--qemu/hw/virtio/virtio-bus.c182
-rw-r--r--qemu/hw/virtio/virtio-mmio.c580
-rw-r--r--qemu/hw/virtio/virtio-pci.c2534
-rw-r--r--qemu/hw/virtio/virtio-pci.h317
-rw-r--r--qemu/hw/virtio/virtio-rng.c278
-rw-r--r--qemu/hw/virtio/virtio.c1926
-rw-r--r--qemu/hw/watchdog/Makefile.objs4
-rw-r--r--qemu/hw/watchdog/watchdog.c149
-rw-r--r--qemu/hw/watchdog/wdt_diag288.c142
-rw-r--r--qemu/hw/watchdog/wdt_i6300esb.c465
-rw-r--r--qemu/hw/watchdog/wdt_ib700.c157
-rw-r--r--qemu/hw/xen/Makefile.objs5
-rw-r--r--qemu/hw/xen/xen-host-pci-device.c404
-rw-r--r--qemu/hw/xen/xen-host-pci-device.h58
-rw-r--r--qemu/hw/xen/xen_backend.c802
-rw-r--r--qemu/hw/xen/xen_devconfig.c176
-rw-r--r--qemu/hw/xen/xen_pt.c974
-rw-r--r--qemu/hw/xen/xen_pt.h335
-rw-r--r--qemu/hw/xen/xen_pt_config_init.c2090
-rw-r--r--qemu/hw/xen/xen_pt_graphics.c275
-rw-r--r--qemu/hw/xen/xen_pt_msi.c635
-rw-r--r--qemu/hw/xenpv/Makefile.objs4
-rw-r--r--qemu/hw/xenpv/xen_domainbuild.c302
-rw-r--r--qemu/hw/xenpv/xen_domainbuild.h13
-rw-r--r--qemu/hw/xenpv/xen_machine_pv.c112
-rw-r--r--qemu/hw/xtensa/Makefile.objs3
-rw-r--r--qemu/hw/xtensa/bootparam.h49
-rw-r--r--qemu/hw/xtensa/pic_cpu.c167
-rw-r--r--qemu/hw/xtensa/sim.c119
-rw-r--r--qemu/hw/xtensa/xtfpga.c516
821 files changed, 0 insertions, 416358 deletions
diff --git a/qemu/hw/9pfs/9p-handle.c b/qemu/hw/9pfs/9p-handle.c
deleted file mode 100644
index 894041488..000000000
--- a/qemu/hw/9pfs/9p-handle.c
+++ /dev/null
@@ -1,709 +0,0 @@
-/*
- * 9p handle callback
- *
- * Copyright IBM, Corp. 2011
- *
- * Authors:
- * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "9p.h"
-#include "9p-xattr.h"
-#include <arpa/inet.h>
-#include <pwd.h>
-#include <grp.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include "qemu/xattr.h"
-#include "qemu/cutils.h"
-#include "qemu/error-report.h"
-#include <linux/fs.h>
-#ifdef CONFIG_LINUX_MAGIC_H
-#include <linux/magic.h>
-#endif
-#include <sys/ioctl.h>
-
-#ifndef XFS_SUPER_MAGIC
-#define XFS_SUPER_MAGIC 0x58465342
-#endif
-#ifndef EXT2_SUPER_MAGIC
-#define EXT2_SUPER_MAGIC 0xEF53
-#endif
-#ifndef REISERFS_SUPER_MAGIC
-#define REISERFS_SUPER_MAGIC 0x52654973
-#endif
-#ifndef BTRFS_SUPER_MAGIC
-#define BTRFS_SUPER_MAGIC 0x9123683E
-#endif
-
-struct handle_data {
- int mountfd;
- int handle_bytes;
-};
-
-static inline int name_to_handle(int dirfd, const char *name,
- struct file_handle *fh, int *mnt_id, int flags)
-{
- return name_to_handle_at(dirfd, name, fh, mnt_id, flags);
-}
-
-static inline int open_by_handle(int mountfd, const char *fh, int flags)
-{
- return open_by_handle_at(mountfd, (struct file_handle *)fh, flags);
-}
-
-static int handle_update_file_cred(int dirfd, const char *name, FsCred *credp)
-{
- int fd, ret;
- fd = openat(dirfd, name, O_NONBLOCK | O_NOFOLLOW);
- if (fd < 0) {
- return fd;
- }
- ret = fchownat(fd, "", credp->fc_uid, credp->fc_gid, AT_EMPTY_PATH);
- if (ret < 0) {
- goto err_out;
- }
- ret = fchmod(fd, credp->fc_mode & 07777);
-err_out:
- close(fd);
- return ret;
-}
-
-
-static int handle_lstat(FsContext *fs_ctx, V9fsPath *fs_path,
- struct stat *stbuf)
-{
- int fd, ret;
- struct handle_data *data = (struct handle_data *)fs_ctx->private;
-
- fd = open_by_handle(data->mountfd, fs_path->data, O_PATH);
- if (fd < 0) {
- return fd;
- }
- ret = fstatat(fd, "", stbuf, AT_EMPTY_PATH);
- close(fd);
- return ret;
-}
-
-static ssize_t handle_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
- char *buf, size_t bufsz)
-{
- int fd, ret;
- struct handle_data *data = (struct handle_data *)fs_ctx->private;
-
- fd = open_by_handle(data->mountfd, fs_path->data, O_PATH);
- if (fd < 0) {
- return fd;
- }
- ret = readlinkat(fd, "", buf, bufsz);
- close(fd);
- return ret;
-}
-
-static int handle_close(FsContext *ctx, V9fsFidOpenState *fs)
-{
- return close(fs->fd);
-}
-
-static int handle_closedir(FsContext *ctx, V9fsFidOpenState *fs)
-{
- return closedir(fs->dir);
-}
-
-static int handle_open(FsContext *ctx, V9fsPath *fs_path,
- int flags, V9fsFidOpenState *fs)
-{
- struct handle_data *data = (struct handle_data *)ctx->private;
-
- fs->fd = open_by_handle(data->mountfd, fs_path->data, flags);
- return fs->fd;
-}
-
-static int handle_opendir(FsContext *ctx,
- V9fsPath *fs_path, V9fsFidOpenState *fs)
-{
- int ret;
- ret = handle_open(ctx, fs_path, O_DIRECTORY, fs);
- if (ret < 0) {
- return -1;
- }
- fs->dir = fdopendir(ret);
- if (!fs->dir) {
- return -1;
- }
- return 0;
-}
-
-static void handle_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
-{
- rewinddir(fs->dir);
-}
-
-static off_t handle_telldir(FsContext *ctx, V9fsFidOpenState *fs)
-{
- return telldir(fs->dir);
-}
-
-static int handle_readdir_r(FsContext *ctx, V9fsFidOpenState *fs,
- struct dirent *entry,
- struct dirent **result)
-{
- return readdir_r(fs->dir, entry, result);
-}
-
-static void handle_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
-{
- seekdir(fs->dir, off);
-}
-
-static ssize_t handle_preadv(FsContext *ctx, V9fsFidOpenState *fs,
- const struct iovec *iov,
- int iovcnt, off_t offset)
-{
-#ifdef CONFIG_PREADV
- return preadv(fs->fd, iov, iovcnt, offset);
-#else
- int err = lseek(fs->fd, offset, SEEK_SET);
- if (err == -1) {
- return err;
- } else {
- return readv(fs->fd, iov, iovcnt);
- }
-#endif
-}
-
-static ssize_t handle_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
- const struct iovec *iov,
- int iovcnt, off_t offset)
-{
- ssize_t ret;
-#ifdef CONFIG_PREADV
- ret = pwritev(fs->fd, iov, iovcnt, offset);
-#else
- int err = lseek(fs->fd, offset, SEEK_SET);
- if (err == -1) {
- return err;
- } else {
- ret = writev(fs->fd, iov, iovcnt);
- }
-#endif
-#ifdef CONFIG_SYNC_FILE_RANGE
- if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) {
- /*
- * Initiate a writeback. This is not a data integrity sync.
- * We want to ensure that we don't leave dirty pages in the cache
- * after write when writeout=immediate is sepcified.
- */
- sync_file_range(fs->fd, offset, ret,
- SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE);
- }
-#endif
- return ret;
-}
-
-static int handle_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
-{
- int fd, ret;
- struct handle_data *data = (struct handle_data *)fs_ctx->private;
-
- fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
- if (fd < 0) {
- return fd;
- }
- ret = fchmod(fd, credp->fc_mode);
- close(fd);
- return ret;
-}
-
-static int handle_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
- const char *name, FsCred *credp)
-{
- int dirfd, ret;
- struct handle_data *data = (struct handle_data *)fs_ctx->private;
-
- dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
- if (dirfd < 0) {
- return dirfd;
- }
- ret = mknodat(dirfd, name, credp->fc_mode, credp->fc_rdev);
- if (!ret) {
- ret = handle_update_file_cred(dirfd, name, credp);
- }
- close(dirfd);
- return ret;
-}
-
-static int handle_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
- const char *name, FsCred *credp)
-{
- int dirfd, ret;
- struct handle_data *data = (struct handle_data *)fs_ctx->private;
-
- dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
- if (dirfd < 0) {
- return dirfd;
- }
- ret = mkdirat(dirfd, name, credp->fc_mode);
- if (!ret) {
- ret = handle_update_file_cred(dirfd, name, credp);
- }
- close(dirfd);
- return ret;
-}
-
-static int handle_fstat(FsContext *fs_ctx, int fid_type,
- V9fsFidOpenState *fs, struct stat *stbuf)
-{
- int fd;
-
- if (fid_type == P9_FID_DIR) {
- fd = dirfd(fs->dir);
- } else {
- fd = fs->fd;
- }
- return fstat(fd, stbuf);
-}
-
-static int handle_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
- int flags, FsCred *credp, V9fsFidOpenState *fs)
-{
- int ret;
- int dirfd, fd;
- struct handle_data *data = (struct handle_data *)fs_ctx->private;
-
- dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
- if (dirfd < 0) {
- return dirfd;
- }
- fd = openat(dirfd, name, flags | O_NOFOLLOW, credp->fc_mode);
- if (fd >= 0) {
- ret = handle_update_file_cred(dirfd, name, credp);
- if (ret < 0) {
- close(fd);
- fd = ret;
- } else {
- fs->fd = fd;
- }
- }
- close(dirfd);
- return fd;
-}
-
-
-static int handle_symlink(FsContext *fs_ctx, const char *oldpath,
- V9fsPath *dir_path, const char *name, FsCred *credp)
-{
- int fd, dirfd, ret;
- struct handle_data *data = (struct handle_data *)fs_ctx->private;
-
- dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
- if (dirfd < 0) {
- return dirfd;
- }
- ret = symlinkat(oldpath, dirfd, name);
- if (!ret) {
- fd = openat(dirfd, name, O_PATH | O_NOFOLLOW);
- if (fd < 0) {
- ret = fd;
- goto err_out;
- }
- ret = fchownat(fd, "", credp->fc_uid, credp->fc_gid, AT_EMPTY_PATH);
- close(fd);
- }
-err_out:
- close(dirfd);
- return ret;
-}
-
-static int handle_link(FsContext *ctx, V9fsPath *oldpath,
- V9fsPath *dirpath, const char *name)
-{
- int oldfd, newdirfd, ret;
- struct handle_data *data = (struct handle_data *)ctx->private;
-
- oldfd = open_by_handle(data->mountfd, oldpath->data, O_PATH);
- if (oldfd < 0) {
- return oldfd;
- }
- newdirfd = open_by_handle(data->mountfd, dirpath->data, O_PATH);
- if (newdirfd < 0) {
- close(oldfd);
- return newdirfd;
- }
- ret = linkat(oldfd, "", newdirfd, name, AT_EMPTY_PATH);
- close(newdirfd);
- close(oldfd);
- return ret;
-}
-
-static int handle_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
-{
- int fd, ret;
- struct handle_data *data = (struct handle_data *)ctx->private;
-
- fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK | O_WRONLY);
- if (fd < 0) {
- return fd;
- }
- ret = ftruncate(fd, size);
- close(fd);
- return ret;
-}
-
-static int handle_rename(FsContext *ctx, const char *oldpath,
- const char *newpath)
-{
- errno = EOPNOTSUPP;
- return -1;
-}
-
-static int handle_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
-{
- int fd, ret;
- struct handle_data *data = (struct handle_data *)fs_ctx->private;
-
- fd = open_by_handle(data->mountfd, fs_path->data, O_PATH);
- if (fd < 0) {
- return fd;
- }
- ret = fchownat(fd, "", credp->fc_uid, credp->fc_gid, AT_EMPTY_PATH);
- close(fd);
- return ret;
-}
-
-static int handle_utimensat(FsContext *ctx, V9fsPath *fs_path,
- const struct timespec *buf)
-{
- int ret;
-#ifdef CONFIG_UTIMENSAT
- int fd;
- struct handle_data *data = (struct handle_data *)ctx->private;
-
- fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
- if (fd < 0) {
- return fd;
- }
- ret = futimens(fd, buf);
- close(fd);
-#else
- ret = -1;
- errno = ENOSYS;
-#endif
- return ret;
-}
-
-static int handle_remove(FsContext *ctx, const char *path)
-{
- errno = EOPNOTSUPP;
- return -1;
-}
-
-static int handle_fsync(FsContext *ctx, int fid_type,
- V9fsFidOpenState *fs, int datasync)
-{
- int fd;
-
- if (fid_type == P9_FID_DIR) {
- fd = dirfd(fs->dir);
- } else {
- fd = fs->fd;
- }
-
- if (datasync) {
- return qemu_fdatasync(fd);
- } else {
- return fsync(fd);
- }
-}
-
-static int handle_statfs(FsContext *ctx, V9fsPath *fs_path,
- struct statfs *stbuf)
-{
- int fd, ret;
- struct handle_data *data = (struct handle_data *)ctx->private;
-
- fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
- if (fd < 0) {
- return fd;
- }
- ret = fstatfs(fd, stbuf);
- close(fd);
- return ret;
-}
-
-static ssize_t handle_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
- const char *name, void *value, size_t size)
-{
- int fd, ret;
- struct handle_data *data = (struct handle_data *)ctx->private;
-
- fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
- if (fd < 0) {
- return fd;
- }
- ret = fgetxattr(fd, name, value, size);
- close(fd);
- return ret;
-}
-
-static ssize_t handle_llistxattr(FsContext *ctx, V9fsPath *fs_path,
- void *value, size_t size)
-{
- int fd, ret;
- struct handle_data *data = (struct handle_data *)ctx->private;
-
- fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
- if (fd < 0) {
- return fd;
- }
- ret = flistxattr(fd, value, size);
- close(fd);
- return ret;
-}
-
-static int handle_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name,
- void *value, size_t size, int flags)
-{
- int fd, ret;
- struct handle_data *data = (struct handle_data *)ctx->private;
-
- fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
- if (fd < 0) {
- return fd;
- }
- ret = fsetxattr(fd, name, value, size, flags);
- close(fd);
- return ret;
-}
-
-static int handle_lremovexattr(FsContext *ctx, V9fsPath *fs_path,
- const char *name)
-{
- int fd, ret;
- struct handle_data *data = (struct handle_data *)ctx->private;
-
- fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
- if (fd < 0) {
- return fd;
- }
- ret = fremovexattr(fd, name);
- close(fd);
- return ret;
-}
-
-static int handle_name_to_path(FsContext *ctx, V9fsPath *dir_path,
- const char *name, V9fsPath *target)
-{
- char *buffer;
- struct file_handle *fh;
- int dirfd, ret, mnt_id;
- struct handle_data *data = (struct handle_data *)ctx->private;
-
- /* "." and ".." are not allowed */
- if (!strcmp(name, ".") || !strcmp(name, "..")) {
- errno = EINVAL;
- return -1;
-
- }
- if (dir_path) {
- dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
- } else {
- /* relative to export root */
- buffer = rpath(ctx, ".");
- dirfd = open(buffer, O_DIRECTORY);
- g_free(buffer);
- }
- if (dirfd < 0) {
- return dirfd;
- }
- fh = g_malloc(sizeof(struct file_handle) + data->handle_bytes);
- fh->handle_bytes = data->handle_bytes;
- /* add a "./" at the beginning of the path */
- buffer = g_strdup_printf("./%s", name);
- /* flag = 0 imply don't follow symlink */
- ret = name_to_handle(dirfd, buffer, fh, &mnt_id, 0);
- if (!ret) {
- target->data = (char *)fh;
- target->size = sizeof(struct file_handle) + data->handle_bytes;
- } else {
- g_free(fh);
- }
- close(dirfd);
- g_free(buffer);
- return ret;
-}
-
-static int handle_renameat(FsContext *ctx, V9fsPath *olddir,
- const char *old_name, V9fsPath *newdir,
- const char *new_name)
-{
- int olddirfd, newdirfd, ret;
- struct handle_data *data = (struct handle_data *)ctx->private;
-
- olddirfd = open_by_handle(data->mountfd, olddir->data, O_PATH);
- if (olddirfd < 0) {
- return olddirfd;
- }
- newdirfd = open_by_handle(data->mountfd, newdir->data, O_PATH);
- if (newdirfd < 0) {
- close(olddirfd);
- return newdirfd;
- }
- ret = renameat(olddirfd, old_name, newdirfd, new_name);
- close(newdirfd);
- close(olddirfd);
- return ret;
-}
-
-static int handle_unlinkat(FsContext *ctx, V9fsPath *dir,
- const char *name, int flags)
-{
- int dirfd, ret;
- struct handle_data *data = (struct handle_data *)ctx->private;
- int rflags;
-
- dirfd = open_by_handle(data->mountfd, dir->data, O_PATH);
- if (dirfd < 0) {
- return dirfd;
- }
-
- rflags = 0;
- if (flags & P9_DOTL_AT_REMOVEDIR) {
- rflags |= AT_REMOVEDIR;
- }
-
- ret = unlinkat(dirfd, name, rflags);
-
- close(dirfd);
- return ret;
-}
-
-static int handle_ioc_getversion(FsContext *ctx, V9fsPath *path,
- mode_t st_mode, uint64_t *st_gen)
-{
-#ifdef FS_IOC_GETVERSION
- int err;
- V9fsFidOpenState fid_open;
-
- /*
- * Do not try to open special files like device nodes, fifos etc
- * We can get fd for regular files and directories only
- */
- if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) {
- errno = ENOTTY;
- return -1;
- }
- err = handle_open(ctx, path, O_RDONLY, &fid_open);
- if (err < 0) {
- return err;
- }
- err = ioctl(fid_open.fd, FS_IOC_GETVERSION, st_gen);
- handle_close(ctx, &fid_open);
- return err;
-#else
- errno = ENOTTY;
- return -1;
-#endif
-}
-
-static int handle_init(FsContext *ctx)
-{
- int ret, mnt_id;
- struct statfs stbuf;
- struct file_handle fh;
- struct handle_data *data = g_malloc(sizeof(struct handle_data));
-
- data->mountfd = open(ctx->fs_root, O_DIRECTORY);
- if (data->mountfd < 0) {
- ret = data->mountfd;
- goto err_out;
- }
- ret = statfs(ctx->fs_root, &stbuf);
- if (!ret) {
- switch (stbuf.f_type) {
- case EXT2_SUPER_MAGIC:
- case BTRFS_SUPER_MAGIC:
- case REISERFS_SUPER_MAGIC:
- case XFS_SUPER_MAGIC:
- ctx->exops.get_st_gen = handle_ioc_getversion;
- break;
- }
- }
- memset(&fh, 0, sizeof(struct file_handle));
- ret = name_to_handle(data->mountfd, ".", &fh, &mnt_id, 0);
- if (ret && errno == EOVERFLOW) {
- data->handle_bytes = fh.handle_bytes;
- ctx->private = data;
- ret = 0;
- goto out;
- }
- /* we got 0 byte handle ? */
- ret = -1;
- close(data->mountfd);
-err_out:
- g_free(data);
-out:
- return ret;
-}
-
-static int handle_parse_opts(QemuOpts *opts, struct FsDriverEntry *fse)
-{
- const char *sec_model = qemu_opt_get(opts, "security_model");
- const char *path = qemu_opt_get(opts, "path");
-
- if (sec_model) {
- error_report("Invalid argument security_model specified with handle fsdriver");
- return -1;
- }
-
- if (!path) {
- error_report("fsdev: No path specified");
- return -1;
- }
- fse->path = g_strdup(path);
- return 0;
-
-}
-
-FileOperations handle_ops = {
- .parse_opts = handle_parse_opts,
- .init = handle_init,
- .lstat = handle_lstat,
- .readlink = handle_readlink,
- .close = handle_close,
- .closedir = handle_closedir,
- .open = handle_open,
- .opendir = handle_opendir,
- .rewinddir = handle_rewinddir,
- .telldir = handle_telldir,
- .readdir_r = handle_readdir_r,
- .seekdir = handle_seekdir,
- .preadv = handle_preadv,
- .pwritev = handle_pwritev,
- .chmod = handle_chmod,
- .mknod = handle_mknod,
- .mkdir = handle_mkdir,
- .fstat = handle_fstat,
- .open2 = handle_open2,
- .symlink = handle_symlink,
- .link = handle_link,
- .truncate = handle_truncate,
- .rename = handle_rename,
- .chown = handle_chown,
- .utimensat = handle_utimensat,
- .remove = handle_remove,
- .fsync = handle_fsync,
- .statfs = handle_statfs,
- .lgetxattr = handle_lgetxattr,
- .llistxattr = handle_llistxattr,
- .lsetxattr = handle_lsetxattr,
- .lremovexattr = handle_lremovexattr,
- .name_to_path = handle_name_to_path,
- .renameat = handle_renameat,
- .unlinkat = handle_unlinkat,
-};
diff --git a/qemu/hw/9pfs/9p-local.c b/qemu/hw/9pfs/9p-local.c
deleted file mode 100644
index 16f45f485..000000000
--- a/qemu/hw/9pfs/9p-local.c
+++ /dev/null
@@ -1,1282 +0,0 @@
-/*
- * 9p Posix callback
- *
- * Copyright IBM, Corp. 2010
- *
- * Authors:
- * Anthony Liguori <aliguori@us.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "9p.h"
-#include "9p-xattr.h"
-#include "fsdev/qemu-fsdev.h" /* local_ops */
-#include <arpa/inet.h>
-#include <pwd.h>
-#include <grp.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include "qemu/xattr.h"
-#include "qemu/cutils.h"
-#include "qemu/error-report.h"
-#include <libgen.h>
-#include <linux/fs.h>
-#ifdef CONFIG_LINUX_MAGIC_H
-#include <linux/magic.h>
-#endif
-#include <sys/ioctl.h>
-
-#ifndef XFS_SUPER_MAGIC
-#define XFS_SUPER_MAGIC 0x58465342
-#endif
-#ifndef EXT2_SUPER_MAGIC
-#define EXT2_SUPER_MAGIC 0xEF53
-#endif
-#ifndef REISERFS_SUPER_MAGIC
-#define REISERFS_SUPER_MAGIC 0x52654973
-#endif
-#ifndef BTRFS_SUPER_MAGIC
-#define BTRFS_SUPER_MAGIC 0x9123683E
-#endif
-
-#define VIRTFS_META_DIR ".virtfs_metadata"
-
-static char *local_mapped_attr_path(FsContext *ctx, const char *path)
-{
- int dirlen;
- const char *name = strrchr(path, '/');
- if (name) {
- dirlen = name - path;
- ++name;
- } else {
- name = path;
- dirlen = 0;
- }
- return g_strdup_printf("%s/%.*s/%s/%s", ctx->fs_root,
- dirlen, path, VIRTFS_META_DIR, name);
-}
-
-static FILE *local_fopen(const char *path, const char *mode)
-{
- int fd, o_mode = 0;
- FILE *fp;
- int flags = O_NOFOLLOW;
- /*
- * only supports two modes
- */
- if (mode[0] == 'r') {
- flags |= O_RDONLY;
- } else if (mode[0] == 'w') {
- flags |= O_WRONLY | O_TRUNC | O_CREAT;
- o_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
- } else {
- return NULL;
- }
- fd = open(path, flags, o_mode);
- if (fd == -1) {
- return NULL;
- }
- fp = fdopen(fd, mode);
- if (!fp) {
- close(fd);
- }
- return fp;
-}
-
-#define ATTR_MAX 100
-static void local_mapped_file_attr(FsContext *ctx, const char *path,
- struct stat *stbuf)
-{
- FILE *fp;
- char buf[ATTR_MAX];
- char *attr_path;
-
- attr_path = local_mapped_attr_path(ctx, path);
- fp = local_fopen(attr_path, "r");
- g_free(attr_path);
- if (!fp) {
- return;
- }
- memset(buf, 0, ATTR_MAX);
- while (fgets(buf, ATTR_MAX, fp)) {
- if (!strncmp(buf, "virtfs.uid", 10)) {
- stbuf->st_uid = atoi(buf+11);
- } else if (!strncmp(buf, "virtfs.gid", 10)) {
- stbuf->st_gid = atoi(buf+11);
- } else if (!strncmp(buf, "virtfs.mode", 11)) {
- stbuf->st_mode = atoi(buf+12);
- } else if (!strncmp(buf, "virtfs.rdev", 11)) {
- stbuf->st_rdev = atoi(buf+12);
- }
- memset(buf, 0, ATTR_MAX);
- }
- fclose(fp);
-}
-
-static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
-{
- int err;
- char *buffer;
- char *path = fs_path->data;
-
- buffer = rpath(fs_ctx, path);
- err = lstat(buffer, stbuf);
- if (err) {
- goto err_out;
- }
- if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
- /* Actual credentials are part of extended attrs */
- uid_t tmp_uid;
- gid_t tmp_gid;
- mode_t tmp_mode;
- dev_t tmp_dev;
- if (getxattr(buffer, "user.virtfs.uid", &tmp_uid, sizeof(uid_t)) > 0) {
- stbuf->st_uid = le32_to_cpu(tmp_uid);
- }
- if (getxattr(buffer, "user.virtfs.gid", &tmp_gid, sizeof(gid_t)) > 0) {
- stbuf->st_gid = le32_to_cpu(tmp_gid);
- }
- if (getxattr(buffer, "user.virtfs.mode",
- &tmp_mode, sizeof(mode_t)) > 0) {
- stbuf->st_mode = le32_to_cpu(tmp_mode);
- }
- if (getxattr(buffer, "user.virtfs.rdev", &tmp_dev, sizeof(dev_t)) > 0) {
- stbuf->st_rdev = le64_to_cpu(tmp_dev);
- }
- } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
- local_mapped_file_attr(fs_ctx, path, stbuf);
- }
-
-err_out:
- g_free(buffer);
- return err;
-}
-
-static int local_create_mapped_attr_dir(FsContext *ctx, const char *path)
-{
- int err;
- char *attr_dir;
- char *tmp_path = g_strdup(path);
-
- attr_dir = g_strdup_printf("%s/%s/%s",
- ctx->fs_root, dirname(tmp_path), VIRTFS_META_DIR);
-
- err = mkdir(attr_dir, 0700);
- if (err < 0 && errno == EEXIST) {
- err = 0;
- }
- g_free(attr_dir);
- g_free(tmp_path);
- return err;
-}
-
-static int local_set_mapped_file_attr(FsContext *ctx,
- const char *path, FsCred *credp)
-{
- FILE *fp;
- int ret = 0;
- char buf[ATTR_MAX];
- char *attr_path;
- int uid = -1, gid = -1, mode = -1, rdev = -1;
-
- attr_path = local_mapped_attr_path(ctx, path);
- fp = local_fopen(attr_path, "r");
- if (!fp) {
- goto create_map_file;
- }
- memset(buf, 0, ATTR_MAX);
- while (fgets(buf, ATTR_MAX, fp)) {
- if (!strncmp(buf, "virtfs.uid", 10)) {
- uid = atoi(buf+11);
- } else if (!strncmp(buf, "virtfs.gid", 10)) {
- gid = atoi(buf+11);
- } else if (!strncmp(buf, "virtfs.mode", 11)) {
- mode = atoi(buf+12);
- } else if (!strncmp(buf, "virtfs.rdev", 11)) {
- rdev = atoi(buf+12);
- }
- memset(buf, 0, ATTR_MAX);
- }
- fclose(fp);
- goto update_map_file;
-
-create_map_file:
- ret = local_create_mapped_attr_dir(ctx, path);
- if (ret < 0) {
- goto err_out;
- }
-
-update_map_file:
- fp = local_fopen(attr_path, "w");
- if (!fp) {
- ret = -1;
- goto err_out;
- }
-
- if (credp->fc_uid != -1) {
- uid = credp->fc_uid;
- }
- if (credp->fc_gid != -1) {
- gid = credp->fc_gid;
- }
- if (credp->fc_mode != -1) {
- mode = credp->fc_mode;
- }
- if (credp->fc_rdev != -1) {
- rdev = credp->fc_rdev;
- }
-
-
- if (uid != -1) {
- fprintf(fp, "virtfs.uid=%d\n", uid);
- }
- if (gid != -1) {
- fprintf(fp, "virtfs.gid=%d\n", gid);
- }
- if (mode != -1) {
- fprintf(fp, "virtfs.mode=%d\n", mode);
- }
- if (rdev != -1) {
- fprintf(fp, "virtfs.rdev=%d\n", rdev);
- }
- fclose(fp);
-
-err_out:
- g_free(attr_path);
- return ret;
-}
-
-static int local_set_xattr(const char *path, FsCred *credp)
-{
- int err;
-
- if (credp->fc_uid != -1) {
- uint32_t tmp_uid = cpu_to_le32(credp->fc_uid);
- err = setxattr(path, "user.virtfs.uid", &tmp_uid, sizeof(uid_t), 0);
- if (err) {
- return err;
- }
- }
- if (credp->fc_gid != -1) {
- uint32_t tmp_gid = cpu_to_le32(credp->fc_gid);
- err = setxattr(path, "user.virtfs.gid", &tmp_gid, sizeof(gid_t), 0);
- if (err) {
- return err;
- }
- }
- if (credp->fc_mode != -1) {
- uint32_t tmp_mode = cpu_to_le32(credp->fc_mode);
- err = setxattr(path, "user.virtfs.mode", &tmp_mode, sizeof(mode_t), 0);
- if (err) {
- return err;
- }
- }
- if (credp->fc_rdev != -1) {
- uint64_t tmp_rdev = cpu_to_le64(credp->fc_rdev);
- err = setxattr(path, "user.virtfs.rdev", &tmp_rdev, sizeof(dev_t), 0);
- if (err) {
- return err;
- }
- }
- return 0;
-}
-
-static int local_post_create_passthrough(FsContext *fs_ctx, const char *path,
- FsCred *credp)
-{
- char *buffer;
-
- buffer = rpath(fs_ctx, path);
- if (lchown(buffer, credp->fc_uid, credp->fc_gid) < 0) {
- /*
- * If we fail to change ownership and if we are
- * using security model none. Ignore the error
- */
- if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) {
- goto err;
- }
- }
-
- if (chmod(buffer, credp->fc_mode & 07777) < 0) {
- goto err;
- }
-
- g_free(buffer);
- return 0;
-err:
- g_free(buffer);
- return -1;
-}
-
-static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
- char *buf, size_t bufsz)
-{
- ssize_t tsize = -1;
- char *buffer;
- char *path = fs_path->data;
-
- if ((fs_ctx->export_flags & V9FS_SM_MAPPED) ||
- (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE)) {
- int fd;
- buffer = rpath(fs_ctx, path);
- fd = open(buffer, O_RDONLY | O_NOFOLLOW);
- g_free(buffer);
- if (fd == -1) {
- return -1;
- }
- do {
- tsize = read(fd, (void *)buf, bufsz);
- } while (tsize == -1 && errno == EINTR);
- close(fd);
- } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
- (fs_ctx->export_flags & V9FS_SM_NONE)) {
- buffer = rpath(fs_ctx, path);
- tsize = readlink(buffer, buf, bufsz);
- g_free(buffer);
- }
- return tsize;
-}
-
-static int local_close(FsContext *ctx, V9fsFidOpenState *fs)
-{
- return close(fs->fd);
-}
-
-static int local_closedir(FsContext *ctx, V9fsFidOpenState *fs)
-{
- return closedir(fs->dir);
-}
-
-static int local_open(FsContext *ctx, V9fsPath *fs_path,
- int flags, V9fsFidOpenState *fs)
-{
- char *buffer;
- char *path = fs_path->data;
-
- buffer = rpath(ctx, path);
- fs->fd = open(buffer, flags | O_NOFOLLOW);
- g_free(buffer);
- return fs->fd;
-}
-
-static int local_opendir(FsContext *ctx,
- V9fsPath *fs_path, V9fsFidOpenState *fs)
-{
- char *buffer;
- char *path = fs_path->data;
-
- buffer = rpath(ctx, path);
- fs->dir = opendir(buffer);
- g_free(buffer);
- if (!fs->dir) {
- return -1;
- }
- return 0;
-}
-
-static void local_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
-{
- rewinddir(fs->dir);
-}
-
-static off_t local_telldir(FsContext *ctx, V9fsFidOpenState *fs)
-{
- return telldir(fs->dir);
-}
-
-static int local_readdir_r(FsContext *ctx, V9fsFidOpenState *fs,
- struct dirent *entry,
- struct dirent **result)
-{
- int ret;
-
-again:
- ret = readdir_r(fs->dir, entry, result);
- if (ctx->export_flags & V9FS_SM_MAPPED) {
- entry->d_type = DT_UNKNOWN;
- } else if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
- if (!ret && *result != NULL &&
- !strcmp(entry->d_name, VIRTFS_META_DIR)) {
- /* skp the meta data directory */
- goto again;
- }
- entry->d_type = DT_UNKNOWN;
- }
- return ret;
-}
-
-static void local_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
-{
- seekdir(fs->dir, off);
-}
-
-static ssize_t local_preadv(FsContext *ctx, V9fsFidOpenState *fs,
- const struct iovec *iov,
- int iovcnt, off_t offset)
-{
-#ifdef CONFIG_PREADV
- return preadv(fs->fd, iov, iovcnt, offset);
-#else
- int err = lseek(fs->fd, offset, SEEK_SET);
- if (err == -1) {
- return err;
- } else {
- return readv(fs->fd, iov, iovcnt);
- }
-#endif
-}
-
-static ssize_t local_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
- const struct iovec *iov,
- int iovcnt, off_t offset)
-{
- ssize_t ret
-;
-#ifdef CONFIG_PREADV
- ret = pwritev(fs->fd, iov, iovcnt, offset);
-#else
- int err = lseek(fs->fd, offset, SEEK_SET);
- if (err == -1) {
- return err;
- } else {
- ret = writev(fs->fd, iov, iovcnt);
- }
-#endif
-#ifdef CONFIG_SYNC_FILE_RANGE
- if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) {
- /*
- * Initiate a writeback. This is not a data integrity sync.
- * We want to ensure that we don't leave dirty pages in the cache
- * after write when writeout=immediate is sepcified.
- */
- sync_file_range(fs->fd, offset, ret,
- SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE);
- }
-#endif
- return ret;
-}
-
-static int local_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
-{
- char *buffer;
- int ret = -1;
- char *path = fs_path->data;
-
- if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
- buffer = rpath(fs_ctx, path);
- ret = local_set_xattr(buffer, credp);
- g_free(buffer);
- } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
- return local_set_mapped_file_attr(fs_ctx, path, credp);
- } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
- (fs_ctx->export_flags & V9FS_SM_NONE)) {
- buffer = rpath(fs_ctx, path);
- ret = chmod(buffer, credp->fc_mode);
- g_free(buffer);
- }
- return ret;
-}
-
-static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
- const char *name, FsCred *credp)
-{
- char *path;
- int err = -1;
- int serrno = 0;
- V9fsString fullname;
- char *buffer = NULL;
-
- v9fs_string_init(&fullname);
- v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
- path = fullname.data;
-
- /* Determine the security model */
- if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
- buffer = rpath(fs_ctx, path);
- err = mknod(buffer, SM_LOCAL_MODE_BITS|S_IFREG, 0);
- if (err == -1) {
- goto out;
- }
- err = local_set_xattr(buffer, credp);
- if (err == -1) {
- serrno = errno;
- goto err_end;
- }
- } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
-
- buffer = rpath(fs_ctx, path);
- err = mknod(buffer, SM_LOCAL_MODE_BITS|S_IFREG, 0);
- if (err == -1) {
- goto out;
- }
- err = local_set_mapped_file_attr(fs_ctx, path, credp);
- if (err == -1) {
- serrno = errno;
- goto err_end;
- }
- } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
- (fs_ctx->export_flags & V9FS_SM_NONE)) {
- buffer = rpath(fs_ctx, path);
- err = mknod(buffer, credp->fc_mode, credp->fc_rdev);
- if (err == -1) {
- goto out;
- }
- err = local_post_create_passthrough(fs_ctx, path, credp);
- if (err == -1) {
- serrno = errno;
- goto err_end;
- }
- }
- goto out;
-
-err_end:
- remove(buffer);
- errno = serrno;
-out:
- g_free(buffer);
- v9fs_string_free(&fullname);
- return err;
-}
-
-static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
- const char *name, FsCred *credp)
-{
- char *path;
- int err = -1;
- int serrno = 0;
- V9fsString fullname;
- char *buffer = NULL;
-
- v9fs_string_init(&fullname);
- v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
- path = fullname.data;
-
- /* Determine the security model */
- if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
- buffer = rpath(fs_ctx, path);
- err = mkdir(buffer, SM_LOCAL_DIR_MODE_BITS);
- if (err == -1) {
- goto out;
- }
- credp->fc_mode = credp->fc_mode|S_IFDIR;
- err = local_set_xattr(buffer, credp);
- if (err == -1) {
- serrno = errno;
- goto err_end;
- }
- } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
- buffer = rpath(fs_ctx, path);
- err = mkdir(buffer, SM_LOCAL_DIR_MODE_BITS);
- if (err == -1) {
- goto out;
- }
- credp->fc_mode = credp->fc_mode|S_IFDIR;
- err = local_set_mapped_file_attr(fs_ctx, path, credp);
- if (err == -1) {
- serrno = errno;
- goto err_end;
- }
- } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
- (fs_ctx->export_flags & V9FS_SM_NONE)) {
- buffer = rpath(fs_ctx, path);
- err = mkdir(buffer, credp->fc_mode);
- if (err == -1) {
- goto out;
- }
- err = local_post_create_passthrough(fs_ctx, path, credp);
- if (err == -1) {
- serrno = errno;
- goto err_end;
- }
- }
- goto out;
-
-err_end:
- remove(buffer);
- errno = serrno;
-out:
- g_free(buffer);
- v9fs_string_free(&fullname);
- return err;
-}
-
-static int local_fstat(FsContext *fs_ctx, int fid_type,
- V9fsFidOpenState *fs, struct stat *stbuf)
-{
- int err, fd;
-
- if (fid_type == P9_FID_DIR) {
- fd = dirfd(fs->dir);
- } else {
- fd = fs->fd;
- }
-
- err = fstat(fd, stbuf);
- if (err) {
- return err;
- }
- if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
- /* Actual credentials are part of extended attrs */
- uid_t tmp_uid;
- gid_t tmp_gid;
- mode_t tmp_mode;
- dev_t tmp_dev;
-
- if (fgetxattr(fd, "user.virtfs.uid", &tmp_uid, sizeof(uid_t)) > 0) {
- stbuf->st_uid = le32_to_cpu(tmp_uid);
- }
- if (fgetxattr(fd, "user.virtfs.gid", &tmp_gid, sizeof(gid_t)) > 0) {
- stbuf->st_gid = le32_to_cpu(tmp_gid);
- }
- if (fgetxattr(fd, "user.virtfs.mode", &tmp_mode, sizeof(mode_t)) > 0) {
- stbuf->st_mode = le32_to_cpu(tmp_mode);
- }
- if (fgetxattr(fd, "user.virtfs.rdev", &tmp_dev, sizeof(dev_t)) > 0) {
- stbuf->st_rdev = le64_to_cpu(tmp_dev);
- }
- } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
- errno = EOPNOTSUPP;
- return -1;
- }
- return err;
-}
-
-static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
- int flags, FsCred *credp, V9fsFidOpenState *fs)
-{
- char *path;
- int fd = -1;
- int err = -1;
- int serrno = 0;
- V9fsString fullname;
- char *buffer = NULL;
-
- /*
- * Mark all the open to not follow symlinks
- */
- flags |= O_NOFOLLOW;
-
- v9fs_string_init(&fullname);
- v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
- path = fullname.data;
-
- /* Determine the security model */
- if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
- buffer = rpath(fs_ctx, path);
- fd = open(buffer, flags, SM_LOCAL_MODE_BITS);
- if (fd == -1) {
- err = fd;
- goto out;
- }
- credp->fc_mode = credp->fc_mode|S_IFREG;
- /* Set cleint credentials in xattr */
- err = local_set_xattr(buffer, credp);
- if (err == -1) {
- serrno = errno;
- goto err_end;
- }
- } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
- buffer = rpath(fs_ctx, path);
- fd = open(buffer, flags, SM_LOCAL_MODE_BITS);
- if (fd == -1) {
- err = fd;
- goto out;
- }
- credp->fc_mode = credp->fc_mode|S_IFREG;
- /* Set client credentials in .virtfs_metadata directory files */
- err = local_set_mapped_file_attr(fs_ctx, path, credp);
- if (err == -1) {
- serrno = errno;
- goto err_end;
- }
- } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
- (fs_ctx->export_flags & V9FS_SM_NONE)) {
- buffer = rpath(fs_ctx, path);
- fd = open(buffer, flags, credp->fc_mode);
- if (fd == -1) {
- err = fd;
- goto out;
- }
- err = local_post_create_passthrough(fs_ctx, path, credp);
- if (err == -1) {
- serrno = errno;
- goto err_end;
- }
- }
- err = fd;
- fs->fd = fd;
- goto out;
-
-err_end:
- close(fd);
- remove(buffer);
- errno = serrno;
-out:
- g_free(buffer);
- v9fs_string_free(&fullname);
- return err;
-}
-
-
-static int local_symlink(FsContext *fs_ctx, const char *oldpath,
- V9fsPath *dir_path, const char *name, FsCred *credp)
-{
- int err = -1;
- int serrno = 0;
- char *newpath;
- V9fsString fullname;
- char *buffer = NULL;
-
- v9fs_string_init(&fullname);
- v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
- newpath = fullname.data;
-
- /* Determine the security model */
- if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
- int fd;
- ssize_t oldpath_size, write_size;
- buffer = rpath(fs_ctx, newpath);
- fd = open(buffer, O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW, SM_LOCAL_MODE_BITS);
- if (fd == -1) {
- err = fd;
- goto out;
- }
- /* Write the oldpath (target) to the file. */
- oldpath_size = strlen(oldpath);
- do {
- write_size = write(fd, (void *)oldpath, oldpath_size);
- } while (write_size == -1 && errno == EINTR);
-
- if (write_size != oldpath_size) {
- serrno = errno;
- close(fd);
- err = -1;
- goto err_end;
- }
- close(fd);
- /* Set cleint credentials in symlink's xattr */
- credp->fc_mode = credp->fc_mode|S_IFLNK;
- err = local_set_xattr(buffer, credp);
- if (err == -1) {
- serrno = errno;
- goto err_end;
- }
- } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
- int fd;
- ssize_t oldpath_size, write_size;
- buffer = rpath(fs_ctx, newpath);
- fd = open(buffer, O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW, SM_LOCAL_MODE_BITS);
- if (fd == -1) {
- err = fd;
- goto out;
- }
- /* Write the oldpath (target) to the file. */
- oldpath_size = strlen(oldpath);
- do {
- write_size = write(fd, (void *)oldpath, oldpath_size);
- } while (write_size == -1 && errno == EINTR);
-
- if (write_size != oldpath_size) {
- serrno = errno;
- close(fd);
- err = -1;
- goto err_end;
- }
- close(fd);
- /* Set cleint credentials in symlink's xattr */
- credp->fc_mode = credp->fc_mode|S_IFLNK;
- err = local_set_mapped_file_attr(fs_ctx, newpath, credp);
- if (err == -1) {
- serrno = errno;
- goto err_end;
- }
- } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
- (fs_ctx->export_flags & V9FS_SM_NONE)) {
- buffer = rpath(fs_ctx, newpath);
- err = symlink(oldpath, buffer);
- if (err) {
- goto out;
- }
- err = lchown(buffer, credp->fc_uid, credp->fc_gid);
- if (err == -1) {
- /*
- * If we fail to change ownership and if we are
- * using security model none. Ignore the error
- */
- if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) {
- serrno = errno;
- goto err_end;
- } else
- err = 0;
- }
- }
- goto out;
-
-err_end:
- remove(buffer);
- errno = serrno;
-out:
- g_free(buffer);
- v9fs_string_free(&fullname);
- return err;
-}
-
-static int local_link(FsContext *ctx, V9fsPath *oldpath,
- V9fsPath *dirpath, const char *name)
-{
- int ret;
- V9fsString newpath;
- char *buffer, *buffer1;
-
- v9fs_string_init(&newpath);
- v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name);
-
- buffer = rpath(ctx, oldpath->data);
- buffer1 = rpath(ctx, newpath.data);
- ret = link(buffer, buffer1);
- g_free(buffer);
- g_free(buffer1);
-
- /* now link the virtfs_metadata files */
- if (!ret && (ctx->export_flags & V9FS_SM_MAPPED_FILE)) {
- /* Link the .virtfs_metadata files. Create the metada directory */
- ret = local_create_mapped_attr_dir(ctx, newpath.data);
- if (ret < 0) {
- goto err_out;
- }
- buffer = local_mapped_attr_path(ctx, oldpath->data);
- buffer1 = local_mapped_attr_path(ctx, newpath.data);
- ret = link(buffer, buffer1);
- g_free(buffer);
- g_free(buffer1);
- if (ret < 0 && errno != ENOENT) {
- goto err_out;
- }
- }
-err_out:
- v9fs_string_free(&newpath);
- return ret;
-}
-
-static int local_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
-{
- char *buffer;
- int ret;
- char *path = fs_path->data;
-
- buffer = rpath(ctx, path);
- ret = truncate(buffer, size);
- g_free(buffer);
- return ret;
-}
-
-static int local_rename(FsContext *ctx, const char *oldpath,
- const char *newpath)
-{
- int err;
- char *buffer, *buffer1;
-
- if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
- err = local_create_mapped_attr_dir(ctx, newpath);
- if (err < 0) {
- return err;
- }
- /* rename the .virtfs_metadata files */
- buffer = local_mapped_attr_path(ctx, oldpath);
- buffer1 = local_mapped_attr_path(ctx, newpath);
- err = rename(buffer, buffer1);
- g_free(buffer);
- g_free(buffer1);
- if (err < 0 && errno != ENOENT) {
- return err;
- }
- }
-
- buffer = rpath(ctx, oldpath);
- buffer1 = rpath(ctx, newpath);
- err = rename(buffer, buffer1);
- g_free(buffer);
- g_free(buffer1);
- return err;
-}
-
-static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
-{
- char *buffer;
- int ret = -1;
- char *path = fs_path->data;
-
- if ((credp->fc_uid == -1 && credp->fc_gid == -1) ||
- (fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
- (fs_ctx->export_flags & V9FS_SM_NONE)) {
- buffer = rpath(fs_ctx, path);
- ret = lchown(buffer, credp->fc_uid, credp->fc_gid);
- g_free(buffer);
- } else if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
- buffer = rpath(fs_ctx, path);
- ret = local_set_xattr(buffer, credp);
- g_free(buffer);
- } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
- return local_set_mapped_file_attr(fs_ctx, path, credp);
- }
- return ret;
-}
-
-static int local_utimensat(FsContext *s, V9fsPath *fs_path,
- const struct timespec *buf)
-{
- char *buffer;
- int ret;
- char *path = fs_path->data;
-
- buffer = rpath(s, path);
- ret = qemu_utimens(buffer, buf);
- g_free(buffer);
- return ret;
-}
-
-static int local_remove(FsContext *ctx, const char *path)
-{
- int err;
- struct stat stbuf;
- char *buffer;
-
- if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
- buffer = rpath(ctx, path);
- err = lstat(buffer, &stbuf);
- g_free(buffer);
- if (err) {
- goto err_out;
- }
- /*
- * If directory remove .virtfs_metadata contained in the
- * directory
- */
- if (S_ISDIR(stbuf.st_mode)) {
- buffer = g_strdup_printf("%s/%s/%s", ctx->fs_root,
- path, VIRTFS_META_DIR);
- err = remove(buffer);
- g_free(buffer);
- if (err < 0 && errno != ENOENT) {
- /*
- * We didn't had the .virtfs_metadata file. May be file created
- * in non-mapped mode ?. Ignore ENOENT.
- */
- goto err_out;
- }
- }
- /*
- * Now remove the name from parent directory
- * .virtfs_metadata directory
- */
- buffer = local_mapped_attr_path(ctx, path);
- err = remove(buffer);
- g_free(buffer);
- if (err < 0 && errno != ENOENT) {
- /*
- * We didn't had the .virtfs_metadata file. May be file created
- * in non-mapped mode ?. Ignore ENOENT.
- */
- goto err_out;
- }
- }
-
- buffer = rpath(ctx, path);
- err = remove(buffer);
- g_free(buffer);
-err_out:
- return err;
-}
-
-static int local_fsync(FsContext *ctx, int fid_type,
- V9fsFidOpenState *fs, int datasync)
-{
- int fd;
-
- if (fid_type == P9_FID_DIR) {
- fd = dirfd(fs->dir);
- } else {
- fd = fs->fd;
- }
-
- if (datasync) {
- return qemu_fdatasync(fd);
- } else {
- return fsync(fd);
- }
-}
-
-static int local_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf)
-{
- char *buffer;
- int ret;
- char *path = fs_path->data;
-
- buffer = rpath(s, path);
- ret = statfs(buffer, stbuf);
- g_free(buffer);
- return ret;
-}
-
-static ssize_t local_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
- const char *name, void *value, size_t size)
-{
- char *path = fs_path->data;
-
- return v9fs_get_xattr(ctx, path, name, value, size);
-}
-
-static ssize_t local_llistxattr(FsContext *ctx, V9fsPath *fs_path,
- void *value, size_t size)
-{
- char *path = fs_path->data;
-
- return v9fs_list_xattr(ctx, path, value, size);
-}
-
-static int local_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name,
- void *value, size_t size, int flags)
-{
- char *path = fs_path->data;
-
- return v9fs_set_xattr(ctx, path, name, value, size, flags);
-}
-
-static int local_lremovexattr(FsContext *ctx, V9fsPath *fs_path,
- const char *name)
-{
- char *path = fs_path->data;
-
- return v9fs_remove_xattr(ctx, path, name);
-}
-
-static int local_name_to_path(FsContext *ctx, V9fsPath *dir_path,
- const char *name, V9fsPath *target)
-{
- if (dir_path) {
- v9fs_string_sprintf((V9fsString *)target, "%s/%s",
- dir_path->data, name);
- } else {
- v9fs_string_sprintf((V9fsString *)target, "%s", name);
- }
- /* Bump the size for including terminating NULL */
- target->size++;
- return 0;
-}
-
-static int local_renameat(FsContext *ctx, V9fsPath *olddir,
- const char *old_name, V9fsPath *newdir,
- const char *new_name)
-{
- int ret;
- V9fsString old_full_name, new_full_name;
-
- v9fs_string_init(&old_full_name);
- v9fs_string_init(&new_full_name);
-
- v9fs_string_sprintf(&old_full_name, "%s/%s", olddir->data, old_name);
- v9fs_string_sprintf(&new_full_name, "%s/%s", newdir->data, new_name);
-
- ret = local_rename(ctx, old_full_name.data, new_full_name.data);
- v9fs_string_free(&old_full_name);
- v9fs_string_free(&new_full_name);
- return ret;
-}
-
-static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
- const char *name, int flags)
-{
- int ret;
- V9fsString fullname;
- char *buffer;
-
- v9fs_string_init(&fullname);
-
- v9fs_string_sprintf(&fullname, "%s/%s", dir->data, name);
- if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
- if (flags == AT_REMOVEDIR) {
- /*
- * If directory remove .virtfs_metadata contained in the
- * directory
- */
- buffer = g_strdup_printf("%s/%s/%s", ctx->fs_root,
- fullname.data, VIRTFS_META_DIR);
- ret = remove(buffer);
- g_free(buffer);
- if (ret < 0 && errno != ENOENT) {
- /*
- * We didn't had the .virtfs_metadata file. May be file created
- * in non-mapped mode ?. Ignore ENOENT.
- */
- goto err_out;
- }
- }
- /*
- * Now remove the name from parent directory
- * .virtfs_metadata directory.
- */
- buffer = local_mapped_attr_path(ctx, fullname.data);
- ret = remove(buffer);
- g_free(buffer);
- if (ret < 0 && errno != ENOENT) {
- /*
- * We didn't had the .virtfs_metadata file. May be file created
- * in non-mapped mode ?. Ignore ENOENT.
- */
- goto err_out;
- }
- }
- /* Remove the name finally */
- buffer = rpath(ctx, fullname.data);
- ret = remove(buffer);
- g_free(buffer);
-
-err_out:
- v9fs_string_free(&fullname);
- return ret;
-}
-
-static int local_ioc_getversion(FsContext *ctx, V9fsPath *path,
- mode_t st_mode, uint64_t *st_gen)
-{
-#ifdef FS_IOC_GETVERSION
- int err;
- V9fsFidOpenState fid_open;
-
- /*
- * Do not try to open special files like device nodes, fifos etc
- * We can get fd for regular files and directories only
- */
- if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) {
- errno = ENOTTY;
- return -1;
- }
- err = local_open(ctx, path, O_RDONLY, &fid_open);
- if (err < 0) {
- return err;
- }
- err = ioctl(fid_open.fd, FS_IOC_GETVERSION, st_gen);
- local_close(ctx, &fid_open);
- return err;
-#else
- errno = ENOTTY;
- return -1;
-#endif
-}
-
-static int local_init(FsContext *ctx)
-{
- int err = 0;
- struct statfs stbuf;
-
- if (ctx->export_flags & V9FS_SM_PASSTHROUGH) {
- ctx->xops = passthrough_xattr_ops;
- } else if (ctx->export_flags & V9FS_SM_MAPPED) {
- ctx->xops = mapped_xattr_ops;
- } else if (ctx->export_flags & V9FS_SM_NONE) {
- ctx->xops = none_xattr_ops;
- } else if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
- /*
- * xattr operation for mapped-file and passthrough
- * remain same.
- */
- ctx->xops = passthrough_xattr_ops;
- }
- ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT;
-#ifdef FS_IOC_GETVERSION
- /*
- * use ioc_getversion only if the iocl is definied
- */
- err = statfs(ctx->fs_root, &stbuf);
- if (!err) {
- switch (stbuf.f_type) {
- case EXT2_SUPER_MAGIC:
- case BTRFS_SUPER_MAGIC:
- case REISERFS_SUPER_MAGIC:
- case XFS_SUPER_MAGIC:
- ctx->exops.get_st_gen = local_ioc_getversion;
- break;
- }
- }
-#endif
- return err;
-}
-
-static int local_parse_opts(QemuOpts *opts, struct FsDriverEntry *fse)
-{
- const char *sec_model = qemu_opt_get(opts, "security_model");
- const char *path = qemu_opt_get(opts, "path");
-
- if (!sec_model) {
- error_report("Security model not specified, local fs needs security model");
- error_printf("valid options are:"
- "\tsecurity_model=[passthrough|mapped-xattr|mapped-file|none]\n");
- return -1;
- }
-
- if (!strcmp(sec_model, "passthrough")) {
- fse->export_flags |= V9FS_SM_PASSTHROUGH;
- } else if (!strcmp(sec_model, "mapped") ||
- !strcmp(sec_model, "mapped-xattr")) {
- fse->export_flags |= V9FS_SM_MAPPED;
- } else if (!strcmp(sec_model, "none")) {
- fse->export_flags |= V9FS_SM_NONE;
- } else if (!strcmp(sec_model, "mapped-file")) {
- fse->export_flags |= V9FS_SM_MAPPED_FILE;
- } else {
- error_report("Invalid security model %s specified", sec_model);
- error_printf("valid options are:"
- "\t[passthrough|mapped-xattr|mapped-file|none]\n");
- return -1;
- }
-
- if (!path) {
- error_report("fsdev: No path specified");
- return -1;
- }
- fse->path = g_strdup(path);
-
- return 0;
-}
-
-FileOperations local_ops = {
- .parse_opts = local_parse_opts,
- .init = local_init,
- .lstat = local_lstat,
- .readlink = local_readlink,
- .close = local_close,
- .closedir = local_closedir,
- .open = local_open,
- .opendir = local_opendir,
- .rewinddir = local_rewinddir,
- .telldir = local_telldir,
- .readdir_r = local_readdir_r,
- .seekdir = local_seekdir,
- .preadv = local_preadv,
- .pwritev = local_pwritev,
- .chmod = local_chmod,
- .mknod = local_mknod,
- .mkdir = local_mkdir,
- .fstat = local_fstat,
- .open2 = local_open2,
- .symlink = local_symlink,
- .link = local_link,
- .truncate = local_truncate,
- .rename = local_rename,
- .chown = local_chown,
- .utimensat = local_utimensat,
- .remove = local_remove,
- .fsync = local_fsync,
- .statfs = local_statfs,
- .lgetxattr = local_lgetxattr,
- .llistxattr = local_llistxattr,
- .lsetxattr = local_lsetxattr,
- .lremovexattr = local_lremovexattr,
- .name_to_path = local_name_to_path,
- .renameat = local_renameat,
- .unlinkat = local_unlinkat,
-};
diff --git a/qemu/hw/9pfs/9p-posix-acl.c b/qemu/hw/9pfs/9p-posix-acl.c
deleted file mode 100644
index ec003181c..000000000
--- a/qemu/hw/9pfs/9p-posix-acl.c
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * 9p system.posix* xattr callback
- *
- * Copyright IBM, Corp. 2010
- *
- * Authors:
- * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "qemu/xattr.h"
-#include "9p.h"
-#include "fsdev/file-op-9p.h"
-#include "9p-xattr.h"
-
-#define MAP_ACL_ACCESS "user.virtfs.system.posix_acl_access"
-#define MAP_ACL_DEFAULT "user.virtfs.system.posix_acl_default"
-#define ACL_ACCESS "system.posix_acl_access"
-#define ACL_DEFAULT "system.posix_acl_default"
-
-static ssize_t mp_pacl_getxattr(FsContext *ctx, const char *path,
- const char *name, void *value, size_t size)
-{
- char *buffer;
- ssize_t ret;
-
- buffer = rpath(ctx, path);
- ret = lgetxattr(buffer, MAP_ACL_ACCESS, value, size);
- g_free(buffer);
- return ret;
-}
-
-static ssize_t mp_pacl_listxattr(FsContext *ctx, const char *path,
- char *name, void *value, size_t osize)
-{
- ssize_t len = sizeof(ACL_ACCESS);
-
- if (!value) {
- return len;
- }
-
- if (osize < len) {
- errno = ERANGE;
- return -1;
- }
-
- /* len includes the trailing NUL */
- memcpy(value, ACL_ACCESS, len);
- return 0;
-}
-
-static int mp_pacl_setxattr(FsContext *ctx, const char *path, const char *name,
- void *value, size_t size, int flags)
-{
- char *buffer;
- int ret;
-
- buffer = rpath(ctx, path);
- ret = lsetxattr(buffer, MAP_ACL_ACCESS, value, size, flags);
- g_free(buffer);
- return ret;
-}
-
-static int mp_pacl_removexattr(FsContext *ctx,
- const char *path, const char *name)
-{
- int ret;
- char *buffer;
-
- buffer = rpath(ctx, path);
- ret = lremovexattr(buffer, MAP_ACL_ACCESS);
- if (ret == -1 && errno == ENODATA) {
- /*
- * We don't get ENODATA error when trying to remove a
- * posix acl that is not present. So don't throw the error
- * even in case of mapped security model
- */
- errno = 0;
- ret = 0;
- }
- g_free(buffer);
- return ret;
-}
-
-static ssize_t mp_dacl_getxattr(FsContext *ctx, const char *path,
- const char *name, void *value, size_t size)
-{
- char *buffer;
- ssize_t ret;
-
- buffer = rpath(ctx, path);
- ret = lgetxattr(buffer, MAP_ACL_DEFAULT, value, size);
- g_free(buffer);
- return ret;
-}
-
-static ssize_t mp_dacl_listxattr(FsContext *ctx, const char *path,
- char *name, void *value, size_t osize)
-{
- ssize_t len = sizeof(ACL_DEFAULT);
-
- if (!value) {
- return len;
- }
-
- if (osize < len) {
- errno = ERANGE;
- return -1;
- }
-
- /* len includes the trailing NUL */
- memcpy(value, ACL_DEFAULT, len);
- return 0;
-}
-
-static int mp_dacl_setxattr(FsContext *ctx, const char *path, const char *name,
- void *value, size_t size, int flags)
-{
- char *buffer;
- int ret;
-
- buffer = rpath(ctx, path);
- ret = lsetxattr(buffer, MAP_ACL_DEFAULT, value, size, flags);
- g_free(buffer);
- return ret;
-}
-
-static int mp_dacl_removexattr(FsContext *ctx,
- const char *path, const char *name)
-{
- int ret;
- char *buffer;
-
- buffer = rpath(ctx, path);
- ret = lremovexattr(buffer, MAP_ACL_DEFAULT);
- if (ret == -1 && errno == ENODATA) {
- /*
- * We don't get ENODATA error when trying to remove a
- * posix acl that is not present. So don't throw the error
- * even in case of mapped security model
- */
- errno = 0;
- ret = 0;
- }
- g_free(buffer);
- return ret;
-}
-
-
-XattrOperations mapped_pacl_xattr = {
- .name = "system.posix_acl_access",
- .getxattr = mp_pacl_getxattr,
- .setxattr = mp_pacl_setxattr,
- .listxattr = mp_pacl_listxattr,
- .removexattr = mp_pacl_removexattr,
-};
-
-XattrOperations mapped_dacl_xattr = {
- .name = "system.posix_acl_default",
- .getxattr = mp_dacl_getxattr,
- .setxattr = mp_dacl_setxattr,
- .listxattr = mp_dacl_listxattr,
- .removexattr = mp_dacl_removexattr,
-};
-
-XattrOperations passthrough_acl_xattr = {
- .name = "system.posix_acl_",
- .getxattr = pt_getxattr,
- .setxattr = pt_setxattr,
- .listxattr = pt_listxattr,
- .removexattr = pt_removexattr,
-};
-
-XattrOperations none_acl_xattr = {
- .name = "system.posix_acl_",
- .getxattr = notsup_getxattr,
- .setxattr = notsup_setxattr,
- .listxattr = notsup_listxattr,
- .removexattr = notsup_removexattr,
-};
diff --git a/qemu/hw/9pfs/9p-proxy.c b/qemu/hw/9pfs/9p-proxy.c
deleted file mode 100644
index 00a4eb2a7..000000000
--- a/qemu/hw/9pfs/9p-proxy.c
+++ /dev/null
@@ -1,1220 +0,0 @@
-/*
- * 9p Proxy callback
- *
- * Copyright IBM, Corp. 2011
- *
- * Authors:
- * M. Mohan Kumar <mohan@in.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- */
-#include "qemu/osdep.h"
-#include <sys/socket.h>
-#include <sys/un.h>
-#include "9p.h"
-#include "qemu/cutils.h"
-#include "qemu/error-report.h"
-#include "fsdev/qemu-fsdev.h"
-#include "9p-proxy.h"
-
-typedef struct V9fsProxy {
- int sockfd;
- QemuMutex mutex;
- struct iovec in_iovec;
- struct iovec out_iovec;
-} V9fsProxy;
-
-/*
- * Return received file descriptor on success in *status.
- * errno is also returned on *status (which will be < 0)
- * return < 0 on transport error.
- */
-static int v9fs_receivefd(int sockfd, int *status)
-{
- struct iovec iov;
- struct msghdr msg;
- struct cmsghdr *cmsg;
- int retval, data, fd;
- union MsgControl msg_control;
-
- iov.iov_base = &data;
- iov.iov_len = sizeof(data);
-
- memset(&msg, 0, sizeof(msg));
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_control = &msg_control;
- msg.msg_controllen = sizeof(msg_control);
-
- do {
- retval = recvmsg(sockfd, &msg, 0);
- } while (retval < 0 && errno == EINTR);
- if (retval <= 0) {
- return retval;
- }
- /*
- * data is set to V9FS_FD_VALID, if ancillary data is sent. If this
- * request doesn't need ancillary data (fd) or an error occurred,
- * data is set to negative errno value.
- */
- if (data != V9FS_FD_VALID) {
- *status = data;
- return 0;
- }
- /*
- * File descriptor (fd) is sent in the ancillary data. Check if we
- * indeed received it. One of the reasons to fail to receive it is if
- * we exceeded the maximum number of file descriptors!
- */
- for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
- if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)) ||
- cmsg->cmsg_level != SOL_SOCKET ||
- cmsg->cmsg_type != SCM_RIGHTS) {
- continue;
- }
- fd = *((int *)CMSG_DATA(cmsg));
- *status = fd;
- return 0;
- }
- *status = -ENFILE; /* Ancillary data sent but not received */
- return 0;
-}
-
-static ssize_t socket_read(int sockfd, void *buff, size_t size)
-{
- ssize_t retval, total = 0;
-
- while (size) {
- retval = read(sockfd, buff, size);
- if (retval == 0) {
- return -EIO;
- }
- if (retval < 0) {
- if (errno == EINTR) {
- continue;
- }
- return -errno;
- }
- size -= retval;
- buff += retval;
- total += retval;
- }
- return total;
-}
-
-/* Converts proxy_statfs to VFS statfs structure */
-static void prstatfs_to_statfs(struct statfs *stfs, ProxyStatFS *prstfs)
-{
- memset(stfs, 0, sizeof(*stfs));
- stfs->f_type = prstfs->f_type;
- stfs->f_bsize = prstfs->f_bsize;
- stfs->f_blocks = prstfs->f_blocks;
- stfs->f_bfree = prstfs->f_bfree;
- stfs->f_bavail = prstfs->f_bavail;
- stfs->f_files = prstfs->f_files;
- stfs->f_ffree = prstfs->f_ffree;
- stfs->f_fsid.__val[0] = prstfs->f_fsid[0] & 0xFFFFFFFFU;
- stfs->f_fsid.__val[1] = prstfs->f_fsid[1] >> 32 & 0xFFFFFFFFU;
- stfs->f_namelen = prstfs->f_namelen;
- stfs->f_frsize = prstfs->f_frsize;
-}
-
-/* Converts proxy_stat structure to VFS stat structure */
-static void prstat_to_stat(struct stat *stbuf, ProxyStat *prstat)
-{
- memset(stbuf, 0, sizeof(*stbuf));
- stbuf->st_dev = prstat->st_dev;
- stbuf->st_ino = prstat->st_ino;
- stbuf->st_nlink = prstat->st_nlink;
- stbuf->st_mode = prstat->st_mode;
- stbuf->st_uid = prstat->st_uid;
- stbuf->st_gid = prstat->st_gid;
- stbuf->st_rdev = prstat->st_rdev;
- stbuf->st_size = prstat->st_size;
- stbuf->st_blksize = prstat->st_blksize;
- stbuf->st_blocks = prstat->st_blocks;
- stbuf->st_atim.tv_sec = prstat->st_atim_sec;
- stbuf->st_atim.tv_nsec = prstat->st_atim_nsec;
- stbuf->st_mtime = prstat->st_mtim_sec;
- stbuf->st_mtim.tv_nsec = prstat->st_mtim_nsec;
- stbuf->st_ctime = prstat->st_ctim_sec;
- stbuf->st_ctim.tv_nsec = prstat->st_ctim_nsec;
-}
-
-/*
- * Response contains two parts
- * {header, data}
- * header.type == T_ERROR, data -> -errno
- * header.type == T_SUCCESS, data -> response
- * size of errno/response is given by header.size
- * returns < 0, on transport error. response is
- * valid only if status >= 0.
- */
-static int v9fs_receive_response(V9fsProxy *proxy, int type,
- int *status, void *response)
-{
- int retval;
- ProxyHeader header;
- struct iovec *reply = &proxy->in_iovec;
-
- *status = 0;
- reply->iov_len = 0;
- retval = socket_read(proxy->sockfd, reply->iov_base, PROXY_HDR_SZ);
- if (retval < 0) {
- return retval;
- }
- reply->iov_len = PROXY_HDR_SZ;
- proxy_unmarshal(reply, 0, "dd", &header.type, &header.size);
- /*
- * if response size > PROXY_MAX_IO_SZ, read the response but ignore it and
- * return -ENOBUFS
- */
- if (header.size > PROXY_MAX_IO_SZ) {
- int count;
- while (header.size > 0) {
- count = MIN(PROXY_MAX_IO_SZ, header.size);
- count = socket_read(proxy->sockfd, reply->iov_base, count);
- if (count < 0) {
- return count;
- }
- header.size -= count;
- }
- *status = -ENOBUFS;
- return 0;
- }
-
- retval = socket_read(proxy->sockfd,
- reply->iov_base + PROXY_HDR_SZ, header.size);
- if (retval < 0) {
- return retval;
- }
- reply->iov_len += header.size;
- /* there was an error during processing request */
- if (header.type == T_ERROR) {
- int ret;
- ret = proxy_unmarshal(reply, PROXY_HDR_SZ, "d", status);
- if (ret < 0) {
- *status = ret;
- }
- return 0;
- }
-
- switch (type) {
- case T_LSTAT: {
- ProxyStat prstat;
- retval = proxy_unmarshal(reply, PROXY_HDR_SZ,
- "qqqdddqqqqqqqqqq", &prstat.st_dev,
- &prstat.st_ino, &prstat.st_nlink,
- &prstat.st_mode, &prstat.st_uid,
- &prstat.st_gid, &prstat.st_rdev,
- &prstat.st_size, &prstat.st_blksize,
- &prstat.st_blocks,
- &prstat.st_atim_sec, &prstat.st_atim_nsec,
- &prstat.st_mtim_sec, &prstat.st_mtim_nsec,
- &prstat.st_ctim_sec, &prstat.st_ctim_nsec);
- prstat_to_stat(response, &prstat);
- break;
- }
- case T_STATFS: {
- ProxyStatFS prstfs;
- retval = proxy_unmarshal(reply, PROXY_HDR_SZ,
- "qqqqqqqqqqq", &prstfs.f_type,
- &prstfs.f_bsize, &prstfs.f_blocks,
- &prstfs.f_bfree, &prstfs.f_bavail,
- &prstfs.f_files, &prstfs.f_ffree,
- &prstfs.f_fsid[0], &prstfs.f_fsid[1],
- &prstfs.f_namelen, &prstfs.f_frsize);
- prstatfs_to_statfs(response, &prstfs);
- break;
- }
- case T_READLINK: {
- V9fsString target;
- v9fs_string_init(&target);
- retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "s", &target);
- strcpy(response, target.data);
- v9fs_string_free(&target);
- break;
- }
- case T_LGETXATTR:
- case T_LLISTXATTR: {
- V9fsString xattr;
- v9fs_string_init(&xattr);
- retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "s", &xattr);
- memcpy(response, xattr.data, xattr.size);
- v9fs_string_free(&xattr);
- break;
- }
- case T_GETVERSION:
- proxy_unmarshal(reply, PROXY_HDR_SZ, "q", response);
- break;
- default:
- return -1;
- }
- if (retval < 0) {
- *status = retval;
- }
- return 0;
-}
-
-/*
- * return < 0 on transport error.
- * *status is valid only if return >= 0
- */
-static int v9fs_receive_status(V9fsProxy *proxy,
- struct iovec *reply, int *status)
-{
- int retval;
- ProxyHeader header;
-
- *status = 0;
- reply->iov_len = 0;
- retval = socket_read(proxy->sockfd, reply->iov_base, PROXY_HDR_SZ);
- if (retval < 0) {
- return retval;
- }
- reply->iov_len = PROXY_HDR_SZ;
- proxy_unmarshal(reply, 0, "dd", &header.type, &header.size);
- if (header.size != sizeof(int)) {
- *status = -ENOBUFS;
- return 0;
- }
- retval = socket_read(proxy->sockfd,
- reply->iov_base + PROXY_HDR_SZ, header.size);
- if (retval < 0) {
- return retval;
- }
- reply->iov_len += header.size;
- proxy_unmarshal(reply, PROXY_HDR_SZ, "d", status);
- return 0;
-}
-
-/*
- * Proxy->header and proxy->request written to socket by QEMU process.
- * This request read by proxy helper process
- * returns 0 on success and -errno on error
- */
-static int v9fs_request(V9fsProxy *proxy, int type,
- void *response, const char *fmt, ...)
-{
- dev_t rdev;
- va_list ap;
- int size = 0;
- int retval = 0;
- uint64_t offset;
- ProxyHeader header = { 0, 0};
- struct timespec spec[2];
- int flags, mode, uid, gid;
- V9fsString *name, *value;
- V9fsString *path, *oldpath;
- struct iovec *iovec = NULL, *reply = NULL;
-
- qemu_mutex_lock(&proxy->mutex);
-
- if (proxy->sockfd == -1) {
- retval = -EIO;
- goto err_out;
- }
- iovec = &proxy->out_iovec;
- reply = &proxy->in_iovec;
- va_start(ap, fmt);
- switch (type) {
- case T_OPEN:
- path = va_arg(ap, V9fsString *);
- flags = va_arg(ap, int);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sd", path, flags);
- if (retval > 0) {
- header.size = retval;
- header.type = T_OPEN;
- }
- break;
- case T_CREATE:
- path = va_arg(ap, V9fsString *);
- flags = va_arg(ap, int);
- mode = va_arg(ap, int);
- uid = va_arg(ap, int);
- gid = va_arg(ap, int);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sdddd", path,
- flags, mode, uid, gid);
- if (retval > 0) {
- header.size = retval;
- header.type = T_CREATE;
- }
- break;
- case T_MKNOD:
- path = va_arg(ap, V9fsString *);
- mode = va_arg(ap, int);
- rdev = va_arg(ap, long int);
- uid = va_arg(ap, int);
- gid = va_arg(ap, int);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ddsdq",
- uid, gid, path, mode, rdev);
- if (retval > 0) {
- header.size = retval;
- header.type = T_MKNOD;
- }
- break;
- case T_MKDIR:
- path = va_arg(ap, V9fsString *);
- mode = va_arg(ap, int);
- uid = va_arg(ap, int);
- gid = va_arg(ap, int);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ddsd",
- uid, gid, path, mode);
- if (retval > 0) {
- header.size = retval;
- header.type = T_MKDIR;
- }
- break;
- case T_SYMLINK:
- oldpath = va_arg(ap, V9fsString *);
- path = va_arg(ap, V9fsString *);
- uid = va_arg(ap, int);
- gid = va_arg(ap, int);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ddss",
- uid, gid, oldpath, path);
- if (retval > 0) {
- header.size = retval;
- header.type = T_SYMLINK;
- }
- break;
- case T_LINK:
- oldpath = va_arg(ap, V9fsString *);
- path = va_arg(ap, V9fsString *);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ss",
- oldpath, path);
- if (retval > 0) {
- header.size = retval;
- header.type = T_LINK;
- }
- break;
- case T_LSTAT:
- path = va_arg(ap, V9fsString *);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "s", path);
- if (retval > 0) {
- header.size = retval;
- header.type = T_LSTAT;
- }
- break;
- case T_READLINK:
- path = va_arg(ap, V9fsString *);
- size = va_arg(ap, int);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sd", path, size);
- if (retval > 0) {
- header.size = retval;
- header.type = T_READLINK;
- }
- break;
- case T_STATFS:
- path = va_arg(ap, V9fsString *);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "s", path);
- if (retval > 0) {
- header.size = retval;
- header.type = T_STATFS;
- }
- break;
- case T_CHMOD:
- path = va_arg(ap, V9fsString *);
- mode = va_arg(ap, int);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sd", path, mode);
- if (retval > 0) {
- header.size = retval;
- header.type = T_CHMOD;
- }
- break;
- case T_CHOWN:
- path = va_arg(ap, V9fsString *);
- uid = va_arg(ap, int);
- gid = va_arg(ap, int);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sdd", path, uid, gid);
- if (retval > 0) {
- header.size = retval;
- header.type = T_CHOWN;
- }
- break;
- case T_TRUNCATE:
- path = va_arg(ap, V9fsString *);
- offset = va_arg(ap, uint64_t);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sq", path, offset);
- if (retval > 0) {
- header.size = retval;
- header.type = T_TRUNCATE;
- }
- break;
- case T_UTIME:
- path = va_arg(ap, V9fsString *);
- spec[0].tv_sec = va_arg(ap, long);
- spec[0].tv_nsec = va_arg(ap, long);
- spec[1].tv_sec = va_arg(ap, long);
- spec[1].tv_nsec = va_arg(ap, long);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sqqqq", path,
- spec[0].tv_sec, spec[1].tv_nsec,
- spec[1].tv_sec, spec[1].tv_nsec);
- if (retval > 0) {
- header.size = retval;
- header.type = T_UTIME;
- }
- break;
- case T_RENAME:
- oldpath = va_arg(ap, V9fsString *);
- path = va_arg(ap, V9fsString *);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ss", oldpath, path);
- if (retval > 0) {
- header.size = retval;
- header.type = T_RENAME;
- }
- break;
- case T_REMOVE:
- path = va_arg(ap, V9fsString *);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "s", path);
- if (retval > 0) {
- header.size = retval;
- header.type = T_REMOVE;
- }
- break;
- case T_LGETXATTR:
- size = va_arg(ap, int);
- path = va_arg(ap, V9fsString *);
- name = va_arg(ap, V9fsString *);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ,
- "dss", size, path, name);
- if (retval > 0) {
- header.size = retval;
- header.type = T_LGETXATTR;
- }
- break;
- case T_LLISTXATTR:
- size = va_arg(ap, int);
- path = va_arg(ap, V9fsString *);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ds", size, path);
- if (retval > 0) {
- header.size = retval;
- header.type = T_LLISTXATTR;
- }
- break;
- case T_LSETXATTR:
- path = va_arg(ap, V9fsString *);
- name = va_arg(ap, V9fsString *);
- value = va_arg(ap, V9fsString *);
- size = va_arg(ap, int);
- flags = va_arg(ap, int);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sssdd",
- path, name, value, size, flags);
- if (retval > 0) {
- header.size = retval;
- header.type = T_LSETXATTR;
- }
- break;
- case T_LREMOVEXATTR:
- path = va_arg(ap, V9fsString *);
- name = va_arg(ap, V9fsString *);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ss", path, name);
- if (retval > 0) {
- header.size = retval;
- header.type = T_LREMOVEXATTR;
- }
- break;
- case T_GETVERSION:
- path = va_arg(ap, V9fsString *);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "s", path);
- if (retval > 0) {
- header.size = retval;
- header.type = T_GETVERSION;
- }
- break;
- default:
- error_report("Invalid type %d", type);
- retval = -EINVAL;
- break;
- }
- va_end(ap);
-
- if (retval < 0) {
- goto err_out;
- }
-
- /* marshal the header details */
- proxy_marshal(iovec, 0, "dd", header.type, header.size);
- header.size += PROXY_HDR_SZ;
-
- retval = qemu_write_full(proxy->sockfd, iovec->iov_base, header.size);
- if (retval != header.size) {
- goto close_error;
- }
-
- switch (type) {
- case T_OPEN:
- case T_CREATE:
- /*
- * A file descriptor is returned as response for
- * T_OPEN,T_CREATE on success
- */
- if (v9fs_receivefd(proxy->sockfd, &retval) < 0) {
- goto close_error;
- }
- break;
- case T_MKNOD:
- case T_MKDIR:
- case T_SYMLINK:
- case T_LINK:
- case T_CHMOD:
- case T_CHOWN:
- case T_RENAME:
- case T_TRUNCATE:
- case T_UTIME:
- case T_REMOVE:
- case T_LSETXATTR:
- case T_LREMOVEXATTR:
- if (v9fs_receive_status(proxy, reply, &retval) < 0) {
- goto close_error;
- }
- break;
- case T_LSTAT:
- case T_READLINK:
- case T_STATFS:
- case T_GETVERSION:
- if (v9fs_receive_response(proxy, type, &retval, response) < 0) {
- goto close_error;
- }
- break;
- case T_LGETXATTR:
- case T_LLISTXATTR:
- if (!size) {
- if (v9fs_receive_status(proxy, reply, &retval) < 0) {
- goto close_error;
- }
- } else {
- if (v9fs_receive_response(proxy, type, &retval, response) < 0) {
- goto close_error;
- }
- }
- break;
- }
-
-err_out:
- qemu_mutex_unlock(&proxy->mutex);
- return retval;
-
-close_error:
- close(proxy->sockfd);
- proxy->sockfd = -1;
- qemu_mutex_unlock(&proxy->mutex);
- return -EIO;
-}
-
-static int proxy_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
-{
- int retval;
- retval = v9fs_request(fs_ctx->private, T_LSTAT, stbuf, "s", fs_path);
- if (retval < 0) {
- errno = -retval;
- return -1;
- }
- return retval;
-}
-
-static ssize_t proxy_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
- char *buf, size_t bufsz)
-{
- int retval;
- retval = v9fs_request(fs_ctx->private, T_READLINK, buf, "sd",
- fs_path, bufsz);
- if (retval < 0) {
- errno = -retval;
- return -1;
- }
- return strlen(buf);
-}
-
-static int proxy_close(FsContext *ctx, V9fsFidOpenState *fs)
-{
- return close(fs->fd);
-}
-
-static int proxy_closedir(FsContext *ctx, V9fsFidOpenState *fs)
-{
- return closedir(fs->dir);
-}
-
-static int proxy_open(FsContext *ctx, V9fsPath *fs_path,
- int flags, V9fsFidOpenState *fs)
-{
- fs->fd = v9fs_request(ctx->private, T_OPEN, NULL, "sd", fs_path, flags);
- if (fs->fd < 0) {
- errno = -fs->fd;
- fs->fd = -1;
- }
- return fs->fd;
-}
-
-static int proxy_opendir(FsContext *ctx,
- V9fsPath *fs_path, V9fsFidOpenState *fs)
-{
- int serrno, fd;
-
- fs->dir = NULL;
- fd = v9fs_request(ctx->private, T_OPEN, NULL, "sd", fs_path, O_DIRECTORY);
- if (fd < 0) {
- errno = -fd;
- return -1;
- }
- fs->dir = fdopendir(fd);
- if (!fs->dir) {
- serrno = errno;
- close(fd);
- errno = serrno;
- return -1;
- }
- return 0;
-}
-
-static void proxy_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
-{
- rewinddir(fs->dir);
-}
-
-static off_t proxy_telldir(FsContext *ctx, V9fsFidOpenState *fs)
-{
- return telldir(fs->dir);
-}
-
-static int proxy_readdir_r(FsContext *ctx, V9fsFidOpenState *fs,
- struct dirent *entry,
- struct dirent **result)
-{
- return readdir_r(fs->dir, entry, result);
-}
-
-static void proxy_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
-{
- seekdir(fs->dir, off);
-}
-
-static ssize_t proxy_preadv(FsContext *ctx, V9fsFidOpenState *fs,
- const struct iovec *iov,
- int iovcnt, off_t offset)
-{
- ssize_t ret;
-#ifdef CONFIG_PREADV
- ret = preadv(fs->fd, iov, iovcnt, offset);
-#else
- ret = lseek(fs->fd, offset, SEEK_SET);
- if (ret >= 0) {
- ret = readv(fs->fd, iov, iovcnt);
- }
-#endif
- return ret;
-}
-
-static ssize_t proxy_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
- const struct iovec *iov,
- int iovcnt, off_t offset)
-{
- ssize_t ret;
-
-#ifdef CONFIG_PREADV
- ret = pwritev(fs->fd, iov, iovcnt, offset);
-#else
- ret = lseek(fs->fd, offset, SEEK_SET);
- if (ret >= 0) {
- ret = writev(fs->fd, iov, iovcnt);
- }
-#endif
-#ifdef CONFIG_SYNC_FILE_RANGE
- if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) {
- /*
- * Initiate a writeback. This is not a data integrity sync.
- * We want to ensure that we don't leave dirty pages in the cache
- * after write when writeout=immediate is sepcified.
- */
- sync_file_range(fs->fd, offset, ret,
- SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE);
- }
-#endif
- return ret;
-}
-
-static int proxy_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
-{
- int retval;
- retval = v9fs_request(fs_ctx->private, T_CHMOD, NULL, "sd",
- fs_path, credp->fc_mode);
- if (retval < 0) {
- errno = -retval;
- }
- return retval;
-}
-
-static int proxy_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
- const char *name, FsCred *credp)
-{
- int retval;
- V9fsString fullname;
-
- v9fs_string_init(&fullname);
- v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
-
- retval = v9fs_request(fs_ctx->private, T_MKNOD, NULL, "sdqdd",
- &fullname, credp->fc_mode, credp->fc_rdev,
- credp->fc_uid, credp->fc_gid);
- v9fs_string_free(&fullname);
- if (retval < 0) {
- errno = -retval;
- retval = -1;
- }
- return retval;
-}
-
-static int proxy_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
- const char *name, FsCred *credp)
-{
- int retval;
- V9fsString fullname;
-
- v9fs_string_init(&fullname);
- v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
-
- retval = v9fs_request(fs_ctx->private, T_MKDIR, NULL, "sddd", &fullname,
- credp->fc_mode, credp->fc_uid, credp->fc_gid);
- v9fs_string_free(&fullname);
- if (retval < 0) {
- errno = -retval;
- retval = -1;
- }
- v9fs_string_free(&fullname);
- return retval;
-}
-
-static int proxy_fstat(FsContext *fs_ctx, int fid_type,
- V9fsFidOpenState *fs, struct stat *stbuf)
-{
- int fd;
-
- if (fid_type == P9_FID_DIR) {
- fd = dirfd(fs->dir);
- } else {
- fd = fs->fd;
- }
- return fstat(fd, stbuf);
-}
-
-static int proxy_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
- int flags, FsCred *credp, V9fsFidOpenState *fs)
-{
- V9fsString fullname;
-
- v9fs_string_init(&fullname);
- v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
-
- fs->fd = v9fs_request(fs_ctx->private, T_CREATE, NULL, "sdddd",
- &fullname, flags, credp->fc_mode,
- credp->fc_uid, credp->fc_gid);
- v9fs_string_free(&fullname);
- if (fs->fd < 0) {
- errno = -fs->fd;
- fs->fd = -1;
- }
- return fs->fd;
-}
-
-static int proxy_symlink(FsContext *fs_ctx, const char *oldpath,
- V9fsPath *dir_path, const char *name, FsCred *credp)
-{
- int retval;
- V9fsString fullname, target;
-
- v9fs_string_init(&fullname);
- v9fs_string_init(&target);
-
- v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
- v9fs_string_sprintf(&target, "%s", oldpath);
-
- retval = v9fs_request(fs_ctx->private, T_SYMLINK, NULL, "ssdd",
- &target, &fullname, credp->fc_uid, credp->fc_gid);
- v9fs_string_free(&fullname);
- v9fs_string_free(&target);
- if (retval < 0) {
- errno = -retval;
- retval = -1;
- }
- return retval;
-}
-
-static int proxy_link(FsContext *ctx, V9fsPath *oldpath,
- V9fsPath *dirpath, const char *name)
-{
- int retval;
- V9fsString newpath;
-
- v9fs_string_init(&newpath);
- v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name);
-
- retval = v9fs_request(ctx->private, T_LINK, NULL, "ss", oldpath, &newpath);
- v9fs_string_free(&newpath);
- if (retval < 0) {
- errno = -retval;
- retval = -1;
- }
- return retval;
-}
-
-static int proxy_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
-{
- int retval;
-
- retval = v9fs_request(ctx->private, T_TRUNCATE, NULL, "sq", fs_path, size);
- if (retval < 0) {
- errno = -retval;
- return -1;
- }
- return 0;
-}
-
-static int proxy_rename(FsContext *ctx, const char *oldpath,
- const char *newpath)
-{
- int retval;
- V9fsString oldname, newname;
-
- v9fs_string_init(&oldname);
- v9fs_string_init(&newname);
-
- v9fs_string_sprintf(&oldname, "%s", oldpath);
- v9fs_string_sprintf(&newname, "%s", newpath);
- retval = v9fs_request(ctx->private, T_RENAME, NULL, "ss",
- &oldname, &newname);
- v9fs_string_free(&oldname);
- v9fs_string_free(&newname);
- if (retval < 0) {
- errno = -retval;
- }
- return retval;
-}
-
-static int proxy_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
-{
- int retval;
- retval = v9fs_request(fs_ctx->private, T_CHOWN, NULL, "sdd",
- fs_path, credp->fc_uid, credp->fc_gid);
- if (retval < 0) {
- errno = -retval;
- }
- return retval;
-}
-
-static int proxy_utimensat(FsContext *s, V9fsPath *fs_path,
- const struct timespec *buf)
-{
- int retval;
- retval = v9fs_request(s->private, T_UTIME, NULL, "sqqqq",
- fs_path,
- buf[0].tv_sec, buf[0].tv_nsec,
- buf[1].tv_sec, buf[1].tv_nsec);
- if (retval < 0) {
- errno = -retval;
- }
- return retval;
-}
-
-static int proxy_remove(FsContext *ctx, const char *path)
-{
- int retval;
- V9fsString name;
- v9fs_string_init(&name);
- v9fs_string_sprintf(&name, "%s", path);
- retval = v9fs_request(ctx->private, T_REMOVE, NULL, "s", &name);
- v9fs_string_free(&name);
- if (retval < 0) {
- errno = -retval;
- }
- return retval;
-}
-
-static int proxy_fsync(FsContext *ctx, int fid_type,
- V9fsFidOpenState *fs, int datasync)
-{
- int fd;
-
- if (fid_type == P9_FID_DIR) {
- fd = dirfd(fs->dir);
- } else {
- fd = fs->fd;
- }
-
- if (datasync) {
- return qemu_fdatasync(fd);
- } else {
- return fsync(fd);
- }
-}
-
-static int proxy_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf)
-{
- int retval;
- retval = v9fs_request(s->private, T_STATFS, stbuf, "s", fs_path);
- if (retval < 0) {
- errno = -retval;
- return -1;
- }
- return retval;
-}
-
-static ssize_t proxy_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
- const char *name, void *value, size_t size)
-{
- int retval;
- V9fsString xname;
-
- v9fs_string_init(&xname);
- v9fs_string_sprintf(&xname, "%s", name);
- retval = v9fs_request(ctx->private, T_LGETXATTR, value, "dss", size,
- fs_path, &xname);
- v9fs_string_free(&xname);
- if (retval < 0) {
- errno = -retval;
- }
- return retval;
-}
-
-static ssize_t proxy_llistxattr(FsContext *ctx, V9fsPath *fs_path,
- void *value, size_t size)
-{
- int retval;
- retval = v9fs_request(ctx->private, T_LLISTXATTR, value, "ds", size,
- fs_path);
- if (retval < 0) {
- errno = -retval;
- }
- return retval;
-}
-
-static int proxy_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name,
- void *value, size_t size, int flags)
-{
- int retval;
- V9fsString xname, xvalue;
-
- v9fs_string_init(&xname);
- v9fs_string_sprintf(&xname, "%s", name);
-
- v9fs_string_init(&xvalue);
- xvalue.size = size;
- xvalue.data = g_malloc(size);
- memcpy(xvalue.data, value, size);
-
- retval = v9fs_request(ctx->private, T_LSETXATTR, value, "sssdd",
- fs_path, &xname, &xvalue, size, flags);
- v9fs_string_free(&xname);
- v9fs_string_free(&xvalue);
- if (retval < 0) {
- errno = -retval;
- }
- return retval;
-}
-
-static int proxy_lremovexattr(FsContext *ctx, V9fsPath *fs_path,
- const char *name)
-{
- int retval;
- V9fsString xname;
-
- v9fs_string_init(&xname);
- v9fs_string_sprintf(&xname, "%s", name);
- retval = v9fs_request(ctx->private, T_LREMOVEXATTR, NULL, "ss",
- fs_path, &xname);
- v9fs_string_free(&xname);
- if (retval < 0) {
- errno = -retval;
- }
- return retval;
-}
-
-static int proxy_name_to_path(FsContext *ctx, V9fsPath *dir_path,
- const char *name, V9fsPath *target)
-{
- if (dir_path) {
- v9fs_string_sprintf((V9fsString *)target, "%s/%s",
- dir_path->data, name);
- } else {
- v9fs_string_sprintf((V9fsString *)target, "%s", name);
- }
- /* Bump the size for including terminating NULL */
- target->size++;
- return 0;
-}
-
-static int proxy_renameat(FsContext *ctx, V9fsPath *olddir,
- const char *old_name, V9fsPath *newdir,
- const char *new_name)
-{
- int ret;
- V9fsString old_full_name, new_full_name;
-
- v9fs_string_init(&old_full_name);
- v9fs_string_init(&new_full_name);
-
- v9fs_string_sprintf(&old_full_name, "%s/%s", olddir->data, old_name);
- v9fs_string_sprintf(&new_full_name, "%s/%s", newdir->data, new_name);
-
- ret = proxy_rename(ctx, old_full_name.data, new_full_name.data);
- v9fs_string_free(&old_full_name);
- v9fs_string_free(&new_full_name);
- return ret;
-}
-
-static int proxy_unlinkat(FsContext *ctx, V9fsPath *dir,
- const char *name, int flags)
-{
- int ret;
- V9fsString fullname;
- v9fs_string_init(&fullname);
-
- v9fs_string_sprintf(&fullname, "%s/%s", dir->data, name);
- ret = proxy_remove(ctx, fullname.data);
- v9fs_string_free(&fullname);
-
- return ret;
-}
-
-static int proxy_ioc_getversion(FsContext *fs_ctx, V9fsPath *path,
- mode_t st_mode, uint64_t *st_gen)
-{
- int err;
-
- /* Do not try to open special files like device nodes, fifos etc
- * we can get fd for regular files and directories only
- */
- if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) {
- errno = ENOTTY;
- return -1;
- }
- err = v9fs_request(fs_ctx->private, T_GETVERSION, st_gen, "s", path);
- if (err < 0) {
- errno = -err;
- err = -1;
- }
- return err;
-}
-
-static int connect_namedsocket(const char *path)
-{
- int sockfd, size;
- struct sockaddr_un helper;
-
- if (strlen(path) >= sizeof(helper.sun_path)) {
- error_report("Socket name too long");
- return -1;
- }
- sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
- if (sockfd < 0) {
- error_report("Failed to create socket: %s", strerror(errno));
- return -1;
- }
- strcpy(helper.sun_path, path);
- helper.sun_family = AF_UNIX;
- size = strlen(helper.sun_path) + sizeof(helper.sun_family);
- if (connect(sockfd, (struct sockaddr *)&helper, size) < 0) {
- error_report("Failed to connect to %s: %s", path, strerror(errno));
- close(sockfd);
- return -1;
- }
-
- /* remove the socket for security reasons */
- unlink(path);
- return sockfd;
-}
-
-static int proxy_parse_opts(QemuOpts *opts, struct FsDriverEntry *fs)
-{
- const char *socket = qemu_opt_get(opts, "socket");
- const char *sock_fd = qemu_opt_get(opts, "sock_fd");
-
- if (!socket && !sock_fd) {
- error_report("Must specify either socket or sock_fd");
- return -1;
- }
- if (socket && sock_fd) {
- error_report("Both socket and sock_fd options specified");
- return -1;
- }
- if (socket) {
- fs->path = g_strdup(socket);
- fs->export_flags = V9FS_PROXY_SOCK_NAME;
- } else {
- fs->path = g_strdup(sock_fd);
- fs->export_flags = V9FS_PROXY_SOCK_FD;
- }
- return 0;
-}
-
-static int proxy_init(FsContext *ctx)
-{
- V9fsProxy *proxy = g_malloc(sizeof(V9fsProxy));
- int sock_id;
-
- if (ctx->export_flags & V9FS_PROXY_SOCK_NAME) {
- sock_id = connect_namedsocket(ctx->fs_root);
- } else {
- sock_id = atoi(ctx->fs_root);
- if (sock_id < 0) {
- error_report("Socket descriptor not initialized");
- }
- }
- if (sock_id < 0) {
- g_free(proxy);
- return -1;
- }
- g_free(ctx->fs_root);
- ctx->fs_root = NULL;
-
- proxy->in_iovec.iov_base = g_malloc(PROXY_MAX_IO_SZ + PROXY_HDR_SZ);
- proxy->in_iovec.iov_len = PROXY_MAX_IO_SZ + PROXY_HDR_SZ;
- proxy->out_iovec.iov_base = g_malloc(PROXY_MAX_IO_SZ + PROXY_HDR_SZ);
- proxy->out_iovec.iov_len = PROXY_MAX_IO_SZ + PROXY_HDR_SZ;
-
- ctx->private = proxy;
- proxy->sockfd = sock_id;
- qemu_mutex_init(&proxy->mutex);
-
- ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT;
- ctx->exops.get_st_gen = proxy_ioc_getversion;
- return 0;
-}
-
-FileOperations proxy_ops = {
- .parse_opts = proxy_parse_opts,
- .init = proxy_init,
- .lstat = proxy_lstat,
- .readlink = proxy_readlink,
- .close = proxy_close,
- .closedir = proxy_closedir,
- .open = proxy_open,
- .opendir = proxy_opendir,
- .rewinddir = proxy_rewinddir,
- .telldir = proxy_telldir,
- .readdir_r = proxy_readdir_r,
- .seekdir = proxy_seekdir,
- .preadv = proxy_preadv,
- .pwritev = proxy_pwritev,
- .chmod = proxy_chmod,
- .mknod = proxy_mknod,
- .mkdir = proxy_mkdir,
- .fstat = proxy_fstat,
- .open2 = proxy_open2,
- .symlink = proxy_symlink,
- .link = proxy_link,
- .truncate = proxy_truncate,
- .rename = proxy_rename,
- .chown = proxy_chown,
- .utimensat = proxy_utimensat,
- .remove = proxy_remove,
- .fsync = proxy_fsync,
- .statfs = proxy_statfs,
- .lgetxattr = proxy_lgetxattr,
- .llistxattr = proxy_llistxattr,
- .lsetxattr = proxy_lsetxattr,
- .lremovexattr = proxy_lremovexattr,
- .name_to_path = proxy_name_to_path,
- .renameat = proxy_renameat,
- .unlinkat = proxy_unlinkat,
-};
diff --git a/qemu/hw/9pfs/9p-proxy.h b/qemu/hw/9pfs/9p-proxy.h
deleted file mode 100644
index ba9ca203d..000000000
--- a/qemu/hw/9pfs/9p-proxy.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * 9p Proxy callback
- *
- * Copyright IBM, Corp. 2011
- *
- * Authors:
- * M. Mohan Kumar <mohan@in.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- */
-#ifndef _QEMU_9P_PROXY_H
-#define _QEMU_9P_PROXY_H
-
-#define PROXY_MAX_IO_SZ (64 * 1024)
-#define V9FS_FD_VALID INT_MAX
-
-/*
- * proxy iovec only support one element and
- * marsha/unmarshal doesn't do little endian conversion.
- */
-#define proxy_unmarshal(in_sg, offset, fmt, args...) \
- v9fs_iov_unmarshal(in_sg, 1, offset, 0, fmt, ##args)
-#define proxy_marshal(out_sg, offset, fmt, args...) \
- v9fs_iov_marshal(out_sg, 1, offset, 0, fmt, ##args)
-
-union MsgControl {
- struct cmsghdr cmsg;
- char control[CMSG_SPACE(sizeof(int))];
-};
-
-typedef struct {
- uint32_t type;
- uint32_t size;
-} ProxyHeader;
-
-#define PROXY_HDR_SZ (sizeof(ProxyHeader))
-
-enum {
- T_SUCCESS = 0,
- T_ERROR,
- T_OPEN,
- T_CREATE,
- T_MKNOD,
- T_MKDIR,
- T_SYMLINK,
- T_LINK,
- T_LSTAT,
- T_READLINK,
- T_STATFS,
- T_CHMOD,
- T_CHOWN,
- T_TRUNCATE,
- T_UTIME,
- T_RENAME,
- T_REMOVE,
- T_LGETXATTR,
- T_LLISTXATTR,
- T_LSETXATTR,
- T_LREMOVEXATTR,
- T_GETVERSION,
-};
-
-typedef struct {
- uint64_t st_dev;
- uint64_t st_ino;
- uint64_t st_nlink;
- uint32_t st_mode;
- uint32_t st_uid;
- uint32_t st_gid;
- uint64_t st_rdev;
- uint64_t st_size;
- uint64_t st_blksize;
- uint64_t st_blocks;
- uint64_t st_atim_sec;
- uint64_t st_atim_nsec;
- uint64_t st_mtim_sec;
- uint64_t st_mtim_nsec;
- uint64_t st_ctim_sec;
- uint64_t st_ctim_nsec;
-} ProxyStat;
-
-typedef struct {
- uint64_t f_type;
- uint64_t f_bsize;
- uint64_t f_blocks;
- uint64_t f_bfree;
- uint64_t f_bavail;
- uint64_t f_files;
- uint64_t f_ffree;
- uint64_t f_fsid[2];
- uint64_t f_namelen;
- uint64_t f_frsize;
-} ProxyStatFS;
-#endif
diff --git a/qemu/hw/9pfs/9p-synth.c b/qemu/hw/9pfs/9p-synth.c
deleted file mode 100644
index f1475dfd6..000000000
--- a/qemu/hw/9pfs/9p-synth.c
+++ /dev/null
@@ -1,574 +0,0 @@
-/*
- * Virtio 9p synthetic file system support
- *
- * Copyright IBM, Corp. 2011
- *
- * Authors:
- * Malahal Naineni <malahal@us.ibm.com>
- * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "hw/virtio/virtio.h"
-#include "9p.h"
-#include "9p-xattr.h"
-#include "fsdev/qemu-fsdev.h"
-#include "9p-synth.h"
-#include "qemu/rcu.h"
-#include "qemu/rcu_queue.h"
-#include "qemu/cutils.h"
-
-/* Root node for synth file system */
-static V9fsSynthNode v9fs_synth_root = {
- .name = "/",
- .actual_attr = {
- .mode = 0555 | S_IFDIR,
- .nlink = 1,
- },
- .attr = &v9fs_synth_root.actual_attr,
-};
-
-static QemuMutex v9fs_synth_mutex;
-static int v9fs_synth_node_count;
-/* set to 1 when the synth fs is ready */
-static int v9fs_synth_fs;
-
-static V9fsSynthNode *v9fs_add_dir_node(V9fsSynthNode *parent, int mode,
- const char *name,
- V9fsSynthNodeAttr *attr, int inode)
-{
- V9fsSynthNode *node;
-
- /* Add directory type and remove write bits */
- mode = ((mode & 0777) | S_IFDIR) & ~(S_IWUSR | S_IWGRP | S_IWOTH);
- node = g_malloc0(sizeof(V9fsSynthNode));
- if (attr) {
- /* We are adding .. or . entries */
- node->attr = attr;
- node->attr->nlink++;
- } else {
- node->attr = &node->actual_attr;
- node->attr->inode = inode;
- node->attr->nlink = 1;
- /* We don't allow write to directories */
- node->attr->mode = mode;
- node->attr->write = NULL;
- node->attr->read = NULL;
- }
- node->private = node;
- pstrcpy(node->name, sizeof(node->name), name);
- QLIST_INSERT_HEAD_RCU(&parent->child, node, sibling);
- return node;
-}
-
-int qemu_v9fs_synth_mkdir(V9fsSynthNode *parent, int mode,
- const char *name, V9fsSynthNode **result)
-{
- int ret;
- V9fsSynthNode *node, *tmp;
-
- if (!v9fs_synth_fs) {
- return EAGAIN;
- }
- if (!name || (strlen(name) >= NAME_MAX)) {
- return EINVAL;
- }
- if (!parent) {
- parent = &v9fs_synth_root;
- }
- qemu_mutex_lock(&v9fs_synth_mutex);
- QLIST_FOREACH(tmp, &parent->child, sibling) {
- if (!strcmp(tmp->name, name)) {
- ret = EEXIST;
- goto err_out;
- }
- }
- /* Add the name */
- node = v9fs_add_dir_node(parent, mode, name, NULL, v9fs_synth_node_count++);
- v9fs_add_dir_node(node, parent->attr->mode, "..",
- parent->attr, parent->attr->inode);
- v9fs_add_dir_node(node, node->attr->mode, ".",
- node->attr, node->attr->inode);
- *result = node;
- ret = 0;
-err_out:
- qemu_mutex_unlock(&v9fs_synth_mutex);
- return ret;
-}
-
-int qemu_v9fs_synth_add_file(V9fsSynthNode *parent, int mode,
- const char *name, v9fs_synth_read read,
- v9fs_synth_write write, void *arg)
-{
- int ret;
- V9fsSynthNode *node, *tmp;
-
- if (!v9fs_synth_fs) {
- return EAGAIN;
- }
- if (!name || (strlen(name) >= NAME_MAX)) {
- return EINVAL;
- }
- if (!parent) {
- parent = &v9fs_synth_root;
- }
-
- qemu_mutex_lock(&v9fs_synth_mutex);
- QLIST_FOREACH(tmp, &parent->child, sibling) {
- if (!strcmp(tmp->name, name)) {
- ret = EEXIST;
- goto err_out;
- }
- }
- /* Add file type and remove write bits */
- mode = ((mode & 0777) | S_IFREG);
- node = g_malloc0(sizeof(V9fsSynthNode));
- node->attr = &node->actual_attr;
- node->attr->inode = v9fs_synth_node_count++;
- node->attr->nlink = 1;
- node->attr->read = read;
- node->attr->write = write;
- node->attr->mode = mode;
- node->private = arg;
- pstrcpy(node->name, sizeof(node->name), name);
- QLIST_INSERT_HEAD_RCU(&parent->child, node, sibling);
- ret = 0;
-err_out:
- qemu_mutex_unlock(&v9fs_synth_mutex);
- return ret;
-}
-
-static void v9fs_synth_fill_statbuf(V9fsSynthNode *node, struct stat *stbuf)
-{
- stbuf->st_dev = 0;
- stbuf->st_ino = node->attr->inode;
- stbuf->st_mode = node->attr->mode;
- stbuf->st_nlink = node->attr->nlink;
- stbuf->st_uid = 0;
- stbuf->st_gid = 0;
- stbuf->st_rdev = 0;
- stbuf->st_size = 0;
- stbuf->st_blksize = 0;
- stbuf->st_blocks = 0;
- stbuf->st_atime = 0;
- stbuf->st_mtime = 0;
- stbuf->st_ctime = 0;
-}
-
-static int v9fs_synth_lstat(FsContext *fs_ctx,
- V9fsPath *fs_path, struct stat *stbuf)
-{
- V9fsSynthNode *node = *(V9fsSynthNode **)fs_path->data;
-
- v9fs_synth_fill_statbuf(node, stbuf);
- return 0;
-}
-
-static int v9fs_synth_fstat(FsContext *fs_ctx, int fid_type,
- V9fsFidOpenState *fs, struct stat *stbuf)
-{
- V9fsSynthOpenState *synth_open = fs->private;
- v9fs_synth_fill_statbuf(synth_open->node, stbuf);
- return 0;
-}
-
-static int v9fs_synth_opendir(FsContext *ctx,
- V9fsPath *fs_path, V9fsFidOpenState *fs)
-{
- V9fsSynthOpenState *synth_open;
- V9fsSynthNode *node = *(V9fsSynthNode **)fs_path->data;
-
- synth_open = g_malloc(sizeof(*synth_open));
- synth_open->node = node;
- node->open_count++;
- fs->private = synth_open;
- return 0;
-}
-
-static int v9fs_synth_closedir(FsContext *ctx, V9fsFidOpenState *fs)
-{
- V9fsSynthOpenState *synth_open = fs->private;
- V9fsSynthNode *node = synth_open->node;
-
- node->open_count--;
- g_free(synth_open);
- fs->private = NULL;
- return 0;
-}
-
-static off_t v9fs_synth_telldir(FsContext *ctx, V9fsFidOpenState *fs)
-{
- V9fsSynthOpenState *synth_open = fs->private;
- return synth_open->offset;
-}
-
-static void v9fs_synth_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
-{
- V9fsSynthOpenState *synth_open = fs->private;
- synth_open->offset = off;
-}
-
-static void v9fs_synth_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
-{
- v9fs_synth_seekdir(ctx, fs, 0);
-}
-
-static void v9fs_synth_direntry(V9fsSynthNode *node,
- struct dirent *entry, off_t off)
-{
- strcpy(entry->d_name, node->name);
- entry->d_ino = node->attr->inode;
- entry->d_off = off + 1;
-}
-
-static int v9fs_synth_get_dentry(V9fsSynthNode *dir, struct dirent *entry,
- struct dirent **result, off_t off)
-{
- int i = 0;
- V9fsSynthNode *node;
-
- rcu_read_lock();
- QLIST_FOREACH(node, &dir->child, sibling) {
- /* This is the off child of the directory */
- if (i == off) {
- break;
- }
- i++;
- }
- rcu_read_unlock();
- if (!node) {
- /* end of directory */
- *result = NULL;
- return 0;
- }
- v9fs_synth_direntry(node, entry, off);
- *result = entry;
- return 0;
-}
-
-static int v9fs_synth_readdir_r(FsContext *ctx, V9fsFidOpenState *fs,
- struct dirent *entry, struct dirent **result)
-{
- int ret;
- V9fsSynthOpenState *synth_open = fs->private;
- V9fsSynthNode *node = synth_open->node;
- ret = v9fs_synth_get_dentry(node, entry, result, synth_open->offset);
- if (!ret && *result != NULL) {
- synth_open->offset++;
- }
- return ret;
-}
-
-static int v9fs_synth_open(FsContext *ctx, V9fsPath *fs_path,
- int flags, V9fsFidOpenState *fs)
-{
- V9fsSynthOpenState *synth_open;
- V9fsSynthNode *node = *(V9fsSynthNode **)fs_path->data;
-
- synth_open = g_malloc(sizeof(*synth_open));
- synth_open->node = node;
- node->open_count++;
- fs->private = synth_open;
- return 0;
-}
-
-static int v9fs_synth_open2(FsContext *fs_ctx, V9fsPath *dir_path,
- const char *name, int flags,
- FsCred *credp, V9fsFidOpenState *fs)
-{
- errno = ENOSYS;
- return -1;
-}
-
-static int v9fs_synth_close(FsContext *ctx, V9fsFidOpenState *fs)
-{
- V9fsSynthOpenState *synth_open = fs->private;
- V9fsSynthNode *node = synth_open->node;
-
- node->open_count--;
- g_free(synth_open);
- fs->private = NULL;
- return 0;
-}
-
-static ssize_t v9fs_synth_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
- const struct iovec *iov,
- int iovcnt, off_t offset)
-{
- int i, count = 0, wcount;
- V9fsSynthOpenState *synth_open = fs->private;
- V9fsSynthNode *node = synth_open->node;
- if (!node->attr->write) {
- errno = EPERM;
- return -1;
- }
- for (i = 0; i < iovcnt; i++) {
- wcount = node->attr->write(iov[i].iov_base, iov[i].iov_len,
- offset, node->private);
- offset += wcount;
- count += wcount;
- /* If we wrote less than requested. we are done */
- if (wcount < iov[i].iov_len) {
- break;
- }
- }
- return count;
-}
-
-static ssize_t v9fs_synth_preadv(FsContext *ctx, V9fsFidOpenState *fs,
- const struct iovec *iov,
- int iovcnt, off_t offset)
-{
- int i, count = 0, rcount;
- V9fsSynthOpenState *synth_open = fs->private;
- V9fsSynthNode *node = synth_open->node;
- if (!node->attr->read) {
- errno = EPERM;
- return -1;
- }
- for (i = 0; i < iovcnt; i++) {
- rcount = node->attr->read(iov[i].iov_base, iov[i].iov_len,
- offset, node->private);
- offset += rcount;
- count += rcount;
- /* If we read less than requested. we are done */
- if (rcount < iov[i].iov_len) {
- break;
- }
- }
- return count;
-}
-
-static int v9fs_synth_truncate(FsContext *ctx, V9fsPath *path, off_t offset)
-{
- errno = ENOSYS;
- return -1;
-}
-
-static int v9fs_synth_chmod(FsContext *fs_ctx, V9fsPath *path, FsCred *credp)
-{
- errno = EPERM;
- return -1;
-}
-
-static int v9fs_synth_mknod(FsContext *fs_ctx, V9fsPath *path,
- const char *buf, FsCred *credp)
-{
- errno = EPERM;
- return -1;
-}
-
-static int v9fs_synth_mkdir(FsContext *fs_ctx, V9fsPath *path,
- const char *buf, FsCred *credp)
-{
- errno = EPERM;
- return -1;
-}
-
-static ssize_t v9fs_synth_readlink(FsContext *fs_ctx, V9fsPath *path,
- char *buf, size_t bufsz)
-{
- errno = ENOSYS;
- return -1;
-}
-
-static int v9fs_synth_symlink(FsContext *fs_ctx, const char *oldpath,
- V9fsPath *newpath, const char *buf, FsCred *credp)
-{
- errno = EPERM;
- return -1;
-}
-
-static int v9fs_synth_link(FsContext *fs_ctx, V9fsPath *oldpath,
- V9fsPath *newpath, const char *buf)
-{
- errno = EPERM;
- return -1;
-}
-
-static int v9fs_synth_rename(FsContext *ctx, const char *oldpath,
- const char *newpath)
-{
- errno = EPERM;
- return -1;
-}
-
-static int v9fs_synth_chown(FsContext *fs_ctx, V9fsPath *path, FsCred *credp)
-{
- errno = EPERM;
- return -1;
-}
-
-static int v9fs_synth_utimensat(FsContext *fs_ctx, V9fsPath *path,
- const struct timespec *buf)
-{
- errno = EPERM;
- return 0;
-}
-
-static int v9fs_synth_remove(FsContext *ctx, const char *path)
-{
- errno = EPERM;
- return -1;
-}
-
-static int v9fs_synth_fsync(FsContext *ctx, int fid_type,
- V9fsFidOpenState *fs, int datasync)
-{
- errno = ENOSYS;
- return 0;
-}
-
-static int v9fs_synth_statfs(FsContext *s, V9fsPath *fs_path,
- struct statfs *stbuf)
-{
- stbuf->f_type = 0xABCD;
- stbuf->f_bsize = 512;
- stbuf->f_blocks = 0;
- stbuf->f_files = v9fs_synth_node_count;
- stbuf->f_namelen = NAME_MAX;
- return 0;
-}
-
-static ssize_t v9fs_synth_lgetxattr(FsContext *ctx, V9fsPath *path,
- const char *name, void *value, size_t size)
-{
- errno = ENOTSUP;
- return -1;
-}
-
-static ssize_t v9fs_synth_llistxattr(FsContext *ctx, V9fsPath *path,
- void *value, size_t size)
-{
- errno = ENOTSUP;
- return -1;
-}
-
-static int v9fs_synth_lsetxattr(FsContext *ctx, V9fsPath *path,
- const char *name, void *value,
- size_t size, int flags)
-{
- errno = ENOTSUP;
- return -1;
-}
-
-static int v9fs_synth_lremovexattr(FsContext *ctx,
- V9fsPath *path, const char *name)
-{
- errno = ENOTSUP;
- return -1;
-}
-
-static int v9fs_synth_name_to_path(FsContext *ctx, V9fsPath *dir_path,
- const char *name, V9fsPath *target)
-{
- V9fsSynthNode *node;
- V9fsSynthNode *dir_node;
-
- /* "." and ".." are not allowed */
- if (!strcmp(name, ".") || !strcmp(name, "..")) {
- errno = EINVAL;
- return -1;
-
- }
- if (!dir_path) {
- dir_node = &v9fs_synth_root;
- } else {
- dir_node = *(V9fsSynthNode **)dir_path->data;
- }
- if (!strcmp(name, "/")) {
- node = dir_node;
- goto out;
- }
- /* search for the name in the childern */
- rcu_read_lock();
- QLIST_FOREACH(node, &dir_node->child, sibling) {
- if (!strcmp(node->name, name)) {
- break;
- }
- }
- rcu_read_unlock();
-
- if (!node) {
- errno = ENOENT;
- return -1;
- }
-out:
- /* Copy the node pointer to fid */
- target->data = g_malloc(sizeof(void *));
- memcpy(target->data, &node, sizeof(void *));
- target->size = sizeof(void *);
- return 0;
-}
-
-static int v9fs_synth_renameat(FsContext *ctx, V9fsPath *olddir,
- const char *old_name, V9fsPath *newdir,
- const char *new_name)
-{
- errno = EPERM;
- return -1;
-}
-
-static int v9fs_synth_unlinkat(FsContext *ctx, V9fsPath *dir,
- const char *name, int flags)
-{
- errno = EPERM;
- return -1;
-}
-
-static int v9fs_synth_init(FsContext *ctx)
-{
- QLIST_INIT(&v9fs_synth_root.child);
- qemu_mutex_init(&v9fs_synth_mutex);
-
- /* Add "." and ".." entries for root */
- v9fs_add_dir_node(&v9fs_synth_root, v9fs_synth_root.attr->mode,
- "..", v9fs_synth_root.attr, v9fs_synth_root.attr->inode);
- v9fs_add_dir_node(&v9fs_synth_root, v9fs_synth_root.attr->mode,
- ".", v9fs_synth_root.attr, v9fs_synth_root.attr->inode);
-
- /* Mark the subsystem is ready for use */
- v9fs_synth_fs = 1;
- return 0;
-}
-
-FileOperations synth_ops = {
- .init = v9fs_synth_init,
- .lstat = v9fs_synth_lstat,
- .readlink = v9fs_synth_readlink,
- .close = v9fs_synth_close,
- .closedir = v9fs_synth_closedir,
- .open = v9fs_synth_open,
- .opendir = v9fs_synth_opendir,
- .rewinddir = v9fs_synth_rewinddir,
- .telldir = v9fs_synth_telldir,
- .readdir_r = v9fs_synth_readdir_r,
- .seekdir = v9fs_synth_seekdir,
- .preadv = v9fs_synth_preadv,
- .pwritev = v9fs_synth_pwritev,
- .chmod = v9fs_synth_chmod,
- .mknod = v9fs_synth_mknod,
- .mkdir = v9fs_synth_mkdir,
- .fstat = v9fs_synth_fstat,
- .open2 = v9fs_synth_open2,
- .symlink = v9fs_synth_symlink,
- .link = v9fs_synth_link,
- .truncate = v9fs_synth_truncate,
- .rename = v9fs_synth_rename,
- .chown = v9fs_synth_chown,
- .utimensat = v9fs_synth_utimensat,
- .remove = v9fs_synth_remove,
- .fsync = v9fs_synth_fsync,
- .statfs = v9fs_synth_statfs,
- .lgetxattr = v9fs_synth_lgetxattr,
- .llistxattr = v9fs_synth_llistxattr,
- .lsetxattr = v9fs_synth_lsetxattr,
- .lremovexattr = v9fs_synth_lremovexattr,
- .name_to_path = v9fs_synth_name_to_path,
- .renameat = v9fs_synth_renameat,
- .unlinkat = v9fs_synth_unlinkat,
-};
diff --git a/qemu/hw/9pfs/9p-synth.h b/qemu/hw/9pfs/9p-synth.h
deleted file mode 100644
index 82962512a..000000000
--- a/qemu/hw/9pfs/9p-synth.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 9p
- *
- * Copyright IBM, Corp. 2011
- *
- * Authors:
- * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- */
-#ifndef HW_9PFS_SYNTH_H
-#define HW_9PFS_SYNTH_H 1
-
-
-typedef struct V9fsSynthNode V9fsSynthNode;
-typedef ssize_t (*v9fs_synth_read)(void *buf, int len, off_t offset,
- void *arg);
-typedef ssize_t (*v9fs_synth_write)(void *buf, int len, off_t offset,
- void *arg);
-typedef struct V9fsSynthNodeAttr {
- int mode;
- int inode;
- int nlink;
- v9fs_synth_read read;
- v9fs_synth_write write;
-} V9fsSynthNodeAttr;
-
-struct V9fsSynthNode {
- QLIST_HEAD(, V9fsSynthNode) child;
- QLIST_ENTRY(V9fsSynthNode) sibling;
- char name[NAME_MAX];
- V9fsSynthNodeAttr *attr;
- V9fsSynthNodeAttr actual_attr;
- void *private;
- int open_count;
-};
-
-typedef struct V9fsSynthOpenState {
- off_t offset;
- V9fsSynthNode *node;
-} V9fsSynthOpenState;
-
-extern int qemu_v9fs_synth_mkdir(V9fsSynthNode *parent, int mode,
- const char *name, V9fsSynthNode **result);
-extern int qemu_v9fs_synth_add_file(V9fsSynthNode *parent, int mode,
- const char *name, v9fs_synth_read read,
- v9fs_synth_write write, void *arg);
-
-#endif
diff --git a/qemu/hw/9pfs/9p-xattr-user.c b/qemu/hw/9pfs/9p-xattr-user.c
deleted file mode 100644
index f87530c8b..000000000
--- a/qemu/hw/9pfs/9p-xattr-user.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * 9p user. xattr callback
- *
- * Copyright IBM, Corp. 2010
- *
- * Authors:
- * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "9p.h"
-#include "fsdev/file-op-9p.h"
-#include "9p-xattr.h"
-
-
-static ssize_t mp_user_getxattr(FsContext *ctx, const char *path,
- const char *name, void *value, size_t size)
-{
- char *buffer;
- ssize_t ret;
-
- if (strncmp(name, "user.virtfs.", 12) == 0) {
- /*
- * Don't allow fetch of user.virtfs namesapce
- * in case of mapped security
- */
- errno = ENOATTR;
- return -1;
- }
- buffer = rpath(ctx, path);
- ret = lgetxattr(buffer, name, value, size);
- g_free(buffer);
- return ret;
-}
-
-static ssize_t mp_user_listxattr(FsContext *ctx, const char *path,
- char *name, void *value, size_t size)
-{
- int name_size = strlen(name) + 1;
- if (strncmp(name, "user.virtfs.", 12) == 0) {
-
- /* check if it is a mapped posix acl */
- if (strncmp(name, "user.virtfs.system.posix_acl_", 29) == 0) {
- /* adjust the name and size */
- name += 12;
- name_size -= 12;
- } else {
- /*
- * Don't allow fetch of user.virtfs namesapce
- * in case of mapped security
- */
- return 0;
- }
- }
- if (!value) {
- return name_size;
- }
-
- if (size < name_size) {
- errno = ERANGE;
- return -1;
- }
-
- /* name_size includes the trailing NUL. */
- memcpy(value, name, name_size);
- return name_size;
-}
-
-static int mp_user_setxattr(FsContext *ctx, const char *path, const char *name,
- void *value, size_t size, int flags)
-{
- char *buffer;
- int ret;
-
- if (strncmp(name, "user.virtfs.", 12) == 0) {
- /*
- * Don't allow fetch of user.virtfs namesapce
- * in case of mapped security
- */
- errno = EACCES;
- return -1;
- }
- buffer = rpath(ctx, path);
- ret = lsetxattr(buffer, name, value, size, flags);
- g_free(buffer);
- return ret;
-}
-
-static int mp_user_removexattr(FsContext *ctx,
- const char *path, const char *name)
-{
- char *buffer;
- int ret;
-
- if (strncmp(name, "user.virtfs.", 12) == 0) {
- /*
- * Don't allow fetch of user.virtfs namesapce
- * in case of mapped security
- */
- errno = EACCES;
- return -1;
- }
- buffer = rpath(ctx, path);
- ret = lremovexattr(buffer, name);
- g_free(buffer);
- return ret;
-}
-
-XattrOperations mapped_user_xattr = {
- .name = "user.",
- .getxattr = mp_user_getxattr,
- .setxattr = mp_user_setxattr,
- .listxattr = mp_user_listxattr,
- .removexattr = mp_user_removexattr,
-};
-
-XattrOperations passthrough_user_xattr = {
- .name = "user.",
- .getxattr = pt_getxattr,
- .setxattr = pt_setxattr,
- .listxattr = pt_listxattr,
- .removexattr = pt_removexattr,
-};
diff --git a/qemu/hw/9pfs/9p-xattr.c b/qemu/hw/9pfs/9p-xattr.c
deleted file mode 100644
index 5d8595ed9..000000000
--- a/qemu/hw/9pfs/9p-xattr.c
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * 9p xattr callback
- *
- * Copyright IBM, Corp. 2010
- *
- * Authors:
- * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "9p.h"
-#include "fsdev/file-op-9p.h"
-#include "9p-xattr.h"
-
-
-static XattrOperations *get_xattr_operations(XattrOperations **h,
- const char *name)
-{
- XattrOperations *xops;
- for (xops = *(h)++; xops != NULL; xops = *(h)++) {
- if (!strncmp(name, xops->name, strlen(xops->name))) {
- return xops;
- }
- }
- return NULL;
-}
-
-ssize_t v9fs_get_xattr(FsContext *ctx, const char *path,
- const char *name, void *value, size_t size)
-{
- XattrOperations *xops = get_xattr_operations(ctx->xops, name);
- if (xops) {
- return xops->getxattr(ctx, path, name, value, size);
- }
- errno = EOPNOTSUPP;
- return -1;
-}
-
-ssize_t pt_listxattr(FsContext *ctx, const char *path,
- char *name, void *value, size_t size)
-{
- int name_size = strlen(name) + 1;
- if (!value) {
- return name_size;
- }
-
- if (size < name_size) {
- errno = ERANGE;
- return -1;
- }
-
- /* no need for strncpy: name_size is strlen(name)+1 */
- memcpy(value, name, name_size);
- return name_size;
-}
-
-
-/*
- * Get the list and pass to each layer to find out whether
- * to send the data or not
- */
-ssize_t v9fs_list_xattr(FsContext *ctx, const char *path,
- void *value, size_t vsize)
-{
- ssize_t size = 0;
- char *buffer;
- void *ovalue = value;
- XattrOperations *xops;
- char *orig_value, *orig_value_start;
- ssize_t xattr_len, parsed_len = 0, attr_len;
-
- /* Get the actual len */
- buffer = rpath(ctx, path);
- xattr_len = llistxattr(buffer, value, 0);
- if (xattr_len <= 0) {
- g_free(buffer);
- return xattr_len;
- }
-
- /* Now fetch the xattr and find the actual size */
- orig_value = g_malloc(xattr_len);
- xattr_len = llistxattr(buffer, orig_value, xattr_len);
- g_free(buffer);
-
- /* store the orig pointer */
- orig_value_start = orig_value;
- while (xattr_len > parsed_len) {
- xops = get_xattr_operations(ctx->xops, orig_value);
- if (!xops) {
- goto next_entry;
- }
-
- if (!value) {
- size += xops->listxattr(ctx, path, orig_value, value, vsize);
- } else {
- size = xops->listxattr(ctx, path, orig_value, value, vsize);
- if (size < 0) {
- goto err_out;
- }
- value += size;
- vsize -= size;
- }
-next_entry:
- /* Got the next entry */
- attr_len = strlen(orig_value) + 1;
- parsed_len += attr_len;
- orig_value += attr_len;
- }
- if (value) {
- size = value - ovalue;
- }
-
-err_out:
- g_free(orig_value_start);
- return size;
-}
-
-int v9fs_set_xattr(FsContext *ctx, const char *path, const char *name,
- void *value, size_t size, int flags)
-{
- XattrOperations *xops = get_xattr_operations(ctx->xops, name);
- if (xops) {
- return xops->setxattr(ctx, path, name, value, size, flags);
- }
- errno = EOPNOTSUPP;
- return -1;
-
-}
-
-int v9fs_remove_xattr(FsContext *ctx,
- const char *path, const char *name)
-{
- XattrOperations *xops = get_xattr_operations(ctx->xops, name);
- if (xops) {
- return xops->removexattr(ctx, path, name);
- }
- errno = EOPNOTSUPP;
- return -1;
-
-}
-
-XattrOperations *mapped_xattr_ops[] = {
- &mapped_user_xattr,
- &mapped_pacl_xattr,
- &mapped_dacl_xattr,
- NULL,
-};
-
-XattrOperations *passthrough_xattr_ops[] = {
- &passthrough_user_xattr,
- &passthrough_acl_xattr,
- NULL,
-};
-
-/* for .user none model should be same as passthrough */
-XattrOperations *none_xattr_ops[] = {
- &passthrough_user_xattr,
- &none_acl_xattr,
- NULL,
-};
diff --git a/qemu/hw/9pfs/9p-xattr.h b/qemu/hw/9pfs/9p-xattr.h
deleted file mode 100644
index 4d39a2026..000000000
--- a/qemu/hw/9pfs/9p-xattr.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * 9p
- *
- * Copyright IBM, Corp. 2010
- *
- * Authors:
- * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- */
-#ifndef _QEMU_9P_XATTR_H
-#define _QEMU_9P_XATTR_H
-
-#include "qemu/xattr.h"
-
-typedef struct xattr_operations
-{
- const char *name;
- ssize_t (*getxattr)(FsContext *ctx, const char *path,
- const char *name, void *value, size_t size);
- ssize_t (*listxattr)(FsContext *ctx, const char *path,
- char *name, void *value, size_t size);
- int (*setxattr)(FsContext *ctx, const char *path, const char *name,
- void *value, size_t size, int flags);
- int (*removexattr)(FsContext *ctx,
- const char *path, const char *name);
-} XattrOperations;
-
-
-extern XattrOperations mapped_user_xattr;
-extern XattrOperations passthrough_user_xattr;
-
-extern XattrOperations mapped_pacl_xattr;
-extern XattrOperations mapped_dacl_xattr;
-extern XattrOperations passthrough_acl_xattr;
-extern XattrOperations none_acl_xattr;
-
-extern XattrOperations *mapped_xattr_ops[];
-extern XattrOperations *passthrough_xattr_ops[];
-extern XattrOperations *none_xattr_ops[];
-
-ssize_t v9fs_get_xattr(FsContext *ctx, const char *path, const char *name,
- void *value, size_t size);
-ssize_t v9fs_list_xattr(FsContext *ctx, const char *path, void *value,
- size_t vsize);
-int v9fs_set_xattr(FsContext *ctx, const char *path, const char *name,
- void *value, size_t size, int flags);
-int v9fs_remove_xattr(FsContext *ctx, const char *path, const char *name);
-ssize_t pt_listxattr(FsContext *ctx, const char *path, char *name, void *value,
- size_t size);
-
-static inline ssize_t pt_getxattr(FsContext *ctx, const char *path,
- const char *name, void *value, size_t size)
-{
- char *buffer;
- ssize_t ret;
-
- buffer = rpath(ctx, path);
- ret = lgetxattr(buffer, name, value, size);
- g_free(buffer);
- return ret;
-}
-
-static inline int pt_setxattr(FsContext *ctx, const char *path,
- const char *name, void *value,
- size_t size, int flags)
-{
- char *buffer;
- int ret;
-
- buffer = rpath(ctx, path);
- ret = lsetxattr(buffer, name, value, size, flags);
- g_free(buffer);
- return ret;
-}
-
-static inline int pt_removexattr(FsContext *ctx,
- const char *path, const char *name)
-{
- char *buffer;
- int ret;
-
- buffer = rpath(ctx, path);
- ret = lremovexattr(path, name);
- g_free(buffer);
- return ret;
-}
-
-static inline ssize_t notsup_getxattr(FsContext *ctx, const char *path,
- const char *name, void *value,
- size_t size)
-{
- errno = ENOTSUP;
- return -1;
-}
-
-static inline int notsup_setxattr(FsContext *ctx, const char *path,
- const char *name, void *value,
- size_t size, int flags)
-{
- errno = ENOTSUP;
- return -1;
-}
-
-static inline ssize_t notsup_listxattr(FsContext *ctx, const char *path,
- char *name, void *value, size_t size)
-{
- return 0;
-}
-
-static inline int notsup_removexattr(FsContext *ctx,
- const char *path, const char *name)
-{
- errno = ENOTSUP;
- return -1;
-}
-
-#endif
diff --git a/qemu/hw/9pfs/9p.c b/qemu/hw/9pfs/9p.c
deleted file mode 100644
index f5e30125f..000000000
--- a/qemu/hw/9pfs/9p.c
+++ /dev/null
@@ -1,3380 +0,0 @@
-/*
- * Virtio 9p backend
- *
- * Copyright IBM, Corp. 2010
- *
- * Authors:
- * Anthony Liguori <aliguori@us.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "hw/virtio/virtio.h"
-#include "hw/i386/pc.h"
-#include "qapi/error.h"
-#include "qemu/error-report.h"
-#include "qemu/iov.h"
-#include "qemu/sockets.h"
-#include "virtio-9p.h"
-#include "fsdev/qemu-fsdev.h"
-#include "9p-xattr.h"
-#include "coth.h"
-#include "trace.h"
-#include "migration/migration.h"
-
-int open_fd_hw;
-int total_open_fd;
-static int open_fd_rc;
-
-enum {
- Oread = 0x00,
- Owrite = 0x01,
- Ordwr = 0x02,
- Oexec = 0x03,
- Oexcl = 0x04,
- Otrunc = 0x10,
- Orexec = 0x20,
- Orclose = 0x40,
- Oappend = 0x80,
-};
-
-ssize_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
-{
- ssize_t ret;
- va_list ap;
-
- va_start(ap, fmt);
- ret = virtio_pdu_vmarshal(pdu, offset, fmt, ap);
- va_end(ap);
-
- return ret;
-}
-
-ssize_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
-{
- ssize_t ret;
- va_list ap;
-
- va_start(ap, fmt);
- ret = virtio_pdu_vunmarshal(pdu, offset, fmt, ap);
- va_end(ap);
-
- return ret;
-}
-
-static void pdu_push_and_notify(V9fsPDU *pdu)
-{
- virtio_9p_push_and_notify(pdu);
-}
-
-static int omode_to_uflags(int8_t mode)
-{
- int ret = 0;
-
- switch (mode & 3) {
- case Oread:
- ret = O_RDONLY;
- break;
- case Ordwr:
- ret = O_RDWR;
- break;
- case Owrite:
- ret = O_WRONLY;
- break;
- case Oexec:
- ret = O_RDONLY;
- break;
- }
-
- if (mode & Otrunc) {
- ret |= O_TRUNC;
- }
-
- if (mode & Oappend) {
- ret |= O_APPEND;
- }
-
- if (mode & Oexcl) {
- ret |= O_EXCL;
- }
-
- return ret;
-}
-
-struct dotl_openflag_map {
- int dotl_flag;
- int open_flag;
-};
-
-static int dotl_to_open_flags(int flags)
-{
- int i;
- /*
- * We have same bits for P9_DOTL_READONLY, P9_DOTL_WRONLY
- * and P9_DOTL_NOACCESS
- */
- int oflags = flags & O_ACCMODE;
-
- struct dotl_openflag_map dotl_oflag_map[] = {
- { P9_DOTL_CREATE, O_CREAT },
- { P9_DOTL_EXCL, O_EXCL },
- { P9_DOTL_NOCTTY , O_NOCTTY },
- { P9_DOTL_TRUNC, O_TRUNC },
- { P9_DOTL_APPEND, O_APPEND },
- { P9_DOTL_NONBLOCK, O_NONBLOCK } ,
- { P9_DOTL_DSYNC, O_DSYNC },
- { P9_DOTL_FASYNC, FASYNC },
- { P9_DOTL_DIRECT, O_DIRECT },
- { P9_DOTL_LARGEFILE, O_LARGEFILE },
- { P9_DOTL_DIRECTORY, O_DIRECTORY },
- { P9_DOTL_NOFOLLOW, O_NOFOLLOW },
- { P9_DOTL_NOATIME, O_NOATIME },
- { P9_DOTL_SYNC, O_SYNC },
- };
-
- for (i = 0; i < ARRAY_SIZE(dotl_oflag_map); i++) {
- if (flags & dotl_oflag_map[i].dotl_flag) {
- oflags |= dotl_oflag_map[i].open_flag;
- }
- }
-
- return oflags;
-}
-
-void cred_init(FsCred *credp)
-{
- credp->fc_uid = -1;
- credp->fc_gid = -1;
- credp->fc_mode = -1;
- credp->fc_rdev = -1;
-}
-
-static int get_dotl_openflags(V9fsState *s, int oflags)
-{
- int flags;
- /*
- * Filter the client open flags
- */
- flags = dotl_to_open_flags(oflags);
- flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT);
- /*
- * Ignore direct disk access hint until the server supports it.
- */
- flags &= ~O_DIRECT;
- return flags;
-}
-
-void v9fs_path_init(V9fsPath *path)
-{
- path->data = NULL;
- path->size = 0;
-}
-
-void v9fs_path_free(V9fsPath *path)
-{
- g_free(path->data);
- path->data = NULL;
- path->size = 0;
-}
-
-void v9fs_path_copy(V9fsPath *lhs, V9fsPath *rhs)
-{
- v9fs_path_free(lhs);
- lhs->data = g_malloc(rhs->size);
- memcpy(lhs->data, rhs->data, rhs->size);
- lhs->size = rhs->size;
-}
-
-int v9fs_name_to_path(V9fsState *s, V9fsPath *dirpath,
- const char *name, V9fsPath *path)
-{
- int err;
- err = s->ops->name_to_path(&s->ctx, dirpath, name, path);
- if (err < 0) {
- err = -errno;
- }
- return err;
-}
-
-/*
- * Return TRUE if s1 is an ancestor of s2.
- *
- * E.g. "a/b" is an ancestor of "a/b/c" but not of "a/bc/d".
- * As a special case, We treat s1 as ancestor of s2 if they are same!
- */
-static int v9fs_path_is_ancestor(V9fsPath *s1, V9fsPath *s2)
-{
- if (!strncmp(s1->data, s2->data, s1->size - 1)) {
- if (s2->data[s1->size - 1] == '\0' || s2->data[s1->size - 1] == '/') {
- return 1;
- }
- }
- return 0;
-}
-
-static size_t v9fs_string_size(V9fsString *str)
-{
- return str->size;
-}
-
-/*
- * returns 0 if fid got re-opened, 1 if not, < 0 on error */
-static int v9fs_reopen_fid(V9fsPDU *pdu, V9fsFidState *f)
-{
- int err = 1;
- if (f->fid_type == P9_FID_FILE) {
- if (f->fs.fd == -1) {
- do {
- err = v9fs_co_open(pdu, f, f->open_flags);
- } while (err == -EINTR && !pdu->cancelled);
- }
- } else if (f->fid_type == P9_FID_DIR) {
- if (f->fs.dir == NULL) {
- do {
- err = v9fs_co_opendir(pdu, f);
- } while (err == -EINTR && !pdu->cancelled);
- }
- }
- return err;
-}
-
-static V9fsFidState *get_fid(V9fsPDU *pdu, int32_t fid)
-{
- int err;
- V9fsFidState *f;
- V9fsState *s = pdu->s;
-
- for (f = s->fid_list; f; f = f->next) {
- BUG_ON(f->clunked);
- if (f->fid == fid) {
- /*
- * Update the fid ref upfront so that
- * we don't get reclaimed when we yield
- * in open later.
- */
- f->ref++;
- /*
- * check whether we need to reopen the
- * file. We might have closed the fd
- * while trying to free up some file
- * descriptors.
- */
- err = v9fs_reopen_fid(pdu, f);
- if (err < 0) {
- f->ref--;
- return NULL;
- }
- /*
- * Mark the fid as referenced so that the LRU
- * reclaim won't close the file descriptor
- */
- f->flags |= FID_REFERENCED;
- return f;
- }
- }
- return NULL;
-}
-
-static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid)
-{
- V9fsFidState *f;
-
- for (f = s->fid_list; f; f = f->next) {
- /* If fid is already there return NULL */
- BUG_ON(f->clunked);
- if (f->fid == fid) {
- return NULL;
- }
- }
- f = g_malloc0(sizeof(V9fsFidState));
- f->fid = fid;
- f->fid_type = P9_FID_NONE;
- f->ref = 1;
- /*
- * Mark the fid as referenced so that the LRU
- * reclaim won't close the file descriptor
- */
- f->flags |= FID_REFERENCED;
- f->next = s->fid_list;
- s->fid_list = f;
-
- return f;
-}
-
-static int v9fs_xattr_fid_clunk(V9fsPDU *pdu, V9fsFidState *fidp)
-{
- int retval = 0;
-
- if (fidp->fs.xattr.copied_len == -1) {
- /* getxattr/listxattr fid */
- goto free_value;
- }
- /*
- * if this is fid for setxattr. clunk should
- * result in setxattr localcall
- */
- if (fidp->fs.xattr.len != fidp->fs.xattr.copied_len) {
- /* clunk after partial write */
- retval = -EINVAL;
- goto free_out;
- }
- if (fidp->fs.xattr.len) {
- retval = v9fs_co_lsetxattr(pdu, &fidp->path, &fidp->fs.xattr.name,
- fidp->fs.xattr.value,
- fidp->fs.xattr.len,
- fidp->fs.xattr.flags);
- } else {
- retval = v9fs_co_lremovexattr(pdu, &fidp->path, &fidp->fs.xattr.name);
- }
-free_out:
- v9fs_string_free(&fidp->fs.xattr.name);
-free_value:
- g_free(fidp->fs.xattr.value);
- return retval;
-}
-
-static int free_fid(V9fsPDU *pdu, V9fsFidState *fidp)
-{
- int retval = 0;
-
- if (fidp->fid_type == P9_FID_FILE) {
- /* If we reclaimed the fd no need to close */
- if (fidp->fs.fd != -1) {
- retval = v9fs_co_close(pdu, &fidp->fs);
- }
- } else if (fidp->fid_type == P9_FID_DIR) {
- if (fidp->fs.dir != NULL) {
- retval = v9fs_co_closedir(pdu, &fidp->fs);
- }
- } else if (fidp->fid_type == P9_FID_XATTR) {
- retval = v9fs_xattr_fid_clunk(pdu, fidp);
- }
- v9fs_path_free(&fidp->path);
- g_free(fidp);
- return retval;
-}
-
-static int put_fid(V9fsPDU *pdu, V9fsFidState *fidp)
-{
- BUG_ON(!fidp->ref);
- fidp->ref--;
- /*
- * Don't free the fid if it is in reclaim list
- */
- if (!fidp->ref && fidp->clunked) {
- if (fidp->fid == pdu->s->root_fid) {
- /*
- * if the clunked fid is root fid then we
- * have unmounted the fs on the client side.
- * delete the migration blocker. Ideally, this
- * should be hooked to transport close notification
- */
- if (pdu->s->migration_blocker) {
- migrate_del_blocker(pdu->s->migration_blocker);
- error_free(pdu->s->migration_blocker);
- pdu->s->migration_blocker = NULL;
- }
- }
- return free_fid(pdu, fidp);
- }
- return 0;
-}
-
-static V9fsFidState *clunk_fid(V9fsState *s, int32_t fid)
-{
- V9fsFidState **fidpp, *fidp;
-
- for (fidpp = &s->fid_list; *fidpp; fidpp = &(*fidpp)->next) {
- if ((*fidpp)->fid == fid) {
- break;
- }
- }
- if (*fidpp == NULL) {
- return NULL;
- }
- fidp = *fidpp;
- *fidpp = fidp->next;
- fidp->clunked = 1;
- return fidp;
-}
-
-void v9fs_reclaim_fd(V9fsPDU *pdu)
-{
- int reclaim_count = 0;
- V9fsState *s = pdu->s;
- V9fsFidState *f, *reclaim_list = NULL;
-
- for (f = s->fid_list; f; f = f->next) {
- /*
- * Unlink fids cannot be reclaimed. Check
- * for them and skip them. Also skip fids
- * currently being operated on.
- */
- if (f->ref || f->flags & FID_NON_RECLAIMABLE) {
- continue;
- }
- /*
- * if it is a recently referenced fid
- * we leave the fid untouched and clear the
- * reference bit. We come back to it later
- * in the next iteration. (a simple LRU without
- * moving list elements around)
- */
- if (f->flags & FID_REFERENCED) {
- f->flags &= ~FID_REFERENCED;
- continue;
- }
- /*
- * Add fids to reclaim list.
- */
- if (f->fid_type == P9_FID_FILE) {
- if (f->fs.fd != -1) {
- /*
- * Up the reference count so that
- * a clunk request won't free this fid
- */
- f->ref++;
- f->rclm_lst = reclaim_list;
- reclaim_list = f;
- f->fs_reclaim.fd = f->fs.fd;
- f->fs.fd = -1;
- reclaim_count++;
- }
- } else if (f->fid_type == P9_FID_DIR) {
- if (f->fs.dir != NULL) {
- /*
- * Up the reference count so that
- * a clunk request won't free this fid
- */
- f->ref++;
- f->rclm_lst = reclaim_list;
- reclaim_list = f;
- f->fs_reclaim.dir = f->fs.dir;
- f->fs.dir = NULL;
- reclaim_count++;
- }
- }
- if (reclaim_count >= open_fd_rc) {
- break;
- }
- }
- /*
- * Now close the fid in reclaim list. Free them if they
- * are already clunked.
- */
- while (reclaim_list) {
- f = reclaim_list;
- reclaim_list = f->rclm_lst;
- if (f->fid_type == P9_FID_FILE) {
- v9fs_co_close(pdu, &f->fs_reclaim);
- } else if (f->fid_type == P9_FID_DIR) {
- v9fs_co_closedir(pdu, &f->fs_reclaim);
- }
- f->rclm_lst = NULL;
- /*
- * Now drop the fid reference, free it
- * if clunked.
- */
- put_fid(pdu, f);
- }
-}
-
-static int v9fs_mark_fids_unreclaim(V9fsPDU *pdu, V9fsPath *path)
-{
- int err;
- V9fsState *s = pdu->s;
- V9fsFidState *fidp, head_fid;
-
- head_fid.next = s->fid_list;
- for (fidp = s->fid_list; fidp; fidp = fidp->next) {
- if (fidp->path.size != path->size) {
- continue;
- }
- if (!memcmp(fidp->path.data, path->data, path->size)) {
- /* Mark the fid non reclaimable. */
- fidp->flags |= FID_NON_RECLAIMABLE;
-
- /* reopen the file/dir if already closed */
- err = v9fs_reopen_fid(pdu, fidp);
- if (err < 0) {
- return -1;
- }
- /*
- * Go back to head of fid list because
- * the list could have got updated when
- * switched to the worker thread
- */
- if (err == 0) {
- fidp = &head_fid;
- }
- }
- }
- return 0;
-}
-
-static void virtfs_reset(V9fsPDU *pdu)
-{
- V9fsState *s = pdu->s;
- V9fsFidState *fidp = NULL;
-
- /* Free all fids */
- while (s->fid_list) {
- fidp = s->fid_list;
- s->fid_list = fidp->next;
-
- if (fidp->ref) {
- fidp->clunked = 1;
- } else {
- free_fid(pdu, fidp);
- }
- }
- if (fidp) {
- /* One or more unclunked fids found... */
- error_report("9pfs:%s: One or more uncluncked fids "
- "found during reset", __func__);
- }
-}
-
-#define P9_QID_TYPE_DIR 0x80
-#define P9_QID_TYPE_SYMLINK 0x02
-
-#define P9_STAT_MODE_DIR 0x80000000
-#define P9_STAT_MODE_APPEND 0x40000000
-#define P9_STAT_MODE_EXCL 0x20000000
-#define P9_STAT_MODE_MOUNT 0x10000000
-#define P9_STAT_MODE_AUTH 0x08000000
-#define P9_STAT_MODE_TMP 0x04000000
-#define P9_STAT_MODE_SYMLINK 0x02000000
-#define P9_STAT_MODE_LINK 0x01000000
-#define P9_STAT_MODE_DEVICE 0x00800000
-#define P9_STAT_MODE_NAMED_PIPE 0x00200000
-#define P9_STAT_MODE_SOCKET 0x00100000
-#define P9_STAT_MODE_SETUID 0x00080000
-#define P9_STAT_MODE_SETGID 0x00040000
-#define P9_STAT_MODE_SETVTX 0x00010000
-
-#define P9_STAT_MODE_TYPE_BITS (P9_STAT_MODE_DIR | \
- P9_STAT_MODE_SYMLINK | \
- P9_STAT_MODE_LINK | \
- P9_STAT_MODE_DEVICE | \
- P9_STAT_MODE_NAMED_PIPE | \
- P9_STAT_MODE_SOCKET)
-
-/* This is the algorithm from ufs in spfs */
-static void stat_to_qid(const struct stat *stbuf, V9fsQID *qidp)
-{
- size_t size;
-
- memset(&qidp->path, 0, sizeof(qidp->path));
- size = MIN(sizeof(stbuf->st_ino), sizeof(qidp->path));
- memcpy(&qidp->path, &stbuf->st_ino, size);
- qidp->version = stbuf->st_mtime ^ (stbuf->st_size << 8);
- qidp->type = 0;
- if (S_ISDIR(stbuf->st_mode)) {
- qidp->type |= P9_QID_TYPE_DIR;
- }
- if (S_ISLNK(stbuf->st_mode)) {
- qidp->type |= P9_QID_TYPE_SYMLINK;
- }
-}
-
-static int fid_to_qid(V9fsPDU *pdu, V9fsFidState *fidp, V9fsQID *qidp)
-{
- struct stat stbuf;
- int err;
-
- err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
- if (err < 0) {
- return err;
- }
- stat_to_qid(&stbuf, qidp);
- return 0;
-}
-
-V9fsPDU *pdu_alloc(V9fsState *s)
-{
- V9fsPDU *pdu = NULL;
-
- if (!QLIST_EMPTY(&s->free_list)) {
- pdu = QLIST_FIRST(&s->free_list);
- QLIST_REMOVE(pdu, next);
- QLIST_INSERT_HEAD(&s->active_list, pdu, next);
- }
- return pdu;
-}
-
-void pdu_free(V9fsPDU *pdu)
-{
- if (pdu) {
- V9fsState *s = pdu->s;
- /*
- * Cancelled pdu are added back to the freelist
- * by flush request .
- */
- if (!pdu->cancelled) {
- QLIST_REMOVE(pdu, next);
- QLIST_INSERT_HEAD(&s->free_list, pdu, next);
- }
- }
-}
-
-/*
- * We don't do error checking for pdu_marshal/unmarshal here
- * because we always expect to have enough space to encode
- * error details
- */
-static void pdu_complete(V9fsPDU *pdu, ssize_t len)
-{
- int8_t id = pdu->id + 1; /* Response */
- V9fsState *s = pdu->s;
-
- if (len < 0) {
- int err = -len;
- len = 7;
-
- if (s->proto_version != V9FS_PROTO_2000L) {
- V9fsString str;
-
- str.data = strerror(err);
- str.size = strlen(str.data);
-
- len += pdu_marshal(pdu, len, "s", &str);
- id = P9_RERROR;
- }
-
- len += pdu_marshal(pdu, len, "d", err);
-
- if (s->proto_version == V9FS_PROTO_2000L) {
- id = P9_RLERROR;
- }
- trace_v9fs_rerror(pdu->tag, pdu->id, err); /* Trace ERROR */
- }
-
- /* fill out the header */
- pdu_marshal(pdu, 0, "dbw", (int32_t)len, id, pdu->tag);
-
- /* keep these in sync */
- pdu->size = len;
- pdu->id = id;
-
- pdu_push_and_notify(pdu);
-
- /* Now wakeup anybody waiting in flush for this request */
- qemu_co_queue_next(&pdu->complete);
-
- pdu_free(pdu);
-}
-
-static mode_t v9mode_to_mode(uint32_t mode, V9fsString *extension)
-{
- mode_t ret;
-
- ret = mode & 0777;
- if (mode & P9_STAT_MODE_DIR) {
- ret |= S_IFDIR;
- }
-
- if (mode & P9_STAT_MODE_SYMLINK) {
- ret |= S_IFLNK;
- }
- if (mode & P9_STAT_MODE_SOCKET) {
- ret |= S_IFSOCK;
- }
- if (mode & P9_STAT_MODE_NAMED_PIPE) {
- ret |= S_IFIFO;
- }
- if (mode & P9_STAT_MODE_DEVICE) {
- if (extension->size && extension->data[0] == 'c') {
- ret |= S_IFCHR;
- } else {
- ret |= S_IFBLK;
- }
- }
-
- if (!(ret&~0777)) {
- ret |= S_IFREG;
- }
-
- if (mode & P9_STAT_MODE_SETUID) {
- ret |= S_ISUID;
- }
- if (mode & P9_STAT_MODE_SETGID) {
- ret |= S_ISGID;
- }
- if (mode & P9_STAT_MODE_SETVTX) {
- ret |= S_ISVTX;
- }
-
- return ret;
-}
-
-static int donttouch_stat(V9fsStat *stat)
-{
- if (stat->type == -1 &&
- stat->dev == -1 &&
- stat->qid.type == -1 &&
- stat->qid.version == -1 &&
- stat->qid.path == -1 &&
- stat->mode == -1 &&
- stat->atime == -1 &&
- stat->mtime == -1 &&
- stat->length == -1 &&
- !stat->name.size &&
- !stat->uid.size &&
- !stat->gid.size &&
- !stat->muid.size &&
- stat->n_uid == -1 &&
- stat->n_gid == -1 &&
- stat->n_muid == -1) {
- return 1;
- }
-
- return 0;
-}
-
-static void v9fs_stat_init(V9fsStat *stat)
-{
- v9fs_string_init(&stat->name);
- v9fs_string_init(&stat->uid);
- v9fs_string_init(&stat->gid);
- v9fs_string_init(&stat->muid);
- v9fs_string_init(&stat->extension);
-}
-
-static void v9fs_stat_free(V9fsStat *stat)
-{
- v9fs_string_free(&stat->name);
- v9fs_string_free(&stat->uid);
- v9fs_string_free(&stat->gid);
- v9fs_string_free(&stat->muid);
- v9fs_string_free(&stat->extension);
-}
-
-static uint32_t stat_to_v9mode(const struct stat *stbuf)
-{
- uint32_t mode;
-
- mode = stbuf->st_mode & 0777;
- if (S_ISDIR(stbuf->st_mode)) {
- mode |= P9_STAT_MODE_DIR;
- }
-
- if (S_ISLNK(stbuf->st_mode)) {
- mode |= P9_STAT_MODE_SYMLINK;
- }
-
- if (S_ISSOCK(stbuf->st_mode)) {
- mode |= P9_STAT_MODE_SOCKET;
- }
-
- if (S_ISFIFO(stbuf->st_mode)) {
- mode |= P9_STAT_MODE_NAMED_PIPE;
- }
-
- if (S_ISBLK(stbuf->st_mode) || S_ISCHR(stbuf->st_mode)) {
- mode |= P9_STAT_MODE_DEVICE;
- }
-
- if (stbuf->st_mode & S_ISUID) {
- mode |= P9_STAT_MODE_SETUID;
- }
-
- if (stbuf->st_mode & S_ISGID) {
- mode |= P9_STAT_MODE_SETGID;
- }
-
- if (stbuf->st_mode & S_ISVTX) {
- mode |= P9_STAT_MODE_SETVTX;
- }
-
- return mode;
-}
-
-static int stat_to_v9stat(V9fsPDU *pdu, V9fsPath *name,
- const struct stat *stbuf,
- V9fsStat *v9stat)
-{
- int err;
- const char *str;
-
- memset(v9stat, 0, sizeof(*v9stat));
-
- stat_to_qid(stbuf, &v9stat->qid);
- v9stat->mode = stat_to_v9mode(stbuf);
- v9stat->atime = stbuf->st_atime;
- v9stat->mtime = stbuf->st_mtime;
- v9stat->length = stbuf->st_size;
-
- v9fs_string_null(&v9stat->uid);
- v9fs_string_null(&v9stat->gid);
- v9fs_string_null(&v9stat->muid);
-
- v9stat->n_uid = stbuf->st_uid;
- v9stat->n_gid = stbuf->st_gid;
- v9stat->n_muid = 0;
-
- v9fs_string_null(&v9stat->extension);
-
- if (v9stat->mode & P9_STAT_MODE_SYMLINK) {
- err = v9fs_co_readlink(pdu, name, &v9stat->extension);
- if (err < 0) {
- return err;
- }
- } else if (v9stat->mode & P9_STAT_MODE_DEVICE) {
- v9fs_string_sprintf(&v9stat->extension, "%c %u %u",
- S_ISCHR(stbuf->st_mode) ? 'c' : 'b',
- major(stbuf->st_rdev), minor(stbuf->st_rdev));
- } else if (S_ISDIR(stbuf->st_mode) || S_ISREG(stbuf->st_mode)) {
- v9fs_string_sprintf(&v9stat->extension, "%s %lu",
- "HARDLINKCOUNT", (unsigned long)stbuf->st_nlink);
- }
-
- str = strrchr(name->data, '/');
- if (str) {
- str += 1;
- } else {
- str = name->data;
- }
-
- v9fs_string_sprintf(&v9stat->name, "%s", str);
-
- v9stat->size = 61 +
- v9fs_string_size(&v9stat->name) +
- v9fs_string_size(&v9stat->uid) +
- v9fs_string_size(&v9stat->gid) +
- v9fs_string_size(&v9stat->muid) +
- v9fs_string_size(&v9stat->extension);
- return 0;
-}
-
-#define P9_STATS_MODE 0x00000001ULL
-#define P9_STATS_NLINK 0x00000002ULL
-#define P9_STATS_UID 0x00000004ULL
-#define P9_STATS_GID 0x00000008ULL
-#define P9_STATS_RDEV 0x00000010ULL
-#define P9_STATS_ATIME 0x00000020ULL
-#define P9_STATS_MTIME 0x00000040ULL
-#define P9_STATS_CTIME 0x00000080ULL
-#define P9_STATS_INO 0x00000100ULL
-#define P9_STATS_SIZE 0x00000200ULL
-#define P9_STATS_BLOCKS 0x00000400ULL
-
-#define P9_STATS_BTIME 0x00000800ULL
-#define P9_STATS_GEN 0x00001000ULL
-#define P9_STATS_DATA_VERSION 0x00002000ULL
-
-#define P9_STATS_BASIC 0x000007ffULL /* Mask for fields up to BLOCKS */
-#define P9_STATS_ALL 0x00003fffULL /* Mask for All fields above */
-
-
-static void stat_to_v9stat_dotl(V9fsState *s, const struct stat *stbuf,
- V9fsStatDotl *v9lstat)
-{
- memset(v9lstat, 0, sizeof(*v9lstat));
-
- v9lstat->st_mode = stbuf->st_mode;
- v9lstat->st_nlink = stbuf->st_nlink;
- v9lstat->st_uid = stbuf->st_uid;
- v9lstat->st_gid = stbuf->st_gid;
- v9lstat->st_rdev = stbuf->st_rdev;
- v9lstat->st_size = stbuf->st_size;
- v9lstat->st_blksize = stbuf->st_blksize;
- v9lstat->st_blocks = stbuf->st_blocks;
- v9lstat->st_atime_sec = stbuf->st_atime;
- v9lstat->st_atime_nsec = stbuf->st_atim.tv_nsec;
- v9lstat->st_mtime_sec = stbuf->st_mtime;
- v9lstat->st_mtime_nsec = stbuf->st_mtim.tv_nsec;
- v9lstat->st_ctime_sec = stbuf->st_ctime;
- v9lstat->st_ctime_nsec = stbuf->st_ctim.tv_nsec;
- /* Currently we only support BASIC fields in stat */
- v9lstat->st_result_mask = P9_STATS_BASIC;
-
- stat_to_qid(stbuf, &v9lstat->qid);
-}
-
-static void print_sg(struct iovec *sg, int cnt)
-{
- int i;
-
- printf("sg[%d]: {", cnt);
- for (i = 0; i < cnt; i++) {
- if (i) {
- printf(", ");
- }
- printf("(%p, %zd)", sg[i].iov_base, sg[i].iov_len);
- }
- printf("}\n");
-}
-
-/* Will call this only for path name based fid */
-static void v9fs_fix_path(V9fsPath *dst, V9fsPath *src, int len)
-{
- V9fsPath str;
- v9fs_path_init(&str);
- v9fs_path_copy(&str, dst);
- v9fs_string_sprintf((V9fsString *)dst, "%s%s", src->data, str.data+len);
- v9fs_path_free(&str);
- /* +1 to include terminating NULL */
- dst->size++;
-}
-
-static inline bool is_ro_export(FsContext *ctx)
-{
- return ctx->export_flags & V9FS_RDONLY;
-}
-
-static void v9fs_version(void *opaque)
-{
- ssize_t err;
- V9fsPDU *pdu = opaque;
- V9fsState *s = pdu->s;
- V9fsString version;
- size_t offset = 7;
-
- v9fs_string_init(&version);
- err = pdu_unmarshal(pdu, offset, "ds", &s->msize, &version);
- if (err < 0) {
- offset = err;
- goto out;
- }
- trace_v9fs_version(pdu->tag, pdu->id, s->msize, version.data);
-
- virtfs_reset(pdu);
-
- if (!strcmp(version.data, "9P2000.u")) {
- s->proto_version = V9FS_PROTO_2000U;
- } else if (!strcmp(version.data, "9P2000.L")) {
- s->proto_version = V9FS_PROTO_2000L;
- } else {
- v9fs_string_sprintf(&version, "unknown");
- }
-
- err = pdu_marshal(pdu, offset, "ds", s->msize, &version);
- if (err < 0) {
- offset = err;
- goto out;
- }
- offset += err;
- trace_v9fs_version_return(pdu->tag, pdu->id, s->msize, version.data);
-out:
- pdu_complete(pdu, offset);
- v9fs_string_free(&version);
-}
-
-static void v9fs_attach(void *opaque)
-{
- V9fsPDU *pdu = opaque;
- V9fsState *s = pdu->s;
- int32_t fid, afid, n_uname;
- V9fsString uname, aname;
- V9fsFidState *fidp;
- size_t offset = 7;
- V9fsQID qid;
- ssize_t err;
-
- v9fs_string_init(&uname);
- v9fs_string_init(&aname);
- err = pdu_unmarshal(pdu, offset, "ddssd", &fid,
- &afid, &uname, &aname, &n_uname);
- if (err < 0) {
- goto out_nofid;
- }
- trace_v9fs_attach(pdu->tag, pdu->id, fid, afid, uname.data, aname.data);
-
- fidp = alloc_fid(s, fid);
- if (fidp == NULL) {
- err = -EINVAL;
- goto out_nofid;
- }
- fidp->uid = n_uname;
- err = v9fs_co_name_to_path(pdu, NULL, "/", &fidp->path);
- if (err < 0) {
- err = -EINVAL;
- clunk_fid(s, fid);
- goto out;
- }
- err = fid_to_qid(pdu, fidp, &qid);
- if (err < 0) {
- err = -EINVAL;
- clunk_fid(s, fid);
- goto out;
- }
- err = pdu_marshal(pdu, offset, "Q", &qid);
- if (err < 0) {
- clunk_fid(s, fid);
- goto out;
- }
- err += offset;
- trace_v9fs_attach_return(pdu->tag, pdu->id,
- qid.type, qid.version, qid.path);
- /*
- * disable migration if we haven't done already.
- * attach could get called multiple times for the same export.
- */
- if (!s->migration_blocker) {
- s->root_fid = fid;
- error_setg(&s->migration_blocker,
- "Migration is disabled when VirtFS export path '%s' is mounted in the guest using mount_tag '%s'",
- s->ctx.fs_root ? s->ctx.fs_root : "NULL", s->tag);
- migrate_add_blocker(s->migration_blocker);
- }
-out:
- put_fid(pdu, fidp);
-out_nofid:
- pdu_complete(pdu, err);
- v9fs_string_free(&uname);
- v9fs_string_free(&aname);
-}
-
-static void v9fs_stat(void *opaque)
-{
- int32_t fid;
- V9fsStat v9stat;
- ssize_t err = 0;
- size_t offset = 7;
- struct stat stbuf;
- V9fsFidState *fidp;
- V9fsPDU *pdu = opaque;
-
- err = pdu_unmarshal(pdu, offset, "d", &fid);
- if (err < 0) {
- goto out_nofid;
- }
- trace_v9fs_stat(pdu->tag, pdu->id, fid);
-
- fidp = get_fid(pdu, fid);
- if (fidp == NULL) {
- err = -ENOENT;
- goto out_nofid;
- }
- err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
- if (err < 0) {
- goto out;
- }
- err = stat_to_v9stat(pdu, &fidp->path, &stbuf, &v9stat);
- if (err < 0) {
- goto out;
- }
- err = pdu_marshal(pdu, offset, "wS", 0, &v9stat);
- if (err < 0) {
- v9fs_stat_free(&v9stat);
- goto out;
- }
- trace_v9fs_stat_return(pdu->tag, pdu->id, v9stat.mode,
- v9stat.atime, v9stat.mtime, v9stat.length);
- err += offset;
- v9fs_stat_free(&v9stat);
-out:
- put_fid(pdu, fidp);
-out_nofid:
- pdu_complete(pdu, err);
-}
-
-static void v9fs_getattr(void *opaque)
-{
- int32_t fid;
- size_t offset = 7;
- ssize_t retval = 0;
- struct stat stbuf;
- V9fsFidState *fidp;
- uint64_t request_mask;
- V9fsStatDotl v9stat_dotl;
- V9fsPDU *pdu = opaque;
- V9fsState *s = pdu->s;
-
- retval = pdu_unmarshal(pdu, offset, "dq", &fid, &request_mask);
- if (retval < 0) {
- goto out_nofid;
- }
- trace_v9fs_getattr(pdu->tag, pdu->id, fid, request_mask);
-
- fidp = get_fid(pdu, fid);
- if (fidp == NULL) {
- retval = -ENOENT;
- goto out_nofid;
- }
- /*
- * Currently we only support BASIC fields in stat, so there is no
- * need to look at request_mask.
- */
- retval = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
- if (retval < 0) {
- goto out;
- }
- stat_to_v9stat_dotl(s, &stbuf, &v9stat_dotl);
-
- /* fill st_gen if requested and supported by underlying fs */
- if (request_mask & P9_STATS_GEN) {
- retval = v9fs_co_st_gen(pdu, &fidp->path, stbuf.st_mode, &v9stat_dotl);
- switch (retval) {
- case 0:
- /* we have valid st_gen: update result mask */
- v9stat_dotl.st_result_mask |= P9_STATS_GEN;
- break;
- case -EINTR:
- /* request cancelled, e.g. by Tflush */
- goto out;
- default:
- /* failed to get st_gen: not fatal, ignore */
- break;
- }
- }
- retval = pdu_marshal(pdu, offset, "A", &v9stat_dotl);
- if (retval < 0) {
- goto out;
- }
- retval += offset;
- trace_v9fs_getattr_return(pdu->tag, pdu->id, v9stat_dotl.st_result_mask,
- v9stat_dotl.st_mode, v9stat_dotl.st_uid,
- v9stat_dotl.st_gid);
-out:
- put_fid(pdu, fidp);
-out_nofid:
- pdu_complete(pdu, retval);
-}
-
-/* Attribute flags */
-#define P9_ATTR_MODE (1 << 0)
-#define P9_ATTR_UID (1 << 1)
-#define P9_ATTR_GID (1 << 2)
-#define P9_ATTR_SIZE (1 << 3)
-#define P9_ATTR_ATIME (1 << 4)
-#define P9_ATTR_MTIME (1 << 5)
-#define P9_ATTR_CTIME (1 << 6)
-#define P9_ATTR_ATIME_SET (1 << 7)
-#define P9_ATTR_MTIME_SET (1 << 8)
-
-#define P9_ATTR_MASK 127
-
-static void v9fs_setattr(void *opaque)
-{
- int err = 0;
- int32_t fid;
- V9fsFidState *fidp;
- size_t offset = 7;
- V9fsIattr v9iattr;
- V9fsPDU *pdu = opaque;
-
- err = pdu_unmarshal(pdu, offset, "dI", &fid, &v9iattr);
- if (err < 0) {
- goto out_nofid;
- }
-
- fidp = get_fid(pdu, fid);
- if (fidp == NULL) {
- err = -EINVAL;
- goto out_nofid;
- }
- if (v9iattr.valid & P9_ATTR_MODE) {
- err = v9fs_co_chmod(pdu, &fidp->path, v9iattr.mode);
- if (err < 0) {
- goto out;
- }
- }
- if (v9iattr.valid & (P9_ATTR_ATIME | P9_ATTR_MTIME)) {
- struct timespec times[2];
- if (v9iattr.valid & P9_ATTR_ATIME) {
- if (v9iattr.valid & P9_ATTR_ATIME_SET) {
- times[0].tv_sec = v9iattr.atime_sec;
- times[0].tv_nsec = v9iattr.atime_nsec;
- } else {
- times[0].tv_nsec = UTIME_NOW;
- }
- } else {
- times[0].tv_nsec = UTIME_OMIT;
- }
- if (v9iattr.valid & P9_ATTR_MTIME) {
- if (v9iattr.valid & P9_ATTR_MTIME_SET) {
- times[1].tv_sec = v9iattr.mtime_sec;
- times[1].tv_nsec = v9iattr.mtime_nsec;
- } else {
- times[1].tv_nsec = UTIME_NOW;
- }
- } else {
- times[1].tv_nsec = UTIME_OMIT;
- }
- err = v9fs_co_utimensat(pdu, &fidp->path, times);
- if (err < 0) {
- goto out;
- }
- }
- /*
- * If the only valid entry in iattr is ctime we can call
- * chown(-1,-1) to update the ctime of the file
- */
- if ((v9iattr.valid & (P9_ATTR_UID | P9_ATTR_GID)) ||
- ((v9iattr.valid & P9_ATTR_CTIME)
- && !((v9iattr.valid & P9_ATTR_MASK) & ~P9_ATTR_CTIME))) {
- if (!(v9iattr.valid & P9_ATTR_UID)) {
- v9iattr.uid = -1;
- }
- if (!(v9iattr.valid & P9_ATTR_GID)) {
- v9iattr.gid = -1;
- }
- err = v9fs_co_chown(pdu, &fidp->path, v9iattr.uid,
- v9iattr.gid);
- if (err < 0) {
- goto out;
- }
- }
- if (v9iattr.valid & (P9_ATTR_SIZE)) {
- err = v9fs_co_truncate(pdu, &fidp->path, v9iattr.size);
- if (err < 0) {
- goto out;
- }
- }
- err = offset;
-out:
- put_fid(pdu, fidp);
-out_nofid:
- pdu_complete(pdu, err);
-}
-
-static int v9fs_walk_marshal(V9fsPDU *pdu, uint16_t nwnames, V9fsQID *qids)
-{
- int i;
- ssize_t err;
- size_t offset = 7;
-
- err = pdu_marshal(pdu, offset, "w", nwnames);
- if (err < 0) {
- return err;
- }
- offset += err;
- for (i = 0; i < nwnames; i++) {
- err = pdu_marshal(pdu, offset, "Q", &qids[i]);
- if (err < 0) {
- return err;
- }
- offset += err;
- }
- return offset;
-}
-
-static void v9fs_walk(void *opaque)
-{
- int name_idx;
- V9fsQID *qids = NULL;
- int i, err = 0;
- V9fsPath dpath, path;
- uint16_t nwnames;
- struct stat stbuf;
- size_t offset = 7;
- int32_t fid, newfid;
- V9fsString *wnames = NULL;
- V9fsFidState *fidp;
- V9fsFidState *newfidp = NULL;
- V9fsPDU *pdu = opaque;
- V9fsState *s = pdu->s;
-
- err = pdu_unmarshal(pdu, offset, "ddw", &fid, &newfid, &nwnames);
- if (err < 0) {
- pdu_complete(pdu, err);
- return ;
- }
- offset += err;
-
- trace_v9fs_walk(pdu->tag, pdu->id, fid, newfid, nwnames);
-
- if (nwnames && nwnames <= P9_MAXWELEM) {
- wnames = g_malloc0(sizeof(wnames[0]) * nwnames);
- qids = g_malloc0(sizeof(qids[0]) * nwnames);
- for (i = 0; i < nwnames; i++) {
- err = pdu_unmarshal(pdu, offset, "s", &wnames[i]);
- if (err < 0) {
- goto out_nofid;
- }
- offset += err;
- }
- } else if (nwnames > P9_MAXWELEM) {
- err = -EINVAL;
- goto out_nofid;
- }
- fidp = get_fid(pdu, fid);
- if (fidp == NULL) {
- err = -ENOENT;
- goto out_nofid;
- }
- v9fs_path_init(&dpath);
- v9fs_path_init(&path);
- /*
- * Both dpath and path initially poin to fidp.
- * Needed to handle request with nwnames == 0
- */
- v9fs_path_copy(&dpath, &fidp->path);
- v9fs_path_copy(&path, &fidp->path);
- for (name_idx = 0; name_idx < nwnames; name_idx++) {
- err = v9fs_co_name_to_path(pdu, &dpath, wnames[name_idx].data, &path);
- if (err < 0) {
- goto out;
- }
- err = v9fs_co_lstat(pdu, &path, &stbuf);
- if (err < 0) {
- goto out;
- }
- stat_to_qid(&stbuf, &qids[name_idx]);
- v9fs_path_copy(&dpath, &path);
- }
- if (fid == newfid) {
- BUG_ON(fidp->fid_type != P9_FID_NONE);
- v9fs_path_copy(&fidp->path, &path);
- } else {
- newfidp = alloc_fid(s, newfid);
- if (newfidp == NULL) {
- err = -EINVAL;
- goto out;
- }
- newfidp->uid = fidp->uid;
- v9fs_path_copy(&newfidp->path, &path);
- }
- err = v9fs_walk_marshal(pdu, nwnames, qids);
- trace_v9fs_walk_return(pdu->tag, pdu->id, nwnames, qids);
-out:
- put_fid(pdu, fidp);
- if (newfidp) {
- put_fid(pdu, newfidp);
- }
- v9fs_path_free(&dpath);
- v9fs_path_free(&path);
-out_nofid:
- pdu_complete(pdu, err);
- if (nwnames && nwnames <= P9_MAXWELEM) {
- for (name_idx = 0; name_idx < nwnames; name_idx++) {
- v9fs_string_free(&wnames[name_idx]);
- }
- g_free(wnames);
- g_free(qids);
- }
-}
-
-static int32_t get_iounit(V9fsPDU *pdu, V9fsPath *path)
-{
- struct statfs stbuf;
- int32_t iounit = 0;
- V9fsState *s = pdu->s;
-
- /*
- * iounit should be multiples of f_bsize (host filesystem block size
- * and as well as less than (client msize - P9_IOHDRSZ))
- */
- if (!v9fs_co_statfs(pdu, path, &stbuf)) {
- iounit = stbuf.f_bsize;
- iounit *= (s->msize - P9_IOHDRSZ)/stbuf.f_bsize;
- }
- if (!iounit) {
- iounit = s->msize - P9_IOHDRSZ;
- }
- return iounit;
-}
-
-static void v9fs_open(void *opaque)
-{
- int flags;
- int32_t fid;
- int32_t mode;
- V9fsQID qid;
- int iounit = 0;
- ssize_t err = 0;
- size_t offset = 7;
- struct stat stbuf;
- V9fsFidState *fidp;
- V9fsPDU *pdu = opaque;
- V9fsState *s = pdu->s;
-
- if (s->proto_version == V9FS_PROTO_2000L) {
- err = pdu_unmarshal(pdu, offset, "dd", &fid, &mode);
- } else {
- uint8_t modebyte;
- err = pdu_unmarshal(pdu, offset, "db", &fid, &modebyte);
- mode = modebyte;
- }
- if (err < 0) {
- goto out_nofid;
- }
- trace_v9fs_open(pdu->tag, pdu->id, fid, mode);
-
- fidp = get_fid(pdu, fid);
- if (fidp == NULL) {
- err = -ENOENT;
- goto out_nofid;
- }
- BUG_ON(fidp->fid_type != P9_FID_NONE);
-
- err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
- if (err < 0) {
- goto out;
- }
- stat_to_qid(&stbuf, &qid);
- if (S_ISDIR(stbuf.st_mode)) {
- err = v9fs_co_opendir(pdu, fidp);
- if (err < 0) {
- goto out;
- }
- fidp->fid_type = P9_FID_DIR;
- err = pdu_marshal(pdu, offset, "Qd", &qid, 0);
- if (err < 0) {
- goto out;
- }
- err += offset;
- } else {
- if (s->proto_version == V9FS_PROTO_2000L) {
- flags = get_dotl_openflags(s, mode);
- } else {
- flags = omode_to_uflags(mode);
- }
- if (is_ro_export(&s->ctx)) {
- if (mode & O_WRONLY || mode & O_RDWR ||
- mode & O_APPEND || mode & O_TRUNC) {
- err = -EROFS;
- goto out;
- }
- }
- err = v9fs_co_open(pdu, fidp, flags);
- if (err < 0) {
- goto out;
- }
- fidp->fid_type = P9_FID_FILE;
- fidp->open_flags = flags;
- if (flags & O_EXCL) {
- /*
- * We let the host file system do O_EXCL check
- * We should not reclaim such fd
- */
- fidp->flags |= FID_NON_RECLAIMABLE;
- }
- iounit = get_iounit(pdu, &fidp->path);
- err = pdu_marshal(pdu, offset, "Qd", &qid, iounit);
- if (err < 0) {
- goto out;
- }
- err += offset;
- }
- trace_v9fs_open_return(pdu->tag, pdu->id,
- qid.type, qid.version, qid.path, iounit);
-out:
- put_fid(pdu, fidp);
-out_nofid:
- pdu_complete(pdu, err);
-}
-
-static void v9fs_lcreate(void *opaque)
-{
- int32_t dfid, flags, mode;
- gid_t gid;
- ssize_t err = 0;
- ssize_t offset = 7;
- V9fsString name;
- V9fsFidState *fidp;
- struct stat stbuf;
- V9fsQID qid;
- int32_t iounit;
- V9fsPDU *pdu = opaque;
-
- v9fs_string_init(&name);
- err = pdu_unmarshal(pdu, offset, "dsddd", &dfid,
- &name, &flags, &mode, &gid);
- if (err < 0) {
- goto out_nofid;
- }
- trace_v9fs_lcreate(pdu->tag, pdu->id, dfid, flags, mode, gid);
-
- fidp = get_fid(pdu, dfid);
- if (fidp == NULL) {
- err = -ENOENT;
- goto out_nofid;
- }
-
- flags = get_dotl_openflags(pdu->s, flags);
- err = v9fs_co_open2(pdu, fidp, &name, gid,
- flags | O_CREAT, mode, &stbuf);
- if (err < 0) {
- goto out;
- }
- fidp->fid_type = P9_FID_FILE;
- fidp->open_flags = flags;
- if (flags & O_EXCL) {
- /*
- * We let the host file system do O_EXCL check
- * We should not reclaim such fd
- */
- fidp->flags |= FID_NON_RECLAIMABLE;
- }
- iounit = get_iounit(pdu, &fidp->path);
- stat_to_qid(&stbuf, &qid);
- err = pdu_marshal(pdu, offset, "Qd", &qid, iounit);
- if (err < 0) {
- goto out;
- }
- err += offset;
- trace_v9fs_lcreate_return(pdu->tag, pdu->id,
- qid.type, qid.version, qid.path, iounit);
-out:
- put_fid(pdu, fidp);
-out_nofid:
- pdu_complete(pdu, err);
- v9fs_string_free(&name);
-}
-
-static void v9fs_fsync(void *opaque)
-{
- int err;
- int32_t fid;
- int datasync;
- size_t offset = 7;
- V9fsFidState *fidp;
- V9fsPDU *pdu = opaque;
-
- err = pdu_unmarshal(pdu, offset, "dd", &fid, &datasync);
- if (err < 0) {
- goto out_nofid;
- }
- trace_v9fs_fsync(pdu->tag, pdu->id, fid, datasync);
-
- fidp = get_fid(pdu, fid);
- if (fidp == NULL) {
- err = -ENOENT;
- goto out_nofid;
- }
- err = v9fs_co_fsync(pdu, fidp, datasync);
- if (!err) {
- err = offset;
- }
- put_fid(pdu, fidp);
-out_nofid:
- pdu_complete(pdu, err);
-}
-
-static void v9fs_clunk(void *opaque)
-{
- int err;
- int32_t fid;
- size_t offset = 7;
- V9fsFidState *fidp;
- V9fsPDU *pdu = opaque;
- V9fsState *s = pdu->s;
-
- err = pdu_unmarshal(pdu, offset, "d", &fid);
- if (err < 0) {
- goto out_nofid;
- }
- trace_v9fs_clunk(pdu->tag, pdu->id, fid);
-
- fidp = clunk_fid(s, fid);
- if (fidp == NULL) {
- err = -ENOENT;
- goto out_nofid;
- }
- /*
- * Bump the ref so that put_fid will
- * free the fid.
- */
- fidp->ref++;
- err = put_fid(pdu, fidp);
- if (!err) {
- err = offset;
- }
-out_nofid:
- pdu_complete(pdu, err);
-}
-
-static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
- uint64_t off, uint32_t max_count)
-{
- ssize_t err;
- size_t offset = 7;
- int read_count;
- int64_t xattr_len;
- V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
- VirtQueueElement *elem = v->elems[pdu->idx];
-
- xattr_len = fidp->fs.xattr.len;
- read_count = xattr_len - off;
- if (read_count > max_count) {
- read_count = max_count;
- } else if (read_count < 0) {
- /*
- * read beyond XATTR value
- */
- read_count = 0;
- }
- err = pdu_marshal(pdu, offset, "d", read_count);
- if (err < 0) {
- return err;
- }
- offset += err;
-
- err = v9fs_pack(elem->in_sg, elem->in_num, offset,
- ((char *)fidp->fs.xattr.value) + off,
- read_count);
- if (err < 0) {
- return err;
- }
- offset += err;
- return offset;
-}
-
-static int v9fs_do_readdir_with_stat(V9fsPDU *pdu,
- V9fsFidState *fidp, uint32_t max_count)
-{
- V9fsPath path;
- V9fsStat v9stat;
- int len, err = 0;
- int32_t count = 0;
- struct stat stbuf;
- off_t saved_dir_pos;
- struct dirent *dent, *result;
-
- /* save the directory position */
- saved_dir_pos = v9fs_co_telldir(pdu, fidp);
- if (saved_dir_pos < 0) {
- return saved_dir_pos;
- }
-
- dent = g_malloc(sizeof(struct dirent));
-
- while (1) {
- v9fs_path_init(&path);
- err = v9fs_co_readdir_r(pdu, fidp, dent, &result);
- if (err || !result) {
- break;
- }
- err = v9fs_co_name_to_path(pdu, &fidp->path, dent->d_name, &path);
- if (err < 0) {
- goto out;
- }
- err = v9fs_co_lstat(pdu, &path, &stbuf);
- if (err < 0) {
- goto out;
- }
- err = stat_to_v9stat(pdu, &path, &stbuf, &v9stat);
- if (err < 0) {
- goto out;
- }
- /* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */
- len = pdu_marshal(pdu, 11 + count, "S", &v9stat);
- if ((len != (v9stat.size + 2)) || ((count + len) > max_count)) {
- /* Ran out of buffer. Set dir back to old position and return */
- v9fs_co_seekdir(pdu, fidp, saved_dir_pos);
- v9fs_stat_free(&v9stat);
- v9fs_path_free(&path);
- g_free(dent);
- return count;
- }
- count += len;
- v9fs_stat_free(&v9stat);
- v9fs_path_free(&path);
- saved_dir_pos = dent->d_off;
- }
-out:
- g_free(dent);
- v9fs_path_free(&path);
- if (err < 0) {
- return err;
- }
- return count;
-}
-
-/*
- * Create a QEMUIOVector for a sub-region of PDU iovecs
- *
- * @qiov: uninitialized QEMUIOVector
- * @skip: number of bytes to skip from beginning of PDU
- * @size: number of bytes to include
- * @is_write: true - write, false - read
- *
- * The resulting QEMUIOVector has heap-allocated iovecs and must be cleaned up
- * with qemu_iovec_destroy().
- */
-static void v9fs_init_qiov_from_pdu(QEMUIOVector *qiov, V9fsPDU *pdu,
- size_t skip, size_t size,
- bool is_write)
-{
- QEMUIOVector elem;
- struct iovec *iov;
- unsigned int niov;
-
- virtio_init_iov_from_pdu(pdu, &iov, &niov, is_write);
-
- qemu_iovec_init_external(&elem, iov, niov);
- qemu_iovec_init(qiov, niov);
- qemu_iovec_concat(qiov, &elem, skip, size);
-}
-
-static void v9fs_read(void *opaque)
-{
- int32_t fid;
- uint64_t off;
- ssize_t err = 0;
- int32_t count = 0;
- size_t offset = 7;
- uint32_t max_count;
- V9fsFidState *fidp;
- V9fsPDU *pdu = opaque;
- V9fsState *s = pdu->s;
-
- err = pdu_unmarshal(pdu, offset, "dqd", &fid, &off, &max_count);
- if (err < 0) {
- goto out_nofid;
- }
- trace_v9fs_read(pdu->tag, pdu->id, fid, off, max_count);
-
- fidp = get_fid(pdu, fid);
- if (fidp == NULL) {
- err = -EINVAL;
- goto out_nofid;
- }
- if (fidp->fid_type == P9_FID_DIR) {
-
- if (off == 0) {
- v9fs_co_rewinddir(pdu, fidp);
- }
- count = v9fs_do_readdir_with_stat(pdu, fidp, max_count);
- if (count < 0) {
- err = count;
- goto out;
- }
- err = pdu_marshal(pdu, offset, "d", count);
- if (err < 0) {
- goto out;
- }
- err += offset + count;
- } else if (fidp->fid_type == P9_FID_FILE) {
- QEMUIOVector qiov_full;
- QEMUIOVector qiov;
- int32_t len;
-
- v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset + 4, max_count, false);
- qemu_iovec_init(&qiov, qiov_full.niov);
- do {
- qemu_iovec_reset(&qiov);
- qemu_iovec_concat(&qiov, &qiov_full, count, qiov_full.size - count);
- if (0) {
- print_sg(qiov.iov, qiov.niov);
- }
- /* Loop in case of EINTR */
- do {
- len = v9fs_co_preadv(pdu, fidp, qiov.iov, qiov.niov, off);
- if (len >= 0) {
- off += len;
- count += len;
- }
- } while (len == -EINTR && !pdu->cancelled);
- if (len < 0) {
- /* IO error return the error */
- err = len;
- goto out;
- }
- } while (count < max_count && len > 0);
- err = pdu_marshal(pdu, offset, "d", count);
- if (err < 0) {
- goto out;
- }
- err += offset + count;
- qemu_iovec_destroy(&qiov);
- qemu_iovec_destroy(&qiov_full);
- } else if (fidp->fid_type == P9_FID_XATTR) {
- err = v9fs_xattr_read(s, pdu, fidp, off, max_count);
- } else {
- err = -EINVAL;
- }
- trace_v9fs_read_return(pdu->tag, pdu->id, count, err);
-out:
- put_fid(pdu, fidp);
-out_nofid:
- pdu_complete(pdu, err);
-}
-
-static size_t v9fs_readdir_data_size(V9fsString *name)
-{
- /*
- * Size of each dirent on the wire: size of qid (13) + size of offset (8)
- * size of type (1) + size of name.size (2) + strlen(name.data)
- */
- return 24 + v9fs_string_size(name);
-}
-
-static int v9fs_do_readdir(V9fsPDU *pdu,
- V9fsFidState *fidp, int32_t max_count)
-{
- size_t size;
- V9fsQID qid;
- V9fsString name;
- int len, err = 0;
- int32_t count = 0;
- off_t saved_dir_pos;
- struct dirent *dent, *result;
-
- /* save the directory position */
- saved_dir_pos = v9fs_co_telldir(pdu, fidp);
- if (saved_dir_pos < 0) {
- return saved_dir_pos;
- }
-
- dent = g_malloc(sizeof(struct dirent));
-
- while (1) {
- err = v9fs_co_readdir_r(pdu, fidp, dent, &result);
- if (err || !result) {
- break;
- }
- v9fs_string_init(&name);
- v9fs_string_sprintf(&name, "%s", dent->d_name);
- if ((count + v9fs_readdir_data_size(&name)) > max_count) {
- /* Ran out of buffer. Set dir back to old position and return */
- v9fs_co_seekdir(pdu, fidp, saved_dir_pos);
- v9fs_string_free(&name);
- g_free(dent);
- return count;
- }
- /*
- * Fill up just the path field of qid because the client uses
- * only that. To fill the entire qid structure we will have
- * to stat each dirent found, which is expensive
- */
- size = MIN(sizeof(dent->d_ino), sizeof(qid.path));
- memcpy(&qid.path, &dent->d_ino, size);
- /* Fill the other fields with dummy values */
- qid.type = 0;
- qid.version = 0;
-
- /* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */
- len = pdu_marshal(pdu, 11 + count, "Qqbs",
- &qid, dent->d_off,
- dent->d_type, &name);
- if (len < 0) {
- v9fs_co_seekdir(pdu, fidp, saved_dir_pos);
- v9fs_string_free(&name);
- g_free(dent);
- return len;
- }
- count += len;
- v9fs_string_free(&name);
- saved_dir_pos = dent->d_off;
- }
- g_free(dent);
- if (err < 0) {
- return err;
- }
- return count;
-}
-
-static void v9fs_readdir(void *opaque)
-{
- int32_t fid;
- V9fsFidState *fidp;
- ssize_t retval = 0;
- size_t offset = 7;
- uint64_t initial_offset;
- int32_t count;
- uint32_t max_count;
- V9fsPDU *pdu = opaque;
-
- retval = pdu_unmarshal(pdu, offset, "dqd", &fid,
- &initial_offset, &max_count);
- if (retval < 0) {
- goto out_nofid;
- }
- trace_v9fs_readdir(pdu->tag, pdu->id, fid, initial_offset, max_count);
-
- fidp = get_fid(pdu, fid);
- if (fidp == NULL) {
- retval = -EINVAL;
- goto out_nofid;
- }
- if (!fidp->fs.dir) {
- retval = -EINVAL;
- goto out;
- }
- if (initial_offset == 0) {
- v9fs_co_rewinddir(pdu, fidp);
- } else {
- v9fs_co_seekdir(pdu, fidp, initial_offset);
- }
- count = v9fs_do_readdir(pdu, fidp, max_count);
- if (count < 0) {
- retval = count;
- goto out;
- }
- retval = pdu_marshal(pdu, offset, "d", count);
- if (retval < 0) {
- goto out;
- }
- retval += count + offset;
- trace_v9fs_readdir_return(pdu->tag, pdu->id, count, retval);
-out:
- put_fid(pdu, fidp);
-out_nofid:
- pdu_complete(pdu, retval);
-}
-
-static int v9fs_xattr_write(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
- uint64_t off, uint32_t count,
- struct iovec *sg, int cnt)
-{
- int i, to_copy;
- ssize_t err = 0;
- int write_count;
- int64_t xattr_len;
- size_t offset = 7;
-
-
- xattr_len = fidp->fs.xattr.len;
- write_count = xattr_len - off;
- if (write_count > count) {
- write_count = count;
- } else if (write_count < 0) {
- /*
- * write beyond XATTR value len specified in
- * xattrcreate
- */
- err = -ENOSPC;
- goto out;
- }
- err = pdu_marshal(pdu, offset, "d", write_count);
- if (err < 0) {
- return err;
- }
- err += offset;
- fidp->fs.xattr.copied_len += write_count;
- /*
- * Now copy the content from sg list
- */
- for (i = 0; i < cnt; i++) {
- if (write_count > sg[i].iov_len) {
- to_copy = sg[i].iov_len;
- } else {
- to_copy = write_count;
- }
- memcpy((char *)fidp->fs.xattr.value + off, sg[i].iov_base, to_copy);
- /* updating vs->off since we are not using below */
- off += to_copy;
- write_count -= to_copy;
- }
-out:
- return err;
-}
-
-static void v9fs_write(void *opaque)
-{
- ssize_t err;
- int32_t fid;
- uint64_t off;
- uint32_t count;
- int32_t len = 0;
- int32_t total = 0;
- size_t offset = 7;
- V9fsFidState *fidp;
- V9fsPDU *pdu = opaque;
- V9fsState *s = pdu->s;
- QEMUIOVector qiov_full;
- QEMUIOVector qiov;
-
- err = pdu_unmarshal(pdu, offset, "dqd", &fid, &off, &count);
- if (err < 0) {
- pdu_complete(pdu, err);
- return;
- }
- offset += err;
- v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset, count, true);
- trace_v9fs_write(pdu->tag, pdu->id, fid, off, count, qiov_full.niov);
-
- fidp = get_fid(pdu, fid);
- if (fidp == NULL) {
- err = -EINVAL;
- goto out_nofid;
- }
- if (fidp->fid_type == P9_FID_FILE) {
- if (fidp->fs.fd == -1) {
- err = -EINVAL;
- goto out;
- }
- } else if (fidp->fid_type == P9_FID_XATTR) {
- /*
- * setxattr operation
- */
- err = v9fs_xattr_write(s, pdu, fidp, off, count,
- qiov_full.iov, qiov_full.niov);
- goto out;
- } else {
- err = -EINVAL;
- goto out;
- }
- qemu_iovec_init(&qiov, qiov_full.niov);
- do {
- qemu_iovec_reset(&qiov);
- qemu_iovec_concat(&qiov, &qiov_full, total, qiov_full.size - total);
- if (0) {
- print_sg(qiov.iov, qiov.niov);
- }
- /* Loop in case of EINTR */
- do {
- len = v9fs_co_pwritev(pdu, fidp, qiov.iov, qiov.niov, off);
- if (len >= 0) {
- off += len;
- total += len;
- }
- } while (len == -EINTR && !pdu->cancelled);
- if (len < 0) {
- /* IO error return the error */
- err = len;
- goto out_qiov;
- }
- } while (total < count && len > 0);
-
- offset = 7;
- err = pdu_marshal(pdu, offset, "d", total);
- if (err < 0) {
- goto out;
- }
- err += offset;
- trace_v9fs_write_return(pdu->tag, pdu->id, total, err);
-out_qiov:
- qemu_iovec_destroy(&qiov);
-out:
- put_fid(pdu, fidp);
-out_nofid:
- qemu_iovec_destroy(&qiov_full);
- pdu_complete(pdu, err);
-}
-
-static void v9fs_create(void *opaque)
-{
- int32_t fid;
- int err = 0;
- size_t offset = 7;
- V9fsFidState *fidp;
- V9fsQID qid;
- int32_t perm;
- int8_t mode;
- V9fsPath path;
- struct stat stbuf;
- V9fsString name;
- V9fsString extension;
- int iounit;
- V9fsPDU *pdu = opaque;
-
- v9fs_path_init(&path);
- v9fs_string_init(&name);
- v9fs_string_init(&extension);
- err = pdu_unmarshal(pdu, offset, "dsdbs", &fid, &name,
- &perm, &mode, &extension);
- if (err < 0) {
- goto out_nofid;
- }
- trace_v9fs_create(pdu->tag, pdu->id, fid, name.data, perm, mode);
-
- fidp = get_fid(pdu, fid);
- if (fidp == NULL) {
- err = -EINVAL;
- goto out_nofid;
- }
- if (perm & P9_STAT_MODE_DIR) {
- err = v9fs_co_mkdir(pdu, fidp, &name, perm & 0777,
- fidp->uid, -1, &stbuf);
- if (err < 0) {
- goto out;
- }
- err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
- if (err < 0) {
- goto out;
- }
- v9fs_path_copy(&fidp->path, &path);
- err = v9fs_co_opendir(pdu, fidp);
- if (err < 0) {
- goto out;
- }
- fidp->fid_type = P9_FID_DIR;
- } else if (perm & P9_STAT_MODE_SYMLINK) {
- err = v9fs_co_symlink(pdu, fidp, &name,
- extension.data, -1 , &stbuf);
- if (err < 0) {
- goto out;
- }
- err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
- if (err < 0) {
- goto out;
- }
- v9fs_path_copy(&fidp->path, &path);
- } else if (perm & P9_STAT_MODE_LINK) {
- int32_t ofid = atoi(extension.data);
- V9fsFidState *ofidp = get_fid(pdu, ofid);
- if (ofidp == NULL) {
- err = -EINVAL;
- goto out;
- }
- err = v9fs_co_link(pdu, ofidp, fidp, &name);
- put_fid(pdu, ofidp);
- if (err < 0) {
- goto out;
- }
- err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
- if (err < 0) {
- fidp->fid_type = P9_FID_NONE;
- goto out;
- }
- v9fs_path_copy(&fidp->path, &path);
- err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
- if (err < 0) {
- fidp->fid_type = P9_FID_NONE;
- goto out;
- }
- } else if (perm & P9_STAT_MODE_DEVICE) {
- char ctype;
- uint32_t major, minor;
- mode_t nmode = 0;
-
- if (sscanf(extension.data, "%c %u %u", &ctype, &major, &minor) != 3) {
- err = -errno;
- goto out;
- }
-
- switch (ctype) {
- case 'c':
- nmode = S_IFCHR;
- break;
- case 'b':
- nmode = S_IFBLK;
- break;
- default:
- err = -EIO;
- goto out;
- }
-
- nmode |= perm & 0777;
- err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
- makedev(major, minor), nmode, &stbuf);
- if (err < 0) {
- goto out;
- }
- err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
- if (err < 0) {
- goto out;
- }
- v9fs_path_copy(&fidp->path, &path);
- } else if (perm & P9_STAT_MODE_NAMED_PIPE) {
- err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
- 0, S_IFIFO | (perm & 0777), &stbuf);
- if (err < 0) {
- goto out;
- }
- err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
- if (err < 0) {
- goto out;
- }
- v9fs_path_copy(&fidp->path, &path);
- } else if (perm & P9_STAT_MODE_SOCKET) {
- err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
- 0, S_IFSOCK | (perm & 0777), &stbuf);
- if (err < 0) {
- goto out;
- }
- err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
- if (err < 0) {
- goto out;
- }
- v9fs_path_copy(&fidp->path, &path);
- } else {
- err = v9fs_co_open2(pdu, fidp, &name, -1,
- omode_to_uflags(mode)|O_CREAT, perm, &stbuf);
- if (err < 0) {
- goto out;
- }
- fidp->fid_type = P9_FID_FILE;
- fidp->open_flags = omode_to_uflags(mode);
- if (fidp->open_flags & O_EXCL) {
- /*
- * We let the host file system do O_EXCL check
- * We should not reclaim such fd
- */
- fidp->flags |= FID_NON_RECLAIMABLE;
- }
- }
- iounit = get_iounit(pdu, &fidp->path);
- stat_to_qid(&stbuf, &qid);
- err = pdu_marshal(pdu, offset, "Qd", &qid, iounit);
- if (err < 0) {
- goto out;
- }
- err += offset;
- trace_v9fs_create_return(pdu->tag, pdu->id,
- qid.type, qid.version, qid.path, iounit);
-out:
- put_fid(pdu, fidp);
-out_nofid:
- pdu_complete(pdu, err);
- v9fs_string_free(&name);
- v9fs_string_free(&extension);
- v9fs_path_free(&path);
-}
-
-static void v9fs_symlink(void *opaque)
-{
- V9fsPDU *pdu = opaque;
- V9fsString name;
- V9fsString symname;
- V9fsFidState *dfidp;
- V9fsQID qid;
- struct stat stbuf;
- int32_t dfid;
- int err = 0;
- gid_t gid;
- size_t offset = 7;
-
- v9fs_string_init(&name);
- v9fs_string_init(&symname);
- err = pdu_unmarshal(pdu, offset, "dssd", &dfid, &name, &symname, &gid);
- if (err < 0) {
- goto out_nofid;
- }
- trace_v9fs_symlink(pdu->tag, pdu->id, dfid, name.data, symname.data, gid);
-
- dfidp = get_fid(pdu, dfid);
- if (dfidp == NULL) {
- err = -EINVAL;
- goto out_nofid;
- }
- err = v9fs_co_symlink(pdu, dfidp, &name, symname.data, gid, &stbuf);
- if (err < 0) {
- goto out;
- }
- stat_to_qid(&stbuf, &qid);
- err = pdu_marshal(pdu, offset, "Q", &qid);
- if (err < 0) {
- goto out;
- }
- err += offset;
- trace_v9fs_symlink_return(pdu->tag, pdu->id,
- qid.type, qid.version, qid.path);
-out:
- put_fid(pdu, dfidp);
-out_nofid:
- pdu_complete(pdu, err);
- v9fs_string_free(&name);
- v9fs_string_free(&symname);
-}
-
-static void v9fs_flush(void *opaque)
-{
- ssize_t err;
- int16_t tag;
- size_t offset = 7;
- V9fsPDU *cancel_pdu;
- V9fsPDU *pdu = opaque;
- V9fsState *s = pdu->s;
-
- err = pdu_unmarshal(pdu, offset, "w", &tag);
- if (err < 0) {
- pdu_complete(pdu, err);
- return;
- }
- trace_v9fs_flush(pdu->tag, pdu->id, tag);
-
- QLIST_FOREACH(cancel_pdu, &s->active_list, next) {
- if (cancel_pdu->tag == tag) {
- break;
- }
- }
- if (cancel_pdu) {
- cancel_pdu->cancelled = 1;
- /*
- * Wait for pdu to complete.
- */
- qemu_co_queue_wait(&cancel_pdu->complete);
- cancel_pdu->cancelled = 0;
- pdu_free(cancel_pdu);
- }
- pdu_complete(pdu, 7);
-}
-
-static void v9fs_link(void *opaque)
-{
- V9fsPDU *pdu = opaque;
- int32_t dfid, oldfid;
- V9fsFidState *dfidp, *oldfidp;
- V9fsString name;
- size_t offset = 7;
- int err = 0;
-
- v9fs_string_init(&name);
- err = pdu_unmarshal(pdu, offset, "dds", &dfid, &oldfid, &name);
- if (err < 0) {
- goto out_nofid;
- }
- trace_v9fs_link(pdu->tag, pdu->id, dfid, oldfid, name.data);
-
- dfidp = get_fid(pdu, dfid);
- if (dfidp == NULL) {
- err = -ENOENT;
- goto out_nofid;
- }
-
- oldfidp = get_fid(pdu, oldfid);
- if (oldfidp == NULL) {
- err = -ENOENT;
- goto out;
- }
- err = v9fs_co_link(pdu, oldfidp, dfidp, &name);
- if (!err) {
- err = offset;
- }
-out:
- put_fid(pdu, dfidp);
-out_nofid:
- v9fs_string_free(&name);
- pdu_complete(pdu, err);
-}
-
-/* Only works with path name based fid */
-static void v9fs_remove(void *opaque)
-{
- int32_t fid;
- int err = 0;
- size_t offset = 7;
- V9fsFidState *fidp;
- V9fsPDU *pdu = opaque;
-
- err = pdu_unmarshal(pdu, offset, "d", &fid);
- if (err < 0) {
- goto out_nofid;
- }
- trace_v9fs_remove(pdu->tag, pdu->id, fid);
-
- fidp = get_fid(pdu, fid);
- if (fidp == NULL) {
- err = -EINVAL;
- goto out_nofid;
- }
- /* if fs driver is not path based, return EOPNOTSUPP */
- if (!(pdu->s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT)) {
- err = -EOPNOTSUPP;
- goto out_err;
- }
- /*
- * IF the file is unlinked, we cannot reopen
- * the file later. So don't reclaim fd
- */
- err = v9fs_mark_fids_unreclaim(pdu, &fidp->path);
- if (err < 0) {
- goto out_err;
- }
- err = v9fs_co_remove(pdu, &fidp->path);
- if (!err) {
- err = offset;
- }
-out_err:
- /* For TREMOVE we need to clunk the fid even on failed remove */
- clunk_fid(pdu->s, fidp->fid);
- put_fid(pdu, fidp);
-out_nofid:
- pdu_complete(pdu, err);
-}
-
-static void v9fs_unlinkat(void *opaque)
-{
- int err = 0;
- V9fsString name;
- int32_t dfid, flags;
- size_t offset = 7;
- V9fsPath path;
- V9fsFidState *dfidp;
- V9fsPDU *pdu = opaque;
-
- v9fs_string_init(&name);
- err = pdu_unmarshal(pdu, offset, "dsd", &dfid, &name, &flags);
- if (err < 0) {
- goto out_nofid;
- }
- dfidp = get_fid(pdu, dfid);
- if (dfidp == NULL) {
- err = -EINVAL;
- goto out_nofid;
- }
- /*
- * IF the file is unlinked, we cannot reopen
- * the file later. So don't reclaim fd
- */
- v9fs_path_init(&path);
- err = v9fs_co_name_to_path(pdu, &dfidp->path, name.data, &path);
- if (err < 0) {
- goto out_err;
- }
- err = v9fs_mark_fids_unreclaim(pdu, &path);
- if (err < 0) {
- goto out_err;
- }
- err = v9fs_co_unlinkat(pdu, &dfidp->path, &name, flags);
- if (!err) {
- err = offset;
- }
-out_err:
- put_fid(pdu, dfidp);
- v9fs_path_free(&path);
-out_nofid:
- pdu_complete(pdu, err);
- v9fs_string_free(&name);
-}
-
-
-/* Only works with path name based fid */
-static int v9fs_complete_rename(V9fsPDU *pdu, V9fsFidState *fidp,
- int32_t newdirfid, V9fsString *name)
-{
- char *end;
- int err = 0;
- V9fsPath new_path;
- V9fsFidState *tfidp;
- V9fsState *s = pdu->s;
- V9fsFidState *dirfidp = NULL;
- char *old_name, *new_name;
-
- v9fs_path_init(&new_path);
- if (newdirfid != -1) {
- dirfidp = get_fid(pdu, newdirfid);
- if (dirfidp == NULL) {
- err = -ENOENT;
- goto out_nofid;
- }
- BUG_ON(dirfidp->fid_type != P9_FID_NONE);
- v9fs_co_name_to_path(pdu, &dirfidp->path, name->data, &new_path);
- } else {
- old_name = fidp->path.data;
- end = strrchr(old_name, '/');
- if (end) {
- end++;
- } else {
- end = old_name;
- }
- new_name = g_malloc0(end - old_name + name->size + 1);
- strncat(new_name, old_name, end - old_name);
- strncat(new_name + (end - old_name), name->data, name->size);
- v9fs_co_name_to_path(pdu, NULL, new_name, &new_path);
- g_free(new_name);
- }
- err = v9fs_co_rename(pdu, &fidp->path, &new_path);
- if (err < 0) {
- goto out;
- }
- /*
- * Fixup fid's pointing to the old name to
- * start pointing to the new name
- */
- for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
- if (v9fs_path_is_ancestor(&fidp->path, &tfidp->path)) {
- /* replace the name */
- v9fs_fix_path(&tfidp->path, &new_path, strlen(fidp->path.data));
- }
- }
-out:
- if (dirfidp) {
- put_fid(pdu, dirfidp);
- }
- v9fs_path_free(&new_path);
-out_nofid:
- return err;
-}
-
-/* Only works with path name based fid */
-static void v9fs_rename(void *opaque)
-{
- int32_t fid;
- ssize_t err = 0;
- size_t offset = 7;
- V9fsString name;
- int32_t newdirfid;
- V9fsFidState *fidp;
- V9fsPDU *pdu = opaque;
- V9fsState *s = pdu->s;
-
- v9fs_string_init(&name);
- err = pdu_unmarshal(pdu, offset, "dds", &fid, &newdirfid, &name);
- if (err < 0) {
- goto out_nofid;
- }
- fidp = get_fid(pdu, fid);
- if (fidp == NULL) {
- err = -ENOENT;
- goto out_nofid;
- }
- BUG_ON(fidp->fid_type != P9_FID_NONE);
- /* if fs driver is not path based, return EOPNOTSUPP */
- if (!(pdu->s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT)) {
- err = -EOPNOTSUPP;
- goto out;
- }
- v9fs_path_write_lock(s);
- err = v9fs_complete_rename(pdu, fidp, newdirfid, &name);
- v9fs_path_unlock(s);
- if (!err) {
- err = offset;
- }
-out:
- put_fid(pdu, fidp);
-out_nofid:
- pdu_complete(pdu, err);
- v9fs_string_free(&name);
-}
-
-static void v9fs_fix_fid_paths(V9fsPDU *pdu, V9fsPath *olddir,
- V9fsString *old_name, V9fsPath *newdir,
- V9fsString *new_name)
-{
- V9fsFidState *tfidp;
- V9fsPath oldpath, newpath;
- V9fsState *s = pdu->s;
-
-
- v9fs_path_init(&oldpath);
- v9fs_path_init(&newpath);
- v9fs_co_name_to_path(pdu, olddir, old_name->data, &oldpath);
- v9fs_co_name_to_path(pdu, newdir, new_name->data, &newpath);
-
- /*
- * Fixup fid's pointing to the old name to
- * start pointing to the new name
- */
- for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
- if (v9fs_path_is_ancestor(&oldpath, &tfidp->path)) {
- /* replace the name */
- v9fs_fix_path(&tfidp->path, &newpath, strlen(oldpath.data));
- }
- }
- v9fs_path_free(&oldpath);
- v9fs_path_free(&newpath);
-}
-
-static int v9fs_complete_renameat(V9fsPDU *pdu, int32_t olddirfid,
- V9fsString *old_name, int32_t newdirfid,
- V9fsString *new_name)
-{
- int err = 0;
- V9fsState *s = pdu->s;
- V9fsFidState *newdirfidp = NULL, *olddirfidp = NULL;
-
- olddirfidp = get_fid(pdu, olddirfid);
- if (olddirfidp == NULL) {
- err = -ENOENT;
- goto out;
- }
- if (newdirfid != -1) {
- newdirfidp = get_fid(pdu, newdirfid);
- if (newdirfidp == NULL) {
- err = -ENOENT;
- goto out;
- }
- } else {
- newdirfidp = get_fid(pdu, olddirfid);
- }
-
- err = v9fs_co_renameat(pdu, &olddirfidp->path, old_name,
- &newdirfidp->path, new_name);
- if (err < 0) {
- goto out;
- }
- if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) {
- /* Only for path based fid we need to do the below fixup */
- v9fs_fix_fid_paths(pdu, &olddirfidp->path, old_name,
- &newdirfidp->path, new_name);
- }
-out:
- if (olddirfidp) {
- put_fid(pdu, olddirfidp);
- }
- if (newdirfidp) {
- put_fid(pdu, newdirfidp);
- }
- return err;
-}
-
-static void v9fs_renameat(void *opaque)
-{
- ssize_t err = 0;
- size_t offset = 7;
- V9fsPDU *pdu = opaque;
- V9fsState *s = pdu->s;
- int32_t olddirfid, newdirfid;
- V9fsString old_name, new_name;
-
- v9fs_string_init(&old_name);
- v9fs_string_init(&new_name);
- err = pdu_unmarshal(pdu, offset, "dsds", &olddirfid,
- &old_name, &newdirfid, &new_name);
- if (err < 0) {
- goto out_err;
- }
-
- v9fs_path_write_lock(s);
- err = v9fs_complete_renameat(pdu, olddirfid,
- &old_name, newdirfid, &new_name);
- v9fs_path_unlock(s);
- if (!err) {
- err = offset;
- }
-
-out_err:
- pdu_complete(pdu, err);
- v9fs_string_free(&old_name);
- v9fs_string_free(&new_name);
-}
-
-static void v9fs_wstat(void *opaque)
-{
- int32_t fid;
- int err = 0;
- int16_t unused;
- V9fsStat v9stat;
- size_t offset = 7;
- struct stat stbuf;
- V9fsFidState *fidp;
- V9fsPDU *pdu = opaque;
-
- v9fs_stat_init(&v9stat);
- err = pdu_unmarshal(pdu, offset, "dwS", &fid, &unused, &v9stat);
- if (err < 0) {
- goto out_nofid;
- }
- trace_v9fs_wstat(pdu->tag, pdu->id, fid,
- v9stat.mode, v9stat.atime, v9stat.mtime);
-
- fidp = get_fid(pdu, fid);
- if (fidp == NULL) {
- err = -EINVAL;
- goto out_nofid;
- }
- /* do we need to sync the file? */
- if (donttouch_stat(&v9stat)) {
- err = v9fs_co_fsync(pdu, fidp, 0);
- goto out;
- }
- if (v9stat.mode != -1) {
- uint32_t v9_mode;
- err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
- if (err < 0) {
- goto out;
- }
- v9_mode = stat_to_v9mode(&stbuf);
- if ((v9stat.mode & P9_STAT_MODE_TYPE_BITS) !=
- (v9_mode & P9_STAT_MODE_TYPE_BITS)) {
- /* Attempting to change the type */
- err = -EIO;
- goto out;
- }
- err = v9fs_co_chmod(pdu, &fidp->path,
- v9mode_to_mode(v9stat.mode,
- &v9stat.extension));
- if (err < 0) {
- goto out;
- }
- }
- if (v9stat.mtime != -1 || v9stat.atime != -1) {
- struct timespec times[2];
- if (v9stat.atime != -1) {
- times[0].tv_sec = v9stat.atime;
- times[0].tv_nsec = 0;
- } else {
- times[0].tv_nsec = UTIME_OMIT;
- }
- if (v9stat.mtime != -1) {
- times[1].tv_sec = v9stat.mtime;
- times[1].tv_nsec = 0;
- } else {
- times[1].tv_nsec = UTIME_OMIT;
- }
- err = v9fs_co_utimensat(pdu, &fidp->path, times);
- if (err < 0) {
- goto out;
- }
- }
- if (v9stat.n_gid != -1 || v9stat.n_uid != -1) {
- err = v9fs_co_chown(pdu, &fidp->path, v9stat.n_uid, v9stat.n_gid);
- if (err < 0) {
- goto out;
- }
- }
- if (v9stat.name.size != 0) {
- err = v9fs_complete_rename(pdu, fidp, -1, &v9stat.name);
- if (err < 0) {
- goto out;
- }
- }
- if (v9stat.length != -1) {
- err = v9fs_co_truncate(pdu, &fidp->path, v9stat.length);
- if (err < 0) {
- goto out;
- }
- }
- err = offset;
-out:
- put_fid(pdu, fidp);
-out_nofid:
- v9fs_stat_free(&v9stat);
- pdu_complete(pdu, err);
-}
-
-static int v9fs_fill_statfs(V9fsState *s, V9fsPDU *pdu, struct statfs *stbuf)
-{
- uint32_t f_type;
- uint32_t f_bsize;
- uint64_t f_blocks;
- uint64_t f_bfree;
- uint64_t f_bavail;
- uint64_t f_files;
- uint64_t f_ffree;
- uint64_t fsid_val;
- uint32_t f_namelen;
- size_t offset = 7;
- int32_t bsize_factor;
-
- /*
- * compute bsize factor based on host file system block size
- * and client msize
- */
- bsize_factor = (s->msize - P9_IOHDRSZ)/stbuf->f_bsize;
- if (!bsize_factor) {
- bsize_factor = 1;
- }
- f_type = stbuf->f_type;
- f_bsize = stbuf->f_bsize;
- f_bsize *= bsize_factor;
- /*
- * f_bsize is adjusted(multiplied) by bsize factor, so we need to
- * adjust(divide) the number of blocks, free blocks and available
- * blocks by bsize factor
- */
- f_blocks = stbuf->f_blocks/bsize_factor;
- f_bfree = stbuf->f_bfree/bsize_factor;
- f_bavail = stbuf->f_bavail/bsize_factor;
- f_files = stbuf->f_files;
- f_ffree = stbuf->f_ffree;
- fsid_val = (unsigned int) stbuf->f_fsid.__val[0] |
- (unsigned long long)stbuf->f_fsid.__val[1] << 32;
- f_namelen = stbuf->f_namelen;
-
- return pdu_marshal(pdu, offset, "ddqqqqqqd",
- f_type, f_bsize, f_blocks, f_bfree,
- f_bavail, f_files, f_ffree,
- fsid_val, f_namelen);
-}
-
-static void v9fs_statfs(void *opaque)
-{
- int32_t fid;
- ssize_t retval = 0;
- size_t offset = 7;
- V9fsFidState *fidp;
- struct statfs stbuf;
- V9fsPDU *pdu = opaque;
- V9fsState *s = pdu->s;
-
- retval = pdu_unmarshal(pdu, offset, "d", &fid);
- if (retval < 0) {
- goto out_nofid;
- }
- fidp = get_fid(pdu, fid);
- if (fidp == NULL) {
- retval = -ENOENT;
- goto out_nofid;
- }
- retval = v9fs_co_statfs(pdu, &fidp->path, &stbuf);
- if (retval < 0) {
- goto out;
- }
- retval = v9fs_fill_statfs(s, pdu, &stbuf);
- if (retval < 0) {
- goto out;
- }
- retval += offset;
-out:
- put_fid(pdu, fidp);
-out_nofid:
- pdu_complete(pdu, retval);
-}
-
-static void v9fs_mknod(void *opaque)
-{
-
- int mode;
- gid_t gid;
- int32_t fid;
- V9fsQID qid;
- int err = 0;
- int major, minor;
- size_t offset = 7;
- V9fsString name;
- struct stat stbuf;
- V9fsFidState *fidp;
- V9fsPDU *pdu = opaque;
-
- v9fs_string_init(&name);
- err = pdu_unmarshal(pdu, offset, "dsdddd", &fid, &name, &mode,
- &major, &minor, &gid);
- if (err < 0) {
- goto out_nofid;
- }
- trace_v9fs_mknod(pdu->tag, pdu->id, fid, mode, major, minor);
-
- fidp = get_fid(pdu, fid);
- if (fidp == NULL) {
- err = -ENOENT;
- goto out_nofid;
- }
- err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, gid,
- makedev(major, minor), mode, &stbuf);
- if (err < 0) {
- goto out;
- }
- stat_to_qid(&stbuf, &qid);
- err = pdu_marshal(pdu, offset, "Q", &qid);
- if (err < 0) {
- goto out;
- }
- err += offset;
- trace_v9fs_mknod_return(pdu->tag, pdu->id,
- qid.type, qid.version, qid.path);
-out:
- put_fid(pdu, fidp);
-out_nofid:
- pdu_complete(pdu, err);
- v9fs_string_free(&name);
-}
-
-/*
- * Implement posix byte range locking code
- * Server side handling of locking code is very simple, because 9p server in
- * QEMU can handle only one client. And most of the lock handling
- * (like conflict, merging) etc is done by the VFS layer itself, so no need to
- * do any thing in * qemu 9p server side lock code path.
- * So when a TLOCK request comes, always return success
- */
-static void v9fs_lock(void *opaque)
-{
- int8_t status;
- V9fsFlock flock;
- size_t offset = 7;
- struct stat stbuf;
- V9fsFidState *fidp;
- int32_t fid, err = 0;
- V9fsPDU *pdu = opaque;
-
- status = P9_LOCK_ERROR;
- v9fs_string_init(&flock.client_id);
- err = pdu_unmarshal(pdu, offset, "dbdqqds", &fid, &flock.type,
- &flock.flags, &flock.start, &flock.length,
- &flock.proc_id, &flock.client_id);
- if (err < 0) {
- goto out_nofid;
- }
- trace_v9fs_lock(pdu->tag, pdu->id, fid,
- flock.type, flock.start, flock.length);
-
-
- /* We support only block flag now (that too ignored currently) */
- if (flock.flags & ~P9_LOCK_FLAGS_BLOCK) {
- err = -EINVAL;
- goto out_nofid;
- }
- fidp = get_fid(pdu, fid);
- if (fidp == NULL) {
- err = -ENOENT;
- goto out_nofid;
- }
- err = v9fs_co_fstat(pdu, fidp, &stbuf);
- if (err < 0) {
- goto out;
- }
- status = P9_LOCK_SUCCESS;
-out:
- put_fid(pdu, fidp);
-out_nofid:
- err = pdu_marshal(pdu, offset, "b", status);
- if (err > 0) {
- err += offset;
- }
- trace_v9fs_lock_return(pdu->tag, pdu->id, status);
- pdu_complete(pdu, err);
- v9fs_string_free(&flock.client_id);
-}
-
-/*
- * When a TGETLOCK request comes, always return success because all lock
- * handling is done by client's VFS layer.
- */
-static void v9fs_getlock(void *opaque)
-{
- size_t offset = 7;
- struct stat stbuf;
- V9fsFidState *fidp;
- V9fsGetlock glock;
- int32_t fid, err = 0;
- V9fsPDU *pdu = opaque;
-
- v9fs_string_init(&glock.client_id);
- err = pdu_unmarshal(pdu, offset, "dbqqds", &fid, &glock.type,
- &glock.start, &glock.length, &glock.proc_id,
- &glock.client_id);
- if (err < 0) {
- goto out_nofid;
- }
- trace_v9fs_getlock(pdu->tag, pdu->id, fid,
- glock.type, glock.start, glock.length);
-
- fidp = get_fid(pdu, fid);
- if (fidp == NULL) {
- err = -ENOENT;
- goto out_nofid;
- }
- err = v9fs_co_fstat(pdu, fidp, &stbuf);
- if (err < 0) {
- goto out;
- }
- glock.type = P9_LOCK_TYPE_UNLCK;
- err = pdu_marshal(pdu, offset, "bqqds", glock.type,
- glock.start, glock.length, glock.proc_id,
- &glock.client_id);
- if (err < 0) {
- goto out;
- }
- err += offset;
- trace_v9fs_getlock_return(pdu->tag, pdu->id, glock.type, glock.start,
- glock.length, glock.proc_id);
-out:
- put_fid(pdu, fidp);
-out_nofid:
- pdu_complete(pdu, err);
- v9fs_string_free(&glock.client_id);
-}
-
-static void v9fs_mkdir(void *opaque)
-{
- V9fsPDU *pdu = opaque;
- size_t offset = 7;
- int32_t fid;
- struct stat stbuf;
- V9fsQID qid;
- V9fsString name;
- V9fsFidState *fidp;
- gid_t gid;
- int mode;
- int err = 0;
-
- v9fs_string_init(&name);
- err = pdu_unmarshal(pdu, offset, "dsdd", &fid, &name, &mode, &gid);
- if (err < 0) {
- goto out_nofid;
- }
- trace_v9fs_mkdir(pdu->tag, pdu->id, fid, name.data, mode, gid);
-
- fidp = get_fid(pdu, fid);
- if (fidp == NULL) {
- err = -ENOENT;
- goto out_nofid;
- }
- err = v9fs_co_mkdir(pdu, fidp, &name, mode, fidp->uid, gid, &stbuf);
- if (err < 0) {
- goto out;
- }
- stat_to_qid(&stbuf, &qid);
- err = pdu_marshal(pdu, offset, "Q", &qid);
- if (err < 0) {
- goto out;
- }
- err += offset;
- trace_v9fs_mkdir_return(pdu->tag, pdu->id,
- qid.type, qid.version, qid.path, err);
-out:
- put_fid(pdu, fidp);
-out_nofid:
- pdu_complete(pdu, err);
- v9fs_string_free(&name);
-}
-
-static void v9fs_xattrwalk(void *opaque)
-{
- int64_t size;
- V9fsString name;
- ssize_t err = 0;
- size_t offset = 7;
- int32_t fid, newfid;
- V9fsFidState *file_fidp;
- V9fsFidState *xattr_fidp = NULL;
- V9fsPDU *pdu = opaque;
- V9fsState *s = pdu->s;
-
- v9fs_string_init(&name);
- err = pdu_unmarshal(pdu, offset, "dds", &fid, &newfid, &name);
- if (err < 0) {
- goto out_nofid;
- }
- trace_v9fs_xattrwalk(pdu->tag, pdu->id, fid, newfid, name.data);
-
- file_fidp = get_fid(pdu, fid);
- if (file_fidp == NULL) {
- err = -ENOENT;
- goto out_nofid;
- }
- xattr_fidp = alloc_fid(s, newfid);
- if (xattr_fidp == NULL) {
- err = -EINVAL;
- goto out;
- }
- v9fs_path_copy(&xattr_fidp->path, &file_fidp->path);
- if (name.data == NULL) {
- /*
- * listxattr request. Get the size first
- */
- size = v9fs_co_llistxattr(pdu, &xattr_fidp->path, NULL, 0);
- if (size < 0) {
- err = size;
- clunk_fid(s, xattr_fidp->fid);
- goto out;
- }
- /*
- * Read the xattr value
- */
- xattr_fidp->fs.xattr.len = size;
- xattr_fidp->fid_type = P9_FID_XATTR;
- xattr_fidp->fs.xattr.copied_len = -1;
- if (size) {
- xattr_fidp->fs.xattr.value = g_malloc(size);
- err = v9fs_co_llistxattr(pdu, &xattr_fidp->path,
- xattr_fidp->fs.xattr.value,
- xattr_fidp->fs.xattr.len);
- if (err < 0) {
- clunk_fid(s, xattr_fidp->fid);
- goto out;
- }
- }
- err = pdu_marshal(pdu, offset, "q", size);
- if (err < 0) {
- goto out;
- }
- err += offset;
- } else {
- /*
- * specific xattr fid. We check for xattr
- * presence also collect the xattr size
- */
- size = v9fs_co_lgetxattr(pdu, &xattr_fidp->path,
- &name, NULL, 0);
- if (size < 0) {
- err = size;
- clunk_fid(s, xattr_fidp->fid);
- goto out;
- }
- /*
- * Read the xattr value
- */
- xattr_fidp->fs.xattr.len = size;
- xattr_fidp->fid_type = P9_FID_XATTR;
- xattr_fidp->fs.xattr.copied_len = -1;
- if (size) {
- xattr_fidp->fs.xattr.value = g_malloc(size);
- err = v9fs_co_lgetxattr(pdu, &xattr_fidp->path,
- &name, xattr_fidp->fs.xattr.value,
- xattr_fidp->fs.xattr.len);
- if (err < 0) {
- clunk_fid(s, xattr_fidp->fid);
- goto out;
- }
- }
- err = pdu_marshal(pdu, offset, "q", size);
- if (err < 0) {
- goto out;
- }
- err += offset;
- }
- trace_v9fs_xattrwalk_return(pdu->tag, pdu->id, size);
-out:
- put_fid(pdu, file_fidp);
- if (xattr_fidp) {
- put_fid(pdu, xattr_fidp);
- }
-out_nofid:
- pdu_complete(pdu, err);
- v9fs_string_free(&name);
-}
-
-static void v9fs_xattrcreate(void *opaque)
-{
- int flags;
- int32_t fid;
- int64_t size;
- ssize_t err = 0;
- V9fsString name;
- size_t offset = 7;
- V9fsFidState *file_fidp;
- V9fsFidState *xattr_fidp;
- V9fsPDU *pdu = opaque;
-
- v9fs_string_init(&name);
- err = pdu_unmarshal(pdu, offset, "dsqd", &fid, &name, &size, &flags);
- if (err < 0) {
- goto out_nofid;
- }
- trace_v9fs_xattrcreate(pdu->tag, pdu->id, fid, name.data, size, flags);
-
- file_fidp = get_fid(pdu, fid);
- if (file_fidp == NULL) {
- err = -EINVAL;
- goto out_nofid;
- }
- /* Make the file fid point to xattr */
- xattr_fidp = file_fidp;
- xattr_fidp->fid_type = P9_FID_XATTR;
- xattr_fidp->fs.xattr.copied_len = 0;
- xattr_fidp->fs.xattr.len = size;
- xattr_fidp->fs.xattr.flags = flags;
- v9fs_string_init(&xattr_fidp->fs.xattr.name);
- v9fs_string_copy(&xattr_fidp->fs.xattr.name, &name);
- xattr_fidp->fs.xattr.value = g_malloc(size);
- err = offset;
- put_fid(pdu, file_fidp);
-out_nofid:
- pdu_complete(pdu, err);
- v9fs_string_free(&name);
-}
-
-static void v9fs_readlink(void *opaque)
-{
- V9fsPDU *pdu = opaque;
- size_t offset = 7;
- V9fsString target;
- int32_t fid;
- int err = 0;
- V9fsFidState *fidp;
-
- err = pdu_unmarshal(pdu, offset, "d", &fid);
- if (err < 0) {
- goto out_nofid;
- }
- trace_v9fs_readlink(pdu->tag, pdu->id, fid);
- fidp = get_fid(pdu, fid);
- if (fidp == NULL) {
- err = -ENOENT;
- goto out_nofid;
- }
-
- v9fs_string_init(&target);
- err = v9fs_co_readlink(pdu, &fidp->path, &target);
- if (err < 0) {
- goto out;
- }
- err = pdu_marshal(pdu, offset, "s", &target);
- if (err < 0) {
- v9fs_string_free(&target);
- goto out;
- }
- err += offset;
- trace_v9fs_readlink_return(pdu->tag, pdu->id, target.data);
- v9fs_string_free(&target);
-out:
- put_fid(pdu, fidp);
-out_nofid:
- pdu_complete(pdu, err);
-}
-
-static CoroutineEntry *pdu_co_handlers[] = {
- [P9_TREADDIR] = v9fs_readdir,
- [P9_TSTATFS] = v9fs_statfs,
- [P9_TGETATTR] = v9fs_getattr,
- [P9_TSETATTR] = v9fs_setattr,
- [P9_TXATTRWALK] = v9fs_xattrwalk,
- [P9_TXATTRCREATE] = v9fs_xattrcreate,
- [P9_TMKNOD] = v9fs_mknod,
- [P9_TRENAME] = v9fs_rename,
- [P9_TLOCK] = v9fs_lock,
- [P9_TGETLOCK] = v9fs_getlock,
- [P9_TRENAMEAT] = v9fs_renameat,
- [P9_TREADLINK] = v9fs_readlink,
- [P9_TUNLINKAT] = v9fs_unlinkat,
- [P9_TMKDIR] = v9fs_mkdir,
- [P9_TVERSION] = v9fs_version,
- [P9_TLOPEN] = v9fs_open,
- [P9_TATTACH] = v9fs_attach,
- [P9_TSTAT] = v9fs_stat,
- [P9_TWALK] = v9fs_walk,
- [P9_TCLUNK] = v9fs_clunk,
- [P9_TFSYNC] = v9fs_fsync,
- [P9_TOPEN] = v9fs_open,
- [P9_TREAD] = v9fs_read,
-#if 0
- [P9_TAUTH] = v9fs_auth,
-#endif
- [P9_TFLUSH] = v9fs_flush,
- [P9_TLINK] = v9fs_link,
- [P9_TSYMLINK] = v9fs_symlink,
- [P9_TCREATE] = v9fs_create,
- [P9_TLCREATE] = v9fs_lcreate,
- [P9_TWRITE] = v9fs_write,
- [P9_TWSTAT] = v9fs_wstat,
- [P9_TREMOVE] = v9fs_remove,
-};
-
-static void v9fs_op_not_supp(void *opaque)
-{
- V9fsPDU *pdu = opaque;
- pdu_complete(pdu, -EOPNOTSUPP);
-}
-
-static void v9fs_fs_ro(void *opaque)
-{
- V9fsPDU *pdu = opaque;
- pdu_complete(pdu, -EROFS);
-}
-
-static inline bool is_read_only_op(V9fsPDU *pdu)
-{
- switch (pdu->id) {
- case P9_TREADDIR:
- case P9_TSTATFS:
- case P9_TGETATTR:
- case P9_TXATTRWALK:
- case P9_TLOCK:
- case P9_TGETLOCK:
- case P9_TREADLINK:
- case P9_TVERSION:
- case P9_TLOPEN:
- case P9_TATTACH:
- case P9_TSTAT:
- case P9_TWALK:
- case P9_TCLUNK:
- case P9_TFSYNC:
- case P9_TOPEN:
- case P9_TREAD:
- case P9_TAUTH:
- case P9_TFLUSH:
- return 1;
- default:
- return 0;
- }
-}
-
-void pdu_submit(V9fsPDU *pdu)
-{
- Coroutine *co;
- CoroutineEntry *handler;
- V9fsState *s = pdu->s;
-
- if (pdu->id >= ARRAY_SIZE(pdu_co_handlers) ||
- (pdu_co_handlers[pdu->id] == NULL)) {
- handler = v9fs_op_not_supp;
- } else {
- handler = pdu_co_handlers[pdu->id];
- }
-
- if (is_ro_export(&s->ctx) && !is_read_only_op(pdu)) {
- handler = v9fs_fs_ro;
- }
- co = qemu_coroutine_create(handler);
- qemu_coroutine_enter(co, pdu);
-}
-
-/* Returns 0 on success, 1 on failure. */
-int v9fs_device_realize_common(V9fsState *s, Error **errp)
-{
- V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
- int i, len;
- struct stat stat;
- FsDriverEntry *fse;
- V9fsPath path;
- int rc = 1;
-
- /* initialize pdu allocator */
- QLIST_INIT(&s->free_list);
- QLIST_INIT(&s->active_list);
- for (i = 0; i < (MAX_REQ - 1); i++) {
- QLIST_INSERT_HEAD(&s->free_list, &v->pdus[i], next);
- v->pdus[i].s = s;
- v->pdus[i].idx = i;
- }
-
- v9fs_path_init(&path);
-
- fse = get_fsdev_fsentry(s->fsconf.fsdev_id);
-
- if (!fse) {
- /* We don't have a fsdev identified by fsdev_id */
- error_setg(errp, "9pfs device couldn't find fsdev with the "
- "id = %s",
- s->fsconf.fsdev_id ? s->fsconf.fsdev_id : "NULL");
- goto out;
- }
-
- if (!s->fsconf.tag) {
- /* we haven't specified a mount_tag */
- error_setg(errp, "fsdev with id %s needs mount_tag arguments",
- s->fsconf.fsdev_id);
- goto out;
- }
-
- s->ctx.export_flags = fse->export_flags;
- s->ctx.fs_root = g_strdup(fse->path);
- s->ctx.exops.get_st_gen = NULL;
- len = strlen(s->fsconf.tag);
- if (len > MAX_TAG_LEN - 1) {
- error_setg(errp, "mount tag '%s' (%d bytes) is longer than "
- "maximum (%d bytes)", s->fsconf.tag, len, MAX_TAG_LEN - 1);
- goto out;
- }
-
- s->tag = g_strdup(s->fsconf.tag);
- s->ctx.uid = -1;
-
- s->ops = fse->ops;
-
- s->fid_list = NULL;
- qemu_co_rwlock_init(&s->rename_lock);
-
- if (s->ops->init(&s->ctx) < 0) {
- error_setg(errp, "9pfs Failed to initialize fs-driver with id:%s"
- " and export path:%s", s->fsconf.fsdev_id, s->ctx.fs_root);
- goto out;
- }
-
- /*
- * Check details of export path, We need to use fs driver
- * call back to do that. Since we are in the init path, we don't
- * use co-routines here.
- */
- if (s->ops->name_to_path(&s->ctx, NULL, "/", &path) < 0) {
- error_setg(errp,
- "error in converting name to path %s", strerror(errno));
- goto out;
- }
- if (s->ops->lstat(&s->ctx, &path, &stat)) {
- error_setg(errp, "share path %s does not exist", fse->path);
- goto out;
- } else if (!S_ISDIR(stat.st_mode)) {
- error_setg(errp, "share path %s is not a directory", fse->path);
- goto out;
- }
- v9fs_path_free(&path);
-
- rc = 0;
-out:
- if (rc) {
- g_free(s->ctx.fs_root);
- g_free(s->tag);
- v9fs_path_free(&path);
- }
- return rc;
-}
-
-void v9fs_device_unrealize_common(V9fsState *s, Error **errp)
-{
- g_free(s->ctx.fs_root);
- g_free(s->tag);
-}
-
-static void __attribute__((__constructor__)) v9fs_set_fd_limit(void)
-{
- struct rlimit rlim;
- if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
- error_report("Failed to get the resource limit");
- exit(1);
- }
- open_fd_hw = rlim.rlim_cur - MIN(400, rlim.rlim_cur/3);
- open_fd_rc = rlim.rlim_cur/2;
-}
diff --git a/qemu/hw/9pfs/9p.h b/qemu/hw/9pfs/9p.h
deleted file mode 100644
index 1a19418a8..000000000
--- a/qemu/hw/9pfs/9p.h
+++ /dev/null
@@ -1,324 +0,0 @@
-#ifndef _QEMU_9P_H
-#define _QEMU_9P_H
-
-#include <dirent.h>
-#include <utime.h>
-#include <sys/resource.h>
-#include <glib.h>
-#include "standard-headers/linux/virtio_9p.h"
-#include "hw/virtio/virtio.h"
-#include "fsdev/file-op-9p.h"
-#include "fsdev/9p-iov-marshal.h"
-#include "qemu/thread.h"
-#include "qemu/coroutine.h"
-
-enum {
- P9_TLERROR = 6,
- P9_RLERROR,
- P9_TSTATFS = 8,
- P9_RSTATFS,
- P9_TLOPEN = 12,
- P9_RLOPEN,
- P9_TLCREATE = 14,
- P9_RLCREATE,
- P9_TSYMLINK = 16,
- P9_RSYMLINK,
- P9_TMKNOD = 18,
- P9_RMKNOD,
- P9_TRENAME = 20,
- P9_RRENAME,
- P9_TREADLINK = 22,
- P9_RREADLINK,
- P9_TGETATTR = 24,
- P9_RGETATTR,
- P9_TSETATTR = 26,
- P9_RSETATTR,
- P9_TXATTRWALK = 30,
- P9_RXATTRWALK,
- P9_TXATTRCREATE = 32,
- P9_RXATTRCREATE,
- P9_TREADDIR = 40,
- P9_RREADDIR,
- P9_TFSYNC = 50,
- P9_RFSYNC,
- P9_TLOCK = 52,
- P9_RLOCK,
- P9_TGETLOCK = 54,
- P9_RGETLOCK,
- P9_TLINK = 70,
- P9_RLINK,
- P9_TMKDIR = 72,
- P9_RMKDIR,
- P9_TRENAMEAT = 74,
- P9_RRENAMEAT,
- P9_TUNLINKAT = 76,
- P9_RUNLINKAT,
- P9_TVERSION = 100,
- P9_RVERSION,
- P9_TAUTH = 102,
- P9_RAUTH,
- P9_TATTACH = 104,
- P9_RATTACH,
- P9_TERROR = 106,
- P9_RERROR,
- P9_TFLUSH = 108,
- P9_RFLUSH,
- P9_TWALK = 110,
- P9_RWALK,
- P9_TOPEN = 112,
- P9_ROPEN,
- P9_TCREATE = 114,
- P9_RCREATE,
- P9_TREAD = 116,
- P9_RREAD,
- P9_TWRITE = 118,
- P9_RWRITE,
- P9_TCLUNK = 120,
- P9_RCLUNK,
- P9_TREMOVE = 122,
- P9_RREMOVE,
- P9_TSTAT = 124,
- P9_RSTAT,
- P9_TWSTAT = 126,
- P9_RWSTAT,
-};
-
-
-/* qid.types */
-enum {
- P9_QTDIR = 0x80,
- P9_QTAPPEND = 0x40,
- P9_QTEXCL = 0x20,
- P9_QTMOUNT = 0x10,
- P9_QTAUTH = 0x08,
- P9_QTTMP = 0x04,
- P9_QTSYMLINK = 0x02,
- P9_QTLINK = 0x01,
- P9_QTFILE = 0x00,
-};
-
-enum p9_proto_version {
- V9FS_PROTO_2000U = 0x01,
- V9FS_PROTO_2000L = 0x02,
-};
-
-#define P9_NOTAG (u16)(~0)
-#define P9_NOFID (u32)(~0)
-#define P9_MAXWELEM 16
-
-#define FID_REFERENCED 0x1
-#define FID_NON_RECLAIMABLE 0x2
-static inline char *rpath(FsContext *ctx, const char *path)
-{
- return g_strdup_printf("%s/%s", ctx->fs_root, path);
-}
-
-/*
- * ample room for Twrite/Rread header
- * size[4] Tread/Twrite tag[2] fid[4] offset[8] count[4]
- */
-#define P9_IOHDRSZ 24
-
-typedef struct V9fsPDU V9fsPDU;
-struct V9fsState;
-
-struct V9fsPDU
-{
- uint32_t size;
- uint16_t tag;
- uint8_t id;
- uint8_t cancelled;
- CoQueue complete;
- struct V9fsState *s;
- QLIST_ENTRY(V9fsPDU) next;
- uint32_t idx;
-};
-
-
-/* FIXME
- * 1) change user needs to set groups and stuff
- */
-
-#define MAX_REQ 128
-#define MAX_TAG_LEN 32
-
-#define BUG_ON(cond) assert(!(cond))
-
-typedef struct V9fsFidState V9fsFidState;
-
-enum {
- P9_FID_NONE = 0,
- P9_FID_FILE,
- P9_FID_DIR,
- P9_FID_XATTR,
-};
-
-typedef struct V9fsConf
-{
- /* tag name for the device */
- char *tag;
- char *fsdev_id;
-} V9fsConf;
-
-typedef struct V9fsXattr
-{
- int64_t copied_len;
- int64_t len;
- void *value;
- V9fsString name;
- int flags;
-} V9fsXattr;
-
-/*
- * Filled by fs driver on open and other
- * calls.
- */
-union V9fsFidOpenState {
- int fd;
- DIR *dir;
- V9fsXattr xattr;
- /*
- * private pointer for fs drivers, that
- * have its own internal representation of
- * open files.
- */
- void *private;
-};
-
-struct V9fsFidState
-{
- int fid_type;
- int32_t fid;
- V9fsPath path;
- V9fsFidOpenState fs;
- V9fsFidOpenState fs_reclaim;
- int flags;
- int open_flags;
- uid_t uid;
- int ref;
- int clunked;
- V9fsFidState *next;
- V9fsFidState *rclm_lst;
-};
-
-typedef struct V9fsState
-{
- QLIST_HEAD(, V9fsPDU) free_list;
- QLIST_HEAD(, V9fsPDU) active_list;
- V9fsFidState *fid_list;
- FileOperations *ops;
- FsContext ctx;
- char *tag;
- enum p9_proto_version proto_version;
- int32_t msize;
- /*
- * lock ensuring atomic path update
- * on rename.
- */
- CoRwlock rename_lock;
- int32_t root_fid;
- Error *migration_blocker;
- V9fsConf fsconf;
-} V9fsState;
-
-/* 9p2000.L open flags */
-#define P9_DOTL_RDONLY 00000000
-#define P9_DOTL_WRONLY 00000001
-#define P9_DOTL_RDWR 00000002
-#define P9_DOTL_NOACCESS 00000003
-#define P9_DOTL_CREATE 00000100
-#define P9_DOTL_EXCL 00000200
-#define P9_DOTL_NOCTTY 00000400
-#define P9_DOTL_TRUNC 00001000
-#define P9_DOTL_APPEND 00002000
-#define P9_DOTL_NONBLOCK 00004000
-#define P9_DOTL_DSYNC 00010000
-#define P9_DOTL_FASYNC 00020000
-#define P9_DOTL_DIRECT 00040000
-#define P9_DOTL_LARGEFILE 00100000
-#define P9_DOTL_DIRECTORY 00200000
-#define P9_DOTL_NOFOLLOW 00400000
-#define P9_DOTL_NOATIME 01000000
-#define P9_DOTL_CLOEXEC 02000000
-#define P9_DOTL_SYNC 04000000
-
-/* 9p2000.L at flags */
-#define P9_DOTL_AT_REMOVEDIR 0x200
-
-/* 9P2000.L lock type */
-#define P9_LOCK_TYPE_RDLCK 0
-#define P9_LOCK_TYPE_WRLCK 1
-#define P9_LOCK_TYPE_UNLCK 2
-
-#define P9_LOCK_SUCCESS 0
-#define P9_LOCK_BLOCKED 1
-#define P9_LOCK_ERROR 2
-#define P9_LOCK_GRACE 3
-
-#define P9_LOCK_FLAGS_BLOCK 1
-#define P9_LOCK_FLAGS_RECLAIM 2
-
-typedef struct V9fsFlock
-{
- uint8_t type;
- uint32_t flags;
- uint64_t start; /* absolute offset */
- uint64_t length;
- uint32_t proc_id;
- V9fsString client_id;
-} V9fsFlock;
-
-typedef struct V9fsGetlock
-{
- uint8_t type;
- uint64_t start; /* absolute offset */
- uint64_t length;
- uint32_t proc_id;
- V9fsString client_id;
-} V9fsGetlock;
-
-extern int open_fd_hw;
-extern int total_open_fd;
-
-static inline void v9fs_path_write_lock(V9fsState *s)
-{
- if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) {
- qemu_co_rwlock_wrlock(&s->rename_lock);
- }
-}
-
-static inline void v9fs_path_read_lock(V9fsState *s)
-{
- if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) {
- qemu_co_rwlock_rdlock(&s->rename_lock);
- }
-}
-
-static inline void v9fs_path_unlock(V9fsState *s)
-{
- if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) {
- qemu_co_rwlock_unlock(&s->rename_lock);
- }
-}
-
-static inline uint8_t v9fs_request_cancelled(V9fsPDU *pdu)
-{
- return pdu->cancelled;
-}
-
-extern void v9fs_reclaim_fd(V9fsPDU *pdu);
-extern void v9fs_path_init(V9fsPath *path);
-extern void v9fs_path_free(V9fsPath *path);
-extern void v9fs_path_copy(V9fsPath *lhs, V9fsPath *rhs);
-extern int v9fs_name_to_path(V9fsState *s, V9fsPath *dirpath,
- const char *name, V9fsPath *path);
-extern int v9fs_device_realize_common(V9fsState *s, Error **errp);
-extern void v9fs_device_unrealize_common(V9fsState *s, Error **errp);
-
-ssize_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...);
-ssize_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...);
-V9fsPDU *pdu_alloc(V9fsState *s);
-void pdu_free(V9fsPDU *pdu);
-void pdu_submit(V9fsPDU *pdu);
-
-#endif
diff --git a/qemu/hw/9pfs/Makefile.objs b/qemu/hw/9pfs/Makefile.objs
deleted file mode 100644
index da0ae0cfd..000000000
--- a/qemu/hw/9pfs/Makefile.objs
+++ /dev/null
@@ -1,9 +0,0 @@
-common-obj-y = 9p.o
-common-obj-y += 9p-local.o 9p-xattr.o
-common-obj-y += 9p-xattr-user.o 9p-posix-acl.o
-common-obj-y += coth.o cofs.o codir.o cofile.o
-common-obj-y += coxattr.o 9p-synth.o
-common-obj-$(CONFIG_OPEN_BY_HANDLE) += 9p-handle.o
-common-obj-y += 9p-proxy.o
-
-obj-y += virtio-9p-device.o
diff --git a/qemu/hw/9pfs/codir.c b/qemu/hw/9pfs/codir.c
deleted file mode 100644
index 91df7f7a7..000000000
--- a/qemu/hw/9pfs/codir.c
+++ /dev/null
@@ -1,169 +0,0 @@
-
-/*
- * Virtio 9p backend
- *
- * Copyright IBM, Corp. 2011
- *
- * Authors:
- * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "fsdev/qemu-fsdev.h"
-#include "qemu/thread.h"
-#include "qemu/coroutine.h"
-#include "coth.h"
-
-int v9fs_co_readdir_r(V9fsPDU *pdu, V9fsFidState *fidp, struct dirent *dent,
- struct dirent **result)
-{
- int err;
- V9fsState *s = pdu->s;
-
- if (v9fs_request_cancelled(pdu)) {
- return -EINTR;
- }
- v9fs_co_run_in_worker(
- {
- errno = 0;
- err = s->ops->readdir_r(&s->ctx, &fidp->fs, dent, result);
- if (!*result && errno) {
- err = -errno;
- } else {
- err = 0;
- }
- });
- return err;
-}
-
-off_t v9fs_co_telldir(V9fsPDU *pdu, V9fsFidState *fidp)
-{
- off_t err;
- V9fsState *s = pdu->s;
-
- if (v9fs_request_cancelled(pdu)) {
- return -EINTR;
- }
- v9fs_co_run_in_worker(
- {
- err = s->ops->telldir(&s->ctx, &fidp->fs);
- if (err < 0) {
- err = -errno;
- }
- });
- return err;
-}
-
-void v9fs_co_seekdir(V9fsPDU *pdu, V9fsFidState *fidp, off_t offset)
-{
- V9fsState *s = pdu->s;
- if (v9fs_request_cancelled(pdu)) {
- return;
- }
- v9fs_co_run_in_worker(
- {
- s->ops->seekdir(&s->ctx, &fidp->fs, offset);
- });
-}
-
-void v9fs_co_rewinddir(V9fsPDU *pdu, V9fsFidState *fidp)
-{
- V9fsState *s = pdu->s;
- if (v9fs_request_cancelled(pdu)) {
- return;
- }
- v9fs_co_run_in_worker(
- {
- s->ops->rewinddir(&s->ctx, &fidp->fs);
- });
-}
-
-int v9fs_co_mkdir(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name,
- mode_t mode, uid_t uid, gid_t gid, struct stat *stbuf)
-{
- int err;
- FsCred cred;
- V9fsPath path;
- V9fsState *s = pdu->s;
-
- if (v9fs_request_cancelled(pdu)) {
- return -EINTR;
- }
- cred_init(&cred);
- cred.fc_mode = mode;
- cred.fc_uid = uid;
- cred.fc_gid = gid;
- v9fs_path_read_lock(s);
- v9fs_co_run_in_worker(
- {
- err = s->ops->mkdir(&s->ctx, &fidp->path, name->data, &cred);
- if (err < 0) {
- err = -errno;
- } else {
- v9fs_path_init(&path);
- err = v9fs_name_to_path(s, &fidp->path, name->data, &path);
- if (!err) {
- err = s->ops->lstat(&s->ctx, &path, stbuf);
- if (err < 0) {
- err = -errno;
- }
- }
- v9fs_path_free(&path);
- }
- });
- v9fs_path_unlock(s);
- return err;
-}
-
-int v9fs_co_opendir(V9fsPDU *pdu, V9fsFidState *fidp)
-{
- int err;
- V9fsState *s = pdu->s;
-
- if (v9fs_request_cancelled(pdu)) {
- return -EINTR;
- }
- v9fs_path_read_lock(s);
- v9fs_co_run_in_worker(
- {
- err = s->ops->opendir(&s->ctx, &fidp->path, &fidp->fs);
- if (err < 0) {
- err = -errno;
- } else {
- err = 0;
- }
- });
- v9fs_path_unlock(s);
- if (!err) {
- total_open_fd++;
- if (total_open_fd > open_fd_hw) {
- v9fs_reclaim_fd(pdu);
- }
- }
- return err;
-}
-
-int v9fs_co_closedir(V9fsPDU *pdu, V9fsFidOpenState *fs)
-{
- int err;
- V9fsState *s = pdu->s;
-
- if (v9fs_request_cancelled(pdu)) {
- return -EINTR;
- }
- v9fs_co_run_in_worker(
- {
- err = s->ops->closedir(&s->ctx, fs);
- if (err < 0) {
- err = -errno;
- }
- });
- if (!err) {
- total_open_fd--;
- }
- return err;
-}
diff --git a/qemu/hw/9pfs/cofile.c b/qemu/hw/9pfs/cofile.c
deleted file mode 100644
index 293483e0c..000000000
--- a/qemu/hw/9pfs/cofile.c
+++ /dev/null
@@ -1,276 +0,0 @@
-
-/*
- * Virtio 9p backend
- *
- * Copyright IBM, Corp. 2011
- *
- * Authors:
- * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "fsdev/qemu-fsdev.h"
-#include "qemu/thread.h"
-#include "qemu/coroutine.h"
-#include "coth.h"
-
-int v9fs_co_st_gen(V9fsPDU *pdu, V9fsPath *path, mode_t st_mode,
- V9fsStatDotl *v9stat)
-{
- int err = 0;
- V9fsState *s = pdu->s;
-
- if (v9fs_request_cancelled(pdu)) {
- return -EINTR;
- }
- if (s->ctx.exops.get_st_gen) {
- v9fs_path_read_lock(s);
- v9fs_co_run_in_worker(
- {
- err = s->ctx.exops.get_st_gen(&s->ctx, path, st_mode,
- &v9stat->st_gen);
- if (err < 0) {
- err = -errno;
- }
- });
- v9fs_path_unlock(s);
- }
- return err;
-}
-
-int v9fs_co_lstat(V9fsPDU *pdu, V9fsPath *path, struct stat *stbuf)
-{
- int err;
- V9fsState *s = pdu->s;
-
- if (v9fs_request_cancelled(pdu)) {
- return -EINTR;
- }
- v9fs_path_read_lock(s);
- v9fs_co_run_in_worker(
- {
- err = s->ops->lstat(&s->ctx, path, stbuf);
- if (err < 0) {
- err = -errno;
- }
- });
- v9fs_path_unlock(s);
- return err;
-}
-
-int v9fs_co_fstat(V9fsPDU *pdu, V9fsFidState *fidp, struct stat *stbuf)
-{
- int err;
- V9fsState *s = pdu->s;
-
- if (v9fs_request_cancelled(pdu)) {
- return -EINTR;
- }
- v9fs_co_run_in_worker(
- {
- err = s->ops->fstat(&s->ctx, fidp->fid_type, &fidp->fs, stbuf);
- if (err < 0) {
- err = -errno;
- }
- });
- /*
- * Some FS driver (local:mapped-file) can't support fetching attributes
- * using file descriptor. Use Path name in that case.
- */
- if (err == -EOPNOTSUPP) {
- err = v9fs_co_lstat(pdu, &fidp->path, stbuf);
- if (err == -ENOENT) {
- /*
- * fstat on an unlinked file. Work with partial results
- * returned from s->ops->fstat
- */
- err = 0;
- }
- }
- return err;
-}
-
-int v9fs_co_open(V9fsPDU *pdu, V9fsFidState *fidp, int flags)
-{
- int err;
- V9fsState *s = pdu->s;
-
- if (v9fs_request_cancelled(pdu)) {
- return -EINTR;
- }
- v9fs_path_read_lock(s);
- v9fs_co_run_in_worker(
- {
- err = s->ops->open(&s->ctx, &fidp->path, flags, &fidp->fs);
- if (err == -1) {
- err = -errno;
- } else {
- err = 0;
- }
- });
- v9fs_path_unlock(s);
- if (!err) {
- total_open_fd++;
- if (total_open_fd > open_fd_hw) {
- v9fs_reclaim_fd(pdu);
- }
- }
- return err;
-}
-
-int v9fs_co_open2(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name, gid_t gid,
- int flags, int mode, struct stat *stbuf)
-{
- int err;
- FsCred cred;
- V9fsPath path;
- V9fsState *s = pdu->s;
-
- if (v9fs_request_cancelled(pdu)) {
- return -EINTR;
- }
- cred_init(&cred);
- cred.fc_mode = mode & 07777;
- cred.fc_uid = fidp->uid;
- cred.fc_gid = gid;
- /*
- * Hold the directory fid lock so that directory path name
- * don't change. Read lock is fine because this fid cannot
- * be used by any other operation.
- */
- v9fs_path_read_lock(s);
- v9fs_co_run_in_worker(
- {
- err = s->ops->open2(&s->ctx, &fidp->path,
- name->data, flags, &cred, &fidp->fs);
- if (err < 0) {
- err = -errno;
- } else {
- v9fs_path_init(&path);
- err = v9fs_name_to_path(s, &fidp->path, name->data, &path);
- if (!err) {
- err = s->ops->lstat(&s->ctx, &path, stbuf);
- if (err < 0) {
- err = -errno;
- s->ops->close(&s->ctx, &fidp->fs);
- } else {
- v9fs_path_copy(&fidp->path, &path);
- }
- } else {
- s->ops->close(&s->ctx, &fidp->fs);
- }
- v9fs_path_free(&path);
- }
- });
- v9fs_path_unlock(s);
- if (!err) {
- total_open_fd++;
- if (total_open_fd > open_fd_hw) {
- v9fs_reclaim_fd(pdu);
- }
- }
- return err;
-}
-
-int v9fs_co_close(V9fsPDU *pdu, V9fsFidOpenState *fs)
-{
- int err;
- V9fsState *s = pdu->s;
-
- if (v9fs_request_cancelled(pdu)) {
- return -EINTR;
- }
- v9fs_co_run_in_worker(
- {
- err = s->ops->close(&s->ctx, fs);
- if (err < 0) {
- err = -errno;
- }
- });
- if (!err) {
- total_open_fd--;
- }
- return err;
-}
-
-int v9fs_co_fsync(V9fsPDU *pdu, V9fsFidState *fidp, int datasync)
-{
- int err;
- V9fsState *s = pdu->s;
-
- if (v9fs_request_cancelled(pdu)) {
- return -EINTR;
- }
- v9fs_co_run_in_worker(
- {
- err = s->ops->fsync(&s->ctx, fidp->fid_type, &fidp->fs, datasync);
- if (err < 0) {
- err = -errno;
- }
- });
- return err;
-}
-
-int v9fs_co_link(V9fsPDU *pdu, V9fsFidState *oldfid,
- V9fsFidState *newdirfid, V9fsString *name)
-{
- int err;
- V9fsState *s = pdu->s;
-
- if (v9fs_request_cancelled(pdu)) {
- return -EINTR;
- }
- v9fs_path_read_lock(s);
- v9fs_co_run_in_worker(
- {
- err = s->ops->link(&s->ctx, &oldfid->path,
- &newdirfid->path, name->data);
- if (err < 0) {
- err = -errno;
- }
- });
- v9fs_path_unlock(s);
- return err;
-}
-
-int v9fs_co_pwritev(V9fsPDU *pdu, V9fsFidState *fidp,
- struct iovec *iov, int iovcnt, int64_t offset)
-{
- int err;
- V9fsState *s = pdu->s;
-
- if (v9fs_request_cancelled(pdu)) {
- return -EINTR;
- }
- v9fs_co_run_in_worker(
- {
- err = s->ops->pwritev(&s->ctx, &fidp->fs, iov, iovcnt, offset);
- if (err < 0) {
- err = -errno;
- }
- });
- return err;
-}
-
-int v9fs_co_preadv(V9fsPDU *pdu, V9fsFidState *fidp,
- struct iovec *iov, int iovcnt, int64_t offset)
-{
- int err;
- V9fsState *s = pdu->s;
-
- if (v9fs_request_cancelled(pdu)) {
- return -EINTR;
- }
- v9fs_co_run_in_worker(
- {
- err = s->ops->preadv(&s->ctx, &fidp->fs, iov, iovcnt, offset);
- if (err < 0) {
- err = -errno;
- }
- });
- return err;
-}
diff --git a/qemu/hw/9pfs/cofs.c b/qemu/hw/9pfs/cofs.c
deleted file mode 100644
index 18c81cb3d..000000000
--- a/qemu/hw/9pfs/cofs.c
+++ /dev/null
@@ -1,365 +0,0 @@
-
-/*
- * Virtio 9p backend
- *
- * Copyright IBM, Corp. 2011
- *
- * Authors:
- * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "fsdev/qemu-fsdev.h"
-#include "qemu/thread.h"
-#include "qemu/coroutine.h"
-#include "coth.h"
-
-static ssize_t __readlink(V9fsState *s, V9fsPath *path, V9fsString *buf)
-{
- ssize_t len, maxlen = PATH_MAX;
-
- buf->data = g_malloc(PATH_MAX);
- for(;;) {
- len = s->ops->readlink(&s->ctx, path, buf->data, maxlen);
- if (len < 0) {
- g_free(buf->data);
- buf->data = NULL;
- buf->size = 0;
- break;
- } else if (len == maxlen) {
- /*
- * We dodn't have space to put the NULL or we have more
- * to read. Increase the size and try again
- */
- maxlen *= 2;
- g_free(buf->data);
- buf->data = g_malloc(maxlen);
- continue;
- }
- /*
- * Null terminate the readlink output
- */
- buf->data[len] = '\0';
- buf->size = len;
- break;
- }
- return len;
-}
-
-int v9fs_co_readlink(V9fsPDU *pdu, V9fsPath *path, V9fsString *buf)
-{
- int err;
- V9fsState *s = pdu->s;
-
- if (v9fs_request_cancelled(pdu)) {
- return -EINTR;
- }
- v9fs_path_read_lock(s);
- v9fs_co_run_in_worker(
- {
- err = __readlink(s, path, buf);
- if (err < 0) {
- err = -errno;
- }
- });
- v9fs_path_unlock(s);
- return err;
-}
-
-int v9fs_co_statfs(V9fsPDU *pdu, V9fsPath *path, struct statfs *stbuf)
-{
- int err;
- V9fsState *s = pdu->s;
-
- if (v9fs_request_cancelled(pdu)) {
- return -EINTR;
- }
- v9fs_path_read_lock(s);
- v9fs_co_run_in_worker(
- {
- err = s->ops->statfs(&s->ctx, path, stbuf);
- if (err < 0) {
- err = -errno;
- }
- });
- v9fs_path_unlock(s);
- return err;
-}
-
-int v9fs_co_chmod(V9fsPDU *pdu, V9fsPath *path, mode_t mode)
-{
- int err;
- FsCred cred;
- V9fsState *s = pdu->s;
-
- if (v9fs_request_cancelled(pdu)) {
- return -EINTR;
- }
- cred_init(&cred);
- cred.fc_mode = mode;
- v9fs_path_read_lock(s);
- v9fs_co_run_in_worker(
- {
- err = s->ops->chmod(&s->ctx, path, &cred);
- if (err < 0) {
- err = -errno;
- }
- });
- v9fs_path_unlock(s);
- return err;
-}
-
-int v9fs_co_utimensat(V9fsPDU *pdu, V9fsPath *path,
- struct timespec times[2])
-{
- int err;
- V9fsState *s = pdu->s;
-
- if (v9fs_request_cancelled(pdu)) {
- return -EINTR;
- }
- v9fs_path_read_lock(s);
- v9fs_co_run_in_worker(
- {
- err = s->ops->utimensat(&s->ctx, path, times);
- if (err < 0) {
- err = -errno;
- }
- });
- v9fs_path_unlock(s);
- return err;
-}
-
-int v9fs_co_chown(V9fsPDU *pdu, V9fsPath *path, uid_t uid, gid_t gid)
-{
- int err;
- FsCred cred;
- V9fsState *s = pdu->s;
-
- if (v9fs_request_cancelled(pdu)) {
- return -EINTR;
- }
- cred_init(&cred);
- cred.fc_uid = uid;
- cred.fc_gid = gid;
- v9fs_path_read_lock(s);
- v9fs_co_run_in_worker(
- {
- err = s->ops->chown(&s->ctx, path, &cred);
- if (err < 0) {
- err = -errno;
- }
- });
- v9fs_path_unlock(s);
- return err;
-}
-
-int v9fs_co_truncate(V9fsPDU *pdu, V9fsPath *path, off_t size)
-{
- int err;
- V9fsState *s = pdu->s;
-
- if (v9fs_request_cancelled(pdu)) {
- return -EINTR;
- }
- v9fs_path_read_lock(s);
- v9fs_co_run_in_worker(
- {
- err = s->ops->truncate(&s->ctx, path, size);
- if (err < 0) {
- err = -errno;
- }
- });
- v9fs_path_unlock(s);
- return err;
-}
-
-int v9fs_co_mknod(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name, uid_t uid,
- gid_t gid, dev_t dev, mode_t mode, struct stat *stbuf)
-{
- int err;
- V9fsPath path;
- FsCred cred;
- V9fsState *s = pdu->s;
-
- if (v9fs_request_cancelled(pdu)) {
- return -EINTR;
- }
- cred_init(&cred);
- cred.fc_uid = uid;
- cred.fc_gid = gid;
- cred.fc_mode = mode;
- cred.fc_rdev = dev;
- v9fs_path_read_lock(s);
- v9fs_co_run_in_worker(
- {
- err = s->ops->mknod(&s->ctx, &fidp->path, name->data, &cred);
- if (err < 0) {
- err = -errno;
- } else {
- v9fs_path_init(&path);
- err = v9fs_name_to_path(s, &fidp->path, name->data, &path);
- if (!err) {
- err = s->ops->lstat(&s->ctx, &path, stbuf);
- if (err < 0) {
- err = -errno;
- }
- }
- v9fs_path_free(&path);
- }
- });
- v9fs_path_unlock(s);
- return err;
-}
-
-/* Only works with path name based fid */
-int v9fs_co_remove(V9fsPDU *pdu, V9fsPath *path)
-{
- int err;
- V9fsState *s = pdu->s;
-
- if (v9fs_request_cancelled(pdu)) {
- return -EINTR;
- }
- v9fs_path_read_lock(s);
- v9fs_co_run_in_worker(
- {
- err = s->ops->remove(&s->ctx, path->data);
- if (err < 0) {
- err = -errno;
- }
- });
- v9fs_path_unlock(s);
- return err;
-}
-
-int v9fs_co_unlinkat(V9fsPDU *pdu, V9fsPath *path, V9fsString *name, int flags)
-{
- int err;
- V9fsState *s = pdu->s;
-
- if (v9fs_request_cancelled(pdu)) {
- return -EINTR;
- }
- v9fs_path_read_lock(s);
- v9fs_co_run_in_worker(
- {
- err = s->ops->unlinkat(&s->ctx, path, name->data, flags);
- if (err < 0) {
- err = -errno;
- }
- });
- v9fs_path_unlock(s);
- return err;
-}
-
-/* Only work with path name based fid */
-int v9fs_co_rename(V9fsPDU *pdu, V9fsPath *oldpath, V9fsPath *newpath)
-{
- int err;
- V9fsState *s = pdu->s;
-
- if (v9fs_request_cancelled(pdu)) {
- return -EINTR;
- }
- v9fs_co_run_in_worker(
- {
- err = s->ops->rename(&s->ctx, oldpath->data, newpath->data);
- if (err < 0) {
- err = -errno;
- }
- });
- return err;
-}
-
-int v9fs_co_renameat(V9fsPDU *pdu, V9fsPath *olddirpath, V9fsString *oldname,
- V9fsPath *newdirpath, V9fsString *newname)
-{
- int err;
- V9fsState *s = pdu->s;
-
- if (v9fs_request_cancelled(pdu)) {
- return -EINTR;
- }
- v9fs_co_run_in_worker(
- {
- err = s->ops->renameat(&s->ctx, olddirpath, oldname->data,
- newdirpath, newname->data);
- if (err < 0) {
- err = -errno;
- }
- });
- return err;
-}
-
-int v9fs_co_symlink(V9fsPDU *pdu, V9fsFidState *dfidp, V9fsString *name,
- const char *oldpath, gid_t gid, struct stat *stbuf)
-{
- int err;
- FsCred cred;
- V9fsPath path;
- V9fsState *s = pdu->s;
-
- if (v9fs_request_cancelled(pdu)) {
- return -EINTR;
- }
- cred_init(&cred);
- cred.fc_uid = dfidp->uid;
- cred.fc_gid = gid;
- cred.fc_mode = 0777;
- v9fs_path_read_lock(s);
- v9fs_co_run_in_worker(
- {
- err = s->ops->symlink(&s->ctx, oldpath, &dfidp->path,
- name->data, &cred);
- if (err < 0) {
- err = -errno;
- } else {
- v9fs_path_init(&path);
- err = v9fs_name_to_path(s, &dfidp->path, name->data, &path);
- if (!err) {
- err = s->ops->lstat(&s->ctx, &path, stbuf);
- if (err < 0) {
- err = -errno;
- }
- }
- v9fs_path_free(&path);
- }
- });
- v9fs_path_unlock(s);
- return err;
-}
-
-/*
- * For path name based fid we don't block. So we can
- * directly call the fs driver ops.
- */
-int v9fs_co_name_to_path(V9fsPDU *pdu, V9fsPath *dirpath,
- const char *name, V9fsPath *path)
-{
- int err;
- V9fsState *s = pdu->s;
-
- if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) {
- err = s->ops->name_to_path(&s->ctx, dirpath, name, path);
- if (err < 0) {
- err = -errno;
- }
- } else {
- if (v9fs_request_cancelled(pdu)) {
- return -EINTR;
- }
- v9fs_co_run_in_worker(
- {
- err = s->ops->name_to_path(&s->ctx, dirpath, name, path);
- if (err < 0) {
- err = -errno;
- }
- });
- }
- return err;
-}
diff --git a/qemu/hw/9pfs/coth.c b/qemu/hw/9pfs/coth.c
deleted file mode 100644
index 464293ef2..000000000
--- a/qemu/hw/9pfs/coth.c
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 9p backend
- *
- * Copyright IBM, Corp. 2010
- *
- * Authors:
- * Harsh Prateek Bora <harsh@linux.vnet.ibm.com>
- * Venkateswararao Jujjuri(JV) <jvrao@linux.vnet.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "block/thread-pool.h"
-#include "qemu/coroutine.h"
-#include "qemu/main-loop.h"
-#include "coth.h"
-
-/* Called from QEMU I/O thread. */
-static void coroutine_enter_cb(void *opaque, int ret)
-{
- Coroutine *co = opaque;
- qemu_coroutine_enter(co, NULL);
-}
-
-/* Called from worker thread. */
-static int coroutine_enter_func(void *arg)
-{
- Coroutine *co = arg;
- qemu_coroutine_enter(co, NULL);
- return 0;
-}
-
-void co_run_in_worker_bh(void *opaque)
-{
- Coroutine *co = opaque;
- thread_pool_submit_aio(aio_get_thread_pool(qemu_get_aio_context()),
- coroutine_enter_func, co, coroutine_enter_cb, co);
-}
diff --git a/qemu/hw/9pfs/coth.h b/qemu/hw/9pfs/coth.h
deleted file mode 100644
index 209fc6a9a..000000000
--- a/qemu/hw/9pfs/coth.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * 9p backend
- *
- * Copyright IBM, Corp. 2010
- *
- * Authors:
- * Harsh Prateek Bora <harsh@linux.vnet.ibm.com>
- * Venkateswararao Jujjuri(JV) <jvrao@linux.vnet.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- */
-
-#ifndef _QEMU_9P_COTH_H
-#define _QEMU_9P_COTH_H
-
-#include "qemu/thread.h"
-#include "qemu/coroutine.h"
-#include "virtio-9p.h"
-
-/*
- * we want to use bottom half because we want to make sure the below
- * sequence of events.
- *
- * 1. Yield the coroutine in the QEMU thread.
- * 2. Submit the coroutine to a worker thread.
- * 3. Enter the coroutine in the worker thread.
- * we cannot swap step 1 and 2, because that would imply worker thread
- * can enter coroutine while step1 is still running
- */
-#define v9fs_co_run_in_worker(code_block) \
- do { \
- QEMUBH *co_bh; \
- co_bh = qemu_bh_new(co_run_in_worker_bh, \
- qemu_coroutine_self()); \
- qemu_bh_schedule(co_bh); \
- /* \
- * yield in qemu thread and re-enter back \
- * in worker thread \
- */ \
- qemu_coroutine_yield(); \
- qemu_bh_delete(co_bh); \
- code_block; \
- /* re-enter back to qemu thread */ \
- qemu_coroutine_yield(); \
- } while (0)
-
-extern void co_run_in_worker_bh(void *);
-extern int v9fs_init_worker_threads(void);
-extern int v9fs_co_readlink(V9fsPDU *, V9fsPath *, V9fsString *);
-extern int v9fs_co_readdir_r(V9fsPDU *, V9fsFidState *,
- struct dirent *, struct dirent **result);
-extern off_t v9fs_co_telldir(V9fsPDU *, V9fsFidState *);
-extern void v9fs_co_seekdir(V9fsPDU *, V9fsFidState *, off_t);
-extern void v9fs_co_rewinddir(V9fsPDU *, V9fsFidState *);
-extern int v9fs_co_statfs(V9fsPDU *, V9fsPath *, struct statfs *);
-extern int v9fs_co_lstat(V9fsPDU *, V9fsPath *, struct stat *);
-extern int v9fs_co_chmod(V9fsPDU *, V9fsPath *, mode_t);
-extern int v9fs_co_utimensat(V9fsPDU *, V9fsPath *, struct timespec [2]);
-extern int v9fs_co_chown(V9fsPDU *, V9fsPath *, uid_t, gid_t);
-extern int v9fs_co_truncate(V9fsPDU *, V9fsPath *, off_t);
-extern int v9fs_co_llistxattr(V9fsPDU *, V9fsPath *, void *, size_t);
-extern int v9fs_co_lgetxattr(V9fsPDU *, V9fsPath *,
- V9fsString *, void *, size_t);
-extern int v9fs_co_mknod(V9fsPDU *, V9fsFidState *, V9fsString *, uid_t,
- gid_t, dev_t, mode_t, struct stat *);
-extern int v9fs_co_mkdir(V9fsPDU *, V9fsFidState *, V9fsString *,
- mode_t, uid_t, gid_t, struct stat *);
-extern int v9fs_co_remove(V9fsPDU *, V9fsPath *);
-extern int v9fs_co_rename(V9fsPDU *, V9fsPath *, V9fsPath *);
-extern int v9fs_co_unlinkat(V9fsPDU *, V9fsPath *, V9fsString *, int flags);
-extern int v9fs_co_renameat(V9fsPDU *, V9fsPath *, V9fsString *,
- V9fsPath *, V9fsString *);
-extern int v9fs_co_fstat(V9fsPDU *, V9fsFidState *, struct stat *);
-extern int v9fs_co_opendir(V9fsPDU *, V9fsFidState *);
-extern int v9fs_co_open(V9fsPDU *, V9fsFidState *, int);
-extern int v9fs_co_open2(V9fsPDU *, V9fsFidState *, V9fsString *,
- gid_t, int, int, struct stat *);
-extern int v9fs_co_lsetxattr(V9fsPDU *, V9fsPath *, V9fsString *,
- void *, size_t, int);
-extern int v9fs_co_lremovexattr(V9fsPDU *, V9fsPath *, V9fsString *);
-extern int v9fs_co_closedir(V9fsPDU *, V9fsFidOpenState *);
-extern int v9fs_co_close(V9fsPDU *, V9fsFidOpenState *);
-extern int v9fs_co_fsync(V9fsPDU *, V9fsFidState *, int);
-extern int v9fs_co_symlink(V9fsPDU *, V9fsFidState *, V9fsString *,
- const char *, gid_t, struct stat *);
-extern int v9fs_co_link(V9fsPDU *, V9fsFidState *,
- V9fsFidState *, V9fsString *);
-extern int v9fs_co_pwritev(V9fsPDU *, V9fsFidState *,
- struct iovec *, int, int64_t);
-extern int v9fs_co_preadv(V9fsPDU *, V9fsFidState *,
- struct iovec *, int, int64_t);
-extern int v9fs_co_name_to_path(V9fsPDU *, V9fsPath *,
- const char *, V9fsPath *);
-extern int v9fs_co_st_gen(V9fsPDU *pdu, V9fsPath *path, mode_t,
- V9fsStatDotl *v9stat);
-
-#endif
diff --git a/qemu/hw/9pfs/coxattr.c b/qemu/hw/9pfs/coxattr.c
deleted file mode 100644
index 6ad96ea9f..000000000
--- a/qemu/hw/9pfs/coxattr.c
+++ /dev/null
@@ -1,108 +0,0 @@
-
-/*
- * Virtio 9p backend
- *
- * Copyright IBM, Corp. 2011
- *
- * Authors:
- * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "fsdev/qemu-fsdev.h"
-#include "qemu/thread.h"
-#include "qemu/coroutine.h"
-#include "coth.h"
-
-int v9fs_co_llistxattr(V9fsPDU *pdu, V9fsPath *path, void *value, size_t size)
-{
- int err;
- V9fsState *s = pdu->s;
-
- if (v9fs_request_cancelled(pdu)) {
- return -EINTR;
- }
- v9fs_path_read_lock(s);
- v9fs_co_run_in_worker(
- {
- err = s->ops->llistxattr(&s->ctx, path, value, size);
- if (err < 0) {
- err = -errno;
- }
- });
- v9fs_path_unlock(s);
- return err;
-}
-
-int v9fs_co_lgetxattr(V9fsPDU *pdu, V9fsPath *path,
- V9fsString *xattr_name,
- void *value, size_t size)
-{
- int err;
- V9fsState *s = pdu->s;
-
- if (v9fs_request_cancelled(pdu)) {
- return -EINTR;
- }
- v9fs_path_read_lock(s);
- v9fs_co_run_in_worker(
- {
- err = s->ops->lgetxattr(&s->ctx, path,
- xattr_name->data,
- value, size);
- if (err < 0) {
- err = -errno;
- }
- });
- v9fs_path_unlock(s);
- return err;
-}
-
-int v9fs_co_lsetxattr(V9fsPDU *pdu, V9fsPath *path,
- V9fsString *xattr_name, void *value,
- size_t size, int flags)
-{
- int err;
- V9fsState *s = pdu->s;
-
- if (v9fs_request_cancelled(pdu)) {
- return -EINTR;
- }
- v9fs_path_read_lock(s);
- v9fs_co_run_in_worker(
- {
- err = s->ops->lsetxattr(&s->ctx, path,
- xattr_name->data, value,
- size, flags);
- if (err < 0) {
- err = -errno;
- }
- });
- v9fs_path_unlock(s);
- return err;
-}
-
-int v9fs_co_lremovexattr(V9fsPDU *pdu, V9fsPath *path,
- V9fsString *xattr_name)
-{
- int err;
- V9fsState *s = pdu->s;
-
- if (v9fs_request_cancelled(pdu)) {
- return -EINTR;
- }
- v9fs_path_read_lock(s);
- v9fs_co_run_in_worker(
- {
- err = s->ops->lremovexattr(&s->ctx, path, xattr_name->data);
- if (err < 0) {
- err = -errno;
- }
- });
- v9fs_path_unlock(s);
- return err;
-}
diff --git a/qemu/hw/9pfs/virtio-9p-device.c b/qemu/hw/9pfs/virtio-9p-device.c
deleted file mode 100644
index a38850ee8..000000000
--- a/qemu/hw/9pfs/virtio-9p-device.c
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Virtio 9p backend
- *
- * Copyright IBM, Corp. 2010
- *
- * Authors:
- * Anthony Liguori <aliguori@us.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "hw/virtio/virtio.h"
-#include "hw/i386/pc.h"
-#include "qemu/sockets.h"
-#include "virtio-9p.h"
-#include "fsdev/qemu-fsdev.h"
-#include "9p-xattr.h"
-#include "coth.h"
-#include "hw/virtio/virtio-access.h"
-#include "qemu/iov.h"
-
-void virtio_9p_push_and_notify(V9fsPDU *pdu)
-{
- V9fsState *s = pdu->s;
- V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
- VirtQueueElement *elem = v->elems[pdu->idx];
-
- /* push onto queue and notify */
- virtqueue_push(v->vq, elem, pdu->size);
- g_free(elem);
- v->elems[pdu->idx] = NULL;
-
- /* FIXME: we should batch these completions */
- virtio_notify(VIRTIO_DEVICE(v), v->vq);
-}
-
-static void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
-{
- V9fsVirtioState *v = (V9fsVirtioState *)vdev;
- V9fsState *s = &v->state;
- V9fsPDU *pdu;
- ssize_t len;
-
- while ((pdu = pdu_alloc(s))) {
- struct {
- uint32_t size_le;
- uint8_t id;
- uint16_t tag_le;
- } QEMU_PACKED out;
- VirtQueueElement *elem;
-
- elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
- if (!elem) {
- pdu_free(pdu);
- break;
- }
-
- BUG_ON(elem->out_num == 0 || elem->in_num == 0);
- QEMU_BUILD_BUG_ON(sizeof out != 7);
-
- v->elems[pdu->idx] = elem;
- len = iov_to_buf(elem->out_sg, elem->out_num, 0,
- &out, sizeof out);
- BUG_ON(len != sizeof out);
-
- pdu->size = le32_to_cpu(out.size_le);
-
- pdu->id = out.id;
- pdu->tag = le16_to_cpu(out.tag_le);
-
- qemu_co_queue_init(&pdu->complete);
- pdu_submit(pdu);
- }
-}
-
-static uint64_t virtio_9p_get_features(VirtIODevice *vdev, uint64_t features,
- Error **errp)
-{
- virtio_add_feature(&features, VIRTIO_9P_MOUNT_TAG);
- return features;
-}
-
-static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config)
-{
- int len;
- struct virtio_9p_config *cfg;
- V9fsVirtioState *v = VIRTIO_9P(vdev);
- V9fsState *s = &v->state;
-
- len = strlen(s->tag);
- cfg = g_malloc0(sizeof(struct virtio_9p_config) + len);
- virtio_stw_p(vdev, &cfg->tag_len, len);
- /* We don't copy the terminating null to config space */
- memcpy(cfg->tag, s->tag, len);
- memcpy(config, cfg, v->config_size);
- g_free(cfg);
-}
-
-static void virtio_9p_save(QEMUFile *f, void *opaque)
-{
- virtio_save(VIRTIO_DEVICE(opaque), f);
-}
-
-static int virtio_9p_load(QEMUFile *f, void *opaque, int version_id)
-{
- return virtio_load(VIRTIO_DEVICE(opaque), f, version_id);
-}
-
-static void virtio_9p_device_realize(DeviceState *dev, Error **errp)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
- V9fsVirtioState *v = VIRTIO_9P(dev);
- V9fsState *s = &v->state;
-
- if (v9fs_device_realize_common(s, errp)) {
- goto out;
- }
-
- v->config_size = sizeof(struct virtio_9p_config) + strlen(s->fsconf.tag);
- virtio_init(vdev, "virtio-9p", VIRTIO_ID_9P, v->config_size);
- v->vq = virtio_add_queue(vdev, MAX_REQ, handle_9p_output);
- register_savevm(dev, "virtio-9p", -1, 1, virtio_9p_save, virtio_9p_load, v);
-
-out:
- return;
-}
-
-static void virtio_9p_device_unrealize(DeviceState *dev, Error **errp)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
- V9fsVirtioState *v = VIRTIO_9P(dev);
- V9fsState *s = &v->state;
-
- virtio_cleanup(vdev);
- unregister_savevm(dev, "virtio-9p", v);
- v9fs_device_unrealize_common(s, errp);
-}
-
-ssize_t virtio_pdu_vmarshal(V9fsPDU *pdu, size_t offset,
- const char *fmt, va_list ap)
-{
- V9fsState *s = pdu->s;
- V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
- VirtQueueElement *elem = v->elems[pdu->idx];
-
- return v9fs_iov_vmarshal(elem->in_sg, elem->in_num, offset, 1, fmt, ap);
-}
-
-ssize_t virtio_pdu_vunmarshal(V9fsPDU *pdu, size_t offset,
- const char *fmt, va_list ap)
-{
- V9fsState *s = pdu->s;
- V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
- VirtQueueElement *elem = v->elems[pdu->idx];
-
- return v9fs_iov_vunmarshal(elem->out_sg, elem->out_num, offset, 1, fmt, ap);
-}
-
-void virtio_init_iov_from_pdu(V9fsPDU *pdu, struct iovec **piov,
- unsigned int *pniov, bool is_write)
-{
- V9fsState *s = pdu->s;
- V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
- VirtQueueElement *elem = v->elems[pdu->idx];
-
- if (is_write) {
- *piov = elem->out_sg;
- *pniov = elem->out_num;
- } else {
- *piov = elem->in_sg;
- *pniov = elem->in_num;
- }
-}
-
-/* virtio-9p device */
-
-static Property virtio_9p_properties[] = {
- DEFINE_PROP_STRING("mount_tag", V9fsVirtioState, state.fsconf.tag),
- DEFINE_PROP_STRING("fsdev", V9fsVirtioState, state.fsconf.fsdev_id),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_9p_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
-
- dc->props = virtio_9p_properties;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
- vdc->realize = virtio_9p_device_realize;
- vdc->unrealize = virtio_9p_device_unrealize;
- vdc->get_features = virtio_9p_get_features;
- vdc->get_config = virtio_9p_get_config;
-}
-
-static const TypeInfo virtio_device_info = {
- .name = TYPE_VIRTIO_9P,
- .parent = TYPE_VIRTIO_DEVICE,
- .instance_size = sizeof(V9fsVirtioState),
- .class_init = virtio_9p_class_init,
-};
-
-static void virtio_9p_register_types(void)
-{
- type_register_static(&virtio_device_info);
-}
-
-type_init(virtio_9p_register_types)
diff --git a/qemu/hw/9pfs/virtio-9p.h b/qemu/hw/9pfs/virtio-9p.h
deleted file mode 100644
index 7f6d88553..000000000
--- a/qemu/hw/9pfs/virtio-9p.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef _QEMU_VIRTIO_9P_H
-#define _QEMU_VIRTIO_9P_H
-
-#include "standard-headers/linux/virtio_9p.h"
-#include "hw/virtio/virtio.h"
-#include "9p.h"
-
-typedef struct V9fsVirtioState
-{
- VirtIODevice parent_obj;
- VirtQueue *vq;
- size_t config_size;
- V9fsPDU pdus[MAX_REQ];
- VirtQueueElement *elems[MAX_REQ];
- V9fsState state;
-} V9fsVirtioState;
-
-extern void virtio_9p_push_and_notify(V9fsPDU *pdu);
-
-ssize_t virtio_pdu_vmarshal(V9fsPDU *pdu, size_t offset,
- const char *fmt, va_list ap);
-ssize_t virtio_pdu_vunmarshal(V9fsPDU *pdu, size_t offset,
- const char *fmt, va_list ap);
-void virtio_init_iov_from_pdu(V9fsPDU *pdu, struct iovec **piov,
- unsigned int *pniov, bool is_write);
-
-#define TYPE_VIRTIO_9P "virtio-9p-device"
-#define VIRTIO_9P(obj) \
- OBJECT_CHECK(V9fsVirtioState, (obj), TYPE_VIRTIO_9P)
-
-#endif
diff --git a/qemu/hw/Makefile.objs b/qemu/hw/Makefile.objs
deleted file mode 100644
index 4a07ed434..000000000
--- a/qemu/hw/Makefile.objs
+++ /dev/null
@@ -1,38 +0,0 @@
-devices-dirs-$(call land, $(CONFIG_VIRTIO),$(call land,$(CONFIG_VIRTFS),$(CONFIG_PCI))) += 9pfs/
-devices-dirs-$(CONFIG_ACPI) += acpi/
-devices-dirs-$(CONFIG_SOFTMMU) += audio/
-devices-dirs-$(CONFIG_SOFTMMU) += block/
-devices-dirs-$(CONFIG_SOFTMMU) += bt/
-devices-dirs-$(CONFIG_SOFTMMU) += char/
-devices-dirs-$(CONFIG_SOFTMMU) += cpu/
-devices-dirs-$(CONFIG_SOFTMMU) += display/
-devices-dirs-$(CONFIG_SOFTMMU) += dma/
-devices-dirs-$(CONFIG_SOFTMMU) += gpio/
-devices-dirs-$(CONFIG_SOFTMMU) += i2c/
-devices-dirs-$(CONFIG_SOFTMMU) += ide/
-devices-dirs-$(CONFIG_SOFTMMU) += input/
-devices-dirs-$(CONFIG_SOFTMMU) += intc/
-devices-dirs-$(CONFIG_IPACK) += ipack/
-devices-dirs-$(CONFIG_IPMI) += ipmi/
-devices-dirs-$(CONFIG_SOFTMMU) += isa/
-devices-dirs-$(CONFIG_SOFTMMU) += misc/
-devices-dirs-$(CONFIG_SOFTMMU) += net/
-devices-dirs-$(CONFIG_SOFTMMU) += nvram/
-devices-dirs-$(CONFIG_SOFTMMU) += pci/
-devices-dirs-$(CONFIG_PCI) += pci-bridge/ pci-host/
-devices-dirs-$(CONFIG_SOFTMMU) += pcmcia/
-devices-dirs-$(CONFIG_SOFTMMU) += scsi/
-devices-dirs-$(CONFIG_SOFTMMU) += sd/
-devices-dirs-$(CONFIG_SOFTMMU) += ssi/
-devices-dirs-$(CONFIG_SOFTMMU) += timer/
-devices-dirs-$(CONFIG_TPM) += tpm/
-devices-dirs-$(CONFIG_SOFTMMU) += usb/
-devices-dirs-$(CONFIG_SOFTMMU) += vfio/
-devices-dirs-$(CONFIG_VIRTIO) += virtio/
-devices-dirs-$(CONFIG_SOFTMMU) += watchdog/
-devices-dirs-$(CONFIG_SOFTMMU) += xen/
-devices-dirs-$(CONFIG_MEM_HOTPLUG) += mem/
-devices-dirs-$(CONFIG_SMBIOS) += smbios/
-devices-dirs-y += core/
-common-obj-y += $(devices-dirs-y)
-obj-y += $(devices-dirs-y)
diff --git a/qemu/hw/acpi/Makefile.objs b/qemu/hw/acpi/Makefile.objs
deleted file mode 100644
index faee86c5c..000000000
--- a/qemu/hw/acpi/Makefile.objs
+++ /dev/null
@@ -1,8 +0,0 @@
-common-obj-$(CONFIG_ACPI_X86) += core.o piix4.o pcihp.o
-common-obj-$(CONFIG_ACPI_X86_ICH) += ich9.o tco.o
-common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu_hotplug.o cpu_hotplug_acpi_table.o
-common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o memory_hotplug_acpi_table.o
-obj-$(CONFIG_ACPI_NVDIMM) += nvdimm.o
-common-obj-$(CONFIG_ACPI) += acpi_interface.o
-common-obj-$(CONFIG_ACPI) += bios-linker-loader.o
-common-obj-$(CONFIG_ACPI) += aml-build.o
diff --git a/qemu/hw/acpi/acpi_interface.c b/qemu/hw/acpi/acpi_interface.c
deleted file mode 100644
index d82131326..000000000
--- a/qemu/hw/acpi/acpi_interface.c
+++ /dev/null
@@ -1,16 +0,0 @@
-#include "qemu/osdep.h"
-#include "hw/acpi/acpi_dev_interface.h"
-#include "qemu/module.h"
-
-static void register_types(void)
-{
- static const TypeInfo acpi_dev_if_info = {
- .name = TYPE_ACPI_DEVICE_IF,
- .parent = TYPE_INTERFACE,
- .class_size = sizeof(AcpiDeviceIfClass),
- };
-
- type_register_static(&acpi_dev_if_info);
-}
-
-type_init(register_types)
diff --git a/qemu/hw/acpi/aml-build.c b/qemu/hw/acpi/aml-build.c
deleted file mode 100644
index ab89ca638..000000000
--- a/qemu/hw/acpi/aml-build.c
+++ /dev/null
@@ -1,1565 +0,0 @@
-/* Support for generating ACPI tables and passing them to Guests
- *
- * Copyright (C) 2015 Red Hat Inc
- *
- * Author: Michael S. Tsirkin <mst@redhat.com>
- * Author: Igor Mammedov <imammedo@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include <glib/gprintf.h>
-#include "hw/acpi/aml-build.h"
-#include "qemu/bswap.h"
-#include "qemu/bitops.h"
-#include "hw/acpi/bios-linker-loader.h"
-
-static GArray *build_alloc_array(void)
-{
- return g_array_new(false, true /* clear */, 1);
-}
-
-static void build_free_array(GArray *array)
-{
- g_array_free(array, true);
-}
-
-static void build_prepend_byte(GArray *array, uint8_t val)
-{
- g_array_prepend_val(array, val);
-}
-
-static void build_append_byte(GArray *array, uint8_t val)
-{
- g_array_append_val(array, val);
-}
-
-static void build_append_array(GArray *array, GArray *val)
-{
- g_array_append_vals(array, val->data, val->len);
-}
-
-#define ACPI_NAMESEG_LEN 4
-
-static void
-build_append_nameseg(GArray *array, const char *seg)
-{
- int len;
-
- len = strlen(seg);
- assert(len <= ACPI_NAMESEG_LEN);
-
- g_array_append_vals(array, seg, len);
- /* Pad up to ACPI_NAMESEG_LEN characters if necessary. */
- g_array_append_vals(array, "____", ACPI_NAMESEG_LEN - len);
-}
-
-static void GCC_FMT_ATTR(2, 0)
-build_append_namestringv(GArray *array, const char *format, va_list ap)
-{
- char *s;
- char **segs;
- char **segs_iter;
- int seg_count = 0;
-
- s = g_strdup_vprintf(format, ap);
- segs = g_strsplit(s, ".", 0);
- g_free(s);
-
- /* count segments */
- segs_iter = segs;
- while (*segs_iter) {
- ++segs_iter;
- ++seg_count;
- }
- /*
- * ACPI 5.0 spec: 20.2.2 Name Objects Encoding:
- * "SegCount can be from 1 to 255"
- */
- assert(seg_count > 0 && seg_count <= 255);
-
- /* handle RootPath || PrefixPath */
- s = *segs;
- while (*s == '\\' || *s == '^') {
- build_append_byte(array, *s);
- ++s;
- }
-
- switch (seg_count) {
- case 1:
- if (!*s) {
- build_append_byte(array, 0x00); /* NullName */
- } else {
- build_append_nameseg(array, s);
- }
- break;
-
- case 2:
- build_append_byte(array, 0x2E); /* DualNamePrefix */
- build_append_nameseg(array, s);
- build_append_nameseg(array, segs[1]);
- break;
- default:
- build_append_byte(array, 0x2F); /* MultiNamePrefix */
- build_append_byte(array, seg_count);
-
- /* handle the 1st segment manually due to prefix/root path */
- build_append_nameseg(array, s);
-
- /* add the rest of segments */
- segs_iter = segs + 1;
- while (*segs_iter) {
- build_append_nameseg(array, *segs_iter);
- ++segs_iter;
- }
- break;
- }
- g_strfreev(segs);
-}
-
-GCC_FMT_ATTR(2, 3)
-static void build_append_namestring(GArray *array, const char *format, ...)
-{
- va_list ap;
-
- va_start(ap, format);
- build_append_namestringv(array, format, ap);
- va_end(ap);
-}
-
-/* 5.4 Definition Block Encoding */
-enum {
- PACKAGE_LENGTH_1BYTE_SHIFT = 6, /* Up to 63 - use extra 2 bits. */
- PACKAGE_LENGTH_2BYTE_SHIFT = 4,
- PACKAGE_LENGTH_3BYTE_SHIFT = 12,
- PACKAGE_LENGTH_4BYTE_SHIFT = 20,
-};
-
-static void
-build_prepend_package_length(GArray *package, unsigned length, bool incl_self)
-{
- uint8_t byte;
- unsigned length_bytes;
-
- if (length + 1 < (1 << PACKAGE_LENGTH_1BYTE_SHIFT)) {
- length_bytes = 1;
- } else if (length + 2 < (1 << PACKAGE_LENGTH_3BYTE_SHIFT)) {
- length_bytes = 2;
- } else if (length + 3 < (1 << PACKAGE_LENGTH_4BYTE_SHIFT)) {
- length_bytes = 3;
- } else {
- length_bytes = 4;
- }
-
- /*
- * NamedField uses PkgLength encoding but it doesn't include length
- * of PkgLength itself.
- */
- if (incl_self) {
- /*
- * PkgLength is the length of the inclusive length of the data
- * and PkgLength's length itself when used for terms with
- * explitit length.
- */
- length += length_bytes;
- }
-
- switch (length_bytes) {
- case 1:
- byte = length;
- build_prepend_byte(package, byte);
- return;
- case 4:
- byte = length >> PACKAGE_LENGTH_4BYTE_SHIFT;
- build_prepend_byte(package, byte);
- length &= (1 << PACKAGE_LENGTH_4BYTE_SHIFT) - 1;
- /* fall through */
- case 3:
- byte = length >> PACKAGE_LENGTH_3BYTE_SHIFT;
- build_prepend_byte(package, byte);
- length &= (1 << PACKAGE_LENGTH_3BYTE_SHIFT) - 1;
- /* fall through */
- case 2:
- byte = length >> PACKAGE_LENGTH_2BYTE_SHIFT;
- build_prepend_byte(package, byte);
- length &= (1 << PACKAGE_LENGTH_2BYTE_SHIFT) - 1;
- /* fall through */
- }
- /*
- * Most significant two bits of byte zero indicate how many following bytes
- * are in PkgLength encoding.
- */
- byte = ((length_bytes - 1) << PACKAGE_LENGTH_1BYTE_SHIFT) | length;
- build_prepend_byte(package, byte);
-}
-
-static void
-build_append_pkg_length(GArray *array, unsigned length, bool incl_self)
-{
- GArray *tmp = build_alloc_array();
-
- build_prepend_package_length(tmp, length, incl_self);
- build_append_array(array, tmp);
- build_free_array(tmp);
-}
-
-static void build_package(GArray *package, uint8_t op)
-{
- build_prepend_package_length(package, package->len, true);
- build_prepend_byte(package, op);
-}
-
-static void build_extop_package(GArray *package, uint8_t op)
-{
- build_package(package, op);
- build_prepend_byte(package, 0x5B); /* ExtOpPrefix */
-}
-
-static void build_append_int_noprefix(GArray *table, uint64_t value, int size)
-{
- int i;
-
- for (i = 0; i < size; ++i) {
- build_append_byte(table, value & 0xFF);
- value = value >> 8;
- }
-}
-
-static void build_append_int(GArray *table, uint64_t value)
-{
- if (value == 0x00) {
- build_append_byte(table, 0x00); /* ZeroOp */
- } else if (value == 0x01) {
- build_append_byte(table, 0x01); /* OneOp */
- } else if (value <= 0xFF) {
- build_append_byte(table, 0x0A); /* BytePrefix */
- build_append_int_noprefix(table, value, 1);
- } else if (value <= 0xFFFF) {
- build_append_byte(table, 0x0B); /* WordPrefix */
- build_append_int_noprefix(table, value, 2);
- } else if (value <= 0xFFFFFFFF) {
- build_append_byte(table, 0x0C); /* DWordPrefix */
- build_append_int_noprefix(table, value, 4);
- } else {
- build_append_byte(table, 0x0E); /* QWordPrefix */
- build_append_int_noprefix(table, value, 8);
- }
-}
-
-/*
- * Build NAME(XXXX, 0x00000000) where 0x00000000 is encoded as a dword,
- * and return the offset to 0x00000000 for runtime patching.
- *
- * Warning: runtime patching is best avoided. Only use this as
- * a replacement for DataTableRegion (for guests that don't
- * support it).
- */
-int
-build_append_named_dword(GArray *array, const char *name_format, ...)
-{
- int offset;
- va_list ap;
-
- build_append_byte(array, 0x08); /* NameOp */
- va_start(ap, name_format);
- build_append_namestringv(array, name_format, ap);
- va_end(ap);
-
- build_append_byte(array, 0x0C); /* DWordPrefix */
-
- offset = array->len;
- build_append_int_noprefix(array, 0x00000000, 4);
- assert(array->len == offset + 4);
-
- return offset;
-}
-
-static GPtrArray *alloc_list;
-
-static Aml *aml_alloc(void)
-{
- Aml *var = g_new0(typeof(*var), 1);
-
- g_ptr_array_add(alloc_list, var);
- var->block_flags = AML_NO_OPCODE;
- var->buf = build_alloc_array();
- return var;
-}
-
-static Aml *aml_opcode(uint8_t op)
-{
- Aml *var = aml_alloc();
-
- var->op = op;
- var->block_flags = AML_OPCODE;
- return var;
-}
-
-static Aml *aml_bundle(uint8_t op, AmlBlockFlags flags)
-{
- Aml *var = aml_alloc();
-
- var->op = op;
- var->block_flags = flags;
- return var;
-}
-
-static void aml_free(gpointer data, gpointer user_data)
-{
- Aml *var = data;
- build_free_array(var->buf);
- g_free(var);
-}
-
-Aml *init_aml_allocator(void)
-{
- Aml *var;
-
- assert(!alloc_list);
- alloc_list = g_ptr_array_new();
- var = aml_alloc();
- return var;
-}
-
-void free_aml_allocator(void)
-{
- g_ptr_array_foreach(alloc_list, aml_free, NULL);
- g_ptr_array_free(alloc_list, true);
- alloc_list = 0;
-}
-
-/* pack data with DefBuffer encoding */
-static void build_buffer(GArray *array, uint8_t op)
-{
- GArray *data = build_alloc_array();
-
- build_append_int(data, array->len);
- g_array_prepend_vals(array, data->data, data->len);
- build_free_array(data);
- build_package(array, op);
-}
-
-void aml_append(Aml *parent_ctx, Aml *child)
-{
- GArray *buf = build_alloc_array();
- build_append_array(buf, child->buf);
-
- switch (child->block_flags) {
- case AML_OPCODE:
- build_append_byte(parent_ctx->buf, child->op);
- break;
- case AML_EXT_PACKAGE:
- build_extop_package(buf, child->op);
- break;
- case AML_PACKAGE:
- build_package(buf, child->op);
- break;
- case AML_RES_TEMPLATE:
- build_append_byte(buf, 0x79); /* EndTag */
- /*
- * checksum operations are treated as succeeded if checksum
- * field is zero. [ACPI Spec 1.0b, 6.4.2.8 End Tag]
- */
- build_append_byte(buf, 0);
- /* fall through, to pack resources in buffer */
- case AML_BUFFER:
- build_buffer(buf, child->op);
- break;
- case AML_NO_OPCODE:
- break;
- default:
- assert(0);
- break;
- }
- build_append_array(parent_ctx->buf, buf);
- build_free_array(buf);
-}
-
-/* ACPI 1.0b: 16.2.5.1 Namespace Modifier Objects Encoding: DefScope */
-Aml *aml_scope(const char *name_format, ...)
-{
- va_list ap;
- Aml *var = aml_bundle(0x10 /* ScopeOp */, AML_PACKAGE);
- va_start(ap, name_format);
- build_append_namestringv(var->buf, name_format, ap);
- va_end(ap);
- return var;
-}
-
-/* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefReturn */
-Aml *aml_return(Aml *val)
-{
- Aml *var = aml_opcode(0xA4 /* ReturnOp */);
- aml_append(var, val);
- return var;
-}
-
-/*
- * ACPI 1.0b: 16.2.3 Data Objects Encoding:
- * encodes: ByteConst, WordConst, DWordConst, QWordConst, ZeroOp, OneOp
- */
-Aml *aml_int(const uint64_t val)
-{
- Aml *var = aml_alloc();
- build_append_int(var->buf, val);
- return var;
-}
-
-/*
- * helper to construct NameString, which returns Aml object
- * for using with aml_append or other aml_* terms
- */
-Aml *aml_name(const char *name_format, ...)
-{
- va_list ap;
- Aml *var = aml_alloc();
- va_start(ap, name_format);
- build_append_namestringv(var->buf, name_format, ap);
- va_end(ap);
- return var;
-}
-
-/* ACPI 1.0b: 16.2.5.1 Namespace Modifier Objects Encoding: DefName */
-Aml *aml_name_decl(const char *name, Aml *val)
-{
- Aml *var = aml_opcode(0x08 /* NameOp */);
- build_append_namestring(var->buf, "%s", name);
- aml_append(var, val);
- return var;
-}
-
-/* ACPI 1.0b: 16.2.6.1 Arg Objects Encoding */
-Aml *aml_arg(int pos)
-{
- Aml *var;
- uint8_t op = 0x68 /* ARG0 op */ + pos;
-
- assert(pos <= 6);
- var = aml_opcode(op);
- return var;
-}
-
-/* ACPI 2.0a: 17.2.4.4 Type 2 Opcodes Encoding: DefToInteger */
-Aml *aml_to_integer(Aml *arg)
-{
- Aml *var = aml_opcode(0x99 /* ToIntegerOp */);
- aml_append(var, arg);
- build_append_byte(var->buf, 0x00 /* NullNameOp */);
- return var;
-}
-
-/* ACPI 2.0a: 17.2.4.4 Type 2 Opcodes Encoding: DefToHexString */
-Aml *aml_to_hexstring(Aml *src, Aml *dst)
-{
- Aml *var = aml_opcode(0x98 /* ToHexStringOp */);
- aml_append(var, src);
- if (dst) {
- aml_append(var, dst);
- } else {
- build_append_byte(var->buf, 0x00 /* NullNameOp */);
- }
- return var;
-}
-
-/* ACPI 2.0a: 17.2.4.4 Type 2 Opcodes Encoding: DefToBuffer */
-Aml *aml_to_buffer(Aml *src, Aml *dst)
-{
- Aml *var = aml_opcode(0x96 /* ToBufferOp */);
- aml_append(var, src);
- if (dst) {
- aml_append(var, dst);
- } else {
- build_append_byte(var->buf, 0x00 /* NullNameOp */);
- }
- return var;
-}
-
-/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefStore */
-Aml *aml_store(Aml *val, Aml *target)
-{
- Aml *var = aml_opcode(0x70 /* StoreOp */);
- aml_append(var, val);
- aml_append(var, target);
- return var;
-}
-
-/**
- * build_opcode_2arg_dst:
- * @op: 1-byte opcode
- * @arg1: 1st operand
- * @arg2: 2nd operand
- * @dst: optional target to store to, set to NULL if it's not required
- *
- * An internal helper to compose AML terms that have
- * "Op Operand Operand Target"
- * pattern.
- *
- * Returns: The newly allocated and composed according to patter Aml object.
- */
-static Aml *
-build_opcode_2arg_dst(uint8_t op, Aml *arg1, Aml *arg2, Aml *dst)
-{
- Aml *var = aml_opcode(op);
- aml_append(var, arg1);
- aml_append(var, arg2);
- if (dst) {
- aml_append(var, dst);
- } else {
- build_append_byte(var->buf, 0x00 /* NullNameOp */);
- }
- return var;
-}
-
-/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefAnd */
-Aml *aml_and(Aml *arg1, Aml *arg2, Aml *dst)
-{
- return build_opcode_2arg_dst(0x7B /* AndOp */, arg1, arg2, dst);
-}
-
-/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefOr */
-Aml *aml_or(Aml *arg1, Aml *arg2, Aml *dst)
-{
- return build_opcode_2arg_dst(0x7D /* OrOp */, arg1, arg2, dst);
-}
-
-/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefLOr */
-Aml *aml_lor(Aml *arg1, Aml *arg2)
-{
- Aml *var = aml_opcode(0x91 /* LOrOp */);
- aml_append(var, arg1);
- aml_append(var, arg2);
- return var;
-}
-
-/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefShiftLeft */
-Aml *aml_shiftleft(Aml *arg1, Aml *count)
-{
- return build_opcode_2arg_dst(0x79 /* ShiftLeftOp */, arg1, count, NULL);
-}
-
-/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefShiftRight */
-Aml *aml_shiftright(Aml *arg1, Aml *count, Aml *dst)
-{
- return build_opcode_2arg_dst(0x7A /* ShiftRightOp */, arg1, count, dst);
-}
-
-/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefLLess */
-Aml *aml_lless(Aml *arg1, Aml *arg2)
-{
- Aml *var = aml_opcode(0x95 /* LLessOp */);
- aml_append(var, arg1);
- aml_append(var, arg2);
- return var;
-}
-
-/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefAdd */
-Aml *aml_add(Aml *arg1, Aml *arg2, Aml *dst)
-{
- return build_opcode_2arg_dst(0x72 /* AddOp */, arg1, arg2, dst);
-}
-
-/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefSubtract */
-Aml *aml_subtract(Aml *arg1, Aml *arg2, Aml *dst)
-{
- return build_opcode_2arg_dst(0x74 /* SubtractOp */, arg1, arg2, dst);
-}
-
-/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefIncrement */
-Aml *aml_increment(Aml *arg)
-{
- Aml *var = aml_opcode(0x75 /* IncrementOp */);
- aml_append(var, arg);
- return var;
-}
-
-/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefDecrement */
-Aml *aml_decrement(Aml *arg)
-{
- Aml *var = aml_opcode(0x76 /* DecrementOp */);
- aml_append(var, arg);
- return var;
-}
-
-/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefIndex */
-Aml *aml_index(Aml *arg1, Aml *idx)
-{
- return build_opcode_2arg_dst(0x88 /* IndexOp */, arg1, idx, NULL);
-}
-
-/* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefNotify */
-Aml *aml_notify(Aml *arg1, Aml *arg2)
-{
- Aml *var = aml_opcode(0x86 /* NotifyOp */);
- aml_append(var, arg1);
- aml_append(var, arg2);
- return var;
-}
-
-/* helper to call method with 1 argument */
-Aml *aml_call0(const char *method)
-{
- Aml *var = aml_alloc();
- build_append_namestring(var->buf, "%s", method);
- return var;
-}
-
-/* helper to call method with 1 argument */
-Aml *aml_call1(const char *method, Aml *arg1)
-{
- Aml *var = aml_alloc();
- build_append_namestring(var->buf, "%s", method);
- aml_append(var, arg1);
- return var;
-}
-
-/* helper to call method with 2 arguments */
-Aml *aml_call2(const char *method, Aml *arg1, Aml *arg2)
-{
- Aml *var = aml_alloc();
- build_append_namestring(var->buf, "%s", method);
- aml_append(var, arg1);
- aml_append(var, arg2);
- return var;
-}
-
-/* helper to call method with 3 arguments */
-Aml *aml_call3(const char *method, Aml *arg1, Aml *arg2, Aml *arg3)
-{
- Aml *var = aml_alloc();
- build_append_namestring(var->buf, "%s", method);
- aml_append(var, arg1);
- aml_append(var, arg2);
- aml_append(var, arg3);
- return var;
-}
-
-/* helper to call method with 4 arguments */
-Aml *aml_call4(const char *method, Aml *arg1, Aml *arg2, Aml *arg3, Aml *arg4)
-{
- Aml *var = aml_alloc();
- build_append_namestring(var->buf, "%s", method);
- aml_append(var, arg1);
- aml_append(var, arg2);
- aml_append(var, arg3);
- aml_append(var, arg4);
- return var;
-}
-
-/*
- * ACPI 5.0: 6.4.3.8.1 GPIO Connection Descriptor
- * Type 1, Large Item Name 0xC
- */
-
-static Aml *aml_gpio_connection(AmlGpioConnectionType type,
- AmlConsumerAndProducer con_and_pro,
- uint8_t flags, AmlPinConfig pin_config,
- uint16_t output_drive,
- uint16_t debounce_timeout,
- const uint32_t pin_list[], uint32_t pin_count,
- const char *resource_source_name,
- const uint8_t *vendor_data,
- uint16_t vendor_data_len)
-{
- Aml *var = aml_alloc();
- const uint16_t min_desc_len = 0x16;
- uint16_t resource_source_name_len, length;
- uint16_t pin_table_offset, resource_source_name_offset, vendor_data_offset;
- uint32_t i;
-
- assert(resource_source_name);
- resource_source_name_len = strlen(resource_source_name) + 1;
- length = min_desc_len + resource_source_name_len + vendor_data_len;
- pin_table_offset = min_desc_len + 1;
- resource_source_name_offset = pin_table_offset + pin_count * 2;
- vendor_data_offset = resource_source_name_offset + resource_source_name_len;
-
- build_append_byte(var->buf, 0x8C); /* GPIO Connection Descriptor */
- build_append_int_noprefix(var->buf, length, 2); /* Length */
- build_append_byte(var->buf, 1); /* Revision ID */
- build_append_byte(var->buf, type); /* GPIO Connection Type */
- /* General Flags (2 bytes) */
- build_append_int_noprefix(var->buf, con_and_pro, 2);
- /* Interrupt and IO Flags (2 bytes) */
- build_append_int_noprefix(var->buf, flags, 2);
- /* Pin Configuration 0 = Default 1 = Pull-up 2 = Pull-down 3 = No Pull */
- build_append_byte(var->buf, pin_config);
- /* Output Drive Strength (2 bytes) */
- build_append_int_noprefix(var->buf, output_drive, 2);
- /* Debounce Timeout (2 bytes) */
- build_append_int_noprefix(var->buf, debounce_timeout, 2);
- /* Pin Table Offset (2 bytes) */
- build_append_int_noprefix(var->buf, pin_table_offset, 2);
- build_append_byte(var->buf, 0); /* Resource Source Index */
- /* Resource Source Name Offset (2 bytes) */
- build_append_int_noprefix(var->buf, resource_source_name_offset, 2);
- /* Vendor Data Offset (2 bytes) */
- build_append_int_noprefix(var->buf, vendor_data_offset, 2);
- /* Vendor Data Length (2 bytes) */
- build_append_int_noprefix(var->buf, vendor_data_len, 2);
- /* Pin Number (2n bytes)*/
- for (i = 0; i < pin_count; i++) {
- build_append_int_noprefix(var->buf, pin_list[i], 2);
- }
-
- /* Resource Source Name */
- build_append_namestring(var->buf, "%s", resource_source_name);
- build_append_byte(var->buf, '\0');
-
- /* Vendor-defined Data */
- if (vendor_data != NULL) {
- g_array_append_vals(var->buf, vendor_data, vendor_data_len);
- }
-
- return var;
-}
-
-/*
- * ACPI 5.0: 19.5.53
- * GpioInt(GPIO Interrupt Connection Resource Descriptor Macro)
- */
-Aml *aml_gpio_int(AmlConsumerAndProducer con_and_pro,
- AmlLevelAndEdge edge_level,
- AmlActiveHighAndLow active_level, AmlShared shared,
- AmlPinConfig pin_config, uint16_t debounce_timeout,
- const uint32_t pin_list[], uint32_t pin_count,
- const char *resource_source_name,
- const uint8_t *vendor_data, uint16_t vendor_data_len)
-{
- uint8_t flags = edge_level | (active_level << 1) | (shared << 3);
-
- return aml_gpio_connection(AML_INTERRUPT_CONNECTION, con_and_pro, flags,
- pin_config, 0, debounce_timeout, pin_list,
- pin_count, resource_source_name, vendor_data,
- vendor_data_len);
-}
-
-/*
- * ACPI 1.0b: 6.4.3.4 32-Bit Fixed Location Memory Range Descriptor
- * (Type 1, Large Item Name 0x6)
- */
-Aml *aml_memory32_fixed(uint32_t addr, uint32_t size,
- AmlReadAndWrite read_and_write)
-{
- Aml *var = aml_alloc();
- build_append_byte(var->buf, 0x86); /* Memory32Fixed Resource Descriptor */
- build_append_byte(var->buf, 9); /* Length, bits[7:0] value = 9 */
- build_append_byte(var->buf, 0); /* Length, bits[15:8] value = 0 */
- build_append_byte(var->buf, read_and_write); /* Write status, 1 rw 0 ro */
-
- /* Range base address */
- build_append_byte(var->buf, extract32(addr, 0, 8)); /* bits[7:0] */
- build_append_byte(var->buf, extract32(addr, 8, 8)); /* bits[15:8] */
- build_append_byte(var->buf, extract32(addr, 16, 8)); /* bits[23:16] */
- build_append_byte(var->buf, extract32(addr, 24, 8)); /* bits[31:24] */
-
- /* Range length */
- build_append_byte(var->buf, extract32(size, 0, 8)); /* bits[7:0] */
- build_append_byte(var->buf, extract32(size, 8, 8)); /* bits[15:8] */
- build_append_byte(var->buf, extract32(size, 16, 8)); /* bits[23:16] */
- build_append_byte(var->buf, extract32(size, 24, 8)); /* bits[31:24] */
- return var;
-}
-
-/*
- * ACPI 5.0: 6.4.3.6 Extended Interrupt Descriptor
- * Type 1, Large Item Name 0x9
- */
-Aml *aml_interrupt(AmlConsumerAndProducer con_and_pro,
- AmlLevelAndEdge level_and_edge,
- AmlActiveHighAndLow high_and_low, AmlShared shared,
- uint32_t *irq_list, uint8_t irq_count)
-{
- int i;
- Aml *var = aml_alloc();
- uint8_t irq_flags = con_and_pro | (level_and_edge << 1)
- | (high_and_low << 2) | (shared << 3);
- const int header_bytes_in_len = 2;
- uint16_t len = header_bytes_in_len + irq_count * sizeof(uint32_t);
-
- assert(irq_count > 0);
-
- build_append_byte(var->buf, 0x89); /* Extended irq descriptor */
- build_append_byte(var->buf, len & 0xFF); /* Length, bits[7:0] */
- build_append_byte(var->buf, len >> 8); /* Length, bits[15:8] */
- build_append_byte(var->buf, irq_flags); /* Interrupt Vector Information. */
- build_append_byte(var->buf, irq_count); /* Interrupt table length */
-
- /* Interrupt Number List */
- for (i = 0; i < irq_count; i++) {
- build_append_int_noprefix(var->buf, irq_list[i], 4);
- }
- return var;
-}
-
-/* ACPI 1.0b: 6.4.2.5 I/O Port Descriptor */
-Aml *aml_io(AmlIODecode dec, uint16_t min_base, uint16_t max_base,
- uint8_t aln, uint8_t len)
-{
- Aml *var = aml_alloc();
- build_append_byte(var->buf, 0x47); /* IO port descriptor */
- build_append_byte(var->buf, dec);
- build_append_byte(var->buf, min_base & 0xff);
- build_append_byte(var->buf, (min_base >> 8) & 0xff);
- build_append_byte(var->buf, max_base & 0xff);
- build_append_byte(var->buf, (max_base >> 8) & 0xff);
- build_append_byte(var->buf, aln);
- build_append_byte(var->buf, len);
- return var;
-}
-
-/*
- * ACPI 1.0b: 6.4.2.1.1 ASL Macro for IRQ Descriptor
- *
- * More verbose description at:
- * ACPI 5.0: 19.5.64 IRQNoFlags (Interrupt Resource Descriptor Macro)
- * 6.4.2.1 IRQ Descriptor
- */
-Aml *aml_irq_no_flags(uint8_t irq)
-{
- uint16_t irq_mask;
- Aml *var = aml_alloc();
-
- assert(irq < 16);
- build_append_byte(var->buf, 0x22); /* IRQ descriptor 2 byte form */
-
- irq_mask = 1U << irq;
- build_append_byte(var->buf, irq_mask & 0xFF); /* IRQ mask bits[7:0] */
- build_append_byte(var->buf, irq_mask >> 8); /* IRQ mask bits[15:8] */
- return var;
-}
-
-/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefLNot */
-Aml *aml_lnot(Aml *arg)
-{
- Aml *var = aml_opcode(0x92 /* LNotOp */);
- aml_append(var, arg);
- return var;
-}
-
-/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefLEqual */
-Aml *aml_equal(Aml *arg1, Aml *arg2)
-{
- Aml *var = aml_opcode(0x93 /* LequalOp */);
- aml_append(var, arg1);
- aml_append(var, arg2);
- return var;
-}
-
-/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefLGreater */
-Aml *aml_lgreater(Aml *arg1, Aml *arg2)
-{
- Aml *var = aml_opcode(0x94 /* LGreaterOp */);
- aml_append(var, arg1);
- aml_append(var, arg2);
- return var;
-}
-
-/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefLGreaterEqual */
-Aml *aml_lgreater_equal(Aml *arg1, Aml *arg2)
-{
- /* LGreaterEqualOp := LNotOp LLessOp */
- Aml *var = aml_opcode(0x92 /* LNotOp */);
- build_append_byte(var->buf, 0x95 /* LLessOp */);
- aml_append(var, arg1);
- aml_append(var, arg2);
- return var;
-}
-
-/* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefIfElse */
-Aml *aml_if(Aml *predicate)
-{
- Aml *var = aml_bundle(0xA0 /* IfOp */, AML_PACKAGE);
- aml_append(var, predicate);
- return var;
-}
-
-/* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefElse */
-Aml *aml_else(void)
-{
- Aml *var = aml_bundle(0xA1 /* ElseOp */, AML_PACKAGE);
- return var;
-}
-
-/* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefWhile */
-Aml *aml_while(Aml *predicate)
-{
- Aml *var = aml_bundle(0xA2 /* WhileOp */, AML_PACKAGE);
- aml_append(var, predicate);
- return var;
-}
-
-/* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefMethod */
-Aml *aml_method(const char *name, int arg_count, AmlSerializeFlag sflag)
-{
- Aml *var = aml_bundle(0x14 /* MethodOp */, AML_PACKAGE);
- int methodflags;
-
- /*
- * MethodFlags:
- * bit 0-2: ArgCount (0-7)
- * bit 3: SerializeFlag
- * 0: NotSerialized
- * 1: Serialized
- * bit 4-7: reserved (must be 0)
- */
- assert(arg_count < 8);
- methodflags = arg_count | (sflag << 3);
-
- build_append_namestring(var->buf, "%s", name);
- build_append_byte(var->buf, methodflags); /* MethodFlags: ArgCount */
- return var;
-}
-
-/* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefDevice */
-Aml *aml_device(const char *name_format, ...)
-{
- va_list ap;
- Aml *var = aml_bundle(0x82 /* DeviceOp */, AML_EXT_PACKAGE);
- va_start(ap, name_format);
- build_append_namestringv(var->buf, name_format, ap);
- va_end(ap);
- return var;
-}
-
-/* ACPI 1.0b: 6.4.1 ASL Macros for Resource Descriptors */
-Aml *aml_resource_template(void)
-{
- /* ResourceTemplate is a buffer of Resources with EndTag at the end */
- Aml *var = aml_bundle(0x11 /* BufferOp */, AML_RES_TEMPLATE);
- return var;
-}
-
-/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefBuffer
- * Pass byte_list as NULL to request uninitialized buffer to reserve space.
- */
-Aml *aml_buffer(int buffer_size, uint8_t *byte_list)
-{
- int i;
- Aml *var = aml_bundle(0x11 /* BufferOp */, AML_BUFFER);
-
- for (i = 0; i < buffer_size; i++) {
- if (byte_list == NULL) {
- build_append_byte(var->buf, 0x0);
- } else {
- build_append_byte(var->buf, byte_list[i]);
- }
- }
-
- return var;
-}
-
-/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefPackage */
-Aml *aml_package(uint8_t num_elements)
-{
- Aml *var = aml_bundle(0x12 /* PackageOp */, AML_PACKAGE);
- build_append_byte(var->buf, num_elements);
- return var;
-}
-
-/* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefOpRegion */
-Aml *aml_operation_region(const char *name, AmlRegionSpace rs,
- Aml *offset, uint32_t len)
-{
- Aml *var = aml_alloc();
- build_append_byte(var->buf, 0x5B); /* ExtOpPrefix */
- build_append_byte(var->buf, 0x80); /* OpRegionOp */
- build_append_namestring(var->buf, "%s", name);
- build_append_byte(var->buf, rs);
- aml_append(var, offset);
- build_append_int(var->buf, len);
- return var;
-}
-
-/* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: NamedField */
-Aml *aml_named_field(const char *name, unsigned length)
-{
- Aml *var = aml_alloc();
- build_append_nameseg(var->buf, name);
- build_append_pkg_length(var->buf, length, false);
- return var;
-}
-
-/* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: ReservedField */
-Aml *aml_reserved_field(unsigned length)
-{
- Aml *var = aml_alloc();
- /* ReservedField := 0x00 PkgLength */
- build_append_byte(var->buf, 0x00);
- build_append_pkg_length(var->buf, length, false);
- return var;
-}
-
-/* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefField */
-Aml *aml_field(const char *name, AmlAccessType type, AmlLockRule lock,
- AmlUpdateRule rule)
-{
- Aml *var = aml_bundle(0x81 /* FieldOp */, AML_EXT_PACKAGE);
- uint8_t flags = rule << 5 | type;
-
- flags |= lock << 4; /* LockRule at 4 bit offset */
-
- build_append_namestring(var->buf, "%s", name);
- build_append_byte(var->buf, flags);
- return var;
-}
-
-static
-Aml *create_field_common(int opcode, Aml *srcbuf, Aml *index, const char *name)
-{
- Aml *var = aml_opcode(opcode);
- aml_append(var, srcbuf);
- aml_append(var, index);
- build_append_namestring(var->buf, "%s", name);
- return var;
-}
-
-/* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefCreateField */
-Aml *aml_create_field(Aml *srcbuf, Aml *bit_index, Aml *num_bits,
- const char *name)
-{
- Aml *var = aml_alloc();
- build_append_byte(var->buf, 0x5B); /* ExtOpPrefix */
- build_append_byte(var->buf, 0x13); /* CreateFieldOp */
- aml_append(var, srcbuf);
- aml_append(var, bit_index);
- aml_append(var, num_bits);
- build_append_namestring(var->buf, "%s", name);
- return var;
-}
-
-/* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefCreateDWordField */
-Aml *aml_create_dword_field(Aml *srcbuf, Aml *index, const char *name)
-{
- return create_field_common(0x8A /* CreateDWordFieldOp */,
- srcbuf, index, name);
-}
-
-/* ACPI 2.0a: 17.2.4.2 Named Objects Encoding: DefCreateQWordField */
-Aml *aml_create_qword_field(Aml *srcbuf, Aml *index, const char *name)
-{
- return create_field_common(0x8F /* CreateQWordFieldOp */,
- srcbuf, index, name);
-}
-
-/* ACPI 1.0b: 16.2.3 Data Objects Encoding: String */
-Aml *aml_string(const char *name_format, ...)
-{
- Aml *var = aml_opcode(0x0D /* StringPrefix */);
- va_list ap;
- char *s;
- int len;
-
- va_start(ap, name_format);
- len = g_vasprintf(&s, name_format, ap);
- va_end(ap);
-
- g_array_append_vals(var->buf, s, len + 1);
- g_free(s);
-
- return var;
-}
-
-/* ACPI 1.0b: 16.2.6.2 Local Objects Encoding */
-Aml *aml_local(int num)
-{
- Aml *var;
- uint8_t op = 0x60 /* Local0Op */ + num;
-
- assert(num <= 7);
- var = aml_opcode(op);
- return var;
-}
-
-/* ACPI 2.0a: 17.2.2 Data Objects Encoding: DefVarPackage */
-Aml *aml_varpackage(uint32_t num_elements)
-{
- Aml *var = aml_bundle(0x13 /* VarPackageOp */, AML_PACKAGE);
- build_append_int(var->buf, num_elements);
- return var;
-}
-
-/* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefProcessor */
-Aml *aml_processor(uint8_t proc_id, uint32_t pblk_addr, uint8_t pblk_len,
- const char *name_format, ...)
-{
- va_list ap;
- Aml *var = aml_bundle(0x83 /* ProcessorOp */, AML_EXT_PACKAGE);
- va_start(ap, name_format);
- build_append_namestringv(var->buf, name_format, ap);
- va_end(ap);
- build_append_byte(var->buf, proc_id); /* ProcID */
- build_append_int_noprefix(var->buf, pblk_addr, sizeof(pblk_addr));
- build_append_byte(var->buf, pblk_len); /* PblkLen */
- return var;
-}
-
-static uint8_t Hex2Digit(char c)
-{
- if (c >= 'A') {
- return c - 'A' + 10;
- }
-
- return c - '0';
-}
-
-/* ACPI 1.0b: 15.2.3.6.4.1 EISAID Macro - Convert EISA ID String To Integer */
-Aml *aml_eisaid(const char *str)
-{
- Aml *var = aml_alloc();
- uint32_t id;
-
- g_assert(strlen(str) == 7);
- id = (str[0] - 0x40) << 26 |
- (str[1] - 0x40) << 21 |
- (str[2] - 0x40) << 16 |
- Hex2Digit(str[3]) << 12 |
- Hex2Digit(str[4]) << 8 |
- Hex2Digit(str[5]) << 4 |
- Hex2Digit(str[6]);
-
- build_append_byte(var->buf, 0x0C); /* DWordPrefix */
- build_append_int_noprefix(var->buf, bswap32(id), sizeof(id));
- return var;
-}
-
-/* ACPI 1.0b: 6.4.3.5.5 Word Address Space Descriptor: bytes 3-5 */
-static Aml *aml_as_desc_header(AmlResourceType type, AmlMinFixed min_fixed,
- AmlMaxFixed max_fixed, AmlDecode dec,
- uint8_t type_flags)
-{
- uint8_t flags = max_fixed | min_fixed | dec;
- Aml *var = aml_alloc();
-
- build_append_byte(var->buf, type);
- build_append_byte(var->buf, flags);
- build_append_byte(var->buf, type_flags); /* Type Specific Flags */
- return var;
-}
-
-/* ACPI 1.0b: 6.4.3.5.5 Word Address Space Descriptor */
-static Aml *aml_word_as_desc(AmlResourceType type, AmlMinFixed min_fixed,
- AmlMaxFixed max_fixed, AmlDecode dec,
- uint16_t addr_gran, uint16_t addr_min,
- uint16_t addr_max, uint16_t addr_trans,
- uint16_t len, uint8_t type_flags)
-{
- Aml *var = aml_alloc();
-
- build_append_byte(var->buf, 0x88); /* Word Address Space Descriptor */
- /* minimum length since we do not encode optional fields */
- build_append_byte(var->buf, 0x0D);
- build_append_byte(var->buf, 0x0);
-
- aml_append(var,
- aml_as_desc_header(type, min_fixed, max_fixed, dec, type_flags));
- build_append_int_noprefix(var->buf, addr_gran, sizeof(addr_gran));
- build_append_int_noprefix(var->buf, addr_min, sizeof(addr_min));
- build_append_int_noprefix(var->buf, addr_max, sizeof(addr_max));
- build_append_int_noprefix(var->buf, addr_trans, sizeof(addr_trans));
- build_append_int_noprefix(var->buf, len, sizeof(len));
- return var;
-}
-
-/* ACPI 1.0b: 6.4.3.5.3 DWord Address Space Descriptor */
-static Aml *aml_dword_as_desc(AmlResourceType type, AmlMinFixed min_fixed,
- AmlMaxFixed max_fixed, AmlDecode dec,
- uint32_t addr_gran, uint32_t addr_min,
- uint32_t addr_max, uint32_t addr_trans,
- uint32_t len, uint8_t type_flags)
-{
- Aml *var = aml_alloc();
-
- build_append_byte(var->buf, 0x87); /* DWord Address Space Descriptor */
- /* minimum length since we do not encode optional fields */
- build_append_byte(var->buf, 23);
- build_append_byte(var->buf, 0x0);
-
-
- aml_append(var,
- aml_as_desc_header(type, min_fixed, max_fixed, dec, type_flags));
- build_append_int_noprefix(var->buf, addr_gran, sizeof(addr_gran));
- build_append_int_noprefix(var->buf, addr_min, sizeof(addr_min));
- build_append_int_noprefix(var->buf, addr_max, sizeof(addr_max));
- build_append_int_noprefix(var->buf, addr_trans, sizeof(addr_trans));
- build_append_int_noprefix(var->buf, len, sizeof(len));
- return var;
-}
-
-/* ACPI 1.0b: 6.4.3.5.1 QWord Address Space Descriptor */
-static Aml *aml_qword_as_desc(AmlResourceType type, AmlMinFixed min_fixed,
- AmlMaxFixed max_fixed, AmlDecode dec,
- uint64_t addr_gran, uint64_t addr_min,
- uint64_t addr_max, uint64_t addr_trans,
- uint64_t len, uint8_t type_flags)
-{
- Aml *var = aml_alloc();
-
- build_append_byte(var->buf, 0x8A); /* QWord Address Space Descriptor */
- /* minimum length since we do not encode optional fields */
- build_append_byte(var->buf, 0x2B);
- build_append_byte(var->buf, 0x0);
-
- aml_append(var,
- aml_as_desc_header(type, min_fixed, max_fixed, dec, type_flags));
- build_append_int_noprefix(var->buf, addr_gran, sizeof(addr_gran));
- build_append_int_noprefix(var->buf, addr_min, sizeof(addr_min));
- build_append_int_noprefix(var->buf, addr_max, sizeof(addr_max));
- build_append_int_noprefix(var->buf, addr_trans, sizeof(addr_trans));
- build_append_int_noprefix(var->buf, len, sizeof(len));
- return var;
-}
-
-/*
- * ACPI 1.0b: 6.4.3.5.6 ASL Macros for WORD Address Descriptor
- *
- * More verbose description at:
- * ACPI 5.0: 19.5.141 WordBusNumber (Word Bus Number Resource Descriptor Macro)
- */
-Aml *aml_word_bus_number(AmlMinFixed min_fixed, AmlMaxFixed max_fixed,
- AmlDecode dec, uint16_t addr_gran,
- uint16_t addr_min, uint16_t addr_max,
- uint16_t addr_trans, uint16_t len)
-
-{
- return aml_word_as_desc(AML_BUS_NUMBER_RANGE, min_fixed, max_fixed, dec,
- addr_gran, addr_min, addr_max, addr_trans, len, 0);
-}
-
-/*
- * ACPI 1.0b: 6.4.3.5.6 ASL Macros for WORD Address Descriptor
- *
- * More verbose description at:
- * ACPI 5.0: 19.5.142 WordIO (Word IO Resource Descriptor Macro)
- */
-Aml *aml_word_io(AmlMinFixed min_fixed, AmlMaxFixed max_fixed,
- AmlDecode dec, AmlISARanges isa_ranges,
- uint16_t addr_gran, uint16_t addr_min,
- uint16_t addr_max, uint16_t addr_trans,
- uint16_t len)
-
-{
- return aml_word_as_desc(AML_IO_RANGE, min_fixed, max_fixed, dec,
- addr_gran, addr_min, addr_max, addr_trans, len,
- isa_ranges);
-}
-
-/*
- * ACPI 1.0b: 6.4.3.5.4 ASL Macros for DWORD Address Descriptor
- *
- * More verbose description at:
- * ACPI 5.0: 19.5.33 DWordIO (DWord IO Resource Descriptor Macro)
- */
-Aml *aml_dword_io(AmlMinFixed min_fixed, AmlMaxFixed max_fixed,
- AmlDecode dec, AmlISARanges isa_ranges,
- uint32_t addr_gran, uint32_t addr_min,
- uint32_t addr_max, uint32_t addr_trans,
- uint32_t len)
-
-{
- return aml_dword_as_desc(AML_IO_RANGE, min_fixed, max_fixed, dec,
- addr_gran, addr_min, addr_max, addr_trans, len,
- isa_ranges);
-}
-
-/*
- * ACPI 1.0b: 6.4.3.5.4 ASL Macros for DWORD Address Space Descriptor
- *
- * More verbose description at:
- * ACPI 5.0: 19.5.34 DWordMemory (DWord Memory Resource Descriptor Macro)
- */
-Aml *aml_dword_memory(AmlDecode dec, AmlMinFixed min_fixed,
- AmlMaxFixed max_fixed, AmlCacheable cacheable,
- AmlReadAndWrite read_and_write,
- uint32_t addr_gran, uint32_t addr_min,
- uint32_t addr_max, uint32_t addr_trans,
- uint32_t len)
-{
- uint8_t flags = read_and_write | (cacheable << 1);
-
- return aml_dword_as_desc(AML_MEMORY_RANGE, min_fixed, max_fixed,
- dec, addr_gran, addr_min, addr_max,
- addr_trans, len, flags);
-}
-
-/*
- * ACPI 1.0b: 6.4.3.5.2 ASL Macros for QWORD Address Space Descriptor
- *
- * More verbose description at:
- * ACPI 5.0: 19.5.102 QWordMemory (QWord Memory Resource Descriptor Macro)
- */
-Aml *aml_qword_memory(AmlDecode dec, AmlMinFixed min_fixed,
- AmlMaxFixed max_fixed, AmlCacheable cacheable,
- AmlReadAndWrite read_and_write,
- uint64_t addr_gran, uint64_t addr_min,
- uint64_t addr_max, uint64_t addr_trans,
- uint64_t len)
-{
- uint8_t flags = read_and_write | (cacheable << 1);
-
- return aml_qword_as_desc(AML_MEMORY_RANGE, min_fixed, max_fixed,
- dec, addr_gran, addr_min, addr_max,
- addr_trans, len, flags);
-}
-
-/* ACPI 1.0b: 6.4.2.2 DMA Format/6.4.2.2.1 ASL Macro for DMA Descriptor */
-Aml *aml_dma(AmlDmaType typ, AmlDmaBusMaster bm, AmlTransferSize sz,
- uint8_t channel)
-{
- Aml *var = aml_alloc();
- uint8_t flags = sz | bm << 2 | typ << 5;
-
- assert(channel < 8);
- build_append_byte(var->buf, 0x2A); /* Byte 0: DMA Descriptor */
- build_append_byte(var->buf, 1U << channel); /* Byte 1: _DMA - DmaChannel */
- build_append_byte(var->buf, flags); /* Byte 2 */
- return var;
-}
-
-/* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefSleep */
-Aml *aml_sleep(uint64_t msec)
-{
- Aml *var = aml_alloc();
- build_append_byte(var->buf, 0x5B); /* ExtOpPrefix */
- build_append_byte(var->buf, 0x22); /* SleepOp */
- aml_append(var, aml_int(msec));
- return var;
-}
-
-static uint8_t Hex2Byte(const char *src)
-{
- int hi, lo;
-
- hi = Hex2Digit(src[0]);
- assert(hi >= 0);
- assert(hi <= 15);
-
- lo = Hex2Digit(src[1]);
- assert(lo >= 0);
- assert(lo <= 15);
- return (hi << 4) | lo;
-}
-
-/*
- * ACPI 3.0: 17.5.124 ToUUID (Convert String to UUID Macro)
- * e.g. UUID: aabbccdd-eeff-gghh-iijj-kkllmmnnoopp
- * call aml_touuid("aabbccdd-eeff-gghh-iijj-kkllmmnnoopp");
- */
-Aml *aml_touuid(const char *uuid)
-{
- Aml *var = aml_bundle(0x11 /* BufferOp */, AML_BUFFER);
-
- assert(strlen(uuid) == 36);
- assert(uuid[8] == '-');
- assert(uuid[13] == '-');
- assert(uuid[18] == '-');
- assert(uuid[23] == '-');
-
- build_append_byte(var->buf, Hex2Byte(uuid + 6)); /* dd - at offset 00 */
- build_append_byte(var->buf, Hex2Byte(uuid + 4)); /* cc - at offset 01 */
- build_append_byte(var->buf, Hex2Byte(uuid + 2)); /* bb - at offset 02 */
- build_append_byte(var->buf, Hex2Byte(uuid + 0)); /* aa - at offset 03 */
-
- build_append_byte(var->buf, Hex2Byte(uuid + 11)); /* ff - at offset 04 */
- build_append_byte(var->buf, Hex2Byte(uuid + 9)); /* ee - at offset 05 */
-
- build_append_byte(var->buf, Hex2Byte(uuid + 16)); /* hh - at offset 06 */
- build_append_byte(var->buf, Hex2Byte(uuid + 14)); /* gg - at offset 07 */
-
- build_append_byte(var->buf, Hex2Byte(uuid + 19)); /* ii - at offset 08 */
- build_append_byte(var->buf, Hex2Byte(uuid + 21)); /* jj - at offset 09 */
-
- build_append_byte(var->buf, Hex2Byte(uuid + 24)); /* kk - at offset 10 */
- build_append_byte(var->buf, Hex2Byte(uuid + 26)); /* ll - at offset 11 */
- build_append_byte(var->buf, Hex2Byte(uuid + 28)); /* mm - at offset 12 */
- build_append_byte(var->buf, Hex2Byte(uuid + 30)); /* nn - at offset 13 */
- build_append_byte(var->buf, Hex2Byte(uuid + 32)); /* oo - at offset 14 */
- build_append_byte(var->buf, Hex2Byte(uuid + 34)); /* pp - at offset 15 */
-
- return var;
-}
-
-/*
- * ACPI 2.0b: 16.2.3.6.4.3 Unicode Macro (Convert Ascii String To Unicode)
- */
-Aml *aml_unicode(const char *str)
-{
- int i = 0;
- Aml *var = aml_bundle(0x11 /* BufferOp */, AML_BUFFER);
-
- do {
- build_append_byte(var->buf, str[i]);
- build_append_byte(var->buf, 0);
- i++;
- } while (i <= strlen(str));
-
- return var;
-}
-
-/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefDerefOf */
-Aml *aml_derefof(Aml *arg)
-{
- Aml *var = aml_opcode(0x83 /* DerefOfOp */);
- aml_append(var, arg);
- return var;
-}
-
-/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefSizeOf */
-Aml *aml_sizeof(Aml *arg)
-{
- Aml *var = aml_opcode(0x87 /* SizeOfOp */);
- aml_append(var, arg);
- return var;
-}
-
-/* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefMutex */
-Aml *aml_mutex(const char *name, uint8_t sync_level)
-{
- Aml *var = aml_alloc();
- build_append_byte(var->buf, 0x5B); /* ExtOpPrefix */
- build_append_byte(var->buf, 0x01); /* MutexOp */
- build_append_namestring(var->buf, "%s", name);
- assert(!(sync_level & 0xF0));
- build_append_byte(var->buf, sync_level);
- return var;
-}
-
-/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefAcquire */
-Aml *aml_acquire(Aml *mutex, uint16_t timeout)
-{
- Aml *var = aml_alloc();
- build_append_byte(var->buf, 0x5B); /* ExtOpPrefix */
- build_append_byte(var->buf, 0x23); /* AcquireOp */
- aml_append(var, mutex);
- build_append_int_noprefix(var->buf, timeout, sizeof(timeout));
- return var;
-}
-
-/* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefRelease */
-Aml *aml_release(Aml *mutex)
-{
- Aml *var = aml_alloc();
- build_append_byte(var->buf, 0x5B); /* ExtOpPrefix */
- build_append_byte(var->buf, 0x27); /* ReleaseOp */
- aml_append(var, mutex);
- return var;
-}
-
-/* ACPI 1.0b: 16.2.5.1 Name Space Modifier Objects Encoding: DefAlias */
-Aml *aml_alias(const char *source_object, const char *alias_object)
-{
- Aml *var = aml_opcode(0x06 /* AliasOp */);
- aml_append(var, aml_name("%s", source_object));
- aml_append(var, aml_name("%s", alias_object));
- return var;
-}
-
-/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefConcat */
-Aml *aml_concatenate(Aml *source1, Aml *source2, Aml *target)
-{
- return build_opcode_2arg_dst(0x73 /* ConcatOp */, source1, source2,
- target);
-}
-
-void
-build_header(GArray *linker, GArray *table_data,
- AcpiTableHeader *h, const char *sig, int len, uint8_t rev,
- const char *oem_id, const char *oem_table_id)
-{
- memcpy(&h->signature, sig, 4);
- h->length = cpu_to_le32(len);
- h->revision = rev;
-
- if (oem_id) {
- strncpy((char *)h->oem_id, oem_id, sizeof h->oem_id);
- } else {
- memcpy(h->oem_id, ACPI_BUILD_APPNAME6, 6);
- }
-
- if (oem_table_id) {
- strncpy((char *)h->oem_table_id, oem_table_id, sizeof(h->oem_table_id));
- } else {
- memcpy(h->oem_table_id, ACPI_BUILD_APPNAME4, 4);
- memcpy(h->oem_table_id + 4, sig, 4);
- }
-
- h->oem_revision = cpu_to_le32(1);
- memcpy(h->asl_compiler_id, ACPI_BUILD_APPNAME4, 4);
- h->asl_compiler_revision = cpu_to_le32(1);
- h->checksum = 0;
- /* Checksum to be filled in by Guest linker */
- bios_linker_loader_add_checksum(linker, ACPI_BUILD_TABLE_FILE,
- table_data, h, len, &h->checksum);
-}
-
-void *acpi_data_push(GArray *table_data, unsigned size)
-{
- unsigned off = table_data->len;
- g_array_set_size(table_data, off + size);
- return table_data->data + off;
-}
-
-unsigned acpi_data_len(GArray *table)
-{
- assert(g_array_get_element_size(table) == 1);
- return table->len;
-}
-
-void acpi_add_table(GArray *table_offsets, GArray *table_data)
-{
- uint32_t offset = cpu_to_le32(table_data->len);
- g_array_append_val(table_offsets, offset);
-}
-
-void acpi_build_tables_init(AcpiBuildTables *tables)
-{
- tables->rsdp = g_array_new(false, true /* clear */, 1);
- tables->table_data = g_array_new(false, true /* clear */, 1);
- tables->tcpalog = g_array_new(false, true /* clear */, 1);
- tables->linker = bios_linker_loader_init();
-}
-
-void acpi_build_tables_cleanup(AcpiBuildTables *tables, bool mfre)
-{
- void *linker_data = bios_linker_loader_cleanup(tables->linker);
- g_free(linker_data);
- g_array_free(tables->rsdp, true);
- g_array_free(tables->table_data, true);
- g_array_free(tables->tcpalog, mfre);
-}
-
-/* Build rsdt table */
-void
-build_rsdt(GArray *table_data, GArray *linker, GArray *table_offsets,
- const char *oem_id, const char *oem_table_id)
-{
- AcpiRsdtDescriptorRev1 *rsdt;
- size_t rsdt_len;
- int i;
- const int table_data_len = (sizeof(uint32_t) * table_offsets->len);
-
- rsdt_len = sizeof(*rsdt) + table_data_len;
- rsdt = acpi_data_push(table_data, rsdt_len);
- memcpy(rsdt->table_offset_entry, table_offsets->data, table_data_len);
- for (i = 0; i < table_offsets->len; ++i) {
- /* rsdt->table_offset_entry to be filled by Guest linker */
- bios_linker_loader_add_pointer(linker,
- ACPI_BUILD_TABLE_FILE,
- ACPI_BUILD_TABLE_FILE,
- table_data, &rsdt->table_offset_entry[i],
- sizeof(uint32_t));
- }
- build_header(linker, table_data,
- (void *)rsdt, "RSDT", rsdt_len, 1, oem_id, oem_table_id);
-}
diff --git a/qemu/hw/acpi/bios-linker-loader.c b/qemu/hw/acpi/bios-linker-loader.c
deleted file mode 100644
index 5153ab151..000000000
--- a/qemu/hw/acpi/bios-linker-loader.c
+++ /dev/null
@@ -1,240 +0,0 @@
-/* Dynamic linker/loader of ACPI tables
- *
- * Copyright (C) 2013 Red Hat Inc
- *
- * Author: Michael S. Tsirkin <mst@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "hw/acpi/bios-linker-loader.h"
-#include "hw/nvram/fw_cfg.h"
-
-#include "qemu/bswap.h"
-
-/*
- * Linker/loader is a paravirtualized interface that passes commands to guest.
- * The commands can be used to request guest to
- * - allocate memory chunks and initialize them from QEMU FW CFG files
- * - link allocated chunks by storing pointer to one chunk into another
- * - calculate ACPI checksum of part of the chunk and store into same chunk
- */
-#define BIOS_LINKER_LOADER_FILESZ FW_CFG_MAX_FILE_PATH
-
-struct BiosLinkerLoaderEntry {
- uint32_t command;
- union {
- /*
- * COMMAND_ALLOCATE - allocate a table from @alloc.file
- * subject to @alloc.align alignment (must be power of 2)
- * and @alloc.zone (can be HIGH or FSEG) requirements.
- *
- * Must appear exactly once for each file, and before
- * this file is referenced by any other command.
- */
- struct {
- char file[BIOS_LINKER_LOADER_FILESZ];
- uint32_t align;
- uint8_t zone;
- } alloc;
-
- /*
- * COMMAND_ADD_POINTER - patch the table (originating from
- * @dest_file) at @pointer.offset, by adding a pointer to the table
- * originating from @src_file. 1,2,4 or 8 byte unsigned
- * addition is used depending on @pointer.size.
- */
- struct {
- char dest_file[BIOS_LINKER_LOADER_FILESZ];
- char src_file[BIOS_LINKER_LOADER_FILESZ];
- uint32_t offset;
- uint8_t size;
- } pointer;
-
- /*
- * COMMAND_ADD_CHECKSUM - calculate checksum of the range specified by
- * @cksum_start and @cksum_length fields,
- * and then add the value at @cksum.offset.
- * Checksum simply sums -X for each byte X in the range
- * using 8-bit math.
- */
- struct {
- char file[BIOS_LINKER_LOADER_FILESZ];
- uint32_t offset;
- uint32_t start;
- uint32_t length;
- } cksum;
-
- /* padding */
- char pad[124];
- };
-} QEMU_PACKED;
-typedef struct BiosLinkerLoaderEntry BiosLinkerLoaderEntry;
-
-enum {
- BIOS_LINKER_LOADER_COMMAND_ALLOCATE = 0x1,
- BIOS_LINKER_LOADER_COMMAND_ADD_POINTER = 0x2,
- BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM = 0x3,
-};
-
-enum {
- BIOS_LINKER_LOADER_ALLOC_ZONE_HIGH = 0x1,
- BIOS_LINKER_LOADER_ALLOC_ZONE_FSEG = 0x2,
-};
-
-/*
- * bios_linker_loader_init: allocate a new linker file blob array.
- *
- * After initialization, linker commands can be added, and will
- * be stored in the array.
- */
-GArray *bios_linker_loader_init(void)
-{
- return g_array_new(false, true /* clear */, 1);
-}
-
-/* Free linker wrapper and return the linker array. */
-void *bios_linker_loader_cleanup(GArray *linker)
-{
- return g_array_free(linker, false);
-}
-
-/*
- * bios_linker_loader_alloc: ask guest to load file into guest memory.
- *
- * @linker: linker file blob array
- * @file: file to be loaded
- * @alloc_align: required minimal alignment in bytes. Must be a power of 2.
- * @alloc_fseg: request allocation in FSEG zone (useful for the RSDP ACPI table)
- *
- * Note: this command must precede any other linker command using this file.
- */
-void bios_linker_loader_alloc(GArray *linker,
- const char *file,
- uint32_t alloc_align,
- bool alloc_fseg)
-{
- BiosLinkerLoaderEntry entry;
-
- assert(!(alloc_align & (alloc_align - 1)));
-
- memset(&entry, 0, sizeof entry);
- strncpy(entry.alloc.file, file, sizeof entry.alloc.file - 1);
- entry.command = cpu_to_le32(BIOS_LINKER_LOADER_COMMAND_ALLOCATE);
- entry.alloc.align = cpu_to_le32(alloc_align);
- entry.alloc.zone = alloc_fseg ? BIOS_LINKER_LOADER_ALLOC_ZONE_FSEG :
- BIOS_LINKER_LOADER_ALLOC_ZONE_HIGH;
-
- /* Alloc entries must come first, so prepend them */
- g_array_prepend_vals(linker, &entry, sizeof entry);
-}
-
-/*
- * bios_linker_loader_add_checksum: ask guest to add checksum of file data
- * into (same) file at the specified pointer.
- *
- * Checksum calculation simply sums -X for each byte X in the range
- * using 8-bit math (i.e. ACPI checksum).
- *
- * @linker: linker file blob array
- * @file: file that includes the checksum to be calculated
- * and the data to be checksummed
- * @table: @file blob contents
- * @start, @size: range of data to checksum
- * @checksum: location of the checksum to be patched within file blob
- *
- * Notes:
- * - checksum byte initial value must have been pushed into @table
- * and reside at address @checksum.
- * - @size bytes must have been pushed into @table and reside at address
- * @start.
- * - Guest calculates checksum of specified range of data, result is added to
- * initial value at @checksum into copy of @file in Guest memory.
- * - Range might include the checksum itself.
- * - To avoid confusion, caller must always put 0x0 at @checksum.
- * - @file must be loaded into Guest memory using bios_linker_loader_alloc
- */
-void bios_linker_loader_add_checksum(GArray *linker, const char *file,
- GArray *table,
- void *start, unsigned size,
- uint8_t *checksum)
-{
- BiosLinkerLoaderEntry entry;
- ptrdiff_t checksum_offset = (gchar *)checksum - table->data;
- ptrdiff_t start_offset = (gchar *)start - table->data;
-
- assert(checksum_offset >= 0);
- assert(start_offset >= 0);
- assert(checksum_offset + 1 <= table->len);
- assert(start_offset + size <= table->len);
- assert(*checksum == 0x0);
-
- memset(&entry, 0, sizeof entry);
- strncpy(entry.cksum.file, file, sizeof entry.cksum.file - 1);
- entry.command = cpu_to_le32(BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM);
- entry.cksum.offset = cpu_to_le32(checksum_offset);
- entry.cksum.start = cpu_to_le32(start_offset);
- entry.cksum.length = cpu_to_le32(size);
-
- g_array_append_vals(linker, &entry, sizeof entry);
-}
-
-/*
- * bios_linker_loader_add_pointer: ask guest to add address of source file
- * into destination file at the specified pointer.
- *
- * @linker: linker file blob array
- * @dest_file: destination file that must be changed
- * @src_file: source file who's address must be taken
- * @table: @dest_file blob contents array
- * @pointer: location of the pointer to be patched within destination file blob
- * @pointer_size: size of pointer to be patched, in bytes
- *
- * Notes:
- * - @pointer_size bytes must have been pushed into @table
- * and reside at address @pointer.
- * - Guest address is added to initial value at @pointer
- * into copy of @dest_file in Guest memory.
- * e.g. to get start of src_file in guest memory, put 0x0 there
- * to get address of a field at offset 0x10 in src_file, put 0x10 there
- * - Both @dest_file and @src_file must be
- * loaded into Guest memory using bios_linker_loader_alloc
- */
-void bios_linker_loader_add_pointer(GArray *linker,
- const char *dest_file,
- const char *src_file,
- GArray *table, void *pointer,
- uint8_t pointer_size)
-{
- BiosLinkerLoaderEntry entry;
- ptrdiff_t offset = (gchar *)pointer - table->data;
-
- assert(offset >= 0);
- assert(offset + pointer_size <= table->len);
-
- memset(&entry, 0, sizeof entry);
- strncpy(entry.pointer.dest_file, dest_file,
- sizeof entry.pointer.dest_file - 1);
- strncpy(entry.pointer.src_file, src_file,
- sizeof entry.pointer.src_file - 1);
- entry.command = cpu_to_le32(BIOS_LINKER_LOADER_COMMAND_ADD_POINTER);
- entry.pointer.offset = cpu_to_le32(offset);
- entry.pointer.size = pointer_size;
- assert(pointer_size == 1 || pointer_size == 2 ||
- pointer_size == 4 || pointer_size == 8);
-
- g_array_append_vals(linker, &entry, sizeof entry);
-}
diff --git a/qemu/hw/acpi/core.c b/qemu/hw/acpi/core.c
deleted file mode 100644
index 6a2f45214..000000000
--- a/qemu/hw/acpi/core.c
+++ /dev/null
@@ -1,717 +0,0 @@
-/*
- * ACPI implementation
- *
- * Copyright (c) 2006 Fabrice Bellard
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2 as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-#include "qemu/osdep.h"
-#include "sysemu/sysemu.h"
-#include "hw/hw.h"
-#include "hw/i386/pc.h"
-#include "hw/acpi/acpi.h"
-#include "hw/nvram/fw_cfg.h"
-#include "qemu/config-file.h"
-#include "qapi/opts-visitor.h"
-#include "qapi-visit.h"
-#include "qapi-event.h"
-
-struct acpi_table_header {
- uint16_t _length; /* our length, not actual part of the hdr */
- /* allows easier parsing for fw_cfg clients */
- char sig[4]; /* ACPI signature (4 ASCII characters) */
- uint32_t length; /* Length of table, in bytes, including header */
- uint8_t revision; /* ACPI Specification minor version # */
- uint8_t checksum; /* To make sum of entire table == 0 */
- char oem_id[6]; /* OEM identification */
- char oem_table_id[8]; /* OEM table identification */
- uint32_t oem_revision; /* OEM revision number */
- char asl_compiler_id[4]; /* ASL compiler vendor ID */
- uint32_t asl_compiler_revision; /* ASL compiler revision number */
-} QEMU_PACKED;
-
-#define ACPI_TABLE_HDR_SIZE sizeof(struct acpi_table_header)
-#define ACPI_TABLE_PFX_SIZE sizeof(uint16_t) /* size of the extra prefix */
-
-static const char unsigned dfl_hdr[ACPI_TABLE_HDR_SIZE - ACPI_TABLE_PFX_SIZE] =
- "QEMU\0\0\0\0\1\0" /* sig (4), len(4), revno (1), csum (1) */
- "QEMUQEQEMUQEMU\1\0\0\0" /* OEM id (6), table (8), revno (4) */
- "QEMU\1\0\0\0" /* ASL compiler ID (4), version (4) */
- ;
-
-char unsigned *acpi_tables;
-size_t acpi_tables_len;
-
-static QemuOptsList qemu_acpi_opts = {
- .name = "acpi",
- .implied_opt_name = "data",
- .head = QTAILQ_HEAD_INITIALIZER(qemu_acpi_opts.head),
- .desc = { { 0 } } /* validated with OptsVisitor */
-};
-
-static void acpi_register_config(void)
-{
- qemu_add_opts(&qemu_acpi_opts);
-}
-
-opts_init(acpi_register_config);
-
-static int acpi_checksum(const uint8_t *data, int len)
-{
- int sum, i;
- sum = 0;
- for (i = 0; i < len; i++) {
- sum += data[i];
- }
- return (-sum) & 0xff;
-}
-
-
-/* Install a copy of the ACPI table specified in @blob.
- *
- * If @has_header is set, @blob starts with the System Description Table Header
- * structure. Otherwise, "dfl_hdr" is prepended. In any case, each header field
- * is optionally overwritten from @hdrs.
- *
- * It is valid to call this function with
- * (@blob == NULL && bloblen == 0 && !has_header).
- *
- * @hdrs->file and @hdrs->data are ignored.
- *
- * SIZE_MAX is considered "infinity" in this function.
- *
- * The number of tables that can be installed is not limited, but the 16-bit
- * counter at the beginning of "acpi_tables" wraps around after UINT16_MAX.
- */
-static void acpi_table_install(const char unsigned *blob, size_t bloblen,
- bool has_header,
- const struct AcpiTableOptions *hdrs,
- Error **errp)
-{
- size_t body_start;
- const char unsigned *hdr_src;
- size_t body_size, acpi_payload_size;
- struct acpi_table_header *ext_hdr;
- unsigned changed_fields;
-
- /* Calculate where the ACPI table body starts within the blob, plus where
- * to copy the ACPI table header from.
- */
- if (has_header) {
- /* _length | ACPI header in blob | blob body
- * ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^
- * ACPI_TABLE_PFX_SIZE sizeof dfl_hdr body_size
- * == body_start
- *
- * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- * acpi_payload_size == bloblen
- */
- body_start = sizeof dfl_hdr;
-
- if (bloblen < body_start) {
- error_setg(errp, "ACPI table claiming to have header is too "
- "short, available: %zu, expected: %zu", bloblen,
- body_start);
- return;
- }
- hdr_src = blob;
- } else {
- /* _length | ACPI header in template | blob body
- * ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^
- * ACPI_TABLE_PFX_SIZE sizeof dfl_hdr body_size
- * == bloblen
- *
- * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- * acpi_payload_size
- */
- body_start = 0;
- hdr_src = dfl_hdr;
- }
- body_size = bloblen - body_start;
- acpi_payload_size = sizeof dfl_hdr + body_size;
-
- if (acpi_payload_size > UINT16_MAX) {
- error_setg(errp, "ACPI table too big, requested: %zu, max: %u",
- acpi_payload_size, (unsigned)UINT16_MAX);
- return;
- }
-
- /* We won't fail from here on. Initialize / extend the globals. */
- if (acpi_tables == NULL) {
- acpi_tables_len = sizeof(uint16_t);
- acpi_tables = g_malloc0(acpi_tables_len);
- }
-
- acpi_tables = g_realloc(acpi_tables, acpi_tables_len +
- ACPI_TABLE_PFX_SIZE +
- sizeof dfl_hdr + body_size);
-
- ext_hdr = (struct acpi_table_header *)(acpi_tables + acpi_tables_len);
- acpi_tables_len += ACPI_TABLE_PFX_SIZE;
-
- memcpy(acpi_tables + acpi_tables_len, hdr_src, sizeof dfl_hdr);
- acpi_tables_len += sizeof dfl_hdr;
-
- if (blob != NULL) {
- memcpy(acpi_tables + acpi_tables_len, blob + body_start, body_size);
- acpi_tables_len += body_size;
- }
-
- /* increase number of tables */
- stw_le_p(acpi_tables, lduw_le_p(acpi_tables) + 1u);
-
- /* Update the header fields. The strings need not be NUL-terminated. */
- changed_fields = 0;
- ext_hdr->_length = cpu_to_le16(acpi_payload_size);
-
- if (hdrs->has_sig) {
- strncpy(ext_hdr->sig, hdrs->sig, sizeof ext_hdr->sig);
- ++changed_fields;
- }
-
- if (has_header && le32_to_cpu(ext_hdr->length) != acpi_payload_size) {
- fprintf(stderr,
- "warning: ACPI table has wrong length, header says "
- "%" PRIu32 ", actual size %zu bytes\n",
- le32_to_cpu(ext_hdr->length), acpi_payload_size);
- }
- ext_hdr->length = cpu_to_le32(acpi_payload_size);
-
- if (hdrs->has_rev) {
- ext_hdr->revision = hdrs->rev;
- ++changed_fields;
- }
-
- ext_hdr->checksum = 0;
-
- if (hdrs->has_oem_id) {
- strncpy(ext_hdr->oem_id, hdrs->oem_id, sizeof ext_hdr->oem_id);
- ++changed_fields;
- }
- if (hdrs->has_oem_table_id) {
- strncpy(ext_hdr->oem_table_id, hdrs->oem_table_id,
- sizeof ext_hdr->oem_table_id);
- ++changed_fields;
- }
- if (hdrs->has_oem_rev) {
- ext_hdr->oem_revision = cpu_to_le32(hdrs->oem_rev);
- ++changed_fields;
- }
- if (hdrs->has_asl_compiler_id) {
- strncpy(ext_hdr->asl_compiler_id, hdrs->asl_compiler_id,
- sizeof ext_hdr->asl_compiler_id);
- ++changed_fields;
- }
- if (hdrs->has_asl_compiler_rev) {
- ext_hdr->asl_compiler_revision = cpu_to_le32(hdrs->asl_compiler_rev);
- ++changed_fields;
- }
-
- if (!has_header && changed_fields == 0) {
- fprintf(stderr, "warning: ACPI table: no headers are specified\n");
- }
-
- /* recalculate checksum */
- ext_hdr->checksum = acpi_checksum((const char unsigned *)ext_hdr +
- ACPI_TABLE_PFX_SIZE, acpi_payload_size);
-}
-
-void acpi_table_add(const QemuOpts *opts, Error **errp)
-{
- AcpiTableOptions *hdrs = NULL;
- Error *err = NULL;
- char **pathnames = NULL;
- char **cur;
- size_t bloblen = 0;
- char unsigned *blob = NULL;
-
- {
- OptsVisitor *ov;
-
- ov = opts_visitor_new(opts);
- visit_type_AcpiTableOptions(opts_get_visitor(ov), NULL, &hdrs, &err);
- opts_visitor_cleanup(ov);
- }
-
- if (err) {
- goto out;
- }
- if (hdrs->has_file == hdrs->has_data) {
- error_setg(&err, "'-acpitable' requires one of 'data' or 'file'");
- goto out;
- }
-
- pathnames = g_strsplit(hdrs->has_file ? hdrs->file : hdrs->data, ":", 0);
- if (pathnames == NULL || pathnames[0] == NULL) {
- error_setg(&err, "'-acpitable' requires at least one pathname");
- goto out;
- }
-
- /* now read in the data files, reallocating buffer as needed */
- for (cur = pathnames; *cur; ++cur) {
- int fd = open(*cur, O_RDONLY | O_BINARY);
-
- if (fd < 0) {
- error_setg(&err, "can't open file %s: %s", *cur, strerror(errno));
- goto out;
- }
-
- for (;;) {
- char unsigned data[8192];
- ssize_t r;
-
- r = read(fd, data, sizeof data);
- if (r == 0) {
- break;
- } else if (r > 0) {
- blob = g_realloc(blob, bloblen + r);
- memcpy(blob + bloblen, data, r);
- bloblen += r;
- } else if (errno != EINTR) {
- error_setg(&err, "can't read file %s: %s",
- *cur, strerror(errno));
- close(fd);
- goto out;
- }
- }
-
- close(fd);
- }
-
- acpi_table_install(blob, bloblen, hdrs->has_file, hdrs, &err);
-
-out:
- g_free(blob);
- g_strfreev(pathnames);
- qapi_free_AcpiTableOptions(hdrs);
-
- error_propagate(errp, err);
-}
-
-static bool acpi_table_builtin = false;
-
-void acpi_table_add_builtin(const QemuOpts *opts, Error **errp)
-{
- acpi_table_builtin = true;
- acpi_table_add(opts, errp);
-}
-
-unsigned acpi_table_len(void *current)
-{
- struct acpi_table_header *hdr = current - sizeof(hdr->_length);
- return hdr->_length;
-}
-
-static
-void *acpi_table_hdr(void *h)
-{
- struct acpi_table_header *hdr = h;
- return &hdr->sig;
-}
-
-uint8_t *acpi_table_first(void)
-{
- if (acpi_table_builtin || !acpi_tables) {
- return NULL;
- }
- return acpi_table_hdr(acpi_tables + ACPI_TABLE_PFX_SIZE);
-}
-
-uint8_t *acpi_table_next(uint8_t *current)
-{
- uint8_t *next = current + acpi_table_len(current);
-
- if (next - acpi_tables >= acpi_tables_len) {
- return NULL;
- } else {
- return acpi_table_hdr(next);
- }
-}
-
-int acpi_get_slic_oem(AcpiSlicOem *oem)
-{
- uint8_t *u;
-
- for (u = acpi_table_first(); u; u = acpi_table_next(u)) {
- struct acpi_table_header *hdr = (void *)(u - sizeof(hdr->_length));
-
- if (memcmp(hdr->sig, "SLIC", 4) == 0) {
- oem->id = hdr->oem_id;
- oem->table_id = hdr->oem_table_id;
- return 0;
- }
- }
- return -1;
-}
-
-static void acpi_notify_wakeup(Notifier *notifier, void *data)
-{
- ACPIREGS *ar = container_of(notifier, ACPIREGS, wakeup);
- WakeupReason *reason = data;
-
- switch (*reason) {
- case QEMU_WAKEUP_REASON_RTC:
- ar->pm1.evt.sts |=
- (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_RT_CLOCK_STATUS);
- break;
- case QEMU_WAKEUP_REASON_PMTIMER:
- ar->pm1.evt.sts |=
- (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_TIMER_STATUS);
- break;
- case QEMU_WAKEUP_REASON_OTHER:
- /* ACPI_BITMASK_WAKE_STATUS should be set on resume.
- Pretend that resume was caused by power button */
- ar->pm1.evt.sts |=
- (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_POWER_BUTTON_STATUS);
- break;
- default:
- break;
- }
-}
-
-/* ACPI PM1a EVT */
-uint16_t acpi_pm1_evt_get_sts(ACPIREGS *ar)
-{
- /* Compare ns-clock, not PM timer ticks, because
- acpi_pm_tmr_update function uses ns for setting the timer. */
- int64_t d = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- if (d >= muldiv64(ar->tmr.overflow_time,
- NANOSECONDS_PER_SECOND, PM_TIMER_FREQUENCY)) {
- ar->pm1.evt.sts |= ACPI_BITMASK_TIMER_STATUS;
- }
- return ar->pm1.evt.sts;
-}
-
-static void acpi_pm1_evt_write_sts(ACPIREGS *ar, uint16_t val)
-{
- uint16_t pm1_sts = acpi_pm1_evt_get_sts(ar);
- if (pm1_sts & val & ACPI_BITMASK_TIMER_STATUS) {
- /* if TMRSTS is reset, then compute the new overflow time */
- acpi_pm_tmr_calc_overflow_time(ar);
- }
- ar->pm1.evt.sts &= ~val;
-}
-
-static void acpi_pm1_evt_write_en(ACPIREGS *ar, uint16_t val)
-{
- ar->pm1.evt.en = val;
- qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_RTC,
- val & ACPI_BITMASK_RT_CLOCK_ENABLE);
- qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_PMTIMER,
- val & ACPI_BITMASK_TIMER_ENABLE);
-}
-
-void acpi_pm1_evt_power_down(ACPIREGS *ar)
-{
- if (ar->pm1.evt.en & ACPI_BITMASK_POWER_BUTTON_ENABLE) {
- ar->pm1.evt.sts |= ACPI_BITMASK_POWER_BUTTON_STATUS;
- ar->tmr.update_sci(ar);
- }
-}
-
-void acpi_pm1_evt_reset(ACPIREGS *ar)
-{
- ar->pm1.evt.sts = 0;
- ar->pm1.evt.en = 0;
- qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_RTC, 0);
- qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_PMTIMER, 0);
-}
-
-static uint64_t acpi_pm_evt_read(void *opaque, hwaddr addr, unsigned width)
-{
- ACPIREGS *ar = opaque;
- switch (addr) {
- case 0:
- return acpi_pm1_evt_get_sts(ar);
- case 2:
- return ar->pm1.evt.en;
- default:
- return 0;
- }
-}
-
-static void acpi_pm_evt_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned width)
-{
- ACPIREGS *ar = opaque;
- switch (addr) {
- case 0:
- acpi_pm1_evt_write_sts(ar, val);
- ar->pm1.evt.update_sci(ar);
- break;
- case 2:
- acpi_pm1_evt_write_en(ar, val);
- ar->pm1.evt.update_sci(ar);
- break;
- }
-}
-
-static const MemoryRegionOps acpi_pm_evt_ops = {
- .read = acpi_pm_evt_read,
- .write = acpi_pm_evt_write,
- .valid.min_access_size = 2,
- .valid.max_access_size = 2,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-void acpi_pm1_evt_init(ACPIREGS *ar, acpi_update_sci_fn update_sci,
- MemoryRegion *parent)
-{
- ar->pm1.evt.update_sci = update_sci;
- memory_region_init_io(&ar->pm1.evt.io, memory_region_owner(parent),
- &acpi_pm_evt_ops, ar, "acpi-evt", 4);
- memory_region_add_subregion(parent, 0, &ar->pm1.evt.io);
-}
-
-/* ACPI PM_TMR */
-void acpi_pm_tmr_update(ACPIREGS *ar, bool enable)
-{
- int64_t expire_time;
-
- /* schedule a timer interruption if needed */
- if (enable) {
- expire_time = muldiv64(ar->tmr.overflow_time, NANOSECONDS_PER_SECOND,
- PM_TIMER_FREQUENCY);
- timer_mod(ar->tmr.timer, expire_time);
- } else {
- timer_del(ar->tmr.timer);
- }
-}
-
-void acpi_pm_tmr_calc_overflow_time(ACPIREGS *ar)
-{
- int64_t d = acpi_pm_tmr_get_clock();
- ar->tmr.overflow_time = (d + 0x800000LL) & ~0x7fffffLL;
-}
-
-static uint32_t acpi_pm_tmr_get(ACPIREGS *ar)
-{
- uint32_t d = acpi_pm_tmr_get_clock();
- return d & 0xffffff;
-}
-
-static void acpi_pm_tmr_timer(void *opaque)
-{
- ACPIREGS *ar = opaque;
- qemu_system_wakeup_request(QEMU_WAKEUP_REASON_PMTIMER);
- ar->tmr.update_sci(ar);
-}
-
-static uint64_t acpi_pm_tmr_read(void *opaque, hwaddr addr, unsigned width)
-{
- return acpi_pm_tmr_get(opaque);
-}
-
-static void acpi_pm_tmr_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned width)
-{
- /* nothing */
-}
-
-static const MemoryRegionOps acpi_pm_tmr_ops = {
- .read = acpi_pm_tmr_read,
- .write = acpi_pm_tmr_write,
- .valid.min_access_size = 4,
- .valid.max_access_size = 4,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-void acpi_pm_tmr_init(ACPIREGS *ar, acpi_update_sci_fn update_sci,
- MemoryRegion *parent)
-{
- ar->tmr.update_sci = update_sci;
- ar->tmr.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, acpi_pm_tmr_timer, ar);
- memory_region_init_io(&ar->tmr.io, memory_region_owner(parent),
- &acpi_pm_tmr_ops, ar, "acpi-tmr", 4);
- memory_region_add_subregion(parent, 8, &ar->tmr.io);
-}
-
-void acpi_pm_tmr_reset(ACPIREGS *ar)
-{
- ar->tmr.overflow_time = 0;
- timer_del(ar->tmr.timer);
-}
-
-/* ACPI PM1aCNT */
-static void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val)
-{
- ar->pm1.cnt.cnt = val & ~(ACPI_BITMASK_SLEEP_ENABLE);
-
- if (val & ACPI_BITMASK_SLEEP_ENABLE) {
- /* change suspend type */
- uint16_t sus_typ = (val >> 10) & 7;
- switch(sus_typ) {
- case 0: /* soft power off */
- qemu_system_shutdown_request();
- break;
- case 1:
- qemu_system_suspend_request();
- break;
- default:
- if (sus_typ == ar->pm1.cnt.s4_val) { /* S4 request */
- qapi_event_send_suspend_disk(&error_abort);
- qemu_system_shutdown_request();
- }
- break;
- }
- }
-}
-
-void acpi_pm1_cnt_update(ACPIREGS *ar,
- bool sci_enable, bool sci_disable)
-{
- /* ACPI specs 3.0, 4.7.2.5 */
- if (sci_enable) {
- ar->pm1.cnt.cnt |= ACPI_BITMASK_SCI_ENABLE;
- } else if (sci_disable) {
- ar->pm1.cnt.cnt &= ~ACPI_BITMASK_SCI_ENABLE;
- }
-}
-
-static uint64_t acpi_pm_cnt_read(void *opaque, hwaddr addr, unsigned width)
-{
- ACPIREGS *ar = opaque;
- return ar->pm1.cnt.cnt;
-}
-
-static void acpi_pm_cnt_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned width)
-{
- acpi_pm1_cnt_write(opaque, val);
-}
-
-static const MemoryRegionOps acpi_pm_cnt_ops = {
- .read = acpi_pm_cnt_read,
- .write = acpi_pm_cnt_write,
- .valid.min_access_size = 2,
- .valid.max_access_size = 2,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-void acpi_pm1_cnt_init(ACPIREGS *ar, MemoryRegion *parent,
- bool disable_s3, bool disable_s4, uint8_t s4_val)
-{
- FWCfgState *fw_cfg;
-
- ar->pm1.cnt.s4_val = s4_val;
- ar->wakeup.notify = acpi_notify_wakeup;
- qemu_register_wakeup_notifier(&ar->wakeup);
- memory_region_init_io(&ar->pm1.cnt.io, memory_region_owner(parent),
- &acpi_pm_cnt_ops, ar, "acpi-cnt", 2);
- memory_region_add_subregion(parent, 4, &ar->pm1.cnt.io);
-
- fw_cfg = fw_cfg_find();
- if (fw_cfg) {
- uint8_t suspend[6] = {128, 0, 0, 129, 128, 128};
- suspend[3] = 1 | ((!disable_s3) << 7);
- suspend[4] = s4_val | ((!disable_s4) << 7);
-
- fw_cfg_add_file(fw_cfg, "etc/system-states", g_memdup(suspend, 6), 6);
- }
-}
-
-void acpi_pm1_cnt_reset(ACPIREGS *ar)
-{
- ar->pm1.cnt.cnt = 0;
-}
-
-/* ACPI GPE */
-void acpi_gpe_init(ACPIREGS *ar, uint8_t len)
-{
- ar->gpe.len = len;
- /* Only first len / 2 bytes are ever used,
- * but the caller in ich9.c migrates full len bytes.
- * TODO: fix ich9.c and drop the extra allocation.
- */
- ar->gpe.sts = g_malloc0(len);
- ar->gpe.en = g_malloc0(len);
-}
-
-void acpi_gpe_reset(ACPIREGS *ar)
-{
- memset(ar->gpe.sts, 0, ar->gpe.len / 2);
- memset(ar->gpe.en, 0, ar->gpe.len / 2);
-}
-
-static uint8_t *acpi_gpe_ioport_get_ptr(ACPIREGS *ar, uint32_t addr)
-{
- uint8_t *cur = NULL;
-
- if (addr < ar->gpe.len / 2) {
- cur = ar->gpe.sts + addr;
- } else if (addr < ar->gpe.len) {
- cur = ar->gpe.en + addr - ar->gpe.len / 2;
- } else {
- abort();
- }
-
- return cur;
-}
-
-void acpi_gpe_ioport_writeb(ACPIREGS *ar, uint32_t addr, uint32_t val)
-{
- uint8_t *cur;
-
- cur = acpi_gpe_ioport_get_ptr(ar, addr);
- if (addr < ar->gpe.len / 2) {
- /* GPE_STS */
- *cur = (*cur) & ~val;
- } else if (addr < ar->gpe.len) {
- /* GPE_EN */
- *cur = val;
- } else {
- abort();
- }
-}
-
-uint32_t acpi_gpe_ioport_readb(ACPIREGS *ar, uint32_t addr)
-{
- uint8_t *cur;
- uint32_t val;
-
- cur = acpi_gpe_ioport_get_ptr(ar, addr);
- val = 0;
- if (cur != NULL) {
- val = *cur;
- }
-
- return val;
-}
-
-void acpi_send_gpe_event(ACPIREGS *ar, qemu_irq irq,
- AcpiGPEStatusBits status)
-{
- ar->gpe.sts[0] |= status;
- acpi_update_sci(ar, irq);
-}
-
-void acpi_update_sci(ACPIREGS *regs, qemu_irq irq)
-{
- int sci_level, pm1a_sts;
-
- pm1a_sts = acpi_pm1_evt_get_sts(regs);
-
- sci_level = ((pm1a_sts &
- regs->pm1.evt.en & ACPI_BITMASK_PM1_COMMON_ENABLED) != 0) ||
- ((regs->gpe.sts[0] & regs->gpe.en[0]) != 0);
-
- qemu_set_irq(irq, sci_level);
-
- /* schedule a timer interruption if needed */
- acpi_pm_tmr_update(regs,
- (regs->pm1.evt.en & ACPI_BITMASK_TIMER_ENABLE) &&
- !(pm1a_sts & ACPI_BITMASK_TIMER_STATUS));
-}
diff --git a/qemu/hw/acpi/cpu_hotplug.c b/qemu/hw/acpi/cpu_hotplug.c
deleted file mode 100644
index 4d86743fd..000000000
--- a/qemu/hw/acpi/cpu_hotplug.c
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * QEMU ACPI hotplug utilities
- *
- * Copyright (C) 2013 Red Hat Inc
- *
- * Authors:
- * Igor Mammedov <imammedo@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/acpi/cpu_hotplug.h"
-#include "qapi/error.h"
-#include "qom/cpu.h"
-
-static uint64_t cpu_status_read(void *opaque, hwaddr addr, unsigned int size)
-{
- AcpiCpuHotplug *cpus = opaque;
- uint64_t val = cpus->sts[addr];
-
- return val;
-}
-
-static void cpu_status_write(void *opaque, hwaddr addr, uint64_t data,
- unsigned int size)
-{
- /* TODO: implement VCPU removal on guest signal that CPU can be removed */
-}
-
-static const MemoryRegionOps AcpiCpuHotplug_ops = {
- .read = cpu_status_read,
- .write = cpu_status_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .valid = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
-};
-
-static void acpi_set_cpu_present_bit(AcpiCpuHotplug *g, CPUState *cpu,
- Error **errp)
-{
- CPUClass *k = CPU_GET_CLASS(cpu);
- int64_t cpu_id;
-
- cpu_id = k->get_arch_id(cpu);
- if ((cpu_id / 8) >= ACPI_GPE_PROC_LEN) {
- error_setg(errp, "acpi: invalid cpu id: %" PRIi64, cpu_id);
- return;
- }
-
- g->sts[cpu_id / 8] |= (1 << (cpu_id % 8));
-}
-
-void acpi_cpu_plug_cb(ACPIREGS *ar, qemu_irq irq,
- AcpiCpuHotplug *g, DeviceState *dev, Error **errp)
-{
- acpi_set_cpu_present_bit(g, CPU(dev), errp);
- if (*errp != NULL) {
- return;
- }
-
- acpi_send_gpe_event(ar, irq, ACPI_CPU_HOTPLUG_STATUS);
-}
-
-void acpi_cpu_hotplug_init(MemoryRegion *parent, Object *owner,
- AcpiCpuHotplug *gpe_cpu, uint16_t base)
-{
- CPUState *cpu;
-
- CPU_FOREACH(cpu) {
- acpi_set_cpu_present_bit(gpe_cpu, cpu, &error_abort);
- }
- memory_region_init_io(&gpe_cpu->io, owner, &AcpiCpuHotplug_ops,
- gpe_cpu, "acpi-cpu-hotplug", ACPI_GPE_PROC_LEN);
- memory_region_add_subregion(parent, base, &gpe_cpu->io);
-}
diff --git a/qemu/hw/acpi/cpu_hotplug_acpi_table.c b/qemu/hw/acpi/cpu_hotplug_acpi_table.c
deleted file mode 100644
index 97bb1092a..000000000
--- a/qemu/hw/acpi/cpu_hotplug_acpi_table.c
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/acpi/cpu_hotplug.h"
-
-void build_cpu_hotplug_aml(Aml *ctx)
-{
- Aml *method;
- Aml *if_ctx;
- Aml *else_ctx;
- Aml *sb_scope = aml_scope("_SB");
- uint8_t madt_tmpl[8] = {0x00, 0x08, 0x00, 0x00, 0x00, 0, 0, 0};
- Aml *cpu_id = aml_arg(0);
- Aml *cpu_on = aml_local(0);
- Aml *madt = aml_local(1);
- Aml *cpus_map = aml_name(CPU_ON_BITMAP);
- Aml *zero = aml_int(0);
- Aml *one = aml_int(1);
-
- /*
- * _MAT method - creates an madt apic buffer
- * cpu_id = Arg0 = Processor ID = Local APIC ID
- * cpu_on = Local0 = CPON flag for this cpu
- * madt = Local1 = Buffer (in madt apic form) to return
- */
- method = aml_method(CPU_MAT_METHOD, 1, AML_NOTSERIALIZED);
- aml_append(method,
- aml_store(aml_derefof(aml_index(cpus_map, cpu_id)), cpu_on));
- aml_append(method,
- aml_store(aml_buffer(sizeof(madt_tmpl), madt_tmpl), madt));
- /* Update the processor id, lapic id, and enable/disable status */
- aml_append(method, aml_store(cpu_id, aml_index(madt, aml_int(2))));
- aml_append(method, aml_store(cpu_id, aml_index(madt, aml_int(3))));
- aml_append(method, aml_store(cpu_on, aml_index(madt, aml_int(4))));
- aml_append(method, aml_return(madt));
- aml_append(sb_scope, method);
-
- /*
- * _STA method - return ON status of cpu
- * cpu_id = Arg0 = Processor ID = Local APIC ID
- * cpu_on = Local0 = CPON flag for this cpu
- */
- method = aml_method(CPU_STATUS_METHOD, 1, AML_NOTSERIALIZED);
- aml_append(method,
- aml_store(aml_derefof(aml_index(cpus_map, cpu_id)), cpu_on));
- if_ctx = aml_if(cpu_on);
- {
- aml_append(if_ctx, aml_return(aml_int(0xF)));
- }
- aml_append(method, if_ctx);
- else_ctx = aml_else();
- {
- aml_append(else_ctx, aml_return(zero));
- }
- aml_append(method, else_ctx);
- aml_append(sb_scope, method);
-
- method = aml_method(CPU_EJECT_METHOD, 2, AML_NOTSERIALIZED);
- aml_append(method, aml_sleep(200));
- aml_append(sb_scope, method);
-
- method = aml_method(CPU_SCAN_METHOD, 0, AML_NOTSERIALIZED);
- {
- Aml *while_ctx, *if_ctx2, *else_ctx2;
- Aml *bus_check_evt = aml_int(1);
- Aml *remove_evt = aml_int(3);
- Aml *status_map = aml_local(5); /* Local5 = active cpu bitmap */
- Aml *byte = aml_local(2); /* Local2 = last read byte from bitmap */
- Aml *idx = aml_local(0); /* Processor ID / APIC ID iterator */
- Aml *is_cpu_on = aml_local(1); /* Local1 = CPON flag for cpu */
- Aml *status = aml_local(3); /* Local3 = active state for cpu */
-
- aml_append(method, aml_store(aml_name(CPU_STATUS_MAP), status_map));
- aml_append(method, aml_store(zero, byte));
- aml_append(method, aml_store(zero, idx));
-
- /* While (idx < SizeOf(CPON)) */
- while_ctx = aml_while(aml_lless(idx, aml_sizeof(cpus_map)));
- aml_append(while_ctx,
- aml_store(aml_derefof(aml_index(cpus_map, idx)), is_cpu_on));
-
- if_ctx = aml_if(aml_and(idx, aml_int(0x07), NULL));
- {
- /* Shift down previously read bitmap byte */
- aml_append(if_ctx, aml_shiftright(byte, one, byte));
- }
- aml_append(while_ctx, if_ctx);
-
- else_ctx = aml_else();
- {
- /* Read next byte from cpu bitmap */
- aml_append(else_ctx, aml_store(aml_derefof(aml_index(status_map,
- aml_shiftright(idx, aml_int(3), NULL))), byte));
- }
- aml_append(while_ctx, else_ctx);
-
- aml_append(while_ctx, aml_store(aml_and(byte, one, NULL), status));
- if_ctx = aml_if(aml_lnot(aml_equal(is_cpu_on, status)));
- {
- /* State change - update CPON with new state */
- aml_append(if_ctx, aml_store(status, aml_index(cpus_map, idx)));
- if_ctx2 = aml_if(aml_equal(status, one));
- {
- aml_append(if_ctx2,
- aml_call2(AML_NOTIFY_METHOD, idx, bus_check_evt));
- }
- aml_append(if_ctx, if_ctx2);
- else_ctx2 = aml_else();
- {
- aml_append(else_ctx2,
- aml_call2(AML_NOTIFY_METHOD, idx, remove_evt));
- }
- }
- aml_append(if_ctx, else_ctx2);
- aml_append(while_ctx, if_ctx);
-
- aml_append(while_ctx, aml_increment(idx)); /* go to next cpu */
- aml_append(method, while_ctx);
- }
- aml_append(sb_scope, method);
-
- aml_append(ctx, sb_scope);
-}
diff --git a/qemu/hw/acpi/ich9.c b/qemu/hw/acpi/ich9.c
deleted file mode 100644
index 27e978f5f..000000000
--- a/qemu/hw/acpi/ich9.c
+++ /dev/null
@@ -1,477 +0,0 @@
-/*
- * ACPI implementation
- *
- * Copyright (c) 2006 Fabrice Bellard
- * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
- * VA Linux Systems Japan K.K.
- * Copyright (C) 2012 Jason Baron <jbaron@redhat.com>
- *
- * This is based on acpi.c.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2 as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "qapi/error.h"
-#include "qapi/visitor.h"
-#include "hw/i386/pc.h"
-#include "hw/pci/pci.h"
-#include "qemu/timer.h"
-#include "sysemu/sysemu.h"
-#include "hw/acpi/acpi.h"
-#include "hw/acpi/tco.h"
-#include "sysemu/kvm.h"
-#include "exec/address-spaces.h"
-
-#include "hw/i386/ich9.h"
-#include "hw/mem/pc-dimm.h"
-
-//#define DEBUG
-
-#ifdef DEBUG
-#define ICH9_DEBUG(fmt, ...) \
-do { printf("%s "fmt, __func__, ## __VA_ARGS__); } while (0)
-#else
-#define ICH9_DEBUG(fmt, ...) do { } while (0)
-#endif
-
-static void ich9_pm_update_sci_fn(ACPIREGS *regs)
-{
- ICH9LPCPMRegs *pm = container_of(regs, ICH9LPCPMRegs, acpi_regs);
- acpi_update_sci(&pm->acpi_regs, pm->irq);
-}
-
-static uint64_t ich9_gpe_readb(void *opaque, hwaddr addr, unsigned width)
-{
- ICH9LPCPMRegs *pm = opaque;
- return acpi_gpe_ioport_readb(&pm->acpi_regs, addr);
-}
-
-static void ich9_gpe_writeb(void *opaque, hwaddr addr, uint64_t val,
- unsigned width)
-{
- ICH9LPCPMRegs *pm = opaque;
- acpi_gpe_ioport_writeb(&pm->acpi_regs, addr, val);
- acpi_update_sci(&pm->acpi_regs, pm->irq);
-}
-
-static const MemoryRegionOps ich9_gpe_ops = {
- .read = ich9_gpe_readb,
- .write = ich9_gpe_writeb,
- .valid.min_access_size = 1,
- .valid.max_access_size = 4,
- .impl.min_access_size = 1,
- .impl.max_access_size = 1,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static uint64_t ich9_smi_readl(void *opaque, hwaddr addr, unsigned width)
-{
- ICH9LPCPMRegs *pm = opaque;
- switch (addr) {
- case 0:
- return pm->smi_en;
- case 4:
- return pm->smi_sts;
- default:
- return 0;
- }
-}
-
-static void ich9_smi_writel(void *opaque, hwaddr addr, uint64_t val,
- unsigned width)
-{
- ICH9LPCPMRegs *pm = opaque;
- TCOIORegs *tr = &pm->tco_regs;
- uint64_t tco_en;
-
- switch (addr) {
- case 0:
- tco_en = pm->smi_en & ICH9_PMIO_SMI_EN_TCO_EN;
- /* once TCO_LOCK bit is set, TCO_EN bit cannot be overwritten */
- if (tr->tco.cnt1 & TCO_LOCK) {
- val = (val & ~ICH9_PMIO_SMI_EN_TCO_EN) | tco_en;
- }
- pm->smi_en &= ~pm->smi_en_wmask;
- pm->smi_en |= (val & pm->smi_en_wmask);
- break;
- }
-}
-
-static const MemoryRegionOps ich9_smi_ops = {
- .read = ich9_smi_readl,
- .write = ich9_smi_writel,
- .valid.min_access_size = 4,
- .valid.max_access_size = 4,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-void ich9_pm_iospace_update(ICH9LPCPMRegs *pm, uint32_t pm_io_base)
-{
- ICH9_DEBUG("to 0x%x\n", pm_io_base);
-
- assert((pm_io_base & ICH9_PMIO_MASK) == 0);
-
- pm->pm_io_base = pm_io_base;
- memory_region_transaction_begin();
- memory_region_set_enabled(&pm->io, pm->pm_io_base != 0);
- memory_region_set_address(&pm->io, pm->pm_io_base);
- memory_region_transaction_commit();
-}
-
-static int ich9_pm_post_load(void *opaque, int version_id)
-{
- ICH9LPCPMRegs *pm = opaque;
- uint32_t pm_io_base = pm->pm_io_base;
- pm->pm_io_base = 0;
- ich9_pm_iospace_update(pm, pm_io_base);
- return 0;
-}
-
-#define VMSTATE_GPE_ARRAY(_field, _state) \
- { \
- .name = (stringify(_field)), \
- .version_id = 0, \
- .num = ICH9_PMIO_GPE0_LEN, \
- .info = &vmstate_info_uint8, \
- .size = sizeof(uint8_t), \
- .flags = VMS_ARRAY | VMS_POINTER, \
- .offset = vmstate_offset_pointer(_state, _field, uint8_t), \
- }
-
-static bool vmstate_test_use_memhp(void *opaque)
-{
- ICH9LPCPMRegs *s = opaque;
- return s->acpi_memory_hotplug.is_enabled;
-}
-
-static const VMStateDescription vmstate_memhp_state = {
- .name = "ich9_pm/memhp",
- .version_id = 1,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .needed = vmstate_test_use_memhp,
- .fields = (VMStateField[]) {
- VMSTATE_MEMORY_HOTPLUG(acpi_memory_hotplug, ICH9LPCPMRegs),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static bool vmstate_test_use_tco(void *opaque)
-{
- ICH9LPCPMRegs *s = opaque;
- return s->enable_tco;
-}
-
-static const VMStateDescription vmstate_tco_io_state = {
- .name = "ich9_pm/tco",
- .version_id = 1,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .needed = vmstate_test_use_tco,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT(tco_regs, ICH9LPCPMRegs, 1, vmstate_tco_io_sts,
- TCOIORegs),
- VMSTATE_END_OF_LIST()
- }
-};
-
-const VMStateDescription vmstate_ich9_pm = {
- .name = "ich9_pm",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = ich9_pm_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT16(acpi_regs.pm1.evt.sts, ICH9LPCPMRegs),
- VMSTATE_UINT16(acpi_regs.pm1.evt.en, ICH9LPCPMRegs),
- VMSTATE_UINT16(acpi_regs.pm1.cnt.cnt, ICH9LPCPMRegs),
- VMSTATE_TIMER_PTR(acpi_regs.tmr.timer, ICH9LPCPMRegs),
- VMSTATE_INT64(acpi_regs.tmr.overflow_time, ICH9LPCPMRegs),
- VMSTATE_GPE_ARRAY(acpi_regs.gpe.sts, ICH9LPCPMRegs),
- VMSTATE_GPE_ARRAY(acpi_regs.gpe.en, ICH9LPCPMRegs),
- VMSTATE_UINT32(smi_en, ICH9LPCPMRegs),
- VMSTATE_UINT32(smi_sts, ICH9LPCPMRegs),
- VMSTATE_END_OF_LIST()
- },
- .subsections = (const VMStateDescription*[]) {
- &vmstate_memhp_state,
- &vmstate_tco_io_state,
- NULL
- }
-};
-
-static void pm_reset(void *opaque)
-{
- ICH9LPCPMRegs *pm = opaque;
- ich9_pm_iospace_update(pm, 0);
-
- acpi_pm1_evt_reset(&pm->acpi_regs);
- acpi_pm1_cnt_reset(&pm->acpi_regs);
- acpi_pm_tmr_reset(&pm->acpi_regs);
- acpi_gpe_reset(&pm->acpi_regs);
-
- pm->smi_en = 0;
- if (!pm->smm_enabled) {
- /* Mark SMM as already inited to prevent SMM from running. */
- pm->smi_en |= ICH9_PMIO_SMI_EN_APMC_EN;
- }
- pm->smi_en_wmask = ~0;
-
- acpi_update_sci(&pm->acpi_regs, pm->irq);
-}
-
-static void pm_powerdown_req(Notifier *n, void *opaque)
-{
- ICH9LPCPMRegs *pm = container_of(n, ICH9LPCPMRegs, powerdown_notifier);
-
- acpi_pm1_evt_power_down(&pm->acpi_regs);
-}
-
-void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm,
- bool smm_enabled,
- qemu_irq sci_irq)
-{
- memory_region_init(&pm->io, OBJECT(lpc_pci), "ich9-pm", ICH9_PMIO_SIZE);
- memory_region_set_enabled(&pm->io, false);
- memory_region_add_subregion(pci_address_space_io(lpc_pci),
- 0, &pm->io);
-
- acpi_pm_tmr_init(&pm->acpi_regs, ich9_pm_update_sci_fn, &pm->io);
- acpi_pm1_evt_init(&pm->acpi_regs, ich9_pm_update_sci_fn, &pm->io);
- acpi_pm1_cnt_init(&pm->acpi_regs, &pm->io, pm->disable_s3, pm->disable_s4,
- pm->s4_val);
-
- acpi_gpe_init(&pm->acpi_regs, ICH9_PMIO_GPE0_LEN);
- memory_region_init_io(&pm->io_gpe, OBJECT(lpc_pci), &ich9_gpe_ops, pm,
- "acpi-gpe0", ICH9_PMIO_GPE0_LEN);
- memory_region_add_subregion(&pm->io, ICH9_PMIO_GPE0_STS, &pm->io_gpe);
-
- memory_region_init_io(&pm->io_smi, OBJECT(lpc_pci), &ich9_smi_ops, pm,
- "acpi-smi", 8);
- memory_region_add_subregion(&pm->io, ICH9_PMIO_SMI_EN, &pm->io_smi);
-
- pm->smm_enabled = smm_enabled;
-
- pm->enable_tco = true;
- acpi_pm_tco_init(&pm->tco_regs, &pm->io);
-
- pm->irq = sci_irq;
- qemu_register_reset(pm_reset, pm);
- pm->powerdown_notifier.notify = pm_powerdown_req;
- qemu_register_powerdown_notifier(&pm->powerdown_notifier);
-
- acpi_cpu_hotplug_init(pci_address_space_io(lpc_pci), OBJECT(lpc_pci),
- &pm->gpe_cpu, ICH9_CPU_HOTPLUG_IO_BASE);
-
- if (pm->acpi_memory_hotplug.is_enabled) {
- acpi_memory_hotplug_init(pci_address_space_io(lpc_pci), OBJECT(lpc_pci),
- &pm->acpi_memory_hotplug);
- }
-}
-
-static void ich9_pm_get_gpe0_blk(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- ICH9LPCPMRegs *pm = opaque;
- uint32_t value = pm->pm_io_base + ICH9_PMIO_GPE0_STS;
-
- visit_type_uint32(v, name, &value, errp);
-}
-
-static bool ich9_pm_get_memory_hotplug_support(Object *obj, Error **errp)
-{
- ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
-
- return s->pm.acpi_memory_hotplug.is_enabled;
-}
-
-static void ich9_pm_set_memory_hotplug_support(Object *obj, bool value,
- Error **errp)
-{
- ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
-
- s->pm.acpi_memory_hotplug.is_enabled = value;
-}
-
-static void ich9_pm_get_disable_s3(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- ICH9LPCPMRegs *pm = opaque;
- uint8_t value = pm->disable_s3;
-
- visit_type_uint8(v, name, &value, errp);
-}
-
-static void ich9_pm_set_disable_s3(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- ICH9LPCPMRegs *pm = opaque;
- Error *local_err = NULL;
- uint8_t value;
-
- visit_type_uint8(v, name, &value, &local_err);
- if (local_err) {
- goto out;
- }
- pm->disable_s3 = value;
-out:
- error_propagate(errp, local_err);
-}
-
-static void ich9_pm_get_disable_s4(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- ICH9LPCPMRegs *pm = opaque;
- uint8_t value = pm->disable_s4;
-
- visit_type_uint8(v, name, &value, errp);
-}
-
-static void ich9_pm_set_disable_s4(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- ICH9LPCPMRegs *pm = opaque;
- Error *local_err = NULL;
- uint8_t value;
-
- visit_type_uint8(v, name, &value, &local_err);
- if (local_err) {
- goto out;
- }
- pm->disable_s4 = value;
-out:
- error_propagate(errp, local_err);
-}
-
-static void ich9_pm_get_s4_val(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- ICH9LPCPMRegs *pm = opaque;
- uint8_t value = pm->s4_val;
-
- visit_type_uint8(v, name, &value, errp);
-}
-
-static void ich9_pm_set_s4_val(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- ICH9LPCPMRegs *pm = opaque;
- Error *local_err = NULL;
- uint8_t value;
-
- visit_type_uint8(v, name, &value, &local_err);
- if (local_err) {
- goto out;
- }
- pm->s4_val = value;
-out:
- error_propagate(errp, local_err);
-}
-
-static bool ich9_pm_get_enable_tco(Object *obj, Error **errp)
-{
- ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
- return s->pm.enable_tco;
-}
-
-static void ich9_pm_set_enable_tco(Object *obj, bool value, Error **errp)
-{
- ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
- s->pm.enable_tco = value;
-}
-
-void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm, Error **errp)
-{
- static const uint32_t gpe0_len = ICH9_PMIO_GPE0_LEN;
- pm->acpi_memory_hotplug.is_enabled = true;
- pm->disable_s3 = 0;
- pm->disable_s4 = 0;
- pm->s4_val = 2;
-
- object_property_add_uint32_ptr(obj, ACPI_PM_PROP_PM_IO_BASE,
- &pm->pm_io_base, errp);
- object_property_add(obj, ACPI_PM_PROP_GPE0_BLK, "uint32",
- ich9_pm_get_gpe0_blk,
- NULL, NULL, pm, NULL);
- object_property_add_uint32_ptr(obj, ACPI_PM_PROP_GPE0_BLK_LEN,
- &gpe0_len, errp);
- object_property_add_bool(obj, "memory-hotplug-support",
- ich9_pm_get_memory_hotplug_support,
- ich9_pm_set_memory_hotplug_support,
- NULL);
- object_property_add(obj, ACPI_PM_PROP_S3_DISABLED, "uint8",
- ich9_pm_get_disable_s3,
- ich9_pm_set_disable_s3,
- NULL, pm, NULL);
- object_property_add(obj, ACPI_PM_PROP_S4_DISABLED, "uint8",
- ich9_pm_get_disable_s4,
- ich9_pm_set_disable_s4,
- NULL, pm, NULL);
- object_property_add(obj, ACPI_PM_PROP_S4_VAL, "uint8",
- ich9_pm_get_s4_val,
- ich9_pm_set_s4_val,
- NULL, pm, NULL);
- object_property_add_bool(obj, ACPI_PM_PROP_TCO_ENABLED,
- ich9_pm_get_enable_tco,
- ich9_pm_set_enable_tco,
- NULL);
-}
-
-void ich9_pm_device_plug_cb(ICH9LPCPMRegs *pm, DeviceState *dev, Error **errp)
-{
- if (pm->acpi_memory_hotplug.is_enabled &&
- object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
- acpi_memory_plug_cb(&pm->acpi_regs, pm->irq, &pm->acpi_memory_hotplug,
- dev, errp);
- } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
- acpi_cpu_plug_cb(&pm->acpi_regs, pm->irq, &pm->gpe_cpu, dev, errp);
- } else {
- error_setg(errp, "acpi: device plug request for not supported device"
- " type: %s", object_get_typename(OBJECT(dev)));
- }
-}
-
-void ich9_pm_device_unplug_request_cb(ICH9LPCPMRegs *pm, DeviceState *dev,
- Error **errp)
-{
- if (pm->acpi_memory_hotplug.is_enabled &&
- object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
- acpi_memory_unplug_request_cb(&pm->acpi_regs, pm->irq,
- &pm->acpi_memory_hotplug, dev, errp);
- } else {
- error_setg(errp, "acpi: device unplug request for not supported device"
- " type: %s", object_get_typename(OBJECT(dev)));
- }
-}
-
-void ich9_pm_device_unplug_cb(ICH9LPCPMRegs *pm, DeviceState *dev,
- Error **errp)
-{
- if (pm->acpi_memory_hotplug.is_enabled &&
- object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
- acpi_memory_unplug_cb(&pm->acpi_memory_hotplug, dev, errp);
- } else {
- error_setg(errp, "acpi: device unplug for not supported device"
- " type: %s", object_get_typename(OBJECT(dev)));
- }
-}
-
-void ich9_pm_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list)
-{
- ICH9LPCState *s = ICH9_LPC_DEVICE(adev);
-
- acpi_memory_ospm_status(&s->pm.acpi_memory_hotplug, list);
-}
diff --git a/qemu/hw/acpi/memory_hotplug.c b/qemu/hw/acpi/memory_hotplug.c
deleted file mode 100644
index f65a3a21e..000000000
--- a/qemu/hw/acpi/memory_hotplug.c
+++ /dev/null
@@ -1,312 +0,0 @@
-#include "qemu/osdep.h"
-#include "hw/acpi/memory_hotplug.h"
-#include "hw/acpi/pc-hotplug.h"
-#include "hw/mem/pc-dimm.h"
-#include "hw/boards.h"
-#include "hw/qdev-core.h"
-#include "trace.h"
-#include "qapi-event.h"
-
-static ACPIOSTInfo *acpi_memory_device_status(int slot, MemStatus *mdev)
-{
- ACPIOSTInfo *info = g_new0(ACPIOSTInfo, 1);
-
- info->slot_type = ACPI_SLOT_TYPE_DIMM;
- info->slot = g_strdup_printf("%d", slot);
- info->source = mdev->ost_event;
- info->status = mdev->ost_status;
- if (mdev->dimm) {
- DeviceState *dev = DEVICE(mdev->dimm);
- if (dev->id) {
- info->device = g_strdup(dev->id);
- info->has_device = true;
- }
- }
- return info;
-}
-
-void acpi_memory_ospm_status(MemHotplugState *mem_st, ACPIOSTInfoList ***list)
-{
- int i;
-
- for (i = 0; i < mem_st->dev_count; i++) {
- ACPIOSTInfoList *elem = g_new0(ACPIOSTInfoList, 1);
- elem->value = acpi_memory_device_status(i, &mem_st->devs[i]);
- elem->next = NULL;
- **list = elem;
- *list = &elem->next;
- }
-}
-
-static uint64_t acpi_memory_hotplug_read(void *opaque, hwaddr addr,
- unsigned int size)
-{
- uint32_t val = 0;
- MemHotplugState *mem_st = opaque;
- MemStatus *mdev;
- Object *o;
-
- if (mem_st->selector >= mem_st->dev_count) {
- trace_mhp_acpi_invalid_slot_selected(mem_st->selector);
- return 0;
- }
-
- mdev = &mem_st->devs[mem_st->selector];
- o = OBJECT(mdev->dimm);
- switch (addr) {
- case 0x0: /* Lo part of phys address where DIMM is mapped */
- val = o ? object_property_get_int(o, PC_DIMM_ADDR_PROP, NULL) : 0;
- trace_mhp_acpi_read_addr_lo(mem_st->selector, val);
- break;
- case 0x4: /* Hi part of phys address where DIMM is mapped */
- val = o ? object_property_get_int(o, PC_DIMM_ADDR_PROP, NULL) >> 32 : 0;
- trace_mhp_acpi_read_addr_hi(mem_st->selector, val);
- break;
- case 0x8: /* Lo part of DIMM size */
- val = o ? object_property_get_int(o, PC_DIMM_SIZE_PROP, NULL) : 0;
- trace_mhp_acpi_read_size_lo(mem_st->selector, val);
- break;
- case 0xc: /* Hi part of DIMM size */
- val = o ? object_property_get_int(o, PC_DIMM_SIZE_PROP, NULL) >> 32 : 0;
- trace_mhp_acpi_read_size_hi(mem_st->selector, val);
- break;
- case 0x10: /* node proximity for _PXM method */
- val = o ? object_property_get_int(o, PC_DIMM_NODE_PROP, NULL) : 0;
- trace_mhp_acpi_read_pxm(mem_st->selector, val);
- break;
- case 0x14: /* pack and return is_* fields */
- val |= mdev->is_enabled ? 1 : 0;
- val |= mdev->is_inserting ? 2 : 0;
- val |= mdev->is_removing ? 4 : 0;
- trace_mhp_acpi_read_flags(mem_st->selector, val);
- break;
- default:
- val = ~0;
- break;
- }
- return val;
-}
-
-static void acpi_memory_hotplug_write(void *opaque, hwaddr addr, uint64_t data,
- unsigned int size)
-{
- MemHotplugState *mem_st = opaque;
- MemStatus *mdev;
- ACPIOSTInfo *info;
- DeviceState *dev = NULL;
- HotplugHandler *hotplug_ctrl = NULL;
- Error *local_err = NULL;
-
- if (!mem_st->dev_count) {
- return;
- }
-
- if (addr) {
- if (mem_st->selector >= mem_st->dev_count) {
- trace_mhp_acpi_invalid_slot_selected(mem_st->selector);
- return;
- }
- }
-
- switch (addr) {
- case 0x0: /* DIMM slot selector */
- mem_st->selector = data;
- trace_mhp_acpi_write_slot(mem_st->selector);
- break;
- case 0x4: /* _OST event */
- mdev = &mem_st->devs[mem_st->selector];
- if (data == 1) {
- /* TODO: handle device insert OST event */
- } else if (data == 3) {
- /* TODO: handle device remove OST event */
- }
- mdev->ost_event = data;
- trace_mhp_acpi_write_ost_ev(mem_st->selector, mdev->ost_event);
- break;
- case 0x8: /* _OST status */
- mdev = &mem_st->devs[mem_st->selector];
- mdev->ost_status = data;
- trace_mhp_acpi_write_ost_status(mem_st->selector, mdev->ost_status);
- /* TODO: implement memory removal on guest signal */
-
- info = acpi_memory_device_status(mem_st->selector, mdev);
- qapi_event_send_acpi_device_ost(info, &error_abort);
- qapi_free_ACPIOSTInfo(info);
- break;
- case 0x14: /* set is_* fields */
- mdev = &mem_st->devs[mem_st->selector];
- if (data & 2) { /* clear insert event */
- mdev->is_inserting = false;
- trace_mhp_acpi_clear_insert_evt(mem_st->selector);
- } else if (data & 4) {
- mdev->is_removing = false;
- trace_mhp_acpi_clear_remove_evt(mem_st->selector);
- } else if (data & 8) {
- if (!mdev->is_enabled) {
- trace_mhp_acpi_ejecting_invalid_slot(mem_st->selector);
- break;
- }
-
- dev = DEVICE(mdev->dimm);
- hotplug_ctrl = qdev_get_hotplug_handler(dev);
- /* call pc-dimm unplug cb */
- hotplug_handler_unplug(hotplug_ctrl, dev, &local_err);
- if (local_err) {
- trace_mhp_acpi_pc_dimm_delete_failed(mem_st->selector);
- qapi_event_send_mem_unplug_error(dev->id,
- error_get_pretty(local_err),
- &error_abort);
- error_free(local_err);
- break;
- }
- trace_mhp_acpi_pc_dimm_deleted(mem_st->selector);
- }
- break;
- default:
- break;
- }
-
-}
-static const MemoryRegionOps acpi_memory_hotplug_ops = {
- .read = acpi_memory_hotplug_read,
- .write = acpi_memory_hotplug_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .valid = {
- .min_access_size = 1,
- .max_access_size = 4,
- },
-};
-
-void acpi_memory_hotplug_init(MemoryRegion *as, Object *owner,
- MemHotplugState *state)
-{
- MachineState *machine = MACHINE(qdev_get_machine());
-
- state->dev_count = machine->ram_slots;
- if (!state->dev_count) {
- return;
- }
-
- state->devs = g_malloc0(sizeof(*state->devs) * state->dev_count);
- memory_region_init_io(&state->io, owner, &acpi_memory_hotplug_ops, state,
- "acpi-mem-hotplug", ACPI_MEMORY_HOTPLUG_IO_LEN);
- memory_region_add_subregion(as, ACPI_MEMORY_HOTPLUG_BASE, &state->io);
-}
-
-/**
- * acpi_memory_slot_status:
- * @mem_st: memory hotplug state
- * @dev: device
- * @errp: set in case of an error
- *
- * Obtain a single memory slot status.
- *
- * This function will be called by memory unplug request cb and unplug cb.
- */
-static MemStatus *
-acpi_memory_slot_status(MemHotplugState *mem_st,
- DeviceState *dev, Error **errp)
-{
- Error *local_err = NULL;
- int slot = object_property_get_int(OBJECT(dev), PC_DIMM_SLOT_PROP,
- &local_err);
-
- if (local_err) {
- error_propagate(errp, local_err);
- return NULL;
- }
-
- if (slot >= mem_st->dev_count) {
- char *dev_path = object_get_canonical_path(OBJECT(dev));
- error_setg(errp, "acpi_memory_slot_status: "
- "device [%s] returned invalid memory slot[%d]",
- dev_path, slot);
- g_free(dev_path);
- return NULL;
- }
-
- return &mem_st->devs[slot];
-}
-
-void acpi_memory_plug_cb(ACPIREGS *ar, qemu_irq irq, MemHotplugState *mem_st,
- DeviceState *dev, Error **errp)
-{
- MemStatus *mdev;
- DeviceClass *dc = DEVICE_GET_CLASS(dev);
-
- if (!dc->hotpluggable) {
- return;
- }
-
- mdev = acpi_memory_slot_status(mem_st, dev, errp);
- if (!mdev) {
- return;
- }
-
- mdev->dimm = dev;
- mdev->is_enabled = true;
- if (dev->hotplugged) {
- mdev->is_inserting = true;
-
- /* do ACPI magic */
- acpi_send_gpe_event(ar, irq, ACPI_MEMORY_HOTPLUG_STATUS);
- }
-}
-
-void acpi_memory_unplug_request_cb(ACPIREGS *ar, qemu_irq irq,
- MemHotplugState *mem_st,
- DeviceState *dev, Error **errp)
-{
- MemStatus *mdev;
-
- mdev = acpi_memory_slot_status(mem_st, dev, errp);
- if (!mdev) {
- return;
- }
-
- mdev->is_removing = true;
-
- /* Do ACPI magic */
- acpi_send_gpe_event(ar, irq, ACPI_MEMORY_HOTPLUG_STATUS);
-}
-
-void acpi_memory_unplug_cb(MemHotplugState *mem_st,
- DeviceState *dev, Error **errp)
-{
- MemStatus *mdev;
-
- mdev = acpi_memory_slot_status(mem_st, dev, errp);
- if (!mdev) {
- return;
- }
-
- mdev->is_enabled = false;
- mdev->dimm = NULL;
-}
-
-static const VMStateDescription vmstate_memhp_sts = {
- .name = "memory hotplug device state",
- .version_id = 1,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .fields = (VMStateField[]) {
- VMSTATE_BOOL(is_enabled, MemStatus),
- VMSTATE_BOOL(is_inserting, MemStatus),
- VMSTATE_UINT32(ost_event, MemStatus),
- VMSTATE_UINT32(ost_status, MemStatus),
- VMSTATE_END_OF_LIST()
- }
-};
-
-const VMStateDescription vmstate_memory_hotplug = {
- .name = "memory hotplug state",
- .version_id = 1,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(selector, MemHotplugState),
- VMSTATE_STRUCT_VARRAY_POINTER_UINT32(devs, MemHotplugState, dev_count,
- vmstate_memhp_sts, MemStatus),
- VMSTATE_END_OF_LIST()
- }
-};
diff --git a/qemu/hw/acpi/memory_hotplug_acpi_table.c b/qemu/hw/acpi/memory_hotplug_acpi_table.c
deleted file mode 100644
index c75660215..000000000
--- a/qemu/hw/acpi/memory_hotplug_acpi_table.c
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * Memory hotplug AML code of DSDT ACPI table
- *
- * Copyright (C) 2015 Red Hat Inc
- *
- * Author: Igor Mammedov <imammedo@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "hw/acpi/memory_hotplug.h"
-#include "include/hw/acpi/pc-hotplug.h"
-#include "hw/boards.h"
-
-void build_memory_hotplug_aml(Aml *ctx, uint32_t nr_mem,
- uint16_t io_base, uint16_t io_len)
-{
- Aml *ifctx;
- Aml *method;
- Aml *pci_scope;
- Aml *mem_ctrl_dev;
-
- /* scope for memory hotplug controller device node */
- pci_scope = aml_scope("_SB.PCI0");
- mem_ctrl_dev = aml_device(MEMORY_HOTPLUG_DEVICE);
- {
- Aml *one = aml_int(1);
- Aml *zero = aml_int(0);
- Aml *ret_val = aml_local(0);
- Aml *slot_arg0 = aml_arg(0);
- Aml *slots_nr = aml_name(MEMORY_SLOTS_NUMBER);
- Aml *ctrl_lock = aml_name(MEMORY_SLOT_LOCK);
- Aml *slot_selector = aml_name(MEMORY_SLOT_SLECTOR);
-
- aml_append(mem_ctrl_dev, aml_name_decl("_HID", aml_string("PNP0A06")));
- aml_append(mem_ctrl_dev,
- aml_name_decl("_UID", aml_string("Memory hotplug resources")));
-
- method = aml_method("_STA", 0, AML_NOTSERIALIZED);
- ifctx = aml_if(aml_equal(slots_nr, zero));
- {
- aml_append(ifctx, aml_return(zero));
- }
- aml_append(method, ifctx);
- /* present, functioning, decoding, not shown in UI */
- aml_append(method, aml_return(aml_int(0xB)));
- aml_append(mem_ctrl_dev, method);
-
- aml_append(mem_ctrl_dev, aml_mutex(MEMORY_SLOT_LOCK, 0));
-
- method = aml_method(MEMORY_SLOT_SCAN_METHOD, 0, AML_NOTSERIALIZED);
- {
- Aml *else_ctx;
- Aml *while_ctx;
- Aml *idx = aml_local(0);
- Aml *eject_req = aml_int(3);
- Aml *dev_chk = aml_int(1);
-
- ifctx = aml_if(aml_equal(slots_nr, zero));
- {
- aml_append(ifctx, aml_return(zero));
- }
- aml_append(method, ifctx);
-
- aml_append(method, aml_store(zero, idx));
- aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
- /* build AML that:
- * loops over all slots and Notifies DIMMs with
- * Device Check or Eject Request notifications if
- * slot has corresponding status bit set and clears
- * slot status.
- */
- while_ctx = aml_while(aml_lless(idx, slots_nr));
- {
- Aml *ins_evt = aml_name(MEMORY_SLOT_INSERT_EVENT);
- Aml *rm_evt = aml_name(MEMORY_SLOT_REMOVE_EVENT);
-
- aml_append(while_ctx, aml_store(idx, slot_selector));
- ifctx = aml_if(aml_equal(ins_evt, one));
- {
- aml_append(ifctx,
- aml_call2(MEMORY_SLOT_NOTIFY_METHOD,
- idx, dev_chk));
- aml_append(ifctx, aml_store(one, ins_evt));
- }
- aml_append(while_ctx, ifctx);
-
- else_ctx = aml_else();
- ifctx = aml_if(aml_equal(rm_evt, one));
- {
- aml_append(ifctx,
- aml_call2(MEMORY_SLOT_NOTIFY_METHOD,
- idx, eject_req));
- aml_append(ifctx, aml_store(one, rm_evt));
- }
- aml_append(else_ctx, ifctx);
- aml_append(while_ctx, else_ctx);
-
- aml_append(while_ctx, aml_add(idx, one, idx));
- }
- aml_append(method, while_ctx);
- aml_append(method, aml_release(ctrl_lock));
- aml_append(method, aml_return(one));
- }
- aml_append(mem_ctrl_dev, method);
-
- method = aml_method(MEMORY_SLOT_STATUS_METHOD, 1, AML_NOTSERIALIZED);
- {
- Aml *slot_enabled = aml_name(MEMORY_SLOT_ENABLED);
-
- aml_append(method, aml_store(zero, ret_val));
- aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
- aml_append(method,
- aml_store(aml_to_integer(slot_arg0), slot_selector));
-
- ifctx = aml_if(aml_equal(slot_enabled, one));
- {
- aml_append(ifctx, aml_store(aml_int(0xF), ret_val));
- }
- aml_append(method, ifctx);
-
- aml_append(method, aml_release(ctrl_lock));
- aml_append(method, aml_return(ret_val));
- }
- aml_append(mem_ctrl_dev, method);
-
- method = aml_method(MEMORY_SLOT_CRS_METHOD, 1, AML_SERIALIZED);
- {
- Aml *mr64 = aml_name("MR64");
- Aml *mr32 = aml_name("MR32");
- Aml *crs_tmpl = aml_resource_template();
- Aml *minl = aml_name("MINL");
- Aml *minh = aml_name("MINH");
- Aml *maxl = aml_name("MAXL");
- Aml *maxh = aml_name("MAXH");
- Aml *lenl = aml_name("LENL");
- Aml *lenh = aml_name("LENH");
-
- aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
- aml_append(method, aml_store(aml_to_integer(slot_arg0),
- slot_selector));
-
- aml_append(crs_tmpl,
- aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
- AML_CACHEABLE, AML_READ_WRITE,
- 0, 0x0, 0xFFFFFFFFFFFFFFFEULL, 0,
- 0xFFFFFFFFFFFFFFFFULL));
- aml_append(method, aml_name_decl("MR64", crs_tmpl));
- aml_append(method,
- aml_create_dword_field(mr64, aml_int(14), "MINL"));
- aml_append(method,
- aml_create_dword_field(mr64, aml_int(18), "MINH"));
- aml_append(method,
- aml_create_dword_field(mr64, aml_int(38), "LENL"));
- aml_append(method,
- aml_create_dword_field(mr64, aml_int(42), "LENH"));
- aml_append(method,
- aml_create_dword_field(mr64, aml_int(22), "MAXL"));
- aml_append(method,
- aml_create_dword_field(mr64, aml_int(26), "MAXH"));
-
- aml_append(method,
- aml_store(aml_name(MEMORY_SLOT_ADDR_HIGH), minh));
- aml_append(method,
- aml_store(aml_name(MEMORY_SLOT_ADDR_LOW), minl));
- aml_append(method,
- aml_store(aml_name(MEMORY_SLOT_SIZE_HIGH), lenh));
- aml_append(method,
- aml_store(aml_name(MEMORY_SLOT_SIZE_LOW), lenl));
-
- /* 64-bit math: MAX = MIN + LEN - 1 */
- aml_append(method, aml_add(minl, lenl, maxl));
- aml_append(method, aml_add(minh, lenh, maxh));
- ifctx = aml_if(aml_lless(maxl, minl));
- {
- aml_append(ifctx, aml_add(maxh, one, maxh));
- }
- aml_append(method, ifctx);
- ifctx = aml_if(aml_lless(maxl, one));
- {
- aml_append(ifctx, aml_subtract(maxh, one, maxh));
- }
- aml_append(method, ifctx);
- aml_append(method, aml_subtract(maxl, one, maxl));
-
- /* return 32-bit _CRS if addr/size is in low mem */
- /* TODO: remove it since all hotplugged DIMMs are in high mem */
- ifctx = aml_if(aml_equal(maxh, zero));
- {
- crs_tmpl = aml_resource_template();
- aml_append(crs_tmpl,
- aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED,
- AML_MAX_FIXED, AML_CACHEABLE,
- AML_READ_WRITE,
- 0, 0x0, 0xFFFFFFFE, 0,
- 0xFFFFFFFF));
- aml_append(ifctx, aml_name_decl("MR32", crs_tmpl));
- aml_append(ifctx,
- aml_create_dword_field(mr32, aml_int(10), "MIN"));
- aml_append(ifctx,
- aml_create_dword_field(mr32, aml_int(14), "MAX"));
- aml_append(ifctx,
- aml_create_dword_field(mr32, aml_int(22), "LEN"));
- aml_append(ifctx, aml_store(minl, aml_name("MIN")));
- aml_append(ifctx, aml_store(maxl, aml_name("MAX")));
- aml_append(ifctx, aml_store(lenl, aml_name("LEN")));
-
- aml_append(ifctx, aml_release(ctrl_lock));
- aml_append(ifctx, aml_return(mr32));
- }
- aml_append(method, ifctx);
-
- aml_append(method, aml_release(ctrl_lock));
- aml_append(method, aml_return(mr64));
- }
- aml_append(mem_ctrl_dev, method);
-
- method = aml_method(MEMORY_SLOT_PROXIMITY_METHOD, 1,
- AML_NOTSERIALIZED);
- {
- Aml *proximity = aml_name(MEMORY_SLOT_PROXIMITY);
-
- aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
- aml_append(method, aml_store(aml_to_integer(slot_arg0),
- slot_selector));
- aml_append(method, aml_store(proximity, ret_val));
- aml_append(method, aml_release(ctrl_lock));
- aml_append(method, aml_return(ret_val));
- }
- aml_append(mem_ctrl_dev, method);
-
- method = aml_method(MEMORY_SLOT_OST_METHOD, 4, AML_NOTSERIALIZED);
- {
- Aml *ost_evt = aml_name(MEMORY_SLOT_OST_EVENT);
- Aml *ost_status = aml_name(MEMORY_SLOT_OST_STATUS);
-
- aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
- aml_append(method, aml_store(aml_to_integer(slot_arg0),
- slot_selector));
- aml_append(method, aml_store(aml_arg(1), ost_evt));
- aml_append(method, aml_store(aml_arg(2), ost_status));
- aml_append(method, aml_release(ctrl_lock));
- }
- aml_append(mem_ctrl_dev, method);
-
- method = aml_method(MEMORY_SLOT_EJECT_METHOD, 2, AML_NOTSERIALIZED);
- {
- Aml *eject = aml_name(MEMORY_SLOT_EJECT);
-
- aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
- aml_append(method, aml_store(aml_to_integer(slot_arg0),
- slot_selector));
- aml_append(method, aml_store(one, eject));
- aml_append(method, aml_release(ctrl_lock));
- }
- aml_append(mem_ctrl_dev, method);
- }
- aml_append(pci_scope, mem_ctrl_dev);
- aml_append(ctx, pci_scope);
-}
diff --git a/qemu/hw/acpi/nvdimm.c b/qemu/hw/acpi/nvdimm.c
deleted file mode 100644
index 9531340e5..000000000
--- a/qemu/hw/acpi/nvdimm.c
+++ /dev/null
@@ -1,706 +0,0 @@
-/*
- * NVDIMM ACPI Implementation
- *
- * Copyright(C) 2015 Intel Corporation.
- *
- * Author:
- * Xiao Guangrong <guangrong.xiao@linux.intel.com>
- *
- * NFIT is defined in ACPI 6.0: 5.2.25 NVDIMM Firmware Interface Table (NFIT)
- * and the DSM specification can be found at:
- * http://pmem.io/documents/NVDIMM_DSM_Interface_Example.pdf
- *
- * Currently, it only supports PMEM Virtualization.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>
- */
-
-#include "qemu/osdep.h"
-#include "hw/acpi/acpi.h"
-#include "hw/acpi/aml-build.h"
-#include "hw/acpi/bios-linker-loader.h"
-#include "hw/nvram/fw_cfg.h"
-#include "hw/mem/nvdimm.h"
-
-static int nvdimm_plugged_device_list(Object *obj, void *opaque)
-{
- GSList **list = opaque;
-
- if (object_dynamic_cast(obj, TYPE_NVDIMM)) {
- DeviceState *dev = DEVICE(obj);
-
- if (dev->realized) { /* only realized NVDIMMs matter */
- *list = g_slist_append(*list, DEVICE(obj));
- }
- }
-
- object_child_foreach(obj, nvdimm_plugged_device_list, opaque);
- return 0;
-}
-
-/*
- * inquire plugged NVDIMM devices and link them into the list which is
- * returned to the caller.
- *
- * Note: it is the caller's responsibility to free the list to avoid
- * memory leak.
- */
-static GSList *nvdimm_get_plugged_device_list(void)
-{
- GSList *list = NULL;
-
- object_child_foreach(qdev_get_machine(), nvdimm_plugged_device_list,
- &list);
- return list;
-}
-
-#define NVDIMM_UUID_LE(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \
- { (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \
- (b) & 0xff, ((b) >> 8) & 0xff, (c) & 0xff, ((c) >> 8) & 0xff, \
- (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }
-
-/*
- * define Byte Addressable Persistent Memory (PM) Region according to
- * ACPI 6.0: 5.2.25.1 System Physical Address Range Structure.
- */
-static const uint8_t nvdimm_nfit_spa_uuid[] =
- NVDIMM_UUID_LE(0x66f0d379, 0xb4f3, 0x4074, 0xac, 0x43, 0x0d, 0x33,
- 0x18, 0xb7, 0x8c, 0xdb);
-
-/*
- * NVDIMM Firmware Interface Table
- * @signature: "NFIT"
- *
- * It provides information that allows OSPM to enumerate NVDIMM present in
- * the platform and associate system physical address ranges created by the
- * NVDIMMs.
- *
- * It is defined in ACPI 6.0: 5.2.25 NVDIMM Firmware Interface Table (NFIT)
- */
-struct NvdimmNfitHeader {
- ACPI_TABLE_HEADER_DEF
- uint32_t reserved;
-} QEMU_PACKED;
-typedef struct NvdimmNfitHeader NvdimmNfitHeader;
-
-/*
- * define NFIT structures according to ACPI 6.0: 5.2.25 NVDIMM Firmware
- * Interface Table (NFIT).
- */
-
-/*
- * System Physical Address Range Structure
- *
- * It describes the system physical address ranges occupied by NVDIMMs and
- * the types of the regions.
- */
-struct NvdimmNfitSpa {
- uint16_t type;
- uint16_t length;
- uint16_t spa_index;
- uint16_t flags;
- uint32_t reserved;
- uint32_t proximity_domain;
- uint8_t type_guid[16];
- uint64_t spa_base;
- uint64_t spa_length;
- uint64_t mem_attr;
-} QEMU_PACKED;
-typedef struct NvdimmNfitSpa NvdimmNfitSpa;
-
-/*
- * Memory Device to System Physical Address Range Mapping Structure
- *
- * It enables identifying each NVDIMM region and the corresponding SPA
- * describing the memory interleave
- */
-struct NvdimmNfitMemDev {
- uint16_t type;
- uint16_t length;
- uint32_t nfit_handle;
- uint16_t phys_id;
- uint16_t region_id;
- uint16_t spa_index;
- uint16_t dcr_index;
- uint64_t region_len;
- uint64_t region_offset;
- uint64_t region_dpa;
- uint16_t interleave_index;
- uint16_t interleave_ways;
- uint16_t flags;
- uint16_t reserved;
-} QEMU_PACKED;
-typedef struct NvdimmNfitMemDev NvdimmNfitMemDev;
-
-/*
- * NVDIMM Control Region Structure
- *
- * It describes the NVDIMM and if applicable, Block Control Window.
- */
-struct NvdimmNfitControlRegion {
- uint16_t type;
- uint16_t length;
- uint16_t dcr_index;
- uint16_t vendor_id;
- uint16_t device_id;
- uint16_t revision_id;
- uint16_t sub_vendor_id;
- uint16_t sub_device_id;
- uint16_t sub_revision_id;
- uint8_t reserved[6];
- uint32_t serial_number;
- uint16_t fic;
- uint16_t num_bcw;
- uint64_t bcw_size;
- uint64_t cmd_offset;
- uint64_t cmd_size;
- uint64_t status_offset;
- uint64_t status_size;
- uint16_t flags;
- uint8_t reserved2[6];
-} QEMU_PACKED;
-typedef struct NvdimmNfitControlRegion NvdimmNfitControlRegion;
-
-/*
- * Module serial number is a unique number for each device. We use the
- * slot id of NVDIMM device to generate this number so that each device
- * associates with a different number.
- *
- * 0x123456 is a magic number we arbitrarily chose.
- */
-static uint32_t nvdimm_slot_to_sn(int slot)
-{
- return 0x123456 + slot;
-}
-
-/*
- * handle is used to uniquely associate nfit_memdev structure with NVDIMM
- * ACPI device - nfit_memdev.nfit_handle matches with the value returned
- * by ACPI device _ADR method.
- *
- * We generate the handle with the slot id of NVDIMM device and reserve
- * 0 for NVDIMM root device.
- */
-static uint32_t nvdimm_slot_to_handle(int slot)
-{
- return slot + 1;
-}
-
-/*
- * index uniquely identifies the structure, 0 is reserved which indicates
- * that the structure is not valid or the associated structure is not
- * present.
- *
- * Each NVDIMM device needs two indexes, one for nfit_spa and another for
- * nfit_dc which are generated by the slot id of NVDIMM device.
- */
-static uint16_t nvdimm_slot_to_spa_index(int slot)
-{
- return (slot + 1) << 1;
-}
-
-/* See the comments of nvdimm_slot_to_spa_index(). */
-static uint32_t nvdimm_slot_to_dcr_index(int slot)
-{
- return nvdimm_slot_to_spa_index(slot) + 1;
-}
-
-/* ACPI 6.0: 5.2.25.1 System Physical Address Range Structure */
-static void
-nvdimm_build_structure_spa(GArray *structures, DeviceState *dev)
-{
- NvdimmNfitSpa *nfit_spa;
- uint64_t addr = object_property_get_int(OBJECT(dev), PC_DIMM_ADDR_PROP,
- NULL);
- uint64_t size = object_property_get_int(OBJECT(dev), PC_DIMM_SIZE_PROP,
- NULL);
- uint32_t node = object_property_get_int(OBJECT(dev), PC_DIMM_NODE_PROP,
- NULL);
- int slot = object_property_get_int(OBJECT(dev), PC_DIMM_SLOT_PROP,
- NULL);
-
- nfit_spa = acpi_data_push(structures, sizeof(*nfit_spa));
-
- nfit_spa->type = cpu_to_le16(0 /* System Physical Address Range
- Structure */);
- nfit_spa->length = cpu_to_le16(sizeof(*nfit_spa));
- nfit_spa->spa_index = cpu_to_le16(nvdimm_slot_to_spa_index(slot));
-
- /*
- * Control region is strict as all the device info, such as SN, index,
- * is associated with slot id.
- */
- nfit_spa->flags = cpu_to_le16(1 /* Control region is strictly for
- management during hot add/online
- operation */ |
- 2 /* Data in Proximity Domain field is
- valid*/);
-
- /* NUMA node. */
- nfit_spa->proximity_domain = cpu_to_le32(node);
- /* the region reported as PMEM. */
- memcpy(nfit_spa->type_guid, nvdimm_nfit_spa_uuid,
- sizeof(nvdimm_nfit_spa_uuid));
-
- nfit_spa->spa_base = cpu_to_le64(addr);
- nfit_spa->spa_length = cpu_to_le64(size);
-
- /* It is the PMEM and can be cached as writeback. */
- nfit_spa->mem_attr = cpu_to_le64(0x8ULL /* EFI_MEMORY_WB */ |
- 0x8000ULL /* EFI_MEMORY_NV */);
-}
-
-/*
- * ACPI 6.0: 5.2.25.2 Memory Device to System Physical Address Range Mapping
- * Structure
- */
-static void
-nvdimm_build_structure_memdev(GArray *structures, DeviceState *dev)
-{
- NvdimmNfitMemDev *nfit_memdev;
- uint64_t addr = object_property_get_int(OBJECT(dev), PC_DIMM_ADDR_PROP,
- NULL);
- uint64_t size = object_property_get_int(OBJECT(dev), PC_DIMM_SIZE_PROP,
- NULL);
- int slot = object_property_get_int(OBJECT(dev), PC_DIMM_SLOT_PROP,
- NULL);
- uint32_t handle = nvdimm_slot_to_handle(slot);
-
- nfit_memdev = acpi_data_push(structures, sizeof(*nfit_memdev));
-
- nfit_memdev->type = cpu_to_le16(1 /* Memory Device to System Address
- Range Map Structure*/);
- nfit_memdev->length = cpu_to_le16(sizeof(*nfit_memdev));
- nfit_memdev->nfit_handle = cpu_to_le32(handle);
-
- /*
- * associate memory device with System Physical Address Range
- * Structure.
- */
- nfit_memdev->spa_index = cpu_to_le16(nvdimm_slot_to_spa_index(slot));
- /* associate memory device with Control Region Structure. */
- nfit_memdev->dcr_index = cpu_to_le16(nvdimm_slot_to_dcr_index(slot));
-
- /* The memory region on the device. */
- nfit_memdev->region_len = cpu_to_le64(size);
- nfit_memdev->region_dpa = cpu_to_le64(addr);
-
- /* Only one interleave for PMEM. */
- nfit_memdev->interleave_ways = cpu_to_le16(1);
-}
-
-/*
- * ACPI 6.0: 5.2.25.5 NVDIMM Control Region Structure.
- */
-static void nvdimm_build_structure_dcr(GArray *structures, DeviceState *dev)
-{
- NvdimmNfitControlRegion *nfit_dcr;
- int slot = object_property_get_int(OBJECT(dev), PC_DIMM_SLOT_PROP,
- NULL);
- uint32_t sn = nvdimm_slot_to_sn(slot);
-
- nfit_dcr = acpi_data_push(structures, sizeof(*nfit_dcr));
-
- nfit_dcr->type = cpu_to_le16(4 /* NVDIMM Control Region Structure */);
- nfit_dcr->length = cpu_to_le16(sizeof(*nfit_dcr));
- nfit_dcr->dcr_index = cpu_to_le16(nvdimm_slot_to_dcr_index(slot));
-
- /* vendor: Intel. */
- nfit_dcr->vendor_id = cpu_to_le16(0x8086);
- nfit_dcr->device_id = cpu_to_le16(1);
-
- /* The _DSM method is following Intel's DSM specification. */
- nfit_dcr->revision_id = cpu_to_le16(1 /* Current Revision supported
- in ACPI 6.0 is 1. */);
- nfit_dcr->serial_number = cpu_to_le32(sn);
- nfit_dcr->fic = cpu_to_le16(0x201 /* Format Interface Code. See Chapter
- 2: NVDIMM Device Specific Method
- (DSM) in DSM Spec Rev1.*/);
-}
-
-static GArray *nvdimm_build_device_structure(GSList *device_list)
-{
- GArray *structures = g_array_new(false, true /* clear */, 1);
-
- for (; device_list; device_list = device_list->next) {
- DeviceState *dev = device_list->data;
-
- /* build System Physical Address Range Structure. */
- nvdimm_build_structure_spa(structures, dev);
-
- /*
- * build Memory Device to System Physical Address Range Mapping
- * Structure.
- */
- nvdimm_build_structure_memdev(structures, dev);
-
- /* build NVDIMM Control Region Structure. */
- nvdimm_build_structure_dcr(structures, dev);
- }
-
- return structures;
-}
-
-static void nvdimm_build_nfit(GSList *device_list, GArray *table_offsets,
- GArray *table_data, GArray *linker)
-{
- GArray *structures = nvdimm_build_device_structure(device_list);
- unsigned int header;
-
- acpi_add_table(table_offsets, table_data);
-
- /* NFIT header. */
- header = table_data->len;
- acpi_data_push(table_data, sizeof(NvdimmNfitHeader));
- /* NVDIMM device structures. */
- g_array_append_vals(table_data, structures->data, structures->len);
-
- build_header(linker, table_data,
- (void *)(table_data->data + header), "NFIT",
- sizeof(NvdimmNfitHeader) + structures->len, 1, NULL, NULL);
- g_array_free(structures, true);
-}
-
-struct NvdimmDsmIn {
- uint32_t handle;
- uint32_t revision;
- uint32_t function;
- /* the remaining size in the page is used by arg3. */
- union {
- uint8_t arg3[0];
- };
-} QEMU_PACKED;
-typedef struct NvdimmDsmIn NvdimmDsmIn;
-
-struct NvdimmDsmOut {
- /* the size of buffer filled by QEMU. */
- uint32_t len;
- uint8_t data[0];
-} QEMU_PACKED;
-typedef struct NvdimmDsmOut NvdimmDsmOut;
-
-struct NvdimmDsmFunc0Out {
- /* the size of buffer filled by QEMU. */
- uint32_t len;
- uint32_t supported_func;
-} QEMU_PACKED;
-typedef struct NvdimmDsmFunc0Out NvdimmDsmFunc0Out;
-
-struct NvdimmDsmFuncNoPayloadOut {
- /* the size of buffer filled by QEMU. */
- uint32_t len;
- uint32_t func_ret_status;
-} QEMU_PACKED;
-typedef struct NvdimmDsmFuncNoPayloadOut NvdimmDsmFuncNoPayloadOut;
-
-static uint64_t
-nvdimm_dsm_read(void *opaque, hwaddr addr, unsigned size)
-{
- nvdimm_debug("BUG: we never read _DSM IO Port.\n");
- return 0;
-}
-
-static void
-nvdimm_dsm_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
-{
- NvdimmDsmIn *in;
- hwaddr dsm_mem_addr = val;
-
- nvdimm_debug("dsm memory address %#" HWADDR_PRIx ".\n", dsm_mem_addr);
-
- /*
- * The DSM memory is mapped to guest address space so an evil guest
- * can change its content while we are doing DSM emulation. Avoid
- * this by copying DSM memory to QEMU local memory.
- */
- in = g_malloc(TARGET_PAGE_SIZE);
- cpu_physical_memory_read(dsm_mem_addr, in, TARGET_PAGE_SIZE);
-
- le32_to_cpus(&in->revision);
- le32_to_cpus(&in->function);
- le32_to_cpus(&in->handle);
-
- nvdimm_debug("Revision %#x Handler %#x Function %#x.\n", in->revision,
- in->handle, in->function);
-
- /*
- * function 0 is called to inquire which functions are supported by
- * OSPM
- */
- if (in->function == 0) {
- NvdimmDsmFunc0Out func0 = {
- .len = cpu_to_le32(sizeof(func0)),
- /* No function supported other than function 0 */
- .supported_func = cpu_to_le32(0),
- };
- cpu_physical_memory_write(dsm_mem_addr, &func0, sizeof func0);
- } else {
- /* No function except function 0 is supported yet. */
- NvdimmDsmFuncNoPayloadOut out = {
- .len = cpu_to_le32(sizeof(out)),
- .func_ret_status = cpu_to_le32(1) /* Not Supported */,
- };
- cpu_physical_memory_write(dsm_mem_addr, &out, sizeof(out));
- }
-
- g_free(in);
-}
-
-static const MemoryRegionOps nvdimm_dsm_ops = {
- .read = nvdimm_dsm_read,
- .write = nvdimm_dsm_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-void nvdimm_init_acpi_state(AcpiNVDIMMState *state, MemoryRegion *io,
- FWCfgState *fw_cfg, Object *owner)
-{
- memory_region_init_io(&state->io_mr, owner, &nvdimm_dsm_ops, state,
- "nvdimm-acpi-io", NVDIMM_ACPI_IO_LEN);
- memory_region_add_subregion(io, NVDIMM_ACPI_IO_BASE, &state->io_mr);
-
- state->dsm_mem = g_array_new(false, true /* clear */, 1);
- acpi_data_push(state->dsm_mem, TARGET_PAGE_SIZE);
- fw_cfg_add_file(fw_cfg, NVDIMM_DSM_MEM_FILE, state->dsm_mem->data,
- state->dsm_mem->len);
-}
-
-#define NVDIMM_COMMON_DSM "NCAL"
-#define NVDIMM_ACPI_MEM_ADDR "MEMA"
-
-static void nvdimm_build_common_dsm(Aml *dev)
-{
- Aml *method, *ifctx, *function, *dsm_mem, *unpatched, *result_size;
- uint8_t byte_list[1];
-
- method = aml_method(NVDIMM_COMMON_DSM, 4, AML_SERIALIZED);
- function = aml_arg(2);
- dsm_mem = aml_name(NVDIMM_ACPI_MEM_ADDR);
-
- /*
- * do not support any method if DSM memory address has not been
- * patched.
- */
- unpatched = aml_if(aml_equal(dsm_mem, aml_int(0x0)));
-
- /*
- * function 0 is called to inquire what functions are supported by
- * OSPM
- */
- ifctx = aml_if(aml_equal(function, aml_int(0)));
- byte_list[0] = 0 /* No function Supported */;
- aml_append(ifctx, aml_return(aml_buffer(1, byte_list)));
- aml_append(unpatched, ifctx);
-
- /* No function is supported yet. */
- byte_list[0] = 1 /* Not Supported */;
- aml_append(unpatched, aml_return(aml_buffer(1, byte_list)));
- aml_append(method, unpatched);
-
- /*
- * The HDLE indicates the DSM function is issued from which device,
- * it is not used at this time as no function is supported yet.
- * Currently we make it always be 0 for all the devices and will set
- * the appropriate value once real function is implemented.
- */
- aml_append(method, aml_store(aml_int(0x0), aml_name("HDLE")));
- aml_append(method, aml_store(aml_arg(1), aml_name("REVS")));
- aml_append(method, aml_store(aml_arg(2), aml_name("FUNC")));
-
- /*
- * tell QEMU about the real address of DSM memory, then QEMU
- * gets the control and fills the result in DSM memory.
- */
- aml_append(method, aml_store(dsm_mem, aml_name("NTFI")));
-
- result_size = aml_local(1);
- aml_append(method, aml_store(aml_name("RLEN"), result_size));
- aml_append(method, aml_store(aml_shiftleft(result_size, aml_int(3)),
- result_size));
- aml_append(method, aml_create_field(aml_name("ODAT"), aml_int(0),
- result_size, "OBUF"));
- aml_append(method, aml_concatenate(aml_buffer(0, NULL), aml_name("OBUF"),
- aml_arg(6)));
- aml_append(method, aml_return(aml_arg(6)));
- aml_append(dev, method);
-}
-
-static void nvdimm_build_device_dsm(Aml *dev)
-{
- Aml *method;
-
- method = aml_method("_DSM", 4, AML_NOTSERIALIZED);
- aml_append(method, aml_return(aml_call4(NVDIMM_COMMON_DSM, aml_arg(0),
- aml_arg(1), aml_arg(2), aml_arg(3))));
- aml_append(dev, method);
-}
-
-static void nvdimm_build_nvdimm_devices(GSList *device_list, Aml *root_dev)
-{
- for (; device_list; device_list = device_list->next) {
- DeviceState *dev = device_list->data;
- int slot = object_property_get_int(OBJECT(dev), PC_DIMM_SLOT_PROP,
- NULL);
- uint32_t handle = nvdimm_slot_to_handle(slot);
- Aml *nvdimm_dev;
-
- nvdimm_dev = aml_device("NV%02X", slot);
-
- /*
- * ACPI 6.0: 9.20 NVDIMM Devices:
- *
- * _ADR object that is used to supply OSPM with unique address
- * of the NVDIMM device. This is done by returning the NFIT Device
- * handle that is used to identify the associated entries in ACPI
- * table NFIT or _FIT.
- */
- aml_append(nvdimm_dev, aml_name_decl("_ADR", aml_int(handle)));
-
- nvdimm_build_device_dsm(nvdimm_dev);
- aml_append(root_dev, nvdimm_dev);
- }
-}
-
-static void nvdimm_build_ssdt(GSList *device_list, GArray *table_offsets,
- GArray *table_data, GArray *linker)
-{
- Aml *ssdt, *sb_scope, *dev, *field;
- int mem_addr_offset, nvdimm_ssdt;
-
- acpi_add_table(table_offsets, table_data);
-
- ssdt = init_aml_allocator();
- acpi_data_push(ssdt->buf, sizeof(AcpiTableHeader));
-
- sb_scope = aml_scope("\\_SB");
-
- dev = aml_device("NVDR");
-
- /*
- * ACPI 6.0: 9.20 NVDIMM Devices:
- *
- * The ACPI Name Space device uses _HID of ACPI0012 to identify the root
- * NVDIMM interface device. Platform firmware is required to contain one
- * such device in _SB scope if NVDIMMs support is exposed by platform to
- * OSPM.
- * For each NVDIMM present or intended to be supported by platform,
- * platform firmware also exposes an ACPI Namespace Device under the
- * root device.
- */
- aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0012")));
-
- /* map DSM memory and IO into ACPI namespace. */
- aml_append(dev, aml_operation_region("NPIO", AML_SYSTEM_IO,
- aml_int(NVDIMM_ACPI_IO_BASE), NVDIMM_ACPI_IO_LEN));
- aml_append(dev, aml_operation_region("NRAM", AML_SYSTEM_MEMORY,
- aml_name(NVDIMM_ACPI_MEM_ADDR), TARGET_PAGE_SIZE));
-
- /*
- * DSM notifier:
- * NTFI: write the address of DSM memory and notify QEMU to emulate
- * the access.
- *
- * It is the IO port so that accessing them will cause VM-exit, the
- * control will be transferred to QEMU.
- */
- field = aml_field("NPIO", AML_DWORD_ACC, AML_NOLOCK, AML_PRESERVE);
- aml_append(field, aml_named_field("NTFI",
- sizeof(uint32_t) * BITS_PER_BYTE));
- aml_append(dev, field);
-
- /*
- * DSM input:
- * HDLE: store device's handle, it's zero if the _DSM call happens
- * on NVDIMM Root Device.
- * REVS: store the Arg1 of _DSM call.
- * FUNC: store the Arg2 of _DSM call.
- * ARG3: store the Arg3 of _DSM call.
- *
- * They are RAM mapping on host so that these accesses never cause
- * VM-EXIT.
- */
- field = aml_field("NRAM", AML_DWORD_ACC, AML_NOLOCK, AML_PRESERVE);
- aml_append(field, aml_named_field("HDLE",
- sizeof(typeof_field(NvdimmDsmIn, handle)) * BITS_PER_BYTE));
- aml_append(field, aml_named_field("REVS",
- sizeof(typeof_field(NvdimmDsmIn, revision)) * BITS_PER_BYTE));
- aml_append(field, aml_named_field("FUNC",
- sizeof(typeof_field(NvdimmDsmIn, function)) * BITS_PER_BYTE));
- aml_append(field, aml_named_field("ARG3",
- (TARGET_PAGE_SIZE - offsetof(NvdimmDsmIn, arg3)) *
- BITS_PER_BYTE));
- aml_append(dev, field);
-
- /*
- * DSM output:
- * RLEN: the size of the buffer filled by QEMU.
- * ODAT: the buffer QEMU uses to store the result.
- *
- * Since the page is reused by both input and out, the input data
- * will be lost after storing new result into ODAT so we should fetch
- * all the input data before writing the result.
- */
- field = aml_field("NRAM", AML_DWORD_ACC, AML_NOLOCK, AML_PRESERVE);
- aml_append(field, aml_named_field("RLEN",
- sizeof(typeof_field(NvdimmDsmOut, len)) * BITS_PER_BYTE));
- aml_append(field, aml_named_field("ODAT",
- (TARGET_PAGE_SIZE - offsetof(NvdimmDsmOut, data)) *
- BITS_PER_BYTE));
- aml_append(dev, field);
-
- nvdimm_build_common_dsm(dev);
- nvdimm_build_device_dsm(dev);
-
- nvdimm_build_nvdimm_devices(device_list, dev);
-
- aml_append(sb_scope, dev);
- aml_append(ssdt, sb_scope);
-
- nvdimm_ssdt = table_data->len;
-
- /* copy AML table into ACPI tables blob and patch header there */
- g_array_append_vals(table_data, ssdt->buf->data, ssdt->buf->len);
- mem_addr_offset = build_append_named_dword(table_data,
- NVDIMM_ACPI_MEM_ADDR);
-
- bios_linker_loader_alloc(linker, NVDIMM_DSM_MEM_FILE, TARGET_PAGE_SIZE,
- false /* high memory */);
- bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE,
- NVDIMM_DSM_MEM_FILE, table_data,
- table_data->data + mem_addr_offset,
- sizeof(uint32_t));
- build_header(linker, table_data,
- (void *)(table_data->data + nvdimm_ssdt),
- "SSDT", table_data->len - nvdimm_ssdt, 1, NULL, "NVDIMM");
- free_aml_allocator();
-}
-
-void nvdimm_build_acpi(GArray *table_offsets, GArray *table_data,
- GArray *linker)
-{
- GSList *device_list;
-
- /* no NVDIMM device is plugged. */
- device_list = nvdimm_get_plugged_device_list();
- if (!device_list) {
- return;
- }
- nvdimm_build_nfit(device_list, table_offsets, table_data, linker);
- nvdimm_build_ssdt(device_list, table_offsets, table_data, linker);
- g_slist_free(device_list);
-}
diff --git a/qemu/hw/acpi/pcihp.c b/qemu/hw/acpi/pcihp.c
deleted file mode 100644
index 71f4c4e14..000000000
--- a/qemu/hw/acpi/pcihp.c
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- * QEMU<->ACPI BIOS PCI hotplug interface
- *
- * QEMU supports PCI hotplug via ACPI. This module
- * implements the interface between QEMU and the ACPI BIOS.
- * Interface specification - see docs/specs/acpi_pci_hotplug.txt
- *
- * Copyright (c) 2013, Red Hat Inc, Michael S. Tsirkin (mst@redhat.com)
- * Copyright (c) 2006 Fabrice Bellard
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2 as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "hw/acpi/pcihp.h"
-
-#include "hw/hw.h"
-#include "hw/i386/pc.h"
-#include "hw/pci/pci.h"
-#include "hw/acpi/acpi.h"
-#include "sysemu/sysemu.h"
-#include "exec/ioport.h"
-#include "exec/address-spaces.h"
-#include "hw/pci/pci_bus.h"
-#include "qapi/error.h"
-#include "qom/qom-qobject.h"
-#include "qapi/qmp/qint.h"
-
-//#define DEBUG
-
-#ifdef DEBUG
-# define ACPI_PCIHP_DPRINTF(format, ...) printf(format, ## __VA_ARGS__)
-#else
-# define ACPI_PCIHP_DPRINTF(format, ...) do { } while (0)
-#endif
-
-#define ACPI_PCIHP_ADDR 0xae00
-#define ACPI_PCIHP_SIZE 0x0014
-#define ACPI_PCIHP_LEGACY_SIZE 0x000f
-#define PCI_UP_BASE 0x0000
-#define PCI_DOWN_BASE 0x0004
-#define PCI_EJ_BASE 0x0008
-#define PCI_RMV_BASE 0x000c
-#define PCI_SEL_BASE 0x0010
-
-typedef struct AcpiPciHpFind {
- int bsel;
- PCIBus *bus;
-} AcpiPciHpFind;
-
-static int acpi_pcihp_get_bsel(PCIBus *bus)
-{
- Error *local_err = NULL;
- int64_t bsel = object_property_get_int(OBJECT(bus), ACPI_PCIHP_PROP_BSEL,
- &local_err);
-
- if (local_err || bsel < 0 || bsel >= ACPI_PCIHP_MAX_HOTPLUG_BUS) {
- if (local_err) {
- error_free(local_err);
- }
- return -1;
- } else {
- return bsel;
- }
-}
-
-static void acpi_pcihp_test_hotplug_bus(PCIBus *bus, void *opaque)
-{
- AcpiPciHpFind *find = opaque;
- if (find->bsel == acpi_pcihp_get_bsel(bus)) {
- find->bus = bus;
- }
-}
-
-static PCIBus *acpi_pcihp_find_hotplug_bus(AcpiPciHpState *s, int bsel)
-{
- AcpiPciHpFind find = { .bsel = bsel, .bus = NULL };
-
- if (bsel < 0) {
- return NULL;
- }
-
- pci_for_each_bus(s->root, acpi_pcihp_test_hotplug_bus, &find);
-
- /* Make bsel 0 eject root bus if bsel property is not set,
- * for compatibility with non acpi setups.
- * TODO: really needed?
- */
- if (!bsel && !find.bus) {
- find.bus = s->root;
- }
- return find.bus;
-}
-
-static bool acpi_pcihp_pc_no_hotplug(AcpiPciHpState *s, PCIDevice *dev)
-{
- PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
- DeviceClass *dc = DEVICE_GET_CLASS(dev);
- /*
- * ACPI doesn't allow hotplug of bridge devices. Don't allow
- * hot-unplug of bridge devices unless they were added by hotplug
- * (and so, not described by acpi).
- */
- return (pc->is_bridge && !dev->qdev.hotplugged) || !dc->hotpluggable;
-}
-
-static void acpi_pcihp_eject_slot(AcpiPciHpState *s, unsigned bsel, unsigned slots)
-{
- BusChild *kid, *next;
- int slot = ctz32(slots);
- PCIBus *bus = acpi_pcihp_find_hotplug_bus(s, bsel);
-
- if (!bus) {
- return;
- }
-
- /* Mark request as complete */
- s->acpi_pcihp_pci_status[bsel].down &= ~(1U << slot);
- s->acpi_pcihp_pci_status[bsel].up &= ~(1U << slot);
-
- QTAILQ_FOREACH_SAFE(kid, &bus->qbus.children, sibling, next) {
- DeviceState *qdev = kid->child;
- PCIDevice *dev = PCI_DEVICE(qdev);
- if (PCI_SLOT(dev->devfn) == slot) {
- if (!acpi_pcihp_pc_no_hotplug(s, dev)) {
- object_unparent(OBJECT(qdev));
- }
- }
- }
-}
-
-static void acpi_pcihp_update_hotplug_bus(AcpiPciHpState *s, int bsel)
-{
- BusChild *kid, *next;
- PCIBus *bus = acpi_pcihp_find_hotplug_bus(s, bsel);
-
- /* Execute any pending removes during reset */
- while (s->acpi_pcihp_pci_status[bsel].down) {
- acpi_pcihp_eject_slot(s, bsel, s->acpi_pcihp_pci_status[bsel].down);
- }
-
- s->acpi_pcihp_pci_status[bsel].hotplug_enable = ~0;
-
- if (!bus) {
- return;
- }
- QTAILQ_FOREACH_SAFE(kid, &bus->qbus.children, sibling, next) {
- DeviceState *qdev = kid->child;
- PCIDevice *pdev = PCI_DEVICE(qdev);
- int slot = PCI_SLOT(pdev->devfn);
-
- if (acpi_pcihp_pc_no_hotplug(s, pdev)) {
- s->acpi_pcihp_pci_status[bsel].hotplug_enable &= ~(1U << slot);
- }
- }
-}
-
-static void acpi_pcihp_update(AcpiPciHpState *s)
-{
- int i;
-
- for (i = 0; i < ACPI_PCIHP_MAX_HOTPLUG_BUS; ++i) {
- acpi_pcihp_update_hotplug_bus(s, i);
- }
-}
-
-void acpi_pcihp_reset(AcpiPciHpState *s)
-{
- acpi_pcihp_update(s);
-}
-
-void acpi_pcihp_device_plug_cb(ACPIREGS *ar, qemu_irq irq, AcpiPciHpState *s,
- DeviceState *dev, Error **errp)
-{
- PCIDevice *pdev = PCI_DEVICE(dev);
- int slot = PCI_SLOT(pdev->devfn);
- int bsel = acpi_pcihp_get_bsel(pdev->bus);
- if (bsel < 0) {
- error_setg(errp, "Unsupported bus. Bus doesn't have property '"
- ACPI_PCIHP_PROP_BSEL "' set");
- return;
- }
-
- /* Don't send event when device is enabled during qemu machine creation:
- * it is present on boot, no hotplug event is necessary. We do send an
- * event when the device is disabled later. */
- if (!dev->hotplugged) {
- return;
- }
-
- s->acpi_pcihp_pci_status[bsel].up |= (1U << slot);
-
- acpi_send_gpe_event(ar, irq, ACPI_PCI_HOTPLUG_STATUS);
-}
-
-void acpi_pcihp_device_unplug_cb(ACPIREGS *ar, qemu_irq irq, AcpiPciHpState *s,
- DeviceState *dev, Error **errp)
-{
- PCIDevice *pdev = PCI_DEVICE(dev);
- int slot = PCI_SLOT(pdev->devfn);
- int bsel = acpi_pcihp_get_bsel(pdev->bus);
- if (bsel < 0) {
- error_setg(errp, "Unsupported bus. Bus doesn't have property '"
- ACPI_PCIHP_PROP_BSEL "' set");
- return;
- }
-
- s->acpi_pcihp_pci_status[bsel].down |= (1U << slot);
-
- acpi_send_gpe_event(ar, irq, ACPI_PCI_HOTPLUG_STATUS);
-}
-
-static uint64_t pci_read(void *opaque, hwaddr addr, unsigned int size)
-{
- AcpiPciHpState *s = opaque;
- uint32_t val = 0;
- int bsel = s->hotplug_select;
-
- if (bsel < 0 || bsel >= ACPI_PCIHP_MAX_HOTPLUG_BUS) {
- return 0;
- }
-
- switch (addr) {
- case PCI_UP_BASE:
- val = s->acpi_pcihp_pci_status[bsel].up;
- if (!s->legacy_piix) {
- s->acpi_pcihp_pci_status[bsel].up = 0;
- }
- ACPI_PCIHP_DPRINTF("pci_up_read %" PRIu32 "\n", val);
- break;
- case PCI_DOWN_BASE:
- val = s->acpi_pcihp_pci_status[bsel].down;
- ACPI_PCIHP_DPRINTF("pci_down_read %" PRIu32 "\n", val);
- break;
- case PCI_EJ_BASE:
- /* No feature defined yet */
- ACPI_PCIHP_DPRINTF("pci_features_read %" PRIu32 "\n", val);
- break;
- case PCI_RMV_BASE:
- val = s->acpi_pcihp_pci_status[bsel].hotplug_enable;
- ACPI_PCIHP_DPRINTF("pci_rmv_read %" PRIu32 "\n", val);
- break;
- case PCI_SEL_BASE:
- val = s->hotplug_select;
- ACPI_PCIHP_DPRINTF("pci_sel_read %" PRIu32 "\n", val);
- default:
- break;
- }
-
- return val;
-}
-
-static void pci_write(void *opaque, hwaddr addr, uint64_t data,
- unsigned int size)
-{
- AcpiPciHpState *s = opaque;
- switch (addr) {
- case PCI_EJ_BASE:
- if (s->hotplug_select >= ACPI_PCIHP_MAX_HOTPLUG_BUS) {
- break;
- }
- acpi_pcihp_eject_slot(s, s->hotplug_select, data);
- ACPI_PCIHP_DPRINTF("pciej write %" HWADDR_PRIx " <== %" PRIu64 "\n",
- addr, data);
- break;
- case PCI_SEL_BASE:
- s->hotplug_select = data;
- ACPI_PCIHP_DPRINTF("pcisel write %" HWADDR_PRIx " <== %" PRIu64 "\n",
- addr, data);
- default:
- break;
- }
-}
-
-static const MemoryRegionOps acpi_pcihp_io_ops = {
- .read = pci_read,
- .write = pci_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-void acpi_pcihp_init(Object *owner, AcpiPciHpState *s, PCIBus *root_bus,
- MemoryRegion *address_space_io, bool bridges_enabled)
-{
- s->io_len = ACPI_PCIHP_SIZE;
- s->io_base = ACPI_PCIHP_ADDR;
-
- s->root= root_bus;
- s->legacy_piix = !bridges_enabled;
-
- if (s->legacy_piix) {
- unsigned *bus_bsel = g_malloc(sizeof *bus_bsel);
-
- s->io_len = ACPI_PCIHP_LEGACY_SIZE;
-
- *bus_bsel = ACPI_PCIHP_BSEL_DEFAULT;
- object_property_add_uint32_ptr(OBJECT(root_bus), ACPI_PCIHP_PROP_BSEL,
- bus_bsel, NULL);
- }
-
- memory_region_init_io(&s->io, owner, &acpi_pcihp_io_ops, s,
- "acpi-pci-hotplug", s->io_len);
- memory_region_add_subregion(address_space_io, s->io_base, &s->io);
-
- object_property_add_uint16_ptr(owner, ACPI_PCIHP_IO_BASE_PROP, &s->io_base,
- &error_abort);
- object_property_add_uint16_ptr(owner, ACPI_PCIHP_IO_LEN_PROP, &s->io_len,
- &error_abort);
-}
-
-const VMStateDescription vmstate_acpi_pcihp_pci_status = {
- .name = "acpi_pcihp_pci_status",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(up, AcpiPciHpPciStatus),
- VMSTATE_UINT32(down, AcpiPciHpPciStatus),
- VMSTATE_END_OF_LIST()
- }
-};
diff --git a/qemu/hw/acpi/piix4.c b/qemu/hw/acpi/piix4.c
deleted file mode 100644
index 16abdf162..000000000
--- a/qemu/hw/acpi/piix4.c
+++ /dev/null
@@ -1,645 +0,0 @@
-/*
- * ACPI implementation
- *
- * Copyright (c) 2006 Fabrice Bellard
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2 as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/i386/pc.h"
-#include "hw/isa/apm.h"
-#include "hw/i2c/pm_smbus.h"
-#include "hw/pci/pci.h"
-#include "hw/acpi/acpi.h"
-#include "sysemu/sysemu.h"
-#include "qapi/error.h"
-#include "qemu/range.h"
-#include "exec/ioport.h"
-#include "hw/nvram/fw_cfg.h"
-#include "exec/address-spaces.h"
-#include "hw/acpi/piix4.h"
-#include "hw/acpi/pcihp.h"
-#include "hw/acpi/cpu_hotplug.h"
-#include "hw/hotplug.h"
-#include "hw/mem/pc-dimm.h"
-#include "hw/acpi/memory_hotplug.h"
-#include "hw/acpi/acpi_dev_interface.h"
-#include "hw/xen/xen.h"
-
-//#define DEBUG
-
-#ifdef DEBUG
-# define PIIX4_DPRINTF(format, ...) printf(format, ## __VA_ARGS__)
-#else
-# define PIIX4_DPRINTF(format, ...) do { } while (0)
-#endif
-
-#define GPE_BASE 0xafe0
-#define GPE_LEN 4
-
-struct pci_status {
- uint32_t up; /* deprecated, maintained for migration compatibility */
- uint32_t down;
-};
-
-typedef struct PIIX4PMState {
- /*< private >*/
- PCIDevice parent_obj;
- /*< public >*/
-
- MemoryRegion io;
- uint32_t io_base;
-
- MemoryRegion io_gpe;
- ACPIREGS ar;
-
- APMState apm;
-
- PMSMBus smb;
- uint32_t smb_io_base;
-
- qemu_irq irq;
- qemu_irq smi_irq;
- int smm_enabled;
- Notifier machine_ready;
- Notifier powerdown_notifier;
-
- AcpiPciHpState acpi_pci_hotplug;
- bool use_acpi_pci_hotplug;
-
- uint8_t disable_s3;
- uint8_t disable_s4;
- uint8_t s4_val;
-
- AcpiCpuHotplug gpe_cpu;
-
- MemHotplugState acpi_memory_hotplug;
-} PIIX4PMState;
-
-#define TYPE_PIIX4_PM "PIIX4_PM"
-
-#define PIIX4_PM(obj) \
- OBJECT_CHECK(PIIX4PMState, (obj), TYPE_PIIX4_PM)
-
-static void piix4_acpi_system_hot_add_init(MemoryRegion *parent,
- PCIBus *bus, PIIX4PMState *s);
-
-#define ACPI_ENABLE 0xf1
-#define ACPI_DISABLE 0xf0
-
-static void pm_tmr_timer(ACPIREGS *ar)
-{
- PIIX4PMState *s = container_of(ar, PIIX4PMState, ar);
- acpi_update_sci(&s->ar, s->irq);
-}
-
-static void apm_ctrl_changed(uint32_t val, void *arg)
-{
- PIIX4PMState *s = arg;
- PCIDevice *d = PCI_DEVICE(s);
-
- /* ACPI specs 3.0, 4.7.2.5 */
- acpi_pm1_cnt_update(&s->ar, val == ACPI_ENABLE, val == ACPI_DISABLE);
- if (val == ACPI_ENABLE || val == ACPI_DISABLE) {
- return;
- }
-
- if (d->config[0x5b] & (1 << 1)) {
- if (s->smi_irq) {
- qemu_irq_raise(s->smi_irq);
- }
- }
-}
-
-static void pm_io_space_update(PIIX4PMState *s)
-{
- PCIDevice *d = PCI_DEVICE(s);
-
- s->io_base = le32_to_cpu(*(uint32_t *)(d->config + 0x40));
- s->io_base &= 0xffc0;
-
- memory_region_transaction_begin();
- memory_region_set_enabled(&s->io, d->config[0x80] & 1);
- memory_region_set_address(&s->io, s->io_base);
- memory_region_transaction_commit();
-}
-
-static void smbus_io_space_update(PIIX4PMState *s)
-{
- PCIDevice *d = PCI_DEVICE(s);
-
- s->smb_io_base = le32_to_cpu(*(uint32_t *)(d->config + 0x90));
- s->smb_io_base &= 0xffc0;
-
- memory_region_transaction_begin();
- memory_region_set_enabled(&s->smb.io, d->config[0xd2] & 1);
- memory_region_set_address(&s->smb.io, s->smb_io_base);
- memory_region_transaction_commit();
-}
-
-static void pm_write_config(PCIDevice *d,
- uint32_t address, uint32_t val, int len)
-{
- pci_default_write_config(d, address, val, len);
- if (range_covers_byte(address, len, 0x80) ||
- ranges_overlap(address, len, 0x40, 4)) {
- pm_io_space_update((PIIX4PMState *)d);
- }
- if (range_covers_byte(address, len, 0xd2) ||
- ranges_overlap(address, len, 0x90, 4)) {
- smbus_io_space_update((PIIX4PMState *)d);
- }
-}
-
-static int vmstate_acpi_post_load(void *opaque, int version_id)
-{
- PIIX4PMState *s = opaque;
-
- pm_io_space_update(s);
- return 0;
-}
-
-#define VMSTATE_GPE_ARRAY(_field, _state) \
- { \
- .name = (stringify(_field)), \
- .version_id = 0, \
- .info = &vmstate_info_uint16, \
- .size = sizeof(uint16_t), \
- .flags = VMS_SINGLE | VMS_POINTER, \
- .offset = vmstate_offset_pointer(_state, _field, uint8_t), \
- }
-
-static const VMStateDescription vmstate_gpe = {
- .name = "gpe",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_GPE_ARRAY(sts, ACPIGPE),
- VMSTATE_GPE_ARRAY(en, ACPIGPE),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_pci_status = {
- .name = "pci_status",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(up, struct AcpiPciHpPciStatus),
- VMSTATE_UINT32(down, struct AcpiPciHpPciStatus),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static int acpi_load_old(QEMUFile *f, void *opaque, int version_id)
-{
- PIIX4PMState *s = opaque;
- int ret, i;
- uint16_t temp;
-
- ret = pci_device_load(PCI_DEVICE(s), f);
- if (ret < 0) {
- return ret;
- }
- qemu_get_be16s(f, &s->ar.pm1.evt.sts);
- qemu_get_be16s(f, &s->ar.pm1.evt.en);
- qemu_get_be16s(f, &s->ar.pm1.cnt.cnt);
-
- ret = vmstate_load_state(f, &vmstate_apm, &s->apm, 1);
- if (ret) {
- return ret;
- }
-
- timer_get(f, s->ar.tmr.timer);
- qemu_get_sbe64s(f, &s->ar.tmr.overflow_time);
-
- qemu_get_be16s(f, (uint16_t *)s->ar.gpe.sts);
- for (i = 0; i < 3; i++) {
- qemu_get_be16s(f, &temp);
- }
-
- qemu_get_be16s(f, (uint16_t *)s->ar.gpe.en);
- for (i = 0; i < 3; i++) {
- qemu_get_be16s(f, &temp);
- }
-
- ret = vmstate_load_state(f, &vmstate_pci_status,
- &s->acpi_pci_hotplug.acpi_pcihp_pci_status[ACPI_PCIHP_BSEL_DEFAULT], 1);
- return ret;
-}
-
-static bool vmstate_test_use_acpi_pci_hotplug(void *opaque, int version_id)
-{
- PIIX4PMState *s = opaque;
- return s->use_acpi_pci_hotplug;
-}
-
-static bool vmstate_test_no_use_acpi_pci_hotplug(void *opaque, int version_id)
-{
- PIIX4PMState *s = opaque;
- return !s->use_acpi_pci_hotplug;
-}
-
-static bool vmstate_test_use_memhp(void *opaque)
-{
- PIIX4PMState *s = opaque;
- return s->acpi_memory_hotplug.is_enabled;
-}
-
-static const VMStateDescription vmstate_memhp_state = {
- .name = "piix4_pm/memhp",
- .version_id = 1,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .needed = vmstate_test_use_memhp,
- .fields = (VMStateField[]) {
- VMSTATE_MEMORY_HOTPLUG(acpi_memory_hotplug, PIIX4PMState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-/* qemu-kvm 1.2 uses version 3 but advertised as 2
- * To support incoming qemu-kvm 1.2 migration, change version_id
- * and minimum_version_id to 2 below (which breaks migration from
- * qemu 1.2).
- *
- */
-static const VMStateDescription vmstate_acpi = {
- .name = "piix4_pm",
- .version_id = 3,
- .minimum_version_id = 3,
- .minimum_version_id_old = 1,
- .load_state_old = acpi_load_old,
- .post_load = vmstate_acpi_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(parent_obj, PIIX4PMState),
- VMSTATE_UINT16(ar.pm1.evt.sts, PIIX4PMState),
- VMSTATE_UINT16(ar.pm1.evt.en, PIIX4PMState),
- VMSTATE_UINT16(ar.pm1.cnt.cnt, PIIX4PMState),
- VMSTATE_STRUCT(apm, PIIX4PMState, 0, vmstate_apm, APMState),
- VMSTATE_TIMER_PTR(ar.tmr.timer, PIIX4PMState),
- VMSTATE_INT64(ar.tmr.overflow_time, PIIX4PMState),
- VMSTATE_STRUCT(ar.gpe, PIIX4PMState, 2, vmstate_gpe, ACPIGPE),
- VMSTATE_STRUCT_TEST(
- acpi_pci_hotplug.acpi_pcihp_pci_status[ACPI_PCIHP_BSEL_DEFAULT],
- PIIX4PMState,
- vmstate_test_no_use_acpi_pci_hotplug,
- 2, vmstate_pci_status,
- struct AcpiPciHpPciStatus),
- VMSTATE_PCI_HOTPLUG(acpi_pci_hotplug, PIIX4PMState,
- vmstate_test_use_acpi_pci_hotplug),
- VMSTATE_END_OF_LIST()
- },
- .subsections = (const VMStateDescription*[]) {
- &vmstate_memhp_state,
- NULL
- }
-};
-
-static void piix4_reset(void *opaque)
-{
- PIIX4PMState *s = opaque;
- PCIDevice *d = PCI_DEVICE(s);
- uint8_t *pci_conf = d->config;
-
- pci_conf[0x58] = 0;
- pci_conf[0x59] = 0;
- pci_conf[0x5a] = 0;
- pci_conf[0x5b] = 0;
-
- pci_conf[0x40] = 0x01; /* PM io base read only bit */
- pci_conf[0x80] = 0;
-
- if (!s->smm_enabled) {
- /* Mark SMM as already inited (until KVM supports SMM). */
- pci_conf[0x5B] = 0x02;
- }
- pm_io_space_update(s);
- acpi_pcihp_reset(&s->acpi_pci_hotplug);
-}
-
-static void piix4_pm_powerdown_req(Notifier *n, void *opaque)
-{
- PIIX4PMState *s = container_of(n, PIIX4PMState, powerdown_notifier);
-
- assert(s != NULL);
- acpi_pm1_evt_power_down(&s->ar);
-}
-
-static void piix4_device_plug_cb(HotplugHandler *hotplug_dev,
- DeviceState *dev, Error **errp)
-{
- PIIX4PMState *s = PIIX4_PM(hotplug_dev);
-
- if (s->acpi_memory_hotplug.is_enabled &&
- object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
- acpi_memory_plug_cb(&s->ar, s->irq, &s->acpi_memory_hotplug, dev, errp);
- } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
- acpi_pcihp_device_plug_cb(&s->ar, s->irq, &s->acpi_pci_hotplug, dev,
- errp);
- } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
- acpi_cpu_plug_cb(&s->ar, s->irq, &s->gpe_cpu, dev, errp);
- } else {
- error_setg(errp, "acpi: device plug request for not supported device"
- " type: %s", object_get_typename(OBJECT(dev)));
- }
-}
-
-static void piix4_device_unplug_request_cb(HotplugHandler *hotplug_dev,
- DeviceState *dev, Error **errp)
-{
- PIIX4PMState *s = PIIX4_PM(hotplug_dev);
-
- if (s->acpi_memory_hotplug.is_enabled &&
- object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
- acpi_memory_unplug_request_cb(&s->ar, s->irq, &s->acpi_memory_hotplug,
- dev, errp);
- } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
- acpi_pcihp_device_unplug_cb(&s->ar, s->irq, &s->acpi_pci_hotplug, dev,
- errp);
- } else {
- error_setg(errp, "acpi: device unplug request for not supported device"
- " type: %s", object_get_typename(OBJECT(dev)));
- }
-}
-
-static void piix4_device_unplug_cb(HotplugHandler *hotplug_dev,
- DeviceState *dev, Error **errp)
-{
- PIIX4PMState *s = PIIX4_PM(hotplug_dev);
-
- if (s->acpi_memory_hotplug.is_enabled &&
- object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
- acpi_memory_unplug_cb(&s->acpi_memory_hotplug, dev, errp);
- } else {
- error_setg(errp, "acpi: device unplug for not supported device"
- " type: %s", object_get_typename(OBJECT(dev)));
- }
-}
-
-static void piix4_update_bus_hotplug(PCIBus *pci_bus, void *opaque)
-{
- PIIX4PMState *s = opaque;
-
- qbus_set_hotplug_handler(BUS(pci_bus), DEVICE(s), &error_abort);
-}
-
-static void piix4_pm_machine_ready(Notifier *n, void *opaque)
-{
- PIIX4PMState *s = container_of(n, PIIX4PMState, machine_ready);
- PCIDevice *d = PCI_DEVICE(s);
- MemoryRegion *io_as = pci_address_space_io(d);
- uint8_t *pci_conf;
-
- pci_conf = d->config;
- pci_conf[0x5f] = 0x10 |
- (memory_region_present(io_as, 0x378) ? 0x80 : 0);
- pci_conf[0x63] = 0x60;
- pci_conf[0x67] = (memory_region_present(io_as, 0x3f8) ? 0x08 : 0) |
- (memory_region_present(io_as, 0x2f8) ? 0x90 : 0);
-
- if (s->use_acpi_pci_hotplug) {
- pci_for_each_bus(d->bus, piix4_update_bus_hotplug, s);
- } else {
- piix4_update_bus_hotplug(d->bus, s);
- }
-}
-
-static void piix4_pm_add_propeties(PIIX4PMState *s)
-{
- static const uint8_t acpi_enable_cmd = ACPI_ENABLE;
- static const uint8_t acpi_disable_cmd = ACPI_DISABLE;
- static const uint32_t gpe0_blk = GPE_BASE;
- static const uint32_t gpe0_blk_len = GPE_LEN;
- static const uint16_t sci_int = 9;
-
- object_property_add_uint8_ptr(OBJECT(s), ACPI_PM_PROP_ACPI_ENABLE_CMD,
- &acpi_enable_cmd, NULL);
- object_property_add_uint8_ptr(OBJECT(s), ACPI_PM_PROP_ACPI_DISABLE_CMD,
- &acpi_disable_cmd, NULL);
- object_property_add_uint32_ptr(OBJECT(s), ACPI_PM_PROP_GPE0_BLK,
- &gpe0_blk, NULL);
- object_property_add_uint32_ptr(OBJECT(s), ACPI_PM_PROP_GPE0_BLK_LEN,
- &gpe0_blk_len, NULL);
- object_property_add_uint16_ptr(OBJECT(s), ACPI_PM_PROP_SCI_INT,
- &sci_int, NULL);
- object_property_add_uint32_ptr(OBJECT(s), ACPI_PM_PROP_PM_IO_BASE,
- &s->io_base, NULL);
-}
-
-static void piix4_pm_realize(PCIDevice *dev, Error **errp)
-{
- PIIX4PMState *s = PIIX4_PM(dev);
- uint8_t *pci_conf;
-
- pci_conf = dev->config;
- pci_conf[0x06] = 0x80;
- pci_conf[0x07] = 0x02;
- pci_conf[0x09] = 0x00;
- pci_conf[0x3d] = 0x01; // interrupt pin 1
-
- /* APM */
- apm_init(dev, &s->apm, apm_ctrl_changed, s);
-
- if (!s->smm_enabled) {
- /* Mark SMM as already inited to prevent SMM from running. KVM does not
- * support SMM mode. */
- pci_conf[0x5B] = 0x02;
- }
-
- /* XXX: which specification is used ? The i82731AB has different
- mappings */
- pci_conf[0x90] = s->smb_io_base | 1;
- pci_conf[0x91] = s->smb_io_base >> 8;
- pci_conf[0xd2] = 0x09;
- pm_smbus_init(DEVICE(dev), &s->smb);
- memory_region_set_enabled(&s->smb.io, pci_conf[0xd2] & 1);
- memory_region_add_subregion(pci_address_space_io(dev),
- s->smb_io_base, &s->smb.io);
-
- memory_region_init(&s->io, OBJECT(s), "piix4-pm", 64);
- memory_region_set_enabled(&s->io, false);
- memory_region_add_subregion(pci_address_space_io(dev),
- 0, &s->io);
-
- acpi_pm_tmr_init(&s->ar, pm_tmr_timer, &s->io);
- acpi_pm1_evt_init(&s->ar, pm_tmr_timer, &s->io);
- acpi_pm1_cnt_init(&s->ar, &s->io, s->disable_s3, s->disable_s4, s->s4_val);
- acpi_gpe_init(&s->ar, GPE_LEN);
-
- s->powerdown_notifier.notify = piix4_pm_powerdown_req;
- qemu_register_powerdown_notifier(&s->powerdown_notifier);
-
- s->machine_ready.notify = piix4_pm_machine_ready;
- qemu_add_machine_init_done_notifier(&s->machine_ready);
- qemu_register_reset(piix4_reset, s);
-
- piix4_acpi_system_hot_add_init(pci_address_space_io(dev), dev->bus, s);
-
- piix4_pm_add_propeties(s);
-}
-
-Object *piix4_pm_find(void)
-{
- bool ambig;
- Object *o = object_resolve_path_type("", TYPE_PIIX4_PM, &ambig);
-
- if (ambig || !o) {
- return NULL;
- }
- return o;
-}
-
-I2CBus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
- qemu_irq sci_irq, qemu_irq smi_irq,
- int smm_enabled, DeviceState **piix4_pm)
-{
- DeviceState *dev;
- PIIX4PMState *s;
-
- dev = DEVICE(pci_create(bus, devfn, TYPE_PIIX4_PM));
- qdev_prop_set_uint32(dev, "smb_io_base", smb_io_base);
- if (piix4_pm) {
- *piix4_pm = dev;
- }
-
- s = PIIX4_PM(dev);
- s->irq = sci_irq;
- s->smi_irq = smi_irq;
- s->smm_enabled = smm_enabled;
- if (xen_enabled()) {
- s->use_acpi_pci_hotplug = false;
- }
-
- qdev_init_nofail(dev);
-
- return s->smb.smbus;
-}
-
-static uint64_t gpe_readb(void *opaque, hwaddr addr, unsigned width)
-{
- PIIX4PMState *s = opaque;
- uint32_t val = acpi_gpe_ioport_readb(&s->ar, addr);
-
- PIIX4_DPRINTF("gpe read %" HWADDR_PRIx " == %" PRIu32 "\n", addr, val);
- return val;
-}
-
-static void gpe_writeb(void *opaque, hwaddr addr, uint64_t val,
- unsigned width)
-{
- PIIX4PMState *s = opaque;
-
- acpi_gpe_ioport_writeb(&s->ar, addr, val);
- acpi_update_sci(&s->ar, s->irq);
-
- PIIX4_DPRINTF("gpe write %" HWADDR_PRIx " <== %" PRIu64 "\n", addr, val);
-}
-
-static const MemoryRegionOps piix4_gpe_ops = {
- .read = gpe_readb,
- .write = gpe_writeb,
- .valid.min_access_size = 1,
- .valid.max_access_size = 4,
- .impl.min_access_size = 1,
- .impl.max_access_size = 1,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void piix4_acpi_system_hot_add_init(MemoryRegion *parent,
- PCIBus *bus, PIIX4PMState *s)
-{
- memory_region_init_io(&s->io_gpe, OBJECT(s), &piix4_gpe_ops, s,
- "acpi-gpe0", GPE_LEN);
- memory_region_add_subregion(parent, GPE_BASE, &s->io_gpe);
-
- acpi_pcihp_init(OBJECT(s), &s->acpi_pci_hotplug, bus, parent,
- s->use_acpi_pci_hotplug);
-
- acpi_cpu_hotplug_init(parent, OBJECT(s), &s->gpe_cpu,
- PIIX4_CPU_HOTPLUG_IO_BASE);
-
- if (s->acpi_memory_hotplug.is_enabled) {
- acpi_memory_hotplug_init(parent, OBJECT(s), &s->acpi_memory_hotplug);
- }
-}
-
-static void piix4_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list)
-{
- PIIX4PMState *s = PIIX4_PM(adev);
-
- acpi_memory_ospm_status(&s->acpi_memory_hotplug, list);
-}
-
-static Property piix4_pm_properties[] = {
- DEFINE_PROP_UINT32("smb_io_base", PIIX4PMState, smb_io_base, 0),
- DEFINE_PROP_UINT8(ACPI_PM_PROP_S3_DISABLED, PIIX4PMState, disable_s3, 0),
- DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_DISABLED, PIIX4PMState, disable_s4, 0),
- DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_VAL, PIIX4PMState, s4_val, 2),
- DEFINE_PROP_BOOL("acpi-pci-hotplug-with-bridge-support", PIIX4PMState,
- use_acpi_pci_hotplug, true),
- DEFINE_PROP_BOOL("memory-hotplug-support", PIIX4PMState,
- acpi_memory_hotplug.is_enabled, true),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void piix4_pm_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
- AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_CLASS(klass);
-
- k->realize = piix4_pm_realize;
- k->config_write = pm_write_config;
- k->vendor_id = PCI_VENDOR_ID_INTEL;
- k->device_id = PCI_DEVICE_ID_INTEL_82371AB_3;
- k->revision = 0x03;
- k->class_id = PCI_CLASS_BRIDGE_OTHER;
- dc->desc = "PM";
- dc->vmsd = &vmstate_acpi;
- dc->props = piix4_pm_properties;
- /*
- * Reason: part of PIIX4 southbridge, needs to be wired up,
- * e.g. by mips_malta_init()
- */
- dc->cannot_instantiate_with_device_add_yet = true;
- dc->hotpluggable = false;
- hc->plug = piix4_device_plug_cb;
- hc->unplug_request = piix4_device_unplug_request_cb;
- hc->unplug = piix4_device_unplug_cb;
- adevc->ospm_status = piix4_ospm_status;
-}
-
-static const TypeInfo piix4_pm_info = {
- .name = TYPE_PIIX4_PM,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(PIIX4PMState),
- .class_init = piix4_pm_class_init,
- .interfaces = (InterfaceInfo[]) {
- { TYPE_HOTPLUG_HANDLER },
- { TYPE_ACPI_DEVICE_IF },
- { }
- }
-};
-
-static void piix4_pm_register_types(void)
-{
- type_register_static(&piix4_pm_info);
-}
-
-type_init(piix4_pm_register_types)
diff --git a/qemu/hw/acpi/tco.c b/qemu/hw/acpi/tco.c
deleted file mode 100644
index 8ce7daf23..000000000
--- a/qemu/hw/acpi/tco.c
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * QEMU ICH9 TCO emulation
- *
- * Copyright (c) 2015 Paulo Alcantara <pcacjr@zytor.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "sysemu/watchdog.h"
-#include "hw/i386/ich9.h"
-
-#include "hw/acpi/tco.h"
-
-//#define DEBUG
-
-#ifdef DEBUG
-#define TCO_DEBUG(fmt, ...) \
- do { \
- fprintf(stderr, "%s "fmt, __func__, ## __VA_ARGS__); \
- } while (0)
-#else
-#define TCO_DEBUG(fmt, ...) do { } while (0)
-#endif
-
-enum {
- TCO_RLD_DEFAULT = 0x0000,
- TCO_DAT_IN_DEFAULT = 0x00,
- TCO_DAT_OUT_DEFAULT = 0x00,
- TCO1_STS_DEFAULT = 0x0000,
- TCO2_STS_DEFAULT = 0x0000,
- TCO1_CNT_DEFAULT = 0x0000,
- TCO2_CNT_DEFAULT = 0x0008,
- TCO_MESSAGE1_DEFAULT = 0x00,
- TCO_MESSAGE2_DEFAULT = 0x00,
- TCO_WDCNT_DEFAULT = 0x00,
- TCO_TMR_DEFAULT = 0x0004,
- SW_IRQ_GEN_DEFAULT = 0x03,
-};
-
-static inline void tco_timer_reload(TCOIORegs *tr)
-{
- tr->expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- ((int64_t)(tr->tco.tmr & TCO_TMR_MASK) * TCO_TICK_NSEC);
- timer_mod(tr->tco_timer, tr->expire_time);
-}
-
-static inline void tco_timer_stop(TCOIORegs *tr)
-{
- tr->expire_time = -1;
-}
-
-static void tco_timer_expired(void *opaque)
-{
- TCOIORegs *tr = opaque;
- ICH9LPCPMRegs *pm = container_of(tr, ICH9LPCPMRegs, tco_regs);
- ICH9LPCState *lpc = container_of(pm, ICH9LPCState, pm);
- uint32_t gcs = pci_get_long(lpc->chip_config + ICH9_CC_GCS);
-
- tr->tco.rld = 0;
- tr->tco.sts1 |= TCO_TIMEOUT;
- if (++tr->timeouts_no == 2) {
- tr->tco.sts2 |= TCO_SECOND_TO_STS;
- tr->tco.sts2 |= TCO_BOOT_STS;
- tr->timeouts_no = 0;
-
- if (!lpc->pin_strap.spkr_hi && !(gcs & ICH9_CC_GCS_NO_REBOOT)) {
- watchdog_perform_action();
- tco_timer_stop(tr);
- return;
- }
- }
-
- if (pm->smi_en & ICH9_PMIO_SMI_EN_TCO_EN) {
- ich9_generate_smi();
- } else {
- ich9_generate_nmi();
- }
- tr->tco.rld = tr->tco.tmr;
- tco_timer_reload(tr);
-}
-
-/* NOTE: values of 0 or 1 will be ignored by ICH */
-static inline int can_start_tco_timer(TCOIORegs *tr)
-{
- return !(tr->tco.cnt1 & TCO_TMR_HLT) && tr->tco.tmr > 1;
-}
-
-static uint32_t tco_ioport_readw(TCOIORegs *tr, uint32_t addr)
-{
- uint16_t rld;
-
- switch (addr) {
- case TCO_RLD:
- if (tr->expire_time != -1) {
- int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- int64_t elapsed = (tr->expire_time - now) / TCO_TICK_NSEC;
- rld = (uint16_t)elapsed | (tr->tco.rld & ~TCO_RLD_MASK);
- } else {
- rld = tr->tco.rld;
- }
- return rld;
- case TCO_DAT_IN:
- return tr->tco.din;
- case TCO_DAT_OUT:
- return tr->tco.dout;
- case TCO1_STS:
- return tr->tco.sts1;
- case TCO2_STS:
- return tr->tco.sts2;
- case TCO1_CNT:
- return tr->tco.cnt1;
- case TCO2_CNT:
- return tr->tco.cnt2;
- case TCO_MESSAGE1:
- return tr->tco.msg1;
- case TCO_MESSAGE2:
- return tr->tco.msg2;
- case TCO_WDCNT:
- return tr->tco.wdcnt;
- case TCO_TMR:
- return tr->tco.tmr;
- case SW_IRQ_GEN:
- return tr->sw_irq_gen;
- }
- return 0;
-}
-
-static void tco_ioport_writew(TCOIORegs *tr, uint32_t addr, uint32_t val)
-{
- switch (addr) {
- case TCO_RLD:
- tr->timeouts_no = 0;
- if (can_start_tco_timer(tr)) {
- tr->tco.rld = tr->tco.tmr;
- tco_timer_reload(tr);
- } else {
- tr->tco.rld = val;
- }
- break;
- case TCO_DAT_IN:
- tr->tco.din = val;
- tr->tco.sts1 |= SW_TCO_SMI;
- ich9_generate_smi();
- break;
- case TCO_DAT_OUT:
- tr->tco.dout = val;
- tr->tco.sts1 |= TCO_INT_STS;
- /* TODO: cause an interrupt, as selected by the TCO_INT_SEL bits */
- break;
- case TCO1_STS:
- tr->tco.sts1 = val & TCO1_STS_MASK;
- break;
- case TCO2_STS:
- tr->tco.sts2 = val & TCO2_STS_MASK;
- break;
- case TCO1_CNT:
- val &= TCO1_CNT_MASK;
- /*
- * once TCO_LOCK bit is set, it can not be cleared by software. a reset
- * is required to change this bit from 1 to 0 -- it defaults to 0.
- */
- tr->tco.cnt1 = val | (tr->tco.cnt1 & TCO_LOCK);
- if (can_start_tco_timer(tr)) {
- tr->tco.rld = tr->tco.tmr;
- tco_timer_reload(tr);
- } else {
- tco_timer_stop(tr);
- }
- break;
- case TCO2_CNT:
- tr->tco.cnt2 = val;
- break;
- case TCO_MESSAGE1:
- tr->tco.msg1 = val;
- break;
- case TCO_MESSAGE2:
- tr->tco.msg2 = val;
- break;
- case TCO_WDCNT:
- tr->tco.wdcnt = val;
- break;
- case TCO_TMR:
- tr->tco.tmr = val;
- break;
- case SW_IRQ_GEN:
- tr->sw_irq_gen = val;
- break;
- }
-}
-
-static uint64_t tco_io_readw(void *opaque, hwaddr addr, unsigned width)
-{
- TCOIORegs *tr = opaque;
- return tco_ioport_readw(tr, addr);
-}
-
-static void tco_io_writew(void *opaque, hwaddr addr, uint64_t val,
- unsigned width)
-{
- TCOIORegs *tr = opaque;
- tco_ioport_writew(tr, addr, val);
-}
-
-static const MemoryRegionOps tco_io_ops = {
- .read = tco_io_readw,
- .write = tco_io_writew,
- .valid.min_access_size = 1,
- .valid.max_access_size = 4,
- .impl.min_access_size = 1,
- .impl.max_access_size = 2,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-void acpi_pm_tco_init(TCOIORegs *tr, MemoryRegion *parent)
-{
- *tr = (TCOIORegs) {
- .tco = {
- .rld = TCO_RLD_DEFAULT,
- .din = TCO_DAT_IN_DEFAULT,
- .dout = TCO_DAT_OUT_DEFAULT,
- .sts1 = TCO1_STS_DEFAULT,
- .sts2 = TCO2_STS_DEFAULT,
- .cnt1 = TCO1_CNT_DEFAULT,
- .cnt2 = TCO2_CNT_DEFAULT,
- .msg1 = TCO_MESSAGE1_DEFAULT,
- .msg2 = TCO_MESSAGE2_DEFAULT,
- .wdcnt = TCO_WDCNT_DEFAULT,
- .tmr = TCO_TMR_DEFAULT,
- },
- .sw_irq_gen = SW_IRQ_GEN_DEFAULT,
- .tco_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tco_timer_expired, tr),
- .expire_time = -1,
- .timeouts_no = 0,
- };
- memory_region_init_io(&tr->io, memory_region_owner(parent),
- &tco_io_ops, tr, "sm-tco", ICH9_PMIO_TCO_LEN);
- memory_region_add_subregion(parent, ICH9_PMIO_TCO_RLD, &tr->io);
-}
-
-const VMStateDescription vmstate_tco_io_sts = {
- .name = "tco io device status",
- .version_id = 1,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT16(tco.rld, TCOIORegs),
- VMSTATE_UINT8(tco.din, TCOIORegs),
- VMSTATE_UINT8(tco.dout, TCOIORegs),
- VMSTATE_UINT16(tco.sts1, TCOIORegs),
- VMSTATE_UINT16(tco.sts2, TCOIORegs),
- VMSTATE_UINT16(tco.cnt1, TCOIORegs),
- VMSTATE_UINT16(tco.cnt2, TCOIORegs),
- VMSTATE_UINT8(tco.msg1, TCOIORegs),
- VMSTATE_UINT8(tco.msg2, TCOIORegs),
- VMSTATE_UINT8(tco.wdcnt, TCOIORegs),
- VMSTATE_UINT16(tco.tmr, TCOIORegs),
- VMSTATE_UINT8(sw_irq_gen, TCOIORegs),
- VMSTATE_TIMER_PTR(tco_timer, TCOIORegs),
- VMSTATE_INT64(expire_time, TCOIORegs),
- VMSTATE_UINT8(timeouts_no, TCOIORegs),
- VMSTATE_END_OF_LIST()
- }
-};
diff --git a/qemu/hw/alpha/Makefile.objs b/qemu/hw/alpha/Makefile.objs
deleted file mode 100644
index 5c742756f..000000000
--- a/qemu/hw/alpha/Makefile.objs
+++ /dev/null
@@ -1 +0,0 @@
-obj-y += dp264.o pci.o typhoon.o
diff --git a/qemu/hw/alpha/alpha_sys.h b/qemu/hw/alpha/alpha_sys.h
deleted file mode 100644
index e11025b4b..000000000
--- a/qemu/hw/alpha/alpha_sys.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/* Alpha cores and system support chips. */
-
-#ifndef HW_ALPHA_H
-#define HW_ALPHA_H 1
-
-#include "hw/pci/pci.h"
-#include "hw/pci/pci_host.h"
-#include "hw/ide.h"
-#include "hw/i386/pc.h"
-#include "hw/irq.h"
-
-
-PCIBus *typhoon_init(ram_addr_t, ISABus **, qemu_irq *, AlphaCPU *[4],
- pci_map_irq_fn);
-
-/* alpha_pci.c. */
-extern const MemoryRegionOps alpha_pci_ignore_ops;
-extern const MemoryRegionOps alpha_pci_conf1_ops;
-extern const MemoryRegionOps alpha_pci_iack_ops;
-
-#endif
diff --git a/qemu/hw/alpha/dp264.c b/qemu/hw/alpha/dp264.c
deleted file mode 100644
index f1267b544..000000000
--- a/qemu/hw/alpha/dp264.c
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * QEMU Alpha DP264/CLIPPER hardware system emulator.
- *
- * Choose CLIPPER IRQ mappings over, say, DP264, MONET, or WEBBRICK
- * variants because CLIPPER doesn't have an SMC669 SuperIO controller
- * that we need to emulate as well.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/hw.h"
-#include "elf.h"
-#include "hw/loader.h"
-#include "hw/boards.h"
-#include "alpha_sys.h"
-#include "qemu/error-report.h"
-#include "sysemu/sysemu.h"
-#include "hw/timer/mc146818rtc.h"
-#include "hw/ide.h"
-#include "hw/timer/i8254.h"
-#include "hw/char/serial.h"
-#include "qemu/cutils.h"
-
-#define MAX_IDE_BUS 2
-
-static uint64_t cpu_alpha_superpage_to_phys(void *opaque, uint64_t addr)
-{
- if (((addr >> 41) & 3) == 2) {
- addr &= 0xffffffffffull;
- }
- return addr;
-}
-
-/* Note that there are at least 3 viewpoints of IRQ numbers on Alpha systems.
- (0) The dev_irq_n lines into the cpu, which we totally ignore,
- (1) The DRIR lines in the typhoon chipset,
- (2) The "vector" aka mangled interrupt number reported by SRM PALcode,
- (3) The interrupt number assigned by the kernel.
- The following function is concerned with (1) only. */
-
-static int clipper_pci_map_irq(PCIDevice *d, int irq_num)
-{
- int slot = d->devfn >> 3;
-
- assert(irq_num >= 0 && irq_num <= 3);
-
- return (slot + 1) * 4 + irq_num;
-}
-
-static void clipper_init(MachineState *machine)
-{
- ram_addr_t ram_size = machine->ram_size;
- const char *cpu_model = machine->cpu_model;
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- const char *initrd_filename = machine->initrd_filename;
- AlphaCPU *cpus[4];
- PCIBus *pci_bus;
- ISABus *isa_bus;
- qemu_irq rtc_irq;
- long size, i;
- char *palcode_filename;
- uint64_t palcode_entry, palcode_low, palcode_high;
- uint64_t kernel_entry, kernel_low, kernel_high;
-
- /* Create up to 4 cpus. */
- memset(cpus, 0, sizeof(cpus));
- for (i = 0; i < smp_cpus; ++i) {
- cpus[i] = cpu_alpha_init(cpu_model ? cpu_model : "ev67");
- }
-
- cpus[0]->env.trap_arg0 = ram_size;
- cpus[0]->env.trap_arg1 = 0;
- cpus[0]->env.trap_arg2 = smp_cpus;
-
- /* Init the chipset. */
- pci_bus = typhoon_init(ram_size, &isa_bus, &rtc_irq, cpus,
- clipper_pci_map_irq);
-
- /* Since we have an SRM-compatible PALcode, use the SRM epoch. */
- rtc_init(isa_bus, 1900, rtc_irq);
-
- pit_init(isa_bus, 0x40, 0, NULL);
- isa_create_simple(isa_bus, "i8042");
-
- /* VGA setup. Don't bother loading the bios. */
- pci_vga_init(pci_bus);
-
- /* Serial code setup. */
- serial_hds_isa_init(isa_bus, MAX_SERIAL_PORTS);
-
- /* Network setup. e1000 is good enough, failing Tulip support. */
- for (i = 0; i < nb_nics; i++) {
- pci_nic_init_nofail(&nd_table[i], pci_bus, "e1000", NULL);
- }
-
- /* IDE disk setup. */
- {
- DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
- ide_drive_get(hd, ARRAY_SIZE(hd));
-
- pci_cmd646_ide_init(pci_bus, hd, 0);
- }
-
- /* Load PALcode. Given that this is not "real" cpu palcode,
- but one explicitly written for the emulation, we might as
- well load it directly from and ELF image. */
- palcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS,
- bios_name ? bios_name : "palcode-clipper");
- if (palcode_filename == NULL) {
- error_report("no palcode provided");
- exit(1);
- }
- size = load_elf(palcode_filename, cpu_alpha_superpage_to_phys,
- NULL, &palcode_entry, &palcode_low, &palcode_high,
- 0, EM_ALPHA, 0, 0);
- if (size < 0) {
- error_report("could not load palcode '%s'", palcode_filename);
- exit(1);
- }
- g_free(palcode_filename);
-
- /* Start all cpus at the PALcode RESET entry point. */
- for (i = 0; i < smp_cpus; ++i) {
- cpus[i]->env.pal_mode = 1;
- cpus[i]->env.pc = palcode_entry;
- cpus[i]->env.palbr = palcode_entry;
- }
-
- /* Load a kernel. */
- if (kernel_filename) {
- uint64_t param_offset;
-
- size = load_elf(kernel_filename, cpu_alpha_superpage_to_phys,
- NULL, &kernel_entry, &kernel_low, &kernel_high,
- 0, EM_ALPHA, 0, 0);
- if (size < 0) {
- error_report("could not load kernel '%s'", kernel_filename);
- exit(1);
- }
-
- cpus[0]->env.trap_arg1 = kernel_entry;
-
- param_offset = kernel_low - 0x6000;
-
- if (kernel_cmdline) {
- pstrcpy_targphys("cmdline", param_offset, 0x100, kernel_cmdline);
- }
-
- if (initrd_filename) {
- long initrd_base, initrd_size;
-
- initrd_size = get_image_size(initrd_filename);
- if (initrd_size < 0) {
- error_report("could not load initial ram disk '%s'",
- initrd_filename);
- exit(1);
- }
-
- /* Put the initrd image as high in memory as possible. */
- initrd_base = (ram_size - initrd_size) & TARGET_PAGE_MASK;
- load_image_targphys(initrd_filename, initrd_base,
- ram_size - initrd_base);
-
- address_space_stq(&address_space_memory, param_offset + 0x100,
- initrd_base + 0xfffffc0000000000ULL,
- MEMTXATTRS_UNSPECIFIED,
- NULL);
- address_space_stq(&address_space_memory, param_offset + 0x108,
- initrd_size, MEMTXATTRS_UNSPECIFIED, NULL);
- }
- }
-}
-
-static void clipper_machine_init(MachineClass *mc)
-{
- mc->desc = "Alpha DP264/CLIPPER";
- mc->init = clipper_init;
- mc->max_cpus = 4;
- mc->is_default = 1;
-}
-
-DEFINE_MACHINE("clipper", clipper_machine_init)
diff --git a/qemu/hw/alpha/pci.c b/qemu/hw/alpha/pci.c
deleted file mode 100644
index 5baa0eaf1..000000000
--- a/qemu/hw/alpha/pci.c
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * QEMU Alpha PCI support functions.
- *
- * Some of this isn't very Alpha specific at all.
- *
- * ??? Sparse memory access not implemented.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "alpha_sys.h"
-#include "qemu/log.h"
-#include "sysemu/sysemu.h"
-#include "trace.h"
-
-
-/* Fallback for unassigned PCI I/O operations. Avoids MCHK. */
-
-static uint64_t ignore_read(void *opaque, hwaddr addr, unsigned size)
-{
- return 0;
-}
-
-static void ignore_write(void *opaque, hwaddr addr, uint64_t v, unsigned size)
-{
-}
-
-const MemoryRegionOps alpha_pci_ignore_ops = {
- .read = ignore_read,
- .write = ignore_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .valid = {
- .min_access_size = 1,
- .max_access_size = 8,
- },
- .impl = {
- .min_access_size = 1,
- .max_access_size = 8,
- },
-};
-
-
-/* PCI config space reads/writes, to byte-word addressable memory. */
-static uint64_t bw_conf1_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- PCIBus *b = opaque;
- return pci_data_read(b, addr, size);
-}
-
-static void bw_conf1_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- PCIBus *b = opaque;
- pci_data_write(b, addr, val, size);
-}
-
-const MemoryRegionOps alpha_pci_conf1_ops = {
- .read = bw_conf1_read,
- .write = bw_conf1_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 4,
- },
-};
-
-/* PCI/EISA Interrupt Acknowledge Cycle. */
-
-static uint64_t iack_read(void *opaque, hwaddr addr, unsigned size)
-{
- return pic_read_irq(isa_pic);
-}
-
-static void special_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- trace_alpha_pci_iack_write();
-}
-
-const MemoryRegionOps alpha_pci_iack_ops = {
- .read = iack_read,
- .write = special_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .impl = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
diff --git a/qemu/hw/alpha/typhoon.c b/qemu/hw/alpha/typhoon.c
deleted file mode 100644
index 97721b535..000000000
--- a/qemu/hw/alpha/typhoon.c
+++ /dev/null
@@ -1,959 +0,0 @@
-/*
- * DEC 21272 (TSUNAMI/TYPHOON) chipset emulation.
- *
- * Written by Richard Henderson.
- *
- * This work is licensed under the GNU GPL license version 2 or later.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "cpu.h"
-#include "hw/hw.h"
-#include "hw/devices.h"
-#include "sysemu/sysemu.h"
-#include "alpha_sys.h"
-#include "exec/address-spaces.h"
-
-
-#define TYPE_TYPHOON_PCI_HOST_BRIDGE "typhoon-pcihost"
-
-typedef struct TyphoonCchip {
- MemoryRegion region;
- uint64_t misc;
- uint64_t drir;
- uint64_t dim[4];
- uint32_t iic[4];
- AlphaCPU *cpu[4];
-} TyphoonCchip;
-
-typedef struct TyphoonWindow {
- uint64_t wba;
- uint64_t wsm;
- uint64_t tba;
-} TyphoonWindow;
-
-typedef struct TyphoonPchip {
- MemoryRegion region;
- MemoryRegion reg_iack;
- MemoryRegion reg_mem;
- MemoryRegion reg_io;
- MemoryRegion reg_conf;
-
- AddressSpace iommu_as;
- MemoryRegion iommu;
-
- uint64_t ctl;
- TyphoonWindow win[4];
-} TyphoonPchip;
-
-#define TYPHOON_PCI_HOST_BRIDGE(obj) \
- OBJECT_CHECK(TyphoonState, (obj), TYPE_TYPHOON_PCI_HOST_BRIDGE)
-
-typedef struct TyphoonState {
- PCIHostState parent_obj;
-
- TyphoonCchip cchip;
- TyphoonPchip pchip;
- MemoryRegion dchip_region;
- MemoryRegion ram_region;
-} TyphoonState;
-
-/* Called when one of DRIR or DIM changes. */
-static void cpu_irq_change(AlphaCPU *cpu, uint64_t req)
-{
- /* If there are any non-masked interrupts, tell the cpu. */
- if (cpu != NULL) {
- CPUState *cs = CPU(cpu);
- if (req) {
- cpu_interrupt(cs, CPU_INTERRUPT_HARD);
- } else {
- cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
- }
- }
-}
-
-static uint64_t cchip_read(void *opaque, hwaddr addr, unsigned size)
-{
- CPUState *cpu = current_cpu;
- TyphoonState *s = opaque;
- uint64_t ret = 0;
-
- switch (addr) {
- case 0x0000:
- /* CSC: Cchip System Configuration Register. */
- /* All sorts of data here; probably the only thing relevant is
- PIP<14> Pchip 1 Present = 0. */
- break;
-
- case 0x0040:
- /* MTR: Memory Timing Register. */
- /* All sorts of stuff related to real DRAM. */
- break;
-
- case 0x0080:
- /* MISC: Miscellaneous Register. */
- ret = s->cchip.misc | (cpu->cpu_index & 3);
- break;
-
- case 0x00c0:
- /* MPD: Memory Presence Detect Register. */
- break;
-
- case 0x0100: /* AAR0 */
- case 0x0140: /* AAR1 */
- case 0x0180: /* AAR2 */
- case 0x01c0: /* AAR3 */
- /* AAR: Array Address Register. */
- /* All sorts of information about DRAM. */
- break;
-
- case 0x0200:
- /* DIM0: Device Interrupt Mask Register, CPU0. */
- ret = s->cchip.dim[0];
- break;
- case 0x0240:
- /* DIM1: Device Interrupt Mask Register, CPU1. */
- ret = s->cchip.dim[1];
- break;
- case 0x0280:
- /* DIR0: Device Interrupt Request Register, CPU0. */
- ret = s->cchip.dim[0] & s->cchip.drir;
- break;
- case 0x02c0:
- /* DIR1: Device Interrupt Request Register, CPU1. */
- ret = s->cchip.dim[1] & s->cchip.drir;
- break;
- case 0x0300:
- /* DRIR: Device Raw Interrupt Request Register. */
- ret = s->cchip.drir;
- break;
-
- case 0x0340:
- /* PRBEN: Probe Enable Register. */
- break;
-
- case 0x0380:
- /* IIC0: Interval Ignore Count Register, CPU0. */
- ret = s->cchip.iic[0];
- break;
- case 0x03c0:
- /* IIC1: Interval Ignore Count Register, CPU1. */
- ret = s->cchip.iic[1];
- break;
-
- case 0x0400: /* MPR0 */
- case 0x0440: /* MPR1 */
- case 0x0480: /* MPR2 */
- case 0x04c0: /* MPR3 */
- /* MPR: Memory Programming Register. */
- break;
-
- case 0x0580:
- /* TTR: TIGbus Timing Register. */
- /* All sorts of stuff related to interrupt delivery timings. */
- break;
- case 0x05c0:
- /* TDR: TIGbug Device Timing Register. */
- break;
-
- case 0x0600:
- /* DIM2: Device Interrupt Mask Register, CPU2. */
- ret = s->cchip.dim[2];
- break;
- case 0x0640:
- /* DIM3: Device Interrupt Mask Register, CPU3. */
- ret = s->cchip.dim[3];
- break;
- case 0x0680:
- /* DIR2: Device Interrupt Request Register, CPU2. */
- ret = s->cchip.dim[2] & s->cchip.drir;
- break;
- case 0x06c0:
- /* DIR3: Device Interrupt Request Register, CPU3. */
- ret = s->cchip.dim[3] & s->cchip.drir;
- break;
-
- case 0x0700:
- /* IIC2: Interval Ignore Count Register, CPU2. */
- ret = s->cchip.iic[2];
- break;
- case 0x0740:
- /* IIC3: Interval Ignore Count Register, CPU3. */
- ret = s->cchip.iic[3];
- break;
-
- case 0x0780:
- /* PWR: Power Management Control. */
- break;
-
- case 0x0c00: /* CMONCTLA */
- case 0x0c40: /* CMONCTLB */
- case 0x0c80: /* CMONCNT01 */
- case 0x0cc0: /* CMONCNT23 */
- break;
-
- default:
- cpu_unassigned_access(cpu, addr, false, false, 0, size);
- return -1;
- }
-
- return ret;
-}
-
-static uint64_t dchip_read(void *opaque, hwaddr addr, unsigned size)
-{
- /* Skip this. It's all related to DRAM timing and setup. */
- return 0;
-}
-
-static uint64_t pchip_read(void *opaque, hwaddr addr, unsigned size)
-{
- TyphoonState *s = opaque;
- uint64_t ret = 0;
-
- switch (addr) {
- case 0x0000:
- /* WSBA0: Window Space Base Address Register. */
- ret = s->pchip.win[0].wba;
- break;
- case 0x0040:
- /* WSBA1 */
- ret = s->pchip.win[1].wba;
- break;
- case 0x0080:
- /* WSBA2 */
- ret = s->pchip.win[2].wba;
- break;
- case 0x00c0:
- /* WSBA3 */
- ret = s->pchip.win[3].wba;
- break;
-
- case 0x0100:
- /* WSM0: Window Space Mask Register. */
- ret = s->pchip.win[0].wsm;
- break;
- case 0x0140:
- /* WSM1 */
- ret = s->pchip.win[1].wsm;
- break;
- case 0x0180:
- /* WSM2 */
- ret = s->pchip.win[2].wsm;
- break;
- case 0x01c0:
- /* WSM3 */
- ret = s->pchip.win[3].wsm;
- break;
-
- case 0x0200:
- /* TBA0: Translated Base Address Register. */
- ret = s->pchip.win[0].tba;
- break;
- case 0x0240:
- /* TBA1 */
- ret = s->pchip.win[1].tba;
- break;
- case 0x0280:
- /* TBA2 */
- ret = s->pchip.win[2].tba;
- break;
- case 0x02c0:
- /* TBA3 */
- ret = s->pchip.win[3].tba;
- break;
-
- case 0x0300:
- /* PCTL: Pchip Control Register. */
- ret = s->pchip.ctl;
- break;
- case 0x0340:
- /* PLAT: Pchip Master Latency Register. */
- break;
- case 0x03c0:
- /* PERROR: Pchip Error Register. */
- break;
- case 0x0400:
- /* PERRMASK: Pchip Error Mask Register. */
- break;
- case 0x0440:
- /* PERRSET: Pchip Error Set Register. */
- break;
- case 0x0480:
- /* TLBIV: Translation Buffer Invalidate Virtual Register (WO). */
- break;
- case 0x04c0:
- /* TLBIA: Translation Buffer Invalidate All Register (WO). */
- break;
- case 0x0500: /* PMONCTL */
- case 0x0540: /* PMONCNT */
- case 0x0800: /* SPRST */
- break;
-
- default:
- cpu_unassigned_access(current_cpu, addr, false, false, 0, size);
- return -1;
- }
-
- return ret;
-}
-
-static void cchip_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- TyphoonState *s = opaque;
- uint64_t oldval, newval;
-
- switch (addr) {
- case 0x0000:
- /* CSC: Cchip System Configuration Register. */
- /* All sorts of data here; nothing relevant RW. */
- break;
-
- case 0x0040:
- /* MTR: Memory Timing Register. */
- /* All sorts of stuff related to real DRAM. */
- break;
-
- case 0x0080:
- /* MISC: Miscellaneous Register. */
- newval = oldval = s->cchip.misc;
- newval &= ~(val & 0x10000ff0); /* W1C fields */
- if (val & 0x100000) {
- newval &= ~0xff0000ull; /* ACL clears ABT and ABW */
- } else {
- newval |= val & 0x00f00000; /* ABT field is W1S */
- if ((newval & 0xf0000) == 0) {
- newval |= val & 0xf0000; /* ABW field is W1S iff zero */
- }
- }
- newval |= (val & 0xf000) >> 4; /* IPREQ field sets IPINTR. */
-
- newval &= ~0xf0000000000ull; /* WO and RW fields */
- newval |= val & 0xf0000000000ull;
- s->cchip.misc = newval;
-
- /* Pass on changes to IPI and ITI state. */
- if ((newval ^ oldval) & 0xff0) {
- int i;
- for (i = 0; i < 4; ++i) {
- AlphaCPU *cpu = s->cchip.cpu[i];
- if (cpu != NULL) {
- CPUState *cs = CPU(cpu);
- /* IPI can be either cleared or set by the write. */
- if (newval & (1 << (i + 8))) {
- cpu_interrupt(cs, CPU_INTERRUPT_SMP);
- } else {
- cpu_reset_interrupt(cs, CPU_INTERRUPT_SMP);
- }
-
- /* ITI can only be cleared by the write. */
- if ((newval & (1 << (i + 4))) == 0) {
- cpu_reset_interrupt(cs, CPU_INTERRUPT_TIMER);
- }
- }
- }
- }
- break;
-
- case 0x00c0:
- /* MPD: Memory Presence Detect Register. */
- break;
-
- case 0x0100: /* AAR0 */
- case 0x0140: /* AAR1 */
- case 0x0180: /* AAR2 */
- case 0x01c0: /* AAR3 */
- /* AAR: Array Address Register. */
- /* All sorts of information about DRAM. */
- break;
-
- case 0x0200: /* DIM0 */
- /* DIM: Device Interrupt Mask Register, CPU0. */
- s->cchip.dim[0] = val;
- cpu_irq_change(s->cchip.cpu[0], val & s->cchip.drir);
- break;
- case 0x0240: /* DIM1 */
- /* DIM: Device Interrupt Mask Register, CPU1. */
- s->cchip.dim[0] = val;
- cpu_irq_change(s->cchip.cpu[1], val & s->cchip.drir);
- break;
-
- case 0x0280: /* DIR0 (RO) */
- case 0x02c0: /* DIR1 (RO) */
- case 0x0300: /* DRIR (RO) */
- break;
-
- case 0x0340:
- /* PRBEN: Probe Enable Register. */
- break;
-
- case 0x0380: /* IIC0 */
- s->cchip.iic[0] = val & 0xffffff;
- break;
- case 0x03c0: /* IIC1 */
- s->cchip.iic[1] = val & 0xffffff;
- break;
-
- case 0x0400: /* MPR0 */
- case 0x0440: /* MPR1 */
- case 0x0480: /* MPR2 */
- case 0x04c0: /* MPR3 */
- /* MPR: Memory Programming Register. */
- break;
-
- case 0x0580:
- /* TTR: TIGbus Timing Register. */
- /* All sorts of stuff related to interrupt delivery timings. */
- break;
- case 0x05c0:
- /* TDR: TIGbug Device Timing Register. */
- break;
-
- case 0x0600:
- /* DIM2: Device Interrupt Mask Register, CPU2. */
- s->cchip.dim[2] = val;
- cpu_irq_change(s->cchip.cpu[2], val & s->cchip.drir);
- break;
- case 0x0640:
- /* DIM3: Device Interrupt Mask Register, CPU3. */
- s->cchip.dim[3] = val;
- cpu_irq_change(s->cchip.cpu[3], val & s->cchip.drir);
- break;
-
- case 0x0680: /* DIR2 (RO) */
- case 0x06c0: /* DIR3 (RO) */
- break;
-
- case 0x0700: /* IIC2 */
- s->cchip.iic[2] = val & 0xffffff;
- break;
- case 0x0740: /* IIC3 */
- s->cchip.iic[3] = val & 0xffffff;
- break;
-
- case 0x0780:
- /* PWR: Power Management Control. */
- break;
-
- case 0x0c00: /* CMONCTLA */
- case 0x0c40: /* CMONCTLB */
- case 0x0c80: /* CMONCNT01 */
- case 0x0cc0: /* CMONCNT23 */
- break;
-
- default:
- cpu_unassigned_access(current_cpu, addr, true, false, 0, size);
- return;
- }
-}
-
-static void dchip_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- /* Skip this. It's all related to DRAM timing and setup. */
-}
-
-static void pchip_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- TyphoonState *s = opaque;
- uint64_t oldval;
-
- switch (addr) {
- case 0x0000:
- /* WSBA0: Window Space Base Address Register. */
- s->pchip.win[0].wba = val & 0xfff00003u;
- break;
- case 0x0040:
- /* WSBA1 */
- s->pchip.win[1].wba = val & 0xfff00003u;
- break;
- case 0x0080:
- /* WSBA2 */
- s->pchip.win[2].wba = val & 0xfff00003u;
- break;
- case 0x00c0:
- /* WSBA3 */
- s->pchip.win[3].wba = (val & 0x80fff00001ull) | 2;
- break;
-
- case 0x0100:
- /* WSM0: Window Space Mask Register. */
- s->pchip.win[0].wsm = val & 0xfff00000u;
- break;
- case 0x0140:
- /* WSM1 */
- s->pchip.win[1].wsm = val & 0xfff00000u;
- break;
- case 0x0180:
- /* WSM2 */
- s->pchip.win[2].wsm = val & 0xfff00000u;
- break;
- case 0x01c0:
- /* WSM3 */
- s->pchip.win[3].wsm = val & 0xfff00000u;
- break;
-
- case 0x0200:
- /* TBA0: Translated Base Address Register. */
- s->pchip.win[0].tba = val & 0x7fffffc00ull;
- break;
- case 0x0240:
- /* TBA1 */
- s->pchip.win[1].tba = val & 0x7fffffc00ull;
- break;
- case 0x0280:
- /* TBA2 */
- s->pchip.win[2].tba = val & 0x7fffffc00ull;
- break;
- case 0x02c0:
- /* TBA3 */
- s->pchip.win[3].tba = val & 0x7fffffc00ull;
- break;
-
- case 0x0300:
- /* PCTL: Pchip Control Register. */
- oldval = s->pchip.ctl;
- oldval &= ~0x00001cff0fc7ffull; /* RW fields */
- oldval |= val & 0x00001cff0fc7ffull;
- s->pchip.ctl = oldval;
- break;
-
- case 0x0340:
- /* PLAT: Pchip Master Latency Register. */
- break;
- case 0x03c0:
- /* PERROR: Pchip Error Register. */
- break;
- case 0x0400:
- /* PERRMASK: Pchip Error Mask Register. */
- break;
- case 0x0440:
- /* PERRSET: Pchip Error Set Register. */
- break;
-
- case 0x0480:
- /* TLBIV: Translation Buffer Invalidate Virtual Register. */
- break;
-
- case 0x04c0:
- /* TLBIA: Translation Buffer Invalidate All Register (WO). */
- break;
-
- case 0x0500:
- /* PMONCTL */
- case 0x0540:
- /* PMONCNT */
- case 0x0800:
- /* SPRST */
- break;
-
- default:
- cpu_unassigned_access(current_cpu, addr, true, false, 0, size);
- return;
- }
-}
-
-static const MemoryRegionOps cchip_ops = {
- .read = cchip_read,
- .write = cchip_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .valid = {
- .min_access_size = 8,
- .max_access_size = 8,
- },
- .impl = {
- .min_access_size = 8,
- .max_access_size = 8,
- },
-};
-
-static const MemoryRegionOps dchip_ops = {
- .read = dchip_read,
- .write = dchip_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .valid = {
- .min_access_size = 8,
- .max_access_size = 8,
- },
- .impl = {
- .min_access_size = 8,
- .max_access_size = 8,
- },
-};
-
-static const MemoryRegionOps pchip_ops = {
- .read = pchip_read,
- .write = pchip_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .valid = {
- .min_access_size = 8,
- .max_access_size = 8,
- },
- .impl = {
- .min_access_size = 8,
- .max_access_size = 8,
- },
-};
-
-/* A subroutine of typhoon_translate_iommu that builds an IOMMUTLBEntry
- using the given translated address and mask. */
-static bool make_iommu_tlbe(hwaddr taddr, hwaddr mask, IOMMUTLBEntry *ret)
-{
- *ret = (IOMMUTLBEntry) {
- .target_as = &address_space_memory,
- .translated_addr = taddr,
- .addr_mask = mask,
- .perm = IOMMU_RW,
- };
- return true;
-}
-
-/* A subroutine of typhoon_translate_iommu that handles scatter-gather
- translation, given the address of the PTE. */
-static bool pte_translate(hwaddr pte_addr, IOMMUTLBEntry *ret)
-{
- uint64_t pte = address_space_ldq(&address_space_memory, pte_addr,
- MEMTXATTRS_UNSPECIFIED, NULL);
-
- /* Check valid bit. */
- if ((pte & 1) == 0) {
- return false;
- }
-
- return make_iommu_tlbe((pte & 0x3ffffe) << 12, 0x1fff, ret);
-}
-
-/* A subroutine of typhoon_translate_iommu that handles one of the
- four single-address-cycle translation windows. */
-static bool window_translate(TyphoonWindow *win, hwaddr addr,
- IOMMUTLBEntry *ret)
-{
- uint32_t wba = win->wba;
- uint64_t wsm = win->wsm;
- uint64_t tba = win->tba;
- uint64_t wsm_ext = wsm | 0xfffff;
-
- /* Check for window disabled. */
- if ((wba & 1) == 0) {
- return false;
- }
-
- /* Check for window hit. */
- if ((addr & ~wsm_ext) != (wba & 0xfff00000u)) {
- return false;
- }
-
- if (wba & 2) {
- /* Scatter-gather translation. */
- hwaddr pte_addr;
-
- /* See table 10-6, Generating PTE address for PCI DMA Address. */
- pte_addr = tba & ~(wsm >> 10);
- pte_addr |= (addr & (wsm | 0xfe000)) >> 10;
- return pte_translate(pte_addr, ret);
- } else {
- /* Direct-mapped translation. */
- return make_iommu_tlbe(tba & ~wsm_ext, wsm_ext, ret);
- }
-}
-
-/* Handle PCI-to-system address translation. */
-/* TODO: A translation failure here ought to set PCI error codes on the
- Pchip and generate a machine check interrupt. */
-static IOMMUTLBEntry typhoon_translate_iommu(MemoryRegion *iommu, hwaddr addr,
- bool is_write)
-{
- TyphoonPchip *pchip = container_of(iommu, TyphoonPchip, iommu);
- IOMMUTLBEntry ret;
- int i;
-
- if (addr <= 0xffffffffu) {
- /* Single-address cycle. */
-
- /* Check for the Window Hole, inhibiting matching. */
- if ((pchip->ctl & 0x20)
- && addr >= 0x80000
- && addr <= 0xfffff) {
- goto failure;
- }
-
- /* Check the first three windows. */
- for (i = 0; i < 3; ++i) {
- if (window_translate(&pchip->win[i], addr, &ret)) {
- goto success;
- }
- }
-
- /* Check the fourth window for DAC disable. */
- if ((pchip->win[3].wba & 0x80000000000ull) == 0
- && window_translate(&pchip->win[3], addr, &ret)) {
- goto success;
- }
- } else {
- /* Double-address cycle. */
-
- if (addr >= 0x10000000000ull && addr < 0x20000000000ull) {
- /* Check for the DMA monster window. */
- if (pchip->ctl & 0x40) {
- /* See 10.1.4.4; in particular <39:35> is ignored. */
- make_iommu_tlbe(0, 0x007ffffffffull, &ret);
- goto success;
- }
- }
-
- if (addr >= 0x80000000000ull && addr <= 0xfffffffffffull) {
- /* Check the fourth window for DAC enable and window enable. */
- if ((pchip->win[3].wba & 0x80000000001ull) == 0x80000000001ull) {
- uint64_t pte_addr;
-
- pte_addr = pchip->win[3].tba & 0x7ffc00000ull;
- pte_addr |= (addr & 0xffffe000u) >> 10;
- if (pte_translate(pte_addr, &ret)) {
- goto success;
- }
- }
- }
- }
-
- failure:
- ret = (IOMMUTLBEntry) { .perm = IOMMU_NONE };
- success:
- return ret;
-}
-
-static const MemoryRegionIOMMUOps typhoon_iommu_ops = {
- .translate = typhoon_translate_iommu,
-};
-
-static AddressSpace *typhoon_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
-{
- TyphoonState *s = opaque;
- return &s->pchip.iommu_as;
-}
-
-static void typhoon_set_irq(void *opaque, int irq, int level)
-{
- TyphoonState *s = opaque;
- uint64_t drir;
- int i;
-
- /* Set/Reset the bit in CCHIP.DRIR based on IRQ+LEVEL. */
- drir = s->cchip.drir;
- if (level) {
- drir |= 1ull << irq;
- } else {
- drir &= ~(1ull << irq);
- }
- s->cchip.drir = drir;
-
- for (i = 0; i < 4; ++i) {
- cpu_irq_change(s->cchip.cpu[i], s->cchip.dim[i] & drir);
- }
-}
-
-static void typhoon_set_isa_irq(void *opaque, int irq, int level)
-{
- typhoon_set_irq(opaque, 55, level);
-}
-
-static void typhoon_set_timer_irq(void *opaque, int irq, int level)
-{
- TyphoonState *s = opaque;
- int i;
-
- /* Thankfully, the mc146818rtc code doesn't track the IRQ state,
- and so we don't have to worry about missing interrupts just
- because we never actually ACK the interrupt. Just ignore any
- case of the interrupt level going low. */
- if (level == 0) {
- return;
- }
-
- /* Deliver the interrupt to each CPU, considering each CPU's IIC. */
- for (i = 0; i < 4; ++i) {
- AlphaCPU *cpu = s->cchip.cpu[i];
- if (cpu != NULL) {
- uint32_t iic = s->cchip.iic[i];
-
- /* ??? The verbage in Section 10.2.2.10 isn't 100% clear.
- Bit 24 is the OverFlow bit, RO, and set when the count
- decrements past 0. When is OF cleared? My guess is that
- OF is actually cleared when the IIC is written, and that
- the ICNT field always decrements. At least, that's an
- interpretation that makes sense, and "allows the CPU to
- determine exactly how mant interval timer ticks were
- skipped". At least within the next 4M ticks... */
-
- iic = ((iic - 1) & 0x1ffffff) | (iic & 0x1000000);
- s->cchip.iic[i] = iic;
-
- if (iic & 0x1000000) {
- /* Set the ITI bit for this cpu. */
- s->cchip.misc |= 1 << (i + 4);
- /* And signal the interrupt. */
- cpu_interrupt(CPU(cpu), CPU_INTERRUPT_TIMER);
- }
- }
- }
-}
-
-static void typhoon_alarm_timer(void *opaque)
-{
- TyphoonState *s = (TyphoonState *)((uintptr_t)opaque & ~3);
- int cpu = (uintptr_t)opaque & 3;
-
- /* Set the ITI bit for this cpu. */
- s->cchip.misc |= 1 << (cpu + 4);
- cpu_interrupt(CPU(s->cchip.cpu[cpu]), CPU_INTERRUPT_TIMER);
-}
-
-PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus,
- qemu_irq *p_rtc_irq,
- AlphaCPU *cpus[4], pci_map_irq_fn sys_map_irq)
-{
- const uint64_t MB = 1024 * 1024;
- const uint64_t GB = 1024 * MB;
- MemoryRegion *addr_space = get_system_memory();
- DeviceState *dev;
- TyphoonState *s;
- PCIHostState *phb;
- PCIBus *b;
- int i;
-
- dev = qdev_create(NULL, TYPE_TYPHOON_PCI_HOST_BRIDGE);
- qdev_init_nofail(dev);
-
- s = TYPHOON_PCI_HOST_BRIDGE(dev);
- phb = PCI_HOST_BRIDGE(dev);
-
- s->cchip.misc = 0x800000000ull; /* Revision: Typhoon. */
- s->pchip.win[3].wba = 2; /* Window 3 SG always enabled. */
-
- /* Remember the CPUs so that we can deliver interrupts to them. */
- for (i = 0; i < 4; i++) {
- AlphaCPU *cpu = cpus[i];
- s->cchip.cpu[i] = cpu;
- if (cpu != NULL) {
- cpu->alarm_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
- typhoon_alarm_timer,
- (void *)((uintptr_t)s + i));
- }
- }
-
- *p_rtc_irq = qemu_allocate_irq(typhoon_set_timer_irq, s, 0);
-
- /* Main memory region, 0x00.0000.0000. Real hardware supports 32GB,
- but the address space hole reserved at this point is 8TB. */
- memory_region_allocate_system_memory(&s->ram_region, OBJECT(s), "ram",
- ram_size);
- memory_region_add_subregion(addr_space, 0, &s->ram_region);
-
- /* TIGbus, 0x801.0000.0000, 1GB. */
- /* ??? The TIGbus is used for delivering interrupts, and access to
- the flash ROM. I'm not sure that we need to implement it at all. */
-
- /* Pchip0 CSRs, 0x801.8000.0000, 256MB. */
- memory_region_init_io(&s->pchip.region, OBJECT(s), &pchip_ops, s, "pchip0",
- 256*MB);
- memory_region_add_subregion(addr_space, 0x80180000000ULL,
- &s->pchip.region);
-
- /* Cchip CSRs, 0x801.A000.0000, 256MB. */
- memory_region_init_io(&s->cchip.region, OBJECT(s), &cchip_ops, s, "cchip0",
- 256*MB);
- memory_region_add_subregion(addr_space, 0x801a0000000ULL,
- &s->cchip.region);
-
- /* Dchip CSRs, 0x801.B000.0000, 256MB. */
- memory_region_init_io(&s->dchip_region, OBJECT(s), &dchip_ops, s, "dchip0",
- 256*MB);
- memory_region_add_subregion(addr_space, 0x801b0000000ULL,
- &s->dchip_region);
-
- /* Pchip0 PCI memory, 0x800.0000.0000, 4GB. */
- memory_region_init(&s->pchip.reg_mem, OBJECT(s), "pci0-mem", 4*GB);
- memory_region_add_subregion(addr_space, 0x80000000000ULL,
- &s->pchip.reg_mem);
-
- /* Pchip0 PCI I/O, 0x801.FC00.0000, 32MB. */
- memory_region_init_io(&s->pchip.reg_io, OBJECT(s), &alpha_pci_ignore_ops,
- NULL, "pci0-io", 32*MB);
- memory_region_add_subregion(addr_space, 0x801fc000000ULL,
- &s->pchip.reg_io);
-
- b = pci_register_bus(dev, "pci",
- typhoon_set_irq, sys_map_irq, s,
- &s->pchip.reg_mem, &s->pchip.reg_io,
- 0, 64, TYPE_PCI_BUS);
- phb->bus = b;
-
- /* Host memory as seen from the PCI side, via the IOMMU. */
- memory_region_init_iommu(&s->pchip.iommu, OBJECT(s), &typhoon_iommu_ops,
- "iommu-typhoon", UINT64_MAX);
- address_space_init(&s->pchip.iommu_as, &s->pchip.iommu, "pchip0-pci");
- pci_setup_iommu(b, typhoon_pci_dma_iommu, s);
-
- /* Pchip0 PCI special/interrupt acknowledge, 0x801.F800.0000, 64MB. */
- memory_region_init_io(&s->pchip.reg_iack, OBJECT(s), &alpha_pci_iack_ops,
- b, "pci0-iack", 64*MB);
- memory_region_add_subregion(addr_space, 0x801f8000000ULL,
- &s->pchip.reg_iack);
-
- /* Pchip0 PCI configuration, 0x801.FE00.0000, 16MB. */
- memory_region_init_io(&s->pchip.reg_conf, OBJECT(s), &alpha_pci_conf1_ops,
- b, "pci0-conf", 16*MB);
- memory_region_add_subregion(addr_space, 0x801fe000000ULL,
- &s->pchip.reg_conf);
-
- /* For the record, these are the mappings for the second PCI bus.
- We can get away with not implementing them because we indicate
- via the Cchip.CSC<PIP> bit that Pchip1 is not present. */
- /* Pchip1 PCI memory, 0x802.0000.0000, 4GB. */
- /* Pchip1 CSRs, 0x802.8000.0000, 256MB. */
- /* Pchip1 PCI special/interrupt acknowledge, 0x802.F800.0000, 64MB. */
- /* Pchip1 PCI I/O, 0x802.FC00.0000, 32MB. */
- /* Pchip1 PCI configuration, 0x802.FE00.0000, 16MB. */
-
- /* Init the ISA bus. */
- /* ??? Technically there should be a cy82c693ub pci-isa bridge. */
- {
- qemu_irq *isa_irqs;
-
- *isa_bus = isa_bus_new(NULL, get_system_memory(), &s->pchip.reg_io,
- &error_abort);
- isa_irqs = i8259_init(*isa_bus,
- qemu_allocate_irq(typhoon_set_isa_irq, s, 0));
- isa_bus_irqs(*isa_bus, isa_irqs);
- }
-
- return b;
-}
-
-static int typhoon_pcihost_init(SysBusDevice *dev)
-{
- return 0;
-}
-
-static void typhoon_pcihost_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = typhoon_pcihost_init;
-}
-
-static const TypeInfo typhoon_pcihost_info = {
- .name = TYPE_TYPHOON_PCI_HOST_BRIDGE,
- .parent = TYPE_PCI_HOST_BRIDGE,
- .instance_size = sizeof(TyphoonState),
- .class_init = typhoon_pcihost_class_init,
-};
-
-static void typhoon_register_types(void)
-{
- type_register_static(&typhoon_pcihost_info);
-}
-
-type_init(typhoon_register_types)
diff --git a/qemu/hw/arm/Makefile.objs b/qemu/hw/arm/Makefile.objs
deleted file mode 100644
index 954c9fe15..000000000
--- a/qemu/hw/arm/Makefile.objs
+++ /dev/null
@@ -1,19 +0,0 @@
-obj-y += boot.o collie.o exynos4_boards.o gumstix.o highbank.o
-obj-$(CONFIG_DIGIC) += digic_boards.o
-obj-y += integratorcp.o mainstone.o musicpal.o nseries.o
-obj-y += omap_sx1.o palm.o realview.o spitz.o stellaris.o
-obj-y += tosa.o versatilepb.o vexpress.o virt.o xilinx_zynq.o z2.o
-obj-$(CONFIG_ACPI) += virt-acpi-build.o
-obj-y += netduino2.o
-obj-y += sysbus-fdt.o
-
-obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o
-obj-$(CONFIG_DIGIC) += digic.o
-obj-y += omap1.o omap2.o strongarm.o
-obj-$(CONFIG_ALLWINNER_A10) += allwinner-a10.o cubieboard.o
-obj-$(CONFIG_RASPI) += bcm2835_peripherals.o bcm2836.o raspi.o
-obj-$(CONFIG_STM32F205_SOC) += stm32f205_soc.o
-obj-$(CONFIG_XLNX_ZYNQMP) += xlnx-zynqmp.o xlnx-ep108.o
-obj-$(CONFIG_FSL_IMX25) += fsl-imx25.o imx25_pdk.o
-obj-$(CONFIG_FSL_IMX31) += fsl-imx31.o kzm.o
-obj-$(CONFIG_ASPEED_SOC) += ast2400.o palmetto-bmc.o
diff --git a/qemu/hw/arm/allwinner-a10.c b/qemu/hw/arm/allwinner-a10.c
deleted file mode 100644
index ca15d1c8c..000000000
--- a/qemu/hw/arm/allwinner-a10.c
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Allwinner A10 SoC emulation
- *
- * Copyright (C) 2013 Li Guang
- * Written by Li Guang <lig.fnst@cn.fujitsu.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/sysbus.h"
-#include "hw/devices.h"
-#include "hw/arm/allwinner-a10.h"
-
-static void aw_a10_init(Object *obj)
-{
- AwA10State *s = AW_A10(obj);
-
- object_initialize(&s->cpu, sizeof(s->cpu), "cortex-a8-" TYPE_ARM_CPU);
- object_property_add_child(obj, "cpu", OBJECT(&s->cpu), NULL);
-
- object_initialize(&s->intc, sizeof(s->intc), TYPE_AW_A10_PIC);
- qdev_set_parent_bus(DEVICE(&s->intc), sysbus_get_default());
-
- object_initialize(&s->timer, sizeof(s->timer), TYPE_AW_A10_PIT);
- qdev_set_parent_bus(DEVICE(&s->timer), sysbus_get_default());
-
- object_initialize(&s->emac, sizeof(s->emac), TYPE_AW_EMAC);
- qdev_set_parent_bus(DEVICE(&s->emac), sysbus_get_default());
- /* FIXME use qdev NIC properties instead of nd_table[] */
- if (nd_table[0].used) {
- qemu_check_nic_model(&nd_table[0], TYPE_AW_EMAC);
- qdev_set_nic_properties(DEVICE(&s->emac), &nd_table[0]);
- }
-
- object_initialize(&s->sata, sizeof(s->sata), TYPE_ALLWINNER_AHCI);
- qdev_set_parent_bus(DEVICE(&s->sata), sysbus_get_default());
-}
-
-static void aw_a10_realize(DeviceState *dev, Error **errp)
-{
- AwA10State *s = AW_A10(dev);
- SysBusDevice *sysbusdev;
- uint8_t i;
- qemu_irq fiq, irq;
- Error *err = NULL;
-
- object_property_set_bool(OBJECT(&s->cpu), true, "realized", &err);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
- irq = qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_IRQ);
- fiq = qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_FIQ);
-
- object_property_set_bool(OBJECT(&s->intc), true, "realized", &err);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
- sysbusdev = SYS_BUS_DEVICE(&s->intc);
- sysbus_mmio_map(sysbusdev, 0, AW_A10_PIC_REG_BASE);
- sysbus_connect_irq(sysbusdev, 0, irq);
- sysbus_connect_irq(sysbusdev, 1, fiq);
- for (i = 0; i < AW_A10_PIC_INT_NR; i++) {
- s->irq[i] = qdev_get_gpio_in(DEVICE(&s->intc), i);
- }
-
- object_property_set_bool(OBJECT(&s->timer), true, "realized", &err);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
- sysbusdev = SYS_BUS_DEVICE(&s->timer);
- sysbus_mmio_map(sysbusdev, 0, AW_A10_PIT_REG_BASE);
- sysbus_connect_irq(sysbusdev, 0, s->irq[22]);
- sysbus_connect_irq(sysbusdev, 1, s->irq[23]);
- sysbus_connect_irq(sysbusdev, 2, s->irq[24]);
- sysbus_connect_irq(sysbusdev, 3, s->irq[25]);
- sysbus_connect_irq(sysbusdev, 4, s->irq[67]);
- sysbus_connect_irq(sysbusdev, 5, s->irq[68]);
-
- object_property_set_bool(OBJECT(&s->emac), true, "realized", &err);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
- sysbusdev = SYS_BUS_DEVICE(&s->emac);
- sysbus_mmio_map(sysbusdev, 0, AW_A10_EMAC_BASE);
- sysbus_connect_irq(sysbusdev, 0, s->irq[55]);
-
- object_property_set_bool(OBJECT(&s->sata), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->sata), 0, AW_A10_SATA_BASE);
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->sata), 0, s->irq[56]);
-
- /* FIXME use a qdev chardev prop instead of serial_hds[] */
- serial_mm_init(get_system_memory(), AW_A10_UART0_REG_BASE, 2, s->irq[1],
- 115200, serial_hds[0], DEVICE_NATIVE_ENDIAN);
-}
-
-static void aw_a10_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- dc->realize = aw_a10_realize;
-
- /*
- * Reason: creates an ARM CPU, thus use after free(), see
- * arm_cpu_class_init()
- */
- dc->cannot_destroy_with_object_finalize_yet = true;
-}
-
-static const TypeInfo aw_a10_type_info = {
- .name = TYPE_AW_A10,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(AwA10State),
- .instance_init = aw_a10_init,
- .class_init = aw_a10_class_init,
-};
-
-static void aw_a10_register_types(void)
-{
- type_register_static(&aw_a10_type_info);
-}
-
-type_init(aw_a10_register_types)
diff --git a/qemu/hw/arm/armv7m.c b/qemu/hw/arm/armv7m.c
deleted file mode 100644
index bb2a22d96..000000000
--- a/qemu/hw/arm/armv7m.c
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * ARMV7M System emulation.
- *
- * Copyright (c) 2006-2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/sysbus.h"
-#include "hw/arm/arm.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "sysemu/qtest.h"
-#include "qemu/error-report.h"
-
-/* Bitbanded IO. Each word corresponds to a single bit. */
-
-/* Get the byte address of the real memory for a bitband access. */
-static inline uint32_t bitband_addr(void * opaque, uint32_t addr)
-{
- uint32_t res;
-
- res = *(uint32_t *)opaque;
- res |= (addr & 0x1ffffff) >> 5;
- return res;
-
-}
-
-static uint32_t bitband_readb(void *opaque, hwaddr offset)
-{
- uint8_t v;
- cpu_physical_memory_read(bitband_addr(opaque, offset), &v, 1);
- return (v & (1 << ((offset >> 2) & 7))) != 0;
-}
-
-static void bitband_writeb(void *opaque, hwaddr offset,
- uint32_t value)
-{
- uint32_t addr;
- uint8_t mask;
- uint8_t v;
- addr = bitband_addr(opaque, offset);
- mask = (1 << ((offset >> 2) & 7));
- cpu_physical_memory_read(addr, &v, 1);
- if (value & 1)
- v |= mask;
- else
- v &= ~mask;
- cpu_physical_memory_write(addr, &v, 1);
-}
-
-static uint32_t bitband_readw(void *opaque, hwaddr offset)
-{
- uint32_t addr;
- uint16_t mask;
- uint16_t v;
- addr = bitband_addr(opaque, offset) & ~1;
- mask = (1 << ((offset >> 2) & 15));
- mask = tswap16(mask);
- cpu_physical_memory_read(addr, &v, 2);
- return (v & mask) != 0;
-}
-
-static void bitband_writew(void *opaque, hwaddr offset,
- uint32_t value)
-{
- uint32_t addr;
- uint16_t mask;
- uint16_t v;
- addr = bitband_addr(opaque, offset) & ~1;
- mask = (1 << ((offset >> 2) & 15));
- mask = tswap16(mask);
- cpu_physical_memory_read(addr, &v, 2);
- if (value & 1)
- v |= mask;
- else
- v &= ~mask;
- cpu_physical_memory_write(addr, &v, 2);
-}
-
-static uint32_t bitband_readl(void *opaque, hwaddr offset)
-{
- uint32_t addr;
- uint32_t mask;
- uint32_t v;
- addr = bitband_addr(opaque, offset) & ~3;
- mask = (1 << ((offset >> 2) & 31));
- mask = tswap32(mask);
- cpu_physical_memory_read(addr, &v, 4);
- return (v & mask) != 0;
-}
-
-static void bitband_writel(void *opaque, hwaddr offset,
- uint32_t value)
-{
- uint32_t addr;
- uint32_t mask;
- uint32_t v;
- addr = bitband_addr(opaque, offset) & ~3;
- mask = (1 << ((offset >> 2) & 31));
- mask = tswap32(mask);
- cpu_physical_memory_read(addr, &v, 4);
- if (value & 1)
- v |= mask;
- else
- v &= ~mask;
- cpu_physical_memory_write(addr, &v, 4);
-}
-
-static const MemoryRegionOps bitband_ops = {
- .old_mmio = {
- .read = { bitband_readb, bitband_readw, bitband_readl, },
- .write = { bitband_writeb, bitband_writew, bitband_writel, },
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-#define TYPE_BITBAND "ARM,bitband-memory"
-#define BITBAND(obj) OBJECT_CHECK(BitBandState, (obj), TYPE_BITBAND)
-
-typedef struct {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- MemoryRegion iomem;
- uint32_t base;
-} BitBandState;
-
-static int bitband_init(SysBusDevice *dev)
-{
- BitBandState *s = BITBAND(dev);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &bitband_ops, &s->base,
- "bitband", 0x02000000);
- sysbus_init_mmio(dev, &s->iomem);
- return 0;
-}
-
-static void armv7m_bitband_init(void)
-{
- DeviceState *dev;
-
- dev = qdev_create(NULL, TYPE_BITBAND);
- qdev_prop_set_uint32(dev, "base", 0x20000000);
- qdev_init_nofail(dev);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x22000000);
-
- dev = qdev_create(NULL, TYPE_BITBAND);
- qdev_prop_set_uint32(dev, "base", 0x40000000);
- qdev_init_nofail(dev);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x42000000);
-}
-
-/* Board init. */
-
-static void armv7m_reset(void *opaque)
-{
- ARMCPU *cpu = opaque;
-
- cpu_reset(CPU(cpu));
-}
-
-/* Init CPU and memory for a v7-M based board.
- mem_size is in bytes.
- Returns the NVIC array. */
-
-DeviceState *armv7m_init(MemoryRegion *system_memory, int mem_size, int num_irq,
- const char *kernel_filename, const char *cpu_model)
-{
- ARMCPU *cpu;
- CPUARMState *env;
- DeviceState *nvic;
- int image_size;
- uint64_t entry;
- uint64_t lowaddr;
- int big_endian;
- MemoryRegion *hack = g_new(MemoryRegion, 1);
-
- if (cpu_model == NULL) {
- cpu_model = "cortex-m3";
- }
- cpu = cpu_arm_init(cpu_model);
- if (cpu == NULL) {
- fprintf(stderr, "Unable to find CPU definition\n");
- exit(1);
- }
- env = &cpu->env;
-
- armv7m_bitband_init();
-
- nvic = qdev_create(NULL, "armv7m_nvic");
- qdev_prop_set_uint32(nvic, "num-irq", num_irq);
- env->nvic = nvic;
- qdev_init_nofail(nvic);
- sysbus_connect_irq(SYS_BUS_DEVICE(nvic), 0,
- qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ));
-
-#ifdef TARGET_WORDS_BIGENDIAN
- big_endian = 1;
-#else
- big_endian = 0;
-#endif
-
- if (!kernel_filename && !qtest_enabled()) {
- fprintf(stderr, "Guest image must be specified (using -kernel)\n");
- exit(1);
- }
-
- if (kernel_filename) {
- image_size = load_elf(kernel_filename, NULL, NULL, &entry, &lowaddr,
- NULL, big_endian, EM_ARM, 1, 0);
- if (image_size < 0) {
- image_size = load_image_targphys(kernel_filename, 0, mem_size);
- lowaddr = 0;
- }
- if (image_size < 0) {
- error_report("Could not load kernel '%s'", kernel_filename);
- exit(1);
- }
- }
-
- /* Hack to map an additional page of ram at the top of the address
- space. This stops qemu complaining about executing code outside RAM
- when returning from an exception. */
- memory_region_init_ram(hack, NULL, "armv7m.hack", 0x1000, &error_fatal);
- vmstate_register_ram_global(hack);
- memory_region_add_subregion(system_memory, 0xfffff000, hack);
-
- qemu_register_reset(armv7m_reset, cpu);
- return nvic;
-}
-
-static Property bitband_properties[] = {
- DEFINE_PROP_UINT32("base", BitBandState, base, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void bitband_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = bitband_init;
- dc->props = bitband_properties;
-}
-
-static const TypeInfo bitband_info = {
- .name = TYPE_BITBAND,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(BitBandState),
- .class_init = bitband_class_init,
-};
-
-static void armv7m_register_types(void)
-{
- type_register_static(&bitband_info);
-}
-
-type_init(armv7m_register_types)
diff --git a/qemu/hw/arm/ast2400.c b/qemu/hw/arm/ast2400.c
deleted file mode 100644
index 03f993863..000000000
--- a/qemu/hw/arm/ast2400.c
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * AST2400 SoC
- *
- * Andrew Jeffery <andrew@aj.id.au>
- * Jeremy Kerr <jk@ozlabs.org>
- *
- * Copyright 2016 IBM Corp.
- *
- * This code is licensed under the GPL version 2 or later. See
- * the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "exec/address-spaces.h"
-#include "hw/arm/ast2400.h"
-#include "hw/char/serial.h"
-
-#define AST2400_UART_5_BASE 0x00184000
-#define AST2400_IOMEM_SIZE 0x00200000
-#define AST2400_IOMEM_BASE 0x1E600000
-#define AST2400_VIC_BASE 0x1E6C0000
-#define AST2400_TIMER_BASE 0x1E782000
-
-static const int uart_irqs[] = { 9, 32, 33, 34, 10 };
-static const int timer_irqs[] = { 16, 17, 18, 35, 36, 37, 38, 39, };
-
-/*
- * IO handlers: simply catch any reads/writes to IO addresses that aren't
- * handled by a device mapping.
- */
-
-static uint64_t ast2400_io_read(void *p, hwaddr offset, unsigned size)
-{
- qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx " [%u]\n",
- __func__, offset, size);
- return 0;
-}
-
-static void ast2400_io_write(void *opaque, hwaddr offset, uint64_t value,
- unsigned size)
-{
- qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx " <- 0x%" PRIx64 " [%u]\n",
- __func__, offset, value, size);
-}
-
-static const MemoryRegionOps ast2400_io_ops = {
- .read = ast2400_io_read,
- .write = ast2400_io_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void ast2400_init(Object *obj)
-{
- AST2400State *s = AST2400(obj);
-
- s->cpu = cpu_arm_init("arm926");
-
- object_initialize(&s->vic, sizeof(s->vic), TYPE_ASPEED_VIC);
- object_property_add_child(obj, "vic", OBJECT(&s->vic), NULL);
- qdev_set_parent_bus(DEVICE(&s->vic), sysbus_get_default());
-
- object_initialize(&s->timerctrl, sizeof(s->timerctrl), TYPE_ASPEED_TIMER);
- object_property_add_child(obj, "timerctrl", OBJECT(&s->timerctrl), NULL);
- qdev_set_parent_bus(DEVICE(&s->timerctrl), sysbus_get_default());
-}
-
-static void ast2400_realize(DeviceState *dev, Error **errp)
-{
- int i;
- AST2400State *s = AST2400(dev);
- Error *err = NULL;
-
- /* IO space */
- memory_region_init_io(&s->iomem, NULL, &ast2400_io_ops, NULL,
- "ast2400.io", AST2400_IOMEM_SIZE);
- memory_region_add_subregion_overlap(get_system_memory(), AST2400_IOMEM_BASE,
- &s->iomem, -1);
-
- /* VIC */
- object_property_set_bool(OBJECT(&s->vic), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->vic), 0, AST2400_VIC_BASE);
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 0,
- qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_IRQ));
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 1,
- qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_FIQ));
-
- /* Timer */
- object_property_set_bool(OBJECT(&s->timerctrl), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->timerctrl), 0, AST2400_TIMER_BASE);
- for (i = 0; i < ARRAY_SIZE(timer_irqs); i++) {
- qemu_irq irq = qdev_get_gpio_in(DEVICE(&s->vic), timer_irqs[i]);
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->timerctrl), i, irq);
- }
-
- /* UART - attach an 8250 to the IO space as our UART5 */
- if (serial_hds[0]) {
- qemu_irq uart5 = qdev_get_gpio_in(DEVICE(&s->vic), uart_irqs[4]);
- serial_mm_init(&s->iomem, AST2400_UART_5_BASE, 2,
- uart5, 38400, serial_hds[0], DEVICE_LITTLE_ENDIAN);
- }
-}
-
-static void ast2400_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- dc->realize = ast2400_realize;
-
- /*
- * Reason: creates an ARM CPU, thus use after free(), see
- * arm_cpu_class_init()
- */
- dc->cannot_destroy_with_object_finalize_yet = true;
-}
-
-static const TypeInfo ast2400_type_info = {
- .name = TYPE_AST2400,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(AST2400State),
- .instance_init = ast2400_init,
- .class_init = ast2400_class_init,
-};
-
-static void ast2400_register_types(void)
-{
- type_register_static(&ast2400_type_info);
-}
-
-type_init(ast2400_register_types)
diff --git a/qemu/hw/arm/bcm2835_peripherals.c b/qemu/hw/arm/bcm2835_peripherals.c
deleted file mode 100644
index 234d51843..000000000
--- a/qemu/hw/arm/bcm2835_peripherals.c
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
- * Raspberry Pi emulation (c) 2012 Gregory Estrade
- * Upstreaming code cleanup [including bcm2835_*] (c) 2013 Jan Petrous
- *
- * Rasperry Pi 2 emulation and refactoring Copyright (c) 2015, Microsoft
- * Written by Andrew Baumann
- *
- * This code is licensed under the GNU GPLv2 and later.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/arm/bcm2835_peripherals.h"
-#include "hw/misc/bcm2835_mbox_defs.h"
-#include "hw/arm/raspi_platform.h"
-#include "sysemu/char.h"
-
-/* Peripheral base address on the VC (GPU) system bus */
-#define BCM2835_VC_PERI_BASE 0x7e000000
-
-/* Capabilities for SD controller: no DMA, high-speed, default clocks etc. */
-#define BCM2835_SDHC_CAPAREG 0x52034b4
-
-static void bcm2835_peripherals_init(Object *obj)
-{
- BCM2835PeripheralState *s = BCM2835_PERIPHERALS(obj);
-
- /* Memory region for peripheral devices, which we export to our parent */
- memory_region_init(&s->peri_mr, obj,"bcm2835-peripherals", 0x1000000);
- object_property_add_child(obj, "peripheral-io", OBJECT(&s->peri_mr), NULL);
- sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->peri_mr);
-
- /* Internal memory region for peripheral bus addresses (not exported) */
- memory_region_init(&s->gpu_bus_mr, obj, "bcm2835-gpu", (uint64_t)1 << 32);
- object_property_add_child(obj, "gpu-bus", OBJECT(&s->gpu_bus_mr), NULL);
-
- /* Internal memory region for request/response communication with
- * mailbox-addressable peripherals (not exported)
- */
- memory_region_init(&s->mbox_mr, obj, "bcm2835-mbox",
- MBOX_CHAN_COUNT << MBOX_AS_CHAN_SHIFT);
-
- /* Interrupt Controller */
- object_initialize(&s->ic, sizeof(s->ic), TYPE_BCM2835_IC);
- object_property_add_child(obj, "ic", OBJECT(&s->ic), NULL);
- qdev_set_parent_bus(DEVICE(&s->ic), sysbus_get_default());
-
- /* UART0 */
- s->uart0 = SYS_BUS_DEVICE(object_new("pl011"));
- object_property_add_child(obj, "uart0", OBJECT(s->uart0), NULL);
- qdev_set_parent_bus(DEVICE(s->uart0), sysbus_get_default());
-
- /* AUX / UART1 */
- object_initialize(&s->aux, sizeof(s->aux), TYPE_BCM2835_AUX);
- object_property_add_child(obj, "aux", OBJECT(&s->aux), NULL);
- qdev_set_parent_bus(DEVICE(&s->aux), sysbus_get_default());
-
- /* Mailboxes */
- object_initialize(&s->mboxes, sizeof(s->mboxes), TYPE_BCM2835_MBOX);
- object_property_add_child(obj, "mbox", OBJECT(&s->mboxes), NULL);
- qdev_set_parent_bus(DEVICE(&s->mboxes), sysbus_get_default());
-
- object_property_add_const_link(OBJECT(&s->mboxes), "mbox-mr",
- OBJECT(&s->mbox_mr), &error_abort);
-
- /* Framebuffer */
- object_initialize(&s->fb, sizeof(s->fb), TYPE_BCM2835_FB);
- object_property_add_child(obj, "fb", OBJECT(&s->fb), NULL);
- object_property_add_alias(obj, "vcram-size", OBJECT(&s->fb), "vcram-size",
- &error_abort);
- qdev_set_parent_bus(DEVICE(&s->fb), sysbus_get_default());
-
- object_property_add_const_link(OBJECT(&s->fb), "dma-mr",
- OBJECT(&s->gpu_bus_mr), &error_abort);
-
- /* Property channel */
- object_initialize(&s->property, sizeof(s->property), TYPE_BCM2835_PROPERTY);
- object_property_add_child(obj, "property", OBJECT(&s->property), NULL);
- object_property_add_alias(obj, "board-rev", OBJECT(&s->property),
- "board-rev", &error_abort);
- qdev_set_parent_bus(DEVICE(&s->property), sysbus_get_default());
-
- object_property_add_const_link(OBJECT(&s->property), "fb",
- OBJECT(&s->fb), &error_abort);
- object_property_add_const_link(OBJECT(&s->property), "dma-mr",
- OBJECT(&s->gpu_bus_mr), &error_abort);
-
- /* Extended Mass Media Controller */
- object_initialize(&s->sdhci, sizeof(s->sdhci), TYPE_SYSBUS_SDHCI);
- object_property_add_child(obj, "sdhci", OBJECT(&s->sdhci), NULL);
- qdev_set_parent_bus(DEVICE(&s->sdhci), sysbus_get_default());
-
- /* DMA Channels */
- object_initialize(&s->dma, sizeof(s->dma), TYPE_BCM2835_DMA);
- object_property_add_child(obj, "dma", OBJECT(&s->dma), NULL);
- qdev_set_parent_bus(DEVICE(&s->dma), sysbus_get_default());
-
- object_property_add_const_link(OBJECT(&s->dma), "dma-mr",
- OBJECT(&s->gpu_bus_mr), &error_abort);
-}
-
-static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
-{
- BCM2835PeripheralState *s = BCM2835_PERIPHERALS(dev);
- Object *obj;
- MemoryRegion *ram;
- Error *err = NULL;
- uint32_t ram_size, vcram_size;
- CharDriverState *chr;
- int n;
-
- obj = object_property_get_link(OBJECT(dev), "ram", &err);
- if (obj == NULL) {
- error_setg(errp, "%s: required ram link not found: %s",
- __func__, error_get_pretty(err));
- return;
- }
-
- ram = MEMORY_REGION(obj);
- ram_size = memory_region_size(ram);
-
- /* Map peripherals and RAM into the GPU address space. */
- memory_region_init_alias(&s->peri_mr_alias, OBJECT(s),
- "bcm2835-peripherals", &s->peri_mr, 0,
- memory_region_size(&s->peri_mr));
-
- memory_region_add_subregion_overlap(&s->gpu_bus_mr, BCM2835_VC_PERI_BASE,
- &s->peri_mr_alias, 1);
-
- /* RAM is aliased four times (different cache configurations) on the GPU */
- for (n = 0; n < 4; n++) {
- memory_region_init_alias(&s->ram_alias[n], OBJECT(s),
- "bcm2835-gpu-ram-alias[*]", ram, 0, ram_size);
- memory_region_add_subregion_overlap(&s->gpu_bus_mr, (hwaddr)n << 30,
- &s->ram_alias[n], 0);
- }
-
- /* Interrupt Controller */
- object_property_set_bool(OBJECT(&s->ic), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- memory_region_add_subregion(&s->peri_mr, ARMCTRL_IC_OFFSET,
- sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->ic), 0));
- sysbus_pass_irq(SYS_BUS_DEVICE(s), SYS_BUS_DEVICE(&s->ic));
-
- /* UART0 */
- object_property_set_bool(OBJECT(s->uart0), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- memory_region_add_subregion(&s->peri_mr, UART0_OFFSET,
- sysbus_mmio_get_region(s->uart0, 0));
- sysbus_connect_irq(s->uart0, 0,
- qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ,
- INTERRUPT_UART));
-
- /* AUX / UART1 */
- /* TODO: don't call qemu_char_get_next_serial() here, instead set
- * chardev properties for each uart at the board level, once pl011
- * (uart0) has been updated to avoid qemu_char_get_next_serial()
- */
- chr = qemu_char_get_next_serial();
- if (chr == NULL) {
- chr = qemu_chr_new("bcm2835.uart1", "null", NULL);
- }
- qdev_prop_set_chr(DEVICE(&s->aux), "chardev", chr);
-
- object_property_set_bool(OBJECT(&s->aux), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- memory_region_add_subregion(&s->peri_mr, UART1_OFFSET,
- sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->aux), 0));
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->aux), 0,
- qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ,
- INTERRUPT_AUX));
-
- /* Mailboxes */
- object_property_set_bool(OBJECT(&s->mboxes), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- memory_region_add_subregion(&s->peri_mr, ARMCTRL_0_SBM_OFFSET,
- sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->mboxes), 0));
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->mboxes), 0,
- qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_ARM_IRQ,
- INTERRUPT_ARM_MAILBOX));
-
- /* Framebuffer */
- vcram_size = (uint32_t)object_property_get_int(OBJECT(s), "vcram-size",
- &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- object_property_set_int(OBJECT(&s->fb), ram_size - vcram_size,
- "vcram-base", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- object_property_set_bool(OBJECT(&s->fb), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- memory_region_add_subregion(&s->mbox_mr, MBOX_CHAN_FB << MBOX_AS_CHAN_SHIFT,
- sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->fb), 0));
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->fb), 0,
- qdev_get_gpio_in(DEVICE(&s->mboxes), MBOX_CHAN_FB));
-
- /* Property channel */
- object_property_set_bool(OBJECT(&s->property), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- memory_region_add_subregion(&s->mbox_mr,
- MBOX_CHAN_PROPERTY << MBOX_AS_CHAN_SHIFT,
- sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->property), 0));
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->property), 0,
- qdev_get_gpio_in(DEVICE(&s->mboxes), MBOX_CHAN_PROPERTY));
-
- /* Extended Mass Media Controller */
- object_property_set_int(OBJECT(&s->sdhci), BCM2835_SDHC_CAPAREG, "capareg",
- &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- object_property_set_bool(OBJECT(&s->sdhci), true, "pending-insert-quirk",
- &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- object_property_set_bool(OBJECT(&s->sdhci), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- memory_region_add_subregion(&s->peri_mr, EMMC_OFFSET,
- sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->sdhci), 0));
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci), 0,
- qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ,
- INTERRUPT_ARASANSDIO));
- object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->sdhci), "sd-bus",
- &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- /* DMA Channels */
- object_property_set_bool(OBJECT(&s->dma), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- memory_region_add_subregion(&s->peri_mr, DMA_OFFSET,
- sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->dma), 0));
- memory_region_add_subregion(&s->peri_mr, DMA15_OFFSET,
- sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->dma), 1));
-
- for (n = 0; n <= 12; n++) {
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->dma), n,
- qdev_get_gpio_in_named(DEVICE(&s->ic),
- BCM2835_IC_GPU_IRQ,
- INTERRUPT_DMA0 + n));
- }
-}
-
-static void bcm2835_peripherals_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- dc->realize = bcm2835_peripherals_realize;
- /* Reason: realize() method uses qemu_char_get_next_serial() */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo bcm2835_peripherals_type_info = {
- .name = TYPE_BCM2835_PERIPHERALS,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(BCM2835PeripheralState),
- .instance_init = bcm2835_peripherals_init,
- .class_init = bcm2835_peripherals_class_init,
-};
-
-static void bcm2835_peripherals_register_types(void)
-{
- type_register_static(&bcm2835_peripherals_type_info);
-}
-
-type_init(bcm2835_peripherals_register_types)
diff --git a/qemu/hw/arm/bcm2836.c b/qemu/hw/arm/bcm2836.c
deleted file mode 100644
index 8451190a1..000000000
--- a/qemu/hw/arm/bcm2836.c
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Raspberry Pi emulation (c) 2012 Gregory Estrade
- * Upstreaming code cleanup [including bcm2835_*] (c) 2013 Jan Petrous
- *
- * Rasperry Pi 2 emulation and refactoring Copyright (c) 2015, Microsoft
- * Written by Andrew Baumann
- *
- * This code is licensed under the GNU GPLv2 and later.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/arm/bcm2836.h"
-#include "hw/arm/raspi_platform.h"
-#include "hw/sysbus.h"
-#include "exec/address-spaces.h"
-
-/* Peripheral base address seen by the CPU */
-#define BCM2836_PERI_BASE 0x3F000000
-
-/* "QA7" (Pi2) interrupt controller and mailboxes etc. */
-#define BCM2836_CONTROL_BASE 0x40000000
-
-static void bcm2836_init(Object *obj)
-{
- BCM2836State *s = BCM2836(obj);
- int n;
-
- for (n = 0; n < BCM2836_NCPUS; n++) {
- object_initialize(&s->cpus[n], sizeof(s->cpus[n]),
- "cortex-a15-" TYPE_ARM_CPU);
- object_property_add_child(obj, "cpu[*]", OBJECT(&s->cpus[n]),
- &error_abort);
- }
-
- object_initialize(&s->control, sizeof(s->control), TYPE_BCM2836_CONTROL);
- object_property_add_child(obj, "control", OBJECT(&s->control), NULL);
- qdev_set_parent_bus(DEVICE(&s->control), sysbus_get_default());
-
- object_initialize(&s->peripherals, sizeof(s->peripherals),
- TYPE_BCM2835_PERIPHERALS);
- object_property_add_child(obj, "peripherals", OBJECT(&s->peripherals),
- &error_abort);
- object_property_add_alias(obj, "board-rev", OBJECT(&s->peripherals),
- "board-rev", &error_abort);
- object_property_add_alias(obj, "vcram-size", OBJECT(&s->peripherals),
- "vcram-size", &error_abort);
- qdev_set_parent_bus(DEVICE(&s->peripherals), sysbus_get_default());
-}
-
-static void bcm2836_realize(DeviceState *dev, Error **errp)
-{
- BCM2836State *s = BCM2836(dev);
- Object *obj;
- Error *err = NULL;
- int n;
-
- /* common peripherals from bcm2835 */
-
- obj = object_property_get_link(OBJECT(dev), "ram", &err);
- if (obj == NULL) {
- error_setg(errp, "%s: required ram link not found: %s",
- __func__, error_get_pretty(err));
- return;
- }
-
- object_property_add_const_link(OBJECT(&s->peripherals), "ram", obj, &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- object_property_set_bool(OBJECT(&s->peripherals), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->peripherals),
- "sd-bus", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->peripherals), 0,
- BCM2836_PERI_BASE, 1);
-
- /* bcm2836 interrupt controller (and mailboxes, etc.) */
- object_property_set_bool(OBJECT(&s->control), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->control), 0, BCM2836_CONTROL_BASE);
-
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 0,
- qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-irq", 0));
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 1,
- qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-fiq", 0));
-
- for (n = 0; n < BCM2836_NCPUS; n++) {
- /* Mirror bcm2836, which has clusterid set to 0xf
- * TODO: this should be converted to a property of ARM_CPU
- */
- s->cpus[n].mp_affinity = 0xF00 | n;
-
- /* set periphbase/CBAR value for CPU-local registers */
- object_property_set_int(OBJECT(&s->cpus[n]),
- BCM2836_PERI_BASE + MCORE_OFFSET,
- "reset-cbar", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- /* start powered off if not enabled */
- object_property_set_bool(OBJECT(&s->cpus[n]), n >= s->enabled_cpus,
- "start-powered-off", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- object_property_set_bool(OBJECT(&s->cpus[n]), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- /* Connect irq/fiq outputs from the interrupt controller. */
- qdev_connect_gpio_out_named(DEVICE(&s->control), "irq", n,
- qdev_get_gpio_in(DEVICE(&s->cpus[n]), ARM_CPU_IRQ));
- qdev_connect_gpio_out_named(DEVICE(&s->control), "fiq", n,
- qdev_get_gpio_in(DEVICE(&s->cpus[n]), ARM_CPU_FIQ));
-
- /* Connect timers from the CPU to the interrupt controller */
- qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_PHYS,
- qdev_get_gpio_in_named(DEVICE(&s->control), "cntpnsirq", n));
- qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_VIRT,
- qdev_get_gpio_in_named(DEVICE(&s->control), "cntvirq", n));
- qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_HYP,
- qdev_get_gpio_in_named(DEVICE(&s->control), "cnthpirq", n));
- qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_SEC,
- qdev_get_gpio_in_named(DEVICE(&s->control), "cntpsirq", n));
- }
-}
-
-static Property bcm2836_props[] = {
- DEFINE_PROP_UINT32("enabled-cpus", BCM2836State, enabled_cpus, BCM2836_NCPUS),
- DEFINE_PROP_END_OF_LIST()
-};
-
-static void bcm2836_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- dc->props = bcm2836_props;
- dc->realize = bcm2836_realize;
-
- /*
- * Reason: creates an ARM CPU, thus use after free(), see
- * arm_cpu_class_init()
- */
- dc->cannot_destroy_with_object_finalize_yet = true;
-}
-
-static const TypeInfo bcm2836_type_info = {
- .name = TYPE_BCM2836,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(BCM2836State),
- .instance_init = bcm2836_init,
- .class_init = bcm2836_class_init,
-};
-
-static void bcm2836_register_types(void)
-{
- type_register_static(&bcm2836_type_info);
-}
-
-type_init(bcm2836_register_types)
diff --git a/qemu/hw/arm/boot.c b/qemu/hw/arm/boot.c
deleted file mode 100644
index 587694557..000000000
--- a/qemu/hw/arm/boot.c
+++ /dev/null
@@ -1,994 +0,0 @@
-/*
- * ARM kernel loader.
- *
- * Copyright (c) 2006-2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/hw.h"
-#include "hw/arm/arm.h"
-#include "hw/arm/linux-boot-if.h"
-#include "sysemu/kvm.h"
-#include "sysemu/sysemu.h"
-#include "hw/boards.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "sysemu/device_tree.h"
-#include "qemu/config-file.h"
-#include "exec/address-spaces.h"
-
-/* Kernel boot protocol is specified in the kernel docs
- * Documentation/arm/Booting and Documentation/arm64/booting.txt
- * They have different preferred image load offsets from system RAM base.
- */
-#define KERNEL_ARGS_ADDR 0x100
-#define KERNEL_LOAD_ADDR 0x00010000
-#define KERNEL64_LOAD_ADDR 0x00080000
-
-typedef enum {
- FIXUP_NONE = 0, /* do nothing */
- FIXUP_TERMINATOR, /* end of insns */
- FIXUP_BOARDID, /* overwrite with board ID number */
- FIXUP_BOARD_SETUP, /* overwrite with board specific setup code address */
- FIXUP_ARGPTR, /* overwrite with pointer to kernel args */
- FIXUP_ENTRYPOINT, /* overwrite with kernel entry point */
- FIXUP_GIC_CPU_IF, /* overwrite with GIC CPU interface address */
- FIXUP_BOOTREG, /* overwrite with boot register address */
- FIXUP_DSB, /* overwrite with correct DSB insn for cpu */
- FIXUP_MAX,
-} FixupType;
-
-typedef struct ARMInsnFixup {
- uint32_t insn;
- FixupType fixup;
-} ARMInsnFixup;
-
-static const ARMInsnFixup bootloader_aarch64[] = {
- { 0x580000c0 }, /* ldr x0, arg ; Load the lower 32-bits of DTB */
- { 0xaa1f03e1 }, /* mov x1, xzr */
- { 0xaa1f03e2 }, /* mov x2, xzr */
- { 0xaa1f03e3 }, /* mov x3, xzr */
- { 0x58000084 }, /* ldr x4, entry ; Load the lower 32-bits of kernel entry */
- { 0xd61f0080 }, /* br x4 ; Jump to the kernel entry point */
- { 0, FIXUP_ARGPTR }, /* arg: .word @DTB Lower 32-bits */
- { 0 }, /* .word @DTB Higher 32-bits */
- { 0, FIXUP_ENTRYPOINT }, /* entry: .word @Kernel Entry Lower 32-bits */
- { 0 }, /* .word @Kernel Entry Higher 32-bits */
- { 0, FIXUP_TERMINATOR }
-};
-
-/* A very small bootloader: call the board-setup code (if needed),
- * set r0-r2, then jump to the kernel.
- * If we're not calling boot setup code then we don't copy across
- * the first BOOTLOADER_NO_BOARD_SETUP_OFFSET insns in this array.
- */
-
-static const ARMInsnFixup bootloader[] = {
- { 0xe28fe004 }, /* add lr, pc, #4 */
- { 0xe51ff004 }, /* ldr pc, [pc, #-4] */
- { 0, FIXUP_BOARD_SETUP },
-#define BOOTLOADER_NO_BOARD_SETUP_OFFSET 3
- { 0xe3a00000 }, /* mov r0, #0 */
- { 0xe59f1004 }, /* ldr r1, [pc, #4] */
- { 0xe59f2004 }, /* ldr r2, [pc, #4] */
- { 0xe59ff004 }, /* ldr pc, [pc, #4] */
- { 0, FIXUP_BOARDID },
- { 0, FIXUP_ARGPTR },
- { 0, FIXUP_ENTRYPOINT },
- { 0, FIXUP_TERMINATOR }
-};
-
-/* Handling for secondary CPU boot in a multicore system.
- * Unlike the uniprocessor/primary CPU boot, this is platform
- * dependent. The default code here is based on the secondary
- * CPU boot protocol used on realview/vexpress boards, with
- * some parameterisation to increase its flexibility.
- * QEMU platform models for which this code is not appropriate
- * should override write_secondary_boot and secondary_cpu_reset_hook
- * instead.
- *
- * This code enables the interrupt controllers for the secondary
- * CPUs and then puts all the secondary CPUs into a loop waiting
- * for an interprocessor interrupt and polling a configurable
- * location for the kernel secondary CPU entry point.
- */
-#define DSB_INSN 0xf57ff04f
-#define CP15_DSB_INSN 0xee070f9a /* mcr cp15, 0, r0, c7, c10, 4 */
-
-static const ARMInsnFixup smpboot[] = {
- { 0xe59f2028 }, /* ldr r2, gic_cpu_if */
- { 0xe59f0028 }, /* ldr r0, bootreg_addr */
- { 0xe3a01001 }, /* mov r1, #1 */
- { 0xe5821000 }, /* str r1, [r2] - set GICC_CTLR.Enable */
- { 0xe3a010ff }, /* mov r1, #0xff */
- { 0xe5821004 }, /* str r1, [r2, 4] - set GIC_PMR.Priority to 0xff */
- { 0, FIXUP_DSB }, /* dsb */
- { 0xe320f003 }, /* wfi */
- { 0xe5901000 }, /* ldr r1, [r0] */
- { 0xe1110001 }, /* tst r1, r1 */
- { 0x0afffffb }, /* beq <wfi> */
- { 0xe12fff11 }, /* bx r1 */
- { 0, FIXUP_GIC_CPU_IF }, /* gic_cpu_if: .word 0x.... */
- { 0, FIXUP_BOOTREG }, /* bootreg_addr: .word 0x.... */
- { 0, FIXUP_TERMINATOR }
-};
-
-static void write_bootloader(const char *name, hwaddr addr,
- const ARMInsnFixup *insns, uint32_t *fixupcontext)
-{
- /* Fix up the specified bootloader fragment and write it into
- * guest memory using rom_add_blob_fixed(). fixupcontext is
- * an array giving the values to write in for the fixup types
- * which write a value into the code array.
- */
- int i, len;
- uint32_t *code;
-
- len = 0;
- while (insns[len].fixup != FIXUP_TERMINATOR) {
- len++;
- }
-
- code = g_new0(uint32_t, len);
-
- for (i = 0; i < len; i++) {
- uint32_t insn = insns[i].insn;
- FixupType fixup = insns[i].fixup;
-
- switch (fixup) {
- case FIXUP_NONE:
- break;
- case FIXUP_BOARDID:
- case FIXUP_BOARD_SETUP:
- case FIXUP_ARGPTR:
- case FIXUP_ENTRYPOINT:
- case FIXUP_GIC_CPU_IF:
- case FIXUP_BOOTREG:
- case FIXUP_DSB:
- insn = fixupcontext[fixup];
- break;
- default:
- abort();
- }
- code[i] = tswap32(insn);
- }
-
- rom_add_blob_fixed(name, code, len * sizeof(uint32_t), addr);
-
- g_free(code);
-}
-
-static void default_write_secondary(ARMCPU *cpu,
- const struct arm_boot_info *info)
-{
- uint32_t fixupcontext[FIXUP_MAX];
-
- fixupcontext[FIXUP_GIC_CPU_IF] = info->gic_cpu_if_addr;
- fixupcontext[FIXUP_BOOTREG] = info->smp_bootreg_addr;
- if (arm_feature(&cpu->env, ARM_FEATURE_V7)) {
- fixupcontext[FIXUP_DSB] = DSB_INSN;
- } else {
- fixupcontext[FIXUP_DSB] = CP15_DSB_INSN;
- }
-
- write_bootloader("smpboot", info->smp_loader_start,
- smpboot, fixupcontext);
-}
-
-void arm_write_secure_board_setup_dummy_smc(ARMCPU *cpu,
- const struct arm_boot_info *info,
- hwaddr mvbar_addr)
-{
- int n;
- uint32_t mvbar_blob[] = {
- /* mvbar_addr: secure monitor vectors
- * Default unimplemented and unused vectors to spin. Makes it
- * easier to debug (as opposed to the CPU running away).
- */
- 0xeafffffe, /* (spin) */
- 0xeafffffe, /* (spin) */
- 0xe1b0f00e, /* movs pc, lr ;SMC exception return */
- 0xeafffffe, /* (spin) */
- 0xeafffffe, /* (spin) */
- 0xeafffffe, /* (spin) */
- 0xeafffffe, /* (spin) */
- 0xeafffffe, /* (spin) */
- };
- uint32_t board_setup_blob[] = {
- /* board setup addr */
- 0xe3a00e00 + (mvbar_addr >> 4), /* mov r0, #mvbar_addr */
- 0xee0c0f30, /* mcr p15, 0, r0, c12, c0, 1 ;set MVBAR */
- 0xee110f11, /* mrc p15, 0, r0, c1 , c1, 0 ;read SCR */
- 0xe3800031, /* orr r0, #0x31 ;enable AW, FW, NS */
- 0xee010f11, /* mcr p15, 0, r0, c1, c1, 0 ;write SCR */
- 0xe1a0100e, /* mov r1, lr ;save LR across SMC */
- 0xe1600070, /* smc #0 ;call monitor to flush SCR */
- 0xe1a0f001, /* mov pc, r1 ;return */
- };
-
- /* check that mvbar_addr is correctly aligned and relocatable (using MOV) */
- assert((mvbar_addr & 0x1f) == 0 && (mvbar_addr >> 4) < 0x100);
-
- /* check that these blobs don't overlap */
- assert((mvbar_addr + sizeof(mvbar_blob) <= info->board_setup_addr)
- || (info->board_setup_addr + sizeof(board_setup_blob) <= mvbar_addr));
-
- for (n = 0; n < ARRAY_SIZE(mvbar_blob); n++) {
- mvbar_blob[n] = tswap32(mvbar_blob[n]);
- }
- rom_add_blob_fixed("board-setup-mvbar", mvbar_blob, sizeof(mvbar_blob),
- mvbar_addr);
-
- for (n = 0; n < ARRAY_SIZE(board_setup_blob); n++) {
- board_setup_blob[n] = tswap32(board_setup_blob[n]);
- }
- rom_add_blob_fixed("board-setup", board_setup_blob,
- sizeof(board_setup_blob), info->board_setup_addr);
-}
-
-static void default_reset_secondary(ARMCPU *cpu,
- const struct arm_boot_info *info)
-{
- CPUState *cs = CPU(cpu);
-
- address_space_stl_notdirty(&address_space_memory, info->smp_bootreg_addr,
- 0, MEMTXATTRS_UNSPECIFIED, NULL);
- cpu_set_pc(cs, info->smp_loader_start);
-}
-
-static inline bool have_dtb(const struct arm_boot_info *info)
-{
- return info->dtb_filename || info->get_dtb;
-}
-
-#define WRITE_WORD(p, value) do { \
- address_space_stl_notdirty(&address_space_memory, p, value, \
- MEMTXATTRS_UNSPECIFIED, NULL); \
- p += 4; \
-} while (0)
-
-static void set_kernel_args(const struct arm_boot_info *info)
-{
- int initrd_size = info->initrd_size;
- hwaddr base = info->loader_start;
- hwaddr p;
-
- p = base + KERNEL_ARGS_ADDR;
- /* ATAG_CORE */
- WRITE_WORD(p, 5);
- WRITE_WORD(p, 0x54410001);
- WRITE_WORD(p, 1);
- WRITE_WORD(p, 0x1000);
- WRITE_WORD(p, 0);
- /* ATAG_MEM */
- /* TODO: handle multiple chips on one ATAG list */
- WRITE_WORD(p, 4);
- WRITE_WORD(p, 0x54410002);
- WRITE_WORD(p, info->ram_size);
- WRITE_WORD(p, info->loader_start);
- if (initrd_size) {
- /* ATAG_INITRD2 */
- WRITE_WORD(p, 4);
- WRITE_WORD(p, 0x54420005);
- WRITE_WORD(p, info->initrd_start);
- WRITE_WORD(p, initrd_size);
- }
- if (info->kernel_cmdline && *info->kernel_cmdline) {
- /* ATAG_CMDLINE */
- int cmdline_size;
-
- cmdline_size = strlen(info->kernel_cmdline);
- cpu_physical_memory_write(p + 8, info->kernel_cmdline,
- cmdline_size + 1);
- cmdline_size = (cmdline_size >> 2) + 1;
- WRITE_WORD(p, cmdline_size + 2);
- WRITE_WORD(p, 0x54410009);
- p += cmdline_size * 4;
- }
- if (info->atag_board) {
- /* ATAG_BOARD */
- int atag_board_len;
- uint8_t atag_board_buf[0x1000];
-
- atag_board_len = (info->atag_board(info, atag_board_buf) + 3) & ~3;
- WRITE_WORD(p, (atag_board_len + 8) >> 2);
- WRITE_WORD(p, 0x414f4d50);
- cpu_physical_memory_write(p, atag_board_buf, atag_board_len);
- p += atag_board_len;
- }
- /* ATAG_END */
- WRITE_WORD(p, 0);
- WRITE_WORD(p, 0);
-}
-
-static void set_kernel_args_old(const struct arm_boot_info *info)
-{
- hwaddr p;
- const char *s;
- int initrd_size = info->initrd_size;
- hwaddr base = info->loader_start;
-
- /* see linux/include/asm-arm/setup.h */
- p = base + KERNEL_ARGS_ADDR;
- /* page_size */
- WRITE_WORD(p, 4096);
- /* nr_pages */
- WRITE_WORD(p, info->ram_size / 4096);
- /* ramdisk_size */
- WRITE_WORD(p, 0);
-#define FLAG_READONLY 1
-#define FLAG_RDLOAD 4
-#define FLAG_RDPROMPT 8
- /* flags */
- WRITE_WORD(p, FLAG_READONLY | FLAG_RDLOAD | FLAG_RDPROMPT);
- /* rootdev */
- WRITE_WORD(p, (31 << 8) | 0); /* /dev/mtdblock0 */
- /* video_num_cols */
- WRITE_WORD(p, 0);
- /* video_num_rows */
- WRITE_WORD(p, 0);
- /* video_x */
- WRITE_WORD(p, 0);
- /* video_y */
- WRITE_WORD(p, 0);
- /* memc_control_reg */
- WRITE_WORD(p, 0);
- /* unsigned char sounddefault */
- /* unsigned char adfsdrives */
- /* unsigned char bytes_per_char_h */
- /* unsigned char bytes_per_char_v */
- WRITE_WORD(p, 0);
- /* pages_in_bank[4] */
- WRITE_WORD(p, 0);
- WRITE_WORD(p, 0);
- WRITE_WORD(p, 0);
- WRITE_WORD(p, 0);
- /* pages_in_vram */
- WRITE_WORD(p, 0);
- /* initrd_start */
- if (initrd_size) {
- WRITE_WORD(p, info->initrd_start);
- } else {
- WRITE_WORD(p, 0);
- }
- /* initrd_size */
- WRITE_WORD(p, initrd_size);
- /* rd_start */
- WRITE_WORD(p, 0);
- /* system_rev */
- WRITE_WORD(p, 0);
- /* system_serial_low */
- WRITE_WORD(p, 0);
- /* system_serial_high */
- WRITE_WORD(p, 0);
- /* mem_fclk_21285 */
- WRITE_WORD(p, 0);
- /* zero unused fields */
- while (p < base + KERNEL_ARGS_ADDR + 256 + 1024) {
- WRITE_WORD(p, 0);
- }
- s = info->kernel_cmdline;
- if (s) {
- cpu_physical_memory_write(p, s, strlen(s) + 1);
- } else {
- WRITE_WORD(p, 0);
- }
-}
-
-/**
- * load_dtb() - load a device tree binary image into memory
- * @addr: the address to load the image at
- * @binfo: struct describing the boot environment
- * @addr_limit: upper limit of the available memory area at @addr
- *
- * Load a device tree supplied by the machine or by the user with the
- * '-dtb' command line option, and put it at offset @addr in target
- * memory.
- *
- * If @addr_limit contains a meaningful value (i.e., it is strictly greater
- * than @addr), the device tree is only loaded if its size does not exceed
- * the limit.
- *
- * Returns: the size of the device tree image on success,
- * 0 if the image size exceeds the limit,
- * -1 on errors.
- *
- * Note: Must not be called unless have_dtb(binfo) is true.
- */
-static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
- hwaddr addr_limit)
-{
- void *fdt = NULL;
- int size, rc;
- uint32_t acells, scells;
-
- if (binfo->dtb_filename) {
- char *filename;
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, binfo->dtb_filename);
- if (!filename) {
- fprintf(stderr, "Couldn't open dtb file %s\n", binfo->dtb_filename);
- goto fail;
- }
-
- fdt = load_device_tree(filename, &size);
- if (!fdt) {
- fprintf(stderr, "Couldn't open dtb file %s\n", filename);
- g_free(filename);
- goto fail;
- }
- g_free(filename);
- } else {
- fdt = binfo->get_dtb(binfo, &size);
- if (!fdt) {
- fprintf(stderr, "Board was unable to create a dtb blob\n");
- goto fail;
- }
- }
-
- if (addr_limit > addr && size > (addr_limit - addr)) {
- /* Installing the device tree blob at addr would exceed addr_limit.
- * Whether this constitutes failure is up to the caller to decide,
- * so just return 0 as size, i.e., no error.
- */
- g_free(fdt);
- return 0;
- }
-
- acells = qemu_fdt_getprop_cell(fdt, "/", "#address-cells",
- NULL, &error_fatal);
- scells = qemu_fdt_getprop_cell(fdt, "/", "#size-cells",
- NULL, &error_fatal);
- if (acells == 0 || scells == 0) {
- fprintf(stderr, "dtb file invalid (#address-cells or #size-cells 0)\n");
- goto fail;
- }
-
- if (scells < 2 && binfo->ram_size >= (1ULL << 32)) {
- /* This is user error so deserves a friendlier error message
- * than the failure of setprop_sized_cells would provide
- */
- fprintf(stderr, "qemu: dtb file not compatible with "
- "RAM size > 4GB\n");
- goto fail;
- }
-
- rc = qemu_fdt_setprop_sized_cells(fdt, "/memory", "reg",
- acells, binfo->loader_start,
- scells, binfo->ram_size);
- if (rc < 0) {
- fprintf(stderr, "couldn't set /memory/reg\n");
- goto fail;
- }
-
- if (binfo->kernel_cmdline && *binfo->kernel_cmdline) {
- rc = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
- binfo->kernel_cmdline);
- if (rc < 0) {
- fprintf(stderr, "couldn't set /chosen/bootargs\n");
- goto fail;
- }
- }
-
- if (binfo->initrd_size) {
- rc = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start",
- binfo->initrd_start);
- if (rc < 0) {
- fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
- goto fail;
- }
-
- rc = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
- binfo->initrd_start + binfo->initrd_size);
- if (rc < 0) {
- fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
- goto fail;
- }
- }
-
- if (binfo->modify_dtb) {
- binfo->modify_dtb(binfo, fdt);
- }
-
- qemu_fdt_dumpdtb(fdt, size);
-
- /* Put the DTB into the memory map as a ROM image: this will ensure
- * the DTB is copied again upon reset, even if addr points into RAM.
- */
- rom_add_blob_fixed("dtb", fdt, size, addr);
-
- g_free(fdt);
-
- return size;
-
-fail:
- g_free(fdt);
- return -1;
-}
-
-static void do_cpu_reset(void *opaque)
-{
- ARMCPU *cpu = opaque;
- CPUState *cs = CPU(cpu);
- CPUARMState *env = &cpu->env;
- const struct arm_boot_info *info = env->boot_info;
-
- cpu_reset(cs);
- if (info) {
- if (!info->is_linux) {
- int i;
- /* Jump to the entry point. */
- uint64_t entry = info->entry;
-
- switch (info->endianness) {
- case ARM_ENDIANNESS_LE:
- env->cp15.sctlr_el[1] &= ~SCTLR_E0E;
- for (i = 1; i < 4; ++i) {
- env->cp15.sctlr_el[i] &= ~SCTLR_EE;
- }
- env->uncached_cpsr &= ~CPSR_E;
- break;
- case ARM_ENDIANNESS_BE8:
- env->cp15.sctlr_el[1] |= SCTLR_E0E;
- for (i = 1; i < 4; ++i) {
- env->cp15.sctlr_el[i] |= SCTLR_EE;
- }
- env->uncached_cpsr |= CPSR_E;
- break;
- case ARM_ENDIANNESS_BE32:
- env->cp15.sctlr_el[1] |= SCTLR_B;
- break;
- case ARM_ENDIANNESS_UNKNOWN:
- break; /* Board's decision */
- default:
- g_assert_not_reached();
- }
-
- if (!env->aarch64) {
- env->thumb = info->entry & 1;
- entry &= 0xfffffffe;
- }
- cpu_set_pc(cs, entry);
- } else {
- /* If we are booting Linux then we need to check whether we are
- * booting into secure or non-secure state and adjust the state
- * accordingly. Out of reset, ARM is defined to be in secure state
- * (SCR.NS = 0), we change that here if non-secure boot has been
- * requested.
- */
- if (arm_feature(env, ARM_FEATURE_EL3)) {
- /* AArch64 is defined to come out of reset into EL3 if enabled.
- * If we are booting Linux then we need to adjust our EL as
- * Linux expects us to be in EL2 or EL1. AArch32 resets into
- * SVC, which Linux expects, so no privilege/exception level to
- * adjust.
- */
- if (env->aarch64) {
- env->cp15.scr_el3 |= SCR_RW;
- if (arm_feature(env, ARM_FEATURE_EL2)) {
- env->cp15.hcr_el2 |= HCR_RW;
- env->pstate = PSTATE_MODE_EL2h;
- } else {
- env->pstate = PSTATE_MODE_EL1h;
- }
- }
-
- /* Set to non-secure if not a secure boot */
- if (!info->secure_boot &&
- (cs != first_cpu || !info->secure_board_setup)) {
- /* Linux expects non-secure state */
- env->cp15.scr_el3 |= SCR_NS;
- }
- }
-
- if (cs == first_cpu) {
- cpu_set_pc(cs, info->loader_start);
-
- if (!have_dtb(info)) {
- if (old_param) {
- set_kernel_args_old(info);
- } else {
- set_kernel_args(info);
- }
- }
- } else {
- info->secondary_cpu_reset_hook(cpu, info);
- }
- }
- }
-}
-
-/**
- * load_image_to_fw_cfg() - Load an image file into an fw_cfg entry identified
- * by key.
- * @fw_cfg: The firmware config instance to store the data in.
- * @size_key: The firmware config key to store the size of the loaded
- * data under, with fw_cfg_add_i32().
- * @data_key: The firmware config key to store the loaded data under,
- * with fw_cfg_add_bytes().
- * @image_name: The name of the image file to load. If it is NULL, the
- * function returns without doing anything.
- * @try_decompress: Whether the image should be decompressed (gunzipped) before
- * adding it to fw_cfg. If decompression fails, the image is
- * loaded as-is.
- *
- * In case of failure, the function prints an error message to stderr and the
- * process exits with status 1.
- */
-static void load_image_to_fw_cfg(FWCfgState *fw_cfg, uint16_t size_key,
- uint16_t data_key, const char *image_name,
- bool try_decompress)
-{
- size_t size = -1;
- uint8_t *data;
-
- if (image_name == NULL) {
- return;
- }
-
- if (try_decompress) {
- size = load_image_gzipped_buffer(image_name,
- LOAD_IMAGE_MAX_GUNZIP_BYTES, &data);
- }
-
- if (size == (size_t)-1) {
- gchar *contents;
- gsize length;
-
- if (!g_file_get_contents(image_name, &contents, &length, NULL)) {
- fprintf(stderr, "failed to load \"%s\"\n", image_name);
- exit(1);
- }
- size = length;
- data = (uint8_t *)contents;
- }
-
- fw_cfg_add_i32(fw_cfg, size_key, size);
- fw_cfg_add_bytes(fw_cfg, data_key, data, size);
-}
-
-static int do_arm_linux_init(Object *obj, void *opaque)
-{
- if (object_dynamic_cast(obj, TYPE_ARM_LINUX_BOOT_IF)) {
- ARMLinuxBootIf *albif = ARM_LINUX_BOOT_IF(obj);
- ARMLinuxBootIfClass *albifc = ARM_LINUX_BOOT_IF_GET_CLASS(obj);
- struct arm_boot_info *info = opaque;
-
- if (albifc->arm_linux_init) {
- albifc->arm_linux_init(albif, info->secure_boot);
- }
- }
- return 0;
-}
-
-static uint64_t arm_load_elf(struct arm_boot_info *info, uint64_t *pentry,
- uint64_t *lowaddr, uint64_t *highaddr,
- int elf_machine)
-{
- bool elf_is64;
- union {
- Elf32_Ehdr h32;
- Elf64_Ehdr h64;
- } elf_header;
- int data_swab = 0;
- bool big_endian;
- uint64_t ret = -1;
- Error *err = NULL;
-
-
- load_elf_hdr(info->kernel_filename, &elf_header, &elf_is64, &err);
- if (err) {
- return ret;
- }
-
- if (elf_is64) {
- big_endian = elf_header.h64.e_ident[EI_DATA] == ELFDATA2MSB;
- info->endianness = big_endian ? ARM_ENDIANNESS_BE8
- : ARM_ENDIANNESS_LE;
- } else {
- big_endian = elf_header.h32.e_ident[EI_DATA] == ELFDATA2MSB;
- if (big_endian) {
- if (bswap32(elf_header.h32.e_flags) & EF_ARM_BE8) {
- info->endianness = ARM_ENDIANNESS_BE8;
- } else {
- info->endianness = ARM_ENDIANNESS_BE32;
- /* In BE32, the CPU has a different view of the per-byte
- * address map than the rest of the system. BE32 ELF files
- * are organised such that they can be programmed through
- * the CPU's per-word byte-reversed view of the world. QEMU
- * however loads ELF files independently of the CPU. So
- * tell the ELF loader to byte reverse the data for us.
- */
- data_swab = 2;
- }
- } else {
- info->endianness = ARM_ENDIANNESS_LE;
- }
- }
-
- ret = load_elf(info->kernel_filename, NULL, NULL,
- pentry, lowaddr, highaddr, big_endian, elf_machine,
- 1, data_swab);
- if (ret <= 0) {
- /* The header loaded but the image didn't */
- exit(1);
- }
-
- return ret;
-}
-
-static void arm_load_kernel_notify(Notifier *notifier, void *data)
-{
- CPUState *cs;
- int kernel_size;
- int initrd_size;
- int is_linux = 0;
- uint64_t elf_entry, elf_low_addr, elf_high_addr;
- int elf_machine;
- hwaddr entry, kernel_load_offset;
- static const ARMInsnFixup *primary_loader;
- ArmLoadKernelNotifier *n = DO_UPCAST(ArmLoadKernelNotifier,
- notifier, notifier);
- ARMCPU *cpu = n->cpu;
- struct arm_boot_info *info =
- container_of(n, struct arm_boot_info, load_kernel_notifier);
-
- /* The board code is not supposed to set secure_board_setup unless
- * running its code in secure mode is actually possible, and KVM
- * doesn't support secure.
- */
- assert(!(info->secure_board_setup && kvm_enabled()));
-
- /* Load the kernel. */
- if (!info->kernel_filename || info->firmware_loaded) {
-
- if (have_dtb(info)) {
- /* If we have a device tree blob, but no kernel to supply it to (or
- * the kernel is supposed to be loaded by the bootloader), copy the
- * DTB to the base of RAM for the bootloader to pick up.
- */
- if (load_dtb(info->loader_start, info, 0) < 0) {
- exit(1);
- }
- }
-
- if (info->kernel_filename) {
- FWCfgState *fw_cfg;
- bool try_decompressing_kernel;
-
- fw_cfg = fw_cfg_find();
- try_decompressing_kernel = arm_feature(&cpu->env,
- ARM_FEATURE_AARCH64);
-
- /* Expose the kernel, the command line, and the initrd in fw_cfg.
- * We don't process them here at all, it's all left to the
- * firmware.
- */
- load_image_to_fw_cfg(fw_cfg,
- FW_CFG_KERNEL_SIZE, FW_CFG_KERNEL_DATA,
- info->kernel_filename,
- try_decompressing_kernel);
- load_image_to_fw_cfg(fw_cfg,
- FW_CFG_INITRD_SIZE, FW_CFG_INITRD_DATA,
- info->initrd_filename, false);
-
- if (info->kernel_cmdline) {
- fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE,
- strlen(info->kernel_cmdline) + 1);
- fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA,
- info->kernel_cmdline);
- }
- }
-
- /* We will start from address 0 (typically a boot ROM image) in the
- * same way as hardware.
- */
- return;
- }
-
- if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
- primary_loader = bootloader_aarch64;
- kernel_load_offset = KERNEL64_LOAD_ADDR;
- elf_machine = EM_AARCH64;
- } else {
- primary_loader = bootloader;
- if (!info->write_board_setup) {
- primary_loader += BOOTLOADER_NO_BOARD_SETUP_OFFSET;
- }
- kernel_load_offset = KERNEL_LOAD_ADDR;
- elf_machine = EM_ARM;
- }
-
- info->dtb_filename = qemu_opt_get(qemu_get_machine_opts(), "dtb");
-
- if (!info->secondary_cpu_reset_hook) {
- info->secondary_cpu_reset_hook = default_reset_secondary;
- }
- if (!info->write_secondary_boot) {
- info->write_secondary_boot = default_write_secondary;
- }
-
- if (info->nb_cpus == 0)
- info->nb_cpus = 1;
-
- /* We want to put the initrd far enough into RAM that when the
- * kernel is uncompressed it will not clobber the initrd. However
- * on boards without much RAM we must ensure that we still leave
- * enough room for a decent sized initrd, and on boards with large
- * amounts of RAM we must avoid the initrd being so far up in RAM
- * that it is outside lowmem and inaccessible to the kernel.
- * So for boards with less than 256MB of RAM we put the initrd
- * halfway into RAM, and for boards with 256MB of RAM or more we put
- * the initrd at 128MB.
- */
- info->initrd_start = info->loader_start +
- MIN(info->ram_size / 2, 128 * 1024 * 1024);
-
- /* Assume that raw images are linux kernels, and ELF images are not. */
- kernel_size = arm_load_elf(info, &elf_entry, &elf_low_addr,
- &elf_high_addr, elf_machine);
- if (kernel_size > 0 && have_dtb(info)) {
- /* If there is still some room left at the base of RAM, try and put
- * the DTB there like we do for images loaded with -bios or -pflash.
- */
- if (elf_low_addr > info->loader_start
- || elf_high_addr < info->loader_start) {
- /* Pass elf_low_addr as address limit to load_dtb if it may be
- * pointing into RAM, otherwise pass '0' (no limit)
- */
- if (elf_low_addr < info->loader_start) {
- elf_low_addr = 0;
- }
- if (load_dtb(info->loader_start, info, elf_low_addr) < 0) {
- exit(1);
- }
- }
- }
- entry = elf_entry;
- if (kernel_size < 0) {
- kernel_size = load_uimage(info->kernel_filename, &entry, NULL,
- &is_linux, NULL, NULL);
- }
- /* On aarch64, it's the bootloader's job to uncompress the kernel. */
- if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64) && kernel_size < 0) {
- entry = info->loader_start + kernel_load_offset;
- kernel_size = load_image_gzipped(info->kernel_filename, entry,
- info->ram_size - kernel_load_offset);
- is_linux = 1;
- }
- if (kernel_size < 0) {
- entry = info->loader_start + kernel_load_offset;
- kernel_size = load_image_targphys(info->kernel_filename, entry,
- info->ram_size - kernel_load_offset);
- is_linux = 1;
- }
- if (kernel_size < 0) {
- fprintf(stderr, "qemu: could not load kernel '%s'\n",
- info->kernel_filename);
- exit(1);
- }
- info->entry = entry;
- if (is_linux) {
- uint32_t fixupcontext[FIXUP_MAX];
-
- if (info->initrd_filename) {
- initrd_size = load_ramdisk(info->initrd_filename,
- info->initrd_start,
- info->ram_size -
- info->initrd_start);
- if (initrd_size < 0) {
- initrd_size = load_image_targphys(info->initrd_filename,
- info->initrd_start,
- info->ram_size -
- info->initrd_start);
- }
- if (initrd_size < 0) {
- fprintf(stderr, "qemu: could not load initrd '%s'\n",
- info->initrd_filename);
- exit(1);
- }
- } else {
- initrd_size = 0;
- }
- info->initrd_size = initrd_size;
-
- fixupcontext[FIXUP_BOARDID] = info->board_id;
- fixupcontext[FIXUP_BOARD_SETUP] = info->board_setup_addr;
-
- /* for device tree boot, we pass the DTB directly in r2. Otherwise
- * we point to the kernel args.
- */
- if (have_dtb(info)) {
- hwaddr align;
- hwaddr dtb_start;
-
- if (elf_machine == EM_AARCH64) {
- /*
- * Some AArch64 kernels on early bootup map the fdt region as
- *
- * [ ALIGN_DOWN(fdt, 2MB) ... ALIGN_DOWN(fdt, 2MB) + 2MB ]
- *
- * Let's play safe and prealign it to 2MB to give us some space.
- */
- align = 2 * 1024 * 1024;
- } else {
- /*
- * Some 32bit kernels will trash anything in the 4K page the
- * initrd ends in, so make sure the DTB isn't caught up in that.
- */
- align = 4096;
- }
-
- /* Place the DTB after the initrd in memory with alignment. */
- dtb_start = QEMU_ALIGN_UP(info->initrd_start + initrd_size, align);
- if (load_dtb(dtb_start, info, 0) < 0) {
- exit(1);
- }
- fixupcontext[FIXUP_ARGPTR] = dtb_start;
- } else {
- fixupcontext[FIXUP_ARGPTR] = info->loader_start + KERNEL_ARGS_ADDR;
- if (info->ram_size >= (1ULL << 32)) {
- fprintf(stderr, "qemu: RAM size must be less than 4GB to boot"
- " Linux kernel using ATAGS (try passing a device tree"
- " using -dtb)\n");
- exit(1);
- }
- }
- fixupcontext[FIXUP_ENTRYPOINT] = entry;
-
- write_bootloader("bootloader", info->loader_start,
- primary_loader, fixupcontext);
-
- if (info->nb_cpus > 1) {
- info->write_secondary_boot(cpu, info);
- }
- if (info->write_board_setup) {
- info->write_board_setup(cpu, info);
- }
-
- /* Notify devices which need to fake up firmware initialization
- * that we're doing a direct kernel boot.
- */
- object_child_foreach_recursive(object_get_root(),
- do_arm_linux_init, info);
- }
- info->is_linux = is_linux;
-
- for (cs = CPU(cpu); cs; cs = CPU_NEXT(cs)) {
- ARM_CPU(cs)->env.boot_info = info;
- }
-}
-
-void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
-{
- CPUState *cs;
-
- info->load_kernel_notifier.cpu = cpu;
- info->load_kernel_notifier.notifier.notify = arm_load_kernel_notify;
- qemu_add_machine_init_done_notifier(&info->load_kernel_notifier.notifier);
-
- /* CPU objects (unlike devices) are not automatically reset on system
- * reset, so we must always register a handler to do so. If we're
- * actually loading a kernel, the handler is also responsible for
- * arranging that we start it correctly.
- */
- for (cs = CPU(cpu); cs; cs = CPU_NEXT(cs)) {
- qemu_register_reset(do_cpu_reset, ARM_CPU(cs));
- }
-}
-
-static const TypeInfo arm_linux_boot_if_info = {
- .name = TYPE_ARM_LINUX_BOOT_IF,
- .parent = TYPE_INTERFACE,
- .class_size = sizeof(ARMLinuxBootIfClass),
-};
-
-static void arm_linux_boot_register_types(void)
-{
- type_register_static(&arm_linux_boot_if_info);
-}
-
-type_init(arm_linux_boot_register_types)
diff --git a/qemu/hw/arm/collie.c b/qemu/hw/arm/collie.c
deleted file mode 100644
index 8bb308a42..000000000
--- a/qemu/hw/arm/collie.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * SA-1110-based Sharp Zaurus SL-5500 platform.
- *
- * Copyright (C) 2011 Dmitry Eremin-Solenikov
- *
- * This code is licensed under GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "hw/boards.h"
-#include "hw/devices.h"
-#include "strongarm.h"
-#include "hw/arm/arm.h"
-#include "hw/block/flash.h"
-#include "sysemu/block-backend.h"
-#include "exec/address-spaces.h"
-
-static struct arm_boot_info collie_binfo = {
- .loader_start = SA_SDCS0,
- .ram_size = 0x20000000,
-};
-
-static void collie_init(MachineState *machine)
-{
- const char *cpu_model = machine->cpu_model;
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- const char *initrd_filename = machine->initrd_filename;
- StrongARMState *s;
- DriveInfo *dinfo;
- MemoryRegion *sysmem = get_system_memory();
-
- if (!cpu_model) {
- cpu_model = "sa1110";
- }
-
- s = sa1110_init(sysmem, collie_binfo.ram_size, cpu_model);
-
- dinfo = drive_get(IF_PFLASH, 0, 0);
- pflash_cfi01_register(SA_CS0, NULL, "collie.fl1", 0x02000000,
- dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- (64 * 1024), 512, 4, 0x00, 0x00, 0x00, 0x00, 0);
-
- dinfo = drive_get(IF_PFLASH, 0, 1);
- pflash_cfi01_register(SA_CS1, NULL, "collie.fl2", 0x02000000,
- dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- (64 * 1024), 512, 4, 0x00, 0x00, 0x00, 0x00, 0);
-
- sysbus_create_simple("scoop", 0x40800000, NULL);
-
- collie_binfo.kernel_filename = kernel_filename;
- collie_binfo.kernel_cmdline = kernel_cmdline;
- collie_binfo.initrd_filename = initrd_filename;
- collie_binfo.board_id = 0x208;
- arm_load_kernel(s->cpu, &collie_binfo);
-}
-
-static void collie_machine_init(MachineClass *mc)
-{
- mc->desc = "Sharp SL-5500 (Collie) PDA (SA-1110)";
- mc->init = collie_init;
-}
-
-DEFINE_MACHINE("collie", collie_machine_init)
diff --git a/qemu/hw/arm/cubieboard.c b/qemu/hw/arm/cubieboard.c
deleted file mode 100644
index fbd78ed01..000000000
--- a/qemu/hw/arm/cubieboard.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * cubieboard emulation
- *
- * Copyright (C) 2013 Li Guang
- * Written by Li Guang <lig.fnst@cn.fujitsu.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/sysbus.h"
-#include "hw/devices.h"
-#include "hw/boards.h"
-#include "hw/arm/allwinner-a10.h"
-
-static struct arm_boot_info cubieboard_binfo = {
- .loader_start = AW_A10_SDRAM_BASE,
- .board_id = 0x1008,
-};
-
-typedef struct CubieBoardState {
- AwA10State *a10;
- MemoryRegion sdram;
-} CubieBoardState;
-
-static void cubieboard_init(MachineState *machine)
-{
- CubieBoardState *s = g_new(CubieBoardState, 1);
- Error *err = NULL;
-
- s->a10 = AW_A10(object_new(TYPE_AW_A10));
-
- object_property_set_int(OBJECT(&s->a10->emac), 1, "phy-addr", &err);
- if (err != NULL) {
- error_reportf_err(err, "Couldn't set phy address: ");
- exit(1);
- }
-
- object_property_set_int(OBJECT(&s->a10->timer), 32768, "clk0-freq", &err);
- if (err != NULL) {
- error_reportf_err(err, "Couldn't set clk0 frequency: ");
- exit(1);
- }
-
- object_property_set_int(OBJECT(&s->a10->timer), 24000000, "clk1-freq",
- &err);
- if (err != NULL) {
- error_reportf_err(err, "Couldn't set clk1 frequency: ");
- exit(1);
- }
-
- object_property_set_bool(OBJECT(s->a10), true, "realized", &err);
- if (err != NULL) {
- error_reportf_err(err, "Couldn't realize Allwinner A10: ");
- exit(1);
- }
-
- memory_region_allocate_system_memory(&s->sdram, NULL, "cubieboard.ram",
- machine->ram_size);
- memory_region_add_subregion(get_system_memory(), AW_A10_SDRAM_BASE,
- &s->sdram);
-
- cubieboard_binfo.ram_size = machine->ram_size;
- cubieboard_binfo.kernel_filename = machine->kernel_filename;
- cubieboard_binfo.kernel_cmdline = machine->kernel_cmdline;
- arm_load_kernel(&s->a10->cpu, &cubieboard_binfo);
-}
-
-static void cubieboard_machine_init(MachineClass *mc)
-{
- mc->desc = "cubietech cubieboard";
- mc->init = cubieboard_init;
-}
-
-DEFINE_MACHINE("cubieboard", cubieboard_machine_init)
diff --git a/qemu/hw/arm/digic.c b/qemu/hw/arm/digic.c
deleted file mode 100644
index e0f973032..000000000
--- a/qemu/hw/arm/digic.c
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * QEMU model of the Canon DIGIC SoC.
- *
- * Copyright (C) 2013 Antony Pavlov <antonynpavlov@gmail.com>
- *
- * This model is based on reverse engineering efforts
- * made by CHDK (http://chdk.wikia.com) and
- * Magic Lantern (http://www.magiclantern.fm) projects
- * contributors.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/arm/digic.h"
-
-#define DIGIC4_TIMER_BASE(n) (0xc0210000 + (n) * 0x100)
-
-#define DIGIC_UART_BASE 0xc0800000
-
-static void digic_init(Object *obj)
-{
- DigicState *s = DIGIC(obj);
- DeviceState *dev;
- int i;
-
- object_initialize(&s->cpu, sizeof(s->cpu), "arm946-" TYPE_ARM_CPU);
- object_property_add_child(obj, "cpu", OBJECT(&s->cpu), NULL);
-
- for (i = 0; i < DIGIC4_NB_TIMERS; i++) {
-#define DIGIC_TIMER_NAME_MLEN 11
- char name[DIGIC_TIMER_NAME_MLEN];
-
- object_initialize(&s->timer[i], sizeof(s->timer[i]), TYPE_DIGIC_TIMER);
- dev = DEVICE(&s->timer[i]);
- qdev_set_parent_bus(dev, sysbus_get_default());
- snprintf(name, DIGIC_TIMER_NAME_MLEN, "timer[%d]", i);
- object_property_add_child(obj, name, OBJECT(&s->timer[i]), NULL);
- }
-
- object_initialize(&s->uart, sizeof(s->uart), TYPE_DIGIC_UART);
- dev = DEVICE(&s->uart);
- qdev_set_parent_bus(dev, sysbus_get_default());
- object_property_add_child(obj, "uart", OBJECT(&s->uart), NULL);
-}
-
-static void digic_realize(DeviceState *dev, Error **errp)
-{
- DigicState *s = DIGIC(dev);
- Error *err = NULL;
- SysBusDevice *sbd;
- int i;
-
- object_property_set_bool(OBJECT(&s->cpu), true, "reset-hivecs", &err);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
-
- object_property_set_bool(OBJECT(&s->cpu), true, "realized", &err);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
-
- for (i = 0; i < DIGIC4_NB_TIMERS; i++) {
- object_property_set_bool(OBJECT(&s->timer[i]), true, "realized", &err);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
-
- sbd = SYS_BUS_DEVICE(&s->timer[i]);
- sysbus_mmio_map(sbd, 0, DIGIC4_TIMER_BASE(i));
- }
-
- object_property_set_bool(OBJECT(&s->uart), true, "realized", &err);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
-
- sbd = SYS_BUS_DEVICE(&s->uart);
- sysbus_mmio_map(sbd, 0, DIGIC_UART_BASE);
-}
-
-static void digic_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- dc->realize = digic_realize;
-
- /*
- * Reason: creates an ARM CPU, thus use after free(), see
- * arm_cpu_class_init()
- */
- dc->cannot_destroy_with_object_finalize_yet = true;
-}
-
-static const TypeInfo digic_type_info = {
- .name = TYPE_DIGIC,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(DigicState),
- .instance_init = digic_init,
- .class_init = digic_class_init,
-};
-
-static void digic_register_types(void)
-{
- type_register_static(&digic_type_info);
-}
-
-type_init(digic_register_types)
diff --git a/qemu/hw/arm/digic_boards.c b/qemu/hw/arm/digic_boards.c
deleted file mode 100644
index 520c8e9ff..000000000
--- a/qemu/hw/arm/digic_boards.c
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * QEMU model of the Canon DIGIC boards (cameras indeed :).
- *
- * Copyright (C) 2013 Antony Pavlov <antonynpavlov@gmail.com>
- *
- * This model is based on reverse engineering efforts
- * made by CHDK (http://chdk.wikia.com) and
- * Magic Lantern (http://www.magiclantern.fm) projects
- * contributors.
- *
- * See docs here:
- * http://magiclantern.wikia.com/wiki/Register_Map
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/boards.h"
-#include "exec/address-spaces.h"
-#include "qemu/error-report.h"
-#include "hw/arm/digic.h"
-#include "hw/block/flash.h"
-#include "hw/loader.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/qtest.h"
-
-#define DIGIC4_ROM0_BASE 0xf0000000
-#define DIGIC4_ROM1_BASE 0xf8000000
-#define DIGIC4_ROM_MAX_SIZE 0x08000000
-
-typedef struct DigicBoardState {
- DigicState *digic;
- MemoryRegion ram;
-} DigicBoardState;
-
-typedef struct DigicBoard {
- hwaddr ram_size;
- void (*add_rom0)(DigicBoardState *, hwaddr, const char *);
- const char *rom0_def_filename;
- void (*add_rom1)(DigicBoardState *, hwaddr, const char *);
- const char *rom1_def_filename;
-} DigicBoard;
-
-static void digic4_board_setup_ram(DigicBoardState *s, hwaddr ram_size)
-{
- memory_region_allocate_system_memory(&s->ram, NULL, "ram", ram_size);
- memory_region_add_subregion(get_system_memory(), 0, &s->ram);
-}
-
-static void digic4_board_init(DigicBoard *board)
-{
- Error *err = NULL;
-
- DigicBoardState *s = g_new(DigicBoardState, 1);
-
- s->digic = DIGIC(object_new(TYPE_DIGIC));
- object_property_set_bool(OBJECT(s->digic), true, "realized", &err);
- if (err != NULL) {
- error_reportf_err(err, "Couldn't realize DIGIC SoC: ");
- exit(1);
- }
-
- digic4_board_setup_ram(s, board->ram_size);
-
- if (board->add_rom0) {
- board->add_rom0(s, DIGIC4_ROM0_BASE, board->rom0_def_filename);
- }
-
- if (board->add_rom1) {
- board->add_rom1(s, DIGIC4_ROM1_BASE, board->rom1_def_filename);
- }
-}
-
-static void digic_load_rom(DigicBoardState *s, hwaddr addr,
- hwaddr max_size, const char *def_filename)
-{
- target_long rom_size;
- const char *filename;
-
- if (qtest_enabled()) {
- /* qtest runs no code so don't attempt a ROM load which
- * could fail and result in a spurious test failure.
- */
- return;
- }
-
- if (bios_name) {
- filename = bios_name;
- } else {
- filename = def_filename;
- }
-
- if (filename) {
- char *fn = qemu_find_file(QEMU_FILE_TYPE_BIOS, filename);
-
- if (!fn) {
- error_report("Couldn't find rom image '%s'.", filename);
- exit(1);
- }
-
- rom_size = load_image_targphys(fn, addr, max_size);
- if (rom_size < 0 || rom_size > max_size) {
- error_report("Couldn't load rom image '%s'.", filename);
- exit(1);
- }
- g_free(fn);
- }
-}
-
-/*
- * Samsung K8P3215UQB
- * 64M Bit (4Mx16) Page Mode / Multi-Bank NOR Flash Memory
- */
-static void digic4_add_k8p3215uqb_rom(DigicBoardState *s, hwaddr addr,
- const char *def_filename)
-{
-#define FLASH_K8P3215UQB_SIZE (4 * 1024 * 1024)
-#define FLASH_K8P3215UQB_SECTOR_SIZE (64 * 1024)
-
- pflash_cfi02_register(addr, NULL, "pflash", FLASH_K8P3215UQB_SIZE,
- NULL, FLASH_K8P3215UQB_SECTOR_SIZE,
- FLASH_K8P3215UQB_SIZE / FLASH_K8P3215UQB_SECTOR_SIZE,
- DIGIC4_ROM_MAX_SIZE / FLASH_K8P3215UQB_SIZE,
- 4,
- 0x00EC, 0x007E, 0x0003, 0x0001,
- 0x0555, 0x2aa, 0);
-
- digic_load_rom(s, addr, FLASH_K8P3215UQB_SIZE, def_filename);
-}
-
-static DigicBoard digic4_board_canon_a1100 = {
- .ram_size = 64 * 1024 * 1024,
- .add_rom1 = digic4_add_k8p3215uqb_rom,
- .rom1_def_filename = "canon-a1100-rom1.bin",
-};
-
-static void canon_a1100_init(MachineState *machine)
-{
- digic4_board_init(&digic4_board_canon_a1100);
-}
-
-static void canon_a1100_machine_init(MachineClass *mc)
-{
- mc->desc = "Canon PowerShot A1100 IS";
- mc->init = &canon_a1100_init;
-}
-
-DEFINE_MACHINE("canon-a1100", canon_a1100_machine_init)
diff --git a/qemu/hw/arm/exynos4210.c b/qemu/hw/arm/exynos4210.c
deleted file mode 100644
index be3c96d21..000000000
--- a/qemu/hw/arm/exynos4210.c
+++ /dev/null
@@ -1,378 +0,0 @@
-/*
- * Samsung exynos4210 SoC emulation
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved.
- * Maksim Kozlov <m.kozlov@samsung.com>
- * Evgeny Voevodin <e.voevodin@samsung.com>
- * Igor Mitsyanko <i.mitsyanko@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/boards.h"
-#include "sysemu/sysemu.h"
-#include "hw/sysbus.h"
-#include "hw/arm/arm.h"
-#include "hw/loader.h"
-#include "hw/arm/exynos4210.h"
-#include "hw/usb/hcd-ehci.h"
-
-#define EXYNOS4210_CHIPID_ADDR 0x10000000
-
-/* PWM */
-#define EXYNOS4210_PWM_BASE_ADDR 0x139D0000
-
-/* RTC */
-#define EXYNOS4210_RTC_BASE_ADDR 0x10070000
-
-/* MCT */
-#define EXYNOS4210_MCT_BASE_ADDR 0x10050000
-
-/* I2C */
-#define EXYNOS4210_I2C_SHIFT 0x00010000
-#define EXYNOS4210_I2C_BASE_ADDR 0x13860000
-/* Interrupt Group of External Interrupt Combiner for I2C */
-#define EXYNOS4210_I2C_INTG 27
-#define EXYNOS4210_HDMI_INTG 16
-
-/* UART's definitions */
-#define EXYNOS4210_UART0_BASE_ADDR 0x13800000
-#define EXYNOS4210_UART1_BASE_ADDR 0x13810000
-#define EXYNOS4210_UART2_BASE_ADDR 0x13820000
-#define EXYNOS4210_UART3_BASE_ADDR 0x13830000
-#define EXYNOS4210_UART0_FIFO_SIZE 256
-#define EXYNOS4210_UART1_FIFO_SIZE 64
-#define EXYNOS4210_UART2_FIFO_SIZE 16
-#define EXYNOS4210_UART3_FIFO_SIZE 16
-/* Interrupt Group of External Interrupt Combiner for UART */
-#define EXYNOS4210_UART_INT_GRP 26
-
-/* External GIC */
-#define EXYNOS4210_EXT_GIC_CPU_BASE_ADDR 0x10480000
-#define EXYNOS4210_EXT_GIC_DIST_BASE_ADDR 0x10490000
-
-/* Combiner */
-#define EXYNOS4210_EXT_COMBINER_BASE_ADDR 0x10440000
-#define EXYNOS4210_INT_COMBINER_BASE_ADDR 0x10448000
-
-/* PMU SFR base address */
-#define EXYNOS4210_PMU_BASE_ADDR 0x10020000
-
-/* Display controllers (FIMD) */
-#define EXYNOS4210_FIMD0_BASE_ADDR 0x11C00000
-
-/* EHCI */
-#define EXYNOS4210_EHCI_BASE_ADDR 0x12580000
-
-static uint8_t chipid_and_omr[] = { 0x11, 0x02, 0x21, 0x43,
- 0x09, 0x00, 0x00, 0x00 };
-
-static uint64_t exynos4210_chipid_and_omr_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- assert(offset < sizeof(chipid_and_omr));
- return chipid_and_omr[offset];
-}
-
-static void exynos4210_chipid_and_omr_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- return;
-}
-
-static const MemoryRegionOps exynos4210_chipid_and_omr_ops = {
- .read = exynos4210_chipid_and_omr_read,
- .write = exynos4210_chipid_and_omr_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .impl = {
- .max_access_size = 1,
- }
-};
-
-void exynos4210_write_secondary(ARMCPU *cpu,
- const struct arm_boot_info *info)
-{
- int n;
- uint32_t smpboot[] = {
- 0xe59f3034, /* ldr r3, External gic_cpu_if */
- 0xe59f2034, /* ldr r2, Internal gic_cpu_if */
- 0xe59f0034, /* ldr r0, startaddr */
- 0xe3a01001, /* mov r1, #1 */
- 0xe5821000, /* str r1, [r2] */
- 0xe5831000, /* str r1, [r3] */
- 0xe3a010ff, /* mov r1, #0xff */
- 0xe5821004, /* str r1, [r2, #4] */
- 0xe5831004, /* str r1, [r3, #4] */
- 0xf57ff04f, /* dsb */
- 0xe320f003, /* wfi */
- 0xe5901000, /* ldr r1, [r0] */
- 0xe1110001, /* tst r1, r1 */
- 0x0afffffb, /* beq <wfi> */
- 0xe12fff11, /* bx r1 */
- EXYNOS4210_EXT_GIC_CPU_BASE_ADDR,
- 0, /* gic_cpu_if: base address of Internal GIC CPU interface */
- 0 /* bootreg: Boot register address is held here */
- };
- smpboot[ARRAY_SIZE(smpboot) - 1] = info->smp_bootreg_addr;
- smpboot[ARRAY_SIZE(smpboot) - 2] = info->gic_cpu_if_addr;
- for (n = 0; n < ARRAY_SIZE(smpboot); n++) {
- smpboot[n] = tswap32(smpboot[n]);
- }
- rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot),
- info->smp_loader_start);
-}
-
-Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
- unsigned long ram_size)
-{
- int i, n;
- Exynos4210State *s = g_new(Exynos4210State, 1);
- qemu_irq gate_irq[EXYNOS4210_NCPUS][EXYNOS4210_IRQ_GATE_NINPUTS];
- unsigned long mem_size;
- DeviceState *dev;
- SysBusDevice *busdev;
- ObjectClass *cpu_oc;
-
- cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, "cortex-a9");
- assert(cpu_oc);
-
- for (n = 0; n < EXYNOS4210_NCPUS; n++) {
- Object *cpuobj = object_new(object_class_get_name(cpu_oc));
-
- /* By default A9 CPUs have EL3 enabled. This board does not currently
- * support EL3 so the CPU EL3 property is disabled before realization.
- */
- if (object_property_find(cpuobj, "has_el3", NULL)) {
- object_property_set_bool(cpuobj, false, "has_el3", &error_fatal);
- }
-
- s->cpu[n] = ARM_CPU(cpuobj);
- object_property_set_int(cpuobj, EXYNOS4210_SMP_PRIVATE_BASE_ADDR,
- "reset-cbar", &error_abort);
- object_property_set_bool(cpuobj, true, "realized", &error_fatal);
- }
-
- /*** IRQs ***/
-
- s->irq_table = exynos4210_init_irq(&s->irqs);
-
- /* IRQ Gate */
- for (i = 0; i < EXYNOS4210_NCPUS; i++) {
- dev = qdev_create(NULL, "exynos4210.irq_gate");
- qdev_prop_set_uint32(dev, "n_in", EXYNOS4210_IRQ_GATE_NINPUTS);
- qdev_init_nofail(dev);
- /* Get IRQ Gate input in gate_irq */
- for (n = 0; n < EXYNOS4210_IRQ_GATE_NINPUTS; n++) {
- gate_irq[i][n] = qdev_get_gpio_in(dev, n);
- }
- busdev = SYS_BUS_DEVICE(dev);
-
- /* Connect IRQ Gate output to CPU's IRQ line */
- sysbus_connect_irq(busdev, 0,
- qdev_get_gpio_in(DEVICE(s->cpu[i]), ARM_CPU_IRQ));
- }
-
- /* Private memory region and Internal GIC */
- dev = qdev_create(NULL, "a9mpcore_priv");
- qdev_prop_set_uint32(dev, "num-cpu", EXYNOS4210_NCPUS);
- qdev_init_nofail(dev);
- busdev = SYS_BUS_DEVICE(dev);
- sysbus_mmio_map(busdev, 0, EXYNOS4210_SMP_PRIVATE_BASE_ADDR);
- for (n = 0; n < EXYNOS4210_NCPUS; n++) {
- sysbus_connect_irq(busdev, n, gate_irq[n][0]);
- }
- for (n = 0; n < EXYNOS4210_INT_GIC_NIRQ; n++) {
- s->irqs.int_gic_irq[n] = qdev_get_gpio_in(dev, n);
- }
-
- /* Cache controller */
- sysbus_create_simple("l2x0", EXYNOS4210_L2X0_BASE_ADDR, NULL);
-
- /* External GIC */
- dev = qdev_create(NULL, "exynos4210.gic");
- qdev_prop_set_uint32(dev, "num-cpu", EXYNOS4210_NCPUS);
- qdev_init_nofail(dev);
- busdev = SYS_BUS_DEVICE(dev);
- /* Map CPU interface */
- sysbus_mmio_map(busdev, 0, EXYNOS4210_EXT_GIC_CPU_BASE_ADDR);
- /* Map Distributer interface */
- sysbus_mmio_map(busdev, 1, EXYNOS4210_EXT_GIC_DIST_BASE_ADDR);
- for (n = 0; n < EXYNOS4210_NCPUS; n++) {
- sysbus_connect_irq(busdev, n, gate_irq[n][1]);
- }
- for (n = 0; n < EXYNOS4210_EXT_GIC_NIRQ; n++) {
- s->irqs.ext_gic_irq[n] = qdev_get_gpio_in(dev, n);
- }
-
- /* Internal Interrupt Combiner */
- dev = qdev_create(NULL, "exynos4210.combiner");
- qdev_init_nofail(dev);
- busdev = SYS_BUS_DEVICE(dev);
- for (n = 0; n < EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ; n++) {
- sysbus_connect_irq(busdev, n, s->irqs.int_gic_irq[n]);
- }
- exynos4210_combiner_get_gpioin(&s->irqs, dev, 0);
- sysbus_mmio_map(busdev, 0, EXYNOS4210_INT_COMBINER_BASE_ADDR);
-
- /* External Interrupt Combiner */
- dev = qdev_create(NULL, "exynos4210.combiner");
- qdev_prop_set_uint32(dev, "external", 1);
- qdev_init_nofail(dev);
- busdev = SYS_BUS_DEVICE(dev);
- for (n = 0; n < EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ; n++) {
- sysbus_connect_irq(busdev, n, s->irqs.ext_gic_irq[n]);
- }
- exynos4210_combiner_get_gpioin(&s->irqs, dev, 1);
- sysbus_mmio_map(busdev, 0, EXYNOS4210_EXT_COMBINER_BASE_ADDR);
-
- /* Initialize board IRQs. */
- exynos4210_init_board_irqs(&s->irqs);
-
- /*** Memory ***/
-
- /* Chip-ID and OMR */
- memory_region_init_io(&s->chipid_mem, NULL, &exynos4210_chipid_and_omr_ops,
- NULL, "exynos4210.chipid", sizeof(chipid_and_omr));
- memory_region_add_subregion(system_mem, EXYNOS4210_CHIPID_ADDR,
- &s->chipid_mem);
-
- /* Internal ROM */
- memory_region_init_ram(&s->irom_mem, NULL, "exynos4210.irom",
- EXYNOS4210_IROM_SIZE, &error_fatal);
- vmstate_register_ram_global(&s->irom_mem);
- memory_region_set_readonly(&s->irom_mem, true);
- memory_region_add_subregion(system_mem, EXYNOS4210_IROM_BASE_ADDR,
- &s->irom_mem);
- /* mirror of iROM */
- memory_region_init_alias(&s->irom_alias_mem, NULL, "exynos4210.irom_alias",
- &s->irom_mem,
- 0,
- EXYNOS4210_IROM_SIZE);
- memory_region_set_readonly(&s->irom_alias_mem, true);
- memory_region_add_subregion(system_mem, EXYNOS4210_IROM_MIRROR_BASE_ADDR,
- &s->irom_alias_mem);
-
- /* Internal RAM */
- memory_region_init_ram(&s->iram_mem, NULL, "exynos4210.iram",
- EXYNOS4210_IRAM_SIZE, &error_fatal);
- vmstate_register_ram_global(&s->iram_mem);
- memory_region_add_subregion(system_mem, EXYNOS4210_IRAM_BASE_ADDR,
- &s->iram_mem);
-
- /* DRAM */
- mem_size = ram_size;
- if (mem_size > EXYNOS4210_DRAM_MAX_SIZE) {
- memory_region_init_ram(&s->dram1_mem, NULL, "exynos4210.dram1",
- mem_size - EXYNOS4210_DRAM_MAX_SIZE, &error_fatal);
- vmstate_register_ram_global(&s->dram1_mem);
- memory_region_add_subregion(system_mem, EXYNOS4210_DRAM1_BASE_ADDR,
- &s->dram1_mem);
- mem_size = EXYNOS4210_DRAM_MAX_SIZE;
- }
- memory_region_init_ram(&s->dram0_mem, NULL, "exynos4210.dram0", mem_size,
- &error_fatal);
- vmstate_register_ram_global(&s->dram0_mem);
- memory_region_add_subregion(system_mem, EXYNOS4210_DRAM0_BASE_ADDR,
- &s->dram0_mem);
-
- /* PMU.
- * The only reason of existence at the moment is that secondary CPU boot
- * loader uses PMU INFORM5 register as a holding pen.
- */
- sysbus_create_simple("exynos4210.pmu", EXYNOS4210_PMU_BASE_ADDR, NULL);
-
- /* PWM */
- sysbus_create_varargs("exynos4210.pwm", EXYNOS4210_PWM_BASE_ADDR,
- s->irq_table[exynos4210_get_irq(22, 0)],
- s->irq_table[exynos4210_get_irq(22, 1)],
- s->irq_table[exynos4210_get_irq(22, 2)],
- s->irq_table[exynos4210_get_irq(22, 3)],
- s->irq_table[exynos4210_get_irq(22, 4)],
- NULL);
- /* RTC */
- sysbus_create_varargs("exynos4210.rtc", EXYNOS4210_RTC_BASE_ADDR,
- s->irq_table[exynos4210_get_irq(23, 0)],
- s->irq_table[exynos4210_get_irq(23, 1)],
- NULL);
-
- /* Multi Core Timer */
- dev = qdev_create(NULL, "exynos4210.mct");
- qdev_init_nofail(dev);
- busdev = SYS_BUS_DEVICE(dev);
- for (n = 0; n < 4; n++) {
- /* Connect global timer interrupts to Combiner gpio_in */
- sysbus_connect_irq(busdev, n,
- s->irq_table[exynos4210_get_irq(1, 4 + n)]);
- }
- /* Connect local timer interrupts to Combiner gpio_in */
- sysbus_connect_irq(busdev, 4,
- s->irq_table[exynos4210_get_irq(51, 0)]);
- sysbus_connect_irq(busdev, 5,
- s->irq_table[exynos4210_get_irq(35, 3)]);
- sysbus_mmio_map(busdev, 0, EXYNOS4210_MCT_BASE_ADDR);
-
- /*** I2C ***/
- for (n = 0; n < EXYNOS4210_I2C_NUMBER; n++) {
- uint32_t addr = EXYNOS4210_I2C_BASE_ADDR + EXYNOS4210_I2C_SHIFT * n;
- qemu_irq i2c_irq;
-
- if (n < 8) {
- i2c_irq = s->irq_table[exynos4210_get_irq(EXYNOS4210_I2C_INTG, n)];
- } else {
- i2c_irq = s->irq_table[exynos4210_get_irq(EXYNOS4210_HDMI_INTG, 1)];
- }
-
- dev = qdev_create(NULL, "exynos4210.i2c");
- qdev_init_nofail(dev);
- busdev = SYS_BUS_DEVICE(dev);
- sysbus_connect_irq(busdev, 0, i2c_irq);
- sysbus_mmio_map(busdev, 0, addr);
- s->i2c_if[n] = (I2CBus *)qdev_get_child_bus(dev, "i2c");
- }
-
-
- /*** UARTs ***/
- exynos4210_uart_create(EXYNOS4210_UART0_BASE_ADDR,
- EXYNOS4210_UART0_FIFO_SIZE, 0, NULL,
- s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 0)]);
-
- exynos4210_uart_create(EXYNOS4210_UART1_BASE_ADDR,
- EXYNOS4210_UART1_FIFO_SIZE, 1, NULL,
- s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 1)]);
-
- exynos4210_uart_create(EXYNOS4210_UART2_BASE_ADDR,
- EXYNOS4210_UART2_FIFO_SIZE, 2, NULL,
- s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 2)]);
-
- exynos4210_uart_create(EXYNOS4210_UART3_BASE_ADDR,
- EXYNOS4210_UART3_FIFO_SIZE, 3, NULL,
- s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 3)]);
-
- /*** Display controller (FIMD) ***/
- sysbus_create_varargs("exynos4210.fimd", EXYNOS4210_FIMD0_BASE_ADDR,
- s->irq_table[exynos4210_get_irq(11, 0)],
- s->irq_table[exynos4210_get_irq(11, 1)],
- s->irq_table[exynos4210_get_irq(11, 2)],
- NULL);
-
- sysbus_create_simple(TYPE_EXYNOS4210_EHCI, EXYNOS4210_EHCI_BASE_ADDR,
- s->irq_table[exynos4210_get_irq(28, 3)]);
-
- return s;
-}
diff --git a/qemu/hw/arm/exynos4_boards.c b/qemu/hw/arm/exynos4_boards.c
deleted file mode 100644
index 0efa19405..000000000
--- a/qemu/hw/arm/exynos4_boards.c
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Samsung exynos4 SoC based boards emulation
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved.
- * Maksim Kozlov <m.kozlov@samsung.com>
- * Evgeny Voevodin <e.voevodin@samsung.com>
- * Igor Mitsyanko <i.mitsyanko@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/qtest.h"
-#include "hw/sysbus.h"
-#include "net/net.h"
-#include "hw/arm/arm.h"
-#include "exec/address-spaces.h"
-#include "hw/arm/exynos4210.h"
-#include "hw/boards.h"
-
-#undef DEBUG
-
-//#define DEBUG
-
-#ifdef DEBUG
- #undef PRINT_DEBUG
- #define PRINT_DEBUG(fmt, args...) \
- do { \
- fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \
- } while (0)
-#else
- #define PRINT_DEBUG(fmt, args...) do {} while (0)
-#endif
-
-#define SMDK_LAN9118_BASE_ADDR 0x05000000
-
-typedef enum Exynos4BoardType {
- EXYNOS4_BOARD_NURI,
- EXYNOS4_BOARD_SMDKC210,
- EXYNOS4_NUM_OF_BOARDS
-} Exynos4BoardType;
-
-static int exynos4_board_id[EXYNOS4_NUM_OF_BOARDS] = {
- [EXYNOS4_BOARD_NURI] = 0xD33,
- [EXYNOS4_BOARD_SMDKC210] = 0xB16,
-};
-
-static int exynos4_board_smp_bootreg_addr[EXYNOS4_NUM_OF_BOARDS] = {
- [EXYNOS4_BOARD_NURI] = EXYNOS4210_SECOND_CPU_BOOTREG,
- [EXYNOS4_BOARD_SMDKC210] = EXYNOS4210_SECOND_CPU_BOOTREG,
-};
-
-static unsigned long exynos4_board_ram_size[EXYNOS4_NUM_OF_BOARDS] = {
- [EXYNOS4_BOARD_NURI] = 0x40000000,
- [EXYNOS4_BOARD_SMDKC210] = 0x40000000,
-};
-
-static struct arm_boot_info exynos4_board_binfo = {
- .loader_start = EXYNOS4210_BASE_BOOT_ADDR,
- .smp_loader_start = EXYNOS4210_SMP_BOOT_ADDR,
- .nb_cpus = EXYNOS4210_NCPUS,
- .write_secondary_boot = exynos4210_write_secondary,
-};
-
-static void lan9215_init(uint32_t base, qemu_irq irq)
-{
- DeviceState *dev;
- SysBusDevice *s;
-
- /* This should be a 9215 but the 9118 is close enough */
- if (nd_table[0].used) {
- qemu_check_nic_model(&nd_table[0], "lan9118");
- dev = qdev_create(NULL, "lan9118");
- qdev_set_nic_properties(dev, &nd_table[0]);
- qdev_prop_set_uint32(dev, "mode_16bit", 1);
- qdev_init_nofail(dev);
- s = SYS_BUS_DEVICE(dev);
- sysbus_mmio_map(s, 0, base);
- sysbus_connect_irq(s, 0, irq);
- }
-}
-
-static Exynos4210State *exynos4_boards_init_common(MachineState *machine,
- Exynos4BoardType board_type)
-{
- MachineClass *mc = MACHINE_GET_CLASS(machine);
-
- if (smp_cpus != EXYNOS4210_NCPUS && !qtest_enabled()) {
- fprintf(stderr, "%s board supports only %d CPU cores. Ignoring smp_cpus"
- " value.\n",
- mc->name, EXYNOS4210_NCPUS);
- }
-
- exynos4_board_binfo.ram_size = exynos4_board_ram_size[board_type];
- exynos4_board_binfo.board_id = exynos4_board_id[board_type];
- exynos4_board_binfo.smp_bootreg_addr =
- exynos4_board_smp_bootreg_addr[board_type];
- exynos4_board_binfo.kernel_filename = machine->kernel_filename;
- exynos4_board_binfo.initrd_filename = machine->initrd_filename;
- exynos4_board_binfo.kernel_cmdline = machine->kernel_cmdline;
- exynos4_board_binfo.gic_cpu_if_addr =
- EXYNOS4210_SMP_PRIVATE_BASE_ADDR + 0x100;
-
- PRINT_DEBUG("\n ram_size: %luMiB [0x%08lx]\n"
- " kernel_filename: %s\n"
- " kernel_cmdline: %s\n"
- " initrd_filename: %s\n",
- exynos4_board_ram_size[board_type] / 1048576,
- exynos4_board_ram_size[board_type],
- machine->kernel_filename,
- machine->kernel_cmdline,
- machine->initrd_filename);
-
- return exynos4210_init(get_system_memory(),
- exynos4_board_ram_size[board_type]);
-}
-
-static void nuri_init(MachineState *machine)
-{
- exynos4_boards_init_common(machine, EXYNOS4_BOARD_NURI);
-
- arm_load_kernel(ARM_CPU(first_cpu), &exynos4_board_binfo);
-}
-
-static void smdkc210_init(MachineState *machine)
-{
- Exynos4210State *s = exynos4_boards_init_common(machine,
- EXYNOS4_BOARD_SMDKC210);
-
- lan9215_init(SMDK_LAN9118_BASE_ADDR,
- qemu_irq_invert(s->irq_table[exynos4210_get_irq(37, 1)]));
- arm_load_kernel(ARM_CPU(first_cpu), &exynos4_board_binfo);
-}
-
-static void nuri_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "Samsung NURI board (Exynos4210)";
- mc->init = nuri_init;
- mc->max_cpus = EXYNOS4210_NCPUS;
-}
-
-static const TypeInfo nuri_type = {
- .name = MACHINE_TYPE_NAME("nuri"),
- .parent = TYPE_MACHINE,
- .class_init = nuri_class_init,
-};
-
-static void smdkc210_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "Samsung SMDKC210 board (Exynos4210)";
- mc->init = smdkc210_init;
- mc->max_cpus = EXYNOS4210_NCPUS;
-}
-
-static const TypeInfo smdkc210_type = {
- .name = MACHINE_TYPE_NAME("smdkc210"),
- .parent = TYPE_MACHINE,
- .class_init = smdkc210_class_init,
-};
-
-static void exynos4_machines_init(void)
-{
- type_register_static(&nuri_type);
- type_register_static(&smdkc210_type);
-}
-
-type_init(exynos4_machines_init)
diff --git a/qemu/hw/arm/fsl-imx25.c b/qemu/hw/arm/fsl-imx25.c
deleted file mode 100644
index 2f878b935..000000000
--- a/qemu/hw/arm/fsl-imx25.c
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
- * Copyright (c) 2013 Jean-Christophe Dubois <jcd@tribudubois.net>
- *
- * i.MX25 SOC emulation.
- *
- * Based on hw/arm/xlnx-zynqmp.c
- *
- * Copyright (C) 2015 Xilinx Inc
- * Written by Peter Crosthwaite <peter.crosthwaite@xilinx.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/arm/fsl-imx25.h"
-#include "sysemu/sysemu.h"
-#include "exec/address-spaces.h"
-#include "hw/boards.h"
-#include "sysemu/char.h"
-
-static void fsl_imx25_init(Object *obj)
-{
- FslIMX25State *s = FSL_IMX25(obj);
- int i;
-
- object_initialize(&s->cpu, sizeof(s->cpu), "arm926-" TYPE_ARM_CPU);
-
- object_initialize(&s->avic, sizeof(s->avic), TYPE_IMX_AVIC);
- qdev_set_parent_bus(DEVICE(&s->avic), sysbus_get_default());
-
- object_initialize(&s->ccm, sizeof(s->ccm), TYPE_IMX25_CCM);
- qdev_set_parent_bus(DEVICE(&s->ccm), sysbus_get_default());
-
- for (i = 0; i < FSL_IMX25_NUM_UARTS; i++) {
- object_initialize(&s->uart[i], sizeof(s->uart[i]), TYPE_IMX_SERIAL);
- qdev_set_parent_bus(DEVICE(&s->uart[i]), sysbus_get_default());
- }
-
- for (i = 0; i < FSL_IMX25_NUM_GPTS; i++) {
- object_initialize(&s->gpt[i], sizeof(s->gpt[i]), TYPE_IMX_GPT);
- qdev_set_parent_bus(DEVICE(&s->gpt[i]), sysbus_get_default());
- }
-
- for (i = 0; i < FSL_IMX25_NUM_EPITS; i++) {
- object_initialize(&s->epit[i], sizeof(s->epit[i]), TYPE_IMX_EPIT);
- qdev_set_parent_bus(DEVICE(&s->epit[i]), sysbus_get_default());
- }
-
- object_initialize(&s->fec, sizeof(s->fec), TYPE_IMX_FEC);
- qdev_set_parent_bus(DEVICE(&s->fec), sysbus_get_default());
-
- for (i = 0; i < FSL_IMX25_NUM_I2CS; i++) {
- object_initialize(&s->i2c[i], sizeof(s->i2c[i]), TYPE_IMX_I2C);
- qdev_set_parent_bus(DEVICE(&s->i2c[i]), sysbus_get_default());
- }
-
- for (i = 0; i < FSL_IMX25_NUM_GPIOS; i++) {
- object_initialize(&s->gpio[i], sizeof(s->gpio[i]), TYPE_IMX_GPIO);
- qdev_set_parent_bus(DEVICE(&s->gpio[i]), sysbus_get_default());
- }
-}
-
-static void fsl_imx25_realize(DeviceState *dev, Error **errp)
-{
- FslIMX25State *s = FSL_IMX25(dev);
- uint8_t i;
- Error *err = NULL;
-
- object_property_set_bool(OBJECT(&s->cpu), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- object_property_set_bool(OBJECT(&s->avic), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->avic), 0, FSL_IMX25_AVIC_ADDR);
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->avic), 0,
- qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_IRQ));
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->avic), 1,
- qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_FIQ));
-
- object_property_set_bool(OBJECT(&s->ccm), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->ccm), 0, FSL_IMX25_CCM_ADDR);
-
- /* Initialize all UARTs */
- for (i = 0; i < FSL_IMX25_NUM_UARTS; i++) {
- static const struct {
- hwaddr addr;
- unsigned int irq;
- } serial_table[FSL_IMX25_NUM_UARTS] = {
- { FSL_IMX25_UART1_ADDR, FSL_IMX25_UART1_IRQ },
- { FSL_IMX25_UART2_ADDR, FSL_IMX25_UART2_IRQ },
- { FSL_IMX25_UART3_ADDR, FSL_IMX25_UART3_IRQ },
- { FSL_IMX25_UART4_ADDR, FSL_IMX25_UART4_IRQ },
- { FSL_IMX25_UART5_ADDR, FSL_IMX25_UART5_IRQ }
- };
-
- if (i < MAX_SERIAL_PORTS) {
- CharDriverState *chr;
-
- chr = serial_hds[i];
-
- if (!chr) {
- char label[20];
- snprintf(label, sizeof(label), "imx31.uart%d", i);
- chr = qemu_chr_new(label, "null", NULL);
- }
-
- qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", chr);
- }
-
- object_property_set_bool(OBJECT(&s->uart[i]), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart[i]), 0, serial_table[i].addr);
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0,
- qdev_get_gpio_in(DEVICE(&s->avic),
- serial_table[i].irq));
- }
-
- /* Initialize all GPT timers */
- for (i = 0; i < FSL_IMX25_NUM_GPTS; i++) {
- static const struct {
- hwaddr addr;
- unsigned int irq;
- } gpt_table[FSL_IMX25_NUM_GPTS] = {
- { FSL_IMX25_GPT1_ADDR, FSL_IMX25_GPT1_IRQ },
- { FSL_IMX25_GPT2_ADDR, FSL_IMX25_GPT2_IRQ },
- { FSL_IMX25_GPT3_ADDR, FSL_IMX25_GPT3_IRQ },
- { FSL_IMX25_GPT4_ADDR, FSL_IMX25_GPT4_IRQ }
- };
-
- s->gpt[i].ccm = IMX_CCM(&s->ccm);
-
- object_property_set_bool(OBJECT(&s->gpt[i]), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpt[i]), 0, gpt_table[i].addr);
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpt[i]), 0,
- qdev_get_gpio_in(DEVICE(&s->avic),
- gpt_table[i].irq));
- }
-
- /* Initialize all EPIT timers */
- for (i = 0; i < FSL_IMX25_NUM_EPITS; i++) {
- static const struct {
- hwaddr addr;
- unsigned int irq;
- } epit_table[FSL_IMX25_NUM_EPITS] = {
- { FSL_IMX25_EPIT1_ADDR, FSL_IMX25_EPIT1_IRQ },
- { FSL_IMX25_EPIT2_ADDR, FSL_IMX25_EPIT2_IRQ }
- };
-
- s->epit[i].ccm = IMX_CCM(&s->ccm);
-
- object_property_set_bool(OBJECT(&s->epit[i]), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->epit[i]), 0, epit_table[i].addr);
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->epit[i]), 0,
- qdev_get_gpio_in(DEVICE(&s->avic),
- epit_table[i].irq));
- }
-
- qdev_set_nic_properties(DEVICE(&s->fec), &nd_table[0]);
- object_property_set_bool(OBJECT(&s->fec), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->fec), 0, FSL_IMX25_FEC_ADDR);
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->fec), 0,
- qdev_get_gpio_in(DEVICE(&s->avic), FSL_IMX25_FEC_IRQ));
-
-
- /* Initialize all I2C */
- for (i = 0; i < FSL_IMX25_NUM_I2CS; i++) {
- static const struct {
- hwaddr addr;
- unsigned int irq;
- } i2c_table[FSL_IMX25_NUM_I2CS] = {
- { FSL_IMX25_I2C1_ADDR, FSL_IMX25_I2C1_IRQ },
- { FSL_IMX25_I2C2_ADDR, FSL_IMX25_I2C2_IRQ },
- { FSL_IMX25_I2C3_ADDR, FSL_IMX25_I2C3_IRQ }
- };
-
- object_property_set_bool(OBJECT(&s->i2c[i]), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c[i]), 0, i2c_table[i].addr);
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c[i]), 0,
- qdev_get_gpio_in(DEVICE(&s->avic),
- i2c_table[i].irq));
- }
-
- /* Initialize all GPIOs */
- for (i = 0; i < FSL_IMX25_NUM_GPIOS; i++) {
- static const struct {
- hwaddr addr;
- unsigned int irq;
- } gpio_table[FSL_IMX25_NUM_GPIOS] = {
- { FSL_IMX25_GPIO1_ADDR, FSL_IMX25_GPIO1_IRQ },
- { FSL_IMX25_GPIO2_ADDR, FSL_IMX25_GPIO2_IRQ },
- { FSL_IMX25_GPIO3_ADDR, FSL_IMX25_GPIO3_IRQ },
- { FSL_IMX25_GPIO4_ADDR, FSL_IMX25_GPIO4_IRQ }
- };
-
- object_property_set_bool(OBJECT(&s->gpio[i]), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio[i]), 0, gpio_table[i].addr);
- /* Connect GPIO IRQ to PIC */
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 0,
- qdev_get_gpio_in(DEVICE(&s->avic),
- gpio_table[i].irq));
- }
-
- /* initialize 2 x 16 KB ROM */
- memory_region_init_rom_device(&s->rom[0], NULL, NULL, NULL,
- "imx25.rom0", FSL_IMX25_ROM0_SIZE, &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- memory_region_add_subregion(get_system_memory(), FSL_IMX25_ROM0_ADDR,
- &s->rom[0]);
- memory_region_init_rom_device(&s->rom[1], NULL, NULL, NULL,
- "imx25.rom1", FSL_IMX25_ROM1_SIZE, &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- memory_region_add_subregion(get_system_memory(), FSL_IMX25_ROM1_ADDR,
- &s->rom[1]);
-
- /* initialize internal RAM (128 KB) */
- memory_region_init_ram(&s->iram, NULL, "imx25.iram", FSL_IMX25_IRAM_SIZE,
- &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- memory_region_add_subregion(get_system_memory(), FSL_IMX25_IRAM_ADDR,
- &s->iram);
- vmstate_register_ram_global(&s->iram);
-
- /* internal RAM (128 KB) is aliased over 128 MB - 128 KB */
- memory_region_init_alias(&s->iram_alias, NULL, "imx25.iram_alias",
- &s->iram, 0, FSL_IMX25_IRAM_ALIAS_SIZE);
- memory_region_add_subregion(get_system_memory(), FSL_IMX25_IRAM_ALIAS_ADDR,
- &s->iram_alias);
-}
-
-static void fsl_imx25_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- dc->realize = fsl_imx25_realize;
-
- /*
- * Reason: creates an ARM CPU, thus use after free(), see
- * arm_cpu_class_init()
- */
- dc->cannot_destroy_with_object_finalize_yet = true;
- dc->desc = "i.MX25 SOC";
-}
-
-static const TypeInfo fsl_imx25_type_info = {
- .name = TYPE_FSL_IMX25,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(FslIMX25State),
- .instance_init = fsl_imx25_init,
- .class_init = fsl_imx25_class_init,
-};
-
-static void fsl_imx25_register_types(void)
-{
- type_register_static(&fsl_imx25_type_info);
-}
-
-type_init(fsl_imx25_register_types)
diff --git a/qemu/hw/arm/fsl-imx31.c b/qemu/hw/arm/fsl-imx31.c
deleted file mode 100644
index 31a3a8791..000000000
--- a/qemu/hw/arm/fsl-imx31.c
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * Copyright (c) 2013 Jean-Christophe Dubois <jcd@tribudubois.net>
- *
- * i.MX31 SOC emulation.
- *
- * Based on hw/arm/fsl-imx31.c
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/arm/fsl-imx31.h"
-#include "sysemu/sysemu.h"
-#include "exec/address-spaces.h"
-#include "hw/boards.h"
-#include "sysemu/char.h"
-
-static void fsl_imx31_init(Object *obj)
-{
- FslIMX31State *s = FSL_IMX31(obj);
- int i;
-
- object_initialize(&s->cpu, sizeof(s->cpu), "arm1136-" TYPE_ARM_CPU);
-
- object_initialize(&s->avic, sizeof(s->avic), TYPE_IMX_AVIC);
- qdev_set_parent_bus(DEVICE(&s->avic), sysbus_get_default());
-
- object_initialize(&s->ccm, sizeof(s->ccm), TYPE_IMX31_CCM);
- qdev_set_parent_bus(DEVICE(&s->ccm), sysbus_get_default());
-
- for (i = 0; i < FSL_IMX31_NUM_UARTS; i++) {
- object_initialize(&s->uart[i], sizeof(s->uart[i]), TYPE_IMX_SERIAL);
- qdev_set_parent_bus(DEVICE(&s->uart[i]), sysbus_get_default());
- }
-
- object_initialize(&s->gpt, sizeof(s->gpt), TYPE_IMX_GPT);
- qdev_set_parent_bus(DEVICE(&s->gpt), sysbus_get_default());
-
- for (i = 0; i < FSL_IMX31_NUM_EPITS; i++) {
- object_initialize(&s->epit[i], sizeof(s->epit[i]), TYPE_IMX_EPIT);
- qdev_set_parent_bus(DEVICE(&s->epit[i]), sysbus_get_default());
- }
-
- for (i = 0; i < FSL_IMX31_NUM_I2CS; i++) {
- object_initialize(&s->i2c[i], sizeof(s->i2c[i]), TYPE_IMX_I2C);
- qdev_set_parent_bus(DEVICE(&s->i2c[i]), sysbus_get_default());
- }
-
- for (i = 0; i < FSL_IMX31_NUM_GPIOS; i++) {
- object_initialize(&s->gpio[i], sizeof(s->gpio[i]), TYPE_IMX_GPIO);
- qdev_set_parent_bus(DEVICE(&s->gpio[i]), sysbus_get_default());
- }
-}
-
-static void fsl_imx31_realize(DeviceState *dev, Error **errp)
-{
- FslIMX31State *s = FSL_IMX31(dev);
- uint16_t i;
- Error *err = NULL;
-
- object_property_set_bool(OBJECT(&s->cpu), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- object_property_set_bool(OBJECT(&s->avic), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->avic), 0, FSL_IMX31_AVIC_ADDR);
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->avic), 0,
- qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_IRQ));
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->avic), 1,
- qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_FIQ));
-
- object_property_set_bool(OBJECT(&s->ccm), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->ccm), 0, FSL_IMX31_CCM_ADDR);
-
- /* Initialize all UARTS */
- for (i = 0; i < FSL_IMX31_NUM_UARTS; i++) {
- static const struct {
- hwaddr addr;
- unsigned int irq;
- } serial_table[FSL_IMX31_NUM_UARTS] = {
- { FSL_IMX31_UART1_ADDR, FSL_IMX31_UART1_IRQ },
- { FSL_IMX31_UART2_ADDR, FSL_IMX31_UART2_IRQ },
- };
-
- if (i < MAX_SERIAL_PORTS) {
- CharDriverState *chr;
-
- chr = serial_hds[i];
-
- if (!chr) {
- char label[20];
- snprintf(label, sizeof(label), "imx31.uart%d", i);
- chr = qemu_chr_new(label, "null", NULL);
- }
-
- qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", chr);
- }
-
- object_property_set_bool(OBJECT(&s->uart[i]), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart[i]), 0, serial_table[i].addr);
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0,
- qdev_get_gpio_in(DEVICE(&s->avic),
- serial_table[i].irq));
- }
-
- s->gpt.ccm = IMX_CCM(&s->ccm);
-
- object_property_set_bool(OBJECT(&s->gpt), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpt), 0, FSL_IMX31_GPT_ADDR);
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpt), 0,
- qdev_get_gpio_in(DEVICE(&s->avic), FSL_IMX31_GPT_IRQ));
-
- /* Initialize all EPIT timers */
- for (i = 0; i < FSL_IMX31_NUM_EPITS; i++) {
- static const struct {
- hwaddr addr;
- unsigned int irq;
- } epit_table[FSL_IMX31_NUM_EPITS] = {
- { FSL_IMX31_EPIT1_ADDR, FSL_IMX31_EPIT1_IRQ },
- { FSL_IMX31_EPIT2_ADDR, FSL_IMX31_EPIT2_IRQ },
- };
-
- s->epit[i].ccm = IMX_CCM(&s->ccm);
-
- object_property_set_bool(OBJECT(&s->epit[i]), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->epit[i]), 0, epit_table[i].addr);
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->epit[i]), 0,
- qdev_get_gpio_in(DEVICE(&s->avic),
- epit_table[i].irq));
- }
-
- /* Initialize all I2C */
- for (i = 0; i < FSL_IMX31_NUM_I2CS; i++) {
- static const struct {
- hwaddr addr;
- unsigned int irq;
- } i2c_table[FSL_IMX31_NUM_I2CS] = {
- { FSL_IMX31_I2C1_ADDR, FSL_IMX31_I2C1_IRQ },
- { FSL_IMX31_I2C2_ADDR, FSL_IMX31_I2C2_IRQ },
- { FSL_IMX31_I2C3_ADDR, FSL_IMX31_I2C3_IRQ }
- };
-
- /* Initialize the I2C */
- object_property_set_bool(OBJECT(&s->i2c[i]), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- /* Map I2C memory */
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c[i]), 0, i2c_table[i].addr);
- /* Connect I2C IRQ to PIC */
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c[i]), 0,
- qdev_get_gpio_in(DEVICE(&s->avic),
- i2c_table[i].irq));
- }
-
- /* Initialize all GPIOs */
- for (i = 0; i < FSL_IMX31_NUM_GPIOS; i++) {
- static const struct {
- hwaddr addr;
- unsigned int irq;
- } gpio_table[FSL_IMX31_NUM_GPIOS] = {
- { FSL_IMX31_GPIO1_ADDR, FSL_IMX31_GPIO1_IRQ },
- { FSL_IMX31_GPIO2_ADDR, FSL_IMX31_GPIO2_IRQ },
- { FSL_IMX31_GPIO3_ADDR, FSL_IMX31_GPIO3_IRQ }
- };
-
- object_property_set_bool(OBJECT(&s->gpio[i]), false, "has-edge-sel",
- &error_abort);
- object_property_set_bool(OBJECT(&s->gpio[i]), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio[i]), 0, gpio_table[i].addr);
- /* Connect GPIO IRQ to PIC */
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 0,
- qdev_get_gpio_in(DEVICE(&s->avic),
- gpio_table[i].irq));
- }
-
- /* On a real system, the first 16k is a `secure boot rom' */
- memory_region_init_rom_device(&s->secure_rom, NULL, NULL, NULL,
- "imx31.secure_rom",
- FSL_IMX31_SECURE_ROM_SIZE, &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- memory_region_add_subregion(get_system_memory(), FSL_IMX31_SECURE_ROM_ADDR,
- &s->secure_rom);
-
- /* There is also a 16k ROM */
- memory_region_init_rom_device(&s->rom, NULL, NULL, NULL, "imx31.rom",
- FSL_IMX31_ROM_SIZE, &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- memory_region_add_subregion(get_system_memory(), FSL_IMX31_ROM_ADDR,
- &s->rom);
-
- /* initialize internal RAM (16 KB) */
- memory_region_init_ram(&s->iram, NULL, "imx31.iram", FSL_IMX31_IRAM_SIZE,
- &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- memory_region_add_subregion(get_system_memory(), FSL_IMX31_IRAM_ADDR,
- &s->iram);
- vmstate_register_ram_global(&s->iram);
-
- /* internal RAM (16 KB) is aliased over 256 MB - 16 KB */
- memory_region_init_alias(&s->iram_alias, NULL, "imx31.iram_alias",
- &s->iram, 0, FSL_IMX31_IRAM_ALIAS_SIZE);
- memory_region_add_subregion(get_system_memory(), FSL_IMX31_IRAM_ALIAS_ADDR,
- &s->iram_alias);
-}
-
-static void fsl_imx31_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- dc->realize = fsl_imx31_realize;
-
- /*
- * Reason: creates an ARM CPU, thus use after free(), see
- * arm_cpu_class_init()
- */
- dc->cannot_destroy_with_object_finalize_yet = true;
- dc->desc = "i.MX31 SOC";
-}
-
-static const TypeInfo fsl_imx31_type_info = {
- .name = TYPE_FSL_IMX31,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(FslIMX31State),
- .instance_init = fsl_imx31_init,
- .class_init = fsl_imx31_class_init,
-};
-
-static void fsl_imx31_register_types(void)
-{
- type_register_static(&fsl_imx31_type_info);
-}
-
-type_init(fsl_imx31_register_types)
diff --git a/qemu/hw/arm/gumstix.c b/qemu/hw/arm/gumstix.c
deleted file mode 100644
index d59d9ba4e..000000000
--- a/qemu/hw/arm/gumstix.c
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Gumstix Platforms
- *
- * Copyright (c) 2007 by Thorsten Zitterell <info@bitmux.org>
- *
- * Code based on spitz platform by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-/*
- * Example usage:
- *
- * connex:
- * =======
- * create image:
- * # dd of=flash bs=1k count=16k if=/dev/zero
- * # dd of=flash bs=1k conv=notrunc if=u-boot.bin
- * # dd of=flash bs=1k conv=notrunc seek=256 if=rootfs.arm_nofpu.jffs2
- * start it:
- * # qemu-system-arm -M connex -pflash flash -monitor null -nographic
- *
- * verdex:
- * =======
- * create image:
- * # dd of=flash bs=1k count=32k if=/dev/zero
- * # dd of=flash bs=1k conv=notrunc if=u-boot.bin
- * # dd of=flash bs=1k conv=notrunc seek=256 if=rootfs.arm_nofpu.jffs2
- * # dd of=flash bs=1k conv=notrunc seek=31744 if=uImage
- * start it:
- * # qemu-system-arm -M verdex -pflash flash -monitor null -nographic -m 289
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/arm/pxa.h"
-#include "net/net.h"
-#include "hw/block/flash.h"
-#include "hw/devices.h"
-#include "hw/boards.h"
-#include "sysemu/block-backend.h"
-#include "exec/address-spaces.h"
-#include "sysemu/qtest.h"
-
-static const int sector_len = 128 * 1024;
-
-static void connex_init(MachineState *machine)
-{
- PXA2xxState *cpu;
- DriveInfo *dinfo;
- int be;
- MemoryRegion *address_space_mem = get_system_memory();
-
- uint32_t connex_rom = 0x01000000;
- uint32_t connex_ram = 0x04000000;
-
- cpu = pxa255_init(address_space_mem, connex_ram);
-
- dinfo = drive_get(IF_PFLASH, 0, 0);
- if (!dinfo && !qtest_enabled()) {
- fprintf(stderr, "A flash image must be given with the "
- "'pflash' parameter\n");
- exit(1);
- }
-
-#ifdef TARGET_WORDS_BIGENDIAN
- be = 1;
-#else
- be = 0;
-#endif
- if (!pflash_cfi01_register(0x00000000, NULL, "connext.rom", connex_rom,
- dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- sector_len, connex_rom / sector_len,
- 2, 0, 0, 0, 0, be)) {
- fprintf(stderr, "qemu: Error registering flash memory.\n");
- exit(1);
- }
-
- /* Interrupt line of NIC is connected to GPIO line 36 */
- smc91c111_init(&nd_table[0], 0x04000300,
- qdev_get_gpio_in(cpu->gpio, 36));
-}
-
-static void verdex_init(MachineState *machine)
-{
- const char *cpu_model = machine->cpu_model;
- PXA2xxState *cpu;
- DriveInfo *dinfo;
- int be;
- MemoryRegion *address_space_mem = get_system_memory();
-
- uint32_t verdex_rom = 0x02000000;
- uint32_t verdex_ram = 0x10000000;
-
- cpu = pxa270_init(address_space_mem, verdex_ram, cpu_model ?: "pxa270-c0");
-
- dinfo = drive_get(IF_PFLASH, 0, 0);
- if (!dinfo && !qtest_enabled()) {
- fprintf(stderr, "A flash image must be given with the "
- "'pflash' parameter\n");
- exit(1);
- }
-
-#ifdef TARGET_WORDS_BIGENDIAN
- be = 1;
-#else
- be = 0;
-#endif
- if (!pflash_cfi01_register(0x00000000, NULL, "verdex.rom", verdex_rom,
- dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- sector_len, verdex_rom / sector_len,
- 2, 0, 0, 0, 0, be)) {
- fprintf(stderr, "qemu: Error registering flash memory.\n");
- exit(1);
- }
-
- /* Interrupt line of NIC is connected to GPIO line 99 */
- smc91c111_init(&nd_table[0], 0x04000300,
- qdev_get_gpio_in(cpu->gpio, 99));
-}
-
-static void connex_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "Gumstix Connex (PXA255)";
- mc->init = connex_init;
-}
-
-static const TypeInfo connex_type = {
- .name = MACHINE_TYPE_NAME("connex"),
- .parent = TYPE_MACHINE,
- .class_init = connex_class_init,
-};
-
-static void verdex_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "Gumstix Verdex (PXA270)";
- mc->init = verdex_init;
-}
-
-static const TypeInfo verdex_type = {
- .name = MACHINE_TYPE_NAME("verdex"),
- .parent = TYPE_MACHINE,
- .class_init = verdex_class_init,
-};
-
-static void gumstix_machine_init(void)
-{
- type_register_static(&connex_type);
- type_register_static(&verdex_type);
-}
-
-type_init(gumstix_machine_init)
diff --git a/qemu/hw/arm/highbank.c b/qemu/hw/arm/highbank.c
deleted file mode 100644
index d9930c0d3..000000000
--- a/qemu/hw/arm/highbank.c
+++ /dev/null
@@ -1,441 +0,0 @@
-/*
- * Calxeda Highbank SoC emulation
- *
- * Copyright (c) 2010-2012 Calxeda
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2 or later, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/sysbus.h"
-#include "hw/arm/arm.h"
-#include "hw/devices.h"
-#include "hw/loader.h"
-#include "net/net.h"
-#include "sysemu/kvm.h"
-#include "sysemu/sysemu.h"
-#include "hw/boards.h"
-#include "sysemu/block-backend.h"
-#include "exec/address-spaces.h"
-#include "qemu/error-report.h"
-
-#define SMP_BOOT_ADDR 0x100
-#define SMP_BOOT_REG 0x40
-#define MPCORE_PERIPHBASE 0xfff10000
-
-#define MVBAR_ADDR 0x200
-#define BOARD_SETUP_ADDR (MVBAR_ADDR + 8 * sizeof(uint32_t))
-
-#define NIRQ_GIC 160
-
-/* Board init. */
-
-static void hb_write_board_setup(ARMCPU *cpu,
- const struct arm_boot_info *info)
-{
- arm_write_secure_board_setup_dummy_smc(cpu, info, MVBAR_ADDR);
-}
-
-static void hb_write_secondary(ARMCPU *cpu, const struct arm_boot_info *info)
-{
- int n;
- uint32_t smpboot[] = {
- 0xee100fb0, /* mrc p15, 0, r0, c0, c0, 5 - read current core id */
- 0xe210000f, /* ands r0, r0, #0x0f */
- 0xe3a03040, /* mov r3, #0x40 - jump address is 0x40 + 0x10 * core id */
- 0xe0830200, /* add r0, r3, r0, lsl #4 */
- 0xe59f2024, /* ldr r2, privbase */
- 0xe3a01001, /* mov r1, #1 */
- 0xe5821100, /* str r1, [r2, #256] - set GICC_CTLR.Enable */
- 0xe3a010ff, /* mov r1, #0xff */
- 0xe5821104, /* str r1, [r2, #260] - set GICC_PMR.Priority to 0xff */
- 0xf57ff04f, /* dsb */
- 0xe320f003, /* wfi */
- 0xe5901000, /* ldr r1, [r0] */
- 0xe1110001, /* tst r1, r1 */
- 0x0afffffb, /* beq <wfi> */
- 0xe12fff11, /* bx r1 */
- MPCORE_PERIPHBASE /* privbase: MPCore peripheral base address. */
- };
- for (n = 0; n < ARRAY_SIZE(smpboot); n++) {
- smpboot[n] = tswap32(smpboot[n]);
- }
- rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot), SMP_BOOT_ADDR);
-}
-
-static void hb_reset_secondary(ARMCPU *cpu, const struct arm_boot_info *info)
-{
- CPUARMState *env = &cpu->env;
-
- switch (info->nb_cpus) {
- case 4:
- address_space_stl_notdirty(&address_space_memory,
- SMP_BOOT_REG + 0x30, 0,
- MEMTXATTRS_UNSPECIFIED, NULL);
- case 3:
- address_space_stl_notdirty(&address_space_memory,
- SMP_BOOT_REG + 0x20, 0,
- MEMTXATTRS_UNSPECIFIED, NULL);
- case 2:
- address_space_stl_notdirty(&address_space_memory,
- SMP_BOOT_REG + 0x10, 0,
- MEMTXATTRS_UNSPECIFIED, NULL);
- env->regs[15] = SMP_BOOT_ADDR;
- break;
- default:
- break;
- }
-}
-
-#define NUM_REGS 0x200
-static void hb_regs_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- uint32_t *regs = opaque;
-
- if (offset == 0xf00) {
- if (value == 1 || value == 2) {
- qemu_system_reset_request();
- } else if (value == 3) {
- qemu_system_shutdown_request();
- }
- }
-
- regs[offset/4] = value;
-}
-
-static uint64_t hb_regs_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- uint32_t *regs = opaque;
- uint32_t value = regs[offset/4];
-
- if ((offset == 0x100) || (offset == 0x108) || (offset == 0x10C)) {
- value |= 0x30000000;
- }
-
- return value;
-}
-
-static const MemoryRegionOps hb_mem_ops = {
- .read = hb_regs_read,
- .write = hb_regs_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-#define TYPE_HIGHBANK_REGISTERS "highbank-regs"
-#define HIGHBANK_REGISTERS(obj) \
- OBJECT_CHECK(HighbankRegsState, (obj), TYPE_HIGHBANK_REGISTERS)
-
-typedef struct {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- MemoryRegion iomem;
- uint32_t regs[NUM_REGS];
-} HighbankRegsState;
-
-static VMStateDescription vmstate_highbank_regs = {
- .name = "highbank-regs",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, HighbankRegsState, NUM_REGS),
- VMSTATE_END_OF_LIST(),
- },
-};
-
-static void highbank_regs_reset(DeviceState *dev)
-{
- HighbankRegsState *s = HIGHBANK_REGISTERS(dev);
-
- s->regs[0x40] = 0x05F20121;
- s->regs[0x41] = 0x2;
- s->regs[0x42] = 0x05F30121;
- s->regs[0x43] = 0x05F40121;
-}
-
-static int highbank_regs_init(SysBusDevice *dev)
-{
- HighbankRegsState *s = HIGHBANK_REGISTERS(dev);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &hb_mem_ops, s->regs,
- "highbank_regs", 0x1000);
- sysbus_init_mmio(dev, &s->iomem);
-
- return 0;
-}
-
-static void highbank_regs_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- sbc->init = highbank_regs_init;
- dc->desc = "Calxeda Highbank registers";
- dc->vmsd = &vmstate_highbank_regs;
- dc->reset = highbank_regs_reset;
-}
-
-static const TypeInfo highbank_regs_info = {
- .name = TYPE_HIGHBANK_REGISTERS,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(HighbankRegsState),
- .class_init = highbank_regs_class_init,
-};
-
-static void highbank_regs_register_types(void)
-{
- type_register_static(&highbank_regs_info);
-}
-
-type_init(highbank_regs_register_types)
-
-static struct arm_boot_info highbank_binfo;
-
-enum cxmachines {
- CALXEDA_HIGHBANK,
- CALXEDA_MIDWAY,
-};
-
-/* ram_size must be set to match the upper bound of memory in the
- * device tree (linux/arch/arm/boot/dts/highbank.dts), which is
- * normally 0xff900000 or -m 4089. When running this board on a
- * 32-bit host, set the reg value of memory to 0xf7ff00000 in the
- * device tree and pass -m 2047 to QEMU.
- */
-static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
-{
- ram_addr_t ram_size = machine->ram_size;
- const char *cpu_model = machine->cpu_model;
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- const char *initrd_filename = machine->initrd_filename;
- DeviceState *dev = NULL;
- SysBusDevice *busdev;
- qemu_irq pic[128];
- int n;
- qemu_irq cpu_irq[4];
- qemu_irq cpu_fiq[4];
- MemoryRegion *sysram;
- MemoryRegion *dram;
- MemoryRegion *sysmem;
- char *sysboot_filename;
-
- switch (machine_id) {
- case CALXEDA_HIGHBANK:
- cpu_model = "cortex-a9";
- break;
- case CALXEDA_MIDWAY:
- cpu_model = "cortex-a15";
- break;
- }
-
- for (n = 0; n < smp_cpus; n++) {
- ObjectClass *oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
- Object *cpuobj;
- ARMCPU *cpu;
-
- cpuobj = object_new(object_class_get_name(oc));
- cpu = ARM_CPU(cpuobj);
-
- object_property_set_int(cpuobj, QEMU_PSCI_CONDUIT_SMC,
- "psci-conduit", &error_abort);
-
- if (n) {
- /* Secondary CPUs start in PSCI powered-down state */
- object_property_set_bool(cpuobj, true,
- "start-powered-off", &error_abort);
- }
-
- if (object_property_find(cpuobj, "reset-cbar", NULL)) {
- object_property_set_int(cpuobj, MPCORE_PERIPHBASE,
- "reset-cbar", &error_abort);
- }
- object_property_set_bool(cpuobj, true, "realized", &error_fatal);
- cpu_irq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ);
- cpu_fiq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ);
- }
-
- sysmem = get_system_memory();
- dram = g_new(MemoryRegion, 1);
- memory_region_allocate_system_memory(dram, NULL, "highbank.dram", ram_size);
- /* SDRAM at address zero. */
- memory_region_add_subregion(sysmem, 0, dram);
-
- sysram = g_new(MemoryRegion, 1);
- memory_region_init_ram(sysram, NULL, "highbank.sysram", 0x8000,
- &error_fatal);
- memory_region_add_subregion(sysmem, 0xfff88000, sysram);
- if (bios_name != NULL) {
- sysboot_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
- if (sysboot_filename != NULL) {
- if (load_image_targphys(sysboot_filename, 0xfff88000, 0x8000) < 0) {
- error_report("Unable to load %s", bios_name);
- exit(1);
- }
- g_free(sysboot_filename);
- } else {
- error_report("Unable to find %s", bios_name);
- exit(1);
- }
- }
-
- switch (machine_id) {
- case CALXEDA_HIGHBANK:
- dev = qdev_create(NULL, "l2x0");
- qdev_init_nofail(dev);
- busdev = SYS_BUS_DEVICE(dev);
- sysbus_mmio_map(busdev, 0, 0xfff12000);
-
- dev = qdev_create(NULL, "a9mpcore_priv");
- break;
- case CALXEDA_MIDWAY:
- dev = qdev_create(NULL, "a15mpcore_priv");
- break;
- }
- qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
- qdev_prop_set_uint32(dev, "num-irq", NIRQ_GIC);
- qdev_init_nofail(dev);
- busdev = SYS_BUS_DEVICE(dev);
- sysbus_mmio_map(busdev, 0, MPCORE_PERIPHBASE);
- for (n = 0; n < smp_cpus; n++) {
- sysbus_connect_irq(busdev, n, cpu_irq[n]);
- sysbus_connect_irq(busdev, n + smp_cpus, cpu_fiq[n]);
- }
-
- for (n = 0; n < 128; n++) {
- pic[n] = qdev_get_gpio_in(dev, n);
- }
-
- dev = qdev_create(NULL, "sp804");
- qdev_prop_set_uint32(dev, "freq0", 150000000);
- qdev_prop_set_uint32(dev, "freq1", 150000000);
- qdev_init_nofail(dev);
- busdev = SYS_BUS_DEVICE(dev);
- sysbus_mmio_map(busdev, 0, 0xfff34000);
- sysbus_connect_irq(busdev, 0, pic[18]);
- sysbus_create_simple("pl011", 0xfff36000, pic[20]);
-
- dev = qdev_create(NULL, "highbank-regs");
- qdev_init_nofail(dev);
- busdev = SYS_BUS_DEVICE(dev);
- sysbus_mmio_map(busdev, 0, 0xfff3c000);
-
- sysbus_create_simple("pl061", 0xfff30000, pic[14]);
- sysbus_create_simple("pl061", 0xfff31000, pic[15]);
- sysbus_create_simple("pl061", 0xfff32000, pic[16]);
- sysbus_create_simple("pl061", 0xfff33000, pic[17]);
- sysbus_create_simple("pl031", 0xfff35000, pic[19]);
- sysbus_create_simple("pl022", 0xfff39000, pic[23]);
-
- sysbus_create_simple("sysbus-ahci", 0xffe08000, pic[83]);
-
- if (nd_table[0].used) {
- qemu_check_nic_model(&nd_table[0], "xgmac");
- dev = qdev_create(NULL, "xgmac");
- qdev_set_nic_properties(dev, &nd_table[0]);
- qdev_init_nofail(dev);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xfff50000);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[77]);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, pic[78]);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, pic[79]);
-
- qemu_check_nic_model(&nd_table[1], "xgmac");
- dev = qdev_create(NULL, "xgmac");
- qdev_set_nic_properties(dev, &nd_table[1]);
- qdev_init_nofail(dev);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xfff51000);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[80]);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, pic[81]);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, pic[82]);
- }
-
- highbank_binfo.ram_size = ram_size;
- highbank_binfo.kernel_filename = kernel_filename;
- highbank_binfo.kernel_cmdline = kernel_cmdline;
- highbank_binfo.initrd_filename = initrd_filename;
- /* highbank requires a dtb in order to boot, and the dtb will override
- * the board ID. The following value is ignored, so set it to -1 to be
- * clear that the value is meaningless.
- */
- highbank_binfo.board_id = -1;
- highbank_binfo.nb_cpus = smp_cpus;
- highbank_binfo.loader_start = 0;
- highbank_binfo.write_secondary_boot = hb_write_secondary;
- highbank_binfo.secondary_cpu_reset_hook = hb_reset_secondary;
- if (!kvm_enabled()) {
- highbank_binfo.board_setup_addr = BOARD_SETUP_ADDR;
- highbank_binfo.write_board_setup = hb_write_board_setup;
- highbank_binfo.secure_board_setup = true;
- } else {
- error_report("WARNING: cannot load built-in Monitor support "
- "if KVM is enabled. Some guests (such as Linux) "
- "may not boot.");
- }
-
- arm_load_kernel(ARM_CPU(first_cpu), &highbank_binfo);
-}
-
-static void highbank_init(MachineState *machine)
-{
- calxeda_init(machine, CALXEDA_HIGHBANK);
-}
-
-static void midway_init(MachineState *machine)
-{
- calxeda_init(machine, CALXEDA_MIDWAY);
-}
-
-static void highbank_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "Calxeda Highbank (ECX-1000)";
- mc->init = highbank_init;
- mc->block_default_type = IF_SCSI;
- mc->max_cpus = 4;
-}
-
-static const TypeInfo highbank_type = {
- .name = MACHINE_TYPE_NAME("highbank"),
- .parent = TYPE_MACHINE,
- .class_init = highbank_class_init,
-};
-
-static void midway_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "Calxeda Midway (ECX-2000)";
- mc->init = midway_init;
- mc->block_default_type = IF_SCSI;
- mc->max_cpus = 4;
-}
-
-static const TypeInfo midway_type = {
- .name = MACHINE_TYPE_NAME("midway"),
- .parent = TYPE_MACHINE,
- .class_init = midway_class_init,
-};
-
-static void calxeda_machines_init(void)
-{
- type_register_static(&highbank_type);
- type_register_static(&midway_type);
-}
-
-type_init(calxeda_machines_init)
diff --git a/qemu/hw/arm/imx25_pdk.c b/qemu/hw/arm/imx25_pdk.c
deleted file mode 100644
index 025b60843..000000000
--- a/qemu/hw/arm/imx25_pdk.c
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (c) 2013 Jean-Christophe Dubois <jcd@tribudubois.net>
- *
- * PDK Board System emulation.
- *
- * Based on hw/arm/kzm.c
- *
- * Copyright (c) 2008 OKL and 2011 NICTA
- * Written by Hans at OK-Labs
- * Updated by Peter Chubb.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/arm/fsl-imx25.h"
-#include "hw/boards.h"
-#include "qemu/error-report.h"
-#include "exec/address-spaces.h"
-#include "sysemu/qtest.h"
-#include "hw/i2c/i2c.h"
-
-/* Memory map for PDK Emulation Baseboard:
- * 0x00000000-0x7fffffff See i.MX25 SOC fr support
- * 0x80000000-0x87ffffff RAM + Alias EMULATED
- * 0x90000000-0x9fffffff RAM + Alias EMULATED
- * 0xa0000000-0xa7ffffff Flash IGNORED
- * 0xa8000000-0xafffffff Flash IGNORED
- * 0xb0000000-0xb1ffffff SRAM IGNORED
- * 0xb2000000-0xb3ffffff SRAM IGNORED
- * 0xb4000000-0xb5ffffff CS4 IGNORED
- * 0xb6000000-0xb8000fff Reserved IGNORED
- * 0xb8001000-0xb8001fff SDRAM CTRL reg IGNORED
- * 0xb8002000-0xb8002fff WEIM CTRL reg IGNORED
- * 0xb8003000-0xb8003fff M3IF CTRL reg IGNORED
- * 0xb8004000-0xb8004fff EMI CTRL reg IGNORED
- * 0xb8005000-0xbaffffff Reserved IGNORED
- * 0xbb000000-0xbb000fff NAND flash area buf IGNORED
- * 0xbb001000-0xbb0011ff NAND flash reserved IGNORED
- * 0xbb001200-0xbb001dff Reserved IGNORED
- * 0xbb001e00-0xbb001fff NAN flash CTRL reg IGNORED
- * 0xbb012000-0xbfffffff Reserved IGNORED
- * 0xc0000000-0xffffffff Reserved IGNORED
- */
-
-typedef struct IMX25PDK {
- FslIMX25State soc;
- MemoryRegion ram;
- MemoryRegion ram_alias;
-} IMX25PDK;
-
-static struct arm_boot_info imx25_pdk_binfo;
-
-static void imx25_pdk_init(MachineState *machine)
-{
- IMX25PDK *s = g_new0(IMX25PDK, 1);
- unsigned int ram_size;
- unsigned int alias_offset;
- int i;
-
- object_initialize(&s->soc, sizeof(s->soc), TYPE_FSL_IMX25);
- object_property_add_child(OBJECT(machine), "soc", OBJECT(&s->soc),
- &error_abort);
-
- object_property_set_bool(OBJECT(&s->soc), true, "realized", &error_fatal);
-
- /* We need to initialize our memory */
- if (machine->ram_size > (FSL_IMX25_SDRAM0_SIZE + FSL_IMX25_SDRAM1_SIZE)) {
- error_report("WARNING: RAM size " RAM_ADDR_FMT " above max supported, "
- "reduced to %x", machine->ram_size,
- FSL_IMX25_SDRAM0_SIZE + FSL_IMX25_SDRAM1_SIZE);
- machine->ram_size = FSL_IMX25_SDRAM0_SIZE + FSL_IMX25_SDRAM1_SIZE;
- }
-
- memory_region_allocate_system_memory(&s->ram, NULL, "imx25.ram",
- machine->ram_size);
- memory_region_add_subregion(get_system_memory(), FSL_IMX25_SDRAM0_ADDR,
- &s->ram);
-
- /* initialize the alias memory if any */
- for (i = 0, ram_size = machine->ram_size, alias_offset = 0;
- (i < 2) && ram_size; i++) {
- unsigned int size;
- static const struct {
- hwaddr addr;
- unsigned int size;
- } ram[2] = {
- { FSL_IMX25_SDRAM0_ADDR, FSL_IMX25_SDRAM0_SIZE },
- { FSL_IMX25_SDRAM1_ADDR, FSL_IMX25_SDRAM1_SIZE },
- };
-
- size = MIN(ram_size, ram[i].size);
-
- ram_size -= size;
-
- if (size < ram[i].size) {
- memory_region_init_alias(&s->ram_alias, NULL, "ram.alias",
- &s->ram, alias_offset, ram[i].size - size);
- memory_region_add_subregion(get_system_memory(),
- ram[i].addr + size, &s->ram_alias);
- }
-
- alias_offset += ram[i].size;
- }
-
- imx25_pdk_binfo.ram_size = machine->ram_size;
- imx25_pdk_binfo.kernel_filename = machine->kernel_filename;
- imx25_pdk_binfo.kernel_cmdline = machine->kernel_cmdline;
- imx25_pdk_binfo.initrd_filename = machine->initrd_filename;
- imx25_pdk_binfo.loader_start = FSL_IMX25_SDRAM0_ADDR;
- imx25_pdk_binfo.board_id = 1771,
- imx25_pdk_binfo.nb_cpus = 1;
-
- /*
- * We test explicitly for qtest here as it is not done (yet?) in
- * arm_load_kernel(). Without this the "make check" command would
- * fail.
- */
- if (!qtest_enabled()) {
- arm_load_kernel(&s->soc.cpu, &imx25_pdk_binfo);
- } else {
- /*
- * This I2C device doesn't exist on the real board.
- * We add it here (only on qtest usage) to be able to do a bit
- * of simple qtest. See "make check" for details.
- */
- i2c_create_slave((I2CBus *)qdev_get_child_bus(DEVICE(&s->soc.i2c[0]),
- "i2c"),
- "ds1338", 0x68);
- }
-}
-
-static void imx25_pdk_machine_init(MachineClass *mc)
-{
- mc->desc = "ARM i.MX25 PDK board (ARM926)";
- mc->init = imx25_pdk_init;
-}
-
-DEFINE_MACHINE("imx25-pdk", imx25_pdk_machine_init)
diff --git a/qemu/hw/arm/integratorcp.c b/qemu/hw/arm/integratorcp.c
deleted file mode 100644
index e31bca6e7..000000000
--- a/qemu/hw/arm/integratorcp.c
+++ /dev/null
@@ -1,674 +0,0 @@
-/*
- * ARM Integrator CP System emulation.
- *
- * Copyright (c) 2005-2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/sysbus.h"
-#include "hw/devices.h"
-#include "hw/boards.h"
-#include "hw/arm/arm.h"
-#include "hw/misc/arm_integrator_debug.h"
-#include "net/net.h"
-#include "exec/address-spaces.h"
-#include "sysemu/sysemu.h"
-#include "qemu/error-report.h"
-
-#define TYPE_INTEGRATOR_CM "integrator_core"
-#define INTEGRATOR_CM(obj) \
- OBJECT_CHECK(IntegratorCMState, (obj), TYPE_INTEGRATOR_CM)
-
-typedef struct IntegratorCMState {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- MemoryRegion iomem;
- uint32_t memsz;
- MemoryRegion flash;
- uint32_t cm_osc;
- uint32_t cm_ctrl;
- uint32_t cm_lock;
- uint32_t cm_auxosc;
- uint32_t cm_sdram;
- uint32_t cm_init;
- uint32_t cm_flags;
- uint32_t cm_nvflags;
- uint32_t cm_refcnt_offset;
- uint32_t int_level;
- uint32_t irq_enabled;
- uint32_t fiq_enabled;
-} IntegratorCMState;
-
-static uint8_t integrator_spd[128] = {
- 128, 8, 4, 11, 9, 1, 64, 0, 2, 0xa0, 0xa0, 0, 0, 8, 0, 1,
- 0xe, 4, 0x1c, 1, 2, 0x20, 0xc0, 0, 0, 0, 0, 0x30, 0x28, 0x30, 0x28, 0x40
-};
-
-static uint64_t integratorcm_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- IntegratorCMState *s = opaque;
- if (offset >= 0x100 && offset < 0x200) {
- /* CM_SPD */
- if (offset >= 0x180)
- return 0;
- return integrator_spd[offset >> 2];
- }
- switch (offset >> 2) {
- case 0: /* CM_ID */
- return 0x411a3001;
- case 1: /* CM_PROC */
- return 0;
- case 2: /* CM_OSC */
- return s->cm_osc;
- case 3: /* CM_CTRL */
- return s->cm_ctrl;
- case 4: /* CM_STAT */
- return 0x00100000;
- case 5: /* CM_LOCK */
- if (s->cm_lock == 0xa05f) {
- return 0x1a05f;
- } else {
- return s->cm_lock;
- }
- case 6: /* CM_LMBUSCNT */
- /* ??? High frequency timer. */
- hw_error("integratorcm_read: CM_LMBUSCNT");
- case 7: /* CM_AUXOSC */
- return s->cm_auxosc;
- case 8: /* CM_SDRAM */
- return s->cm_sdram;
- case 9: /* CM_INIT */
- return s->cm_init;
- case 10: /* CM_REFCNT */
- /* This register, CM_REFCNT, provides a 32-bit count value.
- * The count increments at the fixed reference clock frequency of 24MHz
- * and can be used as a real-time counter.
- */
- return (uint32_t)muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24,
- 1000) - s->cm_refcnt_offset;
- case 12: /* CM_FLAGS */
- return s->cm_flags;
- case 14: /* CM_NVFLAGS */
- return s->cm_nvflags;
- case 16: /* CM_IRQ_STAT */
- return s->int_level & s->irq_enabled;
- case 17: /* CM_IRQ_RSTAT */
- return s->int_level;
- case 18: /* CM_IRQ_ENSET */
- return s->irq_enabled;
- case 20: /* CM_SOFT_INTSET */
- return s->int_level & 1;
- case 24: /* CM_FIQ_STAT */
- return s->int_level & s->fiq_enabled;
- case 25: /* CM_FIQ_RSTAT */
- return s->int_level;
- case 26: /* CM_FIQ_ENSET */
- return s->fiq_enabled;
- case 32: /* CM_VOLTAGE_CTL0 */
- case 33: /* CM_VOLTAGE_CTL1 */
- case 34: /* CM_VOLTAGE_CTL2 */
- case 35: /* CM_VOLTAGE_CTL3 */
- /* ??? Voltage control unimplemented. */
- return 0;
- default:
- hw_error("integratorcm_read: Unimplemented offset 0x%x\n",
- (int)offset);
- return 0;
- }
-}
-
-static void integratorcm_do_remap(IntegratorCMState *s)
-{
- /* Sync memory region state with CM_CTRL REMAP bit:
- * bit 0 => flash at address 0; bit 1 => RAM
- */
- memory_region_set_enabled(&s->flash, !(s->cm_ctrl & 4));
-}
-
-static void integratorcm_set_ctrl(IntegratorCMState *s, uint32_t value)
-{
- if (value & 8) {
- qemu_system_reset_request();
- }
- if ((s->cm_ctrl ^ value) & 1) {
- /* (value & 1) != 0 means the green "MISC LED" is lit.
- * We don't have any nice place to display LEDs. printf is a bad
- * idea because Linux uses the LED as a heartbeat and the output
- * will swamp anything else on the terminal.
- */
- }
- /* Note that the RESET bit [3] always reads as zero */
- s->cm_ctrl = (s->cm_ctrl & ~5) | (value & 5);
- integratorcm_do_remap(s);
-}
-
-static void integratorcm_update(IntegratorCMState *s)
-{
- /* ??? The CPU irq/fiq is raised when either the core module or base PIC
- are active. */
- if (s->int_level & (s->irq_enabled | s->fiq_enabled))
- hw_error("Core module interrupt\n");
-}
-
-static void integratorcm_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- IntegratorCMState *s = opaque;
- switch (offset >> 2) {
- case 2: /* CM_OSC */
- if (s->cm_lock == 0xa05f)
- s->cm_osc = value;
- break;
- case 3: /* CM_CTRL */
- integratorcm_set_ctrl(s, value);
- break;
- case 5: /* CM_LOCK */
- s->cm_lock = value & 0xffff;
- break;
- case 7: /* CM_AUXOSC */
- if (s->cm_lock == 0xa05f)
- s->cm_auxosc = value;
- break;
- case 8: /* CM_SDRAM */
- s->cm_sdram = value;
- break;
- case 9: /* CM_INIT */
- /* ??? This can change the memory bus frequency. */
- s->cm_init = value;
- break;
- case 12: /* CM_FLAGSS */
- s->cm_flags |= value;
- break;
- case 13: /* CM_FLAGSC */
- s->cm_flags &= ~value;
- break;
- case 14: /* CM_NVFLAGSS */
- s->cm_nvflags |= value;
- break;
- case 15: /* CM_NVFLAGSS */
- s->cm_nvflags &= ~value;
- break;
- case 18: /* CM_IRQ_ENSET */
- s->irq_enabled |= value;
- integratorcm_update(s);
- break;
- case 19: /* CM_IRQ_ENCLR */
- s->irq_enabled &= ~value;
- integratorcm_update(s);
- break;
- case 20: /* CM_SOFT_INTSET */
- s->int_level |= (value & 1);
- integratorcm_update(s);
- break;
- case 21: /* CM_SOFT_INTCLR */
- s->int_level &= ~(value & 1);
- integratorcm_update(s);
- break;
- case 26: /* CM_FIQ_ENSET */
- s->fiq_enabled |= value;
- integratorcm_update(s);
- break;
- case 27: /* CM_FIQ_ENCLR */
- s->fiq_enabled &= ~value;
- integratorcm_update(s);
- break;
- case 32: /* CM_VOLTAGE_CTL0 */
- case 33: /* CM_VOLTAGE_CTL1 */
- case 34: /* CM_VOLTAGE_CTL2 */
- case 35: /* CM_VOLTAGE_CTL3 */
- /* ??? Voltage control unimplemented. */
- break;
- default:
- hw_error("integratorcm_write: Unimplemented offset 0x%x\n",
- (int)offset);
- break;
- }
-}
-
-/* Integrator/CM control registers. */
-
-static const MemoryRegionOps integratorcm_ops = {
- .read = integratorcm_read,
- .write = integratorcm_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int integratorcm_init(SysBusDevice *dev)
-{
- IntegratorCMState *s = INTEGRATOR_CM(dev);
-
- s->cm_osc = 0x01000048;
- /* ??? What should the high bits of this value be? */
- s->cm_auxosc = 0x0007feff;
- s->cm_sdram = 0x00011122;
- if (s->memsz >= 256) {
- integrator_spd[31] = 64;
- s->cm_sdram |= 0x10;
- } else if (s->memsz >= 128) {
- integrator_spd[31] = 32;
- s->cm_sdram |= 0x0c;
- } else if (s->memsz >= 64) {
- integrator_spd[31] = 16;
- s->cm_sdram |= 0x08;
- } else if (s->memsz >= 32) {
- integrator_spd[31] = 4;
- s->cm_sdram |= 0x04;
- } else {
- integrator_spd[31] = 2;
- }
- memcpy(integrator_spd + 73, "QEMU-MEMORY", 11);
- s->cm_init = 0x00000112;
- s->cm_refcnt_offset = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24,
- 1000);
- memory_region_init_ram(&s->flash, OBJECT(s), "integrator.flash", 0x100000,
- &error_fatal);
- vmstate_register_ram_global(&s->flash);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &integratorcm_ops, s,
- "integratorcm", 0x00800000);
- sysbus_init_mmio(dev, &s->iomem);
-
- integratorcm_do_remap(s);
- /* ??? Save/restore. */
- return 0;
-}
-
-/* Integrator/CP hardware emulation. */
-/* Primary interrupt controller. */
-
-#define TYPE_INTEGRATOR_PIC "integrator_pic"
-#define INTEGRATOR_PIC(obj) \
- OBJECT_CHECK(icp_pic_state, (obj), TYPE_INTEGRATOR_PIC)
-
-typedef struct icp_pic_state {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- MemoryRegion iomem;
- uint32_t level;
- uint32_t irq_enabled;
- uint32_t fiq_enabled;
- qemu_irq parent_irq;
- qemu_irq parent_fiq;
-} icp_pic_state;
-
-static void icp_pic_update(icp_pic_state *s)
-{
- uint32_t flags;
-
- flags = (s->level & s->irq_enabled);
- qemu_set_irq(s->parent_irq, flags != 0);
- flags = (s->level & s->fiq_enabled);
- qemu_set_irq(s->parent_fiq, flags != 0);
-}
-
-static void icp_pic_set_irq(void *opaque, int irq, int level)
-{
- icp_pic_state *s = (icp_pic_state *)opaque;
- if (level)
- s->level |= 1 << irq;
- else
- s->level &= ~(1 << irq);
- icp_pic_update(s);
-}
-
-static uint64_t icp_pic_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- icp_pic_state *s = (icp_pic_state *)opaque;
-
- switch (offset >> 2) {
- case 0: /* IRQ_STATUS */
- return s->level & s->irq_enabled;
- case 1: /* IRQ_RAWSTAT */
- return s->level;
- case 2: /* IRQ_ENABLESET */
- return s->irq_enabled;
- case 4: /* INT_SOFTSET */
- return s->level & 1;
- case 8: /* FRQ_STATUS */
- return s->level & s->fiq_enabled;
- case 9: /* FRQ_RAWSTAT */
- return s->level;
- case 10: /* FRQ_ENABLESET */
- return s->fiq_enabled;
- case 3: /* IRQ_ENABLECLR */
- case 5: /* INT_SOFTCLR */
- case 11: /* FRQ_ENABLECLR */
- default:
- printf ("icp_pic_read: Bad register offset 0x%x\n", (int)offset);
- return 0;
- }
-}
-
-static void icp_pic_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- icp_pic_state *s = (icp_pic_state *)opaque;
-
- switch (offset >> 2) {
- case 2: /* IRQ_ENABLESET */
- s->irq_enabled |= value;
- break;
- case 3: /* IRQ_ENABLECLR */
- s->irq_enabled &= ~value;
- break;
- case 4: /* INT_SOFTSET */
- if (value & 1)
- icp_pic_set_irq(s, 0, 1);
- break;
- case 5: /* INT_SOFTCLR */
- if (value & 1)
- icp_pic_set_irq(s, 0, 0);
- break;
- case 10: /* FRQ_ENABLESET */
- s->fiq_enabled |= value;
- break;
- case 11: /* FRQ_ENABLECLR */
- s->fiq_enabled &= ~value;
- break;
- case 0: /* IRQ_STATUS */
- case 1: /* IRQ_RAWSTAT */
- case 8: /* FRQ_STATUS */
- case 9: /* FRQ_RAWSTAT */
- default:
- printf ("icp_pic_write: Bad register offset 0x%x\n", (int)offset);
- return;
- }
- icp_pic_update(s);
-}
-
-static const MemoryRegionOps icp_pic_ops = {
- .read = icp_pic_read,
- .write = icp_pic_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int icp_pic_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- icp_pic_state *s = INTEGRATOR_PIC(dev);
-
- qdev_init_gpio_in(dev, icp_pic_set_irq, 32);
- sysbus_init_irq(sbd, &s->parent_irq);
- sysbus_init_irq(sbd, &s->parent_fiq);
- memory_region_init_io(&s->iomem, OBJECT(s), &icp_pic_ops, s,
- "icp-pic", 0x00800000);
- sysbus_init_mmio(sbd, &s->iomem);
- return 0;
-}
-
-/* CP control registers. */
-
-#define TYPE_ICP_CONTROL_REGS "icp-ctrl-regs"
-#define ICP_CONTROL_REGS(obj) \
- OBJECT_CHECK(ICPCtrlRegsState, (obj), TYPE_ICP_CONTROL_REGS)
-
-typedef struct ICPCtrlRegsState {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- MemoryRegion iomem;
-
- qemu_irq mmc_irq;
- uint32_t intreg_state;
-} ICPCtrlRegsState;
-
-#define ICP_GPIO_MMC_WPROT "mmc-wprot"
-#define ICP_GPIO_MMC_CARDIN "mmc-cardin"
-
-#define ICP_INTREG_WPROT (1 << 0)
-#define ICP_INTREG_CARDIN (1 << 3)
-
-static uint64_t icp_control_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- ICPCtrlRegsState *s = opaque;
-
- switch (offset >> 2) {
- case 0: /* CP_IDFIELD */
- return 0x41034003;
- case 1: /* CP_FLASHPROG */
- return 0;
- case 2: /* CP_INTREG */
- return s->intreg_state;
- case 3: /* CP_DECODE */
- return 0x11;
- default:
- hw_error("icp_control_read: Bad offset %x\n", (int)offset);
- return 0;
- }
-}
-
-static void icp_control_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- ICPCtrlRegsState *s = opaque;
-
- switch (offset >> 2) {
- case 2: /* CP_INTREG */
- s->intreg_state &= ~(value & ICP_INTREG_CARDIN);
- qemu_set_irq(s->mmc_irq, !!(s->intreg_state & ICP_INTREG_CARDIN));
- break;
- case 1: /* CP_FLASHPROG */
- case 3: /* CP_DECODE */
- /* Nothing interesting implemented yet. */
- break;
- default:
- hw_error("icp_control_write: Bad offset %x\n", (int)offset);
- }
-}
-
-static const MemoryRegionOps icp_control_ops = {
- .read = icp_control_read,
- .write = icp_control_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void icp_control_mmc_wprot(void *opaque, int line, int level)
-{
- ICPCtrlRegsState *s = opaque;
-
- s->intreg_state &= ~ICP_INTREG_WPROT;
- if (level) {
- s->intreg_state |= ICP_INTREG_WPROT;
- }
-}
-
-static void icp_control_mmc_cardin(void *opaque, int line, int level)
-{
- ICPCtrlRegsState *s = opaque;
-
- /* line is released by writing to CP_INTREG */
- if (level) {
- s->intreg_state |= ICP_INTREG_CARDIN;
- qemu_set_irq(s->mmc_irq, 1);
- }
-}
-
-static void icp_control_init(Object *obj)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- ICPCtrlRegsState *s = ICP_CONTROL_REGS(obj);
- DeviceState *dev = DEVICE(obj);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &icp_control_ops, s,
- "icp_ctrl_regs", 0x00800000);
- sysbus_init_mmio(sbd, &s->iomem);
-
- qdev_init_gpio_in_named(dev, icp_control_mmc_wprot, ICP_GPIO_MMC_WPROT, 1);
- qdev_init_gpio_in_named(dev, icp_control_mmc_cardin,
- ICP_GPIO_MMC_CARDIN, 1);
- sysbus_init_irq(sbd, &s->mmc_irq);
-}
-
-
-/* Board init. */
-
-static struct arm_boot_info integrator_binfo = {
- .loader_start = 0x0,
- .board_id = 0x113,
-};
-
-static void integratorcp_init(MachineState *machine)
-{
- ram_addr_t ram_size = machine->ram_size;
- const char *cpu_model = machine->cpu_model;
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- const char *initrd_filename = machine->initrd_filename;
- ObjectClass *cpu_oc;
- Object *cpuobj;
- ARMCPU *cpu;
- MemoryRegion *address_space_mem = get_system_memory();
- MemoryRegion *ram = g_new(MemoryRegion, 1);
- MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
- qemu_irq pic[32];
- DeviceState *dev, *sic, *icp;
- int i;
-
- if (!cpu_model) {
- cpu_model = "arm926";
- }
-
- cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
- if (!cpu_oc) {
- fprintf(stderr, "Unable to find CPU definition\n");
- exit(1);
- }
-
- cpuobj = object_new(object_class_get_name(cpu_oc));
-
- /* By default ARM1176 CPUs have EL3 enabled. This board does not
- * currently support EL3 so the CPU EL3 property is disabled before
- * realization.
- */
- if (object_property_find(cpuobj, "has_el3", NULL)) {
- object_property_set_bool(cpuobj, false, "has_el3", &error_fatal);
- }
-
- object_property_set_bool(cpuobj, true, "realized", &error_fatal);
-
- cpu = ARM_CPU(cpuobj);
-
- memory_region_allocate_system_memory(ram, NULL, "integrator.ram",
- ram_size);
- /* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash. */
- /* ??? RAM should repeat to fill physical memory space. */
- /* SDRAM at address zero*/
- memory_region_add_subregion(address_space_mem, 0, ram);
- /* And again at address 0x80000000 */
- memory_region_init_alias(ram_alias, NULL, "ram.alias", ram, 0, ram_size);
- memory_region_add_subregion(address_space_mem, 0x80000000, ram_alias);
-
- dev = qdev_create(NULL, TYPE_INTEGRATOR_CM);
- qdev_prop_set_uint32(dev, "memsz", ram_size >> 20);
- qdev_init_nofail(dev);
- sysbus_mmio_map((SysBusDevice *)dev, 0, 0x10000000);
-
- dev = sysbus_create_varargs(TYPE_INTEGRATOR_PIC, 0x14000000,
- qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ),
- qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ),
- NULL);
- for (i = 0; i < 32; i++) {
- pic[i] = qdev_get_gpio_in(dev, i);
- }
- sic = sysbus_create_simple(TYPE_INTEGRATOR_PIC, 0xca000000, pic[26]);
- sysbus_create_varargs("integrator_pit", 0x13000000,
- pic[5], pic[6], pic[7], NULL);
- sysbus_create_simple("pl031", 0x15000000, pic[8]);
- sysbus_create_simple("pl011", 0x16000000, pic[1]);
- sysbus_create_simple("pl011", 0x17000000, pic[2]);
- icp = sysbus_create_simple(TYPE_ICP_CONTROL_REGS, 0xcb000000,
- qdev_get_gpio_in(sic, 3));
- sysbus_create_simple("pl050_keyboard", 0x18000000, pic[3]);
- sysbus_create_simple("pl050_mouse", 0x19000000, pic[4]);
- sysbus_create_simple(TYPE_INTEGRATOR_DEBUG, 0x1a000000, 0);
-
- dev = sysbus_create_varargs("pl181", 0x1c000000, pic[23], pic[24], NULL);
- qdev_connect_gpio_out(dev, 0,
- qdev_get_gpio_in_named(icp, ICP_GPIO_MMC_WPROT, 0));
- qdev_connect_gpio_out(dev, 1,
- qdev_get_gpio_in_named(icp, ICP_GPIO_MMC_CARDIN, 0));
-
- if (nd_table[0].used)
- smc91c111_init(&nd_table[0], 0xc8000000, pic[27]);
-
- sysbus_create_simple("pl110", 0xc0000000, pic[22]);
-
- integrator_binfo.ram_size = ram_size;
- integrator_binfo.kernel_filename = kernel_filename;
- integrator_binfo.kernel_cmdline = kernel_cmdline;
- integrator_binfo.initrd_filename = initrd_filename;
- arm_load_kernel(cpu, &integrator_binfo);
-}
-
-static void integratorcp_machine_init(MachineClass *mc)
-{
- mc->desc = "ARM Integrator/CP (ARM926EJ-S)";
- mc->init = integratorcp_init;
-}
-
-DEFINE_MACHINE("integratorcp", integratorcp_machine_init)
-
-static Property core_properties[] = {
- DEFINE_PROP_UINT32("memsz", IntegratorCMState, memsz, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void core_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = integratorcm_init;
- dc->props = core_properties;
-}
-
-static const TypeInfo core_info = {
- .name = TYPE_INTEGRATOR_CM,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(IntegratorCMState),
- .class_init = core_class_init,
-};
-
-static void icp_pic_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
- sdc->init = icp_pic_init;
-}
-
-static const TypeInfo icp_pic_info = {
- .name = TYPE_INTEGRATOR_PIC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(icp_pic_state),
- .class_init = icp_pic_class_init,
-};
-
-static const TypeInfo icp_ctrl_regs_info = {
- .name = TYPE_ICP_CONTROL_REGS,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(ICPCtrlRegsState),
- .instance_init = icp_control_init,
-};
-
-static void integratorcp_register_types(void)
-{
- type_register_static(&icp_pic_info);
- type_register_static(&core_info);
- type_register_static(&icp_ctrl_regs_info);
-}
-
-type_init(integratorcp_register_types)
diff --git a/qemu/hw/arm/kzm.c b/qemu/hw/arm/kzm.c
deleted file mode 100644
index 2c96ee33b..000000000
--- a/qemu/hw/arm/kzm.c
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * KZM Board System emulation.
- *
- * Copyright (c) 2008 OKL and 2011 NICTA
- * Written by Hans at OK-Labs
- * Updated by Peter Chubb.
- *
- * This code is licensed under the GPL, version 2 or later.
- * See the file `COPYING' in the top level directory.
- *
- * It (partially) emulates a Kyoto Microcomputer
- * KZM-ARM11-01 evaluation board, with a Freescale
- * i.MX31 SoC
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/arm/fsl-imx31.h"
-#include "hw/boards.h"
-#include "qemu/error-report.h"
-#include "exec/address-spaces.h"
-#include "net/net.h"
-#include "hw/devices.h"
-#include "hw/char/serial.h"
-#include "sysemu/qtest.h"
-
-/* Memory map for Kzm Emulation Baseboard:
- * 0x00000000-0x7fffffff See i.MX31 SOC for support
- * 0x80000000-0x8fffffff RAM EMULATED
- * 0x90000000-0x9fffffff RAM EMULATED
- * 0xa0000000-0xafffffff Flash IGNORED
- * 0xb0000000-0xb3ffffff Unavailable IGNORED
- * 0xb4000000-0xb4000fff 8-bit free space IGNORED
- * 0xb4001000-0xb400100f Board control IGNORED
- * 0xb4001003 DIP switch
- * 0xb4001010-0xb400101f 7-segment LED IGNORED
- * 0xb4001020-0xb400102f LED IGNORED
- * 0xb4001030-0xb400103f LED IGNORED
- * 0xb4001040-0xb400104f FPGA, UART EMULATED
- * 0xb4001050-0xb400105f FPGA, UART EMULATED
- * 0xb4001060-0xb40fffff FPGA IGNORED
- * 0xb6000000-0xb61fffff LAN controller EMULATED
- * 0xb6200000-0xb62fffff FPGA NAND Controller IGNORED
- * 0xb6300000-0xb7ffffff Free IGNORED
- * 0xb8000000-0xb8004fff Memory control registers IGNORED
- * 0xc0000000-0xc3ffffff PCMCIA/CF IGNORED
- * 0xc4000000-0xffffffff Reserved IGNORED
- */
-
-typedef struct IMX31KZM {
- FslIMX31State soc;
- MemoryRegion ram;
- MemoryRegion ram_alias;
-} IMX31KZM;
-
-#define KZM_RAM_ADDR (FSL_IMX31_SDRAM0_ADDR)
-#define KZM_FPGA_ADDR (FSL_IMX31_CS4_ADDR + 0x1040)
-#define KZM_LAN9118_ADDR (FSL_IMX31_CS5_ADDR)
-
-static struct arm_boot_info kzm_binfo = {
- .loader_start = KZM_RAM_ADDR,
- .board_id = 1722,
-};
-
-static void kzm_init(MachineState *machine)
-{
- IMX31KZM *s = g_new0(IMX31KZM, 1);
- unsigned int ram_size;
- unsigned int alias_offset;
- unsigned int i;
-
- object_initialize(&s->soc, sizeof(s->soc), TYPE_FSL_IMX31);
- object_property_add_child(OBJECT(machine), "soc", OBJECT(&s->soc),
- &error_abort);
-
- object_property_set_bool(OBJECT(&s->soc), true, "realized", &error_fatal);
-
- /* Check the amount of memory is compatible with the SOC */
- if (machine->ram_size > (FSL_IMX31_SDRAM0_SIZE + FSL_IMX31_SDRAM1_SIZE)) {
- error_report("WARNING: RAM size " RAM_ADDR_FMT " above max supported, "
- "reduced to %x", machine->ram_size,
- FSL_IMX31_SDRAM0_SIZE + FSL_IMX31_SDRAM1_SIZE);
- machine->ram_size = FSL_IMX31_SDRAM0_SIZE + FSL_IMX31_SDRAM1_SIZE;
- }
-
- memory_region_allocate_system_memory(&s->ram, NULL, "kzm.ram",
- machine->ram_size);
- memory_region_add_subregion(get_system_memory(), FSL_IMX31_SDRAM0_ADDR,
- &s->ram);
-
- /* initialize the alias memory if any */
- for (i = 0, ram_size = machine->ram_size, alias_offset = 0;
- (i < 2) && ram_size; i++) {
- unsigned int size;
- static const struct {
- hwaddr addr;
- unsigned int size;
- } ram[2] = {
- { FSL_IMX31_SDRAM0_ADDR, FSL_IMX31_SDRAM0_SIZE },
- { FSL_IMX31_SDRAM1_ADDR, FSL_IMX31_SDRAM1_SIZE },
- };
-
- size = MIN(ram_size, ram[i].size);
-
- ram_size -= size;
-
- if (size < ram[i].size) {
- memory_region_init_alias(&s->ram_alias, NULL, "ram.alias",
- &s->ram, alias_offset, ram[i].size - size);
- memory_region_add_subregion(get_system_memory(),
- ram[i].addr + size, &s->ram_alias);
- }
-
- alias_offset += ram[i].size;
- }
-
- if (nd_table[0].used) {
- lan9118_init(&nd_table[0], KZM_LAN9118_ADDR,
- qdev_get_gpio_in(DEVICE(&s->soc.avic), 52));
- }
-
- if (serial_hds[2]) { /* touchscreen */
- serial_mm_init(get_system_memory(), KZM_FPGA_ADDR+0x10, 0,
- qdev_get_gpio_in(DEVICE(&s->soc.avic), 52),
- 14745600, serial_hds[2], DEVICE_NATIVE_ENDIAN);
- }
-
- kzm_binfo.ram_size = machine->ram_size;
- kzm_binfo.kernel_filename = machine->kernel_filename;
- kzm_binfo.kernel_cmdline = machine->kernel_cmdline;
- kzm_binfo.initrd_filename = machine->initrd_filename;
- kzm_binfo.nb_cpus = 1;
-
- if (!qtest_enabled()) {
- arm_load_kernel(&s->soc.cpu, &kzm_binfo);
- }
-}
-
-static void kzm_machine_init(MachineClass *mc)
-{
- mc->desc = "ARM KZM Emulation Baseboard (ARM1136)";
- mc->init = kzm_init;
-}
-
-DEFINE_MACHINE("kzm", kzm_machine_init)
diff --git a/qemu/hw/arm/mainstone.c b/qemu/hw/arm/mainstone.c
deleted file mode 100644
index 454acc5d2..000000000
--- a/qemu/hw/arm/mainstone.c
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * PXA270-based Intel Mainstone platforms.
- *
- * Copyright (c) 2007 by Armin Kuster <akuster@kama-aina.net> or
- * <akuster@mvista.com>
- *
- * Code based on spitz platform by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/hw.h"
-#include "hw/arm/pxa.h"
-#include "hw/arm/arm.h"
-#include "net/net.h"
-#include "hw/devices.h"
-#include "hw/boards.h"
-#include "hw/block/flash.h"
-#include "sysemu/block-backend.h"
-#include "hw/sysbus.h"
-#include "exec/address-spaces.h"
-#include "sysemu/qtest.h"
-
-/* Device addresses */
-#define MST_FPGA_PHYS 0x08000000
-#define MST_ETH_PHYS 0x10000300
-#define MST_FLASH_0 0x00000000
-#define MST_FLASH_1 0x04000000
-
-/* IRQ definitions */
-#define MMC_IRQ 0
-#define USIM_IRQ 1
-#define USBC_IRQ 2
-#define ETHERNET_IRQ 3
-#define AC97_IRQ 4
-#define PEN_IRQ 5
-#define MSINS_IRQ 6
-#define EXBRD_IRQ 7
-#define S0_CD_IRQ 9
-#define S0_STSCHG_IRQ 10
-#define S0_IRQ 11
-#define S1_CD_IRQ 13
-#define S1_STSCHG_IRQ 14
-#define S1_IRQ 15
-
-static const struct keymap map[0xE0] = {
- [0 ... 0xDF] = { -1, -1 },
- [0x1e] = {0,0}, /* a */
- [0x30] = {0,1}, /* b */
- [0x2e] = {0,2}, /* c */
- [0x20] = {0,3}, /* d */
- [0x12] = {0,4}, /* e */
- [0x21] = {0,5}, /* f */
- [0x22] = {1,0}, /* g */
- [0x23] = {1,1}, /* h */
- [0x17] = {1,2}, /* i */
- [0x24] = {1,3}, /* j */
- [0x25] = {1,4}, /* k */
- [0x26] = {1,5}, /* l */
- [0x32] = {2,0}, /* m */
- [0x31] = {2,1}, /* n */
- [0x18] = {2,2}, /* o */
- [0x19] = {2,3}, /* p */
- [0x10] = {2,4}, /* q */
- [0x13] = {2,5}, /* r */
- [0x1f] = {3,0}, /* s */
- [0x14] = {3,1}, /* t */
- [0x16] = {3,2}, /* u */
- [0x2f] = {3,3}, /* v */
- [0x11] = {3,4}, /* w */
- [0x2d] = {3,5}, /* x */
- [0x15] = {4,2}, /* y */
- [0x2c] = {4,3}, /* z */
- [0xc7] = {5,0}, /* Home */
- [0x2a] = {5,1}, /* shift */
- /*
- * There are two matrix positions which map to space,
- * but QEMU can only use one of them for the reverse
- * mapping, so simply use the second one.
- */
- /* [0x39] = {5,2}, space */
- [0x39] = {5,3}, /* space */
- /*
- * Matrix position {5,4} and other keys are missing here.
- * TODO: Compare with Linux code and test real hardware.
- */
- [0x1c] = {5,5}, /* enter (TODO: might be wrong) */
- [0xc8] = {6,0}, /* up */
- [0xd0] = {6,1}, /* down */
- [0xcb] = {6,2}, /* left */
- [0xcd] = {6,3}, /* right */
-};
-
-enum mainstone_model_e { mainstone };
-
-#define MAINSTONE_RAM 0x04000000
-#define MAINSTONE_ROM 0x00800000
-#define MAINSTONE_FLASH 0x02000000
-
-static struct arm_boot_info mainstone_binfo = {
- .loader_start = PXA2XX_SDRAM_BASE,
- .ram_size = 0x04000000,
-};
-
-static void mainstone_common_init(MemoryRegion *address_space_mem,
- MachineState *machine,
- enum mainstone_model_e model, int arm_id)
-{
- uint32_t sector_len = 256 * 1024;
- hwaddr mainstone_flash_base[] = { MST_FLASH_0, MST_FLASH_1 };
- PXA2xxState *mpu;
- DeviceState *mst_irq;
- DriveInfo *dinfo;
- int i;
- int be;
- MemoryRegion *rom = g_new(MemoryRegion, 1);
- const char *cpu_model = machine->cpu_model;
-
- if (!cpu_model)
- cpu_model = "pxa270-c5";
-
- /* Setup CPU & memory */
- mpu = pxa270_init(address_space_mem, mainstone_binfo.ram_size, cpu_model);
- memory_region_init_ram(rom, NULL, "mainstone.rom", MAINSTONE_ROM,
- &error_fatal);
- vmstate_register_ram_global(rom);
- memory_region_set_readonly(rom, true);
- memory_region_add_subregion(address_space_mem, 0, rom);
-
-#ifdef TARGET_WORDS_BIGENDIAN
- be = 1;
-#else
- be = 0;
-#endif
- /* There are two 32MiB flash devices on the board */
- for (i = 0; i < 2; i ++) {
- dinfo = drive_get(IF_PFLASH, 0, i);
- if (!dinfo) {
- if (qtest_enabled()) {
- break;
- }
- fprintf(stderr, "Two flash images must be given with the "
- "'pflash' parameter\n");
- exit(1);
- }
-
- if (!pflash_cfi01_register(mainstone_flash_base[i], NULL,
- i ? "mainstone.flash1" : "mainstone.flash0",
- MAINSTONE_FLASH,
- blk_by_legacy_dinfo(dinfo),
- sector_len, MAINSTONE_FLASH / sector_len,
- 4, 0, 0, 0, 0, be)) {
- fprintf(stderr, "qemu: Error registering flash memory.\n");
- exit(1);
- }
- }
-
- mst_irq = sysbus_create_simple("mainstone-fpga", MST_FPGA_PHYS,
- qdev_get_gpio_in(mpu->gpio, 0));
-
- /* setup keypad */
- pxa27x_register_keypad(mpu->kp, map, 0xe0);
-
- /* MMC/SD host */
- pxa2xx_mmci_handlers(mpu->mmc, NULL, qdev_get_gpio_in(mst_irq, MMC_IRQ));
-
- pxa2xx_pcmcia_set_irq_cb(mpu->pcmcia[0],
- qdev_get_gpio_in(mst_irq, S0_IRQ),
- qdev_get_gpio_in(mst_irq, S0_CD_IRQ));
- pxa2xx_pcmcia_set_irq_cb(mpu->pcmcia[1],
- qdev_get_gpio_in(mst_irq, S1_IRQ),
- qdev_get_gpio_in(mst_irq, S1_CD_IRQ));
-
- smc91c111_init(&nd_table[0], MST_ETH_PHYS,
- qdev_get_gpio_in(mst_irq, ETHERNET_IRQ));
-
- mainstone_binfo.kernel_filename = machine->kernel_filename;
- mainstone_binfo.kernel_cmdline = machine->kernel_cmdline;
- mainstone_binfo.initrd_filename = machine->initrd_filename;
- mainstone_binfo.board_id = arm_id;
- arm_load_kernel(mpu->cpu, &mainstone_binfo);
-}
-
-static void mainstone_init(MachineState *machine)
-{
- mainstone_common_init(get_system_memory(), machine, mainstone, 0x196);
-}
-
-static void mainstone2_machine_init(MachineClass *mc)
-{
- mc->desc = "Mainstone II (PXA27x)";
- mc->init = mainstone_init;
-}
-
-DEFINE_MACHINE("mainstone", mainstone2_machine_init)
diff --git a/qemu/hw/arm/musicpal.c b/qemu/hw/arm/musicpal.c
deleted file mode 100644
index 7a4cc07dd..000000000
--- a/qemu/hw/arm/musicpal.c
+++ /dev/null
@@ -1,1751 +0,0 @@
-/*
- * Marvell MV88W8618 / Freecom MusicPal emulation.
- *
- * Copyright (c) 2008 Jan Kiszka
- *
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/sysbus.h"
-#include "hw/arm/arm.h"
-#include "hw/devices.h"
-#include "net/net.h"
-#include "sysemu/sysemu.h"
-#include "hw/boards.h"
-#include "hw/char/serial.h"
-#include "qemu/timer.h"
-#include "hw/ptimer.h"
-#include "hw/block/flash.h"
-#include "ui/console.h"
-#include "hw/i2c/i2c.h"
-#include "sysemu/block-backend.h"
-#include "exec/address-spaces.h"
-#include "ui/pixel_ops.h"
-
-#define MP_MISC_BASE 0x80002000
-#define MP_MISC_SIZE 0x00001000
-
-#define MP_ETH_BASE 0x80008000
-#define MP_ETH_SIZE 0x00001000
-
-#define MP_WLAN_BASE 0x8000C000
-#define MP_WLAN_SIZE 0x00000800
-
-#define MP_UART1_BASE 0x8000C840
-#define MP_UART2_BASE 0x8000C940
-
-#define MP_GPIO_BASE 0x8000D000
-#define MP_GPIO_SIZE 0x00001000
-
-#define MP_FLASHCFG_BASE 0x90006000
-#define MP_FLASHCFG_SIZE 0x00001000
-
-#define MP_AUDIO_BASE 0x90007000
-
-#define MP_PIC_BASE 0x90008000
-#define MP_PIC_SIZE 0x00001000
-
-#define MP_PIT_BASE 0x90009000
-#define MP_PIT_SIZE 0x00001000
-
-#define MP_LCD_BASE 0x9000c000
-#define MP_LCD_SIZE 0x00001000
-
-#define MP_SRAM_BASE 0xC0000000
-#define MP_SRAM_SIZE 0x00020000
-
-#define MP_RAM_DEFAULT_SIZE 32*1024*1024
-#define MP_FLASH_SIZE_MAX 32*1024*1024
-
-#define MP_TIMER1_IRQ 4
-#define MP_TIMER2_IRQ 5
-#define MP_TIMER3_IRQ 6
-#define MP_TIMER4_IRQ 7
-#define MP_EHCI_IRQ 8
-#define MP_ETH_IRQ 9
-#define MP_UART1_IRQ 11
-#define MP_UART2_IRQ 11
-#define MP_GPIO_IRQ 12
-#define MP_RTC_IRQ 28
-#define MP_AUDIO_IRQ 30
-
-/* Wolfson 8750 I2C address */
-#define MP_WM_ADDR 0x1A
-
-/* Ethernet register offsets */
-#define MP_ETH_SMIR 0x010
-#define MP_ETH_PCXR 0x408
-#define MP_ETH_SDCMR 0x448
-#define MP_ETH_ICR 0x450
-#define MP_ETH_IMR 0x458
-#define MP_ETH_FRDP0 0x480
-#define MP_ETH_FRDP1 0x484
-#define MP_ETH_FRDP2 0x488
-#define MP_ETH_FRDP3 0x48C
-#define MP_ETH_CRDP0 0x4A0
-#define MP_ETH_CRDP1 0x4A4
-#define MP_ETH_CRDP2 0x4A8
-#define MP_ETH_CRDP3 0x4AC
-#define MP_ETH_CTDP0 0x4E0
-#define MP_ETH_CTDP1 0x4E4
-
-/* MII PHY access */
-#define MP_ETH_SMIR_DATA 0x0000FFFF
-#define MP_ETH_SMIR_ADDR 0x03FF0000
-#define MP_ETH_SMIR_OPCODE (1 << 26) /* Read value */
-#define MP_ETH_SMIR_RDVALID (1 << 27)
-
-/* PHY registers */
-#define MP_ETH_PHY1_BMSR 0x00210000
-#define MP_ETH_PHY1_PHYSID1 0x00410000
-#define MP_ETH_PHY1_PHYSID2 0x00610000
-
-#define MP_PHY_BMSR_LINK 0x0004
-#define MP_PHY_BMSR_AUTONEG 0x0008
-
-#define MP_PHY_88E3015 0x01410E20
-
-/* TX descriptor status */
-#define MP_ETH_TX_OWN (1U << 31)
-
-/* RX descriptor status */
-#define MP_ETH_RX_OWN (1U << 31)
-
-/* Interrupt cause/mask bits */
-#define MP_ETH_IRQ_RX_BIT 0
-#define MP_ETH_IRQ_RX (1 << MP_ETH_IRQ_RX_BIT)
-#define MP_ETH_IRQ_TXHI_BIT 2
-#define MP_ETH_IRQ_TXLO_BIT 3
-
-/* Port config bits */
-#define MP_ETH_PCXR_2BSM_BIT 28 /* 2-byte incoming suffix */
-
-/* SDMA command bits */
-#define MP_ETH_CMD_TXHI (1 << 23)
-#define MP_ETH_CMD_TXLO (1 << 22)
-
-typedef struct mv88w8618_tx_desc {
- uint32_t cmdstat;
- uint16_t res;
- uint16_t bytes;
- uint32_t buffer;
- uint32_t next;
-} mv88w8618_tx_desc;
-
-typedef struct mv88w8618_rx_desc {
- uint32_t cmdstat;
- uint16_t bytes;
- uint16_t buffer_size;
- uint32_t buffer;
- uint32_t next;
-} mv88w8618_rx_desc;
-
-#define TYPE_MV88W8618_ETH "mv88w8618_eth"
-#define MV88W8618_ETH(obj) \
- OBJECT_CHECK(mv88w8618_eth_state, (obj), TYPE_MV88W8618_ETH)
-
-typedef struct mv88w8618_eth_state {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- MemoryRegion iomem;
- qemu_irq irq;
- uint32_t smir;
- uint32_t icr;
- uint32_t imr;
- int mmio_index;
- uint32_t vlan_header;
- uint32_t tx_queue[2];
- uint32_t rx_queue[4];
- uint32_t frx_queue[4];
- uint32_t cur_rx[4];
- NICState *nic;
- NICConf conf;
-} mv88w8618_eth_state;
-
-static void eth_rx_desc_put(uint32_t addr, mv88w8618_rx_desc *desc)
-{
- cpu_to_le32s(&desc->cmdstat);
- cpu_to_le16s(&desc->bytes);
- cpu_to_le16s(&desc->buffer_size);
- cpu_to_le32s(&desc->buffer);
- cpu_to_le32s(&desc->next);
- cpu_physical_memory_write(addr, desc, sizeof(*desc));
-}
-
-static void eth_rx_desc_get(uint32_t addr, mv88w8618_rx_desc *desc)
-{
- cpu_physical_memory_read(addr, desc, sizeof(*desc));
- le32_to_cpus(&desc->cmdstat);
- le16_to_cpus(&desc->bytes);
- le16_to_cpus(&desc->buffer_size);
- le32_to_cpus(&desc->buffer);
- le32_to_cpus(&desc->next);
-}
-
-static ssize_t eth_receive(NetClientState *nc, const uint8_t *buf, size_t size)
-{
- mv88w8618_eth_state *s = qemu_get_nic_opaque(nc);
- uint32_t desc_addr;
- mv88w8618_rx_desc desc;
- int i;
-
- for (i = 0; i < 4; i++) {
- desc_addr = s->cur_rx[i];
- if (!desc_addr) {
- continue;
- }
- do {
- eth_rx_desc_get(desc_addr, &desc);
- if ((desc.cmdstat & MP_ETH_RX_OWN) && desc.buffer_size >= size) {
- cpu_physical_memory_write(desc.buffer + s->vlan_header,
- buf, size);
- desc.bytes = size + s->vlan_header;
- desc.cmdstat &= ~MP_ETH_RX_OWN;
- s->cur_rx[i] = desc.next;
-
- s->icr |= MP_ETH_IRQ_RX;
- if (s->icr & s->imr) {
- qemu_irq_raise(s->irq);
- }
- eth_rx_desc_put(desc_addr, &desc);
- return size;
- }
- desc_addr = desc.next;
- } while (desc_addr != s->rx_queue[i]);
- }
- return size;
-}
-
-static void eth_tx_desc_put(uint32_t addr, mv88w8618_tx_desc *desc)
-{
- cpu_to_le32s(&desc->cmdstat);
- cpu_to_le16s(&desc->res);
- cpu_to_le16s(&desc->bytes);
- cpu_to_le32s(&desc->buffer);
- cpu_to_le32s(&desc->next);
- cpu_physical_memory_write(addr, desc, sizeof(*desc));
-}
-
-static void eth_tx_desc_get(uint32_t addr, mv88w8618_tx_desc *desc)
-{
- cpu_physical_memory_read(addr, desc, sizeof(*desc));
- le32_to_cpus(&desc->cmdstat);
- le16_to_cpus(&desc->res);
- le16_to_cpus(&desc->bytes);
- le32_to_cpus(&desc->buffer);
- le32_to_cpus(&desc->next);
-}
-
-static void eth_send(mv88w8618_eth_state *s, int queue_index)
-{
- uint32_t desc_addr = s->tx_queue[queue_index];
- mv88w8618_tx_desc desc;
- uint32_t next_desc;
- uint8_t buf[2048];
- int len;
-
- do {
- eth_tx_desc_get(desc_addr, &desc);
- next_desc = desc.next;
- if (desc.cmdstat & MP_ETH_TX_OWN) {
- len = desc.bytes;
- if (len < 2048) {
- cpu_physical_memory_read(desc.buffer, buf, len);
- qemu_send_packet(qemu_get_queue(s->nic), buf, len);
- }
- desc.cmdstat &= ~MP_ETH_TX_OWN;
- s->icr |= 1 << (MP_ETH_IRQ_TXLO_BIT - queue_index);
- eth_tx_desc_put(desc_addr, &desc);
- }
- desc_addr = next_desc;
- } while (desc_addr != s->tx_queue[queue_index]);
-}
-
-static uint64_t mv88w8618_eth_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- mv88w8618_eth_state *s = opaque;
-
- switch (offset) {
- case MP_ETH_SMIR:
- if (s->smir & MP_ETH_SMIR_OPCODE) {
- switch (s->smir & MP_ETH_SMIR_ADDR) {
- case MP_ETH_PHY1_BMSR:
- return MP_PHY_BMSR_LINK | MP_PHY_BMSR_AUTONEG |
- MP_ETH_SMIR_RDVALID;
- case MP_ETH_PHY1_PHYSID1:
- return (MP_PHY_88E3015 >> 16) | MP_ETH_SMIR_RDVALID;
- case MP_ETH_PHY1_PHYSID2:
- return (MP_PHY_88E3015 & 0xFFFF) | MP_ETH_SMIR_RDVALID;
- default:
- return MP_ETH_SMIR_RDVALID;
- }
- }
- return 0;
-
- case MP_ETH_ICR:
- return s->icr;
-
- case MP_ETH_IMR:
- return s->imr;
-
- case MP_ETH_FRDP0 ... MP_ETH_FRDP3:
- return s->frx_queue[(offset - MP_ETH_FRDP0)/4];
-
- case MP_ETH_CRDP0 ... MP_ETH_CRDP3:
- return s->rx_queue[(offset - MP_ETH_CRDP0)/4];
-
- case MP_ETH_CTDP0 ... MP_ETH_CTDP1:
- return s->tx_queue[(offset - MP_ETH_CTDP0)/4];
-
- default:
- return 0;
- }
-}
-
-static void mv88w8618_eth_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- mv88w8618_eth_state *s = opaque;
-
- switch (offset) {
- case MP_ETH_SMIR:
- s->smir = value;
- break;
-
- case MP_ETH_PCXR:
- s->vlan_header = ((value >> MP_ETH_PCXR_2BSM_BIT) & 1) * 2;
- break;
-
- case MP_ETH_SDCMR:
- if (value & MP_ETH_CMD_TXHI) {
- eth_send(s, 1);
- }
- if (value & MP_ETH_CMD_TXLO) {
- eth_send(s, 0);
- }
- if (value & (MP_ETH_CMD_TXHI | MP_ETH_CMD_TXLO) && s->icr & s->imr) {
- qemu_irq_raise(s->irq);
- }
- break;
-
- case MP_ETH_ICR:
- s->icr &= value;
- break;
-
- case MP_ETH_IMR:
- s->imr = value;
- if (s->icr & s->imr) {
- qemu_irq_raise(s->irq);
- }
- break;
-
- case MP_ETH_FRDP0 ... MP_ETH_FRDP3:
- s->frx_queue[(offset - MP_ETH_FRDP0)/4] = value;
- break;
-
- case MP_ETH_CRDP0 ... MP_ETH_CRDP3:
- s->rx_queue[(offset - MP_ETH_CRDP0)/4] =
- s->cur_rx[(offset - MP_ETH_CRDP0)/4] = value;
- break;
-
- case MP_ETH_CTDP0 ... MP_ETH_CTDP1:
- s->tx_queue[(offset - MP_ETH_CTDP0)/4] = value;
- break;
- }
-}
-
-static const MemoryRegionOps mv88w8618_eth_ops = {
- .read = mv88w8618_eth_read,
- .write = mv88w8618_eth_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void eth_cleanup(NetClientState *nc)
-{
- mv88w8618_eth_state *s = qemu_get_nic_opaque(nc);
-
- s->nic = NULL;
-}
-
-static NetClientInfo net_mv88w8618_info = {
- .type = NET_CLIENT_OPTIONS_KIND_NIC,
- .size = sizeof(NICState),
- .receive = eth_receive,
- .cleanup = eth_cleanup,
-};
-
-static int mv88w8618_eth_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- mv88w8618_eth_state *s = MV88W8618_ETH(dev);
-
- sysbus_init_irq(sbd, &s->irq);
- s->nic = qemu_new_nic(&net_mv88w8618_info, &s->conf,
- object_get_typename(OBJECT(dev)), dev->id, s);
- memory_region_init_io(&s->iomem, OBJECT(s), &mv88w8618_eth_ops, s,
- "mv88w8618-eth", MP_ETH_SIZE);
- sysbus_init_mmio(sbd, &s->iomem);
- return 0;
-}
-
-static const VMStateDescription mv88w8618_eth_vmsd = {
- .name = "mv88w8618_eth",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(smir, mv88w8618_eth_state),
- VMSTATE_UINT32(icr, mv88w8618_eth_state),
- VMSTATE_UINT32(imr, mv88w8618_eth_state),
- VMSTATE_UINT32(vlan_header, mv88w8618_eth_state),
- VMSTATE_UINT32_ARRAY(tx_queue, mv88w8618_eth_state, 2),
- VMSTATE_UINT32_ARRAY(rx_queue, mv88w8618_eth_state, 4),
- VMSTATE_UINT32_ARRAY(frx_queue, mv88w8618_eth_state, 4),
- VMSTATE_UINT32_ARRAY(cur_rx, mv88w8618_eth_state, 4),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property mv88w8618_eth_properties[] = {
- DEFINE_NIC_PROPERTIES(mv88w8618_eth_state, conf),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void mv88w8618_eth_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = mv88w8618_eth_init;
- dc->vmsd = &mv88w8618_eth_vmsd;
- dc->props = mv88w8618_eth_properties;
-}
-
-static const TypeInfo mv88w8618_eth_info = {
- .name = TYPE_MV88W8618_ETH,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(mv88w8618_eth_state),
- .class_init = mv88w8618_eth_class_init,
-};
-
-/* LCD register offsets */
-#define MP_LCD_IRQCTRL 0x180
-#define MP_LCD_IRQSTAT 0x184
-#define MP_LCD_SPICTRL 0x1ac
-#define MP_LCD_INST 0x1bc
-#define MP_LCD_DATA 0x1c0
-
-/* Mode magics */
-#define MP_LCD_SPI_DATA 0x00100011
-#define MP_LCD_SPI_CMD 0x00104011
-#define MP_LCD_SPI_INVALID 0x00000000
-
-/* Commmands */
-#define MP_LCD_INST_SETPAGE0 0xB0
-/* ... */
-#define MP_LCD_INST_SETPAGE7 0xB7
-
-#define MP_LCD_TEXTCOLOR 0xe0e0ff /* RRGGBB */
-
-#define TYPE_MUSICPAL_LCD "musicpal_lcd"
-#define MUSICPAL_LCD(obj) \
- OBJECT_CHECK(musicpal_lcd_state, (obj), TYPE_MUSICPAL_LCD)
-
-typedef struct musicpal_lcd_state {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- MemoryRegion iomem;
- uint32_t brightness;
- uint32_t mode;
- uint32_t irqctrl;
- uint32_t page;
- uint32_t page_off;
- QemuConsole *con;
- uint8_t video_ram[128*64/8];
-} musicpal_lcd_state;
-
-static uint8_t scale_lcd_color(musicpal_lcd_state *s, uint8_t col)
-{
- switch (s->brightness) {
- case 7:
- return col;
- case 0:
- return 0;
- default:
- return (col * s->brightness) / 7;
- }
-}
-
-#define SET_LCD_PIXEL(depth, type) \
-static inline void glue(set_lcd_pixel, depth) \
- (musicpal_lcd_state *s, int x, int y, type col) \
-{ \
- int dx, dy; \
- DisplaySurface *surface = qemu_console_surface(s->con); \
- type *pixel = &((type *) surface_data(surface))[(y * 128 * 3 + x) * 3]; \
-\
- for (dy = 0; dy < 3; dy++, pixel += 127 * 3) \
- for (dx = 0; dx < 3; dx++, pixel++) \
- *pixel = col; \
-}
-SET_LCD_PIXEL(8, uint8_t)
-SET_LCD_PIXEL(16, uint16_t)
-SET_LCD_PIXEL(32, uint32_t)
-
-static void lcd_refresh(void *opaque)
-{
- musicpal_lcd_state *s = opaque;
- DisplaySurface *surface = qemu_console_surface(s->con);
- int x, y, col;
-
- switch (surface_bits_per_pixel(surface)) {
- case 0:
- return;
-#define LCD_REFRESH(depth, func) \
- case depth: \
- col = func(scale_lcd_color(s, (MP_LCD_TEXTCOLOR >> 16) & 0xff), \
- scale_lcd_color(s, (MP_LCD_TEXTCOLOR >> 8) & 0xff), \
- scale_lcd_color(s, MP_LCD_TEXTCOLOR & 0xff)); \
- for (x = 0; x < 128; x++) { \
- for (y = 0; y < 64; y++) { \
- if (s->video_ram[x + (y/8)*128] & (1 << (y % 8))) { \
- glue(set_lcd_pixel, depth)(s, x, y, col); \
- } else { \
- glue(set_lcd_pixel, depth)(s, x, y, 0); \
- } \
- } \
- } \
- break;
- LCD_REFRESH(8, rgb_to_pixel8)
- LCD_REFRESH(16, rgb_to_pixel16)
- LCD_REFRESH(32, (is_surface_bgr(surface) ?
- rgb_to_pixel32bgr : rgb_to_pixel32))
- default:
- hw_error("unsupported colour depth %i\n",
- surface_bits_per_pixel(surface));
- }
-
- dpy_gfx_update(s->con, 0, 0, 128*3, 64*3);
-}
-
-static void lcd_invalidate(void *opaque)
-{
-}
-
-static void musicpal_lcd_gpio_brightness_in(void *opaque, int irq, int level)
-{
- musicpal_lcd_state *s = opaque;
- s->brightness &= ~(1 << irq);
- s->brightness |= level << irq;
-}
-
-static uint64_t musicpal_lcd_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- musicpal_lcd_state *s = opaque;
-
- switch (offset) {
- case MP_LCD_IRQCTRL:
- return s->irqctrl;
-
- default:
- return 0;
- }
-}
-
-static void musicpal_lcd_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- musicpal_lcd_state *s = opaque;
-
- switch (offset) {
- case MP_LCD_IRQCTRL:
- s->irqctrl = value;
- break;
-
- case MP_LCD_SPICTRL:
- if (value == MP_LCD_SPI_DATA || value == MP_LCD_SPI_CMD) {
- s->mode = value;
- } else {
- s->mode = MP_LCD_SPI_INVALID;
- }
- break;
-
- case MP_LCD_INST:
- if (value >= MP_LCD_INST_SETPAGE0 && value <= MP_LCD_INST_SETPAGE7) {
- s->page = value - MP_LCD_INST_SETPAGE0;
- s->page_off = 0;
- }
- break;
-
- case MP_LCD_DATA:
- if (s->mode == MP_LCD_SPI_CMD) {
- if (value >= MP_LCD_INST_SETPAGE0 &&
- value <= MP_LCD_INST_SETPAGE7) {
- s->page = value - MP_LCD_INST_SETPAGE0;
- s->page_off = 0;
- }
- } else if (s->mode == MP_LCD_SPI_DATA) {
- s->video_ram[s->page*128 + s->page_off] = value;
- s->page_off = (s->page_off + 1) & 127;
- }
- break;
- }
-}
-
-static const MemoryRegionOps musicpal_lcd_ops = {
- .read = musicpal_lcd_read,
- .write = musicpal_lcd_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const GraphicHwOps musicpal_gfx_ops = {
- .invalidate = lcd_invalidate,
- .gfx_update = lcd_refresh,
-};
-
-static int musicpal_lcd_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- musicpal_lcd_state *s = MUSICPAL_LCD(dev);
-
- s->brightness = 7;
-
- memory_region_init_io(&s->iomem, OBJECT(s), &musicpal_lcd_ops, s,
- "musicpal-lcd", MP_LCD_SIZE);
- sysbus_init_mmio(sbd, &s->iomem);
-
- s->con = graphic_console_init(dev, 0, &musicpal_gfx_ops, s);
- qemu_console_resize(s->con, 128*3, 64*3);
-
- qdev_init_gpio_in(dev, musicpal_lcd_gpio_brightness_in, 3);
-
- return 0;
-}
-
-static const VMStateDescription musicpal_lcd_vmsd = {
- .name = "musicpal_lcd",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(brightness, musicpal_lcd_state),
- VMSTATE_UINT32(mode, musicpal_lcd_state),
- VMSTATE_UINT32(irqctrl, musicpal_lcd_state),
- VMSTATE_UINT32(page, musicpal_lcd_state),
- VMSTATE_UINT32(page_off, musicpal_lcd_state),
- VMSTATE_BUFFER(video_ram, musicpal_lcd_state),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void musicpal_lcd_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = musicpal_lcd_init;
- dc->vmsd = &musicpal_lcd_vmsd;
-}
-
-static const TypeInfo musicpal_lcd_info = {
- .name = TYPE_MUSICPAL_LCD,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(musicpal_lcd_state),
- .class_init = musicpal_lcd_class_init,
-};
-
-/* PIC register offsets */
-#define MP_PIC_STATUS 0x00
-#define MP_PIC_ENABLE_SET 0x08
-#define MP_PIC_ENABLE_CLR 0x0C
-
-#define TYPE_MV88W8618_PIC "mv88w8618_pic"
-#define MV88W8618_PIC(obj) \
- OBJECT_CHECK(mv88w8618_pic_state, (obj), TYPE_MV88W8618_PIC)
-
-typedef struct mv88w8618_pic_state {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- MemoryRegion iomem;
- uint32_t level;
- uint32_t enabled;
- qemu_irq parent_irq;
-} mv88w8618_pic_state;
-
-static void mv88w8618_pic_update(mv88w8618_pic_state *s)
-{
- qemu_set_irq(s->parent_irq, (s->level & s->enabled));
-}
-
-static void mv88w8618_pic_set_irq(void *opaque, int irq, int level)
-{
- mv88w8618_pic_state *s = opaque;
-
- if (level) {
- s->level |= 1 << irq;
- } else {
- s->level &= ~(1 << irq);
- }
- mv88w8618_pic_update(s);
-}
-
-static uint64_t mv88w8618_pic_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- mv88w8618_pic_state *s = opaque;
-
- switch (offset) {
- case MP_PIC_STATUS:
- return s->level & s->enabled;
-
- default:
- return 0;
- }
-}
-
-static void mv88w8618_pic_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- mv88w8618_pic_state *s = opaque;
-
- switch (offset) {
- case MP_PIC_ENABLE_SET:
- s->enabled |= value;
- break;
-
- case MP_PIC_ENABLE_CLR:
- s->enabled &= ~value;
- s->level &= ~value;
- break;
- }
- mv88w8618_pic_update(s);
-}
-
-static void mv88w8618_pic_reset(DeviceState *d)
-{
- mv88w8618_pic_state *s = MV88W8618_PIC(d);
-
- s->level = 0;
- s->enabled = 0;
-}
-
-static const MemoryRegionOps mv88w8618_pic_ops = {
- .read = mv88w8618_pic_read,
- .write = mv88w8618_pic_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int mv88w8618_pic_init(SysBusDevice *dev)
-{
- mv88w8618_pic_state *s = MV88W8618_PIC(dev);
-
- qdev_init_gpio_in(DEVICE(dev), mv88w8618_pic_set_irq, 32);
- sysbus_init_irq(dev, &s->parent_irq);
- memory_region_init_io(&s->iomem, OBJECT(s), &mv88w8618_pic_ops, s,
- "musicpal-pic", MP_PIC_SIZE);
- sysbus_init_mmio(dev, &s->iomem);
- return 0;
-}
-
-static const VMStateDescription mv88w8618_pic_vmsd = {
- .name = "mv88w8618_pic",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(level, mv88w8618_pic_state),
- VMSTATE_UINT32(enabled, mv88w8618_pic_state),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void mv88w8618_pic_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = mv88w8618_pic_init;
- dc->reset = mv88w8618_pic_reset;
- dc->vmsd = &mv88w8618_pic_vmsd;
-}
-
-static const TypeInfo mv88w8618_pic_info = {
- .name = TYPE_MV88W8618_PIC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(mv88w8618_pic_state),
- .class_init = mv88w8618_pic_class_init,
-};
-
-/* PIT register offsets */
-#define MP_PIT_TIMER1_LENGTH 0x00
-/* ... */
-#define MP_PIT_TIMER4_LENGTH 0x0C
-#define MP_PIT_CONTROL 0x10
-#define MP_PIT_TIMER1_VALUE 0x14
-/* ... */
-#define MP_PIT_TIMER4_VALUE 0x20
-#define MP_BOARD_RESET 0x34
-
-/* Magic board reset value (probably some watchdog behind it) */
-#define MP_BOARD_RESET_MAGIC 0x10000
-
-typedef struct mv88w8618_timer_state {
- ptimer_state *ptimer;
- uint32_t limit;
- int freq;
- qemu_irq irq;
-} mv88w8618_timer_state;
-
-#define TYPE_MV88W8618_PIT "mv88w8618_pit"
-#define MV88W8618_PIT(obj) \
- OBJECT_CHECK(mv88w8618_pit_state, (obj), TYPE_MV88W8618_PIT)
-
-typedef struct mv88w8618_pit_state {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- MemoryRegion iomem;
- mv88w8618_timer_state timer[4];
-} mv88w8618_pit_state;
-
-static void mv88w8618_timer_tick(void *opaque)
-{
- mv88w8618_timer_state *s = opaque;
-
- qemu_irq_raise(s->irq);
-}
-
-static void mv88w8618_timer_init(SysBusDevice *dev, mv88w8618_timer_state *s,
- uint32_t freq)
-{
- QEMUBH *bh;
-
- sysbus_init_irq(dev, &s->irq);
- s->freq = freq;
-
- bh = qemu_bh_new(mv88w8618_timer_tick, s);
- s->ptimer = ptimer_init(bh);
-}
-
-static uint64_t mv88w8618_pit_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- mv88w8618_pit_state *s = opaque;
- mv88w8618_timer_state *t;
-
- switch (offset) {
- case MP_PIT_TIMER1_VALUE ... MP_PIT_TIMER4_VALUE:
- t = &s->timer[(offset-MP_PIT_TIMER1_VALUE) >> 2];
- return ptimer_get_count(t->ptimer);
-
- default:
- return 0;
- }
-}
-
-static void mv88w8618_pit_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- mv88w8618_pit_state *s = opaque;
- mv88w8618_timer_state *t;
- int i;
-
- switch (offset) {
- case MP_PIT_TIMER1_LENGTH ... MP_PIT_TIMER4_LENGTH:
- t = &s->timer[offset >> 2];
- t->limit = value;
- if (t->limit > 0) {
- ptimer_set_limit(t->ptimer, t->limit, 1);
- } else {
- ptimer_stop(t->ptimer);
- }
- break;
-
- case MP_PIT_CONTROL:
- for (i = 0; i < 4; i++) {
- t = &s->timer[i];
- if (value & 0xf && t->limit > 0) {
- ptimer_set_limit(t->ptimer, t->limit, 0);
- ptimer_set_freq(t->ptimer, t->freq);
- ptimer_run(t->ptimer, 0);
- } else {
- ptimer_stop(t->ptimer);
- }
- value >>= 4;
- }
- break;
-
- case MP_BOARD_RESET:
- if (value == MP_BOARD_RESET_MAGIC) {
- qemu_system_reset_request();
- }
- break;
- }
-}
-
-static void mv88w8618_pit_reset(DeviceState *d)
-{
- mv88w8618_pit_state *s = MV88W8618_PIT(d);
- int i;
-
- for (i = 0; i < 4; i++) {
- ptimer_stop(s->timer[i].ptimer);
- s->timer[i].limit = 0;
- }
-}
-
-static const MemoryRegionOps mv88w8618_pit_ops = {
- .read = mv88w8618_pit_read,
- .write = mv88w8618_pit_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int mv88w8618_pit_init(SysBusDevice *dev)
-{
- mv88w8618_pit_state *s = MV88W8618_PIT(dev);
- int i;
-
- /* Letting them all run at 1 MHz is likely just a pragmatic
- * simplification. */
- for (i = 0; i < 4; i++) {
- mv88w8618_timer_init(dev, &s->timer[i], 1000000);
- }
-
- memory_region_init_io(&s->iomem, OBJECT(s), &mv88w8618_pit_ops, s,
- "musicpal-pit", MP_PIT_SIZE);
- sysbus_init_mmio(dev, &s->iomem);
- return 0;
-}
-
-static const VMStateDescription mv88w8618_timer_vmsd = {
- .name = "timer",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_PTIMER(ptimer, mv88w8618_timer_state),
- VMSTATE_UINT32(limit, mv88w8618_timer_state),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription mv88w8618_pit_vmsd = {
- .name = "mv88w8618_pit",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT_ARRAY(timer, mv88w8618_pit_state, 4, 1,
- mv88w8618_timer_vmsd, mv88w8618_timer_state),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void mv88w8618_pit_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = mv88w8618_pit_init;
- dc->reset = mv88w8618_pit_reset;
- dc->vmsd = &mv88w8618_pit_vmsd;
-}
-
-static const TypeInfo mv88w8618_pit_info = {
- .name = TYPE_MV88W8618_PIT,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(mv88w8618_pit_state),
- .class_init = mv88w8618_pit_class_init,
-};
-
-/* Flash config register offsets */
-#define MP_FLASHCFG_CFGR0 0x04
-
-#define TYPE_MV88W8618_FLASHCFG "mv88w8618_flashcfg"
-#define MV88W8618_FLASHCFG(obj) \
- OBJECT_CHECK(mv88w8618_flashcfg_state, (obj), TYPE_MV88W8618_FLASHCFG)
-
-typedef struct mv88w8618_flashcfg_state {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- MemoryRegion iomem;
- uint32_t cfgr0;
-} mv88w8618_flashcfg_state;
-
-static uint64_t mv88w8618_flashcfg_read(void *opaque,
- hwaddr offset,
- unsigned size)
-{
- mv88w8618_flashcfg_state *s = opaque;
-
- switch (offset) {
- case MP_FLASHCFG_CFGR0:
- return s->cfgr0;
-
- default:
- return 0;
- }
-}
-
-static void mv88w8618_flashcfg_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- mv88w8618_flashcfg_state *s = opaque;
-
- switch (offset) {
- case MP_FLASHCFG_CFGR0:
- s->cfgr0 = value;
- break;
- }
-}
-
-static const MemoryRegionOps mv88w8618_flashcfg_ops = {
- .read = mv88w8618_flashcfg_read,
- .write = mv88w8618_flashcfg_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int mv88w8618_flashcfg_init(SysBusDevice *dev)
-{
- mv88w8618_flashcfg_state *s = MV88W8618_FLASHCFG(dev);
-
- s->cfgr0 = 0xfffe4285; /* Default as set by U-Boot for 8 MB flash */
- memory_region_init_io(&s->iomem, OBJECT(s), &mv88w8618_flashcfg_ops, s,
- "musicpal-flashcfg", MP_FLASHCFG_SIZE);
- sysbus_init_mmio(dev, &s->iomem);
- return 0;
-}
-
-static const VMStateDescription mv88w8618_flashcfg_vmsd = {
- .name = "mv88w8618_flashcfg",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(cfgr0, mv88w8618_flashcfg_state),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void mv88w8618_flashcfg_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = mv88w8618_flashcfg_init;
- dc->vmsd = &mv88w8618_flashcfg_vmsd;
-}
-
-static const TypeInfo mv88w8618_flashcfg_info = {
- .name = TYPE_MV88W8618_FLASHCFG,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(mv88w8618_flashcfg_state),
- .class_init = mv88w8618_flashcfg_class_init,
-};
-
-/* Misc register offsets */
-#define MP_MISC_BOARD_REVISION 0x18
-
-#define MP_BOARD_REVISION 0x31
-
-typedef struct {
- SysBusDevice parent_obj;
- MemoryRegion iomem;
-} MusicPalMiscState;
-
-#define TYPE_MUSICPAL_MISC "musicpal-misc"
-#define MUSICPAL_MISC(obj) \
- OBJECT_CHECK(MusicPalMiscState, (obj), TYPE_MUSICPAL_MISC)
-
-static uint64_t musicpal_misc_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- switch (offset) {
- case MP_MISC_BOARD_REVISION:
- return MP_BOARD_REVISION;
-
- default:
- return 0;
- }
-}
-
-static void musicpal_misc_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
-}
-
-static const MemoryRegionOps musicpal_misc_ops = {
- .read = musicpal_misc_read,
- .write = musicpal_misc_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void musicpal_misc_init(Object *obj)
-{
- SysBusDevice *sd = SYS_BUS_DEVICE(obj);
- MusicPalMiscState *s = MUSICPAL_MISC(obj);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &musicpal_misc_ops, NULL,
- "musicpal-misc", MP_MISC_SIZE);
- sysbus_init_mmio(sd, &s->iomem);
-}
-
-static const TypeInfo musicpal_misc_info = {
- .name = TYPE_MUSICPAL_MISC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_init = musicpal_misc_init,
- .instance_size = sizeof(MusicPalMiscState),
-};
-
-/* WLAN register offsets */
-#define MP_WLAN_MAGIC1 0x11c
-#define MP_WLAN_MAGIC2 0x124
-
-static uint64_t mv88w8618_wlan_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- switch (offset) {
- /* Workaround to allow loading the binary-only wlandrv.ko crap
- * from the original Freecom firmware. */
- case MP_WLAN_MAGIC1:
- return ~3;
- case MP_WLAN_MAGIC2:
- return -1;
-
- default:
- return 0;
- }
-}
-
-static void mv88w8618_wlan_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
-}
-
-static const MemoryRegionOps mv88w8618_wlan_ops = {
- .read = mv88w8618_wlan_read,
- .write =mv88w8618_wlan_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int mv88w8618_wlan_init(SysBusDevice *dev)
-{
- MemoryRegion *iomem = g_new(MemoryRegion, 1);
-
- memory_region_init_io(iomem, OBJECT(dev), &mv88w8618_wlan_ops, NULL,
- "musicpal-wlan", MP_WLAN_SIZE);
- sysbus_init_mmio(dev, iomem);
- return 0;
-}
-
-/* GPIO register offsets */
-#define MP_GPIO_OE_LO 0x008
-#define MP_GPIO_OUT_LO 0x00c
-#define MP_GPIO_IN_LO 0x010
-#define MP_GPIO_IER_LO 0x014
-#define MP_GPIO_IMR_LO 0x018
-#define MP_GPIO_ISR_LO 0x020
-#define MP_GPIO_OE_HI 0x508
-#define MP_GPIO_OUT_HI 0x50c
-#define MP_GPIO_IN_HI 0x510
-#define MP_GPIO_IER_HI 0x514
-#define MP_GPIO_IMR_HI 0x518
-#define MP_GPIO_ISR_HI 0x520
-
-/* GPIO bits & masks */
-#define MP_GPIO_LCD_BRIGHTNESS 0x00070000
-#define MP_GPIO_I2C_DATA_BIT 29
-#define MP_GPIO_I2C_CLOCK_BIT 30
-
-/* LCD brightness bits in GPIO_OE_HI */
-#define MP_OE_LCD_BRIGHTNESS 0x0007
-
-#define TYPE_MUSICPAL_GPIO "musicpal_gpio"
-#define MUSICPAL_GPIO(obj) \
- OBJECT_CHECK(musicpal_gpio_state, (obj), TYPE_MUSICPAL_GPIO)
-
-typedef struct musicpal_gpio_state {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- MemoryRegion iomem;
- uint32_t lcd_brightness;
- uint32_t out_state;
- uint32_t in_state;
- uint32_t ier;
- uint32_t imr;
- uint32_t isr;
- qemu_irq irq;
- qemu_irq out[5]; /* 3 brightness out + 2 lcd (data and clock ) */
-} musicpal_gpio_state;
-
-static void musicpal_gpio_brightness_update(musicpal_gpio_state *s) {
- int i;
- uint32_t brightness;
-
- /* compute brightness ratio */
- switch (s->lcd_brightness) {
- case 0x00000007:
- brightness = 0;
- break;
-
- case 0x00020000:
- brightness = 1;
- break;
-
- case 0x00020001:
- brightness = 2;
- break;
-
- case 0x00040000:
- brightness = 3;
- break;
-
- case 0x00010006:
- brightness = 4;
- break;
-
- case 0x00020005:
- brightness = 5;
- break;
-
- case 0x00040003:
- brightness = 6;
- break;
-
- case 0x00030004:
- default:
- brightness = 7;
- }
-
- /* set lcd brightness GPIOs */
- for (i = 0; i <= 2; i++) {
- qemu_set_irq(s->out[i], (brightness >> i) & 1);
- }
-}
-
-static void musicpal_gpio_pin_event(void *opaque, int pin, int level)
-{
- musicpal_gpio_state *s = opaque;
- uint32_t mask = 1 << pin;
- uint32_t delta = level << pin;
- uint32_t old = s->in_state & mask;
-
- s->in_state &= ~mask;
- s->in_state |= delta;
-
- if ((old ^ delta) &&
- ((level && (s->imr & mask)) || (!level && (s->ier & mask)))) {
- s->isr = mask;
- qemu_irq_raise(s->irq);
- }
-}
-
-static uint64_t musicpal_gpio_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- musicpal_gpio_state *s = opaque;
-
- switch (offset) {
- case MP_GPIO_OE_HI: /* used for LCD brightness control */
- return s->lcd_brightness & MP_OE_LCD_BRIGHTNESS;
-
- case MP_GPIO_OUT_LO:
- return s->out_state & 0xFFFF;
- case MP_GPIO_OUT_HI:
- return s->out_state >> 16;
-
- case MP_GPIO_IN_LO:
- return s->in_state & 0xFFFF;
- case MP_GPIO_IN_HI:
- return s->in_state >> 16;
-
- case MP_GPIO_IER_LO:
- return s->ier & 0xFFFF;
- case MP_GPIO_IER_HI:
- return s->ier >> 16;
-
- case MP_GPIO_IMR_LO:
- return s->imr & 0xFFFF;
- case MP_GPIO_IMR_HI:
- return s->imr >> 16;
-
- case MP_GPIO_ISR_LO:
- return s->isr & 0xFFFF;
- case MP_GPIO_ISR_HI:
- return s->isr >> 16;
-
- default:
- return 0;
- }
-}
-
-static void musicpal_gpio_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- musicpal_gpio_state *s = opaque;
- switch (offset) {
- case MP_GPIO_OE_HI: /* used for LCD brightness control */
- s->lcd_brightness = (s->lcd_brightness & MP_GPIO_LCD_BRIGHTNESS) |
- (value & MP_OE_LCD_BRIGHTNESS);
- musicpal_gpio_brightness_update(s);
- break;
-
- case MP_GPIO_OUT_LO:
- s->out_state = (s->out_state & 0xFFFF0000) | (value & 0xFFFF);
- break;
- case MP_GPIO_OUT_HI:
- s->out_state = (s->out_state & 0xFFFF) | (value << 16);
- s->lcd_brightness = (s->lcd_brightness & 0xFFFF) |
- (s->out_state & MP_GPIO_LCD_BRIGHTNESS);
- musicpal_gpio_brightness_update(s);
- qemu_set_irq(s->out[3], (s->out_state >> MP_GPIO_I2C_DATA_BIT) & 1);
- qemu_set_irq(s->out[4], (s->out_state >> MP_GPIO_I2C_CLOCK_BIT) & 1);
- break;
-
- case MP_GPIO_IER_LO:
- s->ier = (s->ier & 0xFFFF0000) | (value & 0xFFFF);
- break;
- case MP_GPIO_IER_HI:
- s->ier = (s->ier & 0xFFFF) | (value << 16);
- break;
-
- case MP_GPIO_IMR_LO:
- s->imr = (s->imr & 0xFFFF0000) | (value & 0xFFFF);
- break;
- case MP_GPIO_IMR_HI:
- s->imr = (s->imr & 0xFFFF) | (value << 16);
- break;
- }
-}
-
-static const MemoryRegionOps musicpal_gpio_ops = {
- .read = musicpal_gpio_read,
- .write = musicpal_gpio_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void musicpal_gpio_reset(DeviceState *d)
-{
- musicpal_gpio_state *s = MUSICPAL_GPIO(d);
-
- s->lcd_brightness = 0;
- s->out_state = 0;
- s->in_state = 0xffffffff;
- s->ier = 0;
- s->imr = 0;
- s->isr = 0;
-}
-
-static int musicpal_gpio_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- musicpal_gpio_state *s = MUSICPAL_GPIO(dev);
-
- sysbus_init_irq(sbd, &s->irq);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &musicpal_gpio_ops, s,
- "musicpal-gpio", MP_GPIO_SIZE);
- sysbus_init_mmio(sbd, &s->iomem);
-
- qdev_init_gpio_out(dev, s->out, ARRAY_SIZE(s->out));
-
- qdev_init_gpio_in(dev, musicpal_gpio_pin_event, 32);
-
- return 0;
-}
-
-static const VMStateDescription musicpal_gpio_vmsd = {
- .name = "musicpal_gpio",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(lcd_brightness, musicpal_gpio_state),
- VMSTATE_UINT32(out_state, musicpal_gpio_state),
- VMSTATE_UINT32(in_state, musicpal_gpio_state),
- VMSTATE_UINT32(ier, musicpal_gpio_state),
- VMSTATE_UINT32(imr, musicpal_gpio_state),
- VMSTATE_UINT32(isr, musicpal_gpio_state),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void musicpal_gpio_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = musicpal_gpio_init;
- dc->reset = musicpal_gpio_reset;
- dc->vmsd = &musicpal_gpio_vmsd;
-}
-
-static const TypeInfo musicpal_gpio_info = {
- .name = TYPE_MUSICPAL_GPIO,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(musicpal_gpio_state),
- .class_init = musicpal_gpio_class_init,
-};
-
-/* Keyboard codes & masks */
-#define KEY_RELEASED 0x80
-#define KEY_CODE 0x7f
-
-#define KEYCODE_TAB 0x0f
-#define KEYCODE_ENTER 0x1c
-#define KEYCODE_F 0x21
-#define KEYCODE_M 0x32
-
-#define KEYCODE_EXTENDED 0xe0
-#define KEYCODE_UP 0x48
-#define KEYCODE_DOWN 0x50
-#define KEYCODE_LEFT 0x4b
-#define KEYCODE_RIGHT 0x4d
-
-#define MP_KEY_WHEEL_VOL (1 << 0)
-#define MP_KEY_WHEEL_VOL_INV (1 << 1)
-#define MP_KEY_WHEEL_NAV (1 << 2)
-#define MP_KEY_WHEEL_NAV_INV (1 << 3)
-#define MP_KEY_BTN_FAVORITS (1 << 4)
-#define MP_KEY_BTN_MENU (1 << 5)
-#define MP_KEY_BTN_VOLUME (1 << 6)
-#define MP_KEY_BTN_NAVIGATION (1 << 7)
-
-#define TYPE_MUSICPAL_KEY "musicpal_key"
-#define MUSICPAL_KEY(obj) \
- OBJECT_CHECK(musicpal_key_state, (obj), TYPE_MUSICPAL_KEY)
-
-typedef struct musicpal_key_state {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- MemoryRegion iomem;
- uint32_t kbd_extended;
- uint32_t pressed_keys;
- qemu_irq out[8];
-} musicpal_key_state;
-
-static void musicpal_key_event(void *opaque, int keycode)
-{
- musicpal_key_state *s = opaque;
- uint32_t event = 0;
- int i;
-
- if (keycode == KEYCODE_EXTENDED) {
- s->kbd_extended = 1;
- return;
- }
-
- if (s->kbd_extended) {
- switch (keycode & KEY_CODE) {
- case KEYCODE_UP:
- event = MP_KEY_WHEEL_NAV | MP_KEY_WHEEL_NAV_INV;
- break;
-
- case KEYCODE_DOWN:
- event = MP_KEY_WHEEL_NAV;
- break;
-
- case KEYCODE_LEFT:
- event = MP_KEY_WHEEL_VOL | MP_KEY_WHEEL_VOL_INV;
- break;
-
- case KEYCODE_RIGHT:
- event = MP_KEY_WHEEL_VOL;
- break;
- }
- } else {
- switch (keycode & KEY_CODE) {
- case KEYCODE_F:
- event = MP_KEY_BTN_FAVORITS;
- break;
-
- case KEYCODE_TAB:
- event = MP_KEY_BTN_VOLUME;
- break;
-
- case KEYCODE_ENTER:
- event = MP_KEY_BTN_NAVIGATION;
- break;
-
- case KEYCODE_M:
- event = MP_KEY_BTN_MENU;
- break;
- }
- /* Do not repeat already pressed buttons */
- if (!(keycode & KEY_RELEASED) && (s->pressed_keys & event)) {
- event = 0;
- }
- }
-
- if (event) {
- /* Raise GPIO pin first if repeating a key */
- if (!(keycode & KEY_RELEASED) && (s->pressed_keys & event)) {
- for (i = 0; i <= 7; i++) {
- if (event & (1 << i)) {
- qemu_set_irq(s->out[i], 1);
- }
- }
- }
- for (i = 0; i <= 7; i++) {
- if (event & (1 << i)) {
- qemu_set_irq(s->out[i], !!(keycode & KEY_RELEASED));
- }
- }
- if (keycode & KEY_RELEASED) {
- s->pressed_keys &= ~event;
- } else {
- s->pressed_keys |= event;
- }
- }
-
- s->kbd_extended = 0;
-}
-
-static int musicpal_key_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- musicpal_key_state *s = MUSICPAL_KEY(dev);
-
- memory_region_init(&s->iomem, OBJECT(s), "dummy", 0);
- sysbus_init_mmio(sbd, &s->iomem);
-
- s->kbd_extended = 0;
- s->pressed_keys = 0;
-
- qdev_init_gpio_out(dev, s->out, ARRAY_SIZE(s->out));
-
- qemu_add_kbd_event_handler(musicpal_key_event, s);
-
- return 0;
-}
-
-static const VMStateDescription musicpal_key_vmsd = {
- .name = "musicpal_key",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(kbd_extended, musicpal_key_state),
- VMSTATE_UINT32(pressed_keys, musicpal_key_state),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void musicpal_key_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = musicpal_key_init;
- dc->vmsd = &musicpal_key_vmsd;
-}
-
-static const TypeInfo musicpal_key_info = {
- .name = TYPE_MUSICPAL_KEY,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(musicpal_key_state),
- .class_init = musicpal_key_class_init,
-};
-
-static struct arm_boot_info musicpal_binfo = {
- .loader_start = 0x0,
- .board_id = 0x20e,
-};
-
-static void musicpal_init(MachineState *machine)
-{
- const char *cpu_model = machine->cpu_model;
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- const char *initrd_filename = machine->initrd_filename;
- ARMCPU *cpu;
- qemu_irq pic[32];
- DeviceState *dev;
- DeviceState *i2c_dev;
- DeviceState *lcd_dev;
- DeviceState *key_dev;
- DeviceState *wm8750_dev;
- SysBusDevice *s;
- I2CBus *i2c;
- int i;
- unsigned long flash_size;
- DriveInfo *dinfo;
- MemoryRegion *address_space_mem = get_system_memory();
- MemoryRegion *ram = g_new(MemoryRegion, 1);
- MemoryRegion *sram = g_new(MemoryRegion, 1);
-
- if (!cpu_model) {
- cpu_model = "arm926";
- }
- cpu = cpu_arm_init(cpu_model);
- if (!cpu) {
- fprintf(stderr, "Unable to find CPU definition\n");
- exit(1);
- }
-
- /* For now we use a fixed - the original - RAM size */
- memory_region_allocate_system_memory(ram, NULL, "musicpal.ram",
- MP_RAM_DEFAULT_SIZE);
- memory_region_add_subregion(address_space_mem, 0, ram);
-
- memory_region_init_ram(sram, NULL, "musicpal.sram", MP_SRAM_SIZE,
- &error_fatal);
- vmstate_register_ram_global(sram);
- memory_region_add_subregion(address_space_mem, MP_SRAM_BASE, sram);
-
- dev = sysbus_create_simple(TYPE_MV88W8618_PIC, MP_PIC_BASE,
- qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ));
- for (i = 0; i < 32; i++) {
- pic[i] = qdev_get_gpio_in(dev, i);
- }
- sysbus_create_varargs(TYPE_MV88W8618_PIT, MP_PIT_BASE, pic[MP_TIMER1_IRQ],
- pic[MP_TIMER2_IRQ], pic[MP_TIMER3_IRQ],
- pic[MP_TIMER4_IRQ], NULL);
-
- if (serial_hds[0]) {
- serial_mm_init(address_space_mem, MP_UART1_BASE, 2, pic[MP_UART1_IRQ],
- 1825000, serial_hds[0], DEVICE_NATIVE_ENDIAN);
- }
- if (serial_hds[1]) {
- serial_mm_init(address_space_mem, MP_UART2_BASE, 2, pic[MP_UART2_IRQ],
- 1825000, serial_hds[1], DEVICE_NATIVE_ENDIAN);
- }
-
- /* Register flash */
- dinfo = drive_get(IF_PFLASH, 0, 0);
- if (dinfo) {
- BlockBackend *blk = blk_by_legacy_dinfo(dinfo);
-
- flash_size = blk_getlength(blk);
- if (flash_size != 8*1024*1024 && flash_size != 16*1024*1024 &&
- flash_size != 32*1024*1024) {
- fprintf(stderr, "Invalid flash image size\n");
- exit(1);
- }
-
- /*
- * The original U-Boot accesses the flash at 0xFE000000 instead of
- * 0xFF800000 (if there is 8 MB flash). So remap flash access if the
- * image is smaller than 32 MB.
- */
-#ifdef TARGET_WORDS_BIGENDIAN
- pflash_cfi02_register(0x100000000ULL-MP_FLASH_SIZE_MAX, NULL,
- "musicpal.flash", flash_size,
- blk, 0x10000, (flash_size + 0xffff) >> 16,
- MP_FLASH_SIZE_MAX / flash_size,
- 2, 0x00BF, 0x236D, 0x0000, 0x0000,
- 0x5555, 0x2AAA, 1);
-#else
- pflash_cfi02_register(0x100000000ULL-MP_FLASH_SIZE_MAX, NULL,
- "musicpal.flash", flash_size,
- blk, 0x10000, (flash_size + 0xffff) >> 16,
- MP_FLASH_SIZE_MAX / flash_size,
- 2, 0x00BF, 0x236D, 0x0000, 0x0000,
- 0x5555, 0x2AAA, 0);
-#endif
-
- }
- sysbus_create_simple(TYPE_MV88W8618_FLASHCFG, MP_FLASHCFG_BASE, NULL);
-
- qemu_check_nic_model(&nd_table[0], "mv88w8618");
- dev = qdev_create(NULL, TYPE_MV88W8618_ETH);
- qdev_set_nic_properties(dev, &nd_table[0]);
- qdev_init_nofail(dev);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, MP_ETH_BASE);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[MP_ETH_IRQ]);
-
- sysbus_create_simple("mv88w8618_wlan", MP_WLAN_BASE, NULL);
-
- sysbus_create_simple(TYPE_MUSICPAL_MISC, MP_MISC_BASE, NULL);
-
- dev = sysbus_create_simple(TYPE_MUSICPAL_GPIO, MP_GPIO_BASE,
- pic[MP_GPIO_IRQ]);
- i2c_dev = sysbus_create_simple("gpio_i2c", -1, NULL);
- i2c = (I2CBus *)qdev_get_child_bus(i2c_dev, "i2c");
-
- lcd_dev = sysbus_create_simple(TYPE_MUSICPAL_LCD, MP_LCD_BASE, NULL);
- key_dev = sysbus_create_simple(TYPE_MUSICPAL_KEY, -1, NULL);
-
- /* I2C read data */
- qdev_connect_gpio_out(i2c_dev, 0,
- qdev_get_gpio_in(dev, MP_GPIO_I2C_DATA_BIT));
- /* I2C data */
- qdev_connect_gpio_out(dev, 3, qdev_get_gpio_in(i2c_dev, 0));
- /* I2C clock */
- qdev_connect_gpio_out(dev, 4, qdev_get_gpio_in(i2c_dev, 1));
-
- for (i = 0; i < 3; i++) {
- qdev_connect_gpio_out(dev, i, qdev_get_gpio_in(lcd_dev, i));
- }
- for (i = 0; i < 4; i++) {
- qdev_connect_gpio_out(key_dev, i, qdev_get_gpio_in(dev, i + 8));
- }
- for (i = 4; i < 8; i++) {
- qdev_connect_gpio_out(key_dev, i, qdev_get_gpio_in(dev, i + 15));
- }
-
- wm8750_dev = i2c_create_slave(i2c, "wm8750", MP_WM_ADDR);
- dev = qdev_create(NULL, "mv88w8618_audio");
- s = SYS_BUS_DEVICE(dev);
- qdev_prop_set_ptr(dev, "wm8750", wm8750_dev);
- qdev_init_nofail(dev);
- sysbus_mmio_map(s, 0, MP_AUDIO_BASE);
- sysbus_connect_irq(s, 0, pic[MP_AUDIO_IRQ]);
-
- musicpal_binfo.ram_size = MP_RAM_DEFAULT_SIZE;
- musicpal_binfo.kernel_filename = kernel_filename;
- musicpal_binfo.kernel_cmdline = kernel_cmdline;
- musicpal_binfo.initrd_filename = initrd_filename;
- arm_load_kernel(cpu, &musicpal_binfo);
-}
-
-static void musicpal_machine_init(MachineClass *mc)
-{
- mc->desc = "Marvell 88w8618 / MusicPal (ARM926EJ-S)";
- mc->init = musicpal_init;
-}
-
-DEFINE_MACHINE("musicpal", musicpal_machine_init)
-
-static void mv88w8618_wlan_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
- sdc->init = mv88w8618_wlan_init;
-}
-
-static const TypeInfo mv88w8618_wlan_info = {
- .name = "mv88w8618_wlan",
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(SysBusDevice),
- .class_init = mv88w8618_wlan_class_init,
-};
-
-static void musicpal_register_types(void)
-{
- type_register_static(&mv88w8618_pic_info);
- type_register_static(&mv88w8618_pit_info);
- type_register_static(&mv88w8618_flashcfg_info);
- type_register_static(&mv88w8618_eth_info);
- type_register_static(&mv88w8618_wlan_info);
- type_register_static(&musicpal_lcd_info);
- type_register_static(&musicpal_gpio_info);
- type_register_static(&musicpal_key_info);
- type_register_static(&musicpal_misc_info);
-}
-
-type_init(musicpal_register_types)
diff --git a/qemu/hw/arm/netduino2.c b/qemu/hw/arm/netduino2.c
deleted file mode 100644
index 23d792837..000000000
--- a/qemu/hw/arm/netduino2.c
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Netduino 2 Machine Model
- *
- * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/boards.h"
-#include "qemu/error-report.h"
-#include "hw/arm/stm32f205_soc.h"
-
-static void netduino2_init(MachineState *machine)
-{
- DeviceState *dev;
-
- dev = qdev_create(NULL, TYPE_STM32F205_SOC);
- if (machine->kernel_filename) {
- qdev_prop_set_string(dev, "kernel-filename", machine->kernel_filename);
- }
- qdev_prop_set_string(dev, "cpu-model", "cortex-m3");
- object_property_set_bool(OBJECT(dev), true, "realized", &error_fatal);
-}
-
-static void netduino2_machine_init(MachineClass *mc)
-{
- mc->desc = "Netduino 2 Machine";
- mc->init = netduino2_init;
-}
-
-DEFINE_MACHINE("netduino2", netduino2_machine_init)
diff --git a/qemu/hw/arm/nseries.c b/qemu/hw/arm/nseries.c
deleted file mode 100644
index 538250555..000000000
--- a/qemu/hw/arm/nseries.c
+++ /dev/null
@@ -1,1454 +0,0 @@
-/*
- * Nokia N-series internet tablets.
- *
- * Copyright (C) 2007 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu/cutils.h"
-#include "sysemu/sysemu.h"
-#include "hw/arm/omap.h"
-#include "hw/arm/arm.h"
-#include "hw/irq.h"
-#include "ui/console.h"
-#include "hw/boards.h"
-#include "hw/i2c/i2c.h"
-#include "hw/devices.h"
-#include "hw/block/flash.h"
-#include "hw/hw.h"
-#include "hw/bt.h"
-#include "hw/loader.h"
-#include "sysemu/block-backend.h"
-#include "hw/sysbus.h"
-#include "exec/address-spaces.h"
-
-/* Nokia N8x0 support */
-struct n800_s {
- struct omap_mpu_state_s *mpu;
-
- struct rfbi_chip_s blizzard;
- struct {
- void *opaque;
- uint32_t (*txrx)(void *opaque, uint32_t value, int len);
- uWireSlave *chip;
- } ts;
-
- int keymap[0x80];
- DeviceState *kbd;
-
- DeviceState *usb;
- void *retu;
- void *tahvo;
- DeviceState *nand;
-};
-
-/* GPIO pins */
-#define N8X0_TUSB_ENABLE_GPIO 0
-#define N800_MMC2_WP_GPIO 8
-#define N800_UNKNOWN_GPIO0 9 /* out */
-#define N810_MMC2_VIOSD_GPIO 9
-#define N810_HEADSET_AMP_GPIO 10
-#define N800_CAM_TURN_GPIO 12
-#define N810_GPS_RESET_GPIO 12
-#define N800_BLIZZARD_POWERDOWN_GPIO 15
-#define N800_MMC1_WP_GPIO 23
-#define N810_MMC2_VSD_GPIO 23
-#define N8X0_ONENAND_GPIO 26
-#define N810_BLIZZARD_RESET_GPIO 30
-#define N800_UNKNOWN_GPIO2 53 /* out */
-#define N8X0_TUSB_INT_GPIO 58
-#define N8X0_BT_WKUP_GPIO 61
-#define N8X0_STI_GPIO 62
-#define N8X0_CBUS_SEL_GPIO 64
-#define N8X0_CBUS_DAT_GPIO 65
-#define N8X0_CBUS_CLK_GPIO 66
-#define N8X0_WLAN_IRQ_GPIO 87
-#define N8X0_BT_RESET_GPIO 92
-#define N8X0_TEA5761_CS_GPIO 93
-#define N800_UNKNOWN_GPIO 94
-#define N810_TSC_RESET_GPIO 94
-#define N800_CAM_ACT_GPIO 95
-#define N810_GPS_WAKEUP_GPIO 95
-#define N8X0_MMC_CS_GPIO 96
-#define N8X0_WLAN_PWR_GPIO 97
-#define N8X0_BT_HOST_WKUP_GPIO 98
-#define N810_SPEAKER_AMP_GPIO 101
-#define N810_KB_LOCK_GPIO 102
-#define N800_TSC_TS_GPIO 103
-#define N810_TSC_TS_GPIO 106
-#define N8X0_HEADPHONE_GPIO 107
-#define N8X0_RETU_GPIO 108
-#define N800_TSC_KP_IRQ_GPIO 109
-#define N810_KEYBOARD_GPIO 109
-#define N800_BAT_COVER_GPIO 110
-#define N810_SLIDE_GPIO 110
-#define N8X0_TAHVO_GPIO 111
-#define N800_UNKNOWN_GPIO4 112 /* out */
-#define N810_SLEEPX_LED_GPIO 112
-#define N800_TSC_RESET_GPIO 118 /* ? */
-#define N810_AIC33_RESET_GPIO 118
-#define N800_TSC_UNKNOWN_GPIO 119 /* out */
-#define N8X0_TMP105_GPIO 125
-
-/* Config */
-#define BT_UART 0
-#define XLDR_LL_UART 1
-
-/* Addresses on the I2C bus 0 */
-#define N810_TLV320AIC33_ADDR 0x18 /* Audio CODEC */
-#define N8X0_TCM825x_ADDR 0x29 /* Camera */
-#define N810_LP5521_ADDR 0x32 /* LEDs */
-#define N810_TSL2563_ADDR 0x3d /* Light sensor */
-#define N810_LM8323_ADDR 0x45 /* Keyboard */
-/* Addresses on the I2C bus 1 */
-#define N8X0_TMP105_ADDR 0x48 /* Temperature sensor */
-#define N8X0_MENELAUS_ADDR 0x72 /* Power management */
-
-/* Chipselects on GPMC NOR interface */
-#define N8X0_ONENAND_CS 0
-#define N8X0_USB_ASYNC_CS 1
-#define N8X0_USB_SYNC_CS 4
-
-#define N8X0_BD_ADDR 0x00, 0x1a, 0x89, 0x9e, 0x3e, 0x81
-
-static void n800_mmc_cs_cb(void *opaque, int line, int level)
-{
- /* TODO: this seems to actually be connected to the menelaus, to
- * which also both MMC slots connect. */
- omap_mmc_enable((struct omap_mmc_s *) opaque, !level);
-}
-
-static void n8x0_gpio_setup(struct n800_s *s)
-{
- qdev_connect_gpio_out(s->mpu->gpio, N8X0_MMC_CS_GPIO,
- qemu_allocate_irq(n800_mmc_cs_cb, s->mpu->mmc, 0));
- qemu_irq_lower(qdev_get_gpio_in(s->mpu->gpio, N800_BAT_COVER_GPIO));
-}
-
-#define MAEMO_CAL_HEADER(...) \
- 'C', 'o', 'n', 'F', 0x02, 0x00, 0x04, 0x00, \
- __VA_ARGS__, \
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
-static const uint8_t n8x0_cal_wlan_mac[] = {
- MAEMO_CAL_HEADER('w', 'l', 'a', 'n', '-', 'm', 'a', 'c')
- 0x1c, 0x00, 0x00, 0x00, 0x47, 0xd6, 0x69, 0xb3,
- 0x30, 0x08, 0xa0, 0x83, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00,
- 0x89, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00,
- 0x5d, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00,
-};
-
-static const uint8_t n8x0_cal_bt_id[] = {
- MAEMO_CAL_HEADER('b', 't', '-', 'i', 'd', 0, 0, 0)
- 0x0a, 0x00, 0x00, 0x00, 0xa3, 0x4b, 0xf6, 0x96,
- 0xa8, 0xeb, 0xb2, 0x41, 0x00, 0x00, 0x00, 0x00,
- N8X0_BD_ADDR,
-};
-
-static void n8x0_nand_setup(struct n800_s *s)
-{
- char *otp_region;
- DriveInfo *dinfo;
-
- s->nand = qdev_create(NULL, "onenand");
- qdev_prop_set_uint16(s->nand, "manufacturer_id", NAND_MFR_SAMSUNG);
- /* Either 0x40 or 0x48 are OK for the device ID */
- qdev_prop_set_uint16(s->nand, "device_id", 0x48);
- qdev_prop_set_uint16(s->nand, "version_id", 0);
- qdev_prop_set_int32(s->nand, "shift", 1);
- dinfo = drive_get(IF_MTD, 0, 0);
- if (dinfo) {
- qdev_prop_set_drive(s->nand, "drive", blk_by_legacy_dinfo(dinfo),
- &error_fatal);
- }
- qdev_init_nofail(s->nand);
- sysbus_connect_irq(SYS_BUS_DEVICE(s->nand), 0,
- qdev_get_gpio_in(s->mpu->gpio, N8X0_ONENAND_GPIO));
- omap_gpmc_attach(s->mpu->gpmc, N8X0_ONENAND_CS,
- sysbus_mmio_get_region(SYS_BUS_DEVICE(s->nand), 0));
- otp_region = onenand_raw_otp(s->nand);
-
- memcpy(otp_region + 0x000, n8x0_cal_wlan_mac, sizeof(n8x0_cal_wlan_mac));
- memcpy(otp_region + 0x800, n8x0_cal_bt_id, sizeof(n8x0_cal_bt_id));
- /* XXX: in theory should also update the OOB for both pages */
-}
-
-static qemu_irq n8x0_system_powerdown;
-
-static void n8x0_powerdown_req(Notifier *n, void *opaque)
-{
- qemu_irq_raise(n8x0_system_powerdown);
-}
-
-static Notifier n8x0_system_powerdown_notifier = {
- .notify = n8x0_powerdown_req
-};
-
-static void n8x0_i2c_setup(struct n800_s *s)
-{
- DeviceState *dev;
- qemu_irq tmp_irq = qdev_get_gpio_in(s->mpu->gpio, N8X0_TMP105_GPIO);
- I2CBus *i2c = omap_i2c_bus(s->mpu->i2c[0]);
-
- /* Attach a menelaus PM chip */
- dev = i2c_create_slave(i2c, "twl92230", N8X0_MENELAUS_ADDR);
- qdev_connect_gpio_out(dev, 3,
- qdev_get_gpio_in(s->mpu->ih[0],
- OMAP_INT_24XX_SYS_NIRQ));
-
- n8x0_system_powerdown = qdev_get_gpio_in(dev, 3);
- qemu_register_powerdown_notifier(&n8x0_system_powerdown_notifier);
-
- /* Attach a TMP105 PM chip (A0 wired to ground) */
- dev = i2c_create_slave(i2c, "tmp105", N8X0_TMP105_ADDR);
- qdev_connect_gpio_out(dev, 0, tmp_irq);
-}
-
-/* Touchscreen and keypad controller */
-static MouseTransformInfo n800_pointercal = {
- .x = 800,
- .y = 480,
- .a = { 14560, -68, -3455208, -39, -9621, 35152972, 65536 },
-};
-
-static MouseTransformInfo n810_pointercal = {
- .x = 800,
- .y = 480,
- .a = { 15041, 148, -4731056, 171, -10238, 35933380, 65536 },
-};
-
-#define RETU_KEYCODE 61 /* F3 */
-
-static void n800_key_event(void *opaque, int keycode)
-{
- struct n800_s *s = (struct n800_s *) opaque;
- int code = s->keymap[keycode & 0x7f];
-
- if (code == -1) {
- if ((keycode & 0x7f) == RETU_KEYCODE) {
- retu_key_event(s->retu, !(keycode & 0x80));
- }
- return;
- }
-
- tsc210x_key_event(s->ts.chip, code, !(keycode & 0x80));
-}
-
-static const int n800_keys[16] = {
- -1,
- 72, /* Up */
- 63, /* Home (F5) */
- -1,
- 75, /* Left */
- 28, /* Enter */
- 77, /* Right */
- -1,
- 1, /* Cycle (ESC) */
- 80, /* Down */
- 62, /* Menu (F4) */
- -1,
- 66, /* Zoom- (F8) */
- 64, /* FullScreen (F6) */
- 65, /* Zoom+ (F7) */
- -1,
-};
-
-static void n800_tsc_kbd_setup(struct n800_s *s)
-{
- int i;
-
- /* XXX: are the three pins inverted inside the chip between the
- * tsc and the cpu (N4111)? */
- qemu_irq penirq = NULL; /* NC */
- qemu_irq kbirq = qdev_get_gpio_in(s->mpu->gpio, N800_TSC_KP_IRQ_GPIO);
- qemu_irq dav = qdev_get_gpio_in(s->mpu->gpio, N800_TSC_TS_GPIO);
-
- s->ts.chip = tsc2301_init(penirq, kbirq, dav);
- s->ts.opaque = s->ts.chip->opaque;
- s->ts.txrx = tsc210x_txrx;
-
- for (i = 0; i < 0x80; i++) {
- s->keymap[i] = -1;
- }
- for (i = 0; i < 0x10; i++) {
- if (n800_keys[i] >= 0) {
- s->keymap[n800_keys[i]] = i;
- }
- }
-
- qemu_add_kbd_event_handler(n800_key_event, s);
-
- tsc210x_set_transform(s->ts.chip, &n800_pointercal);
-}
-
-static void n810_tsc_setup(struct n800_s *s)
-{
- qemu_irq pintdav = qdev_get_gpio_in(s->mpu->gpio, N810_TSC_TS_GPIO);
-
- s->ts.opaque = tsc2005_init(pintdav);
- s->ts.txrx = tsc2005_txrx;
-
- tsc2005_set_transform(s->ts.opaque, &n810_pointercal);
-}
-
-/* N810 Keyboard controller */
-static void n810_key_event(void *opaque, int keycode)
-{
- struct n800_s *s = (struct n800_s *) opaque;
- int code = s->keymap[keycode & 0x7f];
-
- if (code == -1) {
- if ((keycode & 0x7f) == RETU_KEYCODE) {
- retu_key_event(s->retu, !(keycode & 0x80));
- }
- return;
- }
-
- lm832x_key_event(s->kbd, code, !(keycode & 0x80));
-}
-
-#define M 0
-
-static int n810_keys[0x80] = {
- [0x01] = 16, /* Q */
- [0x02] = 37, /* K */
- [0x03] = 24, /* O */
- [0x04] = 25, /* P */
- [0x05] = 14, /* Backspace */
- [0x06] = 30, /* A */
- [0x07] = 31, /* S */
- [0x08] = 32, /* D */
- [0x09] = 33, /* F */
- [0x0a] = 34, /* G */
- [0x0b] = 35, /* H */
- [0x0c] = 36, /* J */
-
- [0x11] = 17, /* W */
- [0x12] = 62, /* Menu (F4) */
- [0x13] = 38, /* L */
- [0x14] = 40, /* ' (Apostrophe) */
- [0x16] = 44, /* Z */
- [0x17] = 45, /* X */
- [0x18] = 46, /* C */
- [0x19] = 47, /* V */
- [0x1a] = 48, /* B */
- [0x1b] = 49, /* N */
- [0x1c] = 42, /* Shift (Left shift) */
- [0x1f] = 65, /* Zoom+ (F7) */
-
- [0x21] = 18, /* E */
- [0x22] = 39, /* ; (Semicolon) */
- [0x23] = 12, /* - (Minus) */
- [0x24] = 13, /* = (Equal) */
- [0x2b] = 56, /* Fn (Left Alt) */
- [0x2c] = 50, /* M */
- [0x2f] = 66, /* Zoom- (F8) */
-
- [0x31] = 19, /* R */
- [0x32] = 29 | M, /* Right Ctrl */
- [0x34] = 57, /* Space */
- [0x35] = 51, /* , (Comma) */
- [0x37] = 72 | M, /* Up */
- [0x3c] = 82 | M, /* Compose (Insert) */
- [0x3f] = 64, /* FullScreen (F6) */
-
- [0x41] = 20, /* T */
- [0x44] = 52, /* . (Dot) */
- [0x46] = 77 | M, /* Right */
- [0x4f] = 63, /* Home (F5) */
- [0x51] = 21, /* Y */
- [0x53] = 80 | M, /* Down */
- [0x55] = 28, /* Enter */
- [0x5f] = 1, /* Cycle (ESC) */
-
- [0x61] = 22, /* U */
- [0x64] = 75 | M, /* Left */
-
- [0x71] = 23, /* I */
-#if 0
- [0x75] = 28 | M, /* KP Enter (KP Enter) */
-#else
- [0x75] = 15, /* KP Enter (Tab) */
-#endif
-};
-
-#undef M
-
-static void n810_kbd_setup(struct n800_s *s)
-{
- qemu_irq kbd_irq = qdev_get_gpio_in(s->mpu->gpio, N810_KEYBOARD_GPIO);
- int i;
-
- for (i = 0; i < 0x80; i++) {
- s->keymap[i] = -1;
- }
- for (i = 0; i < 0x80; i++) {
- if (n810_keys[i] > 0) {
- s->keymap[n810_keys[i]] = i;
- }
- }
-
- qemu_add_kbd_event_handler(n810_key_event, s);
-
- /* Attach the LM8322 keyboard to the I2C bus,
- * should happen in n8x0_i2c_setup and s->kbd be initialised here. */
- s->kbd = i2c_create_slave(omap_i2c_bus(s->mpu->i2c[0]),
- "lm8323", N810_LM8323_ADDR);
- qdev_connect_gpio_out(s->kbd, 0, kbd_irq);
-}
-
-/* LCD MIPI DBI-C controller (URAL) */
-struct mipid_s {
- int resp[4];
- int param[4];
- int p;
- int pm;
- int cmd;
-
- int sleep;
- int booster;
- int te;
- int selfcheck;
- int partial;
- int normal;
- int vscr;
- int invert;
- int onoff;
- int gamma;
- uint32_t id;
-};
-
-static void mipid_reset(struct mipid_s *s)
-{
- s->pm = 0;
- s->cmd = 0;
-
- s->sleep = 1;
- s->booster = 0;
- s->selfcheck =
- (1 << 7) | /* Register loading OK. */
- (1 << 5) | /* The chip is attached. */
- (1 << 4); /* Display glass still in one piece. */
- s->te = 0;
- s->partial = 0;
- s->normal = 1;
- s->vscr = 0;
- s->invert = 0;
- s->onoff = 1;
- s->gamma = 0;
-}
-
-static uint32_t mipid_txrx(void *opaque, uint32_t cmd, int len)
-{
- struct mipid_s *s = (struct mipid_s *) opaque;
- uint8_t ret;
-
- if (len > 9) {
- hw_error("%s: FIXME: bad SPI word width %i\n", __FUNCTION__, len);
- }
-
- if (s->p >= ARRAY_SIZE(s->resp)) {
- ret = 0;
- } else {
- ret = s->resp[s->p++];
- }
- if (s->pm-- > 0) {
- s->param[s->pm] = cmd;
- } else {
- s->cmd = cmd;
- }
-
- switch (s->cmd) {
- case 0x00: /* NOP */
- break;
-
- case 0x01: /* SWRESET */
- mipid_reset(s);
- break;
-
- case 0x02: /* BSTROFF */
- s->booster = 0;
- break;
- case 0x03: /* BSTRON */
- s->booster = 1;
- break;
-
- case 0x04: /* RDDID */
- s->p = 0;
- s->resp[0] = (s->id >> 16) & 0xff;
- s->resp[1] = (s->id >> 8) & 0xff;
- s->resp[2] = (s->id >> 0) & 0xff;
- break;
-
- case 0x06: /* RD_RED */
- case 0x07: /* RD_GREEN */
- /* XXX the bootloader sometimes issues RD_BLUE meaning RDDID so
- * for the bootloader one needs to change this. */
- case 0x08: /* RD_BLUE */
- s->p = 0;
- /* TODO: return first pixel components */
- s->resp[0] = 0x01;
- break;
-
- case 0x09: /* RDDST */
- s->p = 0;
- s->resp[0] = s->booster << 7;
- s->resp[1] = (5 << 4) | (s->partial << 2) |
- (s->sleep << 1) | s->normal;
- s->resp[2] = (s->vscr << 7) | (s->invert << 5) |
- (s->onoff << 2) | (s->te << 1) | (s->gamma >> 2);
- s->resp[3] = s->gamma << 6;
- break;
-
- case 0x0a: /* RDDPM */
- s->p = 0;
- s->resp[0] = (s->onoff << 2) | (s->normal << 3) | (s->sleep << 4) |
- (s->partial << 5) | (s->sleep << 6) | (s->booster << 7);
- break;
- case 0x0b: /* RDDMADCTR */
- s->p = 0;
- s->resp[0] = 0;
- break;
- case 0x0c: /* RDDCOLMOD */
- s->p = 0;
- s->resp[0] = 5; /* 65K colours */
- break;
- case 0x0d: /* RDDIM */
- s->p = 0;
- s->resp[0] = (s->invert << 5) | (s->vscr << 7) | s->gamma;
- break;
- case 0x0e: /* RDDSM */
- s->p = 0;
- s->resp[0] = s->te << 7;
- break;
- case 0x0f: /* RDDSDR */
- s->p = 0;
- s->resp[0] = s->selfcheck;
- break;
-
- case 0x10: /* SLPIN */
- s->sleep = 1;
- break;
- case 0x11: /* SLPOUT */
- s->sleep = 0;
- s->selfcheck ^= 1 << 6; /* POFF self-diagnosis Ok */
- break;
-
- case 0x12: /* PTLON */
- s->partial = 1;
- s->normal = 0;
- s->vscr = 0;
- break;
- case 0x13: /* NORON */
- s->partial = 0;
- s->normal = 1;
- s->vscr = 0;
- break;
-
- case 0x20: /* INVOFF */
- s->invert = 0;
- break;
- case 0x21: /* INVON */
- s->invert = 1;
- break;
-
- case 0x22: /* APOFF */
- case 0x23: /* APON */
- goto bad_cmd;
-
- case 0x25: /* WRCNTR */
- if (s->pm < 0) {
- s->pm = 1;
- }
- goto bad_cmd;
-
- case 0x26: /* GAMSET */
- if (!s->pm) {
- s->gamma = ctz32(s->param[0] & 0xf);
- if (s->gamma == 32) {
- s->gamma = -1; /* XXX: should this be 0? */
- }
- } else if (s->pm < 0) {
- s->pm = 1;
- }
- break;
-
- case 0x28: /* DISPOFF */
- s->onoff = 0;
- break;
- case 0x29: /* DISPON */
- s->onoff = 1;
- break;
-
- case 0x2a: /* CASET */
- case 0x2b: /* RASET */
- case 0x2c: /* RAMWR */
- case 0x2d: /* RGBSET */
- case 0x2e: /* RAMRD */
- case 0x30: /* PTLAR */
- case 0x33: /* SCRLAR */
- goto bad_cmd;
-
- case 0x34: /* TEOFF */
- s->te = 0;
- break;
- case 0x35: /* TEON */
- if (!s->pm) {
- s->te = 1;
- } else if (s->pm < 0) {
- s->pm = 1;
- }
- break;
-
- case 0x36: /* MADCTR */
- goto bad_cmd;
-
- case 0x37: /* VSCSAD */
- s->partial = 0;
- s->normal = 0;
- s->vscr = 1;
- break;
-
- case 0x38: /* IDMOFF */
- case 0x39: /* IDMON */
- case 0x3a: /* COLMOD */
- goto bad_cmd;
-
- case 0xb0: /* CLKINT / DISCTL */
- case 0xb1: /* CLKEXT */
- if (s->pm < 0) {
- s->pm = 2;
- }
- break;
-
- case 0xb4: /* FRMSEL */
- break;
-
- case 0xb5: /* FRM8SEL */
- case 0xb6: /* TMPRNG / INIESC */
- case 0xb7: /* TMPHIS / NOP2 */
- case 0xb8: /* TMPREAD / MADCTL */
- case 0xba: /* DISTCTR */
- case 0xbb: /* EPVOL */
- goto bad_cmd;
-
- case 0xbd: /* Unknown */
- s->p = 0;
- s->resp[0] = 0;
- s->resp[1] = 1;
- break;
-
- case 0xc2: /* IFMOD */
- if (s->pm < 0) {
- s->pm = 2;
- }
- break;
-
- case 0xc6: /* PWRCTL */
- case 0xc7: /* PPWRCTL */
- case 0xd0: /* EPWROUT */
- case 0xd1: /* EPWRIN */
- case 0xd4: /* RDEV */
- case 0xd5: /* RDRR */
- goto bad_cmd;
-
- case 0xda: /* RDID1 */
- s->p = 0;
- s->resp[0] = (s->id >> 16) & 0xff;
- break;
- case 0xdb: /* RDID2 */
- s->p = 0;
- s->resp[0] = (s->id >> 8) & 0xff;
- break;
- case 0xdc: /* RDID3 */
- s->p = 0;
- s->resp[0] = (s->id >> 0) & 0xff;
- break;
-
- default:
- bad_cmd:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: unknown command %02x\n", __func__, s->cmd);
- break;
- }
-
- return ret;
-}
-
-static void *mipid_init(void)
-{
- struct mipid_s *s = (struct mipid_s *) g_malloc0(sizeof(*s));
-
- s->id = 0x838f03;
- mipid_reset(s);
-
- return s;
-}
-
-static void n8x0_spi_setup(struct n800_s *s)
-{
- void *tsc = s->ts.opaque;
- void *mipid = mipid_init();
-
- omap_mcspi_attach(s->mpu->mcspi[0], s->ts.txrx, tsc, 0);
- omap_mcspi_attach(s->mpu->mcspi[0], mipid_txrx, mipid, 1);
-}
-
-/* This task is normally performed by the bootloader. If we're loading
- * a kernel directly, we need to enable the Blizzard ourselves. */
-static void n800_dss_init(struct rfbi_chip_s *chip)
-{
- uint8_t *fb_blank;
-
- chip->write(chip->opaque, 0, 0x2a); /* LCD Width register */
- chip->write(chip->opaque, 1, 0x64);
- chip->write(chip->opaque, 0, 0x2c); /* LCD HNDP register */
- chip->write(chip->opaque, 1, 0x1e);
- chip->write(chip->opaque, 0, 0x2e); /* LCD Height 0 register */
- chip->write(chip->opaque, 1, 0xe0);
- chip->write(chip->opaque, 0, 0x30); /* LCD Height 1 register */
- chip->write(chip->opaque, 1, 0x01);
- chip->write(chip->opaque, 0, 0x32); /* LCD VNDP register */
- chip->write(chip->opaque, 1, 0x06);
- chip->write(chip->opaque, 0, 0x68); /* Display Mode register */
- chip->write(chip->opaque, 1, 1); /* Enable bit */
-
- chip->write(chip->opaque, 0, 0x6c);
- chip->write(chip->opaque, 1, 0x00); /* Input X Start Position */
- chip->write(chip->opaque, 1, 0x00); /* Input X Start Position */
- chip->write(chip->opaque, 1, 0x00); /* Input Y Start Position */
- chip->write(chip->opaque, 1, 0x00); /* Input Y Start Position */
- chip->write(chip->opaque, 1, 0x1f); /* Input X End Position */
- chip->write(chip->opaque, 1, 0x03); /* Input X End Position */
- chip->write(chip->opaque, 1, 0xdf); /* Input Y End Position */
- chip->write(chip->opaque, 1, 0x01); /* Input Y End Position */
- chip->write(chip->opaque, 1, 0x00); /* Output X Start Position */
- chip->write(chip->opaque, 1, 0x00); /* Output X Start Position */
- chip->write(chip->opaque, 1, 0x00); /* Output Y Start Position */
- chip->write(chip->opaque, 1, 0x00); /* Output Y Start Position */
- chip->write(chip->opaque, 1, 0x1f); /* Output X End Position */
- chip->write(chip->opaque, 1, 0x03); /* Output X End Position */
- chip->write(chip->opaque, 1, 0xdf); /* Output Y End Position */
- chip->write(chip->opaque, 1, 0x01); /* Output Y End Position */
- chip->write(chip->opaque, 1, 0x01); /* Input Data Format */
- chip->write(chip->opaque, 1, 0x01); /* Data Source Select */
-
- fb_blank = memset(g_malloc(800 * 480 * 2), 0xff, 800 * 480 * 2);
- /* Display Memory Data Port */
- chip->block(chip->opaque, 1, fb_blank, 800 * 480 * 2, 800);
- g_free(fb_blank);
-}
-
-static void n8x0_dss_setup(struct n800_s *s)
-{
- s->blizzard.opaque = s1d13745_init(NULL);
- s->blizzard.block = s1d13745_write_block;
- s->blizzard.write = s1d13745_write;
- s->blizzard.read = s1d13745_read;
-
- omap_rfbi_attach(s->mpu->dss, 0, &s->blizzard);
-}
-
-static void n8x0_cbus_setup(struct n800_s *s)
-{
- qemu_irq dat_out = qdev_get_gpio_in(s->mpu->gpio, N8X0_CBUS_DAT_GPIO);
- qemu_irq retu_irq = qdev_get_gpio_in(s->mpu->gpio, N8X0_RETU_GPIO);
- qemu_irq tahvo_irq = qdev_get_gpio_in(s->mpu->gpio, N8X0_TAHVO_GPIO);
-
- CBus *cbus = cbus_init(dat_out);
-
- qdev_connect_gpio_out(s->mpu->gpio, N8X0_CBUS_CLK_GPIO, cbus->clk);
- qdev_connect_gpio_out(s->mpu->gpio, N8X0_CBUS_DAT_GPIO, cbus->dat);
- qdev_connect_gpio_out(s->mpu->gpio, N8X0_CBUS_SEL_GPIO, cbus->sel);
-
- cbus_attach(cbus, s->retu = retu_init(retu_irq, 1));
- cbus_attach(cbus, s->tahvo = tahvo_init(tahvo_irq, 1));
-}
-
-static void n8x0_uart_setup(struct n800_s *s)
-{
- CharDriverState *radio = uart_hci_init(
- qdev_get_gpio_in(s->mpu->gpio, N8X0_BT_HOST_WKUP_GPIO));
-
- qdev_connect_gpio_out(s->mpu->gpio, N8X0_BT_RESET_GPIO,
- csrhci_pins_get(radio)[csrhci_pin_reset]);
- qdev_connect_gpio_out(s->mpu->gpio, N8X0_BT_WKUP_GPIO,
- csrhci_pins_get(radio)[csrhci_pin_wakeup]);
-
- omap_uart_attach(s->mpu->uart[BT_UART], radio);
-}
-
-static void n8x0_usb_setup(struct n800_s *s)
-{
- SysBusDevice *dev;
- s->usb = qdev_create(NULL, "tusb6010");
- dev = SYS_BUS_DEVICE(s->usb);
- qdev_init_nofail(s->usb);
- sysbus_connect_irq(dev, 0,
- qdev_get_gpio_in(s->mpu->gpio, N8X0_TUSB_INT_GPIO));
- /* Using the NOR interface */
- omap_gpmc_attach(s->mpu->gpmc, N8X0_USB_ASYNC_CS,
- sysbus_mmio_get_region(dev, 0));
- omap_gpmc_attach(s->mpu->gpmc, N8X0_USB_SYNC_CS,
- sysbus_mmio_get_region(dev, 1));
- qdev_connect_gpio_out(s->mpu->gpio, N8X0_TUSB_ENABLE_GPIO,
- qdev_get_gpio_in(s->usb, 0)); /* tusb_pwr */
-}
-
-/* Setup done before the main bootloader starts by some early setup code
- * - used when we want to run the main bootloader in emulation. This
- * isn't documented. */
-static uint32_t n800_pinout[104] = {
- 0x080f00d8, 0x00d40808, 0x03080808, 0x080800d0,
- 0x00dc0808, 0x0b0f0f00, 0x080800b4, 0x00c00808,
- 0x08080808, 0x180800c4, 0x00b80000, 0x08080808,
- 0x080800bc, 0x00cc0808, 0x08081818, 0x18180128,
- 0x01241800, 0x18181818, 0x000000f0, 0x01300000,
- 0x00001b0b, 0x1b0f0138, 0x00e0181b, 0x1b031b0b,
- 0x180f0078, 0x00740018, 0x0f0f0f1a, 0x00000080,
- 0x007c0000, 0x00000000, 0x00000088, 0x00840000,
- 0x00000000, 0x00000094, 0x00980300, 0x0f180003,
- 0x0000008c, 0x00900f0f, 0x0f0f1b00, 0x0f00009c,
- 0x01140000, 0x1b1b0f18, 0x0818013c, 0x01400008,
- 0x00001818, 0x000b0110, 0x010c1800, 0x0b030b0f,
- 0x181800f4, 0x00f81818, 0x00000018, 0x000000fc,
- 0x00401808, 0x00000000, 0x0f1b0030, 0x003c0008,
- 0x00000000, 0x00000038, 0x00340000, 0x00000000,
- 0x1a080070, 0x00641a1a, 0x08080808, 0x08080060,
- 0x005c0808, 0x08080808, 0x08080058, 0x00540808,
- 0x08080808, 0x0808006c, 0x00680808, 0x08080808,
- 0x000000a8, 0x00b00000, 0x08080808, 0x000000a0,
- 0x00a40000, 0x00000000, 0x08ff0050, 0x004c0808,
- 0xffffffff, 0xffff0048, 0x0044ffff, 0xffffffff,
- 0x000000ac, 0x01040800, 0x08080b0f, 0x18180100,
- 0x01081818, 0x0b0b1808, 0x1a0300e4, 0x012c0b1a,
- 0x02020018, 0x0b000134, 0x011c0800, 0x0b1b1b00,
- 0x0f0000c8, 0x00ec181b, 0x000f0f02, 0x00180118,
- 0x01200000, 0x0f0b1b1b, 0x0f0200e8, 0x0000020b,
-};
-
-static void n800_setup_nolo_tags(void *sram_base)
-{
- int i;
- uint32_t *p = sram_base + 0x8000;
- uint32_t *v = sram_base + 0xa000;
-
- memset(p, 0, 0x3000);
-
- strcpy((void *) (p + 0), "QEMU N800");
-
- strcpy((void *) (p + 8), "F5");
-
- stl_p(p + 10, 0x04f70000);
- strcpy((void *) (p + 9), "RX-34");
-
- /* RAM size in MB? */
- stl_p(p + 12, 0x80);
-
- /* Pointer to the list of tags */
- stl_p(p + 13, OMAP2_SRAM_BASE + 0x9000);
-
- /* The NOLO tags start here */
- p = sram_base + 0x9000;
-#define ADD_TAG(tag, len) \
- stw_p((uint16_t *) p + 0, tag); \
- stw_p((uint16_t *) p + 1, len); p++; \
- stl_p(p++, OMAP2_SRAM_BASE | (((void *) v - sram_base) & 0xffff));
-
- /* OMAP STI console? Pin out settings? */
- ADD_TAG(0x6e01, 414);
- for (i = 0; i < ARRAY_SIZE(n800_pinout); i++) {
- stl_p(v++, n800_pinout[i]);
- }
-
- /* Kernel memsize? */
- ADD_TAG(0x6e05, 1);
- stl_p(v++, 2);
-
- /* NOLO serial console */
- ADD_TAG(0x6e02, 4);
- stl_p(v++, XLDR_LL_UART); /* UART number (1 - 3) */
-
-#if 0
- /* CBUS settings (Retu/AVilma) */
- ADD_TAG(0x6e03, 6);
- stw_p((uint16_t *) v + 0, 65); /* CBUS GPIO0 */
- stw_p((uint16_t *) v + 1, 66); /* CBUS GPIO1 */
- stw_p((uint16_t *) v + 2, 64); /* CBUS GPIO2 */
- v += 2;
-#endif
-
- /* Nokia ASIC BB5 (Retu/Tahvo) */
- ADD_TAG(0x6e0a, 4);
- stw_p((uint16_t *) v + 0, 111); /* "Retu" interrupt GPIO */
- stw_p((uint16_t *) v + 1, 108); /* "Tahvo" interrupt GPIO */
- v++;
-
- /* LCD console? */
- ADD_TAG(0x6e04, 4);
- stw_p((uint16_t *) v + 0, 30); /* ??? */
- stw_p((uint16_t *) v + 1, 24); /* ??? */
- v++;
-
-#if 0
- /* LCD settings */
- ADD_TAG(0x6e06, 2);
- stw_p((uint16_t *) (v++), 15); /* ??? */
-#endif
-
- /* I^2C (Menelaus) */
- ADD_TAG(0x6e07, 4);
- stl_p(v++, 0x00720000); /* ??? */
-
- /* Unknown */
- ADD_TAG(0x6e0b, 6);
- stw_p((uint16_t *) v + 0, 94); /* ??? */
- stw_p((uint16_t *) v + 1, 23); /* ??? */
- stw_p((uint16_t *) v + 2, 0); /* ??? */
- v += 2;
-
- /* OMAP gpio switch info */
- ADD_TAG(0x6e0c, 80);
- strcpy((void *) v, "bat_cover"); v += 3;
- stw_p((uint16_t *) v + 0, 110); /* GPIO num ??? */
- stw_p((uint16_t *) v + 1, 1); /* GPIO num ??? */
- v += 2;
- strcpy((void *) v, "cam_act"); v += 3;
- stw_p((uint16_t *) v + 0, 95); /* GPIO num ??? */
- stw_p((uint16_t *) v + 1, 32); /* GPIO num ??? */
- v += 2;
- strcpy((void *) v, "cam_turn"); v += 3;
- stw_p((uint16_t *) v + 0, 12); /* GPIO num ??? */
- stw_p((uint16_t *) v + 1, 33); /* GPIO num ??? */
- v += 2;
- strcpy((void *) v, "headphone"); v += 3;
- stw_p((uint16_t *) v + 0, 107); /* GPIO num ??? */
- stw_p((uint16_t *) v + 1, 17); /* GPIO num ??? */
- v += 2;
-
- /* Bluetooth */
- ADD_TAG(0x6e0e, 12);
- stl_p(v++, 0x5c623d01); /* ??? */
- stl_p(v++, 0x00000201); /* ??? */
- stl_p(v++, 0x00000000); /* ??? */
-
- /* CX3110x WLAN settings */
- ADD_TAG(0x6e0f, 8);
- stl_p(v++, 0x00610025); /* ??? */
- stl_p(v++, 0xffff0057); /* ??? */
-
- /* MMC host settings */
- ADD_TAG(0x6e10, 12);
- stl_p(v++, 0xffff000f); /* ??? */
- stl_p(v++, 0xffffffff); /* ??? */
- stl_p(v++, 0x00000060); /* ??? */
-
- /* OneNAND chip select */
- ADD_TAG(0x6e11, 10);
- stl_p(v++, 0x00000401); /* ??? */
- stl_p(v++, 0x0002003a); /* ??? */
- stl_p(v++, 0x00000002); /* ??? */
-
- /* TEA5761 sensor settings */
- ADD_TAG(0x6e12, 2);
- stl_p(v++, 93); /* GPIO num ??? */
-
-#if 0
- /* Unknown tag */
- ADD_TAG(6e09, 0);
-
- /* Kernel UART / console */
- ADD_TAG(6e12, 0);
-#endif
-
- /* End of the list */
- stl_p(p++, 0x00000000);
- stl_p(p++, 0x00000000);
-}
-
-/* This task is normally performed by the bootloader. If we're loading
- * a kernel directly, we need to set up GPMC mappings ourselves. */
-static void n800_gpmc_init(struct n800_s *s)
-{
- uint32_t config7 =
- (0xf << 8) | /* MASKADDRESS */
- (1 << 6) | /* CSVALID */
- (4 << 0); /* BASEADDRESS */
-
- cpu_physical_memory_write(0x6800a078, /* GPMC_CONFIG7_0 */
- &config7, sizeof(config7));
-}
-
-/* Setup sequence done by the bootloader */
-static void n8x0_boot_init(void *opaque)
-{
- struct n800_s *s = (struct n800_s *) opaque;
- uint32_t buf;
-
- /* PRCM setup */
-#define omap_writel(addr, val) \
- buf = (val); \
- cpu_physical_memory_write(addr, &buf, sizeof(buf))
-
- omap_writel(0x48008060, 0x41); /* PRCM_CLKSRC_CTRL */
- omap_writel(0x48008070, 1); /* PRCM_CLKOUT_CTRL */
- omap_writel(0x48008078, 0); /* PRCM_CLKEMUL_CTRL */
- omap_writel(0x48008090, 0); /* PRCM_VOLTSETUP */
- omap_writel(0x48008094, 0); /* PRCM_CLKSSETUP */
- omap_writel(0x48008098, 0); /* PRCM_POLCTRL */
- omap_writel(0x48008140, 2); /* CM_CLKSEL_MPU */
- omap_writel(0x48008148, 0); /* CM_CLKSTCTRL_MPU */
- omap_writel(0x48008158, 1); /* RM_RSTST_MPU */
- omap_writel(0x480081c8, 0x15); /* PM_WKDEP_MPU */
- omap_writel(0x480081d4, 0x1d4); /* PM_EVGENCTRL_MPU */
- omap_writel(0x480081d8, 0); /* PM_EVEGENONTIM_MPU */
- omap_writel(0x480081dc, 0); /* PM_EVEGENOFFTIM_MPU */
- omap_writel(0x480081e0, 0xc); /* PM_PWSTCTRL_MPU */
- omap_writel(0x48008200, 0x047e7ff7); /* CM_FCLKEN1_CORE */
- omap_writel(0x48008204, 0x00000004); /* CM_FCLKEN2_CORE */
- omap_writel(0x48008210, 0x047e7ff1); /* CM_ICLKEN1_CORE */
- omap_writel(0x48008214, 0x00000004); /* CM_ICLKEN2_CORE */
- omap_writel(0x4800821c, 0x00000000); /* CM_ICLKEN4_CORE */
- omap_writel(0x48008230, 0); /* CM_AUTOIDLE1_CORE */
- omap_writel(0x48008234, 0); /* CM_AUTOIDLE2_CORE */
- omap_writel(0x48008238, 7); /* CM_AUTOIDLE3_CORE */
- omap_writel(0x4800823c, 0); /* CM_AUTOIDLE4_CORE */
- omap_writel(0x48008240, 0x04360626); /* CM_CLKSEL1_CORE */
- omap_writel(0x48008244, 0x00000014); /* CM_CLKSEL2_CORE */
- omap_writel(0x48008248, 0); /* CM_CLKSTCTRL_CORE */
- omap_writel(0x48008300, 0x00000000); /* CM_FCLKEN_GFX */
- omap_writel(0x48008310, 0x00000000); /* CM_ICLKEN_GFX */
- omap_writel(0x48008340, 0x00000001); /* CM_CLKSEL_GFX */
- omap_writel(0x48008400, 0x00000004); /* CM_FCLKEN_WKUP */
- omap_writel(0x48008410, 0x00000004); /* CM_ICLKEN_WKUP */
- omap_writel(0x48008440, 0x00000000); /* CM_CLKSEL_WKUP */
- omap_writel(0x48008500, 0x000000cf); /* CM_CLKEN_PLL */
- omap_writel(0x48008530, 0x0000000c); /* CM_AUTOIDLE_PLL */
- omap_writel(0x48008540, /* CM_CLKSEL1_PLL */
- (0x78 << 12) | (6 << 8));
- omap_writel(0x48008544, 2); /* CM_CLKSEL2_PLL */
-
- /* GPMC setup */
- n800_gpmc_init(s);
-
- /* Video setup */
- n800_dss_init(&s->blizzard);
-
- /* CPU setup */
- s->mpu->cpu->env.GE = 0x5;
-
- /* If the machine has a slided keyboard, open it */
- if (s->kbd) {
- qemu_irq_raise(qdev_get_gpio_in(s->mpu->gpio, N810_SLIDE_GPIO));
- }
-}
-
-#define OMAP_TAG_NOKIA_BT 0x4e01
-#define OMAP_TAG_WLAN_CX3110X 0x4e02
-#define OMAP_TAG_CBUS 0x4e03
-#define OMAP_TAG_EM_ASIC_BB5 0x4e04
-
-static struct omap_gpiosw_info_s {
- const char *name;
- int line;
- int type;
-} n800_gpiosw_info[] = {
- {
- "bat_cover", N800_BAT_COVER_GPIO,
- OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED,
- }, {
- "cam_act", N800_CAM_ACT_GPIO,
- OMAP_GPIOSW_TYPE_ACTIVITY,
- }, {
- "cam_turn", N800_CAM_TURN_GPIO,
- OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_INVERTED,
- }, {
- "headphone", N8X0_HEADPHONE_GPIO,
- OMAP_GPIOSW_TYPE_CONNECTION | OMAP_GPIOSW_INVERTED,
- },
- { NULL }
-}, n810_gpiosw_info[] = {
- {
- "gps_reset", N810_GPS_RESET_GPIO,
- OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_OUTPUT,
- }, {
- "gps_wakeup", N810_GPS_WAKEUP_GPIO,
- OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_OUTPUT,
- }, {
- "headphone", N8X0_HEADPHONE_GPIO,
- OMAP_GPIOSW_TYPE_CONNECTION | OMAP_GPIOSW_INVERTED,
- }, {
- "kb_lock", N810_KB_LOCK_GPIO,
- OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED,
- }, {
- "sleepx_led", N810_SLEEPX_LED_GPIO,
- OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_INVERTED | OMAP_GPIOSW_OUTPUT,
- }, {
- "slide", N810_SLIDE_GPIO,
- OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED,
- },
- { NULL }
-};
-
-static struct omap_partition_info_s {
- uint32_t offset;
- uint32_t size;
- int mask;
- const char *name;
-} n800_part_info[] = {
- { 0x00000000, 0x00020000, 0x3, "bootloader" },
- { 0x00020000, 0x00060000, 0x0, "config" },
- { 0x00080000, 0x00200000, 0x0, "kernel" },
- { 0x00280000, 0x00200000, 0x3, "initfs" },
- { 0x00480000, 0x0fb80000, 0x3, "rootfs" },
-
- { 0, 0, 0, NULL }
-}, n810_part_info[] = {
- { 0x00000000, 0x00020000, 0x3, "bootloader" },
- { 0x00020000, 0x00060000, 0x0, "config" },
- { 0x00080000, 0x00220000, 0x0, "kernel" },
- { 0x002a0000, 0x00400000, 0x0, "initfs" },
- { 0x006a0000, 0x0f960000, 0x0, "rootfs" },
-
- { 0, 0, 0, NULL }
-};
-
-static bdaddr_t n8x0_bd_addr = {{ N8X0_BD_ADDR }};
-
-static int n8x0_atag_setup(void *p, int model)
-{
- uint8_t *b;
- uint16_t *w;
- uint32_t *l;
- struct omap_gpiosw_info_s *gpiosw;
- struct omap_partition_info_s *partition;
- const char *tag;
-
- w = p;
-
- stw_p(w++, OMAP_TAG_UART); /* u16 tag */
- stw_p(w++, 4); /* u16 len */
- stw_p(w++, (1 << 2) | (1 << 1) | (1 << 0)); /* uint enabled_uarts */
- w++;
-
-#if 0
- stw_p(w++, OMAP_TAG_SERIAL_CONSOLE); /* u16 tag */
- stw_p(w++, 4); /* u16 len */
- stw_p(w++, XLDR_LL_UART + 1); /* u8 console_uart */
- stw_p(w++, 115200); /* u32 console_speed */
-#endif
-
- stw_p(w++, OMAP_TAG_LCD); /* u16 tag */
- stw_p(w++, 36); /* u16 len */
- strcpy((void *) w, "QEMU LCD panel"); /* char panel_name[16] */
- w += 8;
- strcpy((void *) w, "blizzard"); /* char ctrl_name[16] */
- w += 8;
- stw_p(w++, N810_BLIZZARD_RESET_GPIO); /* TODO: n800 s16 nreset_gpio */
- stw_p(w++, 24); /* u8 data_lines */
-
- stw_p(w++, OMAP_TAG_CBUS); /* u16 tag */
- stw_p(w++, 8); /* u16 len */
- stw_p(w++, N8X0_CBUS_CLK_GPIO); /* s16 clk_gpio */
- stw_p(w++, N8X0_CBUS_DAT_GPIO); /* s16 dat_gpio */
- stw_p(w++, N8X0_CBUS_SEL_GPIO); /* s16 sel_gpio */
- w++;
-
- stw_p(w++, OMAP_TAG_EM_ASIC_BB5); /* u16 tag */
- stw_p(w++, 4); /* u16 len */
- stw_p(w++, N8X0_RETU_GPIO); /* s16 retu_irq_gpio */
- stw_p(w++, N8X0_TAHVO_GPIO); /* s16 tahvo_irq_gpio */
-
- gpiosw = (model == 810) ? n810_gpiosw_info : n800_gpiosw_info;
- for (; gpiosw->name; gpiosw++) {
- stw_p(w++, OMAP_TAG_GPIO_SWITCH); /* u16 tag */
- stw_p(w++, 20); /* u16 len */
- strcpy((void *) w, gpiosw->name); /* char name[12] */
- w += 6;
- stw_p(w++, gpiosw->line); /* u16 gpio */
- stw_p(w++, gpiosw->type);
- stw_p(w++, 0);
- stw_p(w++, 0);
- }
-
- stw_p(w++, OMAP_TAG_NOKIA_BT); /* u16 tag */
- stw_p(w++, 12); /* u16 len */
- b = (void *) w;
- stb_p(b++, 0x01); /* u8 chip_type (CSR) */
- stb_p(b++, N8X0_BT_WKUP_GPIO); /* u8 bt_wakeup_gpio */
- stb_p(b++, N8X0_BT_HOST_WKUP_GPIO); /* u8 host_wakeup_gpio */
- stb_p(b++, N8X0_BT_RESET_GPIO); /* u8 reset_gpio */
- stb_p(b++, BT_UART + 1); /* u8 bt_uart */
- memcpy(b, &n8x0_bd_addr, 6); /* u8 bd_addr[6] */
- b += 6;
- stb_p(b++, 0x02); /* u8 bt_sysclk (38.4) */
- w = (void *) b;
-
- stw_p(w++, OMAP_TAG_WLAN_CX3110X); /* u16 tag */
- stw_p(w++, 8); /* u16 len */
- stw_p(w++, 0x25); /* u8 chip_type */
- stw_p(w++, N8X0_WLAN_PWR_GPIO); /* s16 power_gpio */
- stw_p(w++, N8X0_WLAN_IRQ_GPIO); /* s16 irq_gpio */
- stw_p(w++, -1); /* s16 spi_cs_gpio */
-
- stw_p(w++, OMAP_TAG_MMC); /* u16 tag */
- stw_p(w++, 16); /* u16 len */
- if (model == 810) {
- stw_p(w++, 0x23f); /* unsigned flags */
- stw_p(w++, -1); /* s16 power_pin */
- stw_p(w++, -1); /* s16 switch_pin */
- stw_p(w++, -1); /* s16 wp_pin */
- stw_p(w++, 0x240); /* unsigned flags */
- stw_p(w++, 0xc000); /* s16 power_pin */
- stw_p(w++, 0x0248); /* s16 switch_pin */
- stw_p(w++, 0xc000); /* s16 wp_pin */
- } else {
- stw_p(w++, 0xf); /* unsigned flags */
- stw_p(w++, -1); /* s16 power_pin */
- stw_p(w++, -1); /* s16 switch_pin */
- stw_p(w++, -1); /* s16 wp_pin */
- stw_p(w++, 0); /* unsigned flags */
- stw_p(w++, 0); /* s16 power_pin */
- stw_p(w++, 0); /* s16 switch_pin */
- stw_p(w++, 0); /* s16 wp_pin */
- }
-
- stw_p(w++, OMAP_TAG_TEA5761); /* u16 tag */
- stw_p(w++, 4); /* u16 len */
- stw_p(w++, N8X0_TEA5761_CS_GPIO); /* u16 enable_gpio */
- w++;
-
- partition = (model == 810) ? n810_part_info : n800_part_info;
- for (; partition->name; partition++) {
- stw_p(w++, OMAP_TAG_PARTITION); /* u16 tag */
- stw_p(w++, 28); /* u16 len */
- strcpy((void *) w, partition->name); /* char name[16] */
- l = (void *) (w + 8);
- stl_p(l++, partition->size); /* unsigned int size */
- stl_p(l++, partition->offset); /* unsigned int offset */
- stl_p(l++, partition->mask); /* unsigned int mask_flags */
- w = (void *) l;
- }
-
- stw_p(w++, OMAP_TAG_BOOT_REASON); /* u16 tag */
- stw_p(w++, 12); /* u16 len */
-#if 0
- strcpy((void *) w, "por"); /* char reason_str[12] */
- strcpy((void *) w, "charger"); /* char reason_str[12] */
- strcpy((void *) w, "32wd_to"); /* char reason_str[12] */
- strcpy((void *) w, "sw_rst"); /* char reason_str[12] */
- strcpy((void *) w, "mbus"); /* char reason_str[12] */
- strcpy((void *) w, "unknown"); /* char reason_str[12] */
- strcpy((void *) w, "swdg_to"); /* char reason_str[12] */
- strcpy((void *) w, "sec_vio"); /* char reason_str[12] */
- strcpy((void *) w, "pwr_key"); /* char reason_str[12] */
- strcpy((void *) w, "rtc_alarm"); /* char reason_str[12] */
-#else
- strcpy((void *) w, "pwr_key"); /* char reason_str[12] */
-#endif
- w += 6;
-
- tag = (model == 810) ? "RX-44" : "RX-34";
- stw_p(w++, OMAP_TAG_VERSION_STR); /* u16 tag */
- stw_p(w++, 24); /* u16 len */
- strcpy((void *) w, "product"); /* char component[12] */
- w += 6;
- strcpy((void *) w, tag); /* char version[12] */
- w += 6;
-
- stw_p(w++, OMAP_TAG_VERSION_STR); /* u16 tag */
- stw_p(w++, 24); /* u16 len */
- strcpy((void *) w, "hw-build"); /* char component[12] */
- w += 6;
- strcpy((void *) w, "QEMU ");
- pstrcat((void *) w, 12, qemu_hw_version()); /* char version[12] */
- w += 6;
-
- tag = (model == 810) ? "1.1.10-qemu" : "1.1.6-qemu";
- stw_p(w++, OMAP_TAG_VERSION_STR); /* u16 tag */
- stw_p(w++, 24); /* u16 len */
- strcpy((void *) w, "nolo"); /* char component[12] */
- w += 6;
- strcpy((void *) w, tag); /* char version[12] */
- w += 6;
-
- return (void *) w - p;
-}
-
-static int n800_atag_setup(const struct arm_boot_info *info, void *p)
-{
- return n8x0_atag_setup(p, 800);
-}
-
-static int n810_atag_setup(const struct arm_boot_info *info, void *p)
-{
- return n8x0_atag_setup(p, 810);
-}
-
-static void n8x0_init(MachineState *machine,
- struct arm_boot_info *binfo, int model)
-{
- MemoryRegion *sysmem = get_system_memory();
- struct n800_s *s = (struct n800_s *) g_malloc0(sizeof(*s));
- int sdram_size = binfo->ram_size;
-
- s->mpu = omap2420_mpu_init(sysmem, sdram_size, machine->cpu_model);
-
- /* Setup peripherals
- *
- * Believed external peripherals layout in the N810:
- * (spi bus 1)
- * tsc2005
- * lcd_mipid
- * (spi bus 2)
- * Conexant cx3110x (WLAN)
- * optional: pc2400m (WiMAX)
- * (i2c bus 0)
- * TLV320AIC33 (audio codec)
- * TCM825x (camera by Toshiba)
- * lp5521 (clever LEDs)
- * tsl2563 (light sensor, hwmon, model 7, rev. 0)
- * lm8323 (keypad, manf 00, rev 04)
- * (i2c bus 1)
- * tmp105 (temperature sensor, hwmon)
- * menelaus (pm)
- * (somewhere on i2c - maybe N800-only)
- * tea5761 (FM tuner)
- * (serial 0)
- * GPS
- * (some serial port)
- * csr41814 (Bluetooth)
- */
- n8x0_gpio_setup(s);
- n8x0_nand_setup(s);
- n8x0_i2c_setup(s);
- if (model == 800) {
- n800_tsc_kbd_setup(s);
- } else if (model == 810) {
- n810_tsc_setup(s);
- n810_kbd_setup(s);
- }
- n8x0_spi_setup(s);
- n8x0_dss_setup(s);
- n8x0_cbus_setup(s);
- n8x0_uart_setup(s);
- if (usb_enabled()) {
- n8x0_usb_setup(s);
- }
-
- if (machine->kernel_filename) {
- /* Or at the linux loader. */
- binfo->kernel_filename = machine->kernel_filename;
- binfo->kernel_cmdline = machine->kernel_cmdline;
- binfo->initrd_filename = machine->initrd_filename;
- arm_load_kernel(s->mpu->cpu, binfo);
-
- qemu_register_reset(n8x0_boot_init, s);
- }
-
- if (option_rom[0].name &&
- (machine->boot_order[0] == 'n' || !machine->kernel_filename)) {
- uint8_t nolo_tags[0x10000];
- /* No, wait, better start at the ROM. */
- s->mpu->cpu->env.regs[15] = OMAP2_Q2_BASE + 0x400000;
-
- /* This is intended for loading the `secondary.bin' program from
- * Nokia images (the NOLO bootloader). The entry point seems
- * to be at OMAP2_Q2_BASE + 0x400000.
- *
- * The `2nd.bin' files contain some kind of earlier boot code and
- * for them the entry point needs to be set to OMAP2_SRAM_BASE.
- *
- * The code above is for loading the `zImage' file from Nokia
- * images. */
- load_image_targphys(option_rom[0].name,
- OMAP2_Q2_BASE + 0x400000,
- sdram_size - 0x400000);
-
- n800_setup_nolo_tags(nolo_tags);
- cpu_physical_memory_write(OMAP2_SRAM_BASE, nolo_tags, 0x10000);
- }
-}
-
-static struct arm_boot_info n800_binfo = {
- .loader_start = OMAP2_Q2_BASE,
- /* Actually two chips of 0x4000000 bytes each */
- .ram_size = 0x08000000,
- .board_id = 0x4f7,
- .atag_board = n800_atag_setup,
-};
-
-static struct arm_boot_info n810_binfo = {
- .loader_start = OMAP2_Q2_BASE,
- /* Actually two chips of 0x4000000 bytes each */
- .ram_size = 0x08000000,
- /* 0x60c and 0x6bf (WiMAX Edition) have been assigned but are not
- * used by some older versions of the bootloader and 5555 is used
- * instead (including versions that shipped with many devices). */
- .board_id = 0x60c,
- .atag_board = n810_atag_setup,
-};
-
-static void n800_init(MachineState *machine)
-{
- n8x0_init(machine, &n800_binfo, 800);
-}
-
-static void n810_init(MachineState *machine)
-{
- n8x0_init(machine, &n810_binfo, 810);
-}
-
-static void n800_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "Nokia N800 tablet aka. RX-34 (OMAP2420)";
- mc->init = n800_init;
- mc->default_boot_order = "";
-}
-
-static const TypeInfo n800_type = {
- .name = MACHINE_TYPE_NAME("n800"),
- .parent = TYPE_MACHINE,
- .class_init = n800_class_init,
-};
-
-static void n810_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "Nokia N810 tablet aka. RX-44 (OMAP2420)";
- mc->init = n810_init;
- mc->default_boot_order = "";
-}
-
-static const TypeInfo n810_type = {
- .name = MACHINE_TYPE_NAME("n810"),
- .parent = TYPE_MACHINE,
- .class_init = n810_class_init,
-};
-
-static void nseries_machine_init(void)
-{
- type_register_static(&n800_type);
- type_register_static(&n810_type);
-}
-
-type_init(nseries_machine_init)
diff --git a/qemu/hw/arm/omap1.c b/qemu/hw/arm/omap1.c
deleted file mode 100644
index b3cf0ec69..000000000
--- a/qemu/hw/arm/omap1.c
+++ /dev/null
@@ -1,4086 +0,0 @@
-/*
- * TI OMAP processors emulation.
- *
- * Copyright (C) 2006-2008 Andrzej Zaborowski <balrog@zabor.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/boards.h"
-#include "hw/hw.h"
-#include "hw/arm/arm.h"
-#include "hw/arm/omap.h"
-#include "sysemu/sysemu.h"
-#include "hw/arm/soc_dma.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
-#include "qemu/range.h"
-#include "hw/sysbus.h"
-#include "qemu/cutils.h"
-#include "qemu/bcd.h"
-
-/* Should signal the TCMI/GPMC */
-uint32_t omap_badwidth_read8(void *opaque, hwaddr addr)
-{
- uint8_t ret;
-
- OMAP_8B_REG(addr);
- cpu_physical_memory_read(addr, &ret, 1);
- return ret;
-}
-
-void omap_badwidth_write8(void *opaque, hwaddr addr,
- uint32_t value)
-{
- uint8_t val8 = value;
-
- OMAP_8B_REG(addr);
- cpu_physical_memory_write(addr, &val8, 1);
-}
-
-uint32_t omap_badwidth_read16(void *opaque, hwaddr addr)
-{
- uint16_t ret;
-
- OMAP_16B_REG(addr);
- cpu_physical_memory_read(addr, &ret, 2);
- return ret;
-}
-
-void omap_badwidth_write16(void *opaque, hwaddr addr,
- uint32_t value)
-{
- uint16_t val16 = value;
-
- OMAP_16B_REG(addr);
- cpu_physical_memory_write(addr, &val16, 2);
-}
-
-uint32_t omap_badwidth_read32(void *opaque, hwaddr addr)
-{
- uint32_t ret;
-
- OMAP_32B_REG(addr);
- cpu_physical_memory_read(addr, &ret, 4);
- return ret;
-}
-
-void omap_badwidth_write32(void *opaque, hwaddr addr,
- uint32_t value)
-{
- OMAP_32B_REG(addr);
- cpu_physical_memory_write(addr, &value, 4);
-}
-
-/* MPU OS timers */
-struct omap_mpu_timer_s {
- MemoryRegion iomem;
- qemu_irq irq;
- omap_clk clk;
- uint32_t val;
- int64_t time;
- QEMUTimer *timer;
- QEMUBH *tick;
- int64_t rate;
- int it_ena;
-
- int enable;
- int ptv;
- int ar;
- int st;
- uint32_t reset_val;
-};
-
-static inline uint32_t omap_timer_read(struct omap_mpu_timer_s *timer)
-{
- uint64_t distance = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - timer->time;
-
- if (timer->st && timer->enable && timer->rate)
- return timer->val - muldiv64(distance >> (timer->ptv + 1),
- timer->rate, NANOSECONDS_PER_SECOND);
- else
- return timer->val;
-}
-
-static inline void omap_timer_sync(struct omap_mpu_timer_s *timer)
-{
- timer->val = omap_timer_read(timer);
- timer->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-}
-
-static inline void omap_timer_update(struct omap_mpu_timer_s *timer)
-{
- int64_t expires;
-
- if (timer->enable && timer->st && timer->rate) {
- timer->val = timer->reset_val; /* Should skip this on clk enable */
- expires = muldiv64((uint64_t) timer->val << (timer->ptv + 1),
- NANOSECONDS_PER_SECOND, timer->rate);
-
- /* If timer expiry would be sooner than in about 1 ms and
- * auto-reload isn't set, then fire immediately. This is a hack
- * to make systems like PalmOS run in acceptable time. PalmOS
- * sets the interval to a very low value and polls the status bit
- * in a busy loop when it wants to sleep just a couple of CPU
- * ticks. */
- if (expires > (NANOSECONDS_PER_SECOND >> 10) || timer->ar) {
- timer_mod(timer->timer, timer->time + expires);
- } else {
- qemu_bh_schedule(timer->tick);
- }
- } else
- timer_del(timer->timer);
-}
-
-static void omap_timer_fire(void *opaque)
-{
- struct omap_mpu_timer_s *timer = opaque;
-
- if (!timer->ar) {
- timer->val = 0;
- timer->st = 0;
- }
-
- if (timer->it_ena)
- /* Edge-triggered irq */
- qemu_irq_pulse(timer->irq);
-}
-
-static void omap_timer_tick(void *opaque)
-{
- struct omap_mpu_timer_s *timer = (struct omap_mpu_timer_s *) opaque;
-
- omap_timer_sync(timer);
- omap_timer_fire(timer);
- omap_timer_update(timer);
-}
-
-static void omap_timer_clk_update(void *opaque, int line, int on)
-{
- struct omap_mpu_timer_s *timer = (struct omap_mpu_timer_s *) opaque;
-
- omap_timer_sync(timer);
- timer->rate = on ? omap_clk_getrate(timer->clk) : 0;
- omap_timer_update(timer);
-}
-
-static void omap_timer_clk_setup(struct omap_mpu_timer_s *timer)
-{
- omap_clk_adduser(timer->clk,
- qemu_allocate_irq(omap_timer_clk_update, timer, 0));
- timer->rate = omap_clk_getrate(timer->clk);
-}
-
-static uint64_t omap_mpu_timer_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *) opaque;
-
- if (size != 4) {
- return omap_badwidth_read32(opaque, addr);
- }
-
- switch (addr) {
- case 0x00: /* CNTL_TIMER */
- return (s->enable << 5) | (s->ptv << 2) | (s->ar << 1) | s->st;
-
- case 0x04: /* LOAD_TIM */
- break;
-
- case 0x08: /* READ_TIM */
- return omap_timer_read(s);
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_mpu_timer_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *) opaque;
-
- if (size != 4) {
- omap_badwidth_write32(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x00: /* CNTL_TIMER */
- omap_timer_sync(s);
- s->enable = (value >> 5) & 1;
- s->ptv = (value >> 2) & 7;
- s->ar = (value >> 1) & 1;
- s->st = value & 1;
- omap_timer_update(s);
- return;
-
- case 0x04: /* LOAD_TIM */
- s->reset_val = value;
- return;
-
- case 0x08: /* READ_TIM */
- OMAP_RO_REG(addr);
- break;
-
- default:
- OMAP_BAD_REG(addr);
- }
-}
-
-static const MemoryRegionOps omap_mpu_timer_ops = {
- .read = omap_mpu_timer_read,
- .write = omap_mpu_timer_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void omap_mpu_timer_reset(struct omap_mpu_timer_s *s)
-{
- timer_del(s->timer);
- s->enable = 0;
- s->reset_val = 31337;
- s->val = 0;
- s->ptv = 0;
- s->ar = 0;
- s->st = 0;
- s->it_ena = 1;
-}
-
-static struct omap_mpu_timer_s *omap_mpu_timer_init(MemoryRegion *system_memory,
- hwaddr base,
- qemu_irq irq, omap_clk clk)
-{
- struct omap_mpu_timer_s *s = g_new0(struct omap_mpu_timer_s, 1);
-
- s->irq = irq;
- s->clk = clk;
- s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, omap_timer_tick, s);
- s->tick = qemu_bh_new(omap_timer_fire, s);
- omap_mpu_timer_reset(s);
- omap_timer_clk_setup(s);
-
- memory_region_init_io(&s->iomem, NULL, &omap_mpu_timer_ops, s,
- "omap-mpu-timer", 0x100);
-
- memory_region_add_subregion(system_memory, base, &s->iomem);
-
- return s;
-}
-
-/* Watchdog timer */
-struct omap_watchdog_timer_s {
- struct omap_mpu_timer_s timer;
- MemoryRegion iomem;
- uint8_t last_wr;
- int mode;
- int free;
- int reset;
-};
-
-static uint64_t omap_wd_timer_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) opaque;
-
- if (size != 2) {
- return omap_badwidth_read16(opaque, addr);
- }
-
- switch (addr) {
- case 0x00: /* CNTL_TIMER */
- return (s->timer.ptv << 9) | (s->timer.ar << 8) |
- (s->timer.st << 7) | (s->free << 1);
-
- case 0x04: /* READ_TIMER */
- return omap_timer_read(&s->timer);
-
- case 0x08: /* TIMER_MODE */
- return s->mode << 15;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_wd_timer_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) opaque;
-
- if (size != 2) {
- omap_badwidth_write16(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x00: /* CNTL_TIMER */
- omap_timer_sync(&s->timer);
- s->timer.ptv = (value >> 9) & 7;
- s->timer.ar = (value >> 8) & 1;
- s->timer.st = (value >> 7) & 1;
- s->free = (value >> 1) & 1;
- omap_timer_update(&s->timer);
- break;
-
- case 0x04: /* LOAD_TIMER */
- s->timer.reset_val = value & 0xffff;
- break;
-
- case 0x08: /* TIMER_MODE */
- if (!s->mode && ((value >> 15) & 1))
- omap_clk_get(s->timer.clk);
- s->mode |= (value >> 15) & 1;
- if (s->last_wr == 0xf5) {
- if ((value & 0xff) == 0xa0) {
- if (s->mode) {
- s->mode = 0;
- omap_clk_put(s->timer.clk);
- }
- } else {
- /* XXX: on T|E hardware somehow this has no effect,
- * on Zire 71 it works as specified. */
- s->reset = 1;
- qemu_system_reset_request();
- }
- }
- s->last_wr = value & 0xff;
- break;
-
- default:
- OMAP_BAD_REG(addr);
- }
-}
-
-static const MemoryRegionOps omap_wd_timer_ops = {
- .read = omap_wd_timer_read,
- .write = omap_wd_timer_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void omap_wd_timer_reset(struct omap_watchdog_timer_s *s)
-{
- timer_del(s->timer.timer);
- if (!s->mode)
- omap_clk_get(s->timer.clk);
- s->mode = 1;
- s->free = 1;
- s->reset = 0;
- s->timer.enable = 1;
- s->timer.it_ena = 1;
- s->timer.reset_val = 0xffff;
- s->timer.val = 0;
- s->timer.st = 0;
- s->timer.ptv = 0;
- s->timer.ar = 0;
- omap_timer_update(&s->timer);
-}
-
-static struct omap_watchdog_timer_s *omap_wd_timer_init(MemoryRegion *memory,
- hwaddr base,
- qemu_irq irq, omap_clk clk)
-{
- struct omap_watchdog_timer_s *s = g_new0(struct omap_watchdog_timer_s, 1);
-
- s->timer.irq = irq;
- s->timer.clk = clk;
- s->timer.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, omap_timer_tick, &s->timer);
- omap_wd_timer_reset(s);
- omap_timer_clk_setup(&s->timer);
-
- memory_region_init_io(&s->iomem, NULL, &omap_wd_timer_ops, s,
- "omap-wd-timer", 0x100);
- memory_region_add_subregion(memory, base, &s->iomem);
-
- return s;
-}
-
-/* 32-kHz timer */
-struct omap_32khz_timer_s {
- struct omap_mpu_timer_s timer;
- MemoryRegion iomem;
-};
-
-static uint64_t omap_os_timer_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) opaque;
- int offset = addr & OMAP_MPUI_REG_MASK;
-
- if (size != 4) {
- return omap_badwidth_read32(opaque, addr);
- }
-
- switch (offset) {
- case 0x00: /* TVR */
- return s->timer.reset_val;
-
- case 0x04: /* TCR */
- return omap_timer_read(&s->timer);
-
- case 0x08: /* CR */
- return (s->timer.ar << 3) | (s->timer.it_ena << 2) | s->timer.st;
-
- default:
- break;
- }
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_os_timer_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) opaque;
- int offset = addr & OMAP_MPUI_REG_MASK;
-
- if (size != 4) {
- omap_badwidth_write32(opaque, addr, value);
- return;
- }
-
- switch (offset) {
- case 0x00: /* TVR */
- s->timer.reset_val = value & 0x00ffffff;
- break;
-
- case 0x04: /* TCR */
- OMAP_RO_REG(addr);
- break;
-
- case 0x08: /* CR */
- s->timer.ar = (value >> 3) & 1;
- s->timer.it_ena = (value >> 2) & 1;
- if (s->timer.st != (value & 1) || (value & 2)) {
- omap_timer_sync(&s->timer);
- s->timer.enable = value & 1;
- s->timer.st = value & 1;
- omap_timer_update(&s->timer);
- }
- break;
-
- default:
- OMAP_BAD_REG(addr);
- }
-}
-
-static const MemoryRegionOps omap_os_timer_ops = {
- .read = omap_os_timer_read,
- .write = omap_os_timer_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void omap_os_timer_reset(struct omap_32khz_timer_s *s)
-{
- timer_del(s->timer.timer);
- s->timer.enable = 0;
- s->timer.it_ena = 0;
- s->timer.reset_val = 0x00ffffff;
- s->timer.val = 0;
- s->timer.st = 0;
- s->timer.ptv = 0;
- s->timer.ar = 1;
-}
-
-static struct omap_32khz_timer_s *omap_os_timer_init(MemoryRegion *memory,
- hwaddr base,
- qemu_irq irq, omap_clk clk)
-{
- struct omap_32khz_timer_s *s = g_new0(struct omap_32khz_timer_s, 1);
-
- s->timer.irq = irq;
- s->timer.clk = clk;
- s->timer.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, omap_timer_tick, &s->timer);
- omap_os_timer_reset(s);
- omap_timer_clk_setup(&s->timer);
-
- memory_region_init_io(&s->iomem, NULL, &omap_os_timer_ops, s,
- "omap-os-timer", 0x800);
- memory_region_add_subregion(memory, base, &s->iomem);
-
- return s;
-}
-
-/* Ultra Low-Power Device Module */
-static uint64_t omap_ulpd_pm_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
- uint16_t ret;
-
- if (size != 2) {
- return omap_badwidth_read16(opaque, addr);
- }
-
- switch (addr) {
- case 0x14: /* IT_STATUS */
- ret = s->ulpd_pm_regs[addr >> 2];
- s->ulpd_pm_regs[addr >> 2] = 0;
- qemu_irq_lower(qdev_get_gpio_in(s->ih[1], OMAP_INT_GAUGE_32K));
- return ret;
-
- case 0x18: /* Reserved */
- case 0x1c: /* Reserved */
- case 0x20: /* Reserved */
- 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 */
- case 0x0c: /* COUNTER_HIGH_FREQ_MSB */
- case 0x10: /* GAUGING_CTRL */
- case 0x24: /* SETUP_ANALOG_CELL3_ULPD1 */
- case 0x30: /* CLOCK_CTRL */
- case 0x34: /* SOFT_REQ */
- case 0x38: /* COUNTER_32_FIQ */
- case 0x3c: /* DPLL_CTRL */
- case 0x40: /* STATUS_REQ */
- /* XXX: check clk::usecount state for every clock */
- case 0x48: /* LOCL_TIME */
- case 0x4c: /* APLL_CTRL */
- case 0x50: /* POWER_CTRL */
- return s->ulpd_pm_regs[addr >> 2];
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static inline void omap_ulpd_clk_update(struct omap_mpu_state_s *s,
- uint16_t diff, uint16_t value)
-{
- if (diff & (1 << 4)) /* USB_MCLK_EN */
- omap_clk_onoff(omap_findclk(s, "usb_clk0"), (value >> 4) & 1);
- if (diff & (1 << 5)) /* DIS_USB_PVCI_CLK */
- omap_clk_onoff(omap_findclk(s, "usb_w2fc_ck"), (~value >> 5) & 1);
-}
-
-static inline void omap_ulpd_req_update(struct omap_mpu_state_s *s,
- uint16_t diff, uint16_t value)
-{
- if (diff & (1 << 0)) /* SOFT_DPLL_REQ */
- omap_clk_canidle(omap_findclk(s, "dpll4"), (~value >> 0) & 1);
- if (diff & (1 << 1)) /* SOFT_COM_REQ */
- omap_clk_canidle(omap_findclk(s, "com_mclk_out"), (~value >> 1) & 1);
- if (diff & (1 << 2)) /* SOFT_SDW_REQ */
- omap_clk_canidle(omap_findclk(s, "bt_mclk_out"), (~value >> 2) & 1);
- if (diff & (1 << 3)) /* SOFT_USB_REQ */
- omap_clk_canidle(omap_findclk(s, "usb_clk0"), (~value >> 3) & 1);
-}
-
-static void omap_ulpd_pm_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
- int64_t now, ticks;
- int div, mult;
- static const int bypass_div[4] = { 1, 2, 4, 4 };
- uint16_t diff;
-
- if (size != 2) {
- omap_badwidth_write16(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x00: /* COUNTER_32_LSB */
- case 0x04: /* COUNTER_32_MSB */
- case 0x08: /* COUNTER_HIGH_FREQ_LSB */
- case 0x0c: /* COUNTER_HIGH_FREQ_MSB */
- case 0x14: /* IT_STATUS */
- case 0x40: /* STATUS_REQ */
- OMAP_RO_REG(addr);
- break;
-
- case 0x10: /* GAUGING_CTRL */
- /* Bits 0 and 1 seem to be confused in the OMAP 310 TRM */
- if ((s->ulpd_pm_regs[addr >> 2] ^ value) & 1) {
- now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-
- if (value & 1)
- s->ulpd_gauge_start = now;
- else {
- now -= s->ulpd_gauge_start;
-
- /* 32-kHz ticks */
- ticks = muldiv64(now, 32768, NANOSECONDS_PER_SECOND);
- s->ulpd_pm_regs[0x00 >> 2] = (ticks >> 0) & 0xffff;
- s->ulpd_pm_regs[0x04 >> 2] = (ticks >> 16) & 0xffff;
- if (ticks >> 32) /* OVERFLOW_32K */
- s->ulpd_pm_regs[0x14 >> 2] |= 1 << 2;
-
- /* High frequency ticks */
- ticks = muldiv64(now, 12000000, NANOSECONDS_PER_SECOND);
- s->ulpd_pm_regs[0x08 >> 2] = (ticks >> 0) & 0xffff;
- s->ulpd_pm_regs[0x0c >> 2] = (ticks >> 16) & 0xffff;
- if (ticks >> 32) /* OVERFLOW_HI_FREQ */
- s->ulpd_pm_regs[0x14 >> 2] |= 1 << 1;
-
- s->ulpd_pm_regs[0x14 >> 2] |= 1 << 0; /* IT_GAUGING */
- qemu_irq_raise(qdev_get_gpio_in(s->ih[1], OMAP_INT_GAUGE_32K));
- }
- }
- s->ulpd_pm_regs[addr >> 2] = value;
- break;
-
- case 0x18: /* Reserved */
- case 0x1c: /* Reserved */
- case 0x20: /* Reserved */
- 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 */
- case 0x50: /* POWER_CTRL */
- s->ulpd_pm_regs[addr >> 2] = value;
- break;
-
- case 0x30: /* CLOCK_CTRL */
- diff = s->ulpd_pm_regs[addr >> 2] ^ value;
- s->ulpd_pm_regs[addr >> 2] = value & 0x3f;
- omap_ulpd_clk_update(s, diff, value);
- break;
-
- case 0x34: /* SOFT_REQ */
- diff = s->ulpd_pm_regs[addr >> 2] ^ value;
- s->ulpd_pm_regs[addr >> 2] = value & 0x1f;
- omap_ulpd_req_update(s, diff, value);
- break;
-
- case 0x3c: /* DPLL_CTRL */
- /* XXX: OMAP310 TRM claims bit 3 is PLL_ENABLE, and bit 4 is
- * omitted altogether, probably a typo. */
- /* This register has identical semantics with DPLL(1:3) control
- * registers, see omap_dpll_write() */
- diff = s->ulpd_pm_regs[addr >> 2] & value;
- s->ulpd_pm_regs[addr >> 2] = value & 0x2fff;
- if (diff & (0x3ff << 2)) {
- if (value & (1 << 4)) { /* PLL_ENABLE */
- div = ((value >> 5) & 3) + 1; /* PLL_DIV */
- mult = MIN((value >> 7) & 0x1f, 1); /* PLL_MULT */
- } else {
- div = bypass_div[((value >> 2) & 3)]; /* BYPASS_DIV */
- mult = 1;
- }
- omap_clk_setrate(omap_findclk(s, "dpll4"), div, mult);
- }
-
- /* Enter the desired mode. */
- s->ulpd_pm_regs[addr >> 2] =
- (s->ulpd_pm_regs[addr >> 2] & 0xfffe) |
- ((s->ulpd_pm_regs[addr >> 2] >> 4) & 1);
-
- /* Act as if the lock is restored. */
- s->ulpd_pm_regs[addr >> 2] |= 2;
- break;
-
- case 0x4c: /* APLL_CTRL */
- diff = s->ulpd_pm_regs[addr >> 2] & value;
- s->ulpd_pm_regs[addr >> 2] = value & 0xf;
- if (diff & (1 << 0)) /* APLL_NDPLL_SWITCH */
- omap_clk_reparent(omap_findclk(s, "ck_48m"), omap_findclk(s,
- (value & (1 << 0)) ? "apll" : "dpll4"));
- break;
-
- default:
- OMAP_BAD_REG(addr);
- }
-}
-
-static const MemoryRegionOps omap_ulpd_pm_ops = {
- .read = omap_ulpd_pm_read,
- .write = omap_ulpd_pm_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void omap_ulpd_pm_reset(struct omap_mpu_state_s *mpu)
-{
- mpu->ulpd_pm_regs[0x00 >> 2] = 0x0001;
- mpu->ulpd_pm_regs[0x04 >> 2] = 0x0000;
- mpu->ulpd_pm_regs[0x08 >> 2] = 0x0001;
- mpu->ulpd_pm_regs[0x0c >> 2] = 0x0000;
- mpu->ulpd_pm_regs[0x10 >> 2] = 0x0000;
- mpu->ulpd_pm_regs[0x18 >> 2] = 0x01;
- mpu->ulpd_pm_regs[0x1c >> 2] = 0x01;
- mpu->ulpd_pm_regs[0x20 >> 2] = 0x01;
- mpu->ulpd_pm_regs[0x24 >> 2] = 0x03ff;
- mpu->ulpd_pm_regs[0x28 >> 2] = 0x01;
- mpu->ulpd_pm_regs[0x2c >> 2] = 0x01;
- omap_ulpd_clk_update(mpu, mpu->ulpd_pm_regs[0x30 >> 2], 0x0000);
- mpu->ulpd_pm_regs[0x30 >> 2] = 0x0000;
- omap_ulpd_req_update(mpu, mpu->ulpd_pm_regs[0x34 >> 2], 0x0000);
- mpu->ulpd_pm_regs[0x34 >> 2] = 0x0000;
- mpu->ulpd_pm_regs[0x38 >> 2] = 0x0001;
- mpu->ulpd_pm_regs[0x3c >> 2] = 0x2211;
- mpu->ulpd_pm_regs[0x40 >> 2] = 0x0000; /* FIXME: dump a real STATUS_REQ */
- mpu->ulpd_pm_regs[0x48 >> 2] = 0x960;
- mpu->ulpd_pm_regs[0x4c >> 2] = 0x08;
- mpu->ulpd_pm_regs[0x50 >> 2] = 0x08;
- omap_clk_setrate(omap_findclk(mpu, "dpll4"), 1, 4);
- omap_clk_reparent(omap_findclk(mpu, "ck_48m"), omap_findclk(mpu, "dpll4"));
-}
-
-static void omap_ulpd_pm_init(MemoryRegion *system_memory,
- hwaddr base,
- struct omap_mpu_state_s *mpu)
-{
- memory_region_init_io(&mpu->ulpd_pm_iomem, NULL, &omap_ulpd_pm_ops, mpu,
- "omap-ulpd-pm", 0x800);
- memory_region_add_subregion(system_memory, base, &mpu->ulpd_pm_iomem);
- omap_ulpd_pm_reset(mpu);
-}
-
-/* OMAP Pin Configuration */
-static uint64_t omap_pin_cfg_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
-
- if (size != 4) {
- return omap_badwidth_read32(opaque, addr);
- }
-
- switch (addr) {
- case 0x00: /* FUNC_MUX_CTRL_0 */
- case 0x04: /* FUNC_MUX_CTRL_1 */
- case 0x08: /* FUNC_MUX_CTRL_2 */
- return s->func_mux_ctrl[addr >> 2];
-
- case 0x0c: /* COMP_MODE_CTRL_0 */
- return s->comp_mode_ctrl[0];
-
- case 0x10: /* FUNC_MUX_CTRL_3 */
- case 0x14: /* FUNC_MUX_CTRL_4 */
- case 0x18: /* FUNC_MUX_CTRL_5 */
- case 0x1c: /* FUNC_MUX_CTRL_6 */
- case 0x20: /* FUNC_MUX_CTRL_7 */
- case 0x24: /* FUNC_MUX_CTRL_8 */
- case 0x28: /* FUNC_MUX_CTRL_9 */
- case 0x2c: /* FUNC_MUX_CTRL_A */
- case 0x30: /* FUNC_MUX_CTRL_B */
- case 0x34: /* FUNC_MUX_CTRL_C */
- case 0x38: /* FUNC_MUX_CTRL_D */
- return s->func_mux_ctrl[(addr >> 2) - 1];
-
- case 0x40: /* PULL_DWN_CTRL_0 */
- case 0x44: /* PULL_DWN_CTRL_1 */
- case 0x48: /* PULL_DWN_CTRL_2 */
- case 0x4c: /* PULL_DWN_CTRL_3 */
- return s->pull_dwn_ctrl[(addr & 0xf) >> 2];
-
- case 0x50: /* GATE_INH_CTRL_0 */
- return s->gate_inh_ctrl[0];
-
- case 0x60: /* VOLTAGE_CTRL_0 */
- return s->voltage_ctrl[0];
-
- case 0x70: /* TEST_DBG_CTRL_0 */
- return s->test_dbg_ctrl[0];
-
- case 0x80: /* MOD_CONF_CTRL_0 */
- return s->mod_conf_ctrl[0];
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static inline void omap_pin_funcmux0_update(struct omap_mpu_state_s *s,
- uint32_t diff, uint32_t value)
-{
- if (s->compat1509) {
- if (diff & (1 << 9)) /* BLUETOOTH */
- omap_clk_onoff(omap_findclk(s, "bt_mclk_out"),
- (~value >> 9) & 1);
- if (diff & (1 << 7)) /* USB.CLKO */
- omap_clk_onoff(omap_findclk(s, "usb.clko"),
- (value >> 7) & 1);
- }
-}
-
-static inline void omap_pin_funcmux1_update(struct omap_mpu_state_s *s,
- uint32_t diff, uint32_t value)
-{
- if (s->compat1509) {
- if (diff & (1U << 31)) {
- /* MCBSP3_CLK_HIZ_DI */
- omap_clk_onoff(omap_findclk(s, "mcbsp3.clkx"), (value >> 31) & 1);
- }
- if (diff & (1 << 1)) {
- /* CLK32K */
- omap_clk_onoff(omap_findclk(s, "clk32k_out"), (~value >> 1) & 1);
- }
- }
-}
-
-static inline void omap_pin_modconf1_update(struct omap_mpu_state_s *s,
- uint32_t diff, uint32_t value)
-{
- if (diff & (1U << 31)) {
- /* CONF_MOD_UART3_CLK_MODE_R */
- omap_clk_reparent(omap_findclk(s, "uart3_ck"),
- omap_findclk(s, ((value >> 31) & 1) ?
- "ck_48m" : "armper_ck"));
- }
- if (diff & (1 << 30)) /* CONF_MOD_UART2_CLK_MODE_R */
- omap_clk_reparent(omap_findclk(s, "uart2_ck"),
- omap_findclk(s, ((value >> 30) & 1) ?
- "ck_48m" : "armper_ck"));
- if (diff & (1 << 29)) /* CONF_MOD_UART1_CLK_MODE_R */
- omap_clk_reparent(omap_findclk(s, "uart1_ck"),
- omap_findclk(s, ((value >> 29) & 1) ?
- "ck_48m" : "armper_ck"));
- if (diff & (1 << 23)) /* CONF_MOD_MMC_SD_CLK_REQ_R */
- omap_clk_reparent(omap_findclk(s, "mmc_ck"),
- omap_findclk(s, ((value >> 23) & 1) ?
- "ck_48m" : "armper_ck"));
- if (diff & (1 << 12)) /* CONF_MOD_COM_MCLK_12_48_S */
- omap_clk_reparent(omap_findclk(s, "com_mclk_out"),
- omap_findclk(s, ((value >> 12) & 1) ?
- "ck_48m" : "armper_ck"));
- if (diff & (1 << 9)) /* CONF_MOD_USB_HOST_HHC_UHO */
- omap_clk_onoff(omap_findclk(s, "usb_hhc_ck"), (value >> 9) & 1);
-}
-
-static void omap_pin_cfg_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
- uint32_t diff;
-
- if (size != 4) {
- omap_badwidth_write32(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x00: /* FUNC_MUX_CTRL_0 */
- diff = s->func_mux_ctrl[addr >> 2] ^ value;
- s->func_mux_ctrl[addr >> 2] = value;
- omap_pin_funcmux0_update(s, diff, value);
- return;
-
- case 0x04: /* FUNC_MUX_CTRL_1 */
- diff = s->func_mux_ctrl[addr >> 2] ^ value;
- s->func_mux_ctrl[addr >> 2] = value;
- omap_pin_funcmux1_update(s, diff, value);
- return;
-
- case 0x08: /* FUNC_MUX_CTRL_2 */
- s->func_mux_ctrl[addr >> 2] = value;
- return;
-
- case 0x0c: /* COMP_MODE_CTRL_0 */
- s->comp_mode_ctrl[0] = value;
- s->compat1509 = (value != 0x0000eaef);
- omap_pin_funcmux0_update(s, ~0, s->func_mux_ctrl[0]);
- omap_pin_funcmux1_update(s, ~0, s->func_mux_ctrl[1]);
- return;
-
- case 0x10: /* FUNC_MUX_CTRL_3 */
- case 0x14: /* FUNC_MUX_CTRL_4 */
- case 0x18: /* FUNC_MUX_CTRL_5 */
- case 0x1c: /* FUNC_MUX_CTRL_6 */
- case 0x20: /* FUNC_MUX_CTRL_7 */
- case 0x24: /* FUNC_MUX_CTRL_8 */
- case 0x28: /* FUNC_MUX_CTRL_9 */
- case 0x2c: /* FUNC_MUX_CTRL_A */
- case 0x30: /* FUNC_MUX_CTRL_B */
- case 0x34: /* FUNC_MUX_CTRL_C */
- case 0x38: /* FUNC_MUX_CTRL_D */
- s->func_mux_ctrl[(addr >> 2) - 1] = value;
- return;
-
- case 0x40: /* PULL_DWN_CTRL_0 */
- case 0x44: /* PULL_DWN_CTRL_1 */
- case 0x48: /* PULL_DWN_CTRL_2 */
- case 0x4c: /* PULL_DWN_CTRL_3 */
- s->pull_dwn_ctrl[(addr & 0xf) >> 2] = value;
- return;
-
- case 0x50: /* GATE_INH_CTRL_0 */
- s->gate_inh_ctrl[0] = value;
- return;
-
- case 0x60: /* VOLTAGE_CTRL_0 */
- s->voltage_ctrl[0] = value;
- return;
-
- case 0x70: /* TEST_DBG_CTRL_0 */
- s->test_dbg_ctrl[0] = value;
- return;
-
- case 0x80: /* MOD_CONF_CTRL_0 */
- diff = s->mod_conf_ctrl[0] ^ value;
- s->mod_conf_ctrl[0] = value;
- omap_pin_modconf1_update(s, diff, value);
- return;
-
- default:
- OMAP_BAD_REG(addr);
- }
-}
-
-static const MemoryRegionOps omap_pin_cfg_ops = {
- .read = omap_pin_cfg_read,
- .write = omap_pin_cfg_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void omap_pin_cfg_reset(struct omap_mpu_state_s *mpu)
-{
- /* Start in Compatibility Mode. */
- mpu->compat1509 = 1;
- omap_pin_funcmux0_update(mpu, mpu->func_mux_ctrl[0], 0);
- omap_pin_funcmux1_update(mpu, mpu->func_mux_ctrl[1], 0);
- omap_pin_modconf1_update(mpu, mpu->mod_conf_ctrl[0], 0);
- memset(mpu->func_mux_ctrl, 0, sizeof(mpu->func_mux_ctrl));
- memset(mpu->comp_mode_ctrl, 0, sizeof(mpu->comp_mode_ctrl));
- memset(mpu->pull_dwn_ctrl, 0, sizeof(mpu->pull_dwn_ctrl));
- memset(mpu->gate_inh_ctrl, 0, sizeof(mpu->gate_inh_ctrl));
- memset(mpu->voltage_ctrl, 0, sizeof(mpu->voltage_ctrl));
- memset(mpu->test_dbg_ctrl, 0, sizeof(mpu->test_dbg_ctrl));
- memset(mpu->mod_conf_ctrl, 0, sizeof(mpu->mod_conf_ctrl));
-}
-
-static void omap_pin_cfg_init(MemoryRegion *system_memory,
- hwaddr base,
- struct omap_mpu_state_s *mpu)
-{
- memory_region_init_io(&mpu->pin_cfg_iomem, NULL, &omap_pin_cfg_ops, mpu,
- "omap-pin-cfg", 0x800);
- memory_region_add_subregion(system_memory, base, &mpu->pin_cfg_iomem);
- omap_pin_cfg_reset(mpu);
-}
-
-/* Device Identification, Die Identification */
-static uint64_t omap_id_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
-
- if (size != 4) {
- return omap_badwidth_read32(opaque, addr);
- }
-
- switch (addr) {
- case 0xfffe1800: /* DIE_ID_LSB */
- return 0xc9581f0e;
- case 0xfffe1804: /* DIE_ID_MSB */
- return 0xa8858bfa;
-
- case 0xfffe2000: /* PRODUCT_ID_LSB */
- return 0x00aaaafc;
- case 0xfffe2004: /* PRODUCT_ID_MSB */
- return 0xcafeb574;
-
- case 0xfffed400: /* JTAG_ID_LSB */
- switch (s->mpu_model) {
- case omap310:
- return 0x03310315;
- case omap1510:
- return 0x03310115;
- default:
- hw_error("%s: bad mpu model\n", __FUNCTION__);
- }
- break;
-
- case 0xfffed404: /* JTAG_ID_MSB */
- switch (s->mpu_model) {
- case omap310:
- return 0xfb57402f;
- case omap1510:
- return 0xfb47002f;
- default:
- hw_error("%s: bad mpu model\n", __FUNCTION__);
- }
- break;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_id_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- if (size != 4) {
- omap_badwidth_write32(opaque, addr, value);
- return;
- }
-
- OMAP_BAD_REG(addr);
-}
-
-static const MemoryRegionOps omap_id_ops = {
- .read = omap_id_read,
- .write = omap_id_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void omap_id_init(MemoryRegion *memory, struct omap_mpu_state_s *mpu)
-{
- memory_region_init_io(&mpu->id_iomem, NULL, &omap_id_ops, mpu,
- "omap-id", 0x100000000ULL);
- memory_region_init_alias(&mpu->id_iomem_e18, NULL, "omap-id-e18", &mpu->id_iomem,
- 0xfffe1800, 0x800);
- memory_region_add_subregion(memory, 0xfffe1800, &mpu->id_iomem_e18);
- memory_region_init_alias(&mpu->id_iomem_ed4, NULL, "omap-id-ed4", &mpu->id_iomem,
- 0xfffed400, 0x100);
- memory_region_add_subregion(memory, 0xfffed400, &mpu->id_iomem_ed4);
- if (!cpu_is_omap15xx(mpu)) {
- memory_region_init_alias(&mpu->id_iomem_ed4, NULL, "omap-id-e20",
- &mpu->id_iomem, 0xfffe2000, 0x800);
- memory_region_add_subregion(memory, 0xfffe2000, &mpu->id_iomem_e20);
- }
-}
-
-/* MPUI Control (Dummy) */
-static uint64_t omap_mpui_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
-
- if (size != 4) {
- return omap_badwidth_read32(opaque, addr);
- }
-
- switch (addr) {
- case 0x00: /* CTRL */
- return s->mpui_ctrl;
- case 0x04: /* DEBUG_ADDR */
- return 0x01ffffff;
- case 0x08: /* DEBUG_DATA */
- return 0xffffffff;
- case 0x0c: /* DEBUG_FLAG */
- return 0x00000800;
- case 0x10: /* STATUS */
- return 0x00000000;
-
- /* Not in OMAP310 */
- case 0x14: /* DSP_STATUS */
- case 0x18: /* DSP_BOOT_CONFIG */
- return 0x00000000;
- case 0x1c: /* DSP_MPUI_CONFIG */
- return 0x0000ffff;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_mpui_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
-
- if (size != 4) {
- omap_badwidth_write32(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x00: /* CTRL */
- s->mpui_ctrl = value & 0x007fffff;
- break;
-
- case 0x04: /* DEBUG_ADDR */
- case 0x08: /* DEBUG_DATA */
- case 0x0c: /* DEBUG_FLAG */
- case 0x10: /* STATUS */
- /* Not in OMAP310 */
- case 0x14: /* DSP_STATUS */
- OMAP_RO_REG(addr);
- break;
- case 0x18: /* DSP_BOOT_CONFIG */
- case 0x1c: /* DSP_MPUI_CONFIG */
- break;
-
- default:
- OMAP_BAD_REG(addr);
- }
-}
-
-static const MemoryRegionOps omap_mpui_ops = {
- .read = omap_mpui_read,
- .write = omap_mpui_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void omap_mpui_reset(struct omap_mpu_state_s *s)
-{
- s->mpui_ctrl = 0x0003ff1b;
-}
-
-static void omap_mpui_init(MemoryRegion *memory, hwaddr base,
- struct omap_mpu_state_s *mpu)
-{
- memory_region_init_io(&mpu->mpui_iomem, NULL, &omap_mpui_ops, mpu,
- "omap-mpui", 0x100);
- memory_region_add_subregion(memory, base, &mpu->mpui_iomem);
-
- omap_mpui_reset(mpu);
-}
-
-/* TIPB Bridges */
-struct omap_tipb_bridge_s {
- qemu_irq abort;
- MemoryRegion iomem;
-
- int width_intr;
- uint16_t control;
- uint16_t alloc;
- uint16_t buffer;
- uint16_t enh_control;
-};
-
-static uint64_t omap_tipb_bridge_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *) opaque;
-
- if (size < 2) {
- return omap_badwidth_read16(opaque, addr);
- }
-
- switch (addr) {
- case 0x00: /* TIPB_CNTL */
- return s->control;
- case 0x04: /* TIPB_BUS_ALLOC */
- return s->alloc;
- case 0x08: /* MPU_TIPB_CNTL */
- return s->buffer;
- case 0x0c: /* ENHANCED_TIPB_CNTL */
- return s->enh_control;
- case 0x10: /* ADDRESS_DBG */
- case 0x14: /* DATA_DEBUG_LOW */
- case 0x18: /* DATA_DEBUG_HIGH */
- return 0xffff;
- case 0x1c: /* DEBUG_CNTR_SIG */
- return 0x00f8;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_tipb_bridge_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *) opaque;
-
- if (size < 2) {
- omap_badwidth_write16(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x00: /* TIPB_CNTL */
- s->control = value & 0xffff;
- break;
-
- case 0x04: /* TIPB_BUS_ALLOC */
- s->alloc = value & 0x003f;
- break;
-
- case 0x08: /* MPU_TIPB_CNTL */
- s->buffer = value & 0x0003;
- break;
-
- case 0x0c: /* ENHANCED_TIPB_CNTL */
- s->width_intr = !(value & 2);
- s->enh_control = value & 0x000f;
- break;
-
- case 0x10: /* ADDRESS_DBG */
- case 0x14: /* DATA_DEBUG_LOW */
- case 0x18: /* DATA_DEBUG_HIGH */
- case 0x1c: /* DEBUG_CNTR_SIG */
- OMAP_RO_REG(addr);
- break;
-
- default:
- OMAP_BAD_REG(addr);
- }
-}
-
-static const MemoryRegionOps omap_tipb_bridge_ops = {
- .read = omap_tipb_bridge_read,
- .write = omap_tipb_bridge_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void omap_tipb_bridge_reset(struct omap_tipb_bridge_s *s)
-{
- s->control = 0xffff;
- s->alloc = 0x0009;
- s->buffer = 0x0000;
- s->enh_control = 0x000f;
-}
-
-static struct omap_tipb_bridge_s *omap_tipb_bridge_init(
- MemoryRegion *memory, hwaddr base,
- qemu_irq abort_irq, omap_clk clk)
-{
- struct omap_tipb_bridge_s *s = g_new0(struct omap_tipb_bridge_s, 1);
-
- s->abort = abort_irq;
- omap_tipb_bridge_reset(s);
-
- memory_region_init_io(&s->iomem, NULL, &omap_tipb_bridge_ops, s,
- "omap-tipb-bridge", 0x100);
- memory_region_add_subregion(memory, base, &s->iomem);
-
- return s;
-}
-
-/* Dummy Traffic Controller's Memory Interface */
-static uint64_t omap_tcmi_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
- uint32_t ret;
-
- if (size != 4) {
- return omap_badwidth_read32(opaque, addr);
- }
-
- switch (addr) {
- case 0x00: /* IMIF_PRIO */
- case 0x04: /* EMIFS_PRIO */
- case 0x08: /* EMIFF_PRIO */
- case 0x0c: /* EMIFS_CONFIG */
- case 0x10: /* EMIFS_CS0_CONFIG */
- case 0x14: /* EMIFS_CS1_CONFIG */
- case 0x18: /* EMIFS_CS2_CONFIG */
- case 0x1c: /* EMIFS_CS3_CONFIG */
- case 0x24: /* EMIFF_MRS */
- case 0x28: /* TIMEOUT1 */
- case 0x2c: /* TIMEOUT2 */
- case 0x30: /* TIMEOUT3 */
- case 0x3c: /* EMIFF_SDRAM_CONFIG_2 */
- case 0x40: /* EMIFS_CFG_DYN_WAIT */
- return s->tcmi_regs[addr >> 2];
-
- case 0x20: /* EMIFF_SDRAM_CONFIG */
- ret = s->tcmi_regs[addr >> 2];
- s->tcmi_regs[addr >> 2] &= ~1; /* XXX: Clear SLRF on SDRAM access */
- /* XXX: We can try using the VGA_DIRTY flag for this */
- return ret;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_tcmi_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
-
- if (size != 4) {
- omap_badwidth_write32(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x00: /* IMIF_PRIO */
- case 0x04: /* EMIFS_PRIO */
- case 0x08: /* EMIFF_PRIO */
- case 0x10: /* EMIFS_CS0_CONFIG */
- case 0x14: /* EMIFS_CS1_CONFIG */
- case 0x18: /* EMIFS_CS2_CONFIG */
- case 0x1c: /* EMIFS_CS3_CONFIG */
- case 0x20: /* EMIFF_SDRAM_CONFIG */
- case 0x24: /* EMIFF_MRS */
- case 0x28: /* TIMEOUT1 */
- case 0x2c: /* TIMEOUT2 */
- case 0x30: /* TIMEOUT3 */
- case 0x3c: /* EMIFF_SDRAM_CONFIG_2 */
- case 0x40: /* EMIFS_CFG_DYN_WAIT */
- s->tcmi_regs[addr >> 2] = value;
- break;
- case 0x0c: /* EMIFS_CONFIG */
- s->tcmi_regs[addr >> 2] = (value & 0xf) | (1 << 4);
- break;
-
- default:
- OMAP_BAD_REG(addr);
- }
-}
-
-static const MemoryRegionOps omap_tcmi_ops = {
- .read = omap_tcmi_read,
- .write = omap_tcmi_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void omap_tcmi_reset(struct omap_mpu_state_s *mpu)
-{
- mpu->tcmi_regs[0x00 >> 2] = 0x00000000;
- mpu->tcmi_regs[0x04 >> 2] = 0x00000000;
- mpu->tcmi_regs[0x08 >> 2] = 0x00000000;
- mpu->tcmi_regs[0x0c >> 2] = 0x00000010;
- mpu->tcmi_regs[0x10 >> 2] = 0x0010fffb;
- mpu->tcmi_regs[0x14 >> 2] = 0x0010fffb;
- mpu->tcmi_regs[0x18 >> 2] = 0x0010fffb;
- mpu->tcmi_regs[0x1c >> 2] = 0x0010fffb;
- mpu->tcmi_regs[0x20 >> 2] = 0x00618800;
- mpu->tcmi_regs[0x24 >> 2] = 0x00000037;
- mpu->tcmi_regs[0x28 >> 2] = 0x00000000;
- mpu->tcmi_regs[0x2c >> 2] = 0x00000000;
- mpu->tcmi_regs[0x30 >> 2] = 0x00000000;
- mpu->tcmi_regs[0x3c >> 2] = 0x00000003;
- mpu->tcmi_regs[0x40 >> 2] = 0x00000000;
-}
-
-static void omap_tcmi_init(MemoryRegion *memory, hwaddr base,
- struct omap_mpu_state_s *mpu)
-{
- memory_region_init_io(&mpu->tcmi_iomem, NULL, &omap_tcmi_ops, mpu,
- "omap-tcmi", 0x100);
- memory_region_add_subregion(memory, base, &mpu->tcmi_iomem);
- omap_tcmi_reset(mpu);
-}
-
-/* Digital phase-locked loops control */
-struct dpll_ctl_s {
- MemoryRegion iomem;
- uint16_t mode;
- omap_clk dpll;
-};
-
-static uint64_t omap_dpll_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct dpll_ctl_s *s = (struct dpll_ctl_s *) opaque;
-
- if (size != 2) {
- return omap_badwidth_read16(opaque, addr);
- }
-
- if (addr == 0x00) /* CTL_REG */
- return s->mode;
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_dpll_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct dpll_ctl_s *s = (struct dpll_ctl_s *) opaque;
- uint16_t diff;
- static const int bypass_div[4] = { 1, 2, 4, 4 };
- int div, mult;
-
- if (size != 2) {
- omap_badwidth_write16(opaque, addr, value);
- return;
- }
-
- if (addr == 0x00) { /* CTL_REG */
- /* See omap_ulpd_pm_write() too */
- diff = s->mode & value;
- s->mode = value & 0x2fff;
- if (diff & (0x3ff << 2)) {
- if (value & (1 << 4)) { /* PLL_ENABLE */
- div = ((value >> 5) & 3) + 1; /* PLL_DIV */
- mult = MIN((value >> 7) & 0x1f, 1); /* PLL_MULT */
- } else {
- div = bypass_div[((value >> 2) & 3)]; /* BYPASS_DIV */
- mult = 1;
- }
- omap_clk_setrate(s->dpll, div, mult);
- }
-
- /* Enter the desired mode. */
- s->mode = (s->mode & 0xfffe) | ((s->mode >> 4) & 1);
-
- /* Act as if the lock is restored. */
- s->mode |= 2;
- } else {
- OMAP_BAD_REG(addr);
- }
-}
-
-static const MemoryRegionOps omap_dpll_ops = {
- .read = omap_dpll_read,
- .write = omap_dpll_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void omap_dpll_reset(struct dpll_ctl_s *s)
-{
- s->mode = 0x2002;
- omap_clk_setrate(s->dpll, 1, 1);
-}
-
-static struct dpll_ctl_s *omap_dpll_init(MemoryRegion *memory,
- hwaddr base, omap_clk clk)
-{
- struct dpll_ctl_s *s = g_malloc0(sizeof(*s));
- memory_region_init_io(&s->iomem, NULL, &omap_dpll_ops, s, "omap-dpll", 0x100);
-
- s->dpll = clk;
- omap_dpll_reset(s);
-
- memory_region_add_subregion(memory, base, &s->iomem);
- return s;
-}
-
-/* MPU Clock/Reset/Power Mode Control */
-static uint64_t omap_clkm_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
-
- if (size != 2) {
- return omap_badwidth_read16(opaque, addr);
- }
-
- switch (addr) {
- case 0x00: /* ARM_CKCTL */
- return s->clkm.arm_ckctl;
-
- case 0x04: /* ARM_IDLECT1 */
- return s->clkm.arm_idlect1;
-
- case 0x08: /* ARM_IDLECT2 */
- return s->clkm.arm_idlect2;
-
- case 0x0c: /* ARM_EWUPCT */
- return s->clkm.arm_ewupct;
-
- case 0x10: /* ARM_RSTCT1 */
- return s->clkm.arm_rstct1;
-
- case 0x14: /* ARM_RSTCT2 */
- return s->clkm.arm_rstct2;
-
- case 0x18: /* ARM_SYSST */
- return (s->clkm.clocking_scheme << 11) | s->clkm.cold_start;
-
- case 0x1c: /* ARM_CKOUT1 */
- return s->clkm.arm_ckout1;
-
- case 0x20: /* ARM_CKOUT2 */
- break;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static inline void omap_clkm_ckctl_update(struct omap_mpu_state_s *s,
- uint16_t diff, uint16_t value)
-{
- omap_clk clk;
-
- if (diff & (1 << 14)) { /* ARM_INTHCK_SEL */
- if (value & (1 << 14))
- /* Reserved */;
- else {
- clk = omap_findclk(s, "arminth_ck");
- omap_clk_reparent(clk, omap_findclk(s, "tc_ck"));
- }
- }
- if (diff & (1 << 12)) { /* ARM_TIMXO */
- clk = omap_findclk(s, "armtim_ck");
- if (value & (1 << 12))
- omap_clk_reparent(clk, omap_findclk(s, "clkin"));
- else
- omap_clk_reparent(clk, omap_findclk(s, "ck_gen1"));
- }
- /* XXX: en_dspck */
- if (diff & (3 << 10)) { /* DSPMMUDIV */
- clk = omap_findclk(s, "dspmmu_ck");
- omap_clk_setrate(clk, 1 << ((value >> 10) & 3), 1);
- }
- if (diff & (3 << 8)) { /* TCDIV */
- clk = omap_findclk(s, "tc_ck");
- omap_clk_setrate(clk, 1 << ((value >> 8) & 3), 1);
- }
- if (diff & (3 << 6)) { /* DSPDIV */
- clk = omap_findclk(s, "dsp_ck");
- omap_clk_setrate(clk, 1 << ((value >> 6) & 3), 1);
- }
- if (diff & (3 << 4)) { /* ARMDIV */
- clk = omap_findclk(s, "arm_ck");
- omap_clk_setrate(clk, 1 << ((value >> 4) & 3), 1);
- }
- if (diff & (3 << 2)) { /* LCDDIV */
- clk = omap_findclk(s, "lcd_ck");
- omap_clk_setrate(clk, 1 << ((value >> 2) & 3), 1);
- }
- if (diff & (3 << 0)) { /* PERDIV */
- clk = omap_findclk(s, "armper_ck");
- omap_clk_setrate(clk, 1 << ((value >> 0) & 3), 1);
- }
-}
-
-static inline void omap_clkm_idlect1_update(struct omap_mpu_state_s *s,
- uint16_t diff, uint16_t value)
-{
- omap_clk clk;
-
- if (value & (1 << 11)) { /* SETARM_IDLE */
- cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_HALT);
- }
- if (!(value & (1 << 10))) /* WKUP_MODE */
- qemu_system_shutdown_request(); /* XXX: disable wakeup from IRQ */
-
-#define SET_CANIDLE(clock, bit) \
- if (diff & (1 << bit)) { \
- clk = omap_findclk(s, clock); \
- omap_clk_canidle(clk, (value >> bit) & 1); \
- }
- SET_CANIDLE("mpuwd_ck", 0) /* IDLWDT_ARM */
- SET_CANIDLE("armxor_ck", 1) /* IDLXORP_ARM */
- SET_CANIDLE("mpuper_ck", 2) /* IDLPER_ARM */
- SET_CANIDLE("lcd_ck", 3) /* IDLLCD_ARM */
- SET_CANIDLE("lb_ck", 4) /* IDLLB_ARM */
- SET_CANIDLE("hsab_ck", 5) /* IDLHSAB_ARM */
- SET_CANIDLE("tipb_ck", 6) /* IDLIF_ARM */
- SET_CANIDLE("dma_ck", 6) /* IDLIF_ARM */
- SET_CANIDLE("tc_ck", 6) /* IDLIF_ARM */
- SET_CANIDLE("dpll1", 7) /* IDLDPLL_ARM */
- SET_CANIDLE("dpll2", 7) /* IDLDPLL_ARM */
- SET_CANIDLE("dpll3", 7) /* IDLDPLL_ARM */
- SET_CANIDLE("mpui_ck", 8) /* IDLAPI_ARM */
- SET_CANIDLE("armtim_ck", 9) /* IDLTIM_ARM */
-}
-
-static inline void omap_clkm_idlect2_update(struct omap_mpu_state_s *s,
- uint16_t diff, uint16_t value)
-{
- omap_clk clk;
-
-#define SET_ONOFF(clock, bit) \
- if (diff & (1 << bit)) { \
- clk = omap_findclk(s, clock); \
- omap_clk_onoff(clk, (value >> bit) & 1); \
- }
- SET_ONOFF("mpuwd_ck", 0) /* EN_WDTCK */
- SET_ONOFF("armxor_ck", 1) /* EN_XORPCK */
- SET_ONOFF("mpuper_ck", 2) /* EN_PERCK */
- SET_ONOFF("lcd_ck", 3) /* EN_LCDCK */
- SET_ONOFF("lb_ck", 4) /* EN_LBCK */
- SET_ONOFF("hsab_ck", 5) /* EN_HSABCK */
- SET_ONOFF("mpui_ck", 6) /* EN_APICK */
- SET_ONOFF("armtim_ck", 7) /* EN_TIMCK */
- SET_CANIDLE("dma_ck", 8) /* DMACK_REQ */
- SET_ONOFF("arm_gpio_ck", 9) /* EN_GPIOCK */
- SET_ONOFF("lbfree_ck", 10) /* EN_LBFREECK */
-}
-
-static inline void omap_clkm_ckout1_update(struct omap_mpu_state_s *s,
- uint16_t diff, uint16_t value)
-{
- omap_clk clk;
-
- if (diff & (3 << 4)) { /* TCLKOUT */
- clk = omap_findclk(s, "tclk_out");
- switch ((value >> 4) & 3) {
- case 1:
- omap_clk_reparent(clk, omap_findclk(s, "ck_gen3"));
- omap_clk_onoff(clk, 1);
- break;
- case 2:
- omap_clk_reparent(clk, omap_findclk(s, "tc_ck"));
- omap_clk_onoff(clk, 1);
- break;
- default:
- omap_clk_onoff(clk, 0);
- }
- }
- if (diff & (3 << 2)) { /* DCLKOUT */
- clk = omap_findclk(s, "dclk_out");
- switch ((value >> 2) & 3) {
- case 0:
- omap_clk_reparent(clk, omap_findclk(s, "dspmmu_ck"));
- break;
- case 1:
- omap_clk_reparent(clk, omap_findclk(s, "ck_gen2"));
- break;
- case 2:
- omap_clk_reparent(clk, omap_findclk(s, "dsp_ck"));
- break;
- case 3:
- omap_clk_reparent(clk, omap_findclk(s, "ck_ref14"));
- break;
- }
- }
- if (diff & (3 << 0)) { /* ACLKOUT */
- clk = omap_findclk(s, "aclk_out");
- switch ((value >> 0) & 3) {
- case 1:
- omap_clk_reparent(clk, omap_findclk(s, "ck_gen1"));
- omap_clk_onoff(clk, 1);
- break;
- case 2:
- omap_clk_reparent(clk, omap_findclk(s, "arm_ck"));
- omap_clk_onoff(clk, 1);
- break;
- case 3:
- omap_clk_reparent(clk, omap_findclk(s, "ck_ref14"));
- omap_clk_onoff(clk, 1);
- break;
- default:
- omap_clk_onoff(clk, 0);
- }
- }
-}
-
-static void omap_clkm_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
- uint16_t diff;
- omap_clk clk;
- static const char *clkschemename[8] = {
- "fully synchronous", "fully asynchronous", "synchronous scalable",
- "mix mode 1", "mix mode 2", "bypass mode", "mix mode 3", "mix mode 4",
- };
-
- if (size != 2) {
- omap_badwidth_write16(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x00: /* ARM_CKCTL */
- diff = s->clkm.arm_ckctl ^ value;
- s->clkm.arm_ckctl = value & 0x7fff;
- omap_clkm_ckctl_update(s, diff, value);
- return;
-
- case 0x04: /* ARM_IDLECT1 */
- diff = s->clkm.arm_idlect1 ^ value;
- s->clkm.arm_idlect1 = value & 0x0fff;
- omap_clkm_idlect1_update(s, diff, value);
- return;
-
- case 0x08: /* ARM_IDLECT2 */
- diff = s->clkm.arm_idlect2 ^ value;
- s->clkm.arm_idlect2 = value & 0x07ff;
- omap_clkm_idlect2_update(s, diff, value);
- return;
-
- case 0x0c: /* ARM_EWUPCT */
- s->clkm.arm_ewupct = value & 0x003f;
- return;
-
- case 0x10: /* ARM_RSTCT1 */
- diff = s->clkm.arm_rstct1 ^ value;
- s->clkm.arm_rstct1 = value & 0x0007;
- if (value & 9) {
- qemu_system_reset_request();
- s->clkm.cold_start = 0xa;
- }
- if (diff & ~value & 4) { /* DSP_RST */
- omap_mpui_reset(s);
- omap_tipb_bridge_reset(s->private_tipb);
- omap_tipb_bridge_reset(s->public_tipb);
- }
- if (diff & 2) { /* DSP_EN */
- clk = omap_findclk(s, "dsp_ck");
- omap_clk_canidle(clk, (~value >> 1) & 1);
- }
- return;
-
- case 0x14: /* ARM_RSTCT2 */
- s->clkm.arm_rstct2 = value & 0x0001;
- return;
-
- case 0x18: /* ARM_SYSST */
- if ((s->clkm.clocking_scheme ^ (value >> 11)) & 7) {
- s->clkm.clocking_scheme = (value >> 11) & 7;
- printf("%s: clocking scheme set to %s\n", __FUNCTION__,
- clkschemename[s->clkm.clocking_scheme]);
- }
- s->clkm.cold_start &= value & 0x3f;
- return;
-
- case 0x1c: /* ARM_CKOUT1 */
- diff = s->clkm.arm_ckout1 ^ value;
- s->clkm.arm_ckout1 = value & 0x003f;
- omap_clkm_ckout1_update(s, diff, value);
- return;
-
- case 0x20: /* ARM_CKOUT2 */
- default:
- OMAP_BAD_REG(addr);
- }
-}
-
-static const MemoryRegionOps omap_clkm_ops = {
- .read = omap_clkm_read,
- .write = omap_clkm_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static uint64_t omap_clkdsp_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
- CPUState *cpu = CPU(s->cpu);
-
- if (size != 2) {
- return omap_badwidth_read16(opaque, addr);
- }
-
- switch (addr) {
- case 0x04: /* DSP_IDLECT1 */
- return s->clkm.dsp_idlect1;
-
- case 0x08: /* DSP_IDLECT2 */
- return s->clkm.dsp_idlect2;
-
- case 0x14: /* DSP_RSTCT2 */
- return s->clkm.dsp_rstct2;
-
- case 0x18: /* DSP_SYSST */
- cpu = CPU(s->cpu);
- return (s->clkm.clocking_scheme << 11) | s->clkm.cold_start |
- (cpu->halted << 6); /* Quite useless... */
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static inline void omap_clkdsp_idlect1_update(struct omap_mpu_state_s *s,
- uint16_t diff, uint16_t value)
-{
- omap_clk clk;
-
- SET_CANIDLE("dspxor_ck", 1); /* IDLXORP_DSP */
-}
-
-static inline void omap_clkdsp_idlect2_update(struct omap_mpu_state_s *s,
- uint16_t diff, uint16_t value)
-{
- omap_clk clk;
-
- SET_ONOFF("dspxor_ck", 1); /* EN_XORPCK */
-}
-
-static void omap_clkdsp_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
- uint16_t diff;
-
- if (size != 2) {
- omap_badwidth_write16(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x04: /* DSP_IDLECT1 */
- diff = s->clkm.dsp_idlect1 ^ value;
- s->clkm.dsp_idlect1 = value & 0x01f7;
- omap_clkdsp_idlect1_update(s, diff, value);
- break;
-
- case 0x08: /* DSP_IDLECT2 */
- s->clkm.dsp_idlect2 = value & 0x0037;
- diff = s->clkm.dsp_idlect1 ^ value;
- omap_clkdsp_idlect2_update(s, diff, value);
- break;
-
- case 0x14: /* DSP_RSTCT2 */
- s->clkm.dsp_rstct2 = value & 0x0001;
- break;
-
- case 0x18: /* DSP_SYSST */
- s->clkm.cold_start &= value & 0x3f;
- break;
-
- default:
- OMAP_BAD_REG(addr);
- }
-}
-
-static const MemoryRegionOps omap_clkdsp_ops = {
- .read = omap_clkdsp_read,
- .write = omap_clkdsp_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void omap_clkm_reset(struct omap_mpu_state_s *s)
-{
- if (s->wdt && s->wdt->reset)
- s->clkm.cold_start = 0x6;
- s->clkm.clocking_scheme = 0;
- omap_clkm_ckctl_update(s, ~0, 0x3000);
- s->clkm.arm_ckctl = 0x3000;
- omap_clkm_idlect1_update(s, s->clkm.arm_idlect1 ^ 0x0400, 0x0400);
- s->clkm.arm_idlect1 = 0x0400;
- omap_clkm_idlect2_update(s, s->clkm.arm_idlect2 ^ 0x0100, 0x0100);
- s->clkm.arm_idlect2 = 0x0100;
- s->clkm.arm_ewupct = 0x003f;
- s->clkm.arm_rstct1 = 0x0000;
- s->clkm.arm_rstct2 = 0x0000;
- s->clkm.arm_ckout1 = 0x0015;
- s->clkm.dpll1_mode = 0x2002;
- omap_clkdsp_idlect1_update(s, s->clkm.dsp_idlect1 ^ 0x0040, 0x0040);
- s->clkm.dsp_idlect1 = 0x0040;
- omap_clkdsp_idlect2_update(s, ~0, 0x0000);
- s->clkm.dsp_idlect2 = 0x0000;
- s->clkm.dsp_rstct2 = 0x0000;
-}
-
-static void omap_clkm_init(MemoryRegion *memory, hwaddr mpu_base,
- hwaddr dsp_base, struct omap_mpu_state_s *s)
-{
- memory_region_init_io(&s->clkm_iomem, NULL, &omap_clkm_ops, s,
- "omap-clkm", 0x100);
- memory_region_init_io(&s->clkdsp_iomem, NULL, &omap_clkdsp_ops, s,
- "omap-clkdsp", 0x1000);
-
- s->clkm.arm_idlect1 = 0x03ff;
- s->clkm.arm_idlect2 = 0x0100;
- s->clkm.dsp_idlect1 = 0x0002;
- omap_clkm_reset(s);
- s->clkm.cold_start = 0x3a;
-
- memory_region_add_subregion(memory, mpu_base, &s->clkm_iomem);
- memory_region_add_subregion(memory, dsp_base, &s->clkdsp_iomem);
-}
-
-/* MPU I/O */
-struct omap_mpuio_s {
- qemu_irq irq;
- qemu_irq kbd_irq;
- qemu_irq *in;
- qemu_irq handler[16];
- qemu_irq wakeup;
- MemoryRegion iomem;
-
- uint16_t inputs;
- uint16_t outputs;
- uint16_t dir;
- uint16_t edge;
- uint16_t mask;
- uint16_t ints;
-
- uint16_t debounce;
- uint16_t latch;
- uint8_t event;
-
- uint8_t buttons[5];
- uint8_t row_latch;
- uint8_t cols;
- int kbd_mask;
- int clk;
-};
-
-static void omap_mpuio_set(void *opaque, int line, int level)
-{
- struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque;
- uint16_t prev = s->inputs;
-
- if (level)
- s->inputs |= 1 << line;
- else
- s->inputs &= ~(1 << line);
-
- if (((1 << line) & s->dir & ~s->mask) && s->clk) {
- if ((s->edge & s->inputs & ~prev) | (~s->edge & ~s->inputs & prev)) {
- s->ints |= 1 << line;
- qemu_irq_raise(s->irq);
- /* TODO: wakeup */
- }
- if ((s->event & (1 << 0)) && /* SET_GPIO_EVENT_MODE */
- (s->event >> 1) == line) /* PIN_SELECT */
- s->latch = s->inputs;
- }
-}
-
-static void omap_mpuio_kbd_update(struct omap_mpuio_s *s)
-{
- int i;
- uint8_t *row, rows = 0, cols = ~s->cols;
-
- for (row = s->buttons + 4, i = 1 << 4; i; row --, i >>= 1)
- if (*row & cols)
- rows |= i;
-
- qemu_set_irq(s->kbd_irq, rows && !s->kbd_mask && s->clk);
- s->row_latch = ~rows;
-}
-
-static uint64_t omap_mpuio_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque;
- int offset = addr & OMAP_MPUI_REG_MASK;
- uint16_t ret;
-
- if (size != 2) {
- return omap_badwidth_read16(opaque, addr);
- }
-
- switch (offset) {
- case 0x00: /* INPUT_LATCH */
- return s->inputs;
-
- case 0x04: /* OUTPUT_REG */
- return s->outputs;
-
- case 0x08: /* IO_CNTL */
- return s->dir;
-
- case 0x10: /* KBR_LATCH */
- return s->row_latch;
-
- case 0x14: /* KBC_REG */
- return s->cols;
-
- case 0x18: /* GPIO_EVENT_MODE_REG */
- return s->event;
-
- case 0x1c: /* GPIO_INT_EDGE_REG */
- return s->edge;
-
- case 0x20: /* KBD_INT */
- return (~s->row_latch & 0x1f) && !s->kbd_mask;
-
- case 0x24: /* GPIO_INT */
- ret = s->ints;
- s->ints &= s->mask;
- if (ret)
- qemu_irq_lower(s->irq);
- return ret;
-
- case 0x28: /* KBD_MASKIT */
- return s->kbd_mask;
-
- case 0x2c: /* GPIO_MASKIT */
- return s->mask;
-
- case 0x30: /* GPIO_DEBOUNCING_REG */
- return s->debounce;
-
- case 0x34: /* GPIO_LATCH_REG */
- return s->latch;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_mpuio_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque;
- int offset = addr & OMAP_MPUI_REG_MASK;
- uint16_t diff;
- int ln;
-
- if (size != 2) {
- omap_badwidth_write16(opaque, addr, value);
- return;
- }
-
- switch (offset) {
- case 0x04: /* OUTPUT_REG */
- diff = (s->outputs ^ value) & ~s->dir;
- s->outputs = value;
- while ((ln = ctz32(diff)) != 32) {
- if (s->handler[ln])
- qemu_set_irq(s->handler[ln], (value >> ln) & 1);
- diff &= ~(1 << ln);
- }
- break;
-
- case 0x08: /* IO_CNTL */
- diff = s->outputs & (s->dir ^ value);
- s->dir = value;
-
- value = s->outputs & ~s->dir;
- while ((ln = ctz32(diff)) != 32) {
- if (s->handler[ln])
- qemu_set_irq(s->handler[ln], (value >> ln) & 1);
- diff &= ~(1 << ln);
- }
- break;
-
- case 0x14: /* KBC_REG */
- s->cols = value;
- omap_mpuio_kbd_update(s);
- break;
-
- case 0x18: /* GPIO_EVENT_MODE_REG */
- s->event = value & 0x1f;
- break;
-
- case 0x1c: /* GPIO_INT_EDGE_REG */
- s->edge = value;
- break;
-
- case 0x28: /* KBD_MASKIT */
- s->kbd_mask = value & 1;
- omap_mpuio_kbd_update(s);
- break;
-
- case 0x2c: /* GPIO_MASKIT */
- s->mask = value;
- break;
-
- case 0x30: /* GPIO_DEBOUNCING_REG */
- s->debounce = value & 0x1ff;
- break;
-
- case 0x00: /* INPUT_LATCH */
- case 0x10: /* KBR_LATCH */
- case 0x20: /* KBD_INT */
- case 0x24: /* GPIO_INT */
- case 0x34: /* GPIO_LATCH_REG */
- OMAP_RO_REG(addr);
- return;
-
- default:
- OMAP_BAD_REG(addr);
- return;
- }
-}
-
-static const MemoryRegionOps omap_mpuio_ops = {
- .read = omap_mpuio_read,
- .write = omap_mpuio_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void omap_mpuio_reset(struct omap_mpuio_s *s)
-{
- s->inputs = 0;
- s->outputs = 0;
- s->dir = ~0;
- s->event = 0;
- s->edge = 0;
- s->kbd_mask = 0;
- s->mask = 0;
- s->debounce = 0;
- s->latch = 0;
- s->ints = 0;
- s->row_latch = 0x1f;
- s->clk = 1;
-}
-
-static void omap_mpuio_onoff(void *opaque, int line, int on)
-{
- struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque;
-
- s->clk = on;
- if (on)
- omap_mpuio_kbd_update(s);
-}
-
-static struct omap_mpuio_s *omap_mpuio_init(MemoryRegion *memory,
- hwaddr base,
- qemu_irq kbd_int, qemu_irq gpio_int, qemu_irq wakeup,
- omap_clk clk)
-{
- struct omap_mpuio_s *s = g_new0(struct omap_mpuio_s, 1);
-
- s->irq = gpio_int;
- s->kbd_irq = kbd_int;
- s->wakeup = wakeup;
- s->in = qemu_allocate_irqs(omap_mpuio_set, s, 16);
- omap_mpuio_reset(s);
-
- memory_region_init_io(&s->iomem, NULL, &omap_mpuio_ops, s,
- "omap-mpuio", 0x800);
- memory_region_add_subregion(memory, base, &s->iomem);
-
- omap_clk_adduser(clk, qemu_allocate_irq(omap_mpuio_onoff, s, 0));
-
- return s;
-}
-
-qemu_irq *omap_mpuio_in_get(struct omap_mpuio_s *s)
-{
- return s->in;
-}
-
-void omap_mpuio_out_set(struct omap_mpuio_s *s, int line, qemu_irq handler)
-{
- if (line >= 16 || line < 0)
- hw_error("%s: No GPIO line %i\n", __FUNCTION__, line);
- s->handler[line] = handler;
-}
-
-void omap_mpuio_key(struct omap_mpuio_s *s, int row, int col, int down)
-{
- if (row >= 5 || row < 0)
- hw_error("%s: No key %i-%i\n", __FUNCTION__, col, row);
-
- if (down)
- s->buttons[row] |= 1 << col;
- else
- s->buttons[row] &= ~(1 << col);
-
- omap_mpuio_kbd_update(s);
-}
-
-/* MicroWire Interface */
-struct omap_uwire_s {
- MemoryRegion iomem;
- qemu_irq txirq;
- qemu_irq rxirq;
- qemu_irq txdrq;
-
- uint16_t txbuf;
- uint16_t rxbuf;
- uint16_t control;
- uint16_t setup[5];
-
- uWireSlave *chip[4];
-};
-
-static void omap_uwire_transfer_start(struct omap_uwire_s *s)
-{
- int chipselect = (s->control >> 10) & 3; /* INDEX */
- uWireSlave *slave = s->chip[chipselect];
-
- if ((s->control >> 5) & 0x1f) { /* NB_BITS_WR */
- if (s->control & (1 << 12)) /* CS_CMD */
- if (slave && slave->send)
- slave->send(slave->opaque,
- s->txbuf >> (16 - ((s->control >> 5) & 0x1f)));
- s->control &= ~(1 << 14); /* CSRB */
- /* TODO: depending on s->setup[4] bits [1:0] assert an IRQ or
- * a DRQ. When is the level IRQ supposed to be reset? */
- }
-
- if ((s->control >> 0) & 0x1f) { /* NB_BITS_RD */
- if (s->control & (1 << 12)) /* CS_CMD */
- if (slave && slave->receive)
- s->rxbuf = slave->receive(slave->opaque);
- s->control |= 1 << 15; /* RDRB */
- /* TODO: depending on s->setup[4] bits [1:0] assert an IRQ or
- * a DRQ. When is the level IRQ supposed to be reset? */
- }
-}
-
-static uint64_t omap_uwire_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_uwire_s *s = (struct omap_uwire_s *) opaque;
- int offset = addr & OMAP_MPUI_REG_MASK;
-
- if (size != 2) {
- return omap_badwidth_read16(opaque, addr);
- }
-
- switch (offset) {
- case 0x00: /* RDR */
- s->control &= ~(1 << 15); /* RDRB */
- return s->rxbuf;
-
- case 0x04: /* CSR */
- return s->control;
-
- case 0x08: /* SR1 */
- return s->setup[0];
- case 0x0c: /* SR2 */
- return s->setup[1];
- case 0x10: /* SR3 */
- return s->setup[2];
- case 0x14: /* SR4 */
- return s->setup[3];
- case 0x18: /* SR5 */
- return s->setup[4];
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_uwire_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_uwire_s *s = (struct omap_uwire_s *) opaque;
- int offset = addr & OMAP_MPUI_REG_MASK;
-
- if (size != 2) {
- omap_badwidth_write16(opaque, addr, value);
- return;
- }
-
- switch (offset) {
- case 0x00: /* TDR */
- s->txbuf = value; /* TD */
- if ((s->setup[4] & (1 << 2)) && /* AUTO_TX_EN */
- ((s->setup[4] & (1 << 3)) || /* CS_TOGGLE_TX_EN */
- (s->control & (1 << 12)))) { /* CS_CMD */
- s->control |= 1 << 14; /* CSRB */
- omap_uwire_transfer_start(s);
- }
- break;
-
- case 0x04: /* CSR */
- s->control = value & 0x1fff;
- if (value & (1 << 13)) /* START */
- omap_uwire_transfer_start(s);
- break;
-
- case 0x08: /* SR1 */
- s->setup[0] = value & 0x003f;
- break;
-
- case 0x0c: /* SR2 */
- s->setup[1] = value & 0x0fc0;
- break;
-
- case 0x10: /* SR3 */
- s->setup[2] = value & 0x0003;
- break;
-
- case 0x14: /* SR4 */
- s->setup[3] = value & 0x0001;
- break;
-
- case 0x18: /* SR5 */
- s->setup[4] = value & 0x000f;
- break;
-
- default:
- OMAP_BAD_REG(addr);
- return;
- }
-}
-
-static const MemoryRegionOps omap_uwire_ops = {
- .read = omap_uwire_read,
- .write = omap_uwire_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void omap_uwire_reset(struct omap_uwire_s *s)
-{
- s->control = 0;
- s->setup[0] = 0;
- s->setup[1] = 0;
- s->setup[2] = 0;
- s->setup[3] = 0;
- s->setup[4] = 0;
-}
-
-static struct omap_uwire_s *omap_uwire_init(MemoryRegion *system_memory,
- hwaddr base,
- qemu_irq txirq, qemu_irq rxirq,
- qemu_irq dma,
- omap_clk clk)
-{
- struct omap_uwire_s *s = g_new0(struct omap_uwire_s, 1);
-
- s->txirq = txirq;
- s->rxirq = rxirq;
- s->txdrq = dma;
- omap_uwire_reset(s);
-
- memory_region_init_io(&s->iomem, NULL, &omap_uwire_ops, s, "omap-uwire", 0x800);
- memory_region_add_subregion(system_memory, base, &s->iomem);
-
- return s;
-}
-
-void omap_uwire_attach(struct omap_uwire_s *s,
- uWireSlave *slave, int chipselect)
-{
- if (chipselect < 0 || chipselect > 3) {
- fprintf(stderr, "%s: Bad chipselect %i\n", __FUNCTION__, chipselect);
- exit(-1);
- }
-
- s->chip[chipselect] = slave;
-}
-
-/* Pseudonoise Pulse-Width Light Modulator */
-struct omap_pwl_s {
- MemoryRegion iomem;
- uint8_t output;
- uint8_t level;
- uint8_t enable;
- int clk;
-};
-
-static void omap_pwl_update(struct omap_pwl_s *s)
-{
- int output = (s->clk && s->enable) ? s->level : 0;
-
- if (output != s->output) {
- s->output = output;
- printf("%s: Backlight now at %i/256\n", __FUNCTION__, output);
- }
-}
-
-static uint64_t omap_pwl_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_pwl_s *s = (struct omap_pwl_s *) opaque;
- int offset = addr & OMAP_MPUI_REG_MASK;
-
- if (size != 1) {
- return omap_badwidth_read8(opaque, addr);
- }
-
- switch (offset) {
- case 0x00: /* PWL_LEVEL */
- return s->level;
- case 0x04: /* PWL_CTRL */
- return s->enable;
- }
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_pwl_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_pwl_s *s = (struct omap_pwl_s *) opaque;
- int offset = addr & OMAP_MPUI_REG_MASK;
-
- if (size != 1) {
- omap_badwidth_write8(opaque, addr, value);
- return;
- }
-
- switch (offset) {
- case 0x00: /* PWL_LEVEL */
- s->level = value;
- omap_pwl_update(s);
- break;
- case 0x04: /* PWL_CTRL */
- s->enable = value & 1;
- omap_pwl_update(s);
- break;
- default:
- OMAP_BAD_REG(addr);
- return;
- }
-}
-
-static const MemoryRegionOps omap_pwl_ops = {
- .read = omap_pwl_read,
- .write = omap_pwl_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void omap_pwl_reset(struct omap_pwl_s *s)
-{
- s->output = 0;
- s->level = 0;
- s->enable = 0;
- s->clk = 1;
- omap_pwl_update(s);
-}
-
-static void omap_pwl_clk_update(void *opaque, int line, int on)
-{
- struct omap_pwl_s *s = (struct omap_pwl_s *) opaque;
-
- s->clk = on;
- omap_pwl_update(s);
-}
-
-static struct omap_pwl_s *omap_pwl_init(MemoryRegion *system_memory,
- hwaddr base,
- omap_clk clk)
-{
- struct omap_pwl_s *s = g_malloc0(sizeof(*s));
-
- omap_pwl_reset(s);
-
- memory_region_init_io(&s->iomem, NULL, &omap_pwl_ops, s,
- "omap-pwl", 0x800);
- memory_region_add_subregion(system_memory, base, &s->iomem);
-
- omap_clk_adduser(clk, qemu_allocate_irq(omap_pwl_clk_update, s, 0));
- return s;
-}
-
-/* Pulse-Width Tone module */
-struct omap_pwt_s {
- MemoryRegion iomem;
- uint8_t frc;
- uint8_t vrc;
- uint8_t gcr;
- omap_clk clk;
-};
-
-static uint64_t omap_pwt_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_pwt_s *s = (struct omap_pwt_s *) opaque;
- int offset = addr & OMAP_MPUI_REG_MASK;
-
- if (size != 1) {
- return omap_badwidth_read8(opaque, addr);
- }
-
- switch (offset) {
- case 0x00: /* FRC */
- return s->frc;
- case 0x04: /* VCR */
- return s->vrc;
- case 0x08: /* GCR */
- return s->gcr;
- }
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_pwt_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_pwt_s *s = (struct omap_pwt_s *) opaque;
- int offset = addr & OMAP_MPUI_REG_MASK;
-
- if (size != 1) {
- omap_badwidth_write8(opaque, addr, value);
- return;
- }
-
- switch (offset) {
- case 0x00: /* FRC */
- s->frc = value & 0x3f;
- break;
- case 0x04: /* VRC */
- if ((value ^ s->vrc) & 1) {
- if (value & 1)
- printf("%s: %iHz buzz on\n", __FUNCTION__, (int)
- /* 1.5 MHz from a 12-MHz or 13-MHz PWT_CLK */
- ((omap_clk_getrate(s->clk) >> 3) /
- /* Pre-multiplexer divider */
- ((s->gcr & 2) ? 1 : 154) /
- /* Octave multiplexer */
- (2 << (value & 3)) *
- /* 101/107 divider */
- ((value & (1 << 2)) ? 101 : 107) *
- /* 49/55 divider */
- ((value & (1 << 3)) ? 49 : 55) *
- /* 50/63 divider */
- ((value & (1 << 4)) ? 50 : 63) *
- /* 80/127 divider */
- ((value & (1 << 5)) ? 80 : 127) /
- (107 * 55 * 63 * 127)));
- else
- printf("%s: silence!\n", __FUNCTION__);
- }
- s->vrc = value & 0x7f;
- break;
- case 0x08: /* GCR */
- s->gcr = value & 3;
- break;
- default:
- OMAP_BAD_REG(addr);
- return;
- }
-}
-
-static const MemoryRegionOps omap_pwt_ops = {
- .read =omap_pwt_read,
- .write = omap_pwt_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void omap_pwt_reset(struct omap_pwt_s *s)
-{
- s->frc = 0;
- s->vrc = 0;
- s->gcr = 0;
-}
-
-static struct omap_pwt_s *omap_pwt_init(MemoryRegion *system_memory,
- hwaddr base,
- omap_clk clk)
-{
- struct omap_pwt_s *s = g_malloc0(sizeof(*s));
- s->clk = clk;
- omap_pwt_reset(s);
-
- memory_region_init_io(&s->iomem, NULL, &omap_pwt_ops, s,
- "omap-pwt", 0x800);
- memory_region_add_subregion(system_memory, base, &s->iomem);
- return s;
-}
-
-/* Real-time Clock module */
-struct omap_rtc_s {
- MemoryRegion iomem;
- qemu_irq irq;
- qemu_irq alarm;
- QEMUTimer *clk;
-
- uint8_t interrupts;
- uint8_t status;
- int16_t comp_reg;
- int running;
- int pm_am;
- int auto_comp;
- int round;
- struct tm alarm_tm;
- time_t alarm_ti;
-
- struct tm current_tm;
- time_t ti;
- uint64_t tick;
-};
-
-static void omap_rtc_interrupts_update(struct omap_rtc_s *s)
-{
- /* s->alarm is level-triggered */
- qemu_set_irq(s->alarm, (s->status >> 6) & 1);
-}
-
-static void omap_rtc_alarm_update(struct omap_rtc_s *s)
-{
- s->alarm_ti = mktimegm(&s->alarm_tm);
- if (s->alarm_ti == -1)
- printf("%s: conversion failed\n", __FUNCTION__);
-}
-
-static uint64_t omap_rtc_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_rtc_s *s = (struct omap_rtc_s *) opaque;
- int offset = addr & OMAP_MPUI_REG_MASK;
- uint8_t i;
-
- if (size != 1) {
- return omap_badwidth_read8(opaque, addr);
- }
-
- switch (offset) {
- case 0x00: /* SECONDS_REG */
- return to_bcd(s->current_tm.tm_sec);
-
- case 0x04: /* MINUTES_REG */
- return to_bcd(s->current_tm.tm_min);
-
- case 0x08: /* HOURS_REG */
- if (s->pm_am)
- return ((s->current_tm.tm_hour > 11) << 7) |
- to_bcd(((s->current_tm.tm_hour - 1) % 12) + 1);
- else
- return to_bcd(s->current_tm.tm_hour);
-
- case 0x0c: /* DAYS_REG */
- return to_bcd(s->current_tm.tm_mday);
-
- case 0x10: /* MONTHS_REG */
- return to_bcd(s->current_tm.tm_mon + 1);
-
- case 0x14: /* YEARS_REG */
- return to_bcd(s->current_tm.tm_year % 100);
-
- case 0x18: /* WEEK_REG */
- return s->current_tm.tm_wday;
-
- case 0x20: /* ALARM_SECONDS_REG */
- return to_bcd(s->alarm_tm.tm_sec);
-
- case 0x24: /* ALARM_MINUTES_REG */
- return to_bcd(s->alarm_tm.tm_min);
-
- case 0x28: /* ALARM_HOURS_REG */
- if (s->pm_am)
- return ((s->alarm_tm.tm_hour > 11) << 7) |
- to_bcd(((s->alarm_tm.tm_hour - 1) % 12) + 1);
- else
- return to_bcd(s->alarm_tm.tm_hour);
-
- case 0x2c: /* ALARM_DAYS_REG */
- return to_bcd(s->alarm_tm.tm_mday);
-
- case 0x30: /* ALARM_MONTHS_REG */
- return to_bcd(s->alarm_tm.tm_mon + 1);
-
- case 0x34: /* ALARM_YEARS_REG */
- return to_bcd(s->alarm_tm.tm_year % 100);
-
- case 0x40: /* RTC_CTRL_REG */
- return (s->pm_am << 3) | (s->auto_comp << 2) |
- (s->round << 1) | s->running;
-
- case 0x44: /* RTC_STATUS_REG */
- i = s->status;
- s->status &= ~0x3d;
- return i;
-
- case 0x48: /* RTC_INTERRUPTS_REG */
- return s->interrupts;
-
- case 0x4c: /* RTC_COMP_LSB_REG */
- return ((uint16_t) s->comp_reg) & 0xff;
-
- case 0x50: /* RTC_COMP_MSB_REG */
- return ((uint16_t) s->comp_reg) >> 8;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_rtc_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_rtc_s *s = (struct omap_rtc_s *) opaque;
- int offset = addr & OMAP_MPUI_REG_MASK;
- struct tm new_tm;
- time_t ti[2];
-
- if (size != 1) {
- omap_badwidth_write8(opaque, addr, value);
- return;
- }
-
- switch (offset) {
- case 0x00: /* SECONDS_REG */
-#ifdef ALMDEBUG
- printf("RTC SEC_REG <-- %02x\n", value);
-#endif
- s->ti -= s->current_tm.tm_sec;
- s->ti += from_bcd(value);
- return;
-
- case 0x04: /* MINUTES_REG */
-#ifdef ALMDEBUG
- printf("RTC MIN_REG <-- %02x\n", value);
-#endif
- s->ti -= s->current_tm.tm_min * 60;
- s->ti += from_bcd(value) * 60;
- return;
-
- case 0x08: /* HOURS_REG */
-#ifdef ALMDEBUG
- printf("RTC HRS_REG <-- %02x\n", value);
-#endif
- s->ti -= s->current_tm.tm_hour * 3600;
- if (s->pm_am) {
- s->ti += (from_bcd(value & 0x3f) & 12) * 3600;
- s->ti += ((value >> 7) & 1) * 43200;
- } else
- s->ti += from_bcd(value & 0x3f) * 3600;
- return;
-
- case 0x0c: /* DAYS_REG */
-#ifdef ALMDEBUG
- printf("RTC DAY_REG <-- %02x\n", value);
-#endif
- s->ti -= s->current_tm.tm_mday * 86400;
- s->ti += from_bcd(value) * 86400;
- return;
-
- case 0x10: /* MONTHS_REG */
-#ifdef ALMDEBUG
- printf("RTC MTH_REG <-- %02x\n", value);
-#endif
- memcpy(&new_tm, &s->current_tm, sizeof(new_tm));
- new_tm.tm_mon = from_bcd(value);
- ti[0] = mktimegm(&s->current_tm);
- ti[1] = mktimegm(&new_tm);
-
- if (ti[0] != -1 && ti[1] != -1) {
- s->ti -= ti[0];
- s->ti += ti[1];
- } else {
- /* A less accurate version */
- s->ti -= s->current_tm.tm_mon * 2592000;
- s->ti += from_bcd(value) * 2592000;
- }
- return;
-
- case 0x14: /* YEARS_REG */
-#ifdef ALMDEBUG
- printf("RTC YRS_REG <-- %02x\n", value);
-#endif
- memcpy(&new_tm, &s->current_tm, sizeof(new_tm));
- new_tm.tm_year += from_bcd(value) - (new_tm.tm_year % 100);
- ti[0] = mktimegm(&s->current_tm);
- ti[1] = mktimegm(&new_tm);
-
- if (ti[0] != -1 && ti[1] != -1) {
- s->ti -= ti[0];
- s->ti += ti[1];
- } else {
- /* A less accurate version */
- s->ti -= (time_t)(s->current_tm.tm_year % 100) * 31536000;
- s->ti += (time_t)from_bcd(value) * 31536000;
- }
- return;
-
- case 0x18: /* WEEK_REG */
- return; /* Ignored */
-
- case 0x20: /* ALARM_SECONDS_REG */
-#ifdef ALMDEBUG
- printf("ALM SEC_REG <-- %02x\n", value);
-#endif
- s->alarm_tm.tm_sec = from_bcd(value);
- omap_rtc_alarm_update(s);
- return;
-
- case 0x24: /* ALARM_MINUTES_REG */
-#ifdef ALMDEBUG
- printf("ALM MIN_REG <-- %02x\n", value);
-#endif
- s->alarm_tm.tm_min = from_bcd(value);
- omap_rtc_alarm_update(s);
- return;
-
- case 0x28: /* ALARM_HOURS_REG */
-#ifdef ALMDEBUG
- printf("ALM HRS_REG <-- %02x\n", value);
-#endif
- if (s->pm_am)
- s->alarm_tm.tm_hour =
- ((from_bcd(value & 0x3f)) % 12) +
- ((value >> 7) & 1) * 12;
- else
- s->alarm_tm.tm_hour = from_bcd(value);
- omap_rtc_alarm_update(s);
- return;
-
- case 0x2c: /* ALARM_DAYS_REG */
-#ifdef ALMDEBUG
- printf("ALM DAY_REG <-- %02x\n", value);
-#endif
- s->alarm_tm.tm_mday = from_bcd(value);
- omap_rtc_alarm_update(s);
- return;
-
- case 0x30: /* ALARM_MONTHS_REG */
-#ifdef ALMDEBUG
- printf("ALM MON_REG <-- %02x\n", value);
-#endif
- s->alarm_tm.tm_mon = from_bcd(value);
- omap_rtc_alarm_update(s);
- return;
-
- case 0x34: /* ALARM_YEARS_REG */
-#ifdef ALMDEBUG
- printf("ALM YRS_REG <-- %02x\n", value);
-#endif
- s->alarm_tm.tm_year = from_bcd(value);
- omap_rtc_alarm_update(s);
- return;
-
- case 0x40: /* RTC_CTRL_REG */
-#ifdef ALMDEBUG
- printf("RTC CONTROL <-- %02x\n", value);
-#endif
- s->pm_am = (value >> 3) & 1;
- s->auto_comp = (value >> 2) & 1;
- s->round = (value >> 1) & 1;
- s->running = value & 1;
- s->status &= 0xfd;
- s->status |= s->running << 1;
- return;
-
- case 0x44: /* RTC_STATUS_REG */
-#ifdef ALMDEBUG
- printf("RTC STATUSL <-- %02x\n", value);
-#endif
- s->status &= ~((value & 0xc0) ^ 0x80);
- omap_rtc_interrupts_update(s);
- return;
-
- case 0x48: /* RTC_INTERRUPTS_REG */
-#ifdef ALMDEBUG
- printf("RTC INTRS <-- %02x\n", value);
-#endif
- s->interrupts = value;
- return;
-
- case 0x4c: /* RTC_COMP_LSB_REG */
-#ifdef ALMDEBUG
- printf("RTC COMPLSB <-- %02x\n", value);
-#endif
- s->comp_reg &= 0xff00;
- s->comp_reg |= 0x00ff & value;
- return;
-
- case 0x50: /* RTC_COMP_MSB_REG */
-#ifdef ALMDEBUG
- printf("RTC COMPMSB <-- %02x\n", value);
-#endif
- s->comp_reg &= 0x00ff;
- s->comp_reg |= 0xff00 & (value << 8);
- return;
-
- default:
- OMAP_BAD_REG(addr);
- return;
- }
-}
-
-static const MemoryRegionOps omap_rtc_ops = {
- .read = omap_rtc_read,
- .write = omap_rtc_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void omap_rtc_tick(void *opaque)
-{
- struct omap_rtc_s *s = opaque;
-
- if (s->round) {
- /* Round to nearest full minute. */
- if (s->current_tm.tm_sec < 30)
- s->ti -= s->current_tm.tm_sec;
- else
- s->ti += 60 - s->current_tm.tm_sec;
-
- s->round = 0;
- }
-
- localtime_r(&s->ti, &s->current_tm);
-
- if ((s->interrupts & 0x08) && s->ti == s->alarm_ti) {
- s->status |= 0x40;
- omap_rtc_interrupts_update(s);
- }
-
- if (s->interrupts & 0x04)
- switch (s->interrupts & 3) {
- case 0:
- s->status |= 0x04;
- qemu_irq_pulse(s->irq);
- break;
- case 1:
- if (s->current_tm.tm_sec)
- break;
- s->status |= 0x08;
- qemu_irq_pulse(s->irq);
- break;
- case 2:
- if (s->current_tm.tm_sec || s->current_tm.tm_min)
- break;
- s->status |= 0x10;
- qemu_irq_pulse(s->irq);
- break;
- case 3:
- if (s->current_tm.tm_sec ||
- s->current_tm.tm_min || s->current_tm.tm_hour)
- break;
- s->status |= 0x20;
- qemu_irq_pulse(s->irq);
- break;
- }
-
- /* Move on */
- if (s->running)
- s->ti ++;
- s->tick += 1000;
-
- /*
- * Every full hour add a rough approximation of the compensation
- * register to the 32kHz Timer (which drives the RTC) value.
- */
- if (s->auto_comp && !s->current_tm.tm_sec && !s->current_tm.tm_min)
- s->tick += s->comp_reg * 1000 / 32768;
-
- timer_mod(s->clk, s->tick);
-}
-
-static void omap_rtc_reset(struct omap_rtc_s *s)
-{
- struct tm tm;
-
- s->interrupts = 0;
- s->comp_reg = 0;
- s->running = 0;
- s->pm_am = 0;
- s->auto_comp = 0;
- s->round = 0;
- s->tick = qemu_clock_get_ms(rtc_clock);
- memset(&s->alarm_tm, 0, sizeof(s->alarm_tm));
- s->alarm_tm.tm_mday = 0x01;
- s->status = 1 << 7;
- qemu_get_timedate(&tm, 0);
- s->ti = mktimegm(&tm);
-
- omap_rtc_alarm_update(s);
- omap_rtc_tick(s);
-}
-
-static struct omap_rtc_s *omap_rtc_init(MemoryRegion *system_memory,
- hwaddr base,
- qemu_irq timerirq, qemu_irq alarmirq,
- omap_clk clk)
-{
- struct omap_rtc_s *s = g_new0(struct omap_rtc_s, 1);
-
- s->irq = timerirq;
- s->alarm = alarmirq;
- s->clk = timer_new_ms(rtc_clock, omap_rtc_tick, s);
-
- omap_rtc_reset(s);
-
- memory_region_init_io(&s->iomem, NULL, &omap_rtc_ops, s,
- "omap-rtc", 0x800);
- memory_region_add_subregion(system_memory, base, &s->iomem);
-
- return s;
-}
-
-/* Multi-channel Buffered Serial Port interfaces */
-struct omap_mcbsp_s {
- MemoryRegion iomem;
- qemu_irq txirq;
- qemu_irq rxirq;
- qemu_irq txdrq;
- qemu_irq rxdrq;
-
- uint16_t spcr[2];
- uint16_t rcr[2];
- uint16_t xcr[2];
- uint16_t srgr[2];
- uint16_t mcr[2];
- uint16_t pcr;
- uint16_t rcer[8];
- uint16_t xcer[8];
- int tx_rate;
- int rx_rate;
- int tx_req;
- int rx_req;
-
- I2SCodec *codec;
- QEMUTimer *source_timer;
- QEMUTimer *sink_timer;
-};
-
-static void omap_mcbsp_intr_update(struct omap_mcbsp_s *s)
-{
- int irq;
-
- switch ((s->spcr[0] >> 4) & 3) { /* RINTM */
- case 0:
- irq = (s->spcr[0] >> 1) & 1; /* RRDY */
- break;
- case 3:
- irq = (s->spcr[0] >> 3) & 1; /* RSYNCERR */
- break;
- default:
- irq = 0;
- break;
- }
-
- if (irq)
- qemu_irq_pulse(s->rxirq);
-
- switch ((s->spcr[1] >> 4) & 3) { /* XINTM */
- case 0:
- irq = (s->spcr[1] >> 1) & 1; /* XRDY */
- break;
- case 3:
- irq = (s->spcr[1] >> 3) & 1; /* XSYNCERR */
- break;
- default:
- irq = 0;
- break;
- }
-
- if (irq)
- qemu_irq_pulse(s->txirq);
-}
-
-static void omap_mcbsp_rx_newdata(struct omap_mcbsp_s *s)
-{
- if ((s->spcr[0] >> 1) & 1) /* RRDY */
- s->spcr[0] |= 1 << 2; /* RFULL */
- s->spcr[0] |= 1 << 1; /* RRDY */
- qemu_irq_raise(s->rxdrq);
- omap_mcbsp_intr_update(s);
-}
-
-static void omap_mcbsp_source_tick(void *opaque)
-{
- struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque;
- static const int bps[8] = { 0, 1, 1, 2, 2, 2, -255, -255 };
-
- if (!s->rx_rate)
- return;
- if (s->rx_req)
- printf("%s: Rx FIFO overrun\n", __FUNCTION__);
-
- s->rx_req = s->rx_rate << bps[(s->rcr[0] >> 5) & 7];
-
- omap_mcbsp_rx_newdata(s);
- timer_mod(s->source_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- NANOSECONDS_PER_SECOND);
-}
-
-static void omap_mcbsp_rx_start(struct omap_mcbsp_s *s)
-{
- if (!s->codec || !s->codec->rts)
- omap_mcbsp_source_tick(s);
- else if (s->codec->in.len) {
- s->rx_req = s->codec->in.len;
- omap_mcbsp_rx_newdata(s);
- }
-}
-
-static void omap_mcbsp_rx_stop(struct omap_mcbsp_s *s)
-{
- timer_del(s->source_timer);
-}
-
-static void omap_mcbsp_rx_done(struct omap_mcbsp_s *s)
-{
- s->spcr[0] &= ~(1 << 1); /* RRDY */
- qemu_irq_lower(s->rxdrq);
- omap_mcbsp_intr_update(s);
-}
-
-static void omap_mcbsp_tx_newdata(struct omap_mcbsp_s *s)
-{
- s->spcr[1] |= 1 << 1; /* XRDY */
- qemu_irq_raise(s->txdrq);
- omap_mcbsp_intr_update(s);
-}
-
-static void omap_mcbsp_sink_tick(void *opaque)
-{
- struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque;
- static const int bps[8] = { 0, 1, 1, 2, 2, 2, -255, -255 };
-
- if (!s->tx_rate)
- return;
- if (s->tx_req)
- printf("%s: Tx FIFO underrun\n", __FUNCTION__);
-
- s->tx_req = s->tx_rate << bps[(s->xcr[0] >> 5) & 7];
-
- omap_mcbsp_tx_newdata(s);
- timer_mod(s->sink_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- NANOSECONDS_PER_SECOND);
-}
-
-static void omap_mcbsp_tx_start(struct omap_mcbsp_s *s)
-{
- if (!s->codec || !s->codec->cts)
- omap_mcbsp_sink_tick(s);
- else if (s->codec->out.size) {
- s->tx_req = s->codec->out.size;
- omap_mcbsp_tx_newdata(s);
- }
-}
-
-static void omap_mcbsp_tx_done(struct omap_mcbsp_s *s)
-{
- s->spcr[1] &= ~(1 << 1); /* XRDY */
- qemu_irq_lower(s->txdrq);
- omap_mcbsp_intr_update(s);
- if (s->codec && s->codec->cts)
- s->codec->tx_swallow(s->codec->opaque);
-}
-
-static void omap_mcbsp_tx_stop(struct omap_mcbsp_s *s)
-{
- s->tx_req = 0;
- omap_mcbsp_tx_done(s);
- timer_del(s->sink_timer);
-}
-
-static void omap_mcbsp_req_update(struct omap_mcbsp_s *s)
-{
- int prev_rx_rate, prev_tx_rate;
- int rx_rate = 0, tx_rate = 0;
- int cpu_rate = 1500000; /* XXX */
-
- /* TODO: check CLKSTP bit */
- if (s->spcr[1] & (1 << 6)) { /* GRST */
- if (s->spcr[0] & (1 << 0)) { /* RRST */
- if ((s->srgr[1] & (1 << 13)) && /* CLKSM */
- (s->pcr & (1 << 8))) { /* CLKRM */
- if (~s->pcr & (1 << 7)) /* SCLKME */
- rx_rate = cpu_rate /
- ((s->srgr[0] & 0xff) + 1); /* CLKGDV */
- } else
- if (s->codec)
- rx_rate = s->codec->rx_rate;
- }
-
- if (s->spcr[1] & (1 << 0)) { /* XRST */
- if ((s->srgr[1] & (1 << 13)) && /* CLKSM */
- (s->pcr & (1 << 9))) { /* CLKXM */
- if (~s->pcr & (1 << 7)) /* SCLKME */
- tx_rate = cpu_rate /
- ((s->srgr[0] & 0xff) + 1); /* CLKGDV */
- } else
- if (s->codec)
- tx_rate = s->codec->tx_rate;
- }
- }
- prev_tx_rate = s->tx_rate;
- prev_rx_rate = s->rx_rate;
- s->tx_rate = tx_rate;
- s->rx_rate = rx_rate;
-
- if (s->codec)
- s->codec->set_rate(s->codec->opaque, rx_rate, tx_rate);
-
- if (!prev_tx_rate && tx_rate)
- omap_mcbsp_tx_start(s);
- else if (s->tx_rate && !tx_rate)
- omap_mcbsp_tx_stop(s);
-
- if (!prev_rx_rate && rx_rate)
- omap_mcbsp_rx_start(s);
- else if (prev_tx_rate && !tx_rate)
- omap_mcbsp_rx_stop(s);
-}
-
-static uint64_t omap_mcbsp_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque;
- int offset = addr & OMAP_MPUI_REG_MASK;
- uint16_t ret;
-
- if (size != 2) {
- return omap_badwidth_read16(opaque, addr);
- }
-
- switch (offset) {
- case 0x00: /* DRR2 */
- if (((s->rcr[0] >> 5) & 7) < 3) /* RWDLEN1 */
- return 0x0000;
- /* Fall through. */
- case 0x02: /* DRR1 */
- if (s->rx_req < 2) {
- printf("%s: Rx FIFO underrun\n", __FUNCTION__);
- omap_mcbsp_rx_done(s);
- } else {
- s->tx_req -= 2;
- if (s->codec && s->codec->in.len >= 2) {
- ret = s->codec->in.fifo[s->codec->in.start ++] << 8;
- ret |= s->codec->in.fifo[s->codec->in.start ++];
- s->codec->in.len -= 2;
- } else
- ret = 0x0000;
- if (!s->tx_req)
- omap_mcbsp_rx_done(s);
- return ret;
- }
- return 0x0000;
-
- case 0x04: /* DXR2 */
- case 0x06: /* DXR1 */
- return 0x0000;
-
- case 0x08: /* SPCR2 */
- return s->spcr[1];
- case 0x0a: /* SPCR1 */
- return s->spcr[0];
- case 0x0c: /* RCR2 */
- return s->rcr[1];
- case 0x0e: /* RCR1 */
- return s->rcr[0];
- case 0x10: /* XCR2 */
- return s->xcr[1];
- case 0x12: /* XCR1 */
- return s->xcr[0];
- case 0x14: /* SRGR2 */
- return s->srgr[1];
- case 0x16: /* SRGR1 */
- return s->srgr[0];
- case 0x18: /* MCR2 */
- return s->mcr[1];
- case 0x1a: /* MCR1 */
- return s->mcr[0];
- case 0x1c: /* RCERA */
- return s->rcer[0];
- case 0x1e: /* RCERB */
- return s->rcer[1];
- case 0x20: /* XCERA */
- return s->xcer[0];
- case 0x22: /* XCERB */
- return s->xcer[1];
- case 0x24: /* PCR0 */
- return s->pcr;
- case 0x26: /* RCERC */
- return s->rcer[2];
- case 0x28: /* RCERD */
- return s->rcer[3];
- case 0x2a: /* XCERC */
- return s->xcer[2];
- case 0x2c: /* XCERD */
- return s->xcer[3];
- case 0x2e: /* RCERE */
- return s->rcer[4];
- case 0x30: /* RCERF */
- return s->rcer[5];
- case 0x32: /* XCERE */
- return s->xcer[4];
- case 0x34: /* XCERF */
- return s->xcer[5];
- case 0x36: /* RCERG */
- return s->rcer[6];
- case 0x38: /* RCERH */
- return s->rcer[7];
- case 0x3a: /* XCERG */
- return s->xcer[6];
- case 0x3c: /* XCERH */
- return s->xcer[7];
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_mcbsp_writeh(void *opaque, hwaddr addr,
- uint32_t value)
-{
- struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque;
- int offset = addr & OMAP_MPUI_REG_MASK;
-
- switch (offset) {
- case 0x00: /* DRR2 */
- case 0x02: /* DRR1 */
- OMAP_RO_REG(addr);
- return;
-
- case 0x04: /* DXR2 */
- if (((s->xcr[0] >> 5) & 7) < 3) /* XWDLEN1 */
- return;
- /* Fall through. */
- case 0x06: /* DXR1 */
- if (s->tx_req > 1) {
- s->tx_req -= 2;
- if (s->codec && s->codec->cts) {
- s->codec->out.fifo[s->codec->out.len ++] = (value >> 8) & 0xff;
- s->codec->out.fifo[s->codec->out.len ++] = (value >> 0) & 0xff;
- }
- if (s->tx_req < 2)
- omap_mcbsp_tx_done(s);
- } else
- printf("%s: Tx FIFO overrun\n", __FUNCTION__);
- return;
-
- case 0x08: /* SPCR2 */
- s->spcr[1] &= 0x0002;
- s->spcr[1] |= 0x03f9 & value;
- s->spcr[1] |= 0x0004 & (value << 2); /* XEMPTY := XRST */
- if (~value & 1) /* XRST */
- s->spcr[1] &= ~6;
- omap_mcbsp_req_update(s);
- return;
- case 0x0a: /* SPCR1 */
- s->spcr[0] &= 0x0006;
- s->spcr[0] |= 0xf8f9 & value;
- if (value & (1 << 15)) /* DLB */
- printf("%s: Digital Loopback mode enable attempt\n", __FUNCTION__);
- if (~value & 1) { /* RRST */
- s->spcr[0] &= ~6;
- s->rx_req = 0;
- omap_mcbsp_rx_done(s);
- }
- omap_mcbsp_req_update(s);
- return;
-
- case 0x0c: /* RCR2 */
- s->rcr[1] = value & 0xffff;
- return;
- case 0x0e: /* RCR1 */
- s->rcr[0] = value & 0x7fe0;
- return;
- case 0x10: /* XCR2 */
- s->xcr[1] = value & 0xffff;
- return;
- case 0x12: /* XCR1 */
- s->xcr[0] = value & 0x7fe0;
- return;
- case 0x14: /* SRGR2 */
- s->srgr[1] = value & 0xffff;
- omap_mcbsp_req_update(s);
- return;
- case 0x16: /* SRGR1 */
- s->srgr[0] = value & 0xffff;
- omap_mcbsp_req_update(s);
- return;
- case 0x18: /* MCR2 */
- s->mcr[1] = value & 0x03e3;
- if (value & 3) /* XMCM */
- printf("%s: Tx channel selection mode enable attempt\n",
- __FUNCTION__);
- return;
- case 0x1a: /* MCR1 */
- s->mcr[0] = value & 0x03e1;
- if (value & 1) /* RMCM */
- printf("%s: Rx channel selection mode enable attempt\n",
- __FUNCTION__);
- return;
- case 0x1c: /* RCERA */
- s->rcer[0] = value & 0xffff;
- return;
- case 0x1e: /* RCERB */
- s->rcer[1] = value & 0xffff;
- return;
- case 0x20: /* XCERA */
- s->xcer[0] = value & 0xffff;
- return;
- case 0x22: /* XCERB */
- s->xcer[1] = value & 0xffff;
- return;
- case 0x24: /* PCR0 */
- s->pcr = value & 0x7faf;
- return;
- case 0x26: /* RCERC */
- s->rcer[2] = value & 0xffff;
- return;
- case 0x28: /* RCERD */
- s->rcer[3] = value & 0xffff;
- return;
- case 0x2a: /* XCERC */
- s->xcer[2] = value & 0xffff;
- return;
- case 0x2c: /* XCERD */
- s->xcer[3] = value & 0xffff;
- return;
- case 0x2e: /* RCERE */
- s->rcer[4] = value & 0xffff;
- return;
- case 0x30: /* RCERF */
- s->rcer[5] = value & 0xffff;
- return;
- case 0x32: /* XCERE */
- s->xcer[4] = value & 0xffff;
- return;
- case 0x34: /* XCERF */
- s->xcer[5] = value & 0xffff;
- return;
- case 0x36: /* RCERG */
- s->rcer[6] = value & 0xffff;
- return;
- case 0x38: /* RCERH */
- s->rcer[7] = value & 0xffff;
- return;
- case 0x3a: /* XCERG */
- s->xcer[6] = value & 0xffff;
- return;
- case 0x3c: /* XCERH */
- s->xcer[7] = value & 0xffff;
- return;
- }
-
- OMAP_BAD_REG(addr);
-}
-
-static void omap_mcbsp_writew(void *opaque, hwaddr addr,
- uint32_t value)
-{
- struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque;
- int offset = addr & OMAP_MPUI_REG_MASK;
-
- if (offset == 0x04) { /* DXR */
- if (((s->xcr[0] >> 5) & 7) < 3) /* XWDLEN1 */
- return;
- if (s->tx_req > 3) {
- s->tx_req -= 4;
- if (s->codec && s->codec->cts) {
- s->codec->out.fifo[s->codec->out.len ++] =
- (value >> 24) & 0xff;
- s->codec->out.fifo[s->codec->out.len ++] =
- (value >> 16) & 0xff;
- s->codec->out.fifo[s->codec->out.len ++] =
- (value >> 8) & 0xff;
- s->codec->out.fifo[s->codec->out.len ++] =
- (value >> 0) & 0xff;
- }
- if (s->tx_req < 4)
- omap_mcbsp_tx_done(s);
- } else
- printf("%s: Tx FIFO overrun\n", __FUNCTION__);
- return;
- }
-
- omap_badwidth_write16(opaque, addr, value);
-}
-
-static void omap_mcbsp_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- switch (size) {
- case 2:
- omap_mcbsp_writeh(opaque, addr, value);
- break;
- case 4:
- omap_mcbsp_writew(opaque, addr, value);
- break;
- default:
- omap_badwidth_write16(opaque, addr, value);
- }
-}
-
-static const MemoryRegionOps omap_mcbsp_ops = {
- .read = omap_mcbsp_read,
- .write = omap_mcbsp_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void omap_mcbsp_reset(struct omap_mcbsp_s *s)
-{
- memset(&s->spcr, 0, sizeof(s->spcr));
- memset(&s->rcr, 0, sizeof(s->rcr));
- memset(&s->xcr, 0, sizeof(s->xcr));
- s->srgr[0] = 0x0001;
- s->srgr[1] = 0x2000;
- memset(&s->mcr, 0, sizeof(s->mcr));
- memset(&s->pcr, 0, sizeof(s->pcr));
- memset(&s->rcer, 0, sizeof(s->rcer));
- memset(&s->xcer, 0, sizeof(s->xcer));
- s->tx_req = 0;
- s->rx_req = 0;
- s->tx_rate = 0;
- s->rx_rate = 0;
- timer_del(s->source_timer);
- timer_del(s->sink_timer);
-}
-
-static struct omap_mcbsp_s *omap_mcbsp_init(MemoryRegion *system_memory,
- hwaddr base,
- qemu_irq txirq, qemu_irq rxirq,
- qemu_irq *dma, omap_clk clk)
-{
- struct omap_mcbsp_s *s = g_new0(struct omap_mcbsp_s, 1);
-
- s->txirq = txirq;
- s->rxirq = rxirq;
- s->txdrq = dma[0];
- s->rxdrq = dma[1];
- s->sink_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, omap_mcbsp_sink_tick, s);
- s->source_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, omap_mcbsp_source_tick, s);
- omap_mcbsp_reset(s);
-
- memory_region_init_io(&s->iomem, NULL, &omap_mcbsp_ops, s, "omap-mcbsp", 0x800);
- memory_region_add_subregion(system_memory, base, &s->iomem);
-
- return s;
-}
-
-static void omap_mcbsp_i2s_swallow(void *opaque, int line, int level)
-{
- struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque;
-
- if (s->rx_rate) {
- s->rx_req = s->codec->in.len;
- omap_mcbsp_rx_newdata(s);
- }
-}
-
-static void omap_mcbsp_i2s_start(void *opaque, int line, int level)
-{
- struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque;
-
- if (s->tx_rate) {
- s->tx_req = s->codec->out.size;
- omap_mcbsp_tx_newdata(s);
- }
-}
-
-void omap_mcbsp_i2s_attach(struct omap_mcbsp_s *s, I2SCodec *slave)
-{
- s->codec = slave;
- slave->rx_swallow = qemu_allocate_irq(omap_mcbsp_i2s_swallow, s, 0);
- slave->tx_start = qemu_allocate_irq(omap_mcbsp_i2s_start, s, 0);
-}
-
-/* LED Pulse Generators */
-struct omap_lpg_s {
- MemoryRegion iomem;
- QEMUTimer *tm;
-
- uint8_t control;
- uint8_t power;
- int64_t on;
- int64_t period;
- int clk;
- int cycle;
-};
-
-static void omap_lpg_tick(void *opaque)
-{
- struct omap_lpg_s *s = opaque;
-
- if (s->cycle)
- timer_mod(s->tm, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + s->period - s->on);
- else
- timer_mod(s->tm, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + s->on);
-
- s->cycle = !s->cycle;
- printf("%s: LED is %s\n", __FUNCTION__, s->cycle ? "on" : "off");
-}
-
-static void omap_lpg_update(struct omap_lpg_s *s)
-{
- int64_t on, period = 1, ticks = 1000;
- static const int per[8] = { 1, 2, 4, 8, 12, 16, 20, 24 };
-
- if (~s->control & (1 << 6)) /* LPGRES */
- on = 0;
- else if (s->control & (1 << 7)) /* PERM_ON */
- on = period;
- else {
- period = muldiv64(ticks, per[s->control & 7], /* PERCTRL */
- 256 / 32);
- on = (s->clk && s->power) ? muldiv64(ticks,
- per[(s->control >> 3) & 7], 256) : 0; /* ONCTRL */
- }
-
- timer_del(s->tm);
- if (on == period && s->on < s->period)
- printf("%s: LED is on\n", __FUNCTION__);
- else if (on == 0 && s->on)
- printf("%s: LED is off\n", __FUNCTION__);
- else if (on && (on != s->on || period != s->period)) {
- s->cycle = 0;
- s->on = on;
- s->period = period;
- omap_lpg_tick(s);
- return;
- }
-
- s->on = on;
- s->period = period;
-}
-
-static void omap_lpg_reset(struct omap_lpg_s *s)
-{
- s->control = 0x00;
- s->power = 0x00;
- s->clk = 1;
- omap_lpg_update(s);
-}
-
-static uint64_t omap_lpg_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_lpg_s *s = (struct omap_lpg_s *) opaque;
- int offset = addr & OMAP_MPUI_REG_MASK;
-
- if (size != 1) {
- return omap_badwidth_read8(opaque, addr);
- }
-
- switch (offset) {
- case 0x00: /* LCR */
- return s->control;
-
- case 0x04: /* PMR */
- return s->power;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_lpg_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_lpg_s *s = (struct omap_lpg_s *) opaque;
- int offset = addr & OMAP_MPUI_REG_MASK;
-
- if (size != 1) {
- omap_badwidth_write8(opaque, addr, value);
- return;
- }
-
- switch (offset) {
- case 0x00: /* LCR */
- if (~value & (1 << 6)) /* LPGRES */
- omap_lpg_reset(s);
- s->control = value & 0xff;
- omap_lpg_update(s);
- return;
-
- case 0x04: /* PMR */
- s->power = value & 0x01;
- omap_lpg_update(s);
- return;
-
- default:
- OMAP_BAD_REG(addr);
- return;
- }
-}
-
-static const MemoryRegionOps omap_lpg_ops = {
- .read = omap_lpg_read,
- .write = omap_lpg_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void omap_lpg_clk_update(void *opaque, int line, int on)
-{
- struct omap_lpg_s *s = (struct omap_lpg_s *) opaque;
-
- s->clk = on;
- omap_lpg_update(s);
-}
-
-static struct omap_lpg_s *omap_lpg_init(MemoryRegion *system_memory,
- hwaddr base, omap_clk clk)
-{
- struct omap_lpg_s *s = g_new0(struct omap_lpg_s, 1);
-
- s->tm = timer_new_ms(QEMU_CLOCK_VIRTUAL, omap_lpg_tick, s);
-
- omap_lpg_reset(s);
-
- memory_region_init_io(&s->iomem, NULL, &omap_lpg_ops, s, "omap-lpg", 0x800);
- memory_region_add_subregion(system_memory, base, &s->iomem);
-
- omap_clk_adduser(clk, qemu_allocate_irq(omap_lpg_clk_update, s, 0));
-
- return s;
-}
-
-/* MPUI Peripheral Bridge configuration */
-static uint64_t omap_mpui_io_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- if (size != 2) {
- return omap_badwidth_read16(opaque, addr);
- }
-
- if (addr == OMAP_MPUI_BASE) /* CMR */
- return 0xfe4d;
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_mpui_io_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- /* FIXME: infinite loop */
- omap_badwidth_write16(opaque, addr, value);
-}
-
-static const MemoryRegionOps omap_mpui_io_ops = {
- .read = omap_mpui_io_read,
- .write = omap_mpui_io_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void omap_setup_mpui_io(MemoryRegion *system_memory,
- struct omap_mpu_state_s *mpu)
-{
- memory_region_init_io(&mpu->mpui_io_iomem, NULL, &omap_mpui_io_ops, mpu,
- "omap-mpui-io", 0x7fff);
- memory_region_add_subregion(system_memory, OMAP_MPUI_BASE,
- &mpu->mpui_io_iomem);
-}
-
-/* General chip reset */
-static void omap1_mpu_reset(void *opaque)
-{
- struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque;
-
- omap_dma_reset(mpu->dma);
- omap_mpu_timer_reset(mpu->timer[0]);
- omap_mpu_timer_reset(mpu->timer[1]);
- omap_mpu_timer_reset(mpu->timer[2]);
- omap_wd_timer_reset(mpu->wdt);
- omap_os_timer_reset(mpu->os_timer);
- omap_lcdc_reset(mpu->lcd);
- omap_ulpd_pm_reset(mpu);
- omap_pin_cfg_reset(mpu);
- omap_mpui_reset(mpu);
- omap_tipb_bridge_reset(mpu->private_tipb);
- omap_tipb_bridge_reset(mpu->public_tipb);
- omap_dpll_reset(mpu->dpll[0]);
- omap_dpll_reset(mpu->dpll[1]);
- omap_dpll_reset(mpu->dpll[2]);
- omap_uart_reset(mpu->uart[0]);
- omap_uart_reset(mpu->uart[1]);
- omap_uart_reset(mpu->uart[2]);
- omap_mmc_reset(mpu->mmc);
- omap_mpuio_reset(mpu->mpuio);
- omap_uwire_reset(mpu->microwire);
- omap_pwl_reset(mpu->pwl);
- omap_pwt_reset(mpu->pwt);
- omap_rtc_reset(mpu->rtc);
- omap_mcbsp_reset(mpu->mcbsp1);
- omap_mcbsp_reset(mpu->mcbsp2);
- omap_mcbsp_reset(mpu->mcbsp3);
- omap_lpg_reset(mpu->led[0]);
- omap_lpg_reset(mpu->led[1]);
- omap_clkm_reset(mpu);
- cpu_reset(CPU(mpu->cpu));
-}
-
-static const struct omap_map_s {
- hwaddr phys_dsp;
- hwaddr phys_mpu;
- uint32_t size;
- const char *name;
-} omap15xx_dsp_mm[] = {
- /* Strobe 0 */
- { 0xe1010000, 0xfffb0000, 0x800, "UART1 BT" }, /* CS0 */
- { 0xe1010800, 0xfffb0800, 0x800, "UART2 COM" }, /* CS1 */
- { 0xe1011800, 0xfffb1800, 0x800, "McBSP1 audio" }, /* CS3 */
- { 0xe1012000, 0xfffb2000, 0x800, "MCSI2 communication" }, /* CS4 */
- { 0xe1012800, 0xfffb2800, 0x800, "MCSI1 BT u-Law" }, /* CS5 */
- { 0xe1013000, 0xfffb3000, 0x800, "uWire" }, /* CS6 */
- { 0xe1013800, 0xfffb3800, 0x800, "I^2C" }, /* CS7 */
- { 0xe1014000, 0xfffb4000, 0x800, "USB W2FC" }, /* CS8 */
- { 0xe1014800, 0xfffb4800, 0x800, "RTC" }, /* CS9 */
- { 0xe1015000, 0xfffb5000, 0x800, "MPUIO" }, /* CS10 */
- { 0xe1015800, 0xfffb5800, 0x800, "PWL" }, /* CS11 */
- { 0xe1016000, 0xfffb6000, 0x800, "PWT" }, /* CS12 */
- { 0xe1017000, 0xfffb7000, 0x800, "McBSP3" }, /* CS14 */
- { 0xe1017800, 0xfffb7800, 0x800, "MMC" }, /* CS15 */
- { 0xe1019000, 0xfffb9000, 0x800, "32-kHz timer" }, /* CS18 */
- { 0xe1019800, 0xfffb9800, 0x800, "UART3" }, /* CS19 */
- { 0xe101c800, 0xfffbc800, 0x800, "TIPB switches" }, /* CS25 */
- /* Strobe 1 */
- { 0xe101e000, 0xfffce000, 0x800, "GPIOs" }, /* CS28 */
-
- { 0 }
-};
-
-static void omap_setup_dsp_mapping(MemoryRegion *system_memory,
- const struct omap_map_s *map)
-{
- MemoryRegion *io;
-
- for (; map->phys_dsp; map ++) {
- io = g_new(MemoryRegion, 1);
- memory_region_init_alias(io, NULL, map->name,
- system_memory, map->phys_mpu, map->size);
- memory_region_add_subregion(system_memory, map->phys_dsp, io);
- }
-}
-
-void omap_mpu_wakeup(void *opaque, int irq, int req)
-{
- struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque;
- CPUState *cpu = CPU(mpu->cpu);
-
- if (cpu->halted) {
- cpu_interrupt(cpu, CPU_INTERRUPT_EXITTB);
- }
-}
-
-static const struct dma_irq_map omap1_dma_irq_map[] = {
- { 0, OMAP_INT_DMA_CH0_6 },
- { 0, OMAP_INT_DMA_CH1_7 },
- { 0, OMAP_INT_DMA_CH2_8 },
- { 0, OMAP_INT_DMA_CH3 },
- { 0, OMAP_INT_DMA_CH4 },
- { 0, OMAP_INT_DMA_CH5 },
- { 1, OMAP_INT_1610_DMA_CH6 },
- { 1, OMAP_INT_1610_DMA_CH7 },
- { 1, OMAP_INT_1610_DMA_CH8 },
- { 1, OMAP_INT_1610_DMA_CH9 },
- { 1, OMAP_INT_1610_DMA_CH10 },
- { 1, OMAP_INT_1610_DMA_CH11 },
- { 1, OMAP_INT_1610_DMA_CH12 },
- { 1, OMAP_INT_1610_DMA_CH13 },
- { 1, OMAP_INT_1610_DMA_CH14 },
- { 1, OMAP_INT_1610_DMA_CH15 }
-};
-
-/* DMA ports for OMAP1 */
-static int omap_validate_emiff_addr(struct omap_mpu_state_s *s,
- hwaddr addr)
-{
- return range_covers_byte(OMAP_EMIFF_BASE, s->sdram_size, addr);
-}
-
-static int omap_validate_emifs_addr(struct omap_mpu_state_s *s,
- hwaddr addr)
-{
- return range_covers_byte(OMAP_EMIFS_BASE, OMAP_EMIFF_BASE - OMAP_EMIFS_BASE,
- addr);
-}
-
-static int omap_validate_imif_addr(struct omap_mpu_state_s *s,
- hwaddr addr)
-{
- return range_covers_byte(OMAP_IMIF_BASE, s->sram_size, addr);
-}
-
-static int omap_validate_tipb_addr(struct omap_mpu_state_s *s,
- hwaddr addr)
-{
- return range_covers_byte(0xfffb0000, 0xffff0000 - 0xfffb0000, addr);
-}
-
-static int omap_validate_local_addr(struct omap_mpu_state_s *s,
- hwaddr addr)
-{
- return range_covers_byte(OMAP_LOCALBUS_BASE, 0x1000000, addr);
-}
-
-static int omap_validate_tipb_mpui_addr(struct omap_mpu_state_s *s,
- hwaddr addr)
-{
- return range_covers_byte(0xe1010000, 0xe1020004 - 0xe1010000, addr);
-}
-
-struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
- unsigned long sdram_size,
- const char *core)
-{
- int i;
- struct omap_mpu_state_s *s = g_new0(struct omap_mpu_state_s, 1);
- qemu_irq dma_irqs[6];
- DriveInfo *dinfo;
- SysBusDevice *busdev;
-
- if (!core)
- core = "ti925t";
-
- /* Core */
- s->mpu_model = omap310;
- s->cpu = cpu_arm_init(core);
- if (s->cpu == NULL) {
- fprintf(stderr, "Unable to find CPU definition\n");
- exit(1);
- }
- s->sdram_size = sdram_size;
- s->sram_size = OMAP15XX_SRAM_SIZE;
-
- s->wakeup = qemu_allocate_irq(omap_mpu_wakeup, s, 0);
-
- /* Clocks */
- omap_clk_init(s);
-
- /* Memory-mapped stuff */
- memory_region_allocate_system_memory(&s->emiff_ram, NULL, "omap1.dram",
- s->sdram_size);
- memory_region_add_subregion(system_memory, OMAP_EMIFF_BASE, &s->emiff_ram);
- memory_region_init_ram(&s->imif_ram, NULL, "omap1.sram", s->sram_size,
- &error_fatal);
- vmstate_register_ram_global(&s->imif_ram);
- memory_region_add_subregion(system_memory, OMAP_IMIF_BASE, &s->imif_ram);
-
- omap_clkm_init(system_memory, 0xfffece00, 0xe1008000, s);
-
- s->ih[0] = qdev_create(NULL, "omap-intc");
- qdev_prop_set_uint32(s->ih[0], "size", 0x100);
- qdev_prop_set_ptr(s->ih[0], "clk", omap_findclk(s, "arminth_ck"));
- qdev_init_nofail(s->ih[0]);
- busdev = SYS_BUS_DEVICE(s->ih[0]);
- sysbus_connect_irq(busdev, 0,
- qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_IRQ));
- sysbus_connect_irq(busdev, 1,
- qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_FIQ));
- sysbus_mmio_map(busdev, 0, 0xfffecb00);
- s->ih[1] = qdev_create(NULL, "omap-intc");
- qdev_prop_set_uint32(s->ih[1], "size", 0x800);
- qdev_prop_set_ptr(s->ih[1], "clk", omap_findclk(s, "arminth_ck"));
- qdev_init_nofail(s->ih[1]);
- busdev = SYS_BUS_DEVICE(s->ih[1]);
- sysbus_connect_irq(busdev, 0,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_15XX_IH2_IRQ));
- /* The second interrupt controller's FIQ output is not wired up */
- sysbus_mmio_map(busdev, 0, 0xfffe0000);
-
- for (i = 0; i < 6; i++) {
- dma_irqs[i] = qdev_get_gpio_in(s->ih[omap1_dma_irq_map[i].ih],
- omap1_dma_irq_map[i].intr);
- }
- s->dma = omap_dma_init(0xfffed800, dma_irqs, system_memory,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_DMA_LCD),
- s, omap_findclk(s, "dma_ck"), omap_dma_3_1);
-
- s->port[emiff ].addr_valid = omap_validate_emiff_addr;
- s->port[emifs ].addr_valid = omap_validate_emifs_addr;
- s->port[imif ].addr_valid = omap_validate_imif_addr;
- s->port[tipb ].addr_valid = omap_validate_tipb_addr;
- s->port[local ].addr_valid = omap_validate_local_addr;
- s->port[tipb_mpui].addr_valid = omap_validate_tipb_mpui_addr;
-
- /* Register SDRAM and SRAM DMA ports for fast transfers. */
- soc_dma_port_add_mem(s->dma, memory_region_get_ram_ptr(&s->emiff_ram),
- OMAP_EMIFF_BASE, s->sdram_size);
- soc_dma_port_add_mem(s->dma, memory_region_get_ram_ptr(&s->imif_ram),
- OMAP_IMIF_BASE, s->sram_size);
-
- s->timer[0] = omap_mpu_timer_init(system_memory, 0xfffec500,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_TIMER1),
- omap_findclk(s, "mputim_ck"));
- s->timer[1] = omap_mpu_timer_init(system_memory, 0xfffec600,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_TIMER2),
- omap_findclk(s, "mputim_ck"));
- s->timer[2] = omap_mpu_timer_init(system_memory, 0xfffec700,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_TIMER3),
- omap_findclk(s, "mputim_ck"));
-
- s->wdt = omap_wd_timer_init(system_memory, 0xfffec800,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_WD_TIMER),
- omap_findclk(s, "armwdt_ck"));
-
- s->os_timer = omap_os_timer_init(system_memory, 0xfffb9000,
- qdev_get_gpio_in(s->ih[1], OMAP_INT_OS_TIMER),
- omap_findclk(s, "clk32-kHz"));
-
- s->lcd = omap_lcdc_init(system_memory, 0xfffec000,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_LCD_CTRL),
- omap_dma_get_lcdch(s->dma),
- omap_findclk(s, "lcd_ck"));
-
- omap_ulpd_pm_init(system_memory, 0xfffe0800, s);
- omap_pin_cfg_init(system_memory, 0xfffe1000, s);
- omap_id_init(system_memory, s);
-
- omap_mpui_init(system_memory, 0xfffec900, s);
-
- s->private_tipb = omap_tipb_bridge_init(system_memory, 0xfffeca00,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_BRIDGE_PRIV),
- omap_findclk(s, "tipb_ck"));
- s->public_tipb = omap_tipb_bridge_init(system_memory, 0xfffed300,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_BRIDGE_PUB),
- omap_findclk(s, "tipb_ck"));
-
- omap_tcmi_init(system_memory, 0xfffecc00, s);
-
- s->uart[0] = omap_uart_init(0xfffb0000,
- qdev_get_gpio_in(s->ih[1], OMAP_INT_UART1),
- omap_findclk(s, "uart1_ck"),
- omap_findclk(s, "uart1_ck"),
- s->drq[OMAP_DMA_UART1_TX], s->drq[OMAP_DMA_UART1_RX],
- "uart1",
- serial_hds[0]);
- s->uart[1] = omap_uart_init(0xfffb0800,
- qdev_get_gpio_in(s->ih[1], OMAP_INT_UART2),
- omap_findclk(s, "uart2_ck"),
- omap_findclk(s, "uart2_ck"),
- s->drq[OMAP_DMA_UART2_TX], s->drq[OMAP_DMA_UART2_RX],
- "uart2",
- serial_hds[0] ? serial_hds[1] : NULL);
- s->uart[2] = omap_uart_init(0xfffb9800,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_UART3),
- omap_findclk(s, "uart3_ck"),
- omap_findclk(s, "uart3_ck"),
- s->drq[OMAP_DMA_UART3_TX], s->drq[OMAP_DMA_UART3_RX],
- "uart3",
- serial_hds[0] && serial_hds[1] ? serial_hds[2] : NULL);
-
- s->dpll[0] = omap_dpll_init(system_memory, 0xfffecf00,
- omap_findclk(s, "dpll1"));
- s->dpll[1] = omap_dpll_init(system_memory, 0xfffed000,
- omap_findclk(s, "dpll2"));
- s->dpll[2] = omap_dpll_init(system_memory, 0xfffed100,
- omap_findclk(s, "dpll3"));
-
- dinfo = drive_get(IF_SD, 0, 0);
- if (!dinfo) {
- fprintf(stderr, "qemu: missing SecureDigital device\n");
- exit(1);
- }
- s->mmc = omap_mmc_init(0xfffb7800, system_memory,
- blk_by_legacy_dinfo(dinfo),
- qdev_get_gpio_in(s->ih[1], OMAP_INT_OQN),
- &s->drq[OMAP_DMA_MMC_TX],
- omap_findclk(s, "mmc_ck"));
-
- s->mpuio = omap_mpuio_init(system_memory, 0xfffb5000,
- qdev_get_gpio_in(s->ih[1], OMAP_INT_KEYBOARD),
- qdev_get_gpio_in(s->ih[1], OMAP_INT_MPUIO),
- s->wakeup, omap_findclk(s, "clk32-kHz"));
-
- s->gpio = qdev_create(NULL, "omap-gpio");
- qdev_prop_set_int32(s->gpio, "mpu_model", s->mpu_model);
- qdev_prop_set_ptr(s->gpio, "clk", omap_findclk(s, "arm_gpio_ck"));
- qdev_init_nofail(s->gpio);
- sysbus_connect_irq(SYS_BUS_DEVICE(s->gpio), 0,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_GPIO_BANK1));
- sysbus_mmio_map(SYS_BUS_DEVICE(s->gpio), 0, 0xfffce000);
-
- s->microwire = omap_uwire_init(system_memory, 0xfffb3000,
- qdev_get_gpio_in(s->ih[1], OMAP_INT_uWireTX),
- qdev_get_gpio_in(s->ih[1], OMAP_INT_uWireRX),
- s->drq[OMAP_DMA_UWIRE_TX], omap_findclk(s, "mpuper_ck"));
-
- s->pwl = omap_pwl_init(system_memory, 0xfffb5800,
- omap_findclk(s, "armxor_ck"));
- s->pwt = omap_pwt_init(system_memory, 0xfffb6000,
- omap_findclk(s, "armxor_ck"));
-
- s->i2c[0] = qdev_create(NULL, "omap_i2c");
- qdev_prop_set_uint8(s->i2c[0], "revision", 0x11);
- qdev_prop_set_ptr(s->i2c[0], "fclk", omap_findclk(s, "mpuper_ck"));
- qdev_init_nofail(s->i2c[0]);
- busdev = SYS_BUS_DEVICE(s->i2c[0]);
- sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(s->ih[1], OMAP_INT_I2C));
- sysbus_connect_irq(busdev, 1, s->drq[OMAP_DMA_I2C_TX]);
- sysbus_connect_irq(busdev, 2, s->drq[OMAP_DMA_I2C_RX]);
- sysbus_mmio_map(busdev, 0, 0xfffb3800);
-
- s->rtc = omap_rtc_init(system_memory, 0xfffb4800,
- qdev_get_gpio_in(s->ih[1], OMAP_INT_RTC_TIMER),
- qdev_get_gpio_in(s->ih[1], OMAP_INT_RTC_ALARM),
- omap_findclk(s, "clk32-kHz"));
-
- s->mcbsp1 = omap_mcbsp_init(system_memory, 0xfffb1800,
- qdev_get_gpio_in(s->ih[1], OMAP_INT_McBSP1TX),
- qdev_get_gpio_in(s->ih[1], OMAP_INT_McBSP1RX),
- &s->drq[OMAP_DMA_MCBSP1_TX], omap_findclk(s, "dspxor_ck"));
- s->mcbsp2 = omap_mcbsp_init(system_memory, 0xfffb1000,
- qdev_get_gpio_in(s->ih[0],
- OMAP_INT_310_McBSP2_TX),
- qdev_get_gpio_in(s->ih[0],
- OMAP_INT_310_McBSP2_RX),
- &s->drq[OMAP_DMA_MCBSP2_TX], omap_findclk(s, "mpuper_ck"));
- s->mcbsp3 = omap_mcbsp_init(system_memory, 0xfffb7000,
- qdev_get_gpio_in(s->ih[1], OMAP_INT_McBSP3TX),
- qdev_get_gpio_in(s->ih[1], OMAP_INT_McBSP3RX),
- &s->drq[OMAP_DMA_MCBSP3_TX], omap_findclk(s, "dspxor_ck"));
-
- s->led[0] = omap_lpg_init(system_memory,
- 0xfffbd000, omap_findclk(s, "clk32-kHz"));
- s->led[1] = omap_lpg_init(system_memory,
- 0xfffbd800, omap_findclk(s, "clk32-kHz"));
-
- /* Register mappings not currenlty implemented:
- * MCSI2 Comm fffb2000 - fffb27ff (not mapped on OMAP310)
- * MCSI1 Bluetooth fffb2800 - fffb2fff (not mapped on OMAP310)
- * USB W2FC fffb4000 - fffb47ff
- * Camera Interface fffb6800 - fffb6fff
- * USB Host fffba000 - fffba7ff
- * FAC fffba800 - fffbafff
- * HDQ/1-Wire fffbc000 - fffbc7ff
- * TIPB switches fffbc800 - fffbcfff
- * Mailbox fffcf000 - fffcf7ff
- * Local bus IF fffec100 - fffec1ff
- * Local bus MMU fffec200 - fffec2ff
- * DSP MMU fffed200 - fffed2ff
- */
-
- omap_setup_dsp_mapping(system_memory, omap15xx_dsp_mm);
- omap_setup_mpui_io(system_memory, s);
-
- qemu_register_reset(omap1_mpu_reset, s);
-
- return s;
-}
diff --git a/qemu/hw/arm/omap2.c b/qemu/hw/arm/omap2.c
deleted file mode 100644
index 3a0d77714..000000000
--- a/qemu/hw/arm/omap2.c
+++ /dev/null
@@ -1,2691 +0,0 @@
-/*
- * TI OMAP processors emulation.
- *
- * Copyright (C) 2007-2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
-#include "hw/boards.h"
-#include "hw/hw.h"
-#include "hw/arm/arm.h"
-#include "hw/arm/omap.h"
-#include "sysemu/sysemu.h"
-#include "qemu/timer.h"
-#include "sysemu/char.h"
-#include "hw/block/flash.h"
-#include "hw/arm/soc_dma.h"
-#include "hw/sysbus.h"
-#include "audio/audio.h"
-
-/* Enhanced Audio Controller (CODEC only) */
-struct omap_eac_s {
- qemu_irq irq;
- MemoryRegion iomem;
-
- uint16_t sysconfig;
- uint8_t config[4];
- uint8_t control;
- uint8_t address;
- uint16_t data;
- uint8_t vtol;
- uint8_t vtsl;
- uint16_t mixer;
- uint16_t gain[4];
- uint8_t att;
- uint16_t max[7];
-
- struct {
- qemu_irq txdrq;
- qemu_irq rxdrq;
- uint32_t (*txrx)(void *opaque, uint32_t, int);
- void *opaque;
-
-#define EAC_BUF_LEN 1024
- uint32_t rxbuf[EAC_BUF_LEN];
- int rxoff;
- int rxlen;
- int rxavail;
- uint32_t txbuf[EAC_BUF_LEN];
- int txlen;
- int txavail;
-
- int enable;
- int rate;
-
- uint16_t config[4];
-
- /* These need to be moved to the actual codec */
- QEMUSoundCard card;
- SWVoiceIn *in_voice;
- SWVoiceOut *out_voice;
- int hw_enable;
- } codec;
-
- struct {
- uint8_t control;
- uint16_t config;
- } modem, bt;
-};
-
-static inline void omap_eac_interrupt_update(struct omap_eac_s *s)
-{
- qemu_set_irq(s->irq, (s->codec.config[1] >> 14) & 1); /* AURDI */
-}
-
-static inline void omap_eac_in_dmarequest_update(struct omap_eac_s *s)
-{
- qemu_set_irq(s->codec.rxdrq, (s->codec.rxavail || s->codec.rxlen) &&
- ((s->codec.config[1] >> 12) & 1)); /* DMAREN */
-}
-
-static inline void omap_eac_out_dmarequest_update(struct omap_eac_s *s)
-{
- qemu_set_irq(s->codec.txdrq, s->codec.txlen < s->codec.txavail &&
- ((s->codec.config[1] >> 11) & 1)); /* DMAWEN */
-}
-
-static inline void omap_eac_in_refill(struct omap_eac_s *s)
-{
- int left = MIN(EAC_BUF_LEN - s->codec.rxlen, s->codec.rxavail) << 2;
- int start = ((s->codec.rxoff + s->codec.rxlen) & (EAC_BUF_LEN - 1)) << 2;
- int leftwrap = MIN(left, (EAC_BUF_LEN << 2) - start);
- int recv = 1;
- uint8_t *buf = (uint8_t *) s->codec.rxbuf + start;
-
- left -= leftwrap;
- start = 0;
- while (leftwrap && (recv = AUD_read(s->codec.in_voice, buf + start,
- leftwrap)) > 0) { /* Be defensive */
- start += recv;
- leftwrap -= recv;
- }
- if (recv <= 0)
- s->codec.rxavail = 0;
- else
- s->codec.rxavail -= start >> 2;
- s->codec.rxlen += start >> 2;
-
- if (recv > 0 && left > 0) {
- start = 0;
- while (left && (recv = AUD_read(s->codec.in_voice,
- (uint8_t *) s->codec.rxbuf + start,
- left)) > 0) { /* Be defensive */
- start += recv;
- left -= recv;
- }
- if (recv <= 0)
- s->codec.rxavail = 0;
- else
- s->codec.rxavail -= start >> 2;
- s->codec.rxlen += start >> 2;
- }
-}
-
-static inline void omap_eac_out_empty(struct omap_eac_s *s)
-{
- int left = s->codec.txlen << 2;
- int start = 0;
- int sent = 1;
-
- while (left && (sent = AUD_write(s->codec.out_voice,
- (uint8_t *) s->codec.txbuf + start,
- left)) > 0) { /* Be defensive */
- start += sent;
- left -= sent;
- }
-
- if (!sent) {
- s->codec.txavail = 0;
- omap_eac_out_dmarequest_update(s);
- }
-
- if (start)
- s->codec.txlen = 0;
-}
-
-static void omap_eac_in_cb(void *opaque, int avail_b)
-{
- struct omap_eac_s *s = (struct omap_eac_s *) opaque;
-
- s->codec.rxavail = avail_b >> 2;
- omap_eac_in_refill(s);
- /* TODO: possibly discard current buffer if overrun */
- omap_eac_in_dmarequest_update(s);
-}
-
-static void omap_eac_out_cb(void *opaque, int free_b)
-{
- struct omap_eac_s *s = (struct omap_eac_s *) opaque;
-
- s->codec.txavail = free_b >> 2;
- if (s->codec.txlen)
- omap_eac_out_empty(s);
- else
- omap_eac_out_dmarequest_update(s);
-}
-
-static void omap_eac_enable_update(struct omap_eac_s *s)
-{
- s->codec.enable = !(s->codec.config[1] & 1) && /* EACPWD */
- (s->codec.config[1] & 2) && /* AUDEN */
- s->codec.hw_enable;
-}
-
-static const int omap_eac_fsint[4] = {
- 8000,
- 11025,
- 22050,
- 44100,
-};
-
-static const int omap_eac_fsint2[8] = {
- 8000,
- 11025,
- 22050,
- 44100,
- 48000,
- 0, 0, 0,
-};
-
-static const int omap_eac_fsint3[16] = {
- 8000,
- 11025,
- 16000,
- 22050,
- 24000,
- 32000,
- 44100,
- 48000,
- 0, 0, 0, 0, 0, 0, 0, 0,
-};
-
-static void omap_eac_rate_update(struct omap_eac_s *s)
-{
- int fsint[3];
-
- fsint[2] = (s->codec.config[3] >> 9) & 0xf;
- fsint[1] = (s->codec.config[2] >> 0) & 0x7;
- fsint[0] = (s->codec.config[0] >> 6) & 0x3;
- if (fsint[2] < 0xf)
- s->codec.rate = omap_eac_fsint3[fsint[2]];
- else if (fsint[1] < 0x7)
- s->codec.rate = omap_eac_fsint2[fsint[1]];
- else
- s->codec.rate = omap_eac_fsint[fsint[0]];
-}
-
-static void omap_eac_volume_update(struct omap_eac_s *s)
-{
- /* TODO */
-}
-
-static void omap_eac_format_update(struct omap_eac_s *s)
-{
- struct audsettings fmt;
-
- /* The hardware buffers at most one sample */
- if (s->codec.rxlen)
- s->codec.rxlen = 1;
-
- if (s->codec.in_voice) {
- AUD_set_active_in(s->codec.in_voice, 0);
- AUD_close_in(&s->codec.card, s->codec.in_voice);
- s->codec.in_voice = NULL;
- }
- if (s->codec.out_voice) {
- omap_eac_out_empty(s);
- AUD_set_active_out(s->codec.out_voice, 0);
- AUD_close_out(&s->codec.card, s->codec.out_voice);
- s->codec.out_voice = NULL;
- s->codec.txavail = 0;
- }
- /* Discard what couldn't be written */
- s->codec.txlen = 0;
-
- omap_eac_enable_update(s);
- if (!s->codec.enable)
- return;
-
- omap_eac_rate_update(s);
- fmt.endianness = ((s->codec.config[0] >> 8) & 1); /* LI_BI */
- fmt.nchannels = ((s->codec.config[0] >> 10) & 1) ? 2 : 1; /* MN_ST */
- fmt.freq = s->codec.rate;
- /* TODO: signedness possibly depends on the CODEC hardware - or
- * does I2S specify it? */
- /* All register writes are 16 bits so we we store 16-bit samples
- * in the buffers regardless of AGCFR[B8_16] value. */
- fmt.fmt = AUD_FMT_U16;
-
- s->codec.in_voice = AUD_open_in(&s->codec.card, s->codec.in_voice,
- "eac.codec.in", s, omap_eac_in_cb, &fmt);
- s->codec.out_voice = AUD_open_out(&s->codec.card, s->codec.out_voice,
- "eac.codec.out", s, omap_eac_out_cb, &fmt);
-
- omap_eac_volume_update(s);
-
- AUD_set_active_in(s->codec.in_voice, 1);
- AUD_set_active_out(s->codec.out_voice, 1);
-}
-
-static void omap_eac_reset(struct omap_eac_s *s)
-{
- s->sysconfig = 0;
- s->config[0] = 0x0c;
- s->config[1] = 0x09;
- s->config[2] = 0xab;
- s->config[3] = 0x03;
- s->control = 0x00;
- s->address = 0x00;
- s->data = 0x0000;
- s->vtol = 0x00;
- s->vtsl = 0x00;
- s->mixer = 0x0000;
- s->gain[0] = 0xe7e7;
- s->gain[1] = 0x6767;
- s->gain[2] = 0x6767;
- s->gain[3] = 0x6767;
- s->att = 0xce;
- s->max[0] = 0;
- s->max[1] = 0;
- s->max[2] = 0;
- s->max[3] = 0;
- s->max[4] = 0;
- s->max[5] = 0;
- s->max[6] = 0;
-
- s->modem.control = 0x00;
- s->modem.config = 0x0000;
- s->bt.control = 0x00;
- s->bt.config = 0x0000;
- s->codec.config[0] = 0x0649;
- s->codec.config[1] = 0x0000;
- s->codec.config[2] = 0x0007;
- s->codec.config[3] = 0x1ffc;
- s->codec.rxoff = 0;
- s->codec.rxlen = 0;
- s->codec.txlen = 0;
- s->codec.rxavail = 0;
- s->codec.txavail = 0;
-
- omap_eac_format_update(s);
- omap_eac_interrupt_update(s);
-}
-
-static uint64_t omap_eac_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_eac_s *s = (struct omap_eac_s *) opaque;
- uint32_t ret;
-
- if (size != 2) {
- return omap_badwidth_read16(opaque, addr);
- }
-
- switch (addr) {
- case 0x000: /* CPCFR1 */
- return s->config[0];
- case 0x004: /* CPCFR2 */
- return s->config[1];
- case 0x008: /* CPCFR3 */
- return s->config[2];
- case 0x00c: /* CPCFR4 */
- return s->config[3];
-
- case 0x010: /* CPTCTL */
- return s->control | ((s->codec.rxavail + s->codec.rxlen > 0) << 7) |
- ((s->codec.txlen < s->codec.txavail) << 5);
-
- case 0x014: /* CPTTADR */
- return s->address;
- case 0x018: /* CPTDATL */
- return s->data & 0xff;
- case 0x01c: /* CPTDATH */
- return s->data >> 8;
- case 0x020: /* CPTVSLL */
- return s->vtol;
- case 0x024: /* CPTVSLH */
- return s->vtsl | (3 << 5); /* CRDY1 | CRDY2 */
- case 0x040: /* MPCTR */
- return s->modem.control;
- case 0x044: /* MPMCCFR */
- return s->modem.config;
- case 0x060: /* BPCTR */
- return s->bt.control;
- case 0x064: /* BPMCCFR */
- return s->bt.config;
- case 0x080: /* AMSCFR */
- return s->mixer;
- case 0x084: /* AMVCTR */
- return s->gain[0];
- case 0x088: /* AM1VCTR */
- return s->gain[1];
- case 0x08c: /* AM2VCTR */
- return s->gain[2];
- case 0x090: /* AM3VCTR */
- return s->gain[3];
- case 0x094: /* ASTCTR */
- return s->att;
- case 0x098: /* APD1LCR */
- return s->max[0];
- case 0x09c: /* APD1RCR */
- return s->max[1];
- case 0x0a0: /* APD2LCR */
- return s->max[2];
- case 0x0a4: /* APD2RCR */
- return s->max[3];
- case 0x0a8: /* APD3LCR */
- return s->max[4];
- case 0x0ac: /* APD3RCR */
- return s->max[5];
- case 0x0b0: /* APD4R */
- return s->max[6];
- case 0x0b4: /* ADWR */
- /* This should be write-only? Docs list it as read-only. */
- return 0x0000;
- case 0x0b8: /* ADRDR */
- if (likely(s->codec.rxlen > 1)) {
- ret = s->codec.rxbuf[s->codec.rxoff ++];
- s->codec.rxlen --;
- s->codec.rxoff &= EAC_BUF_LEN - 1;
- return ret;
- } else if (s->codec.rxlen) {
- ret = s->codec.rxbuf[s->codec.rxoff ++];
- s->codec.rxlen --;
- s->codec.rxoff &= EAC_BUF_LEN - 1;
- if (s->codec.rxavail)
- omap_eac_in_refill(s);
- omap_eac_in_dmarequest_update(s);
- return ret;
- }
- return 0x0000;
- case 0x0bc: /* AGCFR */
- return s->codec.config[0];
- case 0x0c0: /* AGCTR */
- return s->codec.config[1] | ((s->codec.config[1] & 2) << 14);
- case 0x0c4: /* AGCFR2 */
- return s->codec.config[2];
- case 0x0c8: /* AGCFR3 */
- return s->codec.config[3];
- case 0x0cc: /* MBPDMACTR */
- case 0x0d0: /* MPDDMARR */
- case 0x0d8: /* MPUDMARR */
- case 0x0e4: /* BPDDMARR */
- case 0x0ec: /* BPUDMARR */
- return 0x0000;
-
- case 0x100: /* VERSION_NUMBER */
- return 0x0010;
-
- case 0x104: /* SYSCONFIG */
- return s->sysconfig;
-
- case 0x108: /* SYSSTATUS */
- return 1 | 0xe; /* RESETDONE | stuff */
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_eac_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_eac_s *s = (struct omap_eac_s *) opaque;
-
- if (size != 2) {
- omap_badwidth_write16(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x098: /* APD1LCR */
- case 0x09c: /* APD1RCR */
- case 0x0a0: /* APD2LCR */
- case 0x0a4: /* APD2RCR */
- case 0x0a8: /* APD3LCR */
- case 0x0ac: /* APD3RCR */
- case 0x0b0: /* APD4R */
- case 0x0b8: /* ADRDR */
- case 0x0d0: /* MPDDMARR */
- case 0x0d8: /* MPUDMARR */
- case 0x0e4: /* BPDDMARR */
- case 0x0ec: /* BPUDMARR */
- case 0x100: /* VERSION_NUMBER */
- case 0x108: /* SYSSTATUS */
- OMAP_RO_REG(addr);
- return;
-
- case 0x000: /* CPCFR1 */
- s->config[0] = value & 0xff;
- omap_eac_format_update(s);
- break;
- case 0x004: /* CPCFR2 */
- s->config[1] = value & 0xff;
- omap_eac_format_update(s);
- break;
- case 0x008: /* CPCFR3 */
- s->config[2] = value & 0xff;
- omap_eac_format_update(s);
- break;
- case 0x00c: /* CPCFR4 */
- s->config[3] = value & 0xff;
- omap_eac_format_update(s);
- break;
-
- case 0x010: /* CPTCTL */
- /* Assuming TXF and TXE bits are read-only... */
- s->control = value & 0x5f;
- omap_eac_interrupt_update(s);
- break;
-
- case 0x014: /* CPTTADR */
- s->address = value & 0xff;
- break;
- case 0x018: /* CPTDATL */
- s->data &= 0xff00;
- s->data |= value & 0xff;
- break;
- case 0x01c: /* CPTDATH */
- s->data &= 0x00ff;
- s->data |= value << 8;
- break;
- case 0x020: /* CPTVSLL */
- s->vtol = value & 0xf8;
- break;
- case 0x024: /* CPTVSLH */
- s->vtsl = value & 0x9f;
- break;
- case 0x040: /* MPCTR */
- s->modem.control = value & 0x8f;
- break;
- case 0x044: /* MPMCCFR */
- s->modem.config = value & 0x7fff;
- break;
- case 0x060: /* BPCTR */
- s->bt.control = value & 0x8f;
- break;
- case 0x064: /* BPMCCFR */
- s->bt.config = value & 0x7fff;
- break;
- case 0x080: /* AMSCFR */
- s->mixer = value & 0x0fff;
- break;
- case 0x084: /* AMVCTR */
- s->gain[0] = value & 0xffff;
- break;
- case 0x088: /* AM1VCTR */
- s->gain[1] = value & 0xff7f;
- break;
- case 0x08c: /* AM2VCTR */
- s->gain[2] = value & 0xff7f;
- break;
- case 0x090: /* AM3VCTR */
- s->gain[3] = value & 0xff7f;
- break;
- case 0x094: /* ASTCTR */
- s->att = value & 0xff;
- break;
-
- case 0x0b4: /* ADWR */
- s->codec.txbuf[s->codec.txlen ++] = value;
- if (unlikely(s->codec.txlen == EAC_BUF_LEN ||
- s->codec.txlen == s->codec.txavail)) {
- if (s->codec.txavail)
- omap_eac_out_empty(s);
- /* Discard what couldn't be written */
- s->codec.txlen = 0;
- }
- break;
-
- case 0x0bc: /* AGCFR */
- s->codec.config[0] = value & 0x07ff;
- omap_eac_format_update(s);
- break;
- case 0x0c0: /* AGCTR */
- s->codec.config[1] = value & 0x780f;
- omap_eac_format_update(s);
- break;
- case 0x0c4: /* AGCFR2 */
- s->codec.config[2] = value & 0x003f;
- omap_eac_format_update(s);
- break;
- case 0x0c8: /* AGCFR3 */
- s->codec.config[3] = value & 0xffff;
- omap_eac_format_update(s);
- break;
- case 0x0cc: /* MBPDMACTR */
- case 0x0d4: /* MPDDMAWR */
- case 0x0e0: /* MPUDMAWR */
- case 0x0e8: /* BPDDMAWR */
- case 0x0f0: /* BPUDMAWR */
- break;
-
- case 0x104: /* SYSCONFIG */
- if (value & (1 << 1)) /* SOFTRESET */
- omap_eac_reset(s);
- s->sysconfig = value & 0x31d;
- break;
-
- default:
- OMAP_BAD_REG(addr);
- return;
- }
-}
-
-static const MemoryRegionOps omap_eac_ops = {
- .read = omap_eac_read,
- .write = omap_eac_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static struct omap_eac_s *omap_eac_init(struct omap_target_agent_s *ta,
- qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk)
-{
- struct omap_eac_s *s = g_new0(struct omap_eac_s, 1);
-
- s->irq = irq;
- s->codec.rxdrq = *drq ++;
- s->codec.txdrq = *drq;
- omap_eac_reset(s);
-
- AUD_register_card("OMAP EAC", &s->codec.card);
-
- memory_region_init_io(&s->iomem, NULL, &omap_eac_ops, s, "omap.eac",
- omap_l4_region_size(ta, 0));
- omap_l4_attach(ta, 0, &s->iomem);
-
- return s;
-}
-
-/* STI/XTI (emulation interface) console - reverse engineered only */
-struct omap_sti_s {
- qemu_irq irq;
- MemoryRegion iomem;
- MemoryRegion iomem_fifo;
- CharDriverState *chr;
-
- uint32_t sysconfig;
- uint32_t systest;
- uint32_t irqst;
- uint32_t irqen;
- uint32_t clkcontrol;
- uint32_t serial_config;
-};
-
-#define STI_TRACE_CONSOLE_CHANNEL 239
-#define STI_TRACE_CONTROL_CHANNEL 253
-
-static inline void omap_sti_interrupt_update(struct omap_sti_s *s)
-{
- qemu_set_irq(s->irq, s->irqst & s->irqen);
-}
-
-static void omap_sti_reset(struct omap_sti_s *s)
-{
- s->sysconfig = 0;
- s->irqst = 0;
- s->irqen = 0;
- s->clkcontrol = 0;
- s->serial_config = 0;
-
- omap_sti_interrupt_update(s);
-}
-
-static uint64_t omap_sti_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_sti_s *s = (struct omap_sti_s *) opaque;
-
- if (size != 4) {
- return omap_badwidth_read32(opaque, addr);
- }
-
- switch (addr) {
- case 0x00: /* STI_REVISION */
- return 0x10;
-
- case 0x10: /* STI_SYSCONFIG */
- return s->sysconfig;
-
- case 0x14: /* STI_SYSSTATUS / STI_RX_STATUS / XTI_SYSSTATUS */
- return 0x00;
-
- case 0x18: /* STI_IRQSTATUS */
- return s->irqst;
-
- case 0x1c: /* STI_IRQSETEN / STI_IRQCLREN */
- return s->irqen;
-
- case 0x24: /* STI_ER / STI_DR / XTI_TRACESELECT */
- case 0x28: /* STI_RX_DR / XTI_RXDATA */
- /* TODO */
- return 0;
-
- case 0x2c: /* STI_CLK_CTRL / XTI_SCLKCRTL */
- return s->clkcontrol;
-
- case 0x30: /* STI_SERIAL_CFG / XTI_SCONFIG */
- return s->serial_config;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_sti_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_sti_s *s = (struct omap_sti_s *) opaque;
-
- if (size != 4) {
- omap_badwidth_write32(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x00: /* STI_REVISION */
- case 0x14: /* STI_SYSSTATUS / STI_RX_STATUS / XTI_SYSSTATUS */
- OMAP_RO_REG(addr);
- return;
-
- case 0x10: /* STI_SYSCONFIG */
- if (value & (1 << 1)) /* SOFTRESET */
- omap_sti_reset(s);
- s->sysconfig = value & 0xfe;
- break;
-
- case 0x18: /* STI_IRQSTATUS */
- s->irqst &= ~value;
- omap_sti_interrupt_update(s);
- break;
-
- case 0x1c: /* STI_IRQSETEN / STI_IRQCLREN */
- s->irqen = value & 0xffff;
- omap_sti_interrupt_update(s);
- break;
-
- case 0x2c: /* STI_CLK_CTRL / XTI_SCLKCRTL */
- s->clkcontrol = value & 0xff;
- break;
-
- case 0x30: /* STI_SERIAL_CFG / XTI_SCONFIG */
- s->serial_config = value & 0xff;
- break;
-
- case 0x24: /* STI_ER / STI_DR / XTI_TRACESELECT */
- case 0x28: /* STI_RX_DR / XTI_RXDATA */
- /* TODO */
- return;
-
- default:
- OMAP_BAD_REG(addr);
- return;
- }
-}
-
-static const MemoryRegionOps omap_sti_ops = {
- .read = omap_sti_read,
- .write = omap_sti_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static uint64_t omap_sti_fifo_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_sti_fifo_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_sti_s *s = (struct omap_sti_s *) opaque;
- int ch = addr >> 6;
- uint8_t byte = value;
-
- if (size != 1) {
- omap_badwidth_write8(opaque, addr, size);
- return;
- }
-
- if (ch == STI_TRACE_CONTROL_CHANNEL) {
- /* Flush channel <i>value</i>. */
- qemu_chr_fe_write(s->chr, (const uint8_t *) "\r", 1);
- } else if (ch == STI_TRACE_CONSOLE_CHANNEL || 1) {
- if (value == 0xc0 || value == 0xc3) {
- /* Open channel <i>ch</i>. */
- } else if (value == 0x00)
- qemu_chr_fe_write(s->chr, (const uint8_t *) "\n", 1);
- else
- qemu_chr_fe_write(s->chr, &byte, 1);
- }
-}
-
-static const MemoryRegionOps omap_sti_fifo_ops = {
- .read = omap_sti_fifo_read,
- .write = omap_sti_fifo_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static struct omap_sti_s *omap_sti_init(struct omap_target_agent_s *ta,
- MemoryRegion *sysmem,
- hwaddr channel_base, qemu_irq irq, omap_clk clk,
- CharDriverState *chr)
-{
- struct omap_sti_s *s = g_new0(struct omap_sti_s, 1);
-
- s->irq = irq;
- omap_sti_reset(s);
-
- s->chr = chr ?: qemu_chr_new("null", "null", NULL);
-
- memory_region_init_io(&s->iomem, NULL, &omap_sti_ops, s, "omap.sti",
- omap_l4_region_size(ta, 0));
- omap_l4_attach(ta, 0, &s->iomem);
-
- memory_region_init_io(&s->iomem_fifo, NULL, &omap_sti_fifo_ops, s,
- "omap.sti.fifo", 0x10000);
- memory_region_add_subregion(sysmem, channel_base, &s->iomem_fifo);
-
- return s;
-}
-
-/* L4 Interconnect */
-#define L4TA(n) (n)
-#define L4TAO(n) ((n) + 39)
-
-static const struct omap_l4_region_s omap_l4_region[125] = {
- [ 1] = { 0x40800, 0x800, 32 }, /* Initiator agent */
- [ 2] = { 0x41000, 0x1000, 32 }, /* Link agent */
- [ 0] = { 0x40000, 0x800, 32 }, /* Address and protection */
- [ 3] = { 0x00000, 0x1000, 32 | 16 | 8 }, /* System Control and Pinout */
- [ 4] = { 0x01000, 0x1000, 32 | 16 | 8 }, /* L4TAO1 */
- [ 5] = { 0x04000, 0x1000, 32 | 16 }, /* 32K Timer */
- [ 6] = { 0x05000, 0x1000, 32 | 16 | 8 }, /* L4TAO2 */
- [ 7] = { 0x08000, 0x800, 32 }, /* PRCM Region A */
- [ 8] = { 0x08800, 0x800, 32 }, /* PRCM Region B */
- [ 9] = { 0x09000, 0x1000, 32 | 16 | 8 }, /* L4TAO */
- [ 10] = { 0x12000, 0x1000, 32 | 16 | 8 }, /* Test (BCM) */
- [ 11] = { 0x13000, 0x1000, 32 | 16 | 8 }, /* L4TA1 */
- [ 12] = { 0x14000, 0x1000, 32 }, /* Test/emulation (TAP) */
- [ 13] = { 0x15000, 0x1000, 32 | 16 | 8 }, /* L4TA2 */
- [ 14] = { 0x18000, 0x1000, 32 | 16 | 8 }, /* GPIO1 */
- [ 16] = { 0x1a000, 0x1000, 32 | 16 | 8 }, /* GPIO2 */
- [ 18] = { 0x1c000, 0x1000, 32 | 16 | 8 }, /* GPIO3 */
- [ 19] = { 0x1e000, 0x1000, 32 | 16 | 8 }, /* GPIO4 */
- [ 15] = { 0x19000, 0x1000, 32 | 16 | 8 }, /* Quad GPIO TOP */
- [ 17] = { 0x1b000, 0x1000, 32 | 16 | 8 }, /* L4TA3 */
- [ 20] = { 0x20000, 0x1000, 32 | 16 | 8 }, /* WD Timer 1 (Secure) */
- [ 22] = { 0x22000, 0x1000, 32 | 16 | 8 }, /* WD Timer 2 (OMAP) */
- [ 21] = { 0x21000, 0x1000, 32 | 16 | 8 }, /* Dual WD timer TOP */
- [ 23] = { 0x23000, 0x1000, 32 | 16 | 8 }, /* L4TA4 */
- [ 24] = { 0x28000, 0x1000, 32 | 16 | 8 }, /* GP Timer 1 */
- [ 25] = { 0x29000, 0x1000, 32 | 16 | 8 }, /* L4TA7 */
- [ 26] = { 0x48000, 0x2000, 32 | 16 | 8 }, /* Emulation (ARM11ETB) */
- [ 27] = { 0x4a000, 0x1000, 32 | 16 | 8 }, /* L4TA9 */
- [ 28] = { 0x50000, 0x400, 32 | 16 | 8 }, /* Display top */
- [ 29] = { 0x50400, 0x400, 32 | 16 | 8 }, /* Display control */
- [ 30] = { 0x50800, 0x400, 32 | 16 | 8 }, /* Display RFBI */
- [ 31] = { 0x50c00, 0x400, 32 | 16 | 8 }, /* Display encoder */
- [ 32] = { 0x51000, 0x1000, 32 | 16 | 8 }, /* L4TA10 */
- [ 33] = { 0x52000, 0x400, 32 | 16 | 8 }, /* Camera top */
- [ 34] = { 0x52400, 0x400, 32 | 16 | 8 }, /* Camera core */
- [ 35] = { 0x52800, 0x400, 32 | 16 | 8 }, /* Camera DMA */
- [ 36] = { 0x52c00, 0x400, 32 | 16 | 8 }, /* Camera MMU */
- [ 37] = { 0x53000, 0x1000, 32 | 16 | 8 }, /* L4TA11 */
- [ 38] = { 0x56000, 0x1000, 32 | 16 | 8 }, /* sDMA */
- [ 39] = { 0x57000, 0x1000, 32 | 16 | 8 }, /* L4TA12 */
- [ 40] = { 0x58000, 0x1000, 32 | 16 | 8 }, /* SSI top */
- [ 41] = { 0x59000, 0x1000, 32 | 16 | 8 }, /* SSI GDD */
- [ 42] = { 0x5a000, 0x1000, 32 | 16 | 8 }, /* SSI Port1 */
- [ 43] = { 0x5b000, 0x1000, 32 | 16 | 8 }, /* SSI Port2 */
- [ 44] = { 0x5c000, 0x1000, 32 | 16 | 8 }, /* L4TA13 */
- [ 45] = { 0x5e000, 0x1000, 32 | 16 | 8 }, /* USB OTG */
- [ 46] = { 0x5f000, 0x1000, 32 | 16 | 8 }, /* L4TAO4 */
- [ 47] = { 0x60000, 0x1000, 32 | 16 | 8 }, /* Emulation (WIN_TRACER1SDRC) */
- [ 48] = { 0x61000, 0x1000, 32 | 16 | 8 }, /* L4TA14 */
- [ 49] = { 0x62000, 0x1000, 32 | 16 | 8 }, /* Emulation (WIN_TRACER2GPMC) */
- [ 50] = { 0x63000, 0x1000, 32 | 16 | 8 }, /* L4TA15 */
- [ 51] = { 0x64000, 0x1000, 32 | 16 | 8 }, /* Emulation (WIN_TRACER3OCM) */
- [ 52] = { 0x65000, 0x1000, 32 | 16 | 8 }, /* L4TA16 */
- [ 53] = { 0x66000, 0x300, 32 | 16 | 8 }, /* Emulation (WIN_TRACER4L4) */
- [ 54] = { 0x67000, 0x1000, 32 | 16 | 8 }, /* L4TA17 */
- [ 55] = { 0x68000, 0x1000, 32 | 16 | 8 }, /* Emulation (XTI) */
- [ 56] = { 0x69000, 0x1000, 32 | 16 | 8 }, /* L4TA18 */
- [ 57] = { 0x6a000, 0x1000, 16 | 8 }, /* UART1 */
- [ 58] = { 0x6b000, 0x1000, 32 | 16 | 8 }, /* L4TA19 */
- [ 59] = { 0x6c000, 0x1000, 16 | 8 }, /* UART2 */
- [ 60] = { 0x6d000, 0x1000, 32 | 16 | 8 }, /* L4TA20 */
- [ 61] = { 0x6e000, 0x1000, 16 | 8 }, /* UART3 */
- [ 62] = { 0x6f000, 0x1000, 32 | 16 | 8 }, /* L4TA21 */
- [ 63] = { 0x70000, 0x1000, 16 }, /* I2C1 */
- [ 64] = { 0x71000, 0x1000, 32 | 16 | 8 }, /* L4TAO5 */
- [ 65] = { 0x72000, 0x1000, 16 }, /* I2C2 */
- [ 66] = { 0x73000, 0x1000, 32 | 16 | 8 }, /* L4TAO6 */
- [ 67] = { 0x74000, 0x1000, 16 }, /* McBSP1 */
- [ 68] = { 0x75000, 0x1000, 32 | 16 | 8 }, /* L4TAO7 */
- [ 69] = { 0x76000, 0x1000, 16 }, /* McBSP2 */
- [ 70] = { 0x77000, 0x1000, 32 | 16 | 8 }, /* L4TAO8 */
- [ 71] = { 0x24000, 0x1000, 32 | 16 | 8 }, /* WD Timer 3 (DSP) */
- [ 72] = { 0x25000, 0x1000, 32 | 16 | 8 }, /* L4TA5 */
- [ 73] = { 0x26000, 0x1000, 32 | 16 | 8 }, /* WD Timer 4 (IVA) */
- [ 74] = { 0x27000, 0x1000, 32 | 16 | 8 }, /* L4TA6 */
- [ 75] = { 0x2a000, 0x1000, 32 | 16 | 8 }, /* GP Timer 2 */
- [ 76] = { 0x2b000, 0x1000, 32 | 16 | 8 }, /* L4TA8 */
- [ 77] = { 0x78000, 0x1000, 32 | 16 | 8 }, /* GP Timer 3 */
- [ 78] = { 0x79000, 0x1000, 32 | 16 | 8 }, /* L4TA22 */
- [ 79] = { 0x7a000, 0x1000, 32 | 16 | 8 }, /* GP Timer 4 */
- [ 80] = { 0x7b000, 0x1000, 32 | 16 | 8 }, /* L4TA23 */
- [ 81] = { 0x7c000, 0x1000, 32 | 16 | 8 }, /* GP Timer 5 */
- [ 82] = { 0x7d000, 0x1000, 32 | 16 | 8 }, /* L4TA24 */
- [ 83] = { 0x7e000, 0x1000, 32 | 16 | 8 }, /* GP Timer 6 */
- [ 84] = { 0x7f000, 0x1000, 32 | 16 | 8 }, /* L4TA25 */
- [ 85] = { 0x80000, 0x1000, 32 | 16 | 8 }, /* GP Timer 7 */
- [ 86] = { 0x81000, 0x1000, 32 | 16 | 8 }, /* L4TA26 */
- [ 87] = { 0x82000, 0x1000, 32 | 16 | 8 }, /* GP Timer 8 */
- [ 88] = { 0x83000, 0x1000, 32 | 16 | 8 }, /* L4TA27 */
- [ 89] = { 0x84000, 0x1000, 32 | 16 | 8 }, /* GP Timer 9 */
- [ 90] = { 0x85000, 0x1000, 32 | 16 | 8 }, /* L4TA28 */
- [ 91] = { 0x86000, 0x1000, 32 | 16 | 8 }, /* GP Timer 10 */
- [ 92] = { 0x87000, 0x1000, 32 | 16 | 8 }, /* L4TA29 */
- [ 93] = { 0x88000, 0x1000, 32 | 16 | 8 }, /* GP Timer 11 */
- [ 94] = { 0x89000, 0x1000, 32 | 16 | 8 }, /* L4TA30 */
- [ 95] = { 0x8a000, 0x1000, 32 | 16 | 8 }, /* GP Timer 12 */
- [ 96] = { 0x8b000, 0x1000, 32 | 16 | 8 }, /* L4TA31 */
- [ 97] = { 0x90000, 0x1000, 16 }, /* EAC */
- [ 98] = { 0x91000, 0x1000, 32 | 16 | 8 }, /* L4TA32 */
- [ 99] = { 0x92000, 0x1000, 16 }, /* FAC */
- [100] = { 0x93000, 0x1000, 32 | 16 | 8 }, /* L4TA33 */
- [101] = { 0x94000, 0x1000, 32 | 16 | 8 }, /* IPC (MAILBOX) */
- [102] = { 0x95000, 0x1000, 32 | 16 | 8 }, /* L4TA34 */
- [103] = { 0x98000, 0x1000, 32 | 16 | 8 }, /* SPI1 */
- [104] = { 0x99000, 0x1000, 32 | 16 | 8 }, /* L4TA35 */
- [105] = { 0x9a000, 0x1000, 32 | 16 | 8 }, /* SPI2 */
- [106] = { 0x9b000, 0x1000, 32 | 16 | 8 }, /* L4TA36 */
- [107] = { 0x9c000, 0x1000, 16 | 8 }, /* MMC SDIO */
- [108] = { 0x9d000, 0x1000, 32 | 16 | 8 }, /* L4TAO9 */
- [109] = { 0x9e000, 0x1000, 32 | 16 | 8 }, /* MS_PRO */
- [110] = { 0x9f000, 0x1000, 32 | 16 | 8 }, /* L4TAO10 */
- [111] = { 0xa0000, 0x1000, 32 }, /* RNG */
- [112] = { 0xa1000, 0x1000, 32 | 16 | 8 }, /* L4TAO11 */
- [113] = { 0xa2000, 0x1000, 32 }, /* DES3DES */
- [114] = { 0xa3000, 0x1000, 32 | 16 | 8 }, /* L4TAO12 */
- [115] = { 0xa4000, 0x1000, 32 }, /* SHA1MD5 */
- [116] = { 0xa5000, 0x1000, 32 | 16 | 8 }, /* L4TAO13 */
- [117] = { 0xa6000, 0x1000, 32 }, /* AES */
- [118] = { 0xa7000, 0x1000, 32 | 16 | 8 }, /* L4TA37 */
- [119] = { 0xa8000, 0x2000, 32 }, /* PKA */
- [120] = { 0xaa000, 0x1000, 32 | 16 | 8 }, /* L4TA38 */
- [121] = { 0xb0000, 0x1000, 32 }, /* MG */
- [122] = { 0xb1000, 0x1000, 32 | 16 | 8 },
- [123] = { 0xb2000, 0x1000, 32 }, /* HDQ/1-Wire */
- [124] = { 0xb3000, 0x1000, 32 | 16 | 8 }, /* L4TA39 */
-};
-
-static const struct omap_l4_agent_info_s omap_l4_agent_info[54] = {
- { 0, 0, 3, 2 }, /* L4IA initiatior agent */
- { L4TAO(1), 3, 2, 1 }, /* Control and pinout module */
- { L4TAO(2), 5, 2, 1 }, /* 32K timer */
- { L4TAO(3), 7, 3, 2 }, /* PRCM */
- { L4TA(1), 10, 2, 1 }, /* BCM */
- { L4TA(2), 12, 2, 1 }, /* Test JTAG */
- { L4TA(3), 14, 6, 3 }, /* Quad GPIO */
- { L4TA(4), 20, 4, 3 }, /* WD timer 1/2 */
- { L4TA(7), 24, 2, 1 }, /* GP timer 1 */
- { L4TA(9), 26, 2, 1 }, /* ATM11 ETB */
- { L4TA(10), 28, 5, 4 }, /* Display subsystem */
- { L4TA(11), 33, 5, 4 }, /* Camera subsystem */
- { L4TA(12), 38, 2, 1 }, /* sDMA */
- { L4TA(13), 40, 5, 4 }, /* SSI */
- { L4TAO(4), 45, 2, 1 }, /* USB */
- { L4TA(14), 47, 2, 1 }, /* Win Tracer1 */
- { L4TA(15), 49, 2, 1 }, /* Win Tracer2 */
- { L4TA(16), 51, 2, 1 }, /* Win Tracer3 */
- { L4TA(17), 53, 2, 1 }, /* Win Tracer4 */
- { L4TA(18), 55, 2, 1 }, /* XTI */
- { L4TA(19), 57, 2, 1 }, /* UART1 */
- { L4TA(20), 59, 2, 1 }, /* UART2 */
- { L4TA(21), 61, 2, 1 }, /* UART3 */
- { L4TAO(5), 63, 2, 1 }, /* I2C1 */
- { L4TAO(6), 65, 2, 1 }, /* I2C2 */
- { L4TAO(7), 67, 2, 1 }, /* McBSP1 */
- { L4TAO(8), 69, 2, 1 }, /* McBSP2 */
- { L4TA(5), 71, 2, 1 }, /* WD Timer 3 (DSP) */
- { L4TA(6), 73, 2, 1 }, /* WD Timer 4 (IVA) */
- { L4TA(8), 75, 2, 1 }, /* GP Timer 2 */
- { L4TA(22), 77, 2, 1 }, /* GP Timer 3 */
- { L4TA(23), 79, 2, 1 }, /* GP Timer 4 */
- { L4TA(24), 81, 2, 1 }, /* GP Timer 5 */
- { L4TA(25), 83, 2, 1 }, /* GP Timer 6 */
- { L4TA(26), 85, 2, 1 }, /* GP Timer 7 */
- { L4TA(27), 87, 2, 1 }, /* GP Timer 8 */
- { L4TA(28), 89, 2, 1 }, /* GP Timer 9 */
- { L4TA(29), 91, 2, 1 }, /* GP Timer 10 */
- { L4TA(30), 93, 2, 1 }, /* GP Timer 11 */
- { L4TA(31), 95, 2, 1 }, /* GP Timer 12 */
- { L4TA(32), 97, 2, 1 }, /* EAC */
- { L4TA(33), 99, 2, 1 }, /* FAC */
- { L4TA(34), 101, 2, 1 }, /* IPC */
- { L4TA(35), 103, 2, 1 }, /* SPI1 */
- { L4TA(36), 105, 2, 1 }, /* SPI2 */
- { L4TAO(9), 107, 2, 1 }, /* MMC SDIO */
- { L4TAO(10), 109, 2, 1 },
- { L4TAO(11), 111, 2, 1 }, /* RNG */
- { L4TAO(12), 113, 2, 1 }, /* DES3DES */
- { L4TAO(13), 115, 2, 1 }, /* SHA1MD5 */
- { L4TA(37), 117, 2, 1 }, /* AES */
- { L4TA(38), 119, 2, 1 }, /* PKA */
- { -1, 121, 2, 1 },
- { L4TA(39), 123, 2, 1 }, /* HDQ/1-Wire */
-};
-
-#define omap_l4ta(bus, cs) \
- omap_l4ta_get(bus, omap_l4_region, omap_l4_agent_info, L4TA(cs))
-#define omap_l4tao(bus, cs) \
- omap_l4ta_get(bus, omap_l4_region, omap_l4_agent_info, L4TAO(cs))
-
-/* Power, Reset, and Clock Management */
-struct omap_prcm_s {
- qemu_irq irq[3];
- struct omap_mpu_state_s *mpu;
- MemoryRegion iomem0;
- MemoryRegion iomem1;
-
- uint32_t irqst[3];
- uint32_t irqen[3];
-
- uint32_t sysconfig;
- uint32_t voltctrl;
- uint32_t scratch[20];
-
- uint32_t clksrc[1];
- uint32_t clkout[1];
- uint32_t clkemul[1];
- uint32_t clkpol[1];
- uint32_t clksel[8];
- uint32_t clken[12];
- uint32_t clkctrl[4];
- uint32_t clkidle[7];
- uint32_t setuptime[2];
-
- uint32_t wkup[3];
- uint32_t wken[3];
- uint32_t wkst[3];
- uint32_t rst[4];
- uint32_t rstctrl[1];
- uint32_t power[4];
- uint32_t rsttime_wkup;
-
- uint32_t ev;
- uint32_t evtime[2];
-
- int dpll_lock, apll_lock[2];
-};
-
-static void omap_prcm_int_update(struct omap_prcm_s *s, int dom)
-{
- qemu_set_irq(s->irq[dom], s->irqst[dom] & s->irqen[dom]);
- /* XXX or is the mask applied before PRCM_IRQSTATUS_* ? */
-}
-
-static uint64_t omap_prcm_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_prcm_s *s = (struct omap_prcm_s *) opaque;
- uint32_t ret;
-
- if (size != 4) {
- return omap_badwidth_read32(opaque, addr);
- }
-
- switch (addr) {
- case 0x000: /* PRCM_REVISION */
- return 0x10;
-
- case 0x010: /* PRCM_SYSCONFIG */
- return s->sysconfig;
-
- case 0x018: /* PRCM_IRQSTATUS_MPU */
- return s->irqst[0];
-
- case 0x01c: /* PRCM_IRQENABLE_MPU */
- return s->irqen[0];
-
- case 0x050: /* PRCM_VOLTCTRL */
- return s->voltctrl;
- case 0x054: /* PRCM_VOLTST */
- return s->voltctrl & 3;
-
- case 0x060: /* PRCM_CLKSRC_CTRL */
- return s->clksrc[0];
- case 0x070: /* PRCM_CLKOUT_CTRL */
- return s->clkout[0];
- case 0x078: /* PRCM_CLKEMUL_CTRL */
- return s->clkemul[0];
- case 0x080: /* PRCM_CLKCFG_CTRL */
- case 0x084: /* PRCM_CLKCFG_STATUS */
- return 0;
-
- case 0x090: /* PRCM_VOLTSETUP */
- return s->setuptime[0];
-
- case 0x094: /* PRCM_CLKSSETUP */
- return s->setuptime[1];
-
- case 0x098: /* PRCM_POLCTRL */
- return s->clkpol[0];
-
- case 0x0b0: /* GENERAL_PURPOSE1 */
- case 0x0b4: /* GENERAL_PURPOSE2 */
- case 0x0b8: /* GENERAL_PURPOSE3 */
- case 0x0bc: /* GENERAL_PURPOSE4 */
- case 0x0c0: /* GENERAL_PURPOSE5 */
- case 0x0c4: /* GENERAL_PURPOSE6 */
- case 0x0c8: /* GENERAL_PURPOSE7 */
- case 0x0cc: /* GENERAL_PURPOSE8 */
- case 0x0d0: /* GENERAL_PURPOSE9 */
- case 0x0d4: /* GENERAL_PURPOSE10 */
- case 0x0d8: /* GENERAL_PURPOSE11 */
- case 0x0dc: /* GENERAL_PURPOSE12 */
- case 0x0e0: /* GENERAL_PURPOSE13 */
- case 0x0e4: /* GENERAL_PURPOSE14 */
- case 0x0e8: /* GENERAL_PURPOSE15 */
- case 0x0ec: /* GENERAL_PURPOSE16 */
- case 0x0f0: /* GENERAL_PURPOSE17 */
- case 0x0f4: /* GENERAL_PURPOSE18 */
- case 0x0f8: /* GENERAL_PURPOSE19 */
- case 0x0fc: /* GENERAL_PURPOSE20 */
- return s->scratch[(addr - 0xb0) >> 2];
-
- case 0x140: /* CM_CLKSEL_MPU */
- return s->clksel[0];
- case 0x148: /* CM_CLKSTCTRL_MPU */
- return s->clkctrl[0];
-
- case 0x158: /* RM_RSTST_MPU */
- return s->rst[0];
- case 0x1c8: /* PM_WKDEP_MPU */
- return s->wkup[0];
- case 0x1d4: /* PM_EVGENCTRL_MPU */
- return s->ev;
- case 0x1d8: /* PM_EVEGENONTIM_MPU */
- return s->evtime[0];
- case 0x1dc: /* PM_EVEGENOFFTIM_MPU */
- return s->evtime[1];
- case 0x1e0: /* PM_PWSTCTRL_MPU */
- return s->power[0];
- case 0x1e4: /* PM_PWSTST_MPU */
- return 0;
-
- case 0x200: /* CM_FCLKEN1_CORE */
- return s->clken[0];
- case 0x204: /* CM_FCLKEN2_CORE */
- return s->clken[1];
- case 0x210: /* CM_ICLKEN1_CORE */
- return s->clken[2];
- case 0x214: /* CM_ICLKEN2_CORE */
- return s->clken[3];
- case 0x21c: /* CM_ICLKEN4_CORE */
- return s->clken[4];
-
- case 0x220: /* CM_IDLEST1_CORE */
- /* TODO: check the actual iclk status */
- return 0x7ffffff9;
- case 0x224: /* CM_IDLEST2_CORE */
- /* TODO: check the actual iclk status */
- return 0x00000007;
- case 0x22c: /* CM_IDLEST4_CORE */
- /* TODO: check the actual iclk status */
- return 0x0000001f;
-
- case 0x230: /* CM_AUTOIDLE1_CORE */
- return s->clkidle[0];
- case 0x234: /* CM_AUTOIDLE2_CORE */
- return s->clkidle[1];
- case 0x238: /* CM_AUTOIDLE3_CORE */
- return s->clkidle[2];
- case 0x23c: /* CM_AUTOIDLE4_CORE */
- return s->clkidle[3];
-
- case 0x240: /* CM_CLKSEL1_CORE */
- return s->clksel[1];
- case 0x244: /* CM_CLKSEL2_CORE */
- return s->clksel[2];
-
- case 0x248: /* CM_CLKSTCTRL_CORE */
- return s->clkctrl[1];
-
- case 0x2a0: /* PM_WKEN1_CORE */
- return s->wken[0];
- case 0x2a4: /* PM_WKEN2_CORE */
- return s->wken[1];
-
- case 0x2b0: /* PM_WKST1_CORE */
- return s->wkst[0];
- case 0x2b4: /* PM_WKST2_CORE */
- return s->wkst[1];
- case 0x2c8: /* PM_WKDEP_CORE */
- return 0x1e;
-
- case 0x2e0: /* PM_PWSTCTRL_CORE */
- return s->power[1];
- case 0x2e4: /* PM_PWSTST_CORE */
- return 0x000030 | (s->power[1] & 0xfc00);
-
- case 0x300: /* CM_FCLKEN_GFX */
- return s->clken[5];
- case 0x310: /* CM_ICLKEN_GFX */
- return s->clken[6];
- case 0x320: /* CM_IDLEST_GFX */
- /* TODO: check the actual iclk status */
- return 0x00000001;
- case 0x340: /* CM_CLKSEL_GFX */
- return s->clksel[3];
- case 0x348: /* CM_CLKSTCTRL_GFX */
- return s->clkctrl[2];
- case 0x350: /* RM_RSTCTRL_GFX */
- return s->rstctrl[0];
- case 0x358: /* RM_RSTST_GFX */
- return s->rst[1];
- case 0x3c8: /* PM_WKDEP_GFX */
- return s->wkup[1];
-
- case 0x3e0: /* PM_PWSTCTRL_GFX */
- return s->power[2];
- case 0x3e4: /* PM_PWSTST_GFX */
- return s->power[2] & 3;
-
- case 0x400: /* CM_FCLKEN_WKUP */
- return s->clken[7];
- case 0x410: /* CM_ICLKEN_WKUP */
- return s->clken[8];
- case 0x420: /* CM_IDLEST_WKUP */
- /* TODO: check the actual iclk status */
- return 0x0000003f;
- case 0x430: /* CM_AUTOIDLE_WKUP */
- return s->clkidle[4];
- case 0x440: /* CM_CLKSEL_WKUP */
- return s->clksel[4];
- case 0x450: /* RM_RSTCTRL_WKUP */
- return 0;
- case 0x454: /* RM_RSTTIME_WKUP */
- return s->rsttime_wkup;
- case 0x458: /* RM_RSTST_WKUP */
- return s->rst[2];
- case 0x4a0: /* PM_WKEN_WKUP */
- return s->wken[2];
- case 0x4b0: /* PM_WKST_WKUP */
- return s->wkst[2];
-
- case 0x500: /* CM_CLKEN_PLL */
- return s->clken[9];
- case 0x520: /* CM_IDLEST_CKGEN */
- ret = 0x0000070 | (s->apll_lock[0] << 9) | (s->apll_lock[1] << 8);
- if (!(s->clksel[6] & 3))
- /* Core uses 32-kHz clock */
- ret |= 3 << 0;
- else if (!s->dpll_lock)
- /* DPLL not locked, core uses ref_clk */
- ret |= 1 << 0;
- else
- /* Core uses DPLL */
- ret |= 2 << 0;
- return ret;
- case 0x530: /* CM_AUTOIDLE_PLL */
- return s->clkidle[5];
- case 0x540: /* CM_CLKSEL1_PLL */
- return s->clksel[5];
- case 0x544: /* CM_CLKSEL2_PLL */
- return s->clksel[6];
-
- case 0x800: /* CM_FCLKEN_DSP */
- return s->clken[10];
- case 0x810: /* CM_ICLKEN_DSP */
- return s->clken[11];
- case 0x820: /* CM_IDLEST_DSP */
- /* TODO: check the actual iclk status */
- return 0x00000103;
- case 0x830: /* CM_AUTOIDLE_DSP */
- return s->clkidle[6];
- case 0x840: /* CM_CLKSEL_DSP */
- return s->clksel[7];
- case 0x848: /* CM_CLKSTCTRL_DSP */
- return s->clkctrl[3];
- case 0x850: /* RM_RSTCTRL_DSP */
- return 0;
- case 0x858: /* RM_RSTST_DSP */
- return s->rst[3];
- case 0x8c8: /* PM_WKDEP_DSP */
- return s->wkup[2];
- case 0x8e0: /* PM_PWSTCTRL_DSP */
- return s->power[3];
- case 0x8e4: /* PM_PWSTST_DSP */
- return 0x008030 | (s->power[3] & 0x3003);
-
- case 0x8f0: /* PRCM_IRQSTATUS_DSP */
- return s->irqst[1];
- case 0x8f4: /* PRCM_IRQENABLE_DSP */
- return s->irqen[1];
-
- case 0x8f8: /* PRCM_IRQSTATUS_IVA */
- return s->irqst[2];
- case 0x8fc: /* PRCM_IRQENABLE_IVA */
- return s->irqen[2];
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_prcm_apll_update(struct omap_prcm_s *s)
-{
- int mode[2];
-
- mode[0] = (s->clken[9] >> 6) & 3;
- s->apll_lock[0] = (mode[0] == 3);
- mode[1] = (s->clken[9] >> 2) & 3;
- s->apll_lock[1] = (mode[1] == 3);
- /* TODO: update clocks */
-
- if (mode[0] == 1 || mode[0] == 2 || mode[1] == 1 || mode[1] == 2)
- fprintf(stderr, "%s: bad EN_54M_PLL or bad EN_96M_PLL\n",
- __FUNCTION__);
-}
-
-static void omap_prcm_dpll_update(struct omap_prcm_s *s)
-{
- omap_clk dpll = omap_findclk(s->mpu, "dpll");
- omap_clk dpll_x2 = omap_findclk(s->mpu, "dpll");
- omap_clk core = omap_findclk(s->mpu, "core_clk");
- int mode = (s->clken[9] >> 0) & 3;
- int mult, div;
-
- mult = (s->clksel[5] >> 12) & 0x3ff;
- div = (s->clksel[5] >> 8) & 0xf;
- if (mult == 0 || mult == 1)
- mode = 1; /* Bypass */
-
- s->dpll_lock = 0;
- switch (mode) {
- case 0:
- fprintf(stderr, "%s: bad EN_DPLL\n", __FUNCTION__);
- break;
- case 1: /* Low-power bypass mode (Default) */
- case 2: /* Fast-relock bypass mode */
- omap_clk_setrate(dpll, 1, 1);
- omap_clk_setrate(dpll_x2, 1, 1);
- break;
- case 3: /* Lock mode */
- s->dpll_lock = 1; /* After 20 FINT cycles (ref_clk / (div + 1)). */
-
- omap_clk_setrate(dpll, div + 1, mult);
- omap_clk_setrate(dpll_x2, div + 1, mult * 2);
- break;
- }
-
- switch ((s->clksel[6] >> 0) & 3) {
- case 0:
- omap_clk_reparent(core, omap_findclk(s->mpu, "clk32-kHz"));
- break;
- case 1:
- omap_clk_reparent(core, dpll);
- break;
- case 2:
- /* Default */
- omap_clk_reparent(core, dpll_x2);
- break;
- case 3:
- fprintf(stderr, "%s: bad CORE_CLK_SRC\n", __FUNCTION__);
- break;
- }
-}
-
-static void omap_prcm_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_prcm_s *s = (struct omap_prcm_s *) opaque;
-
- if (size != 4) {
- omap_badwidth_write32(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x000: /* PRCM_REVISION */
- case 0x054: /* PRCM_VOLTST */
- case 0x084: /* PRCM_CLKCFG_STATUS */
- case 0x1e4: /* PM_PWSTST_MPU */
- case 0x220: /* CM_IDLEST1_CORE */
- case 0x224: /* CM_IDLEST2_CORE */
- case 0x22c: /* CM_IDLEST4_CORE */
- case 0x2c8: /* PM_WKDEP_CORE */
- case 0x2e4: /* PM_PWSTST_CORE */
- case 0x320: /* CM_IDLEST_GFX */
- case 0x3e4: /* PM_PWSTST_GFX */
- case 0x420: /* CM_IDLEST_WKUP */
- case 0x520: /* CM_IDLEST_CKGEN */
- case 0x820: /* CM_IDLEST_DSP */
- case 0x8e4: /* PM_PWSTST_DSP */
- OMAP_RO_REG(addr);
- return;
-
- case 0x010: /* PRCM_SYSCONFIG */
- s->sysconfig = value & 1;
- break;
-
- case 0x018: /* PRCM_IRQSTATUS_MPU */
- s->irqst[0] &= ~value;
- omap_prcm_int_update(s, 0);
- break;
- case 0x01c: /* PRCM_IRQENABLE_MPU */
- s->irqen[0] = value & 0x3f;
- omap_prcm_int_update(s, 0);
- break;
-
- case 0x050: /* PRCM_VOLTCTRL */
- s->voltctrl = value & 0xf1c3;
- break;
-
- case 0x060: /* PRCM_CLKSRC_CTRL */
- s->clksrc[0] = value & 0xdb;
- /* TODO update clocks */
- break;
-
- case 0x070: /* PRCM_CLKOUT_CTRL */
- s->clkout[0] = value & 0xbbbb;
- /* TODO update clocks */
- break;
-
- case 0x078: /* PRCM_CLKEMUL_CTRL */
- s->clkemul[0] = value & 1;
- /* TODO update clocks */
- break;
-
- case 0x080: /* PRCM_CLKCFG_CTRL */
- break;
-
- case 0x090: /* PRCM_VOLTSETUP */
- s->setuptime[0] = value & 0xffff;
- break;
- case 0x094: /* PRCM_CLKSSETUP */
- s->setuptime[1] = value & 0xffff;
- break;
-
- case 0x098: /* PRCM_POLCTRL */
- s->clkpol[0] = value & 0x701;
- break;
-
- case 0x0b0: /* GENERAL_PURPOSE1 */
- case 0x0b4: /* GENERAL_PURPOSE2 */
- case 0x0b8: /* GENERAL_PURPOSE3 */
- case 0x0bc: /* GENERAL_PURPOSE4 */
- case 0x0c0: /* GENERAL_PURPOSE5 */
- case 0x0c4: /* GENERAL_PURPOSE6 */
- case 0x0c8: /* GENERAL_PURPOSE7 */
- case 0x0cc: /* GENERAL_PURPOSE8 */
- case 0x0d0: /* GENERAL_PURPOSE9 */
- case 0x0d4: /* GENERAL_PURPOSE10 */
- case 0x0d8: /* GENERAL_PURPOSE11 */
- case 0x0dc: /* GENERAL_PURPOSE12 */
- case 0x0e0: /* GENERAL_PURPOSE13 */
- case 0x0e4: /* GENERAL_PURPOSE14 */
- case 0x0e8: /* GENERAL_PURPOSE15 */
- case 0x0ec: /* GENERAL_PURPOSE16 */
- case 0x0f0: /* GENERAL_PURPOSE17 */
- case 0x0f4: /* GENERAL_PURPOSE18 */
- case 0x0f8: /* GENERAL_PURPOSE19 */
- case 0x0fc: /* GENERAL_PURPOSE20 */
- s->scratch[(addr - 0xb0) >> 2] = value;
- break;
-
- case 0x140: /* CM_CLKSEL_MPU */
- s->clksel[0] = value & 0x1f;
- /* TODO update clocks */
- break;
- case 0x148: /* CM_CLKSTCTRL_MPU */
- s->clkctrl[0] = value & 0x1f;
- break;
-
- case 0x158: /* RM_RSTST_MPU */
- s->rst[0] &= ~value;
- break;
- case 0x1c8: /* PM_WKDEP_MPU */
- s->wkup[0] = value & 0x15;
- break;
-
- case 0x1d4: /* PM_EVGENCTRL_MPU */
- s->ev = value & 0x1f;
- break;
- case 0x1d8: /* PM_EVEGENONTIM_MPU */
- s->evtime[0] = value;
- break;
- case 0x1dc: /* PM_EVEGENOFFTIM_MPU */
- s->evtime[1] = value;
- break;
-
- case 0x1e0: /* PM_PWSTCTRL_MPU */
- s->power[0] = value & 0xc0f;
- break;
-
- case 0x200: /* CM_FCLKEN1_CORE */
- s->clken[0] = value & 0xbfffffff;
- /* TODO update clocks */
- /* The EN_EAC bit only gets/puts func_96m_clk. */
- break;
- case 0x204: /* CM_FCLKEN2_CORE */
- s->clken[1] = value & 0x00000007;
- /* TODO update clocks */
- break;
- case 0x210: /* CM_ICLKEN1_CORE */
- s->clken[2] = value & 0xfffffff9;
- /* TODO update clocks */
- /* The EN_EAC bit only gets/puts core_l4_iclk. */
- break;
- case 0x214: /* CM_ICLKEN2_CORE */
- s->clken[3] = value & 0x00000007;
- /* TODO update clocks */
- break;
- case 0x21c: /* CM_ICLKEN4_CORE */
- s->clken[4] = value & 0x0000001f;
- /* TODO update clocks */
- break;
-
- case 0x230: /* CM_AUTOIDLE1_CORE */
- s->clkidle[0] = value & 0xfffffff9;
- /* TODO update clocks */
- break;
- case 0x234: /* CM_AUTOIDLE2_CORE */
- s->clkidle[1] = value & 0x00000007;
- /* TODO update clocks */
- break;
- case 0x238: /* CM_AUTOIDLE3_CORE */
- s->clkidle[2] = value & 0x00000007;
- /* TODO update clocks */
- break;
- case 0x23c: /* CM_AUTOIDLE4_CORE */
- s->clkidle[3] = value & 0x0000001f;
- /* TODO update clocks */
- break;
-
- case 0x240: /* CM_CLKSEL1_CORE */
- s->clksel[1] = value & 0x0fffbf7f;
- /* TODO update clocks */
- break;
-
- case 0x244: /* CM_CLKSEL2_CORE */
- s->clksel[2] = value & 0x00fffffc;
- /* TODO update clocks */
- break;
-
- case 0x248: /* CM_CLKSTCTRL_CORE */
- s->clkctrl[1] = value & 0x7;
- break;
-
- case 0x2a0: /* PM_WKEN1_CORE */
- s->wken[0] = value & 0x04667ff8;
- break;
- case 0x2a4: /* PM_WKEN2_CORE */
- s->wken[1] = value & 0x00000005;
- break;
-
- case 0x2b0: /* PM_WKST1_CORE */
- s->wkst[0] &= ~value;
- break;
- case 0x2b4: /* PM_WKST2_CORE */
- s->wkst[1] &= ~value;
- break;
-
- case 0x2e0: /* PM_PWSTCTRL_CORE */
- s->power[1] = (value & 0x00fc3f) | (1 << 2);
- break;
-
- case 0x300: /* CM_FCLKEN_GFX */
- s->clken[5] = value & 6;
- /* TODO update clocks */
- break;
- case 0x310: /* CM_ICLKEN_GFX */
- s->clken[6] = value & 1;
- /* TODO update clocks */
- break;
- case 0x340: /* CM_CLKSEL_GFX */
- s->clksel[3] = value & 7;
- /* TODO update clocks */
- break;
- case 0x348: /* CM_CLKSTCTRL_GFX */
- s->clkctrl[2] = value & 1;
- break;
- case 0x350: /* RM_RSTCTRL_GFX */
- s->rstctrl[0] = value & 1;
- /* TODO: reset */
- break;
- case 0x358: /* RM_RSTST_GFX */
- s->rst[1] &= ~value;
- break;
- case 0x3c8: /* PM_WKDEP_GFX */
- s->wkup[1] = value & 0x13;
- break;
- case 0x3e0: /* PM_PWSTCTRL_GFX */
- s->power[2] = (value & 0x00c0f) | (3 << 2);
- break;
-
- case 0x400: /* CM_FCLKEN_WKUP */
- s->clken[7] = value & 0xd;
- /* TODO update clocks */
- break;
- case 0x410: /* CM_ICLKEN_WKUP */
- s->clken[8] = value & 0x3f;
- /* TODO update clocks */
- break;
- case 0x430: /* CM_AUTOIDLE_WKUP */
- s->clkidle[4] = value & 0x0000003f;
- /* TODO update clocks */
- break;
- case 0x440: /* CM_CLKSEL_WKUP */
- s->clksel[4] = value & 3;
- /* TODO update clocks */
- break;
- case 0x450: /* RM_RSTCTRL_WKUP */
- /* TODO: reset */
- if (value & 2)
- qemu_system_reset_request();
- break;
- case 0x454: /* RM_RSTTIME_WKUP */
- s->rsttime_wkup = value & 0x1fff;
- break;
- case 0x458: /* RM_RSTST_WKUP */
- s->rst[2] &= ~value;
- break;
- case 0x4a0: /* PM_WKEN_WKUP */
- s->wken[2] = value & 0x00000005;
- break;
- case 0x4b0: /* PM_WKST_WKUP */
- s->wkst[2] &= ~value;
- break;
-
- case 0x500: /* CM_CLKEN_PLL */
- if (value & 0xffffff30)
- fprintf(stderr, "%s: write 0s in CM_CLKEN_PLL for "
- "future compatibility\n", __FUNCTION__);
- if ((s->clken[9] ^ value) & 0xcc) {
- s->clken[9] &= ~0xcc;
- s->clken[9] |= value & 0xcc;
- omap_prcm_apll_update(s);
- }
- if ((s->clken[9] ^ value) & 3) {
- s->clken[9] &= ~3;
- s->clken[9] |= value & 3;
- omap_prcm_dpll_update(s);
- }
- break;
- case 0x530: /* CM_AUTOIDLE_PLL */
- s->clkidle[5] = value & 0x000000cf;
- /* TODO update clocks */
- break;
- case 0x540: /* CM_CLKSEL1_PLL */
- if (value & 0xfc4000d7)
- fprintf(stderr, "%s: write 0s in CM_CLKSEL1_PLL for "
- "future compatibility\n", __FUNCTION__);
- if ((s->clksel[5] ^ value) & 0x003fff00) {
- s->clksel[5] = value & 0x03bfff28;
- omap_prcm_dpll_update(s);
- }
- /* TODO update the other clocks */
-
- s->clksel[5] = value & 0x03bfff28;
- break;
- case 0x544: /* CM_CLKSEL2_PLL */
- if (value & ~3)
- fprintf(stderr, "%s: write 0s in CM_CLKSEL2_PLL[31:2] for "
- "future compatibility\n", __FUNCTION__);
- if (s->clksel[6] != (value & 3)) {
- s->clksel[6] = value & 3;
- omap_prcm_dpll_update(s);
- }
- break;
-
- case 0x800: /* CM_FCLKEN_DSP */
- s->clken[10] = value & 0x501;
- /* TODO update clocks */
- break;
- case 0x810: /* CM_ICLKEN_DSP */
- s->clken[11] = value & 0x2;
- /* TODO update clocks */
- break;
- case 0x830: /* CM_AUTOIDLE_DSP */
- s->clkidle[6] = value & 0x2;
- /* TODO update clocks */
- break;
- case 0x840: /* CM_CLKSEL_DSP */
- s->clksel[7] = value & 0x3fff;
- /* TODO update clocks */
- break;
- case 0x848: /* CM_CLKSTCTRL_DSP */
- s->clkctrl[3] = value & 0x101;
- break;
- case 0x850: /* RM_RSTCTRL_DSP */
- /* TODO: reset */
- break;
- case 0x858: /* RM_RSTST_DSP */
- s->rst[3] &= ~value;
- break;
- case 0x8c8: /* PM_WKDEP_DSP */
- s->wkup[2] = value & 0x13;
- break;
- case 0x8e0: /* PM_PWSTCTRL_DSP */
- s->power[3] = (value & 0x03017) | (3 << 2);
- break;
-
- case 0x8f0: /* PRCM_IRQSTATUS_DSP */
- s->irqst[1] &= ~value;
- omap_prcm_int_update(s, 1);
- break;
- case 0x8f4: /* PRCM_IRQENABLE_DSP */
- s->irqen[1] = value & 0x7;
- omap_prcm_int_update(s, 1);
- break;
-
- case 0x8f8: /* PRCM_IRQSTATUS_IVA */
- s->irqst[2] &= ~value;
- omap_prcm_int_update(s, 2);
- break;
- case 0x8fc: /* PRCM_IRQENABLE_IVA */
- s->irqen[2] = value & 0x7;
- omap_prcm_int_update(s, 2);
- break;
-
- default:
- OMAP_BAD_REG(addr);
- return;
- }
-}
-
-static const MemoryRegionOps omap_prcm_ops = {
- .read = omap_prcm_read,
- .write = omap_prcm_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void omap_prcm_reset(struct omap_prcm_s *s)
-{
- s->sysconfig = 0;
- s->irqst[0] = 0;
- s->irqst[1] = 0;
- s->irqst[2] = 0;
- s->irqen[0] = 0;
- s->irqen[1] = 0;
- s->irqen[2] = 0;
- s->voltctrl = 0x1040;
- s->ev = 0x14;
- s->evtime[0] = 0;
- s->evtime[1] = 0;
- s->clkctrl[0] = 0;
- s->clkctrl[1] = 0;
- s->clkctrl[2] = 0;
- s->clkctrl[3] = 0;
- s->clken[1] = 7;
- s->clken[3] = 7;
- s->clken[4] = 0;
- s->clken[5] = 0;
- s->clken[6] = 0;
- s->clken[7] = 0xc;
- s->clken[8] = 0x3e;
- s->clken[9] = 0x0d;
- s->clken[10] = 0;
- s->clken[11] = 0;
- s->clkidle[0] = 0;
- s->clkidle[2] = 7;
- s->clkidle[3] = 0;
- s->clkidle[4] = 0;
- s->clkidle[5] = 0x0c;
- s->clkidle[6] = 0;
- s->clksel[0] = 0x01;
- s->clksel[1] = 0x02100121;
- s->clksel[2] = 0x00000000;
- s->clksel[3] = 0x01;
- s->clksel[4] = 0;
- s->clksel[7] = 0x0121;
- s->wkup[0] = 0x15;
- s->wkup[1] = 0x13;
- s->wkup[2] = 0x13;
- s->wken[0] = 0x04667ff8;
- s->wken[1] = 0x00000005;
- s->wken[2] = 5;
- s->wkst[0] = 0;
- s->wkst[1] = 0;
- s->wkst[2] = 0;
- s->power[0] = 0x00c;
- s->power[1] = 4;
- s->power[2] = 0x0000c;
- s->power[3] = 0x14;
- s->rstctrl[0] = 1;
- s->rst[3] = 1;
- omap_prcm_apll_update(s);
- omap_prcm_dpll_update(s);
-}
-
-static void omap_prcm_coldreset(struct omap_prcm_s *s)
-{
- s->setuptime[0] = 0;
- s->setuptime[1] = 0;
- memset(&s->scratch, 0, sizeof(s->scratch));
- s->rst[0] = 0x01;
- s->rst[1] = 0x00;
- s->rst[2] = 0x01;
- s->clken[0] = 0;
- s->clken[2] = 0;
- s->clkidle[1] = 0;
- s->clksel[5] = 0;
- s->clksel[6] = 2;
- s->clksrc[0] = 0x43;
- s->clkout[0] = 0x0303;
- s->clkemul[0] = 0;
- s->clkpol[0] = 0x100;
- s->rsttime_wkup = 0x1002;
-
- omap_prcm_reset(s);
-}
-
-static struct omap_prcm_s *omap_prcm_init(struct omap_target_agent_s *ta,
- qemu_irq mpu_int, qemu_irq dsp_int, qemu_irq iva_int,
- struct omap_mpu_state_s *mpu)
-{
- struct omap_prcm_s *s = g_new0(struct omap_prcm_s, 1);
-
- s->irq[0] = mpu_int;
- s->irq[1] = dsp_int;
- s->irq[2] = iva_int;
- s->mpu = mpu;
- omap_prcm_coldreset(s);
-
- memory_region_init_io(&s->iomem0, NULL, &omap_prcm_ops, s, "omap.pcrm0",
- omap_l4_region_size(ta, 0));
- memory_region_init_io(&s->iomem1, NULL, &omap_prcm_ops, s, "omap.pcrm1",
- omap_l4_region_size(ta, 1));
- omap_l4_attach(ta, 0, &s->iomem0);
- omap_l4_attach(ta, 1, &s->iomem1);
-
- return s;
-}
-
-/* System and Pinout control */
-struct omap_sysctl_s {
- struct omap_mpu_state_s *mpu;
- MemoryRegion iomem;
-
- uint32_t sysconfig;
- uint32_t devconfig;
- uint32_t psaconfig;
- uint32_t padconf[0x45];
- uint8_t obs;
- uint32_t msuspendmux[5];
-};
-
-static uint32_t omap_sysctl_read8(void *opaque, hwaddr addr)
-{
-
- struct omap_sysctl_s *s = (struct omap_sysctl_s *) opaque;
- int pad_offset, byte_offset;
- int value;
-
- switch (addr) {
- case 0x030 ... 0x140: /* CONTROL_PADCONF - only used in the POP */
- pad_offset = (addr - 0x30) >> 2;
- byte_offset = (addr - 0x30) & (4 - 1);
-
- value = s->padconf[pad_offset];
- value = (value >> (byte_offset * 8)) & 0xff;
-
- return value;
-
- default:
- break;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static uint32_t omap_sysctl_read(void *opaque, hwaddr addr)
-{
- struct omap_sysctl_s *s = (struct omap_sysctl_s *) opaque;
-
- switch (addr) {
- case 0x000: /* CONTROL_REVISION */
- return 0x20;
-
- case 0x010: /* CONTROL_SYSCONFIG */
- return s->sysconfig;
-
- case 0x030 ... 0x140: /* CONTROL_PADCONF - only used in the POP */
- return s->padconf[(addr - 0x30) >> 2];
-
- case 0x270: /* CONTROL_DEBOBS */
- return s->obs;
-
- case 0x274: /* CONTROL_DEVCONF */
- return s->devconfig;
-
- case 0x28c: /* CONTROL_EMU_SUPPORT */
- return 0;
-
- case 0x290: /* CONTROL_MSUSPENDMUX_0 */
- return s->msuspendmux[0];
- case 0x294: /* CONTROL_MSUSPENDMUX_1 */
- return s->msuspendmux[1];
- case 0x298: /* CONTROL_MSUSPENDMUX_2 */
- return s->msuspendmux[2];
- case 0x29c: /* CONTROL_MSUSPENDMUX_3 */
- return s->msuspendmux[3];
- case 0x2a0: /* CONTROL_MSUSPENDMUX_4 */
- return s->msuspendmux[4];
- case 0x2a4: /* CONTROL_MSUSPENDMUX_5 */
- return 0;
-
- case 0x2b8: /* CONTROL_PSA_CTRL */
- return s->psaconfig;
- case 0x2bc: /* CONTROL_PSA_CMD */
- case 0x2c0: /* CONTROL_PSA_VALUE */
- return 0;
-
- case 0x2b0: /* CONTROL_SEC_CTRL */
- return 0x800000f1;
- case 0x2d0: /* CONTROL_SEC_EMU */
- return 0x80000015;
- case 0x2d4: /* CONTROL_SEC_TAP */
- return 0x8000007f;
- case 0x2b4: /* CONTROL_SEC_TEST */
- case 0x2f0: /* CONTROL_SEC_STATUS */
- case 0x2f4: /* CONTROL_SEC_ERR_STATUS */
- /* Secure mode is not present on general-pusrpose device. Outside
- * secure mode these values cannot be read or written. */
- return 0;
-
- case 0x2d8: /* CONTROL_OCM_RAM_PERM */
- return 0xff;
- case 0x2dc: /* CONTROL_OCM_PUB_RAM_ADD */
- case 0x2e0: /* CONTROL_EXT_SEC_RAM_START_ADD */
- case 0x2e4: /* CONTROL_EXT_SEC_RAM_STOP_ADD */
- /* No secure mode so no Extended Secure RAM present. */
- return 0;
-
- case 0x2f8: /* CONTROL_STATUS */
- /* Device Type => General-purpose */
- return 0x0300;
- case 0x2fc: /* CONTROL_GENERAL_PURPOSE_STATUS */
-
- case 0x300: /* CONTROL_RPUB_KEY_H_0 */
- case 0x304: /* CONTROL_RPUB_KEY_H_1 */
- case 0x308: /* CONTROL_RPUB_KEY_H_2 */
- case 0x30c: /* CONTROL_RPUB_KEY_H_3 */
- return 0xdecafbad;
-
- case 0x310: /* CONTROL_RAND_KEY_0 */
- case 0x314: /* CONTROL_RAND_KEY_1 */
- case 0x318: /* CONTROL_RAND_KEY_2 */
- case 0x31c: /* CONTROL_RAND_KEY_3 */
- case 0x320: /* CONTROL_CUST_KEY_0 */
- case 0x324: /* CONTROL_CUST_KEY_1 */
- case 0x330: /* CONTROL_TEST_KEY_0 */
- case 0x334: /* CONTROL_TEST_KEY_1 */
- case 0x338: /* CONTROL_TEST_KEY_2 */
- case 0x33c: /* CONTROL_TEST_KEY_3 */
- case 0x340: /* CONTROL_TEST_KEY_4 */
- case 0x344: /* CONTROL_TEST_KEY_5 */
- case 0x348: /* CONTROL_TEST_KEY_6 */
- case 0x34c: /* CONTROL_TEST_KEY_7 */
- case 0x350: /* CONTROL_TEST_KEY_8 */
- case 0x354: /* CONTROL_TEST_KEY_9 */
- /* Can only be accessed in secure mode and when C_FieldAccEnable
- * bit is set in CONTROL_SEC_CTRL.
- * TODO: otherwise an interconnect access error is generated. */
- return 0;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_sysctl_write8(void *opaque, hwaddr addr,
- uint32_t value)
-{
- struct omap_sysctl_s *s = (struct omap_sysctl_s *) opaque;
- int pad_offset, byte_offset;
- int prev_value;
-
- switch (addr) {
- case 0x030 ... 0x140: /* CONTROL_PADCONF - only used in the POP */
- pad_offset = (addr - 0x30) >> 2;
- byte_offset = (addr - 0x30) & (4 - 1);
-
- prev_value = s->padconf[pad_offset];
- prev_value &= ~(0xff << (byte_offset * 8));
- prev_value |= ((value & 0x1f1f1f1f) << (byte_offset * 8)) & 0x1f1f1f1f;
- s->padconf[pad_offset] = prev_value;
- break;
-
- default:
- OMAP_BAD_REG(addr);
- break;
- }
-}
-
-static void omap_sysctl_write(void *opaque, hwaddr addr,
- uint32_t value)
-{
- struct omap_sysctl_s *s = (struct omap_sysctl_s *) opaque;
-
- switch (addr) {
- case 0x000: /* CONTROL_REVISION */
- case 0x2a4: /* CONTROL_MSUSPENDMUX_5 */
- case 0x2c0: /* CONTROL_PSA_VALUE */
- case 0x2f8: /* CONTROL_STATUS */
- case 0x2fc: /* CONTROL_GENERAL_PURPOSE_STATUS */
- case 0x300: /* CONTROL_RPUB_KEY_H_0 */
- case 0x304: /* CONTROL_RPUB_KEY_H_1 */
- case 0x308: /* CONTROL_RPUB_KEY_H_2 */
- case 0x30c: /* CONTROL_RPUB_KEY_H_3 */
- case 0x310: /* CONTROL_RAND_KEY_0 */
- case 0x314: /* CONTROL_RAND_KEY_1 */
- case 0x318: /* CONTROL_RAND_KEY_2 */
- case 0x31c: /* CONTROL_RAND_KEY_3 */
- case 0x320: /* CONTROL_CUST_KEY_0 */
- case 0x324: /* CONTROL_CUST_KEY_1 */
- case 0x330: /* CONTROL_TEST_KEY_0 */
- case 0x334: /* CONTROL_TEST_KEY_1 */
- case 0x338: /* CONTROL_TEST_KEY_2 */
- case 0x33c: /* CONTROL_TEST_KEY_3 */
- case 0x340: /* CONTROL_TEST_KEY_4 */
- case 0x344: /* CONTROL_TEST_KEY_5 */
- case 0x348: /* CONTROL_TEST_KEY_6 */
- case 0x34c: /* CONTROL_TEST_KEY_7 */
- case 0x350: /* CONTROL_TEST_KEY_8 */
- case 0x354: /* CONTROL_TEST_KEY_9 */
- OMAP_RO_REG(addr);
- return;
-
- case 0x010: /* CONTROL_SYSCONFIG */
- s->sysconfig = value & 0x1e;
- break;
-
- case 0x030 ... 0x140: /* CONTROL_PADCONF - only used in the POP */
- /* XXX: should check constant bits */
- s->padconf[(addr - 0x30) >> 2] = value & 0x1f1f1f1f;
- break;
-
- case 0x270: /* CONTROL_DEBOBS */
- s->obs = value & 0xff;
- break;
-
- case 0x274: /* CONTROL_DEVCONF */
- s->devconfig = value & 0xffffc7ff;
- break;
-
- case 0x28c: /* CONTROL_EMU_SUPPORT */
- break;
-
- case 0x290: /* CONTROL_MSUSPENDMUX_0 */
- s->msuspendmux[0] = value & 0x3fffffff;
- break;
- case 0x294: /* CONTROL_MSUSPENDMUX_1 */
- s->msuspendmux[1] = value & 0x3fffffff;
- break;
- case 0x298: /* CONTROL_MSUSPENDMUX_2 */
- s->msuspendmux[2] = value & 0x3fffffff;
- break;
- case 0x29c: /* CONTROL_MSUSPENDMUX_3 */
- s->msuspendmux[3] = value & 0x3fffffff;
- break;
- case 0x2a0: /* CONTROL_MSUSPENDMUX_4 */
- s->msuspendmux[4] = value & 0x3fffffff;
- break;
-
- case 0x2b8: /* CONTROL_PSA_CTRL */
- s->psaconfig = value & 0x1c;
- s->psaconfig |= (value & 0x20) ? 2 : 1;
- break;
- case 0x2bc: /* CONTROL_PSA_CMD */
- break;
-
- case 0x2b0: /* CONTROL_SEC_CTRL */
- case 0x2b4: /* CONTROL_SEC_TEST */
- case 0x2d0: /* CONTROL_SEC_EMU */
- case 0x2d4: /* CONTROL_SEC_TAP */
- case 0x2d8: /* CONTROL_OCM_RAM_PERM */
- case 0x2dc: /* CONTROL_OCM_PUB_RAM_ADD */
- case 0x2e0: /* CONTROL_EXT_SEC_RAM_START_ADD */
- case 0x2e4: /* CONTROL_EXT_SEC_RAM_STOP_ADD */
- case 0x2f0: /* CONTROL_SEC_STATUS */
- case 0x2f4: /* CONTROL_SEC_ERR_STATUS */
- break;
-
- default:
- OMAP_BAD_REG(addr);
- return;
- }
-}
-
-static const MemoryRegionOps omap_sysctl_ops = {
- .old_mmio = {
- .read = {
- omap_sysctl_read8,
- omap_badwidth_read32, /* TODO */
- omap_sysctl_read,
- },
- .write = {
- omap_sysctl_write8,
- omap_badwidth_write32, /* TODO */
- omap_sysctl_write,
- },
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void omap_sysctl_reset(struct omap_sysctl_s *s)
-{
- /* (power-on reset) */
- s->sysconfig = 0;
- s->obs = 0;
- s->devconfig = 0x0c000000;
- s->msuspendmux[0] = 0x00000000;
- s->msuspendmux[1] = 0x00000000;
- s->msuspendmux[2] = 0x00000000;
- s->msuspendmux[3] = 0x00000000;
- s->msuspendmux[4] = 0x00000000;
- s->psaconfig = 1;
-
- s->padconf[0x00] = 0x000f0f0f;
- s->padconf[0x01] = 0x00000000;
- s->padconf[0x02] = 0x00000000;
- s->padconf[0x03] = 0x00000000;
- s->padconf[0x04] = 0x00000000;
- s->padconf[0x05] = 0x00000000;
- s->padconf[0x06] = 0x00000000;
- s->padconf[0x07] = 0x00000000;
- s->padconf[0x08] = 0x08080800;
- s->padconf[0x09] = 0x08080808;
- s->padconf[0x0a] = 0x08080808;
- s->padconf[0x0b] = 0x08080808;
- s->padconf[0x0c] = 0x08080808;
- s->padconf[0x0d] = 0x08080800;
- s->padconf[0x0e] = 0x08080808;
- s->padconf[0x0f] = 0x08080808;
- s->padconf[0x10] = 0x18181808; /* | 0x07070700 if SBoot3 */
- s->padconf[0x11] = 0x18181818; /* | 0x07070707 if SBoot3 */
- s->padconf[0x12] = 0x18181818; /* | 0x07070707 if SBoot3 */
- s->padconf[0x13] = 0x18181818; /* | 0x07070707 if SBoot3 */
- s->padconf[0x14] = 0x18181818; /* | 0x00070707 if SBoot3 */
- s->padconf[0x15] = 0x18181818;
- s->padconf[0x16] = 0x18181818; /* | 0x07000000 if SBoot3 */
- s->padconf[0x17] = 0x1f001f00;
- s->padconf[0x18] = 0x1f1f1f1f;
- s->padconf[0x19] = 0x00000000;
- s->padconf[0x1a] = 0x1f180000;
- s->padconf[0x1b] = 0x00001f1f;
- s->padconf[0x1c] = 0x1f001f00;
- s->padconf[0x1d] = 0x00000000;
- s->padconf[0x1e] = 0x00000000;
- s->padconf[0x1f] = 0x08000000;
- s->padconf[0x20] = 0x08080808;
- s->padconf[0x21] = 0x08080808;
- s->padconf[0x22] = 0x0f080808;
- s->padconf[0x23] = 0x0f0f0f0f;
- s->padconf[0x24] = 0x000f0f0f;
- s->padconf[0x25] = 0x1f1f1f0f;
- s->padconf[0x26] = 0x080f0f1f;
- s->padconf[0x27] = 0x070f1808;
- s->padconf[0x28] = 0x0f070707;
- s->padconf[0x29] = 0x000f0f1f;
- s->padconf[0x2a] = 0x0f0f0f1f;
- s->padconf[0x2b] = 0x08000000;
- s->padconf[0x2c] = 0x0000001f;
- s->padconf[0x2d] = 0x0f0f1f00;
- s->padconf[0x2e] = 0x1f1f0f0f;
- s->padconf[0x2f] = 0x0f1f1f1f;
- s->padconf[0x30] = 0x0f0f0f0f;
- s->padconf[0x31] = 0x0f1f0f1f;
- s->padconf[0x32] = 0x0f0f0f0f;
- s->padconf[0x33] = 0x0f1f0f1f;
- s->padconf[0x34] = 0x1f1f0f0f;
- s->padconf[0x35] = 0x0f0f1f1f;
- s->padconf[0x36] = 0x0f0f1f0f;
- s->padconf[0x37] = 0x0f0f0f0f;
- s->padconf[0x38] = 0x1f18180f;
- s->padconf[0x39] = 0x1f1f1f1f;
- s->padconf[0x3a] = 0x00001f1f;
- s->padconf[0x3b] = 0x00000000;
- s->padconf[0x3c] = 0x00000000;
- s->padconf[0x3d] = 0x0f0f0f0f;
- s->padconf[0x3e] = 0x18000f0f;
- s->padconf[0x3f] = 0x00070000;
- s->padconf[0x40] = 0x00000707;
- s->padconf[0x41] = 0x0f1f0700;
- s->padconf[0x42] = 0x1f1f070f;
- s->padconf[0x43] = 0x0008081f;
- s->padconf[0x44] = 0x00000800;
-}
-
-static struct omap_sysctl_s *omap_sysctl_init(struct omap_target_agent_s *ta,
- omap_clk iclk, struct omap_mpu_state_s *mpu)
-{
- struct omap_sysctl_s *s = g_new0(struct omap_sysctl_s, 1);
-
- s->mpu = mpu;
- omap_sysctl_reset(s);
-
- memory_region_init_io(&s->iomem, NULL, &omap_sysctl_ops, s, "omap.sysctl",
- omap_l4_region_size(ta, 0));
- omap_l4_attach(ta, 0, &s->iomem);
-
- return s;
-}
-
-/* General chip reset */
-static void omap2_mpu_reset(void *opaque)
-{
- struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque;
-
- omap_dma_reset(mpu->dma);
- omap_prcm_reset(mpu->prcm);
- omap_sysctl_reset(mpu->sysc);
- omap_gp_timer_reset(mpu->gptimer[0]);
- omap_gp_timer_reset(mpu->gptimer[1]);
- omap_gp_timer_reset(mpu->gptimer[2]);
- omap_gp_timer_reset(mpu->gptimer[3]);
- omap_gp_timer_reset(mpu->gptimer[4]);
- omap_gp_timer_reset(mpu->gptimer[5]);
- omap_gp_timer_reset(mpu->gptimer[6]);
- omap_gp_timer_reset(mpu->gptimer[7]);
- omap_gp_timer_reset(mpu->gptimer[8]);
- omap_gp_timer_reset(mpu->gptimer[9]);
- omap_gp_timer_reset(mpu->gptimer[10]);
- omap_gp_timer_reset(mpu->gptimer[11]);
- omap_synctimer_reset(mpu->synctimer);
- omap_sdrc_reset(mpu->sdrc);
- omap_gpmc_reset(mpu->gpmc);
- omap_dss_reset(mpu->dss);
- omap_uart_reset(mpu->uart[0]);
- omap_uart_reset(mpu->uart[1]);
- omap_uart_reset(mpu->uart[2]);
- omap_mmc_reset(mpu->mmc);
- omap_mcspi_reset(mpu->mcspi[0]);
- omap_mcspi_reset(mpu->mcspi[1]);
- cpu_reset(CPU(mpu->cpu));
-}
-
-static int omap2_validate_addr(struct omap_mpu_state_s *s,
- hwaddr addr)
-{
- return 1;
-}
-
-static const struct dma_irq_map omap2_dma_irq_map[] = {
- { 0, OMAP_INT_24XX_SDMA_IRQ0 },
- { 0, OMAP_INT_24XX_SDMA_IRQ1 },
- { 0, OMAP_INT_24XX_SDMA_IRQ2 },
- { 0, OMAP_INT_24XX_SDMA_IRQ3 },
-};
-
-struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sysmem,
- unsigned long sdram_size,
- const char *core)
-{
- struct omap_mpu_state_s *s = g_new0(struct omap_mpu_state_s, 1);
- qemu_irq dma_irqs[4];
- DriveInfo *dinfo;
- int i;
- SysBusDevice *busdev;
- struct omap_target_agent_s *ta;
-
- /* Core */
- s->mpu_model = omap2420;
- s->cpu = cpu_arm_init(core ?: "arm1136-r2");
- if (s->cpu == NULL) {
- fprintf(stderr, "Unable to find CPU definition\n");
- exit(1);
- }
- s->sdram_size = sdram_size;
- s->sram_size = OMAP242X_SRAM_SIZE;
-
- s->wakeup = qemu_allocate_irq(omap_mpu_wakeup, s, 0);
-
- /* Clocks */
- omap_clk_init(s);
-
- /* Memory-mapped stuff */
- memory_region_allocate_system_memory(&s->sdram, NULL, "omap2.dram",
- s->sdram_size);
- memory_region_add_subregion(sysmem, OMAP2_Q2_BASE, &s->sdram);
- memory_region_init_ram(&s->sram, NULL, "omap2.sram", s->sram_size,
- &error_fatal);
- vmstate_register_ram_global(&s->sram);
- memory_region_add_subregion(sysmem, OMAP2_SRAM_BASE, &s->sram);
-
- s->l4 = omap_l4_init(sysmem, OMAP2_L4_BASE, 54);
-
- /* Actually mapped at any 2K boundary in the ARM11 private-peripheral if */
- s->ih[0] = qdev_create(NULL, "omap2-intc");
- qdev_prop_set_uint8(s->ih[0], "revision", 0x21);
- qdev_prop_set_ptr(s->ih[0], "fclk", omap_findclk(s, "mpu_intc_fclk"));
- qdev_prop_set_ptr(s->ih[0], "iclk", omap_findclk(s, "mpu_intc_iclk"));
- qdev_init_nofail(s->ih[0]);
- busdev = SYS_BUS_DEVICE(s->ih[0]);
- sysbus_connect_irq(busdev, 0,
- qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_IRQ));
- sysbus_connect_irq(busdev, 1,
- qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_FIQ));
- sysbus_mmio_map(busdev, 0, 0x480fe000);
- s->prcm = omap_prcm_init(omap_l4tao(s->l4, 3),
- qdev_get_gpio_in(s->ih[0],
- OMAP_INT_24XX_PRCM_MPU_IRQ),
- NULL, NULL, s);
-
- s->sysc = omap_sysctl_init(omap_l4tao(s->l4, 1),
- omap_findclk(s, "omapctrl_iclk"), s);
-
- for (i = 0; i < 4; i++) {
- dma_irqs[i] = qdev_get_gpio_in(s->ih[omap2_dma_irq_map[i].ih],
- omap2_dma_irq_map[i].intr);
- }
- s->dma = omap_dma4_init(0x48056000, dma_irqs, sysmem, s, 256, 32,
- omap_findclk(s, "sdma_iclk"),
- omap_findclk(s, "sdma_fclk"));
- s->port->addr_valid = omap2_validate_addr;
-
- /* Register SDRAM and SRAM ports for fast DMA transfers. */
- soc_dma_port_add_mem(s->dma, memory_region_get_ram_ptr(&s->sdram),
- OMAP2_Q2_BASE, s->sdram_size);
- soc_dma_port_add_mem(s->dma, memory_region_get_ram_ptr(&s->sram),
- OMAP2_SRAM_BASE, s->sram_size);
-
- s->uart[0] = omap2_uart_init(sysmem, omap_l4ta(s->l4, 19),
- qdev_get_gpio_in(s->ih[0],
- OMAP_INT_24XX_UART1_IRQ),
- omap_findclk(s, "uart1_fclk"),
- omap_findclk(s, "uart1_iclk"),
- s->drq[OMAP24XX_DMA_UART1_TX],
- s->drq[OMAP24XX_DMA_UART1_RX],
- "uart1",
- serial_hds[0]);
- s->uart[1] = omap2_uart_init(sysmem, omap_l4ta(s->l4, 20),
- qdev_get_gpio_in(s->ih[0],
- OMAP_INT_24XX_UART2_IRQ),
- omap_findclk(s, "uart2_fclk"),
- omap_findclk(s, "uart2_iclk"),
- s->drq[OMAP24XX_DMA_UART2_TX],
- s->drq[OMAP24XX_DMA_UART2_RX],
- "uart2",
- serial_hds[0] ? serial_hds[1] : NULL);
- s->uart[2] = omap2_uart_init(sysmem, omap_l4ta(s->l4, 21),
- qdev_get_gpio_in(s->ih[0],
- OMAP_INT_24XX_UART3_IRQ),
- omap_findclk(s, "uart3_fclk"),
- omap_findclk(s, "uart3_iclk"),
- s->drq[OMAP24XX_DMA_UART3_TX],
- s->drq[OMAP24XX_DMA_UART3_RX],
- "uart3",
- serial_hds[0] && serial_hds[1] ? serial_hds[2] : NULL);
-
- s->gptimer[0] = omap_gp_timer_init(omap_l4ta(s->l4, 7),
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER1),
- omap_findclk(s, "wu_gpt1_clk"),
- omap_findclk(s, "wu_l4_iclk"));
- s->gptimer[1] = omap_gp_timer_init(omap_l4ta(s->l4, 8),
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER2),
- omap_findclk(s, "core_gpt2_clk"),
- omap_findclk(s, "core_l4_iclk"));
- s->gptimer[2] = omap_gp_timer_init(omap_l4ta(s->l4, 22),
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER3),
- omap_findclk(s, "core_gpt3_clk"),
- omap_findclk(s, "core_l4_iclk"));
- s->gptimer[3] = omap_gp_timer_init(omap_l4ta(s->l4, 23),
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER4),
- omap_findclk(s, "core_gpt4_clk"),
- omap_findclk(s, "core_l4_iclk"));
- s->gptimer[4] = omap_gp_timer_init(omap_l4ta(s->l4, 24),
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER5),
- omap_findclk(s, "core_gpt5_clk"),
- omap_findclk(s, "core_l4_iclk"));
- s->gptimer[5] = omap_gp_timer_init(omap_l4ta(s->l4, 25),
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER6),
- omap_findclk(s, "core_gpt6_clk"),
- omap_findclk(s, "core_l4_iclk"));
- s->gptimer[6] = omap_gp_timer_init(omap_l4ta(s->l4, 26),
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER7),
- omap_findclk(s, "core_gpt7_clk"),
- omap_findclk(s, "core_l4_iclk"));
- s->gptimer[7] = omap_gp_timer_init(omap_l4ta(s->l4, 27),
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER8),
- omap_findclk(s, "core_gpt8_clk"),
- omap_findclk(s, "core_l4_iclk"));
- s->gptimer[8] = omap_gp_timer_init(omap_l4ta(s->l4, 28),
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER9),
- omap_findclk(s, "core_gpt9_clk"),
- omap_findclk(s, "core_l4_iclk"));
- s->gptimer[9] = omap_gp_timer_init(omap_l4ta(s->l4, 29),
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER10),
- omap_findclk(s, "core_gpt10_clk"),
- omap_findclk(s, "core_l4_iclk"));
- s->gptimer[10] = omap_gp_timer_init(omap_l4ta(s->l4, 30),
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER11),
- omap_findclk(s, "core_gpt11_clk"),
- omap_findclk(s, "core_l4_iclk"));
- s->gptimer[11] = omap_gp_timer_init(omap_l4ta(s->l4, 31),
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER12),
- omap_findclk(s, "core_gpt12_clk"),
- omap_findclk(s, "core_l4_iclk"));
-
- omap_tap_init(omap_l4ta(s->l4, 2), s);
-
- s->synctimer = omap_synctimer_init(omap_l4tao(s->l4, 2), s,
- omap_findclk(s, "clk32-kHz"),
- omap_findclk(s, "core_l4_iclk"));
-
- s->i2c[0] = qdev_create(NULL, "omap_i2c");
- qdev_prop_set_uint8(s->i2c[0], "revision", 0x34);
- qdev_prop_set_ptr(s->i2c[0], "iclk", omap_findclk(s, "i2c1.iclk"));
- qdev_prop_set_ptr(s->i2c[0], "fclk", omap_findclk(s, "i2c1.fclk"));
- qdev_init_nofail(s->i2c[0]);
- busdev = SYS_BUS_DEVICE(s->i2c[0]);
- sysbus_connect_irq(busdev, 0,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_I2C1_IRQ));
- sysbus_connect_irq(busdev, 1, s->drq[OMAP24XX_DMA_I2C1_TX]);
- sysbus_connect_irq(busdev, 2, s->drq[OMAP24XX_DMA_I2C1_RX]);
- sysbus_mmio_map(busdev, 0, omap_l4_region_base(omap_l4tao(s->l4, 5), 0));
-
- s->i2c[1] = qdev_create(NULL, "omap_i2c");
- qdev_prop_set_uint8(s->i2c[1], "revision", 0x34);
- qdev_prop_set_ptr(s->i2c[1], "iclk", omap_findclk(s, "i2c2.iclk"));
- qdev_prop_set_ptr(s->i2c[1], "fclk", omap_findclk(s, "i2c2.fclk"));
- qdev_init_nofail(s->i2c[1]);
- busdev = SYS_BUS_DEVICE(s->i2c[1]);
- sysbus_connect_irq(busdev, 0,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_I2C2_IRQ));
- sysbus_connect_irq(busdev, 1, s->drq[OMAP24XX_DMA_I2C2_TX]);
- sysbus_connect_irq(busdev, 2, s->drq[OMAP24XX_DMA_I2C2_RX]);
- sysbus_mmio_map(busdev, 0, omap_l4_region_base(omap_l4tao(s->l4, 6), 0));
-
- s->gpio = qdev_create(NULL, "omap2-gpio");
- qdev_prop_set_int32(s->gpio, "mpu_model", s->mpu_model);
- qdev_prop_set_ptr(s->gpio, "iclk", omap_findclk(s, "gpio_iclk"));
- qdev_prop_set_ptr(s->gpio, "fclk0", omap_findclk(s, "gpio1_dbclk"));
- qdev_prop_set_ptr(s->gpio, "fclk1", omap_findclk(s, "gpio2_dbclk"));
- qdev_prop_set_ptr(s->gpio, "fclk2", omap_findclk(s, "gpio3_dbclk"));
- qdev_prop_set_ptr(s->gpio, "fclk3", omap_findclk(s, "gpio4_dbclk"));
- if (s->mpu_model == omap2430) {
- qdev_prop_set_ptr(s->gpio, "fclk4", omap_findclk(s, "gpio5_dbclk"));
- }
- qdev_init_nofail(s->gpio);
- busdev = SYS_BUS_DEVICE(s->gpio);
- sysbus_connect_irq(busdev, 0,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK1));
- sysbus_connect_irq(busdev, 3,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK2));
- sysbus_connect_irq(busdev, 6,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK3));
- sysbus_connect_irq(busdev, 9,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK4));
- if (s->mpu_model == omap2430) {
- sysbus_connect_irq(busdev, 12,
- qdev_get_gpio_in(s->ih[0],
- OMAP_INT_243X_GPIO_BANK5));
- }
- ta = omap_l4ta(s->l4, 3);
- sysbus_mmio_map(busdev, 0, omap_l4_region_base(ta, 1));
- sysbus_mmio_map(busdev, 1, omap_l4_region_base(ta, 0));
- sysbus_mmio_map(busdev, 2, omap_l4_region_base(ta, 2));
- sysbus_mmio_map(busdev, 3, omap_l4_region_base(ta, 4));
- sysbus_mmio_map(busdev, 4, omap_l4_region_base(ta, 5));
-
- s->sdrc = omap_sdrc_init(sysmem, 0x68009000);
- s->gpmc = omap_gpmc_init(s, 0x6800a000,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPMC_IRQ),
- s->drq[OMAP24XX_DMA_GPMC]);
-
- dinfo = drive_get(IF_SD, 0, 0);
- if (!dinfo) {
- fprintf(stderr, "qemu: missing SecureDigital device\n");
- exit(1);
- }
- s->mmc = omap2_mmc_init(omap_l4tao(s->l4, 9),
- blk_by_legacy_dinfo(dinfo),
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_MMC_IRQ),
- &s->drq[OMAP24XX_DMA_MMC1_TX],
- omap_findclk(s, "mmc_fclk"), omap_findclk(s, "mmc_iclk"));
-
- s->mcspi[0] = omap_mcspi_init(omap_l4ta(s->l4, 35), 4,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_MCSPI1_IRQ),
- &s->drq[OMAP24XX_DMA_SPI1_TX0],
- omap_findclk(s, "spi1_fclk"),
- omap_findclk(s, "spi1_iclk"));
- s->mcspi[1] = omap_mcspi_init(omap_l4ta(s->l4, 36), 2,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_MCSPI2_IRQ),
- &s->drq[OMAP24XX_DMA_SPI2_TX0],
- omap_findclk(s, "spi2_fclk"),
- omap_findclk(s, "spi2_iclk"));
-
- s->dss = omap_dss_init(omap_l4ta(s->l4, 10), sysmem, 0x68000800,
- /* XXX wire M_IRQ_25, D_L2_IRQ_30 and I_IRQ_13 together */
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_DSS_IRQ),
- s->drq[OMAP24XX_DMA_DSS],
- omap_findclk(s, "dss_clk1"), omap_findclk(s, "dss_clk2"),
- omap_findclk(s, "dss_54m_clk"),
- omap_findclk(s, "dss_l3_iclk"),
- omap_findclk(s, "dss_l4_iclk"));
-
- omap_sti_init(omap_l4ta(s->l4, 18), sysmem, 0x54000000,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_STI),
- omap_findclk(s, "emul_ck"),
- serial_hds[0] && serial_hds[1] && serial_hds[2] ?
- serial_hds[3] : NULL);
-
- s->eac = omap_eac_init(omap_l4ta(s->l4, 32),
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_EAC_IRQ),
- /* Ten consecutive lines */
- &s->drq[OMAP24XX_DMA_EAC_AC_RD],
- omap_findclk(s, "func_96m_clk"),
- omap_findclk(s, "core_l4_iclk"));
-
- /* All register mappings (includin those not currenlty implemented):
- * SystemControlMod 48000000 - 48000fff
- * SystemControlL4 48001000 - 48001fff
- * 32kHz Timer Mod 48004000 - 48004fff
- * 32kHz Timer L4 48005000 - 48005fff
- * PRCM ModA 48008000 - 480087ff
- * PRCM ModB 48008800 - 48008fff
- * PRCM L4 48009000 - 48009fff
- * TEST-BCM Mod 48012000 - 48012fff
- * TEST-BCM L4 48013000 - 48013fff
- * TEST-TAP Mod 48014000 - 48014fff
- * TEST-TAP L4 48015000 - 48015fff
- * GPIO1 Mod 48018000 - 48018fff
- * GPIO Top 48019000 - 48019fff
- * GPIO2 Mod 4801a000 - 4801afff
- * GPIO L4 4801b000 - 4801bfff
- * GPIO3 Mod 4801c000 - 4801cfff
- * GPIO4 Mod 4801e000 - 4801efff
- * WDTIMER1 Mod 48020000 - 48010fff
- * WDTIMER Top 48021000 - 48011fff
- * WDTIMER2 Mod 48022000 - 48012fff
- * WDTIMER L4 48023000 - 48013fff
- * WDTIMER3 Mod 48024000 - 48014fff
- * WDTIMER3 L4 48025000 - 48015fff
- * WDTIMER4 Mod 48026000 - 48016fff
- * WDTIMER4 L4 48027000 - 48017fff
- * GPTIMER1 Mod 48028000 - 48018fff
- * GPTIMER1 L4 48029000 - 48019fff
- * GPTIMER2 Mod 4802a000 - 4801afff
- * GPTIMER2 L4 4802b000 - 4801bfff
- * L4-Config AP 48040000 - 480407ff
- * L4-Config IP 48040800 - 48040fff
- * L4-Config LA 48041000 - 48041fff
- * ARM11ETB Mod 48048000 - 48049fff
- * ARM11ETB L4 4804a000 - 4804afff
- * DISPLAY Top 48050000 - 480503ff
- * DISPLAY DISPC 48050400 - 480507ff
- * DISPLAY RFBI 48050800 - 48050bff
- * DISPLAY VENC 48050c00 - 48050fff
- * DISPLAY L4 48051000 - 48051fff
- * CAMERA Top 48052000 - 480523ff
- * CAMERA core 48052400 - 480527ff
- * CAMERA DMA 48052800 - 48052bff
- * CAMERA MMU 48052c00 - 48052fff
- * CAMERA L4 48053000 - 48053fff
- * SDMA Mod 48056000 - 48056fff
- * SDMA L4 48057000 - 48057fff
- * SSI Top 48058000 - 48058fff
- * SSI GDD 48059000 - 48059fff
- * SSI Port1 4805a000 - 4805afff
- * SSI Port2 4805b000 - 4805bfff
- * SSI L4 4805c000 - 4805cfff
- * USB Mod 4805e000 - 480fefff
- * USB L4 4805f000 - 480fffff
- * WIN_TRACER1 Mod 48060000 - 48060fff
- * WIN_TRACER1 L4 48061000 - 48061fff
- * WIN_TRACER2 Mod 48062000 - 48062fff
- * WIN_TRACER2 L4 48063000 - 48063fff
- * WIN_TRACER3 Mod 48064000 - 48064fff
- * WIN_TRACER3 L4 48065000 - 48065fff
- * WIN_TRACER4 Top 48066000 - 480660ff
- * WIN_TRACER4 ETT 48066100 - 480661ff
- * WIN_TRACER4 WT 48066200 - 480662ff
- * WIN_TRACER4 L4 48067000 - 48067fff
- * XTI Mod 48068000 - 48068fff
- * XTI L4 48069000 - 48069fff
- * UART1 Mod 4806a000 - 4806afff
- * UART1 L4 4806b000 - 4806bfff
- * UART2 Mod 4806c000 - 4806cfff
- * UART2 L4 4806d000 - 4806dfff
- * UART3 Mod 4806e000 - 4806efff
- * UART3 L4 4806f000 - 4806ffff
- * I2C1 Mod 48070000 - 48070fff
- * I2C1 L4 48071000 - 48071fff
- * I2C2 Mod 48072000 - 48072fff
- * I2C2 L4 48073000 - 48073fff
- * McBSP1 Mod 48074000 - 48074fff
- * McBSP1 L4 48075000 - 48075fff
- * McBSP2 Mod 48076000 - 48076fff
- * McBSP2 L4 48077000 - 48077fff
- * GPTIMER3 Mod 48078000 - 48078fff
- * GPTIMER3 L4 48079000 - 48079fff
- * GPTIMER4 Mod 4807a000 - 4807afff
- * GPTIMER4 L4 4807b000 - 4807bfff
- * GPTIMER5 Mod 4807c000 - 4807cfff
- * GPTIMER5 L4 4807d000 - 4807dfff
- * GPTIMER6 Mod 4807e000 - 4807efff
- * GPTIMER6 L4 4807f000 - 4807ffff
- * GPTIMER7 Mod 48080000 - 48080fff
- * GPTIMER7 L4 48081000 - 48081fff
- * GPTIMER8 Mod 48082000 - 48082fff
- * GPTIMER8 L4 48083000 - 48083fff
- * GPTIMER9 Mod 48084000 - 48084fff
- * GPTIMER9 L4 48085000 - 48085fff
- * GPTIMER10 Mod 48086000 - 48086fff
- * GPTIMER10 L4 48087000 - 48087fff
- * GPTIMER11 Mod 48088000 - 48088fff
- * GPTIMER11 L4 48089000 - 48089fff
- * GPTIMER12 Mod 4808a000 - 4808afff
- * GPTIMER12 L4 4808b000 - 4808bfff
- * EAC Mod 48090000 - 48090fff
- * EAC L4 48091000 - 48091fff
- * FAC Mod 48092000 - 48092fff
- * FAC L4 48093000 - 48093fff
- * MAILBOX Mod 48094000 - 48094fff
- * MAILBOX L4 48095000 - 48095fff
- * SPI1 Mod 48098000 - 48098fff
- * SPI1 L4 48099000 - 48099fff
- * SPI2 Mod 4809a000 - 4809afff
- * SPI2 L4 4809b000 - 4809bfff
- * MMC/SDIO Mod 4809c000 - 4809cfff
- * MMC/SDIO L4 4809d000 - 4809dfff
- * MS_PRO Mod 4809e000 - 4809efff
- * MS_PRO L4 4809f000 - 4809ffff
- * RNG Mod 480a0000 - 480a0fff
- * RNG L4 480a1000 - 480a1fff
- * DES3DES Mod 480a2000 - 480a2fff
- * DES3DES L4 480a3000 - 480a3fff
- * SHA1MD5 Mod 480a4000 - 480a4fff
- * SHA1MD5 L4 480a5000 - 480a5fff
- * AES Mod 480a6000 - 480a6fff
- * AES L4 480a7000 - 480a7fff
- * PKA Mod 480a8000 - 480a9fff
- * PKA L4 480aa000 - 480aafff
- * MG Mod 480b0000 - 480b0fff
- * MG L4 480b1000 - 480b1fff
- * HDQ/1-wire Mod 480b2000 - 480b2fff
- * HDQ/1-wire L4 480b3000 - 480b3fff
- * MPU interrupt 480fe000 - 480fefff
- * STI channel base 54000000 - 5400ffff
- * IVA RAM 5c000000 - 5c01ffff
- * IVA ROM 5c020000 - 5c027fff
- * IMG_BUF_A 5c040000 - 5c040fff
- * IMG_BUF_B 5c042000 - 5c042fff
- * VLCDS 5c048000 - 5c0487ff
- * IMX_COEF 5c049000 - 5c04afff
- * IMX_CMD 5c051000 - 5c051fff
- * VLCDQ 5c053000 - 5c0533ff
- * VLCDH 5c054000 - 5c054fff
- * SEQ_CMD 5c055000 - 5c055fff
- * IMX_REG 5c056000 - 5c0560ff
- * VLCD_REG 5c056100 - 5c0561ff
- * SEQ_REG 5c056200 - 5c0562ff
- * IMG_BUF_REG 5c056300 - 5c0563ff
- * SEQIRQ_REG 5c056400 - 5c0564ff
- * OCP_REG 5c060000 - 5c060fff
- * SYSC_REG 5c070000 - 5c070fff
- * MMU_REG 5d000000 - 5d000fff
- * sDMA R 68000400 - 680005ff
- * sDMA W 68000600 - 680007ff
- * Display Control 68000800 - 680009ff
- * DSP subsystem 68000a00 - 68000bff
- * MPU subsystem 68000c00 - 68000dff
- * IVA subsystem 68001000 - 680011ff
- * USB 68001200 - 680013ff
- * Camera 68001400 - 680015ff
- * VLYNQ (firewall) 68001800 - 68001bff
- * VLYNQ 68001e00 - 68001fff
- * SSI 68002000 - 680021ff
- * L4 68002400 - 680025ff
- * DSP (firewall) 68002800 - 68002bff
- * DSP subsystem 68002e00 - 68002fff
- * IVA (firewall) 68003000 - 680033ff
- * IVA 68003600 - 680037ff
- * GFX 68003a00 - 68003bff
- * CMDWR emulation 68003c00 - 68003dff
- * SMS 68004000 - 680041ff
- * OCM 68004200 - 680043ff
- * GPMC 68004400 - 680045ff
- * RAM (firewall) 68005000 - 680053ff
- * RAM (err login) 68005400 - 680057ff
- * ROM (firewall) 68005800 - 68005bff
- * ROM (err login) 68005c00 - 68005fff
- * GPMC (firewall) 68006000 - 680063ff
- * GPMC (err login) 68006400 - 680067ff
- * SMS (err login) 68006c00 - 68006fff
- * SMS registers 68008000 - 68008fff
- * SDRC registers 68009000 - 68009fff
- * GPMC registers 6800a000 6800afff
- */
-
- qemu_register_reset(omap2_mpu_reset, s);
-
- return s;
-}
diff --git a/qemu/hw/arm/omap_sx1.c b/qemu/hw/arm/omap_sx1.c
deleted file mode 100644
index 5d74026cb..000000000
--- a/qemu/hw/arm/omap_sx1.c
+++ /dev/null
@@ -1,256 +0,0 @@
-/* omap_sx1.c Support for the Siemens SX1 smartphone emulation.
- *
- * Copyright (C) 2008
- * Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
- * Copyright (C) 2007 Vladimir Ananiev <vovan888@gmail.com>
- *
- * based on PalmOne's (TM) PDAs support (palm.c)
- */
-
-/*
- * PalmOne's (TM) PDAs.
- *
- * Copyright (C) 2006-2007 Andrzej Zaborowski <balrog@zabor.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/hw.h"
-#include "ui/console.h"
-#include "hw/arm/omap.h"
-#include "hw/boards.h"
-#include "hw/arm/arm.h"
-#include "hw/block/flash.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/qtest.h"
-#include "exec/address-spaces.h"
-
-/*****************************************************************************/
-/* Siemens SX1 Cellphone V1 */
-/* - ARM OMAP310 processor
- * - SRAM 192 kB
- * - SDRAM 32 MB at 0x10000000
- * - Boot flash 16 MB at 0x00000000
- * - Application flash 8 MB at 0x04000000
- * - 3 serial ports
- * - 1 SecureDigital
- * - 1 LCD display
- * - 1 RTC
- */
-
-/*****************************************************************************/
-/* Siemens SX1 Cellphone V2 */
-/* - ARM OMAP310 processor
- * - SRAM 192 kB
- * - SDRAM 32 MB at 0x10000000
- * - Boot flash 32 MB at 0x00000000
- * - 3 serial ports
- * - 1 SecureDigital
- * - 1 LCD display
- * - 1 RTC
- */
-
-static uint64_t static_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- uint32_t *val = (uint32_t *) opaque;
- uint32_t mask = (4 / size) - 1;
-
- return *val >> ((offset & mask) << 3);
-}
-
-static void static_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
-#ifdef SPY
- printf("%s: value %" PRIx64 " %u bytes written at 0x%x\n",
- __func__, value, size, (int)offset);
-#endif
-}
-
-static const MemoryRegionOps static_ops = {
- .read = static_read,
- .write = static_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-#define sdram_size 0x02000000
-#define sector_size (128 * 1024)
-#define flash0_size (16 * 1024 * 1024)
-#define flash1_size ( 8 * 1024 * 1024)
-#define flash2_size (32 * 1024 * 1024)
-#define total_ram_v1 (sdram_size + flash0_size + flash1_size + OMAP15XX_SRAM_SIZE)
-#define total_ram_v2 (sdram_size + flash2_size + OMAP15XX_SRAM_SIZE)
-
-static struct arm_boot_info sx1_binfo = {
- .loader_start = OMAP_EMIFF_BASE,
- .ram_size = sdram_size,
- .board_id = 0x265,
-};
-
-static void sx1_init(MachineState *machine, const int version)
-{
- struct omap_mpu_state_s *mpu;
- MemoryRegion *address_space = get_system_memory();
- MemoryRegion *flash = g_new(MemoryRegion, 1);
- MemoryRegion *cs = g_new(MemoryRegion, 4);
- static uint32_t cs0val = 0x00213090;
- static uint32_t cs1val = 0x00215070;
- static uint32_t cs2val = 0x00001139;
- static uint32_t cs3val = 0x00001139;
- DriveInfo *dinfo;
- int fl_idx;
- uint32_t flash_size = flash0_size;
- int be;
-
- if (version == 2) {
- flash_size = flash2_size;
- }
-
- mpu = omap310_mpu_init(address_space, sx1_binfo.ram_size,
- machine->cpu_model);
-
- /* External Flash (EMIFS) */
- memory_region_init_ram(flash, NULL, "omap_sx1.flash0-0", flash_size,
- &error_fatal);
- vmstate_register_ram_global(flash);
- memory_region_set_readonly(flash, true);
- memory_region_add_subregion(address_space, OMAP_CS0_BASE, flash);
-
- memory_region_init_io(&cs[0], NULL, &static_ops, &cs0val,
- "sx1.cs0", OMAP_CS0_SIZE - flash_size);
- memory_region_add_subregion(address_space,
- OMAP_CS0_BASE + flash_size, &cs[0]);
-
-
- memory_region_init_io(&cs[2], NULL, &static_ops, &cs2val,
- "sx1.cs2", OMAP_CS2_SIZE);
- memory_region_add_subregion(address_space,
- OMAP_CS2_BASE, &cs[2]);
-
- memory_region_init_io(&cs[3], NULL, &static_ops, &cs3val,
- "sx1.cs3", OMAP_CS3_SIZE);
- memory_region_add_subregion(address_space,
- OMAP_CS2_BASE, &cs[3]);
-
- fl_idx = 0;
-#ifdef TARGET_WORDS_BIGENDIAN
- be = 1;
-#else
- be = 0;
-#endif
-
- if ((dinfo = drive_get(IF_PFLASH, 0, fl_idx)) != NULL) {
- if (!pflash_cfi01_register(OMAP_CS0_BASE, NULL,
- "omap_sx1.flash0-1", flash_size,
- blk_by_legacy_dinfo(dinfo),
- sector_size, flash_size / sector_size,
- 4, 0, 0, 0, 0, be)) {
- fprintf(stderr, "qemu: Error registering flash memory %d.\n",
- fl_idx);
- }
- fl_idx++;
- }
-
- if ((version == 1) &&
- (dinfo = drive_get(IF_PFLASH, 0, fl_idx)) != NULL) {
- MemoryRegion *flash_1 = g_new(MemoryRegion, 1);
- memory_region_init_ram(flash_1, NULL, "omap_sx1.flash1-0", flash1_size,
- &error_fatal);
- vmstate_register_ram_global(flash_1);
- memory_region_set_readonly(flash_1, true);
- memory_region_add_subregion(address_space, OMAP_CS1_BASE, flash_1);
-
- memory_region_init_io(&cs[1], NULL, &static_ops, &cs1val,
- "sx1.cs1", OMAP_CS1_SIZE - flash1_size);
- memory_region_add_subregion(address_space,
- OMAP_CS1_BASE + flash1_size, &cs[1]);
-
- if (!pflash_cfi01_register(OMAP_CS1_BASE, NULL,
- "omap_sx1.flash1-1", flash1_size,
- blk_by_legacy_dinfo(dinfo),
- sector_size, flash1_size / sector_size,
- 4, 0, 0, 0, 0, be)) {
- fprintf(stderr, "qemu: Error registering flash memory %d.\n",
- fl_idx);
- }
- fl_idx++;
- } else {
- memory_region_init_io(&cs[1], NULL, &static_ops, &cs1val,
- "sx1.cs1", OMAP_CS1_SIZE);
- memory_region_add_subregion(address_space,
- OMAP_CS1_BASE, &cs[1]);
- }
-
- if (!machine->kernel_filename && !fl_idx && !qtest_enabled()) {
- fprintf(stderr, "Kernel or Flash image must be specified\n");
- exit(1);
- }
-
- /* Load the kernel. */
- sx1_binfo.kernel_filename = machine->kernel_filename;
- sx1_binfo.kernel_cmdline = machine->kernel_cmdline;
- sx1_binfo.initrd_filename = machine->initrd_filename;
- arm_load_kernel(mpu->cpu, &sx1_binfo);
-
- /* TODO: fix next line */
- //~ qemu_console_resize(ds, 640, 480);
-}
-
-static void sx1_init_v1(MachineState *machine)
-{
- sx1_init(machine, 1);
-}
-
-static void sx1_init_v2(MachineState *machine)
-{
- sx1_init(machine, 2);
-}
-
-static void sx1_machine_v2_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "Siemens SX1 (OMAP310) V2";
- mc->init = sx1_init_v2;
-}
-
-static const TypeInfo sx1_machine_v2_type = {
- .name = MACHINE_TYPE_NAME("sx1"),
- .parent = TYPE_MACHINE,
- .class_init = sx1_machine_v2_class_init,
-};
-
-static void sx1_machine_v1_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "Siemens SX1 (OMAP310) V1";
- mc->init = sx1_init_v1;
-}
-
-static const TypeInfo sx1_machine_v1_type = {
- .name = MACHINE_TYPE_NAME("sx1-v1"),
- .parent = TYPE_MACHINE,
- .class_init = sx1_machine_v1_class_init,
-};
-
-static void sx1_machine_init(void)
-{
- type_register_static(&sx1_machine_v1_type);
- type_register_static(&sx1_machine_v2_type);
-}
-
-type_init(sx1_machine_init)
diff --git a/qemu/hw/arm/palm.c b/qemu/hw/arm/palm.c
deleted file mode 100644
index 7f460732e..000000000
--- a/qemu/hw/arm/palm.c
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * PalmOne's (TM) PDAs.
- *
- * Copyright (C) 2006-2007 Andrzej Zaborowski <balrog@zabor.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/hw.h"
-#include "audio/audio.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/qtest.h"
-#include "ui/console.h"
-#include "hw/arm/omap.h"
-#include "hw/boards.h"
-#include "hw/arm/arm.h"
-#include "hw/devices.h"
-#include "hw/loader.h"
-#include "exec/address-spaces.h"
-
-static uint32_t static_readb(void *opaque, hwaddr offset)
-{
- uint32_t *val = (uint32_t *) opaque;
- return *val >> ((offset & 3) << 3);
-}
-
-static uint32_t static_readh(void *opaque, hwaddr offset)
-{
- uint32_t *val = (uint32_t *) opaque;
- return *val >> ((offset & 1) << 3);
-}
-
-static uint32_t static_readw(void *opaque, hwaddr offset)
-{
- uint32_t *val = (uint32_t *) opaque;
- return *val >> ((offset & 0) << 3);
-}
-
-static void static_write(void *opaque, hwaddr offset,
- uint32_t value)
-{
-#ifdef SPY
- printf("%s: value %08lx written at " PA_FMT "\n",
- __FUNCTION__, value, offset);
-#endif
-}
-
-static const MemoryRegionOps static_ops = {
- .old_mmio = {
- .read = { static_readb, static_readh, static_readw, },
- .write = { static_write, static_write, static_write, },
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-/* Palm Tunsgten|E support */
-
-/* Shared GPIOs */
-#define PALMTE_USBDETECT_GPIO 0
-#define PALMTE_USB_OR_DC_GPIO 1
-#define PALMTE_TSC_GPIO 4
-#define PALMTE_PINTDAV_GPIO 6
-#define PALMTE_MMC_WP_GPIO 8
-#define PALMTE_MMC_POWER_GPIO 9
-#define PALMTE_HDQ_GPIO 11
-#define PALMTE_HEADPHONES_GPIO 14
-#define PALMTE_SPEAKER_GPIO 15
-/* MPU private GPIOs */
-#define PALMTE_DC_GPIO 2
-#define PALMTE_MMC_SWITCH_GPIO 4
-#define PALMTE_MMC1_GPIO 6
-#define PALMTE_MMC2_GPIO 7
-#define PALMTE_MMC3_GPIO 11
-
-static MouseTransformInfo palmte_pointercal = {
- .x = 320,
- .y = 320,
- .a = { -5909, 8, 22465308, 104, 7644, -1219972, 65536 },
-};
-
-static void palmte_microwire_setup(struct omap_mpu_state_s *cpu)
-{
- uWireSlave *tsc;
-
- tsc = tsc2102_init(qdev_get_gpio_in(cpu->gpio, PALMTE_PINTDAV_GPIO));
-
- omap_uwire_attach(cpu->microwire, tsc, 0);
- omap_mcbsp_i2s_attach(cpu->mcbsp1, tsc210x_codec(tsc));
-
- tsc210x_set_transform(tsc, &palmte_pointercal);
-}
-
-static struct {
- int row;
- int column;
-} palmte_keymap[0x80] = {
- [0 ... 0x7f] = { -1, -1 },
- [0x3b] = { 0, 0 }, /* F1 -> Calendar */
- [0x3c] = { 1, 0 }, /* F2 -> Contacts */
- [0x3d] = { 2, 0 }, /* F3 -> Tasks List */
- [0x3e] = { 3, 0 }, /* F4 -> Note Pad */
- [0x01] = { 4, 0 }, /* Esc -> Power */
- [0x4b] = { 0, 1 }, /* Left */
- [0x50] = { 1, 1 }, /* Down */
- [0x48] = { 2, 1 }, /* Up */
- [0x4d] = { 3, 1 }, /* Right */
- [0x4c] = { 4, 1 }, /* Centre */
- [0x39] = { 4, 1 }, /* Spc -> Centre */
-};
-
-static void palmte_button_event(void *opaque, int keycode)
-{
- struct omap_mpu_state_s *cpu = (struct omap_mpu_state_s *) opaque;
-
- if (palmte_keymap[keycode & 0x7f].row != -1)
- omap_mpuio_key(cpu->mpuio,
- palmte_keymap[keycode & 0x7f].row,
- palmte_keymap[keycode & 0x7f].column,
- !(keycode & 0x80));
-}
-
-static void palmte_onoff_gpios(void *opaque, int line, int level)
-{
- switch (line) {
- case 0:
- printf("%s: current to MMC/SD card %sabled.\n",
- __FUNCTION__, level ? "dis" : "en");
- break;
- case 1:
- printf("%s: internal speaker amplifier %s.\n",
- __FUNCTION__, level ? "down" : "on");
- break;
-
- /* These LCD & Audio output signals have not been identified yet. */
- case 2:
- case 3:
- case 4:
- printf("%s: LCD GPIO%i %s.\n",
- __FUNCTION__, line - 1, level ? "high" : "low");
- break;
- case 5:
- case 6:
- printf("%s: Audio GPIO%i %s.\n",
- __FUNCTION__, line - 4, level ? "high" : "low");
- break;
- }
-}
-
-static void palmte_gpio_setup(struct omap_mpu_state_s *cpu)
-{
- qemu_irq *misc_gpio;
-
- omap_mmc_handlers(cpu->mmc,
- qdev_get_gpio_in(cpu->gpio, PALMTE_MMC_WP_GPIO),
- qemu_irq_invert(omap_mpuio_in_get(cpu->mpuio)
- [PALMTE_MMC_SWITCH_GPIO]));
-
- misc_gpio = qemu_allocate_irqs(palmte_onoff_gpios, cpu, 7);
- qdev_connect_gpio_out(cpu->gpio, PALMTE_MMC_POWER_GPIO, misc_gpio[0]);
- qdev_connect_gpio_out(cpu->gpio, PALMTE_SPEAKER_GPIO, misc_gpio[1]);
- qdev_connect_gpio_out(cpu->gpio, 11, misc_gpio[2]);
- qdev_connect_gpio_out(cpu->gpio, 12, misc_gpio[3]);
- qdev_connect_gpio_out(cpu->gpio, 13, misc_gpio[4]);
- omap_mpuio_out_set(cpu->mpuio, 1, misc_gpio[5]);
- omap_mpuio_out_set(cpu->mpuio, 3, misc_gpio[6]);
-
- /* Reset some inputs to initial state. */
- qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_USBDETECT_GPIO));
- qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_USB_OR_DC_GPIO));
- qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, 4));
- qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_HEADPHONES_GPIO));
- qemu_irq_lower(omap_mpuio_in_get(cpu->mpuio)[PALMTE_DC_GPIO]);
- qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[6]);
- qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[7]);
- qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[11]);
-}
-
-static struct arm_boot_info palmte_binfo = {
- .loader_start = OMAP_EMIFF_BASE,
- .ram_size = 0x02000000,
- .board_id = 0x331,
-};
-
-static void palmte_init(MachineState *machine)
-{
- const char *cpu_model = machine->cpu_model;
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- const char *initrd_filename = machine->initrd_filename;
- MemoryRegion *address_space_mem = get_system_memory();
- struct omap_mpu_state_s *mpu;
- int flash_size = 0x00800000;
- int sdram_size = palmte_binfo.ram_size;
- static uint32_t cs0val = 0xffffffff;
- static uint32_t cs1val = 0x0000e1a0;
- static uint32_t cs2val = 0x0000e1a0;
- static uint32_t cs3val = 0xe1a0e1a0;
- int rom_size, rom_loaded = 0;
- MemoryRegion *flash = g_new(MemoryRegion, 1);
- MemoryRegion *cs = g_new(MemoryRegion, 4);
-
- mpu = omap310_mpu_init(address_space_mem, sdram_size, cpu_model);
-
- /* External Flash (EMIFS) */
- memory_region_init_ram(flash, NULL, "palmte.flash", flash_size,
- &error_fatal);
- vmstate_register_ram_global(flash);
- memory_region_set_readonly(flash, true);
- memory_region_add_subregion(address_space_mem, OMAP_CS0_BASE, flash);
-
- memory_region_init_io(&cs[0], NULL, &static_ops, &cs0val, "palmte-cs0",
- OMAP_CS0_SIZE - flash_size);
- memory_region_add_subregion(address_space_mem, OMAP_CS0_BASE + flash_size,
- &cs[0]);
- memory_region_init_io(&cs[1], NULL, &static_ops, &cs1val, "palmte-cs1",
- OMAP_CS1_SIZE);
- memory_region_add_subregion(address_space_mem, OMAP_CS1_BASE, &cs[1]);
- memory_region_init_io(&cs[2], NULL, &static_ops, &cs2val, "palmte-cs2",
- OMAP_CS2_SIZE);
- memory_region_add_subregion(address_space_mem, OMAP_CS2_BASE, &cs[2]);
- memory_region_init_io(&cs[3], NULL, &static_ops, &cs3val, "palmte-cs3",
- OMAP_CS3_SIZE);
- memory_region_add_subregion(address_space_mem, OMAP_CS3_BASE, &cs[3]);
-
- palmte_microwire_setup(mpu);
-
- qemu_add_kbd_event_handler(palmte_button_event, mpu);
-
- palmte_gpio_setup(mpu);
-
- /* Setup initial (reset) machine state */
- if (nb_option_roms) {
- rom_size = get_image_size(option_rom[0].name);
- if (rom_size > flash_size) {
- fprintf(stderr, "%s: ROM image too big (%x > %x)\n",
- __FUNCTION__, rom_size, flash_size);
- rom_size = 0;
- }
- if (rom_size > 0) {
- rom_size = load_image_targphys(option_rom[0].name, OMAP_CS0_BASE,
- flash_size);
- rom_loaded = 1;
- }
- if (rom_size < 0) {
- fprintf(stderr, "%s: error loading '%s'\n",
- __FUNCTION__, option_rom[0].name);
- }
- }
-
- if (!rom_loaded && !kernel_filename && !qtest_enabled()) {
- fprintf(stderr, "Kernel or ROM image must be specified\n");
- exit(1);
- }
-
- /* Load the kernel. */
- palmte_binfo.kernel_filename = kernel_filename;
- palmte_binfo.kernel_cmdline = kernel_cmdline;
- palmte_binfo.initrd_filename = initrd_filename;
- arm_load_kernel(mpu->cpu, &palmte_binfo);
-}
-
-static void palmte_machine_init(MachineClass *mc)
-{
- mc->desc = "Palm Tungsten|E aka. Cheetah PDA (OMAP310)";
- mc->init = palmte_init;
-}
-
-DEFINE_MACHINE("cheetah", palmte_machine_init)
diff --git a/qemu/hw/arm/palmetto-bmc.c b/qemu/hw/arm/palmetto-bmc.c
deleted file mode 100644
index 89ebd92b9..000000000
--- a/qemu/hw/arm/palmetto-bmc.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * OpenPOWER Palmetto BMC
- *
- * Andrew Jeffery <andrew@aj.id.au>
- *
- * Copyright 2016 IBM Corp.
- *
- * This code is licensed under the GPL version 2 or later. See
- * the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "exec/address-spaces.h"
-#include "hw/arm/arm.h"
-#include "hw/arm/ast2400.h"
-#include "hw/boards.h"
-
-static struct arm_boot_info palmetto_bmc_binfo = {
- .loader_start = AST2400_SDRAM_BASE,
- .board_id = 0,
- .nb_cpus = 1,
-};
-
-typedef struct PalmettoBMCState {
- AST2400State soc;
- MemoryRegion ram;
-} PalmettoBMCState;
-
-static void palmetto_bmc_init(MachineState *machine)
-{
- PalmettoBMCState *bmc;
-
- bmc = g_new0(PalmettoBMCState, 1);
- object_initialize(&bmc->soc, (sizeof(bmc->soc)), TYPE_AST2400);
- object_property_add_child(OBJECT(machine), "soc", OBJECT(&bmc->soc),
- &error_abort);
-
- memory_region_allocate_system_memory(&bmc->ram, NULL, "ram", ram_size);
- memory_region_add_subregion(get_system_memory(), AST2400_SDRAM_BASE,
- &bmc->ram);
- object_property_add_const_link(OBJECT(&bmc->soc), "ram", OBJECT(&bmc->ram),
- &error_abort);
- object_property_set_bool(OBJECT(&bmc->soc), true, "realized",
- &error_abort);
-
- palmetto_bmc_binfo.kernel_filename = machine->kernel_filename;
- palmetto_bmc_binfo.initrd_filename = machine->initrd_filename;
- palmetto_bmc_binfo.kernel_cmdline = machine->kernel_cmdline;
- palmetto_bmc_binfo.ram_size = ram_size;
- arm_load_kernel(ARM_CPU(first_cpu), &palmetto_bmc_binfo);
-}
-
-static void palmetto_bmc_machine_init(MachineClass *mc)
-{
- mc->desc = "OpenPOWER Palmetto BMC";
- mc->init = palmetto_bmc_init;
- mc->max_cpus = 1;
- mc->no_sdcard = 1;
- mc->no_floppy = 1;
- mc->no_cdrom = 1;
- mc->no_sdcard = 1;
- mc->no_parallel = 1;
-}
-
-DEFINE_MACHINE("palmetto-bmc", palmetto_bmc_machine_init);
diff --git a/qemu/hw/arm/pxa2xx.c b/qemu/hw/arm/pxa2xx.c
deleted file mode 100644
index 1a8c36033..000000000
--- a/qemu/hw/arm/pxa2xx.c
+++ /dev/null
@@ -1,2358 +0,0 @@
-/*
- * Intel XScale PXA255/270 processor support.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GPL.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/sysbus.h"
-#include "hw/arm/pxa.h"
-#include "sysemu/sysemu.h"
-#include "hw/char/serial.h"
-#include "hw/i2c/i2c.h"
-#include "hw/ssi/ssi.h"
-#include "sysemu/char.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
-#include "qemu/cutils.h"
-
-static struct {
- hwaddr io_base;
- int irqn;
-} pxa255_serial[] = {
- { 0x40100000, PXA2XX_PIC_FFUART },
- { 0x40200000, PXA2XX_PIC_BTUART },
- { 0x40700000, PXA2XX_PIC_STUART },
- { 0x41600000, PXA25X_PIC_HWUART },
- { 0, 0 }
-}, pxa270_serial[] = {
- { 0x40100000, PXA2XX_PIC_FFUART },
- { 0x40200000, PXA2XX_PIC_BTUART },
- { 0x40700000, PXA2XX_PIC_STUART },
- { 0, 0 }
-};
-
-typedef struct PXASSPDef {
- hwaddr io_base;
- int irqn;
-} PXASSPDef;
-
-#if 0
-static PXASSPDef pxa250_ssp[] = {
- { 0x41000000, PXA2XX_PIC_SSP },
- { 0, 0 }
-};
-#endif
-
-static PXASSPDef pxa255_ssp[] = {
- { 0x41000000, PXA2XX_PIC_SSP },
- { 0x41400000, PXA25X_PIC_NSSP },
- { 0, 0 }
-};
-
-#if 0
-static PXASSPDef pxa26x_ssp[] = {
- { 0x41000000, PXA2XX_PIC_SSP },
- { 0x41400000, PXA25X_PIC_NSSP },
- { 0x41500000, PXA26X_PIC_ASSP },
- { 0, 0 }
-};
-#endif
-
-static PXASSPDef pxa27x_ssp[] = {
- { 0x41000000, PXA2XX_PIC_SSP },
- { 0x41700000, PXA27X_PIC_SSP2 },
- { 0x41900000, PXA2XX_PIC_SSP3 },
- { 0, 0 }
-};
-
-#define PMCR 0x00 /* Power Manager Control register */
-#define PSSR 0x04 /* Power Manager Sleep Status register */
-#define PSPR 0x08 /* Power Manager Scratch-Pad register */
-#define PWER 0x0c /* Power Manager Wake-Up Enable register */
-#define PRER 0x10 /* Power Manager Rising-Edge Detect Enable register */
-#define PFER 0x14 /* Power Manager Falling-Edge Detect Enable register */
-#define PEDR 0x18 /* Power Manager Edge-Detect Status register */
-#define PCFR 0x1c /* Power Manager General Configuration register */
-#define PGSR0 0x20 /* Power Manager GPIO Sleep-State register 0 */
-#define PGSR1 0x24 /* Power Manager GPIO Sleep-State register 1 */
-#define PGSR2 0x28 /* Power Manager GPIO Sleep-State register 2 */
-#define PGSR3 0x2c /* Power Manager GPIO Sleep-State register 3 */
-#define RCSR 0x30 /* Reset Controller Status register */
-#define PSLR 0x34 /* Power Manager Sleep Configuration register */
-#define PTSR 0x38 /* Power Manager Standby Configuration register */
-#define PVCR 0x40 /* Power Manager Voltage Change Control register */
-#define PUCR 0x4c /* Power Manager USIM Card Control/Status register */
-#define PKWR 0x50 /* Power Manager Keyboard Wake-Up Enable register */
-#define PKSR 0x54 /* Power Manager Keyboard Level-Detect Status */
-#define PCMD0 0x80 /* Power Manager I2C Command register File 0 */
-#define PCMD31 0xfc /* Power Manager I2C Command register File 31 */
-
-static uint64_t pxa2xx_pm_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- PXA2xxState *s = (PXA2xxState *) opaque;
-
- switch (addr) {
- case PMCR ... PCMD31:
- if (addr & 3)
- goto fail;
-
- return s->pm_regs[addr >> 2];
- default:
- fail:
- printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
- break;
- }
- return 0;
-}
-
-static void pxa2xx_pm_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- PXA2xxState *s = (PXA2xxState *) opaque;
-
- switch (addr) {
- case PMCR:
- /* Clear the write-one-to-clear bits... */
- s->pm_regs[addr >> 2] &= ~(value & 0x2a);
- /* ...and set the plain r/w bits */
- s->pm_regs[addr >> 2] &= ~0x15;
- s->pm_regs[addr >> 2] |= value & 0x15;
- break;
-
- case PSSR: /* Read-clean registers */
- case RCSR:
- case PKSR:
- s->pm_regs[addr >> 2] &= ~value;
- break;
-
- default: /* Read-write registers */
- if (!(addr & 3)) {
- s->pm_regs[addr >> 2] = value;
- break;
- }
-
- printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
- break;
- }
-}
-
-static const MemoryRegionOps pxa2xx_pm_ops = {
- .read = pxa2xx_pm_read,
- .write = pxa2xx_pm_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_pxa2xx_pm = {
- .name = "pxa2xx_pm",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(pm_regs, PXA2xxState, 0x40),
- VMSTATE_END_OF_LIST()
- }
-};
-
-#define CCCR 0x00 /* Core Clock Configuration register */
-#define CKEN 0x04 /* Clock Enable register */
-#define OSCC 0x08 /* Oscillator Configuration register */
-#define CCSR 0x0c /* Core Clock Status register */
-
-static uint64_t pxa2xx_cm_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- PXA2xxState *s = (PXA2xxState *) opaque;
-
- switch (addr) {
- case CCCR:
- case CKEN:
- case OSCC:
- return s->cm_regs[addr >> 2];
-
- case CCSR:
- return s->cm_regs[CCCR >> 2] | (3 << 28);
-
- default:
- printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
- break;
- }
- return 0;
-}
-
-static void pxa2xx_cm_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- PXA2xxState *s = (PXA2xxState *) opaque;
-
- switch (addr) {
- case CCCR:
- case CKEN:
- s->cm_regs[addr >> 2] = value;
- break;
-
- case OSCC:
- s->cm_regs[addr >> 2] &= ~0x6c;
- s->cm_regs[addr >> 2] |= value & 0x6e;
- if ((value >> 1) & 1) /* OON */
- s->cm_regs[addr >> 2] |= 1 << 0; /* Oscillator is now stable */
- break;
-
- default:
- printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
- break;
- }
-}
-
-static const MemoryRegionOps pxa2xx_cm_ops = {
- .read = pxa2xx_cm_read,
- .write = pxa2xx_cm_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_pxa2xx_cm = {
- .name = "pxa2xx_cm",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(cm_regs, PXA2xxState, 4),
- VMSTATE_UINT32(clkcfg, PXA2xxState),
- VMSTATE_UINT32(pmnc, PXA2xxState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static uint64_t pxa2xx_clkcfg_read(CPUARMState *env, const ARMCPRegInfo *ri)
-{
- PXA2xxState *s = (PXA2xxState *)ri->opaque;
- return s->clkcfg;
-}
-
-static void pxa2xx_clkcfg_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- PXA2xxState *s = (PXA2xxState *)ri->opaque;
- s->clkcfg = value & 0xf;
- if (value & 2) {
- printf("%s: CPU frequency change attempt\n", __func__);
- }
-}
-
-static void pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- PXA2xxState *s = (PXA2xxState *)ri->opaque;
- static const char *pwrmode[8] = {
- "Normal", "Idle", "Deep-idle", "Standby",
- "Sleep", "reserved (!)", "reserved (!)", "Deep-sleep",
- };
-
- if (value & 8) {
- printf("%s: CPU voltage change attempt\n", __func__);
- }
- switch (value & 7) {
- case 0:
- /* Do nothing */
- break;
-
- case 1:
- /* Idle */
- if (!(s->cm_regs[CCCR >> 2] & (1U << 31))) { /* CPDIS */
- cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_HALT);
- break;
- }
- /* Fall through. */
-
- case 2:
- /* Deep-Idle */
- cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_HALT);
- s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */
- goto message;
-
- case 3:
- s->cpu->env.uncached_cpsr = ARM_CPU_MODE_SVC;
- s->cpu->env.daif = PSTATE_A | PSTATE_F | PSTATE_I;
- s->cpu->env.cp15.sctlr_ns = 0;
- s->cpu->env.cp15.cpacr_el1 = 0;
- s->cpu->env.cp15.ttbr0_el[1] = 0;
- s->cpu->env.cp15.dacr_ns = 0;
- s->pm_regs[PSSR >> 2] |= 0x8; /* Set STS */
- s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */
-
- /*
- * The scratch-pad register is almost universally used
- * for storing the return address on suspend. For the
- * lack of a resuming bootloader, perform a jump
- * directly to that address.
- */
- memset(s->cpu->env.regs, 0, 4 * 15);
- s->cpu->env.regs[15] = s->pm_regs[PSPR >> 2];
-
-#if 0
- buffer = 0xe59ff000; /* ldr pc, [pc, #0] */
- cpu_physical_memory_write(0, &buffer, 4);
- buffer = s->pm_regs[PSPR >> 2];
- cpu_physical_memory_write(8, &buffer, 4);
-#endif
-
- /* Suspend */
- cpu_interrupt(current_cpu, CPU_INTERRUPT_HALT);
-
- goto message;
-
- default:
- message:
- printf("%s: machine entered %s mode\n", __func__,
- pwrmode[value & 7]);
- }
-}
-
-static uint64_t pxa2xx_cppmnc_read(CPUARMState *env, const ARMCPRegInfo *ri)
-{
- PXA2xxState *s = (PXA2xxState *)ri->opaque;
- return s->pmnc;
-}
-
-static void pxa2xx_cppmnc_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- PXA2xxState *s = (PXA2xxState *)ri->opaque;
- s->pmnc = value;
-}
-
-static uint64_t pxa2xx_cpccnt_read(CPUARMState *env, const ARMCPRegInfo *ri)
-{
- PXA2xxState *s = (PXA2xxState *)ri->opaque;
- if (s->pmnc & 1) {
- return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- } else {
- return 0;
- }
-}
-
-static const ARMCPRegInfo pxa_cp_reginfo[] = {
- /* cp14 crm==1: perf registers */
- { .name = "CPPMNC", .cp = 14, .crn = 0, .crm = 1, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .type = ARM_CP_IO,
- .readfn = pxa2xx_cppmnc_read, .writefn = pxa2xx_cppmnc_write },
- { .name = "CPCCNT", .cp = 14, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .type = ARM_CP_IO,
- .readfn = pxa2xx_cpccnt_read, .writefn = arm_cp_write_ignore },
- { .name = "CPINTEN", .cp = 14, .crn = 4, .crm = 1, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
- { .name = "CPFLAG", .cp = 14, .crn = 5, .crm = 1, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
- { .name = "CPEVTSEL", .cp = 14, .crn = 8, .crm = 1, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
- /* cp14 crm==2: performance count registers */
- { .name = "CPPMN0", .cp = 14, .crn = 0, .crm = 2, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
- { .name = "CPPMN1", .cp = 14, .crn = 1, .crm = 2, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
- { .name = "CPPMN2", .cp = 14, .crn = 2, .crm = 2, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
- { .name = "CPPMN3", .cp = 14, .crn = 2, .crm = 3, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
- /* cp14 crn==6: CLKCFG */
- { .name = "CLKCFG", .cp = 14, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .type = ARM_CP_IO,
- .readfn = pxa2xx_clkcfg_read, .writefn = pxa2xx_clkcfg_write },
- /* cp14 crn==7: PWRMODE */
- { .name = "PWRMODE", .cp = 14, .crn = 7, .crm = 0, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .type = ARM_CP_IO,
- .readfn = arm_cp_read_zero, .writefn = pxa2xx_pwrmode_write },
- REGINFO_SENTINEL
-};
-
-static void pxa2xx_setup_cp14(PXA2xxState *s)
-{
- define_arm_cp_regs_with_opaque(s->cpu, pxa_cp_reginfo, s);
-}
-
-#define MDCNFG 0x00 /* SDRAM Configuration register */
-#define MDREFR 0x04 /* SDRAM Refresh Control register */
-#define MSC0 0x08 /* Static Memory Control register 0 */
-#define MSC1 0x0c /* Static Memory Control register 1 */
-#define MSC2 0x10 /* Static Memory Control register 2 */
-#define MECR 0x14 /* Expansion Memory Bus Config register */
-#define SXCNFG 0x1c /* Synchronous Static Memory Config register */
-#define MCMEM0 0x28 /* PC Card Memory Socket 0 Timing register */
-#define MCMEM1 0x2c /* PC Card Memory Socket 1 Timing register */
-#define MCATT0 0x30 /* PC Card Attribute Socket 0 register */
-#define MCATT1 0x34 /* PC Card Attribute Socket 1 register */
-#define MCIO0 0x38 /* PC Card I/O Socket 0 Timing register */
-#define MCIO1 0x3c /* PC Card I/O Socket 1 Timing register */
-#define MDMRS 0x40 /* SDRAM Mode Register Set Config register */
-#define BOOT_DEF 0x44 /* Boot-time Default Configuration register */
-#define ARB_CNTL 0x48 /* Arbiter Control register */
-#define BSCNTR0 0x4c /* Memory Buffer Strength Control register 0 */
-#define BSCNTR1 0x50 /* Memory Buffer Strength Control register 1 */
-#define LCDBSCNTR 0x54 /* LCD Buffer Strength Control register */
-#define MDMRSLP 0x58 /* Low Power SDRAM Mode Set Config register */
-#define BSCNTR2 0x5c /* Memory Buffer Strength Control register 2 */
-#define BSCNTR3 0x60 /* Memory Buffer Strength Control register 3 */
-#define SA1110 0x64 /* SA-1110 Memory Compatibility register */
-
-static uint64_t pxa2xx_mm_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- PXA2xxState *s = (PXA2xxState *) opaque;
-
- switch (addr) {
- case MDCNFG ... SA1110:
- if ((addr & 3) == 0)
- return s->mm_regs[addr >> 2];
-
- default:
- printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
- break;
- }
- return 0;
-}
-
-static void pxa2xx_mm_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- PXA2xxState *s = (PXA2xxState *) opaque;
-
- switch (addr) {
- case MDCNFG ... SA1110:
- if ((addr & 3) == 0) {
- s->mm_regs[addr >> 2] = value;
- break;
- }
-
- default:
- printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
- break;
- }
-}
-
-static const MemoryRegionOps pxa2xx_mm_ops = {
- .read = pxa2xx_mm_read,
- .write = pxa2xx_mm_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_pxa2xx_mm = {
- .name = "pxa2xx_mm",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(mm_regs, PXA2xxState, 0x1a),
- VMSTATE_END_OF_LIST()
- }
-};
-
-#define TYPE_PXA2XX_SSP "pxa2xx-ssp"
-#define PXA2XX_SSP(obj) \
- OBJECT_CHECK(PXA2xxSSPState, (obj), TYPE_PXA2XX_SSP)
-
-/* Synchronous Serial Ports */
-typedef struct {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- MemoryRegion iomem;
- qemu_irq irq;
- uint32_t enable;
- SSIBus *bus;
-
- uint32_t sscr[2];
- uint32_t sspsp;
- uint32_t ssto;
- uint32_t ssitr;
- uint32_t sssr;
- uint8_t sstsa;
- uint8_t ssrsa;
- uint8_t ssacd;
-
- uint32_t rx_fifo[16];
- uint32_t rx_level;
- uint32_t rx_start;
-} PXA2xxSSPState;
-
-static bool pxa2xx_ssp_vmstate_validate(void *opaque, int version_id)
-{
- PXA2xxSSPState *s = opaque;
-
- return s->rx_start < sizeof(s->rx_fifo);
-}
-
-static const VMStateDescription vmstate_pxa2xx_ssp = {
- .name = "pxa2xx-ssp",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(enable, PXA2xxSSPState),
- VMSTATE_UINT32_ARRAY(sscr, PXA2xxSSPState, 2),
- VMSTATE_UINT32(sspsp, PXA2xxSSPState),
- VMSTATE_UINT32(ssto, PXA2xxSSPState),
- VMSTATE_UINT32(ssitr, PXA2xxSSPState),
- VMSTATE_UINT32(sssr, PXA2xxSSPState),
- VMSTATE_UINT8(sstsa, PXA2xxSSPState),
- VMSTATE_UINT8(ssrsa, PXA2xxSSPState),
- VMSTATE_UINT8(ssacd, PXA2xxSSPState),
- VMSTATE_UINT32(rx_level, PXA2xxSSPState),
- VMSTATE_UINT32(rx_start, PXA2xxSSPState),
- VMSTATE_VALIDATE("fifo is 16 bytes", pxa2xx_ssp_vmstate_validate),
- VMSTATE_UINT32_ARRAY(rx_fifo, PXA2xxSSPState, 16),
- VMSTATE_END_OF_LIST()
- }
-};
-
-#define SSCR0 0x00 /* SSP Control register 0 */
-#define SSCR1 0x04 /* SSP Control register 1 */
-#define SSSR 0x08 /* SSP Status register */
-#define SSITR 0x0c /* SSP Interrupt Test register */
-#define SSDR 0x10 /* SSP Data register */
-#define SSTO 0x28 /* SSP Time-Out register */
-#define SSPSP 0x2c /* SSP Programmable Serial Protocol register */
-#define SSTSA 0x30 /* SSP TX Time Slot Active register */
-#define SSRSA 0x34 /* SSP RX Time Slot Active register */
-#define SSTSS 0x38 /* SSP Time Slot Status register */
-#define SSACD 0x3c /* SSP Audio Clock Divider register */
-
-/* Bitfields for above registers */
-#define SSCR0_SPI(x) (((x) & 0x30) == 0x00)
-#define SSCR0_SSP(x) (((x) & 0x30) == 0x10)
-#define SSCR0_UWIRE(x) (((x) & 0x30) == 0x20)
-#define SSCR0_PSP(x) (((x) & 0x30) == 0x30)
-#define SSCR0_SSE (1 << 7)
-#define SSCR0_RIM (1 << 22)
-#define SSCR0_TIM (1 << 23)
-#define SSCR0_MOD (1U << 31)
-#define SSCR0_DSS(x) (((((x) >> 16) & 0x10) | ((x) & 0xf)) + 1)
-#define SSCR1_RIE (1 << 0)
-#define SSCR1_TIE (1 << 1)
-#define SSCR1_LBM (1 << 2)
-#define SSCR1_MWDS (1 << 5)
-#define SSCR1_TFT(x) ((((x) >> 6) & 0xf) + 1)
-#define SSCR1_RFT(x) ((((x) >> 10) & 0xf) + 1)
-#define SSCR1_EFWR (1 << 14)
-#define SSCR1_PINTE (1 << 18)
-#define SSCR1_TINTE (1 << 19)
-#define SSCR1_RSRE (1 << 20)
-#define SSCR1_TSRE (1 << 21)
-#define SSCR1_EBCEI (1 << 29)
-#define SSITR_INT (7 << 5)
-#define SSSR_TNF (1 << 2)
-#define SSSR_RNE (1 << 3)
-#define SSSR_TFS (1 << 5)
-#define SSSR_RFS (1 << 6)
-#define SSSR_ROR (1 << 7)
-#define SSSR_PINT (1 << 18)
-#define SSSR_TINT (1 << 19)
-#define SSSR_EOC (1 << 20)
-#define SSSR_TUR (1 << 21)
-#define SSSR_BCE (1 << 23)
-#define SSSR_RW 0x00bc0080
-
-static void pxa2xx_ssp_int_update(PXA2xxSSPState *s)
-{
- int level = 0;
-
- level |= s->ssitr & SSITR_INT;
- level |= (s->sssr & SSSR_BCE) && (s->sscr[1] & SSCR1_EBCEI);
- level |= (s->sssr & SSSR_TUR) && !(s->sscr[0] & SSCR0_TIM);
- level |= (s->sssr & SSSR_EOC) && (s->sssr & (SSSR_TINT | SSSR_PINT));
- level |= (s->sssr & SSSR_TINT) && (s->sscr[1] & SSCR1_TINTE);
- level |= (s->sssr & SSSR_PINT) && (s->sscr[1] & SSCR1_PINTE);
- level |= (s->sssr & SSSR_ROR) && !(s->sscr[0] & SSCR0_RIM);
- level |= (s->sssr & SSSR_RFS) && (s->sscr[1] & SSCR1_RIE);
- level |= (s->sssr & SSSR_TFS) && (s->sscr[1] & SSCR1_TIE);
- qemu_set_irq(s->irq, !!level);
-}
-
-static void pxa2xx_ssp_fifo_update(PXA2xxSSPState *s)
-{
- s->sssr &= ~(0xf << 12); /* Clear RFL */
- s->sssr &= ~(0xf << 8); /* Clear TFL */
- s->sssr &= ~SSSR_TFS;
- s->sssr &= ~SSSR_TNF;
- if (s->enable) {
- s->sssr |= ((s->rx_level - 1) & 0xf) << 12;
- if (s->rx_level >= SSCR1_RFT(s->sscr[1]))
- s->sssr |= SSSR_RFS;
- else
- s->sssr &= ~SSSR_RFS;
- if (s->rx_level)
- s->sssr |= SSSR_RNE;
- else
- s->sssr &= ~SSSR_RNE;
- /* TX FIFO is never filled, so it is always in underrun
- condition if SSP is enabled */
- s->sssr |= SSSR_TFS;
- s->sssr |= SSSR_TNF;
- }
-
- pxa2xx_ssp_int_update(s);
-}
-
-static uint64_t pxa2xx_ssp_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- PXA2xxSSPState *s = (PXA2xxSSPState *) opaque;
- uint32_t retval;
-
- switch (addr) {
- case SSCR0:
- return s->sscr[0];
- case SSCR1:
- return s->sscr[1];
- case SSPSP:
- return s->sspsp;
- case SSTO:
- return s->ssto;
- case SSITR:
- return s->ssitr;
- case SSSR:
- return s->sssr | s->ssitr;
- case SSDR:
- if (!s->enable)
- return 0xffffffff;
- if (s->rx_level < 1) {
- printf("%s: SSP Rx Underrun\n", __FUNCTION__);
- return 0xffffffff;
- }
- s->rx_level --;
- retval = s->rx_fifo[s->rx_start ++];
- s->rx_start &= 0xf;
- pxa2xx_ssp_fifo_update(s);
- return retval;
- case SSTSA:
- return s->sstsa;
- case SSRSA:
- return s->ssrsa;
- case SSTSS:
- return 0;
- case SSACD:
- return s->ssacd;
- default:
- printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
- break;
- }
- return 0;
-}
-
-static void pxa2xx_ssp_write(void *opaque, hwaddr addr,
- uint64_t value64, unsigned size)
-{
- PXA2xxSSPState *s = (PXA2xxSSPState *) opaque;
- uint32_t value = value64;
-
- switch (addr) {
- case SSCR0:
- s->sscr[0] = value & 0xc7ffffff;
- s->enable = value & SSCR0_SSE;
- if (value & SSCR0_MOD)
- printf("%s: Attempt to use network mode\n", __FUNCTION__);
- if (s->enable && SSCR0_DSS(value) < 4)
- printf("%s: Wrong data size: %i bits\n", __FUNCTION__,
- SSCR0_DSS(value));
- if (!(value & SSCR0_SSE)) {
- s->sssr = 0;
- s->ssitr = 0;
- s->rx_level = 0;
- }
- pxa2xx_ssp_fifo_update(s);
- break;
-
- case SSCR1:
- s->sscr[1] = value;
- if (value & (SSCR1_LBM | SSCR1_EFWR))
- printf("%s: Attempt to use SSP test mode\n", __FUNCTION__);
- pxa2xx_ssp_fifo_update(s);
- break;
-
- case SSPSP:
- s->sspsp = value;
- break;
-
- case SSTO:
- s->ssto = value;
- break;
-
- case SSITR:
- s->ssitr = value & SSITR_INT;
- pxa2xx_ssp_int_update(s);
- break;
-
- case SSSR:
- s->sssr &= ~(value & SSSR_RW);
- pxa2xx_ssp_int_update(s);
- break;
-
- case SSDR:
- if (SSCR0_UWIRE(s->sscr[0])) {
- if (s->sscr[1] & SSCR1_MWDS)
- value &= 0xffff;
- else
- value &= 0xff;
- } else
- /* Note how 32bits overflow does no harm here */
- value &= (1 << SSCR0_DSS(s->sscr[0])) - 1;
-
- /* Data goes from here to the Tx FIFO and is shifted out from
- * there directly to the slave, no need to buffer it.
- */
- if (s->enable) {
- uint32_t readval;
- readval = ssi_transfer(s->bus, value);
- if (s->rx_level < 0x10) {
- s->rx_fifo[(s->rx_start + s->rx_level ++) & 0xf] = readval;
- } else {
- s->sssr |= SSSR_ROR;
- }
- }
- pxa2xx_ssp_fifo_update(s);
- break;
-
- case SSTSA:
- s->sstsa = value;
- break;
-
- case SSRSA:
- s->ssrsa = value;
- break;
-
- case SSACD:
- s->ssacd = value;
- break;
-
- default:
- printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
- break;
- }
-}
-
-static const MemoryRegionOps pxa2xx_ssp_ops = {
- .read = pxa2xx_ssp_read,
- .write = pxa2xx_ssp_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void pxa2xx_ssp_reset(DeviceState *d)
-{
- PXA2xxSSPState *s = PXA2XX_SSP(d);
-
- s->enable = 0;
- s->sscr[0] = s->sscr[1] = 0;
- s->sspsp = 0;
- s->ssto = 0;
- s->ssitr = 0;
- s->sssr = 0;
- s->sstsa = 0;
- s->ssrsa = 0;
- s->ssacd = 0;
- s->rx_start = s->rx_level = 0;
-}
-
-static int pxa2xx_ssp_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- PXA2xxSSPState *s = PXA2XX_SSP(dev);
-
- sysbus_init_irq(sbd, &s->irq);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &pxa2xx_ssp_ops, s,
- "pxa2xx-ssp", 0x1000);
- sysbus_init_mmio(sbd, &s->iomem);
-
- s->bus = ssi_create_bus(dev, "ssi");
- return 0;
-}
-
-/* Real-Time Clock */
-#define RCNR 0x00 /* RTC Counter register */
-#define RTAR 0x04 /* RTC Alarm register */
-#define RTSR 0x08 /* RTC Status register */
-#define RTTR 0x0c /* RTC Timer Trim register */
-#define RDCR 0x10 /* RTC Day Counter register */
-#define RYCR 0x14 /* RTC Year Counter register */
-#define RDAR1 0x18 /* RTC Wristwatch Day Alarm register 1 */
-#define RYAR1 0x1c /* RTC Wristwatch Year Alarm register 1 */
-#define RDAR2 0x20 /* RTC Wristwatch Day Alarm register 2 */
-#define RYAR2 0x24 /* RTC Wristwatch Year Alarm register 2 */
-#define SWCR 0x28 /* RTC Stopwatch Counter register */
-#define SWAR1 0x2c /* RTC Stopwatch Alarm register 1 */
-#define SWAR2 0x30 /* RTC Stopwatch Alarm register 2 */
-#define RTCPICR 0x34 /* RTC Periodic Interrupt Counter register */
-#define PIAR 0x38 /* RTC Periodic Interrupt Alarm register */
-
-#define TYPE_PXA2XX_RTC "pxa2xx_rtc"
-#define PXA2XX_RTC(obj) \
- OBJECT_CHECK(PXA2xxRTCState, (obj), TYPE_PXA2XX_RTC)
-
-typedef struct {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- MemoryRegion iomem;
- uint32_t rttr;
- uint32_t rtsr;
- uint32_t rtar;
- uint32_t rdar1;
- uint32_t rdar2;
- uint32_t ryar1;
- uint32_t ryar2;
- uint32_t swar1;
- uint32_t swar2;
- uint32_t piar;
- uint32_t last_rcnr;
- uint32_t last_rdcr;
- uint32_t last_rycr;
- uint32_t last_swcr;
- uint32_t last_rtcpicr;
- int64_t last_hz;
- int64_t last_sw;
- int64_t last_pi;
- QEMUTimer *rtc_hz;
- QEMUTimer *rtc_rdal1;
- QEMUTimer *rtc_rdal2;
- QEMUTimer *rtc_swal1;
- QEMUTimer *rtc_swal2;
- QEMUTimer *rtc_pi;
- qemu_irq rtc_irq;
-} PXA2xxRTCState;
-
-static inline void pxa2xx_rtc_int_update(PXA2xxRTCState *s)
-{
- qemu_set_irq(s->rtc_irq, !!(s->rtsr & 0x2553));
-}
-
-static void pxa2xx_rtc_hzupdate(PXA2xxRTCState *s)
-{
- int64_t rt = qemu_clock_get_ms(rtc_clock);
- s->last_rcnr += ((rt - s->last_hz) << 15) /
- (1000 * ((s->rttr & 0xffff) + 1));
- s->last_rdcr += ((rt - s->last_hz) << 15) /
- (1000 * ((s->rttr & 0xffff) + 1));
- s->last_hz = rt;
-}
-
-static void pxa2xx_rtc_swupdate(PXA2xxRTCState *s)
-{
- int64_t rt = qemu_clock_get_ms(rtc_clock);
- if (s->rtsr & (1 << 12))
- s->last_swcr += (rt - s->last_sw) / 10;
- s->last_sw = rt;
-}
-
-static void pxa2xx_rtc_piupdate(PXA2xxRTCState *s)
-{
- int64_t rt = qemu_clock_get_ms(rtc_clock);
- if (s->rtsr & (1 << 15))
- s->last_swcr += rt - s->last_pi;
- s->last_pi = rt;
-}
-
-static inline void pxa2xx_rtc_alarm_update(PXA2xxRTCState *s,
- uint32_t rtsr)
-{
- if ((rtsr & (1 << 2)) && !(rtsr & (1 << 0)))
- timer_mod(s->rtc_hz, s->last_hz +
- (((s->rtar - s->last_rcnr) * 1000 *
- ((s->rttr & 0xffff) + 1)) >> 15));
- else
- timer_del(s->rtc_hz);
-
- if ((rtsr & (1 << 5)) && !(rtsr & (1 << 4)))
- timer_mod(s->rtc_rdal1, s->last_hz +
- (((s->rdar1 - s->last_rdcr) * 1000 *
- ((s->rttr & 0xffff) + 1)) >> 15)); /* TODO: fixup */
- else
- timer_del(s->rtc_rdal1);
-
- if ((rtsr & (1 << 7)) && !(rtsr & (1 << 6)))
- timer_mod(s->rtc_rdal2, s->last_hz +
- (((s->rdar2 - s->last_rdcr) * 1000 *
- ((s->rttr & 0xffff) + 1)) >> 15)); /* TODO: fixup */
- else
- timer_del(s->rtc_rdal2);
-
- if ((rtsr & 0x1200) == 0x1200 && !(rtsr & (1 << 8)))
- timer_mod(s->rtc_swal1, s->last_sw +
- (s->swar1 - s->last_swcr) * 10); /* TODO: fixup */
- else
- timer_del(s->rtc_swal1);
-
- if ((rtsr & 0x1800) == 0x1800 && !(rtsr & (1 << 10)))
- timer_mod(s->rtc_swal2, s->last_sw +
- (s->swar2 - s->last_swcr) * 10); /* TODO: fixup */
- else
- timer_del(s->rtc_swal2);
-
- if ((rtsr & 0xc000) == 0xc000 && !(rtsr & (1 << 13)))
- timer_mod(s->rtc_pi, s->last_pi +
- (s->piar & 0xffff) - s->last_rtcpicr);
- else
- timer_del(s->rtc_pi);
-}
-
-static inline void pxa2xx_rtc_hz_tick(void *opaque)
-{
- PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
- s->rtsr |= (1 << 0);
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- pxa2xx_rtc_int_update(s);
-}
-
-static inline void pxa2xx_rtc_rdal1_tick(void *opaque)
-{
- PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
- s->rtsr |= (1 << 4);
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- pxa2xx_rtc_int_update(s);
-}
-
-static inline void pxa2xx_rtc_rdal2_tick(void *opaque)
-{
- PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
- s->rtsr |= (1 << 6);
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- pxa2xx_rtc_int_update(s);
-}
-
-static inline void pxa2xx_rtc_swal1_tick(void *opaque)
-{
- PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
- s->rtsr |= (1 << 8);
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- pxa2xx_rtc_int_update(s);
-}
-
-static inline void pxa2xx_rtc_swal2_tick(void *opaque)
-{
- PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
- s->rtsr |= (1 << 10);
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- pxa2xx_rtc_int_update(s);
-}
-
-static inline void pxa2xx_rtc_pi_tick(void *opaque)
-{
- PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
- s->rtsr |= (1 << 13);
- pxa2xx_rtc_piupdate(s);
- s->last_rtcpicr = 0;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- pxa2xx_rtc_int_update(s);
-}
-
-static uint64_t pxa2xx_rtc_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
-
- switch (addr) {
- case RTTR:
- return s->rttr;
- case RTSR:
- return s->rtsr;
- case RTAR:
- return s->rtar;
- case RDAR1:
- return s->rdar1;
- case RDAR2:
- return s->rdar2;
- case RYAR1:
- return s->ryar1;
- case RYAR2:
- return s->ryar2;
- case SWAR1:
- return s->swar1;
- case SWAR2:
- return s->swar2;
- case PIAR:
- return s->piar;
- case RCNR:
- return s->last_rcnr +
- ((qemu_clock_get_ms(rtc_clock) - s->last_hz) << 15) /
- (1000 * ((s->rttr & 0xffff) + 1));
- case RDCR:
- return s->last_rdcr +
- ((qemu_clock_get_ms(rtc_clock) - s->last_hz) << 15) /
- (1000 * ((s->rttr & 0xffff) + 1));
- case RYCR:
- return s->last_rycr;
- case SWCR:
- if (s->rtsr & (1 << 12))
- return s->last_swcr +
- (qemu_clock_get_ms(rtc_clock) - s->last_sw) / 10;
- else
- return s->last_swcr;
- default:
- printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
- break;
- }
- return 0;
-}
-
-static void pxa2xx_rtc_write(void *opaque, hwaddr addr,
- uint64_t value64, unsigned size)
-{
- PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
- uint32_t value = value64;
-
- switch (addr) {
- case RTTR:
- if (!(s->rttr & (1U << 31))) {
- pxa2xx_rtc_hzupdate(s);
- s->rttr = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- }
- break;
-
- case RTSR:
- if ((s->rtsr ^ value) & (1 << 15))
- pxa2xx_rtc_piupdate(s);
-
- if ((s->rtsr ^ value) & (1 << 12))
- pxa2xx_rtc_swupdate(s);
-
- if (((s->rtsr ^ value) & 0x4aac) | (value & ~0xdaac))
- pxa2xx_rtc_alarm_update(s, value);
-
- s->rtsr = (value & 0xdaac) | (s->rtsr & ~(value & ~0xdaac));
- pxa2xx_rtc_int_update(s);
- break;
-
- case RTAR:
- s->rtar = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case RDAR1:
- s->rdar1 = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case RDAR2:
- s->rdar2 = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case RYAR1:
- s->ryar1 = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case RYAR2:
- s->ryar2 = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case SWAR1:
- pxa2xx_rtc_swupdate(s);
- s->swar1 = value;
- s->last_swcr = 0;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case SWAR2:
- s->swar2 = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case PIAR:
- s->piar = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case RCNR:
- pxa2xx_rtc_hzupdate(s);
- s->last_rcnr = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case RDCR:
- pxa2xx_rtc_hzupdate(s);
- s->last_rdcr = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case RYCR:
- s->last_rycr = value;
- break;
-
- case SWCR:
- pxa2xx_rtc_swupdate(s);
- s->last_swcr = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case RTCPICR:
- pxa2xx_rtc_piupdate(s);
- s->last_rtcpicr = value & 0xffff;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- default:
- printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
- }
-}
-
-static const MemoryRegionOps pxa2xx_rtc_ops = {
- .read = pxa2xx_rtc_read,
- .write = pxa2xx_rtc_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int pxa2xx_rtc_init(SysBusDevice *dev)
-{
- PXA2xxRTCState *s = PXA2XX_RTC(dev);
- struct tm tm;
- int wom;
-
- s->rttr = 0x7fff;
- s->rtsr = 0;
-
- qemu_get_timedate(&tm, 0);
- wom = ((tm.tm_mday - 1) / 7) + 1;
-
- s->last_rcnr = (uint32_t) mktimegm(&tm);
- s->last_rdcr = (wom << 20) | ((tm.tm_wday + 1) << 17) |
- (tm.tm_hour << 12) | (tm.tm_min << 6) | tm.tm_sec;
- s->last_rycr = ((tm.tm_year + 1900) << 9) |
- ((tm.tm_mon + 1) << 5) | tm.tm_mday;
- s->last_swcr = (tm.tm_hour << 19) |
- (tm.tm_min << 13) | (tm.tm_sec << 7);
- s->last_rtcpicr = 0;
- s->last_hz = s->last_sw = s->last_pi = qemu_clock_get_ms(rtc_clock);
-
- s->rtc_hz = timer_new_ms(rtc_clock, pxa2xx_rtc_hz_tick, s);
- s->rtc_rdal1 = timer_new_ms(rtc_clock, pxa2xx_rtc_rdal1_tick, s);
- s->rtc_rdal2 = timer_new_ms(rtc_clock, pxa2xx_rtc_rdal2_tick, s);
- s->rtc_swal1 = timer_new_ms(rtc_clock, pxa2xx_rtc_swal1_tick, s);
- s->rtc_swal2 = timer_new_ms(rtc_clock, pxa2xx_rtc_swal2_tick, s);
- s->rtc_pi = timer_new_ms(rtc_clock, pxa2xx_rtc_pi_tick, s);
-
- sysbus_init_irq(dev, &s->rtc_irq);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &pxa2xx_rtc_ops, s,
- "pxa2xx-rtc", 0x10000);
- sysbus_init_mmio(dev, &s->iomem);
-
- return 0;
-}
-
-static void pxa2xx_rtc_pre_save(void *opaque)
-{
- PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
-
- pxa2xx_rtc_hzupdate(s);
- pxa2xx_rtc_piupdate(s);
- pxa2xx_rtc_swupdate(s);
-}
-
-static int pxa2xx_rtc_post_load(void *opaque, int version_id)
-{
- PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
-
- pxa2xx_rtc_alarm_update(s, s->rtsr);
-
- return 0;
-}
-
-static const VMStateDescription vmstate_pxa2xx_rtc_regs = {
- .name = "pxa2xx_rtc",
- .version_id = 0,
- .minimum_version_id = 0,
- .pre_save = pxa2xx_rtc_pre_save,
- .post_load = pxa2xx_rtc_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(rttr, PXA2xxRTCState),
- VMSTATE_UINT32(rtsr, PXA2xxRTCState),
- VMSTATE_UINT32(rtar, PXA2xxRTCState),
- VMSTATE_UINT32(rdar1, PXA2xxRTCState),
- VMSTATE_UINT32(rdar2, PXA2xxRTCState),
- VMSTATE_UINT32(ryar1, PXA2xxRTCState),
- VMSTATE_UINT32(ryar2, PXA2xxRTCState),
- VMSTATE_UINT32(swar1, PXA2xxRTCState),
- VMSTATE_UINT32(swar2, PXA2xxRTCState),
- VMSTATE_UINT32(piar, PXA2xxRTCState),
- VMSTATE_UINT32(last_rcnr, PXA2xxRTCState),
- VMSTATE_UINT32(last_rdcr, PXA2xxRTCState),
- VMSTATE_UINT32(last_rycr, PXA2xxRTCState),
- VMSTATE_UINT32(last_swcr, PXA2xxRTCState),
- VMSTATE_UINT32(last_rtcpicr, PXA2xxRTCState),
- VMSTATE_INT64(last_hz, PXA2xxRTCState),
- VMSTATE_INT64(last_sw, PXA2xxRTCState),
- VMSTATE_INT64(last_pi, PXA2xxRTCState),
- VMSTATE_END_OF_LIST(),
- },
-};
-
-static void pxa2xx_rtc_sysbus_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = pxa2xx_rtc_init;
- dc->desc = "PXA2xx RTC Controller";
- dc->vmsd = &vmstate_pxa2xx_rtc_regs;
-}
-
-static const TypeInfo pxa2xx_rtc_sysbus_info = {
- .name = TYPE_PXA2XX_RTC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PXA2xxRTCState),
- .class_init = pxa2xx_rtc_sysbus_class_init,
-};
-
-/* I2C Interface */
-
-#define TYPE_PXA2XX_I2C_SLAVE "pxa2xx-i2c-slave"
-#define PXA2XX_I2C_SLAVE(obj) \
- OBJECT_CHECK(PXA2xxI2CSlaveState, (obj), TYPE_PXA2XX_I2C_SLAVE)
-
-typedef struct PXA2xxI2CSlaveState {
- I2CSlave parent_obj;
-
- PXA2xxI2CState *host;
-} PXA2xxI2CSlaveState;
-
-#define TYPE_PXA2XX_I2C "pxa2xx_i2c"
-#define PXA2XX_I2C(obj) \
- OBJECT_CHECK(PXA2xxI2CState, (obj), TYPE_PXA2XX_I2C)
-
-struct PXA2xxI2CState {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- MemoryRegion iomem;
- PXA2xxI2CSlaveState *slave;
- I2CBus *bus;
- qemu_irq irq;
- uint32_t offset;
- uint32_t region_size;
-
- uint16_t control;
- uint16_t status;
- uint8_t ibmr;
- uint8_t data;
-};
-
-#define IBMR 0x80 /* I2C Bus Monitor register */
-#define IDBR 0x88 /* I2C Data Buffer register */
-#define ICR 0x90 /* I2C Control register */
-#define ISR 0x98 /* I2C Status register */
-#define ISAR 0xa0 /* I2C Slave Address register */
-
-static void pxa2xx_i2c_update(PXA2xxI2CState *s)
-{
- uint16_t level = 0;
- level |= s->status & s->control & (1 << 10); /* BED */
- level |= (s->status & (1 << 7)) && (s->control & (1 << 9)); /* IRF */
- level |= (s->status & (1 << 6)) && (s->control & (1 << 8)); /* ITE */
- level |= s->status & (1 << 9); /* SAD */
- qemu_set_irq(s->irq, !!level);
-}
-
-/* These are only stubs now. */
-static void pxa2xx_i2c_event(I2CSlave *i2c, enum i2c_event event)
-{
- PXA2xxI2CSlaveState *slave = PXA2XX_I2C_SLAVE(i2c);
- PXA2xxI2CState *s = slave->host;
-
- switch (event) {
- case I2C_START_SEND:
- s->status |= (1 << 9); /* set SAD */
- s->status &= ~(1 << 0); /* clear RWM */
- break;
- case I2C_START_RECV:
- s->status |= (1 << 9); /* set SAD */
- s->status |= 1 << 0; /* set RWM */
- break;
- case I2C_FINISH:
- s->status |= (1 << 4); /* set SSD */
- break;
- case I2C_NACK:
- s->status |= 1 << 1; /* set ACKNAK */
- break;
- }
- pxa2xx_i2c_update(s);
-}
-
-static int pxa2xx_i2c_rx(I2CSlave *i2c)
-{
- PXA2xxI2CSlaveState *slave = PXA2XX_I2C_SLAVE(i2c);
- PXA2xxI2CState *s = slave->host;
-
- if ((s->control & (1 << 14)) || !(s->control & (1 << 6))) {
- return 0;
- }
-
- if (s->status & (1 << 0)) { /* RWM */
- s->status |= 1 << 6; /* set ITE */
- }
- pxa2xx_i2c_update(s);
-
- return s->data;
-}
-
-static int pxa2xx_i2c_tx(I2CSlave *i2c, uint8_t data)
-{
- PXA2xxI2CSlaveState *slave = PXA2XX_I2C_SLAVE(i2c);
- PXA2xxI2CState *s = slave->host;
-
- if ((s->control & (1 << 14)) || !(s->control & (1 << 6))) {
- return 1;
- }
-
- if (!(s->status & (1 << 0))) { /* RWM */
- s->status |= 1 << 7; /* set IRF */
- s->data = data;
- }
- pxa2xx_i2c_update(s);
-
- return 1;
-}
-
-static uint64_t pxa2xx_i2c_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- PXA2xxI2CState *s = (PXA2xxI2CState *) opaque;
- I2CSlave *slave;
-
- addr -= s->offset;
- switch (addr) {
- case ICR:
- return s->control;
- case ISR:
- return s->status | (i2c_bus_busy(s->bus) << 2);
- case ISAR:
- slave = I2C_SLAVE(s->slave);
- return slave->address;
- case IDBR:
- return s->data;
- case IBMR:
- if (s->status & (1 << 2))
- s->ibmr ^= 3; /* Fake SCL and SDA pin changes */
- else
- s->ibmr = 0;
- return s->ibmr;
- default:
- printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
- break;
- }
- return 0;
-}
-
-static void pxa2xx_i2c_write(void *opaque, hwaddr addr,
- uint64_t value64, unsigned size)
-{
- PXA2xxI2CState *s = (PXA2xxI2CState *) opaque;
- uint32_t value = value64;
- int ack;
-
- addr -= s->offset;
- switch (addr) {
- case ICR:
- s->control = value & 0xfff7;
- if ((value & (1 << 3)) && (value & (1 << 6))) { /* TB and IUE */
- /* TODO: slave mode */
- if (value & (1 << 0)) { /* START condition */
- if (s->data & 1)
- s->status |= 1 << 0; /* set RWM */
- else
- s->status &= ~(1 << 0); /* clear RWM */
- ack = !i2c_start_transfer(s->bus, s->data >> 1, s->data & 1);
- } else {
- if (s->status & (1 << 0)) { /* RWM */
- s->data = i2c_recv(s->bus);
- if (value & (1 << 2)) /* ACKNAK */
- i2c_nack(s->bus);
- ack = 1;
- } else
- ack = !i2c_send(s->bus, s->data);
- }
-
- if (value & (1 << 1)) /* STOP condition */
- i2c_end_transfer(s->bus);
-
- if (ack) {
- if (value & (1 << 0)) /* START condition */
- s->status |= 1 << 6; /* set ITE */
- else
- if (s->status & (1 << 0)) /* RWM */
- s->status |= 1 << 7; /* set IRF */
- else
- s->status |= 1 << 6; /* set ITE */
- s->status &= ~(1 << 1); /* clear ACKNAK */
- } else {
- s->status |= 1 << 6; /* set ITE */
- s->status |= 1 << 10; /* set BED */
- s->status |= 1 << 1; /* set ACKNAK */
- }
- }
- if (!(value & (1 << 3)) && (value & (1 << 6))) /* !TB and IUE */
- if (value & (1 << 4)) /* MA */
- i2c_end_transfer(s->bus);
- pxa2xx_i2c_update(s);
- break;
-
- case ISR:
- s->status &= ~(value & 0x07f0);
- pxa2xx_i2c_update(s);
- break;
-
- case ISAR:
- i2c_set_slave_address(I2C_SLAVE(s->slave), value & 0x7f);
- break;
-
- case IDBR:
- s->data = value & 0xff;
- break;
-
- default:
- printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
- }
-}
-
-static const MemoryRegionOps pxa2xx_i2c_ops = {
- .read = pxa2xx_i2c_read,
- .write = pxa2xx_i2c_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_pxa2xx_i2c_slave = {
- .name = "pxa2xx_i2c_slave",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_I2C_SLAVE(parent_obj, PXA2xxI2CSlaveState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_pxa2xx_i2c = {
- .name = "pxa2xx_i2c",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT16(control, PXA2xxI2CState),
- VMSTATE_UINT16(status, PXA2xxI2CState),
- VMSTATE_UINT8(ibmr, PXA2xxI2CState),
- VMSTATE_UINT8(data, PXA2xxI2CState),
- VMSTATE_STRUCT_POINTER(slave, PXA2xxI2CState,
- vmstate_pxa2xx_i2c_slave, PXA2xxI2CSlaveState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static int pxa2xx_i2c_slave_init(I2CSlave *i2c)
-{
- /* Nothing to do. */
- return 0;
-}
-
-static void pxa2xx_i2c_slave_class_init(ObjectClass *klass, void *data)
-{
- I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
-
- k->init = pxa2xx_i2c_slave_init;
- k->event = pxa2xx_i2c_event;
- k->recv = pxa2xx_i2c_rx;
- k->send = pxa2xx_i2c_tx;
-}
-
-static const TypeInfo pxa2xx_i2c_slave_info = {
- .name = TYPE_PXA2XX_I2C_SLAVE,
- .parent = TYPE_I2C_SLAVE,
- .instance_size = sizeof(PXA2xxI2CSlaveState),
- .class_init = pxa2xx_i2c_slave_class_init,
-};
-
-PXA2xxI2CState *pxa2xx_i2c_init(hwaddr base,
- qemu_irq irq, uint32_t region_size)
-{
- DeviceState *dev;
- SysBusDevice *i2c_dev;
- PXA2xxI2CState *s;
- I2CBus *i2cbus;
-
- dev = qdev_create(NULL, TYPE_PXA2XX_I2C);
- qdev_prop_set_uint32(dev, "size", region_size + 1);
- qdev_prop_set_uint32(dev, "offset", base & region_size);
- qdev_init_nofail(dev);
-
- i2c_dev = SYS_BUS_DEVICE(dev);
- sysbus_mmio_map(i2c_dev, 0, base & ~region_size);
- sysbus_connect_irq(i2c_dev, 0, irq);
-
- s = PXA2XX_I2C(i2c_dev);
- /* FIXME: Should the slave device really be on a separate bus? */
- i2cbus = i2c_init_bus(dev, "dummy");
- dev = i2c_create_slave(i2cbus, TYPE_PXA2XX_I2C_SLAVE, 0);
- s->slave = PXA2XX_I2C_SLAVE(dev);
- s->slave->host = s;
-
- return s;
-}
-
-static int pxa2xx_i2c_initfn(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- PXA2xxI2CState *s = PXA2XX_I2C(dev);
-
- s->bus = i2c_init_bus(dev, "i2c");
-
- memory_region_init_io(&s->iomem, OBJECT(s), &pxa2xx_i2c_ops, s,
- "pxa2xx-i2c", s->region_size);
- sysbus_init_mmio(sbd, &s->iomem);
- sysbus_init_irq(sbd, &s->irq);
-
- return 0;
-}
-
-I2CBus *pxa2xx_i2c_bus(PXA2xxI2CState *s)
-{
- return s->bus;
-}
-
-static Property pxa2xx_i2c_properties[] = {
- DEFINE_PROP_UINT32("size", PXA2xxI2CState, region_size, 0x10000),
- DEFINE_PROP_UINT32("offset", PXA2xxI2CState, offset, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pxa2xx_i2c_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = pxa2xx_i2c_initfn;
- dc->desc = "PXA2xx I2C Bus Controller";
- dc->vmsd = &vmstate_pxa2xx_i2c;
- dc->props = pxa2xx_i2c_properties;
-}
-
-static const TypeInfo pxa2xx_i2c_info = {
- .name = TYPE_PXA2XX_I2C,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PXA2xxI2CState),
- .class_init = pxa2xx_i2c_class_init,
-};
-
-/* PXA Inter-IC Sound Controller */
-static void pxa2xx_i2s_reset(PXA2xxI2SState *i2s)
-{
- i2s->rx_len = 0;
- i2s->tx_len = 0;
- i2s->fifo_len = 0;
- i2s->clk = 0x1a;
- i2s->control[0] = 0x00;
- i2s->control[1] = 0x00;
- i2s->status = 0x00;
- i2s->mask = 0x00;
-}
-
-#define SACR_TFTH(val) ((val >> 8) & 0xf)
-#define SACR_RFTH(val) ((val >> 12) & 0xf)
-#define SACR_DREC(val) (val & (1 << 3))
-#define SACR_DPRL(val) (val & (1 << 4))
-
-static inline void pxa2xx_i2s_update(PXA2xxI2SState *i2s)
-{
- int rfs, tfs;
- rfs = SACR_RFTH(i2s->control[0]) < i2s->rx_len &&
- !SACR_DREC(i2s->control[1]);
- tfs = (i2s->tx_len || i2s->fifo_len < SACR_TFTH(i2s->control[0])) &&
- i2s->enable && !SACR_DPRL(i2s->control[1]);
-
- qemu_set_irq(i2s->rx_dma, rfs);
- qemu_set_irq(i2s->tx_dma, tfs);
-
- i2s->status &= 0xe0;
- if (i2s->fifo_len < 16 || !i2s->enable)
- i2s->status |= 1 << 0; /* TNF */
- if (i2s->rx_len)
- i2s->status |= 1 << 1; /* RNE */
- if (i2s->enable)
- i2s->status |= 1 << 2; /* BSY */
- if (tfs)
- i2s->status |= 1 << 3; /* TFS */
- if (rfs)
- i2s->status |= 1 << 4; /* RFS */
- if (!(i2s->tx_len && i2s->enable))
- i2s->status |= i2s->fifo_len << 8; /* TFL */
- i2s->status |= MAX(i2s->rx_len, 0xf) << 12; /* RFL */
-
- qemu_set_irq(i2s->irq, i2s->status & i2s->mask);
-}
-
-#define SACR0 0x00 /* Serial Audio Global Control register */
-#define SACR1 0x04 /* Serial Audio I2S/MSB-Justified Control register */
-#define SASR0 0x0c /* Serial Audio Interface and FIFO Status register */
-#define SAIMR 0x14 /* Serial Audio Interrupt Mask register */
-#define SAICR 0x18 /* Serial Audio Interrupt Clear register */
-#define SADIV 0x60 /* Serial Audio Clock Divider register */
-#define SADR 0x80 /* Serial Audio Data register */
-
-static uint64_t pxa2xx_i2s_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- PXA2xxI2SState *s = (PXA2xxI2SState *) opaque;
-
- switch (addr) {
- case SACR0:
- return s->control[0];
- case SACR1:
- return s->control[1];
- case SASR0:
- return s->status;
- case SAIMR:
- return s->mask;
- case SAICR:
- return 0;
- case SADIV:
- return s->clk;
- case SADR:
- if (s->rx_len > 0) {
- s->rx_len --;
- pxa2xx_i2s_update(s);
- return s->codec_in(s->opaque);
- }
- return 0;
- default:
- printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
- break;
- }
- return 0;
-}
-
-static void pxa2xx_i2s_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- PXA2xxI2SState *s = (PXA2xxI2SState *) opaque;
- uint32_t *sample;
-
- switch (addr) {
- case SACR0:
- if (value & (1 << 3)) /* RST */
- pxa2xx_i2s_reset(s);
- s->control[0] = value & 0xff3d;
- if (!s->enable && (value & 1) && s->tx_len) { /* ENB */
- for (sample = s->fifo; s->fifo_len > 0; s->fifo_len --, sample ++)
- s->codec_out(s->opaque, *sample);
- s->status &= ~(1 << 7); /* I2SOFF */
- }
- if (value & (1 << 4)) /* EFWR */
- printf("%s: Attempt to use special function\n", __FUNCTION__);
- s->enable = (value & 9) == 1; /* ENB && !RST*/
- pxa2xx_i2s_update(s);
- break;
- case SACR1:
- s->control[1] = value & 0x0039;
- if (value & (1 << 5)) /* ENLBF */
- printf("%s: Attempt to use loopback function\n", __FUNCTION__);
- if (value & (1 << 4)) /* DPRL */
- s->fifo_len = 0;
- pxa2xx_i2s_update(s);
- break;
- case SAIMR:
- s->mask = value & 0x0078;
- pxa2xx_i2s_update(s);
- break;
- case SAICR:
- s->status &= ~(value & (3 << 5));
- pxa2xx_i2s_update(s);
- break;
- case SADIV:
- s->clk = value & 0x007f;
- break;
- case SADR:
- if (s->tx_len && s->enable) {
- s->tx_len --;
- pxa2xx_i2s_update(s);
- s->codec_out(s->opaque, value);
- } else if (s->fifo_len < 16) {
- s->fifo[s->fifo_len ++] = value;
- pxa2xx_i2s_update(s);
- }
- break;
- default:
- printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
- }
-}
-
-static const MemoryRegionOps pxa2xx_i2s_ops = {
- .read = pxa2xx_i2s_read,
- .write = pxa2xx_i2s_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_pxa2xx_i2s = {
- .name = "pxa2xx_i2s",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(control, PXA2xxI2SState, 2),
- VMSTATE_UINT32(status, PXA2xxI2SState),
- VMSTATE_UINT32(mask, PXA2xxI2SState),
- VMSTATE_UINT32(clk, PXA2xxI2SState),
- VMSTATE_INT32(enable, PXA2xxI2SState),
- VMSTATE_INT32(rx_len, PXA2xxI2SState),
- VMSTATE_INT32(tx_len, PXA2xxI2SState),
- VMSTATE_INT32(fifo_len, PXA2xxI2SState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void pxa2xx_i2s_data_req(void *opaque, int tx, int rx)
-{
- PXA2xxI2SState *s = (PXA2xxI2SState *) opaque;
- uint32_t *sample;
-
- /* Signal FIFO errors */
- if (s->enable && s->tx_len)
- s->status |= 1 << 5; /* TUR */
- if (s->enable && s->rx_len)
- s->status |= 1 << 6; /* ROR */
-
- /* Should be tx - MIN(tx, s->fifo_len) but we don't really need to
- * handle the cases where it makes a difference. */
- s->tx_len = tx - s->fifo_len;
- s->rx_len = rx;
- /* Note that is s->codec_out wasn't set, we wouldn't get called. */
- if (s->enable)
- for (sample = s->fifo; s->fifo_len; s->fifo_len --, sample ++)
- s->codec_out(s->opaque, *sample);
- pxa2xx_i2s_update(s);
-}
-
-static PXA2xxI2SState *pxa2xx_i2s_init(MemoryRegion *sysmem,
- hwaddr base,
- qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma)
-{
- PXA2xxI2SState *s = g_new0(PXA2xxI2SState, 1);
-
- s->irq = irq;
- s->rx_dma = rx_dma;
- s->tx_dma = tx_dma;
- s->data_req = pxa2xx_i2s_data_req;
-
- pxa2xx_i2s_reset(s);
-
- memory_region_init_io(&s->iomem, NULL, &pxa2xx_i2s_ops, s,
- "pxa2xx-i2s", 0x100000);
- memory_region_add_subregion(sysmem, base, &s->iomem);
-
- vmstate_register(NULL, base, &vmstate_pxa2xx_i2s, s);
-
- return s;
-}
-
-/* PXA Fast Infra-red Communications Port */
-#define TYPE_PXA2XX_FIR "pxa2xx-fir"
-#define PXA2XX_FIR(obj) OBJECT_CHECK(PXA2xxFIrState, (obj), TYPE_PXA2XX_FIR)
-
-struct PXA2xxFIrState {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- MemoryRegion iomem;
- qemu_irq irq;
- qemu_irq rx_dma;
- qemu_irq tx_dma;
- uint32_t enable;
- CharDriverState *chr;
-
- uint8_t control[3];
- uint8_t status[2];
-
- uint32_t rx_len;
- uint32_t rx_start;
- uint8_t rx_fifo[64];
-};
-
-static void pxa2xx_fir_reset(DeviceState *d)
-{
- PXA2xxFIrState *s = PXA2XX_FIR(d);
-
- s->control[0] = 0x00;
- s->control[1] = 0x00;
- s->control[2] = 0x00;
- s->status[0] = 0x00;
- s->status[1] = 0x00;
- s->enable = 0;
-}
-
-static inline void pxa2xx_fir_update(PXA2xxFIrState *s)
-{
- static const int tresh[4] = { 8, 16, 32, 0 };
- int intr = 0;
- if ((s->control[0] & (1 << 4)) && /* RXE */
- s->rx_len >= tresh[s->control[2] & 3]) /* TRIG */
- s->status[0] |= 1 << 4; /* RFS */
- else
- s->status[0] &= ~(1 << 4); /* RFS */
- if (s->control[0] & (1 << 3)) /* TXE */
- s->status[0] |= 1 << 3; /* TFS */
- else
- s->status[0] &= ~(1 << 3); /* TFS */
- if (s->rx_len)
- s->status[1] |= 1 << 2; /* RNE */
- else
- s->status[1] &= ~(1 << 2); /* RNE */
- if (s->control[0] & (1 << 4)) /* RXE */
- s->status[1] |= 1 << 0; /* RSY */
- else
- s->status[1] &= ~(1 << 0); /* RSY */
-
- intr |= (s->control[0] & (1 << 5)) && /* RIE */
- (s->status[0] & (1 << 4)); /* RFS */
- intr |= (s->control[0] & (1 << 6)) && /* TIE */
- (s->status[0] & (1 << 3)); /* TFS */
- intr |= (s->control[2] & (1 << 4)) && /* TRAIL */
- (s->status[0] & (1 << 6)); /* EOC */
- intr |= (s->control[0] & (1 << 2)) && /* TUS */
- (s->status[0] & (1 << 1)); /* TUR */
- intr |= s->status[0] & 0x25; /* FRE, RAB, EIF */
-
- qemu_set_irq(s->rx_dma, (s->status[0] >> 4) & 1);
- qemu_set_irq(s->tx_dma, (s->status[0] >> 3) & 1);
-
- qemu_set_irq(s->irq, intr && s->enable);
-}
-
-#define ICCR0 0x00 /* FICP Control register 0 */
-#define ICCR1 0x04 /* FICP Control register 1 */
-#define ICCR2 0x08 /* FICP Control register 2 */
-#define ICDR 0x0c /* FICP Data register */
-#define ICSR0 0x14 /* FICP Status register 0 */
-#define ICSR1 0x18 /* FICP Status register 1 */
-#define ICFOR 0x1c /* FICP FIFO Occupancy Status register */
-
-static uint64_t pxa2xx_fir_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- PXA2xxFIrState *s = (PXA2xxFIrState *) opaque;
- uint8_t ret;
-
- switch (addr) {
- case ICCR0:
- return s->control[0];
- case ICCR1:
- return s->control[1];
- case ICCR2:
- return s->control[2];
- case ICDR:
- s->status[0] &= ~0x01;
- s->status[1] &= ~0x72;
- if (s->rx_len) {
- s->rx_len --;
- ret = s->rx_fifo[s->rx_start ++];
- s->rx_start &= 63;
- pxa2xx_fir_update(s);
- return ret;
- }
- printf("%s: Rx FIFO underrun.\n", __FUNCTION__);
- break;
- case ICSR0:
- return s->status[0];
- case ICSR1:
- return s->status[1] | (1 << 3); /* TNF */
- case ICFOR:
- return s->rx_len;
- default:
- printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
- break;
- }
- return 0;
-}
-
-static void pxa2xx_fir_write(void *opaque, hwaddr addr,
- uint64_t value64, unsigned size)
-{
- PXA2xxFIrState *s = (PXA2xxFIrState *) opaque;
- uint32_t value = value64;
- uint8_t ch;
-
- switch (addr) {
- case ICCR0:
- s->control[0] = value;
- if (!(value & (1 << 4))) /* RXE */
- s->rx_len = s->rx_start = 0;
- if (!(value & (1 << 3))) { /* TXE */
- /* Nop */
- }
- s->enable = value & 1; /* ITR */
- if (!s->enable)
- s->status[0] = 0;
- pxa2xx_fir_update(s);
- break;
- case ICCR1:
- s->control[1] = value;
- break;
- case ICCR2:
- s->control[2] = value & 0x3f;
- pxa2xx_fir_update(s);
- break;
- case ICDR:
- if (s->control[2] & (1 << 2)) /* TXP */
- ch = value;
- else
- ch = ~value;
- if (s->chr && s->enable && (s->control[0] & (1 << 3))) /* TXE */
- qemu_chr_fe_write(s->chr, &ch, 1);
- break;
- case ICSR0:
- s->status[0] &= ~(value & 0x66);
- pxa2xx_fir_update(s);
- break;
- case ICFOR:
- break;
- default:
- printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
- }
-}
-
-static const MemoryRegionOps pxa2xx_fir_ops = {
- .read = pxa2xx_fir_read,
- .write = pxa2xx_fir_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int pxa2xx_fir_is_empty(void *opaque)
-{
- PXA2xxFIrState *s = (PXA2xxFIrState *) opaque;
- return (s->rx_len < 64);
-}
-
-static void pxa2xx_fir_rx(void *opaque, const uint8_t *buf, int size)
-{
- PXA2xxFIrState *s = (PXA2xxFIrState *) opaque;
- if (!(s->control[0] & (1 << 4))) /* RXE */
- return;
-
- while (size --) {
- s->status[1] |= 1 << 4; /* EOF */
- if (s->rx_len >= 64) {
- s->status[1] |= 1 << 6; /* ROR */
- break;
- }
-
- if (s->control[2] & (1 << 3)) /* RXP */
- s->rx_fifo[(s->rx_start + s->rx_len ++) & 63] = *(buf ++);
- else
- s->rx_fifo[(s->rx_start + s->rx_len ++) & 63] = ~*(buf ++);
- }
-
- pxa2xx_fir_update(s);
-}
-
-static void pxa2xx_fir_event(void *opaque, int event)
-{
-}
-
-static void pxa2xx_fir_instance_init(Object *obj)
-{
- PXA2xxFIrState *s = PXA2XX_FIR(obj);
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
-
- memory_region_init_io(&s->iomem, obj, &pxa2xx_fir_ops, s,
- "pxa2xx-fir", 0x1000);
- sysbus_init_mmio(sbd, &s->iomem);
- sysbus_init_irq(sbd, &s->irq);
- sysbus_init_irq(sbd, &s->rx_dma);
- sysbus_init_irq(sbd, &s->tx_dma);
-}
-
-static void pxa2xx_fir_realize(DeviceState *dev, Error **errp)
-{
- PXA2xxFIrState *s = PXA2XX_FIR(dev);
-
- if (s->chr) {
- qemu_chr_fe_claim_no_fail(s->chr);
- qemu_chr_add_handlers(s->chr, pxa2xx_fir_is_empty,
- pxa2xx_fir_rx, pxa2xx_fir_event, s);
- }
-}
-
-static bool pxa2xx_fir_vmstate_validate(void *opaque, int version_id)
-{
- PXA2xxFIrState *s = opaque;
-
- return s->rx_start < ARRAY_SIZE(s->rx_fifo);
-}
-
-static const VMStateDescription pxa2xx_fir_vmsd = {
- .name = "pxa2xx-fir",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(enable, PXA2xxFIrState),
- VMSTATE_UINT8_ARRAY(control, PXA2xxFIrState, 3),
- VMSTATE_UINT8_ARRAY(status, PXA2xxFIrState, 2),
- VMSTATE_UINT32(rx_len, PXA2xxFIrState),
- VMSTATE_UINT32(rx_start, PXA2xxFIrState),
- VMSTATE_VALIDATE("fifo is 64 bytes", pxa2xx_fir_vmstate_validate),
- VMSTATE_UINT8_ARRAY(rx_fifo, PXA2xxFIrState, 64),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property pxa2xx_fir_properties[] = {
- DEFINE_PROP_CHR("chardev", PXA2xxFIrState, chr),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pxa2xx_fir_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = pxa2xx_fir_realize;
- dc->vmsd = &pxa2xx_fir_vmsd;
- dc->props = pxa2xx_fir_properties;
- dc->reset = pxa2xx_fir_reset;
-}
-
-static const TypeInfo pxa2xx_fir_info = {
- .name = TYPE_PXA2XX_FIR,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PXA2xxFIrState),
- .class_init = pxa2xx_fir_class_init,
- .instance_init = pxa2xx_fir_instance_init,
-};
-
-static PXA2xxFIrState *pxa2xx_fir_init(MemoryRegion *sysmem,
- hwaddr base,
- qemu_irq irq, qemu_irq rx_dma,
- qemu_irq tx_dma,
- CharDriverState *chr)
-{
- DeviceState *dev;
- SysBusDevice *sbd;
-
- dev = qdev_create(NULL, TYPE_PXA2XX_FIR);
- qdev_prop_set_chr(dev, "chardev", chr);
- qdev_init_nofail(dev);
- sbd = SYS_BUS_DEVICE(dev);
- sysbus_mmio_map(sbd, 0, base);
- sysbus_connect_irq(sbd, 0, irq);
- sysbus_connect_irq(sbd, 1, rx_dma);
- sysbus_connect_irq(sbd, 2, tx_dma);
- return PXA2XX_FIR(dev);
-}
-
-static void pxa2xx_reset(void *opaque, int line, int level)
-{
- PXA2xxState *s = (PXA2xxState *) opaque;
-
- if (level && (s->pm_regs[PCFR >> 2] & 0x10)) { /* GPR_EN */
- cpu_reset(CPU(s->cpu));
- /* TODO: reset peripherals */
- }
-}
-
-/* Initialise a PXA270 integrated chip (ARM based core). */
-PXA2xxState *pxa270_init(MemoryRegion *address_space,
- unsigned int sdram_size, const char *revision)
-{
- PXA2xxState *s;
- int i;
- DriveInfo *dinfo;
- s = g_new0(PXA2xxState, 1);
-
- if (revision && strncmp(revision, "pxa27", 5)) {
- fprintf(stderr, "Machine requires a PXA27x processor.\n");
- exit(1);
- }
- if (!revision)
- revision = "pxa270";
-
- s->cpu = cpu_arm_init(revision);
- if (s->cpu == NULL) {
- fprintf(stderr, "Unable to find CPU definition\n");
- exit(1);
- }
- s->reset = qemu_allocate_irq(pxa2xx_reset, s, 0);
-
- /* SDRAM & Internal Memory Storage */
- memory_region_init_ram(&s->sdram, NULL, "pxa270.sdram", sdram_size,
- &error_fatal);
- vmstate_register_ram_global(&s->sdram);
- memory_region_add_subregion(address_space, PXA2XX_SDRAM_BASE, &s->sdram);
- memory_region_init_ram(&s->internal, NULL, "pxa270.internal", 0x40000,
- &error_fatal);
- vmstate_register_ram_global(&s->internal);
- memory_region_add_subregion(address_space, PXA2XX_INTERNAL_BASE,
- &s->internal);
-
- s->pic = pxa2xx_pic_init(0x40d00000, s->cpu);
-
- s->dma = pxa27x_dma_init(0x40000000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_DMA));
-
- sysbus_create_varargs("pxa27x-timer", 0x40a00000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 0),
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 1),
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 2),
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 3),
- qdev_get_gpio_in(s->pic, PXA27X_PIC_OST_4_11),
- NULL);
-
- s->gpio = pxa2xx_gpio_init(0x40e00000, s->cpu, s->pic, 121);
-
- dinfo = drive_get(IF_SD, 0, 0);
- if (!dinfo) {
- fprintf(stderr, "qemu: missing SecureDigital device\n");
- exit(1);
- }
- s->mmc = pxa2xx_mmci_init(address_space, 0x41100000,
- blk_by_legacy_dinfo(dinfo),
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_MMC),
- qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_MMCI),
- qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_MMCI));
-
- for (i = 0; pxa270_serial[i].io_base; i++) {
- if (serial_hds[i]) {
- serial_mm_init(address_space, pxa270_serial[i].io_base, 2,
- qdev_get_gpio_in(s->pic, pxa270_serial[i].irqn),
- 14857000 / 16, serial_hds[i],
- DEVICE_NATIVE_ENDIAN);
- } else {
- break;
- }
- }
- if (serial_hds[i])
- s->fir = pxa2xx_fir_init(address_space, 0x40800000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_ICP),
- qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_ICP),
- qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_ICP),
- serial_hds[i]);
-
- s->lcd = pxa2xx_lcdc_init(address_space, 0x44000000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_LCD));
-
- s->cm_base = 0x41300000;
- s->cm_regs[CCCR >> 2] = 0x02000210; /* 416.0 MHz */
- s->clkcfg = 0x00000009; /* Turbo mode active */
- memory_region_init_io(&s->cm_iomem, NULL, &pxa2xx_cm_ops, s, "pxa2xx-cm", 0x1000);
- memory_region_add_subregion(address_space, s->cm_base, &s->cm_iomem);
- vmstate_register(NULL, 0, &vmstate_pxa2xx_cm, s);
-
- pxa2xx_setup_cp14(s);
-
- s->mm_base = 0x48000000;
- s->mm_regs[MDMRS >> 2] = 0x00020002;
- s->mm_regs[MDREFR >> 2] = 0x03ca4000;
- s->mm_regs[MECR >> 2] = 0x00000001; /* Two PC Card sockets */
- memory_region_init_io(&s->mm_iomem, NULL, &pxa2xx_mm_ops, s, "pxa2xx-mm", 0x1000);
- memory_region_add_subregion(address_space, s->mm_base, &s->mm_iomem);
- vmstate_register(NULL, 0, &vmstate_pxa2xx_mm, s);
-
- s->pm_base = 0x40f00000;
- memory_region_init_io(&s->pm_iomem, NULL, &pxa2xx_pm_ops, s, "pxa2xx-pm", 0x100);
- memory_region_add_subregion(address_space, s->pm_base, &s->pm_iomem);
- vmstate_register(NULL, 0, &vmstate_pxa2xx_pm, s);
-
- for (i = 0; pxa27x_ssp[i].io_base; i ++);
- s->ssp = g_new0(SSIBus *, i);
- for (i = 0; pxa27x_ssp[i].io_base; i ++) {
- DeviceState *dev;
- dev = sysbus_create_simple(TYPE_PXA2XX_SSP, pxa27x_ssp[i].io_base,
- qdev_get_gpio_in(s->pic, pxa27x_ssp[i].irqn));
- s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi");
- }
-
- if (usb_enabled()) {
- sysbus_create_simple("sysbus-ohci", 0x4c000000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_USBH1));
- }
-
- s->pcmcia[0] = pxa2xx_pcmcia_init(address_space, 0x20000000);
- s->pcmcia[1] = pxa2xx_pcmcia_init(address_space, 0x30000000);
-
- sysbus_create_simple(TYPE_PXA2XX_RTC, 0x40900000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_RTCALARM));
-
- s->i2c[0] = pxa2xx_i2c_init(0x40301600,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_I2C), 0xffff);
- s->i2c[1] = pxa2xx_i2c_init(0x40f00100,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_PWRI2C), 0xff);
-
- s->i2s = pxa2xx_i2s_init(address_space, 0x40400000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_I2S),
- qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_I2S),
- qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_I2S));
-
- s->kp = pxa27x_keypad_init(address_space, 0x41500000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_KEYPAD));
-
- /* GPIO1 resets the processor */
- /* The handler can be overridden by board-specific code */
- qdev_connect_gpio_out(s->gpio, 1, s->reset);
- return s;
-}
-
-/* Initialise a PXA255 integrated chip (ARM based core). */
-PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size)
-{
- PXA2xxState *s;
- int i;
- DriveInfo *dinfo;
-
- s = g_new0(PXA2xxState, 1);
-
- s->cpu = cpu_arm_init("pxa255");
- if (s->cpu == NULL) {
- fprintf(stderr, "Unable to find CPU definition\n");
- exit(1);
- }
- s->reset = qemu_allocate_irq(pxa2xx_reset, s, 0);
-
- /* SDRAM & Internal Memory Storage */
- memory_region_init_ram(&s->sdram, NULL, "pxa255.sdram", sdram_size,
- &error_fatal);
- vmstate_register_ram_global(&s->sdram);
- memory_region_add_subregion(address_space, PXA2XX_SDRAM_BASE, &s->sdram);
- memory_region_init_ram(&s->internal, NULL, "pxa255.internal",
- PXA2XX_INTERNAL_SIZE, &error_fatal);
- vmstate_register_ram_global(&s->internal);
- memory_region_add_subregion(address_space, PXA2XX_INTERNAL_BASE,
- &s->internal);
-
- s->pic = pxa2xx_pic_init(0x40d00000, s->cpu);
-
- s->dma = pxa255_dma_init(0x40000000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_DMA));
-
- sysbus_create_varargs("pxa25x-timer", 0x40a00000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 0),
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 1),
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 2),
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 3),
- NULL);
-
- s->gpio = pxa2xx_gpio_init(0x40e00000, s->cpu, s->pic, 85);
-
- dinfo = drive_get(IF_SD, 0, 0);
- if (!dinfo) {
- fprintf(stderr, "qemu: missing SecureDigital device\n");
- exit(1);
- }
- s->mmc = pxa2xx_mmci_init(address_space, 0x41100000,
- blk_by_legacy_dinfo(dinfo),
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_MMC),
- qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_MMCI),
- qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_MMCI));
-
- for (i = 0; pxa255_serial[i].io_base; i++) {
- if (serial_hds[i]) {
- serial_mm_init(address_space, pxa255_serial[i].io_base, 2,
- qdev_get_gpio_in(s->pic, pxa255_serial[i].irqn),
- 14745600 / 16, serial_hds[i],
- DEVICE_NATIVE_ENDIAN);
- } else {
- break;
- }
- }
- if (serial_hds[i])
- s->fir = pxa2xx_fir_init(address_space, 0x40800000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_ICP),
- qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_ICP),
- qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_ICP),
- serial_hds[i]);
-
- s->lcd = pxa2xx_lcdc_init(address_space, 0x44000000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_LCD));
-
- s->cm_base = 0x41300000;
- s->cm_regs[CCCR >> 2] = 0x02000210; /* 416.0 MHz */
- s->clkcfg = 0x00000009; /* Turbo mode active */
- memory_region_init_io(&s->cm_iomem, NULL, &pxa2xx_cm_ops, s, "pxa2xx-cm", 0x1000);
- memory_region_add_subregion(address_space, s->cm_base, &s->cm_iomem);
- vmstate_register(NULL, 0, &vmstate_pxa2xx_cm, s);
-
- pxa2xx_setup_cp14(s);
-
- s->mm_base = 0x48000000;
- s->mm_regs[MDMRS >> 2] = 0x00020002;
- s->mm_regs[MDREFR >> 2] = 0x03ca4000;
- s->mm_regs[MECR >> 2] = 0x00000001; /* Two PC Card sockets */
- memory_region_init_io(&s->mm_iomem, NULL, &pxa2xx_mm_ops, s, "pxa2xx-mm", 0x1000);
- memory_region_add_subregion(address_space, s->mm_base, &s->mm_iomem);
- vmstate_register(NULL, 0, &vmstate_pxa2xx_mm, s);
-
- s->pm_base = 0x40f00000;
- memory_region_init_io(&s->pm_iomem, NULL, &pxa2xx_pm_ops, s, "pxa2xx-pm", 0x100);
- memory_region_add_subregion(address_space, s->pm_base, &s->pm_iomem);
- vmstate_register(NULL, 0, &vmstate_pxa2xx_pm, s);
-
- for (i = 0; pxa255_ssp[i].io_base; i ++);
- s->ssp = g_new0(SSIBus *, i);
- for (i = 0; pxa255_ssp[i].io_base; i ++) {
- DeviceState *dev;
- dev = sysbus_create_simple(TYPE_PXA2XX_SSP, pxa255_ssp[i].io_base,
- qdev_get_gpio_in(s->pic, pxa255_ssp[i].irqn));
- s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi");
- }
-
- if (usb_enabled()) {
- sysbus_create_simple("sysbus-ohci", 0x4c000000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_USBH1));
- }
-
- s->pcmcia[0] = pxa2xx_pcmcia_init(address_space, 0x20000000);
- s->pcmcia[1] = pxa2xx_pcmcia_init(address_space, 0x30000000);
-
- sysbus_create_simple(TYPE_PXA2XX_RTC, 0x40900000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_RTCALARM));
-
- s->i2c[0] = pxa2xx_i2c_init(0x40301600,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_I2C), 0xffff);
- s->i2c[1] = pxa2xx_i2c_init(0x40f00100,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_PWRI2C), 0xff);
-
- s->i2s = pxa2xx_i2s_init(address_space, 0x40400000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_I2S),
- qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_I2S),
- qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_I2S));
-
- /* GPIO1 resets the processor */
- /* The handler can be overridden by board-specific code */
- qdev_connect_gpio_out(s->gpio, 1, s->reset);
- return s;
-}
-
-static void pxa2xx_ssp_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- sdc->init = pxa2xx_ssp_init;
- dc->reset = pxa2xx_ssp_reset;
- dc->vmsd = &vmstate_pxa2xx_ssp;
-}
-
-static const TypeInfo pxa2xx_ssp_info = {
- .name = TYPE_PXA2XX_SSP,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PXA2xxSSPState),
- .class_init = pxa2xx_ssp_class_init,
-};
-
-static void pxa2xx_register_types(void)
-{
- type_register_static(&pxa2xx_i2c_slave_info);
- type_register_static(&pxa2xx_ssp_info);
- type_register_static(&pxa2xx_i2c_info);
- type_register_static(&pxa2xx_rtc_sysbus_info);
- type_register_static(&pxa2xx_fir_info);
-}
-
-type_init(pxa2xx_register_types)
diff --git a/qemu/hw/arm/pxa2xx_gpio.c b/qemu/hw/arm/pxa2xx_gpio.c
deleted file mode 100644
index 67e7e7094..000000000
--- a/qemu/hw/arm/pxa2xx_gpio.c
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
- * Intel XScale PXA255/270 GPIO controller emulation.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GPL.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "hw/arm/pxa.h"
-
-#define PXA2XX_GPIO_BANKS 4
-
-#define TYPE_PXA2XX_GPIO "pxa2xx-gpio"
-#define PXA2XX_GPIO(obj) \
- OBJECT_CHECK(PXA2xxGPIOInfo, (obj), TYPE_PXA2XX_GPIO)
-
-typedef struct PXA2xxGPIOInfo PXA2xxGPIOInfo;
-struct PXA2xxGPIOInfo {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- MemoryRegion iomem;
- qemu_irq irq0, irq1, irqX;
- int lines;
- int ncpu;
- ARMCPU *cpu;
-
- /* XXX: GNU C vectors are more suitable */
- uint32_t ilevel[PXA2XX_GPIO_BANKS];
- uint32_t olevel[PXA2XX_GPIO_BANKS];
- uint32_t dir[PXA2XX_GPIO_BANKS];
- uint32_t rising[PXA2XX_GPIO_BANKS];
- uint32_t falling[PXA2XX_GPIO_BANKS];
- uint32_t status[PXA2XX_GPIO_BANKS];
- uint32_t gafr[PXA2XX_GPIO_BANKS * 2];
-
- uint32_t prev_level[PXA2XX_GPIO_BANKS];
- qemu_irq handler[PXA2XX_GPIO_BANKS * 32];
- qemu_irq read_notify;
-};
-
-static struct {
- enum {
- GPIO_NONE,
- GPLR,
- GPSR,
- GPCR,
- GPDR,
- GRER,
- GFER,
- GEDR,
- GAFR_L,
- GAFR_U,
- } reg;
- int bank;
-} pxa2xx_gpio_regs[0x200] = {
- [0 ... 0x1ff] = { GPIO_NONE, 0 },
-#define PXA2XX_REG(reg, a0, a1, a2, a3) \
- [a0] = { reg, 0 }, [a1] = { reg, 1 }, [a2] = { reg, 2 }, [a3] = { reg, 3 },
-
- PXA2XX_REG(GPLR, 0x000, 0x004, 0x008, 0x100)
- PXA2XX_REG(GPSR, 0x018, 0x01c, 0x020, 0x118)
- PXA2XX_REG(GPCR, 0x024, 0x028, 0x02c, 0x124)
- PXA2XX_REG(GPDR, 0x00c, 0x010, 0x014, 0x10c)
- PXA2XX_REG(GRER, 0x030, 0x034, 0x038, 0x130)
- PXA2XX_REG(GFER, 0x03c, 0x040, 0x044, 0x13c)
- PXA2XX_REG(GEDR, 0x048, 0x04c, 0x050, 0x148)
- PXA2XX_REG(GAFR_L, 0x054, 0x05c, 0x064, 0x06c)
- PXA2XX_REG(GAFR_U, 0x058, 0x060, 0x068, 0x070)
-};
-
-static void pxa2xx_gpio_irq_update(PXA2xxGPIOInfo *s)
-{
- if (s->status[0] & (1 << 0))
- qemu_irq_raise(s->irq0);
- else
- qemu_irq_lower(s->irq0);
-
- if (s->status[0] & (1 << 1))
- qemu_irq_raise(s->irq1);
- else
- qemu_irq_lower(s->irq1);
-
- if ((s->status[0] & ~3) | s->status[1] | s->status[2] | s->status[3])
- qemu_irq_raise(s->irqX);
- else
- qemu_irq_lower(s->irqX);
-}
-
-/* Bitmap of pins used as standby and sleep wake-up sources. */
-static const int pxa2xx_gpio_wake[PXA2XX_GPIO_BANKS] = {
- 0x8003fe1b, 0x002001fc, 0xec080000, 0x0012007f,
-};
-
-static void pxa2xx_gpio_set(void *opaque, int line, int level)
-{
- PXA2xxGPIOInfo *s = (PXA2xxGPIOInfo *) opaque;
- CPUState *cpu = CPU(s->cpu);
- int bank;
- uint32_t mask;
-
- if (line >= s->lines) {
- printf("%s: No GPIO pin %i\n", __FUNCTION__, line);
- return;
- }
-
- bank = line >> 5;
- mask = 1U << (line & 31);
-
- if (level) {
- s->status[bank] |= s->rising[bank] & mask &
- ~s->ilevel[bank] & ~s->dir[bank];
- s->ilevel[bank] |= mask;
- } else {
- s->status[bank] |= s->falling[bank] & mask &
- s->ilevel[bank] & ~s->dir[bank];
- s->ilevel[bank] &= ~mask;
- }
-
- if (s->status[bank] & mask)
- pxa2xx_gpio_irq_update(s);
-
- /* Wake-up GPIOs */
- if (cpu->halted && (mask & ~s->dir[bank] & pxa2xx_gpio_wake[bank])) {
- cpu_interrupt(cpu, CPU_INTERRUPT_EXITTB);
- }
-}
-
-static void pxa2xx_gpio_handler_update(PXA2xxGPIOInfo *s) {
- uint32_t level, diff;
- int i, bit, line;
- for (i = 0; i < PXA2XX_GPIO_BANKS; i ++) {
- level = s->olevel[i] & s->dir[i];
-
- for (diff = s->prev_level[i] ^ level; diff; diff ^= 1 << bit) {
- bit = ctz32(diff);
- line = bit + 32 * i;
- qemu_set_irq(s->handler[line], (level >> bit) & 1);
- }
-
- s->prev_level[i] = level;
- }
-}
-
-static uint64_t pxa2xx_gpio_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- PXA2xxGPIOInfo *s = (PXA2xxGPIOInfo *) opaque;
- uint32_t ret;
- int bank;
- if (offset >= 0x200)
- return 0;
-
- bank = pxa2xx_gpio_regs[offset].bank;
- switch (pxa2xx_gpio_regs[offset].reg) {
- case GPDR: /* GPIO Pin-Direction registers */
- return s->dir[bank];
-
- case GPSR: /* GPIO Pin-Output Set registers */
- qemu_log_mask(LOG_GUEST_ERROR,
- "pxa2xx GPIO: read from write only register GPSR\n");
- return 0;
-
- case GPCR: /* GPIO Pin-Output Clear registers */
- qemu_log_mask(LOG_GUEST_ERROR,
- "pxa2xx GPIO: read from write only register GPCR\n");
- return 0;
-
- case GRER: /* GPIO Rising-Edge Detect Enable registers */
- return s->rising[bank];
-
- case GFER: /* GPIO Falling-Edge Detect Enable registers */
- return s->falling[bank];
-
- case GAFR_L: /* GPIO Alternate Function registers */
- return s->gafr[bank * 2];
-
- case GAFR_U: /* GPIO Alternate Function registers */
- return s->gafr[bank * 2 + 1];
-
- case GPLR: /* GPIO Pin-Level registers */
- ret = (s->olevel[bank] & s->dir[bank]) |
- (s->ilevel[bank] & ~s->dir[bank]);
- qemu_irq_raise(s->read_notify);
- return ret;
-
- case GEDR: /* GPIO Edge Detect Status registers */
- return s->status[bank];
-
- default:
- hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
- }
-
- return 0;
-}
-
-static void pxa2xx_gpio_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PXA2xxGPIOInfo *s = (PXA2xxGPIOInfo *) opaque;
- int bank;
- if (offset >= 0x200)
- return;
-
- bank = pxa2xx_gpio_regs[offset].bank;
- switch (pxa2xx_gpio_regs[offset].reg) {
- case GPDR: /* GPIO Pin-Direction registers */
- s->dir[bank] = value;
- pxa2xx_gpio_handler_update(s);
- break;
-
- case GPSR: /* GPIO Pin-Output Set registers */
- s->olevel[bank] |= value;
- pxa2xx_gpio_handler_update(s);
- break;
-
- case GPCR: /* GPIO Pin-Output Clear registers */
- s->olevel[bank] &= ~value;
- pxa2xx_gpio_handler_update(s);
- break;
-
- case GRER: /* GPIO Rising-Edge Detect Enable registers */
- s->rising[bank] = value;
- break;
-
- case GFER: /* GPIO Falling-Edge Detect Enable registers */
- s->falling[bank] = value;
- break;
-
- case GAFR_L: /* GPIO Alternate Function registers */
- s->gafr[bank * 2] = value;
- break;
-
- case GAFR_U: /* GPIO Alternate Function registers */
- s->gafr[bank * 2 + 1] = value;
- break;
-
- case GEDR: /* GPIO Edge Detect Status registers */
- s->status[bank] &= ~value;
- pxa2xx_gpio_irq_update(s);
- break;
-
- default:
- hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
- }
-}
-
-static const MemoryRegionOps pxa_gpio_ops = {
- .read = pxa2xx_gpio_read,
- .write = pxa2xx_gpio_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-DeviceState *pxa2xx_gpio_init(hwaddr base,
- ARMCPU *cpu, DeviceState *pic, int lines)
-{
- CPUState *cs = CPU(cpu);
- DeviceState *dev;
-
- dev = qdev_create(NULL, TYPE_PXA2XX_GPIO);
- qdev_prop_set_int32(dev, "lines", lines);
- qdev_prop_set_int32(dev, "ncpu", cs->cpu_index);
- qdev_init_nofail(dev);
-
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0,
- qdev_get_gpio_in(pic, PXA2XX_PIC_GPIO_0));
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1,
- qdev_get_gpio_in(pic, PXA2XX_PIC_GPIO_1));
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2,
- qdev_get_gpio_in(pic, PXA2XX_PIC_GPIO_X));
-
- return dev;
-}
-
-static int pxa2xx_gpio_initfn(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- PXA2xxGPIOInfo *s = PXA2XX_GPIO(dev);
-
- s->cpu = ARM_CPU(qemu_get_cpu(s->ncpu));
-
- qdev_init_gpio_in(dev, pxa2xx_gpio_set, s->lines);
- qdev_init_gpio_out(dev, s->handler, s->lines);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &pxa_gpio_ops, s, "pxa2xx-gpio", 0x1000);
- sysbus_init_mmio(sbd, &s->iomem);
- sysbus_init_irq(sbd, &s->irq0);
- sysbus_init_irq(sbd, &s->irq1);
- sysbus_init_irq(sbd, &s->irqX);
-
- return 0;
-}
-
-/*
- * Registers a callback to notify on GPLR reads. This normally
- * shouldn't be needed but it is used for the hack on Spitz machines.
- */
-void pxa2xx_gpio_read_notifier(DeviceState *dev, qemu_irq handler)
-{
- PXA2xxGPIOInfo *s = PXA2XX_GPIO(dev);
-
- s->read_notify = handler;
-}
-
-static const VMStateDescription vmstate_pxa2xx_gpio_regs = {
- .name = "pxa2xx-gpio",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(ilevel, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
- VMSTATE_UINT32_ARRAY(olevel, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
- VMSTATE_UINT32_ARRAY(dir, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
- VMSTATE_UINT32_ARRAY(rising, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
- VMSTATE_UINT32_ARRAY(falling, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
- VMSTATE_UINT32_ARRAY(status, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
- VMSTATE_UINT32_ARRAY(gafr, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS * 2),
- VMSTATE_UINT32_ARRAY(prev_level, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
- VMSTATE_END_OF_LIST(),
- },
-};
-
-static Property pxa2xx_gpio_properties[] = {
- DEFINE_PROP_INT32("lines", PXA2xxGPIOInfo, lines, 0),
- DEFINE_PROP_INT32("ncpu", PXA2xxGPIOInfo, ncpu, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pxa2xx_gpio_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = pxa2xx_gpio_initfn;
- dc->desc = "PXA2xx GPIO controller";
- dc->props = pxa2xx_gpio_properties;
- dc->vmsd = &vmstate_pxa2xx_gpio_regs;
-}
-
-static const TypeInfo pxa2xx_gpio_info = {
- .name = TYPE_PXA2XX_GPIO,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PXA2xxGPIOInfo),
- .class_init = pxa2xx_gpio_class_init,
-};
-
-static void pxa2xx_gpio_register_types(void)
-{
- type_register_static(&pxa2xx_gpio_info);
-}
-
-type_init(pxa2xx_gpio_register_types)
diff --git a/qemu/hw/arm/pxa2xx_pic.c b/qemu/hw/arm/pxa2xx_pic.c
deleted file mode 100644
index 7e51532cd..000000000
--- a/qemu/hw/arm/pxa2xx_pic.c
+++ /dev/null
@@ -1,340 +0,0 @@
-/*
- * Intel XScale PXA Programmable Interrupt Controller.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Copyright (c) 2006 Thorsten Zitterell
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GPL.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/hw.h"
-#include "hw/arm/pxa.h"
-#include "hw/sysbus.h"
-
-#define ICIP 0x00 /* Interrupt Controller IRQ Pending register */
-#define ICMR 0x04 /* Interrupt Controller Mask register */
-#define ICLR 0x08 /* Interrupt Controller Level register */
-#define ICFP 0x0c /* Interrupt Controller FIQ Pending register */
-#define ICPR 0x10 /* Interrupt Controller Pending register */
-#define ICCR 0x14 /* Interrupt Controller Control register */
-#define ICHP 0x18 /* Interrupt Controller Highest Priority register */
-#define IPR0 0x1c /* Interrupt Controller Priority register 0 */
-#define IPR31 0x98 /* Interrupt Controller Priority register 31 */
-#define ICIP2 0x9c /* Interrupt Controller IRQ Pending register 2 */
-#define ICMR2 0xa0 /* Interrupt Controller Mask register 2 */
-#define ICLR2 0xa4 /* Interrupt Controller Level register 2 */
-#define ICFP2 0xa8 /* Interrupt Controller FIQ Pending register 2 */
-#define ICPR2 0xac /* Interrupt Controller Pending register 2 */
-#define IPR32 0xb0 /* Interrupt Controller Priority register 32 */
-#define IPR39 0xcc /* Interrupt Controller Priority register 39 */
-
-#define PXA2XX_PIC_SRCS 40
-
-#define TYPE_PXA2XX_PIC "pxa2xx_pic"
-#define PXA2XX_PIC(obj) \
- OBJECT_CHECK(PXA2xxPICState, (obj), TYPE_PXA2XX_PIC)
-
-typedef struct {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- MemoryRegion iomem;
- ARMCPU *cpu;
- uint32_t int_enabled[2];
- uint32_t int_pending[2];
- uint32_t is_fiq[2];
- uint32_t int_idle;
- uint32_t priority[PXA2XX_PIC_SRCS];
-} PXA2xxPICState;
-
-static void pxa2xx_pic_update(void *opaque)
-{
- uint32_t mask[2];
- PXA2xxPICState *s = (PXA2xxPICState *) opaque;
- CPUState *cpu = CPU(s->cpu);
-
- if (cpu->halted) {
- mask[0] = s->int_pending[0] & (s->int_enabled[0] | s->int_idle);
- mask[1] = s->int_pending[1] & (s->int_enabled[1] | s->int_idle);
- if (mask[0] || mask[1]) {
- cpu_interrupt(cpu, CPU_INTERRUPT_EXITTB);
- }
- }
-
- mask[0] = s->int_pending[0] & s->int_enabled[0];
- mask[1] = s->int_pending[1] & s->int_enabled[1];
-
- if ((mask[0] & s->is_fiq[0]) || (mask[1] & s->is_fiq[1])) {
- cpu_interrupt(cpu, CPU_INTERRUPT_FIQ);
- } else {
- cpu_reset_interrupt(cpu, CPU_INTERRUPT_FIQ);
- }
-
- if ((mask[0] & ~s->is_fiq[0]) || (mask[1] & ~s->is_fiq[1])) {
- cpu_interrupt(cpu, CPU_INTERRUPT_HARD);
- } else {
- cpu_reset_interrupt(cpu, CPU_INTERRUPT_HARD);
- }
-}
-
-/* Note: Here level means state of the signal on a pin, not
- * IRQ/FIQ distinction as in PXA Developer Manual. */
-static void pxa2xx_pic_set_irq(void *opaque, int irq, int level)
-{
- PXA2xxPICState *s = (PXA2xxPICState *) opaque;
- int int_set = (irq >= 32);
- irq &= 31;
-
- if (level)
- s->int_pending[int_set] |= 1 << irq;
- else
- s->int_pending[int_set] &= ~(1 << irq);
-
- pxa2xx_pic_update(opaque);
-}
-
-static inline uint32_t pxa2xx_pic_highest(PXA2xxPICState *s) {
- int i, int_set, irq;
- uint32_t bit, mask[2];
- uint32_t ichp = 0x003f003f; /* Both IDs invalid */
-
- mask[0] = s->int_pending[0] & s->int_enabled[0];
- mask[1] = s->int_pending[1] & s->int_enabled[1];
-
- for (i = PXA2XX_PIC_SRCS - 1; i >= 0; i --) {
- irq = s->priority[i] & 0x3f;
- if ((s->priority[i] & (1U << 31)) && irq < PXA2XX_PIC_SRCS) {
- /* Source peripheral ID is valid. */
- bit = 1 << (irq & 31);
- int_set = (irq >= 32);
-
- if (mask[int_set] & bit & s->is_fiq[int_set]) {
- /* FIQ asserted */
- ichp &= 0xffff0000;
- ichp |= (1 << 15) | irq;
- }
-
- if (mask[int_set] & bit & ~s->is_fiq[int_set]) {
- /* IRQ asserted */
- ichp &= 0x0000ffff;
- ichp |= (1U << 31) | (irq << 16);
- }
- }
- }
-
- return ichp;
-}
-
-static uint64_t pxa2xx_pic_mem_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- PXA2xxPICState *s = (PXA2xxPICState *) opaque;
-
- switch (offset) {
- case ICIP: /* IRQ Pending register */
- return s->int_pending[0] & ~s->is_fiq[0] & s->int_enabled[0];
- case ICIP2: /* IRQ Pending register 2 */
- return s->int_pending[1] & ~s->is_fiq[1] & s->int_enabled[1];
- case ICMR: /* Mask register */
- return s->int_enabled[0];
- case ICMR2: /* Mask register 2 */
- return s->int_enabled[1];
- case ICLR: /* Level register */
- return s->is_fiq[0];
- case ICLR2: /* Level register 2 */
- return s->is_fiq[1];
- case ICCR: /* Idle mask */
- return (s->int_idle == 0);
- case ICFP: /* FIQ Pending register */
- return s->int_pending[0] & s->is_fiq[0] & s->int_enabled[0];
- case ICFP2: /* FIQ Pending register 2 */
- return s->int_pending[1] & s->is_fiq[1] & s->int_enabled[1];
- case ICPR: /* Pending register */
- return s->int_pending[0];
- case ICPR2: /* Pending register 2 */
- return s->int_pending[1];
- case IPR0 ... IPR31:
- return s->priority[0 + ((offset - IPR0 ) >> 2)];
- case IPR32 ... IPR39:
- return s->priority[32 + ((offset - IPR32) >> 2)];
- case ICHP: /* Highest Priority register */
- return pxa2xx_pic_highest(s);
- default:
- printf("%s: Bad register offset " REG_FMT "\n", __FUNCTION__, offset);
- return 0;
- }
-}
-
-static void pxa2xx_pic_mem_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PXA2xxPICState *s = (PXA2xxPICState *) opaque;
-
- switch (offset) {
- case ICMR: /* Mask register */
- s->int_enabled[0] = value;
- break;
- case ICMR2: /* Mask register 2 */
- s->int_enabled[1] = value;
- break;
- case ICLR: /* Level register */
- s->is_fiq[0] = value;
- break;
- case ICLR2: /* Level register 2 */
- s->is_fiq[1] = value;
- break;
- case ICCR: /* Idle mask */
- s->int_idle = (value & 1) ? 0 : ~0;
- break;
- case IPR0 ... IPR31:
- s->priority[0 + ((offset - IPR0 ) >> 2)] = value & 0x8000003f;
- break;
- case IPR32 ... IPR39:
- s->priority[32 + ((offset - IPR32) >> 2)] = value & 0x8000003f;
- break;
- default:
- printf("%s: Bad register offset " REG_FMT "\n", __FUNCTION__, offset);
- return;
- }
- pxa2xx_pic_update(opaque);
-}
-
-/* Interrupt Controller Coprocessor Space Register Mapping */
-static const int pxa2xx_cp_reg_map[0x10] = {
- [0x0 ... 0xf] = -1,
- [0x0] = ICIP,
- [0x1] = ICMR,
- [0x2] = ICLR,
- [0x3] = ICFP,
- [0x4] = ICPR,
- [0x5] = ICHP,
- [0x6] = ICIP2,
- [0x7] = ICMR2,
- [0x8] = ICLR2,
- [0x9] = ICFP2,
- [0xa] = ICPR2,
-};
-
-static uint64_t pxa2xx_pic_cp_read(CPUARMState *env, const ARMCPRegInfo *ri)
-{
- int offset = pxa2xx_cp_reg_map[ri->crn];
- return pxa2xx_pic_mem_read(ri->opaque, offset, 4);
-}
-
-static void pxa2xx_pic_cp_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- int offset = pxa2xx_cp_reg_map[ri->crn];
- pxa2xx_pic_mem_write(ri->opaque, offset, value, 4);
-}
-
-#define REGINFO_FOR_PIC_CP(NAME, CRN) \
- { .name = NAME, .cp = 6, .crn = CRN, .crm = 0, .opc1 = 0, .opc2 = 0, \
- .access = PL1_RW, .type = ARM_CP_IO, \
- .readfn = pxa2xx_pic_cp_read, .writefn = pxa2xx_pic_cp_write }
-
-static const ARMCPRegInfo pxa_pic_cp_reginfo[] = {
- REGINFO_FOR_PIC_CP("ICIP", 0),
- REGINFO_FOR_PIC_CP("ICMR", 1),
- REGINFO_FOR_PIC_CP("ICLR", 2),
- REGINFO_FOR_PIC_CP("ICFP", 3),
- REGINFO_FOR_PIC_CP("ICPR", 4),
- REGINFO_FOR_PIC_CP("ICHP", 5),
- REGINFO_FOR_PIC_CP("ICIP2", 6),
- REGINFO_FOR_PIC_CP("ICMR2", 7),
- REGINFO_FOR_PIC_CP("ICLR2", 8),
- REGINFO_FOR_PIC_CP("ICFP2", 9),
- REGINFO_FOR_PIC_CP("ICPR2", 0xa),
- REGINFO_SENTINEL
-};
-
-static const MemoryRegionOps pxa2xx_pic_ops = {
- .read = pxa2xx_pic_mem_read,
- .write = pxa2xx_pic_mem_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int pxa2xx_pic_post_load(void *opaque, int version_id)
-{
- pxa2xx_pic_update(opaque);
- return 0;
-}
-
-DeviceState *pxa2xx_pic_init(hwaddr base, ARMCPU *cpu)
-{
- DeviceState *dev = qdev_create(NULL, TYPE_PXA2XX_PIC);
- PXA2xxPICState *s = PXA2XX_PIC(dev);
-
- s->cpu = cpu;
-
- s->int_pending[0] = 0;
- s->int_pending[1] = 0;
- s->int_enabled[0] = 0;
- s->int_enabled[1] = 0;
- s->is_fiq[0] = 0;
- s->is_fiq[1] = 0;
-
- qdev_init_nofail(dev);
-
- qdev_init_gpio_in(dev, pxa2xx_pic_set_irq, PXA2XX_PIC_SRCS);
-
- /* Enable IC memory-mapped registers access. */
- memory_region_init_io(&s->iomem, OBJECT(s), &pxa2xx_pic_ops, s,
- "pxa2xx-pic", 0x00100000);
- sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
-
- /* Enable IC coprocessor access. */
- define_arm_cp_regs_with_opaque(cpu, pxa_pic_cp_reginfo, s);
-
- return dev;
-}
-
-static VMStateDescription vmstate_pxa2xx_pic_regs = {
- .name = "pxa2xx_pic",
- .version_id = 0,
- .minimum_version_id = 0,
- .post_load = pxa2xx_pic_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(int_enabled, PXA2xxPICState, 2),
- VMSTATE_UINT32_ARRAY(int_pending, PXA2xxPICState, 2),
- VMSTATE_UINT32_ARRAY(is_fiq, PXA2xxPICState, 2),
- VMSTATE_UINT32(int_idle, PXA2xxPICState),
- VMSTATE_UINT32_ARRAY(priority, PXA2xxPICState, PXA2XX_PIC_SRCS),
- VMSTATE_END_OF_LIST(),
- },
-};
-
-static int pxa2xx_pic_initfn(SysBusDevice *dev)
-{
- return 0;
-}
-
-static void pxa2xx_pic_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = pxa2xx_pic_initfn;
- dc->desc = "PXA2xx PIC";
- dc->vmsd = &vmstate_pxa2xx_pic_regs;
-}
-
-static const TypeInfo pxa2xx_pic_info = {
- .name = TYPE_PXA2XX_PIC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PXA2xxPICState),
- .class_init = pxa2xx_pic_class_init,
-};
-
-static void pxa2xx_pic_register_types(void)
-{
- type_register_static(&pxa2xx_pic_info);
-}
-
-type_init(pxa2xx_pic_register_types)
diff --git a/qemu/hw/arm/raspi.c b/qemu/hw/arm/raspi.c
deleted file mode 100644
index 2b295f14c..000000000
--- a/qemu/hw/arm/raspi.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Raspberry Pi emulation (c) 2012 Gregory Estrade
- * Upstreaming code cleanup [including bcm2835_*] (c) 2013 Jan Petrous
- *
- * Rasperry Pi 2 emulation Copyright (c) 2015, Microsoft
- * Written by Andrew Baumann
- *
- * This code is licensed under the GNU GPLv2 and later.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/arm/bcm2836.h"
-#include "qemu/error-report.h"
-#include "hw/boards.h"
-#include "hw/loader.h"
-#include "hw/arm/arm.h"
-#include "sysemu/sysemu.h"
-
-#define SMPBOOT_ADDR 0x300 /* this should leave enough space for ATAGS */
-#define MVBAR_ADDR 0x400 /* secure vectors */
-#define BOARDSETUP_ADDR (MVBAR_ADDR + 0x20) /* board setup code */
-#define FIRMWARE_ADDR 0x8000 /* Pi loads kernel.img here by default */
-
-/* Table of Linux board IDs for different Pi versions */
-static const int raspi_boardid[] = {[1] = 0xc42, [2] = 0xc43};
-
-typedef struct RasPiState {
- BCM2836State soc;
- MemoryRegion ram;
-} RasPiState;
-
-static void write_smpboot(ARMCPU *cpu, const struct arm_boot_info *info)
-{
- static const uint32_t smpboot[] = {
- 0xe1a0e00f, /* mov lr, pc */
- 0xe3a0fe00 + (BOARDSETUP_ADDR >> 4), /* mov pc, BOARDSETUP_ADDR */
- 0xee100fb0, /* mrc p15, 0, r0, c0, c0, 5;get core ID */
- 0xe7e10050, /* ubfx r0, r0, #0, #2 ;extract LSB */
- 0xe59f5014, /* ldr r5, =0x400000CC ;load mbox base */
- 0xe320f001, /* 1: yield */
- 0xe7953200, /* ldr r3, [r5, r0, lsl #4] ;read mbox for our core*/
- 0xe3530000, /* cmp r3, #0 ;spin while zero */
- 0x0afffffb, /* beq 1b */
- 0xe7853200, /* str r3, [r5, r0, lsl #4] ;clear mbox */
- 0xe12fff13, /* bx r3 ;jump to target */
- 0x400000cc, /* (constant: mailbox 3 read/clear base) */
- };
-
- /* check that we don't overrun board setup vectors */
- QEMU_BUILD_BUG_ON(SMPBOOT_ADDR + sizeof(smpboot) > MVBAR_ADDR);
- /* check that board setup address is correctly relocated */
- QEMU_BUILD_BUG_ON((BOARDSETUP_ADDR & 0xf) != 0
- || (BOARDSETUP_ADDR >> 4) >= 0x100);
-
- rom_add_blob_fixed("raspi_smpboot", smpboot, sizeof(smpboot),
- info->smp_loader_start);
-}
-
-static void write_board_setup(ARMCPU *cpu, const struct arm_boot_info *info)
-{
- arm_write_secure_board_setup_dummy_smc(cpu, info, MVBAR_ADDR);
-}
-
-static void reset_secondary(ARMCPU *cpu, const struct arm_boot_info *info)
-{
- CPUState *cs = CPU(cpu);
- cpu_set_pc(cs, info->smp_loader_start);
-}
-
-static void setup_boot(MachineState *machine, int version, size_t ram_size)
-{
- static struct arm_boot_info binfo;
- int r;
-
- binfo.board_id = raspi_boardid[version];
- binfo.ram_size = ram_size;
- binfo.nb_cpus = smp_cpus;
- binfo.board_setup_addr = BOARDSETUP_ADDR;
- binfo.write_board_setup = write_board_setup;
- binfo.secure_board_setup = true;
- binfo.secure_boot = true;
-
- /* Pi2 requires SMP setup */
- if (version == 2) {
- binfo.smp_loader_start = SMPBOOT_ADDR;
- binfo.write_secondary_boot = write_smpboot;
- binfo.secondary_cpu_reset_hook = reset_secondary;
- }
-
- /* If the user specified a "firmware" image (e.g. UEFI), we bypass
- * the normal Linux boot process
- */
- if (machine->firmware) {
- /* load the firmware image (typically kernel.img) */
- r = load_image_targphys(machine->firmware, FIRMWARE_ADDR,
- ram_size - FIRMWARE_ADDR);
- if (r < 0) {
- error_report("Failed to load firmware from %s", machine->firmware);
- exit(1);
- }
-
- binfo.entry = FIRMWARE_ADDR;
- binfo.firmware_loaded = true;
- } else {
- binfo.kernel_filename = machine->kernel_filename;
- binfo.kernel_cmdline = machine->kernel_cmdline;
- binfo.initrd_filename = machine->initrd_filename;
- }
-
- arm_load_kernel(ARM_CPU(first_cpu), &binfo);
-}
-
-static void raspi2_init(MachineState *machine)
-{
- RasPiState *s = g_new0(RasPiState, 1);
- uint32_t vcram_size;
- DriveInfo *di;
- BlockBackend *blk;
- BusState *bus;
- DeviceState *carddev;
-
- object_initialize(&s->soc, sizeof(s->soc), TYPE_BCM2836);
- object_property_add_child(OBJECT(machine), "soc", OBJECT(&s->soc),
- &error_abort);
-
- /* Allocate and map RAM */
- memory_region_allocate_system_memory(&s->ram, OBJECT(machine), "ram",
- machine->ram_size);
- /* FIXME: Remove when we have custom CPU address space support */
- memory_region_add_subregion_overlap(get_system_memory(), 0, &s->ram, 0);
-
- /* Setup the SOC */
- object_property_add_const_link(OBJECT(&s->soc), "ram", OBJECT(&s->ram),
- &error_abort);
- object_property_set_int(OBJECT(&s->soc), smp_cpus, "enabled-cpus",
- &error_abort);
- object_property_set_int(OBJECT(&s->soc), 0xa21041, "board-rev",
- &error_abort);
- object_property_set_bool(OBJECT(&s->soc), true, "realized", &error_abort);
-
- /* Create and plug in the SD cards */
- di = drive_get_next(IF_SD);
- blk = di ? blk_by_legacy_dinfo(di) : NULL;
- bus = qdev_get_child_bus(DEVICE(&s->soc), "sd-bus");
- if (bus == NULL) {
- error_report("No SD bus found in SOC object");
- exit(1);
- }
- carddev = qdev_create(bus, TYPE_SD_CARD);
- qdev_prop_set_drive(carddev, "drive", blk, &error_fatal);
- object_property_set_bool(OBJECT(carddev), true, "realized", &error_fatal);
-
- vcram_size = object_property_get_int(OBJECT(&s->soc), "vcram-size",
- &error_abort);
- setup_boot(machine, 2, machine->ram_size - vcram_size);
-}
-
-static void raspi2_machine_init(MachineClass *mc)
-{
- mc->desc = "Raspberry Pi 2";
- mc->init = raspi2_init;
- mc->block_default_type = IF_SD;
- mc->no_parallel = 1;
- mc->no_floppy = 1;
- mc->no_cdrom = 1;
- mc->max_cpus = BCM2836_NCPUS;
- mc->default_ram_size = 1024 * 1024 * 1024;
-};
-DEFINE_MACHINE("raspi2", raspi2_machine_init)
diff --git a/qemu/hw/arm/realview.c b/qemu/hw/arm/realview.c
deleted file mode 100644
index 3222b360e..000000000
--- a/qemu/hw/arm/realview.c
+++ /dev/null
@@ -1,463 +0,0 @@
-/*
- * ARM RealView Baseboard System emulation.
- *
- * Copyright (c) 2006-2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/sysbus.h"
-#include "hw/arm/arm.h"
-#include "hw/arm/primecell.h"
-#include "hw/devices.h"
-#include "hw/pci/pci.h"
-#include "net/net.h"
-#include "sysemu/sysemu.h"
-#include "hw/boards.h"
-#include "hw/i2c/i2c.h"
-#include "sysemu/block-backend.h"
-#include "exec/address-spaces.h"
-#include "qemu/error-report.h"
-
-#define SMP_BOOT_ADDR 0xe0000000
-#define SMP_BOOTREG_ADDR 0x10000030
-
-/* Board init. */
-
-static struct arm_boot_info realview_binfo = {
- .smp_loader_start = SMP_BOOT_ADDR,
- .smp_bootreg_addr = SMP_BOOTREG_ADDR,
-};
-
-/* The following two lists must be consistent. */
-enum realview_board_type {
- BOARD_EB,
- BOARD_EB_MPCORE,
- BOARD_PB_A8,
- BOARD_PBX_A9,
-};
-
-static const int realview_board_id[] = {
- 0x33b,
- 0x33b,
- 0x769,
- 0x76d
-};
-
-static void realview_init(MachineState *machine,
- enum realview_board_type board_type)
-{
- ARMCPU *cpu = NULL;
- CPUARMState *env;
- ObjectClass *cpu_oc;
- MemoryRegion *sysmem = get_system_memory();
- MemoryRegion *ram_lo;
- MemoryRegion *ram_hi = g_new(MemoryRegion, 1);
- MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
- MemoryRegion *ram_hack = g_new(MemoryRegion, 1);
- DeviceState *dev, *sysctl, *gpio2, *pl041;
- SysBusDevice *busdev;
- qemu_irq pic[64];
- qemu_irq mmc_irq[2];
- PCIBus *pci_bus = NULL;
- NICInfo *nd;
- I2CBus *i2c;
- int n;
- int done_nic = 0;
- qemu_irq cpu_irq[4];
- int is_mpcore = 0;
- int is_pb = 0;
- uint32_t proc_id = 0;
- uint32_t sys_id;
- ram_addr_t low_ram_size;
- ram_addr_t ram_size = machine->ram_size;
- hwaddr periphbase = 0;
-
- switch (board_type) {
- case BOARD_EB:
- break;
- case BOARD_EB_MPCORE:
- is_mpcore = 1;
- periphbase = 0x10100000;
- break;
- case BOARD_PB_A8:
- is_pb = 1;
- break;
- case BOARD_PBX_A9:
- is_mpcore = 1;
- is_pb = 1;
- periphbase = 0x1f000000;
- break;
- }
-
- cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, machine->cpu_model);
- if (!cpu_oc) {
- fprintf(stderr, "Unable to find CPU definition\n");
- exit(1);
- }
-
- for (n = 0; n < smp_cpus; n++) {
- Object *cpuobj = object_new(object_class_get_name(cpu_oc));
-
- /* By default A9,A15 and ARM1176 CPUs have EL3 enabled. This board
- * does not currently support EL3 so the CPU EL3 property is disabled
- * before realization.
- */
- if (object_property_find(cpuobj, "has_el3", NULL)) {
- object_property_set_bool(cpuobj, false, "has_el3", &error_fatal);
- }
-
- if (is_pb && is_mpcore) {
- object_property_set_int(cpuobj, periphbase, "reset-cbar",
- &error_fatal);
- }
-
- object_property_set_bool(cpuobj, true, "realized", &error_fatal);
-
- cpu_irq[n] = qdev_get_gpio_in(DEVICE(cpuobj), ARM_CPU_IRQ);
- }
- cpu = ARM_CPU(first_cpu);
- env = &cpu->env;
- if (arm_feature(env, ARM_FEATURE_V7)) {
- if (is_mpcore) {
- proc_id = 0x0c000000;
- } else {
- proc_id = 0x0e000000;
- }
- } else if (arm_feature(env, ARM_FEATURE_V6K)) {
- proc_id = 0x06000000;
- } else if (arm_feature(env, ARM_FEATURE_V6)) {
- proc_id = 0x04000000;
- } else {
- proc_id = 0x02000000;
- }
-
- if (is_pb && ram_size > 0x20000000) {
- /* Core tile RAM. */
- ram_lo = g_new(MemoryRegion, 1);
- low_ram_size = ram_size - 0x20000000;
- ram_size = 0x20000000;
- memory_region_init_ram(ram_lo, NULL, "realview.lowmem", low_ram_size,
- &error_fatal);
- vmstate_register_ram_global(ram_lo);
- memory_region_add_subregion(sysmem, 0x20000000, ram_lo);
- }
-
- memory_region_init_ram(ram_hi, NULL, "realview.highmem", ram_size,
- &error_fatal);
- vmstate_register_ram_global(ram_hi);
- low_ram_size = ram_size;
- if (low_ram_size > 0x10000000)
- low_ram_size = 0x10000000;
- /* SDRAM at address zero. */
- memory_region_init_alias(ram_alias, NULL, "realview.alias",
- ram_hi, 0, low_ram_size);
- memory_region_add_subregion(sysmem, 0, ram_alias);
- if (is_pb) {
- /* And again at a high address. */
- memory_region_add_subregion(sysmem, 0x70000000, ram_hi);
- } else {
- ram_size = low_ram_size;
- }
-
- sys_id = is_pb ? 0x01780500 : 0xc1400400;
- sysctl = qdev_create(NULL, "realview_sysctl");
- qdev_prop_set_uint32(sysctl, "sys_id", sys_id);
- qdev_prop_set_uint32(sysctl, "proc_id", proc_id);
- qdev_init_nofail(sysctl);
- sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, 0x10000000);
-
- if (is_mpcore) {
- dev = qdev_create(NULL, is_pb ? "a9mpcore_priv": "realview_mpcore");
- qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
- qdev_init_nofail(dev);
- busdev = SYS_BUS_DEVICE(dev);
- sysbus_mmio_map(busdev, 0, periphbase);
- for (n = 0; n < smp_cpus; n++) {
- sysbus_connect_irq(busdev, n, cpu_irq[n]);
- }
- sysbus_create_varargs("l2x0", periphbase + 0x2000, NULL);
- /* Both A9 and 11MPCore put the GIC CPU i/f at base + 0x100 */
- realview_binfo.gic_cpu_if_addr = periphbase + 0x100;
- } else {
- uint32_t gic_addr = is_pb ? 0x1e000000 : 0x10040000;
- /* For now just create the nIRQ GIC, and ignore the others. */
- dev = sysbus_create_simple("realview_gic", gic_addr, cpu_irq[0]);
- }
- for (n = 0; n < 64; n++) {
- pic[n] = qdev_get_gpio_in(dev, n);
- }
-
- pl041 = qdev_create(NULL, "pl041");
- qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512);
- qdev_init_nofail(pl041);
- sysbus_mmio_map(SYS_BUS_DEVICE(pl041), 0, 0x10004000);
- sysbus_connect_irq(SYS_BUS_DEVICE(pl041), 0, pic[19]);
-
- sysbus_create_simple("pl050_keyboard", 0x10006000, pic[20]);
- sysbus_create_simple("pl050_mouse", 0x10007000, pic[21]);
-
- sysbus_create_simple("pl011", 0x10009000, pic[12]);
- sysbus_create_simple("pl011", 0x1000a000, pic[13]);
- sysbus_create_simple("pl011", 0x1000b000, pic[14]);
- sysbus_create_simple("pl011", 0x1000c000, pic[15]);
-
- /* DMA controller is optional, apparently. */
- sysbus_create_simple("pl081", 0x10030000, pic[24]);
-
- sysbus_create_simple("sp804", 0x10011000, pic[4]);
- sysbus_create_simple("sp804", 0x10012000, pic[5]);
-
- sysbus_create_simple("pl061", 0x10013000, pic[6]);
- sysbus_create_simple("pl061", 0x10014000, pic[7]);
- gpio2 = sysbus_create_simple("pl061", 0x10015000, pic[8]);
-
- sysbus_create_simple("pl111", 0x10020000, pic[23]);
-
- dev = sysbus_create_varargs("pl181", 0x10005000, pic[17], pic[18], NULL);
- /* Wire up MMC card detect and read-only signals. These have
- * to go to both the PL061 GPIO and the sysctl register.
- * Note that the PL181 orders these lines (readonly,inserted)
- * and the PL061 has them the other way about. Also the card
- * detect line is inverted.
- */
- mmc_irq[0] = qemu_irq_split(
- qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_WPROT),
- qdev_get_gpio_in(gpio2, 1));
- mmc_irq[1] = qemu_irq_split(
- qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_CARDIN),
- qemu_irq_invert(qdev_get_gpio_in(gpio2, 0)));
- qdev_connect_gpio_out(dev, 0, mmc_irq[0]);
- qdev_connect_gpio_out(dev, 1, mmc_irq[1]);
-
- sysbus_create_simple("pl031", 0x10017000, pic[10]);
-
- if (!is_pb) {
- dev = qdev_create(NULL, "realview_pci");
- busdev = SYS_BUS_DEVICE(dev);
- qdev_init_nofail(dev);
- sysbus_mmio_map(busdev, 0, 0x10019000); /* PCI controller registers */
- sysbus_mmio_map(busdev, 1, 0x60000000); /* PCI self-config */
- sysbus_mmio_map(busdev, 2, 0x61000000); /* PCI config */
- sysbus_mmio_map(busdev, 3, 0x62000000); /* PCI I/O */
- sysbus_mmio_map(busdev, 4, 0x63000000); /* PCI memory window 1 */
- sysbus_mmio_map(busdev, 5, 0x64000000); /* PCI memory window 2 */
- sysbus_mmio_map(busdev, 6, 0x68000000); /* PCI memory window 3 */
- sysbus_connect_irq(busdev, 0, pic[48]);
- sysbus_connect_irq(busdev, 1, pic[49]);
- sysbus_connect_irq(busdev, 2, pic[50]);
- sysbus_connect_irq(busdev, 3, pic[51]);
- pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci");
- if (usb_enabled()) {
- pci_create_simple(pci_bus, -1, "pci-ohci");
- }
- n = drive_get_max_bus(IF_SCSI);
- while (n >= 0) {
- pci_create_simple(pci_bus, -1, "lsi53c895a");
- n--;
- }
- }
- for(n = 0; n < nb_nics; n++) {
- nd = &nd_table[n];
-
- if (!done_nic && (!nd->model ||
- strcmp(nd->model, is_pb ? "lan9118" : "smc91c111") == 0)) {
- if (is_pb) {
- lan9118_init(nd, 0x4e000000, pic[28]);
- } else {
- smc91c111_init(nd, 0x4e000000, pic[28]);
- }
- done_nic = 1;
- } else {
- if (pci_bus) {
- pci_nic_init_nofail(nd, pci_bus, "rtl8139", NULL);
- }
- }
- }
-
- dev = sysbus_create_simple("versatile_i2c", 0x10002000, NULL);
- i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c");
- i2c_create_slave(i2c, "ds1338", 0x68);
-
- /* Memory map for RealView Emulation Baseboard: */
- /* 0x10000000 System registers. */
- /* 0x10001000 System controller. */
- /* 0x10002000 Two-Wire Serial Bus. */
- /* 0x10003000 Reserved. */
- /* 0x10004000 AACI. */
- /* 0x10005000 MCI. */
- /* 0x10006000 KMI0. */
- /* 0x10007000 KMI1. */
- /* 0x10008000 Character LCD. (EB) */
- /* 0x10009000 UART0. */
- /* 0x1000a000 UART1. */
- /* 0x1000b000 UART2. */
- /* 0x1000c000 UART3. */
- /* 0x1000d000 SSPI. */
- /* 0x1000e000 SCI. */
- /* 0x1000f000 Reserved. */
- /* 0x10010000 Watchdog. */
- /* 0x10011000 Timer 0+1. */
- /* 0x10012000 Timer 2+3. */
- /* 0x10013000 GPIO 0. */
- /* 0x10014000 GPIO 1. */
- /* 0x10015000 GPIO 2. */
- /* 0x10002000 Two-Wire Serial Bus - DVI. (PB) */
- /* 0x10017000 RTC. */
- /* 0x10018000 DMC. */
- /* 0x10019000 PCI controller config. */
- /* 0x10020000 CLCD. */
- /* 0x10030000 DMA Controller. */
- /* 0x10040000 GIC1. (EB) */
- /* 0x10050000 GIC2. (EB) */
- /* 0x10060000 GIC3. (EB) */
- /* 0x10070000 GIC4. (EB) */
- /* 0x10080000 SMC. */
- /* 0x1e000000 GIC1. (PB) */
- /* 0x1e001000 GIC2. (PB) */
- /* 0x1e002000 GIC3. (PB) */
- /* 0x1e003000 GIC4. (PB) */
- /* 0x40000000 NOR flash. */
- /* 0x44000000 DoC flash. */
- /* 0x48000000 SRAM. */
- /* 0x4c000000 Configuration flash. */
- /* 0x4e000000 Ethernet. */
- /* 0x4f000000 USB. */
- /* 0x50000000 PISMO. */
- /* 0x54000000 PISMO. */
- /* 0x58000000 PISMO. */
- /* 0x5c000000 PISMO. */
- /* 0x60000000 PCI. */
- /* 0x60000000 PCI Self Config. */
- /* 0x61000000 PCI Config. */
- /* 0x62000000 PCI IO. */
- /* 0x63000000 PCI mem 0. */
- /* 0x64000000 PCI mem 1. */
- /* 0x68000000 PCI mem 2. */
-
- /* ??? Hack to map an additional page of ram for the secondary CPU
- startup code. I guess this works on real hardware because the
- BootROM happens to be in ROM/flash or in memory that isn't clobbered
- until after Linux boots the secondary CPUs. */
- memory_region_init_ram(ram_hack, NULL, "realview.hack", 0x1000,
- &error_fatal);
- vmstate_register_ram_global(ram_hack);
- memory_region_add_subregion(sysmem, SMP_BOOT_ADDR, ram_hack);
-
- realview_binfo.ram_size = ram_size;
- realview_binfo.kernel_filename = machine->kernel_filename;
- realview_binfo.kernel_cmdline = machine->kernel_cmdline;
- realview_binfo.initrd_filename = machine->initrd_filename;
- realview_binfo.nb_cpus = smp_cpus;
- realview_binfo.board_id = realview_board_id[board_type];
- realview_binfo.loader_start = (board_type == BOARD_PB_A8 ? 0x70000000 : 0);
- arm_load_kernel(ARM_CPU(first_cpu), &realview_binfo);
-}
-
-static void realview_eb_init(MachineState *machine)
-{
- if (!machine->cpu_model) {
- machine->cpu_model = "arm926";
- }
- realview_init(machine, BOARD_EB);
-}
-
-static void realview_eb_mpcore_init(MachineState *machine)
-{
- if (!machine->cpu_model) {
- machine->cpu_model = "arm11mpcore";
- }
- realview_init(machine, BOARD_EB_MPCORE);
-}
-
-static void realview_pb_a8_init(MachineState *machine)
-{
- if (!machine->cpu_model) {
- machine->cpu_model = "cortex-a8";
- }
- realview_init(machine, BOARD_PB_A8);
-}
-
-static void realview_pbx_a9_init(MachineState *machine)
-{
- if (!machine->cpu_model) {
- machine->cpu_model = "cortex-a9";
- }
- realview_init(machine, BOARD_PBX_A9);
-}
-
-static void realview_eb_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "ARM RealView Emulation Baseboard (ARM926EJ-S)";
- mc->init = realview_eb_init;
- mc->block_default_type = IF_SCSI;
-}
-
-static const TypeInfo realview_eb_type = {
- .name = MACHINE_TYPE_NAME("realview-eb"),
- .parent = TYPE_MACHINE,
- .class_init = realview_eb_class_init,
-};
-
-static void realview_eb_mpcore_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "ARM RealView Emulation Baseboard (ARM11MPCore)";
- mc->init = realview_eb_mpcore_init;
- mc->block_default_type = IF_SCSI;
- mc->max_cpus = 4;
-}
-
-static const TypeInfo realview_eb_mpcore_type = {
- .name = MACHINE_TYPE_NAME("realview-eb-mpcore"),
- .parent = TYPE_MACHINE,
- .class_init = realview_eb_mpcore_class_init,
-};
-
-static void realview_pb_a8_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "ARM RealView Platform Baseboard for Cortex-A8";
- mc->init = realview_pb_a8_init;
-}
-
-static const TypeInfo realview_pb_a8_type = {
- .name = MACHINE_TYPE_NAME("realview-pb-a8"),
- .parent = TYPE_MACHINE,
- .class_init = realview_pb_a8_class_init,
-};
-
-static void realview_pbx_a9_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "ARM RealView Platform Baseboard Explore for Cortex-A9";
- mc->init = realview_pbx_a9_init;
- mc->block_default_type = IF_SCSI;
- mc->max_cpus = 4;
-}
-
-static const TypeInfo realview_pbx_a9_type = {
- .name = MACHINE_TYPE_NAME("realview-pbx-a9"),
- .parent = TYPE_MACHINE,
- .class_init = realview_pbx_a9_class_init,
-};
-
-static void realview_machine_init(void)
-{
- type_register_static(&realview_eb_type);
- type_register_static(&realview_eb_mpcore_type);
- type_register_static(&realview_pb_a8_type);
- type_register_static(&realview_pbx_a9_type);
-}
-
-type_init(realview_machine_init)
diff --git a/qemu/hw/arm/spitz.c b/qemu/hw/arm/spitz.c
deleted file mode 100644
index bf61d63b5..000000000
--- a/qemu/hw/arm/spitz.c
+++ /dev/null
@@ -1,1178 +0,0 @@
-/*
- * PXA270-based Clamshell PDA platforms.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/hw.h"
-#include "hw/arm/pxa.h"
-#include "hw/arm/arm.h"
-#include "sysemu/sysemu.h"
-#include "hw/pcmcia.h"
-#include "hw/i2c/i2c.h"
-#include "hw/ssi/ssi.h"
-#include "hw/block/flash.h"
-#include "qemu/timer.h"
-#include "hw/devices.h"
-#include "hw/arm/sharpsl.h"
-#include "ui/console.h"
-#include "audio/audio.h"
-#include "hw/boards.h"
-#include "sysemu/block-backend.h"
-#include "hw/sysbus.h"
-#include "exec/address-spaces.h"
-
-#undef REG_FMT
-#define REG_FMT "0x%02lx"
-
-/* Spitz Flash */
-#define FLASH_BASE 0x0c000000
-#define FLASH_ECCLPLB 0x00 /* Line parity 7 - 0 bit */
-#define FLASH_ECCLPUB 0x04 /* Line parity 15 - 8 bit */
-#define FLASH_ECCCP 0x08 /* Column parity 5 - 0 bit */
-#define FLASH_ECCCNTR 0x0c /* ECC byte counter */
-#define FLASH_ECCCLRR 0x10 /* Clear ECC */
-#define FLASH_FLASHIO 0x14 /* Flash I/O */
-#define FLASH_FLASHCTL 0x18 /* Flash Control */
-
-#define FLASHCTL_CE0 (1 << 0)
-#define FLASHCTL_CLE (1 << 1)
-#define FLASHCTL_ALE (1 << 2)
-#define FLASHCTL_WP (1 << 3)
-#define FLASHCTL_CE1 (1 << 4)
-#define FLASHCTL_RYBY (1 << 5)
-#define FLASHCTL_NCE (FLASHCTL_CE0 | FLASHCTL_CE1)
-
-#define TYPE_SL_NAND "sl-nand"
-#define SL_NAND(obj) OBJECT_CHECK(SLNANDState, (obj), TYPE_SL_NAND)
-
-typedef struct {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- DeviceState *nand;
- uint8_t ctl;
- uint8_t manf_id;
- uint8_t chip_id;
- ECCState ecc;
-} SLNANDState;
-
-static uint64_t sl_read(void *opaque, hwaddr addr, unsigned size)
-{
- SLNANDState *s = (SLNANDState *) opaque;
- int ryby;
-
- switch (addr) {
-#define BSHR(byte, from, to) ((s->ecc.lp[byte] >> (from - to)) & (1 << to))
- case FLASH_ECCLPLB:
- return BSHR(0, 4, 0) | BSHR(0, 5, 2) | BSHR(0, 6, 4) | BSHR(0, 7, 6) |
- BSHR(1, 4, 1) | BSHR(1, 5, 3) | BSHR(1, 6, 5) | BSHR(1, 7, 7);
-
-#define BSHL(byte, from, to) ((s->ecc.lp[byte] << (to - from)) & (1 << to))
- case FLASH_ECCLPUB:
- return BSHL(0, 0, 0) | BSHL(0, 1, 2) | BSHL(0, 2, 4) | BSHL(0, 3, 6) |
- BSHL(1, 0, 1) | BSHL(1, 1, 3) | BSHL(1, 2, 5) | BSHL(1, 3, 7);
-
- case FLASH_ECCCP:
- return s->ecc.cp;
-
- case FLASH_ECCCNTR:
- return s->ecc.count & 0xff;
-
- case FLASH_FLASHCTL:
- nand_getpins(s->nand, &ryby);
- if (ryby)
- return s->ctl | FLASHCTL_RYBY;
- else
- return s->ctl;
-
- case FLASH_FLASHIO:
- if (size == 4) {
- return ecc_digest(&s->ecc, nand_getio(s->nand)) |
- (ecc_digest(&s->ecc, nand_getio(s->nand)) << 16);
- }
- return ecc_digest(&s->ecc, nand_getio(s->nand));
-
- default:
- zaurus_printf("Bad register offset " REG_FMT "\n", (unsigned long)addr);
- }
- return 0;
-}
-
-static void sl_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- SLNANDState *s = (SLNANDState *) opaque;
-
- switch (addr) {
- case FLASH_ECCCLRR:
- /* Value is ignored. */
- ecc_reset(&s->ecc);
- break;
-
- case FLASH_FLASHCTL:
- s->ctl = value & 0xff & ~FLASHCTL_RYBY;
- nand_setpins(s->nand,
- s->ctl & FLASHCTL_CLE,
- s->ctl & FLASHCTL_ALE,
- s->ctl & FLASHCTL_NCE,
- s->ctl & FLASHCTL_WP,
- 0);
- break;
-
- case FLASH_FLASHIO:
- nand_setio(s->nand, ecc_digest(&s->ecc, value & 0xff));
- break;
-
- default:
- zaurus_printf("Bad register offset " REG_FMT "\n", (unsigned long)addr);
- }
-}
-
-enum {
- FLASH_128M,
- FLASH_1024M,
-};
-
-static const MemoryRegionOps sl_ops = {
- .read = sl_read,
- .write = sl_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void sl_flash_register(PXA2xxState *cpu, int size)
-{
- DeviceState *dev;
-
- dev = qdev_create(NULL, TYPE_SL_NAND);
-
- qdev_prop_set_uint8(dev, "manf_id", NAND_MFR_SAMSUNG);
- if (size == FLASH_128M)
- qdev_prop_set_uint8(dev, "chip_id", 0x73);
- else if (size == FLASH_1024M)
- qdev_prop_set_uint8(dev, "chip_id", 0xf1);
-
- qdev_init_nofail(dev);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, FLASH_BASE);
-}
-
-static int sl_nand_init(SysBusDevice *dev)
-{
- SLNANDState *s = SL_NAND(dev);
- DriveInfo *nand;
-
- s->ctl = 0;
- /* FIXME use a qdev drive property instead of drive_get() */
- nand = drive_get(IF_MTD, 0, 0);
- s->nand = nand_init(nand ? blk_by_legacy_dinfo(nand) : NULL,
- s->manf_id, s->chip_id);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &sl_ops, s, "sl", 0x40);
- sysbus_init_mmio(dev, &s->iomem);
-
- return 0;
-}
-
-/* Spitz Keyboard */
-
-#define SPITZ_KEY_STROBE_NUM 11
-#define SPITZ_KEY_SENSE_NUM 7
-
-static const int spitz_gpio_key_sense[SPITZ_KEY_SENSE_NUM] = {
- 12, 17, 91, 34, 36, 38, 39
-};
-
-static const int spitz_gpio_key_strobe[SPITZ_KEY_STROBE_NUM] = {
- 88, 23, 24, 25, 26, 27, 52, 103, 107, 108, 114
-};
-
-/* Eighth additional row maps the special keys */
-static int spitz_keymap[SPITZ_KEY_SENSE_NUM + 1][SPITZ_KEY_STROBE_NUM] = {
- { 0x1d, 0x02, 0x04, 0x06, 0x07, 0x08, 0x0a, 0x0b, 0x0e, 0x3f, 0x40 },
- { -1 , 0x03, 0x05, 0x13, 0x15, 0x09, 0x17, 0x18, 0x19, 0x41, 0x42 },
- { 0x0f, 0x10, 0x12, 0x14, 0x22, 0x16, 0x24, 0x25, -1 , -1 , -1 },
- { 0x3c, 0x11, 0x1f, 0x21, 0x2f, 0x23, 0x32, 0x26, -1 , 0x36, -1 },
- { 0x3b, 0x1e, 0x20, 0x2e, 0x30, 0x31, 0x34, -1 , 0x1c, 0x2a, -1 },
- { 0x44, 0x2c, 0x2d, 0x0c, 0x39, 0x33, -1 , 0x48, -1 , -1 , 0x38 },
- { 0x37, 0x3d, -1 , 0x45, 0x57, 0x58, 0x4b, 0x50, 0x4d, -1 , -1 },
- { 0x52, 0x43, 0x01, 0x47, 0x49, -1 , -1 , -1 , -1 , -1 , -1 },
-};
-
-#define SPITZ_GPIO_AK_INT 13 /* Remote control */
-#define SPITZ_GPIO_SYNC 16 /* Sync button */
-#define SPITZ_GPIO_ON_KEY 95 /* Power button */
-#define SPITZ_GPIO_SWA 97 /* Lid */
-#define SPITZ_GPIO_SWB 96 /* Tablet mode */
-
-/* The special buttons are mapped to unused keys */
-static const int spitz_gpiomap[5] = {
- SPITZ_GPIO_AK_INT, SPITZ_GPIO_SYNC, SPITZ_GPIO_ON_KEY,
- SPITZ_GPIO_SWA, SPITZ_GPIO_SWB,
-};
-
-#define TYPE_SPITZ_KEYBOARD "spitz-keyboard"
-#define SPITZ_KEYBOARD(obj) \
- OBJECT_CHECK(SpitzKeyboardState, (obj), TYPE_SPITZ_KEYBOARD)
-
-typedef struct {
- SysBusDevice parent_obj;
-
- qemu_irq sense[SPITZ_KEY_SENSE_NUM];
- qemu_irq gpiomap[5];
- int keymap[0x80];
- uint16_t keyrow[SPITZ_KEY_SENSE_NUM];
- uint16_t strobe_state;
- uint16_t sense_state;
-
- uint16_t pre_map[0x100];
- uint16_t modifiers;
- uint16_t imodifiers;
- uint8_t fifo[16];
- int fifopos, fifolen;
- QEMUTimer *kbdtimer;
-} SpitzKeyboardState;
-
-static void spitz_keyboard_sense_update(SpitzKeyboardState *s)
-{
- int i;
- uint16_t strobe, sense = 0;
- for (i = 0; i < SPITZ_KEY_SENSE_NUM; i ++) {
- strobe = s->keyrow[i] & s->strobe_state;
- if (strobe) {
- sense |= 1 << i;
- if (!(s->sense_state & (1 << i)))
- qemu_irq_raise(s->sense[i]);
- } else if (s->sense_state & (1 << i))
- qemu_irq_lower(s->sense[i]);
- }
-
- s->sense_state = sense;
-}
-
-static void spitz_keyboard_strobe(void *opaque, int line, int level)
-{
- SpitzKeyboardState *s = (SpitzKeyboardState *) opaque;
-
- if (level)
- s->strobe_state |= 1 << line;
- else
- s->strobe_state &= ~(1 << line);
- spitz_keyboard_sense_update(s);
-}
-
-static void spitz_keyboard_keydown(SpitzKeyboardState *s, int keycode)
-{
- int spitz_keycode = s->keymap[keycode & 0x7f];
- if (spitz_keycode == -1)
- return;
-
- /* Handle the additional keys */
- if ((spitz_keycode >> 4) == SPITZ_KEY_SENSE_NUM) {
- qemu_set_irq(s->gpiomap[spitz_keycode & 0xf], (keycode < 0x80));
- return;
- }
-
- if (keycode & 0x80)
- s->keyrow[spitz_keycode >> 4] &= ~(1 << (spitz_keycode & 0xf));
- else
- s->keyrow[spitz_keycode >> 4] |= 1 << (spitz_keycode & 0xf);
-
- spitz_keyboard_sense_update(s);
-}
-
-#define SPITZ_MOD_SHIFT (1 << 7)
-#define SPITZ_MOD_CTRL (1 << 8)
-#define SPITZ_MOD_FN (1 << 9)
-
-#define QUEUE_KEY(c) s->fifo[(s->fifopos + s->fifolen ++) & 0xf] = c
-
-static void spitz_keyboard_handler(void *opaque, int keycode)
-{
- SpitzKeyboardState *s = opaque;
- uint16_t code;
- int mapcode;
- switch (keycode) {
- case 0x2a: /* Left Shift */
- s->modifiers |= 1;
- break;
- case 0xaa:
- s->modifiers &= ~1;
- break;
- case 0x36: /* Right Shift */
- s->modifiers |= 2;
- break;
- case 0xb6:
- s->modifiers &= ~2;
- break;
- case 0x1d: /* Control */
- s->modifiers |= 4;
- break;
- case 0x9d:
- s->modifiers &= ~4;
- break;
- case 0x38: /* Alt */
- s->modifiers |= 8;
- break;
- case 0xb8:
- s->modifiers &= ~8;
- break;
- }
-
- code = s->pre_map[mapcode = ((s->modifiers & 3) ?
- (keycode | SPITZ_MOD_SHIFT) :
- (keycode & ~SPITZ_MOD_SHIFT))];
-
- if (code != mapcode) {
-#if 0
- if ((code & SPITZ_MOD_SHIFT) && !(s->modifiers & 1)) {
- QUEUE_KEY(0x2a | (keycode & 0x80));
- }
- if ((code & SPITZ_MOD_CTRL) && !(s->modifiers & 4)) {
- QUEUE_KEY(0x1d | (keycode & 0x80));
- }
- if ((code & SPITZ_MOD_FN) && !(s->modifiers & 8)) {
- QUEUE_KEY(0x38 | (keycode & 0x80));
- }
- if ((code & SPITZ_MOD_FN) && (s->modifiers & 1)) {
- QUEUE_KEY(0x2a | (~keycode & 0x80));
- }
- if ((code & SPITZ_MOD_FN) && (s->modifiers & 2)) {
- QUEUE_KEY(0x36 | (~keycode & 0x80));
- }
-#else
- if (keycode & 0x80) {
- if ((s->imodifiers & 1 ) && !(s->modifiers & 1))
- QUEUE_KEY(0x2a | 0x80);
- if ((s->imodifiers & 4 ) && !(s->modifiers & 4))
- QUEUE_KEY(0x1d | 0x80);
- if ((s->imodifiers & 8 ) && !(s->modifiers & 8))
- QUEUE_KEY(0x38 | 0x80);
- if ((s->imodifiers & 0x10) && (s->modifiers & 1))
- QUEUE_KEY(0x2a);
- if ((s->imodifiers & 0x20) && (s->modifiers & 2))
- QUEUE_KEY(0x36);
- s->imodifiers = 0;
- } else {
- if ((code & SPITZ_MOD_SHIFT) &&
- !((s->modifiers | s->imodifiers) & 1)) {
- QUEUE_KEY(0x2a);
- s->imodifiers |= 1;
- }
- if ((code & SPITZ_MOD_CTRL) &&
- !((s->modifiers | s->imodifiers) & 4)) {
- QUEUE_KEY(0x1d);
- s->imodifiers |= 4;
- }
- if ((code & SPITZ_MOD_FN) &&
- !((s->modifiers | s->imodifiers) & 8)) {
- QUEUE_KEY(0x38);
- s->imodifiers |= 8;
- }
- if ((code & SPITZ_MOD_FN) && (s->modifiers & 1) &&
- !(s->imodifiers & 0x10)) {
- QUEUE_KEY(0x2a | 0x80);
- s->imodifiers |= 0x10;
- }
- if ((code & SPITZ_MOD_FN) && (s->modifiers & 2) &&
- !(s->imodifiers & 0x20)) {
- QUEUE_KEY(0x36 | 0x80);
- s->imodifiers |= 0x20;
- }
- }
-#endif
- }
-
- QUEUE_KEY((code & 0x7f) | (keycode & 0x80));
-}
-
-static void spitz_keyboard_tick(void *opaque)
-{
- SpitzKeyboardState *s = (SpitzKeyboardState *) opaque;
-
- if (s->fifolen) {
- spitz_keyboard_keydown(s, s->fifo[s->fifopos ++]);
- s->fifolen --;
- if (s->fifopos >= 16)
- s->fifopos = 0;
- }
-
- timer_mod(s->kbdtimer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- NANOSECONDS_PER_SECOND / 32);
-}
-
-static void spitz_keyboard_pre_map(SpitzKeyboardState *s)
-{
- int i;
- for (i = 0; i < 0x100; i ++)
- s->pre_map[i] = i;
- s->pre_map[0x02 | SPITZ_MOD_SHIFT] = 0x02 | SPITZ_MOD_SHIFT; /* exclam */
- s->pre_map[0x28 | SPITZ_MOD_SHIFT] = 0x03 | SPITZ_MOD_SHIFT; /* quotedbl */
- s->pre_map[0x04 | SPITZ_MOD_SHIFT] = 0x04 | SPITZ_MOD_SHIFT; /* # */
- s->pre_map[0x05 | SPITZ_MOD_SHIFT] = 0x05 | SPITZ_MOD_SHIFT; /* dollar */
- s->pre_map[0x06 | SPITZ_MOD_SHIFT] = 0x06 | SPITZ_MOD_SHIFT; /* percent */
- s->pre_map[0x08 | SPITZ_MOD_SHIFT] = 0x07 | SPITZ_MOD_SHIFT; /* ampersand */
- s->pre_map[0x28] = 0x08 | SPITZ_MOD_SHIFT; /* ' */
- s->pre_map[0x0a | SPITZ_MOD_SHIFT] = 0x09 | SPITZ_MOD_SHIFT; /* ( */
- s->pre_map[0x0b | SPITZ_MOD_SHIFT] = 0x0a | SPITZ_MOD_SHIFT; /* ) */
- s->pre_map[0x29 | SPITZ_MOD_SHIFT] = 0x0b | SPITZ_MOD_SHIFT; /* tilde */
- s->pre_map[0x03 | SPITZ_MOD_SHIFT] = 0x0c | SPITZ_MOD_SHIFT; /* at */
- s->pre_map[0xd3] = 0x0e | SPITZ_MOD_FN; /* Delete */
- s->pre_map[0x3a] = 0x0f | SPITZ_MOD_FN; /* Caps_Lock */
- s->pre_map[0x07 | SPITZ_MOD_SHIFT] = 0x11 | SPITZ_MOD_FN; /* ^ */
- s->pre_map[0x0d] = 0x12 | SPITZ_MOD_FN; /* equal */
- s->pre_map[0x0d | SPITZ_MOD_SHIFT] = 0x13 | SPITZ_MOD_FN; /* plus */
- s->pre_map[0x1a] = 0x14 | SPITZ_MOD_FN; /* [ */
- s->pre_map[0x1b] = 0x15 | SPITZ_MOD_FN; /* ] */
- s->pre_map[0x1a | SPITZ_MOD_SHIFT] = 0x16 | SPITZ_MOD_FN; /* { */
- s->pre_map[0x1b | SPITZ_MOD_SHIFT] = 0x17 | SPITZ_MOD_FN; /* } */
- s->pre_map[0x27] = 0x22 | SPITZ_MOD_FN; /* semicolon */
- s->pre_map[0x27 | SPITZ_MOD_SHIFT] = 0x23 | SPITZ_MOD_FN; /* colon */
- s->pre_map[0x09 | SPITZ_MOD_SHIFT] = 0x24 | SPITZ_MOD_FN; /* asterisk */
- s->pre_map[0x2b] = 0x25 | SPITZ_MOD_FN; /* backslash */
- s->pre_map[0x2b | SPITZ_MOD_SHIFT] = 0x26 | SPITZ_MOD_FN; /* bar */
- s->pre_map[0x0c | SPITZ_MOD_SHIFT] = 0x30 | SPITZ_MOD_FN; /* _ */
- s->pre_map[0x33 | SPITZ_MOD_SHIFT] = 0x33 | SPITZ_MOD_FN; /* less */
- s->pre_map[0x35] = 0x33 | SPITZ_MOD_SHIFT; /* slash */
- s->pre_map[0x34 | SPITZ_MOD_SHIFT] = 0x34 | SPITZ_MOD_FN; /* greater */
- s->pre_map[0x35 | SPITZ_MOD_SHIFT] = 0x34 | SPITZ_MOD_SHIFT; /* question */
- s->pre_map[0x49] = 0x48 | SPITZ_MOD_FN; /* Page_Up */
- s->pre_map[0x51] = 0x50 | SPITZ_MOD_FN; /* Page_Down */
-
- s->modifiers = 0;
- s->imodifiers = 0;
- s->fifopos = 0;
- s->fifolen = 0;
-}
-
-#undef SPITZ_MOD_SHIFT
-#undef SPITZ_MOD_CTRL
-#undef SPITZ_MOD_FN
-
-static int spitz_keyboard_post_load(void *opaque, int version_id)
-{
- SpitzKeyboardState *s = (SpitzKeyboardState *) opaque;
-
- /* Release all pressed keys */
- memset(s->keyrow, 0, sizeof(s->keyrow));
- spitz_keyboard_sense_update(s);
- s->modifiers = 0;
- s->imodifiers = 0;
- s->fifopos = 0;
- s->fifolen = 0;
-
- return 0;
-}
-
-static void spitz_keyboard_register(PXA2xxState *cpu)
-{
- int i;
- DeviceState *dev;
- SpitzKeyboardState *s;
-
- dev = sysbus_create_simple(TYPE_SPITZ_KEYBOARD, -1, NULL);
- s = SPITZ_KEYBOARD(dev);
-
- for (i = 0; i < SPITZ_KEY_SENSE_NUM; i ++)
- qdev_connect_gpio_out(dev, i, qdev_get_gpio_in(cpu->gpio, spitz_gpio_key_sense[i]));
-
- for (i = 0; i < 5; i ++)
- s->gpiomap[i] = qdev_get_gpio_in(cpu->gpio, spitz_gpiomap[i]);
-
- if (!graphic_rotate)
- s->gpiomap[4] = qemu_irq_invert(s->gpiomap[4]);
-
- for (i = 0; i < 5; i++)
- qemu_set_irq(s->gpiomap[i], 0);
-
- for (i = 0; i < SPITZ_KEY_STROBE_NUM; i ++)
- qdev_connect_gpio_out(cpu->gpio, spitz_gpio_key_strobe[i],
- qdev_get_gpio_in(dev, i));
-
- timer_mod(s->kbdtimer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
-
- qemu_add_kbd_event_handler(spitz_keyboard_handler, s);
-}
-
-static int spitz_keyboard_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- SpitzKeyboardState *s = SPITZ_KEYBOARD(dev);
- int i, j;
-
- for (i = 0; i < 0x80; i ++)
- s->keymap[i] = -1;
- for (i = 0; i < SPITZ_KEY_SENSE_NUM + 1; i ++)
- for (j = 0; j < SPITZ_KEY_STROBE_NUM; j ++)
- if (spitz_keymap[i][j] != -1)
- s->keymap[spitz_keymap[i][j]] = (i << 4) | j;
-
- spitz_keyboard_pre_map(s);
-
- s->kbdtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, spitz_keyboard_tick, s);
- qdev_init_gpio_in(dev, spitz_keyboard_strobe, SPITZ_KEY_STROBE_NUM);
- qdev_init_gpio_out(dev, s->sense, SPITZ_KEY_SENSE_NUM);
-
- return 0;
-}
-
-/* LCD backlight controller */
-
-#define LCDTG_RESCTL 0x00
-#define LCDTG_PHACTRL 0x01
-#define LCDTG_DUTYCTRL 0x02
-#define LCDTG_POWERREG0 0x03
-#define LCDTG_POWERREG1 0x04
-#define LCDTG_GPOR3 0x05
-#define LCDTG_PICTRL 0x06
-#define LCDTG_POLCTRL 0x07
-
-typedef struct {
- SSISlave ssidev;
- uint32_t bl_intensity;
- uint32_t bl_power;
-} SpitzLCDTG;
-
-static void spitz_bl_update(SpitzLCDTG *s)
-{
- if (s->bl_power && s->bl_intensity)
- zaurus_printf("LCD Backlight now at %i/63\n", s->bl_intensity);
- else
- zaurus_printf("LCD Backlight now off\n");
-}
-
-/* FIXME: Implement GPIO properly and remove this hack. */
-static SpitzLCDTG *spitz_lcdtg;
-
-static inline void spitz_bl_bit5(void *opaque, int line, int level)
-{
- SpitzLCDTG *s = spitz_lcdtg;
- int prev = s->bl_intensity;
-
- if (level)
- s->bl_intensity &= ~0x20;
- else
- s->bl_intensity |= 0x20;
-
- if (s->bl_power && prev != s->bl_intensity)
- spitz_bl_update(s);
-}
-
-static inline void spitz_bl_power(void *opaque, int line, int level)
-{
- SpitzLCDTG *s = spitz_lcdtg;
- s->bl_power = !!level;
- spitz_bl_update(s);
-}
-
-static uint32_t spitz_lcdtg_transfer(SSISlave *dev, uint32_t value)
-{
- SpitzLCDTG *s = FROM_SSI_SLAVE(SpitzLCDTG, dev);
- int addr;
- addr = value >> 5;
- value &= 0x1f;
-
- switch (addr) {
- case LCDTG_RESCTL:
- if (value)
- zaurus_printf("LCD in QVGA mode\n");
- else
- zaurus_printf("LCD in VGA mode\n");
- break;
-
- case LCDTG_DUTYCTRL:
- s->bl_intensity &= ~0x1f;
- s->bl_intensity |= value;
- if (s->bl_power)
- spitz_bl_update(s);
- break;
-
- case LCDTG_POWERREG0:
- /* Set common voltage to M62332FP */
- break;
- }
- return 0;
-}
-
-static int spitz_lcdtg_init(SSISlave *dev)
-{
- SpitzLCDTG *s = FROM_SSI_SLAVE(SpitzLCDTG, dev);
-
- spitz_lcdtg = s;
- s->bl_power = 0;
- s->bl_intensity = 0x20;
-
- return 0;
-}
-
-/* SSP devices */
-
-#define CORGI_SSP_PORT 2
-
-#define SPITZ_GPIO_LCDCON_CS 53
-#define SPITZ_GPIO_ADS7846_CS 14
-#define SPITZ_GPIO_MAX1111_CS 20
-#define SPITZ_GPIO_TP_INT 11
-
-static DeviceState *max1111;
-
-/* "Demux" the signal based on current chipselect */
-typedef struct {
- SSISlave ssidev;
- SSIBus *bus[3];
- uint32_t enable[3];
-} CorgiSSPState;
-
-static uint32_t corgi_ssp_transfer(SSISlave *dev, uint32_t value)
-{
- CorgiSSPState *s = FROM_SSI_SLAVE(CorgiSSPState, dev);
- int i;
-
- for (i = 0; i < 3; i++) {
- if (s->enable[i]) {
- return ssi_transfer(s->bus[i], value);
- }
- }
- return 0;
-}
-
-static void corgi_ssp_gpio_cs(void *opaque, int line, int level)
-{
- CorgiSSPState *s = (CorgiSSPState *)opaque;
- assert(line >= 0 && line < 3);
- s->enable[line] = !level;
-}
-
-#define MAX1111_BATT_VOLT 1
-#define MAX1111_BATT_TEMP 2
-#define MAX1111_ACIN_VOLT 3
-
-#define SPITZ_BATTERY_TEMP 0xe0 /* About 2.9V */
-#define SPITZ_BATTERY_VOLT 0xd0 /* About 4.0V */
-#define SPITZ_CHARGEON_ACIN 0x80 /* About 5.0V */
-
-static void spitz_adc_temp_on(void *opaque, int line, int level)
-{
- if (!max1111)
- return;
-
- if (level)
- max111x_set_input(max1111, MAX1111_BATT_TEMP, SPITZ_BATTERY_TEMP);
- else
- max111x_set_input(max1111, MAX1111_BATT_TEMP, 0);
-}
-
-static int corgi_ssp_init(SSISlave *d)
-{
- DeviceState *dev = DEVICE(d);
- CorgiSSPState *s = FROM_SSI_SLAVE(CorgiSSPState, d);
-
- qdev_init_gpio_in(dev, corgi_ssp_gpio_cs, 3);
- s->bus[0] = ssi_create_bus(dev, "ssi0");
- s->bus[1] = ssi_create_bus(dev, "ssi1");
- s->bus[2] = ssi_create_bus(dev, "ssi2");
-
- return 0;
-}
-
-static void spitz_ssp_attach(PXA2xxState *cpu)
-{
- DeviceState *mux;
- DeviceState *dev;
- void *bus;
-
- mux = ssi_create_slave(cpu->ssp[CORGI_SSP_PORT - 1], "corgi-ssp");
-
- bus = qdev_get_child_bus(mux, "ssi0");
- ssi_create_slave(bus, "spitz-lcdtg");
-
- bus = qdev_get_child_bus(mux, "ssi1");
- dev = ssi_create_slave(bus, "ads7846");
- qdev_connect_gpio_out(dev, 0,
- qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_TP_INT));
-
- bus = qdev_get_child_bus(mux, "ssi2");
- max1111 = ssi_create_slave(bus, "max1111");
- max111x_set_input(max1111, MAX1111_BATT_VOLT, SPITZ_BATTERY_VOLT);
- max111x_set_input(max1111, MAX1111_BATT_TEMP, 0);
- max111x_set_input(max1111, MAX1111_ACIN_VOLT, SPITZ_CHARGEON_ACIN);
-
- qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_LCDCON_CS,
- qdev_get_gpio_in(mux, 0));
- qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_ADS7846_CS,
- qdev_get_gpio_in(mux, 1));
- qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_MAX1111_CS,
- qdev_get_gpio_in(mux, 2));
-}
-
-/* CF Microdrive */
-
-static void spitz_microdrive_attach(PXA2xxState *cpu, int slot)
-{
- PCMCIACardState *md;
- DriveInfo *dinfo;
-
- dinfo = drive_get(IF_IDE, 0, 0);
- if (!dinfo || dinfo->media_cd)
- return;
- md = dscm1xxxx_init(dinfo);
- pxa2xx_pcmcia_attach(cpu->pcmcia[slot], md);
-}
-
-/* Wm8750 and Max7310 on I2C */
-
-#define AKITA_MAX_ADDR 0x18
-#define SPITZ_WM_ADDRL 0x1b
-#define SPITZ_WM_ADDRH 0x1a
-
-#define SPITZ_GPIO_WM 5
-
-static void spitz_wm8750_addr(void *opaque, int line, int level)
-{
- I2CSlave *wm = (I2CSlave *) opaque;
- if (level)
- i2c_set_slave_address(wm, SPITZ_WM_ADDRH);
- else
- i2c_set_slave_address(wm, SPITZ_WM_ADDRL);
-}
-
-static void spitz_i2c_setup(PXA2xxState *cpu)
-{
- /* Attach the CPU on one end of our I2C bus. */
- I2CBus *bus = pxa2xx_i2c_bus(cpu->i2c[0]);
-
- DeviceState *wm;
-
- /* Attach a WM8750 to the bus */
- wm = i2c_create_slave(bus, "wm8750", 0);
-
- spitz_wm8750_addr(wm, 0, 0);
- qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_WM,
- qemu_allocate_irq(spitz_wm8750_addr, wm, 0));
- /* .. and to the sound interface. */
- cpu->i2s->opaque = wm;
- cpu->i2s->codec_out = wm8750_dac_dat;
- cpu->i2s->codec_in = wm8750_adc_dat;
- wm8750_data_req_set(wm, cpu->i2s->data_req, cpu->i2s);
-}
-
-static void spitz_akita_i2c_setup(PXA2xxState *cpu)
-{
- /* Attach a Max7310 to Akita I2C bus. */
- i2c_create_slave(pxa2xx_i2c_bus(cpu->i2c[0]), "max7310",
- AKITA_MAX_ADDR);
-}
-
-/* Other peripherals */
-
-static void spitz_out_switch(void *opaque, int line, int level)
-{
- switch (line) {
- case 0:
- zaurus_printf("Charging %s.\n", level ? "off" : "on");
- break;
- case 1:
- zaurus_printf("Discharging %s.\n", level ? "on" : "off");
- break;
- case 2:
- zaurus_printf("Green LED %s.\n", level ? "on" : "off");
- break;
- case 3:
- zaurus_printf("Orange LED %s.\n", level ? "on" : "off");
- break;
- case 4:
- spitz_bl_bit5(opaque, line, level);
- break;
- case 5:
- spitz_bl_power(opaque, line, level);
- break;
- case 6:
- spitz_adc_temp_on(opaque, line, level);
- break;
- }
-}
-
-#define SPITZ_SCP_LED_GREEN 1
-#define SPITZ_SCP_JK_B 2
-#define SPITZ_SCP_CHRG_ON 3
-#define SPITZ_SCP_MUTE_L 4
-#define SPITZ_SCP_MUTE_R 5
-#define SPITZ_SCP_CF_POWER 6
-#define SPITZ_SCP_LED_ORANGE 7
-#define SPITZ_SCP_JK_A 8
-#define SPITZ_SCP_ADC_TEMP_ON 9
-#define SPITZ_SCP2_IR_ON 1
-#define SPITZ_SCP2_AKIN_PULLUP 2
-#define SPITZ_SCP2_BACKLIGHT_CONT 7
-#define SPITZ_SCP2_BACKLIGHT_ON 8
-#define SPITZ_SCP2_MIC_BIAS 9
-
-static void spitz_scoop_gpio_setup(PXA2xxState *cpu,
- DeviceState *scp0, DeviceState *scp1)
-{
- qemu_irq *outsignals = qemu_allocate_irqs(spitz_out_switch, cpu, 8);
-
- qdev_connect_gpio_out(scp0, SPITZ_SCP_CHRG_ON, outsignals[0]);
- qdev_connect_gpio_out(scp0, SPITZ_SCP_JK_B, outsignals[1]);
- qdev_connect_gpio_out(scp0, SPITZ_SCP_LED_GREEN, outsignals[2]);
- qdev_connect_gpio_out(scp0, SPITZ_SCP_LED_ORANGE, outsignals[3]);
-
- if (scp1) {
- qdev_connect_gpio_out(scp1, SPITZ_SCP2_BACKLIGHT_CONT, outsignals[4]);
- qdev_connect_gpio_out(scp1, SPITZ_SCP2_BACKLIGHT_ON, outsignals[5]);
- }
-
- qdev_connect_gpio_out(scp0, SPITZ_SCP_ADC_TEMP_ON, outsignals[6]);
-}
-
-#define SPITZ_GPIO_HSYNC 22
-#define SPITZ_GPIO_SD_DETECT 9
-#define SPITZ_GPIO_SD_WP 81
-#define SPITZ_GPIO_ON_RESET 89
-#define SPITZ_GPIO_BAT_COVER 90
-#define SPITZ_GPIO_CF1_IRQ 105
-#define SPITZ_GPIO_CF1_CD 94
-#define SPITZ_GPIO_CF2_IRQ 106
-#define SPITZ_GPIO_CF2_CD 93
-
-static int spitz_hsync;
-
-static void spitz_lcd_hsync_handler(void *opaque, int line, int level)
-{
- PXA2xxState *cpu = (PXA2xxState *) opaque;
- qemu_set_irq(qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_HSYNC), spitz_hsync);
- spitz_hsync ^= 1;
-}
-
-static void spitz_gpio_setup(PXA2xxState *cpu, int slots)
-{
- qemu_irq lcd_hsync;
- /*
- * Bad hack: We toggle the LCD hsync GPIO on every GPIO status
- * read to satisfy broken guests that poll-wait for hsync.
- * Simulating a real hsync event would be less practical and
- * wouldn't guarantee that a guest ever exits the loop.
- */
- spitz_hsync = 0;
- lcd_hsync = qemu_allocate_irq(spitz_lcd_hsync_handler, cpu, 0);
- pxa2xx_gpio_read_notifier(cpu->gpio, lcd_hsync);
- pxa2xx_lcd_vsync_notifier(cpu->lcd, lcd_hsync);
-
- /* MMC/SD host */
- pxa2xx_mmci_handlers(cpu->mmc,
- qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_SD_WP),
- qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_SD_DETECT));
-
- /* Battery lock always closed */
- qemu_irq_raise(qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_BAT_COVER));
-
- /* Handle reset */
- qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_ON_RESET, cpu->reset);
-
- /* PCMCIA signals: card's IRQ and Card-Detect */
- if (slots >= 1)
- pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[0],
- qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF1_IRQ),
- qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF1_CD));
- if (slots >= 2)
- pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[1],
- qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF2_IRQ),
- qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF2_CD));
-}
-
-/* Board init. */
-enum spitz_model_e { spitz, akita, borzoi, terrier };
-
-#define SPITZ_RAM 0x04000000
-#define SPITZ_ROM 0x00800000
-
-static struct arm_boot_info spitz_binfo = {
- .loader_start = PXA2XX_SDRAM_BASE,
- .ram_size = 0x04000000,
-};
-
-static void spitz_common_init(MachineState *machine,
- enum spitz_model_e model, int arm_id)
-{
- PXA2xxState *mpu;
- DeviceState *scp0, *scp1 = NULL;
- MemoryRegion *address_space_mem = get_system_memory();
- MemoryRegion *rom = g_new(MemoryRegion, 1);
- const char *cpu_model = machine->cpu_model;
-
- if (!cpu_model)
- cpu_model = (model == terrier) ? "pxa270-c5" : "pxa270-c0";
-
- /* Setup CPU & memory */
- mpu = pxa270_init(address_space_mem, spitz_binfo.ram_size, cpu_model);
-
- sl_flash_register(mpu, (model == spitz) ? FLASH_128M : FLASH_1024M);
-
- memory_region_init_ram(rom, NULL, "spitz.rom", SPITZ_ROM, &error_fatal);
- vmstate_register_ram_global(rom);
- memory_region_set_readonly(rom, true);
- memory_region_add_subregion(address_space_mem, 0, rom);
-
- /* Setup peripherals */
- spitz_keyboard_register(mpu);
-
- spitz_ssp_attach(mpu);
-
- scp0 = sysbus_create_simple("scoop", 0x10800000, NULL);
- if (model != akita) {
- scp1 = sysbus_create_simple("scoop", 0x08800040, NULL);
- }
-
- spitz_scoop_gpio_setup(mpu, scp0, scp1);
-
- spitz_gpio_setup(mpu, (model == akita) ? 1 : 2);
-
- spitz_i2c_setup(mpu);
-
- if (model == akita)
- spitz_akita_i2c_setup(mpu);
-
- if (model == terrier)
- /* A 6.0 GB microdrive is permanently sitting in CF slot 1. */
- spitz_microdrive_attach(mpu, 1);
- else if (model != akita)
- /* A 4.0 GB microdrive is permanently sitting in CF slot 0. */
- spitz_microdrive_attach(mpu, 0);
-
- spitz_binfo.kernel_filename = machine->kernel_filename;
- spitz_binfo.kernel_cmdline = machine->kernel_cmdline;
- spitz_binfo.initrd_filename = machine->initrd_filename;
- spitz_binfo.board_id = arm_id;
- arm_load_kernel(mpu->cpu, &spitz_binfo);
- sl_bootparam_write(SL_PXA_PARAM_BASE);
-}
-
-static void spitz_init(MachineState *machine)
-{
- spitz_common_init(machine, spitz, 0x2c9);
-}
-
-static void borzoi_init(MachineState *machine)
-{
- spitz_common_init(machine, borzoi, 0x33f);
-}
-
-static void akita_init(MachineState *machine)
-{
- spitz_common_init(machine, akita, 0x2e8);
-}
-
-static void terrier_init(MachineState *machine)
-{
- spitz_common_init(machine, terrier, 0x33f);
-}
-
-static void akitapda_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "Sharp SL-C1000 (Akita) PDA (PXA270)";
- mc->init = akita_init;
-}
-
-static const TypeInfo akitapda_type = {
- .name = MACHINE_TYPE_NAME("akita"),
- .parent = TYPE_MACHINE,
- .class_init = akitapda_class_init,
-};
-
-static void spitzpda_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "Sharp SL-C3000 (Spitz) PDA (PXA270)";
- mc->init = spitz_init;
-}
-
-static const TypeInfo spitzpda_type = {
- .name = MACHINE_TYPE_NAME("spitz"),
- .parent = TYPE_MACHINE,
- .class_init = spitzpda_class_init,
-};
-
-static void borzoipda_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "Sharp SL-C3100 (Borzoi) PDA (PXA270)";
- mc->init = borzoi_init;
-}
-
-static const TypeInfo borzoipda_type = {
- .name = MACHINE_TYPE_NAME("borzoi"),
- .parent = TYPE_MACHINE,
- .class_init = borzoipda_class_init,
-};
-
-static void terrierpda_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "Sharp SL-C3200 (Terrier) PDA (PXA270)";
- mc->init = terrier_init;
-}
-
-static const TypeInfo terrierpda_type = {
- .name = MACHINE_TYPE_NAME("terrier"),
- .parent = TYPE_MACHINE,
- .class_init = terrierpda_class_init,
-};
-
-static void spitz_machine_init(void)
-{
- type_register_static(&akitapda_type);
- type_register_static(&spitzpda_type);
- type_register_static(&borzoipda_type);
- type_register_static(&terrierpda_type);
-}
-
-type_init(spitz_machine_init)
-
-static bool is_version_0(void *opaque, int version_id)
-{
- return version_id == 0;
-}
-
-static VMStateDescription vmstate_sl_nand_info = {
- .name = "sl-nand",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(ctl, SLNANDState),
- VMSTATE_STRUCT(ecc, SLNANDState, 0, vmstate_ecc_state, ECCState),
- VMSTATE_END_OF_LIST(),
- },
-};
-
-static Property sl_nand_properties[] = {
- DEFINE_PROP_UINT8("manf_id", SLNANDState, manf_id, NAND_MFR_SAMSUNG),
- DEFINE_PROP_UINT8("chip_id", SLNANDState, chip_id, 0xf1),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void sl_nand_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = sl_nand_init;
- dc->vmsd = &vmstate_sl_nand_info;
- dc->props = sl_nand_properties;
- /* Reason: init() method uses drive_get() */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo sl_nand_info = {
- .name = TYPE_SL_NAND,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(SLNANDState),
- .class_init = sl_nand_class_init,
-};
-
-static VMStateDescription vmstate_spitz_kbd = {
- .name = "spitz-keyboard",
- .version_id = 1,
- .minimum_version_id = 0,
- .post_load = spitz_keyboard_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT16(sense_state, SpitzKeyboardState),
- VMSTATE_UINT16(strobe_state, SpitzKeyboardState),
- VMSTATE_UNUSED_TEST(is_version_0, 5),
- VMSTATE_END_OF_LIST(),
- },
-};
-
-static void spitz_keyboard_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = spitz_keyboard_init;
- dc->vmsd = &vmstate_spitz_kbd;
-}
-
-static const TypeInfo spitz_keyboard_info = {
- .name = TYPE_SPITZ_KEYBOARD,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(SpitzKeyboardState),
- .class_init = spitz_keyboard_class_init,
-};
-
-static const VMStateDescription vmstate_corgi_ssp_regs = {
- .name = "corgi-ssp",
- .version_id = 2,
- .minimum_version_id = 2,
- .fields = (VMStateField[]) {
- VMSTATE_SSI_SLAVE(ssidev, CorgiSSPState),
- VMSTATE_UINT32_ARRAY(enable, CorgiSSPState, 3),
- VMSTATE_END_OF_LIST(),
- }
-};
-
-static void corgi_ssp_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
-
- k->init = corgi_ssp_init;
- k->transfer = corgi_ssp_transfer;
- dc->vmsd = &vmstate_corgi_ssp_regs;
-}
-
-static const TypeInfo corgi_ssp_info = {
- .name = "corgi-ssp",
- .parent = TYPE_SSI_SLAVE,
- .instance_size = sizeof(CorgiSSPState),
- .class_init = corgi_ssp_class_init,
-};
-
-static const VMStateDescription vmstate_spitz_lcdtg_regs = {
- .name = "spitz-lcdtg",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_SSI_SLAVE(ssidev, SpitzLCDTG),
- VMSTATE_UINT32(bl_intensity, SpitzLCDTG),
- VMSTATE_UINT32(bl_power, SpitzLCDTG),
- VMSTATE_END_OF_LIST(),
- }
-};
-
-static void spitz_lcdtg_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
-
- k->init = spitz_lcdtg_init;
- k->transfer = spitz_lcdtg_transfer;
- dc->vmsd = &vmstate_spitz_lcdtg_regs;
-}
-
-static const TypeInfo spitz_lcdtg_info = {
- .name = "spitz-lcdtg",
- .parent = TYPE_SSI_SLAVE,
- .instance_size = sizeof(SpitzLCDTG),
- .class_init = spitz_lcdtg_class_init,
-};
-
-static void spitz_register_types(void)
-{
- type_register_static(&corgi_ssp_info);
- type_register_static(&spitz_lcdtg_info);
- type_register_static(&spitz_keyboard_info);
- type_register_static(&sl_nand_info);
-}
-
-type_init(spitz_register_types)
diff --git a/qemu/hw/arm/stellaris.c b/qemu/hw/arm/stellaris.c
deleted file mode 100644
index c1766f856..000000000
--- a/qemu/hw/arm/stellaris.c
+++ /dev/null
@@ -1,1475 +0,0 @@
-/*
- * Luminary Micro Stellaris peripherals
- *
- * Copyright (c) 2006 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/sysbus.h"
-#include "hw/ssi/ssi.h"
-#include "hw/arm/arm.h"
-#include "hw/devices.h"
-#include "qemu/timer.h"
-#include "hw/i2c/i2c.h"
-#include "net/net.h"
-#include "hw/boards.h"
-#include "exec/address-spaces.h"
-#include "sysemu/sysemu.h"
-
-#define GPIO_A 0
-#define GPIO_B 1
-#define GPIO_C 2
-#define GPIO_D 3
-#define GPIO_E 4
-#define GPIO_F 5
-#define GPIO_G 6
-
-#define BP_OLED_I2C 0x01
-#define BP_OLED_SSI 0x02
-#define BP_GAMEPAD 0x04
-
-#define NUM_IRQ_LINES 64
-
-typedef const struct {
- const char *name;
- uint32_t did0;
- uint32_t did1;
- uint32_t dc0;
- uint32_t dc1;
- uint32_t dc2;
- uint32_t dc3;
- uint32_t dc4;
- uint32_t peripherals;
-} stellaris_board_info;
-
-/* General purpose timer module. */
-
-#define TYPE_STELLARIS_GPTM "stellaris-gptm"
-#define STELLARIS_GPTM(obj) \
- OBJECT_CHECK(gptm_state, (obj), TYPE_STELLARIS_GPTM)
-
-typedef struct gptm_state {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- uint32_t config;
- uint32_t mode[2];
- uint32_t control;
- uint32_t state;
- uint32_t mask;
- uint32_t load[2];
- uint32_t match[2];
- uint32_t prescale[2];
- uint32_t match_prescale[2];
- uint32_t rtc;
- int64_t tick[2];
- struct gptm_state *opaque[2];
- QEMUTimer *timer[2];
- /* The timers have an alternate output used to trigger the ADC. */
- qemu_irq trigger;
- qemu_irq irq;
-} gptm_state;
-
-static void gptm_update_irq(gptm_state *s)
-{
- int level;
- level = (s->state & s->mask) != 0;
- qemu_set_irq(s->irq, level);
-}
-
-static void gptm_stop(gptm_state *s, int n)
-{
- timer_del(s->timer[n]);
-}
-
-static void gptm_reload(gptm_state *s, int n, int reset)
-{
- int64_t tick;
- if (reset)
- tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- else
- tick = s->tick[n];
-
- if (s->config == 0) {
- /* 32-bit CountDown. */
- uint32_t count;
- count = s->load[0] | (s->load[1] << 16);
- tick += (int64_t)count * system_clock_scale;
- } else if (s->config == 1) {
- /* 32-bit RTC. 1Hz tick. */
- tick += NANOSECONDS_PER_SECOND;
- } else if (s->mode[n] == 0xa) {
- /* PWM mode. Not implemented. */
- } else {
- hw_error("TODO: 16-bit timer mode 0x%x\n", s->mode[n]);
- }
- s->tick[n] = tick;
- timer_mod(s->timer[n], tick);
-}
-
-static void gptm_tick(void *opaque)
-{
- gptm_state **p = (gptm_state **)opaque;
- gptm_state *s;
- int n;
-
- s = *p;
- n = p - s->opaque;
- if (s->config == 0) {
- s->state |= 1;
- if ((s->control & 0x20)) {
- /* Output trigger. */
- qemu_irq_pulse(s->trigger);
- }
- if (s->mode[0] & 1) {
- /* One-shot. */
- s->control &= ~1;
- } else {
- /* Periodic. */
- gptm_reload(s, 0, 0);
- }
- } else if (s->config == 1) {
- /* RTC. */
- uint32_t match;
- s->rtc++;
- match = s->match[0] | (s->match[1] << 16);
- if (s->rtc > match)
- s->rtc = 0;
- if (s->rtc == 0) {
- s->state |= 8;
- }
- gptm_reload(s, 0, 0);
- } else if (s->mode[n] == 0xa) {
- /* PWM mode. Not implemented. */
- } else {
- hw_error("TODO: 16-bit timer mode 0x%x\n", s->mode[n]);
- }
- gptm_update_irq(s);
-}
-
-static uint64_t gptm_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- gptm_state *s = (gptm_state *)opaque;
-
- switch (offset) {
- case 0x00: /* CFG */
- return s->config;
- case 0x04: /* TAMR */
- return s->mode[0];
- case 0x08: /* TBMR */
- return s->mode[1];
- case 0x0c: /* CTL */
- return s->control;
- case 0x18: /* IMR */
- return s->mask;
- case 0x1c: /* RIS */
- return s->state;
- case 0x20: /* MIS */
- return s->state & s->mask;
- case 0x24: /* CR */
- return 0;
- case 0x28: /* TAILR */
- return s->load[0] | ((s->config < 4) ? (s->load[1] << 16) : 0);
- case 0x2c: /* TBILR */
- return s->load[1];
- case 0x30: /* TAMARCHR */
- return s->match[0] | ((s->config < 4) ? (s->match[1] << 16) : 0);
- case 0x34: /* TBMATCHR */
- return s->match[1];
- case 0x38: /* TAPR */
- return s->prescale[0];
- case 0x3c: /* TBPR */
- return s->prescale[1];
- case 0x40: /* TAPMR */
- return s->match_prescale[0];
- case 0x44: /* TBPMR */
- return s->match_prescale[1];
- case 0x48: /* TAR */
- if (s->config == 1) {
- return s->rtc;
- }
- qemu_log_mask(LOG_UNIMP,
- "GPTM: read of TAR but timer read not supported");
- return 0;
- case 0x4c: /* TBR */
- qemu_log_mask(LOG_UNIMP,
- "GPTM: read of TBR but timer read not supported");
- return 0;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "GPTM: read at bad offset 0x%x\n", (int)offset);
- return 0;
- }
-}
-
-static void gptm_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- gptm_state *s = (gptm_state *)opaque;
- uint32_t oldval;
-
- /* The timers should be disabled before changing the configuration.
- We take advantage of this and defer everything until the timer
- is enabled. */
- switch (offset) {
- case 0x00: /* CFG */
- s->config = value;
- break;
- case 0x04: /* TAMR */
- s->mode[0] = value;
- break;
- case 0x08: /* TBMR */
- s->mode[1] = value;
- break;
- case 0x0c: /* CTL */
- oldval = s->control;
- s->control = value;
- /* TODO: Implement pause. */
- if ((oldval ^ value) & 1) {
- if (value & 1) {
- gptm_reload(s, 0, 1);
- } else {
- gptm_stop(s, 0);
- }
- }
- if (((oldval ^ value) & 0x100) && s->config >= 4) {
- if (value & 0x100) {
- gptm_reload(s, 1, 1);
- } else {
- gptm_stop(s, 1);
- }
- }
- break;
- case 0x18: /* IMR */
- s->mask = value & 0x77;
- gptm_update_irq(s);
- break;
- case 0x24: /* CR */
- s->state &= ~value;
- break;
- case 0x28: /* TAILR */
- s->load[0] = value & 0xffff;
- if (s->config < 4) {
- s->load[1] = value >> 16;
- }
- break;
- case 0x2c: /* TBILR */
- s->load[1] = value & 0xffff;
- break;
- case 0x30: /* TAMARCHR */
- s->match[0] = value & 0xffff;
- if (s->config < 4) {
- s->match[1] = value >> 16;
- }
- break;
- case 0x34: /* TBMATCHR */
- s->match[1] = value >> 16;
- break;
- case 0x38: /* TAPR */
- s->prescale[0] = value;
- break;
- case 0x3c: /* TBPR */
- s->prescale[1] = value;
- break;
- case 0x40: /* TAPMR */
- s->match_prescale[0] = value;
- break;
- case 0x44: /* TBPMR */
- s->match_prescale[0] = value;
- break;
- default:
- hw_error("gptm_write: Bad offset 0x%x\n", (int)offset);
- }
- gptm_update_irq(s);
-}
-
-static const MemoryRegionOps gptm_ops = {
- .read = gptm_read,
- .write = gptm_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_stellaris_gptm = {
- .name = "stellaris_gptm",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(config, gptm_state),
- VMSTATE_UINT32_ARRAY(mode, gptm_state, 2),
- VMSTATE_UINT32(control, gptm_state),
- VMSTATE_UINT32(state, gptm_state),
- VMSTATE_UINT32(mask, gptm_state),
- VMSTATE_UNUSED(8),
- VMSTATE_UINT32_ARRAY(load, gptm_state, 2),
- VMSTATE_UINT32_ARRAY(match, gptm_state, 2),
- VMSTATE_UINT32_ARRAY(prescale, gptm_state, 2),
- VMSTATE_UINT32_ARRAY(match_prescale, gptm_state, 2),
- VMSTATE_UINT32(rtc, gptm_state),
- VMSTATE_INT64_ARRAY(tick, gptm_state, 2),
- VMSTATE_TIMER_PTR_ARRAY(timer, gptm_state, 2),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static int stellaris_gptm_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- gptm_state *s = STELLARIS_GPTM(dev);
-
- sysbus_init_irq(sbd, &s->irq);
- qdev_init_gpio_out(dev, &s->trigger, 1);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &gptm_ops, s,
- "gptm", 0x1000);
- sysbus_init_mmio(sbd, &s->iomem);
-
- s->opaque[0] = s->opaque[1] = s;
- s->timer[0] = timer_new_ns(QEMU_CLOCK_VIRTUAL, gptm_tick, &s->opaque[0]);
- s->timer[1] = timer_new_ns(QEMU_CLOCK_VIRTUAL, gptm_tick, &s->opaque[1]);
- vmstate_register(dev, -1, &vmstate_stellaris_gptm, s);
- return 0;
-}
-
-
-/* System controller. */
-
-typedef struct {
- MemoryRegion iomem;
- uint32_t pborctl;
- uint32_t ldopctl;
- uint32_t int_status;
- uint32_t int_mask;
- uint32_t resc;
- uint32_t rcc;
- uint32_t rcc2;
- uint32_t rcgc[3];
- uint32_t scgc[3];
- uint32_t dcgc[3];
- uint32_t clkvclr;
- uint32_t ldoarst;
- uint32_t user0;
- uint32_t user1;
- qemu_irq irq;
- stellaris_board_info *board;
-} ssys_state;
-
-static void ssys_update(ssys_state *s)
-{
- qemu_set_irq(s->irq, (s->int_status & s->int_mask) != 0);
-}
-
-static uint32_t pllcfg_sandstorm[16] = {
- 0x31c0, /* 1 Mhz */
- 0x1ae0, /* 1.8432 Mhz */
- 0x18c0, /* 2 Mhz */
- 0xd573, /* 2.4576 Mhz */
- 0x37a6, /* 3.57954 Mhz */
- 0x1ae2, /* 3.6864 Mhz */
- 0x0c40, /* 4 Mhz */
- 0x98bc, /* 4.906 Mhz */
- 0x935b, /* 4.9152 Mhz */
- 0x09c0, /* 5 Mhz */
- 0x4dee, /* 5.12 Mhz */
- 0x0c41, /* 6 Mhz */
- 0x75db, /* 6.144 Mhz */
- 0x1ae6, /* 7.3728 Mhz */
- 0x0600, /* 8 Mhz */
- 0x585b /* 8.192 Mhz */
-};
-
-static uint32_t pllcfg_fury[16] = {
- 0x3200, /* 1 Mhz */
- 0x1b20, /* 1.8432 Mhz */
- 0x1900, /* 2 Mhz */
- 0xf42b, /* 2.4576 Mhz */
- 0x37e3, /* 3.57954 Mhz */
- 0x1b21, /* 3.6864 Mhz */
- 0x0c80, /* 4 Mhz */
- 0x98ee, /* 4.906 Mhz */
- 0xd5b4, /* 4.9152 Mhz */
- 0x0a00, /* 5 Mhz */
- 0x4e27, /* 5.12 Mhz */
- 0x1902, /* 6 Mhz */
- 0xec1c, /* 6.144 Mhz */
- 0x1b23, /* 7.3728 Mhz */
- 0x0640, /* 8 Mhz */
- 0xb11c /* 8.192 Mhz */
-};
-
-#define DID0_VER_MASK 0x70000000
-#define DID0_VER_0 0x00000000
-#define DID0_VER_1 0x10000000
-
-#define DID0_CLASS_MASK 0x00FF0000
-#define DID0_CLASS_SANDSTORM 0x00000000
-#define DID0_CLASS_FURY 0x00010000
-
-static int ssys_board_class(const ssys_state *s)
-{
- uint32_t did0 = s->board->did0;
- switch (did0 & DID0_VER_MASK) {
- case DID0_VER_0:
- return DID0_CLASS_SANDSTORM;
- case DID0_VER_1:
- switch (did0 & DID0_CLASS_MASK) {
- case DID0_CLASS_SANDSTORM:
- case DID0_CLASS_FURY:
- return did0 & DID0_CLASS_MASK;
- }
- /* for unknown classes, fall through */
- default:
- hw_error("ssys_board_class: Unknown class 0x%08x\n", did0);
- }
-}
-
-static uint64_t ssys_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- ssys_state *s = (ssys_state *)opaque;
-
- switch (offset) {
- case 0x000: /* DID0 */
- return s->board->did0;
- case 0x004: /* DID1 */
- return s->board->did1;
- case 0x008: /* DC0 */
- return s->board->dc0;
- case 0x010: /* DC1 */
- return s->board->dc1;
- case 0x014: /* DC2 */
- return s->board->dc2;
- case 0x018: /* DC3 */
- return s->board->dc3;
- case 0x01c: /* DC4 */
- return s->board->dc4;
- case 0x030: /* PBORCTL */
- return s->pborctl;
- case 0x034: /* LDOPCTL */
- return s->ldopctl;
- case 0x040: /* SRCR0 */
- return 0;
- case 0x044: /* SRCR1 */
- return 0;
- case 0x048: /* SRCR2 */
- return 0;
- case 0x050: /* RIS */
- return s->int_status;
- case 0x054: /* IMC */
- return s->int_mask;
- case 0x058: /* MISC */
- return s->int_status & s->int_mask;
- case 0x05c: /* RESC */
- return s->resc;
- case 0x060: /* RCC */
- return s->rcc;
- case 0x064: /* PLLCFG */
- {
- int xtal;
- xtal = (s->rcc >> 6) & 0xf;
- switch (ssys_board_class(s)) {
- case DID0_CLASS_FURY:
- return pllcfg_fury[xtal];
- case DID0_CLASS_SANDSTORM:
- return pllcfg_sandstorm[xtal];
- default:
- hw_error("ssys_read: Unhandled class for PLLCFG read.\n");
- return 0;
- }
- }
- case 0x070: /* RCC2 */
- return s->rcc2;
- case 0x100: /* RCGC0 */
- return s->rcgc[0];
- case 0x104: /* RCGC1 */
- return s->rcgc[1];
- case 0x108: /* RCGC2 */
- return s->rcgc[2];
- case 0x110: /* SCGC0 */
- return s->scgc[0];
- case 0x114: /* SCGC1 */
- return s->scgc[1];
- case 0x118: /* SCGC2 */
- return s->scgc[2];
- case 0x120: /* DCGC0 */
- return s->dcgc[0];
- case 0x124: /* DCGC1 */
- return s->dcgc[1];
- case 0x128: /* DCGC2 */
- return s->dcgc[2];
- case 0x150: /* CLKVCLR */
- return s->clkvclr;
- case 0x160: /* LDOARST */
- return s->ldoarst;
- case 0x1e0: /* USER0 */
- return s->user0;
- case 0x1e4: /* USER1 */
- return s->user1;
- default:
- hw_error("ssys_read: Bad offset 0x%x\n", (int)offset);
- return 0;
- }
-}
-
-static bool ssys_use_rcc2(ssys_state *s)
-{
- return (s->rcc2 >> 31) & 0x1;
-}
-
-/*
- * Caculate the sys. clock period in ms.
- */
-static void ssys_calculate_system_clock(ssys_state *s)
-{
- if (ssys_use_rcc2(s)) {
- system_clock_scale = 5 * (((s->rcc2 >> 23) & 0x3f) + 1);
- } else {
- system_clock_scale = 5 * (((s->rcc >> 23) & 0xf) + 1);
- }
-}
-
-static void ssys_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- ssys_state *s = (ssys_state *)opaque;
-
- switch (offset) {
- case 0x030: /* PBORCTL */
- s->pborctl = value & 0xffff;
- break;
- case 0x034: /* LDOPCTL */
- s->ldopctl = value & 0x1f;
- break;
- case 0x040: /* SRCR0 */
- case 0x044: /* SRCR1 */
- case 0x048: /* SRCR2 */
- fprintf(stderr, "Peripheral reset not implemented\n");
- break;
- case 0x054: /* IMC */
- s->int_mask = value & 0x7f;
- break;
- case 0x058: /* MISC */
- s->int_status &= ~value;
- break;
- case 0x05c: /* RESC */
- s->resc = value & 0x3f;
- break;
- case 0x060: /* RCC */
- if ((s->rcc & (1 << 13)) != 0 && (value & (1 << 13)) == 0) {
- /* PLL enable. */
- s->int_status |= (1 << 6);
- }
- s->rcc = value;
- ssys_calculate_system_clock(s);
- break;
- case 0x070: /* RCC2 */
- if (ssys_board_class(s) == DID0_CLASS_SANDSTORM) {
- break;
- }
-
- if ((s->rcc2 & (1 << 13)) != 0 && (value & (1 << 13)) == 0) {
- /* PLL enable. */
- s->int_status |= (1 << 6);
- }
- s->rcc2 = value;
- ssys_calculate_system_clock(s);
- break;
- case 0x100: /* RCGC0 */
- s->rcgc[0] = value;
- break;
- case 0x104: /* RCGC1 */
- s->rcgc[1] = value;
- break;
- case 0x108: /* RCGC2 */
- s->rcgc[2] = value;
- break;
- case 0x110: /* SCGC0 */
- s->scgc[0] = value;
- break;
- case 0x114: /* SCGC1 */
- s->scgc[1] = value;
- break;
- case 0x118: /* SCGC2 */
- s->scgc[2] = value;
- break;
- case 0x120: /* DCGC0 */
- s->dcgc[0] = value;
- break;
- case 0x124: /* DCGC1 */
- s->dcgc[1] = value;
- break;
- case 0x128: /* DCGC2 */
- s->dcgc[2] = value;
- break;
- case 0x150: /* CLKVCLR */
- s->clkvclr = value;
- break;
- case 0x160: /* LDOARST */
- s->ldoarst = value;
- break;
- default:
- hw_error("ssys_write: Bad offset 0x%x\n", (int)offset);
- }
- ssys_update(s);
-}
-
-static const MemoryRegionOps ssys_ops = {
- .read = ssys_read,
- .write = ssys_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void ssys_reset(void *opaque)
-{
- ssys_state *s = (ssys_state *)opaque;
-
- s->pborctl = 0x7ffd;
- s->rcc = 0x078e3ac0;
-
- if (ssys_board_class(s) == DID0_CLASS_SANDSTORM) {
- s->rcc2 = 0;
- } else {
- s->rcc2 = 0x07802810;
- }
- s->rcgc[0] = 1;
- s->scgc[0] = 1;
- s->dcgc[0] = 1;
- ssys_calculate_system_clock(s);
-}
-
-static int stellaris_sys_post_load(void *opaque, int version_id)
-{
- ssys_state *s = opaque;
-
- ssys_calculate_system_clock(s);
-
- return 0;
-}
-
-static const VMStateDescription vmstate_stellaris_sys = {
- .name = "stellaris_sys",
- .version_id = 2,
- .minimum_version_id = 1,
- .post_load = stellaris_sys_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(pborctl, ssys_state),
- VMSTATE_UINT32(ldopctl, ssys_state),
- VMSTATE_UINT32(int_mask, ssys_state),
- VMSTATE_UINT32(int_status, ssys_state),
- VMSTATE_UINT32(resc, ssys_state),
- VMSTATE_UINT32(rcc, ssys_state),
- VMSTATE_UINT32_V(rcc2, ssys_state, 2),
- VMSTATE_UINT32_ARRAY(rcgc, ssys_state, 3),
- VMSTATE_UINT32_ARRAY(scgc, ssys_state, 3),
- VMSTATE_UINT32_ARRAY(dcgc, ssys_state, 3),
- VMSTATE_UINT32(clkvclr, ssys_state),
- VMSTATE_UINT32(ldoarst, ssys_state),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static int stellaris_sys_init(uint32_t base, qemu_irq irq,
- stellaris_board_info * board,
- uint8_t *macaddr)
-{
- ssys_state *s;
-
- s = g_new0(ssys_state, 1);
- s->irq = irq;
- s->board = board;
- /* Most devices come preprogrammed with a MAC address in the user data. */
- s->user0 = macaddr[0] | (macaddr[1] << 8) | (macaddr[2] << 16);
- s->user1 = macaddr[3] | (macaddr[4] << 8) | (macaddr[5] << 16);
-
- memory_region_init_io(&s->iomem, NULL, &ssys_ops, s, "ssys", 0x00001000);
- memory_region_add_subregion(get_system_memory(), base, &s->iomem);
- ssys_reset(s);
- vmstate_register(NULL, -1, &vmstate_stellaris_sys, s);
- return 0;
-}
-
-
-/* I2C controller. */
-
-#define TYPE_STELLARIS_I2C "stellaris-i2c"
-#define STELLARIS_I2C(obj) \
- OBJECT_CHECK(stellaris_i2c_state, (obj), TYPE_STELLARIS_I2C)
-
-typedef struct {
- SysBusDevice parent_obj;
-
- I2CBus *bus;
- qemu_irq irq;
- MemoryRegion iomem;
- uint32_t msa;
- uint32_t mcs;
- uint32_t mdr;
- uint32_t mtpr;
- uint32_t mimr;
- uint32_t mris;
- uint32_t mcr;
-} stellaris_i2c_state;
-
-#define STELLARIS_I2C_MCS_BUSY 0x01
-#define STELLARIS_I2C_MCS_ERROR 0x02
-#define STELLARIS_I2C_MCS_ADRACK 0x04
-#define STELLARIS_I2C_MCS_DATACK 0x08
-#define STELLARIS_I2C_MCS_ARBLST 0x10
-#define STELLARIS_I2C_MCS_IDLE 0x20
-#define STELLARIS_I2C_MCS_BUSBSY 0x40
-
-static uint64_t stellaris_i2c_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- stellaris_i2c_state *s = (stellaris_i2c_state *)opaque;
-
- switch (offset) {
- case 0x00: /* MSA */
- return s->msa;
- case 0x04: /* MCS */
- /* We don't emulate timing, so the controller is never busy. */
- return s->mcs | STELLARIS_I2C_MCS_IDLE;
- case 0x08: /* MDR */
- return s->mdr;
- case 0x0c: /* MTPR */
- return s->mtpr;
- case 0x10: /* MIMR */
- return s->mimr;
- case 0x14: /* MRIS */
- return s->mris;
- case 0x18: /* MMIS */
- return s->mris & s->mimr;
- case 0x20: /* MCR */
- return s->mcr;
- default:
- hw_error("strllaris_i2c_read: Bad offset 0x%x\n", (int)offset);
- return 0;
- }
-}
-
-static void stellaris_i2c_update(stellaris_i2c_state *s)
-{
- int level;
-
- level = (s->mris & s->mimr) != 0;
- qemu_set_irq(s->irq, level);
-}
-
-static void stellaris_i2c_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- stellaris_i2c_state *s = (stellaris_i2c_state *)opaque;
-
- switch (offset) {
- case 0x00: /* MSA */
- s->msa = value & 0xff;
- break;
- case 0x04: /* MCS */
- if ((s->mcr & 0x10) == 0) {
- /* Disabled. Do nothing. */
- break;
- }
- /* Grab the bus if this is starting a transfer. */
- if ((value & 2) && (s->mcs & STELLARIS_I2C_MCS_BUSBSY) == 0) {
- if (i2c_start_transfer(s->bus, s->msa >> 1, s->msa & 1)) {
- s->mcs |= STELLARIS_I2C_MCS_ARBLST;
- } else {
- s->mcs &= ~STELLARIS_I2C_MCS_ARBLST;
- s->mcs |= STELLARIS_I2C_MCS_BUSBSY;
- }
- }
- /* If we don't have the bus then indicate an error. */
- if (!i2c_bus_busy(s->bus)
- || (s->mcs & STELLARIS_I2C_MCS_BUSBSY) == 0) {
- s->mcs |= STELLARIS_I2C_MCS_ERROR;
- break;
- }
- s->mcs &= ~STELLARIS_I2C_MCS_ERROR;
- if (value & 1) {
- /* Transfer a byte. */
- /* TODO: Handle errors. */
- if (s->msa & 1) {
- /* Recv */
- s->mdr = i2c_recv(s->bus) & 0xff;
- } else {
- /* Send */
- i2c_send(s->bus, s->mdr);
- }
- /* Raise an interrupt. */
- s->mris |= 1;
- }
- if (value & 4) {
- /* Finish transfer. */
- i2c_end_transfer(s->bus);
- s->mcs &= ~STELLARIS_I2C_MCS_BUSBSY;
- }
- break;
- case 0x08: /* MDR */
- s->mdr = value & 0xff;
- break;
- case 0x0c: /* MTPR */
- s->mtpr = value & 0xff;
- break;
- case 0x10: /* MIMR */
- s->mimr = 1;
- break;
- case 0x1c: /* MICR */
- s->mris &= ~value;
- break;
- case 0x20: /* MCR */
- if (value & 1)
- hw_error(
- "stellaris_i2c_write: Loopback not implemented\n");
- if (value & 0x20)
- hw_error(
- "stellaris_i2c_write: Slave mode not implemented\n");
- s->mcr = value & 0x31;
- break;
- default:
- hw_error("stellaris_i2c_write: Bad offset 0x%x\n",
- (int)offset);
- }
- stellaris_i2c_update(s);
-}
-
-static void stellaris_i2c_reset(stellaris_i2c_state *s)
-{
- if (s->mcs & STELLARIS_I2C_MCS_BUSBSY)
- i2c_end_transfer(s->bus);
-
- s->msa = 0;
- s->mcs = 0;
- s->mdr = 0;
- s->mtpr = 1;
- s->mimr = 0;
- s->mris = 0;
- s->mcr = 0;
- stellaris_i2c_update(s);
-}
-
-static const MemoryRegionOps stellaris_i2c_ops = {
- .read = stellaris_i2c_read,
- .write = stellaris_i2c_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_stellaris_i2c = {
- .name = "stellaris_i2c",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(msa, stellaris_i2c_state),
- VMSTATE_UINT32(mcs, stellaris_i2c_state),
- VMSTATE_UINT32(mdr, stellaris_i2c_state),
- VMSTATE_UINT32(mtpr, stellaris_i2c_state),
- VMSTATE_UINT32(mimr, stellaris_i2c_state),
- VMSTATE_UINT32(mris, stellaris_i2c_state),
- VMSTATE_UINT32(mcr, stellaris_i2c_state),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static int stellaris_i2c_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- stellaris_i2c_state *s = STELLARIS_I2C(dev);
- I2CBus *bus;
-
- sysbus_init_irq(sbd, &s->irq);
- bus = i2c_init_bus(dev, "i2c");
- s->bus = bus;
-
- memory_region_init_io(&s->iomem, OBJECT(s), &stellaris_i2c_ops, s,
- "i2c", 0x1000);
- sysbus_init_mmio(sbd, &s->iomem);
- /* ??? For now we only implement the master interface. */
- stellaris_i2c_reset(s);
- vmstate_register(dev, -1, &vmstate_stellaris_i2c, s);
- return 0;
-}
-
-/* Analogue to Digital Converter. This is only partially implemented,
- enough for applications that use a combined ADC and timer tick. */
-
-#define STELLARIS_ADC_EM_CONTROLLER 0
-#define STELLARIS_ADC_EM_COMP 1
-#define STELLARIS_ADC_EM_EXTERNAL 4
-#define STELLARIS_ADC_EM_TIMER 5
-#define STELLARIS_ADC_EM_PWM0 6
-#define STELLARIS_ADC_EM_PWM1 7
-#define STELLARIS_ADC_EM_PWM2 8
-
-#define STELLARIS_ADC_FIFO_EMPTY 0x0100
-#define STELLARIS_ADC_FIFO_FULL 0x1000
-
-#define TYPE_STELLARIS_ADC "stellaris-adc"
-#define STELLARIS_ADC(obj) \
- OBJECT_CHECK(stellaris_adc_state, (obj), TYPE_STELLARIS_ADC)
-
-typedef struct StellarisADCState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- uint32_t actss;
- uint32_t ris;
- uint32_t im;
- uint32_t emux;
- uint32_t ostat;
- uint32_t ustat;
- uint32_t sspri;
- uint32_t sac;
- struct {
- uint32_t state;
- uint32_t data[16];
- } fifo[4];
- uint32_t ssmux[4];
- uint32_t ssctl[4];
- uint32_t noise;
- qemu_irq irq[4];
-} stellaris_adc_state;
-
-static uint32_t stellaris_adc_fifo_read(stellaris_adc_state *s, int n)
-{
- int tail;
-
- tail = s->fifo[n].state & 0xf;
- if (s->fifo[n].state & STELLARIS_ADC_FIFO_EMPTY) {
- s->ustat |= 1 << n;
- } else {
- s->fifo[n].state = (s->fifo[n].state & ~0xf) | ((tail + 1) & 0xf);
- s->fifo[n].state &= ~STELLARIS_ADC_FIFO_FULL;
- if (tail + 1 == ((s->fifo[n].state >> 4) & 0xf))
- s->fifo[n].state |= STELLARIS_ADC_FIFO_EMPTY;
- }
- return s->fifo[n].data[tail];
-}
-
-static void stellaris_adc_fifo_write(stellaris_adc_state *s, int n,
- uint32_t value)
-{
- int head;
-
- /* TODO: Real hardware has limited size FIFOs. We have a full 16 entry
- FIFO fir each sequencer. */
- head = (s->fifo[n].state >> 4) & 0xf;
- if (s->fifo[n].state & STELLARIS_ADC_FIFO_FULL) {
- s->ostat |= 1 << n;
- return;
- }
- s->fifo[n].data[head] = value;
- head = (head + 1) & 0xf;
- s->fifo[n].state &= ~STELLARIS_ADC_FIFO_EMPTY;
- s->fifo[n].state = (s->fifo[n].state & ~0xf0) | (head << 4);
- if ((s->fifo[n].state & 0xf) == head)
- s->fifo[n].state |= STELLARIS_ADC_FIFO_FULL;
-}
-
-static void stellaris_adc_update(stellaris_adc_state *s)
-{
- int level;
- int n;
-
- for (n = 0; n < 4; n++) {
- level = (s->ris & s->im & (1 << n)) != 0;
- qemu_set_irq(s->irq[n], level);
- }
-}
-
-static void stellaris_adc_trigger(void *opaque, int irq, int level)
-{
- stellaris_adc_state *s = (stellaris_adc_state *)opaque;
- int n;
-
- for (n = 0; n < 4; n++) {
- if ((s->actss & (1 << n)) == 0) {
- continue;
- }
-
- if (((s->emux >> (n * 4)) & 0xff) != 5) {
- continue;
- }
-
- /* Some applications use the ADC as a random number source, so introduce
- some variation into the signal. */
- s->noise = s->noise * 314159 + 1;
- /* ??? actual inputs not implemented. Return an arbitrary value. */
- stellaris_adc_fifo_write(s, n, 0x200 + ((s->noise >> 16) & 7));
- s->ris |= (1 << n);
- stellaris_adc_update(s);
- }
-}
-
-static void stellaris_adc_reset(stellaris_adc_state *s)
-{
- int n;
-
- for (n = 0; n < 4; n++) {
- s->ssmux[n] = 0;
- s->ssctl[n] = 0;
- s->fifo[n].state = STELLARIS_ADC_FIFO_EMPTY;
- }
-}
-
-static uint64_t stellaris_adc_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- stellaris_adc_state *s = (stellaris_adc_state *)opaque;
-
- /* TODO: Implement this. */
- if (offset >= 0x40 && offset < 0xc0) {
- int n;
- n = (offset - 0x40) >> 5;
- switch (offset & 0x1f) {
- case 0x00: /* SSMUX */
- return s->ssmux[n];
- case 0x04: /* SSCTL */
- return s->ssctl[n];
- case 0x08: /* SSFIFO */
- return stellaris_adc_fifo_read(s, n);
- case 0x0c: /* SSFSTAT */
- return s->fifo[n].state;
- default:
- break;
- }
- }
- switch (offset) {
- case 0x00: /* ACTSS */
- return s->actss;
- case 0x04: /* RIS */
- return s->ris;
- case 0x08: /* IM */
- return s->im;
- case 0x0c: /* ISC */
- return s->ris & s->im;
- case 0x10: /* OSTAT */
- return s->ostat;
- case 0x14: /* EMUX */
- return s->emux;
- case 0x18: /* USTAT */
- return s->ustat;
- case 0x20: /* SSPRI */
- return s->sspri;
- case 0x30: /* SAC */
- return s->sac;
- default:
- hw_error("strllaris_adc_read: Bad offset 0x%x\n",
- (int)offset);
- return 0;
- }
-}
-
-static void stellaris_adc_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- stellaris_adc_state *s = (stellaris_adc_state *)opaque;
-
- /* TODO: Implement this. */
- if (offset >= 0x40 && offset < 0xc0) {
- int n;
- n = (offset - 0x40) >> 5;
- switch (offset & 0x1f) {
- case 0x00: /* SSMUX */
- s->ssmux[n] = value & 0x33333333;
- return;
- case 0x04: /* SSCTL */
- if (value != 6) {
- hw_error("ADC: Unimplemented sequence %" PRIx64 "\n",
- value);
- }
- s->ssctl[n] = value;
- return;
- default:
- break;
- }
- }
- switch (offset) {
- case 0x00: /* ACTSS */
- s->actss = value & 0xf;
- break;
- case 0x08: /* IM */
- s->im = value;
- break;
- case 0x0c: /* ISC */
- s->ris &= ~value;
- break;
- case 0x10: /* OSTAT */
- s->ostat &= ~value;
- break;
- case 0x14: /* EMUX */
- s->emux = value;
- break;
- case 0x18: /* USTAT */
- s->ustat &= ~value;
- break;
- case 0x20: /* SSPRI */
- s->sspri = value;
- break;
- case 0x28: /* PSSI */
- hw_error("Not implemented: ADC sample initiate\n");
- break;
- case 0x30: /* SAC */
- s->sac = value;
- break;
- default:
- hw_error("stellaris_adc_write: Bad offset 0x%x\n", (int)offset);
- }
- stellaris_adc_update(s);
-}
-
-static const MemoryRegionOps stellaris_adc_ops = {
- .read = stellaris_adc_read,
- .write = stellaris_adc_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_stellaris_adc = {
- .name = "stellaris_adc",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(actss, stellaris_adc_state),
- VMSTATE_UINT32(ris, stellaris_adc_state),
- VMSTATE_UINT32(im, stellaris_adc_state),
- VMSTATE_UINT32(emux, stellaris_adc_state),
- VMSTATE_UINT32(ostat, stellaris_adc_state),
- VMSTATE_UINT32(ustat, stellaris_adc_state),
- VMSTATE_UINT32(sspri, stellaris_adc_state),
- VMSTATE_UINT32(sac, stellaris_adc_state),
- VMSTATE_UINT32(fifo[0].state, stellaris_adc_state),
- VMSTATE_UINT32_ARRAY(fifo[0].data, stellaris_adc_state, 16),
- VMSTATE_UINT32(ssmux[0], stellaris_adc_state),
- VMSTATE_UINT32(ssctl[0], stellaris_adc_state),
- VMSTATE_UINT32(fifo[1].state, stellaris_adc_state),
- VMSTATE_UINT32_ARRAY(fifo[1].data, stellaris_adc_state, 16),
- VMSTATE_UINT32(ssmux[1], stellaris_adc_state),
- VMSTATE_UINT32(ssctl[1], stellaris_adc_state),
- VMSTATE_UINT32(fifo[2].state, stellaris_adc_state),
- VMSTATE_UINT32_ARRAY(fifo[2].data, stellaris_adc_state, 16),
- VMSTATE_UINT32(ssmux[2], stellaris_adc_state),
- VMSTATE_UINT32(ssctl[2], stellaris_adc_state),
- VMSTATE_UINT32(fifo[3].state, stellaris_adc_state),
- VMSTATE_UINT32_ARRAY(fifo[3].data, stellaris_adc_state, 16),
- VMSTATE_UINT32(ssmux[3], stellaris_adc_state),
- VMSTATE_UINT32(ssctl[3], stellaris_adc_state),
- VMSTATE_UINT32(noise, stellaris_adc_state),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static int stellaris_adc_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- stellaris_adc_state *s = STELLARIS_ADC(dev);
- int n;
-
- for (n = 0; n < 4; n++) {
- sysbus_init_irq(sbd, &s->irq[n]);
- }
-
- memory_region_init_io(&s->iomem, OBJECT(s), &stellaris_adc_ops, s,
- "adc", 0x1000);
- sysbus_init_mmio(sbd, &s->iomem);
- stellaris_adc_reset(s);
- qdev_init_gpio_in(dev, stellaris_adc_trigger, 1);
- vmstate_register(dev, -1, &vmstate_stellaris_adc, s);
- return 0;
-}
-
-static
-void do_sys_reset(void *opaque, int n, int level)
-{
- if (level) {
- qemu_system_reset_request();
- }
-}
-
-/* Board init. */
-static stellaris_board_info stellaris_boards[] = {
- { "LM3S811EVB",
- 0,
- 0x0032000e,
- 0x001f001f, /* dc0 */
- 0x001132bf,
- 0x01071013,
- 0x3f0f01ff,
- 0x0000001f,
- BP_OLED_I2C
- },
- { "LM3S6965EVB",
- 0x10010002,
- 0x1073402e,
- 0x00ff007f, /* dc0 */
- 0x001133ff,
- 0x030f5317,
- 0x0f0f87ff,
- 0x5000007f,
- BP_OLED_SSI | BP_GAMEPAD
- }
-};
-
-static void stellaris_init(const char *kernel_filename, const char *cpu_model,
- stellaris_board_info *board)
-{
- static const int uart_irq[] = {5, 6, 33, 34};
- static const int timer_irq[] = {19, 21, 23, 35};
- static const uint32_t gpio_addr[7] =
- { 0x40004000, 0x40005000, 0x40006000, 0x40007000,
- 0x40024000, 0x40025000, 0x40026000};
- static const int gpio_irq[7] = {0, 1, 2, 3, 4, 30, 31};
-
- DeviceState *gpio_dev[7], *nvic;
- qemu_irq gpio_in[7][8];
- qemu_irq gpio_out[7][8];
- qemu_irq adc;
- int sram_size;
- int flash_size;
- I2CBus *i2c;
- DeviceState *dev;
- int i;
- int j;
-
- MemoryRegion *sram = g_new(MemoryRegion, 1);
- MemoryRegion *flash = g_new(MemoryRegion, 1);
- MemoryRegion *system_memory = get_system_memory();
-
- flash_size = (((board->dc0 & 0xffff) + 1) << 1) * 1024;
- sram_size = ((board->dc0 >> 18) + 1) * 1024;
-
- /* Flash programming is done via the SCU, so pretend it is ROM. */
- memory_region_init_ram(flash, NULL, "stellaris.flash", flash_size,
- &error_fatal);
- vmstate_register_ram_global(flash);
- memory_region_set_readonly(flash, true);
- memory_region_add_subregion(system_memory, 0, flash);
-
- memory_region_init_ram(sram, NULL, "stellaris.sram", sram_size,
- &error_fatal);
- vmstate_register_ram_global(sram);
- memory_region_add_subregion(system_memory, 0x20000000, sram);
-
- nvic = armv7m_init(system_memory, flash_size, NUM_IRQ_LINES,
- kernel_filename, cpu_model);
-
- qdev_connect_gpio_out_named(nvic, "SYSRESETREQ", 0,
- qemu_allocate_irq(&do_sys_reset, NULL, 0));
-
- if (board->dc1 & (1 << 16)) {
- dev = sysbus_create_varargs(TYPE_STELLARIS_ADC, 0x40038000,
- qdev_get_gpio_in(nvic, 14),
- qdev_get_gpio_in(nvic, 15),
- qdev_get_gpio_in(nvic, 16),
- qdev_get_gpio_in(nvic, 17),
- NULL);
- adc = qdev_get_gpio_in(dev, 0);
- } else {
- adc = NULL;
- }
- for (i = 0; i < 4; i++) {
- if (board->dc2 & (0x10000 << i)) {
- dev = sysbus_create_simple(TYPE_STELLARIS_GPTM,
- 0x40030000 + i * 0x1000,
- qdev_get_gpio_in(nvic, timer_irq[i]));
- /* TODO: This is incorrect, but we get away with it because
- the ADC output is only ever pulsed. */
- qdev_connect_gpio_out(dev, 0, adc);
- }
- }
-
- stellaris_sys_init(0x400fe000, qdev_get_gpio_in(nvic, 28),
- board, nd_table[0].macaddr.a);
-
- for (i = 0; i < 7; i++) {
- if (board->dc4 & (1 << i)) {
- gpio_dev[i] = sysbus_create_simple("pl061_luminary", gpio_addr[i],
- qdev_get_gpio_in(nvic,
- gpio_irq[i]));
- for (j = 0; j < 8; j++) {
- gpio_in[i][j] = qdev_get_gpio_in(gpio_dev[i], j);
- gpio_out[i][j] = NULL;
- }
- }
- }
-
- if (board->dc2 & (1 << 12)) {
- dev = sysbus_create_simple(TYPE_STELLARIS_I2C, 0x40020000,
- qdev_get_gpio_in(nvic, 8));
- i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c");
- if (board->peripherals & BP_OLED_I2C) {
- i2c_create_slave(i2c, "ssd0303", 0x3d);
- }
- }
-
- for (i = 0; i < 4; i++) {
- if (board->dc2 & (1 << i)) {
- sysbus_create_simple("pl011_luminary", 0x4000c000 + i * 0x1000,
- qdev_get_gpio_in(nvic, uart_irq[i]));
- }
- }
- if (board->dc2 & (1 << 4)) {
- dev = sysbus_create_simple("pl022", 0x40008000,
- qdev_get_gpio_in(nvic, 7));
- if (board->peripherals & BP_OLED_SSI) {
- void *bus;
- DeviceState *sddev;
- DeviceState *ssddev;
-
- /* Some boards have both an OLED controller and SD card connected to
- * the same SSI port, with the SD card chip select connected to a
- * GPIO pin. Technically the OLED chip select is connected to the
- * SSI Fss pin. We do not bother emulating that as both devices
- * should never be selected simultaneously, and our OLED controller
- * ignores stray 0xff commands that occur when deselecting the SD
- * card.
- */
- bus = qdev_get_child_bus(dev, "ssi");
-
- sddev = ssi_create_slave(bus, "ssi-sd");
- ssddev = ssi_create_slave(bus, "ssd0323");
- gpio_out[GPIO_D][0] = qemu_irq_split(
- qdev_get_gpio_in_named(sddev, SSI_GPIO_CS, 0),
- qdev_get_gpio_in_named(ssddev, SSI_GPIO_CS, 0));
- gpio_out[GPIO_C][7] = qdev_get_gpio_in(ssddev, 0);
-
- /* Make sure the select pin is high. */
- qemu_irq_raise(gpio_out[GPIO_D][0]);
- }
- }
- if (board->dc4 & (1 << 28)) {
- DeviceState *enet;
-
- qemu_check_nic_model(&nd_table[0], "stellaris");
-
- enet = qdev_create(NULL, "stellaris_enet");
- qdev_set_nic_properties(enet, &nd_table[0]);
- qdev_init_nofail(enet);
- sysbus_mmio_map(SYS_BUS_DEVICE(enet), 0, 0x40048000);
- sysbus_connect_irq(SYS_BUS_DEVICE(enet), 0, qdev_get_gpio_in(nvic, 42));
- }
- if (board->peripherals & BP_GAMEPAD) {
- qemu_irq gpad_irq[5];
- static const int gpad_keycode[5] = { 0xc8, 0xd0, 0xcb, 0xcd, 0x1d };
-
- gpad_irq[0] = qemu_irq_invert(gpio_in[GPIO_E][0]); /* up */
- gpad_irq[1] = qemu_irq_invert(gpio_in[GPIO_E][1]); /* down */
- gpad_irq[2] = qemu_irq_invert(gpio_in[GPIO_E][2]); /* left */
- gpad_irq[3] = qemu_irq_invert(gpio_in[GPIO_E][3]); /* right */
- gpad_irq[4] = qemu_irq_invert(gpio_in[GPIO_F][1]); /* select */
-
- stellaris_gamepad_init(5, gpad_irq, gpad_keycode);
- }
- for (i = 0; i < 7; i++) {
- if (board->dc4 & (1 << i)) {
- for (j = 0; j < 8; j++) {
- if (gpio_out[i][j]) {
- qdev_connect_gpio_out(gpio_dev[i], j, gpio_out[i][j]);
- }
- }
- }
- }
-}
-
-/* FIXME: Figure out how to generate these from stellaris_boards. */
-static void lm3s811evb_init(MachineState *machine)
-{
- const char *cpu_model = machine->cpu_model;
- const char *kernel_filename = machine->kernel_filename;
- stellaris_init(kernel_filename, cpu_model, &stellaris_boards[0]);
-}
-
-static void lm3s6965evb_init(MachineState *machine)
-{
- const char *cpu_model = machine->cpu_model;
- const char *kernel_filename = machine->kernel_filename;
- stellaris_init(kernel_filename, cpu_model, &stellaris_boards[1]);
-}
-
-static void lm3s811evb_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "Stellaris LM3S811EVB";
- mc->init = lm3s811evb_init;
-}
-
-static const TypeInfo lm3s811evb_type = {
- .name = MACHINE_TYPE_NAME("lm3s811evb"),
- .parent = TYPE_MACHINE,
- .class_init = lm3s811evb_class_init,
-};
-
-static void lm3s6965evb_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "Stellaris LM3S6965EVB";
- mc->init = lm3s6965evb_init;
-}
-
-static const TypeInfo lm3s6965evb_type = {
- .name = MACHINE_TYPE_NAME("lm3s6965evb"),
- .parent = TYPE_MACHINE,
- .class_init = lm3s6965evb_class_init,
-};
-
-static void stellaris_machine_init(void)
-{
- type_register_static(&lm3s811evb_type);
- type_register_static(&lm3s6965evb_type);
-}
-
-type_init(stellaris_machine_init)
-
-static void stellaris_i2c_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
- sdc->init = stellaris_i2c_init;
-}
-
-static const TypeInfo stellaris_i2c_info = {
- .name = TYPE_STELLARIS_I2C,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(stellaris_i2c_state),
- .class_init = stellaris_i2c_class_init,
-};
-
-static void stellaris_gptm_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
- sdc->init = stellaris_gptm_init;
-}
-
-static const TypeInfo stellaris_gptm_info = {
- .name = TYPE_STELLARIS_GPTM,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(gptm_state),
- .class_init = stellaris_gptm_class_init,
-};
-
-static void stellaris_adc_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
- sdc->init = stellaris_adc_init;
-}
-
-static const TypeInfo stellaris_adc_info = {
- .name = TYPE_STELLARIS_ADC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(stellaris_adc_state),
- .class_init = stellaris_adc_class_init,
-};
-
-static void stellaris_register_types(void)
-{
- type_register_static(&stellaris_i2c_info);
- type_register_static(&stellaris_gptm_info);
- type_register_static(&stellaris_adc_info);
-}
-
-type_init(stellaris_register_types)
diff --git a/qemu/hw/arm/stm32f205_soc.c b/qemu/hw/arm/stm32f205_soc.c
deleted file mode 100644
index a5ea1e237..000000000
--- a/qemu/hw/arm/stm32f205_soc.c
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * STM32F205 SoC
- *
- * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/arm/arm.h"
-#include "exec/address-spaces.h"
-#include "hw/arm/stm32f205_soc.h"
-
-/* At the moment only Timer 2 to 5 are modelled */
-static const uint32_t timer_addr[STM_NUM_TIMERS] = { 0x40000000, 0x40000400,
- 0x40000800, 0x40000C00 };
-static const uint32_t usart_addr[STM_NUM_USARTS] = { 0x40011000, 0x40004400,
- 0x40004800, 0x40004C00, 0x40005000, 0x40011400 };
-
-static const int timer_irq[STM_NUM_TIMERS] = {28, 29, 30, 50};
-static const int usart_irq[STM_NUM_USARTS] = {37, 38, 39, 52, 53, 71};
-
-static void stm32f205_soc_initfn(Object *obj)
-{
- STM32F205State *s = STM32F205_SOC(obj);
- int i;
-
- object_initialize(&s->syscfg, sizeof(s->syscfg), TYPE_STM32F2XX_SYSCFG);
- qdev_set_parent_bus(DEVICE(&s->syscfg), sysbus_get_default());
-
- for (i = 0; i < STM_NUM_USARTS; i++) {
- object_initialize(&s->usart[i], sizeof(s->usart[i]),
- TYPE_STM32F2XX_USART);
- qdev_set_parent_bus(DEVICE(&s->usart[i]), sysbus_get_default());
- }
-
- for (i = 0; i < STM_NUM_TIMERS; i++) {
- object_initialize(&s->timer[i], sizeof(s->timer[i]),
- TYPE_STM32F2XX_TIMER);
- qdev_set_parent_bus(DEVICE(&s->timer[i]), sysbus_get_default());
- }
-}
-
-static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp)
-{
- STM32F205State *s = STM32F205_SOC(dev_soc);
- DeviceState *syscfgdev, *usartdev, *timerdev, *nvic;
- SysBusDevice *syscfgbusdev, *usartbusdev, *timerbusdev;
- Error *err = NULL;
- int i;
-
- MemoryRegion *system_memory = get_system_memory();
- MemoryRegion *sram = g_new(MemoryRegion, 1);
- MemoryRegion *flash = g_new(MemoryRegion, 1);
- MemoryRegion *flash_alias = g_new(MemoryRegion, 1);
-
- memory_region_init_ram(flash, NULL, "STM32F205.flash", FLASH_SIZE,
- &error_fatal);
- memory_region_init_alias(flash_alias, NULL, "STM32F205.flash.alias",
- flash, 0, FLASH_SIZE);
-
- vmstate_register_ram_global(flash);
-
- memory_region_set_readonly(flash, true);
- memory_region_set_readonly(flash_alias, true);
-
- memory_region_add_subregion(system_memory, FLASH_BASE_ADDRESS, flash);
- memory_region_add_subregion(system_memory, 0, flash_alias);
-
- memory_region_init_ram(sram, NULL, "STM32F205.sram", SRAM_SIZE,
- &error_fatal);
- vmstate_register_ram_global(sram);
- memory_region_add_subregion(system_memory, SRAM_BASE_ADDRESS, sram);
-
- nvic = armv7m_init(get_system_memory(), FLASH_SIZE, 96,
- s->kernel_filename, s->cpu_model);
-
- /* System configuration controller */
- syscfgdev = DEVICE(&s->syscfg);
- object_property_set_bool(OBJECT(&s->syscfg), true, "realized", &err);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
- syscfgbusdev = SYS_BUS_DEVICE(syscfgdev);
- sysbus_mmio_map(syscfgbusdev, 0, 0x40013800);
- sysbus_connect_irq(syscfgbusdev, 0, qdev_get_gpio_in(nvic, 71));
-
- /* Attach UART (uses USART registers) and USART controllers */
- for (i = 0; i < STM_NUM_USARTS; i++) {
- usartdev = DEVICE(&(s->usart[i]));
- object_property_set_bool(OBJECT(&s->usart[i]), true, "realized", &err);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
- usartbusdev = SYS_BUS_DEVICE(usartdev);
- sysbus_mmio_map(usartbusdev, 0, usart_addr[i]);
- sysbus_connect_irq(usartbusdev, 0,
- qdev_get_gpio_in(nvic, usart_irq[i]));
- }
-
- /* Timer 2 to 5 */
- for (i = 0; i < STM_NUM_TIMERS; i++) {
- timerdev = DEVICE(&(s->timer[i]));
- qdev_prop_set_uint64(timerdev, "clock-frequency", 1000000000);
- object_property_set_bool(OBJECT(&s->timer[i]), true, "realized", &err);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
- timerbusdev = SYS_BUS_DEVICE(timerdev);
- sysbus_mmio_map(timerbusdev, 0, timer_addr[i]);
- sysbus_connect_irq(timerbusdev, 0,
- qdev_get_gpio_in(nvic, timer_irq[i]));
- }
-}
-
-static Property stm32f205_soc_properties[] = {
- DEFINE_PROP_STRING("kernel-filename", STM32F205State, kernel_filename),
- DEFINE_PROP_STRING("cpu-model", STM32F205State, cpu_model),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void stm32f205_soc_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = stm32f205_soc_realize;
- dc->props = stm32f205_soc_properties;
-}
-
-static const TypeInfo stm32f205_soc_info = {
- .name = TYPE_STM32F205_SOC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(STM32F205State),
- .instance_init = stm32f205_soc_initfn,
- .class_init = stm32f205_soc_class_init,
-};
-
-static void stm32f205_soc_types(void)
-{
- type_register_static(&stm32f205_soc_info);
-}
-
-type_init(stm32f205_soc_types)
diff --git a/qemu/hw/arm/strongarm.c b/qemu/hw/arm/strongarm.c
deleted file mode 100644
index 1eeb1ab39..000000000
--- a/qemu/hw/arm/strongarm.c
+++ /dev/null
@@ -1,1662 +0,0 @@
-/*
- * StrongARM SA-1100/SA-1110 emulation
- *
- * Copyright (C) 2011 Dmitry Eremin-Solenikov
- *
- * Largely based on StrongARM emulation:
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * UART code based on QEMU 16550A UART emulation
- * Copyright (c) 2003-2004 Fabrice Bellard
- * Copyright (c) 2008 Citrix Systems, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "cpu.h"
-#include "hw/boards.h"
-#include "hw/sysbus.h"
-#include "strongarm.h"
-#include "qemu/error-report.h"
-#include "hw/arm/arm.h"
-#include "sysemu/char.h"
-#include "sysemu/sysemu.h"
-#include "hw/ssi/ssi.h"
-#include "qemu/cutils.h"
-
-//#define DEBUG
-
-/*
- TODO
- - Implement cp15, c14 ?
- - Implement cp15, c15 !!! (idle used in L)
- - Implement idle mode handling/DIM
- - Implement sleep mode/Wake sources
- - Implement reset control
- - Implement memory control regs
- - PCMCIA handling
- - Maybe support MBGNT/MBREQ
- - DMA channels
- - GPCLK
- - IrDA
- - MCP
- - Enhance UART with modem signals
- */
-
-#ifdef DEBUG
-# define DPRINTF(format, ...) printf(format , ## __VA_ARGS__)
-#else
-# define DPRINTF(format, ...) do { } while (0)
-#endif
-
-static struct {
- hwaddr io_base;
- int irq;
-} sa_serial[] = {
- { 0x80010000, SA_PIC_UART1 },
- { 0x80030000, SA_PIC_UART2 },
- { 0x80050000, SA_PIC_UART3 },
- { 0, 0 }
-};
-
-/* Interrupt Controller */
-
-#define TYPE_STRONGARM_PIC "strongarm_pic"
-#define STRONGARM_PIC(obj) \
- OBJECT_CHECK(StrongARMPICState, (obj), TYPE_STRONGARM_PIC)
-
-typedef struct StrongARMPICState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- qemu_irq irq;
- qemu_irq fiq;
-
- uint32_t pending;
- uint32_t enabled;
- uint32_t is_fiq;
- uint32_t int_idle;
-} StrongARMPICState;
-
-#define ICIP 0x00
-#define ICMR 0x04
-#define ICLR 0x08
-#define ICFP 0x10
-#define ICPR 0x20
-#define ICCR 0x0c
-
-#define SA_PIC_SRCS 32
-
-
-static void strongarm_pic_update(void *opaque)
-{
- StrongARMPICState *s = opaque;
-
- /* FIXME: reflect DIM */
- qemu_set_irq(s->fiq, s->pending & s->enabled & s->is_fiq);
- qemu_set_irq(s->irq, s->pending & s->enabled & ~s->is_fiq);
-}
-
-static void strongarm_pic_set_irq(void *opaque, int irq, int level)
-{
- StrongARMPICState *s = opaque;
-
- if (level) {
- s->pending |= 1 << irq;
- } else {
- s->pending &= ~(1 << irq);
- }
-
- strongarm_pic_update(s);
-}
-
-static uint64_t strongarm_pic_mem_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- StrongARMPICState *s = opaque;
-
- switch (offset) {
- case ICIP:
- return s->pending & ~s->is_fiq & s->enabled;
- case ICMR:
- return s->enabled;
- case ICLR:
- return s->is_fiq;
- case ICCR:
- return s->int_idle == 0;
- case ICFP:
- return s->pending & s->is_fiq & s->enabled;
- case ICPR:
- return s->pending;
- default:
- printf("%s: Bad register offset 0x" TARGET_FMT_plx "\n",
- __func__, offset);
- return 0;
- }
-}
-
-static void strongarm_pic_mem_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- StrongARMPICState *s = opaque;
-
- switch (offset) {
- case ICMR:
- s->enabled = value;
- break;
- case ICLR:
- s->is_fiq = value;
- break;
- case ICCR:
- s->int_idle = (value & 1) ? 0 : ~0;
- break;
- default:
- printf("%s: Bad register offset 0x" TARGET_FMT_plx "\n",
- __func__, offset);
- break;
- }
- strongarm_pic_update(s);
-}
-
-static const MemoryRegionOps strongarm_pic_ops = {
- .read = strongarm_pic_mem_read,
- .write = strongarm_pic_mem_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int strongarm_pic_initfn(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- StrongARMPICState *s = STRONGARM_PIC(dev);
-
- qdev_init_gpio_in(dev, strongarm_pic_set_irq, SA_PIC_SRCS);
- memory_region_init_io(&s->iomem, OBJECT(s), &strongarm_pic_ops, s,
- "pic", 0x1000);
- sysbus_init_mmio(sbd, &s->iomem);
- sysbus_init_irq(sbd, &s->irq);
- sysbus_init_irq(sbd, &s->fiq);
-
- return 0;
-}
-
-static int strongarm_pic_post_load(void *opaque, int version_id)
-{
- strongarm_pic_update(opaque);
- return 0;
-}
-
-static VMStateDescription vmstate_strongarm_pic_regs = {
- .name = "strongarm_pic",
- .version_id = 0,
- .minimum_version_id = 0,
- .post_load = strongarm_pic_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(pending, StrongARMPICState),
- VMSTATE_UINT32(enabled, StrongARMPICState),
- VMSTATE_UINT32(is_fiq, StrongARMPICState),
- VMSTATE_UINT32(int_idle, StrongARMPICState),
- VMSTATE_END_OF_LIST(),
- },
-};
-
-static void strongarm_pic_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = strongarm_pic_initfn;
- dc->desc = "StrongARM PIC";
- dc->vmsd = &vmstate_strongarm_pic_regs;
-}
-
-static const TypeInfo strongarm_pic_info = {
- .name = TYPE_STRONGARM_PIC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(StrongARMPICState),
- .class_init = strongarm_pic_class_init,
-};
-
-/* Real-Time Clock */
-#define RTAR 0x00 /* RTC Alarm register */
-#define RCNR 0x04 /* RTC Counter register */
-#define RTTR 0x08 /* RTC Timer Trim register */
-#define RTSR 0x10 /* RTC Status register */
-
-#define RTSR_AL (1 << 0) /* RTC Alarm detected */
-#define RTSR_HZ (1 << 1) /* RTC 1Hz detected */
-#define RTSR_ALE (1 << 2) /* RTC Alarm enable */
-#define RTSR_HZE (1 << 3) /* RTC 1Hz enable */
-
-/* 16 LSB of RTTR are clockdiv for internal trim logic,
- * trim delete isn't emulated, so
- * f = 32 768 / (RTTR_trim + 1) */
-
-#define TYPE_STRONGARM_RTC "strongarm-rtc"
-#define STRONGARM_RTC(obj) \
- OBJECT_CHECK(StrongARMRTCState, (obj), TYPE_STRONGARM_RTC)
-
-typedef struct StrongARMRTCState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- uint32_t rttr;
- uint32_t rtsr;
- uint32_t rtar;
- uint32_t last_rcnr;
- int64_t last_hz;
- QEMUTimer *rtc_alarm;
- QEMUTimer *rtc_hz;
- qemu_irq rtc_irq;
- qemu_irq rtc_hz_irq;
-} StrongARMRTCState;
-
-static inline void strongarm_rtc_int_update(StrongARMRTCState *s)
-{
- qemu_set_irq(s->rtc_irq, s->rtsr & RTSR_AL);
- qemu_set_irq(s->rtc_hz_irq, s->rtsr & RTSR_HZ);
-}
-
-static void strongarm_rtc_hzupdate(StrongARMRTCState *s)
-{
- int64_t rt = qemu_clock_get_ms(rtc_clock);
- s->last_rcnr += ((rt - s->last_hz) << 15) /
- (1000 * ((s->rttr & 0xffff) + 1));
- s->last_hz = rt;
-}
-
-static inline void strongarm_rtc_timer_update(StrongARMRTCState *s)
-{
- if ((s->rtsr & RTSR_HZE) && !(s->rtsr & RTSR_HZ)) {
- timer_mod(s->rtc_hz, s->last_hz + 1000);
- } else {
- timer_del(s->rtc_hz);
- }
-
- if ((s->rtsr & RTSR_ALE) && !(s->rtsr & RTSR_AL)) {
- timer_mod(s->rtc_alarm, s->last_hz +
- (((s->rtar - s->last_rcnr) * 1000 *
- ((s->rttr & 0xffff) + 1)) >> 15));
- } else {
- timer_del(s->rtc_alarm);
- }
-}
-
-static inline void strongarm_rtc_alarm_tick(void *opaque)
-{
- StrongARMRTCState *s = opaque;
- s->rtsr |= RTSR_AL;
- strongarm_rtc_timer_update(s);
- strongarm_rtc_int_update(s);
-}
-
-static inline void strongarm_rtc_hz_tick(void *opaque)
-{
- StrongARMRTCState *s = opaque;
- s->rtsr |= RTSR_HZ;
- strongarm_rtc_timer_update(s);
- strongarm_rtc_int_update(s);
-}
-
-static uint64_t strongarm_rtc_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- StrongARMRTCState *s = opaque;
-
- switch (addr) {
- case RTTR:
- return s->rttr;
- case RTSR:
- return s->rtsr;
- case RTAR:
- return s->rtar;
- case RCNR:
- return s->last_rcnr +
- ((qemu_clock_get_ms(rtc_clock) - s->last_hz) << 15) /
- (1000 * ((s->rttr & 0xffff) + 1));
- default:
- printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr);
- return 0;
- }
-}
-
-static void strongarm_rtc_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- StrongARMRTCState *s = opaque;
- uint32_t old_rtsr;
-
- switch (addr) {
- case RTTR:
- strongarm_rtc_hzupdate(s);
- s->rttr = value;
- strongarm_rtc_timer_update(s);
- break;
-
- case RTSR:
- old_rtsr = s->rtsr;
- s->rtsr = (value & (RTSR_ALE | RTSR_HZE)) |
- (s->rtsr & ~(value & (RTSR_AL | RTSR_HZ)));
-
- if (s->rtsr != old_rtsr) {
- strongarm_rtc_timer_update(s);
- }
-
- strongarm_rtc_int_update(s);
- break;
-
- case RTAR:
- s->rtar = value;
- strongarm_rtc_timer_update(s);
- break;
-
- case RCNR:
- strongarm_rtc_hzupdate(s);
- s->last_rcnr = value;
- strongarm_rtc_timer_update(s);
- break;
-
- default:
- printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr);
- }
-}
-
-static const MemoryRegionOps strongarm_rtc_ops = {
- .read = strongarm_rtc_read,
- .write = strongarm_rtc_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int strongarm_rtc_init(SysBusDevice *dev)
-{
- StrongARMRTCState *s = STRONGARM_RTC(dev);
- struct tm tm;
-
- s->rttr = 0x0;
- s->rtsr = 0;
-
- qemu_get_timedate(&tm, 0);
-
- s->last_rcnr = (uint32_t) mktimegm(&tm);
- s->last_hz = qemu_clock_get_ms(rtc_clock);
-
- s->rtc_alarm = timer_new_ms(rtc_clock, strongarm_rtc_alarm_tick, s);
- s->rtc_hz = timer_new_ms(rtc_clock, strongarm_rtc_hz_tick, s);
-
- sysbus_init_irq(dev, &s->rtc_irq);
- sysbus_init_irq(dev, &s->rtc_hz_irq);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &strongarm_rtc_ops, s,
- "rtc", 0x10000);
- sysbus_init_mmio(dev, &s->iomem);
-
- return 0;
-}
-
-static void strongarm_rtc_pre_save(void *opaque)
-{
- StrongARMRTCState *s = opaque;
-
- strongarm_rtc_hzupdate(s);
-}
-
-static int strongarm_rtc_post_load(void *opaque, int version_id)
-{
- StrongARMRTCState *s = opaque;
-
- strongarm_rtc_timer_update(s);
- strongarm_rtc_int_update(s);
-
- return 0;
-}
-
-static const VMStateDescription vmstate_strongarm_rtc_regs = {
- .name = "strongarm-rtc",
- .version_id = 0,
- .minimum_version_id = 0,
- .pre_save = strongarm_rtc_pre_save,
- .post_load = strongarm_rtc_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(rttr, StrongARMRTCState),
- VMSTATE_UINT32(rtsr, StrongARMRTCState),
- VMSTATE_UINT32(rtar, StrongARMRTCState),
- VMSTATE_UINT32(last_rcnr, StrongARMRTCState),
- VMSTATE_INT64(last_hz, StrongARMRTCState),
- VMSTATE_END_OF_LIST(),
- },
-};
-
-static void strongarm_rtc_sysbus_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = strongarm_rtc_init;
- dc->desc = "StrongARM RTC Controller";
- dc->vmsd = &vmstate_strongarm_rtc_regs;
-}
-
-static const TypeInfo strongarm_rtc_sysbus_info = {
- .name = TYPE_STRONGARM_RTC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(StrongARMRTCState),
- .class_init = strongarm_rtc_sysbus_class_init,
-};
-
-/* GPIO */
-#define GPLR 0x00
-#define GPDR 0x04
-#define GPSR 0x08
-#define GPCR 0x0c
-#define GRER 0x10
-#define GFER 0x14
-#define GEDR 0x18
-#define GAFR 0x1c
-
-#define TYPE_STRONGARM_GPIO "strongarm-gpio"
-#define STRONGARM_GPIO(obj) \
- OBJECT_CHECK(StrongARMGPIOInfo, (obj), TYPE_STRONGARM_GPIO)
-
-typedef struct StrongARMGPIOInfo StrongARMGPIOInfo;
-struct StrongARMGPIOInfo {
- SysBusDevice busdev;
- MemoryRegion iomem;
- qemu_irq handler[28];
- qemu_irq irqs[11];
- qemu_irq irqX;
-
- uint32_t ilevel;
- uint32_t olevel;
- uint32_t dir;
- uint32_t rising;
- uint32_t falling;
- uint32_t status;
- uint32_t gafr;
-
- uint32_t prev_level;
-};
-
-
-static void strongarm_gpio_irq_update(StrongARMGPIOInfo *s)
-{
- int i;
- for (i = 0; i < 11; i++) {
- qemu_set_irq(s->irqs[i], s->status & (1 << i));
- }
-
- qemu_set_irq(s->irqX, (s->status & ~0x7ff));
-}
-
-static void strongarm_gpio_set(void *opaque, int line, int level)
-{
- StrongARMGPIOInfo *s = opaque;
- uint32_t mask;
-
- mask = 1 << line;
-
- if (level) {
- s->status |= s->rising & mask &
- ~s->ilevel & ~s->dir;
- s->ilevel |= mask;
- } else {
- s->status |= s->falling & mask &
- s->ilevel & ~s->dir;
- s->ilevel &= ~mask;
- }
-
- if (s->status & mask) {
- strongarm_gpio_irq_update(s);
- }
-}
-
-static void strongarm_gpio_handler_update(StrongARMGPIOInfo *s)
-{
- uint32_t level, diff;
- int bit;
-
- level = s->olevel & s->dir;
-
- for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) {
- bit = ctz32(diff);
- qemu_set_irq(s->handler[bit], (level >> bit) & 1);
- }
-
- s->prev_level = level;
-}
-
-static uint64_t strongarm_gpio_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- StrongARMGPIOInfo *s = opaque;
-
- switch (offset) {
- case GPDR: /* GPIO Pin-Direction registers */
- return s->dir;
-
- case GPSR: /* GPIO Pin-Output Set registers */
- qemu_log_mask(LOG_GUEST_ERROR,
- "strongarm GPIO: read from write only register GPSR\n");
- return 0;
-
- case GPCR: /* GPIO Pin-Output Clear registers */
- qemu_log_mask(LOG_GUEST_ERROR,
- "strongarm GPIO: read from write only register GPCR\n");
- return 0;
-
- case GRER: /* GPIO Rising-Edge Detect Enable registers */
- return s->rising;
-
- case GFER: /* GPIO Falling-Edge Detect Enable registers */
- return s->falling;
-
- case GAFR: /* GPIO Alternate Function registers */
- return s->gafr;
-
- case GPLR: /* GPIO Pin-Level registers */
- return (s->olevel & s->dir) |
- (s->ilevel & ~s->dir);
-
- case GEDR: /* GPIO Edge Detect Status registers */
- return s->status;
-
- default:
- printf("%s: Bad offset 0x" TARGET_FMT_plx "\n", __func__, offset);
- }
-
- return 0;
-}
-
-static void strongarm_gpio_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- StrongARMGPIOInfo *s = opaque;
-
- switch (offset) {
- case GPDR: /* GPIO Pin-Direction registers */
- s->dir = value;
- strongarm_gpio_handler_update(s);
- break;
-
- case GPSR: /* GPIO Pin-Output Set registers */
- s->olevel |= value;
- strongarm_gpio_handler_update(s);
- break;
-
- case GPCR: /* GPIO Pin-Output Clear registers */
- s->olevel &= ~value;
- strongarm_gpio_handler_update(s);
- break;
-
- case GRER: /* GPIO Rising-Edge Detect Enable registers */
- s->rising = value;
- break;
-
- case GFER: /* GPIO Falling-Edge Detect Enable registers */
- s->falling = value;
- break;
-
- case GAFR: /* GPIO Alternate Function registers */
- s->gafr = value;
- break;
-
- case GEDR: /* GPIO Edge Detect Status registers */
- s->status &= ~value;
- strongarm_gpio_irq_update(s);
- break;
-
- default:
- printf("%s: Bad offset 0x" TARGET_FMT_plx "\n", __func__, offset);
- }
-}
-
-static const MemoryRegionOps strongarm_gpio_ops = {
- .read = strongarm_gpio_read,
- .write = strongarm_gpio_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static DeviceState *strongarm_gpio_init(hwaddr base,
- DeviceState *pic)
-{
- DeviceState *dev;
- int i;
-
- dev = qdev_create(NULL, TYPE_STRONGARM_GPIO);
- qdev_init_nofail(dev);
-
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
- for (i = 0; i < 12; i++)
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), i,
- qdev_get_gpio_in(pic, SA_PIC_GPIO0_EDGE + i));
-
- return dev;
-}
-
-static int strongarm_gpio_initfn(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- StrongARMGPIOInfo *s = STRONGARM_GPIO(dev);
- int i;
-
- qdev_init_gpio_in(dev, strongarm_gpio_set, 28);
- qdev_init_gpio_out(dev, s->handler, 28);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &strongarm_gpio_ops, s,
- "gpio", 0x1000);
-
- sysbus_init_mmio(sbd, &s->iomem);
- for (i = 0; i < 11; i++) {
- sysbus_init_irq(sbd, &s->irqs[i]);
- }
- sysbus_init_irq(sbd, &s->irqX);
-
- return 0;
-}
-
-static const VMStateDescription vmstate_strongarm_gpio_regs = {
- .name = "strongarm-gpio",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(ilevel, StrongARMGPIOInfo),
- VMSTATE_UINT32(olevel, StrongARMGPIOInfo),
- VMSTATE_UINT32(dir, StrongARMGPIOInfo),
- VMSTATE_UINT32(rising, StrongARMGPIOInfo),
- VMSTATE_UINT32(falling, StrongARMGPIOInfo),
- VMSTATE_UINT32(status, StrongARMGPIOInfo),
- VMSTATE_UINT32(gafr, StrongARMGPIOInfo),
- VMSTATE_UINT32(prev_level, StrongARMGPIOInfo),
- VMSTATE_END_OF_LIST(),
- },
-};
-
-static void strongarm_gpio_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = strongarm_gpio_initfn;
- dc->desc = "StrongARM GPIO controller";
- dc->vmsd = &vmstate_strongarm_gpio_regs;
-}
-
-static const TypeInfo strongarm_gpio_info = {
- .name = TYPE_STRONGARM_GPIO,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(StrongARMGPIOInfo),
- .class_init = strongarm_gpio_class_init,
-};
-
-/* Peripheral Pin Controller */
-#define PPDR 0x00
-#define PPSR 0x04
-#define PPAR 0x08
-#define PSDR 0x0c
-#define PPFR 0x10
-
-#define TYPE_STRONGARM_PPC "strongarm-ppc"
-#define STRONGARM_PPC(obj) \
- OBJECT_CHECK(StrongARMPPCInfo, (obj), TYPE_STRONGARM_PPC)
-
-typedef struct StrongARMPPCInfo StrongARMPPCInfo;
-struct StrongARMPPCInfo {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- qemu_irq handler[28];
-
- uint32_t ilevel;
- uint32_t olevel;
- uint32_t dir;
- uint32_t ppar;
- uint32_t psdr;
- uint32_t ppfr;
-
- uint32_t prev_level;
-};
-
-static void strongarm_ppc_set(void *opaque, int line, int level)
-{
- StrongARMPPCInfo *s = opaque;
-
- if (level) {
- s->ilevel |= 1 << line;
- } else {
- s->ilevel &= ~(1 << line);
- }
-}
-
-static void strongarm_ppc_handler_update(StrongARMPPCInfo *s)
-{
- uint32_t level, diff;
- int bit;
-
- level = s->olevel & s->dir;
-
- for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) {
- bit = ctz32(diff);
- qemu_set_irq(s->handler[bit], (level >> bit) & 1);
- }
-
- s->prev_level = level;
-}
-
-static uint64_t strongarm_ppc_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- StrongARMPPCInfo *s = opaque;
-
- switch (offset) {
- case PPDR: /* PPC Pin Direction registers */
- return s->dir | ~0x3fffff;
-
- case PPSR: /* PPC Pin State registers */
- return (s->olevel & s->dir) |
- (s->ilevel & ~s->dir) |
- ~0x3fffff;
-
- case PPAR:
- return s->ppar | ~0x41000;
-
- case PSDR:
- return s->psdr;
-
- case PPFR:
- return s->ppfr | ~0x7f001;
-
- default:
- printf("%s: Bad offset 0x" TARGET_FMT_plx "\n", __func__, offset);
- }
-
- return 0;
-}
-
-static void strongarm_ppc_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- StrongARMPPCInfo *s = opaque;
-
- switch (offset) {
- case PPDR: /* PPC Pin Direction registers */
- s->dir = value & 0x3fffff;
- strongarm_ppc_handler_update(s);
- break;
-
- case PPSR: /* PPC Pin State registers */
- s->olevel = value & s->dir & 0x3fffff;
- strongarm_ppc_handler_update(s);
- break;
-
- case PPAR:
- s->ppar = value & 0x41000;
- break;
-
- case PSDR:
- s->psdr = value & 0x3fffff;
- break;
-
- case PPFR:
- s->ppfr = value & 0x7f001;
- break;
-
- default:
- printf("%s: Bad offset 0x" TARGET_FMT_plx "\n", __func__, offset);
- }
-}
-
-static const MemoryRegionOps strongarm_ppc_ops = {
- .read = strongarm_ppc_read,
- .write = strongarm_ppc_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int strongarm_ppc_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- StrongARMPPCInfo *s = STRONGARM_PPC(dev);
-
- qdev_init_gpio_in(dev, strongarm_ppc_set, 22);
- qdev_init_gpio_out(dev, s->handler, 22);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &strongarm_ppc_ops, s,
- "ppc", 0x1000);
-
- sysbus_init_mmio(sbd, &s->iomem);
-
- return 0;
-}
-
-static const VMStateDescription vmstate_strongarm_ppc_regs = {
- .name = "strongarm-ppc",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(ilevel, StrongARMPPCInfo),
- VMSTATE_UINT32(olevel, StrongARMPPCInfo),
- VMSTATE_UINT32(dir, StrongARMPPCInfo),
- VMSTATE_UINT32(ppar, StrongARMPPCInfo),
- VMSTATE_UINT32(psdr, StrongARMPPCInfo),
- VMSTATE_UINT32(ppfr, StrongARMPPCInfo),
- VMSTATE_UINT32(prev_level, StrongARMPPCInfo),
- VMSTATE_END_OF_LIST(),
- },
-};
-
-static void strongarm_ppc_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = strongarm_ppc_init;
- dc->desc = "StrongARM PPC controller";
- dc->vmsd = &vmstate_strongarm_ppc_regs;
-}
-
-static const TypeInfo strongarm_ppc_info = {
- .name = TYPE_STRONGARM_PPC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(StrongARMPPCInfo),
- .class_init = strongarm_ppc_class_init,
-};
-
-/* UART Ports */
-#define UTCR0 0x00
-#define UTCR1 0x04
-#define UTCR2 0x08
-#define UTCR3 0x0c
-#define UTDR 0x14
-#define UTSR0 0x1c
-#define UTSR1 0x20
-
-#define UTCR0_PE (1 << 0) /* Parity enable */
-#define UTCR0_OES (1 << 1) /* Even parity */
-#define UTCR0_SBS (1 << 2) /* 2 stop bits */
-#define UTCR0_DSS (1 << 3) /* 8-bit data */
-
-#define UTCR3_RXE (1 << 0) /* Rx enable */
-#define UTCR3_TXE (1 << 1) /* Tx enable */
-#define UTCR3_BRK (1 << 2) /* Force Break */
-#define UTCR3_RIE (1 << 3) /* Rx int enable */
-#define UTCR3_TIE (1 << 4) /* Tx int enable */
-#define UTCR3_LBM (1 << 5) /* Loopback */
-
-#define UTSR0_TFS (1 << 0) /* Tx FIFO nearly empty */
-#define UTSR0_RFS (1 << 1) /* Rx FIFO nearly full */
-#define UTSR0_RID (1 << 2) /* Receiver Idle */
-#define UTSR0_RBB (1 << 3) /* Receiver begin break */
-#define UTSR0_REB (1 << 4) /* Receiver end break */
-#define UTSR0_EIF (1 << 5) /* Error in FIFO */
-
-#define UTSR1_RNE (1 << 1) /* Receive FIFO not empty */
-#define UTSR1_TNF (1 << 2) /* Transmit FIFO not full */
-#define UTSR1_PRE (1 << 3) /* Parity error */
-#define UTSR1_FRE (1 << 4) /* Frame error */
-#define UTSR1_ROR (1 << 5) /* Receive Over Run */
-
-#define RX_FIFO_PRE (1 << 8)
-#define RX_FIFO_FRE (1 << 9)
-#define RX_FIFO_ROR (1 << 10)
-
-#define TYPE_STRONGARM_UART "strongarm-uart"
-#define STRONGARM_UART(obj) \
- OBJECT_CHECK(StrongARMUARTState, (obj), TYPE_STRONGARM_UART)
-
-typedef struct StrongARMUARTState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- CharDriverState *chr;
- qemu_irq irq;
-
- uint8_t utcr0;
- uint16_t brd;
- uint8_t utcr3;
- uint8_t utsr0;
- uint8_t utsr1;
-
- uint8_t tx_fifo[8];
- uint8_t tx_start;
- uint8_t tx_len;
- uint16_t rx_fifo[12]; /* value + error flags in high bits */
- uint8_t rx_start;
- uint8_t rx_len;
-
- uint64_t char_transmit_time; /* time to transmit a char in ticks*/
- bool wait_break_end;
- QEMUTimer *rx_timeout_timer;
- QEMUTimer *tx_timer;
-} StrongARMUARTState;
-
-static void strongarm_uart_update_status(StrongARMUARTState *s)
-{
- uint16_t utsr1 = 0;
-
- if (s->tx_len != 8) {
- utsr1 |= UTSR1_TNF;
- }
-
- if (s->rx_len != 0) {
- uint16_t ent = s->rx_fifo[s->rx_start];
-
- utsr1 |= UTSR1_RNE;
- if (ent & RX_FIFO_PRE) {
- s->utsr1 |= UTSR1_PRE;
- }
- if (ent & RX_FIFO_FRE) {
- s->utsr1 |= UTSR1_FRE;
- }
- if (ent & RX_FIFO_ROR) {
- s->utsr1 |= UTSR1_ROR;
- }
- }
-
- s->utsr1 = utsr1;
-}
-
-static void strongarm_uart_update_int_status(StrongARMUARTState *s)
-{
- uint16_t utsr0 = s->utsr0 &
- (UTSR0_REB | UTSR0_RBB | UTSR0_RID);
- int i;
-
- if ((s->utcr3 & UTCR3_TXE) &&
- (s->utcr3 & UTCR3_TIE) &&
- s->tx_len <= 4) {
- utsr0 |= UTSR0_TFS;
- }
-
- if ((s->utcr3 & UTCR3_RXE) &&
- (s->utcr3 & UTCR3_RIE) &&
- s->rx_len > 4) {
- utsr0 |= UTSR0_RFS;
- }
-
- for (i = 0; i < s->rx_len && i < 4; i++)
- if (s->rx_fifo[(s->rx_start + i) % 12] & ~0xff) {
- utsr0 |= UTSR0_EIF;
- break;
- }
-
- s->utsr0 = utsr0;
- qemu_set_irq(s->irq, utsr0);
-}
-
-static void strongarm_uart_update_parameters(StrongARMUARTState *s)
-{
- int speed, parity, data_bits, stop_bits, frame_size;
- QEMUSerialSetParams ssp;
-
- /* Start bit. */
- frame_size = 1;
- if (s->utcr0 & UTCR0_PE) {
- /* Parity bit. */
- frame_size++;
- if (s->utcr0 & UTCR0_OES) {
- parity = 'E';
- } else {
- parity = 'O';
- }
- } else {
- parity = 'N';
- }
- if (s->utcr0 & UTCR0_SBS) {
- stop_bits = 2;
- } else {
- stop_bits = 1;
- }
-
- data_bits = (s->utcr0 & UTCR0_DSS) ? 8 : 7;
- frame_size += data_bits + stop_bits;
- speed = 3686400 / 16 / (s->brd + 1);
- ssp.speed = speed;
- ssp.parity = parity;
- ssp.data_bits = data_bits;
- ssp.stop_bits = stop_bits;
- s->char_transmit_time = (NANOSECONDS_PER_SECOND / speed) * frame_size;
- if (s->chr) {
- qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
- }
-
- DPRINTF(stderr, "%s speed=%d parity=%c data=%d stop=%d\n", s->chr->label,
- speed, parity, data_bits, stop_bits);
-}
-
-static void strongarm_uart_rx_to(void *opaque)
-{
- StrongARMUARTState *s = opaque;
-
- if (s->rx_len) {
- s->utsr0 |= UTSR0_RID;
- strongarm_uart_update_int_status(s);
- }
-}
-
-static void strongarm_uart_rx_push(StrongARMUARTState *s, uint16_t c)
-{
- if ((s->utcr3 & UTCR3_RXE) == 0) {
- /* rx disabled */
- return;
- }
-
- if (s->wait_break_end) {
- s->utsr0 |= UTSR0_REB;
- s->wait_break_end = false;
- }
-
- if (s->rx_len < 12) {
- s->rx_fifo[(s->rx_start + s->rx_len) % 12] = c;
- s->rx_len++;
- } else
- s->rx_fifo[(s->rx_start + 11) % 12] |= RX_FIFO_ROR;
-}
-
-static int strongarm_uart_can_receive(void *opaque)
-{
- StrongARMUARTState *s = opaque;
-
- if (s->rx_len == 12) {
- return 0;
- }
- /* It's best not to get more than 2/3 of RX FIFO, so advertise that much */
- if (s->rx_len < 8) {
- return 8 - s->rx_len;
- }
- return 1;
-}
-
-static void strongarm_uart_receive(void *opaque, const uint8_t *buf, int size)
-{
- StrongARMUARTState *s = opaque;
- int i;
-
- for (i = 0; i < size; i++) {
- strongarm_uart_rx_push(s, buf[i]);
- }
-
- /* call the timeout receive callback in 3 char transmit time */
- timer_mod(s->rx_timeout_timer,
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->char_transmit_time * 3);
-
- strongarm_uart_update_status(s);
- strongarm_uart_update_int_status(s);
-}
-
-static void strongarm_uart_event(void *opaque, int event)
-{
- StrongARMUARTState *s = opaque;
- if (event == CHR_EVENT_BREAK) {
- s->utsr0 |= UTSR0_RBB;
- strongarm_uart_rx_push(s, RX_FIFO_FRE);
- s->wait_break_end = true;
- strongarm_uart_update_status(s);
- strongarm_uart_update_int_status(s);
- }
-}
-
-static void strongarm_uart_tx(void *opaque)
-{
- StrongARMUARTState *s = opaque;
- uint64_t new_xmit_ts = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-
- if (s->utcr3 & UTCR3_LBM) /* loopback */ {
- strongarm_uart_receive(s, &s->tx_fifo[s->tx_start], 1);
- } else if (s->chr) {
- qemu_chr_fe_write(s->chr, &s->tx_fifo[s->tx_start], 1);
- }
-
- s->tx_start = (s->tx_start + 1) % 8;
- s->tx_len--;
- if (s->tx_len) {
- timer_mod(s->tx_timer, new_xmit_ts + s->char_transmit_time);
- }
- strongarm_uart_update_status(s);
- strongarm_uart_update_int_status(s);
-}
-
-static uint64_t strongarm_uart_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- StrongARMUARTState *s = opaque;
- uint16_t ret;
-
- switch (addr) {
- case UTCR0:
- return s->utcr0;
-
- case UTCR1:
- return s->brd >> 8;
-
- case UTCR2:
- return s->brd & 0xff;
-
- case UTCR3:
- return s->utcr3;
-
- case UTDR:
- if (s->rx_len != 0) {
- ret = s->rx_fifo[s->rx_start];
- s->rx_start = (s->rx_start + 1) % 12;
- s->rx_len--;
- strongarm_uart_update_status(s);
- strongarm_uart_update_int_status(s);
- return ret;
- }
- return 0;
-
- case UTSR0:
- return s->utsr0;
-
- case UTSR1:
- return s->utsr1;
-
- default:
- printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr);
- return 0;
- }
-}
-
-static void strongarm_uart_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- StrongARMUARTState *s = opaque;
-
- switch (addr) {
- case UTCR0:
- s->utcr0 = value & 0x7f;
- strongarm_uart_update_parameters(s);
- break;
-
- case UTCR1:
- s->brd = (s->brd & 0xff) | ((value & 0xf) << 8);
- strongarm_uart_update_parameters(s);
- break;
-
- case UTCR2:
- s->brd = (s->brd & 0xf00) | (value & 0xff);
- strongarm_uart_update_parameters(s);
- break;
-
- case UTCR3:
- s->utcr3 = value & 0x3f;
- if ((s->utcr3 & UTCR3_RXE) == 0) {
- s->rx_len = 0;
- }
- if ((s->utcr3 & UTCR3_TXE) == 0) {
- s->tx_len = 0;
- }
- strongarm_uart_update_status(s);
- strongarm_uart_update_int_status(s);
- break;
-
- case UTDR:
- if ((s->utcr3 & UTCR3_TXE) && s->tx_len != 8) {
- s->tx_fifo[(s->tx_start + s->tx_len) % 8] = value;
- s->tx_len++;
- strongarm_uart_update_status(s);
- strongarm_uart_update_int_status(s);
- if (s->tx_len == 1) {
- strongarm_uart_tx(s);
- }
- }
- break;
-
- case UTSR0:
- s->utsr0 = s->utsr0 & ~(value &
- (UTSR0_REB | UTSR0_RBB | UTSR0_RID));
- strongarm_uart_update_int_status(s);
- break;
-
- default:
- printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr);
- }
-}
-
-static const MemoryRegionOps strongarm_uart_ops = {
- .read = strongarm_uart_read,
- .write = strongarm_uart_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int strongarm_uart_init(SysBusDevice *dev)
-{
- StrongARMUARTState *s = STRONGARM_UART(dev);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &strongarm_uart_ops, s,
- "uart", 0x10000);
- sysbus_init_mmio(dev, &s->iomem);
- sysbus_init_irq(dev, &s->irq);
-
- s->rx_timeout_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, strongarm_uart_rx_to, s);
- s->tx_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, strongarm_uart_tx, s);
-
- if (s->chr) {
- qemu_chr_add_handlers(s->chr,
- strongarm_uart_can_receive,
- strongarm_uart_receive,
- strongarm_uart_event,
- s);
- }
-
- return 0;
-}
-
-static void strongarm_uart_reset(DeviceState *dev)
-{
- StrongARMUARTState *s = STRONGARM_UART(dev);
-
- s->utcr0 = UTCR0_DSS; /* 8 data, no parity */
- s->brd = 23; /* 9600 */
- /* enable send & recv - this actually violates spec */
- s->utcr3 = UTCR3_TXE | UTCR3_RXE;
-
- s->rx_len = s->tx_len = 0;
-
- strongarm_uart_update_parameters(s);
- strongarm_uart_update_status(s);
- strongarm_uart_update_int_status(s);
-}
-
-static int strongarm_uart_post_load(void *opaque, int version_id)
-{
- StrongARMUARTState *s = opaque;
-
- strongarm_uart_update_parameters(s);
- strongarm_uart_update_status(s);
- strongarm_uart_update_int_status(s);
-
- /* tx and restart timer */
- if (s->tx_len) {
- strongarm_uart_tx(s);
- }
-
- /* restart rx timeout timer */
- if (s->rx_len) {
- timer_mod(s->rx_timeout_timer,
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->char_transmit_time * 3);
- }
-
- return 0;
-}
-
-static const VMStateDescription vmstate_strongarm_uart_regs = {
- .name = "strongarm-uart",
- .version_id = 0,
- .minimum_version_id = 0,
- .post_load = strongarm_uart_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(utcr0, StrongARMUARTState),
- VMSTATE_UINT16(brd, StrongARMUARTState),
- VMSTATE_UINT8(utcr3, StrongARMUARTState),
- VMSTATE_UINT8(utsr0, StrongARMUARTState),
- VMSTATE_UINT8_ARRAY(tx_fifo, StrongARMUARTState, 8),
- VMSTATE_UINT8(tx_start, StrongARMUARTState),
- VMSTATE_UINT8(tx_len, StrongARMUARTState),
- VMSTATE_UINT16_ARRAY(rx_fifo, StrongARMUARTState, 12),
- VMSTATE_UINT8(rx_start, StrongARMUARTState),
- VMSTATE_UINT8(rx_len, StrongARMUARTState),
- VMSTATE_BOOL(wait_break_end, StrongARMUARTState),
- VMSTATE_END_OF_LIST(),
- },
-};
-
-static Property strongarm_uart_properties[] = {
- DEFINE_PROP_CHR("chardev", StrongARMUARTState, chr),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void strongarm_uart_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = strongarm_uart_init;
- dc->desc = "StrongARM UART controller";
- dc->reset = strongarm_uart_reset;
- dc->vmsd = &vmstate_strongarm_uart_regs;
- dc->props = strongarm_uart_properties;
-}
-
-static const TypeInfo strongarm_uart_info = {
- .name = TYPE_STRONGARM_UART,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(StrongARMUARTState),
- .class_init = strongarm_uart_class_init,
-};
-
-/* Synchronous Serial Ports */
-
-#define TYPE_STRONGARM_SSP "strongarm-ssp"
-#define STRONGARM_SSP(obj) \
- OBJECT_CHECK(StrongARMSSPState, (obj), TYPE_STRONGARM_SSP)
-
-typedef struct StrongARMSSPState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- qemu_irq irq;
- SSIBus *bus;
-
- uint16_t sscr[2];
- uint16_t sssr;
-
- uint16_t rx_fifo[8];
- uint8_t rx_level;
- uint8_t rx_start;
-} StrongARMSSPState;
-
-#define SSCR0 0x60 /* SSP Control register 0 */
-#define SSCR1 0x64 /* SSP Control register 1 */
-#define SSDR 0x6c /* SSP Data register */
-#define SSSR 0x74 /* SSP Status register */
-
-/* Bitfields for above registers */
-#define SSCR0_SPI(x) (((x) & 0x30) == 0x00)
-#define SSCR0_SSP(x) (((x) & 0x30) == 0x10)
-#define SSCR0_UWIRE(x) (((x) & 0x30) == 0x20)
-#define SSCR0_PSP(x) (((x) & 0x30) == 0x30)
-#define SSCR0_SSE (1 << 7)
-#define SSCR0_DSS(x) (((x) & 0xf) + 1)
-#define SSCR1_RIE (1 << 0)
-#define SSCR1_TIE (1 << 1)
-#define SSCR1_LBM (1 << 2)
-#define SSSR_TNF (1 << 2)
-#define SSSR_RNE (1 << 3)
-#define SSSR_TFS (1 << 5)
-#define SSSR_RFS (1 << 6)
-#define SSSR_ROR (1 << 7)
-#define SSSR_RW 0x0080
-
-static void strongarm_ssp_int_update(StrongARMSSPState *s)
-{
- int level = 0;
-
- level |= (s->sssr & SSSR_ROR);
- level |= (s->sssr & SSSR_RFS) && (s->sscr[1] & SSCR1_RIE);
- level |= (s->sssr & SSSR_TFS) && (s->sscr[1] & SSCR1_TIE);
- qemu_set_irq(s->irq, level);
-}
-
-static void strongarm_ssp_fifo_update(StrongARMSSPState *s)
-{
- s->sssr &= ~SSSR_TFS;
- s->sssr &= ~SSSR_TNF;
- if (s->sscr[0] & SSCR0_SSE) {
- if (s->rx_level >= 4) {
- s->sssr |= SSSR_RFS;
- } else {
- s->sssr &= ~SSSR_RFS;
- }
- if (s->rx_level) {
- s->sssr |= SSSR_RNE;
- } else {
- s->sssr &= ~SSSR_RNE;
- }
- /* TX FIFO is never filled, so it is always in underrun
- condition if SSP is enabled */
- s->sssr |= SSSR_TFS;
- s->sssr |= SSSR_TNF;
- }
-
- strongarm_ssp_int_update(s);
-}
-
-static uint64_t strongarm_ssp_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- StrongARMSSPState *s = opaque;
- uint32_t retval;
-
- switch (addr) {
- case SSCR0:
- return s->sscr[0];
- case SSCR1:
- return s->sscr[1];
- case SSSR:
- return s->sssr;
- case SSDR:
- if (~s->sscr[0] & SSCR0_SSE) {
- return 0xffffffff;
- }
- if (s->rx_level < 1) {
- printf("%s: SSP Rx Underrun\n", __func__);
- return 0xffffffff;
- }
- s->rx_level--;
- retval = s->rx_fifo[s->rx_start++];
- s->rx_start &= 0x7;
- strongarm_ssp_fifo_update(s);
- return retval;
- default:
- printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr);
- break;
- }
- return 0;
-}
-
-static void strongarm_ssp_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- StrongARMSSPState *s = opaque;
-
- switch (addr) {
- case SSCR0:
- s->sscr[0] = value & 0xffbf;
- if ((s->sscr[0] & SSCR0_SSE) && SSCR0_DSS(value) < 4) {
- printf("%s: Wrong data size: %i bits\n", __func__,
- (int)SSCR0_DSS(value));
- }
- if (!(value & SSCR0_SSE)) {
- s->sssr = 0;
- s->rx_level = 0;
- }
- strongarm_ssp_fifo_update(s);
- break;
-
- case SSCR1:
- s->sscr[1] = value & 0x2f;
- if (value & SSCR1_LBM) {
- printf("%s: Attempt to use SSP LBM mode\n", __func__);
- }
- strongarm_ssp_fifo_update(s);
- break;
-
- case SSSR:
- s->sssr &= ~(value & SSSR_RW);
- strongarm_ssp_int_update(s);
- break;
-
- case SSDR:
- if (SSCR0_UWIRE(s->sscr[0])) {
- value &= 0xff;
- } else
- /* Note how 32bits overflow does no harm here */
- value &= (1 << SSCR0_DSS(s->sscr[0])) - 1;
-
- /* Data goes from here to the Tx FIFO and is shifted out from
- * there directly to the slave, no need to buffer it.
- */
- if (s->sscr[0] & SSCR0_SSE) {
- uint32_t readval;
- if (s->sscr[1] & SSCR1_LBM) {
- readval = value;
- } else {
- readval = ssi_transfer(s->bus, value);
- }
-
- if (s->rx_level < 0x08) {
- s->rx_fifo[(s->rx_start + s->rx_level++) & 0x7] = readval;
- } else {
- s->sssr |= SSSR_ROR;
- }
- }
- strongarm_ssp_fifo_update(s);
- break;
-
- default:
- printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr);
- break;
- }
-}
-
-static const MemoryRegionOps strongarm_ssp_ops = {
- .read = strongarm_ssp_read,
- .write = strongarm_ssp_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int strongarm_ssp_post_load(void *opaque, int version_id)
-{
- StrongARMSSPState *s = opaque;
-
- strongarm_ssp_fifo_update(s);
-
- return 0;
-}
-
-static int strongarm_ssp_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- StrongARMSSPState *s = STRONGARM_SSP(dev);
-
- sysbus_init_irq(sbd, &s->irq);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &strongarm_ssp_ops, s,
- "ssp", 0x1000);
- sysbus_init_mmio(sbd, &s->iomem);
-
- s->bus = ssi_create_bus(dev, "ssi");
- return 0;
-}
-
-static void strongarm_ssp_reset(DeviceState *dev)
-{
- StrongARMSSPState *s = STRONGARM_SSP(dev);
-
- s->sssr = 0x03; /* 3 bit data, SPI, disabled */
- s->rx_start = 0;
- s->rx_level = 0;
-}
-
-static const VMStateDescription vmstate_strongarm_ssp_regs = {
- .name = "strongarm-ssp",
- .version_id = 0,
- .minimum_version_id = 0,
- .post_load = strongarm_ssp_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT16_ARRAY(sscr, StrongARMSSPState, 2),
- VMSTATE_UINT16(sssr, StrongARMSSPState),
- VMSTATE_UINT16_ARRAY(rx_fifo, StrongARMSSPState, 8),
- VMSTATE_UINT8(rx_start, StrongARMSSPState),
- VMSTATE_UINT8(rx_level, StrongARMSSPState),
- VMSTATE_END_OF_LIST(),
- },
-};
-
-static void strongarm_ssp_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = strongarm_ssp_init;
- dc->desc = "StrongARM SSP controller";
- dc->reset = strongarm_ssp_reset;
- dc->vmsd = &vmstate_strongarm_ssp_regs;
-}
-
-static const TypeInfo strongarm_ssp_info = {
- .name = TYPE_STRONGARM_SSP,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(StrongARMSSPState),
- .class_init = strongarm_ssp_class_init,
-};
-
-/* Main CPU functions */
-StrongARMState *sa1110_init(MemoryRegion *sysmem,
- unsigned int sdram_size, const char *rev)
-{
- StrongARMState *s;
- int i;
-
- s = g_new0(StrongARMState, 1);
-
- if (!rev) {
- rev = "sa1110-b5";
- }
-
- if (strncmp(rev, "sa1110", 6)) {
- error_report("Machine requires a SA1110 processor.");
- exit(1);
- }
-
- s->cpu = cpu_arm_init(rev);
-
- if (!s->cpu) {
- error_report("Unable to find CPU definition");
- exit(1);
- }
-
- memory_region_allocate_system_memory(&s->sdram, NULL, "strongarm.sdram",
- sdram_size);
- memory_region_add_subregion(sysmem, SA_SDCS0, &s->sdram);
-
- s->pic = sysbus_create_varargs("strongarm_pic", 0x90050000,
- qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_IRQ),
- qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_FIQ),
- NULL);
-
- sysbus_create_varargs("pxa25x-timer", 0x90000000,
- qdev_get_gpio_in(s->pic, SA_PIC_OSTC0),
- qdev_get_gpio_in(s->pic, SA_PIC_OSTC1),
- qdev_get_gpio_in(s->pic, SA_PIC_OSTC2),
- qdev_get_gpio_in(s->pic, SA_PIC_OSTC3),
- NULL);
-
- sysbus_create_simple(TYPE_STRONGARM_RTC, 0x90010000,
- qdev_get_gpio_in(s->pic, SA_PIC_RTC_ALARM));
-
- s->gpio = strongarm_gpio_init(0x90040000, s->pic);
-
- s->ppc = sysbus_create_varargs(TYPE_STRONGARM_PPC, 0x90060000, NULL);
-
- for (i = 0; sa_serial[i].io_base; i++) {
- DeviceState *dev = qdev_create(NULL, TYPE_STRONGARM_UART);
- qdev_prop_set_chr(dev, "chardev", serial_hds[i]);
- qdev_init_nofail(dev);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0,
- sa_serial[i].io_base);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0,
- qdev_get_gpio_in(s->pic, sa_serial[i].irq));
- }
-
- s->ssp = sysbus_create_varargs(TYPE_STRONGARM_SSP, 0x80070000,
- qdev_get_gpio_in(s->pic, SA_PIC_SSP), NULL);
- s->ssp_bus = (SSIBus *)qdev_get_child_bus(s->ssp, "ssi");
-
- return s;
-}
-
-static void strongarm_register_types(void)
-{
- type_register_static(&strongarm_pic_info);
- type_register_static(&strongarm_rtc_sysbus_info);
- type_register_static(&strongarm_gpio_info);
- type_register_static(&strongarm_ppc_info);
- type_register_static(&strongarm_uart_info);
- type_register_static(&strongarm_ssp_info);
-}
-
-type_init(strongarm_register_types)
diff --git a/qemu/hw/arm/strongarm.h b/qemu/hw/arm/strongarm.h
deleted file mode 100644
index 2893f9444..000000000
--- a/qemu/hw/arm/strongarm.h
+++ /dev/null
@@ -1,68 +0,0 @@
-#ifndef _STRONGARM_H
-#define _STRONGARM_H
-
-#include "exec/memory.h"
-
-#define SA_CS0 0x00000000
-#define SA_CS1 0x08000000
-#define SA_CS2 0x10000000
-#define SA_CS3 0x18000000
-#define SA_PCMCIA_CS0 0x20000000
-#define SA_PCMCIA_CS1 0x30000000
-#define SA_CS4 0x40000000
-#define SA_CS5 0x48000000
-/* system registers here */
-#define SA_SDCS0 0xc0000000
-#define SA_SDCS1 0xc8000000
-#define SA_SDCS2 0xd0000000
-#define SA_SDCS3 0xd8000000
-
-enum {
- SA_PIC_GPIO0_EDGE = 0,
- SA_PIC_GPIO1_EDGE,
- SA_PIC_GPIO2_EDGE,
- SA_PIC_GPIO3_EDGE,
- SA_PIC_GPIO4_EDGE,
- SA_PIC_GPIO5_EDGE,
- SA_PIC_GPIO6_EDGE,
- SA_PIC_GPIO7_EDGE,
- SA_PIC_GPIO8_EDGE,
- SA_PIC_GPIO9_EDGE,
- SA_PIC_GPIO10_EDGE,
- SA_PIC_GPIOX_EDGE,
- SA_PIC_LCD,
- SA_PIC_UDC,
- SA_PIC_RSVD1,
- SA_PIC_UART1,
- SA_PIC_UART2,
- SA_PIC_UART3,
- SA_PIC_MCP,
- SA_PIC_SSP,
- SA_PIC_DMA_CH0,
- SA_PIC_DMA_CH1,
- SA_PIC_DMA_CH2,
- SA_PIC_DMA_CH3,
- SA_PIC_DMA_CH4,
- SA_PIC_DMA_CH5,
- SA_PIC_OSTC0,
- SA_PIC_OSTC1,
- SA_PIC_OSTC2,
- SA_PIC_OSTC3,
- SA_PIC_RTC_HZ,
- SA_PIC_RTC_ALARM,
-};
-
-typedef struct {
- ARMCPU *cpu;
- MemoryRegion sdram;
- DeviceState *pic;
- DeviceState *gpio;
- DeviceState *ppc;
- DeviceState *ssp;
- SSIBus *ssp_bus;
-} StrongARMState;
-
-StrongARMState *sa1110_init(MemoryRegion *sysmem,
- unsigned int sdram_size, const char *rev);
-
-#endif
diff --git a/qemu/hw/arm/sysbus-fdt.c b/qemu/hw/arm/sysbus-fdt.c
deleted file mode 100644
index 5debb3348..000000000
--- a/qemu/hw/arm/sysbus-fdt.c
+++ /dev/null
@@ -1,542 +0,0 @@
-/*
- * ARM Platform Bus device tree generation helpers
- *
- * Copyright (c) 2014 Linaro Limited
- *
- * Authors:
- * Alex Graf <agraf@suse.de>
- * Eric Auger <eric.auger@linaro.org>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2 or later, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include <libfdt.h>
-#include "qemu-common.h"
-#ifdef CONFIG_LINUX
-#include <linux/vfio.h>
-#endif
-#include "hw/arm/sysbus-fdt.h"
-#include "qemu/error-report.h"
-#include "sysemu/device_tree.h"
-#include "hw/platform-bus.h"
-#include "sysemu/sysemu.h"
-#include "hw/vfio/vfio-platform.h"
-#include "hw/vfio/vfio-calxeda-xgmac.h"
-#include "hw/vfio/vfio-amd-xgbe.h"
-#include "hw/arm/fdt.h"
-
-/*
- * internal struct that contains the information to create dynamic
- * sysbus device node
- */
-typedef struct PlatformBusFDTData {
- void *fdt; /* device tree handle */
- int irq_start; /* index of the first IRQ usable by platform bus devices */
- const char *pbus_node_name; /* name of the platform bus node */
- PlatformBusDevice *pbus;
-} PlatformBusFDTData;
-
-/*
- * struct used when calling the machine init done notifier
- * that constructs the fdt nodes of platform bus devices
- */
-typedef struct PlatformBusFDTNotifierParams {
- Notifier notifier;
- ARMPlatformBusFDTParams *fdt_params;
-} PlatformBusFDTNotifierParams;
-
-/* struct that associates a device type name and a node creation function */
-typedef struct NodeCreationPair {
- const char *typename;
- int (*add_fdt_node_fn)(SysBusDevice *sbdev, void *opaque);
-} NodeCreationPair;
-
-/* helpers */
-
-typedef struct HostProperty {
- const char *name;
- bool optional;
-} HostProperty;
-
-#ifdef CONFIG_LINUX
-
-/**
- * copy_properties_from_host
- *
- * copies properties listed in an array from host device tree to
- * guest device tree. If a non optional property is not found, the
- * function asserts. An optional property is ignored if not found
- * in the host device tree.
- * @props: array of HostProperty to copy
- * @nb_props: number of properties in the array
- * @host_dt: host device tree blob
- * @guest_dt: guest device tree blob
- * @node_path: host dt node path where the property is supposed to be
- found
- * @nodename: guest node name the properties should be added to
- */
-static void copy_properties_from_host(HostProperty *props, int nb_props,
- void *host_fdt, void *guest_fdt,
- char *node_path, char *nodename)
-{
- int i, prop_len;
- const void *r;
- Error *err = NULL;
-
- for (i = 0; i < nb_props; i++) {
- r = qemu_fdt_getprop(host_fdt, node_path,
- props[i].name,
- &prop_len,
- props[i].optional ? &err : &error_fatal);
- if (r) {
- qemu_fdt_setprop(guest_fdt, nodename,
- props[i].name, r, prop_len);
- } else {
- if (prop_len != -FDT_ERR_NOTFOUND) {
- /* optional property not returned although property exists */
- error_report_err(err);
- } else {
- error_free(err);
- }
- }
- }
-}
-
-/* clock properties whose values are copied/pasted from host */
-static HostProperty clock_copied_properties[] = {
- {"compatible", false},
- {"#clock-cells", false},
- {"clock-frequency", true},
- {"clock-output-names", true},
-};
-
-/**
- * fdt_build_clock_node
- *
- * Build a guest clock node, used as a dependency from a passthrough'ed
- * device. Most information are retrieved from the host clock node.
- * Also check the host clock is a fixed one.
- *
- * @host_fdt: host device tree blob from which info are retrieved
- * @guest_fdt: guest device tree blob where the clock node is added
- * @host_phandle: phandle of the clock in host device tree
- * @guest_phandle: phandle to assign to the guest node
- */
-static void fdt_build_clock_node(void *host_fdt, void *guest_fdt,
- uint32_t host_phandle,
- uint32_t guest_phandle)
-{
- char *node_path = NULL;
- char *nodename;
- const void *r;
- int ret, node_offset, prop_len, path_len = 16;
-
- node_offset = fdt_node_offset_by_phandle(host_fdt, host_phandle);
- if (node_offset <= 0) {
- error_setg(&error_fatal,
- "not able to locate clock handle %d in host device tree",
- host_phandle);
- }
- node_path = g_malloc(path_len);
- while ((ret = fdt_get_path(host_fdt, node_offset, node_path, path_len))
- == -FDT_ERR_NOSPACE) {
- path_len += 16;
- node_path = g_realloc(node_path, path_len);
- }
- if (ret < 0) {
- error_setg(&error_fatal,
- "not able to retrieve node path for clock handle %d",
- host_phandle);
- }
-
- r = qemu_fdt_getprop(host_fdt, node_path, "compatible", &prop_len,
- &error_fatal);
- if (strcmp(r, "fixed-clock")) {
- error_setg(&error_fatal,
- "clock handle %d is not a fixed clock", host_phandle);
- }
-
- nodename = strrchr(node_path, '/');
- qemu_fdt_add_subnode(guest_fdt, nodename);
-
- copy_properties_from_host(clock_copied_properties,
- ARRAY_SIZE(clock_copied_properties),
- host_fdt, guest_fdt,
- node_path, nodename);
-
- qemu_fdt_setprop_cell(guest_fdt, nodename, "phandle", guest_phandle);
-
- g_free(node_path);
-}
-
-/**
- * sysfs_to_dt_name: convert the name found in sysfs into the node name
- * for instance e0900000.xgmac is converted into xgmac@e0900000
- * @sysfs_name: directory name in sysfs
- *
- * returns the device tree name upon success or NULL in case the sysfs name
- * does not match the expected format
- */
-static char *sysfs_to_dt_name(const char *sysfs_name)
-{
- gchar **substrings = g_strsplit(sysfs_name, ".", 2);
- char *dt_name = NULL;
-
- if (!substrings || !substrings[0] || !substrings[1]) {
- goto out;
- }
- dt_name = g_strdup_printf("%s@%s", substrings[1], substrings[0]);
-out:
- g_strfreev(substrings);
- return dt_name;
-}
-
-/* Device Specific Code */
-
-/**
- * add_calxeda_midway_xgmac_fdt_node
- *
- * Generates a simple node with following properties:
- * compatible string, regs, interrupts, dma-coherent
- */
-static int add_calxeda_midway_xgmac_fdt_node(SysBusDevice *sbdev, void *opaque)
-{
- PlatformBusFDTData *data = opaque;
- PlatformBusDevice *pbus = data->pbus;
- void *fdt = data->fdt;
- const char *parent_node = data->pbus_node_name;
- int compat_str_len, i;
- char *nodename;
- uint32_t *irq_attr, *reg_attr;
- uint64_t mmio_base, irq_number;
- VFIOPlatformDevice *vdev = VFIO_PLATFORM_DEVICE(sbdev);
- VFIODevice *vbasedev = &vdev->vbasedev;
-
- mmio_base = platform_bus_get_mmio_addr(pbus, sbdev, 0);
- nodename = g_strdup_printf("%s/%s@%" PRIx64, parent_node,
- vbasedev->name, mmio_base);
- qemu_fdt_add_subnode(fdt, nodename);
-
- compat_str_len = strlen(vdev->compat) + 1;
- qemu_fdt_setprop(fdt, nodename, "compatible",
- vdev->compat, compat_str_len);
-
- qemu_fdt_setprop(fdt, nodename, "dma-coherent", "", 0);
-
- reg_attr = g_new(uint32_t, vbasedev->num_regions * 2);
- for (i = 0; i < vbasedev->num_regions; i++) {
- mmio_base = platform_bus_get_mmio_addr(pbus, sbdev, i);
- reg_attr[2 * i] = cpu_to_be32(mmio_base);
- reg_attr[2 * i + 1] = cpu_to_be32(
- memory_region_size(vdev->regions[i]->mem));
- }
- qemu_fdt_setprop(fdt, nodename, "reg", reg_attr,
- vbasedev->num_regions * 2 * sizeof(uint32_t));
-
- irq_attr = g_new(uint32_t, vbasedev->num_irqs * 3);
- for (i = 0; i < vbasedev->num_irqs; i++) {
- irq_number = platform_bus_get_irqn(pbus, sbdev , i)
- + data->irq_start;
- irq_attr[3 * i] = cpu_to_be32(GIC_FDT_IRQ_TYPE_SPI);
- irq_attr[3 * i + 1] = cpu_to_be32(irq_number);
- irq_attr[3 * i + 2] = cpu_to_be32(GIC_FDT_IRQ_FLAGS_LEVEL_HI);
- }
- qemu_fdt_setprop(fdt, nodename, "interrupts",
- irq_attr, vbasedev->num_irqs * 3 * sizeof(uint32_t));
- g_free(irq_attr);
- g_free(reg_attr);
- g_free(nodename);
- return 0;
-}
-
-/* AMD xgbe properties whose values are copied/pasted from host */
-static HostProperty amd_xgbe_copied_properties[] = {
- {"compatible", false},
- {"dma-coherent", true},
- {"amd,per-channel-interrupt", true},
- {"phy-mode", false},
- {"mac-address", true},
- {"amd,speed-set", false},
- {"amd,serdes-blwc", true},
- {"amd,serdes-cdr-rate", true},
- {"amd,serdes-pq-skew", true},
- {"amd,serdes-tx-amp", true},
- {"amd,serdes-dfe-tap-config", true},
- {"amd,serdes-dfe-tap-enable", true},
- {"clock-names", false},
-};
-
-/**
- * add_amd_xgbe_fdt_node
- *
- * Generates the combined xgbe/phy node following kernel >=4.2
- * binding documentation:
- * Documentation/devicetree/bindings/net/amd-xgbe.txt:
- * Also 2 clock nodes are created (dma and ptp)
- *
- * Asserts in case of error
- */
-static int add_amd_xgbe_fdt_node(SysBusDevice *sbdev, void *opaque)
-{
- PlatformBusFDTData *data = opaque;
- PlatformBusDevice *pbus = data->pbus;
- VFIOPlatformDevice *vdev = VFIO_PLATFORM_DEVICE(sbdev);
- VFIODevice *vbasedev = &vdev->vbasedev;
- VFIOINTp *intp;
- const char *parent_node = data->pbus_node_name;
- char **node_path, *nodename, *dt_name;
- void *guest_fdt = data->fdt, *host_fdt;
- const void *r;
- int i, prop_len;
- uint32_t *irq_attr, *reg_attr, *host_clock_phandles;
- uint64_t mmio_base, irq_number;
- uint32_t guest_clock_phandles[2];
-
- host_fdt = load_device_tree_from_sysfs();
-
- dt_name = sysfs_to_dt_name(vbasedev->name);
- if (!dt_name) {
- error_setg(&error_fatal, "%s incorrect sysfs device name %s",
- __func__, vbasedev->name);
- }
- node_path = qemu_fdt_node_path(host_fdt, dt_name, vdev->compat,
- &error_fatal);
- if (!node_path || !node_path[0]) {
- error_setg(&error_fatal, "%s unable to retrieve node path for %s/%s",
- __func__, dt_name, vdev->compat);
- }
-
- if (node_path[1]) {
- error_setg(&error_fatal, "%s more than one node matching %s/%s!",
- __func__, dt_name, vdev->compat);
- }
-
- g_free(dt_name);
-
- if (vbasedev->num_regions != 5) {
- error_setg(&error_fatal, "%s Does the host dt node combine XGBE/PHY?",
- __func__);
- }
-
- /* generate nodes for DMA_CLK and PTP_CLK */
- r = qemu_fdt_getprop(host_fdt, node_path[0], "clocks",
- &prop_len, &error_fatal);
- if (prop_len != 8) {
- error_setg(&error_fatal, "%s clocks property should contain 2 handles",
- __func__);
- }
- host_clock_phandles = (uint32_t *)r;
- guest_clock_phandles[0] = qemu_fdt_alloc_phandle(guest_fdt);
- guest_clock_phandles[1] = qemu_fdt_alloc_phandle(guest_fdt);
-
- /**
- * clock handles fetched from host dt are in be32 layout whereas
- * rest of the code uses cpu layout. Also guest clock handles are
- * in cpu layout.
- */
- fdt_build_clock_node(host_fdt, guest_fdt,
- be32_to_cpu(host_clock_phandles[0]),
- guest_clock_phandles[0]);
-
- fdt_build_clock_node(host_fdt, guest_fdt,
- be32_to_cpu(host_clock_phandles[1]),
- guest_clock_phandles[1]);
-
- /* combined XGBE/PHY node */
- mmio_base = platform_bus_get_mmio_addr(pbus, sbdev, 0);
- nodename = g_strdup_printf("%s/%s@%" PRIx64, parent_node,
- vbasedev->name, mmio_base);
- qemu_fdt_add_subnode(guest_fdt, nodename);
-
- copy_properties_from_host(amd_xgbe_copied_properties,
- ARRAY_SIZE(amd_xgbe_copied_properties),
- host_fdt, guest_fdt,
- node_path[0], nodename);
-
- qemu_fdt_setprop_cells(guest_fdt, nodename, "clocks",
- guest_clock_phandles[0],
- guest_clock_phandles[1]);
-
- reg_attr = g_new(uint32_t, vbasedev->num_regions * 2);
- for (i = 0; i < vbasedev->num_regions; i++) {
- mmio_base = platform_bus_get_mmio_addr(pbus, sbdev, i);
- reg_attr[2 * i] = cpu_to_be32(mmio_base);
- reg_attr[2 * i + 1] = cpu_to_be32(
- memory_region_size(vdev->regions[i]->mem));
- }
- qemu_fdt_setprop(guest_fdt, nodename, "reg", reg_attr,
- vbasedev->num_regions * 2 * sizeof(uint32_t));
-
- irq_attr = g_new(uint32_t, vbasedev->num_irqs * 3);
- for (i = 0; i < vbasedev->num_irqs; i++) {
- irq_number = platform_bus_get_irqn(pbus, sbdev , i)
- + data->irq_start;
- irq_attr[3 * i] = cpu_to_be32(GIC_FDT_IRQ_TYPE_SPI);
- irq_attr[3 * i + 1] = cpu_to_be32(irq_number);
- /*
- * General device interrupt and PCS auto-negotiation interrupts are
- * level-sensitive while the 4 per-channel interrupts are edge
- * sensitive
- */
- QLIST_FOREACH(intp, &vdev->intp_list, next) {
- if (intp->pin == i) {
- break;
- }
- }
- if (intp->flags & VFIO_IRQ_INFO_AUTOMASKED) {
- irq_attr[3 * i + 2] = cpu_to_be32(GIC_FDT_IRQ_FLAGS_LEVEL_HI);
- } else {
- irq_attr[3 * i + 2] = cpu_to_be32(GIC_FDT_IRQ_FLAGS_EDGE_LO_HI);
- }
- }
- qemu_fdt_setprop(guest_fdt, nodename, "interrupts",
- irq_attr, vbasedev->num_irqs * 3 * sizeof(uint32_t));
-
- g_free(host_fdt);
- g_strfreev(node_path);
- g_free(irq_attr);
- g_free(reg_attr);
- g_free(nodename);
- return 0;
-}
-
-#endif /* CONFIG_LINUX */
-
-/* list of supported dynamic sysbus devices */
-static const NodeCreationPair add_fdt_node_functions[] = {
-#ifdef CONFIG_LINUX
- {TYPE_VFIO_CALXEDA_XGMAC, add_calxeda_midway_xgmac_fdt_node},
- {TYPE_VFIO_AMD_XGBE, add_amd_xgbe_fdt_node},
-#endif
- {"", NULL}, /* last element */
-};
-
-/* Generic Code */
-
-/**
- * add_fdt_node - add the device tree node of a dynamic sysbus device
- *
- * @sbdev: handle to the sysbus device
- * @opaque: handle to the PlatformBusFDTData
- *
- * Checks the sysbus type belongs to the list of device types that
- * are dynamically instantiable and if so call the node creation
- * function.
- */
-static int add_fdt_node(SysBusDevice *sbdev, void *opaque)
-{
- int i, ret;
-
- for (i = 0; i < ARRAY_SIZE(add_fdt_node_functions); i++) {
- if (!strcmp(object_get_typename(OBJECT(sbdev)),
- add_fdt_node_functions[i].typename)) {
- ret = add_fdt_node_functions[i].add_fdt_node_fn(sbdev, opaque);
- assert(!ret);
- return 0;
- }
- }
- error_report("Device %s can not be dynamically instantiated",
- qdev_fw_name(DEVICE(sbdev)));
- exit(1);
-}
-
-/**
- * add_all_platform_bus_fdt_nodes - create all the platform bus nodes
- *
- * builds the parent platform bus node and all the nodes of dynamic
- * sysbus devices attached to it.
- */
-static void add_all_platform_bus_fdt_nodes(ARMPlatformBusFDTParams *fdt_params)
-{
- const char platcomp[] = "qemu,platform\0simple-bus";
- PlatformBusDevice *pbus;
- DeviceState *dev;
- gchar *node;
- uint64_t addr, size;
- int irq_start, dtb_size;
- struct arm_boot_info *info = fdt_params->binfo;
- const ARMPlatformBusSystemParams *params = fdt_params->system_params;
- const char *intc = fdt_params->intc;
- void *fdt = info->get_dtb(info, &dtb_size);
-
- /*
- * If the user provided a dtb, we assume the dynamic sysbus nodes
- * already are integrated there. This corresponds to a use case where
- * the dynamic sysbus nodes are complex and their generation is not yet
- * supported. In that case the user can take charge of the guest dt
- * while qemu takes charge of the qom stuff.
- */
- if (info->dtb_filename) {
- return;
- }
-
- assert(fdt);
-
- node = g_strdup_printf("/platform@%"PRIx64, params->platform_bus_base);
- addr = params->platform_bus_base;
- size = params->platform_bus_size;
- irq_start = params->platform_bus_first_irq;
-
- /* Create a /platform node that we can put all devices into */
- qemu_fdt_add_subnode(fdt, node);
- qemu_fdt_setprop(fdt, node, "compatible", platcomp, sizeof(platcomp));
-
- /* Our platform bus region is less than 32bits, so 1 cell is enough for
- * address and size
- */
- qemu_fdt_setprop_cells(fdt, node, "#size-cells", 1);
- qemu_fdt_setprop_cells(fdt, node, "#address-cells", 1);
- qemu_fdt_setprop_cells(fdt, node, "ranges", 0, addr >> 32, addr, size);
-
- qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", intc);
-
- dev = qdev_find_recursive(sysbus_get_default(), TYPE_PLATFORM_BUS_DEVICE);
- pbus = PLATFORM_BUS_DEVICE(dev);
-
- /* We can only create dt nodes for dynamic devices when they're ready */
- assert(pbus->done_gathering);
-
- PlatformBusFDTData data = {
- .fdt = fdt,
- .irq_start = irq_start,
- .pbus_node_name = node,
- .pbus = pbus,
- };
-
- /* Loop through all dynamic sysbus devices and create their node */
- foreach_dynamic_sysbus_device(add_fdt_node, &data);
-
- g_free(node);
-}
-
-static void platform_bus_fdt_notify(Notifier *notifier, void *data)
-{
- PlatformBusFDTNotifierParams *p = DO_UPCAST(PlatformBusFDTNotifierParams,
- notifier, notifier);
-
- add_all_platform_bus_fdt_nodes(p->fdt_params);
- g_free(p->fdt_params);
- g_free(p);
-}
-
-void arm_register_platform_bus_fdt_creator(ARMPlatformBusFDTParams *fdt_params)
-{
- PlatformBusFDTNotifierParams *p = g_new(PlatformBusFDTNotifierParams, 1);
-
- p->fdt_params = fdt_params;
- p->notifier.notify = platform_bus_fdt_notify;
- qemu_add_machine_init_done_notifier(&p->notifier);
-}
diff --git a/qemu/hw/arm/tosa.c b/qemu/hw/arm/tosa.c
deleted file mode 100644
index 4e9494f94..000000000
--- a/qemu/hw/arm/tosa.c
+++ /dev/null
@@ -1,303 +0,0 @@
-/* vim:set shiftwidth=4 ts=4 et: */
-/*
- * PXA255 Sharp Zaurus SL-6000 PDA platform
- *
- * Copyright (c) 2008 Dmitry Baryshkov
- *
- * Code based on spitz platform by Andrzej Zaborowski <balrog@zabor.org>
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/hw.h"
-#include "hw/arm/pxa.h"
-#include "hw/arm/arm.h"
-#include "hw/devices.h"
-#include "hw/arm/sharpsl.h"
-#include "hw/pcmcia.h"
-#include "hw/boards.h"
-#include "hw/i2c/i2c.h"
-#include "hw/ssi/ssi.h"
-#include "sysemu/block-backend.h"
-#include "hw/sysbus.h"
-#include "exec/address-spaces.h"
-
-#define TOSA_RAM 0x04000000
-#define TOSA_ROM 0x00800000
-
-#define TOSA_GPIO_USB_IN (5)
-#define TOSA_GPIO_nSD_DETECT (9)
-#define TOSA_GPIO_ON_RESET (19)
-#define TOSA_GPIO_CF_IRQ (21) /* CF slot0 Ready */
-#define TOSA_GPIO_CF_CD (13)
-#define TOSA_GPIO_TC6393XB_INT (15)
-#define TOSA_GPIO_JC_CF_IRQ (36) /* CF slot1 Ready */
-
-#define TOSA_SCOOP_GPIO_BASE 1
-#define TOSA_GPIO_IR_POWERDWN (TOSA_SCOOP_GPIO_BASE + 2)
-#define TOSA_GPIO_SD_WP (TOSA_SCOOP_GPIO_BASE + 3)
-#define TOSA_GPIO_PWR_ON (TOSA_SCOOP_GPIO_BASE + 4)
-
-#define TOSA_SCOOP_JC_GPIO_BASE 1
-#define TOSA_GPIO_BT_LED (TOSA_SCOOP_JC_GPIO_BASE + 0)
-#define TOSA_GPIO_NOTE_LED (TOSA_SCOOP_JC_GPIO_BASE + 1)
-#define TOSA_GPIO_CHRG_ERR_LED (TOSA_SCOOP_JC_GPIO_BASE + 2)
-#define TOSA_GPIO_TC6393XB_L3V_ON (TOSA_SCOOP_JC_GPIO_BASE + 5)
-#define TOSA_GPIO_WLAN_LED (TOSA_SCOOP_JC_GPIO_BASE + 7)
-
-#define DAC_BASE 0x4e
-#define DAC_CH1 0
-#define DAC_CH2 1
-
-static void tosa_microdrive_attach(PXA2xxState *cpu)
-{
- PCMCIACardState *md;
- DriveInfo *dinfo;
-
- dinfo = drive_get(IF_IDE, 0, 0);
- if (!dinfo || dinfo->media_cd)
- return;
- md = dscm1xxxx_init(dinfo);
- pxa2xx_pcmcia_attach(cpu->pcmcia[0], md);
-}
-
-static void tosa_out_switch(void *opaque, int line, int level)
-{
- switch (line) {
- case 0:
- fprintf(stderr, "blue LED %s.\n", level ? "on" : "off");
- break;
- case 1:
- fprintf(stderr, "green LED %s.\n", level ? "on" : "off");
- break;
- case 2:
- fprintf(stderr, "amber LED %s.\n", level ? "on" : "off");
- break;
- case 3:
- fprintf(stderr, "wlan LED %s.\n", level ? "on" : "off");
- break;
- default:
- fprintf(stderr, "Uhandled out event: %d = %d\n", line, level);
- break;
- }
-}
-
-
-static void tosa_gpio_setup(PXA2xxState *cpu,
- DeviceState *scp0,
- DeviceState *scp1,
- TC6393xbState *tmio)
-{
- qemu_irq *outsignals = qemu_allocate_irqs(tosa_out_switch, cpu, 4);
- /* MMC/SD host */
- pxa2xx_mmci_handlers(cpu->mmc,
- qdev_get_gpio_in(scp0, TOSA_GPIO_SD_WP),
- qemu_irq_invert(qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_nSD_DETECT)));
-
- /* Handle reset */
- qdev_connect_gpio_out(cpu->gpio, TOSA_GPIO_ON_RESET, cpu->reset);
-
- /* PCMCIA signals: card's IRQ and Card-Detect */
- pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[0],
- qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_CF_IRQ),
- qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_CF_CD));
-
- pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[1],
- qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_JC_CF_IRQ),
- NULL);
-
- qdev_connect_gpio_out(scp1, TOSA_GPIO_BT_LED, outsignals[0]);
- qdev_connect_gpio_out(scp1, TOSA_GPIO_NOTE_LED, outsignals[1]);
- qdev_connect_gpio_out(scp1, TOSA_GPIO_CHRG_ERR_LED, outsignals[2]);
- qdev_connect_gpio_out(scp1, TOSA_GPIO_WLAN_LED, outsignals[3]);
-
- qdev_connect_gpio_out(scp1, TOSA_GPIO_TC6393XB_L3V_ON, tc6393xb_l3v_get(tmio));
-
- /* UDC Vbus */
- qemu_irq_raise(qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_USB_IN));
-}
-
-static uint32_t tosa_ssp_tansfer(SSISlave *dev, uint32_t value)
-{
- fprintf(stderr, "TG: %d %02x\n", value >> 5, value & 0x1f);
- return 0;
-}
-
-static int tosa_ssp_init(SSISlave *dev)
-{
- /* Nothing to do. */
- return 0;
-}
-
-#define TYPE_TOSA_DAC "tosa_dac"
-#define TOSA_DAC(obj) OBJECT_CHECK(TosaDACState, (obj), TYPE_TOSA_DAC)
-
-typedef struct {
- I2CSlave parent_obj;
-
- int len;
- char buf[3];
-} TosaDACState;
-
-static int tosa_dac_send(I2CSlave *i2c, uint8_t data)
-{
- TosaDACState *s = TOSA_DAC(i2c);
-
- s->buf[s->len] = data;
- if (s->len ++ > 2) {
-#ifdef VERBOSE
- fprintf(stderr, "%s: message too long (%i bytes)\n", __FUNCTION__, s->len);
-#endif
- return 1;
- }
-
- if (s->len == 2) {
- fprintf(stderr, "dac: channel %d value 0x%02x\n",
- s->buf[0], s->buf[1]);
- }
-
- return 0;
-}
-
-static void tosa_dac_event(I2CSlave *i2c, enum i2c_event event)
-{
- TosaDACState *s = TOSA_DAC(i2c);
-
- s->len = 0;
- switch (event) {
- case I2C_START_SEND:
- break;
- case I2C_START_RECV:
- printf("%s: recv not supported!!!\n", __FUNCTION__);
- break;
- case I2C_FINISH:
-#ifdef VERBOSE
- if (s->len < 2)
- printf("%s: message too short (%i bytes)\n", __FUNCTION__, s->len);
- if (s->len > 2)
- printf("%s: message too long\n", __FUNCTION__);
-#endif
- break;
- default:
- break;
- }
-}
-
-static int tosa_dac_recv(I2CSlave *s)
-{
- printf("%s: recv not supported!!!\n", __FUNCTION__);
- return -1;
-}
-
-static int tosa_dac_init(I2CSlave *i2c)
-{
- /* Nothing to do. */
- return 0;
-}
-
-static void tosa_tg_init(PXA2xxState *cpu)
-{
- I2CBus *bus = pxa2xx_i2c_bus(cpu->i2c[0]);
- i2c_create_slave(bus, TYPE_TOSA_DAC, DAC_BASE);
- ssi_create_slave(cpu->ssp[1], "tosa-ssp");
-}
-
-
-static struct arm_boot_info tosa_binfo = {
- .loader_start = PXA2XX_SDRAM_BASE,
- .ram_size = 0x04000000,
-};
-
-static void tosa_init(MachineState *machine)
-{
- const char *cpu_model = machine->cpu_model;
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- const char *initrd_filename = machine->initrd_filename;
- MemoryRegion *address_space_mem = get_system_memory();
- MemoryRegion *rom = g_new(MemoryRegion, 1);
- PXA2xxState *mpu;
- TC6393xbState *tmio;
- DeviceState *scp0, *scp1;
-
- if (!cpu_model)
- cpu_model = "pxa255";
-
- mpu = pxa255_init(address_space_mem, tosa_binfo.ram_size);
-
- memory_region_init_ram(rom, NULL, "tosa.rom", TOSA_ROM, &error_fatal);
- vmstate_register_ram_global(rom);
- memory_region_set_readonly(rom, true);
- memory_region_add_subregion(address_space_mem, 0, rom);
-
- tmio = tc6393xb_init(address_space_mem, 0x10000000,
- qdev_get_gpio_in(mpu->gpio, TOSA_GPIO_TC6393XB_INT));
-
- scp0 = sysbus_create_simple("scoop", 0x08800000, NULL);
- scp1 = sysbus_create_simple("scoop", 0x14800040, NULL);
-
- tosa_gpio_setup(mpu, scp0, scp1, tmio);
-
- tosa_microdrive_attach(mpu);
-
- tosa_tg_init(mpu);
-
- tosa_binfo.kernel_filename = kernel_filename;
- tosa_binfo.kernel_cmdline = kernel_cmdline;
- tosa_binfo.initrd_filename = initrd_filename;
- tosa_binfo.board_id = 0x208;
- arm_load_kernel(mpu->cpu, &tosa_binfo);
- sl_bootparam_write(SL_PXA_PARAM_BASE);
-}
-
-static void tosapda_machine_init(MachineClass *mc)
-{
- mc->desc = "Sharp SL-6000 (Tosa) PDA (PXA255)";
- mc->init = tosa_init;
-}
-
-DEFINE_MACHINE("tosa", tosapda_machine_init)
-
-static void tosa_dac_class_init(ObjectClass *klass, void *data)
-{
- I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
-
- k->init = tosa_dac_init;
- k->event = tosa_dac_event;
- k->recv = tosa_dac_recv;
- k->send = tosa_dac_send;
-}
-
-static const TypeInfo tosa_dac_info = {
- .name = TYPE_TOSA_DAC,
- .parent = TYPE_I2C_SLAVE,
- .instance_size = sizeof(TosaDACState),
- .class_init = tosa_dac_class_init,
-};
-
-static void tosa_ssp_class_init(ObjectClass *klass, void *data)
-{
- SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
-
- k->init = tosa_ssp_init;
- k->transfer = tosa_ssp_tansfer;
-}
-
-static const TypeInfo tosa_ssp_info = {
- .name = "tosa-ssp",
- .parent = TYPE_SSI_SLAVE,
- .instance_size = sizeof(SSISlave),
- .class_init = tosa_ssp_class_init,
-};
-
-static void tosa_register_types(void)
-{
- type_register_static(&tosa_dac_info);
- type_register_static(&tosa_ssp_info);
-}
-
-type_init(tosa_register_types)
diff --git a/qemu/hw/arm/versatilepb.c b/qemu/hw/arm/versatilepb.c
deleted file mode 100644
index e5a80c2d2..000000000
--- a/qemu/hw/arm/versatilepb.c
+++ /dev/null
@@ -1,448 +0,0 @@
-/*
- * ARM Versatile Platform/Application Baseboard System emulation.
- *
- * Copyright (c) 2005-2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/sysbus.h"
-#include "hw/arm/arm.h"
-#include "hw/devices.h"
-#include "net/net.h"
-#include "sysemu/sysemu.h"
-#include "hw/pci/pci.h"
-#include "hw/i2c/i2c.h"
-#include "hw/boards.h"
-#include "sysemu/block-backend.h"
-#include "exec/address-spaces.h"
-#include "hw/block/flash.h"
-#include "qemu/error-report.h"
-
-#define VERSATILE_FLASH_ADDR 0x34000000
-#define VERSATILE_FLASH_SIZE (64 * 1024 * 1024)
-#define VERSATILE_FLASH_SECT_SIZE (256 * 1024)
-
-/* Primary interrupt controller. */
-
-#define TYPE_VERSATILE_PB_SIC "versatilepb_sic"
-#define VERSATILE_PB_SIC(obj) \
- OBJECT_CHECK(vpb_sic_state, (obj), TYPE_VERSATILE_PB_SIC)
-
-typedef struct vpb_sic_state {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- uint32_t level;
- uint32_t mask;
- uint32_t pic_enable;
- qemu_irq parent[32];
- int irq;
-} vpb_sic_state;
-
-static const VMStateDescription vmstate_vpb_sic = {
- .name = "versatilepb_sic",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(level, vpb_sic_state),
- VMSTATE_UINT32(mask, vpb_sic_state),
- VMSTATE_UINT32(pic_enable, vpb_sic_state),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void vpb_sic_update(vpb_sic_state *s)
-{
- uint32_t flags;
-
- flags = s->level & s->mask;
- qemu_set_irq(s->parent[s->irq], flags != 0);
-}
-
-static void vpb_sic_update_pic(vpb_sic_state *s)
-{
- int i;
- uint32_t mask;
-
- for (i = 21; i <= 30; i++) {
- mask = 1u << i;
- if (!(s->pic_enable & mask))
- continue;
- qemu_set_irq(s->parent[i], (s->level & mask) != 0);
- }
-}
-
-static void vpb_sic_set_irq(void *opaque, int irq, int level)
-{
- vpb_sic_state *s = (vpb_sic_state *)opaque;
- if (level)
- s->level |= 1u << irq;
- else
- s->level &= ~(1u << irq);
- if (s->pic_enable & (1u << irq))
- qemu_set_irq(s->parent[irq], level);
- vpb_sic_update(s);
-}
-
-static uint64_t vpb_sic_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- vpb_sic_state *s = (vpb_sic_state *)opaque;
-
- switch (offset >> 2) {
- case 0: /* STATUS */
- return s->level & s->mask;
- case 1: /* RAWSTAT */
- return s->level;
- case 2: /* ENABLE */
- return s->mask;
- case 4: /* SOFTINT */
- return s->level & 1;
- case 8: /* PICENABLE */
- return s->pic_enable;
- default:
- printf ("vpb_sic_read: Bad register offset 0x%x\n", (int)offset);
- return 0;
- }
-}
-
-static void vpb_sic_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- vpb_sic_state *s = (vpb_sic_state *)opaque;
-
- switch (offset >> 2) {
- case 2: /* ENSET */
- s->mask |= value;
- break;
- case 3: /* ENCLR */
- s->mask &= ~value;
- break;
- case 4: /* SOFTINTSET */
- if (value)
- s->mask |= 1;
- break;
- case 5: /* SOFTINTCLR */
- if (value)
- s->mask &= ~1u;
- break;
- case 8: /* PICENSET */
- s->pic_enable |= (value & 0x7fe00000);
- vpb_sic_update_pic(s);
- break;
- case 9: /* PICENCLR */
- s->pic_enable &= ~value;
- vpb_sic_update_pic(s);
- break;
- default:
- printf ("vpb_sic_write: Bad register offset 0x%x\n", (int)offset);
- return;
- }
- vpb_sic_update(s);
-}
-
-static const MemoryRegionOps vpb_sic_ops = {
- .read = vpb_sic_read,
- .write = vpb_sic_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int vpb_sic_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- vpb_sic_state *s = VERSATILE_PB_SIC(dev);
- int i;
-
- qdev_init_gpio_in(dev, vpb_sic_set_irq, 32);
- for (i = 0; i < 32; i++) {
- sysbus_init_irq(sbd, &s->parent[i]);
- }
- s->irq = 31;
- memory_region_init_io(&s->iomem, OBJECT(s), &vpb_sic_ops, s,
- "vpb-sic", 0x1000);
- sysbus_init_mmio(sbd, &s->iomem);
- return 0;
-}
-
-/* Board init. */
-
-/* The AB and PB boards both use the same core, just with different
- peripherals and expansion busses. For now we emulate a subset of the
- PB peripherals and just change the board ID. */
-
-static struct arm_boot_info versatile_binfo;
-
-static void versatile_init(MachineState *machine, int board_id)
-{
- ObjectClass *cpu_oc;
- Object *cpuobj;
- ARMCPU *cpu;
- MemoryRegion *sysmem = get_system_memory();
- MemoryRegion *ram = g_new(MemoryRegion, 1);
- qemu_irq pic[32];
- qemu_irq sic[32];
- DeviceState *dev, *sysctl;
- SysBusDevice *busdev;
- DeviceState *pl041;
- PCIBus *pci_bus;
- NICInfo *nd;
- I2CBus *i2c;
- int n;
- int done_smc = 0;
- DriveInfo *dinfo;
-
- if (!machine->cpu_model) {
- machine->cpu_model = "arm926";
- }
-
- cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, machine->cpu_model);
- if (!cpu_oc) {
- fprintf(stderr, "Unable to find CPU definition\n");
- exit(1);
- }
-
- cpuobj = object_new(object_class_get_name(cpu_oc));
-
- /* By default ARM1176 CPUs have EL3 enabled. This board does not
- * currently support EL3 so the CPU EL3 property is disabled before
- * realization.
- */
- if (object_property_find(cpuobj, "has_el3", NULL)) {
- object_property_set_bool(cpuobj, false, "has_el3", &error_fatal);
- }
-
- object_property_set_bool(cpuobj, true, "realized", &error_fatal);
-
- cpu = ARM_CPU(cpuobj);
-
- memory_region_allocate_system_memory(ram, NULL, "versatile.ram",
- machine->ram_size);
- /* ??? RAM should repeat to fill physical memory space. */
- /* SDRAM at address zero. */
- memory_region_add_subregion(sysmem, 0, ram);
-
- sysctl = qdev_create(NULL, "realview_sysctl");
- qdev_prop_set_uint32(sysctl, "sys_id", 0x41007004);
- qdev_prop_set_uint32(sysctl, "proc_id", 0x02000000);
- qdev_init_nofail(sysctl);
- sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, 0x10000000);
-
- dev = sysbus_create_varargs("pl190", 0x10140000,
- qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ),
- qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ),
- NULL);
- for (n = 0; n < 32; n++) {
- pic[n] = qdev_get_gpio_in(dev, n);
- }
- dev = sysbus_create_simple(TYPE_VERSATILE_PB_SIC, 0x10003000, NULL);
- for (n = 0; n < 32; n++) {
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), n, pic[n]);
- sic[n] = qdev_get_gpio_in(dev, n);
- }
-
- sysbus_create_simple("pl050_keyboard", 0x10006000, sic[3]);
- sysbus_create_simple("pl050_mouse", 0x10007000, sic[4]);
-
- dev = qdev_create(NULL, "versatile_pci");
- busdev = SYS_BUS_DEVICE(dev);
- qdev_init_nofail(dev);
- sysbus_mmio_map(busdev, 0, 0x10001000); /* PCI controller regs */
- sysbus_mmio_map(busdev, 1, 0x41000000); /* PCI self-config */
- sysbus_mmio_map(busdev, 2, 0x42000000); /* PCI config */
- sysbus_mmio_map(busdev, 3, 0x43000000); /* PCI I/O */
- sysbus_mmio_map(busdev, 4, 0x44000000); /* PCI memory window 1 */
- sysbus_mmio_map(busdev, 5, 0x50000000); /* PCI memory window 2 */
- sysbus_mmio_map(busdev, 6, 0x60000000); /* PCI memory window 3 */
- sysbus_connect_irq(busdev, 0, sic[27]);
- sysbus_connect_irq(busdev, 1, sic[28]);
- sysbus_connect_irq(busdev, 2, sic[29]);
- sysbus_connect_irq(busdev, 3, sic[30]);
- pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci");
-
- for(n = 0; n < nb_nics; n++) {
- nd = &nd_table[n];
-
- if (!done_smc && (!nd->model || strcmp(nd->model, "smc91c111") == 0)) {
- smc91c111_init(nd, 0x10010000, sic[25]);
- done_smc = 1;
- } else {
- pci_nic_init_nofail(nd, pci_bus, "rtl8139", NULL);
- }
- }
- if (usb_enabled()) {
- pci_create_simple(pci_bus, -1, "pci-ohci");
- }
- n = drive_get_max_bus(IF_SCSI);
- while (n >= 0) {
- pci_create_simple(pci_bus, -1, "lsi53c895a");
- n--;
- }
-
- sysbus_create_simple("pl011", 0x101f1000, pic[12]);
- sysbus_create_simple("pl011", 0x101f2000, pic[13]);
- sysbus_create_simple("pl011", 0x101f3000, pic[14]);
- sysbus_create_simple("pl011", 0x10009000, sic[6]);
-
- sysbus_create_simple("pl080", 0x10130000, pic[17]);
- sysbus_create_simple("sp804", 0x101e2000, pic[4]);
- sysbus_create_simple("sp804", 0x101e3000, pic[5]);
-
- sysbus_create_simple("pl061", 0x101e4000, pic[6]);
- sysbus_create_simple("pl061", 0x101e5000, pic[7]);
- sysbus_create_simple("pl061", 0x101e6000, pic[8]);
- sysbus_create_simple("pl061", 0x101e7000, pic[9]);
-
- /* The versatile/PB actually has a modified Color LCD controller
- that includes hardware cursor support from the PL111. */
- dev = sysbus_create_simple("pl110_versatile", 0x10120000, pic[16]);
- /* Wire up the mux control signals from the SYS_CLCD register */
- qdev_connect_gpio_out(sysctl, 0, qdev_get_gpio_in(dev, 0));
-
- sysbus_create_varargs("pl181", 0x10005000, sic[22], sic[1], NULL);
- sysbus_create_varargs("pl181", 0x1000b000, sic[23], sic[2], NULL);
-
- /* Add PL031 Real Time Clock. */
- sysbus_create_simple("pl031", 0x101e8000, pic[10]);
-
- dev = sysbus_create_simple("versatile_i2c", 0x10002000, NULL);
- i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c");
- i2c_create_slave(i2c, "ds1338", 0x68);
-
- /* Add PL041 AACI Interface to the LM4549 codec */
- pl041 = qdev_create(NULL, "pl041");
- qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512);
- qdev_init_nofail(pl041);
- sysbus_mmio_map(SYS_BUS_DEVICE(pl041), 0, 0x10004000);
- sysbus_connect_irq(SYS_BUS_DEVICE(pl041), 0, sic[24]);
-
- /* Memory map for Versatile/PB: */
- /* 0x10000000 System registers. */
- /* 0x10001000 PCI controller config registers. */
- /* 0x10002000 Serial bus interface. */
- /* 0x10003000 Secondary interrupt controller. */
- /* 0x10004000 AACI (audio). */
- /* 0x10005000 MMCI0. */
- /* 0x10006000 KMI0 (keyboard). */
- /* 0x10007000 KMI1 (mouse). */
- /* 0x10008000 Character LCD Interface. */
- /* 0x10009000 UART3. */
- /* 0x1000a000 Smart card 1. */
- /* 0x1000b000 MMCI1. */
- /* 0x10010000 Ethernet. */
- /* 0x10020000 USB. */
- /* 0x10100000 SSMC. */
- /* 0x10110000 MPMC. */
- /* 0x10120000 CLCD Controller. */
- /* 0x10130000 DMA Controller. */
- /* 0x10140000 Vectored interrupt controller. */
- /* 0x101d0000 AHB Monitor Interface. */
- /* 0x101e0000 System Controller. */
- /* 0x101e1000 Watchdog Interface. */
- /* 0x101e2000 Timer 0/1. */
- /* 0x101e3000 Timer 2/3. */
- /* 0x101e4000 GPIO port 0. */
- /* 0x101e5000 GPIO port 1. */
- /* 0x101e6000 GPIO port 2. */
- /* 0x101e7000 GPIO port 3. */
- /* 0x101e8000 RTC. */
- /* 0x101f0000 Smart card 0. */
- /* 0x101f1000 UART0. */
- /* 0x101f2000 UART1. */
- /* 0x101f3000 UART2. */
- /* 0x101f4000 SSPI. */
- /* 0x34000000 NOR Flash */
-
- dinfo = drive_get(IF_PFLASH, 0, 0);
- if (!pflash_cfi01_register(VERSATILE_FLASH_ADDR, NULL, "versatile.flash",
- VERSATILE_FLASH_SIZE,
- dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- VERSATILE_FLASH_SECT_SIZE,
- VERSATILE_FLASH_SIZE / VERSATILE_FLASH_SECT_SIZE,
- 4, 0x0089, 0x0018, 0x0000, 0x0, 0)) {
- fprintf(stderr, "qemu: Error registering flash memory.\n");
- }
-
- versatile_binfo.ram_size = machine->ram_size;
- versatile_binfo.kernel_filename = machine->kernel_filename;
- versatile_binfo.kernel_cmdline = machine->kernel_cmdline;
- versatile_binfo.initrd_filename = machine->initrd_filename;
- versatile_binfo.board_id = board_id;
- arm_load_kernel(cpu, &versatile_binfo);
-}
-
-static void vpb_init(MachineState *machine)
-{
- versatile_init(machine, 0x183);
-}
-
-static void vab_init(MachineState *machine)
-{
- versatile_init(machine, 0x25e);
-}
-
-static void versatilepb_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "ARM Versatile/PB (ARM926EJ-S)";
- mc->init = vpb_init;
- mc->block_default_type = IF_SCSI;
-}
-
-static const TypeInfo versatilepb_type = {
- .name = MACHINE_TYPE_NAME("versatilepb"),
- .parent = TYPE_MACHINE,
- .class_init = versatilepb_class_init,
-};
-
-static void versatileab_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "ARM Versatile/AB (ARM926EJ-S)";
- mc->init = vab_init;
- mc->block_default_type = IF_SCSI;
-}
-
-static const TypeInfo versatileab_type = {
- .name = MACHINE_TYPE_NAME("versatileab"),
- .parent = TYPE_MACHINE,
- .class_init = versatileab_class_init,
-};
-
-static void versatile_machine_init(void)
-{
- type_register_static(&versatilepb_type);
- type_register_static(&versatileab_type);
-}
-
-type_init(versatile_machine_init)
-
-static void vpb_sic_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = vpb_sic_init;
- dc->vmsd = &vmstate_vpb_sic;
-}
-
-static const TypeInfo vpb_sic_info = {
- .name = TYPE_VERSATILE_PB_SIC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(vpb_sic_state),
- .class_init = vpb_sic_class_init,
-};
-
-static void versatilepb_register_types(void)
-{
- type_register_static(&vpb_sic_info);
-}
-
-type_init(versatilepb_register_types)
diff --git a/qemu/hw/arm/vexpress.c b/qemu/hw/arm/vexpress.c
deleted file mode 100644
index 70b3e701e..000000000
--- a/qemu/hw/arm/vexpress.c
+++ /dev/null
@@ -1,806 +0,0 @@
-/*
- * ARM Versatile Express emulation.
- *
- * Copyright (c) 2010 - 2011 B Labs Ltd.
- * Copyright (c) 2011 Linaro Limited
- * Written by Bahadir Balban, Amit Mahajan, Peter Maydell
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/sysbus.h"
-#include "hw/arm/arm.h"
-#include "hw/arm/primecell.h"
-#include "hw/devices.h"
-#include "net/net.h"
-#include "sysemu/sysemu.h"
-#include "hw/boards.h"
-#include "hw/loader.h"
-#include "exec/address-spaces.h"
-#include "sysemu/block-backend.h"
-#include "hw/block/flash.h"
-#include "sysemu/device_tree.h"
-#include "qemu/error-report.h"
-#include <libfdt.h>
-
-#define VEXPRESS_BOARD_ID 0x8e0
-#define VEXPRESS_FLASH_SIZE (64 * 1024 * 1024)
-#define VEXPRESS_FLASH_SECT_SIZE (256 * 1024)
-
-/* Number of virtio transports to create (0..8; limited by
- * number of available IRQ lines).
- */
-#define NUM_VIRTIO_TRANSPORTS 4
-
-/* Address maps for peripherals:
- * the Versatile Express motherboard has two possible maps,
- * the "legacy" one (used for A9) and the "Cortex-A Series"
- * map (used for newer cores).
- * Individual daughterboards can also have different maps for
- * their peripherals.
- */
-
-enum {
- VE_SYSREGS,
- VE_SP810,
- VE_SERIALPCI,
- VE_PL041,
- VE_MMCI,
- VE_KMI0,
- VE_KMI1,
- VE_UART0,
- VE_UART1,
- VE_UART2,
- VE_UART3,
- VE_WDT,
- VE_TIMER01,
- VE_TIMER23,
- VE_SERIALDVI,
- VE_RTC,
- VE_COMPACTFLASH,
- VE_CLCD,
- VE_NORFLASH0,
- VE_NORFLASH1,
- VE_NORFLASHALIAS,
- VE_SRAM,
- VE_VIDEORAM,
- VE_ETHERNET,
- VE_USB,
- VE_DAPROM,
- VE_VIRTIO,
-};
-
-static hwaddr motherboard_legacy_map[] = {
- [VE_NORFLASHALIAS] = 0,
- /* CS7: 0x10000000 .. 0x10020000 */
- [VE_SYSREGS] = 0x10000000,
- [VE_SP810] = 0x10001000,
- [VE_SERIALPCI] = 0x10002000,
- [VE_PL041] = 0x10004000,
- [VE_MMCI] = 0x10005000,
- [VE_KMI0] = 0x10006000,
- [VE_KMI1] = 0x10007000,
- [VE_UART0] = 0x10009000,
- [VE_UART1] = 0x1000a000,
- [VE_UART2] = 0x1000b000,
- [VE_UART3] = 0x1000c000,
- [VE_WDT] = 0x1000f000,
- [VE_TIMER01] = 0x10011000,
- [VE_TIMER23] = 0x10012000,
- [VE_VIRTIO] = 0x10013000,
- [VE_SERIALDVI] = 0x10016000,
- [VE_RTC] = 0x10017000,
- [VE_COMPACTFLASH] = 0x1001a000,
- [VE_CLCD] = 0x1001f000,
- /* CS0: 0x40000000 .. 0x44000000 */
- [VE_NORFLASH0] = 0x40000000,
- /* CS1: 0x44000000 .. 0x48000000 */
- [VE_NORFLASH1] = 0x44000000,
- /* CS2: 0x48000000 .. 0x4a000000 */
- [VE_SRAM] = 0x48000000,
- /* CS3: 0x4c000000 .. 0x50000000 */
- [VE_VIDEORAM] = 0x4c000000,
- [VE_ETHERNET] = 0x4e000000,
- [VE_USB] = 0x4f000000,
-};
-
-static hwaddr motherboard_aseries_map[] = {
- [VE_NORFLASHALIAS] = 0,
- /* CS0: 0x08000000 .. 0x0c000000 */
- [VE_NORFLASH0] = 0x08000000,
- /* CS4: 0x0c000000 .. 0x10000000 */
- [VE_NORFLASH1] = 0x0c000000,
- /* CS5: 0x10000000 .. 0x14000000 */
- /* CS1: 0x14000000 .. 0x18000000 */
- [VE_SRAM] = 0x14000000,
- /* CS2: 0x18000000 .. 0x1c000000 */
- [VE_VIDEORAM] = 0x18000000,
- [VE_ETHERNET] = 0x1a000000,
- [VE_USB] = 0x1b000000,
- /* CS3: 0x1c000000 .. 0x20000000 */
- [VE_DAPROM] = 0x1c000000,
- [VE_SYSREGS] = 0x1c010000,
- [VE_SP810] = 0x1c020000,
- [VE_SERIALPCI] = 0x1c030000,
- [VE_PL041] = 0x1c040000,
- [VE_MMCI] = 0x1c050000,
- [VE_KMI0] = 0x1c060000,
- [VE_KMI1] = 0x1c070000,
- [VE_UART0] = 0x1c090000,
- [VE_UART1] = 0x1c0a0000,
- [VE_UART2] = 0x1c0b0000,
- [VE_UART3] = 0x1c0c0000,
- [VE_WDT] = 0x1c0f0000,
- [VE_TIMER01] = 0x1c110000,
- [VE_TIMER23] = 0x1c120000,
- [VE_VIRTIO] = 0x1c130000,
- [VE_SERIALDVI] = 0x1c160000,
- [VE_RTC] = 0x1c170000,
- [VE_COMPACTFLASH] = 0x1c1a0000,
- [VE_CLCD] = 0x1c1f0000,
-};
-
-/* Structure defining the peculiarities of a specific daughterboard */
-
-typedef struct VEDBoardInfo VEDBoardInfo;
-
-typedef struct {
- MachineClass parent;
- VEDBoardInfo *daughterboard;
-} VexpressMachineClass;
-
-typedef struct {
- MachineState parent;
- bool secure;
-} VexpressMachineState;
-
-#define TYPE_VEXPRESS_MACHINE "vexpress"
-#define TYPE_VEXPRESS_A9_MACHINE MACHINE_TYPE_NAME("vexpress-a9")
-#define TYPE_VEXPRESS_A15_MACHINE MACHINE_TYPE_NAME("vexpress-a15")
-#define VEXPRESS_MACHINE(obj) \
- OBJECT_CHECK(VexpressMachineState, (obj), TYPE_VEXPRESS_MACHINE)
-#define VEXPRESS_MACHINE_GET_CLASS(obj) \
- OBJECT_GET_CLASS(VexpressMachineClass, obj, TYPE_VEXPRESS_MACHINE)
-#define VEXPRESS_MACHINE_CLASS(klass) \
- OBJECT_CLASS_CHECK(VexpressMachineClass, klass, TYPE_VEXPRESS_MACHINE)
-
-typedef void DBoardInitFn(const VexpressMachineState *machine,
- ram_addr_t ram_size,
- const char *cpu_model,
- qemu_irq *pic);
-
-struct VEDBoardInfo {
- struct arm_boot_info bootinfo;
- const hwaddr *motherboard_map;
- hwaddr loader_start;
- const hwaddr gic_cpu_if_addr;
- uint32_t proc_id;
- uint32_t num_voltage_sensors;
- const uint32_t *voltages;
- uint32_t num_clocks;
- const uint32_t *clocks;
- DBoardInitFn *init;
-};
-
-static void init_cpus(const char *cpu_model, const char *privdev,
- hwaddr periphbase, qemu_irq *pic, bool secure)
-{
- ObjectClass *cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
- DeviceState *dev;
- SysBusDevice *busdev;
- int n;
-
- if (!cpu_oc) {
- fprintf(stderr, "Unable to find CPU definition\n");
- exit(1);
- }
-
- /* Create the actual CPUs */
- for (n = 0; n < smp_cpus; n++) {
- Object *cpuobj = object_new(object_class_get_name(cpu_oc));
-
- if (!secure) {
- object_property_set_bool(cpuobj, false, "has_el3", NULL);
- }
-
- if (object_property_find(cpuobj, "reset-cbar", NULL)) {
- object_property_set_int(cpuobj, periphbase,
- "reset-cbar", &error_abort);
- }
- object_property_set_bool(cpuobj, true, "realized", &error_fatal);
- }
-
- /* Create the private peripheral devices (including the GIC);
- * this must happen after the CPUs are created because a15mpcore_priv
- * wires itself up to the CPU's generic_timer gpio out lines.
- */
- dev = qdev_create(NULL, privdev);
- qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
- qdev_init_nofail(dev);
- busdev = SYS_BUS_DEVICE(dev);
- sysbus_mmio_map(busdev, 0, periphbase);
-
- /* Interrupts [42:0] are from the motherboard;
- * [47:43] are reserved; [63:48] are daughterboard
- * peripherals. Note that some documentation numbers
- * external interrupts starting from 32 (because there
- * are internal interrupts 0..31).
- */
- for (n = 0; n < 64; n++) {
- pic[n] = qdev_get_gpio_in(dev, n);
- }
-
- /* Connect the CPUs to the GIC */
- for (n = 0; n < smp_cpus; n++) {
- DeviceState *cpudev = DEVICE(qemu_get_cpu(n));
-
- sysbus_connect_irq(busdev, n, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
- sysbus_connect_irq(busdev, n + smp_cpus,
- qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
- }
-}
-
-static void a9_daughterboard_init(const VexpressMachineState *vms,
- ram_addr_t ram_size,
- const char *cpu_model,
- qemu_irq *pic)
-{
- MemoryRegion *sysmem = get_system_memory();
- MemoryRegion *ram = g_new(MemoryRegion, 1);
- MemoryRegion *lowram = g_new(MemoryRegion, 1);
- ram_addr_t low_ram_size;
-
- if (!cpu_model) {
- cpu_model = "cortex-a9";
- }
-
- if (ram_size > 0x40000000) {
- /* 1GB is the maximum the address space permits */
- fprintf(stderr, "vexpress-a9: cannot model more than 1GB RAM\n");
- exit(1);
- }
-
- memory_region_allocate_system_memory(ram, NULL, "vexpress.highmem",
- ram_size);
- low_ram_size = ram_size;
- if (low_ram_size > 0x4000000) {
- low_ram_size = 0x4000000;
- }
- /* RAM is from 0x60000000 upwards. The bottom 64MB of the
- * address space should in theory be remappable to various
- * things including ROM or RAM; we always map the RAM there.
- */
- memory_region_init_alias(lowram, NULL, "vexpress.lowmem", ram, 0, low_ram_size);
- memory_region_add_subregion(sysmem, 0x0, lowram);
- memory_region_add_subregion(sysmem, 0x60000000, ram);
-
- /* 0x1e000000 A9MPCore (SCU) private memory region */
- init_cpus(cpu_model, "a9mpcore_priv", 0x1e000000, pic, vms->secure);
-
- /* Daughterboard peripherals : 0x10020000 .. 0x20000000 */
-
- /* 0x10020000 PL111 CLCD (daughterboard) */
- sysbus_create_simple("pl111", 0x10020000, pic[44]);
-
- /* 0x10060000 AXI RAM */
- /* 0x100e0000 PL341 Dynamic Memory Controller */
- /* 0x100e1000 PL354 Static Memory Controller */
- /* 0x100e2000 System Configuration Controller */
-
- sysbus_create_simple("sp804", 0x100e4000, pic[48]);
- /* 0x100e5000 SP805 Watchdog module */
- /* 0x100e6000 BP147 TrustZone Protection Controller */
- /* 0x100e9000 PL301 'Fast' AXI matrix */
- /* 0x100ea000 PL301 'Slow' AXI matrix */
- /* 0x100ec000 TrustZone Address Space Controller */
- /* 0x10200000 CoreSight debug APB */
- /* 0x1e00a000 PL310 L2 Cache Controller */
- sysbus_create_varargs("l2x0", 0x1e00a000, NULL);
-}
-
-/* Voltage values for SYS_CFG_VOLT daughterboard registers;
- * values are in microvolts.
- */
-static const uint32_t a9_voltages[] = {
- 1000000, /* VD10 : 1.0V : SoC internal logic voltage */
- 1000000, /* VD10_S2 : 1.0V : PL310, L2 cache, RAM, non-PL310 logic */
- 1000000, /* VD10_S3 : 1.0V : Cortex-A9, cores, MPEs, SCU, PL310 logic */
- 1800000, /* VCC1V8 : 1.8V : DDR2 SDRAM, test chip DDR2 I/O supply */
- 900000, /* DDR2VTT : 0.9V : DDR2 SDRAM VTT termination voltage */
- 3300000, /* VCC3V3 : 3.3V : local board supply for misc external logic */
-};
-
-/* Reset values for daughterboard oscillators (in Hz) */
-static const uint32_t a9_clocks[] = {
- 45000000, /* AMBA AXI ACLK: 45MHz */
- 23750000, /* daughterboard CLCD clock: 23.75MHz */
- 66670000, /* Test chip reference clock: 66.67MHz */
-};
-
-static VEDBoardInfo a9_daughterboard = {
- .motherboard_map = motherboard_legacy_map,
- .loader_start = 0x60000000,
- .gic_cpu_if_addr = 0x1e000100,
- .proc_id = 0x0c000191,
- .num_voltage_sensors = ARRAY_SIZE(a9_voltages),
- .voltages = a9_voltages,
- .num_clocks = ARRAY_SIZE(a9_clocks),
- .clocks = a9_clocks,
- .init = a9_daughterboard_init,
-};
-
-static void a15_daughterboard_init(const VexpressMachineState *vms,
- ram_addr_t ram_size,
- const char *cpu_model,
- qemu_irq *pic)
-{
- MemoryRegion *sysmem = get_system_memory();
- MemoryRegion *ram = g_new(MemoryRegion, 1);
- MemoryRegion *sram = g_new(MemoryRegion, 1);
-
- if (!cpu_model) {
- cpu_model = "cortex-a15";
- }
-
- {
- /* We have to use a separate 64 bit variable here to avoid the gcc
- * "comparison is always false due to limited range of data type"
- * warning if we are on a host where ram_addr_t is 32 bits.
- */
- uint64_t rsz = ram_size;
- if (rsz > (30ULL * 1024 * 1024 * 1024)) {
- fprintf(stderr, "vexpress-a15: cannot model more than 30GB RAM\n");
- exit(1);
- }
- }
-
- memory_region_allocate_system_memory(ram, NULL, "vexpress.highmem",
- ram_size);
- /* RAM is from 0x80000000 upwards; there is no low-memory alias for it. */
- memory_region_add_subregion(sysmem, 0x80000000, ram);
-
- /* 0x2c000000 A15MPCore private memory region (GIC) */
- init_cpus(cpu_model, "a15mpcore_priv", 0x2c000000, pic, vms->secure);
-
- /* A15 daughterboard peripherals: */
-
- /* 0x20000000: CoreSight interfaces: not modelled */
- /* 0x2a000000: PL301 AXI interconnect: not modelled */
- /* 0x2a420000: SCC: not modelled */
- /* 0x2a430000: system counter: not modelled */
- /* 0x2b000000: HDLCD controller: not modelled */
- /* 0x2b060000: SP805 watchdog: not modelled */
- /* 0x2b0a0000: PL341 dynamic memory controller: not modelled */
- /* 0x2e000000: system SRAM */
- memory_region_init_ram(sram, NULL, "vexpress.a15sram", 0x10000,
- &error_fatal);
- vmstate_register_ram_global(sram);
- memory_region_add_subregion(sysmem, 0x2e000000, sram);
-
- /* 0x7ffb0000: DMA330 DMA controller: not modelled */
- /* 0x7ffd0000: PL354 static memory controller: not modelled */
-}
-
-static const uint32_t a15_voltages[] = {
- 900000, /* Vcore: 0.9V : CPU core voltage */
-};
-
-static const uint32_t a15_clocks[] = {
- 60000000, /* OSCCLK0: 60MHz : CPU_CLK reference */
- 0, /* OSCCLK1: reserved */
- 0, /* OSCCLK2: reserved */
- 0, /* OSCCLK3: reserved */
- 40000000, /* OSCCLK4: 40MHz : external AXI master clock */
- 23750000, /* OSCCLK5: 23.75MHz : HDLCD PLL reference */
- 50000000, /* OSCCLK6: 50MHz : static memory controller clock */
- 60000000, /* OSCCLK7: 60MHz : SYSCLK reference */
- 40000000, /* OSCCLK8: 40MHz : DDR2 PLL reference */
-};
-
-static VEDBoardInfo a15_daughterboard = {
- .motherboard_map = motherboard_aseries_map,
- .loader_start = 0x80000000,
- .gic_cpu_if_addr = 0x2c002000,
- .proc_id = 0x14000237,
- .num_voltage_sensors = ARRAY_SIZE(a15_voltages),
- .voltages = a15_voltages,
- .num_clocks = ARRAY_SIZE(a15_clocks),
- .clocks = a15_clocks,
- .init = a15_daughterboard_init,
-};
-
-static int add_virtio_mmio_node(void *fdt, uint32_t acells, uint32_t scells,
- hwaddr addr, hwaddr size, uint32_t intc,
- int irq)
-{
- /* Add a virtio_mmio node to the device tree blob:
- * virtio_mmio@ADDRESS {
- * compatible = "virtio,mmio";
- * reg = <ADDRESS, SIZE>;
- * interrupt-parent = <&intc>;
- * interrupts = <0, irq, 1>;
- * }
- * (Note that the format of the interrupts property is dependent on the
- * interrupt controller that interrupt-parent points to; these are for
- * the ARM GIC and indicate an SPI interrupt, rising-edge-triggered.)
- */
- int rc;
- char *nodename = g_strdup_printf("/virtio_mmio@%" PRIx64, addr);
-
- rc = qemu_fdt_add_subnode(fdt, nodename);
- rc |= qemu_fdt_setprop_string(fdt, nodename,
- "compatible", "virtio,mmio");
- rc |= qemu_fdt_setprop_sized_cells(fdt, nodename, "reg",
- acells, addr, scells, size);
- qemu_fdt_setprop_cells(fdt, nodename, "interrupt-parent", intc);
- qemu_fdt_setprop_cells(fdt, nodename, "interrupts", 0, irq, 1);
- g_free(nodename);
- if (rc) {
- return -1;
- }
- return 0;
-}
-
-static uint32_t find_int_controller(void *fdt)
-{
- /* Find the FDT node corresponding to the interrupt controller
- * for virtio-mmio devices. We do this by scanning the fdt for
- * a node with the right compatibility, since we know there is
- * only one GIC on a vexpress board.
- * We return the phandle of the node, or 0 if none was found.
- */
- const char *compat = "arm,cortex-a9-gic";
- int offset;
-
- offset = fdt_node_offset_by_compatible(fdt, -1, compat);
- if (offset >= 0) {
- return fdt_get_phandle(fdt, offset);
- }
- return 0;
-}
-
-static void vexpress_modify_dtb(const struct arm_boot_info *info, void *fdt)
-{
- uint32_t acells, scells, intc;
- const VEDBoardInfo *daughterboard = (const VEDBoardInfo *)info;
-
- acells = qemu_fdt_getprop_cell(fdt, "/", "#address-cells",
- NULL, &error_fatal);
- scells = qemu_fdt_getprop_cell(fdt, "/", "#size-cells",
- NULL, &error_fatal);
- intc = find_int_controller(fdt);
- if (!intc) {
- /* Not fatal, we just won't provide virtio. This will
- * happen with older device tree blobs.
- */
- fprintf(stderr, "QEMU: warning: couldn't find interrupt controller in "
- "dtb; will not include virtio-mmio devices in the dtb.\n");
- } else {
- int i;
- const hwaddr *map = daughterboard->motherboard_map;
-
- /* We iterate backwards here because adding nodes
- * to the dtb puts them in last-first.
- */
- for (i = NUM_VIRTIO_TRANSPORTS - 1; i >= 0; i--) {
- add_virtio_mmio_node(fdt, acells, scells,
- map[VE_VIRTIO] + 0x200 * i,
- 0x200, intc, 40 + i);
- }
- }
-}
-
-
-/* Open code a private version of pflash registration since we
- * need to set non-default device width for VExpress platform.
- */
-static pflash_t *ve_pflash_cfi01_register(hwaddr base, const char *name,
- DriveInfo *di)
-{
- DeviceState *dev = qdev_create(NULL, "cfi.pflash01");
-
- if (di) {
- qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(di),
- &error_abort);
- }
-
- qdev_prop_set_uint32(dev, "num-blocks",
- VEXPRESS_FLASH_SIZE / VEXPRESS_FLASH_SECT_SIZE);
- qdev_prop_set_uint64(dev, "sector-length", VEXPRESS_FLASH_SECT_SIZE);
- qdev_prop_set_uint8(dev, "width", 4);
- qdev_prop_set_uint8(dev, "device-width", 2);
- qdev_prop_set_bit(dev, "big-endian", false);
- qdev_prop_set_uint16(dev, "id0", 0x89);
- qdev_prop_set_uint16(dev, "id1", 0x18);
- qdev_prop_set_uint16(dev, "id2", 0x00);
- qdev_prop_set_uint16(dev, "id3", 0x00);
- qdev_prop_set_string(dev, "name", name);
- qdev_init_nofail(dev);
-
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
- return OBJECT_CHECK(pflash_t, (dev), "cfi.pflash01");
-}
-
-static void vexpress_common_init(MachineState *machine)
-{
- VexpressMachineState *vms = VEXPRESS_MACHINE(machine);
- VexpressMachineClass *vmc = VEXPRESS_MACHINE_GET_CLASS(machine);
- VEDBoardInfo *daughterboard = vmc->daughterboard;
- DeviceState *dev, *sysctl, *pl041;
- qemu_irq pic[64];
- uint32_t sys_id;
- DriveInfo *dinfo;
- pflash_t *pflash0;
- ram_addr_t vram_size, sram_size;
- MemoryRegion *sysmem = get_system_memory();
- MemoryRegion *vram = g_new(MemoryRegion, 1);
- MemoryRegion *sram = g_new(MemoryRegion, 1);
- MemoryRegion *flashalias = g_new(MemoryRegion, 1);
- MemoryRegion *flash0mem;
- const hwaddr *map = daughterboard->motherboard_map;
- int i;
-
- daughterboard->init(vms, machine->ram_size, machine->cpu_model, pic);
-
- /*
- * If a bios file was provided, attempt to map it into memory
- */
- if (bios_name) {
- char *fn;
- int image_size;
-
- if (drive_get(IF_PFLASH, 0, 0)) {
- error_report("The contents of the first flash device may be "
- "specified with -bios or with -drive if=pflash... "
- "but you cannot use both options at once");
- exit(1);
- }
- fn = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
- if (!fn) {
- error_report("Could not find ROM image '%s'", bios_name);
- exit(1);
- }
- image_size = load_image_targphys(fn, map[VE_NORFLASH0],
- VEXPRESS_FLASH_SIZE);
- g_free(fn);
- if (image_size < 0) {
- error_report("Could not load ROM image '%s'", bios_name);
- exit(1);
- }
- }
-
- /* Motherboard peripherals: the wiring is the same but the
- * addresses vary between the legacy and A-Series memory maps.
- */
-
- sys_id = 0x1190f500;
-
- sysctl = qdev_create(NULL, "realview_sysctl");
- qdev_prop_set_uint32(sysctl, "sys_id", sys_id);
- qdev_prop_set_uint32(sysctl, "proc_id", daughterboard->proc_id);
- qdev_prop_set_uint32(sysctl, "len-db-voltage",
- daughterboard->num_voltage_sensors);
- for (i = 0; i < daughterboard->num_voltage_sensors; i++) {
- char *propname = g_strdup_printf("db-voltage[%d]", i);
- qdev_prop_set_uint32(sysctl, propname, daughterboard->voltages[i]);
- g_free(propname);
- }
- qdev_prop_set_uint32(sysctl, "len-db-clock",
- daughterboard->num_clocks);
- for (i = 0; i < daughterboard->num_clocks; i++) {
- char *propname = g_strdup_printf("db-clock[%d]", i);
- qdev_prop_set_uint32(sysctl, propname, daughterboard->clocks[i]);
- g_free(propname);
- }
- qdev_init_nofail(sysctl);
- sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, map[VE_SYSREGS]);
-
- /* VE_SP810: not modelled */
- /* VE_SERIALPCI: not modelled */
-
- pl041 = qdev_create(NULL, "pl041");
- qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512);
- qdev_init_nofail(pl041);
- sysbus_mmio_map(SYS_BUS_DEVICE(pl041), 0, map[VE_PL041]);
- sysbus_connect_irq(SYS_BUS_DEVICE(pl041), 0, pic[11]);
-
- dev = sysbus_create_varargs("pl181", map[VE_MMCI], pic[9], pic[10], NULL);
- /* Wire up MMC card detect and read-only signals */
- qdev_connect_gpio_out(dev, 0,
- qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_WPROT));
- qdev_connect_gpio_out(dev, 1,
- qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_CARDIN));
-
- sysbus_create_simple("pl050_keyboard", map[VE_KMI0], pic[12]);
- sysbus_create_simple("pl050_mouse", map[VE_KMI1], pic[13]);
-
- sysbus_create_simple("pl011", map[VE_UART0], pic[5]);
- sysbus_create_simple("pl011", map[VE_UART1], pic[6]);
- sysbus_create_simple("pl011", map[VE_UART2], pic[7]);
- sysbus_create_simple("pl011", map[VE_UART3], pic[8]);
-
- sysbus_create_simple("sp804", map[VE_TIMER01], pic[2]);
- sysbus_create_simple("sp804", map[VE_TIMER23], pic[3]);
-
- /* VE_SERIALDVI: not modelled */
-
- sysbus_create_simple("pl031", map[VE_RTC], pic[4]); /* RTC */
-
- /* VE_COMPACTFLASH: not modelled */
-
- sysbus_create_simple("pl111", map[VE_CLCD], pic[14]);
-
- dinfo = drive_get_next(IF_PFLASH);
- pflash0 = ve_pflash_cfi01_register(map[VE_NORFLASH0], "vexpress.flash0",
- dinfo);
- if (!pflash0) {
- fprintf(stderr, "vexpress: error registering flash 0.\n");
- exit(1);
- }
-
- if (map[VE_NORFLASHALIAS] != -1) {
- /* Map flash 0 as an alias into low memory */
- flash0mem = sysbus_mmio_get_region(SYS_BUS_DEVICE(pflash0), 0);
- memory_region_init_alias(flashalias, NULL, "vexpress.flashalias",
- flash0mem, 0, VEXPRESS_FLASH_SIZE);
- memory_region_add_subregion(sysmem, map[VE_NORFLASHALIAS], flashalias);
- }
-
- dinfo = drive_get_next(IF_PFLASH);
- if (!ve_pflash_cfi01_register(map[VE_NORFLASH1], "vexpress.flash1",
- dinfo)) {
- fprintf(stderr, "vexpress: error registering flash 1.\n");
- exit(1);
- }
-
- sram_size = 0x2000000;
- memory_region_init_ram(sram, NULL, "vexpress.sram", sram_size,
- &error_fatal);
- vmstate_register_ram_global(sram);
- memory_region_add_subregion(sysmem, map[VE_SRAM], sram);
-
- vram_size = 0x800000;
- memory_region_init_ram(vram, NULL, "vexpress.vram", vram_size,
- &error_fatal);
- vmstate_register_ram_global(vram);
- memory_region_add_subregion(sysmem, map[VE_VIDEORAM], vram);
-
- /* 0x4e000000 LAN9118 Ethernet */
- if (nd_table[0].used) {
- lan9118_init(&nd_table[0], map[VE_ETHERNET], pic[15]);
- }
-
- /* VE_USB: not modelled */
-
- /* VE_DAPROM: not modelled */
-
- /* Create mmio transports, so the user can create virtio backends
- * (which will be automatically plugged in to the transports). If
- * no backend is created the transport will just sit harmlessly idle.
- */
- for (i = 0; i < NUM_VIRTIO_TRANSPORTS; i++) {
- sysbus_create_simple("virtio-mmio", map[VE_VIRTIO] + 0x200 * i,
- pic[40 + i]);
- }
-
- daughterboard->bootinfo.ram_size = machine->ram_size;
- daughterboard->bootinfo.kernel_filename = machine->kernel_filename;
- daughterboard->bootinfo.kernel_cmdline = machine->kernel_cmdline;
- daughterboard->bootinfo.initrd_filename = machine->initrd_filename;
- daughterboard->bootinfo.nb_cpus = smp_cpus;
- daughterboard->bootinfo.board_id = VEXPRESS_BOARD_ID;
- daughterboard->bootinfo.loader_start = daughterboard->loader_start;
- daughterboard->bootinfo.smp_loader_start = map[VE_SRAM];
- daughterboard->bootinfo.smp_bootreg_addr = map[VE_SYSREGS] + 0x30;
- daughterboard->bootinfo.gic_cpu_if_addr = daughterboard->gic_cpu_if_addr;
- daughterboard->bootinfo.modify_dtb = vexpress_modify_dtb;
- /* Indicate that when booting Linux we should be in secure state */
- daughterboard->bootinfo.secure_boot = true;
- arm_load_kernel(ARM_CPU(first_cpu), &daughterboard->bootinfo);
-}
-
-static bool vexpress_get_secure(Object *obj, Error **errp)
-{
- VexpressMachineState *vms = VEXPRESS_MACHINE(obj);
-
- return vms->secure;
-}
-
-static void vexpress_set_secure(Object *obj, bool value, Error **errp)
-{
- VexpressMachineState *vms = VEXPRESS_MACHINE(obj);
-
- vms->secure = value;
-}
-
-static void vexpress_instance_init(Object *obj)
-{
- VexpressMachineState *vms = VEXPRESS_MACHINE(obj);
-
- /* EL3 is enabled by default on vexpress */
- vms->secure = true;
- object_property_add_bool(obj, "secure", vexpress_get_secure,
- vexpress_set_secure, NULL);
- object_property_set_description(obj, "secure",
- "Set on/off to enable/disable the ARM "
- "Security Extensions (TrustZone)",
- NULL);
-}
-
-static void vexpress_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "ARM Versatile Express";
- mc->init = vexpress_common_init;
- mc->block_default_type = IF_SCSI;
- mc->max_cpus = 4;
-}
-
-static void vexpress_a9_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
- VexpressMachineClass *vmc = VEXPRESS_MACHINE_CLASS(oc);
-
- mc->desc = "ARM Versatile Express for Cortex-A9";
-
- vmc->daughterboard = &a9_daughterboard;
-}
-
-static void vexpress_a15_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
- VexpressMachineClass *vmc = VEXPRESS_MACHINE_CLASS(oc);
-
- mc->desc = "ARM Versatile Express for Cortex-A15";
-
- vmc->daughterboard = &a15_daughterboard;
-}
-
-static const TypeInfo vexpress_info = {
- .name = TYPE_VEXPRESS_MACHINE,
- .parent = TYPE_MACHINE,
- .abstract = true,
- .instance_size = sizeof(VexpressMachineState),
- .instance_init = vexpress_instance_init,
- .class_size = sizeof(VexpressMachineClass),
- .class_init = vexpress_class_init,
-};
-
-static const TypeInfo vexpress_a9_info = {
- .name = TYPE_VEXPRESS_A9_MACHINE,
- .parent = TYPE_VEXPRESS_MACHINE,
- .class_init = vexpress_a9_class_init,
-};
-
-static const TypeInfo vexpress_a15_info = {
- .name = TYPE_VEXPRESS_A15_MACHINE,
- .parent = TYPE_VEXPRESS_MACHINE,
- .class_init = vexpress_a15_class_init,
-};
-
-static void vexpress_machine_init(void)
-{
- type_register_static(&vexpress_info);
- type_register_static(&vexpress_a9_info);
- type_register_static(&vexpress_a15_info);
-}
-
-type_init(vexpress_machine_init);
diff --git a/qemu/hw/arm/virt-acpi-build.c b/qemu/hw/arm/virt-acpi-build.c
deleted file mode 100644
index f51fe396c..000000000
--- a/qemu/hw/arm/virt-acpi-build.c
+++ /dev/null
@@ -1,755 +0,0 @@
-/* Support for generating ACPI tables and passing them to Guests
- *
- * ARM virt ACPI generation
- *
- * Copyright (C) 2008-2010 Kevin O'Connor <kevin@koconnor.net>
- * Copyright (C) 2006 Fabrice Bellard
- * Copyright (C) 2013 Red Hat Inc
- *
- * Author: Michael S. Tsirkin <mst@redhat.com>
- *
- * Copyright (c) 2015 HUAWEI TECHNOLOGIES CO.,LTD.
- *
- * Author: Shannon Zhao <zhaoshenglong@huawei.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "hw/arm/virt-acpi-build.h"
-#include "qemu/bitmap.h"
-#include "trace.h"
-#include "qom/cpu.h"
-#include "target-arm/cpu.h"
-#include "hw/acpi/acpi-defs.h"
-#include "hw/acpi/acpi.h"
-#include "hw/nvram/fw_cfg.h"
-#include "hw/acpi/bios-linker-loader.h"
-#include "hw/loader.h"
-#include "hw/hw.h"
-#include "hw/acpi/aml-build.h"
-#include "hw/pci/pcie_host.h"
-#include "hw/pci/pci.h"
-
-#define ARM_SPI_BASE 32
-#define ACPI_POWER_BUTTON_DEVICE "PWRB"
-
-static void acpi_dsdt_add_cpus(Aml *scope, int smp_cpus)
-{
- uint16_t i;
-
- for (i = 0; i < smp_cpus; i++) {
- Aml *dev = aml_device("C%03x", i);
- aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0007")));
- aml_append(dev, aml_name_decl("_UID", aml_int(i)));
- aml_append(scope, dev);
- }
-}
-
-static void acpi_dsdt_add_uart(Aml *scope, const MemMapEntry *uart_memmap,
- uint32_t uart_irq)
-{
- Aml *dev = aml_device("COM0");
- aml_append(dev, aml_name_decl("_HID", aml_string("ARMH0011")));
- aml_append(dev, aml_name_decl("_UID", aml_int(0)));
-
- Aml *crs = aml_resource_template();
- aml_append(crs, aml_memory32_fixed(uart_memmap->base,
- uart_memmap->size, AML_READ_WRITE));
- aml_append(crs,
- aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
- AML_EXCLUSIVE, &uart_irq, 1));
- aml_append(dev, aml_name_decl("_CRS", crs));
-
- /* The _ADR entry is used to link this device to the UART described
- * in the SPCR table, i.e. SPCR.base_address.address == _ADR.
- */
- aml_append(dev, aml_name_decl("_ADR", aml_int(uart_memmap->base)));
-
- aml_append(scope, dev);
-}
-
-static void acpi_dsdt_add_fw_cfg(Aml *scope, const MemMapEntry *fw_cfg_memmap)
-{
- Aml *dev = aml_device("FWCF");
- aml_append(dev, aml_name_decl("_HID", aml_string("QEMU0002")));
- /* device present, functioning, decoding, not shown in UI */
- aml_append(dev, aml_name_decl("_STA", aml_int(0xB)));
-
- Aml *crs = aml_resource_template();
- aml_append(crs, aml_memory32_fixed(fw_cfg_memmap->base,
- fw_cfg_memmap->size, AML_READ_WRITE));
- aml_append(dev, aml_name_decl("_CRS", crs));
- aml_append(scope, dev);
-}
-
-static void acpi_dsdt_add_flash(Aml *scope, const MemMapEntry *flash_memmap)
-{
- Aml *dev, *crs;
- hwaddr base = flash_memmap->base;
- hwaddr size = flash_memmap->size / 2;
-
- dev = aml_device("FLS0");
- aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0015")));
- aml_append(dev, aml_name_decl("_UID", aml_int(0)));
-
- crs = aml_resource_template();
- aml_append(crs, aml_memory32_fixed(base, size, AML_READ_WRITE));
- aml_append(dev, aml_name_decl("_CRS", crs));
- aml_append(scope, dev);
-
- dev = aml_device("FLS1");
- aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0015")));
- aml_append(dev, aml_name_decl("_UID", aml_int(1)));
- crs = aml_resource_template();
- aml_append(crs, aml_memory32_fixed(base + size, size, AML_READ_WRITE));
- aml_append(dev, aml_name_decl("_CRS", crs));
- aml_append(scope, dev);
-}
-
-static void acpi_dsdt_add_virtio(Aml *scope,
- const MemMapEntry *virtio_mmio_memmap,
- uint32_t mmio_irq, int num)
-{
- hwaddr base = virtio_mmio_memmap->base;
- hwaddr size = virtio_mmio_memmap->size;
- int i;
-
- for (i = 0; i < num; i++) {
- uint32_t irq = mmio_irq + i;
- Aml *dev = aml_device("VR%02u", i);
- aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0005")));
- aml_append(dev, aml_name_decl("_UID", aml_int(i)));
-
- Aml *crs = aml_resource_template();
- aml_append(crs, aml_memory32_fixed(base, size, AML_READ_WRITE));
- aml_append(crs,
- aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
- AML_EXCLUSIVE, &irq, 1));
- aml_append(dev, aml_name_decl("_CRS", crs));
- aml_append(scope, dev);
- base += size;
- }
-}
-
-static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap,
- uint32_t irq, bool use_highmem)
-{
- Aml *method, *crs, *ifctx, *UUID, *ifctx1, *elsectx, *buf;
- int i, bus_no;
- hwaddr base_mmio = memmap[VIRT_PCIE_MMIO].base;
- hwaddr size_mmio = memmap[VIRT_PCIE_MMIO].size;
- hwaddr base_pio = memmap[VIRT_PCIE_PIO].base;
- hwaddr size_pio = memmap[VIRT_PCIE_PIO].size;
- hwaddr base_ecam = memmap[VIRT_PCIE_ECAM].base;
- hwaddr size_ecam = memmap[VIRT_PCIE_ECAM].size;
- int nr_pcie_buses = size_ecam / PCIE_MMCFG_SIZE_MIN;
-
- Aml *dev = aml_device("%s", "PCI0");
- aml_append(dev, aml_name_decl("_HID", aml_string("PNP0A08")));
- aml_append(dev, aml_name_decl("_CID", aml_string("PNP0A03")));
- aml_append(dev, aml_name_decl("_SEG", aml_int(0)));
- aml_append(dev, aml_name_decl("_BBN", aml_int(0)));
- aml_append(dev, aml_name_decl("_ADR", aml_int(0)));
- aml_append(dev, aml_name_decl("_UID", aml_string("PCI0")));
- aml_append(dev, aml_name_decl("_STR", aml_unicode("PCIe 0 Device")));
- aml_append(dev, aml_name_decl("_CCA", aml_int(1)));
-
- /* Declare the PCI Routing Table. */
- Aml *rt_pkg = aml_package(nr_pcie_buses * PCI_NUM_PINS);
- for (bus_no = 0; bus_no < nr_pcie_buses; bus_no++) {
- for (i = 0; i < PCI_NUM_PINS; i++) {
- int gsi = (i + bus_no) % PCI_NUM_PINS;
- Aml *pkg = aml_package(4);
- aml_append(pkg, aml_int((bus_no << 16) | 0xFFFF));
- aml_append(pkg, aml_int(i));
- aml_append(pkg, aml_name("GSI%d", gsi));
- aml_append(pkg, aml_int(0));
- aml_append(rt_pkg, pkg);
- }
- }
- aml_append(dev, aml_name_decl("_PRT", rt_pkg));
-
- /* Create GSI link device */
- for (i = 0; i < PCI_NUM_PINS; i++) {
- uint32_t irqs = irq + i;
- Aml *dev_gsi = aml_device("GSI%d", i);
- aml_append(dev_gsi, aml_name_decl("_HID", aml_string("PNP0C0F")));
- aml_append(dev_gsi, aml_name_decl("_UID", aml_int(0)));
- crs = aml_resource_template();
- aml_append(crs,
- aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
- AML_EXCLUSIVE, &irqs, 1));
- aml_append(dev_gsi, aml_name_decl("_PRS", crs));
- crs = aml_resource_template();
- aml_append(crs,
- aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
- AML_EXCLUSIVE, &irqs, 1));
- aml_append(dev_gsi, aml_name_decl("_CRS", crs));
- method = aml_method("_SRS", 1, AML_NOTSERIALIZED);
- aml_append(dev_gsi, method);
- aml_append(dev, dev_gsi);
- }
-
- method = aml_method("_CBA", 0, AML_NOTSERIALIZED);
- aml_append(method, aml_return(aml_int(base_ecam)));
- aml_append(dev, method);
-
- method = aml_method("_CRS", 0, AML_NOTSERIALIZED);
- Aml *rbuf = aml_resource_template();
- aml_append(rbuf,
- aml_word_bus_number(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE,
- 0x0000, 0x0000, nr_pcie_buses - 1, 0x0000,
- nr_pcie_buses));
- aml_append(rbuf,
- aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
- AML_NON_CACHEABLE, AML_READ_WRITE, 0x0000, base_mmio,
- base_mmio + size_mmio - 1, 0x0000, size_mmio));
- aml_append(rbuf,
- aml_dword_io(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE,
- AML_ENTIRE_RANGE, 0x0000, 0x0000, size_pio - 1, base_pio,
- size_pio));
-
- if (use_highmem) {
- hwaddr base_mmio_high = memmap[VIRT_PCIE_MMIO_HIGH].base;
- hwaddr size_mmio_high = memmap[VIRT_PCIE_MMIO_HIGH].size;
-
- aml_append(rbuf,
- aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
- AML_NON_CACHEABLE, AML_READ_WRITE, 0x0000,
- base_mmio_high, base_mmio_high, 0x0000,
- size_mmio_high));
- }
-
- aml_append(method, aml_name_decl("RBUF", rbuf));
- aml_append(method, aml_return(rbuf));
- aml_append(dev, method);
-
- /* Declare an _OSC (OS Control Handoff) method */
- aml_append(dev, aml_name_decl("SUPP", aml_int(0)));
- aml_append(dev, aml_name_decl("CTRL", aml_int(0)));
- method = aml_method("_OSC", 4, AML_NOTSERIALIZED);
- aml_append(method,
- aml_create_dword_field(aml_arg(3), aml_int(0), "CDW1"));
-
- /* PCI Firmware Specification 3.0
- * 4.5.1. _OSC Interface for PCI Host Bridge Devices
- * The _OSC interface for a PCI/PCI-X/PCI Express hierarchy is
- * identified by the Universal Unique IDentifier (UUID)
- * 33DB4D5B-1FF7-401C-9657-7441C03DD766
- */
- UUID = aml_touuid("33DB4D5B-1FF7-401C-9657-7441C03DD766");
- ifctx = aml_if(aml_equal(aml_arg(0), UUID));
- aml_append(ifctx,
- aml_create_dword_field(aml_arg(3), aml_int(4), "CDW2"));
- aml_append(ifctx,
- aml_create_dword_field(aml_arg(3), aml_int(8), "CDW3"));
- aml_append(ifctx, aml_store(aml_name("CDW2"), aml_name("SUPP")));
- aml_append(ifctx, aml_store(aml_name("CDW3"), aml_name("CTRL")));
- aml_append(ifctx, aml_store(aml_and(aml_name("CTRL"), aml_int(0x1D), NULL),
- aml_name("CTRL")));
-
- ifctx1 = aml_if(aml_lnot(aml_equal(aml_arg(1), aml_int(0x1))));
- aml_append(ifctx1, aml_store(aml_or(aml_name("CDW1"), aml_int(0x08), NULL),
- aml_name("CDW1")));
- aml_append(ifctx, ifctx1);
-
- ifctx1 = aml_if(aml_lnot(aml_equal(aml_name("CDW3"), aml_name("CTRL"))));
- aml_append(ifctx1, aml_store(aml_or(aml_name("CDW1"), aml_int(0x10), NULL),
- aml_name("CDW1")));
- aml_append(ifctx, ifctx1);
-
- aml_append(ifctx, aml_store(aml_name("CTRL"), aml_name("CDW3")));
- aml_append(ifctx, aml_return(aml_arg(3)));
- aml_append(method, ifctx);
-
- elsectx = aml_else();
- aml_append(elsectx, aml_store(aml_or(aml_name("CDW1"), aml_int(4), NULL),
- aml_name("CDW1")));
- aml_append(elsectx, aml_return(aml_arg(3)));
- aml_append(method, elsectx);
- aml_append(dev, method);
-
- method = aml_method("_DSM", 4, AML_NOTSERIALIZED);
-
- /* PCI Firmware Specification 3.0
- * 4.6.1. _DSM for PCI Express Slot Information
- * The UUID in _DSM in this context is
- * {E5C937D0-3553-4D7A-9117-EA4D19C3434D}
- */
- UUID = aml_touuid("E5C937D0-3553-4D7A-9117-EA4D19C3434D");
- ifctx = aml_if(aml_equal(aml_arg(0), UUID));
- ifctx1 = aml_if(aml_equal(aml_arg(2), aml_int(0)));
- uint8_t byte_list[1] = {1};
- buf = aml_buffer(1, byte_list);
- aml_append(ifctx1, aml_return(buf));
- aml_append(ifctx, ifctx1);
- aml_append(method, ifctx);
-
- byte_list[0] = 0;
- buf = aml_buffer(1, byte_list);
- aml_append(method, aml_return(buf));
- aml_append(dev, method);
-
- Aml *dev_rp0 = aml_device("%s", "RP0");
- aml_append(dev_rp0, aml_name_decl("_ADR", aml_int(0)));
- aml_append(dev, dev_rp0);
- aml_append(scope, dev);
-}
-
-static void acpi_dsdt_add_gpio(Aml *scope, const MemMapEntry *gpio_memmap,
- uint32_t gpio_irq)
-{
- Aml *dev = aml_device("GPO0");
- aml_append(dev, aml_name_decl("_HID", aml_string("ARMH0061")));
- aml_append(dev, aml_name_decl("_ADR", aml_int(0)));
- aml_append(dev, aml_name_decl("_UID", aml_int(0)));
-
- Aml *crs = aml_resource_template();
- aml_append(crs, aml_memory32_fixed(gpio_memmap->base, gpio_memmap->size,
- AML_READ_WRITE));
- aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
- AML_EXCLUSIVE, &gpio_irq, 1));
- aml_append(dev, aml_name_decl("_CRS", crs));
-
- Aml *aei = aml_resource_template();
- /* Pin 3 for power button */
- const uint32_t pin_list[1] = {3};
- aml_append(aei, aml_gpio_int(AML_CONSUMER, AML_EDGE, AML_ACTIVE_HIGH,
- AML_EXCLUSIVE, AML_PULL_UP, 0, pin_list, 1,
- "GPO0", NULL, 0));
- aml_append(dev, aml_name_decl("_AEI", aei));
-
- /* _E03 is handle for power button */
- Aml *method = aml_method("_E03", 0, AML_NOTSERIALIZED);
- aml_append(method, aml_notify(aml_name(ACPI_POWER_BUTTON_DEVICE),
- aml_int(0x80)));
- aml_append(dev, method);
- aml_append(scope, dev);
-}
-
-static void acpi_dsdt_add_power_button(Aml *scope)
-{
- Aml *dev = aml_device(ACPI_POWER_BUTTON_DEVICE);
- aml_append(dev, aml_name_decl("_HID", aml_string("PNP0C0C")));
- aml_append(dev, aml_name_decl("_ADR", aml_int(0)));
- aml_append(dev, aml_name_decl("_UID", aml_int(0)));
- aml_append(scope, dev);
-}
-
-/* RSDP */
-static GArray *
-build_rsdp(GArray *rsdp_table, GArray *linker, unsigned rsdt)
-{
- AcpiRsdpDescriptor *rsdp = acpi_data_push(rsdp_table, sizeof *rsdp);
-
- bios_linker_loader_alloc(linker, ACPI_BUILD_RSDP_FILE, 16,
- true /* fseg memory */);
-
- memcpy(&rsdp->signature, "RSD PTR ", sizeof(rsdp->signature));
- memcpy(rsdp->oem_id, ACPI_BUILD_APPNAME6, sizeof(rsdp->oem_id));
- rsdp->length = cpu_to_le32(sizeof(*rsdp));
- rsdp->revision = 0x02;
-
- /* Point to RSDT */
- rsdp->rsdt_physical_address = cpu_to_le32(rsdt);
- /* Address to be filled by Guest linker */
- bios_linker_loader_add_pointer(linker, ACPI_BUILD_RSDP_FILE,
- ACPI_BUILD_TABLE_FILE,
- rsdp_table, &rsdp->rsdt_physical_address,
- sizeof rsdp->rsdt_physical_address);
- rsdp->checksum = 0;
- /* Checksum to be filled by Guest linker */
- bios_linker_loader_add_checksum(linker, ACPI_BUILD_RSDP_FILE,
- rsdp_table, rsdp, sizeof *rsdp,
- &rsdp->checksum);
-
- return rsdp_table;
-}
-
-static void
-build_spcr(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info)
-{
- AcpiSerialPortConsoleRedirection *spcr;
- const MemMapEntry *uart_memmap = &guest_info->memmap[VIRT_UART];
- int irq = guest_info->irqmap[VIRT_UART] + ARM_SPI_BASE;
-
- spcr = acpi_data_push(table_data, sizeof(*spcr));
-
- spcr->interface_type = 0x3; /* ARM PL011 UART */
-
- spcr->base_address.space_id = AML_SYSTEM_MEMORY;
- spcr->base_address.bit_width = 8;
- spcr->base_address.bit_offset = 0;
- spcr->base_address.access_width = 1;
- spcr->base_address.address = cpu_to_le64(uart_memmap->base);
-
- spcr->interrupt_types = (1 << 3); /* Bit[3] ARMH GIC interrupt */
- spcr->gsi = cpu_to_le32(irq); /* Global System Interrupt */
-
- spcr->baud = 3; /* Baud Rate: 3 = 9600 */
- spcr->parity = 0; /* No Parity */
- spcr->stopbits = 1; /* 1 Stop bit */
- spcr->flowctrl = (1 << 1); /* Bit[1] = RTS/CTS hardware flow control */
- spcr->term_type = 0; /* Terminal Type: 0 = VT100 */
-
- spcr->pci_device_id = 0xffff; /* PCI Device ID: not a PCI device */
- spcr->pci_vendor_id = 0xffff; /* PCI Vendor ID: not a PCI device */
-
- build_header(linker, table_data, (void *)spcr, "SPCR", sizeof(*spcr), 2,
- NULL, NULL);
-}
-
-static void
-build_mcfg(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info)
-{
- AcpiTableMcfg *mcfg;
- const MemMapEntry *memmap = guest_info->memmap;
- int len = sizeof(*mcfg) + sizeof(mcfg->allocation[0]);
-
- mcfg = acpi_data_push(table_data, len);
- mcfg->allocation[0].address = cpu_to_le64(memmap[VIRT_PCIE_ECAM].base);
-
- /* Only a single allocation so no need to play with segments */
- mcfg->allocation[0].pci_segment = cpu_to_le16(0);
- mcfg->allocation[0].start_bus_number = 0;
- mcfg->allocation[0].end_bus_number = (memmap[VIRT_PCIE_ECAM].size
- / PCIE_MMCFG_SIZE_MIN) - 1;
-
- build_header(linker, table_data, (void *)mcfg, "MCFG", len, 1, NULL, NULL);
-}
-
-/* GTDT */
-static void
-build_gtdt(GArray *table_data, GArray *linker)
-{
- int gtdt_start = table_data->len;
- AcpiGenericTimerTable *gtdt;
-
- gtdt = acpi_data_push(table_data, sizeof *gtdt);
- /* The interrupt values are the same with the device tree when adding 16 */
- gtdt->secure_el1_interrupt = ARCH_TIMER_S_EL1_IRQ + 16;
- gtdt->secure_el1_flags = ACPI_EDGE_SENSITIVE;
-
- gtdt->non_secure_el1_interrupt = ARCH_TIMER_NS_EL1_IRQ + 16;
- gtdt->non_secure_el1_flags = ACPI_EDGE_SENSITIVE | ACPI_GTDT_ALWAYS_ON;
-
- gtdt->virtual_timer_interrupt = ARCH_TIMER_VIRT_IRQ + 16;
- gtdt->virtual_timer_flags = ACPI_EDGE_SENSITIVE;
-
- gtdt->non_secure_el2_interrupt = ARCH_TIMER_NS_EL2_IRQ + 16;
- gtdt->non_secure_el2_flags = ACPI_EDGE_SENSITIVE;
-
- build_header(linker, table_data,
- (void *)(table_data->data + gtdt_start), "GTDT",
- table_data->len - gtdt_start, 2, NULL, NULL);
-}
-
-/* MADT */
-static void
-build_madt(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info)
-{
- int madt_start = table_data->len;
- const MemMapEntry *memmap = guest_info->memmap;
- const int *irqmap = guest_info->irqmap;
- AcpiMultipleApicTable *madt;
- AcpiMadtGenericDistributor *gicd;
- AcpiMadtGenericMsiFrame *gic_msi;
- int i;
-
- madt = acpi_data_push(table_data, sizeof *madt);
-
- gicd = acpi_data_push(table_data, sizeof *gicd);
- gicd->type = ACPI_APIC_GENERIC_DISTRIBUTOR;
- gicd->length = sizeof(*gicd);
- gicd->base_address = memmap[VIRT_GIC_DIST].base;
-
- for (i = 0; i < guest_info->smp_cpus; i++) {
- AcpiMadtGenericInterrupt *gicc = acpi_data_push(table_data,
- sizeof *gicc);
- ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(i));
-
- gicc->type = ACPI_APIC_GENERIC_INTERRUPT;
- gicc->length = sizeof(*gicc);
- if (guest_info->gic_version == 2) {
- gicc->base_address = memmap[VIRT_GIC_CPU].base;
- }
- gicc->cpu_interface_number = i;
- gicc->arm_mpidr = armcpu->mp_affinity;
- gicc->uid = i;
- gicc->flags = cpu_to_le32(ACPI_GICC_ENABLED);
- }
-
- if (guest_info->gic_version == 3) {
- AcpiMadtGenericRedistributor *gicr = acpi_data_push(table_data,
- sizeof *gicr);
-
- gicr->type = ACPI_APIC_GENERIC_REDISTRIBUTOR;
- gicr->length = sizeof(*gicr);
- gicr->base_address = cpu_to_le64(memmap[VIRT_GIC_REDIST].base);
- gicr->range_length = cpu_to_le32(memmap[VIRT_GIC_REDIST].size);
- } else {
- gic_msi = acpi_data_push(table_data, sizeof *gic_msi);
- gic_msi->type = ACPI_APIC_GENERIC_MSI_FRAME;
- gic_msi->length = sizeof(*gic_msi);
- gic_msi->gic_msi_frame_id = 0;
- gic_msi->base_address = cpu_to_le64(memmap[VIRT_GIC_V2M].base);
- gic_msi->flags = cpu_to_le32(1);
- gic_msi->spi_count = cpu_to_le16(NUM_GICV2M_SPIS);
- gic_msi->spi_base = cpu_to_le16(irqmap[VIRT_GIC_V2M] + ARM_SPI_BASE);
- }
-
- build_header(linker, table_data,
- (void *)(table_data->data + madt_start), "APIC",
- table_data->len - madt_start, 3, NULL, NULL);
-}
-
-/* FADT */
-static void
-build_fadt(GArray *table_data, GArray *linker, unsigned dsdt)
-{
- AcpiFadtDescriptorRev5_1 *fadt = acpi_data_push(table_data, sizeof(*fadt));
-
- /* Hardware Reduced = 1 and use PSCI 0.2+ and with HVC */
- fadt->flags = cpu_to_le32(1 << ACPI_FADT_F_HW_REDUCED_ACPI);
- fadt->arm_boot_flags = cpu_to_le16((1 << ACPI_FADT_ARM_USE_PSCI_G_0_2) |
- (1 << ACPI_FADT_ARM_PSCI_USE_HVC));
-
- /* ACPI v5.1 (fadt->revision.fadt->minor_revision) */
- fadt->minor_revision = 0x1;
-
- fadt->dsdt = cpu_to_le32(dsdt);
- /* DSDT address to be filled by Guest linker */
- bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE,
- ACPI_BUILD_TABLE_FILE,
- table_data, &fadt->dsdt,
- sizeof fadt->dsdt);
-
- build_header(linker, table_data,
- (void *)fadt, "FACP", sizeof(*fadt), 5, NULL, NULL);
-}
-
-/* DSDT */
-static void
-build_dsdt(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info)
-{
- Aml *scope, *dsdt;
- const MemMapEntry *memmap = guest_info->memmap;
- const int *irqmap = guest_info->irqmap;
-
- dsdt = init_aml_allocator();
- /* Reserve space for header */
- acpi_data_push(dsdt->buf, sizeof(AcpiTableHeader));
-
- /* When booting the VM with UEFI, UEFI takes ownership of the RTC hardware.
- * While UEFI can use libfdt to disable the RTC device node in the DTB that
- * it passes to the OS, it cannot modify AML. Therefore, we won't generate
- * the RTC ACPI device at all when using UEFI.
- */
- scope = aml_scope("\\_SB");
- acpi_dsdt_add_cpus(scope, guest_info->smp_cpus);
- acpi_dsdt_add_uart(scope, &memmap[VIRT_UART],
- (irqmap[VIRT_UART] + ARM_SPI_BASE));
- acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]);
- acpi_dsdt_add_fw_cfg(scope, &memmap[VIRT_FW_CFG]);
- acpi_dsdt_add_virtio(scope, &memmap[VIRT_MMIO],
- (irqmap[VIRT_MMIO] + ARM_SPI_BASE), NUM_VIRTIO_TRANSPORTS);
- acpi_dsdt_add_pci(scope, memmap, (irqmap[VIRT_PCIE] + ARM_SPI_BASE),
- guest_info->use_highmem);
- acpi_dsdt_add_gpio(scope, &memmap[VIRT_GPIO],
- (irqmap[VIRT_GPIO] + ARM_SPI_BASE));
- acpi_dsdt_add_power_button(scope);
-
- aml_append(dsdt, scope);
-
- /* copy AML table into ACPI tables blob and patch header there */
- g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len);
- build_header(linker, table_data,
- (void *)(table_data->data + table_data->len - dsdt->buf->len),
- "DSDT", dsdt->buf->len, 2, NULL, NULL);
- free_aml_allocator();
-}
-
-typedef
-struct AcpiBuildState {
- /* Copy of table in RAM (for patching). */
- MemoryRegion *table_mr;
- MemoryRegion *rsdp_mr;
- MemoryRegion *linker_mr;
- /* Is table patched? */
- bool patched;
- VirtGuestInfo *guest_info;
-} AcpiBuildState;
-
-static
-void virt_acpi_build(VirtGuestInfo *guest_info, AcpiBuildTables *tables)
-{
- GArray *table_offsets;
- unsigned dsdt, rsdt;
- GArray *tables_blob = tables->table_data;
-
- table_offsets = g_array_new(false, true /* clear */,
- sizeof(uint32_t));
-
- bios_linker_loader_alloc(tables->linker, ACPI_BUILD_TABLE_FILE,
- 64, false /* high memory */);
-
- /*
- * The ACPI v5.1 tables for Hardware-reduced ACPI platform are:
- * RSDP
- * RSDT
- * FADT
- * GTDT
- * MADT
- * MCFG
- * DSDT
- */
-
- /* DSDT is pointed to by FADT */
- dsdt = tables_blob->len;
- build_dsdt(tables_blob, tables->linker, guest_info);
-
- /* FADT MADT GTDT MCFG SPCR pointed to by RSDT */
- acpi_add_table(table_offsets, tables_blob);
- build_fadt(tables_blob, tables->linker, dsdt);
-
- acpi_add_table(table_offsets, tables_blob);
- build_madt(tables_blob, tables->linker, guest_info);
-
- acpi_add_table(table_offsets, tables_blob);
- build_gtdt(tables_blob, tables->linker);
-
- acpi_add_table(table_offsets, tables_blob);
- build_mcfg(tables_blob, tables->linker, guest_info);
-
- acpi_add_table(table_offsets, tables_blob);
- build_spcr(tables_blob, tables->linker, guest_info);
-
- /* RSDT is pointed to by RSDP */
- rsdt = tables_blob->len;
- build_rsdt(tables_blob, tables->linker, table_offsets, NULL, NULL);
-
- /* RSDP is in FSEG memory, so allocate it separately */
- build_rsdp(tables->rsdp, tables->linker, rsdt);
-
- /* Cleanup memory that's no longer used. */
- g_array_free(table_offsets, true);
-}
-
-static void acpi_ram_update(MemoryRegion *mr, GArray *data)
-{
- uint32_t size = acpi_data_len(data);
-
- /* Make sure RAM size is correct - in case it got changed
- * e.g. by migration */
- memory_region_ram_resize(mr, size, &error_abort);
-
- memcpy(memory_region_get_ram_ptr(mr), data->data, size);
- memory_region_set_dirty(mr, 0, size);
-}
-
-static void virt_acpi_build_update(void *build_opaque)
-{
- AcpiBuildState *build_state = build_opaque;
- AcpiBuildTables tables;
-
- /* No state to update or already patched? Nothing to do. */
- if (!build_state || build_state->patched) {
- return;
- }
- build_state->patched = true;
-
- acpi_build_tables_init(&tables);
-
- virt_acpi_build(build_state->guest_info, &tables);
-
- acpi_ram_update(build_state->table_mr, tables.table_data);
- acpi_ram_update(build_state->rsdp_mr, tables.rsdp);
- acpi_ram_update(build_state->linker_mr, tables.linker);
-
-
- acpi_build_tables_cleanup(&tables, true);
-}
-
-static void virt_acpi_build_reset(void *build_opaque)
-{
- AcpiBuildState *build_state = build_opaque;
- build_state->patched = false;
-}
-
-static MemoryRegion *acpi_add_rom_blob(AcpiBuildState *build_state,
- GArray *blob, const char *name,
- uint64_t max_size)
-{
- return rom_add_blob(name, blob->data, acpi_data_len(blob), max_size, -1,
- name, virt_acpi_build_update, build_state);
-}
-
-static const VMStateDescription vmstate_virt_acpi_build = {
- .name = "virt_acpi_build",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_BOOL(patched, AcpiBuildState),
- VMSTATE_END_OF_LIST()
- },
-};
-
-void virt_acpi_setup(VirtGuestInfo *guest_info)
-{
- AcpiBuildTables tables;
- AcpiBuildState *build_state;
-
- if (!guest_info->fw_cfg) {
- trace_virt_acpi_setup();
- return;
- }
-
- if (!acpi_enabled) {
- trace_virt_acpi_setup();
- return;
- }
-
- build_state = g_malloc0(sizeof *build_state);
- build_state->guest_info = guest_info;
-
- acpi_build_tables_init(&tables);
- virt_acpi_build(build_state->guest_info, &tables);
-
- /* Now expose it all to Guest */
- build_state->table_mr = acpi_add_rom_blob(build_state, tables.table_data,
- ACPI_BUILD_TABLE_FILE,
- ACPI_BUILD_TABLE_MAX_SIZE);
- assert(build_state->table_mr != NULL);
-
- build_state->linker_mr =
- acpi_add_rom_blob(build_state, tables.linker, "etc/table-loader", 0);
-
- fw_cfg_add_file(guest_info->fw_cfg, ACPI_BUILD_TPMLOG_FILE,
- tables.tcpalog->data, acpi_data_len(tables.tcpalog));
-
- build_state->rsdp_mr = acpi_add_rom_blob(build_state, tables.rsdp,
- ACPI_BUILD_RSDP_FILE, 0);
-
- qemu_register_reset(virt_acpi_build_reset, build_state);
- virt_acpi_build_reset(build_state);
- vmstate_register(NULL, 0, &vmstate_virt_acpi_build, build_state);
-
- /* Cleanup tables but don't free the memory: we track it
- * in build_state.
- */
- acpi_build_tables_cleanup(&tables, false);
-}
diff --git a/qemu/hw/arm/virt.c b/qemu/hw/arm/virt.c
deleted file mode 100644
index 56d35c771..000000000
--- a/qemu/hw/arm/virt.c
+++ /dev/null
@@ -1,1435 +0,0 @@
-/*
- * ARM mach-virt emulation
- *
- * Copyright (c) 2013 Linaro Limited
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2 or later, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * Emulate a virtual board which works by passing Linux all the information
- * it needs about what devices are present via the device tree.
- * There are some restrictions about what we can do here:
- * + we can only present devices whose Linux drivers will work based
- * purely on the device tree with no platform data at all
- * + we want to present a very stripped-down minimalist platform,
- * both because this reduces the security attack surface from the guest
- * and also because it reduces our exposure to being broken when
- * the kernel updates its device tree bindings and requires further
- * information in a device binding that we aren't providing.
- * This is essentially the same approach kvmtool uses.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/sysbus.h"
-#include "hw/arm/arm.h"
-#include "hw/arm/primecell.h"
-#include "hw/arm/virt.h"
-#include "hw/devices.h"
-#include "net/net.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/device_tree.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/kvm.h"
-#include "hw/boards.h"
-#include "hw/loader.h"
-#include "exec/address-spaces.h"
-#include "qemu/bitops.h"
-#include "qemu/error-report.h"
-#include "hw/pci-host/gpex.h"
-#include "hw/arm/virt-acpi-build.h"
-#include "hw/arm/sysbus-fdt.h"
-#include "hw/platform-bus.h"
-#include "hw/arm/fdt.h"
-#include "hw/intc/arm_gic_common.h"
-#include "kvm_arm.h"
-#include "hw/smbios/smbios.h"
-#include "qapi/visitor.h"
-#include "standard-headers/linux/input.h"
-
-/* Number of external interrupt lines to configure the GIC with */
-#define NUM_IRQS 256
-
-#define PLATFORM_BUS_NUM_IRQS 64
-
-static ARMPlatformBusSystemParams platform_bus_params;
-
-typedef struct VirtBoardInfo {
- struct arm_boot_info bootinfo;
- const char *cpu_model;
- const MemMapEntry *memmap;
- const int *irqmap;
- int smp_cpus;
- void *fdt;
- int fdt_size;
- uint32_t clock_phandle;
- uint32_t gic_phandle;
- uint32_t v2m_phandle;
- bool using_psci;
-} VirtBoardInfo;
-
-typedef struct {
- MachineClass parent;
- VirtBoardInfo *daughterboard;
-} VirtMachineClass;
-
-typedef struct {
- MachineState parent;
- bool secure;
- bool highmem;
- int32_t gic_version;
-} VirtMachineState;
-
-#define TYPE_VIRT_MACHINE MACHINE_TYPE_NAME("virt")
-#define VIRT_MACHINE(obj) \
- OBJECT_CHECK(VirtMachineState, (obj), TYPE_VIRT_MACHINE)
-#define VIRT_MACHINE_GET_CLASS(obj) \
- OBJECT_GET_CLASS(VirtMachineClass, obj, TYPE_VIRT_MACHINE)
-#define VIRT_MACHINE_CLASS(klass) \
- OBJECT_CLASS_CHECK(VirtMachineClass, klass, TYPE_VIRT_MACHINE)
-
-/* RAM limit in GB. Since VIRT_MEM starts at the 1GB mark, this means
- * RAM can go up to the 256GB mark, leaving 256GB of the physical
- * address space unallocated and free for future use between 256G and 512G.
- * If we need to provide more RAM to VMs in the future then we need to:
- * * allocate a second bank of RAM starting at 2TB and working up
- * * fix the DT and ACPI table generation code in QEMU to correctly
- * report two split lumps of RAM to the guest
- * * fix KVM in the host kernel to allow guests with >40 bit address spaces
- * (We don't want to fill all the way up to 512GB with RAM because
- * we might want it for non-RAM purposes later. Conversely it seems
- * reasonable to assume that anybody configuring a VM with a quarter
- * of a terabyte of RAM will be doing it on a host with more than a
- * terabyte of physical address space.)
- */
-#define RAMLIMIT_GB 255
-#define RAMLIMIT_BYTES (RAMLIMIT_GB * 1024ULL * 1024 * 1024)
-
-/* Addresses and sizes of our components.
- * 0..128MB is space for a flash device so we can run bootrom code such as UEFI.
- * 128MB..256MB is used for miscellaneous device I/O.
- * 256MB..1GB is reserved for possible future PCI support (ie where the
- * PCI memory window will go if we add a PCI host controller).
- * 1GB and up is RAM (which may happily spill over into the
- * high memory region beyond 4GB).
- * This represents a compromise between how much RAM can be given to
- * a 32 bit VM and leaving space for expansion and in particular for PCI.
- * Note that devices should generally be placed at multiples of 0x10000,
- * to accommodate guests using 64K pages.
- */
-static const MemMapEntry a15memmap[] = {
- /* Space up to 0x8000000 is reserved for a boot ROM */
- [VIRT_FLASH] = { 0, 0x08000000 },
- [VIRT_CPUPERIPHS] = { 0x08000000, 0x00020000 },
- /* GIC distributor and CPU interfaces sit inside the CPU peripheral space */
- [VIRT_GIC_DIST] = { 0x08000000, 0x00010000 },
- [VIRT_GIC_CPU] = { 0x08010000, 0x00010000 },
- [VIRT_GIC_V2M] = { 0x08020000, 0x00001000 },
- /* The space in between here is reserved for GICv3 CPU/vCPU/HYP */
- [VIRT_GIC_ITS] = { 0x08080000, 0x00020000 },
- /* This redistributor space allows up to 2*64kB*123 CPUs */
- [VIRT_GIC_REDIST] = { 0x080A0000, 0x00F60000 },
- [VIRT_UART] = { 0x09000000, 0x00001000 },
- [VIRT_RTC] = { 0x09010000, 0x00001000 },
- [VIRT_FW_CFG] = { 0x09020000, 0x00000018 },
- [VIRT_GPIO] = { 0x09030000, 0x00001000 },
- [VIRT_SECURE_UART] = { 0x09040000, 0x00001000 },
- [VIRT_MMIO] = { 0x0a000000, 0x00000200 },
- /* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
- [VIRT_PLATFORM_BUS] = { 0x0c000000, 0x02000000 },
- [VIRT_SECURE_MEM] = { 0x0e000000, 0x01000000 },
- [VIRT_PCIE_MMIO] = { 0x10000000, 0x2eff0000 },
- [VIRT_PCIE_PIO] = { 0x3eff0000, 0x00010000 },
- [VIRT_PCIE_ECAM] = { 0x3f000000, 0x01000000 },
- [VIRT_MEM] = { 0x40000000, RAMLIMIT_BYTES },
- /* Second PCIe window, 512GB wide at the 512GB boundary */
- [VIRT_PCIE_MMIO_HIGH] = { 0x8000000000ULL, 0x8000000000ULL },
-};
-
-static const int a15irqmap[] = {
- [VIRT_UART] = 1,
- [VIRT_RTC] = 2,
- [VIRT_PCIE] = 3, /* ... to 6 */
- [VIRT_GPIO] = 7,
- [VIRT_SECURE_UART] = 8,
- [VIRT_MMIO] = 16, /* ...to 16 + NUM_VIRTIO_TRANSPORTS - 1 */
- [VIRT_GIC_V2M] = 48, /* ...to 48 + NUM_GICV2M_SPIS - 1 */
- [VIRT_PLATFORM_BUS] = 112, /* ...to 112 + PLATFORM_BUS_NUM_IRQS -1 */
-};
-
-static VirtBoardInfo machines[] = {
- {
- .cpu_model = "cortex-a15",
- .memmap = a15memmap,
- .irqmap = a15irqmap,
- },
- {
- .cpu_model = "cortex-a53",
- .memmap = a15memmap,
- .irqmap = a15irqmap,
- },
- {
- .cpu_model = "cortex-a57",
- .memmap = a15memmap,
- .irqmap = a15irqmap,
- },
- {
- .cpu_model = "host",
- .memmap = a15memmap,
- .irqmap = a15irqmap,
- },
-};
-
-static VirtBoardInfo *find_machine_info(const char *cpu)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(machines); i++) {
- if (strcmp(cpu, machines[i].cpu_model) == 0) {
- return &machines[i];
- }
- }
- return NULL;
-}
-
-static void create_fdt(VirtBoardInfo *vbi)
-{
- void *fdt = create_device_tree(&vbi->fdt_size);
-
- if (!fdt) {
- error_report("create_device_tree() failed");
- exit(1);
- }
-
- vbi->fdt = fdt;
-
- /* Header */
- qemu_fdt_setprop_string(fdt, "/", "compatible", "linux,dummy-virt");
- qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 0x2);
- qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 0x2);
-
- /*
- * /chosen and /memory nodes must exist for load_dtb
- * to fill in necessary properties later
- */
- qemu_fdt_add_subnode(fdt, "/chosen");
- qemu_fdt_add_subnode(fdt, "/memory");
- qemu_fdt_setprop_string(fdt, "/memory", "device_type", "memory");
-
- /* Clock node, for the benefit of the UART. The kernel device tree
- * binding documentation claims the PL011 node clock properties are
- * optional but in practice if you omit them the kernel refuses to
- * probe for the device.
- */
- vbi->clock_phandle = qemu_fdt_alloc_phandle(fdt);
- qemu_fdt_add_subnode(fdt, "/apb-pclk");
- qemu_fdt_setprop_string(fdt, "/apb-pclk", "compatible", "fixed-clock");
- qemu_fdt_setprop_cell(fdt, "/apb-pclk", "#clock-cells", 0x0);
- qemu_fdt_setprop_cell(fdt, "/apb-pclk", "clock-frequency", 24000000);
- qemu_fdt_setprop_string(fdt, "/apb-pclk", "clock-output-names",
- "clk24mhz");
- qemu_fdt_setprop_cell(fdt, "/apb-pclk", "phandle", vbi->clock_phandle);
-
-}
-
-static void fdt_add_psci_node(const VirtBoardInfo *vbi)
-{
- uint32_t cpu_suspend_fn;
- uint32_t cpu_off_fn;
- uint32_t cpu_on_fn;
- uint32_t migrate_fn;
- void *fdt = vbi->fdt;
- ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(0));
-
- if (!vbi->using_psci) {
- return;
- }
-
- qemu_fdt_add_subnode(fdt, "/psci");
- if (armcpu->psci_version == 2) {
- const char comp[] = "arm,psci-0.2\0arm,psci";
- qemu_fdt_setprop(fdt, "/psci", "compatible", comp, sizeof(comp));
-
- cpu_off_fn = QEMU_PSCI_0_2_FN_CPU_OFF;
- if (arm_feature(&armcpu->env, ARM_FEATURE_AARCH64)) {
- cpu_suspend_fn = QEMU_PSCI_0_2_FN64_CPU_SUSPEND;
- cpu_on_fn = QEMU_PSCI_0_2_FN64_CPU_ON;
- migrate_fn = QEMU_PSCI_0_2_FN64_MIGRATE;
- } else {
- cpu_suspend_fn = QEMU_PSCI_0_2_FN_CPU_SUSPEND;
- cpu_on_fn = QEMU_PSCI_0_2_FN_CPU_ON;
- migrate_fn = QEMU_PSCI_0_2_FN_MIGRATE;
- }
- } else {
- qemu_fdt_setprop_string(fdt, "/psci", "compatible", "arm,psci");
-
- cpu_suspend_fn = QEMU_PSCI_0_1_FN_CPU_SUSPEND;
- cpu_off_fn = QEMU_PSCI_0_1_FN_CPU_OFF;
- cpu_on_fn = QEMU_PSCI_0_1_FN_CPU_ON;
- migrate_fn = QEMU_PSCI_0_1_FN_MIGRATE;
- }
-
- /* We adopt the PSCI spec's nomenclature, and use 'conduit' to refer
- * to the instruction that should be used to invoke PSCI functions.
- * However, the device tree binding uses 'method' instead, so that is
- * what we should use here.
- */
- qemu_fdt_setprop_string(fdt, "/psci", "method", "hvc");
-
- qemu_fdt_setprop_cell(fdt, "/psci", "cpu_suspend", cpu_suspend_fn);
- qemu_fdt_setprop_cell(fdt, "/psci", "cpu_off", cpu_off_fn);
- qemu_fdt_setprop_cell(fdt, "/psci", "cpu_on", cpu_on_fn);
- qemu_fdt_setprop_cell(fdt, "/psci", "migrate", migrate_fn);
-}
-
-static void fdt_add_timer_nodes(const VirtBoardInfo *vbi, int gictype)
-{
- /* Note that on A15 h/w these interrupts are level-triggered,
- * but for the GIC implementation provided by both QEMU and KVM
- * they are edge-triggered.
- */
- ARMCPU *armcpu;
- uint32_t irqflags = GIC_FDT_IRQ_FLAGS_EDGE_LO_HI;
-
- if (gictype == 2) {
- irqflags = deposit32(irqflags, GIC_FDT_IRQ_PPI_CPU_START,
- GIC_FDT_IRQ_PPI_CPU_WIDTH,
- (1 << vbi->smp_cpus) - 1);
- }
-
- qemu_fdt_add_subnode(vbi->fdt, "/timer");
-
- armcpu = ARM_CPU(qemu_get_cpu(0));
- if (arm_feature(&armcpu->env, ARM_FEATURE_V8)) {
- const char compat[] = "arm,armv8-timer\0arm,armv7-timer";
- qemu_fdt_setprop(vbi->fdt, "/timer", "compatible",
- compat, sizeof(compat));
- } else {
- qemu_fdt_setprop_string(vbi->fdt, "/timer", "compatible",
- "arm,armv7-timer");
- }
- qemu_fdt_setprop(vbi->fdt, "/timer", "always-on", NULL, 0);
- qemu_fdt_setprop_cells(vbi->fdt, "/timer", "interrupts",
- GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_S_EL1_IRQ, irqflags,
- GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_NS_EL1_IRQ, irqflags,
- GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_VIRT_IRQ, irqflags,
- GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_NS_EL2_IRQ, irqflags);
-}
-
-static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi)
-{
- int cpu;
- int addr_cells = 1;
-
- /*
- * From Documentation/devicetree/bindings/arm/cpus.txt
- * On ARM v8 64-bit systems value should be set to 2,
- * that corresponds to the MPIDR_EL1 register size.
- * If MPIDR_EL1[63:32] value is equal to 0 on all CPUs
- * in the system, #address-cells can be set to 1, since
- * MPIDR_EL1[63:32] bits are not used for CPUs
- * identification.
- *
- * Here we actually don't know whether our system is 32- or 64-bit one.
- * The simplest way to go is to examine affinity IDs of all our CPUs. If
- * at least one of them has Aff3 populated, we set #address-cells to 2.
- */
- for (cpu = 0; cpu < vbi->smp_cpus; cpu++) {
- ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(cpu));
-
- if (armcpu->mp_affinity & ARM_AFF3_MASK) {
- addr_cells = 2;
- break;
- }
- }
-
- qemu_fdt_add_subnode(vbi->fdt, "/cpus");
- qemu_fdt_setprop_cell(vbi->fdt, "/cpus", "#address-cells", addr_cells);
- qemu_fdt_setprop_cell(vbi->fdt, "/cpus", "#size-cells", 0x0);
-
- for (cpu = vbi->smp_cpus - 1; cpu >= 0; cpu--) {
- char *nodename = g_strdup_printf("/cpus/cpu@%d", cpu);
- ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(cpu));
-
- qemu_fdt_add_subnode(vbi->fdt, nodename);
- qemu_fdt_setprop_string(vbi->fdt, nodename, "device_type", "cpu");
- qemu_fdt_setprop_string(vbi->fdt, nodename, "compatible",
- armcpu->dtb_compatible);
-
- if (vbi->using_psci && vbi->smp_cpus > 1) {
- qemu_fdt_setprop_string(vbi->fdt, nodename,
- "enable-method", "psci");
- }
-
- if (addr_cells == 2) {
- qemu_fdt_setprop_u64(vbi->fdt, nodename, "reg",
- armcpu->mp_affinity);
- } else {
- qemu_fdt_setprop_cell(vbi->fdt, nodename, "reg",
- armcpu->mp_affinity);
- }
-
- g_free(nodename);
- }
-}
-
-static void fdt_add_v2m_gic_node(VirtBoardInfo *vbi)
-{
- vbi->v2m_phandle = qemu_fdt_alloc_phandle(vbi->fdt);
- qemu_fdt_add_subnode(vbi->fdt, "/intc/v2m");
- qemu_fdt_setprop_string(vbi->fdt, "/intc/v2m", "compatible",
- "arm,gic-v2m-frame");
- qemu_fdt_setprop(vbi->fdt, "/intc/v2m", "msi-controller", NULL, 0);
- qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc/v2m", "reg",
- 2, vbi->memmap[VIRT_GIC_V2M].base,
- 2, vbi->memmap[VIRT_GIC_V2M].size);
- qemu_fdt_setprop_cell(vbi->fdt, "/intc/v2m", "phandle", vbi->v2m_phandle);
-}
-
-static void fdt_add_gic_node(VirtBoardInfo *vbi, int type)
-{
- vbi->gic_phandle = qemu_fdt_alloc_phandle(vbi->fdt);
- qemu_fdt_setprop_cell(vbi->fdt, "/", "interrupt-parent", vbi->gic_phandle);
-
- qemu_fdt_add_subnode(vbi->fdt, "/intc");
- qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#interrupt-cells", 3);
- qemu_fdt_setprop(vbi->fdt, "/intc", "interrupt-controller", NULL, 0);
- qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#address-cells", 0x2);
- qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#size-cells", 0x2);
- qemu_fdt_setprop(vbi->fdt, "/intc", "ranges", NULL, 0);
- if (type == 3) {
- qemu_fdt_setprop_string(vbi->fdt, "/intc", "compatible",
- "arm,gic-v3");
- qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc", "reg",
- 2, vbi->memmap[VIRT_GIC_DIST].base,
- 2, vbi->memmap[VIRT_GIC_DIST].size,
- 2, vbi->memmap[VIRT_GIC_REDIST].base,
- 2, vbi->memmap[VIRT_GIC_REDIST].size);
- } else {
- /* 'cortex-a15-gic' means 'GIC v2' */
- qemu_fdt_setprop_string(vbi->fdt, "/intc", "compatible",
- "arm,cortex-a15-gic");
- qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc", "reg",
- 2, vbi->memmap[VIRT_GIC_DIST].base,
- 2, vbi->memmap[VIRT_GIC_DIST].size,
- 2, vbi->memmap[VIRT_GIC_CPU].base,
- 2, vbi->memmap[VIRT_GIC_CPU].size);
- }
-
- qemu_fdt_setprop_cell(vbi->fdt, "/intc", "phandle", vbi->gic_phandle);
-}
-
-static void create_v2m(VirtBoardInfo *vbi, qemu_irq *pic)
-{
- int i;
- int irq = vbi->irqmap[VIRT_GIC_V2M];
- DeviceState *dev;
-
- dev = qdev_create(NULL, "arm-gicv2m");
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vbi->memmap[VIRT_GIC_V2M].base);
- qdev_prop_set_uint32(dev, "base-spi", irq);
- qdev_prop_set_uint32(dev, "num-spi", NUM_GICV2M_SPIS);
- qdev_init_nofail(dev);
-
- for (i = 0; i < NUM_GICV2M_SPIS; i++) {
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pic[irq + i]);
- }
-
- fdt_add_v2m_gic_node(vbi);
-}
-
-static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic, int type, bool secure)
-{
- /* We create a standalone GIC */
- DeviceState *gicdev;
- SysBusDevice *gicbusdev;
- const char *gictype;
- int i;
-
- gictype = (type == 3) ? gicv3_class_name() : gic_class_name();
-
- gicdev = qdev_create(NULL, gictype);
- qdev_prop_set_uint32(gicdev, "revision", type);
- qdev_prop_set_uint32(gicdev, "num-cpu", smp_cpus);
- /* Note that the num-irq property counts both internal and external
- * interrupts; there are always 32 of the former (mandated by GIC spec).
- */
- qdev_prop_set_uint32(gicdev, "num-irq", NUM_IRQS + 32);
- if (!kvm_irqchip_in_kernel()) {
- qdev_prop_set_bit(gicdev, "has-security-extensions", secure);
- }
- qdev_init_nofail(gicdev);
- gicbusdev = SYS_BUS_DEVICE(gicdev);
- sysbus_mmio_map(gicbusdev, 0, vbi->memmap[VIRT_GIC_DIST].base);
- if (type == 3) {
- sysbus_mmio_map(gicbusdev, 1, vbi->memmap[VIRT_GIC_REDIST].base);
- } else {
- sysbus_mmio_map(gicbusdev, 1, vbi->memmap[VIRT_GIC_CPU].base);
- }
-
- /* Wire the outputs from each CPU's generic timer to the
- * appropriate GIC PPI inputs, and the GIC's IRQ output to
- * the CPU's IRQ input.
- */
- for (i = 0; i < smp_cpus; i++) {
- DeviceState *cpudev = DEVICE(qemu_get_cpu(i));
- int ppibase = NUM_IRQS + i * GIC_INTERNAL + GIC_NR_SGIS;
- int irq;
- /* Mapping from the output timer irq lines from the CPU to the
- * GIC PPI inputs we use for the virt board.
- */
- const int timer_irq[] = {
- [GTIMER_PHYS] = ARCH_TIMER_NS_EL1_IRQ,
- [GTIMER_VIRT] = ARCH_TIMER_VIRT_IRQ,
- [GTIMER_HYP] = ARCH_TIMER_NS_EL2_IRQ,
- [GTIMER_SEC] = ARCH_TIMER_S_EL1_IRQ,
- };
-
- for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) {
- qdev_connect_gpio_out(cpudev, irq,
- qdev_get_gpio_in(gicdev,
- ppibase + timer_irq[irq]));
- }
-
- sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
- sysbus_connect_irq(gicbusdev, i + smp_cpus,
- qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
- }
-
- for (i = 0; i < NUM_IRQS; i++) {
- pic[i] = qdev_get_gpio_in(gicdev, i);
- }
-
- fdt_add_gic_node(vbi, type);
-
- if (type == 2) {
- create_v2m(vbi, pic);
- }
-}
-
-static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic, int uart,
- MemoryRegion *mem)
-{
- char *nodename;
- hwaddr base = vbi->memmap[uart].base;
- hwaddr size = vbi->memmap[uart].size;
- int irq = vbi->irqmap[uart];
- const char compat[] = "arm,pl011\0arm,primecell";
- const char clocknames[] = "uartclk\0apb_pclk";
- DeviceState *dev = qdev_create(NULL, "pl011");
- SysBusDevice *s = SYS_BUS_DEVICE(dev);
-
- qdev_init_nofail(dev);
- memory_region_add_subregion(mem, base,
- sysbus_mmio_get_region(s, 0));
- sysbus_connect_irq(s, 0, pic[irq]);
-
- nodename = g_strdup_printf("/pl011@%" PRIx64, base);
- qemu_fdt_add_subnode(vbi->fdt, nodename);
- /* Note that we can't use setprop_string because of the embedded NUL */
- qemu_fdt_setprop(vbi->fdt, nodename, "compatible",
- compat, sizeof(compat));
- qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg",
- 2, base, 2, size);
- qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupts",
- GIC_FDT_IRQ_TYPE_SPI, irq,
- GIC_FDT_IRQ_FLAGS_LEVEL_HI);
- qemu_fdt_setprop_cells(vbi->fdt, nodename, "clocks",
- vbi->clock_phandle, vbi->clock_phandle);
- qemu_fdt_setprop(vbi->fdt, nodename, "clock-names",
- clocknames, sizeof(clocknames));
-
- if (uart == VIRT_UART) {
- qemu_fdt_setprop_string(vbi->fdt, "/chosen", "stdout-path", nodename);
- } else {
- /* Mark as not usable by the normal world */
- qemu_fdt_setprop_string(vbi->fdt, nodename, "status", "disabled");
- qemu_fdt_setprop_string(vbi->fdt, nodename, "secure-status", "okay");
- }
-
- g_free(nodename);
-}
-
-static void create_rtc(const VirtBoardInfo *vbi, qemu_irq *pic)
-{
- char *nodename;
- hwaddr base = vbi->memmap[VIRT_RTC].base;
- hwaddr size = vbi->memmap[VIRT_RTC].size;
- int irq = vbi->irqmap[VIRT_RTC];
- const char compat[] = "arm,pl031\0arm,primecell";
-
- sysbus_create_simple("pl031", base, pic[irq]);
-
- nodename = g_strdup_printf("/pl031@%" PRIx64, base);
- qemu_fdt_add_subnode(vbi->fdt, nodename);
- qemu_fdt_setprop(vbi->fdt, nodename, "compatible", compat, sizeof(compat));
- qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg",
- 2, base, 2, size);
- qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupts",
- GIC_FDT_IRQ_TYPE_SPI, irq,
- GIC_FDT_IRQ_FLAGS_LEVEL_HI);
- qemu_fdt_setprop_cell(vbi->fdt, nodename, "clocks", vbi->clock_phandle);
- qemu_fdt_setprop_string(vbi->fdt, nodename, "clock-names", "apb_pclk");
- g_free(nodename);
-}
-
-static DeviceState *gpio_key_dev;
-static void virt_powerdown_req(Notifier *n, void *opaque)
-{
- /* use gpio Pin 3 for power button event */
- qemu_set_irq(qdev_get_gpio_in(gpio_key_dev, 0), 1);
-}
-
-static Notifier virt_system_powerdown_notifier = {
- .notify = virt_powerdown_req
-};
-
-static void create_gpio(const VirtBoardInfo *vbi, qemu_irq *pic)
-{
- char *nodename;
- DeviceState *pl061_dev;
- hwaddr base = vbi->memmap[VIRT_GPIO].base;
- hwaddr size = vbi->memmap[VIRT_GPIO].size;
- int irq = vbi->irqmap[VIRT_GPIO];
- const char compat[] = "arm,pl061\0arm,primecell";
-
- pl061_dev = sysbus_create_simple("pl061", base, pic[irq]);
-
- uint32_t phandle = qemu_fdt_alloc_phandle(vbi->fdt);
- nodename = g_strdup_printf("/pl061@%" PRIx64, base);
- qemu_fdt_add_subnode(vbi->fdt, nodename);
- qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg",
- 2, base, 2, size);
- qemu_fdt_setprop(vbi->fdt, nodename, "compatible", compat, sizeof(compat));
- qemu_fdt_setprop_cell(vbi->fdt, nodename, "#gpio-cells", 2);
- qemu_fdt_setprop(vbi->fdt, nodename, "gpio-controller", NULL, 0);
- qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupts",
- GIC_FDT_IRQ_TYPE_SPI, irq,
- GIC_FDT_IRQ_FLAGS_LEVEL_HI);
- qemu_fdt_setprop_cell(vbi->fdt, nodename, "clocks", vbi->clock_phandle);
- qemu_fdt_setprop_string(vbi->fdt, nodename, "clock-names", "apb_pclk");
- qemu_fdt_setprop_cell(vbi->fdt, nodename, "phandle", phandle);
-
- gpio_key_dev = sysbus_create_simple("gpio-key", -1,
- qdev_get_gpio_in(pl061_dev, 3));
- qemu_fdt_add_subnode(vbi->fdt, "/gpio-keys");
- qemu_fdt_setprop_string(vbi->fdt, "/gpio-keys", "compatible", "gpio-keys");
- qemu_fdt_setprop_cell(vbi->fdt, "/gpio-keys", "#size-cells", 0);
- qemu_fdt_setprop_cell(vbi->fdt, "/gpio-keys", "#address-cells", 1);
-
- qemu_fdt_add_subnode(vbi->fdt, "/gpio-keys/poweroff");
- qemu_fdt_setprop_string(vbi->fdt, "/gpio-keys/poweroff",
- "label", "GPIO Key Poweroff");
- qemu_fdt_setprop_cell(vbi->fdt, "/gpio-keys/poweroff", "linux,code",
- KEY_POWER);
- qemu_fdt_setprop_cells(vbi->fdt, "/gpio-keys/poweroff",
- "gpios", phandle, 3, 0);
-
- /* connect powerdown request */
- qemu_register_powerdown_notifier(&virt_system_powerdown_notifier);
-
- g_free(nodename);
-}
-
-static void create_virtio_devices(const VirtBoardInfo *vbi, qemu_irq *pic)
-{
- int i;
- hwaddr size = vbi->memmap[VIRT_MMIO].size;
-
- /* We create the transports in forwards order. Since qbus_realize()
- * prepends (not appends) new child buses, the incrementing loop below will
- * create a list of virtio-mmio buses with decreasing base addresses.
- *
- * When a -device option is processed from the command line,
- * qbus_find_recursive() picks the next free virtio-mmio bus in forwards
- * order. The upshot is that -device options in increasing command line
- * order are mapped to virtio-mmio buses with decreasing base addresses.
- *
- * When this code was originally written, that arrangement ensured that the
- * guest Linux kernel would give the lowest "name" (/dev/vda, eth0, etc) to
- * the first -device on the command line. (The end-to-end order is a
- * function of this loop, qbus_realize(), qbus_find_recursive(), and the
- * guest kernel's name-to-address assignment strategy.)
- *
- * Meanwhile, the kernel's traversal seems to have been reversed; see eg.
- * the message, if not necessarily the code, of commit 70161ff336.
- * Therefore the loop now establishes the inverse of the original intent.
- *
- * Unfortunately, we can't counteract the kernel change by reversing the
- * loop; it would break existing command lines.
- *
- * In any case, the kernel makes no guarantee about the stability of
- * enumeration order of virtio devices (as demonstrated by it changing
- * between kernel versions). For reliable and stable identification
- * of disks users must use UUIDs or similar mechanisms.
- */
- for (i = 0; i < NUM_VIRTIO_TRANSPORTS; i++) {
- int irq = vbi->irqmap[VIRT_MMIO] + i;
- hwaddr base = vbi->memmap[VIRT_MMIO].base + i * size;
-
- sysbus_create_simple("virtio-mmio", base, pic[irq]);
- }
-
- /* We add dtb nodes in reverse order so that they appear in the finished
- * device tree lowest address first.
- *
- * Note that this mapping is independent of the loop above. The previous
- * loop influences virtio device to virtio transport assignment, whereas
- * this loop controls how virtio transports are laid out in the dtb.
- */
- for (i = NUM_VIRTIO_TRANSPORTS - 1; i >= 0; i--) {
- char *nodename;
- int irq = vbi->irqmap[VIRT_MMIO] + i;
- hwaddr base = vbi->memmap[VIRT_MMIO].base + i * size;
-
- nodename = g_strdup_printf("/virtio_mmio@%" PRIx64, base);
- qemu_fdt_add_subnode(vbi->fdt, nodename);
- qemu_fdt_setprop_string(vbi->fdt, nodename,
- "compatible", "virtio,mmio");
- qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg",
- 2, base, 2, size);
- qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupts",
- GIC_FDT_IRQ_TYPE_SPI, irq,
- GIC_FDT_IRQ_FLAGS_EDGE_LO_HI);
- g_free(nodename);
- }
-}
-
-static void create_one_flash(const char *name, hwaddr flashbase,
- hwaddr flashsize, const char *file,
- MemoryRegion *sysmem)
-{
- /* Create and map a single flash device. We use the same
- * parameters as the flash devices on the Versatile Express board.
- */
- DriveInfo *dinfo = drive_get_next(IF_PFLASH);
- DeviceState *dev = qdev_create(NULL, "cfi.pflash01");
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- const uint64_t sectorlength = 256 * 1024;
-
- if (dinfo) {
- qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(dinfo),
- &error_abort);
- }
-
- qdev_prop_set_uint32(dev, "num-blocks", flashsize / sectorlength);
- qdev_prop_set_uint64(dev, "sector-length", sectorlength);
- qdev_prop_set_uint8(dev, "width", 4);
- qdev_prop_set_uint8(dev, "device-width", 2);
- qdev_prop_set_bit(dev, "big-endian", false);
- qdev_prop_set_uint16(dev, "id0", 0x89);
- qdev_prop_set_uint16(dev, "id1", 0x18);
- qdev_prop_set_uint16(dev, "id2", 0x00);
- qdev_prop_set_uint16(dev, "id3", 0x00);
- qdev_prop_set_string(dev, "name", name);
- qdev_init_nofail(dev);
-
- memory_region_add_subregion(sysmem, flashbase,
- sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0));
-
- if (file) {
- char *fn;
- int image_size;
-
- if (drive_get(IF_PFLASH, 0, 0)) {
- error_report("The contents of the first flash device may be "
- "specified with -bios or with -drive if=pflash... "
- "but you cannot use both options at once");
- exit(1);
- }
- fn = qemu_find_file(QEMU_FILE_TYPE_BIOS, file);
- if (!fn) {
- error_report("Could not find ROM image '%s'", file);
- exit(1);
- }
- image_size = load_image_mr(fn, sysbus_mmio_get_region(sbd, 0));
- g_free(fn);
- if (image_size < 0) {
- error_report("Could not load ROM image '%s'", file);
- exit(1);
- }
- }
-}
-
-static void create_flash(const VirtBoardInfo *vbi,
- MemoryRegion *sysmem,
- MemoryRegion *secure_sysmem)
-{
- /* Create two flash devices to fill the VIRT_FLASH space in the memmap.
- * Any file passed via -bios goes in the first of these.
- * sysmem is the system memory space. secure_sysmem is the secure view
- * of the system, and the first flash device should be made visible only
- * there. The second flash device is visible to both secure and nonsecure.
- * If sysmem == secure_sysmem this means there is no separate Secure
- * address space and both flash devices are generally visible.
- */
- hwaddr flashsize = vbi->memmap[VIRT_FLASH].size / 2;
- hwaddr flashbase = vbi->memmap[VIRT_FLASH].base;
- char *nodename;
-
- create_one_flash("virt.flash0", flashbase, flashsize,
- bios_name, secure_sysmem);
- create_one_flash("virt.flash1", flashbase + flashsize, flashsize,
- NULL, sysmem);
-
- if (sysmem == secure_sysmem) {
- /* Report both flash devices as a single node in the DT */
- nodename = g_strdup_printf("/flash@%" PRIx64, flashbase);
- qemu_fdt_add_subnode(vbi->fdt, nodename);
- qemu_fdt_setprop_string(vbi->fdt, nodename, "compatible", "cfi-flash");
- qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg",
- 2, flashbase, 2, flashsize,
- 2, flashbase + flashsize, 2, flashsize);
- qemu_fdt_setprop_cell(vbi->fdt, nodename, "bank-width", 4);
- g_free(nodename);
- } else {
- /* Report the devices as separate nodes so we can mark one as
- * only visible to the secure world.
- */
- nodename = g_strdup_printf("/secflash@%" PRIx64, flashbase);
- qemu_fdt_add_subnode(vbi->fdt, nodename);
- qemu_fdt_setprop_string(vbi->fdt, nodename, "compatible", "cfi-flash");
- qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg",
- 2, flashbase, 2, flashsize);
- qemu_fdt_setprop_cell(vbi->fdt, nodename, "bank-width", 4);
- qemu_fdt_setprop_string(vbi->fdt, nodename, "status", "disabled");
- qemu_fdt_setprop_string(vbi->fdt, nodename, "secure-status", "okay");
- g_free(nodename);
-
- nodename = g_strdup_printf("/flash@%" PRIx64, flashbase);
- qemu_fdt_add_subnode(vbi->fdt, nodename);
- qemu_fdt_setprop_string(vbi->fdt, nodename, "compatible", "cfi-flash");
- qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg",
- 2, flashbase + flashsize, 2, flashsize);
- qemu_fdt_setprop_cell(vbi->fdt, nodename, "bank-width", 4);
- g_free(nodename);
- }
-}
-
-static void create_fw_cfg(const VirtBoardInfo *vbi, AddressSpace *as)
-{
- hwaddr base = vbi->memmap[VIRT_FW_CFG].base;
- hwaddr size = vbi->memmap[VIRT_FW_CFG].size;
- char *nodename;
-
- fw_cfg_init_mem_wide(base + 8, base, 8, base + 16, as);
-
- nodename = g_strdup_printf("/fw-cfg@%" PRIx64, base);
- qemu_fdt_add_subnode(vbi->fdt, nodename);
- qemu_fdt_setprop_string(vbi->fdt, nodename,
- "compatible", "qemu,fw-cfg-mmio");
- qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg",
- 2, base, 2, size);
- g_free(nodename);
-}
-
-static void create_pcie_irq_map(const VirtBoardInfo *vbi, uint32_t gic_phandle,
- int first_irq, const char *nodename)
-{
- int devfn, pin;
- uint32_t full_irq_map[4 * 4 * 10] = { 0 };
- uint32_t *irq_map = full_irq_map;
-
- for (devfn = 0; devfn <= 0x18; devfn += 0x8) {
- for (pin = 0; pin < 4; pin++) {
- int irq_type = GIC_FDT_IRQ_TYPE_SPI;
- int irq_nr = first_irq + ((pin + PCI_SLOT(devfn)) % PCI_NUM_PINS);
- int irq_level = GIC_FDT_IRQ_FLAGS_LEVEL_HI;
- int i;
-
- uint32_t map[] = {
- devfn << 8, 0, 0, /* devfn */
- pin + 1, /* PCI pin */
- gic_phandle, 0, 0, irq_type, irq_nr, irq_level }; /* GIC irq */
-
- /* Convert map to big endian */
- for (i = 0; i < 10; i++) {
- irq_map[i] = cpu_to_be32(map[i]);
- }
- irq_map += 10;
- }
- }
-
- qemu_fdt_setprop(vbi->fdt, nodename, "interrupt-map",
- full_irq_map, sizeof(full_irq_map));
-
- qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupt-map-mask",
- 0x1800, 0, 0, /* devfn (PCI_SLOT(3)) */
- 0x7 /* PCI irq */);
-}
-
-static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic,
- bool use_highmem)
-{
- hwaddr base_mmio = vbi->memmap[VIRT_PCIE_MMIO].base;
- hwaddr size_mmio = vbi->memmap[VIRT_PCIE_MMIO].size;
- hwaddr base_mmio_high = vbi->memmap[VIRT_PCIE_MMIO_HIGH].base;
- hwaddr size_mmio_high = vbi->memmap[VIRT_PCIE_MMIO_HIGH].size;
- hwaddr base_pio = vbi->memmap[VIRT_PCIE_PIO].base;
- hwaddr size_pio = vbi->memmap[VIRT_PCIE_PIO].size;
- hwaddr base_ecam = vbi->memmap[VIRT_PCIE_ECAM].base;
- hwaddr size_ecam = vbi->memmap[VIRT_PCIE_ECAM].size;
- hwaddr base = base_mmio;
- int nr_pcie_buses = size_ecam / PCIE_MMCFG_SIZE_MIN;
- int irq = vbi->irqmap[VIRT_PCIE];
- MemoryRegion *mmio_alias;
- MemoryRegion *mmio_reg;
- MemoryRegion *ecam_alias;
- MemoryRegion *ecam_reg;
- DeviceState *dev;
- char *nodename;
- int i;
- PCIHostState *pci;
-
- dev = qdev_create(NULL, TYPE_GPEX_HOST);
- qdev_init_nofail(dev);
-
- /* Map only the first size_ecam bytes of ECAM space */
- ecam_alias = g_new0(MemoryRegion, 1);
- ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
- memory_region_init_alias(ecam_alias, OBJECT(dev), "pcie-ecam",
- ecam_reg, 0, size_ecam);
- memory_region_add_subregion(get_system_memory(), base_ecam, ecam_alias);
-
- /* Map the MMIO window into system address space so as to expose
- * the section of PCI MMIO space which starts at the same base address
- * (ie 1:1 mapping for that part of PCI MMIO space visible through
- * the window).
- */
- mmio_alias = g_new0(MemoryRegion, 1);
- mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
- memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio",
- mmio_reg, base_mmio, size_mmio);
- memory_region_add_subregion(get_system_memory(), base_mmio, mmio_alias);
-
- if (use_highmem) {
- /* Map high MMIO space */
- MemoryRegion *high_mmio_alias = g_new0(MemoryRegion, 1);
-
- memory_region_init_alias(high_mmio_alias, OBJECT(dev), "pcie-mmio-high",
- mmio_reg, base_mmio_high, size_mmio_high);
- memory_region_add_subregion(get_system_memory(), base_mmio_high,
- high_mmio_alias);
- }
-
- /* Map IO port space */
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, base_pio);
-
- for (i = 0; i < GPEX_NUM_IRQS; i++) {
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pic[irq + i]);
- }
-
- pci = PCI_HOST_BRIDGE(dev);
- if (pci->bus) {
- for (i = 0; i < nb_nics; i++) {
- NICInfo *nd = &nd_table[i];
-
- if (!nd->model) {
- nd->model = g_strdup("virtio");
- }
-
- pci_nic_init_nofail(nd, pci->bus, nd->model, NULL);
- }
- }
-
- nodename = g_strdup_printf("/pcie@%" PRIx64, base);
- qemu_fdt_add_subnode(vbi->fdt, nodename);
- qemu_fdt_setprop_string(vbi->fdt, nodename,
- "compatible", "pci-host-ecam-generic");
- qemu_fdt_setprop_string(vbi->fdt, nodename, "device_type", "pci");
- qemu_fdt_setprop_cell(vbi->fdt, nodename, "#address-cells", 3);
- qemu_fdt_setprop_cell(vbi->fdt, nodename, "#size-cells", 2);
- qemu_fdt_setprop_cells(vbi->fdt, nodename, "bus-range", 0,
- nr_pcie_buses - 1);
-
- if (vbi->v2m_phandle) {
- qemu_fdt_setprop_cells(vbi->fdt, nodename, "msi-parent",
- vbi->v2m_phandle);
- }
-
- qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg",
- 2, base_ecam, 2, size_ecam);
-
- if (use_highmem) {
- qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "ranges",
- 1, FDT_PCI_RANGE_IOPORT, 2, 0,
- 2, base_pio, 2, size_pio,
- 1, FDT_PCI_RANGE_MMIO, 2, base_mmio,
- 2, base_mmio, 2, size_mmio,
- 1, FDT_PCI_RANGE_MMIO_64BIT,
- 2, base_mmio_high,
- 2, base_mmio_high, 2, size_mmio_high);
- } else {
- qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "ranges",
- 1, FDT_PCI_RANGE_IOPORT, 2, 0,
- 2, base_pio, 2, size_pio,
- 1, FDT_PCI_RANGE_MMIO, 2, base_mmio,
- 2, base_mmio, 2, size_mmio);
- }
-
- qemu_fdt_setprop_cell(vbi->fdt, nodename, "#interrupt-cells", 1);
- create_pcie_irq_map(vbi, vbi->gic_phandle, irq, nodename);
-
- g_free(nodename);
-}
-
-static void create_platform_bus(VirtBoardInfo *vbi, qemu_irq *pic)
-{
- DeviceState *dev;
- SysBusDevice *s;
- int i;
- ARMPlatformBusFDTParams *fdt_params = g_new(ARMPlatformBusFDTParams, 1);
- MemoryRegion *sysmem = get_system_memory();
-
- platform_bus_params.platform_bus_base = vbi->memmap[VIRT_PLATFORM_BUS].base;
- platform_bus_params.platform_bus_size = vbi->memmap[VIRT_PLATFORM_BUS].size;
- platform_bus_params.platform_bus_first_irq = vbi->irqmap[VIRT_PLATFORM_BUS];
- platform_bus_params.platform_bus_num_irqs = PLATFORM_BUS_NUM_IRQS;
-
- fdt_params->system_params = &platform_bus_params;
- fdt_params->binfo = &vbi->bootinfo;
- fdt_params->intc = "/intc";
- /*
- * register a machine init done notifier that creates the device tree
- * nodes of the platform bus and its children dynamic sysbus devices
- */
- arm_register_platform_bus_fdt_creator(fdt_params);
-
- dev = qdev_create(NULL, TYPE_PLATFORM_BUS_DEVICE);
- dev->id = TYPE_PLATFORM_BUS_DEVICE;
- qdev_prop_set_uint32(dev, "num_irqs",
- platform_bus_params.platform_bus_num_irqs);
- qdev_prop_set_uint32(dev, "mmio_size",
- platform_bus_params.platform_bus_size);
- qdev_init_nofail(dev);
- s = SYS_BUS_DEVICE(dev);
-
- for (i = 0; i < platform_bus_params.platform_bus_num_irqs; i++) {
- int irqn = platform_bus_params.platform_bus_first_irq + i;
- sysbus_connect_irq(s, i, pic[irqn]);
- }
-
- memory_region_add_subregion(sysmem,
- platform_bus_params.platform_bus_base,
- sysbus_mmio_get_region(s, 0));
-}
-
-static void create_secure_ram(VirtBoardInfo *vbi, MemoryRegion *secure_sysmem)
-{
- MemoryRegion *secram = g_new(MemoryRegion, 1);
- char *nodename;
- hwaddr base = vbi->memmap[VIRT_SECURE_MEM].base;
- hwaddr size = vbi->memmap[VIRT_SECURE_MEM].size;
-
- memory_region_init_ram(secram, NULL, "virt.secure-ram", size, &error_fatal);
- vmstate_register_ram_global(secram);
- memory_region_add_subregion(secure_sysmem, base, secram);
-
- nodename = g_strdup_printf("/secram@%" PRIx64, base);
- qemu_fdt_add_subnode(vbi->fdt, nodename);
- qemu_fdt_setprop_string(vbi->fdt, nodename, "device_type", "memory");
- qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", 2, base, 2, size);
- qemu_fdt_setprop_string(vbi->fdt, nodename, "status", "disabled");
- qemu_fdt_setprop_string(vbi->fdt, nodename, "secure-status", "okay");
-
- g_free(nodename);
-}
-
-static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size)
-{
- const VirtBoardInfo *board = (const VirtBoardInfo *)binfo;
-
- *fdt_size = board->fdt_size;
- return board->fdt;
-}
-
-static void virt_build_smbios(VirtGuestInfo *guest_info)
-{
- FWCfgState *fw_cfg = guest_info->fw_cfg;
- uint8_t *smbios_tables, *smbios_anchor;
- size_t smbios_tables_len, smbios_anchor_len;
- const char *product = "QEMU Virtual Machine";
-
- if (!fw_cfg) {
- return;
- }
-
- if (kvm_enabled()) {
- product = "KVM Virtual Machine";
- }
-
- smbios_set_defaults("QEMU", product,
- "1.0", false, true, SMBIOS_ENTRY_POINT_30);
-
- smbios_get_tables(NULL, 0, &smbios_tables, &smbios_tables_len,
- &smbios_anchor, &smbios_anchor_len);
-
- if (smbios_anchor) {
- fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-tables",
- smbios_tables, smbios_tables_len);
- fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-anchor",
- smbios_anchor, smbios_anchor_len);
- }
-}
-
-static
-void virt_guest_info_machine_done(Notifier *notifier, void *data)
-{
- VirtGuestInfoState *guest_info_state = container_of(notifier,
- VirtGuestInfoState, machine_done);
- virt_acpi_setup(&guest_info_state->info);
- virt_build_smbios(&guest_info_state->info);
-}
-
-static void machvirt_init(MachineState *machine)
-{
- VirtMachineState *vms = VIRT_MACHINE(machine);
- qemu_irq pic[NUM_IRQS];
- MemoryRegion *sysmem = get_system_memory();
- MemoryRegion *secure_sysmem = NULL;
- int gic_version = vms->gic_version;
- int n, virt_max_cpus;
- MemoryRegion *ram = g_new(MemoryRegion, 1);
- const char *cpu_model = machine->cpu_model;
- VirtBoardInfo *vbi;
- VirtGuestInfoState *guest_info_state = g_malloc0(sizeof *guest_info_state);
- VirtGuestInfo *guest_info = &guest_info_state->info;
- char **cpustr;
- bool firmware_loaded = bios_name || drive_get(IF_PFLASH, 0, 0);
-
- if (!cpu_model) {
- cpu_model = "cortex-a15";
- }
-
- /* We can probe only here because during property set
- * KVM is not available yet
- */
- if (!gic_version) {
- gic_version = kvm_arm_vgic_probe();
- if (!gic_version) {
- error_report("Unable to determine GIC version supported by host");
- error_printf("KVM acceleration is probably not supported\n");
- exit(1);
- }
- }
-
- /* Separate the actual CPU model name from any appended features */
- cpustr = g_strsplit(cpu_model, ",", 2);
-
- vbi = find_machine_info(cpustr[0]);
-
- if (!vbi) {
- error_report("mach-virt: CPU %s not supported", cpustr[0]);
- exit(1);
- }
-
- /* If we have an EL3 boot ROM then the assumption is that it will
- * implement PSCI itself, so disable QEMU's internal implementation
- * so it doesn't get in the way. Instead of starting secondary
- * CPUs in PSCI powerdown state we will start them all running and
- * let the boot ROM sort them out.
- * The usual case is that we do use QEMU's PSCI implementation.
- */
- vbi->using_psci = !(vms->secure && firmware_loaded);
-
- /* The maximum number of CPUs depends on the GIC version, or on how
- * many redistributors we can fit into the memory map.
- */
- if (gic_version == 3) {
- virt_max_cpus = vbi->memmap[VIRT_GIC_REDIST].size / 0x20000;
- } else {
- virt_max_cpus = GIC_NCPU;
- }
-
- if (max_cpus > virt_max_cpus) {
- error_report("Number of SMP CPUs requested (%d) exceeds max CPUs "
- "supported by machine 'mach-virt' (%d)",
- max_cpus, virt_max_cpus);
- exit(1);
- }
-
- vbi->smp_cpus = smp_cpus;
-
- if (machine->ram_size > vbi->memmap[VIRT_MEM].size) {
- error_report("mach-virt: cannot model more than %dGB RAM", RAMLIMIT_GB);
- exit(1);
- }
-
- if (vms->secure) {
- if (kvm_enabled()) {
- error_report("mach-virt: KVM does not support Security extensions");
- exit(1);
- }
-
- /* The Secure view of the world is the same as the NonSecure,
- * but with a few extra devices. Create it as a container region
- * containing the system memory at low priority; any secure-only
- * devices go in at higher priority and take precedence.
- */
- secure_sysmem = g_new(MemoryRegion, 1);
- memory_region_init(secure_sysmem, OBJECT(machine), "secure-memory",
- UINT64_MAX);
- memory_region_add_subregion_overlap(secure_sysmem, 0, sysmem, -1);
- }
-
- create_fdt(vbi);
-
- for (n = 0; n < smp_cpus; n++) {
- ObjectClass *oc = cpu_class_by_name(TYPE_ARM_CPU, cpustr[0]);
- CPUClass *cc = CPU_CLASS(oc);
- Object *cpuobj;
- Error *err = NULL;
- char *cpuopts = g_strdup(cpustr[1]);
-
- if (!oc) {
- error_report("Unable to find CPU definition");
- exit(1);
- }
- cpuobj = object_new(object_class_get_name(oc));
-
- /* Handle any CPU options specified by the user */
- cc->parse_features(CPU(cpuobj), cpuopts, &err);
- g_free(cpuopts);
- if (err) {
- error_report_err(err);
- exit(1);
- }
-
- if (!vms->secure) {
- object_property_set_bool(cpuobj, false, "has_el3", NULL);
- }
-
- if (vbi->using_psci) {
- object_property_set_int(cpuobj, QEMU_PSCI_CONDUIT_HVC,
- "psci-conduit", NULL);
-
- /* Secondary CPUs start in PSCI powered-down state */
- if (n > 0) {
- object_property_set_bool(cpuobj, true,
- "start-powered-off", NULL);
- }
- }
-
- if (object_property_find(cpuobj, "reset-cbar", NULL)) {
- object_property_set_int(cpuobj, vbi->memmap[VIRT_CPUPERIPHS].base,
- "reset-cbar", &error_abort);
- }
-
- object_property_set_link(cpuobj, OBJECT(sysmem), "memory",
- &error_abort);
- if (vms->secure) {
- object_property_set_link(cpuobj, OBJECT(secure_sysmem),
- "secure-memory", &error_abort);
- }
-
- object_property_set_bool(cpuobj, true, "realized", NULL);
- }
- g_strfreev(cpustr);
- fdt_add_timer_nodes(vbi, gic_version);
- fdt_add_cpu_nodes(vbi);
- fdt_add_psci_node(vbi);
-
- memory_region_allocate_system_memory(ram, NULL, "mach-virt.ram",
- machine->ram_size);
- memory_region_add_subregion(sysmem, vbi->memmap[VIRT_MEM].base, ram);
-
- create_flash(vbi, sysmem, secure_sysmem ? secure_sysmem : sysmem);
-
- create_gic(vbi, pic, gic_version, vms->secure);
-
- create_uart(vbi, pic, VIRT_UART, sysmem);
-
- if (vms->secure) {
- create_secure_ram(vbi, secure_sysmem);
- create_uart(vbi, pic, VIRT_SECURE_UART, secure_sysmem);
- }
-
- create_rtc(vbi, pic);
-
- create_pcie(vbi, pic, vms->highmem);
-
- create_gpio(vbi, pic);
-
- /* Create mmio transports, so the user can create virtio backends
- * (which will be automatically plugged in to the transports). If
- * no backend is created the transport will just sit harmlessly idle.
- */
- create_virtio_devices(vbi, pic);
-
- create_fw_cfg(vbi, &address_space_memory);
- rom_set_fw(fw_cfg_find());
-
- guest_info->smp_cpus = smp_cpus;
- guest_info->fw_cfg = fw_cfg_find();
- guest_info->memmap = vbi->memmap;
- guest_info->irqmap = vbi->irqmap;
- guest_info->use_highmem = vms->highmem;
- guest_info->gic_version = gic_version;
- guest_info_state->machine_done.notify = virt_guest_info_machine_done;
- qemu_add_machine_init_done_notifier(&guest_info_state->machine_done);
-
- vbi->bootinfo.ram_size = machine->ram_size;
- vbi->bootinfo.kernel_filename = machine->kernel_filename;
- vbi->bootinfo.kernel_cmdline = machine->kernel_cmdline;
- vbi->bootinfo.initrd_filename = machine->initrd_filename;
- vbi->bootinfo.nb_cpus = smp_cpus;
- vbi->bootinfo.board_id = -1;
- vbi->bootinfo.loader_start = vbi->memmap[VIRT_MEM].base;
- vbi->bootinfo.get_dtb = machvirt_dtb;
- vbi->bootinfo.firmware_loaded = firmware_loaded;
- arm_load_kernel(ARM_CPU(first_cpu), &vbi->bootinfo);
-
- /*
- * arm_load_kernel machine init done notifier registration must
- * happen before the platform_bus_create call. In this latter,
- * another notifier is registered which adds platform bus nodes.
- * Notifiers are executed in registration reverse order.
- */
- create_platform_bus(vbi, pic);
-}
-
-static bool virt_get_secure(Object *obj, Error **errp)
-{
- VirtMachineState *vms = VIRT_MACHINE(obj);
-
- return vms->secure;
-}
-
-static void virt_set_secure(Object *obj, bool value, Error **errp)
-{
- VirtMachineState *vms = VIRT_MACHINE(obj);
-
- vms->secure = value;
-}
-
-static bool virt_get_highmem(Object *obj, Error **errp)
-{
- VirtMachineState *vms = VIRT_MACHINE(obj);
-
- return vms->highmem;
-}
-
-static void virt_set_highmem(Object *obj, bool value, Error **errp)
-{
- VirtMachineState *vms = VIRT_MACHINE(obj);
-
- vms->highmem = value;
-}
-
-static char *virt_get_gic_version(Object *obj, Error **errp)
-{
- VirtMachineState *vms = VIRT_MACHINE(obj);
- const char *val = vms->gic_version == 3 ? "3" : "2";
-
- return g_strdup(val);
-}
-
-static void virt_set_gic_version(Object *obj, const char *value, Error **errp)
-{
- VirtMachineState *vms = VIRT_MACHINE(obj);
-
- if (!strcmp(value, "3")) {
- vms->gic_version = 3;
- } else if (!strcmp(value, "2")) {
- vms->gic_version = 2;
- } else if (!strcmp(value, "host")) {
- vms->gic_version = 0; /* Will probe later */
- } else {
- error_setg(errp, "Invalid gic-version value");
- error_append_hint(errp, "Valid values are 3, 2, host.\n");
- }
-}
-
-static void virt_machine_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->init = machvirt_init;
- /* Start max_cpus at the maximum QEMU supports. We'll further restrict
- * it later in machvirt_init, where we have more information about the
- * configuration of the particular instance.
- */
- mc->max_cpus = MAX_CPUMASK_BITS;
- mc->has_dynamic_sysbus = true;
- mc->block_default_type = IF_VIRTIO;
- mc->no_cdrom = 1;
- mc->pci_allow_0_address = true;
-}
-
-static const TypeInfo virt_machine_info = {
- .name = TYPE_VIRT_MACHINE,
- .parent = TYPE_MACHINE,
- .abstract = true,
- .instance_size = sizeof(VirtMachineState),
- .class_size = sizeof(VirtMachineClass),
- .class_init = virt_machine_class_init,
-};
-
-static void virt_2_6_instance_init(Object *obj)
-{
- VirtMachineState *vms = VIRT_MACHINE(obj);
-
- /* EL3 is disabled by default on virt: this makes us consistent
- * between KVM and TCG for this board, and it also allows us to
- * boot UEFI blobs which assume no TrustZone support.
- */
- vms->secure = false;
- object_property_add_bool(obj, "secure", virt_get_secure,
- virt_set_secure, NULL);
- object_property_set_description(obj, "secure",
- "Set on/off to enable/disable the ARM "
- "Security Extensions (TrustZone)",
- NULL);
-
- /* High memory is enabled by default */
- vms->highmem = true;
- object_property_add_bool(obj, "highmem", virt_get_highmem,
- virt_set_highmem, NULL);
- object_property_set_description(obj, "highmem",
- "Set on/off to enable/disable using "
- "physical address space above 32 bits",
- NULL);
- /* Default GIC type is v2 */
- vms->gic_version = 2;
- object_property_add_str(obj, "gic-version", virt_get_gic_version,
- virt_set_gic_version, NULL);
- object_property_set_description(obj, "gic-version",
- "Set GIC version. "
- "Valid values are 2, 3 and host", NULL);
-}
-
-static void virt_2_6_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
- static GlobalProperty compat_props[] = {
- { /* end of list */ }
- };
-
- mc->desc = "QEMU 2.6 ARM Virtual Machine";
- mc->alias = "virt";
- mc->compat_props = compat_props;
-}
-
-static const TypeInfo machvirt_info = {
- .name = MACHINE_TYPE_NAME("virt-2.6"),
- .parent = TYPE_VIRT_MACHINE,
- .instance_init = virt_2_6_instance_init,
- .class_init = virt_2_6_class_init,
-};
-
-static void machvirt_machine_init(void)
-{
- type_register_static(&virt_machine_info);
- type_register_static(&machvirt_info);
-}
-
-type_init(machvirt_machine_init);
diff --git a/qemu/hw/arm/xilinx_zynq.c b/qemu/hw/arm/xilinx_zynq.c
deleted file mode 100644
index 98b17c9ae..000000000
--- a/qemu/hw/arm/xilinx_zynq.c
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * Xilinx Zynq Baseboard System emulation.
- *
- * Copyright (c) 2010 Xilinx.
- * Copyright (c) 2012 Peter A.G. Crosthwaite (peter.croshtwaite@petalogix.com)
- * Copyright (c) 2012 Petalogix Pty Ltd.
- * Written by Haibing Ma
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/sysbus.h"
-#include "hw/arm/arm.h"
-#include "net/net.h"
-#include "exec/address-spaces.h"
-#include "sysemu/sysemu.h"
-#include "hw/boards.h"
-#include "hw/block/flash.h"
-#include "sysemu/block-backend.h"
-#include "hw/loader.h"
-#include "hw/misc/zynq-xadc.h"
-#include "hw/ssi/ssi.h"
-#include "qemu/error-report.h"
-#include "hw/sd/sd.h"
-
-#define NUM_SPI_FLASHES 4
-#define NUM_QSPI_FLASHES 2
-#define NUM_QSPI_BUSSES 2
-
-#define FLASH_SIZE (64 * 1024 * 1024)
-#define FLASH_SECTOR_SIZE (128 * 1024)
-
-#define IRQ_OFFSET 32 /* pic interrupts start from index 32 */
-
-#define MPCORE_PERIPHBASE 0xF8F00000
-#define ZYNQ_BOARD_MIDR 0x413FC090
-
-static const int dma_irqs[8] = {
- 46, 47, 48, 49, 72, 73, 74, 75
-};
-
-#define BOARD_SETUP_ADDR 0x100
-
-#define SLCR_LOCK_OFFSET 0x004
-#define SLCR_UNLOCK_OFFSET 0x008
-#define SLCR_ARM_PLL_OFFSET 0x100
-
-#define SLCR_XILINX_UNLOCK_KEY 0xdf0d
-#define SLCR_XILINX_LOCK_KEY 0x767b
-
-#define ARMV7_IMM16(x) (extract32((x), 0, 12) | \
- extract32((x), 12, 4) << 16)
-
-/* Write immediate val to address r0 + addr. r0 should contain base offset
- * of the SLCR block. Clobbers r1.
- */
-
-#define SLCR_WRITE(addr, val) \
- 0xe3001000 + ARMV7_IMM16(extract32((val), 0, 16)), /* movw r1 ... */ \
- 0xe3401000 + ARMV7_IMM16(extract32((val), 16, 16)), /* movt r1 ... */ \
- 0xe5801000 + (addr)
-
-static void zynq_write_board_setup(ARMCPU *cpu,
- const struct arm_boot_info *info)
-{
- int n;
- uint32_t board_setup_blob[] = {
- 0xe3a004f8, /* mov r0, #0xf8000000 */
- SLCR_WRITE(SLCR_UNLOCK_OFFSET, SLCR_XILINX_UNLOCK_KEY),
- SLCR_WRITE(SLCR_ARM_PLL_OFFSET, 0x00014008),
- SLCR_WRITE(SLCR_LOCK_OFFSET, SLCR_XILINX_LOCK_KEY),
- 0xe12fff1e, /* bx lr */
- };
- for (n = 0; n < ARRAY_SIZE(board_setup_blob); n++) {
- board_setup_blob[n] = tswap32(board_setup_blob[n]);
- }
- rom_add_blob_fixed("board-setup", board_setup_blob,
- sizeof(board_setup_blob), BOARD_SETUP_ADDR);
-}
-
-static struct arm_boot_info zynq_binfo = {};
-
-static void gem_init(NICInfo *nd, uint32_t base, qemu_irq irq)
-{
- DeviceState *dev;
- SysBusDevice *s;
-
- dev = qdev_create(NULL, "cadence_gem");
- if (nd->used) {
- qemu_check_nic_model(nd, "cadence_gem");
- qdev_set_nic_properties(dev, nd);
- }
- qdev_init_nofail(dev);
- s = SYS_BUS_DEVICE(dev);
- sysbus_mmio_map(s, 0, base);
- sysbus_connect_irq(s, 0, irq);
-}
-
-static inline void zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq,
- bool is_qspi)
-{
- DeviceState *dev;
- SysBusDevice *busdev;
- SSIBus *spi;
- DeviceState *flash_dev;
- int i, j;
- int num_busses = is_qspi ? NUM_QSPI_BUSSES : 1;
- int num_ss = is_qspi ? NUM_QSPI_FLASHES : NUM_SPI_FLASHES;
-
- dev = qdev_create(NULL, is_qspi ? "xlnx.ps7-qspi" : "xlnx.ps7-spi");
- qdev_prop_set_uint8(dev, "num-txrx-bytes", is_qspi ? 4 : 1);
- qdev_prop_set_uint8(dev, "num-ss-bits", num_ss);
- qdev_prop_set_uint8(dev, "num-busses", num_busses);
- qdev_init_nofail(dev);
- busdev = SYS_BUS_DEVICE(dev);
- sysbus_mmio_map(busdev, 0, base_addr);
- if (is_qspi) {
- sysbus_mmio_map(busdev, 1, 0xFC000000);
- }
- sysbus_connect_irq(busdev, 0, irq);
-
- for (i = 0; i < num_busses; ++i) {
- char bus_name[16];
- qemu_irq cs_line;
-
- snprintf(bus_name, 16, "spi%d", i);
- spi = (SSIBus *)qdev_get_child_bus(dev, bus_name);
-
- for (j = 0; j < num_ss; ++j) {
- flash_dev = ssi_create_slave(spi, "n25q128");
-
- cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0);
- sysbus_connect_irq(busdev, i * num_ss + j + 1, cs_line);
- }
- }
-
-}
-
-static void zynq_init(MachineState *machine)
-{
- ram_addr_t ram_size = machine->ram_size;
- const char *cpu_model = machine->cpu_model;
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- const char *initrd_filename = machine->initrd_filename;
- ObjectClass *cpu_oc;
- ARMCPU *cpu;
- MemoryRegion *address_space_mem = get_system_memory();
- MemoryRegion *ext_ram = g_new(MemoryRegion, 1);
- MemoryRegion *ocm_ram = g_new(MemoryRegion, 1);
- DeviceState *dev, *carddev;
- SysBusDevice *busdev;
- DriveInfo *di;
- BlockBackend *blk;
- qemu_irq pic[64];
- int n;
-
- if (!cpu_model) {
- cpu_model = "cortex-a9";
- }
- cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
-
- cpu = ARM_CPU(object_new(object_class_get_name(cpu_oc)));
-
- /* By default A9 CPUs have EL3 enabled. This board does not
- * currently support EL3 so the CPU EL3 property is disabled before
- * realization.
- */
- if (object_property_find(OBJECT(cpu), "has_el3", NULL)) {
- object_property_set_bool(OBJECT(cpu), false, "has_el3", &error_fatal);
- }
-
- object_property_set_int(OBJECT(cpu), ZYNQ_BOARD_MIDR, "midr",
- &error_fatal);
- object_property_set_int(OBJECT(cpu), MPCORE_PERIPHBASE, "reset-cbar",
- &error_fatal);
- object_property_set_bool(OBJECT(cpu), true, "realized", &error_fatal);
-
- /* max 2GB ram */
- if (ram_size > 0x80000000) {
- ram_size = 0x80000000;
- }
-
- /* DDR remapped to address zero. */
- memory_region_allocate_system_memory(ext_ram, NULL, "zynq.ext_ram",
- ram_size);
- memory_region_add_subregion(address_space_mem, 0, ext_ram);
-
- /* 256K of on-chip memory */
- memory_region_init_ram(ocm_ram, NULL, "zynq.ocm_ram", 256 << 10,
- &error_fatal);
- vmstate_register_ram_global(ocm_ram);
- memory_region_add_subregion(address_space_mem, 0xFFFC0000, ocm_ram);
-
- DriveInfo *dinfo = drive_get(IF_PFLASH, 0, 0);
-
- /* AMD */
- pflash_cfi02_register(0xe2000000, NULL, "zynq.pflash", FLASH_SIZE,
- dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- FLASH_SECTOR_SIZE,
- FLASH_SIZE/FLASH_SECTOR_SIZE, 1,
- 1, 0x0066, 0x0022, 0x0000, 0x0000, 0x0555, 0x2aa,
- 0);
-
- dev = qdev_create(NULL, "xilinx,zynq_slcr");
- qdev_init_nofail(dev);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xF8000000);
-
- dev = qdev_create(NULL, "a9mpcore_priv");
- qdev_prop_set_uint32(dev, "num-cpu", 1);
- qdev_init_nofail(dev);
- busdev = SYS_BUS_DEVICE(dev);
- sysbus_mmio_map(busdev, 0, MPCORE_PERIPHBASE);
- sysbus_connect_irq(busdev, 0,
- qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ));
-
- for (n = 0; n < 64; n++) {
- pic[n] = qdev_get_gpio_in(dev, n);
- }
-
- zynq_init_spi_flashes(0xE0006000, pic[58-IRQ_OFFSET], false);
- zynq_init_spi_flashes(0xE0007000, pic[81-IRQ_OFFSET], false);
- zynq_init_spi_flashes(0xE000D000, pic[51-IRQ_OFFSET], true);
-
- sysbus_create_simple("xlnx,ps7-usb", 0xE0002000, pic[53-IRQ_OFFSET]);
- sysbus_create_simple("xlnx,ps7-usb", 0xE0003000, pic[76-IRQ_OFFSET]);
-
- sysbus_create_simple("cadence_uart", 0xE0000000, pic[59-IRQ_OFFSET]);
- sysbus_create_simple("cadence_uart", 0xE0001000, pic[82-IRQ_OFFSET]);
-
- sysbus_create_varargs("cadence_ttc", 0xF8001000,
- pic[42-IRQ_OFFSET], pic[43-IRQ_OFFSET], pic[44-IRQ_OFFSET], NULL);
- sysbus_create_varargs("cadence_ttc", 0xF8002000,
- pic[69-IRQ_OFFSET], pic[70-IRQ_OFFSET], pic[71-IRQ_OFFSET], NULL);
-
- gem_init(&nd_table[0], 0xE000B000, pic[54-IRQ_OFFSET]);
- gem_init(&nd_table[1], 0xE000C000, pic[77-IRQ_OFFSET]);
-
- dev = qdev_create(NULL, "generic-sdhci");
- qdev_init_nofail(dev);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xE0100000);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[56-IRQ_OFFSET]);
-
- di = drive_get_next(IF_SD);
- blk = di ? blk_by_legacy_dinfo(di) : NULL;
- carddev = qdev_create(qdev_get_child_bus(dev, "sd-bus"), TYPE_SD_CARD);
- qdev_prop_set_drive(carddev, "drive", blk, &error_fatal);
- object_property_set_bool(OBJECT(carddev), true, "realized", &error_fatal);
-
- dev = qdev_create(NULL, "generic-sdhci");
- qdev_init_nofail(dev);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xE0101000);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[79-IRQ_OFFSET]);
-
- di = drive_get_next(IF_SD);
- blk = di ? blk_by_legacy_dinfo(di) : NULL;
- carddev = qdev_create(qdev_get_child_bus(dev, "sd-bus"), TYPE_SD_CARD);
- qdev_prop_set_drive(carddev, "drive", blk, &error_fatal);
- object_property_set_bool(OBJECT(carddev), true, "realized", &error_fatal);
-
- dev = qdev_create(NULL, TYPE_ZYNQ_XADC);
- qdev_init_nofail(dev);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xF8007100);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[39-IRQ_OFFSET]);
-
- dev = qdev_create(NULL, "pl330");
- qdev_prop_set_uint8(dev, "num_chnls", 8);
- qdev_prop_set_uint8(dev, "num_periph_req", 4);
- qdev_prop_set_uint8(dev, "num_events", 16);
-
- qdev_prop_set_uint8(dev, "data_width", 64);
- qdev_prop_set_uint8(dev, "wr_cap", 8);
- qdev_prop_set_uint8(dev, "wr_q_dep", 16);
- qdev_prop_set_uint8(dev, "rd_cap", 8);
- qdev_prop_set_uint8(dev, "rd_q_dep", 16);
- qdev_prop_set_uint16(dev, "data_buffer_dep", 256);
-
- qdev_init_nofail(dev);
- busdev = SYS_BUS_DEVICE(dev);
- sysbus_mmio_map(busdev, 0, 0xF8003000);
- sysbus_connect_irq(busdev, 0, pic[45-IRQ_OFFSET]); /* abort irq line */
- for (n = 0; n < 8; ++n) { /* event irqs */
- sysbus_connect_irq(busdev, n + 1, pic[dma_irqs[n] - IRQ_OFFSET]);
- }
-
- zynq_binfo.ram_size = ram_size;
- zynq_binfo.kernel_filename = kernel_filename;
- zynq_binfo.kernel_cmdline = kernel_cmdline;
- zynq_binfo.initrd_filename = initrd_filename;
- zynq_binfo.nb_cpus = 1;
- zynq_binfo.board_id = 0xd32;
- zynq_binfo.loader_start = 0;
- zynq_binfo.board_setup_addr = BOARD_SETUP_ADDR;
- zynq_binfo.write_board_setup = zynq_write_board_setup;
-
- arm_load_kernel(ARM_CPU(first_cpu), &zynq_binfo);
-}
-
-static void zynq_machine_init(MachineClass *mc)
-{
- mc->desc = "Xilinx Zynq Platform Baseboard for Cortex-A9";
- mc->init = zynq_init;
- mc->block_default_type = IF_SCSI;
- mc->max_cpus = 1;
- mc->no_sdcard = 1;
-}
-
-DEFINE_MACHINE("xilinx-zynq-a9", zynq_machine_init)
diff --git a/qemu/hw/arm/xlnx-ep108.c b/qemu/hw/arm/xlnx-ep108.c
deleted file mode 100644
index 5f480182b..000000000
--- a/qemu/hw/arm/xlnx-ep108.c
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Xilinx ZynqMP EP108 board
- *
- * Copyright (C) 2015 Xilinx Inc
- * Written by Peter Crosthwaite <peter.crosthwaite@xilinx.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/arm/xlnx-zynqmp.h"
-#include "hw/boards.h"
-#include "qemu/error-report.h"
-#include "exec/address-spaces.h"
-
-typedef struct XlnxEP108 {
- XlnxZynqMPState soc;
- MemoryRegion ddr_ram;
-} XlnxEP108;
-
-static struct arm_boot_info xlnx_ep108_binfo;
-
-static void xlnx_ep108_init(MachineState *machine)
-{
- XlnxEP108 *s = g_new0(XlnxEP108, 1);
- int i;
- uint64_t ram_size = machine->ram_size;
-
- /* Create the memory region to pass to the SoC */
- if (ram_size > XLNX_ZYNQMP_MAX_RAM_SIZE) {
- error_report("ERROR: RAM size 0x%" PRIx64 " above max supported of "
- "0x%llx", ram_size,
- XLNX_ZYNQMP_MAX_RAM_SIZE);
- exit(1);
- }
-
- if (ram_size < 0x08000000) {
- qemu_log("WARNING: RAM size 0x%" PRIx64 " is small for EP108",
- ram_size);
- }
-
- memory_region_allocate_system_memory(&s->ddr_ram, NULL, "ddr-ram",
- ram_size);
-
- object_initialize(&s->soc, sizeof(s->soc), TYPE_XLNX_ZYNQMP);
- object_property_add_child(OBJECT(machine), "soc", OBJECT(&s->soc),
- &error_abort);
-
- object_property_set_link(OBJECT(&s->soc), OBJECT(&s->ddr_ram),
- "ddr-ram", &error_abort);
-
- object_property_set_bool(OBJECT(&s->soc), true, "realized", &error_fatal);
-
- /* Create and plug in the SD cards */
- for (i = 0; i < XLNX_ZYNQMP_NUM_SDHCI; i++) {
- BusState *bus;
- DriveInfo *di = drive_get_next(IF_SD);
- BlockBackend *blk = di ? blk_by_legacy_dinfo(di) : NULL;
- DeviceState *carddev;
- char *bus_name;
-
- bus_name = g_strdup_printf("sd-bus%d", i);
- bus = qdev_get_child_bus(DEVICE(&s->soc), bus_name);
- g_free(bus_name);
- if (!bus) {
- error_report("No SD bus found for SD card %d", i);
- exit(1);
- }
- carddev = qdev_create(bus, TYPE_SD_CARD);
- qdev_prop_set_drive(carddev, "drive", blk, &error_fatal);
- object_property_set_bool(OBJECT(carddev), true, "realized",
- &error_fatal);
- }
-
- for (i = 0; i < XLNX_ZYNQMP_NUM_SPIS; i++) {
- SSIBus *spi_bus;
- DeviceState *flash_dev;
- qemu_irq cs_line;
- gchar *bus_name = g_strdup_printf("spi%d", i);
-
- spi_bus = (SSIBus *)qdev_get_child_bus(DEVICE(&s->soc), bus_name);
- g_free(bus_name);
-
- flash_dev = ssi_create_slave(spi_bus, "sst25wf080");
- cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0);
-
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->soc.spi[i]), 1, cs_line);
- }
-
- xlnx_ep108_binfo.ram_size = ram_size;
- xlnx_ep108_binfo.kernel_filename = machine->kernel_filename;
- xlnx_ep108_binfo.kernel_cmdline = machine->kernel_cmdline;
- xlnx_ep108_binfo.initrd_filename = machine->initrd_filename;
- xlnx_ep108_binfo.loader_start = 0;
- arm_load_kernel(s->soc.boot_cpu_ptr, &xlnx_ep108_binfo);
-}
-
-static void xlnx_ep108_machine_init(MachineClass *mc)
-{
- mc->desc = "Xilinx ZynqMP EP108 board";
- mc->init = xlnx_ep108_init;
-}
-
-DEFINE_MACHINE("xlnx-ep108", xlnx_ep108_machine_init)
diff --git a/qemu/hw/arm/xlnx-zynqmp.c b/qemu/hw/arm/xlnx-zynqmp.c
deleted file mode 100644
index 4d504da64..000000000
--- a/qemu/hw/arm/xlnx-zynqmp.c
+++ /dev/null
@@ -1,403 +0,0 @@
-/*
- * Xilinx Zynq MPSoC emulation
- *
- * Copyright (C) 2015 Xilinx Inc
- * Written by Peter Crosthwaite <peter.crosthwaite@xilinx.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/arm/xlnx-zynqmp.h"
-#include "hw/intc/arm_gic_common.h"
-#include "exec/address-spaces.h"
-
-#define GIC_NUM_SPI_INTR 160
-
-#define ARM_PHYS_TIMER_PPI 30
-#define ARM_VIRT_TIMER_PPI 27
-
-#define GIC_BASE_ADDR 0xf9000000
-#define GIC_DIST_ADDR 0xf9010000
-#define GIC_CPU_ADDR 0xf9020000
-
-#define SATA_INTR 133
-#define SATA_ADDR 0xFD0C0000
-#define SATA_NUM_PORTS 2
-
-static const uint64_t gem_addr[XLNX_ZYNQMP_NUM_GEMS] = {
- 0xFF0B0000, 0xFF0C0000, 0xFF0D0000, 0xFF0E0000,
-};
-
-static const int gem_intr[XLNX_ZYNQMP_NUM_GEMS] = {
- 57, 59, 61, 63,
-};
-
-static const uint64_t uart_addr[XLNX_ZYNQMP_NUM_UARTS] = {
- 0xFF000000, 0xFF010000,
-};
-
-static const int uart_intr[XLNX_ZYNQMP_NUM_UARTS] = {
- 21, 22,
-};
-
-static const uint64_t sdhci_addr[XLNX_ZYNQMP_NUM_SDHCI] = {
- 0xFF160000, 0xFF170000,
-};
-
-static const int sdhci_intr[XLNX_ZYNQMP_NUM_SDHCI] = {
- 48, 49,
-};
-
-static const uint64_t spi_addr[XLNX_ZYNQMP_NUM_SPIS] = {
- 0xFF040000, 0xFF050000,
-};
-
-static const int spi_intr[XLNX_ZYNQMP_NUM_SPIS] = {
- 19, 20,
-};
-
-typedef struct XlnxZynqMPGICRegion {
- int region_index;
- uint32_t address;
-} XlnxZynqMPGICRegion;
-
-static const XlnxZynqMPGICRegion xlnx_zynqmp_gic_regions[] = {
- { .region_index = 0, .address = GIC_DIST_ADDR, },
- { .region_index = 1, .address = GIC_CPU_ADDR, },
-};
-
-static inline int arm_gic_ppi_index(int cpu_nr, int ppi_index)
-{
- return GIC_NUM_SPI_INTR + cpu_nr * GIC_INTERNAL + ppi_index;
-}
-
-static void xlnx_zynqmp_init(Object *obj)
-{
- XlnxZynqMPState *s = XLNX_ZYNQMP(obj);
- int i;
-
- for (i = 0; i < XLNX_ZYNQMP_NUM_APU_CPUS; i++) {
- object_initialize(&s->apu_cpu[i], sizeof(s->apu_cpu[i]),
- "cortex-a53-" TYPE_ARM_CPU);
- object_property_add_child(obj, "apu-cpu[*]", OBJECT(&s->apu_cpu[i]),
- &error_abort);
- }
-
- for (i = 0; i < XLNX_ZYNQMP_NUM_RPU_CPUS; i++) {
- object_initialize(&s->rpu_cpu[i], sizeof(s->rpu_cpu[i]),
- "cortex-r5-" TYPE_ARM_CPU);
- object_property_add_child(obj, "rpu-cpu[*]", OBJECT(&s->rpu_cpu[i]),
- &error_abort);
- }
-
- object_property_add_link(obj, "ddr-ram", TYPE_MEMORY_REGION,
- (Object **)&s->ddr_ram,
- qdev_prop_allow_set_link_before_realize,
- OBJ_PROP_LINK_UNREF_ON_RELEASE, &error_abort);
-
- object_initialize(&s->gic, sizeof(s->gic), TYPE_ARM_GIC);
- qdev_set_parent_bus(DEVICE(&s->gic), sysbus_get_default());
-
- for (i = 0; i < XLNX_ZYNQMP_NUM_GEMS; i++) {
- object_initialize(&s->gem[i], sizeof(s->gem[i]), TYPE_CADENCE_GEM);
- qdev_set_parent_bus(DEVICE(&s->gem[i]), sysbus_get_default());
- }
-
- for (i = 0; i < XLNX_ZYNQMP_NUM_UARTS; i++) {
- object_initialize(&s->uart[i], sizeof(s->uart[i]), TYPE_CADENCE_UART);
- qdev_set_parent_bus(DEVICE(&s->uart[i]), sysbus_get_default());
- }
-
- object_initialize(&s->sata, sizeof(s->sata), TYPE_SYSBUS_AHCI);
- qdev_set_parent_bus(DEVICE(&s->sata), sysbus_get_default());
-
- for (i = 0; i < XLNX_ZYNQMP_NUM_SDHCI; i++) {
- object_initialize(&s->sdhci[i], sizeof(s->sdhci[i]),
- TYPE_SYSBUS_SDHCI);
- qdev_set_parent_bus(DEVICE(&s->sdhci[i]),
- sysbus_get_default());
- }
-
- for (i = 0; i < XLNX_ZYNQMP_NUM_SPIS; i++) {
- object_initialize(&s->spi[i], sizeof(s->spi[i]),
- TYPE_XILINX_SPIPS);
- qdev_set_parent_bus(DEVICE(&s->spi[i]), sysbus_get_default());
- }
-}
-
-static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
-{
- XlnxZynqMPState *s = XLNX_ZYNQMP(dev);
- MemoryRegion *system_memory = get_system_memory();
- uint8_t i;
- uint64_t ram_size;
- const char *boot_cpu = s->boot_cpu ? s->boot_cpu : "apu-cpu[0]";
- ram_addr_t ddr_low_size, ddr_high_size;
- qemu_irq gic_spi[GIC_NUM_SPI_INTR];
- Error *err = NULL;
-
- ram_size = memory_region_size(s->ddr_ram);
-
- /* Create the DDR Memory Regions. User friendly checks should happen at
- * the board level
- */
- if (ram_size > XLNX_ZYNQMP_MAX_LOW_RAM_SIZE) {
- /* The RAM size is above the maximum available for the low DDR.
- * Create the high DDR memory region as well.
- */
- assert(ram_size <= XLNX_ZYNQMP_MAX_RAM_SIZE);
- ddr_low_size = XLNX_ZYNQMP_MAX_LOW_RAM_SIZE;
- ddr_high_size = ram_size - XLNX_ZYNQMP_MAX_LOW_RAM_SIZE;
-
- memory_region_init_alias(&s->ddr_ram_high, NULL,
- "ddr-ram-high", s->ddr_ram,
- ddr_low_size, ddr_high_size);
- memory_region_add_subregion(get_system_memory(),
- XLNX_ZYNQMP_HIGH_RAM_START,
- &s->ddr_ram_high);
- } else {
- /* RAM must be non-zero */
- assert(ram_size);
- ddr_low_size = ram_size;
- }
-
- memory_region_init_alias(&s->ddr_ram_low, NULL,
- "ddr-ram-low", s->ddr_ram,
- 0, ddr_low_size);
- memory_region_add_subregion(get_system_memory(), 0, &s->ddr_ram_low);
-
- /* Create the four OCM banks */
- for (i = 0; i < XLNX_ZYNQMP_NUM_OCM_BANKS; i++) {
- char *ocm_name = g_strdup_printf("zynqmp.ocm_ram_bank_%d", i);
-
- memory_region_init_ram(&s->ocm_ram[i], NULL, ocm_name,
- XLNX_ZYNQMP_OCM_RAM_SIZE, &error_fatal);
- vmstate_register_ram_global(&s->ocm_ram[i]);
- memory_region_add_subregion(get_system_memory(),
- XLNX_ZYNQMP_OCM_RAM_0_ADDRESS +
- i * XLNX_ZYNQMP_OCM_RAM_SIZE,
- &s->ocm_ram[i]);
-
- g_free(ocm_name);
- }
-
- qdev_prop_set_uint32(DEVICE(&s->gic), "num-irq", GIC_NUM_SPI_INTR + 32);
- qdev_prop_set_uint32(DEVICE(&s->gic), "revision", 2);
- qdev_prop_set_uint32(DEVICE(&s->gic), "num-cpu", XLNX_ZYNQMP_NUM_APU_CPUS);
- object_property_set_bool(OBJECT(&s->gic), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- assert(ARRAY_SIZE(xlnx_zynqmp_gic_regions) == XLNX_ZYNQMP_GIC_REGIONS);
- for (i = 0; i < XLNX_ZYNQMP_GIC_REGIONS; i++) {
- SysBusDevice *gic = SYS_BUS_DEVICE(&s->gic);
- const XlnxZynqMPGICRegion *r = &xlnx_zynqmp_gic_regions[i];
- MemoryRegion *mr = sysbus_mmio_get_region(gic, r->region_index);
- uint32_t addr = r->address;
- int j;
-
- sysbus_mmio_map(gic, r->region_index, addr);
-
- for (j = 0; j < XLNX_ZYNQMP_GIC_ALIASES; j++) {
- MemoryRegion *alias = &s->gic_mr[i][j];
-
- addr += XLNX_ZYNQMP_GIC_REGION_SIZE;
- memory_region_init_alias(alias, OBJECT(s), "zynqmp-gic-alias", mr,
- 0, XLNX_ZYNQMP_GIC_REGION_SIZE);
- memory_region_add_subregion(system_memory, addr, alias);
- }
- }
-
- for (i = 0; i < XLNX_ZYNQMP_NUM_APU_CPUS; i++) {
- qemu_irq irq;
- char *name;
-
- object_property_set_int(OBJECT(&s->apu_cpu[i]), QEMU_PSCI_CONDUIT_SMC,
- "psci-conduit", &error_abort);
-
- name = object_get_canonical_path_component(OBJECT(&s->apu_cpu[i]));
- if (strcmp(name, boot_cpu)) {
- /* Secondary CPUs start in PSCI powered-down state */
- object_property_set_bool(OBJECT(&s->apu_cpu[i]), true,
- "start-powered-off", &error_abort);
- } else {
- s->boot_cpu_ptr = &s->apu_cpu[i];
- }
- g_free(name);
-
- object_property_set_int(OBJECT(&s->apu_cpu[i]), GIC_BASE_ADDR,
- "reset-cbar", &error_abort);
- object_property_set_bool(OBJECT(&s->apu_cpu[i]), true, "realized",
- &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), i,
- qdev_get_gpio_in(DEVICE(&s->apu_cpu[i]),
- ARM_CPU_IRQ));
- irq = qdev_get_gpio_in(DEVICE(&s->gic),
- arm_gic_ppi_index(i, ARM_PHYS_TIMER_PPI));
- qdev_connect_gpio_out(DEVICE(&s->apu_cpu[i]), 0, irq);
- irq = qdev_get_gpio_in(DEVICE(&s->gic),
- arm_gic_ppi_index(i, ARM_VIRT_TIMER_PPI));
- qdev_connect_gpio_out(DEVICE(&s->apu_cpu[i]), 1, irq);
- }
-
- for (i = 0; i < XLNX_ZYNQMP_NUM_RPU_CPUS; i++) {
- char *name;
-
- name = object_get_canonical_path_component(OBJECT(&s->rpu_cpu[i]));
- if (strcmp(name, boot_cpu)) {
- /* Secondary CPUs start in PSCI powered-down state */
- object_property_set_bool(OBJECT(&s->rpu_cpu[i]), true,
- "start-powered-off", &error_abort);
- } else {
- s->boot_cpu_ptr = &s->rpu_cpu[i];
- }
- g_free(name);
-
- object_property_set_bool(OBJECT(&s->rpu_cpu[i]), true, "reset-hivecs",
- &error_abort);
- object_property_set_bool(OBJECT(&s->rpu_cpu[i]), true, "realized",
- &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- }
-
- if (!s->boot_cpu_ptr) {
- error_setg(errp, "ZynqMP Boot cpu %s not found", boot_cpu);
- return;
- }
-
- for (i = 0; i < GIC_NUM_SPI_INTR; i++) {
- gic_spi[i] = qdev_get_gpio_in(DEVICE(&s->gic), i);
- }
-
- for (i = 0; i < XLNX_ZYNQMP_NUM_GEMS; i++) {
- NICInfo *nd = &nd_table[i];
-
- if (nd->used) {
- qemu_check_nic_model(nd, TYPE_CADENCE_GEM);
- qdev_set_nic_properties(DEVICE(&s->gem[i]), nd);
- }
- object_property_set_bool(OBJECT(&s->gem[i]), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->gem[i]), 0, gem_addr[i]);
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->gem[i]), 0,
- gic_spi[gem_intr[i]]);
- }
-
- for (i = 0; i < XLNX_ZYNQMP_NUM_UARTS; i++) {
- object_property_set_bool(OBJECT(&s->uart[i]), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart[i]), 0, uart_addr[i]);
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0,
- gic_spi[uart_intr[i]]);
- }
-
- object_property_set_int(OBJECT(&s->sata), SATA_NUM_PORTS, "num-ports",
- &error_abort);
- object_property_set_bool(OBJECT(&s->sata), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->sata), 0, SATA_ADDR);
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->sata), 0, gic_spi[SATA_INTR]);
-
- for (i = 0; i < XLNX_ZYNQMP_NUM_SDHCI; i++) {
- char *bus_name;
-
- object_property_set_bool(OBJECT(&s->sdhci[i]), true,
- "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdhci[i]), 0,
- sdhci_addr[i]);
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci[i]), 0,
- gic_spi[sdhci_intr[i]]);
- /* Alias controller SD bus to the SoC itself */
- bus_name = g_strdup_printf("sd-bus%d", i);
- object_property_add_alias(OBJECT(s), bus_name,
- OBJECT(&s->sdhci[i]), "sd-bus",
- &error_abort);
- g_free(bus_name);
- }
-
- for (i = 0; i < XLNX_ZYNQMP_NUM_SPIS; i++) {
- gchar *bus_name;
-
- object_property_set_bool(OBJECT(&s->spi[i]), true, "realized", &err);
-
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0, spi_addr[i]);
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi[i]), 0,
- gic_spi[spi_intr[i]]);
-
- /* Alias controller SPI bus to the SoC itself */
- bus_name = g_strdup_printf("spi%d", i);
- object_property_add_alias(OBJECT(s), bus_name,
- OBJECT(&s->spi[i]), "spi0",
- &error_abort);
- g_free(bus_name);
- }
-}
-
-static Property xlnx_zynqmp_props[] = {
- DEFINE_PROP_STRING("boot-cpu", XlnxZynqMPState, boot_cpu),
- DEFINE_PROP_END_OF_LIST()
-};
-
-static void xlnx_zynqmp_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- dc->props = xlnx_zynqmp_props;
- dc->realize = xlnx_zynqmp_realize;
-
- /*
- * Reason: creates an ARM CPU, thus use after free(), see
- * arm_cpu_class_init()
- */
- dc->cannot_destroy_with_object_finalize_yet = true;
-}
-
-static const TypeInfo xlnx_zynqmp_type_info = {
- .name = TYPE_XLNX_ZYNQMP,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(XlnxZynqMPState),
- .instance_init = xlnx_zynqmp_init,
- .class_init = xlnx_zynqmp_class_init,
-};
-
-static void xlnx_zynqmp_register_types(void)
-{
- type_register_static(&xlnx_zynqmp_type_info);
-}
-
-type_init(xlnx_zynqmp_register_types)
diff --git a/qemu/hw/arm/z2.c b/qemu/hw/arm/z2.c
deleted file mode 100644
index aea895a50..000000000
--- a/qemu/hw/arm/z2.c
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- * PXA270-based Zipit Z2 device
- *
- * Copyright (c) 2011 by Vasily Khoruzhick <anarsoul@gmail.com>
- *
- * Code is based on mainstone platform.
- *
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/arm/pxa.h"
-#include "hw/arm/arm.h"
-#include "hw/devices.h"
-#include "hw/i2c/i2c.h"
-#include "hw/ssi/ssi.h"
-#include "hw/boards.h"
-#include "sysemu/sysemu.h"
-#include "hw/block/flash.h"
-#include "sysemu/block-backend.h"
-#include "ui/console.h"
-#include "audio/audio.h"
-#include "exec/address-spaces.h"
-#include "sysemu/qtest.h"
-
-#ifdef DEBUG_Z2
-#define DPRINTF(fmt, ...) \
- printf(fmt, ## __VA_ARGS__)
-#else
-#define DPRINTF(fmt, ...)
-#endif
-
-static const struct keymap map[0x100] = {
- [0 ... 0xff] = { -1, -1 },
- [0x3b] = {0, 0}, /* Option = F1 */
- [0xc8] = {0, 1}, /* Up */
- [0xd0] = {0, 2}, /* Down */
- [0xcb] = {0, 3}, /* Left */
- [0xcd] = {0, 4}, /* Right */
- [0xcf] = {0, 5}, /* End */
- [0x0d] = {0, 6}, /* KPPLUS */
- [0xc7] = {1, 0}, /* Home */
- [0x10] = {1, 1}, /* Q */
- [0x17] = {1, 2}, /* I */
- [0x22] = {1, 3}, /* G */
- [0x2d] = {1, 4}, /* X */
- [0x1c] = {1, 5}, /* Enter */
- [0x0c] = {1, 6}, /* KPMINUS */
- [0xc9] = {2, 0}, /* PageUp */
- [0x11] = {2, 1}, /* W */
- [0x18] = {2, 2}, /* O */
- [0x23] = {2, 3}, /* H */
- [0x2e] = {2, 4}, /* C */
- [0x38] = {2, 5}, /* LeftAlt */
- [0xd1] = {3, 0}, /* PageDown */
- [0x12] = {3, 1}, /* E */
- [0x19] = {3, 2}, /* P */
- [0x24] = {3, 3}, /* J */
- [0x2f] = {3, 4}, /* V */
- [0x2a] = {3, 5}, /* LeftShift */
- [0x01] = {4, 0}, /* Esc */
- [0x13] = {4, 1}, /* R */
- [0x1e] = {4, 2}, /* A */
- [0x25] = {4, 3}, /* K */
- [0x30] = {4, 4}, /* B */
- [0x1d] = {4, 5}, /* LeftCtrl */
- [0x0f] = {5, 0}, /* Tab */
- [0x14] = {5, 1}, /* T */
- [0x1f] = {5, 2}, /* S */
- [0x26] = {5, 3}, /* L */
- [0x31] = {5, 4}, /* N */
- [0x39] = {5, 5}, /* Space */
- [0x3c] = {6, 0}, /* Stop = F2 */
- [0x15] = {6, 1}, /* Y */
- [0x20] = {6, 2}, /* D */
- [0x0e] = {6, 3}, /* Backspace */
- [0x32] = {6, 4}, /* M */
- [0x33] = {6, 5}, /* Comma */
- [0x3d] = {7, 0}, /* Play = F3 */
- [0x16] = {7, 1}, /* U */
- [0x21] = {7, 2}, /* F */
- [0x2c] = {7, 3}, /* Z */
- [0x27] = {7, 4}, /* Semicolon */
- [0x34] = {7, 5}, /* Dot */
-};
-
-#define Z2_RAM_SIZE 0x02000000
-#define Z2_FLASH_BASE 0x00000000
-#define Z2_FLASH_SIZE 0x00800000
-
-static struct arm_boot_info z2_binfo = {
- .loader_start = PXA2XX_SDRAM_BASE,
- .ram_size = Z2_RAM_SIZE,
-};
-
-#define Z2_GPIO_SD_DETECT 96
-#define Z2_GPIO_AC_IN 0
-#define Z2_GPIO_KEY_ON 1
-#define Z2_GPIO_LCD_CS 88
-
-typedef struct {
- SSISlave ssidev;
- int32_t selected;
- int32_t enabled;
- uint8_t buf[3];
- uint32_t cur_reg;
- int pos;
-} ZipitLCD;
-
-static uint32_t zipit_lcd_transfer(SSISlave *dev, uint32_t value)
-{
- ZipitLCD *z = FROM_SSI_SLAVE(ZipitLCD, dev);
- uint16_t val;
- if (z->selected) {
- z->buf[z->pos] = value & 0xff;
- z->pos++;
- }
- if (z->pos == 3) {
- switch (z->buf[0]) {
- case 0x74:
- DPRINTF("%s: reg: 0x%.2x\n", __func__, z->buf[2]);
- z->cur_reg = z->buf[2];
- break;
- case 0x76:
- val = z->buf[1] << 8 | z->buf[2];
- DPRINTF("%s: value: 0x%.4x\n", __func__, val);
- if (z->cur_reg == 0x22 && val == 0x0000) {
- z->enabled = 1;
- printf("%s: LCD enabled\n", __func__);
- } else if (z->cur_reg == 0x10 && val == 0x0000) {
- z->enabled = 0;
- printf("%s: LCD disabled\n", __func__);
- }
- break;
- default:
- DPRINTF("%s: unknown command!\n", __func__);
- break;
- }
- z->pos = 0;
- }
- return 0;
-}
-
-static void z2_lcd_cs(void *opaque, int line, int level)
-{
- ZipitLCD *z2_lcd = opaque;
- z2_lcd->selected = !level;
-}
-
-static int zipit_lcd_init(SSISlave *dev)
-{
- ZipitLCD *z = FROM_SSI_SLAVE(ZipitLCD, dev);
- z->selected = 0;
- z->enabled = 0;
- z->pos = 0;
-
- return 0;
-}
-
-static VMStateDescription vmstate_zipit_lcd_state = {
- .name = "zipit-lcd",
- .version_id = 2,
- .minimum_version_id = 2,
- .fields = (VMStateField[]) {
- VMSTATE_SSI_SLAVE(ssidev, ZipitLCD),
- VMSTATE_INT32(selected, ZipitLCD),
- VMSTATE_INT32(enabled, ZipitLCD),
- VMSTATE_BUFFER(buf, ZipitLCD),
- VMSTATE_UINT32(cur_reg, ZipitLCD),
- VMSTATE_INT32(pos, ZipitLCD),
- VMSTATE_END_OF_LIST(),
- }
-};
-
-static void zipit_lcd_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
-
- k->init = zipit_lcd_init;
- k->transfer = zipit_lcd_transfer;
- dc->vmsd = &vmstate_zipit_lcd_state;
-}
-
-static const TypeInfo zipit_lcd_info = {
- .name = "zipit-lcd",
- .parent = TYPE_SSI_SLAVE,
- .instance_size = sizeof(ZipitLCD),
- .class_init = zipit_lcd_class_init,
-};
-
-#define TYPE_AER915 "aer915"
-#define AER915(obj) OBJECT_CHECK(AER915State, (obj), TYPE_AER915)
-
-typedef struct AER915State {
- I2CSlave parent_obj;
-
- int len;
- uint8_t buf[3];
-} AER915State;
-
-static int aer915_send(I2CSlave *i2c, uint8_t data)
-{
- AER915State *s = AER915(i2c);
-
- s->buf[s->len] = data;
- if (s->len++ > 2) {
- DPRINTF("%s: message too long (%i bytes)\n",
- __func__, s->len);
- return 1;
- }
-
- if (s->len == 2) {
- DPRINTF("%s: reg %d value 0x%02x\n", __func__,
- s->buf[0], s->buf[1]);
- }
-
- return 0;
-}
-
-static void aer915_event(I2CSlave *i2c, enum i2c_event event)
-{
- AER915State *s = AER915(i2c);
-
- switch (event) {
- case I2C_START_SEND:
- s->len = 0;
- break;
- case I2C_START_RECV:
- if (s->len != 1) {
- DPRINTF("%s: short message!?\n", __func__);
- }
- break;
- case I2C_FINISH:
- break;
- default:
- break;
- }
-}
-
-static int aer915_recv(I2CSlave *slave)
-{
- AER915State *s = AER915(slave);
- int retval = 0x00;
-
- switch (s->buf[0]) {
- /* Return hardcoded battery voltage,
- * 0xf0 means ~4.1V
- */
- case 0x02:
- retval = 0xf0;
- break;
- /* Return 0x00 for other regs,
- * we don't know what they are for,
- * anyway they return 0x00 on real hardware.
- */
- default:
- break;
- }
-
- return retval;
-}
-
-static int aer915_init(I2CSlave *i2c)
-{
- /* Nothing to do. */
- return 0;
-}
-
-static VMStateDescription vmstate_aer915_state = {
- .name = "aer915",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_INT32(len, AER915State),
- VMSTATE_BUFFER(buf, AER915State),
- VMSTATE_END_OF_LIST(),
- }
-};
-
-static void aer915_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
-
- k->init = aer915_init;
- k->event = aer915_event;
- k->recv = aer915_recv;
- k->send = aer915_send;
- dc->vmsd = &vmstate_aer915_state;
-}
-
-static const TypeInfo aer915_info = {
- .name = TYPE_AER915,
- .parent = TYPE_I2C_SLAVE,
- .instance_size = sizeof(AER915State),
- .class_init = aer915_class_init,
-};
-
-static void z2_init(MachineState *machine)
-{
- const char *cpu_model = machine->cpu_model;
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- const char *initrd_filename = machine->initrd_filename;
- MemoryRegion *address_space_mem = get_system_memory();
- uint32_t sector_len = 0x10000;
- PXA2xxState *mpu;
- DriveInfo *dinfo;
- int be;
- void *z2_lcd;
- I2CBus *bus;
- DeviceState *wm;
-
- if (!cpu_model) {
- cpu_model = "pxa270-c5";
- }
-
- /* Setup CPU & memory */
- mpu = pxa270_init(address_space_mem, z2_binfo.ram_size, cpu_model);
-
-#ifdef TARGET_WORDS_BIGENDIAN
- be = 1;
-#else
- be = 0;
-#endif
- dinfo = drive_get(IF_PFLASH, 0, 0);
- if (!dinfo && !qtest_enabled()) {
- fprintf(stderr, "Flash image must be given with the "
- "'pflash' parameter\n");
- exit(1);
- }
-
- if (!pflash_cfi01_register(Z2_FLASH_BASE,
- NULL, "z2.flash0", Z2_FLASH_SIZE,
- dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- sector_len, Z2_FLASH_SIZE / sector_len,
- 4, 0, 0, 0, 0, be)) {
- fprintf(stderr, "qemu: Error registering flash memory.\n");
- exit(1);
- }
-
- /* setup keypad */
- pxa27x_register_keypad(mpu->kp, map, 0x100);
-
- /* MMC/SD host */
- pxa2xx_mmci_handlers(mpu->mmc,
- NULL,
- qdev_get_gpio_in(mpu->gpio, Z2_GPIO_SD_DETECT));
-
- type_register_static(&zipit_lcd_info);
- type_register_static(&aer915_info);
- z2_lcd = ssi_create_slave(mpu->ssp[1], "zipit-lcd");
- bus = pxa2xx_i2c_bus(mpu->i2c[0]);
- i2c_create_slave(bus, TYPE_AER915, 0x55);
- wm = i2c_create_slave(bus, "wm8750", 0x1b);
- mpu->i2s->opaque = wm;
- mpu->i2s->codec_out = wm8750_dac_dat;
- mpu->i2s->codec_in = wm8750_adc_dat;
- wm8750_data_req_set(wm, mpu->i2s->data_req, mpu->i2s);
-
- qdev_connect_gpio_out(mpu->gpio, Z2_GPIO_LCD_CS,
- qemu_allocate_irq(z2_lcd_cs, z2_lcd, 0));
-
- z2_binfo.kernel_filename = kernel_filename;
- z2_binfo.kernel_cmdline = kernel_cmdline;
- z2_binfo.initrd_filename = initrd_filename;
- z2_binfo.board_id = 0x6dd;
- arm_load_kernel(mpu->cpu, &z2_binfo);
-}
-
-static void z2_machine_init(MachineClass *mc)
-{
- mc->desc = "Zipit Z2 (PXA27x)";
- mc->init = z2_init;
-}
-
-DEFINE_MACHINE("z2", z2_machine_init)
diff --git a/qemu/hw/audio/Makefile.objs b/qemu/hw/audio/Makefile.objs
deleted file mode 100644
index 7ce85a2e8..000000000
--- a/qemu/hw/audio/Makefile.objs
+++ /dev/null
@@ -1,18 +0,0 @@
-# Sound
-common-obj-$(CONFIG_SB16) += sb16.o
-common-obj-$(CONFIG_ES1370) += es1370.o
-common-obj-$(CONFIG_AC97) += ac97.o
-common-obj-$(CONFIG_ADLIB) += fmopl.o adlib.o
-common-obj-$(CONFIG_GUS) += gus.o gusemu_hal.o gusemu_mixer.o
-common-obj-$(CONFIG_CS4231A) += cs4231a.o
-common-obj-$(CONFIG_HDA) += intel-hda.o hda-codec.o
-
-common-obj-$(CONFIG_PCSPK) += pcspk.o
-common-obj-$(CONFIG_WM8750) += wm8750.o
-common-obj-$(CONFIG_PL041) += pl041.o lm4549.o
-
-common-obj-$(CONFIG_CS4231) += cs4231.o
-common-obj-$(CONFIG_MARVELL_88W8618) += marvell_88w8618.o
-common-obj-$(CONFIG_MILKYMIST) += milkymist-ac97.o
-
-$(obj)/adlib.o $(obj)/fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0
diff --git a/qemu/hw/audio/ac97.c b/qemu/hw/audio/ac97.c
deleted file mode 100644
index cbd959e0b..000000000
--- a/qemu/hw/audio/ac97.c
+++ /dev/null
@@ -1,1431 +0,0 @@
-/*
- * Copyright (C) 2006 InnoTek Systemberatung GmbH
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License as published by the Free Software Foundation,
- * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
- * distribution. VirtualBox OSE is distributed in the hope that it will
- * be useful, but WITHOUT ANY WARRANTY of any kind.
- *
- * If you received this file as part of a commercial VirtualBox
- * distribution, then only the terms of your commercial VirtualBox
- * license agreement apply instead of the previous paragraph.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/audio/audio.h"
-#include "audio/audio.h"
-#include "hw/pci/pci.h"
-#include "sysemu/dma.h"
-
-enum {
- AC97_Reset = 0x00,
- AC97_Master_Volume_Mute = 0x02,
- AC97_Headphone_Volume_Mute = 0x04,
- AC97_Master_Volume_Mono_Mute = 0x06,
- AC97_Master_Tone_RL = 0x08,
- AC97_PC_BEEP_Volume_Mute = 0x0A,
- AC97_Phone_Volume_Mute = 0x0C,
- AC97_Mic_Volume_Mute = 0x0E,
- AC97_Line_In_Volume_Mute = 0x10,
- AC97_CD_Volume_Mute = 0x12,
- AC97_Video_Volume_Mute = 0x14,
- AC97_Aux_Volume_Mute = 0x16,
- AC97_PCM_Out_Volume_Mute = 0x18,
- AC97_Record_Select = 0x1A,
- AC97_Record_Gain_Mute = 0x1C,
- AC97_Record_Gain_Mic_Mute = 0x1E,
- AC97_General_Purpose = 0x20,
- AC97_3D_Control = 0x22,
- AC97_AC_97_RESERVED = 0x24,
- AC97_Powerdown_Ctrl_Stat = 0x26,
- AC97_Extended_Audio_ID = 0x28,
- AC97_Extended_Audio_Ctrl_Stat = 0x2A,
- AC97_PCM_Front_DAC_Rate = 0x2C,
- AC97_PCM_Surround_DAC_Rate = 0x2E,
- AC97_PCM_LFE_DAC_Rate = 0x30,
- AC97_PCM_LR_ADC_Rate = 0x32,
- AC97_MIC_ADC_Rate = 0x34,
- AC97_6Ch_Vol_C_LFE_Mute = 0x36,
- AC97_6Ch_Vol_L_R_Surround_Mute = 0x38,
- AC97_Vendor_Reserved = 0x58,
- AC97_Sigmatel_Analog = 0x6c, /* We emulate a Sigmatel codec */
- AC97_Sigmatel_Dac2Invert = 0x6e, /* We emulate a Sigmatel codec */
- AC97_Vendor_ID1 = 0x7c,
- AC97_Vendor_ID2 = 0x7e
-};
-
-#define SOFT_VOLUME
-#define SR_FIFOE 16 /* rwc */
-#define SR_BCIS 8 /* rwc */
-#define SR_LVBCI 4 /* rwc */
-#define SR_CELV 2 /* ro */
-#define SR_DCH 1 /* ro */
-#define SR_VALID_MASK ((1 << 5) - 1)
-#define SR_WCLEAR_MASK (SR_FIFOE | SR_BCIS | SR_LVBCI)
-#define SR_RO_MASK (SR_DCH | SR_CELV)
-#define SR_INT_MASK (SR_FIFOE | SR_BCIS | SR_LVBCI)
-
-#define CR_IOCE 16 /* rw */
-#define CR_FEIE 8 /* rw */
-#define CR_LVBIE 4 /* rw */
-#define CR_RR 2 /* rw */
-#define CR_RPBM 1 /* rw */
-#define CR_VALID_MASK ((1 << 5) - 1)
-#define CR_DONT_CLEAR_MASK (CR_IOCE | CR_FEIE | CR_LVBIE)
-
-#define GC_WR 4 /* rw */
-#define GC_CR 2 /* rw */
-#define GC_VALID_MASK ((1 << 6) - 1)
-
-#define GS_MD3 (1<<17) /* rw */
-#define GS_AD3 (1<<16) /* rw */
-#define GS_RCS (1<<15) /* rwc */
-#define GS_B3S12 (1<<14) /* ro */
-#define GS_B2S12 (1<<13) /* ro */
-#define GS_B1S12 (1<<12) /* ro */
-#define GS_S1R1 (1<<11) /* rwc */
-#define GS_S0R1 (1<<10) /* rwc */
-#define GS_S1CR (1<<9) /* ro */
-#define GS_S0CR (1<<8) /* ro */
-#define GS_MINT (1<<7) /* ro */
-#define GS_POINT (1<<6) /* ro */
-#define GS_PIINT (1<<5) /* ro */
-#define GS_RSRVD ((1<<4)|(1<<3))
-#define GS_MOINT (1<<2) /* ro */
-#define GS_MIINT (1<<1) /* ro */
-#define GS_GSCI 1 /* rwc */
-#define GS_RO_MASK (GS_B3S12| \
- GS_B2S12| \
- GS_B1S12| \
- GS_S1CR| \
- GS_S0CR| \
- GS_MINT| \
- GS_POINT| \
- GS_PIINT| \
- GS_RSRVD| \
- GS_MOINT| \
- GS_MIINT)
-#define GS_VALID_MASK ((1 << 18) - 1)
-#define GS_WCLEAR_MASK (GS_RCS|GS_S1R1|GS_S0R1|GS_GSCI)
-
-#define BD_IOC (1<<31)
-#define BD_BUP (1<<30)
-
-#define EACS_VRA 1
-#define EACS_VRM 8
-
-#define MUTE_SHIFT 15
-
-#define REC_MASK 7
-enum {
- REC_MIC = 0,
- REC_CD,
- REC_VIDEO,
- REC_AUX,
- REC_LINE_IN,
- REC_STEREO_MIX,
- REC_MONO_MIX,
- REC_PHONE
-};
-
-typedef struct BD {
- uint32_t addr;
- uint32_t ctl_len;
-} BD;
-
-typedef struct AC97BusMasterRegs {
- uint32_t bdbar; /* rw 0 */
- uint8_t civ; /* ro 0 */
- uint8_t lvi; /* rw 0 */
- uint16_t sr; /* rw 1 */
- uint16_t picb; /* ro 0 */
- uint8_t piv; /* ro 0 */
- uint8_t cr; /* rw 0 */
- unsigned int bd_valid;
- BD bd;
-} AC97BusMasterRegs;
-
-typedef struct AC97LinkState {
- PCIDevice dev;
- QEMUSoundCard card;
- uint32_t use_broken_id;
- uint32_t glob_cnt;
- uint32_t glob_sta;
- uint32_t cas;
- uint32_t last_samp;
- AC97BusMasterRegs bm_regs[3];
- uint8_t mixer_data[256];
- SWVoiceIn *voice_pi;
- SWVoiceOut *voice_po;
- SWVoiceIn *voice_mc;
- int invalid_freq[3];
- uint8_t silence[128];
- int bup_flag;
- MemoryRegion io_nam;
- MemoryRegion io_nabm;
-} AC97LinkState;
-
-enum {
- BUP_SET = 1,
- BUP_LAST = 2
-};
-
-#ifdef DEBUG_AC97
-#define dolog(...) AUD_log ("ac97", __VA_ARGS__)
-#else
-#define dolog(...)
-#endif
-
-#define MKREGS(prefix, start) \
-enum { \
- prefix ## _BDBAR = start, \
- prefix ## _CIV = start + 4, \
- prefix ## _LVI = start + 5, \
- prefix ## _SR = start + 6, \
- prefix ## _PICB = start + 8, \
- prefix ## _PIV = start + 10, \
- prefix ## _CR = start + 11 \
-}
-
-enum {
- PI_INDEX = 0,
- PO_INDEX,
- MC_INDEX,
- LAST_INDEX
-};
-
-MKREGS (PI, PI_INDEX * 16);
-MKREGS (PO, PO_INDEX * 16);
-MKREGS (MC, MC_INDEX * 16);
-
-enum {
- GLOB_CNT = 0x2c,
- GLOB_STA = 0x30,
- CAS = 0x34
-};
-
-#define GET_BM(index) (((index) >> 4) & 3)
-
-static void po_callback (void *opaque, int free);
-static void pi_callback (void *opaque, int avail);
-static void mc_callback (void *opaque, int avail);
-
-static void warm_reset (AC97LinkState *s)
-{
- (void) s;
-}
-
-static void cold_reset (AC97LinkState * s)
-{
- (void) s;
-}
-
-static void fetch_bd (AC97LinkState *s, AC97BusMasterRegs *r)
-{
- uint8_t b[8];
-
- pci_dma_read (&s->dev, r->bdbar + r->civ * 8, b, 8);
- r->bd_valid = 1;
- r->bd.addr = le32_to_cpu (*(uint32_t *) &b[0]) & ~3;
- r->bd.ctl_len = le32_to_cpu (*(uint32_t *) &b[4]);
- r->picb = r->bd.ctl_len & 0xffff;
- dolog ("bd %2d addr=%#x ctl=%#06x len=%#x(%d bytes)\n",
- r->civ, r->bd.addr, r->bd.ctl_len >> 16,
- r->bd.ctl_len & 0xffff,
- (r->bd.ctl_len & 0xffff) << 1);
-}
-
-static void update_sr (AC97LinkState *s, AC97BusMasterRegs *r, uint32_t new_sr)
-{
- int event = 0;
- int level = 0;
- uint32_t new_mask = new_sr & SR_INT_MASK;
- uint32_t old_mask = r->sr & SR_INT_MASK;
- uint32_t masks[] = {GS_PIINT, GS_POINT, GS_MINT};
-
- if (new_mask ^ old_mask) {
- /** @todo is IRQ deasserted when only one of status bits is cleared? */
- if (!new_mask) {
- event = 1;
- level = 0;
- }
- else {
- if ((new_mask & SR_LVBCI) && (r->cr & CR_LVBIE)) {
- event = 1;
- level = 1;
- }
- if ((new_mask & SR_BCIS) && (r->cr & CR_IOCE)) {
- event = 1;
- level = 1;
- }
- }
- }
-
- r->sr = new_sr;
-
- dolog ("IOC%d LVB%d sr=%#x event=%d level=%d\n",
- r->sr & SR_BCIS, r->sr & SR_LVBCI,
- r->sr,
- event, level);
-
- if (!event)
- return;
-
- if (level) {
- s->glob_sta |= masks[r - s->bm_regs];
- dolog ("set irq level=1\n");
- pci_irq_assert(&s->dev);
- }
- else {
- s->glob_sta &= ~masks[r - s->bm_regs];
- dolog ("set irq level=0\n");
- pci_irq_deassert(&s->dev);
- }
-}
-
-static void voice_set_active (AC97LinkState *s, int bm_index, int on)
-{
- switch (bm_index) {
- case PI_INDEX:
- AUD_set_active_in (s->voice_pi, on);
- break;
-
- case PO_INDEX:
- AUD_set_active_out (s->voice_po, on);
- break;
-
- case MC_INDEX:
- AUD_set_active_in (s->voice_mc, on);
- break;
-
- default:
- AUD_log ("ac97", "invalid bm_index(%d) in voice_set_active", bm_index);
- break;
- }
-}
-
-static void reset_bm_regs (AC97LinkState *s, AC97BusMasterRegs *r)
-{
- dolog ("reset_bm_regs\n");
- r->bdbar = 0;
- r->civ = 0;
- r->lvi = 0;
- /** todo do we need to do that? */
- update_sr (s, r, SR_DCH);
- r->picb = 0;
- r->piv = 0;
- r->cr = r->cr & CR_DONT_CLEAR_MASK;
- r->bd_valid = 0;
-
- voice_set_active (s, r - s->bm_regs, 0);
- memset (s->silence, 0, sizeof (s->silence));
-}
-
-static void mixer_store (AC97LinkState *s, uint32_t i, uint16_t v)
-{
- if (i + 2 > sizeof (s->mixer_data)) {
- dolog ("mixer_store: index %d out of bounds %zd\n",
- i, sizeof (s->mixer_data));
- return;
- }
-
- s->mixer_data[i + 0] = v & 0xff;
- s->mixer_data[i + 1] = v >> 8;
-}
-
-static uint16_t mixer_load (AC97LinkState *s, uint32_t i)
-{
- uint16_t val = 0xffff;
-
- if (i + 2 > sizeof (s->mixer_data)) {
- dolog ("mixer_load: index %d out of bounds %zd\n",
- i, sizeof (s->mixer_data));
- }
- else {
- val = s->mixer_data[i + 0] | (s->mixer_data[i + 1] << 8);
- }
-
- return val;
-}
-
-static void open_voice (AC97LinkState *s, int index, int freq)
-{
- struct audsettings as;
-
- as.freq = freq;
- as.nchannels = 2;
- as.fmt = AUD_FMT_S16;
- as.endianness = 0;
-
- if (freq > 0) {
- s->invalid_freq[index] = 0;
- switch (index) {
- case PI_INDEX:
- s->voice_pi = AUD_open_in (
- &s->card,
- s->voice_pi,
- "ac97.pi",
- s,
- pi_callback,
- &as
- );
- break;
-
- case PO_INDEX:
- s->voice_po = AUD_open_out (
- &s->card,
- s->voice_po,
- "ac97.po",
- s,
- po_callback,
- &as
- );
- break;
-
- case MC_INDEX:
- s->voice_mc = AUD_open_in (
- &s->card,
- s->voice_mc,
- "ac97.mc",
- s,
- mc_callback,
- &as
- );
- break;
- }
- }
- else {
- s->invalid_freq[index] = freq;
- switch (index) {
- case PI_INDEX:
- AUD_close_in (&s->card, s->voice_pi);
- s->voice_pi = NULL;
- break;
-
- case PO_INDEX:
- AUD_close_out (&s->card, s->voice_po);
- s->voice_po = NULL;
- break;
-
- case MC_INDEX:
- AUD_close_in (&s->card, s->voice_mc);
- s->voice_mc = NULL;
- break;
- }
- }
-}
-
-static void reset_voices (AC97LinkState *s, uint8_t active[LAST_INDEX])
-{
- uint16_t freq;
-
- freq = mixer_load (s, AC97_PCM_LR_ADC_Rate);
- open_voice (s, PI_INDEX, freq);
- AUD_set_active_in (s->voice_pi, active[PI_INDEX]);
-
- freq = mixer_load (s, AC97_PCM_Front_DAC_Rate);
- open_voice (s, PO_INDEX, freq);
- AUD_set_active_out (s->voice_po, active[PO_INDEX]);
-
- freq = mixer_load (s, AC97_MIC_ADC_Rate);
- open_voice (s, MC_INDEX, freq);
- AUD_set_active_in (s->voice_mc, active[MC_INDEX]);
-}
-
-static void get_volume (uint16_t vol, uint16_t mask, int inverse,
- int *mute, uint8_t *lvol, uint8_t *rvol)
-{
- *mute = (vol >> MUTE_SHIFT) & 1;
- *rvol = (255 * (vol & mask)) / mask;
- *lvol = (255 * ((vol >> 8) & mask)) / mask;
-
- if (inverse) {
- *rvol = 255 - *rvol;
- *lvol = 255 - *lvol;
- }
-}
-
-static void update_combined_volume_out (AC97LinkState *s)
-{
- uint8_t lvol, rvol, plvol, prvol;
- int mute, pmute;
-
- get_volume (mixer_load (s, AC97_Master_Volume_Mute), 0x3f, 1,
- &mute, &lvol, &rvol);
- get_volume (mixer_load (s, AC97_PCM_Out_Volume_Mute), 0x1f, 1,
- &pmute, &plvol, &prvol);
-
- mute = mute | pmute;
- lvol = (lvol * plvol) / 255;
- rvol = (rvol * prvol) / 255;
-
- AUD_set_volume_out (s->voice_po, mute, lvol, rvol);
-}
-
-static void update_volume_in (AC97LinkState *s)
-{
- uint8_t lvol, rvol;
- int mute;
-
- get_volume (mixer_load (s, AC97_Record_Gain_Mute), 0x0f, 0,
- &mute, &lvol, &rvol);
-
- AUD_set_volume_in (s->voice_pi, mute, lvol, rvol);
-}
-
-static void set_volume (AC97LinkState *s, int index, uint32_t val)
-{
- switch (index) {
- case AC97_Master_Volume_Mute:
- val &= 0xbf3f;
- mixer_store (s, index, val);
- update_combined_volume_out (s);
- break;
- case AC97_PCM_Out_Volume_Mute:
- val &= 0x9f1f;
- mixer_store (s, index, val);
- update_combined_volume_out (s);
- break;
- case AC97_Record_Gain_Mute:
- val &= 0x8f0f;
- mixer_store (s, index, val);
- update_volume_in (s);
- break;
- }
-}
-
-static void record_select (AC97LinkState *s, uint32_t val)
-{
- uint8_t rs = val & REC_MASK;
- uint8_t ls = (val >> 8) & REC_MASK;
- mixer_store (s, AC97_Record_Select, rs | (ls << 8));
-}
-
-static void mixer_reset (AC97LinkState *s)
-{
- uint8_t active[LAST_INDEX];
-
- dolog ("mixer_reset\n");
- memset (s->mixer_data, 0, sizeof (s->mixer_data));
- memset (active, 0, sizeof (active));
- mixer_store (s, AC97_Reset , 0x0000); /* 6940 */
- mixer_store (s, AC97_Headphone_Volume_Mute , 0x0000);
- mixer_store (s, AC97_Master_Volume_Mono_Mute , 0x0000);
- mixer_store (s, AC97_Master_Tone_RL, 0x0000);
- mixer_store (s, AC97_PC_BEEP_Volume_Mute , 0x0000);
- mixer_store (s, AC97_Phone_Volume_Mute , 0x0000);
- mixer_store (s, AC97_Mic_Volume_Mute , 0x0000);
- mixer_store (s, AC97_Line_In_Volume_Mute , 0x0000);
- mixer_store (s, AC97_CD_Volume_Mute , 0x0000);
- mixer_store (s, AC97_Video_Volume_Mute , 0x0000);
- mixer_store (s, AC97_Aux_Volume_Mute , 0x0000);
- mixer_store (s, AC97_Record_Gain_Mic_Mute , 0x0000);
- mixer_store (s, AC97_General_Purpose , 0x0000);
- mixer_store (s, AC97_3D_Control , 0x0000);
- mixer_store (s, AC97_Powerdown_Ctrl_Stat , 0x000f);
-
- /*
- * Sigmatel 9700 (STAC9700)
- */
- mixer_store (s, AC97_Vendor_ID1 , 0x8384);
- mixer_store (s, AC97_Vendor_ID2 , 0x7600); /* 7608 */
-
- mixer_store (s, AC97_Extended_Audio_ID , 0x0809);
- mixer_store (s, AC97_Extended_Audio_Ctrl_Stat, 0x0009);
- mixer_store (s, AC97_PCM_Front_DAC_Rate , 0xbb80);
- mixer_store (s, AC97_PCM_Surround_DAC_Rate , 0xbb80);
- mixer_store (s, AC97_PCM_LFE_DAC_Rate , 0xbb80);
- mixer_store (s, AC97_PCM_LR_ADC_Rate , 0xbb80);
- mixer_store (s, AC97_MIC_ADC_Rate , 0xbb80);
-
- record_select (s, 0);
- set_volume (s, AC97_Master_Volume_Mute, 0x8000);
- set_volume (s, AC97_PCM_Out_Volume_Mute, 0x8808);
- set_volume (s, AC97_Record_Gain_Mute, 0x8808);
-
- reset_voices (s, active);
-}
-
-/**
- * Native audio mixer
- * I/O Reads
- */
-static uint32_t nam_readb (void *opaque, uint32_t addr)
-{
- AC97LinkState *s = opaque;
- dolog ("U nam readb %#x\n", addr);
- s->cas = 0;
- return ~0U;
-}
-
-static uint32_t nam_readw (void *opaque, uint32_t addr)
-{
- AC97LinkState *s = opaque;
- uint32_t val = ~0U;
- uint32_t index = addr;
- s->cas = 0;
- val = mixer_load (s, index);
- return val;
-}
-
-static uint32_t nam_readl (void *opaque, uint32_t addr)
-{
- AC97LinkState *s = opaque;
- dolog ("U nam readl %#x\n", addr);
- s->cas = 0;
- return ~0U;
-}
-
-/**
- * Native audio mixer
- * I/O Writes
- */
-static void nam_writeb (void *opaque, uint32_t addr, uint32_t val)
-{
- AC97LinkState *s = opaque;
- dolog ("U nam writeb %#x <- %#x\n", addr, val);
- s->cas = 0;
-}
-
-static void nam_writew (void *opaque, uint32_t addr, uint32_t val)
-{
- AC97LinkState *s = opaque;
- uint32_t index = addr;
- s->cas = 0;
- switch (index) {
- case AC97_Reset:
- mixer_reset (s);
- break;
- case AC97_Powerdown_Ctrl_Stat:
- val &= ~0x800f;
- val |= mixer_load (s, index) & 0xf;
- mixer_store (s, index, val);
- break;
- case AC97_PCM_Out_Volume_Mute:
- case AC97_Master_Volume_Mute:
- case AC97_Record_Gain_Mute:
- set_volume (s, index, val);
- break;
- case AC97_Record_Select:
- record_select (s, val);
- break;
- case AC97_Vendor_ID1:
- case AC97_Vendor_ID2:
- dolog ("Attempt to write vendor ID to %#x\n", val);
- break;
- case AC97_Extended_Audio_ID:
- dolog ("Attempt to write extended audio ID to %#x\n", val);
- break;
- case AC97_Extended_Audio_Ctrl_Stat:
- if (!(val & EACS_VRA)) {
- mixer_store (s, AC97_PCM_Front_DAC_Rate, 0xbb80);
- mixer_store (s, AC97_PCM_LR_ADC_Rate, 0xbb80);
- open_voice (s, PI_INDEX, 48000);
- open_voice (s, PO_INDEX, 48000);
- }
- if (!(val & EACS_VRM)) {
- mixer_store (s, AC97_MIC_ADC_Rate, 0xbb80);
- open_voice (s, MC_INDEX, 48000);
- }
- dolog ("Setting extended audio control to %#x\n", val);
- mixer_store (s, AC97_Extended_Audio_Ctrl_Stat, val);
- break;
- case AC97_PCM_Front_DAC_Rate:
- if (mixer_load (s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA) {
- mixer_store (s, index, val);
- dolog ("Set front DAC rate to %d\n", val);
- open_voice (s, PO_INDEX, val);
- }
- else {
- dolog ("Attempt to set front DAC rate to %d, "
- "but VRA is not set\n",
- val);
- }
- break;
- case AC97_MIC_ADC_Rate:
- if (mixer_load (s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRM) {
- mixer_store (s, index, val);
- dolog ("Set MIC ADC rate to %d\n", val);
- open_voice (s, MC_INDEX, val);
- }
- else {
- dolog ("Attempt to set MIC ADC rate to %d, "
- "but VRM is not set\n",
- val);
- }
- break;
- case AC97_PCM_LR_ADC_Rate:
- if (mixer_load (s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA) {
- mixer_store (s, index, val);
- dolog ("Set front LR ADC rate to %d\n", val);
- open_voice (s, PI_INDEX, val);
- }
- else {
- dolog ("Attempt to set LR ADC rate to %d, but VRA is not set\n",
- val);
- }
- break;
- case AC97_Headphone_Volume_Mute:
- case AC97_Master_Volume_Mono_Mute:
- case AC97_Master_Tone_RL:
- case AC97_PC_BEEP_Volume_Mute:
- case AC97_Phone_Volume_Mute:
- case AC97_Mic_Volume_Mute:
- case AC97_Line_In_Volume_Mute:
- case AC97_CD_Volume_Mute:
- case AC97_Video_Volume_Mute:
- case AC97_Aux_Volume_Mute:
- case AC97_Record_Gain_Mic_Mute:
- case AC97_General_Purpose:
- case AC97_3D_Control:
- case AC97_Sigmatel_Analog:
- case AC97_Sigmatel_Dac2Invert:
- /* None of the features in these regs are emulated, so they are RO */
- break;
- default:
- dolog ("U nam writew %#x <- %#x\n", addr, val);
- mixer_store (s, index, val);
- break;
- }
-}
-
-static void nam_writel (void *opaque, uint32_t addr, uint32_t val)
-{
- AC97LinkState *s = opaque;
- dolog ("U nam writel %#x <- %#x\n", addr, val);
- s->cas = 0;
-}
-
-/**
- * Native audio bus master
- * I/O Reads
- */
-static uint32_t nabm_readb (void *opaque, uint32_t addr)
-{
- AC97LinkState *s = opaque;
- AC97BusMasterRegs *r = NULL;
- uint32_t index = addr;
- uint32_t val = ~0U;
-
- switch (index) {
- case CAS:
- dolog ("CAS %d\n", s->cas);
- val = s->cas;
- s->cas = 1;
- break;
- case PI_CIV:
- case PO_CIV:
- case MC_CIV:
- r = &s->bm_regs[GET_BM (index)];
- val = r->civ;
- dolog ("CIV[%d] -> %#x\n", GET_BM (index), val);
- break;
- case PI_LVI:
- case PO_LVI:
- case MC_LVI:
- r = &s->bm_regs[GET_BM (index)];
- val = r->lvi;
- dolog ("LVI[%d] -> %#x\n", GET_BM (index), val);
- break;
- case PI_PIV:
- case PO_PIV:
- case MC_PIV:
- r = &s->bm_regs[GET_BM (index)];
- val = r->piv;
- dolog ("PIV[%d] -> %#x\n", GET_BM (index), val);
- break;
- case PI_CR:
- case PO_CR:
- case MC_CR:
- r = &s->bm_regs[GET_BM (index)];
- val = r->cr;
- dolog ("CR[%d] -> %#x\n", GET_BM (index), val);
- break;
- case PI_SR:
- case PO_SR:
- case MC_SR:
- r = &s->bm_regs[GET_BM (index)];
- val = r->sr & 0xff;
- dolog ("SRb[%d] -> %#x\n", GET_BM (index), val);
- break;
- default:
- dolog ("U nabm readb %#x -> %#x\n", addr, val);
- break;
- }
- return val;
-}
-
-static uint32_t nabm_readw (void *opaque, uint32_t addr)
-{
- AC97LinkState *s = opaque;
- AC97BusMasterRegs *r = NULL;
- uint32_t index = addr;
- uint32_t val = ~0U;
-
- switch (index) {
- case PI_SR:
- case PO_SR:
- case MC_SR:
- r = &s->bm_regs[GET_BM (index)];
- val = r->sr;
- dolog ("SR[%d] -> %#x\n", GET_BM (index), val);
- break;
- case PI_PICB:
- case PO_PICB:
- case MC_PICB:
- r = &s->bm_regs[GET_BM (index)];
- val = r->picb;
- dolog ("PICB[%d] -> %#x\n", GET_BM (index), val);
- break;
- default:
- dolog ("U nabm readw %#x -> %#x\n", addr, val);
- break;
- }
- return val;
-}
-
-static uint32_t nabm_readl (void *opaque, uint32_t addr)
-{
- AC97LinkState *s = opaque;
- AC97BusMasterRegs *r = NULL;
- uint32_t index = addr;
- uint32_t val = ~0U;
-
- switch (index) {
- case PI_BDBAR:
- case PO_BDBAR:
- case MC_BDBAR:
- r = &s->bm_regs[GET_BM (index)];
- val = r->bdbar;
- dolog ("BMADDR[%d] -> %#x\n", GET_BM (index), val);
- break;
- case PI_CIV:
- case PO_CIV:
- case MC_CIV:
- r = &s->bm_regs[GET_BM (index)];
- val = r->civ | (r->lvi << 8) | (r->sr << 16);
- dolog ("CIV LVI SR[%d] -> %#x, %#x, %#x\n", GET_BM (index),
- r->civ, r->lvi, r->sr);
- break;
- case PI_PICB:
- case PO_PICB:
- case MC_PICB:
- r = &s->bm_regs[GET_BM (index)];
- val = r->picb | (r->piv << 16) | (r->cr << 24);
- dolog ("PICB PIV CR[%d] -> %#x %#x %#x %#x\n", GET_BM (index),
- val, r->picb, r->piv, r->cr);
- break;
- case GLOB_CNT:
- val = s->glob_cnt;
- dolog ("glob_cnt -> %#x\n", val);
- break;
- case GLOB_STA:
- val = s->glob_sta | GS_S0CR;
- dolog ("glob_sta -> %#x\n", val);
- break;
- default:
- dolog ("U nabm readl %#x -> %#x\n", addr, val);
- break;
- }
- return val;
-}
-
-/**
- * Native audio bus master
- * I/O Writes
- */
-static void nabm_writeb (void *opaque, uint32_t addr, uint32_t val)
-{
- AC97LinkState *s = opaque;
- AC97BusMasterRegs *r = NULL;
- uint32_t index = addr;
- switch (index) {
- case PI_LVI:
- case PO_LVI:
- case MC_LVI:
- r = &s->bm_regs[GET_BM (index)];
- if ((r->cr & CR_RPBM) && (r->sr & SR_DCH)) {
- r->sr &= ~(SR_DCH | SR_CELV);
- r->civ = r->piv;
- r->piv = (r->piv + 1) % 32;
- fetch_bd (s, r);
- }
- r->lvi = val % 32;
- dolog ("LVI[%d] <- %#x\n", GET_BM (index), val);
- break;
- case PI_CR:
- case PO_CR:
- case MC_CR:
- r = &s->bm_regs[GET_BM (index)];
- if (val & CR_RR) {
- reset_bm_regs (s, r);
- }
- else {
- r->cr = val & CR_VALID_MASK;
- if (!(r->cr & CR_RPBM)) {
- voice_set_active (s, r - s->bm_regs, 0);
- r->sr |= SR_DCH;
- }
- else {
- r->civ = r->piv;
- r->piv = (r->piv + 1) % 32;
- fetch_bd (s, r);
- r->sr &= ~SR_DCH;
- voice_set_active (s, r - s->bm_regs, 1);
- }
- }
- dolog ("CR[%d] <- %#x (cr %#x)\n", GET_BM (index), val, r->cr);
- break;
- case PI_SR:
- case PO_SR:
- case MC_SR:
- r = &s->bm_regs[GET_BM (index)];
- r->sr |= val & ~(SR_RO_MASK | SR_WCLEAR_MASK);
- update_sr (s, r, r->sr & ~(val & SR_WCLEAR_MASK));
- dolog ("SR[%d] <- %#x (sr %#x)\n", GET_BM (index), val, r->sr);
- break;
- default:
- dolog ("U nabm writeb %#x <- %#x\n", addr, val);
- break;
- }
-}
-
-static void nabm_writew (void *opaque, uint32_t addr, uint32_t val)
-{
- AC97LinkState *s = opaque;
- AC97BusMasterRegs *r = NULL;
- uint32_t index = addr;
- switch (index) {
- case PI_SR:
- case PO_SR:
- case MC_SR:
- r = &s->bm_regs[GET_BM (index)];
- r->sr |= val & ~(SR_RO_MASK | SR_WCLEAR_MASK);
- update_sr (s, r, r->sr & ~(val & SR_WCLEAR_MASK));
- dolog ("SR[%d] <- %#x (sr %#x)\n", GET_BM (index), val, r->sr);
- break;
- default:
- dolog ("U nabm writew %#x <- %#x\n", addr, val);
- break;
- }
-}
-
-static void nabm_writel (void *opaque, uint32_t addr, uint32_t val)
-{
- AC97LinkState *s = opaque;
- AC97BusMasterRegs *r = NULL;
- uint32_t index = addr;
- switch (index) {
- case PI_BDBAR:
- case PO_BDBAR:
- case MC_BDBAR:
- r = &s->bm_regs[GET_BM (index)];
- r->bdbar = val & ~3;
- dolog ("BDBAR[%d] <- %#x (bdbar %#x)\n",
- GET_BM (index), val, r->bdbar);
- break;
- case GLOB_CNT:
- if (val & GC_WR)
- warm_reset (s);
- if (val & GC_CR)
- cold_reset (s);
- if (!(val & (GC_WR | GC_CR)))
- s->glob_cnt = val & GC_VALID_MASK;
- dolog ("glob_cnt <- %#x (glob_cnt %#x)\n", val, s->glob_cnt);
- break;
- case GLOB_STA:
- s->glob_sta &= ~(val & GS_WCLEAR_MASK);
- s->glob_sta |= (val & ~(GS_WCLEAR_MASK | GS_RO_MASK)) & GS_VALID_MASK;
- dolog ("glob_sta <- %#x (glob_sta %#x)\n", val, s->glob_sta);
- break;
- default:
- dolog ("U nabm writel %#x <- %#x\n", addr, val);
- break;
- }
-}
-
-static int write_audio (AC97LinkState *s, AC97BusMasterRegs *r,
- int max, int *stop)
-{
- uint8_t tmpbuf[4096];
- uint32_t addr = r->bd.addr;
- uint32_t temp = r->picb << 1;
- uint32_t written = 0;
- int to_copy = 0;
- temp = audio_MIN (temp, max);
-
- if (!temp) {
- *stop = 1;
- return 0;
- }
-
- while (temp) {
- int copied;
- to_copy = audio_MIN (temp, sizeof (tmpbuf));
- pci_dma_read (&s->dev, addr, tmpbuf, to_copy);
- copied = AUD_write (s->voice_po, tmpbuf, to_copy);
- dolog ("write_audio max=%x to_copy=%x copied=%x\n",
- max, to_copy, copied);
- if (!copied) {
- *stop = 1;
- break;
- }
- temp -= copied;
- addr += copied;
- written += copied;
- }
-
- if (!temp) {
- if (to_copy < 4) {
- dolog ("whoops\n");
- s->last_samp = 0;
- }
- else {
- s->last_samp = *(uint32_t *) &tmpbuf[to_copy - 4];
- }
- }
-
- r->bd.addr = addr;
- return written;
-}
-
-static void write_bup (AC97LinkState *s, int elapsed)
-{
- dolog ("write_bup\n");
- if (!(s->bup_flag & BUP_SET)) {
- if (s->bup_flag & BUP_LAST) {
- int i;
- uint8_t *p = s->silence;
- for (i = 0; i < sizeof (s->silence) / 4; i++, p += 4) {
- *(uint32_t *) p = s->last_samp;
- }
- }
- else {
- memset (s->silence, 0, sizeof (s->silence));
- }
- s->bup_flag |= BUP_SET;
- }
-
- while (elapsed) {
- int temp = audio_MIN (elapsed, sizeof (s->silence));
- while (temp) {
- int copied = AUD_write (s->voice_po, s->silence, temp);
- if (!copied)
- return;
- temp -= copied;
- elapsed -= copied;
- }
- }
-}
-
-static int read_audio (AC97LinkState *s, AC97BusMasterRegs *r,
- int max, int *stop)
-{
- uint8_t tmpbuf[4096];
- uint32_t addr = r->bd.addr;
- uint32_t temp = r->picb << 1;
- uint32_t nread = 0;
- int to_copy = 0;
- SWVoiceIn *voice = (r - s->bm_regs) == MC_INDEX ? s->voice_mc : s->voice_pi;
-
- temp = audio_MIN (temp, max);
-
- if (!temp) {
- *stop = 1;
- return 0;
- }
-
- while (temp) {
- int acquired;
- to_copy = audio_MIN (temp, sizeof (tmpbuf));
- acquired = AUD_read (voice, tmpbuf, to_copy);
- if (!acquired) {
- *stop = 1;
- break;
- }
- pci_dma_write (&s->dev, addr, tmpbuf, acquired);
- temp -= acquired;
- addr += acquired;
- nread += acquired;
- }
-
- r->bd.addr = addr;
- return nread;
-}
-
-static void transfer_audio (AC97LinkState *s, int index, int elapsed)
-{
- AC97BusMasterRegs *r = &s->bm_regs[index];
- int stop = 0;
-
- if (s->invalid_freq[index]) {
- AUD_log ("ac97", "attempt to use voice %d with invalid frequency %d\n",
- index, s->invalid_freq[index]);
- return;
- }
-
- if (r->sr & SR_DCH) {
- if (r->cr & CR_RPBM) {
- switch (index) {
- case PO_INDEX:
- write_bup (s, elapsed);
- break;
- }
- }
- return;
- }
-
- while ((elapsed >> 1) && !stop) {
- int temp;
-
- if (!r->bd_valid) {
- dolog ("invalid bd\n");
- fetch_bd (s, r);
- }
-
- if (!r->picb) {
- dolog ("fresh bd %d is empty %#x %#x\n",
- r->civ, r->bd.addr, r->bd.ctl_len);
- if (r->civ == r->lvi) {
- r->sr |= SR_DCH; /* CELV? */
- s->bup_flag = 0;
- break;
- }
- r->sr &= ~SR_CELV;
- r->civ = r->piv;
- r->piv = (r->piv + 1) % 32;
- fetch_bd (s, r);
- return;
- }
-
- switch (index) {
- case PO_INDEX:
- temp = write_audio (s, r, elapsed, &stop);
- elapsed -= temp;
- r->picb -= (temp >> 1);
- break;
-
- case PI_INDEX:
- case MC_INDEX:
- temp = read_audio (s, r, elapsed, &stop);
- elapsed -= temp;
- r->picb -= (temp >> 1);
- break;
- }
-
- if (!r->picb) {
- uint32_t new_sr = r->sr & ~SR_CELV;
-
- if (r->bd.ctl_len & BD_IOC) {
- new_sr |= SR_BCIS;
- }
-
- if (r->civ == r->lvi) {
- dolog ("Underrun civ (%d) == lvi (%d)\n", r->civ, r->lvi);
-
- new_sr |= SR_LVBCI | SR_DCH | SR_CELV;
- stop = 1;
- s->bup_flag = (r->bd.ctl_len & BD_BUP) ? BUP_LAST : 0;
- }
- else {
- r->civ = r->piv;
- r->piv = (r->piv + 1) % 32;
- fetch_bd (s, r);
- }
-
- update_sr (s, r, new_sr);
- }
- }
-}
-
-static void pi_callback (void *opaque, int avail)
-{
- transfer_audio (opaque, PI_INDEX, avail);
-}
-
-static void mc_callback (void *opaque, int avail)
-{
- transfer_audio (opaque, MC_INDEX, avail);
-}
-
-static void po_callback (void *opaque, int free)
-{
- transfer_audio (opaque, PO_INDEX, free);
-}
-
-static const VMStateDescription vmstate_ac97_bm_regs = {
- .name = "ac97_bm_regs",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32 (bdbar, AC97BusMasterRegs),
- VMSTATE_UINT8 (civ, AC97BusMasterRegs),
- VMSTATE_UINT8 (lvi, AC97BusMasterRegs),
- VMSTATE_UINT16 (sr, AC97BusMasterRegs),
- VMSTATE_UINT16 (picb, AC97BusMasterRegs),
- VMSTATE_UINT8 (piv, AC97BusMasterRegs),
- VMSTATE_UINT8 (cr, AC97BusMasterRegs),
- VMSTATE_UINT32 (bd_valid, AC97BusMasterRegs),
- VMSTATE_UINT32 (bd.addr, AC97BusMasterRegs),
- VMSTATE_UINT32 (bd.ctl_len, AC97BusMasterRegs),
- VMSTATE_END_OF_LIST ()
- }
-};
-
-static int ac97_post_load (void *opaque, int version_id)
-{
- uint8_t active[LAST_INDEX];
- AC97LinkState *s = opaque;
-
- record_select (s, mixer_load (s, AC97_Record_Select));
- set_volume (s, AC97_Master_Volume_Mute,
- mixer_load (s, AC97_Master_Volume_Mute));
- set_volume (s, AC97_PCM_Out_Volume_Mute,
- mixer_load (s, AC97_PCM_Out_Volume_Mute));
- set_volume (s, AC97_Record_Gain_Mute,
- mixer_load (s, AC97_Record_Gain_Mute));
-
- active[PI_INDEX] = !!(s->bm_regs[PI_INDEX].cr & CR_RPBM);
- active[PO_INDEX] = !!(s->bm_regs[PO_INDEX].cr & CR_RPBM);
- active[MC_INDEX] = !!(s->bm_regs[MC_INDEX].cr & CR_RPBM);
- reset_voices (s, active);
-
- s->bup_flag = 0;
- s->last_samp = 0;
- return 0;
-}
-
-static bool is_version_2 (void *opaque, int version_id)
-{
- return version_id == 2;
-}
-
-static const VMStateDescription vmstate_ac97 = {
- .name = "ac97",
- .version_id = 3,
- .minimum_version_id = 2,
- .post_load = ac97_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE (dev, AC97LinkState),
- VMSTATE_UINT32 (glob_cnt, AC97LinkState),
- VMSTATE_UINT32 (glob_sta, AC97LinkState),
- VMSTATE_UINT32 (cas, AC97LinkState),
- VMSTATE_STRUCT_ARRAY (bm_regs, AC97LinkState, 3, 1,
- vmstate_ac97_bm_regs, AC97BusMasterRegs),
- VMSTATE_BUFFER (mixer_data, AC97LinkState),
- VMSTATE_UNUSED_TEST (is_version_2, 3),
- VMSTATE_END_OF_LIST ()
- }
-};
-
-static uint64_t nam_read(void *opaque, hwaddr addr, unsigned size)
-{
- if ((addr / size) > 256) {
- return -1;
- }
-
- switch (size) {
- case 1:
- return nam_readb(opaque, addr);
- case 2:
- return nam_readw(opaque, addr);
- case 4:
- return nam_readl(opaque, addr);
- default:
- return -1;
- }
-}
-
-static void nam_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned size)
-{
- if ((addr / size) > 256) {
- return;
- }
-
- switch (size) {
- case 1:
- nam_writeb(opaque, addr, val);
- break;
- case 2:
- nam_writew(opaque, addr, val);
- break;
- case 4:
- nam_writel(opaque, addr, val);
- break;
- }
-}
-
-static const MemoryRegionOps ac97_io_nam_ops = {
- .read = nam_read,
- .write = nam_write,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 4,
- },
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static uint64_t nabm_read(void *opaque, hwaddr addr, unsigned size)
-{
- if ((addr / size) > 64) {
- return -1;
- }
-
- switch (size) {
- case 1:
- return nabm_readb(opaque, addr);
- case 2:
- return nabm_readw(opaque, addr);
- case 4:
- return nabm_readl(opaque, addr);
- default:
- return -1;
- }
-}
-
-static void nabm_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned size)
-{
- if ((addr / size) > 64) {
- return;
- }
-
- switch (size) {
- case 1:
- nabm_writeb(opaque, addr, val);
- break;
- case 2:
- nabm_writew(opaque, addr, val);
- break;
- case 4:
- nabm_writel(opaque, addr, val);
- break;
- }
-}
-
-
-static const MemoryRegionOps ac97_io_nabm_ops = {
- .read = nabm_read,
- .write = nabm_write,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 4,
- },
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void ac97_on_reset (DeviceState *dev)
-{
- AC97LinkState *s = container_of(dev, AC97LinkState, dev.qdev);
-
- reset_bm_regs (s, &s->bm_regs[0]);
- reset_bm_regs (s, &s->bm_regs[1]);
- reset_bm_regs (s, &s->bm_regs[2]);
-
- /*
- * Reset the mixer too. The Windows XP driver seems to rely on
- * this. At least it wants to read the vendor id before it resets
- * the codec manually.
- */
- mixer_reset (s);
-}
-
-static void ac97_realize(PCIDevice *dev, Error **errp)
-{
- AC97LinkState *s = DO_UPCAST (AC97LinkState, dev, dev);
- uint8_t *c = s->dev.config;
-
- /* TODO: no need to override */
- c[PCI_COMMAND] = 0x00; /* pcicmd pci command rw, ro */
- c[PCI_COMMAND + 1] = 0x00;
-
- /* TODO: */
- c[PCI_STATUS] = PCI_STATUS_FAST_BACK; /* pcists pci status rwc, ro */
- c[PCI_STATUS + 1] = PCI_STATUS_DEVSEL_MEDIUM >> 8;
-
- c[PCI_CLASS_PROG] = 0x00; /* pi programming interface ro */
-
- /* TODO set when bar is registered. no need to override. */
- /* nabmar native audio mixer base address rw */
- c[PCI_BASE_ADDRESS_0] = PCI_BASE_ADDRESS_SPACE_IO;
- c[PCI_BASE_ADDRESS_0 + 1] = 0x00;
- c[PCI_BASE_ADDRESS_0 + 2] = 0x00;
- c[PCI_BASE_ADDRESS_0 + 3] = 0x00;
-
- /* TODO set when bar is registered. no need to override. */
- /* nabmbar native audio bus mastering base address rw */
- c[PCI_BASE_ADDRESS_0 + 4] = PCI_BASE_ADDRESS_SPACE_IO;
- c[PCI_BASE_ADDRESS_0 + 5] = 0x00;
- c[PCI_BASE_ADDRESS_0 + 6] = 0x00;
- c[PCI_BASE_ADDRESS_0 + 7] = 0x00;
-
- if (s->use_broken_id) {
- c[PCI_SUBSYSTEM_VENDOR_ID] = 0x86;
- c[PCI_SUBSYSTEM_VENDOR_ID + 1] = 0x80;
- c[PCI_SUBSYSTEM_ID] = 0x00;
- c[PCI_SUBSYSTEM_ID + 1] = 0x00;
- }
-
- c[PCI_INTERRUPT_LINE] = 0x00; /* intr_ln interrupt line rw */
- c[PCI_INTERRUPT_PIN] = 0x01; /* intr_pn interrupt pin ro */
-
- memory_region_init_io (&s->io_nam, OBJECT(s), &ac97_io_nam_ops, s,
- "ac97-nam", 1024);
- memory_region_init_io (&s->io_nabm, OBJECT(s), &ac97_io_nabm_ops, s,
- "ac97-nabm", 256);
- pci_register_bar (&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_nam);
- pci_register_bar (&s->dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->io_nabm);
- AUD_register_card ("ac97", &s->card);
- ac97_on_reset (&s->dev.qdev);
-}
-
-static int ac97_init (PCIBus *bus)
-{
- pci_create_simple (bus, -1, "AC97");
- return 0;
-}
-
-static Property ac97_properties[] = {
- DEFINE_PROP_UINT32 ("use_broken_id", AC97LinkState, use_broken_id, 0),
- DEFINE_PROP_END_OF_LIST (),
-};
-
-static void ac97_class_init (ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS (klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS (klass);
-
- k->realize = ac97_realize;
- k->vendor_id = PCI_VENDOR_ID_INTEL;
- k->device_id = PCI_DEVICE_ID_INTEL_82801AA_5;
- k->revision = 0x01;
- k->class_id = PCI_CLASS_MULTIMEDIA_AUDIO;
- set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
- dc->desc = "Intel 82801AA AC97 Audio";
- dc->vmsd = &vmstate_ac97;
- dc->props = ac97_properties;
- dc->reset = ac97_on_reset;
-}
-
-static const TypeInfo ac97_info = {
- .name = "AC97",
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof (AC97LinkState),
- .class_init = ac97_class_init,
-};
-
-static void ac97_register_types (void)
-{
- type_register_static (&ac97_info);
- pci_register_soundhw("ac97", "Intel 82801AA AC97 Audio", ac97_init);
-}
-
-type_init (ac97_register_types)
diff --git a/qemu/hw/audio/adlib.c b/qemu/hw/audio/adlib.c
deleted file mode 100644
index 7836446fc..000000000
--- a/qemu/hw/audio/adlib.c
+++ /dev/null
@@ -1,386 +0,0 @@
-/*
- * QEMU Proxy for OPL2/3 emulation by MAME team
- *
- * Copyright (c) 2004-2005 Vassili Karpov (malc)
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/hw.h"
-#include "hw/audio/audio.h"
-#include "audio/audio.h"
-#include "hw/isa/isa.h"
-
-//#define DEBUG
-
-#define ADLIB_KILL_TIMERS 1
-
-#ifdef HAS_YMF262
-#define ADLIB_DESC "Yamaha YMF262 (OPL3)"
-#else
-#define ADLIB_DESC "Yamaha YM3812 (OPL2)"
-#endif
-
-#ifdef DEBUG
-#include "qemu/timer.h"
-#endif
-
-#define dolog(...) AUD_log ("adlib", __VA_ARGS__)
-#ifdef DEBUG
-#define ldebug(...) dolog (__VA_ARGS__)
-#else
-#define ldebug(...)
-#endif
-
-#ifdef HAS_YMF262
-#include "ymf262.h"
-void YMF262UpdateOneQEMU (int which, INT16 *dst, int length);
-#define SHIFT 2
-#else
-#include "fmopl.h"
-#define SHIFT 1
-#endif
-
-#define TYPE_ADLIB "adlib"
-#define ADLIB(obj) OBJECT_CHECK(AdlibState, (obj), TYPE_ADLIB)
-
-typedef struct {
- ISADevice parent_obj;
-
- QEMUSoundCard card;
- uint32_t freq;
- uint32_t port;
- int ticking[2];
- int enabled;
- int active;
- int bufpos;
-#ifdef DEBUG
- int64_t exp[2];
-#endif
- int16_t *mixbuf;
- uint64_t dexp[2];
- SWVoiceOut *voice;
- int left, pos, samples;
- QEMUAudioTimeStamp ats;
-#ifndef HAS_YMF262
- FM_OPL *opl;
-#endif
- PortioList port_list;
-} AdlibState;
-
-static AdlibState *glob_adlib;
-
-static void adlib_stop_opl_timer (AdlibState *s, size_t n)
-{
-#ifdef HAS_YMF262
- YMF262TimerOver (0, n);
-#else
- OPLTimerOver (s->opl, n);
-#endif
- s->ticking[n] = 0;
-}
-
-static void adlib_kill_timers (AdlibState *s)
-{
- size_t i;
-
- for (i = 0; i < 2; ++i) {
- if (s->ticking[i]) {
- uint64_t delta;
-
- delta = AUD_get_elapsed_usec_out (s->voice, &s->ats);
- ldebug (
- "delta = %f dexp = %f expired => %d\n",
- delta / 1000000.0,
- s->dexp[i] / 1000000.0,
- delta >= s->dexp[i]
- );
- if (ADLIB_KILL_TIMERS || delta >= s->dexp[i]) {
- adlib_stop_opl_timer (s, i);
- AUD_init_time_stamp_out (s->voice, &s->ats);
- }
- }
- }
-}
-
-static void adlib_write(void *opaque, uint32_t nport, uint32_t val)
-{
- AdlibState *s = opaque;
- int a = nport & 3;
-
- s->active = 1;
- AUD_set_active_out (s->voice, 1);
-
- adlib_kill_timers (s);
-
-#ifdef HAS_YMF262
- YMF262Write (0, a, val);
-#else
- OPLWrite (s->opl, a, val);
-#endif
-}
-
-static uint32_t adlib_read(void *opaque, uint32_t nport)
-{
- AdlibState *s = opaque;
- uint8_t data;
- int a = nport & 3;
-
- adlib_kill_timers (s);
-
-#ifdef HAS_YMF262
- data = YMF262Read (0, a);
-#else
- data = OPLRead (s->opl, a);
-#endif
- return data;
-}
-
-static void timer_handler (int c, double interval_Sec)
-{
- AdlibState *s = glob_adlib;
- unsigned n = c & 1;
-#ifdef DEBUG
- double interval;
- int64_t exp;
-#endif
-
- if (interval_Sec == 0.0) {
- s->ticking[n] = 0;
- return;
- }
-
- s->ticking[n] = 1;
-#ifdef DEBUG
- interval = NANOSECONDS_PER_SECOND * interval_Sec;
- exp = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + interval;
- s->exp[n] = exp;
-#endif
-
- s->dexp[n] = interval_Sec * 1000000.0;
- AUD_init_time_stamp_out (s->voice, &s->ats);
-}
-
-static int write_audio (AdlibState *s, int samples)
-{
- int net = 0;
- int pos = s->pos;
-
- while (samples) {
- int nbytes, wbytes, wsampl;
-
- nbytes = samples << SHIFT;
- wbytes = AUD_write (
- s->voice,
- s->mixbuf + (pos << (SHIFT - 1)),
- nbytes
- );
-
- if (wbytes) {
- wsampl = wbytes >> SHIFT;
-
- samples -= wsampl;
- pos = (pos + wsampl) % s->samples;
-
- net += wsampl;
- }
- else {
- break;
- }
- }
-
- return net;
-}
-
-static void adlib_callback (void *opaque, int free)
-{
- AdlibState *s = opaque;
- int samples, net = 0, to_play, written;
-
- samples = free >> SHIFT;
- if (!(s->active && s->enabled) || !samples) {
- return;
- }
-
- to_play = audio_MIN (s->left, samples);
- while (to_play) {
- written = write_audio (s, to_play);
-
- if (written) {
- s->left -= written;
- samples -= written;
- to_play -= written;
- s->pos = (s->pos + written) % s->samples;
- }
- else {
- return;
- }
- }
-
- samples = audio_MIN (samples, s->samples - s->pos);
- if (!samples) {
- return;
- }
-
-#ifdef HAS_YMF262
- YMF262UpdateOneQEMU (0, s->mixbuf + s->pos * 2, samples);
-#else
- YM3812UpdateOne (s->opl, s->mixbuf + s->pos, samples);
-#endif
-
- while (samples) {
- written = write_audio (s, samples);
-
- if (written) {
- net += written;
- samples -= written;
- s->pos = (s->pos + written) % s->samples;
- }
- else {
- s->left = samples;
- return;
- }
- }
-}
-
-static void Adlib_fini (AdlibState *s)
-{
-#ifdef HAS_YMF262
- YMF262Shutdown ();
-#else
- if (s->opl) {
- OPLDestroy (s->opl);
- s->opl = NULL;
- }
-#endif
-
- g_free(s->mixbuf);
-
- s->active = 0;
- s->enabled = 0;
- AUD_remove_card (&s->card);
-}
-
-static MemoryRegionPortio adlib_portio_list[] = {
- { 0, 4, 1, .read = adlib_read, .write = adlib_write, },
- { 0, 2, 1, .read = adlib_read, .write = adlib_write, },
- { 0x388, 4, 1, .read = adlib_read, .write = adlib_write, },
- PORTIO_END_OF_LIST(),
-};
-
-static void adlib_realizefn (DeviceState *dev, Error **errp)
-{
- AdlibState *s = ADLIB(dev);
- struct audsettings as;
-
- if (glob_adlib) {
- error_setg (errp, "Cannot create more than 1 adlib device");
- return;
- }
- glob_adlib = s;
-
-#ifdef HAS_YMF262
- if (YMF262Init (1, 14318180, s->freq)) {
- error_setg (errp, "YMF262Init %d failed", s->freq);
- return;
- }
- else {
- YMF262SetTimerHandler (0, timer_handler, 0);
- s->enabled = 1;
- }
-#else
- s->opl = OPLCreate (OPL_TYPE_YM3812, 3579545, s->freq);
- if (!s->opl) {
- error_setg (errp, "OPLCreate %d failed", s->freq);
- return;
- }
- else {
- OPLSetTimerHandler (s->opl, timer_handler, 0);
- s->enabled = 1;
- }
-#endif
-
- as.freq = s->freq;
- as.nchannels = SHIFT;
- as.fmt = AUD_FMT_S16;
- as.endianness = AUDIO_HOST_ENDIANNESS;
-
- AUD_register_card ("adlib", &s->card);
-
- s->voice = AUD_open_out (
- &s->card,
- s->voice,
- "adlib",
- s,
- adlib_callback,
- &as
- );
- if (!s->voice) {
- Adlib_fini (s);
- error_setg (errp, "Initializing audio voice failed");
- return;
- }
-
- s->samples = AUD_get_buffer_size_out (s->voice) >> SHIFT;
- s->mixbuf = g_malloc0 (s->samples << SHIFT);
-
- adlib_portio_list[0].offset = s->port;
- adlib_portio_list[1].offset = s->port + 8;
- portio_list_init (&s->port_list, OBJECT(s), adlib_portio_list, s, "adlib");
- portio_list_add (&s->port_list, isa_address_space_io(&s->parent_obj), 0);
-}
-
-static Property adlib_properties[] = {
- DEFINE_PROP_UINT32 ("iobase", AdlibState, port, 0x220),
- DEFINE_PROP_UINT32 ("freq", AdlibState, freq, 44100),
- DEFINE_PROP_END_OF_LIST (),
-};
-
-static void adlib_class_initfn (ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS (klass);
-
- dc->realize = adlib_realizefn;
- set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
- dc->desc = ADLIB_DESC;
- dc->props = adlib_properties;
-}
-
-static const TypeInfo adlib_info = {
- .name = TYPE_ADLIB,
- .parent = TYPE_ISA_DEVICE,
- .instance_size = sizeof (AdlibState),
- .class_init = adlib_class_initfn,
-};
-
-static int Adlib_init (ISABus *bus)
-{
- isa_create_simple (bus, TYPE_ADLIB);
- return 0;
-}
-
-static void adlib_register_types (void)
-{
- type_register_static (&adlib_info);
- isa_register_soundhw("adlib", ADLIB_DESC, Adlib_init);
-}
-
-type_init (adlib_register_types)
diff --git a/qemu/hw/audio/cs4231.c b/qemu/hw/audio/cs4231.c
deleted file mode 100644
index caf97c169..000000000
--- a/qemu/hw/audio/cs4231.c
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * QEMU Crystal CS4231 audio chip emulation
- *
- * Copyright (c) 2006 Fabrice Bellard
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-
-/*
- * In addition to Crystal CS4231 there is a DMA controller on Sparc.
- */
-#define CS_SIZE 0x40
-#define CS_REGS 16
-#define CS_DREGS 32
-#define CS_MAXDREG (CS_DREGS - 1)
-
-#define TYPE_CS4231 "SUNW,CS4231"
-#define CS4231(obj) \
- OBJECT_CHECK(CSState, (obj), TYPE_CS4231)
-
-typedef struct CSState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- qemu_irq irq;
- uint32_t regs[CS_REGS];
- uint8_t dregs[CS_DREGS];
-} CSState;
-
-#define CS_RAP(s) ((s)->regs[0] & CS_MAXDREG)
-#define CS_VER 0xa0
-#define CS_CDC_VER 0x8a
-
-static void cs_reset(DeviceState *d)
-{
- CSState *s = CS4231(d);
-
- memset(s->regs, 0, CS_REGS * 4);
- memset(s->dregs, 0, CS_DREGS);
- s->dregs[12] = CS_CDC_VER;
- s->dregs[25] = CS_VER;
-}
-
-static uint64_t cs_mem_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- CSState *s = opaque;
- uint32_t saddr, ret;
-
- saddr = addr >> 2;
- switch (saddr) {
- case 1:
- switch (CS_RAP(s)) {
- case 3: // Write only
- ret = 0;
- break;
- default:
- ret = s->dregs[CS_RAP(s)];
- break;
- }
- trace_cs4231_mem_readl_dreg(CS_RAP(s), ret);
- break;
- default:
- ret = s->regs[saddr];
- trace_cs4231_mem_readl_reg(saddr, ret);
- break;
- }
- return ret;
-}
-
-static void cs_mem_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- CSState *s = opaque;
- uint32_t saddr;
-
- saddr = addr >> 2;
- trace_cs4231_mem_writel_reg(saddr, s->regs[saddr], val);
- switch (saddr) {
- case 1:
- trace_cs4231_mem_writel_dreg(CS_RAP(s), s->dregs[CS_RAP(s)], val);
- switch(CS_RAP(s)) {
- case 11:
- case 25: // Read only
- break;
- case 12:
- val &= 0x40;
- val |= CS_CDC_VER; // Codec version
- s->dregs[CS_RAP(s)] = val;
- break;
- default:
- s->dregs[CS_RAP(s)] = val;
- break;
- }
- break;
- case 2: // Read only
- break;
- case 4:
- if (val & 1) {
- cs_reset(DEVICE(s));
- }
- val &= 0x7f;
- s->regs[saddr] = val;
- break;
- default:
- s->regs[saddr] = val;
- break;
- }
-}
-
-static const MemoryRegionOps cs_mem_ops = {
- .read = cs_mem_read,
- .write = cs_mem_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_cs4231 = {
- .name ="cs4231",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, CSState, CS_REGS),
- VMSTATE_UINT8_ARRAY(dregs, CSState, CS_DREGS),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static int cs4231_init1(SysBusDevice *dev)
-{
- CSState *s = CS4231(dev);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &cs_mem_ops, s, "cs4321",
- CS_SIZE);
- sysbus_init_mmio(dev, &s->iomem);
- sysbus_init_irq(dev, &s->irq);
-
- return 0;
-}
-
-static Property cs4231_properties[] = {
- {.name = NULL},
-};
-
-static void cs4231_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = cs4231_init1;
- dc->reset = cs_reset;
- dc->vmsd = &vmstate_cs4231;
- dc->props = cs4231_properties;
-}
-
-static const TypeInfo cs4231_info = {
- .name = TYPE_CS4231,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(CSState),
- .class_init = cs4231_class_init,
-};
-
-static void cs4231_register_types(void)
-{
- type_register_static(&cs4231_info);
-}
-
-type_init(cs4231_register_types)
diff --git a/qemu/hw/audio/cs4231a.c b/qemu/hw/audio/cs4231a.c
deleted file mode 100644
index 3ecd0582b..000000000
--- a/qemu/hw/audio/cs4231a.c
+++ /dev/null
@@ -1,715 +0,0 @@
-/*
- * QEMU Crystal CS4231 audio chip emulation
- *
- * Copyright (c) 2006 Fabrice Bellard
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/audio/audio.h"
-#include "audio/audio.h"
-#include "hw/isa/isa.h"
-#include "hw/qdev.h"
-#include "qemu/timer.h"
-
-/*
- Missing features:
- ADC
- Loopback
- Timer
- ADPCM
- More...
-*/
-
-/* #define DEBUG */
-/* #define DEBUG_XLAW */
-
-static struct {
- int aci_counter;
-} conf = {1};
-
-#ifdef DEBUG
-#define dolog(...) AUD_log ("cs4231a", __VA_ARGS__)
-#else
-#define dolog(...)
-#endif
-
-#define lwarn(...) AUD_log ("cs4231a", "warning: " __VA_ARGS__)
-#define lerr(...) AUD_log ("cs4231a", "error: " __VA_ARGS__)
-
-#define CS_REGS 16
-#define CS_DREGS 32
-
-#define TYPE_CS4231A "cs4231a"
-#define CS4231A(obj) OBJECT_CHECK (CSState, (obj), TYPE_CS4231A)
-
-typedef struct CSState {
- ISADevice dev;
- QEMUSoundCard card;
- MemoryRegion ioports;
- qemu_irq pic;
- uint32_t regs[CS_REGS];
- uint8_t dregs[CS_DREGS];
- uint32_t irq;
- uint32_t dma;
- uint32_t port;
- IsaDma *isa_dma;
- int shift;
- int dma_running;
- int audio_free;
- int transferred;
- int aci_counter;
- SWVoiceOut *voice;
- int16_t *tab;
-} CSState;
-
-#define MODE2 (1 << 6)
-#define MCE (1 << 6)
-#define PMCE (1 << 4)
-#define CMCE (1 << 5)
-#define TE (1 << 6)
-#define PEN (1 << 0)
-#define INT (1 << 0)
-#define IEN (1 << 1)
-#define PPIO (1 << 6)
-#define PI (1 << 4)
-#define CI (1 << 5)
-#define TI (1 << 6)
-
-enum {
- Index_Address,
- Index_Data,
- Status,
- PIO_Data
-};
-
-enum {
- Left_ADC_Input_Control,
- Right_ADC_Input_Control,
- Left_AUX1_Input_Control,
- Right_AUX1_Input_Control,
- Left_AUX2_Input_Control,
- Right_AUX2_Input_Control,
- Left_DAC_Output_Control,
- Right_DAC_Output_Control,
- FS_And_Playback_Data_Format,
- Interface_Configuration,
- Pin_Control,
- Error_Status_And_Initialization,
- MODE_And_ID,
- Loopback_Control,
- Playback_Upper_Base_Count,
- Playback_Lower_Base_Count,
- Alternate_Feature_Enable_I,
- Alternate_Feature_Enable_II,
- Left_Line_Input_Control,
- Right_Line_Input_Control,
- Timer_Low_Base,
- Timer_High_Base,
- RESERVED,
- Alternate_Feature_Enable_III,
- Alternate_Feature_Status,
- Version_Chip_ID,
- Mono_Input_And_Output_Control,
- RESERVED_2,
- Capture_Data_Format,
- RESERVED_3,
- Capture_Upper_Base_Count,
- Capture_Lower_Base_Count
-};
-
-static int freqs[2][8] = {
- { 8000, 16000, 27420, 32000, -1, -1, 48000, 9000 },
- { 5510, 11025, 18900, 22050, 37800, 44100, 33075, 6620 }
-};
-
-/* Tables courtesy http://hazelware.luggle.com/tutorials/mulawcompression.html */
-static int16_t MuLawDecompressTable[256] =
-{
- -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956,
- -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764,
- -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412,
- -11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316,
- -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
- -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
- -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
- -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
- -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
- -1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
- -876, -844, -812, -780, -748, -716, -684, -652,
- -620, -588, -556, -524, -492, -460, -428, -396,
- -372, -356, -340, -324, -308, -292, -276, -260,
- -244, -228, -212, -196, -180, -164, -148, -132,
- -120, -112, -104, -96, -88, -80, -72, -64,
- -56, -48, -40, -32, -24, -16, -8, 0,
- 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
- 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
- 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
- 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316,
- 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140,
- 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092,
- 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004,
- 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980,
- 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436,
- 1372, 1308, 1244, 1180, 1116, 1052, 988, 924,
- 876, 844, 812, 780, 748, 716, 684, 652,
- 620, 588, 556, 524, 492, 460, 428, 396,
- 372, 356, 340, 324, 308, 292, 276, 260,
- 244, 228, 212, 196, 180, 164, 148, 132,
- 120, 112, 104, 96, 88, 80, 72, 64,
- 56, 48, 40, 32, 24, 16, 8, 0
-};
-
-static int16_t ALawDecompressTable[256] =
-{
- -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
- -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
- -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
- -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
- -22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944,
- -30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136,
- -11008,-10496,-12032,-11520,-8960, -8448, -9984, -9472,
- -15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568,
- -344, -328, -376, -360, -280, -264, -312, -296,
- -472, -456, -504, -488, -408, -392, -440, -424,
- -88, -72, -120, -104, -24, -8, -56, -40,
- -216, -200, -248, -232, -152, -136, -184, -168,
- -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
- -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
- -688, -656, -752, -720, -560, -528, -624, -592,
- -944, -912, -1008, -976, -816, -784, -880, -848,
- 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736,
- 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784,
- 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368,
- 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392,
- 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
- 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
- 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472,
- 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
- 344, 328, 376, 360, 280, 264, 312, 296,
- 472, 456, 504, 488, 408, 392, 440, 424,
- 88, 72, 120, 104, 24, 8, 56, 40,
- 216, 200, 248, 232, 152, 136, 184, 168,
- 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184,
- 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696,
- 688, 656, 752, 720, 560, 528, 624, 592,
- 944, 912, 1008, 976, 816, 784, 880, 848
-};
-
-static void cs4231a_reset (DeviceState *dev)
-{
- CSState *s = CS4231A (dev);
-
- s->regs[Index_Address] = 0x40;
- s->regs[Index_Data] = 0x00;
- s->regs[Status] = 0x00;
- s->regs[PIO_Data] = 0x00;
-
- s->dregs[Left_ADC_Input_Control] = 0x00;
- s->dregs[Right_ADC_Input_Control] = 0x00;
- s->dregs[Left_AUX1_Input_Control] = 0x88;
- s->dregs[Right_AUX1_Input_Control] = 0x88;
- s->dregs[Left_AUX2_Input_Control] = 0x88;
- s->dregs[Right_AUX2_Input_Control] = 0x88;
- s->dregs[Left_DAC_Output_Control] = 0x80;
- s->dregs[Right_DAC_Output_Control] = 0x80;
- s->dregs[FS_And_Playback_Data_Format] = 0x00;
- s->dregs[Interface_Configuration] = 0x08;
- s->dregs[Pin_Control] = 0x00;
- s->dregs[Error_Status_And_Initialization] = 0x00;
- s->dregs[MODE_And_ID] = 0x8a;
- s->dregs[Loopback_Control] = 0x00;
- s->dregs[Playback_Upper_Base_Count] = 0x00;
- s->dregs[Playback_Lower_Base_Count] = 0x00;
- s->dregs[Alternate_Feature_Enable_I] = 0x00;
- s->dregs[Alternate_Feature_Enable_II] = 0x00;
- s->dregs[Left_Line_Input_Control] = 0x88;
- s->dregs[Right_Line_Input_Control] = 0x88;
- s->dregs[Timer_Low_Base] = 0x00;
- s->dregs[Timer_High_Base] = 0x00;
- s->dregs[RESERVED] = 0x00;
- s->dregs[Alternate_Feature_Enable_III] = 0x00;
- s->dregs[Alternate_Feature_Status] = 0x00;
- s->dregs[Version_Chip_ID] = 0xa0;
- s->dregs[Mono_Input_And_Output_Control] = 0xa0;
- s->dregs[RESERVED_2] = 0x00;
- s->dregs[Capture_Data_Format] = 0x00;
- s->dregs[RESERVED_3] = 0x00;
- s->dregs[Capture_Upper_Base_Count] = 0x00;
- s->dregs[Capture_Lower_Base_Count] = 0x00;
-}
-
-static void cs_audio_callback (void *opaque, int free)
-{
- CSState *s = opaque;
- s->audio_free = free;
-}
-
-static void cs_reset_voices (CSState *s, uint32_t val)
-{
- int xtal;
- struct audsettings as;
- IsaDmaClass *k = ISADMA_GET_CLASS(s->isa_dma);
-
-#ifdef DEBUG_XLAW
- if (val == 0 || val == 32)
- val = (1 << 4) | (1 << 5);
-#endif
-
- xtal = val & 1;
- as.freq = freqs[xtal][(val >> 1) & 7];
-
- if (as.freq == -1) {
- lerr ("unsupported frequency (val=%#x)\n", val);
- goto error;
- }
-
- as.nchannels = (val & (1 << 4)) ? 2 : 1;
- as.endianness = 0;
- s->tab = NULL;
-
- switch ((val >> 5) & ((s->dregs[MODE_And_ID] & MODE2) ? 7 : 3)) {
- case 0:
- as.fmt = AUD_FMT_U8;
- s->shift = as.nchannels == 2;
- break;
-
- case 1:
- s->tab = MuLawDecompressTable;
- goto x_law;
- case 3:
- s->tab = ALawDecompressTable;
- x_law:
- as.fmt = AUD_FMT_S16;
- as.endianness = AUDIO_HOST_ENDIANNESS;
- s->shift = as.nchannels == 2;
- break;
-
- case 6:
- as.endianness = 1;
- case 2:
- as.fmt = AUD_FMT_S16;
- s->shift = as.nchannels;
- break;
-
- case 7:
- case 4:
- lerr ("attempt to use reserved format value (%#x)\n", val);
- goto error;
-
- case 5:
- lerr ("ADPCM 4 bit IMA compatible format is not supported\n");
- goto error;
- }
-
- s->voice = AUD_open_out (
- &s->card,
- s->voice,
- "cs4231a",
- s,
- cs_audio_callback,
- &as
- );
-
- if (s->dregs[Interface_Configuration] & PEN) {
- if (!s->dma_running) {
- k->hold_DREQ(s->isa_dma, s->dma);
- AUD_set_active_out (s->voice, 1);
- s->transferred = 0;
- }
- s->dma_running = 1;
- }
- else {
- if (s->dma_running) {
- k->release_DREQ(s->isa_dma, s->dma);
- AUD_set_active_out (s->voice, 0);
- }
- s->dma_running = 0;
- }
- return;
-
- error:
- if (s->dma_running) {
- k->release_DREQ(s->isa_dma, s->dma);
- AUD_set_active_out (s->voice, 0);
- }
-}
-
-static uint64_t cs_read (void *opaque, hwaddr addr, unsigned size)
-{
- CSState *s = opaque;
- uint32_t saddr, iaddr, ret;
-
- saddr = addr;
- iaddr = ~0U;
-
- switch (saddr) {
- case Index_Address:
- ret = s->regs[saddr] & ~0x80;
- break;
-
- case Index_Data:
- if (!(s->dregs[MODE_And_ID] & MODE2))
- iaddr = s->regs[Index_Address] & 0x0f;
- else
- iaddr = s->regs[Index_Address] & 0x1f;
-
- ret = s->dregs[iaddr];
- if (iaddr == Error_Status_And_Initialization) {
- /* keep SEAL happy */
- if (s->aci_counter) {
- ret |= 1 << 5;
- s->aci_counter -= 1;
- }
- }
- break;
-
- default:
- ret = s->regs[saddr];
- break;
- }
- dolog ("read %d:%d -> %d\n", saddr, iaddr, ret);
- return ret;
-}
-
-static void cs_write (void *opaque, hwaddr addr,
- uint64_t val64, unsigned size)
-{
- CSState *s = opaque;
- uint32_t saddr, iaddr, val;
-
- saddr = addr;
- val = val64;
-
- switch (saddr) {
- case Index_Address:
- if (!(s->regs[Index_Address] & MCE) && (val & MCE)
- && (s->dregs[Interface_Configuration] & (3 << 3)))
- s->aci_counter = conf.aci_counter;
-
- s->regs[Index_Address] = val & ~(1 << 7);
- break;
-
- case Index_Data:
- if (!(s->dregs[MODE_And_ID] & MODE2))
- iaddr = s->regs[Index_Address] & 0x0f;
- else
- iaddr = s->regs[Index_Address] & 0x1f;
-
- switch (iaddr) {
- case RESERVED:
- case RESERVED_2:
- case RESERVED_3:
- lwarn ("attempt to write %#x to reserved indirect register %d\n",
- val, iaddr);
- break;
-
- case FS_And_Playback_Data_Format:
- if (s->regs[Index_Address] & MCE) {
- cs_reset_voices (s, val);
- }
- else {
- if (s->dregs[Alternate_Feature_Status] & PMCE) {
- val = (val & ~0x0f) | (s->dregs[iaddr] & 0x0f);
- cs_reset_voices (s, val);
- }
- else {
- lwarn ("[P]MCE(%#x, %#x) is not set, val=%#x\n",
- s->regs[Index_Address],
- s->dregs[Alternate_Feature_Status],
- val);
- break;
- }
- }
- s->dregs[iaddr] = val;
- break;
-
- case Interface_Configuration:
- val &= ~(1 << 5); /* D5 is reserved */
- s->dregs[iaddr] = val;
- if (val & PPIO) {
- lwarn ("PIO is not supported (%#x)\n", val);
- break;
- }
- if (val & PEN) {
- if (!s->dma_running) {
- cs_reset_voices (s, s->dregs[FS_And_Playback_Data_Format]);
- }
- }
- else {
- if (s->dma_running) {
- IsaDmaClass *k = ISADMA_GET_CLASS(s->isa_dma);
- k->release_DREQ(s->isa_dma, s->dma);
- AUD_set_active_out (s->voice, 0);
- s->dma_running = 0;
- }
- }
- break;
-
- case Error_Status_And_Initialization:
- lwarn ("attempt to write to read only register %d\n", iaddr);
- break;
-
- case MODE_And_ID:
- dolog ("val=%#x\n", val);
- if (val & MODE2)
- s->dregs[iaddr] |= MODE2;
- else
- s->dregs[iaddr] &= ~MODE2;
- break;
-
- case Alternate_Feature_Enable_I:
- if (val & TE)
- lerr ("timer is not yet supported\n");
- s->dregs[iaddr] = val;
- break;
-
- case Alternate_Feature_Status:
- if ((s->dregs[iaddr] & PI) && !(val & PI)) {
- /* XXX: TI CI */
- qemu_irq_lower (s->pic);
- s->regs[Status] &= ~INT;
- }
- s->dregs[iaddr] = val;
- break;
-
- case Version_Chip_ID:
- lwarn ("write to Version_Chip_ID register %#x\n", val);
- s->dregs[iaddr] = val;
- break;
-
- default:
- s->dregs[iaddr] = val;
- break;
- }
- dolog ("written value %#x to indirect register %d\n", val, iaddr);
- break;
-
- case Status:
- if (s->regs[Status] & INT) {
- qemu_irq_lower (s->pic);
- }
- s->regs[Status] &= ~INT;
- s->dregs[Alternate_Feature_Status] &= ~(PI | CI | TI);
- break;
-
- case PIO_Data:
- lwarn ("attempt to write value %#x to PIO register\n", val);
- break;
- }
-}
-
-static int cs_write_audio (CSState *s, int nchan, int dma_pos,
- int dma_len, int len)
-{
- int temp, net;
- uint8_t tmpbuf[4096];
- IsaDmaClass *k = ISADMA_GET_CLASS(s->isa_dma);
-
- temp = len;
- net = 0;
-
- while (temp) {
- int left = dma_len - dma_pos;
- int copied;
- size_t to_copy;
-
- to_copy = audio_MIN (temp, left);
- if (to_copy > sizeof (tmpbuf)) {
- to_copy = sizeof (tmpbuf);
- }
-
- copied = k->read_memory(s->isa_dma, nchan, tmpbuf, dma_pos, to_copy);
- if (s->tab) {
- int i;
- int16_t linbuf[4096];
-
- for (i = 0; i < copied; ++i)
- linbuf[i] = s->tab[tmpbuf[i]];
- copied = AUD_write (s->voice, linbuf, copied << 1);
- copied >>= 1;
- }
- else {
- copied = AUD_write (s->voice, tmpbuf, copied);
- }
-
- temp -= copied;
- dma_pos = (dma_pos + copied) % dma_len;
- net += copied;
-
- if (!copied) {
- break;
- }
- }
-
- return net;
-}
-
-static int cs_dma_read (void *opaque, int nchan, int dma_pos, int dma_len)
-{
- CSState *s = opaque;
- int copy, written;
- int till = -1;
-
- copy = s->voice ? (s->audio_free >> (s->tab != NULL)) : dma_len;
-
- if (s->dregs[Pin_Control] & IEN) {
- till = (s->dregs[Playback_Lower_Base_Count]
- | (s->dregs[Playback_Upper_Base_Count] << 8)) << s->shift;
- till -= s->transferred;
- copy = audio_MIN (till, copy);
- }
-
- if ((copy <= 0) || (dma_len <= 0)) {
- return dma_pos;
- }
-
- written = cs_write_audio (s, nchan, dma_pos, dma_len, copy);
-
- dma_pos = (dma_pos + written) % dma_len;
- s->audio_free -= (written << (s->tab != NULL));
-
- if (written == till) {
- s->regs[Status] |= INT;
- s->dregs[Alternate_Feature_Status] |= PI;
- s->transferred = 0;
- qemu_irq_raise (s->pic);
- }
- else {
- s->transferred += written;
- }
-
- return dma_pos;
-}
-
-static int cs4231a_pre_load (void *opaque)
-{
- CSState *s = opaque;
-
- if (s->dma_running) {
- IsaDmaClass *k = ISADMA_GET_CLASS(s->isa_dma);
- k->release_DREQ(s->isa_dma, s->dma);
- AUD_set_active_out (s->voice, 0);
- }
- s->dma_running = 0;
- return 0;
-}
-
-static int cs4231a_post_load (void *opaque, int version_id)
-{
- CSState *s = opaque;
-
- if (s->dma_running && (s->dregs[Interface_Configuration] & PEN)) {
- s->dma_running = 0;
- cs_reset_voices (s, s->dregs[FS_And_Playback_Data_Format]);
- }
- return 0;
-}
-
-static const VMStateDescription vmstate_cs4231a = {
- .name = "cs4231a",
- .version_id = 1,
- .minimum_version_id = 1,
- .pre_load = cs4231a_pre_load,
- .post_load = cs4231a_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY (regs, CSState, CS_REGS),
- VMSTATE_BUFFER (dregs, CSState),
- VMSTATE_INT32 (dma_running, CSState),
- VMSTATE_INT32 (audio_free, CSState),
- VMSTATE_INT32 (transferred, CSState),
- VMSTATE_INT32 (aci_counter, CSState),
- VMSTATE_END_OF_LIST ()
- }
-};
-
-static const MemoryRegionOps cs_ioport_ops = {
- .read = cs_read,
- .write = cs_write,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 1,
- }
-};
-
-static void cs4231a_initfn (Object *obj)
-{
- CSState *s = CS4231A (obj);
-
- memory_region_init_io (&s->ioports, OBJECT(s), &cs_ioport_ops, s,
- "cs4231a", 4);
-}
-
-static void cs4231a_realizefn (DeviceState *dev, Error **errp)
-{
- ISADevice *d = ISA_DEVICE (dev);
- CSState *s = CS4231A (dev);
- IsaDmaClass *k;
-
- isa_init_irq (d, &s->pic, s->irq);
- s->isa_dma = isa_get_dma(isa_bus_from_device(d), s->dma);
- k = ISADMA_GET_CLASS(s->isa_dma);
- k->register_channel(s->isa_dma, s->dma, cs_dma_read, s);
-
- isa_register_ioport (d, &s->ioports, s->port);
-
- AUD_register_card ("cs4231a", &s->card);
-}
-
-static int cs4231a_init (ISABus *bus)
-{
- isa_create_simple (bus, TYPE_CS4231A);
- return 0;
-}
-
-static Property cs4231a_properties[] = {
- DEFINE_PROP_UINT32 ("iobase", CSState, port, 0x534),
- DEFINE_PROP_UINT32 ("irq", CSState, irq, 9),
- DEFINE_PROP_UINT32 ("dma", CSState, dma, 3),
- DEFINE_PROP_END_OF_LIST (),
-};
-
-static void cs4231a_class_initfn (ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS (klass);
-
- dc->realize = cs4231a_realizefn;
- dc->reset = cs4231a_reset;
- set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
- dc->desc = "Crystal Semiconductor CS4231A";
- dc->vmsd = &vmstate_cs4231a;
- dc->props = cs4231a_properties;
-}
-
-static const TypeInfo cs4231a_info = {
- .name = TYPE_CS4231A,
- .parent = TYPE_ISA_DEVICE,
- .instance_size = sizeof (CSState),
- .instance_init = cs4231a_initfn,
- .class_init = cs4231a_class_initfn,
-};
-
-static void cs4231a_register_types (void)
-{
- type_register_static (&cs4231a_info);
- isa_register_soundhw("cs4231a", "CS4231A", cs4231a_init);
-}
-
-type_init (cs4231a_register_types)
diff --git a/qemu/hw/audio/es1370.c b/qemu/hw/audio/es1370.c
deleted file mode 100644
index 8449b5f43..000000000
--- a/qemu/hw/audio/es1370.c
+++ /dev/null
@@ -1,1080 +0,0 @@
-/*
- * QEMU ES1370 emulation
- *
- * Copyright (c) 2005 Vassili Karpov (malc)
- *
- * 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.
- */
-
-/* #define DEBUG_ES1370 */
-/* #define VERBOSE_ES1370 */
-#define SILENT_ES1370
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/audio/audio.h"
-#include "audio/audio.h"
-#include "hw/pci/pci.h"
-#include "sysemu/dma.h"
-
-/* Missing stuff:
- SCTRL_P[12](END|ST)INC
- SCTRL_P1SCTRLD
- SCTRL_P2DACSEN
- CTRL_DAC_SYNC
- MIDI
- non looped mode
- surely more
-*/
-
-/*
- Following macros and samplerate array were copied verbatim from
- Linux kernel 2.4.30: drivers/sound/es1370.c
-
- Copyright (C) 1998-2001, 2003 Thomas Sailer (t.sailer@alumni.ethz.ch)
-*/
-
-/* Start blatant GPL violation */
-
-#define ES1370_REG_CONTROL 0x00
-#define ES1370_REG_STATUS 0x04
-#define ES1370_REG_UART_DATA 0x08
-#define ES1370_REG_UART_STATUS 0x09
-#define ES1370_REG_UART_CONTROL 0x09
-#define ES1370_REG_UART_TEST 0x0a
-#define ES1370_REG_MEMPAGE 0x0c
-#define ES1370_REG_CODEC 0x10
-#define ES1370_REG_SERIAL_CONTROL 0x20
-#define ES1370_REG_DAC1_SCOUNT 0x24
-#define ES1370_REG_DAC2_SCOUNT 0x28
-#define ES1370_REG_ADC_SCOUNT 0x2c
-
-#define ES1370_REG_DAC1_FRAMEADR 0xc30
-#define ES1370_REG_DAC1_FRAMECNT 0xc34
-#define ES1370_REG_DAC2_FRAMEADR 0xc38
-#define ES1370_REG_DAC2_FRAMECNT 0xc3c
-#define ES1370_REG_ADC_FRAMEADR 0xd30
-#define ES1370_REG_ADC_FRAMECNT 0xd34
-#define ES1370_REG_PHANTOM_FRAMEADR 0xd38
-#define ES1370_REG_PHANTOM_FRAMECNT 0xd3c
-
-static const unsigned dac1_samplerate[] = { 5512, 11025, 22050, 44100 };
-
-#define DAC2_SRTODIV(x) (((1411200+(x)/2)/(x))-2)
-#define DAC2_DIVTOSR(x) (1411200/((x)+2))
-
-#define CTRL_ADC_STOP 0x80000000 /* 1 = ADC stopped */
-#define CTRL_XCTL1 0x40000000 /* electret mic bias */
-#define CTRL_OPEN 0x20000000 /* no function, can be read and written */
-#define CTRL_PCLKDIV 0x1fff0000 /* ADC/DAC2 clock divider */
-#define CTRL_SH_PCLKDIV 16
-#define CTRL_MSFMTSEL 0x00008000 /* MPEG serial data fmt: 0 = Sony, 1 = I2S */
-#define CTRL_M_SBB 0x00004000 /* DAC2 clock: 0 = PCLKDIV, 1 = MPEG */
-#define CTRL_WTSRSEL 0x00003000 /* DAC1 clock freq: 0=5512, 1=11025, 2=22050, 3=44100 */
-#define CTRL_SH_WTSRSEL 12
-#define CTRL_DAC_SYNC 0x00000800 /* 1 = DAC2 runs off DAC1 clock */
-#define CTRL_CCB_INTRM 0x00000400 /* 1 = CCB "voice" ints enabled */
-#define CTRL_M_CB 0x00000200 /* recording source: 0 = ADC, 1 = MPEG */
-#define CTRL_XCTL0 0x00000100 /* 0 = Line in, 1 = Line out */
-#define CTRL_BREQ 0x00000080 /* 1 = test mode (internal mem test) */
-#define CTRL_DAC1_EN 0x00000040 /* enable DAC1 */
-#define CTRL_DAC2_EN 0x00000020 /* enable DAC2 */
-#define CTRL_ADC_EN 0x00000010 /* enable ADC */
-#define CTRL_UART_EN 0x00000008 /* enable MIDI uart */
-#define CTRL_JYSTK_EN 0x00000004 /* enable Joystick port (presumably at address 0x200) */
-#define CTRL_CDC_EN 0x00000002 /* enable serial (CODEC) interface */
-#define CTRL_SERR_DIS 0x00000001 /* 1 = disable PCI SERR signal */
-
-#define STAT_INTR 0x80000000 /* wired or of all interrupt bits */
-#define STAT_CSTAT 0x00000400 /* 1 = codec busy or codec write in progress */
-#define STAT_CBUSY 0x00000200 /* 1 = codec busy */
-#define STAT_CWRIP 0x00000100 /* 1 = codec write in progress */
-#define STAT_VC 0x00000060 /* CCB int source, 0=DAC1, 1=DAC2, 2=ADC, 3=undef */
-#define STAT_SH_VC 5
-#define STAT_MCCB 0x00000010 /* CCB int pending */
-#define STAT_UART 0x00000008 /* UART int pending */
-#define STAT_DAC1 0x00000004 /* DAC1 int pending */
-#define STAT_DAC2 0x00000002 /* DAC2 int pending */
-#define STAT_ADC 0x00000001 /* ADC int pending */
-
-#define USTAT_RXINT 0x80 /* UART rx int pending */
-#define USTAT_TXINT 0x04 /* UART tx int pending */
-#define USTAT_TXRDY 0x02 /* UART tx ready */
-#define USTAT_RXRDY 0x01 /* UART rx ready */
-
-#define UCTRL_RXINTEN 0x80 /* 1 = enable RX ints */
-#define UCTRL_TXINTEN 0x60 /* TX int enable field mask */
-#define UCTRL_ENA_TXINT 0x20 /* enable TX int */
-#define UCTRL_CNTRL 0x03 /* control field */
-#define UCTRL_CNTRL_SWR 0x03 /* software reset command */
-
-#define SCTRL_P2ENDINC 0x00380000 /* */
-#define SCTRL_SH_P2ENDINC 19
-#define SCTRL_P2STINC 0x00070000 /* */
-#define SCTRL_SH_P2STINC 16
-#define SCTRL_R1LOOPSEL 0x00008000 /* 0 = loop mode */
-#define SCTRL_P2LOOPSEL 0x00004000 /* 0 = loop mode */
-#define SCTRL_P1LOOPSEL 0x00002000 /* 0 = loop mode */
-#define SCTRL_P2PAUSE 0x00001000 /* 1 = pause mode */
-#define SCTRL_P1PAUSE 0x00000800 /* 1 = pause mode */
-#define SCTRL_R1INTEN 0x00000400 /* enable interrupt */
-#define SCTRL_P2INTEN 0x00000200 /* enable interrupt */
-#define SCTRL_P1INTEN 0x00000100 /* enable interrupt */
-#define SCTRL_P1SCTRLD 0x00000080 /* reload sample count register for DAC1 */
-#define SCTRL_P2DACSEN 0x00000040 /* 1 = DAC2 play back last sample when disabled */
-#define SCTRL_R1SEB 0x00000020 /* 1 = 16bit */
-#define SCTRL_R1SMB 0x00000010 /* 1 = stereo */
-#define SCTRL_R1FMT 0x00000030 /* format mask */
-#define SCTRL_SH_R1FMT 4
-#define SCTRL_P2SEB 0x00000008 /* 1 = 16bit */
-#define SCTRL_P2SMB 0x00000004 /* 1 = stereo */
-#define SCTRL_P2FMT 0x0000000c /* format mask */
-#define SCTRL_SH_P2FMT 2
-#define SCTRL_P1SEB 0x00000002 /* 1 = 16bit */
-#define SCTRL_P1SMB 0x00000001 /* 1 = stereo */
-#define SCTRL_P1FMT 0x00000003 /* format mask */
-#define SCTRL_SH_P1FMT 0
-
-/* End blatant GPL violation */
-
-#define NB_CHANNELS 3
-#define DAC1_CHANNEL 0
-#define DAC2_CHANNEL 1
-#define ADC_CHANNEL 2
-
-static void es1370_dac1_callback (void *opaque, int free);
-static void es1370_dac2_callback (void *opaque, int free);
-static void es1370_adc_callback (void *opaque, int avail);
-
-#ifdef DEBUG_ES1370
-
-#define ldebug(...) AUD_log ("es1370", __VA_ARGS__)
-
-static void print_ctl (uint32_t val)
-{
- char buf[1024];
-
- buf[0] = '\0';
-#define a(n) if (val & CTRL_##n) strcat (buf, " "#n)
- a (ADC_STOP);
- a (XCTL1);
- a (OPEN);
- a (MSFMTSEL);
- a (M_SBB);
- a (DAC_SYNC);
- a (CCB_INTRM);
- a (M_CB);
- a (XCTL0);
- a (BREQ);
- a (DAC1_EN);
- a (DAC2_EN);
- a (ADC_EN);
- a (UART_EN);
- a (JYSTK_EN);
- a (CDC_EN);
- a (SERR_DIS);
-#undef a
- AUD_log ("es1370", "ctl - PCLKDIV %d(DAC2 freq %d), freq %d,%s\n",
- (val & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV,
- DAC2_DIVTOSR ((val & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV),
- dac1_samplerate[(val & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL],
- buf);
-}
-
-static void print_sctl (uint32_t val)
-{
- static const char *fmt_names[] = {"8M", "8S", "16M", "16S"};
- char buf[1024];
-
- buf[0] = '\0';
-
-#define a(n) if (val & SCTRL_##n) strcat (buf, " "#n)
-#define b(n) if (!(val & SCTRL_##n)) strcat (buf, " "#n)
- b (R1LOOPSEL);
- b (P2LOOPSEL);
- b (P1LOOPSEL);
- a (P2PAUSE);
- a (P1PAUSE);
- a (R1INTEN);
- a (P2INTEN);
- a (P1INTEN);
- a (P1SCTRLD);
- a (P2DACSEN);
- if (buf[0]) {
- strcat (buf, "\n ");
- }
- else {
- buf[0] = ' ';
- buf[1] = '\0';
- }
-#undef b
-#undef a
- AUD_log ("es1370",
- "%s"
- "p2_end_inc %d, p2_st_inc %d, r1_fmt %s, p2_fmt %s, p1_fmt %s\n",
- buf,
- (val & SCTRL_P2ENDINC) >> SCTRL_SH_P2ENDINC,
- (val & SCTRL_P2STINC) >> SCTRL_SH_P2STINC,
- fmt_names [(val >> SCTRL_SH_R1FMT) & 3],
- fmt_names [(val >> SCTRL_SH_P2FMT) & 3],
- fmt_names [(val >> SCTRL_SH_P1FMT) & 3]
- );
-}
-#else
-#define ldebug(...)
-#define print_ctl(...)
-#define print_sctl(...)
-#endif
-
-#ifdef VERBOSE_ES1370
-#define dolog(...) AUD_log ("es1370", __VA_ARGS__)
-#else
-#define dolog(...)
-#endif
-
-#ifndef SILENT_ES1370
-#define lwarn(...) AUD_log ("es1370: warning", __VA_ARGS__)
-#else
-#define lwarn(...)
-#endif
-
-struct chan {
- uint32_t shift;
- uint32_t leftover;
- uint32_t scount;
- uint32_t frame_addr;
- uint32_t frame_cnt;
-};
-
-typedef struct ES1370State {
- PCIDevice dev;
- QEMUSoundCard card;
- MemoryRegion io;
- struct chan chan[NB_CHANNELS];
- SWVoiceOut *dac_voice[2];
- SWVoiceIn *adc_voice;
-
- uint32_t ctl;
- uint32_t status;
- uint32_t mempage;
- uint32_t codec;
- uint32_t sctl;
-} ES1370State;
-
-struct chan_bits {
- uint32_t ctl_en;
- uint32_t stat_int;
- uint32_t sctl_pause;
- uint32_t sctl_inten;
- uint32_t sctl_fmt;
- uint32_t sctl_sh_fmt;
- uint32_t sctl_loopsel;
- void (*calc_freq) (ES1370State *s, uint32_t ctl,
- uint32_t *old_freq, uint32_t *new_freq);
-};
-
-#define TYPE_ES1370 "ES1370"
-#define ES1370(obj) \
- OBJECT_CHECK(ES1370State, (obj), TYPE_ES1370)
-
-static void es1370_dac1_calc_freq (ES1370State *s, uint32_t ctl,
- uint32_t *old_freq, uint32_t *new_freq);
-static void es1370_dac2_and_adc_calc_freq (ES1370State *s, uint32_t ctl,
- uint32_t *old_freq,
- uint32_t *new_freq);
-
-static const struct chan_bits es1370_chan_bits[] = {
- {CTRL_DAC1_EN, STAT_DAC1, SCTRL_P1PAUSE, SCTRL_P1INTEN,
- SCTRL_P1FMT, SCTRL_SH_P1FMT, SCTRL_P1LOOPSEL,
- es1370_dac1_calc_freq},
-
- {CTRL_DAC2_EN, STAT_DAC2, SCTRL_P2PAUSE, SCTRL_P2INTEN,
- SCTRL_P2FMT, SCTRL_SH_P2FMT, SCTRL_P2LOOPSEL,
- es1370_dac2_and_adc_calc_freq},
-
- {CTRL_ADC_EN, STAT_ADC, 0, SCTRL_R1INTEN,
- SCTRL_R1FMT, SCTRL_SH_R1FMT, SCTRL_R1LOOPSEL,
- es1370_dac2_and_adc_calc_freq}
-};
-
-static void es1370_update_status (ES1370State *s, uint32_t new_status)
-{
- uint32_t level = new_status & (STAT_DAC1 | STAT_DAC2 | STAT_ADC);
-
- if (level) {
- s->status = new_status | STAT_INTR;
- }
- else {
- s->status = new_status & ~STAT_INTR;
- }
- pci_set_irq(&s->dev, !!level);
-}
-
-static void es1370_reset (ES1370State *s)
-{
- size_t i;
-
- s->ctl = 1;
- s->status = 0x60;
- s->mempage = 0;
- s->codec = 0;
- s->sctl = 0;
-
- for (i = 0; i < NB_CHANNELS; ++i) {
- struct chan *d = &s->chan[i];
- d->scount = 0;
- d->leftover = 0;
- if (i == ADC_CHANNEL) {
- AUD_close_in (&s->card, s->adc_voice);
- s->adc_voice = NULL;
- }
- else {
- AUD_close_out (&s->card, s->dac_voice[i]);
- s->dac_voice[i] = NULL;
- }
- }
- pci_irq_deassert(&s->dev);
-}
-
-static void es1370_maybe_lower_irq (ES1370State *s, uint32_t sctl)
-{
- uint32_t new_status = s->status;
-
- if (!(sctl & SCTRL_P1INTEN) && (s->sctl & SCTRL_P1INTEN)) {
- new_status &= ~STAT_DAC1;
- }
-
- if (!(sctl & SCTRL_P2INTEN) && (s->sctl & SCTRL_P2INTEN)) {
- new_status &= ~STAT_DAC2;
- }
-
- if (!(sctl & SCTRL_R1INTEN) && (s->sctl & SCTRL_R1INTEN)) {
- new_status &= ~STAT_ADC;
- }
-
- if (new_status != s->status) {
- es1370_update_status (s, new_status);
- }
-}
-
-static void es1370_dac1_calc_freq (ES1370State *s, uint32_t ctl,
- uint32_t *old_freq, uint32_t *new_freq)
-
-{
- *old_freq = dac1_samplerate[(s->ctl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL];
- *new_freq = dac1_samplerate[(ctl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL];
-}
-
-static void es1370_dac2_and_adc_calc_freq (ES1370State *s, uint32_t ctl,
- uint32_t *old_freq,
- uint32_t *new_freq)
-
-{
- uint32_t old_pclkdiv, new_pclkdiv;
-
- new_pclkdiv = (ctl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV;
- old_pclkdiv = (s->ctl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV;
- *new_freq = DAC2_DIVTOSR (new_pclkdiv);
- *old_freq = DAC2_DIVTOSR (old_pclkdiv);
-}
-
-static void es1370_update_voices (ES1370State *s, uint32_t ctl, uint32_t sctl)
-{
- size_t i;
- uint32_t old_freq, new_freq, old_fmt, new_fmt;
-
- for (i = 0; i < NB_CHANNELS; ++i) {
- struct chan *d = &s->chan[i];
- const struct chan_bits *b = &es1370_chan_bits[i];
-
- new_fmt = (sctl & b->sctl_fmt) >> b->sctl_sh_fmt;
- old_fmt = (s->sctl & b->sctl_fmt) >> b->sctl_sh_fmt;
-
- b->calc_freq (s, ctl, &old_freq, &new_freq);
-
- if ((old_fmt != new_fmt) || (old_freq != new_freq)) {
- d->shift = (new_fmt & 1) + (new_fmt >> 1);
- ldebug ("channel %zu, freq = %d, nchannels %d, fmt %d, shift %d\n",
- i,
- new_freq,
- 1 << (new_fmt & 1),
- (new_fmt & 2) ? AUD_FMT_S16 : AUD_FMT_U8,
- d->shift);
- if (new_freq) {
- struct audsettings as;
-
- as.freq = new_freq;
- as.nchannels = 1 << (new_fmt & 1);
- as.fmt = (new_fmt & 2) ? AUD_FMT_S16 : AUD_FMT_U8;
- as.endianness = 0;
-
- if (i == ADC_CHANNEL) {
- s->adc_voice =
- AUD_open_in (
- &s->card,
- s->adc_voice,
- "es1370.adc",
- s,
- es1370_adc_callback,
- &as
- );
- }
- else {
- s->dac_voice[i] =
- AUD_open_out (
- &s->card,
- s->dac_voice[i],
- i ? "es1370.dac2" : "es1370.dac1",
- s,
- i ? es1370_dac2_callback : es1370_dac1_callback,
- &as
- );
- }
- }
- }
-
- if (((ctl ^ s->ctl) & b->ctl_en)
- || ((sctl ^ s->sctl) & b->sctl_pause)) {
- int on = (ctl & b->ctl_en) && !(sctl & b->sctl_pause);
-
- if (i == ADC_CHANNEL) {
- AUD_set_active_in (s->adc_voice, on);
- }
- else {
- AUD_set_active_out (s->dac_voice[i], on);
- }
- }
- }
-
- s->ctl = ctl;
- s->sctl = sctl;
-}
-
-static inline uint32_t es1370_fixup (ES1370State *s, uint32_t addr)
-{
- addr &= 0xff;
- if (addr >= 0x30 && addr <= 0x3f)
- addr |= s->mempage << 8;
- return addr;
-}
-
-static void es1370_writeb(void *opaque, uint32_t addr, uint32_t val)
-{
- ES1370State *s = opaque;
- uint32_t shift, mask;
-
- addr = es1370_fixup (s, addr);
-
- switch (addr) {
- case ES1370_REG_CONTROL:
- case ES1370_REG_CONTROL + 1:
- case ES1370_REG_CONTROL + 2:
- case ES1370_REG_CONTROL + 3:
- shift = (addr - ES1370_REG_CONTROL) << 3;
- mask = 0xff << shift;
- val = (s->ctl & ~mask) | ((val & 0xff) << shift);
- es1370_update_voices (s, val, s->sctl);
- print_ctl (val);
- break;
- case ES1370_REG_MEMPAGE:
- s->mempage = val;
- break;
- case ES1370_REG_SERIAL_CONTROL:
- case ES1370_REG_SERIAL_CONTROL + 1:
- case ES1370_REG_SERIAL_CONTROL + 2:
- case ES1370_REG_SERIAL_CONTROL + 3:
- shift = (addr - ES1370_REG_SERIAL_CONTROL) << 3;
- mask = 0xff << shift;
- val = (s->sctl & ~mask) | ((val & 0xff) << shift);
- es1370_maybe_lower_irq (s, val);
- es1370_update_voices (s, s->ctl, val);
- print_sctl (val);
- break;
- default:
- lwarn ("writeb %#x <- %#x\n", addr, val);
- break;
- }
-}
-
-static void es1370_writew(void *opaque, uint32_t addr, uint32_t val)
-{
- ES1370State *s = opaque;
- addr = es1370_fixup (s, addr);
- uint32_t shift, mask;
- struct chan *d = &s->chan[0];
-
- switch (addr) {
- case ES1370_REG_CODEC:
- dolog ("ignored codec write address %#x, data %#x\n",
- (val >> 8) & 0xff, val & 0xff);
- s->codec = val;
- break;
-
- case ES1370_REG_CONTROL:
- case ES1370_REG_CONTROL + 2:
- shift = (addr != ES1370_REG_CONTROL) << 4;
- mask = 0xffff << shift;
- val = (s->ctl & ~mask) | ((val & 0xffff) << shift);
- es1370_update_voices (s, val, s->sctl);
- print_ctl (val);
- break;
-
- case ES1370_REG_ADC_SCOUNT:
- d++;
- case ES1370_REG_DAC2_SCOUNT:
- d++;
- case ES1370_REG_DAC1_SCOUNT:
- d->scount = (d->scount & ~0xffff) | (val & 0xffff);
- break;
-
- default:
- lwarn ("writew %#x <- %#x\n", addr, val);
- break;
- }
-}
-
-static void es1370_writel(void *opaque, uint32_t addr, uint32_t val)
-{
- ES1370State *s = opaque;
- struct chan *d = &s->chan[0];
-
- addr = es1370_fixup (s, addr);
-
- switch (addr) {
- case ES1370_REG_CONTROL:
- es1370_update_voices (s, val, s->sctl);
- print_ctl (val);
- break;
-
- case ES1370_REG_MEMPAGE:
- s->mempage = val & 0xf;
- break;
-
- case ES1370_REG_SERIAL_CONTROL:
- es1370_maybe_lower_irq (s, val);
- es1370_update_voices (s, s->ctl, val);
- print_sctl (val);
- break;
-
- case ES1370_REG_ADC_SCOUNT:
- d++;
- case ES1370_REG_DAC2_SCOUNT:
- d++;
- case ES1370_REG_DAC1_SCOUNT:
- d->scount = (val & 0xffff) | (d->scount & ~0xffff);
- ldebug ("chan %td CURR_SAMP_CT %d, SAMP_CT %d\n",
- d - &s->chan[0], val >> 16, (val & 0xffff));
- break;
-
- case ES1370_REG_ADC_FRAMEADR:
- d++;
- case ES1370_REG_DAC2_FRAMEADR:
- d++;
- case ES1370_REG_DAC1_FRAMEADR:
- d->frame_addr = val;
- ldebug ("chan %td frame address %#x\n", d - &s->chan[0], val);
- break;
-
- case ES1370_REG_PHANTOM_FRAMECNT:
- lwarn ("writing to phantom frame count %#x\n", val);
- break;
- case ES1370_REG_PHANTOM_FRAMEADR:
- lwarn ("writing to phantom frame address %#x\n", val);
- break;
-
- case ES1370_REG_ADC_FRAMECNT:
- d++;
- case ES1370_REG_DAC2_FRAMECNT:
- d++;
- case ES1370_REG_DAC1_FRAMECNT:
- d->frame_cnt = val;
- d->leftover = 0;
- ldebug ("chan %td frame count %d, buffer size %d\n",
- d - &s->chan[0], val >> 16, val & 0xffff);
- break;
-
- default:
- lwarn ("writel %#x <- %#x\n", addr, val);
- break;
- }
-}
-
-static uint32_t es1370_readb(void *opaque, uint32_t addr)
-{
- ES1370State *s = opaque;
- uint32_t val;
-
- addr = es1370_fixup (s, addr);
-
- switch (addr) {
- case 0x1b: /* Legacy */
- lwarn ("Attempt to read from legacy register\n");
- val = 5;
- break;
- case ES1370_REG_MEMPAGE:
- val = s->mempage;
- break;
- case ES1370_REG_CONTROL + 0:
- case ES1370_REG_CONTROL + 1:
- case ES1370_REG_CONTROL + 2:
- case ES1370_REG_CONTROL + 3:
- val = s->ctl >> ((addr - ES1370_REG_CONTROL) << 3);
- break;
- case ES1370_REG_STATUS + 0:
- case ES1370_REG_STATUS + 1:
- case ES1370_REG_STATUS + 2:
- case ES1370_REG_STATUS + 3:
- val = s->status >> ((addr - ES1370_REG_STATUS) << 3);
- break;
- default:
- val = ~0;
- lwarn ("readb %#x -> %#x\n", addr, val);
- break;
- }
- return val;
-}
-
-static uint32_t es1370_readw(void *opaque, uint32_t addr)
-{
- ES1370State *s = opaque;
- struct chan *d = &s->chan[0];
- uint32_t val;
-
- addr = es1370_fixup (s, addr);
-
- switch (addr) {
- case ES1370_REG_ADC_SCOUNT + 2:
- d++;
- case ES1370_REG_DAC2_SCOUNT + 2:
- d++;
- case ES1370_REG_DAC1_SCOUNT + 2:
- val = d->scount >> 16;
- break;
-
- case ES1370_REG_ADC_FRAMECNT:
- d++;
- case ES1370_REG_DAC2_FRAMECNT:
- d++;
- case ES1370_REG_DAC1_FRAMECNT:
- val = d->frame_cnt & 0xffff;
- break;
-
- case ES1370_REG_ADC_FRAMECNT + 2:
- d++;
- case ES1370_REG_DAC2_FRAMECNT + 2:
- d++;
- case ES1370_REG_DAC1_FRAMECNT + 2:
- val = d->frame_cnt >> 16;
- break;
-
- default:
- val = ~0;
- lwarn ("readw %#x -> %#x\n", addr, val);
- break;
- }
-
- return val;
-}
-
-static uint32_t es1370_readl(void *opaque, uint32_t addr)
-{
- ES1370State *s = opaque;
- uint32_t val;
- struct chan *d = &s->chan[0];
-
- addr = es1370_fixup (s, addr);
-
- switch (addr) {
- case ES1370_REG_CONTROL:
- val = s->ctl;
- break;
- case ES1370_REG_STATUS:
- val = s->status;
- break;
- case ES1370_REG_MEMPAGE:
- val = s->mempage;
- break;
- case ES1370_REG_CODEC:
- val = s->codec;
- break;
- case ES1370_REG_SERIAL_CONTROL:
- val = s->sctl;
- break;
-
- case ES1370_REG_ADC_SCOUNT:
- d++;
- case ES1370_REG_DAC2_SCOUNT:
- d++;
- case ES1370_REG_DAC1_SCOUNT:
- val = d->scount;
-#ifdef DEBUG_ES1370
- {
- uint32_t curr_count = d->scount >> 16;
- uint32_t count = d->scount & 0xffff;
-
- curr_count <<= d->shift;
- count <<= d->shift;
- dolog ("read scount curr %d, total %d\n", curr_count, count);
- }
-#endif
- break;
-
- case ES1370_REG_ADC_FRAMECNT:
- d++;
- case ES1370_REG_DAC2_FRAMECNT:
- d++;
- case ES1370_REG_DAC1_FRAMECNT:
- val = d->frame_cnt;
-#ifdef DEBUG_ES1370
- {
- uint32_t size = ((d->frame_cnt & 0xffff) + 1) << 2;
- uint32_t curr = ((d->frame_cnt >> 16) + 1) << 2;
- if (curr > size) {
- dolog ("read framecnt curr %d, size %d %d\n", curr, size,
- curr > size);
- }
- }
-#endif
- break;
-
- case ES1370_REG_ADC_FRAMEADR:
- d++;
- case ES1370_REG_DAC2_FRAMEADR:
- d++;
- case ES1370_REG_DAC1_FRAMEADR:
- val = d->frame_addr;
- break;
-
- case ES1370_REG_PHANTOM_FRAMECNT:
- val = ~0U;
- lwarn ("reading from phantom frame count\n");
- break;
- case ES1370_REG_PHANTOM_FRAMEADR:
- val = ~0U;
- lwarn ("reading from phantom frame address\n");
- break;
-
- default:
- val = ~0U;
- lwarn ("readl %#x -> %#x\n", addr, val);
- break;
- }
- return val;
-}
-
-static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel,
- int max, int *irq)
-{
- uint8_t tmpbuf[4096];
- uint32_t addr = d->frame_addr;
- int sc = d->scount & 0xffff;
- int csc = d->scount >> 16;
- int csc_bytes = (csc + 1) << d->shift;
- int cnt = d->frame_cnt >> 16;
- int size = d->frame_cnt & 0xffff;
- int left = ((size - cnt + 1) << 2) + d->leftover;
- int transferred = 0;
- int temp = audio_MIN (max, audio_MIN (left, csc_bytes));
- int index = d - &s->chan[0];
-
- addr += (cnt << 2) + d->leftover;
-
- if (index == ADC_CHANNEL) {
- while (temp) {
- int acquired, to_copy;
-
- to_copy = audio_MIN ((size_t) temp, sizeof (tmpbuf));
- acquired = AUD_read (s->adc_voice, tmpbuf, to_copy);
- if (!acquired)
- break;
-
- pci_dma_write (&s->dev, addr, tmpbuf, acquired);
-
- temp -= acquired;
- addr += acquired;
- transferred += acquired;
- }
- }
- else {
- SWVoiceOut *voice = s->dac_voice[index];
-
- while (temp) {
- int copied, to_copy;
-
- to_copy = audio_MIN ((size_t) temp, sizeof (tmpbuf));
- pci_dma_read (&s->dev, addr, tmpbuf, to_copy);
- copied = AUD_write (voice, tmpbuf, to_copy);
- if (!copied)
- break;
- temp -= copied;
- addr += copied;
- transferred += copied;
- }
- }
-
- if (csc_bytes == transferred) {
- *irq = 1;
- d->scount = sc | (sc << 16);
- ldebug ("sc = %d, rate = %f\n",
- (sc + 1) << d->shift,
- (sc + 1) / (double) 44100);
- }
- else {
- *irq = 0;
- d->scount = sc | (((csc_bytes - transferred - 1) >> d->shift) << 16);
- }
-
- cnt += (transferred + d->leftover) >> 2;
-
- if (s->sctl & loop_sel) {
- /* Bah, how stupid is that having a 0 represent true value?
- i just spent few hours on this shit */
- AUD_log ("es1370: warning", "non looping mode\n");
- }
- else {
- d->frame_cnt = size;
-
- if ((uint32_t) cnt <= d->frame_cnt)
- d->frame_cnt |= cnt << 16;
- }
-
- d->leftover = (transferred + d->leftover) & 3;
-}
-
-static void es1370_run_channel (ES1370State *s, size_t chan, int free_or_avail)
-{
- uint32_t new_status = s->status;
- int max_bytes, irq;
- struct chan *d = &s->chan[chan];
- const struct chan_bits *b = &es1370_chan_bits[chan];
-
- if (!(s->ctl & b->ctl_en) || (s->sctl & b->sctl_pause)) {
- return;
- }
-
- max_bytes = free_or_avail;
- max_bytes &= ~((1 << d->shift) - 1);
- if (!max_bytes) {
- return;
- }
-
- es1370_transfer_audio (s, d, b->sctl_loopsel, max_bytes, &irq);
-
- if (irq) {
- if (s->sctl & b->sctl_inten) {
- new_status |= b->stat_int;
- }
- }
-
- if (new_status != s->status) {
- es1370_update_status (s, new_status);
- }
-}
-
-static void es1370_dac1_callback (void *opaque, int free)
-{
- ES1370State *s = opaque;
-
- es1370_run_channel (s, DAC1_CHANNEL, free);
-}
-
-static void es1370_dac2_callback (void *opaque, int free)
-{
- ES1370State *s = opaque;
-
- es1370_run_channel (s, DAC2_CHANNEL, free);
-}
-
-static void es1370_adc_callback (void *opaque, int avail)
-{
- ES1370State *s = opaque;
-
- es1370_run_channel (s, ADC_CHANNEL, avail);
-}
-
-static uint64_t es1370_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- switch (size) {
- case 1:
- return es1370_readb(opaque, addr);
- case 2:
- return es1370_readw(opaque, addr);
- case 4:
- return es1370_readl(opaque, addr);
- default:
- return -1;
- }
-}
-
-static void es1370_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned size)
-{
- switch (size) {
- case 1:
- es1370_writeb(opaque, addr, val);
- break;
- case 2:
- es1370_writew(opaque, addr, val);
- break;
- case 4:
- es1370_writel(opaque, addr, val);
- break;
- }
-}
-
-static const MemoryRegionOps es1370_io_ops = {
- .read = es1370_read,
- .write = es1370_write,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 4,
- },
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_es1370_channel = {
- .name = "es1370_channel",
- .version_id = 2,
- .minimum_version_id = 2,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32 (shift, struct chan),
- VMSTATE_UINT32 (leftover, struct chan),
- VMSTATE_UINT32 (scount, struct chan),
- VMSTATE_UINT32 (frame_addr, struct chan),
- VMSTATE_UINT32 (frame_cnt, struct chan),
- VMSTATE_END_OF_LIST ()
- }
-};
-
-static int es1370_post_load (void *opaque, int version_id)
-{
- uint32_t ctl, sctl;
- ES1370State *s = opaque;
- size_t i;
-
- for (i = 0; i < NB_CHANNELS; ++i) {
- if (i == ADC_CHANNEL) {
- if (s->adc_voice) {
- AUD_close_in (&s->card, s->adc_voice);
- s->adc_voice = NULL;
- }
- }
- else {
- if (s->dac_voice[i]) {
- AUD_close_out (&s->card, s->dac_voice[i]);
- s->dac_voice[i] = NULL;
- }
- }
- }
-
- ctl = s->ctl;
- sctl = s->sctl;
- s->ctl = 0;
- s->sctl = 0;
- es1370_update_voices (s, ctl, sctl);
- return 0;
-}
-
-static const VMStateDescription vmstate_es1370 = {
- .name = "es1370",
- .version_id = 2,
- .minimum_version_id = 2,
- .post_load = es1370_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE (dev, ES1370State),
- VMSTATE_STRUCT_ARRAY (chan, ES1370State, NB_CHANNELS, 2,
- vmstate_es1370_channel, struct chan),
- VMSTATE_UINT32 (ctl, ES1370State),
- VMSTATE_UINT32 (status, ES1370State),
- VMSTATE_UINT32 (mempage, ES1370State),
- VMSTATE_UINT32 (codec, ES1370State),
- VMSTATE_UINT32 (sctl, ES1370State),
- VMSTATE_END_OF_LIST ()
- }
-};
-
-static void es1370_on_reset (void *opaque)
-{
- ES1370State *s = opaque;
- es1370_reset (s);
-}
-
-static void es1370_realize(PCIDevice *dev, Error **errp)
-{
- ES1370State *s = ES1370(dev);
- uint8_t *c = s->dev.config;
-
- c[PCI_STATUS + 1] = PCI_STATUS_DEVSEL_SLOW >> 8;
-
-#if 0
- c[PCI_CAPABILITY_LIST] = 0xdc;
- c[PCI_INTERRUPT_LINE] = 10;
- c[0xdc] = 0x00;
-#endif
-
- c[PCI_INTERRUPT_PIN] = 1;
- c[PCI_MIN_GNT] = 0x0c;
- c[PCI_MAX_LAT] = 0x80;
-
- memory_region_init_io (&s->io, OBJECT(s), &es1370_io_ops, s, "es1370", 256);
- pci_register_bar (&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io);
- qemu_register_reset (es1370_on_reset, s);
-
- AUD_register_card ("es1370", &s->card);
- es1370_reset (s);
-}
-
-static int es1370_init (PCIBus *bus)
-{
- pci_create_simple (bus, -1, TYPE_ES1370);
- return 0;
-}
-
-static void es1370_class_init (ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS (klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS (klass);
-
- k->realize = es1370_realize;
- k->vendor_id = PCI_VENDOR_ID_ENSONIQ;
- k->device_id = PCI_DEVICE_ID_ENSONIQ_ES1370;
- k->class_id = PCI_CLASS_MULTIMEDIA_AUDIO;
- k->subsystem_vendor_id = 0x4942;
- k->subsystem_id = 0x4c4c;
- set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
- dc->desc = "ENSONIQ AudioPCI ES1370";
- dc->vmsd = &vmstate_es1370;
-}
-
-static const TypeInfo es1370_info = {
- .name = TYPE_ES1370,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof (ES1370State),
- .class_init = es1370_class_init,
-};
-
-static void es1370_register_types (void)
-{
- type_register_static (&es1370_info);
- pci_register_soundhw("es1370", "ENSONIQ AudioPCI ES1370", es1370_init);
-}
-
-type_init (es1370_register_types)
-
diff --git a/qemu/hw/audio/fmopl.c b/qemu/hw/audio/fmopl.c
deleted file mode 100644
index 731110fe8..000000000
--- a/qemu/hw/audio/fmopl.c
+++ /dev/null
@@ -1,1391 +0,0 @@
-/*
-**
-** File: fmopl.c -- software implementation of FM sound generator
-**
-** Copyright (C) 1999,2000 Tatsuyuki Satoh , MultiArcadeMachineEmurator development
-**
-** Version 0.37a
-**
-*/
-
-/*
- preliminary :
- Problem :
- note:
-*/
-
-/* This version of fmopl.c is a fork of the MAME one, relicensed under the LGPL.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#define HAS_YM3812 1
-
-#include "qemu/osdep.h"
-#include <math.h>
-//#include "driver.h" /* use M.A.M.E. */
-#include "fmopl.h"
-
-#ifndef PI
-#define PI 3.14159265358979323846
-#endif
-
-#ifndef ARRAY_SIZE
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-#endif
-
-/* -------------------- for debug --------------------- */
-/* #define OPL_OUTPUT_LOG */
-#ifdef OPL_OUTPUT_LOG
-static FILE *opl_dbg_fp = NULL;
-static FM_OPL *opl_dbg_opl[16];
-static int opl_dbg_maxchip,opl_dbg_chip;
-#endif
-
-/* -------------------- preliminary define section --------------------- */
-/* attack/decay rate time rate */
-#define OPL_ARRATE 141280 /* RATE 4 = 2826.24ms @ 3.6MHz */
-#define OPL_DRRATE 1956000 /* RATE 4 = 39280.64ms @ 3.6MHz */
-
-#define DELTAT_MIXING_LEVEL (1) /* DELTA-T ADPCM MIXING LEVEL */
-
-#define FREQ_BITS 24 /* frequency turn */
-
-/* counter bits = 20 , octerve 7 */
-#define FREQ_RATE (1<<(FREQ_BITS-20))
-#define TL_BITS (FREQ_BITS+2)
-
-/* final output shift , limit minimum and maximum */
-#define OPL_OUTSB (TL_BITS+3-16) /* OPL output final shift 16bit */
-#define OPL_MAXOUT (0x7fff<<OPL_OUTSB)
-#define OPL_MINOUT (-0x8000<<OPL_OUTSB)
-
-/* -------------------- quality selection --------------------- */
-
-/* sinwave entries */
-/* used static memory = SIN_ENT * 4 (byte) */
-#define SIN_ENT 2048
-
-/* output level entries (envelope,sinwave) */
-/* envelope counter lower bits */
-#define ENV_BITS 16
-/* envelope output entries */
-#define EG_ENT 4096
-/* used dynamic memory = EG_ENT*4*4(byte)or EG_ENT*6*4(byte) */
-/* used static memory = EG_ENT*4 (byte) */
-
-#define EG_OFF ((2*EG_ENT)<<ENV_BITS) /* OFF */
-#define EG_DED EG_OFF
-#define EG_DST (EG_ENT<<ENV_BITS) /* DECAY START */
-#define EG_AED EG_DST
-#define EG_AST 0 /* ATTACK START */
-
-#define EG_STEP (96.0/EG_ENT) /* OPL is 0.1875 dB step */
-
-/* LFO table entries */
-#define VIB_ENT 512
-#define VIB_SHIFT (32-9)
-#define AMS_ENT 512
-#define AMS_SHIFT (32-9)
-
-#define VIB_RATE 256
-
-/* -------------------- local defines , macros --------------------- */
-
-/* register number to channel number , slot offset */
-#define SLOT1 0
-#define SLOT2 1
-
-/* envelope phase */
-#define ENV_MOD_RR 0x00
-#define ENV_MOD_DR 0x01
-#define ENV_MOD_AR 0x02
-
-/* -------------------- tables --------------------- */
-static const int slot_array[32]=
-{
- 0, 2, 4, 1, 3, 5,-1,-1,
- 6, 8,10, 7, 9,11,-1,-1,
- 12,14,16,13,15,17,-1,-1,
- -1,-1,-1,-1,-1,-1,-1,-1
-};
-
-/* key scale level */
-/* table is 3dB/OCT , DV converts this in TL step at 6dB/OCT */
-#define DV (EG_STEP/2)
-static const UINT32 KSL_TABLE[8*16]=
-{
- /* OCT 0 */
- 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
- 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
- 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
- 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
- /* OCT 1 */
- 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
- 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
- 0.000/DV, 0.750/DV, 1.125/DV, 1.500/DV,
- 1.875/DV, 2.250/DV, 2.625/DV, 3.000/DV,
- /* OCT 2 */
- 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
- 0.000/DV, 1.125/DV, 1.875/DV, 2.625/DV,
- 3.000/DV, 3.750/DV, 4.125/DV, 4.500/DV,
- 4.875/DV, 5.250/DV, 5.625/DV, 6.000/DV,
- /* OCT 3 */
- 0.000/DV, 0.000/DV, 0.000/DV, 1.875/DV,
- 3.000/DV, 4.125/DV, 4.875/DV, 5.625/DV,
- 6.000/DV, 6.750/DV, 7.125/DV, 7.500/DV,
- 7.875/DV, 8.250/DV, 8.625/DV, 9.000/DV,
- /* OCT 4 */
- 0.000/DV, 0.000/DV, 3.000/DV, 4.875/DV,
- 6.000/DV, 7.125/DV, 7.875/DV, 8.625/DV,
- 9.000/DV, 9.750/DV,10.125/DV,10.500/DV,
- 10.875/DV,11.250/DV,11.625/DV,12.000/DV,
- /* OCT 5 */
- 0.000/DV, 3.000/DV, 6.000/DV, 7.875/DV,
- 9.000/DV,10.125/DV,10.875/DV,11.625/DV,
- 12.000/DV,12.750/DV,13.125/DV,13.500/DV,
- 13.875/DV,14.250/DV,14.625/DV,15.000/DV,
- /* OCT 6 */
- 0.000/DV, 6.000/DV, 9.000/DV,10.875/DV,
- 12.000/DV,13.125/DV,13.875/DV,14.625/DV,
- 15.000/DV,15.750/DV,16.125/DV,16.500/DV,
- 16.875/DV,17.250/DV,17.625/DV,18.000/DV,
- /* OCT 7 */
- 0.000/DV, 9.000/DV,12.000/DV,13.875/DV,
- 15.000/DV,16.125/DV,16.875/DV,17.625/DV,
- 18.000/DV,18.750/DV,19.125/DV,19.500/DV,
- 19.875/DV,20.250/DV,20.625/DV,21.000/DV
-};
-#undef DV
-
-/* sustain lebel table (3db per step) */
-/* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/
-#define SC(db) (db*((3/EG_STEP)*(1<<ENV_BITS)))+EG_DST
-static const INT32 SL_TABLE[16]={
- SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7),
- SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31)
-};
-#undef SC
-
-#define TL_MAX (EG_ENT*2) /* limit(tl + ksr + envelope) + sinwave */
-/* TotalLevel : 48 24 12 6 3 1.5 0.75 (dB) */
-/* TL_TABLE[ 0 to TL_MAX ] : plus section */
-/* TL_TABLE[ TL_MAX to TL_MAX+TL_MAX-1 ] : minus section */
-static INT32 *TL_TABLE;
-
-/* pointers to TL_TABLE with sinwave output offset */
-static INT32 **SIN_TABLE;
-
-/* LFO table */
-static INT32 *AMS_TABLE;
-static INT32 *VIB_TABLE;
-
-/* envelope output curve table */
-/* attack + decay + OFF */
-static INT32 ENV_CURVE[2*EG_ENT+1];
-
-/* multiple table */
-#define ML 2
-static const UINT32 MUL_TABLE[16]= {
-/* 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15 */
- 0.50*ML, 1.00*ML, 2.00*ML, 3.00*ML, 4.00*ML, 5.00*ML, 6.00*ML, 7.00*ML,
- 8.00*ML, 9.00*ML,10.00*ML,10.00*ML,12.00*ML,12.00*ML,15.00*ML,15.00*ML
-};
-#undef ML
-
-/* dummy attack / decay rate ( when rate == 0 ) */
-static INT32 RATE_0[16]=
-{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
-
-/* -------------------- static state --------------------- */
-
-/* lock level of common table */
-static int num_lock = 0;
-
-/* work table */
-static void *cur_chip = NULL; /* current chip point */
-/* currenct chip state */
-/* static OPLSAMPLE *bufL,*bufR; */
-static OPL_CH *S_CH;
-static OPL_CH *E_CH;
-static OPL_SLOT *SLOT7_1, *SLOT7_2, *SLOT8_1, *SLOT8_2;
-
-static INT32 outd[1];
-static INT32 ams;
-static INT32 vib;
-static INT32 *ams_table;
-static INT32 *vib_table;
-static INT32 amsIncr;
-static INT32 vibIncr;
-static INT32 feedback2; /* connect for SLOT 2 */
-
-/* log output level */
-#define LOG_ERR 3 /* ERROR */
-#define LOG_WAR 2 /* WARNING */
-#define LOG_INF 1 /* INFORMATION */
-
-//#define LOG_LEVEL LOG_INF
-#define LOG_LEVEL LOG_ERR
-
-//#define LOG(n,x) if( (n)>=LOG_LEVEL ) logerror x
-#define LOG(n,x)
-
-/* --------------------- subroutines --------------------- */
-
-static inline int Limit( int val, int max, int min ) {
- if ( val > max )
- val = max;
- else if ( val < min )
- val = min;
-
- return val;
-}
-
-/* status set and IRQ handling */
-static inline void OPL_STATUS_SET(FM_OPL *OPL,int flag)
-{
- /* set status flag */
- OPL->status |= flag;
- if(!(OPL->status & 0x80))
- {
- if(OPL->status & OPL->statusmask)
- { /* IRQ on */
- OPL->status |= 0x80;
- /* callback user interrupt handler (IRQ is OFF to ON) */
- if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,1);
- }
- }
-}
-
-/* status reset and IRQ handling */
-static inline void OPL_STATUS_RESET(FM_OPL *OPL,int flag)
-{
- /* reset status flag */
- OPL->status &=~flag;
- if((OPL->status & 0x80))
- {
- if (!(OPL->status & OPL->statusmask) )
- {
- OPL->status &= 0x7f;
- /* callback user interrupt handler (IRQ is ON to OFF) */
- if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,0);
- }
- }
-}
-
-/* IRQ mask set */
-static inline void OPL_STATUSMASK_SET(FM_OPL *OPL,int flag)
-{
- OPL->statusmask = flag;
- /* IRQ handling check */
- OPL_STATUS_SET(OPL,0);
- OPL_STATUS_RESET(OPL,0);
-}
-
-/* ----- key on ----- */
-static inline void OPL_KEYON(OPL_SLOT *SLOT)
-{
- /* sin wave restart */
- SLOT->Cnt = 0;
- /* set attack */
- SLOT->evm = ENV_MOD_AR;
- SLOT->evs = SLOT->evsa;
- SLOT->evc = EG_AST;
- SLOT->eve = EG_AED;
-}
-/* ----- key off ----- */
-static inline void OPL_KEYOFF(OPL_SLOT *SLOT)
-{
- if( SLOT->evm > ENV_MOD_RR)
- {
- /* set envelope counter from envleope output */
- SLOT->evm = ENV_MOD_RR;
- if( !(SLOT->evc&EG_DST) )
- //SLOT->evc = (ENV_CURVE[SLOT->evc>>ENV_BITS]<<ENV_BITS) + EG_DST;
- SLOT->evc = EG_DST;
- SLOT->eve = EG_DED;
- SLOT->evs = SLOT->evsr;
- }
-}
-
-/* ---------- calcrate Envelope Generator & Phase Generator ---------- */
-/* return : envelope output */
-static inline UINT32 OPL_CALC_SLOT( OPL_SLOT *SLOT )
-{
- /* calcrate envelope generator */
- if( (SLOT->evc+=SLOT->evs) >= SLOT->eve )
- {
- switch( SLOT->evm ){
- case ENV_MOD_AR: /* ATTACK -> DECAY1 */
- /* next DR */
- SLOT->evm = ENV_MOD_DR;
- SLOT->evc = EG_DST;
- SLOT->eve = SLOT->SL;
- SLOT->evs = SLOT->evsd;
- break;
- case ENV_MOD_DR: /* DECAY -> SL or RR */
- SLOT->evc = SLOT->SL;
- SLOT->eve = EG_DED;
- if(SLOT->eg_typ)
- {
- SLOT->evs = 0;
- }
- else
- {
- SLOT->evm = ENV_MOD_RR;
- SLOT->evs = SLOT->evsr;
- }
- break;
- case ENV_MOD_RR: /* RR -> OFF */
- SLOT->evc = EG_OFF;
- SLOT->eve = EG_OFF+1;
- SLOT->evs = 0;
- break;
- }
- }
- /* calcrate envelope */
- return SLOT->TLL+ENV_CURVE[SLOT->evc>>ENV_BITS]+(SLOT->ams ? ams : 0);
-}
-
-/* set algorithm connection */
-static void set_algorithm( OPL_CH *CH)
-{
- INT32 *carrier = &outd[0];
- CH->connect1 = CH->CON ? carrier : &feedback2;
- CH->connect2 = carrier;
-}
-
-/* ---------- frequency counter for operater update ---------- */
-static inline void CALC_FCSLOT(OPL_CH *CH,OPL_SLOT *SLOT)
-{
- int ksr;
-
- /* frequency step counter */
- SLOT->Incr = CH->fc * SLOT->mul;
- ksr = CH->kcode >> SLOT->KSR;
-
- if( SLOT->ksr != ksr )
- {
- SLOT->ksr = ksr;
- /* attack , decay rate recalcration */
- SLOT->evsa = SLOT->AR[ksr];
- SLOT->evsd = SLOT->DR[ksr];
- SLOT->evsr = SLOT->RR[ksr];
- }
- SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl);
-}
-
-/* set multi,am,vib,EG-TYP,KSR,mul */
-static inline void set_mul(FM_OPL *OPL,int slot,int v)
-{
- OPL_CH *CH = &OPL->P_CH[slot/2];
- OPL_SLOT *SLOT = &CH->SLOT[slot&1];
-
- SLOT->mul = MUL_TABLE[v&0x0f];
- SLOT->KSR = (v&0x10) ? 0 : 2;
- SLOT->eg_typ = (v&0x20)>>5;
- SLOT->vib = (v&0x40);
- SLOT->ams = (v&0x80);
- CALC_FCSLOT(CH,SLOT);
-}
-
-/* set ksl & tl */
-static inline void set_ksl_tl(FM_OPL *OPL,int slot,int v)
-{
- OPL_CH *CH = &OPL->P_CH[slot/2];
- OPL_SLOT *SLOT = &CH->SLOT[slot&1];
- int ksl = v>>6; /* 0 / 1.5 / 3 / 6 db/OCT */
-
- SLOT->ksl = ksl ? 3-ksl : 31;
- SLOT->TL = (v&0x3f)*(0.75/EG_STEP); /* 0.75db step */
-
- if( !(OPL->mode&0x80) )
- { /* not CSM latch total level */
- SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl);
- }
-}
-
-/* set attack rate & decay rate */
-static inline void set_ar_dr(FM_OPL *OPL,int slot,int v)
-{
- OPL_CH *CH = &OPL->P_CH[slot/2];
- OPL_SLOT *SLOT = &CH->SLOT[slot&1];
- int ar = v>>4;
- int dr = v&0x0f;
-
- SLOT->AR = ar ? &OPL->AR_TABLE[ar<<2] : RATE_0;
- SLOT->evsa = SLOT->AR[SLOT->ksr];
- if( SLOT->evm == ENV_MOD_AR ) SLOT->evs = SLOT->evsa;
-
- SLOT->DR = dr ? &OPL->DR_TABLE[dr<<2] : RATE_0;
- SLOT->evsd = SLOT->DR[SLOT->ksr];
- if( SLOT->evm == ENV_MOD_DR ) SLOT->evs = SLOT->evsd;
-}
-
-/* set sustain level & release rate */
-static inline void set_sl_rr(FM_OPL *OPL,int slot,int v)
-{
- OPL_CH *CH = &OPL->P_CH[slot/2];
- OPL_SLOT *SLOT = &CH->SLOT[slot&1];
- int sl = v>>4;
- int rr = v & 0x0f;
-
- SLOT->SL = SL_TABLE[sl];
- if( SLOT->evm == ENV_MOD_DR ) SLOT->eve = SLOT->SL;
- SLOT->RR = &OPL->DR_TABLE[rr<<2];
- SLOT->evsr = SLOT->RR[SLOT->ksr];
- if( SLOT->evm == ENV_MOD_RR ) SLOT->evs = SLOT->evsr;
-}
-
-/* operator output calcrator */
-#define OP_OUT(slot,env,con) slot->wavetable[((slot->Cnt+con)/(0x1000000/SIN_ENT))&(SIN_ENT-1)][env]
-/* ---------- calcrate one of channel ---------- */
-static inline void OPL_CALC_CH( OPL_CH *CH )
-{
- UINT32 env_out;
- OPL_SLOT *SLOT;
-
- feedback2 = 0;
- /* SLOT 1 */
- SLOT = &CH->SLOT[SLOT1];
- env_out=OPL_CALC_SLOT(SLOT);
- if( env_out < EG_ENT-1 )
- {
- /* PG */
- if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE);
- else SLOT->Cnt += SLOT->Incr;
- /* connectoion */
- if(CH->FB)
- {
- int feedback1 = (CH->op1_out[0]+CH->op1_out[1])>>CH->FB;
- CH->op1_out[1] = CH->op1_out[0];
- *CH->connect1 += CH->op1_out[0] = OP_OUT(SLOT,env_out,feedback1);
- }
- else
- {
- *CH->connect1 += OP_OUT(SLOT,env_out,0);
- }
- }else
- {
- CH->op1_out[1] = CH->op1_out[0];
- CH->op1_out[0] = 0;
- }
- /* SLOT 2 */
- SLOT = &CH->SLOT[SLOT2];
- env_out=OPL_CALC_SLOT(SLOT);
- if( env_out < EG_ENT-1 )
- {
- /* PG */
- if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE);
- else SLOT->Cnt += SLOT->Incr;
- /* connectoion */
- outd[0] += OP_OUT(SLOT,env_out, feedback2);
- }
-}
-
-/* ---------- calcrate rhythm block ---------- */
-#define WHITE_NOISE_db 6.0
-static inline void OPL_CALC_RH( OPL_CH *CH )
-{
- UINT32 env_tam,env_sd,env_top,env_hh;
- int whitenoise = (rand()&1)*(WHITE_NOISE_db/EG_STEP);
- INT32 tone8;
-
- OPL_SLOT *SLOT;
- int env_out;
-
- /* BD : same as FM serial mode and output level is large */
- feedback2 = 0;
- /* SLOT 1 */
- SLOT = &CH[6].SLOT[SLOT1];
- env_out=OPL_CALC_SLOT(SLOT);
- if( env_out < EG_ENT-1 )
- {
- /* PG */
- if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE);
- else SLOT->Cnt += SLOT->Incr;
- /* connectoion */
- if(CH[6].FB)
- {
- int feedback1 = (CH[6].op1_out[0]+CH[6].op1_out[1])>>CH[6].FB;
- CH[6].op1_out[1] = CH[6].op1_out[0];
- feedback2 = CH[6].op1_out[0] = OP_OUT(SLOT,env_out,feedback1);
- }
- else
- {
- feedback2 = OP_OUT(SLOT,env_out,0);
- }
- }else
- {
- feedback2 = 0;
- CH[6].op1_out[1] = CH[6].op1_out[0];
- CH[6].op1_out[0] = 0;
- }
- /* SLOT 2 */
- SLOT = &CH[6].SLOT[SLOT2];
- env_out=OPL_CALC_SLOT(SLOT);
- if( env_out < EG_ENT-1 )
- {
- /* PG */
- if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE);
- else SLOT->Cnt += SLOT->Incr;
- /* connectoion */
- outd[0] += OP_OUT(SLOT,env_out, feedback2)*2;
- }
-
- // SD (17) = mul14[fnum7] + white noise
- // TAM (15) = mul15[fnum8]
- // TOP (18) = fnum6(mul18[fnum8]+whitenoise)
- // HH (14) = fnum7(mul18[fnum8]+whitenoise) + white noise
- env_sd =OPL_CALC_SLOT(SLOT7_2) + whitenoise;
- env_tam=OPL_CALC_SLOT(SLOT8_1);
- env_top=OPL_CALC_SLOT(SLOT8_2);
- env_hh =OPL_CALC_SLOT(SLOT7_1) + whitenoise;
-
- /* PG */
- if(SLOT7_1->vib) SLOT7_1->Cnt += (2*SLOT7_1->Incr*vib/VIB_RATE);
- else SLOT7_1->Cnt += 2*SLOT7_1->Incr;
- if(SLOT7_2->vib) SLOT7_2->Cnt += ((CH[7].fc*8)*vib/VIB_RATE);
- else SLOT7_2->Cnt += (CH[7].fc*8);
- if(SLOT8_1->vib) SLOT8_1->Cnt += (SLOT8_1->Incr*vib/VIB_RATE);
- else SLOT8_1->Cnt += SLOT8_1->Incr;
- if(SLOT8_2->vib) SLOT8_2->Cnt += ((CH[8].fc*48)*vib/VIB_RATE);
- else SLOT8_2->Cnt += (CH[8].fc*48);
-
- tone8 = OP_OUT(SLOT8_2,whitenoise,0 );
-
- /* SD */
- if( env_sd < EG_ENT-1 )
- outd[0] += OP_OUT(SLOT7_1,env_sd, 0)*8;
- /* TAM */
- if( env_tam < EG_ENT-1 )
- outd[0] += OP_OUT(SLOT8_1,env_tam, 0)*2;
- /* TOP-CY */
- if( env_top < EG_ENT-1 )
- outd[0] += OP_OUT(SLOT7_2,env_top,tone8)*2;
- /* HH */
- if( env_hh < EG_ENT-1 )
- outd[0] += OP_OUT(SLOT7_2,env_hh,tone8)*2;
-}
-
-/* ----------- initialize time tabls ----------- */
-static void init_timetables( FM_OPL *OPL , int ARRATE , int DRRATE )
-{
- int i;
- double rate;
-
- /* make attack rate & decay rate tables */
- for (i = 0;i < 4;i++) OPL->AR_TABLE[i] = OPL->DR_TABLE[i] = 0;
- for (i = 4;i <= 60;i++){
- rate = OPL->freqbase; /* frequency rate */
- if( i < 60 ) rate *= 1.0+(i&3)*0.25; /* b0-1 : x1 , x1.25 , x1.5 , x1.75 */
- rate *= 1<<((i>>2)-1); /* b2-5 : shift bit */
- rate *= (double)(EG_ENT<<ENV_BITS);
- OPL->AR_TABLE[i] = rate / ARRATE;
- OPL->DR_TABLE[i] = rate / DRRATE;
- }
- for (i = 60; i < ARRAY_SIZE(OPL->AR_TABLE); i++)
- {
- OPL->AR_TABLE[i] = EG_AED-1;
- OPL->DR_TABLE[i] = OPL->DR_TABLE[60];
- }
-#if 0
- for (i = 0;i < 64 ;i++){ /* make for overflow area */
- LOG(LOG_WAR, ("rate %2d , ar %f ms , dr %f ms\n", i,
- ((double)(EG_ENT<<ENV_BITS) / OPL->AR_TABLE[i]) * (1000.0 / OPL->rate),
- ((double)(EG_ENT<<ENV_BITS) / OPL->DR_TABLE[i]) * (1000.0 / OPL->rate) ));
- }
-#endif
-}
-
-/* ---------- generic table initialize ---------- */
-static int OPLOpenTable( void )
-{
- int s,t;
- double rate;
- int i,j;
- double pom;
-
- /* allocate dynamic tables */
- if( (TL_TABLE = malloc(TL_MAX*2*sizeof(INT32))) == NULL)
- return 0;
- if( (SIN_TABLE = malloc(SIN_ENT*4 *sizeof(INT32 *))) == NULL)
- {
- free(TL_TABLE);
- return 0;
- }
- if( (AMS_TABLE = malloc(AMS_ENT*2 *sizeof(INT32))) == NULL)
- {
- free(TL_TABLE);
- free(SIN_TABLE);
- return 0;
- }
- if( (VIB_TABLE = malloc(VIB_ENT*2 *sizeof(INT32))) == NULL)
- {
- free(TL_TABLE);
- free(SIN_TABLE);
- free(AMS_TABLE);
- return 0;
- }
- /* make total level table */
- for (t = 0;t < EG_ENT-1 ;t++){
- rate = ((1<<TL_BITS)-1)/pow(10,EG_STEP*t/20); /* dB -> voltage */
- TL_TABLE[ t] = (int)rate;
- TL_TABLE[TL_MAX+t] = -TL_TABLE[t];
-/* LOG(LOG_INF,("TotalLevel(%3d) = %x\n",t,TL_TABLE[t]));*/
- }
- /* fill volume off area */
- for ( t = EG_ENT-1; t < TL_MAX ;t++){
- TL_TABLE[t] = TL_TABLE[TL_MAX+t] = 0;
- }
-
- /* make sinwave table (total level offet) */
- /* degree 0 = degree 180 = off */
- SIN_TABLE[0] = SIN_TABLE[SIN_ENT/2] = &TL_TABLE[EG_ENT-1];
- for (s = 1;s <= SIN_ENT/4;s++){
- pom = sin(2*PI*s/SIN_ENT); /* sin */
- pom = 20*log10(1/pom); /* decibel */
- j = pom / EG_STEP; /* TL_TABLE steps */
-
- /* degree 0 - 90 , degree 180 - 90 : plus section */
- SIN_TABLE[ s] = SIN_TABLE[SIN_ENT/2-s] = &TL_TABLE[j];
- /* degree 180 - 270 , degree 360 - 270 : minus section */
- SIN_TABLE[SIN_ENT/2+s] = SIN_TABLE[SIN_ENT -s] = &TL_TABLE[TL_MAX+j];
-/* LOG(LOG_INF,("sin(%3d) = %f:%f db\n",s,pom,(double)j * EG_STEP));*/
- }
- for (s = 0;s < SIN_ENT;s++)
- {
- SIN_TABLE[SIN_ENT*1+s] = s<(SIN_ENT/2) ? SIN_TABLE[s] : &TL_TABLE[EG_ENT];
- SIN_TABLE[SIN_ENT*2+s] = SIN_TABLE[s % (SIN_ENT/2)];
- SIN_TABLE[SIN_ENT*3+s] = (s/(SIN_ENT/4))&1 ? &TL_TABLE[EG_ENT] : SIN_TABLE[SIN_ENT*2+s];
- }
-
- /* envelope counter -> envelope output table */
- for (i=0; i<EG_ENT; i++)
- {
- /* ATTACK curve */
- pom = pow( ((double)(EG_ENT-1-i)/EG_ENT) , 8 ) * EG_ENT;
- /* if( pom >= EG_ENT ) pom = EG_ENT-1; */
- ENV_CURVE[i] = (int)pom;
- /* DECAY ,RELEASE curve */
- ENV_CURVE[(EG_DST>>ENV_BITS)+i]= i;
- }
- /* off */
- ENV_CURVE[EG_OFF>>ENV_BITS]= EG_ENT-1;
- /* make LFO ams table */
- for (i=0; i<AMS_ENT; i++)
- {
- pom = (1.0+sin(2*PI*i/AMS_ENT))/2; /* sin */
- AMS_TABLE[i] = (1.0/EG_STEP)*pom; /* 1dB */
- AMS_TABLE[AMS_ENT+i] = (4.8/EG_STEP)*pom; /* 4.8dB */
- }
- /* make LFO vibrate table */
- for (i=0; i<VIB_ENT; i++)
- {
- /* 100cent = 1seminote = 6% ?? */
- pom = (double)VIB_RATE*0.06*sin(2*PI*i/VIB_ENT); /* +-100sect step */
- VIB_TABLE[i] = VIB_RATE + (pom*0.07); /* +- 7cent */
- VIB_TABLE[VIB_ENT+i] = VIB_RATE + (pom*0.14); /* +-14cent */
- /* LOG(LOG_INF,("vib %d=%d\n",i,VIB_TABLE[VIB_ENT+i])); */
- }
- return 1;
-}
-
-
-static void OPLCloseTable( void )
-{
- free(TL_TABLE);
- free(SIN_TABLE);
- free(AMS_TABLE);
- free(VIB_TABLE);
-}
-
-/* CSM Key Control */
-static inline void CSMKeyControll(OPL_CH *CH)
-{
- OPL_SLOT *slot1 = &CH->SLOT[SLOT1];
- OPL_SLOT *slot2 = &CH->SLOT[SLOT2];
- /* all key off */
- OPL_KEYOFF(slot1);
- OPL_KEYOFF(slot2);
- /* total level latch */
- slot1->TLL = slot1->TL + (CH->ksl_base>>slot1->ksl);
- slot1->TLL = slot1->TL + (CH->ksl_base>>slot1->ksl);
- /* key on */
- CH->op1_out[0] = CH->op1_out[1] = 0;
- OPL_KEYON(slot1);
- OPL_KEYON(slot2);
-}
-
-/* ---------- opl initialize ---------- */
-static void OPL_initialize(FM_OPL *OPL)
-{
- int fn;
-
- /* frequency base */
- OPL->freqbase = (OPL->rate) ? ((double)OPL->clock / OPL->rate) / 72 : 0;
- /* Timer base time */
- OPL->TimerBase = 1.0/((double)OPL->clock / 72.0 );
- /* make time tables */
- init_timetables( OPL , OPL_ARRATE , OPL_DRRATE );
- /* make fnumber -> increment counter table */
- for( fn=0 ; fn < 1024 ; fn++ )
- {
- OPL->FN_TABLE[fn] = OPL->freqbase * fn * FREQ_RATE * (1<<7) / 2;
- }
- /* LFO freq.table */
- OPL->amsIncr = OPL->rate ? (double)AMS_ENT*(1<<AMS_SHIFT) / OPL->rate * 3.7 * ((double)OPL->clock/3600000) : 0;
- OPL->vibIncr = OPL->rate ? (double)VIB_ENT*(1<<VIB_SHIFT) / OPL->rate * 6.4 * ((double)OPL->clock/3600000) : 0;
-}
-
-/* ---------- write a OPL registers ---------- */
-static void OPLWriteReg(FM_OPL *OPL, int r, int v)
-{
- OPL_CH *CH;
- int slot;
- int block_fnum;
-
- switch(r&0xe0)
- {
- case 0x00: /* 00-1f:control */
- switch(r&0x1f)
- {
- case 0x01:
- /* wave selector enable */
- if(OPL->type&OPL_TYPE_WAVESEL)
- {
- OPL->wavesel = v&0x20;
- if(!OPL->wavesel)
- {
- /* preset compatible mode */
- int c;
- for(c=0;c<OPL->max_ch;c++)
- {
- OPL->P_CH[c].SLOT[SLOT1].wavetable = &SIN_TABLE[0];
- OPL->P_CH[c].SLOT[SLOT2].wavetable = &SIN_TABLE[0];
- }
- }
- }
- return;
- case 0x02: /* Timer 1 */
- OPL->T[0] = (256-v)*4;
- break;
- case 0x03: /* Timer 2 */
- OPL->T[1] = (256-v)*16;
- return;
- case 0x04: /* IRQ clear / mask and Timer enable */
- if(v&0x80)
- { /* IRQ flag clear */
- OPL_STATUS_RESET(OPL,0x7f);
- }
- else
- { /* set IRQ mask ,timer enable*/
- UINT8 st1 = v&1;
- UINT8 st2 = (v>>1)&1;
- /* IRQRST,T1MSK,t2MSK,EOSMSK,BRMSK,x,ST2,ST1 */
- OPL_STATUS_RESET(OPL,v&0x78);
- OPL_STATUSMASK_SET(OPL,((~v)&0x78)|0x01);
- /* timer 2 */
- if(OPL->st[1] != st2)
- {
- double interval = st2 ? (double)OPL->T[1]*OPL->TimerBase : 0.0;
- OPL->st[1] = st2;
- if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+1,interval);
- }
- /* timer 1 */
- if(OPL->st[0] != st1)
- {
- double interval = st1 ? (double)OPL->T[0]*OPL->TimerBase : 0.0;
- OPL->st[0] = st1;
- if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+0,interval);
- }
- }
- return;
-#if BUILD_Y8950
- case 0x06: /* Key Board OUT */
- if(OPL->type&OPL_TYPE_KEYBOARD)
- {
- if(OPL->keyboardhandler_w)
- OPL->keyboardhandler_w(OPL->keyboard_param,v);
- else
- LOG(LOG_WAR,("OPL:write unmapped KEYBOARD port\n"));
- }
- return;
- case 0x07: /* DELTA-T control : START,REC,MEMDATA,REPT,SPOFF,x,x,RST */
- if(OPL->type&OPL_TYPE_ADPCM)
- YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v);
- return;
- case 0x08: /* MODE,DELTA-T : CSM,NOTESEL,x,x,smpl,da/ad,64k,rom */
- OPL->mode = v;
- v&=0x1f; /* for DELTA-T unit */
- case 0x09: /* START ADD */
- case 0x0a:
- case 0x0b: /* STOP ADD */
- case 0x0c:
- case 0x0d: /* PRESCALE */
- case 0x0e:
- case 0x0f: /* ADPCM data */
- case 0x10: /* DELTA-N */
- case 0x11: /* DELTA-N */
- case 0x12: /* EG-CTRL */
- if(OPL->type&OPL_TYPE_ADPCM)
- YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v);
- return;
-#if 0
- case 0x15: /* DAC data */
- case 0x16:
- case 0x17: /* SHIFT */
- return;
- case 0x18: /* I/O CTRL (Direction) */
- if(OPL->type&OPL_TYPE_IO)
- OPL->portDirection = v&0x0f;
- return;
- case 0x19: /* I/O DATA */
- if(OPL->type&OPL_TYPE_IO)
- {
- OPL->portLatch = v;
- if(OPL->porthandler_w)
- OPL->porthandler_w(OPL->port_param,v&OPL->portDirection);
- }
- return;
- case 0x1a: /* PCM data */
- return;
-#endif
-#endif
- }
- break;
- case 0x20: /* am,vib,ksr,eg type,mul */
- slot = slot_array[r&0x1f];
- if(slot == -1) return;
- set_mul(OPL,slot,v);
- return;
- case 0x40:
- slot = slot_array[r&0x1f];
- if(slot == -1) return;
- set_ksl_tl(OPL,slot,v);
- return;
- case 0x60:
- slot = slot_array[r&0x1f];
- if(slot == -1) return;
- set_ar_dr(OPL,slot,v);
- return;
- case 0x80:
- slot = slot_array[r&0x1f];
- if(slot == -1) return;
- set_sl_rr(OPL,slot,v);
- return;
- case 0xa0:
- switch(r)
- {
- case 0xbd:
- /* amsep,vibdep,r,bd,sd,tom,tc,hh */
- {
- UINT8 rkey = OPL->rhythm^v;
- OPL->ams_table = &AMS_TABLE[v&0x80 ? AMS_ENT : 0];
- OPL->vib_table = &VIB_TABLE[v&0x40 ? VIB_ENT : 0];
- OPL->rhythm = v&0x3f;
- if(OPL->rhythm&0x20)
- {
-#if 0
- usrintf_showmessage("OPL Rhythm mode select");
-#endif
- /* BD key on/off */
- if(rkey&0x10)
- {
- if(v&0x10)
- {
- OPL->P_CH[6].op1_out[0] = OPL->P_CH[6].op1_out[1] = 0;
- OPL_KEYON(&OPL->P_CH[6].SLOT[SLOT1]);
- OPL_KEYON(&OPL->P_CH[6].SLOT[SLOT2]);
- }
- else
- {
- OPL_KEYOFF(&OPL->P_CH[6].SLOT[SLOT1]);
- OPL_KEYOFF(&OPL->P_CH[6].SLOT[SLOT2]);
- }
- }
- /* SD key on/off */
- if(rkey&0x08)
- {
- if(v&0x08) OPL_KEYON(&OPL->P_CH[7].SLOT[SLOT2]);
- else OPL_KEYOFF(&OPL->P_CH[7].SLOT[SLOT2]);
- }/* TAM key on/off */
- if(rkey&0x04)
- {
- if(v&0x04) OPL_KEYON(&OPL->P_CH[8].SLOT[SLOT1]);
- else OPL_KEYOFF(&OPL->P_CH[8].SLOT[SLOT1]);
- }
- /* TOP-CY key on/off */
- if(rkey&0x02)
- {
- if(v&0x02) OPL_KEYON(&OPL->P_CH[8].SLOT[SLOT2]);
- else OPL_KEYOFF(&OPL->P_CH[8].SLOT[SLOT2]);
- }
- /* HH key on/off */
- if(rkey&0x01)
- {
- if(v&0x01) OPL_KEYON(&OPL->P_CH[7].SLOT[SLOT1]);
- else OPL_KEYOFF(&OPL->P_CH[7].SLOT[SLOT1]);
- }
- }
- }
- return;
- }
- /* keyon,block,fnum */
- if( (r&0x0f) > 8) return;
- CH = &OPL->P_CH[r&0x0f];
- if(!(r&0x10))
- { /* a0-a8 */
- block_fnum = (CH->block_fnum&0x1f00) | v;
- }
- else
- { /* b0-b8 */
- int keyon = (v>>5)&1;
- block_fnum = ((v&0x1f)<<8) | (CH->block_fnum&0xff);
- if(CH->keyon != keyon)
- {
- if( (CH->keyon=keyon) )
- {
- CH->op1_out[0] = CH->op1_out[1] = 0;
- OPL_KEYON(&CH->SLOT[SLOT1]);
- OPL_KEYON(&CH->SLOT[SLOT2]);
- }
- else
- {
- OPL_KEYOFF(&CH->SLOT[SLOT1]);
- OPL_KEYOFF(&CH->SLOT[SLOT2]);
- }
- }
- }
- /* update */
- if(CH->block_fnum != block_fnum)
- {
- int blockRv = 7-(block_fnum>>10);
- int fnum = block_fnum&0x3ff;
- CH->block_fnum = block_fnum;
-
- CH->ksl_base = KSL_TABLE[block_fnum>>6];
- CH->fc = OPL->FN_TABLE[fnum]>>blockRv;
- CH->kcode = CH->block_fnum>>9;
- if( (OPL->mode&0x40) && CH->block_fnum&0x100) CH->kcode |=1;
- CALC_FCSLOT(CH,&CH->SLOT[SLOT1]);
- CALC_FCSLOT(CH,&CH->SLOT[SLOT2]);
- }
- return;
- case 0xc0:
- /* FB,C */
- if( (r&0x0f) > 8) return;
- CH = &OPL->P_CH[r&0x0f];
- {
- int feedback = (v>>1)&7;
- CH->FB = feedback ? (8+1) - feedback : 0;
- CH->CON = v&1;
- set_algorithm(CH);
- }
- return;
- case 0xe0: /* wave type */
- slot = slot_array[r&0x1f];
- if(slot == -1) return;
- CH = &OPL->P_CH[slot/2];
- if(OPL->wavesel)
- {
- /* LOG(LOG_INF,("OPL SLOT %d wave select %d\n",slot,v&3)); */
- CH->SLOT[slot&1].wavetable = &SIN_TABLE[(v&0x03)*SIN_ENT];
- }
- return;
- }
-}
-
-/* lock/unlock for common table */
-static int OPL_LockTable(void)
-{
- num_lock++;
- if(num_lock>1) return 0;
- /* first time */
- cur_chip = NULL;
- /* allocate total level table (128kb space) */
- if( !OPLOpenTable() )
- {
- num_lock--;
- return -1;
- }
- return 0;
-}
-
-static void OPL_UnLockTable(void)
-{
- if(num_lock) num_lock--;
- if(num_lock) return;
- /* last time */
- cur_chip = NULL;
- OPLCloseTable();
-}
-
-#if (BUILD_YM3812 || BUILD_YM3526)
-/*******************************************************************************/
-/* YM3812 local section */
-/*******************************************************************************/
-
-/* ---------- update one of chip ----------- */
-void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length)
-{
- int i;
- int data;
- OPLSAMPLE *buf = buffer;
- UINT32 amsCnt = OPL->amsCnt;
- UINT32 vibCnt = OPL->vibCnt;
- UINT8 rhythm = OPL->rhythm&0x20;
- OPL_CH *CH,*R_CH;
-
- if( (void *)OPL != cur_chip ){
- cur_chip = (void *)OPL;
- /* channel pointers */
- S_CH = OPL->P_CH;
- E_CH = &S_CH[9];
- /* rhythm slot */
- SLOT7_1 = &S_CH[7].SLOT[SLOT1];
- SLOT7_2 = &S_CH[7].SLOT[SLOT2];
- SLOT8_1 = &S_CH[8].SLOT[SLOT1];
- SLOT8_2 = &S_CH[8].SLOT[SLOT2];
- /* LFO state */
- amsIncr = OPL->amsIncr;
- vibIncr = OPL->vibIncr;
- ams_table = OPL->ams_table;
- vib_table = OPL->vib_table;
- }
- R_CH = rhythm ? &S_CH[6] : E_CH;
- for( i=0; i < length ; i++ )
- {
- /* channel A channel B channel C */
- /* LFO */
- ams = ams_table[(amsCnt+=amsIncr)>>AMS_SHIFT];
- vib = vib_table[(vibCnt+=vibIncr)>>VIB_SHIFT];
- outd[0] = 0;
- /* FM part */
- for(CH=S_CH ; CH < R_CH ; CH++)
- OPL_CALC_CH(CH);
- /* Rythn part */
- if(rhythm)
- OPL_CALC_RH(S_CH);
- /* limit check */
- data = Limit( outd[0] , OPL_MAXOUT, OPL_MINOUT );
- /* store to sound buffer */
- buf[i] = data >> OPL_OUTSB;
- }
-
- OPL->amsCnt = amsCnt;
- OPL->vibCnt = vibCnt;
-#ifdef OPL_OUTPUT_LOG
- if(opl_dbg_fp)
- {
- for(opl_dbg_chip=0;opl_dbg_chip<opl_dbg_maxchip;opl_dbg_chip++)
- if( opl_dbg_opl[opl_dbg_chip] == OPL) break;
- fprintf(opl_dbg_fp,"%c%c%c",0x20+opl_dbg_chip,length&0xff,length/256);
- }
-#endif
-}
-#endif /* (BUILD_YM3812 || BUILD_YM3526) */
-
-#if BUILD_Y8950
-
-void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length)
-{
- int i;
- int data;
- OPLSAMPLE *buf = buffer;
- UINT32 amsCnt = OPL->amsCnt;
- UINT32 vibCnt = OPL->vibCnt;
- UINT8 rhythm = OPL->rhythm&0x20;
- OPL_CH *CH,*R_CH;
- YM_DELTAT *DELTAT = OPL->deltat;
-
- /* setup DELTA-T unit */
- YM_DELTAT_DECODE_PRESET(DELTAT);
-
- if( (void *)OPL != cur_chip ){
- cur_chip = (void *)OPL;
- /* channel pointers */
- S_CH = OPL->P_CH;
- E_CH = &S_CH[9];
- /* rhythm slot */
- SLOT7_1 = &S_CH[7].SLOT[SLOT1];
- SLOT7_2 = &S_CH[7].SLOT[SLOT2];
- SLOT8_1 = &S_CH[8].SLOT[SLOT1];
- SLOT8_2 = &S_CH[8].SLOT[SLOT2];
- /* LFO state */
- amsIncr = OPL->amsIncr;
- vibIncr = OPL->vibIncr;
- ams_table = OPL->ams_table;
- vib_table = OPL->vib_table;
- }
- R_CH = rhythm ? &S_CH[6] : E_CH;
- for( i=0; i < length ; i++ )
- {
- /* channel A channel B channel C */
- /* LFO */
- ams = ams_table[(amsCnt+=amsIncr)>>AMS_SHIFT];
- vib = vib_table[(vibCnt+=vibIncr)>>VIB_SHIFT];
- outd[0] = 0;
- /* deltaT ADPCM */
- if( DELTAT->portstate )
- YM_DELTAT_ADPCM_CALC(DELTAT);
- /* FM part */
- for(CH=S_CH ; CH < R_CH ; CH++)
- OPL_CALC_CH(CH);
- /* Rythn part */
- if(rhythm)
- OPL_CALC_RH(S_CH);
- /* limit check */
- data = Limit( outd[0] , OPL_MAXOUT, OPL_MINOUT );
- /* store to sound buffer */
- buf[i] = data >> OPL_OUTSB;
- }
- OPL->amsCnt = amsCnt;
- OPL->vibCnt = vibCnt;
- /* deltaT START flag */
- if( !DELTAT->portstate )
- OPL->status &= 0xfe;
-}
-#endif
-
-/* ---------- reset one of chip ---------- */
-void OPLResetChip(FM_OPL *OPL)
-{
- int c,s;
- int i;
-
- /* reset chip */
- OPL->mode = 0; /* normal mode */
- OPL_STATUS_RESET(OPL,0x7f);
- /* reset with register write */
- OPLWriteReg(OPL,0x01,0); /* wabesel disable */
- OPLWriteReg(OPL,0x02,0); /* Timer1 */
- OPLWriteReg(OPL,0x03,0); /* Timer2 */
- OPLWriteReg(OPL,0x04,0); /* IRQ mask clear */
- for(i = 0xff ; i >= 0x20 ; i-- ) OPLWriteReg(OPL,i,0);
- /* reset operator parameter */
- for( c = 0 ; c < OPL->max_ch ; c++ )
- {
- OPL_CH *CH = &OPL->P_CH[c];
- /* OPL->P_CH[c].PAN = OPN_CENTER; */
- for(s = 0 ; s < 2 ; s++ )
- {
- /* wave table */
- CH->SLOT[s].wavetable = &SIN_TABLE[0];
- /* CH->SLOT[s].evm = ENV_MOD_RR; */
- CH->SLOT[s].evc = EG_OFF;
- CH->SLOT[s].eve = EG_OFF+1;
- CH->SLOT[s].evs = 0;
- }
- }
-#if BUILD_Y8950
- if(OPL->type&OPL_TYPE_ADPCM)
- {
- YM_DELTAT *DELTAT = OPL->deltat;
-
- DELTAT->freqbase = OPL->freqbase;
- DELTAT->output_pointer = outd;
- DELTAT->portshift = 5;
- DELTAT->output_range = DELTAT_MIXING_LEVEL<<TL_BITS;
- YM_DELTAT_ADPCM_Reset(DELTAT,0);
- }
-#endif
-}
-
-/* ---------- Create one of vietual YM3812 ---------- */
-/* 'rate' is sampling rate and 'bufsiz' is the size of the */
-FM_OPL *OPLCreate(int type, int clock, int rate)
-{
- char *ptr;
- FM_OPL *OPL;
- int state_size;
- int max_ch = 9; /* normaly 9 channels */
-
- if( OPL_LockTable() ==-1) return NULL;
- /* allocate OPL state space */
- state_size = sizeof(FM_OPL);
- state_size += sizeof(OPL_CH)*max_ch;
-#if BUILD_Y8950
- if(type&OPL_TYPE_ADPCM) state_size+= sizeof(YM_DELTAT);
-#endif
- /* allocate memory block */
- ptr = malloc(state_size);
- if(ptr==NULL) return NULL;
- /* clear */
- memset(ptr,0,state_size);
- OPL = (FM_OPL *)ptr; ptr+=sizeof(FM_OPL);
- OPL->P_CH = (OPL_CH *)ptr; ptr+=sizeof(OPL_CH)*max_ch;
-#if BUILD_Y8950
- if(type&OPL_TYPE_ADPCM) OPL->deltat = (YM_DELTAT *)ptr; ptr+=sizeof(YM_DELTAT);
-#endif
- /* set channel state pointer */
- OPL->type = type;
- OPL->clock = clock;
- OPL->rate = rate;
- OPL->max_ch = max_ch;
- /* init grobal tables */
- OPL_initialize(OPL);
- /* reset chip */
- OPLResetChip(OPL);
-#ifdef OPL_OUTPUT_LOG
- if(!opl_dbg_fp)
- {
- opl_dbg_fp = fopen("opllog.opl","wb");
- opl_dbg_maxchip = 0;
- }
- if(opl_dbg_fp)
- {
- opl_dbg_opl[opl_dbg_maxchip] = OPL;
- fprintf(opl_dbg_fp,"%c%c%c%c%c%c",0x00+opl_dbg_maxchip,
- type,
- clock&0xff,
- (clock/0x100)&0xff,
- (clock/0x10000)&0xff,
- (clock/0x1000000)&0xff);
- opl_dbg_maxchip++;
- }
-#endif
- return OPL;
-}
-
-/* ---------- Destroy one of vietual YM3812 ---------- */
-void OPLDestroy(FM_OPL *OPL)
-{
-#ifdef OPL_OUTPUT_LOG
- if(opl_dbg_fp)
- {
- fclose(opl_dbg_fp);
- opl_dbg_fp = NULL;
- }
-#endif
- OPL_UnLockTable();
- free(OPL);
-}
-
-/* ---------- Option handlers ---------- */
-
-void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset)
-{
- OPL->TimerHandler = TimerHandler;
- OPL->TimerParam = channelOffset;
-}
-void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param)
-{
- OPL->IRQHandler = IRQHandler;
- OPL->IRQParam = param;
-}
-void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param)
-{
- OPL->UpdateHandler = UpdateHandler;
- OPL->UpdateParam = param;
-}
-#if BUILD_Y8950
-void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param)
-{
- OPL->porthandler_w = PortHandler_w;
- OPL->porthandler_r = PortHandler_r;
- OPL->port_param = param;
-}
-
-void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param)
-{
- OPL->keyboardhandler_w = KeyboardHandler_w;
- OPL->keyboardhandler_r = KeyboardHandler_r;
- OPL->keyboard_param = param;
-}
-#endif
-/* ---------- YM3812 I/O interface ---------- */
-int OPLWrite(FM_OPL *OPL,int a,int v)
-{
- if( !(a&1) )
- { /* address port */
- OPL->address = v & 0xff;
- }
- else
- { /* data port */
- if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0);
-#ifdef OPL_OUTPUT_LOG
- if(opl_dbg_fp)
- {
- for(opl_dbg_chip=0;opl_dbg_chip<opl_dbg_maxchip;opl_dbg_chip++)
- if( opl_dbg_opl[opl_dbg_chip] == OPL) break;
- fprintf(opl_dbg_fp,"%c%c%c",0x10+opl_dbg_chip,OPL->address,v);
- }
-#endif
- OPLWriteReg(OPL,OPL->address,v);
- }
- return OPL->status>>7;
-}
-
-unsigned char OPLRead(FM_OPL *OPL,int a)
-{
- if( !(a&1) )
- { /* status port */
- return OPL->status & (OPL->statusmask|0x80);
- }
- /* data port */
- switch(OPL->address)
- {
- case 0x05: /* KeyBoard IN */
- if(OPL->type&OPL_TYPE_KEYBOARD)
- {
- if(OPL->keyboardhandler_r)
- return OPL->keyboardhandler_r(OPL->keyboard_param);
- else {
- LOG(LOG_WAR,("OPL:read unmapped KEYBOARD port\n"));
- }
- }
- return 0;
-#if 0
- case 0x0f: /* ADPCM-DATA */
- return 0;
-#endif
- case 0x19: /* I/O DATA */
- if(OPL->type&OPL_TYPE_IO)
- {
- if(OPL->porthandler_r)
- return OPL->porthandler_r(OPL->port_param);
- else {
- LOG(LOG_WAR,("OPL:read unmapped I/O port\n"));
- }
- }
- return 0;
- case 0x1a: /* PCM-DATA */
- return 0;
- }
- return 0;
-}
-
-int OPLTimerOver(FM_OPL *OPL,int c)
-{
- if( c )
- { /* Timer B */
- OPL_STATUS_SET(OPL,0x20);
- }
- else
- { /* Timer A */
- OPL_STATUS_SET(OPL,0x40);
- /* CSM mode key,TL control */
- if( OPL->mode & 0x80 )
- { /* CSM mode total level latch and auto key on */
- int ch;
- if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0);
- for(ch=0;ch<9;ch++)
- CSMKeyControll( &OPL->P_CH[ch] );
- }
- }
- /* reload timer */
- if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+c,(double)OPL->T[c]*OPL->TimerBase);
- return OPL->status>>7;
-}
diff --git a/qemu/hw/audio/fmopl.h b/qemu/hw/audio/fmopl.h
deleted file mode 100644
index 24ba5f480..000000000
--- a/qemu/hw/audio/fmopl.h
+++ /dev/null
@@ -1,174 +0,0 @@
-#ifndef __FMOPL_H_
-#define __FMOPL_H_
-
-/* --- select emulation chips --- */
-#define BUILD_YM3812 (HAS_YM3812)
-//#define BUILD_YM3526 (HAS_YM3526)
-//#define BUILD_Y8950 (HAS_Y8950)
-
-/* --- system optimize --- */
-/* select bit size of output : 8 or 16 */
-#define OPL_OUTPUT_BIT 16
-
-/* compiler dependence */
-#ifndef OSD_CPU_H
-#define OSD_CPU_H
-typedef unsigned char UINT8; /* unsigned 8bit */
-typedef unsigned short UINT16; /* unsigned 16bit */
-typedef unsigned int UINT32; /* unsigned 32bit */
-typedef signed char INT8; /* signed 8bit */
-typedef signed short INT16; /* signed 16bit */
-typedef signed int INT32; /* signed 32bit */
-#endif
-
-#if (OPL_OUTPUT_BIT==16)
-typedef INT16 OPLSAMPLE;
-#endif
-#if (OPL_OUTPUT_BIT==8)
-typedef unsigned char OPLSAMPLE;
-#endif
-
-
-#if BUILD_Y8950
-#include "ymdeltat.h"
-#endif
-
-typedef void (*OPL_TIMERHANDLER)(int channel,double interval_Sec);
-typedef void (*OPL_IRQHANDLER)(int param,int irq);
-typedef void (*OPL_UPDATEHANDLER)(int param,int min_interval_us);
-typedef void (*OPL_PORTHANDLER_W)(int param,unsigned char data);
-typedef unsigned char (*OPL_PORTHANDLER_R)(int param);
-
-/* !!!!! here is private section , do not access there member direct !!!!! */
-
-#define OPL_TYPE_WAVESEL 0x01 /* waveform select */
-#define OPL_TYPE_ADPCM 0x02 /* DELTA-T ADPCM unit */
-#define OPL_TYPE_KEYBOARD 0x04 /* keyboard interface */
-#define OPL_TYPE_IO 0x08 /* I/O port */
-
-/* Saving is necessary for member of the 'R' mark for suspend/resume */
-/* ---------- OPL one of slot ---------- */
-typedef struct fm_opl_slot {
- INT32 TL; /* total level :TL << 8 */
- INT32 TLL; /* adjusted now TL */
- UINT8 KSR; /* key scale rate :(shift down bit) */
- INT32 *AR; /* attack rate :&AR_TABLE[AR<<2] */
- INT32 *DR; /* decay rate :&DR_TALBE[DR<<2] */
- INT32 SL; /* sustin level :SL_TALBE[SL] */
- INT32 *RR; /* release rate :&DR_TABLE[RR<<2] */
- UINT8 ksl; /* keyscale level :(shift down bits) */
- UINT8 ksr; /* key scale rate :kcode>>KSR */
- UINT32 mul; /* multiple :ML_TABLE[ML] */
- UINT32 Cnt; /* frequency count : */
- UINT32 Incr; /* frequency step : */
- /* envelope generator state */
- UINT8 eg_typ; /* envelope type flag */
- UINT8 evm; /* envelope phase */
- INT32 evc; /* envelope counter */
- INT32 eve; /* envelope counter end point */
- INT32 evs; /* envelope counter step */
- INT32 evsa; /* envelope step for AR :AR[ksr] */
- INT32 evsd; /* envelope step for DR :DR[ksr] */
- INT32 evsr; /* envelope step for RR :RR[ksr] */
- /* LFO */
- UINT8 ams; /* ams flag */
- UINT8 vib; /* vibrate flag */
- /* wave selector */
- INT32 **wavetable;
-}OPL_SLOT;
-
-/* ---------- OPL one of channel ---------- */
-typedef struct fm_opl_channel {
- OPL_SLOT SLOT[2];
- UINT8 CON; /* connection type */
- UINT8 FB; /* feed back :(shift down bit) */
- INT32 *connect1; /* slot1 output pointer */
- INT32 *connect2; /* slot2 output pointer */
- INT32 op1_out[2]; /* slot1 output for selfeedback */
- /* phase generator state */
- UINT32 block_fnum; /* block+fnum : */
- UINT8 kcode; /* key code : KeyScaleCode */
- UINT32 fc; /* Freq. Increment base */
- UINT32 ksl_base; /* KeyScaleLevel Base step */
- UINT8 keyon; /* key on/off flag */
-} OPL_CH;
-
-/* OPL state */
-typedef struct fm_opl_f {
- UINT8 type; /* chip type */
- int clock; /* master clock (Hz) */
- int rate; /* sampling rate (Hz) */
- double freqbase; /* frequency base */
- double TimerBase; /* Timer base time (==sampling time) */
- UINT8 address; /* address register */
- UINT8 status; /* status flag */
- UINT8 statusmask; /* status mask */
- UINT32 mode; /* Reg.08 : CSM , notesel,etc. */
- /* Timer */
- int T[2]; /* timer counter */
- UINT8 st[2]; /* timer enable */
- /* FM channel slots */
- OPL_CH *P_CH; /* pointer of CH */
- int max_ch; /* maximum channel */
- /* Rhythm sention */
- UINT8 rhythm; /* Rhythm mode , key flag */
-#if BUILD_Y8950
- /* Delta-T ADPCM unit (Y8950) */
- YM_DELTAT *deltat; /* DELTA-T ADPCM */
-#endif
- /* Keyboard / I/O interface unit (Y8950) */
- UINT8 portDirection;
- UINT8 portLatch;
- OPL_PORTHANDLER_R porthandler_r;
- OPL_PORTHANDLER_W porthandler_w;
- int port_param;
- OPL_PORTHANDLER_R keyboardhandler_r;
- OPL_PORTHANDLER_W keyboardhandler_w;
- int keyboard_param;
- /* time tables */
- INT32 AR_TABLE[75]; /* atttack rate tables */
- INT32 DR_TABLE[75]; /* decay rate tables */
- UINT32 FN_TABLE[1024]; /* fnumber -> increment counter */
- /* LFO */
- INT32 *ams_table;
- INT32 *vib_table;
- INT32 amsCnt;
- INT32 amsIncr;
- INT32 vibCnt;
- INT32 vibIncr;
- /* wave selector enable flag */
- UINT8 wavesel;
- /* external event callback handler */
- OPL_TIMERHANDLER TimerHandler; /* TIMER handler */
- int TimerParam; /* TIMER parameter */
- OPL_IRQHANDLER IRQHandler; /* IRQ handler */
- int IRQParam; /* IRQ parameter */
- OPL_UPDATEHANDLER UpdateHandler; /* stream update handler */
- int UpdateParam; /* stream update parameter */
-} FM_OPL;
-
-/* ---------- Generic interface section ---------- */
-#define OPL_TYPE_YM3526 (0)
-#define OPL_TYPE_YM3812 (OPL_TYPE_WAVESEL)
-#define OPL_TYPE_Y8950 (OPL_TYPE_ADPCM|OPL_TYPE_KEYBOARD|OPL_TYPE_IO)
-
-FM_OPL *OPLCreate(int type, int clock, int rate);
-void OPLDestroy(FM_OPL *OPL);
-void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset);
-void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param);
-void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param);
-/* Y8950 port handlers */
-void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param);
-void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param);
-
-void OPLResetChip(FM_OPL *OPL);
-int OPLWrite(FM_OPL *OPL,int a,int v);
-unsigned char OPLRead(FM_OPL *OPL,int a);
-int OPLTimerOver(FM_OPL *OPL,int c);
-
-/* YM3626/YM3812 local section */
-void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length);
-
-void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length);
-
-#endif
diff --git a/qemu/hw/audio/gus.c b/qemu/hw/audio/gus.c
deleted file mode 100644
index 9dd6947be..000000000
--- a/qemu/hw/audio/gus.c
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- * QEMU Proxy for Gravis Ultrasound GF1 emulation by Tibor "TS" Schütz
- *
- * Copyright (c) 2002-2005 Vassili Karpov (malc)
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/hw.h"
-#include "hw/audio/audio.h"
-#include "audio/audio.h"
-#include "hw/isa/isa.h"
-#include "gusemu.h"
-#include "gustate.h"
-
-#define dolog(...) AUD_log ("audio", __VA_ARGS__)
-#ifdef DEBUG
-#define ldebug(...) dolog (__VA_ARGS__)
-#else
-#define ldebug(...)
-#endif
-
-#ifdef HOST_WORDS_BIGENDIAN
-#define GUS_ENDIANNESS 1
-#else
-#define GUS_ENDIANNESS 0
-#endif
-
-#define TYPE_GUS "gus"
-#define GUS(obj) OBJECT_CHECK (GUSState, (obj), TYPE_GUS)
-
-typedef struct GUSState {
- ISADevice dev;
- GUSEmuState emu;
- QEMUSoundCard card;
- uint32_t freq;
- uint32_t port;
- int pos, left, shift, irqs;
- GUSsample *mixbuf;
- uint8_t himem[1024 * 1024 + 32 + 4096];
- int samples;
- SWVoiceOut *voice;
- int64_t last_ticks;
- qemu_irq pic;
- IsaDma *isa_dma;
-} GUSState;
-
-static uint32_t gus_readb(void *opaque, uint32_t nport)
-{
- GUSState *s = opaque;
-
- return gus_read (&s->emu, nport, 1);
-}
-
-static void gus_writeb(void *opaque, uint32_t nport, uint32_t val)
-{
- GUSState *s = opaque;
-
- gus_write (&s->emu, nport, 1, val);
-}
-
-static int write_audio (GUSState *s, int samples)
-{
- int net = 0;
- int pos = s->pos;
-
- while (samples) {
- int nbytes, wbytes, wsampl;
-
- nbytes = samples << s->shift;
- wbytes = AUD_write (
- s->voice,
- s->mixbuf + (pos << (s->shift - 1)),
- nbytes
- );
-
- if (wbytes) {
- wsampl = wbytes >> s->shift;
-
- samples -= wsampl;
- pos = (pos + wsampl) % s->samples;
-
- net += wsampl;
- }
- else {
- break;
- }
- }
-
- return net;
-}
-
-static void GUS_callback (void *opaque, int free)
-{
- int samples, to_play, net = 0;
- GUSState *s = opaque;
-
- samples = free >> s->shift;
- to_play = audio_MIN (samples, s->left);
-
- while (to_play) {
- int written = write_audio (s, to_play);
-
- if (!written) {
- goto reset;
- }
-
- s->left -= written;
- to_play -= written;
- samples -= written;
- net += written;
- }
-
- samples = audio_MIN (samples, s->samples);
- if (samples) {
- gus_mixvoices (&s->emu, s->freq, samples, s->mixbuf);
-
- while (samples) {
- int written = write_audio (s, samples);
- if (!written) {
- break;
- }
- samples -= written;
- net += written;
- }
- }
- s->left = samples;
-
- reset:
- gus_irqgen (&s->emu, muldiv64 (net, 1000000, s->freq));
-}
-
-int GUS_irqrequest (GUSEmuState *emu, int hwirq, int n)
-{
- GUSState *s = emu->opaque;
- /* qemu_irq_lower (s->pic); */
- qemu_irq_raise (s->pic);
- s->irqs += n;
- ldebug ("irqrequest %d %d %d\n", hwirq, n, s->irqs);
- return n;
-}
-
-void GUS_irqclear (GUSEmuState *emu, int hwirq)
-{
- GUSState *s = emu->opaque;
- ldebug ("irqclear %d %d\n", hwirq, s->irqs);
- qemu_irq_lower (s->pic);
- s->irqs -= 1;
-#ifdef IRQ_STORM
- if (s->irqs > 0) {
- qemu_irq_raise (s->pic[hwirq]);
- }
-#endif
-}
-
-void GUS_dmarequest (GUSEmuState *emu)
-{
- GUSState *s = emu->opaque;
- IsaDmaClass *k = ISADMA_GET_CLASS(s->isa_dma);
- ldebug ("dma request %d\n", der->gusdma);
- k->hold_DREQ(s->isa_dma, s->emu.gusdma);
-}
-
-static int GUS_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len)
-{
- GUSState *s = opaque;
- IsaDmaClass *k = ISADMA_GET_CLASS(s->isa_dma);
- char tmpbuf[4096];
- int pos = dma_pos, mode, left = dma_len - dma_pos;
-
- ldebug ("read DMA %#x %d\n", dma_pos, dma_len);
- mode = k->has_autoinitialization(s->isa_dma, s->emu.gusdma);
- while (left) {
- int to_copy = audio_MIN ((size_t) left, sizeof (tmpbuf));
- int copied;
-
- ldebug ("left=%d to_copy=%d pos=%d\n", left, to_copy, pos);
- copied = k->read_memory(s->isa_dma, nchan, tmpbuf, pos, to_copy);
- gus_dma_transferdata (&s->emu, tmpbuf, copied, left == copied);
- left -= copied;
- pos += copied;
- }
-
- if (((mode >> 4) & 1) == 0) {
- k->release_DREQ(s->isa_dma, s->emu.gusdma);
- }
- return dma_len;
-}
-
-static const VMStateDescription vmstate_gus = {
- .name = "gus",
- .version_id = 2,
- .minimum_version_id = 2,
- .fields = (VMStateField[]) {
- VMSTATE_INT32 (pos, GUSState),
- VMSTATE_INT32 (left, GUSState),
- VMSTATE_INT32 (shift, GUSState),
- VMSTATE_INT32 (irqs, GUSState),
- VMSTATE_INT32 (samples, GUSState),
- VMSTATE_INT64 (last_ticks, GUSState),
- VMSTATE_BUFFER (himem, GUSState),
- VMSTATE_END_OF_LIST ()
- }
-};
-
-static const MemoryRegionPortio gus_portio_list1[] = {
- {0x000, 1, 1, .write = gus_writeb },
- {0x006, 10, 1, .read = gus_readb, .write = gus_writeb },
- {0x100, 8, 1, .read = gus_readb, .write = gus_writeb },
- PORTIO_END_OF_LIST (),
-};
-
-static const MemoryRegionPortio gus_portio_list2[] = {
- {0, 2, 1, .read = gus_readb },
- PORTIO_END_OF_LIST (),
-};
-
-static void gus_realizefn (DeviceState *dev, Error **errp)
-{
- ISADevice *d = ISA_DEVICE(dev);
- GUSState *s = GUS (dev);
- IsaDmaClass *k;
- struct audsettings as;
-
- AUD_register_card ("gus", &s->card);
-
- as.freq = s->freq;
- as.nchannels = 2;
- as.fmt = AUD_FMT_S16;
- as.endianness = GUS_ENDIANNESS;
-
- s->voice = AUD_open_out (
- &s->card,
- NULL,
- "gus",
- s,
- GUS_callback,
- &as
- );
-
- if (!s->voice) {
- AUD_remove_card (&s->card);
- error_setg(errp, "No voice");
- return;
- }
-
- s->shift = 2;
- s->samples = AUD_get_buffer_size_out (s->voice) >> s->shift;
- s->mixbuf = g_malloc0 (s->samples << s->shift);
-
- isa_register_portio_list (d, s->port, gus_portio_list1, s, "gus");
- isa_register_portio_list (d, (s->port + 0x100) & 0xf00,
- gus_portio_list2, s, "gus");
-
- s->isa_dma = isa_get_dma(isa_bus_from_device(d), s->emu.gusdma);
- k = ISADMA_GET_CLASS(s->isa_dma);
- k->register_channel(s->isa_dma, s->emu.gusdma, GUS_read_DMA, s);
- s->emu.himemaddr = s->himem;
- s->emu.gusdatapos = s->emu.himemaddr + 1024 * 1024 + 32;
- s->emu.opaque = s;
- isa_init_irq (d, &s->pic, s->emu.gusirq);
-
- AUD_set_active_out (s->voice, 1);
-}
-
-static int GUS_init (ISABus *bus)
-{
- isa_create_simple (bus, TYPE_GUS);
- return 0;
-}
-
-static Property gus_properties[] = {
- DEFINE_PROP_UINT32 ("freq", GUSState, freq, 44100),
- DEFINE_PROP_UINT32 ("iobase", GUSState, port, 0x240),
- DEFINE_PROP_UINT32 ("irq", GUSState, emu.gusirq, 7),
- DEFINE_PROP_UINT32 ("dma", GUSState, emu.gusdma, 3),
- DEFINE_PROP_END_OF_LIST (),
-};
-
-static void gus_class_initfn (ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS (klass);
-
- dc->realize = gus_realizefn;
- set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
- dc->desc = "Gravis Ultrasound GF1";
- dc->vmsd = &vmstate_gus;
- dc->props = gus_properties;
-}
-
-static const TypeInfo gus_info = {
- .name = TYPE_GUS,
- .parent = TYPE_ISA_DEVICE,
- .instance_size = sizeof (GUSState),
- .class_init = gus_class_initfn,
-};
-
-static void gus_register_types (void)
-{
- type_register_static (&gus_info);
- isa_register_soundhw("gus", "Gravis Ultrasound GF1", GUS_init);
-}
-
-type_init (gus_register_types)
diff --git a/qemu/hw/audio/gusemu.h b/qemu/hw/audio/gusemu.h
deleted file mode 100644
index b7f075126..000000000
--- a/qemu/hw/audio/gusemu.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * GUSEMU32 - API
- *
- * Copyright (C) 2000-2007 Tibor "TS" Schütz
- *
- * 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.
- */
-
-#ifndef GUSEMU_H
-#define GUSEMU_H
-
-/* data types (need to be adjusted if neither a VC6 nor a C99 compatible compiler is used) */
-
-#if defined _WIN32 && defined _MSC_VER /* doesn't support other win32 compilers yet, do it yourself... */
- typedef unsigned char GUSbyte;
- typedef unsigned short GUSword;
- typedef unsigned int GUSdword;
- typedef signed char GUSchar;
- typedef signed short GUSsample;
-#else
- typedef int8_t GUSchar;
- typedef uint8_t GUSbyte;
- typedef uint16_t GUSword;
- typedef uint32_t GUSdword;
- typedef int16_t GUSsample;
-#endif
-
-typedef struct _GUSEmuState
-{
- GUSbyte *himemaddr; /* 1024*1024 bytes used for storing uploaded samples (+32 additional bytes for read padding) */
- GUSbyte *gusdatapos; /* (gusdataend-gusdata) bytes used for storing emulated GF1/mixer register states (32*32+4 bytes in initial GUSemu32 version) */
- uint32_t gusirq;
- uint32_t gusdma;
- unsigned int timer1fraction;
- unsigned int timer2fraction;
- void *opaque;
-} GUSEmuState;
-
-/* ** Callback functions needed: */
-/* NMI is defined as hwirq=-1 (not supported (yet?)) */
-/* GUS_irqrequest returns the number of IRQs actually scheduled into the virtual machine */
-/* Level triggered IRQ simulations normally return 1 */
-/* Event triggered IRQ simulation can safely ignore GUS_irqclear calls */
-int GUS_irqrequest(GUSEmuState *state, int hwirq, int num);/* needed in both mixer and bus emulation functions. */
-void GUS_irqclear( GUSEmuState *state, int hwirq); /* used by gus_write() only - can be left empty for mixer functions */
-void GUS_dmarequest(GUSEmuState *state); /* used by gus_write() only - can be left empty for mixer functions */
-
-/* ** ISA bus interface functions: */
-
-/* Port I/O handlers */
-/* support the following ports: */
-/* 2x0,2x6,2x8...2xF,3x0...3x7; */
-/* optional: 388,389 (at least writes should be forwarded or some GUS detection algorithms will fail) */
-/* data is passed in host byte order */
-unsigned int gus_read( GUSEmuState *state, int port, int size);
-void gus_write(GUSEmuState *state, int port, int size, unsigned int data);
-/* size is given in bytes (1 for byte, 2 for word) */
-
-/* DMA data transfer function */
-/* data pointed to is passed in native x86 order */
-void gus_dma_transferdata(GUSEmuState *state, char *dma_addr, unsigned int count, int TC);
-/* Called back by GUS_start_DMA as soon as the emulated DMA controller is ready for a transfer to or from GUS */
-/* (might be immediately if the DMA controller was programmed first) */
-/* dma_addr is an already translated address directly pointing to the beginning of the memory block */
-/* do not forget to update DMA states after the call, including the DREQ and TC flags */
-/* it is possible to break down a single transfer into multiple ones, but take care that: */
-/* -dma_count is actually count-1 */
-/* -before and during a transfer, DREQ is set and TC cleared */
-/* -when calling gus_dma_transferdata(), TC is only set true for call transferring the last byte */
-/* -after the last transfer, DREQ is cleared and TC is set */
-
-/* ** GF1 mixer emulation functions: */
-/* Usually, gus_irqgen should be called directly after gus_mixvoices if you can meet the recommended ranges. */
-/* If the interrupts are executed immediately (i.e., are synchronous), it may be useful to break this */
-/* down into a sequence of gus_mixvoice();gus_irqgen(); calls while mixing an audio block. */
-/* If the interrupts are asynchronous, it may be needed to use a separate thread mixing into a temporary */
-/* audio buffer in order to avoid quality loss caused by large numsamples and elapsed_time values. */
-
-void gus_mixvoices(GUSEmuState *state, unsigned int playback_freq, unsigned int numsamples, GUSsample *bufferpos);
-/* recommended range: 10 < numsamples < 100 */
-/* lower values may result in increased rounding error, higher values often cause audible timing delays */
-
-void gus_irqgen(GUSEmuState *state, unsigned int elapsed_time);
-/* recommended range: 80us < elapsed_time < max(1000us, numsamples/playback_freq) */
-/* lower values won´t provide any benefit at all, higher values can cause audible timing delays */
-/* note: masked timers are also calculated by this function, thus it might be needed even without any IRQs in use! */
-
-#endif /* gusemu.h */
diff --git a/qemu/hw/audio/gusemu_hal.c b/qemu/hw/audio/gusemu_hal.c
deleted file mode 100644
index 973d6b9f4..000000000
--- a/qemu/hw/audio/gusemu_hal.c
+++ /dev/null
@@ -1,555 +0,0 @@
-/*
- * GUSEMU32 - bus interface part
- *
- * Copyright (C) 2000-2007 Tibor "TS" Schütz
- *
- * 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.
- */
-
-/*
- * TODO: check mixer: see 7.20 of sdk for panning pos (applies to all gus models?)?
- */
-
-#include "qemu/osdep.h"
-#include "gustate.h"
-#include "gusemu.h"
-
-#define GUSregb(position) (* (gusptr+(position)))
-#define GUSregw(position) (*(GUSword *) (gusptr+(position)))
-#define GUSregd(position) (*(GUSdword *)(gusptr+(position)))
-
-/* size given in bytes */
-unsigned int gus_read(GUSEmuState * state, int port, int size)
-{
- int value_read = 0;
-
- GUSbyte *gusptr;
- gusptr = state->gusdatapos;
- GUSregd(portaccesses)++;
-
- switch (port & 0xff0f)
- {
- /* MixerCtrlReg (read not supported on GUS classic) */
- /* case 0x200: return GUSregb(MixerCtrlReg2x0); */
- case 0x206: /* IRQstatReg / SB2x6IRQ */
- /* adlib/sb bits set in port handlers */
- /* timer/voice bits set in gus_irqgen() */
- /* dma bit set in gus_dma_transferdata */
- /* midi not implemented yet */
- return GUSregb(IRQStatReg2x6);
- /* case 0x308: */ /* AdLib388 */
- case 0x208:
- if (GUSregb(GUS45TimerCtrl) & 1)
- return GUSregb(TimerStatus2x8);
- return GUSregb(AdLibStatus2x8); /* AdLibStatus */
- case 0x309: /* AdLib389 */
- case 0x209:
- return GUSregb(AdLibData2x9); /* AdLibData */
- case 0x20A:
- return GUSregb(AdLibCommand2xA); /* AdLib2x8_2xA */
-
-#if 0
- case 0x20B: /* GUS hidden registers (read not supported on GUS classic) */
- switch (GUSregb(RegCtrl_2xF) & 0x07)
- {
- case 0: /* IRQ/DMA select */
- if (GUSregb(MixerCtrlReg2x0) & 0x40)
- return GUSregb(IRQ_2xB); /* control register select bit */
- else
- return GUSregb(DMA_2xB);
- /* case 1-5: */ /* general purpose emulation regs */
- /* return ... */ /* + status reset reg (write only) */
- case 6:
- return GUSregb(Jumper_2xB); /* Joystick/MIDI enable (JumperReg) */
- default:;
- }
- break;
-#endif
-
- case 0x20C: /* SB2xCd */
- value_read = GUSregb(SB2xCd);
- if (GUSregb(StatRead_2xF) & 0x20)
- GUSregb(SB2xCd) ^= 0x80; /* toggle MSB on read */
- return value_read;
- /* case 0x20D: */ /* SB2xD is write only -> 2xE writes to it*/
- case 0x20E:
- if (GUSregb(RegCtrl_2xF) & 0x80) /* 2xE read IRQ enabled? */
- {
- GUSregb(StatRead_2xF) |= 0x80;
- GUS_irqrequest(state, state->gusirq, 1);
- }
- return GUSregb(SB2xE); /* SB2xE */
- case 0x20F: /* StatRead_2xF */
- /*set/clear fixed bits */
- /*value_read = (GUSregb(StatRead_2xF) & 0xf9)|1; */ /*(LSB not set on GUS classic!)*/
- value_read = (GUSregb(StatRead_2xF) & 0xf9);
- if (GUSregb(MixerCtrlReg2x0) & 0x08)
- value_read |= 2; /* DMA/IRQ enabled flag */
- return value_read;
- /* case 0x300: */ /* MIDI (not implemented) */
- /* case 0x301: */ /* MIDI (not implemented) */
- case 0x302:
- return GUSregb(VoiceSelReg3x2); /* VoiceSelReg */
- case 0x303:
- return GUSregb(FunkSelReg3x3); /* FunkSelReg */
- case 0x304: /* DataRegLoByte3x4 + DataRegWord3x4 */
- case 0x305: /* DataRegHiByte3x5 */
- switch (GUSregb(FunkSelReg3x3))
- {
- /* common functions */
- case 0x41: /* DramDMAContrReg */
- value_read = GUSregb(GUS41DMACtrl); /* &0xfb */
- GUSregb(GUS41DMACtrl) &= 0xbb;
- if (state->gusdma >= 4)
- value_read |= 0x04;
- if (GUSregb(IRQStatReg2x6) & 0x80)
- {
- value_read |= 0x40;
- GUSregb(IRQStatReg2x6) &= 0x7f;
- if (!GUSregb(IRQStatReg2x6))
- GUS_irqclear(state, state->gusirq);
- }
- return (GUSbyte) value_read;
- /* DramDMAmemPosReg */
- /* case 0x42: value_read=GUSregw(GUS42DMAStart); break;*/
- /* 43h+44h write only */
- case 0x45:
- return GUSregb(GUS45TimerCtrl); /* TimerCtrlReg */
- /* 46h+47h write only */
- /* 48h: samp freq - write only */
- case 0x49:
- return GUSregb(GUS49SampCtrl) & 0xbf; /* SampCtrlReg */
- /* case 4bh: */ /* joystick trim not supported */
- /* case 0x4c: return GUSregb(GUS4cReset); */ /* GUSreset: write only*/
- /* voice specific functions */
- case 0x80:
- case 0x81:
- case 0x82:
- case 0x83:
- case 0x84:
- case 0x85:
- case 0x86:
- case 0x87:
- case 0x88:
- case 0x89:
- case 0x8a:
- case 0x8b:
- case 0x8c:
- case 0x8d:
- {
- int offset = 2 * (GUSregb(FunkSelReg3x3) & 0x0f);
- offset += ((int) GUSregb(VoiceSelReg3x2) & 0x1f) << 5; /* = Voice*32 + Funktion*2 */
- value_read = GUSregw(offset);
- }
- break;
- /* voice unspecific functions */
- case 0x8e: /* NumVoice */
- return GUSregb(NumVoices);
- case 0x8f: /* irqstatreg */
- /* (pseudo IRQ-FIFO is processed during a gus_write(0x3X3,0x8f)) */
- return GUSregb(SynVoiceIRQ8f);
- default:
- return 0xffff;
- }
- if (size == 1)
- {
- if ((port & 0xff0f) == 0x305)
- value_read = value_read >> 8;
- value_read &= 0xff;
- }
- return (GUSword) value_read;
- /* case 0x306: */ /* Mixer/Version info */
- /* return 0xff; */ /* Pre 3.6 boards, ICS mixer NOT present */
- case 0x307: /* DRAMaccess */
- {
- GUSbyte *adr;
- adr = state->himemaddr + (GUSregd(GUSDRAMPOS24bit) & 0xfffff);
- return *adr;
- }
- default:;
- }
- return 0xffff;
-}
-
-void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
-{
- GUSbyte *gusptr;
- gusptr = state->gusdatapos;
- GUSregd(portaccesses)++;
-
- switch (port & 0xff0f)
- {
- case 0x200: /* MixerCtrlReg */
- GUSregb(MixerCtrlReg2x0) = (GUSbyte) data;
- break;
- case 0x206: /* IRQstatReg / SB2x6IRQ */
- if (GUSregb(GUS45TimerCtrl) & 0x20) /* SB IRQ enabled? -> set 2x6IRQ bit */
- {
- GUSregb(TimerStatus2x8) |= 0x08;
- GUSregb(IRQStatReg2x6) = 0x10;
- GUS_irqrequest(state, state->gusirq, 1);
- }
- break;
- case 0x308: /* AdLib 388h */
- case 0x208: /* AdLibCommandReg */
- GUSregb(AdLibCommand2xA) = (GUSbyte) data;
- break;
- case 0x309: /* AdLib 389h */
- case 0x209: /* AdLibDataReg */
- if ((GUSregb(AdLibCommand2xA) == 0x04) && (!(GUSregb(GUS45TimerCtrl) & 1))) /* GUS auto timer mode enabled? */
- {
- if (data & 0x80)
- GUSregb(TimerStatus2x8) &= 0x1f; /* AdLib IRQ reset? -> clear maskable adl. timer int regs */
- else
- GUSregb(TimerDataReg2x9) = (GUSbyte) data;
- }
- else
- {
- GUSregb(AdLibData2x9) = (GUSbyte) data;
- if (GUSregb(GUS45TimerCtrl) & 0x02)
- {
- GUSregb(TimerStatus2x8) |= 0x01;
- GUSregb(IRQStatReg2x6) = 0x10;
- GUS_irqrequest(state, state->gusirq, 1);
- }
- }
- break;
- case 0x20A:
- GUSregb(AdLibStatus2x8) = (GUSbyte) data;
- break; /* AdLibStatus2x8 */
- case 0x20B: /* GUS hidden registers */
- switch (GUSregb(RegCtrl_2xF) & 0x7)
- {
- case 0:
- if (GUSregb(MixerCtrlReg2x0) & 0x40)
- GUSregb(IRQ_2xB) = (GUSbyte) data; /* control register select bit */
- else
- GUSregb(DMA_2xB) = (GUSbyte) data;
- break;
- /* case 1-4: general purpose emulation regs */
- case 5: /* clear stat reg 2xF */
- GUSregb(StatRead_2xF) = 0; /* ToDo: is this identical with GUS classic? */
- if (!GUSregb(IRQStatReg2x6))
- GUS_irqclear(state, state->gusirq);
- break;
- case 6: /* Jumper reg (Joystick/MIDI enable) */
- GUSregb(Jumper_2xB) = (GUSbyte) data;
- break;
- default:;
- }
- break;
- case 0x20C: /* SB2xCd */
- if (GUSregb(GUS45TimerCtrl) & 0x20)
- {
- GUSregb(TimerStatus2x8) |= 0x10; /* SB IRQ enabled? -> set 2xCIRQ bit */
- GUSregb(IRQStatReg2x6) = 0x10;
- GUS_irqrequest(state, state->gusirq, 1);
- }
- case 0x20D: /* SB2xCd no IRQ */
- GUSregb(SB2xCd) = (GUSbyte) data;
- break;
- case 0x20E: /* SB2xE */
- GUSregb(SB2xE) = (GUSbyte) data;
- break;
- case 0x20F:
- GUSregb(RegCtrl_2xF) = (GUSbyte) data;
- break; /* CtrlReg2xF */
- case 0x302: /* VoiceSelReg */
- GUSregb(VoiceSelReg3x2) = (GUSbyte) data;
- break;
- case 0x303: /* FunkSelReg */
- GUSregb(FunkSelReg3x3) = (GUSbyte) data;
- if ((GUSbyte) data == 0x8f) /* set irqstatreg, get voicereg and clear IRQ */
- {
- int voice;
- if (GUSregd(voicewavetableirq)) /* WavetableIRQ */
- {
- for (voice = 0; voice < 31; voice++)
- {
- if (GUSregd(voicewavetableirq) & (1 << voice))
- {
- GUSregd(voicewavetableirq) ^= (1 << voice); /* clear IRQ bit */
- GUSregb(voice << 5) &= 0x7f; /* clear voice reg irq bit */
- if (!GUSregd(voicewavetableirq))
- GUSregb(IRQStatReg2x6) &= 0xdf;
- if (!GUSregb(IRQStatReg2x6))
- GUS_irqclear(state, state->gusirq);
- GUSregb(SynVoiceIRQ8f) = voice | 0x60; /* (bit==0 => IRQ wartend) */
- return;
- }
- }
- }
- else if (GUSregd(voicevolrampirq)) /* VolRamp IRQ */
- {
- for (voice = 0; voice < 31; voice++)
- {
- if (GUSregd(voicevolrampirq) & (1 << voice))
- {
- GUSregd(voicevolrampirq) ^= (1 << voice); /* clear IRQ bit */
- GUSregb((voice << 5) + VSRVolRampControl) &= 0x7f; /* clear voice volume reg irq bit */
- if (!GUSregd(voicevolrampirq))
- GUSregb(IRQStatReg2x6) &= 0xbf;
- if (!GUSregb(IRQStatReg2x6))
- GUS_irqclear(state, state->gusirq);
- GUSregb(SynVoiceIRQ8f) = voice | 0x80; /* (bit==0 => IRQ wartend) */
- return;
- }
- }
- }
- GUSregb(SynVoiceIRQ8f) = 0xe8; /* kein IRQ wartet */
- }
- break;
- case 0x304:
- case 0x305:
- {
- GUSword writedata = (GUSword) data;
- GUSword readmask = 0x0000;
- if (size == 1)
- {
- readmask = 0xff00;
- writedata &= 0xff;
- if ((port & 0xff0f) == 0x305)
- {
- writedata = (GUSword) (writedata << 8);
- readmask = 0x00ff;
- }
- }
- switch (GUSregb(FunkSelReg3x3))
- {
- /* voice specific functions */
- case 0x00:
- case 0x01:
- case 0x02:
- case 0x03:
- case 0x04:
- case 0x05:
- case 0x06:
- case 0x07:
- case 0x08:
- case 0x09:
- case 0x0a:
- case 0x0b:
- case 0x0c:
- case 0x0d:
- {
- int offset;
- if (!(GUSregb(GUS4cReset) & 0x01))
- break; /* reset flag active? */
- offset = 2 * (GUSregb(FunkSelReg3x3) & 0x0f);
- offset += (GUSregb(VoiceSelReg3x2) & 0x1f) << 5; /* = Voice*32 + Funktion*2 */
- GUSregw(offset) = (GUSword) ((GUSregw(offset) & readmask) | writedata);
- }
- break;
- /* voice unspecific functions */
- case 0x0e: /* NumVoices */
- GUSregb(NumVoices) = (GUSbyte) data;
- break;
- /* case 0x0f: */ /* read only */
- /* common functions */
- case 0x41: /* DramDMAContrReg */
- GUSregb(GUS41DMACtrl) = (GUSbyte) data;
- if (data & 0x01)
- GUS_dmarequest(state);
- break;
- case 0x42: /* DramDMAmemPosReg */
- GUSregw(GUS42DMAStart) = (GUSregw(GUS42DMAStart) & readmask) | writedata;
- GUSregb(GUS50DMAHigh) &= 0xf; /* compatibility stuff... */
- break;
- case 0x43: /* DRAMaddrLo */
- GUSregd(GUSDRAMPOS24bit) =
- (GUSregd(GUSDRAMPOS24bit) & (readmask | 0xff0000)) | writedata;
- break;
- case 0x44: /* DRAMaddrHi */
- GUSregd(GUSDRAMPOS24bit) =
- (GUSregd(GUSDRAMPOS24bit) & 0xffff) | ((data & 0x0f) << 16);
- break;
- case 0x45: /* TCtrlReg */
- GUSregb(GUS45TimerCtrl) = (GUSbyte) data;
- if (!(data & 0x20))
- GUSregb(TimerStatus2x8) &= 0xe7; /* sb IRQ dis? -> clear 2x8/2xC sb IRQ flags */
- if (!(data & 0x02))
- GUSregb(TimerStatus2x8) &= 0xfe; /* adlib data IRQ dis? -> clear 2x8 adlib IRQ flag */
- if (!(GUSregb(TimerStatus2x8) & 0x19))
- GUSregb(IRQStatReg2x6) &= 0xef; /* 0xe6; $$clear IRQ if both IRQ bits are inactive or cleared */
- /* catch up delayed timer IRQs: */
- if ((GUSregw(TimerIRQs) > 1) && (GUSregb(TimerDataReg2x9) & 3))
- {
- if (GUSregb(TimerDataReg2x9) & 1) /* start timer 1 (80us decrement rate) */
- {
- if (!(GUSregb(TimerDataReg2x9) & 0x40))
- GUSregb(TimerStatus2x8) |= 0xc0; /* maskable bits */
- if (data & 4) /* timer1 irq enable */
- {
- GUSregb(TimerStatus2x8) |= 4; /* nonmaskable bit */
- GUSregb(IRQStatReg2x6) |= 4; /* timer 1 irq pending */
- }
- }
- if (GUSregb(TimerDataReg2x9) & 2) /* start timer 2 (320us decrement rate) */
- {
- if (!(GUSregb(TimerDataReg2x9) & 0x20))
- GUSregb(TimerStatus2x8) |= 0xa0; /* maskable bits */
- if (data & 8) /* timer2 irq enable */
- {
- GUSregb(TimerStatus2x8) |= 2; /* nonmaskable bit */
- GUSregb(IRQStatReg2x6) |= 8; /* timer 2 irq pending */
- }
- }
- GUSregw(TimerIRQs)--;
- if (GUSregw(BusyTimerIRQs) > 1)
- GUSregw(BusyTimerIRQs)--;
- else
- GUSregw(BusyTimerIRQs) =
- GUS_irqrequest(state, state->gusirq, GUSregw(TimerIRQs));
- }
- else
- GUSregw(TimerIRQs) = 0;
-
- if (!(data & 0x04))
- {
- GUSregb(TimerStatus2x8) &= 0xfb; /* clear non-maskable timer1 bit */
- GUSregb(IRQStatReg2x6) &= 0xfb;
- }
- if (!(data & 0x08))
- {
- GUSregb(TimerStatus2x8) &= 0xfd; /* clear non-maskable timer2 bit */
- GUSregb(IRQStatReg2x6) &= 0xf7;
- }
- if (!GUSregb(IRQStatReg2x6))
- GUS_irqclear(state, state->gusirq);
- break;
- case 0x46: /* Counter1 */
- GUSregb(GUS46Counter1) = (GUSbyte) data;
- break;
- case 0x47: /* Counter2 */
- GUSregb(GUS47Counter2) = (GUSbyte) data;
- break;
- /* case 0x48: */ /* sampling freq reg not emulated (same as interwave) */
- case 0x49: /* SampCtrlReg */
- GUSregb(GUS49SampCtrl) = (GUSbyte) data;
- break;
- /* case 0x4b: */ /* joystick trim not emulated */
- case 0x4c: /* GUSreset */
- GUSregb(GUS4cReset) = (GUSbyte) data;
- if (!(GUSregb(GUS4cReset) & 1)) /* reset... */
- {
- GUSregd(voicewavetableirq) = 0;
- GUSregd(voicevolrampirq) = 0;
- GUSregw(TimerIRQs) = 0;
- GUSregw(BusyTimerIRQs) = 0;
- GUSregb(NumVoices) = 0xcd;
- GUSregb(IRQStatReg2x6) = 0;
- GUSregb(TimerStatus2x8) = 0;
- GUSregb(AdLibData2x9) = 0;
- GUSregb(TimerDataReg2x9) = 0;
- GUSregb(GUS41DMACtrl) = 0;
- GUSregb(GUS45TimerCtrl) = 0;
- GUSregb(GUS49SampCtrl) = 0;
- GUSregb(GUS4cReset) &= 0xf9; /* clear IRQ and DAC enable bits */
- GUS_irqclear(state, state->gusirq);
- }
- /* IRQ enable bit checked elsewhere */
- /* EnableDAC bit may be used by external callers */
- break;
- }
- }
- break;
- case 0x307: /* DRAMaccess */
- {
- GUSbyte *adr;
- adr = state->himemaddr + (GUSregd(GUSDRAMPOS24bit) & 0xfffff);
- *adr = (GUSbyte) data;
- }
- break;
- }
-}
-
-/* Attention when breaking up a single DMA transfer to multiple ones:
- * it may lead to multiple terminal count interrupts and broken transfers:
- *
- * 1. Whenever you transfer a piece of data, the gusemu callback is invoked
- * 2. The callback may generate a TC irq (if the register was set up to do so)
- * 3. The irq may result in the program using the GUS to reprogram the GUS
- *
- * Some programs also decide to upload by just checking if TC occurs
- * (via interrupt or a cleared GUS dma flag)
- * and then start the next transfer, without checking DMA state
- *
- * Thus: Always make sure to set the TC flag correctly!
- *
- * Note that the genuine GUS had a granularity of 16 bytes/words for low/high DMA
- * while later cards had atomic granularity provided by an additional GUS50DMAHigh register
- * GUSemu also uses this register to support byte-granular transfers for better compatibility
- * with emulators other than GUSemu32
- */
-
-void gus_dma_transferdata(GUSEmuState * state, char *dma_addr, unsigned int count, int TC)
-{
- /* this function gets called by the callback function as soon as a DMA transfer is about to start
- * dma_addr is a translated address within accessible memory, not the physical one,
- * count is (real dma count register)+1
- * note that the amount of bytes transferred is fully determined by values in the DMA registers
- * do not forget to update DMA states after transferring the entire block:
- * DREQ cleared & TC asserted after the _whole_ transfer */
-
- char *srcaddr;
- char *destaddr;
- char msbmask = 0;
- GUSbyte *gusptr;
- gusptr = state->gusdatapos;
-
- srcaddr = dma_addr; /* system memory address */
- {
- int offset = (GUSregw(GUS42DMAStart) << 4) + (GUSregb(GUS50DMAHigh) & 0xf);
- if (state->gusdma >= 4)
- offset = (offset & 0xc0000) + (2 * (offset & 0x1fff0)); /* 16 bit address translation */
- destaddr = (char *) state->himemaddr + offset; /* wavetable RAM address */
- }
-
- GUSregw(GUS42DMAStart) += (GUSword) (count >> 4); /* ToDo: add 16bit GUS page limit? */
- GUSregb(GUS50DMAHigh) = (GUSbyte) ((count + GUSregb(GUS50DMAHigh)) & 0xf); /* ToDo: add 16bit GUS page limit? */
-
- if (GUSregb(GUS41DMACtrl) & 0x02) /* direction, 0 := sysram->gusram */
- {
- char *tmpaddr = destaddr;
- destaddr = srcaddr;
- srcaddr = tmpaddr;
- }
-
- if ((GUSregb(GUS41DMACtrl) & 0x80) && (!(GUSregb(GUS41DMACtrl) & 0x02)))
- msbmask = (const char) 0x80; /* invert MSB */
- for (; count > 0; count--)
- {
- if (GUSregb(GUS41DMACtrl) & 0x40)
- *(destaddr++) = *(srcaddr++); /* 16 bit lobyte */
- else
- *(destaddr++) = (msbmask ^ (*(srcaddr++))); /* 8 bit */
- if (state->gusdma >= 4)
- *(destaddr++) = (msbmask ^ (*(srcaddr++))); /* 16 bit hibyte */
- }
-
- if (TC)
- {
- (GUSregb(GUS41DMACtrl)) &= 0xfe; /* clear DMA request bit */
- if (GUSregb(GUS41DMACtrl) & 0x20) /* DMA terminal count IRQ */
- {
- GUSregb(IRQStatReg2x6) |= 0x80;
- GUS_irqrequest(state, state->gusirq, 1);
- }
- }
-}
diff --git a/qemu/hw/audio/gusemu_mixer.c b/qemu/hw/audio/gusemu_mixer.c
deleted file mode 100644
index 701e8fb0e..000000000
--- a/qemu/hw/audio/gusemu_mixer.c
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * GUSEMU32 - mixing engine (similar to Interwave GF1 compatibility)
- *
- * Copyright (C) 2000-2007 Tibor "TS" Schütz
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "gusemu.h"
-#include "gustate.h"
-
-#define GUSregb(position) (* (gusptr+(position)))
-#define GUSregw(position) (*(GUSword *) (gusptr+(position)))
-#define GUSregd(position) (*(GUSdword *)(gusptr+(position)))
-
-#define GUSvoice(position) (*(GUSword *)(voiceptr+(position)))
-
-/* samples are always 16bit stereo (4 bytes each, first right then left interleaved) */
-void gus_mixvoices(GUSEmuState * state, unsigned int playback_freq, unsigned int numsamples,
- GUSsample *bufferpos)
-{
- /* note that byte registers are stored in the upper half of each voice register! */
- GUSbyte *gusptr;
- int Voice;
- GUSword *voiceptr;
-
- unsigned int count;
- for (count = 0; count < numsamples * 2; count++)
- *(bufferpos + count) = 0; /* clear */
-
- gusptr = state->gusdatapos;
- voiceptr = (GUSword *) gusptr;
- if (!(GUSregb(GUS4cReset) & 0x01)) /* reset flag active? */
- return;
-
- for (Voice = 0; Voice <= (GUSregb(NumVoices) & 31); Voice++)
- {
- if (GUSvoice(wVSRControl) & 0x200)
- GUSvoice(wVSRControl) |= 0x100; /* voice stop request */
- if (GUSvoice(wVSRVolRampControl) & 0x200)
- GUSvoice(wVSRVolRampControl) |= 0x100; /* Volume ramp stop request */
- if (!(GUSvoice(wVSRControl) & GUSvoice(wVSRVolRampControl) & 0x100)) /* neither voice nor volume calculation active - save some time here ;) */
- {
- unsigned int sample;
-
- unsigned int LoopStart = (GUSvoice(wVSRLoopStartHi) << 16) | GUSvoice(wVSRLoopStartLo); /* 23.9 format */
- unsigned int LoopEnd = (GUSvoice(wVSRLoopEndHi) << 16) | GUSvoice(wVSRLoopEndLo); /* 23.9 format */
- unsigned int CurrPos = (GUSvoice(wVSRCurrPosHi) << 16) | GUSvoice(wVSRCurrPosLo); /* 23.9 format */
- int VoiceIncrement = ((((unsigned long) GUSvoice(wVSRFreq) * 44100) / playback_freq) * (14 >> 1)) /
- ((GUSregb(NumVoices) & 31) + 1); /* 6.10 increment/frame to 23.9 increment/sample */
-
- int PanningPos = (GUSvoice(wVSRPanning) >> 8) & 0xf;
-
- unsigned int Volume32 = 32 * GUSvoice(wVSRCurrVol); /* 32 times larger than original gus for maintaining precision while ramping */
- unsigned int StartVol32 = (GUSvoice(wVSRVolRampStartVol) & 0xff00) * 32;
- unsigned int EndVol32 = (GUSvoice(wVSRVolRampEndVol) & 0xff00) * 32;
- int VolumeIncrement32 = (32 * 16 * (GUSvoice(wVSRVolRampRate) & 0x3f00) >> 8) >> ((((GUSvoice(wVSRVolRampRate) & 0xc000) >> 8) >> 6) * 3); /* including 1/8/64/512 volume speed divisor */
- VolumeIncrement32 = (((VolumeIncrement32 * 44100 / 2) / playback_freq) * 14) / ((GUSregb(NumVoices) & 31) + 1); /* adjust ramping speed to playback speed */
-
- if (GUSvoice(wVSRControl) & 0x4000)
- VoiceIncrement = -VoiceIncrement; /* reverse playback */
- if (GUSvoice(wVSRVolRampControl) & 0x4000)
- VolumeIncrement32 = -VolumeIncrement32; /* reverse ramping */
-
- for (sample = 0; sample < numsamples; sample++)
- {
- int sample1, sample2, Volume;
- if (GUSvoice(wVSRControl) & 0x400) /* 16bit */
- {
- int offset = ((CurrPos >> 9) & 0xc0000) + (((CurrPos >> 9) & 0x1ffff) << 1);
- GUSchar *adr;
- adr = (GUSchar *) state->himemaddr + offset;
- sample1 = (*adr & 0xff) + (*(adr + 1) * 256);
- sample2 = (*(adr + 2) & 0xff) + (*(adr + 2 + 1) * 256);
- }
- else /* 8bit */
- {
- int offset = (CurrPos >> 9) & 0xfffff;
- GUSchar *adr;
- adr = (GUSchar *) state->himemaddr + offset;
- sample1 = (*adr) * 256;
- sample2 = (*(adr + 1)) * 256;
- }
-
- Volume = ((((Volume32 >> (4 + 5)) & 0xff) + 256) << (Volume32 >> ((4 + 8) + 5))) / 512; /* semi-logarithmic volume, +5 due to additional precision */
- sample1 = (((sample1 * Volume) >> 16) * (512 - (CurrPos % 512))) / 512;
- sample2 = (((sample2 * Volume) >> 16) * (CurrPos % 512)) / 512;
- sample1 += sample2;
-
- if (!(GUSvoice(wVSRVolRampControl) & 0x100))
- {
- Volume32 += VolumeIncrement32;
- if ((GUSvoice(wVSRVolRampControl) & 0x4000) ? (Volume32 <= StartVol32) : (Volume32 >= EndVol32)) /* ramp up boundary cross */
- {
- if (GUSvoice(wVSRVolRampControl) & 0x2000)
- GUSvoice(wVSRVolRampControl) |= 0x8000; /* volramp IRQ enabled? -> IRQ wait flag */
- if (GUSvoice(wVSRVolRampControl) & 0x800) /* loop enabled */
- {
- if (GUSvoice(wVSRVolRampControl) & 0x1000) /* bidir. loop */
- {
- GUSvoice(wVSRVolRampControl) ^= 0x4000; /* toggle dir */
- VolumeIncrement32 = -VolumeIncrement32;
- }
- else
- Volume32 = (GUSvoice(wVSRVolRampControl) & 0x4000) ? EndVol32 : StartVol32; /* unidir. loop ramp */
- }
- else
- {
- GUSvoice(wVSRVolRampControl) |= 0x100;
- Volume32 =
- (GUSvoice(wVSRVolRampControl) & 0x4000) ? StartVol32 : EndVol32;
- }
- }
- }
- if ((GUSvoice(wVSRVolRampControl) & 0xa000) == 0xa000) /* volramp IRQ set and enabled? */
- {
- GUSregd(voicevolrampirq) |= 1 << Voice; /* set irq slot */
- }
- else
- {
- GUSregd(voicevolrampirq) &= (~(1 << Voice)); /* clear irq slot */
- GUSvoice(wVSRVolRampControl) &= 0x7f00;
- }
-
- if (!(GUSvoice(wVSRControl) & 0x100))
- {
- CurrPos += VoiceIncrement;
- if ((GUSvoice(wVSRControl) & 0x4000) ? (CurrPos <= LoopStart) : (CurrPos >= LoopEnd)) /* playback boundary cross */
- {
- if (GUSvoice(wVSRControl) & 0x2000)
- GUSvoice(wVSRControl) |= 0x8000; /* voice IRQ enabled -> IRQ wait flag */
- if (GUSvoice(wVSRControl) & 0x800) /* loop enabled */
- {
- if (GUSvoice(wVSRControl) & 0x1000) /* pingpong loop */
- {
- GUSvoice(wVSRControl) ^= 0x4000; /* toggle dir */
- VoiceIncrement = -VoiceIncrement;
- }
- else
- CurrPos = (GUSvoice(wVSRControl) & 0x4000) ? LoopEnd : LoopStart; /* unidir. loop */
- }
- else if (!(GUSvoice(wVSRVolRampControl) & 0x400))
- GUSvoice(wVSRControl) |= 0x100; /* loop disabled, rollover check */
- }
- }
- if ((GUSvoice(wVSRControl) & 0xa000) == 0xa000) /* wavetable IRQ set and enabled? */
- {
- GUSregd(voicewavetableirq) |= 1 << Voice; /* set irq slot */
- }
- else
- {
- GUSregd(voicewavetableirq) &= (~(1 << Voice)); /* clear irq slot */
- GUSvoice(wVSRControl) &= 0x7f00;
- }
-
- /* mix samples into buffer */
- *(bufferpos + 2 * sample) += (GUSsample) ((sample1 * PanningPos) >> 4); /* right */
- *(bufferpos + 2 * sample + 1) += (GUSsample) ((sample1 * (15 - PanningPos)) >> 4); /* left */
- }
- /* write back voice and volume */
- GUSvoice(wVSRCurrVol) = Volume32 / 32;
- GUSvoice(wVSRCurrPosHi) = CurrPos >> 16;
- GUSvoice(wVSRCurrPosLo) = CurrPos & 0xffff;
- }
- voiceptr += 16; /* next voice */
- }
-}
-
-void gus_irqgen(GUSEmuState * state, unsigned int elapsed_time)
-/* time given in microseconds */
-{
- int requestedIRQs = 0;
- GUSbyte *gusptr;
- gusptr = state->gusdatapos;
- if (GUSregb(TimerDataReg2x9) & 1) /* start timer 1 (80us decrement rate) */
- {
- unsigned int timer1fraction = state->timer1fraction;
- int newtimerirqs;
- newtimerirqs = (elapsed_time + timer1fraction) / (80 * (256 - GUSregb(GUS46Counter1)));
- state->timer1fraction = (elapsed_time + timer1fraction) % (80 * (256 - GUSregb(GUS46Counter1)));
- if (newtimerirqs)
- {
- if (!(GUSregb(TimerDataReg2x9) & 0x40))
- GUSregb(TimerStatus2x8) |= 0xc0; /* maskable bits */
- if (GUSregb(GUS45TimerCtrl) & 4) /* timer1 irq enable */
- {
- GUSregb(TimerStatus2x8) |= 4; /* nonmaskable bit */
- GUSregb(IRQStatReg2x6) |= 4; /* timer 1 irq pending */
- GUSregw(TimerIRQs) += newtimerirqs;
- requestedIRQs += newtimerirqs;
- }
- }
- }
- if (GUSregb(TimerDataReg2x9) & 2) /* start timer 2 (320us decrement rate) */
- {
- unsigned int timer2fraction = state->timer2fraction;
- int newtimerirqs;
- newtimerirqs = (elapsed_time + timer2fraction) / (320 * (256 - GUSregb(GUS47Counter2)));
- state->timer2fraction = (elapsed_time + timer2fraction) % (320 * (256 - GUSregb(GUS47Counter2)));
- if (newtimerirqs)
- {
- if (!(GUSregb(TimerDataReg2x9) & 0x20))
- GUSregb(TimerStatus2x8) |= 0xa0; /* maskable bits */
- if (GUSregb(GUS45TimerCtrl) & 8) /* timer2 irq enable */
- {
- GUSregb(TimerStatus2x8) |= 2; /* nonmaskable bit */
- GUSregb(IRQStatReg2x6) |= 8; /* timer 2 irq pending */
- GUSregw(TimerIRQs) += newtimerirqs;
- requestedIRQs += newtimerirqs;
- }
- }
- }
- if (GUSregb(GUS4cReset) & 0x4) /* synth IRQ enable */
- {
- if (GUSregd(voicewavetableirq))
- GUSregb(IRQStatReg2x6) |= 0x20;
- if (GUSregd(voicevolrampirq))
- GUSregb(IRQStatReg2x6) |= 0x40;
- }
- if ((!requestedIRQs) && GUSregb(IRQStatReg2x6))
- requestedIRQs++;
- if (GUSregb(IRQStatReg2x6))
- GUSregw(BusyTimerIRQs) = GUS_irqrequest(state, state->gusirq, requestedIRQs);
-}
diff --git a/qemu/hw/audio/gustate.h b/qemu/hw/audio/gustate.h
deleted file mode 100644
index ece903abb..000000000
--- a/qemu/hw/audio/gustate.h
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * GUSEMU32 - persistent GUS register state
- *
- * Copyright (C) 2000-2007 Tibor "TS" Schütz
- *
- * 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.
- */
-
-#ifndef GUSTATE_H
-#define GUSTATE_H
-
-/*state block offset*/
-#define gusdata (0)
-
-/* data stored using this structure is in host byte order! */
-
-/*access type*/
-#define PortRead (0)
-#define PortWrite (1)
-
-#define Port8Bitacc (0)
-#define Port16Bitacc (1)
-
-/*voice register offsets (in bytes)*/
-#define VSRegs (0)
-#define VSRControl (0)
-#define VSRegsEnd (VSRControl+VSRegs + 32*(16*2))
-#define VSRFreq (2)
-#define VSRLoopStartHi (4)
-#define VSRLoopStartLo (6)
-#define VSRLoopEndHi (8)
-#define VSRLoopEndLo (10)
-#define VSRVolRampRate (12)
-#define VSRVolRampStartVol (14)
-#define VSRVolRampEndVol (16)
-#define VSRCurrVol (18)
-#define VSRCurrPosHi (20)
-#define VSRCurrPosLo (22)
-#define VSRPanning (24)
-#define VSRVolRampControl (26)
-
-/*voice register offsets (in words)*/
-#define wVSRegs (0)
-#define wVSRControl (0)
-#define wVSRegsEnd (wVSRControl+wVSRegs + 32*(16))
-#define wVSRFreq (1)
-#define wVSRLoopStartHi (2)
-#define wVSRLoopStartLo (3)
-#define wVSRLoopEndHi (4)
-#define wVSRLoopEndLo (5)
-#define wVSRVolRampRate (6)
-#define wVSRVolRampStartVol (7)
-#define wVSRVolRampEndVol (8)
-#define wVSRCurrVol (9)
-#define wVSRCurrPosHi (10)
-#define wVSRCurrPosLo (11)
-#define wVSRPanning (12)
-#define wVSRVolRampControl (13)
-
-/*GUS register state block: 32 voices, padding filled with remaining registers*/
-#define DataRegLoByte3x4 (VSRVolRampControl+2)
-#define DataRegWord3x4 (DataRegLoByte3x4)
-#define DataRegHiByte3x5 (VSRVolRampControl+2 +1)
-#define DMA_2xB (VSRVolRampControl+2+2)
-#define IRQ_2xB (VSRVolRampControl+2+3)
-
-#define RegCtrl_2xF (VSRVolRampControl+2+(16*2))
-#define Jumper_2xB (VSRVolRampControl+2+(16*2)+1)
-#define GUS42DMAStart (VSRVolRampControl+2+(16*2)+2)
-
-#define GUS43DRAMIOlo (VSRVolRampControl+2+(16*2)*2)
-#define GUSDRAMPOS24bit (GUS43DRAMIOlo)
-#define GUS44DRAMIOhi (VSRVolRampControl+2+(16*2)*2+2)
-
-#define voicewavetableirq (VSRVolRampControl+2+(16*2)*3) /* voice IRQ pseudoqueue: 1 bit per voice */
-
-#define voicevolrampirq (VSRVolRampControl+2+(16*2)*4) /* voice IRQ pseudoqueue: 1 bit per voice */
-
-#define startvoices (VSRVolRampControl+2+(16*2)*5) /* statistics / optimizations */
-
-#define IRQStatReg2x6 (VSRVolRampControl+2+(16*2)*6)
-#define TimerStatus2x8 (VSRVolRampControl+2+(16*2)*6+1)
-#define TimerDataReg2x9 (VSRVolRampControl+2+(16*2)*6+2)
-#define MixerCtrlReg2x0 (VSRVolRampControl+2+(16*2)*6+3)
-
-#define VoiceSelReg3x2 (VSRVolRampControl+2+(16*2)*7)
-#define FunkSelReg3x3 (VSRVolRampControl+2+(16*2)*7+1)
-#define AdLibStatus2x8 (VSRVolRampControl+2+(16*2)*7+2)
-#define StatRead_2xF (VSRVolRampControl+2+(16*2)*7+3)
-
-#define GUS48SampSpeed (VSRVolRampControl+2+(16*2)*8)
-#define GUS41DMACtrl (VSRVolRampControl+2+(16*2)*8+1)
-#define GUS45TimerCtrl (VSRVolRampControl+2+(16*2)*8+2)
-#define GUS46Counter1 (VSRVolRampControl+2+(16*2)*8+3)
-
-#define GUS47Counter2 (VSRVolRampControl+2+(16*2)*9)
-#define GUS49SampCtrl (VSRVolRampControl+2+(16*2)*9+1)
-#define GUS4cReset (VSRVolRampControl+2+(16*2)*9+2)
-#define NumVoices (VSRVolRampControl+2+(16*2)*9+3)
-
-#define TimerIRQs (VSRVolRampControl+2+(16*2)*10) /* delayed IRQ, statistics */
-#define BusyTimerIRQs (VSRVolRampControl+2+(16*2)*10+2) /* delayed IRQ, statistics */
-
-#define AdLibCommand2xA (VSRVolRampControl+2+(16*2)*11)
-#define AdLibData2x9 (VSRVolRampControl+2+(16*2)*11+1)
-#define SB2xCd (VSRVolRampControl+2+(16*2)*11+2)
-#define SB2xE (VSRVolRampControl+2+(16*2)*11+3)
-
-#define SynVoiceIRQ8f (VSRVolRampControl+2+(16*2)*12)
-#define GUS50DMAHigh (VSRVolRampControl+2+(16*2)*12+1)
-
-#define portaccesses (VSRegsEnd) /* statistics / suspend mode */
-
-#define gusdataend (VSRegsEnd+4)
-
-#endif /* gustate.h */
diff --git a/qemu/hw/audio/hda-codec-common.h b/qemu/hw/audio/hda-codec-common.h
deleted file mode 100644
index b4fdb51e8..000000000
--- a/qemu/hw/audio/hda-codec-common.h
+++ /dev/null
@@ -1,456 +0,0 @@
-/*
- * Common code to disable/enable mixer emulation at run time
- *
- * Copyright (C) 2013 Red Hat, Inc.
- *
- * Written by Bandan Das <bsd@redhat.com>
- * with important bits picked up from hda-codec.c
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * HDA codec descriptions
- */
-
-#ifdef HDA_MIXER
-#define QEMU_HDA_ID_OUTPUT ((QEMU_HDA_ID_VENDOR << 16) | 0x12)
-#define QEMU_HDA_ID_DUPLEX ((QEMU_HDA_ID_VENDOR << 16) | 0x22)
-#define QEMU_HDA_ID_MICRO ((QEMU_HDA_ID_VENDOR << 16) | 0x32)
-#define QEMU_HDA_AMP_CAPS \
- (AC_AMPCAP_MUTE | \
- (QEMU_HDA_AMP_STEPS << AC_AMPCAP_OFFSET_SHIFT) | \
- (QEMU_HDA_AMP_STEPS << AC_AMPCAP_NUM_STEPS_SHIFT) | \
- (3 << AC_AMPCAP_STEP_SIZE_SHIFT))
-#else
-#define QEMU_HDA_ID_OUTPUT ((QEMU_HDA_ID_VENDOR << 16) | 0x11)
-#define QEMU_HDA_ID_DUPLEX ((QEMU_HDA_ID_VENDOR << 16) | 0x21)
-#define QEMU_HDA_ID_MICRO ((QEMU_HDA_ID_VENDOR << 16) | 0x31)
-#define QEMU_HDA_AMP_CAPS QEMU_HDA_AMP_NONE
-#endif
-
-
-/* common: audio output widget */
-static const desc_param glue(common_params_audio_dac_, PARAM)[] = {
- {
- .id = AC_PAR_AUDIO_WIDGET_CAP,
- .val = ((AC_WID_AUD_OUT << AC_WCAP_TYPE_SHIFT) |
- AC_WCAP_FORMAT_OVRD |
- AC_WCAP_AMP_OVRD |
- AC_WCAP_OUT_AMP |
- AC_WCAP_STEREO),
- },{
- .id = AC_PAR_PCM,
- .val = QEMU_HDA_PCM_FORMATS,
- },{
- .id = AC_PAR_STREAM,
- .val = AC_SUPFMT_PCM,
- },{
- .id = AC_PAR_AMP_IN_CAP,
- .val = QEMU_HDA_AMP_NONE,
- },{
- .id = AC_PAR_AMP_OUT_CAP,
- .val = QEMU_HDA_AMP_CAPS,
- },
-};
-
-/* common: audio input widget */
-static const desc_param glue(common_params_audio_adc_, PARAM)[] = {
- {
- .id = AC_PAR_AUDIO_WIDGET_CAP,
- .val = ((AC_WID_AUD_IN << AC_WCAP_TYPE_SHIFT) |
- AC_WCAP_CONN_LIST |
- AC_WCAP_FORMAT_OVRD |
- AC_WCAP_AMP_OVRD |
- AC_WCAP_IN_AMP |
- AC_WCAP_STEREO),
- },{
- .id = AC_PAR_CONNLIST_LEN,
- .val = 1,
- },{
- .id = AC_PAR_PCM,
- .val = QEMU_HDA_PCM_FORMATS,
- },{
- .id = AC_PAR_STREAM,
- .val = AC_SUPFMT_PCM,
- },{
- .id = AC_PAR_AMP_IN_CAP,
- .val = QEMU_HDA_AMP_CAPS,
- },{
- .id = AC_PAR_AMP_OUT_CAP,
- .val = QEMU_HDA_AMP_NONE,
- },
-};
-
-/* common: pin widget (line-out) */
-static const desc_param glue(common_params_audio_lineout_, PARAM)[] = {
- {
- .id = AC_PAR_AUDIO_WIDGET_CAP,
- .val = ((AC_WID_PIN << AC_WCAP_TYPE_SHIFT) |
- AC_WCAP_CONN_LIST |
- AC_WCAP_STEREO),
- },{
- .id = AC_PAR_PIN_CAP,
- .val = AC_PINCAP_OUT,
- },{
- .id = AC_PAR_CONNLIST_LEN,
- .val = 1,
- },{
- .id = AC_PAR_AMP_IN_CAP,
- .val = QEMU_HDA_AMP_NONE,
- },{
- .id = AC_PAR_AMP_OUT_CAP,
- .val = QEMU_HDA_AMP_NONE,
- },
-};
-
-/* common: pin widget (line-in) */
-static const desc_param glue(common_params_audio_linein_, PARAM)[] = {
- {
- .id = AC_PAR_AUDIO_WIDGET_CAP,
- .val = ((AC_WID_PIN << AC_WCAP_TYPE_SHIFT) |
- AC_WCAP_STEREO),
- },{
- .id = AC_PAR_PIN_CAP,
- .val = AC_PINCAP_IN,
- },{
- .id = AC_PAR_AMP_IN_CAP,
- .val = QEMU_HDA_AMP_NONE,
- },{
- .id = AC_PAR_AMP_OUT_CAP,
- .val = QEMU_HDA_AMP_NONE,
- },
-};
-
-/* output: root node */
-static const desc_param glue(output_params_root_, PARAM)[] = {
- {
- .id = AC_PAR_VENDOR_ID,
- .val = QEMU_HDA_ID_OUTPUT,
- },{
- .id = AC_PAR_SUBSYSTEM_ID,
- .val = QEMU_HDA_ID_OUTPUT,
- },{
- .id = AC_PAR_REV_ID,
- .val = 0x00100101,
- },{
- .id = AC_PAR_NODE_COUNT,
- .val = 0x00010001,
- },
-};
-
-/* output: audio function */
-static const desc_param glue(output_params_audio_func_, PARAM)[] = {
- {
- .id = AC_PAR_FUNCTION_TYPE,
- .val = AC_GRP_AUDIO_FUNCTION,
- },{
- .id = AC_PAR_SUBSYSTEM_ID,
- .val = QEMU_HDA_ID_OUTPUT,
- },{
- .id = AC_PAR_NODE_COUNT,
- .val = 0x00020002,
- },{
- .id = AC_PAR_PCM,
- .val = QEMU_HDA_PCM_FORMATS,
- },{
- .id = AC_PAR_STREAM,
- .val = AC_SUPFMT_PCM,
- },{
- .id = AC_PAR_AMP_IN_CAP,
- .val = QEMU_HDA_AMP_NONE,
- },{
- .id = AC_PAR_AMP_OUT_CAP,
- .val = QEMU_HDA_AMP_NONE,
- },{
- .id = AC_PAR_GPIO_CAP,
- .val = 0,
- },{
- .id = AC_PAR_AUDIO_FG_CAP,
- .val = 0x00000808,
- },{
- .id = AC_PAR_POWER_STATE,
- .val = 0,
- },
-};
-
-/* output: nodes */
-static const desc_node glue(output_nodes_, PARAM)[] = {
- {
- .nid = AC_NODE_ROOT,
- .name = "root",
- .params = glue(output_params_root_, PARAM),
- .nparams = ARRAY_SIZE(glue(output_params_root_, PARAM)),
- },{
- .nid = 1,
- .name = "func",
- .params = glue(output_params_audio_func_, PARAM),
- .nparams = ARRAY_SIZE(glue(output_params_audio_func_, PARAM)),
- },{
- .nid = 2,
- .name = "dac",
- .params = glue(common_params_audio_dac_, PARAM),
- .nparams = ARRAY_SIZE(glue(common_params_audio_dac_, PARAM)),
- .stindex = 0,
- },{
- .nid = 3,
- .name = "out",
- .params = glue(common_params_audio_lineout_, PARAM),
- .nparams = ARRAY_SIZE(glue(common_params_audio_lineout_, PARAM)),
- .config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) |
- (AC_JACK_LINE_OUT << AC_DEFCFG_DEVICE_SHIFT) |
- (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) |
- (AC_JACK_COLOR_GREEN << AC_DEFCFG_COLOR_SHIFT) |
- 0x10),
- .pinctl = AC_PINCTL_OUT_EN,
- .conn = (uint32_t[]) { 2 },
- }
-};
-
-/* output: codec */
-static const desc_codec glue(output_, PARAM) = {
- .name = "output",
- .iid = QEMU_HDA_ID_OUTPUT,
- .nodes = glue(output_nodes_, PARAM),
- .nnodes = ARRAY_SIZE(glue(output_nodes_, PARAM)),
-};
-
-/* duplex: root node */
-static const desc_param glue(duplex_params_root_, PARAM)[] = {
- {
- .id = AC_PAR_VENDOR_ID,
- .val = QEMU_HDA_ID_DUPLEX,
- },{
- .id = AC_PAR_SUBSYSTEM_ID,
- .val = QEMU_HDA_ID_DUPLEX,
- },{
- .id = AC_PAR_REV_ID,
- .val = 0x00100101,
- },{
- .id = AC_PAR_NODE_COUNT,
- .val = 0x00010001,
- },
-};
-
-/* duplex: audio function */
-static const desc_param glue(duplex_params_audio_func_, PARAM)[] = {
- {
- .id = AC_PAR_FUNCTION_TYPE,
- .val = AC_GRP_AUDIO_FUNCTION,
- },{
- .id = AC_PAR_SUBSYSTEM_ID,
- .val = QEMU_HDA_ID_DUPLEX,
- },{
- .id = AC_PAR_NODE_COUNT,
- .val = 0x00020004,
- },{
- .id = AC_PAR_PCM,
- .val = QEMU_HDA_PCM_FORMATS,
- },{
- .id = AC_PAR_STREAM,
- .val = AC_SUPFMT_PCM,
- },{
- .id = AC_PAR_AMP_IN_CAP,
- .val = QEMU_HDA_AMP_NONE,
- },{
- .id = AC_PAR_AMP_OUT_CAP,
- .val = QEMU_HDA_AMP_NONE,
- },{
- .id = AC_PAR_GPIO_CAP,
- .val = 0,
- },{
- .id = AC_PAR_AUDIO_FG_CAP,
- .val = 0x00000808,
- },{
- .id = AC_PAR_POWER_STATE,
- .val = 0,
- },
-};
-
-/* duplex: nodes */
-static const desc_node glue(duplex_nodes_, PARAM)[] = {
- {
- .nid = AC_NODE_ROOT,
- .name = "root",
- .params = glue(duplex_params_root_, PARAM),
- .nparams = ARRAY_SIZE(glue(duplex_params_root_, PARAM)),
- },{
- .nid = 1,
- .name = "func",
- .params = glue(duplex_params_audio_func_, PARAM),
- .nparams = ARRAY_SIZE(glue(duplex_params_audio_func_, PARAM)),
- },{
- .nid = 2,
- .name = "dac",
- .params = glue(common_params_audio_dac_, PARAM),
- .nparams = ARRAY_SIZE(glue(common_params_audio_dac_, PARAM)),
- .stindex = 0,
- },{
- .nid = 3,
- .name = "out",
- .params = glue(common_params_audio_lineout_, PARAM),
- .nparams = ARRAY_SIZE(glue(common_params_audio_lineout_, PARAM)),
- .config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) |
- (AC_JACK_LINE_OUT << AC_DEFCFG_DEVICE_SHIFT) |
- (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) |
- (AC_JACK_COLOR_GREEN << AC_DEFCFG_COLOR_SHIFT) |
- 0x10),
- .pinctl = AC_PINCTL_OUT_EN,
- .conn = (uint32_t[]) { 2 },
- },{
- .nid = 4,
- .name = "adc",
- .params = glue(common_params_audio_adc_, PARAM),
- .nparams = ARRAY_SIZE(glue(common_params_audio_adc_, PARAM)),
- .stindex = 1,
- .conn = (uint32_t[]) { 5 },
- },{
- .nid = 5,
- .name = "in",
- .params = glue(common_params_audio_linein_, PARAM),
- .nparams = ARRAY_SIZE(glue(common_params_audio_linein_, PARAM)),
- .config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) |
- (AC_JACK_LINE_IN << AC_DEFCFG_DEVICE_SHIFT) |
- (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) |
- (AC_JACK_COLOR_RED << AC_DEFCFG_COLOR_SHIFT) |
- 0x20),
- .pinctl = AC_PINCTL_IN_EN,
- }
-};
-
-/* duplex: codec */
-static const desc_codec glue(duplex_, PARAM) = {
- .name = "duplex",
- .iid = QEMU_HDA_ID_DUPLEX,
- .nodes = glue(duplex_nodes_, PARAM),
- .nnodes = ARRAY_SIZE(glue(duplex_nodes_, PARAM)),
-};
-
-/* micro: root node */
-static const desc_param glue(micro_params_root_, PARAM)[] = {
- {
- .id = AC_PAR_VENDOR_ID,
- .val = QEMU_HDA_ID_MICRO,
- },{
- .id = AC_PAR_SUBSYSTEM_ID,
- .val = QEMU_HDA_ID_MICRO,
- },{
- .id = AC_PAR_REV_ID,
- .val = 0x00100101,
- },{
- .id = AC_PAR_NODE_COUNT,
- .val = 0x00010001,
- },
-};
-
-/* micro: audio function */
-static const desc_param glue(micro_params_audio_func_, PARAM)[] = {
- {
- .id = AC_PAR_FUNCTION_TYPE,
- .val = AC_GRP_AUDIO_FUNCTION,
- },{
- .id = AC_PAR_SUBSYSTEM_ID,
- .val = QEMU_HDA_ID_MICRO,
- },{
- .id = AC_PAR_NODE_COUNT,
- .val = 0x00020004,
- },{
- .id = AC_PAR_PCM,
- .val = QEMU_HDA_PCM_FORMATS,
- },{
- .id = AC_PAR_STREAM,
- .val = AC_SUPFMT_PCM,
- },{
- .id = AC_PAR_AMP_IN_CAP,
- .val = QEMU_HDA_AMP_NONE,
- },{
- .id = AC_PAR_AMP_OUT_CAP,
- .val = QEMU_HDA_AMP_NONE,
- },{
- .id = AC_PAR_GPIO_CAP,
- .val = 0,
- },{
- .id = AC_PAR_AUDIO_FG_CAP,
- .val = 0x00000808,
- },{
- .id = AC_PAR_POWER_STATE,
- .val = 0,
- },
-};
-
-/* micro: nodes */
-static const desc_node glue(micro_nodes_, PARAM)[] = {
- {
- .nid = AC_NODE_ROOT,
- .name = "root",
- .params = glue(micro_params_root_, PARAM),
- .nparams = ARRAY_SIZE(glue(micro_params_root_, PARAM)),
- },{
- .nid = 1,
- .name = "func",
- .params = glue(micro_params_audio_func_, PARAM),
- .nparams = ARRAY_SIZE(glue(micro_params_audio_func_, PARAM)),
- },{
- .nid = 2,
- .name = "dac",
- .params = glue(common_params_audio_dac_, PARAM),
- .nparams = ARRAY_SIZE(glue(common_params_audio_dac_, PARAM)),
- .stindex = 0,
- },{
- .nid = 3,
- .name = "out",
- .params = glue(common_params_audio_lineout_, PARAM),
- .nparams = ARRAY_SIZE(glue(common_params_audio_lineout_, PARAM)),
- .config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) |
- (AC_JACK_SPEAKER << AC_DEFCFG_DEVICE_SHIFT) |
- (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) |
- (AC_JACK_COLOR_GREEN << AC_DEFCFG_COLOR_SHIFT) |
- 0x10),
- .pinctl = AC_PINCTL_OUT_EN,
- .conn = (uint32_t[]) { 2 },
- },{
- .nid = 4,
- .name = "adc",
- .params = glue(common_params_audio_adc_, PARAM),
- .nparams = ARRAY_SIZE(glue(common_params_audio_adc_, PARAM)),
- .stindex = 1,
- .conn = (uint32_t[]) { 5 },
- },{
- .nid = 5,
- .name = "in",
- .params = glue(common_params_audio_linein_, PARAM),
- .nparams = ARRAY_SIZE(glue(common_params_audio_linein_, PARAM)),
- .config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) |
- (AC_JACK_MIC_IN << AC_DEFCFG_DEVICE_SHIFT) |
- (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) |
- (AC_JACK_COLOR_RED << AC_DEFCFG_COLOR_SHIFT) |
- 0x20),
- .pinctl = AC_PINCTL_IN_EN,
- }
-};
-
-/* micro: codec */
-static const desc_codec glue(micro_, PARAM) = {
- .name = "micro",
- .iid = QEMU_HDA_ID_MICRO,
- .nodes = glue(micro_nodes_, PARAM),
- .nnodes = ARRAY_SIZE(glue(micro_nodes_, PARAM)),
-};
-
-#undef PARAM
-#undef HDA_MIXER
-#undef QEMU_HDA_ID_OUTPUT
-#undef QEMU_HDA_ID_DUPLEX
-#undef QEMU_HDA_ID_MICRO
-#undef QEMU_HDA_AMP_CAPS
diff --git a/qemu/hw/audio/hda-codec.c b/qemu/hw/audio/hda-codec.c
deleted file mode 100644
index 52d4640e6..000000000
--- a/qemu/hw/audio/hda-codec.c
+++ /dev/null
@@ -1,732 +0,0 @@
-/*
- * Copyright (C) 2010 Red Hat, Inc.
- *
- * written by Gerd Hoffmann <kraxel@redhat.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/pci/pci.h"
-#include "intel-hda.h"
-#include "intel-hda-defs.h"
-#include "audio/audio.h"
-
-/* -------------------------------------------------------------------------- */
-
-typedef struct desc_param {
- uint32_t id;
- uint32_t val;
-} desc_param;
-
-typedef struct desc_node {
- uint32_t nid;
- const char *name;
- const desc_param *params;
- uint32_t nparams;
- uint32_t config;
- uint32_t pinctl;
- uint32_t *conn;
- uint32_t stindex;
-} desc_node;
-
-typedef struct desc_codec {
- const char *name;
- uint32_t iid;
- const desc_node *nodes;
- uint32_t nnodes;
-} desc_codec;
-
-static const desc_param* hda_codec_find_param(const desc_node *node, uint32_t id)
-{
- int i;
-
- for (i = 0; i < node->nparams; i++) {
- if (node->params[i].id == id) {
- return &node->params[i];
- }
- }
- return NULL;
-}
-
-static const desc_node* hda_codec_find_node(const desc_codec *codec, uint32_t nid)
-{
- int i;
-
- for (i = 0; i < codec->nnodes; i++) {
- if (codec->nodes[i].nid == nid) {
- return &codec->nodes[i];
- }
- }
- return NULL;
-}
-
-static void hda_codec_parse_fmt(uint32_t format, struct audsettings *as)
-{
- if (format & AC_FMT_TYPE_NON_PCM) {
- return;
- }
-
- as->freq = (format & AC_FMT_BASE_44K) ? 44100 : 48000;
-
- switch ((format & AC_FMT_MULT_MASK) >> AC_FMT_MULT_SHIFT) {
- case 1: as->freq *= 2; break;
- case 2: as->freq *= 3; break;
- case 3: as->freq *= 4; break;
- }
-
- switch ((format & AC_FMT_DIV_MASK) >> AC_FMT_DIV_SHIFT) {
- case 1: as->freq /= 2; break;
- case 2: as->freq /= 3; break;
- case 3: as->freq /= 4; break;
- case 4: as->freq /= 5; break;
- case 5: as->freq /= 6; break;
- case 6: as->freq /= 7; break;
- case 7: as->freq /= 8; break;
- }
-
- switch (format & AC_FMT_BITS_MASK) {
- case AC_FMT_BITS_8: as->fmt = AUD_FMT_S8; break;
- case AC_FMT_BITS_16: as->fmt = AUD_FMT_S16; break;
- case AC_FMT_BITS_32: as->fmt = AUD_FMT_S32; break;
- }
-
- as->nchannels = ((format & AC_FMT_CHAN_MASK) >> AC_FMT_CHAN_SHIFT) + 1;
-}
-
-/* -------------------------------------------------------------------------- */
-/*
- * HDA codec descriptions
- */
-
-/* some defines */
-
-#define QEMU_HDA_ID_VENDOR 0x1af4
-#define QEMU_HDA_PCM_FORMATS (AC_SUPPCM_BITS_16 | \
- 0x1fc /* 16 -> 96 kHz */)
-#define QEMU_HDA_AMP_NONE (0)
-#define QEMU_HDA_AMP_STEPS 0x4a
-
-#define PARAM mixemu
-#define HDA_MIXER
-#include "hda-codec-common.h"
-
-#define PARAM nomixemu
-#include "hda-codec-common.h"
-
-/* -------------------------------------------------------------------------- */
-
-static const char *fmt2name[] = {
- [ AUD_FMT_U8 ] = "PCM-U8",
- [ AUD_FMT_S8 ] = "PCM-S8",
- [ AUD_FMT_U16 ] = "PCM-U16",
- [ AUD_FMT_S16 ] = "PCM-S16",
- [ AUD_FMT_U32 ] = "PCM-U32",
- [ AUD_FMT_S32 ] = "PCM-S32",
-};
-
-typedef struct HDAAudioState HDAAudioState;
-typedef struct HDAAudioStream HDAAudioStream;
-
-struct HDAAudioStream {
- HDAAudioState *state;
- const desc_node *node;
- bool output, running;
- uint32_t stream;
- uint32_t channel;
- uint32_t format;
- uint32_t gain_left, gain_right;
- bool mute_left, mute_right;
- struct audsettings as;
- union {
- SWVoiceIn *in;
- SWVoiceOut *out;
- } voice;
- uint8_t buf[HDA_BUFFER_SIZE];
- uint32_t bpos;
-};
-
-#define TYPE_HDA_AUDIO "hda-audio"
-#define HDA_AUDIO(obj) OBJECT_CHECK(HDAAudioState, (obj), TYPE_HDA_AUDIO)
-
-struct HDAAudioState {
- HDACodecDevice hda;
- const char *name;
-
- QEMUSoundCard card;
- const desc_codec *desc;
- HDAAudioStream st[4];
- bool running_compat[16];
- bool running_real[2 * 16];
-
- /* properties */
- uint32_t debug;
- bool mixer;
-};
-
-static void hda_audio_input_cb(void *opaque, int avail)
-{
- HDAAudioStream *st = opaque;
- int recv = 0;
- int len;
- bool rc;
-
- while (avail - recv >= sizeof(st->buf)) {
- if (st->bpos != sizeof(st->buf)) {
- len = AUD_read(st->voice.in, st->buf + st->bpos,
- sizeof(st->buf) - st->bpos);
- st->bpos += len;
- recv += len;
- if (st->bpos != sizeof(st->buf)) {
- break;
- }
- }
- rc = hda_codec_xfer(&st->state->hda, st->stream, false,
- st->buf, sizeof(st->buf));
- if (!rc) {
- break;
- }
- st->bpos = 0;
- }
-}
-
-static void hda_audio_output_cb(void *opaque, int avail)
-{
- HDAAudioStream *st = opaque;
- int sent = 0;
- int len;
- bool rc;
-
- while (avail - sent >= sizeof(st->buf)) {
- if (st->bpos == sizeof(st->buf)) {
- rc = hda_codec_xfer(&st->state->hda, st->stream, true,
- st->buf, sizeof(st->buf));
- if (!rc) {
- break;
- }
- st->bpos = 0;
- }
- len = AUD_write(st->voice.out, st->buf + st->bpos,
- sizeof(st->buf) - st->bpos);
- st->bpos += len;
- sent += len;
- if (st->bpos != sizeof(st->buf)) {
- break;
- }
- }
-}
-
-static void hda_audio_set_running(HDAAudioStream *st, bool running)
-{
- if (st->node == NULL) {
- return;
- }
- if (st->running == running) {
- return;
- }
- st->running = running;
- dprint(st->state, 1, "%s: %s (stream %d)\n", st->node->name,
- st->running ? "on" : "off", st->stream);
- if (st->output) {
- AUD_set_active_out(st->voice.out, st->running);
- } else {
- AUD_set_active_in(st->voice.in, st->running);
- }
-}
-
-static void hda_audio_set_amp(HDAAudioStream *st)
-{
- bool muted;
- uint32_t left, right;
-
- if (st->node == NULL) {
- return;
- }
-
- muted = st->mute_left && st->mute_right;
- left = st->mute_left ? 0 : st->gain_left;
- right = st->mute_right ? 0 : st->gain_right;
-
- left = left * 255 / QEMU_HDA_AMP_STEPS;
- right = right * 255 / QEMU_HDA_AMP_STEPS;
-
- if (!st->state->mixer) {
- return;
- }
- if (st->output) {
- AUD_set_volume_out(st->voice.out, muted, left, right);
- } else {
- AUD_set_volume_in(st->voice.in, muted, left, right);
- }
-}
-
-static void hda_audio_setup(HDAAudioStream *st)
-{
- if (st->node == NULL) {
- return;
- }
-
- dprint(st->state, 1, "%s: format: %d x %s @ %d Hz\n",
- st->node->name, st->as.nchannels,
- fmt2name[st->as.fmt], st->as.freq);
-
- if (st->output) {
- st->voice.out = AUD_open_out(&st->state->card, st->voice.out,
- st->node->name, st,
- hda_audio_output_cb, &st->as);
- } else {
- st->voice.in = AUD_open_in(&st->state->card, st->voice.in,
- st->node->name, st,
- hda_audio_input_cb, &st->as);
- }
-}
-
-static void hda_audio_command(HDACodecDevice *hda, uint32_t nid, uint32_t data)
-{
- HDAAudioState *a = HDA_AUDIO(hda);
- HDAAudioStream *st;
- const desc_node *node = NULL;
- const desc_param *param;
- uint32_t verb, payload, response, count, shift;
-
- if ((data & 0x70000) == 0x70000) {
- /* 12/8 id/payload */
- verb = (data >> 8) & 0xfff;
- payload = data & 0x00ff;
- } else {
- /* 4/16 id/payload */
- verb = (data >> 8) & 0xf00;
- payload = data & 0xffff;
- }
-
- node = hda_codec_find_node(a->desc, nid);
- if (node == NULL) {
- goto fail;
- }
- dprint(a, 2, "%s: nid %d (%s), verb 0x%x, payload 0x%x\n",
- __FUNCTION__, nid, node->name, verb, payload);
-
- switch (verb) {
- /* all nodes */
- case AC_VERB_PARAMETERS:
- param = hda_codec_find_param(node, payload);
- if (param == NULL) {
- goto fail;
- }
- hda_codec_response(hda, true, param->val);
- break;
- case AC_VERB_GET_SUBSYSTEM_ID:
- hda_codec_response(hda, true, a->desc->iid);
- break;
-
- /* all functions */
- case AC_VERB_GET_CONNECT_LIST:
- param = hda_codec_find_param(node, AC_PAR_CONNLIST_LEN);
- count = param ? param->val : 0;
- response = 0;
- shift = 0;
- while (payload < count && shift < 32) {
- response |= node->conn[payload] << shift;
- payload++;
- shift += 8;
- }
- hda_codec_response(hda, true, response);
- break;
-
- /* pin widget */
- case AC_VERB_GET_CONFIG_DEFAULT:
- hda_codec_response(hda, true, node->config);
- break;
- case AC_VERB_GET_PIN_WIDGET_CONTROL:
- hda_codec_response(hda, true, node->pinctl);
- break;
- case AC_VERB_SET_PIN_WIDGET_CONTROL:
- if (node->pinctl != payload) {
- dprint(a, 1, "unhandled pin control bit\n");
- }
- hda_codec_response(hda, true, 0);
- break;
-
- /* audio in/out widget */
- case AC_VERB_SET_CHANNEL_STREAMID:
- st = a->st + node->stindex;
- if (st->node == NULL) {
- goto fail;
- }
- hda_audio_set_running(st, false);
- st->stream = (payload >> 4) & 0x0f;
- st->channel = payload & 0x0f;
- dprint(a, 2, "%s: stream %d, channel %d\n",
- st->node->name, st->stream, st->channel);
- hda_audio_set_running(st, a->running_real[st->output * 16 + st->stream]);
- hda_codec_response(hda, true, 0);
- break;
- case AC_VERB_GET_CONV:
- st = a->st + node->stindex;
- if (st->node == NULL) {
- goto fail;
- }
- response = st->stream << 4 | st->channel;
- hda_codec_response(hda, true, response);
- break;
- case AC_VERB_SET_STREAM_FORMAT:
- st = a->st + node->stindex;
- if (st->node == NULL) {
- goto fail;
- }
- st->format = payload;
- hda_codec_parse_fmt(st->format, &st->as);
- hda_audio_setup(st);
- hda_codec_response(hda, true, 0);
- break;
- case AC_VERB_GET_STREAM_FORMAT:
- st = a->st + node->stindex;
- if (st->node == NULL) {
- goto fail;
- }
- hda_codec_response(hda, true, st->format);
- break;
- case AC_VERB_GET_AMP_GAIN_MUTE:
- st = a->st + node->stindex;
- if (st->node == NULL) {
- goto fail;
- }
- if (payload & AC_AMP_GET_LEFT) {
- response = st->gain_left | (st->mute_left ? AC_AMP_MUTE : 0);
- } else {
- response = st->gain_right | (st->mute_right ? AC_AMP_MUTE : 0);
- }
- hda_codec_response(hda, true, response);
- break;
- case AC_VERB_SET_AMP_GAIN_MUTE:
- st = a->st + node->stindex;
- if (st->node == NULL) {
- goto fail;
- }
- dprint(a, 1, "amp (%s): %s%s%s%s index %d gain %3d %s\n",
- st->node->name,
- (payload & AC_AMP_SET_OUTPUT) ? "o" : "-",
- (payload & AC_AMP_SET_INPUT) ? "i" : "-",
- (payload & AC_AMP_SET_LEFT) ? "l" : "-",
- (payload & AC_AMP_SET_RIGHT) ? "r" : "-",
- (payload & AC_AMP_SET_INDEX) >> AC_AMP_SET_INDEX_SHIFT,
- (payload & AC_AMP_GAIN),
- (payload & AC_AMP_MUTE) ? "muted" : "");
- if (payload & AC_AMP_SET_LEFT) {
- st->gain_left = payload & AC_AMP_GAIN;
- st->mute_left = payload & AC_AMP_MUTE;
- }
- if (payload & AC_AMP_SET_RIGHT) {
- st->gain_right = payload & AC_AMP_GAIN;
- st->mute_right = payload & AC_AMP_MUTE;
- }
- hda_audio_set_amp(st);
- hda_codec_response(hda, true, 0);
- break;
-
- /* not supported */
- case AC_VERB_SET_POWER_STATE:
- case AC_VERB_GET_POWER_STATE:
- case AC_VERB_GET_SDI_SELECT:
- hda_codec_response(hda, true, 0);
- break;
- default:
- goto fail;
- }
- return;
-
-fail:
- dprint(a, 1, "%s: not handled: nid %d (%s), verb 0x%x, payload 0x%x\n",
- __FUNCTION__, nid, node ? node->name : "?", verb, payload);
- hda_codec_response(hda, true, 0);
-}
-
-static void hda_audio_stream(HDACodecDevice *hda, uint32_t stnr, bool running, bool output)
-{
- HDAAudioState *a = HDA_AUDIO(hda);
- int s;
-
- a->running_compat[stnr] = running;
- a->running_real[output * 16 + stnr] = running;
- for (s = 0; s < ARRAY_SIZE(a->st); s++) {
- if (a->st[s].node == NULL) {
- continue;
- }
- if (a->st[s].output != output) {
- continue;
- }
- if (a->st[s].stream != stnr) {
- continue;
- }
- hda_audio_set_running(&a->st[s], running);
- }
-}
-
-static int hda_audio_init(HDACodecDevice *hda, const struct desc_codec *desc)
-{
- HDAAudioState *a = HDA_AUDIO(hda);
- HDAAudioStream *st;
- const desc_node *node;
- const desc_param *param;
- uint32_t i, type;
-
- a->desc = desc;
- a->name = object_get_typename(OBJECT(a));
- dprint(a, 1, "%s: cad %d\n", __FUNCTION__, a->hda.cad);
-
- AUD_register_card("hda", &a->card);
- for (i = 0; i < a->desc->nnodes; i++) {
- node = a->desc->nodes + i;
- param = hda_codec_find_param(node, AC_PAR_AUDIO_WIDGET_CAP);
- if (param == NULL) {
- continue;
- }
- type = (param->val & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
- switch (type) {
- case AC_WID_AUD_OUT:
- case AC_WID_AUD_IN:
- assert(node->stindex < ARRAY_SIZE(a->st));
- st = a->st + node->stindex;
- st->state = a;
- st->node = node;
- if (type == AC_WID_AUD_OUT) {
- /* unmute output by default */
- st->gain_left = QEMU_HDA_AMP_STEPS;
- st->gain_right = QEMU_HDA_AMP_STEPS;
- st->bpos = sizeof(st->buf);
- st->output = true;
- } else {
- st->output = false;
- }
- st->format = AC_FMT_TYPE_PCM | AC_FMT_BITS_16 |
- (1 << AC_FMT_CHAN_SHIFT);
- hda_codec_parse_fmt(st->format, &st->as);
- hda_audio_setup(st);
- break;
- }
- }
- return 0;
-}
-
-static int hda_audio_exit(HDACodecDevice *hda)
-{
- HDAAudioState *a = HDA_AUDIO(hda);
- HDAAudioStream *st;
- int i;
-
- dprint(a, 1, "%s\n", __FUNCTION__);
- for (i = 0; i < ARRAY_SIZE(a->st); i++) {
- st = a->st + i;
- if (st->node == NULL) {
- continue;
- }
- if (st->output) {
- AUD_close_out(&a->card, st->voice.out);
- } else {
- AUD_close_in(&a->card, st->voice.in);
- }
- }
- AUD_remove_card(&a->card);
- return 0;
-}
-
-static int hda_audio_post_load(void *opaque, int version)
-{
- HDAAudioState *a = opaque;
- HDAAudioStream *st;
- int i;
-
- dprint(a, 1, "%s\n", __FUNCTION__);
- if (version == 1) {
- /* assume running_compat[] is for output streams */
- for (i = 0; i < ARRAY_SIZE(a->running_compat); i++)
- a->running_real[16 + i] = a->running_compat[i];
- }
-
- for (i = 0; i < ARRAY_SIZE(a->st); i++) {
- st = a->st + i;
- if (st->node == NULL)
- continue;
- hda_codec_parse_fmt(st->format, &st->as);
- hda_audio_setup(st);
- hda_audio_set_amp(st);
- hda_audio_set_running(st, a->running_real[st->output * 16 + st->stream]);
- }
- return 0;
-}
-
-static void hda_audio_reset(DeviceState *dev)
-{
- HDAAudioState *a = HDA_AUDIO(dev);
- HDAAudioStream *st;
- int i;
-
- dprint(a, 1, "%s\n", __func__);
- for (i = 0; i < ARRAY_SIZE(a->st); i++) {
- st = a->st + i;
- if (st->node != NULL) {
- hda_audio_set_running(st, false);
- }
- }
-}
-
-static const VMStateDescription vmstate_hda_audio_stream = {
- .name = "hda-audio-stream",
- .version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(stream, HDAAudioStream),
- VMSTATE_UINT32(channel, HDAAudioStream),
- VMSTATE_UINT32(format, HDAAudioStream),
- VMSTATE_UINT32(gain_left, HDAAudioStream),
- VMSTATE_UINT32(gain_right, HDAAudioStream),
- VMSTATE_BOOL(mute_left, HDAAudioStream),
- VMSTATE_BOOL(mute_right, HDAAudioStream),
- VMSTATE_UINT32(bpos, HDAAudioStream),
- VMSTATE_BUFFER(buf, HDAAudioStream),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_hda_audio = {
- .name = "hda-audio",
- .version_id = 2,
- .post_load = hda_audio_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT_ARRAY(st, HDAAudioState, 4, 0,
- vmstate_hda_audio_stream,
- HDAAudioStream),
- VMSTATE_BOOL_ARRAY(running_compat, HDAAudioState, 16),
- VMSTATE_BOOL_ARRAY_V(running_real, HDAAudioState, 2 * 16, 2),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property hda_audio_properties[] = {
- DEFINE_PROP_UINT32("debug", HDAAudioState, debug, 0),
- DEFINE_PROP_BOOL("mixer", HDAAudioState, mixer, true),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static int hda_audio_init_output(HDACodecDevice *hda)
-{
- HDAAudioState *a = HDA_AUDIO(hda);
-
- if (!a->mixer) {
- return hda_audio_init(hda, &output_nomixemu);
- } else {
- return hda_audio_init(hda, &output_mixemu);
- }
-}
-
-static int hda_audio_init_duplex(HDACodecDevice *hda)
-{
- HDAAudioState *a = HDA_AUDIO(hda);
-
- if (!a->mixer) {
- return hda_audio_init(hda, &duplex_nomixemu);
- } else {
- return hda_audio_init(hda, &duplex_mixemu);
- }
-}
-
-static int hda_audio_init_micro(HDACodecDevice *hda)
-{
- HDAAudioState *a = HDA_AUDIO(hda);
-
- if (!a->mixer) {
- return hda_audio_init(hda, &micro_nomixemu);
- } else {
- return hda_audio_init(hda, &micro_mixemu);
- }
-}
-
-static void hda_audio_base_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass);
-
- k->exit = hda_audio_exit;
- k->command = hda_audio_command;
- k->stream = hda_audio_stream;
- set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
- dc->reset = hda_audio_reset;
- dc->vmsd = &vmstate_hda_audio;
- dc->props = hda_audio_properties;
-}
-
-static const TypeInfo hda_audio_info = {
- .name = TYPE_HDA_AUDIO,
- .parent = TYPE_HDA_CODEC_DEVICE,
- .class_init = hda_audio_base_class_init,
- .abstract = true,
-};
-
-static void hda_audio_output_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass);
-
- k->init = hda_audio_init_output;
- dc->desc = "HDA Audio Codec, output-only (line-out)";
-}
-
-static const TypeInfo hda_audio_output_info = {
- .name = "hda-output",
- .parent = TYPE_HDA_AUDIO,
- .instance_size = sizeof(HDAAudioState),
- .class_init = hda_audio_output_class_init,
-};
-
-static void hda_audio_duplex_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass);
-
- k->init = hda_audio_init_duplex;
- dc->desc = "HDA Audio Codec, duplex (line-out, line-in)";
-}
-
-static const TypeInfo hda_audio_duplex_info = {
- .name = "hda-duplex",
- .parent = TYPE_HDA_AUDIO,
- .instance_size = sizeof(HDAAudioState),
- .class_init = hda_audio_duplex_class_init,
-};
-
-static void hda_audio_micro_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass);
-
- k->init = hda_audio_init_micro;
- dc->desc = "HDA Audio Codec, duplex (speaker, microphone)";
-}
-
-static const TypeInfo hda_audio_micro_info = {
- .name = "hda-micro",
- .parent = TYPE_HDA_AUDIO,
- .instance_size = sizeof(HDAAudioState),
- .class_init = hda_audio_micro_class_init,
-};
-
-static void hda_audio_register_types(void)
-{
- type_register_static(&hda_audio_info);
- type_register_static(&hda_audio_output_info);
- type_register_static(&hda_audio_duplex_info);
- type_register_static(&hda_audio_micro_info);
-}
-
-type_init(hda_audio_register_types)
diff --git a/qemu/hw/audio/intel-hda-defs.h b/qemu/hw/audio/intel-hda-defs.h
deleted file mode 100644
index 2e37e5b87..000000000
--- a/qemu/hw/audio/intel-hda-defs.h
+++ /dev/null
@@ -1,717 +0,0 @@
-#ifndef HW_INTEL_HDA_DEFS_H
-#define HW_INTEL_HDA_DEFS_H
-
-/* qemu */
-#define HDA_BUFFER_SIZE 256
-
-/* --------------------------------------------------------------------- */
-/* from linux/sound/pci/hda/hda_intel.c */
-
-/*
- * registers
- */
-#define ICH6_REG_GCAP 0x00
-#define ICH6_GCAP_64OK (1 << 0) /* 64bit address support */
-#define ICH6_GCAP_NSDO (3 << 1) /* # of serial data out signals */
-#define ICH6_GCAP_BSS (31 << 3) /* # of bidirectional streams */
-#define ICH6_GCAP_ISS (15 << 8) /* # of input streams */
-#define ICH6_GCAP_OSS (15 << 12) /* # of output streams */
-#define ICH6_REG_VMIN 0x02
-#define ICH6_REG_VMAJ 0x03
-#define ICH6_REG_OUTPAY 0x04
-#define ICH6_REG_INPAY 0x06
-#define ICH6_REG_GCTL 0x08
-#define ICH6_GCTL_RESET (1 << 0) /* controller reset */
-#define ICH6_GCTL_FCNTRL (1 << 1) /* flush control */
-#define ICH6_GCTL_UNSOL (1 << 8) /* accept unsol. response enable */
-#define ICH6_REG_WAKEEN 0x0c
-#define ICH6_REG_STATESTS 0x0e
-#define ICH6_REG_GSTS 0x10
-#define ICH6_GSTS_FSTS (1 << 1) /* flush status */
-#define ICH6_REG_INTCTL 0x20
-#define ICH6_REG_INTSTS 0x24
-#define ICH6_REG_WALLCLK 0x30 /* 24Mhz source */
-#define ICH6_REG_SYNC 0x34
-#define ICH6_REG_CORBLBASE 0x40
-#define ICH6_REG_CORBUBASE 0x44
-#define ICH6_REG_CORBWP 0x48
-#define ICH6_REG_CORBRP 0x4a
-#define ICH6_CORBRP_RST (1 << 15) /* read pointer reset */
-#define ICH6_REG_CORBCTL 0x4c
-#define ICH6_CORBCTL_RUN (1 << 1) /* enable DMA */
-#define ICH6_CORBCTL_CMEIE (1 << 0) /* enable memory error irq */
-#define ICH6_REG_CORBSTS 0x4d
-#define ICH6_CORBSTS_CMEI (1 << 0) /* memory error indication */
-#define ICH6_REG_CORBSIZE 0x4e
-
-#define ICH6_REG_RIRBLBASE 0x50
-#define ICH6_REG_RIRBUBASE 0x54
-#define ICH6_REG_RIRBWP 0x58
-#define ICH6_RIRBWP_RST (1 << 15) /* write pointer reset */
-#define ICH6_REG_RINTCNT 0x5a
-#define ICH6_REG_RIRBCTL 0x5c
-#define ICH6_RBCTL_IRQ_EN (1 << 0) /* enable IRQ */
-#define ICH6_RBCTL_DMA_EN (1 << 1) /* enable DMA */
-#define ICH6_RBCTL_OVERRUN_EN (1 << 2) /* enable overrun irq */
-#define ICH6_REG_RIRBSTS 0x5d
-#define ICH6_RBSTS_IRQ (1 << 0) /* response irq */
-#define ICH6_RBSTS_OVERRUN (1 << 2) /* overrun irq */
-#define ICH6_REG_RIRBSIZE 0x5e
-
-#define ICH6_REG_IC 0x60
-#define ICH6_REG_IR 0x64
-#define ICH6_REG_IRS 0x68
-#define ICH6_IRS_VALID (1<<1)
-#define ICH6_IRS_BUSY (1<<0)
-
-#define ICH6_REG_DPLBASE 0x70
-#define ICH6_REG_DPUBASE 0x74
-#define ICH6_DPLBASE_ENABLE 0x1 /* Enable position buffer */
-
-/* SD offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
-enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
-
-/* stream register offsets from stream base */
-#define ICH6_REG_SD_CTL 0x00
-#define ICH6_REG_SD_STS 0x03
-#define ICH6_REG_SD_LPIB 0x04
-#define ICH6_REG_SD_CBL 0x08
-#define ICH6_REG_SD_LVI 0x0c
-#define ICH6_REG_SD_FIFOW 0x0e
-#define ICH6_REG_SD_FIFOSIZE 0x10
-#define ICH6_REG_SD_FORMAT 0x12
-#define ICH6_REG_SD_BDLPL 0x18
-#define ICH6_REG_SD_BDLPU 0x1c
-
-/* PCI space */
-#define ICH6_PCIREG_TCSEL 0x44
-
-/*
- * other constants
- */
-
-/* max number of SDs */
-/* ICH, ATI and VIA have 4 playback and 4 capture */
-#define ICH6_NUM_CAPTURE 4
-#define ICH6_NUM_PLAYBACK 4
-
-/* ULI has 6 playback and 5 capture */
-#define ULI_NUM_CAPTURE 5
-#define ULI_NUM_PLAYBACK 6
-
-/* ATI HDMI has 1 playback and 0 capture */
-#define ATIHDMI_NUM_CAPTURE 0
-#define ATIHDMI_NUM_PLAYBACK 1
-
-/* TERA has 4 playback and 3 capture */
-#define TERA_NUM_CAPTURE 3
-#define TERA_NUM_PLAYBACK 4
-
-/* this number is statically defined for simplicity */
-#define MAX_AZX_DEV 16
-
-/* max number of fragments - we may use more if allocating more pages for BDL */
-#define BDL_SIZE 4096
-#define AZX_MAX_BDL_ENTRIES (BDL_SIZE / 16)
-#define AZX_MAX_FRAG 32
-/* max buffer size - no h/w limit, you can increase as you like */
-#define AZX_MAX_BUF_SIZE (1024*1024*1024)
-
-/* RIRB int mask: overrun[2], response[0] */
-#define RIRB_INT_RESPONSE 0x01
-#define RIRB_INT_OVERRUN 0x04
-#define RIRB_INT_MASK 0x05
-
-/* STATESTS int mask: S3,SD2,SD1,SD0 */
-#define AZX_MAX_CODECS 8
-#define AZX_DEFAULT_CODECS 4
-#define STATESTS_INT_MASK ((1 << AZX_MAX_CODECS) - 1)
-
-/* SD_CTL bits */
-#define SD_CTL_STREAM_RESET 0x01 /* stream reset bit */
-#define SD_CTL_DMA_START 0x02 /* stream DMA start bit */
-#define SD_CTL_STRIPE (3 << 16) /* stripe control */
-#define SD_CTL_TRAFFIC_PRIO (1 << 18) /* traffic priority */
-#define SD_CTL_DIR (1 << 19) /* bi-directional stream */
-#define SD_CTL_STREAM_TAG_MASK (0xf << 20)
-#define SD_CTL_STREAM_TAG_SHIFT 20
-
-/* SD_CTL and SD_STS */
-#define SD_INT_DESC_ERR 0x10 /* descriptor error interrupt */
-#define SD_INT_FIFO_ERR 0x08 /* FIFO error interrupt */
-#define SD_INT_COMPLETE 0x04 /* completion interrupt */
-#define SD_INT_MASK (SD_INT_DESC_ERR|SD_INT_FIFO_ERR|\
- SD_INT_COMPLETE)
-
-/* SD_STS */
-#define SD_STS_FIFO_READY 0x20 /* FIFO ready */
-
-/* INTCTL and INTSTS */
-#define ICH6_INT_ALL_STREAM 0xff /* all stream interrupts */
-#define ICH6_INT_CTRL_EN 0x40000000 /* controller interrupt enable bit */
-#define ICH6_INT_GLOBAL_EN 0x80000000 /* global interrupt enable bit */
-
-/* below are so far hardcoded - should read registers in future */
-#define ICH6_MAX_CORB_ENTRIES 256
-#define ICH6_MAX_RIRB_ENTRIES 256
-
-/* position fix mode */
-enum {
- POS_FIX_AUTO,
- POS_FIX_LPIB,
- POS_FIX_POSBUF,
-};
-
-/* Defines for ATI HD Audio support in SB450 south bridge */
-#define ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR 0x42
-#define ATI_SB450_HDAUDIO_ENABLE_SNOOP 0x02
-
-/* Defines for Nvidia HDA support */
-#define NVIDIA_HDA_TRANSREG_ADDR 0x4e
-#define NVIDIA_HDA_ENABLE_COHBITS 0x0f
-#define NVIDIA_HDA_ISTRM_COH 0x4d
-#define NVIDIA_HDA_OSTRM_COH 0x4c
-#define NVIDIA_HDA_ENABLE_COHBIT 0x01
-
-/* Defines for Intel SCH HDA snoop control */
-#define INTEL_SCH_HDA_DEVC 0x78
-#define INTEL_SCH_HDA_DEVC_NOSNOOP (0x1<<11)
-
-/* Define IN stream 0 FIFO size offset in VIA controller */
-#define VIA_IN_STREAM0_FIFO_SIZE_OFFSET 0x90
-/* Define VIA HD Audio Device ID*/
-#define VIA_HDAC_DEVICE_ID 0x3288
-
-/* HD Audio class code */
-#define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403
-
-/* --------------------------------------------------------------------- */
-/* from linux/sound/pci/hda/hda_codec.h */
-
-/*
- * nodes
- */
-#define AC_NODE_ROOT 0x00
-
-/*
- * function group types
- */
-enum {
- AC_GRP_AUDIO_FUNCTION = 0x01,
- AC_GRP_MODEM_FUNCTION = 0x02,
-};
-
-/*
- * widget types
- */
-enum {
- AC_WID_AUD_OUT, /* Audio Out */
- AC_WID_AUD_IN, /* Audio In */
- AC_WID_AUD_MIX, /* Audio Mixer */
- AC_WID_AUD_SEL, /* Audio Selector */
- AC_WID_PIN, /* Pin Complex */
- AC_WID_POWER, /* Power */
- AC_WID_VOL_KNB, /* Volume Knob */
- AC_WID_BEEP, /* Beep Generator */
- AC_WID_VENDOR = 0x0f /* Vendor specific */
-};
-
-/*
- * GET verbs
- */
-#define AC_VERB_GET_STREAM_FORMAT 0x0a00
-#define AC_VERB_GET_AMP_GAIN_MUTE 0x0b00
-#define AC_VERB_GET_PROC_COEF 0x0c00
-#define AC_VERB_GET_COEF_INDEX 0x0d00
-#define AC_VERB_PARAMETERS 0x0f00
-#define AC_VERB_GET_CONNECT_SEL 0x0f01
-#define AC_VERB_GET_CONNECT_LIST 0x0f02
-#define AC_VERB_GET_PROC_STATE 0x0f03
-#define AC_VERB_GET_SDI_SELECT 0x0f04
-#define AC_VERB_GET_POWER_STATE 0x0f05
-#define AC_VERB_GET_CONV 0x0f06
-#define AC_VERB_GET_PIN_WIDGET_CONTROL 0x0f07
-#define AC_VERB_GET_UNSOLICITED_RESPONSE 0x0f08
-#define AC_VERB_GET_PIN_SENSE 0x0f09
-#define AC_VERB_GET_BEEP_CONTROL 0x0f0a
-#define AC_VERB_GET_EAPD_BTLENABLE 0x0f0c
-#define AC_VERB_GET_DIGI_CONVERT_1 0x0f0d
-#define AC_VERB_GET_DIGI_CONVERT_2 0x0f0e /* unused */
-#define AC_VERB_GET_VOLUME_KNOB_CONTROL 0x0f0f
-/* f10-f1a: GPIO */
-#define AC_VERB_GET_GPIO_DATA 0x0f15
-#define AC_VERB_GET_GPIO_MASK 0x0f16
-#define AC_VERB_GET_GPIO_DIRECTION 0x0f17
-#define AC_VERB_GET_GPIO_WAKE_MASK 0x0f18
-#define AC_VERB_GET_GPIO_UNSOLICITED_RSP_MASK 0x0f19
-#define AC_VERB_GET_GPIO_STICKY_MASK 0x0f1a
-#define AC_VERB_GET_CONFIG_DEFAULT 0x0f1c
-/* f20: AFG/MFG */
-#define AC_VERB_GET_SUBSYSTEM_ID 0x0f20
-#define AC_VERB_GET_CVT_CHAN_COUNT 0x0f2d
-#define AC_VERB_GET_HDMI_DIP_SIZE 0x0f2e
-#define AC_VERB_GET_HDMI_ELDD 0x0f2f
-#define AC_VERB_GET_HDMI_DIP_INDEX 0x0f30
-#define AC_VERB_GET_HDMI_DIP_DATA 0x0f31
-#define AC_VERB_GET_HDMI_DIP_XMIT 0x0f32
-#define AC_VERB_GET_HDMI_CP_CTRL 0x0f33
-#define AC_VERB_GET_HDMI_CHAN_SLOT 0x0f34
-
-/*
- * SET verbs
- */
-#define AC_VERB_SET_STREAM_FORMAT 0x200
-#define AC_VERB_SET_AMP_GAIN_MUTE 0x300
-#define AC_VERB_SET_PROC_COEF 0x400
-#define AC_VERB_SET_COEF_INDEX 0x500
-#define AC_VERB_SET_CONNECT_SEL 0x701
-#define AC_VERB_SET_PROC_STATE 0x703
-#define AC_VERB_SET_SDI_SELECT 0x704
-#define AC_VERB_SET_POWER_STATE 0x705
-#define AC_VERB_SET_CHANNEL_STREAMID 0x706
-#define AC_VERB_SET_PIN_WIDGET_CONTROL 0x707
-#define AC_VERB_SET_UNSOLICITED_ENABLE 0x708
-#define AC_VERB_SET_PIN_SENSE 0x709
-#define AC_VERB_SET_BEEP_CONTROL 0x70a
-#define AC_VERB_SET_EAPD_BTLENABLE 0x70c
-#define AC_VERB_SET_DIGI_CONVERT_1 0x70d
-#define AC_VERB_SET_DIGI_CONVERT_2 0x70e
-#define AC_VERB_SET_VOLUME_KNOB_CONTROL 0x70f
-#define AC_VERB_SET_GPIO_DATA 0x715
-#define AC_VERB_SET_GPIO_MASK 0x716
-#define AC_VERB_SET_GPIO_DIRECTION 0x717
-#define AC_VERB_SET_GPIO_WAKE_MASK 0x718
-#define AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK 0x719
-#define AC_VERB_SET_GPIO_STICKY_MASK 0x71a
-#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 0x71c
-#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_1 0x71d
-#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_2 0x71e
-#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_3 0x71f
-#define AC_VERB_SET_EAPD 0x788
-#define AC_VERB_SET_CODEC_RESET 0x7ff
-#define AC_VERB_SET_CVT_CHAN_COUNT 0x72d
-#define AC_VERB_SET_HDMI_DIP_INDEX 0x730
-#define AC_VERB_SET_HDMI_DIP_DATA 0x731
-#define AC_VERB_SET_HDMI_DIP_XMIT 0x732
-#define AC_VERB_SET_HDMI_CP_CTRL 0x733
-#define AC_VERB_SET_HDMI_CHAN_SLOT 0x734
-
-/*
- * Parameter IDs
- */
-#define AC_PAR_VENDOR_ID 0x00
-#define AC_PAR_SUBSYSTEM_ID 0x01
-#define AC_PAR_REV_ID 0x02
-#define AC_PAR_NODE_COUNT 0x04
-#define AC_PAR_FUNCTION_TYPE 0x05
-#define AC_PAR_AUDIO_FG_CAP 0x08
-#define AC_PAR_AUDIO_WIDGET_CAP 0x09
-#define AC_PAR_PCM 0x0a
-#define AC_PAR_STREAM 0x0b
-#define AC_PAR_PIN_CAP 0x0c
-#define AC_PAR_AMP_IN_CAP 0x0d
-#define AC_PAR_CONNLIST_LEN 0x0e
-#define AC_PAR_POWER_STATE 0x0f
-#define AC_PAR_PROC_CAP 0x10
-#define AC_PAR_GPIO_CAP 0x11
-#define AC_PAR_AMP_OUT_CAP 0x12
-#define AC_PAR_VOL_KNB_CAP 0x13
-#define AC_PAR_HDMI_LPCM_CAP 0x20
-
-/*
- * AC_VERB_PARAMETERS results (32bit)
- */
-
-/* Function Group Type */
-#define AC_FGT_TYPE (0xff<<0)
-#define AC_FGT_TYPE_SHIFT 0
-#define AC_FGT_UNSOL_CAP (1<<8)
-
-/* Audio Function Group Capabilities */
-#define AC_AFG_OUT_DELAY (0xf<<0)
-#define AC_AFG_IN_DELAY (0xf<<8)
-#define AC_AFG_BEEP_GEN (1<<16)
-
-/* Audio Widget Capabilities */
-#define AC_WCAP_STEREO (1<<0) /* stereo I/O */
-#define AC_WCAP_IN_AMP (1<<1) /* AMP-in present */
-#define AC_WCAP_OUT_AMP (1<<2) /* AMP-out present */
-#define AC_WCAP_AMP_OVRD (1<<3) /* AMP-parameter override */
-#define AC_WCAP_FORMAT_OVRD (1<<4) /* format override */
-#define AC_WCAP_STRIPE (1<<5) /* stripe */
-#define AC_WCAP_PROC_WID (1<<6) /* Proc Widget */
-#define AC_WCAP_UNSOL_CAP (1<<7) /* Unsol capable */
-#define AC_WCAP_CONN_LIST (1<<8) /* connection list */
-#define AC_WCAP_DIGITAL (1<<9) /* digital I/O */
-#define AC_WCAP_POWER (1<<10) /* power control */
-#define AC_WCAP_LR_SWAP (1<<11) /* L/R swap */
-#define AC_WCAP_CP_CAPS (1<<12) /* content protection */
-#define AC_WCAP_CHAN_CNT_EXT (7<<13) /* channel count ext */
-#define AC_WCAP_DELAY (0xf<<16)
-#define AC_WCAP_DELAY_SHIFT 16
-#define AC_WCAP_TYPE (0xf<<20)
-#define AC_WCAP_TYPE_SHIFT 20
-
-/* supported PCM rates and bits */
-#define AC_SUPPCM_RATES (0xfff << 0)
-#define AC_SUPPCM_BITS_8 (1<<16)
-#define AC_SUPPCM_BITS_16 (1<<17)
-#define AC_SUPPCM_BITS_20 (1<<18)
-#define AC_SUPPCM_BITS_24 (1<<19)
-#define AC_SUPPCM_BITS_32 (1<<20)
-
-/* supported PCM stream format */
-#define AC_SUPFMT_PCM (1<<0)
-#define AC_SUPFMT_FLOAT32 (1<<1)
-#define AC_SUPFMT_AC3 (1<<2)
-
-/* GP I/O count */
-#define AC_GPIO_IO_COUNT (0xff<<0)
-#define AC_GPIO_O_COUNT (0xff<<8)
-#define AC_GPIO_O_COUNT_SHIFT 8
-#define AC_GPIO_I_COUNT (0xff<<16)
-#define AC_GPIO_I_COUNT_SHIFT 16
-#define AC_GPIO_UNSOLICITED (1<<30)
-#define AC_GPIO_WAKE (1<<31)
-
-/* Converter stream, channel */
-#define AC_CONV_CHANNEL (0xf<<0)
-#define AC_CONV_STREAM (0xf<<4)
-#define AC_CONV_STREAM_SHIFT 4
-
-/* Input converter SDI select */
-#define AC_SDI_SELECT (0xf<<0)
-
-/* stream format id */
-#define AC_FMT_CHAN_SHIFT 0
-#define AC_FMT_CHAN_MASK (0x0f << 0)
-#define AC_FMT_BITS_SHIFT 4
-#define AC_FMT_BITS_MASK (7 << 4)
-#define AC_FMT_BITS_8 (0 << 4)
-#define AC_FMT_BITS_16 (1 << 4)
-#define AC_FMT_BITS_20 (2 << 4)
-#define AC_FMT_BITS_24 (3 << 4)
-#define AC_FMT_BITS_32 (4 << 4)
-#define AC_FMT_DIV_SHIFT 8
-#define AC_FMT_DIV_MASK (7 << 8)
-#define AC_FMT_MULT_SHIFT 11
-#define AC_FMT_MULT_MASK (7 << 11)
-#define AC_FMT_BASE_SHIFT 14
-#define AC_FMT_BASE_48K (0 << 14)
-#define AC_FMT_BASE_44K (1 << 14)
-#define AC_FMT_TYPE_SHIFT 15
-#define AC_FMT_TYPE_PCM (0 << 15)
-#define AC_FMT_TYPE_NON_PCM (1 << 15)
-
-/* Unsolicited response control */
-#define AC_UNSOL_TAG (0x3f<<0)
-#define AC_UNSOL_ENABLED (1<<7)
-#define AC_USRSP_EN AC_UNSOL_ENABLED
-
-/* Unsolicited responses */
-#define AC_UNSOL_RES_TAG (0x3f<<26)
-#define AC_UNSOL_RES_TAG_SHIFT 26
-#define AC_UNSOL_RES_SUBTAG (0x1f<<21)
-#define AC_UNSOL_RES_SUBTAG_SHIFT 21
-#define AC_UNSOL_RES_ELDV (1<<1) /* ELD Data valid (for HDMI) */
-#define AC_UNSOL_RES_PD (1<<0) /* pinsense detect */
-#define AC_UNSOL_RES_CP_STATE (1<<1) /* content protection */
-#define AC_UNSOL_RES_CP_READY (1<<0) /* content protection */
-
-/* Pin widget capabilies */
-#define AC_PINCAP_IMP_SENSE (1<<0) /* impedance sense capable */
-#define AC_PINCAP_TRIG_REQ (1<<1) /* trigger required */
-#define AC_PINCAP_PRES_DETECT (1<<2) /* presence detect capable */
-#define AC_PINCAP_HP_DRV (1<<3) /* headphone drive capable */
-#define AC_PINCAP_OUT (1<<4) /* output capable */
-#define AC_PINCAP_IN (1<<5) /* input capable */
-#define AC_PINCAP_BALANCE (1<<6) /* balanced I/O capable */
-/* Note: This LR_SWAP pincap is defined in the Realtek ALC883 specification,
- * but is marked reserved in the Intel HDA specification.
- */
-#define AC_PINCAP_LR_SWAP (1<<7) /* L/R swap */
-/* Note: The same bit as LR_SWAP is newly defined as HDMI capability
- * in HD-audio specification
- */
-#define AC_PINCAP_HDMI (1<<7) /* HDMI pin */
-#define AC_PINCAP_DP (1<<24) /* DisplayPort pin, can
- * coexist with AC_PINCAP_HDMI
- */
-#define AC_PINCAP_VREF (0x37<<8)
-#define AC_PINCAP_VREF_SHIFT 8
-#define AC_PINCAP_EAPD (1<<16) /* EAPD capable */
-#define AC_PINCAP_HBR (1<<27) /* High Bit Rate */
-/* Vref status (used in pin cap) */
-#define AC_PINCAP_VREF_HIZ (1<<0) /* Hi-Z */
-#define AC_PINCAP_VREF_50 (1<<1) /* 50% */
-#define AC_PINCAP_VREF_GRD (1<<2) /* ground */
-#define AC_PINCAP_VREF_80 (1<<4) /* 80% */
-#define AC_PINCAP_VREF_100 (1<<5) /* 100% */
-
-/* Amplifier capabilities */
-#define AC_AMPCAP_OFFSET (0x7f<<0) /* 0dB offset */
-#define AC_AMPCAP_OFFSET_SHIFT 0
-#define AC_AMPCAP_NUM_STEPS (0x7f<<8) /* number of steps */
-#define AC_AMPCAP_NUM_STEPS_SHIFT 8
-#define AC_AMPCAP_STEP_SIZE (0x7f<<16) /* step size 0-32dB
- * in 0.25dB
- */
-#define AC_AMPCAP_STEP_SIZE_SHIFT 16
-#define AC_AMPCAP_MUTE (1<<31) /* mute capable */
-#define AC_AMPCAP_MUTE_SHIFT 31
-
-/* Connection list */
-#define AC_CLIST_LENGTH (0x7f<<0)
-#define AC_CLIST_LONG (1<<7)
-
-/* Supported power status */
-#define AC_PWRST_D0SUP (1<<0)
-#define AC_PWRST_D1SUP (1<<1)
-#define AC_PWRST_D2SUP (1<<2)
-#define AC_PWRST_D3SUP (1<<3)
-#define AC_PWRST_D3COLDSUP (1<<4)
-#define AC_PWRST_S3D3COLDSUP (1<<29)
-#define AC_PWRST_CLKSTOP (1<<30)
-#define AC_PWRST_EPSS (1U<<31)
-
-/* Power state values */
-#define AC_PWRST_SETTING (0xf<<0)
-#define AC_PWRST_ACTUAL (0xf<<4)
-#define AC_PWRST_ACTUAL_SHIFT 4
-#define AC_PWRST_D0 0x00
-#define AC_PWRST_D1 0x01
-#define AC_PWRST_D2 0x02
-#define AC_PWRST_D3 0x03
-
-/* Processing capabilies */
-#define AC_PCAP_BENIGN (1<<0)
-#define AC_PCAP_NUM_COEF (0xff<<8)
-#define AC_PCAP_NUM_COEF_SHIFT 8
-
-/* Volume knobs capabilities */
-#define AC_KNBCAP_NUM_STEPS (0x7f<<0)
-#define AC_KNBCAP_DELTA (1<<7)
-
-/* HDMI LPCM capabilities */
-#define AC_LPCMCAP_48K_CP_CHNS (0x0f<<0) /* max channels w/ CP-on */
-#define AC_LPCMCAP_48K_NO_CHNS (0x0f<<4) /* max channels w/o CP-on */
-#define AC_LPCMCAP_48K_20BIT (1<<8) /* 20b bitrate supported */
-#define AC_LPCMCAP_48K_24BIT (1<<9) /* 24b bitrate supported */
-#define AC_LPCMCAP_96K_CP_CHNS (0x0f<<10) /* max channels w/ CP-on */
-#define AC_LPCMCAP_96K_NO_CHNS (0x0f<<14) /* max channels w/o CP-on */
-#define AC_LPCMCAP_96K_20BIT (1<<18) /* 20b bitrate supported */
-#define AC_LPCMCAP_96K_24BIT (1<<19) /* 24b bitrate supported */
-#define AC_LPCMCAP_192K_CP_CHNS (0x0f<<20) /* max channels w/ CP-on */
-#define AC_LPCMCAP_192K_NO_CHNS (0x0f<<24) /* max channels w/o CP-on */
-#define AC_LPCMCAP_192K_20BIT (1<<28) /* 20b bitrate supported */
-#define AC_LPCMCAP_192K_24BIT (1<<29) /* 24b bitrate supported */
-#define AC_LPCMCAP_44K (1<<30) /* 44.1kHz support */
-#define AC_LPCMCAP_44K_MS (1<<31) /* 44.1kHz-multiplies support */
-
-/*
- * Control Parameters
- */
-
-/* Amp gain/mute */
-#define AC_AMP_MUTE (1<<7)
-#define AC_AMP_GAIN (0x7f)
-#define AC_AMP_GET_INDEX (0xf<<0)
-
-#define AC_AMP_GET_LEFT (1<<13)
-#define AC_AMP_GET_RIGHT (0<<13)
-#define AC_AMP_GET_OUTPUT (1<<15)
-#define AC_AMP_GET_INPUT (0<<15)
-
-#define AC_AMP_SET_INDEX (0xf<<8)
-#define AC_AMP_SET_INDEX_SHIFT 8
-#define AC_AMP_SET_RIGHT (1<<12)
-#define AC_AMP_SET_LEFT (1<<13)
-#define AC_AMP_SET_INPUT (1<<14)
-#define AC_AMP_SET_OUTPUT (1<<15)
-
-/* DIGITAL1 bits */
-#define AC_DIG1_ENABLE (1<<0)
-#define AC_DIG1_V (1<<1)
-#define AC_DIG1_VCFG (1<<2)
-#define AC_DIG1_EMPHASIS (1<<3)
-#define AC_DIG1_COPYRIGHT (1<<4)
-#define AC_DIG1_NONAUDIO (1<<5)
-#define AC_DIG1_PROFESSIONAL (1<<6)
-#define AC_DIG1_LEVEL (1<<7)
-
-/* DIGITAL2 bits */
-#define AC_DIG2_CC (0x7f<<0)
-
-/* Pin widget control - 8bit */
-#define AC_PINCTL_EPT (0x3<<0)
-#define AC_PINCTL_EPT_NATIVE 0
-#define AC_PINCTL_EPT_HBR 3
-#define AC_PINCTL_VREFEN (0x7<<0)
-#define AC_PINCTL_VREF_HIZ 0 /* Hi-Z */
-#define AC_PINCTL_VREF_50 1 /* 50% */
-#define AC_PINCTL_VREF_GRD 2 /* ground */
-#define AC_PINCTL_VREF_80 4 /* 80% */
-#define AC_PINCTL_VREF_100 5 /* 100% */
-#define AC_PINCTL_IN_EN (1<<5)
-#define AC_PINCTL_OUT_EN (1<<6)
-#define AC_PINCTL_HP_EN (1<<7)
-
-/* Pin sense - 32bit */
-#define AC_PINSENSE_IMPEDANCE_MASK (0x7fffffff)
-#define AC_PINSENSE_PRESENCE (1<<31)
-#define AC_PINSENSE_ELDV (1<<30) /* ELD valid (HDMI) */
-
-/* EAPD/BTL enable - 32bit */
-#define AC_EAPDBTL_BALANCED (1<<0)
-#define AC_EAPDBTL_EAPD (1<<1)
-#define AC_EAPDBTL_LR_SWAP (1<<2)
-
-/* HDMI ELD data */
-#define AC_ELDD_ELD_VALID (1<<31)
-#define AC_ELDD_ELD_DATA 0xff
-
-/* HDMI DIP size */
-#define AC_DIPSIZE_ELD_BUF (1<<3) /* ELD buf size of packet size */
-#define AC_DIPSIZE_PACK_IDX (0x07<<0) /* packet index */
-
-/* HDMI DIP index */
-#define AC_DIPIDX_PACK_IDX (0x07<<5) /* packet idnex */
-#define AC_DIPIDX_BYTE_IDX (0x1f<<0) /* byte index */
-
-/* HDMI DIP xmit (transmit) control */
-#define AC_DIPXMIT_MASK (0x3<<6)
-#define AC_DIPXMIT_DISABLE (0x0<<6) /* disable xmit */
-#define AC_DIPXMIT_ONCE (0x2<<6) /* xmit once then disable */
-#define AC_DIPXMIT_BEST (0x3<<6) /* best effort */
-
-/* HDMI content protection (CP) control */
-#define AC_CPCTRL_CES (1<<9) /* current encryption state */
-#define AC_CPCTRL_READY (1<<8) /* ready bit */
-#define AC_CPCTRL_SUBTAG (0x1f<<3) /* subtag for unsol-resp */
-#define AC_CPCTRL_STATE (3<<0) /* current CP request state */
-
-/* Converter channel <-> HDMI slot mapping */
-#define AC_CVTMAP_HDMI_SLOT (0xf<<0) /* HDMI slot number */
-#define AC_CVTMAP_CHAN (0xf<<4) /* converter channel number */
-
-/* configuration default - 32bit */
-#define AC_DEFCFG_SEQUENCE (0xf<<0)
-#define AC_DEFCFG_DEF_ASSOC (0xf<<4)
-#define AC_DEFCFG_ASSOC_SHIFT 4
-#define AC_DEFCFG_MISC (0xf<<8)
-#define AC_DEFCFG_MISC_SHIFT 8
-#define AC_DEFCFG_MISC_NO_PRESENCE (1<<0)
-#define AC_DEFCFG_COLOR (0xf<<12)
-#define AC_DEFCFG_COLOR_SHIFT 12
-#define AC_DEFCFG_CONN_TYPE (0xf<<16)
-#define AC_DEFCFG_CONN_TYPE_SHIFT 16
-#define AC_DEFCFG_DEVICE (0xf<<20)
-#define AC_DEFCFG_DEVICE_SHIFT 20
-#define AC_DEFCFG_LOCATION (0x3f<<24)
-#define AC_DEFCFG_LOCATION_SHIFT 24
-#define AC_DEFCFG_PORT_CONN (0x3<<30)
-#define AC_DEFCFG_PORT_CONN_SHIFT 30
-
-/* device device types (0x0-0xf) */
-enum {
- AC_JACK_LINE_OUT,
- AC_JACK_SPEAKER,
- AC_JACK_HP_OUT,
- AC_JACK_CD,
- AC_JACK_SPDIF_OUT,
- AC_JACK_DIG_OTHER_OUT,
- AC_JACK_MODEM_LINE_SIDE,
- AC_JACK_MODEM_HAND_SIDE,
- AC_JACK_LINE_IN,
- AC_JACK_AUX,
- AC_JACK_MIC_IN,
- AC_JACK_TELEPHONY,
- AC_JACK_SPDIF_IN,
- AC_JACK_DIG_OTHER_IN,
- AC_JACK_OTHER = 0xf,
-};
-
-/* jack connection types (0x0-0xf) */
-enum {
- AC_JACK_CONN_UNKNOWN,
- AC_JACK_CONN_1_8,
- AC_JACK_CONN_1_4,
- AC_JACK_CONN_ATAPI,
- AC_JACK_CONN_RCA,
- AC_JACK_CONN_OPTICAL,
- AC_JACK_CONN_OTHER_DIGITAL,
- AC_JACK_CONN_OTHER_ANALOG,
- AC_JACK_CONN_DIN,
- AC_JACK_CONN_XLR,
- AC_JACK_CONN_RJ11,
- AC_JACK_CONN_COMB,
- AC_JACK_CONN_OTHER = 0xf,
-};
-
-/* jack colors (0x0-0xf) */
-enum {
- AC_JACK_COLOR_UNKNOWN,
- AC_JACK_COLOR_BLACK,
- AC_JACK_COLOR_GREY,
- AC_JACK_COLOR_BLUE,
- AC_JACK_COLOR_GREEN,
- AC_JACK_COLOR_RED,
- AC_JACK_COLOR_ORANGE,
- AC_JACK_COLOR_YELLOW,
- AC_JACK_COLOR_PURPLE,
- AC_JACK_COLOR_PINK,
- AC_JACK_COLOR_WHITE = 0xe,
- AC_JACK_COLOR_OTHER,
-};
-
-/* Jack location (0x0-0x3f) */
-/* common case */
-enum {
- AC_JACK_LOC_NONE,
- AC_JACK_LOC_REAR,
- AC_JACK_LOC_FRONT,
- AC_JACK_LOC_LEFT,
- AC_JACK_LOC_RIGHT,
- AC_JACK_LOC_TOP,
- AC_JACK_LOC_BOTTOM,
-};
-/* bits 4-5 */
-enum {
- AC_JACK_LOC_EXTERNAL = 0x00,
- AC_JACK_LOC_INTERNAL = 0x10,
- AC_JACK_LOC_SEPARATE = 0x20,
- AC_JACK_LOC_OTHER = 0x30,
-};
-enum {
- /* external on primary chasis */
- AC_JACK_LOC_REAR_PANEL = 0x07,
- AC_JACK_LOC_DRIVE_BAY,
- /* internal */
- AC_JACK_LOC_RISER = 0x17,
- AC_JACK_LOC_HDMI,
- AC_JACK_LOC_ATAPI,
- /* others */
- AC_JACK_LOC_MOBILE_IN = 0x37,
- AC_JACK_LOC_MOBILE_OUT,
-};
-
-/* Port connectivity (0-3) */
-enum {
- AC_JACK_PORT_COMPLEX,
- AC_JACK_PORT_NONE,
- AC_JACK_PORT_FIXED,
- AC_JACK_PORT_BOTH,
-};
-
-/* max. connections to a widget */
-#define HDA_MAX_CONNECTIONS 32
-
-/* max. codec address */
-#define HDA_MAX_CODEC_ADDRESS 0x0f
-
-/* max number of PCM devics per card */
-#define HDA_MAX_PCMS 10
-
-/* --------------------------------------------------------------------- */
-
-#endif
diff --git a/qemu/hw/audio/intel-hda.c b/qemu/hw/audio/intel-hda.c
deleted file mode 100644
index d372d4ab9..000000000
--- a/qemu/hw/audio/intel-hda.c
+++ /dev/null
@@ -1,1344 +0,0 @@
-/*
- * Copyright (C) 2010 Red Hat, Inc.
- *
- * written by Gerd Hoffmann <kraxel@redhat.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/msi.h"
-#include "qemu/timer.h"
-#include "hw/audio/audio.h"
-#include "intel-hda.h"
-#include "intel-hda-defs.h"
-#include "sysemu/dma.h"
-
-/* --------------------------------------------------------------------- */
-/* hda bus */
-
-static Property hda_props[] = {
- DEFINE_PROP_UINT32("cad", HDACodecDevice, cad, -1),
- DEFINE_PROP_END_OF_LIST()
-};
-
-static const TypeInfo hda_codec_bus_info = {
- .name = TYPE_HDA_BUS,
- .parent = TYPE_BUS,
- .instance_size = sizeof(HDACodecBus),
-};
-
-void hda_codec_bus_init(DeviceState *dev, HDACodecBus *bus, size_t bus_size,
- hda_codec_response_func response,
- hda_codec_xfer_func xfer)
-{
- qbus_create_inplace(bus, bus_size, TYPE_HDA_BUS, dev, NULL);
- bus->response = response;
- bus->xfer = xfer;
-}
-
-static int hda_codec_dev_init(DeviceState *qdev)
-{
- HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, qdev->parent_bus);
- HDACodecDevice *dev = DO_UPCAST(HDACodecDevice, qdev, qdev);
- HDACodecDeviceClass *cdc = HDA_CODEC_DEVICE_GET_CLASS(dev);
-
- if (dev->cad == -1) {
- dev->cad = bus->next_cad;
- }
- if (dev->cad >= 15) {
- return -1;
- }
- bus->next_cad = dev->cad + 1;
- return cdc->init(dev);
-}
-
-static int hda_codec_dev_exit(DeviceState *qdev)
-{
- HDACodecDevice *dev = DO_UPCAST(HDACodecDevice, qdev, qdev);
- HDACodecDeviceClass *cdc = HDA_CODEC_DEVICE_GET_CLASS(dev);
-
- if (cdc->exit) {
- cdc->exit(dev);
- }
- return 0;
-}
-
-HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad)
-{
- BusChild *kid;
- HDACodecDevice *cdev;
-
- QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) {
- DeviceState *qdev = kid->child;
- cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
- if (cdev->cad == cad) {
- return cdev;
- }
- }
- return NULL;
-}
-
-void hda_codec_response(HDACodecDevice *dev, bool solicited, uint32_t response)
-{
- HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus);
- bus->response(dev, solicited, response);
-}
-
-bool hda_codec_xfer(HDACodecDevice *dev, uint32_t stnr, bool output,
- uint8_t *buf, uint32_t len)
-{
- HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus);
- return bus->xfer(dev, stnr, output, buf, len);
-}
-
-/* --------------------------------------------------------------------- */
-/* intel hda emulation */
-
-typedef struct IntelHDAStream IntelHDAStream;
-typedef struct IntelHDAState IntelHDAState;
-typedef struct IntelHDAReg IntelHDAReg;
-
-typedef struct bpl {
- uint64_t addr;
- uint32_t len;
- uint32_t flags;
-} bpl;
-
-struct IntelHDAStream {
- /* registers */
- uint32_t ctl;
- uint32_t lpib;
- uint32_t cbl;
- uint32_t lvi;
- uint32_t fmt;
- uint32_t bdlp_lbase;
- uint32_t bdlp_ubase;
-
- /* state */
- bpl *bpl;
- uint32_t bentries;
- uint32_t bsize, be, bp;
-};
-
-struct IntelHDAState {
- PCIDevice pci;
- const char *name;
- HDACodecBus codecs;
-
- /* registers */
- uint32_t g_ctl;
- uint32_t wake_en;
- uint32_t state_sts;
- uint32_t int_ctl;
- uint32_t int_sts;
- uint32_t wall_clk;
-
- uint32_t corb_lbase;
- uint32_t corb_ubase;
- uint32_t corb_rp;
- uint32_t corb_wp;
- uint32_t corb_ctl;
- uint32_t corb_sts;
- uint32_t corb_size;
-
- uint32_t rirb_lbase;
- uint32_t rirb_ubase;
- uint32_t rirb_wp;
- uint32_t rirb_cnt;
- uint32_t rirb_ctl;
- uint32_t rirb_sts;
- uint32_t rirb_size;
-
- uint32_t dp_lbase;
- uint32_t dp_ubase;
-
- uint32_t icw;
- uint32_t irr;
- uint32_t ics;
-
- /* streams */
- IntelHDAStream st[8];
-
- /* state */
- MemoryRegion mmio;
- uint32_t rirb_count;
- int64_t wall_base_ns;
-
- /* debug logging */
- const IntelHDAReg *last_reg;
- uint32_t last_val;
- uint32_t last_write;
- uint32_t last_sec;
- uint32_t repeat_count;
-
- /* properties */
- uint32_t debug;
- uint32_t msi;
- bool old_msi_addr;
-};
-
-#define TYPE_INTEL_HDA_GENERIC "intel-hda-generic"
-
-#define INTEL_HDA(obj) \
- OBJECT_CHECK(IntelHDAState, (obj), TYPE_INTEL_HDA_GENERIC)
-
-struct IntelHDAReg {
- const char *name; /* register name */
- uint32_t size; /* size in bytes */
- uint32_t reset; /* reset value */
- uint32_t wmask; /* write mask */
- uint32_t wclear; /* write 1 to clear bits */
- uint32_t offset; /* location in IntelHDAState */
- uint32_t shift; /* byte access entries for dwords */
- uint32_t stream;
- void (*whandler)(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old);
- void (*rhandler)(IntelHDAState *d, const IntelHDAReg *reg);
-};
-
-static void intel_hda_reset(DeviceState *dev);
-
-/* --------------------------------------------------------------------- */
-
-static hwaddr intel_hda_addr(uint32_t lbase, uint32_t ubase)
-{
- hwaddr addr;
-
- addr = ((uint64_t)ubase << 32) | lbase;
- return addr;
-}
-
-static void intel_hda_update_int_sts(IntelHDAState *d)
-{
- uint32_t sts = 0;
- uint32_t i;
-
- /* update controller status */
- if (d->rirb_sts & ICH6_RBSTS_IRQ) {
- sts |= (1 << 30);
- }
- if (d->rirb_sts & ICH6_RBSTS_OVERRUN) {
- sts |= (1 << 30);
- }
- if (d->state_sts & d->wake_en) {
- sts |= (1 << 30);
- }
-
- /* update stream status */
- for (i = 0; i < 8; i++) {
- /* buffer completion interrupt */
- if (d->st[i].ctl & (1 << 26)) {
- sts |= (1 << i);
- }
- }
-
- /* update global status */
- if (sts & d->int_ctl) {
- sts |= (1U << 31);
- }
-
- d->int_sts = sts;
-}
-
-static void intel_hda_update_irq(IntelHDAState *d)
-{
- int msi = d->msi && msi_enabled(&d->pci);
- int level;
-
- intel_hda_update_int_sts(d);
- if (d->int_sts & (1U << 31) && d->int_ctl & (1U << 31)) {
- level = 1;
- } else {
- level = 0;
- }
- dprint(d, 2, "%s: level %d [%s]\n", __FUNCTION__,
- level, msi ? "msi" : "intx");
- if (msi) {
- if (level) {
- msi_notify(&d->pci, 0);
- }
- } else {
- pci_set_irq(&d->pci, level);
- }
-}
-
-static int intel_hda_send_command(IntelHDAState *d, uint32_t verb)
-{
- uint32_t cad, nid, data;
- HDACodecDevice *codec;
- HDACodecDeviceClass *cdc;
-
- cad = (verb >> 28) & 0x0f;
- if (verb & (1 << 27)) {
- /* indirect node addressing, not specified in HDA 1.0 */
- dprint(d, 1, "%s: indirect node addressing (guest bug?)\n", __FUNCTION__);
- return -1;
- }
- nid = (verb >> 20) & 0x7f;
- data = verb & 0xfffff;
-
- codec = hda_codec_find(&d->codecs, cad);
- if (codec == NULL) {
- dprint(d, 1, "%s: addressed non-existing codec\n", __FUNCTION__);
- return -1;
- }
- cdc = HDA_CODEC_DEVICE_GET_CLASS(codec);
- cdc->command(codec, nid, data);
- return 0;
-}
-
-static void intel_hda_corb_run(IntelHDAState *d)
-{
- hwaddr addr;
- uint32_t rp, verb;
-
- if (d->ics & ICH6_IRS_BUSY) {
- dprint(d, 2, "%s: [icw] verb 0x%08x\n", __FUNCTION__, d->icw);
- intel_hda_send_command(d, d->icw);
- return;
- }
-
- for (;;) {
- if (!(d->corb_ctl & ICH6_CORBCTL_RUN)) {
- dprint(d, 2, "%s: !run\n", __FUNCTION__);
- return;
- }
- if ((d->corb_rp & 0xff) == d->corb_wp) {
- dprint(d, 2, "%s: corb ring empty\n", __FUNCTION__);
- return;
- }
- if (d->rirb_count == d->rirb_cnt) {
- dprint(d, 2, "%s: rirb count reached\n", __FUNCTION__);
- return;
- }
-
- rp = (d->corb_rp + 1) & 0xff;
- addr = intel_hda_addr(d->corb_lbase, d->corb_ubase);
- verb = ldl_le_pci_dma(&d->pci, addr + 4*rp);
- d->corb_rp = rp;
-
- dprint(d, 2, "%s: [rp 0x%x] verb 0x%08x\n", __FUNCTION__, rp, verb);
- intel_hda_send_command(d, verb);
- }
-}
-
-static void intel_hda_response(HDACodecDevice *dev, bool solicited, uint32_t response)
-{
- HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus);
- IntelHDAState *d = container_of(bus, IntelHDAState, codecs);
- hwaddr addr;
- uint32_t wp, ex;
-
- if (d->ics & ICH6_IRS_BUSY) {
- dprint(d, 2, "%s: [irr] response 0x%x, cad 0x%x\n",
- __FUNCTION__, response, dev->cad);
- d->irr = response;
- d->ics &= ~(ICH6_IRS_BUSY | 0xf0);
- d->ics |= (ICH6_IRS_VALID | (dev->cad << 4));
- return;
- }
-
- if (!(d->rirb_ctl & ICH6_RBCTL_DMA_EN)) {
- dprint(d, 1, "%s: rirb dma disabled, drop codec response\n", __FUNCTION__);
- return;
- }
-
- ex = (solicited ? 0 : (1 << 4)) | dev->cad;
- wp = (d->rirb_wp + 1) & 0xff;
- addr = intel_hda_addr(d->rirb_lbase, d->rirb_ubase);
- stl_le_pci_dma(&d->pci, addr + 8*wp, response);
- stl_le_pci_dma(&d->pci, addr + 8*wp + 4, ex);
- d->rirb_wp = wp;
-
- dprint(d, 2, "%s: [wp 0x%x] response 0x%x, extra 0x%x\n",
- __FUNCTION__, wp, response, ex);
-
- d->rirb_count++;
- if (d->rirb_count == d->rirb_cnt) {
- dprint(d, 2, "%s: rirb count reached (%d)\n", __FUNCTION__, d->rirb_count);
- if (d->rirb_ctl & ICH6_RBCTL_IRQ_EN) {
- d->rirb_sts |= ICH6_RBSTS_IRQ;
- intel_hda_update_irq(d);
- }
- } else if ((d->corb_rp & 0xff) == d->corb_wp) {
- dprint(d, 2, "%s: corb ring empty (%d/%d)\n", __FUNCTION__,
- d->rirb_count, d->rirb_cnt);
- if (d->rirb_ctl & ICH6_RBCTL_IRQ_EN) {
- d->rirb_sts |= ICH6_RBSTS_IRQ;
- intel_hda_update_irq(d);
- }
- }
-}
-
-static bool intel_hda_xfer(HDACodecDevice *dev, uint32_t stnr, bool output,
- uint8_t *buf, uint32_t len)
-{
- HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus);
- IntelHDAState *d = container_of(bus, IntelHDAState, codecs);
- hwaddr addr;
- uint32_t s, copy, left;
- IntelHDAStream *st;
- bool irq = false;
-
- st = output ? d->st + 4 : d->st;
- for (s = 0; s < 4; s++) {
- if (stnr == ((st[s].ctl >> 20) & 0x0f)) {
- st = st + s;
- break;
- }
- }
- if (s == 4) {
- return false;
- }
- if (st->bpl == NULL) {
- return false;
- }
- if (st->ctl & (1 << 26)) {
- /*
- * Wait with the next DMA xfer until the guest
- * has acked the buffer completion interrupt
- */
- return false;
- }
-
- left = len;
- while (left > 0) {
- copy = left;
- if (copy > st->bsize - st->lpib)
- copy = st->bsize - st->lpib;
- if (copy > st->bpl[st->be].len - st->bp)
- copy = st->bpl[st->be].len - st->bp;
-
- dprint(d, 3, "dma: entry %d, pos %d/%d, copy %d\n",
- st->be, st->bp, st->bpl[st->be].len, copy);
-
- pci_dma_rw(&d->pci, st->bpl[st->be].addr + st->bp, buf, copy, !output);
- st->lpib += copy;
- st->bp += copy;
- buf += copy;
- left -= copy;
-
- if (st->bpl[st->be].len == st->bp) {
- /* bpl entry filled */
- if (st->bpl[st->be].flags & 0x01) {
- irq = true;
- }
- st->bp = 0;
- st->be++;
- if (st->be == st->bentries) {
- /* bpl wrap around */
- st->be = 0;
- st->lpib = 0;
- }
- }
- }
- if (d->dp_lbase & 0x01) {
- s = st - d->st;
- addr = intel_hda_addr(d->dp_lbase & ~0x01, d->dp_ubase);
- stl_le_pci_dma(&d->pci, addr + 8*s, st->lpib);
- }
- dprint(d, 3, "dma: --\n");
-
- if (irq) {
- st->ctl |= (1 << 26); /* buffer completion interrupt */
- intel_hda_update_irq(d);
- }
- return true;
-}
-
-static void intel_hda_parse_bdl(IntelHDAState *d, IntelHDAStream *st)
-{
- hwaddr addr;
- uint8_t buf[16];
- uint32_t i;
-
- addr = intel_hda_addr(st->bdlp_lbase, st->bdlp_ubase);
- st->bentries = st->lvi +1;
- g_free(st->bpl);
- st->bpl = g_malloc(sizeof(bpl) * st->bentries);
- for (i = 0; i < st->bentries; i++, addr += 16) {
- pci_dma_read(&d->pci, addr, buf, 16);
- st->bpl[i].addr = le64_to_cpu(*(uint64_t *)buf);
- st->bpl[i].len = le32_to_cpu(*(uint32_t *)(buf + 8));
- st->bpl[i].flags = le32_to_cpu(*(uint32_t *)(buf + 12));
- dprint(d, 1, "bdl/%d: 0x%" PRIx64 " +0x%x, 0x%x\n",
- i, st->bpl[i].addr, st->bpl[i].len, st->bpl[i].flags);
- }
-
- st->bsize = st->cbl;
- st->lpib = 0;
- st->be = 0;
- st->bp = 0;
-}
-
-static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool running, bool output)
-{
- BusChild *kid;
- HDACodecDevice *cdev;
-
- QTAILQ_FOREACH(kid, &d->codecs.qbus.children, sibling) {
- DeviceState *qdev = kid->child;
- HDACodecDeviceClass *cdc;
-
- cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
- cdc = HDA_CODEC_DEVICE_GET_CLASS(cdev);
- if (cdc->stream) {
- cdc->stream(cdev, stream, running, output);
- }
- }
-}
-
-/* --------------------------------------------------------------------- */
-
-static void intel_hda_set_g_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
-{
- if ((d->g_ctl & ICH6_GCTL_RESET) == 0) {
- intel_hda_reset(DEVICE(d));
- }
-}
-
-static void intel_hda_set_wake_en(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
-{
- intel_hda_update_irq(d);
-}
-
-static void intel_hda_set_state_sts(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
-{
- intel_hda_update_irq(d);
-}
-
-static void intel_hda_set_int_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
-{
- intel_hda_update_irq(d);
-}
-
-static void intel_hda_get_wall_clk(IntelHDAState *d, const IntelHDAReg *reg)
-{
- int64_t ns;
-
- ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - d->wall_base_ns;
- d->wall_clk = (uint32_t)(ns * 24 / 1000); /* 24 MHz */
-}
-
-static void intel_hda_set_corb_wp(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
-{
- intel_hda_corb_run(d);
-}
-
-static void intel_hda_set_corb_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
-{
- intel_hda_corb_run(d);
-}
-
-static void intel_hda_set_rirb_wp(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
-{
- if (d->rirb_wp & ICH6_RIRBWP_RST) {
- d->rirb_wp = 0;
- }
-}
-
-static void intel_hda_set_rirb_sts(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
-{
- intel_hda_update_irq(d);
-
- if ((old & ICH6_RBSTS_IRQ) && !(d->rirb_sts & ICH6_RBSTS_IRQ)) {
- /* cleared ICH6_RBSTS_IRQ */
- d->rirb_count = 0;
- intel_hda_corb_run(d);
- }
-}
-
-static void intel_hda_set_ics(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
-{
- if (d->ics & ICH6_IRS_BUSY) {
- intel_hda_corb_run(d);
- }
-}
-
-static void intel_hda_set_st_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
-{
- bool output = reg->stream >= 4;
- IntelHDAStream *st = d->st + reg->stream;
-
- if (st->ctl & 0x01) {
- /* reset */
- dprint(d, 1, "st #%d: reset\n", reg->stream);
- st->ctl = SD_STS_FIFO_READY << 24;
- }
- if ((st->ctl & 0x02) != (old & 0x02)) {
- uint32_t stnr = (st->ctl >> 20) & 0x0f;
- /* run bit flipped */
- if (st->ctl & 0x02) {
- /* start */
- dprint(d, 1, "st #%d: start %d (ring buf %d bytes)\n",
- reg->stream, stnr, st->cbl);
- intel_hda_parse_bdl(d, st);
- intel_hda_notify_codecs(d, stnr, true, output);
- } else {
- /* stop */
- dprint(d, 1, "st #%d: stop %d\n", reg->stream, stnr);
- intel_hda_notify_codecs(d, stnr, false, output);
- }
- }
- intel_hda_update_irq(d);
-}
-
-/* --------------------------------------------------------------------- */
-
-#define ST_REG(_n, _o) (0x80 + (_n) * 0x20 + (_o))
-
-static const struct IntelHDAReg regtab[] = {
- /* global */
- [ ICH6_REG_GCAP ] = {
- .name = "GCAP",
- .size = 2,
- .reset = 0x4401,
- },
- [ ICH6_REG_VMIN ] = {
- .name = "VMIN",
- .size = 1,
- },
- [ ICH6_REG_VMAJ ] = {
- .name = "VMAJ",
- .size = 1,
- .reset = 1,
- },
- [ ICH6_REG_OUTPAY ] = {
- .name = "OUTPAY",
- .size = 2,
- .reset = 0x3c,
- },
- [ ICH6_REG_INPAY ] = {
- .name = "INPAY",
- .size = 2,
- .reset = 0x1d,
- },
- [ ICH6_REG_GCTL ] = {
- .name = "GCTL",
- .size = 4,
- .wmask = 0x0103,
- .offset = offsetof(IntelHDAState, g_ctl),
- .whandler = intel_hda_set_g_ctl,
- },
- [ ICH6_REG_WAKEEN ] = {
- .name = "WAKEEN",
- .size = 2,
- .wmask = 0x7fff,
- .offset = offsetof(IntelHDAState, wake_en),
- .whandler = intel_hda_set_wake_en,
- },
- [ ICH6_REG_STATESTS ] = {
- .name = "STATESTS",
- .size = 2,
- .wmask = 0x7fff,
- .wclear = 0x7fff,
- .offset = offsetof(IntelHDAState, state_sts),
- .whandler = intel_hda_set_state_sts,
- },
-
- /* interrupts */
- [ ICH6_REG_INTCTL ] = {
- .name = "INTCTL",
- .size = 4,
- .wmask = 0xc00000ff,
- .offset = offsetof(IntelHDAState, int_ctl),
- .whandler = intel_hda_set_int_ctl,
- },
- [ ICH6_REG_INTSTS ] = {
- .name = "INTSTS",
- .size = 4,
- .wmask = 0xc00000ff,
- .wclear = 0xc00000ff,
- .offset = offsetof(IntelHDAState, int_sts),
- },
-
- /* misc */
- [ ICH6_REG_WALLCLK ] = {
- .name = "WALLCLK",
- .size = 4,
- .offset = offsetof(IntelHDAState, wall_clk),
- .rhandler = intel_hda_get_wall_clk,
- },
- [ ICH6_REG_WALLCLK + 0x2000 ] = {
- .name = "WALLCLK(alias)",
- .size = 4,
- .offset = offsetof(IntelHDAState, wall_clk),
- .rhandler = intel_hda_get_wall_clk,
- },
-
- /* dma engine */
- [ ICH6_REG_CORBLBASE ] = {
- .name = "CORBLBASE",
- .size = 4,
- .wmask = 0xffffff80,
- .offset = offsetof(IntelHDAState, corb_lbase),
- },
- [ ICH6_REG_CORBUBASE ] = {
- .name = "CORBUBASE",
- .size = 4,
- .wmask = 0xffffffff,
- .offset = offsetof(IntelHDAState, corb_ubase),
- },
- [ ICH6_REG_CORBWP ] = {
- .name = "CORBWP",
- .size = 2,
- .wmask = 0xff,
- .offset = offsetof(IntelHDAState, corb_wp),
- .whandler = intel_hda_set_corb_wp,
- },
- [ ICH6_REG_CORBRP ] = {
- .name = "CORBRP",
- .size = 2,
- .wmask = 0x80ff,
- .offset = offsetof(IntelHDAState, corb_rp),
- },
- [ ICH6_REG_CORBCTL ] = {
- .name = "CORBCTL",
- .size = 1,
- .wmask = 0x03,
- .offset = offsetof(IntelHDAState, corb_ctl),
- .whandler = intel_hda_set_corb_ctl,
- },
- [ ICH6_REG_CORBSTS ] = {
- .name = "CORBSTS",
- .size = 1,
- .wmask = 0x01,
- .wclear = 0x01,
- .offset = offsetof(IntelHDAState, corb_sts),
- },
- [ ICH6_REG_CORBSIZE ] = {
- .name = "CORBSIZE",
- .size = 1,
- .reset = 0x42,
- .offset = offsetof(IntelHDAState, corb_size),
- },
- [ ICH6_REG_RIRBLBASE ] = {
- .name = "RIRBLBASE",
- .size = 4,
- .wmask = 0xffffff80,
- .offset = offsetof(IntelHDAState, rirb_lbase),
- },
- [ ICH6_REG_RIRBUBASE ] = {
- .name = "RIRBUBASE",
- .size = 4,
- .wmask = 0xffffffff,
- .offset = offsetof(IntelHDAState, rirb_ubase),
- },
- [ ICH6_REG_RIRBWP ] = {
- .name = "RIRBWP",
- .size = 2,
- .wmask = 0x8000,
- .offset = offsetof(IntelHDAState, rirb_wp),
- .whandler = intel_hda_set_rirb_wp,
- },
- [ ICH6_REG_RINTCNT ] = {
- .name = "RINTCNT",
- .size = 2,
- .wmask = 0xff,
- .offset = offsetof(IntelHDAState, rirb_cnt),
- },
- [ ICH6_REG_RIRBCTL ] = {
- .name = "RIRBCTL",
- .size = 1,
- .wmask = 0x07,
- .offset = offsetof(IntelHDAState, rirb_ctl),
- },
- [ ICH6_REG_RIRBSTS ] = {
- .name = "RIRBSTS",
- .size = 1,
- .wmask = 0x05,
- .wclear = 0x05,
- .offset = offsetof(IntelHDAState, rirb_sts),
- .whandler = intel_hda_set_rirb_sts,
- },
- [ ICH6_REG_RIRBSIZE ] = {
- .name = "RIRBSIZE",
- .size = 1,
- .reset = 0x42,
- .offset = offsetof(IntelHDAState, rirb_size),
- },
-
- [ ICH6_REG_DPLBASE ] = {
- .name = "DPLBASE",
- .size = 4,
- .wmask = 0xffffff81,
- .offset = offsetof(IntelHDAState, dp_lbase),
- },
- [ ICH6_REG_DPUBASE ] = {
- .name = "DPUBASE",
- .size = 4,
- .wmask = 0xffffffff,
- .offset = offsetof(IntelHDAState, dp_ubase),
- },
-
- [ ICH6_REG_IC ] = {
- .name = "ICW",
- .size = 4,
- .wmask = 0xffffffff,
- .offset = offsetof(IntelHDAState, icw),
- },
- [ ICH6_REG_IR ] = {
- .name = "IRR",
- .size = 4,
- .offset = offsetof(IntelHDAState, irr),
- },
- [ ICH6_REG_IRS ] = {
- .name = "ICS",
- .size = 2,
- .wmask = 0x0003,
- .wclear = 0x0002,
- .offset = offsetof(IntelHDAState, ics),
- .whandler = intel_hda_set_ics,
- },
-
-#define HDA_STREAM(_t, _i) \
- [ ST_REG(_i, ICH6_REG_SD_CTL) ] = { \
- .stream = _i, \
- .name = _t stringify(_i) " CTL", \
- .size = 4, \
- .wmask = 0x1cff001f, \
- .offset = offsetof(IntelHDAState, st[_i].ctl), \
- .whandler = intel_hda_set_st_ctl, \
- }, \
- [ ST_REG(_i, ICH6_REG_SD_CTL) + 2] = { \
- .stream = _i, \
- .name = _t stringify(_i) " CTL(stnr)", \
- .size = 1, \
- .shift = 16, \
- .wmask = 0x00ff0000, \
- .offset = offsetof(IntelHDAState, st[_i].ctl), \
- .whandler = intel_hda_set_st_ctl, \
- }, \
- [ ST_REG(_i, ICH6_REG_SD_STS)] = { \
- .stream = _i, \
- .name = _t stringify(_i) " CTL(sts)", \
- .size = 1, \
- .shift = 24, \
- .wmask = 0x1c000000, \
- .wclear = 0x1c000000, \
- .offset = offsetof(IntelHDAState, st[_i].ctl), \
- .whandler = intel_hda_set_st_ctl, \
- .reset = SD_STS_FIFO_READY << 24 \
- }, \
- [ ST_REG(_i, ICH6_REG_SD_LPIB) ] = { \
- .stream = _i, \
- .name = _t stringify(_i) " LPIB", \
- .size = 4, \
- .offset = offsetof(IntelHDAState, st[_i].lpib), \
- }, \
- [ ST_REG(_i, ICH6_REG_SD_LPIB) + 0x2000 ] = { \
- .stream = _i, \
- .name = _t stringify(_i) " LPIB(alias)", \
- .size = 4, \
- .offset = offsetof(IntelHDAState, st[_i].lpib), \
- }, \
- [ ST_REG(_i, ICH6_REG_SD_CBL) ] = { \
- .stream = _i, \
- .name = _t stringify(_i) " CBL", \
- .size = 4, \
- .wmask = 0xffffffff, \
- .offset = offsetof(IntelHDAState, st[_i].cbl), \
- }, \
- [ ST_REG(_i, ICH6_REG_SD_LVI) ] = { \
- .stream = _i, \
- .name = _t stringify(_i) " LVI", \
- .size = 2, \
- .wmask = 0x00ff, \
- .offset = offsetof(IntelHDAState, st[_i].lvi), \
- }, \
- [ ST_REG(_i, ICH6_REG_SD_FIFOSIZE) ] = { \
- .stream = _i, \
- .name = _t stringify(_i) " FIFOS", \
- .size = 2, \
- .reset = HDA_BUFFER_SIZE, \
- }, \
- [ ST_REG(_i, ICH6_REG_SD_FORMAT) ] = { \
- .stream = _i, \
- .name = _t stringify(_i) " FMT", \
- .size = 2, \
- .wmask = 0x7f7f, \
- .offset = offsetof(IntelHDAState, st[_i].fmt), \
- }, \
- [ ST_REG(_i, ICH6_REG_SD_BDLPL) ] = { \
- .stream = _i, \
- .name = _t stringify(_i) " BDLPL", \
- .size = 4, \
- .wmask = 0xffffff80, \
- .offset = offsetof(IntelHDAState, st[_i].bdlp_lbase), \
- }, \
- [ ST_REG(_i, ICH6_REG_SD_BDLPU) ] = { \
- .stream = _i, \
- .name = _t stringify(_i) " BDLPU", \
- .size = 4, \
- .wmask = 0xffffffff, \
- .offset = offsetof(IntelHDAState, st[_i].bdlp_ubase), \
- }, \
-
- HDA_STREAM("IN", 0)
- HDA_STREAM("IN", 1)
- HDA_STREAM("IN", 2)
- HDA_STREAM("IN", 3)
-
- HDA_STREAM("OUT", 4)
- HDA_STREAM("OUT", 5)
- HDA_STREAM("OUT", 6)
- HDA_STREAM("OUT", 7)
-
-};
-
-static const IntelHDAReg *intel_hda_reg_find(IntelHDAState *d, hwaddr addr)
-{
- const IntelHDAReg *reg;
-
- if (addr >= ARRAY_SIZE(regtab)) {
- goto noreg;
- }
- reg = regtab+addr;
- if (reg->name == NULL) {
- goto noreg;
- }
- return reg;
-
-noreg:
- dprint(d, 1, "unknown register, addr 0x%x\n", (int) addr);
- return NULL;
-}
-
-static uint32_t *intel_hda_reg_addr(IntelHDAState *d, const IntelHDAReg *reg)
-{
- uint8_t *addr = (void*)d;
-
- addr += reg->offset;
- return (uint32_t*)addr;
-}
-
-static void intel_hda_reg_write(IntelHDAState *d, const IntelHDAReg *reg, uint32_t val,
- uint32_t wmask)
-{
- uint32_t *addr;
- uint32_t old;
-
- if (!reg) {
- return;
- }
-
- if (d->debug) {
- time_t now = time(NULL);
- if (d->last_write && d->last_reg == reg && d->last_val == val) {
- d->repeat_count++;
- if (d->last_sec != now) {
- dprint(d, 2, "previous register op repeated %d times\n", d->repeat_count);
- d->last_sec = now;
- d->repeat_count = 0;
- }
- } else {
- if (d->repeat_count) {
- dprint(d, 2, "previous register op repeated %d times\n", d->repeat_count);
- }
- dprint(d, 2, "write %-16s: 0x%x (%x)\n", reg->name, val, wmask);
- d->last_write = 1;
- d->last_reg = reg;
- d->last_val = val;
- d->last_sec = now;
- d->repeat_count = 0;
- }
- }
- assert(reg->offset != 0);
-
- addr = intel_hda_reg_addr(d, reg);
- old = *addr;
-
- if (reg->shift) {
- val <<= reg->shift;
- wmask <<= reg->shift;
- }
- wmask &= reg->wmask;
- *addr &= ~wmask;
- *addr |= wmask & val;
- *addr &= ~(val & reg->wclear);
-
- if (reg->whandler) {
- reg->whandler(d, reg, old);
- }
-}
-
-static uint32_t intel_hda_reg_read(IntelHDAState *d, const IntelHDAReg *reg,
- uint32_t rmask)
-{
- uint32_t *addr, ret;
-
- if (!reg) {
- return 0;
- }
-
- if (reg->rhandler) {
- reg->rhandler(d, reg);
- }
-
- if (reg->offset == 0) {
- /* constant read-only register */
- ret = reg->reset;
- } else {
- addr = intel_hda_reg_addr(d, reg);
- ret = *addr;
- if (reg->shift) {
- ret >>= reg->shift;
- }
- ret &= rmask;
- }
- if (d->debug) {
- time_t now = time(NULL);
- if (!d->last_write && d->last_reg == reg && d->last_val == ret) {
- d->repeat_count++;
- if (d->last_sec != now) {
- dprint(d, 2, "previous register op repeated %d times\n", d->repeat_count);
- d->last_sec = now;
- d->repeat_count = 0;
- }
- } else {
- if (d->repeat_count) {
- dprint(d, 2, "previous register op repeated %d times\n", d->repeat_count);
- }
- dprint(d, 2, "read %-16s: 0x%x (%x)\n", reg->name, ret, rmask);
- d->last_write = 0;
- d->last_reg = reg;
- d->last_val = ret;
- d->last_sec = now;
- d->repeat_count = 0;
- }
- }
- return ret;
-}
-
-static void intel_hda_regs_reset(IntelHDAState *d)
-{
- uint32_t *addr;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(regtab); i++) {
- if (regtab[i].name == NULL) {
- continue;
- }
- if (regtab[i].offset == 0) {
- continue;
- }
- addr = intel_hda_reg_addr(d, regtab + i);
- *addr = regtab[i].reset;
- }
-}
-
-/* --------------------------------------------------------------------- */
-
-static void intel_hda_mmio_writeb(void *opaque, hwaddr addr, uint32_t val)
-{
- IntelHDAState *d = opaque;
- const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
-
- intel_hda_reg_write(d, reg, val, 0xff);
-}
-
-static void intel_hda_mmio_writew(void *opaque, hwaddr addr, uint32_t val)
-{
- IntelHDAState *d = opaque;
- const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
-
- intel_hda_reg_write(d, reg, val, 0xffff);
-}
-
-static void intel_hda_mmio_writel(void *opaque, hwaddr addr, uint32_t val)
-{
- IntelHDAState *d = opaque;
- const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
-
- intel_hda_reg_write(d, reg, val, 0xffffffff);
-}
-
-static uint32_t intel_hda_mmio_readb(void *opaque, hwaddr addr)
-{
- IntelHDAState *d = opaque;
- const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
-
- return intel_hda_reg_read(d, reg, 0xff);
-}
-
-static uint32_t intel_hda_mmio_readw(void *opaque, hwaddr addr)
-{
- IntelHDAState *d = opaque;
- const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
-
- return intel_hda_reg_read(d, reg, 0xffff);
-}
-
-static uint32_t intel_hda_mmio_readl(void *opaque, hwaddr addr)
-{
- IntelHDAState *d = opaque;
- const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
-
- return intel_hda_reg_read(d, reg, 0xffffffff);
-}
-
-static const MemoryRegionOps intel_hda_mmio_ops = {
- .old_mmio = {
- .read = {
- intel_hda_mmio_readb,
- intel_hda_mmio_readw,
- intel_hda_mmio_readl,
- },
- .write = {
- intel_hda_mmio_writeb,
- intel_hda_mmio_writew,
- intel_hda_mmio_writel,
- },
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-/* --------------------------------------------------------------------- */
-
-static void intel_hda_reset(DeviceState *dev)
-{
- BusChild *kid;
- IntelHDAState *d = INTEL_HDA(dev);
- HDACodecDevice *cdev;
-
- intel_hda_regs_reset(d);
- d->wall_base_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-
- /* reset codecs */
- QTAILQ_FOREACH(kid, &d->codecs.qbus.children, sibling) {
- DeviceState *qdev = kid->child;
- cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
- device_reset(DEVICE(cdev));
- d->state_sts |= (1 << cdev->cad);
- }
- intel_hda_update_irq(d);
-}
-
-static void intel_hda_realize(PCIDevice *pci, Error **errp)
-{
- IntelHDAState *d = INTEL_HDA(pci);
- uint8_t *conf = d->pci.config;
-
- d->name = object_get_typename(OBJECT(d));
-
- pci_config_set_interrupt_pin(conf, 1);
-
- /* HDCTL off 0x40 bit 0 selects signaling mode (1-HDA, 0 - Ac97) 18.1.19 */
- conf[0x40] = 0x01;
-
- memory_region_init_io(&d->mmio, OBJECT(d), &intel_hda_mmio_ops, d,
- "intel-hda", 0x4000);
- pci_register_bar(&d->pci, 0, 0, &d->mmio);
- if (d->msi) {
- msi_init(&d->pci, d->old_msi_addr ? 0x50 : 0x60, 1, true, false);
- }
-
- hda_codec_bus_init(DEVICE(pci), &d->codecs, sizeof(d->codecs),
- intel_hda_response, intel_hda_xfer);
-}
-
-static void intel_hda_exit(PCIDevice *pci)
-{
- IntelHDAState *d = INTEL_HDA(pci);
-
- msi_uninit(&d->pci);
-}
-
-static int intel_hda_post_load(void *opaque, int version)
-{
- IntelHDAState* d = opaque;
- int i;
-
- dprint(d, 1, "%s\n", __FUNCTION__);
- for (i = 0; i < ARRAY_SIZE(d->st); i++) {
- if (d->st[i].ctl & 0x02) {
- intel_hda_parse_bdl(d, &d->st[i]);
- }
- }
- intel_hda_update_irq(d);
- return 0;
-}
-
-static const VMStateDescription vmstate_intel_hda_stream = {
- .name = "intel-hda-stream",
- .version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(ctl, IntelHDAStream),
- VMSTATE_UINT32(lpib, IntelHDAStream),
- VMSTATE_UINT32(cbl, IntelHDAStream),
- VMSTATE_UINT32(lvi, IntelHDAStream),
- VMSTATE_UINT32(fmt, IntelHDAStream),
- VMSTATE_UINT32(bdlp_lbase, IntelHDAStream),
- VMSTATE_UINT32(bdlp_ubase, IntelHDAStream),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_intel_hda = {
- .name = "intel-hda",
- .version_id = 1,
- .post_load = intel_hda_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(pci, IntelHDAState),
-
- /* registers */
- VMSTATE_UINT32(g_ctl, IntelHDAState),
- VMSTATE_UINT32(wake_en, IntelHDAState),
- VMSTATE_UINT32(state_sts, IntelHDAState),
- VMSTATE_UINT32(int_ctl, IntelHDAState),
- VMSTATE_UINT32(int_sts, IntelHDAState),
- VMSTATE_UINT32(wall_clk, IntelHDAState),
- VMSTATE_UINT32(corb_lbase, IntelHDAState),
- VMSTATE_UINT32(corb_ubase, IntelHDAState),
- VMSTATE_UINT32(corb_rp, IntelHDAState),
- VMSTATE_UINT32(corb_wp, IntelHDAState),
- VMSTATE_UINT32(corb_ctl, IntelHDAState),
- VMSTATE_UINT32(corb_sts, IntelHDAState),
- VMSTATE_UINT32(corb_size, IntelHDAState),
- VMSTATE_UINT32(rirb_lbase, IntelHDAState),
- VMSTATE_UINT32(rirb_ubase, IntelHDAState),
- VMSTATE_UINT32(rirb_wp, IntelHDAState),
- VMSTATE_UINT32(rirb_cnt, IntelHDAState),
- VMSTATE_UINT32(rirb_ctl, IntelHDAState),
- VMSTATE_UINT32(rirb_sts, IntelHDAState),
- VMSTATE_UINT32(rirb_size, IntelHDAState),
- VMSTATE_UINT32(dp_lbase, IntelHDAState),
- VMSTATE_UINT32(dp_ubase, IntelHDAState),
- VMSTATE_UINT32(icw, IntelHDAState),
- VMSTATE_UINT32(irr, IntelHDAState),
- VMSTATE_UINT32(ics, IntelHDAState),
- VMSTATE_STRUCT_ARRAY(st, IntelHDAState, 8, 0,
- vmstate_intel_hda_stream,
- IntelHDAStream),
-
- /* additional state info */
- VMSTATE_UINT32(rirb_count, IntelHDAState),
- VMSTATE_INT64(wall_base_ns, IntelHDAState),
-
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property intel_hda_properties[] = {
- DEFINE_PROP_UINT32("debug", IntelHDAState, debug, 0),
- DEFINE_PROP_UINT32("msi", IntelHDAState, msi, 1),
- DEFINE_PROP_BOOL("old_msi_addr", IntelHDAState, old_msi_addr, false),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void intel_hda_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = intel_hda_realize;
- k->exit = intel_hda_exit;
- k->vendor_id = PCI_VENDOR_ID_INTEL;
- k->class_id = PCI_CLASS_MULTIMEDIA_HD_AUDIO;
- dc->reset = intel_hda_reset;
- dc->vmsd = &vmstate_intel_hda;
- dc->props = intel_hda_properties;
-}
-
-static void intel_hda_class_init_ich6(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->device_id = 0x2668;
- k->revision = 1;
- set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
- dc->desc = "Intel HD Audio Controller (ich6)";
-}
-
-static void intel_hda_class_init_ich9(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->device_id = 0x293e;
- k->revision = 3;
- set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
- dc->desc = "Intel HD Audio Controller (ich9)";
-}
-
-static const TypeInfo intel_hda_info = {
- .name = TYPE_INTEL_HDA_GENERIC,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(IntelHDAState),
- .class_init = intel_hda_class_init,
- .abstract = true,
-};
-
-static const TypeInfo intel_hda_info_ich6 = {
- .name = "intel-hda",
- .parent = TYPE_INTEL_HDA_GENERIC,
- .class_init = intel_hda_class_init_ich6,
-};
-
-static const TypeInfo intel_hda_info_ich9 = {
- .name = "ich9-intel-hda",
- .parent = TYPE_INTEL_HDA_GENERIC,
- .class_init = intel_hda_class_init_ich9,
-};
-
-static void hda_codec_device_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *k = DEVICE_CLASS(klass);
- k->init = hda_codec_dev_init;
- k->exit = hda_codec_dev_exit;
- set_bit(DEVICE_CATEGORY_SOUND, k->categories);
- k->bus_type = TYPE_HDA_BUS;
- k->props = hda_props;
-}
-
-static const TypeInfo hda_codec_device_type_info = {
- .name = TYPE_HDA_CODEC_DEVICE,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(HDACodecDevice),
- .abstract = true,
- .class_size = sizeof(HDACodecDeviceClass),
- .class_init = hda_codec_device_class_init,
-};
-
-/*
- * create intel hda controller with codec attached to it,
- * so '-soundhw hda' works.
- */
-static int intel_hda_and_codec_init(PCIBus *bus)
-{
- DeviceState *controller;
- BusState *hdabus;
- DeviceState *codec;
-
- controller = DEVICE(pci_create_simple(bus, -1, "intel-hda"));
- hdabus = QLIST_FIRST(&controller->child_bus);
- codec = qdev_create(hdabus, "hda-duplex");
- qdev_init_nofail(codec);
- return 0;
-}
-
-static void intel_hda_register_types(void)
-{
- type_register_static(&hda_codec_bus_info);
- type_register_static(&intel_hda_info);
- type_register_static(&intel_hda_info_ich6);
- type_register_static(&intel_hda_info_ich9);
- type_register_static(&hda_codec_device_type_info);
- pci_register_soundhw("hda", "Intel HD Audio", intel_hda_and_codec_init);
-}
-
-type_init(intel_hda_register_types)
diff --git a/qemu/hw/audio/intel-hda.h b/qemu/hw/audio/intel-hda.h
deleted file mode 100644
index d784bcf5f..000000000
--- a/qemu/hw/audio/intel-hda.h
+++ /dev/null
@@ -1,72 +0,0 @@
-#ifndef HW_INTEL_HDA_H
-#define HW_INTEL_HDA_H
-
-#include "hw/qdev.h"
-
-/* --------------------------------------------------------------------- */
-/* hda bus */
-
-#define TYPE_HDA_CODEC_DEVICE "hda-codec"
-#define HDA_CODEC_DEVICE(obj) \
- OBJECT_CHECK(HDACodecDevice, (obj), TYPE_HDA_CODEC_DEVICE)
-#define HDA_CODEC_DEVICE_CLASS(klass) \
- OBJECT_CLASS_CHECK(HDACodecDeviceClass, (klass), TYPE_HDA_CODEC_DEVICE)
-#define HDA_CODEC_DEVICE_GET_CLASS(obj) \
- OBJECT_GET_CLASS(HDACodecDeviceClass, (obj), TYPE_HDA_CODEC_DEVICE)
-
-#define TYPE_HDA_BUS "HDA"
-#define HDA_BUS(obj) OBJECT_CHECK(HDACodecBus, (obj), TYPE_HDA_BUS)
-
-typedef struct HDACodecBus HDACodecBus;
-typedef struct HDACodecDevice HDACodecDevice;
-
-typedef void (*hda_codec_response_func)(HDACodecDevice *dev,
- bool solicited, uint32_t response);
-typedef bool (*hda_codec_xfer_func)(HDACodecDevice *dev,
- uint32_t stnr, bool output,
- uint8_t *buf, uint32_t len);
-
-struct HDACodecBus {
- BusState qbus;
- uint32_t next_cad;
- hda_codec_response_func response;
- hda_codec_xfer_func xfer;
-};
-
-typedef struct HDACodecDeviceClass
-{
- DeviceClass parent_class;
-
- int (*init)(HDACodecDevice *dev);
- int (*exit)(HDACodecDevice *dev);
- void (*command)(HDACodecDevice *dev, uint32_t nid, uint32_t data);
- void (*stream)(HDACodecDevice *dev, uint32_t stnr, bool running, bool output);
-} HDACodecDeviceClass;
-
-struct HDACodecDevice {
- DeviceState qdev;
- uint32_t cad; /* codec address */
-};
-
-void hda_codec_bus_init(DeviceState *dev, HDACodecBus *bus, size_t bus_size,
- hda_codec_response_func response,
- hda_codec_xfer_func xfer);
-HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad);
-
-void hda_codec_response(HDACodecDevice *dev, bool solicited, uint32_t response);
-bool hda_codec_xfer(HDACodecDevice *dev, uint32_t stnr, bool output,
- uint8_t *buf, uint32_t len);
-
-/* --------------------------------------------------------------------- */
-
-#define dprint(_dev, _level, _fmt, ...) \
- do { \
- if (_dev->debug >= _level) { \
- fprintf(stderr, "%s: ", _dev->name); \
- fprintf(stderr, _fmt, ## __VA_ARGS__); \
- } \
- } while (0)
-
-/* --------------------------------------------------------------------- */
-
-#endif
diff --git a/qemu/hw/audio/lm4549.c b/qemu/hw/audio/lm4549.c
deleted file mode 100644
index a46f2301a..000000000
--- a/qemu/hw/audio/lm4549.c
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * LM4549 Audio Codec Interface
- *
- * Copyright (c) 2011
- * Written by Mathieu Sonet - www.elasticsheep.com
- *
- * This code is licensed under the GPL.
- *
- * *****************************************************************
- *
- * This driver emulates the LM4549 codec.
- *
- * It supports only one playback voice and no record voice.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "audio/audio.h"
-#include "lm4549.h"
-
-#if 0
-#define LM4549_DEBUG 1
-#endif
-
-#if 0
-#define LM4549_DUMP_DAC_INPUT 1
-#endif
-
-#ifdef LM4549_DEBUG
-#define DPRINTF(fmt, ...) \
-do { printf("lm4549: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while (0)
-#endif
-
-#if defined(LM4549_DUMP_DAC_INPUT)
-static FILE *fp_dac_input;
-#endif
-
-/* LM4549 register list */
-enum {
- LM4549_Reset = 0x00,
- LM4549_Master_Volume = 0x02,
- LM4549_Line_Out_Volume = 0x04,
- LM4549_Master_Volume_Mono = 0x06,
- LM4549_PC_Beep_Volume = 0x0A,
- LM4549_Phone_Volume = 0x0C,
- LM4549_Mic_Volume = 0x0E,
- LM4549_Line_In_Volume = 0x10,
- LM4549_CD_Volume = 0x12,
- LM4549_Video_Volume = 0x14,
- LM4549_Aux_Volume = 0x16,
- LM4549_PCM_Out_Volume = 0x18,
- LM4549_Record_Select = 0x1A,
- LM4549_Record_Gain = 0x1C,
- LM4549_General_Purpose = 0x20,
- LM4549_3D_Control = 0x22,
- LM4549_Powerdown_Ctrl_Stat = 0x26,
- LM4549_Ext_Audio_ID = 0x28,
- LM4549_Ext_Audio_Stat_Ctrl = 0x2A,
- LM4549_PCM_Front_DAC_Rate = 0x2C,
- LM4549_PCM_ADC_Rate = 0x32,
- LM4549_Vendor_ID1 = 0x7C,
- LM4549_Vendor_ID2 = 0x7E
-};
-
-static void lm4549_reset(lm4549_state *s)
-{
- uint16_t *regfile = s->regfile;
-
- regfile[LM4549_Reset] = 0x0d50;
- regfile[LM4549_Master_Volume] = 0x8008;
- regfile[LM4549_Line_Out_Volume] = 0x8000;
- regfile[LM4549_Master_Volume_Mono] = 0x8000;
- regfile[LM4549_PC_Beep_Volume] = 0x0000;
- regfile[LM4549_Phone_Volume] = 0x8008;
- regfile[LM4549_Mic_Volume] = 0x8008;
- regfile[LM4549_Line_In_Volume] = 0x8808;
- regfile[LM4549_CD_Volume] = 0x8808;
- regfile[LM4549_Video_Volume] = 0x8808;
- regfile[LM4549_Aux_Volume] = 0x8808;
- regfile[LM4549_PCM_Out_Volume] = 0x8808;
- regfile[LM4549_Record_Select] = 0x0000;
- regfile[LM4549_Record_Gain] = 0x8000;
- regfile[LM4549_General_Purpose] = 0x0000;
- regfile[LM4549_3D_Control] = 0x0101;
- regfile[LM4549_Powerdown_Ctrl_Stat] = 0x000f;
- regfile[LM4549_Ext_Audio_ID] = 0x0001;
- regfile[LM4549_Ext_Audio_Stat_Ctrl] = 0x0000;
- regfile[LM4549_PCM_Front_DAC_Rate] = 0xbb80;
- regfile[LM4549_PCM_ADC_Rate] = 0xbb80;
- regfile[LM4549_Vendor_ID1] = 0x4e53;
- regfile[LM4549_Vendor_ID2] = 0x4331;
-}
-
-static void lm4549_audio_transfer(lm4549_state *s)
-{
- uint32_t written_bytes, written_samples;
- uint32_t i;
-
- /* Activate the voice */
- AUD_set_active_out(s->voice, 1);
- s->voice_is_active = 1;
-
- /* Try to write the buffer content */
- written_bytes = AUD_write(s->voice, s->buffer,
- s->buffer_level * sizeof(uint16_t));
- written_samples = written_bytes >> 1;
-
-#if defined(LM4549_DUMP_DAC_INPUT)
- fwrite(s->buffer, sizeof(uint8_t), written_bytes, fp_dac_input);
-#endif
-
- s->buffer_level -= written_samples;
-
- if (s->buffer_level > 0) {
- /* Move the data back to the start of the buffer */
- for (i = 0; i < s->buffer_level; i++) {
- s->buffer[i] = s->buffer[i + written_samples];
- }
- }
-}
-
-static void lm4549_audio_out_callback(void *opaque, int free)
-{
- lm4549_state *s = (lm4549_state *)opaque;
- static uint32_t prev_buffer_level;
-
-#ifdef LM4549_DEBUG
- int size = AUD_get_buffer_size_out(s->voice);
- DPRINTF("audio_out_callback size = %i free = %i\n", size, free);
-#endif
-
- /* Detect that no data are consumed
- => disable the voice */
- if (s->buffer_level == prev_buffer_level) {
- AUD_set_active_out(s->voice, 0);
- s->voice_is_active = 0;
- }
- prev_buffer_level = s->buffer_level;
-
- /* Check if a buffer transfer is pending */
- if (s->buffer_level == LM4549_BUFFER_SIZE) {
- lm4549_audio_transfer(s);
-
- /* Request more data */
- if (s->data_req_cb != NULL) {
- (s->data_req_cb)(s->opaque);
- }
- }
-}
-
-uint32_t lm4549_read(lm4549_state *s, hwaddr offset)
-{
- uint16_t *regfile = s->regfile;
- uint32_t value = 0;
-
- /* Read the stored value */
- assert(offset < 128);
- value = regfile[offset];
-
- DPRINTF("read [0x%02x] = 0x%04x\n", offset, value);
-
- return value;
-}
-
-void lm4549_write(lm4549_state *s,
- hwaddr offset, uint32_t value)
-{
- uint16_t *regfile = s->regfile;
-
- assert(offset < 128);
- DPRINTF("write [0x%02x] = 0x%04x\n", offset, value);
-
- switch (offset) {
- case LM4549_Reset:
- lm4549_reset(s);
- break;
-
- case LM4549_PCM_Front_DAC_Rate:
- regfile[LM4549_PCM_Front_DAC_Rate] = value;
- DPRINTF("DAC rate change = %i\n", value);
-
- /* Re-open a voice with the new sample rate */
- struct audsettings as;
- as.freq = value;
- as.nchannels = 2;
- as.fmt = AUD_FMT_S16;
- as.endianness = 0;
-
- s->voice = AUD_open_out(
- &s->card,
- s->voice,
- "lm4549.out",
- s,
- lm4549_audio_out_callback,
- &as
- );
- break;
-
- case LM4549_Powerdown_Ctrl_Stat:
- value &= ~0xf;
- value |= regfile[LM4549_Powerdown_Ctrl_Stat] & 0xf;
- regfile[LM4549_Powerdown_Ctrl_Stat] = value;
- break;
-
- case LM4549_Ext_Audio_ID:
- case LM4549_Vendor_ID1:
- case LM4549_Vendor_ID2:
- DPRINTF("Write to read-only register 0x%x\n", (int)offset);
- break;
-
- default:
- /* Store the new value */
- regfile[offset] = value;
- break;
- }
-}
-
-uint32_t lm4549_write_samples(lm4549_state *s, uint32_t left, uint32_t right)
-{
- /* The left and right samples are in 20-bit resolution.
- The LM4549 has 18-bit resolution and only uses the bits [19:2].
- This model supports 16-bit playback.
- */
-
- if (s->buffer_level > LM4549_BUFFER_SIZE - 2) {
- DPRINTF("write_sample Buffer full\n");
- return 0;
- }
-
- /* Store 16-bit samples in the buffer */
- s->buffer[s->buffer_level++] = (left >> 4);
- s->buffer[s->buffer_level++] = (right >> 4);
-
- if (s->buffer_level == LM4549_BUFFER_SIZE) {
- /* Trigger the transfer of the buffer to the audio host */
- lm4549_audio_transfer(s);
- }
-
- return 1;
-}
-
-static int lm4549_post_load(void *opaque, int version_id)
-{
- lm4549_state *s = (lm4549_state *)opaque;
- uint16_t *regfile = s->regfile;
-
- /* Re-open a voice with the current sample rate */
- uint32_t freq = regfile[LM4549_PCM_Front_DAC_Rate];
-
- DPRINTF("post_load freq = %i\n", freq);
- DPRINTF("post_load voice_is_active = %i\n", s->voice_is_active);
-
- struct audsettings as;
- as.freq = freq;
- as.nchannels = 2;
- as.fmt = AUD_FMT_S16;
- as.endianness = 0;
-
- s->voice = AUD_open_out(
- &s->card,
- s->voice,
- "lm4549.out",
- s,
- lm4549_audio_out_callback,
- &as
- );
-
- /* Request data */
- if (s->voice_is_active == 1) {
- lm4549_audio_out_callback(s, AUD_get_buffer_size_out(s->voice));
- }
-
- return 0;
-}
-
-void lm4549_init(lm4549_state *s, lm4549_callback data_req_cb, void* opaque)
-{
- struct audsettings as;
-
- /* Store the callback and opaque pointer */
- s->data_req_cb = data_req_cb;
- s->opaque = opaque;
-
- /* Init the registers */
- lm4549_reset(s);
-
- /* Register an audio card */
- AUD_register_card("lm4549", &s->card);
-
- /* Open a default voice */
- as.freq = 48000;
- as.nchannels = 2;
- as.fmt = AUD_FMT_S16;
- as.endianness = 0;
-
- s->voice = AUD_open_out(
- &s->card,
- s->voice,
- "lm4549.out",
- s,
- lm4549_audio_out_callback,
- &as
- );
-
- AUD_set_volume_out(s->voice, 0, 255, 255);
-
- s->voice_is_active = 0;
-
- /* Reset the input buffer */
- memset(s->buffer, 0x00, sizeof(s->buffer));
- s->buffer_level = 0;
-
-#if defined(LM4549_DUMP_DAC_INPUT)
- fp_dac_input = fopen("lm4549_dac_input.pcm", "wb");
- if (!fp_dac_input) {
- hw_error("Unable to open lm4549_dac_input.pcm for writing\n");
- }
-#endif
-}
-
-const VMStateDescription vmstate_lm4549_state = {
- .name = "lm4549_state",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = lm4549_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(voice_is_active, lm4549_state),
- VMSTATE_UINT16_ARRAY(regfile, lm4549_state, 128),
- VMSTATE_UINT16_ARRAY(buffer, lm4549_state, LM4549_BUFFER_SIZE),
- VMSTATE_UINT32(buffer_level, lm4549_state),
- VMSTATE_END_OF_LIST()
- }
-};
diff --git a/qemu/hw/audio/lm4549.h b/qemu/hw/audio/lm4549.h
deleted file mode 100644
index 812a7a444..000000000
--- a/qemu/hw/audio/lm4549.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * LM4549 Audio Codec Interface
- *
- * Copyright (c) 2011
- * Written by Mathieu Sonet - www.elasticsheep.com
- *
- * This code is licensed under the GPL.
- *
- * *****************************************************************
- */
-
-#ifndef HW_LM4549_H
-#define HW_LM4549_H
-
-#include "audio/audio.h"
-
-typedef void (*lm4549_callback)(void *opaque);
-
-#define LM4549_BUFFER_SIZE (512 * 2) /* 512 16-bit stereo samples */
-
-
-typedef struct {
- QEMUSoundCard card;
- SWVoiceOut *voice;
- uint32_t voice_is_active;
-
- uint16_t regfile[128];
- lm4549_callback data_req_cb;
- void *opaque;
-
- uint16_t buffer[LM4549_BUFFER_SIZE];
- uint32_t buffer_level;
-} lm4549_state;
-
-extern const VMStateDescription vmstate_lm4549_state;
-
-
-void lm4549_init(lm4549_state *s, lm4549_callback data_req, void *opaque);
-uint32_t lm4549_read(lm4549_state *s, hwaddr offset);
-void lm4549_write(lm4549_state *s, hwaddr offset, uint32_t value);
-uint32_t lm4549_write_samples(lm4549_state *s, uint32_t left, uint32_t right);
-
-#endif /* #ifndef HW_LM4549_H */
diff --git a/qemu/hw/audio/marvell_88w8618.c b/qemu/hw/audio/marvell_88w8618.c
deleted file mode 100644
index a6ca1806b..000000000
--- a/qemu/hw/audio/marvell_88w8618.c
+++ /dev/null
@@ -1,307 +0,0 @@
-/*
- * Marvell 88w8618 audio emulation extracted from
- * Marvell MV88w8618 / Freecom MusicPal emulation.
- *
- * Copyright (c) 2008 Jan Kiszka
- *
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "hw/hw.h"
-#include "hw/i2c/i2c.h"
-#include "audio/audio.h"
-
-#define MP_AUDIO_SIZE 0x00001000
-
-/* Audio register offsets */
-#define MP_AUDIO_PLAYBACK_MODE 0x00
-#define MP_AUDIO_CLOCK_DIV 0x18
-#define MP_AUDIO_IRQ_STATUS 0x20
-#define MP_AUDIO_IRQ_ENABLE 0x24
-#define MP_AUDIO_TX_START_LO 0x28
-#define MP_AUDIO_TX_THRESHOLD 0x2C
-#define MP_AUDIO_TX_STATUS 0x38
-#define MP_AUDIO_TX_START_HI 0x40
-
-/* Status register and IRQ enable bits */
-#define MP_AUDIO_TX_HALF (1 << 6)
-#define MP_AUDIO_TX_FULL (1 << 7)
-
-/* Playback mode bits */
-#define MP_AUDIO_16BIT_SAMPLE (1 << 0)
-#define MP_AUDIO_PLAYBACK_EN (1 << 7)
-#define MP_AUDIO_CLOCK_24MHZ (1 << 9)
-#define MP_AUDIO_MONO (1 << 14)
-
-#define TYPE_MV88W8618_AUDIO "mv88w8618_audio"
-#define MV88W8618_AUDIO(obj) \
- OBJECT_CHECK(mv88w8618_audio_state, (obj), TYPE_MV88W8618_AUDIO)
-
-typedef struct mv88w8618_audio_state {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- qemu_irq irq;
- uint32_t playback_mode;
- uint32_t status;
- uint32_t irq_enable;
- uint32_t phys_buf;
- uint32_t target_buffer;
- uint32_t threshold;
- uint32_t play_pos;
- uint32_t last_free;
- uint32_t clock_div;
- void *wm;
-} mv88w8618_audio_state;
-
-static void mv88w8618_audio_callback(void *opaque, int free_out, int free_in)
-{
- mv88w8618_audio_state *s = opaque;
- int16_t *codec_buffer;
- int8_t buf[4096];
- int8_t *mem_buffer;
- int pos, block_size;
-
- if (!(s->playback_mode & MP_AUDIO_PLAYBACK_EN)) {
- return;
- }
- if (s->playback_mode & MP_AUDIO_16BIT_SAMPLE) {
- free_out <<= 1;
- }
- if (!(s->playback_mode & MP_AUDIO_MONO)) {
- free_out <<= 1;
- }
- block_size = s->threshold / 2;
- if (free_out - s->last_free < block_size) {
- return;
- }
- if (block_size > 4096) {
- return;
- }
- cpu_physical_memory_read(s->target_buffer + s->play_pos, buf, block_size);
- mem_buffer = buf;
- if (s->playback_mode & MP_AUDIO_16BIT_SAMPLE) {
- if (s->playback_mode & MP_AUDIO_MONO) {
- codec_buffer = wm8750_dac_buffer(s->wm, block_size >> 1);
- for (pos = 0; pos < block_size; pos += 2) {
- *codec_buffer++ = *(int16_t *)mem_buffer;
- *codec_buffer++ = *(int16_t *)mem_buffer;
- mem_buffer += 2;
- }
- } else {
- memcpy(wm8750_dac_buffer(s->wm, block_size >> 2),
- (uint32_t *)mem_buffer, block_size);
- }
- } else {
- if (s->playback_mode & MP_AUDIO_MONO) {
- codec_buffer = wm8750_dac_buffer(s->wm, block_size);
- for (pos = 0; pos < block_size; pos++) {
- *codec_buffer++ = cpu_to_le16(256 * *mem_buffer);
- *codec_buffer++ = cpu_to_le16(256 * *mem_buffer++);
- }
- } else {
- codec_buffer = wm8750_dac_buffer(s->wm, block_size >> 1);
- for (pos = 0; pos < block_size; pos += 2) {
- *codec_buffer++ = cpu_to_le16(256 * *mem_buffer++);
- *codec_buffer++ = cpu_to_le16(256 * *mem_buffer++);
- }
- }
- }
- wm8750_dac_commit(s->wm);
-
- s->last_free = free_out - block_size;
-
- if (s->play_pos == 0) {
- s->status |= MP_AUDIO_TX_HALF;
- s->play_pos = block_size;
- } else {
- s->status |= MP_AUDIO_TX_FULL;
- s->play_pos = 0;
- }
-
- if (s->status & s->irq_enable) {
- qemu_irq_raise(s->irq);
- }
-}
-
-static void mv88w8618_audio_clock_update(mv88w8618_audio_state *s)
-{
- int rate;
-
- if (s->playback_mode & MP_AUDIO_CLOCK_24MHZ) {
- rate = 24576000 / 64; /* 24.576MHz */
- } else {
- rate = 11289600 / 64; /* 11.2896MHz */
- }
- rate /= ((s->clock_div >> 8) & 0xff) + 1;
-
- wm8750_set_bclk_in(s->wm, rate);
-}
-
-static uint64_t mv88w8618_audio_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- mv88w8618_audio_state *s = opaque;
-
- switch (offset) {
- case MP_AUDIO_PLAYBACK_MODE:
- return s->playback_mode;
-
- case MP_AUDIO_CLOCK_DIV:
- return s->clock_div;
-
- case MP_AUDIO_IRQ_STATUS:
- return s->status;
-
- case MP_AUDIO_IRQ_ENABLE:
- return s->irq_enable;
-
- case MP_AUDIO_TX_STATUS:
- return s->play_pos >> 2;
-
- default:
- return 0;
- }
-}
-
-static void mv88w8618_audio_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- mv88w8618_audio_state *s = opaque;
-
- switch (offset) {
- case MP_AUDIO_PLAYBACK_MODE:
- if (value & MP_AUDIO_PLAYBACK_EN &&
- !(s->playback_mode & MP_AUDIO_PLAYBACK_EN)) {
- s->status = 0;
- s->last_free = 0;
- s->play_pos = 0;
- }
- s->playback_mode = value;
- mv88w8618_audio_clock_update(s);
- break;
-
- case MP_AUDIO_CLOCK_DIV:
- s->clock_div = value;
- s->last_free = 0;
- s->play_pos = 0;
- mv88w8618_audio_clock_update(s);
- break;
-
- case MP_AUDIO_IRQ_STATUS:
- s->status &= ~value;
- break;
-
- case MP_AUDIO_IRQ_ENABLE:
- s->irq_enable = value;
- if (s->status & s->irq_enable) {
- qemu_irq_raise(s->irq);
- }
- break;
-
- case MP_AUDIO_TX_START_LO:
- s->phys_buf = (s->phys_buf & 0xFFFF0000) | (value & 0xFFFF);
- s->target_buffer = s->phys_buf;
- s->play_pos = 0;
- s->last_free = 0;
- break;
-
- case MP_AUDIO_TX_THRESHOLD:
- s->threshold = (value + 1) * 4;
- break;
-
- case MP_AUDIO_TX_START_HI:
- s->phys_buf = (s->phys_buf & 0xFFFF) | (value << 16);
- s->target_buffer = s->phys_buf;
- s->play_pos = 0;
- s->last_free = 0;
- break;
- }
-}
-
-static void mv88w8618_audio_reset(DeviceState *d)
-{
- mv88w8618_audio_state *s = MV88W8618_AUDIO(d);
-
- s->playback_mode = 0;
- s->status = 0;
- s->irq_enable = 0;
- s->clock_div = 0;
- s->threshold = 0;
- s->phys_buf = 0;
-}
-
-static const MemoryRegionOps mv88w8618_audio_ops = {
- .read = mv88w8618_audio_read,
- .write = mv88w8618_audio_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int mv88w8618_audio_init(SysBusDevice *dev)
-{
- mv88w8618_audio_state *s = MV88W8618_AUDIO(dev);
-
- sysbus_init_irq(dev, &s->irq);
-
- wm8750_data_req_set(s->wm, mv88w8618_audio_callback, s);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &mv88w8618_audio_ops, s,
- "audio", MP_AUDIO_SIZE);
- sysbus_init_mmio(dev, &s->iomem);
-
- return 0;
-}
-
-static const VMStateDescription mv88w8618_audio_vmsd = {
- .name = "mv88w8618_audio",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(playback_mode, mv88w8618_audio_state),
- VMSTATE_UINT32(status, mv88w8618_audio_state),
- VMSTATE_UINT32(irq_enable, mv88w8618_audio_state),
- VMSTATE_UINT32(phys_buf, mv88w8618_audio_state),
- VMSTATE_UINT32(target_buffer, mv88w8618_audio_state),
- VMSTATE_UINT32(threshold, mv88w8618_audio_state),
- VMSTATE_UINT32(play_pos, mv88w8618_audio_state),
- VMSTATE_UINT32(last_free, mv88w8618_audio_state),
- VMSTATE_UINT32(clock_div, mv88w8618_audio_state),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property mv88w8618_audio_properties[] = {
- DEFINE_PROP_PTR("wm8750", mv88w8618_audio_state, wm),
- {/* end of list */},
-};
-
-static void mv88w8618_audio_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = mv88w8618_audio_init;
- dc->reset = mv88w8618_audio_reset;
- dc->vmsd = &mv88w8618_audio_vmsd;
- dc->props = mv88w8618_audio_properties;
- /* Reason: pointer property "wm8750" */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo mv88w8618_audio_info = {
- .name = TYPE_MV88W8618_AUDIO,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(mv88w8618_audio_state),
- .class_init = mv88w8618_audio_class_init,
-};
-
-static void mv88w8618_register_types(void)
-{
- type_register_static(&mv88w8618_audio_info);
-}
-
-type_init(mv88w8618_register_types)
diff --git a/qemu/hw/audio/milkymist-ac97.c b/qemu/hw/audio/milkymist-ac97.c
deleted file mode 100644
index 6a3b53674..000000000
--- a/qemu/hw/audio/milkymist-ac97.c
+++ /dev/null
@@ -1,349 +0,0 @@
-/*
- * QEMU model of the Milkymist System Controller.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * Specification available at:
- * http://www.milkymist.org/socdoc/ac97.pdf
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "audio/audio.h"
-#include "qemu/error-report.h"
-
-enum {
- R_AC97_CTRL = 0,
- R_AC97_ADDR,
- R_AC97_DATAOUT,
- R_AC97_DATAIN,
- R_D_CTRL,
- R_D_ADDR,
- R_D_REMAINING,
- R_RESERVED,
- R_U_CTRL,
- R_U_ADDR,
- R_U_REMAINING,
- R_MAX
-};
-
-enum {
- AC97_CTRL_RQEN = (1<<0),
- AC97_CTRL_WRITE = (1<<1),
-};
-
-enum {
- CTRL_EN = (1<<0),
-};
-
-#define TYPE_MILKYMIST_AC97 "milkymist-ac97"
-#define MILKYMIST_AC97(obj) \
- OBJECT_CHECK(MilkymistAC97State, (obj), TYPE_MILKYMIST_AC97)
-
-struct MilkymistAC97State {
- SysBusDevice parent_obj;
-
- MemoryRegion regs_region;
-
- QEMUSoundCard card;
- SWVoiceIn *voice_in;
- SWVoiceOut *voice_out;
-
- uint32_t regs[R_MAX];
-
- qemu_irq crrequest_irq;
- qemu_irq crreply_irq;
- qemu_irq dmar_irq;
- qemu_irq dmaw_irq;
-};
-typedef struct MilkymistAC97State MilkymistAC97State;
-
-static void update_voices(MilkymistAC97State *s)
-{
- if (s->regs[R_D_CTRL] & CTRL_EN) {
- AUD_set_active_out(s->voice_out, 1);
- } else {
- AUD_set_active_out(s->voice_out, 0);
- }
-
- if (s->regs[R_U_CTRL] & CTRL_EN) {
- AUD_set_active_in(s->voice_in, 1);
- } else {
- AUD_set_active_in(s->voice_in, 0);
- }
-}
-
-static uint64_t ac97_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- MilkymistAC97State *s = opaque;
- uint32_t r = 0;
-
- addr >>= 2;
- switch (addr) {
- case R_AC97_CTRL:
- case R_AC97_ADDR:
- case R_AC97_DATAOUT:
- case R_AC97_DATAIN:
- case R_D_CTRL:
- case R_D_ADDR:
- case R_D_REMAINING:
- case R_U_CTRL:
- case R_U_ADDR:
- case R_U_REMAINING:
- r = s->regs[addr];
- break;
-
- default:
- error_report("milkymist_ac97: read access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-
- trace_milkymist_ac97_memory_read(addr << 2, r);
-
- return r;
-}
-
-static void ac97_write(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
- MilkymistAC97State *s = opaque;
-
- trace_milkymist_ac97_memory_write(addr, value);
-
- addr >>= 2;
- switch (addr) {
- case R_AC97_CTRL:
- /* always raise an IRQ according to the direction */
- if (value & AC97_CTRL_RQEN) {
- if (value & AC97_CTRL_WRITE) {
- trace_milkymist_ac97_pulse_irq_crrequest();
- qemu_irq_pulse(s->crrequest_irq);
- } else {
- trace_milkymist_ac97_pulse_irq_crreply();
- qemu_irq_pulse(s->crreply_irq);
- }
- }
-
- /* RQEN is self clearing */
- s->regs[addr] = value & ~AC97_CTRL_RQEN;
- break;
- case R_D_CTRL:
- case R_U_CTRL:
- s->regs[addr] = value;
- update_voices(s);
- break;
- case R_AC97_ADDR:
- case R_AC97_DATAOUT:
- case R_AC97_DATAIN:
- case R_D_ADDR:
- case R_D_REMAINING:
- case R_U_ADDR:
- case R_U_REMAINING:
- s->regs[addr] = value;
- break;
-
- default:
- error_report("milkymist_ac97: write access to unknown register 0x"
- TARGET_FMT_plx, addr);
- break;
- }
-
-}
-
-static const MemoryRegionOps ac97_mmio_ops = {
- .read = ac97_read,
- .write = ac97_write,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void ac97_in_cb(void *opaque, int avail_b)
-{
- MilkymistAC97State *s = opaque;
- uint8_t buf[4096];
- uint32_t remaining = s->regs[R_U_REMAINING];
- int temp = audio_MIN(remaining, avail_b);
- uint32_t addr = s->regs[R_U_ADDR];
- int transferred = 0;
-
- trace_milkymist_ac97_in_cb(avail_b, remaining);
-
- /* prevent from raising an IRQ */
- if (temp == 0) {
- return;
- }
-
- while (temp) {
- int acquired, to_copy;
-
- to_copy = audio_MIN(temp, sizeof(buf));
- acquired = AUD_read(s->voice_in, buf, to_copy);
- if (!acquired) {
- break;
- }
-
- cpu_physical_memory_write(addr, buf, acquired);
-
- temp -= acquired;
- addr += acquired;
- transferred += acquired;
- }
-
- trace_milkymist_ac97_in_cb_transferred(transferred);
-
- s->regs[R_U_ADDR] = addr;
- s->regs[R_U_REMAINING] -= transferred;
-
- if ((s->regs[R_U_CTRL] & CTRL_EN) && (s->regs[R_U_REMAINING] == 0)) {
- trace_milkymist_ac97_pulse_irq_dmaw();
- qemu_irq_pulse(s->dmaw_irq);
- }
-}
-
-static void ac97_out_cb(void *opaque, int free_b)
-{
- MilkymistAC97State *s = opaque;
- uint8_t buf[4096];
- uint32_t remaining = s->regs[R_D_REMAINING];
- int temp = audio_MIN(remaining, free_b);
- uint32_t addr = s->regs[R_D_ADDR];
- int transferred = 0;
-
- trace_milkymist_ac97_out_cb(free_b, remaining);
-
- /* prevent from raising an IRQ */
- if (temp == 0) {
- return;
- }
-
- while (temp) {
- int copied, to_copy;
-
- to_copy = audio_MIN(temp, sizeof(buf));
- cpu_physical_memory_read(addr, buf, to_copy);
- copied = AUD_write(s->voice_out, buf, to_copy);
- if (!copied) {
- break;
- }
- temp -= copied;
- addr += copied;
- transferred += copied;
- }
-
- trace_milkymist_ac97_out_cb_transferred(transferred);
-
- s->regs[R_D_ADDR] = addr;
- s->regs[R_D_REMAINING] -= transferred;
-
- if ((s->regs[R_D_CTRL] & CTRL_EN) && (s->regs[R_D_REMAINING] == 0)) {
- trace_milkymist_ac97_pulse_irq_dmar();
- qemu_irq_pulse(s->dmar_irq);
- }
-}
-
-static void milkymist_ac97_reset(DeviceState *d)
-{
- MilkymistAC97State *s = MILKYMIST_AC97(d);
- int i;
-
- for (i = 0; i < R_MAX; i++) {
- s->regs[i] = 0;
- }
-
- AUD_set_active_in(s->voice_in, 0);
- AUD_set_active_out(s->voice_out, 0);
-}
-
-static int ac97_post_load(void *opaque, int version_id)
-{
- MilkymistAC97State *s = opaque;
-
- update_voices(s);
-
- return 0;
-}
-
-static int milkymist_ac97_init(SysBusDevice *dev)
-{
- MilkymistAC97State *s = MILKYMIST_AC97(dev);
-
- struct audsettings as;
- sysbus_init_irq(dev, &s->crrequest_irq);
- sysbus_init_irq(dev, &s->crreply_irq);
- sysbus_init_irq(dev, &s->dmar_irq);
- sysbus_init_irq(dev, &s->dmaw_irq);
-
- AUD_register_card("Milkymist AC'97", &s->card);
-
- as.freq = 48000;
- as.nchannels = 2;
- as.fmt = AUD_FMT_S16;
- as.endianness = 1;
-
- s->voice_in = AUD_open_in(&s->card, s->voice_in,
- "mm_ac97.in", s, ac97_in_cb, &as);
- s->voice_out = AUD_open_out(&s->card, s->voice_out,
- "mm_ac97.out", s, ac97_out_cb, &as);
-
- memory_region_init_io(&s->regs_region, OBJECT(s), &ac97_mmio_ops, s,
- "milkymist-ac97", R_MAX * 4);
- sysbus_init_mmio(dev, &s->regs_region);
-
- return 0;
-}
-
-static const VMStateDescription vmstate_milkymist_ac97 = {
- .name = "milkymist-ac97",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = ac97_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, MilkymistAC97State, R_MAX),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void milkymist_ac97_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = milkymist_ac97_init;
- dc->reset = milkymist_ac97_reset;
- dc->vmsd = &vmstate_milkymist_ac97;
-}
-
-static const TypeInfo milkymist_ac97_info = {
- .name = TYPE_MILKYMIST_AC97,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(MilkymistAC97State),
- .class_init = milkymist_ac97_class_init,
-};
-
-static void milkymist_ac97_register_types(void)
-{
- type_register_static(&milkymist_ac97_info);
-}
-
-type_init(milkymist_ac97_register_types)
diff --git a/qemu/hw/audio/pcspk.c b/qemu/hw/audio/pcspk.c
deleted file mode 100644
index f9afc8eda..000000000
--- a/qemu/hw/audio/pcspk.c
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * QEMU PC speaker emulation
- *
- * Copyright (c) 2006 Joachim Henke
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/i386/pc.h"
-#include "hw/isa/isa.h"
-#include "hw/audio/audio.h"
-#include "audio/audio.h"
-#include "qemu/timer.h"
-#include "hw/timer/i8254.h"
-#include "hw/audio/pcspk.h"
-
-#define PCSPK_BUF_LEN 1792
-#define PCSPK_SAMPLE_RATE 32000
-#define PCSPK_MAX_FREQ (PCSPK_SAMPLE_RATE >> 1)
-#define PCSPK_MIN_COUNT ((PIT_FREQ + PCSPK_MAX_FREQ - 1) / PCSPK_MAX_FREQ)
-
-#define PC_SPEAKER(obj) OBJECT_CHECK(PCSpkState, (obj), TYPE_PC_SPEAKER)
-
-typedef struct {
- ISADevice parent_obj;
-
- MemoryRegion ioport;
- uint32_t iobase;
- uint8_t sample_buf[PCSPK_BUF_LEN];
- QEMUSoundCard card;
- SWVoiceOut *voice;
- void *pit;
- unsigned int pit_count;
- unsigned int samples;
- unsigned int play_pos;
- int data_on;
- int dummy_refresh_clock;
-} PCSpkState;
-
-static const char *s_spk = "pcspk";
-static PCSpkState *pcspk_state;
-
-static inline void generate_samples(PCSpkState *s)
-{
- unsigned int i;
-
- if (s->pit_count) {
- const uint32_t m = PCSPK_SAMPLE_RATE * s->pit_count;
- const uint32_t n = ((uint64_t)PIT_FREQ << 32) / m;
-
- /* multiple of wavelength for gapless looping */
- s->samples = (PCSPK_BUF_LEN * PIT_FREQ / m * m / (PIT_FREQ >> 1) + 1) >> 1;
- for (i = 0; i < s->samples; ++i)
- s->sample_buf[i] = (64 & (n * i >> 25)) - 32;
- } else {
- s->samples = PCSPK_BUF_LEN;
- for (i = 0; i < PCSPK_BUF_LEN; ++i)
- s->sample_buf[i] = 128; /* silence */
- }
-}
-
-static void pcspk_callback(void *opaque, int free)
-{
- PCSpkState *s = opaque;
- PITChannelInfo ch;
- unsigned int n;
-
- pit_get_channel_info(s->pit, 2, &ch);
-
- if (ch.mode != 3) {
- return;
- }
-
- n = ch.initial_count;
- /* avoid frequencies that are not reproducible with sample rate */
- if (n < PCSPK_MIN_COUNT)
- n = 0;
-
- if (s->pit_count != n) {
- s->pit_count = n;
- s->play_pos = 0;
- generate_samples(s);
- }
-
- while (free > 0) {
- n = audio_MIN(s->samples - s->play_pos, (unsigned int)free);
- n = AUD_write(s->voice, &s->sample_buf[s->play_pos], n);
- if (!n)
- break;
- s->play_pos = (s->play_pos + n) % s->samples;
- free -= n;
- }
-}
-
-static int pcspk_audio_init(ISABus *bus)
-{
- PCSpkState *s = pcspk_state;
- struct audsettings as = {PCSPK_SAMPLE_RATE, 1, AUD_FMT_U8, 0};
-
- AUD_register_card(s_spk, &s->card);
-
- s->voice = AUD_open_out(&s->card, s->voice, s_spk, s, pcspk_callback, &as);
- if (!s->voice) {
- AUD_log(s_spk, "Could not open voice\n");
- return -1;
- }
-
- return 0;
-}
-
-static uint64_t pcspk_io_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- PCSpkState *s = opaque;
- PITChannelInfo ch;
-
- pit_get_channel_info(s->pit, 2, &ch);
-
- s->dummy_refresh_clock ^= (1 << 4);
-
- return ch.gate | (s->data_on << 1) | s->dummy_refresh_clock |
- (ch.out << 5);
-}
-
-static void pcspk_io_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned size)
-{
- PCSpkState *s = opaque;
- const int gate = val & 1;
-
- s->data_on = (val >> 1) & 1;
- pit_set_gate(s->pit, 2, gate);
- if (s->voice) {
- if (gate) /* restart */
- s->play_pos = 0;
- AUD_set_active_out(s->voice, gate & s->data_on);
- }
-}
-
-static const MemoryRegionOps pcspk_io_ops = {
- .read = pcspk_io_read,
- .write = pcspk_io_write,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
-};
-
-static void pcspk_initfn(Object *obj)
-{
- PCSpkState *s = PC_SPEAKER(obj);
-
- memory_region_init_io(&s->ioport, OBJECT(s), &pcspk_io_ops, s, "pcspk", 1);
-}
-
-static void pcspk_realizefn(DeviceState *dev, Error **errp)
-{
- ISADevice *isadev = ISA_DEVICE(dev);
- PCSpkState *s = PC_SPEAKER(dev);
-
- isa_register_ioport(isadev, &s->ioport, s->iobase);
-
- pcspk_state = s;
-}
-
-static Property pcspk_properties[] = {
- DEFINE_PROP_UINT32("iobase", PCSpkState, iobase, -1),
- DEFINE_PROP_PTR("pit", PCSpkState, pit),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pcspk_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = pcspk_realizefn;
- set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
- dc->props = pcspk_properties;
- /* Reason: pointer property "pit", realize sets global pcspk_state */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo pcspk_info = {
- .name = TYPE_PC_SPEAKER,
- .parent = TYPE_ISA_DEVICE,
- .instance_size = sizeof(PCSpkState),
- .instance_init = pcspk_initfn,
- .class_init = pcspk_class_initfn,
-};
-
-static void pcspk_register(void)
-{
- type_register_static(&pcspk_info);
- isa_register_soundhw("pcspk", "PC speaker", pcspk_audio_init);
-}
-type_init(pcspk_register)
diff --git a/qemu/hw/audio/pl041.c b/qemu/hw/audio/pl041.c
deleted file mode 100644
index 4717bc9b9..000000000
--- a/qemu/hw/audio/pl041.c
+++ /dev/null
@@ -1,650 +0,0 @@
-/*
- * Arm PrimeCell PL041 Advanced Audio Codec Interface
- *
- * Copyright (c) 2011
- * Written by Mathieu Sonet - www.elasticsheep.com
- *
- * This code is licensed under the GPL.
- *
- * *****************************************************************
- *
- * This driver emulates the ARM AACI interface
- * connected to a LM4549 codec.
- *
- * Limitations:
- * - Supports only a playback on one channel (Versatile/Vexpress)
- * - Supports only one TX FIFO in compact-mode or non-compact mode.
- * - Supports playback of 12, 16, 18 and 20 bits samples.
- * - Record is not supported.
- * - The PL041 is hardwired to a LM4549 codec.
- *
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-
-#include "pl041.h"
-#include "lm4549.h"
-
-#if 0
-#define PL041_DEBUG_LEVEL 1
-#endif
-
-#if defined(PL041_DEBUG_LEVEL) && (PL041_DEBUG_LEVEL >= 1)
-#define DBG_L1(fmt, ...) \
-do { printf("pl041: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DBG_L1(fmt, ...) \
-do { } while (0)
-#endif
-
-#if defined(PL041_DEBUG_LEVEL) && (PL041_DEBUG_LEVEL >= 2)
-#define DBG_L2(fmt, ...) \
-do { printf("pl041: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DBG_L2(fmt, ...) \
-do { } while (0)
-#endif
-
-
-#define MAX_FIFO_DEPTH (1024)
-#define DEFAULT_FIFO_DEPTH (8)
-
-#define SLOT1_RW (1 << 19)
-
-/* This FIFO only stores 20-bit samples on 32-bit words.
- So its level is independent of the selected mode */
-typedef struct {
- uint32_t level;
- uint32_t data[MAX_FIFO_DEPTH];
-} pl041_fifo;
-
-typedef struct {
- pl041_fifo tx_fifo;
- uint8_t tx_enabled;
- uint8_t tx_compact_mode;
- uint8_t tx_sample_size;
-
- pl041_fifo rx_fifo;
- uint8_t rx_enabled;
- uint8_t rx_compact_mode;
- uint8_t rx_sample_size;
-} pl041_channel;
-
-#define TYPE_PL041 "pl041"
-#define PL041(obj) OBJECT_CHECK(PL041State, (obj), TYPE_PL041)
-
-typedef struct PL041State {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- qemu_irq irq;
-
- uint32_t fifo_depth; /* FIFO depth in non-compact mode */
-
- pl041_regfile regs;
- pl041_channel fifo1;
- lm4549_state codec;
-} PL041State;
-
-
-static const unsigned char pl041_default_id[8] = {
- 0x41, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1
-};
-
-#if defined(PL041_DEBUG_LEVEL)
-#define REGISTER(name, offset) #name,
-static const char *pl041_regs_name[] = {
- #include "pl041.hx"
-};
-#undef REGISTER
-#endif
-
-
-#if defined(PL041_DEBUG_LEVEL)
-static const char *get_reg_name(hwaddr offset)
-{
- if (offset <= PL041_dr1_7) {
- return pl041_regs_name[offset >> 2];
- }
-
- return "unknown";
-}
-#endif
-
-static uint8_t pl041_compute_periphid3(PL041State *s)
-{
- uint8_t id3 = 1; /* One channel */
-
- /* Add the fifo depth information */
- switch (s->fifo_depth) {
- case 8:
- id3 |= 0 << 3;
- break;
- case 32:
- id3 |= 1 << 3;
- break;
- case 64:
- id3 |= 2 << 3;
- break;
- case 128:
- id3 |= 3 << 3;
- break;
- case 256:
- id3 |= 4 << 3;
- break;
- case 512:
- id3 |= 5 << 3;
- break;
- case 1024:
- id3 |= 6 << 3;
- break;
- case 2048:
- id3 |= 7 << 3;
- break;
- }
-
- return id3;
-}
-
-static void pl041_reset(PL041State *s)
-{
- DBG_L1("pl041_reset\n");
-
- memset(&s->regs, 0x00, sizeof(pl041_regfile));
-
- s->regs.slfr = SL1TXEMPTY | SL2TXEMPTY | SL12TXEMPTY;
- s->regs.sr1 = TXFE | RXFE | TXHE;
- s->regs.isr1 = 0;
-
- memset(&s->fifo1, 0x00, sizeof(s->fifo1));
-}
-
-
-static void pl041_fifo1_write(PL041State *s, uint32_t value)
-{
- pl041_channel *channel = &s->fifo1;
- pl041_fifo *fifo = &s->fifo1.tx_fifo;
-
- /* Push the value in the FIFO */
- if (channel->tx_compact_mode == 0) {
- /* Non-compact mode */
-
- if (fifo->level < s->fifo_depth) {
- /* Pad the value with 0 to obtain a 20-bit sample */
- switch (channel->tx_sample_size) {
- case 12:
- value = (value << 8) & 0xFFFFF;
- break;
- case 16:
- value = (value << 4) & 0xFFFFF;
- break;
- case 18:
- value = (value << 2) & 0xFFFFF;
- break;
- case 20:
- default:
- break;
- }
-
- /* Store the sample in the FIFO */
- fifo->data[fifo->level++] = value;
- }
-#if defined(PL041_DEBUG_LEVEL)
- else {
- DBG_L1("fifo1 write: overrun\n");
- }
-#endif
- } else {
- /* Compact mode */
-
- if ((fifo->level + 2) < s->fifo_depth) {
- uint32_t i = 0;
- uint32_t sample = 0;
-
- for (i = 0; i < 2; i++) {
- sample = value & 0xFFFF;
- value = value >> 16;
-
- /* Pad each sample with 0 to obtain a 20-bit sample */
- switch (channel->tx_sample_size) {
- case 12:
- sample = sample << 8;
- break;
- case 16:
- default:
- sample = sample << 4;
- break;
- }
-
- /* Store the sample in the FIFO */
- fifo->data[fifo->level++] = sample;
- }
- }
-#if defined(PL041_DEBUG_LEVEL)
- else {
- DBG_L1("fifo1 write: overrun\n");
- }
-#endif
- }
-
- /* Update the status register */
- if (fifo->level > 0) {
- s->regs.sr1 &= ~(TXUNDERRUN | TXFE);
- }
-
- if (fifo->level >= (s->fifo_depth / 2)) {
- s->regs.sr1 &= ~TXHE;
- }
-
- if (fifo->level >= s->fifo_depth) {
- s->regs.sr1 |= TXFF;
- }
-
- DBG_L2("fifo1_push sr1 = 0x%08x\n", s->regs.sr1);
-}
-
-static void pl041_fifo1_transmit(PL041State *s)
-{
- pl041_channel *channel = &s->fifo1;
- pl041_fifo *fifo = &s->fifo1.tx_fifo;
- uint32_t slots = s->regs.txcr1 & TXSLOT_MASK;
- uint32_t written_samples;
-
- /* Check if FIFO1 transmit is enabled */
- if ((channel->tx_enabled) && (slots & (TXSLOT3 | TXSLOT4))) {
- if (fifo->level >= (s->fifo_depth / 2)) {
- int i;
-
- DBG_L1("Transfer FIFO level = %i\n", fifo->level);
-
- /* Try to transfer the whole FIFO */
- for (i = 0; i < (fifo->level / 2); i++) {
- uint32_t left = fifo->data[i * 2];
- uint32_t right = fifo->data[i * 2 + 1];
-
- /* Transmit two 20-bit samples to the codec */
- if (lm4549_write_samples(&s->codec, left, right) == 0) {
- DBG_L1("Codec buffer full\n");
- break;
- }
- }
-
- written_samples = i * 2;
- if (written_samples > 0) {
- /* Update the FIFO level */
- fifo->level -= written_samples;
-
- /* Move back the pending samples to the start of the FIFO */
- for (i = 0; i < fifo->level; i++) {
- fifo->data[i] = fifo->data[written_samples + i];
- }
-
- /* Update the status register */
- s->regs.sr1 &= ~TXFF;
-
- if (fifo->level <= (s->fifo_depth / 2)) {
- s->regs.sr1 |= TXHE;
- }
-
- if (fifo->level == 0) {
- s->regs.sr1 |= TXFE | TXUNDERRUN;
- DBG_L1("Empty FIFO\n");
- }
- }
- }
- }
-}
-
-static void pl041_isr1_update(PL041State *s)
-{
- /* Update ISR1 */
- if (s->regs.sr1 & TXUNDERRUN) {
- s->regs.isr1 |= URINTR;
- } else {
- s->regs.isr1 &= ~URINTR;
- }
-
- if (s->regs.sr1 & TXHE) {
- s->regs.isr1 |= TXINTR;
- } else {
- s->regs.isr1 &= ~TXINTR;
- }
-
- if (!(s->regs.sr1 & TXBUSY) && (s->regs.sr1 & TXFE)) {
- s->regs.isr1 |= TXCINTR;
- } else {
- s->regs.isr1 &= ~TXCINTR;
- }
-
- /* Update the irq state */
- qemu_set_irq(s->irq, ((s->regs.isr1 & s->regs.ie1) > 0) ? 1 : 0);
- DBG_L2("Set interrupt sr1 = 0x%08x isr1 = 0x%08x masked = 0x%08x\n",
- s->regs.sr1, s->regs.isr1, s->regs.isr1 & s->regs.ie1);
-}
-
-static void pl041_request_data(void *opaque)
-{
- PL041State *s = (PL041State *)opaque;
-
- /* Trigger pending transfers */
- pl041_fifo1_transmit(s);
- pl041_isr1_update(s);
-}
-
-static uint64_t pl041_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- PL041State *s = (PL041State *)opaque;
- int value;
-
- if ((offset >= PL041_periphid0) && (offset <= PL041_pcellid3)) {
- if (offset == PL041_periphid3) {
- value = pl041_compute_periphid3(s);
- } else {
- value = pl041_default_id[(offset - PL041_periphid0) >> 2];
- }
-
- DBG_L1("pl041_read [0x%08x] => 0x%08x\n", offset, value);
- return value;
- } else if (offset <= PL041_dr4_7) {
- value = *((uint32_t *)&s->regs + (offset >> 2));
- } else {
- DBG_L1("pl041_read: Reserved offset %x\n", (int)offset);
- return 0;
- }
-
- switch (offset) {
- case PL041_allints:
- value = s->regs.isr1 & 0x7F;
- break;
- }
-
- DBG_L1("pl041_read [0x%08x] %s => 0x%08x\n", offset,
- get_reg_name(offset), value);
-
- return value;
-}
-
-static void pl041_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PL041State *s = (PL041State *)opaque;
- uint16_t control, data;
- uint32_t result;
-
- DBG_L1("pl041_write [0x%08x] %s <= 0x%08x\n", offset,
- get_reg_name(offset), (unsigned int)value);
-
- /* Write the register */
- if (offset <= PL041_dr4_7) {
- *((uint32_t *)&s->regs + (offset >> 2)) = value;
- } else {
- DBG_L1("pl041_write: Reserved offset %x\n", (int)offset);
- return;
- }
-
- /* Execute the actions */
- switch (offset) {
- case PL041_txcr1:
- {
- pl041_channel *channel = &s->fifo1;
-
- uint32_t txen = s->regs.txcr1 & TXEN;
- uint32_t tsize = (s->regs.txcr1 & TSIZE_MASK) >> TSIZE_MASK_BIT;
- uint32_t compact_mode = (s->regs.txcr1 & TXCOMPACT) ? 1 : 0;
-#if defined(PL041_DEBUG_LEVEL)
- uint32_t slots = (s->regs.txcr1 & TXSLOT_MASK) >> TXSLOT_MASK_BIT;
- uint32_t txfen = (s->regs.txcr1 & TXFEN) > 0 ? 1 : 0;
-#endif
-
- DBG_L1("=> txen = %i slots = 0x%01x tsize = %i compact = %i "
- "txfen = %i\n", txen, slots, tsize, compact_mode, txfen);
-
- channel->tx_enabled = txen;
- channel->tx_compact_mode = compact_mode;
-
- switch (tsize) {
- case 0:
- channel->tx_sample_size = 16;
- break;
- case 1:
- channel->tx_sample_size = 18;
- break;
- case 2:
- channel->tx_sample_size = 20;
- break;
- case 3:
- channel->tx_sample_size = 12;
- break;
- }
-
- DBG_L1("TX enabled = %i\n", channel->tx_enabled);
- DBG_L1("TX compact mode = %i\n", channel->tx_compact_mode);
- DBG_L1("TX sample width = %i\n", channel->tx_sample_size);
-
- /* Check if compact mode is allowed with selected tsize */
- if (channel->tx_compact_mode == 1) {
- if ((channel->tx_sample_size == 18) ||
- (channel->tx_sample_size == 20)) {
- channel->tx_compact_mode = 0;
- DBG_L1("Compact mode not allowed with 18/20-bit sample size\n");
- }
- }
-
- break;
- }
- case PL041_sl1tx:
- s->regs.slfr &= ~SL1TXEMPTY;
-
- control = (s->regs.sl1tx >> 12) & 0x7F;
- data = (s->regs.sl2tx >> 4) & 0xFFFF;
-
- if ((s->regs.sl1tx & SLOT1_RW) == 0) {
- /* Write operation */
- lm4549_write(&s->codec, control, data);
- } else {
- /* Read operation */
- result = lm4549_read(&s->codec, control);
-
- /* Store the returned value */
- s->regs.sl1rx = s->regs.sl1tx & ~SLOT1_RW;
- s->regs.sl2rx = result << 4;
-
- s->regs.slfr &= ~(SL1RXBUSY | SL2RXBUSY);
- s->regs.slfr |= SL1RXVALID | SL2RXVALID;
- }
- break;
-
- case PL041_sl2tx:
- s->regs.sl2tx = value;
- s->regs.slfr &= ~SL2TXEMPTY;
- break;
-
- case PL041_intclr:
- DBG_L1("=> Clear interrupt intclr = 0x%08x isr1 = 0x%08x\n",
- s->regs.intclr, s->regs.isr1);
-
- if (s->regs.intclr & TXUEC1) {
- s->regs.sr1 &= ~TXUNDERRUN;
- }
- break;
-
- case PL041_maincr:
- {
-#if defined(PL041_DEBUG_LEVEL)
- char debug[] = " AACIFE SL1RXEN SL1TXEN";
- if (!(value & AACIFE)) {
- debug[0] = '!';
- }
- if (!(value & SL1RXEN)) {
- debug[8] = '!';
- }
- if (!(value & SL1TXEN)) {
- debug[17] = '!';
- }
- DBG_L1("%s\n", debug);
-#endif
-
- if ((s->regs.maincr & AACIFE) == 0) {
- pl041_reset(s);
- }
- break;
- }
-
- case PL041_dr1_0:
- case PL041_dr1_1:
- case PL041_dr1_2:
- case PL041_dr1_3:
- pl041_fifo1_write(s, value);
- break;
- }
-
- /* Transmit the FIFO content */
- pl041_fifo1_transmit(s);
-
- /* Update the ISR1 register */
- pl041_isr1_update(s);
-}
-
-static void pl041_device_reset(DeviceState *d)
-{
- PL041State *s = PL041(d);
-
- pl041_reset(s);
-}
-
-static const MemoryRegionOps pl041_ops = {
- .read = pl041_read,
- .write = pl041_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int pl041_init(SysBusDevice *dev)
-{
- PL041State *s = PL041(dev);
-
- DBG_L1("pl041_init 0x%08x\n", (uint32_t)s);
-
- /* Check the device properties */
- switch (s->fifo_depth) {
- case 8:
- case 32:
- case 64:
- case 128:
- case 256:
- case 512:
- case 1024:
- case 2048:
- break;
- case 16:
- default:
- /* NC FIFO depth of 16 is not allowed because its id bits in
- AACIPERIPHID3 overlap with the id for the default NC FIFO depth */
- qemu_log_mask(LOG_UNIMP,
- "pl041: unsupported non-compact fifo depth [%i]\n",
- s->fifo_depth);
- return -1;
- }
-
- /* Connect the device to the sysbus */
- memory_region_init_io(&s->iomem, OBJECT(s), &pl041_ops, s, "pl041", 0x1000);
- sysbus_init_mmio(dev, &s->iomem);
- sysbus_init_irq(dev, &s->irq);
-
- /* Init the codec */
- lm4549_init(&s->codec, &pl041_request_data, (void *)s);
-
- return 0;
-}
-
-static const VMStateDescription vmstate_pl041_regfile = {
- .name = "pl041_regfile",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
-#define REGISTER(name, offset) VMSTATE_UINT32(name, pl041_regfile),
- #include "pl041.hx"
-#undef REGISTER
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_pl041_fifo = {
- .name = "pl041_fifo",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(level, pl041_fifo),
- VMSTATE_UINT32_ARRAY(data, pl041_fifo, MAX_FIFO_DEPTH),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_pl041_channel = {
- .name = "pl041_channel",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT(tx_fifo, pl041_channel, 0,
- vmstate_pl041_fifo, pl041_fifo),
- VMSTATE_UINT8(tx_enabled, pl041_channel),
- VMSTATE_UINT8(tx_compact_mode, pl041_channel),
- VMSTATE_UINT8(tx_sample_size, pl041_channel),
- VMSTATE_STRUCT(rx_fifo, pl041_channel, 0,
- vmstate_pl041_fifo, pl041_fifo),
- VMSTATE_UINT8(rx_enabled, pl041_channel),
- VMSTATE_UINT8(rx_compact_mode, pl041_channel),
- VMSTATE_UINT8(rx_sample_size, pl041_channel),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_pl041 = {
- .name = "pl041",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(fifo_depth, PL041State),
- VMSTATE_STRUCT(regs, PL041State, 0,
- vmstate_pl041_regfile, pl041_regfile),
- VMSTATE_STRUCT(fifo1, PL041State, 0,
- vmstate_pl041_channel, pl041_channel),
- VMSTATE_STRUCT(codec, PL041State, 0,
- vmstate_lm4549_state, lm4549_state),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property pl041_device_properties[] = {
- /* Non-compact FIFO depth property */
- DEFINE_PROP_UINT32("nc_fifo_depth", PL041State, fifo_depth,
- DEFAULT_FIFO_DEPTH),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pl041_device_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = pl041_init;
- set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
- dc->reset = pl041_device_reset;
- dc->vmsd = &vmstate_pl041;
- dc->props = pl041_device_properties;
-}
-
-static const TypeInfo pl041_device_info = {
- .name = TYPE_PL041,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PL041State),
- .class_init = pl041_device_class_init,
-};
-
-static void pl041_register_types(void)
-{
- type_register_static(&pl041_device_info);
-}
-
-type_init(pl041_register_types)
diff --git a/qemu/hw/audio/pl041.h b/qemu/hw/audio/pl041.h
deleted file mode 100644
index 427ab6d6f..000000000
--- a/qemu/hw/audio/pl041.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Arm PrimeCell PL041 Advanced Audio Codec Interface
- *
- * Copyright (c) 2011
- * Written by Mathieu Sonet - www.elasticsheep.com
- *
- * This code is licensed under the GPL.
- *
- * *****************************************************************
- */
-
-#ifndef HW_PL041_H
-#define HW_PL041_H
-
-/* Register file */
-#define REGISTER(name, offset) uint32_t name;
-typedef struct {
- #include "pl041.hx"
-} pl041_regfile;
-#undef REGISTER
-
-/* Register addresses */
-#define REGISTER(name, offset) PL041_##name = offset,
-enum {
- #include "pl041.hx"
-
- PL041_periphid0 = 0xFE0,
- PL041_periphid1 = 0xFE4,
- PL041_periphid2 = 0xFE8,
- PL041_periphid3 = 0xFEC,
- PL041_pcellid0 = 0xFF0,
- PL041_pcellid1 = 0xFF4,
- PL041_pcellid2 = 0xFF8,
- PL041_pcellid3 = 0xFFC,
-};
-#undef REGISTER
-
-/* Register bits */
-
-/* IEx */
-#define TXCIE (1 << 0)
-#define RXTIE (1 << 1)
-#define TXIE (1 << 2)
-#define RXIE (1 << 3)
-#define RXOIE (1 << 4)
-#define TXUIE (1 << 5)
-#define RXTOIE (1 << 6)
-
-/* TXCRx */
-#define TXEN (1 << 0)
-#define TXSLOT1 (1 << 1)
-#define TXSLOT2 (1 << 2)
-#define TXSLOT3 (1 << 3)
-#define TXSLOT4 (1 << 4)
-#define TXCOMPACT (1 << 15)
-#define TXFEN (1 << 16)
-
-#define TXSLOT_MASK_BIT (1)
-#define TXSLOT_MASK (0xFFF << TXSLOT_MASK_BIT)
-
-#define TSIZE_MASK_BIT (13)
-#define TSIZE_MASK (0x3 << TSIZE_MASK_BIT)
-
-#define TSIZE_16BITS (0x0 << TSIZE_MASK_BIT)
-#define TSIZE_18BITS (0x1 << TSIZE_MASK_BIT)
-#define TSIZE_20BITS (0x2 << TSIZE_MASK_BIT)
-#define TSIZE_12BITS (0x3 << TSIZE_MASK_BIT)
-
-/* SRx */
-#define RXFE (1 << 0)
-#define TXFE (1 << 1)
-#define RXHF (1 << 2)
-#define TXHE (1 << 3)
-#define RXFF (1 << 4)
-#define TXFF (1 << 5)
-#define RXBUSY (1 << 6)
-#define TXBUSY (1 << 7)
-#define RXOVERRUN (1 << 8)
-#define TXUNDERRUN (1 << 9)
-#define RXTIMEOUT (1 << 10)
-#define RXTOFE (1 << 11)
-
-/* ISRx */
-#define TXCINTR (1 << 0)
-#define RXTOINTR (1 << 1)
-#define TXINTR (1 << 2)
-#define RXINTR (1 << 3)
-#define ORINTR (1 << 4)
-#define URINTR (1 << 5)
-#define RXTOFEINTR (1 << 6)
-
-/* SLFR */
-#define SL1RXBUSY (1 << 0)
-#define SL1TXBUSY (1 << 1)
-#define SL2RXBUSY (1 << 2)
-#define SL2TXBUSY (1 << 3)
-#define SL12RXBUSY (1 << 4)
-#define SL12TXBUSY (1 << 5)
-#define SL1RXVALID (1 << 6)
-#define SL1TXEMPTY (1 << 7)
-#define SL2RXVALID (1 << 8)
-#define SL2TXEMPTY (1 << 9)
-#define SL12RXVALID (1 << 10)
-#define SL12TXEMPTY (1 << 11)
-#define RAWGPIOINT (1 << 12)
-#define RWIS (1 << 13)
-
-/* MAINCR */
-#define AACIFE (1 << 0)
-#define LOOPBACK (1 << 1)
-#define LOWPOWER (1 << 2)
-#define SL1RXEN (1 << 3)
-#define SL1TXEN (1 << 4)
-#define SL2RXEN (1 << 5)
-#define SL2TXEN (1 << 6)
-#define SL12RXEN (1 << 7)
-#define SL12TXEN (1 << 8)
-#define DMAENABLE (1 << 9)
-
-/* INTCLR */
-#define WISC (1 << 0)
-#define RXOEC1 (1 << 1)
-#define RXOEC2 (1 << 2)
-#define RXOEC3 (1 << 3)
-#define RXOEC4 (1 << 4)
-#define TXUEC1 (1 << 5)
-#define TXUEC2 (1 << 6)
-#define TXUEC3 (1 << 7)
-#define TXUEC4 (1 << 8)
-#define RXTOFEC1 (1 << 9)
-#define RXTOFEC2 (1 << 10)
-#define RXTOFEC3 (1 << 11)
-#define RXTOFEC4 (1 << 12)
-
-#endif /* #ifndef HW_PL041_H */
diff --git a/qemu/hw/audio/pl041.hx b/qemu/hw/audio/pl041.hx
deleted file mode 100644
index dd7188cbc..000000000
--- a/qemu/hw/audio/pl041.hx
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Arm PrimeCell PL041 Advanced Audio Codec Interface
- *
- * Copyright (c) 2011
- * Written by Mathieu Sonet - www.elasticsheep.com
- *
- * This code is licensed under the GPL.
- *
- * *****************************************************************
- */
-
-/* PL041 register file description */
-
-REGISTER( rxcr1, 0x00 )
-REGISTER( txcr1, 0x04 )
-REGISTER( sr1, 0x08 )
-REGISTER( isr1, 0x0C )
-REGISTER( ie1, 0x10 )
-REGISTER( rxcr2, 0x14 )
-REGISTER( txcr2, 0x18 )
-REGISTER( sr2, 0x1C )
-REGISTER( isr2, 0x20 )
-REGISTER( ie2, 0x24 )
-REGISTER( rxcr3, 0x28 )
-REGISTER( txcr3, 0x2C )
-REGISTER( sr3, 0x30 )
-REGISTER( isr3, 0x34 )
-REGISTER( ie3, 0x38 )
-REGISTER( rxcr4, 0x3C )
-REGISTER( txcr4, 0x40 )
-REGISTER( sr4, 0x44 )
-REGISTER( isr4, 0x48 )
-REGISTER( ie4, 0x4C )
-REGISTER( sl1rx, 0x50 )
-REGISTER( sl1tx, 0x54 )
-REGISTER( sl2rx, 0x58 )
-REGISTER( sl2tx, 0x5C )
-REGISTER( sl12rx, 0x60 )
-REGISTER( sl12tx, 0x64 )
-REGISTER( slfr, 0x68 )
-REGISTER( slistat, 0x6C )
-REGISTER( slien, 0x70 )
-REGISTER( intclr, 0x74 )
-REGISTER( maincr, 0x78 )
-REGISTER( reset, 0x7C )
-REGISTER( sync, 0x80 )
-REGISTER( allints, 0x84 )
-REGISTER( mainfr, 0x88 )
-REGISTER( unused, 0x8C )
-REGISTER( dr1_0, 0x90 )
-REGISTER( dr1_1, 0x94 )
-REGISTER( dr1_2, 0x98 )
-REGISTER( dr1_3, 0x9C )
-REGISTER( dr1_4, 0xA0 )
-REGISTER( dr1_5, 0xA4 )
-REGISTER( dr1_6, 0xA8 )
-REGISTER( dr1_7, 0xAC )
-REGISTER( dr2_0, 0xB0 )
-REGISTER( dr2_1, 0xB4 )
-REGISTER( dr2_2, 0xB8 )
-REGISTER( dr2_3, 0xBC )
-REGISTER( dr2_4, 0xC0 )
-REGISTER( dr2_5, 0xC4 )
-REGISTER( dr2_6, 0xC8 )
-REGISTER( dr2_7, 0xCC )
-REGISTER( dr3_0, 0xD0 )
-REGISTER( dr3_1, 0xD4 )
-REGISTER( dr3_2, 0xD8 )
-REGISTER( dr3_3, 0xDC )
-REGISTER( dr3_4, 0xE0 )
-REGISTER( dr3_5, 0xE4 )
-REGISTER( dr3_6, 0xE8 )
-REGISTER( dr3_7, 0xEC )
-REGISTER( dr4_0, 0xF0 )
-REGISTER( dr4_1, 0xF4 )
-REGISTER( dr4_2, 0xF8 )
-REGISTER( dr4_3, 0xFC )
-REGISTER( dr4_4, 0x100 )
-REGISTER( dr4_5, 0x104 )
-REGISTER( dr4_6, 0x108 )
-REGISTER( dr4_7, 0x10C )
diff --git a/qemu/hw/audio/sb16.c b/qemu/hw/audio/sb16.c
deleted file mode 100644
index 3a4a57ac3..000000000
--- a/qemu/hw/audio/sb16.c
+++ /dev/null
@@ -1,1436 +0,0 @@
-/*
- * QEMU Soundblaster 16 emulation
- *
- * Copyright (c) 2003-2005 Vassili Karpov (malc)
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/audio/audio.h"
-#include "audio/audio.h"
-#include "hw/isa/isa.h"
-#include "hw/qdev.h"
-#include "qemu/timer.h"
-#include "qemu/host-utils.h"
-
-#define dolog(...) AUD_log ("sb16", __VA_ARGS__)
-
-/* #define DEBUG */
-/* #define DEBUG_SB16_MOST */
-
-#ifdef DEBUG
-#define ldebug(...) dolog (__VA_ARGS__)
-#else
-#define ldebug(...)
-#endif
-
-static const char e3[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992.";
-
-#define TYPE_SB16 "sb16"
-#define SB16(obj) OBJECT_CHECK (SB16State, (obj), TYPE_SB16)
-
-typedef struct SB16State {
- ISADevice parent_obj;
-
- QEMUSoundCard card;
- qemu_irq pic;
- uint32_t irq;
- uint32_t dma;
- uint32_t hdma;
- uint32_t port;
- uint32_t ver;
- IsaDma *isa_dma;
- IsaDma *isa_hdma;
-
- int in_index;
- int out_data_len;
- int fmt_stereo;
- int fmt_signed;
- int fmt_bits;
- audfmt_e fmt;
- int dma_auto;
- int block_size;
- int fifo;
- int freq;
- int time_const;
- int speaker;
- int needed_bytes;
- int cmd;
- int use_hdma;
- int highspeed;
- int can_write;
-
- int v2x6;
-
- uint8_t csp_param;
- uint8_t csp_value;
- uint8_t csp_mode;
- uint8_t csp_regs[256];
- uint8_t csp_index;
- uint8_t csp_reg83[4];
- int csp_reg83r;
- int csp_reg83w;
-
- uint8_t in2_data[10];
- uint8_t out_data[50];
- uint8_t test_reg;
- uint8_t last_read_byte;
- int nzero;
-
- int left_till_irq;
-
- int dma_running;
- int bytes_per_second;
- int align;
- int audio_free;
- SWVoiceOut *voice;
-
- QEMUTimer *aux_ts;
- /* mixer state */
- int mixer_nreg;
- uint8_t mixer_regs[256];
-} SB16State;
-
-static void SB_audio_callback (void *opaque, int free);
-
-static int magic_of_irq (int irq)
-{
- switch (irq) {
- case 5:
- return 2;
- case 7:
- return 4;
- case 9:
- return 1;
- case 10:
- return 8;
- default:
- dolog ("bad irq %d\n", irq);
- return 2;
- }
-}
-
-static int irq_of_magic (int magic)
-{
- switch (magic) {
- case 1:
- return 9;
- case 2:
- return 5;
- case 4:
- return 7;
- case 8:
- return 10;
- default:
- dolog ("bad irq magic %d\n", magic);
- return -1;
- }
-}
-
-#if 0
-static void log_dsp (SB16State *dsp)
-{
- ldebug ("%s:%s:%d:%s:dmasize=%d:freq=%d:const=%d:speaker=%d\n",
- dsp->fmt_stereo ? "Stereo" : "Mono",
- dsp->fmt_signed ? "Signed" : "Unsigned",
- dsp->fmt_bits,
- dsp->dma_auto ? "Auto" : "Single",
- dsp->block_size,
- dsp->freq,
- dsp->time_const,
- dsp->speaker);
-}
-#endif
-
-static void speaker (SB16State *s, int on)
-{
- s->speaker = on;
- /* AUD_enable (s->voice, on); */
-}
-
-static void control (SB16State *s, int hold)
-{
- int dma = s->use_hdma ? s->hdma : s->dma;
- IsaDma *isa_dma = s->use_hdma ? s->isa_hdma : s->isa_dma;
- IsaDmaClass *k = ISADMA_GET_CLASS(isa_dma);
- s->dma_running = hold;
-
- ldebug ("hold %d high %d dma %d\n", hold, s->use_hdma, dma);
-
- if (hold) {
- k->hold_DREQ(isa_dma, dma);
- AUD_set_active_out (s->voice, 1);
- }
- else {
- k->release_DREQ(isa_dma, dma);
- AUD_set_active_out (s->voice, 0);
- }
-}
-
-static void aux_timer (void *opaque)
-{
- SB16State *s = opaque;
- s->can_write = 1;
- qemu_irq_raise (s->pic);
-}
-
-#define DMA8_AUTO 1
-#define DMA8_HIGH 2
-
-static void continue_dma8 (SB16State *s)
-{
- if (s->freq > 0) {
- struct audsettings as;
-
- s->audio_free = 0;
-
- as.freq = s->freq;
- as.nchannels = 1 << s->fmt_stereo;
- as.fmt = s->fmt;
- as.endianness = 0;
-
- s->voice = AUD_open_out (
- &s->card,
- s->voice,
- "sb16",
- s,
- SB_audio_callback,
- &as
- );
- }
-
- control (s, 1);
-}
-
-static void dma_cmd8 (SB16State *s, int mask, int dma_len)
-{
- s->fmt = AUD_FMT_U8;
- s->use_hdma = 0;
- s->fmt_bits = 8;
- s->fmt_signed = 0;
- s->fmt_stereo = (s->mixer_regs[0x0e] & 2) != 0;
- if (-1 == s->time_const) {
- if (s->freq <= 0)
- s->freq = 11025;
- }
- else {
- int tmp = (256 - s->time_const);
- s->freq = (1000000 + (tmp / 2)) / tmp;
- }
-
- if (dma_len != -1) {
- s->block_size = dma_len << s->fmt_stereo;
- }
- else {
- /* This is apparently the only way to make both Act1/PL
- and SecondReality/FC work
-
- Act1 sets block size via command 0x48 and it's an odd number
- SR does the same with even number
- Both use stereo, and Creatives own documentation states that
- 0x48 sets block size in bytes less one.. go figure */
- s->block_size &= ~s->fmt_stereo;
- }
-
- s->freq >>= s->fmt_stereo;
- s->left_till_irq = s->block_size;
- s->bytes_per_second = (s->freq << s->fmt_stereo);
- /* s->highspeed = (mask & DMA8_HIGH) != 0; */
- s->dma_auto = (mask & DMA8_AUTO) != 0;
- s->align = (1 << s->fmt_stereo) - 1;
-
- if (s->block_size & s->align) {
- dolog ("warning: misaligned block size %d, alignment %d\n",
- s->block_size, s->align + 1);
- }
-
- ldebug ("freq %d, stereo %d, sign %d, bits %d, "
- "dma %d, auto %d, fifo %d, high %d\n",
- s->freq, s->fmt_stereo, s->fmt_signed, s->fmt_bits,
- s->block_size, s->dma_auto, s->fifo, s->highspeed);
-
- continue_dma8 (s);
- speaker (s, 1);
-}
-
-static void dma_cmd (SB16State *s, uint8_t cmd, uint8_t d0, int dma_len)
-{
- s->use_hdma = cmd < 0xc0;
- s->fifo = (cmd >> 1) & 1;
- s->dma_auto = (cmd >> 2) & 1;
- s->fmt_signed = (d0 >> 4) & 1;
- s->fmt_stereo = (d0 >> 5) & 1;
-
- switch (cmd >> 4) {
- case 11:
- s->fmt_bits = 16;
- break;
-
- case 12:
- s->fmt_bits = 8;
- break;
- }
-
- if (-1 != s->time_const) {
-#if 1
- int tmp = 256 - s->time_const;
- s->freq = (1000000 + (tmp / 2)) / tmp;
-#else
- /* s->freq = 1000000 / ((255 - s->time_const) << s->fmt_stereo); */
- s->freq = 1000000 / ((255 - s->time_const));
-#endif
- s->time_const = -1;
- }
-
- s->block_size = dma_len + 1;
- s->block_size <<= (s->fmt_bits == 16);
- if (!s->dma_auto) {
- /* It is clear that for DOOM and auto-init this value
- shouldn't take stereo into account, while Miles Sound Systems
- setsound.exe with single transfer mode wouldn't work without it
- wonders of SB16 yet again */
- s->block_size <<= s->fmt_stereo;
- }
-
- ldebug ("freq %d, stereo %d, sign %d, bits %d, "
- "dma %d, auto %d, fifo %d, high %d\n",
- s->freq, s->fmt_stereo, s->fmt_signed, s->fmt_bits,
- s->block_size, s->dma_auto, s->fifo, s->highspeed);
-
- if (16 == s->fmt_bits) {
- if (s->fmt_signed) {
- s->fmt = AUD_FMT_S16;
- }
- else {
- s->fmt = AUD_FMT_U16;
- }
- }
- else {
- if (s->fmt_signed) {
- s->fmt = AUD_FMT_S8;
- }
- else {
- s->fmt = AUD_FMT_U8;
- }
- }
-
- s->left_till_irq = s->block_size;
-
- s->bytes_per_second = (s->freq << s->fmt_stereo) << (s->fmt_bits == 16);
- s->highspeed = 0;
- s->align = (1 << (s->fmt_stereo + (s->fmt_bits == 16))) - 1;
- if (s->block_size & s->align) {
- dolog ("warning: misaligned block size %d, alignment %d\n",
- s->block_size, s->align + 1);
- }
-
- if (s->freq) {
- struct audsettings as;
-
- s->audio_free = 0;
-
- as.freq = s->freq;
- as.nchannels = 1 << s->fmt_stereo;
- as.fmt = s->fmt;
- as.endianness = 0;
-
- s->voice = AUD_open_out (
- &s->card,
- s->voice,
- "sb16",
- s,
- SB_audio_callback,
- &as
- );
- }
-
- control (s, 1);
- speaker (s, 1);
-}
-
-static inline void dsp_out_data (SB16State *s, uint8_t val)
-{
- ldebug ("outdata %#x\n", val);
- if ((size_t) s->out_data_len < sizeof (s->out_data)) {
- s->out_data[s->out_data_len++] = val;
- }
-}
-
-static inline uint8_t dsp_get_data (SB16State *s)
-{
- if (s->in_index) {
- return s->in2_data[--s->in_index];
- }
- else {
- dolog ("buffer underflow\n");
- return 0;
- }
-}
-
-static void command (SB16State *s, uint8_t cmd)
-{
- ldebug ("command %#x\n", cmd);
-
- if (cmd > 0xaf && cmd < 0xd0) {
- if (cmd & 8) {
- dolog ("ADC not yet supported (command %#x)\n", cmd);
- }
-
- switch (cmd >> 4) {
- case 11:
- case 12:
- break;
- default:
- dolog ("%#x wrong bits\n", cmd);
- }
- s->needed_bytes = 3;
- }
- else {
- s->needed_bytes = 0;
-
- switch (cmd) {
- case 0x03:
- dsp_out_data (s, 0x10); /* s->csp_param); */
- goto warn;
-
- case 0x04:
- s->needed_bytes = 1;
- goto warn;
-
- case 0x05:
- s->needed_bytes = 2;
- goto warn;
-
- case 0x08:
- /* __asm__ ("int3"); */
- goto warn;
-
- case 0x0e:
- s->needed_bytes = 2;
- goto warn;
-
- case 0x09:
- dsp_out_data (s, 0xf8);
- goto warn;
-
- case 0x0f:
- s->needed_bytes = 1;
- goto warn;
-
- case 0x10:
- s->needed_bytes = 1;
- goto warn;
-
- case 0x14:
- s->needed_bytes = 2;
- s->block_size = 0;
- break;
-
- case 0x1c: /* Auto-Initialize DMA DAC, 8-bit */
- dma_cmd8 (s, DMA8_AUTO, -1);
- break;
-
- case 0x20: /* Direct ADC, Juice/PL */
- dsp_out_data (s, 0xff);
- goto warn;
-
- case 0x35:
- dolog ("0x35 - MIDI command not implemented\n");
- break;
-
- case 0x40:
- s->freq = -1;
- s->time_const = -1;
- s->needed_bytes = 1;
- break;
-
- case 0x41:
- s->freq = -1;
- s->time_const = -1;
- s->needed_bytes = 2;
- break;
-
- case 0x42:
- s->freq = -1;
- s->time_const = -1;
- s->needed_bytes = 2;
- goto warn;
-
- case 0x45:
- dsp_out_data (s, 0xaa);
- goto warn;
-
- case 0x47: /* Continue Auto-Initialize DMA 16bit */
- break;
-
- case 0x48:
- s->needed_bytes = 2;
- break;
-
- case 0x74:
- s->needed_bytes = 2; /* DMA DAC, 4-bit ADPCM */
- dolog ("0x75 - DMA DAC, 4-bit ADPCM not implemented\n");
- break;
-
- case 0x75: /* DMA DAC, 4-bit ADPCM Reference */
- s->needed_bytes = 2;
- dolog ("0x74 - DMA DAC, 4-bit ADPCM Reference not implemented\n");
- break;
-
- case 0x76: /* DMA DAC, 2.6-bit ADPCM */
- s->needed_bytes = 2;
- dolog ("0x74 - DMA DAC, 2.6-bit ADPCM not implemented\n");
- break;
-
- case 0x77: /* DMA DAC, 2.6-bit ADPCM Reference */
- s->needed_bytes = 2;
- dolog ("0x74 - DMA DAC, 2.6-bit ADPCM Reference not implemented\n");
- break;
-
- case 0x7d:
- dolog ("0x7d - Autio-Initialize DMA DAC, 4-bit ADPCM Reference\n");
- dolog ("not implemented\n");
- break;
-
- case 0x7f:
- dolog (
- "0x7d - Autio-Initialize DMA DAC, 2.6-bit ADPCM Reference\n"
- );
- dolog ("not implemented\n");
- break;
-
- case 0x80:
- s->needed_bytes = 2;
- break;
-
- case 0x90:
- case 0x91:
- dma_cmd8 (s, ((cmd & 1) == 0) | DMA8_HIGH, -1);
- break;
-
- case 0xd0: /* halt DMA operation. 8bit */
- control (s, 0);
- break;
-
- case 0xd1: /* speaker on */
- speaker (s, 1);
- break;
-
- case 0xd3: /* speaker off */
- speaker (s, 0);
- break;
-
- case 0xd4: /* continue DMA operation. 8bit */
- /* KQ6 (or maybe Sierras audblst.drv in general) resets
- the frequency between halt/continue */
- continue_dma8 (s);
- break;
-
- case 0xd5: /* halt DMA operation. 16bit */
- control (s, 0);
- break;
-
- case 0xd6: /* continue DMA operation. 16bit */
- control (s, 1);
- break;
-
- case 0xd9: /* exit auto-init DMA after this block. 16bit */
- s->dma_auto = 0;
- break;
-
- case 0xda: /* exit auto-init DMA after this block. 8bit */
- s->dma_auto = 0;
- break;
-
- case 0xe0: /* DSP identification */
- s->needed_bytes = 1;
- break;
-
- case 0xe1:
- dsp_out_data (s, s->ver & 0xff);
- dsp_out_data (s, s->ver >> 8);
- break;
-
- case 0xe2:
- s->needed_bytes = 1;
- goto warn;
-
- case 0xe3:
- {
- int i;
- for (i = sizeof (e3) - 1; i >= 0; --i)
- dsp_out_data (s, e3[i]);
- }
- break;
-
- case 0xe4: /* write test reg */
- s->needed_bytes = 1;
- break;
-
- case 0xe7:
- dolog ("Attempt to probe for ESS (0xe7)?\n");
- break;
-
- case 0xe8: /* read test reg */
- dsp_out_data (s, s->test_reg);
- break;
-
- case 0xf2:
- case 0xf3:
- dsp_out_data (s, 0xaa);
- s->mixer_regs[0x82] |= (cmd == 0xf2) ? 1 : 2;
- qemu_irq_raise (s->pic);
- break;
-
- case 0xf9:
- s->needed_bytes = 1;
- goto warn;
-
- case 0xfa:
- dsp_out_data (s, 0);
- goto warn;
-
- case 0xfc: /* FIXME */
- dsp_out_data (s, 0);
- goto warn;
-
- default:
- dolog ("Unrecognized command %#x\n", cmd);
- break;
- }
- }
-
- if (!s->needed_bytes) {
- ldebug ("\n");
- }
-
- exit:
- if (!s->needed_bytes) {
- s->cmd = -1;
- }
- else {
- s->cmd = cmd;
- }
- return;
-
- warn:
- dolog ("warning: command %#x,%d is not truly understood yet\n",
- cmd, s->needed_bytes);
- goto exit;
-
-}
-
-static uint16_t dsp_get_lohi (SB16State *s)
-{
- uint8_t hi = dsp_get_data (s);
- uint8_t lo = dsp_get_data (s);
- return (hi << 8) | lo;
-}
-
-static uint16_t dsp_get_hilo (SB16State *s)
-{
- uint8_t lo = dsp_get_data (s);
- uint8_t hi = dsp_get_data (s);
- return (hi << 8) | lo;
-}
-
-static void complete (SB16State *s)
-{
- int d0, d1, d2;
- ldebug ("complete command %#x, in_index %d, needed_bytes %d\n",
- s->cmd, s->in_index, s->needed_bytes);
-
- if (s->cmd > 0xaf && s->cmd < 0xd0) {
- d2 = dsp_get_data (s);
- d1 = dsp_get_data (s);
- d0 = dsp_get_data (s);
-
- if (s->cmd & 8) {
- dolog ("ADC params cmd = %#x d0 = %d, d1 = %d, d2 = %d\n",
- s->cmd, d0, d1, d2);
- }
- else {
- ldebug ("cmd = %#x d0 = %d, d1 = %d, d2 = %d\n",
- s->cmd, d0, d1, d2);
- dma_cmd (s, s->cmd, d0, d1 + (d2 << 8));
- }
- }
- else {
- switch (s->cmd) {
- case 0x04:
- s->csp_mode = dsp_get_data (s);
- s->csp_reg83r = 0;
- s->csp_reg83w = 0;
- ldebug ("CSP command 0x04: mode=%#x\n", s->csp_mode);
- break;
-
- case 0x05:
- s->csp_param = dsp_get_data (s);
- s->csp_value = dsp_get_data (s);
- ldebug ("CSP command 0x05: param=%#x value=%#x\n",
- s->csp_param,
- s->csp_value);
- break;
-
- case 0x0e:
- d0 = dsp_get_data (s);
- d1 = dsp_get_data (s);
- ldebug ("write CSP register %d <- %#x\n", d1, d0);
- if (d1 == 0x83) {
- ldebug ("0x83[%d] <- %#x\n", s->csp_reg83r, d0);
- s->csp_reg83[s->csp_reg83r % 4] = d0;
- s->csp_reg83r += 1;
- }
- else {
- s->csp_regs[d1] = d0;
- }
- break;
-
- case 0x0f:
- d0 = dsp_get_data (s);
- ldebug ("read CSP register %#x -> %#x, mode=%#x\n",
- d0, s->csp_regs[d0], s->csp_mode);
- if (d0 == 0x83) {
- ldebug ("0x83[%d] -> %#x\n",
- s->csp_reg83w,
- s->csp_reg83[s->csp_reg83w % 4]);
- dsp_out_data (s, s->csp_reg83[s->csp_reg83w % 4]);
- s->csp_reg83w += 1;
- }
- else {
- dsp_out_data (s, s->csp_regs[d0]);
- }
- break;
-
- case 0x10:
- d0 = dsp_get_data (s);
- dolog ("cmd 0x10 d0=%#x\n", d0);
- break;
-
- case 0x14:
- dma_cmd8 (s, 0, dsp_get_lohi (s) + 1);
- break;
-
- case 0x40:
- s->time_const = dsp_get_data (s);
- ldebug ("set time const %d\n", s->time_const);
- break;
-
- case 0x42: /* FT2 sets output freq with this, go figure */
-#if 0
- dolog ("cmd 0x42 might not do what it think it should\n");
-#endif
- case 0x41:
- s->freq = dsp_get_hilo (s);
- ldebug ("set freq %d\n", s->freq);
- break;
-
- case 0x48:
- s->block_size = dsp_get_lohi (s) + 1;
- ldebug ("set dma block len %d\n", s->block_size);
- break;
-
- case 0x74:
- case 0x75:
- case 0x76:
- case 0x77:
- /* ADPCM stuff, ignore */
- break;
-
- case 0x80:
- {
- int freq, samples, bytes;
- int64_t ticks;
-
- freq = s->freq > 0 ? s->freq : 11025;
- samples = dsp_get_lohi (s) + 1;
- bytes = samples << s->fmt_stereo << (s->fmt_bits == 16);
- ticks = muldiv64(bytes, NANOSECONDS_PER_SECOND, freq);
- if (ticks < NANOSECONDS_PER_SECOND / 1024) {
- qemu_irq_raise (s->pic);
- }
- else {
- if (s->aux_ts) {
- timer_mod (
- s->aux_ts,
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ticks
- );
- }
- }
- ldebug ("mix silence %d %d %" PRId64 "\n", samples, bytes, ticks);
- }
- break;
-
- case 0xe0:
- d0 = dsp_get_data (s);
- s->out_data_len = 0;
- ldebug ("E0 data = %#x\n", d0);
- dsp_out_data (s, ~d0);
- break;
-
- case 0xe2:
-#ifdef DEBUG
- d0 = dsp_get_data (s);
- dolog ("E2 = %#x\n", d0);
-#endif
- break;
-
- case 0xe4:
- s->test_reg = dsp_get_data (s);
- break;
-
- case 0xf9:
- d0 = dsp_get_data (s);
- ldebug ("command 0xf9 with %#x\n", d0);
- switch (d0) {
- case 0x0e:
- dsp_out_data (s, 0xff);
- break;
-
- case 0x0f:
- dsp_out_data (s, 0x07);
- break;
-
- case 0x37:
- dsp_out_data (s, 0x38);
- break;
-
- default:
- dsp_out_data (s, 0x00);
- break;
- }
- break;
-
- default:
- dolog ("complete: unrecognized command %#x\n", s->cmd);
- return;
- }
- }
-
- ldebug ("\n");
- s->cmd = -1;
-}
-
-static void legacy_reset (SB16State *s)
-{
- struct audsettings as;
-
- s->freq = 11025;
- s->fmt_signed = 0;
- s->fmt_bits = 8;
- s->fmt_stereo = 0;
-
- as.freq = s->freq;
- as.nchannels = 1;
- as.fmt = AUD_FMT_U8;
- as.endianness = 0;
-
- s->voice = AUD_open_out (
- &s->card,
- s->voice,
- "sb16",
- s,
- SB_audio_callback,
- &as
- );
-
- /* Not sure about that... */
- /* AUD_set_active_out (s->voice, 1); */
-}
-
-static void reset (SB16State *s)
-{
- qemu_irq_lower (s->pic);
- if (s->dma_auto) {
- qemu_irq_raise (s->pic);
- qemu_irq_lower (s->pic);
- }
-
- s->mixer_regs[0x82] = 0;
- s->dma_auto = 0;
- s->in_index = 0;
- s->out_data_len = 0;
- s->left_till_irq = 0;
- s->needed_bytes = 0;
- s->block_size = -1;
- s->nzero = 0;
- s->highspeed = 0;
- s->v2x6 = 0;
- s->cmd = -1;
-
- dsp_out_data (s, 0xaa);
- speaker (s, 0);
- control (s, 0);
- legacy_reset (s);
-}
-
-static void dsp_write(void *opaque, uint32_t nport, uint32_t val)
-{
- SB16State *s = opaque;
- int iport;
-
- iport = nport - s->port;
-
- ldebug ("write %#x <- %#x\n", nport, val);
- switch (iport) {
- case 0x06:
- switch (val) {
- case 0x00:
- if (s->v2x6 == 1) {
- reset (s);
- }
- s->v2x6 = 0;
- break;
-
- case 0x01:
- case 0x03: /* FreeBSD kludge */
- s->v2x6 = 1;
- break;
-
- case 0xc6:
- s->v2x6 = 0; /* Prince of Persia, csp.sys, diagnose.exe */
- break;
-
- case 0xb8: /* Panic */
- reset (s);
- break;
-
- case 0x39:
- dsp_out_data (s, 0x38);
- reset (s);
- s->v2x6 = 0x39;
- break;
-
- default:
- s->v2x6 = val;
- break;
- }
- break;
-
- case 0x0c: /* write data or command | write status */
-/* if (s->highspeed) */
-/* break; */
-
- if (s->needed_bytes == 0) {
- command (s, val);
-#if 0
- if (0 == s->needed_bytes) {
- log_dsp (s);
- }
-#endif
- }
- else {
- if (s->in_index == sizeof (s->in2_data)) {
- dolog ("in data overrun\n");
- }
- else {
- s->in2_data[s->in_index++] = val;
- if (s->in_index == s->needed_bytes) {
- s->needed_bytes = 0;
- complete (s);
-#if 0
- log_dsp (s);
-#endif
- }
- }
- }
- break;
-
- default:
- ldebug ("(nport=%#x, val=%#x)\n", nport, val);
- break;
- }
-}
-
-static uint32_t dsp_read(void *opaque, uint32_t nport)
-{
- SB16State *s = opaque;
- int iport, retval, ack = 0;
-
- iport = nport - s->port;
-
- switch (iport) {
- case 0x06: /* reset */
- retval = 0xff;
- break;
-
- case 0x0a: /* read data */
- if (s->out_data_len) {
- retval = s->out_data[--s->out_data_len];
- s->last_read_byte = retval;
- }
- else {
- if (s->cmd != -1) {
- dolog ("empty output buffer for command %#x\n",
- s->cmd);
- }
- retval = s->last_read_byte;
- /* goto error; */
- }
- break;
-
- case 0x0c: /* 0 can write */
- retval = s->can_write ? 0 : 0x80;
- break;
-
- case 0x0d: /* timer interrupt clear */
- /* dolog ("timer interrupt clear\n"); */
- retval = 0;
- break;
-
- case 0x0e: /* data available status | irq 8 ack */
- retval = (!s->out_data_len || s->highspeed) ? 0 : 0x80;
- if (s->mixer_regs[0x82] & 1) {
- ack = 1;
- s->mixer_regs[0x82] &= ~1;
- qemu_irq_lower (s->pic);
- }
- break;
-
- case 0x0f: /* irq 16 ack */
- retval = 0xff;
- if (s->mixer_regs[0x82] & 2) {
- ack = 1;
- s->mixer_regs[0x82] &= ~2;
- qemu_irq_lower (s->pic);
- }
- break;
-
- default:
- goto error;
- }
-
- if (!ack) {
- ldebug ("read %#x -> %#x\n", nport, retval);
- }
-
- return retval;
-
- error:
- dolog ("warning: dsp_read %#x error\n", nport);
- return 0xff;
-}
-
-static void reset_mixer (SB16State *s)
-{
- int i;
-
- memset (s->mixer_regs, 0xff, 0x7f);
- memset (s->mixer_regs + 0x83, 0xff, sizeof (s->mixer_regs) - 0x83);
-
- s->mixer_regs[0x02] = 4; /* master volume 3bits */
- s->mixer_regs[0x06] = 4; /* MIDI volume 3bits */
- s->mixer_regs[0x08] = 0; /* CD volume 3bits */
- s->mixer_regs[0x0a] = 0; /* voice volume 2bits */
-
- /* d5=input filt, d3=lowpass filt, d1,d2=input source */
- s->mixer_regs[0x0c] = 0;
-
- /* d5=output filt, d1=stereo switch */
- s->mixer_regs[0x0e] = 0;
-
- /* voice volume L d5,d7, R d1,d3 */
- s->mixer_regs[0x04] = (4 << 5) | (4 << 1);
- /* master ... */
- s->mixer_regs[0x22] = (4 << 5) | (4 << 1);
- /* MIDI ... */
- s->mixer_regs[0x26] = (4 << 5) | (4 << 1);
-
- for (i = 0x30; i < 0x48; i++) {
- s->mixer_regs[i] = 0x20;
- }
-}
-
-static void mixer_write_indexb(void *opaque, uint32_t nport, uint32_t val)
-{
- SB16State *s = opaque;
- (void) nport;
- s->mixer_nreg = val;
-}
-
-static void mixer_write_datab(void *opaque, uint32_t nport, uint32_t val)
-{
- SB16State *s = opaque;
-
- (void) nport;
- ldebug ("mixer_write [%#x] <- %#x\n", s->mixer_nreg, val);
-
- switch (s->mixer_nreg) {
- case 0x00:
- reset_mixer (s);
- break;
-
- case 0x80:
- {
- int irq = irq_of_magic (val);
- ldebug ("setting irq to %d (val=%#x)\n", irq, val);
- if (irq > 0) {
- s->irq = irq;
- }
- }
- break;
-
- case 0x81:
- {
- int dma, hdma;
-
- dma = ctz32 (val & 0xf);
- hdma = ctz32 (val & 0xf0);
- if (dma != s->dma || hdma != s->hdma) {
- dolog (
- "attempt to change DMA "
- "8bit %d(%d), 16bit %d(%d) (val=%#x)\n",
- dma, s->dma, hdma, s->hdma, val);
- }
-#if 0
- s->dma = dma;
- s->hdma = hdma;
-#endif
- }
- break;
-
- case 0x82:
- dolog ("attempt to write into IRQ status register (val=%#x)\n",
- val);
- return;
-
- default:
- if (s->mixer_nreg >= 0x80) {
- ldebug ("attempt to write mixer[%#x] <- %#x\n", s->mixer_nreg, val);
- }
- break;
- }
-
- s->mixer_regs[s->mixer_nreg] = val;
-}
-
-static uint32_t mixer_read(void *opaque, uint32_t nport)
-{
- SB16State *s = opaque;
-
- (void) nport;
-#ifndef DEBUG_SB16_MOST
- if (s->mixer_nreg != 0x82) {
- ldebug ("mixer_read[%#x] -> %#x\n",
- s->mixer_nreg, s->mixer_regs[s->mixer_nreg]);
- }
-#else
- ldebug ("mixer_read[%#x] -> %#x\n",
- s->mixer_nreg, s->mixer_regs[s->mixer_nreg]);
-#endif
- return s->mixer_regs[s->mixer_nreg];
-}
-
-static int write_audio (SB16State *s, int nchan, int dma_pos,
- int dma_len, int len)
-{
- IsaDma *isa_dma = nchan == s->dma ? s->isa_dma : s->isa_hdma;
- IsaDmaClass *k = ISADMA_GET_CLASS(isa_dma);
- int temp, net;
- uint8_t tmpbuf[4096];
-
- temp = len;
- net = 0;
-
- while (temp) {
- int left = dma_len - dma_pos;
- int copied;
- size_t to_copy;
-
- to_copy = audio_MIN (temp, left);
- if (to_copy > sizeof (tmpbuf)) {
- to_copy = sizeof (tmpbuf);
- }
-
- copied = k->read_memory(isa_dma, nchan, tmpbuf, dma_pos, to_copy);
- copied = AUD_write (s->voice, tmpbuf, copied);
-
- temp -= copied;
- dma_pos = (dma_pos + copied) % dma_len;
- net += copied;
-
- if (!copied) {
- break;
- }
- }
-
- return net;
-}
-
-static int SB_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len)
-{
- SB16State *s = opaque;
- int till, copy, written, free;
-
- if (s->block_size <= 0) {
- dolog ("invalid block size=%d nchan=%d dma_pos=%d dma_len=%d\n",
- s->block_size, nchan, dma_pos, dma_len);
- return dma_pos;
- }
-
- if (s->left_till_irq < 0) {
- s->left_till_irq = s->block_size;
- }
-
- if (s->voice) {
- free = s->audio_free & ~s->align;
- if ((free <= 0) || !dma_len) {
- return dma_pos;
- }
- }
- else {
- free = dma_len;
- }
-
- copy = free;
- till = s->left_till_irq;
-
-#ifdef DEBUG_SB16_MOST
- dolog ("pos:%06d %d till:%d len:%d\n",
- dma_pos, free, till, dma_len);
-#endif
-
- if (till <= copy) {
- if (s->dma_auto == 0) {
- copy = till;
- }
- }
-
- written = write_audio (s, nchan, dma_pos, dma_len, copy);
- dma_pos = (dma_pos + written) % dma_len;
- s->left_till_irq -= written;
-
- if (s->left_till_irq <= 0) {
- s->mixer_regs[0x82] |= (nchan & 4) ? 2 : 1;
- qemu_irq_raise (s->pic);
- if (s->dma_auto == 0) {
- control (s, 0);
- speaker (s, 0);
- }
- }
-
-#ifdef DEBUG_SB16_MOST
- ldebug ("pos %5d free %5d size %5d till % 5d copy %5d written %5d size %5d\n",
- dma_pos, free, dma_len, s->left_till_irq, copy, written,
- s->block_size);
-#endif
-
- while (s->left_till_irq <= 0) {
- s->left_till_irq = s->block_size + s->left_till_irq;
- }
-
- return dma_pos;
-}
-
-static void SB_audio_callback (void *opaque, int free)
-{
- SB16State *s = opaque;
- s->audio_free = free;
-}
-
-static int sb16_post_load (void *opaque, int version_id)
-{
- SB16State *s = opaque;
-
- if (s->voice) {
- AUD_close_out (&s->card, s->voice);
- s->voice = NULL;
- }
-
- if (s->dma_running) {
- if (s->freq) {
- struct audsettings as;
-
- s->audio_free = 0;
-
- as.freq = s->freq;
- as.nchannels = 1 << s->fmt_stereo;
- as.fmt = s->fmt;
- as.endianness = 0;
-
- s->voice = AUD_open_out (
- &s->card,
- s->voice,
- "sb16",
- s,
- SB_audio_callback,
- &as
- );
- }
-
- control (s, 1);
- speaker (s, s->speaker);
- }
- return 0;
-}
-
-static const VMStateDescription vmstate_sb16 = {
- .name = "sb16",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = sb16_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32 (irq, SB16State),
- VMSTATE_UINT32 (dma, SB16State),
- VMSTATE_UINT32 (hdma, SB16State),
- VMSTATE_UINT32 (port, SB16State),
- VMSTATE_UINT32 (ver, SB16State),
- VMSTATE_INT32 (in_index, SB16State),
- VMSTATE_INT32 (out_data_len, SB16State),
- VMSTATE_INT32 (fmt_stereo, SB16State),
- VMSTATE_INT32 (fmt_signed, SB16State),
- VMSTATE_INT32 (fmt_bits, SB16State),
- VMSTATE_UINT32 (fmt, SB16State),
- VMSTATE_INT32 (dma_auto, SB16State),
- VMSTATE_INT32 (block_size, SB16State),
- VMSTATE_INT32 (fifo, SB16State),
- VMSTATE_INT32 (freq, SB16State),
- VMSTATE_INT32 (time_const, SB16State),
- VMSTATE_INT32 (speaker, SB16State),
- VMSTATE_INT32 (needed_bytes, SB16State),
- VMSTATE_INT32 (cmd, SB16State),
- VMSTATE_INT32 (use_hdma, SB16State),
- VMSTATE_INT32 (highspeed, SB16State),
- VMSTATE_INT32 (can_write, SB16State),
- VMSTATE_INT32 (v2x6, SB16State),
-
- VMSTATE_UINT8 (csp_param, SB16State),
- VMSTATE_UINT8 (csp_value, SB16State),
- VMSTATE_UINT8 (csp_mode, SB16State),
- VMSTATE_UINT8 (csp_param, SB16State),
- VMSTATE_BUFFER (csp_regs, SB16State),
- VMSTATE_UINT8 (csp_index, SB16State),
- VMSTATE_BUFFER (csp_reg83, SB16State),
- VMSTATE_INT32 (csp_reg83r, SB16State),
- VMSTATE_INT32 (csp_reg83w, SB16State),
-
- VMSTATE_BUFFER (in2_data, SB16State),
- VMSTATE_BUFFER (out_data, SB16State),
- VMSTATE_UINT8 (test_reg, SB16State),
- VMSTATE_UINT8 (last_read_byte, SB16State),
-
- VMSTATE_INT32 (nzero, SB16State),
- VMSTATE_INT32 (left_till_irq, SB16State),
- VMSTATE_INT32 (dma_running, SB16State),
- VMSTATE_INT32 (bytes_per_second, SB16State),
- VMSTATE_INT32 (align, SB16State),
-
- VMSTATE_INT32 (mixer_nreg, SB16State),
- VMSTATE_BUFFER (mixer_regs, SB16State),
-
- VMSTATE_END_OF_LIST ()
- }
-};
-
-static const MemoryRegionPortio sb16_ioport_list[] = {
- { 4, 1, 1, .write = mixer_write_indexb },
- { 5, 1, 1, .read = mixer_read, .write = mixer_write_datab },
- { 6, 1, 1, .read = dsp_read, .write = dsp_write },
- { 10, 1, 1, .read = dsp_read },
- { 12, 1, 1, .write = dsp_write },
- { 12, 4, 1, .read = dsp_read },
- PORTIO_END_OF_LIST (),
-};
-
-
-static void sb16_initfn (Object *obj)
-{
- SB16State *s = SB16 (obj);
-
- s->cmd = -1;
-}
-
-static void sb16_realizefn (DeviceState *dev, Error **errp)
-{
- ISADevice *isadev = ISA_DEVICE (dev);
- SB16State *s = SB16 (dev);
- IsaDmaClass *k;
-
- isa_init_irq (isadev, &s->pic, s->irq);
-
- s->mixer_regs[0x80] = magic_of_irq (s->irq);
- s->mixer_regs[0x81] = (1 << s->dma) | (1 << s->hdma);
- s->mixer_regs[0x82] = 2 << 5;
-
- s->csp_regs[5] = 1;
- s->csp_regs[9] = 0xf8;
-
- reset_mixer (s);
- s->aux_ts = timer_new_ns(QEMU_CLOCK_VIRTUAL, aux_timer, s);
- if (!s->aux_ts) {
- dolog ("warning: Could not create auxiliary timer\n");
- }
-
- isa_register_portio_list (isadev, s->port, sb16_ioport_list, s, "sb16");
-
- s->isa_hdma = isa_get_dma(isa_bus_from_device(isadev), s->hdma);
- k = ISADMA_GET_CLASS(s->isa_hdma);
- k->register_channel(s->isa_hdma, s->hdma, SB_read_DMA, s);
-
- s->isa_dma = isa_get_dma(isa_bus_from_device(isadev), s->dma);
- k = ISADMA_GET_CLASS(s->isa_dma);
- k->register_channel(s->isa_dma, s->dma, SB_read_DMA, s);
-
- s->can_write = 1;
-
- AUD_register_card ("sb16", &s->card);
-}
-
-static int SB16_init (ISABus *bus)
-{
- isa_create_simple (bus, TYPE_SB16);
- return 0;
-}
-
-static Property sb16_properties[] = {
- DEFINE_PROP_UINT32 ("version", SB16State, ver, 0x0405), /* 4.5 */
- DEFINE_PROP_UINT32 ("iobase", SB16State, port, 0x220),
- DEFINE_PROP_UINT32 ("irq", SB16State, irq, 5),
- DEFINE_PROP_UINT32 ("dma", SB16State, dma, 1),
- DEFINE_PROP_UINT32 ("dma16", SB16State, hdma, 5),
- DEFINE_PROP_END_OF_LIST (),
-};
-
-static void sb16_class_initfn (ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS (klass);
-
- dc->realize = sb16_realizefn;
- set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
- dc->desc = "Creative Sound Blaster 16";
- dc->vmsd = &vmstate_sb16;
- dc->props = sb16_properties;
-}
-
-static const TypeInfo sb16_info = {
- .name = TYPE_SB16,
- .parent = TYPE_ISA_DEVICE,
- .instance_size = sizeof (SB16State),
- .instance_init = sb16_initfn,
- .class_init = sb16_class_initfn,
-};
-
-static void sb16_register_types (void)
-{
- type_register_static (&sb16_info);
- isa_register_soundhw("sb16", "Creative Sound Blaster 16", SB16_init);
-}
-
-type_init (sb16_register_types)
diff --git a/qemu/hw/audio/wm8750.c b/qemu/hw/audio/wm8750.c
deleted file mode 100644
index 0c6500e96..000000000
--- a/qemu/hw/audio/wm8750.c
+++ /dev/null
@@ -1,723 +0,0 @@
-/*
- * WM8750 audio CODEC.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This file is licensed under GNU GPL.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/i2c/i2c.h"
-#include "audio/audio.h"
-
-#define IN_PORT_N 3
-#define OUT_PORT_N 3
-
-#define CODEC "wm8750"
-
-typedef struct {
- int adc;
- int adc_hz;
- int dac;
- int dac_hz;
-} WMRate;
-
-#define TYPE_WM8750 "wm8750"
-#define WM8750(obj) OBJECT_CHECK(WM8750State, (obj), TYPE_WM8750)
-
-typedef struct WM8750State {
- I2CSlave parent_obj;
-
- uint8_t i2c_data[2];
- int i2c_len;
- QEMUSoundCard card;
- SWVoiceIn *adc_voice[IN_PORT_N];
- SWVoiceOut *dac_voice[OUT_PORT_N];
- int enable;
- void (*data_req)(void *, int, int);
- void *opaque;
- uint8_t data_in[4096];
- uint8_t data_out[4096];
- int idx_in, req_in;
- int idx_out, req_out;
-
- SWVoiceOut **out[2];
- uint8_t outvol[7], outmute[2];
- SWVoiceIn **in[2];
- uint8_t invol[4], inmute[2];
-
- uint8_t diff[2], pol, ds, monomix[2], alc, mute;
- uint8_t path[4], mpath[2], power, format;
- const WMRate *rate;
- uint8_t rate_vmstate;
- int adc_hz, dac_hz, ext_adc_hz, ext_dac_hz, master;
-} WM8750State;
-
-/* pow(10.0, -i / 20.0) * 255, i = 0..42 */
-static const uint8_t wm8750_vol_db_table[] = {
- 255, 227, 203, 181, 161, 143, 128, 114, 102, 90, 81, 72, 64, 57, 51, 45,
- 40, 36, 32, 29, 26, 23, 20, 18, 16, 14, 13, 11, 10, 9, 8, 7, 6, 6, 5, 5,
- 4, 4, 3, 3, 3, 2, 2
-};
-
-#define WM8750_OUTVOL_TRANSFORM(x) wm8750_vol_db_table[(0x7f - x) / 3]
-#define WM8750_INVOL_TRANSFORM(x) (x << 2)
-
-static inline void wm8750_in_load(WM8750State *s)
-{
- if (s->idx_in + s->req_in <= sizeof(s->data_in))
- return;
- s->idx_in = audio_MAX(0, (int) sizeof(s->data_in) - s->req_in);
- AUD_read(*s->in[0], s->data_in + s->idx_in,
- sizeof(s->data_in) - s->idx_in);
-}
-
-static inline void wm8750_out_flush(WM8750State *s)
-{
- int sent = 0;
- while (sent < s->idx_out)
- sent += AUD_write(*s->out[0], s->data_out + sent, s->idx_out - sent)
- ?: s->idx_out;
- s->idx_out = 0;
-}
-
-static void wm8750_audio_in_cb(void *opaque, int avail_b)
-{
- WM8750State *s = (WM8750State *) opaque;
- s->req_in = avail_b;
- s->data_req(s->opaque, s->req_out >> 2, avail_b >> 2);
-}
-
-static void wm8750_audio_out_cb(void *opaque, int free_b)
-{
- WM8750State *s = (WM8750State *) opaque;
-
- if (s->idx_out >= free_b) {
- s->idx_out = free_b;
- s->req_out = 0;
- wm8750_out_flush(s);
- } else
- s->req_out = free_b - s->idx_out;
-
- s->data_req(s->opaque, s->req_out >> 2, s->req_in >> 2);
-}
-
-static const WMRate wm_rate_table[] = {
- { 256, 48000, 256, 48000 }, /* SR: 00000 */
- { 384, 48000, 384, 48000 }, /* SR: 00001 */
- { 256, 48000, 1536, 8000 }, /* SR: 00010 */
- { 384, 48000, 2304, 8000 }, /* SR: 00011 */
- { 1536, 8000, 256, 48000 }, /* SR: 00100 */
- { 2304, 8000, 384, 48000 }, /* SR: 00101 */
- { 1536, 8000, 1536, 8000 }, /* SR: 00110 */
- { 2304, 8000, 2304, 8000 }, /* SR: 00111 */
- { 1024, 12000, 1024, 12000 }, /* SR: 01000 */
- { 1526, 12000, 1536, 12000 }, /* SR: 01001 */
- { 768, 16000, 768, 16000 }, /* SR: 01010 */
- { 1152, 16000, 1152, 16000 }, /* SR: 01011 */
- { 384, 32000, 384, 32000 }, /* SR: 01100 */
- { 576, 32000, 576, 32000 }, /* SR: 01101 */
- { 128, 96000, 128, 96000 }, /* SR: 01110 */
- { 192, 96000, 192, 96000 }, /* SR: 01111 */
- { 256, 44100, 256, 44100 }, /* SR: 10000 */
- { 384, 44100, 384, 44100 }, /* SR: 10001 */
- { 256, 44100, 1408, 8018 }, /* SR: 10010 */
- { 384, 44100, 2112, 8018 }, /* SR: 10011 */
- { 1408, 8018, 256, 44100 }, /* SR: 10100 */
- { 2112, 8018, 384, 44100 }, /* SR: 10101 */
- { 1408, 8018, 1408, 8018 }, /* SR: 10110 */
- { 2112, 8018, 2112, 8018 }, /* SR: 10111 */
- { 1024, 11025, 1024, 11025 }, /* SR: 11000 */
- { 1536, 11025, 1536, 11025 }, /* SR: 11001 */
- { 512, 22050, 512, 22050 }, /* SR: 11010 */
- { 768, 22050, 768, 22050 }, /* SR: 11011 */
- { 512, 24000, 512, 24000 }, /* SR: 11100 */
- { 768, 24000, 768, 24000 }, /* SR: 11101 */
- { 128, 88200, 128, 88200 }, /* SR: 11110 */
- { 192, 88200, 192, 88200 }, /* SR: 11111 */
-};
-
-static void wm8750_vol_update(WM8750State *s)
-{
- /* FIXME: multiply all volumes by s->invol[2], s->invol[3] */
-
- AUD_set_volume_in(s->adc_voice[0], s->mute,
- s->inmute[0] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[0]),
- s->inmute[1] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[1]));
- AUD_set_volume_in(s->adc_voice[1], s->mute,
- s->inmute[0] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[0]),
- s->inmute[1] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[1]));
- AUD_set_volume_in(s->adc_voice[2], s->mute,
- s->inmute[0] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[0]),
- s->inmute[1] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[1]));
-
- /* FIXME: multiply all volumes by s->outvol[0], s->outvol[1] */
-
- /* Speaker: LOUT2VOL ROUT2VOL */
- AUD_set_volume_out(s->dac_voice[0], s->mute,
- s->outmute[0] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[4]),
- s->outmute[1] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[5]));
-
- /* Headphone: LOUT1VOL ROUT1VOL */
- AUD_set_volume_out(s->dac_voice[1], s->mute,
- s->outmute[0] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[2]),
- s->outmute[1] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[3]));
-
- /* MONOOUT: MONOVOL MONOVOL */
- AUD_set_volume_out(s->dac_voice[2], s->mute,
- s->outmute[0] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[6]),
- s->outmute[1] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[6]));
-}
-
-static void wm8750_set_format(WM8750State *s)
-{
- int i;
- struct audsettings in_fmt;
- struct audsettings out_fmt;
-
- wm8750_out_flush(s);
-
- if (s->in[0] && *s->in[0])
- AUD_set_active_in(*s->in[0], 0);
- if (s->out[0] && *s->out[0])
- AUD_set_active_out(*s->out[0], 0);
-
- for (i = 0; i < IN_PORT_N; i ++)
- if (s->adc_voice[i]) {
- AUD_close_in(&s->card, s->adc_voice[i]);
- s->adc_voice[i] = NULL;
- }
- for (i = 0; i < OUT_PORT_N; i ++)
- if (s->dac_voice[i]) {
- AUD_close_out(&s->card, s->dac_voice[i]);
- s->dac_voice[i] = NULL;
- }
-
- if (!s->enable)
- return;
-
- /* Setup input */
- in_fmt.endianness = 0;
- in_fmt.nchannels = 2;
- in_fmt.freq = s->adc_hz;
- in_fmt.fmt = AUD_FMT_S16;
-
- s->adc_voice[0] = AUD_open_in(&s->card, s->adc_voice[0],
- CODEC ".input1", s, wm8750_audio_in_cb, &in_fmt);
- s->adc_voice[1] = AUD_open_in(&s->card, s->adc_voice[1],
- CODEC ".input2", s, wm8750_audio_in_cb, &in_fmt);
- s->adc_voice[2] = AUD_open_in(&s->card, s->adc_voice[2],
- CODEC ".input3", s, wm8750_audio_in_cb, &in_fmt);
-
- /* Setup output */
- out_fmt.endianness = 0;
- out_fmt.nchannels = 2;
- out_fmt.freq = s->dac_hz;
- out_fmt.fmt = AUD_FMT_S16;
-
- s->dac_voice[0] = AUD_open_out(&s->card, s->dac_voice[0],
- CODEC ".speaker", s, wm8750_audio_out_cb, &out_fmt);
- s->dac_voice[1] = AUD_open_out(&s->card, s->dac_voice[1],
- CODEC ".headphone", s, wm8750_audio_out_cb, &out_fmt);
- /* MONOMIX is also in stereo for simplicity */
- s->dac_voice[2] = AUD_open_out(&s->card, s->dac_voice[2],
- CODEC ".monomix", s, wm8750_audio_out_cb, &out_fmt);
- /* no sense emulating OUT3 which is a mix of other outputs */
-
- wm8750_vol_update(s);
-
- /* We should connect the left and right channels to their
- * respective inputs/outputs but we have completely no need
- * for mixing or combining paths to different ports, so we
- * connect both channels to where the left channel is routed. */
- if (s->in[0] && *s->in[0])
- AUD_set_active_in(*s->in[0], 1);
- if (s->out[0] && *s->out[0])
- AUD_set_active_out(*s->out[0], 1);
-}
-
-static void wm8750_clk_update(WM8750State *s, int ext)
-{
- if (s->master || !s->ext_dac_hz)
- s->dac_hz = s->rate->dac_hz;
- else
- s->dac_hz = s->ext_dac_hz;
-
- if (s->master || !s->ext_adc_hz)
- s->adc_hz = s->rate->adc_hz;
- else
- s->adc_hz = s->ext_adc_hz;
-
- if (s->master || (!s->ext_dac_hz && !s->ext_adc_hz)) {
- if (!ext)
- wm8750_set_format(s);
- } else {
- if (ext)
- wm8750_set_format(s);
- }
-}
-
-static void wm8750_reset(I2CSlave *i2c)
-{
- WM8750State *s = WM8750(i2c);
-
- s->rate = &wm_rate_table[0];
- s->enable = 0;
- wm8750_clk_update(s, 1);
- s->diff[0] = 0;
- s->diff[1] = 0;
- s->ds = 0;
- s->alc = 0;
- s->in[0] = &s->adc_voice[0];
- s->invol[0] = 0x17;
- s->invol[1] = 0x17;
- s->invol[2] = 0xc3;
- s->invol[3] = 0xc3;
- s->out[0] = &s->dac_voice[0];
- s->outvol[0] = 0xff;
- s->outvol[1] = 0xff;
- s->outvol[2] = 0x79;
- s->outvol[3] = 0x79;
- s->outvol[4] = 0x79;
- s->outvol[5] = 0x79;
- s->outvol[6] = 0x79;
- s->inmute[0] = 0;
- s->inmute[1] = 0;
- s->outmute[0] = 0;
- s->outmute[1] = 0;
- s->mute = 1;
- s->path[0] = 0;
- s->path[1] = 0;
- s->path[2] = 0;
- s->path[3] = 0;
- s->mpath[0] = 0;
- s->mpath[1] = 0;
- s->format = 0x0a;
- s->idx_in = sizeof(s->data_in);
- s->req_in = 0;
- s->idx_out = 0;
- s->req_out = 0;
- wm8750_vol_update(s);
- s->i2c_len = 0;
-}
-
-static void wm8750_event(I2CSlave *i2c, enum i2c_event event)
-{
- WM8750State *s = WM8750(i2c);
-
- switch (event) {
- case I2C_START_SEND:
- s->i2c_len = 0;
- break;
- case I2C_FINISH:
-#ifdef VERBOSE
- if (s->i2c_len < 2)
- printf("%s: message too short (%i bytes)\n",
- __FUNCTION__, s->i2c_len);
-#endif
- break;
- default:
- break;
- }
-}
-
-#define WM8750_LINVOL 0x00
-#define WM8750_RINVOL 0x01
-#define WM8750_LOUT1V 0x02
-#define WM8750_ROUT1V 0x03
-#define WM8750_ADCDAC 0x05
-#define WM8750_IFACE 0x07
-#define WM8750_SRATE 0x08
-#define WM8750_LDAC 0x0a
-#define WM8750_RDAC 0x0b
-#define WM8750_BASS 0x0c
-#define WM8750_TREBLE 0x0d
-#define WM8750_RESET 0x0f
-#define WM8750_3D 0x10
-#define WM8750_ALC1 0x11
-#define WM8750_ALC2 0x12
-#define WM8750_ALC3 0x13
-#define WM8750_NGATE 0x14
-#define WM8750_LADC 0x15
-#define WM8750_RADC 0x16
-#define WM8750_ADCTL1 0x17
-#define WM8750_ADCTL2 0x18
-#define WM8750_PWR1 0x19
-#define WM8750_PWR2 0x1a
-#define WM8750_ADCTL3 0x1b
-#define WM8750_ADCIN 0x1f
-#define WM8750_LADCIN 0x20
-#define WM8750_RADCIN 0x21
-#define WM8750_LOUTM1 0x22
-#define WM8750_LOUTM2 0x23
-#define WM8750_ROUTM1 0x24
-#define WM8750_ROUTM2 0x25
-#define WM8750_MOUTM1 0x26
-#define WM8750_MOUTM2 0x27
-#define WM8750_LOUT2V 0x28
-#define WM8750_ROUT2V 0x29
-#define WM8750_MOUTV 0x2a
-
-static int wm8750_tx(I2CSlave *i2c, uint8_t data)
-{
- WM8750State *s = WM8750(i2c);
- uint8_t cmd;
- uint16_t value;
-
- if (s->i2c_len >= 2) {
-#ifdef VERBOSE
- printf("%s: long message (%i bytes)\n", __func__, s->i2c_len);
-#endif
- return 1;
- }
- s->i2c_data[s->i2c_len ++] = data;
- if (s->i2c_len != 2)
- return 0;
-
- cmd = s->i2c_data[0] >> 1;
- value = ((s->i2c_data[0] << 8) | s->i2c_data[1]) & 0x1ff;
-
- switch (cmd) {
- case WM8750_LADCIN: /* ADC Signal Path Control (Left) */
- s->diff[0] = (((value >> 6) & 3) == 3); /* LINSEL */
- if (s->diff[0])
- s->in[0] = &s->adc_voice[0 + s->ds * 1];
- else
- s->in[0] = &s->adc_voice[((value >> 6) & 3) * 1 + 0];
- break;
-
- case WM8750_RADCIN: /* ADC Signal Path Control (Right) */
- s->diff[1] = (((value >> 6) & 3) == 3); /* RINSEL */
- if (s->diff[1])
- s->in[1] = &s->adc_voice[0 + s->ds * 1];
- else
- s->in[1] = &s->adc_voice[((value >> 6) & 3) * 1 + 0];
- break;
-
- case WM8750_ADCIN: /* ADC Input Mode */
- s->ds = (value >> 8) & 1; /* DS */
- if (s->diff[0])
- s->in[0] = &s->adc_voice[0 + s->ds * 1];
- if (s->diff[1])
- s->in[1] = &s->adc_voice[0 + s->ds * 1];
- s->monomix[0] = (value >> 6) & 3; /* MONOMIX */
- break;
-
- case WM8750_ADCTL1: /* Additional Control (1) */
- s->monomix[1] = (value >> 1) & 1; /* DMONOMIX */
- break;
-
- case WM8750_PWR1: /* Power Management (1) */
- s->enable = ((value >> 6) & 7) == 3; /* VMIDSEL, VREF */
- wm8750_set_format(s);
- break;
-
- case WM8750_LINVOL: /* Left Channel PGA */
- s->invol[0] = value & 0x3f; /* LINVOL */
- s->inmute[0] = (value >> 7) & 1; /* LINMUTE */
- wm8750_vol_update(s);
- break;
-
- case WM8750_RINVOL: /* Right Channel PGA */
- s->invol[1] = value & 0x3f; /* RINVOL */
- s->inmute[1] = (value >> 7) & 1; /* RINMUTE */
- wm8750_vol_update(s);
- break;
-
- case WM8750_ADCDAC: /* ADC and DAC Control */
- s->pol = (value >> 5) & 3; /* ADCPOL */
- s->mute = (value >> 3) & 1; /* DACMU */
- wm8750_vol_update(s);
- break;
-
- case WM8750_ADCTL3: /* Additional Control (3) */
- break;
-
- case WM8750_LADC: /* Left ADC Digital Volume */
- s->invol[2] = value & 0xff; /* LADCVOL */
- wm8750_vol_update(s);
- break;
-
- case WM8750_RADC: /* Right ADC Digital Volume */
- s->invol[3] = value & 0xff; /* RADCVOL */
- wm8750_vol_update(s);
- break;
-
- case WM8750_ALC1: /* ALC Control (1) */
- s->alc = (value >> 7) & 3; /* ALCSEL */
- break;
-
- case WM8750_NGATE: /* Noise Gate Control */
- case WM8750_3D: /* 3D enhance */
- break;
-
- case WM8750_LDAC: /* Left Channel Digital Volume */
- s->outvol[0] = value & 0xff; /* LDACVOL */
- wm8750_vol_update(s);
- break;
-
- case WM8750_RDAC: /* Right Channel Digital Volume */
- s->outvol[1] = value & 0xff; /* RDACVOL */
- wm8750_vol_update(s);
- break;
-
- case WM8750_BASS: /* Bass Control */
- break;
-
- case WM8750_LOUTM1: /* Left Mixer Control (1) */
- s->path[0] = (value >> 8) & 1; /* LD2LO */
- /* TODO: mute/unmute respective paths */
- wm8750_vol_update(s);
- break;
-
- case WM8750_LOUTM2: /* Left Mixer Control (2) */
- s->path[1] = (value >> 8) & 1; /* RD2LO */
- /* TODO: mute/unmute respective paths */
- wm8750_vol_update(s);
- break;
-
- case WM8750_ROUTM1: /* Right Mixer Control (1) */
- s->path[2] = (value >> 8) & 1; /* LD2RO */
- /* TODO: mute/unmute respective paths */
- wm8750_vol_update(s);
- break;
-
- case WM8750_ROUTM2: /* Right Mixer Control (2) */
- s->path[3] = (value >> 8) & 1; /* RD2RO */
- /* TODO: mute/unmute respective paths */
- wm8750_vol_update(s);
- break;
-
- case WM8750_MOUTM1: /* Mono Mixer Control (1) */
- s->mpath[0] = (value >> 8) & 1; /* LD2MO */
- /* TODO: mute/unmute respective paths */
- wm8750_vol_update(s);
- break;
-
- case WM8750_MOUTM2: /* Mono Mixer Control (2) */
- s->mpath[1] = (value >> 8) & 1; /* RD2MO */
- /* TODO: mute/unmute respective paths */
- wm8750_vol_update(s);
- break;
-
- case WM8750_LOUT1V: /* LOUT1 Volume */
- s->outvol[2] = value & 0x7f; /* LOUT1VOL */
- wm8750_vol_update(s);
- break;
-
- case WM8750_LOUT2V: /* LOUT2 Volume */
- s->outvol[4] = value & 0x7f; /* LOUT2VOL */
- wm8750_vol_update(s);
- break;
-
- case WM8750_ROUT1V: /* ROUT1 Volume */
- s->outvol[3] = value & 0x7f; /* ROUT1VOL */
- wm8750_vol_update(s);
- break;
-
- case WM8750_ROUT2V: /* ROUT2 Volume */
- s->outvol[5] = value & 0x7f; /* ROUT2VOL */
- wm8750_vol_update(s);
- break;
-
- case WM8750_MOUTV: /* MONOOUT Volume */
- s->outvol[6] = value & 0x7f; /* MONOOUTVOL */
- wm8750_vol_update(s);
- break;
-
- case WM8750_ADCTL2: /* Additional Control (2) */
- break;
-
- case WM8750_PWR2: /* Power Management (2) */
- s->power = value & 0x7e;
- /* TODO: mute/unmute respective paths */
- wm8750_vol_update(s);
- break;
-
- case WM8750_IFACE: /* Digital Audio Interface Format */
- s->format = value;
- s->master = (value >> 6) & 1; /* MS */
- wm8750_clk_update(s, s->master);
- break;
-
- case WM8750_SRATE: /* Clocking and Sample Rate Control */
- s->rate = &wm_rate_table[(value >> 1) & 0x1f];
- wm8750_clk_update(s, 0);
- break;
-
- case WM8750_RESET: /* Reset */
- wm8750_reset(I2C_SLAVE(s));
- break;
-
-#ifdef VERBOSE
- default:
- printf("%s: unknown register %02x\n", __FUNCTION__, cmd);
-#endif
- }
-
- return 0;
-}
-
-static int wm8750_rx(I2CSlave *i2c)
-{
- return 0x00;
-}
-
-static void wm8750_pre_save(void *opaque)
-{
- WM8750State *s = opaque;
-
- s->rate_vmstate = s->rate - wm_rate_table;
-}
-
-static int wm8750_post_load(void *opaque, int version_id)
-{
- WM8750State *s = opaque;
-
- s->rate = &wm_rate_table[s->rate_vmstate & 0x1f];
- return 0;
-}
-
-static const VMStateDescription vmstate_wm8750 = {
- .name = CODEC,
- .version_id = 0,
- .minimum_version_id = 0,
- .pre_save = wm8750_pre_save,
- .post_load = wm8750_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8_ARRAY(i2c_data, WM8750State, 2),
- VMSTATE_INT32(i2c_len, WM8750State),
- VMSTATE_INT32(enable, WM8750State),
- VMSTATE_INT32(idx_in, WM8750State),
- VMSTATE_INT32(req_in, WM8750State),
- VMSTATE_INT32(idx_out, WM8750State),
- VMSTATE_INT32(req_out, WM8750State),
- VMSTATE_UINT8_ARRAY(outvol, WM8750State, 7),
- VMSTATE_UINT8_ARRAY(outmute, WM8750State, 2),
- VMSTATE_UINT8_ARRAY(invol, WM8750State, 4),
- VMSTATE_UINT8_ARRAY(inmute, WM8750State, 2),
- VMSTATE_UINT8_ARRAY(diff, WM8750State, 2),
- VMSTATE_UINT8(pol, WM8750State),
- VMSTATE_UINT8(ds, WM8750State),
- VMSTATE_UINT8_ARRAY(monomix, WM8750State, 2),
- VMSTATE_UINT8(alc, WM8750State),
- VMSTATE_UINT8(mute, WM8750State),
- VMSTATE_UINT8_ARRAY(path, WM8750State, 4),
- VMSTATE_UINT8_ARRAY(mpath, WM8750State, 2),
- VMSTATE_UINT8(format, WM8750State),
- VMSTATE_UINT8(power, WM8750State),
- VMSTATE_UINT8(rate_vmstate, WM8750State),
- VMSTATE_I2C_SLAVE(parent_obj, WM8750State),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static int wm8750_init(I2CSlave *i2c)
-{
- WM8750State *s = WM8750(i2c);
-
- AUD_register_card(CODEC, &s->card);
- wm8750_reset(I2C_SLAVE(s));
-
- return 0;
-}
-
-#if 0
-static void wm8750_fini(I2CSlave *i2c)
-{
- WM8750State *s = WM8750(i2c);
-
- wm8750_reset(I2C_SLAVE(s));
- AUD_remove_card(&s->card);
- g_free(s);
-}
-#endif
-
-void wm8750_data_req_set(DeviceState *dev,
- void (*data_req)(void *, int, int), void *opaque)
-{
- WM8750State *s = WM8750(dev);
-
- s->data_req = data_req;
- s->opaque = opaque;
-}
-
-void wm8750_dac_dat(void *opaque, uint32_t sample)
-{
- WM8750State *s = (WM8750State *) opaque;
-
- *(uint32_t *) &s->data_out[s->idx_out] = sample;
- s->req_out -= 4;
- s->idx_out += 4;
- if (s->idx_out >= sizeof(s->data_out) || s->req_out <= 0)
- wm8750_out_flush(s);
-}
-
-void *wm8750_dac_buffer(void *opaque, int samples)
-{
- WM8750State *s = (WM8750State *) opaque;
- /* XXX: Should check if there are <i>samples</i> free samples available */
- void *ret = s->data_out + s->idx_out;
-
- s->idx_out += samples << 2;
- s->req_out -= samples << 2;
- return ret;
-}
-
-void wm8750_dac_commit(void *opaque)
-{
- WM8750State *s = (WM8750State *) opaque;
-
- wm8750_out_flush(s);
-}
-
-uint32_t wm8750_adc_dat(void *opaque)
-{
- WM8750State *s = (WM8750State *) opaque;
- uint32_t *data;
-
- if (s->idx_in >= sizeof(s->data_in))
- wm8750_in_load(s);
-
- data = (uint32_t *) &s->data_in[s->idx_in];
- s->req_in -= 4;
- s->idx_in += 4;
- return *data;
-}
-
-void wm8750_set_bclk_in(void *opaque, int new_hz)
-{
- WM8750State *s = (WM8750State *) opaque;
-
- s->ext_adc_hz = new_hz;
- s->ext_dac_hz = new_hz;
- wm8750_clk_update(s, 1);
-}
-
-static void wm8750_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
-
- sc->init = wm8750_init;
- sc->event = wm8750_event;
- sc->recv = wm8750_rx;
- sc->send = wm8750_tx;
- dc->vmsd = &vmstate_wm8750;
-}
-
-static const TypeInfo wm8750_info = {
- .name = TYPE_WM8750,
- .parent = TYPE_I2C_SLAVE,
- .instance_size = sizeof(WM8750State),
- .class_init = wm8750_class_init,
-};
-
-static void wm8750_register_types(void)
-{
- type_register_static(&wm8750_info);
-}
-
-type_init(wm8750_register_types)
diff --git a/qemu/hw/block/Makefile.objs b/qemu/hw/block/Makefile.objs
deleted file mode 100644
index d4c3ab758..000000000
--- a/qemu/hw/block/Makefile.objs
+++ /dev/null
@@ -1,15 +0,0 @@
-common-obj-y += block.o cdrom.o hd-geometry.o
-common-obj-$(CONFIG_FDC) += fdc.o
-common-obj-$(CONFIG_SSI_M25P80) += m25p80.o
-common-obj-$(CONFIG_NAND) += nand.o
-common-obj-$(CONFIG_PFLASH_CFI01) += pflash_cfi01.o
-common-obj-$(CONFIG_PFLASH_CFI02) += pflash_cfi02.o
-common-obj-$(CONFIG_XEN_BACKEND) += xen_disk.o
-common-obj-$(CONFIG_ECC) += ecc.o
-common-obj-$(CONFIG_ONENAND) += onenand.o
-common-obj-$(CONFIG_NVME_PCI) += nvme.o
-
-obj-$(CONFIG_SH4) += tc58128.o
-
-obj-$(CONFIG_VIRTIO) += virtio-blk.o
-obj-$(CONFIG_VIRTIO) += dataplane/
diff --git a/qemu/hw/block/block.c b/qemu/hw/block/block.c
deleted file mode 100644
index 97a59d4fa..000000000
--- a/qemu/hw/block/block.c
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Common code for block device models
- *
- * Copyright (C) 2012 Red Hat, Inc.
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or
- * later. See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "sysemu/blockdev.h"
-#include "sysemu/block-backend.h"
-#include "hw/block/block.h"
-#include "qapi/error.h"
-#include "qemu/error-report.h"
-
-void blkconf_serial(BlockConf *conf, char **serial)
-{
- DriveInfo *dinfo;
-
- if (!*serial) {
- /* try to fall back to value set with legacy -drive serial=... */
- dinfo = blk_legacy_dinfo(conf->blk);
- if (dinfo) {
- *serial = g_strdup(dinfo->serial);
- }
- }
-}
-
-void blkconf_blocksizes(BlockConf *conf)
-{
- BlockBackend *blk = conf->blk;
- BlockSizes blocksizes;
- int backend_ret;
-
- backend_ret = blk_probe_blocksizes(blk, &blocksizes);
- /* fill in detected values if they are not defined via qemu command line */
- if (!conf->physical_block_size) {
- if (!backend_ret) {
- conf->physical_block_size = blocksizes.phys;
- } else {
- conf->physical_block_size = BDRV_SECTOR_SIZE;
- }
- }
- if (!conf->logical_block_size) {
- if (!backend_ret) {
- conf->logical_block_size = blocksizes.log;
- } else {
- conf->logical_block_size = BDRV_SECTOR_SIZE;
- }
- }
-}
-
-void blkconf_geometry(BlockConf *conf, int *ptrans,
- unsigned cyls_max, unsigned heads_max, unsigned secs_max,
- Error **errp)
-{
- DriveInfo *dinfo;
-
- if (!conf->cyls && !conf->heads && !conf->secs) {
- /* try to fall back to value set with legacy -drive cyls=... */
- dinfo = blk_legacy_dinfo(conf->blk);
- if (dinfo) {
- conf->cyls = dinfo->cyls;
- conf->heads = dinfo->heads;
- conf->secs = dinfo->secs;
- if (ptrans) {
- *ptrans = dinfo->trans;
- }
- }
- }
- if (!conf->cyls && !conf->heads && !conf->secs) {
- hd_geometry_guess(conf->blk,
- &conf->cyls, &conf->heads, &conf->secs,
- ptrans);
- } else if (ptrans && *ptrans == BIOS_ATA_TRANSLATION_AUTO) {
- *ptrans = hd_bios_chs_auto_trans(conf->cyls, conf->heads, conf->secs);
- }
- if (conf->cyls || conf->heads || conf->secs) {
- if (conf->cyls < 1 || conf->cyls > cyls_max) {
- error_setg(errp, "cyls must be between 1 and %u", cyls_max);
- return;
- }
- if (conf->heads < 1 || conf->heads > heads_max) {
- error_setg(errp, "heads must be between 1 and %u", heads_max);
- return;
- }
- if (conf->secs < 1 || conf->secs > secs_max) {
- error_setg(errp, "secs must be between 1 and %u", secs_max);
- return;
- }
- }
-}
diff --git a/qemu/hw/block/cdrom.c b/qemu/hw/block/cdrom.c
deleted file mode 100644
index da937fe33..000000000
--- a/qemu/hw/block/cdrom.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * QEMU ATAPI CD-ROM Emulator
- *
- * Copyright (c) 2006 Fabrice Bellard
- *
- * 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.
- */
-
-/* ??? Most of the ATAPI emulation is still in ide.c. It should be moved
- here. */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "hw/scsi/scsi.h"
-
-static void lba_to_msf(uint8_t *buf, int lba)
-{
- lba += 150;
- buf[0] = (lba / 75) / 60;
- buf[1] = (lba / 75) % 60;
- buf[2] = lba % 75;
-}
-
-/* same toc as bochs. Return -1 if error or the toc length */
-/* XXX: check this */
-int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track)
-{
- uint8_t *q;
- int len;
-
- if (start_track > 1 && start_track != 0xaa)
- return -1;
- q = buf + 2;
- *q++ = 1; /* first session */
- *q++ = 1; /* last session */
- if (start_track <= 1) {
- *q++ = 0; /* reserved */
- *q++ = 0x14; /* ADR, control */
- *q++ = 1; /* track number */
- *q++ = 0; /* reserved */
- if (msf) {
- *q++ = 0; /* reserved */
- lba_to_msf(q, 0);
- q += 3;
- } else {
- /* sector 0 */
- stl_be_p(q, 0);
- q += 4;
- }
- }
- /* lead out track */
- *q++ = 0; /* reserved */
- *q++ = 0x16; /* ADR, control */
- *q++ = 0xaa; /* track number */
- *q++ = 0; /* reserved */
- if (msf) {
- *q++ = 0; /* reserved */
- lba_to_msf(q, nb_sectors);
- q += 3;
- } else {
- stl_be_p(q, nb_sectors);
- q += 4;
- }
- len = q - buf;
- stw_be_p(buf, len - 2);
- return len;
-}
-
-/* mostly same info as PearPc */
-int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num)
-{
- uint8_t *q;
- int len;
-
- q = buf + 2;
- *q++ = 1; /* first session */
- *q++ = 1; /* last session */
-
- *q++ = 1; /* session number */
- *q++ = 0x14; /* data track */
- *q++ = 0; /* track number */
- *q++ = 0xa0; /* lead-in */
- *q++ = 0; /* min */
- *q++ = 0; /* sec */
- *q++ = 0; /* frame */
- *q++ = 0;
- *q++ = 1; /* first track */
- *q++ = 0x00; /* disk type */
- *q++ = 0x00;
-
- *q++ = 1; /* session number */
- *q++ = 0x14; /* data track */
- *q++ = 0; /* track number */
- *q++ = 0xa1;
- *q++ = 0; /* min */
- *q++ = 0; /* sec */
- *q++ = 0; /* frame */
- *q++ = 0;
- *q++ = 1; /* last track */
- *q++ = 0x00;
- *q++ = 0x00;
-
- *q++ = 1; /* session number */
- *q++ = 0x14; /* data track */
- *q++ = 0; /* track number */
- *q++ = 0xa2; /* lead-out */
- *q++ = 0; /* min */
- *q++ = 0; /* sec */
- *q++ = 0; /* frame */
- if (msf) {
- *q++ = 0; /* reserved */
- lba_to_msf(q, nb_sectors);
- q += 3;
- } else {
- stl_be_p(q, nb_sectors);
- q += 4;
- }
-
- *q++ = 1; /* session number */
- *q++ = 0x14; /* ADR, control */
- *q++ = 0; /* track number */
- *q++ = 1; /* point */
- *q++ = 0; /* min */
- *q++ = 0; /* sec */
- *q++ = 0; /* frame */
- if (msf) {
- *q++ = 0;
- lba_to_msf(q, 0);
- q += 3;
- } else {
- *q++ = 0;
- *q++ = 0;
- *q++ = 0;
- *q++ = 0;
- }
-
- len = q - buf;
- stw_be_p(buf, len - 2);
- return len;
-}
diff --git a/qemu/hw/block/dataplane/Makefile.objs b/qemu/hw/block/dataplane/Makefile.objs
deleted file mode 100644
index e786f6642..000000000
--- a/qemu/hw/block/dataplane/Makefile.objs
+++ /dev/null
@@ -1 +0,0 @@
-obj-y += virtio-blk.o
diff --git a/qemu/hw/block/dataplane/virtio-blk.c b/qemu/hw/block/dataplane/virtio-blk.c
deleted file mode 100644
index 3cb97c9a2..000000000
--- a/qemu/hw/block/dataplane/virtio-blk.c
+++ /dev/null
@@ -1,290 +0,0 @@
-/*
- * Dedicated thread for virtio-blk I/O processing
- *
- * Copyright 2012 IBM, Corp.
- * Copyright 2012 Red Hat, Inc. and/or its affiliates
- *
- * Authors:
- * Stefan Hajnoczi <stefanha@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "trace.h"
-#include "qemu/iov.h"
-#include "qemu/thread.h"
-#include "qemu/error-report.h"
-#include "hw/virtio/virtio-access.h"
-#include "sysemu/block-backend.h"
-#include "hw/virtio/virtio-blk.h"
-#include "virtio-blk.h"
-#include "block/aio.h"
-#include "hw/virtio/virtio-bus.h"
-#include "qom/object_interfaces.h"
-
-struct VirtIOBlockDataPlane {
- bool starting;
- bool stopping;
-
- VirtIOBlkConf *conf;
-
- VirtIODevice *vdev;
- VirtQueue *vq; /* virtqueue vring */
- EventNotifier *guest_notifier; /* irq */
- QEMUBH *bh; /* bh for guest notification */
-
- Notifier insert_notifier, remove_notifier;
-
- /* Note that these EventNotifiers are assigned by value. This is
- * fine as long as you do not call event_notifier_cleanup on them
- * (because you don't own the file descriptor or handle; you just
- * use it).
- */
- IOThread *iothread;
- AioContext *ctx;
-
- /* Operation blocker on BDS */
- Error *blocker;
-};
-
-/* Raise an interrupt to signal guest, if necessary */
-void virtio_blk_data_plane_notify(VirtIOBlockDataPlane *s)
-{
- qemu_bh_schedule(s->bh);
-}
-
-static void notify_guest_bh(void *opaque)
-{
- VirtIOBlockDataPlane *s = opaque;
-
- if (!virtio_should_notify(s->vdev, s->vq)) {
- return;
- }
-
- event_notifier_set(s->guest_notifier);
-}
-
-static void data_plane_set_up_op_blockers(VirtIOBlockDataPlane *s)
-{
- assert(!s->blocker);
- error_setg(&s->blocker, "block device is in use by data plane");
- blk_op_block_all(s->conf->conf.blk, s->blocker);
- blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_RESIZE, s->blocker);
- blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_DRIVE_DEL, s->blocker);
- blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_BACKUP_SOURCE, s->blocker);
- blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_CHANGE, s->blocker);
- blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_COMMIT_SOURCE, s->blocker);
- blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_COMMIT_TARGET, s->blocker);
- blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_EJECT, s->blocker);
- blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_EXTERNAL_SNAPSHOT,
- s->blocker);
- blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT,
- s->blocker);
- blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT_DELETE,
- s->blocker);
- blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_MIRROR_SOURCE, s->blocker);
- blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_STREAM, s->blocker);
- blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_REPLACE, s->blocker);
-}
-
-static void data_plane_remove_op_blockers(VirtIOBlockDataPlane *s)
-{
- if (s->blocker) {
- blk_op_unblock_all(s->conf->conf.blk, s->blocker);
- error_free(s->blocker);
- s->blocker = NULL;
- }
-}
-
-static void data_plane_blk_insert_notifier(Notifier *n, void *data)
-{
- VirtIOBlockDataPlane *s = container_of(n, VirtIOBlockDataPlane,
- insert_notifier);
- assert(s->conf->conf.blk == data);
- data_plane_set_up_op_blockers(s);
-}
-
-static void data_plane_blk_remove_notifier(Notifier *n, void *data)
-{
- VirtIOBlockDataPlane *s = container_of(n, VirtIOBlockDataPlane,
- remove_notifier);
- assert(s->conf->conf.blk == data);
- data_plane_remove_op_blockers(s);
-}
-
-/* Context: QEMU global mutex held */
-void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf,
- VirtIOBlockDataPlane **dataplane,
- Error **errp)
-{
- VirtIOBlockDataPlane *s;
- BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
- VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
-
- *dataplane = NULL;
-
- if (!conf->iothread) {
- return;
- }
-
- /* Don't try if transport does not support notifiers. */
- if (!k->set_guest_notifiers || !k->set_host_notifier) {
- error_setg(errp,
- "device is incompatible with dataplane "
- "(transport does not support notifiers)");
- return;
- }
-
- /* If dataplane is (re-)enabled while the guest is running there could be
- * block jobs that can conflict.
- */
- if (blk_op_is_blocked(conf->conf.blk, BLOCK_OP_TYPE_DATAPLANE, errp)) {
- error_prepend(errp, "cannot start dataplane thread: ");
- return;
- }
-
- s = g_new0(VirtIOBlockDataPlane, 1);
- s->vdev = vdev;
- s->conf = conf;
-
- if (conf->iothread) {
- s->iothread = conf->iothread;
- object_ref(OBJECT(s->iothread));
- }
- s->ctx = iothread_get_aio_context(s->iothread);
- s->bh = aio_bh_new(s->ctx, notify_guest_bh, s);
-
- s->insert_notifier.notify = data_plane_blk_insert_notifier;
- s->remove_notifier.notify = data_plane_blk_remove_notifier;
- blk_add_insert_bs_notifier(conf->conf.blk, &s->insert_notifier);
- blk_add_remove_bs_notifier(conf->conf.blk, &s->remove_notifier);
-
- data_plane_set_up_op_blockers(s);
-
- *dataplane = s;
-}
-
-/* Context: QEMU global mutex held */
-void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s)
-{
- if (!s) {
- return;
- }
-
- virtio_blk_data_plane_stop(s);
- data_plane_remove_op_blockers(s);
- notifier_remove(&s->insert_notifier);
- notifier_remove(&s->remove_notifier);
- qemu_bh_delete(s->bh);
- object_unref(OBJECT(s->iothread));
- g_free(s);
-}
-
-static void virtio_blk_data_plane_handle_output(VirtIODevice *vdev,
- VirtQueue *vq)
-{
- VirtIOBlock *s = (VirtIOBlock *)vdev;
-
- assert(s->dataplane);
- assert(s->dataplane_started);
-
- virtio_blk_handle_vq(s, vq);
-}
-
-/* Context: QEMU global mutex held */
-void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s)
-{
- BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s->vdev)));
- VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
- VirtIOBlock *vblk = VIRTIO_BLK(s->vdev);
- int r;
-
- if (vblk->dataplane_started || s->starting) {
- return;
- }
-
- s->starting = true;
- s->vq = virtio_get_queue(s->vdev, 0);
-
- /* Set up guest notifier (irq) */
- r = k->set_guest_notifiers(qbus->parent, 1, true);
- if (r != 0) {
- fprintf(stderr, "virtio-blk failed to set guest notifier (%d), "
- "ensure -enable-kvm is set\n", r);
- goto fail_guest_notifiers;
- }
- s->guest_notifier = virtio_queue_get_guest_notifier(s->vq);
-
- /* Set up virtqueue notify */
- r = k->set_host_notifier(qbus->parent, 0, true);
- if (r != 0) {
- fprintf(stderr, "virtio-blk failed to set host notifier (%d)\n", r);
- goto fail_host_notifier;
- }
-
- s->starting = false;
- vblk->dataplane_started = true;
- trace_virtio_blk_data_plane_start(s);
-
- blk_set_aio_context(s->conf->conf.blk, s->ctx);
-
- /* Kick right away to begin processing requests already in vring */
- event_notifier_set(virtio_queue_get_host_notifier(s->vq));
-
- /* Get this show started by hooking up our callbacks */
- aio_context_acquire(s->ctx);
- virtio_queue_aio_set_host_notifier_handler(s->vq, s->ctx,
- virtio_blk_data_plane_handle_output);
- aio_context_release(s->ctx);
- return;
-
- fail_host_notifier:
- k->set_guest_notifiers(qbus->parent, 1, false);
- fail_guest_notifiers:
- vblk->dataplane_disabled = true;
- s->starting = false;
- vblk->dataplane_started = true;
-}
-
-/* Context: QEMU global mutex held */
-void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s)
-{
- BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s->vdev)));
- VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
- VirtIOBlock *vblk = VIRTIO_BLK(s->vdev);
-
- if (!vblk->dataplane_started || s->stopping) {
- return;
- }
-
- /* Better luck next time. */
- if (vblk->dataplane_disabled) {
- vblk->dataplane_disabled = false;
- vblk->dataplane_started = false;
- return;
- }
- s->stopping = true;
- trace_virtio_blk_data_plane_stop(s);
-
- aio_context_acquire(s->ctx);
-
- /* Stop notifications for new requests from guest */
- virtio_queue_aio_set_host_notifier_handler(s->vq, s->ctx, NULL);
-
- /* Drain and switch bs back to the QEMU main loop */
- blk_set_aio_context(s->conf->conf.blk, qemu_get_aio_context());
-
- aio_context_release(s->ctx);
-
- k->set_host_notifier(qbus->parent, 0, false);
-
- /* Clean up guest notifier (irq) */
- k->set_guest_notifiers(qbus->parent, 1, false);
-
- vblk->dataplane_started = false;
- s->stopping = false;
-}
diff --git a/qemu/hw/block/dataplane/virtio-blk.h b/qemu/hw/block/dataplane/virtio-blk.h
deleted file mode 100644
index 0714c11a2..000000000
--- a/qemu/hw/block/dataplane/virtio-blk.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Dedicated thread for virtio-blk I/O processing
- *
- * Copyright 2012 IBM, Corp.
- * Copyright 2012 Red Hat, Inc. and/or its affiliates
- *
- * Authors:
- * Stefan Hajnoczi <stefanha@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#ifndef HW_DATAPLANE_VIRTIO_BLK_H
-#define HW_DATAPLANE_VIRTIO_BLK_H
-
-#include "hw/virtio/virtio.h"
-
-typedef struct VirtIOBlockDataPlane VirtIOBlockDataPlane;
-
-void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf,
- VirtIOBlockDataPlane **dataplane,
- Error **errp);
-void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s);
-void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s);
-void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s);
-void virtio_blk_data_plane_drain(VirtIOBlockDataPlane *s);
-void virtio_blk_data_plane_notify(VirtIOBlockDataPlane *s);
-
-#endif /* HW_DATAPLANE_VIRTIO_BLK_H */
diff --git a/qemu/hw/block/ecc.c b/qemu/hw/block/ecc.c
deleted file mode 100644
index 48311d260..000000000
--- a/qemu/hw/block/ecc.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Calculate Error-correcting Codes. Used by NAND Flash controllers
- * (not by NAND chips).
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/block/flash.h"
-
-/*
- * Pre-calculated 256-way 1 byte column parity. Table borrowed from Linux.
- */
-static const uint8_t nand_ecc_precalc_table[] = {
- 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a,
- 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
- 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f,
- 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
- 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c,
- 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
- 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59,
- 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
- 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33,
- 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
- 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56,
- 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
- 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55,
- 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
- 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30,
- 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
- 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30,
- 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
- 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55,
- 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
- 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56,
- 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
- 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33,
- 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
- 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59,
- 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
- 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c,
- 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
- 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f,
- 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
- 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a,
- 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
-};
-
-/* Update ECC parity count. */
-uint8_t ecc_digest(ECCState *s, uint8_t sample)
-{
- uint8_t idx = nand_ecc_precalc_table[sample];
-
- s->cp ^= idx & 0x3f;
- if (idx & 0x40) {
- s->lp[0] ^= ~s->count;
- s->lp[1] ^= s->count;
- }
- s->count ++;
-
- return sample;
-}
-
-/* Reinitialise the counters. */
-void ecc_reset(ECCState *s)
-{
- s->lp[0] = 0x0000;
- s->lp[1] = 0x0000;
- s->cp = 0x00;
- s->count = 0;
-}
-
-/* Save/restore */
-VMStateDescription vmstate_ecc_state = {
- .name = "ecc-state",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(cp, ECCState),
- VMSTATE_UINT16_ARRAY(lp, ECCState, 2),
- VMSTATE_UINT16(count, ECCState),
- VMSTATE_END_OF_LIST(),
- },
-};
diff --git a/qemu/hw/block/fdc.c b/qemu/hw/block/fdc.c
deleted file mode 100644
index 372227569..000000000
--- a/qemu/hw/block/fdc.c
+++ /dev/null
@@ -1,2738 +0,0 @@
-/*
- * QEMU Floppy disk emulator (Intel 82078)
- *
- * Copyright (c) 2003, 2007 Jocelyn Mayer
- * Copyright (c) 2008 Hervé Poussineau
- *
- * 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.
- */
-/*
- * The controller is used in Sun4m systems in a slightly different
- * way. There are changes in DOR register and DMA is not available.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/block/fdc.h"
-#include "qapi/error.h"
-#include "qemu/error-report.h"
-#include "qemu/timer.h"
-#include "hw/isa/isa.h"
-#include "hw/sysbus.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
-#include "sysemu/sysemu.h"
-#include "qemu/log.h"
-
-/********************************************************/
-/* debug Floppy devices */
-
-#define DEBUG_FLOPPY 0
-
-#define FLOPPY_DPRINTF(fmt, ...) \
- do { \
- if (DEBUG_FLOPPY) { \
- fprintf(stderr, "FLOPPY: " fmt , ## __VA_ARGS__); \
- } \
- } while (0)
-
-/********************************************************/
-/* Floppy drive emulation */
-
-typedef enum FDriveRate {
- FDRIVE_RATE_500K = 0x00, /* 500 Kbps */
- FDRIVE_RATE_300K = 0x01, /* 300 Kbps */
- FDRIVE_RATE_250K = 0x02, /* 250 Kbps */
- FDRIVE_RATE_1M = 0x03, /* 1 Mbps */
-} FDriveRate;
-
-typedef enum FDriveSize {
- FDRIVE_SIZE_UNKNOWN,
- FDRIVE_SIZE_350,
- FDRIVE_SIZE_525,
-} FDriveSize;
-
-typedef struct FDFormat {
- FloppyDriveType drive;
- uint8_t last_sect;
- uint8_t max_track;
- uint8_t max_head;
- FDriveRate rate;
-} FDFormat;
-
-/* In many cases, the total sector size of a format is enough to uniquely
- * identify it. However, there are some total sector collisions between
- * formats of different physical size, and these are noted below by
- * highlighting the total sector size for entries with collisions. */
-static const FDFormat fd_formats[] = {
- /* First entry is default format */
- /* 1.44 MB 3"1/2 floppy disks */
- { FLOPPY_DRIVE_TYPE_144, 18, 80, 1, FDRIVE_RATE_500K, }, /* 3.5" 2880 */
- { FLOPPY_DRIVE_TYPE_144, 20, 80, 1, FDRIVE_RATE_500K, }, /* 3.5" 3200 */
- { FLOPPY_DRIVE_TYPE_144, 21, 80, 1, FDRIVE_RATE_500K, },
- { FLOPPY_DRIVE_TYPE_144, 21, 82, 1, FDRIVE_RATE_500K, },
- { FLOPPY_DRIVE_TYPE_144, 21, 83, 1, FDRIVE_RATE_500K, },
- { FLOPPY_DRIVE_TYPE_144, 22, 80, 1, FDRIVE_RATE_500K, },
- { FLOPPY_DRIVE_TYPE_144, 23, 80, 1, FDRIVE_RATE_500K, },
- { FLOPPY_DRIVE_TYPE_144, 24, 80, 1, FDRIVE_RATE_500K, },
- /* 2.88 MB 3"1/2 floppy disks */
- { FLOPPY_DRIVE_TYPE_288, 36, 80, 1, FDRIVE_RATE_1M, },
- { FLOPPY_DRIVE_TYPE_288, 39, 80, 1, FDRIVE_RATE_1M, },
- { FLOPPY_DRIVE_TYPE_288, 40, 80, 1, FDRIVE_RATE_1M, },
- { FLOPPY_DRIVE_TYPE_288, 44, 80, 1, FDRIVE_RATE_1M, },
- { FLOPPY_DRIVE_TYPE_288, 48, 80, 1, FDRIVE_RATE_1M, },
- /* 720 kB 3"1/2 floppy disks */
- { FLOPPY_DRIVE_TYPE_144, 9, 80, 1, FDRIVE_RATE_250K, }, /* 3.5" 1440 */
- { FLOPPY_DRIVE_TYPE_144, 10, 80, 1, FDRIVE_RATE_250K, },
- { FLOPPY_DRIVE_TYPE_144, 10, 82, 1, FDRIVE_RATE_250K, },
- { FLOPPY_DRIVE_TYPE_144, 10, 83, 1, FDRIVE_RATE_250K, },
- { FLOPPY_DRIVE_TYPE_144, 13, 80, 1, FDRIVE_RATE_250K, },
- { FLOPPY_DRIVE_TYPE_144, 14, 80, 1, FDRIVE_RATE_250K, },
- /* 1.2 MB 5"1/4 floppy disks */
- { FLOPPY_DRIVE_TYPE_120, 15, 80, 1, FDRIVE_RATE_500K, },
- { FLOPPY_DRIVE_TYPE_120, 18, 80, 1, FDRIVE_RATE_500K, }, /* 5.25" 2880 */
- { FLOPPY_DRIVE_TYPE_120, 18, 82, 1, FDRIVE_RATE_500K, },
- { FLOPPY_DRIVE_TYPE_120, 18, 83, 1, FDRIVE_RATE_500K, },
- { FLOPPY_DRIVE_TYPE_120, 20, 80, 1, FDRIVE_RATE_500K, }, /* 5.25" 3200 */
- /* 720 kB 5"1/4 floppy disks */
- { FLOPPY_DRIVE_TYPE_120, 9, 80, 1, FDRIVE_RATE_250K, }, /* 5.25" 1440 */
- { FLOPPY_DRIVE_TYPE_120, 11, 80, 1, FDRIVE_RATE_250K, },
- /* 360 kB 5"1/4 floppy disks */
- { FLOPPY_DRIVE_TYPE_120, 9, 40, 1, FDRIVE_RATE_300K, }, /* 5.25" 720 */
- { FLOPPY_DRIVE_TYPE_120, 9, 40, 0, FDRIVE_RATE_300K, },
- { FLOPPY_DRIVE_TYPE_120, 10, 41, 1, FDRIVE_RATE_300K, },
- { FLOPPY_DRIVE_TYPE_120, 10, 42, 1, FDRIVE_RATE_300K, },
- /* 320 kB 5"1/4 floppy disks */
- { FLOPPY_DRIVE_TYPE_120, 8, 40, 1, FDRIVE_RATE_250K, },
- { FLOPPY_DRIVE_TYPE_120, 8, 40, 0, FDRIVE_RATE_250K, },
- /* 360 kB must match 5"1/4 better than 3"1/2... */
- { FLOPPY_DRIVE_TYPE_144, 9, 80, 0, FDRIVE_RATE_250K, }, /* 3.5" 720 */
- /* end */
- { FLOPPY_DRIVE_TYPE_NONE, -1, -1, 0, 0, },
-};
-
-static FDriveSize drive_size(FloppyDriveType drive)
-{
- switch (drive) {
- case FLOPPY_DRIVE_TYPE_120:
- return FDRIVE_SIZE_525;
- case FLOPPY_DRIVE_TYPE_144:
- case FLOPPY_DRIVE_TYPE_288:
- return FDRIVE_SIZE_350;
- default:
- return FDRIVE_SIZE_UNKNOWN;
- }
-}
-
-#define GET_CUR_DRV(fdctrl) ((fdctrl)->cur_drv)
-#define SET_CUR_DRV(fdctrl, drive) ((fdctrl)->cur_drv = (drive))
-
-/* Will always be a fixed parameter for us */
-#define FD_SECTOR_LEN 512
-#define FD_SECTOR_SC 2 /* Sector size code */
-#define FD_RESET_SENSEI_COUNT 4 /* Number of sense interrupts on RESET */
-
-typedef struct FDCtrl FDCtrl;
-
-/* Floppy disk drive emulation */
-typedef enum FDiskFlags {
- FDISK_DBL_SIDES = 0x01,
-} FDiskFlags;
-
-typedef struct FDrive {
- FDCtrl *fdctrl;
- BlockBackend *blk;
- /* Drive status */
- FloppyDriveType drive; /* CMOS drive type */
- uint8_t perpendicular; /* 2.88 MB access mode */
- /* Position */
- uint8_t head;
- uint8_t track;
- uint8_t sect;
- /* Media */
- FloppyDriveType disk; /* Current disk type */
- FDiskFlags flags;
- uint8_t last_sect; /* Nb sector per track */
- uint8_t max_track; /* Nb of tracks */
- uint16_t bps; /* Bytes per sector */
- uint8_t ro; /* Is read-only */
- uint8_t media_changed; /* Is media changed */
- uint8_t media_rate; /* Data rate of medium */
-
- bool media_validated; /* Have we validated the media? */
-} FDrive;
-
-
-static FloppyDriveType get_fallback_drive_type(FDrive *drv);
-
-/* Hack: FD_SEEK is expected to work on empty drives. However, QEMU
- * currently goes through some pains to keep seeks within the bounds
- * established by last_sect and max_track. Correcting this is difficult,
- * as refactoring FDC code tends to expose nasty bugs in the Linux kernel.
- *
- * For now: allow empty drives to have large bounds so we can seek around,
- * with the understanding that when a diskette is inserted, the bounds will
- * properly tighten to match the geometry of that inserted medium.
- */
-static void fd_empty_seek_hack(FDrive *drv)
-{
- drv->last_sect = 0xFF;
- drv->max_track = 0xFF;
-}
-
-static void fd_init(FDrive *drv)
-{
- /* Drive */
- drv->perpendicular = 0;
- /* Disk */
- drv->disk = FLOPPY_DRIVE_TYPE_NONE;
- drv->last_sect = 0;
- drv->max_track = 0;
- drv->ro = true;
- drv->media_changed = 1;
-}
-
-#define NUM_SIDES(drv) ((drv)->flags & FDISK_DBL_SIDES ? 2 : 1)
-
-static int fd_sector_calc(uint8_t head, uint8_t track, uint8_t sect,
- uint8_t last_sect, uint8_t num_sides)
-{
- return (((track * num_sides) + head) * last_sect) + sect - 1;
-}
-
-/* Returns current position, in sectors, for given drive */
-static int fd_sector(FDrive *drv)
-{
- return fd_sector_calc(drv->head, drv->track, drv->sect, drv->last_sect,
- NUM_SIDES(drv));
-}
-
-/* Seek to a new position:
- * returns 0 if already on right track
- * returns 1 if track changed
- * returns 2 if track is invalid
- * returns 3 if sector is invalid
- * returns 4 if seek is disabled
- */
-static int fd_seek(FDrive *drv, uint8_t head, uint8_t track, uint8_t sect,
- int enable_seek)
-{
- uint32_t sector;
- int ret;
-
- if (track > drv->max_track ||
- (head != 0 && (drv->flags & FDISK_DBL_SIDES) == 0)) {
- FLOPPY_DPRINTF("try to read %d %02x %02x (max=%d %d %02x %02x)\n",
- head, track, sect, 1,
- (drv->flags & FDISK_DBL_SIDES) == 0 ? 0 : 1,
- drv->max_track, drv->last_sect);
- return 2;
- }
- if (sect > drv->last_sect) {
- FLOPPY_DPRINTF("try to read %d %02x %02x (max=%d %d %02x %02x)\n",
- head, track, sect, 1,
- (drv->flags & FDISK_DBL_SIDES) == 0 ? 0 : 1,
- drv->max_track, drv->last_sect);
- return 3;
- }
- sector = fd_sector_calc(head, track, sect, drv->last_sect, NUM_SIDES(drv));
- ret = 0;
- if (sector != fd_sector(drv)) {
-#if 0
- if (!enable_seek) {
- FLOPPY_DPRINTF("error: no implicit seek %d %02x %02x"
- " (max=%d %02x %02x)\n",
- head, track, sect, 1, drv->max_track,
- drv->last_sect);
- return 4;
- }
-#endif
- drv->head = head;
- if (drv->track != track) {
- if (drv->blk != NULL && blk_is_inserted(drv->blk)) {
- drv->media_changed = 0;
- }
- ret = 1;
- }
- drv->track = track;
- drv->sect = sect;
- }
-
- if (drv->blk == NULL || !blk_is_inserted(drv->blk)) {
- ret = 2;
- }
-
- return ret;
-}
-
-/* Set drive back to track 0 */
-static void fd_recalibrate(FDrive *drv)
-{
- FLOPPY_DPRINTF("recalibrate\n");
- fd_seek(drv, 0, 0, 1, 1);
-}
-
-/**
- * Determine geometry based on inserted diskette.
- * Will not operate on an empty drive.
- *
- * @return: 0 on success, -1 if the drive is empty.
- */
-static int pick_geometry(FDrive *drv)
-{
- BlockBackend *blk = drv->blk;
- const FDFormat *parse;
- uint64_t nb_sectors, size;
- int i;
- int match, size_match, type_match;
- bool magic = drv->drive == FLOPPY_DRIVE_TYPE_AUTO;
-
- /* We can only pick a geometry if we have a diskette. */
- if (!drv->blk || !blk_is_inserted(drv->blk) ||
- drv->drive == FLOPPY_DRIVE_TYPE_NONE)
- {
- return -1;
- }
-
- /* We need to determine the likely geometry of the inserted medium.
- * In order of preference, we look for:
- * (1) The same drive type and number of sectors,
- * (2) The same diskette size and number of sectors,
- * (3) The same drive type.
- *
- * In all cases, matches that occur higher in the drive table will take
- * precedence over matches that occur later in the table.
- */
- blk_get_geometry(blk, &nb_sectors);
- match = size_match = type_match = -1;
- for (i = 0; ; i++) {
- parse = &fd_formats[i];
- if (parse->drive == FLOPPY_DRIVE_TYPE_NONE) {
- break;
- }
- size = (parse->max_head + 1) * parse->max_track * parse->last_sect;
- if (nb_sectors == size) {
- if (magic || parse->drive == drv->drive) {
- /* (1) perfect match -- nb_sectors and drive type */
- goto out;
- } else if (drive_size(parse->drive) == drive_size(drv->drive)) {
- /* (2) size match -- nb_sectors and physical medium size */
- match = (match == -1) ? i : match;
- } else {
- /* This is suspicious -- Did the user misconfigure? */
- size_match = (size_match == -1) ? i : size_match;
- }
- } else if (type_match == -1) {
- if ((parse->drive == drv->drive) ||
- (magic && (parse->drive == get_fallback_drive_type(drv)))) {
- /* (3) type match -- nb_sectors mismatch, but matches the type
- * specified explicitly by the user, or matches the fallback
- * default type when using the drive autodetect mechanism */
- type_match = i;
- }
- }
- }
-
- /* No exact match found */
- if (match == -1) {
- if (size_match != -1) {
- parse = &fd_formats[size_match];
- FLOPPY_DPRINTF("User requested floppy drive type '%s', "
- "but inserted medium appears to be a "
- "%"PRId64" sector '%s' type\n",
- FloppyDriveType_lookup[drv->drive],
- nb_sectors,
- FloppyDriveType_lookup[parse->drive]);
- }
- match = type_match;
- }
-
- /* No match of any kind found -- fd_format is misconfigured, abort. */
- if (match == -1) {
- error_setg(&error_abort, "No candidate geometries present in table "
- " for floppy drive type '%s'",
- FloppyDriveType_lookup[drv->drive]);
- }
-
- parse = &(fd_formats[match]);
-
- out:
- if (parse->max_head == 0) {
- drv->flags &= ~FDISK_DBL_SIDES;
- } else {
- drv->flags |= FDISK_DBL_SIDES;
- }
- drv->max_track = parse->max_track;
- drv->last_sect = parse->last_sect;
- drv->disk = parse->drive;
- drv->media_rate = parse->rate;
- return 0;
-}
-
-static void pick_drive_type(FDrive *drv)
-{
- if (drv->drive != FLOPPY_DRIVE_TYPE_AUTO) {
- return;
- }
-
- if (pick_geometry(drv) == 0) {
- drv->drive = drv->disk;
- } else {
- drv->drive = get_fallback_drive_type(drv);
- }
-
- g_assert(drv->drive != FLOPPY_DRIVE_TYPE_AUTO);
-}
-
-/* Revalidate a disk drive after a disk change */
-static void fd_revalidate(FDrive *drv)
-{
- int rc;
-
- FLOPPY_DPRINTF("revalidate\n");
- if (drv->blk != NULL) {
- drv->ro = blk_is_read_only(drv->blk);
- if (!blk_is_inserted(drv->blk)) {
- FLOPPY_DPRINTF("No disk in drive\n");
- drv->disk = FLOPPY_DRIVE_TYPE_NONE;
- fd_empty_seek_hack(drv);
- } else if (!drv->media_validated) {
- rc = pick_geometry(drv);
- if (rc) {
- FLOPPY_DPRINTF("Could not validate floppy drive media");
- } else {
- drv->media_validated = true;
- FLOPPY_DPRINTF("Floppy disk (%d h %d t %d s) %s\n",
- (drv->flags & FDISK_DBL_SIDES) ? 2 : 1,
- drv->max_track, drv->last_sect,
- drv->ro ? "ro" : "rw");
- }
- }
- } else {
- FLOPPY_DPRINTF("No drive connected\n");
- drv->last_sect = 0;
- drv->max_track = 0;
- drv->flags &= ~FDISK_DBL_SIDES;
- drv->drive = FLOPPY_DRIVE_TYPE_NONE;
- drv->disk = FLOPPY_DRIVE_TYPE_NONE;
- }
-}
-
-/********************************************************/
-/* Intel 82078 floppy disk controller emulation */
-
-static void fdctrl_reset(FDCtrl *fdctrl, int do_irq);
-static void fdctrl_to_command_phase(FDCtrl *fdctrl);
-static int fdctrl_transfer_handler (void *opaque, int nchan,
- int dma_pos, int dma_len);
-static void fdctrl_raise_irq(FDCtrl *fdctrl);
-static FDrive *get_cur_drv(FDCtrl *fdctrl);
-
-static uint32_t fdctrl_read_statusA(FDCtrl *fdctrl);
-static uint32_t fdctrl_read_statusB(FDCtrl *fdctrl);
-static uint32_t fdctrl_read_dor(FDCtrl *fdctrl);
-static void fdctrl_write_dor(FDCtrl *fdctrl, uint32_t value);
-static uint32_t fdctrl_read_tape(FDCtrl *fdctrl);
-static void fdctrl_write_tape(FDCtrl *fdctrl, uint32_t value);
-static uint32_t fdctrl_read_main_status(FDCtrl *fdctrl);
-static void fdctrl_write_rate(FDCtrl *fdctrl, uint32_t value);
-static uint32_t fdctrl_read_data(FDCtrl *fdctrl);
-static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value);
-static uint32_t fdctrl_read_dir(FDCtrl *fdctrl);
-static void fdctrl_write_ccr(FDCtrl *fdctrl, uint32_t value);
-
-enum {
- FD_DIR_WRITE = 0,
- FD_DIR_READ = 1,
- FD_DIR_SCANE = 2,
- FD_DIR_SCANL = 3,
- FD_DIR_SCANH = 4,
- FD_DIR_VERIFY = 5,
-};
-
-enum {
- FD_STATE_MULTI = 0x01, /* multi track flag */
- FD_STATE_FORMAT = 0x02, /* format flag */
-};
-
-enum {
- FD_REG_SRA = 0x00,
- FD_REG_SRB = 0x01,
- FD_REG_DOR = 0x02,
- FD_REG_TDR = 0x03,
- FD_REG_MSR = 0x04,
- FD_REG_DSR = 0x04,
- FD_REG_FIFO = 0x05,
- FD_REG_DIR = 0x07,
- FD_REG_CCR = 0x07,
-};
-
-enum {
- FD_CMD_READ_TRACK = 0x02,
- FD_CMD_SPECIFY = 0x03,
- FD_CMD_SENSE_DRIVE_STATUS = 0x04,
- FD_CMD_WRITE = 0x05,
- FD_CMD_READ = 0x06,
- FD_CMD_RECALIBRATE = 0x07,
- FD_CMD_SENSE_INTERRUPT_STATUS = 0x08,
- FD_CMD_WRITE_DELETED = 0x09,
- FD_CMD_READ_ID = 0x0a,
- FD_CMD_READ_DELETED = 0x0c,
- FD_CMD_FORMAT_TRACK = 0x0d,
- FD_CMD_DUMPREG = 0x0e,
- FD_CMD_SEEK = 0x0f,
- FD_CMD_VERSION = 0x10,
- FD_CMD_SCAN_EQUAL = 0x11,
- FD_CMD_PERPENDICULAR_MODE = 0x12,
- FD_CMD_CONFIGURE = 0x13,
- FD_CMD_LOCK = 0x14,
- FD_CMD_VERIFY = 0x16,
- FD_CMD_POWERDOWN_MODE = 0x17,
- FD_CMD_PART_ID = 0x18,
- FD_CMD_SCAN_LOW_OR_EQUAL = 0x19,
- FD_CMD_SCAN_HIGH_OR_EQUAL = 0x1d,
- FD_CMD_SAVE = 0x2e,
- FD_CMD_OPTION = 0x33,
- FD_CMD_RESTORE = 0x4e,
- FD_CMD_DRIVE_SPECIFICATION_COMMAND = 0x8e,
- FD_CMD_RELATIVE_SEEK_OUT = 0x8f,
- FD_CMD_FORMAT_AND_WRITE = 0xcd,
- FD_CMD_RELATIVE_SEEK_IN = 0xcf,
-};
-
-enum {
- FD_CONFIG_PRETRK = 0xff, /* Pre-compensation set to track 0 */
- FD_CONFIG_FIFOTHR = 0x0f, /* FIFO threshold set to 1 byte */
- FD_CONFIG_POLL = 0x10, /* Poll enabled */
- FD_CONFIG_EFIFO = 0x20, /* FIFO disabled */
- FD_CONFIG_EIS = 0x40, /* No implied seeks */
-};
-
-enum {
- FD_SR0_DS0 = 0x01,
- FD_SR0_DS1 = 0x02,
- FD_SR0_HEAD = 0x04,
- FD_SR0_EQPMT = 0x10,
- FD_SR0_SEEK = 0x20,
- FD_SR0_ABNTERM = 0x40,
- FD_SR0_INVCMD = 0x80,
- FD_SR0_RDYCHG = 0xc0,
-};
-
-enum {
- FD_SR1_MA = 0x01, /* Missing address mark */
- FD_SR1_NW = 0x02, /* Not writable */
- FD_SR1_EC = 0x80, /* End of cylinder */
-};
-
-enum {
- FD_SR2_SNS = 0x04, /* Scan not satisfied */
- FD_SR2_SEH = 0x08, /* Scan equal hit */
-};
-
-enum {
- FD_SRA_DIR = 0x01,
- FD_SRA_nWP = 0x02,
- FD_SRA_nINDX = 0x04,
- FD_SRA_HDSEL = 0x08,
- FD_SRA_nTRK0 = 0x10,
- FD_SRA_STEP = 0x20,
- FD_SRA_nDRV2 = 0x40,
- FD_SRA_INTPEND = 0x80,
-};
-
-enum {
- FD_SRB_MTR0 = 0x01,
- FD_SRB_MTR1 = 0x02,
- FD_SRB_WGATE = 0x04,
- FD_SRB_RDATA = 0x08,
- FD_SRB_WDATA = 0x10,
- FD_SRB_DR0 = 0x20,
-};
-
-enum {
-#if MAX_FD == 4
- FD_DOR_SELMASK = 0x03,
-#else
- FD_DOR_SELMASK = 0x01,
-#endif
- FD_DOR_nRESET = 0x04,
- FD_DOR_DMAEN = 0x08,
- FD_DOR_MOTEN0 = 0x10,
- FD_DOR_MOTEN1 = 0x20,
- FD_DOR_MOTEN2 = 0x40,
- FD_DOR_MOTEN3 = 0x80,
-};
-
-enum {
-#if MAX_FD == 4
- FD_TDR_BOOTSEL = 0x0c,
-#else
- FD_TDR_BOOTSEL = 0x04,
-#endif
-};
-
-enum {
- FD_DSR_DRATEMASK= 0x03,
- FD_DSR_PWRDOWN = 0x40,
- FD_DSR_SWRESET = 0x80,
-};
-
-enum {
- FD_MSR_DRV0BUSY = 0x01,
- FD_MSR_DRV1BUSY = 0x02,
- FD_MSR_DRV2BUSY = 0x04,
- FD_MSR_DRV3BUSY = 0x08,
- FD_MSR_CMDBUSY = 0x10,
- FD_MSR_NONDMA = 0x20,
- FD_MSR_DIO = 0x40,
- FD_MSR_RQM = 0x80,
-};
-
-enum {
- FD_DIR_DSKCHG = 0x80,
-};
-
-/*
- * See chapter 5.0 "Controller phases" of the spec:
- *
- * Command phase:
- * The host writes a command and its parameters into the FIFO. The command
- * phase is completed when all parameters for the command have been supplied,
- * and execution phase is entered.
- *
- * Execution phase:
- * Data transfers, either DMA or non-DMA. For non-DMA transfers, the FIFO
- * contains the payload now, otherwise it's unused. When all bytes of the
- * required data have been transferred, the state is switched to either result
- * phase (if the command produces status bytes) or directly back into the
- * command phase for the next command.
- *
- * Result phase:
- * The host reads out the FIFO, which contains one or more result bytes now.
- */
-enum {
- /* Only for migration: reconstruct phase from registers like qemu 2.3 */
- FD_PHASE_RECONSTRUCT = 0,
-
- FD_PHASE_COMMAND = 1,
- FD_PHASE_EXECUTION = 2,
- FD_PHASE_RESULT = 3,
-};
-
-#define FD_MULTI_TRACK(state) ((state) & FD_STATE_MULTI)
-#define FD_FORMAT_CMD(state) ((state) & FD_STATE_FORMAT)
-
-struct FDCtrl {
- MemoryRegion iomem;
- qemu_irq irq;
- /* Controller state */
- QEMUTimer *result_timer;
- int dma_chann;
- uint8_t phase;
- IsaDma *dma;
- /* Controller's identification */
- uint8_t version;
- /* HW */
- uint8_t sra;
- uint8_t srb;
- uint8_t dor;
- uint8_t dor_vmstate; /* only used as temp during vmstate */
- uint8_t tdr;
- uint8_t dsr;
- uint8_t msr;
- uint8_t cur_drv;
- uint8_t status0;
- uint8_t status1;
- uint8_t status2;
- /* Command FIFO */
- uint8_t *fifo;
- int32_t fifo_size;
- uint32_t data_pos;
- uint32_t data_len;
- uint8_t data_state;
- uint8_t data_dir;
- uint8_t eot; /* last wanted sector */
- /* States kept only to be returned back */
- /* precompensation */
- uint8_t precomp_trk;
- uint8_t config;
- uint8_t lock;
- /* Power down config (also with status regB access mode */
- uint8_t pwrd;
- /* Floppy drives */
- uint8_t num_floppies;
- FDrive drives[MAX_FD];
- int reset_sensei;
- uint32_t check_media_rate;
- FloppyDriveType fallback; /* type=auto failure fallback */
- /* Timers state */
- uint8_t timer0;
- uint8_t timer1;
-};
-
-static FloppyDriveType get_fallback_drive_type(FDrive *drv)
-{
- return drv->fdctrl->fallback;
-}
-
-#define TYPE_SYSBUS_FDC "base-sysbus-fdc"
-#define SYSBUS_FDC(obj) OBJECT_CHECK(FDCtrlSysBus, (obj), TYPE_SYSBUS_FDC)
-
-typedef struct FDCtrlSysBus {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- struct FDCtrl state;
-} FDCtrlSysBus;
-
-#define ISA_FDC(obj) OBJECT_CHECK(FDCtrlISABus, (obj), TYPE_ISA_FDC)
-
-typedef struct FDCtrlISABus {
- ISADevice parent_obj;
-
- uint32_t iobase;
- uint32_t irq;
- uint32_t dma;
- struct FDCtrl state;
- int32_t bootindexA;
- int32_t bootindexB;
-} FDCtrlISABus;
-
-static uint32_t fdctrl_read (void *opaque, uint32_t reg)
-{
- FDCtrl *fdctrl = opaque;
- uint32_t retval;
-
- reg &= 7;
- switch (reg) {
- case FD_REG_SRA:
- retval = fdctrl_read_statusA(fdctrl);
- break;
- case FD_REG_SRB:
- retval = fdctrl_read_statusB(fdctrl);
- break;
- case FD_REG_DOR:
- retval = fdctrl_read_dor(fdctrl);
- break;
- case FD_REG_TDR:
- retval = fdctrl_read_tape(fdctrl);
- break;
- case FD_REG_MSR:
- retval = fdctrl_read_main_status(fdctrl);
- break;
- case FD_REG_FIFO:
- retval = fdctrl_read_data(fdctrl);
- break;
- case FD_REG_DIR:
- retval = fdctrl_read_dir(fdctrl);
- break;
- default:
- retval = (uint32_t)(-1);
- break;
- }
- FLOPPY_DPRINTF("read reg%d: 0x%02x\n", reg & 7, retval);
-
- return retval;
-}
-
-static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value)
-{
- FDCtrl *fdctrl = opaque;
-
- FLOPPY_DPRINTF("write reg%d: 0x%02x\n", reg & 7, value);
-
- reg &= 7;
- switch (reg) {
- case FD_REG_DOR:
- fdctrl_write_dor(fdctrl, value);
- break;
- case FD_REG_TDR:
- fdctrl_write_tape(fdctrl, value);
- break;
- case FD_REG_DSR:
- fdctrl_write_rate(fdctrl, value);
- break;
- case FD_REG_FIFO:
- fdctrl_write_data(fdctrl, value);
- break;
- case FD_REG_CCR:
- fdctrl_write_ccr(fdctrl, value);
- break;
- default:
- break;
- }
-}
-
-static uint64_t fdctrl_read_mem (void *opaque, hwaddr reg,
- unsigned ize)
-{
- return fdctrl_read(opaque, (uint32_t)reg);
-}
-
-static void fdctrl_write_mem (void *opaque, hwaddr reg,
- uint64_t value, unsigned size)
-{
- fdctrl_write(opaque, (uint32_t)reg, value);
-}
-
-static const MemoryRegionOps fdctrl_mem_ops = {
- .read = fdctrl_read_mem,
- .write = fdctrl_write_mem,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const MemoryRegionOps fdctrl_mem_strict_ops = {
- .read = fdctrl_read_mem,
- .write = fdctrl_write_mem,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
-};
-
-static bool fdrive_media_changed_needed(void *opaque)
-{
- FDrive *drive = opaque;
-
- return (drive->blk != NULL && drive->media_changed != 1);
-}
-
-static const VMStateDescription vmstate_fdrive_media_changed = {
- .name = "fdrive/media_changed",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = fdrive_media_changed_needed,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(media_changed, FDrive),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static bool fdrive_media_rate_needed(void *opaque)
-{
- FDrive *drive = opaque;
-
- return drive->fdctrl->check_media_rate;
-}
-
-static const VMStateDescription vmstate_fdrive_media_rate = {
- .name = "fdrive/media_rate",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = fdrive_media_rate_needed,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(media_rate, FDrive),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static bool fdrive_perpendicular_needed(void *opaque)
-{
- FDrive *drive = opaque;
-
- return drive->perpendicular != 0;
-}
-
-static const VMStateDescription vmstate_fdrive_perpendicular = {
- .name = "fdrive/perpendicular",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = fdrive_perpendicular_needed,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(perpendicular, FDrive),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static int fdrive_post_load(void *opaque, int version_id)
-{
- fd_revalidate(opaque);
- return 0;
-}
-
-static const VMStateDescription vmstate_fdrive = {
- .name = "fdrive",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = fdrive_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(head, FDrive),
- VMSTATE_UINT8(track, FDrive),
- VMSTATE_UINT8(sect, FDrive),
- VMSTATE_END_OF_LIST()
- },
- .subsections = (const VMStateDescription*[]) {
- &vmstate_fdrive_media_changed,
- &vmstate_fdrive_media_rate,
- &vmstate_fdrive_perpendicular,
- NULL
- }
-};
-
-/*
- * Reconstructs the phase from register values according to the logic that was
- * implemented in qemu 2.3. This is the default value that is used if the phase
- * subsection is not present on migration.
- *
- * Don't change this function to reflect newer qemu versions, it is part of
- * the migration ABI.
- */
-static int reconstruct_phase(FDCtrl *fdctrl)
-{
- if (fdctrl->msr & FD_MSR_NONDMA) {
- return FD_PHASE_EXECUTION;
- } else if ((fdctrl->msr & FD_MSR_RQM) == 0) {
- /* qemu 2.3 disabled RQM only during DMA transfers */
- return FD_PHASE_EXECUTION;
- } else if (fdctrl->msr & FD_MSR_DIO) {
- return FD_PHASE_RESULT;
- } else {
- return FD_PHASE_COMMAND;
- }
-}
-
-static void fdc_pre_save(void *opaque)
-{
- FDCtrl *s = opaque;
-
- s->dor_vmstate = s->dor | GET_CUR_DRV(s);
-}
-
-static int fdc_pre_load(void *opaque)
-{
- FDCtrl *s = opaque;
- s->phase = FD_PHASE_RECONSTRUCT;
- return 0;
-}
-
-static int fdc_post_load(void *opaque, int version_id)
-{
- FDCtrl *s = opaque;
-
- SET_CUR_DRV(s, s->dor_vmstate & FD_DOR_SELMASK);
- s->dor = s->dor_vmstate & ~FD_DOR_SELMASK;
-
- if (s->phase == FD_PHASE_RECONSTRUCT) {
- s->phase = reconstruct_phase(s);
- }
-
- return 0;
-}
-
-static bool fdc_reset_sensei_needed(void *opaque)
-{
- FDCtrl *s = opaque;
-
- return s->reset_sensei != 0;
-}
-
-static const VMStateDescription vmstate_fdc_reset_sensei = {
- .name = "fdc/reset_sensei",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = fdc_reset_sensei_needed,
- .fields = (VMStateField[]) {
- VMSTATE_INT32(reset_sensei, FDCtrl),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static bool fdc_result_timer_needed(void *opaque)
-{
- FDCtrl *s = opaque;
-
- return timer_pending(s->result_timer);
-}
-
-static const VMStateDescription vmstate_fdc_result_timer = {
- .name = "fdc/result_timer",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = fdc_result_timer_needed,
- .fields = (VMStateField[]) {
- VMSTATE_TIMER_PTR(result_timer, FDCtrl),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static bool fdc_phase_needed(void *opaque)
-{
- FDCtrl *fdctrl = opaque;
-
- return reconstruct_phase(fdctrl) != fdctrl->phase;
-}
-
-static const VMStateDescription vmstate_fdc_phase = {
- .name = "fdc/phase",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = fdc_phase_needed,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(phase, FDCtrl),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_fdc = {
- .name = "fdc",
- .version_id = 2,
- .minimum_version_id = 2,
- .pre_save = fdc_pre_save,
- .pre_load = fdc_pre_load,
- .post_load = fdc_post_load,
- .fields = (VMStateField[]) {
- /* Controller State */
- VMSTATE_UINT8(sra, FDCtrl),
- VMSTATE_UINT8(srb, FDCtrl),
- VMSTATE_UINT8(dor_vmstate, FDCtrl),
- VMSTATE_UINT8(tdr, FDCtrl),
- VMSTATE_UINT8(dsr, FDCtrl),
- VMSTATE_UINT8(msr, FDCtrl),
- VMSTATE_UINT8(status0, FDCtrl),
- VMSTATE_UINT8(status1, FDCtrl),
- VMSTATE_UINT8(status2, FDCtrl),
- /* Command FIFO */
- VMSTATE_VARRAY_INT32(fifo, FDCtrl, fifo_size, 0, vmstate_info_uint8,
- uint8_t),
- VMSTATE_UINT32(data_pos, FDCtrl),
- VMSTATE_UINT32(data_len, FDCtrl),
- VMSTATE_UINT8(data_state, FDCtrl),
- VMSTATE_UINT8(data_dir, FDCtrl),
- VMSTATE_UINT8(eot, FDCtrl),
- /* States kept only to be returned back */
- VMSTATE_UINT8(timer0, FDCtrl),
- VMSTATE_UINT8(timer1, FDCtrl),
- VMSTATE_UINT8(precomp_trk, FDCtrl),
- VMSTATE_UINT8(config, FDCtrl),
- VMSTATE_UINT8(lock, FDCtrl),
- VMSTATE_UINT8(pwrd, FDCtrl),
- VMSTATE_UINT8_EQUAL(num_floppies, FDCtrl),
- VMSTATE_STRUCT_ARRAY(drives, FDCtrl, MAX_FD, 1,
- vmstate_fdrive, FDrive),
- VMSTATE_END_OF_LIST()
- },
- .subsections = (const VMStateDescription*[]) {
- &vmstate_fdc_reset_sensei,
- &vmstate_fdc_result_timer,
- &vmstate_fdc_phase,
- NULL
- }
-};
-
-static void fdctrl_external_reset_sysbus(DeviceState *d)
-{
- FDCtrlSysBus *sys = SYSBUS_FDC(d);
- FDCtrl *s = &sys->state;
-
- fdctrl_reset(s, 0);
-}
-
-static void fdctrl_external_reset_isa(DeviceState *d)
-{
- FDCtrlISABus *isa = ISA_FDC(d);
- FDCtrl *s = &isa->state;
-
- fdctrl_reset(s, 0);
-}
-
-static void fdctrl_handle_tc(void *opaque, int irq, int level)
-{
- //FDCtrl *s = opaque;
-
- if (level) {
- // XXX
- FLOPPY_DPRINTF("TC pulsed\n");
- }
-}
-
-/* Change IRQ state */
-static void fdctrl_reset_irq(FDCtrl *fdctrl)
-{
- fdctrl->status0 = 0;
- if (!(fdctrl->sra & FD_SRA_INTPEND))
- return;
- FLOPPY_DPRINTF("Reset interrupt\n");
- qemu_set_irq(fdctrl->irq, 0);
- fdctrl->sra &= ~FD_SRA_INTPEND;
-}
-
-static void fdctrl_raise_irq(FDCtrl *fdctrl)
-{
- if (!(fdctrl->sra & FD_SRA_INTPEND)) {
- qemu_set_irq(fdctrl->irq, 1);
- fdctrl->sra |= FD_SRA_INTPEND;
- }
-
- fdctrl->reset_sensei = 0;
- FLOPPY_DPRINTF("Set interrupt status to 0x%02x\n", fdctrl->status0);
-}
-
-/* Reset controller */
-static void fdctrl_reset(FDCtrl *fdctrl, int do_irq)
-{
- int i;
-
- FLOPPY_DPRINTF("reset controller\n");
- fdctrl_reset_irq(fdctrl);
- /* Initialise controller */
- fdctrl->sra = 0;
- fdctrl->srb = 0xc0;
- if (!fdctrl->drives[1].blk) {
- fdctrl->sra |= FD_SRA_nDRV2;
- }
- fdctrl->cur_drv = 0;
- fdctrl->dor = FD_DOR_nRESET;
- fdctrl->dor |= (fdctrl->dma_chann != -1) ? FD_DOR_DMAEN : 0;
- fdctrl->msr = FD_MSR_RQM;
- fdctrl->reset_sensei = 0;
- timer_del(fdctrl->result_timer);
- /* FIFO state */
- fdctrl->data_pos = 0;
- fdctrl->data_len = 0;
- fdctrl->data_state = 0;
- fdctrl->data_dir = FD_DIR_WRITE;
- for (i = 0; i < MAX_FD; i++)
- fd_recalibrate(&fdctrl->drives[i]);
- fdctrl_to_command_phase(fdctrl);
- if (do_irq) {
- fdctrl->status0 |= FD_SR0_RDYCHG;
- fdctrl_raise_irq(fdctrl);
- fdctrl->reset_sensei = FD_RESET_SENSEI_COUNT;
- }
-}
-
-static inline FDrive *drv0(FDCtrl *fdctrl)
-{
- return &fdctrl->drives[(fdctrl->tdr & FD_TDR_BOOTSEL) >> 2];
-}
-
-static inline FDrive *drv1(FDCtrl *fdctrl)
-{
- if ((fdctrl->tdr & FD_TDR_BOOTSEL) < (1 << 2))
- return &fdctrl->drives[1];
- else
- return &fdctrl->drives[0];
-}
-
-#if MAX_FD == 4
-static inline FDrive *drv2(FDCtrl *fdctrl)
-{
- if ((fdctrl->tdr & FD_TDR_BOOTSEL) < (2 << 2))
- return &fdctrl->drives[2];
- else
- return &fdctrl->drives[1];
-}
-
-static inline FDrive *drv3(FDCtrl *fdctrl)
-{
- if ((fdctrl->tdr & FD_TDR_BOOTSEL) < (3 << 2))
- return &fdctrl->drives[3];
- else
- return &fdctrl->drives[2];
-}
-#endif
-
-static FDrive *get_cur_drv(FDCtrl *fdctrl)
-{
- switch (fdctrl->cur_drv) {
- case 0: return drv0(fdctrl);
- case 1: return drv1(fdctrl);
-#if MAX_FD == 4
- case 2: return drv2(fdctrl);
- case 3: return drv3(fdctrl);
-#endif
- default: return NULL;
- }
-}
-
-/* Status A register : 0x00 (read-only) */
-static uint32_t fdctrl_read_statusA(FDCtrl *fdctrl)
-{
- uint32_t retval = fdctrl->sra;
-
- FLOPPY_DPRINTF("status register A: 0x%02x\n", retval);
-
- return retval;
-}
-
-/* Status B register : 0x01 (read-only) */
-static uint32_t fdctrl_read_statusB(FDCtrl *fdctrl)
-{
- uint32_t retval = fdctrl->srb;
-
- FLOPPY_DPRINTF("status register B: 0x%02x\n", retval);
-
- return retval;
-}
-
-/* Digital output register : 0x02 */
-static uint32_t fdctrl_read_dor(FDCtrl *fdctrl)
-{
- uint32_t retval = fdctrl->dor;
-
- /* Selected drive */
- retval |= fdctrl->cur_drv;
- FLOPPY_DPRINTF("digital output register: 0x%02x\n", retval);
-
- return retval;
-}
-
-static void fdctrl_write_dor(FDCtrl *fdctrl, uint32_t value)
-{
- FLOPPY_DPRINTF("digital output register set to 0x%02x\n", value);
-
- /* Motors */
- if (value & FD_DOR_MOTEN0)
- fdctrl->srb |= FD_SRB_MTR0;
- else
- fdctrl->srb &= ~FD_SRB_MTR0;
- if (value & FD_DOR_MOTEN1)
- fdctrl->srb |= FD_SRB_MTR1;
- else
- fdctrl->srb &= ~FD_SRB_MTR1;
-
- /* Drive */
- if (value & 1)
- fdctrl->srb |= FD_SRB_DR0;
- else
- fdctrl->srb &= ~FD_SRB_DR0;
-
- /* Reset */
- if (!(value & FD_DOR_nRESET)) {
- if (fdctrl->dor & FD_DOR_nRESET) {
- FLOPPY_DPRINTF("controller enter RESET state\n");
- }
- } else {
- if (!(fdctrl->dor & FD_DOR_nRESET)) {
- FLOPPY_DPRINTF("controller out of RESET state\n");
- fdctrl_reset(fdctrl, 1);
- fdctrl->dsr &= ~FD_DSR_PWRDOWN;
- }
- }
- /* Selected drive */
- fdctrl->cur_drv = value & FD_DOR_SELMASK;
-
- fdctrl->dor = value;
-}
-
-/* Tape drive register : 0x03 */
-static uint32_t fdctrl_read_tape(FDCtrl *fdctrl)
-{
- uint32_t retval = fdctrl->tdr;
-
- FLOPPY_DPRINTF("tape drive register: 0x%02x\n", retval);
-
- return retval;
-}
-
-static void fdctrl_write_tape(FDCtrl *fdctrl, uint32_t value)
-{
- /* Reset mode */
- if (!(fdctrl->dor & FD_DOR_nRESET)) {
- FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
- return;
- }
- FLOPPY_DPRINTF("tape drive register set to 0x%02x\n", value);
- /* Disk boot selection indicator */
- fdctrl->tdr = value & FD_TDR_BOOTSEL;
- /* Tape indicators: never allow */
-}
-
-/* Main status register : 0x04 (read) */
-static uint32_t fdctrl_read_main_status(FDCtrl *fdctrl)
-{
- uint32_t retval = fdctrl->msr;
-
- fdctrl->dsr &= ~FD_DSR_PWRDOWN;
- fdctrl->dor |= FD_DOR_nRESET;
-
- FLOPPY_DPRINTF("main status register: 0x%02x\n", retval);
-
- return retval;
-}
-
-/* Data select rate register : 0x04 (write) */
-static void fdctrl_write_rate(FDCtrl *fdctrl, uint32_t value)
-{
- /* Reset mode */
- if (!(fdctrl->dor & FD_DOR_nRESET)) {
- FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
- return;
- }
- FLOPPY_DPRINTF("select rate register set to 0x%02x\n", value);
- /* Reset: autoclear */
- if (value & FD_DSR_SWRESET) {
- fdctrl->dor &= ~FD_DOR_nRESET;
- fdctrl_reset(fdctrl, 1);
- fdctrl->dor |= FD_DOR_nRESET;
- }
- if (value & FD_DSR_PWRDOWN) {
- fdctrl_reset(fdctrl, 1);
- }
- fdctrl->dsr = value;
-}
-
-/* Configuration control register: 0x07 (write) */
-static void fdctrl_write_ccr(FDCtrl *fdctrl, uint32_t value)
-{
- /* Reset mode */
- if (!(fdctrl->dor & FD_DOR_nRESET)) {
- FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
- return;
- }
- FLOPPY_DPRINTF("configuration control register set to 0x%02x\n", value);
-
- /* Only the rate selection bits used in AT mode, and we
- * store those in the DSR.
- */
- fdctrl->dsr = (fdctrl->dsr & ~FD_DSR_DRATEMASK) |
- (value & FD_DSR_DRATEMASK);
-}
-
-static int fdctrl_media_changed(FDrive *drv)
-{
- return drv->media_changed;
-}
-
-/* Digital input register : 0x07 (read-only) */
-static uint32_t fdctrl_read_dir(FDCtrl *fdctrl)
-{
- uint32_t retval = 0;
-
- if (fdctrl_media_changed(get_cur_drv(fdctrl))) {
- retval |= FD_DIR_DSKCHG;
- }
- if (retval != 0) {
- FLOPPY_DPRINTF("Floppy digital input register: 0x%02x\n", retval);
- }
-
- return retval;
-}
-
-/* Clear the FIFO and update the state for receiving the next command */
-static void fdctrl_to_command_phase(FDCtrl *fdctrl)
-{
- fdctrl->phase = FD_PHASE_COMMAND;
- fdctrl->data_dir = FD_DIR_WRITE;
- fdctrl->data_pos = 0;
- fdctrl->data_len = 1; /* Accept command byte, adjust for params later */
- fdctrl->msr &= ~(FD_MSR_CMDBUSY | FD_MSR_DIO);
- fdctrl->msr |= FD_MSR_RQM;
-}
-
-/* Update the state to allow the guest to read out the command status.
- * @fifo_len is the number of result bytes to be read out. */
-static void fdctrl_to_result_phase(FDCtrl *fdctrl, int fifo_len)
-{
- fdctrl->phase = FD_PHASE_RESULT;
- fdctrl->data_dir = FD_DIR_READ;
- fdctrl->data_len = fifo_len;
- fdctrl->data_pos = 0;
- fdctrl->msr |= FD_MSR_CMDBUSY | FD_MSR_RQM | FD_MSR_DIO;
-}
-
-/* Set an error: unimplemented/unknown command */
-static void fdctrl_unimplemented(FDCtrl *fdctrl, int direction)
-{
- qemu_log_mask(LOG_UNIMP, "fdc: unimplemented command 0x%02x\n",
- fdctrl->fifo[0]);
- fdctrl->fifo[0] = FD_SR0_INVCMD;
- fdctrl_to_result_phase(fdctrl, 1);
-}
-
-/* Seek to next sector
- * returns 0 when end of track reached (for DBL_SIDES on head 1)
- * otherwise returns 1
- */
-static int fdctrl_seek_to_next_sect(FDCtrl *fdctrl, FDrive *cur_drv)
-{
- FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d)\n",
- cur_drv->head, cur_drv->track, cur_drv->sect,
- fd_sector(cur_drv));
- /* XXX: cur_drv->sect >= cur_drv->last_sect should be an
- error in fact */
- uint8_t new_head = cur_drv->head;
- uint8_t new_track = cur_drv->track;
- uint8_t new_sect = cur_drv->sect;
-
- int ret = 1;
-
- if (new_sect >= cur_drv->last_sect ||
- new_sect == fdctrl->eot) {
- new_sect = 1;
- if (FD_MULTI_TRACK(fdctrl->data_state)) {
- if (new_head == 0 &&
- (cur_drv->flags & FDISK_DBL_SIDES) != 0) {
- new_head = 1;
- } else {
- new_head = 0;
- new_track++;
- fdctrl->status0 |= FD_SR0_SEEK;
- if ((cur_drv->flags & FDISK_DBL_SIDES) == 0) {
- ret = 0;
- }
- }
- } else {
- fdctrl->status0 |= FD_SR0_SEEK;
- new_track++;
- ret = 0;
- }
- if (ret == 1) {
- FLOPPY_DPRINTF("seek to next track (%d %02x %02x => %d)\n",
- new_head, new_track, new_sect, fd_sector(cur_drv));
- }
- } else {
- new_sect++;
- }
- fd_seek(cur_drv, new_head, new_track, new_sect, 1);
- return ret;
-}
-
-/* Callback for transfer end (stop or abort) */
-static void fdctrl_stop_transfer(FDCtrl *fdctrl, uint8_t status0,
- uint8_t status1, uint8_t status2)
-{
- FDrive *cur_drv;
- cur_drv = get_cur_drv(fdctrl);
-
- fdctrl->status0 &= ~(FD_SR0_DS0 | FD_SR0_DS1 | FD_SR0_HEAD);
- fdctrl->status0 |= GET_CUR_DRV(fdctrl);
- if (cur_drv->head) {
- fdctrl->status0 |= FD_SR0_HEAD;
- }
- fdctrl->status0 |= status0;
-
- FLOPPY_DPRINTF("transfer status: %02x %02x %02x (%02x)\n",
- status0, status1, status2, fdctrl->status0);
- fdctrl->fifo[0] = fdctrl->status0;
- fdctrl->fifo[1] = status1;
- fdctrl->fifo[2] = status2;
- fdctrl->fifo[3] = cur_drv->track;
- fdctrl->fifo[4] = cur_drv->head;
- fdctrl->fifo[5] = cur_drv->sect;
- fdctrl->fifo[6] = FD_SECTOR_SC;
- fdctrl->data_dir = FD_DIR_READ;
- if (!(fdctrl->msr & FD_MSR_NONDMA)) {
- IsaDmaClass *k = ISADMA_GET_CLASS(fdctrl->dma);
- k->release_DREQ(fdctrl->dma, fdctrl->dma_chann);
- }
- fdctrl->msr |= FD_MSR_RQM | FD_MSR_DIO;
- fdctrl->msr &= ~FD_MSR_NONDMA;
-
- fdctrl_to_result_phase(fdctrl, 7);
- fdctrl_raise_irq(fdctrl);
-}
-
-/* Prepare a data transfer (either DMA or FIFO) */
-static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction)
-{
- FDrive *cur_drv;
- uint8_t kh, kt, ks;
-
- SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
- cur_drv = get_cur_drv(fdctrl);
- kt = fdctrl->fifo[2];
- kh = fdctrl->fifo[3];
- ks = fdctrl->fifo[4];
- FLOPPY_DPRINTF("Start transfer at %d %d %02x %02x (%d)\n",
- GET_CUR_DRV(fdctrl), kh, kt, ks,
- fd_sector_calc(kh, kt, ks, cur_drv->last_sect,
- NUM_SIDES(cur_drv)));
- switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & FD_CONFIG_EIS)) {
- case 2:
- /* sect too big */
- fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00);
- fdctrl->fifo[3] = kt;
- fdctrl->fifo[4] = kh;
- fdctrl->fifo[5] = ks;
- return;
- case 3:
- /* track too big */
- fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_EC, 0x00);
- fdctrl->fifo[3] = kt;
- fdctrl->fifo[4] = kh;
- fdctrl->fifo[5] = ks;
- return;
- case 4:
- /* No seek enabled */
- fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00);
- fdctrl->fifo[3] = kt;
- fdctrl->fifo[4] = kh;
- fdctrl->fifo[5] = ks;
- return;
- case 1:
- fdctrl->status0 |= FD_SR0_SEEK;
- break;
- default:
- break;
- }
-
- /* Check the data rate. If the programmed data rate does not match
- * the currently inserted medium, the operation has to fail. */
- if (fdctrl->check_media_rate &&
- (fdctrl->dsr & FD_DSR_DRATEMASK) != cur_drv->media_rate) {
- FLOPPY_DPRINTF("data rate mismatch (fdc=%d, media=%d)\n",
- fdctrl->dsr & FD_DSR_DRATEMASK, cur_drv->media_rate);
- fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_MA, 0x00);
- fdctrl->fifo[3] = kt;
- fdctrl->fifo[4] = kh;
- fdctrl->fifo[5] = ks;
- return;
- }
-
- /* Set the FIFO state */
- fdctrl->data_dir = direction;
- fdctrl->data_pos = 0;
- assert(fdctrl->msr & FD_MSR_CMDBUSY);
- if (fdctrl->fifo[0] & 0x80)
- fdctrl->data_state |= FD_STATE_MULTI;
- else
- fdctrl->data_state &= ~FD_STATE_MULTI;
- if (fdctrl->fifo[5] == 0) {
- fdctrl->data_len = fdctrl->fifo[8];
- } else {
- int tmp;
- fdctrl->data_len = 128 << (fdctrl->fifo[5] > 7 ? 7 : fdctrl->fifo[5]);
- tmp = (fdctrl->fifo[6] - ks + 1);
- if (fdctrl->fifo[0] & 0x80)
- tmp += fdctrl->fifo[6];
- fdctrl->data_len *= tmp;
- }
- fdctrl->eot = fdctrl->fifo[6];
- if (fdctrl->dor & FD_DOR_DMAEN) {
- IsaDmaTransferMode dma_mode;
- IsaDmaClass *k = ISADMA_GET_CLASS(fdctrl->dma);
- bool dma_mode_ok;
- /* DMA transfer are enabled. Check if DMA channel is well programmed */
- dma_mode = k->get_transfer_mode(fdctrl->dma, fdctrl->dma_chann);
- FLOPPY_DPRINTF("dma_mode=%d direction=%d (%d - %d)\n",
- dma_mode, direction,
- (128 << fdctrl->fifo[5]) *
- (cur_drv->last_sect - ks + 1), fdctrl->data_len);
- switch (direction) {
- case FD_DIR_SCANE:
- case FD_DIR_SCANL:
- case FD_DIR_SCANH:
- dma_mode_ok = (dma_mode == ISADMA_TRANSFER_VERIFY);
- break;
- case FD_DIR_WRITE:
- dma_mode_ok = (dma_mode == ISADMA_TRANSFER_WRITE);
- break;
- case FD_DIR_READ:
- dma_mode_ok = (dma_mode == ISADMA_TRANSFER_READ);
- break;
- case FD_DIR_VERIFY:
- dma_mode_ok = true;
- break;
- default:
- dma_mode_ok = false;
- break;
- }
- if (dma_mode_ok) {
- /* No access is allowed until DMA transfer has completed */
- fdctrl->msr &= ~FD_MSR_RQM;
- if (direction != FD_DIR_VERIFY) {
- /* Now, we just have to wait for the DMA controller to
- * recall us...
- */
- k->hold_DREQ(fdctrl->dma, fdctrl->dma_chann);
- k->schedule(fdctrl->dma);
- } else {
- /* Start transfer */
- fdctrl_transfer_handler(fdctrl, fdctrl->dma_chann, 0,
- fdctrl->data_len);
- }
- return;
- } else {
- FLOPPY_DPRINTF("bad dma_mode=%d direction=%d\n", dma_mode,
- direction);
- }
- }
- FLOPPY_DPRINTF("start non-DMA transfer\n");
- fdctrl->msr |= FD_MSR_NONDMA | FD_MSR_RQM;
- if (direction != FD_DIR_WRITE)
- fdctrl->msr |= FD_MSR_DIO;
- /* IO based transfer: calculate len */
- fdctrl_raise_irq(fdctrl);
-}
-
-/* Prepare a transfer of deleted data */
-static void fdctrl_start_transfer_del(FDCtrl *fdctrl, int direction)
-{
- qemu_log_mask(LOG_UNIMP, "fdctrl_start_transfer_del() unimplemented\n");
-
- /* We don't handle deleted data,
- * so we don't return *ANYTHING*
- */
- fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
-}
-
-/* handlers for DMA transfers */
-static int fdctrl_transfer_handler (void *opaque, int nchan,
- int dma_pos, int dma_len)
-{
- FDCtrl *fdctrl;
- FDrive *cur_drv;
- int len, start_pos, rel_pos;
- uint8_t status0 = 0x00, status1 = 0x00, status2 = 0x00;
- IsaDmaClass *k;
-
- fdctrl = opaque;
- if (fdctrl->msr & FD_MSR_RQM) {
- FLOPPY_DPRINTF("Not in DMA transfer mode !\n");
- return 0;
- }
- k = ISADMA_GET_CLASS(fdctrl->dma);
- cur_drv = get_cur_drv(fdctrl);
- if (fdctrl->data_dir == FD_DIR_SCANE || fdctrl->data_dir == FD_DIR_SCANL ||
- fdctrl->data_dir == FD_DIR_SCANH)
- status2 = FD_SR2_SNS;
- if (dma_len > fdctrl->data_len)
- dma_len = fdctrl->data_len;
- if (cur_drv->blk == NULL) {
- if (fdctrl->data_dir == FD_DIR_WRITE)
- fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
- else
- fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00);
- len = 0;
- goto transfer_error;
- }
- rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;
- for (start_pos = fdctrl->data_pos; fdctrl->data_pos < dma_len;) {
- len = dma_len - fdctrl->data_pos;
- if (len + rel_pos > FD_SECTOR_LEN)
- len = FD_SECTOR_LEN - rel_pos;
- FLOPPY_DPRINTF("copy %d bytes (%d %d %d) %d pos %d %02x "
- "(%d-0x%08x 0x%08x)\n", len, dma_len, fdctrl->data_pos,
- fdctrl->data_len, GET_CUR_DRV(fdctrl), cur_drv->head,
- cur_drv->track, cur_drv->sect, fd_sector(cur_drv),
- fd_sector(cur_drv) * FD_SECTOR_LEN);
- if (fdctrl->data_dir != FD_DIR_WRITE ||
- len < FD_SECTOR_LEN || rel_pos != 0) {
- /* READ & SCAN commands and realign to a sector for WRITE */
- if (blk_read(cur_drv->blk, fd_sector(cur_drv),
- fdctrl->fifo, 1) < 0) {
- FLOPPY_DPRINTF("Floppy: error getting sector %d\n",
- fd_sector(cur_drv));
- /* Sure, image size is too small... */
- memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
- }
- }
- switch (fdctrl->data_dir) {
- case FD_DIR_READ:
- /* READ commands */
- k->write_memory(fdctrl->dma, nchan, fdctrl->fifo + rel_pos,
- fdctrl->data_pos, len);
- break;
- case FD_DIR_WRITE:
- /* WRITE commands */
- if (cur_drv->ro) {
- /* Handle readonly medium early, no need to do DMA, touch the
- * LED or attempt any writes. A real floppy doesn't attempt
- * to write to readonly media either. */
- fdctrl_stop_transfer(fdctrl,
- FD_SR0_ABNTERM | FD_SR0_SEEK, FD_SR1_NW,
- 0x00);
- goto transfer_error;
- }
-
- k->read_memory(fdctrl->dma, nchan, fdctrl->fifo + rel_pos,
- fdctrl->data_pos, len);
- if (blk_write(cur_drv->blk, fd_sector(cur_drv),
- fdctrl->fifo, 1) < 0) {
- FLOPPY_DPRINTF("error writing sector %d\n",
- fd_sector(cur_drv));
- fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
- goto transfer_error;
- }
- break;
- case FD_DIR_VERIFY:
- /* VERIFY commands */
- break;
- default:
- /* SCAN commands */
- {
- uint8_t tmpbuf[FD_SECTOR_LEN];
- int ret;
- k->read_memory(fdctrl->dma, nchan, tmpbuf, fdctrl->data_pos,
- len);
- ret = memcmp(tmpbuf, fdctrl->fifo + rel_pos, len);
- if (ret == 0) {
- status2 = FD_SR2_SEH;
- goto end_transfer;
- }
- if ((ret < 0 && fdctrl->data_dir == FD_DIR_SCANL) ||
- (ret > 0 && fdctrl->data_dir == FD_DIR_SCANH)) {
- status2 = 0x00;
- goto end_transfer;
- }
- }
- break;
- }
- fdctrl->data_pos += len;
- rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;
- if (rel_pos == 0) {
- /* Seek to next sector */
- if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv))
- break;
- }
- }
- end_transfer:
- len = fdctrl->data_pos - start_pos;
- FLOPPY_DPRINTF("end transfer %d %d %d\n",
- fdctrl->data_pos, len, fdctrl->data_len);
- if (fdctrl->data_dir == FD_DIR_SCANE ||
- fdctrl->data_dir == FD_DIR_SCANL ||
- fdctrl->data_dir == FD_DIR_SCANH)
- status2 = FD_SR2_SEH;
- fdctrl->data_len -= len;
- fdctrl_stop_transfer(fdctrl, status0, status1, status2);
- transfer_error:
-
- return len;
-}
-
-/* Data register : 0x05 */
-static uint32_t fdctrl_read_data(FDCtrl *fdctrl)
-{
- FDrive *cur_drv;
- uint32_t retval = 0;
- uint32_t pos;
-
- cur_drv = get_cur_drv(fdctrl);
- fdctrl->dsr &= ~FD_DSR_PWRDOWN;
- if (!(fdctrl->msr & FD_MSR_RQM) || !(fdctrl->msr & FD_MSR_DIO)) {
- FLOPPY_DPRINTF("error: controller not ready for reading\n");
- return 0;
- }
-
- /* If data_len spans multiple sectors, the current position in the FIFO
- * wraps around while fdctrl->data_pos is the real position in the whole
- * request. */
- pos = fdctrl->data_pos;
- pos %= FD_SECTOR_LEN;
-
- switch (fdctrl->phase) {
- case FD_PHASE_EXECUTION:
- assert(fdctrl->msr & FD_MSR_NONDMA);
- if (pos == 0) {
- if (fdctrl->data_pos != 0)
- if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv)) {
- FLOPPY_DPRINTF("error seeking to next sector %d\n",
- fd_sector(cur_drv));
- return 0;
- }
- if (blk_read(cur_drv->blk, fd_sector(cur_drv), fdctrl->fifo, 1)
- < 0) {
- FLOPPY_DPRINTF("error getting sector %d\n",
- fd_sector(cur_drv));
- /* Sure, image size is too small... */
- memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
- }
- }
-
- if (++fdctrl->data_pos == fdctrl->data_len) {
- fdctrl->msr &= ~FD_MSR_RQM;
- fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
- }
- break;
-
- case FD_PHASE_RESULT:
- assert(!(fdctrl->msr & FD_MSR_NONDMA));
- if (++fdctrl->data_pos == fdctrl->data_len) {
- fdctrl->msr &= ~FD_MSR_RQM;
- fdctrl_to_command_phase(fdctrl);
- fdctrl_reset_irq(fdctrl);
- }
- break;
-
- case FD_PHASE_COMMAND:
- default:
- abort();
- }
-
- retval = fdctrl->fifo[pos];
- FLOPPY_DPRINTF("data register: 0x%02x\n", retval);
-
- return retval;
-}
-
-static void fdctrl_format_sector(FDCtrl *fdctrl)
-{
- FDrive *cur_drv;
- uint8_t kh, kt, ks;
-
- SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
- cur_drv = get_cur_drv(fdctrl);
- kt = fdctrl->fifo[6];
- kh = fdctrl->fifo[7];
- ks = fdctrl->fifo[8];
- FLOPPY_DPRINTF("format sector at %d %d %02x %02x (%d)\n",
- GET_CUR_DRV(fdctrl), kh, kt, ks,
- fd_sector_calc(kh, kt, ks, cur_drv->last_sect,
- NUM_SIDES(cur_drv)));
- switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & FD_CONFIG_EIS)) {
- case 2:
- /* sect too big */
- fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00);
- fdctrl->fifo[3] = kt;
- fdctrl->fifo[4] = kh;
- fdctrl->fifo[5] = ks;
- return;
- case 3:
- /* track too big */
- fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_EC, 0x00);
- fdctrl->fifo[3] = kt;
- fdctrl->fifo[4] = kh;
- fdctrl->fifo[5] = ks;
- return;
- case 4:
- /* No seek enabled */
- fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00);
- fdctrl->fifo[3] = kt;
- fdctrl->fifo[4] = kh;
- fdctrl->fifo[5] = ks;
- return;
- case 1:
- fdctrl->status0 |= FD_SR0_SEEK;
- break;
- default:
- break;
- }
- memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
- if (cur_drv->blk == NULL ||
- blk_write(cur_drv->blk, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) {
- FLOPPY_DPRINTF("error formatting sector %d\n", fd_sector(cur_drv));
- fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
- } else {
- if (cur_drv->sect == cur_drv->last_sect) {
- fdctrl->data_state &= ~FD_STATE_FORMAT;
- /* Last sector done */
- fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
- } else {
- /* More to do */
- fdctrl->data_pos = 0;
- fdctrl->data_len = 4;
- }
- }
-}
-
-static void fdctrl_handle_lock(FDCtrl *fdctrl, int direction)
-{
- fdctrl->lock = (fdctrl->fifo[0] & 0x80) ? 1 : 0;
- fdctrl->fifo[0] = fdctrl->lock << 4;
- fdctrl_to_result_phase(fdctrl, 1);
-}
-
-static void fdctrl_handle_dumpreg(FDCtrl *fdctrl, int direction)
-{
- FDrive *cur_drv = get_cur_drv(fdctrl);
-
- /* Drives position */
- fdctrl->fifo[0] = drv0(fdctrl)->track;
- fdctrl->fifo[1] = drv1(fdctrl)->track;
-#if MAX_FD == 4
- fdctrl->fifo[2] = drv2(fdctrl)->track;
- fdctrl->fifo[3] = drv3(fdctrl)->track;
-#else
- fdctrl->fifo[2] = 0;
- fdctrl->fifo[3] = 0;
-#endif
- /* timers */
- fdctrl->fifo[4] = fdctrl->timer0;
- fdctrl->fifo[5] = (fdctrl->timer1 << 1) | (fdctrl->dor & FD_DOR_DMAEN ? 1 : 0);
- fdctrl->fifo[6] = cur_drv->last_sect;
- fdctrl->fifo[7] = (fdctrl->lock << 7) |
- (cur_drv->perpendicular << 2);
- fdctrl->fifo[8] = fdctrl->config;
- fdctrl->fifo[9] = fdctrl->precomp_trk;
- fdctrl_to_result_phase(fdctrl, 10);
-}
-
-static void fdctrl_handle_version(FDCtrl *fdctrl, int direction)
-{
- /* Controller's version */
- fdctrl->fifo[0] = fdctrl->version;
- fdctrl_to_result_phase(fdctrl, 1);
-}
-
-static void fdctrl_handle_partid(FDCtrl *fdctrl, int direction)
-{
- fdctrl->fifo[0] = 0x41; /* Stepping 1 */
- fdctrl_to_result_phase(fdctrl, 1);
-}
-
-static void fdctrl_handle_restore(FDCtrl *fdctrl, int direction)
-{
- FDrive *cur_drv = get_cur_drv(fdctrl);
-
- /* Drives position */
- drv0(fdctrl)->track = fdctrl->fifo[3];
- drv1(fdctrl)->track = fdctrl->fifo[4];
-#if MAX_FD == 4
- drv2(fdctrl)->track = fdctrl->fifo[5];
- drv3(fdctrl)->track = fdctrl->fifo[6];
-#endif
- /* timers */
- fdctrl->timer0 = fdctrl->fifo[7];
- fdctrl->timer1 = fdctrl->fifo[8];
- cur_drv->last_sect = fdctrl->fifo[9];
- fdctrl->lock = fdctrl->fifo[10] >> 7;
- cur_drv->perpendicular = (fdctrl->fifo[10] >> 2) & 0xF;
- fdctrl->config = fdctrl->fifo[11];
- fdctrl->precomp_trk = fdctrl->fifo[12];
- fdctrl->pwrd = fdctrl->fifo[13];
- fdctrl_to_command_phase(fdctrl);
-}
-
-static void fdctrl_handle_save(FDCtrl *fdctrl, int direction)
-{
- FDrive *cur_drv = get_cur_drv(fdctrl);
-
- fdctrl->fifo[0] = 0;
- fdctrl->fifo[1] = 0;
- /* Drives position */
- fdctrl->fifo[2] = drv0(fdctrl)->track;
- fdctrl->fifo[3] = drv1(fdctrl)->track;
-#if MAX_FD == 4
- fdctrl->fifo[4] = drv2(fdctrl)->track;
- fdctrl->fifo[5] = drv3(fdctrl)->track;
-#else
- fdctrl->fifo[4] = 0;
- fdctrl->fifo[5] = 0;
-#endif
- /* timers */
- fdctrl->fifo[6] = fdctrl->timer0;
- fdctrl->fifo[7] = fdctrl->timer1;
- fdctrl->fifo[8] = cur_drv->last_sect;
- fdctrl->fifo[9] = (fdctrl->lock << 7) |
- (cur_drv->perpendicular << 2);
- fdctrl->fifo[10] = fdctrl->config;
- fdctrl->fifo[11] = fdctrl->precomp_trk;
- fdctrl->fifo[12] = fdctrl->pwrd;
- fdctrl->fifo[13] = 0;
- fdctrl->fifo[14] = 0;
- fdctrl_to_result_phase(fdctrl, 15);
-}
-
-static void fdctrl_handle_readid(FDCtrl *fdctrl, int direction)
-{
- FDrive *cur_drv = get_cur_drv(fdctrl);
-
- cur_drv->head = (fdctrl->fifo[1] >> 2) & 1;
- timer_mod(fdctrl->result_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- (NANOSECONDS_PER_SECOND / 50));
-}
-
-static void fdctrl_handle_format_track(FDCtrl *fdctrl, int direction)
-{
- FDrive *cur_drv;
-
- SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
- cur_drv = get_cur_drv(fdctrl);
- fdctrl->data_state |= FD_STATE_FORMAT;
- if (fdctrl->fifo[0] & 0x80)
- fdctrl->data_state |= FD_STATE_MULTI;
- else
- fdctrl->data_state &= ~FD_STATE_MULTI;
- cur_drv->bps =
- fdctrl->fifo[2] > 7 ? 16384 : 128 << fdctrl->fifo[2];
-#if 0
- cur_drv->last_sect =
- cur_drv->flags & FDISK_DBL_SIDES ? fdctrl->fifo[3] :
- fdctrl->fifo[3] / 2;
-#else
- cur_drv->last_sect = fdctrl->fifo[3];
-#endif
- /* TODO: implement format using DMA expected by the Bochs BIOS
- * and Linux fdformat (read 3 bytes per sector via DMA and fill
- * the sector with the specified fill byte
- */
- fdctrl->data_state &= ~FD_STATE_FORMAT;
- fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
-}
-
-static void fdctrl_handle_specify(FDCtrl *fdctrl, int direction)
-{
- fdctrl->timer0 = (fdctrl->fifo[1] >> 4) & 0xF;
- fdctrl->timer1 = fdctrl->fifo[2] >> 1;
- if (fdctrl->fifo[2] & 1)
- fdctrl->dor &= ~FD_DOR_DMAEN;
- else
- fdctrl->dor |= FD_DOR_DMAEN;
- /* No result back */
- fdctrl_to_command_phase(fdctrl);
-}
-
-static void fdctrl_handle_sense_drive_status(FDCtrl *fdctrl, int direction)
-{
- FDrive *cur_drv;
-
- SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
- cur_drv = get_cur_drv(fdctrl);
- cur_drv->head = (fdctrl->fifo[1] >> 2) & 1;
- /* 1 Byte status back */
- fdctrl->fifo[0] = (cur_drv->ro << 6) |
- (cur_drv->track == 0 ? 0x10 : 0x00) |
- (cur_drv->head << 2) |
- GET_CUR_DRV(fdctrl) |
- 0x28;
- fdctrl_to_result_phase(fdctrl, 1);
-}
-
-static void fdctrl_handle_recalibrate(FDCtrl *fdctrl, int direction)
-{
- FDrive *cur_drv;
-
- SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
- cur_drv = get_cur_drv(fdctrl);
- fd_recalibrate(cur_drv);
- fdctrl_to_command_phase(fdctrl);
- /* Raise Interrupt */
- fdctrl->status0 |= FD_SR0_SEEK;
- fdctrl_raise_irq(fdctrl);
-}
-
-static void fdctrl_handle_sense_interrupt_status(FDCtrl *fdctrl, int direction)
-{
- FDrive *cur_drv = get_cur_drv(fdctrl);
-
- if (fdctrl->reset_sensei > 0) {
- fdctrl->fifo[0] =
- FD_SR0_RDYCHG + FD_RESET_SENSEI_COUNT - fdctrl->reset_sensei;
- fdctrl->reset_sensei--;
- } else if (!(fdctrl->sra & FD_SRA_INTPEND)) {
- fdctrl->fifo[0] = FD_SR0_INVCMD;
- fdctrl_to_result_phase(fdctrl, 1);
- return;
- } else {
- fdctrl->fifo[0] =
- (fdctrl->status0 & ~(FD_SR0_HEAD | FD_SR0_DS1 | FD_SR0_DS0))
- | GET_CUR_DRV(fdctrl);
- }
-
- fdctrl->fifo[1] = cur_drv->track;
- fdctrl_to_result_phase(fdctrl, 2);
- fdctrl_reset_irq(fdctrl);
- fdctrl->status0 = FD_SR0_RDYCHG;
-}
-
-static void fdctrl_handle_seek(FDCtrl *fdctrl, int direction)
-{
- FDrive *cur_drv;
-
- SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
- cur_drv = get_cur_drv(fdctrl);
- fdctrl_to_command_phase(fdctrl);
- /* The seek command just sends step pulses to the drive and doesn't care if
- * there is a medium inserted of if it's banging the head against the drive.
- */
- fd_seek(cur_drv, cur_drv->head, fdctrl->fifo[2], cur_drv->sect, 1);
- /* Raise Interrupt */
- fdctrl->status0 |= FD_SR0_SEEK;
- fdctrl_raise_irq(fdctrl);
-}
-
-static void fdctrl_handle_perpendicular_mode(FDCtrl *fdctrl, int direction)
-{
- FDrive *cur_drv = get_cur_drv(fdctrl);
-
- if (fdctrl->fifo[1] & 0x80)
- cur_drv->perpendicular = fdctrl->fifo[1] & 0x7;
- /* No result back */
- fdctrl_to_command_phase(fdctrl);
-}
-
-static void fdctrl_handle_configure(FDCtrl *fdctrl, int direction)
-{
- fdctrl->config = fdctrl->fifo[2];
- fdctrl->precomp_trk = fdctrl->fifo[3];
- /* No result back */
- fdctrl_to_command_phase(fdctrl);
-}
-
-static void fdctrl_handle_powerdown_mode(FDCtrl *fdctrl, int direction)
-{
- fdctrl->pwrd = fdctrl->fifo[1];
- fdctrl->fifo[0] = fdctrl->fifo[1];
- fdctrl_to_result_phase(fdctrl, 1);
-}
-
-static void fdctrl_handle_option(FDCtrl *fdctrl, int direction)
-{
- /* No result back */
- fdctrl_to_command_phase(fdctrl);
-}
-
-static void fdctrl_handle_drive_specification_command(FDCtrl *fdctrl, int direction)
-{
- FDrive *cur_drv = get_cur_drv(fdctrl);
- uint32_t pos;
-
- pos = fdctrl->data_pos - 1;
- pos %= FD_SECTOR_LEN;
- if (fdctrl->fifo[pos] & 0x80) {
- /* Command parameters done */
- if (fdctrl->fifo[pos] & 0x40) {
- fdctrl->fifo[0] = fdctrl->fifo[1];
- fdctrl->fifo[2] = 0;
- fdctrl->fifo[3] = 0;
- fdctrl_to_result_phase(fdctrl, 4);
- } else {
- fdctrl_to_command_phase(fdctrl);
- }
- } else if (fdctrl->data_len > 7) {
- /* ERROR */
- fdctrl->fifo[0] = 0x80 |
- (cur_drv->head << 2) | GET_CUR_DRV(fdctrl);
- fdctrl_to_result_phase(fdctrl, 1);
- }
-}
-
-static void fdctrl_handle_relative_seek_in(FDCtrl *fdctrl, int direction)
-{
- FDrive *cur_drv;
-
- SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
- cur_drv = get_cur_drv(fdctrl);
- if (fdctrl->fifo[2] + cur_drv->track >= cur_drv->max_track) {
- fd_seek(cur_drv, cur_drv->head, cur_drv->max_track - 1,
- cur_drv->sect, 1);
- } else {
- fd_seek(cur_drv, cur_drv->head,
- cur_drv->track + fdctrl->fifo[2], cur_drv->sect, 1);
- }
- fdctrl_to_command_phase(fdctrl);
- /* Raise Interrupt */
- fdctrl->status0 |= FD_SR0_SEEK;
- fdctrl_raise_irq(fdctrl);
-}
-
-static void fdctrl_handle_relative_seek_out(FDCtrl *fdctrl, int direction)
-{
- FDrive *cur_drv;
-
- SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
- cur_drv = get_cur_drv(fdctrl);
- if (fdctrl->fifo[2] > cur_drv->track) {
- fd_seek(cur_drv, cur_drv->head, 0, cur_drv->sect, 1);
- } else {
- fd_seek(cur_drv, cur_drv->head,
- cur_drv->track - fdctrl->fifo[2], cur_drv->sect, 1);
- }
- fdctrl_to_command_phase(fdctrl);
- /* Raise Interrupt */
- fdctrl->status0 |= FD_SR0_SEEK;
- fdctrl_raise_irq(fdctrl);
-}
-
-/*
- * Handlers for the execution phase of each command
- */
-typedef struct FDCtrlCommand {
- uint8_t value;
- uint8_t mask;
- const char* name;
- int parameters;
- void (*handler)(FDCtrl *fdctrl, int direction);
- int direction;
-} FDCtrlCommand;
-
-static const FDCtrlCommand handlers[] = {
- { FD_CMD_READ, 0x1f, "READ", 8, fdctrl_start_transfer, FD_DIR_READ },
- { FD_CMD_WRITE, 0x3f, "WRITE", 8, fdctrl_start_transfer, FD_DIR_WRITE },
- { FD_CMD_SEEK, 0xff, "SEEK", 2, fdctrl_handle_seek },
- { FD_CMD_SENSE_INTERRUPT_STATUS, 0xff, "SENSE INTERRUPT STATUS", 0, fdctrl_handle_sense_interrupt_status },
- { FD_CMD_RECALIBRATE, 0xff, "RECALIBRATE", 1, fdctrl_handle_recalibrate },
- { FD_CMD_FORMAT_TRACK, 0xbf, "FORMAT TRACK", 5, fdctrl_handle_format_track },
- { FD_CMD_READ_TRACK, 0xbf, "READ TRACK", 8, fdctrl_start_transfer, FD_DIR_READ },
- { FD_CMD_RESTORE, 0xff, "RESTORE", 17, fdctrl_handle_restore }, /* part of READ DELETED DATA */
- { FD_CMD_SAVE, 0xff, "SAVE", 0, fdctrl_handle_save }, /* part of READ DELETED DATA */
- { FD_CMD_READ_DELETED, 0x1f, "READ DELETED DATA", 8, fdctrl_start_transfer_del, FD_DIR_READ },
- { FD_CMD_SCAN_EQUAL, 0x1f, "SCAN EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANE },
- { FD_CMD_VERIFY, 0x1f, "VERIFY", 8, fdctrl_start_transfer, FD_DIR_VERIFY },
- { FD_CMD_SCAN_LOW_OR_EQUAL, 0x1f, "SCAN LOW OR EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANL },
- { FD_CMD_SCAN_HIGH_OR_EQUAL, 0x1f, "SCAN HIGH OR EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANH },
- { FD_CMD_WRITE_DELETED, 0x3f, "WRITE DELETED DATA", 8, fdctrl_start_transfer_del, FD_DIR_WRITE },
- { FD_CMD_READ_ID, 0xbf, "READ ID", 1, fdctrl_handle_readid },
- { FD_CMD_SPECIFY, 0xff, "SPECIFY", 2, fdctrl_handle_specify },
- { FD_CMD_SENSE_DRIVE_STATUS, 0xff, "SENSE DRIVE STATUS", 1, fdctrl_handle_sense_drive_status },
- { FD_CMD_PERPENDICULAR_MODE, 0xff, "PERPENDICULAR MODE", 1, fdctrl_handle_perpendicular_mode },
- { FD_CMD_CONFIGURE, 0xff, "CONFIGURE", 3, fdctrl_handle_configure },
- { FD_CMD_POWERDOWN_MODE, 0xff, "POWERDOWN MODE", 2, fdctrl_handle_powerdown_mode },
- { FD_CMD_OPTION, 0xff, "OPTION", 1, fdctrl_handle_option },
- { FD_CMD_DRIVE_SPECIFICATION_COMMAND, 0xff, "DRIVE SPECIFICATION COMMAND", 5, fdctrl_handle_drive_specification_command },
- { FD_CMD_RELATIVE_SEEK_OUT, 0xff, "RELATIVE SEEK OUT", 2, fdctrl_handle_relative_seek_out },
- { FD_CMD_FORMAT_AND_WRITE, 0xff, "FORMAT AND WRITE", 10, fdctrl_unimplemented },
- { FD_CMD_RELATIVE_SEEK_IN, 0xff, "RELATIVE SEEK IN", 2, fdctrl_handle_relative_seek_in },
- { FD_CMD_LOCK, 0x7f, "LOCK", 0, fdctrl_handle_lock },
- { FD_CMD_DUMPREG, 0xff, "DUMPREG", 0, fdctrl_handle_dumpreg },
- { FD_CMD_VERSION, 0xff, "VERSION", 0, fdctrl_handle_version },
- { FD_CMD_PART_ID, 0xff, "PART ID", 0, fdctrl_handle_partid },
- { FD_CMD_WRITE, 0x1f, "WRITE (BeOS)", 8, fdctrl_start_transfer, FD_DIR_WRITE }, /* not in specification ; BeOS 4.5 bug */
- { 0, 0, "unknown", 0, fdctrl_unimplemented }, /* default handler */
-};
-/* Associate command to an index in the 'handlers' array */
-static uint8_t command_to_handler[256];
-
-static const FDCtrlCommand *get_command(uint8_t cmd)
-{
- int idx;
-
- idx = command_to_handler[cmd];
- FLOPPY_DPRINTF("%s command\n", handlers[idx].name);
- return &handlers[idx];
-}
-
-static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value)
-{
- FDrive *cur_drv;
- const FDCtrlCommand *cmd;
- uint32_t pos;
-
- /* Reset mode */
- if (!(fdctrl->dor & FD_DOR_nRESET)) {
- FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
- return;
- }
- if (!(fdctrl->msr & FD_MSR_RQM) || (fdctrl->msr & FD_MSR_DIO)) {
- FLOPPY_DPRINTF("error: controller not ready for writing\n");
- return;
- }
- fdctrl->dsr &= ~FD_DSR_PWRDOWN;
-
- FLOPPY_DPRINTF("%s: %02x\n", __func__, value);
-
- /* If data_len spans multiple sectors, the current position in the FIFO
- * wraps around while fdctrl->data_pos is the real position in the whole
- * request. */
- pos = fdctrl->data_pos++;
- pos %= FD_SECTOR_LEN;
- fdctrl->fifo[pos] = value;
-
- if (fdctrl->data_pos == fdctrl->data_len) {
- fdctrl->msr &= ~FD_MSR_RQM;
- }
-
- switch (fdctrl->phase) {
- case FD_PHASE_EXECUTION:
- /* For DMA requests, RQM should be cleared during execution phase, so
- * we would have errored out above. */
- assert(fdctrl->msr & FD_MSR_NONDMA);
-
- /* FIFO data write */
- if (pos == FD_SECTOR_LEN - 1 ||
- fdctrl->data_pos == fdctrl->data_len) {
- cur_drv = get_cur_drv(fdctrl);
- if (blk_write(cur_drv->blk, fd_sector(cur_drv), fdctrl->fifo, 1)
- < 0) {
- FLOPPY_DPRINTF("error writing sector %d\n",
- fd_sector(cur_drv));
- break;
- }
- if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv)) {
- FLOPPY_DPRINTF("error seeking to next sector %d\n",
- fd_sector(cur_drv));
- break;
- }
- }
-
- /* Switch to result phase when done with the transfer */
- if (fdctrl->data_pos == fdctrl->data_len) {
- fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
- }
- break;
-
- case FD_PHASE_COMMAND:
- assert(!(fdctrl->msr & FD_MSR_NONDMA));
- assert(fdctrl->data_pos < FD_SECTOR_LEN);
-
- if (pos == 0) {
- /* The first byte specifies the command. Now we start reading
- * as many parameters as this command requires. */
- cmd = get_command(value);
- fdctrl->data_len = cmd->parameters + 1;
- if (cmd->parameters) {
- fdctrl->msr |= FD_MSR_RQM;
- }
- fdctrl->msr |= FD_MSR_CMDBUSY;
- }
-
- if (fdctrl->data_pos == fdctrl->data_len) {
- /* We have all parameters now, execute the command */
- fdctrl->phase = FD_PHASE_EXECUTION;
-
- if (fdctrl->data_state & FD_STATE_FORMAT) {
- fdctrl_format_sector(fdctrl);
- break;
- }
-
- cmd = get_command(fdctrl->fifo[0]);
- FLOPPY_DPRINTF("Calling handler for '%s'\n", cmd->name);
- cmd->handler(fdctrl, cmd->direction);
- }
- break;
-
- case FD_PHASE_RESULT:
- default:
- abort();
- }
-}
-
-static void fdctrl_result_timer(void *opaque)
-{
- FDCtrl *fdctrl = opaque;
- FDrive *cur_drv = get_cur_drv(fdctrl);
-
- /* Pretend we are spinning.
- * This is needed for Coherent, which uses READ ID to check for
- * sector interleaving.
- */
- if (cur_drv->last_sect != 0) {
- cur_drv->sect = (cur_drv->sect % cur_drv->last_sect) + 1;
- }
- /* READ_ID can't automatically succeed! */
- if (fdctrl->check_media_rate &&
- (fdctrl->dsr & FD_DSR_DRATEMASK) != cur_drv->media_rate) {
- FLOPPY_DPRINTF("read id rate mismatch (fdc=%d, media=%d)\n",
- fdctrl->dsr & FD_DSR_DRATEMASK, cur_drv->media_rate);
- fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_MA, 0x00);
- } else {
- fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
- }
-}
-
-static void fdctrl_change_cb(void *opaque, bool load)
-{
- FDrive *drive = opaque;
-
- drive->media_changed = 1;
- drive->media_validated = false;
- fd_revalidate(drive);
-}
-
-static const BlockDevOps fdctrl_block_ops = {
- .change_media_cb = fdctrl_change_cb,
-};
-
-/* Init functions */
-static void fdctrl_connect_drives(FDCtrl *fdctrl, Error **errp)
-{
- unsigned int i;
- FDrive *drive;
-
- for (i = 0; i < MAX_FD; i++) {
- drive = &fdctrl->drives[i];
- drive->fdctrl = fdctrl;
-
- if (drive->blk) {
- if (blk_get_on_error(drive->blk, 0) != BLOCKDEV_ON_ERROR_ENOSPC) {
- error_setg(errp, "fdc doesn't support drive option werror");
- return;
- }
- if (blk_get_on_error(drive->blk, 1) != BLOCKDEV_ON_ERROR_REPORT) {
- error_setg(errp, "fdc doesn't support drive option rerror");
- return;
- }
- }
-
- fd_init(drive);
- if (drive->blk) {
- blk_set_dev_ops(drive->blk, &fdctrl_block_ops, drive);
- pick_drive_type(drive);
- }
- fd_revalidate(drive);
- }
-}
-
-ISADevice *fdctrl_init_isa(ISABus *bus, DriveInfo **fds)
-{
- DeviceState *dev;
- ISADevice *isadev;
-
- isadev = isa_try_create(bus, TYPE_ISA_FDC);
- if (!isadev) {
- return NULL;
- }
- dev = DEVICE(isadev);
-
- if (fds[0]) {
- qdev_prop_set_drive(dev, "driveA", blk_by_legacy_dinfo(fds[0]),
- &error_fatal);
- }
- if (fds[1]) {
- qdev_prop_set_drive(dev, "driveB", blk_by_legacy_dinfo(fds[1]),
- &error_fatal);
- }
- qdev_init_nofail(dev);
-
- return isadev;
-}
-
-void fdctrl_init_sysbus(qemu_irq irq, int dma_chann,
- hwaddr mmio_base, DriveInfo **fds)
-{
- FDCtrl *fdctrl;
- DeviceState *dev;
- SysBusDevice *sbd;
- FDCtrlSysBus *sys;
-
- dev = qdev_create(NULL, "sysbus-fdc");
- sys = SYSBUS_FDC(dev);
- fdctrl = &sys->state;
- fdctrl->dma_chann = dma_chann; /* FIXME */
- if (fds[0]) {
- qdev_prop_set_drive(dev, "driveA", blk_by_legacy_dinfo(fds[0]),
- &error_fatal);
- }
- if (fds[1]) {
- qdev_prop_set_drive(dev, "driveB", blk_by_legacy_dinfo(fds[1]),
- &error_fatal);
- }
- qdev_init_nofail(dev);
- sbd = SYS_BUS_DEVICE(dev);
- sysbus_connect_irq(sbd, 0, irq);
- sysbus_mmio_map(sbd, 0, mmio_base);
-}
-
-void sun4m_fdctrl_init(qemu_irq irq, hwaddr io_base,
- DriveInfo **fds, qemu_irq *fdc_tc)
-{
- DeviceState *dev;
- FDCtrlSysBus *sys;
-
- dev = qdev_create(NULL, "SUNW,fdtwo");
- if (fds[0]) {
- qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(fds[0]),
- &error_fatal);
- }
- qdev_init_nofail(dev);
- sys = SYSBUS_FDC(dev);
- sysbus_connect_irq(SYS_BUS_DEVICE(sys), 0, irq);
- sysbus_mmio_map(SYS_BUS_DEVICE(sys), 0, io_base);
- *fdc_tc = qdev_get_gpio_in(dev, 0);
-}
-
-static void fdctrl_realize_common(FDCtrl *fdctrl, Error **errp)
-{
- int i, j;
- static int command_tables_inited = 0;
-
- if (fdctrl->fallback == FLOPPY_DRIVE_TYPE_AUTO) {
- error_setg(errp, "Cannot choose a fallback FDrive type of 'auto'");
- }
-
- /* Fill 'command_to_handler' lookup table */
- if (!command_tables_inited) {
- command_tables_inited = 1;
- for (i = ARRAY_SIZE(handlers) - 1; i >= 0; i--) {
- for (j = 0; j < sizeof(command_to_handler); j++) {
- if ((j & handlers[i].mask) == handlers[i].value) {
- command_to_handler[j] = i;
- }
- }
- }
- }
-
- FLOPPY_DPRINTF("init controller\n");
- fdctrl->fifo = qemu_memalign(512, FD_SECTOR_LEN);
- fdctrl->fifo_size = 512;
- fdctrl->result_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
- fdctrl_result_timer, fdctrl);
-
- fdctrl->version = 0x90; /* Intel 82078 controller */
- fdctrl->config = FD_CONFIG_EIS | FD_CONFIG_EFIFO; /* Implicit seek, polling & FIFO enabled */
- fdctrl->num_floppies = MAX_FD;
-
- if (fdctrl->dma_chann != -1) {
- IsaDmaClass *k;
- assert(fdctrl->dma);
- k = ISADMA_GET_CLASS(fdctrl->dma);
- k->register_channel(fdctrl->dma, fdctrl->dma_chann,
- &fdctrl_transfer_handler, fdctrl);
- }
- fdctrl_connect_drives(fdctrl, errp);
-}
-
-static const MemoryRegionPortio fdc_portio_list[] = {
- { 1, 5, 1, .read = fdctrl_read, .write = fdctrl_write },
- { 7, 1, 1, .read = fdctrl_read, .write = fdctrl_write },
- PORTIO_END_OF_LIST(),
-};
-
-static void isabus_fdc_realize(DeviceState *dev, Error **errp)
-{
- ISADevice *isadev = ISA_DEVICE(dev);
- FDCtrlISABus *isa = ISA_FDC(dev);
- FDCtrl *fdctrl = &isa->state;
- Error *err = NULL;
-
- isa_register_portio_list(isadev, isa->iobase, fdc_portio_list, fdctrl,
- "fdc");
-
- isa_init_irq(isadev, &fdctrl->irq, isa->irq);
- fdctrl->dma_chann = isa->dma;
- if (fdctrl->dma_chann != -1) {
- fdctrl->dma = isa_get_dma(isa_bus_from_device(isadev), isa->dma);
- assert(fdctrl->dma);
- }
-
- qdev_set_legacy_instance_id(dev, isa->iobase, 2);
- fdctrl_realize_common(fdctrl, &err);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
-}
-
-static void sysbus_fdc_initfn(Object *obj)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- FDCtrlSysBus *sys = SYSBUS_FDC(obj);
- FDCtrl *fdctrl = &sys->state;
-
- fdctrl->dma_chann = -1;
-
- memory_region_init_io(&fdctrl->iomem, obj, &fdctrl_mem_ops, fdctrl,
- "fdc", 0x08);
- sysbus_init_mmio(sbd, &fdctrl->iomem);
-}
-
-static void sun4m_fdc_initfn(Object *obj)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- FDCtrlSysBus *sys = SYSBUS_FDC(obj);
- FDCtrl *fdctrl = &sys->state;
-
- fdctrl->dma_chann = -1;
-
- memory_region_init_io(&fdctrl->iomem, obj, &fdctrl_mem_strict_ops,
- fdctrl, "fdctrl", 0x08);
- sysbus_init_mmio(sbd, &fdctrl->iomem);
-}
-
-static void sysbus_fdc_common_initfn(Object *obj)
-{
- DeviceState *dev = DEVICE(obj);
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- FDCtrlSysBus *sys = SYSBUS_FDC(obj);
- FDCtrl *fdctrl = &sys->state;
-
- qdev_set_legacy_instance_id(dev, 0 /* io */, 2); /* FIXME */
-
- sysbus_init_irq(sbd, &fdctrl->irq);
- qdev_init_gpio_in(dev, fdctrl_handle_tc, 1);
-}
-
-static void sysbus_fdc_common_realize(DeviceState *dev, Error **errp)
-{
- FDCtrlSysBus *sys = SYSBUS_FDC(dev);
- FDCtrl *fdctrl = &sys->state;
-
- fdctrl_realize_common(fdctrl, errp);
-}
-
-FloppyDriveType isa_fdc_get_drive_type(ISADevice *fdc, int i)
-{
- FDCtrlISABus *isa = ISA_FDC(fdc);
-
- return isa->state.drives[i].drive;
-}
-
-void isa_fdc_get_drive_max_chs(FloppyDriveType type,
- uint8_t *maxc, uint8_t *maxh, uint8_t *maxs)
-{
- const FDFormat *fdf;
-
- *maxc = *maxh = *maxs = 0;
- for (fdf = fd_formats; fdf->drive != FLOPPY_DRIVE_TYPE_NONE; fdf++) {
- if (fdf->drive != type) {
- continue;
- }
- if (*maxc < fdf->max_track) {
- *maxc = fdf->max_track;
- }
- if (*maxh < fdf->max_head) {
- *maxh = fdf->max_head;
- }
- if (*maxs < fdf->last_sect) {
- *maxs = fdf->last_sect;
- }
- }
- (*maxc)--;
-}
-
-static const VMStateDescription vmstate_isa_fdc ={
- .name = "fdc",
- .version_id = 2,
- .minimum_version_id = 2,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT(state, FDCtrlISABus, 0, vmstate_fdc, FDCtrl),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property isa_fdc_properties[] = {
- DEFINE_PROP_UINT32("iobase", FDCtrlISABus, iobase, 0x3f0),
- DEFINE_PROP_UINT32("irq", FDCtrlISABus, irq, 6),
- DEFINE_PROP_UINT32("dma", FDCtrlISABus, dma, 2),
- DEFINE_PROP_DRIVE("driveA", FDCtrlISABus, state.drives[0].blk),
- DEFINE_PROP_DRIVE("driveB", FDCtrlISABus, state.drives[1].blk),
- DEFINE_PROP_BIT("check_media_rate", FDCtrlISABus, state.check_media_rate,
- 0, true),
- DEFINE_PROP_DEFAULT("fdtypeA", FDCtrlISABus, state.drives[0].drive,
- FLOPPY_DRIVE_TYPE_AUTO, qdev_prop_fdc_drive_type,
- FloppyDriveType),
- DEFINE_PROP_DEFAULT("fdtypeB", FDCtrlISABus, state.drives[1].drive,
- FLOPPY_DRIVE_TYPE_AUTO, qdev_prop_fdc_drive_type,
- FloppyDriveType),
- DEFINE_PROP_DEFAULT("fallback", FDCtrlISABus, state.fallback,
- FLOPPY_DRIVE_TYPE_288, qdev_prop_fdc_drive_type,
- FloppyDriveType),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void isabus_fdc_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = isabus_fdc_realize;
- dc->fw_name = "fdc";
- dc->reset = fdctrl_external_reset_isa;
- dc->vmsd = &vmstate_isa_fdc;
- dc->props = isa_fdc_properties;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
-}
-
-static void isabus_fdc_instance_init(Object *obj)
-{
- FDCtrlISABus *isa = ISA_FDC(obj);
-
- device_add_bootindex_property(obj, &isa->bootindexA,
- "bootindexA", "/floppy@0",
- DEVICE(obj), NULL);
- device_add_bootindex_property(obj, &isa->bootindexB,
- "bootindexB", "/floppy@1",
- DEVICE(obj), NULL);
-}
-
-static const TypeInfo isa_fdc_info = {
- .name = TYPE_ISA_FDC,
- .parent = TYPE_ISA_DEVICE,
- .instance_size = sizeof(FDCtrlISABus),
- .class_init = isabus_fdc_class_init,
- .instance_init = isabus_fdc_instance_init,
-};
-
-static const VMStateDescription vmstate_sysbus_fdc ={
- .name = "fdc",
- .version_id = 2,
- .minimum_version_id = 2,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT(state, FDCtrlSysBus, 0, vmstate_fdc, FDCtrl),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property sysbus_fdc_properties[] = {
- DEFINE_PROP_DRIVE("driveA", FDCtrlSysBus, state.drives[0].blk),
- DEFINE_PROP_DRIVE("driveB", FDCtrlSysBus, state.drives[1].blk),
- DEFINE_PROP_DEFAULT("fdtypeA", FDCtrlSysBus, state.drives[0].drive,
- FLOPPY_DRIVE_TYPE_AUTO, qdev_prop_fdc_drive_type,
- FloppyDriveType),
- DEFINE_PROP_DEFAULT("fdtypeB", FDCtrlSysBus, state.drives[1].drive,
- FLOPPY_DRIVE_TYPE_AUTO, qdev_prop_fdc_drive_type,
- FloppyDriveType),
- DEFINE_PROP_DEFAULT("fallback", FDCtrlISABus, state.fallback,
- FLOPPY_DRIVE_TYPE_144, qdev_prop_fdc_drive_type,
- FloppyDriveType),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void sysbus_fdc_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->props = sysbus_fdc_properties;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
-}
-
-static const TypeInfo sysbus_fdc_info = {
- .name = "sysbus-fdc",
- .parent = TYPE_SYSBUS_FDC,
- .instance_init = sysbus_fdc_initfn,
- .class_init = sysbus_fdc_class_init,
-};
-
-static Property sun4m_fdc_properties[] = {
- DEFINE_PROP_DRIVE("drive", FDCtrlSysBus, state.drives[0].blk),
- DEFINE_PROP_DEFAULT("fdtype", FDCtrlSysBus, state.drives[0].drive,
- FLOPPY_DRIVE_TYPE_AUTO, qdev_prop_fdc_drive_type,
- FloppyDriveType),
- DEFINE_PROP_DEFAULT("fallback", FDCtrlISABus, state.fallback,
- FLOPPY_DRIVE_TYPE_144, qdev_prop_fdc_drive_type,
- FloppyDriveType),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void sun4m_fdc_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->props = sun4m_fdc_properties;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
-}
-
-static const TypeInfo sun4m_fdc_info = {
- .name = "SUNW,fdtwo",
- .parent = TYPE_SYSBUS_FDC,
- .instance_init = sun4m_fdc_initfn,
- .class_init = sun4m_fdc_class_init,
-};
-
-static void sysbus_fdc_common_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = sysbus_fdc_common_realize;
- dc->reset = fdctrl_external_reset_sysbus;
- dc->vmsd = &vmstate_sysbus_fdc;
-}
-
-static const TypeInfo sysbus_fdc_type_info = {
- .name = TYPE_SYSBUS_FDC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(FDCtrlSysBus),
- .instance_init = sysbus_fdc_common_initfn,
- .abstract = true,
- .class_init = sysbus_fdc_common_class_init,
-};
-
-static void fdc_register_types(void)
-{
- type_register_static(&isa_fdc_info);
- type_register_static(&sysbus_fdc_type_info);
- type_register_static(&sysbus_fdc_info);
- type_register_static(&sun4m_fdc_info);
-}
-
-type_init(fdc_register_types)
diff --git a/qemu/hw/block/hd-geometry.c b/qemu/hw/block/hd-geometry.c
deleted file mode 100644
index 6d02192db..000000000
--- a/qemu/hw/block/hd-geometry.c
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Hard disk geometry utilities
- *
- * Copyright (C) 2012 Red Hat, Inc.
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- * This file incorporates work covered by the following copyright and
- * permission notice:
- *
- * Copyright (c) 2003 Fabrice Bellard
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "sysemu/block-backend.h"
-#include "hw/block/block.h"
-#include "trace.h"
-
-struct partition {
- uint8_t boot_ind; /* 0x80 - active */
- uint8_t head; /* starting head */
- uint8_t sector; /* starting sector */
- uint8_t cyl; /* starting cylinder */
- uint8_t sys_ind; /* What partition type */
- uint8_t end_head; /* end head */
- uint8_t end_sector; /* end sector */
- uint8_t end_cyl; /* end cylinder */
- uint32_t start_sect; /* starting sector counting from 0 */
- uint32_t nr_sects; /* nr of sectors in partition */
-} QEMU_PACKED;
-
-/* try to guess the disk logical geometry from the MSDOS partition table.
- Return 0 if OK, -1 if could not guess */
-static int guess_disk_lchs(BlockBackend *blk,
- int *pcylinders, int *pheads, int *psectors)
-{
- uint8_t buf[BDRV_SECTOR_SIZE];
- int i, heads, sectors, cylinders;
- struct partition *p;
- uint32_t nr_sects;
- uint64_t nb_sectors;
-
- blk_get_geometry(blk, &nb_sectors);
-
- /**
- * The function will be invoked during startup not only in sync I/O mode,
- * but also in async I/O mode. So the I/O throttling function has to
- * be disabled temporarily here, not permanently.
- */
- if (blk_read_unthrottled(blk, 0, buf, 1) < 0) {
- return -1;
- }
- /* test msdos magic */
- if (buf[510] != 0x55 || buf[511] != 0xaa) {
- return -1;
- }
- for (i = 0; i < 4; i++) {
- p = ((struct partition *)(buf + 0x1be)) + i;
- nr_sects = le32_to_cpu(p->nr_sects);
- if (nr_sects && p->end_head) {
- /* We make the assumption that the partition terminates on
- a cylinder boundary */
- heads = p->end_head + 1;
- sectors = p->end_sector & 63;
- if (sectors == 0) {
- continue;
- }
- cylinders = nb_sectors / (heads * sectors);
- if (cylinders < 1 || cylinders > 16383) {
- continue;
- }
- *pheads = heads;
- *psectors = sectors;
- *pcylinders = cylinders;
- trace_hd_geometry_lchs_guess(blk, cylinders, heads, sectors);
- return 0;
- }
- }
- return -1;
-}
-
-static void guess_chs_for_size(BlockBackend *blk,
- uint32_t *pcyls, uint32_t *pheads, uint32_t *psecs)
-{
- uint64_t nb_sectors;
- int cylinders;
-
- blk_get_geometry(blk, &nb_sectors);
-
- cylinders = nb_sectors / (16 * 63);
- if (cylinders > 16383) {
- cylinders = 16383;
- } else if (cylinders < 2) {
- cylinders = 2;
- }
- *pcyls = cylinders;
- *pheads = 16;
- *psecs = 63;
-}
-
-void hd_geometry_guess(BlockBackend *blk,
- uint32_t *pcyls, uint32_t *pheads, uint32_t *psecs,
- int *ptrans)
-{
- int cylinders, heads, secs, translation;
- HDGeometry geo;
-
- /* Try to probe the backing device geometry, otherwise fallback
- to the old logic. (as of 12/2014 probing only succeeds on DASDs) */
- if (blk_probe_geometry(blk, &geo) == 0) {
- *pcyls = geo.cylinders;
- *psecs = geo.sectors;
- *pheads = geo.heads;
- translation = BIOS_ATA_TRANSLATION_NONE;
- } else if (guess_disk_lchs(blk, &cylinders, &heads, &secs) < 0) {
- /* no LCHS guess: use a standard physical disk geometry */
- guess_chs_for_size(blk, pcyls, pheads, psecs);
- translation = hd_bios_chs_auto_trans(*pcyls, *pheads, *psecs);
- } else if (heads > 16) {
- /* LCHS guess with heads > 16 means that a BIOS LBA
- translation was active, so a standard physical disk
- geometry is OK */
- guess_chs_for_size(blk, pcyls, pheads, psecs);
- translation = *pcyls * *pheads <= 131072
- ? BIOS_ATA_TRANSLATION_LARGE
- : BIOS_ATA_TRANSLATION_LBA;
- } else {
- /* LCHS guess with heads <= 16: use as physical geometry */
- *pcyls = cylinders;
- *pheads = heads;
- *psecs = secs;
- /* disable any translation to be in sync with
- the logical geometry */
- translation = BIOS_ATA_TRANSLATION_NONE;
- }
- if (ptrans) {
- *ptrans = translation;
- }
- trace_hd_geometry_guess(blk, *pcyls, *pheads, *psecs, translation);
-}
-
-int hd_bios_chs_auto_trans(uint32_t cyls, uint32_t heads, uint32_t secs)
-{
- return cyls <= 1024 && heads <= 16 && secs <= 63
- ? BIOS_ATA_TRANSLATION_NONE
- : BIOS_ATA_TRANSLATION_LBA;
-}
diff --git a/qemu/hw/block/m25p80.c b/qemu/hw/block/m25p80.c
deleted file mode 100644
index 906b71257..000000000
--- a/qemu/hw/block/m25p80.c
+++ /dev/null
@@ -1,1005 +0,0 @@
-/*
- * ST M25P80 emulator. Emulate all SPI flash devices based on the m25p80 command
- * set. Known devices table current as of Jun/2012 and taken from linux.
- * See drivers/mtd/devices/m25p80.c.
- *
- * Copyright (C) 2011 Edgar E. Iglesias <edgar.iglesias@gmail.com>
- * Copyright (C) 2012 Peter A. G. Crosthwaite <peter.crosthwaite@petalogix.com>
- * Copyright (C) 2012 PetaLogix
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) a later version of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
-#include "hw/ssi/ssi.h"
-#include "qemu/bitops.h"
-
-#ifndef M25P80_ERR_DEBUG
-#define M25P80_ERR_DEBUG 0
-#endif
-
-#define DB_PRINT_L(level, ...) do { \
- if (M25P80_ERR_DEBUG > (level)) { \
- fprintf(stderr, ": %s: ", __func__); \
- fprintf(stderr, ## __VA_ARGS__); \
- } \
-} while (0);
-
-/* Fields for FlashPartInfo->flags */
-
-/* erase capabilities */
-#define ER_4K 1
-#define ER_32K 2
-/* set to allow the page program command to write 0s back to 1. Useful for
- * modelling EEPROM with SPI flash command set
- */
-#define EEPROM 0x100
-
-/* 16 MiB max in 3 byte address mode */
-#define MAX_3BYTES_SIZE 0x1000000
-
-typedef struct FlashPartInfo {
- const char *part_name;
- /* jedec code. (jedec >> 16) & 0xff is the 1st byte, >> 8 the 2nd etc */
- uint32_t jedec;
- /* extended jedec code */
- uint16_t ext_jedec;
- /* there is confusion between manufacturers as to what a sector is. In this
- * device model, a "sector" is the size that is erased by the ERASE_SECTOR
- * command (opcode 0xd8).
- */
- uint32_t sector_size;
- uint32_t n_sectors;
- uint32_t page_size;
- uint16_t flags;
-} FlashPartInfo;
-
-/* adapted from linux */
-
-#define INFO(_part_name, _jedec, _ext_jedec, _sector_size, _n_sectors, _flags)\
- .part_name = (_part_name),\
- .jedec = (_jedec),\
- .ext_jedec = (_ext_jedec),\
- .sector_size = (_sector_size),\
- .n_sectors = (_n_sectors),\
- .page_size = 256,\
- .flags = (_flags),\
-
-#define JEDEC_NUMONYX 0x20
-#define JEDEC_WINBOND 0xEF
-#define JEDEC_SPANSION 0x01
-
-/* Numonyx (Micron) Configuration register macros */
-#define VCFG_DUMMY 0x1
-#define VCFG_WRAP_SEQUENTIAL 0x2
-#define NVCFG_XIP_MODE_DISABLED (7 << 9)
-#define NVCFG_XIP_MODE_MASK (7 << 9)
-#define VCFG_XIP_MODE_ENABLED (1 << 3)
-#define CFG_DUMMY_CLK_LEN 4
-#define NVCFG_DUMMY_CLK_POS 12
-#define VCFG_DUMMY_CLK_POS 4
-#define EVCFG_OUT_DRIVER_STRENGHT_DEF 7
-#define EVCFG_VPP_ACCELERATOR (1 << 3)
-#define EVCFG_RESET_HOLD_ENABLED (1 << 4)
-#define NVCFG_DUAL_IO_MASK (1 << 2)
-#define EVCFG_DUAL_IO_ENABLED (1 << 6)
-#define NVCFG_QUAD_IO_MASK (1 << 3)
-#define EVCFG_QUAD_IO_ENABLED (1 << 7)
-#define NVCFG_4BYTE_ADDR_MASK (1 << 0)
-#define NVCFG_LOWER_SEGMENT_MASK (1 << 1)
-#define CFG_UPPER_128MB_SEG_ENABLED 0x3
-
-/* Numonyx (Micron) Flag Status Register macros */
-#define FSR_4BYTE_ADDR_MODE_ENABLED 0x1
-#define FSR_FLASH_READY (1 << 7)
-
-static const FlashPartInfo known_devices[] = {
- /* Atmel -- some are (confusingly) marketed as "DataFlash" */
- { INFO("at25fs010", 0x1f6601, 0, 32 << 10, 4, ER_4K) },
- { INFO("at25fs040", 0x1f6604, 0, 64 << 10, 8, ER_4K) },
-
- { INFO("at25df041a", 0x1f4401, 0, 64 << 10, 8, ER_4K) },
- { INFO("at25df321a", 0x1f4701, 0, 64 << 10, 64, ER_4K) },
- { INFO("at25df641", 0x1f4800, 0, 64 << 10, 128, ER_4K) },
-
- { INFO("at26f004", 0x1f0400, 0, 64 << 10, 8, ER_4K) },
- { INFO("at26df081a", 0x1f4501, 0, 64 << 10, 16, ER_4K) },
- { INFO("at26df161a", 0x1f4601, 0, 64 << 10, 32, ER_4K) },
- { INFO("at26df321", 0x1f4700, 0, 64 << 10, 64, ER_4K) },
-
- { INFO("at45db081d", 0x1f2500, 0, 64 << 10, 16, ER_4K) },
-
- /* Atmel EEPROMS - it is assumed, that don't care bit in command
- * is set to 0. Block protection is not supported.
- */
- { INFO("at25128a-nonjedec", 0x0, 0, 1, 131072, EEPROM) },
- { INFO("at25256a-nonjedec", 0x0, 0, 1, 262144, EEPROM) },
-
- /* EON -- en25xxx */
- { INFO("en25f32", 0x1c3116, 0, 64 << 10, 64, ER_4K) },
- { INFO("en25p32", 0x1c2016, 0, 64 << 10, 64, 0) },
- { INFO("en25q32b", 0x1c3016, 0, 64 << 10, 64, 0) },
- { INFO("en25p64", 0x1c2017, 0, 64 << 10, 128, 0) },
- { INFO("en25q64", 0x1c3017, 0, 64 << 10, 128, ER_4K) },
-
- /* GigaDevice */
- { INFO("gd25q32", 0xc84016, 0, 64 << 10, 64, ER_4K) },
- { INFO("gd25q64", 0xc84017, 0, 64 << 10, 128, ER_4K) },
-
- /* Intel/Numonyx -- xxxs33b */
- { INFO("160s33b", 0x898911, 0, 64 << 10, 32, 0) },
- { INFO("320s33b", 0x898912, 0, 64 << 10, 64, 0) },
- { INFO("640s33b", 0x898913, 0, 64 << 10, 128, 0) },
- { INFO("n25q064", 0x20ba17, 0, 64 << 10, 128, 0) },
-
- /* Macronix */
- { INFO("mx25l2005a", 0xc22012, 0, 64 << 10, 4, ER_4K) },
- { INFO("mx25l4005a", 0xc22013, 0, 64 << 10, 8, ER_4K) },
- { INFO("mx25l8005", 0xc22014, 0, 64 << 10, 16, 0) },
- { INFO("mx25l1606e", 0xc22015, 0, 64 << 10, 32, ER_4K) },
- { INFO("mx25l3205d", 0xc22016, 0, 64 << 10, 64, 0) },
- { INFO("mx25l6405d", 0xc22017, 0, 64 << 10, 128, 0) },
- { INFO("mx25l12805d", 0xc22018, 0, 64 << 10, 256, 0) },
- { INFO("mx25l12855e", 0xc22618, 0, 64 << 10, 256, 0) },
- { INFO("mx25l25635e", 0xc22019, 0, 64 << 10, 512, 0) },
- { INFO("mx25l25655e", 0xc22619, 0, 64 << 10, 512, 0) },
-
- /* Micron */
- { INFO("n25q032a11", 0x20bb16, 0, 64 << 10, 64, ER_4K) },
- { INFO("n25q032a13", 0x20ba16, 0, 64 << 10, 64, ER_4K) },
- { INFO("n25q064a11", 0x20bb17, 0, 64 << 10, 128, ER_4K) },
- { INFO("n25q064a13", 0x20ba17, 0, 64 << 10, 128, ER_4K) },
- { INFO("n25q128a11", 0x20bb18, 0, 64 << 10, 256, ER_4K) },
- { INFO("n25q128a13", 0x20ba18, 0, 64 << 10, 256, ER_4K) },
- { INFO("n25q256a11", 0x20bb19, 0, 64 << 10, 512, ER_4K) },
- { INFO("n25q256a13", 0x20ba19, 0, 64 << 10, 512, ER_4K) },
-
- /* Spansion -- single (large) sector size only, at least
- * for the chips listed here (without boot sectors).
- */
- { INFO("s25sl032p", 0x010215, 0x4d00, 64 << 10, 64, ER_4K) },
- { INFO("s25sl064p", 0x010216, 0x4d00, 64 << 10, 128, ER_4K) },
- { INFO("s25fl256s0", 0x010219, 0x4d00, 256 << 10, 128, 0) },
- { INFO("s25fl256s1", 0x010219, 0x4d01, 64 << 10, 512, 0) },
- { INFO("s25fl512s", 0x010220, 0x4d00, 256 << 10, 256, 0) },
- { INFO("s70fl01gs", 0x010221, 0x4d00, 256 << 10, 256, 0) },
- { INFO("s25sl12800", 0x012018, 0x0300, 256 << 10, 64, 0) },
- { INFO("s25sl12801", 0x012018, 0x0301, 64 << 10, 256, 0) },
- { INFO("s25fl129p0", 0x012018, 0x4d00, 256 << 10, 64, 0) },
- { INFO("s25fl129p1", 0x012018, 0x4d01, 64 << 10, 256, 0) },
- { INFO("s25sl004a", 0x010212, 0, 64 << 10, 8, 0) },
- { INFO("s25sl008a", 0x010213, 0, 64 << 10, 16, 0) },
- { INFO("s25sl016a", 0x010214, 0, 64 << 10, 32, 0) },
- { INFO("s25sl032a", 0x010215, 0, 64 << 10, 64, 0) },
- { INFO("s25sl064a", 0x010216, 0, 64 << 10, 128, 0) },
- { INFO("s25fl016k", 0xef4015, 0, 64 << 10, 32, ER_4K | ER_32K) },
- { INFO("s25fl064k", 0xef4017, 0, 64 << 10, 128, ER_4K | ER_32K) },
-
- /* SST -- large erase sizes are "overlays", "sectors" are 4<< 10 */
- { INFO("sst25vf040b", 0xbf258d, 0, 64 << 10, 8, ER_4K) },
- { INFO("sst25vf080b", 0xbf258e, 0, 64 << 10, 16, ER_4K) },
- { INFO("sst25vf016b", 0xbf2541, 0, 64 << 10, 32, ER_4K) },
- { INFO("sst25vf032b", 0xbf254a, 0, 64 << 10, 64, ER_4K) },
- { INFO("sst25wf512", 0xbf2501, 0, 64 << 10, 1, ER_4K) },
- { INFO("sst25wf010", 0xbf2502, 0, 64 << 10, 2, ER_4K) },
- { INFO("sst25wf020", 0xbf2503, 0, 64 << 10, 4, ER_4K) },
- { INFO("sst25wf040", 0xbf2504, 0, 64 << 10, 8, ER_4K) },
- { INFO("sst25wf080", 0xbf2505, 0, 64 << 10, 16, ER_4K) },
-
- /* ST Microelectronics -- newer production may have feature updates */
- { INFO("m25p05", 0x202010, 0, 32 << 10, 2, 0) },
- { INFO("m25p10", 0x202011, 0, 32 << 10, 4, 0) },
- { INFO("m25p20", 0x202012, 0, 64 << 10, 4, 0) },
- { INFO("m25p40", 0x202013, 0, 64 << 10, 8, 0) },
- { INFO("m25p80", 0x202014, 0, 64 << 10, 16, 0) },
- { INFO("m25p16", 0x202015, 0, 64 << 10, 32, 0) },
- { INFO("m25p32", 0x202016, 0, 64 << 10, 64, 0) },
- { INFO("m25p64", 0x202017, 0, 64 << 10, 128, 0) },
- { INFO("m25p128", 0x202018, 0, 256 << 10, 64, 0) },
- { INFO("n25q032", 0x20ba16, 0, 64 << 10, 64, 0) },
-
- { INFO("m45pe10", 0x204011, 0, 64 << 10, 2, 0) },
- { INFO("m45pe80", 0x204014, 0, 64 << 10, 16, 0) },
- { INFO("m45pe16", 0x204015, 0, 64 << 10, 32, 0) },
-
- { INFO("m25pe20", 0x208012, 0, 64 << 10, 4, 0) },
- { INFO("m25pe80", 0x208014, 0, 64 << 10, 16, 0) },
- { INFO("m25pe16", 0x208015, 0, 64 << 10, 32, ER_4K) },
-
- { INFO("m25px32", 0x207116, 0, 64 << 10, 64, ER_4K) },
- { INFO("m25px32-s0", 0x207316, 0, 64 << 10, 64, ER_4K) },
- { INFO("m25px32-s1", 0x206316, 0, 64 << 10, 64, ER_4K) },
- { INFO("m25px64", 0x207117, 0, 64 << 10, 128, 0) },
-
- /* Winbond -- w25x "blocks" are 64k, "sectors" are 4KiB */
- { INFO("w25x10", 0xef3011, 0, 64 << 10, 2, ER_4K) },
- { INFO("w25x20", 0xef3012, 0, 64 << 10, 4, ER_4K) },
- { INFO("w25x40", 0xef3013, 0, 64 << 10, 8, ER_4K) },
- { INFO("w25x80", 0xef3014, 0, 64 << 10, 16, ER_4K) },
- { INFO("w25x16", 0xef3015, 0, 64 << 10, 32, ER_4K) },
- { INFO("w25x32", 0xef3016, 0, 64 << 10, 64, ER_4K) },
- { INFO("w25q32", 0xef4016, 0, 64 << 10, 64, ER_4K) },
- { INFO("w25q32dw", 0xef6016, 0, 64 << 10, 64, ER_4K) },
- { INFO("w25x64", 0xef3017, 0, 64 << 10, 128, ER_4K) },
- { INFO("w25q64", 0xef4017, 0, 64 << 10, 128, ER_4K) },
- { INFO("w25q80", 0xef5014, 0, 64 << 10, 16, ER_4K) },
- { INFO("w25q80bl", 0xef4014, 0, 64 << 10, 16, ER_4K) },
- { INFO("w25q256", 0xef4019, 0, 64 << 10, 512, ER_4K) },
-
- { INFO("n25q128", 0x20ba18, 0, 64 << 10, 256, 0) },
- { INFO("n25q256a", 0x20ba19, 0, 64 << 10, 512, ER_4K) },
- { INFO("n25q512a", 0x20ba20, 0, 64 << 10, 1024, ER_4K) },
-};
-
-typedef enum {
- NOP = 0,
- WRSR = 0x1,
- WRDI = 0x4,
- RDSR = 0x5,
- WREN = 0x6,
- JEDEC_READ = 0x9f,
- BULK_ERASE = 0xc7,
- READ_FSR = 0x70,
-
- READ = 0x03,
- READ4 = 0x13,
- FAST_READ = 0x0b,
- FAST_READ4 = 0x0c,
- DOR = 0x3b,
- DOR4 = 0x3c,
- QOR = 0x6b,
- QOR4 = 0x6c,
- DIOR = 0xbb,
- DIOR4 = 0xbc,
- QIOR = 0xeb,
- QIOR4 = 0xec,
-
- PP = 0x02,
- PP4 = 0x12,
- DPP = 0xa2,
- QPP = 0x32,
-
- ERASE_4K = 0x20,
- ERASE4_4K = 0x21,
- ERASE_32K = 0x52,
- ERASE_SECTOR = 0xd8,
- ERASE4_SECTOR = 0xdc,
-
- EN_4BYTE_ADDR = 0xB7,
- EX_4BYTE_ADDR = 0xE9,
-
- EXTEND_ADDR_READ = 0xC8,
- EXTEND_ADDR_WRITE = 0xC5,
-
- RESET_ENABLE = 0x66,
- RESET_MEMORY = 0x99,
-
- RNVCR = 0xB5,
- WNVCR = 0xB1,
-
- RVCR = 0x85,
- WVCR = 0x81,
-
- REVCR = 0x65,
- WEVCR = 0x61,
-} FlashCMD;
-
-typedef enum {
- STATE_IDLE,
- STATE_PAGE_PROGRAM,
- STATE_READ,
- STATE_COLLECTING_DATA,
- STATE_READING_DATA,
-} CMDState;
-
-typedef struct Flash {
- SSISlave parent_obj;
-
- BlockBackend *blk;
-
- uint8_t *storage;
- uint32_t size;
- int page_size;
-
- uint8_t state;
- uint8_t data[16];
- uint32_t len;
- uint32_t pos;
- uint8_t needed_bytes;
- uint8_t cmd_in_progress;
- uint64_t cur_addr;
- uint32_t nonvolatile_cfg;
- uint32_t volatile_cfg;
- uint32_t enh_volatile_cfg;
- bool write_enable;
- bool four_bytes_address_mode;
- bool reset_enable;
- uint8_t ear;
-
- int64_t dirty_page;
-
- const FlashPartInfo *pi;
-
-} Flash;
-
-typedef struct M25P80Class {
- SSISlaveClass parent_class;
- FlashPartInfo *pi;
-} M25P80Class;
-
-#define TYPE_M25P80 "m25p80-generic"
-#define M25P80(obj) \
- OBJECT_CHECK(Flash, (obj), TYPE_M25P80)
-#define M25P80_CLASS(klass) \
- OBJECT_CLASS_CHECK(M25P80Class, (klass), TYPE_M25P80)
-#define M25P80_GET_CLASS(obj) \
- OBJECT_GET_CLASS(M25P80Class, (obj), TYPE_M25P80)
-
-static void blk_sync_complete(void *opaque, int ret)
-{
- /* do nothing. Masters do not directly interact with the backing store,
- * only the working copy so no mutexing required.
- */
-}
-
-static void flash_sync_page(Flash *s, int page)
-{
- int blk_sector, nb_sectors;
- QEMUIOVector iov;
-
- if (!s->blk || blk_is_read_only(s->blk)) {
- return;
- }
-
- blk_sector = (page * s->pi->page_size) / BDRV_SECTOR_SIZE;
- nb_sectors = DIV_ROUND_UP(s->pi->page_size, BDRV_SECTOR_SIZE);
- qemu_iovec_init(&iov, 1);
- qemu_iovec_add(&iov, s->storage + blk_sector * BDRV_SECTOR_SIZE,
- nb_sectors * BDRV_SECTOR_SIZE);
- blk_aio_writev(s->blk, blk_sector, &iov, nb_sectors, blk_sync_complete,
- NULL);
-}
-
-static inline void flash_sync_area(Flash *s, int64_t off, int64_t len)
-{
- int64_t start, end, nb_sectors;
- QEMUIOVector iov;
-
- if (!s->blk || blk_is_read_only(s->blk)) {
- return;
- }
-
- assert(!(len % BDRV_SECTOR_SIZE));
- start = off / BDRV_SECTOR_SIZE;
- end = (off + len) / BDRV_SECTOR_SIZE;
- nb_sectors = end - start;
- qemu_iovec_init(&iov, 1);
- qemu_iovec_add(&iov, s->storage + (start * BDRV_SECTOR_SIZE),
- nb_sectors * BDRV_SECTOR_SIZE);
- blk_aio_writev(s->blk, start, &iov, nb_sectors, blk_sync_complete, NULL);
-}
-
-static void flash_erase(Flash *s, int offset, FlashCMD cmd)
-{
- uint32_t len;
- uint8_t capa_to_assert = 0;
-
- switch (cmd) {
- case ERASE_4K:
- case ERASE4_4K:
- len = 4 << 10;
- capa_to_assert = ER_4K;
- break;
- case ERASE_32K:
- len = 32 << 10;
- capa_to_assert = ER_32K;
- break;
- case ERASE_SECTOR:
- case ERASE4_SECTOR:
- len = s->pi->sector_size;
- break;
- case BULK_ERASE:
- len = s->size;
- break;
- default:
- abort();
- }
-
- DB_PRINT_L(0, "offset = %#x, len = %d\n", offset, len);
- if ((s->pi->flags & capa_to_assert) != capa_to_assert) {
- qemu_log_mask(LOG_GUEST_ERROR, "M25P80: %d erase size not supported by"
- " device\n", len);
- }
-
- if (!s->write_enable) {
- qemu_log_mask(LOG_GUEST_ERROR, "M25P80: erase with write protect!\n");
- return;
- }
- memset(s->storage + offset, 0xff, len);
- flash_sync_area(s, offset, len);
-}
-
-static inline void flash_sync_dirty(Flash *s, int64_t newpage)
-{
- if (s->dirty_page >= 0 && s->dirty_page != newpage) {
- flash_sync_page(s, s->dirty_page);
- s->dirty_page = newpage;
- }
-}
-
-static inline
-void flash_write8(Flash *s, uint64_t addr, uint8_t data)
-{
- int64_t page = addr / s->pi->page_size;
- uint8_t prev = s->storage[s->cur_addr];
-
- if (!s->write_enable) {
- qemu_log_mask(LOG_GUEST_ERROR, "M25P80: write with write protect!\n");
- }
-
- if ((prev ^ data) & data) {
- DB_PRINT_L(1, "programming zero to one! addr=%" PRIx64 " %" PRIx8
- " -> %" PRIx8 "\n", addr, prev, data);
- }
-
- if (s->pi->flags & EEPROM) {
- s->storage[s->cur_addr] = data;
- } else {
- s->storage[s->cur_addr] &= data;
- }
-
- flash_sync_dirty(s, page);
- s->dirty_page = page;
-}
-
-static inline int get_addr_length(Flash *s)
-{
- /* check if eeprom is in use */
- if (s->pi->flags == EEPROM) {
- return 2;
- }
-
- switch (s->cmd_in_progress) {
- case PP4:
- case READ4:
- case QIOR4:
- case ERASE4_4K:
- case ERASE4_SECTOR:
- case FAST_READ4:
- case DOR4:
- case QOR4:
- case DIOR4:
- return 4;
- default:
- return s->four_bytes_address_mode ? 4 : 3;
- }
-}
-
-static void complete_collecting_data(Flash *s)
-{
- int i;
-
- s->cur_addr = 0;
-
- for (i = 0; i < get_addr_length(s); ++i) {
- s->cur_addr <<= 8;
- s->cur_addr |= s->data[i];
- }
-
- if (get_addr_length(s) == 3) {
- s->cur_addr += (s->ear & 0x3) * MAX_3BYTES_SIZE;
- }
-
- s->state = STATE_IDLE;
-
- switch (s->cmd_in_progress) {
- case DPP:
- case QPP:
- case PP:
- case PP4:
- s->state = STATE_PAGE_PROGRAM;
- break;
- case READ:
- case READ4:
- case FAST_READ:
- case FAST_READ4:
- case DOR:
- case DOR4:
- case QOR:
- case QOR4:
- case DIOR:
- case DIOR4:
- case QIOR:
- case QIOR4:
- s->state = STATE_READ;
- break;
- case ERASE_4K:
- case ERASE4_4K:
- case ERASE_32K:
- case ERASE_SECTOR:
- case ERASE4_SECTOR:
- flash_erase(s, s->cur_addr, s->cmd_in_progress);
- break;
- case WRSR:
- if (s->write_enable) {
- s->write_enable = false;
- }
- break;
- case EXTEND_ADDR_WRITE:
- s->ear = s->data[0];
- break;
- case WNVCR:
- s->nonvolatile_cfg = s->data[0] | (s->data[1] << 8);
- break;
- case WVCR:
- s->volatile_cfg = s->data[0];
- break;
- case WEVCR:
- s->enh_volatile_cfg = s->data[0];
- break;
- default:
- break;
- }
-}
-
-static void reset_memory(Flash *s)
-{
- s->cmd_in_progress = NOP;
- s->cur_addr = 0;
- s->ear = 0;
- s->four_bytes_address_mode = false;
- s->len = 0;
- s->needed_bytes = 0;
- s->pos = 0;
- s->state = STATE_IDLE;
- s->write_enable = false;
- s->reset_enable = false;
-
- if (((s->pi->jedec >> 16) & 0xFF) == JEDEC_NUMONYX) {
- s->volatile_cfg = 0;
- s->volatile_cfg |= VCFG_DUMMY;
- s->volatile_cfg |= VCFG_WRAP_SEQUENTIAL;
- if ((s->nonvolatile_cfg & NVCFG_XIP_MODE_MASK)
- != NVCFG_XIP_MODE_DISABLED) {
- s->volatile_cfg |= VCFG_XIP_MODE_ENABLED;
- }
- s->volatile_cfg |= deposit32(s->volatile_cfg,
- VCFG_DUMMY_CLK_POS,
- CFG_DUMMY_CLK_LEN,
- extract32(s->nonvolatile_cfg,
- NVCFG_DUMMY_CLK_POS,
- CFG_DUMMY_CLK_LEN)
- );
-
- s->enh_volatile_cfg = 0;
- s->enh_volatile_cfg |= EVCFG_OUT_DRIVER_STRENGHT_DEF;
- s->enh_volatile_cfg |= EVCFG_VPP_ACCELERATOR;
- s->enh_volatile_cfg |= EVCFG_RESET_HOLD_ENABLED;
- if (s->nonvolatile_cfg & NVCFG_DUAL_IO_MASK) {
- s->enh_volatile_cfg |= EVCFG_DUAL_IO_ENABLED;
- }
- if (s->nonvolatile_cfg & NVCFG_QUAD_IO_MASK) {
- s->enh_volatile_cfg |= EVCFG_QUAD_IO_ENABLED;
- }
- if (!(s->nonvolatile_cfg & NVCFG_4BYTE_ADDR_MASK)) {
- s->four_bytes_address_mode = true;
- }
- if (!(s->nonvolatile_cfg & NVCFG_LOWER_SEGMENT_MASK)) {
- s->ear = CFG_UPPER_128MB_SEG_ENABLED;
- }
- }
-
- DB_PRINT_L(0, "Reset done.\n");
-}
-
-static void decode_new_cmd(Flash *s, uint32_t value)
-{
- s->cmd_in_progress = value;
- DB_PRINT_L(0, "decoded new command:%x\n", value);
-
- if (value != RESET_MEMORY) {
- s->reset_enable = false;
- }
-
- switch (value) {
-
- case ERASE_4K:
- case ERASE4_4K:
- case ERASE_32K:
- case ERASE_SECTOR:
- case ERASE4_SECTOR:
- case READ:
- case READ4:
- case DPP:
- case QPP:
- case PP:
- case PP4:
- s->needed_bytes = get_addr_length(s);
- s->pos = 0;
- s->len = 0;
- s->state = STATE_COLLECTING_DATA;
- break;
-
- case FAST_READ:
- case FAST_READ4:
- case DOR:
- case DOR4:
- case QOR:
- case QOR4:
- s->needed_bytes = get_addr_length(s);
- if (((s->pi->jedec >> 16) & 0xFF) == JEDEC_NUMONYX) {
- /* Dummy cycles modeled with bytes writes instead of bits */
- s->needed_bytes += extract32(s->volatile_cfg, 4, 4);
- }
- s->pos = 0;
- s->len = 0;
- s->state = STATE_COLLECTING_DATA;
- break;
-
- case DIOR:
- case DIOR4:
- switch ((s->pi->jedec >> 16) & 0xFF) {
- case JEDEC_WINBOND:
- case JEDEC_SPANSION:
- s->needed_bytes = 4;
- break;
- default:
- s->needed_bytes = get_addr_length(s);
- /* Dummy cycles modeled with bytes writes instead of bits */
- s->needed_bytes += extract32(s->volatile_cfg, 4, 4);
- }
- s->pos = 0;
- s->len = 0;
- s->state = STATE_COLLECTING_DATA;
- break;
-
- case QIOR:
- case QIOR4:
- switch ((s->pi->jedec >> 16) & 0xFF) {
- case JEDEC_WINBOND:
- case JEDEC_SPANSION:
- s->needed_bytes = 6;
- break;
- default:
- s->needed_bytes = get_addr_length(s);
- /* Dummy cycles modeled with bytes writes instead of bits */
- s->needed_bytes += extract32(s->volatile_cfg, 4, 4);
- }
- s->pos = 0;
- s->len = 0;
- s->state = STATE_COLLECTING_DATA;
- break;
-
- case WRSR:
- if (s->write_enable) {
- s->needed_bytes = 1;
- s->pos = 0;
- s->len = 0;
- s->state = STATE_COLLECTING_DATA;
- }
- break;
-
- case WRDI:
- s->write_enable = false;
- break;
- case WREN:
- s->write_enable = true;
- break;
-
- case RDSR:
- s->data[0] = (!!s->write_enable) << 1;
- s->pos = 0;
- s->len = 1;
- s->state = STATE_READING_DATA;
- break;
-
- case READ_FSR:
- s->data[0] = FSR_FLASH_READY;
- if (s->four_bytes_address_mode) {
- s->data[0] |= FSR_4BYTE_ADDR_MODE_ENABLED;
- }
- s->pos = 0;
- s->len = 1;
- s->state = STATE_READING_DATA;
- break;
-
- case JEDEC_READ:
- DB_PRINT_L(0, "populated jedec code\n");
- s->data[0] = (s->pi->jedec >> 16) & 0xff;
- s->data[1] = (s->pi->jedec >> 8) & 0xff;
- s->data[2] = s->pi->jedec & 0xff;
- if (s->pi->ext_jedec) {
- s->data[3] = (s->pi->ext_jedec >> 8) & 0xff;
- s->data[4] = s->pi->ext_jedec & 0xff;
- s->len = 5;
- } else {
- s->len = 3;
- }
- s->pos = 0;
- s->state = STATE_READING_DATA;
- break;
-
- case BULK_ERASE:
- if (s->write_enable) {
- DB_PRINT_L(0, "chip erase\n");
- flash_erase(s, 0, BULK_ERASE);
- } else {
- qemu_log_mask(LOG_GUEST_ERROR, "M25P80: chip erase with write "
- "protect!\n");
- }
- break;
- case NOP:
- break;
- case EN_4BYTE_ADDR:
- s->four_bytes_address_mode = true;
- break;
- case EX_4BYTE_ADDR:
- s->four_bytes_address_mode = false;
- break;
- case EXTEND_ADDR_READ:
- s->data[0] = s->ear;
- s->pos = 0;
- s->len = 1;
- s->state = STATE_READING_DATA;
- break;
- case EXTEND_ADDR_WRITE:
- if (s->write_enable) {
- s->needed_bytes = 1;
- s->pos = 0;
- s->len = 0;
- s->state = STATE_COLLECTING_DATA;
- }
- break;
- case RNVCR:
- s->data[0] = s->nonvolatile_cfg & 0xFF;
- s->data[1] = (s->nonvolatile_cfg >> 8) & 0xFF;
- s->pos = 0;
- s->len = 2;
- s->state = STATE_READING_DATA;
- break;
- case WNVCR:
- if (s->write_enable) {
- s->needed_bytes = 2;
- s->pos = 0;
- s->len = 0;
- s->state = STATE_COLLECTING_DATA;
- }
- break;
- case RVCR:
- s->data[0] = s->volatile_cfg & 0xFF;
- s->pos = 0;
- s->len = 1;
- s->state = STATE_READING_DATA;
- break;
- case WVCR:
- if (s->write_enable) {
- s->needed_bytes = 1;
- s->pos = 0;
- s->len = 0;
- s->state = STATE_COLLECTING_DATA;
- }
- break;
- case REVCR:
- s->data[0] = s->enh_volatile_cfg & 0xFF;
- s->pos = 0;
- s->len = 1;
- s->state = STATE_READING_DATA;
- break;
- case WEVCR:
- if (s->write_enable) {
- s->needed_bytes = 1;
- s->pos = 0;
- s->len = 0;
- s->state = STATE_COLLECTING_DATA;
- }
- break;
- case RESET_ENABLE:
- s->reset_enable = true;
- break;
- case RESET_MEMORY:
- if (s->reset_enable) {
- reset_memory(s);
- }
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "M25P80: Unknown cmd %x\n", value);
- break;
- }
-}
-
-static int m25p80_cs(SSISlave *ss, bool select)
-{
- Flash *s = M25P80(ss);
-
- if (select) {
- s->len = 0;
- s->pos = 0;
- s->state = STATE_IDLE;
- flash_sync_dirty(s, -1);
- }
-
- DB_PRINT_L(0, "%sselect\n", select ? "de" : "");
-
- return 0;
-}
-
-static uint32_t m25p80_transfer8(SSISlave *ss, uint32_t tx)
-{
- Flash *s = M25P80(ss);
- uint32_t r = 0;
-
- switch (s->state) {
-
- case STATE_PAGE_PROGRAM:
- DB_PRINT_L(1, "page program cur_addr=%#" PRIx64 " data=%" PRIx8 "\n",
- s->cur_addr, (uint8_t)tx);
- flash_write8(s, s->cur_addr, (uint8_t)tx);
- s->cur_addr++;
- break;
-
- case STATE_READ:
- r = s->storage[s->cur_addr];
- DB_PRINT_L(1, "READ 0x%" PRIx64 "=%" PRIx8 "\n", s->cur_addr,
- (uint8_t)r);
- s->cur_addr = (s->cur_addr + 1) % s->size;
- break;
-
- case STATE_COLLECTING_DATA:
- s->data[s->len] = (uint8_t)tx;
- s->len++;
-
- if (s->len == s->needed_bytes) {
- complete_collecting_data(s);
- }
- break;
-
- case STATE_READING_DATA:
- r = s->data[s->pos];
- s->pos++;
- if (s->pos == s->len) {
- s->pos = 0;
- s->state = STATE_IDLE;
- }
- break;
-
- default:
- case STATE_IDLE:
- decode_new_cmd(s, (uint8_t)tx);
- break;
- }
-
- return r;
-}
-
-static int m25p80_init(SSISlave *ss)
-{
- DriveInfo *dinfo;
- Flash *s = M25P80(ss);
- M25P80Class *mc = M25P80_GET_CLASS(s);
-
- s->pi = mc->pi;
-
- s->size = s->pi->sector_size * s->pi->n_sectors;
- s->dirty_page = -1;
-
- /* FIXME use a qdev drive property instead of drive_get_next() */
- dinfo = drive_get_next(IF_MTD);
-
- if (dinfo) {
- DB_PRINT_L(0, "Binding to IF_MTD drive\n");
- s->blk = blk_by_legacy_dinfo(dinfo);
- blk_attach_dev_nofail(s->blk, s);
-
- s->storage = blk_blockalign(s->blk, s->size);
-
- /* FIXME: Move to late init */
- if (blk_read(s->blk, 0, s->storage,
- DIV_ROUND_UP(s->size, BDRV_SECTOR_SIZE))) {
- fprintf(stderr, "Failed to initialize SPI flash!\n");
- return 1;
- }
- } else {
- DB_PRINT_L(0, "No BDRV - binding to RAM\n");
- s->storage = blk_blockalign(NULL, s->size);
- memset(s->storage, 0xFF, s->size);
- }
-
- return 0;
-}
-
-static void m25p80_reset(DeviceState *d)
-{
- Flash *s = M25P80(d);
-
- reset_memory(s);
-}
-
-static void m25p80_pre_save(void *opaque)
-{
- flash_sync_dirty((Flash *)opaque, -1);
-}
-
-static Property m25p80_properties[] = {
- DEFINE_PROP_UINT32("nonvolatile-cfg", Flash, nonvolatile_cfg, 0x8FFF),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static const VMStateDescription vmstate_m25p80 = {
- .name = "xilinx_spi",
- .version_id = 2,
- .minimum_version_id = 1,
- .pre_save = m25p80_pre_save,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(state, Flash),
- VMSTATE_UINT8_ARRAY(data, Flash, 16),
- VMSTATE_UINT32(len, Flash),
- VMSTATE_UINT32(pos, Flash),
- VMSTATE_UINT8(needed_bytes, Flash),
- VMSTATE_UINT8(cmd_in_progress, Flash),
- VMSTATE_UINT64(cur_addr, Flash),
- VMSTATE_BOOL(write_enable, Flash),
- VMSTATE_BOOL_V(reset_enable, Flash, 2),
- VMSTATE_UINT8_V(ear, Flash, 2),
- VMSTATE_BOOL_V(four_bytes_address_mode, Flash, 2),
- VMSTATE_UINT32_V(nonvolatile_cfg, Flash, 2),
- VMSTATE_UINT32_V(volatile_cfg, Flash, 2),
- VMSTATE_UINT32_V(enh_volatile_cfg, Flash, 2),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void m25p80_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
- M25P80Class *mc = M25P80_CLASS(klass);
-
- k->init = m25p80_init;
- k->transfer = m25p80_transfer8;
- k->set_cs = m25p80_cs;
- k->cs_polarity = SSI_CS_LOW;
- dc->vmsd = &vmstate_m25p80;
- dc->props = m25p80_properties;
- dc->reset = m25p80_reset;
- mc->pi = data;
-}
-
-static const TypeInfo m25p80_info = {
- .name = TYPE_M25P80,
- .parent = TYPE_SSI_SLAVE,
- .instance_size = sizeof(Flash),
- .class_size = sizeof(M25P80Class),
- .abstract = true,
-};
-
-static void m25p80_register_types(void)
-{
- int i;
-
- type_register_static(&m25p80_info);
- for (i = 0; i < ARRAY_SIZE(known_devices); ++i) {
- TypeInfo ti = {
- .name = known_devices[i].part_name,
- .parent = TYPE_M25P80,
- .class_init = m25p80_class_init,
- .class_data = (void *)&known_devices[i],
- };
- type_register(&ti);
- }
-}
-
-type_init(m25p80_register_types)
diff --git a/qemu/hw/block/nand.c b/qemu/hw/block/nand.c
deleted file mode 100644
index 29c659681..000000000
--- a/qemu/hw/block/nand.c
+++ /dev/null
@@ -1,801 +0,0 @@
-/*
- * Flash NAND memory emulation. Based on "16M x 8 Bit NAND Flash
- * Memory" datasheet for the KM29U128AT / K9F2808U0A chips from
- * Samsung Electronic.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * Support for additional features based on "MT29F2G16ABCWP 2Gx16"
- * datasheet from Micron Technology and "NAND02G-B2C" datasheet
- * from ST Microelectronics.
- *
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#ifndef NAND_IO
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/block/flash.h"
-#include "sysemu/block-backend.h"
-#include "hw/qdev.h"
-#include "qapi/error.h"
-#include "qemu/error-report.h"
-
-# define NAND_CMD_READ0 0x00
-# define NAND_CMD_READ1 0x01
-# define NAND_CMD_READ2 0x50
-# define NAND_CMD_LPREAD2 0x30
-# define NAND_CMD_NOSERIALREAD2 0x35
-# define NAND_CMD_RANDOMREAD1 0x05
-# define NAND_CMD_RANDOMREAD2 0xe0
-# define NAND_CMD_READID 0x90
-# define NAND_CMD_RESET 0xff
-# define NAND_CMD_PAGEPROGRAM1 0x80
-# define NAND_CMD_PAGEPROGRAM2 0x10
-# define NAND_CMD_CACHEPROGRAM2 0x15
-# define NAND_CMD_BLOCKERASE1 0x60
-# define NAND_CMD_BLOCKERASE2 0xd0
-# define NAND_CMD_READSTATUS 0x70
-# define NAND_CMD_COPYBACKPRG1 0x85
-
-# define NAND_IOSTATUS_ERROR (1 << 0)
-# define NAND_IOSTATUS_PLANE0 (1 << 1)
-# define NAND_IOSTATUS_PLANE1 (1 << 2)
-# define NAND_IOSTATUS_PLANE2 (1 << 3)
-# define NAND_IOSTATUS_PLANE3 (1 << 4)
-# define NAND_IOSTATUS_READY (1 << 6)
-# define NAND_IOSTATUS_UNPROTCT (1 << 7)
-
-# define MAX_PAGE 0x800
-# define MAX_OOB 0x40
-
-typedef struct NANDFlashState NANDFlashState;
-struct NANDFlashState {
- DeviceState parent_obj;
-
- uint8_t manf_id, chip_id;
- uint8_t buswidth; /* in BYTES */
- int size, pages;
- int page_shift, oob_shift, erase_shift, addr_shift;
- uint8_t *storage;
- BlockBackend *blk;
- int mem_oob;
-
- uint8_t cle, ale, ce, wp, gnd;
-
- uint8_t io[MAX_PAGE + MAX_OOB + 0x400];
- uint8_t *ioaddr;
- int iolen;
-
- uint32_t cmd;
- uint64_t addr;
- int addrlen;
- int status;
- int offset;
-
- void (*blk_write)(NANDFlashState *s);
- void (*blk_erase)(NANDFlashState *s);
- void (*blk_load)(NANDFlashState *s, uint64_t addr, int offset);
-
- uint32_t ioaddr_vmstate;
-};
-
-#define TYPE_NAND "nand"
-
-#define NAND(obj) \
- OBJECT_CHECK(NANDFlashState, (obj), TYPE_NAND)
-
-static void mem_and(uint8_t *dest, const uint8_t *src, size_t n)
-{
- /* Like memcpy() but we logical-AND the data into the destination */
- int i;
- for (i = 0; i < n; i++) {
- dest[i] &= src[i];
- }
-}
-
-# define NAND_NO_AUTOINCR 0x00000001
-# define NAND_BUSWIDTH_16 0x00000002
-# define NAND_NO_PADDING 0x00000004
-# define NAND_CACHEPRG 0x00000008
-# define NAND_COPYBACK 0x00000010
-# define NAND_IS_AND 0x00000020
-# define NAND_4PAGE_ARRAY 0x00000040
-# define NAND_NO_READRDY 0x00000100
-# define NAND_SAMSUNG_LP (NAND_NO_PADDING | NAND_COPYBACK)
-
-# define NAND_IO
-
-# define PAGE(addr) ((addr) >> ADDR_SHIFT)
-# define PAGE_START(page) (PAGE(page) * (PAGE_SIZE + OOB_SIZE))
-# define PAGE_MASK ((1 << ADDR_SHIFT) - 1)
-# define OOB_SHIFT (PAGE_SHIFT - 5)
-# define OOB_SIZE (1 << OOB_SHIFT)
-# define SECTOR(addr) ((addr) >> (9 + ADDR_SHIFT - PAGE_SHIFT))
-# define SECTOR_OFFSET(addr) ((addr) & ((511 >> PAGE_SHIFT) << 8))
-
-# define PAGE_SIZE 256
-# define PAGE_SHIFT 8
-# define PAGE_SECTORS 1
-# define ADDR_SHIFT 8
-# include "nand.c"
-# define PAGE_SIZE 512
-# define PAGE_SHIFT 9
-# define PAGE_SECTORS 1
-# define ADDR_SHIFT 8
-# include "nand.c"
-# define PAGE_SIZE 2048
-# define PAGE_SHIFT 11
-# define PAGE_SECTORS 4
-# define ADDR_SHIFT 16
-# include "nand.c"
-
-/* Information based on Linux drivers/mtd/nand/nand_ids.c */
-static const struct {
- int size;
- int width;
- int page_shift;
- int erase_shift;
- uint32_t options;
-} nand_flash_ids[0x100] = {
- [0 ... 0xff] = { 0 },
-
- [0x6e] = { 1, 8, 8, 4, 0 },
- [0x64] = { 2, 8, 8, 4, 0 },
- [0x6b] = { 4, 8, 9, 4, 0 },
- [0xe8] = { 1, 8, 8, 4, 0 },
- [0xec] = { 1, 8, 8, 4, 0 },
- [0xea] = { 2, 8, 8, 4, 0 },
- [0xd5] = { 4, 8, 9, 4, 0 },
- [0xe3] = { 4, 8, 9, 4, 0 },
- [0xe5] = { 4, 8, 9, 4, 0 },
- [0xd6] = { 8, 8, 9, 4, 0 },
-
- [0x39] = { 8, 8, 9, 4, 0 },
- [0xe6] = { 8, 8, 9, 4, 0 },
- [0x49] = { 8, 16, 9, 4, NAND_BUSWIDTH_16 },
- [0x59] = { 8, 16, 9, 4, NAND_BUSWIDTH_16 },
-
- [0x33] = { 16, 8, 9, 5, 0 },
- [0x73] = { 16, 8, 9, 5, 0 },
- [0x43] = { 16, 16, 9, 5, NAND_BUSWIDTH_16 },
- [0x53] = { 16, 16, 9, 5, NAND_BUSWIDTH_16 },
-
- [0x35] = { 32, 8, 9, 5, 0 },
- [0x75] = { 32, 8, 9, 5, 0 },
- [0x45] = { 32, 16, 9, 5, NAND_BUSWIDTH_16 },
- [0x55] = { 32, 16, 9, 5, NAND_BUSWIDTH_16 },
-
- [0x36] = { 64, 8, 9, 5, 0 },
- [0x76] = { 64, 8, 9, 5, 0 },
- [0x46] = { 64, 16, 9, 5, NAND_BUSWIDTH_16 },
- [0x56] = { 64, 16, 9, 5, NAND_BUSWIDTH_16 },
-
- [0x78] = { 128, 8, 9, 5, 0 },
- [0x39] = { 128, 8, 9, 5, 0 },
- [0x79] = { 128, 8, 9, 5, 0 },
- [0x72] = { 128, 16, 9, 5, NAND_BUSWIDTH_16 },
- [0x49] = { 128, 16, 9, 5, NAND_BUSWIDTH_16 },
- [0x74] = { 128, 16, 9, 5, NAND_BUSWIDTH_16 },
- [0x59] = { 128, 16, 9, 5, NAND_BUSWIDTH_16 },
-
- [0x71] = { 256, 8, 9, 5, 0 },
-
- /*
- * These are the new chips with large page size. The pagesize and the
- * erasesize is determined from the extended id bytes
- */
-# define LP_OPTIONS (NAND_SAMSUNG_LP | NAND_NO_READRDY | NAND_NO_AUTOINCR)
-# define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16)
-
- /* 512 Megabit */
- [0xa2] = { 64, 8, 0, 0, LP_OPTIONS },
- [0xf2] = { 64, 8, 0, 0, LP_OPTIONS },
- [0xb2] = { 64, 16, 0, 0, LP_OPTIONS16 },
- [0xc2] = { 64, 16, 0, 0, LP_OPTIONS16 },
-
- /* 1 Gigabit */
- [0xa1] = { 128, 8, 0, 0, LP_OPTIONS },
- [0xf1] = { 128, 8, 0, 0, LP_OPTIONS },
- [0xb1] = { 128, 16, 0, 0, LP_OPTIONS16 },
- [0xc1] = { 128, 16, 0, 0, LP_OPTIONS16 },
-
- /* 2 Gigabit */
- [0xaa] = { 256, 8, 0, 0, LP_OPTIONS },
- [0xda] = { 256, 8, 0, 0, LP_OPTIONS },
- [0xba] = { 256, 16, 0, 0, LP_OPTIONS16 },
- [0xca] = { 256, 16, 0, 0, LP_OPTIONS16 },
-
- /* 4 Gigabit */
- [0xac] = { 512, 8, 0, 0, LP_OPTIONS },
- [0xdc] = { 512, 8, 0, 0, LP_OPTIONS },
- [0xbc] = { 512, 16, 0, 0, LP_OPTIONS16 },
- [0xcc] = { 512, 16, 0, 0, LP_OPTIONS16 },
-
- /* 8 Gigabit */
- [0xa3] = { 1024, 8, 0, 0, LP_OPTIONS },
- [0xd3] = { 1024, 8, 0, 0, LP_OPTIONS },
- [0xb3] = { 1024, 16, 0, 0, LP_OPTIONS16 },
- [0xc3] = { 1024, 16, 0, 0, LP_OPTIONS16 },
-
- /* 16 Gigabit */
- [0xa5] = { 2048, 8, 0, 0, LP_OPTIONS },
- [0xd5] = { 2048, 8, 0, 0, LP_OPTIONS },
- [0xb5] = { 2048, 16, 0, 0, LP_OPTIONS16 },
- [0xc5] = { 2048, 16, 0, 0, LP_OPTIONS16 },
-};
-
-static void nand_reset(DeviceState *dev)
-{
- NANDFlashState *s = NAND(dev);
- s->cmd = NAND_CMD_READ0;
- s->addr = 0;
- s->addrlen = 0;
- s->iolen = 0;
- s->offset = 0;
- s->status &= NAND_IOSTATUS_UNPROTCT;
- s->status |= NAND_IOSTATUS_READY;
-}
-
-static inline void nand_pushio_byte(NANDFlashState *s, uint8_t value)
-{
- s->ioaddr[s->iolen++] = value;
- for (value = s->buswidth; --value;) {
- s->ioaddr[s->iolen++] = 0;
- }
-}
-
-static void nand_command(NANDFlashState *s)
-{
- unsigned int offset;
- switch (s->cmd) {
- case NAND_CMD_READ0:
- s->iolen = 0;
- break;
-
- case NAND_CMD_READID:
- s->ioaddr = s->io;
- s->iolen = 0;
- nand_pushio_byte(s, s->manf_id);
- nand_pushio_byte(s, s->chip_id);
- nand_pushio_byte(s, 'Q'); /* Don't-care byte (often 0xa5) */
- if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
- /* Page Size, Block Size, Spare Size; bit 6 indicates
- * 8 vs 16 bit width NAND.
- */
- nand_pushio_byte(s, (s->buswidth == 2) ? 0x55 : 0x15);
- } else {
- nand_pushio_byte(s, 0xc0); /* Multi-plane */
- }
- break;
-
- case NAND_CMD_RANDOMREAD2:
- case NAND_CMD_NOSERIALREAD2:
- if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP))
- break;
- offset = s->addr & ((1 << s->addr_shift) - 1);
- s->blk_load(s, s->addr, offset);
- if (s->gnd)
- s->iolen = (1 << s->page_shift) - offset;
- else
- s->iolen = (1 << s->page_shift) + (1 << s->oob_shift) - offset;
- break;
-
- case NAND_CMD_RESET:
- nand_reset(DEVICE(s));
- break;
-
- case NAND_CMD_PAGEPROGRAM1:
- s->ioaddr = s->io;
- s->iolen = 0;
- break;
-
- case NAND_CMD_PAGEPROGRAM2:
- if (s->wp) {
- s->blk_write(s);
- }
- break;
-
- case NAND_CMD_BLOCKERASE1:
- break;
-
- case NAND_CMD_BLOCKERASE2:
- s->addr &= (1ull << s->addrlen * 8) - 1;
- s->addr <<= nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP ?
- 16 : 8;
-
- if (s->wp) {
- s->blk_erase(s);
- }
- break;
-
- case NAND_CMD_READSTATUS:
- s->ioaddr = s->io;
- s->iolen = 0;
- nand_pushio_byte(s, s->status);
- break;
-
- default:
- printf("%s: Unknown NAND command 0x%02x\n", __FUNCTION__, s->cmd);
- }
-}
-
-static void nand_pre_save(void *opaque)
-{
- NANDFlashState *s = NAND(opaque);
-
- s->ioaddr_vmstate = s->ioaddr - s->io;
-}
-
-static int nand_post_load(void *opaque, int version_id)
-{
- NANDFlashState *s = NAND(opaque);
-
- if (s->ioaddr_vmstate > sizeof(s->io)) {
- return -EINVAL;
- }
- s->ioaddr = s->io + s->ioaddr_vmstate;
-
- return 0;
-}
-
-static const VMStateDescription vmstate_nand = {
- .name = "nand",
- .version_id = 1,
- .minimum_version_id = 1,
- .pre_save = nand_pre_save,
- .post_load = nand_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(cle, NANDFlashState),
- VMSTATE_UINT8(ale, NANDFlashState),
- VMSTATE_UINT8(ce, NANDFlashState),
- VMSTATE_UINT8(wp, NANDFlashState),
- VMSTATE_UINT8(gnd, NANDFlashState),
- VMSTATE_BUFFER(io, NANDFlashState),
- VMSTATE_UINT32(ioaddr_vmstate, NANDFlashState),
- VMSTATE_INT32(iolen, NANDFlashState),
- VMSTATE_UINT32(cmd, NANDFlashState),
- VMSTATE_UINT64(addr, NANDFlashState),
- VMSTATE_INT32(addrlen, NANDFlashState),
- VMSTATE_INT32(status, NANDFlashState),
- VMSTATE_INT32(offset, NANDFlashState),
- /* XXX: do we want to save s->storage too? */
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void nand_realize(DeviceState *dev, Error **errp)
-{
- int pagesize;
- NANDFlashState *s = NAND(dev);
-
- s->buswidth = nand_flash_ids[s->chip_id].width >> 3;
- s->size = nand_flash_ids[s->chip_id].size << 20;
- if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
- s->page_shift = 11;
- s->erase_shift = 6;
- } else {
- s->page_shift = nand_flash_ids[s->chip_id].page_shift;
- s->erase_shift = nand_flash_ids[s->chip_id].erase_shift;
- }
-
- switch (1 << s->page_shift) {
- case 256:
- nand_init_256(s);
- break;
- case 512:
- nand_init_512(s);
- break;
- case 2048:
- nand_init_2048(s);
- break;
- default:
- error_setg(errp, "Unsupported NAND block size %#x",
- 1 << s->page_shift);
- return;
- }
-
- pagesize = 1 << s->oob_shift;
- s->mem_oob = 1;
- if (s->blk) {
- if (blk_is_read_only(s->blk)) {
- error_setg(errp, "Can't use a read-only drive");
- return;
- }
- if (blk_getlength(s->blk) >=
- (s->pages << s->page_shift) + (s->pages << s->oob_shift)) {
- pagesize = 0;
- s->mem_oob = 0;
- }
- } else {
- pagesize += 1 << s->page_shift;
- }
- if (pagesize) {
- s->storage = (uint8_t *) memset(g_malloc(s->pages * pagesize),
- 0xff, s->pages * pagesize);
- }
- /* Give s->ioaddr a sane value in case we save state before it is used. */
- s->ioaddr = s->io;
-}
-
-static Property nand_properties[] = {
- DEFINE_PROP_UINT8("manufacturer_id", NANDFlashState, manf_id, 0),
- DEFINE_PROP_UINT8("chip_id", NANDFlashState, chip_id, 0),
- DEFINE_PROP_DRIVE("drive", NANDFlashState, blk),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void nand_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = nand_realize;
- dc->reset = nand_reset;
- dc->vmsd = &vmstate_nand;
- dc->props = nand_properties;
-}
-
-static const TypeInfo nand_info = {
- .name = TYPE_NAND,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(NANDFlashState),
- .class_init = nand_class_init,
-};
-
-static void nand_register_types(void)
-{
- type_register_static(&nand_info);
-}
-
-/*
- * Chip inputs are CLE, ALE, CE, WP, GND and eight I/O pins. Chip
- * outputs are R/B and eight I/O pins.
- *
- * CE, WP and R/B are active low.
- */
-void nand_setpins(DeviceState *dev, uint8_t cle, uint8_t ale,
- uint8_t ce, uint8_t wp, uint8_t gnd)
-{
- NANDFlashState *s = NAND(dev);
-
- s->cle = cle;
- s->ale = ale;
- s->ce = ce;
- s->wp = wp;
- s->gnd = gnd;
- if (wp) {
- s->status |= NAND_IOSTATUS_UNPROTCT;
- } else {
- s->status &= ~NAND_IOSTATUS_UNPROTCT;
- }
-}
-
-void nand_getpins(DeviceState *dev, int *rb)
-{
- *rb = 1;
-}
-
-void nand_setio(DeviceState *dev, uint32_t value)
-{
- int i;
- NANDFlashState *s = NAND(dev);
-
- if (!s->ce && s->cle) {
- if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
- if (s->cmd == NAND_CMD_READ0 && value == NAND_CMD_LPREAD2)
- return;
- if (value == NAND_CMD_RANDOMREAD1) {
- s->addr &= ~((1 << s->addr_shift) - 1);
- s->addrlen = 0;
- return;
- }
- }
- if (value == NAND_CMD_READ0) {
- s->offset = 0;
- } else if (value == NAND_CMD_READ1) {
- s->offset = 0x100;
- value = NAND_CMD_READ0;
- } else if (value == NAND_CMD_READ2) {
- s->offset = 1 << s->page_shift;
- value = NAND_CMD_READ0;
- }
-
- s->cmd = value;
-
- if (s->cmd == NAND_CMD_READSTATUS ||
- s->cmd == NAND_CMD_PAGEPROGRAM2 ||
- s->cmd == NAND_CMD_BLOCKERASE1 ||
- s->cmd == NAND_CMD_BLOCKERASE2 ||
- s->cmd == NAND_CMD_NOSERIALREAD2 ||
- s->cmd == NAND_CMD_RANDOMREAD2 ||
- s->cmd == NAND_CMD_RESET) {
- nand_command(s);
- }
-
- if (s->cmd != NAND_CMD_RANDOMREAD2) {
- s->addrlen = 0;
- }
- }
-
- if (s->ale) {
- unsigned int shift = s->addrlen * 8;
- uint64_t mask = ~(0xffull << shift);
- uint64_t v = (uint64_t)value << shift;
-
- s->addr = (s->addr & mask) | v;
- s->addrlen ++;
-
- switch (s->addrlen) {
- case 1:
- if (s->cmd == NAND_CMD_READID) {
- nand_command(s);
- }
- break;
- case 2: /* fix cache address as a byte address */
- s->addr <<= (s->buswidth - 1);
- break;
- case 3:
- if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
- (s->cmd == NAND_CMD_READ0 ||
- s->cmd == NAND_CMD_PAGEPROGRAM1)) {
- nand_command(s);
- }
- break;
- case 4:
- if ((nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
- nand_flash_ids[s->chip_id].size < 256 && /* 1Gb or less */
- (s->cmd == NAND_CMD_READ0 ||
- s->cmd == NAND_CMD_PAGEPROGRAM1)) {
- nand_command(s);
- }
- break;
- case 5:
- if ((nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
- nand_flash_ids[s->chip_id].size >= 256 && /* 2Gb or more */
- (s->cmd == NAND_CMD_READ0 ||
- s->cmd == NAND_CMD_PAGEPROGRAM1)) {
- nand_command(s);
- }
- break;
- default:
- break;
- }
- }
-
- if (!s->cle && !s->ale && s->cmd == NAND_CMD_PAGEPROGRAM1) {
- if (s->iolen < (1 << s->page_shift) + (1 << s->oob_shift)) {
- for (i = s->buswidth; i--; value >>= 8) {
- s->io[s->iolen ++] = (uint8_t) (value & 0xff);
- }
- }
- } else if (!s->cle && !s->ale && s->cmd == NAND_CMD_COPYBACKPRG1) {
- if ((s->addr & ((1 << s->addr_shift) - 1)) <
- (1 << s->page_shift) + (1 << s->oob_shift)) {
- for (i = s->buswidth; i--; s->addr++, value >>= 8) {
- s->io[s->iolen + (s->addr & ((1 << s->addr_shift) - 1))] =
- (uint8_t) (value & 0xff);
- }
- }
- }
-}
-
-uint32_t nand_getio(DeviceState *dev)
-{
- int offset;
- uint32_t x = 0;
- NANDFlashState *s = NAND(dev);
-
- /* Allow sequential reading */
- if (!s->iolen && s->cmd == NAND_CMD_READ0) {
- offset = (int) (s->addr & ((1 << s->addr_shift) - 1)) + s->offset;
- s->offset = 0;
-
- s->blk_load(s, s->addr, offset);
- if (s->gnd)
- s->iolen = (1 << s->page_shift) - offset;
- else
- s->iolen = (1 << s->page_shift) + (1 << s->oob_shift) - offset;
- }
-
- if (s->ce || s->iolen <= 0) {
- return 0;
- }
-
- for (offset = s->buswidth; offset--;) {
- x |= s->ioaddr[offset] << (offset << 3);
- }
- /* after receiving READ STATUS command all subsequent reads will
- * return the status register value until another command is issued
- */
- if (s->cmd != NAND_CMD_READSTATUS) {
- s->addr += s->buswidth;
- s->ioaddr += s->buswidth;
- s->iolen -= s->buswidth;
- }
- return x;
-}
-
-uint32_t nand_getbuswidth(DeviceState *dev)
-{
- NANDFlashState *s = (NANDFlashState *) dev;
- return s->buswidth << 3;
-}
-
-DeviceState *nand_init(BlockBackend *blk, int manf_id, int chip_id)
-{
- DeviceState *dev;
-
- if (nand_flash_ids[chip_id].size == 0) {
- hw_error("%s: Unsupported NAND chip ID.\n", __FUNCTION__);
- }
- dev = DEVICE(object_new(TYPE_NAND));
- qdev_prop_set_uint8(dev, "manufacturer_id", manf_id);
- qdev_prop_set_uint8(dev, "chip_id", chip_id);
- if (blk) {
- qdev_prop_set_drive(dev, "drive", blk, &error_fatal);
- }
-
- qdev_init_nofail(dev);
- return dev;
-}
-
-type_init(nand_register_types)
-
-#else
-
-/* Program a single page */
-static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *s)
-{
- uint64_t off, page, sector, soff;
- uint8_t iobuf[(PAGE_SECTORS + 2) * 0x200];
- if (PAGE(s->addr) >= s->pages)
- return;
-
- if (!s->blk) {
- mem_and(s->storage + PAGE_START(s->addr) + (s->addr & PAGE_MASK) +
- s->offset, s->io, s->iolen);
- } else if (s->mem_oob) {
- sector = SECTOR(s->addr);
- off = (s->addr & PAGE_MASK) + s->offset;
- soff = SECTOR_OFFSET(s->addr);
- if (blk_read(s->blk, sector, iobuf, PAGE_SECTORS) < 0) {
- printf("%s: read error in sector %" PRIu64 "\n", __func__, sector);
- return;
- }
-
- mem_and(iobuf + (soff | off), s->io, MIN(s->iolen, PAGE_SIZE - off));
- if (off + s->iolen > PAGE_SIZE) {
- page = PAGE(s->addr);
- mem_and(s->storage + (page << OOB_SHIFT), s->io + PAGE_SIZE - off,
- MIN(OOB_SIZE, off + s->iolen - PAGE_SIZE));
- }
-
- if (blk_write(s->blk, sector, iobuf, PAGE_SECTORS) < 0) {
- printf("%s: write error in sector %" PRIu64 "\n", __func__, sector);
- }
- } else {
- off = PAGE_START(s->addr) + (s->addr & PAGE_MASK) + s->offset;
- sector = off >> 9;
- soff = off & 0x1ff;
- if (blk_read(s->blk, sector, iobuf, PAGE_SECTORS + 2) < 0) {
- printf("%s: read error in sector %" PRIu64 "\n", __func__, sector);
- return;
- }
-
- mem_and(iobuf + soff, s->io, s->iolen);
-
- if (blk_write(s->blk, sector, iobuf, PAGE_SECTORS + 2) < 0) {
- printf("%s: write error in sector %" PRIu64 "\n", __func__, sector);
- }
- }
- s->offset = 0;
-}
-
-/* Erase a single block */
-static void glue(nand_blk_erase_, PAGE_SIZE)(NANDFlashState *s)
-{
- uint64_t i, page, addr;
- uint8_t iobuf[0x200] = { [0 ... 0x1ff] = 0xff, };
- addr = s->addr & ~((1 << (ADDR_SHIFT + s->erase_shift)) - 1);
-
- if (PAGE(addr) >= s->pages) {
- return;
- }
-
- if (!s->blk) {
- memset(s->storage + PAGE_START(addr),
- 0xff, (PAGE_SIZE + OOB_SIZE) << s->erase_shift);
- } else if (s->mem_oob) {
- memset(s->storage + (PAGE(addr) << OOB_SHIFT),
- 0xff, OOB_SIZE << s->erase_shift);
- i = SECTOR(addr);
- page = SECTOR(addr + (1 << (ADDR_SHIFT + s->erase_shift)));
- for (; i < page; i ++)
- if (blk_write(s->blk, i, iobuf, 1) < 0) {
- printf("%s: write error in sector %" PRIu64 "\n", __func__, i);
- }
- } else {
- addr = PAGE_START(addr);
- page = addr >> 9;
- if (blk_read(s->blk, page, iobuf, 1) < 0) {
- printf("%s: read error in sector %" PRIu64 "\n", __func__, page);
- }
- memset(iobuf + (addr & 0x1ff), 0xff, (~addr & 0x1ff) + 1);
- if (blk_write(s->blk, page, iobuf, 1) < 0) {
- printf("%s: write error in sector %" PRIu64 "\n", __func__, page);
- }
-
- memset(iobuf, 0xff, 0x200);
- i = (addr & ~0x1ff) + 0x200;
- for (addr += ((PAGE_SIZE + OOB_SIZE) << s->erase_shift) - 0x200;
- i < addr; i += 0x200) {
- if (blk_write(s->blk, i >> 9, iobuf, 1) < 0) {
- printf("%s: write error in sector %" PRIu64 "\n",
- __func__, i >> 9);
- }
- }
-
- page = i >> 9;
- if (blk_read(s->blk, page, iobuf, 1) < 0) {
- printf("%s: read error in sector %" PRIu64 "\n", __func__, page);
- }
- memset(iobuf, 0xff, ((addr - 1) & 0x1ff) + 1);
- if (blk_write(s->blk, page, iobuf, 1) < 0) {
- printf("%s: write error in sector %" PRIu64 "\n", __func__, page);
- }
- }
-}
-
-static void glue(nand_blk_load_, PAGE_SIZE)(NANDFlashState *s,
- uint64_t addr, int offset)
-{
- if (PAGE(addr) >= s->pages) {
- return;
- }
-
- if (s->blk) {
- if (s->mem_oob) {
- if (blk_read(s->blk, SECTOR(addr), s->io, PAGE_SECTORS) < 0) {
- printf("%s: read error in sector %" PRIu64 "\n",
- __func__, SECTOR(addr));
- }
- memcpy(s->io + SECTOR_OFFSET(s->addr) + PAGE_SIZE,
- s->storage + (PAGE(s->addr) << OOB_SHIFT),
- OOB_SIZE);
- s->ioaddr = s->io + SECTOR_OFFSET(s->addr) + offset;
- } else {
- if (blk_read(s->blk, PAGE_START(addr) >> 9,
- s->io, (PAGE_SECTORS + 2)) < 0) {
- printf("%s: read error in sector %" PRIu64 "\n",
- __func__, PAGE_START(addr) >> 9);
- }
- s->ioaddr = s->io + (PAGE_START(addr) & 0x1ff) + offset;
- }
- } else {
- memcpy(s->io, s->storage + PAGE_START(s->addr) +
- offset, PAGE_SIZE + OOB_SIZE - offset);
- s->ioaddr = s->io;
- }
-}
-
-static void glue(nand_init_, PAGE_SIZE)(NANDFlashState *s)
-{
- s->oob_shift = PAGE_SHIFT - 5;
- s->pages = s->size >> PAGE_SHIFT;
- s->addr_shift = ADDR_SHIFT;
-
- s->blk_erase = glue(nand_blk_erase_, PAGE_SIZE);
- s->blk_write = glue(nand_blk_write_, PAGE_SIZE);
- s->blk_load = glue(nand_blk_load_, PAGE_SIZE);
-}
-
-# undef PAGE_SIZE
-# undef PAGE_SHIFT
-# undef PAGE_SECTORS
-# undef ADDR_SHIFT
-#endif /* NAND_IO */
diff --git a/qemu/hw/block/nvme.c b/qemu/hw/block/nvme.c
deleted file mode 100644
index 173988ee8..000000000
--- a/qemu/hw/block/nvme.c
+++ /dev/null
@@ -1,942 +0,0 @@
-/*
- * QEMU NVM Express Controller
- *
- * Copyright (c) 2012, Intel Corporation
- *
- * Written by Keith Busch <keith.busch@intel.com>
- *
- * This code is licensed under the GNU GPL v2 or later.
- */
-
-/**
- * Reference Specs: http://www.nvmexpress.org, 1.1, 1.0e
- *
- * http://www.nvmexpress.org/resources/
- */
-
-/**
- * Usage: add options:
- * -drive file=<file>,if=none,id=<drive_id>
- * -device nvme,drive=<drive_id>,serial=<serial>,id=<id[optional]>
- */
-
-#include "qemu/osdep.h"
-#include <hw/block/block.h>
-#include <hw/hw.h>
-#include <hw/pci/msix.h>
-#include <hw/pci/pci.h>
-#include "sysemu/sysemu.h"
-#include "qapi/error.h"
-#include "qapi/visitor.h"
-#include "sysemu/block-backend.h"
-
-#include "nvme.h"
-
-static void nvme_process_sq(void *opaque);
-
-static int nvme_check_sqid(NvmeCtrl *n, uint16_t sqid)
-{
- return sqid < n->num_queues && n->sq[sqid] != NULL ? 0 : -1;
-}
-
-static int nvme_check_cqid(NvmeCtrl *n, uint16_t cqid)
-{
- return cqid < n->num_queues && n->cq[cqid] != NULL ? 0 : -1;
-}
-
-static void nvme_inc_cq_tail(NvmeCQueue *cq)
-{
- cq->tail++;
- if (cq->tail >= cq->size) {
- cq->tail = 0;
- cq->phase = !cq->phase;
- }
-}
-
-static void nvme_inc_sq_head(NvmeSQueue *sq)
-{
- sq->head = (sq->head + 1) % sq->size;
-}
-
-static uint8_t nvme_cq_full(NvmeCQueue *cq)
-{
- return (cq->tail + 1) % cq->size == cq->head;
-}
-
-static uint8_t nvme_sq_empty(NvmeSQueue *sq)
-{
- return sq->head == sq->tail;
-}
-
-static void nvme_isr_notify(NvmeCtrl *n, NvmeCQueue *cq)
-{
- if (cq->irq_enabled) {
- if (msix_enabled(&(n->parent_obj))) {
- msix_notify(&(n->parent_obj), cq->vector);
- } else {
- pci_irq_pulse(&n->parent_obj);
- }
- }
-}
-
-static uint16_t nvme_map_prp(QEMUSGList *qsg, uint64_t prp1, uint64_t prp2,
- uint32_t len, NvmeCtrl *n)
-{
- hwaddr trans_len = n->page_size - (prp1 % n->page_size);
- trans_len = MIN(len, trans_len);
- int num_prps = (len >> n->page_bits) + 1;
-
- if (!prp1) {
- return NVME_INVALID_FIELD | NVME_DNR;
- }
-
- pci_dma_sglist_init(qsg, &n->parent_obj, num_prps);
- qemu_sglist_add(qsg, prp1, trans_len);
- len -= trans_len;
- if (len) {
- if (!prp2) {
- goto unmap;
- }
- if (len > n->page_size) {
- uint64_t prp_list[n->max_prp_ents];
- uint32_t nents, prp_trans;
- int i = 0;
-
- nents = (len + n->page_size - 1) >> n->page_bits;
- prp_trans = MIN(n->max_prp_ents, nents) * sizeof(uint64_t);
- pci_dma_read(&n->parent_obj, prp2, (void *)prp_list, prp_trans);
- while (len != 0) {
- uint64_t prp_ent = le64_to_cpu(prp_list[i]);
-
- if (i == n->max_prp_ents - 1 && len > n->page_size) {
- if (!prp_ent || prp_ent & (n->page_size - 1)) {
- goto unmap;
- }
-
- i = 0;
- nents = (len + n->page_size - 1) >> n->page_bits;
- prp_trans = MIN(n->max_prp_ents, nents) * sizeof(uint64_t);
- pci_dma_read(&n->parent_obj, prp_ent, (void *)prp_list,
- prp_trans);
- prp_ent = le64_to_cpu(prp_list[i]);
- }
-
- if (!prp_ent || prp_ent & (n->page_size - 1)) {
- goto unmap;
- }
-
- trans_len = MIN(len, n->page_size);
- qemu_sglist_add(qsg, prp_ent, trans_len);
- len -= trans_len;
- i++;
- }
- } else {
- if (prp2 & (n->page_size - 1)) {
- goto unmap;
- }
- qemu_sglist_add(qsg, prp2, len);
- }
- }
- return NVME_SUCCESS;
-
- unmap:
- qemu_sglist_destroy(qsg);
- return NVME_INVALID_FIELD | NVME_DNR;
-}
-
-static uint16_t nvme_dma_read_prp(NvmeCtrl *n, uint8_t *ptr, uint32_t len,
- uint64_t prp1, uint64_t prp2)
-{
- QEMUSGList qsg;
-
- if (nvme_map_prp(&qsg, prp1, prp2, len, n)) {
- return NVME_INVALID_FIELD | NVME_DNR;
- }
- if (dma_buf_read(ptr, len, &qsg)) {
- qemu_sglist_destroy(&qsg);
- return NVME_INVALID_FIELD | NVME_DNR;
- }
- qemu_sglist_destroy(&qsg);
- return NVME_SUCCESS;
-}
-
-static void nvme_post_cqes(void *opaque)
-{
- NvmeCQueue *cq = opaque;
- NvmeCtrl *n = cq->ctrl;
- NvmeRequest *req, *next;
-
- QTAILQ_FOREACH_SAFE(req, &cq->req_list, entry, next) {
- NvmeSQueue *sq;
- hwaddr addr;
-
- if (nvme_cq_full(cq)) {
- break;
- }
-
- QTAILQ_REMOVE(&cq->req_list, req, entry);
- sq = req->sq;
- req->cqe.status = cpu_to_le16((req->status << 1) | cq->phase);
- req->cqe.sq_id = cpu_to_le16(sq->sqid);
- req->cqe.sq_head = cpu_to_le16(sq->head);
- addr = cq->dma_addr + cq->tail * n->cqe_size;
- nvme_inc_cq_tail(cq);
- pci_dma_write(&n->parent_obj, addr, (void *)&req->cqe,
- sizeof(req->cqe));
- QTAILQ_INSERT_TAIL(&sq->req_list, req, entry);
- }
- nvme_isr_notify(n, cq);
-}
-
-static void nvme_enqueue_req_completion(NvmeCQueue *cq, NvmeRequest *req)
-{
- assert(cq->cqid == req->sq->cqid);
- QTAILQ_REMOVE(&req->sq->out_req_list, req, entry);
- QTAILQ_INSERT_TAIL(&cq->req_list, req, entry);
- timer_mod(cq->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 500);
-}
-
-static void nvme_rw_cb(void *opaque, int ret)
-{
- NvmeRequest *req = opaque;
- NvmeSQueue *sq = req->sq;
- NvmeCtrl *n = sq->ctrl;
- NvmeCQueue *cq = n->cq[sq->cqid];
-
- if (!ret) {
- block_acct_done(blk_get_stats(n->conf.blk), &req->acct);
- req->status = NVME_SUCCESS;
- } else {
- block_acct_failed(blk_get_stats(n->conf.blk), &req->acct);
- req->status = NVME_INTERNAL_DEV_ERROR;
- }
- if (req->has_sg) {
- qemu_sglist_destroy(&req->qsg);
- }
- nvme_enqueue_req_completion(cq, req);
-}
-
-static uint16_t nvme_flush(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
- NvmeRequest *req)
-{
- req->has_sg = false;
- block_acct_start(blk_get_stats(n->conf.blk), &req->acct, 0,
- BLOCK_ACCT_FLUSH);
- req->aiocb = blk_aio_flush(n->conf.blk, nvme_rw_cb, req);
-
- return NVME_NO_COMPLETE;
-}
-
-static uint16_t nvme_rw(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
- NvmeRequest *req)
-{
- NvmeRwCmd *rw = (NvmeRwCmd *)cmd;
- uint32_t nlb = le32_to_cpu(rw->nlb) + 1;
- uint64_t slba = le64_to_cpu(rw->slba);
- uint64_t prp1 = le64_to_cpu(rw->prp1);
- uint64_t prp2 = le64_to_cpu(rw->prp2);
-
- uint8_t lba_index = NVME_ID_NS_FLBAS_INDEX(ns->id_ns.flbas);
- uint8_t data_shift = ns->id_ns.lbaf[lba_index].ds;
- uint64_t data_size = (uint64_t)nlb << data_shift;
- uint64_t aio_slba = slba << (data_shift - BDRV_SECTOR_BITS);
- int is_write = rw->opcode == NVME_CMD_WRITE ? 1 : 0;
- enum BlockAcctType acct = is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ;
-
- if ((slba + nlb) > ns->id_ns.nsze) {
- block_acct_invalid(blk_get_stats(n->conf.blk), acct);
- return NVME_LBA_RANGE | NVME_DNR;
- }
-
- if (nvme_map_prp(&req->qsg, prp1, prp2, data_size, n)) {
- block_acct_invalid(blk_get_stats(n->conf.blk), acct);
- return NVME_INVALID_FIELD | NVME_DNR;
- }
-
- assert((nlb << data_shift) == req->qsg.size);
-
- req->has_sg = true;
- dma_acct_start(n->conf.blk, &req->acct, &req->qsg, acct);
- req->aiocb = is_write ?
- dma_blk_write(n->conf.blk, &req->qsg, aio_slba, nvme_rw_cb, req) :
- dma_blk_read(n->conf.blk, &req->qsg, aio_slba, nvme_rw_cb, req);
-
- return NVME_NO_COMPLETE;
-}
-
-static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
-{
- NvmeNamespace *ns;
- uint32_t nsid = le32_to_cpu(cmd->nsid);
-
- if (nsid == 0 || nsid > n->num_namespaces) {
- return NVME_INVALID_NSID | NVME_DNR;
- }
-
- ns = &n->namespaces[nsid - 1];
- switch (cmd->opcode) {
- case NVME_CMD_FLUSH:
- return nvme_flush(n, ns, cmd, req);
- case NVME_CMD_WRITE:
- case NVME_CMD_READ:
- return nvme_rw(n, ns, cmd, req);
- default:
- return NVME_INVALID_OPCODE | NVME_DNR;
- }
-}
-
-static void nvme_free_sq(NvmeSQueue *sq, NvmeCtrl *n)
-{
- n->sq[sq->sqid] = NULL;
- timer_del(sq->timer);
- timer_free(sq->timer);
- g_free(sq->io_req);
- if (sq->sqid) {
- g_free(sq);
- }
-}
-
-static uint16_t nvme_del_sq(NvmeCtrl *n, NvmeCmd *cmd)
-{
- NvmeDeleteQ *c = (NvmeDeleteQ *)cmd;
- NvmeRequest *req, *next;
- NvmeSQueue *sq;
- NvmeCQueue *cq;
- uint16_t qid = le16_to_cpu(c->qid);
-
- if (!qid || nvme_check_sqid(n, qid)) {
- return NVME_INVALID_QID | NVME_DNR;
- }
-
- sq = n->sq[qid];
- while (!QTAILQ_EMPTY(&sq->out_req_list)) {
- req = QTAILQ_FIRST(&sq->out_req_list);
- assert(req->aiocb);
- blk_aio_cancel(req->aiocb);
- }
- if (!nvme_check_cqid(n, sq->cqid)) {
- cq = n->cq[sq->cqid];
- QTAILQ_REMOVE(&cq->sq_list, sq, entry);
-
- nvme_post_cqes(cq);
- QTAILQ_FOREACH_SAFE(req, &cq->req_list, entry, next) {
- if (req->sq == sq) {
- QTAILQ_REMOVE(&cq->req_list, req, entry);
- QTAILQ_INSERT_TAIL(&sq->req_list, req, entry);
- }
- }
- }
-
- nvme_free_sq(sq, n);
- return NVME_SUCCESS;
-}
-
-static void nvme_init_sq(NvmeSQueue *sq, NvmeCtrl *n, uint64_t dma_addr,
- uint16_t sqid, uint16_t cqid, uint16_t size)
-{
- int i;
- NvmeCQueue *cq;
-
- sq->ctrl = n;
- sq->dma_addr = dma_addr;
- sq->sqid = sqid;
- sq->size = size;
- sq->cqid = cqid;
- sq->head = sq->tail = 0;
- sq->io_req = g_new(NvmeRequest, sq->size);
-
- QTAILQ_INIT(&sq->req_list);
- QTAILQ_INIT(&sq->out_req_list);
- for (i = 0; i < sq->size; i++) {
- sq->io_req[i].sq = sq;
- QTAILQ_INSERT_TAIL(&(sq->req_list), &sq->io_req[i], entry);
- }
- sq->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, nvme_process_sq, sq);
-
- assert(n->cq[cqid]);
- cq = n->cq[cqid];
- QTAILQ_INSERT_TAIL(&(cq->sq_list), sq, entry);
- n->sq[sqid] = sq;
-}
-
-static uint16_t nvme_create_sq(NvmeCtrl *n, NvmeCmd *cmd)
-{
- NvmeSQueue *sq;
- NvmeCreateSq *c = (NvmeCreateSq *)cmd;
-
- uint16_t cqid = le16_to_cpu(c->cqid);
- uint16_t sqid = le16_to_cpu(c->sqid);
- uint16_t qsize = le16_to_cpu(c->qsize);
- uint16_t qflags = le16_to_cpu(c->sq_flags);
- uint64_t prp1 = le64_to_cpu(c->prp1);
-
- if (!cqid || nvme_check_cqid(n, cqid)) {
- return NVME_INVALID_CQID | NVME_DNR;
- }
- if (!sqid || (sqid && !nvme_check_sqid(n, sqid))) {
- return NVME_INVALID_QID | NVME_DNR;
- }
- if (!qsize || qsize > NVME_CAP_MQES(n->bar.cap)) {
- return NVME_MAX_QSIZE_EXCEEDED | NVME_DNR;
- }
- if (!prp1 || prp1 & (n->page_size - 1)) {
- return NVME_INVALID_FIELD | NVME_DNR;
- }
- if (!(NVME_SQ_FLAGS_PC(qflags))) {
- return NVME_INVALID_FIELD | NVME_DNR;
- }
- sq = g_malloc0(sizeof(*sq));
- nvme_init_sq(sq, n, prp1, sqid, cqid, qsize + 1);
- return NVME_SUCCESS;
-}
-
-static void nvme_free_cq(NvmeCQueue *cq, NvmeCtrl *n)
-{
- n->cq[cq->cqid] = NULL;
- timer_del(cq->timer);
- timer_free(cq->timer);
- msix_vector_unuse(&n->parent_obj, cq->vector);
- if (cq->cqid) {
- g_free(cq);
- }
-}
-
-static uint16_t nvme_del_cq(NvmeCtrl *n, NvmeCmd *cmd)
-{
- NvmeDeleteQ *c = (NvmeDeleteQ *)cmd;
- NvmeCQueue *cq;
- uint16_t qid = le16_to_cpu(c->qid);
-
- if (!qid || nvme_check_cqid(n, qid)) {
- return NVME_INVALID_CQID | NVME_DNR;
- }
-
- cq = n->cq[qid];
- if (!QTAILQ_EMPTY(&cq->sq_list)) {
- return NVME_INVALID_QUEUE_DEL;
- }
- nvme_free_cq(cq, n);
- return NVME_SUCCESS;
-}
-
-static void nvme_init_cq(NvmeCQueue *cq, NvmeCtrl *n, uint64_t dma_addr,
- uint16_t cqid, uint16_t vector, uint16_t size, uint16_t irq_enabled)
-{
- cq->ctrl = n;
- cq->cqid = cqid;
- cq->size = size;
- cq->dma_addr = dma_addr;
- cq->phase = 1;
- cq->irq_enabled = irq_enabled;
- cq->vector = vector;
- cq->head = cq->tail = 0;
- QTAILQ_INIT(&cq->req_list);
- QTAILQ_INIT(&cq->sq_list);
- msix_vector_use(&n->parent_obj, cq->vector);
- n->cq[cqid] = cq;
- cq->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, nvme_post_cqes, cq);
-}
-
-static uint16_t nvme_create_cq(NvmeCtrl *n, NvmeCmd *cmd)
-{
- NvmeCQueue *cq;
- NvmeCreateCq *c = (NvmeCreateCq *)cmd;
- uint16_t cqid = le16_to_cpu(c->cqid);
- uint16_t vector = le16_to_cpu(c->irq_vector);
- uint16_t qsize = le16_to_cpu(c->qsize);
- uint16_t qflags = le16_to_cpu(c->cq_flags);
- uint64_t prp1 = le64_to_cpu(c->prp1);
-
- if (!cqid || (cqid && !nvme_check_cqid(n, cqid))) {
- return NVME_INVALID_CQID | NVME_DNR;
- }
- if (!qsize || qsize > NVME_CAP_MQES(n->bar.cap)) {
- return NVME_MAX_QSIZE_EXCEEDED | NVME_DNR;
- }
- if (!prp1) {
- return NVME_INVALID_FIELD | NVME_DNR;
- }
- if (vector > n->num_queues) {
- return NVME_INVALID_IRQ_VECTOR | NVME_DNR;
- }
- if (!(NVME_CQ_FLAGS_PC(qflags))) {
- return NVME_INVALID_FIELD | NVME_DNR;
- }
-
- cq = g_malloc0(sizeof(*cq));
- nvme_init_cq(cq, n, prp1, cqid, vector, qsize + 1,
- NVME_CQ_FLAGS_IEN(qflags));
- return NVME_SUCCESS;
-}
-
-static uint16_t nvme_identify(NvmeCtrl *n, NvmeCmd *cmd)
-{
- NvmeNamespace *ns;
- NvmeIdentify *c = (NvmeIdentify *)cmd;
- uint32_t cns = le32_to_cpu(c->cns);
- uint32_t nsid = le32_to_cpu(c->nsid);
- uint64_t prp1 = le64_to_cpu(c->prp1);
- uint64_t prp2 = le64_to_cpu(c->prp2);
-
- if (cns) {
- return nvme_dma_read_prp(n, (uint8_t *)&n->id_ctrl, sizeof(n->id_ctrl),
- prp1, prp2);
- }
- if (nsid == 0 || nsid > n->num_namespaces) {
- return NVME_INVALID_NSID | NVME_DNR;
- }
-
- ns = &n->namespaces[nsid - 1];
- return nvme_dma_read_prp(n, (uint8_t *)&ns->id_ns, sizeof(ns->id_ns),
- prp1, prp2);
-}
-
-static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
-{
- uint32_t dw10 = le32_to_cpu(cmd->cdw10);
- uint32_t result;
-
- switch (dw10) {
- case NVME_VOLATILE_WRITE_CACHE:
- result = blk_enable_write_cache(n->conf.blk);
- break;
- case NVME_NUMBER_OF_QUEUES:
- result = cpu_to_le32((n->num_queues - 1) | ((n->num_queues - 1) << 16));
- break;
- default:
- return NVME_INVALID_FIELD | NVME_DNR;
- }
-
- req->cqe.result = result;
- return NVME_SUCCESS;
-}
-
-static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
-{
- uint32_t dw10 = le32_to_cpu(cmd->cdw10);
- uint32_t dw11 = le32_to_cpu(cmd->cdw11);
-
- switch (dw10) {
- case NVME_VOLATILE_WRITE_CACHE:
- blk_set_enable_write_cache(n->conf.blk, dw11 & 1);
- break;
- case NVME_NUMBER_OF_QUEUES:
- req->cqe.result =
- cpu_to_le32((n->num_queues - 1) | ((n->num_queues - 1) << 16));
- break;
- default:
- return NVME_INVALID_FIELD | NVME_DNR;
- }
- return NVME_SUCCESS;
-}
-
-static uint16_t nvme_admin_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
-{
- switch (cmd->opcode) {
- case NVME_ADM_CMD_DELETE_SQ:
- return nvme_del_sq(n, cmd);
- case NVME_ADM_CMD_CREATE_SQ:
- return nvme_create_sq(n, cmd);
- case NVME_ADM_CMD_DELETE_CQ:
- return nvme_del_cq(n, cmd);
- case NVME_ADM_CMD_CREATE_CQ:
- return nvme_create_cq(n, cmd);
- case NVME_ADM_CMD_IDENTIFY:
- return nvme_identify(n, cmd);
- case NVME_ADM_CMD_SET_FEATURES:
- return nvme_set_feature(n, cmd, req);
- case NVME_ADM_CMD_GET_FEATURES:
- return nvme_get_feature(n, cmd, req);
- default:
- return NVME_INVALID_OPCODE | NVME_DNR;
- }
-}
-
-static void nvme_process_sq(void *opaque)
-{
- NvmeSQueue *sq = opaque;
- NvmeCtrl *n = sq->ctrl;
- NvmeCQueue *cq = n->cq[sq->cqid];
-
- uint16_t status;
- hwaddr addr;
- NvmeCmd cmd;
- NvmeRequest *req;
-
- while (!(nvme_sq_empty(sq) || QTAILQ_EMPTY(&sq->req_list))) {
- addr = sq->dma_addr + sq->head * n->sqe_size;
- pci_dma_read(&n->parent_obj, addr, (void *)&cmd, sizeof(cmd));
- nvme_inc_sq_head(sq);
-
- req = QTAILQ_FIRST(&sq->req_list);
- QTAILQ_REMOVE(&sq->req_list, req, entry);
- QTAILQ_INSERT_TAIL(&sq->out_req_list, req, entry);
- memset(&req->cqe, 0, sizeof(req->cqe));
- req->cqe.cid = cmd.cid;
-
- status = sq->sqid ? nvme_io_cmd(n, &cmd, req) :
- nvme_admin_cmd(n, &cmd, req);
- if (status != NVME_NO_COMPLETE) {
- req->status = status;
- nvme_enqueue_req_completion(cq, req);
- }
- }
-}
-
-static void nvme_clear_ctrl(NvmeCtrl *n)
-{
- int i;
-
- for (i = 0; i < n->num_queues; i++) {
- if (n->sq[i] != NULL) {
- nvme_free_sq(n->sq[i], n);
- }
- }
- for (i = 0; i < n->num_queues; i++) {
- if (n->cq[i] != NULL) {
- nvme_free_cq(n->cq[i], n);
- }
- }
-
- blk_flush(n->conf.blk);
- n->bar.cc = 0;
-}
-
-static int nvme_start_ctrl(NvmeCtrl *n)
-{
- uint32_t page_bits = NVME_CC_MPS(n->bar.cc) + 12;
- uint32_t page_size = 1 << page_bits;
-
- if (n->cq[0] || n->sq[0] || !n->bar.asq || !n->bar.acq ||
- n->bar.asq & (page_size - 1) || n->bar.acq & (page_size - 1) ||
- NVME_CC_MPS(n->bar.cc) < NVME_CAP_MPSMIN(n->bar.cap) ||
- NVME_CC_MPS(n->bar.cc) > NVME_CAP_MPSMAX(n->bar.cap) ||
- NVME_CC_IOCQES(n->bar.cc) < NVME_CTRL_CQES_MIN(n->id_ctrl.cqes) ||
- NVME_CC_IOCQES(n->bar.cc) > NVME_CTRL_CQES_MAX(n->id_ctrl.cqes) ||
- NVME_CC_IOSQES(n->bar.cc) < NVME_CTRL_SQES_MIN(n->id_ctrl.sqes) ||
- NVME_CC_IOSQES(n->bar.cc) > NVME_CTRL_SQES_MAX(n->id_ctrl.sqes) ||
- !NVME_AQA_ASQS(n->bar.aqa) || !NVME_AQA_ACQS(n->bar.aqa)) {
- return -1;
- }
-
- n->page_bits = page_bits;
- n->page_size = page_size;
- n->max_prp_ents = n->page_size / sizeof(uint64_t);
- n->cqe_size = 1 << NVME_CC_IOCQES(n->bar.cc);
- n->sqe_size = 1 << NVME_CC_IOSQES(n->bar.cc);
- nvme_init_cq(&n->admin_cq, n, n->bar.acq, 0, 0,
- NVME_AQA_ACQS(n->bar.aqa) + 1, 1);
- nvme_init_sq(&n->admin_sq, n, n->bar.asq, 0, 0,
- NVME_AQA_ASQS(n->bar.aqa) + 1);
-
- return 0;
-}
-
-static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data,
- unsigned size)
-{
- switch (offset) {
- case 0xc:
- n->bar.intms |= data & 0xffffffff;
- n->bar.intmc = n->bar.intms;
- break;
- case 0x10:
- n->bar.intms &= ~(data & 0xffffffff);
- n->bar.intmc = n->bar.intms;
- break;
- case 0x14:
- /* Windows first sends data, then sends enable bit */
- if (!NVME_CC_EN(data) && !NVME_CC_EN(n->bar.cc) &&
- !NVME_CC_SHN(data) && !NVME_CC_SHN(n->bar.cc))
- {
- n->bar.cc = data;
- }
-
- if (NVME_CC_EN(data) && !NVME_CC_EN(n->bar.cc)) {
- n->bar.cc = data;
- if (nvme_start_ctrl(n)) {
- n->bar.csts = NVME_CSTS_FAILED;
- } else {
- n->bar.csts = NVME_CSTS_READY;
- }
- } else if (!NVME_CC_EN(data) && NVME_CC_EN(n->bar.cc)) {
- nvme_clear_ctrl(n);
- n->bar.csts &= ~NVME_CSTS_READY;
- }
- if (NVME_CC_SHN(data) && !(NVME_CC_SHN(n->bar.cc))) {
- nvme_clear_ctrl(n);
- n->bar.cc = data;
- n->bar.csts |= NVME_CSTS_SHST_COMPLETE;
- } else if (!NVME_CC_SHN(data) && NVME_CC_SHN(n->bar.cc)) {
- n->bar.csts &= ~NVME_CSTS_SHST_COMPLETE;
- n->bar.cc = data;
- }
- break;
- case 0x24:
- n->bar.aqa = data & 0xffffffff;
- break;
- case 0x28:
- n->bar.asq = data;
- break;
- case 0x2c:
- n->bar.asq |= data << 32;
- break;
- case 0x30:
- n->bar.acq = data;
- break;
- case 0x34:
- n->bar.acq |= data << 32;
- break;
- default:
- break;
- }
-}
-
-static uint64_t nvme_mmio_read(void *opaque, hwaddr addr, unsigned size)
-{
- NvmeCtrl *n = (NvmeCtrl *)opaque;
- uint8_t *ptr = (uint8_t *)&n->bar;
- uint64_t val = 0;
-
- if (addr < sizeof(n->bar)) {
- memcpy(&val, ptr + addr, size);
- }
- return val;
-}
-
-static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val)
-{
- uint32_t qid;
-
- if (addr & ((1 << 2) - 1)) {
- return;
- }
-
- if (((addr - 0x1000) >> 2) & 1) {
- uint16_t new_head = val & 0xffff;
- int start_sqs;
- NvmeCQueue *cq;
-
- qid = (addr - (0x1000 + (1 << 2))) >> 3;
- if (nvme_check_cqid(n, qid)) {
- return;
- }
-
- cq = n->cq[qid];
- if (new_head >= cq->size) {
- return;
- }
-
- start_sqs = nvme_cq_full(cq) ? 1 : 0;
- cq->head = new_head;
- if (start_sqs) {
- NvmeSQueue *sq;
- QTAILQ_FOREACH(sq, &cq->sq_list, entry) {
- timer_mod(sq->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 500);
- }
- timer_mod(cq->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 500);
- }
-
- if (cq->tail != cq->head) {
- nvme_isr_notify(n, cq);
- }
- } else {
- uint16_t new_tail = val & 0xffff;
- NvmeSQueue *sq;
-
- qid = (addr - 0x1000) >> 3;
- if (nvme_check_sqid(n, qid)) {
- return;
- }
-
- sq = n->sq[qid];
- if (new_tail >= sq->size) {
- return;
- }
-
- sq->tail = new_tail;
- timer_mod(sq->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 500);
- }
-}
-
-static void nvme_mmio_write(void *opaque, hwaddr addr, uint64_t data,
- unsigned size)
-{
- NvmeCtrl *n = (NvmeCtrl *)opaque;
- if (addr < sizeof(n->bar)) {
- nvme_write_bar(n, addr, data, size);
- } else if (addr >= 0x1000) {
- nvme_process_db(n, addr, data);
- }
-}
-
-static const MemoryRegionOps nvme_mmio_ops = {
- .read = nvme_mmio_read,
- .write = nvme_mmio_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .impl = {
- .min_access_size = 2,
- .max_access_size = 8,
- },
-};
-
-static int nvme_init(PCIDevice *pci_dev)
-{
- NvmeCtrl *n = NVME(pci_dev);
- NvmeIdCtrl *id = &n->id_ctrl;
-
- int i;
- int64_t bs_size;
- uint8_t *pci_conf;
-
- if (!n->conf.blk) {
- return -1;
- }
-
- bs_size = blk_getlength(n->conf.blk);
- if (bs_size < 0) {
- return -1;
- }
-
- blkconf_serial(&n->conf, &n->serial);
- if (!n->serial) {
- return -1;
- }
- blkconf_blocksizes(&n->conf);
-
- pci_conf = pci_dev->config;
- pci_conf[PCI_INTERRUPT_PIN] = 1;
- pci_config_set_prog_interface(pci_dev->config, 0x2);
- pci_config_set_class(pci_dev->config, PCI_CLASS_STORAGE_EXPRESS);
- pcie_endpoint_cap_init(&n->parent_obj, 0x80);
-
- n->num_namespaces = 1;
- n->num_queues = 64;
- n->reg_size = pow2ceil(0x1004 + 2 * (n->num_queues + 1) * 4);
- n->ns_size = bs_size / (uint64_t)n->num_namespaces;
-
- n->namespaces = g_new0(NvmeNamespace, n->num_namespaces);
- n->sq = g_new0(NvmeSQueue *, n->num_queues);
- n->cq = g_new0(NvmeCQueue *, n->num_queues);
-
- memory_region_init_io(&n->iomem, OBJECT(n), &nvme_mmio_ops, n,
- "nvme", n->reg_size);
- pci_register_bar(&n->parent_obj, 0,
- PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64,
- &n->iomem);
- msix_init_exclusive_bar(&n->parent_obj, n->num_queues, 4);
-
- id->vid = cpu_to_le16(pci_get_word(pci_conf + PCI_VENDOR_ID));
- id->ssvid = cpu_to_le16(pci_get_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID));
- strpadcpy((char *)id->mn, sizeof(id->mn), "QEMU NVMe Ctrl", ' ');
- strpadcpy((char *)id->fr, sizeof(id->fr), "1.0", ' ');
- strpadcpy((char *)id->sn, sizeof(id->sn), n->serial, ' ');
- id->rab = 6;
- id->ieee[0] = 0x00;
- id->ieee[1] = 0x02;
- id->ieee[2] = 0xb3;
- id->oacs = cpu_to_le16(0);
- id->frmw = 7 << 1;
- id->lpa = 1 << 0;
- id->sqes = (0x6 << 4) | 0x6;
- id->cqes = (0x4 << 4) | 0x4;
- id->nn = cpu_to_le32(n->num_namespaces);
- id->psd[0].mp = cpu_to_le16(0x9c4);
- id->psd[0].enlat = cpu_to_le32(0x10);
- id->psd[0].exlat = cpu_to_le32(0x4);
- if (blk_enable_write_cache(n->conf.blk)) {
- id->vwc = 1;
- }
-
- n->bar.cap = 0;
- NVME_CAP_SET_MQES(n->bar.cap, 0x7ff);
- NVME_CAP_SET_CQR(n->bar.cap, 1);
- NVME_CAP_SET_AMS(n->bar.cap, 1);
- NVME_CAP_SET_TO(n->bar.cap, 0xf);
- NVME_CAP_SET_CSS(n->bar.cap, 1);
- NVME_CAP_SET_MPSMAX(n->bar.cap, 4);
-
- n->bar.vs = 0x00010100;
- n->bar.intmc = n->bar.intms = 0;
-
- for (i = 0; i < n->num_namespaces; i++) {
- NvmeNamespace *ns = &n->namespaces[i];
- NvmeIdNs *id_ns = &ns->id_ns;
- id_ns->nsfeat = 0;
- id_ns->nlbaf = 0;
- id_ns->flbas = 0;
- id_ns->mc = 0;
- id_ns->dpc = 0;
- id_ns->dps = 0;
- id_ns->lbaf[0].ds = BDRV_SECTOR_BITS;
- id_ns->ncap = id_ns->nuse = id_ns->nsze =
- cpu_to_le64(n->ns_size >>
- id_ns->lbaf[NVME_ID_NS_FLBAS_INDEX(ns->id_ns.flbas)].ds);
- }
- return 0;
-}
-
-static void nvme_exit(PCIDevice *pci_dev)
-{
- NvmeCtrl *n = NVME(pci_dev);
-
- nvme_clear_ctrl(n);
- g_free(n->namespaces);
- g_free(n->cq);
- g_free(n->sq);
- msix_uninit_exclusive_bar(pci_dev);
-}
-
-static Property nvme_props[] = {
- DEFINE_BLOCK_PROPERTIES(NvmeCtrl, conf),
- DEFINE_PROP_STRING("serial", NvmeCtrl, serial),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static const VMStateDescription nvme_vmstate = {
- .name = "nvme",
- .unmigratable = 1,
-};
-
-static void nvme_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
- PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc);
-
- pc->init = nvme_init;
- pc->exit = nvme_exit;
- pc->class_id = PCI_CLASS_STORAGE_EXPRESS;
- pc->vendor_id = PCI_VENDOR_ID_INTEL;
- pc->device_id = 0x5845;
- pc->revision = 1;
- pc->is_express = 1;
-
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
- dc->desc = "Non-Volatile Memory Express";
- dc->props = nvme_props;
- dc->vmsd = &nvme_vmstate;
-}
-
-static void nvme_instance_init(Object *obj)
-{
- NvmeCtrl *s = NVME(obj);
-
- device_add_bootindex_property(obj, &s->conf.bootindex,
- "bootindex", "/namespace@1,0",
- DEVICE(obj), &error_abort);
-}
-
-static const TypeInfo nvme_info = {
- .name = "nvme",
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(NvmeCtrl),
- .class_init = nvme_class_init,
- .instance_init = nvme_instance_init,
-};
-
-static void nvme_register_types(void)
-{
- type_register_static(&nvme_info);
-}
-
-type_init(nvme_register_types)
diff --git a/qemu/hw/block/nvme.h b/qemu/hw/block/nvme.h
deleted file mode 100644
index 8fb0c1075..000000000
--- a/qemu/hw/block/nvme.h
+++ /dev/null
@@ -1,713 +0,0 @@
-#ifndef HW_NVME_H
-#define HW_NVME_H
-#include "qemu/cutils.h"
-
-typedef struct NvmeBar {
- uint64_t cap;
- uint32_t vs;
- uint32_t intms;
- uint32_t intmc;
- uint32_t cc;
- uint32_t rsvd1;
- uint32_t csts;
- uint32_t nssrc;
- uint32_t aqa;
- uint64_t asq;
- uint64_t acq;
-} NvmeBar;
-
-enum NvmeCapShift {
- CAP_MQES_SHIFT = 0,
- CAP_CQR_SHIFT = 16,
- CAP_AMS_SHIFT = 17,
- CAP_TO_SHIFT = 24,
- CAP_DSTRD_SHIFT = 32,
- CAP_NSSRS_SHIFT = 33,
- CAP_CSS_SHIFT = 37,
- CAP_MPSMIN_SHIFT = 48,
- CAP_MPSMAX_SHIFT = 52,
-};
-
-enum NvmeCapMask {
- CAP_MQES_MASK = 0xffff,
- CAP_CQR_MASK = 0x1,
- CAP_AMS_MASK = 0x3,
- CAP_TO_MASK = 0xff,
- CAP_DSTRD_MASK = 0xf,
- CAP_NSSRS_MASK = 0x1,
- CAP_CSS_MASK = 0xff,
- CAP_MPSMIN_MASK = 0xf,
- CAP_MPSMAX_MASK = 0xf,
-};
-
-#define NVME_CAP_MQES(cap) (((cap) >> CAP_MQES_SHIFT) & CAP_MQES_MASK)
-#define NVME_CAP_CQR(cap) (((cap) >> CAP_CQR_SHIFT) & CAP_CQR_MASK)
-#define NVME_CAP_AMS(cap) (((cap) >> CAP_AMS_SHIFT) & CAP_AMS_MASK)
-#define NVME_CAP_TO(cap) (((cap) >> CAP_TO_SHIFT) & CAP_TO_MASK)
-#define NVME_CAP_DSTRD(cap) (((cap) >> CAP_DSTRD_SHIFT) & CAP_DSTRD_MASK)
-#define NVME_CAP_NSSRS(cap) (((cap) >> CAP_NSSRS_SHIFT) & CAP_NSSRS_MASK)
-#define NVME_CAP_CSS(cap) (((cap) >> CAP_CSS_SHIFT) & CAP_CSS_MASK)
-#define NVME_CAP_MPSMIN(cap)(((cap) >> CAP_MPSMIN_SHIFT) & CAP_MPSMIN_MASK)
-#define NVME_CAP_MPSMAX(cap)(((cap) >> CAP_MPSMAX_SHIFT) & CAP_MPSMAX_MASK)
-
-#define NVME_CAP_SET_MQES(cap, val) (cap |= (uint64_t)(val & CAP_MQES_MASK) \
- << CAP_MQES_SHIFT)
-#define NVME_CAP_SET_CQR(cap, val) (cap |= (uint64_t)(val & CAP_CQR_MASK) \
- << CAP_CQR_SHIFT)
-#define NVME_CAP_SET_AMS(cap, val) (cap |= (uint64_t)(val & CAP_AMS_MASK) \
- << CAP_AMS_SHIFT)
-#define NVME_CAP_SET_TO(cap, val) (cap |= (uint64_t)(val & CAP_TO_MASK) \
- << CAP_TO_SHIFT)
-#define NVME_CAP_SET_DSTRD(cap, val) (cap |= (uint64_t)(val & CAP_DSTRD_MASK) \
- << CAP_DSTRD_SHIFT)
-#define NVME_CAP_SET_NSSRS(cap, val) (cap |= (uint64_t)(val & CAP_NSSRS_MASK) \
- << CAP_NSSRS_SHIFT)
-#define NVME_CAP_SET_CSS(cap, val) (cap |= (uint64_t)(val & CAP_CSS_MASK) \
- << CAP_CSS_SHIFT)
-#define NVME_CAP_SET_MPSMIN(cap, val) (cap |= (uint64_t)(val & CAP_MPSMIN_MASK)\
- << CAP_MPSMIN_SHIFT)
-#define NVME_CAP_SET_MPSMAX(cap, val) (cap |= (uint64_t)(val & CAP_MPSMAX_MASK)\
- << CAP_MPSMAX_SHIFT)
-
-enum NvmeCcShift {
- CC_EN_SHIFT = 0,
- CC_CSS_SHIFT = 4,
- CC_MPS_SHIFT = 7,
- CC_AMS_SHIFT = 11,
- CC_SHN_SHIFT = 14,
- CC_IOSQES_SHIFT = 16,
- CC_IOCQES_SHIFT = 20,
-};
-
-enum NvmeCcMask {
- CC_EN_MASK = 0x1,
- CC_CSS_MASK = 0x7,
- CC_MPS_MASK = 0xf,
- CC_AMS_MASK = 0x7,
- CC_SHN_MASK = 0x3,
- CC_IOSQES_MASK = 0xf,
- CC_IOCQES_MASK = 0xf,
-};
-
-#define NVME_CC_EN(cc) ((cc >> CC_EN_SHIFT) & CC_EN_MASK)
-#define NVME_CC_CSS(cc) ((cc >> CC_CSS_SHIFT) & CC_CSS_MASK)
-#define NVME_CC_MPS(cc) ((cc >> CC_MPS_SHIFT) & CC_MPS_MASK)
-#define NVME_CC_AMS(cc) ((cc >> CC_AMS_SHIFT) & CC_AMS_MASK)
-#define NVME_CC_SHN(cc) ((cc >> CC_SHN_SHIFT) & CC_SHN_MASK)
-#define NVME_CC_IOSQES(cc) ((cc >> CC_IOSQES_SHIFT) & CC_IOSQES_MASK)
-#define NVME_CC_IOCQES(cc) ((cc >> CC_IOCQES_SHIFT) & CC_IOCQES_MASK)
-
-enum NvmeCstsShift {
- CSTS_RDY_SHIFT = 0,
- CSTS_CFS_SHIFT = 1,
- CSTS_SHST_SHIFT = 2,
- CSTS_NSSRO_SHIFT = 4,
-};
-
-enum NvmeCstsMask {
- CSTS_RDY_MASK = 0x1,
- CSTS_CFS_MASK = 0x1,
- CSTS_SHST_MASK = 0x3,
- CSTS_NSSRO_MASK = 0x1,
-};
-
-enum NvmeCsts {
- NVME_CSTS_READY = 1 << CSTS_RDY_SHIFT,
- NVME_CSTS_FAILED = 1 << CSTS_CFS_SHIFT,
- NVME_CSTS_SHST_NORMAL = 0 << CSTS_SHST_SHIFT,
- NVME_CSTS_SHST_PROGRESS = 1 << CSTS_SHST_SHIFT,
- NVME_CSTS_SHST_COMPLETE = 2 << CSTS_SHST_SHIFT,
- NVME_CSTS_NSSRO = 1 << CSTS_NSSRO_SHIFT,
-};
-
-#define NVME_CSTS_RDY(csts) ((csts >> CSTS_RDY_SHIFT) & CSTS_RDY_MASK)
-#define NVME_CSTS_CFS(csts) ((csts >> CSTS_CFS_SHIFT) & CSTS_CFS_MASK)
-#define NVME_CSTS_SHST(csts) ((csts >> CSTS_SHST_SHIFT) & CSTS_SHST_MASK)
-#define NVME_CSTS_NSSRO(csts) ((csts >> CSTS_NSSRO_SHIFT) & CSTS_NSSRO_MASK)
-
-enum NvmeAqaShift {
- AQA_ASQS_SHIFT = 0,
- AQA_ACQS_SHIFT = 16,
-};
-
-enum NvmeAqaMask {
- AQA_ASQS_MASK = 0xfff,
- AQA_ACQS_MASK = 0xfff,
-};
-
-#define NVME_AQA_ASQS(aqa) ((aqa >> AQA_ASQS_SHIFT) & AQA_ASQS_MASK)
-#define NVME_AQA_ACQS(aqa) ((aqa >> AQA_ACQS_SHIFT) & AQA_ACQS_MASK)
-
-typedef struct NvmeCmd {
- uint8_t opcode;
- uint8_t fuse;
- uint16_t cid;
- uint32_t nsid;
- uint64_t res1;
- uint64_t mptr;
- uint64_t prp1;
- uint64_t prp2;
- uint32_t cdw10;
- uint32_t cdw11;
- uint32_t cdw12;
- uint32_t cdw13;
- uint32_t cdw14;
- uint32_t cdw15;
-} NvmeCmd;
-
-enum NvmeAdminCommands {
- NVME_ADM_CMD_DELETE_SQ = 0x00,
- NVME_ADM_CMD_CREATE_SQ = 0x01,
- NVME_ADM_CMD_GET_LOG_PAGE = 0x02,
- NVME_ADM_CMD_DELETE_CQ = 0x04,
- NVME_ADM_CMD_CREATE_CQ = 0x05,
- NVME_ADM_CMD_IDENTIFY = 0x06,
- NVME_ADM_CMD_ABORT = 0x08,
- NVME_ADM_CMD_SET_FEATURES = 0x09,
- NVME_ADM_CMD_GET_FEATURES = 0x0a,
- NVME_ADM_CMD_ASYNC_EV_REQ = 0x0c,
- NVME_ADM_CMD_ACTIVATE_FW = 0x10,
- NVME_ADM_CMD_DOWNLOAD_FW = 0x11,
- NVME_ADM_CMD_FORMAT_NVM = 0x80,
- NVME_ADM_CMD_SECURITY_SEND = 0x81,
- NVME_ADM_CMD_SECURITY_RECV = 0x82,
-};
-
-enum NvmeIoCommands {
- NVME_CMD_FLUSH = 0x00,
- NVME_CMD_WRITE = 0x01,
- NVME_CMD_READ = 0x02,
- NVME_CMD_WRITE_UNCOR = 0x04,
- NVME_CMD_COMPARE = 0x05,
- NVME_CMD_DSM = 0x09,
-};
-
-typedef struct NvmeDeleteQ {
- uint8_t opcode;
- uint8_t flags;
- uint16_t cid;
- uint32_t rsvd1[9];
- uint16_t qid;
- uint16_t rsvd10;
- uint32_t rsvd11[5];
-} NvmeDeleteQ;
-
-typedef struct NvmeCreateCq {
- uint8_t opcode;
- uint8_t flags;
- uint16_t cid;
- uint32_t rsvd1[5];
- uint64_t prp1;
- uint64_t rsvd8;
- uint16_t cqid;
- uint16_t qsize;
- uint16_t cq_flags;
- uint16_t irq_vector;
- uint32_t rsvd12[4];
-} NvmeCreateCq;
-
-#define NVME_CQ_FLAGS_PC(cq_flags) (cq_flags & 0x1)
-#define NVME_CQ_FLAGS_IEN(cq_flags) ((cq_flags >> 1) & 0x1)
-
-typedef struct NvmeCreateSq {
- uint8_t opcode;
- uint8_t flags;
- uint16_t cid;
- uint32_t rsvd1[5];
- uint64_t prp1;
- uint64_t rsvd8;
- uint16_t sqid;
- uint16_t qsize;
- uint16_t sq_flags;
- uint16_t cqid;
- uint32_t rsvd12[4];
-} NvmeCreateSq;
-
-#define NVME_SQ_FLAGS_PC(sq_flags) (sq_flags & 0x1)
-#define NVME_SQ_FLAGS_QPRIO(sq_flags) ((sq_flags >> 1) & 0x3)
-
-enum NvmeQueueFlags {
- NVME_Q_PC = 1,
- NVME_Q_PRIO_URGENT = 0,
- NVME_Q_PRIO_HIGH = 1,
- NVME_Q_PRIO_NORMAL = 2,
- NVME_Q_PRIO_LOW = 3,
-};
-
-typedef struct NvmeIdentify {
- uint8_t opcode;
- uint8_t flags;
- uint16_t cid;
- uint32_t nsid;
- uint64_t rsvd2[2];
- uint64_t prp1;
- uint64_t prp2;
- uint32_t cns;
- uint32_t rsvd11[5];
-} NvmeIdentify;
-
-typedef struct NvmeRwCmd {
- uint8_t opcode;
- uint8_t flags;
- uint16_t cid;
- uint32_t nsid;
- uint64_t rsvd2;
- uint64_t mptr;
- uint64_t prp1;
- uint64_t prp2;
- uint64_t slba;
- uint16_t nlb;
- uint16_t control;
- uint32_t dsmgmt;
- uint32_t reftag;
- uint16_t apptag;
- uint16_t appmask;
-} NvmeRwCmd;
-
-enum {
- NVME_RW_LR = 1 << 15,
- NVME_RW_FUA = 1 << 14,
- NVME_RW_DSM_FREQ_UNSPEC = 0,
- NVME_RW_DSM_FREQ_TYPICAL = 1,
- NVME_RW_DSM_FREQ_RARE = 2,
- NVME_RW_DSM_FREQ_READS = 3,
- NVME_RW_DSM_FREQ_WRITES = 4,
- NVME_RW_DSM_FREQ_RW = 5,
- NVME_RW_DSM_FREQ_ONCE = 6,
- NVME_RW_DSM_FREQ_PREFETCH = 7,
- NVME_RW_DSM_FREQ_TEMP = 8,
- NVME_RW_DSM_LATENCY_NONE = 0 << 4,
- NVME_RW_DSM_LATENCY_IDLE = 1 << 4,
- NVME_RW_DSM_LATENCY_NORM = 2 << 4,
- NVME_RW_DSM_LATENCY_LOW = 3 << 4,
- NVME_RW_DSM_SEQ_REQ = 1 << 6,
- NVME_RW_DSM_COMPRESSED = 1 << 7,
- NVME_RW_PRINFO_PRACT = 1 << 13,
- NVME_RW_PRINFO_PRCHK_GUARD = 1 << 12,
- NVME_RW_PRINFO_PRCHK_APP = 1 << 11,
- NVME_RW_PRINFO_PRCHK_REF = 1 << 10,
-};
-
-typedef struct NvmeDsmCmd {
- uint8_t opcode;
- uint8_t flags;
- uint16_t cid;
- uint32_t nsid;
- uint64_t rsvd2[2];
- uint64_t prp1;
- uint64_t prp2;
- uint32_t nr;
- uint32_t attributes;
- uint32_t rsvd12[4];
-} NvmeDsmCmd;
-
-enum {
- NVME_DSMGMT_IDR = 1 << 0,
- NVME_DSMGMT_IDW = 1 << 1,
- NVME_DSMGMT_AD = 1 << 2,
-};
-
-typedef struct NvmeDsmRange {
- uint32_t cattr;
- uint32_t nlb;
- uint64_t slba;
-} NvmeDsmRange;
-
-enum NvmeAsyncEventRequest {
- NVME_AER_TYPE_ERROR = 0,
- NVME_AER_TYPE_SMART = 1,
- NVME_AER_TYPE_IO_SPECIFIC = 6,
- NVME_AER_TYPE_VENDOR_SPECIFIC = 7,
- NVME_AER_INFO_ERR_INVALID_SQ = 0,
- NVME_AER_INFO_ERR_INVALID_DB = 1,
- NVME_AER_INFO_ERR_DIAG_FAIL = 2,
- NVME_AER_INFO_ERR_PERS_INTERNAL_ERR = 3,
- NVME_AER_INFO_ERR_TRANS_INTERNAL_ERR = 4,
- NVME_AER_INFO_ERR_FW_IMG_LOAD_ERR = 5,
- NVME_AER_INFO_SMART_RELIABILITY = 0,
- NVME_AER_INFO_SMART_TEMP_THRESH = 1,
- NVME_AER_INFO_SMART_SPARE_THRESH = 2,
-};
-
-typedef struct NvmeAerResult {
- uint8_t event_type;
- uint8_t event_info;
- uint8_t log_page;
- uint8_t resv;
-} NvmeAerResult;
-
-typedef struct NvmeCqe {
- uint32_t result;
- uint32_t rsvd;
- uint16_t sq_head;
- uint16_t sq_id;
- uint16_t cid;
- uint16_t status;
-} NvmeCqe;
-
-enum NvmeStatusCodes {
- NVME_SUCCESS = 0x0000,
- NVME_INVALID_OPCODE = 0x0001,
- NVME_INVALID_FIELD = 0x0002,
- NVME_CID_CONFLICT = 0x0003,
- NVME_DATA_TRAS_ERROR = 0x0004,
- NVME_POWER_LOSS_ABORT = 0x0005,
- NVME_INTERNAL_DEV_ERROR = 0x0006,
- NVME_CMD_ABORT_REQ = 0x0007,
- NVME_CMD_ABORT_SQ_DEL = 0x0008,
- NVME_CMD_ABORT_FAILED_FUSE = 0x0009,
- NVME_CMD_ABORT_MISSING_FUSE = 0x000a,
- NVME_INVALID_NSID = 0x000b,
- NVME_CMD_SEQ_ERROR = 0x000c,
- NVME_LBA_RANGE = 0x0080,
- NVME_CAP_EXCEEDED = 0x0081,
- NVME_NS_NOT_READY = 0x0082,
- NVME_NS_RESV_CONFLICT = 0x0083,
- NVME_INVALID_CQID = 0x0100,
- NVME_INVALID_QID = 0x0101,
- NVME_MAX_QSIZE_EXCEEDED = 0x0102,
- NVME_ACL_EXCEEDED = 0x0103,
- NVME_RESERVED = 0x0104,
- NVME_AER_LIMIT_EXCEEDED = 0x0105,
- NVME_INVALID_FW_SLOT = 0x0106,
- NVME_INVALID_FW_IMAGE = 0x0107,
- NVME_INVALID_IRQ_VECTOR = 0x0108,
- NVME_INVALID_LOG_ID = 0x0109,
- NVME_INVALID_FORMAT = 0x010a,
- NVME_FW_REQ_RESET = 0x010b,
- NVME_INVALID_QUEUE_DEL = 0x010c,
- NVME_FID_NOT_SAVEABLE = 0x010d,
- NVME_FID_NOT_NSID_SPEC = 0x010f,
- NVME_FW_REQ_SUSYSTEM_RESET = 0x0110,
- NVME_CONFLICTING_ATTRS = 0x0180,
- NVME_INVALID_PROT_INFO = 0x0181,
- NVME_WRITE_TO_RO = 0x0182,
- NVME_WRITE_FAULT = 0x0280,
- NVME_UNRECOVERED_READ = 0x0281,
- NVME_E2E_GUARD_ERROR = 0x0282,
- NVME_E2E_APP_ERROR = 0x0283,
- NVME_E2E_REF_ERROR = 0x0284,
- NVME_CMP_FAILURE = 0x0285,
- NVME_ACCESS_DENIED = 0x0286,
- NVME_MORE = 0x2000,
- NVME_DNR = 0x4000,
- NVME_NO_COMPLETE = 0xffff,
-};
-
-typedef struct NvmeFwSlotInfoLog {
- uint8_t afi;
- uint8_t reserved1[7];
- uint8_t frs1[8];
- uint8_t frs2[8];
- uint8_t frs3[8];
- uint8_t frs4[8];
- uint8_t frs5[8];
- uint8_t frs6[8];
- uint8_t frs7[8];
- uint8_t reserved2[448];
-} NvmeFwSlotInfoLog;
-
-typedef struct NvmeErrorLog {
- uint64_t error_count;
- uint16_t sqid;
- uint16_t cid;
- uint16_t status_field;
- uint16_t param_error_location;
- uint64_t lba;
- uint32_t nsid;
- uint8_t vs;
- uint8_t resv[35];
-} NvmeErrorLog;
-
-typedef struct NvmeSmartLog {
- uint8_t critical_warning;
- uint8_t temperature[2];
- uint8_t available_spare;
- uint8_t available_spare_threshold;
- uint8_t percentage_used;
- uint8_t reserved1[26];
- uint64_t data_units_read[2];
- uint64_t data_units_written[2];
- uint64_t host_read_commands[2];
- uint64_t host_write_commands[2];
- uint64_t controller_busy_time[2];
- uint64_t power_cycles[2];
- uint64_t power_on_hours[2];
- uint64_t unsafe_shutdowns[2];
- uint64_t media_errors[2];
- uint64_t number_of_error_log_entries[2];
- uint8_t reserved2[320];
-} NvmeSmartLog;
-
-enum NvmeSmartWarn {
- NVME_SMART_SPARE = 1 << 0,
- NVME_SMART_TEMPERATURE = 1 << 1,
- NVME_SMART_RELIABILITY = 1 << 2,
- NVME_SMART_MEDIA_READ_ONLY = 1 << 3,
- NVME_SMART_FAILED_VOLATILE_MEDIA = 1 << 4,
-};
-
-enum LogIdentifier {
- NVME_LOG_ERROR_INFO = 0x01,
- NVME_LOG_SMART_INFO = 0x02,
- NVME_LOG_FW_SLOT_INFO = 0x03,
-};
-
-typedef struct NvmePSD {
- uint16_t mp;
- uint16_t reserved;
- uint32_t enlat;
- uint32_t exlat;
- uint8_t rrt;
- uint8_t rrl;
- uint8_t rwt;
- uint8_t rwl;
- uint8_t resv[16];
-} NvmePSD;
-
-typedef struct NvmeIdCtrl {
- uint16_t vid;
- uint16_t ssvid;
- uint8_t sn[20];
- uint8_t mn[40];
- uint8_t fr[8];
- uint8_t rab;
- uint8_t ieee[3];
- uint8_t cmic;
- uint8_t mdts;
- uint8_t rsvd255[178];
- uint16_t oacs;
- uint8_t acl;
- uint8_t aerl;
- uint8_t frmw;
- uint8_t lpa;
- uint8_t elpe;
- uint8_t npss;
- uint8_t rsvd511[248];
- uint8_t sqes;
- uint8_t cqes;
- uint16_t rsvd515;
- uint32_t nn;
- uint16_t oncs;
- uint16_t fuses;
- uint8_t fna;
- uint8_t vwc;
- uint16_t awun;
- uint16_t awupf;
- uint8_t rsvd703[174];
- uint8_t rsvd2047[1344];
- NvmePSD psd[32];
- uint8_t vs[1024];
-} NvmeIdCtrl;
-
-enum NvmeIdCtrlOacs {
- NVME_OACS_SECURITY = 1 << 0,
- NVME_OACS_FORMAT = 1 << 1,
- NVME_OACS_FW = 1 << 2,
-};
-
-enum NvmeIdCtrlOncs {
- NVME_ONCS_COMPARE = 1 << 0,
- NVME_ONCS_WRITE_UNCORR = 1 << 1,
- NVME_ONCS_DSM = 1 << 2,
- NVME_ONCS_WRITE_ZEROS = 1 << 3,
- NVME_ONCS_FEATURES = 1 << 4,
- NVME_ONCS_RESRVATIONS = 1 << 5,
-};
-
-#define NVME_CTRL_SQES_MIN(sqes) ((sqes) & 0xf)
-#define NVME_CTRL_SQES_MAX(sqes) (((sqes) >> 4) & 0xf)
-#define NVME_CTRL_CQES_MIN(cqes) ((cqes) & 0xf)
-#define NVME_CTRL_CQES_MAX(cqes) (((cqes) >> 4) & 0xf)
-
-typedef struct NvmeFeatureVal {
- uint32_t arbitration;
- uint32_t power_mgmt;
- uint32_t temp_thresh;
- uint32_t err_rec;
- uint32_t volatile_wc;
- uint32_t num_queues;
- uint32_t int_coalescing;
- uint32_t *int_vector_config;
- uint32_t write_atomicity;
- uint32_t async_config;
- uint32_t sw_prog_marker;
-} NvmeFeatureVal;
-
-#define NVME_ARB_AB(arb) (arb & 0x7)
-#define NVME_ARB_LPW(arb) ((arb >> 8) & 0xff)
-#define NVME_ARB_MPW(arb) ((arb >> 16) & 0xff)
-#define NVME_ARB_HPW(arb) ((arb >> 24) & 0xff)
-
-#define NVME_INTC_THR(intc) (intc & 0xff)
-#define NVME_INTC_TIME(intc) ((intc >> 8) & 0xff)
-
-enum NvmeFeatureIds {
- NVME_ARBITRATION = 0x1,
- NVME_POWER_MANAGEMENT = 0x2,
- NVME_LBA_RANGE_TYPE = 0x3,
- NVME_TEMPERATURE_THRESHOLD = 0x4,
- NVME_ERROR_RECOVERY = 0x5,
- NVME_VOLATILE_WRITE_CACHE = 0x6,
- NVME_NUMBER_OF_QUEUES = 0x7,
- NVME_INTERRUPT_COALESCING = 0x8,
- NVME_INTERRUPT_VECTOR_CONF = 0x9,
- NVME_WRITE_ATOMICITY = 0xa,
- NVME_ASYNCHRONOUS_EVENT_CONF = 0xb,
- NVME_SOFTWARE_PROGRESS_MARKER = 0x80
-};
-
-typedef struct NvmeRangeType {
- uint8_t type;
- uint8_t attributes;
- uint8_t rsvd2[14];
- uint64_t slba;
- uint64_t nlb;
- uint8_t guid[16];
- uint8_t rsvd48[16];
-} NvmeRangeType;
-
-typedef struct NvmeLBAF {
- uint16_t ms;
- uint8_t ds;
- uint8_t rp;
-} NvmeLBAF;
-
-typedef struct NvmeIdNs {
- uint64_t nsze;
- uint64_t ncap;
- uint64_t nuse;
- uint8_t nsfeat;
- uint8_t nlbaf;
- uint8_t flbas;
- uint8_t mc;
- uint8_t dpc;
- uint8_t dps;
- uint8_t res30[98];
- NvmeLBAF lbaf[16];
- uint8_t res192[192];
- uint8_t vs[3712];
-} NvmeIdNs;
-
-#define NVME_ID_NS_NSFEAT_THIN(nsfeat) ((nsfeat & 0x1))
-#define NVME_ID_NS_FLBAS_EXTENDED(flbas) ((flbas >> 4) & 0x1)
-#define NVME_ID_NS_FLBAS_INDEX(flbas) ((flbas & 0xf))
-#define NVME_ID_NS_MC_SEPARATE(mc) ((mc >> 1) & 0x1)
-#define NVME_ID_NS_MC_EXTENDED(mc) ((mc & 0x1))
-#define NVME_ID_NS_DPC_LAST_EIGHT(dpc) ((dpc >> 4) & 0x1)
-#define NVME_ID_NS_DPC_FIRST_EIGHT(dpc) ((dpc >> 3) & 0x1)
-#define NVME_ID_NS_DPC_TYPE_3(dpc) ((dpc >> 2) & 0x1)
-#define NVME_ID_NS_DPC_TYPE_2(dpc) ((dpc >> 1) & 0x1)
-#define NVME_ID_NS_DPC_TYPE_1(dpc) ((dpc & 0x1))
-#define NVME_ID_NS_DPC_TYPE_MASK 0x7
-
-enum NvmeIdNsDps {
- DPS_TYPE_NONE = 0,
- DPS_TYPE_1 = 1,
- DPS_TYPE_2 = 2,
- DPS_TYPE_3 = 3,
- DPS_TYPE_MASK = 0x7,
- DPS_FIRST_EIGHT = 8,
-};
-
-static inline void _nvme_check_size(void)
-{
- QEMU_BUILD_BUG_ON(sizeof(NvmeAerResult) != 4);
- QEMU_BUILD_BUG_ON(sizeof(NvmeCqe) != 16);
- QEMU_BUILD_BUG_ON(sizeof(NvmeDsmRange) != 16);
- QEMU_BUILD_BUG_ON(sizeof(NvmeCmd) != 64);
- QEMU_BUILD_BUG_ON(sizeof(NvmeDeleteQ) != 64);
- QEMU_BUILD_BUG_ON(sizeof(NvmeCreateCq) != 64);
- QEMU_BUILD_BUG_ON(sizeof(NvmeCreateSq) != 64);
- QEMU_BUILD_BUG_ON(sizeof(NvmeIdentify) != 64);
- QEMU_BUILD_BUG_ON(sizeof(NvmeRwCmd) != 64);
- QEMU_BUILD_BUG_ON(sizeof(NvmeDsmCmd) != 64);
- QEMU_BUILD_BUG_ON(sizeof(NvmeRangeType) != 64);
- QEMU_BUILD_BUG_ON(sizeof(NvmeErrorLog) != 64);
- QEMU_BUILD_BUG_ON(sizeof(NvmeFwSlotInfoLog) != 512);
- QEMU_BUILD_BUG_ON(sizeof(NvmeSmartLog) != 512);
- QEMU_BUILD_BUG_ON(sizeof(NvmeIdCtrl) != 4096);
- QEMU_BUILD_BUG_ON(sizeof(NvmeIdNs) != 4096);
-}
-
-typedef struct NvmeAsyncEvent {
- QSIMPLEQ_ENTRY(NvmeAsyncEvent) entry;
- NvmeAerResult result;
-} NvmeAsyncEvent;
-
-typedef struct NvmeRequest {
- struct NvmeSQueue *sq;
- BlockAIOCB *aiocb;
- uint16_t status;
- bool has_sg;
- NvmeCqe cqe;
- BlockAcctCookie acct;
- QEMUSGList qsg;
- QTAILQ_ENTRY(NvmeRequest)entry;
-} NvmeRequest;
-
-typedef struct NvmeSQueue {
- struct NvmeCtrl *ctrl;
- uint16_t sqid;
- uint16_t cqid;
- uint32_t head;
- uint32_t tail;
- uint32_t size;
- uint64_t dma_addr;
- QEMUTimer *timer;
- NvmeRequest *io_req;
- QTAILQ_HEAD(sq_req_list, NvmeRequest) req_list;
- QTAILQ_HEAD(out_req_list, NvmeRequest) out_req_list;
- QTAILQ_ENTRY(NvmeSQueue) entry;
-} NvmeSQueue;
-
-typedef struct NvmeCQueue {
- struct NvmeCtrl *ctrl;
- uint8_t phase;
- uint16_t cqid;
- uint16_t irq_enabled;
- uint32_t head;
- uint32_t tail;
- uint32_t vector;
- uint32_t size;
- uint64_t dma_addr;
- QEMUTimer *timer;
- QTAILQ_HEAD(sq_list, NvmeSQueue) sq_list;
- QTAILQ_HEAD(cq_req_list, NvmeRequest) req_list;
-} NvmeCQueue;
-
-typedef struct NvmeNamespace {
- NvmeIdNs id_ns;
-} NvmeNamespace;
-
-#define TYPE_NVME "nvme"
-#define NVME(obj) \
- OBJECT_CHECK(NvmeCtrl, (obj), TYPE_NVME)
-
-typedef struct NvmeCtrl {
- PCIDevice parent_obj;
- MemoryRegion iomem;
- NvmeBar bar;
- BlockConf conf;
-
- uint32_t page_size;
- uint16_t page_bits;
- uint16_t max_prp_ents;
- uint16_t cqe_size;
- uint16_t sqe_size;
- uint32_t reg_size;
- uint32_t num_namespaces;
- uint32_t num_queues;
- uint32_t max_q_ents;
- uint64_t ns_size;
-
- char *serial;
- NvmeNamespace *namespaces;
- NvmeSQueue **sq;
- NvmeCQueue **cq;
- NvmeSQueue admin_sq;
- NvmeCQueue admin_cq;
- NvmeIdCtrl id_ctrl;
-} NvmeCtrl;
-
-#endif /* HW_NVME_H */
diff --git a/qemu/hw/block/onenand.c b/qemu/hw/block/onenand.c
deleted file mode 100644
index 883f4b1fa..000000000
--- a/qemu/hw/block/onenand.c
+++ /dev/null
@@ -1,850 +0,0 @@
-/*
- * OneNAND flash memories emulation.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "hw/hw.h"
-#include "hw/block/flash.h"
-#include "hw/irq.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
-#include "exec/memory.h"
-#include "exec/address-spaces.h"
-#include "hw/sysbus.h"
-#include "qemu/error-report.h"
-
-/* 11 for 2kB-page OneNAND ("2nd generation") and 10 for 1kB-page chips */
-#define PAGE_SHIFT 11
-
-/* Fixed */
-#define BLOCK_SHIFT (PAGE_SHIFT + 6)
-
-#define TYPE_ONE_NAND "onenand"
-#define ONE_NAND(obj) OBJECT_CHECK(OneNANDState, (obj), TYPE_ONE_NAND)
-
-typedef struct OneNANDState {
- SysBusDevice parent_obj;
-
- struct {
- uint16_t man;
- uint16_t dev;
- uint16_t ver;
- } id;
- int shift;
- hwaddr base;
- qemu_irq intr;
- qemu_irq rdy;
- BlockBackend *blk;
- BlockBackend *blk_cur;
- uint8_t *image;
- uint8_t *otp;
- uint8_t *current;
- MemoryRegion ram;
- MemoryRegion mapped_ram;
- uint8_t current_direction;
- uint8_t *boot[2];
- uint8_t *data[2][2];
- MemoryRegion iomem;
- MemoryRegion container;
- int cycle;
- int otpmode;
-
- uint16_t addr[8];
- uint16_t unladdr[8];
- int bufaddr;
- int count;
- uint16_t command;
- uint16_t config[2];
- uint16_t status;
- uint16_t intstatus;
- uint16_t wpstatus;
-
- ECCState ecc;
-
- int density_mask;
- int secs;
- int secs_cur;
- int blocks;
- uint8_t *blockwp;
-} OneNANDState;
-
-enum {
- ONEN_BUF_BLOCK = 0,
- ONEN_BUF_BLOCK2 = 1,
- ONEN_BUF_DEST_BLOCK = 2,
- ONEN_BUF_DEST_PAGE = 3,
- ONEN_BUF_PAGE = 7,
-};
-
-enum {
- ONEN_ERR_CMD = 1 << 10,
- ONEN_ERR_ERASE = 1 << 11,
- ONEN_ERR_PROG = 1 << 12,
- ONEN_ERR_LOAD = 1 << 13,
-};
-
-enum {
- ONEN_INT_RESET = 1 << 4,
- ONEN_INT_ERASE = 1 << 5,
- ONEN_INT_PROG = 1 << 6,
- ONEN_INT_LOAD = 1 << 7,
- ONEN_INT = 1 << 15,
-};
-
-enum {
- ONEN_LOCK_LOCKTIGHTEN = 1 << 0,
- ONEN_LOCK_LOCKED = 1 << 1,
- ONEN_LOCK_UNLOCKED = 1 << 2,
-};
-
-static void onenand_mem_setup(OneNANDState *s)
-{
- /* XXX: We should use IO_MEM_ROMD but we broke it earlier...
- * Both 0x0000 ... 0x01ff and 0x8000 ... 0x800f can be used to
- * write boot commands. Also take note of the BWPS bit. */
- memory_region_init(&s->container, OBJECT(s), "onenand",
- 0x10000 << s->shift);
- memory_region_add_subregion(&s->container, 0, &s->iomem);
- memory_region_init_alias(&s->mapped_ram, OBJECT(s), "onenand-mapped-ram",
- &s->ram, 0x0200 << s->shift,
- 0xbe00 << s->shift);
- memory_region_add_subregion_overlap(&s->container,
- 0x0200 << s->shift,
- &s->mapped_ram,
- 1);
-}
-
-static void onenand_intr_update(OneNANDState *s)
-{
- qemu_set_irq(s->intr, ((s->intstatus >> 15) ^ (~s->config[0] >> 6)) & 1);
-}
-
-static void onenand_pre_save(void *opaque)
-{
- OneNANDState *s = opaque;
- if (s->current == s->otp) {
- s->current_direction = 1;
- } else if (s->current == s->image) {
- s->current_direction = 2;
- } else {
- s->current_direction = 0;
- }
-}
-
-static int onenand_post_load(void *opaque, int version_id)
-{
- OneNANDState *s = opaque;
- switch (s->current_direction) {
- case 0:
- break;
- case 1:
- s->current = s->otp;
- break;
- case 2:
- s->current = s->image;
- break;
- default:
- return -1;
- }
- onenand_intr_update(s);
- return 0;
-}
-
-static const VMStateDescription vmstate_onenand = {
- .name = "onenand",
- .version_id = 1,
- .minimum_version_id = 1,
- .pre_save = onenand_pre_save,
- .post_load = onenand_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(current_direction, OneNANDState),
- VMSTATE_INT32(cycle, OneNANDState),
- VMSTATE_INT32(otpmode, OneNANDState),
- VMSTATE_UINT16_ARRAY(addr, OneNANDState, 8),
- VMSTATE_UINT16_ARRAY(unladdr, OneNANDState, 8),
- VMSTATE_INT32(bufaddr, OneNANDState),
- VMSTATE_INT32(count, OneNANDState),
- VMSTATE_UINT16(command, OneNANDState),
- VMSTATE_UINT16_ARRAY(config, OneNANDState, 2),
- VMSTATE_UINT16(status, OneNANDState),
- VMSTATE_UINT16(intstatus, OneNANDState),
- VMSTATE_UINT16(wpstatus, OneNANDState),
- VMSTATE_INT32(secs_cur, OneNANDState),
- VMSTATE_PARTIAL_VBUFFER(blockwp, OneNANDState, blocks),
- VMSTATE_UINT8(ecc.cp, OneNANDState),
- VMSTATE_UINT16_ARRAY(ecc.lp, OneNANDState, 2),
- VMSTATE_UINT16(ecc.count, OneNANDState),
- VMSTATE_BUFFER_POINTER_UNSAFE(otp, OneNANDState, 0,
- ((64 + 2) << PAGE_SHIFT)),
- VMSTATE_END_OF_LIST()
- }
-};
-
-/* Hot reset (Reset OneNAND command) or warm reset (RP pin low) */
-static void onenand_reset(OneNANDState *s, int cold)
-{
- memset(&s->addr, 0, sizeof(s->addr));
- s->command = 0;
- s->count = 1;
- s->bufaddr = 0;
- s->config[0] = 0x40c0;
- s->config[1] = 0x0000;
- onenand_intr_update(s);
- qemu_irq_raise(s->rdy);
- s->status = 0x0000;
- s->intstatus = cold ? 0x8080 : 0x8010;
- s->unladdr[0] = 0;
- s->unladdr[1] = 0;
- s->wpstatus = 0x0002;
- s->cycle = 0;
- s->otpmode = 0;
- s->blk_cur = s->blk;
- s->current = s->image;
- s->secs_cur = s->secs;
-
- if (cold) {
- /* Lock the whole flash */
- memset(s->blockwp, ONEN_LOCK_LOCKED, s->blocks);
-
- if (s->blk_cur && blk_read(s->blk_cur, 0, s->boot[0], 8) < 0) {
- hw_error("%s: Loading the BootRAM failed.\n", __func__);
- }
- }
-}
-
-static void onenand_system_reset(DeviceState *dev)
-{
- OneNANDState *s = ONE_NAND(dev);
-
- onenand_reset(s, 1);
-}
-
-static inline int onenand_load_main(OneNANDState *s, int sec, int secn,
- void *dest)
-{
- if (s->blk_cur) {
- return blk_read(s->blk_cur, sec, dest, secn) < 0;
- } else if (sec + secn > s->secs_cur) {
- return 1;
- }
-
- memcpy(dest, s->current + (sec << 9), secn << 9);
-
- return 0;
-}
-
-static inline int onenand_prog_main(OneNANDState *s, int sec, int secn,
- void *src)
-{
- int result = 0;
-
- if (secn > 0) {
- uint32_t size = (uint32_t)secn * 512;
- const uint8_t *sp = (const uint8_t *)src;
- uint8_t *dp = 0;
- if (s->blk_cur) {
- dp = g_malloc(size);
- if (!dp || blk_read(s->blk_cur, sec, dp, secn) < 0) {
- result = 1;
- }
- } else {
- if (sec + secn > s->secs_cur) {
- result = 1;
- } else {
- dp = (uint8_t *)s->current + (sec << 9);
- }
- }
- if (!result) {
- uint32_t i;
- for (i = 0; i < size; i++) {
- dp[i] &= sp[i];
- }
- if (s->blk_cur) {
- result = blk_write(s->blk_cur, sec, dp, secn) < 0;
- }
- }
- if (dp && s->blk_cur) {
- g_free(dp);
- }
- }
-
- return result;
-}
-
-static inline int onenand_load_spare(OneNANDState *s, int sec, int secn,
- void *dest)
-{
- uint8_t buf[512];
-
- if (s->blk_cur) {
- if (blk_read(s->blk_cur, s->secs_cur + (sec >> 5), buf, 1) < 0) {
- return 1;
- }
- memcpy(dest, buf + ((sec & 31) << 4), secn << 4);
- } else if (sec + secn > s->secs_cur) {
- return 1;
- } else {
- memcpy(dest, s->current + (s->secs_cur << 9) + (sec << 4), secn << 4);
- }
-
- return 0;
-}
-
-static inline int onenand_prog_spare(OneNANDState *s, int sec, int secn,
- void *src)
-{
- int result = 0;
- if (secn > 0) {
- const uint8_t *sp = (const uint8_t *)src;
- uint8_t *dp = 0, *dpp = 0;
- if (s->blk_cur) {
- dp = g_malloc(512);
- if (!dp
- || blk_read(s->blk_cur, s->secs_cur + (sec >> 5), dp, 1) < 0) {
- result = 1;
- } else {
- dpp = dp + ((sec & 31) << 4);
- }
- } else {
- if (sec + secn > s->secs_cur) {
- result = 1;
- } else {
- dpp = s->current + (s->secs_cur << 9) + (sec << 4);
- }
- }
- if (!result) {
- uint32_t i;
- for (i = 0; i < (secn << 4); i++) {
- dpp[i] &= sp[i];
- }
- if (s->blk_cur) {
- result = blk_write(s->blk_cur, s->secs_cur + (sec >> 5),
- dp, 1) < 0;
- }
- }
- g_free(dp);
- }
- return result;
-}
-
-static inline int onenand_erase(OneNANDState *s, int sec, int num)
-{
- uint8_t *blankbuf, *tmpbuf;
-
- blankbuf = g_malloc(512);
- tmpbuf = g_malloc(512);
- memset(blankbuf, 0xff, 512);
- for (; num > 0; num--, sec++) {
- if (s->blk_cur) {
- int erasesec = s->secs_cur + (sec >> 5);
- if (blk_write(s->blk_cur, sec, blankbuf, 1) < 0) {
- goto fail;
- }
- if (blk_read(s->blk_cur, erasesec, tmpbuf, 1) < 0) {
- goto fail;
- }
- memcpy(tmpbuf + ((sec & 31) << 4), blankbuf, 1 << 4);
- if (blk_write(s->blk_cur, erasesec, tmpbuf, 1) < 0) {
- goto fail;
- }
- } else {
- if (sec + 1 > s->secs_cur) {
- goto fail;
- }
- memcpy(s->current + (sec << 9), blankbuf, 512);
- memcpy(s->current + (s->secs_cur << 9) + (sec << 4),
- blankbuf, 1 << 4);
- }
- }
-
- g_free(tmpbuf);
- g_free(blankbuf);
- return 0;
-
-fail:
- g_free(tmpbuf);
- g_free(blankbuf);
- return 1;
-}
-
-static void onenand_command(OneNANDState *s)
-{
- int b;
- int sec;
- void *buf;
-#define SETADDR(block, page) \
- sec = (s->addr[page] & 3) + \
- ((((s->addr[page] >> 2) & 0x3f) + \
- (((s->addr[block] & 0xfff) | \
- (s->addr[block] >> 15 ? \
- s->density_mask : 0)) << 6)) << (PAGE_SHIFT - 9));
-#define SETBUF_M() \
- buf = (s->bufaddr & 8) ? \
- s->data[(s->bufaddr >> 2) & 1][0] : s->boot[0]; \
- buf += (s->bufaddr & 3) << 9;
-#define SETBUF_S() \
- buf = (s->bufaddr & 8) ? \
- s->data[(s->bufaddr >> 2) & 1][1] : s->boot[1]; \
- buf += (s->bufaddr & 3) << 4;
-
- switch (s->command) {
- case 0x00: /* Load single/multiple sector data unit into buffer */
- SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
-
- SETBUF_M()
- if (onenand_load_main(s, sec, s->count, buf))
- s->status |= ONEN_ERR_CMD | ONEN_ERR_LOAD;
-
-#if 0
- SETBUF_S()
- if (onenand_load_spare(s, sec, s->count, buf))
- s->status |= ONEN_ERR_CMD | ONEN_ERR_LOAD;
-#endif
-
- /* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages)
- * or if (s->bufaddr & 1) + s->count was > 2 (1k-pages)
- * then we need two split the read/write into two chunks.
- */
- s->intstatus |= ONEN_INT | ONEN_INT_LOAD;
- break;
- case 0x13: /* Load single/multiple spare sector into buffer */
- SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
-
- SETBUF_S()
- if (onenand_load_spare(s, sec, s->count, buf))
- s->status |= ONEN_ERR_CMD | ONEN_ERR_LOAD;
-
- /* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages)
- * or if (s->bufaddr & 1) + s->count was > 2 (1k-pages)
- * then we need two split the read/write into two chunks.
- */
- s->intstatus |= ONEN_INT | ONEN_INT_LOAD;
- break;
- case 0x80: /* Program single/multiple sector data unit from buffer */
- SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
-
- SETBUF_M()
- if (onenand_prog_main(s, sec, s->count, buf))
- s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
-
-#if 0
- SETBUF_S()
- if (onenand_prog_spare(s, sec, s->count, buf))
- s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
-#endif
-
- /* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages)
- * or if (s->bufaddr & 1) + s->count was > 2 (1k-pages)
- * then we need two split the read/write into two chunks.
- */
- s->intstatus |= ONEN_INT | ONEN_INT_PROG;
- break;
- case 0x1a: /* Program single/multiple spare area sector from buffer */
- SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
-
- SETBUF_S()
- if (onenand_prog_spare(s, sec, s->count, buf))
- s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
-
- /* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages)
- * or if (s->bufaddr & 1) + s->count was > 2 (1k-pages)
- * then we need two split the read/write into two chunks.
- */
- s->intstatus |= ONEN_INT | ONEN_INT_PROG;
- break;
- case 0x1b: /* Copy-back program */
- SETBUF_S()
-
- SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
- if (onenand_load_main(s, sec, s->count, buf))
- s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
-
- SETADDR(ONEN_BUF_DEST_BLOCK, ONEN_BUF_DEST_PAGE)
- if (onenand_prog_main(s, sec, s->count, buf))
- s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
-
- /* TODO: spare areas */
-
- s->intstatus |= ONEN_INT | ONEN_INT_PROG;
- break;
-
- case 0x23: /* Unlock NAND array block(s) */
- s->intstatus |= ONEN_INT;
-
- /* XXX the previous (?) area should be locked automatically */
- for (b = s->unladdr[0]; b <= s->unladdr[1]; b ++) {
- if (b >= s->blocks) {
- s->status |= ONEN_ERR_CMD;
- break;
- }
- if (s->blockwp[b] == ONEN_LOCK_LOCKTIGHTEN)
- break;
-
- s->wpstatus = s->blockwp[b] = ONEN_LOCK_UNLOCKED;
- }
- break;
- case 0x27: /* Unlock All NAND array blocks */
- s->intstatus |= ONEN_INT;
-
- for (b = 0; b < s->blocks; b ++) {
- if (b >= s->blocks) {
- s->status |= ONEN_ERR_CMD;
- break;
- }
- if (s->blockwp[b] == ONEN_LOCK_LOCKTIGHTEN)
- break;
-
- s->wpstatus = s->blockwp[b] = ONEN_LOCK_UNLOCKED;
- }
- break;
-
- case 0x2a: /* Lock NAND array block(s) */
- s->intstatus |= ONEN_INT;
-
- for (b = s->unladdr[0]; b <= s->unladdr[1]; b ++) {
- if (b >= s->blocks) {
- s->status |= ONEN_ERR_CMD;
- break;
- }
- if (s->blockwp[b] == ONEN_LOCK_LOCKTIGHTEN)
- break;
-
- s->wpstatus = s->blockwp[b] = ONEN_LOCK_LOCKED;
- }
- break;
- case 0x2c: /* Lock-tight NAND array block(s) */
- s->intstatus |= ONEN_INT;
-
- for (b = s->unladdr[0]; b <= s->unladdr[1]; b ++) {
- if (b >= s->blocks) {
- s->status |= ONEN_ERR_CMD;
- break;
- }
- if (s->blockwp[b] == ONEN_LOCK_UNLOCKED)
- continue;
-
- s->wpstatus = s->blockwp[b] = ONEN_LOCK_LOCKTIGHTEN;
- }
- break;
-
- case 0x71: /* Erase-Verify-Read */
- s->intstatus |= ONEN_INT;
- break;
- case 0x95: /* Multi-block erase */
- qemu_irq_pulse(s->intr);
- /* Fall through. */
- case 0x94: /* Block erase */
- sec = ((s->addr[ONEN_BUF_BLOCK] & 0xfff) |
- (s->addr[ONEN_BUF_BLOCK] >> 15 ? s->density_mask : 0))
- << (BLOCK_SHIFT - 9);
- if (onenand_erase(s, sec, 1 << (BLOCK_SHIFT - 9)))
- s->status |= ONEN_ERR_CMD | ONEN_ERR_ERASE;
-
- s->intstatus |= ONEN_INT | ONEN_INT_ERASE;
- break;
- case 0xb0: /* Erase suspend */
- break;
- case 0x30: /* Erase resume */
- s->intstatus |= ONEN_INT | ONEN_INT_ERASE;
- break;
-
- case 0xf0: /* Reset NAND Flash core */
- onenand_reset(s, 0);
- break;
- case 0xf3: /* Reset OneNAND */
- onenand_reset(s, 0);
- break;
-
- case 0x65: /* OTP Access */
- s->intstatus |= ONEN_INT;
- s->blk_cur = NULL;
- s->current = s->otp;
- s->secs_cur = 1 << (BLOCK_SHIFT - 9);
- s->addr[ONEN_BUF_BLOCK] = 0;
- s->otpmode = 1;
- break;
-
- default:
- s->status |= ONEN_ERR_CMD;
- s->intstatus |= ONEN_INT;
- fprintf(stderr, "%s: unknown OneNAND command %x\n",
- __func__, s->command);
- }
-
- onenand_intr_update(s);
-}
-
-static uint64_t onenand_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- OneNANDState *s = (OneNANDState *) opaque;
- int offset = addr >> s->shift;
-
- switch (offset) {
- case 0x0000 ... 0xc000:
- return lduw_le_p(s->boot[0] + addr);
-
- case 0xf000: /* Manufacturer ID */
- return s->id.man;
- case 0xf001: /* Device ID */
- return s->id.dev;
- case 0xf002: /* Version ID */
- return s->id.ver;
- /* TODO: get the following values from a real chip! */
- case 0xf003: /* Data Buffer size */
- return 1 << PAGE_SHIFT;
- case 0xf004: /* Boot Buffer size */
- return 0x200;
- case 0xf005: /* Amount of buffers */
- return 1 | (2 << 8);
- case 0xf006: /* Technology */
- return 0;
-
- case 0xf100 ... 0xf107: /* Start addresses */
- return s->addr[offset - 0xf100];
-
- case 0xf200: /* Start buffer */
- return (s->bufaddr << 8) | ((s->count - 1) & (1 << (PAGE_SHIFT - 10)));
-
- case 0xf220: /* Command */
- return s->command;
- case 0xf221: /* System Configuration 1 */
- return s->config[0] & 0xffe0;
- case 0xf222: /* System Configuration 2 */
- return s->config[1];
-
- case 0xf240: /* Controller Status */
- return s->status;
- case 0xf241: /* Interrupt */
- return s->intstatus;
- case 0xf24c: /* Unlock Start Block Address */
- return s->unladdr[0];
- case 0xf24d: /* Unlock End Block Address */
- return s->unladdr[1];
- case 0xf24e: /* Write Protection Status */
- return s->wpstatus;
-
- case 0xff00: /* ECC Status */
- return 0x00;
- case 0xff01: /* ECC Result of main area data */
- case 0xff02: /* ECC Result of spare area data */
- case 0xff03: /* ECC Result of main area data */
- case 0xff04: /* ECC Result of spare area data */
- hw_error("%s: imeplement ECC\n", __FUNCTION__);
- return 0x0000;
- }
-
- fprintf(stderr, "%s: unknown OneNAND register %x\n",
- __FUNCTION__, offset);
- return 0;
-}
-
-static void onenand_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- OneNANDState *s = (OneNANDState *) opaque;
- int offset = addr >> s->shift;
- int sec;
-
- switch (offset) {
- case 0x0000 ... 0x01ff:
- case 0x8000 ... 0x800f:
- if (s->cycle) {
- s->cycle = 0;
-
- if (value == 0x0000) {
- SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
- onenand_load_main(s, sec,
- 1 << (PAGE_SHIFT - 9), s->data[0][0]);
- s->addr[ONEN_BUF_PAGE] += 4;
- s->addr[ONEN_BUF_PAGE] &= 0xff;
- }
- break;
- }
-
- switch (value) {
- case 0x00f0: /* Reset OneNAND */
- onenand_reset(s, 0);
- break;
-
- case 0x00e0: /* Load Data into Buffer */
- s->cycle = 1;
- break;
-
- case 0x0090: /* Read Identification Data */
- memset(s->boot[0], 0, 3 << s->shift);
- s->boot[0][0 << s->shift] = s->id.man & 0xff;
- s->boot[0][1 << s->shift] = s->id.dev & 0xff;
- s->boot[0][2 << s->shift] = s->wpstatus & 0xff;
- break;
-
- default:
- fprintf(stderr, "%s: unknown OneNAND boot command %"PRIx64"\n",
- __FUNCTION__, value);
- }
- break;
-
- case 0xf100 ... 0xf107: /* Start addresses */
- s->addr[offset - 0xf100] = value;
- break;
-
- case 0xf200: /* Start buffer */
- s->bufaddr = (value >> 8) & 0xf;
- if (PAGE_SHIFT == 11)
- s->count = (value & 3) ?: 4;
- else if (PAGE_SHIFT == 10)
- s->count = (value & 1) ?: 2;
- break;
-
- case 0xf220: /* Command */
- if (s->intstatus & (1 << 15))
- break;
- s->command = value;
- onenand_command(s);
- break;
- case 0xf221: /* System Configuration 1 */
- s->config[0] = value;
- onenand_intr_update(s);
- qemu_set_irq(s->rdy, (s->config[0] >> 7) & 1);
- break;
- case 0xf222: /* System Configuration 2 */
- s->config[1] = value;
- break;
-
- case 0xf241: /* Interrupt */
- s->intstatus &= value;
- if ((1 << 15) & ~s->intstatus)
- s->status &= ~(ONEN_ERR_CMD | ONEN_ERR_ERASE |
- ONEN_ERR_PROG | ONEN_ERR_LOAD);
- onenand_intr_update(s);
- break;
- case 0xf24c: /* Unlock Start Block Address */
- s->unladdr[0] = value & (s->blocks - 1);
- /* For some reason we have to set the end address to by default
- * be same as start because the software forgets to write anything
- * in there. */
- s->unladdr[1] = value & (s->blocks - 1);
- break;
- case 0xf24d: /* Unlock End Block Address */
- s->unladdr[1] = value & (s->blocks - 1);
- break;
-
- default:
- fprintf(stderr, "%s: unknown OneNAND register %x\n",
- __FUNCTION__, offset);
- }
-}
-
-static const MemoryRegionOps onenand_ops = {
- .read = onenand_read,
- .write = onenand_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int onenand_initfn(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- OneNANDState *s = ONE_NAND(dev);
- uint32_t size = 1 << (24 + ((s->id.dev >> 4) & 7));
- void *ram;
-
- s->base = (hwaddr)-1;
- s->rdy = NULL;
- s->blocks = size >> BLOCK_SHIFT;
- s->secs = size >> 9;
- s->blockwp = g_malloc(s->blocks);
- s->density_mask = (s->id.dev & 0x08)
- ? (1 << (6 + ((s->id.dev >> 4) & 7))) : 0;
- memory_region_init_io(&s->iomem, OBJECT(s), &onenand_ops, s, "onenand",
- 0x10000 << s->shift);
- if (!s->blk) {
- s->image = memset(g_malloc(size + (size >> 5)),
- 0xff, size + (size >> 5));
- } else {
- if (blk_is_read_only(s->blk)) {
- error_report("Can't use a read-only drive");
- return -1;
- }
- s->blk_cur = s->blk;
- }
- s->otp = memset(g_malloc((64 + 2) << PAGE_SHIFT),
- 0xff, (64 + 2) << PAGE_SHIFT);
- memory_region_init_ram(&s->ram, OBJECT(s), "onenand.ram",
- 0xc000 << s->shift, &error_fatal);
- vmstate_register_ram_global(&s->ram);
- ram = memory_region_get_ram_ptr(&s->ram);
- s->boot[0] = ram + (0x0000 << s->shift);
- s->boot[1] = ram + (0x8000 << s->shift);
- s->data[0][0] = ram + ((0x0200 + (0 << (PAGE_SHIFT - 1))) << s->shift);
- s->data[0][1] = ram + ((0x8010 + (0 << (PAGE_SHIFT - 6))) << s->shift);
- s->data[1][0] = ram + ((0x0200 + (1 << (PAGE_SHIFT - 1))) << s->shift);
- s->data[1][1] = ram + ((0x8010 + (1 << (PAGE_SHIFT - 6))) << s->shift);
- onenand_mem_setup(s);
- sysbus_init_irq(sbd, &s->intr);
- sysbus_init_mmio(sbd, &s->container);
- vmstate_register(dev,
- ((s->shift & 0x7f) << 24)
- | ((s->id.man & 0xff) << 16)
- | ((s->id.dev & 0xff) << 8)
- | (s->id.ver & 0xff),
- &vmstate_onenand, s);
- return 0;
-}
-
-static Property onenand_properties[] = {
- DEFINE_PROP_UINT16("manufacturer_id", OneNANDState, id.man, 0),
- DEFINE_PROP_UINT16("device_id", OneNANDState, id.dev, 0),
- DEFINE_PROP_UINT16("version_id", OneNANDState, id.ver, 0),
- DEFINE_PROP_INT32("shift", OneNANDState, shift, 0),
- DEFINE_PROP_DRIVE("drive", OneNANDState, blk),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void onenand_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = onenand_initfn;
- dc->reset = onenand_system_reset;
- dc->props = onenand_properties;
-}
-
-static const TypeInfo onenand_info = {
- .name = TYPE_ONE_NAND,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(OneNANDState),
- .class_init = onenand_class_init,
-};
-
-static void onenand_register_types(void)
-{
- type_register_static(&onenand_info);
-}
-
-void *onenand_raw_otp(DeviceState *onenand_device)
-{
- OneNANDState *s = ONE_NAND(onenand_device);
-
- return s->otp;
-}
-
-type_init(onenand_register_types)
diff --git a/qemu/hw/block/pflash_cfi01.c b/qemu/hw/block/pflash_cfi01.c
deleted file mode 100644
index 106a77523..000000000
--- a/qemu/hw/block/pflash_cfi01.c
+++ /dev/null
@@ -1,970 +0,0 @@
-/*
- * CFI parallel flash with Intel command set emulation
- *
- * Copyright (c) 2006 Thorsten Zitterell
- * Copyright (c) 2005 Jocelyn Mayer
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * For now, this code can emulate flashes of 1, 2 or 4 bytes width.
- * Supported commands/modes are:
- * - flash read
- * - flash write
- * - flash ID read
- * - sector erase
- * - CFI queries
- *
- * It does not support timings
- * It does not support flash interleaving
- * It does not implement software data protection as found in many real chips
- * It does not implement erase suspend/resume commands
- * It does not implement multiple sectors erase
- *
- * It does not implement much more ...
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/block/flash.h"
-#include "sysemu/block-backend.h"
-#include "qapi/error.h"
-#include "qemu/timer.h"
-#include "qemu/bitops.h"
-#include "exec/address-spaces.h"
-#include "qemu/host-utils.h"
-#include "hw/sysbus.h"
-#include "sysemu/sysemu.h"
-
-#define PFLASH_BUG(fmt, ...) \
-do { \
- fprintf(stderr, "PFLASH: Possible BUG - " fmt, ## __VA_ARGS__); \
- exit(1); \
-} while(0)
-
-/* #define PFLASH_DEBUG */
-#ifdef PFLASH_DEBUG
-#define DPRINTF(fmt, ...) \
-do { \
- fprintf(stderr, "PFLASH: " fmt , ## __VA_ARGS__); \
-} while (0)
-#else
-#define DPRINTF(fmt, ...) do { } while (0)
-#endif
-
-#define TYPE_CFI_PFLASH01 "cfi.pflash01"
-#define CFI_PFLASH01(obj) OBJECT_CHECK(pflash_t, (obj), TYPE_CFI_PFLASH01)
-
-#define PFLASH_BE 0
-#define PFLASH_SECURE 1
-
-struct pflash_t {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- BlockBackend *blk;
- uint32_t nb_blocs;
- uint64_t sector_len;
- uint8_t bank_width;
- uint8_t device_width; /* If 0, device width not specified. */
- uint8_t max_device_width; /* max device width in bytes */
- uint32_t features;
- uint8_t wcycle; /* if 0, the flash is read normally */
- int ro;
- uint8_t cmd;
- uint8_t status;
- uint16_t ident0;
- uint16_t ident1;
- uint16_t ident2;
- uint16_t ident3;
- uint8_t cfi_len;
- uint8_t cfi_table[0x52];
- uint64_t counter;
- unsigned int writeblock_size;
- QEMUTimer *timer;
- MemoryRegion mem;
- char *name;
- void *storage;
- VMChangeStateEntry *vmstate;
-};
-
-static int pflash_post_load(void *opaque, int version_id);
-
-static const VMStateDescription vmstate_pflash = {
- .name = "pflash_cfi01",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = pflash_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(wcycle, pflash_t),
- VMSTATE_UINT8(cmd, pflash_t),
- VMSTATE_UINT8(status, pflash_t),
- VMSTATE_UINT64(counter, pflash_t),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void pflash_timer (void *opaque)
-{
- pflash_t *pfl = opaque;
-
- DPRINTF("%s: command %02x done\n", __func__, pfl->cmd);
- /* Reset flash */
- pfl->status ^= 0x80;
- memory_region_rom_device_set_romd(&pfl->mem, true);
- pfl->wcycle = 0;
- pfl->cmd = 0;
-}
-
-/* Perform a CFI query based on the bank width of the flash.
- * If this code is called we know we have a device_width set for
- * this flash.
- */
-static uint32_t pflash_cfi_query(pflash_t *pfl, hwaddr offset)
-{
- int i;
- uint32_t resp = 0;
- hwaddr boff;
-
- /* Adjust incoming offset to match expected device-width
- * addressing. CFI query addresses are always specified in terms of
- * the maximum supported width of the device. This means that x8
- * devices and x8/x16 devices in x8 mode behave differently. For
- * devices that are not used at their max width, we will be
- * provided with addresses that use higher address bits than
- * expected (based on the max width), so we will shift them lower
- * so that they will match the addresses used when
- * device_width==max_device_width.
- */
- boff = offset >> (ctz32(pfl->bank_width) +
- ctz32(pfl->max_device_width) - ctz32(pfl->device_width));
-
- if (boff > pfl->cfi_len) {
- return 0;
- }
- /* Now we will construct the CFI response generated by a single
- * device, then replicate that for all devices that make up the
- * bus. For wide parts used in x8 mode, CFI query responses
- * are different than native byte-wide parts.
- */
- resp = pfl->cfi_table[boff];
- if (pfl->device_width != pfl->max_device_width) {
- /* The only case currently supported is x8 mode for a
- * wider part.
- */
- if (pfl->device_width != 1 || pfl->bank_width > 4) {
- DPRINTF("%s: Unsupported device configuration: "
- "device_width=%d, max_device_width=%d\n",
- __func__, pfl->device_width,
- pfl->max_device_width);
- return 0;
- }
- /* CFI query data is repeated, rather than zero padded for
- * wide devices used in x8 mode.
- */
- for (i = 1; i < pfl->max_device_width; i++) {
- resp = deposit32(resp, 8 * i, 8, pfl->cfi_table[boff]);
- }
- }
- /* Replicate responses for each device in bank. */
- if (pfl->device_width < pfl->bank_width) {
- for (i = pfl->device_width;
- i < pfl->bank_width; i += pfl->device_width) {
- resp = deposit32(resp, 8 * i, 8 * pfl->device_width, resp);
- }
- }
-
- return resp;
-}
-
-
-
-/* Perform a device id query based on the bank width of the flash. */
-static uint32_t pflash_devid_query(pflash_t *pfl, hwaddr offset)
-{
- int i;
- uint32_t resp;
- hwaddr boff;
-
- /* Adjust incoming offset to match expected device-width
- * addressing. Device ID read addresses are always specified in
- * terms of the maximum supported width of the device. This means
- * that x8 devices and x8/x16 devices in x8 mode behave
- * differently. For devices that are not used at their max width,
- * we will be provided with addresses that use higher address bits
- * than expected (based on the max width), so we will shift them
- * lower so that they will match the addresses used when
- * device_width==max_device_width.
- */
- boff = offset >> (ctz32(pfl->bank_width) +
- ctz32(pfl->max_device_width) - ctz32(pfl->device_width));
-
- /* Mask off upper bits which may be used in to query block
- * or sector lock status at other addresses.
- * Offsets 2/3 are block lock status, is not emulated.
- */
- switch (boff & 0xFF) {
- case 0:
- resp = pfl->ident0;
- DPRINTF("%s: Manufacturer Code %04x\n", __func__, resp);
- break;
- case 1:
- resp = pfl->ident1;
- DPRINTF("%s: Device ID Code %04x\n", __func__, resp);
- break;
- default:
- DPRINTF("%s: Read Device Information offset=%x\n", __func__,
- (unsigned)offset);
- return 0;
- break;
- }
- /* Replicate responses for each device in bank. */
- if (pfl->device_width < pfl->bank_width) {
- for (i = pfl->device_width;
- i < pfl->bank_width; i += pfl->device_width) {
- resp = deposit32(resp, 8 * i, 8 * pfl->device_width, resp);
- }
- }
-
- return resp;
-}
-
-static uint32_t pflash_data_read(pflash_t *pfl, hwaddr offset,
- int width, int be)
-{
- uint8_t *p;
- uint32_t ret;
-
- p = pfl->storage;
- switch (width) {
- case 1:
- ret = p[offset];
- DPRINTF("%s: data offset " TARGET_FMT_plx " %02x\n",
- __func__, offset, ret);
- break;
- case 2:
- if (be) {
- ret = p[offset] << 8;
- ret |= p[offset + 1];
- } else {
- ret = p[offset];
- ret |= p[offset + 1] << 8;
- }
- DPRINTF("%s: data offset " TARGET_FMT_plx " %04x\n",
- __func__, offset, ret);
- break;
- case 4:
- if (be) {
- ret = p[offset] << 24;
- ret |= p[offset + 1] << 16;
- ret |= p[offset + 2] << 8;
- ret |= p[offset + 3];
- } else {
- ret = p[offset];
- ret |= p[offset + 1] << 8;
- ret |= p[offset + 2] << 16;
- ret |= p[offset + 3] << 24;
- }
- DPRINTF("%s: data offset " TARGET_FMT_plx " %08x\n",
- __func__, offset, ret);
- break;
- default:
- DPRINTF("BUG in %s\n", __func__);
- abort();
- }
- return ret;
-}
-
-static uint32_t pflash_read (pflash_t *pfl, hwaddr offset,
- int width, int be)
-{
- hwaddr boff;
- uint32_t ret;
-
- ret = -1;
-
-#if 0
- DPRINTF("%s: reading offset " TARGET_FMT_plx " under cmd %02x width %d\n",
- __func__, offset, pfl->cmd, width);
-#endif
- switch (pfl->cmd) {
- default:
- /* This should never happen : reset state & treat it as a read */
- DPRINTF("%s: unknown command state: %x\n", __func__, pfl->cmd);
- pfl->wcycle = 0;
- pfl->cmd = 0;
- /* fall through to read code */
- case 0x00:
- /* Flash area read */
- ret = pflash_data_read(pfl, offset, width, be);
- break;
- case 0x10: /* Single byte program */
- case 0x20: /* Block erase */
- case 0x28: /* Block erase */
- case 0x40: /* single byte program */
- case 0x50: /* Clear status register */
- case 0x60: /* Block /un)lock */
- case 0x70: /* Status Register */
- case 0xe8: /* Write block */
- /* Status register read. Return status from each device in
- * bank.
- */
- ret = pfl->status;
- if (pfl->device_width && width > pfl->device_width) {
- int shift = pfl->device_width * 8;
- while (shift + pfl->device_width * 8 <= width * 8) {
- ret |= pfl->status << shift;
- shift += pfl->device_width * 8;
- }
- } else if (!pfl->device_width && width > 2) {
- /* Handle 32 bit flash cases where device width is not
- * set. (Existing behavior before device width added.)
- */
- ret |= pfl->status << 16;
- }
- DPRINTF("%s: status %x\n", __func__, ret);
- break;
- case 0x90:
- if (!pfl->device_width) {
- /* Preserve old behavior if device width not specified */
- boff = offset & 0xFF;
- if (pfl->bank_width == 2) {
- boff = boff >> 1;
- } else if (pfl->bank_width == 4) {
- boff = boff >> 2;
- }
-
- switch (boff) {
- case 0:
- ret = pfl->ident0 << 8 | pfl->ident1;
- DPRINTF("%s: Manufacturer Code %04x\n", __func__, ret);
- break;
- case 1:
- ret = pfl->ident2 << 8 | pfl->ident3;
- DPRINTF("%s: Device ID Code %04x\n", __func__, ret);
- break;
- default:
- DPRINTF("%s: Read Device Information boff=%x\n", __func__,
- (unsigned)boff);
- ret = 0;
- break;
- }
- } else {
- /* If we have a read larger than the bank_width, combine multiple
- * manufacturer/device ID queries into a single response.
- */
- int i;
- for (i = 0; i < width; i += pfl->bank_width) {
- ret = deposit32(ret, i * 8, pfl->bank_width * 8,
- pflash_devid_query(pfl,
- offset + i * pfl->bank_width));
- }
- }
- break;
- case 0x98: /* Query mode */
- if (!pfl->device_width) {
- /* Preserve old behavior if device width not specified */
- boff = offset & 0xFF;
- if (pfl->bank_width == 2) {
- boff = boff >> 1;
- } else if (pfl->bank_width == 4) {
- boff = boff >> 2;
- }
-
- if (boff > pfl->cfi_len) {
- ret = 0;
- } else {
- ret = pfl->cfi_table[boff];
- }
- } else {
- /* If we have a read larger than the bank_width, combine multiple
- * CFI queries into a single response.
- */
- int i;
- for (i = 0; i < width; i += pfl->bank_width) {
- ret = deposit32(ret, i * 8, pfl->bank_width * 8,
- pflash_cfi_query(pfl,
- offset + i * pfl->bank_width));
- }
- }
-
- break;
- }
- return ret;
-}
-
-/* update flash content on disk */
-static void pflash_update(pflash_t *pfl, int offset,
- int size)
-{
- int offset_end;
- if (pfl->blk) {
- offset_end = offset + size;
- /* round to sectors */
- offset = offset >> 9;
- offset_end = (offset_end + 511) >> 9;
- blk_write(pfl->blk, offset, pfl->storage + (offset << 9),
- offset_end - offset);
- }
-}
-
-static inline void pflash_data_write(pflash_t *pfl, hwaddr offset,
- uint32_t value, int width, int be)
-{
- uint8_t *p = pfl->storage;
-
- DPRINTF("%s: block write offset " TARGET_FMT_plx
- " value %x counter %016" PRIx64 "\n",
- __func__, offset, value, pfl->counter);
- switch (width) {
- case 1:
- p[offset] = value;
- break;
- case 2:
- if (be) {
- p[offset] = value >> 8;
- p[offset + 1] = value;
- } else {
- p[offset] = value;
- p[offset + 1] = value >> 8;
- }
- break;
- case 4:
- if (be) {
- p[offset] = value >> 24;
- p[offset + 1] = value >> 16;
- p[offset + 2] = value >> 8;
- p[offset + 3] = value;
- } else {
- p[offset] = value;
- p[offset + 1] = value >> 8;
- p[offset + 2] = value >> 16;
- p[offset + 3] = value >> 24;
- }
- break;
- }
-
-}
-
-static void pflash_write(pflash_t *pfl, hwaddr offset,
- uint32_t value, int width, int be)
-{
- uint8_t *p;
- uint8_t cmd;
-
- cmd = value;
-
- DPRINTF("%s: writing offset " TARGET_FMT_plx " value %08x width %d wcycle 0x%x\n",
- __func__, offset, value, width, pfl->wcycle);
-
- if (!pfl->wcycle) {
- /* Set the device in I/O access mode */
- memory_region_rom_device_set_romd(&pfl->mem, false);
- }
-
- switch (pfl->wcycle) {
- case 0:
- /* read mode */
- switch (cmd) {
- case 0x00: /* ??? */
- goto reset_flash;
- case 0x10: /* Single Byte Program */
- case 0x40: /* Single Byte Program */
- DPRINTF("%s: Single Byte Program\n", __func__);
- break;
- case 0x20: /* Block erase */
- p = pfl->storage;
- offset &= ~(pfl->sector_len - 1);
-
- DPRINTF("%s: block erase at " TARGET_FMT_plx " bytes %x\n",
- __func__, offset, (unsigned)pfl->sector_len);
-
- if (!pfl->ro) {
- memset(p + offset, 0xff, pfl->sector_len);
- pflash_update(pfl, offset, pfl->sector_len);
- } else {
- pfl->status |= 0x20; /* Block erase error */
- }
- pfl->status |= 0x80; /* Ready! */
- break;
- case 0x50: /* Clear status bits */
- DPRINTF("%s: Clear status bits\n", __func__);
- pfl->status = 0x0;
- goto reset_flash;
- case 0x60: /* Block (un)lock */
- DPRINTF("%s: Block unlock\n", __func__);
- break;
- case 0x70: /* Status Register */
- DPRINTF("%s: Read status register\n", __func__);
- pfl->cmd = cmd;
- return;
- case 0x90: /* Read Device ID */
- DPRINTF("%s: Read Device information\n", __func__);
- pfl->cmd = cmd;
- return;
- case 0x98: /* CFI query */
- DPRINTF("%s: CFI query\n", __func__);
- break;
- case 0xe8: /* Write to buffer */
- DPRINTF("%s: Write to buffer\n", __func__);
- pfl->status |= 0x80; /* Ready! */
- break;
- case 0xf0: /* Probe for AMD flash */
- DPRINTF("%s: Probe for AMD flash\n", __func__);
- goto reset_flash;
- case 0xff: /* Read array mode */
- DPRINTF("%s: Read array mode\n", __func__);
- goto reset_flash;
- default:
- goto error_flash;
- }
- pfl->wcycle++;
- pfl->cmd = cmd;
- break;
- case 1:
- switch (pfl->cmd) {
- case 0x10: /* Single Byte Program */
- case 0x40: /* Single Byte Program */
- DPRINTF("%s: Single Byte Program\n", __func__);
- if (!pfl->ro) {
- pflash_data_write(pfl, offset, value, width, be);
- pflash_update(pfl, offset, width);
- } else {
- pfl->status |= 0x10; /* Programming error */
- }
- pfl->status |= 0x80; /* Ready! */
- pfl->wcycle = 0;
- break;
- case 0x20: /* Block erase */
- case 0x28:
- if (cmd == 0xd0) { /* confirm */
- pfl->wcycle = 0;
- pfl->status |= 0x80;
- } else if (cmd == 0xff) { /* read array mode */
- goto reset_flash;
- } else
- goto error_flash;
-
- break;
- case 0xe8:
- /* Mask writeblock size based on device width, or bank width if
- * device width not specified.
- */
- if (pfl->device_width) {
- value = extract32(value, 0, pfl->device_width * 8);
- } else {
- value = extract32(value, 0, pfl->bank_width * 8);
- }
- DPRINTF("%s: block write of %x bytes\n", __func__, value);
- pfl->counter = value;
- pfl->wcycle++;
- break;
- case 0x60:
- if (cmd == 0xd0) {
- pfl->wcycle = 0;
- pfl->status |= 0x80;
- } else if (cmd == 0x01) {
- pfl->wcycle = 0;
- pfl->status |= 0x80;
- } else if (cmd == 0xff) {
- goto reset_flash;
- } else {
- DPRINTF("%s: Unknown (un)locking command\n", __func__);
- goto reset_flash;
- }
- break;
- case 0x98:
- if (cmd == 0xff) {
- goto reset_flash;
- } else {
- DPRINTF("%s: leaving query mode\n", __func__);
- }
- break;
- default:
- goto error_flash;
- }
- break;
- case 2:
- switch (pfl->cmd) {
- case 0xe8: /* Block write */
- if (!pfl->ro) {
- pflash_data_write(pfl, offset, value, width, be);
- } else {
- pfl->status |= 0x10; /* Programming error */
- }
-
- pfl->status |= 0x80;
-
- if (!pfl->counter) {
- hwaddr mask = pfl->writeblock_size - 1;
- mask = ~mask;
-
- DPRINTF("%s: block write finished\n", __func__);
- pfl->wcycle++;
- if (!pfl->ro) {
- /* Flush the entire write buffer onto backing storage. */
- pflash_update(pfl, offset & mask, pfl->writeblock_size);
- } else {
- pfl->status |= 0x10; /* Programming error */
- }
- }
-
- pfl->counter--;
- break;
- default:
- goto error_flash;
- }
- break;
- case 3: /* Confirm mode */
- switch (pfl->cmd) {
- case 0xe8: /* Block write */
- if (cmd == 0xd0) {
- pfl->wcycle = 0;
- pfl->status |= 0x80;
- } else {
- DPRINTF("%s: unknown command for \"write block\"\n", __func__);
- PFLASH_BUG("Write block confirm");
- goto reset_flash;
- }
- break;
- default:
- goto error_flash;
- }
- break;
- default:
- /* Should never happen */
- DPRINTF("%s: invalid write state\n", __func__);
- goto reset_flash;
- }
- return;
-
- error_flash:
- qemu_log_mask(LOG_UNIMP, "%s: Unimplemented flash cmd sequence "
- "(offset " TARGET_FMT_plx ", wcycle 0x%x cmd 0x%x value 0x%x)"
- "\n", __func__, offset, pfl->wcycle, pfl->cmd, value);
-
- reset_flash:
- memory_region_rom_device_set_romd(&pfl->mem, true);
-
- pfl->wcycle = 0;
- pfl->cmd = 0;
-}
-
-
-static MemTxResult pflash_mem_read_with_attrs(void *opaque, hwaddr addr, uint64_t *value,
- unsigned len, MemTxAttrs attrs)
-{
- pflash_t *pfl = opaque;
- bool be = !!(pfl->features & (1 << PFLASH_BE));
-
- if ((pfl->features & (1 << PFLASH_SECURE)) && !attrs.secure) {
- *value = pflash_data_read(opaque, addr, len, be);
- } else {
- *value = pflash_read(opaque, addr, len, be);
- }
- return MEMTX_OK;
-}
-
-static MemTxResult pflash_mem_write_with_attrs(void *opaque, hwaddr addr, uint64_t value,
- unsigned len, MemTxAttrs attrs)
-{
- pflash_t *pfl = opaque;
- bool be = !!(pfl->features & (1 << PFLASH_BE));
-
- if ((pfl->features & (1 << PFLASH_SECURE)) && !attrs.secure) {
- return MEMTX_ERROR;
- } else {
- pflash_write(opaque, addr, value, len, be);
- return MEMTX_OK;
- }
-}
-
-static const MemoryRegionOps pflash_cfi01_ops = {
- .read_with_attrs = pflash_mem_read_with_attrs,
- .write_with_attrs = pflash_mem_write_with_attrs,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void pflash_cfi01_realize(DeviceState *dev, Error **errp)
-{
- pflash_t *pfl = CFI_PFLASH01(dev);
- uint64_t total_len;
- int ret;
- uint64_t blocks_per_device, device_len;
- int num_devices;
- Error *local_err = NULL;
-
- total_len = pfl->sector_len * pfl->nb_blocs;
-
- /* These are only used to expose the parameters of each device
- * in the cfi_table[].
- */
- num_devices = pfl->device_width ? (pfl->bank_width / pfl->device_width) : 1;
- blocks_per_device = pfl->nb_blocs / num_devices;
- device_len = pfl->sector_len * blocks_per_device;
-
- /* XXX: to be fixed */
-#if 0
- if (total_len != (8 * 1024 * 1024) && total_len != (16 * 1024 * 1024) &&
- total_len != (32 * 1024 * 1024) && total_len != (64 * 1024 * 1024))
- return NULL;
-#endif
-
- memory_region_init_rom_device(
- &pfl->mem, OBJECT(dev),
- &pflash_cfi01_ops,
- pfl,
- pfl->name, total_len, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- vmstate_register_ram(&pfl->mem, DEVICE(pfl));
- pfl->storage = memory_region_get_ram_ptr(&pfl->mem);
- sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->mem);
-
- if (pfl->blk) {
- /* read the initial flash content */
- ret = blk_read(pfl->blk, 0, pfl->storage, total_len >> 9);
-
- if (ret < 0) {
- vmstate_unregister_ram(&pfl->mem, DEVICE(pfl));
- error_setg(errp, "failed to read the initial flash content");
- return;
- }
- }
-
- if (pfl->blk) {
- pfl->ro = blk_is_read_only(pfl->blk);
- } else {
- pfl->ro = 0;
- }
-
- /* Default to devices being used at their maximum device width. This was
- * assumed before the device_width support was added.
- */
- if (!pfl->max_device_width) {
- pfl->max_device_width = pfl->device_width;
- }
-
- pfl->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, pflash_timer, pfl);
- pfl->wcycle = 0;
- pfl->cmd = 0;
- pfl->status = 0;
- /* Hardcoded CFI table */
- pfl->cfi_len = 0x52;
- /* Standard "QRY" string */
- pfl->cfi_table[0x10] = 'Q';
- pfl->cfi_table[0x11] = 'R';
- pfl->cfi_table[0x12] = 'Y';
- /* Command set (Intel) */
- pfl->cfi_table[0x13] = 0x01;
- pfl->cfi_table[0x14] = 0x00;
- /* Primary extended table address (none) */
- pfl->cfi_table[0x15] = 0x31;
- pfl->cfi_table[0x16] = 0x00;
- /* Alternate command set (none) */
- pfl->cfi_table[0x17] = 0x00;
- pfl->cfi_table[0x18] = 0x00;
- /* Alternate extended table (none) */
- pfl->cfi_table[0x19] = 0x00;
- pfl->cfi_table[0x1A] = 0x00;
- /* Vcc min */
- pfl->cfi_table[0x1B] = 0x45;
- /* Vcc max */
- pfl->cfi_table[0x1C] = 0x55;
- /* Vpp min (no Vpp pin) */
- pfl->cfi_table[0x1D] = 0x00;
- /* Vpp max (no Vpp pin) */
- pfl->cfi_table[0x1E] = 0x00;
- /* Reserved */
- pfl->cfi_table[0x1F] = 0x07;
- /* Timeout for min size buffer write */
- pfl->cfi_table[0x20] = 0x07;
- /* Typical timeout for block erase */
- pfl->cfi_table[0x21] = 0x0a;
- /* Typical timeout for full chip erase (4096 ms) */
- pfl->cfi_table[0x22] = 0x00;
- /* Reserved */
- pfl->cfi_table[0x23] = 0x04;
- /* Max timeout for buffer write */
- pfl->cfi_table[0x24] = 0x04;
- /* Max timeout for block erase */
- pfl->cfi_table[0x25] = 0x04;
- /* Max timeout for chip erase */
- pfl->cfi_table[0x26] = 0x00;
- /* Device size */
- pfl->cfi_table[0x27] = ctz32(device_len); /* + 1; */
- /* Flash device interface (8 & 16 bits) */
- pfl->cfi_table[0x28] = 0x02;
- pfl->cfi_table[0x29] = 0x00;
- /* Max number of bytes in multi-bytes write */
- if (pfl->bank_width == 1) {
- pfl->cfi_table[0x2A] = 0x08;
- } else {
- pfl->cfi_table[0x2A] = 0x0B;
- }
- pfl->writeblock_size = 1 << pfl->cfi_table[0x2A];
-
- pfl->cfi_table[0x2B] = 0x00;
- /* Number of erase block regions (uniform) */
- pfl->cfi_table[0x2C] = 0x01;
- /* Erase block region 1 */
- pfl->cfi_table[0x2D] = blocks_per_device - 1;
- pfl->cfi_table[0x2E] = (blocks_per_device - 1) >> 8;
- pfl->cfi_table[0x2F] = pfl->sector_len >> 8;
- pfl->cfi_table[0x30] = pfl->sector_len >> 16;
-
- /* Extended */
- pfl->cfi_table[0x31] = 'P';
- pfl->cfi_table[0x32] = 'R';
- pfl->cfi_table[0x33] = 'I';
-
- pfl->cfi_table[0x34] = '1';
- pfl->cfi_table[0x35] = '0';
-
- pfl->cfi_table[0x36] = 0x00;
- pfl->cfi_table[0x37] = 0x00;
- pfl->cfi_table[0x38] = 0x00;
- pfl->cfi_table[0x39] = 0x00;
-
- pfl->cfi_table[0x3a] = 0x00;
-
- pfl->cfi_table[0x3b] = 0x00;
- pfl->cfi_table[0x3c] = 0x00;
-
- pfl->cfi_table[0x3f] = 0x01; /* Number of protection fields */
-}
-
-static Property pflash_cfi01_properties[] = {
- DEFINE_PROP_DRIVE("drive", struct pflash_t, blk),
- /* num-blocks is the number of blocks actually visible to the guest,
- * ie the total size of the device divided by the sector length.
- * If we're emulating flash devices wired in parallel the actual
- * number of blocks per indvidual device will differ.
- */
- DEFINE_PROP_UINT32("num-blocks", struct pflash_t, nb_blocs, 0),
- DEFINE_PROP_UINT64("sector-length", struct pflash_t, sector_len, 0),
- /* width here is the overall width of this QEMU device in bytes.
- * The QEMU device may be emulating a number of flash devices
- * wired up in parallel; the width of each individual flash
- * device should be specified via device-width. If the individual
- * devices have a maximum width which is greater than the width
- * they are being used for, this maximum width should be set via
- * max-device-width (which otherwise defaults to device-width).
- * So for instance a 32-bit wide QEMU flash device made from four
- * 16-bit flash devices used in 8-bit wide mode would be configured
- * with width = 4, device-width = 1, max-device-width = 2.
- *
- * If device-width is not specified we default to backwards
- * compatible behaviour which is a bad emulation of two
- * 16 bit devices making up a 32 bit wide QEMU device. This
- * is deprecated for new uses of this device.
- */
- DEFINE_PROP_UINT8("width", struct pflash_t, bank_width, 0),
- DEFINE_PROP_UINT8("device-width", struct pflash_t, device_width, 0),
- DEFINE_PROP_UINT8("max-device-width", struct pflash_t, max_device_width, 0),
- DEFINE_PROP_BIT("big-endian", struct pflash_t, features, PFLASH_BE, 0),
- DEFINE_PROP_BIT("secure", struct pflash_t, features, PFLASH_SECURE, 0),
- DEFINE_PROP_UINT16("id0", struct pflash_t, ident0, 0),
- DEFINE_PROP_UINT16("id1", struct pflash_t, ident1, 0),
- DEFINE_PROP_UINT16("id2", struct pflash_t, ident2, 0),
- DEFINE_PROP_UINT16("id3", struct pflash_t, ident3, 0),
- DEFINE_PROP_STRING("name", struct pflash_t, name),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pflash_cfi01_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = pflash_cfi01_realize;
- dc->props = pflash_cfi01_properties;
- dc->vmsd = &vmstate_pflash;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
-}
-
-
-static const TypeInfo pflash_cfi01_info = {
- .name = TYPE_CFI_PFLASH01,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(struct pflash_t),
- .class_init = pflash_cfi01_class_init,
-};
-
-static void pflash_cfi01_register_types(void)
-{
- type_register_static(&pflash_cfi01_info);
-}
-
-type_init(pflash_cfi01_register_types)
-
-pflash_t *pflash_cfi01_register(hwaddr base,
- DeviceState *qdev, const char *name,
- hwaddr size,
- BlockBackend *blk,
- uint32_t sector_len, int nb_blocs,
- int bank_width, uint16_t id0, uint16_t id1,
- uint16_t id2, uint16_t id3, int be)
-{
- DeviceState *dev = qdev_create(NULL, TYPE_CFI_PFLASH01);
-
- if (blk) {
- qdev_prop_set_drive(dev, "drive", blk, &error_abort);
- }
- qdev_prop_set_uint32(dev, "num-blocks", nb_blocs);
- qdev_prop_set_uint64(dev, "sector-length", sector_len);
- qdev_prop_set_uint8(dev, "width", bank_width);
- qdev_prop_set_bit(dev, "big-endian", !!be);
- qdev_prop_set_uint16(dev, "id0", id0);
- qdev_prop_set_uint16(dev, "id1", id1);
- qdev_prop_set_uint16(dev, "id2", id2);
- qdev_prop_set_uint16(dev, "id3", id3);
- qdev_prop_set_string(dev, "name", name);
- qdev_init_nofail(dev);
-
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
- return CFI_PFLASH01(dev);
-}
-
-MemoryRegion *pflash_cfi01_get_memory(pflash_t *fl)
-{
- return &fl->mem;
-}
-
-static void postload_update_cb(void *opaque, int running, RunState state)
-{
- pflash_t *pfl = opaque;
-
- /* This is called after bdrv_invalidate_cache_all. */
- qemu_del_vm_change_state_handler(pfl->vmstate);
- pfl->vmstate = NULL;
-
- DPRINTF("%s: updating bdrv for %s\n", __func__, pfl->name);
- pflash_update(pfl, 0, pfl->sector_len * pfl->nb_blocs);
-}
-
-static int pflash_post_load(void *opaque, int version_id)
-{
- pflash_t *pfl = opaque;
-
- if (!pfl->ro) {
- pfl->vmstate = qemu_add_vm_change_state_handler(postload_update_cb,
- pfl);
- }
- return 0;
-}
diff --git a/qemu/hw/block/pflash_cfi02.c b/qemu/hw/block/pflash_cfi02.c
deleted file mode 100644
index b13172c6e..000000000
--- a/qemu/hw/block/pflash_cfi02.c
+++ /dev/null
@@ -1,797 +0,0 @@
-/*
- * CFI parallel flash with AMD command set emulation
- *
- * Copyright (c) 2005 Jocelyn Mayer
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * For now, this code can emulate flashes of 1, 2 or 4 bytes width.
- * Supported commands/modes are:
- * - flash read
- * - flash write
- * - flash ID read
- * - sector erase
- * - chip erase
- * - unlock bypass command
- * - CFI queries
- *
- * It does not support flash interleaving.
- * It does not implement boot blocs with reduced size
- * It does not implement software data protection as found in many real chips
- * It does not implement erase suspend/resume commands
- * It does not implement multiple sectors erase
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/block/flash.h"
-#include "qapi/error.h"
-#include "qemu/timer.h"
-#include "sysemu/block-backend.h"
-#include "exec/address-spaces.h"
-#include "qemu/host-utils.h"
-#include "hw/sysbus.h"
-
-//#define PFLASH_DEBUG
-#ifdef PFLASH_DEBUG
-#define DPRINTF(fmt, ...) \
-do { \
- fprintf(stderr, "PFLASH: " fmt , ## __VA_ARGS__); \
-} while (0)
-#else
-#define DPRINTF(fmt, ...) do { } while (0)
-#endif
-
-#define PFLASH_LAZY_ROMD_THRESHOLD 42
-
-#define TYPE_CFI_PFLASH02 "cfi.pflash02"
-#define CFI_PFLASH02(obj) OBJECT_CHECK(pflash_t, (obj), TYPE_CFI_PFLASH02)
-
-struct pflash_t {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- BlockBackend *blk;
- uint32_t sector_len;
- uint32_t nb_blocs;
- uint32_t chip_len;
- uint8_t mappings;
- uint8_t width;
- uint8_t be;
- int wcycle; /* if 0, the flash is read normally */
- int bypass;
- int ro;
- uint8_t cmd;
- uint8_t status;
- /* FIXME: implement array device properties */
- uint16_t ident0;
- uint16_t ident1;
- uint16_t ident2;
- uint16_t ident3;
- uint16_t unlock_addr0;
- uint16_t unlock_addr1;
- uint8_t cfi_len;
- uint8_t cfi_table[0x52];
- QEMUTimer *timer;
- /* The device replicates the flash memory across its memory space. Emulate
- * that by having a container (.mem) filled with an array of aliases
- * (.mem_mappings) pointing to the flash memory (.orig_mem).
- */
- MemoryRegion mem;
- MemoryRegion *mem_mappings; /* array; one per mapping */
- MemoryRegion orig_mem;
- int rom_mode;
- int read_counter; /* used for lazy switch-back to rom mode */
- char *name;
- void *storage;
-};
-
-/*
- * Set up replicated mappings of the same region.
- */
-static void pflash_setup_mappings(pflash_t *pfl)
-{
- unsigned i;
- hwaddr size = memory_region_size(&pfl->orig_mem);
-
- memory_region_init(&pfl->mem, OBJECT(pfl), "pflash", pfl->mappings * size);
- pfl->mem_mappings = g_new(MemoryRegion, pfl->mappings);
- for (i = 0; i < pfl->mappings; ++i) {
- memory_region_init_alias(&pfl->mem_mappings[i], OBJECT(pfl),
- "pflash-alias", &pfl->orig_mem, 0, size);
- memory_region_add_subregion(&pfl->mem, i * size, &pfl->mem_mappings[i]);
- }
-}
-
-static void pflash_register_memory(pflash_t *pfl, int rom_mode)
-{
- memory_region_rom_device_set_romd(&pfl->orig_mem, rom_mode);
- pfl->rom_mode = rom_mode;
-}
-
-static void pflash_timer (void *opaque)
-{
- pflash_t *pfl = opaque;
-
- DPRINTF("%s: command %02x done\n", __func__, pfl->cmd);
- /* Reset flash */
- pfl->status ^= 0x80;
- if (pfl->bypass) {
- pfl->wcycle = 2;
- } else {
- pflash_register_memory(pfl, 1);
- pfl->wcycle = 0;
- }
- pfl->cmd = 0;
-}
-
-static uint32_t pflash_read (pflash_t *pfl, hwaddr offset,
- int width, int be)
-{
- hwaddr boff;
- uint32_t ret;
- uint8_t *p;
-
- DPRINTF("%s: offset " TARGET_FMT_plx "\n", __func__, offset);
- ret = -1;
- /* Lazy reset to ROMD mode after a certain amount of read accesses */
- if (!pfl->rom_mode && pfl->wcycle == 0 &&
- ++pfl->read_counter > PFLASH_LAZY_ROMD_THRESHOLD) {
- pflash_register_memory(pfl, 1);
- }
- offset &= pfl->chip_len - 1;
- boff = offset & 0xFF;
- if (pfl->width == 2)
- boff = boff >> 1;
- else if (pfl->width == 4)
- boff = boff >> 2;
- switch (pfl->cmd) {
- default:
- /* This should never happen : reset state & treat it as a read*/
- 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:
- flash_read:
- /* Flash area read */
- p = pfl->storage;
- switch (width) {
- case 1:
- ret = p[offset];
-// DPRINTF("%s: data offset %08x %02x\n", __func__, offset, ret);
- break;
- case 2:
- if (be) {
- ret = p[offset] << 8;
- ret |= p[offset + 1];
- } else {
- ret = p[offset];
- ret |= p[offset + 1] << 8;
- }
-// DPRINTF("%s: data offset %08x %04x\n", __func__, offset, ret);
- break;
- case 4:
- if (be) {
- ret = p[offset] << 24;
- ret |= p[offset + 1] << 16;
- ret |= p[offset + 2] << 8;
- ret |= p[offset + 3];
- } else {
- ret = p[offset];
- ret |= p[offset + 1] << 8;
- ret |= p[offset + 2] << 16;
- ret |= p[offset + 3] << 24;
- }
-// DPRINTF("%s: data offset %08x %08x\n", __func__, offset, ret);
- break;
- }
- break;
- case 0x90:
- /* flash ID read */
- switch (boff) {
- case 0x00:
- case 0x01:
- ret = boff & 0x01 ? pfl->ident1 : pfl->ident0;
- break;
- case 0x02:
- ret = 0x00; /* Pretend all sectors are unprotected */
- break;
- case 0x0E:
- case 0x0F:
- ret = boff & 0x01 ? pfl->ident3 : pfl->ident2;
- if (ret == (uint8_t)-1) {
- goto flash_read;
- }
- break;
- default:
- goto flash_read;
- }
- DPRINTF("%s: ID " TARGET_FMT_plx " %x\n", __func__, boff, ret);
- break;
- case 0xA0:
- case 0x10:
- case 0x30:
- /* Status register read */
- ret = pfl->status;
- DPRINTF("%s: status %x\n", __func__, ret);
- /* Toggle bit 6 */
- pfl->status ^= 0x40;
- break;
- case 0x98:
- /* CFI query mode */
- if (boff > pfl->cfi_len)
- ret = 0;
- else
- ret = pfl->cfi_table[boff];
- break;
- }
-
- return ret;
-}
-
-/* update flash content on disk */
-static void pflash_update(pflash_t *pfl, int offset,
- int size)
-{
- int offset_end;
- if (pfl->blk) {
- offset_end = offset + size;
- /* round to sectors */
- offset = offset >> 9;
- offset_end = (offset_end + 511) >> 9;
- blk_write(pfl->blk, offset, pfl->storage + (offset << 9),
- offset_end - offset);
- }
-}
-
-static void pflash_write (pflash_t *pfl, hwaddr offset,
- uint32_t value, int width, int be)
-{
- hwaddr boff;
- uint8_t *p;
- uint8_t cmd;
-
- cmd = value;
- if (pfl->cmd != 0xA0 && cmd == 0xF0) {
-#if 0
- DPRINTF("%s: flash reset asked (%02x %02x)\n",
- __func__, pfl->cmd, cmd);
-#endif
- goto reset_flash;
- }
- DPRINTF("%s: offset " TARGET_FMT_plx " %08x %d %d\n", __func__,
- offset, value, width, pfl->wcycle);
- offset &= pfl->chip_len - 1;
-
- DPRINTF("%s: offset " TARGET_FMT_plx " %08x %d\n", __func__,
- offset, value, width);
- boff = offset & (pfl->sector_len - 1);
- if (pfl->width == 2)
- boff = boff >> 1;
- else if (pfl->width == 4)
- boff = boff >> 2;
- switch (pfl->wcycle) {
- case 0:
- /* Set the device in I/O access mode if required */
- if (pfl->rom_mode)
- pflash_register_memory(pfl, 0);
- pfl->read_counter = 0;
- /* We're in read mode */
- check_unlock0:
- if (boff == 0x55 && cmd == 0x98) {
- enter_CFI_mode:
- /* Enter CFI query mode */
- pfl->wcycle = 7;
- pfl->cmd = 0x98;
- return;
- }
- if (boff != pfl->unlock_addr0 || cmd != 0xAA) {
- DPRINTF("%s: unlock0 failed " TARGET_FMT_plx " %02x %04x\n",
- __func__, boff, cmd, pfl->unlock_addr0);
- goto reset_flash;
- }
- DPRINTF("%s: unlock sequence started\n", __func__);
- break;
- case 1:
- /* We started an unlock sequence */
- check_unlock1:
- if (boff != pfl->unlock_addr1 || cmd != 0x55) {
- DPRINTF("%s: unlock1 failed " TARGET_FMT_plx " %02x\n", __func__,
- boff, cmd);
- goto reset_flash;
- }
- DPRINTF("%s: unlock sequence done\n", __func__);
- break;
- case 2:
- /* We finished an unlock sequence */
- if (!pfl->bypass && boff != pfl->unlock_addr0) {
- DPRINTF("%s: command failed " TARGET_FMT_plx " %02x\n", __func__,
- boff, cmd);
- goto reset_flash;
- }
- switch (cmd) {
- case 0x20:
- pfl->bypass = 1;
- goto do_bypass;
- case 0x80:
- case 0x90:
- case 0xA0:
- pfl->cmd = cmd;
- DPRINTF("%s: starting command %02x\n", __func__, cmd);
- break;
- default:
- DPRINTF("%s: unknown command %02x\n", __func__, cmd);
- goto reset_flash;
- }
- break;
- case 3:
- switch (pfl->cmd) {
- case 0x80:
- /* We need another unlock sequence */
- goto check_unlock0;
- case 0xA0:
- DPRINTF("%s: write data offset " TARGET_FMT_plx " %08x %d\n",
- __func__, offset, value, width);
- p = pfl->storage;
- if (!pfl->ro) {
- switch (width) {
- case 1:
- p[offset] &= value;
- pflash_update(pfl, offset, 1);
- break;
- case 2:
- if (be) {
- p[offset] &= value >> 8;
- p[offset + 1] &= value;
- } else {
- p[offset] &= value;
- p[offset + 1] &= value >> 8;
- }
- pflash_update(pfl, offset, 2);
- break;
- case 4:
- if (be) {
- p[offset] &= value >> 24;
- p[offset + 1] &= value >> 16;
- p[offset + 2] &= value >> 8;
- p[offset + 3] &= value;
- } else {
- p[offset] &= value;
- p[offset + 1] &= value >> 8;
- p[offset + 2] &= value >> 16;
- p[offset + 3] &= value >> 24;
- }
- pflash_update(pfl, offset, 4);
- break;
- }
- }
- pfl->status = 0x00 | ~(value & 0x80);
- /* Let's pretend write is immediate */
- if (pfl->bypass)
- goto do_bypass;
- goto reset_flash;
- case 0x90:
- if (pfl->bypass && cmd == 0x00) {
- /* Unlock bypass reset */
- goto reset_flash;
- }
- /* We can enter CFI query mode from autoselect mode */
- if (boff == 0x55 && cmd == 0x98)
- goto enter_CFI_mode;
- /* No break here */
- default:
- DPRINTF("%s: invalid write for command %02x\n",
- __func__, pfl->cmd);
- goto reset_flash;
- }
- case 4:
- switch (pfl->cmd) {
- case 0xA0:
- /* Ignore writes while flash data write is occurring */
- /* As we suppose write is immediate, this should never happen */
- return;
- case 0x80:
- goto check_unlock1;
- default:
- /* Should never happen */
- DPRINTF("%s: invalid command state %02x (wc 4)\n",
- __func__, pfl->cmd);
- goto reset_flash;
- }
- break;
- case 5:
- switch (cmd) {
- case 0x10:
- if (boff != pfl->unlock_addr0) {
- DPRINTF("%s: chip erase: invalid address " TARGET_FMT_plx "\n",
- __func__, offset);
- goto reset_flash;
- }
- /* Chip erase */
- DPRINTF("%s: start chip erase\n", __func__);
- if (!pfl->ro) {
- memset(pfl->storage, 0xFF, pfl->chip_len);
- pflash_update(pfl, 0, pfl->chip_len);
- }
- pfl->status = 0x00;
- /* Let's wait 5 seconds before chip erase is done */
- timer_mod(pfl->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- (NANOSECONDS_PER_SECOND * 5));
- break;
- case 0x30:
- /* Sector erase */
- p = pfl->storage;
- offset &= ~(pfl->sector_len - 1);
- DPRINTF("%s: start sector erase at " TARGET_FMT_plx "\n", __func__,
- offset);
- if (!pfl->ro) {
- memset(p + offset, 0xFF, pfl->sector_len);
- pflash_update(pfl, offset, pfl->sector_len);
- }
- pfl->status = 0x00;
- /* Let's wait 1/2 second before sector erase is done */
- timer_mod(pfl->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- (NANOSECONDS_PER_SECOND / 2));
- break;
- default:
- DPRINTF("%s: invalid command %02x (wc 5)\n", __func__, cmd);
- goto reset_flash;
- }
- pfl->cmd = cmd;
- break;
- case 6:
- switch (pfl->cmd) {
- case 0x10:
- /* Ignore writes during chip erase */
- return;
- case 0x30:
- /* Ignore writes during sector erase */
- return;
- default:
- /* Should never happen */
- DPRINTF("%s: invalid command state %02x (wc 6)\n",
- __func__, pfl->cmd);
- goto reset_flash;
- }
- break;
- case 7: /* Special value for CFI queries */
- DPRINTF("%s: invalid write in CFI query mode\n", __func__);
- goto reset_flash;
- default:
- /* Should never happen */
- DPRINTF("%s: invalid write state (wc 7)\n", __func__);
- goto reset_flash;
- }
- pfl->wcycle++;
-
- return;
-
- /* Reset flash */
- reset_flash:
- pfl->bypass = 0;
- pfl->wcycle = 0;
- pfl->cmd = 0;
- return;
-
- do_bypass:
- pfl->wcycle = 2;
- pfl->cmd = 0;
-}
-
-
-static uint32_t pflash_readb_be(void *opaque, hwaddr addr)
-{
- return pflash_read(opaque, addr, 1, 1);
-}
-
-static uint32_t pflash_readb_le(void *opaque, hwaddr addr)
-{
- return pflash_read(opaque, addr, 1, 0);
-}
-
-static uint32_t pflash_readw_be(void *opaque, hwaddr addr)
-{
- pflash_t *pfl = opaque;
-
- return pflash_read(pfl, addr, 2, 1);
-}
-
-static uint32_t pflash_readw_le(void *opaque, hwaddr addr)
-{
- pflash_t *pfl = opaque;
-
- return pflash_read(pfl, addr, 2, 0);
-}
-
-static uint32_t pflash_readl_be(void *opaque, hwaddr addr)
-{
- pflash_t *pfl = opaque;
-
- return pflash_read(pfl, addr, 4, 1);
-}
-
-static uint32_t pflash_readl_le(void *opaque, hwaddr addr)
-{
- pflash_t *pfl = opaque;
-
- return pflash_read(pfl, addr, 4, 0);
-}
-
-static void pflash_writeb_be(void *opaque, hwaddr addr,
- uint32_t value)
-{
- pflash_write(opaque, addr, value, 1, 1);
-}
-
-static void pflash_writeb_le(void *opaque, hwaddr addr,
- uint32_t value)
-{
- pflash_write(opaque, addr, value, 1, 0);
-}
-
-static void pflash_writew_be(void *opaque, hwaddr addr,
- uint32_t value)
-{
- pflash_t *pfl = opaque;
-
- pflash_write(pfl, addr, value, 2, 1);
-}
-
-static void pflash_writew_le(void *opaque, hwaddr addr,
- uint32_t value)
-{
- pflash_t *pfl = opaque;
-
- pflash_write(pfl, addr, value, 2, 0);
-}
-
-static void pflash_writel_be(void *opaque, hwaddr addr,
- uint32_t value)
-{
- pflash_t *pfl = opaque;
-
- pflash_write(pfl, addr, value, 4, 1);
-}
-
-static void pflash_writel_le(void *opaque, hwaddr addr,
- uint32_t value)
-{
- pflash_t *pfl = opaque;
-
- pflash_write(pfl, addr, value, 4, 0);
-}
-
-static const MemoryRegionOps pflash_cfi02_ops_be = {
- .old_mmio = {
- .read = { pflash_readb_be, pflash_readw_be, pflash_readl_be, },
- .write = { pflash_writeb_be, pflash_writew_be, pflash_writel_be, },
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const MemoryRegionOps pflash_cfi02_ops_le = {
- .old_mmio = {
- .read = { pflash_readb_le, pflash_readw_le, pflash_readl_le, },
- .write = { pflash_writeb_le, pflash_writew_le, pflash_writel_le, },
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
-{
- pflash_t *pfl = CFI_PFLASH02(dev);
- uint32_t chip_len;
- int ret;
- Error *local_err = NULL;
-
- chip_len = pfl->sector_len * pfl->nb_blocs;
- /* XXX: to be fixed */
-#if 0
- if (total_len != (8 * 1024 * 1024) && total_len != (16 * 1024 * 1024) &&
- total_len != (32 * 1024 * 1024) && total_len != (64 * 1024 * 1024))
- return NULL;
-#endif
-
- memory_region_init_rom_device(&pfl->orig_mem, OBJECT(pfl), pfl->be ?
- &pflash_cfi02_ops_be : &pflash_cfi02_ops_le,
- pfl, pfl->name, chip_len, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- vmstate_register_ram(&pfl->orig_mem, DEVICE(pfl));
- pfl->storage = memory_region_get_ram_ptr(&pfl->orig_mem);
- pfl->chip_len = chip_len;
- if (pfl->blk) {
- /* read the initial flash content */
- ret = blk_read(pfl->blk, 0, pfl->storage, chip_len >> 9);
- if (ret < 0) {
- vmstate_unregister_ram(&pfl->orig_mem, DEVICE(pfl));
- error_setg(errp, "failed to read the initial flash content");
- return;
- }
- }
-
- pflash_setup_mappings(pfl);
- pfl->rom_mode = 1;
- sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->mem);
-
- if (pfl->blk) {
- pfl->ro = blk_is_read_only(pfl->blk);
- } else {
- pfl->ro = 0;
- }
-
- pfl->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, pflash_timer, pfl);
- pfl->wcycle = 0;
- pfl->cmd = 0;
- pfl->status = 0;
- /* Hardcoded CFI table (mostly from SG29 Spansion flash) */
- pfl->cfi_len = 0x52;
- /* Standard "QRY" string */
- pfl->cfi_table[0x10] = 'Q';
- pfl->cfi_table[0x11] = 'R';
- pfl->cfi_table[0x12] = 'Y';
- /* Command set (AMD/Fujitsu) */
- pfl->cfi_table[0x13] = 0x02;
- pfl->cfi_table[0x14] = 0x00;
- /* Primary extended table address */
- pfl->cfi_table[0x15] = 0x31;
- pfl->cfi_table[0x16] = 0x00;
- /* Alternate command set (none) */
- pfl->cfi_table[0x17] = 0x00;
- pfl->cfi_table[0x18] = 0x00;
- /* Alternate extended table (none) */
- pfl->cfi_table[0x19] = 0x00;
- pfl->cfi_table[0x1A] = 0x00;
- /* Vcc min */
- pfl->cfi_table[0x1B] = 0x27;
- /* Vcc max */
- pfl->cfi_table[0x1C] = 0x36;
- /* Vpp min (no Vpp pin) */
- pfl->cfi_table[0x1D] = 0x00;
- /* Vpp max (no Vpp pin) */
- pfl->cfi_table[0x1E] = 0x00;
- /* Reserved */
- pfl->cfi_table[0x1F] = 0x07;
- /* Timeout for min size buffer write (NA) */
- pfl->cfi_table[0x20] = 0x00;
- /* Typical timeout for block erase (512 ms) */
- pfl->cfi_table[0x21] = 0x09;
- /* Typical timeout for full chip erase (4096 ms) */
- pfl->cfi_table[0x22] = 0x0C;
- /* Reserved */
- pfl->cfi_table[0x23] = 0x01;
- /* Max timeout for buffer write (NA) */
- pfl->cfi_table[0x24] = 0x00;
- /* Max timeout for block erase */
- pfl->cfi_table[0x25] = 0x0A;
- /* Max timeout for chip erase */
- pfl->cfi_table[0x26] = 0x0D;
- /* Device size */
- pfl->cfi_table[0x27] = ctz32(chip_len);
- /* Flash device interface (8 & 16 bits) */
- pfl->cfi_table[0x28] = 0x02;
- pfl->cfi_table[0x29] = 0x00;
- /* Max number of bytes in multi-bytes write */
- /* XXX: disable buffered write as it's not supported */
- // pfl->cfi_table[0x2A] = 0x05;
- pfl->cfi_table[0x2A] = 0x00;
- pfl->cfi_table[0x2B] = 0x00;
- /* Number of erase block regions (uniform) */
- pfl->cfi_table[0x2C] = 0x01;
- /* Erase block region 1 */
- pfl->cfi_table[0x2D] = pfl->nb_blocs - 1;
- pfl->cfi_table[0x2E] = (pfl->nb_blocs - 1) >> 8;
- pfl->cfi_table[0x2F] = pfl->sector_len >> 8;
- pfl->cfi_table[0x30] = pfl->sector_len >> 16;
-
- /* Extended */
- pfl->cfi_table[0x31] = 'P';
- pfl->cfi_table[0x32] = 'R';
- pfl->cfi_table[0x33] = 'I';
-
- pfl->cfi_table[0x34] = '1';
- pfl->cfi_table[0x35] = '0';
-
- pfl->cfi_table[0x36] = 0x00;
- pfl->cfi_table[0x37] = 0x00;
- pfl->cfi_table[0x38] = 0x00;
- pfl->cfi_table[0x39] = 0x00;
-
- pfl->cfi_table[0x3a] = 0x00;
-
- pfl->cfi_table[0x3b] = 0x00;
- pfl->cfi_table[0x3c] = 0x00;
-}
-
-static Property pflash_cfi02_properties[] = {
- DEFINE_PROP_DRIVE("drive", struct pflash_t, blk),
- DEFINE_PROP_UINT32("num-blocks", struct pflash_t, nb_blocs, 0),
- DEFINE_PROP_UINT32("sector-length", struct pflash_t, sector_len, 0),
- DEFINE_PROP_UINT8("width", struct pflash_t, width, 0),
- DEFINE_PROP_UINT8("mappings", struct pflash_t, mappings, 0),
- DEFINE_PROP_UINT8("big-endian", struct pflash_t, be, 0),
- DEFINE_PROP_UINT16("id0", struct pflash_t, ident0, 0),
- DEFINE_PROP_UINT16("id1", struct pflash_t, ident1, 0),
- DEFINE_PROP_UINT16("id2", struct pflash_t, ident2, 0),
- DEFINE_PROP_UINT16("id3", struct pflash_t, ident3, 0),
- DEFINE_PROP_UINT16("unlock-addr0", struct pflash_t, unlock_addr0, 0),
- DEFINE_PROP_UINT16("unlock-addr1", struct pflash_t, unlock_addr1, 0),
- DEFINE_PROP_STRING("name", struct pflash_t, name),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pflash_cfi02_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = pflash_cfi02_realize;
- dc->props = pflash_cfi02_properties;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
-}
-
-static const TypeInfo pflash_cfi02_info = {
- .name = TYPE_CFI_PFLASH02,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(struct pflash_t),
- .class_init = pflash_cfi02_class_init,
-};
-
-static void pflash_cfi02_register_types(void)
-{
- type_register_static(&pflash_cfi02_info);
-}
-
-type_init(pflash_cfi02_register_types)
-
-pflash_t *pflash_cfi02_register(hwaddr base,
- DeviceState *qdev, const char *name,
- hwaddr size,
- BlockBackend *blk, uint32_t sector_len,
- int nb_blocs, int nb_mappings, int width,
- uint16_t id0, uint16_t id1,
- uint16_t id2, uint16_t id3,
- uint16_t unlock_addr0, uint16_t unlock_addr1,
- int be)
-{
- DeviceState *dev = qdev_create(NULL, TYPE_CFI_PFLASH02);
-
- if (blk) {
- qdev_prop_set_drive(dev, "drive", blk, &error_abort);
- }
- qdev_prop_set_uint32(dev, "num-blocks", nb_blocs);
- qdev_prop_set_uint32(dev, "sector-length", sector_len);
- qdev_prop_set_uint8(dev, "width", width);
- qdev_prop_set_uint8(dev, "mappings", nb_mappings);
- qdev_prop_set_uint8(dev, "big-endian", !!be);
- qdev_prop_set_uint16(dev, "id0", id0);
- qdev_prop_set_uint16(dev, "id1", id1);
- qdev_prop_set_uint16(dev, "id2", id2);
- qdev_prop_set_uint16(dev, "id3", id3);
- qdev_prop_set_uint16(dev, "unlock-addr0", unlock_addr0);
- qdev_prop_set_uint16(dev, "unlock-addr1", unlock_addr1);
- qdev_prop_set_string(dev, "name", name);
- qdev_init_nofail(dev);
-
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
- return CFI_PFLASH02(dev);
-}
diff --git a/qemu/hw/block/tc58128.c b/qemu/hw/block/tc58128.c
deleted file mode 100644
index 7909d5041..000000000
--- a/qemu/hw/block/tc58128.c
+++ /dev/null
@@ -1,181 +0,0 @@
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/sh4/sh.h"
-#include "hw/loader.h"
-#include "sysemu/qtest.h"
-#include "qemu/error-report.h"
-
-#define CE1 0x0100
-#define CE2 0x0200
-#define RE 0x0400
-#define WE 0x0800
-#define ALE 0x1000
-#define CLE 0x2000
-#define RDY1 0x4000
-#define RDY2 0x8000
-#define RDY(n) ((n) == 0 ? RDY1 : RDY2)
-
-typedef enum { WAIT, READ1, READ2, READ3 } state_t;
-
-typedef struct {
- uint8_t *flash_contents;
- state_t state;
- uint32_t address;
- uint8_t address_cycle;
-} tc58128_dev;
-
-static tc58128_dev tc58128_devs[2];
-
-#define FLASH_SIZE (16*1024*1024)
-
-static void init_dev(tc58128_dev * dev, const char *filename)
-{
- int ret, blocks;
-
- dev->state = WAIT;
- dev->flash_contents = g_malloc(FLASH_SIZE);
- memset(dev->flash_contents, 0xff, FLASH_SIZE);
- if (filename) {
- /* Load flash image skipping the first block */
- ret = load_image(filename, dev->flash_contents + 528 * 32);
- if (ret < 0) {
- if (!qtest_enabled()) {
- error_report("Could not load flash image %s", filename);
- exit(1);
- }
- } else {
- /* Build first block with number of blocks */
- blocks = (ret + 528 * 32 - 1) / (528 * 32);
- dev->flash_contents[0] = blocks & 0xff;
- dev->flash_contents[1] = (blocks >> 8) & 0xff;
- dev->flash_contents[2] = (blocks >> 16) & 0xff;
- dev->flash_contents[3] = (blocks >> 24) & 0xff;
- fprintf(stderr, "loaded %d bytes for %s into flash\n", ret,
- filename);
- }
- }
-}
-
-static void handle_command(tc58128_dev * dev, uint8_t command)
-{
- switch (command) {
- case 0xff:
- fprintf(stderr, "reset flash device\n");
- dev->state = WAIT;
- break;
- case 0x00:
- fprintf(stderr, "read mode 1\n");
- dev->state = READ1;
- dev->address_cycle = 0;
- break;
- case 0x01:
- fprintf(stderr, "read mode 2\n");
- dev->state = READ2;
- dev->address_cycle = 0;
- break;
- case 0x50:
- fprintf(stderr, "read mode 3\n");
- dev->state = READ3;
- dev->address_cycle = 0;
- break;
- default:
- fprintf(stderr, "unknown flash command 0x%02x\n", command);
- abort();
- }
-}
-
-static void handle_address(tc58128_dev * dev, uint8_t data)
-{
- switch (dev->state) {
- case READ1:
- case READ2:
- case READ3:
- switch (dev->address_cycle) {
- case 0:
- dev->address = data;
- if (dev->state == READ2)
- dev->address |= 0x100;
- else if (dev->state == READ3)
- dev->address |= 0x200;
- break;
- case 1:
- dev->address += data * 528 * 0x100;
- break;
- case 2:
- dev->address += data * 528;
- fprintf(stderr, "address pointer in flash: 0x%08x\n",
- dev->address);
- break;
- default:
- /* Invalid data */
- abort();
- }
- dev->address_cycle++;
- break;
- default:
- abort();
- }
-}
-
-static uint8_t handle_read(tc58128_dev * dev)
-{
-#if 0
- if (dev->address % 0x100000 == 0)
- fprintf(stderr, "reading flash at address 0x%08x\n", dev->address);
-#endif
- return dev->flash_contents[dev->address++];
-}
-
-/* We never mark the device as busy, so interrupts cannot be triggered
- XXXXX */
-
-static int tc58128_cb(uint16_t porta, uint16_t portb,
- uint16_t * periph_pdtra, uint16_t * periph_portadir,
- uint16_t * periph_pdtrb, uint16_t * periph_portbdir)
-{
- int dev;
-
- if ((porta & CE1) == 0)
- dev = 0;
- else if ((porta & CE2) == 0)
- dev = 1;
- else
- return 0; /* No device selected */
-
- if ((porta & RE) && (porta & WE)) {
- /* Nothing to do, assert ready and return to input state */
- *periph_portadir &= 0xff00;
- *periph_portadir |= RDY(dev);
- *periph_pdtra |= RDY(dev);
- return 1;
- }
-
- if (porta & CLE) {
- /* Command */
- assert((porta & WE) == 0);
- handle_command(&tc58128_devs[dev], porta & 0x00ff);
- } else if (porta & ALE) {
- assert((porta & WE) == 0);
- handle_address(&tc58128_devs[dev], porta & 0x00ff);
- } else if ((porta & RE) == 0) {
- *periph_portadir |= 0x00ff;
- *periph_pdtra &= 0xff00;
- *periph_pdtra |= handle_read(&tc58128_devs[dev]);
- } else {
- abort();
- }
- return 1;
-}
-
-static sh7750_io_device tc58128 = {
- RE | WE, /* Port A triggers */
- 0, /* Port B triggers */
- tc58128_cb /* Callback */
-};
-
-int tc58128_init(struct SH7750State *s, const char *zone1, const char *zone2)
-{
- init_dev(&tc58128_devs[0], zone1);
- init_dev(&tc58128_devs[1], zone2);
- return sh7750_register_io_device(s, &tc58128);
-}
diff --git a/qemu/hw/block/virtio-blk.c b/qemu/hw/block/virtio-blk.c
deleted file mode 100644
index 3f88f8cf5..000000000
--- a/qemu/hw/block/virtio-blk.c
+++ /dev/null
@@ -1,980 +0,0 @@
-/*
- * Virtio Block Device
- *
- * Copyright IBM, Corp. 2007
- *
- * Authors:
- * Anthony Liguori <aliguori@us.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "qemu/iov.h"
-#include "qemu/error-report.h"
-#include "trace.h"
-#include "hw/block/block.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
-#include "hw/virtio/virtio-blk.h"
-#include "dataplane/virtio-blk.h"
-#include "block/scsi.h"
-#ifdef __linux__
-# include <scsi/sg.h>
-#endif
-#include "hw/virtio/virtio-bus.h"
-#include "hw/virtio/virtio-access.h"
-
-void virtio_blk_init_request(VirtIOBlock *s, VirtIOBlockReq *req)
-{
- req->dev = s;
- req->qiov.size = 0;
- req->in_len = 0;
- req->next = NULL;
- req->mr_next = NULL;
-}
-
-void virtio_blk_free_request(VirtIOBlockReq *req)
-{
- if (req) {
- g_free(req);
- }
-}
-
-static void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status)
-{
- VirtIOBlock *s = req->dev;
- VirtIODevice *vdev = VIRTIO_DEVICE(s);
-
- trace_virtio_blk_req_complete(req, status);
-
- stb_p(&req->in->status, status);
- virtqueue_push(s->vq, &req->elem, req->in_len);
- if (s->dataplane_started && !s->dataplane_disabled) {
- virtio_blk_data_plane_notify(s->dataplane);
- } else {
- virtio_notify(vdev, s->vq);
- }
-}
-
-static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error,
- bool is_read)
-{
- BlockErrorAction action = blk_get_error_action(req->dev->blk,
- is_read, error);
- VirtIOBlock *s = req->dev;
-
- if (action == BLOCK_ERROR_ACTION_STOP) {
- /* Break the link as the next request is going to be parsed from the
- * ring again. Otherwise we may end up doing a double completion! */
- req->mr_next = NULL;
- req->next = s->rq;
- s->rq = req;
- } else if (action == BLOCK_ERROR_ACTION_REPORT) {
- virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
- block_acct_failed(blk_get_stats(s->blk), &req->acct);
- virtio_blk_free_request(req);
- }
-
- blk_error_action(s->blk, action, is_read, error);
- return action != BLOCK_ERROR_ACTION_IGNORE;
-}
-
-static void virtio_blk_rw_complete(void *opaque, int ret)
-{
- VirtIOBlockReq *next = opaque;
-
- while (next) {
- VirtIOBlockReq *req = next;
- next = req->mr_next;
- trace_virtio_blk_rw_complete(req, ret);
-
- if (req->qiov.nalloc != -1) {
- /* If nalloc is != 1 req->qiov is a local copy of the original
- * external iovec. It was allocated in submit_merged_requests
- * to be able to merge requests. */
- qemu_iovec_destroy(&req->qiov);
- }
-
- if (ret) {
- int p = virtio_ldl_p(VIRTIO_DEVICE(req->dev), &req->out.type);
- bool is_read = !(p & VIRTIO_BLK_T_OUT);
- /* Note that memory may be dirtied on read failure. If the
- * virtio request is not completed here, as is the case for
- * BLOCK_ERROR_ACTION_STOP, the memory may not be copied
- * correctly during live migration. While this is ugly,
- * it is acceptable because the device is free to write to
- * the memory until the request is completed (which will
- * happen on the other side of the migration).
- */
- if (virtio_blk_handle_rw_error(req, -ret, is_read)) {
- continue;
- }
- }
-
- virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
- block_acct_done(blk_get_stats(req->dev->blk), &req->acct);
- virtio_blk_free_request(req);
- }
-}
-
-static void virtio_blk_flush_complete(void *opaque, int ret)
-{
- VirtIOBlockReq *req = opaque;
-
- if (ret) {
- if (virtio_blk_handle_rw_error(req, -ret, 0)) {
- return;
- }
- }
-
- virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
- block_acct_done(blk_get_stats(req->dev->blk), &req->acct);
- virtio_blk_free_request(req);
-}
-
-#ifdef __linux__
-
-typedef struct {
- VirtIOBlockReq *req;
- struct sg_io_hdr hdr;
-} VirtIOBlockIoctlReq;
-
-static void virtio_blk_ioctl_complete(void *opaque, int status)
-{
- VirtIOBlockIoctlReq *ioctl_req = opaque;
- VirtIOBlockReq *req = ioctl_req->req;
- VirtIODevice *vdev = VIRTIO_DEVICE(req->dev);
- struct virtio_scsi_inhdr *scsi;
- struct sg_io_hdr *hdr;
-
- scsi = (void *)req->elem.in_sg[req->elem.in_num - 2].iov_base;
-
- if (status) {
- status = VIRTIO_BLK_S_UNSUPP;
- virtio_stl_p(vdev, &scsi->errors, 255);
- goto out;
- }
-
- hdr = &ioctl_req->hdr;
- /*
- * From SCSI-Generic-HOWTO: "Some lower level drivers (e.g. ide-scsi)
- * clear the masked_status field [hence status gets cleared too, see
- * block/scsi_ioctl.c] even when a CHECK_CONDITION or COMMAND_TERMINATED
- * status has occurred. However they do set DRIVER_SENSE in driver_status
- * field. Also a (sb_len_wr > 0) indicates there is a sense buffer.
- */
- if (hdr->status == 0 && hdr->sb_len_wr > 0) {
- hdr->status = CHECK_CONDITION;
- }
-
- virtio_stl_p(vdev, &scsi->errors,
- hdr->status | (hdr->msg_status << 8) |
- (hdr->host_status << 16) | (hdr->driver_status << 24));
- virtio_stl_p(vdev, &scsi->residual, hdr->resid);
- virtio_stl_p(vdev, &scsi->sense_len, hdr->sb_len_wr);
- virtio_stl_p(vdev, &scsi->data_len, hdr->dxfer_len);
-
-out:
- virtio_blk_req_complete(req, status);
- virtio_blk_free_request(req);
- g_free(ioctl_req);
-}
-
-#endif
-
-static VirtIOBlockReq *virtio_blk_get_request(VirtIOBlock *s)
-{
- VirtIOBlockReq *req = virtqueue_pop(s->vq, sizeof(VirtIOBlockReq));
-
- if (req) {
- virtio_blk_init_request(s, req);
- }
- return req;
-}
-
-static int virtio_blk_handle_scsi_req(VirtIOBlockReq *req)
-{
- int status = VIRTIO_BLK_S_OK;
- struct virtio_scsi_inhdr *scsi = NULL;
- VirtIODevice *vdev = VIRTIO_DEVICE(req->dev);
- VirtQueueElement *elem = &req->elem;
- VirtIOBlock *blk = req->dev;
-
-#ifdef __linux__
- int i;
- VirtIOBlockIoctlReq *ioctl_req;
- BlockAIOCB *acb;
-#endif
-
- /*
- * We require at least one output segment each for the virtio_blk_outhdr
- * and the SCSI command block.
- *
- * We also at least require the virtio_blk_inhdr, the virtio_scsi_inhdr
- * and the sense buffer pointer in the input segments.
- */
- if (elem->out_num < 2 || elem->in_num < 3) {
- status = VIRTIO_BLK_S_IOERR;
- goto fail;
- }
-
- /*
- * The scsi inhdr is placed in the second-to-last input segment, just
- * before the regular inhdr.
- */
- scsi = (void *)elem->in_sg[elem->in_num - 2].iov_base;
-
- if (!blk->conf.scsi) {
- status = VIRTIO_BLK_S_UNSUPP;
- goto fail;
- }
-
- /*
- * No support for bidirection commands yet.
- */
- if (elem->out_num > 2 && elem->in_num > 3) {
- status = VIRTIO_BLK_S_UNSUPP;
- goto fail;
- }
-
-#ifdef __linux__
- ioctl_req = g_new0(VirtIOBlockIoctlReq, 1);
- ioctl_req->req = req;
- ioctl_req->hdr.interface_id = 'S';
- ioctl_req->hdr.cmd_len = elem->out_sg[1].iov_len;
- ioctl_req->hdr.cmdp = elem->out_sg[1].iov_base;
- ioctl_req->hdr.dxfer_len = 0;
-
- if (elem->out_num > 2) {
- /*
- * If there are more than the minimally required 2 output segments
- * there is write payload starting from the third iovec.
- */
- ioctl_req->hdr.dxfer_direction = SG_DXFER_TO_DEV;
- ioctl_req->hdr.iovec_count = elem->out_num - 2;
-
- for (i = 0; i < ioctl_req->hdr.iovec_count; i++) {
- ioctl_req->hdr.dxfer_len += elem->out_sg[i + 2].iov_len;
- }
-
- ioctl_req->hdr.dxferp = elem->out_sg + 2;
-
- } else if (elem->in_num > 3) {
- /*
- * If we have more than 3 input segments the guest wants to actually
- * read data.
- */
- ioctl_req->hdr.dxfer_direction = SG_DXFER_FROM_DEV;
- ioctl_req->hdr.iovec_count = elem->in_num - 3;
- for (i = 0; i < ioctl_req->hdr.iovec_count; i++) {
- ioctl_req->hdr.dxfer_len += elem->in_sg[i].iov_len;
- }
-
- ioctl_req->hdr.dxferp = elem->in_sg;
- } else {
- /*
- * Some SCSI commands don't actually transfer any data.
- */
- ioctl_req->hdr.dxfer_direction = SG_DXFER_NONE;
- }
-
- ioctl_req->hdr.sbp = elem->in_sg[elem->in_num - 3].iov_base;
- ioctl_req->hdr.mx_sb_len = elem->in_sg[elem->in_num - 3].iov_len;
-
- acb = blk_aio_ioctl(blk->blk, SG_IO, &ioctl_req->hdr,
- virtio_blk_ioctl_complete, ioctl_req);
- if (!acb) {
- g_free(ioctl_req);
- status = VIRTIO_BLK_S_UNSUPP;
- goto fail;
- }
- return -EINPROGRESS;
-#else
- abort();
-#endif
-
-fail:
- /* Just put anything nonzero so that the ioctl fails in the guest. */
- if (scsi) {
- virtio_stl_p(vdev, &scsi->errors, 255);
- }
- return status;
-}
-
-static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
-{
- int status;
-
- status = virtio_blk_handle_scsi_req(req);
- if (status != -EINPROGRESS) {
- virtio_blk_req_complete(req, status);
- virtio_blk_free_request(req);
- }
-}
-
-static inline void submit_requests(BlockBackend *blk, MultiReqBuffer *mrb,
- int start, int num_reqs, int niov)
-{
- QEMUIOVector *qiov = &mrb->reqs[start]->qiov;
- int64_t sector_num = mrb->reqs[start]->sector_num;
- int nb_sectors = mrb->reqs[start]->qiov.size / BDRV_SECTOR_SIZE;
- bool is_write = mrb->is_write;
-
- if (num_reqs > 1) {
- int i;
- struct iovec *tmp_iov = qiov->iov;
- int tmp_niov = qiov->niov;
-
- /* mrb->reqs[start]->qiov was initialized from external so we can't
- * modifiy it here. We need to initialize it locally and then add the
- * external iovecs. */
- qemu_iovec_init(qiov, niov);
-
- for (i = 0; i < tmp_niov; i++) {
- qemu_iovec_add(qiov, tmp_iov[i].iov_base, tmp_iov[i].iov_len);
- }
-
- for (i = start + 1; i < start + num_reqs; i++) {
- qemu_iovec_concat(qiov, &mrb->reqs[i]->qiov, 0,
- mrb->reqs[i]->qiov.size);
- mrb->reqs[i - 1]->mr_next = mrb->reqs[i];
- nb_sectors += mrb->reqs[i]->qiov.size / BDRV_SECTOR_SIZE;
- }
- assert(nb_sectors == qiov->size / BDRV_SECTOR_SIZE);
-
- trace_virtio_blk_submit_multireq(mrb, start, num_reqs, sector_num,
- nb_sectors, is_write);
- block_acct_merge_done(blk_get_stats(blk),
- is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ,
- num_reqs - 1);
- }
-
- if (is_write) {
- blk_aio_writev(blk, sector_num, qiov, nb_sectors,
- virtio_blk_rw_complete, mrb->reqs[start]);
- } else {
- blk_aio_readv(blk, sector_num, qiov, nb_sectors,
- virtio_blk_rw_complete, mrb->reqs[start]);
- }
-}
-
-static int multireq_compare(const void *a, const void *b)
-{
- const VirtIOBlockReq *req1 = *(VirtIOBlockReq **)a,
- *req2 = *(VirtIOBlockReq **)b;
-
- /*
- * Note that we can't simply subtract sector_num1 from sector_num2
- * here as that could overflow the return value.
- */
- if (req1->sector_num > req2->sector_num) {
- return 1;
- } else if (req1->sector_num < req2->sector_num) {
- return -1;
- } else {
- return 0;
- }
-}
-
-void virtio_blk_submit_multireq(BlockBackend *blk, MultiReqBuffer *mrb)
-{
- int i = 0, start = 0, num_reqs = 0, niov = 0, nb_sectors = 0;
- int max_xfer_len = 0;
- int64_t sector_num = 0;
-
- if (mrb->num_reqs == 1) {
- submit_requests(blk, mrb, 0, 1, -1);
- mrb->num_reqs = 0;
- return;
- }
-
- max_xfer_len = blk_get_max_transfer_length(mrb->reqs[0]->dev->blk);
- max_xfer_len = MIN_NON_ZERO(max_xfer_len, BDRV_REQUEST_MAX_SECTORS);
-
- qsort(mrb->reqs, mrb->num_reqs, sizeof(*mrb->reqs),
- &multireq_compare);
-
- for (i = 0; i < mrb->num_reqs; i++) {
- VirtIOBlockReq *req = mrb->reqs[i];
- if (num_reqs > 0) {
- /*
- * NOTE: We cannot merge the requests in below situations:
- * 1. requests are not sequential
- * 2. merge would exceed maximum number of IOVs
- * 3. merge would exceed maximum transfer length of backend device
- */
- if (sector_num + nb_sectors != req->sector_num ||
- niov > blk_get_max_iov(blk) - req->qiov.niov ||
- req->qiov.size / BDRV_SECTOR_SIZE > max_xfer_len ||
- nb_sectors > max_xfer_len - req->qiov.size / BDRV_SECTOR_SIZE) {
- submit_requests(blk, mrb, start, num_reqs, niov);
- num_reqs = 0;
- }
- }
-
- if (num_reqs == 0) {
- sector_num = req->sector_num;
- nb_sectors = niov = 0;
- start = i;
- }
-
- nb_sectors += req->qiov.size / BDRV_SECTOR_SIZE;
- niov += req->qiov.niov;
- num_reqs++;
- }
-
- submit_requests(blk, mrb, start, num_reqs, niov);
- mrb->num_reqs = 0;
-}
-
-static void virtio_blk_handle_flush(VirtIOBlockReq *req, MultiReqBuffer *mrb)
-{
- block_acct_start(blk_get_stats(req->dev->blk), &req->acct, 0,
- BLOCK_ACCT_FLUSH);
-
- /*
- * Make sure all outstanding writes are posted to the backing device.
- */
- if (mrb->is_write && mrb->num_reqs > 0) {
- virtio_blk_submit_multireq(req->dev->blk, mrb);
- }
- blk_aio_flush(req->dev->blk, virtio_blk_flush_complete, req);
-}
-
-static bool virtio_blk_sect_range_ok(VirtIOBlock *dev,
- uint64_t sector, size_t size)
-{
- uint64_t nb_sectors = size >> BDRV_SECTOR_BITS;
- uint64_t total_sectors;
-
- if (nb_sectors > BDRV_REQUEST_MAX_SECTORS) {
- return false;
- }
- if (sector & dev->sector_mask) {
- return false;
- }
- if (size % dev->conf.conf.logical_block_size) {
- return false;
- }
- blk_get_geometry(dev->blk, &total_sectors);
- if (sector > total_sectors || nb_sectors > total_sectors - sector) {
- return false;
- }
- return true;
-}
-
-void virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
-{
- uint32_t type;
- struct iovec *in_iov = req->elem.in_sg;
- struct iovec *iov = req->elem.out_sg;
- unsigned in_num = req->elem.in_num;
- unsigned out_num = req->elem.out_num;
-
- if (req->elem.out_num < 1 || req->elem.in_num < 1) {
- error_report("virtio-blk missing headers");
- exit(1);
- }
-
- if (unlikely(iov_to_buf(iov, out_num, 0, &req->out,
- sizeof(req->out)) != sizeof(req->out))) {
- error_report("virtio-blk request outhdr too short");
- exit(1);
- }
-
- iov_discard_front(&iov, &out_num, sizeof(req->out));
-
- if (in_iov[in_num - 1].iov_len < sizeof(struct virtio_blk_inhdr)) {
- error_report("virtio-blk request inhdr too short");
- exit(1);
- }
-
- /* We always touch the last byte, so just see how big in_iov is. */
- req->in_len = iov_size(in_iov, in_num);
- req->in = (void *)in_iov[in_num - 1].iov_base
- + in_iov[in_num - 1].iov_len
- - sizeof(struct virtio_blk_inhdr);
- iov_discard_back(in_iov, &in_num, sizeof(struct virtio_blk_inhdr));
-
- type = virtio_ldl_p(VIRTIO_DEVICE(req->dev), &req->out.type);
-
- /* VIRTIO_BLK_T_OUT defines the command direction. VIRTIO_BLK_T_BARRIER
- * is an optional flag. Although a guest should not send this flag if
- * not negotiated we ignored it in the past. So keep ignoring it. */
- switch (type & ~(VIRTIO_BLK_T_OUT | VIRTIO_BLK_T_BARRIER)) {
- case VIRTIO_BLK_T_IN:
- {
- bool is_write = type & VIRTIO_BLK_T_OUT;
- req->sector_num = virtio_ldq_p(VIRTIO_DEVICE(req->dev),
- &req->out.sector);
-
- if (is_write) {
- qemu_iovec_init_external(&req->qiov, iov, out_num);
- trace_virtio_blk_handle_write(req, req->sector_num,
- req->qiov.size / BDRV_SECTOR_SIZE);
- } else {
- qemu_iovec_init_external(&req->qiov, in_iov, in_num);
- trace_virtio_blk_handle_read(req, req->sector_num,
- req->qiov.size / BDRV_SECTOR_SIZE);
- }
-
- if (!virtio_blk_sect_range_ok(req->dev, req->sector_num,
- req->qiov.size)) {
- virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
- block_acct_invalid(blk_get_stats(req->dev->blk),
- is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ);
- virtio_blk_free_request(req);
- return;
- }
-
- block_acct_start(blk_get_stats(req->dev->blk),
- &req->acct, req->qiov.size,
- is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ);
-
- /* merge would exceed maximum number of requests or IO direction
- * changes */
- if (mrb->num_reqs > 0 && (mrb->num_reqs == VIRTIO_BLK_MAX_MERGE_REQS ||
- is_write != mrb->is_write ||
- !req->dev->conf.request_merging)) {
- virtio_blk_submit_multireq(req->dev->blk, mrb);
- }
-
- assert(mrb->num_reqs < VIRTIO_BLK_MAX_MERGE_REQS);
- mrb->reqs[mrb->num_reqs++] = req;
- mrb->is_write = is_write;
- break;
- }
- case VIRTIO_BLK_T_FLUSH:
- virtio_blk_handle_flush(req, mrb);
- break;
- case VIRTIO_BLK_T_SCSI_CMD:
- virtio_blk_handle_scsi(req);
- break;
- case VIRTIO_BLK_T_GET_ID:
- {
- VirtIOBlock *s = req->dev;
-
- /*
- * NB: per existing s/n string convention the string is
- * terminated by '\0' only when shorter than buffer.
- */
- const char *serial = s->conf.serial ? s->conf.serial : "";
- size_t size = MIN(strlen(serial) + 1,
- MIN(iov_size(in_iov, in_num),
- VIRTIO_BLK_ID_BYTES));
- iov_from_buf(in_iov, in_num, 0, serial, size);
- virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
- virtio_blk_free_request(req);
- break;
- }
- default:
- virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
- virtio_blk_free_request(req);
- }
-}
-
-void virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq)
-{
- VirtIOBlockReq *req;
- MultiReqBuffer mrb = {};
-
- blk_io_plug(s->blk);
-
- while ((req = virtio_blk_get_request(s))) {
- virtio_blk_handle_request(req, &mrb);
- }
-
- if (mrb.num_reqs) {
- virtio_blk_submit_multireq(s->blk, &mrb);
- }
-
- blk_io_unplug(s->blk);
-}
-
-static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
-{
- VirtIOBlock *s = (VirtIOBlock *)vdev;
-
- if (s->dataplane) {
- /* Some guests kick before setting VIRTIO_CONFIG_S_DRIVER_OK so start
- * dataplane here instead of waiting for .set_status().
- */
- virtio_blk_data_plane_start(s->dataplane);
- if (!s->dataplane_disabled) {
- return;
- }
- }
- virtio_blk_handle_vq(s, vq);
-}
-
-static void virtio_blk_dma_restart_bh(void *opaque)
-{
- VirtIOBlock *s = opaque;
- VirtIOBlockReq *req = s->rq;
- MultiReqBuffer mrb = {};
-
- qemu_bh_delete(s->bh);
- s->bh = NULL;
-
- s->rq = NULL;
-
- while (req) {
- VirtIOBlockReq *next = req->next;
- virtio_blk_handle_request(req, &mrb);
- req = next;
- }
-
- if (mrb.num_reqs) {
- virtio_blk_submit_multireq(s->blk, &mrb);
- }
-}
-
-static void virtio_blk_dma_restart_cb(void *opaque, int running,
- RunState state)
-{
- VirtIOBlock *s = opaque;
-
- if (!running) {
- return;
- }
-
- if (!s->bh) {
- s->bh = aio_bh_new(blk_get_aio_context(s->conf.conf.blk),
- virtio_blk_dma_restart_bh, s);
- qemu_bh_schedule(s->bh);
- }
-}
-
-static void virtio_blk_reset(VirtIODevice *vdev)
-{
- VirtIOBlock *s = VIRTIO_BLK(vdev);
- AioContext *ctx;
-
- /*
- * This should cancel pending requests, but can't do nicely until there
- * are per-device request lists.
- */
- ctx = blk_get_aio_context(s->blk);
- aio_context_acquire(ctx);
- blk_drain(s->blk);
-
- if (s->dataplane) {
- virtio_blk_data_plane_stop(s->dataplane);
- }
- aio_context_release(ctx);
-
- blk_set_enable_write_cache(s->blk, s->original_wce);
-}
-
-/* coalesce internal state, copy to pci i/o region 0
- */
-static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
-{
- VirtIOBlock *s = VIRTIO_BLK(vdev);
- BlockConf *conf = &s->conf.conf;
- struct virtio_blk_config blkcfg;
- uint64_t capacity;
- int blk_size = conf->logical_block_size;
-
- blk_get_geometry(s->blk, &capacity);
- memset(&blkcfg, 0, sizeof(blkcfg));
- virtio_stq_p(vdev, &blkcfg.capacity, capacity);
- virtio_stl_p(vdev, &blkcfg.seg_max, 128 - 2);
- virtio_stw_p(vdev, &blkcfg.geometry.cylinders, conf->cyls);
- virtio_stl_p(vdev, &blkcfg.blk_size, blk_size);
- virtio_stw_p(vdev, &blkcfg.min_io_size, conf->min_io_size / blk_size);
- virtio_stw_p(vdev, &blkcfg.opt_io_size, conf->opt_io_size / blk_size);
- blkcfg.geometry.heads = conf->heads;
- /*
- * We must ensure that the block device capacity is a multiple of
- * the logical block size. If that is not the case, let's use
- * sector_mask to adopt the geometry to have a correct picture.
- * For those devices where the capacity is ok for the given geometry
- * we don't touch the sector value of the geometry, since some devices
- * (like s390 dasd) need a specific value. Here the capacity is already
- * cyls*heads*secs*blk_size and the sector value is not block size
- * divided by 512 - instead it is the amount of blk_size blocks
- * per track (cylinder).
- */
- if (blk_getlength(s->blk) / conf->heads / conf->secs % blk_size) {
- blkcfg.geometry.sectors = conf->secs & ~s->sector_mask;
- } else {
- blkcfg.geometry.sectors = conf->secs;
- }
- blkcfg.size_max = 0;
- blkcfg.physical_block_exp = get_physical_block_exp(conf);
- blkcfg.alignment_offset = 0;
- blkcfg.wce = blk_enable_write_cache(s->blk);
- memcpy(config, &blkcfg, sizeof(struct virtio_blk_config));
-}
-
-static void virtio_blk_set_config(VirtIODevice *vdev, const uint8_t *config)
-{
- VirtIOBlock *s = VIRTIO_BLK(vdev);
- struct virtio_blk_config blkcfg;
-
- memcpy(&blkcfg, config, sizeof(blkcfg));
-
- aio_context_acquire(blk_get_aio_context(s->blk));
- blk_set_enable_write_cache(s->blk, blkcfg.wce != 0);
- aio_context_release(blk_get_aio_context(s->blk));
-}
-
-static uint64_t virtio_blk_get_features(VirtIODevice *vdev, uint64_t features,
- Error **errp)
-{
- VirtIOBlock *s = VIRTIO_BLK(vdev);
-
- virtio_add_feature(&features, VIRTIO_BLK_F_SEG_MAX);
- virtio_add_feature(&features, VIRTIO_BLK_F_GEOMETRY);
- virtio_add_feature(&features, VIRTIO_BLK_F_TOPOLOGY);
- virtio_add_feature(&features, VIRTIO_BLK_F_BLK_SIZE);
- if (virtio_has_feature(features, VIRTIO_F_VERSION_1)) {
- if (s->conf.scsi) {
- error_setg(errp, "Please set scsi=off for virtio-blk devices in order to use virtio 1.0");
- return 0;
- }
- } else {
- virtio_clear_feature(&features, VIRTIO_F_ANY_LAYOUT);
- virtio_add_feature(&features, VIRTIO_BLK_F_SCSI);
- }
-
- if (s->conf.config_wce) {
- virtio_add_feature(&features, VIRTIO_BLK_F_CONFIG_WCE);
- }
- if (blk_enable_write_cache(s->blk)) {
- virtio_add_feature(&features, VIRTIO_BLK_F_WCE);
- }
- if (blk_is_read_only(s->blk)) {
- virtio_add_feature(&features, VIRTIO_BLK_F_RO);
- }
-
- return features;
-}
-
-static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status)
-{
- VirtIOBlock *s = VIRTIO_BLK(vdev);
-
- if (s->dataplane && !(status & (VIRTIO_CONFIG_S_DRIVER |
- VIRTIO_CONFIG_S_DRIVER_OK))) {
- virtio_blk_data_plane_stop(s->dataplane);
- }
-
- if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) {
- return;
- }
-
- /* A guest that supports VIRTIO_BLK_F_CONFIG_WCE must be able to send
- * cache flushes. Thus, the "auto writethrough" behavior is never
- * necessary for guests that support the VIRTIO_BLK_F_CONFIG_WCE feature.
- * Leaving it enabled would break the following sequence:
- *
- * Guest started with "-drive cache=writethrough"
- * Guest sets status to 0
- * Guest sets DRIVER bit in status field
- * Guest reads host features (WCE=0, CONFIG_WCE=1)
- * Guest writes guest features (WCE=0, CONFIG_WCE=1)
- * Guest writes 1 to the WCE configuration field (writeback mode)
- * Guest sets DRIVER_OK bit in status field
- *
- * s->blk would erroneously be placed in writethrough mode.
- */
- if (!virtio_vdev_has_feature(vdev, VIRTIO_BLK_F_CONFIG_WCE)) {
- aio_context_acquire(blk_get_aio_context(s->blk));
- blk_set_enable_write_cache(s->blk,
- virtio_vdev_has_feature(vdev,
- VIRTIO_BLK_F_WCE));
- aio_context_release(blk_get_aio_context(s->blk));
- }
-}
-
-static void virtio_blk_save(QEMUFile *f, void *opaque)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(opaque);
- VirtIOBlock *s = VIRTIO_BLK(vdev);
-
- if (s->dataplane) {
- virtio_blk_data_plane_stop(s->dataplane);
- }
-
- virtio_save(vdev, f);
-}
-
-static void virtio_blk_save_device(VirtIODevice *vdev, QEMUFile *f)
-{
- VirtIOBlock *s = VIRTIO_BLK(vdev);
- VirtIOBlockReq *req = s->rq;
-
- while (req) {
- qemu_put_sbyte(f, 1);
- qemu_put_virtqueue_element(f, &req->elem);
- req = req->next;
- }
- qemu_put_sbyte(f, 0);
-}
-
-static int virtio_blk_load(QEMUFile *f, void *opaque, int version_id)
-{
- VirtIOBlock *s = opaque;
- VirtIODevice *vdev = VIRTIO_DEVICE(s);
-
- if (version_id != 2)
- return -EINVAL;
-
- return virtio_load(vdev, f, version_id);
-}
-
-static int virtio_blk_load_device(VirtIODevice *vdev, QEMUFile *f,
- int version_id)
-{
- VirtIOBlock *s = VIRTIO_BLK(vdev);
-
- while (qemu_get_sbyte(f)) {
- VirtIOBlockReq *req;
- req = qemu_get_virtqueue_element(f, sizeof(VirtIOBlockReq));
- virtio_blk_init_request(s, req);
- req->next = s->rq;
- s->rq = req;
- }
-
- return 0;
-}
-
-static void virtio_blk_resize(void *opaque)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(opaque);
-
- virtio_notify_config(vdev);
-}
-
-static const BlockDevOps virtio_block_ops = {
- .resize_cb = virtio_blk_resize,
-};
-
-static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
- VirtIOBlock *s = VIRTIO_BLK(dev);
- VirtIOBlkConf *conf = &s->conf;
- Error *err = NULL;
- static int virtio_blk_id;
-
- if (!conf->conf.blk) {
- error_setg(errp, "drive property not set");
- return;
- }
- if (!blk_is_inserted(conf->conf.blk)) {
- error_setg(errp, "Device needs media, but drive is empty");
- return;
- }
-
- blkconf_serial(&conf->conf, &conf->serial);
- s->original_wce = blk_enable_write_cache(conf->conf.blk);
- blkconf_geometry(&conf->conf, NULL, 65535, 255, 255, &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- blkconf_blocksizes(&conf->conf);
-
- virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK,
- sizeof(struct virtio_blk_config));
-
- s->blk = conf->conf.blk;
- s->rq = NULL;
- s->sector_mask = (s->conf.conf.logical_block_size / BDRV_SECTOR_SIZE) - 1;
-
- s->vq = virtio_add_queue(vdev, 128, virtio_blk_handle_output);
- virtio_blk_data_plane_create(vdev, conf, &s->dataplane, &err);
- if (err != NULL) {
- error_propagate(errp, err);
- virtio_cleanup(vdev);
- return;
- }
-
- s->change = qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s);
- register_savevm(dev, "virtio-blk", virtio_blk_id++, 2,
- virtio_blk_save, virtio_blk_load, s);
- blk_set_dev_ops(s->blk, &virtio_block_ops, s);
- blk_set_guest_block_size(s->blk, s->conf.conf.logical_block_size);
-
- blk_iostatus_enable(s->blk);
-}
-
-static void virtio_blk_device_unrealize(DeviceState *dev, Error **errp)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
- VirtIOBlock *s = VIRTIO_BLK(dev);
-
- virtio_blk_data_plane_destroy(s->dataplane);
- s->dataplane = NULL;
- qemu_del_vm_change_state_handler(s->change);
- unregister_savevm(dev, "virtio-blk", s);
- blockdev_mark_auto_del(s->blk);
- virtio_cleanup(vdev);
-}
-
-static void virtio_blk_instance_init(Object *obj)
-{
- VirtIOBlock *s = VIRTIO_BLK(obj);
-
- object_property_add_link(obj, "iothread", TYPE_IOTHREAD,
- (Object **)&s->conf.iothread,
- qdev_prop_allow_set_link_before_realize,
- OBJ_PROP_LINK_UNREF_ON_RELEASE, NULL);
- device_add_bootindex_property(obj, &s->conf.conf.bootindex,
- "bootindex", "/disk@0,0",
- DEVICE(obj), NULL);
-}
-
-static Property virtio_blk_properties[] = {
- DEFINE_BLOCK_PROPERTIES(VirtIOBlock, conf.conf),
- DEFINE_BLOCK_CHS_PROPERTIES(VirtIOBlock, conf.conf),
- DEFINE_PROP_STRING("serial", VirtIOBlock, conf.serial),
- DEFINE_PROP_BIT("config-wce", VirtIOBlock, conf.config_wce, 0, true),
-#ifdef __linux__
- DEFINE_PROP_BIT("scsi", VirtIOBlock, conf.scsi, 0, false),
-#endif
- DEFINE_PROP_BIT("request-merging", VirtIOBlock, conf.request_merging, 0,
- true),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_blk_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
-
- dc->props = virtio_blk_properties;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
- vdc->realize = virtio_blk_device_realize;
- vdc->unrealize = virtio_blk_device_unrealize;
- vdc->get_config = virtio_blk_update_config;
- vdc->set_config = virtio_blk_set_config;
- vdc->get_features = virtio_blk_get_features;
- vdc->set_status = virtio_blk_set_status;
- vdc->reset = virtio_blk_reset;
- vdc->save = virtio_blk_save_device;
- vdc->load = virtio_blk_load_device;
-}
-
-static const TypeInfo virtio_device_info = {
- .name = TYPE_VIRTIO_BLK,
- .parent = TYPE_VIRTIO_DEVICE,
- .instance_size = sizeof(VirtIOBlock),
- .instance_init = virtio_blk_instance_init,
- .class_init = virtio_blk_class_init,
-};
-
-static void virtio_register_types(void)
-{
- type_register_static(&virtio_device_info);
-}
-
-type_init(virtio_register_types)
diff --git a/qemu/hw/block/xen_blkif.h b/qemu/hw/block/xen_blkif.h
deleted file mode 100644
index c68487cb3..000000000
--- a/qemu/hw/block/xen_blkif.h
+++ /dev/null
@@ -1,119 +0,0 @@
-#ifndef __XEN_BLKIF_H__
-#define __XEN_BLKIF_H__
-
-#include <xen/io/ring.h>
-#include <xen/io/blkif.h>
-#include <xen/io/protocols.h>
-
-/* Not a real protocol. Used to generate ring structs which contain
- * the elements common to all protocols only. This way we get a
- * compiler-checkable way to use common struct elements, so we can
- * avoid using switch(protocol) in a number of places. */
-struct blkif_common_request {
- char dummy;
-};
-struct blkif_common_response {
- char dummy;
-};
-
-/* i386 protocol version */
-#pragma pack(push, 4)
-struct blkif_x86_32_request {
- uint8_t operation; /* BLKIF_OP_??? */
- uint8_t nr_segments; /* number of segments */
- blkif_vdev_t handle; /* only for read/write requests */
- uint64_t id; /* private guest value, echoed in resp */
- blkif_sector_t sector_number;/* start sector idx on disk (r/w only) */
- struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
-};
-struct blkif_x86_32_response {
- uint64_t id; /* copied from request */
- uint8_t operation; /* copied from request */
- int16_t status; /* BLKIF_RSP_??? */
-};
-typedef struct blkif_x86_32_request blkif_x86_32_request_t;
-typedef struct blkif_x86_32_response blkif_x86_32_response_t;
-#pragma pack(pop)
-
-/* x86_64 protocol version */
-struct blkif_x86_64_request {
- uint8_t operation; /* BLKIF_OP_??? */
- uint8_t nr_segments; /* number of segments */
- blkif_vdev_t handle; /* only for read/write requests */
- uint64_t __attribute__((__aligned__(8))) id;
- blkif_sector_t sector_number;/* start sector idx on disk (r/w only) */
- struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
-};
-struct blkif_x86_64_response {
- uint64_t __attribute__((__aligned__(8))) id;
- uint8_t operation; /* copied from request */
- int16_t status; /* BLKIF_RSP_??? */
-};
-typedef struct blkif_x86_64_request blkif_x86_64_request_t;
-typedef struct blkif_x86_64_response blkif_x86_64_response_t;
-
-DEFINE_RING_TYPES(blkif_common, struct blkif_common_request, struct blkif_common_response);
-DEFINE_RING_TYPES(blkif_x86_32, struct blkif_x86_32_request, struct blkif_x86_32_response);
-DEFINE_RING_TYPES(blkif_x86_64, struct blkif_x86_64_request, struct blkif_x86_64_response);
-
-union blkif_back_rings {
- blkif_back_ring_t native;
- blkif_common_back_ring_t common;
- blkif_x86_32_back_ring_t x86_32_part;
- blkif_x86_64_back_ring_t x86_64_part;
-};
-typedef union blkif_back_rings blkif_back_rings_t;
-
-enum blkif_protocol {
- BLKIF_PROTOCOL_NATIVE = 1,
- BLKIF_PROTOCOL_X86_32 = 2,
- BLKIF_PROTOCOL_X86_64 = 3,
-};
-
-static inline void blkif_get_x86_32_req(blkif_request_t *dst, blkif_x86_32_request_t *src)
-{
- int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST;
-
- dst->operation = src->operation;
- dst->nr_segments = src->nr_segments;
- dst->handle = src->handle;
- dst->id = src->id;
- dst->sector_number = src->sector_number;
- if (src->operation == BLKIF_OP_DISCARD) {
- struct blkif_request_discard *s = (void *)src;
- struct blkif_request_discard *d = (void *)dst;
- d->nr_sectors = s->nr_sectors;
- return;
- }
- /* prevent the compiler from optimizing the code and using src->nr_segments instead */
- barrier();
- if (n > dst->nr_segments)
- n = dst->nr_segments;
- for (i = 0; i < n; i++)
- dst->seg[i] = src->seg[i];
-}
-
-static inline void blkif_get_x86_64_req(blkif_request_t *dst, blkif_x86_64_request_t *src)
-{
- int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST;
-
- dst->operation = src->operation;
- dst->nr_segments = src->nr_segments;
- dst->handle = src->handle;
- dst->id = src->id;
- dst->sector_number = src->sector_number;
- if (src->operation == BLKIF_OP_DISCARD) {
- struct blkif_request_discard *s = (void *)src;
- struct blkif_request_discard *d = (void *)dst;
- d->nr_sectors = s->nr_sectors;
- return;
- }
- /* prevent the compiler from optimizing the code and using src->nr_segments instead */
- barrier();
- if (n > dst->nr_segments)
- n = dst->nr_segments;
- for (i = 0; i < n; i++)
- dst->seg[i] = src->seg[i];
-}
-
-#endif /* __XEN_BLKIF_H__ */
diff --git a/qemu/hw/block/xen_disk.c b/qemu/hw/block/xen_disk.c
deleted file mode 100644
index d4ce380fe..000000000
--- a/qemu/hw/block/xen_disk.c
+++ /dev/null
@@ -1,1121 +0,0 @@
-/*
- * xen paravirt block device backend
- *
- * (c) Gerd Hoffmann <kraxel@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; under version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <sys/uio.h>
-
-#include "hw/hw.h"
-#include "hw/xen/xen_backend.h"
-#include "xen_blkif.h"
-#include "sysemu/blockdev.h"
-#include "sysemu/block-backend.h"
-#include "qapi/error.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qstring.h"
-
-/* ------------------------------------------------------------- */
-
-static int batch_maps = 0;
-
-static int max_requests = 32;
-
-/* ------------------------------------------------------------- */
-
-#define BLOCK_SIZE 512
-#define IOCB_COUNT (BLKIF_MAX_SEGMENTS_PER_REQUEST + 2)
-
-struct PersistentGrant {
- void *page;
- struct XenBlkDev *blkdev;
-};
-
-typedef struct PersistentGrant PersistentGrant;
-
-struct PersistentRegion {
- void *addr;
- int num;
-};
-
-typedef struct PersistentRegion PersistentRegion;
-
-struct ioreq {
- blkif_request_t req;
- int16_t status;
-
- /* parsed request */
- off_t start;
- QEMUIOVector v;
- int presync;
- uint8_t mapped;
-
- /* grant mapping */
- uint32_t domids[BLKIF_MAX_SEGMENTS_PER_REQUEST];
- uint32_t refs[BLKIF_MAX_SEGMENTS_PER_REQUEST];
- int prot;
- void *page[BLKIF_MAX_SEGMENTS_PER_REQUEST];
- void *pages;
- int num_unmap;
-
- /* aio status */
- int aio_inflight;
- int aio_errors;
-
- struct XenBlkDev *blkdev;
- QLIST_ENTRY(ioreq) list;
- BlockAcctCookie acct;
-};
-
-struct XenBlkDev {
- struct XenDevice xendev; /* must be first */
- char *params;
- char *mode;
- char *type;
- char *dev;
- char *devtype;
- bool directiosafe;
- const char *fileproto;
- const char *filename;
- int ring_ref;
- void *sring;
- int64_t file_blk;
- int64_t file_size;
- int protocol;
- blkif_back_rings_t rings;
- int more_work;
- int cnt_map;
-
- /* request lists */
- QLIST_HEAD(inflight_head, ioreq) inflight;
- QLIST_HEAD(finished_head, ioreq) finished;
- QLIST_HEAD(freelist_head, ioreq) freelist;
- int requests_total;
- int requests_inflight;
- int requests_finished;
-
- /* Persistent grants extension */
- gboolean feature_discard;
- gboolean feature_persistent;
- GTree *persistent_gnts;
- GSList *persistent_regions;
- unsigned int persistent_gnt_count;
- unsigned int max_grants;
-
- /* qemu block driver */
- DriveInfo *dinfo;
- BlockBackend *blk;
- QEMUBH *bh;
-};
-
-/* ------------------------------------------------------------- */
-
-static void ioreq_reset(struct ioreq *ioreq)
-{
- memset(&ioreq->req, 0, sizeof(ioreq->req));
- ioreq->status = 0;
- ioreq->start = 0;
- ioreq->presync = 0;
- ioreq->mapped = 0;
-
- memset(ioreq->domids, 0, sizeof(ioreq->domids));
- memset(ioreq->refs, 0, sizeof(ioreq->refs));
- ioreq->prot = 0;
- memset(ioreq->page, 0, sizeof(ioreq->page));
- ioreq->pages = NULL;
-
- ioreq->aio_inflight = 0;
- ioreq->aio_errors = 0;
-
- ioreq->blkdev = NULL;
- memset(&ioreq->list, 0, sizeof(ioreq->list));
- memset(&ioreq->acct, 0, sizeof(ioreq->acct));
-
- qemu_iovec_reset(&ioreq->v);
-}
-
-static gint int_cmp(gconstpointer a, gconstpointer b, gpointer user_data)
-{
- uint ua = GPOINTER_TO_UINT(a);
- uint ub = GPOINTER_TO_UINT(b);
- return (ua > ub) - (ua < ub);
-}
-
-static void destroy_grant(gpointer pgnt)
-{
- PersistentGrant *grant = pgnt;
- xengnttab_handle *gnt = grant->blkdev->xendev.gnttabdev;
-
- if (xengnttab_unmap(gnt, grant->page, 1) != 0) {
- xen_be_printf(&grant->blkdev->xendev, 0,
- "xengnttab_unmap failed: %s\n",
- strerror(errno));
- }
- grant->blkdev->persistent_gnt_count--;
- xen_be_printf(&grant->blkdev->xendev, 3,
- "unmapped grant %p\n", grant->page);
- g_free(grant);
-}
-
-static void remove_persistent_region(gpointer data, gpointer dev)
-{
- PersistentRegion *region = data;
- struct XenBlkDev *blkdev = dev;
- xengnttab_handle *gnt = blkdev->xendev.gnttabdev;
-
- if (xengnttab_unmap(gnt, region->addr, region->num) != 0) {
- xen_be_printf(&blkdev->xendev, 0,
- "xengnttab_unmap region %p failed: %s\n",
- region->addr, strerror(errno));
- }
- xen_be_printf(&blkdev->xendev, 3,
- "unmapped grant region %p with %d pages\n",
- region->addr, region->num);
- g_free(region);
-}
-
-static struct ioreq *ioreq_start(struct XenBlkDev *blkdev)
-{
- struct ioreq *ioreq = NULL;
-
- if (QLIST_EMPTY(&blkdev->freelist)) {
- if (blkdev->requests_total >= max_requests) {
- goto out;
- }
- /* allocate new struct */
- ioreq = g_malloc0(sizeof(*ioreq));
- ioreq->blkdev = blkdev;
- blkdev->requests_total++;
- qemu_iovec_init(&ioreq->v, BLKIF_MAX_SEGMENTS_PER_REQUEST);
- } else {
- /* get one from freelist */
- ioreq = QLIST_FIRST(&blkdev->freelist);
- QLIST_REMOVE(ioreq, list);
- }
- QLIST_INSERT_HEAD(&blkdev->inflight, ioreq, list);
- blkdev->requests_inflight++;
-
-out:
- return ioreq;
-}
-
-static void ioreq_finish(struct ioreq *ioreq)
-{
- struct XenBlkDev *blkdev = ioreq->blkdev;
-
- QLIST_REMOVE(ioreq, list);
- QLIST_INSERT_HEAD(&blkdev->finished, ioreq, list);
- blkdev->requests_inflight--;
- blkdev->requests_finished++;
-}
-
-static void ioreq_release(struct ioreq *ioreq, bool finish)
-{
- struct XenBlkDev *blkdev = ioreq->blkdev;
-
- QLIST_REMOVE(ioreq, list);
- ioreq_reset(ioreq);
- ioreq->blkdev = blkdev;
- QLIST_INSERT_HEAD(&blkdev->freelist, ioreq, list);
- if (finish) {
- blkdev->requests_finished--;
- } else {
- blkdev->requests_inflight--;
- }
-}
-
-/*
- * translate request into iovec + start offset
- * do sanity checks along the way
- */
-static int ioreq_parse(struct ioreq *ioreq)
-{
- struct XenBlkDev *blkdev = ioreq->blkdev;
- uintptr_t mem;
- size_t len;
- int i;
-
- xen_be_printf(&blkdev->xendev, 3,
- "op %d, nr %d, handle %d, id %" PRId64 ", sector %" PRId64 "\n",
- ioreq->req.operation, ioreq->req.nr_segments,
- ioreq->req.handle, ioreq->req.id, ioreq->req.sector_number);
- switch (ioreq->req.operation) {
- case BLKIF_OP_READ:
- ioreq->prot = PROT_WRITE; /* to memory */
- break;
- case BLKIF_OP_FLUSH_DISKCACHE:
- ioreq->presync = 1;
- if (!ioreq->req.nr_segments) {
- return 0;
- }
- /* fall through */
- case BLKIF_OP_WRITE:
- ioreq->prot = PROT_READ; /* from memory */
- break;
- case BLKIF_OP_DISCARD:
- return 0;
- default:
- xen_be_printf(&blkdev->xendev, 0, "error: unknown operation (%d)\n",
- ioreq->req.operation);
- goto err;
- };
-
- if (ioreq->req.operation != BLKIF_OP_READ && blkdev->mode[0] != 'w') {
- xen_be_printf(&blkdev->xendev, 0, "error: write req for ro device\n");
- goto err;
- }
-
- ioreq->start = ioreq->req.sector_number * blkdev->file_blk;
- for (i = 0; i < ioreq->req.nr_segments; i++) {
- if (i == BLKIF_MAX_SEGMENTS_PER_REQUEST) {
- xen_be_printf(&blkdev->xendev, 0, "error: nr_segments too big\n");
- goto err;
- }
- if (ioreq->req.seg[i].first_sect > ioreq->req.seg[i].last_sect) {
- xen_be_printf(&blkdev->xendev, 0, "error: first > last sector\n");
- goto err;
- }
- if (ioreq->req.seg[i].last_sect * BLOCK_SIZE >= XC_PAGE_SIZE) {
- xen_be_printf(&blkdev->xendev, 0, "error: page crossing\n");
- goto err;
- }
-
- ioreq->domids[i] = blkdev->xendev.dom;
- ioreq->refs[i] = ioreq->req.seg[i].gref;
-
- mem = ioreq->req.seg[i].first_sect * blkdev->file_blk;
- len = (ioreq->req.seg[i].last_sect - ioreq->req.seg[i].first_sect + 1) * blkdev->file_blk;
- qemu_iovec_add(&ioreq->v, (void*)mem, len);
- }
- if (ioreq->start + ioreq->v.size > blkdev->file_size) {
- xen_be_printf(&blkdev->xendev, 0, "error: access beyond end of file\n");
- goto err;
- }
- return 0;
-
-err:
- ioreq->status = BLKIF_RSP_ERROR;
- return -1;
-}
-
-static void ioreq_unmap(struct ioreq *ioreq)
-{
- xengnttab_handle *gnt = ioreq->blkdev->xendev.gnttabdev;
- int i;
-
- if (ioreq->num_unmap == 0 || ioreq->mapped == 0) {
- return;
- }
- if (batch_maps) {
- if (!ioreq->pages) {
- return;
- }
- if (xengnttab_unmap(gnt, ioreq->pages, ioreq->num_unmap) != 0) {
- xen_be_printf(&ioreq->blkdev->xendev, 0,
- "xengnttab_unmap failed: %s\n",
- strerror(errno));
- }
- ioreq->blkdev->cnt_map -= ioreq->num_unmap;
- ioreq->pages = NULL;
- } else {
- for (i = 0; i < ioreq->num_unmap; i++) {
- if (!ioreq->page[i]) {
- continue;
- }
- if (xengnttab_unmap(gnt, ioreq->page[i], 1) != 0) {
- xen_be_printf(&ioreq->blkdev->xendev, 0,
- "xengnttab_unmap failed: %s\n",
- strerror(errno));
- }
- ioreq->blkdev->cnt_map--;
- ioreq->page[i] = NULL;
- }
- }
- ioreq->mapped = 0;
-}
-
-static int ioreq_map(struct ioreq *ioreq)
-{
- xengnttab_handle *gnt = ioreq->blkdev->xendev.gnttabdev;
- uint32_t domids[BLKIF_MAX_SEGMENTS_PER_REQUEST];
- uint32_t refs[BLKIF_MAX_SEGMENTS_PER_REQUEST];
- void *page[BLKIF_MAX_SEGMENTS_PER_REQUEST];
- int i, j, new_maps = 0;
- PersistentGrant *grant;
- PersistentRegion *region;
- /* domids and refs variables will contain the information necessary
- * to map the grants that are needed to fulfill this request.
- *
- * After mapping the needed grants, the page array will contain the
- * memory address of each granted page in the order specified in ioreq
- * (disregarding if it's a persistent grant or not).
- */
-
- if (ioreq->v.niov == 0 || ioreq->mapped == 1) {
- return 0;
- }
- if (ioreq->blkdev->feature_persistent) {
- for (i = 0; i < ioreq->v.niov; i++) {
- grant = g_tree_lookup(ioreq->blkdev->persistent_gnts,
- GUINT_TO_POINTER(ioreq->refs[i]));
-
- if (grant != NULL) {
- page[i] = grant->page;
- xen_be_printf(&ioreq->blkdev->xendev, 3,
- "using persistent-grant %" PRIu32 "\n",
- ioreq->refs[i]);
- } else {
- /* Add the grant to the list of grants that
- * should be mapped
- */
- domids[new_maps] = ioreq->domids[i];
- refs[new_maps] = ioreq->refs[i];
- page[i] = NULL;
- new_maps++;
- }
- }
- /* Set the protection to RW, since grants may be reused later
- * with a different protection than the one needed for this request
- */
- ioreq->prot = PROT_WRITE | PROT_READ;
- } else {
- /* All grants in the request should be mapped */
- memcpy(refs, ioreq->refs, sizeof(refs));
- memcpy(domids, ioreq->domids, sizeof(domids));
- memset(page, 0, sizeof(page));
- new_maps = ioreq->v.niov;
- }
-
- if (batch_maps && new_maps) {
- ioreq->pages = xengnttab_map_grant_refs
- (gnt, new_maps, domids, refs, ioreq->prot);
- if (ioreq->pages == NULL) {
- xen_be_printf(&ioreq->blkdev->xendev, 0,
- "can't map %d grant refs (%s, %d maps)\n",
- new_maps, strerror(errno), ioreq->blkdev->cnt_map);
- return -1;
- }
- for (i = 0, j = 0; i < ioreq->v.niov; i++) {
- if (page[i] == NULL) {
- page[i] = ioreq->pages + (j++) * XC_PAGE_SIZE;
- }
- }
- ioreq->blkdev->cnt_map += new_maps;
- } else if (new_maps) {
- for (i = 0; i < new_maps; i++) {
- ioreq->page[i] = xengnttab_map_grant_ref
- (gnt, domids[i], refs[i], ioreq->prot);
- if (ioreq->page[i] == NULL) {
- xen_be_printf(&ioreq->blkdev->xendev, 0,
- "can't map grant ref %d (%s, %d maps)\n",
- refs[i], strerror(errno), ioreq->blkdev->cnt_map);
- ioreq->mapped = 1;
- ioreq_unmap(ioreq);
- return -1;
- }
- ioreq->blkdev->cnt_map++;
- }
- for (i = 0, j = 0; i < ioreq->v.niov; i++) {
- if (page[i] == NULL) {
- page[i] = ioreq->page[j++];
- }
- }
- }
- if (ioreq->blkdev->feature_persistent && new_maps != 0 &&
- (!batch_maps || (ioreq->blkdev->persistent_gnt_count + new_maps <=
- ioreq->blkdev->max_grants))) {
- /*
- * If we are using persistent grants and batch mappings only
- * add the new maps to the list of persistent grants if the whole
- * area can be persistently mapped.
- */
- if (batch_maps) {
- region = g_malloc0(sizeof(*region));
- region->addr = ioreq->pages;
- region->num = new_maps;
- ioreq->blkdev->persistent_regions = g_slist_append(
- ioreq->blkdev->persistent_regions,
- region);
- }
- while ((ioreq->blkdev->persistent_gnt_count < ioreq->blkdev->max_grants)
- && new_maps) {
- /* Go through the list of newly mapped grants and add as many
- * as possible to the list of persistently mapped grants.
- *
- * Since we start at the end of ioreq->page(s), we only need
- * to decrease new_maps to prevent this granted pages from
- * being unmapped in ioreq_unmap.
- */
- grant = g_malloc0(sizeof(*grant));
- new_maps--;
- if (batch_maps) {
- grant->page = ioreq->pages + (new_maps) * XC_PAGE_SIZE;
- } else {
- grant->page = ioreq->page[new_maps];
- }
- grant->blkdev = ioreq->blkdev;
- xen_be_printf(&ioreq->blkdev->xendev, 3,
- "adding grant %" PRIu32 " page: %p\n",
- refs[new_maps], grant->page);
- g_tree_insert(ioreq->blkdev->persistent_gnts,
- GUINT_TO_POINTER(refs[new_maps]),
- grant);
- ioreq->blkdev->persistent_gnt_count++;
- }
- assert(!batch_maps || new_maps == 0);
- }
- for (i = 0; i < ioreq->v.niov; i++) {
- ioreq->v.iov[i].iov_base += (uintptr_t)page[i];
- }
- ioreq->mapped = 1;
- ioreq->num_unmap = new_maps;
- return 0;
-}
-
-static int ioreq_runio_qemu_aio(struct ioreq *ioreq);
-
-static void qemu_aio_complete(void *opaque, int ret)
-{
- struct ioreq *ioreq = opaque;
-
- if (ret != 0) {
- xen_be_printf(&ioreq->blkdev->xendev, 0, "%s I/O error\n",
- ioreq->req.operation == BLKIF_OP_READ ? "read" : "write");
- ioreq->aio_errors++;
- }
-
- ioreq->aio_inflight--;
- if (ioreq->presync) {
- ioreq->presync = 0;
- ioreq_runio_qemu_aio(ioreq);
- return;
- }
- if (ioreq->aio_inflight > 0) {
- return;
- }
-
- ioreq->status = ioreq->aio_errors ? BLKIF_RSP_ERROR : BLKIF_RSP_OKAY;
- ioreq_unmap(ioreq);
- ioreq_finish(ioreq);
- switch (ioreq->req.operation) {
- case BLKIF_OP_WRITE:
- case BLKIF_OP_FLUSH_DISKCACHE:
- if (!ioreq->req.nr_segments) {
- break;
- }
- case BLKIF_OP_READ:
- if (ioreq->status == BLKIF_RSP_OKAY) {
- block_acct_done(blk_get_stats(ioreq->blkdev->blk), &ioreq->acct);
- } else {
- block_acct_failed(blk_get_stats(ioreq->blkdev->blk), &ioreq->acct);
- }
- break;
- case BLKIF_OP_DISCARD:
- default:
- break;
- }
- qemu_bh_schedule(ioreq->blkdev->bh);
-}
-
-static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
-{
- struct XenBlkDev *blkdev = ioreq->blkdev;
-
- if (ioreq->req.nr_segments && ioreq_map(ioreq) == -1) {
- goto err_no_map;
- }
-
- ioreq->aio_inflight++;
- if (ioreq->presync) {
- blk_aio_flush(ioreq->blkdev->blk, qemu_aio_complete, ioreq);
- return 0;
- }
-
- switch (ioreq->req.operation) {
- case BLKIF_OP_READ:
- block_acct_start(blk_get_stats(blkdev->blk), &ioreq->acct,
- ioreq->v.size, BLOCK_ACCT_READ);
- ioreq->aio_inflight++;
- blk_aio_readv(blkdev->blk, ioreq->start / BLOCK_SIZE,
- &ioreq->v, ioreq->v.size / BLOCK_SIZE,
- qemu_aio_complete, ioreq);
- break;
- case BLKIF_OP_WRITE:
- case BLKIF_OP_FLUSH_DISKCACHE:
- if (!ioreq->req.nr_segments) {
- break;
- }
-
- block_acct_start(blk_get_stats(blkdev->blk), &ioreq->acct,
- ioreq->v.size,
- ioreq->req.operation == BLKIF_OP_WRITE ?
- BLOCK_ACCT_WRITE : BLOCK_ACCT_FLUSH);
- ioreq->aio_inflight++;
- blk_aio_writev(blkdev->blk, ioreq->start / BLOCK_SIZE,
- &ioreq->v, ioreq->v.size / BLOCK_SIZE,
- qemu_aio_complete, ioreq);
- break;
- case BLKIF_OP_DISCARD:
- {
- struct blkif_request_discard *discard_req = (void *)&ioreq->req;
- ioreq->aio_inflight++;
- blk_aio_discard(blkdev->blk,
- discard_req->sector_number, discard_req->nr_sectors,
- qemu_aio_complete, ioreq);
- break;
- }
- default:
- /* unknown operation (shouldn't happen -- parse catches this) */
- goto err;
- }
-
- qemu_aio_complete(ioreq, 0);
-
- return 0;
-
-err:
- ioreq_unmap(ioreq);
-err_no_map:
- ioreq_finish(ioreq);
- ioreq->status = BLKIF_RSP_ERROR;
- return -1;
-}
-
-static int blk_send_response_one(struct ioreq *ioreq)
-{
- struct XenBlkDev *blkdev = ioreq->blkdev;
- int send_notify = 0;
- int have_requests = 0;
- blkif_response_t resp;
- void *dst;
-
- resp.id = ioreq->req.id;
- resp.operation = ioreq->req.operation;
- resp.status = ioreq->status;
-
- /* Place on the response ring for the relevant domain. */
- switch (blkdev->protocol) {
- case BLKIF_PROTOCOL_NATIVE:
- dst = RING_GET_RESPONSE(&blkdev->rings.native, blkdev->rings.native.rsp_prod_pvt);
- break;
- case BLKIF_PROTOCOL_X86_32:
- dst = RING_GET_RESPONSE(&blkdev->rings.x86_32_part,
- blkdev->rings.x86_32_part.rsp_prod_pvt);
- break;
- case BLKIF_PROTOCOL_X86_64:
- dst = RING_GET_RESPONSE(&blkdev->rings.x86_64_part,
- blkdev->rings.x86_64_part.rsp_prod_pvt);
- break;
- default:
- dst = NULL;
- return 0;
- }
- memcpy(dst, &resp, sizeof(resp));
- blkdev->rings.common.rsp_prod_pvt++;
-
- RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&blkdev->rings.common, send_notify);
- if (blkdev->rings.common.rsp_prod_pvt == blkdev->rings.common.req_cons) {
- /*
- * Tail check for pending requests. Allows frontend to avoid
- * notifications if requests are already in flight (lower
- * overheads and promotes batching).
- */
- RING_FINAL_CHECK_FOR_REQUESTS(&blkdev->rings.common, have_requests);
- } else if (RING_HAS_UNCONSUMED_REQUESTS(&blkdev->rings.common)) {
- have_requests = 1;
- }
-
- if (have_requests) {
- blkdev->more_work++;
- }
- return send_notify;
-}
-
-/* walk finished list, send outstanding responses, free requests */
-static void blk_send_response_all(struct XenBlkDev *blkdev)
-{
- struct ioreq *ioreq;
- int send_notify = 0;
-
- while (!QLIST_EMPTY(&blkdev->finished)) {
- ioreq = QLIST_FIRST(&blkdev->finished);
- send_notify += blk_send_response_one(ioreq);
- ioreq_release(ioreq, true);
- }
- if (send_notify) {
- xen_be_send_notify(&blkdev->xendev);
- }
-}
-
-static int blk_get_request(struct XenBlkDev *blkdev, struct ioreq *ioreq, RING_IDX rc)
-{
- switch (blkdev->protocol) {
- case BLKIF_PROTOCOL_NATIVE:
- memcpy(&ioreq->req, RING_GET_REQUEST(&blkdev->rings.native, rc),
- sizeof(ioreq->req));
- break;
- case BLKIF_PROTOCOL_X86_32:
- blkif_get_x86_32_req(&ioreq->req,
- RING_GET_REQUEST(&blkdev->rings.x86_32_part, rc));
- break;
- case BLKIF_PROTOCOL_X86_64:
- blkif_get_x86_64_req(&ioreq->req,
- RING_GET_REQUEST(&blkdev->rings.x86_64_part, rc));
- break;
- }
- return 0;
-}
-
-static void blk_handle_requests(struct XenBlkDev *blkdev)
-{
- RING_IDX rc, rp;
- struct ioreq *ioreq;
-
- blkdev->more_work = 0;
-
- rc = blkdev->rings.common.req_cons;
- rp = blkdev->rings.common.sring->req_prod;
- xen_rmb(); /* Ensure we see queued requests up to 'rp'. */
-
- blk_send_response_all(blkdev);
- while (rc != rp) {
- /* pull request from ring */
- if (RING_REQUEST_CONS_OVERFLOW(&blkdev->rings.common, rc)) {
- break;
- }
- ioreq = ioreq_start(blkdev);
- if (ioreq == NULL) {
- blkdev->more_work++;
- break;
- }
- blk_get_request(blkdev, ioreq, rc);
- blkdev->rings.common.req_cons = ++rc;
-
- /* parse them */
- if (ioreq_parse(ioreq) != 0) {
-
- switch (ioreq->req.operation) {
- case BLKIF_OP_READ:
- block_acct_invalid(blk_get_stats(blkdev->blk),
- BLOCK_ACCT_READ);
- break;
- case BLKIF_OP_WRITE:
- block_acct_invalid(blk_get_stats(blkdev->blk),
- BLOCK_ACCT_WRITE);
- break;
- case BLKIF_OP_FLUSH_DISKCACHE:
- block_acct_invalid(blk_get_stats(blkdev->blk),
- BLOCK_ACCT_FLUSH);
- default:
- break;
- };
-
- if (blk_send_response_one(ioreq)) {
- xen_be_send_notify(&blkdev->xendev);
- }
- ioreq_release(ioreq, false);
- continue;
- }
-
- ioreq_runio_qemu_aio(ioreq);
- }
-
- if (blkdev->more_work && blkdev->requests_inflight < max_requests) {
- qemu_bh_schedule(blkdev->bh);
- }
-}
-
-/* ------------------------------------------------------------- */
-
-static void blk_bh(void *opaque)
-{
- struct XenBlkDev *blkdev = opaque;
- blk_handle_requests(blkdev);
-}
-
-/*
- * We need to account for the grant allocations requiring contiguous
- * chunks; the worst case number would be
- * max_req * max_seg + (max_req - 1) * (max_seg - 1) + 1,
- * but in order to keep things simple just use
- * 2 * max_req * max_seg.
- */
-#define MAX_GRANTS(max_req, max_seg) (2 * (max_req) * (max_seg))
-
-static void blk_alloc(struct XenDevice *xendev)
-{
- struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
-
- QLIST_INIT(&blkdev->inflight);
- QLIST_INIT(&blkdev->finished);
- QLIST_INIT(&blkdev->freelist);
- blkdev->bh = qemu_bh_new(blk_bh, blkdev);
- if (xen_mode != XEN_EMULATE) {
- batch_maps = 1;
- }
- if (xengnttab_set_max_grants(xendev->gnttabdev,
- MAX_GRANTS(max_requests, BLKIF_MAX_SEGMENTS_PER_REQUEST)) < 0) {
- xen_be_printf(xendev, 0, "xengnttab_set_max_grants failed: %s\n",
- strerror(errno));
- }
-}
-
-static void blk_parse_discard(struct XenBlkDev *blkdev)
-{
- int enable;
-
- blkdev->feature_discard = true;
-
- if (xenstore_read_be_int(&blkdev->xendev, "discard-enable", &enable) == 0) {
- blkdev->feature_discard = !!enable;
- }
-
- if (blkdev->feature_discard) {
- xenstore_write_be_int(&blkdev->xendev, "feature-discard", 1);
- }
-}
-
-static int blk_init(struct XenDevice *xendev)
-{
- struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
- int info = 0;
- char *directiosafe = NULL;
-
- /* read xenstore entries */
- if (blkdev->params == NULL) {
- char *h = NULL;
- blkdev->params = xenstore_read_be_str(&blkdev->xendev, "params");
- if (blkdev->params != NULL) {
- h = strchr(blkdev->params, ':');
- }
- if (h != NULL) {
- blkdev->fileproto = blkdev->params;
- blkdev->filename = h+1;
- *h = 0;
- } else {
- blkdev->fileproto = "<unset>";
- blkdev->filename = blkdev->params;
- }
- }
- if (!strcmp("aio", blkdev->fileproto)) {
- blkdev->fileproto = "raw";
- }
- if (!strcmp("vhd", blkdev->fileproto)) {
- blkdev->fileproto = "vpc";
- }
- if (blkdev->mode == NULL) {
- blkdev->mode = xenstore_read_be_str(&blkdev->xendev, "mode");
- }
- if (blkdev->type == NULL) {
- blkdev->type = xenstore_read_be_str(&blkdev->xendev, "type");
- }
- if (blkdev->dev == NULL) {
- blkdev->dev = xenstore_read_be_str(&blkdev->xendev, "dev");
- }
- if (blkdev->devtype == NULL) {
- blkdev->devtype = xenstore_read_be_str(&blkdev->xendev, "device-type");
- }
- directiosafe = xenstore_read_be_str(&blkdev->xendev, "direct-io-safe");
- blkdev->directiosafe = (directiosafe && atoi(directiosafe));
-
- /* do we have all we need? */
- if (blkdev->params == NULL ||
- blkdev->mode == NULL ||
- blkdev->type == NULL ||
- blkdev->dev == NULL) {
- goto out_error;
- }
-
- /* read-only ? */
- if (strcmp(blkdev->mode, "w")) {
- info |= VDISK_READONLY;
- }
-
- /* cdrom ? */
- if (blkdev->devtype && !strcmp(blkdev->devtype, "cdrom")) {
- info |= VDISK_CDROM;
- }
-
- blkdev->file_blk = BLOCK_SIZE;
-
- /* fill info
- * blk_connect supplies sector-size and sectors
- */
- xenstore_write_be_int(&blkdev->xendev, "feature-flush-cache", 1);
- xenstore_write_be_int(&blkdev->xendev, "feature-persistent", 1);
- xenstore_write_be_int(&blkdev->xendev, "info", info);
-
- blk_parse_discard(blkdev);
-
- g_free(directiosafe);
- return 0;
-
-out_error:
- g_free(blkdev->params);
- blkdev->params = NULL;
- g_free(blkdev->mode);
- blkdev->mode = NULL;
- g_free(blkdev->type);
- blkdev->type = NULL;
- g_free(blkdev->dev);
- blkdev->dev = NULL;
- g_free(blkdev->devtype);
- blkdev->devtype = NULL;
- g_free(directiosafe);
- blkdev->directiosafe = false;
- return -1;
-}
-
-static int blk_connect(struct XenDevice *xendev)
-{
- struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
- int pers, index, qflags;
- bool readonly = true;
- bool writethrough = true;
-
- /* read-only ? */
- if (blkdev->directiosafe) {
- qflags = BDRV_O_NOCACHE | BDRV_O_NATIVE_AIO;
- } else {
- qflags = 0;
- writethrough = false;
- }
- if (strcmp(blkdev->mode, "w") == 0) {
- qflags |= BDRV_O_RDWR;
- readonly = false;
- }
- if (blkdev->feature_discard) {
- qflags |= BDRV_O_UNMAP;
- }
-
- /* init qemu block driver */
- index = (blkdev->xendev.dev - 202 * 256) / 16;
- blkdev->dinfo = drive_get(IF_XEN, 0, index);
- if (!blkdev->dinfo) {
- Error *local_err = NULL;
- QDict *options = NULL;
-
- if (strcmp(blkdev->fileproto, "<unset>")) {
- options = qdict_new();
- qdict_put(options, "driver", qstring_from_str(blkdev->fileproto));
- }
-
- /* setup via xenbus -> create new block driver instance */
- xen_be_printf(&blkdev->xendev, 2, "create new bdrv (xenbus setup)\n");
- blkdev->blk = blk_new_open(blkdev->filename, NULL, options,
- qflags, &local_err);
- if (!blkdev->blk) {
- xen_be_printf(&blkdev->xendev, 0, "error: %s\n",
- error_get_pretty(local_err));
- error_free(local_err);
- return -1;
- }
- blk_set_enable_write_cache(blkdev->blk, !writethrough);
- } else {
- /* setup via qemu cmdline -> already setup for us */
- xen_be_printf(&blkdev->xendev, 2, "get configured bdrv (cmdline setup)\n");
- blkdev->blk = blk_by_legacy_dinfo(blkdev->dinfo);
- if (blk_is_read_only(blkdev->blk) && !readonly) {
- xen_be_printf(&blkdev->xendev, 0, "Unexpected read-only drive");
- blkdev->blk = NULL;
- return -1;
- }
- /* blkdev->blk is not create by us, we get a reference
- * so we can blk_unref() unconditionally */
- blk_ref(blkdev->blk);
- }
- blk_attach_dev_nofail(blkdev->blk, blkdev);
- blkdev->file_size = blk_getlength(blkdev->blk);
- if (blkdev->file_size < 0) {
- BlockDriverState *bs = blk_bs(blkdev->blk);
- const char *drv_name = bs ? bdrv_get_format_name(bs) : NULL;
- xen_be_printf(&blkdev->xendev, 1, "blk_getlength: %d (%s) | drv %s\n",
- (int)blkdev->file_size, strerror(-blkdev->file_size),
- drv_name ?: "-");
- blkdev->file_size = 0;
- }
-
- xen_be_printf(xendev, 1, "type \"%s\", fileproto \"%s\", filename \"%s\","
- " size %" PRId64 " (%" PRId64 " MB)\n",
- blkdev->type, blkdev->fileproto, blkdev->filename,
- blkdev->file_size, blkdev->file_size >> 20);
-
- /* Fill in number of sector size and number of sectors */
- xenstore_write_be_int(&blkdev->xendev, "sector-size", blkdev->file_blk);
- xenstore_write_be_int64(&blkdev->xendev, "sectors",
- blkdev->file_size / blkdev->file_blk);
-
- if (xenstore_read_fe_int(&blkdev->xendev, "ring-ref", &blkdev->ring_ref) == -1) {
- return -1;
- }
- if (xenstore_read_fe_int(&blkdev->xendev, "event-channel",
- &blkdev->xendev.remote_port) == -1) {
- return -1;
- }
- if (xenstore_read_fe_int(&blkdev->xendev, "feature-persistent", &pers)) {
- blkdev->feature_persistent = FALSE;
- } else {
- blkdev->feature_persistent = !!pers;
- }
-
- blkdev->protocol = BLKIF_PROTOCOL_NATIVE;
- if (blkdev->xendev.protocol) {
- if (strcmp(blkdev->xendev.protocol, XEN_IO_PROTO_ABI_X86_32) == 0) {
- blkdev->protocol = BLKIF_PROTOCOL_X86_32;
- }
- if (strcmp(blkdev->xendev.protocol, XEN_IO_PROTO_ABI_X86_64) == 0) {
- blkdev->protocol = BLKIF_PROTOCOL_X86_64;
- }
- }
-
- blkdev->sring = xengnttab_map_grant_ref(blkdev->xendev.gnttabdev,
- blkdev->xendev.dom,
- blkdev->ring_ref,
- PROT_READ | PROT_WRITE);
- if (!blkdev->sring) {
- return -1;
- }
- blkdev->cnt_map++;
-
- switch (blkdev->protocol) {
- case BLKIF_PROTOCOL_NATIVE:
- {
- blkif_sring_t *sring_native = blkdev->sring;
- BACK_RING_INIT(&blkdev->rings.native, sring_native, XC_PAGE_SIZE);
- break;
- }
- case BLKIF_PROTOCOL_X86_32:
- {
- blkif_x86_32_sring_t *sring_x86_32 = blkdev->sring;
-
- BACK_RING_INIT(&blkdev->rings.x86_32_part, sring_x86_32, XC_PAGE_SIZE);
- break;
- }
- case BLKIF_PROTOCOL_X86_64:
- {
- blkif_x86_64_sring_t *sring_x86_64 = blkdev->sring;
-
- BACK_RING_INIT(&blkdev->rings.x86_64_part, sring_x86_64, XC_PAGE_SIZE);
- break;
- }
- }
-
- if (blkdev->feature_persistent) {
- /* Init persistent grants */
- blkdev->max_grants = max_requests * BLKIF_MAX_SEGMENTS_PER_REQUEST;
- blkdev->persistent_gnts = g_tree_new_full((GCompareDataFunc)int_cmp,
- NULL, NULL,
- batch_maps ?
- (GDestroyNotify)g_free :
- (GDestroyNotify)destroy_grant);
- blkdev->persistent_regions = NULL;
- blkdev->persistent_gnt_count = 0;
- }
-
- xen_be_bind_evtchn(&blkdev->xendev);
-
- xen_be_printf(&blkdev->xendev, 1, "ok: proto %s, ring-ref %d, "
- "remote port %d, local port %d\n",
- blkdev->xendev.protocol, blkdev->ring_ref,
- blkdev->xendev.remote_port, blkdev->xendev.local_port);
- return 0;
-}
-
-static void blk_disconnect(struct XenDevice *xendev)
-{
- struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
-
- if (blkdev->blk) {
- blk_detach_dev(blkdev->blk, blkdev);
- blk_unref(blkdev->blk);
- blkdev->blk = NULL;
- }
- xen_be_unbind_evtchn(&blkdev->xendev);
-
- if (blkdev->sring) {
- xengnttab_unmap(blkdev->xendev.gnttabdev, blkdev->sring, 1);
- blkdev->cnt_map--;
- blkdev->sring = NULL;
- }
-
- /*
- * Unmap persistent grants before switching to the closed state
- * so the frontend can free them.
- *
- * In the !batch_maps case g_tree_destroy will take care of unmapping
- * the grant, but in the batch_maps case we need to iterate over every
- * region in persistent_regions and unmap it.
- */
- if (blkdev->feature_persistent) {
- g_tree_destroy(blkdev->persistent_gnts);
- assert(batch_maps || blkdev->persistent_gnt_count == 0);
- if (batch_maps) {
- blkdev->persistent_gnt_count = 0;
- g_slist_foreach(blkdev->persistent_regions,
- (GFunc)remove_persistent_region, blkdev);
- g_slist_free(blkdev->persistent_regions);
- }
- blkdev->feature_persistent = false;
- }
-}
-
-static int blk_free(struct XenDevice *xendev)
-{
- struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
- struct ioreq *ioreq;
-
- if (blkdev->blk || blkdev->sring) {
- blk_disconnect(xendev);
- }
-
- while (!QLIST_EMPTY(&blkdev->freelist)) {
- ioreq = QLIST_FIRST(&blkdev->freelist);
- QLIST_REMOVE(ioreq, list);
- qemu_iovec_destroy(&ioreq->v);
- g_free(ioreq);
- }
-
- g_free(blkdev->params);
- g_free(blkdev->mode);
- g_free(blkdev->type);
- g_free(blkdev->dev);
- g_free(blkdev->devtype);
- qemu_bh_delete(blkdev->bh);
- return 0;
-}
-
-static void blk_event(struct XenDevice *xendev)
-{
- struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
-
- qemu_bh_schedule(blkdev->bh);
-}
-
-struct XenDevOps xen_blkdev_ops = {
- .size = sizeof(struct XenBlkDev),
- .flags = DEVOPS_FLAG_NEED_GNTDEV,
- .alloc = blk_alloc,
- .init = blk_init,
- .initialise = blk_connect,
- .disconnect = blk_disconnect,
- .event = blk_event,
- .free = blk_free,
-};
diff --git a/qemu/hw/bt/Makefile.objs b/qemu/hw/bt/Makefile.objs
deleted file mode 100644
index 867a7d2e8..000000000
--- a/qemu/hw/bt/Makefile.objs
+++ /dev/null
@@ -1,3 +0,0 @@
-common-obj-y += core.o l2cap.o sdp.o hci.o hid.o
-common-obj-y += hci-csr.o
-
diff --git a/qemu/hw/bt/core.c b/qemu/hw/bt/core.c
deleted file mode 100644
index 615f0af07..000000000
--- a/qemu/hw/bt/core.c
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Convenience functions for bluetooth.
- *
- * Copyright (C) 2008 Andrzej Zaborowski <balrog@zabor.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "sysemu/bt.h"
-#include "hw/bt.h"
-
-/* Slave implementations can ignore this */
-static void bt_dummy_lmp_mode_change(struct bt_link_s *link)
-{
-}
-
-/* Slaves should never receive these PDUs */
-static void bt_dummy_lmp_connection_complete(struct bt_link_s *link)
-{
- if (link->slave->reject_reason)
- fprintf(stderr, "%s: stray LMP_not_accepted received, fixme\n",
- __FUNCTION__);
- else
- fprintf(stderr, "%s: stray LMP_accepted received, fixme\n",
- __FUNCTION__);
- exit(-1);
-}
-
-static void bt_dummy_lmp_disconnect_master(struct bt_link_s *link)
-{
- fprintf(stderr, "%s: stray LMP_detach received, fixme\n", __FUNCTION__);
- exit(-1);
-}
-
-static void bt_dummy_lmp_acl_resp(struct bt_link_s *link,
- const uint8_t *data, int start, int len)
-{
- fprintf(stderr, "%s: stray ACL response PDU, fixme\n", __FUNCTION__);
- exit(-1);
-}
-
-/* Slaves that don't hold any additional per link state can use these */
-static void bt_dummy_lmp_connection_request(struct bt_link_s *req)
-{
- struct bt_link_s *link = g_malloc0(sizeof(struct bt_link_s));
-
- link->slave = req->slave;
- link->host = req->host;
-
- req->host->reject_reason = 0;
- req->host->lmp_connection_complete(link);
-}
-
-static void bt_dummy_lmp_disconnect_slave(struct bt_link_s *link)
-{
- g_free(link);
-}
-
-static void bt_dummy_destroy(struct bt_device_s *device)
-{
- bt_device_done(device);
- g_free(device);
-}
-
-static int bt_dev_idx = 0;
-
-void bt_device_init(struct bt_device_s *dev, struct bt_scatternet_s *net)
-{
- memset(dev, 0, sizeof(*dev));
- dev->inquiry_scan = 1;
- dev->page_scan = 1;
-
- dev->bd_addr.b[0] = bt_dev_idx & 0xff;
- dev->bd_addr.b[1] = bt_dev_idx >> 8;
- dev->bd_addr.b[2] = 0xd0;
- dev->bd_addr.b[3] = 0xba;
- dev->bd_addr.b[4] = 0xbe;
- dev->bd_addr.b[5] = 0xba;
- bt_dev_idx ++;
-
- /* Simple slave-only devices need to implement only .lmp_acl_data */
- dev->lmp_connection_complete = bt_dummy_lmp_connection_complete;
- dev->lmp_disconnect_master = bt_dummy_lmp_disconnect_master;
- dev->lmp_acl_resp = bt_dummy_lmp_acl_resp;
- dev->lmp_mode_change = bt_dummy_lmp_mode_change;
- dev->lmp_connection_request = bt_dummy_lmp_connection_request;
- dev->lmp_disconnect_slave = bt_dummy_lmp_disconnect_slave;
-
- dev->handle_destroy = bt_dummy_destroy;
-
- dev->net = net;
- dev->next = net->slave;
- net->slave = dev;
-}
-
-void bt_device_done(struct bt_device_s *dev)
-{
- struct bt_device_s **p = &dev->net->slave;
-
- while (*p && *p != dev)
- p = &(*p)->next;
- if (*p != dev) {
- fprintf(stderr, "%s: bad bt device \"%s\"\n", __FUNCTION__,
- dev->lmp_name ?: "(null)");
- exit(-1);
- }
-
- *p = dev->next;
-}
-
-static struct bt_vlan_s {
- struct bt_scatternet_s net;
- int id;
- struct bt_vlan_s *next;
-} *first_bt_vlan;
-
-/* find or alloc a new bluetooth "VLAN" */
-struct bt_scatternet_s *qemu_find_bt_vlan(int id)
-{
- struct bt_vlan_s **pvlan, *vlan;
- for (vlan = first_bt_vlan; vlan != NULL; vlan = vlan->next) {
- if (vlan->id == id)
- return &vlan->net;
- }
- vlan = g_malloc0(sizeof(struct bt_vlan_s));
- vlan->id = id;
- pvlan = &first_bt_vlan;
- while (*pvlan != NULL)
- pvlan = &(*pvlan)->next;
- *pvlan = vlan;
- return &vlan->net;
-}
diff --git a/qemu/hw/bt/hci-csr.c b/qemu/hw/bt/hci-csr.c
deleted file mode 100644
index 2e970b656..000000000
--- a/qemu/hw/bt/hci-csr.c
+++ /dev/null
@@ -1,455 +0,0 @@
-/*
- * Bluetooth serial HCI transport.
- * CSR41814 HCI with H4p vendor extensions.
- *
- * Copyright (C) 2008 Andrzej Zaborowski <balrog@zabor.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "sysemu/char.h"
-#include "qemu/timer.h"
-#include "hw/irq.h"
-#include "sysemu/bt.h"
-#include "hw/bt.h"
-
-struct csrhci_s {
- int enable;
- qemu_irq *pins;
- int pin_state;
- int modem_state;
- CharDriverState chr;
-#define FIFO_LEN 4096
- int out_start;
- int out_len;
- int out_size;
- uint8_t outfifo[FIFO_LEN * 2];
- uint8_t inpkt[FIFO_LEN];
- int in_len;
- int in_hdr;
- int in_data;
- QEMUTimer *out_tm;
- int64_t baud_delay;
-
- bdaddr_t bd_addr;
- struct HCIInfo *hci;
-};
-
-/* H4+ packet types */
-enum {
- H4_CMD_PKT = 1,
- H4_ACL_PKT = 2,
- H4_SCO_PKT = 3,
- H4_EVT_PKT = 4,
- H4_NEG_PKT = 6,
- H4_ALIVE_PKT = 7,
-};
-
-/* CSR41814 negotiation start magic packet */
-static const uint8_t csrhci_neg_packet[] = {
- H4_NEG_PKT, 10,
- 0x00, 0xa0, 0x01, 0x00, 0x00,
- 0x4c, 0x00, 0x96, 0x00, 0x00,
-};
-
-/* CSR41814 vendor-specific command OCFs */
-enum {
- OCF_CSR_SEND_FIRMWARE = 0x000,
-};
-
-static inline void csrhci_fifo_wake(struct csrhci_s *s)
-{
- if (!s->enable || !s->out_len)
- return;
-
- /* XXX: Should wait for s->modem_state & CHR_TIOCM_RTS? */
- if (s->chr.chr_can_read && s->chr.chr_can_read(s->chr.handler_opaque) &&
- s->chr.chr_read) {
- s->chr.chr_read(s->chr.handler_opaque,
- s->outfifo + s->out_start ++, 1);
- s->out_len --;
- if (s->out_start >= s->out_size) {
- s->out_start = 0;
- s->out_size = FIFO_LEN;
- }
- }
-
- if (s->out_len)
- timer_mod(s->out_tm, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->baud_delay);
-}
-
-#define csrhci_out_packetz(s, len) memset(csrhci_out_packet(s, len), 0, len)
-static uint8_t *csrhci_out_packet(struct csrhci_s *s, int len)
-{
- int off = s->out_start + s->out_len;
-
- /* TODO: do the padding here, i.e. align len */
- s->out_len += len;
-
- if (off < FIFO_LEN) {
- if (off + len > FIFO_LEN && (s->out_size = off + len) > FIFO_LEN * 2) {
- fprintf(stderr, "%s: can't alloc %i bytes\n", __FUNCTION__, len);
- exit(-1);
- }
- return s->outfifo + off;
- }
-
- if (s->out_len > s->out_size) {
- fprintf(stderr, "%s: can't alloc %i bytes\n", __FUNCTION__, len);
- exit(-1);
- }
-
- return s->outfifo + off - s->out_size;
-}
-
-static inline uint8_t *csrhci_out_packet_csr(struct csrhci_s *s,
- int type, int len)
-{
- uint8_t *ret = csrhci_out_packetz(s, len + 2);
-
- *ret ++ = type;
- *ret ++ = len;
-
- return ret;
-}
-
-static inline uint8_t *csrhci_out_packet_event(struct csrhci_s *s,
- int evt, int len)
-{
- uint8_t *ret = csrhci_out_packetz(s,
- len + 1 + sizeof(struct hci_event_hdr));
-
- *ret ++ = H4_EVT_PKT;
- ((struct hci_event_hdr *) ret)->evt = evt;
- ((struct hci_event_hdr *) ret)->plen = len;
-
- return ret + sizeof(struct hci_event_hdr);
-}
-
-static void csrhci_in_packet_vendor(struct csrhci_s *s, int ocf,
- uint8_t *data, int len)
-{
- int offset;
- uint8_t *rpkt;
-
- switch (ocf) {
- case OCF_CSR_SEND_FIRMWARE:
- /* Check if this is the bd_address packet */
- if (len >= 18 + 8 && data[12] == 0x01 && data[13] == 0x00) {
- offset = 18;
- s->bd_addr.b[0] = data[offset + 7]; /* Beyond cmd packet end(!?) */
- s->bd_addr.b[1] = data[offset + 6];
- s->bd_addr.b[2] = data[offset + 4];
- s->bd_addr.b[3] = data[offset + 0];
- s->bd_addr.b[4] = data[offset + 3];
- s->bd_addr.b[5] = data[offset + 2];
-
- s->hci->bdaddr_set(s->hci, s->bd_addr.b);
- fprintf(stderr, "%s: bd_address loaded from firmware: "
- "%02x:%02x:%02x:%02x:%02x:%02x\n", __FUNCTION__,
- s->bd_addr.b[0], s->bd_addr.b[1], s->bd_addr.b[2],
- s->bd_addr.b[3], s->bd_addr.b[4], s->bd_addr.b[5]);
- }
-
- rpkt = csrhci_out_packet_event(s, EVT_VENDOR, 11);
- /* Status bytes: no error */
- rpkt[9] = 0x00;
- rpkt[10] = 0x00;
- break;
-
- default:
- fprintf(stderr, "%s: got a bad CMD packet\n", __FUNCTION__);
- return;
- }
-
- csrhci_fifo_wake(s);
-}
-
-static void csrhci_in_packet(struct csrhci_s *s, uint8_t *pkt)
-{
- uint8_t *rpkt;
- int opc;
-
- switch (*pkt ++) {
- case H4_CMD_PKT:
- opc = le16_to_cpu(((struct hci_command_hdr *) pkt)->opcode);
- if (cmd_opcode_ogf(opc) == OGF_VENDOR_CMD) {
- csrhci_in_packet_vendor(s, cmd_opcode_ocf(opc),
- pkt + sizeof(struct hci_command_hdr),
- s->in_len - sizeof(struct hci_command_hdr) - 1);
- return;
- }
-
- /* TODO: if the command is OCF_READ_LOCAL_COMMANDS or the likes,
- * we need to send it to the HCI layer and then add our supported
- * commands to the returned mask (such as OGF_VENDOR_CMD). With
- * bt-hci.c we could just have hooks for this kind of commands but
- * we can't with bt-host.c. */
-
- s->hci->cmd_send(s->hci, pkt, s->in_len - 1);
- break;
-
- case H4_EVT_PKT:
- goto bad_pkt;
-
- case H4_ACL_PKT:
- s->hci->acl_send(s->hci, pkt, s->in_len - 1);
- break;
-
- case H4_SCO_PKT:
- s->hci->sco_send(s->hci, pkt, s->in_len - 1);
- break;
-
- case H4_NEG_PKT:
- if (s->in_hdr != sizeof(csrhci_neg_packet) ||
- memcmp(pkt - 1, csrhci_neg_packet, s->in_hdr)) {
- fprintf(stderr, "%s: got a bad NEG packet\n", __FUNCTION__);
- return;
- }
- pkt += 2;
-
- rpkt = csrhci_out_packet_csr(s, H4_NEG_PKT, 10);
-
- *rpkt ++ = 0x20; /* Operational settings negotiation Ok */
- memcpy(rpkt, pkt, 7); rpkt += 7;
- *rpkt ++ = 0xff;
- *rpkt = 0xff;
- break;
-
- case H4_ALIVE_PKT:
- if (s->in_hdr != 4 || pkt[1] != 0x55 || pkt[2] != 0x00) {
- fprintf(stderr, "%s: got a bad ALIVE packet\n", __FUNCTION__);
- return;
- }
-
- rpkt = csrhci_out_packet_csr(s, H4_ALIVE_PKT, 2);
-
- *rpkt ++ = 0xcc;
- *rpkt = 0x00;
- break;
-
- default:
- bad_pkt:
- /* TODO: error out */
- fprintf(stderr, "%s: got a bad packet\n", __FUNCTION__);
- break;
- }
-
- csrhci_fifo_wake(s);
-}
-
-static int csrhci_header_len(const uint8_t *pkt)
-{
- switch (pkt[0]) {
- case H4_CMD_PKT:
- return HCI_COMMAND_HDR_SIZE;
- case H4_EVT_PKT:
- return HCI_EVENT_HDR_SIZE;
- case H4_ACL_PKT:
- return HCI_ACL_HDR_SIZE;
- case H4_SCO_PKT:
- return HCI_SCO_HDR_SIZE;
- case H4_NEG_PKT:
- return pkt[1] + 1;
- case H4_ALIVE_PKT:
- return 3;
- }
-
- exit(-1);
-}
-
-static int csrhci_data_len(const uint8_t *pkt)
-{
- switch (*pkt ++) {
- case H4_CMD_PKT:
- /* It seems that vendor-specific command packets for H4+ are all
- * one byte longer than indicated in the standard header. */
- if (le16_to_cpu(((struct hci_command_hdr *) pkt)->opcode) == 0xfc00)
- return (((struct hci_command_hdr *) pkt)->plen + 1) & ~1;
-
- return ((struct hci_command_hdr *) pkt)->plen;
- case H4_EVT_PKT:
- return ((struct hci_event_hdr *) pkt)->plen;
- case H4_ACL_PKT:
- return le16_to_cpu(((struct hci_acl_hdr *) pkt)->dlen);
- case H4_SCO_PKT:
- return ((struct hci_sco_hdr *) pkt)->dlen;
- case H4_NEG_PKT:
- case H4_ALIVE_PKT:
- return 0;
- }
-
- exit(-1);
-}
-
-static int csrhci_write(struct CharDriverState *chr,
- const uint8_t *buf, int len)
-{
- struct csrhci_s *s = (struct csrhci_s *) chr->opaque;
- int plen = s->in_len;
-
- if (!s->enable)
- return 0;
-
- s->in_len += len;
- memcpy(s->inpkt + plen, buf, len);
-
- while (1) {
- if (s->in_len >= 2 && plen < 2)
- s->in_hdr = csrhci_header_len(s->inpkt) + 1;
-
- if (s->in_len >= s->in_hdr && plen < s->in_hdr)
- s->in_data = csrhci_data_len(s->inpkt) + s->in_hdr;
-
- if (s->in_len >= s->in_data) {
- csrhci_in_packet(s, s->inpkt);
-
- memmove(s->inpkt, s->inpkt + s->in_len, s->in_len - s->in_data);
- s->in_len -= s->in_data;
- s->in_hdr = INT_MAX;
- s->in_data = INT_MAX;
- plen = 0;
- } else
- break;
- }
-
- return len;
-}
-
-static void csrhci_out_hci_packet_event(void *opaque,
- const uint8_t *data, int len)
-{
- struct csrhci_s *s = (struct csrhci_s *) opaque;
- uint8_t *pkt = csrhci_out_packet(s, (len + 2) & ~1); /* Align */
-
- *pkt ++ = H4_EVT_PKT;
- memcpy(pkt, data, len);
-
- csrhci_fifo_wake(s);
-}
-
-static void csrhci_out_hci_packet_acl(void *opaque,
- const uint8_t *data, int len)
-{
- struct csrhci_s *s = (struct csrhci_s *) opaque;
- uint8_t *pkt = csrhci_out_packet(s, (len + 2) & ~1); /* Align */
-
- *pkt ++ = H4_ACL_PKT;
- pkt[len & ~1] = 0;
- memcpy(pkt, data, len);
-
- csrhci_fifo_wake(s);
-}
-
-static int csrhci_ioctl(struct CharDriverState *chr, int cmd, void *arg)
-{
- QEMUSerialSetParams *ssp;
- struct csrhci_s *s = (struct csrhci_s *) chr->opaque;
- int prev_state = s->modem_state;
-
- switch (cmd) {
- case CHR_IOCTL_SERIAL_SET_PARAMS:
- ssp = (QEMUSerialSetParams *) arg;
- s->baud_delay = NANOSECONDS_PER_SECOND / ssp->speed;
- /* Moments later... (but shorter than 100ms) */
- s->modem_state |= CHR_TIOCM_CTS;
- break;
-
- case CHR_IOCTL_SERIAL_GET_TIOCM:
- *(int *) arg = s->modem_state;
- break;
-
- case CHR_IOCTL_SERIAL_SET_TIOCM:
- s->modem_state = *(int *) arg;
- if (~s->modem_state & prev_state & CHR_TIOCM_RTS)
- s->modem_state &= ~CHR_TIOCM_CTS;
- break;
-
- default:
- return -ENOTSUP;
- }
- return 0;
-}
-
-static void csrhci_reset(struct csrhci_s *s)
-{
- s->out_len = 0;
- s->out_size = FIFO_LEN;
- s->in_len = 0;
- s->baud_delay = NANOSECONDS_PER_SECOND;
- s->enable = 0;
- s->in_hdr = INT_MAX;
- s->in_data = INT_MAX;
-
- s->modem_state = 0;
- /* After a while... (but sooner than 10ms) */
- s->modem_state |= CHR_TIOCM_CTS;
-
- memset(&s->bd_addr, 0, sizeof(bdaddr_t));
-}
-
-static void csrhci_out_tick(void *opaque)
-{
- csrhci_fifo_wake((struct csrhci_s *) opaque);
-}
-
-static void csrhci_pins(void *opaque, int line, int level)
-{
- struct csrhci_s *s = (struct csrhci_s *) opaque;
- int state = s->pin_state;
-
- s->pin_state &= ~(1 << line);
- s->pin_state |= (!!level) << line;
-
- if ((state & ~s->pin_state) & (1 << csrhci_pin_reset)) {
- /* TODO: Disappear from lower layers */
- csrhci_reset(s);
- }
-
- if (s->pin_state == 3 && state != 3) {
- s->enable = 1;
- /* TODO: Wake lower layers up */
- }
-}
-
-qemu_irq *csrhci_pins_get(CharDriverState *chr)
-{
- struct csrhci_s *s = (struct csrhci_s *) chr->opaque;
-
- return s->pins;
-}
-
-CharDriverState *uart_hci_init(qemu_irq wakeup)
-{
- struct csrhci_s *s = (struct csrhci_s *)
- g_malloc0(sizeof(struct csrhci_s));
-
- s->chr.opaque = s;
- s->chr.chr_write = csrhci_write;
- s->chr.chr_ioctl = csrhci_ioctl;
- s->chr.avail_connections = 1;
-
- s->hci = qemu_next_hci();
- s->hci->opaque = s;
- s->hci->evt_recv = csrhci_out_hci_packet_event;
- s->hci->acl_recv = csrhci_out_hci_packet_acl;
-
- s->out_tm = timer_new_ns(QEMU_CLOCK_VIRTUAL, csrhci_out_tick, s);
- s->pins = qemu_allocate_irqs(csrhci_pins, s, __csrhci_pins);
- csrhci_reset(s);
-
- return &s->chr;
-}
diff --git a/qemu/hw/bt/hci.c b/qemu/hw/bt/hci.c
deleted file mode 100644
index 7d5220509..000000000
--- a/qemu/hw/bt/hci.c
+++ /dev/null
@@ -1,2272 +0,0 @@
-/*
- * QEMU Bluetooth HCI logic.
- *
- * Copyright (C) 2007 OpenMoko, Inc.
- * Copyright (C) 2008 Andrzej Zaborowski <balrog@zabor.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "qemu/timer.h"
-#include "hw/usb.h"
-#include "sysemu/bt.h"
-#include "hw/bt.h"
-#include "qapi/qmp/qerror.h"
-#include "sysemu/replay.h"
-#include "qemu/cutils.h"
-
-struct bt_hci_s {
- uint8_t *(*evt_packet)(void *opaque);
- void (*evt_submit)(void *opaque, int len);
- void *opaque;
- uint8_t evt_buf[256];
-
- uint8_t acl_buf[4096];
- int acl_len;
-
- uint16_t asb_handle;
- uint16_t psb_handle;
-
- int last_cmd; /* Note: Always little-endian */
-
- struct bt_device_s *conn_req_host;
-
- struct {
- int inquire;
- int periodic;
- int responses_left;
- int responses;
- QEMUTimer *inquiry_done;
- QEMUTimer *inquiry_next;
- int inquiry_length;
- int inquiry_period;
- int inquiry_mode;
-
-#define HCI_HANDLE_OFFSET 0x20
-#define HCI_HANDLES_MAX 0x10
- struct bt_hci_master_link_s {
- struct bt_link_s *link;
- void (*lmp_acl_data)(struct bt_link_s *link,
- const uint8_t *data, int start, int len);
- QEMUTimer *acl_mode_timer;
- } handle[HCI_HANDLES_MAX];
- uint32_t role_bmp;
- int last_handle;
- int connecting;
- bdaddr_t awaiting_bdaddr[HCI_HANDLES_MAX];
- } lm;
-
- uint8_t event_mask[8];
- uint16_t voice_setting; /* Notw: Always little-endian */
- uint16_t conn_accept_tout;
- QEMUTimer *conn_accept_timer;
-
- struct HCIInfo info;
- struct bt_device_s device;
-
- Error *replay_blocker;
-};
-
-#define DEFAULT_RSSI_DBM 20
-
-#define hci_from_info(ptr) container_of((ptr), struct bt_hci_s, info)
-#define hci_from_device(ptr) container_of((ptr), struct bt_hci_s, device)
-
-struct bt_hci_link_s {
- struct bt_link_s btlink;
- uint16_t handle; /* Local */
-};
-
-/* LMP layer emulation */
-#if 0
-static void bt_submit_lmp(struct bt_device_s *bt, int length, uint8_t *data)
-{
- int resp, resplen, error, op, tr;
- uint8_t respdata[17];
-
- if (length < 1)
- return;
-
- tr = *data & 1;
- op = *(data ++) >> 1;
- resp = LMP_ACCEPTED;
- resplen = 2;
- respdata[1] = op;
- error = 0;
- length --;
-
- if (op >= 0x7c) { /* Extended opcode */
- op |= *(data ++) << 8;
- resp = LMP_ACCEPTED_EXT;
- resplen = 4;
- respdata[0] = op >> 8;
- respdata[1] = op & 0xff;
- length --;
- }
-
- switch (op) {
- case LMP_ACCEPTED:
- /* data[0] Op code
- */
- if (length < 1) {
- error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
- goto not_accepted;
- }
- resp = 0;
- break;
-
- case LMP_ACCEPTED_EXT:
- /* data[0] Escape op code
- * data[1] Extended op code
- */
- if (length < 2) {
- error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
- goto not_accepted;
- }
- resp = 0;
- break;
-
- case LMP_NOT_ACCEPTED:
- /* data[0] Op code
- * data[1] Error code
- */
- if (length < 2) {
- error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
- goto not_accepted;
- }
- resp = 0;
- break;
-
- case LMP_NOT_ACCEPTED_EXT:
- /* data[0] Op code
- * data[1] Extended op code
- * data[2] Error code
- */
- if (length < 3) {
- error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
- goto not_accepted;
- }
- resp = 0;
- break;
-
- case LMP_HOST_CONNECTION_REQ:
- break;
-
- case LMP_SETUP_COMPLETE:
- resp = LMP_SETUP_COMPLETE;
- resplen = 1;
- bt->setup = 1;
- break;
-
- case LMP_DETACH:
- /* data[0] Error code
- */
- if (length < 1) {
- error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
- goto not_accepted;
- }
- bt->setup = 0;
- resp = 0;
- break;
-
- case LMP_SUPERVISION_TIMEOUT:
- /* data[0,1] Supervision timeout
- */
- if (length < 2) {
- error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
- goto not_accepted;
- }
- resp = 0;
- break;
-
- case LMP_QUALITY_OF_SERVICE:
- resp = 0;
- /* Fall through */
- case LMP_QOS_REQ:
- /* data[0,1] Poll interval
- * data[2] N(BC)
- */
- if (length < 3) {
- error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
- goto not_accepted;
- }
- break;
-
- case LMP_MAX_SLOT:
- resp = 0;
- /* Fall through */
- case LMP_MAX_SLOT_REQ:
- /* data[0] Max slots
- */
- if (length < 1) {
- error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
- goto not_accepted;
- }
- break;
-
- case LMP_AU_RAND:
- case LMP_IN_RAND:
- case LMP_COMB_KEY:
- /* data[0-15] Random number
- */
- if (length < 16) {
- error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
- goto not_accepted;
- }
- if (op == LMP_AU_RAND) {
- if (bt->key_present) {
- resp = LMP_SRES;
- resplen = 5;
- /* XXX: [Part H] Section 6.1 on page 801 */
- } else {
- error = HCI_PIN_OR_KEY_MISSING;
- goto not_accepted;
- }
- } else if (op == LMP_IN_RAND) {
- error = HCI_PAIRING_NOT_ALLOWED;
- goto not_accepted;
- } else {
- /* XXX: [Part H] Section 3.2 on page 779 */
- resp = LMP_UNIT_KEY;
- resplen = 17;
- memcpy(respdata + 1, bt->key, 16);
-
- error = HCI_UNIT_LINK_KEY_USED;
- goto not_accepted;
- }
- break;
-
- case LMP_UNIT_KEY:
- /* data[0-15] Key
- */
- if (length < 16) {
- error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
- goto not_accepted;
- }
- memcpy(bt->key, data, 16);
- bt->key_present = 1;
- break;
-
- case LMP_SRES:
- /* data[0-3] Authentication response
- */
- if (length < 4) {
- error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
- goto not_accepted;
- }
- break;
-
- case LMP_CLKOFFSET_REQ:
- resp = LMP_CLKOFFSET_RES;
- resplen = 3;
- respdata[1] = 0x33;
- respdata[2] = 0x33;
- break;
-
- case LMP_CLKOFFSET_RES:
- /* data[0,1] Clock offset
- * (Slave to master only)
- */
- if (length < 2) {
- error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
- goto not_accepted;
- }
- break;
-
- case LMP_VERSION_REQ:
- case LMP_VERSION_RES:
- /* data[0] VersNr
- * data[1,2] CompId
- * data[3,4] SubVersNr
- */
- if (length < 5) {
- error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
- goto not_accepted;
- }
- if (op == LMP_VERSION_REQ) {
- resp = LMP_VERSION_RES;
- resplen = 6;
- respdata[1] = 0x20;
- respdata[2] = 0xff;
- respdata[3] = 0xff;
- respdata[4] = 0xff;
- respdata[5] = 0xff;
- } else
- resp = 0;
- break;
-
- case LMP_FEATURES_REQ:
- case LMP_FEATURES_RES:
- /* data[0-7] Features
- */
- if (length < 8) {
- error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
- goto not_accepted;
- }
- if (op == LMP_FEATURES_REQ) {
- resp = LMP_FEATURES_RES;
- resplen = 9;
- respdata[1] = (bt->lmp_caps >> 0) & 0xff;
- respdata[2] = (bt->lmp_caps >> 8) & 0xff;
- respdata[3] = (bt->lmp_caps >> 16) & 0xff;
- respdata[4] = (bt->lmp_caps >> 24) & 0xff;
- respdata[5] = (bt->lmp_caps >> 32) & 0xff;
- respdata[6] = (bt->lmp_caps >> 40) & 0xff;
- respdata[7] = (bt->lmp_caps >> 48) & 0xff;
- respdata[8] = (bt->lmp_caps >> 56) & 0xff;
- } else
- resp = 0;
- break;
-
- case LMP_NAME_REQ:
- /* data[0] Name offset
- */
- if (length < 1) {
- error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
- goto not_accepted;
- }
- resp = LMP_NAME_RES;
- resplen = 17;
- respdata[1] = data[0];
- respdata[2] = strlen(bt->lmp_name);
- memset(respdata + 3, 0x00, 14);
- if (respdata[2] > respdata[1])
- memcpy(respdata + 3, bt->lmp_name + respdata[1],
- respdata[2] - respdata[1]);
- break;
-
- case LMP_NAME_RES:
- /* data[0] Name offset
- * data[1] Name length
- * data[2-15] Name fragment
- */
- if (length < 16) {
- error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
- goto not_accepted;
- }
- resp = 0;
- break;
-
- default:
- error = HCI_UNKNOWN_LMP_PDU;
- /* Fall through */
- not_accepted:
- if (op >> 8) {
- resp = LMP_NOT_ACCEPTED_EXT;
- resplen = 5;
- respdata[0] = op >> 8;
- respdata[1] = op & 0xff;
- respdata[2] = error;
- } else {
- resp = LMP_NOT_ACCEPTED;
- resplen = 3;
- respdata[0] = op & 0xff;
- respdata[1] = error;
- }
- }
-
- if (resp == 0)
- return;
-
- if (resp >> 8) {
- respdata[0] = resp >> 8;
- respdata[1] = resp & 0xff;
- } else
- respdata[0] = resp & 0xff;
-
- respdata[0] <<= 1;
- respdata[0] |= tr;
-}
-
-static void bt_submit_raw_acl(struct bt_piconet_s *net, int length, uint8_t *data)
-{
- struct bt_device_s *slave;
- if (length < 1)
- return;
-
- slave = 0;
-#if 0
- slave = net->slave;
-#endif
-
- switch (data[0] & 3) {
- case LLID_ACLC:
- bt_submit_lmp(slave, length - 1, data + 1);
- break;
- case LLID_ACLU_START:
-#if 0
- bt_sumbit_l2cap(slave, length - 1, data + 1, (data[0] >> 2) & 1);
- breka;
-#endif
- default:
- case LLID_ACLU_CONT:
- break;
- }
-}
-#endif
-
-/* HCI layer emulation */
-
-/* Note: we could ignore endiannes because unswapped handles will still
- * be valid as connection identifiers for the guest - they don't have to
- * be continuously allocated. We do it though, to preserve similar
- * behaviour between hosts. Some things, like the BD_ADDR cannot be
- * preserved though (for example if a real hci is used). */
-#ifdef HOST_WORDS_BIGENDIAN
-# define HNDL(raw) bswap16(raw)
-#else
-# define HNDL(raw) (raw)
-#endif
-
-static const uint8_t bt_event_reserved_mask[8] = {
- 0xff, 0x9f, 0xfb, 0xff, 0x07, 0x18, 0x00, 0x00,
-};
-
-
-static void null_hci_send(struct HCIInfo *hci, const uint8_t *data, int len)
-{
-}
-
-static int null_hci_addr_set(struct HCIInfo *hci, const uint8_t *bd_addr)
-{
- return -ENOTSUP;
-}
-
-struct HCIInfo null_hci = {
- .cmd_send = null_hci_send,
- .sco_send = null_hci_send,
- .acl_send = null_hci_send,
- .bdaddr_set = null_hci_addr_set,
-};
-
-
-static inline uint8_t *bt_hci_event_start(struct bt_hci_s *hci,
- int evt, int len)
-{
- uint8_t *packet, mask;
- int mask_byte;
-
- if (len > 255) {
- fprintf(stderr, "%s: HCI event params too long (%ib)\n",
- __FUNCTION__, len);
- exit(-1);
- }
-
- mask_byte = (evt - 1) >> 3;
- mask = 1 << ((evt - 1) & 3);
- if (mask & bt_event_reserved_mask[mask_byte] & ~hci->event_mask[mask_byte])
- return NULL;
-
- packet = hci->evt_packet(hci->opaque);
- packet[0] = evt;
- packet[1] = len;
-
- return &packet[2];
-}
-
-static inline void bt_hci_event(struct bt_hci_s *hci, int evt,
- void *params, int len)
-{
- uint8_t *packet = bt_hci_event_start(hci, evt, len);
-
- if (!packet)
- return;
-
- if (len)
- memcpy(packet, params, len);
-
- hci->evt_submit(hci->opaque, len + 2);
-}
-
-static inline void bt_hci_event_status(struct bt_hci_s *hci, int status)
-{
- evt_cmd_status params = {
- .status = status,
- .ncmd = 1,
- .opcode = hci->last_cmd,
- };
-
- bt_hci_event(hci, EVT_CMD_STATUS, &params, EVT_CMD_STATUS_SIZE);
-}
-
-static inline void bt_hci_event_complete(struct bt_hci_s *hci,
- void *ret, int len)
-{
- uint8_t *packet = bt_hci_event_start(hci, EVT_CMD_COMPLETE,
- len + EVT_CMD_COMPLETE_SIZE);
- evt_cmd_complete *params = (evt_cmd_complete *) packet;
-
- if (!packet)
- return;
-
- params->ncmd = 1;
- params->opcode = hci->last_cmd;
- if (len)
- memcpy(&packet[EVT_CMD_COMPLETE_SIZE], ret, len);
-
- hci->evt_submit(hci->opaque, len + EVT_CMD_COMPLETE_SIZE + 2);
-}
-
-static void bt_hci_inquiry_done(void *opaque)
-{
- struct bt_hci_s *hci = (struct bt_hci_s *) opaque;
- uint8_t status = HCI_SUCCESS;
-
- if (!hci->lm.periodic)
- hci->lm.inquire = 0;
-
- /* The specification is inconsistent about this one. Page 565 reads
- * "The event parameters of Inquiry Complete event will have a summary
- * of the result from the Inquiry process, which reports the number of
- * nearby Bluetooth devices that responded [so hci->responses].", but
- * Event Parameters (see page 729) has only Status. */
- bt_hci_event(hci, EVT_INQUIRY_COMPLETE, &status, 1);
-}
-
-static void bt_hci_inquiry_result_standard(struct bt_hci_s *hci,
- struct bt_device_s *slave)
-{
- inquiry_info params = {
- .num_responses = 1,
- .bdaddr = BAINIT(&slave->bd_addr),
- .pscan_rep_mode = 0x00, /* R0 */
- .pscan_period_mode = 0x00, /* P0 - deprecated */
- .pscan_mode = 0x00, /* Standard scan - deprecated */
- .dev_class[0] = slave->class[0],
- .dev_class[1] = slave->class[1],
- .dev_class[2] = slave->class[2],
- /* TODO: return the clkoff *differenece* */
- .clock_offset = slave->clkoff, /* Note: no swapping */
- };
-
- bt_hci_event(hci, EVT_INQUIRY_RESULT, &params, INQUIRY_INFO_SIZE);
-}
-
-static void bt_hci_inquiry_result_with_rssi(struct bt_hci_s *hci,
- struct bt_device_s *slave)
-{
- inquiry_info_with_rssi params = {
- .num_responses = 1,
- .bdaddr = BAINIT(&slave->bd_addr),
- .pscan_rep_mode = 0x00, /* R0 */
- .pscan_period_mode = 0x00, /* P0 - deprecated */
- .dev_class[0] = slave->class[0],
- .dev_class[1] = slave->class[1],
- .dev_class[2] = slave->class[2],
- /* TODO: return the clkoff *differenece* */
- .clock_offset = slave->clkoff, /* Note: no swapping */
- .rssi = DEFAULT_RSSI_DBM,
- };
-
- bt_hci_event(hci, EVT_INQUIRY_RESULT_WITH_RSSI,
- &params, INQUIRY_INFO_WITH_RSSI_SIZE);
-}
-
-static void bt_hci_inquiry_result(struct bt_hci_s *hci,
- struct bt_device_s *slave)
-{
- if (!slave->inquiry_scan || !hci->lm.responses_left)
- return;
-
- hci->lm.responses_left --;
- hci->lm.responses ++;
-
- switch (hci->lm.inquiry_mode) {
- case 0x00:
- bt_hci_inquiry_result_standard(hci, slave);
- return;
- case 0x01:
- bt_hci_inquiry_result_with_rssi(hci, slave);
- return;
- default:
- fprintf(stderr, "%s: bad inquiry mode %02x\n", __FUNCTION__,
- hci->lm.inquiry_mode);
- exit(-1);
- }
-}
-
-static void bt_hci_mod_timer_1280ms(QEMUTimer *timer, int period)
-{
- timer_mod(timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- (uint64_t)(period << 7) * 10000000);
-}
-
-static void bt_hci_inquiry_start(struct bt_hci_s *hci, int length)
-{
- struct bt_device_s *slave;
-
- hci->lm.inquiry_length = length;
- for (slave = hci->device.net->slave; slave; slave = slave->next)
- /* Don't uncover ourselves. */
- if (slave != &hci->device)
- bt_hci_inquiry_result(hci, slave);
-
- /* TODO: register for a callback on a new device's addition to the
- * scatternet so that if it's added before inquiry_length expires,
- * an Inquiry Result is generated immediately. Alternatively re-loop
- * through the devices on the inquiry_length expiration and report
- * devices not seen before. */
- if (hci->lm.responses_left)
- bt_hci_mod_timer_1280ms(hci->lm.inquiry_done, hci->lm.inquiry_length);
- else
- bt_hci_inquiry_done(hci);
-
- if (hci->lm.periodic)
- bt_hci_mod_timer_1280ms(hci->lm.inquiry_next, hci->lm.inquiry_period);
-}
-
-static void bt_hci_inquiry_next(void *opaque)
-{
- struct bt_hci_s *hci = (struct bt_hci_s *) opaque;
-
- hci->lm.responses_left += hci->lm.responses;
- hci->lm.responses = 0;
- bt_hci_inquiry_start(hci, hci->lm.inquiry_length);
-}
-
-static inline int bt_hci_handle_bad(struct bt_hci_s *hci, uint16_t handle)
-{
- return !(handle & HCI_HANDLE_OFFSET) ||
- handle >= (HCI_HANDLE_OFFSET | HCI_HANDLES_MAX) ||
- !hci->lm.handle[handle & ~HCI_HANDLE_OFFSET].link;
-}
-
-static inline int bt_hci_role_master(struct bt_hci_s *hci, uint16_t handle)
-{
- return !!(hci->lm.role_bmp & (1 << (handle & ~HCI_HANDLE_OFFSET)));
-}
-
-static inline struct bt_device_s *bt_hci_remote_dev(struct bt_hci_s *hci,
- uint16_t handle)
-{
- struct bt_link_s *link = hci->lm.handle[handle & ~HCI_HANDLE_OFFSET].link;
-
- return bt_hci_role_master(hci, handle) ? link->slave : link->host;
-}
-
-static void bt_hci_mode_tick(void *opaque);
-static void bt_hci_lmp_link_establish(struct bt_hci_s *hci,
- struct bt_link_s *link, int master)
-{
- hci->lm.handle[hci->lm.last_handle].link = link;
-
- if (master) {
- /* We are the master side of an ACL link */
- hci->lm.role_bmp |= 1 << hci->lm.last_handle;
-
- hci->lm.handle[hci->lm.last_handle].lmp_acl_data =
- link->slave->lmp_acl_data;
- } else {
- /* We are the slave side of an ACL link */
- hci->lm.role_bmp &= ~(1 << hci->lm.last_handle);
-
- hci->lm.handle[hci->lm.last_handle].lmp_acl_data =
- link->host->lmp_acl_resp;
- }
-
- /* Mode */
- if (master) {
- link->acl_mode = acl_active;
- hci->lm.handle[hci->lm.last_handle].acl_mode_timer =
- timer_new_ns(QEMU_CLOCK_VIRTUAL, bt_hci_mode_tick, link);
- }
-}
-
-static void bt_hci_lmp_link_teardown(struct bt_hci_s *hci, uint16_t handle)
-{
- handle &= ~HCI_HANDLE_OFFSET;
- hci->lm.handle[handle].link = NULL;
-
- if (bt_hci_role_master(hci, handle)) {
- timer_del(hci->lm.handle[handle].acl_mode_timer);
- timer_free(hci->lm.handle[handle].acl_mode_timer);
- }
-}
-
-static int bt_hci_connect(struct bt_hci_s *hci, bdaddr_t *bdaddr)
-{
- struct bt_device_s *slave;
- struct bt_link_s link;
-
- for (slave = hci->device.net->slave; slave; slave = slave->next)
- if (slave->page_scan && !bacmp(&slave->bd_addr, bdaddr))
- break;
- if (!slave || slave == &hci->device)
- return -ENODEV;
-
- bacpy(&hci->lm.awaiting_bdaddr[hci->lm.connecting ++], &slave->bd_addr);
-
- link.slave = slave;
- link.host = &hci->device;
- link.slave->lmp_connection_request(&link); /* Always last */
-
- return 0;
-}
-
-static void bt_hci_connection_reject(struct bt_hci_s *hci,
- struct bt_device_s *host, uint8_t because)
-{
- struct bt_link_s link = {
- .slave = &hci->device,
- .host = host,
- /* Rest uninitialised */
- };
-
- host->reject_reason = because;
- host->lmp_connection_complete(&link);
-}
-
-static void bt_hci_connection_reject_event(struct bt_hci_s *hci,
- bdaddr_t *bdaddr)
-{
- evt_conn_complete params;
-
- params.status = HCI_NO_CONNECTION;
- params.handle = 0;
- bacpy(&params.bdaddr, bdaddr);
- params.link_type = ACL_LINK;
- params.encr_mode = 0x00; /* Encryption not required */
- bt_hci_event(hci, EVT_CONN_COMPLETE, &params, EVT_CONN_COMPLETE_SIZE);
-}
-
-static void bt_hci_connection_accept(struct bt_hci_s *hci,
- struct bt_device_s *host)
-{
- struct bt_hci_link_s *link = g_malloc0(sizeof(struct bt_hci_link_s));
- evt_conn_complete params;
- uint16_t handle;
- uint8_t status = HCI_SUCCESS;
- int tries = HCI_HANDLES_MAX;
-
- /* Make a connection handle */
- do {
- while (hci->lm.handle[++ hci->lm.last_handle].link && -- tries)
- hci->lm.last_handle &= HCI_HANDLES_MAX - 1;
- handle = hci->lm.last_handle | HCI_HANDLE_OFFSET;
- } while ((handle == hci->asb_handle || handle == hci->psb_handle) &&
- tries);
-
- if (!tries) {
- g_free(link);
- bt_hci_connection_reject(hci, host, HCI_REJECTED_LIMITED_RESOURCES);
- status = HCI_NO_CONNECTION;
- goto complete;
- }
-
- link->btlink.slave = &hci->device;
- link->btlink.host = host;
- link->handle = handle;
-
- /* Link established */
- bt_hci_lmp_link_establish(hci, &link->btlink, 0);
-
-complete:
- params.status = status;
- params.handle = HNDL(handle);
- bacpy(&params.bdaddr, &host->bd_addr);
- params.link_type = ACL_LINK;
- params.encr_mode = 0x00; /* Encryption not required */
- bt_hci_event(hci, EVT_CONN_COMPLETE, &params, EVT_CONN_COMPLETE_SIZE);
-
- /* Neets to be done at the very end because it can trigger a (nested)
- * disconnected, in case the other and had cancelled the request
- * locally. */
- if (status == HCI_SUCCESS) {
- host->reject_reason = 0;
- host->lmp_connection_complete(&link->btlink);
- }
-}
-
-static void bt_hci_lmp_connection_request(struct bt_link_s *link)
-{
- struct bt_hci_s *hci = hci_from_device(link->slave);
- evt_conn_request params;
-
- if (hci->conn_req_host) {
- bt_hci_connection_reject(hci, link->host,
- HCI_REJECTED_LIMITED_RESOURCES);
- return;
- }
- hci->conn_req_host = link->host;
- /* TODO: if masked and auto-accept, then auto-accept,
- * if masked and not auto-accept, then auto-reject */
- /* TODO: kick the hci->conn_accept_timer, timeout after
- * hci->conn_accept_tout * 0.625 msec */
-
- bacpy(&params.bdaddr, &link->host->bd_addr);
- memcpy(&params.dev_class, &link->host->class, sizeof(params.dev_class));
- params.link_type = ACL_LINK;
- bt_hci_event(hci, EVT_CONN_REQUEST, &params, EVT_CONN_REQUEST_SIZE);
-}
-
-static void bt_hci_conn_accept_timeout(void *opaque)
-{
- struct bt_hci_s *hci = (struct bt_hci_s *) opaque;
-
- if (!hci->conn_req_host)
- /* Already accepted or rejected. If the other end cancelled the
- * connection request then we still have to reject or accept it
- * and then we'll get a disconnect. */
- return;
-
- /* TODO */
-}
-
-/* Remove from the list of devices which we wanted to connect to and
- * are awaiting a response from. If the callback sees a response from
- * a device which is not on the list it will assume it's a connection
- * that's been cancelled by the host in the meantime and immediately
- * try to detach the link and send a Connection Complete. */
-static int bt_hci_lmp_connection_ready(struct bt_hci_s *hci,
- bdaddr_t *bdaddr)
-{
- int i;
-
- for (i = 0; i < hci->lm.connecting; i ++)
- if (!bacmp(&hci->lm.awaiting_bdaddr[i], bdaddr)) {
- if (i < -- hci->lm.connecting)
- bacpy(&hci->lm.awaiting_bdaddr[i],
- &hci->lm.awaiting_bdaddr[hci->lm.connecting]);
- return 0;
- }
-
- return 1;
-}
-
-static void bt_hci_lmp_connection_complete(struct bt_link_s *link)
-{
- struct bt_hci_s *hci = hci_from_device(link->host);
- evt_conn_complete params;
- uint16_t handle;
- uint8_t status = HCI_SUCCESS;
- int tries = HCI_HANDLES_MAX;
-
- if (bt_hci_lmp_connection_ready(hci, &link->slave->bd_addr)) {
- if (!hci->device.reject_reason)
- link->slave->lmp_disconnect_slave(link);
- handle = 0;
- status = HCI_NO_CONNECTION;
- goto complete;
- }
-
- if (hci->device.reject_reason) {
- handle = 0;
- status = hci->device.reject_reason;
- goto complete;
- }
-
- /* Make a connection handle */
- do {
- while (hci->lm.handle[++ hci->lm.last_handle].link && -- tries)
- hci->lm.last_handle &= HCI_HANDLES_MAX - 1;
- handle = hci->lm.last_handle | HCI_HANDLE_OFFSET;
- } while ((handle == hci->asb_handle || handle == hci->psb_handle) &&
- tries);
-
- if (!tries) {
- link->slave->lmp_disconnect_slave(link);
- status = HCI_NO_CONNECTION;
- goto complete;
- }
-
- /* Link established */
- link->handle = handle;
- bt_hci_lmp_link_establish(hci, link, 1);
-
-complete:
- params.status = status;
- params.handle = HNDL(handle);
- params.link_type = ACL_LINK;
- bacpy(&params.bdaddr, &link->slave->bd_addr);
- params.encr_mode = 0x00; /* Encryption not required */
- bt_hci_event(hci, EVT_CONN_COMPLETE, &params, EVT_CONN_COMPLETE_SIZE);
-}
-
-static void bt_hci_disconnect(struct bt_hci_s *hci,
- uint16_t handle, int reason)
-{
- struct bt_link_s *btlink =
- hci->lm.handle[handle & ~HCI_HANDLE_OFFSET].link;
- struct bt_hci_link_s *link;
- evt_disconn_complete params;
-
- if (bt_hci_role_master(hci, handle)) {
- btlink->slave->reject_reason = reason;
- btlink->slave->lmp_disconnect_slave(btlink);
- /* The link pointer is invalid from now on */
-
- goto complete;
- }
-
- btlink->host->reject_reason = reason;
- btlink->host->lmp_disconnect_master(btlink);
-
- /* We are the slave, we get to clean this burden */
- link = (struct bt_hci_link_s *) btlink;
- g_free(link);
-
-complete:
- bt_hci_lmp_link_teardown(hci, handle);
-
- params.status = HCI_SUCCESS;
- params.handle = HNDL(handle);
- params.reason = HCI_CONNECTION_TERMINATED;
- bt_hci_event(hci, EVT_DISCONN_COMPLETE,
- &params, EVT_DISCONN_COMPLETE_SIZE);
-}
-
-/* TODO: use only one function */
-static void bt_hci_lmp_disconnect_host(struct bt_link_s *link)
-{
- struct bt_hci_s *hci = hci_from_device(link->host);
- uint16_t handle = link->handle;
- evt_disconn_complete params;
-
- bt_hci_lmp_link_teardown(hci, handle);
-
- params.status = HCI_SUCCESS;
- params.handle = HNDL(handle);
- params.reason = hci->device.reject_reason;
- bt_hci_event(hci, EVT_DISCONN_COMPLETE,
- &params, EVT_DISCONN_COMPLETE_SIZE);
-}
-
-static void bt_hci_lmp_disconnect_slave(struct bt_link_s *btlink)
-{
- struct bt_hci_link_s *link = (struct bt_hci_link_s *) btlink;
- struct bt_hci_s *hci = hci_from_device(btlink->slave);
- uint16_t handle = link->handle;
- evt_disconn_complete params;
-
- g_free(link);
-
- bt_hci_lmp_link_teardown(hci, handle);
-
- params.status = HCI_SUCCESS;
- params.handle = HNDL(handle);
- params.reason = hci->device.reject_reason;
- bt_hci_event(hci, EVT_DISCONN_COMPLETE,
- &params, EVT_DISCONN_COMPLETE_SIZE);
-}
-
-static int bt_hci_name_req(struct bt_hci_s *hci, bdaddr_t *bdaddr)
-{
- struct bt_device_s *slave;
- evt_remote_name_req_complete params;
-
- for (slave = hci->device.net->slave; slave; slave = slave->next)
- if (slave->page_scan && !bacmp(&slave->bd_addr, bdaddr))
- break;
- if (!slave)
- return -ENODEV;
-
- bt_hci_event_status(hci, HCI_SUCCESS);
-
- params.status = HCI_SUCCESS;
- bacpy(&params.bdaddr, &slave->bd_addr);
- pstrcpy(params.name, sizeof(params.name), slave->lmp_name ?: "");
- bt_hci_event(hci, EVT_REMOTE_NAME_REQ_COMPLETE,
- &params, EVT_REMOTE_NAME_REQ_COMPLETE_SIZE);
-
- return 0;
-}
-
-static int bt_hci_features_req(struct bt_hci_s *hci, uint16_t handle)
-{
- struct bt_device_s *slave;
- evt_read_remote_features_complete params;
-
- if (bt_hci_handle_bad(hci, handle))
- return -ENODEV;
-
- slave = bt_hci_remote_dev(hci, handle);
-
- bt_hci_event_status(hci, HCI_SUCCESS);
-
- params.status = HCI_SUCCESS;
- params.handle = HNDL(handle);
- params.features[0] = (slave->lmp_caps >> 0) & 0xff;
- params.features[1] = (slave->lmp_caps >> 8) & 0xff;
- params.features[2] = (slave->lmp_caps >> 16) & 0xff;
- params.features[3] = (slave->lmp_caps >> 24) & 0xff;
- params.features[4] = (slave->lmp_caps >> 32) & 0xff;
- params.features[5] = (slave->lmp_caps >> 40) & 0xff;
- params.features[6] = (slave->lmp_caps >> 48) & 0xff;
- params.features[7] = (slave->lmp_caps >> 56) & 0xff;
- bt_hci_event(hci, EVT_READ_REMOTE_FEATURES_COMPLETE,
- &params, EVT_READ_REMOTE_FEATURES_COMPLETE_SIZE);
-
- return 0;
-}
-
-static int bt_hci_version_req(struct bt_hci_s *hci, uint16_t handle)
-{
- evt_read_remote_version_complete params;
-
- if (bt_hci_handle_bad(hci, handle))
- return -ENODEV;
-
- bt_hci_remote_dev(hci, handle);
-
- bt_hci_event_status(hci, HCI_SUCCESS);
-
- params.status = HCI_SUCCESS;
- params.handle = HNDL(handle);
- params.lmp_ver = 0x03;
- params.manufacturer = cpu_to_le16(0xa000);
- params.lmp_subver = cpu_to_le16(0xa607);
- bt_hci_event(hci, EVT_READ_REMOTE_VERSION_COMPLETE,
- &params, EVT_READ_REMOTE_VERSION_COMPLETE_SIZE);
-
- return 0;
-}
-
-static int bt_hci_clkoffset_req(struct bt_hci_s *hci, uint16_t handle)
-{
- struct bt_device_s *slave;
- evt_read_clock_offset_complete params;
-
- if (bt_hci_handle_bad(hci, handle))
- return -ENODEV;
-
- slave = bt_hci_remote_dev(hci, handle);
-
- bt_hci_event_status(hci, HCI_SUCCESS);
-
- params.status = HCI_SUCCESS;
- params.handle = HNDL(handle);
- /* TODO: return the clkoff *differenece* */
- params.clock_offset = slave->clkoff; /* Note: no swapping */
- bt_hci_event(hci, EVT_READ_CLOCK_OFFSET_COMPLETE,
- &params, EVT_READ_CLOCK_OFFSET_COMPLETE_SIZE);
-
- return 0;
-}
-
-static void bt_hci_event_mode(struct bt_hci_s *hci, struct bt_link_s *link,
- uint16_t handle)
-{
- evt_mode_change params = {
- .status = HCI_SUCCESS,
- .handle = HNDL(handle),
- .mode = link->acl_mode,
- .interval = cpu_to_le16(link->acl_interval),
- };
-
- bt_hci_event(hci, EVT_MODE_CHANGE, &params, EVT_MODE_CHANGE_SIZE);
-}
-
-static void bt_hci_lmp_mode_change_master(struct bt_hci_s *hci,
- struct bt_link_s *link, int mode, uint16_t interval)
-{
- link->acl_mode = mode;
- link->acl_interval = interval;
-
- bt_hci_event_mode(hci, link, link->handle);
-
- link->slave->lmp_mode_change(link);
-}
-
-static void bt_hci_lmp_mode_change_slave(struct bt_link_s *btlink)
-{
- struct bt_hci_link_s *link = (struct bt_hci_link_s *) btlink;
- struct bt_hci_s *hci = hci_from_device(btlink->slave);
-
- bt_hci_event_mode(hci, btlink, link->handle);
-}
-
-static int bt_hci_mode_change(struct bt_hci_s *hci, uint16_t handle,
- int interval, int mode)
-{
- struct bt_hci_master_link_s *link;
-
- if (bt_hci_handle_bad(hci, handle) || !bt_hci_role_master(hci, handle))
- return -ENODEV;
-
- link = &hci->lm.handle[handle & ~HCI_HANDLE_OFFSET];
- if (link->link->acl_mode != acl_active) {
- bt_hci_event_status(hci, HCI_COMMAND_DISALLOWED);
- return 0;
- }
-
- bt_hci_event_status(hci, HCI_SUCCESS);
-
- timer_mod(link->acl_mode_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- ((uint64_t)interval * 625) * 1000);
- bt_hci_lmp_mode_change_master(hci, link->link, mode, interval);
-
- return 0;
-}
-
-static int bt_hci_mode_cancel(struct bt_hci_s *hci, uint16_t handle, int mode)
-{
- struct bt_hci_master_link_s *link;
-
- if (bt_hci_handle_bad(hci, handle) || !bt_hci_role_master(hci, handle))
- return -ENODEV;
-
- link = &hci->lm.handle[handle & ~HCI_HANDLE_OFFSET];
- if (link->link->acl_mode != mode) {
- bt_hci_event_status(hci, HCI_COMMAND_DISALLOWED);
-
- return 0;
- }
-
- bt_hci_event_status(hci, HCI_SUCCESS);
-
- timer_del(link->acl_mode_timer);
- bt_hci_lmp_mode_change_master(hci, link->link, acl_active, 0);
-
- return 0;
-}
-
-static void bt_hci_mode_tick(void *opaque)
-{
- struct bt_link_s *link = opaque;
- struct bt_hci_s *hci = hci_from_device(link->host);
-
- bt_hci_lmp_mode_change_master(hci, link, acl_active, 0);
-}
-
-static void bt_hci_reset(struct bt_hci_s *hci)
-{
- hci->acl_len = 0;
- hci->last_cmd = 0;
- hci->lm.connecting = 0;
-
- hci->event_mask[0] = 0xff;
- hci->event_mask[1] = 0xff;
- hci->event_mask[2] = 0xff;
- hci->event_mask[3] = 0xff;
- hci->event_mask[4] = 0xff;
- hci->event_mask[5] = 0x1f;
- hci->event_mask[6] = 0x00;
- hci->event_mask[7] = 0x00;
- hci->device.inquiry_scan = 0;
- hci->device.page_scan = 0;
- g_free((void *) hci->device.lmp_name);
- hci->device.lmp_name = NULL;
- hci->device.class[0] = 0x00;
- hci->device.class[1] = 0x00;
- hci->device.class[2] = 0x00;
- hci->voice_setting = 0x0000;
- hci->conn_accept_tout = 0x1f40;
- hci->lm.inquiry_mode = 0x00;
-
- hci->psb_handle = 0x000;
- hci->asb_handle = 0x000;
-
- /* XXX: timer_del(sl->acl_mode_timer); for all links */
- timer_del(hci->lm.inquiry_done);
- timer_del(hci->lm.inquiry_next);
- timer_del(hci->conn_accept_timer);
-}
-
-static void bt_hci_read_local_version_rp(struct bt_hci_s *hci)
-{
- read_local_version_rp lv = {
- .status = HCI_SUCCESS,
- .hci_ver = 0x03,
- .hci_rev = cpu_to_le16(0xa607),
- .lmp_ver = 0x03,
- .manufacturer = cpu_to_le16(0xa000),
- .lmp_subver = cpu_to_le16(0xa607),
- };
-
- bt_hci_event_complete(hci, &lv, READ_LOCAL_VERSION_RP_SIZE);
-}
-
-static void bt_hci_read_local_commands_rp(struct bt_hci_s *hci)
-{
- read_local_commands_rp lc = {
- .status = HCI_SUCCESS,
- .commands = {
- /* Keep updated! */
- /* Also, keep in sync with hci->device.lmp_caps in bt_new_hci */
- 0xbf, 0x80, 0xf9, 0x03, 0xb2, 0xc0, 0x03, 0xc3,
- 0x00, 0x0f, 0x80, 0x00, 0xc0, 0x00, 0xe8, 0x13,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- },
- };
-
- bt_hci_event_complete(hci, &lc, READ_LOCAL_COMMANDS_RP_SIZE);
-}
-
-static void bt_hci_read_local_features_rp(struct bt_hci_s *hci)
-{
- read_local_features_rp lf = {
- .status = HCI_SUCCESS,
- .features = {
- (hci->device.lmp_caps >> 0) & 0xff,
- (hci->device.lmp_caps >> 8) & 0xff,
- (hci->device.lmp_caps >> 16) & 0xff,
- (hci->device.lmp_caps >> 24) & 0xff,
- (hci->device.lmp_caps >> 32) & 0xff,
- (hci->device.lmp_caps >> 40) & 0xff,
- (hci->device.lmp_caps >> 48) & 0xff,
- (hci->device.lmp_caps >> 56) & 0xff,
- },
- };
-
- bt_hci_event_complete(hci, &lf, READ_LOCAL_FEATURES_RP_SIZE);
-}
-
-static void bt_hci_read_local_ext_features_rp(struct bt_hci_s *hci, int page)
-{
- read_local_ext_features_rp lef = {
- .status = HCI_SUCCESS,
- .page_num = page,
- .max_page_num = 0x00,
- .features = {
- /* Keep updated! */
- 0x5f, 0x35, 0x85, 0x7e, 0x9b, 0x19, 0x00, 0x80,
- },
- };
- if (page)
- memset(lef.features, 0, sizeof(lef.features));
-
- bt_hci_event_complete(hci, &lef, READ_LOCAL_EXT_FEATURES_RP_SIZE);
-}
-
-static void bt_hci_read_buffer_size_rp(struct bt_hci_s *hci)
-{
- read_buffer_size_rp bs = {
- /* This can be made configurable, for one standard USB dongle HCI
- * the four values are cpu_to_le16(0x0180), 0x40,
- * cpu_to_le16(0x0008), cpu_to_le16(0x0008). */
- .status = HCI_SUCCESS,
- .acl_mtu = cpu_to_le16(0x0200),
- .sco_mtu = 0,
- .acl_max_pkt = cpu_to_le16(0x0001),
- .sco_max_pkt = cpu_to_le16(0x0000),
- };
-
- bt_hci_event_complete(hci, &bs, READ_BUFFER_SIZE_RP_SIZE);
-}
-
-/* Deprecated in V2.0 (page 661) */
-static void bt_hci_read_country_code_rp(struct bt_hci_s *hci)
-{
- read_country_code_rp cc ={
- .status = HCI_SUCCESS,
- .country_code = 0x00, /* North America & Europe^1 and Japan */
- };
-
- bt_hci_event_complete(hci, &cc, READ_COUNTRY_CODE_RP_SIZE);
-
- /* ^1. Except France, sorry */
-}
-
-static void bt_hci_read_bd_addr_rp(struct bt_hci_s *hci)
-{
- read_bd_addr_rp ba = {
- .status = HCI_SUCCESS,
- .bdaddr = BAINIT(&hci->device.bd_addr),
- };
-
- bt_hci_event_complete(hci, &ba, READ_BD_ADDR_RP_SIZE);
-}
-
-static int bt_hci_link_quality_rp(struct bt_hci_s *hci, uint16_t handle)
-{
- read_link_quality_rp lq = {
- .status = HCI_SUCCESS,
- .handle = HNDL(handle),
- .link_quality = 0xff,
- };
-
- if (bt_hci_handle_bad(hci, handle))
- lq.status = HCI_NO_CONNECTION;
-
- bt_hci_event_complete(hci, &lq, READ_LINK_QUALITY_RP_SIZE);
- return 0;
-}
-
-/* Generate a Command Complete event with only the Status parameter */
-static inline void bt_hci_event_complete_status(struct bt_hci_s *hci,
- uint8_t status)
-{
- bt_hci_event_complete(hci, &status, 1);
-}
-
-static inline void bt_hci_event_complete_conn_cancel(struct bt_hci_s *hci,
- uint8_t status, bdaddr_t *bd_addr)
-{
- create_conn_cancel_rp params = {
- .status = status,
- .bdaddr = BAINIT(bd_addr),
- };
-
- bt_hci_event_complete(hci, &params, CREATE_CONN_CANCEL_RP_SIZE);
-}
-
-static inline void bt_hci_event_auth_complete(struct bt_hci_s *hci,
- uint16_t handle)
-{
- evt_auth_complete params = {
- .status = HCI_SUCCESS,
- .handle = HNDL(handle),
- };
-
- bt_hci_event(hci, EVT_AUTH_COMPLETE, &params, EVT_AUTH_COMPLETE_SIZE);
-}
-
-static inline void bt_hci_event_encrypt_change(struct bt_hci_s *hci,
- uint16_t handle, uint8_t mode)
-{
- evt_encrypt_change params = {
- .status = HCI_SUCCESS,
- .handle = HNDL(handle),
- .encrypt = mode,
- };
-
- bt_hci_event(hci, EVT_ENCRYPT_CHANGE, &params, EVT_ENCRYPT_CHANGE_SIZE);
-}
-
-static inline void bt_hci_event_complete_name_cancel(struct bt_hci_s *hci,
- bdaddr_t *bd_addr)
-{
- remote_name_req_cancel_rp params = {
- .status = HCI_INVALID_PARAMETERS,
- .bdaddr = BAINIT(bd_addr),
- };
-
- bt_hci_event_complete(hci, &params, REMOTE_NAME_REQ_CANCEL_RP_SIZE);
-}
-
-static inline void bt_hci_event_read_remote_ext_features(struct bt_hci_s *hci,
- uint16_t handle)
-{
- evt_read_remote_ext_features_complete params = {
- .status = HCI_UNSUPPORTED_FEATURE,
- .handle = HNDL(handle),
- /* Rest uninitialised */
- };
-
- bt_hci_event(hci, EVT_READ_REMOTE_EXT_FEATURES_COMPLETE,
- &params, EVT_READ_REMOTE_EXT_FEATURES_COMPLETE_SIZE);
-}
-
-static inline void bt_hci_event_complete_lmp_handle(struct bt_hci_s *hci,
- uint16_t handle)
-{
- read_lmp_handle_rp params = {
- .status = HCI_NO_CONNECTION,
- .handle = HNDL(handle),
- .reserved = 0,
- /* Rest uninitialised */
- };
-
- bt_hci_event_complete(hci, &params, READ_LMP_HANDLE_RP_SIZE);
-}
-
-static inline void bt_hci_event_complete_role_discovery(struct bt_hci_s *hci,
- int status, uint16_t handle, int master)
-{
- role_discovery_rp params = {
- .status = status,
- .handle = HNDL(handle),
- .role = master ? 0x00 : 0x01,
- };
-
- bt_hci_event_complete(hci, &params, ROLE_DISCOVERY_RP_SIZE);
-}
-
-static inline void bt_hci_event_complete_flush(struct bt_hci_s *hci,
- int status, uint16_t handle)
-{
- flush_rp params = {
- .status = status,
- .handle = HNDL(handle),
- };
-
- bt_hci_event_complete(hci, &params, FLUSH_RP_SIZE);
-}
-
-static inline void bt_hci_event_complete_read_local_name(struct bt_hci_s *hci)
-{
- read_local_name_rp params;
- params.status = HCI_SUCCESS;
- memset(params.name, 0, sizeof(params.name));
- if (hci->device.lmp_name)
- pstrcpy(params.name, sizeof(params.name), hci->device.lmp_name);
-
- bt_hci_event_complete(hci, &params, READ_LOCAL_NAME_RP_SIZE);
-}
-
-static inline void bt_hci_event_complete_read_conn_accept_timeout(
- struct bt_hci_s *hci)
-{
- read_conn_accept_timeout_rp params = {
- .status = HCI_SUCCESS,
- .timeout = cpu_to_le16(hci->conn_accept_tout),
- };
-
- bt_hci_event_complete(hci, &params, READ_CONN_ACCEPT_TIMEOUT_RP_SIZE);
-}
-
-static inline void bt_hci_event_complete_read_scan_enable(struct bt_hci_s *hci)
-{
- read_scan_enable_rp params = {
- .status = HCI_SUCCESS,
- .enable =
- (hci->device.inquiry_scan ? SCAN_INQUIRY : 0) |
- (hci->device.page_scan ? SCAN_PAGE : 0),
- };
-
- bt_hci_event_complete(hci, &params, READ_SCAN_ENABLE_RP_SIZE);
-}
-
-static inline void bt_hci_event_complete_read_local_class(struct bt_hci_s *hci)
-{
- read_class_of_dev_rp params;
-
- params.status = HCI_SUCCESS;
- memcpy(params.dev_class, hci->device.class, sizeof(params.dev_class));
-
- bt_hci_event_complete(hci, &params, READ_CLASS_OF_DEV_RP_SIZE);
-}
-
-static inline void bt_hci_event_complete_voice_setting(struct bt_hci_s *hci)
-{
- read_voice_setting_rp params = {
- .status = HCI_SUCCESS,
- .voice_setting = hci->voice_setting, /* Note: no swapping */
- };
-
- bt_hci_event_complete(hci, &params, READ_VOICE_SETTING_RP_SIZE);
-}
-
-static inline void bt_hci_event_complete_read_inquiry_mode(
- struct bt_hci_s *hci)
-{
- read_inquiry_mode_rp params = {
- .status = HCI_SUCCESS,
- .mode = hci->lm.inquiry_mode,
- };
-
- bt_hci_event_complete(hci, &params, READ_INQUIRY_MODE_RP_SIZE);
-}
-
-static inline void bt_hci_event_num_comp_pkts(struct bt_hci_s *hci,
- uint16_t handle, int packets)
-{
- uint16_t buf[EVT_NUM_COMP_PKTS_SIZE(1) / 2 + 1];
- evt_num_comp_pkts *params = (void *) ((uint8_t *) buf + 1);
-
- params->num_hndl = 1;
- params->connection->handle = HNDL(handle);
- params->connection->num_packets = cpu_to_le16(packets);
-
- bt_hci_event(hci, EVT_NUM_COMP_PKTS, params, EVT_NUM_COMP_PKTS_SIZE(1));
-}
-
-static void bt_submit_hci(struct HCIInfo *info,
- const uint8_t *data, int length)
-{
- struct bt_hci_s *hci = hci_from_info(info);
- uint16_t cmd;
- int paramlen, i;
-
- if (length < HCI_COMMAND_HDR_SIZE)
- goto short_hci;
-
- memcpy(&hci->last_cmd, data, 2);
-
- cmd = (data[1] << 8) | data[0];
- paramlen = data[2];
- if (cmd_opcode_ogf(cmd) == 0 || cmd_opcode_ocf(cmd) == 0) /* NOP */
- return;
-
- data += HCI_COMMAND_HDR_SIZE;
- length -= HCI_COMMAND_HDR_SIZE;
-
- if (paramlen > length)
- return;
-
-#define PARAM(cmd, param) (((cmd##_cp *) data)->param)
-#define PARAM16(cmd, param) le16_to_cpup(&PARAM(cmd, param))
-#define PARAMHANDLE(cmd) HNDL(PARAM(cmd, handle))
-#define LENGTH_CHECK(cmd) if (length < sizeof(cmd##_cp)) goto short_hci
- /* Note: the supported commands bitmask in bt_hci_read_local_commands_rp
- * needs to be updated every time a command is implemented here! */
- switch (cmd) {
- case cmd_opcode_pack(OGF_LINK_CTL, OCF_INQUIRY):
- LENGTH_CHECK(inquiry);
-
- if (PARAM(inquiry, length) < 1) {
- bt_hci_event_complete_status(hci, HCI_INVALID_PARAMETERS);
- break;
- }
-
- hci->lm.inquire = 1;
- hci->lm.periodic = 0;
- hci->lm.responses_left = PARAM(inquiry, num_rsp) ?: INT_MAX;
- hci->lm.responses = 0;
- bt_hci_event_status(hci, HCI_SUCCESS);
- bt_hci_inquiry_start(hci, PARAM(inquiry, length));
- break;
-
- case cmd_opcode_pack(OGF_LINK_CTL, OCF_INQUIRY_CANCEL):
- if (!hci->lm.inquire || hci->lm.periodic) {
- fprintf(stderr, "%s: Inquiry Cancel should only be issued after "
- "the Inquiry command has been issued, a Command "
- "Status event has been received for the Inquiry "
- "command, and before the Inquiry Complete event "
- "occurs", __FUNCTION__);
- bt_hci_event_complete_status(hci, HCI_COMMAND_DISALLOWED);
- break;
- }
-
- hci->lm.inquire = 0;
- timer_del(hci->lm.inquiry_done);
- bt_hci_event_complete_status(hci, HCI_SUCCESS);
- break;
-
- case cmd_opcode_pack(OGF_LINK_CTL, OCF_PERIODIC_INQUIRY):
- LENGTH_CHECK(periodic_inquiry);
-
- if (!(PARAM(periodic_inquiry, length) <
- PARAM16(periodic_inquiry, min_period) &&
- PARAM16(periodic_inquiry, min_period) <
- PARAM16(periodic_inquiry, max_period)) ||
- PARAM(periodic_inquiry, length) < 1 ||
- PARAM16(periodic_inquiry, min_period) < 2 ||
- PARAM16(periodic_inquiry, max_period) < 3) {
- bt_hci_event_complete_status(hci, HCI_INVALID_PARAMETERS);
- break;
- }
-
- hci->lm.inquire = 1;
- hci->lm.periodic = 1;
- hci->lm.responses_left = PARAM(periodic_inquiry, num_rsp);
- hci->lm.responses = 0;
- hci->lm.inquiry_period = PARAM16(periodic_inquiry, max_period);
- bt_hci_event_complete_status(hci, HCI_SUCCESS);
- bt_hci_inquiry_start(hci, PARAM(periodic_inquiry, length));
- break;
-
- case cmd_opcode_pack(OGF_LINK_CTL, OCF_EXIT_PERIODIC_INQUIRY):
- if (!hci->lm.inquire || !hci->lm.periodic) {
- fprintf(stderr, "%s: Inquiry Cancel should only be issued after "
- "the Inquiry command has been issued, a Command "
- "Status event has been received for the Inquiry "
- "command, and before the Inquiry Complete event "
- "occurs", __FUNCTION__);
- bt_hci_event_complete_status(hci, HCI_COMMAND_DISALLOWED);
- break;
- }
- hci->lm.inquire = 0;
- timer_del(hci->lm.inquiry_done);
- timer_del(hci->lm.inquiry_next);
- bt_hci_event_complete_status(hci, HCI_SUCCESS);
- break;
-
- case cmd_opcode_pack(OGF_LINK_CTL, OCF_CREATE_CONN):
- LENGTH_CHECK(create_conn);
-
- if (hci->lm.connecting >= HCI_HANDLES_MAX) {
- bt_hci_event_status(hci, HCI_REJECTED_LIMITED_RESOURCES);
- break;
- }
- bt_hci_event_status(hci, HCI_SUCCESS);
-
- if (bt_hci_connect(hci, &PARAM(create_conn, bdaddr)))
- bt_hci_connection_reject_event(hci, &PARAM(create_conn, bdaddr));
- break;
-
- case cmd_opcode_pack(OGF_LINK_CTL, OCF_DISCONNECT):
- LENGTH_CHECK(disconnect);
-
- if (bt_hci_handle_bad(hci, PARAMHANDLE(disconnect))) {
- bt_hci_event_status(hci, HCI_NO_CONNECTION);
- break;
- }
-
- bt_hci_event_status(hci, HCI_SUCCESS);
- bt_hci_disconnect(hci, PARAMHANDLE(disconnect),
- PARAM(disconnect, reason));
- break;
-
- case cmd_opcode_pack(OGF_LINK_CTL, OCF_CREATE_CONN_CANCEL):
- LENGTH_CHECK(create_conn_cancel);
-
- if (bt_hci_lmp_connection_ready(hci,
- &PARAM(create_conn_cancel, bdaddr))) {
- for (i = 0; i < HCI_HANDLES_MAX; i ++)
- if (bt_hci_role_master(hci, i) && hci->lm.handle[i].link &&
- !bacmp(&hci->lm.handle[i].link->slave->bd_addr,
- &PARAM(create_conn_cancel, bdaddr)))
- break;
-
- bt_hci_event_complete_conn_cancel(hci, i < HCI_HANDLES_MAX ?
- HCI_ACL_CONNECTION_EXISTS : HCI_NO_CONNECTION,
- &PARAM(create_conn_cancel, bdaddr));
- } else
- bt_hci_event_complete_conn_cancel(hci, HCI_SUCCESS,
- &PARAM(create_conn_cancel, bdaddr));
- break;
-
- case cmd_opcode_pack(OGF_LINK_CTL, OCF_ACCEPT_CONN_REQ):
- LENGTH_CHECK(accept_conn_req);
-
- if (!hci->conn_req_host ||
- bacmp(&PARAM(accept_conn_req, bdaddr),
- &hci->conn_req_host->bd_addr)) {
- bt_hci_event_status(hci, HCI_INVALID_PARAMETERS);
- break;
- }
-
- bt_hci_event_status(hci, HCI_SUCCESS);
- bt_hci_connection_accept(hci, hci->conn_req_host);
- hci->conn_req_host = NULL;
- break;
-
- case cmd_opcode_pack(OGF_LINK_CTL, OCF_REJECT_CONN_REQ):
- LENGTH_CHECK(reject_conn_req);
-
- if (!hci->conn_req_host ||
- bacmp(&PARAM(reject_conn_req, bdaddr),
- &hci->conn_req_host->bd_addr)) {
- bt_hci_event_status(hci, HCI_INVALID_PARAMETERS);
- break;
- }
-
- bt_hci_event_status(hci, HCI_SUCCESS);
- bt_hci_connection_reject(hci, hci->conn_req_host,
- PARAM(reject_conn_req, reason));
- bt_hci_connection_reject_event(hci, &hci->conn_req_host->bd_addr);
- hci->conn_req_host = NULL;
- break;
-
- case cmd_opcode_pack(OGF_LINK_CTL, OCF_AUTH_REQUESTED):
- LENGTH_CHECK(auth_requested);
-
- if (bt_hci_handle_bad(hci, PARAMHANDLE(auth_requested)))
- bt_hci_event_status(hci, HCI_NO_CONNECTION);
- else {
- bt_hci_event_status(hci, HCI_SUCCESS);
- bt_hci_event_auth_complete(hci, PARAMHANDLE(auth_requested));
- }
- break;
-
- case cmd_opcode_pack(OGF_LINK_CTL, OCF_SET_CONN_ENCRYPT):
- LENGTH_CHECK(set_conn_encrypt);
-
- if (bt_hci_handle_bad(hci, PARAMHANDLE(set_conn_encrypt)))
- bt_hci_event_status(hci, HCI_NO_CONNECTION);
- else {
- bt_hci_event_status(hci, HCI_SUCCESS);
- bt_hci_event_encrypt_change(hci,
- PARAMHANDLE(set_conn_encrypt),
- PARAM(set_conn_encrypt, encrypt));
- }
- break;
-
- case cmd_opcode_pack(OGF_LINK_CTL, OCF_REMOTE_NAME_REQ):
- LENGTH_CHECK(remote_name_req);
-
- if (bt_hci_name_req(hci, &PARAM(remote_name_req, bdaddr)))
- bt_hci_event_status(hci, HCI_NO_CONNECTION);
- break;
-
- case cmd_opcode_pack(OGF_LINK_CTL, OCF_REMOTE_NAME_REQ_CANCEL):
- LENGTH_CHECK(remote_name_req_cancel);
-
- bt_hci_event_complete_name_cancel(hci,
- &PARAM(remote_name_req_cancel, bdaddr));
- break;
-
- case cmd_opcode_pack(OGF_LINK_CTL, OCF_READ_REMOTE_FEATURES):
- LENGTH_CHECK(read_remote_features);
-
- if (bt_hci_features_req(hci, PARAMHANDLE(read_remote_features)))
- bt_hci_event_status(hci, HCI_NO_CONNECTION);
- break;
-
- case cmd_opcode_pack(OGF_LINK_CTL, OCF_READ_REMOTE_EXT_FEATURES):
- LENGTH_CHECK(read_remote_ext_features);
-
- if (bt_hci_handle_bad(hci, PARAMHANDLE(read_remote_ext_features)))
- bt_hci_event_status(hci, HCI_NO_CONNECTION);
- else {
- bt_hci_event_status(hci, HCI_SUCCESS);
- bt_hci_event_read_remote_ext_features(hci,
- PARAMHANDLE(read_remote_ext_features));
- }
- break;
-
- case cmd_opcode_pack(OGF_LINK_CTL, OCF_READ_REMOTE_VERSION):
- LENGTH_CHECK(read_remote_version);
-
- if (bt_hci_version_req(hci, PARAMHANDLE(read_remote_version)))
- bt_hci_event_status(hci, HCI_NO_CONNECTION);
- break;
-
- case cmd_opcode_pack(OGF_LINK_CTL, OCF_READ_CLOCK_OFFSET):
- LENGTH_CHECK(read_clock_offset);
-
- if (bt_hci_clkoffset_req(hci, PARAMHANDLE(read_clock_offset)))
- bt_hci_event_status(hci, HCI_NO_CONNECTION);
- break;
-
- case cmd_opcode_pack(OGF_LINK_CTL, OCF_READ_LMP_HANDLE):
- LENGTH_CHECK(read_lmp_handle);
-
- /* TODO: */
- bt_hci_event_complete_lmp_handle(hci, PARAMHANDLE(read_lmp_handle));
- break;
-
- case cmd_opcode_pack(OGF_LINK_POLICY, OCF_HOLD_MODE):
- LENGTH_CHECK(hold_mode);
-
- if (PARAM16(hold_mode, min_interval) >
- PARAM16(hold_mode, max_interval) ||
- PARAM16(hold_mode, min_interval) < 0x0002 ||
- PARAM16(hold_mode, max_interval) > 0xff00 ||
- (PARAM16(hold_mode, min_interval) & 1) ||
- (PARAM16(hold_mode, max_interval) & 1)) {
- bt_hci_event_status(hci, HCI_INVALID_PARAMETERS);
- break;
- }
-
- if (bt_hci_mode_change(hci, PARAMHANDLE(hold_mode),
- PARAM16(hold_mode, max_interval),
- acl_hold))
- bt_hci_event_status(hci, HCI_NO_CONNECTION);
- break;
-
- case cmd_opcode_pack(OGF_LINK_POLICY, OCF_PARK_MODE):
- LENGTH_CHECK(park_mode);
-
- if (PARAM16(park_mode, min_interval) >
- PARAM16(park_mode, max_interval) ||
- PARAM16(park_mode, min_interval) < 0x000e ||
- (PARAM16(park_mode, min_interval) & 1) ||
- (PARAM16(park_mode, max_interval) & 1)) {
- bt_hci_event_status(hci, HCI_INVALID_PARAMETERS);
- break;
- }
-
- if (bt_hci_mode_change(hci, PARAMHANDLE(park_mode),
- PARAM16(park_mode, max_interval),
- acl_parked))
- bt_hci_event_status(hci, HCI_NO_CONNECTION);
- break;
-
- case cmd_opcode_pack(OGF_LINK_POLICY, OCF_EXIT_PARK_MODE):
- LENGTH_CHECK(exit_park_mode);
-
- if (bt_hci_mode_cancel(hci, PARAMHANDLE(exit_park_mode),
- acl_parked))
- bt_hci_event_status(hci, HCI_NO_CONNECTION);
- break;
-
- case cmd_opcode_pack(OGF_LINK_POLICY, OCF_ROLE_DISCOVERY):
- LENGTH_CHECK(role_discovery);
-
- if (bt_hci_handle_bad(hci, PARAMHANDLE(role_discovery)))
- bt_hci_event_complete_role_discovery(hci,
- HCI_NO_CONNECTION, PARAMHANDLE(role_discovery), 0);
- else
- bt_hci_event_complete_role_discovery(hci,
- HCI_SUCCESS, PARAMHANDLE(role_discovery),
- bt_hci_role_master(hci,
- PARAMHANDLE(role_discovery)));
- break;
-
- case cmd_opcode_pack(OGF_HOST_CTL, OCF_SET_EVENT_MASK):
- LENGTH_CHECK(set_event_mask);
-
- memcpy(hci->event_mask, PARAM(set_event_mask, mask), 8);
- bt_hci_event_complete_status(hci, HCI_SUCCESS);
- break;
-
- case cmd_opcode_pack(OGF_HOST_CTL, OCF_RESET):
- bt_hci_reset(hci);
- bt_hci_event_status(hci, HCI_SUCCESS);
- break;
-
- case cmd_opcode_pack(OGF_HOST_CTL, OCF_SET_EVENT_FLT):
- if (length >= 1 && PARAM(set_event_flt, flt_type) == FLT_CLEAR_ALL)
- /* No length check */;
- else
- LENGTH_CHECK(set_event_flt);
-
- /* Filters are not implemented */
- bt_hci_event_complete_status(hci, HCI_SUCCESS);
- break;
-
- case cmd_opcode_pack(OGF_HOST_CTL, OCF_FLUSH):
- LENGTH_CHECK(flush);
-
- if (bt_hci_handle_bad(hci, PARAMHANDLE(flush)))
- bt_hci_event_complete_flush(hci,
- HCI_NO_CONNECTION, PARAMHANDLE(flush));
- else {
- /* TODO: ordering? */
- bt_hci_event(hci, EVT_FLUSH_OCCURRED,
- &PARAM(flush, handle),
- EVT_FLUSH_OCCURRED_SIZE);
- bt_hci_event_complete_flush(hci,
- HCI_SUCCESS, PARAMHANDLE(flush));
- }
- break;
-
- case cmd_opcode_pack(OGF_HOST_CTL, OCF_CHANGE_LOCAL_NAME):
- LENGTH_CHECK(change_local_name);
-
- g_free((void *) hci->device.lmp_name);
- hci->device.lmp_name = g_strndup(PARAM(change_local_name, name),
- sizeof(PARAM(change_local_name, name)));
- bt_hci_event_complete_status(hci, HCI_SUCCESS);
- break;
-
- case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_LOCAL_NAME):
- bt_hci_event_complete_read_local_name(hci);
- break;
-
- case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_CONN_ACCEPT_TIMEOUT):
- bt_hci_event_complete_read_conn_accept_timeout(hci);
- break;
-
- case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_CONN_ACCEPT_TIMEOUT):
- /* TODO */
- LENGTH_CHECK(write_conn_accept_timeout);
-
- if (PARAM16(write_conn_accept_timeout, timeout) < 0x0001 ||
- PARAM16(write_conn_accept_timeout, timeout) > 0xb540) {
- bt_hci_event_complete_status(hci, HCI_INVALID_PARAMETERS);
- break;
- }
-
- hci->conn_accept_tout = PARAM16(write_conn_accept_timeout, timeout);
- bt_hci_event_complete_status(hci, HCI_SUCCESS);
- break;
-
- case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_SCAN_ENABLE):
- bt_hci_event_complete_read_scan_enable(hci);
- break;
-
- case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE):
- LENGTH_CHECK(write_scan_enable);
-
- /* TODO: check that the remaining bits are all 0 */
- hci->device.inquiry_scan =
- !!(PARAM(write_scan_enable, scan_enable) & SCAN_INQUIRY);
- hci->device.page_scan =
- !!(PARAM(write_scan_enable, scan_enable) & SCAN_PAGE);
- bt_hci_event_complete_status(hci, HCI_SUCCESS);
- break;
-
- case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_CLASS_OF_DEV):
- bt_hci_event_complete_read_local_class(hci);
- break;
-
- case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_CLASS_OF_DEV):
- LENGTH_CHECK(write_class_of_dev);
-
- memcpy(hci->device.class, PARAM(write_class_of_dev, dev_class),
- sizeof(PARAM(write_class_of_dev, dev_class)));
- bt_hci_event_complete_status(hci, HCI_SUCCESS);
- break;
-
- case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_VOICE_SETTING):
- bt_hci_event_complete_voice_setting(hci);
- break;
-
- case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_VOICE_SETTING):
- LENGTH_CHECK(write_voice_setting);
-
- hci->voice_setting = PARAM(write_voice_setting, voice_setting);
- bt_hci_event_complete_status(hci, HCI_SUCCESS);
- break;
-
- case cmd_opcode_pack(OGF_HOST_CTL, OCF_HOST_NUMBER_OF_COMPLETED_PACKETS):
- if (length < data[0] * 2 + 1)
- goto short_hci;
-
- for (i = 0; i < data[0]; i ++)
- if (bt_hci_handle_bad(hci,
- data[i * 2 + 1] | (data[i * 2 + 2] << 8)))
- bt_hci_event_complete_status(hci, HCI_INVALID_PARAMETERS);
- break;
-
- case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_INQUIRY_MODE):
- /* Only if (local_features[3] & 0x40) && (local_commands[12] & 0x40)
- * else
- * goto unknown_command */
- bt_hci_event_complete_read_inquiry_mode(hci);
- break;
-
- case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_INQUIRY_MODE):
- /* Only if (local_features[3] & 0x40) && (local_commands[12] & 0x80)
- * else
- * goto unknown_command */
- LENGTH_CHECK(write_inquiry_mode);
-
- if (PARAM(write_inquiry_mode, mode) > 0x01) {
- bt_hci_event_complete_status(hci, HCI_INVALID_PARAMETERS);
- break;
- }
-
- hci->lm.inquiry_mode = PARAM(write_inquiry_mode, mode);
- bt_hci_event_complete_status(hci, HCI_SUCCESS);
- break;
-
- case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_VERSION):
- bt_hci_read_local_version_rp(hci);
- break;
-
- case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_COMMANDS):
- bt_hci_read_local_commands_rp(hci);
- break;
-
- case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_FEATURES):
- bt_hci_read_local_features_rp(hci);
- break;
-
- case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_EXT_FEATURES):
- LENGTH_CHECK(read_local_ext_features);
-
- bt_hci_read_local_ext_features_rp(hci,
- PARAM(read_local_ext_features, page_num));
- break;
-
- case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_BUFFER_SIZE):
- bt_hci_read_buffer_size_rp(hci);
- break;
-
- case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_COUNTRY_CODE):
- bt_hci_read_country_code_rp(hci);
- break;
-
- case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_BD_ADDR):
- bt_hci_read_bd_addr_rp(hci);
- break;
-
- case cmd_opcode_pack(OGF_STATUS_PARAM, OCF_READ_LINK_QUALITY):
- LENGTH_CHECK(read_link_quality);
-
- bt_hci_link_quality_rp(hci, PARAMHANDLE(read_link_quality));
- break;
-
- default:
- bt_hci_event_status(hci, HCI_UNKNOWN_COMMAND);
- break;
-
- short_hci:
- fprintf(stderr, "%s: HCI packet too short (%iB)\n",
- __FUNCTION__, length);
- bt_hci_event_status(hci, HCI_INVALID_PARAMETERS);
- break;
- }
-}
-
-/* We could perform fragmentation here, we can't do "recombination" because
- * at this layer the length of the payload is not know ahead, so we only
- * know that a packet contained the last fragment of the SDU when the next
- * SDU starts. */
-static inline void bt_hci_lmp_acl_data(struct bt_hci_s *hci, uint16_t handle,
- const uint8_t *data, int start, int len)
-{
- struct hci_acl_hdr *pkt = (void *) hci->acl_buf;
-
- /* TODO: packet flags */
- /* TODO: avoid memcpy'ing */
-
- if (len + HCI_ACL_HDR_SIZE > sizeof(hci->acl_buf)) {
- fprintf(stderr, "%s: can't take ACL packets %i bytes long\n",
- __FUNCTION__, len);
- return;
- }
- memcpy(hci->acl_buf + HCI_ACL_HDR_SIZE, data, len);
-
- pkt->handle = cpu_to_le16(
- acl_handle_pack(handle, start ? ACL_START : ACL_CONT));
- pkt->dlen = cpu_to_le16(len);
- hci->info.acl_recv(hci->info.opaque,
- hci->acl_buf, len + HCI_ACL_HDR_SIZE);
-}
-
-static void bt_hci_lmp_acl_data_slave(struct bt_link_s *btlink,
- const uint8_t *data, int start, int len)
-{
- struct bt_hci_link_s *link = (struct bt_hci_link_s *) btlink;
-
- bt_hci_lmp_acl_data(hci_from_device(btlink->slave),
- link->handle, data, start, len);
-}
-
-static void bt_hci_lmp_acl_data_host(struct bt_link_s *link,
- const uint8_t *data, int start, int len)
-{
- bt_hci_lmp_acl_data(hci_from_device(link->host),
- link->handle, data, start, len);
-}
-
-static void bt_submit_acl(struct HCIInfo *info,
- const uint8_t *data, int length)
-{
- struct bt_hci_s *hci = hci_from_info(info);
- uint16_t handle;
- int datalen, flags;
- struct bt_link_s *link;
-
- if (length < HCI_ACL_HDR_SIZE) {
- fprintf(stderr, "%s: ACL packet too short (%iB)\n",
- __FUNCTION__, length);
- return;
- }
-
- handle = acl_handle((data[1] << 8) | data[0]);
- flags = acl_flags((data[1] << 8) | data[0]);
- datalen = (data[3] << 8) | data[2];
- data += HCI_ACL_HDR_SIZE;
- length -= HCI_ACL_HDR_SIZE;
-
- if (bt_hci_handle_bad(hci, handle)) {
- fprintf(stderr, "%s: invalid ACL handle %03x\n",
- __FUNCTION__, handle);
- /* TODO: signal an error */
- return;
- }
- handle &= ~HCI_HANDLE_OFFSET;
-
- if (datalen > length) {
- fprintf(stderr, "%s: ACL packet too short (%iB < %iB)\n",
- __FUNCTION__, length, datalen);
- return;
- }
-
- link = hci->lm.handle[handle].link;
-
- if ((flags & ~3) == ACL_ACTIVE_BCAST) {
- if (!hci->asb_handle)
- hci->asb_handle = handle;
- else if (handle != hci->asb_handle) {
- fprintf(stderr, "%s: Bad handle %03x in Active Slave Broadcast\n",
- __FUNCTION__, handle);
- /* TODO: signal an error */
- return;
- }
-
- /* TODO */
- }
-
- if ((flags & ~3) == ACL_PICO_BCAST) {
- if (!hci->psb_handle)
- hci->psb_handle = handle;
- else if (handle != hci->psb_handle) {
- fprintf(stderr, "%s: Bad handle %03x in Parked Slave Broadcast\n",
- __FUNCTION__, handle);
- /* TODO: signal an error */
- return;
- }
-
- /* TODO */
- }
-
- /* TODO: increase counter and send EVT_NUM_COMP_PKTS */
- bt_hci_event_num_comp_pkts(hci, handle | HCI_HANDLE_OFFSET, 1);
-
- /* Do this last as it can trigger further events even in this HCI */
- hci->lm.handle[handle].lmp_acl_data(link, data,
- (flags & 3) == ACL_START, length);
-}
-
-static void bt_submit_sco(struct HCIInfo *info,
- const uint8_t *data, int length)
-{
- struct bt_hci_s *hci = hci_from_info(info);
- uint16_t handle;
- int datalen;
-
- if (length < 3)
- return;
-
- handle = acl_handle((data[1] << 8) | data[0]);
- datalen = data[2];
- length -= 3;
-
- if (bt_hci_handle_bad(hci, handle)) {
- fprintf(stderr, "%s: invalid SCO handle %03x\n",
- __FUNCTION__, handle);
- return;
- }
-
- if (datalen > length) {
- fprintf(stderr, "%s: SCO packet too short (%iB < %iB)\n",
- __FUNCTION__, length, datalen);
- return;
- }
-
- /* TODO */
-
- /* TODO: increase counter and send EVT_NUM_COMP_PKTS if synchronous
- * Flow Control is enabled.
- * (See Read/Write_Synchronous_Flow_Control_Enable on page 513 and
- * page 514.) */
-}
-
-static uint8_t *bt_hci_evt_packet(void *opaque)
-{
- /* TODO: allocate a packet from upper layer */
- struct bt_hci_s *s = opaque;
-
- return s->evt_buf;
-}
-
-static void bt_hci_evt_submit(void *opaque, int len)
-{
- /* TODO: notify upper layer */
- struct bt_hci_s *s = opaque;
-
- s->info.evt_recv(s->info.opaque, s->evt_buf, len);
-}
-
-static int bt_hci_bdaddr_set(struct HCIInfo *info, const uint8_t *bd_addr)
-{
- struct bt_hci_s *hci = hci_from_info(info);
-
- bacpy(&hci->device.bd_addr, (const bdaddr_t *) bd_addr);
- return 0;
-}
-
-static void bt_hci_done(struct HCIInfo *info);
-static void bt_hci_destroy(struct bt_device_s *dev)
-{
- struct bt_hci_s *hci = hci_from_device(dev);
-
- bt_hci_done(&hci->info);
-}
-
-struct HCIInfo *bt_new_hci(struct bt_scatternet_s *net)
-{
- struct bt_hci_s *s = g_malloc0(sizeof(struct bt_hci_s));
-
- s->lm.inquiry_done = timer_new_ns(QEMU_CLOCK_VIRTUAL, bt_hci_inquiry_done, s);
- s->lm.inquiry_next = timer_new_ns(QEMU_CLOCK_VIRTUAL, bt_hci_inquiry_next, s);
- s->conn_accept_timer =
- timer_new_ns(QEMU_CLOCK_VIRTUAL, bt_hci_conn_accept_timeout, s);
-
- s->evt_packet = bt_hci_evt_packet;
- s->evt_submit = bt_hci_evt_submit;
- s->opaque = s;
-
- bt_device_init(&s->device, net);
- s->device.lmp_connection_request = bt_hci_lmp_connection_request;
- s->device.lmp_connection_complete = bt_hci_lmp_connection_complete;
- s->device.lmp_disconnect_master = bt_hci_lmp_disconnect_host;
- s->device.lmp_disconnect_slave = bt_hci_lmp_disconnect_slave;
- s->device.lmp_acl_data = bt_hci_lmp_acl_data_slave;
- s->device.lmp_acl_resp = bt_hci_lmp_acl_data_host;
- s->device.lmp_mode_change = bt_hci_lmp_mode_change_slave;
-
- /* Keep updated! */
- /* Also keep in sync with supported commands bitmask in
- * bt_hci_read_local_commands_rp */
- s->device.lmp_caps = 0x8000199b7e85355fll;
-
- bt_hci_reset(s);
-
- s->info.cmd_send = bt_submit_hci;
- s->info.sco_send = bt_submit_sco;
- s->info.acl_send = bt_submit_acl;
- s->info.bdaddr_set = bt_hci_bdaddr_set;
-
- s->device.handle_destroy = bt_hci_destroy;
-
- error_setg(&s->replay_blocker, QERR_REPLAY_NOT_SUPPORTED, "-bt hci");
- replay_add_blocker(s->replay_blocker);
-
- return &s->info;
-}
-
-struct HCIInfo *hci_init(const char *str)
-{
- char *endp;
- struct bt_scatternet_s *vlan = 0;
-
- if (!strcmp(str, "null"))
- /* null */
- return &null_hci;
- else if (!strncmp(str, "host", 4) && (str[4] == '\0' || str[4] == ':'))
- /* host[:hciN] */
- return bt_host_hci(str[4] ? str + 5 : "hci0");
- else if (!strncmp(str, "hci", 3)) {
- /* hci[,vlan=n] */
- if (str[3]) {
- if (!strncmp(str + 3, ",vlan=", 6)) {
- vlan = qemu_find_bt_vlan(strtol(str + 9, &endp, 0));
- if (*endp)
- vlan = 0;
- }
- } else
- vlan = qemu_find_bt_vlan(0);
- if (vlan)
- return bt_new_hci(vlan);
- }
-
- fprintf(stderr, "qemu: Unknown bluetooth HCI `%s'.\n", str);
-
- return 0;
-}
-
-static void bt_hci_done(struct HCIInfo *info)
-{
- struct bt_hci_s *hci = hci_from_info(info);
- int handle;
-
- bt_device_done(&hci->device);
-
- g_free((void *) hci->device.lmp_name);
-
- /* Be gentle and send DISCONNECT to all connected peers and those
- * currently waiting for us to accept or reject a connection request.
- * This frees the links. */
- if (hci->conn_req_host) {
- bt_hci_connection_reject(hci,
- hci->conn_req_host, HCI_OE_POWER_OFF);
- return;
- }
-
- for (handle = HCI_HANDLE_OFFSET;
- handle < (HCI_HANDLE_OFFSET | HCI_HANDLES_MAX); handle ++)
- if (!bt_hci_handle_bad(hci, handle))
- bt_hci_disconnect(hci, handle, HCI_OE_POWER_OFF);
-
- /* TODO: this is not enough actually, there may be slaves from whom
- * we have requested a connection who will soon (or not) respond with
- * an accept or a reject, so we should also check if hci->lm.connecting
- * is non-zero and if so, avoid freeing the hci but otherwise disappear
- * from all qemu social life (e.g. stop scanning and request to be
- * removed from s->device.net) and arrange for
- * s->device.lmp_connection_complete to free the remaining bits once
- * hci->lm.awaiting_bdaddr[] is empty. */
-
- timer_free(hci->lm.inquiry_done);
- timer_free(hci->lm.inquiry_next);
- timer_free(hci->conn_accept_timer);
-
- g_free(hci);
-}
diff --git a/qemu/hw/bt/hid.c b/qemu/hw/bt/hid.c
deleted file mode 100644
index f6affbbb4..000000000
--- a/qemu/hw/bt/hid.c
+++ /dev/null
@@ -1,554 +0,0 @@
-/*
- * QEMU Bluetooth HID Profile wrapper for USB HID.
- *
- * Copyright (C) 2007-2008 OpenMoko, Inc.
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "qemu/timer.h"
-#include "ui/console.h"
-#include "hw/input/hid.h"
-#include "hw/bt.h"
-
-enum hid_transaction_req {
- BT_HANDSHAKE = 0x0,
- BT_HID_CONTROL = 0x1,
- BT_GET_REPORT = 0x4,
- BT_SET_REPORT = 0x5,
- BT_GET_PROTOCOL = 0x6,
- BT_SET_PROTOCOL = 0x7,
- BT_GET_IDLE = 0x8,
- BT_SET_IDLE = 0x9,
- BT_DATA = 0xa,
- BT_DATC = 0xb,
-};
-
-enum hid_transaction_handshake {
- BT_HS_SUCCESSFUL = 0x0,
- BT_HS_NOT_READY = 0x1,
- BT_HS_ERR_INVALID_REPORT_ID = 0x2,
- BT_HS_ERR_UNSUPPORTED_REQUEST = 0x3,
- BT_HS_ERR_INVALID_PARAMETER = 0x4,
- BT_HS_ERR_UNKNOWN = 0xe,
- BT_HS_ERR_FATAL = 0xf,
-};
-
-enum hid_transaction_control {
- BT_HC_NOP = 0x0,
- BT_HC_HARD_RESET = 0x1,
- BT_HC_SOFT_RESET = 0x2,
- BT_HC_SUSPEND = 0x3,
- BT_HC_EXIT_SUSPEND = 0x4,
- BT_HC_VIRTUAL_CABLE_UNPLUG = 0x5,
-};
-
-enum hid_protocol {
- BT_HID_PROTO_BOOT = 0,
- BT_HID_PROTO_REPORT = 1,
-};
-
-enum hid_boot_reportid {
- BT_HID_BOOT_INVALID = 0,
- BT_HID_BOOT_KEYBOARD,
- BT_HID_BOOT_MOUSE,
-};
-
-enum hid_data_pkt {
- BT_DATA_OTHER = 0,
- BT_DATA_INPUT,
- BT_DATA_OUTPUT,
- BT_DATA_FEATURE,
-};
-
-#define BT_HID_MTU 48
-
-/* HID interface requests */
-#define GET_REPORT 0xa101
-#define GET_IDLE 0xa102
-#define GET_PROTOCOL 0xa103
-#define SET_REPORT 0x2109
-#define SET_IDLE 0x210a
-#define SET_PROTOCOL 0x210b
-
-struct bt_hid_device_s {
- struct bt_l2cap_device_s btdev;
- struct bt_l2cap_conn_params_s *control;
- struct bt_l2cap_conn_params_s *interrupt;
- HIDState hid;
-
- int proto;
- int connected;
- int data_type;
- int intr_state;
- struct {
- int len;
- uint8_t buffer[1024];
- } dataother, datain, dataout, feature, intrdataout;
- enum {
- bt_state_ready,
- bt_state_transaction,
- bt_state_suspend,
- } state;
-};
-
-static void bt_hid_reset(struct bt_hid_device_s *s)
-{
- struct bt_scatternet_s *net = s->btdev.device.net;
-
- /* Go as far as... */
- bt_l2cap_device_done(&s->btdev);
- bt_l2cap_device_init(&s->btdev, net);
-
- hid_reset(&s->hid);
- s->proto = BT_HID_PROTO_REPORT;
- s->state = bt_state_ready;
- s->dataother.len = 0;
- s->datain.len = 0;
- s->dataout.len = 0;
- s->feature.len = 0;
- s->intrdataout.len = 0;
- s->intr_state = 0;
-}
-
-static int bt_hid_out(struct bt_hid_device_s *s)
-{
- if (s->data_type == BT_DATA_OUTPUT) {
- /* nothing */
- ;
- }
-
- if (s->data_type == BT_DATA_FEATURE) {
- /* XXX:
- * does this send a USB_REQ_CLEAR_FEATURE/USB_REQ_SET_FEATURE
- * or a SET_REPORT? */
- ;
- }
-
- return -1;
-}
-
-static int bt_hid_in(struct bt_hid_device_s *s)
-{
- s->datain.len = hid_keyboard_poll(&s->hid, s->datain.buffer,
- sizeof(s->datain.buffer));
- return s->datain.len;
-}
-
-static void bt_hid_send_handshake(struct bt_hid_device_s *s, int result)
-{
- *s->control->sdu_out(s->control, 1) =
- (BT_HANDSHAKE << 4) | result;
- s->control->sdu_submit(s->control);
-}
-
-static void bt_hid_send_control(struct bt_hid_device_s *s, int operation)
-{
- *s->control->sdu_out(s->control, 1) =
- (BT_HID_CONTROL << 4) | operation;
- s->control->sdu_submit(s->control);
-}
-
-static void bt_hid_disconnect(struct bt_hid_device_s *s)
-{
- /* Disconnect s->control and s->interrupt */
-}
-
-static void bt_hid_send_data(struct bt_l2cap_conn_params_s *ch, int type,
- const uint8_t *data, int len)
-{
- uint8_t *pkt, hdr = (BT_DATA << 4) | type;
- int plen;
-
- do {
- plen = MIN(len, ch->remote_mtu - 1);
- pkt = ch->sdu_out(ch, plen + 1);
-
- pkt[0] = hdr;
- if (plen)
- memcpy(pkt + 1, data, plen);
- ch->sdu_submit(ch);
-
- len -= plen;
- data += plen;
- hdr = (BT_DATC << 4) | type;
- } while (plen == ch->remote_mtu - 1);
-}
-
-static void bt_hid_control_transaction(struct bt_hid_device_s *s,
- const uint8_t *data, int len)
-{
- uint8_t type, parameter;
- int rlen, ret = -1;
- if (len < 1)
- return;
-
- type = data[0] >> 4;
- parameter = data[0] & 0xf;
-
- switch (type) {
- case BT_HANDSHAKE:
- case BT_DATA:
- switch (parameter) {
- default:
- /* These are not expected to be sent this direction. */
- ret = BT_HS_ERR_INVALID_PARAMETER;
- }
- break;
-
- case BT_HID_CONTROL:
- if (len != 1 || (parameter != BT_HC_VIRTUAL_CABLE_UNPLUG &&
- s->state == bt_state_transaction)) {
- ret = BT_HS_ERR_INVALID_PARAMETER;
- break;
- }
- switch (parameter) {
- case BT_HC_NOP:
- break;
- case BT_HC_HARD_RESET:
- case BT_HC_SOFT_RESET:
- bt_hid_reset(s);
- break;
- case BT_HC_SUSPEND:
- if (s->state == bt_state_ready)
- s->state = bt_state_suspend;
- else
- ret = BT_HS_ERR_INVALID_PARAMETER;
- break;
- case BT_HC_EXIT_SUSPEND:
- if (s->state == bt_state_suspend)
- s->state = bt_state_ready;
- else
- ret = BT_HS_ERR_INVALID_PARAMETER;
- break;
- case BT_HC_VIRTUAL_CABLE_UNPLUG:
- bt_hid_disconnect(s);
- break;
- default:
- ret = BT_HS_ERR_INVALID_PARAMETER;
- }
- break;
-
- case BT_GET_REPORT:
- /* No ReportIDs declared. */
- if (((parameter & 8) && len != 3) ||
- (!(parameter & 8) && len != 1) ||
- s->state != bt_state_ready) {
- ret = BT_HS_ERR_INVALID_PARAMETER;
- break;
- }
- if (parameter & 8)
- rlen = data[2] | (data[3] << 8);
- else
- rlen = INT_MAX;
- switch (parameter & 3) {
- case BT_DATA_OTHER:
- ret = BT_HS_ERR_INVALID_PARAMETER;
- break;
- case BT_DATA_INPUT:
- /* Here we can as well poll s->usbdev */
- bt_hid_send_data(s->control, BT_DATA_INPUT,
- s->datain.buffer, MIN(rlen, s->datain.len));
- break;
- case BT_DATA_OUTPUT:
- bt_hid_send_data(s->control, BT_DATA_OUTPUT,
- s->dataout.buffer, MIN(rlen, s->dataout.len));
- break;
- case BT_DATA_FEATURE:
- bt_hid_send_data(s->control, BT_DATA_FEATURE,
- s->feature.buffer, MIN(rlen, s->feature.len));
- break;
- }
- break;
-
- case BT_SET_REPORT:
- if (len < 2 || len > BT_HID_MTU || s->state != bt_state_ready ||
- (parameter & 3) == BT_DATA_OTHER ||
- (parameter & 3) == BT_DATA_INPUT) {
- ret = BT_HS_ERR_INVALID_PARAMETER;
- break;
- }
- s->data_type = parameter & 3;
- if (s->data_type == BT_DATA_OUTPUT) {
- s->dataout.len = len - 1;
- memcpy(s->dataout.buffer, data + 1, s->dataout.len);
- } else {
- s->feature.len = len - 1;
- memcpy(s->feature.buffer, data + 1, s->feature.len);
- }
- if (len == BT_HID_MTU)
- s->state = bt_state_transaction;
- else
- bt_hid_out(s);
- break;
-
- case BT_GET_PROTOCOL:
- if (len != 1 || s->state == bt_state_transaction) {
- ret = BT_HS_ERR_INVALID_PARAMETER;
- break;
- }
- *s->control->sdu_out(s->control, 1) = s->proto;
- s->control->sdu_submit(s->control);
- break;
-
- case BT_SET_PROTOCOL:
- if (len != 1 || s->state == bt_state_transaction ||
- (parameter != BT_HID_PROTO_BOOT &&
- parameter != BT_HID_PROTO_REPORT)) {
- ret = BT_HS_ERR_INVALID_PARAMETER;
- break;
- }
- s->proto = parameter;
- s->hid.protocol = parameter;
- ret = BT_HS_SUCCESSFUL;
- break;
-
- case BT_GET_IDLE:
- if (len != 1 || s->state == bt_state_transaction) {
- ret = BT_HS_ERR_INVALID_PARAMETER;
- break;
- }
- *s->control->sdu_out(s->control, 1) = s->hid.idle;
- s->control->sdu_submit(s->control);
- break;
-
- case BT_SET_IDLE:
- if (len != 2 || s->state == bt_state_transaction) {
- ret = BT_HS_ERR_INVALID_PARAMETER;
- break;
- }
-
- s->hid.idle = data[1];
- /* XXX: Does this generate a handshake? */
- break;
-
- case BT_DATC:
- if (len > BT_HID_MTU || s->state != bt_state_transaction) {
- ret = BT_HS_ERR_INVALID_PARAMETER;
- break;
- }
- if (s->data_type == BT_DATA_OUTPUT) {
- memcpy(s->dataout.buffer + s->dataout.len, data + 1, len - 1);
- s->dataout.len += len - 1;
- } else {
- memcpy(s->feature.buffer + s->feature.len, data + 1, len - 1);
- s->feature.len += len - 1;
- }
- if (len < BT_HID_MTU) {
- bt_hid_out(s);
- s->state = bt_state_ready;
- }
- break;
-
- default:
- ret = BT_HS_ERR_UNSUPPORTED_REQUEST;
- }
-
- if (ret != -1)
- bt_hid_send_handshake(s, ret);
-}
-
-static void bt_hid_control_sdu(void *opaque, const uint8_t *data, int len)
-{
- struct bt_hid_device_s *hid = opaque;
-
- bt_hid_control_transaction(hid, data, len);
-}
-
-static void bt_hid_datain(HIDState *hs)
-{
- struct bt_hid_device_s *hid =
- container_of(hs, struct bt_hid_device_s, hid);
-
- /* If suspended, wake-up and send a wake-up event first. We might
- * want to also inspect the input report and ignore event like
- * mouse movements until a button event occurs. */
- if (hid->state == bt_state_suspend) {
- hid->state = bt_state_ready;
- }
-
- if (bt_hid_in(hid) > 0)
- /* TODO: when in boot-mode precede any Input reports with the ReportID
- * byte, here and in GetReport/SetReport on the Control channel. */
- bt_hid_send_data(hid->interrupt, BT_DATA_INPUT,
- hid->datain.buffer, hid->datain.len);
-}
-
-static void bt_hid_interrupt_sdu(void *opaque, const uint8_t *data, int len)
-{
- struct bt_hid_device_s *hid = opaque;
-
- if (len > BT_HID_MTU || len < 1)
- goto bad;
- if ((data[0] & 3) != BT_DATA_OUTPUT)
- goto bad;
- if ((data[0] >> 4) == BT_DATA) {
- if (hid->intr_state)
- goto bad;
-
- hid->data_type = BT_DATA_OUTPUT;
- hid->intrdataout.len = 0;
- } else if ((data[0] >> 4) == BT_DATC) {
- if (!hid->intr_state)
- goto bad;
- } else
- goto bad;
-
- memcpy(hid->intrdataout.buffer + hid->intrdataout.len, data + 1, len - 1);
- hid->intrdataout.len += len - 1;
- hid->intr_state = (len == BT_HID_MTU);
- if (!hid->intr_state) {
- memcpy(hid->dataout.buffer, hid->intrdataout.buffer,
- hid->dataout.len = hid->intrdataout.len);
- bt_hid_out(hid);
- }
-
- return;
-bad:
- fprintf(stderr, "%s: bad transaction on Interrupt channel.\n",
- __FUNCTION__);
-}
-
-/* "Virtual cable" plug/unplug event. */
-static void bt_hid_connected_update(struct bt_hid_device_s *hid)
-{
- int prev = hid->connected;
-
- hid->connected = hid->control && hid->interrupt;
-
- /* Stop page-/inquiry-scanning when a host is connected. */
- hid->btdev.device.page_scan = !hid->connected;
- hid->btdev.device.inquiry_scan = !hid->connected;
-
- if (hid->connected && !prev) {
- hid_reset(&hid->hid);
- hid->proto = BT_HID_PROTO_REPORT;
- }
-
- /* Should set HIDVirtualCable in SDP (possibly need to check that SDP
- * isn't destroyed yet, in case we're being called from handle_destroy) */
-}
-
-static void bt_hid_close_control(void *opaque)
-{
- struct bt_hid_device_s *hid = opaque;
-
- hid->control = NULL;
- bt_hid_connected_update(hid);
-}
-
-static void bt_hid_close_interrupt(void *opaque)
-{
- struct bt_hid_device_s *hid = opaque;
-
- hid->interrupt = NULL;
- bt_hid_connected_update(hid);
-}
-
-static int bt_hid_new_control_ch(struct bt_l2cap_device_s *dev,
- struct bt_l2cap_conn_params_s *params)
-{
- struct bt_hid_device_s *hid = (struct bt_hid_device_s *) dev;
-
- if (hid->control)
- return 1;
-
- hid->control = params;
- hid->control->opaque = hid;
- hid->control->close = bt_hid_close_control;
- hid->control->sdu_in = bt_hid_control_sdu;
-
- bt_hid_connected_update(hid);
-
- return 0;
-}
-
-static int bt_hid_new_interrupt_ch(struct bt_l2cap_device_s *dev,
- struct bt_l2cap_conn_params_s *params)
-{
- struct bt_hid_device_s *hid = (struct bt_hid_device_s *) dev;
-
- if (hid->interrupt)
- return 1;
-
- hid->interrupt = params;
- hid->interrupt->opaque = hid;
- hid->interrupt->close = bt_hid_close_interrupt;
- hid->interrupt->sdu_in = bt_hid_interrupt_sdu;
-
- bt_hid_connected_update(hid);
-
- return 0;
-}
-
-static void bt_hid_destroy(struct bt_device_s *dev)
-{
- struct bt_hid_device_s *hid = (struct bt_hid_device_s *) dev;
-
- if (hid->connected)
- bt_hid_send_control(hid, BT_HC_VIRTUAL_CABLE_UNPLUG);
- bt_l2cap_device_done(&hid->btdev);
-
- hid_free(&hid->hid);
-
- g_free(hid);
-}
-
-enum peripheral_minor_class {
- class_other = 0 << 4,
- class_keyboard = 1 << 4,
- class_pointing = 2 << 4,
- class_combo = 3 << 4,
-};
-
-static struct bt_device_s *bt_hid_init(struct bt_scatternet_s *net,
- enum peripheral_minor_class minor)
-{
- struct bt_hid_device_s *s = g_malloc0(sizeof(*s));
- uint32_t class =
- /* Format type */
- (0 << 0) |
- /* Device class */
- (minor << 2) |
- (5 << 8) | /* "Peripheral" */
- /* Service classes */
- (1 << 13) | /* Limited discoverable mode */
- (1 << 19); /* Capturing device (?) */
-
- bt_l2cap_device_init(&s->btdev, net);
- bt_l2cap_sdp_init(&s->btdev);
- bt_l2cap_psm_register(&s->btdev, BT_PSM_HID_CTRL,
- BT_HID_MTU, bt_hid_new_control_ch);
- bt_l2cap_psm_register(&s->btdev, BT_PSM_HID_INTR,
- BT_HID_MTU, bt_hid_new_interrupt_ch);
-
- hid_init(&s->hid, HID_KEYBOARD, bt_hid_datain);
- s->btdev.device.lmp_name = "BT Keyboard";
-
- s->btdev.device.handle_destroy = bt_hid_destroy;
-
- s->btdev.device.class[0] = (class >> 0) & 0xff;
- s->btdev.device.class[1] = (class >> 8) & 0xff;
- s->btdev.device.class[2] = (class >> 16) & 0xff;
-
- return &s->btdev.device;
-}
-
-struct bt_device_s *bt_keyboard_init(struct bt_scatternet_s *net)
-{
- return bt_hid_init(net, class_keyboard);
-}
diff --git a/qemu/hw/bt/l2cap.c b/qemu/hw/bt/l2cap.c
deleted file mode 100644
index 806525194..000000000
--- a/qemu/hw/bt/l2cap.c
+++ /dev/null
@@ -1,1366 +0,0 @@
-/*
- * QEMU Bluetooth L2CAP logic.
- *
- * Copyright (C) 2008 Andrzej Zaborowski <balrog@zabor.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "qemu/timer.h"
-#include "hw/bt.h"
-
-#define L2CAP_CID_MAX 0x100 /* Between 0x40 and 0x10000 */
-
-struct l2cap_instance_s {
- struct bt_link_s *link;
- struct bt_l2cap_device_s *dev;
- int role;
-
- uint8_t frame_in[65535 + L2CAP_HDR_SIZE] __attribute__ ((aligned (4)));
- int frame_in_len;
-
- uint8_t frame_out[65535 + L2CAP_HDR_SIZE] __attribute__ ((aligned (4)));
- int frame_out_len;
-
- /* Signalling channel timers. They exist per-request but we can make
- * sure we have no more than one outstanding request at any time. */
- QEMUTimer *rtx;
- QEMUTimer *ertx;
-
- int last_id;
- int next_id;
-
- struct l2cap_chan_s {
- struct bt_l2cap_conn_params_s params;
-
- void (*frame_in)(struct l2cap_chan_s *chan, uint16_t cid,
- const l2cap_hdr *hdr, int len);
- int mps;
- int min_mtu;
-
- struct l2cap_instance_s *l2cap;
-
- /* Only allocated channels */
- uint16_t remote_cid;
-#define L2CAP_CFG_INIT 2
-#define L2CAP_CFG_ACC 1
- int config_req_id; /* TODO: handle outgoing requests generically */
- int config;
-
- /* Only connection-oriented channels. Note: if we allow the tx and
- * rx traffic to be in different modes at any time, we need two. */
- int mode;
-
- /* Only flow-controlled, connection-oriented channels */
- uint8_t sdu[65536]; /* TODO: dynamically allocate */
- int len_cur, len_total;
- int rexmit;
- int monitor_timeout;
- QEMUTimer *monitor_timer;
- QEMUTimer *retransmission_timer;
- } *cid[L2CAP_CID_MAX];
- /* The channel state machine states map as following:
- * CLOSED -> !cid[N]
- * WAIT_CONNECT -> never occurs
- * WAIT_CONNECT_RSP -> never occurs
- * CONFIG -> cid[N] && config < 3
- * WAIT_CONFIG -> never occurs, cid[N] && config == 0 && !config_r
- * WAIT_SEND_CONFIG -> never occurs, cid[N] && config == 1 && !config_r
- * WAIT_CONFIG_REQ_RSP -> cid[N] && config == 0 && config_req_id
- * WAIT_CONFIG_RSP -> cid[N] && config == 1 && config_req_id
- * WAIT_CONFIG_REQ -> cid[N] && config == 2
- * OPEN -> cid[N] && config == 3
- * WAIT_DISCONNECT -> never occurs
- */
-
- struct l2cap_chan_s signalling_ch;
- struct l2cap_chan_s group_ch;
-};
-
-struct slave_l2cap_instance_s {
- struct bt_link_s link; /* Underlying logical link (ACL) */
- struct l2cap_instance_s l2cap;
-};
-
-struct bt_l2cap_psm_s {
- int psm;
- int min_mtu;
- int (*new_channel)(struct bt_l2cap_device_s *device,
- struct bt_l2cap_conn_params_s *params);
- struct bt_l2cap_psm_s *next;
-};
-
-static const uint16_t l2cap_fcs16_table[256] = {
- 0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
- 0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
- 0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
- 0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
- 0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
- 0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
- 0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
- 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
- 0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
- 0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
- 0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
- 0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
- 0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
- 0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
- 0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
- 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
- 0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
- 0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
- 0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
- 0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
- 0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
- 0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
- 0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
- 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
- 0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
- 0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
- 0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
- 0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
- 0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
- 0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
- 0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
- 0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040,
-};
-
-static uint16_t l2cap_fcs16(const uint8_t *message, int len)
-{
- uint16_t fcs = 0x0000;
-
- while (len --)
-#if 0
- {
- int i;
-
- fcs ^= *message ++;
- for (i = 8; i; -- i)
- if (fcs & 1)
- fcs = (fcs >> 1) ^ 0xa001;
- else
- fcs = (fcs >> 1);
- }
-#else
- fcs = (fcs >> 8) ^ l2cap_fcs16_table[(fcs ^ *message ++) & 0xff];
-#endif
-
- return fcs;
-}
-
-/* L2CAP layer logic (protocol) */
-
-static void l2cap_retransmission_timer_update(struct l2cap_chan_s *ch)
-{
-#if 0
- if (ch->mode != L2CAP_MODE_BASIC && ch->rexmit)
- timer_mod(ch->retransmission_timer);
- else
- timer_del(ch->retransmission_timer);
-#endif
-}
-
-static void l2cap_monitor_timer_update(struct l2cap_chan_s *ch)
-{
-#if 0
- if (ch->mode != L2CAP_MODE_BASIC && !ch->rexmit)
- timer_mod(ch->monitor_timer);
- else
- timer_del(ch->monitor_timer);
-#endif
-}
-
-static void l2cap_command_reject(struct l2cap_instance_s *l2cap, int id,
- uint16_t reason, const void *data, int plen)
-{
- uint8_t *pkt;
- l2cap_cmd_hdr *hdr;
- l2cap_cmd_rej *params;
- uint16_t len;
-
- reason = cpu_to_le16(reason);
- len = cpu_to_le16(L2CAP_CMD_REJ_SIZE + plen);
-
- pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params,
- L2CAP_CMD_HDR_SIZE + L2CAP_CMD_REJ_SIZE + plen);
- hdr = (void *) (pkt + 0);
- params = (void *) (pkt + L2CAP_CMD_HDR_SIZE);
-
- hdr->code = L2CAP_COMMAND_REJ;
- hdr->ident = id;
- memcpy(&hdr->len, &len, sizeof(hdr->len));
- memcpy(&params->reason, &reason, sizeof(reason));
- if (plen)
- memcpy(pkt + L2CAP_CMD_HDR_SIZE + L2CAP_CMD_REJ_SIZE, data, plen);
-
- l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params);
-}
-
-static void l2cap_command_reject_cid(struct l2cap_instance_s *l2cap, int id,
- uint16_t reason, uint16_t dcid, uint16_t scid)
-{
- l2cap_cmd_rej_cid params = {
- .dcid = dcid,
- .scid = scid,
- };
-
- l2cap_command_reject(l2cap, id, reason, &params, L2CAP_CMD_REJ_CID_SIZE);
-}
-
-static void l2cap_connection_response(struct l2cap_instance_s *l2cap,
- int dcid, int scid, int result, int status)
-{
- uint8_t *pkt;
- l2cap_cmd_hdr *hdr;
- l2cap_conn_rsp *params;
-
- pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params,
- L2CAP_CMD_HDR_SIZE + L2CAP_CONN_RSP_SIZE);
- hdr = (void *) (pkt + 0);
- params = (void *) (pkt + L2CAP_CMD_HDR_SIZE);
-
- hdr->code = L2CAP_CONN_RSP;
- hdr->ident = l2cap->last_id;
- hdr->len = cpu_to_le16(L2CAP_CONN_RSP_SIZE);
-
- params->dcid = cpu_to_le16(dcid);
- params->scid = cpu_to_le16(scid);
- params->result = cpu_to_le16(result);
- params->status = cpu_to_le16(status);
-
- l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params);
-}
-
-static void l2cap_configuration_request(struct l2cap_instance_s *l2cap,
- int dcid, int flag, const uint8_t *data, int len)
-{
- uint8_t *pkt;
- l2cap_cmd_hdr *hdr;
- l2cap_conf_req *params;
-
- pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params,
- L2CAP_CMD_HDR_SIZE + L2CAP_CONF_REQ_SIZE(len));
- hdr = (void *) (pkt + 0);
- params = (void *) (pkt + L2CAP_CMD_HDR_SIZE);
-
- /* TODO: unify the id sequencing */
- l2cap->last_id = l2cap->next_id;
- l2cap->next_id = l2cap->next_id == 255 ? 1 : l2cap->next_id + 1;
-
- hdr->code = L2CAP_CONF_REQ;
- hdr->ident = l2cap->last_id;
- hdr->len = cpu_to_le16(L2CAP_CONF_REQ_SIZE(len));
-
- params->dcid = cpu_to_le16(dcid);
- params->flags = cpu_to_le16(flag);
- if (len)
- memcpy(params->data, data, len);
-
- l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params);
-}
-
-static void l2cap_configuration_response(struct l2cap_instance_s *l2cap,
- int scid, int flag, int result, const uint8_t *data, int len)
-{
- uint8_t *pkt;
- l2cap_cmd_hdr *hdr;
- l2cap_conf_rsp *params;
-
- pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params,
- L2CAP_CMD_HDR_SIZE + L2CAP_CONF_RSP_SIZE(len));
- hdr = (void *) (pkt + 0);
- params = (void *) (pkt + L2CAP_CMD_HDR_SIZE);
-
- hdr->code = L2CAP_CONF_RSP;
- hdr->ident = l2cap->last_id;
- hdr->len = cpu_to_le16(L2CAP_CONF_RSP_SIZE(len));
-
- params->scid = cpu_to_le16(scid);
- params->flags = cpu_to_le16(flag);
- params->result = cpu_to_le16(result);
- if (len)
- memcpy(params->data, data, len);
-
- l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params);
-}
-
-static void l2cap_disconnection_response(struct l2cap_instance_s *l2cap,
- int dcid, int scid)
-{
- uint8_t *pkt;
- l2cap_cmd_hdr *hdr;
- l2cap_disconn_rsp *params;
-
- pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params,
- L2CAP_CMD_HDR_SIZE + L2CAP_DISCONN_RSP_SIZE);
- hdr = (void *) (pkt + 0);
- params = (void *) (pkt + L2CAP_CMD_HDR_SIZE);
-
- hdr->code = L2CAP_DISCONN_RSP;
- hdr->ident = l2cap->last_id;
- hdr->len = cpu_to_le16(L2CAP_DISCONN_RSP_SIZE);
-
- params->dcid = cpu_to_le16(dcid);
- params->scid = cpu_to_le16(scid);
-
- l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params);
-}
-
-static void l2cap_echo_response(struct l2cap_instance_s *l2cap,
- const uint8_t *data, int len)
-{
- uint8_t *pkt;
- l2cap_cmd_hdr *hdr;
- uint8_t *params;
-
- pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params,
- L2CAP_CMD_HDR_SIZE + len);
- hdr = (void *) (pkt + 0);
- params = (void *) (pkt + L2CAP_CMD_HDR_SIZE);
-
- hdr->code = L2CAP_ECHO_RSP;
- hdr->ident = l2cap->last_id;
- hdr->len = cpu_to_le16(len);
-
- memcpy(params, data, len);
-
- l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params);
-}
-
-static void l2cap_info_response(struct l2cap_instance_s *l2cap, int type,
- int result, const uint8_t *data, int len)
-{
- uint8_t *pkt;
- l2cap_cmd_hdr *hdr;
- l2cap_info_rsp *params;
-
- pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params,
- L2CAP_CMD_HDR_SIZE + L2CAP_INFO_RSP_SIZE + len);
- hdr = (void *) (pkt + 0);
- params = (void *) (pkt + L2CAP_CMD_HDR_SIZE);
-
- hdr->code = L2CAP_INFO_RSP;
- hdr->ident = l2cap->last_id;
- hdr->len = cpu_to_le16(L2CAP_INFO_RSP_SIZE + len);
-
- params->type = cpu_to_le16(type);
- params->result = cpu_to_le16(result);
- if (len)
- memcpy(params->data, data, len);
-
- l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params);
-}
-
-static uint8_t *l2cap_bframe_out(struct bt_l2cap_conn_params_s *parm, int len);
-static void l2cap_bframe_submit(struct bt_l2cap_conn_params_s *parms);
-#if 0
-static uint8_t *l2cap_iframe_out(struct bt_l2cap_conn_params_s *parm, int len);
-static void l2cap_iframe_submit(struct bt_l2cap_conn_params_s *parm);
-#endif
-static void l2cap_bframe_in(struct l2cap_chan_s *ch, uint16_t cid,
- const l2cap_hdr *hdr, int len);
-static void l2cap_iframe_in(struct l2cap_chan_s *ch, uint16_t cid,
- const l2cap_hdr *hdr, int len);
-
-static int l2cap_cid_new(struct l2cap_instance_s *l2cap)
-{
- int i;
-
- for (i = L2CAP_CID_ALLOC; i < L2CAP_CID_MAX; i ++)
- if (!l2cap->cid[i])
- return i;
-
- return L2CAP_CID_INVALID;
-}
-
-static inline struct bt_l2cap_psm_s *l2cap_psm(
- struct bt_l2cap_device_s *device, int psm)
-{
- struct bt_l2cap_psm_s *ret = device->first_psm;
-
- while (ret && ret->psm != psm)
- ret = ret->next;
-
- return ret;
-}
-
-static struct l2cap_chan_s *l2cap_channel_open(struct l2cap_instance_s *l2cap,
- int psm, int source_cid)
-{
- struct l2cap_chan_s *ch = NULL;
- struct bt_l2cap_psm_s *psm_info;
- int result, status;
- int cid = l2cap_cid_new(l2cap);
-
- if (cid) {
- /* See what the channel is to be used for.. */
- psm_info = l2cap_psm(l2cap->dev, psm);
-
- if (psm_info) {
- /* Device supports this use-case. */
- ch = g_malloc0(sizeof(*ch));
- ch->params.sdu_out = l2cap_bframe_out;
- ch->params.sdu_submit = l2cap_bframe_submit;
- ch->frame_in = l2cap_bframe_in;
- ch->mps = 65536;
- ch->min_mtu = MAX(48, psm_info->min_mtu);
- ch->params.remote_mtu = MAX(672, ch->min_mtu);
- ch->remote_cid = source_cid;
- ch->mode = L2CAP_MODE_BASIC;
- ch->l2cap = l2cap;
-
- /* Does it feel like opening yet another channel though? */
- if (!psm_info->new_channel(l2cap->dev, &ch->params)) {
- l2cap->cid[cid] = ch;
-
- result = L2CAP_CR_SUCCESS;
- status = L2CAP_CS_NO_INFO;
- } else {
- g_free(ch);
- ch = NULL;
- result = L2CAP_CR_NO_MEM;
- status = L2CAP_CS_NO_INFO;
- }
- } else {
- result = L2CAP_CR_BAD_PSM;
- status = L2CAP_CS_NO_INFO;
- }
- } else {
- result = L2CAP_CR_NO_MEM;
- status = L2CAP_CS_NO_INFO;
- }
-
- l2cap_connection_response(l2cap, cid, source_cid, result, status);
-
- return ch;
-}
-
-static void l2cap_channel_close(struct l2cap_instance_s *l2cap,
- int cid, int source_cid)
-{
- struct l2cap_chan_s *ch = NULL;
-
- /* According to Volume 3, section 6.1.1, pg 1048 of BT Core V2.0, a
- * connection in CLOSED state still responds with a L2CAP_DisconnectRsp
- * message on an L2CAP_DisconnectReq event. */
- if (unlikely(cid < L2CAP_CID_ALLOC)) {
- l2cap_command_reject_cid(l2cap, l2cap->last_id, L2CAP_REJ_CID_INVAL,
- cid, source_cid);
- return;
- }
- if (likely(cid >= L2CAP_CID_ALLOC && cid < L2CAP_CID_MAX))
- ch = l2cap->cid[cid];
-
- if (likely(ch)) {
- if (ch->remote_cid != source_cid) {
- fprintf(stderr, "%s: Ignoring a Disconnection Request with the "
- "invalid SCID %04x.\n", __FUNCTION__, source_cid);
- return;
- }
-
- l2cap->cid[cid] = NULL;
-
- ch->params.close(ch->params.opaque);
- g_free(ch);
- }
-
- l2cap_disconnection_response(l2cap, cid, source_cid);
-}
-
-static void l2cap_channel_config_null(struct l2cap_instance_s *l2cap,
- struct l2cap_chan_s *ch)
-{
- l2cap_configuration_request(l2cap, ch->remote_cid, 0, NULL, 0);
- ch->config_req_id = l2cap->last_id;
- ch->config &= ~L2CAP_CFG_INIT;
-}
-
-static void l2cap_channel_config_req_event(struct l2cap_instance_s *l2cap,
- struct l2cap_chan_s *ch)
-{
- /* Use all default channel options and terminate negotiation. */
- l2cap_channel_config_null(l2cap, ch);
-}
-
-static int l2cap_channel_config(struct l2cap_instance_s *l2cap,
- struct l2cap_chan_s *ch, int flag,
- const uint8_t *data, int len)
-{
- l2cap_conf_opt *opt;
- l2cap_conf_opt_qos *qos;
- uint32_t val;
- uint8_t rsp[len];
- int result = L2CAP_CONF_SUCCESS;
-
- data = memcpy(rsp, data, len);
- while (len) {
- opt = (void *) data;
-
- if (len < L2CAP_CONF_OPT_SIZE ||
- len < L2CAP_CONF_OPT_SIZE + opt->len) {
- result = L2CAP_CONF_REJECT;
- break;
- }
- data += L2CAP_CONF_OPT_SIZE + opt->len;
- len -= L2CAP_CONF_OPT_SIZE + opt->len;
-
- switch (opt->type & 0x7f) {
- case L2CAP_CONF_MTU:
- if (opt->len != 2) {
- result = L2CAP_CONF_REJECT;
- break;
- }
-
- /* MTU */
- val = le16_to_cpup((void *) opt->val);
- if (val < ch->min_mtu) {
- cpu_to_le16w((void *) opt->val, ch->min_mtu);
- result = L2CAP_CONF_UNACCEPT;
- break;
- }
-
- ch->params.remote_mtu = val;
- break;
-
- case L2CAP_CONF_FLUSH_TO:
- if (opt->len != 2) {
- result = L2CAP_CONF_REJECT;
- break;
- }
-
- /* Flush Timeout */
- val = le16_to_cpup((void *) opt->val);
- if (val < 0x0001) {
- opt->val[0] = 0xff;
- opt->val[1] = 0xff;
- result = L2CAP_CONF_UNACCEPT;
- break;
- }
- break;
-
- case L2CAP_CONF_QOS:
- if (opt->len != L2CAP_CONF_OPT_QOS_SIZE) {
- result = L2CAP_CONF_REJECT;
- break;
- }
- qos = (void *) opt->val;
-
- /* Flags */
- val = qos->flags;
- if (val) {
- qos->flags = 0;
- result = L2CAP_CONF_UNACCEPT;
- }
-
- /* Service type */
- val = qos->service_type;
- if (val != L2CAP_CONF_QOS_BEST_EFFORT &&
- val != L2CAP_CONF_QOS_NO_TRAFFIC) {
- qos->service_type = L2CAP_CONF_QOS_BEST_EFFORT;
- result = L2CAP_CONF_UNACCEPT;
- }
-
- if (val != L2CAP_CONF_QOS_NO_TRAFFIC) {
- /* XXX: These values should possibly be calculated
- * based on LM / baseband properties also. */
-
- /* Token rate */
- val = le32_to_cpu(qos->token_rate);
- if (val == L2CAP_CONF_QOS_WILDCARD)
- qos->token_rate = cpu_to_le32(0x100000);
-
- /* Token bucket size */
- val = le32_to_cpu(qos->token_bucket_size);
- if (val == L2CAP_CONF_QOS_WILDCARD)
- qos->token_bucket_size = cpu_to_le32(65500);
-
- /* Any Peak bandwidth value is correct to return as-is */
- /* Any Access latency value is correct to return as-is */
- /* Any Delay variation value is correct to return as-is */
- }
- break;
-
- case L2CAP_CONF_RFC:
- if (opt->len != 9) {
- result = L2CAP_CONF_REJECT;
- break;
- }
-
- /* Mode */
- val = opt->val[0];
- switch (val) {
- case L2CAP_MODE_BASIC:
- ch->mode = val;
- ch->frame_in = l2cap_bframe_in;
-
- /* All other parameters shall be ignored */
- break;
-
- case L2CAP_MODE_RETRANS:
- case L2CAP_MODE_FLOWCTL:
- ch->mode = val;
- ch->frame_in = l2cap_iframe_in;
- /* Note: most of these parameters refer to incoming traffic
- * so we don't need to save them as long as we can accept
- * incoming PDUs at any values of the parameters. */
-
- /* TxWindow size */
- val = opt->val[1];
- if (val < 1 || val > 32) {
- opt->val[1] = 32;
- result = L2CAP_CONF_UNACCEPT;
- break;
- }
-
- /* MaxTransmit */
- val = opt->val[2];
- if (val < 1) {
- opt->val[2] = 1;
- result = L2CAP_CONF_UNACCEPT;
- break;
- }
-
- /* Remote Retransmission time-out shouldn't affect local
- * operation (?) */
-
- /* The Monitor time-out drives the local Monitor timer (?),
- * so save the value. */
- val = (opt->val[6] << 8) | opt->val[5];
- if (val < 30) {
- opt->val[5] = 100 & 0xff;
- opt->val[6] = 100 >> 8;
- result = L2CAP_CONF_UNACCEPT;
- break;
- }
- ch->monitor_timeout = val;
- l2cap_monitor_timer_update(ch);
-
- /* MPS */
- val = (opt->val[8] << 8) | opt->val[7];
- if (val < ch->min_mtu) {
- opt->val[7] = ch->min_mtu & 0xff;
- opt->val[8] = ch->min_mtu >> 8;
- result = L2CAP_CONF_UNACCEPT;
- break;
- }
- ch->mps = val;
- break;
-
- default:
- result = L2CAP_CONF_UNACCEPT;
- break;
- }
- break;
-
- default:
- if (!(opt->type >> 7))
- result = L2CAP_CONF_UNKNOWN;
- break;
- }
-
- if (result != L2CAP_CONF_SUCCESS)
- break; /* XXX: should continue? */
- }
-
- l2cap_configuration_response(l2cap, ch->remote_cid,
- flag, result, rsp, len);
-
- return result == L2CAP_CONF_SUCCESS && !flag;
-}
-
-static void l2cap_channel_config_req_msg(struct l2cap_instance_s *l2cap,
- int flag, int cid, const uint8_t *data, int len)
-{
- struct l2cap_chan_s *ch;
-
- if (unlikely(cid >= L2CAP_CID_MAX || !l2cap->cid[cid])) {
- l2cap_command_reject_cid(l2cap, l2cap->last_id, L2CAP_REJ_CID_INVAL,
- cid, 0x0000);
- return;
- }
- ch = l2cap->cid[cid];
-
- /* From OPEN go to WAIT_CONFIG_REQ and from WAIT_CONFIG_REQ_RSP to
- * WAIT_CONFIG_REQ_RSP. This is assuming the transition chart for OPEN
- * on pg 1053, section 6.1.5, volume 3 of BT Core V2.0 has a mistake
- * and on options-acceptable we go back to OPEN and otherwise to
- * WAIT_CONFIG_REQ and not the other way. */
- ch->config &= ~L2CAP_CFG_ACC;
-
- if (l2cap_channel_config(l2cap, ch, flag, data, len))
- /* Go to OPEN or WAIT_CONFIG_RSP */
- ch->config |= L2CAP_CFG_ACC;
-
- /* TODO: if the incoming traffic flow control or retransmission mode
- * changed then we probably need to also generate the
- * ConfigureChannel_Req event and set the outgoing traffic to the same
- * mode. */
- if (!(ch->config & L2CAP_CFG_INIT) && (ch->config & L2CAP_CFG_ACC) &&
- !ch->config_req_id)
- l2cap_channel_config_req_event(l2cap, ch);
-}
-
-static int l2cap_channel_config_rsp_msg(struct l2cap_instance_s *l2cap,
- int result, int flag, int cid, const uint8_t *data, int len)
-{
- struct l2cap_chan_s *ch;
-
- if (unlikely(cid >= L2CAP_CID_MAX || !l2cap->cid[cid])) {
- l2cap_command_reject_cid(l2cap, l2cap->last_id, L2CAP_REJ_CID_INVAL,
- cid, 0x0000);
- return 0;
- }
- ch = l2cap->cid[cid];
-
- if (ch->config_req_id != l2cap->last_id)
- return 1;
- ch->config_req_id = 0;
-
- if (result == L2CAP_CONF_SUCCESS) {
- if (!flag)
- ch->config |= L2CAP_CFG_INIT;
- else
- l2cap_channel_config_null(l2cap, ch);
- } else
- /* Retry until we succeed */
- l2cap_channel_config_req_event(l2cap, ch);
-
- return 0;
-}
-
-static void l2cap_channel_open_req_msg(struct l2cap_instance_s *l2cap,
- int psm, int source_cid)
-{
- struct l2cap_chan_s *ch = l2cap_channel_open(l2cap, psm, source_cid);
-
- if (!ch)
- return;
-
- /* Optional */
- if (!(ch->config & L2CAP_CFG_INIT) && !ch->config_req_id)
- l2cap_channel_config_req_event(l2cap, ch);
-}
-
-static void l2cap_info(struct l2cap_instance_s *l2cap, int type)
-{
- uint8_t data[4];
- int len = 0;
- int result = L2CAP_IR_SUCCESS;
-
- switch (type) {
- case L2CAP_IT_CL_MTU:
- data[len ++] = l2cap->group_ch.mps & 0xff;
- data[len ++] = l2cap->group_ch.mps >> 8;
- break;
-
- case L2CAP_IT_FEAT_MASK:
- /* (Prematurely) report Flow control and Retransmission modes. */
- data[len ++] = 0x03;
- data[len ++] = 0x00;
- data[len ++] = 0x00;
- data[len ++] = 0x00;
- break;
-
- default:
- result = L2CAP_IR_NOTSUPP;
- }
-
- l2cap_info_response(l2cap, type, result, data, len);
-}
-
-static void l2cap_command(struct l2cap_instance_s *l2cap, int code, int id,
- const uint8_t *params, int len)
-{
- int err;
-
-#if 0
- /* TODO: do the IDs really have to be in sequence? */
- if (!id || (id != l2cap->last_id && id != l2cap->next_id)) {
- fprintf(stderr, "%s: out of sequence command packet ignored.\n",
- __FUNCTION__);
- return;
- }
-#else
- l2cap->next_id = id;
-#endif
- if (id == l2cap->next_id) {
- l2cap->last_id = l2cap->next_id;
- l2cap->next_id = l2cap->next_id == 255 ? 1 : l2cap->next_id + 1;
- } else {
- /* TODO: Need to re-send the same response, without re-executing
- * the corresponding command! */
- }
-
- switch (code) {
- case L2CAP_COMMAND_REJ:
- if (unlikely(len != 2 && len != 4 && len != 6)) {
- err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
- goto reject;
- }
-
- /* We never issue commands other than Command Reject currently. */
- fprintf(stderr, "%s: stray Command Reject (%02x, %04x) "
- "packet, ignoring.\n", __FUNCTION__, id,
- le16_to_cpu(((l2cap_cmd_rej *) params)->reason));
- break;
-
- case L2CAP_CONN_REQ:
- if (unlikely(len != L2CAP_CONN_REQ_SIZE)) {
- err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
- goto reject;
- }
-
- l2cap_channel_open_req_msg(l2cap,
- le16_to_cpu(((l2cap_conn_req *) params)->psm),
- le16_to_cpu(((l2cap_conn_req *) params)->scid));
- break;
-
- case L2CAP_CONN_RSP:
- if (unlikely(len != L2CAP_CONN_RSP_SIZE)) {
- err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
- goto reject;
- }
-
- /* We never issue Connection Requests currently. TODO */
- fprintf(stderr, "%s: unexpected Connection Response (%02x) "
- "packet, ignoring.\n", __FUNCTION__, id);
- break;
-
- case L2CAP_CONF_REQ:
- if (unlikely(len < L2CAP_CONF_REQ_SIZE(0))) {
- err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
- goto reject;
- }
-
- l2cap_channel_config_req_msg(l2cap,
- le16_to_cpu(((l2cap_conf_req *) params)->flags) & 1,
- le16_to_cpu(((l2cap_conf_req *) params)->dcid),
- ((l2cap_conf_req *) params)->data,
- len - L2CAP_CONF_REQ_SIZE(0));
- break;
-
- case L2CAP_CONF_RSP:
- if (unlikely(len < L2CAP_CONF_RSP_SIZE(0))) {
- err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
- goto reject;
- }
-
- if (l2cap_channel_config_rsp_msg(l2cap,
- le16_to_cpu(((l2cap_conf_rsp *) params)->result),
- le16_to_cpu(((l2cap_conf_rsp *) params)->flags) & 1,
- le16_to_cpu(((l2cap_conf_rsp *) params)->scid),
- ((l2cap_conf_rsp *) params)->data,
- len - L2CAP_CONF_RSP_SIZE(0)))
- fprintf(stderr, "%s: unexpected Configure Response (%02x) "
- "packet, ignoring.\n", __FUNCTION__, id);
- break;
-
- case L2CAP_DISCONN_REQ:
- if (unlikely(len != L2CAP_DISCONN_REQ_SIZE)) {
- err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
- goto reject;
- }
-
- l2cap_channel_close(l2cap,
- le16_to_cpu(((l2cap_disconn_req *) params)->dcid),
- le16_to_cpu(((l2cap_disconn_req *) params)->scid));
- break;
-
- case L2CAP_DISCONN_RSP:
- if (unlikely(len != L2CAP_DISCONN_RSP_SIZE)) {
- err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
- goto reject;
- }
-
- /* We never issue Disconnection Requests currently. TODO */
- fprintf(stderr, "%s: unexpected Disconnection Response (%02x) "
- "packet, ignoring.\n", __FUNCTION__, id);
- break;
-
- case L2CAP_ECHO_REQ:
- l2cap_echo_response(l2cap, params, len);
- break;
-
- case L2CAP_ECHO_RSP:
- /* We never issue Echo Requests currently. TODO */
- fprintf(stderr, "%s: unexpected Echo Response (%02x) "
- "packet, ignoring.\n", __FUNCTION__, id);
- break;
-
- case L2CAP_INFO_REQ:
- if (unlikely(len != L2CAP_INFO_REQ_SIZE)) {
- err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
- goto reject;
- }
-
- l2cap_info(l2cap, le16_to_cpu(((l2cap_info_req *) params)->type));
- break;
-
- case L2CAP_INFO_RSP:
- if (unlikely(len != L2CAP_INFO_RSP_SIZE)) {
- err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
- goto reject;
- }
-
- /* We never issue Information Requests currently. TODO */
- fprintf(stderr, "%s: unexpected Information Response (%02x) "
- "packet, ignoring.\n", __FUNCTION__, id);
- break;
-
- default:
- err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
- reject:
- l2cap_command_reject(l2cap, id, err, 0, 0);
- break;
- }
-}
-
-static void l2cap_rexmit_enable(struct l2cap_chan_s *ch, int enable)
-{
- ch->rexmit = enable;
-
- l2cap_retransmission_timer_update(ch);
- l2cap_monitor_timer_update(ch);
-}
-
-/* Command frame SDU */
-static void l2cap_cframe_in(void *opaque, const uint8_t *data, int len)
-{
- struct l2cap_instance_s *l2cap = opaque;
- const l2cap_cmd_hdr *hdr;
- int clen;
-
- while (len) {
- hdr = (void *) data;
- if (len < L2CAP_CMD_HDR_SIZE)
- /* TODO: signal an error */
- return;
- len -= L2CAP_CMD_HDR_SIZE;
- data += L2CAP_CMD_HDR_SIZE;
-
- clen = le16_to_cpu(hdr->len);
- if (len < clen) {
- l2cap_command_reject(l2cap, hdr->ident,
- L2CAP_REJ_CMD_NOT_UNDERSTOOD, 0, 0);
- break;
- }
-
- l2cap_command(l2cap, hdr->code, hdr->ident, data, clen);
- len -= clen;
- data += clen;
- }
-}
-
-/* Group frame SDU */
-static void l2cap_gframe_in(void *opaque, const uint8_t *data, int len)
-{
-}
-
-/* Supervisory frame */
-static void l2cap_sframe_in(struct l2cap_chan_s *ch, uint16_t ctrl)
-{
-}
-
-/* Basic L2CAP mode Information frame */
-static void l2cap_bframe_in(struct l2cap_chan_s *ch, uint16_t cid,
- const l2cap_hdr *hdr, int len)
-{
- /* We have a full SDU, no further processing */
- ch->params.sdu_in(ch->params.opaque, hdr->data, len);
-}
-
-/* Flow Control and Retransmission mode frame */
-static void l2cap_iframe_in(struct l2cap_chan_s *ch, uint16_t cid,
- const l2cap_hdr *hdr, int len)
-{
- uint16_t fcs = le16_to_cpup((void *) (hdr->data + len - 2));
-
- if (len < 4)
- goto len_error;
- if (l2cap_fcs16((const uint8_t *) hdr, L2CAP_HDR_SIZE + len - 2) != fcs)
- goto fcs_error;
-
- if ((hdr->data[0] >> 7) == ch->rexmit)
- l2cap_rexmit_enable(ch, !(hdr->data[0] >> 7));
-
- if (hdr->data[0] & 1) {
- if (len != 4) {
- /* TODO: Signal an error? */
- return;
- }
- l2cap_sframe_in(ch, le16_to_cpup((void *) hdr->data));
- return;
- }
-
- switch (hdr->data[1] >> 6) { /* SAR */
- case L2CAP_SAR_NO_SEG:
- if (ch->len_total)
- goto seg_error;
- if (len - 4 > ch->mps)
- goto len_error;
-
- ch->params.sdu_in(ch->params.opaque, hdr->data + 2, len - 4);
- break;
-
- case L2CAP_SAR_START:
- if (ch->len_total || len < 6)
- goto seg_error;
- if (len - 6 > ch->mps)
- goto len_error;
-
- ch->len_total = le16_to_cpup((void *) (hdr->data + 2));
- if (len >= 6 + ch->len_total)
- goto seg_error;
-
- ch->len_cur = len - 6;
- memcpy(ch->sdu, hdr->data + 4, ch->len_cur);
- break;
-
- case L2CAP_SAR_END:
- if (!ch->len_total || ch->len_cur + len - 4 < ch->len_total)
- goto seg_error;
- if (len - 4 > ch->mps)
- goto len_error;
-
- memcpy(ch->sdu + ch->len_cur, hdr->data + 2, len - 4);
- ch->params.sdu_in(ch->params.opaque, ch->sdu, ch->len_total);
- break;
-
- case L2CAP_SAR_CONT:
- if (!ch->len_total || ch->len_cur + len - 4 >= ch->len_total)
- goto seg_error;
- if (len - 4 > ch->mps)
- goto len_error;
-
- memcpy(ch->sdu + ch->len_cur, hdr->data + 2, len - 4);
- ch->len_cur += len - 4;
- break;
-
- seg_error:
- len_error: /* TODO */
- fcs_error: /* TODO */
- ch->len_cur = 0;
- ch->len_total = 0;
- break;
- }
-}
-
-static void l2cap_frame_in(struct l2cap_instance_s *l2cap,
- const l2cap_hdr *frame)
-{
- uint16_t cid = le16_to_cpu(frame->cid);
- uint16_t len = le16_to_cpu(frame->len);
-
- if (unlikely(cid >= L2CAP_CID_MAX || !l2cap->cid[cid])) {
- fprintf(stderr, "%s: frame addressed to a non-existent L2CAP "
- "channel %04x received.\n", __FUNCTION__, cid);
- return;
- }
-
- l2cap->cid[cid]->frame_in(l2cap->cid[cid], cid, frame, len);
-}
-
-/* "Recombination" */
-static void l2cap_pdu_in(struct l2cap_instance_s *l2cap,
- const uint8_t *data, int len)
-{
- const l2cap_hdr *hdr = (void *) l2cap->frame_in;
-
- if (unlikely(len + l2cap->frame_in_len > sizeof(l2cap->frame_in))) {
- if (l2cap->frame_in_len < sizeof(l2cap->frame_in)) {
- memcpy(l2cap->frame_in + l2cap->frame_in_len, data,
- sizeof(l2cap->frame_in) - l2cap->frame_in_len);
- l2cap->frame_in_len = sizeof(l2cap->frame_in);
- /* TODO: truncate */
- l2cap_frame_in(l2cap, hdr);
- }
-
- return;
- }
-
- memcpy(l2cap->frame_in + l2cap->frame_in_len, data, len);
- l2cap->frame_in_len += len;
-
- if (len >= L2CAP_HDR_SIZE)
- if (len >= L2CAP_HDR_SIZE + le16_to_cpu(hdr->len))
- l2cap_frame_in(l2cap, hdr);
- /* There is never a start of a new PDU in the same ACL packet, so
- * no need to memmove the remaining payload and loop. */
-}
-
-static inline uint8_t *l2cap_pdu_out(struct l2cap_instance_s *l2cap,
- uint16_t cid, uint16_t len)
-{
- l2cap_hdr *hdr = (void *) l2cap->frame_out;
-
- l2cap->frame_out_len = len + L2CAP_HDR_SIZE;
-
- hdr->cid = cpu_to_le16(cid);
- hdr->len = cpu_to_le16(len);
-
- return l2cap->frame_out + L2CAP_HDR_SIZE;
-}
-
-static inline void l2cap_pdu_submit(struct l2cap_instance_s *l2cap)
-{
- /* TODO: Fragmentation */
- (l2cap->role ?
- l2cap->link->slave->lmp_acl_data : l2cap->link->host->lmp_acl_resp)
- (l2cap->link, l2cap->frame_out, 1, l2cap->frame_out_len);
-}
-
-static uint8_t *l2cap_bframe_out(struct bt_l2cap_conn_params_s *parm, int len)
-{
- struct l2cap_chan_s *chan = (struct l2cap_chan_s *) parm;
-
- if (len > chan->params.remote_mtu) {
- fprintf(stderr, "%s: B-Frame for CID %04x longer than %i octets.\n",
- __FUNCTION__,
- chan->remote_cid, chan->params.remote_mtu);
- exit(-1);
- }
-
- return l2cap_pdu_out(chan->l2cap, chan->remote_cid, len);
-}
-
-static void l2cap_bframe_submit(struct bt_l2cap_conn_params_s *parms)
-{
- struct l2cap_chan_s *chan = (struct l2cap_chan_s *) parms;
-
- l2cap_pdu_submit(chan->l2cap);
-}
-
-#if 0
-/* Stub: Only used if an emulated device requests outgoing flow control */
-static uint8_t *l2cap_iframe_out(struct bt_l2cap_conn_params_s *parm, int len)
-{
- struct l2cap_chan_s *chan = (struct l2cap_chan_s *) parm;
-
- if (len > chan->params.remote_mtu) {
- /* TODO: slice into segments and queue each segment as a separate
- * I-Frame in a FIFO of I-Frames, local to the CID. */
- } else {
- /* TODO: add to the FIFO of I-Frames, local to the CID. */
- /* Possibly we need to return a pointer to a contiguous buffer
- * for now and then memcpy from it into FIFOs in l2cap_iframe_submit
- * while segmenting at the same time. */
- }
- return 0;
-}
-
-static void l2cap_iframe_submit(struct bt_l2cap_conn_params_s *parm)
-{
- /* TODO: If flow control indicates clear to send, start submitting the
- * invidual I-Frames from the FIFO, but don't remove them from there.
- * Kick the appropriate timer until we get an S-Frame, and only then
- * remove from FIFO or resubmit and re-kick the timer if the timer
- * expired. */
-}
-#endif
-
-static void l2cap_init(struct l2cap_instance_s *l2cap,
- struct bt_link_s *link, int role)
-{
- l2cap->link = link;
- l2cap->role = role;
- l2cap->dev = (struct bt_l2cap_device_s *)
- (role ? link->host : link->slave);
-
- l2cap->next_id = 1;
-
- /* Establish the signalling channel */
- l2cap->signalling_ch.params.sdu_in = l2cap_cframe_in;
- l2cap->signalling_ch.params.sdu_out = l2cap_bframe_out;
- l2cap->signalling_ch.params.sdu_submit = l2cap_bframe_submit;
- l2cap->signalling_ch.params.opaque = l2cap;
- l2cap->signalling_ch.params.remote_mtu = 48;
- l2cap->signalling_ch.remote_cid = L2CAP_CID_SIGNALLING;
- l2cap->signalling_ch.frame_in = l2cap_bframe_in;
- l2cap->signalling_ch.mps = 65536;
- l2cap->signalling_ch.min_mtu = 48;
- l2cap->signalling_ch.mode = L2CAP_MODE_BASIC;
- l2cap->signalling_ch.l2cap = l2cap;
- l2cap->cid[L2CAP_CID_SIGNALLING] = &l2cap->signalling_ch;
-
- /* Establish the connection-less data channel */
- l2cap->group_ch.params.sdu_in = l2cap_gframe_in;
- l2cap->group_ch.params.opaque = l2cap;
- l2cap->group_ch.frame_in = l2cap_bframe_in;
- l2cap->group_ch.mps = 65533;
- l2cap->group_ch.l2cap = l2cap;
- l2cap->group_ch.remote_cid = L2CAP_CID_INVALID;
- l2cap->cid[L2CAP_CID_GROUP] = &l2cap->group_ch;
-}
-
-static void l2cap_teardown(struct l2cap_instance_s *l2cap, int send_disconnect)
-{
- int cid;
-
- /* Don't send DISCONNECT if we are currently handling a DISCONNECT
- * sent from the other side. */
- if (send_disconnect) {
- if (l2cap->role)
- l2cap->dev->device.lmp_disconnect_slave(l2cap->link);
- /* l2cap->link is invalid from now on. */
- else
- l2cap->dev->device.lmp_disconnect_master(l2cap->link);
- }
-
- for (cid = L2CAP_CID_ALLOC; cid < L2CAP_CID_MAX; cid ++)
- if (l2cap->cid[cid]) {
- l2cap->cid[cid]->params.close(l2cap->cid[cid]->params.opaque);
- g_free(l2cap->cid[cid]);
- }
-
- if (l2cap->role)
- g_free(l2cap);
- else
- g_free(l2cap->link);
-}
-
-/* L2CAP glue to lower layers in bluetooth stack (LMP) */
-
-static void l2cap_lmp_connection_request(struct bt_link_s *link)
-{
- struct bt_l2cap_device_s *dev = (struct bt_l2cap_device_s *) link->slave;
- struct slave_l2cap_instance_s *l2cap;
-
- /* Always accept - we only get called if (dev->device->page_scan). */
-
- l2cap = g_malloc0(sizeof(struct slave_l2cap_instance_s));
- l2cap->link.slave = &dev->device;
- l2cap->link.host = link->host;
- l2cap_init(&l2cap->l2cap, &l2cap->link, 0);
-
- /* Always at the end */
- link->host->reject_reason = 0;
- link->host->lmp_connection_complete(&l2cap->link);
-}
-
-/* Stub */
-static void l2cap_lmp_connection_complete(struct bt_link_s *link)
-{
- struct bt_l2cap_device_s *dev = (struct bt_l2cap_device_s *) link->host;
- struct l2cap_instance_s *l2cap;
-
- if (dev->device.reject_reason) {
- /* Signal to upper layer */
- return;
- }
-
- l2cap = g_malloc0(sizeof(struct l2cap_instance_s));
- l2cap_init(l2cap, link, 1);
-
- link->acl_mode = acl_active;
-
- /* Signal to upper layer */
-}
-
-/* Stub */
-static void l2cap_lmp_disconnect_host(struct bt_link_s *link)
-{
- struct bt_l2cap_device_s *dev = (struct bt_l2cap_device_s *) link->host;
- struct l2cap_instance_s *l2cap =
- /* TODO: Retrieve from upper layer */ (void *) dev;
-
- /* Signal to upper layer */
-
- l2cap_teardown(l2cap, 0);
-}
-
-static void l2cap_lmp_disconnect_slave(struct bt_link_s *link)
-{
- struct slave_l2cap_instance_s *l2cap =
- (struct slave_l2cap_instance_s *) link;
-
- l2cap_teardown(&l2cap->l2cap, 0);
-}
-
-static void l2cap_lmp_acl_data_slave(struct bt_link_s *link,
- const uint8_t *data, int start, int len)
-{
- struct slave_l2cap_instance_s *l2cap =
- (struct slave_l2cap_instance_s *) link;
-
- if (start)
- l2cap->l2cap.frame_in_len = 0;
-
- l2cap_pdu_in(&l2cap->l2cap, data, len);
-}
-
-/* Stub */
-static void l2cap_lmp_acl_data_host(struct bt_link_s *link,
- const uint8_t *data, int start, int len)
-{
- struct bt_l2cap_device_s *dev = (struct bt_l2cap_device_s *) link->host;
- struct l2cap_instance_s *l2cap =
- /* TODO: Retrieve from upper layer */ (void *) dev;
-
- if (start)
- l2cap->frame_in_len = 0;
-
- l2cap_pdu_in(l2cap, data, len);
-}
-
-static void l2cap_dummy_destroy(struct bt_device_s *dev)
-{
- struct bt_l2cap_device_s *l2cap_dev = (struct bt_l2cap_device_s *) dev;
-
- bt_l2cap_device_done(l2cap_dev);
-}
-
-void bt_l2cap_device_init(struct bt_l2cap_device_s *dev,
- struct bt_scatternet_s *net)
-{
- bt_device_init(&dev->device, net);
-
- dev->device.lmp_connection_request = l2cap_lmp_connection_request;
- dev->device.lmp_connection_complete = l2cap_lmp_connection_complete;
- dev->device.lmp_disconnect_master = l2cap_lmp_disconnect_host;
- dev->device.lmp_disconnect_slave = l2cap_lmp_disconnect_slave;
- dev->device.lmp_acl_data = l2cap_lmp_acl_data_slave;
- dev->device.lmp_acl_resp = l2cap_lmp_acl_data_host;
-
- dev->device.handle_destroy = l2cap_dummy_destroy;
-}
-
-void bt_l2cap_device_done(struct bt_l2cap_device_s *dev)
-{
- bt_device_done(&dev->device);
-
- /* Should keep a list of all instances and go through it and
- * invoke l2cap_teardown() for each. */
-}
-
-void bt_l2cap_psm_register(struct bt_l2cap_device_s *dev, int psm, int min_mtu,
- int (*new_channel)(struct bt_l2cap_device_s *dev,
- struct bt_l2cap_conn_params_s *params))
-{
- struct bt_l2cap_psm_s *new_psm = l2cap_psm(dev, psm);
-
- if (new_psm) {
- fprintf(stderr, "%s: PSM %04x already registered for device `%s'.\n",
- __FUNCTION__, psm, dev->device.lmp_name);
- exit(-1);
- }
-
- new_psm = g_malloc0(sizeof(*new_psm));
- new_psm->psm = psm;
- new_psm->min_mtu = min_mtu;
- new_psm->new_channel = new_channel;
- new_psm->next = dev->first_psm;
- dev->first_psm = new_psm;
-}
diff --git a/qemu/hw/bt/sdp.c b/qemu/hw/bt/sdp.c
deleted file mode 100644
index be26009b0..000000000
--- a/qemu/hw/bt/sdp.c
+++ /dev/null
@@ -1,979 +0,0 @@
-/*
- * Service Discover Protocol server for QEMU L2CAP devices
- *
- * Copyright (C) 2008 Andrzej Zaborowski <balrog@zabor.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "hw/bt.h"
-
-struct bt_l2cap_sdp_state_s {
- struct bt_l2cap_conn_params_s *channel;
-
- struct sdp_service_record_s {
- int match;
-
- int *uuid;
- int uuids;
- struct sdp_service_attribute_s {
- int match;
-
- int attribute_id;
- int len;
- void *pair;
- } *attribute_list;
- int attributes;
- } *service_list;
- int services;
-};
-
-static ssize_t sdp_datalen(const uint8_t **element, ssize_t *left)
-{
- uint32_t len = *(*element) ++ & SDP_DSIZE_MASK;
-
- if (!*left)
- return -1;
- (*left) --;
-
- if (len < SDP_DSIZE_NEXT1)
- return 1 << len;
- else if (len == SDP_DSIZE_NEXT1) {
- if (*left < 1)
- return -1;
- (*left) --;
-
- return *(*element) ++;
- } else if (len == SDP_DSIZE_NEXT2) {
- if (*left < 2)
- return -1;
- (*left) -= 2;
-
- len = (*(*element) ++) << 8;
- return len | (*(*element) ++);
- } else {
- if (*left < 4)
- return -1;
- (*left) -= 4;
-
- len = (*(*element) ++) << 24;
- len |= (*(*element) ++) << 16;
- len |= (*(*element) ++) << 8;
- return len | (*(*element) ++);
- }
-}
-
-static const uint8_t bt_base_uuid[12] = {
- 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
-};
-
-static int sdp_uuid_match(struct sdp_service_record_s *record,
- const uint8_t *uuid, ssize_t datalen)
-{
- int *lo, hi, val;
-
- if (datalen == 16 || datalen == 4) {
- if (datalen == 16 && memcmp(uuid + 4, bt_base_uuid, 12))
- return 0;
-
- if (uuid[0] | uuid[1])
- return 0;
- uuid += 2;
- }
-
- val = (uuid[0] << 8) | uuid[1];
- lo = record->uuid;
- hi = record->uuids;
- while (hi >>= 1)
- if (lo[hi] <= val)
- lo += hi;
-
- return *lo == val;
-}
-
-#define CONTINUATION_PARAM_SIZE (1 + sizeof(int))
-#define MAX_PDU_OUT_SIZE 96 /* Arbitrary */
-#define PDU_HEADER_SIZE 5
-#define MAX_RSP_PARAM_SIZE (MAX_PDU_OUT_SIZE - PDU_HEADER_SIZE - \
- CONTINUATION_PARAM_SIZE)
-
-static int sdp_svc_match(struct bt_l2cap_sdp_state_s *sdp,
- const uint8_t **req, ssize_t *len)
-{
- size_t datalen;
- int i;
-
- if ((**req & ~SDP_DSIZE_MASK) != SDP_DTYPE_UUID)
- return 1;
-
- datalen = sdp_datalen(req, len);
- if (datalen != 2 && datalen != 4 && datalen != 16)
- return 1;
-
- for (i = 0; i < sdp->services; i ++)
- if (sdp_uuid_match(&sdp->service_list[i], *req, datalen))
- sdp->service_list[i].match = 1;
-
- (*req) += datalen;
- (*len) -= datalen;
-
- return 0;
-}
-
-static ssize_t sdp_svc_search(struct bt_l2cap_sdp_state_s *sdp,
- uint8_t *rsp, const uint8_t *req, ssize_t len)
-{
- ssize_t seqlen;
- int i, count, start, end, max;
- int32_t handle;
-
- /* Perform the search */
- for (i = 0; i < sdp->services; i ++)
- sdp->service_list[i].match = 0;
-
- if (len < 1)
- return -SDP_INVALID_SYNTAX;
- if ((*req & ~SDP_DSIZE_MASK) == SDP_DTYPE_SEQ) {
- seqlen = sdp_datalen(&req, &len);
- if (seqlen < 3 || len < seqlen)
- return -SDP_INVALID_SYNTAX;
- len -= seqlen;
- while (seqlen)
- if (sdp_svc_match(sdp, &req, &seqlen))
- return -SDP_INVALID_SYNTAX;
- } else {
- if (sdp_svc_match(sdp, &req, &len)) {
- return -SDP_INVALID_SYNTAX;
- }
- }
-
- if (len < 3)
- return -SDP_INVALID_SYNTAX;
- max = (req[0] << 8) | req[1];
- req += 2;
- len -= 2;
-
- if (*req) {
- if (len <= sizeof(int))
- return -SDP_INVALID_SYNTAX;
- len -= sizeof(int);
- memcpy(&start, req + 1, sizeof(int));
- } else
- start = 0;
-
- if (len > 1)
- return -SDP_INVALID_SYNTAX;
-
- /* Output the results */
- len = 4;
- count = 0;
- end = start;
- for (i = 0; i < sdp->services; i ++)
- if (sdp->service_list[i].match) {
- if (count >= start && count < max && len + 4 < MAX_RSP_PARAM_SIZE) {
- handle = i;
- memcpy(rsp + len, &handle, 4);
- len += 4;
- end = count + 1;
- }
-
- count ++;
- }
-
- rsp[0] = count >> 8;
- rsp[1] = count & 0xff;
- rsp[2] = (end - start) >> 8;
- rsp[3] = (end - start) & 0xff;
-
- if (end < count) {
- rsp[len ++] = sizeof(int);
- memcpy(rsp + len, &end, sizeof(int));
- len += 4;
- } else
- rsp[len ++] = 0;
-
- return len;
-}
-
-static int sdp_attr_match(struct sdp_service_record_s *record,
- const uint8_t **req, ssize_t *len)
-{
- int i, start, end;
-
- if (**req == (SDP_DTYPE_UINT | SDP_DSIZE_2)) {
- (*req) ++;
- if (*len < 3)
- return 1;
-
- start = (*(*req) ++) << 8;
- start |= *(*req) ++;
- end = start;
- *len -= 3;
- } else if (**req == (SDP_DTYPE_UINT | SDP_DSIZE_4)) {
- (*req) ++;
- if (*len < 5)
- return 1;
-
- start = (*(*req) ++) << 8;
- start |= *(*req) ++;
- end = (*(*req) ++) << 8;
- end |= *(*req) ++;
- *len -= 5;
- } else
- return 1;
-
- for (i = 0; i < record->attributes; i ++)
- if (record->attribute_list[i].attribute_id >= start &&
- record->attribute_list[i].attribute_id <= end)
- record->attribute_list[i].match = 1;
-
- return 0;
-}
-
-static ssize_t sdp_attr_get(struct bt_l2cap_sdp_state_s *sdp,
- uint8_t *rsp, const uint8_t *req, ssize_t len)
-{
- ssize_t seqlen;
- int i, start, end, max;
- int32_t handle;
- struct sdp_service_record_s *record;
- uint8_t *lst;
-
- /* Perform the search */
- if (len < 7)
- return -SDP_INVALID_SYNTAX;
- memcpy(&handle, req, 4);
- req += 4;
- len -= 4;
-
- if (handle < 0 || handle > sdp->services)
- return -SDP_INVALID_RECORD_HANDLE;
- record = &sdp->service_list[handle];
-
- for (i = 0; i < record->attributes; i ++)
- record->attribute_list[i].match = 0;
-
- max = (req[0] << 8) | req[1];
- req += 2;
- len -= 2;
- if (max < 0x0007)
- return -SDP_INVALID_SYNTAX;
-
- if ((*req & ~SDP_DSIZE_MASK) == SDP_DTYPE_SEQ) {
- seqlen = sdp_datalen(&req, &len);
- if (seqlen < 3 || len < seqlen)
- return -SDP_INVALID_SYNTAX;
- len -= seqlen;
-
- while (seqlen)
- if (sdp_attr_match(record, &req, &seqlen))
- return -SDP_INVALID_SYNTAX;
- } else {
- if (sdp_attr_match(record, &req, &len)) {
- return -SDP_INVALID_SYNTAX;
- }
- }
-
- if (len < 1)
- return -SDP_INVALID_SYNTAX;
-
- if (*req) {
- if (len <= sizeof(int))
- return -SDP_INVALID_SYNTAX;
- len -= sizeof(int);
- memcpy(&start, req + 1, sizeof(int));
- } else
- start = 0;
-
- if (len > 1)
- return -SDP_INVALID_SYNTAX;
-
- /* Output the results */
- lst = rsp + 2;
- max = MIN(max, MAX_RSP_PARAM_SIZE);
- len = 3 - start;
- end = 0;
- for (i = 0; i < record->attributes; i ++)
- if (record->attribute_list[i].match) {
- if (len >= 0 && len + record->attribute_list[i].len < max) {
- memcpy(lst + len, record->attribute_list[i].pair,
- record->attribute_list[i].len);
- end = len + record->attribute_list[i].len;
- }
- len += record->attribute_list[i].len;
- }
- if (0 >= start) {
- lst[0] = SDP_DTYPE_SEQ | SDP_DSIZE_NEXT2;
- lst[1] = (len + start - 3) >> 8;
- lst[2] = (len + start - 3) & 0xff;
- }
-
- rsp[0] = end >> 8;
- rsp[1] = end & 0xff;
-
- if (end < len) {
- len = end + start;
- lst[end ++] = sizeof(int);
- memcpy(lst + end, &len, sizeof(int));
- end += sizeof(int);
- } else
- lst[end ++] = 0;
-
- return end + 2;
-}
-
-static int sdp_svc_attr_match(struct bt_l2cap_sdp_state_s *sdp,
- const uint8_t **req, ssize_t *len)
-{
- int i, j, start, end;
- struct sdp_service_record_s *record;
-
- if (**req == (SDP_DTYPE_UINT | SDP_DSIZE_2)) {
- (*req) ++;
- if (*len < 3)
- return 1;
-
- start = (*(*req) ++) << 8;
- start |= *(*req) ++;
- end = start;
- *len -= 3;
- } else if (**req == (SDP_DTYPE_UINT | SDP_DSIZE_4)) {
- (*req) ++;
- if (*len < 5)
- return 1;
-
- start = (*(*req) ++) << 8;
- start |= *(*req) ++;
- end = (*(*req) ++) << 8;
- end |= *(*req) ++;
- *len -= 5;
- } else
- return 1;
-
- for (i = 0; i < sdp->services; i ++)
- if ((record = &sdp->service_list[i])->match)
- for (j = 0; j < record->attributes; j ++)
- if (record->attribute_list[j].attribute_id >= start &&
- record->attribute_list[j].attribute_id <= end)
- record->attribute_list[j].match = 1;
-
- return 0;
-}
-
-static ssize_t sdp_svc_search_attr_get(struct bt_l2cap_sdp_state_s *sdp,
- uint8_t *rsp, const uint8_t *req, ssize_t len)
-{
- ssize_t seqlen;
- int i, j, start, end, max;
- struct sdp_service_record_s *record;
- uint8_t *lst;
-
- /* Perform the search */
- for (i = 0; i < sdp->services; i ++) {
- sdp->service_list[i].match = 0;
- for (j = 0; j < sdp->service_list[i].attributes; j ++)
- sdp->service_list[i].attribute_list[j].match = 0;
- }
-
- if (len < 1)
- return -SDP_INVALID_SYNTAX;
- if ((*req & ~SDP_DSIZE_MASK) == SDP_DTYPE_SEQ) {
- seqlen = sdp_datalen(&req, &len);
- if (seqlen < 3 || len < seqlen)
- return -SDP_INVALID_SYNTAX;
- len -= seqlen;
-
- while (seqlen)
- if (sdp_svc_match(sdp, &req, &seqlen))
- return -SDP_INVALID_SYNTAX;
- } else {
- if (sdp_svc_match(sdp, &req, &len)) {
- return -SDP_INVALID_SYNTAX;
- }
- }
-
- if (len < 3)
- return -SDP_INVALID_SYNTAX;
- max = (req[0] << 8) | req[1];
- req += 2;
- len -= 2;
- if (max < 0x0007)
- return -SDP_INVALID_SYNTAX;
-
- if ((*req & ~SDP_DSIZE_MASK) == SDP_DTYPE_SEQ) {
- seqlen = sdp_datalen(&req, &len);
- if (seqlen < 3 || len < seqlen)
- return -SDP_INVALID_SYNTAX;
- len -= seqlen;
-
- while (seqlen)
- if (sdp_svc_attr_match(sdp, &req, &seqlen))
- return -SDP_INVALID_SYNTAX;
- } else {
- if (sdp_svc_attr_match(sdp, &req, &len)) {
- return -SDP_INVALID_SYNTAX;
- }
- }
-
- if (len < 1)
- return -SDP_INVALID_SYNTAX;
-
- if (*req) {
- if (len <= sizeof(int))
- return -SDP_INVALID_SYNTAX;
- len -= sizeof(int);
- memcpy(&start, req + 1, sizeof(int));
- } else
- start = 0;
-
- if (len > 1)
- return -SDP_INVALID_SYNTAX;
-
- /* Output the results */
- /* This assumes empty attribute lists are never to be returned even
- * for matching Service Records. In practice this shouldn't happen
- * as the requestor will usually include the always present
- * ServiceRecordHandle AttributeID in AttributeIDList. */
- lst = rsp + 2;
- max = MIN(max, MAX_RSP_PARAM_SIZE);
- len = 3 - start;
- end = 0;
- for (i = 0; i < sdp->services; i ++)
- if ((record = &sdp->service_list[i])->match) {
- len += 3;
- seqlen = len;
- for (j = 0; j < record->attributes; j ++)
- if (record->attribute_list[j].match) {
- if (len >= 0)
- if (len + record->attribute_list[j].len < max) {
- memcpy(lst + len, record->attribute_list[j].pair,
- record->attribute_list[j].len);
- end = len + record->attribute_list[j].len;
- }
- len += record->attribute_list[j].len;
- }
- if (seqlen == len)
- len -= 3;
- else if (seqlen >= 3 && seqlen < max) {
- lst[seqlen - 3] = SDP_DTYPE_SEQ | SDP_DSIZE_NEXT2;
- lst[seqlen - 2] = (len - seqlen) >> 8;
- lst[seqlen - 1] = (len - seqlen) & 0xff;
- }
- }
- if (len == 3 - start)
- len -= 3;
- else if (0 >= start) {
- lst[0] = SDP_DTYPE_SEQ | SDP_DSIZE_NEXT2;
- lst[1] = (len + start - 3) >> 8;
- lst[2] = (len + start - 3) & 0xff;
- }
-
- rsp[0] = end >> 8;
- rsp[1] = end & 0xff;
-
- if (end < len) {
- len = end + start;
- lst[end ++] = sizeof(int);
- memcpy(lst + end, &len, sizeof(int));
- end += sizeof(int);
- } else
- lst[end ++] = 0;
-
- return end + 2;
-}
-
-static void bt_l2cap_sdp_sdu_in(void *opaque, const uint8_t *data, int len)
-{
- struct bt_l2cap_sdp_state_s *sdp = opaque;
- enum bt_sdp_cmd pdu_id;
- uint8_t rsp[MAX_PDU_OUT_SIZE - PDU_HEADER_SIZE], *sdu_out;
- int transaction_id, plen;
- int err = 0;
- int rsp_len = 0;
-
- if (len < 5) {
- fprintf(stderr, "%s: short SDP PDU (%iB).\n", __FUNCTION__, len);
- return;
- }
-
- pdu_id = *data ++;
- transaction_id = (data[0] << 8) | data[1];
- plen = (data[2] << 8) | data[3];
- data += 4;
- len -= 5;
-
- if (len != plen) {
- fprintf(stderr, "%s: wrong SDP PDU length (%iB != %iB).\n",
- __FUNCTION__, plen, len);
- err = SDP_INVALID_PDU_SIZE;
- goto respond;
- }
-
- switch (pdu_id) {
- case SDP_SVC_SEARCH_REQ:
- rsp_len = sdp_svc_search(sdp, rsp, data, len);
- pdu_id = SDP_SVC_SEARCH_RSP;
- break;
-
- case SDP_SVC_ATTR_REQ:
- rsp_len = sdp_attr_get(sdp, rsp, data, len);
- pdu_id = SDP_SVC_ATTR_RSP;
- break;
-
- case SDP_SVC_SEARCH_ATTR_REQ:
- rsp_len = sdp_svc_search_attr_get(sdp, rsp, data, len);
- pdu_id = SDP_SVC_SEARCH_ATTR_RSP;
- break;
-
- case SDP_ERROR_RSP:
- case SDP_SVC_ATTR_RSP:
- case SDP_SVC_SEARCH_RSP:
- case SDP_SVC_SEARCH_ATTR_RSP:
- default:
- fprintf(stderr, "%s: unexpected SDP PDU ID %02x.\n",
- __FUNCTION__, pdu_id);
- err = SDP_INVALID_SYNTAX;
- break;
- }
-
- if (rsp_len < 0) {
- err = -rsp_len;
- rsp_len = 0;
- }
-
-respond:
- if (err) {
- pdu_id = SDP_ERROR_RSP;
- rsp[rsp_len ++] = err >> 8;
- rsp[rsp_len ++] = err & 0xff;
- }
-
- sdu_out = sdp->channel->sdu_out(sdp->channel, rsp_len + PDU_HEADER_SIZE);
-
- sdu_out[0] = pdu_id;
- sdu_out[1] = transaction_id >> 8;
- sdu_out[2] = transaction_id & 0xff;
- sdu_out[3] = rsp_len >> 8;
- sdu_out[4] = rsp_len & 0xff;
- memcpy(sdu_out + PDU_HEADER_SIZE, rsp, rsp_len);
-
- sdp->channel->sdu_submit(sdp->channel);
-}
-
-static void bt_l2cap_sdp_close_ch(void *opaque)
-{
- struct bt_l2cap_sdp_state_s *sdp = opaque;
- int i;
-
- for (i = 0; i < sdp->services; i ++) {
- g_free(sdp->service_list[i].attribute_list->pair);
- g_free(sdp->service_list[i].attribute_list);
- g_free(sdp->service_list[i].uuid);
- }
- g_free(sdp->service_list);
- g_free(sdp);
-}
-
-struct sdp_def_service_s {
- uint16_t class_uuid;
- struct sdp_def_attribute_s {
- uint16_t id;
- struct sdp_def_data_element_s {
- uint8_t type;
- union {
- uint32_t uint;
- const char *str;
- struct sdp_def_data_element_s *list;
- } value;
- } data;
- } attributes[];
-};
-
-/* Calculate a safe byte count to allocate that will store the given
- * element, at the same time count elements of a UUID type. */
-static int sdp_attr_max_size(struct sdp_def_data_element_s *element,
- int *uuids)
-{
- int type = element->type & ~SDP_DSIZE_MASK;
- int len;
-
- if (type == SDP_DTYPE_UINT || type == SDP_DTYPE_UUID ||
- type == SDP_DTYPE_BOOL) {
- if (type == SDP_DTYPE_UUID)
- (*uuids) ++;
- return 1 + (1 << (element->type & SDP_DSIZE_MASK));
- }
-
- if (type == SDP_DTYPE_STRING || type == SDP_DTYPE_URL) {
- if (element->type & SDP_DSIZE_MASK) {
- for (len = 0; element->value.str[len] |
- element->value.str[len + 1]; len ++);
- return len;
- } else
- return 2 + strlen(element->value.str);
- }
-
- if (type != SDP_DTYPE_SEQ)
- exit(-1);
- len = 2;
- element = element->value.list;
- while (element->type)
- len += sdp_attr_max_size(element ++, uuids);
- if (len > 255)
- exit (-1);
-
- return len;
-}
-
-static int sdp_attr_write(uint8_t *data,
- struct sdp_def_data_element_s *element, int **uuid)
-{
- int type = element->type & ~SDP_DSIZE_MASK;
- int len = 0;
-
- if (type == SDP_DTYPE_UINT || type == SDP_DTYPE_BOOL) {
- data[len ++] = element->type;
- if ((element->type & SDP_DSIZE_MASK) == SDP_DSIZE_1)
- data[len ++] = (element->value.uint >> 0) & 0xff;
- else if ((element->type & SDP_DSIZE_MASK) == SDP_DSIZE_2) {
- data[len ++] = (element->value.uint >> 8) & 0xff;
- data[len ++] = (element->value.uint >> 0) & 0xff;
- } else if ((element->type & SDP_DSIZE_MASK) == SDP_DSIZE_4) {
- data[len ++] = (element->value.uint >> 24) & 0xff;
- data[len ++] = (element->value.uint >> 16) & 0xff;
- data[len ++] = (element->value.uint >> 8) & 0xff;
- data[len ++] = (element->value.uint >> 0) & 0xff;
- }
-
- return len;
- }
-
- if (type == SDP_DTYPE_UUID) {
- *(*uuid) ++ = element->value.uint;
-
- data[len ++] = element->type;
- data[len ++] = (element->value.uint >> 24) & 0xff;
- data[len ++] = (element->value.uint >> 16) & 0xff;
- data[len ++] = (element->value.uint >> 8) & 0xff;
- data[len ++] = (element->value.uint >> 0) & 0xff;
- memcpy(data + len, bt_base_uuid, 12);
-
- return len + 12;
- }
-
- data[0] = type | SDP_DSIZE_NEXT1;
- if (type == SDP_DTYPE_STRING || type == SDP_DTYPE_URL) {
- if (element->type & SDP_DSIZE_MASK)
- for (len = 0; element->value.str[len] |
- element->value.str[len + 1]; len ++);
- else
- len = strlen(element->value.str);
- memcpy(data + 2, element->value.str, data[1] = len);
-
- return len + 2;
- }
-
- len = 2;
- element = element->value.list;
- while (element->type)
- len += sdp_attr_write(data + len, element ++, uuid);
- data[1] = len - 2;
-
- return len;
-}
-
-static int sdp_attributeid_compare(const struct sdp_service_attribute_s *a,
- const struct sdp_service_attribute_s *b)
-{
- return (int) b->attribute_id - a->attribute_id;
-}
-
-static int sdp_uuid_compare(const int *a, const int *b)
-{
- return *a - *b;
-}
-
-static void sdp_service_record_build(struct sdp_service_record_s *record,
- struct sdp_def_service_s *def, int handle)
-{
- int len = 0;
- uint8_t *data;
- int *uuid;
-
- record->uuids = 0;
- while (def->attributes[record->attributes].data.type) {
- len += 3;
- len += sdp_attr_max_size(&def->attributes[record->attributes ++].data,
- &record->uuids);
- }
- record->uuids = pow2ceil(record->uuids);
- record->attribute_list =
- g_malloc0(record->attributes * sizeof(*record->attribute_list));
- record->uuid =
- g_malloc0(record->uuids * sizeof(*record->uuid));
- data = g_malloc(len);
-
- record->attributes = 0;
- uuid = record->uuid;
- while (def->attributes[record->attributes].data.type) {
- record->attribute_list[record->attributes].pair = data;
-
- len = 0;
- data[len ++] = SDP_DTYPE_UINT | SDP_DSIZE_2;
- data[len ++] = def->attributes[record->attributes].id >> 8;
- data[len ++] = def->attributes[record->attributes].id & 0xff;
- len += sdp_attr_write(data + len,
- &def->attributes[record->attributes].data, &uuid);
-
- /* Special case: assign a ServiceRecordHandle in sequence */
- if (def->attributes[record->attributes].id == SDP_ATTR_RECORD_HANDLE)
- def->attributes[record->attributes].data.value.uint = handle;
- /* Note: we could also assign a ServiceDescription based on
- * sdp->device.device->lmp_name. */
-
- record->attribute_list[record->attributes ++].len = len;
- data += len;
- }
-
- /* Sort the attribute list by the AttributeID */
- qsort(record->attribute_list, record->attributes,
- sizeof(*record->attribute_list),
- (void *) sdp_attributeid_compare);
- /* Sort the searchable UUIDs list for bisection */
- qsort(record->uuid, record->uuids,
- sizeof(*record->uuid),
- (void *) sdp_uuid_compare);
-}
-
-static void sdp_service_db_build(struct bt_l2cap_sdp_state_s *sdp,
- struct sdp_def_service_s **service)
-{
- sdp->services = 0;
- while (service[sdp->services])
- sdp->services ++;
- sdp->service_list =
- g_malloc0(sdp->services * sizeof(*sdp->service_list));
-
- sdp->services = 0;
- while (*service) {
- sdp_service_record_build(&sdp->service_list[sdp->services],
- *service, sdp->services);
- service ++;
- sdp->services ++;
- }
-}
-
-#define LAST { .type = 0 }
-#define SERVICE(name, attrs) \
- static struct sdp_def_service_s glue(glue(sdp_service_, name), _s) = { \
- .attributes = { attrs { .data = LAST } }, \
- };
-#define ATTRIBUTE(attrid, val) { .id = glue(SDP_ATTR_, attrid), .data = val },
-#define UINT8(val) { \
- .type = SDP_DTYPE_UINT | SDP_DSIZE_1, \
- .value.uint = val, \
- },
-#define UINT16(val) { \
- .type = SDP_DTYPE_UINT | SDP_DSIZE_2, \
- .value.uint = val, \
- },
-#define UINT32(val) { \
- .type = SDP_DTYPE_UINT | SDP_DSIZE_4, \
- .value.uint = val, \
- },
-#define UUID128(val) { \
- .type = SDP_DTYPE_UUID | SDP_DSIZE_16, \
- .value.uint = val, \
- },
-#define SDP_TRUE { \
- .type = SDP_DTYPE_BOOL | SDP_DSIZE_1, \
- .value.uint = 1, \
- },
-#define SDP_FALSE { \
- .type = SDP_DTYPE_BOOL | SDP_DSIZE_1, \
- .value.uint = 0, \
- },
-#define STRING(val) { \
- .type = SDP_DTYPE_STRING, \
- .value.str = val, \
- },
-#define ARRAY(...) { \
- .type = SDP_DTYPE_STRING | SDP_DSIZE_2, \
- .value.str = (char []) { __VA_ARGS__, 0, 0 }, \
- },
-#define URL(val) { \
- .type = SDP_DTYPE_URL, \
- .value.str = val, \
- },
-#if 1
-#define LIST(val) { \
- .type = SDP_DTYPE_SEQ, \
- .value.list = (struct sdp_def_data_element_s []) { val LAST }, \
- },
-#endif
-
-/* Try to keep each single attribute below MAX_PDU_OUT_SIZE bytes
- * in resulting SDP data representation size. */
-
-SERVICE(hid,
- ATTRIBUTE(RECORD_HANDLE, UINT32(0)) /* Filled in later */
- ATTRIBUTE(SVCLASS_ID_LIST, LIST(UUID128(HID_SVCLASS_ID)))
- ATTRIBUTE(RECORD_STATE, UINT32(1))
- ATTRIBUTE(PROTO_DESC_LIST, LIST(
- LIST(UUID128(L2CAP_UUID) UINT16(BT_PSM_HID_CTRL))
- LIST(UUID128(HIDP_UUID))
- ))
- ATTRIBUTE(BROWSE_GRP_LIST, LIST(UUID128(0x1002)))
- ATTRIBUTE(LANG_BASE_ATTR_ID_LIST, LIST(
- UINT16(0x656e) UINT16(0x006a) UINT16(0x0100)
- ))
- ATTRIBUTE(PFILE_DESC_LIST, LIST(
- LIST(UUID128(HID_PROFILE_ID) UINT16(0x0100))
- ))
- ATTRIBUTE(DOC_URL, URL("http://bellard.org/qemu/user-doc.html"))
- ATTRIBUTE(SVCNAME_PRIMARY, STRING("QEMU Bluetooth HID"))
- ATTRIBUTE(SVCDESC_PRIMARY, STRING("QEMU Keyboard/Mouse"))
- ATTRIBUTE(SVCPROV_PRIMARY, STRING("QEMU"))
-
- /* Profile specific */
- ATTRIBUTE(DEVICE_RELEASE_NUMBER, UINT16(0x0091)) /* Deprecated, remove */
- ATTRIBUTE(PARSER_VERSION, UINT16(0x0111))
- /* TODO: extract from l2cap_device->device.class[0] */
- ATTRIBUTE(DEVICE_SUBCLASS, UINT8(0x40))
- ATTRIBUTE(COUNTRY_CODE, UINT8(0x15))
- ATTRIBUTE(VIRTUAL_CABLE, SDP_TRUE)
- ATTRIBUTE(RECONNECT_INITIATE, SDP_FALSE)
- /* TODO: extract from hid->usbdev->report_desc */
- ATTRIBUTE(DESCRIPTOR_LIST, LIST(
- LIST(UINT8(0x22) ARRAY(
- 0x05, 0x01, /* Usage Page (Generic Desktop) */
- 0x09, 0x06, /* Usage (Keyboard) */
- 0xa1, 0x01, /* Collection (Application) */
- 0x75, 0x01, /* Report Size (1) */
- 0x95, 0x08, /* Report Count (8) */
- 0x05, 0x07, /* Usage Page (Key Codes) */
- 0x19, 0xe0, /* Usage Minimum (224) */
- 0x29, 0xe7, /* Usage Maximum (231) */
- 0x15, 0x00, /* Logical Minimum (0) */
- 0x25, 0x01, /* Logical Maximum (1) */
- 0x81, 0x02, /* Input (Data, Variable, Absolute) */
- 0x95, 0x01, /* Report Count (1) */
- 0x75, 0x08, /* Report Size (8) */
- 0x81, 0x01, /* Input (Constant) */
- 0x95, 0x05, /* Report Count (5) */
- 0x75, 0x01, /* Report Size (1) */
- 0x05, 0x08, /* Usage Page (LEDs) */
- 0x19, 0x01, /* Usage Minimum (1) */
- 0x29, 0x05, /* Usage Maximum (5) */
- 0x91, 0x02, /* Output (Data, Variable, Absolute) */
- 0x95, 0x01, /* Report Count (1) */
- 0x75, 0x03, /* Report Size (3) */
- 0x91, 0x01, /* Output (Constant) */
- 0x95, 0x06, /* Report Count (6) */
- 0x75, 0x08, /* Report Size (8) */
- 0x15, 0x00, /* Logical Minimum (0) */
- 0x25, 0xff, /* Logical Maximum (255) */
- 0x05, 0x07, /* Usage Page (Key Codes) */
- 0x19, 0x00, /* Usage Minimum (0) */
- 0x29, 0xff, /* Usage Maximum (255) */
- 0x81, 0x00, /* Input (Data, Array) */
- 0xc0 /* End Collection */
- ))))
- ATTRIBUTE(LANG_ID_BASE_LIST, LIST(
- LIST(UINT16(0x0409) UINT16(0x0100))
- ))
- ATTRIBUTE(SDP_DISABLE, SDP_FALSE)
- ATTRIBUTE(BATTERY_POWER, SDP_TRUE)
- ATTRIBUTE(REMOTE_WAKEUP, SDP_TRUE)
- ATTRIBUTE(BOOT_DEVICE, SDP_TRUE) /* XXX: untested */
- ATTRIBUTE(SUPERVISION_TIMEOUT, UINT16(0x0c80))
- ATTRIBUTE(NORMALLY_CONNECTABLE, SDP_TRUE)
- ATTRIBUTE(PROFILE_VERSION, UINT16(0x0100))
-)
-
-SERVICE(sdp,
- ATTRIBUTE(RECORD_HANDLE, UINT32(0)) /* Filled in later */
- ATTRIBUTE(SVCLASS_ID_LIST, LIST(UUID128(SDP_SERVER_SVCLASS_ID)))
- ATTRIBUTE(RECORD_STATE, UINT32(1))
- ATTRIBUTE(PROTO_DESC_LIST, LIST(
- LIST(UUID128(L2CAP_UUID) UINT16(BT_PSM_SDP))
- LIST(UUID128(SDP_UUID))
- ))
- ATTRIBUTE(BROWSE_GRP_LIST, LIST(UUID128(0x1002)))
- ATTRIBUTE(LANG_BASE_ATTR_ID_LIST, LIST(
- UINT16(0x656e) UINT16(0x006a) UINT16(0x0100)
- ))
- ATTRIBUTE(PFILE_DESC_LIST, LIST(
- LIST(UUID128(SDP_SERVER_PROFILE_ID) UINT16(0x0100))
- ))
- ATTRIBUTE(DOC_URL, URL("http://bellard.org/qemu/user-doc.html"))
- ATTRIBUTE(SVCPROV_PRIMARY, STRING("QEMU"))
-
- /* Profile specific */
- ATTRIBUTE(VERSION_NUM_LIST, LIST(UINT16(0x0100)))
- ATTRIBUTE(SVCDB_STATE , UINT32(1))
-)
-
-SERVICE(pnp,
- ATTRIBUTE(RECORD_HANDLE, UINT32(0)) /* Filled in later */
- ATTRIBUTE(SVCLASS_ID_LIST, LIST(UUID128(PNP_INFO_SVCLASS_ID)))
- ATTRIBUTE(RECORD_STATE, UINT32(1))
- ATTRIBUTE(PROTO_DESC_LIST, LIST(
- LIST(UUID128(L2CAP_UUID) UINT16(BT_PSM_SDP))
- LIST(UUID128(SDP_UUID))
- ))
- ATTRIBUTE(BROWSE_GRP_LIST, LIST(UUID128(0x1002)))
- ATTRIBUTE(LANG_BASE_ATTR_ID_LIST, LIST(
- UINT16(0x656e) UINT16(0x006a) UINT16(0x0100)
- ))
- ATTRIBUTE(PFILE_DESC_LIST, LIST(
- LIST(UUID128(PNP_INFO_PROFILE_ID) UINT16(0x0100))
- ))
- ATTRIBUTE(DOC_URL, URL("http://bellard.org/qemu/user-doc.html"))
- ATTRIBUTE(SVCPROV_PRIMARY, STRING("QEMU"))
-
- /* Profile specific */
- ATTRIBUTE(SPECIFICATION_ID, UINT16(0x0100))
- ATTRIBUTE(VERSION, UINT16(0x0100))
- ATTRIBUTE(PRIMARY_RECORD, SDP_TRUE)
-)
-
-static int bt_l2cap_sdp_new_ch(struct bt_l2cap_device_s *dev,
- struct bt_l2cap_conn_params_s *params)
-{
- struct bt_l2cap_sdp_state_s *sdp = g_malloc0(sizeof(*sdp));
- struct sdp_def_service_s *services[] = {
- &sdp_service_sdp_s,
- &sdp_service_hid_s,
- &sdp_service_pnp_s,
- NULL,
- };
-
- sdp->channel = params;
- sdp->channel->opaque = sdp;
- sdp->channel->close = bt_l2cap_sdp_close_ch;
- sdp->channel->sdu_in = bt_l2cap_sdp_sdu_in;
-
- sdp_service_db_build(sdp, services);
-
- return 0;
-}
-
-void bt_l2cap_sdp_init(struct bt_l2cap_device_s *dev)
-{
- bt_l2cap_psm_register(dev, BT_PSM_SDP,
- MAX_PDU_OUT_SIZE, bt_l2cap_sdp_new_ch);
-}
diff --git a/qemu/hw/char/Makefile.objs b/qemu/hw/char/Makefile.objs
deleted file mode 100644
index 69a553cd8..000000000
--- a/qemu/hw/char/Makefile.objs
+++ /dev/null
@@ -1,30 +0,0 @@
-common-obj-$(CONFIG_IPACK) += ipoctal232.o
-common-obj-$(CONFIG_ESCC) += escc.o
-common-obj-$(CONFIG_PARALLEL) += parallel.o
-common-obj-$(CONFIG_PL011) += pl011.o
-common-obj-$(CONFIG_SERIAL) += serial.o serial-isa.o
-common-obj-$(CONFIG_SERIAL_PCI) += serial-pci.o
-common-obj-$(CONFIG_VIRTIO) += virtio-console.o
-common-obj-$(CONFIG_XILINX) += xilinx_uartlite.o
-common-obj-$(CONFIG_XEN_BACKEND) += xen_console.o
-common-obj-$(CONFIG_CADENCE) += cadence_uart.o
-
-obj-$(CONFIG_EXYNOS4) += exynos4210_uart.o
-obj-$(CONFIG_COLDFIRE) += mcf_uart.o
-obj-$(CONFIG_OMAP) += omap_uart.o
-obj-$(CONFIG_SH4) += sh_serial.o
-obj-$(CONFIG_PSERIES) += spapr_vty.o
-obj-$(CONFIG_DIGIC) += digic-uart.o
-obj-$(CONFIG_STM32F2XX_USART) += stm32f2xx_usart.o
-obj-$(CONFIG_RASPI) += bcm2835_aux.o
-
-common-obj-$(CONFIG_ETRAXFS) += etraxfs_ser.o
-common-obj-$(CONFIG_ISA_DEBUG) += debugcon.o
-common-obj-$(CONFIG_GRLIB) += grlib_apbuart.o
-common-obj-$(CONFIG_IMX) += imx_serial.o
-common-obj-$(CONFIG_LM32) += lm32_juart.o
-common-obj-$(CONFIG_LM32) += lm32_uart.o
-common-obj-$(CONFIG_MILKYMIST) += milkymist-uart.o
-common-obj-$(CONFIG_SCLPCONSOLE) += sclpconsole.o sclpconsole-lm.o
-
-obj-$(CONFIG_VIRTIO) += virtio-serial-bus.o
diff --git a/qemu/hw/char/bcm2835_aux.c b/qemu/hw/char/bcm2835_aux.c
deleted file mode 100644
index 0394d11a8..000000000
--- a/qemu/hw/char/bcm2835_aux.c
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- * BCM2835 (Raspberry Pi / Pi 2) Aux block (mini UART and SPI).
- * Copyright (c) 2015, Microsoft
- * Written by Andrew Baumann
- * Based on pl011.c, copyright terms below:
- *
- * Arm PrimeCell PL011 UART
- *
- * Copyright (c) 2006 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- *
- * At present only the core UART functions (data path for tx/rx) are
- * implemented. The following features/registers are unimplemented:
- * - Line/modem control
- * - Scratch register
- * - Extra control
- * - Baudrate
- * - SPI interfaces
- */
-
-#include "qemu/osdep.h"
-#include "hw/char/bcm2835_aux.h"
-
-#define AUX_IRQ 0x0
-#define AUX_ENABLES 0x4
-#define AUX_MU_IO_REG 0x40
-#define AUX_MU_IER_REG 0x44
-#define AUX_MU_IIR_REG 0x48
-#define AUX_MU_LCR_REG 0x4c
-#define AUX_MU_MCR_REG 0x50
-#define AUX_MU_LSR_REG 0x54
-#define AUX_MU_MSR_REG 0x58
-#define AUX_MU_SCRATCH 0x5c
-#define AUX_MU_CNTL_REG 0x60
-#define AUX_MU_STAT_REG 0x64
-#define AUX_MU_BAUD_REG 0x68
-
-/* bits in IER/IIR registers */
-#define TX_INT 0x1
-#define RX_INT 0x2
-
-static void bcm2835_aux_update(BCM2835AuxState *s)
-{
- /* signal an interrupt if either:
- * 1. rx interrupt is enabled and we have a non-empty rx fifo, or
- * 2. the tx interrupt is enabled (since we instantly drain the tx fifo)
- */
- s->iir = 0;
- if ((s->ier & RX_INT) && s->read_count != 0) {
- s->iir |= RX_INT;
- }
- if (s->ier & TX_INT) {
- s->iir |= TX_INT;
- }
- qemu_set_irq(s->irq, s->iir != 0);
-}
-
-static uint64_t bcm2835_aux_read(void *opaque, hwaddr offset, unsigned size)
-{
- BCM2835AuxState *s = opaque;
- uint32_t c, res;
-
- switch (offset) {
- case AUX_IRQ:
- return s->iir != 0;
-
- case AUX_ENABLES:
- return 1; /* mini UART permanently enabled */
-
- case AUX_MU_IO_REG:
- /* "DLAB bit set means access baudrate register" is NYI */
- c = s->read_fifo[s->read_pos];
- if (s->read_count > 0) {
- s->read_count--;
- if (++s->read_pos == BCM2835_AUX_RX_FIFO_LEN) {
- s->read_pos = 0;
- }
- }
- if (s->chr) {
- qemu_chr_accept_input(s->chr);
- }
- bcm2835_aux_update(s);
- return c;
-
- case AUX_MU_IER_REG:
- /* "DLAB bit set means access baudrate register" is NYI */
- return 0xc0 | s->ier; /* FIFO enables always read 1 */
-
- case AUX_MU_IIR_REG:
- res = 0xc0; /* FIFO enables */
- /* The spec is unclear on what happens when both tx and rx
- * interrupts are active, besides that this cannot occur. At
- * present, we choose to prioritise the rx interrupt, since
- * the tx fifo is always empty. */
- if (s->read_count != 0) {
- res |= 0x4;
- } else {
- res |= 0x2;
- }
- if (s->iir == 0) {
- res |= 0x1;
- }
- return res;
-
- case AUX_MU_LCR_REG:
- qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_LCR_REG unsupported\n", __func__);
- return 0;
-
- case AUX_MU_MCR_REG:
- qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_MCR_REG unsupported\n", __func__);
- return 0;
-
- case AUX_MU_LSR_REG:
- res = 0x60; /* tx idle, empty */
- if (s->read_count != 0) {
- res |= 0x1;
- }
- return res;
-
- case AUX_MU_MSR_REG:
- qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_MSR_REG unsupported\n", __func__);
- return 0;
-
- case AUX_MU_SCRATCH:
- qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_SCRATCH unsupported\n", __func__);
- return 0;
-
- case AUX_MU_CNTL_REG:
- return 0x3; /* tx, rx enabled */
-
- case AUX_MU_STAT_REG:
- res = 0x30e; /* space in the output buffer, empty tx fifo, idle tx/rx */
- if (s->read_count > 0) {
- res |= 0x1; /* data in input buffer */
- assert(s->read_count < BCM2835_AUX_RX_FIFO_LEN);
- res |= ((uint32_t)s->read_count) << 16; /* rx fifo fill level */
- }
- return res;
-
- case AUX_MU_BAUD_REG:
- qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_BAUD_REG unsupported\n", __func__);
- return 0;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
- __func__, offset);
- return 0;
- }
-}
-
-static void bcm2835_aux_write(void *opaque, hwaddr offset, uint64_t value,
- unsigned size)
-{
- BCM2835AuxState *s = opaque;
- unsigned char ch;
-
- switch (offset) {
- case AUX_ENABLES:
- if (value != 1) {
- qemu_log_mask(LOG_UNIMP, "%s: unsupported attempt to enable SPI "
- "or disable UART\n", __func__);
- }
- break;
-
- case AUX_MU_IO_REG:
- /* "DLAB bit set means access baudrate register" is NYI */
- ch = value;
- if (s->chr) {
- qemu_chr_fe_write(s->chr, &ch, 1);
- }
- break;
-
- case AUX_MU_IER_REG:
- /* "DLAB bit set means access baudrate register" is NYI */
- s->ier = value & (TX_INT | RX_INT);
- bcm2835_aux_update(s);
- break;
-
- case AUX_MU_IIR_REG:
- if (value & 0x2) {
- s->read_count = 0;
- }
- break;
-
- case AUX_MU_LCR_REG:
- qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_LCR_REG unsupported\n", __func__);
- break;
-
- case AUX_MU_MCR_REG:
- qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_MCR_REG unsupported\n", __func__);
- break;
-
- case AUX_MU_SCRATCH:
- qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_SCRATCH unsupported\n", __func__);
- break;
-
- case AUX_MU_CNTL_REG:
- qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_CNTL_REG unsupported\n", __func__);
- break;
-
- case AUX_MU_BAUD_REG:
- qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_BAUD_REG unsupported\n", __func__);
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
- __func__, offset);
- }
-
- bcm2835_aux_update(s);
-}
-
-static int bcm2835_aux_can_receive(void *opaque)
-{
- BCM2835AuxState *s = opaque;
-
- return s->read_count < BCM2835_AUX_RX_FIFO_LEN;
-}
-
-static void bcm2835_aux_put_fifo(void *opaque, uint8_t value)
-{
- BCM2835AuxState *s = opaque;
- int slot;
-
- slot = s->read_pos + s->read_count;
- if (slot >= BCM2835_AUX_RX_FIFO_LEN) {
- slot -= BCM2835_AUX_RX_FIFO_LEN;
- }
- s->read_fifo[slot] = value;
- s->read_count++;
- if (s->read_count == BCM2835_AUX_RX_FIFO_LEN) {
- /* buffer full */
- }
- bcm2835_aux_update(s);
-}
-
-static void bcm2835_aux_receive(void *opaque, const uint8_t *buf, int size)
-{
- bcm2835_aux_put_fifo(opaque, *buf);
-}
-
-static const MemoryRegionOps bcm2835_aux_ops = {
- .read = bcm2835_aux_read,
- .write = bcm2835_aux_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid.min_access_size = 4,
- .valid.max_access_size = 4,
-};
-
-static const VMStateDescription vmstate_bcm2835_aux = {
- .name = TYPE_BCM2835_AUX,
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8_ARRAY(read_fifo, BCM2835AuxState,
- BCM2835_AUX_RX_FIFO_LEN),
- VMSTATE_UINT8(read_pos, BCM2835AuxState),
- VMSTATE_UINT8(read_count, BCM2835AuxState),
- VMSTATE_UINT8(ier, BCM2835AuxState),
- VMSTATE_UINT8(iir, BCM2835AuxState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void bcm2835_aux_init(Object *obj)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- BCM2835AuxState *s = BCM2835_AUX(obj);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_aux_ops, s,
- TYPE_BCM2835_AUX, 0x100);
- sysbus_init_mmio(sbd, &s->iomem);
- sysbus_init_irq(sbd, &s->irq);
-}
-
-static void bcm2835_aux_realize(DeviceState *dev, Error **errp)
-{
- BCM2835AuxState *s = BCM2835_AUX(dev);
-
- if (s->chr) {
- qemu_chr_add_handlers(s->chr, bcm2835_aux_can_receive,
- bcm2835_aux_receive, NULL, s);
- }
-}
-
-static Property bcm2835_aux_props[] = {
- DEFINE_PROP_CHR("chardev", BCM2835AuxState, chr),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void bcm2835_aux_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- dc->realize = bcm2835_aux_realize;
- dc->vmsd = &vmstate_bcm2835_aux;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
- dc->props = bcm2835_aux_props;
-}
-
-static const TypeInfo bcm2835_aux_info = {
- .name = TYPE_BCM2835_AUX,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(BCM2835AuxState),
- .instance_init = bcm2835_aux_init,
- .class_init = bcm2835_aux_class_init,
-};
-
-static void bcm2835_aux_register_types(void)
-{
- type_register_static(&bcm2835_aux_info);
-}
-
-type_init(bcm2835_aux_register_types)
diff --git a/qemu/hw/char/cadence_uart.c b/qemu/hw/char/cadence_uart.c
deleted file mode 100644
index 797787823..000000000
--- a/qemu/hw/char/cadence_uart.c
+++ /dev/null
@@ -1,540 +0,0 @@
-/*
- * Device model for Cadence UART
- *
- * Copyright (c) 2010 Xilinx Inc.
- * Copyright (c) 2012 Peter A.G. Crosthwaite (peter.crosthwaite@petalogix.com)
- * Copyright (c) 2012 PetaLogix Pty Ltd.
- * Written by Haibing Ma
- * M.Habib
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/char/cadence_uart.h"
-
-#ifdef CADENCE_UART_ERR_DEBUG
-#define DB_PRINT(...) do { \
- fprintf(stderr, ": %s: ", __func__); \
- fprintf(stderr, ## __VA_ARGS__); \
- } while (0);
-#else
- #define DB_PRINT(...)
-#endif
-
-#define UART_SR_INTR_RTRIG 0x00000001
-#define UART_SR_INTR_REMPTY 0x00000002
-#define UART_SR_INTR_RFUL 0x00000004
-#define UART_SR_INTR_TEMPTY 0x00000008
-#define UART_SR_INTR_TFUL 0x00000010
-/* somewhat awkwardly, TTRIG is misaligned between SR and ISR */
-#define UART_SR_TTRIG 0x00002000
-#define UART_INTR_TTRIG 0x00000400
-/* bits fields in CSR that correlate to CISR. If any of these bits are set in
- * SR, then the same bit in CISR is set high too */
-#define UART_SR_TO_CISR_MASK 0x0000001F
-
-#define UART_INTR_ROVR 0x00000020
-#define UART_INTR_FRAME 0x00000040
-#define UART_INTR_PARE 0x00000080
-#define UART_INTR_TIMEOUT 0x00000100
-#define UART_INTR_DMSI 0x00000200
-#define UART_INTR_TOVR 0x00001000
-
-#define UART_SR_RACTIVE 0x00000400
-#define UART_SR_TACTIVE 0x00000800
-#define UART_SR_FDELT 0x00001000
-
-#define UART_CR_RXRST 0x00000001
-#define UART_CR_TXRST 0x00000002
-#define UART_CR_RX_EN 0x00000004
-#define UART_CR_RX_DIS 0x00000008
-#define UART_CR_TX_EN 0x00000010
-#define UART_CR_TX_DIS 0x00000020
-#define UART_CR_RST_TO 0x00000040
-#define UART_CR_STARTBRK 0x00000080
-#define UART_CR_STOPBRK 0x00000100
-
-#define UART_MR_CLKS 0x00000001
-#define UART_MR_CHRL 0x00000006
-#define UART_MR_CHRL_SH 1
-#define UART_MR_PAR 0x00000038
-#define UART_MR_PAR_SH 3
-#define UART_MR_NBSTOP 0x000000C0
-#define UART_MR_NBSTOP_SH 6
-#define UART_MR_CHMODE 0x00000300
-#define UART_MR_CHMODE_SH 8
-#define UART_MR_UCLKEN 0x00000400
-#define UART_MR_IRMODE 0x00000800
-
-#define UART_DATA_BITS_6 (0x3 << UART_MR_CHRL_SH)
-#define UART_DATA_BITS_7 (0x2 << UART_MR_CHRL_SH)
-#define UART_PARITY_ODD (0x1 << UART_MR_PAR_SH)
-#define UART_PARITY_EVEN (0x0 << UART_MR_PAR_SH)
-#define UART_STOP_BITS_1 (0x3 << UART_MR_NBSTOP_SH)
-#define UART_STOP_BITS_2 (0x2 << UART_MR_NBSTOP_SH)
-#define NORMAL_MODE (0x0 << UART_MR_CHMODE_SH)
-#define ECHO_MODE (0x1 << UART_MR_CHMODE_SH)
-#define LOCAL_LOOPBACK (0x2 << UART_MR_CHMODE_SH)
-#define REMOTE_LOOPBACK (0x3 << UART_MR_CHMODE_SH)
-
-#define UART_INPUT_CLK 50000000
-
-#define R_CR (0x00/4)
-#define R_MR (0x04/4)
-#define R_IER (0x08/4)
-#define R_IDR (0x0C/4)
-#define R_IMR (0x10/4)
-#define R_CISR (0x14/4)
-#define R_BRGR (0x18/4)
-#define R_RTOR (0x1C/4)
-#define R_RTRIG (0x20/4)
-#define R_MCR (0x24/4)
-#define R_MSR (0x28/4)
-#define R_SR (0x2C/4)
-#define R_TX_RX (0x30/4)
-#define R_BDIV (0x34/4)
-#define R_FDEL (0x38/4)
-#define R_PMIN (0x3C/4)
-#define R_PWID (0x40/4)
-#define R_TTRIG (0x44/4)
-
-
-static void uart_update_status(CadenceUARTState *s)
-{
- s->r[R_SR] = 0;
-
- s->r[R_SR] |= s->rx_count == CADENCE_UART_RX_FIFO_SIZE ? UART_SR_INTR_RFUL
- : 0;
- s->r[R_SR] |= !s->rx_count ? UART_SR_INTR_REMPTY : 0;
- s->r[R_SR] |= s->rx_count >= s->r[R_RTRIG] ? UART_SR_INTR_RTRIG : 0;
-
- s->r[R_SR] |= s->tx_count == CADENCE_UART_TX_FIFO_SIZE ? UART_SR_INTR_TFUL
- : 0;
- s->r[R_SR] |= !s->tx_count ? UART_SR_INTR_TEMPTY : 0;
- s->r[R_SR] |= s->tx_count >= s->r[R_TTRIG] ? UART_SR_TTRIG : 0;
-
- s->r[R_CISR] |= s->r[R_SR] & UART_SR_TO_CISR_MASK;
- s->r[R_CISR] |= s->r[R_SR] & UART_SR_TTRIG ? UART_INTR_TTRIG : 0;
- qemu_set_irq(s->irq, !!(s->r[R_IMR] & s->r[R_CISR]));
-}
-
-static void fifo_trigger_update(void *opaque)
-{
- CadenceUARTState *s = opaque;
-
- s->r[R_CISR] |= UART_INTR_TIMEOUT;
-
- uart_update_status(s);
-}
-
-static void uart_rx_reset(CadenceUARTState *s)
-{
- s->rx_wpos = 0;
- s->rx_count = 0;
- if (s->chr) {
- qemu_chr_accept_input(s->chr);
- }
-}
-
-static void uart_tx_reset(CadenceUARTState *s)
-{
- s->tx_count = 0;
-}
-
-static void uart_send_breaks(CadenceUARTState *s)
-{
- int break_enabled = 1;
-
- if (s->chr) {
- qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_BREAK,
- &break_enabled);
- }
-}
-
-static void uart_parameters_setup(CadenceUARTState *s)
-{
- QEMUSerialSetParams ssp;
- unsigned int baud_rate, packet_size;
-
- baud_rate = (s->r[R_MR] & UART_MR_CLKS) ?
- UART_INPUT_CLK / 8 : UART_INPUT_CLK;
-
- ssp.speed = baud_rate / (s->r[R_BRGR] * (s->r[R_BDIV] + 1));
- packet_size = 1;
-
- switch (s->r[R_MR] & UART_MR_PAR) {
- case UART_PARITY_EVEN:
- ssp.parity = 'E';
- packet_size++;
- break;
- case UART_PARITY_ODD:
- ssp.parity = 'O';
- packet_size++;
- break;
- default:
- ssp.parity = 'N';
- break;
- }
-
- switch (s->r[R_MR] & UART_MR_CHRL) {
- case UART_DATA_BITS_6:
- ssp.data_bits = 6;
- break;
- case UART_DATA_BITS_7:
- ssp.data_bits = 7;
- break;
- default:
- ssp.data_bits = 8;
- break;
- }
-
- switch (s->r[R_MR] & UART_MR_NBSTOP) {
- case UART_STOP_BITS_1:
- ssp.stop_bits = 1;
- break;
- default:
- ssp.stop_bits = 2;
- break;
- }
-
- packet_size += ssp.data_bits + ssp.stop_bits;
- s->char_tx_time = (NANOSECONDS_PER_SECOND / ssp.speed) * packet_size;
- if (s->chr) {
- qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
- }
-}
-
-static int uart_can_receive(void *opaque)
-{
- CadenceUARTState *s = opaque;
- int ret = MAX(CADENCE_UART_RX_FIFO_SIZE, CADENCE_UART_TX_FIFO_SIZE);
- uint32_t ch_mode = s->r[R_MR] & UART_MR_CHMODE;
-
- if (ch_mode == NORMAL_MODE || ch_mode == ECHO_MODE) {
- ret = MIN(ret, CADENCE_UART_RX_FIFO_SIZE - s->rx_count);
- }
- if (ch_mode == REMOTE_LOOPBACK || ch_mode == ECHO_MODE) {
- ret = MIN(ret, CADENCE_UART_TX_FIFO_SIZE - s->tx_count);
- }
- return ret;
-}
-
-static void uart_ctrl_update(CadenceUARTState *s)
-{
- if (s->r[R_CR] & UART_CR_TXRST) {
- uart_tx_reset(s);
- }
-
- if (s->r[R_CR] & UART_CR_RXRST) {
- uart_rx_reset(s);
- }
-
- s->r[R_CR] &= ~(UART_CR_TXRST | UART_CR_RXRST);
-
- if (s->r[R_CR] & UART_CR_STARTBRK && !(s->r[R_CR] & UART_CR_STOPBRK)) {
- uart_send_breaks(s);
- }
-}
-
-static void uart_write_rx_fifo(void *opaque, const uint8_t *buf, int size)
-{
- CadenceUARTState *s = opaque;
- uint64_t new_rx_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- int i;
-
- if ((s->r[R_CR] & UART_CR_RX_DIS) || !(s->r[R_CR] & UART_CR_RX_EN)) {
- return;
- }
-
- if (s->rx_count == CADENCE_UART_RX_FIFO_SIZE) {
- s->r[R_CISR] |= UART_INTR_ROVR;
- } else {
- for (i = 0; i < size; i++) {
- s->rx_fifo[s->rx_wpos] = buf[i];
- s->rx_wpos = (s->rx_wpos + 1) % CADENCE_UART_RX_FIFO_SIZE;
- s->rx_count++;
- }
- timer_mod(s->fifo_trigger_handle, new_rx_time +
- (s->char_tx_time * 4));
- }
- uart_update_status(s);
-}
-
-static gboolean cadence_uart_xmit(GIOChannel *chan, GIOCondition cond,
- void *opaque)
-{
- CadenceUARTState *s = opaque;
- int ret;
-
- /* instant drain the fifo when there's no back-end */
- if (!s->chr) {
- s->tx_count = 0;
- return FALSE;
- }
-
- if (!s->tx_count) {
- return FALSE;
- }
-
- ret = qemu_chr_fe_write(s->chr, s->tx_fifo, s->tx_count);
- s->tx_count -= ret;
- memmove(s->tx_fifo, s->tx_fifo + ret, s->tx_count);
-
- if (s->tx_count) {
- int r = qemu_chr_fe_add_watch(s->chr, G_IO_OUT|G_IO_HUP,
- cadence_uart_xmit, s);
- assert(r);
- }
-
- uart_update_status(s);
- return FALSE;
-}
-
-static void uart_write_tx_fifo(CadenceUARTState *s, const uint8_t *buf,
- int size)
-{
- if ((s->r[R_CR] & UART_CR_TX_DIS) || !(s->r[R_CR] & UART_CR_TX_EN)) {
- return;
- }
-
- if (size > CADENCE_UART_TX_FIFO_SIZE - s->tx_count) {
- size = CADENCE_UART_TX_FIFO_SIZE - s->tx_count;
- /*
- * This can only be a guest error via a bad tx fifo register push,
- * as can_receive() should stop remote loop and echo modes ever getting
- * us to here.
- */
- qemu_log_mask(LOG_GUEST_ERROR, "cadence_uart: TxFIFO overflow");
- s->r[R_CISR] |= UART_INTR_ROVR;
- }
-
- memcpy(s->tx_fifo + s->tx_count, buf, size);
- s->tx_count += size;
-
- cadence_uart_xmit(NULL, G_IO_OUT, s);
-}
-
-static void uart_receive(void *opaque, const uint8_t *buf, int size)
-{
- CadenceUARTState *s = opaque;
- uint32_t ch_mode = s->r[R_MR] & UART_MR_CHMODE;
-
- if (ch_mode == NORMAL_MODE || ch_mode == ECHO_MODE) {
- uart_write_rx_fifo(opaque, buf, size);
- }
- if (ch_mode == REMOTE_LOOPBACK || ch_mode == ECHO_MODE) {
- uart_write_tx_fifo(s, buf, size);
- }
-}
-
-static void uart_event(void *opaque, int event)
-{
- CadenceUARTState *s = opaque;
- uint8_t buf = '\0';
-
- if (event == CHR_EVENT_BREAK) {
- uart_write_rx_fifo(opaque, &buf, 1);
- }
-
- uart_update_status(s);
-}
-
-static void uart_read_rx_fifo(CadenceUARTState *s, uint32_t *c)
-{
- if ((s->r[R_CR] & UART_CR_RX_DIS) || !(s->r[R_CR] & UART_CR_RX_EN)) {
- return;
- }
-
- if (s->rx_count) {
- uint32_t rx_rpos = (CADENCE_UART_RX_FIFO_SIZE + s->rx_wpos -
- s->rx_count) % CADENCE_UART_RX_FIFO_SIZE;
- *c = s->rx_fifo[rx_rpos];
- s->rx_count--;
-
- if (s->chr) {
- qemu_chr_accept_input(s->chr);
- }
- } else {
- *c = 0;
- }
-
- uart_update_status(s);
-}
-
-static void uart_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- CadenceUARTState *s = opaque;
-
- DB_PRINT(" offset:%x data:%08x\n", (unsigned)offset, (unsigned)value);
- offset >>= 2;
- if (offset >= CADENCE_UART_R_MAX) {
- return;
- }
- switch (offset) {
- case R_IER: /* ier (wts imr) */
- s->r[R_IMR] |= value;
- break;
- case R_IDR: /* idr (wtc imr) */
- s->r[R_IMR] &= ~value;
- break;
- case R_IMR: /* imr (read only) */
- break;
- case R_CISR: /* cisr (wtc) */
- s->r[R_CISR] &= ~value;
- break;
- case R_TX_RX: /* UARTDR */
- switch (s->r[R_MR] & UART_MR_CHMODE) {
- case NORMAL_MODE:
- uart_write_tx_fifo(s, (uint8_t *) &value, 1);
- break;
- case LOCAL_LOOPBACK:
- uart_write_rx_fifo(opaque, (uint8_t *) &value, 1);
- break;
- }
- break;
- default:
- s->r[offset] = value;
- }
-
- switch (offset) {
- case R_CR:
- uart_ctrl_update(s);
- break;
- case R_MR:
- uart_parameters_setup(s);
- break;
- }
- uart_update_status(s);
-}
-
-static uint64_t uart_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- CadenceUARTState *s = opaque;
- uint32_t c = 0;
-
- offset >>= 2;
- if (offset >= CADENCE_UART_R_MAX) {
- c = 0;
- } else if (offset == R_TX_RX) {
- uart_read_rx_fifo(s, &c);
- } else {
- c = s->r[offset];
- }
-
- DB_PRINT(" offset:%x data:%08x\n", (unsigned)(offset << 2), (unsigned)c);
- return c;
-}
-
-static const MemoryRegionOps uart_ops = {
- .read = uart_read,
- .write = uart_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void cadence_uart_reset(DeviceState *dev)
-{
- CadenceUARTState *s = CADENCE_UART(dev);
-
- s->r[R_CR] = 0x00000128;
- s->r[R_IMR] = 0;
- s->r[R_CISR] = 0;
- s->r[R_RTRIG] = 0x00000020;
- s->r[R_BRGR] = 0x0000000F;
- s->r[R_TTRIG] = 0x00000020;
-
- uart_rx_reset(s);
- uart_tx_reset(s);
-
- uart_update_status(s);
-}
-
-static void cadence_uart_realize(DeviceState *dev, Error **errp)
-{
- CadenceUARTState *s = CADENCE_UART(dev);
-
- s->fifo_trigger_handle = timer_new_ns(QEMU_CLOCK_VIRTUAL,
- fifo_trigger_update, s);
-
- /* FIXME use a qdev chardev prop instead of qemu_char_get_next_serial() */
- s->chr = qemu_char_get_next_serial();
-
- if (s->chr) {
- qemu_chr_add_handlers(s->chr, uart_can_receive, uart_receive,
- uart_event, s);
- }
-}
-
-static void cadence_uart_init(Object *obj)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- CadenceUARTState *s = CADENCE_UART(obj);
-
- memory_region_init_io(&s->iomem, obj, &uart_ops, s, "uart", 0x1000);
- sysbus_init_mmio(sbd, &s->iomem);
- sysbus_init_irq(sbd, &s->irq);
-
- s->char_tx_time = (NANOSECONDS_PER_SECOND / 9600) * 10;
-}
-
-static int cadence_uart_post_load(void *opaque, int version_id)
-{
- CadenceUARTState *s = opaque;
-
- uart_parameters_setup(s);
- uart_update_status(s);
- return 0;
-}
-
-static const VMStateDescription vmstate_cadence_uart = {
- .name = "cadence_uart",
- .version_id = 2,
- .minimum_version_id = 2,
- .post_load = cadence_uart_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(r, CadenceUARTState, CADENCE_UART_R_MAX),
- VMSTATE_UINT8_ARRAY(rx_fifo, CadenceUARTState,
- CADENCE_UART_RX_FIFO_SIZE),
- VMSTATE_UINT8_ARRAY(tx_fifo, CadenceUARTState,
- CADENCE_UART_TX_FIFO_SIZE),
- VMSTATE_UINT32(rx_count, CadenceUARTState),
- VMSTATE_UINT32(tx_count, CadenceUARTState),
- VMSTATE_UINT32(rx_wpos, CadenceUARTState),
- VMSTATE_TIMER_PTR(fifo_trigger_handle, CadenceUARTState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void cadence_uart_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = cadence_uart_realize;
- dc->vmsd = &vmstate_cadence_uart;
- dc->reset = cadence_uart_reset;
- /* Reason: realize() method uses qemu_char_get_next_serial() */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo cadence_uart_info = {
- .name = TYPE_CADENCE_UART,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(CadenceUARTState),
- .instance_init = cadence_uart_init,
- .class_init = cadence_uart_class_init,
-};
-
-static void cadence_uart_register_types(void)
-{
- type_register_static(&cadence_uart_info);
-}
-
-type_init(cadence_uart_register_types)
diff --git a/qemu/hw/char/debugcon.c b/qemu/hw/char/debugcon.c
deleted file mode 100644
index e7f025ec6..000000000
--- a/qemu/hw/char/debugcon.c
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * QEMU Bochs-style debug console ("port E9") emulation
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- * Copyright (c) 2008 Citrix Systems, Inc.
- * Copyright (c) Intel Corporation; author: H. Peter Anvin
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/hw.h"
-#include "sysemu/char.h"
-#include "hw/isa/isa.h"
-#include "hw/i386/pc.h"
-
-#define TYPE_ISA_DEBUGCON_DEVICE "isa-debugcon"
-#define ISA_DEBUGCON_DEVICE(obj) \
- OBJECT_CHECK(ISADebugconState, (obj), TYPE_ISA_DEBUGCON_DEVICE)
-
-//#define DEBUG_DEBUGCON
-
-typedef struct DebugconState {
- MemoryRegion io;
- CharDriverState *chr;
- uint32_t readback;
-} DebugconState;
-
-typedef struct ISADebugconState {
- ISADevice parent_obj;
-
- uint32_t iobase;
- DebugconState state;
-} ISADebugconState;
-
-static void debugcon_ioport_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned width)
-{
- DebugconState *s = opaque;
- unsigned char ch = val;
-
-#ifdef DEBUG_DEBUGCON
- printf(" [debugcon: write addr=0x%04" HWADDR_PRIx " val=0x%02" PRIx64 "]\n", addr, val);
-#endif
-
- qemu_chr_fe_write(s->chr, &ch, 1);
-}
-
-
-static uint64_t debugcon_ioport_read(void *opaque, hwaddr addr, unsigned width)
-{
- DebugconState *s = opaque;
-
-#ifdef DEBUG_DEBUGCON
- printf("debugcon: read addr=0x%04" HWADDR_PRIx "\n", addr);
-#endif
-
- return s->readback;
-}
-
-static const MemoryRegionOps debugcon_ops = {
- .read = debugcon_ioport_read,
- .write = debugcon_ioport_write,
- .valid.min_access_size = 1,
- .valid.max_access_size = 1,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void debugcon_realize_core(DebugconState *s, Error **errp)
-{
- if (!s->chr) {
- error_setg(errp, "Can't create debugcon device, empty char device");
- return;
- }
-
- qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, s);
-}
-
-static void debugcon_isa_realizefn(DeviceState *dev, Error **errp)
-{
- ISADevice *d = ISA_DEVICE(dev);
- ISADebugconState *isa = ISA_DEBUGCON_DEVICE(dev);
- DebugconState *s = &isa->state;
- Error *err = NULL;
-
- debugcon_realize_core(s, &err);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
- memory_region_init_io(&s->io, OBJECT(dev), &debugcon_ops, s,
- TYPE_ISA_DEBUGCON_DEVICE, 1);
- memory_region_add_subregion(isa_address_space_io(d),
- isa->iobase, &s->io);
-}
-
-static Property debugcon_isa_properties[] = {
- DEFINE_PROP_UINT32("iobase", ISADebugconState, iobase, 0xe9),
- DEFINE_PROP_CHR("chardev", ISADebugconState, state.chr),
- DEFINE_PROP_UINT32("readback", ISADebugconState, state.readback, 0xe9),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void debugcon_isa_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = debugcon_isa_realizefn;
- dc->props = debugcon_isa_properties;
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
-}
-
-static const TypeInfo debugcon_isa_info = {
- .name = TYPE_ISA_DEBUGCON_DEVICE,
- .parent = TYPE_ISA_DEVICE,
- .instance_size = sizeof(ISADebugconState),
- .class_init = debugcon_isa_class_initfn,
-};
-
-static void debugcon_register_types(void)
-{
- type_register_static(&debugcon_isa_info);
-}
-
-type_init(debugcon_register_types)
diff --git a/qemu/hw/char/digic-uart.c b/qemu/hw/char/digic-uart.c
deleted file mode 100644
index d3bc533d7..000000000
--- a/qemu/hw/char/digic-uart.c
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * QEMU model of the Canon DIGIC UART block.
- *
- * Copyright (C) 2013 Antony Pavlov <antonynpavlov@gmail.com>
- *
- * This model is based on reverse engineering efforts
- * made by CHDK (http://chdk.wikia.com) and
- * Magic Lantern (http://www.magiclantern.fm) projects
- * contributors.
- *
- * See "Serial terminal" docs here:
- * http://magiclantern.wikia.com/wiki/Register_Map#Misc_Registers
- *
- * The QEMU model of the Milkymist UART block by Michael Walle
- * is used as a template.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "sysemu/char.h"
-
-#include "hw/char/digic-uart.h"
-
-enum {
- ST_RX_RDY = (1 << 0),
- ST_TX_RDY = (1 << 1),
-};
-
-static uint64_t digic_uart_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- DigicUartState *s = opaque;
- uint64_t ret = 0;
-
- addr >>= 2;
-
- switch (addr) {
- case R_RX:
- s->reg_st &= ~(ST_RX_RDY);
- ret = s->reg_rx;
- break;
-
- case R_ST:
- ret = s->reg_st;
- break;
-
- default:
- qemu_log_mask(LOG_UNIMP,
- "digic-uart: read access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- }
-
- return ret;
-}
-
-static void digic_uart_write(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
- DigicUartState *s = opaque;
- unsigned char ch = value;
-
- addr >>= 2;
-
- switch (addr) {
- case R_TX:
- if (s->chr) {
- qemu_chr_fe_write_all(s->chr, &ch, 1);
- }
- break;
-
- case R_ST:
- /*
- * Ignore write to R_ST.
- *
- * The point is that this register is actively used
- * during receiving and transmitting symbols,
- * but we don't know the function of most of bits.
- *
- * Ignoring writes to R_ST is only a simplification
- * of the model. It has no perceptible side effects
- * for existing guests.
- */
- break;
-
- default:
- qemu_log_mask(LOG_UNIMP,
- "digic-uart: write access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- }
-}
-
-static const MemoryRegionOps uart_mmio_ops = {
- .read = digic_uart_read,
- .write = digic_uart_write,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int uart_can_rx(void *opaque)
-{
- DigicUartState *s = opaque;
-
- return !(s->reg_st & ST_RX_RDY);
-}
-
-static void uart_rx(void *opaque, const uint8_t *buf, int size)
-{
- DigicUartState *s = opaque;
-
- assert(uart_can_rx(opaque));
-
- s->reg_st |= ST_RX_RDY;
- s->reg_rx = *buf;
-}
-
-static void uart_event(void *opaque, int event)
-{
-}
-
-static void digic_uart_reset(DeviceState *d)
-{
- DigicUartState *s = DIGIC_UART(d);
-
- s->reg_rx = 0;
- s->reg_st = ST_TX_RDY;
-}
-
-static void digic_uart_realize(DeviceState *dev, Error **errp)
-{
- DigicUartState *s = DIGIC_UART(dev);
-
- /* FIXME use a qdev chardev prop instead of qemu_char_get_next_serial() */
- s->chr = qemu_char_get_next_serial();
- if (s->chr) {
- qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
- }
-}
-
-static void digic_uart_init(Object *obj)
-{
- DigicUartState *s = DIGIC_UART(obj);
-
- memory_region_init_io(&s->regs_region, OBJECT(s), &uart_mmio_ops, s,
- TYPE_DIGIC_UART, 0x18);
- sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->regs_region);
-}
-
-static const VMStateDescription vmstate_digic_uart = {
- .name = "digic-uart",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(reg_rx, DigicUartState),
- VMSTATE_UINT32(reg_st, DigicUartState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void digic_uart_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = digic_uart_realize;
- dc->reset = digic_uart_reset;
- dc->vmsd = &vmstate_digic_uart;
- /* Reason: realize() method uses qemu_char_get_next_serial() */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo digic_uart_info = {
- .name = TYPE_DIGIC_UART,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(DigicUartState),
- .instance_init = digic_uart_init,
- .class_init = digic_uart_class_init,
-};
-
-static void digic_uart_register_types(void)
-{
- type_register_static(&digic_uart_info);
-}
-
-type_init(digic_uart_register_types)
diff --git a/qemu/hw/char/escc.c b/qemu/hw/char/escc.c
deleted file mode 100644
index 7bf09a007..000000000
--- a/qemu/hw/char/escc.c
+++ /dev/null
@@ -1,1056 +0,0 @@
-/*
- * QEMU ESCC (Z8030/Z8530/Z85C30/SCC/ESCC) serial port emulation
- *
- * Copyright (c) 2003-2005 Fabrice Bellard
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "hw/char/escc.h"
-#include "sysemu/char.h"
-#include "ui/console.h"
-#include "ui/input.h"
-#include "trace.h"
-
-/*
- * Chipset docs:
- * "Z80C30/Z85C30/Z80230/Z85230/Z85233 SCC/ESCC User Manual",
- * http://www.zilog.com/docs/serial/scc_escc_um.pdf
- *
- * On Sparc32 this is the serial port, mouse and keyboard part of chip STP2001
- * (Slave I/O), also produced as NCR89C105. See
- * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
- *
- * The serial ports implement full AMD AM8530 or Zilog Z8530 chips,
- * mouse and keyboard ports don't implement all functions and they are
- * only asynchronous. There is no DMA.
- *
- * Z85C30 is also used on PowerMacs. There are some small differences
- * between Sparc version (sunzilog) and PowerMac (pmac):
- * Offset between control and data registers
- * There is some kind of lockup bug, but we can ignore it
- * CTS is inverted
- * DMA on pmac using DBDMA chip
- * pmac can do IRDA and faster rates, sunzilog can only do 38400
- * pmac baud rate generator clock is 3.6864 MHz, sunzilog 4.9152 MHz
- */
-
-/*
- * Modifications:
- * 2006-Aug-10 Igor Kovalenko : Renamed KBDQueue to SERIOQueue, implemented
- * serial mouse queue.
- * Implemented serial mouse protocol.
- *
- * 2010-May-23 Artyom Tarasenko: Reworked IUS logic
- */
-
-typedef enum {
- chn_a, chn_b,
-} ChnID;
-
-#define CHN_C(s) ((s)->chn == chn_b? 'b' : 'a')
-
-typedef enum {
- ser, kbd, mouse,
-} ChnType;
-
-#define SERIO_QUEUE_SIZE 256
-
-typedef struct {
- uint8_t data[SERIO_QUEUE_SIZE];
- int rptr, wptr, count;
-} SERIOQueue;
-
-#define SERIAL_REGS 16
-typedef struct ChannelState {
- qemu_irq irq;
- uint32_t rxint, txint, rxint_under_svc, txint_under_svc;
- struct ChannelState *otherchn;
- uint32_t reg;
- uint8_t wregs[SERIAL_REGS], rregs[SERIAL_REGS];
- SERIOQueue queue;
- CharDriverState *chr;
- int e0_mode, led_mode, caps_lock_mode, num_lock_mode;
- int disabled;
- int clock;
- uint32_t vmstate_dummy;
- ChnID chn; // this channel, A (base+4) or B (base+0)
- ChnType type;
- uint8_t rx, tx;
- QemuInputHandlerState *hs;
-} ChannelState;
-
-#define ESCC(obj) OBJECT_CHECK(ESCCState, (obj), TYPE_ESCC)
-
-typedef struct ESCCState {
- SysBusDevice parent_obj;
-
- struct ChannelState chn[2];
- uint32_t it_shift;
- MemoryRegion mmio;
- uint32_t disabled;
- uint32_t frequency;
-} ESCCState;
-
-#define SERIAL_CTRL 0
-#define SERIAL_DATA 1
-
-#define W_CMD 0
-#define CMD_PTR_MASK 0x07
-#define CMD_CMD_MASK 0x38
-#define CMD_HI 0x08
-#define CMD_CLR_TXINT 0x28
-#define CMD_CLR_IUS 0x38
-#define W_INTR 1
-#define INTR_INTALL 0x01
-#define INTR_TXINT 0x02
-#define INTR_RXMODEMSK 0x18
-#define INTR_RXINT1ST 0x08
-#define INTR_RXINTALL 0x10
-#define W_IVEC 2
-#define W_RXCTRL 3
-#define RXCTRL_RXEN 0x01
-#define W_TXCTRL1 4
-#define TXCTRL1_PAREN 0x01
-#define TXCTRL1_PAREV 0x02
-#define TXCTRL1_1STOP 0x04
-#define TXCTRL1_1HSTOP 0x08
-#define TXCTRL1_2STOP 0x0c
-#define TXCTRL1_STPMSK 0x0c
-#define TXCTRL1_CLK1X 0x00
-#define TXCTRL1_CLK16X 0x40
-#define TXCTRL1_CLK32X 0x80
-#define TXCTRL1_CLK64X 0xc0
-#define TXCTRL1_CLKMSK 0xc0
-#define W_TXCTRL2 5
-#define TXCTRL2_TXEN 0x08
-#define TXCTRL2_BITMSK 0x60
-#define TXCTRL2_5BITS 0x00
-#define TXCTRL2_7BITS 0x20
-#define TXCTRL2_6BITS 0x40
-#define TXCTRL2_8BITS 0x60
-#define W_SYNC1 6
-#define W_SYNC2 7
-#define W_TXBUF 8
-#define W_MINTR 9
-#define MINTR_STATUSHI 0x10
-#define MINTR_RST_MASK 0xc0
-#define MINTR_RST_B 0x40
-#define MINTR_RST_A 0x80
-#define MINTR_RST_ALL 0xc0
-#define W_MISC1 10
-#define W_CLOCK 11
-#define CLOCK_TRXC 0x08
-#define W_BRGLO 12
-#define W_BRGHI 13
-#define W_MISC2 14
-#define MISC2_PLLDIS 0x30
-#define W_EXTINT 15
-#define EXTINT_DCD 0x08
-#define EXTINT_SYNCINT 0x10
-#define EXTINT_CTSINT 0x20
-#define EXTINT_TXUNDRN 0x40
-#define EXTINT_BRKINT 0x80
-
-#define R_STATUS 0
-#define STATUS_RXAV 0x01
-#define STATUS_ZERO 0x02
-#define STATUS_TXEMPTY 0x04
-#define STATUS_DCD 0x08
-#define STATUS_SYNC 0x10
-#define STATUS_CTS 0x20
-#define STATUS_TXUNDRN 0x40
-#define STATUS_BRK 0x80
-#define R_SPEC 1
-#define SPEC_ALLSENT 0x01
-#define SPEC_BITS8 0x06
-#define R_IVEC 2
-#define IVEC_TXINTB 0x00
-#define IVEC_LONOINT 0x06
-#define IVEC_LORXINTA 0x0c
-#define IVEC_LORXINTB 0x04
-#define IVEC_LOTXINTA 0x08
-#define IVEC_HINOINT 0x60
-#define IVEC_HIRXINTA 0x30
-#define IVEC_HIRXINTB 0x20
-#define IVEC_HITXINTA 0x10
-#define R_INTR 3
-#define INTR_EXTINTB 0x01
-#define INTR_TXINTB 0x02
-#define INTR_RXINTB 0x04
-#define INTR_EXTINTA 0x08
-#define INTR_TXINTA 0x10
-#define INTR_RXINTA 0x20
-#define R_IPEN 4
-#define R_TXCTRL1 5
-#define R_TXCTRL2 6
-#define R_BC 7
-#define R_RXBUF 8
-#define R_RXCTRL 9
-#define R_MISC 10
-#define R_MISC1 11
-#define R_BRGLO 12
-#define R_BRGHI 13
-#define R_MISC1I 14
-#define R_EXTINT 15
-
-static void handle_kbd_command(ChannelState *s, int val);
-static int serial_can_receive(void *opaque);
-static void serial_receive_byte(ChannelState *s, int ch);
-
-static void clear_queue(void *opaque)
-{
- ChannelState *s = opaque;
- SERIOQueue *q = &s->queue;
- q->rptr = q->wptr = q->count = 0;
-}
-
-static void put_queue(void *opaque, int b)
-{
- ChannelState *s = opaque;
- SERIOQueue *q = &s->queue;
-
- trace_escc_put_queue(CHN_C(s), b);
- if (q->count >= SERIO_QUEUE_SIZE)
- return;
- q->data[q->wptr] = b;
- if (++q->wptr == SERIO_QUEUE_SIZE)
- q->wptr = 0;
- q->count++;
- serial_receive_byte(s, 0);
-}
-
-static uint32_t get_queue(void *opaque)
-{
- ChannelState *s = opaque;
- SERIOQueue *q = &s->queue;
- int val;
-
- if (q->count == 0) {
- return 0;
- } else {
- val = q->data[q->rptr];
- if (++q->rptr == SERIO_QUEUE_SIZE)
- q->rptr = 0;
- q->count--;
- }
- trace_escc_get_queue(CHN_C(s), val);
- if (q->count > 0)
- serial_receive_byte(s, 0);
- return val;
-}
-
-static int escc_update_irq_chn(ChannelState *s)
-{
- if ((((s->wregs[W_INTR] & INTR_TXINT) && (s->txint == 1)) ||
- // tx ints enabled, pending
- ((((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINT1ST) ||
- ((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINTALL)) &&
- s->rxint == 1) || // rx ints enabled, pending
- ((s->wregs[W_EXTINT] & EXTINT_BRKINT) &&
- (s->rregs[R_STATUS] & STATUS_BRK)))) { // break int e&p
- return 1;
- }
- return 0;
-}
-
-static void escc_update_irq(ChannelState *s)
-{
- int irq;
-
- irq = escc_update_irq_chn(s);
- irq |= escc_update_irq_chn(s->otherchn);
-
- trace_escc_update_irq(irq);
- qemu_set_irq(s->irq, irq);
-}
-
-static void escc_reset_chn(ChannelState *s)
-{
- int i;
-
- s->reg = 0;
- for (i = 0; i < SERIAL_REGS; i++) {
- s->rregs[i] = 0;
- s->wregs[i] = 0;
- }
- s->wregs[W_TXCTRL1] = TXCTRL1_1STOP; // 1X divisor, 1 stop bit, no parity
- s->wregs[W_MINTR] = MINTR_RST_ALL;
- s->wregs[W_CLOCK] = CLOCK_TRXC; // Synch mode tx clock = TRxC
- s->wregs[W_MISC2] = MISC2_PLLDIS; // PLL disabled
- s->wregs[W_EXTINT] = EXTINT_DCD | EXTINT_SYNCINT | EXTINT_CTSINT |
- EXTINT_TXUNDRN | EXTINT_BRKINT; // Enable most interrupts
- if (s->disabled)
- s->rregs[R_STATUS] = STATUS_TXEMPTY | STATUS_DCD | STATUS_SYNC |
- STATUS_CTS | STATUS_TXUNDRN;
- else
- s->rregs[R_STATUS] = STATUS_TXEMPTY | STATUS_TXUNDRN;
- s->rregs[R_SPEC] = SPEC_BITS8 | SPEC_ALLSENT;
-
- s->rx = s->tx = 0;
- s->rxint = s->txint = 0;
- s->rxint_under_svc = s->txint_under_svc = 0;
- s->e0_mode = s->led_mode = s->caps_lock_mode = s->num_lock_mode = 0;
- clear_queue(s);
-}
-
-static void escc_reset(DeviceState *d)
-{
- ESCCState *s = ESCC(d);
-
- escc_reset_chn(&s->chn[0]);
- escc_reset_chn(&s->chn[1]);
-}
-
-static inline void set_rxint(ChannelState *s)
-{
- s->rxint = 1;
- /* XXX: missing daisy chainnig: chn_b rx should have a lower priority
- than chn_a rx/tx/special_condition service*/
- s->rxint_under_svc = 1;
- if (s->chn == chn_a) {
- s->rregs[R_INTR] |= INTR_RXINTA;
- if (s->wregs[W_MINTR] & MINTR_STATUSHI)
- s->otherchn->rregs[R_IVEC] = IVEC_HIRXINTA;
- else
- s->otherchn->rregs[R_IVEC] = IVEC_LORXINTA;
- } else {
- s->otherchn->rregs[R_INTR] |= INTR_RXINTB;
- if (s->wregs[W_MINTR] & MINTR_STATUSHI)
- s->rregs[R_IVEC] = IVEC_HIRXINTB;
- else
- s->rregs[R_IVEC] = IVEC_LORXINTB;
- }
- escc_update_irq(s);
-}
-
-static inline void set_txint(ChannelState *s)
-{
- s->txint = 1;
- if (!s->rxint_under_svc) {
- s->txint_under_svc = 1;
- if (s->chn == chn_a) {
- if (s->wregs[W_INTR] & INTR_TXINT) {
- s->rregs[R_INTR] |= INTR_TXINTA;
- }
- if (s->wregs[W_MINTR] & MINTR_STATUSHI)
- s->otherchn->rregs[R_IVEC] = IVEC_HITXINTA;
- else
- s->otherchn->rregs[R_IVEC] = IVEC_LOTXINTA;
- } else {
- s->rregs[R_IVEC] = IVEC_TXINTB;
- if (s->wregs[W_INTR] & INTR_TXINT) {
- s->otherchn->rregs[R_INTR] |= INTR_TXINTB;
- }
- }
- escc_update_irq(s);
- }
-}
-
-static inline void clr_rxint(ChannelState *s)
-{
- s->rxint = 0;
- s->rxint_under_svc = 0;
- if (s->chn == chn_a) {
- if (s->wregs[W_MINTR] & MINTR_STATUSHI)
- s->otherchn->rregs[R_IVEC] = IVEC_HINOINT;
- else
- s->otherchn->rregs[R_IVEC] = IVEC_LONOINT;
- s->rregs[R_INTR] &= ~INTR_RXINTA;
- } else {
- if (s->wregs[W_MINTR] & MINTR_STATUSHI)
- s->rregs[R_IVEC] = IVEC_HINOINT;
- else
- s->rregs[R_IVEC] = IVEC_LONOINT;
- s->otherchn->rregs[R_INTR] &= ~INTR_RXINTB;
- }
- if (s->txint)
- set_txint(s);
- escc_update_irq(s);
-}
-
-static inline void clr_txint(ChannelState *s)
-{
- s->txint = 0;
- s->txint_under_svc = 0;
- if (s->chn == chn_a) {
- if (s->wregs[W_MINTR] & MINTR_STATUSHI)
- s->otherchn->rregs[R_IVEC] = IVEC_HINOINT;
- else
- s->otherchn->rregs[R_IVEC] = IVEC_LONOINT;
- s->rregs[R_INTR] &= ~INTR_TXINTA;
- } else {
- s->otherchn->rregs[R_INTR] &= ~INTR_TXINTB;
- if (s->wregs[W_MINTR] & MINTR_STATUSHI)
- s->rregs[R_IVEC] = IVEC_HINOINT;
- else
- s->rregs[R_IVEC] = IVEC_LONOINT;
- s->otherchn->rregs[R_INTR] &= ~INTR_TXINTB;
- }
- if (s->rxint)
- set_rxint(s);
- escc_update_irq(s);
-}
-
-static void escc_update_parameters(ChannelState *s)
-{
- int speed, parity, data_bits, stop_bits;
- QEMUSerialSetParams ssp;
-
- if (!s->chr || s->type != ser)
- return;
-
- if (s->wregs[W_TXCTRL1] & TXCTRL1_PAREN) {
- if (s->wregs[W_TXCTRL1] & TXCTRL1_PAREV)
- parity = 'E';
- else
- parity = 'O';
- } else {
- parity = 'N';
- }
- if ((s->wregs[W_TXCTRL1] & TXCTRL1_STPMSK) == TXCTRL1_2STOP)
- stop_bits = 2;
- else
- stop_bits = 1;
- switch (s->wregs[W_TXCTRL2] & TXCTRL2_BITMSK) {
- case TXCTRL2_5BITS:
- data_bits = 5;
- break;
- case TXCTRL2_7BITS:
- data_bits = 7;
- break;
- case TXCTRL2_6BITS:
- data_bits = 6;
- break;
- default:
- case TXCTRL2_8BITS:
- data_bits = 8;
- break;
- }
- speed = s->clock / ((s->wregs[W_BRGLO] | (s->wregs[W_BRGHI] << 8)) + 2);
- switch (s->wregs[W_TXCTRL1] & TXCTRL1_CLKMSK) {
- case TXCTRL1_CLK1X:
- break;
- case TXCTRL1_CLK16X:
- speed /= 16;
- break;
- case TXCTRL1_CLK32X:
- speed /= 32;
- break;
- default:
- case TXCTRL1_CLK64X:
- speed /= 64;
- break;
- }
- ssp.speed = speed;
- ssp.parity = parity;
- ssp.data_bits = data_bits;
- ssp.stop_bits = stop_bits;
- trace_escc_update_parameters(CHN_C(s), speed, parity, data_bits, stop_bits);
- qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
-}
-
-static void escc_mem_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- ESCCState *serial = opaque;
- ChannelState *s;
- uint32_t saddr;
- int newreg, channel;
-
- val &= 0xff;
- saddr = (addr >> serial->it_shift) & 1;
- channel = (addr >> (serial->it_shift + 1)) & 1;
- s = &serial->chn[channel];
- switch (saddr) {
- case SERIAL_CTRL:
- trace_escc_mem_writeb_ctrl(CHN_C(s), s->reg, val & 0xff);
- newreg = 0;
- switch (s->reg) {
- case W_CMD:
- newreg = val & CMD_PTR_MASK;
- val &= CMD_CMD_MASK;
- switch (val) {
- case CMD_HI:
- newreg |= CMD_HI;
- break;
- case CMD_CLR_TXINT:
- clr_txint(s);
- break;
- case CMD_CLR_IUS:
- if (s->rxint_under_svc) {
- s->rxint_under_svc = 0;
- if (s->txint) {
- set_txint(s);
- }
- } else if (s->txint_under_svc) {
- s->txint_under_svc = 0;
- }
- escc_update_irq(s);
- break;
- default:
- break;
- }
- break;
- case W_INTR ... W_RXCTRL:
- case W_SYNC1 ... W_TXBUF:
- case W_MISC1 ... W_CLOCK:
- case W_MISC2 ... W_EXTINT:
- s->wregs[s->reg] = val;
- break;
- case W_TXCTRL1:
- case W_TXCTRL2:
- s->wregs[s->reg] = val;
- escc_update_parameters(s);
- break;
- case W_BRGLO:
- case W_BRGHI:
- s->wregs[s->reg] = val;
- s->rregs[s->reg] = val;
- escc_update_parameters(s);
- break;
- case W_MINTR:
- switch (val & MINTR_RST_MASK) {
- case 0:
- default:
- break;
- case MINTR_RST_B:
- escc_reset_chn(&serial->chn[0]);
- return;
- case MINTR_RST_A:
- escc_reset_chn(&serial->chn[1]);
- return;
- case MINTR_RST_ALL:
- escc_reset(DEVICE(serial));
- return;
- }
- break;
- default:
- break;
- }
- if (s->reg == 0)
- s->reg = newreg;
- else
- s->reg = 0;
- break;
- case SERIAL_DATA:
- trace_escc_mem_writeb_data(CHN_C(s), val);
- s->tx = val;
- if (s->wregs[W_TXCTRL2] & TXCTRL2_TXEN) { // tx enabled
- if (s->chr)
- qemu_chr_fe_write(s->chr, &s->tx, 1);
- else if (s->type == kbd && !s->disabled) {
- handle_kbd_command(s, val);
- }
- }
- s->rregs[R_STATUS] |= STATUS_TXEMPTY; // Tx buffer empty
- s->rregs[R_SPEC] |= SPEC_ALLSENT; // All sent
- set_txint(s);
- break;
- default:
- break;
- }
-}
-
-static uint64_t escc_mem_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- ESCCState *serial = opaque;
- ChannelState *s;
- uint32_t saddr;
- uint32_t ret;
- int channel;
-
- saddr = (addr >> serial->it_shift) & 1;
- channel = (addr >> (serial->it_shift + 1)) & 1;
- s = &serial->chn[channel];
- switch (saddr) {
- case SERIAL_CTRL:
- trace_escc_mem_readb_ctrl(CHN_C(s), s->reg, s->rregs[s->reg]);
- ret = s->rregs[s->reg];
- s->reg = 0;
- return ret;
- case SERIAL_DATA:
- s->rregs[R_STATUS] &= ~STATUS_RXAV;
- clr_rxint(s);
- if (s->type == kbd || s->type == mouse)
- ret = get_queue(s);
- else
- ret = s->rx;
- trace_escc_mem_readb_data(CHN_C(s), ret);
- if (s->chr)
- qemu_chr_accept_input(s->chr);
- return ret;
- default:
- break;
- }
- return 0;
-}
-
-static const MemoryRegionOps escc_mem_ops = {
- .read = escc_mem_read,
- .write = escc_mem_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
-};
-
-static int serial_can_receive(void *opaque)
-{
- ChannelState *s = opaque;
- int ret;
-
- if (((s->wregs[W_RXCTRL] & RXCTRL_RXEN) == 0) // Rx not enabled
- || ((s->rregs[R_STATUS] & STATUS_RXAV) == STATUS_RXAV))
- // char already available
- ret = 0;
- else
- ret = 1;
- return ret;
-}
-
-static void serial_receive_byte(ChannelState *s, int ch)
-{
- trace_escc_serial_receive_byte(CHN_C(s), ch);
- s->rregs[R_STATUS] |= STATUS_RXAV;
- s->rx = ch;
- set_rxint(s);
-}
-
-static void serial_receive_break(ChannelState *s)
-{
- s->rregs[R_STATUS] |= STATUS_BRK;
- escc_update_irq(s);
-}
-
-static void serial_receive1(void *opaque, const uint8_t *buf, int size)
-{
- ChannelState *s = opaque;
- serial_receive_byte(s, buf[0]);
-}
-
-static void serial_event(void *opaque, int event)
-{
- ChannelState *s = opaque;
- if (event == CHR_EVENT_BREAK)
- serial_receive_break(s);
-}
-
-static const VMStateDescription vmstate_escc_chn = {
- .name ="escc_chn",
- .version_id = 2,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(vmstate_dummy, ChannelState),
- VMSTATE_UINT32(reg, ChannelState),
- VMSTATE_UINT32(rxint, ChannelState),
- VMSTATE_UINT32(txint, ChannelState),
- VMSTATE_UINT32(rxint_under_svc, ChannelState),
- VMSTATE_UINT32(txint_under_svc, ChannelState),
- VMSTATE_UINT8(rx, ChannelState),
- VMSTATE_UINT8(tx, ChannelState),
- VMSTATE_BUFFER(wregs, ChannelState),
- VMSTATE_BUFFER(rregs, ChannelState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_escc = {
- .name ="escc",
- .version_id = 2,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT_ARRAY(chn, ESCCState, 2, 2, vmstate_escc_chn,
- ChannelState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-MemoryRegion *escc_init(hwaddr base, qemu_irq irqA, qemu_irq irqB,
- CharDriverState *chrA, CharDriverState *chrB,
- int clock, int it_shift)
-{
- DeviceState *dev;
- SysBusDevice *s;
- ESCCState *d;
-
- dev = qdev_create(NULL, TYPE_ESCC);
- qdev_prop_set_uint32(dev, "disabled", 0);
- qdev_prop_set_uint32(dev, "frequency", clock);
- qdev_prop_set_uint32(dev, "it_shift", it_shift);
- qdev_prop_set_chr(dev, "chrB", chrB);
- qdev_prop_set_chr(dev, "chrA", chrA);
- qdev_prop_set_uint32(dev, "chnBtype", ser);
- qdev_prop_set_uint32(dev, "chnAtype", ser);
- qdev_init_nofail(dev);
- s = SYS_BUS_DEVICE(dev);
- sysbus_connect_irq(s, 0, irqB);
- sysbus_connect_irq(s, 1, irqA);
- if (base) {
- sysbus_mmio_map(s, 0, base);
- }
-
- d = ESCC(s);
- return &d->mmio;
-}
-
-static const uint8_t qcode_to_keycode[Q_KEY_CODE__MAX] = {
- [Q_KEY_CODE_SHIFT] = 99,
- [Q_KEY_CODE_SHIFT_R] = 110,
- [Q_KEY_CODE_ALT] = 19,
- [Q_KEY_CODE_ALT_R] = 13,
- [Q_KEY_CODE_ALTGR] = 13,
- [Q_KEY_CODE_CTRL] = 76,
- [Q_KEY_CODE_CTRL_R] = 76,
- [Q_KEY_CODE_ESC] = 29,
- [Q_KEY_CODE_1] = 30,
- [Q_KEY_CODE_2] = 31,
- [Q_KEY_CODE_3] = 32,
- [Q_KEY_CODE_4] = 33,
- [Q_KEY_CODE_5] = 34,
- [Q_KEY_CODE_6] = 35,
- [Q_KEY_CODE_7] = 36,
- [Q_KEY_CODE_8] = 37,
- [Q_KEY_CODE_9] = 38,
- [Q_KEY_CODE_0] = 39,
- [Q_KEY_CODE_MINUS] = 40,
- [Q_KEY_CODE_EQUAL] = 41,
- [Q_KEY_CODE_BACKSPACE] = 43,
- [Q_KEY_CODE_TAB] = 53,
- [Q_KEY_CODE_Q] = 54,
- [Q_KEY_CODE_W] = 55,
- [Q_KEY_CODE_E] = 56,
- [Q_KEY_CODE_R] = 57,
- [Q_KEY_CODE_T] = 58,
- [Q_KEY_CODE_Y] = 59,
- [Q_KEY_CODE_U] = 60,
- [Q_KEY_CODE_I] = 61,
- [Q_KEY_CODE_O] = 62,
- [Q_KEY_CODE_P] = 63,
- [Q_KEY_CODE_BRACKET_LEFT] = 64,
- [Q_KEY_CODE_BRACKET_RIGHT] = 65,
- [Q_KEY_CODE_RET] = 89,
- [Q_KEY_CODE_A] = 77,
- [Q_KEY_CODE_S] = 78,
- [Q_KEY_CODE_D] = 79,
- [Q_KEY_CODE_F] = 80,
- [Q_KEY_CODE_G] = 81,
- [Q_KEY_CODE_H] = 82,
- [Q_KEY_CODE_J] = 83,
- [Q_KEY_CODE_K] = 84,
- [Q_KEY_CODE_L] = 85,
- [Q_KEY_CODE_SEMICOLON] = 86,
- [Q_KEY_CODE_APOSTROPHE] = 87,
- [Q_KEY_CODE_GRAVE_ACCENT] = 42,
- [Q_KEY_CODE_BACKSLASH] = 88,
- [Q_KEY_CODE_Z] = 100,
- [Q_KEY_CODE_X] = 101,
- [Q_KEY_CODE_C] = 102,
- [Q_KEY_CODE_V] = 103,
- [Q_KEY_CODE_B] = 104,
- [Q_KEY_CODE_N] = 105,
- [Q_KEY_CODE_M] = 106,
- [Q_KEY_CODE_COMMA] = 107,
- [Q_KEY_CODE_DOT] = 108,
- [Q_KEY_CODE_SLASH] = 109,
- [Q_KEY_CODE_ASTERISK] = 47,
- [Q_KEY_CODE_SPC] = 121,
- [Q_KEY_CODE_CAPS_LOCK] = 119,
- [Q_KEY_CODE_F1] = 5,
- [Q_KEY_CODE_F2] = 6,
- [Q_KEY_CODE_F3] = 8,
- [Q_KEY_CODE_F4] = 10,
- [Q_KEY_CODE_F5] = 12,
- [Q_KEY_CODE_F6] = 14,
- [Q_KEY_CODE_F7] = 16,
- [Q_KEY_CODE_F8] = 17,
- [Q_KEY_CODE_F9] = 18,
- [Q_KEY_CODE_F10] = 7,
- [Q_KEY_CODE_NUM_LOCK] = 98,
- [Q_KEY_CODE_SCROLL_LOCK] = 23,
- [Q_KEY_CODE_KP_DIVIDE] = 46,
- [Q_KEY_CODE_KP_MULTIPLY] = 47,
- [Q_KEY_CODE_KP_SUBTRACT] = 71,
- [Q_KEY_CODE_KP_ADD] = 125,
- [Q_KEY_CODE_KP_ENTER] = 90,
- [Q_KEY_CODE_KP_DECIMAL] = 50,
- [Q_KEY_CODE_KP_0] = 94,
- [Q_KEY_CODE_KP_1] = 112,
- [Q_KEY_CODE_KP_2] = 113,
- [Q_KEY_CODE_KP_3] = 114,
- [Q_KEY_CODE_KP_4] = 91,
- [Q_KEY_CODE_KP_5] = 92,
- [Q_KEY_CODE_KP_6] = 93,
- [Q_KEY_CODE_KP_7] = 68,
- [Q_KEY_CODE_KP_8] = 69,
- [Q_KEY_CODE_KP_9] = 70,
- [Q_KEY_CODE_LESS] = 124,
- [Q_KEY_CODE_F11] = 9,
- [Q_KEY_CODE_F12] = 11,
- [Q_KEY_CODE_HOME] = 52,
- [Q_KEY_CODE_PGUP] = 96,
- [Q_KEY_CODE_PGDN] = 123,
- [Q_KEY_CODE_END] = 74,
- [Q_KEY_CODE_LEFT] = 24,
- [Q_KEY_CODE_UP] = 20,
- [Q_KEY_CODE_DOWN] = 27,
- [Q_KEY_CODE_RIGHT] = 28,
- [Q_KEY_CODE_INSERT] = 44,
- [Q_KEY_CODE_DELETE] = 66,
- [Q_KEY_CODE_STOP] = 1,
- [Q_KEY_CODE_AGAIN] = 3,
- [Q_KEY_CODE_PROPS] = 25,
- [Q_KEY_CODE_UNDO] = 26,
- [Q_KEY_CODE_FRONT] = 49,
- [Q_KEY_CODE_COPY] = 51,
- [Q_KEY_CODE_OPEN] = 72,
- [Q_KEY_CODE_PASTE] = 73,
- [Q_KEY_CODE_FIND] = 95,
- [Q_KEY_CODE_CUT] = 97,
- [Q_KEY_CODE_LF] = 111,
- [Q_KEY_CODE_HELP] = 118,
- [Q_KEY_CODE_META_L] = 120,
- [Q_KEY_CODE_META_R] = 122,
- [Q_KEY_CODE_COMPOSE] = 67,
- [Q_KEY_CODE_PRINT] = 22,
- [Q_KEY_CODE_SYSRQ] = 21,
-};
-
-static void sunkbd_handle_event(DeviceState *dev, QemuConsole *src,
- InputEvent *evt)
-{
- ChannelState *s = (ChannelState *)dev;
- int qcode, keycode;
- InputKeyEvent *key;
-
- assert(evt->type == INPUT_EVENT_KIND_KEY);
- key = evt->u.key.data;
- qcode = qemu_input_key_value_to_qcode(key->key);
- trace_escc_sunkbd_event_in(qcode, QKeyCode_lookup[qcode],
- key->down);
-
- if (qcode == Q_KEY_CODE_CAPS_LOCK) {
- if (key->down) {
- s->caps_lock_mode ^= 1;
- if (s->caps_lock_mode == 2) {
- return; /* Drop second press */
- }
- } else {
- s->caps_lock_mode ^= 2;
- if (s->caps_lock_mode == 3) {
- return; /* Drop first release */
- }
- }
- }
-
- if (qcode == Q_KEY_CODE_NUM_LOCK) {
- if (key->down) {
- s->num_lock_mode ^= 1;
- if (s->num_lock_mode == 2) {
- return; /* Drop second press */
- }
- } else {
- s->num_lock_mode ^= 2;
- if (s->num_lock_mode == 3) {
- return; /* Drop first release */
- }
- }
- }
-
- keycode = qcode_to_keycode[qcode];
- if (!key->down) {
- keycode |= 0x80;
- }
- trace_escc_sunkbd_event_out(keycode);
- put_queue(s, keycode);
-}
-
-static QemuInputHandler sunkbd_handler = {
- .name = "sun keyboard",
- .mask = INPUT_EVENT_MASK_KEY,
- .event = sunkbd_handle_event,
-};
-
-static void handle_kbd_command(ChannelState *s, int val)
-{
- trace_escc_kbd_command(val);
- if (s->led_mode) { // Ignore led byte
- s->led_mode = 0;
- return;
- }
- switch (val) {
- case 1: // Reset, return type code
- clear_queue(s);
- put_queue(s, 0xff);
- put_queue(s, 4); // Type 4
- put_queue(s, 0x7f);
- break;
- case 0xe: // Set leds
- s->led_mode = 1;
- break;
- case 7: // Query layout
- case 0xf:
- clear_queue(s);
- put_queue(s, 0xfe);
- put_queue(s, 0x21); /* en-us layout */
- break;
- default:
- break;
- }
-}
-
-static void sunmouse_event(void *opaque,
- int dx, int dy, int dz, int buttons_state)
-{
- ChannelState *s = opaque;
- int ch;
-
- trace_escc_sunmouse_event(dx, dy, buttons_state);
- ch = 0x80 | 0x7; /* protocol start byte, no buttons pressed */
-
- if (buttons_state & MOUSE_EVENT_LBUTTON)
- ch ^= 0x4;
- if (buttons_state & MOUSE_EVENT_MBUTTON)
- ch ^= 0x2;
- if (buttons_state & MOUSE_EVENT_RBUTTON)
- ch ^= 0x1;
-
- put_queue(s, ch);
-
- ch = dx;
-
- if (ch > 127)
- ch = 127;
- else if (ch < -127)
- ch = -127;
-
- put_queue(s, ch & 0xff);
-
- ch = -dy;
-
- if (ch > 127)
- ch = 127;
- else if (ch < -127)
- ch = -127;
-
- put_queue(s, ch & 0xff);
-
- // MSC protocol specify two extra motion bytes
-
- put_queue(s, 0);
- put_queue(s, 0);
-}
-
-void slavio_serial_ms_kbd_init(hwaddr base, qemu_irq irq,
- int disabled, int clock, int it_shift)
-{
- DeviceState *dev;
- SysBusDevice *s;
-
- dev = qdev_create(NULL, TYPE_ESCC);
- qdev_prop_set_uint32(dev, "disabled", disabled);
- qdev_prop_set_uint32(dev, "frequency", clock);
- qdev_prop_set_uint32(dev, "it_shift", it_shift);
- qdev_prop_set_chr(dev, "chrB", NULL);
- qdev_prop_set_chr(dev, "chrA", NULL);
- qdev_prop_set_uint32(dev, "chnBtype", mouse);
- qdev_prop_set_uint32(dev, "chnAtype", kbd);
- qdev_init_nofail(dev);
- s = SYS_BUS_DEVICE(dev);
- sysbus_connect_irq(s, 0, irq);
- sysbus_connect_irq(s, 1, irq);
- sysbus_mmio_map(s, 0, base);
-}
-
-static int escc_init1(SysBusDevice *dev)
-{
- ESCCState *s = ESCC(dev);
- unsigned int i;
-
- s->chn[0].disabled = s->disabled;
- s->chn[1].disabled = s->disabled;
- for (i = 0; i < 2; i++) {
- sysbus_init_irq(dev, &s->chn[i].irq);
- s->chn[i].chn = 1 - i;
- s->chn[i].clock = s->frequency / 2;
- if (s->chn[i].chr) {
- qemu_chr_add_handlers(s->chn[i].chr, serial_can_receive,
- serial_receive1, serial_event, &s->chn[i]);
- }
- }
- s->chn[0].otherchn = &s->chn[1];
- s->chn[1].otherchn = &s->chn[0];
-
- memory_region_init_io(&s->mmio, OBJECT(s), &escc_mem_ops, s, "escc",
- ESCC_SIZE << s->it_shift);
- sysbus_init_mmio(dev, &s->mmio);
-
- if (s->chn[0].type == mouse) {
- qemu_add_mouse_event_handler(sunmouse_event, &s->chn[0], 0,
- "QEMU Sun Mouse");
- }
- if (s->chn[1].type == kbd) {
- s->chn[1].hs = qemu_input_handler_register((DeviceState *)(&s->chn[1]),
- &sunkbd_handler);
- }
-
- return 0;
-}
-
-static Property escc_properties[] = {
- DEFINE_PROP_UINT32("frequency", ESCCState, frequency, 0),
- DEFINE_PROP_UINT32("it_shift", ESCCState, it_shift, 0),
- DEFINE_PROP_UINT32("disabled", ESCCState, disabled, 0),
- DEFINE_PROP_UINT32("chnBtype", ESCCState, chn[0].type, 0),
- DEFINE_PROP_UINT32("chnAtype", ESCCState, chn[1].type, 0),
- DEFINE_PROP_CHR("chrB", ESCCState, chn[0].chr),
- DEFINE_PROP_CHR("chrA", ESCCState, chn[1].chr),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void escc_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = escc_init1;
- dc->reset = escc_reset;
- dc->vmsd = &vmstate_escc;
- dc->props = escc_properties;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
-}
-
-static const TypeInfo escc_info = {
- .name = TYPE_ESCC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(ESCCState),
- .class_init = escc_class_init,
-};
-
-static void escc_register_types(void)
-{
- type_register_static(&escc_info);
-}
-
-type_init(escc_register_types)
diff --git a/qemu/hw/char/etraxfs_ser.c b/qemu/hw/char/etraxfs_ser.c
deleted file mode 100644
index 146b387e7..000000000
--- a/qemu/hw/char/etraxfs_ser.c
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * QEMU ETRAX System Emulator
- *
- * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB.
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "sysemu/char.h"
-#include "qemu/log.h"
-
-#define D(x)
-
-#define RW_TR_CTRL (0x00 / 4)
-#define RW_TR_DMA_EN (0x04 / 4)
-#define RW_REC_CTRL (0x08 / 4)
-#define RW_DOUT (0x1c / 4)
-#define RS_STAT_DIN (0x20 / 4)
-#define R_STAT_DIN (0x24 / 4)
-#define RW_INTR_MASK (0x2c / 4)
-#define RW_ACK_INTR (0x30 / 4)
-#define R_INTR (0x34 / 4)
-#define R_MASKED_INTR (0x38 / 4)
-#define R_MAX (0x3c / 4)
-
-#define STAT_DAV 16
-#define STAT_TR_IDLE 22
-#define STAT_TR_RDY 24
-
-#define TYPE_ETRAX_FS_SERIAL "etraxfs,serial"
-#define ETRAX_SERIAL(obj) \
- OBJECT_CHECK(ETRAXSerial, (obj), TYPE_ETRAX_FS_SERIAL)
-
-typedef struct ETRAXSerial {
- SysBusDevice parent_obj;
-
- MemoryRegion mmio;
- CharDriverState *chr;
- qemu_irq irq;
-
- int pending_tx;
-
- uint8_t rx_fifo[16];
- unsigned int rx_fifo_pos;
- unsigned int rx_fifo_len;
-
- /* Control registers. */
- uint32_t regs[R_MAX];
-} ETRAXSerial;
-
-static void ser_update_irq(ETRAXSerial *s)
-{
-
- if (s->rx_fifo_len) {
- s->regs[R_INTR] |= 8;
- } else {
- s->regs[R_INTR] &= ~8;
- }
-
- s->regs[R_MASKED_INTR] = s->regs[R_INTR] & s->regs[RW_INTR_MASK];
- qemu_set_irq(s->irq, !!s->regs[R_MASKED_INTR]);
-}
-
-static uint64_t
-ser_read(void *opaque, hwaddr addr, unsigned int size)
-{
- ETRAXSerial *s = opaque;
- uint32_t r = 0;
-
- addr >>= 2;
- switch (addr)
- {
- case R_STAT_DIN:
- r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & 15];
- if (s->rx_fifo_len) {
- r |= 1 << STAT_DAV;
- }
- r |= 1 << STAT_TR_RDY;
- r |= 1 << STAT_TR_IDLE;
- break;
- case RS_STAT_DIN:
- r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & 15];
- if (s->rx_fifo_len) {
- r |= 1 << STAT_DAV;
- s->rx_fifo_len--;
- }
- r |= 1 << STAT_TR_RDY;
- r |= 1 << STAT_TR_IDLE;
- break;
- default:
- r = s->regs[addr];
- D(qemu_log("%s " TARGET_FMT_plx "=%x\n", __func__, addr, r));
- break;
- }
- return r;
-}
-
-static void
-ser_write(void *opaque, hwaddr addr,
- uint64_t val64, unsigned int size)
-{
- ETRAXSerial *s = opaque;
- uint32_t value = val64;
- unsigned char ch = val64;
-
- D(qemu_log("%s " TARGET_FMT_plx "=%x\n", __func__, addr, value));
- addr >>= 2;
- switch (addr)
- {
- case RW_DOUT:
- qemu_chr_fe_write(s->chr, &ch, 1);
- s->regs[R_INTR] |= 3;
- s->pending_tx = 1;
- s->regs[addr] = value;
- break;
- case RW_ACK_INTR:
- if (s->pending_tx) {
- value &= ~1;
- s->pending_tx = 0;
- D(qemu_log("fixedup value=%x r_intr=%x\n",
- value, s->regs[R_INTR]));
- }
- s->regs[addr] = value;
- s->regs[R_INTR] &= ~value;
- D(printf("r_intr=%x\n", s->regs[R_INTR]));
- break;
- default:
- s->regs[addr] = value;
- break;
- }
- ser_update_irq(s);
-}
-
-static const MemoryRegionOps ser_ops = {
- .read = ser_read,
- .write = ser_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4
- }
-};
-
-static void serial_receive(void *opaque, const uint8_t *buf, int size)
-{
- ETRAXSerial *s = opaque;
- int i;
-
- /* Got a byte. */
- if (s->rx_fifo_len >= 16) {
- D(qemu_log("WARNING: UART dropped char.\n"));
- return;
- }
-
- for (i = 0; i < size; i++) {
- s->rx_fifo[s->rx_fifo_pos] = buf[i];
- s->rx_fifo_pos++;
- s->rx_fifo_pos &= 15;
- s->rx_fifo_len++;
- }
-
- ser_update_irq(s);
-}
-
-static int serial_can_receive(void *opaque)
-{
- ETRAXSerial *s = opaque;
-
- /* Is the receiver enabled? */
- if (!(s->regs[RW_REC_CTRL] & (1 << 3))) {
- return 0;
- }
-
- return sizeof(s->rx_fifo) - s->rx_fifo_len;
-}
-
-static void serial_event(void *opaque, int event)
-{
-
-}
-
-static void etraxfs_ser_reset(DeviceState *d)
-{
- ETRAXSerial *s = ETRAX_SERIAL(d);
-
- /* transmitter begins ready and idle. */
- s->regs[RS_STAT_DIN] |= (1 << STAT_TR_RDY);
- s->regs[RS_STAT_DIN] |= (1 << STAT_TR_IDLE);
-
- s->regs[RW_REC_CTRL] = 0x10000;
-
-}
-
-static int etraxfs_ser_init(SysBusDevice *dev)
-{
- ETRAXSerial *s = ETRAX_SERIAL(dev);
-
- sysbus_init_irq(dev, &s->irq);
- memory_region_init_io(&s->mmio, OBJECT(s), &ser_ops, s,
- "etraxfs-serial", R_MAX * 4);
- sysbus_init_mmio(dev, &s->mmio);
-
- /* FIXME use a qdev chardev prop instead of qemu_char_get_next_serial() */
- s->chr = qemu_char_get_next_serial();
- if (s->chr) {
- qemu_chr_add_handlers(s->chr,
- serial_can_receive, serial_receive,
- serial_event, s);
- }
- return 0;
-}
-
-static void etraxfs_ser_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = etraxfs_ser_init;
- dc->reset = etraxfs_ser_reset;
- /* Reason: init() method uses qemu_char_get_next_serial() */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo etraxfs_ser_info = {
- .name = TYPE_ETRAX_FS_SERIAL,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(ETRAXSerial),
- .class_init = etraxfs_ser_class_init,
-};
-
-static void etraxfs_serial_register_types(void)
-{
- type_register_static(&etraxfs_ser_info);
-}
-
-type_init(etraxfs_serial_register_types)
diff --git a/qemu/hw/char/exynos4210_uart.c b/qemu/hw/char/exynos4210_uart.c
deleted file mode 100644
index 885ecc027..000000000
--- a/qemu/hw/char/exynos4210_uart.c
+++ /dev/null
@@ -1,678 +0,0 @@
-/*
- * Exynos4210 UART Emulation
- *
- * Copyright (C) 2011 Samsung Electronics Co Ltd.
- * Maksim Kozlov, <m.kozlov@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "qemu/error-report.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/char.h"
-
-#include "hw/arm/exynos4210.h"
-
-#undef DEBUG_UART
-#undef DEBUG_UART_EXTEND
-#undef DEBUG_IRQ
-#undef DEBUG_Rx_DATA
-#undef DEBUG_Tx_DATA
-
-#define DEBUG_UART 0
-#define DEBUG_UART_EXTEND 0
-#define DEBUG_IRQ 0
-#define DEBUG_Rx_DATA 0
-#define DEBUG_Tx_DATA 0
-
-#if DEBUG_UART
-#define PRINT_DEBUG(fmt, args...) \
- do { \
- fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \
- } while (0)
-
-#if DEBUG_UART_EXTEND
-#define PRINT_DEBUG_EXTEND(fmt, args...) \
- do { \
- fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \
- } while (0)
-#else
-#define PRINT_DEBUG_EXTEND(fmt, args...) \
- do {} while (0)
-#endif /* EXTEND */
-
-#else
-#define PRINT_DEBUG(fmt, args...) \
- do {} while (0)
-#define PRINT_DEBUG_EXTEND(fmt, args...) \
- do {} while (0)
-#endif
-
-#define PRINT_ERROR(fmt, args...) \
- do { \
- fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \
- } while (0)
-
-/*
- * Offsets for UART registers relative to SFR base address
- * for UARTn
- *
- */
-#define ULCON 0x0000 /* Line Control */
-#define UCON 0x0004 /* Control */
-#define UFCON 0x0008 /* FIFO Control */
-#define UMCON 0x000C /* Modem Control */
-#define UTRSTAT 0x0010 /* Tx/Rx Status */
-#define UERSTAT 0x0014 /* UART Error Status */
-#define UFSTAT 0x0018 /* FIFO Status */
-#define UMSTAT 0x001C /* Modem Status */
-#define UTXH 0x0020 /* Transmit Buffer */
-#define URXH 0x0024 /* Receive Buffer */
-#define UBRDIV 0x0028 /* Baud Rate Divisor */
-#define UFRACVAL 0x002C /* Divisor Fractional Value */
-#define UINTP 0x0030 /* Interrupt Pending */
-#define UINTSP 0x0034 /* Interrupt Source Pending */
-#define UINTM 0x0038 /* Interrupt Mask */
-
-/*
- * for indexing register in the uint32_t array
- *
- * 'reg' - register offset (see offsets definitions above)
- *
- */
-#define I_(reg) (reg / sizeof(uint32_t))
-
-typedef struct Exynos4210UartReg {
- const char *name; /* the only reason is the debug output */
- hwaddr offset;
- uint32_t reset_value;
-} Exynos4210UartReg;
-
-static Exynos4210UartReg exynos4210_uart_regs[] = {
- {"ULCON", ULCON, 0x00000000},
- {"UCON", UCON, 0x00003000},
- {"UFCON", UFCON, 0x00000000},
- {"UMCON", UMCON, 0x00000000},
- {"UTRSTAT", UTRSTAT, 0x00000006}, /* RO */
- {"UERSTAT", UERSTAT, 0x00000000}, /* RO */
- {"UFSTAT", UFSTAT, 0x00000000}, /* RO */
- {"UMSTAT", UMSTAT, 0x00000000}, /* RO */
- {"UTXH", UTXH, 0x5c5c5c5c}, /* WO, undefined reset value*/
- {"URXH", URXH, 0x00000000}, /* RO */
- {"UBRDIV", UBRDIV, 0x00000000},
- {"UFRACVAL", UFRACVAL, 0x00000000},
- {"UINTP", UINTP, 0x00000000},
- {"UINTSP", UINTSP, 0x00000000},
- {"UINTM", UINTM, 0x00000000},
-};
-
-#define EXYNOS4210_UART_REGS_MEM_SIZE 0x3C
-
-/* UART FIFO Control */
-#define UFCON_FIFO_ENABLE 0x1
-#define UFCON_Rx_FIFO_RESET 0x2
-#define UFCON_Tx_FIFO_RESET 0x4
-#define UFCON_Tx_FIFO_TRIGGER_LEVEL_SHIFT 8
-#define UFCON_Tx_FIFO_TRIGGER_LEVEL (7 << UFCON_Tx_FIFO_TRIGGER_LEVEL_SHIFT)
-#define UFCON_Rx_FIFO_TRIGGER_LEVEL_SHIFT 4
-#define UFCON_Rx_FIFO_TRIGGER_LEVEL (7 << UFCON_Rx_FIFO_TRIGGER_LEVEL_SHIFT)
-
-/* Uart FIFO Status */
-#define UFSTAT_Rx_FIFO_COUNT 0xff
-#define UFSTAT_Rx_FIFO_FULL 0x100
-#define UFSTAT_Rx_FIFO_ERROR 0x200
-#define UFSTAT_Tx_FIFO_COUNT_SHIFT 16
-#define UFSTAT_Tx_FIFO_COUNT (0xff << UFSTAT_Tx_FIFO_COUNT_SHIFT)
-#define UFSTAT_Tx_FIFO_FULL_SHIFT 24
-#define UFSTAT_Tx_FIFO_FULL (1 << UFSTAT_Tx_FIFO_FULL_SHIFT)
-
-/* UART Interrupt Source Pending */
-#define UINTSP_RXD 0x1 /* Receive interrupt */
-#define UINTSP_ERROR 0x2 /* Error interrupt */
-#define UINTSP_TXD 0x4 /* Transmit interrupt */
-#define UINTSP_MODEM 0x8 /* Modem interrupt */
-
-/* UART Line Control */
-#define ULCON_IR_MODE_SHIFT 6
-#define ULCON_PARITY_SHIFT 3
-#define ULCON_STOP_BIT_SHIFT 1
-
-/* UART Tx/Rx Status */
-#define UTRSTAT_TRANSMITTER_EMPTY 0x4
-#define UTRSTAT_Tx_BUFFER_EMPTY 0x2
-#define UTRSTAT_Rx_BUFFER_DATA_READY 0x1
-
-/* UART Error Status */
-#define UERSTAT_OVERRUN 0x1
-#define UERSTAT_PARITY 0x2
-#define UERSTAT_FRAME 0x4
-#define UERSTAT_BREAK 0x8
-
-typedef struct {
- uint8_t *data;
- uint32_t sp, rp; /* store and retrieve pointers */
- uint32_t size;
-} Exynos4210UartFIFO;
-
-#define TYPE_EXYNOS4210_UART "exynos4210.uart"
-#define EXYNOS4210_UART(obj) \
- OBJECT_CHECK(Exynos4210UartState, (obj), TYPE_EXYNOS4210_UART)
-
-typedef struct Exynos4210UartState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
-
- uint32_t reg[EXYNOS4210_UART_REGS_MEM_SIZE / sizeof(uint32_t)];
- Exynos4210UartFIFO rx;
- Exynos4210UartFIFO tx;
-
- CharDriverState *chr;
- qemu_irq irq;
-
- uint32_t channel;
-
-} Exynos4210UartState;
-
-
-#if DEBUG_UART
-/* Used only for debugging inside PRINT_DEBUG_... macros */
-static const char *exynos4210_uart_regname(hwaddr offset)
-{
-
- int i;
-
- for (i = 0; i < ARRAY_SIZE(exynos4210_uart_regs); i++) {
- if (offset == exynos4210_uart_regs[i].offset) {
- return exynos4210_uart_regs[i].name;
- }
- }
-
- return NULL;
-}
-#endif
-
-
-static void fifo_store(Exynos4210UartFIFO *q, uint8_t ch)
-{
- q->data[q->sp] = ch;
- q->sp = (q->sp + 1) % q->size;
-}
-
-static uint8_t fifo_retrieve(Exynos4210UartFIFO *q)
-{
- uint8_t ret = q->data[q->rp];
- q->rp = (q->rp + 1) % q->size;
- return ret;
-}
-
-static int fifo_elements_number(Exynos4210UartFIFO *q)
-{
- if (q->sp < q->rp) {
- return q->size - q->rp + q->sp;
- }
-
- return q->sp - q->rp;
-}
-
-static int fifo_empty_elements_number(Exynos4210UartFIFO *q)
-{
- return q->size - fifo_elements_number(q);
-}
-
-static void fifo_reset(Exynos4210UartFIFO *q)
-{
- g_free(q->data);
- q->data = NULL;
-
- q->data = (uint8_t *)g_malloc0(q->size);
-
- q->sp = 0;
- q->rp = 0;
-}
-
-static uint32_t exynos4210_uart_Tx_FIFO_trigger_level(Exynos4210UartState *s)
-{
- uint32_t level = 0;
- uint32_t reg;
-
- reg = (s->reg[I_(UFCON)] & UFCON_Tx_FIFO_TRIGGER_LEVEL) >>
- UFCON_Tx_FIFO_TRIGGER_LEVEL_SHIFT;
-
- switch (s->channel) {
- case 0:
- level = reg * 32;
- break;
- case 1:
- case 4:
- level = reg * 8;
- break;
- case 2:
- case 3:
- level = reg * 2;
- break;
- default:
- level = 0;
- PRINT_ERROR("Wrong UART channel number: %d\n", s->channel);
- }
-
- return level;
-}
-
-static void exynos4210_uart_update_irq(Exynos4210UartState *s)
-{
- /*
- * The Tx interrupt is always requested if the number of data in the
- * transmit FIFO is smaller than the trigger level.
- */
- if (s->reg[I_(UFCON)] & UFCON_FIFO_ENABLE) {
-
- uint32_t count = (s->reg[I_(UFSTAT)] & UFSTAT_Tx_FIFO_COUNT) >>
- UFSTAT_Tx_FIFO_COUNT_SHIFT;
-
- if (count <= exynos4210_uart_Tx_FIFO_trigger_level(s)) {
- s->reg[I_(UINTSP)] |= UINTSP_TXD;
- }
- }
-
- s->reg[I_(UINTP)] = s->reg[I_(UINTSP)] & ~s->reg[I_(UINTM)];
-
- if (s->reg[I_(UINTP)]) {
- qemu_irq_raise(s->irq);
-
-#if DEBUG_IRQ
- fprintf(stderr, "UART%d: IRQ has been raised: %08x\n",
- s->channel, s->reg[I_(UINTP)]);
-#endif
-
- } else {
- qemu_irq_lower(s->irq);
- }
-}
-
-static void exynos4210_uart_update_parameters(Exynos4210UartState *s)
-{
- int speed, parity, data_bits, stop_bits, frame_size;
- QEMUSerialSetParams ssp;
- uint64_t uclk_rate;
-
- if (s->reg[I_(UBRDIV)] == 0) {
- return;
- }
-
- frame_size = 1; /* start bit */
- if (s->reg[I_(ULCON)] & 0x20) {
- frame_size++; /* parity bit */
- if (s->reg[I_(ULCON)] & 0x28) {
- parity = 'E';
- } else {
- parity = 'O';
- }
- } else {
- parity = 'N';
- }
-
- if (s->reg[I_(ULCON)] & 0x4) {
- stop_bits = 2;
- } else {
- stop_bits = 1;
- }
-
- data_bits = (s->reg[I_(ULCON)] & 0x3) + 5;
-
- frame_size += data_bits + stop_bits;
-
- uclk_rate = 24000000;
-
- speed = uclk_rate / ((16 * (s->reg[I_(UBRDIV)]) & 0xffff) +
- (s->reg[I_(UFRACVAL)] & 0x7) + 16);
-
- ssp.speed = speed;
- ssp.parity = parity;
- ssp.data_bits = data_bits;
- ssp.stop_bits = stop_bits;
-
- qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
-
- PRINT_DEBUG("UART%d: speed: %d, parity: %c, data: %d, stop: %d\n",
- s->channel, speed, parity, data_bits, stop_bits);
-}
-
-static void exynos4210_uart_write(void *opaque, hwaddr offset,
- uint64_t val, unsigned size)
-{
- Exynos4210UartState *s = (Exynos4210UartState *)opaque;
- uint8_t ch;
-
- PRINT_DEBUG_EXTEND("UART%d: <0x%04x> %s <- 0x%08llx\n", s->channel,
- offset, exynos4210_uart_regname(offset), (long long unsigned int)val);
-
- switch (offset) {
- case ULCON:
- case UBRDIV:
- case UFRACVAL:
- s->reg[I_(offset)] = val;
- exynos4210_uart_update_parameters(s);
- break;
- case UFCON:
- s->reg[I_(UFCON)] = val;
- if (val & UFCON_Rx_FIFO_RESET) {
- fifo_reset(&s->rx);
- s->reg[I_(UFCON)] &= ~UFCON_Rx_FIFO_RESET;
- PRINT_DEBUG("UART%d: Rx FIFO Reset\n", s->channel);
- }
- if (val & UFCON_Tx_FIFO_RESET) {
- fifo_reset(&s->tx);
- s->reg[I_(UFCON)] &= ~UFCON_Tx_FIFO_RESET;
- PRINT_DEBUG("UART%d: Tx FIFO Reset\n", s->channel);
- }
- break;
-
- case UTXH:
- if (s->chr) {
- s->reg[I_(UTRSTAT)] &= ~(UTRSTAT_TRANSMITTER_EMPTY |
- UTRSTAT_Tx_BUFFER_EMPTY);
- ch = (uint8_t)val;
- qemu_chr_fe_write(s->chr, &ch, 1);
-#if DEBUG_Tx_DATA
- fprintf(stderr, "%c", ch);
-#endif
- s->reg[I_(UTRSTAT)] |= UTRSTAT_TRANSMITTER_EMPTY |
- UTRSTAT_Tx_BUFFER_EMPTY;
- s->reg[I_(UINTSP)] |= UINTSP_TXD;
- exynos4210_uart_update_irq(s);
- }
- break;
-
- case UINTP:
- s->reg[I_(UINTP)] &= ~val;
- s->reg[I_(UINTSP)] &= ~val;
- PRINT_DEBUG("UART%d: UINTP [%04x] have been cleared: %08x\n",
- s->channel, offset, s->reg[I_(UINTP)]);
- exynos4210_uart_update_irq(s);
- break;
- case UTRSTAT:
- case UERSTAT:
- case UFSTAT:
- case UMSTAT:
- case URXH:
- PRINT_DEBUG("UART%d: Trying to write into RO register: %s [%04x]\n",
- s->channel, exynos4210_uart_regname(offset), offset);
- break;
- case UINTSP:
- s->reg[I_(UINTSP)] &= ~val;
- break;
- case UINTM:
- s->reg[I_(UINTM)] = val;
- exynos4210_uart_update_irq(s);
- break;
- case UCON:
- case UMCON:
- default:
- s->reg[I_(offset)] = val;
- break;
- }
-}
-static uint64_t exynos4210_uart_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- Exynos4210UartState *s = (Exynos4210UartState *)opaque;
- uint32_t res;
-
- switch (offset) {
- case UERSTAT: /* Read Only */
- res = s->reg[I_(UERSTAT)];
- s->reg[I_(UERSTAT)] = 0;
- return res;
- case UFSTAT: /* Read Only */
- s->reg[I_(UFSTAT)] = fifo_elements_number(&s->rx) & 0xff;
- if (fifo_empty_elements_number(&s->rx) == 0) {
- s->reg[I_(UFSTAT)] |= UFSTAT_Rx_FIFO_FULL;
- s->reg[I_(UFSTAT)] &= ~0xff;
- }
- return s->reg[I_(UFSTAT)];
- case URXH:
- if (s->reg[I_(UFCON)] & UFCON_FIFO_ENABLE) {
- if (fifo_elements_number(&s->rx)) {
- res = fifo_retrieve(&s->rx);
-#if DEBUG_Rx_DATA
- fprintf(stderr, "%c", res);
-#endif
- if (!fifo_elements_number(&s->rx)) {
- s->reg[I_(UTRSTAT)] &= ~UTRSTAT_Rx_BUFFER_DATA_READY;
- } else {
- s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY;
- }
- } else {
- s->reg[I_(UINTSP)] |= UINTSP_ERROR;
- exynos4210_uart_update_irq(s);
- res = 0;
- }
- } else {
- s->reg[I_(UTRSTAT)] &= ~UTRSTAT_Rx_BUFFER_DATA_READY;
- res = s->reg[I_(URXH)];
- }
- return res;
- case UTXH:
- PRINT_DEBUG("UART%d: Trying to read from WO register: %s [%04x]\n",
- s->channel, exynos4210_uart_regname(offset), offset);
- break;
- default:
- return s->reg[I_(offset)];
- }
-
- return 0;
-}
-
-static const MemoryRegionOps exynos4210_uart_ops = {
- .read = exynos4210_uart_read,
- .write = exynos4210_uart_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .max_access_size = 4,
- .unaligned = false
- },
-};
-
-static int exynos4210_uart_can_receive(void *opaque)
-{
- Exynos4210UartState *s = (Exynos4210UartState *)opaque;
-
- return fifo_empty_elements_number(&s->rx);
-}
-
-
-static void exynos4210_uart_receive(void *opaque, const uint8_t *buf, int size)
-{
- Exynos4210UartState *s = (Exynos4210UartState *)opaque;
- int i;
-
- if (s->reg[I_(UFCON)] & UFCON_FIFO_ENABLE) {
- if (fifo_empty_elements_number(&s->rx) < size) {
- for (i = 0; i < fifo_empty_elements_number(&s->rx); i++) {
- fifo_store(&s->rx, buf[i]);
- }
- s->reg[I_(UINTSP)] |= UINTSP_ERROR;
- s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY;
- } else {
- for (i = 0; i < size; i++) {
- fifo_store(&s->rx, buf[i]);
- }
- s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY;
- }
- /* XXX: Around here we maybe should check Rx trigger level */
- s->reg[I_(UINTSP)] |= UINTSP_RXD;
- } else {
- s->reg[I_(URXH)] = buf[0];
- s->reg[I_(UINTSP)] |= UINTSP_RXD;
- s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY;
- }
-
- exynos4210_uart_update_irq(s);
-}
-
-
-static void exynos4210_uart_event(void *opaque, int event)
-{
- Exynos4210UartState *s = (Exynos4210UartState *)opaque;
-
- if (event == CHR_EVENT_BREAK) {
- /* When the RxDn is held in logic 0, then a null byte is pushed into the
- * fifo */
- fifo_store(&s->rx, '\0');
- s->reg[I_(UERSTAT)] |= UERSTAT_BREAK;
- exynos4210_uart_update_irq(s);
- }
-}
-
-
-static void exynos4210_uart_reset(DeviceState *dev)
-{
- Exynos4210UartState *s = EXYNOS4210_UART(dev);
- int i;
-
- for (i = 0; i < ARRAY_SIZE(exynos4210_uart_regs); i++) {
- s->reg[I_(exynos4210_uart_regs[i].offset)] =
- exynos4210_uart_regs[i].reset_value;
- }
-
- fifo_reset(&s->rx);
- fifo_reset(&s->tx);
-
- PRINT_DEBUG("UART%d: Rx FIFO size: %d\n", s->channel, s->rx.size);
-}
-
-static const VMStateDescription vmstate_exynos4210_uart_fifo = {
- .name = "exynos4210.uart.fifo",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(sp, Exynos4210UartFIFO),
- VMSTATE_UINT32(rp, Exynos4210UartFIFO),
- VMSTATE_VBUFFER_UINT32(data, Exynos4210UartFIFO, 1, NULL, 0, size),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_exynos4210_uart = {
- .name = "exynos4210.uart",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT(rx, Exynos4210UartState, 1,
- vmstate_exynos4210_uart_fifo, Exynos4210UartFIFO),
- VMSTATE_UINT32_ARRAY(reg, Exynos4210UartState,
- EXYNOS4210_UART_REGS_MEM_SIZE / sizeof(uint32_t)),
- VMSTATE_END_OF_LIST()
- }
-};
-
-DeviceState *exynos4210_uart_create(hwaddr addr,
- int fifo_size,
- int channel,
- CharDriverState *chr,
- qemu_irq irq)
-{
- DeviceState *dev;
- SysBusDevice *bus;
-
- const char chr_name[] = "serial";
- char label[ARRAY_SIZE(chr_name) + 1];
-
- dev = qdev_create(NULL, TYPE_EXYNOS4210_UART);
-
- if (!chr) {
- if (channel >= MAX_SERIAL_PORTS) {
- error_report("Only %d serial ports are supported by QEMU",
- MAX_SERIAL_PORTS);
- exit(1);
- }
- chr = serial_hds[channel];
- if (!chr) {
- snprintf(label, ARRAY_SIZE(label), "%s%d", chr_name, channel);
- chr = qemu_chr_new(label, "null", NULL);
- if (!(chr)) {
- error_report("Can't assign serial port to UART%d", channel);
- exit(1);
- }
- }
- }
-
- qdev_prop_set_chr(dev, "chardev", chr);
- qdev_prop_set_uint32(dev, "channel", channel);
- qdev_prop_set_uint32(dev, "rx-size", fifo_size);
- qdev_prop_set_uint32(dev, "tx-size", fifo_size);
-
- bus = SYS_BUS_DEVICE(dev);
- qdev_init_nofail(dev);
- if (addr != (hwaddr)-1) {
- sysbus_mmio_map(bus, 0, addr);
- }
- sysbus_connect_irq(bus, 0, irq);
-
- return dev;
-}
-
-static int exynos4210_uart_init(SysBusDevice *dev)
-{
- Exynos4210UartState *s = EXYNOS4210_UART(dev);
-
- /* memory mapping */
- memory_region_init_io(&s->iomem, OBJECT(s), &exynos4210_uart_ops, s,
- "exynos4210.uart", EXYNOS4210_UART_REGS_MEM_SIZE);
- sysbus_init_mmio(dev, &s->iomem);
-
- sysbus_init_irq(dev, &s->irq);
-
- qemu_chr_add_handlers(s->chr, exynos4210_uart_can_receive,
- exynos4210_uart_receive, exynos4210_uart_event, s);
-
- return 0;
-}
-
-static Property exynos4210_uart_properties[] = {
- DEFINE_PROP_CHR("chardev", Exynos4210UartState, chr),
- DEFINE_PROP_UINT32("channel", Exynos4210UartState, channel, 0),
- DEFINE_PROP_UINT32("rx-size", Exynos4210UartState, rx.size, 16),
- DEFINE_PROP_UINT32("tx-size", Exynos4210UartState, tx.size, 16),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void exynos4210_uart_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = exynos4210_uart_init;
- dc->reset = exynos4210_uart_reset;
- dc->props = exynos4210_uart_properties;
- dc->vmsd = &vmstate_exynos4210_uart;
-}
-
-static const TypeInfo exynos4210_uart_info = {
- .name = TYPE_EXYNOS4210_UART,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(Exynos4210UartState),
- .class_init = exynos4210_uart_class_init,
-};
-
-static void exynos4210_uart_register(void)
-{
- type_register_static(&exynos4210_uart_info);
-}
-
-type_init(exynos4210_uart_register)
diff --git a/qemu/hw/char/grlib_apbuart.c b/qemu/hw/char/grlib_apbuart.c
deleted file mode 100644
index 871524c82..000000000
--- a/qemu/hw/char/grlib_apbuart.c
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
- * QEMU GRLIB APB UART Emulator
- *
- * Copyright (c) 2010-2011 AdaCore
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "sysemu/char.h"
-
-#include "trace.h"
-
-#define UART_REG_SIZE 20 /* Size of memory mapped registers */
-
-/* UART status register fields */
-#define UART_DATA_READY (1 << 0)
-#define UART_TRANSMIT_SHIFT_EMPTY (1 << 1)
-#define UART_TRANSMIT_FIFO_EMPTY (1 << 2)
-#define UART_BREAK_RECEIVED (1 << 3)
-#define UART_OVERRUN (1 << 4)
-#define UART_PARITY_ERROR (1 << 5)
-#define UART_FRAMING_ERROR (1 << 6)
-#define UART_TRANSMIT_FIFO_HALF (1 << 7)
-#define UART_RECEIVE_FIFO_HALF (1 << 8)
-#define UART_TRANSMIT_FIFO_FULL (1 << 9)
-#define UART_RECEIVE_FIFO_FULL (1 << 10)
-
-/* UART control register fields */
-#define UART_RECEIVE_ENABLE (1 << 0)
-#define UART_TRANSMIT_ENABLE (1 << 1)
-#define UART_RECEIVE_INTERRUPT (1 << 2)
-#define UART_TRANSMIT_INTERRUPT (1 << 3)
-#define UART_PARITY_SELECT (1 << 4)
-#define UART_PARITY_ENABLE (1 << 5)
-#define UART_FLOW_CONTROL (1 << 6)
-#define UART_LOOPBACK (1 << 7)
-#define UART_EXTERNAL_CLOCK (1 << 8)
-#define UART_RECEIVE_FIFO_INTERRUPT (1 << 9)
-#define UART_TRANSMIT_FIFO_INTERRUPT (1 << 10)
-#define UART_FIFO_DEBUG_MODE (1 << 11)
-#define UART_OUTPUT_ENABLE (1 << 12)
-#define UART_FIFO_AVAILABLE (1 << 31)
-
-/* Memory mapped register offsets */
-#define DATA_OFFSET 0x00
-#define STATUS_OFFSET 0x04
-#define CONTROL_OFFSET 0x08
-#define SCALER_OFFSET 0x0C /* not supported */
-#define FIFO_DEBUG_OFFSET 0x10 /* not supported */
-
-#define FIFO_LENGTH 1024
-
-#define TYPE_GRLIB_APB_UART "grlib,apbuart"
-#define GRLIB_APB_UART(obj) \
- OBJECT_CHECK(UART, (obj), TYPE_GRLIB_APB_UART)
-
-typedef struct UART {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- qemu_irq irq;
-
- CharDriverState *chr;
-
- /* registers */
- uint32_t status;
- uint32_t control;
-
- /* FIFO */
- char buffer[FIFO_LENGTH];
- int len;
- int current;
-} UART;
-
-static int uart_data_to_read(UART *uart)
-{
- return uart->current < uart->len;
-}
-
-static char uart_pop(UART *uart)
-{
- char ret;
-
- if (uart->len == 0) {
- uart->status &= ~UART_DATA_READY;
- return 0;
- }
-
- ret = uart->buffer[uart->current++];
-
- if (uart->current >= uart->len) {
- /* Flush */
- uart->len = 0;
- uart->current = 0;
- }
-
- if (!uart_data_to_read(uart)) {
- uart->status &= ~UART_DATA_READY;
- }
-
- return ret;
-}
-
-static void uart_add_to_fifo(UART *uart,
- const uint8_t *buffer,
- int length)
-{
- if (uart->len + length > FIFO_LENGTH) {
- abort();
- }
- memcpy(uart->buffer + uart->len, buffer, length);
- uart->len += length;
-}
-
-static int grlib_apbuart_can_receive(void *opaque)
-{
- UART *uart = opaque;
-
- return FIFO_LENGTH - uart->len;
-}
-
-static void grlib_apbuart_receive(void *opaque, const uint8_t *buf, int size)
-{
- UART *uart = opaque;
-
- if (uart->control & UART_RECEIVE_ENABLE) {
- uart_add_to_fifo(uart, buf, size);
-
- uart->status |= UART_DATA_READY;
-
- if (uart->control & UART_RECEIVE_INTERRUPT) {
- qemu_irq_pulse(uart->irq);
- }
- }
-}
-
-static void grlib_apbuart_event(void *opaque, int event)
-{
- trace_grlib_apbuart_event(event);
-}
-
-
-static uint64_t grlib_apbuart_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- UART *uart = opaque;
-
- addr &= 0xff;
-
- /* Unit registers */
- switch (addr) {
- case DATA_OFFSET:
- case DATA_OFFSET + 3: /* when only one byte read */
- return uart_pop(uart);
-
- case STATUS_OFFSET:
- /* Read Only */
- return uart->status;
-
- case CONTROL_OFFSET:
- return uart->control;
-
- case SCALER_OFFSET:
- /* Not supported */
- return 0;
-
- default:
- trace_grlib_apbuart_readl_unknown(addr);
- return 0;
- }
-}
-
-static void grlib_apbuart_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- UART *uart = opaque;
- unsigned char c = 0;
-
- addr &= 0xff;
-
- /* Unit registers */
- switch (addr) {
- case DATA_OFFSET:
- case DATA_OFFSET + 3: /* When only one byte write */
- /* Transmit when character device available and transmitter enabled */
- if ((uart->chr) && (uart->control & UART_TRANSMIT_ENABLE)) {
- c = value & 0xFF;
- qemu_chr_fe_write(uart->chr, &c, 1);
- /* Generate interrupt */
- if (uart->control & UART_TRANSMIT_INTERRUPT) {
- qemu_irq_pulse(uart->irq);
- }
- }
- return;
-
- case STATUS_OFFSET:
- /* Read Only */
- return;
-
- case CONTROL_OFFSET:
- uart->control = value;
- return;
-
- case SCALER_OFFSET:
- /* Not supported */
- return;
-
- default:
- break;
- }
-
- trace_grlib_apbuart_writel_unknown(addr, value);
-}
-
-static const MemoryRegionOps grlib_apbuart_ops = {
- .write = grlib_apbuart_write,
- .read = grlib_apbuart_read,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int grlib_apbuart_init(SysBusDevice *dev)
-{
- UART *uart = GRLIB_APB_UART(dev);
-
- qemu_chr_add_handlers(uart->chr,
- grlib_apbuart_can_receive,
- grlib_apbuart_receive,
- grlib_apbuart_event,
- uart);
-
- sysbus_init_irq(dev, &uart->irq);
-
- memory_region_init_io(&uart->iomem, OBJECT(uart), &grlib_apbuart_ops, uart,
- "uart", UART_REG_SIZE);
-
- sysbus_init_mmio(dev, &uart->iomem);
-
- return 0;
-}
-
-static void grlib_apbuart_reset(DeviceState *d)
-{
- UART *uart = GRLIB_APB_UART(d);
-
- /* Transmitter FIFO and shift registers are always empty in QEMU */
- uart->status = UART_TRANSMIT_FIFO_EMPTY | UART_TRANSMIT_SHIFT_EMPTY;
- /* Everything is off */
- uart->control = 0;
- /* Flush receive FIFO */
- uart->len = 0;
- uart->current = 0;
-}
-
-static Property grlib_apbuart_properties[] = {
- DEFINE_PROP_CHR("chrdev", UART, chr),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void grlib_apbuart_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = grlib_apbuart_init;
- dc->reset = grlib_apbuart_reset;
- dc->props = grlib_apbuart_properties;
-}
-
-static const TypeInfo grlib_apbuart_info = {
- .name = TYPE_GRLIB_APB_UART,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(UART),
- .class_init = grlib_apbuart_class_init,
-};
-
-static void grlib_apbuart_register_types(void)
-{
- type_register_static(&grlib_apbuart_info);
-}
-
-type_init(grlib_apbuart_register_types)
diff --git a/qemu/hw/char/imx_serial.c b/qemu/hw/char/imx_serial.c
deleted file mode 100644
index 6df74ac7c..000000000
--- a/qemu/hw/char/imx_serial.c
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- * IMX31 UARTS
- *
- * Copyright (c) 2008 OKL
- * Originally Written by Hans Jiang
- * Copyright (c) 2011 NICTA Pty Ltd.
- * Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- * This is a `bare-bones' implementation of the IMX series serial ports.
- * TODO:
- * -- implement FIFOs. The real hardware has 32 word transmit
- * and receive FIFOs; we currently use a 1-char buffer
- * -- implement DMA
- * -- implement BAUD-rate and modem lines, for when the backend
- * is a real serial device.
- */
-
-#include "qemu/osdep.h"
-#include "hw/char/imx_serial.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/char.h"
-
-#ifndef DEBUG_IMX_UART
-#define DEBUG_IMX_UART 0
-#endif
-
-#define DPRINTF(fmt, args...) \
- do { \
- if (DEBUG_IMX_UART) { \
- fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_SERIAL, \
- __func__, ##args); \
- } \
- } while (0)
-
-static const VMStateDescription vmstate_imx_serial = {
- .name = TYPE_IMX_SERIAL,
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_INT32(readbuff, IMXSerialState),
- VMSTATE_UINT32(usr1, IMXSerialState),
- VMSTATE_UINT32(usr2, IMXSerialState),
- VMSTATE_UINT32(ucr1, IMXSerialState),
- VMSTATE_UINT32(uts1, IMXSerialState),
- VMSTATE_UINT32(onems, IMXSerialState),
- VMSTATE_UINT32(ufcr, IMXSerialState),
- VMSTATE_UINT32(ubmr, IMXSerialState),
- VMSTATE_UINT32(ubrc, IMXSerialState),
- VMSTATE_UINT32(ucr3, IMXSerialState),
- VMSTATE_END_OF_LIST()
- },
-};
-
-static void imx_update(IMXSerialState *s)
-{
- uint32_t flags;
-
- flags = (s->usr1 & s->ucr1) & (USR1_TRDY|USR1_RRDY);
- if (s->ucr1 & UCR1_TXMPTYEN) {
- flags |= (s->uts1 & UTS1_TXEMPTY);
- } else {
- flags &= ~USR1_TRDY;
- }
-
- qemu_set_irq(s->irq, !!flags);
-}
-
-static void imx_serial_reset(IMXSerialState *s)
-{
-
- s->usr1 = USR1_TRDY | USR1_RXDS;
- /*
- * Fake attachment of a terminal: assert RTS.
- */
- s->usr1 |= USR1_RTSS;
- s->usr2 = USR2_TXFE | USR2_TXDC | USR2_DCDIN;
- s->uts1 = UTS1_RXEMPTY | UTS1_TXEMPTY;
- s->ucr1 = 0;
- s->ucr2 = UCR2_SRST;
- s->ucr3 = 0x700;
- s->ubmr = 0;
- s->ubrc = 4;
- s->readbuff = URXD_ERR;
-}
-
-static void imx_serial_reset_at_boot(DeviceState *dev)
-{
- IMXSerialState *s = IMX_SERIAL(dev);
-
- imx_serial_reset(s);
-
- /*
- * enable the uart on boot, so messages from the linux decompresser
- * are visible. On real hardware this is done by the boot rom
- * before anything else is loaded.
- */
- s->ucr1 = UCR1_UARTEN;
- s->ucr2 = UCR2_TXEN;
-
-}
-
-static uint64_t imx_serial_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- IMXSerialState *s = (IMXSerialState *)opaque;
- uint32_t c;
-
- DPRINTF("read(offset=0x%" HWADDR_PRIx ")\n", offset);
-
- switch (offset >> 2) {
- case 0x0: /* URXD */
- c = s->readbuff;
- if (!(s->uts1 & UTS1_RXEMPTY)) {
- /* Character is valid */
- c |= URXD_CHARRDY;
- s->usr1 &= ~USR1_RRDY;
- s->usr2 &= ~USR2_RDR;
- s->uts1 |= UTS1_RXEMPTY;
- imx_update(s);
- if (s->chr) {
- qemu_chr_accept_input(s->chr);
- }
- }
- return c;
-
- case 0x20: /* UCR1 */
- return s->ucr1;
-
- case 0x21: /* UCR2 */
- return s->ucr2;
-
- case 0x25: /* USR1 */
- return s->usr1;
-
- case 0x26: /* USR2 */
- return s->usr2;
-
- case 0x2A: /* BRM Modulator */
- return s->ubmr;
-
- case 0x2B: /* Baud Rate Count */
- return s->ubrc;
-
- case 0x2d: /* Test register */
- return s->uts1;
-
- case 0x24: /* UFCR */
- return s->ufcr;
-
- case 0x2c:
- return s->onems;
-
- case 0x22: /* UCR3 */
- return s->ucr3;
-
- case 0x23: /* UCR4 */
- case 0x29: /* BRM Incremental */
- return 0x0; /* TODO */
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
- HWADDR_PRIx "\n", TYPE_IMX_SERIAL, __func__, offset);
- return 0;
- }
-}
-
-static void imx_serial_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- IMXSerialState *s = (IMXSerialState *)opaque;
- unsigned char ch;
-
- DPRINTF("write(offset=0x%" HWADDR_PRIx ", value = 0x%x) to %s\n",
- offset, (unsigned int)value, s->chr ? s->chr->label : "NODEV");
-
- switch (offset >> 2) {
- case 0x10: /* UTXD */
- ch = value;
- if (s->ucr2 & UCR2_TXEN) {
- if (s->chr) {
- qemu_chr_fe_write(s->chr, &ch, 1);
- }
- s->usr1 &= ~USR1_TRDY;
- imx_update(s);
- s->usr1 |= USR1_TRDY;
- imx_update(s);
- }
- break;
-
- case 0x20: /* UCR1 */
- s->ucr1 = value & 0xffff;
-
- DPRINTF("write(ucr1=%x)\n", (unsigned int)value);
-
- imx_update(s);
- break;
-
- case 0x21: /* UCR2 */
- /*
- * Only a few bits in control register 2 are implemented as yet.
- * If it's intended to use a real serial device as a back-end, this
- * register will have to be implemented more fully.
- */
- if (!(value & UCR2_SRST)) {
- imx_serial_reset(s);
- imx_update(s);
- value |= UCR2_SRST;
- }
- if (value & UCR2_RXEN) {
- if (!(s->ucr2 & UCR2_RXEN)) {
- if (s->chr) {
- qemu_chr_accept_input(s->chr);
- }
- }
- }
- s->ucr2 = value & 0xffff;
- break;
-
- case 0x25: /* USR1 */
- value &= USR1_AWAKE | USR1_AIRINT | USR1_DTRD | USR1_AGTIM |
- USR1_FRAMERR | USR1_ESCF | USR1_RTSD | USR1_PARTYER;
- s->usr1 &= ~value;
- break;
-
- case 0x26: /* USR2 */
- /*
- * Writing 1 to some bits clears them; all other
- * values are ignored
- */
- value &= USR2_ADET | USR2_DTRF | USR2_IDLE | USR2_ACST |
- USR2_RIDELT | USR2_IRINT | USR2_WAKE |
- USR2_DCDDELT | USR2_RTSF | USR2_BRCD | USR2_ORE;
- s->usr2 &= ~value;
- break;
-
- /*
- * Linux expects to see what it writes to these registers
- * We don't currently alter the baud rate
- */
- case 0x29: /* UBIR */
- s->ubrc = value & 0xffff;
- break;
-
- case 0x2a: /* UBMR */
- s->ubmr = value & 0xffff;
- break;
-
- case 0x2c: /* One ms reg */
- s->onems = value & 0xffff;
- break;
-
- case 0x24: /* FIFO control register */
- s->ufcr = value & 0xffff;
- break;
-
- case 0x22: /* UCR3 */
- s->ucr3 = value & 0xffff;
- break;
-
- case 0x2d: /* UTS1 */
- case 0x23: /* UCR4 */
- qemu_log_mask(LOG_UNIMP, "[%s]%s: Unimplemented reg 0x%"
- HWADDR_PRIx "\n", TYPE_IMX_SERIAL, __func__, offset);
- /* TODO */
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
- HWADDR_PRIx "\n", TYPE_IMX_SERIAL, __func__, offset);
- }
-}
-
-static int imx_can_receive(void *opaque)
-{
- IMXSerialState *s = (IMXSerialState *)opaque;
- return !(s->usr1 & USR1_RRDY);
-}
-
-static void imx_put_data(void *opaque, uint32_t value)
-{
- IMXSerialState *s = (IMXSerialState *)opaque;
-
- DPRINTF("received char\n");
-
- s->usr1 |= USR1_RRDY;
- s->usr2 |= USR2_RDR;
- s->uts1 &= ~UTS1_RXEMPTY;
- s->readbuff = value;
- imx_update(s);
-}
-
-static void imx_receive(void *opaque, const uint8_t *buf, int size)
-{
- imx_put_data(opaque, *buf);
-}
-
-static void imx_event(void *opaque, int event)
-{
- if (event == CHR_EVENT_BREAK) {
- imx_put_data(opaque, URXD_BRK);
- }
-}
-
-
-static const struct MemoryRegionOps imx_serial_ops = {
- .read = imx_serial_read,
- .write = imx_serial_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void imx_serial_realize(DeviceState *dev, Error **errp)
-{
- IMXSerialState *s = IMX_SERIAL(dev);
-
- if (s->chr) {
- qemu_chr_add_handlers(s->chr, imx_can_receive, imx_receive,
- imx_event, s);
- } else {
- DPRINTF("No char dev for uart\n");
- }
-}
-
-static void imx_serial_init(Object *obj)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- IMXSerialState *s = IMX_SERIAL(obj);
-
- memory_region_init_io(&s->iomem, obj, &imx_serial_ops, s,
- TYPE_IMX_SERIAL, 0x1000);
- sysbus_init_mmio(sbd, &s->iomem);
- sysbus_init_irq(sbd, &s->irq);
-}
-
-static Property imx_serial_properties[] = {
- DEFINE_PROP_CHR("chardev", IMXSerialState, chr),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void imx_serial_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = imx_serial_realize;
- dc->vmsd = &vmstate_imx_serial;
- dc->reset = imx_serial_reset_at_boot;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
- dc->desc = "i.MX series UART";
- dc->props = imx_serial_properties;
-}
-
-static const TypeInfo imx_serial_info = {
- .name = TYPE_IMX_SERIAL,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(IMXSerialState),
- .instance_init = imx_serial_init,
- .class_init = imx_serial_class_init,
-};
-
-static void imx_serial_register_types(void)
-{
- type_register_static(&imx_serial_info);
-}
-
-type_init(imx_serial_register_types)
diff --git a/qemu/hw/char/ipoctal232.c b/qemu/hw/char/ipoctal232.c
deleted file mode 100644
index bc0ae4980..000000000
--- a/qemu/hw/char/ipoctal232.c
+++ /dev/null
@@ -1,604 +0,0 @@
-/*
- * QEMU GE IP-Octal 232 IndustryPack emulation
- *
- * Copyright (C) 2012 Igalia, S.L.
- * Author: Alberto Garcia <agarcia@igalia.com>
- *
- * This code is licensed under the GNU GPL v2 or (at your option) any
- * later version.
- */
-
-#include "qemu/osdep.h"
-#include "hw/ipack/ipack.h"
-#include "qemu/bitops.h"
-#include "sysemu/char.h"
-
-/* #define DEBUG_IPOCTAL */
-
-#ifdef DEBUG_IPOCTAL
-#define DPRINTF2(fmt, ...) \
- do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF2(fmt, ...) do { } while (0)
-#endif
-
-#define DPRINTF(fmt, ...) DPRINTF2("IP-Octal: " fmt, ## __VA_ARGS__)
-
-#define RX_FIFO_SIZE 3
-
-/* The IP-Octal has 8 channels (a-h)
- divided into 4 blocks (A-D) */
-#define N_CHANNELS 8
-#define N_BLOCKS 4
-
-#define REG_MRa 0x01
-#define REG_MRb 0x11
-#define REG_SRa 0x03
-#define REG_SRb 0x13
-#define REG_CSRa 0x03
-#define REG_CSRb 0x13
-#define REG_CRa 0x05
-#define REG_CRb 0x15
-#define REG_RHRa 0x07
-#define REG_RHRb 0x17
-#define REG_THRa 0x07
-#define REG_THRb 0x17
-#define REG_ACR 0x09
-#define REG_ISR 0x0B
-#define REG_IMR 0x0B
-#define REG_OPCR 0x1B
-
-#define CR_ENABLE_RX BIT(0)
-#define CR_DISABLE_RX BIT(1)
-#define CR_ENABLE_TX BIT(2)
-#define CR_DISABLE_TX BIT(3)
-#define CR_CMD(cr) ((cr) >> 4)
-#define CR_NO_OP 0
-#define CR_RESET_MR 1
-#define CR_RESET_RX 2
-#define CR_RESET_TX 3
-#define CR_RESET_ERR 4
-#define CR_RESET_BRKINT 5
-#define CR_START_BRK 6
-#define CR_STOP_BRK 7
-#define CR_ASSERT_RTSN 8
-#define CR_NEGATE_RTSN 9
-#define CR_TIMEOUT_ON 10
-#define CR_TIMEOUT_OFF 12
-
-#define SR_RXRDY BIT(0)
-#define SR_FFULL BIT(1)
-#define SR_TXRDY BIT(2)
-#define SR_TXEMT BIT(3)
-#define SR_OVERRUN BIT(4)
-#define SR_PARITY BIT(5)
-#define SR_FRAMING BIT(6)
-#define SR_BREAK BIT(7)
-
-#define ISR_TXRDYA BIT(0)
-#define ISR_RXRDYA BIT(1)
-#define ISR_BREAKA BIT(2)
-#define ISR_CNTRDY BIT(3)
-#define ISR_TXRDYB BIT(4)
-#define ISR_RXRDYB BIT(5)
-#define ISR_BREAKB BIT(6)
-#define ISR_MPICHG BIT(7)
-#define ISR_TXRDY(CH) (((CH) & 1) ? BIT(4) : BIT(0))
-#define ISR_RXRDY(CH) (((CH) & 1) ? BIT(5) : BIT(1))
-#define ISR_BREAK(CH) (((CH) & 1) ? BIT(6) : BIT(2))
-
-typedef struct IPOctalState IPOctalState;
-typedef struct SCC2698Channel SCC2698Channel;
-typedef struct SCC2698Block SCC2698Block;
-
-struct SCC2698Channel {
- IPOctalState *ipoctal;
- CharDriverState *dev;
- bool rx_enabled;
- uint8_t mr[2];
- uint8_t mr_idx;
- uint8_t sr;
- uint8_t rhr[RX_FIFO_SIZE];
- uint8_t rhr_idx;
- uint8_t rx_pending;
-};
-
-struct SCC2698Block {
- uint8_t imr;
- uint8_t isr;
-};
-
-struct IPOctalState {
- IPackDevice parent_obj;
-
- SCC2698Channel ch[N_CHANNELS];
- SCC2698Block blk[N_BLOCKS];
- uint8_t irq_vector;
-};
-
-#define TYPE_IPOCTAL "ipoctal232"
-
-#define IPOCTAL(obj) \
- OBJECT_CHECK(IPOctalState, (obj), TYPE_IPOCTAL)
-
-static const VMStateDescription vmstate_scc2698_channel = {
- .name = "scc2698_channel",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_BOOL(rx_enabled, SCC2698Channel),
- VMSTATE_UINT8_ARRAY(mr, SCC2698Channel, 2),
- VMSTATE_UINT8(mr_idx, SCC2698Channel),
- VMSTATE_UINT8(sr, SCC2698Channel),
- VMSTATE_UINT8_ARRAY(rhr, SCC2698Channel, RX_FIFO_SIZE),
- VMSTATE_UINT8(rhr_idx, SCC2698Channel),
- VMSTATE_UINT8(rx_pending, SCC2698Channel),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_scc2698_block = {
- .name = "scc2698_block",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(imr, SCC2698Block),
- VMSTATE_UINT8(isr, SCC2698Block),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_ipoctal = {
- .name = "ipoctal232",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_IPACK_DEVICE(parent_obj, IPOctalState),
- VMSTATE_STRUCT_ARRAY(ch, IPOctalState, N_CHANNELS, 1,
- vmstate_scc2698_channel, SCC2698Channel),
- VMSTATE_STRUCT_ARRAY(blk, IPOctalState, N_BLOCKS, 1,
- vmstate_scc2698_block, SCC2698Block),
- VMSTATE_UINT8(irq_vector, IPOctalState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-/* data[10] is 0x0C, not 0x0B as the doc says */
-static const uint8_t id_prom_data[] = {
- 0x49, 0x50, 0x41, 0x43, 0xF0, 0x22,
- 0xA1, 0x00, 0x00, 0x00, 0x0C, 0xCC
-};
-
-static void update_irq(IPOctalState *dev, unsigned block)
-{
- IPackDevice *idev = IPACK_DEVICE(dev);
- /* Blocks A and B interrupt on INT0#, C and D on INT1#.
- Thus, to get the status we have to check two blocks. */
- SCC2698Block *blk0 = &dev->blk[block];
- SCC2698Block *blk1 = &dev->blk[block^1];
- unsigned intno = block / 2;
-
- if ((blk0->isr & blk0->imr) || (blk1->isr & blk1->imr)) {
- qemu_irq_raise(idev->irq[intno]);
- } else {
- qemu_irq_lower(idev->irq[intno]);
- }
-}
-
-static void write_cr(IPOctalState *dev, unsigned channel, uint8_t val)
-{
- SCC2698Channel *ch = &dev->ch[channel];
- SCC2698Block *blk = &dev->blk[channel / 2];
-
- DPRINTF("Write CR%c %u: ", channel + 'a', val);
-
- /* The lower 4 bits are used to enable and disable Tx and Rx */
- if (val & CR_ENABLE_RX) {
- DPRINTF2("Rx on, ");
- ch->rx_enabled = true;
- }
- if (val & CR_DISABLE_RX) {
- DPRINTF2("Rx off, ");
- ch->rx_enabled = false;
- }
- if (val & CR_ENABLE_TX) {
- DPRINTF2("Tx on, ");
- ch->sr |= SR_TXRDY | SR_TXEMT;
- blk->isr |= ISR_TXRDY(channel);
- }
- if (val & CR_DISABLE_TX) {
- DPRINTF2("Tx off, ");
- ch->sr &= ~(SR_TXRDY | SR_TXEMT);
- blk->isr &= ~ISR_TXRDY(channel);
- }
-
- DPRINTF2("cmd: ");
-
- /* The rest of the bits implement different commands */
- switch (CR_CMD(val)) {
- case CR_NO_OP:
- DPRINTF2("none");
- break;
- case CR_RESET_MR:
- DPRINTF2("reset MR");
- ch->mr_idx = 0;
- break;
- case CR_RESET_RX:
- DPRINTF2("reset Rx");
- ch->rx_enabled = false;
- ch->rx_pending = 0;
- ch->sr &= ~SR_RXRDY;
- blk->isr &= ~ISR_RXRDY(channel);
- break;
- case CR_RESET_TX:
- DPRINTF2("reset Tx");
- ch->sr &= ~(SR_TXRDY | SR_TXEMT);
- blk->isr &= ~ISR_TXRDY(channel);
- break;
- case CR_RESET_ERR:
- DPRINTF2("reset err");
- ch->sr &= ~(SR_OVERRUN | SR_PARITY | SR_FRAMING | SR_BREAK);
- break;
- case CR_RESET_BRKINT:
- DPRINTF2("reset brk ch int");
- blk->isr &= ~(ISR_BREAKA | ISR_BREAKB);
- break;
- default:
- DPRINTF2("unsupported 0x%x", CR_CMD(val));
- }
-
- DPRINTF2("\n");
-}
-
-static uint16_t io_read(IPackDevice *ip, uint8_t addr)
-{
- IPOctalState *dev = IPOCTAL(ip);
- uint16_t ret = 0;
- /* addr[7:6]: block (A-D)
- addr[7:5]: channel (a-h)
- addr[5:0]: register */
- unsigned block = addr >> 5;
- unsigned channel = addr >> 4;
- /* Big endian, accessed using 8-bit bytes at odd locations */
- unsigned offset = (addr & 0x1F) ^ 1;
- SCC2698Channel *ch = &dev->ch[channel];
- SCC2698Block *blk = &dev->blk[block];
- uint8_t old_isr = blk->isr;
-
- switch (offset) {
-
- case REG_MRa:
- case REG_MRb:
- ret = ch->mr[ch->mr_idx];
- DPRINTF("Read MR%u%c: 0x%x\n", ch->mr_idx + 1, channel + 'a', ret);
- ch->mr_idx = 1;
- break;
-
- case REG_SRa:
- case REG_SRb:
- ret = ch->sr;
- DPRINTF("Read SR%c: 0x%x\n", channel + 'a', ret);
- break;
-
- case REG_RHRa:
- case REG_RHRb:
- ret = ch->rhr[ch->rhr_idx];
- if (ch->rx_pending > 0) {
- ch->rx_pending--;
- if (ch->rx_pending == 0) {
- ch->sr &= ~SR_RXRDY;
- blk->isr &= ~ISR_RXRDY(channel);
- if (ch->dev) {
- qemu_chr_accept_input(ch->dev);
- }
- } else {
- ch->rhr_idx = (ch->rhr_idx + 1) % RX_FIFO_SIZE;
- }
- if (ch->sr & SR_BREAK) {
- ch->sr &= ~SR_BREAK;
- blk->isr |= ISR_BREAK(channel);
- }
- }
- DPRINTF("Read RHR%c (0x%x)\n", channel + 'a', ret);
- break;
-
- case REG_ISR:
- ret = blk->isr;
- DPRINTF("Read ISR%c: 0x%x\n", block + 'A', ret);
- break;
-
- default:
- DPRINTF("Read unknown/unsupported register 0x%02x\n", offset);
- }
-
- if (old_isr != blk->isr) {
- update_irq(dev, block);
- }
-
- return ret;
-}
-
-static void io_write(IPackDevice *ip, uint8_t addr, uint16_t val)
-{
- IPOctalState *dev = IPOCTAL(ip);
- unsigned reg = val & 0xFF;
- /* addr[7:6]: block (A-D)
- addr[7:5]: channel (a-h)
- addr[5:0]: register */
- unsigned block = addr >> 5;
- unsigned channel = addr >> 4;
- /* Big endian, accessed using 8-bit bytes at odd locations */
- unsigned offset = (addr & 0x1F) ^ 1;
- SCC2698Channel *ch = &dev->ch[channel];
- SCC2698Block *blk = &dev->blk[block];
- uint8_t old_isr = blk->isr;
- uint8_t old_imr = blk->imr;
-
- switch (offset) {
-
- case REG_MRa:
- case REG_MRb:
- ch->mr[ch->mr_idx] = reg;
- DPRINTF("Write MR%u%c 0x%x\n", ch->mr_idx + 1, channel + 'a', reg);
- ch->mr_idx = 1;
- break;
-
- /* Not implemented */
- case REG_CSRa:
- case REG_CSRb:
- DPRINTF("Write CSR%c: 0x%x\n", channel + 'a', reg);
- break;
-
- case REG_CRa:
- case REG_CRb:
- write_cr(dev, channel, reg);
- break;
-
- case REG_THRa:
- case REG_THRb:
- if (ch->sr & SR_TXRDY) {
- DPRINTF("Write THR%c (0x%x)\n", channel + 'a', reg);
- if (ch->dev) {
- uint8_t thr = reg;
- qemu_chr_fe_write(ch->dev, &thr, 1);
- }
- } else {
- DPRINTF("Write THR%c (0x%x), Tx disabled\n", channel + 'a', reg);
- }
- break;
-
- /* Not implemented */
- case REG_ACR:
- DPRINTF("Write ACR%c 0x%x\n", block + 'A', val);
- break;
-
- case REG_IMR:
- DPRINTF("Write IMR%c 0x%x\n", block + 'A', val);
- blk->imr = reg;
- break;
-
- /* Not implemented */
- case REG_OPCR:
- DPRINTF("Write OPCR%c 0x%x\n", block + 'A', val);
- break;
-
- default:
- DPRINTF("Write unknown/unsupported register 0x%02x %u\n", offset, val);
- }
-
- if (old_isr != blk->isr || old_imr != blk->imr) {
- update_irq(dev, block);
- }
-}
-
-static uint16_t id_read(IPackDevice *ip, uint8_t addr)
-{
- uint16_t ret = 0;
- unsigned pos = addr / 2; /* The ID PROM data is stored every other byte */
-
- if (pos < ARRAY_SIZE(id_prom_data)) {
- ret = id_prom_data[pos];
- } else {
- DPRINTF("Attempt to read unavailable PROM data at 0x%x\n", addr);
- }
-
- return ret;
-}
-
-static void id_write(IPackDevice *ip, uint8_t addr, uint16_t val)
-{
- IPOctalState *dev = IPOCTAL(ip);
- if (addr == 1) {
- DPRINTF("Write IRQ vector: %u\n", (unsigned) val);
- dev->irq_vector = val; /* Undocumented, but the hw works like that */
- } else {
- DPRINTF("Attempt to write 0x%x to 0x%x\n", val, addr);
- }
-}
-
-static uint16_t int_read(IPackDevice *ip, uint8_t addr)
-{
- IPOctalState *dev = IPOCTAL(ip);
- /* Read address 0 to ACK INT0# and address 2 to ACK INT1# */
- if (addr != 0 && addr != 2) {
- DPRINTF("Attempt to read from 0x%x\n", addr);
- return 0;
- } else {
- /* Update interrupts if necessary */
- update_irq(dev, addr);
- return dev->irq_vector;
- }
-}
-
-static void int_write(IPackDevice *ip, uint8_t addr, uint16_t val)
-{
- DPRINTF("Attempt to write 0x%x to 0x%x\n", val, addr);
-}
-
-static uint16_t mem_read16(IPackDevice *ip, uint32_t addr)
-{
- DPRINTF("Attempt to read from 0x%x\n", addr);
- return 0;
-}
-
-static void mem_write16(IPackDevice *ip, uint32_t addr, uint16_t val)
-{
- DPRINTF("Attempt to write 0x%x to 0x%x\n", val, addr);
-}
-
-static uint8_t mem_read8(IPackDevice *ip, uint32_t addr)
-{
- DPRINTF("Attempt to read from 0x%x\n", addr);
- return 0;
-}
-
-static void mem_write8(IPackDevice *ip, uint32_t addr, uint8_t val)
-{
- IPOctalState *dev = IPOCTAL(ip);
- if (addr == 1) {
- DPRINTF("Write IRQ vector: %u\n", (unsigned) val);
- dev->irq_vector = val;
- } else {
- DPRINTF("Attempt to write 0x%x to 0x%x\n", val, addr);
- }
-}
-
-static int hostdev_can_receive(void *opaque)
-{
- SCC2698Channel *ch = opaque;
- int available_bytes = RX_FIFO_SIZE - ch->rx_pending;
- return ch->rx_enabled ? available_bytes : 0;
-}
-
-static void hostdev_receive(void *opaque, const uint8_t *buf, int size)
-{
- SCC2698Channel *ch = opaque;
- IPOctalState *dev = ch->ipoctal;
- unsigned pos = ch->rhr_idx + ch->rx_pending;
- int i;
-
- assert(size + ch->rx_pending <= RX_FIFO_SIZE);
-
- /* Copy data to the RxFIFO */
- for (i = 0; i < size; i++) {
- pos %= RX_FIFO_SIZE;
- ch->rhr[pos++] = buf[i];
- }
-
- ch->rx_pending += size;
-
- /* If the RxFIFO was empty raise an interrupt */
- if (!(ch->sr & SR_RXRDY)) {
- unsigned block, channel = 0;
- /* Find channel number to update the ISR register */
- while (&dev->ch[channel] != ch) {
- channel++;
- }
- block = channel / 2;
- dev->blk[block].isr |= ISR_RXRDY(channel);
- ch->sr |= SR_RXRDY;
- update_irq(dev, block);
- }
-}
-
-static void hostdev_event(void *opaque, int event)
-{
- SCC2698Channel *ch = opaque;
- switch (event) {
- case CHR_EVENT_OPENED:
- DPRINTF("Device %s opened\n", ch->dev->label);
- break;
- case CHR_EVENT_BREAK: {
- uint8_t zero = 0;
- DPRINTF("Device %s received break\n", ch->dev->label);
-
- if (!(ch->sr & SR_BREAK)) {
- IPOctalState *dev = ch->ipoctal;
- unsigned block, channel = 0;
-
- while (&dev->ch[channel] != ch) {
- channel++;
- }
- block = channel / 2;
-
- ch->sr |= SR_BREAK;
- dev->blk[block].isr |= ISR_BREAK(channel);
- }
-
- /* Put a zero character in the buffer */
- hostdev_receive(ch, &zero, 1);
- }
- break;
- default:
- DPRINTF("Device %s received event %d\n", ch->dev->label, event);
- }
-}
-
-static void ipoctal_realize(DeviceState *dev, Error **errp)
-{
- IPOctalState *s = IPOCTAL(dev);
- unsigned i;
-
- for (i = 0; i < N_CHANNELS; i++) {
- SCC2698Channel *ch = &s->ch[i];
- ch->ipoctal = s;
-
- /* Redirect IP-Octal channels to host character devices */
- if (ch->dev) {
- qemu_chr_add_handlers(ch->dev, hostdev_can_receive,
- hostdev_receive, hostdev_event, ch);
- DPRINTF("Redirecting channel %u to %s\n", i, ch->dev->label);
- } else {
- DPRINTF("Could not redirect channel %u, no chardev set\n", i);
- }
- }
-}
-
-static Property ipoctal_properties[] = {
- DEFINE_PROP_CHR("chardev0", IPOctalState, ch[0].dev),
- DEFINE_PROP_CHR("chardev1", IPOctalState, ch[1].dev),
- DEFINE_PROP_CHR("chardev2", IPOctalState, ch[2].dev),
- DEFINE_PROP_CHR("chardev3", IPOctalState, ch[3].dev),
- DEFINE_PROP_CHR("chardev4", IPOctalState, ch[4].dev),
- DEFINE_PROP_CHR("chardev5", IPOctalState, ch[5].dev),
- DEFINE_PROP_CHR("chardev6", IPOctalState, ch[6].dev),
- DEFINE_PROP_CHR("chardev7", IPOctalState, ch[7].dev),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void ipoctal_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- IPackDeviceClass *ic = IPACK_DEVICE_CLASS(klass);
-
- ic->realize = ipoctal_realize;
- ic->io_read = io_read;
- ic->io_write = io_write;
- ic->id_read = id_read;
- ic->id_write = id_write;
- ic->int_read = int_read;
- ic->int_write = int_write;
- ic->mem_read16 = mem_read16;
- ic->mem_write16 = mem_write16;
- ic->mem_read8 = mem_read8;
- ic->mem_write8 = mem_write8;
-
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
- dc->desc = "GE IP-Octal 232 8-channel RS-232 IndustryPack";
- dc->props = ipoctal_properties;
- dc->vmsd = &vmstate_ipoctal;
-}
-
-static const TypeInfo ipoctal_info = {
- .name = TYPE_IPOCTAL,
- .parent = TYPE_IPACK_DEVICE,
- .instance_size = sizeof(IPOctalState),
- .class_init = ipoctal_class_init,
-};
-
-static void ipoctal_register_types(void)
-{
- type_register_static(&ipoctal_info);
-}
-
-type_init(ipoctal_register_types)
diff --git a/qemu/hw/char/lm32_juart.c b/qemu/hw/char/lm32_juart.c
deleted file mode 100644
index 5bf8acfe8..000000000
--- a/qemu/hw/char/lm32_juart.c
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * LatticeMico32 JTAG UART model.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "sysemu/char.h"
-
-#include "hw/char/lm32_juart.h"
-
-enum {
- LM32_JUART_MIN_SAVE_VERSION = 0,
- LM32_JUART_CURRENT_SAVE_VERSION = 0,
- LM32_JUART_MAX_SAVE_VERSION = 0,
-};
-
-enum {
- JTX_FULL = (1<<8),
-};
-
-enum {
- JRX_FULL = (1<<8),
-};
-
-#define LM32_JUART(obj) OBJECT_CHECK(LM32JuartState, (obj), TYPE_LM32_JUART)
-
-struct LM32JuartState {
- SysBusDevice parent_obj;
-
- CharDriverState *chr;
-
- uint32_t jtx;
- uint32_t jrx;
-};
-typedef struct LM32JuartState LM32JuartState;
-
-uint32_t lm32_juart_get_jtx(DeviceState *d)
-{
- LM32JuartState *s = LM32_JUART(d);
-
- trace_lm32_juart_get_jtx(s->jtx);
- return s->jtx;
-}
-
-uint32_t lm32_juart_get_jrx(DeviceState *d)
-{
- LM32JuartState *s = LM32_JUART(d);
-
- trace_lm32_juart_get_jrx(s->jrx);
- return s->jrx;
-}
-
-void lm32_juart_set_jtx(DeviceState *d, uint32_t jtx)
-{
- LM32JuartState *s = LM32_JUART(d);
- unsigned char ch = jtx & 0xff;
-
- trace_lm32_juart_set_jtx(s->jtx);
-
- s->jtx = jtx;
- if (s->chr) {
- qemu_chr_fe_write_all(s->chr, &ch, 1);
- }
-}
-
-void lm32_juart_set_jrx(DeviceState *d, uint32_t jtx)
-{
- LM32JuartState *s = LM32_JUART(d);
-
- trace_lm32_juart_set_jrx(s->jrx);
- s->jrx &= ~JRX_FULL;
-}
-
-static void juart_rx(void *opaque, const uint8_t *buf, int size)
-{
- LM32JuartState *s = opaque;
-
- s->jrx = *buf | JRX_FULL;
-}
-
-static int juart_can_rx(void *opaque)
-{
- LM32JuartState *s = opaque;
-
- return !(s->jrx & JRX_FULL);
-}
-
-static void juart_event(void *opaque, int event)
-{
-}
-
-static void juart_reset(DeviceState *d)
-{
- LM32JuartState *s = LM32_JUART(d);
-
- s->jtx = 0;
- s->jrx = 0;
-}
-
-static int lm32_juart_init(SysBusDevice *dev)
-{
- LM32JuartState *s = LM32_JUART(dev);
-
- /* FIXME use a qdev chardev prop instead of qemu_char_get_next_serial() */
- s->chr = qemu_char_get_next_serial();
- if (s->chr) {
- qemu_chr_add_handlers(s->chr, juart_can_rx, juart_rx, juart_event, s);
- }
-
- return 0;
-}
-
-static const VMStateDescription vmstate_lm32_juart = {
- .name = "lm32-juart",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(jtx, LM32JuartState),
- VMSTATE_UINT32(jrx, LM32JuartState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void lm32_juart_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = lm32_juart_init;
- dc->reset = juart_reset;
- dc->vmsd = &vmstate_lm32_juart;
- /* Reason: init() method uses qemu_char_get_next_serial() */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo lm32_juart_info = {
- .name = TYPE_LM32_JUART,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(LM32JuartState),
- .class_init = lm32_juart_class_init,
-};
-
-static void lm32_juart_register_types(void)
-{
- type_register_static(&lm32_juart_info);
-}
-
-type_init(lm32_juart_register_types)
diff --git a/qemu/hw/char/lm32_uart.c b/qemu/hw/char/lm32_uart.c
deleted file mode 100644
index 036813d0f..000000000
--- a/qemu/hw/char/lm32_uart.c
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * QEMU model of the LatticeMico32 UART block.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * Specification available at:
- * http://www.latticesemi.com/documents/mico32uart.pdf
- */
-
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "sysemu/char.h"
-#include "qemu/error-report.h"
-
-enum {
- R_RXTX = 0,
- R_IER,
- R_IIR,
- R_LCR,
- R_MCR,
- R_LSR,
- R_MSR,
- R_DIV,
- R_MAX
-};
-
-enum {
- IER_RBRI = (1<<0),
- IER_THRI = (1<<1),
- IER_RLSI = (1<<2),
- IER_MSI = (1<<3),
-};
-
-enum {
- IIR_STAT = (1<<0),
- IIR_ID0 = (1<<1),
- IIR_ID1 = (1<<2),
-};
-
-enum {
- LCR_WLS0 = (1<<0),
- LCR_WLS1 = (1<<1),
- LCR_STB = (1<<2),
- LCR_PEN = (1<<3),
- LCR_EPS = (1<<4),
- LCR_SP = (1<<5),
- LCR_SB = (1<<6),
-};
-
-enum {
- MCR_DTR = (1<<0),
- MCR_RTS = (1<<1),
-};
-
-enum {
- LSR_DR = (1<<0),
- LSR_OE = (1<<1),
- LSR_PE = (1<<2),
- LSR_FE = (1<<3),
- LSR_BI = (1<<4),
- LSR_THRE = (1<<5),
- LSR_TEMT = (1<<6),
-};
-
-enum {
- MSR_DCTS = (1<<0),
- MSR_DDSR = (1<<1),
- MSR_TERI = (1<<2),
- MSR_DDCD = (1<<3),
- MSR_CTS = (1<<4),
- MSR_DSR = (1<<5),
- MSR_RI = (1<<6),
- MSR_DCD = (1<<7),
-};
-
-#define TYPE_LM32_UART "lm32-uart"
-#define LM32_UART(obj) OBJECT_CHECK(LM32UartState, (obj), TYPE_LM32_UART)
-
-struct LM32UartState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- CharDriverState *chr;
- qemu_irq irq;
-
- uint32_t regs[R_MAX];
-};
-typedef struct LM32UartState LM32UartState;
-
-static void uart_update_irq(LM32UartState *s)
-{
- unsigned int irq;
-
- if ((s->regs[R_LSR] & (LSR_OE | LSR_PE | LSR_FE | LSR_BI))
- && (s->regs[R_IER] & IER_RLSI)) {
- irq = 1;
- s->regs[R_IIR] = IIR_ID1 | IIR_ID0;
- } else if ((s->regs[R_LSR] & LSR_DR) && (s->regs[R_IER] & IER_RBRI)) {
- irq = 1;
- s->regs[R_IIR] = IIR_ID1;
- } else if ((s->regs[R_LSR] & LSR_THRE) && (s->regs[R_IER] & IER_THRI)) {
- irq = 1;
- s->regs[R_IIR] = IIR_ID0;
- } else if ((s->regs[R_MSR] & 0x0f) && (s->regs[R_IER] & IER_MSI)) {
- irq = 1;
- s->regs[R_IIR] = 0;
- } else {
- irq = 0;
- s->regs[R_IIR] = IIR_STAT;
- }
-
- trace_lm32_uart_irq_state(irq);
- qemu_set_irq(s->irq, irq);
-}
-
-static uint64_t uart_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- LM32UartState *s = opaque;
- uint32_t r = 0;
-
- addr >>= 2;
- switch (addr) {
- case R_RXTX:
- r = s->regs[R_RXTX];
- s->regs[R_LSR] &= ~LSR_DR;
- uart_update_irq(s);
- qemu_chr_accept_input(s->chr);
- break;
- case R_IIR:
- case R_LSR:
- case R_MSR:
- r = s->regs[addr];
- break;
- case R_IER:
- case R_LCR:
- case R_MCR:
- case R_DIV:
- error_report("lm32_uart: read access to write only register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- default:
- error_report("lm32_uart: read access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-
- trace_lm32_uart_memory_read(addr << 2, r);
- return r;
-}
-
-static void uart_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- LM32UartState *s = opaque;
- unsigned char ch = value;
-
- trace_lm32_uart_memory_write(addr, value);
-
- addr >>= 2;
- switch (addr) {
- case R_RXTX:
- if (s->chr) {
- qemu_chr_fe_write_all(s->chr, &ch, 1);
- }
- break;
- case R_IER:
- case R_LCR:
- case R_MCR:
- case R_DIV:
- s->regs[addr] = value;
- break;
- case R_IIR:
- case R_LSR:
- case R_MSR:
- error_report("lm32_uart: write access to read only register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- default:
- error_report("lm32_uart: write access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
- uart_update_irq(s);
-}
-
-static const MemoryRegionOps uart_ops = {
- .read = uart_read,
- .write = uart_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static void uart_rx(void *opaque, const uint8_t *buf, int size)
-{
- LM32UartState *s = opaque;
-
- if (s->regs[R_LSR] & LSR_DR) {
- s->regs[R_LSR] |= LSR_OE;
- }
-
- s->regs[R_LSR] |= LSR_DR;
- s->regs[R_RXTX] = *buf;
-
- uart_update_irq(s);
-}
-
-static int uart_can_rx(void *opaque)
-{
- LM32UartState *s = opaque;
-
- return !(s->regs[R_LSR] & LSR_DR);
-}
-
-static void uart_event(void *opaque, int event)
-{
-}
-
-static void uart_reset(DeviceState *d)
-{
- LM32UartState *s = LM32_UART(d);
- int i;
-
- for (i = 0; i < R_MAX; i++) {
- s->regs[i] = 0;
- }
-
- /* defaults */
- s->regs[R_LSR] = LSR_THRE | LSR_TEMT;
-}
-
-static int lm32_uart_init(SysBusDevice *dev)
-{
- LM32UartState *s = LM32_UART(dev);
-
- sysbus_init_irq(dev, &s->irq);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &uart_ops, s,
- "uart", R_MAX * 4);
- sysbus_init_mmio(dev, &s->iomem);
-
- /* FIXME use a qdev chardev prop instead of qemu_char_get_next_serial() */
- s->chr = qemu_char_get_next_serial();
- if (s->chr) {
- qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
- }
-
- return 0;
-}
-
-static const VMStateDescription vmstate_lm32_uart = {
- .name = "lm32-uart",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, LM32UartState, R_MAX),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void lm32_uart_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = lm32_uart_init;
- dc->reset = uart_reset;
- dc->vmsd = &vmstate_lm32_uart;
- /* Reason: init() method uses qemu_char_get_next_serial() */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo lm32_uart_info = {
- .name = TYPE_LM32_UART,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(LM32UartState),
- .class_init = lm32_uart_class_init,
-};
-
-static void lm32_uart_register_types(void)
-{
- type_register_static(&lm32_uart_info);
-}
-
-type_init(lm32_uart_register_types)
diff --git a/qemu/hw/char/mcf_uart.c b/qemu/hw/char/mcf_uart.c
deleted file mode 100644
index 3c0438fd7..000000000
--- a/qemu/hw/char/mcf_uart.c
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * ColdFire UART emulation.
- *
- * Copyright (c) 2007 CodeSourcery.
- *
- * This code is licensed under the GPL
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/m68k/mcf.h"
-#include "sysemu/char.h"
-#include "exec/address-spaces.h"
-
-typedef struct {
- MemoryRegion iomem;
- uint8_t mr[2];
- uint8_t sr;
- uint8_t isr;
- uint8_t imr;
- uint8_t bg1;
- uint8_t bg2;
- uint8_t fifo[4];
- uint8_t tb;
- int current_mr;
- int fifo_len;
- int tx_enabled;
- int rx_enabled;
- qemu_irq irq;
- CharDriverState *chr;
-} mcf_uart_state;
-
-/* UART Status Register bits. */
-#define MCF_UART_RxRDY 0x01
-#define MCF_UART_FFULL 0x02
-#define MCF_UART_TxRDY 0x04
-#define MCF_UART_TxEMP 0x08
-#define MCF_UART_OE 0x10
-#define MCF_UART_PE 0x20
-#define MCF_UART_FE 0x40
-#define MCF_UART_RB 0x80
-
-/* Interrupt flags. */
-#define MCF_UART_TxINT 0x01
-#define MCF_UART_RxINT 0x02
-#define MCF_UART_DBINT 0x04
-#define MCF_UART_COSINT 0x80
-
-/* UMR1 flags. */
-#define MCF_UART_BC0 0x01
-#define MCF_UART_BC1 0x02
-#define MCF_UART_PT 0x04
-#define MCF_UART_PM0 0x08
-#define MCF_UART_PM1 0x10
-#define MCF_UART_ERR 0x20
-#define MCF_UART_RxIRQ 0x40
-#define MCF_UART_RxRTS 0x80
-
-static void mcf_uart_update(mcf_uart_state *s)
-{
- s->isr &= ~(MCF_UART_TxINT | MCF_UART_RxINT);
- if (s->sr & MCF_UART_TxRDY)
- s->isr |= MCF_UART_TxINT;
- if ((s->sr & ((s->mr[0] & MCF_UART_RxIRQ)
- ? MCF_UART_FFULL : MCF_UART_RxRDY)) != 0)
- s->isr |= MCF_UART_RxINT;
-
- qemu_set_irq(s->irq, (s->isr & s->imr) != 0);
-}
-
-uint64_t mcf_uart_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- mcf_uart_state *s = (mcf_uart_state *)opaque;
- switch (addr & 0x3f) {
- case 0x00:
- return s->mr[s->current_mr];
- case 0x04:
- return s->sr;
- case 0x0c:
- {
- uint8_t val;
- int i;
-
- if (s->fifo_len == 0)
- return 0;
-
- val = s->fifo[0];
- s->fifo_len--;
- for (i = 0; i < s->fifo_len; i++)
- s->fifo[i] = s->fifo[i + 1];
- s->sr &= ~MCF_UART_FFULL;
- if (s->fifo_len == 0)
- s->sr &= ~MCF_UART_RxRDY;
- mcf_uart_update(s);
- qemu_chr_accept_input(s->chr);
- return val;
- }
- case 0x10:
- /* TODO: Implement IPCR. */
- return 0;
- case 0x14:
- return s->isr;
- case 0x18:
- return s->bg1;
- case 0x1c:
- return s->bg2;
- default:
- return 0;
- }
-}
-
-/* Update TxRDY flag and set data if present and enabled. */
-static void mcf_uart_do_tx(mcf_uart_state *s)
-{
- if (s->tx_enabled && (s->sr & MCF_UART_TxEMP) == 0) {
- if (s->chr)
- qemu_chr_fe_write(s->chr, (unsigned char *)&s->tb, 1);
- s->sr |= MCF_UART_TxEMP;
- }
- if (s->tx_enabled) {
- s->sr |= MCF_UART_TxRDY;
- } else {
- s->sr &= ~MCF_UART_TxRDY;
- }
-}
-
-static void mcf_do_command(mcf_uart_state *s, uint8_t cmd)
-{
- /* Misc command. */
- switch ((cmd >> 4) & 7) {
- case 0: /* No-op. */
- break;
- case 1: /* Reset mode register pointer. */
- s->current_mr = 0;
- break;
- case 2: /* Reset receiver. */
- s->rx_enabled = 0;
- s->fifo_len = 0;
- s->sr &= ~(MCF_UART_RxRDY | MCF_UART_FFULL);
- break;
- case 3: /* Reset transmitter. */
- s->tx_enabled = 0;
- s->sr |= MCF_UART_TxEMP;
- s->sr &= ~MCF_UART_TxRDY;
- break;
- case 4: /* Reset error status. */
- break;
- case 5: /* Reset break-change interrupt. */
- s->isr &= ~MCF_UART_DBINT;
- break;
- case 6: /* Start break. */
- case 7: /* Stop break. */
- break;
- }
-
- /* Transmitter command. */
- switch ((cmd >> 2) & 3) {
- case 0: /* No-op. */
- break;
- case 1: /* Enable. */
- s->tx_enabled = 1;
- mcf_uart_do_tx(s);
- break;
- case 2: /* Disable. */
- s->tx_enabled = 0;
- mcf_uart_do_tx(s);
- break;
- case 3: /* Reserved. */
- fprintf(stderr, "mcf_uart: Bad TX command\n");
- break;
- }
-
- /* Receiver command. */
- switch (cmd & 3) {
- case 0: /* No-op. */
- break;
- case 1: /* Enable. */
- s->rx_enabled = 1;
- break;
- case 2:
- s->rx_enabled = 0;
- break;
- case 3: /* Reserved. */
- fprintf(stderr, "mcf_uart: Bad RX command\n");
- break;
- }
-}
-
-void mcf_uart_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- mcf_uart_state *s = (mcf_uart_state *)opaque;
- switch (addr & 0x3f) {
- case 0x00:
- s->mr[s->current_mr] = val;
- s->current_mr = 1;
- break;
- case 0x04:
- /* CSR is ignored. */
- break;
- case 0x08: /* Command Register. */
- mcf_do_command(s, val);
- break;
- case 0x0c: /* Transmit Buffer. */
- s->sr &= ~MCF_UART_TxEMP;
- s->tb = val;
- mcf_uart_do_tx(s);
- break;
- case 0x10:
- /* ACR is ignored. */
- break;
- case 0x14:
- s->imr = val;
- break;
- default:
- break;
- }
- mcf_uart_update(s);
-}
-
-static void mcf_uart_reset(mcf_uart_state *s)
-{
- s->fifo_len = 0;
- s->mr[0] = 0;
- s->mr[1] = 0;
- s->sr = MCF_UART_TxEMP;
- s->tx_enabled = 0;
- s->rx_enabled = 0;
- s->isr = 0;
- s->imr = 0;
-}
-
-static void mcf_uart_push_byte(mcf_uart_state *s, uint8_t data)
-{
- /* Break events overwrite the last byte if the fifo is full. */
- if (s->fifo_len == 4)
- s->fifo_len--;
-
- s->fifo[s->fifo_len] = data;
- s->fifo_len++;
- s->sr |= MCF_UART_RxRDY;
- if (s->fifo_len == 4)
- s->sr |= MCF_UART_FFULL;
-
- mcf_uart_update(s);
-}
-
-static void mcf_uart_event(void *opaque, int event)
-{
- mcf_uart_state *s = (mcf_uart_state *)opaque;
-
- switch (event) {
- case CHR_EVENT_BREAK:
- s->isr |= MCF_UART_DBINT;
- mcf_uart_push_byte(s, 0);
- break;
- default:
- break;
- }
-}
-
-static int mcf_uart_can_receive(void *opaque)
-{
- mcf_uart_state *s = (mcf_uart_state *)opaque;
-
- return s->rx_enabled && (s->sr & MCF_UART_FFULL) == 0;
-}
-
-static void mcf_uart_receive(void *opaque, const uint8_t *buf, int size)
-{
- mcf_uart_state *s = (mcf_uart_state *)opaque;
-
- mcf_uart_push_byte(s, buf[0]);
-}
-
-void *mcf_uart_init(qemu_irq irq, CharDriverState *chr)
-{
- mcf_uart_state *s;
-
- s = g_malloc0(sizeof(mcf_uart_state));
- s->chr = chr;
- s->irq = irq;
- if (chr) {
- qemu_chr_fe_claim_no_fail(chr);
- qemu_chr_add_handlers(chr, mcf_uart_can_receive, mcf_uart_receive,
- mcf_uart_event, s);
- }
- mcf_uart_reset(s);
- return s;
-}
-
-static const MemoryRegionOps mcf_uart_ops = {
- .read = mcf_uart_read,
- .write = mcf_uart_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-void mcf_uart_mm_init(MemoryRegion *sysmem,
- hwaddr base,
- qemu_irq irq,
- CharDriverState *chr)
-{
- mcf_uart_state *s;
-
- s = mcf_uart_init(irq, chr);
- memory_region_init_io(&s->iomem, NULL, &mcf_uart_ops, s, "uart", 0x40);
- memory_region_add_subregion(sysmem, base, &s->iomem);
-}
diff --git a/qemu/hw/char/milkymist-uart.c b/qemu/hw/char/milkymist-uart.c
deleted file mode 100644
index 03b36b223..000000000
--- a/qemu/hw/char/milkymist-uart.c
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * QEMU model of the Milkymist UART block.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * Specification available at:
- * http://www.milkymist.org/socdoc/uart.pdf
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "sysemu/char.h"
-#include "qemu/error-report.h"
-
-enum {
- R_RXTX = 0,
- R_DIV,
- R_STAT,
- R_CTRL,
- R_DBG,
- R_MAX
-};
-
-enum {
- STAT_THRE = (1<<0),
- STAT_RX_EVT = (1<<1),
- STAT_TX_EVT = (1<<2),
-};
-
-enum {
- CTRL_RX_IRQ_EN = (1<<0),
- CTRL_TX_IRQ_EN = (1<<1),
- CTRL_THRU_EN = (1<<2),
-};
-
-enum {
- DBG_BREAK_EN = (1<<0),
-};
-
-#define TYPE_MILKYMIST_UART "milkymist-uart"
-#define MILKYMIST_UART(obj) \
- OBJECT_CHECK(MilkymistUartState, (obj), TYPE_MILKYMIST_UART)
-
-struct MilkymistUartState {
- SysBusDevice parent_obj;
-
- MemoryRegion regs_region;
- CharDriverState *chr;
- qemu_irq irq;
-
- uint32_t regs[R_MAX];
-};
-typedef struct MilkymistUartState MilkymistUartState;
-
-static void uart_update_irq(MilkymistUartState *s)
-{
- int rx_event = s->regs[R_STAT] & STAT_RX_EVT;
- int tx_event = s->regs[R_STAT] & STAT_TX_EVT;
- int rx_irq_en = s->regs[R_CTRL] & CTRL_RX_IRQ_EN;
- int tx_irq_en = s->regs[R_CTRL] & CTRL_TX_IRQ_EN;
-
- if ((rx_irq_en && rx_event) || (tx_irq_en && tx_event)) {
- trace_milkymist_uart_raise_irq();
- qemu_irq_raise(s->irq);
- } else {
- trace_milkymist_uart_lower_irq();
- qemu_irq_lower(s->irq);
- }
-}
-
-static uint64_t uart_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- MilkymistUartState *s = opaque;
- uint32_t r = 0;
-
- addr >>= 2;
- switch (addr) {
- case R_RXTX:
- r = s->regs[addr];
- break;
- case R_DIV:
- case R_STAT:
- case R_CTRL:
- case R_DBG:
- r = s->regs[addr];
- break;
-
- default:
- error_report("milkymist_uart: read access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-
- trace_milkymist_uart_memory_read(addr << 2, r);
-
- return r;
-}
-
-static void uart_write(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
- MilkymistUartState *s = opaque;
- unsigned char ch = value;
-
- trace_milkymist_uart_memory_write(addr, value);
-
- addr >>= 2;
- switch (addr) {
- case R_RXTX:
- if (s->chr) {
- qemu_chr_fe_write_all(s->chr, &ch, 1);
- }
- s->regs[R_STAT] |= STAT_TX_EVT;
- break;
- case R_DIV:
- case R_CTRL:
- case R_DBG:
- s->regs[addr] = value;
- break;
-
- case R_STAT:
- /* write one to clear bits */
- s->regs[addr] &= ~(value & (STAT_RX_EVT | STAT_TX_EVT));
- qemu_chr_accept_input(s->chr);
- break;
-
- default:
- error_report("milkymist_uart: write access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-
- uart_update_irq(s);
-}
-
-static const MemoryRegionOps uart_mmio_ops = {
- .read = uart_read,
- .write = uart_write,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void uart_rx(void *opaque, const uint8_t *buf, int size)
-{
- MilkymistUartState *s = opaque;
-
- assert(!(s->regs[R_STAT] & STAT_RX_EVT));
-
- s->regs[R_STAT] |= STAT_RX_EVT;
- s->regs[R_RXTX] = *buf;
-
- uart_update_irq(s);
-}
-
-static int uart_can_rx(void *opaque)
-{
- MilkymistUartState *s = opaque;
-
- return !(s->regs[R_STAT] & STAT_RX_EVT);
-}
-
-static void uart_event(void *opaque, int event)
-{
-}
-
-static void milkymist_uart_reset(DeviceState *d)
-{
- MilkymistUartState *s = MILKYMIST_UART(d);
- int i;
-
- for (i = 0; i < R_MAX; i++) {
- s->regs[i] = 0;
- }
-
- /* THRE is always set */
- s->regs[R_STAT] = STAT_THRE;
-}
-
-static void milkymist_uart_realize(DeviceState *dev, Error **errp)
-{
- MilkymistUartState *s = MILKYMIST_UART(dev);
-
- /* FIXME use a qdev chardev prop instead of qemu_char_get_next_serial() */
- s->chr = qemu_char_get_next_serial();
- if (s->chr) {
- qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
- }
-}
-
-static void milkymist_uart_init(Object *obj)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- MilkymistUartState *s = MILKYMIST_UART(obj);
-
- sysbus_init_irq(sbd, &s->irq);
-
- memory_region_init_io(&s->regs_region, OBJECT(s), &uart_mmio_ops, s,
- "milkymist-uart", R_MAX * 4);
- sysbus_init_mmio(sbd, &s->regs_region);
-}
-
-static const VMStateDescription vmstate_milkymist_uart = {
- .name = "milkymist-uart",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, MilkymistUartState, R_MAX),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void milkymist_uart_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = milkymist_uart_realize;
- dc->reset = milkymist_uart_reset;
- dc->vmsd = &vmstate_milkymist_uart;
- /* Reason: realize() method uses qemu_char_get_next_serial() */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo milkymist_uart_info = {
- .name = TYPE_MILKYMIST_UART,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(MilkymistUartState),
- .instance_init = milkymist_uart_init,
- .class_init = milkymist_uart_class_init,
-};
-
-static void milkymist_uart_register_types(void)
-{
- type_register_static(&milkymist_uart_info);
-}
-
-type_init(milkymist_uart_register_types)
diff --git a/qemu/hw/char/omap_uart.c b/qemu/hw/char/omap_uart.c
deleted file mode 100644
index 415bec5fa..000000000
--- a/qemu/hw/char/omap_uart.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * TI OMAP processors UART emulation.
- *
- * Copyright (C) 2006-2008 Andrzej Zaborowski <balrog@zabor.org>
- * Copyright (C) 2007-2009 Nokia Corporation
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "qemu/osdep.h"
-#include "sysemu/char.h"
-#include "hw/hw.h"
-#include "hw/arm/omap.h"
-#include "hw/char/serial.h"
-#include "exec/address-spaces.h"
-
-/* UARTs */
-struct omap_uart_s {
- MemoryRegion iomem;
- hwaddr base;
- SerialState *serial; /* TODO */
- struct omap_target_agent_s *ta;
- omap_clk fclk;
- qemu_irq irq;
-
- uint8_t eblr;
- uint8_t syscontrol;
- uint8_t wkup;
- uint8_t cfps;
- uint8_t mdr[2];
- uint8_t scr;
- uint8_t clksel;
-};
-
-void omap_uart_reset(struct omap_uart_s *s)
-{
- s->eblr = 0x00;
- s->syscontrol = 0;
- s->wkup = 0x3f;
- s->cfps = 0x69;
- s->clksel = 0;
-}
-
-struct omap_uart_s *omap_uart_init(hwaddr base,
- qemu_irq irq, omap_clk fclk, omap_clk iclk,
- qemu_irq txdma, qemu_irq rxdma,
- const char *label, CharDriverState *chr)
-{
- struct omap_uart_s *s = g_new0(struct omap_uart_s, 1);
-
- s->base = base;
- s->fclk = fclk;
- s->irq = irq;
- s->serial = serial_mm_init(get_system_memory(), base, 2, irq,
- omap_clk_getrate(fclk)/16,
- chr ?: qemu_chr_new(label, "null", NULL),
- DEVICE_NATIVE_ENDIAN);
- return s;
-}
-
-static uint64_t omap_uart_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_uart_s *s = (struct omap_uart_s *) opaque;
-
- if (size == 4) {
- return omap_badwidth_read8(opaque, addr);
- }
-
- switch (addr) {
- case 0x20: /* MDR1 */
- return s->mdr[0];
- case 0x24: /* MDR2 */
- return s->mdr[1];
- case 0x40: /* SCR */
- return s->scr;
- case 0x44: /* SSR */
- return 0x0;
- case 0x48: /* EBLR (OMAP2) */
- return s->eblr;
- case 0x4C: /* OSC_12M_SEL (OMAP1) */
- return s->clksel;
- case 0x50: /* MVR */
- return 0x30;
- case 0x54: /* SYSC (OMAP2) */
- return s->syscontrol;
- case 0x58: /* SYSS (OMAP2) */
- return 1;
- case 0x5c: /* WER (OMAP2) */
- return s->wkup;
- case 0x60: /* CFPS (OMAP2) */
- return s->cfps;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_uart_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_uart_s *s = (struct omap_uart_s *) opaque;
-
- if (size == 4) {
- omap_badwidth_write8(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x20: /* MDR1 */
- s->mdr[0] = value & 0x7f;
- break;
- case 0x24: /* MDR2 */
- s->mdr[1] = value & 0xff;
- break;
- case 0x40: /* SCR */
- s->scr = value & 0xff;
- break;
- case 0x48: /* EBLR (OMAP2) */
- s->eblr = value & 0xff;
- break;
- case 0x4C: /* OSC_12M_SEL (OMAP1) */
- s->clksel = value & 1;
- break;
- case 0x44: /* SSR */
- case 0x50: /* MVR */
- case 0x58: /* SYSS (OMAP2) */
- OMAP_RO_REG(addr);
- break;
- case 0x54: /* SYSC (OMAP2) */
- s->syscontrol = value & 0x1d;
- if (value & 2)
- omap_uart_reset(s);
- break;
- case 0x5c: /* WER (OMAP2) */
- s->wkup = value & 0x7f;
- break;
- case 0x60: /* CFPS (OMAP2) */
- s->cfps = value & 0xff;
- break;
- default:
- OMAP_BAD_REG(addr);
- }
-}
-
-static const MemoryRegionOps omap_uart_ops = {
- .read = omap_uart_read,
- .write = omap_uart_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct omap_uart_s *omap2_uart_init(MemoryRegion *sysmem,
- struct omap_target_agent_s *ta,
- qemu_irq irq, omap_clk fclk, omap_clk iclk,
- qemu_irq txdma, qemu_irq rxdma,
- const char *label, CharDriverState *chr)
-{
- hwaddr base = omap_l4_attach(ta, 0, NULL);
- struct omap_uart_s *s = omap_uart_init(base, irq,
- fclk, iclk, txdma, rxdma, label, chr);
-
- memory_region_init_io(&s->iomem, NULL, &omap_uart_ops, s, "omap.uart", 0x100);
-
- s->ta = ta;
-
- memory_region_add_subregion(sysmem, base + 0x20, &s->iomem);
-
- return s;
-}
-
-void omap_uart_attach(struct omap_uart_s *s, CharDriverState *chr)
-{
- /* TODO: Should reuse or destroy current s->serial */
- s->serial = serial_mm_init(get_system_memory(), s->base, 2, s->irq,
- omap_clk_getrate(s->fclk) / 16,
- chr ?: qemu_chr_new("null", "null", NULL),
- DEVICE_NATIVE_ENDIAN);
-}
diff --git a/qemu/hw/char/parallel.c b/qemu/hw/char/parallel.c
deleted file mode 100644
index 11c78fed8..000000000
--- a/qemu/hw/char/parallel.c
+++ /dev/null
@@ -1,645 +0,0 @@
-/*
- * QEMU Parallel PORT emulation
- *
- * Copyright (c) 2003-2005 Fabrice Bellard
- * Copyright (c) 2007 Marko Kohtala
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/hw.h"
-#include "sysemu/char.h"
-#include "hw/isa/isa.h"
-#include "hw/i386/pc.h"
-#include "sysemu/sysemu.h"
-
-//#define DEBUG_PARALLEL
-
-#ifdef DEBUG_PARALLEL
-#define pdebug(fmt, ...) printf("pp: " fmt, ## __VA_ARGS__)
-#else
-#define pdebug(fmt, ...) ((void)0)
-#endif
-
-#define PARA_REG_DATA 0
-#define PARA_REG_STS 1
-#define PARA_REG_CTR 2
-#define PARA_REG_EPP_ADDR 3
-#define PARA_REG_EPP_DATA 4
-
-/*
- * These are the definitions for the Printer Status Register
- */
-#define PARA_STS_BUSY 0x80 /* Busy complement */
-#define PARA_STS_ACK 0x40 /* Acknowledge */
-#define PARA_STS_PAPER 0x20 /* Out of paper */
-#define PARA_STS_ONLINE 0x10 /* Online */
-#define PARA_STS_ERROR 0x08 /* Error complement */
-#define PARA_STS_TMOUT 0x01 /* EPP timeout */
-
-/*
- * These are the definitions for the Printer Control Register
- */
-#define PARA_CTR_DIR 0x20 /* Direction (1=read, 0=write) */
-#define PARA_CTR_INTEN 0x10 /* IRQ Enable */
-#define PARA_CTR_SELECT 0x08 /* Select In complement */
-#define PARA_CTR_INIT 0x04 /* Initialize Printer complement */
-#define PARA_CTR_AUTOLF 0x02 /* Auto linefeed complement */
-#define PARA_CTR_STROBE 0x01 /* Strobe complement */
-
-#define PARA_CTR_SIGNAL (PARA_CTR_SELECT|PARA_CTR_INIT|PARA_CTR_AUTOLF|PARA_CTR_STROBE)
-
-typedef struct ParallelState {
- MemoryRegion iomem;
- uint8_t dataw;
- uint8_t datar;
- uint8_t status;
- uint8_t control;
- qemu_irq irq;
- int irq_pending;
- CharDriverState *chr;
- int hw_driver;
- int epp_timeout;
- uint32_t last_read_offset; /* For debugging */
- /* Memory-mapped interface */
- int it_shift;
-} ParallelState;
-
-#define TYPE_ISA_PARALLEL "isa-parallel"
-#define ISA_PARALLEL(obj) \
- OBJECT_CHECK(ISAParallelState, (obj), TYPE_ISA_PARALLEL)
-
-typedef struct ISAParallelState {
- ISADevice parent_obj;
-
- uint32_t index;
- uint32_t iobase;
- uint32_t isairq;
- ParallelState state;
-} ISAParallelState;
-
-static void parallel_update_irq(ParallelState *s)
-{
- if (s->irq_pending)
- qemu_irq_raise(s->irq);
- else
- qemu_irq_lower(s->irq);
-}
-
-static void
-parallel_ioport_write_sw(void *opaque, uint32_t addr, uint32_t val)
-{
- ParallelState *s = opaque;
-
- pdebug("write addr=0x%02x val=0x%02x\n", addr, val);
-
- addr &= 7;
- switch(addr) {
- case PARA_REG_DATA:
- s->dataw = val;
- parallel_update_irq(s);
- break;
- case PARA_REG_CTR:
- val |= 0xc0;
- if ((val & PARA_CTR_INIT) == 0 ) {
- s->status = PARA_STS_BUSY;
- s->status |= PARA_STS_ACK;
- s->status |= PARA_STS_ONLINE;
- s->status |= PARA_STS_ERROR;
- }
- else if (val & PARA_CTR_SELECT) {
- if (val & PARA_CTR_STROBE) {
- s->status &= ~PARA_STS_BUSY;
- if ((s->control & PARA_CTR_STROBE) == 0)
- qemu_chr_fe_write(s->chr, &s->dataw, 1);
- } else {
- if (s->control & PARA_CTR_INTEN) {
- s->irq_pending = 1;
- }
- }
- }
- parallel_update_irq(s);
- s->control = val;
- break;
- }
-}
-
-static void parallel_ioport_write_hw(void *opaque, uint32_t addr, uint32_t val)
-{
- ParallelState *s = opaque;
- uint8_t parm = val;
- int dir;
-
- /* Sometimes programs do several writes for timing purposes on old
- HW. Take care not to waste time on writes that do nothing. */
-
- s->last_read_offset = ~0U;
-
- addr &= 7;
- switch(addr) {
- case PARA_REG_DATA:
- if (s->dataw == val)
- return;
- pdebug("wd%02x\n", val);
- qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_WRITE_DATA, &parm);
- s->dataw = val;
- break;
- case PARA_REG_STS:
- pdebug("ws%02x\n", val);
- if (val & PARA_STS_TMOUT)
- s->epp_timeout = 0;
- break;
- case PARA_REG_CTR:
- val |= 0xc0;
- if (s->control == val)
- return;
- pdebug("wc%02x\n", val);
-
- if ((val & PARA_CTR_DIR) != (s->control & PARA_CTR_DIR)) {
- if (val & PARA_CTR_DIR) {
- dir = 1;
- } else {
- dir = 0;
- }
- qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_DATA_DIR, &dir);
- parm &= ~PARA_CTR_DIR;
- }
-
- qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_WRITE_CONTROL, &parm);
- s->control = val;
- break;
- case PARA_REG_EPP_ADDR:
- if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT)
- /* Controls not correct for EPP address cycle, so do nothing */
- pdebug("wa%02x s\n", val);
- else {
- struct ParallelIOArg ioarg = { .buffer = &parm, .count = 1 };
- if (qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE_ADDR, &ioarg)) {
- s->epp_timeout = 1;
- pdebug("wa%02x t\n", val);
- }
- else
- pdebug("wa%02x\n", val);
- }
- break;
- case PARA_REG_EPP_DATA:
- if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT)
- /* Controls not correct for EPP data cycle, so do nothing */
- pdebug("we%02x s\n", val);
- else {
- struct ParallelIOArg ioarg = { .buffer = &parm, .count = 1 };
- if (qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg)) {
- s->epp_timeout = 1;
- pdebug("we%02x t\n", val);
- }
- else
- pdebug("we%02x\n", val);
- }
- break;
- }
-}
-
-static void
-parallel_ioport_eppdata_write_hw2(void *opaque, uint32_t addr, uint32_t val)
-{
- ParallelState *s = opaque;
- uint16_t eppdata = cpu_to_le16(val);
- int err;
- struct ParallelIOArg ioarg = {
- .buffer = &eppdata, .count = sizeof(eppdata)
- };
- if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT) {
- /* Controls not correct for EPP data cycle, so do nothing */
- pdebug("we%04x s\n", val);
- return;
- }
- err = qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg);
- if (err) {
- s->epp_timeout = 1;
- pdebug("we%04x t\n", val);
- }
- else
- pdebug("we%04x\n", val);
-}
-
-static void
-parallel_ioport_eppdata_write_hw4(void *opaque, uint32_t addr, uint32_t val)
-{
- ParallelState *s = opaque;
- uint32_t eppdata = cpu_to_le32(val);
- int err;
- struct ParallelIOArg ioarg = {
- .buffer = &eppdata, .count = sizeof(eppdata)
- };
- if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT) {
- /* Controls not correct for EPP data cycle, so do nothing */
- pdebug("we%08x s\n", val);
- return;
- }
- err = qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg);
- if (err) {
- s->epp_timeout = 1;
- pdebug("we%08x t\n", val);
- }
- else
- pdebug("we%08x\n", val);
-}
-
-static uint32_t parallel_ioport_read_sw(void *opaque, uint32_t addr)
-{
- ParallelState *s = opaque;
- uint32_t ret = 0xff;
-
- addr &= 7;
- switch(addr) {
- case PARA_REG_DATA:
- if (s->control & PARA_CTR_DIR)
- ret = s->datar;
- else
- ret = s->dataw;
- break;
- case PARA_REG_STS:
- ret = s->status;
- s->irq_pending = 0;
- if ((s->status & PARA_STS_BUSY) == 0 && (s->control & PARA_CTR_STROBE) == 0) {
- /* XXX Fixme: wait 5 microseconds */
- if (s->status & PARA_STS_ACK)
- s->status &= ~PARA_STS_ACK;
- else {
- /* XXX Fixme: wait 5 microseconds */
- s->status |= PARA_STS_ACK;
- s->status |= PARA_STS_BUSY;
- }
- }
- parallel_update_irq(s);
- break;
- case PARA_REG_CTR:
- ret = s->control;
- break;
- }
- pdebug("read addr=0x%02x val=0x%02x\n", addr, ret);
- return ret;
-}
-
-static uint32_t parallel_ioport_read_hw(void *opaque, uint32_t addr)
-{
- ParallelState *s = opaque;
- uint8_t ret = 0xff;
- addr &= 7;
- switch(addr) {
- case PARA_REG_DATA:
- qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_READ_DATA, &ret);
- if (s->last_read_offset != addr || s->datar != ret)
- pdebug("rd%02x\n", ret);
- s->datar = ret;
- break;
- case PARA_REG_STS:
- qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_READ_STATUS, &ret);
- ret &= ~PARA_STS_TMOUT;
- if (s->epp_timeout)
- ret |= PARA_STS_TMOUT;
- if (s->last_read_offset != addr || s->status != ret)
- pdebug("rs%02x\n", ret);
- s->status = ret;
- break;
- case PARA_REG_CTR:
- /* s->control has some bits fixed to 1. It is zero only when
- it has not been yet written to. */
- if (s->control == 0) {
- qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_READ_CONTROL, &ret);
- if (s->last_read_offset != addr)
- pdebug("rc%02x\n", ret);
- s->control = ret;
- }
- else {
- ret = s->control;
- if (s->last_read_offset != addr)
- pdebug("rc%02x\n", ret);
- }
- break;
- case PARA_REG_EPP_ADDR:
- if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT))
- /* Controls not correct for EPP addr cycle, so do nothing */
- pdebug("ra%02x s\n", ret);
- else {
- struct ParallelIOArg ioarg = { .buffer = &ret, .count = 1 };
- if (qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ_ADDR, &ioarg)) {
- s->epp_timeout = 1;
- pdebug("ra%02x t\n", ret);
- }
- else
- pdebug("ra%02x\n", ret);
- }
- break;
- case PARA_REG_EPP_DATA:
- if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT))
- /* Controls not correct for EPP data cycle, so do nothing */
- pdebug("re%02x s\n", ret);
- else {
- struct ParallelIOArg ioarg = { .buffer = &ret, .count = 1 };
- if (qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg)) {
- s->epp_timeout = 1;
- pdebug("re%02x t\n", ret);
- }
- else
- pdebug("re%02x\n", ret);
- }
- break;
- }
- s->last_read_offset = addr;
- return ret;
-}
-
-static uint32_t
-parallel_ioport_eppdata_read_hw2(void *opaque, uint32_t addr)
-{
- ParallelState *s = opaque;
- uint32_t ret;
- uint16_t eppdata = ~0;
- int err;
- struct ParallelIOArg ioarg = {
- .buffer = &eppdata, .count = sizeof(eppdata)
- };
- if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT)) {
- /* Controls not correct for EPP data cycle, so do nothing */
- pdebug("re%04x s\n", eppdata);
- return eppdata;
- }
- err = qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg);
- ret = le16_to_cpu(eppdata);
-
- if (err) {
- s->epp_timeout = 1;
- pdebug("re%04x t\n", ret);
- }
- else
- pdebug("re%04x\n", ret);
- return ret;
-}
-
-static uint32_t
-parallel_ioport_eppdata_read_hw4(void *opaque, uint32_t addr)
-{
- ParallelState *s = opaque;
- uint32_t ret;
- uint32_t eppdata = ~0U;
- int err;
- struct ParallelIOArg ioarg = {
- .buffer = &eppdata, .count = sizeof(eppdata)
- };
- if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT)) {
- /* Controls not correct for EPP data cycle, so do nothing */
- pdebug("re%08x s\n", eppdata);
- return eppdata;
- }
- err = qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg);
- ret = le32_to_cpu(eppdata);
-
- if (err) {
- s->epp_timeout = 1;
- pdebug("re%08x t\n", ret);
- }
- else
- pdebug("re%08x\n", ret);
- return ret;
-}
-
-static void parallel_ioport_ecp_write(void *opaque, uint32_t addr, uint32_t val)
-{
- pdebug("wecp%d=%02x\n", addr & 7, val);
-}
-
-static uint32_t parallel_ioport_ecp_read(void *opaque, uint32_t addr)
-{
- uint8_t ret = 0xff;
-
- pdebug("recp%d:%02x\n", addr & 7, ret);
- return ret;
-}
-
-static void parallel_reset(void *opaque)
-{
- ParallelState *s = opaque;
-
- s->datar = ~0;
- s->dataw = ~0;
- s->status = PARA_STS_BUSY;
- s->status |= PARA_STS_ACK;
- s->status |= PARA_STS_ONLINE;
- s->status |= PARA_STS_ERROR;
- s->status |= PARA_STS_TMOUT;
- s->control = PARA_CTR_SELECT;
- s->control |= PARA_CTR_INIT;
- s->control |= 0xc0;
- s->irq_pending = 0;
- s->hw_driver = 0;
- s->epp_timeout = 0;
- s->last_read_offset = ~0U;
-}
-
-static const int isa_parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc };
-
-static const MemoryRegionPortio isa_parallel_portio_hw_list[] = {
- { 0, 8, 1,
- .read = parallel_ioport_read_hw,
- .write = parallel_ioport_write_hw },
- { 4, 1, 2,
- .read = parallel_ioport_eppdata_read_hw2,
- .write = parallel_ioport_eppdata_write_hw2 },
- { 4, 1, 4,
- .read = parallel_ioport_eppdata_read_hw4,
- .write = parallel_ioport_eppdata_write_hw4 },
- { 0x400, 8, 1,
- .read = parallel_ioport_ecp_read,
- .write = parallel_ioport_ecp_write },
- PORTIO_END_OF_LIST(),
-};
-
-static const MemoryRegionPortio isa_parallel_portio_sw_list[] = {
- { 0, 8, 1,
- .read = parallel_ioport_read_sw,
- .write = parallel_ioport_write_sw },
- PORTIO_END_OF_LIST(),
-};
-
-
-static const VMStateDescription vmstate_parallel_isa = {
- .name = "parallel_isa",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(state.dataw, ISAParallelState),
- VMSTATE_UINT8(state.datar, ISAParallelState),
- VMSTATE_UINT8(state.status, ISAParallelState),
- VMSTATE_UINT8(state.control, ISAParallelState),
- VMSTATE_INT32(state.irq_pending, ISAParallelState),
- VMSTATE_INT32(state.epp_timeout, ISAParallelState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-
-static void parallel_isa_realizefn(DeviceState *dev, Error **errp)
-{
- static int index;
- ISADevice *isadev = ISA_DEVICE(dev);
- ISAParallelState *isa = ISA_PARALLEL(dev);
- ParallelState *s = &isa->state;
- int base;
- uint8_t dummy;
-
- if (!s->chr) {
- error_setg(errp, "Can't create parallel device, empty char device");
- return;
- }
-
- if (isa->index == -1) {
- isa->index = index;
- }
- if (isa->index >= MAX_PARALLEL_PORTS) {
- error_setg(errp, "Max. supported number of parallel ports is %d.",
- MAX_PARALLEL_PORTS);
- return;
- }
- if (isa->iobase == -1) {
- isa->iobase = isa_parallel_io[isa->index];
- }
- index++;
-
- base = isa->iobase;
- isa_init_irq(isadev, &s->irq, isa->isairq);
- qemu_register_reset(parallel_reset, s);
-
- if (qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_READ_STATUS, &dummy) == 0) {
- s->hw_driver = 1;
- s->status = dummy;
- }
-
- isa_register_portio_list(isadev, base,
- (s->hw_driver
- ? &isa_parallel_portio_hw_list[0]
- : &isa_parallel_portio_sw_list[0]),
- s, "parallel");
-}
-
-/* Memory mapped interface */
-static uint32_t parallel_mm_readb (void *opaque, hwaddr addr)
-{
- ParallelState *s = opaque;
-
- return parallel_ioport_read_sw(s, addr >> s->it_shift) & 0xFF;
-}
-
-static void parallel_mm_writeb (void *opaque,
- hwaddr addr, uint32_t value)
-{
- ParallelState *s = opaque;
-
- parallel_ioport_write_sw(s, addr >> s->it_shift, value & 0xFF);
-}
-
-static uint32_t parallel_mm_readw (void *opaque, hwaddr addr)
-{
- ParallelState *s = opaque;
-
- return parallel_ioport_read_sw(s, addr >> s->it_shift) & 0xFFFF;
-}
-
-static void parallel_mm_writew (void *opaque,
- hwaddr addr, uint32_t value)
-{
- ParallelState *s = opaque;
-
- parallel_ioport_write_sw(s, addr >> s->it_shift, value & 0xFFFF);
-}
-
-static uint32_t parallel_mm_readl (void *opaque, hwaddr addr)
-{
- ParallelState *s = opaque;
-
- return parallel_ioport_read_sw(s, addr >> s->it_shift);
-}
-
-static void parallel_mm_writel (void *opaque,
- hwaddr addr, uint32_t value)
-{
- ParallelState *s = opaque;
-
- parallel_ioport_write_sw(s, addr >> s->it_shift, value);
-}
-
-static const MemoryRegionOps parallel_mm_ops = {
- .old_mmio = {
- .read = { parallel_mm_readb, parallel_mm_readw, parallel_mm_readl },
- .write = { parallel_mm_writeb, parallel_mm_writew, parallel_mm_writel },
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-/* If fd is zero, it means that the parallel device uses the console */
-bool parallel_mm_init(MemoryRegion *address_space,
- hwaddr base, int it_shift, qemu_irq irq,
- CharDriverState *chr)
-{
- ParallelState *s;
-
- s = g_malloc0(sizeof(ParallelState));
- s->irq = irq;
- s->chr = chr;
- s->it_shift = it_shift;
- qemu_register_reset(parallel_reset, s);
-
- memory_region_init_io(&s->iomem, NULL, &parallel_mm_ops, s,
- "parallel", 8 << it_shift);
- memory_region_add_subregion(address_space, base, &s->iomem);
- return true;
-}
-
-static Property parallel_isa_properties[] = {
- DEFINE_PROP_UINT32("index", ISAParallelState, index, -1),
- DEFINE_PROP_UINT32("iobase", ISAParallelState, iobase, -1),
- DEFINE_PROP_UINT32("irq", ISAParallelState, isairq, 7),
- DEFINE_PROP_CHR("chardev", ISAParallelState, state.chr),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void parallel_isa_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = parallel_isa_realizefn;
- dc->vmsd = &vmstate_parallel_isa;
- dc->props = parallel_isa_properties;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
-}
-
-static const TypeInfo parallel_isa_info = {
- .name = TYPE_ISA_PARALLEL,
- .parent = TYPE_ISA_DEVICE,
- .instance_size = sizeof(ISAParallelState),
- .class_init = parallel_isa_class_initfn,
-};
-
-static void parallel_register_types(void)
-{
- type_register_static(&parallel_isa_info);
-}
-
-type_init(parallel_register_types)
diff --git a/qemu/hw/char/pl011.c b/qemu/hw/char/pl011.c
deleted file mode 100644
index 210c87b4c..000000000
--- a/qemu/hw/char/pl011.c
+++ /dev/null
@@ -1,343 +0,0 @@
-/*
- * Arm PrimeCell PL011 UART
- *
- * Copyright (c) 2006 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "sysemu/char.h"
-
-#define TYPE_PL011 "pl011"
-#define PL011(obj) OBJECT_CHECK(PL011State, (obj), TYPE_PL011)
-
-typedef struct PL011State {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- uint32_t readbuff;
- uint32_t flags;
- uint32_t lcr;
- uint32_t rsr;
- uint32_t cr;
- uint32_t dmacr;
- uint32_t int_enabled;
- uint32_t int_level;
- uint32_t read_fifo[16];
- uint32_t ilpr;
- uint32_t ibrd;
- uint32_t fbrd;
- uint32_t ifl;
- int read_pos;
- int read_count;
- int read_trigger;
- CharDriverState *chr;
- qemu_irq irq;
- const unsigned char *id;
-} PL011State;
-
-#define PL011_INT_TX 0x20
-#define PL011_INT_RX 0x10
-
-#define PL011_FLAG_TXFE 0x80
-#define PL011_FLAG_RXFF 0x40
-#define PL011_FLAG_TXFF 0x20
-#define PL011_FLAG_RXFE 0x10
-
-static const unsigned char pl011_id_arm[8] =
- { 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
-static const unsigned char pl011_id_luminary[8] =
- { 0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 };
-
-static void pl011_update(PL011State *s)
-{
- uint32_t flags;
-
- flags = s->int_level & s->int_enabled;
- qemu_set_irq(s->irq, flags != 0);
-}
-
-static uint64_t pl011_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- PL011State *s = (PL011State *)opaque;
- uint32_t c;
-
- if (offset >= 0xfe0 && offset < 0x1000) {
- return s->id[(offset - 0xfe0) >> 2];
- }
- switch (offset >> 2) {
- case 0: /* UARTDR */
- s->flags &= ~PL011_FLAG_RXFF;
- c = s->read_fifo[s->read_pos];
- if (s->read_count > 0) {
- s->read_count--;
- if (++s->read_pos == 16)
- s->read_pos = 0;
- }
- if (s->read_count == 0) {
- s->flags |= PL011_FLAG_RXFE;
- }
- if (s->read_count == s->read_trigger - 1)
- s->int_level &= ~ PL011_INT_RX;
- s->rsr = c >> 8;
- pl011_update(s);
- if (s->chr) {
- qemu_chr_accept_input(s->chr);
- }
- return c;
- case 1: /* UARTRSR */
- return s->rsr;
- case 6: /* UARTFR */
- return s->flags;
- case 8: /* UARTILPR */
- return s->ilpr;
- case 9: /* UARTIBRD */
- return s->ibrd;
- case 10: /* UARTFBRD */
- return s->fbrd;
- case 11: /* UARTLCR_H */
- return s->lcr;
- case 12: /* UARTCR */
- return s->cr;
- case 13: /* UARTIFLS */
- return s->ifl;
- case 14: /* UARTIMSC */
- return s->int_enabled;
- case 15: /* UARTRIS */
- return s->int_level;
- case 16: /* UARTMIS */
- return s->int_level & s->int_enabled;
- case 18: /* UARTDMACR */
- return s->dmacr;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "pl011_read: Bad offset %x\n", (int)offset);
- return 0;
- }
-}
-
-static void pl011_set_read_trigger(PL011State *s)
-{
-#if 0
- /* The docs say the RX interrupt is triggered when the FIFO exceeds
- the threshold. However linux only reads the FIFO in response to an
- interrupt. Triggering the interrupt when the FIFO is non-empty seems
- to make things work. */
- if (s->lcr & 0x10)
- s->read_trigger = (s->ifl >> 1) & 0x1c;
- else
-#endif
- s->read_trigger = 1;
-}
-
-static void pl011_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PL011State *s = (PL011State *)opaque;
- unsigned char ch;
-
- switch (offset >> 2) {
- case 0: /* UARTDR */
- /* ??? Check if transmitter is enabled. */
- ch = value;
- if (s->chr)
- qemu_chr_fe_write(s->chr, &ch, 1);
- s->int_level |= PL011_INT_TX;
- pl011_update(s);
- break;
- case 1: /* UARTRSR/UARTECR */
- s->rsr = 0;
- break;
- case 6: /* UARTFR */
- /* Writes to Flag register are ignored. */
- break;
- case 8: /* UARTUARTILPR */
- s->ilpr = value;
- break;
- case 9: /* UARTIBRD */
- s->ibrd = value;
- break;
- case 10: /* UARTFBRD */
- s->fbrd = value;
- break;
- case 11: /* UARTLCR_H */
- /* Reset the FIFO state on FIFO enable or disable */
- if ((s->lcr ^ value) & 0x10) {
- s->read_count = 0;
- s->read_pos = 0;
- }
- s->lcr = value;
- pl011_set_read_trigger(s);
- break;
- case 12: /* UARTCR */
- /* ??? Need to implement the enable and loopback bits. */
- s->cr = value;
- break;
- case 13: /* UARTIFS */
- s->ifl = value;
- pl011_set_read_trigger(s);
- break;
- case 14: /* UARTIMSC */
- s->int_enabled = value;
- pl011_update(s);
- break;
- case 17: /* UARTICR */
- s->int_level &= ~value;
- pl011_update(s);
- break;
- case 18: /* UARTDMACR */
- s->dmacr = value;
- if (value & 3) {
- qemu_log_mask(LOG_UNIMP, "pl011: DMA not implemented\n");
- }
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "pl011_write: Bad offset %x\n", (int)offset);
- }
-}
-
-static int pl011_can_receive(void *opaque)
-{
- PL011State *s = (PL011State *)opaque;
-
- if (s->lcr & 0x10)
- return s->read_count < 16;
- else
- return s->read_count < 1;
-}
-
-static void pl011_put_fifo(void *opaque, uint32_t value)
-{
- PL011State *s = (PL011State *)opaque;
- int slot;
-
- slot = s->read_pos + s->read_count;
- if (slot >= 16)
- slot -= 16;
- s->read_fifo[slot] = value;
- s->read_count++;
- s->flags &= ~PL011_FLAG_RXFE;
- if (!(s->lcr & 0x10) || s->read_count == 16) {
- s->flags |= PL011_FLAG_RXFF;
- }
- if (s->read_count == s->read_trigger) {
- s->int_level |= PL011_INT_RX;
- pl011_update(s);
- }
-}
-
-static void pl011_receive(void *opaque, const uint8_t *buf, int size)
-{
- pl011_put_fifo(opaque, *buf);
-}
-
-static void pl011_event(void *opaque, int event)
-{
- if (event == CHR_EVENT_BREAK)
- pl011_put_fifo(opaque, 0x400);
-}
-
-static const MemoryRegionOps pl011_ops = {
- .read = pl011_read,
- .write = pl011_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_pl011 = {
- .name = "pl011",
- .version_id = 2,
- .minimum_version_id = 2,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(readbuff, PL011State),
- VMSTATE_UINT32(flags, PL011State),
- VMSTATE_UINT32(lcr, PL011State),
- VMSTATE_UINT32(rsr, PL011State),
- VMSTATE_UINT32(cr, PL011State),
- VMSTATE_UINT32(dmacr, PL011State),
- VMSTATE_UINT32(int_enabled, PL011State),
- VMSTATE_UINT32(int_level, PL011State),
- VMSTATE_UINT32_ARRAY(read_fifo, PL011State, 16),
- VMSTATE_UINT32(ilpr, PL011State),
- VMSTATE_UINT32(ibrd, PL011State),
- VMSTATE_UINT32(fbrd, PL011State),
- VMSTATE_UINT32(ifl, PL011State),
- VMSTATE_INT32(read_pos, PL011State),
- VMSTATE_INT32(read_count, PL011State),
- VMSTATE_INT32(read_trigger, PL011State),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void pl011_init(Object *obj)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- PL011State *s = PL011(obj);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &pl011_ops, s, "pl011", 0x1000);
- sysbus_init_mmio(sbd, &s->iomem);
- sysbus_init_irq(sbd, &s->irq);
-
- s->read_trigger = 1;
- s->ifl = 0x12;
- s->cr = 0x300;
- s->flags = 0x90;
-
- s->id = pl011_id_arm;
-}
-
-static void pl011_realize(DeviceState *dev, Error **errp)
-{
- PL011State *s = PL011(dev);
-
- /* FIXME use a qdev chardev prop instead of qemu_char_get_next_serial() */
- s->chr = qemu_char_get_next_serial();
-
- if (s->chr) {
- qemu_chr_add_handlers(s->chr, pl011_can_receive, pl011_receive,
- pl011_event, s);
- }
-}
-
-static void pl011_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- dc->realize = pl011_realize;
- dc->vmsd = &vmstate_pl011;
- /* Reason: realize() method uses qemu_char_get_next_serial() */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo pl011_arm_info = {
- .name = TYPE_PL011,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PL011State),
- .instance_init = pl011_init,
- .class_init = pl011_class_init,
-};
-
-static void pl011_luminary_init(Object *obj)
-{
- PL011State *s = PL011(obj);
-
- s->id = pl011_id_luminary;
-}
-
-static const TypeInfo pl011_luminary_info = {
- .name = "pl011_luminary",
- .parent = TYPE_PL011,
- .instance_init = pl011_luminary_init,
-};
-
-static void pl011_register_types(void)
-{
- type_register_static(&pl011_arm_info);
- type_register_static(&pl011_luminary_info);
-}
-
-type_init(pl011_register_types)
diff --git a/qemu/hw/char/sclpconsole-lm.c b/qemu/hw/char/sclpconsole-lm.c
deleted file mode 100644
index 7d4ff8120..000000000
--- a/qemu/hw/char/sclpconsole-lm.c
+++ /dev/null
@@ -1,384 +0,0 @@
-/*
- * SCLP event types
- * Operations Command - Line Mode input
- * Message - Line Mode output
- *
- * Copyright IBM, Corp. 2013
- *
- * Authors:
- * Heinz Graalfs <graalfs@linux.vnet.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or (at your
- * option) any later version. See the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "hw/qdev.h"
-#include "qemu/thread.h"
-#include "qemu/error-report.h"
-#include "sysemu/char.h"
-
-#include "hw/s390x/sclp.h"
-#include "hw/s390x/event-facility.h"
-#include "hw/s390x/ebcdic.h"
-
-#define SIZE_BUFFER 4096
-#define NEWLINE "\n"
-
-typedef struct OprtnsCommand {
- EventBufferHeader header;
- MDMSU message_unit;
- char data[0];
-} QEMU_PACKED OprtnsCommand;
-
-/* max size for line-mode data in 4K SCCB page */
-#define SIZE_CONSOLE_BUFFER (SCCB_DATA_LEN - sizeof(OprtnsCommand))
-
-typedef struct SCLPConsoleLM {
- SCLPEvent event;
- CharDriverState *chr;
- bool echo; /* immediate echo of input if true */
- uint32_t write_errors; /* errors writing to char layer */
- uint32_t length; /* length of byte stream in buffer */
- uint8_t buf[SIZE_CONSOLE_BUFFER];
-} SCLPConsoleLM;
-
-/*
-* Character layer call-back functions
- *
- * Allow 1 character at a time
- *
- * Accumulate bytes from character layer in console buffer,
- * event_pending is set when a newline character is encountered
- *
- * The maximum command line length is limited by the maximum
- * space available in an SCCB. Line mode console input is sent
- * truncated to the guest in case it doesn't fit into the SCCB.
- */
-
-static int chr_can_read(void *opaque)
-{
- SCLPConsoleLM *scon = opaque;
-
- if (scon->event.event_pending) {
- return 0;
- }
- return 1;
-}
-
-static void chr_read(void *opaque, const uint8_t *buf, int size)
-{
- SCLPConsoleLM *scon = opaque;
-
- assert(size == 1);
-
- if (*buf == '\r' || *buf == '\n') {
- scon->event.event_pending = true;
- sclp_service_interrupt(0);
- return;
- }
- if (scon->length == SIZE_CONSOLE_BUFFER) {
- /* Eat the character, but still process CR and LF. */
- return;
- }
- scon->buf[scon->length] = *buf;
- scon->length += 1;
- if (scon->echo) {
- qemu_chr_fe_write(scon->chr, buf, size);
- }
-}
-
-/* functions to be called by event facility */
-
-static bool can_handle_event(uint8_t type)
-{
- return type == SCLP_EVENT_MESSAGE || type == SCLP_EVENT_PMSGCMD;
-}
-
-static unsigned int send_mask(void)
-{
- return SCLP_EVENT_MASK_OP_CMD | SCLP_EVENT_MASK_PMSGCMD;
-}
-
-static unsigned int receive_mask(void)
-{
- return SCLP_EVENT_MASK_MSG | SCLP_EVENT_MASK_PMSGCMD;
-}
-
-/*
- * Triggered by SCLP's read_event_data
- * - convert ASCII byte stream to EBCDIC and
- * - copy converted data into provided (SCLP) buffer
- */
-static int get_console_data(SCLPEvent *event, uint8_t *buf, size_t *size,
- int avail)
-{
- int len;
-
- SCLPConsoleLM *cons = DO_UPCAST(SCLPConsoleLM, event, event);
-
- len = cons->length;
- /* data need to fit into provided SCLP buffer */
- if (len > avail) {
- return 1;
- }
-
- ebcdic_put(buf, (char *)&cons->buf, len);
- *size = len;
- cons->length = 0;
- /* data provided and no more data pending */
- event->event_pending = false;
- qemu_notify_event();
- return 0;
-}
-
-static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
- int *slen)
-{
- int avail, rc;
- size_t src_len;
- uint8_t *to;
- OprtnsCommand *oc = (OprtnsCommand *) evt_buf_hdr;
-
- if (!event->event_pending) {
- /* no data pending */
- return 0;
- }
-
- to = (uint8_t *)&oc->data;
- avail = *slen - sizeof(OprtnsCommand);
- rc = get_console_data(event, to, &src_len, avail);
- if (rc) {
- /* data didn't fit, try next SCCB */
- return 1;
- }
-
- oc->message_unit.mdmsu.gds_id = GDS_ID_MDSMU;
- oc->message_unit.mdmsu.length = cpu_to_be16(sizeof(struct MDMSU));
-
- oc->message_unit.cpmsu.gds_id = GDS_ID_CPMSU;
- oc->message_unit.cpmsu.length =
- cpu_to_be16(sizeof(struct MDMSU) - sizeof(GdsVector));
-
- oc->message_unit.text_command.gds_id = GDS_ID_TEXTCMD;
- oc->message_unit.text_command.length =
- cpu_to_be16(sizeof(struct MDMSU) - (2 * sizeof(GdsVector)));
-
- oc->message_unit.self_def_text_message.key = GDS_KEY_SELFDEFTEXTMSG;
- oc->message_unit.self_def_text_message.length =
- cpu_to_be16(sizeof(struct MDMSU) - (3 * sizeof(GdsVector)));
-
- oc->message_unit.text_message.key = GDS_KEY_TEXTMSG;
- oc->message_unit.text_message.length =
- cpu_to_be16(sizeof(GdsSubvector) + src_len);
-
- oc->header.length = cpu_to_be16(sizeof(OprtnsCommand) + src_len);
- oc->header.type = SCLP_EVENT_OPRTNS_COMMAND;
- *slen = avail - src_len;
-
- return 1;
-}
-
-/*
- * Triggered by SCLP's write_event_data
- * - write console data to character layer
- * returns < 0 if an error occurred
- */
-static int write_console_data(SCLPEvent *event, const uint8_t *buf, int len)
-{
- int ret = 0;
- const uint8_t *buf_offset;
-
- SCLPConsoleLM *scon = DO_UPCAST(SCLPConsoleLM, event, event);
-
- if (!scon->chr) {
- /* If there's no backend, we can just say we consumed all data. */
- return len;
- }
-
- buf_offset = buf;
- while (len > 0) {
- ret = qemu_chr_fe_write(scon->chr, buf, len);
- if (ret == 0) {
- /* a pty doesn't seem to be connected - no error */
- len = 0;
- } else if (ret == -EAGAIN || (ret > 0 && ret < len)) {
- len -= ret;
- buf_offset += ret;
- } else {
- len = 0;
- }
- }
-
- return ret;
-}
-
-static int process_mdb(SCLPEvent *event, MDBO *mdbo)
-{
- int rc;
- int len;
- uint8_t buffer[SIZE_BUFFER];
-
- len = be16_to_cpu(mdbo->length);
- len -= sizeof(mdbo->length) + sizeof(mdbo->type)
- + sizeof(mdbo->mto.line_type_flags)
- + sizeof(mdbo->mto.alarm_control)
- + sizeof(mdbo->mto._reserved);
-
- assert(len <= SIZE_BUFFER);
-
- /* convert EBCDIC SCLP contents to ASCII console message */
- ascii_put(buffer, mdbo->mto.message, len);
- rc = write_console_data(event, (uint8_t *)NEWLINE, 1);
- if (rc < 0) {
- return rc;
- }
- return write_console_data(event, buffer, len);
-}
-
-static int write_event_data(SCLPEvent *event, EventBufferHeader *ebh)
-{
- int len;
- int written;
- int errors = 0;
- MDBO *mdbo;
- SclpMsg *data = (SclpMsg *) ebh;
- SCLPConsoleLM *scon = DO_UPCAST(SCLPConsoleLM, event, event);
-
- len = be16_to_cpu(data->mdb.header.length);
- if (len < sizeof(data->mdb.header)) {
- return SCLP_RC_INCONSISTENT_LENGTHS;
- }
- len -= sizeof(data->mdb.header);
-
- /* first check message buffers */
- mdbo = data->mdb.mdbo;
- while (len > 0) {
- if (be16_to_cpu(mdbo->length) > len
- || be16_to_cpu(mdbo->length) == 0) {
- return SCLP_RC_INCONSISTENT_LENGTHS;
- }
- len -= be16_to_cpu(mdbo->length);
- mdbo = (void *) mdbo + be16_to_cpu(mdbo->length);
- }
-
- /* then execute */
- len = be16_to_cpu(data->mdb.header.length) - sizeof(data->mdb.header);
- mdbo = data->mdb.mdbo;
- while (len > 0) {
- switch (be16_to_cpu(mdbo->type)) {
- case MESSAGE_TEXT:
- /* message text object */
- written = process_mdb(event, mdbo);
- if (written < 0) {
- /* character layer error */
- errors++;
- }
- break;
- default: /* ignore */
- break;
- }
- len -= be16_to_cpu(mdbo->length);
- mdbo = (void *) mdbo + be16_to_cpu(mdbo->length);
- }
- if (errors) {
- scon->write_errors += errors;
- }
- data->header.flags = SCLP_EVENT_BUFFER_ACCEPTED;
-
- return SCLP_RC_NORMAL_COMPLETION;
-}
-
-/* functions for live migration */
-
-static const VMStateDescription vmstate_sclplmconsole = {
- .name = "sclplmconsole",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_BOOL(event.event_pending, SCLPConsoleLM),
- VMSTATE_UINT32(write_errors, SCLPConsoleLM),
- VMSTATE_UINT32(length, SCLPConsoleLM),
- VMSTATE_UINT8_ARRAY(buf, SCLPConsoleLM, SIZE_CONSOLE_BUFFER),
- VMSTATE_END_OF_LIST()
- }
-};
-
-/* qemu object creation and initialization functions */
-
-/* tell character layer our call-back functions */
-
-static int console_init(SCLPEvent *event)
-{
- static bool console_available;
-
- SCLPConsoleLM *scon = DO_UPCAST(SCLPConsoleLM, event, event);
-
- if (console_available) {
- error_report("Multiple line-mode operator consoles are not supported");
- return -1;
- }
- console_available = true;
-
- if (scon->chr) {
- qemu_chr_add_handlers(scon->chr, chr_can_read, chr_read, NULL, scon);
- }
-
- return 0;
-}
-
-static int console_exit(SCLPEvent *event)
-{
- return 0;
-}
-
-static void console_reset(DeviceState *dev)
-{
- SCLPEvent *event = SCLP_EVENT(dev);
- SCLPConsoleLM *scon = DO_UPCAST(SCLPConsoleLM, event, event);
-
- event->event_pending = false;
- scon->length = 0;
- scon->write_errors = 0;
-}
-
-static Property console_properties[] = {
- DEFINE_PROP_CHR("chardev", SCLPConsoleLM, chr),
- DEFINE_PROP_UINT32("write_errors", SCLPConsoleLM, write_errors, 0),
- DEFINE_PROP_BOOL("echo", SCLPConsoleLM, echo, true),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void console_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SCLPEventClass *ec = SCLP_EVENT_CLASS(klass);
-
- dc->props = console_properties;
- dc->reset = console_reset;
- dc->vmsd = &vmstate_sclplmconsole;
- ec->init = console_init;
- ec->exit = console_exit;
- ec->get_send_mask = send_mask;
- ec->get_receive_mask = receive_mask;
- ec->can_handle_event = can_handle_event;
- ec->read_event_data = read_event_data;
- ec->write_event_data = write_event_data;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
-}
-
-static const TypeInfo sclp_console_info = {
- .name = "sclplmconsole",
- .parent = TYPE_SCLP_EVENT,
- .instance_size = sizeof(SCLPConsoleLM),
- .class_init = console_class_init,
- .class_size = sizeof(SCLPEventClass),
-};
-
-static void register_types(void)
-{
- type_register_static(&sclp_console_info);
-}
-
-type_init(register_types)
diff --git a/qemu/hw/char/sclpconsole.c b/qemu/hw/char/sclpconsole.c
deleted file mode 100644
index 45997ff4a..000000000
--- a/qemu/hw/char/sclpconsole.c
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- * SCLP event type
- * Ascii Console Data (VT220 Console)
- *
- * Copyright IBM, Corp. 2012
- *
- * Authors:
- * Heinz Graalfs <graalfs@de.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or (at your
- * option) any later version. See the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include <hw/qdev.h>
-#include "qemu/thread.h"
-#include "qemu/error-report.h"
-
-#include "hw/s390x/sclp.h"
-#include "hw/s390x/event-facility.h"
-#include "sysemu/char.h"
-
-typedef struct ASCIIConsoleData {
- EventBufferHeader ebh;
- char data[0];
-} QEMU_PACKED ASCIIConsoleData;
-
-/* max size for ASCII data in 4K SCCB page */
-#define SIZE_BUFFER_VT220 4080
-
-typedef struct SCLPConsole {
- SCLPEvent event;
- CharDriverState *chr;
- uint8_t iov[SIZE_BUFFER_VT220];
- uint32_t iov_sclp; /* offset in buf for SCLP read operation */
- uint32_t iov_bs; /* offset in buf for char layer read operation */
- uint32_t iov_data_len; /* length of byte stream in buffer */
- uint32_t iov_sclp_rest; /* length of byte stream not read via SCLP */
- bool notify; /* qemu_notify_event() req'd if true */
-} SCLPConsole;
-
-/* character layer call-back functions */
-
-/* Return number of bytes that fit into iov buffer */
-static int chr_can_read(void *opaque)
-{
- SCLPConsole *scon = opaque;
- int avail = SIZE_BUFFER_VT220 - scon->iov_data_len;
-
- if (avail == 0) {
- scon->notify = true;
- }
- return avail;
-}
-
-/* Send data from a char device over to the guest */
-static void chr_read(void *opaque, const uint8_t *buf, int size)
-{
- SCLPConsole *scon = opaque;
-
- assert(scon);
- /* read data must fit into current buffer */
- assert(size <= SIZE_BUFFER_VT220 - scon->iov_data_len);
-
- /* put byte-stream from character layer into buffer */
- memcpy(&scon->iov[scon->iov_bs], buf, size);
- scon->iov_data_len += size;
- scon->iov_sclp_rest += size;
- scon->iov_bs += size;
- scon->event.event_pending = true;
- sclp_service_interrupt(0);
-}
-
-/* functions to be called by event facility */
-
-static bool can_handle_event(uint8_t type)
-{
- return type == SCLP_EVENT_ASCII_CONSOLE_DATA;
-}
-
-static unsigned int send_mask(void)
-{
- return SCLP_EVENT_MASK_MSG_ASCII;
-}
-
-static unsigned int receive_mask(void)
-{
- return SCLP_EVENT_MASK_MSG_ASCII;
-}
-
-/* triggered by SCLP's read_event_data -
- * copy console data byte-stream into provided (SCLP) buffer
- */
-static void get_console_data(SCLPEvent *event, uint8_t *buf, size_t *size,
- int avail)
-{
- SCLPConsole *cons = DO_UPCAST(SCLPConsole, event, event);
-
- /* first byte is hex 0 saying an ascii string follows */
- *buf++ = '\0';
- avail--;
- /* if all data fit into provided SCLP buffer */
- if (avail >= cons->iov_sclp_rest) {
- /* copy character byte-stream to SCLP buffer */
- memcpy(buf, &cons->iov[cons->iov_sclp], cons->iov_sclp_rest);
- *size = cons->iov_sclp_rest + 1;
- cons->iov_sclp = 0;
- cons->iov_bs = 0;
- cons->iov_data_len = 0;
- cons->iov_sclp_rest = 0;
- event->event_pending = false;
- /* data provided and no more data pending */
- } else {
- /* if provided buffer is too small, just copy part */
- memcpy(buf, &cons->iov[cons->iov_sclp], avail);
- *size = avail + 1;
- cons->iov_sclp_rest -= avail;
- cons->iov_sclp += avail;
- /* more data pending */
- }
- if (cons->notify) {
- cons->notify = false;
- qemu_notify_event();
- }
-}
-
-static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
- int *slen)
-{
- int avail;
- size_t src_len;
- uint8_t *to;
- ASCIIConsoleData *acd = (ASCIIConsoleData *) evt_buf_hdr;
-
- if (!event->event_pending) {
- /* no data pending */
- return 0;
- }
-
- to = (uint8_t *)&acd->data;
- avail = *slen - sizeof(ASCIIConsoleData);
- get_console_data(event, to, &src_len, avail);
-
- acd->ebh.length = cpu_to_be16(sizeof(ASCIIConsoleData) + src_len);
- acd->ebh.type = SCLP_EVENT_ASCII_CONSOLE_DATA;
- acd->ebh.flags |= SCLP_EVENT_BUFFER_ACCEPTED;
- *slen = avail - src_len;
-
- return 1;
-}
-
-/* triggered by SCLP's write_event_data
- * - write console data to character layer
- * returns < 0 if an error occurred
- */
-static ssize_t write_console_data(SCLPEvent *event, const uint8_t *buf,
- size_t len)
-{
- SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
-
- if (!scon->chr) {
- /* If there's no backend, we can just say we consumed all data. */
- return len;
- }
-
- return qemu_chr_fe_write_all(scon->chr, buf, len);
-}
-
-static int write_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr)
-{
- int rc;
- int length;
- ssize_t written;
- ASCIIConsoleData *acd = (ASCIIConsoleData *) evt_buf_hdr;
-
- length = be16_to_cpu(evt_buf_hdr->length) - sizeof(EventBufferHeader);
- written = write_console_data(event, (uint8_t *)acd->data, length);
-
- rc = SCLP_RC_NORMAL_COMPLETION;
- /* set event buffer accepted flag */
- evt_buf_hdr->flags |= SCLP_EVENT_BUFFER_ACCEPTED;
-
- /* written will be zero if a pty is not connected - don't treat as error */
- if (written < 0) {
- /* event buffer not accepted due to error in character layer */
- evt_buf_hdr->flags &= ~(SCLP_EVENT_BUFFER_ACCEPTED);
- rc = SCLP_RC_CONTAINED_EQUIPMENT_CHECK;
- }
-
- return rc;
-}
-
-static const VMStateDescription vmstate_sclpconsole = {
- .name = "sclpconsole",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_BOOL(event.event_pending, SCLPConsole),
- VMSTATE_UINT8_ARRAY(iov, SCLPConsole, SIZE_BUFFER_VT220),
- VMSTATE_UINT32(iov_sclp, SCLPConsole),
- VMSTATE_UINT32(iov_bs, SCLPConsole),
- VMSTATE_UINT32(iov_data_len, SCLPConsole),
- VMSTATE_UINT32(iov_sclp_rest, SCLPConsole),
- VMSTATE_END_OF_LIST()
- }
-};
-
-/* qemu object creation and initialization functions */
-
-/* tell character layer our call-back functions */
-
-static int console_init(SCLPEvent *event)
-{
- static bool console_available;
-
- SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
-
- if (console_available) {
- error_report("Multiple VT220 operator consoles are not supported");
- return -1;
- }
- console_available = true;
- if (scon->chr) {
- qemu_chr_add_handlers(scon->chr, chr_can_read,
- chr_read, NULL, scon);
- }
-
- return 0;
-}
-
-static void console_reset(DeviceState *dev)
-{
- SCLPEvent *event = SCLP_EVENT(dev);
- SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
-
- event->event_pending = false;
- scon->iov_sclp = 0;
- scon->iov_bs = 0;
- scon->iov_data_len = 0;
- scon->iov_sclp_rest = 0;
- scon->notify = false;
-}
-
-static int console_exit(SCLPEvent *event)
-{
- return 0;
-}
-
-static Property console_properties[] = {
- DEFINE_PROP_CHR("chardev", SCLPConsole, chr),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void console_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SCLPEventClass *ec = SCLP_EVENT_CLASS(klass);
-
- dc->props = console_properties;
- dc->reset = console_reset;
- dc->vmsd = &vmstate_sclpconsole;
- ec->init = console_init;
- ec->exit = console_exit;
- ec->get_send_mask = send_mask;
- ec->get_receive_mask = receive_mask;
- ec->can_handle_event = can_handle_event;
- ec->read_event_data = read_event_data;
- ec->write_event_data = write_event_data;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
-}
-
-static const TypeInfo sclp_console_info = {
- .name = "sclpconsole",
- .parent = TYPE_SCLP_EVENT,
- .instance_size = sizeof(SCLPConsole),
- .class_init = console_class_init,
- .class_size = sizeof(SCLPEventClass),
-};
-
-static void register_types(void)
-{
- type_register_static(&sclp_console_info);
-}
-
-type_init(register_types)
diff --git a/qemu/hw/char/serial-isa.c b/qemu/hw/char/serial-isa.c
deleted file mode 100644
index 1594ec4db..000000000
--- a/qemu/hw/char/serial-isa.c
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * QEMU 16550A UART emulation
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- * Copyright (c) 2008 Citrix Systems, Inc.
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/char/serial.h"
-#include "hw/isa/isa.h"
-
-#define ISA_SERIAL(obj) OBJECT_CHECK(ISASerialState, (obj), TYPE_ISA_SERIAL)
-
-typedef struct ISASerialState {
- ISADevice parent_obj;
-
- uint32_t index;
- uint32_t iobase;
- uint32_t isairq;
- SerialState state;
-} ISASerialState;
-
-static const int isa_serial_io[MAX_SERIAL_PORTS] = {
- 0x3f8, 0x2f8, 0x3e8, 0x2e8
-};
-static const int isa_serial_irq[MAX_SERIAL_PORTS] = {
- 4, 3, 4, 3
-};
-
-static void serial_isa_realizefn(DeviceState *dev, Error **errp)
-{
- static int index;
- ISADevice *isadev = ISA_DEVICE(dev);
- ISASerialState *isa = ISA_SERIAL(dev);
- SerialState *s = &isa->state;
-
- if (isa->index == -1) {
- isa->index = index;
- }
- if (isa->index >= MAX_SERIAL_PORTS) {
- error_setg(errp, "Max. supported number of ISA serial ports is %d.",
- MAX_SERIAL_PORTS);
- return;
- }
- if (isa->iobase == -1) {
- isa->iobase = isa_serial_io[isa->index];
- }
- if (isa->isairq == -1) {
- isa->isairq = isa_serial_irq[isa->index];
- }
- index++;
-
- s->baudbase = 115200;
- isa_init_irq(isadev, &s->irq, isa->isairq);
- serial_realize_core(s, errp);
- qdev_set_legacy_instance_id(dev, isa->iobase, 3);
-
- memory_region_init_io(&s->io, OBJECT(isa), &serial_io_ops, s, "serial", 8);
- isa_register_ioport(isadev, &s->io, isa->iobase);
-}
-
-static const VMStateDescription vmstate_isa_serial = {
- .name = "serial",
- .version_id = 3,
- .minimum_version_id = 2,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT(state, ISASerialState, 0, vmstate_serial, SerialState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property serial_isa_properties[] = {
- DEFINE_PROP_UINT32("index", ISASerialState, index, -1),
- DEFINE_PROP_UINT32("iobase", ISASerialState, iobase, -1),
- DEFINE_PROP_UINT32("irq", ISASerialState, isairq, -1),
- DEFINE_PROP_CHR("chardev", ISASerialState, state.chr),
- DEFINE_PROP_UINT32("wakeup", ISASerialState, state.wakeup, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void serial_isa_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = serial_isa_realizefn;
- dc->vmsd = &vmstate_isa_serial;
- dc->props = serial_isa_properties;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
-}
-
-static const TypeInfo serial_isa_info = {
- .name = TYPE_ISA_SERIAL,
- .parent = TYPE_ISA_DEVICE,
- .instance_size = sizeof(ISASerialState),
- .class_init = serial_isa_class_initfn,
-};
-
-static void serial_register_types(void)
-{
- type_register_static(&serial_isa_info);
-}
-
-type_init(serial_register_types)
-
-static void serial_isa_init(ISABus *bus, int index, CharDriverState *chr)
-{
- DeviceState *dev;
- ISADevice *isadev;
-
- isadev = isa_create(bus, TYPE_ISA_SERIAL);
- dev = DEVICE(isadev);
- qdev_prop_set_uint32(dev, "index", index);
- qdev_prop_set_chr(dev, "chardev", chr);
- qdev_init_nofail(dev);
-}
-
-void serial_hds_isa_init(ISABus *bus, int n)
-{
- int i;
-
- assert(n <= MAX_SERIAL_PORTS);
-
- for (i = 0; i < n; ++i) {
- if (serial_hds[i]) {
- serial_isa_init(bus, i, serial_hds[i]);
- }
- }
-}
diff --git a/qemu/hw/char/serial-pci.c b/qemu/hw/char/serial-pci.c
deleted file mode 100644
index 303104dd1..000000000
--- a/qemu/hw/char/serial-pci.c
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * QEMU 16550A UART emulation
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- * Copyright (c) 2008 Citrix Systems, Inc.
- *
- * 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.
- */
-
-/* see docs/specs/pci-serial.txt */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/char/serial.h"
-#include "hw/pci/pci.h"
-
-#define PCI_SERIAL_MAX_PORTS 4
-
-typedef struct PCISerialState {
- PCIDevice dev;
- SerialState state;
- uint8_t prog_if;
-} PCISerialState;
-
-typedef struct PCIMultiSerialState {
- PCIDevice dev;
- MemoryRegion iobar;
- uint32_t ports;
- char *name[PCI_SERIAL_MAX_PORTS];
- SerialState state[PCI_SERIAL_MAX_PORTS];
- uint32_t level[PCI_SERIAL_MAX_PORTS];
- qemu_irq *irqs;
- uint8_t prog_if;
-} PCIMultiSerialState;
-
-static void multi_serial_pci_exit(PCIDevice *dev);
-
-static void serial_pci_realize(PCIDevice *dev, Error **errp)
-{
- PCISerialState *pci = DO_UPCAST(PCISerialState, dev, dev);
- SerialState *s = &pci->state;
- Error *err = NULL;
-
- s->baudbase = 115200;
- serial_realize_core(s, &err);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
-
- pci->dev.config[PCI_CLASS_PROG] = pci->prog_if;
- pci->dev.config[PCI_INTERRUPT_PIN] = 0x01;
- s->irq = pci_allocate_irq(&pci->dev);
-
- memory_region_init_io(&s->io, OBJECT(pci), &serial_io_ops, s, "serial", 8);
- pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io);
-}
-
-static void multi_serial_irq_mux(void *opaque, int n, int level)
-{
- PCIMultiSerialState *pci = opaque;
- int i, pending = 0;
-
- pci->level[n] = level;
- for (i = 0; i < pci->ports; i++) {
- if (pci->level[i]) {
- pending = 1;
- }
- }
- pci_set_irq(&pci->dev, pending);
-}
-
-static void multi_serial_pci_realize(PCIDevice *dev, Error **errp)
-{
- PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
- PCIMultiSerialState *pci = DO_UPCAST(PCIMultiSerialState, dev, dev);
- SerialState *s;
- Error *err = NULL;
- int i, nr_ports = 0;
-
- switch (pc->device_id) {
- case 0x0003:
- nr_ports = 2;
- break;
- case 0x0004:
- nr_ports = 4;
- break;
- }
- assert(nr_ports > 0);
- assert(nr_ports <= PCI_SERIAL_MAX_PORTS);
-
- pci->dev.config[PCI_CLASS_PROG] = pci->prog_if;
- pci->dev.config[PCI_INTERRUPT_PIN] = 0x01;
- memory_region_init(&pci->iobar, OBJECT(pci), "multiserial", 8 * nr_ports);
- pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &pci->iobar);
- pci->irqs = qemu_allocate_irqs(multi_serial_irq_mux, pci,
- nr_ports);
-
- for (i = 0; i < nr_ports; i++) {
- s = pci->state + i;
- s->baudbase = 115200;
- serial_realize_core(s, &err);
- if (err != NULL) {
- error_propagate(errp, err);
- multi_serial_pci_exit(dev);
- return;
- }
- s->irq = pci->irqs[i];
- pci->name[i] = g_strdup_printf("uart #%d", i+1);
- memory_region_init_io(&s->io, OBJECT(pci), &serial_io_ops, s,
- pci->name[i], 8);
- memory_region_add_subregion(&pci->iobar, 8 * i, &s->io);
- pci->ports++;
- }
-}
-
-static void serial_pci_exit(PCIDevice *dev)
-{
- PCISerialState *pci = DO_UPCAST(PCISerialState, dev, dev);
- SerialState *s = &pci->state;
-
- serial_exit_core(s);
- qemu_free_irq(s->irq);
-}
-
-static void multi_serial_pci_exit(PCIDevice *dev)
-{
- PCIMultiSerialState *pci = DO_UPCAST(PCIMultiSerialState, dev, dev);
- SerialState *s;
- int i;
-
- for (i = 0; i < pci->ports; i++) {
- s = pci->state + i;
- serial_exit_core(s);
- memory_region_del_subregion(&pci->iobar, &s->io);
- g_free(pci->name[i]);
- }
- qemu_free_irqs(pci->irqs, pci->ports);
-}
-
-static const VMStateDescription vmstate_pci_serial = {
- .name = "pci-serial",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(dev, PCISerialState),
- VMSTATE_STRUCT(state, PCISerialState, 0, vmstate_serial, SerialState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_pci_multi_serial = {
- .name = "pci-serial-multi",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(dev, PCIMultiSerialState),
- VMSTATE_STRUCT_ARRAY(state, PCIMultiSerialState, PCI_SERIAL_MAX_PORTS,
- 0, vmstate_serial, SerialState),
- VMSTATE_UINT32_ARRAY(level, PCIMultiSerialState, PCI_SERIAL_MAX_PORTS),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property serial_pci_properties[] = {
- DEFINE_PROP_CHR("chardev", PCISerialState, state.chr),
- DEFINE_PROP_UINT8("prog_if", PCISerialState, prog_if, 0x02),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static Property multi_2x_serial_pci_properties[] = {
- DEFINE_PROP_CHR("chardev1", PCIMultiSerialState, state[0].chr),
- DEFINE_PROP_CHR("chardev2", PCIMultiSerialState, state[1].chr),
- DEFINE_PROP_UINT8("prog_if", PCIMultiSerialState, prog_if, 0x02),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static Property multi_4x_serial_pci_properties[] = {
- DEFINE_PROP_CHR("chardev1", PCIMultiSerialState, state[0].chr),
- DEFINE_PROP_CHR("chardev2", PCIMultiSerialState, state[1].chr),
- DEFINE_PROP_CHR("chardev3", PCIMultiSerialState, state[2].chr),
- DEFINE_PROP_CHR("chardev4", PCIMultiSerialState, state[3].chr),
- DEFINE_PROP_UINT8("prog_if", PCIMultiSerialState, prog_if, 0x02),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void serial_pci_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
- pc->realize = serial_pci_realize;
- pc->exit = serial_pci_exit;
- pc->vendor_id = PCI_VENDOR_ID_REDHAT;
- pc->device_id = PCI_DEVICE_ID_REDHAT_SERIAL;
- pc->revision = 1;
- pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL;
- dc->vmsd = &vmstate_pci_serial;
- dc->props = serial_pci_properties;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
-}
-
-static void multi_2x_serial_pci_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
- pc->realize = multi_serial_pci_realize;
- pc->exit = multi_serial_pci_exit;
- pc->vendor_id = PCI_VENDOR_ID_REDHAT;
- pc->device_id = PCI_DEVICE_ID_REDHAT_SERIAL2;
- pc->revision = 1;
- pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL;
- dc->vmsd = &vmstate_pci_multi_serial;
- dc->props = multi_2x_serial_pci_properties;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
-}
-
-static void multi_4x_serial_pci_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
- pc->realize = multi_serial_pci_realize;
- pc->exit = multi_serial_pci_exit;
- pc->vendor_id = PCI_VENDOR_ID_REDHAT;
- pc->device_id = PCI_DEVICE_ID_REDHAT_SERIAL4;
- pc->revision = 1;
- pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL;
- dc->vmsd = &vmstate_pci_multi_serial;
- dc->props = multi_4x_serial_pci_properties;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
-}
-
-static const TypeInfo serial_pci_info = {
- .name = "pci-serial",
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(PCISerialState),
- .class_init = serial_pci_class_initfn,
-};
-
-static const TypeInfo multi_2x_serial_pci_info = {
- .name = "pci-serial-2x",
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(PCIMultiSerialState),
- .class_init = multi_2x_serial_pci_class_initfn,
-};
-
-static const TypeInfo multi_4x_serial_pci_info = {
- .name = "pci-serial-4x",
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(PCIMultiSerialState),
- .class_init = multi_4x_serial_pci_class_initfn,
-};
-
-static void serial_pci_register_types(void)
-{
- type_register_static(&serial_pci_info);
- type_register_static(&multi_2x_serial_pci_info);
- type_register_static(&multi_4x_serial_pci_info);
-}
-
-type_init(serial_pci_register_types)
diff --git a/qemu/hw/char/serial.c b/qemu/hw/char/serial.c
deleted file mode 100644
index 6d815b5c6..000000000
--- a/qemu/hw/char/serial.c
+++ /dev/null
@@ -1,966 +0,0 @@
-/*
- * QEMU 16550A UART emulation
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- * Copyright (c) 2008 Citrix Systems, Inc.
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/char/serial.h"
-#include "sysemu/char.h"
-#include "qapi/error.h"
-#include "qemu/timer.h"
-#include "exec/address-spaces.h"
-#include "qemu/error-report.h"
-
-//#define DEBUG_SERIAL
-
-#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */
-
-#define UART_IER_MSI 0x08 /* Enable Modem status interrupt */
-#define UART_IER_RLSI 0x04 /* Enable receiver line status interrupt */
-#define UART_IER_THRI 0x02 /* Enable Transmitter holding register int. */
-#define UART_IER_RDI 0x01 /* Enable receiver data interrupt */
-
-#define UART_IIR_NO_INT 0x01 /* No interrupts pending */
-#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */
-
-#define UART_IIR_MSI 0x00 /* Modem status interrupt */
-#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */
-#define UART_IIR_RDI 0x04 /* Receiver data interrupt */
-#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */
-#define UART_IIR_CTI 0x0C /* Character Timeout Indication */
-
-#define UART_IIR_FENF 0x80 /* Fifo enabled, but not functionning */
-#define UART_IIR_FE 0xC0 /* Fifo enabled */
-
-/*
- * These are the definitions for the Modem Control Register
- */
-#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */
-#define UART_MCR_OUT2 0x08 /* Out2 complement */
-#define UART_MCR_OUT1 0x04 /* Out1 complement */
-#define UART_MCR_RTS 0x02 /* RTS complement */
-#define UART_MCR_DTR 0x01 /* DTR complement */
-
-/*
- * These are the definitions for the Modem Status Register
- */
-#define UART_MSR_DCD 0x80 /* Data Carrier Detect */
-#define UART_MSR_RI 0x40 /* Ring Indicator */
-#define UART_MSR_DSR 0x20 /* Data Set Ready */
-#define UART_MSR_CTS 0x10 /* Clear to Send */
-#define UART_MSR_DDCD 0x08 /* Delta DCD */
-#define UART_MSR_TERI 0x04 /* Trailing edge ring indicator */
-#define UART_MSR_DDSR 0x02 /* Delta DSR */
-#define UART_MSR_DCTS 0x01 /* Delta CTS */
-#define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */
-
-#define UART_LSR_TEMT 0x40 /* Transmitter empty */
-#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
-#define UART_LSR_BI 0x10 /* Break interrupt indicator */
-#define UART_LSR_FE 0x08 /* Frame error indicator */
-#define UART_LSR_PE 0x04 /* Parity error indicator */
-#define UART_LSR_OE 0x02 /* Overrun error indicator */
-#define UART_LSR_DR 0x01 /* Receiver data ready */
-#define UART_LSR_INT_ANY 0x1E /* Any of the lsr-interrupt-triggering status bits */
-
-/* Interrupt trigger levels. The byte-counts are for 16550A - in newer UARTs the byte-count for each ITL is higher. */
-
-#define UART_FCR_ITL_1 0x00 /* 1 byte ITL */
-#define UART_FCR_ITL_2 0x40 /* 4 bytes ITL */
-#define UART_FCR_ITL_3 0x80 /* 8 bytes ITL */
-#define UART_FCR_ITL_4 0xC0 /* 14 bytes ITL */
-
-#define UART_FCR_DMS 0x08 /* DMA Mode Select */
-#define UART_FCR_XFR 0x04 /* XMIT Fifo Reset */
-#define UART_FCR_RFR 0x02 /* RCVR Fifo Reset */
-#define UART_FCR_FE 0x01 /* FIFO Enable */
-
-#define MAX_XMIT_RETRY 4
-
-#ifdef DEBUG_SERIAL
-#define DPRINTF(fmt, ...) \
-do { fprintf(stderr, "serial: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) \
-do {} while (0)
-#endif
-
-static void serial_receive1(void *opaque, const uint8_t *buf, int size);
-
-static inline void recv_fifo_put(SerialState *s, uint8_t chr)
-{
- /* Receive overruns do not overwrite FIFO contents. */
- if (!fifo8_is_full(&s->recv_fifo)) {
- fifo8_push(&s->recv_fifo, chr);
- } else {
- s->lsr |= UART_LSR_OE;
- }
-}
-
-static void serial_update_irq(SerialState *s)
-{
- uint8_t tmp_iir = UART_IIR_NO_INT;
-
- if ((s->ier & UART_IER_RLSI) && (s->lsr & UART_LSR_INT_ANY)) {
- tmp_iir = UART_IIR_RLSI;
- } else if ((s->ier & UART_IER_RDI) && s->timeout_ipending) {
- /* Note that(s->ier & UART_IER_RDI) can mask this interrupt,
- * this is not in the specification but is observed on existing
- * hardware. */
- tmp_iir = UART_IIR_CTI;
- } else if ((s->ier & UART_IER_RDI) && (s->lsr & UART_LSR_DR) &&
- (!(s->fcr & UART_FCR_FE) ||
- s->recv_fifo.num >= s->recv_fifo_itl)) {
- tmp_iir = UART_IIR_RDI;
- } else if ((s->ier & UART_IER_THRI) && s->thr_ipending) {
- tmp_iir = UART_IIR_THRI;
- } else if ((s->ier & UART_IER_MSI) && (s->msr & UART_MSR_ANY_DELTA)) {
- tmp_iir = UART_IIR_MSI;
- }
-
- s->iir = tmp_iir | (s->iir & 0xF0);
-
- if (tmp_iir != UART_IIR_NO_INT) {
- qemu_irq_raise(s->irq);
- } else {
- qemu_irq_lower(s->irq);
- }
-}
-
-static void serial_update_parameters(SerialState *s)
-{
- int speed, parity, data_bits, stop_bits, frame_size;
- QEMUSerialSetParams ssp;
-
- if (s->divider == 0)
- return;
-
- /* Start bit. */
- frame_size = 1;
- if (s->lcr & 0x08) {
- /* Parity bit. */
- frame_size++;
- if (s->lcr & 0x10)
- parity = 'E';
- else
- parity = 'O';
- } else {
- parity = 'N';
- }
- if (s->lcr & 0x04)
- stop_bits = 2;
- else
- stop_bits = 1;
-
- data_bits = (s->lcr & 0x03) + 5;
- frame_size += data_bits + stop_bits;
- speed = s->baudbase / s->divider;
- ssp.speed = speed;
- ssp.parity = parity;
- ssp.data_bits = data_bits;
- ssp.stop_bits = stop_bits;
- s->char_transmit_time = (NANOSECONDS_PER_SECOND / speed) * frame_size;
- qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
-
- DPRINTF("speed=%d parity=%c data=%d stop=%d\n",
- speed, parity, data_bits, stop_bits);
-}
-
-static void serial_update_msl(SerialState *s)
-{
- uint8_t omsr;
- int flags;
-
- timer_del(s->modem_status_poll);
-
- if (qemu_chr_fe_ioctl(s->chr,CHR_IOCTL_SERIAL_GET_TIOCM, &flags) == -ENOTSUP) {
- s->poll_msl = -1;
- return;
- }
-
- omsr = s->msr;
-
- s->msr = (flags & CHR_TIOCM_CTS) ? s->msr | UART_MSR_CTS : s->msr & ~UART_MSR_CTS;
- s->msr = (flags & CHR_TIOCM_DSR) ? s->msr | UART_MSR_DSR : s->msr & ~UART_MSR_DSR;
- s->msr = (flags & CHR_TIOCM_CAR) ? s->msr | UART_MSR_DCD : s->msr & ~UART_MSR_DCD;
- s->msr = (flags & CHR_TIOCM_RI) ? s->msr | UART_MSR_RI : s->msr & ~UART_MSR_RI;
-
- if (s->msr != omsr) {
- /* Set delta bits */
- s->msr = s->msr | ((s->msr >> 4) ^ (omsr >> 4));
- /* UART_MSR_TERI only if change was from 1 -> 0 */
- if ((s->msr & UART_MSR_TERI) && !(omsr & UART_MSR_RI))
- s->msr &= ~UART_MSR_TERI;
- serial_update_irq(s);
- }
-
- /* The real 16550A apparently has a 250ns response latency to line status changes.
- We'll be lazy and poll only every 10ms, and only poll it at all if MSI interrupts are turned on */
-
- if (s->poll_msl) {
- timer_mod(s->modem_status_poll, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- NANOSECONDS_PER_SECOND / 100);
- }
-}
-
-static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque)
-{
- SerialState *s = opaque;
-
- do {
- assert(!(s->lsr & UART_LSR_TEMT));
- if (s->tsr_retry <= 0) {
- assert(!(s->lsr & UART_LSR_THRE));
-
- if (s->fcr & UART_FCR_FE) {
- assert(!fifo8_is_empty(&s->xmit_fifo));
- s->tsr = fifo8_pop(&s->xmit_fifo);
- if (!s->xmit_fifo.num) {
- s->lsr |= UART_LSR_THRE;
- }
- } else {
- s->tsr = s->thr;
- s->lsr |= UART_LSR_THRE;
- }
- if ((s->lsr & UART_LSR_THRE) && !s->thr_ipending) {
- s->thr_ipending = 1;
- serial_update_irq(s);
- }
- }
-
- if (s->mcr & UART_MCR_LOOP) {
- /* 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 &&
- qemu_chr_fe_add_watch(s->chr, G_IO_OUT|G_IO_HUP,
- serial_xmit, s) > 0) {
- s->tsr_retry++;
- return FALSE;
- }
- s->tsr_retry = 0;
- } else {
- s->tsr_retry = 0;
- }
-
- /* Transmit another byte if it is already available. It is only
- possible when FIFO is enabled and not empty. */
- } while (!(s->lsr & UART_LSR_THRE));
-
- s->last_xmit_ts = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- s->lsr |= UART_LSR_TEMT;
-
- return FALSE;
-}
-
-
-/* Setter for FCR.
- is_load flag means, that value is set while loading VM state
- and interrupt should not be invoked */
-static void serial_write_fcr(SerialState *s, uint8_t val)
-{
- /* Set fcr - val only has the bits that are supposed to "stick" */
- s->fcr = val;
-
- if (val & UART_FCR_FE) {
- s->iir |= UART_IIR_FE;
- /* Set recv_fifo trigger Level */
- switch (val & 0xC0) {
- case UART_FCR_ITL_1:
- s->recv_fifo_itl = 1;
- break;
- case UART_FCR_ITL_2:
- s->recv_fifo_itl = 4;
- break;
- case UART_FCR_ITL_3:
- s->recv_fifo_itl = 8;
- break;
- case UART_FCR_ITL_4:
- s->recv_fifo_itl = 14;
- break;
- }
- } else {
- s->iir &= ~UART_IIR_FE;
- }
-}
-
-static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned size)
-{
- SerialState *s = opaque;
-
- addr &= 7;
- DPRINTF("write addr=0x%" HWADDR_PRIx " val=0x%" PRIx64 "\n", addr, val);
- switch(addr) {
- default:
- case 0:
- if (s->lcr & UART_LCR_DLAB) {
- s->divider = (s->divider & 0xff00) | val;
- serial_update_parameters(s);
- } else {
- s->thr = (uint8_t) val;
- if(s->fcr & UART_FCR_FE) {
- /* xmit overruns overwrite data, so make space if needed */
- if (fifo8_is_full(&s->xmit_fifo)) {
- fifo8_pop(&s->xmit_fifo);
- }
- fifo8_push(&s->xmit_fifo, s->thr);
- }
- s->thr_ipending = 0;
- s->lsr &= ~UART_LSR_THRE;
- s->lsr &= ~UART_LSR_TEMT;
- serial_update_irq(s);
- if (s->tsr_retry <= 0) {
- serial_xmit(NULL, G_IO_OUT, s);
- }
- }
- break;
- case 1:
- if (s->lcr & UART_LCR_DLAB) {
- s->divider = (s->divider & 0x00ff) | (val << 8);
- serial_update_parameters(s);
- } else {
- uint8_t changed = (s->ier ^ val) & 0x0f;
- s->ier = val & 0x0f;
- /* If the backend device is a real serial port, turn polling of the modem
- * status lines on physical port on or off depending on UART_IER_MSI state.
- */
- if ((changed & UART_IER_MSI) && s->poll_msl >= 0) {
- if (s->ier & UART_IER_MSI) {
- s->poll_msl = 1;
- serial_update_msl(s);
- } else {
- timer_del(s->modem_status_poll);
- s->poll_msl = 0;
- }
- }
-
- /* Turning on the THRE interrupt on IER can trigger the interrupt
- * if LSR.THRE=1, even if it had been masked before by reading IIR.
- * This is not in the datasheet, but Windows relies on it. It is
- * unclear if THRE has to be resampled every time THRI becomes
- * 1, or only on the rising edge. Bochs does the latter, and Windows
- * always toggles IER to all zeroes and back to all ones, so do the
- * same.
- *
- * If IER.THRI is zero, thr_ipending is not used. Set it to zero
- * so that the thr_ipending subsection is not migrated.
- */
- if (changed & UART_IER_THRI) {
- if ((s->ier & UART_IER_THRI) && (s->lsr & UART_LSR_THRE)) {
- s->thr_ipending = 1;
- } else {
- s->thr_ipending = 0;
- }
- }
-
- if (changed) {
- serial_update_irq(s);
- }
- }
- break;
- case 2:
- /* Did the enable/disable flag change? If so, make sure FIFOs get flushed */
- if ((val ^ s->fcr) & UART_FCR_FE) {
- val |= UART_FCR_XFR | UART_FCR_RFR;
- }
-
- /* FIFO clear */
-
- if (val & UART_FCR_RFR) {
- s->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
- timer_del(s->fifo_timeout_timer);
- s->timeout_ipending = 0;
- fifo8_reset(&s->recv_fifo);
- }
-
- if (val & UART_FCR_XFR) {
- s->lsr |= UART_LSR_THRE;
- s->thr_ipending = 1;
- fifo8_reset(&s->xmit_fifo);
- }
-
- serial_write_fcr(s, val & 0xC9);
- serial_update_irq(s);
- break;
- case 3:
- {
- int break_enable;
- s->lcr = val;
- serial_update_parameters(s);
- break_enable = (val >> 6) & 1;
- if (break_enable != s->last_break_enable) {
- s->last_break_enable = break_enable;
- qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_BREAK,
- &break_enable);
- }
- }
- break;
- case 4:
- {
- int flags;
- int old_mcr = s->mcr;
- s->mcr = val & 0x1f;
- if (val & UART_MCR_LOOP)
- break;
-
- if (s->poll_msl >= 0 && old_mcr != s->mcr) {
-
- qemu_chr_fe_ioctl(s->chr,CHR_IOCTL_SERIAL_GET_TIOCM, &flags);
-
- flags &= ~(CHR_TIOCM_RTS | CHR_TIOCM_DTR);
-
- if (val & UART_MCR_RTS)
- flags |= CHR_TIOCM_RTS;
- if (val & UART_MCR_DTR)
- flags |= CHR_TIOCM_DTR;
-
- qemu_chr_fe_ioctl(s->chr,CHR_IOCTL_SERIAL_SET_TIOCM, &flags);
- /* Update the modem status after a one-character-send wait-time, since there may be a response
- from the device/computer at the other end of the serial line */
- timer_mod(s->modem_status_poll, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->char_transmit_time);
- }
- }
- break;
- case 5:
- break;
- case 6:
- break;
- case 7:
- s->scr = val;
- break;
- }
-}
-
-static uint64_t serial_ioport_read(void *opaque, hwaddr addr, unsigned size)
-{
- SerialState *s = opaque;
- uint32_t ret;
-
- addr &= 7;
- switch(addr) {
- default:
- case 0:
- if (s->lcr & UART_LCR_DLAB) {
- ret = s->divider & 0xff;
- } else {
- if(s->fcr & UART_FCR_FE) {
- ret = fifo8_is_empty(&s->recv_fifo) ?
- 0 : fifo8_pop(&s->recv_fifo);
- if (s->recv_fifo.num == 0) {
- s->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
- } else {
- timer_mod(s->fifo_timeout_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->char_transmit_time * 4);
- }
- s->timeout_ipending = 0;
- } else {
- ret = s->rbr;
- s->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
- }
- serial_update_irq(s);
- if (!(s->mcr & UART_MCR_LOOP)) {
- /* in loopback mode, don't receive any data */
- qemu_chr_accept_input(s->chr);
- }
- }
- break;
- case 1:
- if (s->lcr & UART_LCR_DLAB) {
- ret = (s->divider >> 8) & 0xff;
- } else {
- ret = s->ier;
- }
- break;
- case 2:
- ret = s->iir;
- if ((ret & UART_IIR_ID) == UART_IIR_THRI) {
- s->thr_ipending = 0;
- serial_update_irq(s);
- }
- break;
- case 3:
- ret = s->lcr;
- break;
- case 4:
- ret = s->mcr;
- break;
- case 5:
- ret = s->lsr;
- /* Clear break and overrun interrupts */
- if (s->lsr & (UART_LSR_BI|UART_LSR_OE)) {
- s->lsr &= ~(UART_LSR_BI|UART_LSR_OE);
- serial_update_irq(s);
- }
- break;
- case 6:
- if (s->mcr & UART_MCR_LOOP) {
- /* in loopback, the modem output pins are connected to the
- inputs */
- ret = (s->mcr & 0x0c) << 4;
- ret |= (s->mcr & 0x02) << 3;
- ret |= (s->mcr & 0x01) << 5;
- } else {
- if (s->poll_msl >= 0)
- serial_update_msl(s);
- ret = s->msr;
- /* Clear delta bits & msr int after read, if they were set */
- if (s->msr & UART_MSR_ANY_DELTA) {
- s->msr &= 0xF0;
- serial_update_irq(s);
- }
- }
- break;
- case 7:
- ret = s->scr;
- break;
- }
- DPRINTF("read addr=0x%" HWADDR_PRIx " val=0x%02x\n", addr, ret);
- return ret;
-}
-
-static int serial_can_receive(SerialState *s)
-{
- if(s->fcr & UART_FCR_FE) {
- if (s->recv_fifo.num < UART_FIFO_LENGTH) {
- /*
- * Advertise (fifo.itl - fifo.count) bytes when count < ITL, and 1
- * if above. If UART_FIFO_LENGTH - fifo.count is advertised the
- * effect will be to almost always fill the fifo completely before
- * the guest has a chance to respond, effectively overriding the ITL
- * that the guest has set.
- */
- return (s->recv_fifo.num <= s->recv_fifo_itl) ?
- s->recv_fifo_itl - s->recv_fifo.num : 1;
- } else {
- return 0;
- }
- } else {
- return !(s->lsr & UART_LSR_DR);
- }
-}
-
-static void serial_receive_break(SerialState *s)
-{
- s->rbr = 0;
- /* When the LSR_DR is set a null byte is pushed into the fifo */
- recv_fifo_put(s, '\0');
- s->lsr |= UART_LSR_BI | UART_LSR_DR;
- serial_update_irq(s);
-}
-
-/* There's data in recv_fifo and s->rbr has not been read for 4 char transmit times */
-static void fifo_timeout_int (void *opaque) {
- SerialState *s = opaque;
- if (s->recv_fifo.num) {
- s->timeout_ipending = 1;
- serial_update_irq(s);
- }
-}
-
-static int serial_can_receive1(void *opaque)
-{
- SerialState *s = opaque;
- return serial_can_receive(s);
-}
-
-static void serial_receive1(void *opaque, const uint8_t *buf, int size)
-{
- SerialState *s = opaque;
-
- if (s->wakeup) {
- qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
- }
- if(s->fcr & UART_FCR_FE) {
- int i;
- for (i = 0; i < size; i++) {
- recv_fifo_put(s, buf[i]);
- }
- s->lsr |= UART_LSR_DR;
- /* call the timeout receive callback in 4 char transmit time */
- timer_mod(s->fifo_timeout_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->char_transmit_time * 4);
- } else {
- if (s->lsr & UART_LSR_DR)
- s->lsr |= UART_LSR_OE;
- s->rbr = buf[0];
- s->lsr |= UART_LSR_DR;
- }
- serial_update_irq(s);
-}
-
-static void serial_event(void *opaque, int event)
-{
- SerialState *s = opaque;
- DPRINTF("event %x\n", event);
- if (event == CHR_EVENT_BREAK)
- serial_receive_break(s);
-}
-
-static void serial_pre_save(void *opaque)
-{
- SerialState *s = opaque;
- s->fcr_vmstate = s->fcr;
-}
-
-static int serial_pre_load(void *opaque)
-{
- SerialState *s = opaque;
- s->thr_ipending = -1;
- s->poll_msl = -1;
- return 0;
-}
-
-static int serial_post_load(void *opaque, int version_id)
-{
- SerialState *s = opaque;
-
- if (version_id < 3) {
- s->fcr_vmstate = 0;
- }
- if (s->thr_ipending == -1) {
- s->thr_ipending = ((s->iir & UART_IIR_ID) == UART_IIR_THRI);
- }
- s->last_break_enable = (s->lcr >> 6) & 1;
- /* Initialize fcr via setter to perform essential side-effects */
- serial_write_fcr(s, s->fcr_vmstate);
- serial_update_parameters(s);
- return 0;
-}
-
-static bool serial_thr_ipending_needed(void *opaque)
-{
- SerialState *s = opaque;
-
- if (s->ier & UART_IER_THRI) {
- bool expected_value = ((s->iir & UART_IIR_ID) == UART_IIR_THRI);
- return s->thr_ipending != expected_value;
- } else {
- /* LSR.THRE will be sampled again when the interrupt is
- * enabled. thr_ipending is not used in this case, do
- * not migrate it.
- */
- return false;
- }
-}
-
-static const VMStateDescription vmstate_serial_thr_ipending = {
- .name = "serial/thr_ipending",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = serial_thr_ipending_needed,
- .fields = (VMStateField[]) {
- VMSTATE_INT32(thr_ipending, SerialState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static bool serial_tsr_needed(void *opaque)
-{
- SerialState *s = (SerialState *)opaque;
- return s->tsr_retry != 0;
-}
-
-static const VMStateDescription vmstate_serial_tsr = {
- .name = "serial/tsr",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = serial_tsr_needed,
- .fields = (VMStateField[]) {
- VMSTATE_INT32(tsr_retry, SerialState),
- VMSTATE_UINT8(thr, SerialState),
- VMSTATE_UINT8(tsr, SerialState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static bool serial_recv_fifo_needed(void *opaque)
-{
- SerialState *s = (SerialState *)opaque;
- return !fifo8_is_empty(&s->recv_fifo);
-
-}
-
-static const VMStateDescription vmstate_serial_recv_fifo = {
- .name = "serial/recv_fifo",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = serial_recv_fifo_needed,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT(recv_fifo, SerialState, 1, vmstate_fifo8, Fifo8),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static bool serial_xmit_fifo_needed(void *opaque)
-{
- SerialState *s = (SerialState *)opaque;
- return !fifo8_is_empty(&s->xmit_fifo);
-}
-
-static const VMStateDescription vmstate_serial_xmit_fifo = {
- .name = "serial/xmit_fifo",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = serial_xmit_fifo_needed,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT(xmit_fifo, SerialState, 1, vmstate_fifo8, Fifo8),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static bool serial_fifo_timeout_timer_needed(void *opaque)
-{
- SerialState *s = (SerialState *)opaque;
- return timer_pending(s->fifo_timeout_timer);
-}
-
-static const VMStateDescription vmstate_serial_fifo_timeout_timer = {
- .name = "serial/fifo_timeout_timer",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = serial_fifo_timeout_timer_needed,
- .fields = (VMStateField[]) {
- VMSTATE_TIMER_PTR(fifo_timeout_timer, SerialState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static bool serial_timeout_ipending_needed(void *opaque)
-{
- SerialState *s = (SerialState *)opaque;
- return s->timeout_ipending != 0;
-}
-
-static const VMStateDescription vmstate_serial_timeout_ipending = {
- .name = "serial/timeout_ipending",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = serial_timeout_ipending_needed,
- .fields = (VMStateField[]) {
- VMSTATE_INT32(timeout_ipending, SerialState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static bool serial_poll_needed(void *opaque)
-{
- SerialState *s = (SerialState *)opaque;
- return s->poll_msl >= 0;
-}
-
-static const VMStateDescription vmstate_serial_poll = {
- .name = "serial/poll",
- .version_id = 1,
- .needed = serial_poll_needed,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_INT32(poll_msl, SerialState),
- VMSTATE_TIMER_PTR(modem_status_poll, SerialState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-const VMStateDescription vmstate_serial = {
- .name = "serial",
- .version_id = 3,
- .minimum_version_id = 2,
- .pre_save = serial_pre_save,
- .pre_load = serial_pre_load,
- .post_load = serial_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT16_V(divider, SerialState, 2),
- VMSTATE_UINT8(rbr, SerialState),
- VMSTATE_UINT8(ier, SerialState),
- VMSTATE_UINT8(iir, SerialState),
- VMSTATE_UINT8(lcr, SerialState),
- VMSTATE_UINT8(mcr, SerialState),
- VMSTATE_UINT8(lsr, SerialState),
- VMSTATE_UINT8(msr, SerialState),
- VMSTATE_UINT8(scr, SerialState),
- VMSTATE_UINT8_V(fcr_vmstate, SerialState, 3),
- VMSTATE_END_OF_LIST()
- },
- .subsections = (const VMStateDescription*[]) {
- &vmstate_serial_thr_ipending,
- &vmstate_serial_tsr,
- &vmstate_serial_recv_fifo,
- &vmstate_serial_xmit_fifo,
- &vmstate_serial_fifo_timeout_timer,
- &vmstate_serial_timeout_ipending,
- &vmstate_serial_poll,
- NULL
- }
-};
-
-static void serial_reset(void *opaque)
-{
- SerialState *s = opaque;
-
- s->rbr = 0;
- s->ier = 0;
- s->iir = UART_IIR_NO_INT;
- s->lcr = 0;
- s->lsr = UART_LSR_TEMT | UART_LSR_THRE;
- s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS;
- /* Default to 9600 baud, 1 start bit, 8 data bits, 1 stop bit, no parity. */
- s->divider = 0x0C;
- s->mcr = UART_MCR_OUT2;
- s->scr = 0;
- s->tsr_retry = 0;
- s->char_transmit_time = (NANOSECONDS_PER_SECOND / 9600) * 10;
- s->poll_msl = 0;
-
- s->timeout_ipending = 0;
- timer_del(s->fifo_timeout_timer);
- timer_del(s->modem_status_poll);
-
- fifo8_reset(&s->recv_fifo);
- fifo8_reset(&s->xmit_fifo);
-
- s->last_xmit_ts = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-
- s->thr_ipending = 0;
- s->last_break_enable = 0;
- qemu_irq_lower(s->irq);
-
- serial_update_msl(s);
- s->msr &= ~UART_MSR_ANY_DELTA;
-}
-
-void serial_realize_core(SerialState *s, Error **errp)
-{
- if (!s->chr) {
- error_setg(errp, "Can't create serial device, empty char device");
- return;
- }
-
- s->modem_status_poll = timer_new_ns(QEMU_CLOCK_VIRTUAL, (QEMUTimerCB *) serial_update_msl, s);
-
- s->fifo_timeout_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, (QEMUTimerCB *) fifo_timeout_int, s);
- qemu_register_reset(serial_reset, s);
-
- qemu_chr_add_handlers(s->chr, serial_can_receive1, serial_receive1,
- serial_event, s);
- fifo8_create(&s->recv_fifo, UART_FIFO_LENGTH);
- fifo8_create(&s->xmit_fifo, UART_FIFO_LENGTH);
- serial_reset(s);
-}
-
-void serial_exit_core(SerialState *s)
-{
- qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, NULL);
- qemu_unregister_reset(serial_reset, s);
-}
-
-/* Change the main reference oscillator frequency. */
-void serial_set_frequency(SerialState *s, uint32_t frequency)
-{
- s->baudbase = frequency;
- serial_update_parameters(s);
-}
-
-const MemoryRegionOps serial_io_ops = {
- .read = serial_ioport_read,
- .write = serial_ioport_write,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-SerialState *serial_init(int base, qemu_irq irq, int baudbase,
- CharDriverState *chr, MemoryRegion *system_io)
-{
- SerialState *s;
-
- s = g_malloc0(sizeof(SerialState));
-
- s->irq = irq;
- s->baudbase = baudbase;
- s->chr = chr;
- serial_realize_core(s, &error_fatal);
-
- vmstate_register(NULL, base, &vmstate_serial, s);
-
- memory_region_init_io(&s->io, NULL, &serial_io_ops, s, "serial", 8);
- memory_region_add_subregion(system_io, base, &s->io);
-
- return s;
-}
-
-/* Memory mapped interface */
-static uint64_t serial_mm_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- SerialState *s = opaque;
- return serial_ioport_read(s, addr >> s->it_shift, 1);
-}
-
-static void serial_mm_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- SerialState *s = opaque;
- value &= ~0u >> (32 - (size * 8));
- serial_ioport_write(s, addr >> s->it_shift, value, 1);
-}
-
-static const MemoryRegionOps serial_mm_ops[3] = {
- [DEVICE_NATIVE_ENDIAN] = {
- .read = serial_mm_read,
- .write = serial_mm_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- },
- [DEVICE_LITTLE_ENDIAN] = {
- .read = serial_mm_read,
- .write = serial_mm_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- },
- [DEVICE_BIG_ENDIAN] = {
- .read = serial_mm_read,
- .write = serial_mm_write,
- .endianness = DEVICE_BIG_ENDIAN,
- },
-};
-
-SerialState *serial_mm_init(MemoryRegion *address_space,
- hwaddr base, int it_shift,
- qemu_irq irq, int baudbase,
- CharDriverState *chr, enum device_endian end)
-{
- SerialState *s;
-
- s = g_malloc0(sizeof(SerialState));
-
- s->it_shift = it_shift;
- s->irq = irq;
- s->baudbase = baudbase;
- s->chr = chr;
-
- serial_realize_core(s, &error_fatal);
- vmstate_register(NULL, base, &vmstate_serial, s);
-
- memory_region_init_io(&s->io, NULL, &serial_mm_ops[end], s,
- "serial", 8 << it_shift);
- memory_region_add_subregion(address_space, base, &s->io);
- return s;
-}
diff --git a/qemu/hw/char/sh_serial.c b/qemu/hw/char/sh_serial.c
deleted file mode 100644
index 4c55dcb7d..000000000
--- a/qemu/hw/char/sh_serial.c
+++ /dev/null
@@ -1,409 +0,0 @@
-/*
- * QEMU SCI/SCIF serial port emulation
- *
- * Copyright (c) 2007 Magnus Damm
- *
- * Based on serial.c - QEMU 16450 UART emulation
- * Copyright (c) 2003-2004 Fabrice Bellard
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/sh4/sh.h"
-#include "sysemu/char.h"
-#include "exec/address-spaces.h"
-
-//#define DEBUG_SERIAL
-
-#define SH_SERIAL_FLAG_TEND (1 << 0)
-#define SH_SERIAL_FLAG_TDE (1 << 1)
-#define SH_SERIAL_FLAG_RDF (1 << 2)
-#define SH_SERIAL_FLAG_BRK (1 << 3)
-#define SH_SERIAL_FLAG_DR (1 << 4)
-
-#define SH_RX_FIFO_LENGTH (16)
-
-typedef struct {
- MemoryRegion iomem;
- MemoryRegion iomem_p4;
- MemoryRegion iomem_a7;
- uint8_t smr;
- uint8_t brr;
- uint8_t scr;
- uint8_t dr; /* ftdr / tdr */
- uint8_t sr; /* fsr / ssr */
- uint16_t fcr;
- uint8_t sptr;
-
- uint8_t rx_fifo[SH_RX_FIFO_LENGTH]; /* frdr / rdr */
- uint8_t rx_cnt;
- uint8_t rx_tail;
- uint8_t rx_head;
-
- int freq;
- int feat;
- int flags;
- int rtrg;
-
- CharDriverState *chr;
-
- qemu_irq eri;
- qemu_irq rxi;
- qemu_irq txi;
- qemu_irq tei;
- qemu_irq bri;
-} sh_serial_state;
-
-static void sh_serial_clear_fifo(sh_serial_state * s)
-{
- memset(s->rx_fifo, 0, SH_RX_FIFO_LENGTH);
- s->rx_cnt = 0;
- s->rx_head = 0;
- s->rx_tail = 0;
-}
-
-static void sh_serial_write(void *opaque, hwaddr offs,
- uint64_t val, unsigned size)
-{
- sh_serial_state *s = opaque;
- unsigned char ch;
-
-#ifdef DEBUG_SERIAL
- printf("sh_serial: write offs=0x%02x val=0x%02x\n",
- offs, val);
-#endif
- switch(offs) {
- case 0x00: /* SMR */
- s->smr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0x7b : 0xff);
- return;
- case 0x04: /* BRR */
- s->brr = val;
- return;
- case 0x08: /* SCR */
- /* TODO : For SH7751, SCIF mask should be 0xfb. */
- s->scr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0xfa : 0xff);
- if (!(val & (1 << 5)))
- s->flags |= SH_SERIAL_FLAG_TEND;
- if ((s->feat & SH_SERIAL_FEAT_SCIF) && s->txi) {
- qemu_set_irq(s->txi, val & (1 << 7));
- }
- if (!(val & (1 << 6))) {
- qemu_set_irq(s->rxi, 0);
- }
- return;
- case 0x0c: /* FTDR / TDR */
- if (s->chr) {
- ch = val;
- qemu_chr_fe_write(s->chr, &ch, 1);
- }
- s->dr = val;
- s->flags &= ~SH_SERIAL_FLAG_TDE;
- return;
-#if 0
- case 0x14: /* FRDR / RDR */
- ret = 0;
- break;
-#endif
- }
- if (s->feat & SH_SERIAL_FEAT_SCIF) {
- switch(offs) {
- case 0x10: /* FSR */
- if (!(val & (1 << 6)))
- s->flags &= ~SH_SERIAL_FLAG_TEND;
- if (!(val & (1 << 5)))
- s->flags &= ~SH_SERIAL_FLAG_TDE;
- if (!(val & (1 << 4)))
- s->flags &= ~SH_SERIAL_FLAG_BRK;
- if (!(val & (1 << 1)))
- s->flags &= ~SH_SERIAL_FLAG_RDF;
- if (!(val & (1 << 0)))
- s->flags &= ~SH_SERIAL_FLAG_DR;
-
- if (!(val & (1 << 1)) || !(val & (1 << 0))) {
- if (s->rxi) {
- qemu_set_irq(s->rxi, 0);
- }
- }
- return;
- case 0x18: /* FCR */
- s->fcr = val;
- switch ((val >> 6) & 3) {
- case 0:
- s->rtrg = 1;
- break;
- case 1:
- s->rtrg = 4;
- break;
- case 2:
- s->rtrg = 8;
- break;
- case 3:
- s->rtrg = 14;
- break;
- }
- if (val & (1 << 1)) {
- sh_serial_clear_fifo(s);
- s->sr &= ~(1 << 1);
- }
-
- return;
- case 0x20: /* SPTR */
- s->sptr = val & 0xf3;
- return;
- case 0x24: /* LSR */
- return;
- }
- }
- else {
- switch(offs) {
-#if 0
- case 0x0c:
- ret = s->dr;
- break;
- case 0x10:
- ret = 0;
- break;
-#endif
- case 0x1c:
- s->sptr = val & 0x8f;
- return;
- }
- }
-
- fprintf(stderr, "sh_serial: unsupported write to 0x%02"
- HWADDR_PRIx "\n", offs);
- abort();
-}
-
-static uint64_t sh_serial_read(void *opaque, hwaddr offs,
- unsigned size)
-{
- sh_serial_state *s = opaque;
- uint32_t ret = ~0;
-
-#if 0
- switch(offs) {
- case 0x00:
- ret = s->smr;
- break;
- case 0x04:
- ret = s->brr;
- break;
- case 0x08:
- ret = s->scr;
- break;
- case 0x14:
- ret = 0;
- break;
- }
-#endif
- if (s->feat & SH_SERIAL_FEAT_SCIF) {
- switch(offs) {
- case 0x00: /* SMR */
- ret = s->smr;
- break;
- case 0x08: /* SCR */
- ret = s->scr;
- break;
- case 0x10: /* FSR */
- ret = 0;
- if (s->flags & SH_SERIAL_FLAG_TEND)
- ret |= (1 << 6);
- if (s->flags & SH_SERIAL_FLAG_TDE)
- ret |= (1 << 5);
- if (s->flags & SH_SERIAL_FLAG_BRK)
- ret |= (1 << 4);
- if (s->flags & SH_SERIAL_FLAG_RDF)
- ret |= (1 << 1);
- if (s->flags & SH_SERIAL_FLAG_DR)
- ret |= (1 << 0);
-
- if (s->scr & (1 << 5))
- s->flags |= SH_SERIAL_FLAG_TDE | SH_SERIAL_FLAG_TEND;
-
- break;
- case 0x14:
- if (s->rx_cnt > 0) {
- ret = s->rx_fifo[s->rx_tail++];
- s->rx_cnt--;
- if (s->rx_tail == SH_RX_FIFO_LENGTH)
- s->rx_tail = 0;
- if (s->rx_cnt < s->rtrg)
- s->flags &= ~SH_SERIAL_FLAG_RDF;
- }
- break;
- case 0x18:
- ret = s->fcr;
- break;
- case 0x1c:
- ret = s->rx_cnt;
- break;
- case 0x20:
- ret = s->sptr;
- break;
- case 0x24:
- ret = 0;
- break;
- }
- }
- else {
- switch(offs) {
-#if 0
- case 0x0c:
- ret = s->dr;
- break;
- case 0x10:
- ret = 0;
- break;
- case 0x14:
- ret = s->rx_fifo[0];
- break;
-#endif
- case 0x1c:
- ret = s->sptr;
- break;
- }
- }
-#ifdef DEBUG_SERIAL
- printf("sh_serial: read offs=0x%02x val=0x%x\n",
- offs, ret);
-#endif
-
- if (ret & ~((1 << 16) - 1)) {
- fprintf(stderr, "sh_serial: unsupported read from 0x%02"
- HWADDR_PRIx "\n", offs);
- abort();
- }
-
- return ret;
-}
-
-static int sh_serial_can_receive(sh_serial_state *s)
-{
- return s->scr & (1 << 4);
-}
-
-static void sh_serial_receive_break(sh_serial_state *s)
-{
- if (s->feat & SH_SERIAL_FEAT_SCIF)
- s->sr |= (1 << 4);
-}
-
-static int sh_serial_can_receive1(void *opaque)
-{
- sh_serial_state *s = opaque;
- return sh_serial_can_receive(s);
-}
-
-static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size)
-{
- sh_serial_state *s = opaque;
-
- if (s->feat & SH_SERIAL_FEAT_SCIF) {
- int i;
- for (i = 0; i < size; i++) {
- if (s->rx_cnt < SH_RX_FIFO_LENGTH) {
- s->rx_fifo[s->rx_head++] = buf[i];
- if (s->rx_head == SH_RX_FIFO_LENGTH) {
- s->rx_head = 0;
- }
- s->rx_cnt++;
- if (s->rx_cnt >= s->rtrg) {
- s->flags |= SH_SERIAL_FLAG_RDF;
- if (s->scr & (1 << 6) && s->rxi) {
- qemu_set_irq(s->rxi, 1);
- }
- }
- }
- }
- } else {
- s->rx_fifo[0] = buf[0];
- }
-}
-
-static void sh_serial_event(void *opaque, int event)
-{
- sh_serial_state *s = opaque;
- if (event == CHR_EVENT_BREAK)
- sh_serial_receive_break(s);
-}
-
-static const MemoryRegionOps sh_serial_ops = {
- .read = sh_serial_read,
- .write = sh_serial_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-void sh_serial_init(MemoryRegion *sysmem,
- hwaddr base, int feat,
- uint32_t freq, CharDriverState *chr,
- qemu_irq eri_source,
- qemu_irq rxi_source,
- qemu_irq txi_source,
- qemu_irq tei_source,
- qemu_irq bri_source)
-{
- sh_serial_state *s;
-
- s = g_malloc0(sizeof(sh_serial_state));
-
- s->feat = feat;
- s->flags = SH_SERIAL_FLAG_TEND | SH_SERIAL_FLAG_TDE;
- s->rtrg = 1;
-
- s->smr = 0;
- s->brr = 0xff;
- s->scr = 1 << 5; /* pretend that TX is enabled so early printk works */
- s->sptr = 0;
-
- if (feat & SH_SERIAL_FEAT_SCIF) {
- s->fcr = 0;
- }
- else {
- s->dr = 0xff;
- }
-
- sh_serial_clear_fifo(s);
-
- memory_region_init_io(&s->iomem, NULL, &sh_serial_ops, s,
- "serial", 0x100000000ULL);
-
- memory_region_init_alias(&s->iomem_p4, NULL, "serial-p4", &s->iomem,
- 0, 0x28);
- memory_region_add_subregion(sysmem, P4ADDR(base), &s->iomem_p4);
-
- memory_region_init_alias(&s->iomem_a7, NULL, "serial-a7", &s->iomem,
- 0, 0x28);
- memory_region_add_subregion(sysmem, A7ADDR(base), &s->iomem_a7);
-
- s->chr = chr;
-
- if (chr) {
- qemu_chr_fe_claim_no_fail(chr);
- qemu_chr_add_handlers(chr, sh_serial_can_receive1, sh_serial_receive1,
- sh_serial_event, s);
- }
-
- s->eri = eri_source;
- s->rxi = rxi_source;
- s->txi = txi_source;
- s->tei = tei_source;
- s->bri = bri_source;
-}
diff --git a/qemu/hw/char/spapr_vty.c b/qemu/hw/char/spapr_vty.c
deleted file mode 100644
index 3498d7b05..000000000
--- a/qemu/hw/char/spapr_vty.c
+++ /dev/null
@@ -1,249 +0,0 @@
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/qdev.h"
-#include "sysemu/char.h"
-#include "hw/ppc/spapr.h"
-#include "hw/ppc/spapr_vio.h"
-
-#define VTERM_BUFSIZE 16
-
-typedef struct VIOsPAPRVTYDevice {
- VIOsPAPRDevice sdev;
- CharDriverState *chardev;
- uint32_t in, out;
- uint8_t buf[VTERM_BUFSIZE];
-} VIOsPAPRVTYDevice;
-
-#define TYPE_VIO_SPAPR_VTY_DEVICE "spapr-vty"
-#define VIO_SPAPR_VTY_DEVICE(obj) \
- OBJECT_CHECK(VIOsPAPRVTYDevice, (obj), TYPE_VIO_SPAPR_VTY_DEVICE)
-
-static int vty_can_receive(void *opaque)
-{
- VIOsPAPRVTYDevice *dev = VIO_SPAPR_VTY_DEVICE(opaque);
-
- return (dev->in - dev->out) < VTERM_BUFSIZE;
-}
-
-static void vty_receive(void *opaque, const uint8_t *buf, int size)
-{
- VIOsPAPRVTYDevice *dev = VIO_SPAPR_VTY_DEVICE(opaque);
- int i;
-
- if ((dev->in == dev->out) && size) {
- /* toggle line to simulate edge interrupt */
- qemu_irq_pulse(spapr_vio_qirq(&dev->sdev));
- }
- for (i = 0; i < size; i++) {
- assert((dev->in - dev->out) < VTERM_BUFSIZE);
- dev->buf[dev->in++ % VTERM_BUFSIZE] = buf[i];
- }
-}
-
-static int vty_getchars(VIOsPAPRDevice *sdev, uint8_t *buf, int max)
-{
- VIOsPAPRVTYDevice *dev = VIO_SPAPR_VTY_DEVICE(sdev);
- int n = 0;
-
- while ((n < max) && (dev->out != dev->in)) {
- buf[n++] = dev->buf[dev->out++ % VTERM_BUFSIZE];
- }
-
- qemu_chr_accept_input(dev->chardev);
-
- return n;
-}
-
-void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len)
-{
- VIOsPAPRVTYDevice *dev = VIO_SPAPR_VTY_DEVICE(sdev);
-
- /* FIXME: should check the qemu_chr_fe_write() return value */
- qemu_chr_fe_write(dev->chardev, buf, len);
-}
-
-static void spapr_vty_realize(VIOsPAPRDevice *sdev, Error **errp)
-{
- VIOsPAPRVTYDevice *dev = VIO_SPAPR_VTY_DEVICE(sdev);
-
- if (!dev->chardev) {
- error_setg(errp, "chardev property not set");
- return;
- }
-
- qemu_chr_add_handlers(dev->chardev, vty_can_receive,
- vty_receive, NULL, dev);
-}
-
-/* Forward declaration */
-static target_ulong h_put_term_char(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- target_ulong reg = args[0];
- target_ulong len = args[1];
- target_ulong char0_7 = args[2];
- target_ulong char8_15 = args[3];
- VIOsPAPRDevice *sdev;
- uint8_t buf[16];
-
- sdev = vty_lookup(spapr, reg);
- if (!sdev) {
- return H_PARAMETER;
- }
-
- if (len > 16) {
- return H_PARAMETER;
- }
-
- *((uint64_t *)buf) = cpu_to_be64(char0_7);
- *((uint64_t *)buf + 1) = cpu_to_be64(char8_15);
-
- vty_putchars(sdev, buf, len);
-
- return H_SUCCESS;
-}
-
-static target_ulong h_get_term_char(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- target_ulong reg = args[0];
- target_ulong *len = args + 0;
- target_ulong *char0_7 = args + 1;
- target_ulong *char8_15 = args + 2;
- VIOsPAPRDevice *sdev;
- uint8_t buf[16];
-
- sdev = vty_lookup(spapr, reg);
- if (!sdev) {
- return H_PARAMETER;
- }
-
- *len = vty_getchars(sdev, buf, sizeof(buf));
- if (*len < 16) {
- memset(buf + *len, 0, 16 - *len);
- }
-
- *char0_7 = be64_to_cpu(*((uint64_t *)buf));
- *char8_15 = be64_to_cpu(*((uint64_t *)buf + 1));
-
- return H_SUCCESS;
-}
-
-void spapr_vty_create(VIOsPAPRBus *bus, CharDriverState *chardev)
-{
- DeviceState *dev;
-
- dev = qdev_create(&bus->bus, "spapr-vty");
- qdev_prop_set_chr(dev, "chardev", chardev);
- qdev_init_nofail(dev);
-}
-
-static Property spapr_vty_properties[] = {
- DEFINE_SPAPR_PROPERTIES(VIOsPAPRVTYDevice, sdev),
- DEFINE_PROP_CHR("chardev", VIOsPAPRVTYDevice, chardev),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static const VMStateDescription vmstate_spapr_vty = {
- .name = "spapr_vty",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_SPAPR_VIO(sdev, VIOsPAPRVTYDevice),
-
- VMSTATE_UINT32(in, VIOsPAPRVTYDevice),
- VMSTATE_UINT32(out, VIOsPAPRVTYDevice),
- VMSTATE_BUFFER(buf, VIOsPAPRVTYDevice),
- VMSTATE_END_OF_LIST()
- },
-};
-
-static void spapr_vty_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
-
- k->realize = spapr_vty_realize;
- k->dt_name = "vty";
- k->dt_type = "serial";
- k->dt_compatible = "hvterm1";
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
- dc->props = spapr_vty_properties;
- dc->vmsd = &vmstate_spapr_vty;
-}
-
-static const TypeInfo spapr_vty_info = {
- .name = TYPE_VIO_SPAPR_VTY_DEVICE,
- .parent = TYPE_VIO_SPAPR_DEVICE,
- .instance_size = sizeof(VIOsPAPRVTYDevice),
- .class_init = spapr_vty_class_init,
-};
-
-VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus)
-{
- VIOsPAPRDevice *sdev, *selected;
- BusChild *kid;
-
- /*
- * To avoid the console bouncing around we want one VTY to be
- * the "default". We haven't really got anything to go on, so
- * arbitrarily choose the one with the lowest reg value.
- */
-
- selected = NULL;
- QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
- DeviceState *iter = kid->child;
-
- /* Only look at VTY devices */
- if (!object_dynamic_cast(OBJECT(iter), TYPE_VIO_SPAPR_VTY_DEVICE)) {
- continue;
- }
-
- sdev = VIO_SPAPR_DEVICE(iter);
-
- /* First VTY we've found, so it is selected for now */
- if (!selected) {
- selected = sdev;
- continue;
- }
-
- /* Choose VTY with lowest reg value */
- if (sdev->reg < selected->reg) {
- selected = sdev;
- }
- }
-
- return selected;
-}
-
-VIOsPAPRDevice *vty_lookup(sPAPRMachineState *spapr, target_ulong reg)
-{
- VIOsPAPRDevice *sdev;
-
- sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
- if (!sdev && reg == 0) {
- /* Hack for kernel early debug, which always specifies reg==0.
- * We search all VIO devices, and grab the vty with the lowest
- * reg. This attempts to mimic existing PowerVM behaviour
- * (early debug does work there, despite having no vty with
- * reg==0. */
- return spapr_vty_get_default(spapr->vio_bus);
- }
-
- if (!object_dynamic_cast(OBJECT(sdev), TYPE_VIO_SPAPR_VTY_DEVICE)) {
- return NULL;
- }
-
- return sdev;
-}
-
-static void spapr_vty_register_types(void)
-{
- spapr_register_hypercall(H_PUT_TERM_CHAR, h_put_term_char);
- spapr_register_hypercall(H_GET_TERM_CHAR, h_get_term_char);
- type_register_static(&spapr_vty_info);
-}
-
-type_init(spapr_vty_register_types)
diff --git a/qemu/hw/char/stm32f2xx_usart.c b/qemu/hw/char/stm32f2xx_usart.c
deleted file mode 100644
index a94d61ceb..000000000
--- a/qemu/hw/char/stm32f2xx_usart.c
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * STM32F2XX USART
- *
- * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/char/stm32f2xx_usart.h"
-
-#ifndef STM_USART_ERR_DEBUG
-#define STM_USART_ERR_DEBUG 0
-#endif
-
-#define DB_PRINT_L(lvl, fmt, args...) do { \
- if (STM_USART_ERR_DEBUG >= lvl) { \
- qemu_log("%s: " fmt, __func__, ## args); \
- } \
-} while (0);
-
-#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args)
-
-static int stm32f2xx_usart_can_receive(void *opaque)
-{
- STM32F2XXUsartState *s = opaque;
-
- if (!(s->usart_sr & USART_SR_RXNE)) {
- return 1;
- }
-
- return 0;
-}
-
-static void stm32f2xx_usart_receive(void *opaque, const uint8_t *buf, int size)
-{
- STM32F2XXUsartState *s = opaque;
-
- s->usart_dr = *buf;
-
- if (!(s->usart_cr1 & USART_CR1_UE && s->usart_cr1 & USART_CR1_RE)) {
- /* USART not enabled - drop the chars */
- DB_PRINT("Dropping the chars\n");
- return;
- }
-
- s->usart_sr |= USART_SR_RXNE;
-
- if (s->usart_cr1 & USART_CR1_RXNEIE) {
- qemu_set_irq(s->irq, 1);
- }
-
- DB_PRINT("Receiving: %c\n", s->usart_dr);
-}
-
-static void stm32f2xx_usart_reset(DeviceState *dev)
-{
- STM32F2XXUsartState *s = STM32F2XX_USART(dev);
-
- s->usart_sr = USART_SR_RESET;
- s->usart_dr = 0x00000000;
- s->usart_brr = 0x00000000;
- s->usart_cr1 = 0x00000000;
- s->usart_cr2 = 0x00000000;
- s->usart_cr3 = 0x00000000;
- s->usart_gtpr = 0x00000000;
-
- qemu_set_irq(s->irq, 0);
-}
-
-static uint64_t stm32f2xx_usart_read(void *opaque, hwaddr addr,
- unsigned int size)
-{
- STM32F2XXUsartState *s = opaque;
- uint64_t retvalue;
-
- DB_PRINT("Read 0x%"HWADDR_PRIx"\n", addr);
-
- switch (addr) {
- case USART_SR:
- retvalue = s->usart_sr;
- s->usart_sr &= ~USART_SR_TC;
- if (s->chr) {
- qemu_chr_accept_input(s->chr);
- }
- return retvalue;
- case USART_DR:
- DB_PRINT("Value: 0x%" PRIx32 ", %c\n", s->usart_dr, (char) s->usart_dr);
- s->usart_sr |= USART_SR_TXE;
- s->usart_sr &= ~USART_SR_RXNE;
- if (s->chr) {
- qemu_chr_accept_input(s->chr);
- }
- qemu_set_irq(s->irq, 0);
- return s->usart_dr & 0x3FF;
- case USART_BRR:
- return s->usart_brr;
- case USART_CR1:
- return s->usart_cr1;
- case USART_CR2:
- return s->usart_cr2;
- case USART_CR3:
- return s->usart_cr3;
- case USART_GTPR:
- return s->usart_gtpr;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
- return 0;
- }
-
- return 0;
-}
-
-static void stm32f2xx_usart_write(void *opaque, hwaddr addr,
- uint64_t val64, unsigned int size)
-{
- STM32F2XXUsartState *s = opaque;
- uint32_t value = val64;
- unsigned char ch;
-
- DB_PRINT("Write 0x%" PRIx32 ", 0x%"HWADDR_PRIx"\n", value, addr);
-
- switch (addr) {
- case USART_SR:
- if (value <= 0x3FF) {
- s->usart_sr = value;
- } else {
- s->usart_sr &= value;
- }
- if (!(s->usart_sr & USART_SR_RXNE)) {
- qemu_set_irq(s->irq, 0);
- }
- return;
- case USART_DR:
- if (value < 0xF000) {
- ch = value;
- if (s->chr) {
- qemu_chr_fe_write_all(s->chr, &ch, 1);
- }
- s->usart_sr |= USART_SR_TC;
- s->usart_sr &= ~USART_SR_TXE;
- }
- return;
- case USART_BRR:
- s->usart_brr = value;
- return;
- case USART_CR1:
- s->usart_cr1 = value;
- if (s->usart_cr1 & USART_CR1_RXNEIE &&
- s->usart_sr & USART_SR_RXNE) {
- qemu_set_irq(s->irq, 1);
- }
- return;
- case USART_CR2:
- s->usart_cr2 = value;
- return;
- case USART_CR3:
- s->usart_cr3 = value;
- return;
- case USART_GTPR:
- s->usart_gtpr = value;
- return;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
- }
-}
-
-static const MemoryRegionOps stm32f2xx_usart_ops = {
- .read = stm32f2xx_usart_read,
- .write = stm32f2xx_usart_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void stm32f2xx_usart_init(Object *obj)
-{
- STM32F2XXUsartState *s = STM32F2XX_USART(obj);
-
- sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
-
- memory_region_init_io(&s->mmio, obj, &stm32f2xx_usart_ops, s,
- TYPE_STM32F2XX_USART, 0x2000);
- sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
-
- /* FIXME use a qdev chardev prop instead of qemu_char_get_next_serial() */
- s->chr = qemu_char_get_next_serial();
-
- if (s->chr) {
- qemu_chr_add_handlers(s->chr, stm32f2xx_usart_can_receive,
- stm32f2xx_usart_receive, NULL, s);
- }
-}
-
-static void stm32f2xx_usart_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->reset = stm32f2xx_usart_reset;
- /* Reason: instance_init() method uses qemu_char_get_next_serial() */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo stm32f2xx_usart_info = {
- .name = TYPE_STM32F2XX_USART,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(STM32F2XXUsartState),
- .instance_init = stm32f2xx_usart_init,
- .class_init = stm32f2xx_usart_class_init,
-};
-
-static void stm32f2xx_usart_register_types(void)
-{
- type_register_static(&stm32f2xx_usart_info);
-}
-
-type_init(stm32f2xx_usart_register_types)
diff --git a/qemu/hw/char/virtio-console.c b/qemu/hw/char/virtio-console.c
deleted file mode 100644
index 2e36481a7..000000000
--- a/qemu/hw/char/virtio-console.c
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * Virtio Console and Generic Serial Port Devices
- *
- * Copyright Red Hat, Inc. 2009, 2010
- *
- * Authors:
- * Amit Shah <amit.shah@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "sysemu/char.h"
-#include "qemu/error-report.h"
-#include "trace.h"
-#include "hw/virtio/virtio-serial.h"
-#include "qapi-event.h"
-
-#define TYPE_VIRTIO_CONSOLE_SERIAL_PORT "virtserialport"
-#define VIRTIO_CONSOLE(obj) \
- OBJECT_CHECK(VirtConsole, (obj), TYPE_VIRTIO_CONSOLE_SERIAL_PORT)
-
-typedef struct VirtConsole {
- VirtIOSerialPort parent_obj;
-
- CharDriverState *chr;
- guint watch;
-} VirtConsole;
-
-/*
- * Callback function that's called from chardevs when backend becomes
- * writable.
- */
-static gboolean chr_write_unblocked(GIOChannel *chan, GIOCondition cond,
- void *opaque)
-{
- VirtConsole *vcon = opaque;
-
- vcon->watch = 0;
- virtio_serial_throttle_port(VIRTIO_SERIAL_PORT(vcon), false);
- return FALSE;
-}
-
-/* Callback function that's called when the guest sends us data */
-static ssize_t flush_buf(VirtIOSerialPort *port,
- const uint8_t *buf, ssize_t len)
-{
- VirtConsole *vcon = VIRTIO_CONSOLE(port);
- ssize_t ret;
-
- if (!vcon->chr) {
- /* If there's no backend, we can just say we consumed all data. */
- return len;
- }
-
- ret = qemu_chr_fe_write(vcon->chr, buf, len);
- trace_virtio_console_flush_buf(port->id, len, ret);
-
- if (ret < len) {
- VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port);
-
- /*
- * Ideally we'd get a better error code than just -1, but
- * that's what the chardev interface gives us right now. If
- * we had a finer-grained message, like -EPIPE, we could close
- * this connection.
- */
- if (ret < 0)
- ret = 0;
- if (!k->is_console) {
- virtio_serial_throttle_port(port, true);
- if (!vcon->watch) {
- vcon->watch = qemu_chr_fe_add_watch(vcon->chr,
- G_IO_OUT|G_IO_HUP,
- chr_write_unblocked, vcon);
- }
- }
- }
- return ret;
-}
-
-/* Callback function that's called when the guest opens/closes the port */
-static void set_guest_connected(VirtIOSerialPort *port, int guest_connected)
-{
- VirtConsole *vcon = VIRTIO_CONSOLE(port);
- DeviceState *dev = DEVICE(port);
-
- if (vcon->chr) {
- qemu_chr_fe_set_open(vcon->chr, guest_connected);
- }
-
- if (dev->id) {
- qapi_event_send_vserport_change(dev->id, guest_connected,
- &error_abort);
- }
-}
-
-static void guest_writable(VirtIOSerialPort *port)
-{
- VirtConsole *vcon = VIRTIO_CONSOLE(port);
-
- if (vcon->chr) {
- qemu_chr_accept_input(vcon->chr);
- }
-}
-
-/* Readiness of the guest to accept data on a port */
-static int chr_can_read(void *opaque)
-{
- VirtConsole *vcon = opaque;
-
- return virtio_serial_guest_ready(VIRTIO_SERIAL_PORT(vcon));
-}
-
-/* Send data from a char device over to the guest */
-static void chr_read(void *opaque, const uint8_t *buf, int size)
-{
- VirtConsole *vcon = opaque;
- VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(vcon);
-
- trace_virtio_console_chr_read(port->id, size);
- virtio_serial_write(port, buf, size);
-}
-
-static void chr_event(void *opaque, int event)
-{
- VirtConsole *vcon = opaque;
- VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(vcon);
-
- trace_virtio_console_chr_event(port->id, event);
- switch (event) {
- case CHR_EVENT_OPENED:
- virtio_serial_open(port);
- break;
- case CHR_EVENT_CLOSED:
- if (vcon->watch) {
- g_source_remove(vcon->watch);
- vcon->watch = 0;
- }
- virtio_serial_close(port);
- break;
- }
-}
-
-static void virtconsole_realize(DeviceState *dev, Error **errp)
-{
- VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(dev);
- VirtConsole *vcon = VIRTIO_CONSOLE(dev);
- VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(dev);
-
- if (port->id == 0 && !k->is_console) {
- error_setg(errp, "Port number 0 on virtio-serial devices reserved "
- "for virtconsole devices for backward compatibility.");
- return;
- }
-
- if (vcon->chr) {
- vcon->chr->explicit_fe_open = 1;
- qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read, chr_event,
- vcon);
- }
-}
-
-static void virtconsole_unrealize(DeviceState *dev, Error **errp)
-{
- VirtConsole *vcon = VIRTIO_CONSOLE(dev);
-
- if (vcon->watch) {
- g_source_remove(vcon->watch);
- }
-}
-
-static void virtconsole_class_init(ObjectClass *klass, void *data)
-{
- VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_CLASS(klass);
-
- k->is_console = true;
-}
-
-static const TypeInfo virtconsole_info = {
- .name = "virtconsole",
- .parent = TYPE_VIRTIO_CONSOLE_SERIAL_PORT,
- .class_init = virtconsole_class_init,
-};
-
-static Property virtserialport_properties[] = {
- DEFINE_PROP_CHR("chardev", VirtConsole, chr),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtserialport_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_CLASS(klass);
-
- k->realize = virtconsole_realize;
- k->unrealize = virtconsole_unrealize;
- k->have_data = flush_buf;
- k->set_guest_connected = set_guest_connected;
- k->guest_writable = guest_writable;
- dc->props = virtserialport_properties;
-}
-
-static const TypeInfo virtserialport_info = {
- .name = TYPE_VIRTIO_CONSOLE_SERIAL_PORT,
- .parent = TYPE_VIRTIO_SERIAL_PORT,
- .instance_size = sizeof(VirtConsole),
- .class_init = virtserialport_class_init,
-};
-
-static void virtconsole_register_types(void)
-{
- type_register_static(&virtserialport_info);
- type_register_static(&virtconsole_info);
-}
-
-type_init(virtconsole_register_types)
diff --git a/qemu/hw/char/virtio-serial-bus.c b/qemu/hw/char/virtio-serial-bus.c
deleted file mode 100644
index 6e5de6dec..000000000
--- a/qemu/hw/char/virtio-serial-bus.c
+++ /dev/null
@@ -1,1149 +0,0 @@
-/*
- * A bus for connecting virtio serial and console ports
- *
- * Copyright (C) 2009, 2010 Red Hat, Inc.
- *
- * Author(s):
- * Amit Shah <amit.shah@redhat.com>
- *
- * Some earlier parts are:
- * Copyright IBM, Corp. 2008
- * authored by
- * Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu/iov.h"
-#include "monitor/monitor.h"
-#include "qemu/error-report.h"
-#include "qemu/queue.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "hw/virtio/virtio-serial.h"
-#include "hw/virtio/virtio-access.h"
-
-static struct VirtIOSerialDevices {
- QLIST_HEAD(, VirtIOSerial) devices;
-} vserdevices;
-
-static VirtIOSerialPort *find_port_by_id(VirtIOSerial *vser, uint32_t id)
-{
- VirtIOSerialPort *port;
-
- if (id == VIRTIO_CONSOLE_BAD_ID) {
- return NULL;
- }
-
- QTAILQ_FOREACH(port, &vser->ports, next) {
- if (port->id == id)
- return port;
- }
- return NULL;
-}
-
-static VirtIOSerialPort *find_port_by_vq(VirtIOSerial *vser, VirtQueue *vq)
-{
- VirtIOSerialPort *port;
-
- QTAILQ_FOREACH(port, &vser->ports, next) {
- if (port->ivq == vq || port->ovq == vq)
- return port;
- }
- return NULL;
-}
-
-static VirtIOSerialPort *find_port_by_name(char *name)
-{
- VirtIOSerial *vser;
-
- QLIST_FOREACH(vser, &vserdevices.devices, next) {
- VirtIOSerialPort *port;
-
- QTAILQ_FOREACH(port, &vser->ports, next) {
- if (port->name && !strcmp(port->name, name)) {
- return port;
- }
- }
- }
- return NULL;
-}
-
-static bool use_multiport(VirtIOSerial *vser)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(vser);
- return virtio_vdev_has_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT);
-}
-
-static size_t write_to_port(VirtIOSerialPort *port,
- const uint8_t *buf, size_t size)
-{
- VirtQueueElement *elem;
- VirtQueue *vq;
- size_t offset;
-
- vq = port->ivq;
- if (!virtio_queue_ready(vq)) {
- return 0;
- }
-
- offset = 0;
- while (offset < size) {
- size_t len;
-
- elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
- if (!elem) {
- break;
- }
-
- len = iov_from_buf(elem->in_sg, elem->in_num, 0,
- buf + offset, size - offset);
- offset += len;
-
- virtqueue_push(vq, elem, len);
- g_free(elem);
- }
-
- virtio_notify(VIRTIO_DEVICE(port->vser), vq);
- return offset;
-}
-
-static void discard_vq_data(VirtQueue *vq, VirtIODevice *vdev)
-{
- VirtQueueElement *elem;
-
- if (!virtio_queue_ready(vq)) {
- return;
- }
- for (;;) {
- elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
- if (!elem) {
- break;
- }
- virtqueue_push(vq, elem, 0);
- g_free(elem);
- }
- virtio_notify(vdev, vq);
-}
-
-static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
- VirtIODevice *vdev)
-{
- VirtIOSerialPortClass *vsc;
-
- assert(port);
- assert(virtio_queue_ready(vq));
-
- vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
-
- while (!port->throttled) {
- unsigned int i;
-
- /* Pop an elem only if we haven't left off a previous one mid-way */
- if (!port->elem) {
- port->elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
- if (!port->elem) {
- break;
- }
- port->iov_idx = 0;
- port->iov_offset = 0;
- }
-
- for (i = port->iov_idx; i < port->elem->out_num; i++) {
- size_t buf_size;
- ssize_t ret;
-
- buf_size = port->elem->out_sg[i].iov_len - port->iov_offset;
- ret = vsc->have_data(port,
- port->elem->out_sg[i].iov_base
- + port->iov_offset,
- buf_size);
- if (port->throttled) {
- port->iov_idx = i;
- if (ret > 0) {
- port->iov_offset += ret;
- }
- break;
- }
- port->iov_offset = 0;
- }
- if (port->throttled) {
- break;
- }
- virtqueue_push(vq, port->elem, 0);
- g_free(port->elem);
- port->elem = NULL;
- }
- virtio_notify(vdev, vq);
-}
-
-static void flush_queued_data(VirtIOSerialPort *port)
-{
- assert(port);
-
- if (!virtio_queue_ready(port->ovq)) {
- return;
- }
- do_flush_queued_data(port, port->ovq, VIRTIO_DEVICE(port->vser));
-}
-
-static size_t send_control_msg(VirtIOSerial *vser, void *buf, size_t len)
-{
- VirtQueueElement *elem;
- VirtQueue *vq;
-
- vq = vser->c_ivq;
- if (!virtio_queue_ready(vq)) {
- return 0;
- }
-
- elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
- if (!elem) {
- return 0;
- }
-
- /* TODO: detect a buffer that's too short, set NEEDS_RESET */
- iov_from_buf(elem->in_sg, elem->in_num, 0, buf, len);
-
- virtqueue_push(vq, elem, len);
- virtio_notify(VIRTIO_DEVICE(vser), vq);
- g_free(elem);
-
- return len;
-}
-
-static size_t send_control_event(VirtIOSerial *vser, uint32_t port_id,
- uint16_t event, uint16_t value)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(vser);
- struct virtio_console_control cpkt;
-
- virtio_stl_p(vdev, &cpkt.id, port_id);
- virtio_stw_p(vdev, &cpkt.event, event);
- virtio_stw_p(vdev, &cpkt.value, value);
-
- trace_virtio_serial_send_control_event(port_id, event, value);
- return send_control_msg(vser, &cpkt, sizeof(cpkt));
-}
-
-/* Functions for use inside qemu to open and read from/write to ports */
-int virtio_serial_open(VirtIOSerialPort *port)
-{
- /* Don't allow opening an already-open port */
- if (port->host_connected) {
- return 0;
- }
- /* Send port open notification to the guest */
- port->host_connected = true;
- send_control_event(port->vser, port->id, VIRTIO_CONSOLE_PORT_OPEN, 1);
-
- return 0;
-}
-
-int virtio_serial_close(VirtIOSerialPort *port)
-{
- port->host_connected = false;
- /*
- * If there's any data the guest sent which the app didn't
- * consume, reset the throttling flag and discard the data.
- */
- port->throttled = false;
- discard_vq_data(port->ovq, VIRTIO_DEVICE(port->vser));
-
- send_control_event(port->vser, port->id, VIRTIO_CONSOLE_PORT_OPEN, 0);
-
- return 0;
-}
-
-/* Individual ports/apps call this function to write to the guest. */
-ssize_t virtio_serial_write(VirtIOSerialPort *port, const uint8_t *buf,
- size_t size)
-{
- if (!port || !port->host_connected || !port->guest_connected) {
- return 0;
- }
- return write_to_port(port, buf, size);
-}
-
-/*
- * Readiness of the guest to accept data on a port.
- * Returns max. data the guest can receive
- */
-size_t virtio_serial_guest_ready(VirtIOSerialPort *port)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(port->vser);
- VirtQueue *vq = port->ivq;
- unsigned int bytes;
-
- if (!virtio_queue_ready(vq) ||
- !(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK) ||
- virtio_queue_empty(vq)) {
- return 0;
- }
- if (use_multiport(port->vser) && !port->guest_connected) {
- return 0;
- }
- virtqueue_get_avail_bytes(vq, &bytes, NULL, 4096, 0);
- return bytes;
-}
-
-static void flush_queued_data_bh(void *opaque)
-{
- VirtIOSerialPort *port = opaque;
-
- flush_queued_data(port);
-}
-
-void virtio_serial_throttle_port(VirtIOSerialPort *port, bool throttle)
-{
- if (!port) {
- return;
- }
-
- trace_virtio_serial_throttle_port(port->id, throttle);
- port->throttled = throttle;
- if (throttle) {
- return;
- }
- qemu_bh_schedule(port->bh);
-}
-
-/* Guest wants to notify us of some event */
-static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(vser);
- struct VirtIOSerialPort *port;
- VirtIOSerialPortClass *vsc;
- struct virtio_console_control cpkt, *gcpkt;
- uint8_t *buffer;
- size_t buffer_len;
-
- gcpkt = buf;
-
- if (len < sizeof(cpkt)) {
- /* The guest sent an invalid control packet */
- return;
- }
-
- cpkt.event = virtio_lduw_p(vdev, &gcpkt->event);
- cpkt.value = virtio_lduw_p(vdev, &gcpkt->value);
-
- trace_virtio_serial_handle_control_message(cpkt.event, cpkt.value);
-
- if (cpkt.event == VIRTIO_CONSOLE_DEVICE_READY) {
- if (!cpkt.value) {
- error_report("virtio-serial-bus: Guest failure in adding device %s",
- vser->bus.qbus.name);
- return;
- }
- /*
- * The device is up, we can now tell the device about all the
- * ports we have here.
- */
- QTAILQ_FOREACH(port, &vser->ports, next) {
- send_control_event(vser, port->id, VIRTIO_CONSOLE_PORT_ADD, 1);
- }
- return;
- }
-
- port = find_port_by_id(vser, virtio_ldl_p(vdev, &gcpkt->id));
- if (!port) {
- error_report("virtio-serial-bus: Unexpected port id %u for device %s",
- virtio_ldl_p(vdev, &gcpkt->id), vser->bus.qbus.name);
- return;
- }
-
- trace_virtio_serial_handle_control_message_port(port->id);
-
- vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
-
- switch(cpkt.event) {
- case VIRTIO_CONSOLE_PORT_READY:
- if (!cpkt.value) {
- error_report("virtio-serial-bus: Guest failure in adding port %u for device %s",
- port->id, vser->bus.qbus.name);
- break;
- }
- /*
- * Now that we know the guest asked for the port name, we're
- * sure the guest has initialised whatever state is necessary
- * for this port. Now's a good time to let the guest know if
- * this port is a console port so that the guest can hook it
- * up to hvc.
- */
- if (vsc->is_console) {
- send_control_event(vser, port->id, VIRTIO_CONSOLE_CONSOLE_PORT, 1);
- }
-
- if (port->name) {
- virtio_stl_p(vdev, &cpkt.id, port->id);
- virtio_stw_p(vdev, &cpkt.event, VIRTIO_CONSOLE_PORT_NAME);
- virtio_stw_p(vdev, &cpkt.value, 1);
-
- buffer_len = sizeof(cpkt) + strlen(port->name) + 1;
- buffer = g_malloc(buffer_len);
-
- memcpy(buffer, &cpkt, sizeof(cpkt));
- memcpy(buffer + sizeof(cpkt), port->name, strlen(port->name));
- buffer[buffer_len - 1] = 0;
-
- send_control_msg(vser, buffer, buffer_len);
- g_free(buffer);
- }
-
- if (port->host_connected) {
- send_control_event(vser, port->id, VIRTIO_CONSOLE_PORT_OPEN, 1);
- }
-
- /*
- * When the guest has asked us for this information it means
- * the guest is all setup and has its virtqueues
- * initialised. If some app is interested in knowing about
- * this event, let it know.
- */
- if (vsc->guest_ready) {
- vsc->guest_ready(port);
- }
- break;
-
- case VIRTIO_CONSOLE_PORT_OPEN:
- port->guest_connected = cpkt.value;
- if (vsc->set_guest_connected) {
- /* Send the guest opened notification if an app is interested */
- vsc->set_guest_connected(port, cpkt.value);
- }
- break;
- }
-}
-
-static void control_in(VirtIODevice *vdev, VirtQueue *vq)
-{
-}
-
-static void control_out(VirtIODevice *vdev, VirtQueue *vq)
-{
- VirtQueueElement *elem;
- VirtIOSerial *vser;
- uint8_t *buf;
- size_t len;
-
- vser = VIRTIO_SERIAL(vdev);
-
- len = 0;
- buf = NULL;
- for (;;) {
- size_t cur_len;
-
- elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
- if (!elem) {
- break;
- }
-
- cur_len = iov_size(elem->out_sg, elem->out_num);
- /*
- * Allocate a new buf only if we didn't have one previously or
- * if the size of the buf differs
- */
- if (cur_len > len) {
- g_free(buf);
-
- buf = g_malloc(cur_len);
- len = cur_len;
- }
- iov_to_buf(elem->out_sg, elem->out_num, 0, buf, cur_len);
-
- handle_control_message(vser, buf, cur_len);
- virtqueue_push(vq, elem, 0);
- g_free(elem);
- }
- g_free(buf);
- virtio_notify(vdev, vq);
-}
-
-/* Guest wrote something to some port. */
-static void handle_output(VirtIODevice *vdev, VirtQueue *vq)
-{
- VirtIOSerial *vser;
- VirtIOSerialPort *port;
-
- vser = VIRTIO_SERIAL(vdev);
- port = find_port_by_vq(vser, vq);
-
- if (!port || !port->host_connected) {
- discard_vq_data(vq, vdev);
- return;
- }
-
- if (!port->throttled) {
- do_flush_queued_data(port, vq, vdev);
- return;
- }
-}
-
-static void handle_input(VirtIODevice *vdev, VirtQueue *vq)
-{
- /*
- * Users of virtio-serial would like to know when guest becomes
- * writable again -- i.e. if a vq had stuff queued up and the
- * guest wasn't reading at all, the host would not be able to
- * write to the vq anymore. Once the guest reads off something,
- * we can start queueing things up again. However, this call is
- * made for each buffer addition by the guest -- even though free
- * buffers existed prior to the current buffer addition. This is
- * done so as not to maintain previous state, which will need
- * additional live-migration-related changes.
- */
- VirtIOSerial *vser;
- VirtIOSerialPort *port;
- VirtIOSerialPortClass *vsc;
-
- vser = VIRTIO_SERIAL(vdev);
- port = find_port_by_vq(vser, vq);
-
- if (!port) {
- return;
- }
- vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
-
- /*
- * If guest_connected is false, this call is being made by the
- * early-boot queueing up of descriptors, which is just noise for
- * the host apps -- don't disturb them in that case.
- */
- if (port->guest_connected && port->host_connected && vsc->guest_writable) {
- vsc->guest_writable(port);
- }
-}
-
-static uint64_t get_features(VirtIODevice *vdev, uint64_t features,
- Error **errp)
-{
- VirtIOSerial *vser;
-
- vser = VIRTIO_SERIAL(vdev);
-
- if (vser->bus.max_nr_ports > 1) {
- virtio_add_feature(&features, VIRTIO_CONSOLE_F_MULTIPORT);
- }
- return features;
-}
-
-/* Guest requested config info */
-static void get_config(VirtIODevice *vdev, uint8_t *config_data)
-{
- VirtIOSerial *vser = VIRTIO_SERIAL(vdev);
- struct virtio_console_config *config =
- (struct virtio_console_config *)config_data;
-
- config->cols = 0;
- config->rows = 0;
- config->max_nr_ports = virtio_tswap32(vdev,
- vser->serial.max_virtserial_ports);
-}
-
-static void guest_reset(VirtIOSerial *vser)
-{
- VirtIOSerialPort *port;
- VirtIOSerialPortClass *vsc;
-
- QTAILQ_FOREACH(port, &vser->ports, next) {
- vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
- if (port->guest_connected) {
- port->guest_connected = false;
- if (vsc->set_guest_connected) {
- vsc->set_guest_connected(port, false);
- }
- }
- }
-}
-
-static void set_status(VirtIODevice *vdev, uint8_t status)
-{
- VirtIOSerial *vser;
- VirtIOSerialPort *port;
-
- vser = VIRTIO_SERIAL(vdev);
- port = find_port_by_id(vser, 0);
-
- if (port && !use_multiport(port->vser)
- && (status & VIRTIO_CONFIG_S_DRIVER_OK)) {
- /*
- * Non-multiport guests won't be able to tell us guest
- * open/close status. Such guests can only have a port at id
- * 0, so set guest_connected for such ports as soon as guest
- * is up.
- */
- port->guest_connected = true;
- }
- if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) {
- guest_reset(vser);
- }
-}
-
-static void vser_reset(VirtIODevice *vdev)
-{
- VirtIOSerial *vser;
-
- vser = VIRTIO_SERIAL(vdev);
- guest_reset(vser);
-}
-
-static void virtio_serial_save(QEMUFile *f, void *opaque)
-{
- /* The virtio device */
- virtio_save(VIRTIO_DEVICE(opaque), f);
-}
-
-static void virtio_serial_save_device(VirtIODevice *vdev, QEMUFile *f)
-{
- VirtIOSerial *s = VIRTIO_SERIAL(vdev);
- VirtIOSerialPort *port;
- uint32_t nr_active_ports;
- unsigned int i, max_nr_ports;
- struct virtio_console_config config;
-
- /* The config space (ignored on the far end in current versions) */
- get_config(vdev, (uint8_t *)&config);
- qemu_put_be16s(f, &config.cols);
- qemu_put_be16s(f, &config.rows);
- qemu_put_be32s(f, &config.max_nr_ports);
-
- /* The ports map */
- max_nr_ports = s->serial.max_virtserial_ports;
- for (i = 0; i < (max_nr_ports + 31) / 32; i++) {
- qemu_put_be32s(f, &s->ports_map[i]);
- }
-
- /* Ports */
-
- nr_active_ports = 0;
- QTAILQ_FOREACH(port, &s->ports, next) {
- nr_active_ports++;
- }
-
- qemu_put_be32s(f, &nr_active_ports);
-
- /*
- * Items in struct VirtIOSerialPort.
- */
- QTAILQ_FOREACH(port, &s->ports, next) {
- uint32_t elem_popped;
-
- qemu_put_be32s(f, &port->id);
- qemu_put_byte(f, port->guest_connected);
- qemu_put_byte(f, port->host_connected);
-
- elem_popped = 0;
- if (port->elem) {
- elem_popped = 1;
- }
- qemu_put_be32s(f, &elem_popped);
- if (elem_popped) {
- qemu_put_be32s(f, &port->iov_idx);
- qemu_put_be64s(f, &port->iov_offset);
- qemu_put_virtqueue_element(f, port->elem);
- }
- }
-}
-
-static void virtio_serial_post_load_timer_cb(void *opaque)
-{
- uint32_t i;
- VirtIOSerial *s = VIRTIO_SERIAL(opaque);
- VirtIOSerialPort *port;
- uint8_t host_connected;
- VirtIOSerialPortClass *vsc;
-
- if (!s->post_load) {
- return;
- }
- for (i = 0 ; i < s->post_load->nr_active_ports; ++i) {
- port = s->post_load->connected[i].port;
- host_connected = s->post_load->connected[i].host_connected;
- if (host_connected != port->host_connected) {
- /*
- * We have to let the guest know of the host connection
- * status change
- */
- send_control_event(s, port->id, VIRTIO_CONSOLE_PORT_OPEN,
- port->host_connected);
- }
- vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
- if (vsc->set_guest_connected) {
- vsc->set_guest_connected(port, port->guest_connected);
- }
- }
- g_free(s->post_load->connected);
- timer_free(s->post_load->timer);
- g_free(s->post_load);
- s->post_load = NULL;
-}
-
-static int fetch_active_ports_list(QEMUFile *f, int version_id,
- VirtIOSerial *s, uint32_t nr_active_ports)
-{
- uint32_t i;
-
- s->post_load = g_malloc0(sizeof(*s->post_load));
- s->post_load->nr_active_ports = nr_active_ports;
- s->post_load->connected =
- g_malloc0(sizeof(*s->post_load->connected) * nr_active_ports);
-
- s->post_load->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
- virtio_serial_post_load_timer_cb,
- s);
-
- /* Items in struct VirtIOSerialPort */
- for (i = 0; i < nr_active_ports; i++) {
- VirtIOSerialPort *port;
- uint32_t id;
-
- id = qemu_get_be32(f);
- port = find_port_by_id(s, id);
- if (!port) {
- return -EINVAL;
- }
-
- port->guest_connected = qemu_get_byte(f);
- s->post_load->connected[i].port = port;
- s->post_load->connected[i].host_connected = qemu_get_byte(f);
-
- if (version_id > 2) {
- uint32_t elem_popped;
-
- qemu_get_be32s(f, &elem_popped);
- if (elem_popped) {
- qemu_get_be32s(f, &port->iov_idx);
- qemu_get_be64s(f, &port->iov_offset);
-
- port->elem =
- qemu_get_virtqueue_element(f, sizeof(VirtQueueElement));
-
- /*
- * Port was throttled on source machine. Let's
- * unthrottle it here so data starts flowing again.
- */
- virtio_serial_throttle_port(port, false);
- }
- }
- }
- timer_mod(s->post_load->timer, 1);
- return 0;
-}
-
-static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
-{
- if (version_id > 3) {
- return -EINVAL;
- }
-
- /* The virtio device */
- return virtio_load(VIRTIO_DEVICE(opaque), f, version_id);
-}
-
-static int virtio_serial_load_device(VirtIODevice *vdev, QEMUFile *f,
- int version_id)
-{
- VirtIOSerial *s = VIRTIO_SERIAL(vdev);
- uint32_t max_nr_ports, nr_active_ports, ports_map;
- unsigned int i;
- int ret;
- uint32_t tmp;
-
- if (version_id < 2) {
- return 0;
- }
-
- /* Unused */
- qemu_get_be16s(f, (uint16_t *) &tmp);
- qemu_get_be16s(f, (uint16_t *) &tmp);
- qemu_get_be32s(f, &tmp);
-
- max_nr_ports = s->serial.max_virtserial_ports;
- for (i = 0; i < (max_nr_ports + 31) / 32; i++) {
- qemu_get_be32s(f, &ports_map);
-
- if (ports_map != s->ports_map[i]) {
- /*
- * Ports active on source and destination don't
- * match. Fail migration.
- */
- return -EINVAL;
- }
- }
-
- qemu_get_be32s(f, &nr_active_ports);
-
- if (nr_active_ports) {
- ret = fetch_active_ports_list(f, version_id, s, nr_active_ports);
- if (ret) {
- return ret;
- }
- }
- return 0;
-}
-
-static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent);
-
-static Property virtser_props[] = {
- DEFINE_PROP_UINT32("nr", VirtIOSerialPort, id, VIRTIO_CONSOLE_BAD_ID),
- DEFINE_PROP_STRING("name", VirtIOSerialPort, name),
- DEFINE_PROP_END_OF_LIST()
-};
-
-#define TYPE_VIRTIO_SERIAL_BUS "virtio-serial-bus"
-#define VIRTIO_SERIAL_BUS(obj) \
- OBJECT_CHECK(VirtIOSerialBus, (obj), TYPE_VIRTIO_SERIAL_BUS)
-
-static void virtser_bus_class_init(ObjectClass *klass, void *data)
-{
- BusClass *k = BUS_CLASS(klass);
- k->print_dev = virtser_bus_dev_print;
-}
-
-static const TypeInfo virtser_bus_info = {
- .name = TYPE_VIRTIO_SERIAL_BUS,
- .parent = TYPE_BUS,
- .instance_size = sizeof(VirtIOSerialBus),
- .class_init = virtser_bus_class_init,
-};
-
-static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
-{
- VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(qdev);
-
- monitor_printf(mon, "%*sport %d, guest %s, host %s, throttle %s\n",
- indent, "", port->id,
- port->guest_connected ? "on" : "off",
- port->host_connected ? "on" : "off",
- port->throttled ? "on" : "off");
-}
-
-/* This function is only used if a port id is not provided by the user */
-static uint32_t find_free_port_id(VirtIOSerial *vser)
-{
- unsigned int i, max_nr_ports;
-
- max_nr_ports = vser->serial.max_virtserial_ports;
- for (i = 0; i < (max_nr_ports + 31) / 32; i++) {
- uint32_t map, zeroes;
-
- map = vser->ports_map[i];
- zeroes = ctz32(~map);
- if (zeroes != 32) {
- return zeroes + i * 32;
- }
- }
- return VIRTIO_CONSOLE_BAD_ID;
-}
-
-static void mark_port_added(VirtIOSerial *vser, uint32_t port_id)
-{
- unsigned int i;
-
- i = port_id / 32;
- vser->ports_map[i] |= 1U << (port_id % 32);
-}
-
-static void add_port(VirtIOSerial *vser, uint32_t port_id)
-{
- mark_port_added(vser, port_id);
- send_control_event(vser, port_id, VIRTIO_CONSOLE_PORT_ADD, 1);
-}
-
-static void remove_port(VirtIOSerial *vser, uint32_t port_id)
-{
- VirtIOSerialPort *port;
-
- /*
- * Don't mark port 0 removed -- we explicitly reserve it for
- * backward compat with older guests, ensure a virtconsole device
- * unplug retains the reservation.
- */
- if (port_id) {
- unsigned int i;
-
- i = port_id / 32;
- vser->ports_map[i] &= ~(1U << (port_id % 32));
- }
-
- port = find_port_by_id(vser, port_id);
- /*
- * This function is only called from qdev's unplug callback; if we
- * get a NULL port here, we're in trouble.
- */
- assert(port);
-
- /* Flush out any unconsumed buffers first */
- discard_vq_data(port->ovq, VIRTIO_DEVICE(port->vser));
-
- send_control_event(vser, port->id, VIRTIO_CONSOLE_PORT_REMOVE, 1);
-}
-
-static void virtser_port_device_realize(DeviceState *dev, Error **errp)
-{
- VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(dev);
- VirtIOSerialPortClass *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
- VirtIOSerialBus *bus = VIRTIO_SERIAL_BUS(qdev_get_parent_bus(dev));
- int max_nr_ports;
- bool plugging_port0;
- Error *err = NULL;
-
- port->vser = bus->vser;
- port->bh = qemu_bh_new(flush_queued_data_bh, port);
-
- assert(vsc->have_data);
-
- /*
- * Is the first console port we're seeing? If so, put it up at
- * location 0. This is done for backward compatibility (old
- * kernel, new qemu).
- */
- plugging_port0 = vsc->is_console && !find_port_by_id(port->vser, 0);
-
- if (find_port_by_id(port->vser, port->id)) {
- error_setg(errp, "virtio-serial-bus: A port already exists at id %u",
- port->id);
- return;
- }
-
- if (port->name != NULL && find_port_by_name(port->name)) {
- error_setg(errp, "virtio-serial-bus: A port already exists by name %s",
- port->name);
- return;
- }
-
- if (port->id == VIRTIO_CONSOLE_BAD_ID) {
- if (plugging_port0) {
- port->id = 0;
- } else {
- port->id = find_free_port_id(port->vser);
- if (port->id == VIRTIO_CONSOLE_BAD_ID) {
- error_setg(errp, "virtio-serial-bus: Maximum port limit for "
- "this device reached");
- return;
- }
- }
- }
-
- max_nr_ports = port->vser->serial.max_virtserial_ports;
- if (port->id >= max_nr_ports) {
- error_setg(errp, "virtio-serial-bus: Out-of-range port id specified, "
- "max. allowed: %u", max_nr_ports - 1);
- return;
- }
-
- vsc->realize(dev, &err);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
-
- port->elem = NULL;
-}
-
-static void virtser_port_device_plug(HotplugHandler *hotplug_dev,
- DeviceState *dev, Error **errp)
-{
- VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(dev);
-
- QTAILQ_INSERT_TAIL(&port->vser->ports, port, next);
- port->ivq = port->vser->ivqs[port->id];
- port->ovq = port->vser->ovqs[port->id];
-
- add_port(port->vser, port->id);
-
- /* Send an update to the guest about this new port added */
- virtio_notify_config(VIRTIO_DEVICE(hotplug_dev));
-}
-
-static void virtser_port_device_unrealize(DeviceState *dev, Error **errp)
-{
- VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(dev);
- VirtIOSerialPortClass *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(dev);
- VirtIOSerial *vser = port->vser;
-
- qemu_bh_delete(port->bh);
- remove_port(port->vser, port->id);
-
- QTAILQ_REMOVE(&vser->ports, port, next);
-
- if (vsc->unrealize) {
- vsc->unrealize(dev, errp);
- }
-}
-
-static void virtio_serial_device_realize(DeviceState *dev, Error **errp)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
- VirtIOSerial *vser = VIRTIO_SERIAL(dev);
- uint32_t i, max_supported_ports;
-
- if (!vser->serial.max_virtserial_ports) {
- error_setg(errp, "Maximum number of serial ports not specified");
- return;
- }
-
- /* Each port takes 2 queues, and one pair is for the control queue */
- max_supported_ports = VIRTIO_QUEUE_MAX / 2 - 1;
-
- if (vser->serial.max_virtserial_ports > max_supported_ports) {
- error_setg(errp, "maximum ports supported: %u", max_supported_ports);
- return;
- }
-
- /* We don't support emergency write, skip it for now. */
- /* TODO: cleaner fix, depending on host features. */
- virtio_init(vdev, "virtio-serial", VIRTIO_ID_CONSOLE,
- offsetof(struct virtio_console_config, emerg_wr));
-
- /* Spawn a new virtio-serial bus on which the ports will ride as devices */
- qbus_create_inplace(&vser->bus, sizeof(vser->bus), TYPE_VIRTIO_SERIAL_BUS,
- dev, vdev->bus_name);
- qbus_set_hotplug_handler(BUS(&vser->bus), DEVICE(vser), errp);
- vser->bus.vser = vser;
- QTAILQ_INIT(&vser->ports);
-
- vser->bus.max_nr_ports = vser->serial.max_virtserial_ports;
- vser->ivqs = g_malloc(vser->serial.max_virtserial_ports
- * sizeof(VirtQueue *));
- vser->ovqs = g_malloc(vser->serial.max_virtserial_ports
- * sizeof(VirtQueue *));
-
- /* Add a queue for host to guest transfers for port 0 (backward compat) */
- vser->ivqs[0] = virtio_add_queue(vdev, 128, handle_input);
- /* Add a queue for guest to host transfers for port 0 (backward compat) */
- vser->ovqs[0] = virtio_add_queue(vdev, 128, handle_output);
-
- /* TODO: host to guest notifications can get dropped
- * if the queue fills up. Implement queueing in host,
- * this might also make it possible to reduce the control
- * queue size: as guest preposts buffers there,
- * this will save 4Kbyte of guest memory per entry. */
-
- /* control queue: host to guest */
- vser->c_ivq = virtio_add_queue(vdev, 32, control_in);
- /* control queue: guest to host */
- vser->c_ovq = virtio_add_queue(vdev, 32, control_out);
-
- for (i = 1; i < vser->bus.max_nr_ports; i++) {
- /* Add a per-port queue for host to guest transfers */
- vser->ivqs[i] = virtio_add_queue(vdev, 128, handle_input);
- /* Add a per-per queue for guest to host transfers */
- vser->ovqs[i] = virtio_add_queue(vdev, 128, handle_output);
- }
-
- vser->ports_map = g_malloc0(((vser->serial.max_virtserial_ports + 31) / 32)
- * sizeof(vser->ports_map[0]));
- /*
- * Reserve location 0 for a console port for backward compat
- * (old kernel, new qemu)
- */
- mark_port_added(vser, 0);
-
- vser->post_load = NULL;
-
- /*
- * Register for the savevm section with the virtio-console name
- * to preserve backward compat
- */
- register_savevm(dev, "virtio-console", -1, 3, virtio_serial_save,
- virtio_serial_load, vser);
-
- QLIST_INSERT_HEAD(&vserdevices.devices, vser, next);
-}
-
-static void virtio_serial_port_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *k = DEVICE_CLASS(klass);
-
- set_bit(DEVICE_CATEGORY_INPUT, k->categories);
- k->bus_type = TYPE_VIRTIO_SERIAL_BUS;
- k->realize = virtser_port_device_realize;
- k->unrealize = virtser_port_device_unrealize;
- k->props = virtser_props;
-}
-
-static const TypeInfo virtio_serial_port_type_info = {
- .name = TYPE_VIRTIO_SERIAL_PORT,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(VirtIOSerialPort),
- .abstract = true,
- .class_size = sizeof(VirtIOSerialPortClass),
- .class_init = virtio_serial_port_class_init,
-};
-
-static void virtio_serial_device_unrealize(DeviceState *dev, Error **errp)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
- VirtIOSerial *vser = VIRTIO_SERIAL(dev);
-
- QLIST_REMOVE(vser, next);
-
- unregister_savevm(dev, "virtio-console", vser);
-
- g_free(vser->ivqs);
- g_free(vser->ovqs);
- g_free(vser->ports_map);
- if (vser->post_load) {
- g_free(vser->post_load->connected);
- timer_del(vser->post_load->timer);
- timer_free(vser->post_load->timer);
- g_free(vser->post_load);
- }
- virtio_cleanup(vdev);
-}
-
-static Property virtio_serial_properties[] = {
- DEFINE_PROP_UINT32("max_ports", VirtIOSerial, serial.max_virtserial_ports,
- 31),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_serial_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
- HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
-
- QLIST_INIT(&vserdevices.devices);
-
- dc->props = virtio_serial_properties;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
- vdc->realize = virtio_serial_device_realize;
- vdc->unrealize = virtio_serial_device_unrealize;
- vdc->get_features = get_features;
- vdc->get_config = get_config;
- vdc->set_status = set_status;
- vdc->reset = vser_reset;
- vdc->save = virtio_serial_save_device;
- vdc->load = virtio_serial_load_device;
- hc->plug = virtser_port_device_plug;
- hc->unplug = qdev_simple_device_unplug_cb;
-}
-
-static const TypeInfo virtio_device_info = {
- .name = TYPE_VIRTIO_SERIAL,
- .parent = TYPE_VIRTIO_DEVICE,
- .instance_size = sizeof(VirtIOSerial),
- .class_init = virtio_serial_class_init,
- .interfaces = (InterfaceInfo[]) {
- { TYPE_HOTPLUG_HANDLER },
- { }
- }
-};
-
-static void virtio_serial_register_types(void)
-{
- type_register_static(&virtser_bus_info);
- type_register_static(&virtio_serial_port_type_info);
- type_register_static(&virtio_device_info);
-}
-
-type_init(virtio_serial_register_types)
diff --git a/qemu/hw/char/xen_console.c b/qemu/hw/char/xen_console.c
deleted file mode 100644
index cbf1dccbb..000000000
--- a/qemu/hw/char/xen_console.c
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- * Copyright (C) International Business Machines Corp., 2005
- * Author(s): Anthony Liguori <aliguori@us.ibm.com>
- *
- * Copyright (C) Red Hat 2007
- *
- * Xen Console
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; under version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include <sys/select.h>
-#include <termios.h>
-#include <sys/mman.h>
-
-#include "hw/hw.h"
-#include "sysemu/char.h"
-#include "hw/xen/xen_backend.h"
-
-#include <xen/io/console.h>
-
-struct buffer {
- uint8_t *data;
- size_t consumed;
- size_t size;
- size_t capacity;
- size_t max_capacity;
-};
-
-struct XenConsole {
- struct XenDevice xendev; /* must be first */
- struct buffer buffer;
- char console[XEN_BUFSIZE];
- int ring_ref;
- void *sring;
- CharDriverState *chr;
- int backlog;
-};
-
-static void buffer_append(struct XenConsole *con)
-{
- struct buffer *buffer = &con->buffer;
- XENCONS_RING_IDX cons, prod, size;
- struct xencons_interface *intf = con->sring;
-
- cons = intf->out_cons;
- prod = intf->out_prod;
- xen_mb();
-
- size = prod - cons;
- if ((size == 0) || (size > sizeof(intf->out)))
- return;
-
- if ((buffer->capacity - buffer->size) < size) {
- buffer->capacity += (size + 1024);
- buffer->data = g_realloc(buffer->data, buffer->capacity);
- }
-
- while (cons != prod)
- buffer->data[buffer->size++] = intf->out[
- MASK_XENCONS_IDX(cons++, intf->out)];
-
- xen_mb();
- intf->out_cons = cons;
- xen_be_send_notify(&con->xendev);
-
- if (buffer->max_capacity &&
- buffer->size > buffer->max_capacity) {
- /* Discard the middle of the data. */
-
- size_t over = buffer->size - buffer->max_capacity;
- uint8_t *maxpos = buffer->data + buffer->max_capacity;
-
- memmove(maxpos - over, maxpos, over);
- buffer->data = g_realloc(buffer->data, buffer->max_capacity);
- buffer->size = buffer->capacity = buffer->max_capacity;
-
- if (buffer->consumed > buffer->max_capacity - over)
- buffer->consumed = buffer->max_capacity - over;
- }
-}
-
-static void buffer_advance(struct buffer *buffer, size_t len)
-{
- buffer->consumed += len;
- if (buffer->consumed == buffer->size) {
- buffer->consumed = 0;
- buffer->size = 0;
- }
-}
-
-static int ring_free_bytes(struct XenConsole *con)
-{
- struct xencons_interface *intf = con->sring;
- XENCONS_RING_IDX cons, prod, space;
-
- cons = intf->in_cons;
- prod = intf->in_prod;
- xen_mb();
-
- space = prod - cons;
- if (space > sizeof(intf->in))
- return 0; /* ring is screwed: ignore it */
-
- return (sizeof(intf->in) - space);
-}
-
-static int xencons_can_receive(void *opaque)
-{
- struct XenConsole *con = opaque;
- return ring_free_bytes(con);
-}
-
-static void xencons_receive(void *opaque, const uint8_t *buf, int len)
-{
- struct XenConsole *con = opaque;
- struct xencons_interface *intf = con->sring;
- XENCONS_RING_IDX prod;
- int i, max;
-
- max = ring_free_bytes(con);
- /* The can_receive() func limits this, but check again anyway */
- if (max < len)
- len = max;
-
- prod = intf->in_prod;
- for (i = 0; i < len; i++) {
- intf->in[MASK_XENCONS_IDX(prod++, intf->in)] =
- buf[i];
- }
- xen_wmb();
- intf->in_prod = prod;
- xen_be_send_notify(&con->xendev);
-}
-
-static void xencons_send(struct XenConsole *con)
-{
- ssize_t len, size;
-
- size = con->buffer.size - con->buffer.consumed;
- if (con->chr)
- len = qemu_chr_fe_write(con->chr, con->buffer.data + con->buffer.consumed,
- size);
- else
- len = size;
- if (len < 1) {
- if (!con->backlog) {
- con->backlog = 1;
- xen_be_printf(&con->xendev, 1, "backlog piling up, nobody listening?\n");
- }
- } else {
- buffer_advance(&con->buffer, len);
- if (con->backlog && len == size) {
- con->backlog = 0;
- xen_be_printf(&con->xendev, 1, "backlog is gone\n");
- }
- }
-}
-
-/* -------------------------------------------------------------------- */
-
-static int con_init(struct XenDevice *xendev)
-{
- struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
- char *type, *dom, label[32];
- int ret = 0;
- const char *output;
-
- /* setup */
- dom = xs_get_domain_path(xenstore, con->xendev.dom);
- if (!xendev->dev) {
- snprintf(con->console, sizeof(con->console), "%s/console", dom);
- } else {
- snprintf(con->console, sizeof(con->console), "%s/device/console/%d", dom, xendev->dev);
- }
- free(dom);
-
- type = xenstore_read_str(con->console, "type");
- if (!type || strcmp(type, "ioemu") != 0) {
- xen_be_printf(xendev, 1, "not for me (type=%s)\n", type);
- ret = -1;
- goto out;
- }
-
- output = xenstore_read_str(con->console, "output");
-
- /* no Xen override, use qemu output device */
- if (output == NULL) {
- con->chr = serial_hds[con->xendev.dev];
- } else {
- snprintf(label, sizeof(label), "xencons%d", con->xendev.dev);
- con->chr = qemu_chr_new(label, output, NULL);
- }
-
- xenstore_store_pv_console_info(con->xendev.dev, con->chr);
-
-out:
- g_free(type);
- return ret;
-}
-
-static int con_initialise(struct XenDevice *xendev)
-{
- struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
- int limit;
-
- if (xenstore_read_int(con->console, "ring-ref", &con->ring_ref) == -1)
- return -1;
- if (xenstore_read_int(con->console, "port", &con->xendev.remote_port) == -1)
- return -1;
- if (xenstore_read_int(con->console, "limit", &limit) == 0)
- con->buffer.max_capacity = limit;
-
- if (!xendev->dev) {
- xen_pfn_t mfn = con->ring_ref;
- con->sring = xenforeignmemory_map(xen_fmem, con->xendev.dom,
- PROT_READ|PROT_WRITE,
- 1, &mfn, NULL);
- } else {
- con->sring = xengnttab_map_grant_ref(xendev->gnttabdev, con->xendev.dom,
- con->ring_ref,
- PROT_READ|PROT_WRITE);
- }
- if (!con->sring)
- return -1;
-
- xen_be_bind_evtchn(&con->xendev);
- if (con->chr) {
- if (qemu_chr_fe_claim(con->chr) == 0) {
- qemu_chr_add_handlers(con->chr, xencons_can_receive,
- xencons_receive, NULL, con);
- } else {
- xen_be_printf(xendev, 0,
- "xen_console_init error chardev %s already used\n",
- con->chr->label);
- con->chr = NULL;
- }
- }
-
- xen_be_printf(xendev, 1, "ring mfn %d, remote port %d, local port %d, limit %zd\n",
- con->ring_ref,
- con->xendev.remote_port,
- con->xendev.local_port,
- con->buffer.max_capacity);
- return 0;
-}
-
-static void con_disconnect(struct XenDevice *xendev)
-{
- struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
-
- if (con->chr) {
- qemu_chr_add_handlers(con->chr, NULL, NULL, NULL, NULL);
- qemu_chr_fe_release(con->chr);
- }
- xen_be_unbind_evtchn(&con->xendev);
-
- if (con->sring) {
- if (!xendev->dev) {
- xenforeignmemory_unmap(xen_fmem, con->sring, 1);
- } else {
- xengnttab_unmap(xendev->gnttabdev, con->sring, 1);
- }
- con->sring = NULL;
- }
-}
-
-static void con_event(struct XenDevice *xendev)
-{
- struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
-
- buffer_append(con);
- if (con->buffer.size - con->buffer.consumed)
- xencons_send(con);
-}
-
-/* -------------------------------------------------------------------- */
-
-struct XenDevOps xen_console_ops = {
- .size = sizeof(struct XenConsole),
- .flags = DEVOPS_FLAG_IGNORE_STATE|DEVOPS_FLAG_NEED_GNTDEV,
- .init = con_init,
- .initialise = con_initialise,
- .event = con_event,
- .disconnect = con_disconnect,
-};
diff --git a/qemu/hw/char/xilinx_uartlite.c b/qemu/hw/char/xilinx_uartlite.c
deleted file mode 100644
index 911af4a0d..000000000
--- a/qemu/hw/char/xilinx_uartlite.c
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * QEMU model of Xilinx uartlite.
- *
- * Copyright (c) 2009 Edgar E. Iglesias.
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "sysemu/char.h"
-
-#define DUART(x)
-
-#define R_RX 0
-#define R_TX 1
-#define R_STATUS 2
-#define R_CTRL 3
-#define R_MAX 4
-
-#define STATUS_RXVALID 0x01
-#define STATUS_RXFULL 0x02
-#define STATUS_TXEMPTY 0x04
-#define STATUS_TXFULL 0x08
-#define STATUS_IE 0x10
-#define STATUS_OVERRUN 0x20
-#define STATUS_FRAME 0x40
-#define STATUS_PARITY 0x80
-
-#define CONTROL_RST_TX 0x01
-#define CONTROL_RST_RX 0x02
-#define CONTROL_IE 0x10
-
-#define TYPE_XILINX_UARTLITE "xlnx.xps-uartlite"
-#define XILINX_UARTLITE(obj) \
- OBJECT_CHECK(XilinxUARTLite, (obj), TYPE_XILINX_UARTLITE)
-
-typedef struct XilinxUARTLite {
- SysBusDevice parent_obj;
-
- MemoryRegion mmio;
- CharDriverState *chr;
- qemu_irq irq;
-
- uint8_t rx_fifo[8];
- unsigned int rx_fifo_pos;
- unsigned int rx_fifo_len;
-
- uint32_t regs[R_MAX];
-} XilinxUARTLite;
-
-static void uart_update_irq(XilinxUARTLite *s)
-{
- unsigned int irq;
-
- if (s->rx_fifo_len)
- s->regs[R_STATUS] |= STATUS_IE;
-
- irq = (s->regs[R_STATUS] & STATUS_IE) && (s->regs[R_CTRL] & CONTROL_IE);
- qemu_set_irq(s->irq, irq);
-}
-
-static void uart_update_status(XilinxUARTLite *s)
-{
- uint32_t r;
-
- r = s->regs[R_STATUS];
- r &= ~7;
- r |= 1 << 2; /* Tx fifo is always empty. We are fast :) */
- r |= (s->rx_fifo_len == sizeof (s->rx_fifo)) << 1;
- r |= (!!s->rx_fifo_len);
- s->regs[R_STATUS] = r;
-}
-
-static void xilinx_uartlite_reset(DeviceState *dev)
-{
- uart_update_status(XILINX_UARTLITE(dev));
-}
-
-static uint64_t
-uart_read(void *opaque, hwaddr addr, unsigned int size)
-{
- XilinxUARTLite *s = opaque;
- uint32_t r = 0;
- addr >>= 2;
- switch (addr)
- {
- case R_RX:
- r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & 7];
- if (s->rx_fifo_len)
- s->rx_fifo_len--;
- uart_update_status(s);
- uart_update_irq(s);
- qemu_chr_accept_input(s->chr);
- break;
-
- default:
- if (addr < ARRAY_SIZE(s->regs))
- r = s->regs[addr];
- DUART(qemu_log("%s addr=%x v=%x\n", __func__, addr, r));
- break;
- }
- return r;
-}
-
-static void
-uart_write(void *opaque, hwaddr addr,
- uint64_t val64, unsigned int size)
-{
- XilinxUARTLite *s = opaque;
- uint32_t value = val64;
- unsigned char ch = value;
-
- addr >>= 2;
- switch (addr)
- {
- case R_STATUS:
- hw_error("write to UART STATUS?\n");
- break;
-
- case R_CTRL:
- if (value & CONTROL_RST_RX) {
- s->rx_fifo_pos = 0;
- s->rx_fifo_len = 0;
- }
- s->regs[addr] = value;
- break;
-
- case R_TX:
- if (s->chr)
- qemu_chr_fe_write(s->chr, &ch, 1);
-
- s->regs[addr] = value;
-
- /* hax. */
- s->regs[R_STATUS] |= STATUS_IE;
- break;
-
- default:
- DUART(printf("%s addr=%x v=%x\n", __func__, addr, value));
- if (addr < ARRAY_SIZE(s->regs))
- s->regs[addr] = value;
- break;
- }
- uart_update_status(s);
- uart_update_irq(s);
-}
-
-static const MemoryRegionOps uart_ops = {
- .read = uart_read,
- .write = uart_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 1,
- .max_access_size = 4
- }
-};
-
-static void uart_rx(void *opaque, const uint8_t *buf, int size)
-{
- XilinxUARTLite *s = opaque;
-
- /* Got a byte. */
- if (s->rx_fifo_len >= 8) {
- printf("WARNING: UART dropped char.\n");
- return;
- }
- s->rx_fifo[s->rx_fifo_pos] = *buf;
- s->rx_fifo_pos++;
- s->rx_fifo_pos &= 0x7;
- s->rx_fifo_len++;
-
- uart_update_status(s);
- uart_update_irq(s);
-}
-
-static int uart_can_rx(void *opaque)
-{
- XilinxUARTLite *s = opaque;
-
- return s->rx_fifo_len < sizeof(s->rx_fifo);
-}
-
-static void uart_event(void *opaque, int event)
-{
-
-}
-
-static void xilinx_uartlite_realize(DeviceState *dev, Error **errp)
-{
- XilinxUARTLite *s = XILINX_UARTLITE(dev);
-
- /* FIXME use a qdev chardev prop instead of qemu_char_get_next_serial() */
- s->chr = qemu_char_get_next_serial();
- if (s->chr)
- qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
-}
-
-static void xilinx_uartlite_init(Object *obj)
-{
- XilinxUARTLite *s = XILINX_UARTLITE(obj);
-
- sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
-
- memory_region_init_io(&s->mmio, obj, &uart_ops, s,
- "xlnx.xps-uartlite", R_MAX * 4);
- sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
-}
-
-static void xilinx_uartlite_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->reset = xilinx_uartlite_reset;
- dc->realize = xilinx_uartlite_realize;
- /* Reason: realize() method uses qemu_char_get_next_serial() */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo xilinx_uartlite_info = {
- .name = TYPE_XILINX_UARTLITE,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(XilinxUARTLite),
- .instance_init = xilinx_uartlite_init,
- .class_init = xilinx_uartlite_class_init,
-};
-
-static void xilinx_uart_register_types(void)
-{
- type_register_static(&xilinx_uartlite_info);
-}
-
-type_init(xilinx_uart_register_types)
diff --git a/qemu/hw/core/Makefile.objs b/qemu/hw/core/Makefile.objs
deleted file mode 100644
index abb3560be..000000000
--- a/qemu/hw/core/Makefile.objs
+++ /dev/null
@@ -1,17 +0,0 @@
-# core qdev-related obj files, also used by *-user:
-common-obj-y += qdev.o qdev-properties.o
-common-obj-y += fw-path-provider.o
-# irq.o needed for qdev GPIO handling:
-common-obj-y += irq.o
-common-obj-y += hotplug.o
-common-obj-y += nmi.o
-
-common-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o
-common-obj-$(CONFIG_XILINX_AXI) += stream.o
-common-obj-$(CONFIG_PTIMER) += ptimer.o
-common-obj-$(CONFIG_SOFTMMU) += sysbus.o
-common-obj-$(CONFIG_SOFTMMU) += machine.o
-common-obj-$(CONFIG_SOFTMMU) += null-machine.o
-common-obj-$(CONFIG_SOFTMMU) += loader.o
-common-obj-$(CONFIG_SOFTMMU) += qdev-properties-system.o
-common-obj-$(CONFIG_PLATFORM_BUS) += platform-bus.o
diff --git a/qemu/hw/core/empty_slot.c b/qemu/hw/core/empty_slot.c
deleted file mode 100644
index c1b9c2b10..000000000
--- a/qemu/hw/core/empty_slot.c
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * QEMU Empty Slot
- *
- * The empty_slot device emulates known to a bus but not connected devices.
- *
- * Copyright (c) 2010 Artyom Tarasenko
- *
- * This code is licensed under the GNU GPL v2 or (at your option) any later
- * version.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "hw/empty_slot.h"
-
-//#define DEBUG_EMPTY_SLOT
-
-#ifdef DEBUG_EMPTY_SLOT
-#define DPRINTF(fmt, ...) \
- do { printf("empty_slot: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while (0)
-#endif
-
-#define TYPE_EMPTY_SLOT "empty_slot"
-#define EMPTY_SLOT(obj) OBJECT_CHECK(EmptySlot, (obj), TYPE_EMPTY_SLOT)
-
-typedef struct EmptySlot {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- uint64_t size;
-} EmptySlot;
-
-static uint64_t empty_slot_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- DPRINTF("read from " TARGET_FMT_plx "\n", addr);
- return 0;
-}
-
-static void empty_slot_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- DPRINTF("write 0x%x to " TARGET_FMT_plx "\n", (unsigned)val, addr);
-}
-
-static const MemoryRegionOps empty_slot_ops = {
- .read = empty_slot_read,
- .write = empty_slot_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-void empty_slot_init(hwaddr addr, uint64_t slot_size)
-{
- if (slot_size > 0) {
- /* Only empty slots larger than 0 byte need handling. */
- DeviceState *dev;
- SysBusDevice *s;
- EmptySlot *e;
-
- dev = qdev_create(NULL, TYPE_EMPTY_SLOT);
- s = SYS_BUS_DEVICE(dev);
- e = EMPTY_SLOT(dev);
- e->size = slot_size;
-
- qdev_init_nofail(dev);
-
- sysbus_mmio_map(s, 0, addr);
- }
-}
-
-static int empty_slot_init1(SysBusDevice *dev)
-{
- EmptySlot *s = EMPTY_SLOT(dev);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &empty_slot_ops, s,
- "empty-slot", s->size);
- sysbus_init_mmio(dev, &s->iomem);
- return 0;
-}
-
-static void empty_slot_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = empty_slot_init1;
-}
-
-static const TypeInfo empty_slot_info = {
- .name = TYPE_EMPTY_SLOT,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(EmptySlot),
- .class_init = empty_slot_class_init,
-};
-
-static void empty_slot_register_types(void)
-{
- type_register_static(&empty_slot_info);
-}
-
-type_init(empty_slot_register_types)
diff --git a/qemu/hw/core/fw-path-provider.c b/qemu/hw/core/fw-path-provider.c
deleted file mode 100644
index 33b99830e..000000000
--- a/qemu/hw/core/fw-path-provider.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Firmware path provider class and helpers.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License,
- * or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/fw-path-provider.h"
-
-char *fw_path_provider_get_dev_path(FWPathProvider *p, BusState *bus,
- DeviceState *dev)
-{
- FWPathProviderClass *k = FW_PATH_PROVIDER_GET_CLASS(p);
-
- return k->get_dev_path(p, bus, dev);
-}
-
-char *fw_path_provider_try_get_dev_path(Object *o, BusState *bus,
- DeviceState *dev)
-{
- FWPathProvider *p = (FWPathProvider *)
- object_dynamic_cast(o, TYPE_FW_PATH_PROVIDER);
-
- if (p) {
- return fw_path_provider_get_dev_path(p, bus, dev);
- }
-
- return NULL;
-}
-
-static const TypeInfo fw_path_provider_info = {
- .name = TYPE_FW_PATH_PROVIDER,
- .parent = TYPE_INTERFACE,
- .class_size = sizeof(FWPathProviderClass),
-};
-
-static void fw_path_provider_register_types(void)
-{
- type_register_static(&fw_path_provider_info);
-}
-
-type_init(fw_path_provider_register_types)
diff --git a/qemu/hw/core/hotplug.c b/qemu/hw/core/hotplug.c
deleted file mode 100644
index 645cfca1b..000000000
--- a/qemu/hw/core/hotplug.c
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Hotplug handler interface.
- *
- * Copyright (c) 2014 Red Hat Inc.
- *
- * Authors:
- * Igor Mammedov <imammedo@redhat.com>,
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-#include "qemu/osdep.h"
-#include "hw/hotplug.h"
-#include "qemu/module.h"
-
-void hotplug_handler_plug(HotplugHandler *plug_handler,
- DeviceState *plugged_dev,
- Error **errp)
-{
- HotplugHandlerClass *hdc = HOTPLUG_HANDLER_GET_CLASS(plug_handler);
-
- if (hdc->plug) {
- hdc->plug(plug_handler, plugged_dev, errp);
- }
-}
-
-void hotplug_handler_unplug_request(HotplugHandler *plug_handler,
- DeviceState *plugged_dev,
- Error **errp)
-{
- HotplugHandlerClass *hdc = HOTPLUG_HANDLER_GET_CLASS(plug_handler);
-
- if (hdc->unplug_request) {
- hdc->unplug_request(plug_handler, plugged_dev, errp);
- }
-}
-
-void hotplug_handler_unplug(HotplugHandler *plug_handler,
- DeviceState *plugged_dev,
- Error **errp)
-{
- HotplugHandlerClass *hdc = HOTPLUG_HANDLER_GET_CLASS(plug_handler);
-
- if (hdc->unplug) {
- hdc->unplug(plug_handler, plugged_dev, errp);
- }
-}
-
-static const TypeInfo hotplug_handler_info = {
- .name = TYPE_HOTPLUG_HANDLER,
- .parent = TYPE_INTERFACE,
- .class_size = sizeof(HotplugHandlerClass),
-};
-
-static void hotplug_handler_register_types(void)
-{
- type_register_static(&hotplug_handler_info);
-}
-
-type_init(hotplug_handler_register_types)
diff --git a/qemu/hw/core/irq.c b/qemu/hw/core/irq.c
deleted file mode 100644
index 49ff2e64f..000000000
--- a/qemu/hw/core/irq.c
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * QEMU IRQ/GPIO common code.
- *
- * Copyright (c) 2007 CodeSourcery.
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "hw/irq.h"
-#include "qom/object.h"
-
-#define IRQ(obj) OBJECT_CHECK(struct IRQState, (obj), TYPE_IRQ)
-
-struct IRQState {
- Object parent_obj;
-
- qemu_irq_handler handler;
- void *opaque;
- int n;
-};
-
-void qemu_set_irq(qemu_irq irq, int level)
-{
- if (!irq)
- return;
-
- irq->handler(irq->opaque, irq->n, level);
-}
-
-qemu_irq *qemu_extend_irqs(qemu_irq *old, int n_old, qemu_irq_handler handler,
- void *opaque, int n)
-{
- qemu_irq *s;
- int i;
-
- if (!old) {
- n_old = 0;
- }
- s = old ? g_renew(qemu_irq, old, n + n_old) : g_new(qemu_irq, n);
- for (i = n_old; i < n + n_old; i++) {
- s[i] = qemu_allocate_irq(handler, opaque, i);
- }
- return s;
-}
-
-qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n)
-{
- return qemu_extend_irqs(NULL, 0, handler, opaque, n);
-}
-
-qemu_irq qemu_allocate_irq(qemu_irq_handler handler, void *opaque, int n)
-{
- struct IRQState *irq;
-
- irq = IRQ(object_new(TYPE_IRQ));
- irq->handler = handler;
- irq->opaque = opaque;
- irq->n = n;
-
- return irq;
-}
-
-void qemu_free_irqs(qemu_irq *s, int n)
-{
- int i;
- for (i = 0; i < n; i++) {
- qemu_free_irq(s[i]);
- }
- g_free(s);
-}
-
-void qemu_free_irq(qemu_irq irq)
-{
- object_unref(OBJECT(irq));
-}
-
-static void qemu_notirq(void *opaque, int line, int level)
-{
- struct IRQState *irq = opaque;
-
- irq->handler(irq->opaque, irq->n, !level);
-}
-
-qemu_irq qemu_irq_invert(qemu_irq irq)
-{
- /* The default state for IRQs is low, so raise the output now. */
- qemu_irq_raise(irq);
- return qemu_allocate_irq(qemu_notirq, irq, 0);
-}
-
-static void qemu_splitirq(void *opaque, int line, int level)
-{
- struct IRQState **irq = opaque;
- irq[0]->handler(irq[0]->opaque, irq[0]->n, level);
- irq[1]->handler(irq[1]->opaque, irq[1]->n, level);
-}
-
-qemu_irq qemu_irq_split(qemu_irq irq1, qemu_irq irq2)
-{
- qemu_irq *s = g_malloc0(2 * sizeof(qemu_irq));
- s[0] = irq1;
- s[1] = irq2;
- return qemu_allocate_irq(qemu_splitirq, s, 0);
-}
-
-static void proxy_irq_handler(void *opaque, int n, int level)
-{
- qemu_irq **target = opaque;
-
- if (*target) {
- qemu_set_irq((*target)[n], level);
- }
-}
-
-qemu_irq *qemu_irq_proxy(qemu_irq **target, int n)
-{
- return qemu_allocate_irqs(proxy_irq_handler, target, n);
-}
-
-void qemu_irq_intercept_in(qemu_irq *gpio_in, qemu_irq_handler handler, int n)
-{
- int i;
- qemu_irq *old_irqs = qemu_allocate_irqs(NULL, NULL, n);
- for (i = 0; i < n; i++) {
- *old_irqs[i] = *gpio_in[i];
- gpio_in[i]->handler = handler;
- gpio_in[i]->opaque = &old_irqs[i];
- }
-}
-
-static const TypeInfo irq_type_info = {
- .name = TYPE_IRQ,
- .parent = TYPE_OBJECT,
- .instance_size = sizeof(struct IRQState),
-};
-
-static void irq_register_types(void)
-{
- type_register_static(&irq_type_info);
-}
-
-type_init(irq_register_types)
diff --git a/qemu/hw/core/loader.c b/qemu/hw/core/loader.c
deleted file mode 100644
index c0499571c..000000000
--- a/qemu/hw/core/loader.c
+++ /dev/null
@@ -1,1190 +0,0 @@
-/*
- * QEMU Executable loader
- *
- * Copyright (c) 2006 Fabrice Bellard
- *
- * 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.
- *
- * Gunzip functionality in this file is derived from u-boot:
- *
- * (C) Copyright 2008 Semihalf
- *
- * (C) Copyright 2000-2005
- * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/hw.h"
-#include "disas/disas.h"
-#include "monitor/monitor.h"
-#include "sysemu/sysemu.h"
-#include "uboot_image.h"
-#include "hw/loader.h"
-#include "hw/nvram/fw_cfg.h"
-#include "exec/memory.h"
-#include "exec/address-spaces.h"
-#include "hw/boards.h"
-#include "qemu/cutils.h"
-
-#include <zlib.h>
-
-static int roms_loaded;
-
-/* return the size or -1 if error */
-int get_image_size(const char *filename)
-{
- int fd, size;
- fd = open(filename, O_RDONLY | O_BINARY);
- if (fd < 0)
- return -1;
- size = lseek(fd, 0, SEEK_END);
- close(fd);
- return size;
-}
-
-/* return the size or -1 if error */
-/* deprecated, because caller does not specify buffer size! */
-int load_image(const char *filename, uint8_t *addr)
-{
- int fd, size;
- fd = open(filename, O_RDONLY | O_BINARY);
- if (fd < 0)
- return -1;
- size = lseek(fd, 0, SEEK_END);
- if (size == -1) {
- fprintf(stderr, "file %-20s: get size error: %s\n",
- filename, strerror(errno));
- close(fd);
- return -1;
- }
-
- lseek(fd, 0, SEEK_SET);
- if (read(fd, addr, size) != size) {
- close(fd);
- return -1;
- }
- close(fd);
- return size;
-}
-
-/* return the size or -1 if error */
-ssize_t load_image_size(const char *filename, void *addr, size_t size)
-{
- int fd;
- ssize_t actsize;
-
- fd = open(filename, O_RDONLY | O_BINARY);
- if (fd < 0) {
- return -1;
- }
-
- actsize = read(fd, addr, size);
- if (actsize < 0) {
- close(fd);
- return -1;
- }
- close(fd);
-
- return actsize;
-}
-
-/* read()-like version */
-ssize_t read_targphys(const char *name,
- int fd, hwaddr dst_addr, size_t nbytes)
-{
- uint8_t *buf;
- ssize_t did;
-
- buf = g_malloc(nbytes);
- did = read(fd, buf, nbytes);
- if (did > 0)
- rom_add_blob_fixed("read", buf, did, dst_addr);
- g_free(buf);
- return did;
-}
-
-/* return the size or -1 if error */
-int load_image_targphys(const char *filename,
- hwaddr addr, uint64_t max_sz)
-{
- int size;
-
- size = get_image_size(filename);
- if (size > max_sz) {
- return -1;
- }
- if (size > 0) {
- rom_add_file_fixed(filename, addr, -1);
- }
- return size;
-}
-
-int load_image_mr(const char *filename, MemoryRegion *mr)
-{
- int size;
-
- if (!memory_access_is_direct(mr, false)) {
- /* Can only load an image into RAM or ROM */
- return -1;
- }
-
- size = get_image_size(filename);
-
- if (size > memory_region_size(mr)) {
- return -1;
- }
- if (size > 0) {
- if (rom_add_file_mr(filename, mr, -1) < 0) {
- return -1;
- }
- }
- return size;
-}
-
-void pstrcpy_targphys(const char *name, hwaddr dest, int buf_size,
- const char *source)
-{
- const char *nulp;
- char *ptr;
-
- if (buf_size <= 0) return;
- nulp = memchr(source, 0, buf_size);
- if (nulp) {
- rom_add_blob_fixed(name, source, (nulp - source) + 1, dest);
- } else {
- rom_add_blob_fixed(name, source, buf_size, dest);
- ptr = rom_ptr(dest + buf_size - 1);
- *ptr = 0;
- }
-}
-
-/* A.OUT loader */
-
-struct exec
-{
- uint32_t a_info; /* Use macros N_MAGIC, etc for access */
- uint32_t a_text; /* length of text, in bytes */
- uint32_t a_data; /* length of data, in bytes */
- uint32_t a_bss; /* length of uninitialized data area, in bytes */
- uint32_t a_syms; /* length of symbol table data in file, in bytes */
- uint32_t a_entry; /* start address */
- uint32_t a_trsize; /* length of relocation info for text, in bytes */
- uint32_t a_drsize; /* length of relocation info for data, in bytes */
-};
-
-static void bswap_ahdr(struct exec *e)
-{
- bswap32s(&e->a_info);
- bswap32s(&e->a_text);
- bswap32s(&e->a_data);
- bswap32s(&e->a_bss);
- bswap32s(&e->a_syms);
- bswap32s(&e->a_entry);
- bswap32s(&e->a_trsize);
- bswap32s(&e->a_drsize);
-}
-
-#define N_MAGIC(exec) ((exec).a_info & 0xffff)
-#define OMAGIC 0407
-#define NMAGIC 0410
-#define ZMAGIC 0413
-#define QMAGIC 0314
-#define _N_HDROFF(x) (1024 - sizeof (struct exec))
-#define N_TXTOFF(x) \
- (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : \
- (N_MAGIC(x) == QMAGIC ? 0 : sizeof (struct exec)))
-#define N_TXTADDR(x, target_page_size) (N_MAGIC(x) == QMAGIC ? target_page_size : 0)
-#define _N_SEGMENT_ROUND(x, target_page_size) (((x) + target_page_size - 1) & ~(target_page_size - 1))
-
-#define _N_TXTENDADDR(x, target_page_size) (N_TXTADDR(x, target_page_size)+(x).a_text)
-
-#define N_DATADDR(x, target_page_size) \
- (N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x, target_page_size)) \
- : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x, target_page_size), target_page_size)))
-
-
-int load_aout(const char *filename, hwaddr addr, int max_sz,
- int bswap_needed, hwaddr target_page_size)
-{
- int fd;
- ssize_t size, ret;
- struct exec e;
- uint32_t magic;
-
- fd = open(filename, O_RDONLY | O_BINARY);
- if (fd < 0)
- return -1;
-
- size = read(fd, &e, sizeof(e));
- if (size < 0)
- goto fail;
-
- if (bswap_needed) {
- bswap_ahdr(&e);
- }
-
- magic = N_MAGIC(e);
- switch (magic) {
- case ZMAGIC:
- case QMAGIC:
- case OMAGIC:
- if (e.a_text + e.a_data > max_sz)
- goto fail;
- lseek(fd, N_TXTOFF(e), SEEK_SET);
- size = read_targphys(filename, fd, addr, e.a_text + e.a_data);
- if (size < 0)
- goto fail;
- break;
- case NMAGIC:
- if (N_DATADDR(e, target_page_size) + e.a_data > max_sz)
- goto fail;
- lseek(fd, N_TXTOFF(e), SEEK_SET);
- size = read_targphys(filename, fd, addr, e.a_text);
- if (size < 0)
- goto fail;
- ret = read_targphys(filename, fd, addr + N_DATADDR(e, target_page_size),
- e.a_data);
- if (ret < 0)
- goto fail;
- size += ret;
- break;
- default:
- goto fail;
- }
- close(fd);
- return size;
- fail:
- close(fd);
- return -1;
-}
-
-/* ELF loader */
-
-static void *load_at(int fd, off_t offset, size_t size)
-{
- void *ptr;
- if (lseek(fd, offset, SEEK_SET) < 0)
- return NULL;
- ptr = g_malloc(size);
- if (read(fd, ptr, size) != size) {
- g_free(ptr);
- return NULL;
- }
- return ptr;
-}
-
-#ifdef ELF_CLASS
-#undef ELF_CLASS
-#endif
-
-#define ELF_CLASS ELFCLASS32
-#include "elf.h"
-
-#define SZ 32
-#define elf_word uint32_t
-#define elf_sword int32_t
-#define bswapSZs bswap32s
-#include "hw/elf_ops.h"
-
-#undef elfhdr
-#undef elf_phdr
-#undef elf_shdr
-#undef elf_sym
-#undef elf_rela
-#undef elf_note
-#undef elf_word
-#undef elf_sword
-#undef bswapSZs
-#undef SZ
-#define elfhdr elf64_hdr
-#define elf_phdr elf64_phdr
-#define elf_note elf64_note
-#define elf_shdr elf64_shdr
-#define elf_sym elf64_sym
-#define elf_rela elf64_rela
-#define elf_word uint64_t
-#define elf_sword int64_t
-#define bswapSZs bswap64s
-#define SZ 64
-#include "hw/elf_ops.h"
-
-const char *load_elf_strerror(int error)
-{
- switch (error) {
- case 0:
- return "No error";
- case ELF_LOAD_FAILED:
- return "Failed to load ELF";
- case ELF_LOAD_NOT_ELF:
- return "The image is not ELF";
- case ELF_LOAD_WRONG_ARCH:
- return "The image is from incompatible architecture";
- case ELF_LOAD_WRONG_ENDIAN:
- return "The image has incorrect endianness";
- default:
- return "Unknown error";
- }
-}
-
-void load_elf_hdr(const char *filename, void *hdr, bool *is64, Error **errp)
-{
- int fd;
- uint8_t e_ident_local[EI_NIDENT];
- uint8_t *e_ident;
- size_t hdr_size, off;
- bool is64l;
-
- if (!hdr) {
- hdr = e_ident_local;
- }
- e_ident = hdr;
-
- fd = open(filename, O_RDONLY | O_BINARY);
- if (fd < 0) {
- error_setg_errno(errp, errno, "Failed to open file: %s", filename);
- return;
- }
- if (read(fd, hdr, EI_NIDENT) != EI_NIDENT) {
- error_setg_errno(errp, errno, "Failed to read file: %s", filename);
- goto fail;
- }
- if (e_ident[0] != ELFMAG0 ||
- e_ident[1] != ELFMAG1 ||
- e_ident[2] != ELFMAG2 ||
- e_ident[3] != ELFMAG3) {
- error_setg(errp, "Bad ELF magic");
- goto fail;
- }
-
- is64l = e_ident[EI_CLASS] == ELFCLASS64;
- hdr_size = is64l ? sizeof(Elf64_Ehdr) : sizeof(Elf32_Ehdr);
- if (is64) {
- *is64 = is64l;
- }
-
- off = EI_NIDENT;
- while (hdr != e_ident_local && off < hdr_size) {
- size_t br = read(fd, hdr + off, hdr_size - off);
- switch (br) {
- case 0:
- error_setg(errp, "File too short: %s", filename);
- goto fail;
- case -1:
- error_setg_errno(errp, errno, "Failed to read file: %s",
- filename);
- goto fail;
- }
- off += br;
- }
-
-fail:
- close(fd);
-}
-
-/* return < 0 if error, otherwise the number of bytes loaded in memory */
-int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
- void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr,
- uint64_t *highaddr, int big_endian, int elf_machine,
- int clear_lsb, int data_swab)
-{
- int fd, data_order, target_data_order, must_swab, ret = ELF_LOAD_FAILED;
- uint8_t e_ident[EI_NIDENT];
-
- fd = open(filename, O_RDONLY | O_BINARY);
- if (fd < 0) {
- perror(filename);
- return -1;
- }
- if (read(fd, e_ident, sizeof(e_ident)) != sizeof(e_ident))
- goto fail;
- if (e_ident[0] != ELFMAG0 ||
- e_ident[1] != ELFMAG1 ||
- e_ident[2] != ELFMAG2 ||
- e_ident[3] != ELFMAG3) {
- ret = ELF_LOAD_NOT_ELF;
- goto fail;
- }
-#ifdef HOST_WORDS_BIGENDIAN
- data_order = ELFDATA2MSB;
-#else
- data_order = ELFDATA2LSB;
-#endif
- must_swab = data_order != e_ident[EI_DATA];
- if (big_endian) {
- target_data_order = ELFDATA2MSB;
- } else {
- target_data_order = ELFDATA2LSB;
- }
-
- if (target_data_order != e_ident[EI_DATA]) {
- ret = ELF_LOAD_WRONG_ENDIAN;
- goto fail;
- }
-
- lseek(fd, 0, SEEK_SET);
- if (e_ident[EI_CLASS] == ELFCLASS64) {
- ret = load_elf64(filename, fd, translate_fn, translate_opaque, must_swab,
- pentry, lowaddr, highaddr, elf_machine, clear_lsb,
- data_swab);
- } else {
- ret = load_elf32(filename, fd, translate_fn, translate_opaque, must_swab,
- pentry, lowaddr, highaddr, elf_machine, clear_lsb,
- data_swab);
- }
-
- fail:
- close(fd);
- return ret;
-}
-
-static void bswap_uboot_header(uboot_image_header_t *hdr)
-{
-#ifndef HOST_WORDS_BIGENDIAN
- bswap32s(&hdr->ih_magic);
- bswap32s(&hdr->ih_hcrc);
- bswap32s(&hdr->ih_time);
- bswap32s(&hdr->ih_size);
- bswap32s(&hdr->ih_load);
- bswap32s(&hdr->ih_ep);
- bswap32s(&hdr->ih_dcrc);
-#endif
-}
-
-
-#define ZALLOC_ALIGNMENT 16
-
-static void *zalloc(void *x, unsigned items, unsigned size)
-{
- void *p;
-
- size *= items;
- size = (size + ZALLOC_ALIGNMENT - 1) & ~(ZALLOC_ALIGNMENT - 1);
-
- p = g_malloc(size);
-
- return (p);
-}
-
-static void zfree(void *x, void *addr)
-{
- g_free(addr);
-}
-
-
-#define HEAD_CRC 2
-#define EXTRA_FIELD 4
-#define ORIG_NAME 8
-#define COMMENT 0x10
-#define RESERVED 0xe0
-
-#define DEFLATED 8
-
-/* This is the usual maximum in uboot, so if a uImage overflows this, it would
- * overflow on real hardware too. */
-#define UBOOT_MAX_GUNZIP_BYTES (64 << 20)
-
-static ssize_t gunzip(void *dst, size_t dstlen, uint8_t *src,
- size_t srclen)
-{
- z_stream s;
- ssize_t dstbytes;
- int r, i, flags;
-
- /* skip header */
- i = 10;
- flags = src[3];
- if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
- puts ("Error: Bad gzipped data\n");
- return -1;
- }
- if ((flags & EXTRA_FIELD) != 0)
- i = 12 + src[10] + (src[11] << 8);
- if ((flags & ORIG_NAME) != 0)
- while (src[i++] != 0)
- ;
- if ((flags & COMMENT) != 0)
- while (src[i++] != 0)
- ;
- if ((flags & HEAD_CRC) != 0)
- i += 2;
- if (i >= srclen) {
- puts ("Error: gunzip out of data in header\n");
- return -1;
- }
-
- s.zalloc = zalloc;
- s.zfree = zfree;
-
- r = inflateInit2(&s, -MAX_WBITS);
- if (r != Z_OK) {
- printf ("Error: inflateInit2() returned %d\n", r);
- return (-1);
- }
- s.next_in = src + i;
- s.avail_in = srclen - i;
- s.next_out = dst;
- s.avail_out = dstlen;
- r = inflate(&s, Z_FINISH);
- if (r != Z_OK && r != Z_STREAM_END) {
- printf ("Error: inflate() returned %d\n", r);
- return -1;
- }
- dstbytes = s.next_out - (unsigned char *) dst;
- inflateEnd(&s);
-
- return dstbytes;
-}
-
-/* Load a U-Boot image. */
-static int load_uboot_image(const char *filename, hwaddr *ep, hwaddr *loadaddr,
- int *is_linux, uint8_t image_type,
- uint64_t (*translate_fn)(void *, uint64_t),
- void *translate_opaque)
-{
- int fd;
- int size;
- hwaddr address;
- uboot_image_header_t h;
- uboot_image_header_t *hdr = &h;
- uint8_t *data = NULL;
- int ret = -1;
- int do_uncompress = 0;
-
- fd = open(filename, O_RDONLY | O_BINARY);
- if (fd < 0)
- return -1;
-
- size = read(fd, hdr, sizeof(uboot_image_header_t));
- if (size < 0)
- goto out;
-
- bswap_uboot_header(hdr);
-
- if (hdr->ih_magic != IH_MAGIC)
- goto out;
-
- if (hdr->ih_type != image_type) {
- fprintf(stderr, "Wrong image type %d, expected %d\n", hdr->ih_type,
- image_type);
- goto out;
- }
-
- /* TODO: Implement other image types. */
- switch (hdr->ih_type) {
- case IH_TYPE_KERNEL:
- address = hdr->ih_load;
- if (translate_fn) {
- address = translate_fn(translate_opaque, address);
- }
- if (loadaddr) {
- *loadaddr = hdr->ih_load;
- }
-
- switch (hdr->ih_comp) {
- case IH_COMP_NONE:
- break;
- case IH_COMP_GZIP:
- do_uncompress = 1;
- break;
- default:
- fprintf(stderr,
- "Unable to load u-boot images with compression type %d\n",
- hdr->ih_comp);
- goto out;
- }
-
- if (ep) {
- *ep = hdr->ih_ep;
- }
-
- /* TODO: Check CPU type. */
- if (is_linux) {
- if (hdr->ih_os == IH_OS_LINUX) {
- *is_linux = 1;
- } else {
- *is_linux = 0;
- }
- }
-
- break;
- case IH_TYPE_RAMDISK:
- address = *loadaddr;
- break;
- default:
- fprintf(stderr, "Unsupported u-boot image type %d\n", hdr->ih_type);
- goto out;
- }
-
- data = g_malloc(hdr->ih_size);
-
- if (read(fd, data, hdr->ih_size) != hdr->ih_size) {
- fprintf(stderr, "Error reading file\n");
- goto out;
- }
-
- if (do_uncompress) {
- uint8_t *compressed_data;
- size_t max_bytes;
- ssize_t bytes;
-
- compressed_data = data;
- max_bytes = UBOOT_MAX_GUNZIP_BYTES;
- data = g_malloc(max_bytes);
-
- bytes = gunzip(data, max_bytes, compressed_data, hdr->ih_size);
- g_free(compressed_data);
- if (bytes < 0) {
- fprintf(stderr, "Unable to decompress gzipped image!\n");
- goto out;
- }
- hdr->ih_size = bytes;
- }
-
- rom_add_blob_fixed(filename, data, hdr->ih_size, address);
-
- ret = hdr->ih_size;
-
-out:
- g_free(data);
- close(fd);
- return ret;
-}
-
-int load_uimage(const char *filename, hwaddr *ep, hwaddr *loadaddr,
- int *is_linux,
- uint64_t (*translate_fn)(void *, uint64_t),
- void *translate_opaque)
-{
- return load_uboot_image(filename, ep, loadaddr, is_linux, IH_TYPE_KERNEL,
- translate_fn, translate_opaque);
-}
-
-/* Load a ramdisk. */
-int load_ramdisk(const char *filename, hwaddr addr, uint64_t max_sz)
-{
- return load_uboot_image(filename, NULL, &addr, NULL, IH_TYPE_RAMDISK,
- NULL, NULL);
-}
-
-/* Load a gzip-compressed kernel to a dynamically allocated buffer. */
-int load_image_gzipped_buffer(const char *filename, uint64_t max_sz,
- uint8_t **buffer)
-{
- uint8_t *compressed_data = NULL;
- uint8_t *data = NULL;
- gsize len;
- ssize_t bytes;
- int ret = -1;
-
- if (!g_file_get_contents(filename, (char **) &compressed_data, &len,
- NULL)) {
- goto out;
- }
-
- /* Is it a gzip-compressed file? */
- if (len < 2 ||
- compressed_data[0] != 0x1f ||
- compressed_data[1] != 0x8b) {
- goto out;
- }
-
- if (max_sz > LOAD_IMAGE_MAX_GUNZIP_BYTES) {
- max_sz = LOAD_IMAGE_MAX_GUNZIP_BYTES;
- }
-
- data = g_malloc(max_sz);
- bytes = gunzip(data, max_sz, compressed_data, len);
- if (bytes < 0) {
- fprintf(stderr, "%s: unable to decompress gzipped kernel file\n",
- filename);
- goto out;
- }
-
- /* trim to actual size and return to caller */
- *buffer = g_realloc(data, bytes);
- ret = bytes;
- /* ownership has been transferred to caller */
- data = NULL;
-
- out:
- g_free(compressed_data);
- g_free(data);
- return ret;
-}
-
-/* Load a gzip-compressed kernel. */
-int load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz)
-{
- int bytes;
- uint8_t *data;
-
- bytes = load_image_gzipped_buffer(filename, max_sz, &data);
- if (bytes != -1) {
- rom_add_blob_fixed(filename, data, bytes, addr);
- g_free(data);
- }
- return bytes;
-}
-
-/*
- * Functions for reboot-persistent memory regions.
- * - used for vga bios and option roms.
- * - also linux kernel (-kernel / -initrd).
- */
-
-typedef struct Rom Rom;
-
-struct Rom {
- char *name;
- char *path;
-
- /* datasize is the amount of memory allocated in "data". If datasize is less
- * than romsize, it means that the area from datasize to romsize is filled
- * with zeros.
- */
- size_t romsize;
- size_t datasize;
-
- uint8_t *data;
- MemoryRegion *mr;
- int isrom;
- char *fw_dir;
- char *fw_file;
-
- hwaddr addr;
- QTAILQ_ENTRY(Rom) next;
-};
-
-static FWCfgState *fw_cfg;
-static QTAILQ_HEAD(, Rom) roms = QTAILQ_HEAD_INITIALIZER(roms);
-
-static void rom_insert(Rom *rom)
-{
- Rom *item;
-
- if (roms_loaded) {
- hw_error ("ROM images must be loaded at startup\n");
- }
-
- /* list is ordered by load address */
- QTAILQ_FOREACH(item, &roms, next) {
- if (rom->addr >= item->addr)
- continue;
- QTAILQ_INSERT_BEFORE(item, rom, next);
- return;
- }
- QTAILQ_INSERT_TAIL(&roms, rom, next);
-}
-
-static void fw_cfg_resized(const char *id, uint64_t length, void *host)
-{
- if (fw_cfg) {
- fw_cfg_modify_file(fw_cfg, id + strlen("/rom@"), host, length);
- }
-}
-
-static void *rom_set_mr(Rom *rom, Object *owner, const char *name)
-{
- void *data;
-
- rom->mr = g_malloc(sizeof(*rom->mr));
- memory_region_init_resizeable_ram(rom->mr, owner, name,
- rom->datasize, rom->romsize,
- fw_cfg_resized,
- &error_fatal);
- memory_region_set_readonly(rom->mr, true);
- vmstate_register_ram_global(rom->mr);
-
- data = memory_region_get_ram_ptr(rom->mr);
- memcpy(data, rom->data, rom->datasize);
-
- return data;
-}
-
-int rom_add_file(const char *file, const char *fw_dir,
- hwaddr addr, int32_t bootindex,
- bool option_rom, MemoryRegion *mr)
-{
- MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
- Rom *rom;
- int rc, fd = -1;
- char devpath[100];
-
- rom = g_malloc0(sizeof(*rom));
- rom->name = g_strdup(file);
- rom->path = qemu_find_file(QEMU_FILE_TYPE_BIOS, rom->name);
- if (rom->path == NULL) {
- rom->path = g_strdup(file);
- }
-
- fd = open(rom->path, O_RDONLY | O_BINARY);
- if (fd == -1) {
- fprintf(stderr, "Could not open option rom '%s': %s\n",
- rom->path, strerror(errno));
- goto err;
- }
-
- if (fw_dir) {
- rom->fw_dir = g_strdup(fw_dir);
- rom->fw_file = g_strdup(file);
- }
- rom->addr = addr;
- rom->romsize = lseek(fd, 0, SEEK_END);
- if (rom->romsize == -1) {
- fprintf(stderr, "rom: file %-20s: get size error: %s\n",
- rom->name, strerror(errno));
- goto err;
- }
-
- rom->datasize = rom->romsize;
- rom->data = g_malloc0(rom->datasize);
- lseek(fd, 0, SEEK_SET);
- rc = read(fd, rom->data, rom->datasize);
- if (rc != rom->datasize) {
- fprintf(stderr, "rom: file %-20s: read error: rc=%d (expected %zd)\n",
- rom->name, rc, rom->datasize);
- goto err;
- }
- close(fd);
- rom_insert(rom);
- if (rom->fw_file && fw_cfg) {
- const char *basename;
- char fw_file_name[FW_CFG_MAX_FILE_PATH];
- void *data;
-
- basename = strrchr(rom->fw_file, '/');
- if (basename) {
- basename++;
- } else {
- basename = rom->fw_file;
- }
- snprintf(fw_file_name, sizeof(fw_file_name), "%s/%s", rom->fw_dir,
- basename);
- snprintf(devpath, sizeof(devpath), "/rom@%s", fw_file_name);
-
- if ((!option_rom || mc->option_rom_has_mr) && mc->rom_file_has_mr) {
- data = rom_set_mr(rom, OBJECT(fw_cfg), devpath);
- } else {
- data = rom->data;
- }
-
- fw_cfg_add_file(fw_cfg, fw_file_name, data, rom->romsize);
- } else {
- if (mr) {
- rom->mr = mr;
- snprintf(devpath, sizeof(devpath), "/rom@%s", file);
- } else {
- snprintf(devpath, sizeof(devpath), "/rom@" TARGET_FMT_plx, addr);
- }
- }
-
- add_boot_device_path(bootindex, NULL, devpath);
- return 0;
-
-err:
- if (fd != -1)
- close(fd);
- g_free(rom->data);
- g_free(rom->path);
- g_free(rom->name);
- g_free(rom);
- return -1;
-}
-
-MemoryRegion *rom_add_blob(const char *name, const void *blob, size_t len,
- size_t max_len, hwaddr addr, const char *fw_file_name,
- FWCfgReadCallback fw_callback, void *callback_opaque)
-{
- MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
- Rom *rom;
- MemoryRegion *mr = NULL;
-
- rom = g_malloc0(sizeof(*rom));
- rom->name = g_strdup(name);
- rom->addr = addr;
- rom->romsize = max_len ? max_len : len;
- rom->datasize = len;
- rom->data = g_malloc0(rom->datasize);
- memcpy(rom->data, blob, len);
- rom_insert(rom);
- if (fw_file_name && fw_cfg) {
- char devpath[100];
- void *data;
-
- snprintf(devpath, sizeof(devpath), "/rom@%s", fw_file_name);
-
- if (mc->rom_file_has_mr) {
- data = rom_set_mr(rom, OBJECT(fw_cfg), devpath);
- mr = rom->mr;
- } else {
- data = rom->data;
- }
-
- fw_cfg_add_file_callback(fw_cfg, fw_file_name,
- fw_callback, callback_opaque,
- data, rom->datasize);
- }
- return mr;
-}
-
-/* This function is specific for elf program because we don't need to allocate
- * all the rom. We just allocate the first part and the rest is just zeros. This
- * is why romsize and datasize are different. Also, this function seize the
- * memory ownership of "data", so we don't have to allocate and copy the buffer.
- */
-int rom_add_elf_program(const char *name, void *data, size_t datasize,
- size_t romsize, hwaddr addr)
-{
- Rom *rom;
-
- rom = g_malloc0(sizeof(*rom));
- rom->name = g_strdup(name);
- rom->addr = addr;
- rom->datasize = datasize;
- rom->romsize = romsize;
- rom->data = data;
- rom_insert(rom);
- return 0;
-}
-
-int rom_add_vga(const char *file)
-{
- return rom_add_file(file, "vgaroms", 0, -1, true, NULL);
-}
-
-int rom_add_option(const char *file, int32_t bootindex)
-{
- return rom_add_file(file, "genroms", 0, bootindex, true, NULL);
-}
-
-static void rom_reset(void *unused)
-{
- Rom *rom;
-
- QTAILQ_FOREACH(rom, &roms, next) {
- if (rom->fw_file) {
- continue;
- }
- if (rom->data == NULL) {
- continue;
- }
- if (rom->mr) {
- void *host = memory_region_get_ram_ptr(rom->mr);
- memcpy(host, rom->data, rom->datasize);
- } else {
- cpu_physical_memory_write_rom(&address_space_memory,
- rom->addr, rom->data, rom->datasize);
- }
- if (rom->isrom) {
- /* rom needs to be written only once */
- g_free(rom->data);
- rom->data = NULL;
- }
- /*
- * The rom loader is really on the same level as firmware in the guest
- * shadowing a ROM into RAM. Such a shadowing mechanism needs to ensure
- * that the instruction cache for that new region is clear, so that the
- * CPU definitely fetches its instructions from the just written data.
- */
- cpu_flush_icache_range(rom->addr, rom->datasize);
- }
-}
-
-int rom_check_and_register_reset(void)
-{
- hwaddr addr = 0;
- MemoryRegionSection section;
- Rom *rom;
-
- QTAILQ_FOREACH(rom, &roms, next) {
- if (rom->fw_file) {
- continue;
- }
- if (addr > rom->addr) {
- fprintf(stderr, "rom: requested regions overlap "
- "(rom %s. free=0x" TARGET_FMT_plx
- ", addr=0x" TARGET_FMT_plx ")\n",
- rom->name, addr, rom->addr);
- return -1;
- }
- addr = rom->addr;
- addr += rom->romsize;
- section = memory_region_find(get_system_memory(), rom->addr, 1);
- rom->isrom = int128_nz(section.size) && memory_region_is_rom(section.mr);
- memory_region_unref(section.mr);
- }
- qemu_register_reset(rom_reset, NULL);
- roms_loaded = 1;
- return 0;
-}
-
-void rom_set_fw(FWCfgState *f)
-{
- fw_cfg = f;
-}
-
-void rom_set_order_override(int order)
-{
- if (!fw_cfg)
- return;
- fw_cfg_set_order_override(fw_cfg, order);
-}
-
-void rom_reset_order_override(void)
-{
- if (!fw_cfg)
- return;
- fw_cfg_reset_order_override(fw_cfg);
-}
-
-static Rom *find_rom(hwaddr addr)
-{
- Rom *rom;
-
- QTAILQ_FOREACH(rom, &roms, next) {
- if (rom->fw_file) {
- continue;
- }
- if (rom->mr) {
- continue;
- }
- if (rom->addr > addr) {
- continue;
- }
- if (rom->addr + rom->romsize < addr) {
- continue;
- }
- return rom;
- }
- return NULL;
-}
-
-/*
- * Copies memory from registered ROMs to dest. Any memory that is contained in
- * a ROM between addr and addr + size is copied. Note that this can involve
- * multiple ROMs, which need not start at addr and need not end at addr + size.
- */
-int rom_copy(uint8_t *dest, hwaddr addr, size_t size)
-{
- hwaddr end = addr + size;
- uint8_t *s, *d = dest;
- size_t l = 0;
- Rom *rom;
-
- QTAILQ_FOREACH(rom, &roms, next) {
- if (rom->fw_file) {
- continue;
- }
- if (rom->mr) {
- continue;
- }
- if (rom->addr + rom->romsize < addr) {
- continue;
- }
- if (rom->addr > end) {
- break;
- }
-
- d = dest + (rom->addr - addr);
- s = rom->data;
- l = rom->datasize;
-
- if ((d + l) > (dest + size)) {
- l = dest - d;
- }
-
- if (l > 0) {
- memcpy(d, s, l);
- }
-
- if (rom->romsize > rom->datasize) {
- /* If datasize is less than romsize, it means that we didn't
- * allocate all the ROM because the trailing data are only zeros.
- */
-
- d += l;
- l = rom->romsize - rom->datasize;
-
- if ((d + l) > (dest + size)) {
- /* Rom size doesn't fit in the destination area. Adjust to avoid
- * overflow.
- */
- l = dest - d;
- }
-
- if (l > 0) {
- memset(d, 0x0, l);
- }
- }
- }
-
- return (d + l) - dest;
-}
-
-void *rom_ptr(hwaddr addr)
-{
- Rom *rom;
-
- rom = find_rom(addr);
- if (!rom || !rom->data)
- return NULL;
- return rom->data + (addr - rom->addr);
-}
-
-void hmp_info_roms(Monitor *mon, const QDict *qdict)
-{
- Rom *rom;
-
- QTAILQ_FOREACH(rom, &roms, next) {
- if (rom->mr) {
- monitor_printf(mon, "%s"
- " size=0x%06zx name=\"%s\"\n",
- memory_region_name(rom->mr),
- rom->romsize,
- rom->name);
- } else if (!rom->fw_file) {
- monitor_printf(mon, "addr=" TARGET_FMT_plx
- " size=0x%06zx mem=%s name=\"%s\"\n",
- rom->addr, rom->romsize,
- rom->isrom ? "rom" : "ram",
- rom->name);
- } else {
- monitor_printf(mon, "fw=%s/%s"
- " size=0x%06zx name=\"%s\"\n",
- rom->fw_dir,
- rom->fw_file,
- rom->romsize,
- rom->name);
- }
- }
-}
diff --git a/qemu/hw/core/machine.c b/qemu/hw/core/machine.c
deleted file mode 100644
index 6dbbc85b9..000000000
--- a/qemu/hw/core/machine.c
+++ /dev/null
@@ -1,570 +0,0 @@
-/*
- * QEMU Machine
- *
- * Copyright (C) 2014 Red Hat Inc
- *
- * Authors:
- * Marcel Apfelbaum <marcel.a@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "hw/boards.h"
-#include "qapi/error.h"
-#include "qapi-visit.h"
-#include "qapi/visitor.h"
-#include "hw/sysbus.h"
-#include "sysemu/sysemu.h"
-#include "qemu/error-report.h"
-#include "qemu/cutils.h"
-
-static char *machine_get_accel(Object *obj, Error **errp)
-{
- MachineState *ms = MACHINE(obj);
-
- return g_strdup(ms->accel);
-}
-
-static void machine_set_accel(Object *obj, const char *value, Error **errp)
-{
- MachineState *ms = MACHINE(obj);
-
- g_free(ms->accel);
- ms->accel = g_strdup(value);
-}
-
-static void machine_set_kernel_irqchip(Object *obj, Visitor *v,
- const char *name, void *opaque,
- Error **errp)
-{
- Error *err = NULL;
- MachineState *ms = MACHINE(obj);
- OnOffSplit mode;
-
- visit_type_OnOffSplit(v, name, &mode, &err);
- if (err) {
- error_propagate(errp, err);
- return;
- } else {
- switch (mode) {
- case ON_OFF_SPLIT_ON:
- ms->kernel_irqchip_allowed = true;
- ms->kernel_irqchip_required = true;
- ms->kernel_irqchip_split = false;
- break;
- case ON_OFF_SPLIT_OFF:
- ms->kernel_irqchip_allowed = false;
- ms->kernel_irqchip_required = false;
- ms->kernel_irqchip_split = false;
- break;
- case ON_OFF_SPLIT_SPLIT:
- ms->kernel_irqchip_allowed = true;
- ms->kernel_irqchip_required = true;
- ms->kernel_irqchip_split = true;
- break;
- default:
- abort();
- }
- }
-}
-
-static void machine_get_kvm_shadow_mem(Object *obj, Visitor *v,
- const char *name, void *opaque,
- Error **errp)
-{
- MachineState *ms = MACHINE(obj);
- int64_t value = ms->kvm_shadow_mem;
-
- visit_type_int(v, name, &value, errp);
-}
-
-static void machine_set_kvm_shadow_mem(Object *obj, Visitor *v,
- const char *name, void *opaque,
- Error **errp)
-{
- MachineState *ms = MACHINE(obj);
- Error *error = NULL;
- int64_t value;
-
- visit_type_int(v, name, &value, &error);
- if (error) {
- error_propagate(errp, error);
- return;
- }
-
- ms->kvm_shadow_mem = value;
-}
-
-static char *machine_get_kernel(Object *obj, Error **errp)
-{
- MachineState *ms = MACHINE(obj);
-
- return g_strdup(ms->kernel_filename);
-}
-
-static void machine_set_kernel(Object *obj, const char *value, Error **errp)
-{
- MachineState *ms = MACHINE(obj);
-
- g_free(ms->kernel_filename);
- ms->kernel_filename = g_strdup(value);
-}
-
-static char *machine_get_initrd(Object *obj, Error **errp)
-{
- MachineState *ms = MACHINE(obj);
-
- return g_strdup(ms->initrd_filename);
-}
-
-static void machine_set_initrd(Object *obj, const char *value, Error **errp)
-{
- MachineState *ms = MACHINE(obj);
-
- g_free(ms->initrd_filename);
- ms->initrd_filename = g_strdup(value);
-}
-
-static char *machine_get_append(Object *obj, Error **errp)
-{
- MachineState *ms = MACHINE(obj);
-
- return g_strdup(ms->kernel_cmdline);
-}
-
-static void machine_set_append(Object *obj, const char *value, Error **errp)
-{
- MachineState *ms = MACHINE(obj);
-
- g_free(ms->kernel_cmdline);
- ms->kernel_cmdline = g_strdup(value);
-}
-
-static char *machine_get_dtb(Object *obj, Error **errp)
-{
- MachineState *ms = MACHINE(obj);
-
- return g_strdup(ms->dtb);
-}
-
-static void machine_set_dtb(Object *obj, const char *value, Error **errp)
-{
- MachineState *ms = MACHINE(obj);
-
- g_free(ms->dtb);
- ms->dtb = g_strdup(value);
-}
-
-static char *machine_get_dumpdtb(Object *obj, Error **errp)
-{
- MachineState *ms = MACHINE(obj);
-
- return g_strdup(ms->dumpdtb);
-}
-
-static void machine_set_dumpdtb(Object *obj, const char *value, Error **errp)
-{
- MachineState *ms = MACHINE(obj);
-
- g_free(ms->dumpdtb);
- ms->dumpdtb = g_strdup(value);
-}
-
-static void machine_get_phandle_start(Object *obj, Visitor *v,
- const char *name, void *opaque,
- Error **errp)
-{
- MachineState *ms = MACHINE(obj);
- int64_t value = ms->phandle_start;
-
- visit_type_int(v, name, &value, errp);
-}
-
-static void machine_set_phandle_start(Object *obj, Visitor *v,
- const char *name, void *opaque,
- Error **errp)
-{
- MachineState *ms = MACHINE(obj);
- Error *error = NULL;
- int64_t value;
-
- visit_type_int(v, name, &value, &error);
- if (error) {
- error_propagate(errp, error);
- return;
- }
-
- ms->phandle_start = value;
-}
-
-static char *machine_get_dt_compatible(Object *obj, Error **errp)
-{
- MachineState *ms = MACHINE(obj);
-
- return g_strdup(ms->dt_compatible);
-}
-
-static void machine_set_dt_compatible(Object *obj, const char *value, Error **errp)
-{
- MachineState *ms = MACHINE(obj);
-
- g_free(ms->dt_compatible);
- ms->dt_compatible = g_strdup(value);
-}
-
-static bool machine_get_dump_guest_core(Object *obj, Error **errp)
-{
- MachineState *ms = MACHINE(obj);
-
- return ms->dump_guest_core;
-}
-
-static void machine_set_dump_guest_core(Object *obj, bool value, Error **errp)
-{
- MachineState *ms = MACHINE(obj);
-
- ms->dump_guest_core = value;
-}
-
-static bool machine_get_mem_merge(Object *obj, Error **errp)
-{
- MachineState *ms = MACHINE(obj);
-
- return ms->mem_merge;
-}
-
-static void machine_set_mem_merge(Object *obj, bool value, Error **errp)
-{
- MachineState *ms = MACHINE(obj);
-
- ms->mem_merge = value;
-}
-
-static bool machine_get_usb(Object *obj, Error **errp)
-{
- MachineState *ms = MACHINE(obj);
-
- return ms->usb;
-}
-
-static void machine_set_usb(Object *obj, bool value, Error **errp)
-{
- MachineState *ms = MACHINE(obj);
-
- ms->usb = value;
- ms->usb_disabled = !value;
-}
-
-static bool machine_get_igd_gfx_passthru(Object *obj, Error **errp)
-{
- MachineState *ms = MACHINE(obj);
-
- return ms->igd_gfx_passthru;
-}
-
-static void machine_set_igd_gfx_passthru(Object *obj, bool value, Error **errp)
-{
- MachineState *ms = MACHINE(obj);
-
- ms->igd_gfx_passthru = value;
-}
-
-static char *machine_get_firmware(Object *obj, Error **errp)
-{
- MachineState *ms = MACHINE(obj);
-
- return g_strdup(ms->firmware);
-}
-
-static void machine_set_firmware(Object *obj, const char *value, Error **errp)
-{
- MachineState *ms = MACHINE(obj);
-
- g_free(ms->firmware);
- ms->firmware = g_strdup(value);
-}
-
-static bool machine_get_iommu(Object *obj, Error **errp)
-{
- MachineState *ms = MACHINE(obj);
-
- return ms->iommu;
-}
-
-static void machine_set_iommu(Object *obj, bool value, Error **errp)
-{
- MachineState *ms = MACHINE(obj);
-
- ms->iommu = value;
-}
-
-static void machine_set_suppress_vmdesc(Object *obj, bool value, Error **errp)
-{
- MachineState *ms = MACHINE(obj);
-
- ms->suppress_vmdesc = value;
-}
-
-static bool machine_get_suppress_vmdesc(Object *obj, Error **errp)
-{
- MachineState *ms = MACHINE(obj);
-
- return ms->suppress_vmdesc;
-}
-
-static void machine_set_enforce_config_section(Object *obj, bool value,
- Error **errp)
-{
- MachineState *ms = MACHINE(obj);
-
- ms->enforce_config_section = value;
-}
-
-static bool machine_get_enforce_config_section(Object *obj, Error **errp)
-{
- MachineState *ms = MACHINE(obj);
-
- return ms->enforce_config_section;
-}
-
-static int error_on_sysbus_device(SysBusDevice *sbdev, void *opaque)
-{
- error_report("Option '-device %s' cannot be handled by this machine",
- object_class_get_name(object_get_class(OBJECT(sbdev))));
- exit(1);
-}
-
-static void machine_init_notify(Notifier *notifier, void *data)
-{
- Object *machine = qdev_get_machine();
- ObjectClass *oc = object_get_class(machine);
- MachineClass *mc = MACHINE_CLASS(oc);
-
- if (mc->has_dynamic_sysbus) {
- /* Our machine can handle dynamic sysbus devices, we're all good */
- return;
- }
-
- /*
- * Loop through all dynamically created devices and check whether there
- * are sysbus devices among them. If there are, error out.
- */
- foreach_dynamic_sysbus_device(error_on_sysbus_device, NULL);
-}
-
-static void machine_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- /* Default 128 MB as guest ram size */
- mc->default_ram_size = 128 * M_BYTE;
- mc->rom_file_has_mr = true;
-}
-
-static void machine_class_base_init(ObjectClass *oc, void *data)
-{
- if (!object_class_is_abstract(oc)) {
- MachineClass *mc = MACHINE_CLASS(oc);
- const char *cname = object_class_get_name(oc);
- assert(g_str_has_suffix(cname, TYPE_MACHINE_SUFFIX));
- mc->name = g_strndup(cname,
- strlen(cname) - strlen(TYPE_MACHINE_SUFFIX));
- }
-}
-
-static void machine_initfn(Object *obj)
-{
- MachineState *ms = MACHINE(obj);
-
- ms->kernel_irqchip_allowed = true;
- ms->kvm_shadow_mem = -1;
- ms->dump_guest_core = true;
- ms->mem_merge = true;
-
- object_property_add_str(obj, "accel",
- machine_get_accel, machine_set_accel, NULL);
- object_property_set_description(obj, "accel",
- "Accelerator list",
- NULL);
- object_property_add(obj, "kernel-irqchip", "OnOffSplit",
- NULL,
- machine_set_kernel_irqchip,
- NULL, NULL, NULL);
- object_property_set_description(obj, "kernel-irqchip",
- "Configure KVM in-kernel irqchip",
- NULL);
- object_property_add(obj, "kvm-shadow-mem", "int",
- machine_get_kvm_shadow_mem,
- machine_set_kvm_shadow_mem,
- NULL, NULL, NULL);
- object_property_set_description(obj, "kvm-shadow-mem",
- "KVM shadow MMU size",
- NULL);
- object_property_add_str(obj, "kernel",
- machine_get_kernel, machine_set_kernel, NULL);
- object_property_set_description(obj, "kernel",
- "Linux kernel image file",
- NULL);
- object_property_add_str(obj, "initrd",
- machine_get_initrd, machine_set_initrd, NULL);
- object_property_set_description(obj, "initrd",
- "Linux initial ramdisk file",
- NULL);
- object_property_add_str(obj, "append",
- machine_get_append, machine_set_append, NULL);
- object_property_set_description(obj, "append",
- "Linux kernel command line",
- NULL);
- object_property_add_str(obj, "dtb",
- machine_get_dtb, machine_set_dtb, NULL);
- object_property_set_description(obj, "dtb",
- "Linux kernel device tree file",
- NULL);
- object_property_add_str(obj, "dumpdtb",
- machine_get_dumpdtb, machine_set_dumpdtb, NULL);
- object_property_set_description(obj, "dumpdtb",
- "Dump current dtb to a file and quit",
- NULL);
- object_property_add(obj, "phandle-start", "int",
- machine_get_phandle_start,
- machine_set_phandle_start,
- NULL, NULL, NULL);
- object_property_set_description(obj, "phandle-start",
- "The first phandle ID we may generate dynamically",
- NULL);
- object_property_add_str(obj, "dt-compatible",
- machine_get_dt_compatible,
- machine_set_dt_compatible,
- NULL);
- object_property_set_description(obj, "dt-compatible",
- "Overrides the \"compatible\" property of the dt root node",
- NULL);
- object_property_add_bool(obj, "dump-guest-core",
- machine_get_dump_guest_core,
- machine_set_dump_guest_core,
- NULL);
- object_property_set_description(obj, "dump-guest-core",
- "Include guest memory in a core dump",
- NULL);
- object_property_add_bool(obj, "mem-merge",
- machine_get_mem_merge,
- machine_set_mem_merge, NULL);
- object_property_set_description(obj, "mem-merge",
- "Enable/disable memory merge support",
- NULL);
- object_property_add_bool(obj, "usb",
- machine_get_usb,
- machine_set_usb, NULL);
- object_property_set_description(obj, "usb",
- "Set on/off to enable/disable usb",
- NULL);
- object_property_add_bool(obj, "igd-passthru",
- machine_get_igd_gfx_passthru,
- machine_set_igd_gfx_passthru, NULL);
- object_property_set_description(obj, "igd-passthru",
- "Set on/off to enable/disable igd passthrou",
- NULL);
- object_property_add_str(obj, "firmware",
- machine_get_firmware,
- machine_set_firmware, NULL);
- object_property_set_description(obj, "firmware",
- "Firmware image",
- NULL);
- object_property_add_bool(obj, "iommu",
- machine_get_iommu,
- machine_set_iommu, NULL);
- object_property_set_description(obj, "iommu",
- "Set on/off to enable/disable Intel IOMMU (VT-d)",
- NULL);
- object_property_add_bool(obj, "suppress-vmdesc",
- machine_get_suppress_vmdesc,
- machine_set_suppress_vmdesc, NULL);
- object_property_set_description(obj, "suppress-vmdesc",
- "Set on to disable self-describing migration",
- NULL);
- object_property_add_bool(obj, "enforce-config-section",
- machine_get_enforce_config_section,
- machine_set_enforce_config_section, NULL);
- object_property_set_description(obj, "enforce-config-section",
- "Set on to enforce configuration section migration",
- NULL);
-
- /* Register notifier when init is done for sysbus sanity checks */
- ms->sysbus_notifier.notify = machine_init_notify;
- qemu_add_machine_init_done_notifier(&ms->sysbus_notifier);
-}
-
-static void machine_finalize(Object *obj)
-{
- MachineState *ms = MACHINE(obj);
-
- g_free(ms->accel);
- g_free(ms->kernel_filename);
- g_free(ms->initrd_filename);
- g_free(ms->kernel_cmdline);
- g_free(ms->dtb);
- g_free(ms->dumpdtb);
- g_free(ms->dt_compatible);
- g_free(ms->firmware);
-}
-
-bool machine_usb(MachineState *machine)
-{
- return machine->usb;
-}
-
-bool machine_kernel_irqchip_allowed(MachineState *machine)
-{
- return machine->kernel_irqchip_allowed;
-}
-
-bool machine_kernel_irqchip_required(MachineState *machine)
-{
- return machine->kernel_irqchip_required;
-}
-
-bool machine_kernel_irqchip_split(MachineState *machine)
-{
- return machine->kernel_irqchip_split;
-}
-
-int machine_kvm_shadow_mem(MachineState *machine)
-{
- return machine->kvm_shadow_mem;
-}
-
-int machine_phandle_start(MachineState *machine)
-{
- return machine->phandle_start;
-}
-
-bool machine_dump_guest_core(MachineState *machine)
-{
- return machine->dump_guest_core;
-}
-
-bool machine_mem_merge(MachineState *machine)
-{
- return machine->mem_merge;
-}
-
-static const TypeInfo machine_info = {
- .name = TYPE_MACHINE,
- .parent = TYPE_OBJECT,
- .abstract = true,
- .class_size = sizeof(MachineClass),
- .class_init = machine_class_init,
- .class_base_init = machine_class_base_init,
- .instance_size = sizeof(MachineState),
- .instance_init = machine_initfn,
- .instance_finalize = machine_finalize,
-};
-
-static void machine_register_types(void)
-{
- type_register_static(&machine_info);
-}
-
-type_init(machine_register_types)
diff --git a/qemu/hw/core/nmi.c b/qemu/hw/core/nmi.c
deleted file mode 100644
index e8bcc4177..000000000
--- a/qemu/hw/core/nmi.c
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * NMI monitor handler class and helpers.
- *
- * Copyright IBM Corp., 2014
- *
- * Author: Alexey Kardashevskiy <aik@ozlabs.ru>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License,
- * or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/nmi.h"
-#include "qapi/error.h"
-#include "qapi/qmp/qerror.h"
-#include "monitor/monitor.h"
-
-struct do_nmi_s {
- int cpu_index;
- Error *err;
- bool handled;
-};
-
-static void nmi_children(Object *o, struct do_nmi_s *ns);
-
-static int do_nmi(Object *o, void *opaque)
-{
- struct do_nmi_s *ns = opaque;
- NMIState *n = (NMIState *) object_dynamic_cast(o, TYPE_NMI);
-
- if (n) {
- NMIClass *nc = NMI_GET_CLASS(n);
-
- ns->handled = true;
- nc->nmi_monitor_handler(n, ns->cpu_index, &ns->err);
- if (ns->err) {
- return -1;
- }
- }
- nmi_children(o, ns);
-
- return 0;
-}
-
-static void nmi_children(Object *o, struct do_nmi_s *ns)
-{
- object_child_foreach(o, do_nmi, ns);
-}
-
-void nmi_monitor_handle(int cpu_index, Error **errp)
-{
- struct do_nmi_s ns = {
- .cpu_index = cpu_index,
- .err = NULL,
- .handled = false
- };
-
- nmi_children(object_get_root(), &ns);
- if (ns.handled) {
- error_propagate(errp, ns.err);
- } else {
- error_setg(errp, QERR_UNSUPPORTED);
- }
-}
-
-void inject_nmi(void)
-{
-#if defined(TARGET_I386)
- CPUState *cs;
-
- CPU_FOREACH(cs) {
- X86CPU *cpu = X86_CPU(cs);
-
- if (!cpu->apic_state) {
- cpu_interrupt(cs, CPU_INTERRUPT_NMI);
- } else {
- apic_deliver_nmi(cpu->apic_state);
- }
- }
-#else
- nmi_monitor_handle(0, NULL);
-#endif
-}
-
-static const TypeInfo nmi_info = {
- .name = TYPE_NMI,
- .parent = TYPE_INTERFACE,
- .class_size = sizeof(NMIClass),
-};
-
-static void nmi_register_types(void)
-{
- type_register_static(&nmi_info);
-}
-
-type_init(nmi_register_types)
diff --git a/qemu/hw/core/null-machine.c b/qemu/hw/core/null-machine.c
deleted file mode 100644
index 0351ba782..000000000
--- a/qemu/hw/core/null-machine.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Empty machine
- *
- * Copyright IBM, Corp. 2012
- *
- * Authors:
- * Anthony Liguori <aliguori@us.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "hw/hw.h"
-#include "hw/boards.h"
-
-static void machine_none_init(MachineState *machine)
-{
-}
-
-static void machine_none_machine_init(MachineClass *mc)
-{
- mc->desc = "empty machine";
- mc->init = machine_none_init;
- mc->max_cpus = 0;
-}
-
-DEFINE_MACHINE("none", machine_none_machine_init)
diff --git a/qemu/hw/core/platform-bus.c b/qemu/hw/core/platform-bus.c
deleted file mode 100644
index 36f84ab72..000000000
--- a/qemu/hw/core/platform-bus.c
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * Platform Bus device to support dynamic Sysbus devices
- *
- * Copyright (C) 2014 Freescale Semiconductor, Inc. All rights reserved.
- *
- * Author: Alexander Graf, <agraf@suse.de>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/platform-bus.h"
-#include "exec/address-spaces.h"
-#include "qemu/error-report.h"
-#include "sysemu/sysemu.h"
-
-
-/*
- * Returns the PlatformBus IRQ number for a SysBusDevice irq number or -1 if
- * the IRQ is not mapped on this Platform bus.
- */
-int platform_bus_get_irqn(PlatformBusDevice *pbus, SysBusDevice *sbdev,
- int n)
-{
- qemu_irq sbirq = sysbus_get_connected_irq(sbdev, n);
- int i;
-
- for (i = 0; i < pbus->num_irqs; i++) {
- if (pbus->irqs[i] == sbirq) {
- return i;
- }
- }
-
- /* IRQ not mapped on platform bus */
- return -1;
-}
-
-/*
- * Returns the PlatformBus MMIO region offset for Region n of a SysBusDevice or
- * -1 if the region is not mapped on this Platform bus.
- */
-hwaddr platform_bus_get_mmio_addr(PlatformBusDevice *pbus, SysBusDevice *sbdev,
- int n)
-{
- MemoryRegion *pbus_mr = &pbus->mmio;
- MemoryRegion *sbdev_mr = sysbus_mmio_get_region(sbdev, n);
- Object *pbus_mr_obj = OBJECT(pbus_mr);
- Object *parent_mr;
-
- if (!memory_region_is_mapped(sbdev_mr)) {
- /* Region is not mapped? */
- return -1;
- }
-
- parent_mr = object_property_get_link(OBJECT(sbdev_mr), "container", NULL);
-
- assert(parent_mr);
- if (parent_mr != pbus_mr_obj) {
- /* MMIO region is not mapped on platform bus */
- return -1;
- }
-
- return object_property_get_int(OBJECT(sbdev_mr), "addr", NULL);
-}
-
-static int platform_bus_count_irqs(SysBusDevice *sbdev, void *opaque)
-{
- PlatformBusDevice *pbus = opaque;
- qemu_irq sbirq;
- int n, i;
-
- for (n = 0; ; n++) {
- if (!sysbus_has_irq(sbdev, n)) {
- break;
- }
-
- sbirq = sysbus_get_connected_irq(sbdev, n);
- for (i = 0; i < pbus->num_irqs; i++) {
- if (pbus->irqs[i] == sbirq) {
- bitmap_set(pbus->used_irqs, i, 1);
- break;
- }
- }
- }
-
- return 0;
-}
-
-/*
- * Loop through all sysbus devices and look for unassigned IRQ lines as well as
- * unassociated MMIO regions. Connect them to the platform bus if available.
- */
-static void plaform_bus_refresh_irqs(PlatformBusDevice *pbus)
-{
- bitmap_zero(pbus->used_irqs, pbus->num_irqs);
- foreach_dynamic_sysbus_device(platform_bus_count_irqs, pbus);
- pbus->done_gathering = true;
-}
-
-static void platform_bus_map_irq(PlatformBusDevice *pbus, SysBusDevice *sbdev,
- int n)
-{
- int max_irqs = pbus->num_irqs;
- int irqn;
-
- if (sysbus_is_irq_connected(sbdev, n)) {
- /* IRQ is already mapped, nothing to do */
- return;
- }
-
- irqn = find_first_zero_bit(pbus->used_irqs, max_irqs);
- if (irqn >= max_irqs) {
- error_report("Platform Bus: Can not fit IRQ line");
- exit(1);
- }
-
- set_bit(irqn, pbus->used_irqs);
- sysbus_connect_irq(sbdev, n, pbus->irqs[irqn]);
-}
-
-static void platform_bus_map_mmio(PlatformBusDevice *pbus, SysBusDevice *sbdev,
- int n)
-{
- MemoryRegion *sbdev_mr = sysbus_mmio_get_region(sbdev, n);
- uint64_t size = memory_region_size(sbdev_mr);
- uint64_t alignment = (1ULL << (63 - clz64(size + size - 1)));
- uint64_t off;
- bool found_region = false;
-
- if (memory_region_is_mapped(sbdev_mr)) {
- /* Region is already mapped, nothing to do */
- return;
- }
-
- /*
- * Look for empty space in the MMIO space that is naturally aligned with
- * the target device's memory region
- */
- for (off = 0; off < pbus->mmio_size; off += alignment) {
- if (!memory_region_find(&pbus->mmio, off, size).mr) {
- found_region = true;
- break;
- }
- }
-
- if (!found_region) {
- error_report("Platform Bus: Can not fit MMIO region of size %"PRIx64,
- size);
- exit(1);
- }
-
- /* Map the device's region into our Platform Bus MMIO space */
- memory_region_add_subregion(&pbus->mmio, off, sbdev_mr);
-}
-
-/*
- * For each sysbus device, look for unassigned IRQ lines as well as
- * unassociated MMIO regions. Connect them to the platform bus if available.
- */
-static int link_sysbus_device(SysBusDevice *sbdev, void *opaque)
-{
- PlatformBusDevice *pbus = opaque;
- int i;
-
- for (i = 0; sysbus_has_irq(sbdev, i); i++) {
- platform_bus_map_irq(pbus, sbdev, i);
- }
-
- for (i = 0; sysbus_has_mmio(sbdev, i); i++) {
- platform_bus_map_mmio(pbus, sbdev, i);
- }
-
- return 0;
-}
-
-static void platform_bus_init_notify(Notifier *notifier, void *data)
-{
- PlatformBusDevice *pb = container_of(notifier, PlatformBusDevice, notifier);
-
- /*
- * Generate a bitmap of used IRQ lines, as the user might have specified
- * them on the command line.
- */
- plaform_bus_refresh_irqs(pb);
-
- foreach_dynamic_sysbus_device(link_sysbus_device, pb);
-}
-
-static void platform_bus_realize(DeviceState *dev, Error **errp)
-{
- PlatformBusDevice *pbus;
- SysBusDevice *d;
- int i;
-
- d = SYS_BUS_DEVICE(dev);
- pbus = PLATFORM_BUS_DEVICE(dev);
-
- memory_region_init(&pbus->mmio, NULL, "platform bus", pbus->mmio_size);
- sysbus_init_mmio(d, &pbus->mmio);
-
- pbus->used_irqs = bitmap_new(pbus->num_irqs);
- pbus->irqs = g_new0(qemu_irq, pbus->num_irqs);
- for (i = 0; i < pbus->num_irqs; i++) {
- sysbus_init_irq(d, &pbus->irqs[i]);
- }
-
- /*
- * Register notifier that allows us to gather dangling devices once the
- * machine is completely assembled
- */
- pbus->notifier.notify = platform_bus_init_notify;
- qemu_add_machine_init_done_notifier(&pbus->notifier);
-}
-
-static Property platform_bus_properties[] = {
- DEFINE_PROP_UINT32("num_irqs", PlatformBusDevice, num_irqs, 0),
- DEFINE_PROP_UINT32("mmio_size", PlatformBusDevice, mmio_size, 0),
- DEFINE_PROP_END_OF_LIST()
-};
-
-static void platform_bus_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = platform_bus_realize;
- dc->props = platform_bus_properties;
-}
-
-static const TypeInfo platform_bus_info = {
- .name = TYPE_PLATFORM_BUS_DEVICE,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PlatformBusDevice),
- .class_init = platform_bus_class_init,
-};
-
-static void platform_bus_register_types(void)
-{
- type_register_static(&platform_bus_info);
-}
-
-type_init(platform_bus_register_types)
diff --git a/qemu/hw/core/ptimer.c b/qemu/hw/core/ptimer.c
deleted file mode 100644
index 153c83513..000000000
--- a/qemu/hw/core/ptimer.c
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * General purpose implementation of a simple periodic countdown timer.
- *
- * Copyright (c) 2007 CodeSourcery.
- *
- * This code is licensed under the GNU LGPL.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "qemu/timer.h"
-#include "hw/ptimer.h"
-#include "qemu/host-utils.h"
-#include "sysemu/replay.h"
-
-struct ptimer_state
-{
- uint8_t enabled; /* 0 = disabled, 1 = periodic, 2 = oneshot. */
- uint64_t limit;
- uint64_t delta;
- uint32_t period_frac;
- int64_t period;
- int64_t last_event;
- int64_t next_event;
- QEMUBH *bh;
- QEMUTimer *timer;
-};
-
-/* Use a bottom-half routine to avoid reentrancy issues. */
-static void ptimer_trigger(ptimer_state *s)
-{
- if (s->bh) {
- replay_bh_schedule_event(s->bh);
- }
-}
-
-static void ptimer_reload(ptimer_state *s)
-{
- if (s->delta == 0) {
- ptimer_trigger(s);
- s->delta = s->limit;
- }
- if (s->delta == 0 || s->period == 0) {
- fprintf(stderr, "Timer with period zero, disabling\n");
- s->enabled = 0;
- return;
- }
-
- s->last_event = s->next_event;
- s->next_event = s->last_event + s->delta * s->period;
- if (s->period_frac) {
- s->next_event += ((int64_t)s->period_frac * s->delta) >> 32;
- }
- timer_mod(s->timer, s->next_event);
-}
-
-static void ptimer_tick(void *opaque)
-{
- ptimer_state *s = (ptimer_state *)opaque;
- ptimer_trigger(s);
- s->delta = 0;
- if (s->enabled == 2) {
- s->enabled = 0;
- } else {
- ptimer_reload(s);
- }
-}
-
-uint64_t ptimer_get_count(ptimer_state *s)
-{
- int64_t now;
- uint64_t counter;
-
- if (s->enabled) {
- now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- /* Figure out the current counter value. */
- if (now - s->next_event > 0
- || s->period == 0) {
- /* Prevent timer underflowing if it should already have
- triggered. */
- counter = 0;
- } else {
- uint64_t rem;
- uint64_t div;
- int clz1, clz2;
- int shift;
-
- /* We need to divide time by period, where time is stored in
- rem (64-bit integer) and period is stored in period/period_frac
- (64.32 fixed point).
-
- Doing full precision division is hard, so scale values and
- do a 64-bit division. The result should be rounded down,
- so that the rounding error never causes the timer to go
- backwards.
- */
-
- rem = s->next_event - now;
- div = s->period;
-
- clz1 = clz64(rem);
- clz2 = clz64(div);
- shift = clz1 < clz2 ? clz1 : clz2;
-
- rem <<= shift;
- div <<= shift;
- if (shift >= 32) {
- div |= ((uint64_t)s->period_frac << (shift - 32));
- } else {
- if (shift != 0)
- div |= (s->period_frac >> (32 - shift));
- /* Look at remaining bits of period_frac and round div up if
- necessary. */
- if ((uint32_t)(s->period_frac << shift))
- div += 1;
- }
- counter = rem / div;
- }
- } else {
- counter = s->delta;
- }
- return counter;
-}
-
-void ptimer_set_count(ptimer_state *s, uint64_t count)
-{
- s->delta = count;
- if (s->enabled) {
- s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- ptimer_reload(s);
- }
-}
-
-void ptimer_run(ptimer_state *s, int oneshot)
-{
- if (s->enabled) {
- return;
- }
- if (s->period == 0) {
- fprintf(stderr, "Timer with period zero, disabling\n");
- return;
- }
- s->enabled = oneshot ? 2 : 1;
- s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- ptimer_reload(s);
-}
-
-/* Pause a timer. Note that this may cause it to "lose" time, even if it
- is immediately restarted. */
-void ptimer_stop(ptimer_state *s)
-{
- if (!s->enabled)
- return;
-
- s->delta = ptimer_get_count(s);
- timer_del(s->timer);
- s->enabled = 0;
-}
-
-/* Set counter increment interval in nanoseconds. */
-void ptimer_set_period(ptimer_state *s, int64_t period)
-{
- s->period = period;
- s->period_frac = 0;
- if (s->enabled) {
- s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- ptimer_reload(s);
- }
-}
-
-/* Set counter frequency in Hz. */
-void ptimer_set_freq(ptimer_state *s, uint32_t freq)
-{
- s->period = 1000000000ll / freq;
- s->period_frac = (1000000000ll << 32) / freq;
- if (s->enabled) {
- s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- ptimer_reload(s);
- }
-}
-
-/* Set the initial countdown value. If reload is nonzero then also set
- count = limit. */
-void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload)
-{
- /*
- * Artificially limit timeout rate to something
- * achievable under QEMU. Otherwise, QEMU spends all
- * its time generating timer interrupts, and there
- * is no forward progress.
- * About ten microseconds is the fastest that really works
- * on the current generation of host machines.
- */
-
- if (!use_icount && limit * s->period < 10000 && s->period) {
- limit = 10000 / s->period;
- }
-
- s->limit = limit;
- if (reload)
- s->delta = limit;
- if (s->enabled && reload) {
- s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- ptimer_reload(s);
- }
-}
-
-const VMStateDescription vmstate_ptimer = {
- .name = "ptimer",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(enabled, ptimer_state),
- VMSTATE_UINT64(limit, ptimer_state),
- VMSTATE_UINT64(delta, ptimer_state),
- VMSTATE_UINT32(period_frac, ptimer_state),
- VMSTATE_INT64(period, ptimer_state),
- VMSTATE_INT64(last_event, ptimer_state),
- VMSTATE_INT64(next_event, ptimer_state),
- VMSTATE_TIMER_PTR(timer, ptimer_state),
- VMSTATE_END_OF_LIST()
- }
-};
-
-ptimer_state *ptimer_init(QEMUBH *bh)
-{
- ptimer_state *s;
-
- s = (ptimer_state *)g_malloc0(sizeof(ptimer_state));
- s->bh = bh;
- s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ptimer_tick, s);
- return s;
-}
diff --git a/qemu/hw/core/qdev-properties-system.c b/qemu/hw/core/qdev-properties-system.c
deleted file mode 100644
index 891219ae0..000000000
--- a/qemu/hw/core/qdev-properties-system.c
+++ /dev/null
@@ -1,415 +0,0 @@
-/*
- * qdev property parsing and global properties
- * (parts specific for qemu-system-*)
- *
- * This file is based on code from hw/qdev-properties.c from
- * commit 074a86fccd185616469dfcdc0e157f438aebba18,
- * Copyright (c) Gerd Hoffmann <kraxel@redhat.com> and other contributors.
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "net/net.h"
-#include "hw/qdev.h"
-#include "qapi/error.h"
-#include "qapi/qmp/qerror.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
-#include "hw/block/block.h"
-#include "net/hub.h"
-#include "qapi/visitor.h"
-#include "sysemu/char.h"
-#include "sysemu/iothread.h"
-
-static void get_pointer(Object *obj, Visitor *v, Property *prop,
- char *(*print)(void *ptr),
- const char *name, Error **errp)
-{
- DeviceState *dev = DEVICE(obj);
- void **ptr = qdev_get_prop_ptr(dev, prop);
- char *p;
-
- p = *ptr ? print(*ptr) : g_strdup("");
- visit_type_str(v, name, &p, errp);
- g_free(p);
-}
-
-static void set_pointer(Object *obj, Visitor *v, Property *prop,
- void (*parse)(DeviceState *dev, const char *str,
- void **ptr, const char *propname,
- Error **errp),
- const char *name, Error **errp)
-{
- DeviceState *dev = DEVICE(obj);
- Error *local_err = NULL;
- void **ptr = qdev_get_prop_ptr(dev, prop);
- char *str;
-
- if (dev->realized) {
- qdev_prop_set_after_realize(dev, name, errp);
- return;
- }
-
- visit_type_str(v, name, &str, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
- if (!*str) {
- g_free(str);
- *ptr = NULL;
- return;
- }
- parse(dev, str, ptr, prop->name, errp);
- g_free(str);
-}
-
-/* --- drive --- */
-
-static void parse_drive(DeviceState *dev, const char *str, void **ptr,
- const char *propname, Error **errp)
-{
- BlockBackend *blk;
-
- blk = blk_by_name(str);
- if (!blk) {
- error_setg(errp, "Property '%s.%s' can't find value '%s'",
- object_get_typename(OBJECT(dev)), propname, str);
- return;
- }
- if (blk_attach_dev(blk, dev) < 0) {
- DriveInfo *dinfo = blk_legacy_dinfo(blk);
-
- if (dinfo->type != IF_NONE) {
- error_setg(errp, "Drive '%s' is already in use because "
- "it has been automatically connected to another "
- "device (did you need 'if=none' in the drive options?)",
- str);
- } else {
- error_setg(errp, "Drive '%s' is already in use by another device",
- str);
- }
- return;
- }
- *ptr = blk;
-}
-
-static void release_drive(Object *obj, const char *name, void *opaque)
-{
- DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
- BlockBackend **ptr = qdev_get_prop_ptr(dev, prop);
-
- if (*ptr) {
- blk_detach_dev(*ptr, dev);
- blockdev_auto_del(*ptr);
- }
-}
-
-static char *print_drive(void *ptr)
-{
- return g_strdup(blk_name(ptr));
-}
-
-static void get_drive(Object *obj, Visitor *v, const char *name, void *opaque,
- Error **errp)
-{
- get_pointer(obj, v, opaque, print_drive, name, errp);
-}
-
-static void set_drive(Object *obj, Visitor *v, const char *name, void *opaque,
- Error **errp)
-{
- set_pointer(obj, v, opaque, parse_drive, name, errp);
-}
-
-PropertyInfo qdev_prop_drive = {
- .name = "str",
- .description = "ID of a drive to use as a backend",
- .get = get_drive,
- .set = set_drive,
- .release = release_drive,
-};
-
-/* --- character device --- */
-
-static void parse_chr(DeviceState *dev, const char *str, void **ptr,
- const char *propname, Error **errp)
-{
- CharDriverState *chr = qemu_chr_find(str);
- if (chr == NULL) {
- error_setg(errp, "Property '%s.%s' can't find value '%s'",
- object_get_typename(OBJECT(dev)), propname, str);
- return;
- }
- if (qemu_chr_fe_claim(chr) != 0) {
- error_setg(errp, "Property '%s.%s' can't take value '%s', it's in use",
- object_get_typename(OBJECT(dev)), propname, str);
- return;
- }
- *ptr = chr;
-}
-
-static void release_chr(Object *obj, const char *name, void *opaque)
-{
- DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
- CharDriverState **ptr = qdev_get_prop_ptr(dev, prop);
- CharDriverState *chr = *ptr;
-
- if (chr) {
- qemu_chr_add_handlers(chr, NULL, NULL, NULL, NULL);
- qemu_chr_fe_release(chr);
- }
-}
-
-
-static char *print_chr(void *ptr)
-{
- CharDriverState *chr = ptr;
- const char *val = chr->label ? chr->label : "";
-
- return g_strdup(val);
-}
-
-static void get_chr(Object *obj, Visitor *v, const char *name, void *opaque,
- Error **errp)
-{
- get_pointer(obj, v, opaque, print_chr, name, errp);
-}
-
-static void set_chr(Object *obj, Visitor *v, const char *name, void *opaque,
- Error **errp)
-{
- set_pointer(obj, v, opaque, parse_chr, name, errp);
-}
-
-PropertyInfo qdev_prop_chr = {
- .name = "str",
- .description = "ID of a chardev to use as a backend",
- .get = get_chr,
- .set = set_chr,
- .release = release_chr,
-};
-
-/* --- netdev device --- */
-static void get_netdev(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
- NICPeers *peers_ptr = qdev_get_prop_ptr(dev, prop);
- char *p = g_strdup(peers_ptr->ncs[0] ? peers_ptr->ncs[0]->name : "");
-
- visit_type_str(v, name, &p, errp);
- g_free(p);
-}
-
-static void set_netdev(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
- NICPeers *peers_ptr = qdev_get_prop_ptr(dev, prop);
- NetClientState **ncs = peers_ptr->ncs;
- NetClientState *peers[MAX_QUEUE_NUM];
- Error *local_err = NULL;
- int queues, err = 0, i = 0;
- char *str;
-
- if (dev->realized) {
- qdev_prop_set_after_realize(dev, name, errp);
- return;
- }
-
- visit_type_str(v, name, &str, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- queues = qemu_find_net_clients_except(str, peers,
- NET_CLIENT_OPTIONS_KIND_NIC,
- MAX_QUEUE_NUM);
- if (queues == 0) {
- err = -ENOENT;
- goto out;
- }
-
- if (queues > MAX_QUEUE_NUM) {
- error_setg(errp, "queues of backend '%s'(%d) exceeds QEMU limitation(%d)",
- str, queues, MAX_QUEUE_NUM);
- goto out;
- }
-
- for (i = 0; i < queues; i++) {
- if (peers[i] == NULL) {
- err = -ENOENT;
- goto out;
- }
-
- if (peers[i]->peer) {
- err = -EEXIST;
- goto out;
- }
-
- if (ncs[i]) {
- err = -EINVAL;
- goto out;
- }
-
- ncs[i] = peers[i];
- ncs[i]->queue_index = i;
- }
-
- peers_ptr->queues = queues;
-
-out:
- error_set_from_qdev_prop_error(errp, err, dev, prop, str);
- g_free(str);
-}
-
-PropertyInfo qdev_prop_netdev = {
- .name = "str",
- .description = "ID of a netdev to use as a backend",
- .get = get_netdev,
- .set = set_netdev,
-};
-
-/* --- vlan --- */
-
-static int print_vlan(DeviceState *dev, Property *prop, char *dest, size_t len)
-{
- NetClientState **ptr = qdev_get_prop_ptr(dev, prop);
-
- if (*ptr) {
- int id;
- if (!net_hub_id_for_client(*ptr, &id)) {
- return snprintf(dest, len, "%d", id);
- }
- }
-
- return snprintf(dest, len, "<null>");
-}
-
-static void get_vlan(Object *obj, Visitor *v, const char *name, void *opaque,
- Error **errp)
-{
- DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
- NetClientState **ptr = qdev_get_prop_ptr(dev, prop);
- int32_t id = -1;
-
- if (*ptr) {
- int hub_id;
- if (!net_hub_id_for_client(*ptr, &hub_id)) {
- id = hub_id;
- }
- }
-
- visit_type_int32(v, name, &id, errp);
-}
-
-static void set_vlan(Object *obj, Visitor *v, const char *name, void *opaque,
- Error **errp)
-{
- DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
- NICPeers *peers_ptr = qdev_get_prop_ptr(dev, prop);
- NetClientState **ptr = &peers_ptr->ncs[0];
- Error *local_err = NULL;
- int32_t id;
- NetClientState *hubport;
-
- if (dev->realized) {
- qdev_prop_set_after_realize(dev, name, errp);
- return;
- }
-
- visit_type_int32(v, name, &id, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
- if (id == -1) {
- *ptr = NULL;
- return;
- }
- if (*ptr) {
- error_set_from_qdev_prop_error(errp, -EINVAL, dev, prop, name);
- return;
- }
-
- hubport = net_hub_port_find(id);
- if (!hubport) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
- name, prop->info->name);
- return;
- }
- *ptr = hubport;
-}
-
-PropertyInfo qdev_prop_vlan = {
- .name = "int32",
- .description = "Integer VLAN id to connect to",
- .print = print_vlan,
- .get = get_vlan,
- .set = set_vlan,
-};
-
-void qdev_prop_set_drive(DeviceState *dev, const char *name,
- BlockBackend *value, Error **errp)
-{
- object_property_set_str(OBJECT(dev), value ? blk_name(value) : "",
- name, errp);
-}
-
-void qdev_prop_set_chr(DeviceState *dev, const char *name,
- CharDriverState *value)
-{
- assert(!value || value->label);
- object_property_set_str(OBJECT(dev),
- value ? value->label : "", name, &error_abort);
-}
-
-void qdev_prop_set_netdev(DeviceState *dev, const char *name,
- NetClientState *value)
-{
- assert(!value || value->name);
- object_property_set_str(OBJECT(dev),
- value ? value->name : "", name, &error_abort);
-}
-
-void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
-{
- qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a);
- if (nd->netdev) {
- qdev_prop_set_netdev(dev, "netdev", nd->netdev);
- }
- if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
- object_property_find(OBJECT(dev), "vectors", NULL)) {
- qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
- }
- nd->instantiated = 1;
-}
-
-static int qdev_add_one_global(void *opaque, QemuOpts *opts, Error **errp)
-{
- GlobalProperty *g;
-
- g = g_malloc0(sizeof(*g));
- g->driver = qemu_opt_get(opts, "driver");
- g->property = qemu_opt_get(opts, "property");
- g->value = qemu_opt_get(opts, "value");
- g->user_provided = true;
- qdev_prop_register_global(g);
- return 0;
-}
-
-void qemu_add_globals(void)
-{
- qemu_opts_foreach(qemu_find_opts("global"),
- qdev_add_one_global, NULL, NULL);
-}
diff --git a/qemu/hw/core/qdev-properties.c b/qemu/hw/core/qdev-properties.c
deleted file mode 100644
index 737d29c63..000000000
--- a/qemu/hw/core/qdev-properties.c
+++ /dev/null
@@ -1,1131 +0,0 @@
-#include "qemu/osdep.h"
-#include "net/net.h"
-#include "hw/qdev.h"
-#include "qapi/error.h"
-#include "hw/pci/pci.h"
-#include "qapi/qmp/qerror.h"
-#include "qemu/error-report.h"
-#include "sysemu/block-backend.h"
-#include "hw/block/block.h"
-#include "net/hub.h"
-#include "qapi/visitor.h"
-#include "sysemu/char.h"
-
-void qdev_prop_set_after_realize(DeviceState *dev, const char *name,
- Error **errp)
-{
- if (dev->id) {
- error_setg(errp, "Attempt to set property '%s' on device '%s' "
- "(type '%s') after it was realized", name, dev->id,
- object_get_typename(OBJECT(dev)));
- } else {
- error_setg(errp, "Attempt to set property '%s' on anonymous device "
- "(type '%s') after it was realized", name,
- object_get_typename(OBJECT(dev)));
- }
-}
-
-void qdev_prop_allow_set_link_before_realize(Object *obj, const char *name,
- Object *val, Error **errp)
-{
- DeviceState *dev = DEVICE(obj);
-
- if (dev->realized) {
- error_setg(errp, "Attempt to set link property '%s' on device '%s' "
- "(type '%s') after it was realized",
- name, dev->id, object_get_typename(obj));
- }
-}
-
-void *qdev_get_prop_ptr(DeviceState *dev, Property *prop)
-{
- void *ptr = dev;
- ptr += prop->offset;
- return ptr;
-}
-
-static void get_enum(Object *obj, Visitor *v, const char *name, void *opaque,
- Error **errp)
-{
- DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
- int *ptr = qdev_get_prop_ptr(dev, prop);
-
- visit_type_enum(v, prop->name, ptr, prop->info->enum_table, errp);
-}
-
-static void set_enum(Object *obj, Visitor *v, const char *name, void *opaque,
- Error **errp)
-{
- DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
- int *ptr = qdev_get_prop_ptr(dev, prop);
-
- if (dev->realized) {
- qdev_prop_set_after_realize(dev, name, errp);
- return;
- }
-
- visit_type_enum(v, prop->name, ptr, prop->info->enum_table, errp);
-}
-
-/* Bit */
-
-static uint32_t qdev_get_prop_mask(Property *prop)
-{
- assert(prop->info == &qdev_prop_bit);
- return 0x1 << prop->bitnr;
-}
-
-static void bit_prop_set(DeviceState *dev, Property *props, bool val)
-{
- uint32_t *p = qdev_get_prop_ptr(dev, props);
- uint32_t mask = qdev_get_prop_mask(props);
- if (val) {
- *p |= mask;
- } else {
- *p &= ~mask;
- }
-}
-
-static void prop_get_bit(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
- uint32_t *p = qdev_get_prop_ptr(dev, prop);
- bool value = (*p & qdev_get_prop_mask(prop)) != 0;
-
- visit_type_bool(v, name, &value, errp);
-}
-
-static void prop_set_bit(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
- Error *local_err = NULL;
- bool value;
-
- if (dev->realized) {
- qdev_prop_set_after_realize(dev, name, errp);
- return;
- }
-
- visit_type_bool(v, name, &value, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
- bit_prop_set(dev, prop, value);
-}
-
-PropertyInfo qdev_prop_bit = {
- .name = "bool",
- .description = "on/off",
- .get = prop_get_bit,
- .set = prop_set_bit,
-};
-
-/* Bit64 */
-
-static uint64_t qdev_get_prop_mask64(Property *prop)
-{
- assert(prop->info == &qdev_prop_bit64);
- return 0x1ull << prop->bitnr;
-}
-
-static void bit64_prop_set(DeviceState *dev, Property *props, bool val)
-{
- uint64_t *p = qdev_get_prop_ptr(dev, props);
- uint64_t mask = qdev_get_prop_mask64(props);
- if (val) {
- *p |= mask;
- } else {
- *p &= ~mask;
- }
-}
-
-static void prop_get_bit64(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
- uint64_t *p = qdev_get_prop_ptr(dev, prop);
- bool value = (*p & qdev_get_prop_mask64(prop)) != 0;
-
- visit_type_bool(v, name, &value, errp);
-}
-
-static void prop_set_bit64(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
- Error *local_err = NULL;
- bool value;
-
- if (dev->realized) {
- qdev_prop_set_after_realize(dev, name, errp);
- return;
- }
-
- visit_type_bool(v, name, &value, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
- bit64_prop_set(dev, prop, value);
-}
-
-PropertyInfo qdev_prop_bit64 = {
- .name = "bool",
- .description = "on/off",
- .get = prop_get_bit64,
- .set = prop_set_bit64,
-};
-
-/* --- bool --- */
-
-static void get_bool(Object *obj, Visitor *v, const char *name, void *opaque,
- Error **errp)
-{
- DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
- bool *ptr = qdev_get_prop_ptr(dev, prop);
-
- visit_type_bool(v, name, ptr, errp);
-}
-
-static void set_bool(Object *obj, Visitor *v, const char *name, void *opaque,
- Error **errp)
-{
- DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
- bool *ptr = qdev_get_prop_ptr(dev, prop);
-
- if (dev->realized) {
- qdev_prop_set_after_realize(dev, name, errp);
- return;
- }
-
- visit_type_bool(v, name, ptr, errp);
-}
-
-PropertyInfo qdev_prop_bool = {
- .name = "bool",
- .get = get_bool,
- .set = set_bool,
-};
-
-/* --- 8bit integer --- */
-
-static void get_uint8(Object *obj, Visitor *v, const char *name, void *opaque,
- Error **errp)
-{
- DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
- uint8_t *ptr = qdev_get_prop_ptr(dev, prop);
-
- visit_type_uint8(v, name, ptr, errp);
-}
-
-static void set_uint8(Object *obj, Visitor *v, const char *name, void *opaque,
- Error **errp)
-{
- DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
- uint8_t *ptr = qdev_get_prop_ptr(dev, prop);
-
- if (dev->realized) {
- qdev_prop_set_after_realize(dev, name, errp);
- return;
- }
-
- visit_type_uint8(v, name, ptr, errp);
-}
-
-PropertyInfo qdev_prop_uint8 = {
- .name = "uint8",
- .get = get_uint8,
- .set = set_uint8,
-};
-
-/* --- 16bit integer --- */
-
-static void get_uint16(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
- uint16_t *ptr = qdev_get_prop_ptr(dev, prop);
-
- visit_type_uint16(v, name, ptr, errp);
-}
-
-static void set_uint16(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
- uint16_t *ptr = qdev_get_prop_ptr(dev, prop);
-
- if (dev->realized) {
- qdev_prop_set_after_realize(dev, name, errp);
- return;
- }
-
- visit_type_uint16(v, name, ptr, errp);
-}
-
-PropertyInfo qdev_prop_uint16 = {
- .name = "uint16",
- .get = get_uint16,
- .set = set_uint16,
-};
-
-/* --- 32bit integer --- */
-
-static void get_uint32(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
- uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
-
- visit_type_uint32(v, name, ptr, errp);
-}
-
-static void set_uint32(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
- uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
-
- if (dev->realized) {
- qdev_prop_set_after_realize(dev, name, errp);
- return;
- }
-
- visit_type_uint32(v, name, ptr, errp);
-}
-
-static void get_int32(Object *obj, Visitor *v, const char *name, void *opaque,
- Error **errp)
-{
- DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
- int32_t *ptr = qdev_get_prop_ptr(dev, prop);
-
- visit_type_int32(v, name, ptr, errp);
-}
-
-static void set_int32(Object *obj, Visitor *v, const char *name, void *opaque,
- Error **errp)
-{
- DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
- int32_t *ptr = qdev_get_prop_ptr(dev, prop);
-
- if (dev->realized) {
- qdev_prop_set_after_realize(dev, name, errp);
- return;
- }
-
- visit_type_int32(v, name, ptr, errp);
-}
-
-PropertyInfo qdev_prop_uint32 = {
- .name = "uint32",
- .get = get_uint32,
- .set = set_uint32,
-};
-
-PropertyInfo qdev_prop_int32 = {
- .name = "int32",
- .get = get_int32,
- .set = set_int32,
-};
-
-/* --- 64bit integer --- */
-
-static void get_uint64(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
- uint64_t *ptr = qdev_get_prop_ptr(dev, prop);
-
- visit_type_uint64(v, name, ptr, errp);
-}
-
-static void set_uint64(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
- uint64_t *ptr = qdev_get_prop_ptr(dev, prop);
-
- if (dev->realized) {
- qdev_prop_set_after_realize(dev, name, errp);
- return;
- }
-
- visit_type_uint64(v, name, ptr, errp);
-}
-
-PropertyInfo qdev_prop_uint64 = {
- .name = "uint64",
- .get = get_uint64,
- .set = set_uint64,
-};
-
-/* --- string --- */
-
-static void release_string(Object *obj, const char *name, void *opaque)
-{
- Property *prop = opaque;
- g_free(*(char **)qdev_get_prop_ptr(DEVICE(obj), prop));
-}
-
-static void get_string(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
- char **ptr = qdev_get_prop_ptr(dev, prop);
-
- if (!*ptr) {
- char *str = (char *)"";
- visit_type_str(v, name, &str, errp);
- } else {
- visit_type_str(v, name, ptr, errp);
- }
-}
-
-static void set_string(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
- char **ptr = qdev_get_prop_ptr(dev, prop);
- Error *local_err = NULL;
- char *str;
-
- if (dev->realized) {
- qdev_prop_set_after_realize(dev, name, errp);
- return;
- }
-
- visit_type_str(v, name, &str, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
- g_free(*ptr);
- *ptr = str;
-}
-
-PropertyInfo qdev_prop_string = {
- .name = "str",
- .release = release_string,
- .get = get_string,
- .set = set_string,
-};
-
-/* --- pointer --- */
-
-/* Not a proper property, just for dirty hacks. TODO Remove it! */
-PropertyInfo qdev_prop_ptr = {
- .name = "ptr",
-};
-
-/* --- mac address --- */
-
-/*
- * accepted syntax versions:
- * 01:02:03:04:05:06
- * 01-02-03-04-05-06
- */
-static void get_mac(Object *obj, Visitor *v, const char *name, void *opaque,
- Error **errp)
-{
- DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
- MACAddr *mac = qdev_get_prop_ptr(dev, prop);
- char buffer[2 * 6 + 5 + 1];
- char *p = buffer;
-
- snprintf(buffer, sizeof(buffer), "%02x:%02x:%02x:%02x:%02x:%02x",
- mac->a[0], mac->a[1], mac->a[2],
- mac->a[3], mac->a[4], mac->a[5]);
-
- visit_type_str(v, name, &p, errp);
-}
-
-static void set_mac(Object *obj, Visitor *v, const char *name, void *opaque,
- Error **errp)
-{
- DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
- MACAddr *mac = qdev_get_prop_ptr(dev, prop);
- Error *local_err = NULL;
- int i, pos;
- char *str, *p;
-
- if (dev->realized) {
- qdev_prop_set_after_realize(dev, name, errp);
- return;
- }
-
- visit_type_str(v, name, &str, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- for (i = 0, pos = 0; i < 6; i++, pos += 3) {
- if (!qemu_isxdigit(str[pos])) {
- goto inval;
- }
- if (!qemu_isxdigit(str[pos+1])) {
- goto inval;
- }
- if (i == 5) {
- if (str[pos+2] != '\0') {
- goto inval;
- }
- } else {
- if (str[pos+2] != ':' && str[pos+2] != '-') {
- goto inval;
- }
- }
- mac->a[i] = strtol(str+pos, &p, 16);
- }
- g_free(str);
- return;
-
-inval:
- error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
- g_free(str);
-}
-
-PropertyInfo qdev_prop_macaddr = {
- .name = "str",
- .description = "Ethernet 6-byte MAC Address, example: 52:54:00:12:34:56",
- .get = get_mac,
- .set = set_mac,
-};
-
-/* --- on/off/auto --- */
-
-PropertyInfo qdev_prop_on_off_auto = {
- .name = "OnOffAuto",
- .description = "on/off/auto",
- .enum_table = OnOffAuto_lookup,
- .get = get_enum,
- .set = set_enum,
-};
-
-/* --- lost tick policy --- */
-
-QEMU_BUILD_BUG_ON(sizeof(LostTickPolicy) != sizeof(int));
-
-PropertyInfo qdev_prop_losttickpolicy = {
- .name = "LostTickPolicy",
- .enum_table = LostTickPolicy_lookup,
- .get = get_enum,
- .set = set_enum,
-};
-
-/* --- BIOS CHS translation */
-
-QEMU_BUILD_BUG_ON(sizeof(BiosAtaTranslation) != sizeof(int));
-
-PropertyInfo qdev_prop_bios_chs_trans = {
- .name = "BiosAtaTranslation",
- .description = "Logical CHS translation algorithm, "
- "auto/none/lba/large/rechs",
- .enum_table = BiosAtaTranslation_lookup,
- .get = get_enum,
- .set = set_enum,
-};
-
-/* --- FDC default drive types */
-
-PropertyInfo qdev_prop_fdc_drive_type = {
- .name = "FdcDriveType",
- .description = "FDC drive type, "
- "144/288/120/none/auto",
- .enum_table = FloppyDriveType_lookup,
- .get = get_enum,
- .set = set_enum
-};
-
-/* --- pci address --- */
-
-/*
- * bus-local address, i.e. "$slot" or "$slot.$fn"
- */
-static void set_pci_devfn(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
- int32_t value, *ptr = qdev_get_prop_ptr(dev, prop);
- unsigned int slot, fn, n;
- Error *local_err = NULL;
- char *str;
-
- if (dev->realized) {
- qdev_prop_set_after_realize(dev, name, errp);
- return;
- }
-
- visit_type_str(v, name, &str, &local_err);
- if (local_err) {
- error_free(local_err);
- local_err = NULL;
- visit_type_int32(v, name, &value, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- } else if (value < -1 || value > 255) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
- name ? name : "null", "pci_devfn");
- } else {
- *ptr = value;
- }
- return;
- }
-
- if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) {
- fn = 0;
- if (sscanf(str, "%x%n", &slot, &n) != 1) {
- goto invalid;
- }
- }
- if (str[n] != '\0' || fn > 7 || slot > 31) {
- goto invalid;
- }
- *ptr = slot << 3 | fn;
- g_free(str);
- return;
-
-invalid:
- error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
- g_free(str);
-}
-
-static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest,
- size_t len)
-{
- int32_t *ptr = qdev_get_prop_ptr(dev, prop);
-
- if (*ptr == -1) {
- return snprintf(dest, len, "<unset>");
- } else {
- return snprintf(dest, len, "%02x.%x", *ptr >> 3, *ptr & 7);
- }
-}
-
-PropertyInfo qdev_prop_pci_devfn = {
- .name = "int32",
- .description = "Slot and optional function number, example: 06.0 or 06",
- .print = print_pci_devfn,
- .get = get_int32,
- .set = set_pci_devfn,
-};
-
-/* --- blocksize --- */
-
-static void set_blocksize(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
- uint16_t value, *ptr = qdev_get_prop_ptr(dev, prop);
- Error *local_err = NULL;
- const int64_t min = 512;
- const int64_t max = 32768;
-
- if (dev->realized) {
- qdev_prop_set_after_realize(dev, name, errp);
- return;
- }
-
- visit_type_uint16(v, name, &value, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
- /* value of 0 means "unset" */
- if (value && (value < min || value > max)) {
- error_setg(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE,
- dev->id ? : "", name, (int64_t)value, min, max);
- return;
- }
-
- /* We rely on power-of-2 blocksizes for bitmasks */
- if ((value & (value - 1)) != 0) {
- error_setg(errp,
- "Property %s.%s doesn't take value '%" PRId64 "', it's not a power of 2",
- dev->id ?: "", name, (int64_t)value);
- return;
- }
-
- *ptr = value;
-}
-
-PropertyInfo qdev_prop_blocksize = {
- .name = "uint16",
- .description = "A power of two between 512 and 32768",
- .get = get_uint16,
- .set = set_blocksize,
-};
-
-/* --- pci host address --- */
-
-static void get_pci_host_devaddr(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
- PCIHostDeviceAddress *addr = qdev_get_prop_ptr(dev, prop);
- char buffer[] = "xxxx:xx:xx.x";
- char *p = buffer;
- int rc = 0;
-
- rc = snprintf(buffer, sizeof(buffer), "%04x:%02x:%02x.%d",
- addr->domain, addr->bus, addr->slot, addr->function);
- assert(rc == sizeof(buffer) - 1);
-
- visit_type_str(v, name, &p, errp);
-}
-
-/*
- * Parse [<domain>:]<bus>:<slot>.<func>
- * if <domain> is not supplied, it's assumed to be 0.
- */
-static void set_pci_host_devaddr(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
- PCIHostDeviceAddress *addr = qdev_get_prop_ptr(dev, prop);
- Error *local_err = NULL;
- char *str, *p;
- char *e;
- unsigned long val;
- unsigned long dom = 0, bus = 0;
- unsigned int slot = 0, func = 0;
-
- if (dev->realized) {
- qdev_prop_set_after_realize(dev, name, errp);
- return;
- }
-
- visit_type_str(v, name, &str, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- p = str;
- val = strtoul(p, &e, 16);
- if (e == p || *e != ':') {
- goto inval;
- }
- bus = val;
-
- p = e + 1;
- val = strtoul(p, &e, 16);
- if (e == p) {
- goto inval;
- }
- if (*e == ':') {
- dom = bus;
- bus = val;
- p = e + 1;
- val = strtoul(p, &e, 16);
- if (e == p) {
- goto inval;
- }
- }
- slot = val;
-
- if (*e != '.') {
- goto inval;
- }
- p = e + 1;
- val = strtoul(p, &e, 10);
- if (e == p) {
- goto inval;
- }
- func = val;
-
- if (dom > 0xffff || bus > 0xff || slot > 0x1f || func > 7) {
- goto inval;
- }
-
- if (*e) {
- goto inval;
- }
-
- addr->domain = dom;
- addr->bus = bus;
- addr->slot = slot;
- addr->function = func;
-
- g_free(str);
- return;
-
-inval:
- error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
- g_free(str);
-}
-
-PropertyInfo qdev_prop_pci_host_devaddr = {
- .name = "str",
- .description = "Address (bus/device/function) of "
- "the host device, example: 04:10.0",
- .get = get_pci_host_devaddr,
- .set = set_pci_host_devaddr,
-};
-
-/* --- support for array properties --- */
-
-/* Used as an opaque for the object properties we add for each
- * array element. Note that the struct Property must be first
- * in the struct so that a pointer to this works as the opaque
- * for the underlying element's property hooks as well as for
- * our own release callback.
- */
-typedef struct {
- struct Property prop;
- char *propname;
- ObjectPropertyRelease *release;
-} ArrayElementProperty;
-
-/* object property release callback for array element properties:
- * we call the underlying element's property release hook, and
- * then free the memory we allocated when we added the property.
- */
-static void array_element_release(Object *obj, const char *name, void *opaque)
-{
- ArrayElementProperty *p = opaque;
- if (p->release) {
- p->release(obj, name, opaque);
- }
- g_free(p->propname);
- g_free(p);
-}
-
-static void set_prop_arraylen(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- /* Setter for the property which defines the length of a
- * variable-sized property array. As well as actually setting the
- * array-length field in the device struct, we have to create the
- * array itself and dynamically add the corresponding properties.
- */
- DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
- uint32_t *alenptr = qdev_get_prop_ptr(dev, prop);
- void **arrayptr = (void *)dev + prop->arrayoffset;
- Error *local_err = NULL;
- void *eltptr;
- const char *arrayname;
- int i;
-
- if (dev->realized) {
- qdev_prop_set_after_realize(dev, name, errp);
- return;
- }
- if (*alenptr) {
- error_setg(errp, "array size property %s may not be set more than once",
- name);
- return;
- }
- visit_type_uint32(v, name, alenptr, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
- if (!*alenptr) {
- return;
- }
-
- /* DEFINE_PROP_ARRAY guarantees that name should start with this prefix;
- * strip it off so we can get the name of the array itself.
- */
- assert(strncmp(name, PROP_ARRAY_LEN_PREFIX,
- strlen(PROP_ARRAY_LEN_PREFIX)) == 0);
- arrayname = name + strlen(PROP_ARRAY_LEN_PREFIX);
-
- /* Note that it is the responsibility of the individual device's deinit
- * to free the array proper.
- */
- *arrayptr = eltptr = g_malloc0(*alenptr * prop->arrayfieldsize);
- for (i = 0; i < *alenptr; i++, eltptr += prop->arrayfieldsize) {
- char *propname = g_strdup_printf("%s[%d]", arrayname, i);
- ArrayElementProperty *arrayprop = g_new0(ArrayElementProperty, 1);
- arrayprop->release = prop->arrayinfo->release;
- arrayprop->propname = propname;
- arrayprop->prop.info = prop->arrayinfo;
- arrayprop->prop.name = propname;
- /* This ugly piece of pointer arithmetic sets up the offset so
- * that when the underlying get/set hooks call qdev_get_prop_ptr
- * they get the right answer despite the array element not actually
- * being inside the device struct.
- */
- arrayprop->prop.offset = eltptr - (void *)dev;
- assert(qdev_get_prop_ptr(dev, &arrayprop->prop) == eltptr);
- object_property_add(obj, propname,
- arrayprop->prop.info->name,
- arrayprop->prop.info->get,
- arrayprop->prop.info->set,
- array_element_release,
- arrayprop, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
- }
-}
-
-PropertyInfo qdev_prop_arraylen = {
- .name = "uint32",
- .get = get_uint32,
- .set = set_prop_arraylen,
-};
-
-/* --- public helpers --- */
-
-static Property *qdev_prop_walk(Property *props, const char *name)
-{
- if (!props) {
- return NULL;
- }
- while (props->name) {
- if (strcmp(props->name, name) == 0) {
- return props;
- }
- props++;
- }
- return NULL;
-}
-
-static Property *qdev_prop_find(DeviceState *dev, const char *name)
-{
- ObjectClass *class;
- Property *prop;
-
- /* device properties */
- class = object_get_class(OBJECT(dev));
- do {
- prop = qdev_prop_walk(DEVICE_CLASS(class)->props, name);
- if (prop) {
- return prop;
- }
- class = object_class_get_parent(class);
- } while (class != object_class_by_name(TYPE_DEVICE));
-
- return NULL;
-}
-
-void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev,
- Property *prop, const char *value)
-{
- switch (ret) {
- case -EEXIST:
- error_setg(errp, "Property '%s.%s' can't take value '%s', it's in use",
- object_get_typename(OBJECT(dev)), prop->name, value);
- break;
- default:
- case -EINVAL:
- error_setg(errp, QERR_PROPERTY_VALUE_BAD,
- object_get_typename(OBJECT(dev)), prop->name, value);
- break;
- case -ENOENT:
- error_setg(errp, "Property '%s.%s' can't find value '%s'",
- object_get_typename(OBJECT(dev)), prop->name, value);
- break;
- case 0:
- break;
- }
-}
-
-void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value)
-{
- object_property_set_bool(OBJECT(dev), value, name, &error_abort);
-}
-
-void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value)
-{
- object_property_set_int(OBJECT(dev), value, name, &error_abort);
-}
-
-void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value)
-{
- object_property_set_int(OBJECT(dev), value, name, &error_abort);
-}
-
-void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value)
-{
- object_property_set_int(OBJECT(dev), value, name, &error_abort);
-}
-
-void qdev_prop_set_int32(DeviceState *dev, const char *name, int32_t value)
-{
- object_property_set_int(OBJECT(dev), value, name, &error_abort);
-}
-
-void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value)
-{
- object_property_set_int(OBJECT(dev), value, name, &error_abort);
-}
-
-void qdev_prop_set_string(DeviceState *dev, const char *name, const char *value)
-{
- object_property_set_str(OBJECT(dev), value, name, &error_abort);
-}
-
-void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value)
-{
- char str[2 * 6 + 5 + 1];
- snprintf(str, sizeof(str), "%02x:%02x:%02x:%02x:%02x:%02x",
- value[0], value[1], value[2], value[3], value[4], value[5]);
-
- object_property_set_str(OBJECT(dev), str, name, &error_abort);
-}
-
-void qdev_prop_set_enum(DeviceState *dev, const char *name, int value)
-{
- Property *prop;
-
- prop = qdev_prop_find(dev, name);
- object_property_set_str(OBJECT(dev), prop->info->enum_table[value],
- name, &error_abort);
-}
-
-void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value)
-{
- Property *prop;
- void **ptr;
-
- prop = qdev_prop_find(dev, name);
- assert(prop && prop->info == &qdev_prop_ptr);
- ptr = qdev_get_prop_ptr(dev, prop);
- *ptr = value;
-}
-
-static QTAILQ_HEAD(, GlobalProperty) global_props =
- QTAILQ_HEAD_INITIALIZER(global_props);
-
-void qdev_prop_register_global(GlobalProperty *prop)
-{
- QTAILQ_INSERT_TAIL(&global_props, prop, next);
-}
-
-void qdev_prop_register_global_list(GlobalProperty *props)
-{
- int i;
-
- for (i = 0; props[i].driver != NULL; i++) {
- qdev_prop_register_global(props+i);
- }
-}
-
-int qdev_prop_check_globals(void)
-{
- GlobalProperty *prop;
- int ret = 0;
-
- QTAILQ_FOREACH(prop, &global_props, next) {
- ObjectClass *oc;
- DeviceClass *dc;
- if (prop->used) {
- continue;
- }
- if (!prop->user_provided) {
- continue;
- }
- oc = object_class_by_name(prop->driver);
- oc = object_class_dynamic_cast(oc, TYPE_DEVICE);
- if (!oc) {
- error_report("Warning: global %s.%s has invalid class name",
- prop->driver, prop->property);
- ret = 1;
- continue;
- }
- dc = DEVICE_CLASS(oc);
- if (!dc->hotpluggable && !prop->used) {
- error_report("Warning: global %s.%s=%s not used",
- prop->driver, prop->property, prop->value);
- ret = 1;
- continue;
- }
- }
- return ret;
-}
-
-static void qdev_prop_set_globals_for_type(DeviceState *dev,
- const char *typename)
-{
- GlobalProperty *prop;
-
- QTAILQ_FOREACH(prop, &global_props, next) {
- Error *err = NULL;
-
- if (strcmp(typename, prop->driver) != 0) {
- continue;
- }
- prop->used = true;
- object_property_parse(OBJECT(dev), prop->value, prop->property, &err);
- if (err != NULL) {
- assert(prop->user_provided);
- error_reportf_err(err, "Warning: global %s.%s=%s ignored: ",
- prop->driver, prop->property, prop->value);
- return;
- }
- }
-}
-
-void qdev_prop_set_globals(DeviceState *dev)
-{
- ObjectClass *class = object_get_class(OBJECT(dev));
-
- do {
- qdev_prop_set_globals_for_type(dev, object_class_get_name(class));
- class = object_class_get_parent(class);
- } while (class);
-}
-
-/* --- 64bit unsigned int 'size' type --- */
-
-static void get_size(Object *obj, Visitor *v, const char *name, void *opaque,
- Error **errp)
-{
- DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
- uint64_t *ptr = qdev_get_prop_ptr(dev, prop);
-
- visit_type_size(v, name, ptr, errp);
-}
-
-static void set_size(Object *obj, Visitor *v, const char *name, void *opaque,
- Error **errp)
-{
- DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
- uint64_t *ptr = qdev_get_prop_ptr(dev, prop);
-
- visit_type_size(v, name, ptr, errp);
-}
-
-PropertyInfo qdev_prop_size = {
- .name = "size",
- .get = get_size,
- .set = set_size,
-};
diff --git a/qemu/hw/core/qdev.c b/qemu/hw/core/qdev.c
deleted file mode 100644
index db41aa1f2..000000000
--- a/qemu/hw/core/qdev.c
+++ /dev/null
@@ -1,1370 +0,0 @@
-/*
- * Dynamic device configuration and creation.
- *
- * Copyright (c) 2009 CodeSourcery
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-/* The theory here is that it should be possible to create a machine without
- knowledge of specific devices. Historically board init routines have
- passed a bunch of arguments to each device, requiring the board know
- exactly which device it is dealing with. This file provides an abstract
- API for device configuration and initialization. Devices will generally
- inherit from a particular bus (e.g. PCI or I2C) rather than
- this API directly. */
-
-#include "qemu/osdep.h"
-#include "hw/qdev.h"
-#include "hw/fw-path-provider.h"
-#include "sysemu/sysemu.h"
-#include "qapi/qmp/qerror.h"
-#include "qapi/visitor.h"
-#include "qapi/qmp/qjson.h"
-#include "qemu/error-report.h"
-#include "hw/hotplug.h"
-#include "hw/boards.h"
-#include "qapi-event.h"
-
-int qdev_hotplug = 0;
-static bool qdev_hot_added = false;
-static bool qdev_hot_removed = false;
-
-const VMStateDescription *qdev_get_vmsd(DeviceState *dev)
-{
- DeviceClass *dc = DEVICE_GET_CLASS(dev);
- return dc->vmsd;
-}
-
-const char *qdev_fw_name(DeviceState *dev)
-{
- DeviceClass *dc = DEVICE_GET_CLASS(dev);
-
- if (dc->fw_name) {
- return dc->fw_name;
- }
-
- return object_get_typename(OBJECT(dev));
-}
-
-static void qdev_property_add_legacy(DeviceState *dev, Property *prop,
- Error **errp);
-
-static void bus_remove_child(BusState *bus, DeviceState *child)
-{
- BusChild *kid;
-
- QTAILQ_FOREACH(kid, &bus->children, sibling) {
- if (kid->child == child) {
- char name[32];
-
- snprintf(name, sizeof(name), "child[%d]", kid->index);
- QTAILQ_REMOVE(&bus->children, kid, sibling);
-
- /* This gives back ownership of kid->child back to us. */
- object_property_del(OBJECT(bus), name, NULL);
- object_unref(OBJECT(kid->child));
- g_free(kid);
- return;
- }
- }
-}
-
-static void bus_add_child(BusState *bus, DeviceState *child)
-{
- char name[32];
- BusChild *kid = g_malloc0(sizeof(*kid));
-
- kid->index = bus->max_index++;
- kid->child = child;
- object_ref(OBJECT(kid->child));
-
- QTAILQ_INSERT_HEAD(&bus->children, kid, sibling);
-
- /* This transfers ownership of kid->child to the property. */
- snprintf(name, sizeof(name), "child[%d]", kid->index);
- object_property_add_link(OBJECT(bus), name,
- object_get_typename(OBJECT(child)),
- (Object **)&kid->child,
- NULL, /* read-only property */
- 0, /* return ownership on prop deletion */
- NULL);
-}
-
-void qdev_set_parent_bus(DeviceState *dev, BusState *bus)
-{
- dev->parent_bus = bus;
- object_ref(OBJECT(bus));
- bus_add_child(bus, dev);
-}
-
-static void qbus_set_hotplug_handler_internal(BusState *bus, Object *handler,
- Error **errp)
-{
-
- object_property_set_link(OBJECT(bus), OBJECT(handler),
- QDEV_HOTPLUG_HANDLER_PROPERTY, errp);
-}
-
-void qbus_set_hotplug_handler(BusState *bus, DeviceState *handler, Error **errp)
-{
- qbus_set_hotplug_handler_internal(bus, OBJECT(handler), errp);
-}
-
-void qbus_set_bus_hotplug_handler(BusState *bus, Error **errp)
-{
- qbus_set_hotplug_handler_internal(bus, OBJECT(bus), errp);
-}
-
-/* Create a new device. This only initializes the device state
- structure and allows properties to be set. The device still needs
- to be realized. See qdev-core.h. */
-DeviceState *qdev_create(BusState *bus, const char *name)
-{
- DeviceState *dev;
-
- dev = qdev_try_create(bus, name);
- if (!dev) {
- if (bus) {
- error_report("Unknown device '%s' for bus '%s'", name,
- object_get_typename(OBJECT(bus)));
- } else {
- error_report("Unknown device '%s' for default sysbus", name);
- }
- abort();
- }
-
- return dev;
-}
-
-DeviceState *qdev_try_create(BusState *bus, const char *type)
-{
- DeviceState *dev;
-
- if (object_class_by_name(type) == NULL) {
- return NULL;
- }
- dev = DEVICE(object_new(type));
- if (!dev) {
- return NULL;
- }
-
- if (!bus) {
- bus = sysbus_get_default();
- }
-
- qdev_set_parent_bus(dev, bus);
- object_unref(OBJECT(dev));
- return dev;
-}
-
-static QTAILQ_HEAD(device_listeners, DeviceListener) device_listeners
- = QTAILQ_HEAD_INITIALIZER(device_listeners);
-
-enum ListenerDirection { Forward, Reverse };
-
-#define DEVICE_LISTENER_CALL(_callback, _direction, _args...) \
- do { \
- DeviceListener *_listener; \
- \
- switch (_direction) { \
- case Forward: \
- QTAILQ_FOREACH(_listener, &device_listeners, link) { \
- if (_listener->_callback) { \
- _listener->_callback(_listener, ##_args); \
- } \
- } \
- break; \
- case Reverse: \
- QTAILQ_FOREACH_REVERSE(_listener, &device_listeners, \
- device_listeners, link) { \
- if (_listener->_callback) { \
- _listener->_callback(_listener, ##_args); \
- } \
- } \
- break; \
- default: \
- abort(); \
- } \
- } while (0)
-
-static int device_listener_add(DeviceState *dev, void *opaque)
-{
- DEVICE_LISTENER_CALL(realize, Forward, dev);
-
- return 0;
-}
-
-void device_listener_register(DeviceListener *listener)
-{
- QTAILQ_INSERT_TAIL(&device_listeners, listener, link);
-
- qbus_walk_children(sysbus_get_default(), NULL, NULL, device_listener_add,
- NULL, NULL);
-}
-
-void device_listener_unregister(DeviceListener *listener)
-{
- QTAILQ_REMOVE(&device_listeners, listener, link);
-}
-
-static void device_realize(DeviceState *dev, Error **errp)
-{
- DeviceClass *dc = DEVICE_GET_CLASS(dev);
-
- if (dc->init) {
- int rc = dc->init(dev);
- if (rc < 0) {
- error_setg(errp, "Device initialization failed.");
- return;
- }
- }
-}
-
-static void device_unrealize(DeviceState *dev, Error **errp)
-{
- DeviceClass *dc = DEVICE_GET_CLASS(dev);
-
- if (dc->exit) {
- int rc = dc->exit(dev);
- if (rc < 0) {
- error_setg(errp, "Device exit failed.");
- return;
- }
- }
-}
-
-void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
- int required_for_version)
-{
- assert(!dev->realized);
- dev->instance_id_alias = alias_id;
- dev->alias_required_for_version = required_for_version;
-}
-
-HotplugHandler *qdev_get_hotplug_handler(DeviceState *dev)
-{
- HotplugHandler *hotplug_ctrl = NULL;
-
- if (dev->parent_bus && dev->parent_bus->hotplug_handler) {
- hotplug_ctrl = dev->parent_bus->hotplug_handler;
- } else if (object_dynamic_cast(qdev_get_machine(), TYPE_MACHINE)) {
- MachineState *machine = MACHINE(qdev_get_machine());
- MachineClass *mc = MACHINE_GET_CLASS(machine);
-
- if (mc->get_hotplug_handler) {
- hotplug_ctrl = mc->get_hotplug_handler(machine, dev);
- }
- }
- return hotplug_ctrl;
-}
-
-void qdev_unplug(DeviceState *dev, Error **errp)
-{
- DeviceClass *dc = DEVICE_GET_CLASS(dev);
- HotplugHandler *hotplug_ctrl;
- HotplugHandlerClass *hdc;
-
- if (dev->parent_bus && !qbus_is_hotpluggable(dev->parent_bus)) {
- error_setg(errp, QERR_BUS_NO_HOTPLUG, dev->parent_bus->name);
- return;
- }
-
- if (!dc->hotpluggable) {
- error_setg(errp, QERR_DEVICE_NO_HOTPLUG,
- object_get_typename(OBJECT(dev)));
- return;
- }
-
- qdev_hot_removed = true;
-
- hotplug_ctrl = qdev_get_hotplug_handler(dev);
- /* hotpluggable device MUST have HotplugHandler, if it doesn't
- * then something is very wrong with it */
- g_assert(hotplug_ctrl);
-
- /* If device supports async unplug just request it to be done,
- * otherwise just remove it synchronously */
- hdc = HOTPLUG_HANDLER_GET_CLASS(hotplug_ctrl);
- if (hdc->unplug_request) {
- hotplug_handler_unplug_request(hotplug_ctrl, dev, errp);
- } else {
- hotplug_handler_unplug(hotplug_ctrl, dev, errp);
- }
-}
-
-static int qdev_reset_one(DeviceState *dev, void *opaque)
-{
- device_reset(dev);
-
- return 0;
-}
-
-static int qbus_reset_one(BusState *bus, void *opaque)
-{
- BusClass *bc = BUS_GET_CLASS(bus);
- if (bc->reset) {
- bc->reset(bus);
- }
- return 0;
-}
-
-void qdev_reset_all(DeviceState *dev)
-{
- qdev_walk_children(dev, NULL, NULL, qdev_reset_one, qbus_reset_one, NULL);
-}
-
-void qdev_reset_all_fn(void *opaque)
-{
- qdev_reset_all(DEVICE(opaque));
-}
-
-void qbus_reset_all(BusState *bus)
-{
- qbus_walk_children(bus, NULL, NULL, qdev_reset_one, qbus_reset_one, NULL);
-}
-
-void qbus_reset_all_fn(void *opaque)
-{
- BusState *bus = opaque;
- qbus_reset_all(bus);
-}
-
-/* can be used as ->unplug() callback for the simple cases */
-void qdev_simple_device_unplug_cb(HotplugHandler *hotplug_dev,
- DeviceState *dev, Error **errp)
-{
- /* just zap it */
- object_unparent(OBJECT(dev));
-}
-
-/*
- * Realize @dev.
- * Device properties should be set before calling this function. IRQs
- * and MMIO regions should be connected/mapped after calling this
- * function.
- * On failure, report an error with error_report() and terminate the
- * program. This is okay during machine creation. Don't use for
- * hotplug, because there callers need to recover from failure.
- * Exception: if you know the device's init() callback can't fail,
- * then qdev_init_nofail() can't fail either, and is therefore usable
- * even then. But relying on the device implementation that way is
- * somewhat unclean, and best avoided.
- */
-void qdev_init_nofail(DeviceState *dev)
-{
- Error *err = NULL;
-
- assert(!dev->realized);
-
- object_property_set_bool(OBJECT(dev), true, "realized", &err);
- if (err) {
- error_reportf_err(err, "Initialization of device %s failed: ",
- object_get_typename(OBJECT(dev)));
- exit(1);
- }
-}
-
-void qdev_machine_creation_done(void)
-{
- /*
- * ok, initial machine setup is done, starting from now we can
- * only create hotpluggable devices
- */
- qdev_hotplug = 1;
-}
-
-bool qdev_machine_modified(void)
-{
- return qdev_hot_added || qdev_hot_removed;
-}
-
-BusState *qdev_get_parent_bus(DeviceState *dev)
-{
- return dev->parent_bus;
-}
-
-static NamedGPIOList *qdev_get_named_gpio_list(DeviceState *dev,
- const char *name)
-{
- NamedGPIOList *ngl;
-
- QLIST_FOREACH(ngl, &dev->gpios, node) {
- /* NULL is a valid and matchable name, otherwise do a normal
- * strcmp match.
- */
- if ((!ngl->name && !name) ||
- (name && ngl->name && strcmp(name, ngl->name) == 0)) {
- return ngl;
- }
- }
-
- ngl = g_malloc0(sizeof(*ngl));
- ngl->name = g_strdup(name);
- QLIST_INSERT_HEAD(&dev->gpios, ngl, node);
- return ngl;
-}
-
-void qdev_init_gpio_in_named(DeviceState *dev, qemu_irq_handler handler,
- const char *name, int n)
-{
- int i;
- NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name);
-
- assert(gpio_list->num_out == 0 || !name);
- gpio_list->in = qemu_extend_irqs(gpio_list->in, gpio_list->num_in, handler,
- dev, n);
-
- if (!name) {
- name = "unnamed-gpio-in";
- }
- for (i = gpio_list->num_in; i < gpio_list->num_in + n; i++) {
- gchar *propname = g_strdup_printf("%s[%u]", name, i);
-
- object_property_add_child(OBJECT(dev), propname,
- OBJECT(gpio_list->in[i]), &error_abort);
- g_free(propname);
- }
-
- gpio_list->num_in += n;
-}
-
-void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
-{
- qdev_init_gpio_in_named(dev, handler, NULL, n);
-}
-
-void qdev_init_gpio_out_named(DeviceState *dev, qemu_irq *pins,
- const char *name, int n)
-{
- int i;
- NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name);
-
- assert(gpio_list->num_in == 0 || !name);
-
- if (!name) {
- name = "unnamed-gpio-out";
- }
- memset(pins, 0, sizeof(*pins) * n);
- for (i = 0; i < n; ++i) {
- gchar *propname = g_strdup_printf("%s[%u]", name,
- gpio_list->num_out + i);
-
- object_property_add_link(OBJECT(dev), propname, TYPE_IRQ,
- (Object **)&pins[i],
- object_property_allow_set_link,
- OBJ_PROP_LINK_UNREF_ON_RELEASE,
- &error_abort);
- g_free(propname);
- }
- gpio_list->num_out += n;
-}
-
-void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
-{
- qdev_init_gpio_out_named(dev, pins, NULL, n);
-}
-
-qemu_irq qdev_get_gpio_in_named(DeviceState *dev, const char *name, int n)
-{
- NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name);
-
- assert(n >= 0 && n < gpio_list->num_in);
- return gpio_list->in[n];
-}
-
-qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
-{
- return qdev_get_gpio_in_named(dev, NULL, n);
-}
-
-void qdev_connect_gpio_out_named(DeviceState *dev, const char *name, int n,
- qemu_irq pin)
-{
- char *propname = g_strdup_printf("%s[%d]",
- name ? name : "unnamed-gpio-out", n);
- if (pin) {
- /* We need a name for object_property_set_link to work. If the
- * object has a parent, object_property_add_child will come back
- * with an error without doing anything. If it has none, it will
- * never fail. So we can just call it with a NULL Error pointer.
- */
- object_property_add_child(container_get(qdev_get_machine(),
- "/unattached"),
- "non-qdev-gpio[*]", OBJECT(pin), NULL);
- }
- object_property_set_link(OBJECT(dev), OBJECT(pin), propname, &error_abort);
- g_free(propname);
-}
-
-qemu_irq qdev_get_gpio_out_connector(DeviceState *dev, const char *name, int n)
-{
- char *propname = g_strdup_printf("%s[%d]",
- name ? name : "unnamed-gpio-out", n);
-
- qemu_irq ret = (qemu_irq)object_property_get_link(OBJECT(dev), propname,
- NULL);
-
- return ret;
-}
-
-/* disconnect a GPIO output, returning the disconnected input (if any) */
-
-static qemu_irq qdev_disconnect_gpio_out_named(DeviceState *dev,
- const char *name, int n)
-{
- char *propname = g_strdup_printf("%s[%d]",
- name ? name : "unnamed-gpio-out", n);
-
- qemu_irq ret = (qemu_irq)object_property_get_link(OBJECT(dev), propname,
- NULL);
- if (ret) {
- object_property_set_link(OBJECT(dev), NULL, propname, NULL);
- }
- g_free(propname);
- return ret;
-}
-
-qemu_irq qdev_intercept_gpio_out(DeviceState *dev, qemu_irq icpt,
- const char *name, int n)
-{
- qemu_irq disconnected = qdev_disconnect_gpio_out_named(dev, name, n);
- qdev_connect_gpio_out_named(dev, name, n, icpt);
- return disconnected;
-}
-
-void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
-{
- qdev_connect_gpio_out_named(dev, NULL, n, pin);
-}
-
-void qdev_pass_gpios(DeviceState *dev, DeviceState *container,
- const char *name)
-{
- int i;
- NamedGPIOList *ngl = qdev_get_named_gpio_list(dev, name);
-
- for (i = 0; i < ngl->num_in; i++) {
- const char *nm = ngl->name ? ngl->name : "unnamed-gpio-in";
- char *propname = g_strdup_printf("%s[%d]", nm, i);
-
- object_property_add_alias(OBJECT(container), propname,
- OBJECT(dev), propname,
- &error_abort);
- g_free(propname);
- }
- for (i = 0; i < ngl->num_out; i++) {
- const char *nm = ngl->name ? ngl->name : "unnamed-gpio-out";
- char *propname = g_strdup_printf("%s[%d]", nm, i);
-
- object_property_add_alias(OBJECT(container), propname,
- OBJECT(dev), propname,
- &error_abort);
- g_free(propname);
- }
- QLIST_REMOVE(ngl, node);
- QLIST_INSERT_HEAD(&container->gpios, ngl, node);
-}
-
-BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
-{
- BusState *bus;
- Object *child = object_resolve_path_component(OBJECT(dev), name);
-
- bus = (BusState *)object_dynamic_cast(child, TYPE_BUS);
- if (bus) {
- return bus;
- }
-
- QLIST_FOREACH(bus, &dev->child_bus, sibling) {
- if (strcmp(name, bus->name) == 0) {
- return bus;
- }
- }
- return NULL;
-}
-
-int qbus_walk_children(BusState *bus,
- qdev_walkerfn *pre_devfn, qbus_walkerfn *pre_busfn,
- qdev_walkerfn *post_devfn, qbus_walkerfn *post_busfn,
- void *opaque)
-{
- BusChild *kid;
- int err;
-
- if (pre_busfn) {
- err = pre_busfn(bus, opaque);
- if (err) {
- return err;
- }
- }
-
- QTAILQ_FOREACH(kid, &bus->children, sibling) {
- err = qdev_walk_children(kid->child,
- pre_devfn, pre_busfn,
- post_devfn, post_busfn, opaque);
- if (err < 0) {
- return err;
- }
- }
-
- if (post_busfn) {
- err = post_busfn(bus, opaque);
- if (err) {
- return err;
- }
- }
-
- return 0;
-}
-
-int qdev_walk_children(DeviceState *dev,
- qdev_walkerfn *pre_devfn, qbus_walkerfn *pre_busfn,
- qdev_walkerfn *post_devfn, qbus_walkerfn *post_busfn,
- void *opaque)
-{
- BusState *bus;
- int err;
-
- if (pre_devfn) {
- err = pre_devfn(dev, opaque);
- if (err) {
- return err;
- }
- }
-
- QLIST_FOREACH(bus, &dev->child_bus, sibling) {
- err = qbus_walk_children(bus, pre_devfn, pre_busfn,
- post_devfn, post_busfn, opaque);
- if (err < 0) {
- return err;
- }
- }
-
- if (post_devfn) {
- err = post_devfn(dev, opaque);
- if (err) {
- return err;
- }
- }
-
- return 0;
-}
-
-DeviceState *qdev_find_recursive(BusState *bus, const char *id)
-{
- BusChild *kid;
- DeviceState *ret;
- BusState *child;
-
- QTAILQ_FOREACH(kid, &bus->children, sibling) {
- DeviceState *dev = kid->child;
-
- if (dev->id && strcmp(dev->id, id) == 0) {
- return dev;
- }
-
- QLIST_FOREACH(child, &dev->child_bus, sibling) {
- ret = qdev_find_recursive(child, id);
- if (ret) {
- return ret;
- }
- }
- }
- return NULL;
-}
-
-static void qbus_realize(BusState *bus, DeviceState *parent, const char *name)
-{
- const char *typename = object_get_typename(OBJECT(bus));
- BusClass *bc;
- char *buf;
- int i, len, bus_id;
-
- bus->parent = parent;
-
- if (name) {
- bus->name = g_strdup(name);
- } else if (bus->parent && bus->parent->id) {
- /* parent device has id -> use it plus parent-bus-id for bus name */
- bus_id = bus->parent->num_child_bus;
-
- len = strlen(bus->parent->id) + 16;
- buf = g_malloc(len);
- snprintf(buf, len, "%s.%d", bus->parent->id, bus_id);
- bus->name = buf;
- } else {
- /* no id -> use lowercase bus type plus global bus-id for bus name */
- bc = BUS_GET_CLASS(bus);
- bus_id = bc->automatic_ids++;
-
- len = strlen(typename) + 16;
- buf = g_malloc(len);
- len = snprintf(buf, len, "%s.%d", typename, bus_id);
- for (i = 0; i < len; i++) {
- buf[i] = qemu_tolower(buf[i]);
- }
- bus->name = buf;
- }
-
- if (bus->parent) {
- QLIST_INSERT_HEAD(&bus->parent->child_bus, bus, sibling);
- bus->parent->num_child_bus++;
- object_property_add_child(OBJECT(bus->parent), bus->name, OBJECT(bus), NULL);
- object_unref(OBJECT(bus));
- } else if (bus != sysbus_get_default()) {
- /* TODO: once all bus devices are qdevified,
- only reset handler for main_system_bus should be registered here. */
- qemu_register_reset(qbus_reset_all_fn, bus);
- }
-}
-
-static void bus_unparent(Object *obj)
-{
- BusState *bus = BUS(obj);
- BusChild *kid;
-
- while ((kid = QTAILQ_FIRST(&bus->children)) != NULL) {
- DeviceState *dev = kid->child;
- object_unparent(OBJECT(dev));
- }
- if (bus->parent) {
- QLIST_REMOVE(bus, sibling);
- bus->parent->num_child_bus--;
- bus->parent = NULL;
- } else {
- assert(bus != sysbus_get_default()); /* main_system_bus is never freed */
- qemu_unregister_reset(qbus_reset_all_fn, bus);
- }
-}
-
-static bool bus_get_realized(Object *obj, Error **errp)
-{
- BusState *bus = BUS(obj);
-
- return bus->realized;
-}
-
-static void bus_set_realized(Object *obj, bool value, Error **errp)
-{
- BusState *bus = BUS(obj);
- BusClass *bc = BUS_GET_CLASS(bus);
- BusChild *kid;
- Error *local_err = NULL;
-
- if (value && !bus->realized) {
- if (bc->realize) {
- bc->realize(bus, &local_err);
- }
-
- /* TODO: recursive realization */
- } else if (!value && bus->realized) {
- QTAILQ_FOREACH(kid, &bus->children, sibling) {
- DeviceState *dev = kid->child;
- object_property_set_bool(OBJECT(dev), false, "realized",
- &local_err);
- if (local_err != NULL) {
- break;
- }
- }
- if (bc->unrealize && local_err == NULL) {
- bc->unrealize(bus, &local_err);
- }
- }
-
- if (local_err != NULL) {
- error_propagate(errp, local_err);
- return;
- }
-
- bus->realized = value;
-}
-
-void qbus_create_inplace(void *bus, size_t size, const char *typename,
- DeviceState *parent, const char *name)
-{
- object_initialize(bus, size, typename);
- qbus_realize(bus, parent, name);
-}
-
-BusState *qbus_create(const char *typename, DeviceState *parent, const char *name)
-{
- BusState *bus;
-
- bus = BUS(object_new(typename));
- qbus_realize(bus, parent, name);
-
- return bus;
-}
-
-static char *bus_get_fw_dev_path(BusState *bus, DeviceState *dev)
-{
- BusClass *bc = BUS_GET_CLASS(bus);
-
- if (bc->get_fw_dev_path) {
- return bc->get_fw_dev_path(dev);
- }
-
- return NULL;
-}
-
-static char *qdev_get_fw_dev_path_from_handler(BusState *bus, DeviceState *dev)
-{
- Object *obj = OBJECT(dev);
- char *d = NULL;
-
- while (!d && obj->parent) {
- obj = obj->parent;
- d = fw_path_provider_try_get_dev_path(obj, bus, dev);
- }
- return d;
-}
-
-char *qdev_get_own_fw_dev_path_from_handler(BusState *bus, DeviceState *dev)
-{
- Object *obj = OBJECT(dev);
-
- return fw_path_provider_try_get_dev_path(obj, bus, dev);
-}
-
-static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
-{
- int l = 0;
-
- if (dev && dev->parent_bus) {
- char *d;
- l = qdev_get_fw_dev_path_helper(dev->parent_bus->parent, p, size);
- d = qdev_get_fw_dev_path_from_handler(dev->parent_bus, dev);
- if (!d) {
- d = bus_get_fw_dev_path(dev->parent_bus, dev);
- }
- if (d) {
- l += snprintf(p + l, size - l, "%s", d);
- g_free(d);
- } else {
- return l;
- }
- }
- l += snprintf(p + l , size - l, "/");
-
- return l;
-}
-
-char* qdev_get_fw_dev_path(DeviceState *dev)
-{
- char path[128];
- int l;
-
- l = qdev_get_fw_dev_path_helper(dev, path, 128);
-
- path[l-1] = '\0';
-
- return g_strdup(path);
-}
-
-char *qdev_get_dev_path(DeviceState *dev)
-{
- BusClass *bc;
-
- if (!dev || !dev->parent_bus) {
- return NULL;
- }
-
- bc = BUS_GET_CLASS(dev->parent_bus);
- if (bc->get_dev_path) {
- return bc->get_dev_path(dev);
- }
-
- return NULL;
-}
-
-/**
- * Legacy property handling
- */
-
-static void qdev_get_legacy_property(Object *obj, Visitor *v,
- const char *name, void *opaque,
- Error **errp)
-{
- DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
-
- char buffer[1024];
- char *ptr = buffer;
-
- prop->info->print(dev, prop, buffer, sizeof(buffer));
- visit_type_str(v, name, &ptr, errp);
-}
-
-/**
- * @qdev_add_legacy_property - adds a legacy property
- *
- * Do not use this is new code! Properties added through this interface will
- * be given names and types in the "legacy" namespace.
- *
- * Legacy properties are string versions of other OOM properties. The format
- * of the string depends on the property type.
- */
-static void qdev_property_add_legacy(DeviceState *dev, Property *prop,
- Error **errp)
-{
- gchar *name;
-
- /* Register pointer properties as legacy properties */
- if (!prop->info->print && prop->info->get) {
- return;
- }
-
- name = g_strdup_printf("legacy-%s", prop->name);
- object_property_add(OBJECT(dev), name, "str",
- prop->info->print ? qdev_get_legacy_property : prop->info->get,
- NULL,
- NULL,
- prop, errp);
-
- g_free(name);
-}
-
-/**
- * @qdev_property_add_static - add a @Property to a device.
- *
- * Static properties access data in a struct. The actual type of the
- * property and the field depends on the property type.
- */
-void qdev_property_add_static(DeviceState *dev, Property *prop,
- Error **errp)
-{
- Error *local_err = NULL;
- Object *obj = OBJECT(dev);
-
- /*
- * TODO qdev_prop_ptr does not have getters or setters. It must
- * go now that it can be replaced with links. The test should be
- * removed along with it: all static properties are read/write.
- */
- if (!prop->info->get && !prop->info->set) {
- return;
- }
-
- object_property_add(obj, prop->name, prop->info->name,
- prop->info->get, prop->info->set,
- prop->info->release,
- prop, &local_err);
-
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- object_property_set_description(obj, prop->name,
- prop->info->description,
- &error_abort);
-
- if (prop->qtype == QTYPE_NONE) {
- return;
- }
-
- if (prop->qtype == QTYPE_QBOOL) {
- object_property_set_bool(obj, prop->defval, prop->name, &error_abort);
- } else if (prop->info->enum_table) {
- object_property_set_str(obj, prop->info->enum_table[prop->defval],
- prop->name, &error_abort);
- } else if (prop->qtype == QTYPE_QINT) {
- object_property_set_int(obj, prop->defval, prop->name, &error_abort);
- }
-}
-
-/* @qdev_alias_all_properties - Add alias properties to the source object for
- * all qdev properties on the target DeviceState.
- */
-void qdev_alias_all_properties(DeviceState *target, Object *source)
-{
- ObjectClass *class;
- Property *prop;
-
- class = object_get_class(OBJECT(target));
- do {
- DeviceClass *dc = DEVICE_CLASS(class);
-
- for (prop = dc->props; prop && prop->name; prop++) {
- object_property_add_alias(source, prop->name,
- OBJECT(target), prop->name,
- &error_abort);
- }
- class = object_class_get_parent(class);
- } while (class != object_class_by_name(TYPE_DEVICE));
-}
-
-static int qdev_add_hotpluggable_device(Object *obj, void *opaque)
-{
- GSList **list = opaque;
- DeviceState *dev = (DeviceState *)object_dynamic_cast(OBJECT(obj),
- TYPE_DEVICE);
-
- if (dev == NULL) {
- return 0;
- }
-
- if (dev->realized && object_property_get_bool(obj, "hotpluggable", NULL)) {
- *list = g_slist_append(*list, dev);
- }
-
- return 0;
-}
-
-GSList *qdev_build_hotpluggable_device_list(Object *peripheral)
-{
- GSList *list = NULL;
-
- object_child_foreach(peripheral, qdev_add_hotpluggable_device, &list);
-
- return list;
-}
-
-static bool device_get_realized(Object *obj, Error **errp)
-{
- DeviceState *dev = DEVICE(obj);
- return dev->realized;
-}
-
-static void device_set_realized(Object *obj, bool value, Error **errp)
-{
- DeviceState *dev = DEVICE(obj);
- DeviceClass *dc = DEVICE_GET_CLASS(dev);
- HotplugHandler *hotplug_ctrl;
- BusState *bus;
- Error *local_err = NULL;
-
- if (dev->hotplugged && !dc->hotpluggable) {
- error_setg(errp, QERR_DEVICE_NO_HOTPLUG, object_get_typename(obj));
- return;
- }
-
- if (value && !dev->realized) {
- if (!obj->parent) {
- static int unattached_count;
- gchar *name = g_strdup_printf("device[%d]", unattached_count++);
-
- object_property_add_child(container_get(qdev_get_machine(),
- "/unattached"),
- name, obj, &error_abort);
- g_free(name);
- }
-
- if (dc->realize) {
- dc->realize(dev, &local_err);
- }
-
- if (local_err != NULL) {
- goto fail;
- }
-
- DEVICE_LISTENER_CALL(realize, Forward, dev);
-
- hotplug_ctrl = qdev_get_hotplug_handler(dev);
- if (hotplug_ctrl) {
- hotplug_handler_plug(hotplug_ctrl, dev, &local_err);
- }
-
- if (local_err != NULL) {
- goto post_realize_fail;
- }
-
- if (qdev_get_vmsd(dev)) {
- vmstate_register_with_alias_id(dev, -1, qdev_get_vmsd(dev), dev,
- dev->instance_id_alias,
- dev->alias_required_for_version);
- }
-
- QLIST_FOREACH(bus, &dev->child_bus, sibling) {
- object_property_set_bool(OBJECT(bus), true, "realized",
- &local_err);
- if (local_err != NULL) {
- goto child_realize_fail;
- }
- }
- if (dev->hotplugged) {
- device_reset(dev);
- }
- dev->pending_deleted_event = false;
- } else if (!value && dev->realized) {
- Error **local_errp = NULL;
- QLIST_FOREACH(bus, &dev->child_bus, sibling) {
- local_errp = local_err ? NULL : &local_err;
- object_property_set_bool(OBJECT(bus), false, "realized",
- local_errp);
- }
- if (qdev_get_vmsd(dev)) {
- vmstate_unregister(dev, qdev_get_vmsd(dev), dev);
- }
- if (dc->unrealize) {
- local_errp = local_err ? NULL : &local_err;
- dc->unrealize(dev, local_errp);
- }
- dev->pending_deleted_event = true;
- DEVICE_LISTENER_CALL(unrealize, Reverse, dev);
- }
-
- if (local_err != NULL) {
- goto fail;
- }
-
- dev->realized = value;
- return;
-
-child_realize_fail:
- QLIST_FOREACH(bus, &dev->child_bus, sibling) {
- object_property_set_bool(OBJECT(bus), false, "realized",
- NULL);
- }
-
- if (qdev_get_vmsd(dev)) {
- vmstate_unregister(dev, qdev_get_vmsd(dev), dev);
- }
-
-post_realize_fail:
- if (dc->unrealize) {
- dc->unrealize(dev, NULL);
- }
-
-fail:
- error_propagate(errp, local_err);
-}
-
-static bool device_get_hotpluggable(Object *obj, Error **errp)
-{
- DeviceClass *dc = DEVICE_GET_CLASS(obj);
- DeviceState *dev = DEVICE(obj);
-
- return dc->hotpluggable && (dev->parent_bus == NULL ||
- qbus_is_hotpluggable(dev->parent_bus));
-}
-
-static bool device_get_hotplugged(Object *obj, Error **err)
-{
- DeviceState *dev = DEVICE(obj);
-
- return dev->hotplugged;
-}
-
-static void device_set_hotplugged(Object *obj, bool value, Error **err)
-{
- DeviceState *dev = DEVICE(obj);
-
- dev->hotplugged = value;
-}
-
-static void device_initfn(Object *obj)
-{
- DeviceState *dev = DEVICE(obj);
- ObjectClass *class;
- Property *prop;
-
- if (qdev_hotplug) {
- dev->hotplugged = 1;
- qdev_hot_added = true;
- }
-
- dev->instance_id_alias = -1;
- dev->realized = false;
-
- object_property_add_bool(obj, "realized",
- device_get_realized, device_set_realized, NULL);
- object_property_add_bool(obj, "hotpluggable",
- device_get_hotpluggable, NULL, NULL);
- object_property_add_bool(obj, "hotplugged",
- device_get_hotplugged, device_set_hotplugged,
- &error_abort);
-
- class = object_get_class(OBJECT(dev));
- do {
- for (prop = DEVICE_CLASS(class)->props; prop && prop->name; prop++) {
- qdev_property_add_legacy(dev, prop, &error_abort);
- qdev_property_add_static(dev, prop, &error_abort);
- }
- class = object_class_get_parent(class);
- } while (class != object_class_by_name(TYPE_DEVICE));
-
- object_property_add_link(OBJECT(dev), "parent_bus", TYPE_BUS,
- (Object **)&dev->parent_bus, NULL, 0,
- &error_abort);
- QLIST_INIT(&dev->gpios);
-}
-
-static void device_post_init(Object *obj)
-{
- qdev_prop_set_globals(DEVICE(obj));
-}
-
-/* Unlink device from bus and free the structure. */
-static void device_finalize(Object *obj)
-{
- NamedGPIOList *ngl, *next;
-
- DeviceState *dev = DEVICE(obj);
-
- QLIST_FOREACH_SAFE(ngl, &dev->gpios, node, next) {
- QLIST_REMOVE(ngl, node);
- qemu_free_irqs(ngl->in, ngl->num_in);
- g_free(ngl->name);
- g_free(ngl);
- /* ngl->out irqs are owned by the other end and should not be freed
- * here
- */
- }
-}
-
-static void device_class_base_init(ObjectClass *class, void *data)
-{
- DeviceClass *klass = DEVICE_CLASS(class);
-
- /* We explicitly look up properties in the superclasses,
- * so do not propagate them to the subclasses.
- */
- klass->props = NULL;
-}
-
-static void device_unparent(Object *obj)
-{
- DeviceState *dev = DEVICE(obj);
- BusState *bus;
-
- if (dev->realized) {
- object_property_set_bool(obj, false, "realized", NULL);
- }
- while (dev->num_child_bus) {
- bus = QLIST_FIRST(&dev->child_bus);
- object_unparent(OBJECT(bus));
- }
- if (dev->parent_bus) {
- bus_remove_child(dev->parent_bus, dev);
- object_unref(OBJECT(dev->parent_bus));
- dev->parent_bus = NULL;
- }
-
- /* Only send event if the device had been completely realized */
- if (dev->pending_deleted_event) {
- gchar *path = object_get_canonical_path(OBJECT(dev));
-
- qapi_event_send_device_deleted(!!dev->id, dev->id, path, &error_abort);
- g_free(path);
- }
-
- qemu_opts_del(dev->opts);
- dev->opts = NULL;
-}
-
-static void device_class_init(ObjectClass *class, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(class);
-
- class->unparent = device_unparent;
- dc->realize = device_realize;
- dc->unrealize = device_unrealize;
-
- /* by default all devices were considered as hotpluggable,
- * so with intent to check it in generic qdev_unplug() /
- * device_set_realized() functions make every device
- * hotpluggable. Devices that shouldn't be hotpluggable,
- * should override it in their class_init()
- */
- dc->hotpluggable = true;
-}
-
-void device_reset(DeviceState *dev)
-{
- DeviceClass *klass = DEVICE_GET_CLASS(dev);
-
- if (klass->reset) {
- klass->reset(dev);
- }
-}
-
-Object *qdev_get_machine(void)
-{
- static Object *dev;
-
- if (dev == NULL) {
- dev = container_get(object_get_root(), "/machine");
- }
-
- return dev;
-}
-
-static const TypeInfo device_type_info = {
- .name = TYPE_DEVICE,
- .parent = TYPE_OBJECT,
- .instance_size = sizeof(DeviceState),
- .instance_init = device_initfn,
- .instance_post_init = device_post_init,
- .instance_finalize = device_finalize,
- .class_base_init = device_class_base_init,
- .class_init = device_class_init,
- .abstract = true,
- .class_size = sizeof(DeviceClass),
-};
-
-static void qbus_initfn(Object *obj)
-{
- BusState *bus = BUS(obj);
-
- QTAILQ_INIT(&bus->children);
- object_property_add_link(obj, QDEV_HOTPLUG_HANDLER_PROPERTY,
- TYPE_HOTPLUG_HANDLER,
- (Object **)&bus->hotplug_handler,
- object_property_allow_set_link,
- OBJ_PROP_LINK_UNREF_ON_RELEASE,
- NULL);
- object_property_add_bool(obj, "realized",
- bus_get_realized, bus_set_realized, NULL);
-}
-
-static char *default_bus_get_fw_dev_path(DeviceState *dev)
-{
- return g_strdup(object_get_typename(OBJECT(dev)));
-}
-
-static void bus_class_init(ObjectClass *class, void *data)
-{
- BusClass *bc = BUS_CLASS(class);
-
- class->unparent = bus_unparent;
- bc->get_fw_dev_path = default_bus_get_fw_dev_path;
-}
-
-static void qbus_finalize(Object *obj)
-{
- BusState *bus = BUS(obj);
-
- g_free((char *)bus->name);
-}
-
-static const TypeInfo bus_info = {
- .name = TYPE_BUS,
- .parent = TYPE_OBJECT,
- .instance_size = sizeof(BusState),
- .abstract = true,
- .class_size = sizeof(BusClass),
- .instance_init = qbus_initfn,
- .instance_finalize = qbus_finalize,
- .class_init = bus_class_init,
-};
-
-static void qdev_register_types(void)
-{
- type_register_static(&bus_info);
- type_register_static(&device_type_info);
-}
-
-type_init(qdev_register_types)
diff --git a/qemu/hw/core/stream.c b/qemu/hw/core/stream.c
deleted file mode 100644
index 4439ecdf0..000000000
--- a/qemu/hw/core/stream.c
+++ /dev/null
@@ -1,33 +0,0 @@
-#include "qemu/osdep.h"
-#include "hw/stream.h"
-
-size_t
-stream_push(StreamSlave *sink, uint8_t *buf, size_t len)
-{
- StreamSlaveClass *k = STREAM_SLAVE_GET_CLASS(sink);
-
- return k->push(sink, buf, len);
-}
-
-bool
-stream_can_push(StreamSlave *sink, StreamCanPushNotifyFn notify,
- void *notify_opaque)
-{
- StreamSlaveClass *k = STREAM_SLAVE_GET_CLASS(sink);
-
- return k->can_push ? k->can_push(sink, notify, notify_opaque) : true;
-}
-
-static const TypeInfo stream_slave_info = {
- .name = TYPE_STREAM_SLAVE,
- .parent = TYPE_INTERFACE,
- .class_size = sizeof(StreamSlaveClass),
-};
-
-
-static void stream_slave_register_types(void)
-{
- type_register_static(&stream_slave_info);
-}
-
-type_init(stream_slave_register_types)
diff --git a/qemu/hw/core/sysbus.c b/qemu/hw/core/sysbus.c
deleted file mode 100644
index a7dbe2b32..000000000
--- a/qemu/hw/core/sysbus.c
+++ /dev/null
@@ -1,370 +0,0 @@
-/*
- * System (CPU) Bus device support code
- *
- * Copyright (c) 2009 CodeSourcery
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "monitor/monitor.h"
-#include "exec/address-spaces.h"
-
-static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent);
-static char *sysbus_get_fw_dev_path(DeviceState *dev);
-
-typedef struct SysBusFind {
- void *opaque;
- FindSysbusDeviceFunc *func;
-} SysBusFind;
-
-/* Run func() for every sysbus device, traverse the tree for everything else */
-static int find_sysbus_device(Object *obj, void *opaque)
-{
- SysBusFind *find = opaque;
- Object *dev;
- SysBusDevice *sbdev;
-
- dev = object_dynamic_cast(obj, TYPE_SYS_BUS_DEVICE);
- sbdev = (SysBusDevice *)dev;
-
- if (!sbdev) {
- /* Container, traverse it for children */
- return object_child_foreach(obj, find_sysbus_device, opaque);
- }
-
- find->func(sbdev, find->opaque);
-
- return 0;
-}
-
-/*
- * Loop through all dynamically created sysbus devices and call
- * func() for each instance.
- */
-void foreach_dynamic_sysbus_device(FindSysbusDeviceFunc *func, void *opaque)
-{
- Object *container;
- SysBusFind find = {
- .func = func,
- .opaque = opaque,
- };
-
- /* Loop through all sysbus devices that were spawened outside the machine */
- container = container_get(qdev_get_machine(), "/peripheral");
- find_sysbus_device(container, &find);
- container = container_get(qdev_get_machine(), "/peripheral-anon");
- find_sysbus_device(container, &find);
-}
-
-
-static void system_bus_class_init(ObjectClass *klass, void *data)
-{
- BusClass *k = BUS_CLASS(klass);
-
- k->print_dev = sysbus_dev_print;
- k->get_fw_dev_path = sysbus_get_fw_dev_path;
-}
-
-static const TypeInfo system_bus_info = {
- .name = TYPE_SYSTEM_BUS,
- .parent = TYPE_BUS,
- .instance_size = sizeof(BusState),
- .class_init = system_bus_class_init,
-};
-
-/* Check whether an IRQ source exists */
-bool sysbus_has_irq(SysBusDevice *dev, int n)
-{
- char *prop = g_strdup_printf("%s[%d]", SYSBUS_DEVICE_GPIO_IRQ, n);
- ObjectProperty *r;
-
- r = object_property_find(OBJECT(dev), prop, NULL);
- g_free(prop);
-
- return (r != NULL);
-}
-
-bool sysbus_is_irq_connected(SysBusDevice *dev, int n)
-{
- return !!sysbus_get_connected_irq(dev, n);
-}
-
-qemu_irq sysbus_get_connected_irq(SysBusDevice *dev, int n)
-{
- DeviceState *d = DEVICE(dev);
- return qdev_get_gpio_out_connector(d, SYSBUS_DEVICE_GPIO_IRQ, n);
-}
-
-void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq)
-{
- SysBusDeviceClass *sbd = SYS_BUS_DEVICE_GET_CLASS(dev);
-
- qdev_connect_gpio_out_named(DEVICE(dev), SYSBUS_DEVICE_GPIO_IRQ, n, irq);
-
- if (sbd->connect_irq_notifier) {
- sbd->connect_irq_notifier(dev, irq);
- }
-}
-
-/* Check whether an MMIO region exists */
-bool sysbus_has_mmio(SysBusDevice *dev, unsigned int n)
-{
- return (n < dev->num_mmio);
-}
-
-static void sysbus_mmio_map_common(SysBusDevice *dev, int n, hwaddr addr,
- bool may_overlap, int priority)
-{
- assert(n >= 0 && n < dev->num_mmio);
-
- if (dev->mmio[n].addr == addr) {
- /* ??? region already mapped here. */
- return;
- }
- if (dev->mmio[n].addr != (hwaddr)-1) {
- /* Unregister previous mapping. */
- memory_region_del_subregion(get_system_memory(), dev->mmio[n].memory);
- }
- dev->mmio[n].addr = addr;
- if (may_overlap) {
- memory_region_add_subregion_overlap(get_system_memory(),
- addr,
- dev->mmio[n].memory,
- priority);
- }
- else {
- memory_region_add_subregion(get_system_memory(),
- addr,
- dev->mmio[n].memory);
- }
-}
-
-void sysbus_mmio_map(SysBusDevice *dev, int n, hwaddr addr)
-{
- sysbus_mmio_map_common(dev, n, addr, false, 0);
-}
-
-void sysbus_mmio_map_overlap(SysBusDevice *dev, int n, hwaddr addr,
- int priority)
-{
- sysbus_mmio_map_common(dev, n, addr, true, priority);
-}
-
-/* Request an IRQ source. The actual IRQ object may be populated later. */
-void sysbus_init_irq(SysBusDevice *dev, qemu_irq *p)
-{
- qdev_init_gpio_out_named(DEVICE(dev), p, SYSBUS_DEVICE_GPIO_IRQ, 1);
-}
-
-/* Pass IRQs from a target device. */
-void sysbus_pass_irq(SysBusDevice *dev, SysBusDevice *target)
-{
- qdev_pass_gpios(DEVICE(target), DEVICE(dev), SYSBUS_DEVICE_GPIO_IRQ);
-}
-
-void sysbus_init_mmio(SysBusDevice *dev, MemoryRegion *memory)
-{
- int n;
-
- assert(dev->num_mmio < QDEV_MAX_MMIO);
- n = dev->num_mmio++;
- dev->mmio[n].addr = -1;
- dev->mmio[n].memory = memory;
-}
-
-MemoryRegion *sysbus_mmio_get_region(SysBusDevice *dev, int n)
-{
- return dev->mmio[n].memory;
-}
-
-void sysbus_init_ioports(SysBusDevice *dev, pio_addr_t ioport, pio_addr_t size)
-{
- pio_addr_t i;
-
- for (i = 0; i < size; i++) {
- assert(dev->num_pio < QDEV_MAX_PIO);
- dev->pio[dev->num_pio++] = ioport++;
- }
-}
-
-static int sysbus_device_init(DeviceState *dev)
-{
- SysBusDevice *sd = SYS_BUS_DEVICE(dev);
- SysBusDeviceClass *sbc = SYS_BUS_DEVICE_GET_CLASS(sd);
-
- if (!sbc->init) {
- return 0;
- }
- return sbc->init(sd);
-}
-
-DeviceState *sysbus_create_varargs(const char *name,
- hwaddr addr, ...)
-{
- DeviceState *dev;
- SysBusDevice *s;
- va_list va;
- qemu_irq irq;
- int n;
-
- dev = qdev_create(NULL, name);
- s = SYS_BUS_DEVICE(dev);
- qdev_init_nofail(dev);
- if (addr != (hwaddr)-1) {
- sysbus_mmio_map(s, 0, addr);
- }
- va_start(va, addr);
- n = 0;
- while (1) {
- irq = va_arg(va, qemu_irq);
- if (!irq) {
- break;
- }
- sysbus_connect_irq(s, n, irq);
- n++;
- }
- va_end(va);
- return dev;
-}
-
-DeviceState *sysbus_try_create_varargs(const char *name,
- hwaddr addr, ...)
-{
- DeviceState *dev;
- SysBusDevice *s;
- va_list va;
- qemu_irq irq;
- int n;
-
- dev = qdev_try_create(NULL, name);
- if (!dev) {
- return NULL;
- }
- s = SYS_BUS_DEVICE(dev);
- qdev_init_nofail(dev);
- if (addr != (hwaddr)-1) {
- sysbus_mmio_map(s, 0, addr);
- }
- va_start(va, addr);
- n = 0;
- while (1) {
- irq = va_arg(va, qemu_irq);
- if (!irq) {
- break;
- }
- sysbus_connect_irq(s, n, irq);
- n++;
- }
- va_end(va);
- return dev;
-}
-
-static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent)
-{
- SysBusDevice *s = SYS_BUS_DEVICE(dev);
- hwaddr size;
- int i;
-
- for (i = 0; i < s->num_mmio; i++) {
- size = memory_region_size(s->mmio[i].memory);
- monitor_printf(mon, "%*smmio " TARGET_FMT_plx "/" TARGET_FMT_plx "\n",
- indent, "", s->mmio[i].addr, size);
- }
-}
-
-static char *sysbus_get_fw_dev_path(DeviceState *dev)
-{
- SysBusDevice *s = SYS_BUS_DEVICE(dev);
- SysBusDeviceClass *sbc = SYS_BUS_DEVICE_GET_CLASS(s);
- /* for the explicit unit address fallback case: */
- char *addr, *fw_dev_path;
-
- if (s->num_mmio) {
- return g_strdup_printf("%s@" TARGET_FMT_plx, qdev_fw_name(dev),
- s->mmio[0].addr);
- }
- if (s->num_pio) {
- return g_strdup_printf("%s@i%04x", qdev_fw_name(dev), s->pio[0]);
- }
- if (sbc->explicit_ofw_unit_address) {
- addr = sbc->explicit_ofw_unit_address(s);
- if (addr) {
- fw_dev_path = g_strdup_printf("%s@%s", qdev_fw_name(dev), addr);
- g_free(addr);
- return fw_dev_path;
- }
- }
- return g_strdup(qdev_fw_name(dev));
-}
-
-void sysbus_add_io(SysBusDevice *dev, hwaddr addr,
- MemoryRegion *mem)
-{
- memory_region_add_subregion(get_system_io(), addr, mem);
-}
-
-MemoryRegion *sysbus_address_space(SysBusDevice *dev)
-{
- return get_system_memory();
-}
-
-static void sysbus_device_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *k = DEVICE_CLASS(klass);
- k->init = sysbus_device_init;
- k->bus_type = TYPE_SYSTEM_BUS;
-}
-
-static const TypeInfo sysbus_device_type_info = {
- .name = TYPE_SYS_BUS_DEVICE,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(SysBusDevice),
- .abstract = true,
- .class_size = sizeof(SysBusDeviceClass),
- .class_init = sysbus_device_class_init,
-};
-
-/* This is a nasty hack to allow passing a NULL bus to qdev_create. */
-static BusState *main_system_bus;
-
-static void main_system_bus_create(void)
-{
- /* assign main_system_bus before qbus_create_inplace()
- * in order to make "if (bus != sysbus_get_default())" work */
- main_system_bus = g_malloc0(system_bus_info.instance_size);
- qbus_create_inplace(main_system_bus, system_bus_info.instance_size,
- TYPE_SYSTEM_BUS, NULL, "main-system-bus");
- OBJECT(main_system_bus)->free = g_free;
- object_property_add_child(container_get(qdev_get_machine(),
- "/unattached"),
- "sysbus", OBJECT(main_system_bus), NULL);
-}
-
-BusState *sysbus_get_default(void)
-{
- if (!main_system_bus) {
- main_system_bus_create();
- }
- return main_system_bus;
-}
-
-static void sysbus_register_types(void)
-{
- type_register_static(&system_bus_info);
- type_register_static(&sysbus_device_type_info);
-}
-
-type_init(sysbus_register_types)
diff --git a/qemu/hw/core/uboot_image.h b/qemu/hw/core/uboot_image.h
deleted file mode 100644
index 9fc2760b5..000000000
--- a/qemu/hw/core/uboot_image.h
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * (C) Copyright 2000-2005
- * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- ********************************************************************
- * NOTE: This header file defines an interface to U-Boot. Including
- * this (unmodified) header file in another file is considered normal
- * use of U-Boot, and does *not* fall under the heading of "derived
- * work".
- ********************************************************************
- */
-
-#ifndef __UBOOT_IMAGE_H__
-#define __UBOOT_IMAGE_H__
-
-/*
- * Operating System Codes
- */
-#define IH_OS_INVALID 0 /* Invalid OS */
-#define IH_OS_OPENBSD 1 /* OpenBSD */
-#define IH_OS_NETBSD 2 /* NetBSD */
-#define IH_OS_FREEBSD 3 /* FreeBSD */
-#define IH_OS_4_4BSD 4 /* 4.4BSD */
-#define IH_OS_LINUX 5 /* Linux */
-#define IH_OS_SVR4 6 /* SVR4 */
-#define IH_OS_ESIX 7 /* Esix */
-#define IH_OS_SOLARIS 8 /* Solaris */
-#define IH_OS_IRIX 9 /* Irix */
-#define IH_OS_SCO 10 /* SCO */
-#define IH_OS_DELL 11 /* Dell */
-#define IH_OS_NCR 12 /* NCR */
-#define IH_OS_LYNXOS 13 /* LynxOS */
-#define IH_OS_VXWORKS 14 /* VxWorks */
-#define IH_OS_PSOS 15 /* pSOS */
-#define IH_OS_QNX 16 /* QNX */
-#define IH_OS_U_BOOT 17 /* Firmware */
-#define IH_OS_RTEMS 18 /* RTEMS */
-#define IH_OS_ARTOS 19 /* ARTOS */
-#define IH_OS_UNITY 20 /* Unity OS */
-
-/*
- * CPU Architecture Codes (supported by Linux)
- */
-#define IH_CPU_INVALID 0 /* Invalid CPU */
-#define IH_CPU_ALPHA 1 /* Alpha */
-#define IH_CPU_ARM 2 /* ARM */
-#define IH_CPU_I386 3 /* Intel x86 */
-#define IH_CPU_IA64 4 /* IA64 */
-#define IH_CPU_MIPS 5 /* MIPS */
-#define IH_CPU_MIPS64 6 /* MIPS 64 Bit */
-#define IH_CPU_PPC 7 /* PowerPC */
-#define IH_CPU_S390 8 /* IBM S390 */
-#define IH_CPU_SH 9 /* SuperH */
-#define IH_CPU_SPARC 10 /* Sparc */
-#define IH_CPU_SPARC64 11 /* Sparc 64 Bit */
-#define IH_CPU_M68K 12 /* M68K */
-#define IH_CPU_NIOS 13 /* Nios-32 */
-#define IH_CPU_MICROBLAZE 14 /* MicroBlaze */
-#define IH_CPU_NIOS2 15 /* Nios-II */
-#define IH_CPU_BLACKFIN 16 /* Blackfin */
-#define IH_CPU_AVR32 17 /* AVR32 */
-
-/*
- * Image Types
- *
- * "Standalone Programs" are directly runnable in the environment
- * provided by U-Boot; it is expected that (if they behave
- * well) you can continue to work in U-Boot after return from
- * the Standalone Program.
- * "OS Kernel Images" are usually images of some Embedded OS which
- * will take over control completely. Usually these programs
- * will install their own set of exception handlers, device
- * drivers, set up the MMU, etc. - this means, that you cannot
- * expect to re-enter U-Boot except by resetting the CPU.
- * "RAMDisk Images" are more or less just data blocks, and their
- * parameters (address, size) are passed to an OS kernel that is
- * being started.
- * "Multi-File Images" contain several images, typically an OS
- * (Linux) kernel image and one or more data images like
- * RAMDisks. This construct is useful for instance when you want
- * to boot over the network using BOOTP etc., where the boot
- * server provides just a single image file, but you want to get
- * for instance an OS kernel and a RAMDisk image.
- *
- * "Multi-File Images" start with a list of image sizes, each
- * image size (in bytes) specified by an "uint32_t" in network
- * byte order. This list is terminated by an "(uint32_t)0".
- * Immediately after the terminating 0 follow the images, one by
- * one, all aligned on "uint32_t" boundaries (size rounded up to
- * a multiple of 4 bytes - except for the last file).
- *
- * "Firmware Images" are binary images containing firmware (like
- * U-Boot or FPGA images) which usually will be programmed to
- * flash memory.
- *
- * "Script files" are command sequences that will be executed by
- * U-Boot's command interpreter; this feature is especially
- * useful when you configure U-Boot to use a real shell (hush)
- * as command interpreter (=> Shell Scripts).
- */
-
-#define IH_TYPE_INVALID 0 /* Invalid Image */
-#define IH_TYPE_STANDALONE 1 /* Standalone Program */
-#define IH_TYPE_KERNEL 2 /* OS Kernel Image */
-#define IH_TYPE_RAMDISK 3 /* RAMDisk Image */
-#define IH_TYPE_MULTI 4 /* Multi-File Image */
-#define IH_TYPE_FIRMWARE 5 /* Firmware Image */
-#define IH_TYPE_SCRIPT 6 /* Script file */
-#define IH_TYPE_FILESYSTEM 7 /* Filesystem Image (any type) */
-#define IH_TYPE_FLATDT 8 /* Binary Flat Device Tree Blob */
-
-/*
- * Compression Types
- */
-#define IH_COMP_NONE 0 /* No Compression Used */
-#define IH_COMP_GZIP 1 /* gzip Compression Used */
-#define IH_COMP_BZIP2 2 /* bzip2 Compression Used */
-
-#define IH_MAGIC 0x27051956 /* Image Magic Number */
-#define IH_NMLEN 32 /* Image Name Length */
-
-/*
- * all data in network byte order (aka natural aka bigendian)
- */
-
-typedef struct uboot_image_header {
- uint32_t ih_magic; /* Image Header Magic Number */
- uint32_t ih_hcrc; /* Image Header CRC Checksum */
- uint32_t ih_time; /* Image Creation Timestamp */
- uint32_t ih_size; /* Image Data Size */
- uint32_t ih_load; /* Data Load Address */
- uint32_t ih_ep; /* Entry Point Address */
- uint32_t ih_dcrc; /* Image Data CRC Checksum */
- uint8_t ih_os; /* Operating System */
- uint8_t ih_arch; /* CPU architecture */
- uint8_t ih_type; /* Image Type */
- uint8_t ih_comp; /* Compression Type */
- uint8_t ih_name[IH_NMLEN]; /* Image Name */
-} uboot_image_header_t;
-
-
-#endif /* __IMAGE_H__ */
diff --git a/qemu/hw/cpu/Makefile.objs b/qemu/hw/cpu/Makefile.objs
deleted file mode 100644
index 0954a1872..000000000
--- a/qemu/hw/cpu/Makefile.objs
+++ /dev/null
@@ -1,5 +0,0 @@
-obj-$(CONFIG_ARM11MPCORE) += arm11mpcore.o
-obj-$(CONFIG_REALVIEW) += realview_mpcore.o
-obj-$(CONFIG_A9MPCORE) += a9mpcore.o
-obj-$(CONFIG_A15MPCORE) += a15mpcore.o
-
diff --git a/qemu/hw/cpu/a15mpcore.c b/qemu/hw/cpu/a15mpcore.c
deleted file mode 100644
index bc05152fd..000000000
--- a/qemu/hw/cpu/a15mpcore.c
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Cortex-A15MPCore internal peripheral emulation.
- *
- * Copyright (c) 2012 Linaro Limited.
- * Written by Peter Maydell.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/cpu/a15mpcore.h"
-#include "sysemu/kvm.h"
-#include "kvm_arm.h"
-
-static void a15mp_priv_set_irq(void *opaque, int irq, int level)
-{
- A15MPPrivState *s = (A15MPPrivState *)opaque;
-
- qemu_set_irq(qdev_get_gpio_in(DEVICE(&s->gic), irq), level);
-}
-
-static void a15mp_priv_initfn(Object *obj)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- A15MPPrivState *s = A15MPCORE_PRIV(obj);
- DeviceState *gicdev;
-
- memory_region_init(&s->container, obj, "a15mp-priv-container", 0x8000);
- sysbus_init_mmio(sbd, &s->container);
-
- object_initialize(&s->gic, sizeof(s->gic), gic_class_name());
- gicdev = DEVICE(&s->gic);
- qdev_set_parent_bus(gicdev, sysbus_get_default());
- qdev_prop_set_uint32(gicdev, "revision", 2);
-}
-
-static void a15mp_priv_realize(DeviceState *dev, Error **errp)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- A15MPPrivState *s = A15MPCORE_PRIV(dev);
- DeviceState *gicdev;
- SysBusDevice *busdev;
- int i;
- Error *err = NULL;
- bool has_el3;
- Object *cpuobj;
-
- gicdev = DEVICE(&s->gic);
- qdev_prop_set_uint32(gicdev, "num-cpu", s->num_cpu);
- qdev_prop_set_uint32(gicdev, "num-irq", s->num_irq);
-
- if (!kvm_irqchip_in_kernel()) {
- /* Make the GIC's TZ support match the CPUs. We assume that
- * either all the CPUs have TZ, or none do.
- */
- cpuobj = OBJECT(qemu_get_cpu(0));
- has_el3 = object_property_find(cpuobj, "has_el3", NULL) &&
- object_property_get_bool(cpuobj, "has_el3", &error_abort);
- qdev_prop_set_bit(gicdev, "has-security-extensions", has_el3);
- }
-
- object_property_set_bool(OBJECT(&s->gic), true, "realized", &err);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
- busdev = SYS_BUS_DEVICE(&s->gic);
-
- /* Pass through outbound IRQ lines from the GIC */
- sysbus_pass_irq(sbd, busdev);
-
- /* Pass through inbound GPIO lines to the GIC */
- qdev_init_gpio_in(dev, a15mp_priv_set_irq, s->num_irq - 32);
-
- /* Wire the outputs from each CPU's generic timer to the
- * appropriate GIC PPI inputs
- */
- for (i = 0; i < s->num_cpu; i++) {
- DeviceState *cpudev = DEVICE(qemu_get_cpu(i));
- int ppibase = s->num_irq - 32 + i * 32;
- int irq;
- /* Mapping from the output timer irq lines from the CPU to the
- * GIC PPI inputs used on the A15:
- */
- const int timer_irq[] = {
- [GTIMER_PHYS] = 30,
- [GTIMER_VIRT] = 27,
- [GTIMER_HYP] = 26,
- [GTIMER_SEC] = 29,
- };
- for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) {
- qdev_connect_gpio_out(cpudev, irq,
- qdev_get_gpio_in(gicdev,
- ppibase + timer_irq[irq]));
- }
- }
-
- /* Memory map (addresses are offsets from PERIPHBASE):
- * 0x0000-0x0fff -- reserved
- * 0x1000-0x1fff -- GIC Distributor
- * 0x2000-0x3fff -- GIC CPU interface
- * 0x4000-0x4fff -- GIC virtual interface control (not modelled)
- * 0x5000-0x5fff -- GIC virtual interface control (not modelled)
- * 0x6000-0x7fff -- GIC virtual CPU interface (not modelled)
- */
- memory_region_add_subregion(&s->container, 0x1000,
- sysbus_mmio_get_region(busdev, 0));
- memory_region_add_subregion(&s->container, 0x2000,
- sysbus_mmio_get_region(busdev, 1));
-}
-
-static Property a15mp_priv_properties[] = {
- DEFINE_PROP_UINT32("num-cpu", A15MPPrivState, num_cpu, 1),
- /* The Cortex-A15MP may have anything from 0 to 224 external interrupt
- * IRQ lines (with another 32 internal). We default to 128+32, which
- * is the number provided by the Cortex-A15MP test chip in the
- * Versatile Express A15 development board.
- * Other boards may differ and should set this property appropriately.
- */
- DEFINE_PROP_UINT32("num-irq", A15MPPrivState, num_irq, 160),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void a15mp_priv_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = a15mp_priv_realize;
- dc->props = a15mp_priv_properties;
- /* We currently have no savable state */
-}
-
-static const TypeInfo a15mp_priv_info = {
- .name = TYPE_A15MPCORE_PRIV,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(A15MPPrivState),
- .instance_init = a15mp_priv_initfn,
- .class_init = a15mp_priv_class_init,
-};
-
-static void a15mp_register_types(void)
-{
- type_register_static(&a15mp_priv_info);
-}
-
-type_init(a15mp_register_types)
diff --git a/qemu/hw/cpu/a9mpcore.c b/qemu/hw/cpu/a9mpcore.c
deleted file mode 100644
index 5459ae8c1..000000000
--- a/qemu/hw/cpu/a9mpcore.c
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * Cortex-A9MPCore internal peripheral emulation.
- *
- * Copyright (c) 2009 CodeSourcery.
- * Copyright (c) 2011 Linaro Limited.
- * Written by Paul Brook, Peter Maydell.
- *
- * This code is licensed under the GPL.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/cpu/a9mpcore.h"
-
-static void a9mp_priv_set_irq(void *opaque, int irq, int level)
-{
- A9MPPrivState *s = (A9MPPrivState *)opaque;
-
- qemu_set_irq(qdev_get_gpio_in(DEVICE(&s->gic), irq), level);
-}
-
-static void a9mp_priv_initfn(Object *obj)
-{
- A9MPPrivState *s = A9MPCORE_PRIV(obj);
-
- memory_region_init(&s->container, obj, "a9mp-priv-container", 0x2000);
- sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->container);
-
- object_initialize(&s->scu, sizeof(s->scu), TYPE_A9_SCU);
- qdev_set_parent_bus(DEVICE(&s->scu), sysbus_get_default());
-
- object_initialize(&s->gic, sizeof(s->gic), TYPE_ARM_GIC);
- qdev_set_parent_bus(DEVICE(&s->gic), sysbus_get_default());
-
- object_initialize(&s->gtimer, sizeof(s->gtimer), TYPE_A9_GTIMER);
- qdev_set_parent_bus(DEVICE(&s->gtimer), sysbus_get_default());
-
- object_initialize(&s->mptimer, sizeof(s->mptimer), TYPE_ARM_MPTIMER);
- qdev_set_parent_bus(DEVICE(&s->mptimer), sysbus_get_default());
-
- object_initialize(&s->wdt, sizeof(s->wdt), TYPE_ARM_MPTIMER);
- qdev_set_parent_bus(DEVICE(&s->wdt), sysbus_get_default());
-}
-
-static void a9mp_priv_realize(DeviceState *dev, Error **errp)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- A9MPPrivState *s = A9MPCORE_PRIV(dev);
- DeviceState *scudev, *gicdev, *gtimerdev, *mptimerdev, *wdtdev;
- SysBusDevice *scubusdev, *gicbusdev, *gtimerbusdev, *mptimerbusdev,
- *wdtbusdev;
- Error *err = NULL;
- int i;
- bool has_el3;
- Object *cpuobj;
-
- scudev = DEVICE(&s->scu);
- qdev_prop_set_uint32(scudev, "num-cpu", s->num_cpu);
- object_property_set_bool(OBJECT(&s->scu), true, "realized", &err);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
- scubusdev = SYS_BUS_DEVICE(&s->scu);
-
- gicdev = DEVICE(&s->gic);
- qdev_prop_set_uint32(gicdev, "num-cpu", s->num_cpu);
- qdev_prop_set_uint32(gicdev, "num-irq", s->num_irq);
-
- /* Make the GIC's TZ support match the CPUs. We assume that
- * either all the CPUs have TZ, or none do.
- */
- cpuobj = OBJECT(qemu_get_cpu(0));
- has_el3 = object_property_find(cpuobj, "has_el3", NULL) &&
- object_property_get_bool(cpuobj, "has_el3", &error_abort);
- qdev_prop_set_bit(gicdev, "has-security-extensions", has_el3);
-
- object_property_set_bool(OBJECT(&s->gic), true, "realized", &err);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
- gicbusdev = SYS_BUS_DEVICE(&s->gic);
-
- /* Pass through outbound IRQ lines from the GIC */
- sysbus_pass_irq(sbd, gicbusdev);
-
- /* Pass through inbound GPIO lines to the GIC */
- qdev_init_gpio_in(dev, a9mp_priv_set_irq, s->num_irq - 32);
-
- gtimerdev = DEVICE(&s->gtimer);
- qdev_prop_set_uint32(gtimerdev, "num-cpu", s->num_cpu);
- object_property_set_bool(OBJECT(&s->gtimer), true, "realized", &err);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
- gtimerbusdev = SYS_BUS_DEVICE(&s->gtimer);
-
- mptimerdev = DEVICE(&s->mptimer);
- qdev_prop_set_uint32(mptimerdev, "num-cpu", s->num_cpu);
- object_property_set_bool(OBJECT(&s->mptimer), true, "realized", &err);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
- mptimerbusdev = SYS_BUS_DEVICE(&s->mptimer);
-
- wdtdev = DEVICE(&s->wdt);
- qdev_prop_set_uint32(wdtdev, "num-cpu", s->num_cpu);
- object_property_set_bool(OBJECT(&s->wdt), true, "realized", &err);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
- wdtbusdev = SYS_BUS_DEVICE(&s->wdt);
-
- /* Memory map (addresses are offsets from PERIPHBASE):
- * 0x0000-0x00ff -- Snoop Control Unit
- * 0x0100-0x01ff -- GIC CPU interface
- * 0x0200-0x02ff -- Global Timer
- * 0x0300-0x05ff -- nothing
- * 0x0600-0x06ff -- private timers and watchdogs
- * 0x0700-0x0fff -- nothing
- * 0x1000-0x1fff -- GIC Distributor
- */
- memory_region_add_subregion(&s->container, 0,
- sysbus_mmio_get_region(scubusdev, 0));
- /* GIC CPU interface */
- memory_region_add_subregion(&s->container, 0x100,
- sysbus_mmio_get_region(gicbusdev, 1));
- memory_region_add_subregion(&s->container, 0x200,
- sysbus_mmio_get_region(gtimerbusdev, 0));
- /* Note that the A9 exposes only the "timer/watchdog for this core"
- * memory region, not the "timer/watchdog for core X" ones 11MPcore has.
- */
- memory_region_add_subregion(&s->container, 0x600,
- sysbus_mmio_get_region(mptimerbusdev, 0));
- memory_region_add_subregion(&s->container, 0x620,
- sysbus_mmio_get_region(wdtbusdev, 0));
- memory_region_add_subregion(&s->container, 0x1000,
- sysbus_mmio_get_region(gicbusdev, 0));
-
- /* Wire up the interrupt from each watchdog and timer.
- * For each core the global timer is PPI 27, the private
- * timer is PPI 29 and the watchdog PPI 30.
- */
- for (i = 0; i < s->num_cpu; i++) {
- int ppibase = (s->num_irq - 32) + i * 32;
- sysbus_connect_irq(gtimerbusdev, i,
- qdev_get_gpio_in(gicdev, ppibase + 27));
- sysbus_connect_irq(mptimerbusdev, i,
- qdev_get_gpio_in(gicdev, ppibase + 29));
- sysbus_connect_irq(wdtbusdev, i,
- qdev_get_gpio_in(gicdev, ppibase + 30));
- }
-}
-
-static Property a9mp_priv_properties[] = {
- DEFINE_PROP_UINT32("num-cpu", A9MPPrivState, num_cpu, 1),
- /* The Cortex-A9MP may have anything from 0 to 224 external interrupt
- * IRQ lines (with another 32 internal). We default to 64+32, which
- * is the number provided by the Cortex-A9MP test chip in the
- * Realview PBX-A9 and Versatile Express A9 development boards.
- * Other boards may differ and should set this property appropriately.
- */
- DEFINE_PROP_UINT32("num-irq", A9MPPrivState, num_irq, 96),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void a9mp_priv_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = a9mp_priv_realize;
- dc->props = a9mp_priv_properties;
-}
-
-static const TypeInfo a9mp_priv_info = {
- .name = TYPE_A9MPCORE_PRIV,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(A9MPPrivState),
- .instance_init = a9mp_priv_initfn,
- .class_init = a9mp_priv_class_init,
-};
-
-static void a9mp_register_types(void)
-{
- type_register_static(&a9mp_priv_info);
-}
-
-type_init(a9mp_register_types)
diff --git a/qemu/hw/cpu/arm11mpcore.c b/qemu/hw/cpu/arm11mpcore.c
deleted file mode 100644
index eb244658b..000000000
--- a/qemu/hw/cpu/arm11mpcore.c
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * ARM11MPCore internal peripheral emulation.
- *
- * Copyright (c) 2006-2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/cpu/arm11mpcore.h"
-#include "hw/intc/realview_gic.h"
-
-
-static void mpcore_priv_set_irq(void *opaque, int irq, int level)
-{
- ARM11MPCorePriveState *s = (ARM11MPCorePriveState *)opaque;
-
- qemu_set_irq(qdev_get_gpio_in(DEVICE(&s->gic), irq), level);
-}
-
-static void mpcore_priv_map_setup(ARM11MPCorePriveState *s)
-{
- int i;
- SysBusDevice *scubusdev = SYS_BUS_DEVICE(&s->scu);
- DeviceState *gicdev = DEVICE(&s->gic);
- SysBusDevice *gicbusdev = SYS_BUS_DEVICE(&s->gic);
- SysBusDevice *timerbusdev = SYS_BUS_DEVICE(&s->mptimer);
- SysBusDevice *wdtbusdev = SYS_BUS_DEVICE(&s->wdtimer);
-
- memory_region_add_subregion(&s->container, 0,
- sysbus_mmio_get_region(scubusdev, 0));
- /* GIC CPU interfaces: "current CPU" at 0x100, then specific CPUs
- * at 0x200, 0x300...
- */
- for (i = 0; i < (s->num_cpu + 1); i++) {
- hwaddr offset = 0x100 + (i * 0x100);
- memory_region_add_subregion(&s->container, offset,
- sysbus_mmio_get_region(gicbusdev, i + 1));
- }
- /* Add the regions for timer and watchdog for "current CPU" and
- * for each specific CPU.
- */
- for (i = 0; i < (s->num_cpu + 1); i++) {
- /* Timers at 0x600, 0x700, ...; watchdogs at 0x620, 0x720, ... */
- hwaddr offset = 0x600 + i * 0x100;
- memory_region_add_subregion(&s->container, offset,
- sysbus_mmio_get_region(timerbusdev, i));
- memory_region_add_subregion(&s->container, offset + 0x20,
- sysbus_mmio_get_region(wdtbusdev, i));
- }
- memory_region_add_subregion(&s->container, 0x1000,
- sysbus_mmio_get_region(gicbusdev, 0));
- /* Wire up the interrupt from each watchdog and timer.
- * For each core the timer is PPI 29 and the watchdog PPI 30.
- */
- for (i = 0; i < s->num_cpu; i++) {
- int ppibase = (s->num_irq - 32) + i * 32;
- sysbus_connect_irq(timerbusdev, i,
- qdev_get_gpio_in(gicdev, ppibase + 29));
- sysbus_connect_irq(wdtbusdev, i,
- qdev_get_gpio_in(gicdev, ppibase + 30));
- }
-}
-
-static void mpcore_priv_realize(DeviceState *dev, Error **errp)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- ARM11MPCorePriveState *s = ARM11MPCORE_PRIV(dev);
- DeviceState *scudev = DEVICE(&s->scu);
- DeviceState *gicdev = DEVICE(&s->gic);
- DeviceState *mptimerdev = DEVICE(&s->mptimer);
- DeviceState *wdtimerdev = DEVICE(&s->wdtimer);
- Error *err = NULL;
-
- qdev_prop_set_uint32(scudev, "num-cpu", s->num_cpu);
- object_property_set_bool(OBJECT(&s->scu), true, "realized", &err);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
-
- qdev_prop_set_uint32(gicdev, "num-cpu", s->num_cpu);
- qdev_prop_set_uint32(gicdev, "num-irq", s->num_irq);
- object_property_set_bool(OBJECT(&s->gic), true, "realized", &err);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
-
- /* Pass through outbound IRQ lines from the GIC */
- sysbus_pass_irq(sbd, SYS_BUS_DEVICE(&s->gic));
-
- /* Pass through inbound GPIO lines to the GIC */
- qdev_init_gpio_in(dev, mpcore_priv_set_irq, s->num_irq - 32);
-
- qdev_prop_set_uint32(mptimerdev, "num-cpu", s->num_cpu);
- object_property_set_bool(OBJECT(&s->mptimer), true, "realized", &err);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
-
- qdev_prop_set_uint32(wdtimerdev, "num-cpu", s->num_cpu);
- object_property_set_bool(OBJECT(&s->wdtimer), true, "realized", &err);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
-
- mpcore_priv_map_setup(s);
-}
-
-static void mpcore_priv_initfn(Object *obj)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- ARM11MPCorePriveState *s = ARM11MPCORE_PRIV(obj);
-
- memory_region_init(&s->container, OBJECT(s),
- "mpcore-priv-container", 0x2000);
- sysbus_init_mmio(sbd, &s->container);
-
- object_initialize(&s->scu, sizeof(s->scu), TYPE_ARM11_SCU);
- qdev_set_parent_bus(DEVICE(&s->scu), sysbus_get_default());
-
- object_initialize(&s->gic, sizeof(s->gic), TYPE_ARM_GIC);
- qdev_set_parent_bus(DEVICE(&s->gic), sysbus_get_default());
- /* Request the legacy 11MPCore GIC behaviour: */
- qdev_prop_set_uint32(DEVICE(&s->gic), "revision", 0);
-
- object_initialize(&s->mptimer, sizeof(s->mptimer), TYPE_ARM_MPTIMER);
- qdev_set_parent_bus(DEVICE(&s->mptimer), sysbus_get_default());
-
- object_initialize(&s->wdtimer, sizeof(s->wdtimer), TYPE_ARM_MPTIMER);
- qdev_set_parent_bus(DEVICE(&s->wdtimer), sysbus_get_default());
-}
-
-static Property mpcore_priv_properties[] = {
- DEFINE_PROP_UINT32("num-cpu", ARM11MPCorePriveState, num_cpu, 1),
- /* The ARM11 MPCORE TRM says the on-chip controller may have
- * anything from 0 to 224 external interrupt IRQ lines (with another
- * 32 internal). We default to 32+32, which is the number provided by
- * the ARM11 MPCore test chip in the Realview Versatile Express
- * coretile. Other boards may differ and should set this property
- * appropriately. Some Linux kernels may not boot if the hardware
- * has more IRQ lines than the kernel expects.
- */
- DEFINE_PROP_UINT32("num-irq", ARM11MPCorePriveState, num_irq, 64),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void mpcore_priv_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = mpcore_priv_realize;
- dc->props = mpcore_priv_properties;
-}
-
-static const TypeInfo mpcore_priv_info = {
- .name = TYPE_ARM11MPCORE_PRIV,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(ARM11MPCorePriveState),
- .instance_init = mpcore_priv_initfn,
- .class_init = mpcore_priv_class_init,
-};
-
-static void arm11mpcore_register_types(void)
-{
- type_register_static(&mpcore_priv_info);
-}
-
-type_init(arm11mpcore_register_types)
diff --git a/qemu/hw/cpu/realview_mpcore.c b/qemu/hw/cpu/realview_mpcore.c
deleted file mode 100644
index 39d4ebeb1..000000000
--- a/qemu/hw/cpu/realview_mpcore.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * RealView ARM11MPCore internal peripheral emulation
- *
- * Copyright (c) 2006-2007 CodeSourcery.
- * Copyright (c) 2013 SUSE LINUX Products GmbH
- * Written by Paul Brook and Andreas Färber
- *
- * This code is licensed under the GPL.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/cpu/arm11mpcore.h"
-#include "hw/intc/realview_gic.h"
-
-#define TYPE_REALVIEW_MPCORE_RIRQ "realview_mpcore"
-#define REALVIEW_MPCORE_RIRQ(obj) \
- OBJECT_CHECK(mpcore_rirq_state, (obj), TYPE_REALVIEW_MPCORE_RIRQ)
-
-/* Dummy PIC to route IRQ lines. The baseboard has 4 independent IRQ
- controllers. The output of these, plus some of the raw input lines
- are fed into a single SMP-aware interrupt controller on the CPU. */
-typedef struct {
- SysBusDevice parent_obj;
-
- qemu_irq cpuic[32];
- qemu_irq rvic[4][64];
- uint32_t num_cpu;
-
- ARM11MPCorePriveState priv;
- RealViewGICState gic[4];
-} mpcore_rirq_state;
-
-/* Map baseboard IRQs onto CPU IRQ lines. */
-static const int mpcore_irq_map[32] = {
- -1, -1, -1, -1, 1, 2, -1, -1,
- -1, -1, 6, -1, 4, 5, -1, -1,
- -1, 14, 15, 0, 7, 8, -1, -1,
- -1, -1, -1, -1, 9, 3, -1, -1,
-};
-
-static void mpcore_rirq_set_irq(void *opaque, int irq, int level)
-{
- mpcore_rirq_state *s = (mpcore_rirq_state *)opaque;
- int i;
-
- for (i = 0; i < 4; i++) {
- qemu_set_irq(s->rvic[i][irq], level);
- }
- if (irq < 32) {
- irq = mpcore_irq_map[irq];
- if (irq >= 0) {
- qemu_set_irq(s->cpuic[irq], level);
- }
- }
-}
-
-static void realview_mpcore_realize(DeviceState *dev, Error **errp)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- mpcore_rirq_state *s = REALVIEW_MPCORE_RIRQ(dev);
- DeviceState *priv = DEVICE(&s->priv);
- DeviceState *gic;
- SysBusDevice *gicbusdev;
- Error *err = NULL;
- int n;
- int i;
-
- qdev_prop_set_uint32(priv, "num-cpu", s->num_cpu);
- object_property_set_bool(OBJECT(&s->priv), true, "realized", &err);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
- sysbus_pass_irq(sbd, SYS_BUS_DEVICE(&s->priv));
- for (i = 0; i < 32; i++) {
- s->cpuic[i] = qdev_get_gpio_in(priv, i);
- }
- /* ??? IRQ routing is hardcoded to "normal" mode. */
- for (n = 0; n < 4; n++) {
- object_property_set_bool(OBJECT(&s->gic[n]), true, "realized", &err);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
- gic = DEVICE(&s->gic[n]);
- gicbusdev = SYS_BUS_DEVICE(&s->gic[n]);
- sysbus_mmio_map(gicbusdev, 0, 0x10040000 + n * 0x10000);
- sysbus_connect_irq(gicbusdev, 0, s->cpuic[10 + n]);
- for (i = 0; i < 64; i++) {
- s->rvic[n][i] = qdev_get_gpio_in(gic, i);
- }
- }
- qdev_init_gpio_in(dev, mpcore_rirq_set_irq, 64);
-}
-
-static void mpcore_rirq_init(Object *obj)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- mpcore_rirq_state *s = REALVIEW_MPCORE_RIRQ(obj);
- SysBusDevice *privbusdev;
- int i;
-
- object_initialize(&s->priv, sizeof(s->priv), TYPE_ARM11MPCORE_PRIV);
- qdev_set_parent_bus(DEVICE(&s->priv), sysbus_get_default());
- privbusdev = SYS_BUS_DEVICE(&s->priv);
- sysbus_init_mmio(sbd, sysbus_mmio_get_region(privbusdev, 0));
-
- for (i = 0; i < 4; i++) {
- object_initialize(&s->gic[i], sizeof(s->gic[i]), TYPE_REALVIEW_GIC);
- qdev_set_parent_bus(DEVICE(&s->gic[i]), sysbus_get_default());
- }
-}
-
-static Property mpcore_rirq_properties[] = {
- DEFINE_PROP_UINT32("num-cpu", mpcore_rirq_state, num_cpu, 1),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void mpcore_rirq_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = realview_mpcore_realize;
- dc->props = mpcore_rirq_properties;
-}
-
-static const TypeInfo mpcore_rirq_info = {
- .name = TYPE_REALVIEW_MPCORE_RIRQ,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(mpcore_rirq_state),
- .instance_init = mpcore_rirq_init,
- .class_init = mpcore_rirq_class_init,
-};
-
-static void realview_mpcore_register_types(void)
-{
- type_register_static(&mpcore_rirq_info);
-}
-
-type_init(realview_mpcore_register_types)
diff --git a/qemu/hw/cris/Makefile.objs b/qemu/hw/cris/Makefile.objs
deleted file mode 100644
index 7624173f7..000000000
--- a/qemu/hw/cris/Makefile.objs
+++ /dev/null
@@ -1,2 +0,0 @@
-obj-y += boot.o
-obj-y += axis_dev88.o
diff --git a/qemu/hw/cris/axis_dev88.c b/qemu/hw/cris/axis_dev88.c
deleted file mode 100644
index 9f5865874..000000000
--- a/qemu/hw/cris/axis_dev88.c
+++ /dev/null
@@ -1,365 +0,0 @@
-/*
- * QEMU model for the AXIS devboard 88.
- *
- * Copyright (c) 2009 Edgar E. Iglesias, Axis Communications AB.
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/sysbus.h"
-#include "net/net.h"
-#include "hw/block/flash.h"
-#include "hw/boards.h"
-#include "hw/cris/etraxfs.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "boot.h"
-#include "sysemu/block-backend.h"
-#include "exec/address-spaces.h"
-#include "sysemu/qtest.h"
-
-#define D(x)
-#define DNAND(x)
-
-struct nand_state_t
-{
- DeviceState *nand;
- MemoryRegion iomem;
- unsigned int rdy:1;
- unsigned int ale:1;
- unsigned int cle:1;
- unsigned int ce:1;
-};
-
-static struct nand_state_t nand_state;
-static uint64_t nand_read(void *opaque, hwaddr addr, unsigned size)
-{
- struct nand_state_t *s = opaque;
- uint32_t r;
- int rdy;
-
- r = nand_getio(s->nand);
- nand_getpins(s->nand, &rdy);
- s->rdy = rdy;
-
- DNAND(printf("%s addr=%x r=%x\n", __func__, addr, r));
- return r;
-}
-
-static void
-nand_write(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
- struct nand_state_t *s = opaque;
- int rdy;
-
- DNAND(printf("%s addr=%x v=%x\n", __func__, addr, (unsigned)value));
- nand_setpins(s->nand, s->cle, s->ale, s->ce, 1, 0);
- nand_setio(s->nand, value);
- nand_getpins(s->nand, &rdy);
- s->rdy = rdy;
-}
-
-static const MemoryRegionOps nand_ops = {
- .read = nand_read,
- .write = nand_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct tempsensor_t
-{
- unsigned int shiftreg;
- unsigned int count;
- enum {
- ST_OUT, ST_IN, ST_Z
- } state;
-
- uint16_t regs[3];
-};
-
-static void tempsensor_clkedge(struct tempsensor_t *s,
- unsigned int clk, unsigned int data_in)
-{
- D(printf("%s clk=%d state=%d sr=%x\n", __func__,
- clk, s->state, s->shiftreg));
- if (s->count == 0) {
- s->count = 16;
- s->state = ST_OUT;
- }
- switch (s->state) {
- case ST_OUT:
- /* Output reg is clocked at negedge. */
- if (!clk) {
- s->count--;
- s->shiftreg <<= 1;
- if (s->count == 0) {
- s->shiftreg = 0;
- s->state = ST_IN;
- s->count = 16;
- }
- }
- break;
- case ST_Z:
- if (clk) {
- s->count--;
- if (s->count == 0) {
- s->shiftreg = 0;
- s->state = ST_OUT;
- s->count = 16;
- }
- }
- break;
- case ST_IN:
- /* Indata is sampled at posedge. */
- if (clk) {
- s->count--;
- s->shiftreg <<= 1;
- s->shiftreg |= data_in & 1;
- if (s->count == 0) {
- D(printf("%s cfgreg=%x\n", __func__, s->shiftreg));
- s->regs[0] = s->shiftreg;
- s->state = ST_OUT;
- s->count = 16;
-
- if ((s->regs[0] & 0xff) == 0) {
- /* 25 degrees celsius. */
- s->shiftreg = 0x0b9f;
- } else if ((s->regs[0] & 0xff) == 0xff) {
- /* Sensor ID, 0x8100 LM70. */
- s->shiftreg = 0x8100;
- } else
- printf("Invalid tempsens state %x\n", s->regs[0]);
- }
- }
- break;
- }
-}
-
-
-#define RW_PA_DOUT 0x00
-#define R_PA_DIN 0x01
-#define RW_PA_OE 0x02
-#define RW_PD_DOUT 0x10
-#define R_PD_DIN 0x11
-#define RW_PD_OE 0x12
-
-static struct gpio_state_t
-{
- MemoryRegion iomem;
- struct nand_state_t *nand;
- struct tempsensor_t tempsensor;
- uint32_t regs[0x5c / 4];
-} gpio_state;
-
-static uint64_t gpio_read(void *opaque, hwaddr addr, unsigned size)
-{
- struct gpio_state_t *s = opaque;
- uint32_t r = 0;
-
- addr >>= 2;
- switch (addr)
- {
- case R_PA_DIN:
- r = s->regs[RW_PA_DOUT] & s->regs[RW_PA_OE];
-
- /* Encode pins from the nand. */
- r |= s->nand->rdy << 7;
- break;
- case R_PD_DIN:
- r = s->regs[RW_PD_DOUT] & s->regs[RW_PD_OE];
-
- /* Encode temp sensor pins. */
- r |= (!!(s->tempsensor.shiftreg & 0x10000)) << 4;
- break;
-
- default:
- r = s->regs[addr];
- break;
- }
- return r;
- D(printf("%s %x=%x\n", __func__, addr, r));
-}
-
-static void gpio_write(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
- struct gpio_state_t *s = opaque;
- D(printf("%s %x=%x\n", __func__, addr, (unsigned)value));
-
- addr >>= 2;
- switch (addr)
- {
- case RW_PA_DOUT:
- /* Decode nand pins. */
- s->nand->ale = !!(value & (1 << 6));
- s->nand->cle = !!(value & (1 << 5));
- s->nand->ce = !!(value & (1 << 4));
-
- s->regs[addr] = value;
- break;
-
- case RW_PD_DOUT:
- /* Temp sensor clk. */
- if ((s->regs[addr] ^ value) & 2)
- tempsensor_clkedge(&s->tempsensor, !!(value & 2),
- !!(value & 16));
- s->regs[addr] = value;
- break;
-
- default:
- s->regs[addr] = value;
- break;
- }
-}
-
-static const MemoryRegionOps gpio_ops = {
- .read = gpio_read,
- .write = gpio_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-#define INTMEM_SIZE (128 * 1024)
-
-static struct cris_load_info li;
-
-static
-void axisdev88_init(MachineState *machine)
-{
- ram_addr_t ram_size = machine->ram_size;
- const char *cpu_model = machine->cpu_model;
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- CRISCPU *cpu;
- CPUCRISState *env;
- DeviceState *dev;
- SysBusDevice *s;
- DriveInfo *nand;
- qemu_irq irq[30], nmi[2];
- void *etraxfs_dmac;
- struct etraxfs_dma_client *dma_eth;
- int i;
- MemoryRegion *address_space_mem = get_system_memory();
- MemoryRegion *phys_ram = g_new(MemoryRegion, 1);
- MemoryRegion *phys_intmem = g_new(MemoryRegion, 1);
-
- /* init CPUs */
- if (cpu_model == NULL) {
- cpu_model = "crisv32";
- }
- cpu = cpu_cris_init(cpu_model);
- env = &cpu->env;
-
- /* allocate RAM */
- memory_region_allocate_system_memory(phys_ram, NULL, "axisdev88.ram",
- ram_size);
- memory_region_add_subregion(address_space_mem, 0x40000000, phys_ram);
-
- /* The ETRAX-FS has 128Kb on chip ram, the docs refer to it as the
- internal memory. */
- memory_region_init_ram(phys_intmem, NULL, "axisdev88.chipram", INTMEM_SIZE,
- &error_fatal);
- vmstate_register_ram_global(phys_intmem);
- memory_region_add_subregion(address_space_mem, 0x38000000, phys_intmem);
-
- /* Attach a NAND flash to CS1. */
- nand = drive_get(IF_MTD, 0, 0);
- nand_state.nand = nand_init(nand ? blk_by_legacy_dinfo(nand) : NULL,
- NAND_MFR_STMICRO, 0x39);
- memory_region_init_io(&nand_state.iomem, NULL, &nand_ops, &nand_state,
- "nand", 0x05000000);
- memory_region_add_subregion(address_space_mem, 0x10000000,
- &nand_state.iomem);
-
- gpio_state.nand = &nand_state;
- memory_region_init_io(&gpio_state.iomem, NULL, &gpio_ops, &gpio_state,
- "gpio", 0x5c);
- memory_region_add_subregion(address_space_mem, 0x3001a000,
- &gpio_state.iomem);
-
-
- dev = qdev_create(NULL, "etraxfs,pic");
- /* FIXME: Is there a proper way to signal vectors to the CPU core? */
- qdev_prop_set_ptr(dev, "interrupt_vector", &env->interrupt_vector);
- qdev_init_nofail(dev);
- s = SYS_BUS_DEVICE(dev);
- sysbus_mmio_map(s, 0, 0x3001c000);
- sysbus_connect_irq(s, 0, qdev_get_gpio_in(DEVICE(cpu), CRIS_CPU_IRQ));
- sysbus_connect_irq(s, 1, qdev_get_gpio_in(DEVICE(cpu), CRIS_CPU_NMI));
- for (i = 0; i < 30; i++) {
- irq[i] = qdev_get_gpio_in(dev, i);
- }
- nmi[0] = qdev_get_gpio_in(dev, 30);
- nmi[1] = qdev_get_gpio_in(dev, 31);
-
- etraxfs_dmac = etraxfs_dmac_init(0x30000000, 10);
- for (i = 0; i < 10; i++) {
- /* On ETRAX, odd numbered channels are inputs. */
- etraxfs_dmac_connect(etraxfs_dmac, i, irq + 7 + i, i & 1);
- }
-
- /* Add the two ethernet blocks. */
- dma_eth = g_malloc0(sizeof dma_eth[0] * 4); /* Allocate 4 channels. */
- etraxfs_eth_init(&nd_table[0], 0x30034000, 1, &dma_eth[0], &dma_eth[1]);
- if (nb_nics > 1) {
- etraxfs_eth_init(&nd_table[1], 0x30036000, 2, &dma_eth[2], &dma_eth[3]);
- }
-
- /* The DMA Connector block is missing, hardwire things for now. */
- etraxfs_dmac_connect_client(etraxfs_dmac, 0, &dma_eth[0]);
- etraxfs_dmac_connect_client(etraxfs_dmac, 1, &dma_eth[1]);
- if (nb_nics > 1) {
- etraxfs_dmac_connect_client(etraxfs_dmac, 6, &dma_eth[2]);
- etraxfs_dmac_connect_client(etraxfs_dmac, 7, &dma_eth[3]);
- }
-
- /* 2 timers. */
- sysbus_create_varargs("etraxfs,timer", 0x3001e000, irq[0x1b], nmi[1], NULL);
- sysbus_create_varargs("etraxfs,timer", 0x3005e000, irq[0x1b], nmi[1], NULL);
-
- for (i = 0; i < 4; i++) {
- sysbus_create_simple("etraxfs,serial", 0x30026000 + i * 0x2000,
- irq[0x14 + i]);
- }
-
- if (kernel_filename) {
- li.image_filename = kernel_filename;
- li.cmdline = kernel_cmdline;
- cris_load_image(cpu, &li);
- } else if (!qtest_enabled()) {
- fprintf(stderr, "Kernel image must be specified\n");
- exit(1);
- }
-}
-
-static void axisdev88_machine_init(MachineClass *mc)
-{
- mc->desc = "AXIS devboard 88";
- mc->init = axisdev88_init;
- mc->is_default = 1;
-}
-
-DEFINE_MACHINE("axis-dev88", axisdev88_machine_init)
diff --git a/qemu/hw/cris/boot.c b/qemu/hw/cris/boot.c
deleted file mode 100644
index f896ed7f8..000000000
--- a/qemu/hw/cris/boot.c
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * CRIS image loading.
- *
- * Copyright (c) 2010 Edgar E. Iglesias, Axis Communications AB.
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/hw.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "boot.h"
-#include "qemu/cutils.h"
-
-static void main_cpu_reset(void *opaque)
-{
- CRISCPU *cpu = opaque;
- CPUCRISState *env = &cpu->env;
- struct cris_load_info *li;
-
- li = env->load_info;
-
- cpu_reset(CPU(cpu));
-
- if (!li) {
- /* nothing more to do. */
- return;
- }
-
- env->pc = li->entry;
-
- if (li->image_filename) {
- env->regs[8] = 0x56902387; /* RAM boot magic. */
- env->regs[9] = 0x40004000 + li->image_size;
- }
-
- if (li->cmdline) {
- /* Let the kernel know we are modifying the cmdline. */
- env->regs[10] = 0x87109563;
- env->regs[11] = 0x40000000;
- }
-}
-
-static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
-{
- return addr - 0x80000000LL;
-}
-
-void cris_load_image(CRISCPU *cpu, struct cris_load_info *li)
-{
- CPUCRISState *env = &cpu->env;
- uint64_t entry, high;
- int kcmdline_len;
- int image_size;
-
- env->load_info = li;
- /* Boots a kernel elf binary, os/linux-2.6/vmlinux from the axis
- devboard SDK. */
- image_size = load_elf(li->image_filename, translate_kernel_address, NULL,
- &entry, NULL, &high, 0, EM_CRIS, 0, 0);
- li->entry = entry;
- if (image_size < 0) {
- /* Takes a kimage from the axis devboard SDK. */
- image_size = load_image_targphys(li->image_filename, 0x40004000,
- ram_size);
- li->entry = 0x40004000;
- }
-
- if (image_size < 0) {
- fprintf(stderr, "qemu: could not load kernel '%s'\n",
- li->image_filename);
- exit(1);
- }
-
- if (li->cmdline && (kcmdline_len = strlen(li->cmdline))) {
- if (kcmdline_len > 256) {
- fprintf(stderr, "Too long CRIS kernel cmdline (max 256)\n");
- exit(1);
- }
- pstrcpy_targphys("cmdline", 0x40000000, 256, li->cmdline);
- }
- qemu_register_reset(main_cpu_reset, cpu);
-}
diff --git a/qemu/hw/cris/boot.h b/qemu/hw/cris/boot.h
deleted file mode 100644
index c4d3fa6f6..000000000
--- a/qemu/hw/cris/boot.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef _CRIS_BOOT_H
-#define HW_CRIS_BOOT_H 1
-
-struct cris_load_info
-{
- const char *image_filename;
- const char *cmdline;
- int image_size;
-
- hwaddr entry;
-};
-
-void cris_load_image(CRISCPU *cpu, struct cris_load_info *li);
-
-#endif
diff --git a/qemu/hw/display/Makefile.objs b/qemu/hw/display/Makefile.objs
deleted file mode 100644
index d99780eeb..000000000
--- a/qemu/hw/display/Makefile.objs
+++ /dev/null
@@ -1,45 +0,0 @@
-common-obj-$(CONFIG_ADS7846) += ads7846.o
-common-obj-$(CONFIG_VGA_CIRRUS) += cirrus_vga.o
-common-obj-$(CONFIG_G364FB) += g364fb.o
-common-obj-$(CONFIG_JAZZ_LED) += jazz_led.o
-common-obj-$(CONFIG_PL110) += pl110.o
-common-obj-$(CONFIG_SSD0303) += ssd0303.o
-common-obj-$(CONFIG_SSD0323) += ssd0323.o
-common-obj-$(CONFIG_XEN_BACKEND) += xenfb.o
-
-common-obj-$(CONFIG_VGA_PCI) += vga-pci.o
-common-obj-$(CONFIG_VGA_ISA) += vga-isa.o
-common-obj-$(CONFIG_VGA_ISA_MM) += vga-isa-mm.o
-common-obj-$(CONFIG_VMWARE_VGA) += vmware_vga.o
-
-common-obj-$(CONFIG_BLIZZARD) += blizzard.o
-common-obj-$(CONFIG_EXYNOS4) += exynos4210_fimd.o
-common-obj-$(CONFIG_FRAMEBUFFER) += framebuffer.o
-common-obj-$(CONFIG_MILKYMIST) += milkymist-vgafb.o
-common-obj-$(CONFIG_ZAURUS) += tc6393xb.o
-
-ifeq ($(CONFIG_MILKYMIST_TMU2),y)
-common-obj-y += milkymist-tmu2.o
-milkymist-tmu2.o-cflags := $(OPENGL_CFLAGS)
-milkymist-tmu2.o-libs += $(OPENGL_LIBS)
-endif
-
-obj-$(CONFIG_OMAP) += omap_dss.o
-obj-$(CONFIG_OMAP) += omap_lcdc.o
-obj-$(CONFIG_PXA2XX) += pxa2xx_lcd.o
-obj-$(CONFIG_RASPI) += bcm2835_fb.o
-obj-$(CONFIG_SM501) += sm501.o
-obj-$(CONFIG_TCX) += tcx.o
-obj-$(CONFIG_CG3) += cg3.o
-
-obj-$(CONFIG_VGA) += vga.o
-
-common-obj-$(CONFIG_QXL) += qxl.o qxl-logger.o qxl-render.o
-
-obj-$(CONFIG_VIRTIO) += virtio-gpu.o virtio-gpu-3d.o
-obj-$(CONFIG_VIRTIO_PCI) += virtio-gpu-pci.o
-obj-$(CONFIG_VIRTIO_VGA) += virtio-vga.o
-virtio-gpu.o-cflags := $(VIRGL_CFLAGS)
-virtio-gpu.o-libs += $(VIRGL_LIBS)
-virtio-gpu-3d.o-cflags := $(VIRGL_CFLAGS)
-virtio-gpu-3d.o-libs += $(VIRGL_LIBS)
diff --git a/qemu/hw/display/ads7846.c b/qemu/hw/display/ads7846.c
deleted file mode 100644
index 05aa2d1e6..000000000
--- a/qemu/hw/display/ads7846.c
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * TI ADS7846 / TSC2046 chip emulation.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "hw/ssi/ssi.h"
-#include "ui/console.h"
-
-typedef struct {
- SSISlave ssidev;
- qemu_irq interrupt;
-
- int input[8];
- int pressure;
- int noise;
-
- int cycle;
- int output;
-} ADS7846State;
-
-/* Control-byte bitfields */
-#define CB_PD0 (1 << 0)
-#define CB_PD1 (1 << 1)
-#define CB_SER (1 << 2)
-#define CB_MODE (1 << 3)
-#define CB_A0 (1 << 4)
-#define CB_A1 (1 << 5)
-#define CB_A2 (1 << 6)
-#define CB_START (1 << 7)
-
-#define X_AXIS_DMAX 3470
-#define X_AXIS_MIN 290
-#define Y_AXIS_DMAX 3450
-#define Y_AXIS_MIN 200
-
-#define ADS_VBAT 2000
-#define ADS_VAUX 2000
-#define ADS_TEMP0 2000
-#define ADS_TEMP1 3000
-#define ADS_XPOS(x, y) (X_AXIS_MIN + ((X_AXIS_DMAX * (x)) >> 15))
-#define ADS_YPOS(x, y) (Y_AXIS_MIN + ((Y_AXIS_DMAX * (y)) >> 15))
-#define ADS_Z1POS(x, y) 600
-#define ADS_Z2POS(x, y) (600 + 6000 / ADS_XPOS(x, y))
-
-static void ads7846_int_update(ADS7846State *s)
-{
- if (s->interrupt)
- qemu_set_irq(s->interrupt, s->pressure == 0);
-}
-
-static uint32_t ads7846_transfer(SSISlave *dev, uint32_t value)
-{
- ADS7846State *s = FROM_SSI_SLAVE(ADS7846State, dev);
-
- switch (s->cycle ++) {
- case 0:
- if (!(value & CB_START)) {
- s->cycle = 0;
- break;
- }
-
- s->output = s->input[(value >> 4) & 7];
-
- /* Imitate the ADC noise, some drivers expect this. */
- s->noise = (s->noise + 3) & 7;
- switch ((value >> 4) & 7) {
- case 1: s->output += s->noise ^ 2; break;
- case 3: s->output += s->noise ^ 0; break;
- case 4: s->output += s->noise ^ 7; break;
- case 5: s->output += s->noise ^ 5; break;
- }
-
- if (value & CB_MODE)
- s->output >>= 4; /* 8 bits instead of 12 */
-
- break;
- case 1:
- s->cycle = 0;
- break;
- }
- return s->output;
-}
-
-static void ads7846_ts_event(void *opaque,
- int x, int y, int z, int buttons_state)
-{
- ADS7846State *s = opaque;
-
- if (buttons_state) {
- x = 0x7fff - x;
- s->input[1] = ADS_XPOS(x, y);
- s->input[3] = ADS_Z1POS(x, y);
- s->input[4] = ADS_Z2POS(x, y);
- s->input[5] = ADS_YPOS(x, y);
- }
-
- if (s->pressure == !buttons_state) {
- s->pressure = !!buttons_state;
-
- ads7846_int_update(s);
- }
-}
-
-static int ads7856_post_load(void *opaque, int version_id)
-{
- ADS7846State *s = opaque;
-
- s->pressure = 0;
- ads7846_int_update(s);
- return 0;
-}
-
-static const VMStateDescription vmstate_ads7846 = {
- .name = "ads7846",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = ads7856_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_SSI_SLAVE(ssidev, ADS7846State),
- VMSTATE_INT32_ARRAY(input, ADS7846State, 8),
- VMSTATE_INT32(noise, ADS7846State),
- VMSTATE_INT32(cycle, ADS7846State),
- VMSTATE_INT32(output, ADS7846State),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static int ads7846_init(SSISlave *d)
-{
- DeviceState *dev = DEVICE(d);
- ADS7846State *s = FROM_SSI_SLAVE(ADS7846State, d);
-
- qdev_init_gpio_out(dev, &s->interrupt, 1);
-
- s->input[0] = ADS_TEMP0; /* TEMP0 */
- s->input[2] = ADS_VBAT; /* VBAT */
- s->input[6] = ADS_VAUX; /* VAUX */
- s->input[7] = ADS_TEMP1; /* TEMP1 */
-
- /* We want absolute coordinates */
- qemu_add_mouse_event_handler(ads7846_ts_event, s, 1,
- "QEMU ADS7846-driven Touchscreen");
-
- ads7846_int_update(s);
-
- vmstate_register(NULL, -1, &vmstate_ads7846, s);
- return 0;
-}
-
-static void ads7846_class_init(ObjectClass *klass, void *data)
-{
- SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
-
- k->init = ads7846_init;
- k->transfer = ads7846_transfer;
-}
-
-static const TypeInfo ads7846_info = {
- .name = "ads7846",
- .parent = TYPE_SSI_SLAVE,
- .instance_size = sizeof(ADS7846State),
- .class_init = ads7846_class_init,
-};
-
-static void ads7846_register_types(void)
-{
- type_register_static(&ads7846_info);
-}
-
-type_init(ads7846_register_types)
diff --git a/qemu/hw/display/bcm2835_fb.c b/qemu/hw/display/bcm2835_fb.c
deleted file mode 100644
index 506f1d3d9..000000000
--- a/qemu/hw/display/bcm2835_fb.c
+++ /dev/null
@@ -1,425 +0,0 @@
-/*
- * Raspberry Pi emulation (c) 2012 Gregory Estrade
- * Refactoring for Pi2 Copyright (c) 2015, Microsoft. Written by Andrew Baumann.
- * This code is licensed under the GNU GPLv2 and later.
- *
- * Heavily based on milkymist-vgafb.c, copyright terms below:
- * QEMU model of the Milkymist VGA framebuffer.
- *
- * Copyright (c) 2010-2012 Michael Walle <michael@walle.cc>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/display/bcm2835_fb.h"
-#include "hw/display/framebuffer.h"
-#include "ui/pixel_ops.h"
-#include "hw/misc/bcm2835_mbox_defs.h"
-
-#define DEFAULT_VCRAM_SIZE 0x4000000
-#define BCM2835_FB_OFFSET 0x00100000
-
-static void fb_invalidate_display(void *opaque)
-{
- BCM2835FBState *s = BCM2835_FB(opaque);
-
- s->invalidate = true;
-}
-
-static void draw_line_src16(void *opaque, uint8_t *dst, const uint8_t *src,
- int width, int deststep)
-{
- BCM2835FBState *s = opaque;
- uint16_t rgb565;
- uint32_t rgb888;
- uint8_t r, g, b;
- DisplaySurface *surface = qemu_console_surface(s->con);
- int bpp = surface_bits_per_pixel(surface);
-
- while (width--) {
- switch (s->bpp) {
- case 8:
- /* lookup palette starting at video ram base
- * TODO: cache translation, rather than doing this each time!
- */
- rgb888 = ldl_le_phys(&s->dma_as, s->vcram_base + (*src << 2));
- r = (rgb888 >> 0) & 0xff;
- g = (rgb888 >> 8) & 0xff;
- b = (rgb888 >> 16) & 0xff;
- src++;
- break;
- case 16:
- rgb565 = lduw_le_p(src);
- r = ((rgb565 >> 11) & 0x1f) << 3;
- g = ((rgb565 >> 5) & 0x3f) << 2;
- b = ((rgb565 >> 0) & 0x1f) << 3;
- src += 2;
- break;
- case 24:
- rgb888 = ldl_le_p(src);
- r = (rgb888 >> 0) & 0xff;
- g = (rgb888 >> 8) & 0xff;
- b = (rgb888 >> 16) & 0xff;
- src += 3;
- break;
- case 32:
- rgb888 = ldl_le_p(src);
- r = (rgb888 >> 0) & 0xff;
- g = (rgb888 >> 8) & 0xff;
- b = (rgb888 >> 16) & 0xff;
- src += 4;
- break;
- default:
- r = 0;
- g = 0;
- b = 0;
- break;
- }
-
- if (s->pixo == 0) {
- /* swap to BGR pixel format */
- uint8_t tmp = r;
- r = b;
- b = tmp;
- }
-
- switch (bpp) {
- case 8:
- *dst++ = rgb_to_pixel8(r, g, b);
- break;
- case 15:
- *(uint16_t *)dst = rgb_to_pixel15(r, g, b);
- dst += 2;
- break;
- case 16:
- *(uint16_t *)dst = rgb_to_pixel16(r, g, b);
- dst += 2;
- break;
- case 24:
- rgb888 = rgb_to_pixel24(r, g, b);
- *dst++ = rgb888 & 0xff;
- *dst++ = (rgb888 >> 8) & 0xff;
- *dst++ = (rgb888 >> 16) & 0xff;
- break;
- case 32:
- *(uint32_t *)dst = rgb_to_pixel32(r, g, b);
- dst += 4;
- break;
- default:
- return;
- }
- }
-}
-
-static void fb_update_display(void *opaque)
-{
- BCM2835FBState *s = opaque;
- DisplaySurface *surface = qemu_console_surface(s->con);
- int first = 0;
- int last = 0;
- int src_width = 0;
- int dest_width = 0;
-
- if (s->lock || !s->xres) {
- return;
- }
-
- src_width = s->xres * (s->bpp >> 3);
- dest_width = s->xres;
-
- switch (surface_bits_per_pixel(surface)) {
- case 0:
- return;
- case 8:
- break;
- case 15:
- dest_width *= 2;
- break;
- case 16:
- dest_width *= 2;
- break;
- case 24:
- dest_width *= 3;
- break;
- case 32:
- dest_width *= 4;
- break;
- default:
- hw_error("bcm2835_fb: bad color depth\n");
- break;
- }
-
- if (s->invalidate) {
- framebuffer_update_memory_section(&s->fbsection, s->dma_mr, s->base,
- s->yres, src_width);
- }
-
- framebuffer_update_display(surface, &s->fbsection, s->xres, s->yres,
- src_width, dest_width, 0, s->invalidate,
- draw_line_src16, s, &first, &last);
-
- if (first >= 0) {
- dpy_gfx_update(s->con, 0, first, s->xres, last - first + 1);
- }
-
- s->invalidate = false;
-}
-
-static void bcm2835_fb_mbox_push(BCM2835FBState *s, uint32_t value)
-{
- value &= ~0xf;
-
- s->lock = true;
-
- s->xres = ldl_le_phys(&s->dma_as, value);
- s->yres = ldl_le_phys(&s->dma_as, value + 4);
- s->xres_virtual = ldl_le_phys(&s->dma_as, value + 8);
- s->yres_virtual = ldl_le_phys(&s->dma_as, value + 12);
- s->bpp = ldl_le_phys(&s->dma_as, value + 20);
- s->xoffset = ldl_le_phys(&s->dma_as, value + 24);
- s->yoffset = ldl_le_phys(&s->dma_as, value + 28);
-
- s->base = s->vcram_base | (value & 0xc0000000);
- s->base += BCM2835_FB_OFFSET;
-
- /* TODO - Manage properly virtual resolution */
-
- s->pitch = s->xres * (s->bpp >> 3);
- s->size = s->yres * s->pitch;
-
- stl_le_phys(&s->dma_as, value + 16, s->pitch);
- stl_le_phys(&s->dma_as, value + 32, s->base);
- stl_le_phys(&s->dma_as, value + 36, s->size);
-
- s->invalidate = true;
- qemu_console_resize(s->con, s->xres, s->yres);
- s->lock = false;
-}
-
-void bcm2835_fb_reconfigure(BCM2835FBState *s, uint32_t *xres, uint32_t *yres,
- uint32_t *xoffset, uint32_t *yoffset, uint32_t *bpp,
- uint32_t *pixo, uint32_t *alpha)
-{
- s->lock = true;
-
- /* TODO: input validation! */
- if (xres) {
- s->xres = *xres;
- }
- if (yres) {
- s->yres = *yres;
- }
- if (xoffset) {
- s->xoffset = *xoffset;
- }
- if (yoffset) {
- s->yoffset = *yoffset;
- }
- if (bpp) {
- s->bpp = *bpp;
- }
- if (pixo) {
- s->pixo = *pixo;
- }
- if (alpha) {
- s->alpha = *alpha;
- }
-
- /* TODO - Manage properly virtual resolution */
-
- s->pitch = s->xres * (s->bpp >> 3);
- s->size = s->yres * s->pitch;
-
- s->invalidate = true;
- qemu_console_resize(s->con, s->xres, s->yres);
- s->lock = false;
-}
-
-static uint64_t bcm2835_fb_read(void *opaque, hwaddr offset, unsigned size)
-{
- BCM2835FBState *s = opaque;
- uint32_t res = 0;
-
- switch (offset) {
- case MBOX_AS_DATA:
- res = MBOX_CHAN_FB;
- s->pending = false;
- qemu_set_irq(s->mbox_irq, 0);
- break;
-
- case MBOX_AS_PENDING:
- res = s->pending;
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
- __func__, offset);
- return 0;
- }
-
- return res;
-}
-
-static void bcm2835_fb_write(void *opaque, hwaddr offset, uint64_t value,
- unsigned size)
-{
- BCM2835FBState *s = opaque;
-
- switch (offset) {
- case MBOX_AS_DATA:
- /* bcm2835_mbox should check our pending status before pushing */
- assert(!s->pending);
- s->pending = true;
- bcm2835_fb_mbox_push(s, value);
- qemu_set_irq(s->mbox_irq, 1);
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
- __func__, offset);
- return;
- }
-}
-
-static const MemoryRegionOps bcm2835_fb_ops = {
- .read = bcm2835_fb_read,
- .write = bcm2835_fb_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid.min_access_size = 4,
- .valid.max_access_size = 4,
-};
-
-static const VMStateDescription vmstate_bcm2835_fb = {
- .name = TYPE_BCM2835_FB,
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_BOOL(lock, BCM2835FBState),
- VMSTATE_BOOL(invalidate, BCM2835FBState),
- VMSTATE_BOOL(pending, BCM2835FBState),
- VMSTATE_UINT32(xres, BCM2835FBState),
- VMSTATE_UINT32(yres, BCM2835FBState),
- VMSTATE_UINT32(xres_virtual, BCM2835FBState),
- VMSTATE_UINT32(yres_virtual, BCM2835FBState),
- VMSTATE_UINT32(xoffset, BCM2835FBState),
- VMSTATE_UINT32(yoffset, BCM2835FBState),
- VMSTATE_UINT32(bpp, BCM2835FBState),
- VMSTATE_UINT32(base, BCM2835FBState),
- VMSTATE_UINT32(pitch, BCM2835FBState),
- VMSTATE_UINT32(size, BCM2835FBState),
- VMSTATE_UINT32(pixo, BCM2835FBState),
- VMSTATE_UINT32(alpha, BCM2835FBState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const GraphicHwOps vgafb_ops = {
- .invalidate = fb_invalidate_display,
- .gfx_update = fb_update_display,
-};
-
-static void bcm2835_fb_init(Object *obj)
-{
- BCM2835FBState *s = BCM2835_FB(obj);
-
- memory_region_init_io(&s->iomem, obj, &bcm2835_fb_ops, s, TYPE_BCM2835_FB,
- 0x10);
- sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
- sysbus_init_irq(SYS_BUS_DEVICE(s), &s->mbox_irq);
-}
-
-static void bcm2835_fb_reset(DeviceState *dev)
-{
- BCM2835FBState *s = BCM2835_FB(dev);
-
- s->pending = false;
-
- s->xres_virtual = s->xres;
- s->yres_virtual = s->yres;
- s->xoffset = 0;
- s->yoffset = 0;
- s->base = s->vcram_base + BCM2835_FB_OFFSET;
- s->pitch = s->xres * (s->bpp >> 3);
- s->size = s->yres * s->pitch;
-
- s->invalidate = true;
- s->lock = false;
-}
-
-static void bcm2835_fb_realize(DeviceState *dev, Error **errp)
-{
- BCM2835FBState *s = BCM2835_FB(dev);
- Error *err = NULL;
- Object *obj;
-
- if (s->vcram_base == 0) {
- error_setg(errp, "%s: required vcram-base property not set", __func__);
- return;
- }
-
- obj = object_property_get_link(OBJECT(dev), "dma-mr", &err);
- if (obj == NULL) {
- error_setg(errp, "%s: required dma-mr link not found: %s",
- __func__, error_get_pretty(err));
- return;
- }
-
- s->dma_mr = MEMORY_REGION(obj);
- address_space_init(&s->dma_as, s->dma_mr, NULL);
-
- bcm2835_fb_reset(dev);
-
- s->con = graphic_console_init(dev, 0, &vgafb_ops, s);
- qemu_console_resize(s->con, s->xres, s->yres);
-}
-
-static Property bcm2835_fb_props[] = {
- DEFINE_PROP_UINT32("vcram-base", BCM2835FBState, vcram_base, 0),/*required*/
- DEFINE_PROP_UINT32("vcram-size", BCM2835FBState, vcram_size,
- DEFAULT_VCRAM_SIZE),
- DEFINE_PROP_UINT32("xres", BCM2835FBState, xres, 640),
- DEFINE_PROP_UINT32("yres", BCM2835FBState, yres, 480),
- DEFINE_PROP_UINT32("bpp", BCM2835FBState, bpp, 16),
- DEFINE_PROP_UINT32("pixo", BCM2835FBState, pixo, 1), /* 1=RGB, 0=BGR */
- DEFINE_PROP_UINT32("alpha", BCM2835FBState, alpha, 2), /* alpha ignored */
- DEFINE_PROP_END_OF_LIST()
-};
-
-static void bcm2835_fb_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->props = bcm2835_fb_props;
- dc->realize = bcm2835_fb_realize;
- dc->reset = bcm2835_fb_reset;
- dc->vmsd = &vmstate_bcm2835_fb;
-}
-
-static TypeInfo bcm2835_fb_info = {
- .name = TYPE_BCM2835_FB,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(BCM2835FBState),
- .class_init = bcm2835_fb_class_init,
- .instance_init = bcm2835_fb_init,
-};
-
-static void bcm2835_fb_register_types(void)
-{
- type_register_static(&bcm2835_fb_info);
-}
-
-type_init(bcm2835_fb_register_types)
diff --git a/qemu/hw/display/blizzard.c b/qemu/hw/display/blizzard.c
deleted file mode 100644
index c231960d9..000000000
--- a/qemu/hw/display/blizzard.c
+++ /dev/null
@@ -1,987 +0,0 @@
-/*
- * Epson S1D13744/S1D13745 (Blizzard/Hailstorm/Tornado) LCD/TV controller.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "ui/console.h"
-#include "hw/devices.h"
-#include "ui/pixel_ops.h"
-
-typedef void (*blizzard_fn_t)(uint8_t *, const uint8_t *, unsigned int);
-
-typedef struct {
- uint8_t reg;
- uint32_t addr;
- int swallow;
-
- int pll;
- int pll_range;
- int pll_ctrl;
- uint8_t pll_mode;
- uint8_t clksel;
- int memenable;
- int memrefresh;
- uint8_t timing[3];
- int priority;
-
- uint8_t lcd_config;
- int x;
- int y;
- int skipx;
- int skipy;
- uint8_t hndp;
- uint8_t vndp;
- uint8_t hsync;
- uint8_t vsync;
- uint8_t pclk;
- uint8_t u;
- uint8_t v;
- uint8_t yrc[2];
- int ix[2];
- int iy[2];
- int ox[2];
- int oy[2];
-
- int enable;
- int blank;
- int bpp;
- int invalidate;
- int mx[2];
- int my[2];
- uint8_t mode;
- uint8_t effect;
- uint8_t iformat;
- uint8_t source;
- QemuConsole *con;
- blizzard_fn_t *line_fn_tab[2];
- void *fb;
-
- uint8_t hssi_config[3];
- uint8_t tv_config;
- uint8_t tv_timing[4];
- uint8_t vbi;
- uint8_t tv_x;
- uint8_t tv_y;
- uint8_t tv_test;
- uint8_t tv_filter_config;
- uint8_t tv_filter_idx;
- uint8_t tv_filter_coeff[0x20];
- uint8_t border_r;
- uint8_t border_g;
- uint8_t border_b;
- uint8_t gamma_config;
- uint8_t gamma_idx;
- uint8_t gamma_lut[0x100];
- uint8_t matrix_ena;
- uint8_t matrix_coeff[0x12];
- uint8_t matrix_r;
- uint8_t matrix_g;
- uint8_t matrix_b;
- uint8_t pm;
- uint8_t status;
- uint8_t rgbgpio_dir;
- uint8_t rgbgpio;
- uint8_t gpio_dir;
- uint8_t gpio;
- uint8_t gpio_edge[2];
- uint8_t gpio_irq;
- uint8_t gpio_pdown;
-
- struct {
- int x;
- int y;
- int dx;
- int dy;
- int len;
- int buflen;
- void *buf;
- void *data;
- uint16_t *ptr;
- int angle;
- int pitch;
- blizzard_fn_t line_fn;
- } data;
-} BlizzardState;
-
-/* Bytes(!) per pixel */
-static const int blizzard_iformat_bpp[0x10] = {
- 0,
- 2, /* RGB 5:6:5*/
- 3, /* RGB 6:6:6 mode 1 */
- 3, /* RGB 8:8:8 mode 1 */
- 0, 0,
- 4, /* RGB 6:6:6 mode 2 */
- 4, /* RGB 8:8:8 mode 2 */
- 0, /* YUV 4:2:2 */
- 0, /* YUV 4:2:0 */
- 0, 0, 0, 0, 0, 0,
-};
-
-static void blizzard_window(BlizzardState *s)
-{
- DisplaySurface *surface = qemu_console_surface(s->con);
- uint8_t *src, *dst;
- int bypp[2];
- int bypl[3];
- int y;
- blizzard_fn_t fn = s->data.line_fn;
-
- if (!fn)
- return;
- if (s->mx[0] > s->data.x)
- s->mx[0] = s->data.x;
- if (s->my[0] > s->data.y)
- s->my[0] = s->data.y;
- if (s->mx[1] < s->data.x + s->data.dx)
- s->mx[1] = s->data.x + s->data.dx;
- if (s->my[1] < s->data.y + s->data.dy)
- s->my[1] = s->data.y + s->data.dy;
-
- bypp[0] = s->bpp;
- bypp[1] = surface_bytes_per_pixel(surface);
- bypl[0] = bypp[0] * s->data.pitch;
- bypl[1] = bypp[1] * s->x;
- bypl[2] = bypp[0] * s->data.dx;
-
- src = s->data.data;
- dst = s->fb + bypl[1] * s->data.y + bypp[1] * s->data.x;
- for (y = s->data.dy; y > 0; y --, src += bypl[0], dst += bypl[1])
- fn(dst, src, bypl[2]);
-}
-
-static int blizzard_transfer_setup(BlizzardState *s)
-{
- if (s->source > 3 || !s->bpp ||
- s->ix[1] < s->ix[0] || s->iy[1] < s->iy[0])
- return 0;
-
- s->data.angle = s->effect & 3;
- s->data.line_fn = s->line_fn_tab[!!s->data.angle][s->iformat];
- s->data.x = s->ix[0];
- s->data.y = s->iy[0];
- s->data.dx = s->ix[1] - s->ix[0] + 1;
- s->data.dy = s->iy[1] - s->iy[0] + 1;
- s->data.len = s->bpp * s->data.dx * s->data.dy;
- s->data.pitch = s->data.dx;
- if (s->data.len > s->data.buflen) {
- s->data.buf = g_realloc(s->data.buf, s->data.len);
- s->data.buflen = s->data.len;
- }
- s->data.ptr = s->data.buf;
- s->data.data = s->data.buf;
- s->data.len /= 2;
- return 1;
-}
-
-static void blizzard_reset(BlizzardState *s)
-{
- s->reg = 0;
- s->swallow = 0;
-
- s->pll = 9;
- s->pll_range = 1;
- s->pll_ctrl = 0x14;
- s->pll_mode = 0x32;
- s->clksel = 0x00;
- s->memenable = 0;
- s->memrefresh = 0x25c;
- s->timing[0] = 0x3f;
- s->timing[1] = 0x13;
- s->timing[2] = 0x21;
- s->priority = 0;
-
- s->lcd_config = 0x74;
- s->x = 8;
- s->y = 1;
- s->skipx = 0;
- s->skipy = 0;
- s->hndp = 3;
- s->vndp = 2;
- s->hsync = 1;
- s->vsync = 1;
- s->pclk = 0x80;
-
- s->ix[0] = 0;
- s->ix[1] = 0;
- s->iy[0] = 0;
- s->iy[1] = 0;
- s->ox[0] = 0;
- s->ox[1] = 0;
- s->oy[0] = 0;
- s->oy[1] = 0;
-
- s->yrc[0] = 0x00;
- s->yrc[1] = 0x30;
- s->u = 0;
- s->v = 0;
-
- s->iformat = 3;
- s->source = 0;
- s->bpp = blizzard_iformat_bpp[s->iformat];
-
- s->hssi_config[0] = 0x00;
- s->hssi_config[1] = 0x00;
- s->hssi_config[2] = 0x01;
- s->tv_config = 0x00;
- s->tv_timing[0] = 0x00;
- s->tv_timing[1] = 0x00;
- s->tv_timing[2] = 0x00;
- s->tv_timing[3] = 0x00;
- s->vbi = 0x10;
- s->tv_x = 0x14;
- s->tv_y = 0x03;
- s->tv_test = 0x00;
- s->tv_filter_config = 0x80;
- s->tv_filter_idx = 0x00;
- s->border_r = 0x10;
- s->border_g = 0x80;
- s->border_b = 0x80;
- s->gamma_config = 0x00;
- s->gamma_idx = 0x00;
- s->matrix_ena = 0x00;
- memset(&s->matrix_coeff, 0, sizeof(s->matrix_coeff));
- s->matrix_r = 0x00;
- s->matrix_g = 0x00;
- s->matrix_b = 0x00;
- s->pm = 0x02;
- s->status = 0x00;
- s->rgbgpio_dir = 0x00;
- s->gpio_dir = 0x00;
- s->gpio_edge[0] = 0x00;
- s->gpio_edge[1] = 0x00;
- s->gpio_irq = 0x00;
- s->gpio_pdown = 0xff;
-}
-
-static inline void blizzard_invalidate_display(void *opaque) {
- BlizzardState *s = (BlizzardState *) opaque;
-
- s->invalidate = 1;
-}
-
-static uint16_t blizzard_reg_read(void *opaque, uint8_t reg)
-{
- BlizzardState *s = (BlizzardState *) opaque;
-
- switch (reg) {
- case 0x00: /* Revision Code */
- return 0xa5;
-
- case 0x02: /* Configuration Readback */
- return 0x83; /* Macrovision OK, CNF[2:0] = 3 */
-
- case 0x04: /* PLL M-Divider */
- return (s->pll - 1) | (1 << 7);
- case 0x06: /* PLL Lock Range Control */
- return s->pll_range;
- case 0x08: /* PLL Lock Synthesis Control 0 */
- return s->pll_ctrl & 0xff;
- case 0x0a: /* PLL Lock Synthesis Control 1 */
- return s->pll_ctrl >> 8;
- case 0x0c: /* PLL Mode Control 0 */
- return s->pll_mode;
-
- case 0x0e: /* Clock-Source Select */
- return s->clksel;
-
- case 0x10: /* Memory Controller Activate */
- case 0x14: /* Memory Controller Bank 0 Status Flag */
- return s->memenable;
-
- case 0x18: /* Auto-Refresh Interval Setting 0 */
- return s->memrefresh & 0xff;
- case 0x1a: /* Auto-Refresh Interval Setting 1 */
- return s->memrefresh >> 8;
-
- case 0x1c: /* Power-On Sequence Timing Control */
- return s->timing[0];
- case 0x1e: /* Timing Control 0 */
- return s->timing[1];
- case 0x20: /* Timing Control 1 */
- return s->timing[2];
-
- case 0x24: /* Arbitration Priority Control */
- return s->priority;
-
- case 0x28: /* LCD Panel Configuration */
- return s->lcd_config;
-
- case 0x2a: /* LCD Horizontal Display Width */
- return s->x >> 3;
- case 0x2c: /* LCD Horizontal Non-display Period */
- return s->hndp;
- case 0x2e: /* LCD Vertical Display Height 0 */
- return s->y & 0xff;
- case 0x30: /* LCD Vertical Display Height 1 */
- return s->y >> 8;
- case 0x32: /* LCD Vertical Non-display Period */
- return s->vndp;
- case 0x34: /* LCD HS Pulse-width */
- return s->hsync;
- case 0x36: /* LCd HS Pulse Start Position */
- return s->skipx >> 3;
- case 0x38: /* LCD VS Pulse-width */
- return s->vsync;
- case 0x3a: /* LCD VS Pulse Start Position */
- return s->skipy;
-
- case 0x3c: /* PCLK Polarity */
- return s->pclk;
-
- case 0x3e: /* High-speed Serial Interface Tx Configuration Port 0 */
- return s->hssi_config[0];
- case 0x40: /* High-speed Serial Interface Tx Configuration Port 1 */
- return s->hssi_config[1];
- case 0x42: /* High-speed Serial Interface Tx Mode */
- return s->hssi_config[2];
- case 0x44: /* TV Display Configuration */
- return s->tv_config;
- case 0x46 ... 0x4c: /* TV Vertical Blanking Interval Data bits */
- return s->tv_timing[(reg - 0x46) >> 1];
- case 0x4e: /* VBI: Closed Caption / XDS Control / Status */
- return s->vbi;
- case 0x50: /* TV Horizontal Start Position */
- return s->tv_x;
- case 0x52: /* TV Vertical Start Position */
- return s->tv_y;
- case 0x54: /* TV Test Pattern Setting */
- return s->tv_test;
- case 0x56: /* TV Filter Setting */
- return s->tv_filter_config;
- case 0x58: /* TV Filter Coefficient Index */
- return s->tv_filter_idx;
- case 0x5a: /* TV Filter Coefficient Data */
- if (s->tv_filter_idx < 0x20)
- return s->tv_filter_coeff[s->tv_filter_idx ++];
- return 0;
-
- case 0x60: /* Input YUV/RGB Translate Mode 0 */
- return s->yrc[0];
- case 0x62: /* Input YUV/RGB Translate Mode 1 */
- return s->yrc[1];
- case 0x64: /* U Data Fix */
- return s->u;
- case 0x66: /* V Data Fix */
- return s->v;
-
- case 0x68: /* Display Mode */
- return s->mode;
-
- case 0x6a: /* Special Effects */
- return s->effect;
-
- case 0x6c: /* Input Window X Start Position 0 */
- return s->ix[0] & 0xff;
- case 0x6e: /* Input Window X Start Position 1 */
- return s->ix[0] >> 3;
- case 0x70: /* Input Window Y Start Position 0 */
- return s->ix[0] & 0xff;
- case 0x72: /* Input Window Y Start Position 1 */
- return s->ix[0] >> 3;
- case 0x74: /* Input Window X End Position 0 */
- return s->ix[1] & 0xff;
- case 0x76: /* Input Window X End Position 1 */
- return s->ix[1] >> 3;
- case 0x78: /* Input Window Y End Position 0 */
- return s->ix[1] & 0xff;
- case 0x7a: /* Input Window Y End Position 1 */
- return s->ix[1] >> 3;
- case 0x7c: /* Output Window X Start Position 0 */
- return s->ox[0] & 0xff;
- case 0x7e: /* Output Window X Start Position 1 */
- return s->ox[0] >> 3;
- case 0x80: /* Output Window Y Start Position 0 */
- return s->oy[0] & 0xff;
- case 0x82: /* Output Window Y Start Position 1 */
- return s->oy[0] >> 3;
- case 0x84: /* Output Window X End Position 0 */
- return s->ox[1] & 0xff;
- case 0x86: /* Output Window X End Position 1 */
- return s->ox[1] >> 3;
- case 0x88: /* Output Window Y End Position 0 */
- return s->oy[1] & 0xff;
- case 0x8a: /* Output Window Y End Position 1 */
- return s->oy[1] >> 3;
-
- case 0x8c: /* Input Data Format */
- return s->iformat;
- case 0x8e: /* Data Source Select */
- return s->source;
- case 0x90: /* Display Memory Data Port */
- return 0;
-
- case 0xa8: /* Border Color 0 */
- return s->border_r;
- case 0xaa: /* Border Color 1 */
- return s->border_g;
- case 0xac: /* Border Color 2 */
- return s->border_b;
-
- case 0xb4: /* Gamma Correction Enable */
- return s->gamma_config;
- case 0xb6: /* Gamma Correction Table Index */
- return s->gamma_idx;
- case 0xb8: /* Gamma Correction Table Data */
- return s->gamma_lut[s->gamma_idx ++];
-
- case 0xba: /* 3x3 Matrix Enable */
- return s->matrix_ena;
- case 0xbc ... 0xde: /* Coefficient Registers */
- return s->matrix_coeff[(reg - 0xbc) >> 1];
- case 0xe0: /* 3x3 Matrix Red Offset */
- return s->matrix_r;
- case 0xe2: /* 3x3 Matrix Green Offset */
- return s->matrix_g;
- case 0xe4: /* 3x3 Matrix Blue Offset */
- return s->matrix_b;
-
- case 0xe6: /* Power-save */
- return s->pm;
- case 0xe8: /* Non-display Period Control / Status */
- return s->status | (1 << 5);
- case 0xea: /* RGB Interface Control */
- return s->rgbgpio_dir;
- case 0xec: /* RGB Interface Status */
- return s->rgbgpio;
- case 0xee: /* General-purpose IO Pins Configuration */
- return s->gpio_dir;
- case 0xf0: /* General-purpose IO Pins Status / Control */
- return s->gpio;
- case 0xf2: /* GPIO Positive Edge Interrupt Trigger */
- return s->gpio_edge[0];
- case 0xf4: /* GPIO Negative Edge Interrupt Trigger */
- return s->gpio_edge[1];
- case 0xf6: /* GPIO Interrupt Status */
- return s->gpio_irq;
- case 0xf8: /* GPIO Pull-down Control */
- return s->gpio_pdown;
-
- default:
- fprintf(stderr, "%s: unknown register %02x\n", __FUNCTION__, reg);
- return 0;
- }
-}
-
-static void blizzard_reg_write(void *opaque, uint8_t reg, uint16_t value)
-{
- BlizzardState *s = (BlizzardState *) opaque;
-
- switch (reg) {
- case 0x04: /* PLL M-Divider */
- s->pll = (value & 0x3f) + 1;
- break;
- case 0x06: /* PLL Lock Range Control */
- s->pll_range = value & 3;
- break;
- case 0x08: /* PLL Lock Synthesis Control 0 */
- s->pll_ctrl &= 0xf00;
- s->pll_ctrl |= (value << 0) & 0x0ff;
- break;
- case 0x0a: /* PLL Lock Synthesis Control 1 */
- s->pll_ctrl &= 0x0ff;
- s->pll_ctrl |= (value << 8) & 0xf00;
- break;
- case 0x0c: /* PLL Mode Control 0 */
- s->pll_mode = value & 0x77;
- if ((value & 3) == 0 || (value & 3) == 3)
- fprintf(stderr, "%s: wrong PLL Control bits (%i)\n",
- __FUNCTION__, value & 3);
- break;
-
- case 0x0e: /* Clock-Source Select */
- s->clksel = value & 0xff;
- break;
-
- case 0x10: /* Memory Controller Activate */
- s->memenable = value & 1;
- break;
- case 0x14: /* Memory Controller Bank 0 Status Flag */
- break;
-
- case 0x18: /* Auto-Refresh Interval Setting 0 */
- s->memrefresh &= 0xf00;
- s->memrefresh |= (value << 0) & 0x0ff;
- break;
- case 0x1a: /* Auto-Refresh Interval Setting 1 */
- s->memrefresh &= 0x0ff;
- s->memrefresh |= (value << 8) & 0xf00;
- break;
-
- case 0x1c: /* Power-On Sequence Timing Control */
- s->timing[0] = value & 0x7f;
- break;
- case 0x1e: /* Timing Control 0 */
- s->timing[1] = value & 0x17;
- break;
- case 0x20: /* Timing Control 1 */
- s->timing[2] = value & 0x35;
- break;
-
- case 0x24: /* Arbitration Priority Control */
- s->priority = value & 1;
- break;
-
- case 0x28: /* LCD Panel Configuration */
- s->lcd_config = value & 0xff;
- if (value & (1 << 7))
- fprintf(stderr, "%s: data swap not supported!\n", __FUNCTION__);
- break;
-
- case 0x2a: /* LCD Horizontal Display Width */
- s->x = value << 3;
- break;
- case 0x2c: /* LCD Horizontal Non-display Period */
- s->hndp = value & 0xff;
- break;
- case 0x2e: /* LCD Vertical Display Height 0 */
- s->y &= 0x300;
- s->y |= (value << 0) & 0x0ff;
- break;
- case 0x30: /* LCD Vertical Display Height 1 */
- s->y &= 0x0ff;
- s->y |= (value << 8) & 0x300;
- break;
- case 0x32: /* LCD Vertical Non-display Period */
- s->vndp = value & 0xff;
- break;
- case 0x34: /* LCD HS Pulse-width */
- s->hsync = value & 0xff;
- break;
- case 0x36: /* LCD HS Pulse Start Position */
- s->skipx = value & 0xff;
- break;
- case 0x38: /* LCD VS Pulse-width */
- s->vsync = value & 0xbf;
- break;
- case 0x3a: /* LCD VS Pulse Start Position */
- s->skipy = value & 0xff;
- break;
-
- case 0x3c: /* PCLK Polarity */
- s->pclk = value & 0x82;
- /* Affects calculation of s->hndp, s->hsync and s->skipx. */
- break;
-
- case 0x3e: /* High-speed Serial Interface Tx Configuration Port 0 */
- s->hssi_config[0] = value;
- break;
- case 0x40: /* High-speed Serial Interface Tx Configuration Port 1 */
- s->hssi_config[1] = value;
- if (((value >> 4) & 3) == 3)
- fprintf(stderr, "%s: Illegal active-data-links value\n",
- __FUNCTION__);
- break;
- case 0x42: /* High-speed Serial Interface Tx Mode */
- s->hssi_config[2] = value & 0xbd;
- break;
-
- case 0x44: /* TV Display Configuration */
- s->tv_config = value & 0xfe;
- break;
- case 0x46 ... 0x4c: /* TV Vertical Blanking Interval Data bits 0 */
- s->tv_timing[(reg - 0x46) >> 1] = value;
- break;
- case 0x4e: /* VBI: Closed Caption / XDS Control / Status */
- s->vbi = value;
- break;
- case 0x50: /* TV Horizontal Start Position */
- s->tv_x = value;
- break;
- case 0x52: /* TV Vertical Start Position */
- s->tv_y = value & 0x7f;
- break;
- case 0x54: /* TV Test Pattern Setting */
- s->tv_test = value;
- break;
- case 0x56: /* TV Filter Setting */
- s->tv_filter_config = value & 0xbf;
- break;
- case 0x58: /* TV Filter Coefficient Index */
- s->tv_filter_idx = value & 0x1f;
- break;
- case 0x5a: /* TV Filter Coefficient Data */
- if (s->tv_filter_idx < 0x20)
- s->tv_filter_coeff[s->tv_filter_idx ++] = value;
- break;
-
- case 0x60: /* Input YUV/RGB Translate Mode 0 */
- s->yrc[0] = value & 0xb0;
- break;
- case 0x62: /* Input YUV/RGB Translate Mode 1 */
- s->yrc[1] = value & 0x30;
- break;
- case 0x64: /* U Data Fix */
- s->u = value & 0xff;
- break;
- case 0x66: /* V Data Fix */
- s->v = value & 0xff;
- break;
-
- case 0x68: /* Display Mode */
- if ((s->mode ^ value) & 3)
- s->invalidate = 1;
- s->mode = value & 0xb7;
- s->enable = value & 1;
- s->blank = (value >> 1) & 1;
- if (value & (1 << 4))
- fprintf(stderr, "%s: Macrovision enable attempt!\n", __FUNCTION__);
- break;
-
- case 0x6a: /* Special Effects */
- s->effect = value & 0xfb;
- break;
-
- case 0x6c: /* Input Window X Start Position 0 */
- s->ix[0] &= 0x300;
- s->ix[0] |= (value << 0) & 0x0ff;
- break;
- case 0x6e: /* Input Window X Start Position 1 */
- s->ix[0] &= 0x0ff;
- s->ix[0] |= (value << 8) & 0x300;
- break;
- case 0x70: /* Input Window Y Start Position 0 */
- s->iy[0] &= 0x300;
- s->iy[0] |= (value << 0) & 0x0ff;
- break;
- case 0x72: /* Input Window Y Start Position 1 */
- s->iy[0] &= 0x0ff;
- s->iy[0] |= (value << 8) & 0x300;
- break;
- case 0x74: /* Input Window X End Position 0 */
- s->ix[1] &= 0x300;
- s->ix[1] |= (value << 0) & 0x0ff;
- break;
- case 0x76: /* Input Window X End Position 1 */
- s->ix[1] &= 0x0ff;
- s->ix[1] |= (value << 8) & 0x300;
- break;
- case 0x78: /* Input Window Y End Position 0 */
- s->iy[1] &= 0x300;
- s->iy[1] |= (value << 0) & 0x0ff;
- break;
- case 0x7a: /* Input Window Y End Position 1 */
- s->iy[1] &= 0x0ff;
- s->iy[1] |= (value << 8) & 0x300;
- break;
- case 0x7c: /* Output Window X Start Position 0 */
- s->ox[0] &= 0x300;
- s->ox[0] |= (value << 0) & 0x0ff;
- break;
- case 0x7e: /* Output Window X Start Position 1 */
- s->ox[0] &= 0x0ff;
- s->ox[0] |= (value << 8) & 0x300;
- break;
- case 0x80: /* Output Window Y Start Position 0 */
- s->oy[0] &= 0x300;
- s->oy[0] |= (value << 0) & 0x0ff;
- break;
- case 0x82: /* Output Window Y Start Position 1 */
- s->oy[0] &= 0x0ff;
- s->oy[0] |= (value << 8) & 0x300;
- break;
- case 0x84: /* Output Window X End Position 0 */
- s->ox[1] &= 0x300;
- s->ox[1] |= (value << 0) & 0x0ff;
- break;
- case 0x86: /* Output Window X End Position 1 */
- s->ox[1] &= 0x0ff;
- s->ox[1] |= (value << 8) & 0x300;
- break;
- case 0x88: /* Output Window Y End Position 0 */
- s->oy[1] &= 0x300;
- s->oy[1] |= (value << 0) & 0x0ff;
- break;
- case 0x8a: /* Output Window Y End Position 1 */
- s->oy[1] &= 0x0ff;
- s->oy[1] |= (value << 8) & 0x300;
- break;
-
- case 0x8c: /* Input Data Format */
- s->iformat = value & 0xf;
- s->bpp = blizzard_iformat_bpp[s->iformat];
- if (!s->bpp)
- fprintf(stderr, "%s: Illegal or unsupported input format %x\n",
- __FUNCTION__, s->iformat);
- break;
- case 0x8e: /* Data Source Select */
- s->source = value & 7;
- /* Currently all windows will be "destructive overlays". */
- if ((!(s->effect & (1 << 3)) && (s->ix[0] != s->ox[0] ||
- s->iy[0] != s->oy[0] ||
- s->ix[1] != s->ox[1] ||
- s->iy[1] != s->oy[1])) ||
- !((s->ix[1] - s->ix[0]) & (s->iy[1] - s->iy[0]) &
- (s->ox[1] - s->ox[0]) & (s->oy[1] - s->oy[0]) & 1))
- fprintf(stderr, "%s: Illegal input/output window positions\n",
- __FUNCTION__);
-
- blizzard_transfer_setup(s);
- break;
-
- case 0x90: /* Display Memory Data Port */
- if (!s->data.len && !blizzard_transfer_setup(s))
- break;
-
- *s->data.ptr ++ = value;
- if (-- s->data.len == 0)
- blizzard_window(s);
- break;
-
- case 0xa8: /* Border Color 0 */
- s->border_r = value;
- break;
- case 0xaa: /* Border Color 1 */
- s->border_g = value;
- break;
- case 0xac: /* Border Color 2 */
- s->border_b = value;
- break;
-
- case 0xb4: /* Gamma Correction Enable */
- s->gamma_config = value & 0x87;
- break;
- case 0xb6: /* Gamma Correction Table Index */
- s->gamma_idx = value;
- break;
- case 0xb8: /* Gamma Correction Table Data */
- s->gamma_lut[s->gamma_idx ++] = value;
- break;
-
- case 0xba: /* 3x3 Matrix Enable */
- s->matrix_ena = value & 1;
- break;
- case 0xbc ... 0xde: /* Coefficient Registers */
- s->matrix_coeff[(reg - 0xbc) >> 1] = value & ((reg & 2) ? 0x80 : 0xff);
- break;
- case 0xe0: /* 3x3 Matrix Red Offset */
- s->matrix_r = value;
- break;
- case 0xe2: /* 3x3 Matrix Green Offset */
- s->matrix_g = value;
- break;
- case 0xe4: /* 3x3 Matrix Blue Offset */
- s->matrix_b = value;
- break;
-
- case 0xe6: /* Power-save */
- s->pm = value & 0x83;
- if (value & s->mode & 1)
- fprintf(stderr, "%s: The display must be disabled before entering "
- "Standby Mode\n", __FUNCTION__);
- break;
- case 0xe8: /* Non-display Period Control / Status */
- s->status = value & 0x1b;
- break;
- case 0xea: /* RGB Interface Control */
- s->rgbgpio_dir = value & 0x8f;
- break;
- case 0xec: /* RGB Interface Status */
- s->rgbgpio = value & 0xcf;
- break;
- case 0xee: /* General-purpose IO Pins Configuration */
- s->gpio_dir = value;
- break;
- case 0xf0: /* General-purpose IO Pins Status / Control */
- s->gpio = value;
- break;
- case 0xf2: /* GPIO Positive Edge Interrupt Trigger */
- s->gpio_edge[0] = value;
- break;
- case 0xf4: /* GPIO Negative Edge Interrupt Trigger */
- s->gpio_edge[1] = value;
- break;
- case 0xf6: /* GPIO Interrupt Status */
- s->gpio_irq &= value;
- break;
- case 0xf8: /* GPIO Pull-down Control */
- s->gpio_pdown = value;
- break;
-
- default:
- fprintf(stderr, "%s: unknown register %02x\n", __FUNCTION__, reg);
- break;
- }
-}
-
-uint16_t s1d13745_read(void *opaque, int dc)
-{
- BlizzardState *s = (BlizzardState *) opaque;
- uint16_t value = blizzard_reg_read(s, s->reg);
-
- if (s->swallow -- > 0)
- return 0;
- if (dc)
- s->reg ++;
-
- return value;
-}
-
-void s1d13745_write(void *opaque, int dc, uint16_t value)
-{
- BlizzardState *s = (BlizzardState *) opaque;
-
- if (s->swallow -- > 0)
- return;
- if (dc) {
- blizzard_reg_write(s, s->reg, value);
-
- if (s->reg != 0x90 && s->reg != 0x5a && s->reg != 0xb8)
- s->reg += 2;
- } else
- s->reg = value & 0xff;
-}
-
-void s1d13745_write_block(void *opaque, int dc,
- void *buf, size_t len, int pitch)
-{
- BlizzardState *s = (BlizzardState *) opaque;
-
- while (len > 0) {
- if (s->reg == 0x90 && dc &&
- (s->data.len || blizzard_transfer_setup(s)) &&
- len >= (s->data.len << 1)) {
- len -= s->data.len << 1;
- s->data.len = 0;
- s->data.data = buf;
- if (pitch)
- s->data.pitch = pitch;
- blizzard_window(s);
- s->data.data = s->data.buf;
- continue;
- }
-
- s1d13745_write(opaque, dc, *(uint16_t *) buf);
- len -= 2;
- buf += 2;
- }
-}
-
-static void blizzard_update_display(void *opaque)
-{
- BlizzardState *s = (BlizzardState *) opaque;
- DisplaySurface *surface = qemu_console_surface(s->con);
- int y, bypp, bypl, bwidth;
- uint8_t *src, *dst;
-
- if (!s->enable)
- return;
-
- if (s->x != surface_width(surface) || s->y != surface_height(surface)) {
- s->invalidate = 1;
- qemu_console_resize(s->con, s->x, s->y);
- surface = qemu_console_surface(s->con);
- }
-
- if (s->invalidate) {
- s->invalidate = 0;
-
- if (s->blank) {
- bypp = surface_bytes_per_pixel(surface);
- memset(surface_data(surface), 0, bypp * s->x * s->y);
- return;
- }
-
- s->mx[0] = 0;
- s->mx[1] = s->x;
- s->my[0] = 0;
- s->my[1] = s->y;
- }
-
- if (s->mx[1] <= s->mx[0])
- return;
-
- bypp = surface_bytes_per_pixel(surface);
- bypl = bypp * s->x;
- bwidth = bypp * (s->mx[1] - s->mx[0]);
- y = s->my[0];
- src = s->fb + bypl * y + bypp * s->mx[0];
- dst = surface_data(surface) + bypl * y + bypp * s->mx[0];
- for (; y < s->my[1]; y ++, src += bypl, dst += bypl)
- memcpy(dst, src, bwidth);
-
- dpy_gfx_update(s->con, s->mx[0], s->my[0],
- s->mx[1] - s->mx[0], y - s->my[0]);
-
- s->mx[0] = s->x;
- s->mx[1] = 0;
- s->my[0] = s->y;
- s->my[1] = 0;
-}
-
-#define DEPTH 8
-#include "blizzard_template.h"
-#define DEPTH 15
-#include "blizzard_template.h"
-#define DEPTH 16
-#include "blizzard_template.h"
-#define DEPTH 24
-#include "blizzard_template.h"
-#define DEPTH 32
-#include "blizzard_template.h"
-
-static const GraphicHwOps blizzard_ops = {
- .invalidate = blizzard_invalidate_display,
- .gfx_update = blizzard_update_display,
-};
-
-void *s1d13745_init(qemu_irq gpio_int)
-{
- BlizzardState *s = (BlizzardState *) g_malloc0(sizeof(*s));
- DisplaySurface *surface;
-
- s->fb = g_malloc(0x180000);
-
- s->con = graphic_console_init(NULL, 0, &blizzard_ops, s);
- surface = qemu_console_surface(s->con);
-
- switch (surface_bits_per_pixel(surface)) {
- case 0:
- s->line_fn_tab[0] = s->line_fn_tab[1] =
- g_malloc0(sizeof(blizzard_fn_t) * 0x10);
- break;
- case 8:
- s->line_fn_tab[0] = blizzard_draw_fn_8;
- s->line_fn_tab[1] = blizzard_draw_fn_r_8;
- break;
- case 15:
- s->line_fn_tab[0] = blizzard_draw_fn_15;
- s->line_fn_tab[1] = blizzard_draw_fn_r_15;
- break;
- case 16:
- s->line_fn_tab[0] = blizzard_draw_fn_16;
- s->line_fn_tab[1] = blizzard_draw_fn_r_16;
- break;
- case 24:
- s->line_fn_tab[0] = blizzard_draw_fn_24;
- s->line_fn_tab[1] = blizzard_draw_fn_r_24;
- break;
- case 32:
- s->line_fn_tab[0] = blizzard_draw_fn_32;
- s->line_fn_tab[1] = blizzard_draw_fn_r_32;
- break;
- default:
- fprintf(stderr, "%s: Bad color depth\n", __FUNCTION__);
- exit(1);
- }
-
- blizzard_reset(s);
-
- return s;
-}
diff --git a/qemu/hw/display/blizzard_template.h b/qemu/hw/display/blizzard_template.h
deleted file mode 100644
index b7ef27c80..000000000
--- a/qemu/hw/display/blizzard_template.h
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * QEMU Epson S1D13744/S1D13745 templates
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#define SKIP_PIXEL(to) (to += deststep)
-#if DEPTH == 8
-# define PIXEL_TYPE uint8_t
-# define COPY_PIXEL(to, from) do { *to = from; SKIP_PIXEL(to); } while (0)
-# define COPY_PIXEL1(to, from) (*to++ = from)
-#elif DEPTH == 15 || DEPTH == 16
-# define PIXEL_TYPE uint16_t
-# define COPY_PIXEL(to, from) do { *to = from; SKIP_PIXEL(to); } while (0)
-# define COPY_PIXEL1(to, from) (*to++ = from)
-#elif DEPTH == 24
-# define PIXEL_TYPE uint8_t
-# define COPY_PIXEL(to, from) \
- do { \
- to[0] = from; \
- to[1] = (from) >> 8; \
- to[2] = (from) >> 16; \
- SKIP_PIXEL(to); \
- } while (0)
-
-# define COPY_PIXEL1(to, from) \
- do { \
- *to++ = from; \
- *to++ = (from) >> 8; \
- *to++ = (from) >> 16; \
- } while (0)
-#elif DEPTH == 32
-# define PIXEL_TYPE uint32_t
-# define COPY_PIXEL(to, from) do { *to = from; SKIP_PIXEL(to); } while (0)
-# define COPY_PIXEL1(to, from) (*to++ = from)
-#else
-# error unknown bit depth
-#endif
-
-#ifdef HOST_WORDS_BIGENDIAN
-# define SWAP_WORDS 1
-#endif
-
-static void glue(blizzard_draw_line16_, DEPTH)(PIXEL_TYPE *dest,
- const uint16_t *src, unsigned int width)
-{
-#if !defined(SWAP_WORDS) && DEPTH == 16
- memcpy(dest, src, width);
-#else
- uint16_t data;
- unsigned int r, g, b;
- const uint16_t *end = (const void *) src + width;
- while (src < end) {
- data = *src ++;
- b = (data & 0x1f) << 3;
- data >>= 5;
- g = (data & 0x3f) << 2;
- data >>= 6;
- r = (data & 0x1f) << 3;
- data >>= 5;
- COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r, g, b));
- }
-#endif
-}
-
-static void glue(blizzard_draw_line24mode1_, DEPTH)(PIXEL_TYPE *dest,
- const uint8_t *src, unsigned int width)
-{
- /* TODO: check if SDL 24-bit planes are not in the same format and
- * if so, use memcpy */
- unsigned int r[2], g[2], b[2];
- const uint8_t *end = src + width;
- while (src < end) {
- g[0] = *src ++;
- r[0] = *src ++;
- r[1] = *src ++;
- b[0] = *src ++;
- COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r[0], g[0], b[0]));
- b[1] = *src ++;
- g[1] = *src ++;
- COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r[1], g[1], b[1]));
- }
-}
-
-static void glue(blizzard_draw_line24mode2_, DEPTH)(PIXEL_TYPE *dest,
- const uint8_t *src, unsigned int width)
-{
- unsigned int r, g, b;
- const uint8_t *end = src + width;
- while (src < end) {
- r = *src ++;
- src ++;
- b = *src ++;
- g = *src ++;
- COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r, g, b));
- }
-}
-
-/* No rotation */
-static blizzard_fn_t glue(blizzard_draw_fn_, DEPTH)[0x10] = {
- NULL,
- /* RGB 5:6:5*/
- (blizzard_fn_t) glue(blizzard_draw_line16_, DEPTH),
- /* RGB 6:6:6 mode 1 */
- (blizzard_fn_t) glue(blizzard_draw_line24mode1_, DEPTH),
- /* RGB 8:8:8 mode 1 */
- (blizzard_fn_t) glue(blizzard_draw_line24mode1_, DEPTH),
- NULL, NULL,
- /* RGB 6:6:6 mode 2 */
- (blizzard_fn_t) glue(blizzard_draw_line24mode2_, DEPTH),
- /* RGB 8:8:8 mode 2 */
- (blizzard_fn_t) glue(blizzard_draw_line24mode2_, DEPTH),
- /* YUV 4:2:2 */
- NULL,
- /* YUV 4:2:0 */
- NULL,
- NULL, NULL, NULL, NULL, NULL, NULL,
-};
-
-/* 90deg, 180deg and 270deg rotation */
-static blizzard_fn_t glue(blizzard_draw_fn_r_, DEPTH)[0x10] = {
- /* TODO */
- [0 ... 0xf] = NULL,
-};
-
-#undef DEPTH
-#undef SKIP_PIXEL
-#undef COPY_PIXEL
-#undef COPY_PIXEL1
-#undef PIXEL_TYPE
-
-#undef SWAP_WORDS
diff --git a/qemu/hw/display/cg3.c b/qemu/hw/display/cg3.c
deleted file mode 100644
index fc0d97fa4..000000000
--- a/qemu/hw/display/cg3.c
+++ /dev/null
@@ -1,399 +0,0 @@
-/*
- * QEMU CG3 Frame buffer
- *
- * Copyright (c) 2012 Bob Breuer
- * Copyright (c) 2013 Mark Cave-Ayland
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "qemu/error-report.h"
-#include "ui/console.h"
-#include "hw/sysbus.h"
-#include "hw/loader.h"
-
-/* Change to 1 to enable debugging */
-#define DEBUG_CG3 0
-
-#define CG3_ROM_FILE "QEMU,cgthree.bin"
-#define FCODE_MAX_ROM_SIZE 0x10000
-
-#define CG3_REG_SIZE 0x20
-
-#define CG3_REG_BT458_ADDR 0x0
-#define CG3_REG_BT458_COLMAP 0x4
-#define CG3_REG_FBC_CTRL 0x10
-#define CG3_REG_FBC_STATUS 0x11
-#define CG3_REG_FBC_CURSTART 0x12
-#define CG3_REG_FBC_CUREND 0x13
-#define CG3_REG_FBC_VCTRL 0x14
-
-/* Control register flags */
-#define CG3_CR_ENABLE_INTS 0x80
-
-/* Status register flags */
-#define CG3_SR_PENDING_INT 0x80
-#define CG3_SR_1152_900_76_B 0x60
-#define CG3_SR_ID_COLOR 0x01
-
-#define CG3_VRAM_SIZE 0x100000
-#define CG3_VRAM_OFFSET 0x800000
-
-#define DPRINTF(fmt, ...) do { \
- if (DEBUG_CG3) { \
- printf("CG3: " fmt , ## __VA_ARGS__); \
- } \
-} while (0);
-
-#define TYPE_CG3 "cgthree"
-#define CG3(obj) OBJECT_CHECK(CG3State, (obj), TYPE_CG3)
-
-typedef struct CG3State {
- SysBusDevice parent_obj;
-
- QemuConsole *con;
- qemu_irq irq;
- hwaddr prom_addr;
- MemoryRegion vram_mem;
- MemoryRegion rom;
- MemoryRegion reg;
- uint32_t vram_size;
- int full_update;
- uint8_t regs[16];
- uint8_t r[256], g[256], b[256];
- uint16_t width, height, depth;
- uint8_t dac_index, dac_state;
-} CG3State;
-
-static void cg3_update_display(void *opaque)
-{
- CG3State *s = opaque;
- DisplaySurface *surface = qemu_console_surface(s->con);
- const uint8_t *pix;
- uint32_t *data;
- uint32_t dval;
- int x, y, y_start;
- unsigned int width, height;
- ram_addr_t page, page_min, page_max;
-
- if (surface_bits_per_pixel(surface) != 32) {
- return;
- }
- width = s->width;
- height = s->height;
-
- y_start = -1;
- page_min = -1;
- page_max = 0;
- page = 0;
- pix = memory_region_get_ram_ptr(&s->vram_mem);
- data = (uint32_t *)surface_data(surface);
-
- memory_region_sync_dirty_bitmap(&s->vram_mem);
- for (y = 0; y < height; y++) {
- int update = s->full_update;
-
- page = (y * width) & TARGET_PAGE_MASK;
- update |= memory_region_get_dirty(&s->vram_mem, page, page + width,
- DIRTY_MEMORY_VGA);
- if (update) {
- if (y_start < 0) {
- y_start = y;
- }
- if (page < page_min) {
- page_min = page;
- }
- if (page > page_max) {
- page_max = page;
- }
-
- for (x = 0; x < width; x++) {
- dval = *pix++;
- dval = (s->r[dval] << 16) | (s->g[dval] << 8) | s->b[dval];
- *data++ = dval;
- }
- } else {
- if (y_start >= 0) {
- dpy_gfx_update(s->con, 0, y_start, s->width, y - y_start);
- y_start = -1;
- }
- pix += width;
- data += width;
- }
- }
- s->full_update = 0;
- if (y_start >= 0) {
- dpy_gfx_update(s->con, 0, y_start, s->width, y - y_start);
- }
- if (page_max >= page_min) {
- memory_region_reset_dirty(&s->vram_mem,
- page_min, page_max - page_min + TARGET_PAGE_SIZE,
- DIRTY_MEMORY_VGA);
- }
- /* vsync interrupt? */
- if (s->regs[0] & CG3_CR_ENABLE_INTS) {
- s->regs[1] |= CG3_SR_PENDING_INT;
- qemu_irq_raise(s->irq);
- }
-}
-
-static void cg3_invalidate_display(void *opaque)
-{
- CG3State *s = opaque;
-
- memory_region_set_dirty(&s->vram_mem, 0, CG3_VRAM_SIZE);
-}
-
-static uint64_t cg3_reg_read(void *opaque, hwaddr addr, unsigned size)
-{
- CG3State *s = opaque;
- int val;
-
- switch (addr) {
- case CG3_REG_BT458_ADDR:
- case CG3_REG_BT458_COLMAP:
- val = 0;
- break;
- case CG3_REG_FBC_CTRL:
- val = s->regs[0];
- break;
- case CG3_REG_FBC_STATUS:
- /* monitor ID 6, board type = 1 (color) */
- val = s->regs[1] | CG3_SR_1152_900_76_B | CG3_SR_ID_COLOR;
- break;
- case CG3_REG_FBC_CURSTART ... CG3_REG_SIZE - 1:
- val = s->regs[addr - 0x10];
- break;
- default:
- qemu_log_mask(LOG_UNIMP,
- "cg3: Unimplemented register read "
- "reg 0x%" HWADDR_PRIx " size 0x%x\n",
- addr, size);
- val = 0;
- break;
- }
- DPRINTF("read %02x from reg %" HWADDR_PRIx "\n", val, addr);
- return val;
-}
-
-static void cg3_reg_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned size)
-{
- CG3State *s = opaque;
- uint8_t regval;
- int i;
-
- DPRINTF("write %" PRIx64 " to reg %" HWADDR_PRIx " size %d\n",
- val, addr, size);
-
- switch (addr) {
- case CG3_REG_BT458_ADDR:
- s->dac_index = val;
- s->dac_state = 0;
- break;
- case CG3_REG_BT458_COLMAP:
- /* This register can be written to as either a long word or a byte */
- if (size == 1) {
- val <<= 24;
- }
-
- for (i = 0; i < size; i++) {
- regval = val >> 24;
-
- switch (s->dac_state) {
- case 0:
- s->r[s->dac_index] = regval;
- s->dac_state++;
- break;
- case 1:
- s->g[s->dac_index] = regval;
- s->dac_state++;
- break;
- case 2:
- s->b[s->dac_index] = regval;
- /* Index autoincrement */
- s->dac_index = (s->dac_index + 1) & 0xff;
- default:
- s->dac_state = 0;
- break;
- }
- val <<= 8;
- }
- s->full_update = 1;
- break;
- case CG3_REG_FBC_CTRL:
- s->regs[0] = val;
- break;
- case CG3_REG_FBC_STATUS:
- if (s->regs[1] & CG3_SR_PENDING_INT) {
- /* clear interrupt */
- s->regs[1] &= ~CG3_SR_PENDING_INT;
- qemu_irq_lower(s->irq);
- }
- break;
- case CG3_REG_FBC_CURSTART ... CG3_REG_SIZE - 1:
- s->regs[addr - 0x10] = val;
- break;
- default:
- qemu_log_mask(LOG_UNIMP,
- "cg3: Unimplemented register write "
- "reg 0x%" HWADDR_PRIx " size 0x%x value 0x%" PRIx64 "\n",
- addr, size, val);
- break;
- }
-}
-
-static const MemoryRegionOps cg3_reg_ops = {
- .read = cg3_reg_read,
- .write = cg3_reg_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 1,
- .max_access_size = 4,
- },
-};
-
-static const GraphicHwOps cg3_ops = {
- .invalidate = cg3_invalidate_display,
- .gfx_update = cg3_update_display,
-};
-
-static void cg3_initfn(Object *obj)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- CG3State *s = CG3(obj);
-
- memory_region_init_ram(&s->rom, obj, "cg3.prom", FCODE_MAX_ROM_SIZE,
- &error_fatal);
- memory_region_set_readonly(&s->rom, true);
- sysbus_init_mmio(sbd, &s->rom);
-
- memory_region_init_io(&s->reg, obj, &cg3_reg_ops, s, "cg3.reg",
- CG3_REG_SIZE);
- sysbus_init_mmio(sbd, &s->reg);
-}
-
-static void cg3_realizefn(DeviceState *dev, Error **errp)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- CG3State *s = CG3(dev);
- int ret;
- char *fcode_filename;
-
- /* FCode ROM */
- vmstate_register_ram_global(&s->rom);
- fcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, CG3_ROM_FILE);
- if (fcode_filename) {
- ret = load_image_targphys(fcode_filename, s->prom_addr,
- FCODE_MAX_ROM_SIZE);
- g_free(fcode_filename);
- if (ret < 0 || ret > FCODE_MAX_ROM_SIZE) {
- error_report("cg3: could not load prom '%s'", CG3_ROM_FILE);
- }
- }
-
- memory_region_init_ram(&s->vram_mem, NULL, "cg3.vram", s->vram_size,
- &error_fatal);
- memory_region_set_log(&s->vram_mem, true, DIRTY_MEMORY_VGA);
- vmstate_register_ram_global(&s->vram_mem);
- sysbus_init_mmio(sbd, &s->vram_mem);
-
- sysbus_init_irq(sbd, &s->irq);
-
- s->con = graphic_console_init(DEVICE(dev), 0, &cg3_ops, s);
- qemu_console_resize(s->con, s->width, s->height);
-}
-
-static int vmstate_cg3_post_load(void *opaque, int version_id)
-{
- CG3State *s = opaque;
-
- cg3_invalidate_display(s);
-
- return 0;
-}
-
-static const VMStateDescription vmstate_cg3 = {
- .name = "cg3",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = vmstate_cg3_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT16(height, CG3State),
- VMSTATE_UINT16(width, CG3State),
- VMSTATE_UINT16(depth, CG3State),
- VMSTATE_BUFFER(r, CG3State),
- VMSTATE_BUFFER(g, CG3State),
- VMSTATE_BUFFER(b, CG3State),
- VMSTATE_UINT8(dac_index, CG3State),
- VMSTATE_UINT8(dac_state, CG3State),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void cg3_reset(DeviceState *d)
-{
- CG3State *s = CG3(d);
-
- /* Initialize palette */
- memset(s->r, 0, 256);
- memset(s->g, 0, 256);
- memset(s->b, 0, 256);
-
- s->dac_state = 0;
- s->full_update = 1;
- qemu_irq_lower(s->irq);
-}
-
-static Property cg3_properties[] = {
- DEFINE_PROP_UINT32("vram-size", CG3State, vram_size, -1),
- DEFINE_PROP_UINT16("width", CG3State, width, -1),
- DEFINE_PROP_UINT16("height", CG3State, height, -1),
- DEFINE_PROP_UINT16("depth", CG3State, depth, -1),
- DEFINE_PROP_UINT64("prom-addr", CG3State, prom_addr, -1),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void cg3_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = cg3_realizefn;
- dc->reset = cg3_reset;
- dc->vmsd = &vmstate_cg3;
- dc->props = cg3_properties;
-}
-
-static const TypeInfo cg3_info = {
- .name = TYPE_CG3,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(CG3State),
- .instance_init = cg3_initfn,
- .class_init = cg3_class_init,
-};
-
-static void cg3_register_types(void)
-{
- type_register_static(&cg3_info);
-}
-
-type_init(cg3_register_types)
diff --git a/qemu/hw/display/cirrus_vga.c b/qemu/hw/display/cirrus_vga.c
deleted file mode 100644
index 3d712d592..000000000
--- a/qemu/hw/display/cirrus_vga.c
+++ /dev/null
@@ -1,3091 +0,0 @@
-/*
- * QEMU Cirrus CLGD 54xx VGA Emulator.
- *
- * Copyright (c) 2004 Fabrice Bellard
- * Copyright (c) 2004 Makoto Suzuki (suzu)
- *
- * 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.
- */
-/*
- * Reference: Finn Thogersons' VGADOC4b
- * available at http://home.worldonline.dk/~finth/
- */
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/hw.h"
-#include "hw/pci/pci.h"
-#include "ui/console.h"
-#include "ui/pixel_ops.h"
-#include "vga_int.h"
-#include "hw/loader.h"
-
-/*
- * TODO:
- * - destination write mask support not complete (bits 5..7)
- * - optimize linear mappings
- * - optimize bitblt functions
- */
-
-//#define DEBUG_CIRRUS
-//#define DEBUG_BITBLT
-
-/***************************************
- *
- * definitions
- *
- ***************************************/
-
-// ID
-#define CIRRUS_ID_CLGD5422 (0x23<<2)
-#define CIRRUS_ID_CLGD5426 (0x24<<2)
-#define CIRRUS_ID_CLGD5424 (0x25<<2)
-#define CIRRUS_ID_CLGD5428 (0x26<<2)
-#define CIRRUS_ID_CLGD5430 (0x28<<2)
-#define CIRRUS_ID_CLGD5434 (0x2A<<2)
-#define CIRRUS_ID_CLGD5436 (0x2B<<2)
-#define CIRRUS_ID_CLGD5446 (0x2E<<2)
-
-// sequencer 0x07
-#define CIRRUS_SR7_BPP_VGA 0x00
-#define CIRRUS_SR7_BPP_SVGA 0x01
-#define CIRRUS_SR7_BPP_MASK 0x0e
-#define CIRRUS_SR7_BPP_8 0x00
-#define CIRRUS_SR7_BPP_16_DOUBLEVCLK 0x02
-#define CIRRUS_SR7_BPP_24 0x04
-#define CIRRUS_SR7_BPP_16 0x06
-#define CIRRUS_SR7_BPP_32 0x08
-#define CIRRUS_SR7_ISAADDR_MASK 0xe0
-
-// sequencer 0x0f
-#define CIRRUS_MEMSIZE_512k 0x08
-#define CIRRUS_MEMSIZE_1M 0x10
-#define CIRRUS_MEMSIZE_2M 0x18
-#define CIRRUS_MEMFLAGS_BANKSWITCH 0x80 // bank switching is enabled.
-
-// sequencer 0x12
-#define CIRRUS_CURSOR_SHOW 0x01
-#define CIRRUS_CURSOR_HIDDENPEL 0x02
-#define CIRRUS_CURSOR_LARGE 0x04 // 64x64 if set, 32x32 if clear
-
-// sequencer 0x17
-#define CIRRUS_BUSTYPE_VLBFAST 0x10
-#define CIRRUS_BUSTYPE_PCI 0x20
-#define CIRRUS_BUSTYPE_VLBSLOW 0x30
-#define CIRRUS_BUSTYPE_ISA 0x38
-#define CIRRUS_MMIO_ENABLE 0x04
-#define CIRRUS_MMIO_USE_PCIADDR 0x40 // 0xb8000 if cleared.
-#define CIRRUS_MEMSIZEEXT_DOUBLE 0x80
-
-// control 0x0b
-#define CIRRUS_BANKING_DUAL 0x01
-#define CIRRUS_BANKING_GRANULARITY_16K 0x20 // set:16k, clear:4k
-
-// control 0x30
-#define CIRRUS_BLTMODE_BACKWARDS 0x01
-#define CIRRUS_BLTMODE_MEMSYSDEST 0x02
-#define CIRRUS_BLTMODE_MEMSYSSRC 0x04
-#define CIRRUS_BLTMODE_TRANSPARENTCOMP 0x08
-#define CIRRUS_BLTMODE_PATTERNCOPY 0x40
-#define CIRRUS_BLTMODE_COLOREXPAND 0x80
-#define CIRRUS_BLTMODE_PIXELWIDTHMASK 0x30
-#define CIRRUS_BLTMODE_PIXELWIDTH8 0x00
-#define CIRRUS_BLTMODE_PIXELWIDTH16 0x10
-#define CIRRUS_BLTMODE_PIXELWIDTH24 0x20
-#define CIRRUS_BLTMODE_PIXELWIDTH32 0x30
-
-// control 0x31
-#define CIRRUS_BLT_BUSY 0x01
-#define CIRRUS_BLT_START 0x02
-#define CIRRUS_BLT_RESET 0x04
-#define CIRRUS_BLT_FIFOUSED 0x10
-#define CIRRUS_BLT_AUTOSTART 0x80
-
-// control 0x32
-#define CIRRUS_ROP_0 0x00
-#define CIRRUS_ROP_SRC_AND_DST 0x05
-#define CIRRUS_ROP_NOP 0x06
-#define CIRRUS_ROP_SRC_AND_NOTDST 0x09
-#define CIRRUS_ROP_NOTDST 0x0b
-#define CIRRUS_ROP_SRC 0x0d
-#define CIRRUS_ROP_1 0x0e
-#define CIRRUS_ROP_NOTSRC_AND_DST 0x50
-#define CIRRUS_ROP_SRC_XOR_DST 0x59
-#define CIRRUS_ROP_SRC_OR_DST 0x6d
-#define CIRRUS_ROP_NOTSRC_OR_NOTDST 0x90
-#define CIRRUS_ROP_SRC_NOTXOR_DST 0x95
-#define CIRRUS_ROP_SRC_OR_NOTDST 0xad
-#define CIRRUS_ROP_NOTSRC 0xd0
-#define CIRRUS_ROP_NOTSRC_OR_DST 0xd6
-#define CIRRUS_ROP_NOTSRC_AND_NOTDST 0xda
-
-#define CIRRUS_ROP_NOP_INDEX 2
-#define CIRRUS_ROP_SRC_INDEX 5
-
-// control 0x33
-#define CIRRUS_BLTMODEEXT_SOLIDFILL 0x04
-#define CIRRUS_BLTMODEEXT_COLOREXPINV 0x02
-#define CIRRUS_BLTMODEEXT_DWORDGRANULARITY 0x01
-
-// memory-mapped IO
-#define CIRRUS_MMIO_BLTBGCOLOR 0x00 // dword
-#define CIRRUS_MMIO_BLTFGCOLOR 0x04 // dword
-#define CIRRUS_MMIO_BLTWIDTH 0x08 // word
-#define CIRRUS_MMIO_BLTHEIGHT 0x0a // word
-#define CIRRUS_MMIO_BLTDESTPITCH 0x0c // word
-#define CIRRUS_MMIO_BLTSRCPITCH 0x0e // word
-#define CIRRUS_MMIO_BLTDESTADDR 0x10 // dword
-#define CIRRUS_MMIO_BLTSRCADDR 0x14 // dword
-#define CIRRUS_MMIO_BLTWRITEMASK 0x17 // byte
-#define CIRRUS_MMIO_BLTMODE 0x18 // byte
-#define CIRRUS_MMIO_BLTROP 0x1a // byte
-#define CIRRUS_MMIO_BLTMODEEXT 0x1b // byte
-#define CIRRUS_MMIO_BLTTRANSPARENTCOLOR 0x1c // word?
-#define CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK 0x20 // word?
-#define CIRRUS_MMIO_LINEARDRAW_START_X 0x24 // word
-#define CIRRUS_MMIO_LINEARDRAW_START_Y 0x26 // word
-#define CIRRUS_MMIO_LINEARDRAW_END_X 0x28 // word
-#define CIRRUS_MMIO_LINEARDRAW_END_Y 0x2a // word
-#define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_INC 0x2c // byte
-#define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_ROLLOVER 0x2d // byte
-#define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_MASK 0x2e // byte
-#define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_ACCUM 0x2f // byte
-#define CIRRUS_MMIO_BRESENHAM_K1 0x30 // word
-#define CIRRUS_MMIO_BRESENHAM_K3 0x32 // word
-#define CIRRUS_MMIO_BRESENHAM_ERROR 0x34 // word
-#define CIRRUS_MMIO_BRESENHAM_DELTA_MAJOR 0x36 // word
-#define CIRRUS_MMIO_BRESENHAM_DIRECTION 0x38 // byte
-#define CIRRUS_MMIO_LINEDRAW_MODE 0x39 // byte
-#define CIRRUS_MMIO_BLTSTATUS 0x40 // byte
-
-#define CIRRUS_PNPMMIO_SIZE 0x1000
-
-struct CirrusVGAState;
-typedef void (*cirrus_bitblt_rop_t) (struct CirrusVGAState *s,
- uint8_t * dst, const uint8_t * src,
- int dstpitch, int srcpitch,
- int bltwidth, int bltheight);
-typedef void (*cirrus_fill_t)(struct CirrusVGAState *s,
- uint8_t *dst, int dst_pitch, int width, int height);
-
-typedef struct CirrusVGAState {
- VGACommonState vga;
-
- MemoryRegion cirrus_vga_io;
- MemoryRegion cirrus_linear_io;
- MemoryRegion cirrus_linear_bitblt_io;
- MemoryRegion cirrus_mmio_io;
- MemoryRegion pci_bar;
- bool linear_vram; /* vga.vram mapped over cirrus_linear_io */
- MemoryRegion low_mem_container; /* container for 0xa0000-0xc0000 */
- MemoryRegion low_mem; /* always mapped, overridden by: */
- MemoryRegion cirrus_bank[2]; /* aliases at 0xa0000-0xb0000 */
- uint32_t cirrus_addr_mask;
- uint32_t linear_mmio_mask;
- uint8_t cirrus_shadow_gr0;
- uint8_t cirrus_shadow_gr1;
- uint8_t cirrus_hidden_dac_lockindex;
- uint8_t cirrus_hidden_dac_data;
- uint32_t cirrus_bank_base[2];
- uint32_t cirrus_bank_limit[2];
- uint8_t cirrus_hidden_palette[48];
- int cirrus_blt_pixelwidth;
- int cirrus_blt_width;
- int cirrus_blt_height;
- int cirrus_blt_dstpitch;
- int cirrus_blt_srcpitch;
- uint32_t cirrus_blt_fgcol;
- uint32_t cirrus_blt_bgcol;
- uint32_t cirrus_blt_dstaddr;
- uint32_t cirrus_blt_srcaddr;
- uint8_t cirrus_blt_mode;
- uint8_t cirrus_blt_modeext;
- cirrus_bitblt_rop_t cirrus_rop;
-#define CIRRUS_BLTBUFSIZE (2048 * 4) /* one line width */
- uint8_t cirrus_bltbuf[CIRRUS_BLTBUFSIZE];
- uint8_t *cirrus_srcptr;
- uint8_t *cirrus_srcptr_end;
- uint32_t cirrus_srccounter;
- /* hwcursor display state */
- int last_hw_cursor_size;
- int last_hw_cursor_x;
- int last_hw_cursor_y;
- int last_hw_cursor_y_start;
- int last_hw_cursor_y_end;
- int real_vram_size; /* XXX: suppress that */
- int device_id;
- int bustype;
-} CirrusVGAState;
-
-typedef struct PCICirrusVGAState {
- PCIDevice dev;
- CirrusVGAState cirrus_vga;
-} PCICirrusVGAState;
-
-#define TYPE_PCI_CIRRUS_VGA "cirrus-vga"
-#define PCI_CIRRUS_VGA(obj) \
- OBJECT_CHECK(PCICirrusVGAState, (obj), TYPE_PCI_CIRRUS_VGA)
-
-#define TYPE_ISA_CIRRUS_VGA "isa-cirrus-vga"
-#define ISA_CIRRUS_VGA(obj) \
- OBJECT_CHECK(ISACirrusVGAState, (obj), TYPE_ISA_CIRRUS_VGA)
-
-typedef struct ISACirrusVGAState {
- ISADevice parent_obj;
-
- CirrusVGAState cirrus_vga;
-} ISACirrusVGAState;
-
-static uint8_t rop_to_index[256];
-
-/***************************************
- *
- * prototypes.
- *
- ***************************************/
-
-
-static void cirrus_bitblt_reset(CirrusVGAState *s);
-static void cirrus_update_memory_access(CirrusVGAState *s);
-
-/***************************************
- *
- * raster operations
- *
- ***************************************/
-
-static bool blit_region_is_unsafe(struct CirrusVGAState *s,
- int32_t pitch, int32_t addr)
-{
- if (pitch < 0) {
- int64_t min = addr
- + ((int64_t)s->cirrus_blt_height-1) * pitch;
- int32_t max = addr
- + s->cirrus_blt_width;
- if (min < 0 || max > s->vga.vram_size) {
- return true;
- }
- } else {
- int64_t max = addr
- + ((int64_t)s->cirrus_blt_height-1) * pitch
- + s->cirrus_blt_width;
- if (max > s->vga.vram_size) {
- return true;
- }
- }
- return false;
-}
-
-static bool blit_is_unsafe(struct CirrusVGAState *s)
-{
- /* should be the case, see cirrus_bitblt_start */
- assert(s->cirrus_blt_width > 0);
- assert(s->cirrus_blt_height > 0);
-
- if (s->cirrus_blt_width > CIRRUS_BLTBUFSIZE) {
- return true;
- }
-
- if (blit_region_is_unsafe(s, s->cirrus_blt_dstpitch,
- s->cirrus_blt_dstaddr & s->cirrus_addr_mask)) {
- return true;
- }
- if (blit_region_is_unsafe(s, s->cirrus_blt_srcpitch,
- s->cirrus_blt_srcaddr & s->cirrus_addr_mask)) {
- return true;
- }
-
- return false;
-}
-
-static void cirrus_bitblt_rop_nop(CirrusVGAState *s,
- uint8_t *dst,const uint8_t *src,
- int dstpitch,int srcpitch,
- int bltwidth,int bltheight)
-{
-}
-
-static void cirrus_bitblt_fill_nop(CirrusVGAState *s,
- uint8_t *dst,
- int dstpitch, int bltwidth,int bltheight)
-{
-}
-
-#define ROP_NAME 0
-#define ROP_FN(d, s) 0
-#include "cirrus_vga_rop.h"
-
-#define ROP_NAME src_and_dst
-#define ROP_FN(d, s) (s) & (d)
-#include "cirrus_vga_rop.h"
-
-#define ROP_NAME src_and_notdst
-#define ROP_FN(d, s) (s) & (~(d))
-#include "cirrus_vga_rop.h"
-
-#define ROP_NAME notdst
-#define ROP_FN(d, s) ~(d)
-#include "cirrus_vga_rop.h"
-
-#define ROP_NAME src
-#define ROP_FN(d, s) s
-#include "cirrus_vga_rop.h"
-
-#define ROP_NAME 1
-#define ROP_FN(d, s) ~0
-#include "cirrus_vga_rop.h"
-
-#define ROP_NAME notsrc_and_dst
-#define ROP_FN(d, s) (~(s)) & (d)
-#include "cirrus_vga_rop.h"
-
-#define ROP_NAME src_xor_dst
-#define ROP_FN(d, s) (s) ^ (d)
-#include "cirrus_vga_rop.h"
-
-#define ROP_NAME src_or_dst
-#define ROP_FN(d, s) (s) | (d)
-#include "cirrus_vga_rop.h"
-
-#define ROP_NAME notsrc_or_notdst
-#define ROP_FN(d, s) (~(s)) | (~(d))
-#include "cirrus_vga_rop.h"
-
-#define ROP_NAME src_notxor_dst
-#define ROP_FN(d, s) ~((s) ^ (d))
-#include "cirrus_vga_rop.h"
-
-#define ROP_NAME src_or_notdst
-#define ROP_FN(d, s) (s) | (~(d))
-#include "cirrus_vga_rop.h"
-
-#define ROP_NAME notsrc
-#define ROP_FN(d, s) (~(s))
-#include "cirrus_vga_rop.h"
-
-#define ROP_NAME notsrc_or_dst
-#define ROP_FN(d, s) (~(s)) | (d)
-#include "cirrus_vga_rop.h"
-
-#define ROP_NAME notsrc_and_notdst
-#define ROP_FN(d, s) (~(s)) & (~(d))
-#include "cirrus_vga_rop.h"
-
-static const cirrus_bitblt_rop_t cirrus_fwd_rop[16] = {
- cirrus_bitblt_rop_fwd_0,
- cirrus_bitblt_rop_fwd_src_and_dst,
- cirrus_bitblt_rop_nop,
- cirrus_bitblt_rop_fwd_src_and_notdst,
- cirrus_bitblt_rop_fwd_notdst,
- cirrus_bitblt_rop_fwd_src,
- cirrus_bitblt_rop_fwd_1,
- cirrus_bitblt_rop_fwd_notsrc_and_dst,
- cirrus_bitblt_rop_fwd_src_xor_dst,
- cirrus_bitblt_rop_fwd_src_or_dst,
- cirrus_bitblt_rop_fwd_notsrc_or_notdst,
- cirrus_bitblt_rop_fwd_src_notxor_dst,
- cirrus_bitblt_rop_fwd_src_or_notdst,
- cirrus_bitblt_rop_fwd_notsrc,
- cirrus_bitblt_rop_fwd_notsrc_or_dst,
- cirrus_bitblt_rop_fwd_notsrc_and_notdst,
-};
-
-static const cirrus_bitblt_rop_t cirrus_bkwd_rop[16] = {
- cirrus_bitblt_rop_bkwd_0,
- cirrus_bitblt_rop_bkwd_src_and_dst,
- cirrus_bitblt_rop_nop,
- cirrus_bitblt_rop_bkwd_src_and_notdst,
- cirrus_bitblt_rop_bkwd_notdst,
- cirrus_bitblt_rop_bkwd_src,
- cirrus_bitblt_rop_bkwd_1,
- cirrus_bitblt_rop_bkwd_notsrc_and_dst,
- cirrus_bitblt_rop_bkwd_src_xor_dst,
- cirrus_bitblt_rop_bkwd_src_or_dst,
- cirrus_bitblt_rop_bkwd_notsrc_or_notdst,
- cirrus_bitblt_rop_bkwd_src_notxor_dst,
- cirrus_bitblt_rop_bkwd_src_or_notdst,
- cirrus_bitblt_rop_bkwd_notsrc,
- cirrus_bitblt_rop_bkwd_notsrc_or_dst,
- cirrus_bitblt_rop_bkwd_notsrc_and_notdst,
-};
-
-#define TRANSP_ROP(name) {\
- name ## _8,\
- name ## _16,\
- }
-#define TRANSP_NOP(func) {\
- func,\
- func,\
- }
-
-static const cirrus_bitblt_rop_t cirrus_fwd_transp_rop[16][2] = {
- TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_0),
- TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_and_dst),
- TRANSP_NOP(cirrus_bitblt_rop_nop),
- TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_and_notdst),
- TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notdst),
- TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src),
- TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_1),
- TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notsrc_and_dst),
- TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_xor_dst),
- TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_or_dst),
- TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notsrc_or_notdst),
- TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_notxor_dst),
- TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_or_notdst),
- TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notsrc),
- TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notsrc_or_dst),
- TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notsrc_and_notdst),
-};
-
-static const cirrus_bitblt_rop_t cirrus_bkwd_transp_rop[16][2] = {
- TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_0),
- TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_and_dst),
- TRANSP_NOP(cirrus_bitblt_rop_nop),
- TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_and_notdst),
- TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notdst),
- TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src),
- TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_1),
- TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notsrc_and_dst),
- TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_xor_dst),
- TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_or_dst),
- TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notsrc_or_notdst),
- TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_notxor_dst),
- TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_or_notdst),
- TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notsrc),
- TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notsrc_or_dst),
- TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notsrc_and_notdst),
-};
-
-#define ROP2(name) {\
- name ## _8,\
- name ## _16,\
- name ## _24,\
- name ## _32,\
- }
-
-#define ROP_NOP2(func) {\
- func,\
- func,\
- func,\
- func,\
- }
-
-static const cirrus_bitblt_rop_t cirrus_patternfill[16][4] = {
- ROP2(cirrus_patternfill_0),
- ROP2(cirrus_patternfill_src_and_dst),
- ROP_NOP2(cirrus_bitblt_rop_nop),
- ROP2(cirrus_patternfill_src_and_notdst),
- ROP2(cirrus_patternfill_notdst),
- ROP2(cirrus_patternfill_src),
- ROP2(cirrus_patternfill_1),
- ROP2(cirrus_patternfill_notsrc_and_dst),
- ROP2(cirrus_patternfill_src_xor_dst),
- ROP2(cirrus_patternfill_src_or_dst),
- ROP2(cirrus_patternfill_notsrc_or_notdst),
- ROP2(cirrus_patternfill_src_notxor_dst),
- ROP2(cirrus_patternfill_src_or_notdst),
- ROP2(cirrus_patternfill_notsrc),
- ROP2(cirrus_patternfill_notsrc_or_dst),
- ROP2(cirrus_patternfill_notsrc_and_notdst),
-};
-
-static const cirrus_bitblt_rop_t cirrus_colorexpand_transp[16][4] = {
- ROP2(cirrus_colorexpand_transp_0),
- ROP2(cirrus_colorexpand_transp_src_and_dst),
- ROP_NOP2(cirrus_bitblt_rop_nop),
- ROP2(cirrus_colorexpand_transp_src_and_notdst),
- ROP2(cirrus_colorexpand_transp_notdst),
- ROP2(cirrus_colorexpand_transp_src),
- ROP2(cirrus_colorexpand_transp_1),
- ROP2(cirrus_colorexpand_transp_notsrc_and_dst),
- ROP2(cirrus_colorexpand_transp_src_xor_dst),
- ROP2(cirrus_colorexpand_transp_src_or_dst),
- ROP2(cirrus_colorexpand_transp_notsrc_or_notdst),
- ROP2(cirrus_colorexpand_transp_src_notxor_dst),
- ROP2(cirrus_colorexpand_transp_src_or_notdst),
- ROP2(cirrus_colorexpand_transp_notsrc),
- ROP2(cirrus_colorexpand_transp_notsrc_or_dst),
- ROP2(cirrus_colorexpand_transp_notsrc_and_notdst),
-};
-
-static const cirrus_bitblt_rop_t cirrus_colorexpand[16][4] = {
- ROP2(cirrus_colorexpand_0),
- ROP2(cirrus_colorexpand_src_and_dst),
- ROP_NOP2(cirrus_bitblt_rop_nop),
- ROP2(cirrus_colorexpand_src_and_notdst),
- ROP2(cirrus_colorexpand_notdst),
- ROP2(cirrus_colorexpand_src),
- ROP2(cirrus_colorexpand_1),
- ROP2(cirrus_colorexpand_notsrc_and_dst),
- ROP2(cirrus_colorexpand_src_xor_dst),
- ROP2(cirrus_colorexpand_src_or_dst),
- ROP2(cirrus_colorexpand_notsrc_or_notdst),
- ROP2(cirrus_colorexpand_src_notxor_dst),
- ROP2(cirrus_colorexpand_src_or_notdst),
- ROP2(cirrus_colorexpand_notsrc),
- ROP2(cirrus_colorexpand_notsrc_or_dst),
- ROP2(cirrus_colorexpand_notsrc_and_notdst),
-};
-
-static const cirrus_bitblt_rop_t cirrus_colorexpand_pattern_transp[16][4] = {
- ROP2(cirrus_colorexpand_pattern_transp_0),
- ROP2(cirrus_colorexpand_pattern_transp_src_and_dst),
- ROP_NOP2(cirrus_bitblt_rop_nop),
- ROP2(cirrus_colorexpand_pattern_transp_src_and_notdst),
- ROP2(cirrus_colorexpand_pattern_transp_notdst),
- ROP2(cirrus_colorexpand_pattern_transp_src),
- ROP2(cirrus_colorexpand_pattern_transp_1),
- ROP2(cirrus_colorexpand_pattern_transp_notsrc_and_dst),
- ROP2(cirrus_colorexpand_pattern_transp_src_xor_dst),
- ROP2(cirrus_colorexpand_pattern_transp_src_or_dst),
- ROP2(cirrus_colorexpand_pattern_transp_notsrc_or_notdst),
- ROP2(cirrus_colorexpand_pattern_transp_src_notxor_dst),
- ROP2(cirrus_colorexpand_pattern_transp_src_or_notdst),
- ROP2(cirrus_colorexpand_pattern_transp_notsrc),
- ROP2(cirrus_colorexpand_pattern_transp_notsrc_or_dst),
- ROP2(cirrus_colorexpand_pattern_transp_notsrc_and_notdst),
-};
-
-static const cirrus_bitblt_rop_t cirrus_colorexpand_pattern[16][4] = {
- ROP2(cirrus_colorexpand_pattern_0),
- ROP2(cirrus_colorexpand_pattern_src_and_dst),
- ROP_NOP2(cirrus_bitblt_rop_nop),
- ROP2(cirrus_colorexpand_pattern_src_and_notdst),
- ROP2(cirrus_colorexpand_pattern_notdst),
- ROP2(cirrus_colorexpand_pattern_src),
- ROP2(cirrus_colorexpand_pattern_1),
- ROP2(cirrus_colorexpand_pattern_notsrc_and_dst),
- ROP2(cirrus_colorexpand_pattern_src_xor_dst),
- ROP2(cirrus_colorexpand_pattern_src_or_dst),
- ROP2(cirrus_colorexpand_pattern_notsrc_or_notdst),
- ROP2(cirrus_colorexpand_pattern_src_notxor_dst),
- ROP2(cirrus_colorexpand_pattern_src_or_notdst),
- ROP2(cirrus_colorexpand_pattern_notsrc),
- ROP2(cirrus_colorexpand_pattern_notsrc_or_dst),
- ROP2(cirrus_colorexpand_pattern_notsrc_and_notdst),
-};
-
-static const cirrus_fill_t cirrus_fill[16][4] = {
- ROP2(cirrus_fill_0),
- ROP2(cirrus_fill_src_and_dst),
- ROP_NOP2(cirrus_bitblt_fill_nop),
- ROP2(cirrus_fill_src_and_notdst),
- ROP2(cirrus_fill_notdst),
- ROP2(cirrus_fill_src),
- ROP2(cirrus_fill_1),
- ROP2(cirrus_fill_notsrc_and_dst),
- ROP2(cirrus_fill_src_xor_dst),
- ROP2(cirrus_fill_src_or_dst),
- ROP2(cirrus_fill_notsrc_or_notdst),
- ROP2(cirrus_fill_src_notxor_dst),
- ROP2(cirrus_fill_src_or_notdst),
- ROP2(cirrus_fill_notsrc),
- ROP2(cirrus_fill_notsrc_or_dst),
- ROP2(cirrus_fill_notsrc_and_notdst),
-};
-
-static inline void cirrus_bitblt_fgcol(CirrusVGAState *s)
-{
- unsigned int color;
- switch (s->cirrus_blt_pixelwidth) {
- case 1:
- s->cirrus_blt_fgcol = s->cirrus_shadow_gr1;
- break;
- case 2:
- color = s->cirrus_shadow_gr1 | (s->vga.gr[0x11] << 8);
- s->cirrus_blt_fgcol = le16_to_cpu(color);
- break;
- case 3:
- s->cirrus_blt_fgcol = s->cirrus_shadow_gr1 |
- (s->vga.gr[0x11] << 8) | (s->vga.gr[0x13] << 16);
- break;
- default:
- case 4:
- color = s->cirrus_shadow_gr1 | (s->vga.gr[0x11] << 8) |
- (s->vga.gr[0x13] << 16) | (s->vga.gr[0x15] << 24);
- s->cirrus_blt_fgcol = le32_to_cpu(color);
- break;
- }
-}
-
-static inline void cirrus_bitblt_bgcol(CirrusVGAState *s)
-{
- unsigned int color;
- switch (s->cirrus_blt_pixelwidth) {
- case 1:
- s->cirrus_blt_bgcol = s->cirrus_shadow_gr0;
- break;
- case 2:
- color = s->cirrus_shadow_gr0 | (s->vga.gr[0x10] << 8);
- s->cirrus_blt_bgcol = le16_to_cpu(color);
- break;
- case 3:
- s->cirrus_blt_bgcol = s->cirrus_shadow_gr0 |
- (s->vga.gr[0x10] << 8) | (s->vga.gr[0x12] << 16);
- break;
- default:
- case 4:
- color = s->cirrus_shadow_gr0 | (s->vga.gr[0x10] << 8) |
- (s->vga.gr[0x12] << 16) | (s->vga.gr[0x14] << 24);
- s->cirrus_blt_bgcol = le32_to_cpu(color);
- break;
- }
-}
-
-static void cirrus_invalidate_region(CirrusVGAState * s, int off_begin,
- int off_pitch, int bytesperline,
- int lines)
-{
- int y;
- int off_cur;
- int off_cur_end;
-
- for (y = 0; y < lines; y++) {
- off_cur = off_begin;
- off_cur_end = (off_cur + bytesperline) & s->cirrus_addr_mask;
- memory_region_set_dirty(&s->vga.vram, off_cur, off_cur_end - off_cur);
- off_begin += off_pitch;
- }
-}
-
-static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s,
- const uint8_t * src)
-{
- uint8_t *dst;
-
- dst = s->vga.vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask);
-
- if (blit_is_unsafe(s))
- return 0;
-
- (*s->cirrus_rop) (s, dst, src,
- s->cirrus_blt_dstpitch, 0,
- s->cirrus_blt_width, s->cirrus_blt_height);
- cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
- s->cirrus_blt_dstpitch, s->cirrus_blt_width,
- s->cirrus_blt_height);
- return 1;
-}
-
-/* fill */
-
-static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop)
-{
- cirrus_fill_t rop_func;
-
- if (blit_is_unsafe(s)) {
- return 0;
- }
- rop_func = cirrus_fill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
- rop_func(s, s->vga.vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask),
- s->cirrus_blt_dstpitch,
- s->cirrus_blt_width, s->cirrus_blt_height);
- cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
- s->cirrus_blt_dstpitch, s->cirrus_blt_width,
- s->cirrus_blt_height);
- cirrus_bitblt_reset(s);
- return 1;
-}
-
-/***************************************
- *
- * bitblt (video-to-video)
- *
- ***************************************/
-
-static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s)
-{
- return cirrus_bitblt_common_patterncopy(s,
- s->vga.vram_ptr + ((s->cirrus_blt_srcaddr & ~7) &
- s->cirrus_addr_mask));
-}
-
-static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
-{
- int sx = 0, sy = 0;
- int dx = 0, dy = 0;
- int depth = 0;
- int notify = 0;
-
- /* make sure to only copy if it's a plain copy ROP */
- if (*s->cirrus_rop == cirrus_bitblt_rop_fwd_src ||
- *s->cirrus_rop == cirrus_bitblt_rop_bkwd_src) {
-
- int width, height;
-
- depth = s->vga.get_bpp(&s->vga) / 8;
- s->vga.get_resolution(&s->vga, &width, &height);
-
- /* extra x, y */
- sx = (src % ABS(s->cirrus_blt_srcpitch)) / depth;
- sy = (src / ABS(s->cirrus_blt_srcpitch));
- dx = (dst % ABS(s->cirrus_blt_dstpitch)) / depth;
- dy = (dst / ABS(s->cirrus_blt_dstpitch));
-
- /* normalize width */
- w /= depth;
-
- /* if we're doing a backward copy, we have to adjust
- our x/y to be the upper left corner (instead of the lower
- right corner) */
- if (s->cirrus_blt_dstpitch < 0) {
- sx -= (s->cirrus_blt_width / depth) - 1;
- dx -= (s->cirrus_blt_width / depth) - 1;
- sy -= s->cirrus_blt_height - 1;
- dy -= s->cirrus_blt_height - 1;
- }
-
- /* are we in the visible portion of memory? */
- if (sx >= 0 && sy >= 0 && dx >= 0 && dy >= 0 &&
- (sx + w) <= width && (sy + h) <= height &&
- (dx + w) <= width && (dy + h) <= height) {
- notify = 1;
- }
- }
-
- /* we have to flush all pending changes so that the copy
- is generated at the appropriate moment in time */
- if (notify)
- graphic_hw_update(s->vga.con);
-
- (*s->cirrus_rop) (s, s->vga.vram_ptr +
- (s->cirrus_blt_dstaddr & s->cirrus_addr_mask),
- s->vga.vram_ptr +
- (s->cirrus_blt_srcaddr & s->cirrus_addr_mask),
- s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch,
- s->cirrus_blt_width, s->cirrus_blt_height);
-
- if (notify) {
- qemu_console_copy(s->vga.con,
- sx, sy, dx, dy,
- s->cirrus_blt_width / depth,
- s->cirrus_blt_height);
- }
-
- /* we don't have to notify the display that this portion has
- changed since qemu_console_copy implies this */
-
- cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
- s->cirrus_blt_dstpitch, s->cirrus_blt_width,
- s->cirrus_blt_height);
-}
-
-static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s)
-{
- if (blit_is_unsafe(s))
- return 0;
-
- cirrus_do_copy(s, s->cirrus_blt_dstaddr - s->vga.start_addr,
- s->cirrus_blt_srcaddr - s->vga.start_addr,
- s->cirrus_blt_width, s->cirrus_blt_height);
-
- return 1;
-}
-
-/***************************************
- *
- * bitblt (cpu-to-video)
- *
- ***************************************/
-
-static void cirrus_bitblt_cputovideo_next(CirrusVGAState * s)
-{
- int copy_count;
- uint8_t *end_ptr;
-
- if (s->cirrus_srccounter > 0) {
- if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
- cirrus_bitblt_common_patterncopy(s, s->cirrus_bltbuf);
- the_end:
- s->cirrus_srccounter = 0;
- cirrus_bitblt_reset(s);
- } else {
- /* at least one scan line */
- do {
- (*s->cirrus_rop)(s, s->vga.vram_ptr +
- (s->cirrus_blt_dstaddr & s->cirrus_addr_mask),
- s->cirrus_bltbuf, 0, 0, s->cirrus_blt_width, 1);
- cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, 0,
- s->cirrus_blt_width, 1);
- s->cirrus_blt_dstaddr += s->cirrus_blt_dstpitch;
- s->cirrus_srccounter -= s->cirrus_blt_srcpitch;
- if (s->cirrus_srccounter <= 0)
- goto the_end;
- /* more bytes than needed can be transferred because of
- word alignment, so we keep them for the next line */
- /* XXX: keep alignment to speed up transfer */
- end_ptr = s->cirrus_bltbuf + s->cirrus_blt_srcpitch;
- copy_count = s->cirrus_srcptr_end - end_ptr;
- memmove(s->cirrus_bltbuf, end_ptr, copy_count);
- s->cirrus_srcptr = s->cirrus_bltbuf + copy_count;
- s->cirrus_srcptr_end = s->cirrus_bltbuf + s->cirrus_blt_srcpitch;
- } while (s->cirrus_srcptr >= s->cirrus_srcptr_end);
- }
- }
-}
-
-/***************************************
- *
- * bitblt wrapper
- *
- ***************************************/
-
-static void cirrus_bitblt_reset(CirrusVGAState * s)
-{
- int need_update;
-
- s->vga.gr[0x31] &=
- ~(CIRRUS_BLT_START | CIRRUS_BLT_BUSY | CIRRUS_BLT_FIFOUSED);
- need_update = s->cirrus_srcptr != &s->cirrus_bltbuf[0]
- || s->cirrus_srcptr_end != &s->cirrus_bltbuf[0];
- s->cirrus_srcptr = &s->cirrus_bltbuf[0];
- s->cirrus_srcptr_end = &s->cirrus_bltbuf[0];
- s->cirrus_srccounter = 0;
- if (!need_update)
- return;
- cirrus_update_memory_access(s);
-}
-
-static int cirrus_bitblt_cputovideo(CirrusVGAState * s)
-{
- int w;
-
- s->cirrus_blt_mode &= ~CIRRUS_BLTMODE_MEMSYSSRC;
- s->cirrus_srcptr = &s->cirrus_bltbuf[0];
- s->cirrus_srcptr_end = &s->cirrus_bltbuf[0];
-
- if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
- if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) {
- s->cirrus_blt_srcpitch = 8;
- } else {
- /* XXX: check for 24 bpp */
- s->cirrus_blt_srcpitch = 8 * 8 * s->cirrus_blt_pixelwidth;
- }
- s->cirrus_srccounter = s->cirrus_blt_srcpitch;
- } else {
- if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) {
- w = s->cirrus_blt_width / s->cirrus_blt_pixelwidth;
- if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_DWORDGRANULARITY)
- s->cirrus_blt_srcpitch = ((w + 31) >> 5);
- else
- s->cirrus_blt_srcpitch = ((w + 7) >> 3);
- } else {
- /* always align input size to 32 bits */
- s->cirrus_blt_srcpitch = (s->cirrus_blt_width + 3) & ~3;
- }
- s->cirrus_srccounter = s->cirrus_blt_srcpitch * s->cirrus_blt_height;
- }
- s->cirrus_srcptr = s->cirrus_bltbuf;
- s->cirrus_srcptr_end = s->cirrus_bltbuf + s->cirrus_blt_srcpitch;
- cirrus_update_memory_access(s);
- return 1;
-}
-
-static int cirrus_bitblt_videotocpu(CirrusVGAState * s)
-{
- /* XXX */
-#ifdef DEBUG_BITBLT
- printf("cirrus: bitblt (video to cpu) is not implemented yet\n");
-#endif
- return 0;
-}
-
-static int cirrus_bitblt_videotovideo(CirrusVGAState * s)
-{
- int ret;
-
- if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
- ret = cirrus_bitblt_videotovideo_patterncopy(s);
- } else {
- ret = cirrus_bitblt_videotovideo_copy(s);
- }
- if (ret)
- cirrus_bitblt_reset(s);
- return ret;
-}
-
-static void cirrus_bitblt_start(CirrusVGAState * s)
-{
- uint8_t blt_rop;
-
- s->vga.gr[0x31] |= CIRRUS_BLT_BUSY;
-
- s->cirrus_blt_width = (s->vga.gr[0x20] | (s->vga.gr[0x21] << 8)) + 1;
- s->cirrus_blt_height = (s->vga.gr[0x22] | (s->vga.gr[0x23] << 8)) + 1;
- s->cirrus_blt_dstpitch = (s->vga.gr[0x24] | (s->vga.gr[0x25] << 8));
- s->cirrus_blt_srcpitch = (s->vga.gr[0x26] | (s->vga.gr[0x27] << 8));
- s->cirrus_blt_dstaddr =
- (s->vga.gr[0x28] | (s->vga.gr[0x29] << 8) | (s->vga.gr[0x2a] << 16));
- s->cirrus_blt_srcaddr =
- (s->vga.gr[0x2c] | (s->vga.gr[0x2d] << 8) | (s->vga.gr[0x2e] << 16));
- s->cirrus_blt_mode = s->vga.gr[0x30];
- s->cirrus_blt_modeext = s->vga.gr[0x33];
- blt_rop = s->vga.gr[0x32];
-
-#ifdef DEBUG_BITBLT
- printf("rop=0x%02x mode=0x%02x modeext=0x%02x w=%d h=%d dpitch=%d spitch=%d daddr=0x%08x saddr=0x%08x writemask=0x%02x\n",
- blt_rop,
- s->cirrus_blt_mode,
- s->cirrus_blt_modeext,
- s->cirrus_blt_width,
- s->cirrus_blt_height,
- s->cirrus_blt_dstpitch,
- s->cirrus_blt_srcpitch,
- s->cirrus_blt_dstaddr,
- s->cirrus_blt_srcaddr,
- s->vga.gr[0x2f]);
-#endif
-
- switch (s->cirrus_blt_mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) {
- case CIRRUS_BLTMODE_PIXELWIDTH8:
- s->cirrus_blt_pixelwidth = 1;
- break;
- case CIRRUS_BLTMODE_PIXELWIDTH16:
- s->cirrus_blt_pixelwidth = 2;
- break;
- case CIRRUS_BLTMODE_PIXELWIDTH24:
- s->cirrus_blt_pixelwidth = 3;
- break;
- case CIRRUS_BLTMODE_PIXELWIDTH32:
- s->cirrus_blt_pixelwidth = 4;
- break;
- default:
-#ifdef DEBUG_BITBLT
- printf("cirrus: bitblt - pixel width is unknown\n");
-#endif
- goto bitblt_ignore;
- }
- s->cirrus_blt_mode &= ~CIRRUS_BLTMODE_PIXELWIDTHMASK;
-
- if ((s->
- cirrus_blt_mode & (CIRRUS_BLTMODE_MEMSYSSRC |
- CIRRUS_BLTMODE_MEMSYSDEST))
- == (CIRRUS_BLTMODE_MEMSYSSRC | CIRRUS_BLTMODE_MEMSYSDEST)) {
-#ifdef DEBUG_BITBLT
- printf("cirrus: bitblt - memory-to-memory copy is requested\n");
-#endif
- goto bitblt_ignore;
- }
-
- if ((s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_SOLIDFILL) &&
- (s->cirrus_blt_mode & (CIRRUS_BLTMODE_MEMSYSDEST |
- CIRRUS_BLTMODE_TRANSPARENTCOMP |
- CIRRUS_BLTMODE_PATTERNCOPY |
- CIRRUS_BLTMODE_COLOREXPAND)) ==
- (CIRRUS_BLTMODE_PATTERNCOPY | CIRRUS_BLTMODE_COLOREXPAND)) {
- cirrus_bitblt_fgcol(s);
- cirrus_bitblt_solidfill(s, blt_rop);
- } else {
- if ((s->cirrus_blt_mode & (CIRRUS_BLTMODE_COLOREXPAND |
- CIRRUS_BLTMODE_PATTERNCOPY)) ==
- CIRRUS_BLTMODE_COLOREXPAND) {
-
- if (s->cirrus_blt_mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) {
- if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV)
- cirrus_bitblt_bgcol(s);
- else
- cirrus_bitblt_fgcol(s);
- s->cirrus_rop = cirrus_colorexpand_transp[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
- } else {
- cirrus_bitblt_fgcol(s);
- cirrus_bitblt_bgcol(s);
- s->cirrus_rop = cirrus_colorexpand[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
- }
- } else if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
- if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) {
- if (s->cirrus_blt_mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) {
- if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV)
- cirrus_bitblt_bgcol(s);
- else
- cirrus_bitblt_fgcol(s);
- s->cirrus_rop = cirrus_colorexpand_pattern_transp[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
- } else {
- cirrus_bitblt_fgcol(s);
- cirrus_bitblt_bgcol(s);
- s->cirrus_rop = cirrus_colorexpand_pattern[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
- }
- } else {
- s->cirrus_rop = cirrus_patternfill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
- }
- } else {
- if (s->cirrus_blt_mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) {
- if (s->cirrus_blt_pixelwidth > 2) {
- printf("src transparent without colorexpand must be 8bpp or 16bpp\n");
- goto bitblt_ignore;
- }
- if (s->cirrus_blt_mode & CIRRUS_BLTMODE_BACKWARDS) {
- s->cirrus_blt_dstpitch = -s->cirrus_blt_dstpitch;
- s->cirrus_blt_srcpitch = -s->cirrus_blt_srcpitch;
- s->cirrus_rop = cirrus_bkwd_transp_rop[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
- } else {
- s->cirrus_rop = cirrus_fwd_transp_rop[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
- }
- } else {
- if (s->cirrus_blt_mode & CIRRUS_BLTMODE_BACKWARDS) {
- s->cirrus_blt_dstpitch = -s->cirrus_blt_dstpitch;
- s->cirrus_blt_srcpitch = -s->cirrus_blt_srcpitch;
- s->cirrus_rop = cirrus_bkwd_rop[rop_to_index[blt_rop]];
- } else {
- s->cirrus_rop = cirrus_fwd_rop[rop_to_index[blt_rop]];
- }
- }
- }
- // setup bitblt engine.
- if (s->cirrus_blt_mode & CIRRUS_BLTMODE_MEMSYSSRC) {
- if (!cirrus_bitblt_cputovideo(s))
- goto bitblt_ignore;
- } else if (s->cirrus_blt_mode & CIRRUS_BLTMODE_MEMSYSDEST) {
- if (!cirrus_bitblt_videotocpu(s))
- goto bitblt_ignore;
- } else {
- if (!cirrus_bitblt_videotovideo(s))
- goto bitblt_ignore;
- }
- }
- return;
- bitblt_ignore:;
- cirrus_bitblt_reset(s);
-}
-
-static void cirrus_write_bitblt(CirrusVGAState * s, unsigned reg_value)
-{
- unsigned old_value;
-
- old_value = s->vga.gr[0x31];
- s->vga.gr[0x31] = reg_value;
-
- if (((old_value & CIRRUS_BLT_RESET) != 0) &&
- ((reg_value & CIRRUS_BLT_RESET) == 0)) {
- cirrus_bitblt_reset(s);
- } else if (((old_value & CIRRUS_BLT_START) == 0) &&
- ((reg_value & CIRRUS_BLT_START) != 0)) {
- cirrus_bitblt_start(s);
- }
-}
-
-
-/***************************************
- *
- * basic parameters
- *
- ***************************************/
-
-static void cirrus_get_offsets(VGACommonState *s1,
- uint32_t *pline_offset,
- uint32_t *pstart_addr,
- uint32_t *pline_compare)
-{
- CirrusVGAState * s = container_of(s1, CirrusVGAState, vga);
- uint32_t start_addr, line_offset, line_compare;
-
- line_offset = s->vga.cr[0x13]
- | ((s->vga.cr[0x1b] & 0x10) << 4);
- line_offset <<= 3;
- *pline_offset = line_offset;
-
- start_addr = (s->vga.cr[0x0c] << 8)
- | s->vga.cr[0x0d]
- | ((s->vga.cr[0x1b] & 0x01) << 16)
- | ((s->vga.cr[0x1b] & 0x0c) << 15)
- | ((s->vga.cr[0x1d] & 0x80) << 12);
- *pstart_addr = start_addr;
-
- line_compare = s->vga.cr[0x18] |
- ((s->vga.cr[0x07] & 0x10) << 4) |
- ((s->vga.cr[0x09] & 0x40) << 3);
- *pline_compare = line_compare;
-}
-
-static uint32_t cirrus_get_bpp16_depth(CirrusVGAState * s)
-{
- uint32_t ret = 16;
-
- switch (s->cirrus_hidden_dac_data & 0xf) {
- case 0:
- ret = 15;
- break; /* Sierra HiColor */
- case 1:
- ret = 16;
- break; /* XGA HiColor */
- default:
-#ifdef DEBUG_CIRRUS
- printf("cirrus: invalid DAC value %x in 16bpp\n",
- (s->cirrus_hidden_dac_data & 0xf));
-#endif
- ret = 15; /* XXX */
- break;
- }
- return ret;
-}
-
-static int cirrus_get_bpp(VGACommonState *s1)
-{
- CirrusVGAState * s = container_of(s1, CirrusVGAState, vga);
- uint32_t ret = 8;
-
- if ((s->vga.sr[0x07] & 0x01) != 0) {
- /* Cirrus SVGA */
- switch (s->vga.sr[0x07] & CIRRUS_SR7_BPP_MASK) {
- case CIRRUS_SR7_BPP_8:
- ret = 8;
- break;
- case CIRRUS_SR7_BPP_16_DOUBLEVCLK:
- ret = cirrus_get_bpp16_depth(s);
- break;
- case CIRRUS_SR7_BPP_24:
- ret = 24;
- break;
- case CIRRUS_SR7_BPP_16:
- ret = cirrus_get_bpp16_depth(s);
- break;
- case CIRRUS_SR7_BPP_32:
- ret = 32;
- break;
- default:
-#ifdef DEBUG_CIRRUS
- printf("cirrus: unknown bpp - sr7=%x\n", s->vga.sr[0x7]);
-#endif
- ret = 8;
- break;
- }
- } else {
- /* VGA */
- ret = 0;
- }
-
- return ret;
-}
-
-static void cirrus_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
-{
- int width, height;
-
- width = (s->cr[0x01] + 1) * 8;
- height = s->cr[0x12] |
- ((s->cr[0x07] & 0x02) << 7) |
- ((s->cr[0x07] & 0x40) << 3);
- height = (height + 1);
- /* interlace support */
- if (s->cr[0x1a] & 0x01)
- height = height * 2;
- *pwidth = width;
- *pheight = height;
-}
-
-/***************************************
- *
- * bank memory
- *
- ***************************************/
-
-static void cirrus_update_bank_ptr(CirrusVGAState * s, unsigned bank_index)
-{
- unsigned offset;
- unsigned limit;
-
- if ((s->vga.gr[0x0b] & 0x01) != 0) /* dual bank */
- offset = s->vga.gr[0x09 + bank_index];
- else /* single bank */
- offset = s->vga.gr[0x09];
-
- if ((s->vga.gr[0x0b] & 0x20) != 0)
- offset <<= 14;
- else
- offset <<= 12;
-
- if (s->real_vram_size <= offset)
- limit = 0;
- else
- limit = s->real_vram_size - offset;
-
- if (((s->vga.gr[0x0b] & 0x01) == 0) && (bank_index != 0)) {
- if (limit > 0x8000) {
- offset += 0x8000;
- limit -= 0x8000;
- } else {
- limit = 0;
- }
- }
-
- if (limit > 0) {
- s->cirrus_bank_base[bank_index] = offset;
- s->cirrus_bank_limit[bank_index] = limit;
- } else {
- s->cirrus_bank_base[bank_index] = 0;
- s->cirrus_bank_limit[bank_index] = 0;
- }
-}
-
-/***************************************
- *
- * I/O access between 0x3c4-0x3c5
- *
- ***************************************/
-
-static int cirrus_vga_read_sr(CirrusVGAState * s)
-{
- switch (s->vga.sr_index) {
- case 0x00: // Standard VGA
- case 0x01: // Standard VGA
- case 0x02: // Standard VGA
- case 0x03: // Standard VGA
- case 0x04: // Standard VGA
- return s->vga.sr[s->vga.sr_index];
- case 0x06: // Unlock Cirrus extensions
- return s->vga.sr[s->vga.sr_index];
- case 0x10:
- case 0x30:
- case 0x50:
- case 0x70: // Graphics Cursor X
- case 0x90:
- case 0xb0:
- case 0xd0:
- case 0xf0: // Graphics Cursor X
- return s->vga.sr[0x10];
- case 0x11:
- case 0x31:
- case 0x51:
- case 0x71: // Graphics Cursor Y
- case 0x91:
- case 0xb1:
- case 0xd1:
- case 0xf1: // Graphics Cursor Y
- return s->vga.sr[0x11];
- case 0x05: // ???
- case 0x07: // Extended Sequencer Mode
- case 0x08: // EEPROM Control
- case 0x09: // Scratch Register 0
- case 0x0a: // Scratch Register 1
- case 0x0b: // VCLK 0
- case 0x0c: // VCLK 1
- case 0x0d: // VCLK 2
- case 0x0e: // VCLK 3
- case 0x0f: // DRAM Control
- case 0x12: // Graphics Cursor Attribute
- case 0x13: // Graphics Cursor Pattern Address
- case 0x14: // Scratch Register 2
- case 0x15: // Scratch Register 3
- case 0x16: // Performance Tuning Register
- case 0x17: // Configuration Readback and Extended Control
- case 0x18: // Signature Generator Control
- case 0x19: // Signal Generator Result
- case 0x1a: // Signal Generator Result
- case 0x1b: // VCLK 0 Denominator & Post
- case 0x1c: // VCLK 1 Denominator & Post
- case 0x1d: // VCLK 2 Denominator & Post
- case 0x1e: // VCLK 3 Denominator & Post
- case 0x1f: // BIOS Write Enable and MCLK select
-#ifdef DEBUG_CIRRUS
- printf("cirrus: handled inport sr_index %02x\n", s->vga.sr_index);
-#endif
- return s->vga.sr[s->vga.sr_index];
- default:
-#ifdef DEBUG_CIRRUS
- printf("cirrus: inport sr_index %02x\n", s->vga.sr_index);
-#endif
- return 0xff;
- break;
- }
-}
-
-static void cirrus_vga_write_sr(CirrusVGAState * s, uint32_t val)
-{
- switch (s->vga.sr_index) {
- case 0x00: // Standard VGA
- case 0x01: // Standard VGA
- case 0x02: // Standard VGA
- case 0x03: // Standard VGA
- case 0x04: // Standard VGA
- s->vga.sr[s->vga.sr_index] = val & sr_mask[s->vga.sr_index];
- if (s->vga.sr_index == 1)
- s->vga.update_retrace_info(&s->vga);
- break;
- case 0x06: // Unlock Cirrus extensions
- val &= 0x17;
- if (val == 0x12) {
- s->vga.sr[s->vga.sr_index] = 0x12;
- } else {
- s->vga.sr[s->vga.sr_index] = 0x0f;
- }
- break;
- case 0x10:
- case 0x30:
- case 0x50:
- case 0x70: // Graphics Cursor X
- case 0x90:
- case 0xb0:
- case 0xd0:
- case 0xf0: // Graphics Cursor X
- s->vga.sr[0x10] = val;
- s->vga.hw_cursor_x = (val << 3) | (s->vga.sr_index >> 5);
- break;
- case 0x11:
- case 0x31:
- case 0x51:
- case 0x71: // Graphics Cursor Y
- case 0x91:
- case 0xb1:
- case 0xd1:
- case 0xf1: // Graphics Cursor Y
- s->vga.sr[0x11] = val;
- s->vga.hw_cursor_y = (val << 3) | (s->vga.sr_index >> 5);
- break;
- case 0x07: // Extended Sequencer Mode
- cirrus_update_memory_access(s);
- case 0x08: // EEPROM Control
- case 0x09: // Scratch Register 0
- case 0x0a: // Scratch Register 1
- case 0x0b: // VCLK 0
- case 0x0c: // VCLK 1
- case 0x0d: // VCLK 2
- case 0x0e: // VCLK 3
- case 0x0f: // DRAM Control
- case 0x13: // Graphics Cursor Pattern Address
- case 0x14: // Scratch Register 2
- case 0x15: // Scratch Register 3
- case 0x16: // Performance Tuning Register
- case 0x18: // Signature Generator Control
- case 0x19: // Signature Generator Result
- case 0x1a: // Signature Generator Result
- case 0x1b: // VCLK 0 Denominator & Post
- case 0x1c: // VCLK 1 Denominator & Post
- case 0x1d: // VCLK 2 Denominator & Post
- case 0x1e: // VCLK 3 Denominator & Post
- case 0x1f: // BIOS Write Enable and MCLK select
- s->vga.sr[s->vga.sr_index] = val;
-#ifdef DEBUG_CIRRUS
- printf("cirrus: handled outport sr_index %02x, sr_value %02x\n",
- s->vga.sr_index, val);
-#endif
- break;
- case 0x12: // Graphics Cursor Attribute
- s->vga.sr[0x12] = val;
- s->vga.force_shadow = !!(val & CIRRUS_CURSOR_SHOW);
-#ifdef DEBUG_CIRRUS
- printf("cirrus: cursor ctl SR12=%02x (force shadow: %d)\n",
- val, s->vga.force_shadow);
-#endif
- break;
- case 0x17: // Configuration Readback and Extended Control
- s->vga.sr[s->vga.sr_index] = (s->vga.sr[s->vga.sr_index] & 0x38)
- | (val & 0xc7);
- cirrus_update_memory_access(s);
- break;
- default:
-#ifdef DEBUG_CIRRUS
- printf("cirrus: outport sr_index %02x, sr_value %02x\n",
- s->vga.sr_index, val);
-#endif
- break;
- }
-}
-
-/***************************************
- *
- * I/O access at 0x3c6
- *
- ***************************************/
-
-static int cirrus_read_hidden_dac(CirrusVGAState * s)
-{
- if (++s->cirrus_hidden_dac_lockindex == 5) {
- s->cirrus_hidden_dac_lockindex = 0;
- return s->cirrus_hidden_dac_data;
- }
- return 0xff;
-}
-
-static void cirrus_write_hidden_dac(CirrusVGAState * s, int reg_value)
-{
- if (s->cirrus_hidden_dac_lockindex == 4) {
- s->cirrus_hidden_dac_data = reg_value;
-#if defined(DEBUG_CIRRUS)
- printf("cirrus: outport hidden DAC, value %02x\n", reg_value);
-#endif
- }
- s->cirrus_hidden_dac_lockindex = 0;
-}
-
-/***************************************
- *
- * I/O access at 0x3c9
- *
- ***************************************/
-
-static int cirrus_vga_read_palette(CirrusVGAState * s)
-{
- int val;
-
- if ((s->vga.sr[0x12] & CIRRUS_CURSOR_HIDDENPEL)) {
- val = s->cirrus_hidden_palette[(s->vga.dac_read_index & 0x0f) * 3 +
- s->vga.dac_sub_index];
- } else {
- val = s->vga.palette[s->vga.dac_read_index * 3 + s->vga.dac_sub_index];
- }
- if (++s->vga.dac_sub_index == 3) {
- s->vga.dac_sub_index = 0;
- s->vga.dac_read_index++;
- }
- return val;
-}
-
-static void cirrus_vga_write_palette(CirrusVGAState * s, int reg_value)
-{
- s->vga.dac_cache[s->vga.dac_sub_index] = reg_value;
- if (++s->vga.dac_sub_index == 3) {
- if ((s->vga.sr[0x12] & CIRRUS_CURSOR_HIDDENPEL)) {
- memcpy(&s->cirrus_hidden_palette[(s->vga.dac_write_index & 0x0f) * 3],
- s->vga.dac_cache, 3);
- } else {
- memcpy(&s->vga.palette[s->vga.dac_write_index * 3], s->vga.dac_cache, 3);
- }
- /* XXX update cursor */
- s->vga.dac_sub_index = 0;
- s->vga.dac_write_index++;
- }
-}
-
-/***************************************
- *
- * I/O access between 0x3ce-0x3cf
- *
- ***************************************/
-
-static int cirrus_vga_read_gr(CirrusVGAState * s, unsigned reg_index)
-{
- switch (reg_index) {
- case 0x00: // Standard VGA, BGCOLOR 0x000000ff
- return s->cirrus_shadow_gr0;
- case 0x01: // Standard VGA, FGCOLOR 0x000000ff
- return s->cirrus_shadow_gr1;
- case 0x02: // Standard VGA
- case 0x03: // Standard VGA
- case 0x04: // Standard VGA
- case 0x06: // Standard VGA
- case 0x07: // Standard VGA
- case 0x08: // Standard VGA
- return s->vga.gr[s->vga.gr_index];
- case 0x05: // Standard VGA, Cirrus extended mode
- default:
- break;
- }
-
- if (reg_index < 0x3a) {
- return s->vga.gr[reg_index];
- } else {
-#ifdef DEBUG_CIRRUS
- printf("cirrus: inport gr_index %02x\n", reg_index);
-#endif
- return 0xff;
- }
-}
-
-static void
-cirrus_vga_write_gr(CirrusVGAState * s, unsigned reg_index, int reg_value)
-{
-#if defined(DEBUG_BITBLT) && 0
- printf("gr%02x: %02x\n", reg_index, reg_value);
-#endif
- switch (reg_index) {
- case 0x00: // Standard VGA, BGCOLOR 0x000000ff
- s->vga.gr[reg_index] = reg_value & gr_mask[reg_index];
- s->cirrus_shadow_gr0 = reg_value;
- break;
- case 0x01: // Standard VGA, FGCOLOR 0x000000ff
- s->vga.gr[reg_index] = reg_value & gr_mask[reg_index];
- s->cirrus_shadow_gr1 = reg_value;
- break;
- case 0x02: // Standard VGA
- case 0x03: // Standard VGA
- case 0x04: // Standard VGA
- case 0x06: // Standard VGA
- case 0x07: // Standard VGA
- case 0x08: // Standard VGA
- s->vga.gr[reg_index] = reg_value & gr_mask[reg_index];
- break;
- case 0x05: // Standard VGA, Cirrus extended mode
- s->vga.gr[reg_index] = reg_value & 0x7f;
- cirrus_update_memory_access(s);
- break;
- case 0x09: // bank offset #0
- case 0x0A: // bank offset #1
- s->vga.gr[reg_index] = reg_value;
- cirrus_update_bank_ptr(s, 0);
- cirrus_update_bank_ptr(s, 1);
- cirrus_update_memory_access(s);
- break;
- case 0x0B:
- s->vga.gr[reg_index] = reg_value;
- cirrus_update_bank_ptr(s, 0);
- cirrus_update_bank_ptr(s, 1);
- cirrus_update_memory_access(s);
- break;
- case 0x10: // BGCOLOR 0x0000ff00
- case 0x11: // FGCOLOR 0x0000ff00
- case 0x12: // BGCOLOR 0x00ff0000
- case 0x13: // FGCOLOR 0x00ff0000
- case 0x14: // BGCOLOR 0xff000000
- case 0x15: // FGCOLOR 0xff000000
- case 0x20: // BLT WIDTH 0x0000ff
- case 0x22: // BLT HEIGHT 0x0000ff
- case 0x24: // BLT DEST PITCH 0x0000ff
- case 0x26: // BLT SRC PITCH 0x0000ff
- case 0x28: // BLT DEST ADDR 0x0000ff
- case 0x29: // BLT DEST ADDR 0x00ff00
- case 0x2c: // BLT SRC ADDR 0x0000ff
- case 0x2d: // BLT SRC ADDR 0x00ff00
- case 0x2f: // BLT WRITEMASK
- case 0x30: // BLT MODE
- case 0x32: // RASTER OP
- case 0x33: // BLT MODEEXT
- case 0x34: // BLT TRANSPARENT COLOR 0x00ff
- case 0x35: // BLT TRANSPARENT COLOR 0xff00
- case 0x38: // BLT TRANSPARENT COLOR MASK 0x00ff
- case 0x39: // BLT TRANSPARENT COLOR MASK 0xff00
- s->vga.gr[reg_index] = reg_value;
- break;
- case 0x21: // BLT WIDTH 0x001f00
- case 0x23: // BLT HEIGHT 0x001f00
- case 0x25: // BLT DEST PITCH 0x001f00
- case 0x27: // BLT SRC PITCH 0x001f00
- s->vga.gr[reg_index] = reg_value & 0x1f;
- break;
- case 0x2a: // BLT DEST ADDR 0x3f0000
- s->vga.gr[reg_index] = reg_value & 0x3f;
- /* if auto start mode, starts bit blt now */
- if (s->vga.gr[0x31] & CIRRUS_BLT_AUTOSTART) {
- cirrus_bitblt_start(s);
- }
- break;
- case 0x2e: // BLT SRC ADDR 0x3f0000
- s->vga.gr[reg_index] = reg_value & 0x3f;
- break;
- case 0x31: // BLT STATUS/START
- cirrus_write_bitblt(s, reg_value);
- break;
- default:
-#ifdef DEBUG_CIRRUS
- printf("cirrus: outport gr_index %02x, gr_value %02x\n", reg_index,
- reg_value);
-#endif
- break;
- }
-}
-
-/***************************************
- *
- * I/O access between 0x3d4-0x3d5
- *
- ***************************************/
-
-static int cirrus_vga_read_cr(CirrusVGAState * s, unsigned reg_index)
-{
- switch (reg_index) {
- case 0x00: // Standard VGA
- case 0x01: // Standard VGA
- case 0x02: // Standard VGA
- case 0x03: // Standard VGA
- case 0x04: // Standard VGA
- case 0x05: // Standard VGA
- case 0x06: // Standard VGA
- case 0x07: // Standard VGA
- case 0x08: // Standard VGA
- case 0x09: // Standard VGA
- case 0x0a: // Standard VGA
- case 0x0b: // Standard VGA
- case 0x0c: // Standard VGA
- case 0x0d: // Standard VGA
- case 0x0e: // Standard VGA
- case 0x0f: // Standard VGA
- case 0x10: // Standard VGA
- case 0x11: // Standard VGA
- case 0x12: // Standard VGA
- case 0x13: // Standard VGA
- case 0x14: // Standard VGA
- case 0x15: // Standard VGA
- case 0x16: // Standard VGA
- case 0x17: // Standard VGA
- case 0x18: // Standard VGA
- return s->vga.cr[s->vga.cr_index];
- case 0x24: // Attribute Controller Toggle Readback (R)
- return (s->vga.ar_flip_flop << 7);
- case 0x19: // Interlace End
- case 0x1a: // Miscellaneous Control
- case 0x1b: // Extended Display Control
- case 0x1c: // Sync Adjust and Genlock
- case 0x1d: // Overlay Extended Control
- case 0x22: // Graphics Data Latches Readback (R)
- case 0x25: // Part Status
- case 0x27: // Part ID (R)
- return s->vga.cr[s->vga.cr_index];
- case 0x26: // Attribute Controller Index Readback (R)
- return s->vga.ar_index & 0x3f;
- break;
- default:
-#ifdef DEBUG_CIRRUS
- printf("cirrus: inport cr_index %02x\n", reg_index);
-#endif
- return 0xff;
- }
-}
-
-static void cirrus_vga_write_cr(CirrusVGAState * s, int reg_value)
-{
- switch (s->vga.cr_index) {
- case 0x00: // Standard VGA
- case 0x01: // Standard VGA
- case 0x02: // Standard VGA
- case 0x03: // Standard VGA
- case 0x04: // Standard VGA
- case 0x05: // Standard VGA
- case 0x06: // Standard VGA
- case 0x07: // Standard VGA
- case 0x08: // Standard VGA
- case 0x09: // Standard VGA
- case 0x0a: // Standard VGA
- case 0x0b: // Standard VGA
- case 0x0c: // Standard VGA
- case 0x0d: // Standard VGA
- case 0x0e: // Standard VGA
- case 0x0f: // Standard VGA
- case 0x10: // Standard VGA
- case 0x11: // Standard VGA
- case 0x12: // Standard VGA
- case 0x13: // Standard VGA
- case 0x14: // Standard VGA
- case 0x15: // Standard VGA
- case 0x16: // Standard VGA
- case 0x17: // Standard VGA
- case 0x18: // Standard VGA
- /* handle CR0-7 protection */
- if ((s->vga.cr[0x11] & 0x80) && s->vga.cr_index <= 7) {
- /* can always write bit 4 of CR7 */
- if (s->vga.cr_index == 7)
- s->vga.cr[7] = (s->vga.cr[7] & ~0x10) | (reg_value & 0x10);
- return;
- }
- s->vga.cr[s->vga.cr_index] = reg_value;
- switch(s->vga.cr_index) {
- case 0x00:
- case 0x04:
- case 0x05:
- case 0x06:
- case 0x07:
- case 0x11:
- case 0x17:
- s->vga.update_retrace_info(&s->vga);
- break;
- }
- break;
- case 0x19: // Interlace End
- case 0x1a: // Miscellaneous Control
- case 0x1b: // Extended Display Control
- case 0x1c: // Sync Adjust and Genlock
- case 0x1d: // Overlay Extended Control
- s->vga.cr[s->vga.cr_index] = reg_value;
-#ifdef DEBUG_CIRRUS
- printf("cirrus: handled outport cr_index %02x, cr_value %02x\n",
- s->vga.cr_index, reg_value);
-#endif
- break;
- case 0x22: // Graphics Data Latches Readback (R)
- case 0x24: // Attribute Controller Toggle Readback (R)
- case 0x26: // Attribute Controller Index Readback (R)
- case 0x27: // Part ID (R)
- break;
- case 0x25: // Part Status
- default:
-#ifdef DEBUG_CIRRUS
- printf("cirrus: outport cr_index %02x, cr_value %02x\n",
- s->vga.cr_index, reg_value);
-#endif
- break;
- }
-}
-
-/***************************************
- *
- * memory-mapped I/O (bitblt)
- *
- ***************************************/
-
-static uint8_t cirrus_mmio_blt_read(CirrusVGAState * s, unsigned address)
-{
- int value = 0xff;
-
- switch (address) {
- case (CIRRUS_MMIO_BLTBGCOLOR + 0):
- value = cirrus_vga_read_gr(s, 0x00);
- break;
- case (CIRRUS_MMIO_BLTBGCOLOR + 1):
- value = cirrus_vga_read_gr(s, 0x10);
- break;
- case (CIRRUS_MMIO_BLTBGCOLOR + 2):
- value = cirrus_vga_read_gr(s, 0x12);
- break;
- case (CIRRUS_MMIO_BLTBGCOLOR + 3):
- value = cirrus_vga_read_gr(s, 0x14);
- break;
- case (CIRRUS_MMIO_BLTFGCOLOR + 0):
- value = cirrus_vga_read_gr(s, 0x01);
- break;
- case (CIRRUS_MMIO_BLTFGCOLOR + 1):
- value = cirrus_vga_read_gr(s, 0x11);
- break;
- case (CIRRUS_MMIO_BLTFGCOLOR + 2):
- value = cirrus_vga_read_gr(s, 0x13);
- break;
- case (CIRRUS_MMIO_BLTFGCOLOR + 3):
- value = cirrus_vga_read_gr(s, 0x15);
- break;
- case (CIRRUS_MMIO_BLTWIDTH + 0):
- value = cirrus_vga_read_gr(s, 0x20);
- break;
- case (CIRRUS_MMIO_BLTWIDTH + 1):
- value = cirrus_vga_read_gr(s, 0x21);
- break;
- case (CIRRUS_MMIO_BLTHEIGHT + 0):
- value = cirrus_vga_read_gr(s, 0x22);
- break;
- case (CIRRUS_MMIO_BLTHEIGHT + 1):
- value = cirrus_vga_read_gr(s, 0x23);
- break;
- case (CIRRUS_MMIO_BLTDESTPITCH + 0):
- value = cirrus_vga_read_gr(s, 0x24);
- break;
- case (CIRRUS_MMIO_BLTDESTPITCH + 1):
- value = cirrus_vga_read_gr(s, 0x25);
- break;
- case (CIRRUS_MMIO_BLTSRCPITCH + 0):
- value = cirrus_vga_read_gr(s, 0x26);
- break;
- case (CIRRUS_MMIO_BLTSRCPITCH + 1):
- value = cirrus_vga_read_gr(s, 0x27);
- break;
- case (CIRRUS_MMIO_BLTDESTADDR + 0):
- value = cirrus_vga_read_gr(s, 0x28);
- break;
- case (CIRRUS_MMIO_BLTDESTADDR + 1):
- value = cirrus_vga_read_gr(s, 0x29);
- break;
- case (CIRRUS_MMIO_BLTDESTADDR + 2):
- value = cirrus_vga_read_gr(s, 0x2a);
- break;
- case (CIRRUS_MMIO_BLTSRCADDR + 0):
- value = cirrus_vga_read_gr(s, 0x2c);
- break;
- case (CIRRUS_MMIO_BLTSRCADDR + 1):
- value = cirrus_vga_read_gr(s, 0x2d);
- break;
- case (CIRRUS_MMIO_BLTSRCADDR + 2):
- value = cirrus_vga_read_gr(s, 0x2e);
- break;
- case CIRRUS_MMIO_BLTWRITEMASK:
- value = cirrus_vga_read_gr(s, 0x2f);
- break;
- case CIRRUS_MMIO_BLTMODE:
- value = cirrus_vga_read_gr(s, 0x30);
- break;
- case CIRRUS_MMIO_BLTROP:
- value = cirrus_vga_read_gr(s, 0x32);
- break;
- case CIRRUS_MMIO_BLTMODEEXT:
- value = cirrus_vga_read_gr(s, 0x33);
- break;
- case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 0):
- value = cirrus_vga_read_gr(s, 0x34);
- break;
- case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 1):
- value = cirrus_vga_read_gr(s, 0x35);
- break;
- case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 0):
- value = cirrus_vga_read_gr(s, 0x38);
- break;
- case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 1):
- value = cirrus_vga_read_gr(s, 0x39);
- break;
- case CIRRUS_MMIO_BLTSTATUS:
- value = cirrus_vga_read_gr(s, 0x31);
- break;
- default:
-#ifdef DEBUG_CIRRUS
- printf("cirrus: mmio read - address 0x%04x\n", address);
-#endif
- break;
- }
-
- return (uint8_t) value;
-}
-
-static void cirrus_mmio_blt_write(CirrusVGAState * s, unsigned address,
- uint8_t value)
-{
- switch (address) {
- case (CIRRUS_MMIO_BLTBGCOLOR + 0):
- cirrus_vga_write_gr(s, 0x00, value);
- break;
- case (CIRRUS_MMIO_BLTBGCOLOR + 1):
- cirrus_vga_write_gr(s, 0x10, value);
- break;
- case (CIRRUS_MMIO_BLTBGCOLOR + 2):
- cirrus_vga_write_gr(s, 0x12, value);
- break;
- case (CIRRUS_MMIO_BLTBGCOLOR + 3):
- cirrus_vga_write_gr(s, 0x14, value);
- break;
- case (CIRRUS_MMIO_BLTFGCOLOR + 0):
- cirrus_vga_write_gr(s, 0x01, value);
- break;
- case (CIRRUS_MMIO_BLTFGCOLOR + 1):
- cirrus_vga_write_gr(s, 0x11, value);
- break;
- case (CIRRUS_MMIO_BLTFGCOLOR + 2):
- cirrus_vga_write_gr(s, 0x13, value);
- break;
- case (CIRRUS_MMIO_BLTFGCOLOR + 3):
- cirrus_vga_write_gr(s, 0x15, value);
- break;
- case (CIRRUS_MMIO_BLTWIDTH + 0):
- cirrus_vga_write_gr(s, 0x20, value);
- break;
- case (CIRRUS_MMIO_BLTWIDTH + 1):
- cirrus_vga_write_gr(s, 0x21, value);
- break;
- case (CIRRUS_MMIO_BLTHEIGHT + 0):
- cirrus_vga_write_gr(s, 0x22, value);
- break;
- case (CIRRUS_MMIO_BLTHEIGHT + 1):
- cirrus_vga_write_gr(s, 0x23, value);
- break;
- case (CIRRUS_MMIO_BLTDESTPITCH + 0):
- cirrus_vga_write_gr(s, 0x24, value);
- break;
- case (CIRRUS_MMIO_BLTDESTPITCH + 1):
- cirrus_vga_write_gr(s, 0x25, value);
- break;
- case (CIRRUS_MMIO_BLTSRCPITCH + 0):
- cirrus_vga_write_gr(s, 0x26, value);
- break;
- case (CIRRUS_MMIO_BLTSRCPITCH + 1):
- cirrus_vga_write_gr(s, 0x27, value);
- break;
- case (CIRRUS_MMIO_BLTDESTADDR + 0):
- cirrus_vga_write_gr(s, 0x28, value);
- break;
- case (CIRRUS_MMIO_BLTDESTADDR + 1):
- cirrus_vga_write_gr(s, 0x29, value);
- break;
- case (CIRRUS_MMIO_BLTDESTADDR + 2):
- cirrus_vga_write_gr(s, 0x2a, value);
- break;
- case (CIRRUS_MMIO_BLTDESTADDR + 3):
- /* ignored */
- break;
- case (CIRRUS_MMIO_BLTSRCADDR + 0):
- cirrus_vga_write_gr(s, 0x2c, value);
- break;
- case (CIRRUS_MMIO_BLTSRCADDR + 1):
- cirrus_vga_write_gr(s, 0x2d, value);
- break;
- case (CIRRUS_MMIO_BLTSRCADDR + 2):
- cirrus_vga_write_gr(s, 0x2e, value);
- break;
- case CIRRUS_MMIO_BLTWRITEMASK:
- cirrus_vga_write_gr(s, 0x2f, value);
- break;
- case CIRRUS_MMIO_BLTMODE:
- cirrus_vga_write_gr(s, 0x30, value);
- break;
- case CIRRUS_MMIO_BLTROP:
- cirrus_vga_write_gr(s, 0x32, value);
- break;
- case CIRRUS_MMIO_BLTMODEEXT:
- cirrus_vga_write_gr(s, 0x33, value);
- break;
- case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 0):
- cirrus_vga_write_gr(s, 0x34, value);
- break;
- case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 1):
- cirrus_vga_write_gr(s, 0x35, value);
- break;
- case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 0):
- cirrus_vga_write_gr(s, 0x38, value);
- break;
- case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 1):
- cirrus_vga_write_gr(s, 0x39, value);
- break;
- case CIRRUS_MMIO_BLTSTATUS:
- cirrus_vga_write_gr(s, 0x31, value);
- break;
- default:
-#ifdef DEBUG_CIRRUS
- printf("cirrus: mmio write - addr 0x%04x val 0x%02x (ignored)\n",
- address, value);
-#endif
- break;
- }
-}
-
-/***************************************
- *
- * write mode 4/5
- *
- ***************************************/
-
-static void cirrus_mem_writeb_mode4and5_8bpp(CirrusVGAState * s,
- unsigned mode,
- unsigned offset,
- uint32_t mem_value)
-{
- int x;
- unsigned val = mem_value;
- uint8_t *dst;
-
- dst = s->vga.vram_ptr + (offset &= s->cirrus_addr_mask);
- for (x = 0; x < 8; x++) {
- if (val & 0x80) {
- *dst = s->cirrus_shadow_gr1;
- } else if (mode == 5) {
- *dst = s->cirrus_shadow_gr0;
- }
- val <<= 1;
- dst++;
- }
- memory_region_set_dirty(&s->vga.vram, offset, 8);
-}
-
-static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s,
- unsigned mode,
- unsigned offset,
- uint32_t mem_value)
-{
- int x;
- unsigned val = mem_value;
- uint8_t *dst;
-
- dst = s->vga.vram_ptr + (offset &= s->cirrus_addr_mask);
- for (x = 0; x < 8; x++) {
- if (val & 0x80) {
- *dst = s->cirrus_shadow_gr1;
- *(dst + 1) = s->vga.gr[0x11];
- } else if (mode == 5) {
- *dst = s->cirrus_shadow_gr0;
- *(dst + 1) = s->vga.gr[0x10];
- }
- val <<= 1;
- dst += 2;
- }
- memory_region_set_dirty(&s->vga.vram, offset, 16);
-}
-
-/***************************************
- *
- * memory access between 0xa0000-0xbffff
- *
- ***************************************/
-
-static uint64_t cirrus_vga_mem_read(void *opaque,
- hwaddr addr,
- uint32_t size)
-{
- CirrusVGAState *s = opaque;
- unsigned bank_index;
- unsigned bank_offset;
- uint32_t val;
-
- if ((s->vga.sr[0x07] & 0x01) == 0) {
- return vga_mem_readb(&s->vga, addr);
- }
-
- if (addr < 0x10000) {
- /* XXX handle bitblt */
- /* video memory */
- bank_index = addr >> 15;
- bank_offset = addr & 0x7fff;
- if (bank_offset < s->cirrus_bank_limit[bank_index]) {
- bank_offset += s->cirrus_bank_base[bank_index];
- if ((s->vga.gr[0x0B] & 0x14) == 0x14) {
- bank_offset <<= 4;
- } else if (s->vga.gr[0x0B] & 0x02) {
- bank_offset <<= 3;
- }
- bank_offset &= s->cirrus_addr_mask;
- val = *(s->vga.vram_ptr + bank_offset);
- } else
- val = 0xff;
- } else if (addr >= 0x18000 && addr < 0x18100) {
- /* memory-mapped I/O */
- val = 0xff;
- if ((s->vga.sr[0x17] & 0x44) == 0x04) {
- val = cirrus_mmio_blt_read(s, addr & 0xff);
- }
- } else {
- val = 0xff;
-#ifdef DEBUG_CIRRUS
- printf("cirrus: mem_readb " TARGET_FMT_plx "\n", addr);
-#endif
- }
- return val;
-}
-
-static void cirrus_vga_mem_write(void *opaque,
- hwaddr addr,
- uint64_t mem_value,
- uint32_t size)
-{
- CirrusVGAState *s = opaque;
- unsigned bank_index;
- unsigned bank_offset;
- unsigned mode;
-
- if ((s->vga.sr[0x07] & 0x01) == 0) {
- vga_mem_writeb(&s->vga, addr, mem_value);
- return;
- }
-
- if (addr < 0x10000) {
- if (s->cirrus_srcptr != s->cirrus_srcptr_end) {
- /* bitblt */
- *s->cirrus_srcptr++ = (uint8_t) mem_value;
- if (s->cirrus_srcptr >= s->cirrus_srcptr_end) {
- cirrus_bitblt_cputovideo_next(s);
- }
- } else {
- /* video memory */
- bank_index = addr >> 15;
- bank_offset = addr & 0x7fff;
- if (bank_offset < s->cirrus_bank_limit[bank_index]) {
- bank_offset += s->cirrus_bank_base[bank_index];
- if ((s->vga.gr[0x0B] & 0x14) == 0x14) {
- bank_offset <<= 4;
- } else if (s->vga.gr[0x0B] & 0x02) {
- bank_offset <<= 3;
- }
- bank_offset &= s->cirrus_addr_mask;
- mode = s->vga.gr[0x05] & 0x7;
- if (mode < 4 || mode > 5 || ((s->vga.gr[0x0B] & 0x4) == 0)) {
- *(s->vga.vram_ptr + bank_offset) = mem_value;
- memory_region_set_dirty(&s->vga.vram, bank_offset,
- sizeof(mem_value));
- } else {
- if ((s->vga.gr[0x0B] & 0x14) != 0x14) {
- cirrus_mem_writeb_mode4and5_8bpp(s, mode,
- bank_offset,
- mem_value);
- } else {
- cirrus_mem_writeb_mode4and5_16bpp(s, mode,
- bank_offset,
- mem_value);
- }
- }
- }
- }
- } else if (addr >= 0x18000 && addr < 0x18100) {
- /* memory-mapped I/O */
- if ((s->vga.sr[0x17] & 0x44) == 0x04) {
- cirrus_mmio_blt_write(s, addr & 0xff, mem_value);
- }
- } else {
-#ifdef DEBUG_CIRRUS
- printf("cirrus: mem_writeb " TARGET_FMT_plx " value 0x%02" PRIu64 "\n", addr,
- mem_value);
-#endif
- }
-}
-
-static const MemoryRegionOps cirrus_vga_mem_ops = {
- .read = cirrus_vga_mem_read,
- .write = cirrus_vga_mem_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
-};
-
-/***************************************
- *
- * hardware cursor
- *
- ***************************************/
-
-static inline void invalidate_cursor1(CirrusVGAState *s)
-{
- if (s->last_hw_cursor_size) {
- vga_invalidate_scanlines(&s->vga,
- s->last_hw_cursor_y + s->last_hw_cursor_y_start,
- s->last_hw_cursor_y + s->last_hw_cursor_y_end);
- }
-}
-
-static inline void cirrus_cursor_compute_yrange(CirrusVGAState *s)
-{
- const uint8_t *src;
- uint32_t content;
- int y, y_min, y_max;
-
- src = s->vga.vram_ptr + s->real_vram_size - 16 * 1024;
- if (s->vga.sr[0x12] & CIRRUS_CURSOR_LARGE) {
- src += (s->vga.sr[0x13] & 0x3c) * 256;
- y_min = 64;
- y_max = -1;
- for(y = 0; y < 64; y++) {
- content = ((uint32_t *)src)[0] |
- ((uint32_t *)src)[1] |
- ((uint32_t *)src)[2] |
- ((uint32_t *)src)[3];
- if (content) {
- if (y < y_min)
- y_min = y;
- if (y > y_max)
- y_max = y;
- }
- src += 16;
- }
- } else {
- src += (s->vga.sr[0x13] & 0x3f) * 256;
- y_min = 32;
- y_max = -1;
- for(y = 0; y < 32; y++) {
- content = ((uint32_t *)src)[0] |
- ((uint32_t *)(src + 128))[0];
- if (content) {
- if (y < y_min)
- y_min = y;
- if (y > y_max)
- y_max = y;
- }
- src += 4;
- }
- }
- if (y_min > y_max) {
- s->last_hw_cursor_y_start = 0;
- s->last_hw_cursor_y_end = 0;
- } else {
- s->last_hw_cursor_y_start = y_min;
- s->last_hw_cursor_y_end = y_max + 1;
- }
-}
-
-/* NOTE: we do not currently handle the cursor bitmap change, so we
- update the cursor only if it moves. */
-static void cirrus_cursor_invalidate(VGACommonState *s1)
-{
- CirrusVGAState *s = container_of(s1, CirrusVGAState, vga);
- int size;
-
- if (!(s->vga.sr[0x12] & CIRRUS_CURSOR_SHOW)) {
- size = 0;
- } else {
- if (s->vga.sr[0x12] & CIRRUS_CURSOR_LARGE)
- size = 64;
- else
- size = 32;
- }
- /* invalidate last cursor and new cursor if any change */
- if (s->last_hw_cursor_size != size ||
- s->last_hw_cursor_x != s->vga.hw_cursor_x ||
- s->last_hw_cursor_y != s->vga.hw_cursor_y) {
-
- invalidate_cursor1(s);
-
- s->last_hw_cursor_size = size;
- s->last_hw_cursor_x = s->vga.hw_cursor_x;
- s->last_hw_cursor_y = s->vga.hw_cursor_y;
- /* compute the real cursor min and max y */
- cirrus_cursor_compute_yrange(s);
- invalidate_cursor1(s);
- }
-}
-
-static void vga_draw_cursor_line(uint8_t *d1,
- const uint8_t *src1,
- int poffset, int w,
- unsigned int color0,
- unsigned int color1,
- unsigned int color_xor)
-{
- const uint8_t *plane0, *plane1;
- int x, b0, b1;
- uint8_t *d;
-
- d = d1;
- plane0 = src1;
- plane1 = src1 + poffset;
- for (x = 0; x < w; x++) {
- b0 = (plane0[x >> 3] >> (7 - (x & 7))) & 1;
- b1 = (plane1[x >> 3] >> (7 - (x & 7))) & 1;
- switch (b0 | (b1 << 1)) {
- case 0:
- break;
- case 1:
- ((uint32_t *)d)[0] ^= color_xor;
- break;
- case 2:
- ((uint32_t *)d)[0] = color0;
- break;
- case 3:
- ((uint32_t *)d)[0] = color1;
- break;
- }
- d += 4;
- }
-}
-
-static void cirrus_cursor_draw_line(VGACommonState *s1, uint8_t *d1, int scr_y)
-{
- CirrusVGAState *s = container_of(s1, CirrusVGAState, vga);
- int w, h, x1, x2, poffset;
- unsigned int color0, color1;
- const uint8_t *palette, *src;
- uint32_t content;
-
- if (!(s->vga.sr[0x12] & CIRRUS_CURSOR_SHOW))
- return;
- /* fast test to see if the cursor intersects with the scan line */
- if (s->vga.sr[0x12] & CIRRUS_CURSOR_LARGE) {
- h = 64;
- } else {
- h = 32;
- }
- if (scr_y < s->vga.hw_cursor_y ||
- scr_y >= (s->vga.hw_cursor_y + h)) {
- return;
- }
-
- src = s->vga.vram_ptr + s->real_vram_size - 16 * 1024;
- if (s->vga.sr[0x12] & CIRRUS_CURSOR_LARGE) {
- src += (s->vga.sr[0x13] & 0x3c) * 256;
- src += (scr_y - s->vga.hw_cursor_y) * 16;
- poffset = 8;
- content = ((uint32_t *)src)[0] |
- ((uint32_t *)src)[1] |
- ((uint32_t *)src)[2] |
- ((uint32_t *)src)[3];
- } else {
- src += (s->vga.sr[0x13] & 0x3f) * 256;
- src += (scr_y - s->vga.hw_cursor_y) * 4;
-
-
- poffset = 128;
- content = ((uint32_t *)src)[0] |
- ((uint32_t *)(src + 128))[0];
- }
- /* if nothing to draw, no need to continue */
- if (!content)
- return;
- w = h;
-
- x1 = s->vga.hw_cursor_x;
- if (x1 >= s->vga.last_scr_width)
- return;
- x2 = s->vga.hw_cursor_x + w;
- if (x2 > s->vga.last_scr_width)
- x2 = s->vga.last_scr_width;
- w = x2 - x1;
- palette = s->cirrus_hidden_palette;
- color0 = rgb_to_pixel32(c6_to_8(palette[0x0 * 3]),
- c6_to_8(palette[0x0 * 3 + 1]),
- c6_to_8(palette[0x0 * 3 + 2]));
- color1 = rgb_to_pixel32(c6_to_8(palette[0xf * 3]),
- c6_to_8(palette[0xf * 3 + 1]),
- c6_to_8(palette[0xf * 3 + 2]));
- d1 += x1 * 4;
- vga_draw_cursor_line(d1, src, poffset, w, color0, color1, 0xffffff);
-}
-
-/***************************************
- *
- * LFB memory access
- *
- ***************************************/
-
-static uint64_t cirrus_linear_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- CirrusVGAState *s = opaque;
- uint32_t ret;
-
- addr &= s->cirrus_addr_mask;
-
- if (((s->vga.sr[0x17] & 0x44) == 0x44) &&
- ((addr & s->linear_mmio_mask) == s->linear_mmio_mask)) {
- /* memory-mapped I/O */
- ret = cirrus_mmio_blt_read(s, addr & 0xff);
- } else if (0) {
- /* XXX handle bitblt */
- ret = 0xff;
- } else {
- /* video memory */
- if ((s->vga.gr[0x0B] & 0x14) == 0x14) {
- addr <<= 4;
- } else if (s->vga.gr[0x0B] & 0x02) {
- addr <<= 3;
- }
- addr &= s->cirrus_addr_mask;
- ret = *(s->vga.vram_ptr + addr);
- }
-
- return ret;
-}
-
-static void cirrus_linear_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- CirrusVGAState *s = opaque;
- unsigned mode;
-
- addr &= s->cirrus_addr_mask;
-
- if (((s->vga.sr[0x17] & 0x44) == 0x44) &&
- ((addr & s->linear_mmio_mask) == s->linear_mmio_mask)) {
- /* memory-mapped I/O */
- cirrus_mmio_blt_write(s, addr & 0xff, val);
- } else if (s->cirrus_srcptr != s->cirrus_srcptr_end) {
- /* bitblt */
- *s->cirrus_srcptr++ = (uint8_t) val;
- if (s->cirrus_srcptr >= s->cirrus_srcptr_end) {
- cirrus_bitblt_cputovideo_next(s);
- }
- } else {
- /* video memory */
- if ((s->vga.gr[0x0B] & 0x14) == 0x14) {
- addr <<= 4;
- } else if (s->vga.gr[0x0B] & 0x02) {
- addr <<= 3;
- }
- addr &= s->cirrus_addr_mask;
-
- mode = s->vga.gr[0x05] & 0x7;
- if (mode < 4 || mode > 5 || ((s->vga.gr[0x0B] & 0x4) == 0)) {
- *(s->vga.vram_ptr + addr) = (uint8_t) val;
- memory_region_set_dirty(&s->vga.vram, addr, 1);
- } else {
- if ((s->vga.gr[0x0B] & 0x14) != 0x14) {
- cirrus_mem_writeb_mode4and5_8bpp(s, mode, addr, val);
- } else {
- cirrus_mem_writeb_mode4and5_16bpp(s, mode, addr, val);
- }
- }
- }
-}
-
-/***************************************
- *
- * system to screen memory access
- *
- ***************************************/
-
-
-static uint64_t cirrus_linear_bitblt_read(void *opaque,
- hwaddr addr,
- unsigned size)
-{
- CirrusVGAState *s = opaque;
- uint32_t ret;
-
- /* XXX handle bitblt */
- (void)s;
- ret = 0xff;
- return ret;
-}
-
-static void cirrus_linear_bitblt_write(void *opaque,
- hwaddr addr,
- uint64_t val,
- unsigned size)
-{
- CirrusVGAState *s = opaque;
-
- if (s->cirrus_srcptr != s->cirrus_srcptr_end) {
- /* bitblt */
- *s->cirrus_srcptr++ = (uint8_t) val;
- if (s->cirrus_srcptr >= s->cirrus_srcptr_end) {
- cirrus_bitblt_cputovideo_next(s);
- }
- }
-}
-
-static const MemoryRegionOps cirrus_linear_bitblt_io_ops = {
- .read = cirrus_linear_bitblt_read,
- .write = cirrus_linear_bitblt_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
-};
-
-static void map_linear_vram_bank(CirrusVGAState *s, unsigned bank)
-{
- MemoryRegion *mr = &s->cirrus_bank[bank];
- bool enabled = !(s->cirrus_srcptr != s->cirrus_srcptr_end)
- && !((s->vga.sr[0x07] & 0x01) == 0)
- && !((s->vga.gr[0x0B] & 0x14) == 0x14)
- && !(s->vga.gr[0x0B] & 0x02);
-
- memory_region_set_enabled(mr, enabled);
- memory_region_set_alias_offset(mr, s->cirrus_bank_base[bank]);
-}
-
-static void map_linear_vram(CirrusVGAState *s)
-{
- if (s->bustype == CIRRUS_BUSTYPE_PCI && !s->linear_vram) {
- s->linear_vram = true;
- memory_region_add_subregion_overlap(&s->pci_bar, 0, &s->vga.vram, 1);
- }
- map_linear_vram_bank(s, 0);
- map_linear_vram_bank(s, 1);
-}
-
-static void unmap_linear_vram(CirrusVGAState *s)
-{
- if (s->bustype == CIRRUS_BUSTYPE_PCI && s->linear_vram) {
- s->linear_vram = false;
- memory_region_del_subregion(&s->pci_bar, &s->vga.vram);
- }
- memory_region_set_enabled(&s->cirrus_bank[0], false);
- memory_region_set_enabled(&s->cirrus_bank[1], false);
-}
-
-/* Compute the memory access functions */
-static void cirrus_update_memory_access(CirrusVGAState *s)
-{
- unsigned mode;
-
- memory_region_transaction_begin();
- if ((s->vga.sr[0x17] & 0x44) == 0x44) {
- goto generic_io;
- } else if (s->cirrus_srcptr != s->cirrus_srcptr_end) {
- goto generic_io;
- } else {
- if ((s->vga.gr[0x0B] & 0x14) == 0x14) {
- goto generic_io;
- } else if (s->vga.gr[0x0B] & 0x02) {
- goto generic_io;
- }
-
- mode = s->vga.gr[0x05] & 0x7;
- if (mode < 4 || mode > 5 || ((s->vga.gr[0x0B] & 0x4) == 0)) {
- map_linear_vram(s);
- } else {
- generic_io:
- unmap_linear_vram(s);
- }
- }
- memory_region_transaction_commit();
-}
-
-
-/* I/O ports */
-
-static uint64_t cirrus_vga_ioport_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- CirrusVGAState *c = opaque;
- VGACommonState *s = &c->vga;
- int val, index;
-
- addr += 0x3b0;
-
- if (vga_ioport_invalid(s, addr)) {
- val = 0xff;
- } else {
- switch (addr) {
- case 0x3c0:
- if (s->ar_flip_flop == 0) {
- val = s->ar_index;
- } else {
- val = 0;
- }
- break;
- case 0x3c1:
- index = s->ar_index & 0x1f;
- if (index < 21)
- val = s->ar[index];
- else
- val = 0;
- break;
- case 0x3c2:
- val = s->st00;
- break;
- case 0x3c4:
- val = s->sr_index;
- break;
- case 0x3c5:
- val = cirrus_vga_read_sr(c);
- break;
-#ifdef DEBUG_VGA_REG
- printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
-#endif
- break;
- case 0x3c6:
- val = cirrus_read_hidden_dac(c);
- break;
- case 0x3c7:
- val = s->dac_state;
- break;
- case 0x3c8:
- val = s->dac_write_index;
- c->cirrus_hidden_dac_lockindex = 0;
- break;
- case 0x3c9:
- val = cirrus_vga_read_palette(c);
- break;
- case 0x3ca:
- val = s->fcr;
- break;
- case 0x3cc:
- val = s->msr;
- break;
- case 0x3ce:
- val = s->gr_index;
- break;
- case 0x3cf:
- val = cirrus_vga_read_gr(c, s->gr_index);
-#ifdef DEBUG_VGA_REG
- printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
-#endif
- break;
- case 0x3b4:
- case 0x3d4:
- val = s->cr_index;
- break;
- case 0x3b5:
- case 0x3d5:
- val = cirrus_vga_read_cr(c, s->cr_index);
-#ifdef DEBUG_VGA_REG
- printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
-#endif
- break;
- case 0x3ba:
- case 0x3da:
- /* just toggle to fool polling */
- val = s->st01 = s->retrace(s);
- s->ar_flip_flop = 0;
- break;
- default:
- val = 0x00;
- break;
- }
- }
-#if defined(DEBUG_VGA)
- printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
-#endif
- return val;
-}
-
-static void cirrus_vga_ioport_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned size)
-{
- CirrusVGAState *c = opaque;
- VGACommonState *s = &c->vga;
- int index;
-
- addr += 0x3b0;
-
- /* check port range access depending on color/monochrome mode */
- if (vga_ioport_invalid(s, addr)) {
- return;
- }
-#ifdef DEBUG_VGA
- printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
-#endif
-
- switch (addr) {
- case 0x3c0:
- if (s->ar_flip_flop == 0) {
- val &= 0x3f;
- s->ar_index = val;
- } else {
- index = s->ar_index & 0x1f;
- switch (index) {
- case 0x00 ... 0x0f:
- s->ar[index] = val & 0x3f;
- break;
- case 0x10:
- s->ar[index] = val & ~0x10;
- break;
- case 0x11:
- s->ar[index] = val;
- break;
- case 0x12:
- s->ar[index] = val & ~0xc0;
- break;
- case 0x13:
- s->ar[index] = val & ~0xf0;
- break;
- case 0x14:
- s->ar[index] = val & ~0xf0;
- break;
- default:
- break;
- }
- }
- s->ar_flip_flop ^= 1;
- break;
- case 0x3c2:
- s->msr = val & ~0x10;
- s->update_retrace_info(s);
- break;
- case 0x3c4:
- s->sr_index = val;
- break;
- case 0x3c5:
-#ifdef DEBUG_VGA_REG
- printf("vga: write SR%x = 0x%02" PRIu64 "\n", s->sr_index, val);
-#endif
- cirrus_vga_write_sr(c, val);
- break;
- case 0x3c6:
- cirrus_write_hidden_dac(c, val);
- break;
- case 0x3c7:
- s->dac_read_index = val;
- s->dac_sub_index = 0;
- s->dac_state = 3;
- break;
- case 0x3c8:
- s->dac_write_index = val;
- s->dac_sub_index = 0;
- s->dac_state = 0;
- break;
- case 0x3c9:
- cirrus_vga_write_palette(c, val);
- break;
- case 0x3ce:
- s->gr_index = val;
- break;
- case 0x3cf:
-#ifdef DEBUG_VGA_REG
- printf("vga: write GR%x = 0x%02" PRIu64 "\n", s->gr_index, val);
-#endif
- cirrus_vga_write_gr(c, s->gr_index, val);
- break;
- case 0x3b4:
- case 0x3d4:
- s->cr_index = val;
- break;
- case 0x3b5:
- case 0x3d5:
-#ifdef DEBUG_VGA_REG
- printf("vga: write CR%x = 0x%02"PRIu64"\n", s->cr_index, val);
-#endif
- cirrus_vga_write_cr(c, val);
- break;
- case 0x3ba:
- case 0x3da:
- s->fcr = val & 0x10;
- break;
- }
-}
-
-/***************************************
- *
- * memory-mapped I/O access
- *
- ***************************************/
-
-static uint64_t cirrus_mmio_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- CirrusVGAState *s = opaque;
-
- if (addr >= 0x100) {
- return cirrus_mmio_blt_read(s, addr - 0x100);
- } else {
- return cirrus_vga_ioport_read(s, addr + 0x10, size);
- }
-}
-
-static void cirrus_mmio_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- CirrusVGAState *s = opaque;
-
- if (addr >= 0x100) {
- cirrus_mmio_blt_write(s, addr - 0x100, val);
- } else {
- cirrus_vga_ioport_write(s, addr + 0x10, val, size);
- }
-}
-
-static const MemoryRegionOps cirrus_mmio_io_ops = {
- .read = cirrus_mmio_read,
- .write = cirrus_mmio_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
-};
-
-/* load/save state */
-
-static int cirrus_post_load(void *opaque, int version_id)
-{
- CirrusVGAState *s = opaque;
-
- s->vga.gr[0x00] = s->cirrus_shadow_gr0 & 0x0f;
- s->vga.gr[0x01] = s->cirrus_shadow_gr1 & 0x0f;
-
- cirrus_update_memory_access(s);
- /* force refresh */
- s->vga.graphic_mode = -1;
- cirrus_update_bank_ptr(s, 0);
- cirrus_update_bank_ptr(s, 1);
- return 0;
-}
-
-static const VMStateDescription vmstate_cirrus_vga = {
- .name = "cirrus_vga",
- .version_id = 2,
- .minimum_version_id = 1,
- .post_load = cirrus_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(vga.latch, CirrusVGAState),
- VMSTATE_UINT8(vga.sr_index, CirrusVGAState),
- VMSTATE_BUFFER(vga.sr, CirrusVGAState),
- VMSTATE_UINT8(vga.gr_index, CirrusVGAState),
- VMSTATE_UINT8(cirrus_shadow_gr0, CirrusVGAState),
- VMSTATE_UINT8(cirrus_shadow_gr1, CirrusVGAState),
- VMSTATE_BUFFER_START_MIDDLE(vga.gr, CirrusVGAState, 2),
- VMSTATE_UINT8(vga.ar_index, CirrusVGAState),
- VMSTATE_BUFFER(vga.ar, CirrusVGAState),
- VMSTATE_INT32(vga.ar_flip_flop, CirrusVGAState),
- VMSTATE_UINT8(vga.cr_index, CirrusVGAState),
- VMSTATE_BUFFER(vga.cr, CirrusVGAState),
- VMSTATE_UINT8(vga.msr, CirrusVGAState),
- VMSTATE_UINT8(vga.fcr, CirrusVGAState),
- VMSTATE_UINT8(vga.st00, CirrusVGAState),
- VMSTATE_UINT8(vga.st01, CirrusVGAState),
- VMSTATE_UINT8(vga.dac_state, CirrusVGAState),
- VMSTATE_UINT8(vga.dac_sub_index, CirrusVGAState),
- VMSTATE_UINT8(vga.dac_read_index, CirrusVGAState),
- VMSTATE_UINT8(vga.dac_write_index, CirrusVGAState),
- VMSTATE_BUFFER(vga.dac_cache, CirrusVGAState),
- VMSTATE_BUFFER(vga.palette, CirrusVGAState),
- VMSTATE_INT32(vga.bank_offset, CirrusVGAState),
- VMSTATE_UINT8(cirrus_hidden_dac_lockindex, CirrusVGAState),
- VMSTATE_UINT8(cirrus_hidden_dac_data, CirrusVGAState),
- VMSTATE_UINT32(vga.hw_cursor_x, CirrusVGAState),
- VMSTATE_UINT32(vga.hw_cursor_y, CirrusVGAState),
- /* XXX: we do not save the bitblt state - we assume we do not save
- the state when the blitter is active */
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_pci_cirrus_vga = {
- .name = "cirrus_vga",
- .version_id = 2,
- .minimum_version_id = 2,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(dev, PCICirrusVGAState),
- VMSTATE_STRUCT(cirrus_vga, PCICirrusVGAState, 0,
- vmstate_cirrus_vga, CirrusVGAState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-/***************************************
- *
- * initialize
- *
- ***************************************/
-
-static void cirrus_reset(void *opaque)
-{
- CirrusVGAState *s = opaque;
-
- vga_common_reset(&s->vga);
- unmap_linear_vram(s);
- s->vga.sr[0x06] = 0x0f;
- if (s->device_id == CIRRUS_ID_CLGD5446) {
- /* 4MB 64 bit memory config, always PCI */
- s->vga.sr[0x1F] = 0x2d; // MemClock
- s->vga.gr[0x18] = 0x0f; // fastest memory configuration
- s->vga.sr[0x0f] = 0x98;
- s->vga.sr[0x17] = 0x20;
- s->vga.sr[0x15] = 0x04; /* memory size, 3=2MB, 4=4MB */
- } else {
- s->vga.sr[0x1F] = 0x22; // MemClock
- s->vga.sr[0x0F] = CIRRUS_MEMSIZE_2M;
- s->vga.sr[0x17] = s->bustype;
- s->vga.sr[0x15] = 0x03; /* memory size, 3=2MB, 4=4MB */
- }
- s->vga.cr[0x27] = s->device_id;
-
- s->cirrus_hidden_dac_lockindex = 5;
- s->cirrus_hidden_dac_data = 0;
-}
-
-static const MemoryRegionOps cirrus_linear_io_ops = {
- .read = cirrus_linear_read,
- .write = cirrus_linear_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
-};
-
-static const MemoryRegionOps cirrus_vga_io_ops = {
- .read = cirrus_vga_ioport_read,
- .write = cirrus_vga_ioport_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
-};
-
-static void cirrus_init_common(CirrusVGAState *s, Object *owner,
- int device_id, int is_pci,
- MemoryRegion *system_memory,
- MemoryRegion *system_io)
-{
- int i;
- static int inited;
-
- if (!inited) {
- inited = 1;
- for(i = 0;i < 256; i++)
- rop_to_index[i] = CIRRUS_ROP_NOP_INDEX; /* nop rop */
- rop_to_index[CIRRUS_ROP_0] = 0;
- rop_to_index[CIRRUS_ROP_SRC_AND_DST] = 1;
- rop_to_index[CIRRUS_ROP_NOP] = 2;
- rop_to_index[CIRRUS_ROP_SRC_AND_NOTDST] = 3;
- rop_to_index[CIRRUS_ROP_NOTDST] = 4;
- rop_to_index[CIRRUS_ROP_SRC] = 5;
- rop_to_index[CIRRUS_ROP_1] = 6;
- rop_to_index[CIRRUS_ROP_NOTSRC_AND_DST] = 7;
- rop_to_index[CIRRUS_ROP_SRC_XOR_DST] = 8;
- rop_to_index[CIRRUS_ROP_SRC_OR_DST] = 9;
- rop_to_index[CIRRUS_ROP_NOTSRC_OR_NOTDST] = 10;
- rop_to_index[CIRRUS_ROP_SRC_NOTXOR_DST] = 11;
- rop_to_index[CIRRUS_ROP_SRC_OR_NOTDST] = 12;
- rop_to_index[CIRRUS_ROP_NOTSRC] = 13;
- rop_to_index[CIRRUS_ROP_NOTSRC_OR_DST] = 14;
- rop_to_index[CIRRUS_ROP_NOTSRC_AND_NOTDST] = 15;
- s->device_id = device_id;
- if (is_pci)
- s->bustype = CIRRUS_BUSTYPE_PCI;
- else
- s->bustype = CIRRUS_BUSTYPE_ISA;
- }
-
- /* Register ioport 0x3b0 - 0x3df */
- memory_region_init_io(&s->cirrus_vga_io, owner, &cirrus_vga_io_ops, s,
- "cirrus-io", 0x30);
- memory_region_set_flush_coalesced(&s->cirrus_vga_io);
- memory_region_add_subregion(system_io, 0x3b0, &s->cirrus_vga_io);
-
- memory_region_init(&s->low_mem_container, owner,
- "cirrus-lowmem-container",
- 0x20000);
-
- memory_region_init_io(&s->low_mem, owner, &cirrus_vga_mem_ops, s,
- "cirrus-low-memory", 0x20000);
- memory_region_add_subregion(&s->low_mem_container, 0, &s->low_mem);
- for (i = 0; i < 2; ++i) {
- static const char *names[] = { "vga.bank0", "vga.bank1" };
- MemoryRegion *bank = &s->cirrus_bank[i];
- memory_region_init_alias(bank, owner, names[i], &s->vga.vram,
- 0, 0x8000);
- memory_region_set_enabled(bank, false);
- memory_region_add_subregion_overlap(&s->low_mem_container, i * 0x8000,
- bank, 1);
- }
- memory_region_add_subregion_overlap(system_memory,
- 0x000a0000,
- &s->low_mem_container,
- 1);
- memory_region_set_coalescing(&s->low_mem);
-
- /* I/O handler for LFB */
- memory_region_init_io(&s->cirrus_linear_io, owner, &cirrus_linear_io_ops, s,
- "cirrus-linear-io", s->vga.vram_size_mb
- * 1024 * 1024);
- memory_region_set_flush_coalesced(&s->cirrus_linear_io);
-
- /* I/O handler for LFB */
- memory_region_init_io(&s->cirrus_linear_bitblt_io, owner,
- &cirrus_linear_bitblt_io_ops,
- s,
- "cirrus-bitblt-mmio",
- 0x400000);
- memory_region_set_flush_coalesced(&s->cirrus_linear_bitblt_io);
-
- /* I/O handler for memory-mapped I/O */
- memory_region_init_io(&s->cirrus_mmio_io, owner, &cirrus_mmio_io_ops, s,
- "cirrus-mmio", CIRRUS_PNPMMIO_SIZE);
- memory_region_set_flush_coalesced(&s->cirrus_mmio_io);
-
- s->real_vram_size =
- (s->device_id == CIRRUS_ID_CLGD5446) ? 4096 * 1024 : 2048 * 1024;
-
- /* XXX: s->vga.vram_size must be a power of two */
- s->cirrus_addr_mask = s->real_vram_size - 1;
- s->linear_mmio_mask = s->real_vram_size - 256;
-
- s->vga.get_bpp = cirrus_get_bpp;
- s->vga.get_offsets = cirrus_get_offsets;
- s->vga.get_resolution = cirrus_get_resolution;
- s->vga.cursor_invalidate = cirrus_cursor_invalidate;
- s->vga.cursor_draw_line = cirrus_cursor_draw_line;
-
- qemu_register_reset(cirrus_reset, s);
-}
-
-/***************************************
- *
- * ISA bus support
- *
- ***************************************/
-
-static void isa_cirrus_vga_realizefn(DeviceState *dev, Error **errp)
-{
- ISADevice *isadev = ISA_DEVICE(dev);
- ISACirrusVGAState *d = ISA_CIRRUS_VGA(dev);
- VGACommonState *s = &d->cirrus_vga.vga;
-
- /* follow real hardware, cirrus card emulated has 4 MB video memory.
- Also accept 8 MB/16 MB for backward compatibility. */
- if (s->vram_size_mb != 4 && s->vram_size_mb != 8 &&
- s->vram_size_mb != 16) {
- error_setg(errp, "Invalid cirrus_vga ram size '%u'",
- s->vram_size_mb);
- return;
- }
- vga_common_init(s, OBJECT(dev), true);
- cirrus_init_common(&d->cirrus_vga, OBJECT(dev), CIRRUS_ID_CLGD5430, 0,
- isa_address_space(isadev),
- isa_address_space_io(isadev));
- s->con = graphic_console_init(dev, 0, s->hw_ops, s);
- rom_add_vga(VGABIOS_CIRRUS_FILENAME);
- /* XXX ISA-LFB support */
- /* FIXME not qdev yet */
-}
-
-static Property isa_cirrus_vga_properties[] = {
- DEFINE_PROP_UINT32("vgamem_mb", struct ISACirrusVGAState,
- cirrus_vga.vga.vram_size_mb, 8),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void isa_cirrus_vga_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->vmsd = &vmstate_cirrus_vga;
- dc->realize = isa_cirrus_vga_realizefn;
- dc->props = isa_cirrus_vga_properties;
- set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
-}
-
-static const TypeInfo isa_cirrus_vga_info = {
- .name = TYPE_ISA_CIRRUS_VGA,
- .parent = TYPE_ISA_DEVICE,
- .instance_size = sizeof(ISACirrusVGAState),
- .class_init = isa_cirrus_vga_class_init,
-};
-
-/***************************************
- *
- * PCI bus support
- *
- ***************************************/
-
-static void pci_cirrus_vga_realize(PCIDevice *dev, Error **errp)
-{
- PCICirrusVGAState *d = PCI_CIRRUS_VGA(dev);
- CirrusVGAState *s = &d->cirrus_vga;
- PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
- int16_t device_id = pc->device_id;
-
- /* follow real hardware, cirrus card emulated has 4 MB video memory.
- Also accept 8 MB/16 MB for backward compatibility. */
- if (s->vga.vram_size_mb != 4 && s->vga.vram_size_mb != 8 &&
- s->vga.vram_size_mb != 16) {
- error_setg(errp, "Invalid cirrus_vga ram size '%u'",
- s->vga.vram_size_mb);
- return;
- }
- /* setup VGA */
- vga_common_init(&s->vga, OBJECT(dev), true);
- cirrus_init_common(s, OBJECT(dev), device_id, 1, pci_address_space(dev),
- pci_address_space_io(dev));
- s->vga.con = graphic_console_init(DEVICE(dev), 0, s->vga.hw_ops, &s->vga);
-
- /* setup PCI */
-
- memory_region_init(&s->pci_bar, OBJECT(dev), "cirrus-pci-bar0", 0x2000000);
-
- /* XXX: add byte swapping apertures */
- memory_region_add_subregion(&s->pci_bar, 0, &s->cirrus_linear_io);
- memory_region_add_subregion(&s->pci_bar, 0x1000000,
- &s->cirrus_linear_bitblt_io);
-
- /* setup memory space */
- /* memory #0 LFB */
- /* memory #1 memory-mapped I/O */
- /* XXX: s->vga.vram_size must be a power of two */
- pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->pci_bar);
- if (device_id == CIRRUS_ID_CLGD5446) {
- pci_register_bar(&d->dev, 1, 0, &s->cirrus_mmio_io);
- }
-}
-
-static Property pci_vga_cirrus_properties[] = {
- DEFINE_PROP_UINT32("vgamem_mb", struct PCICirrusVGAState,
- cirrus_vga.vga.vram_size_mb, 8),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void cirrus_vga_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = pci_cirrus_vga_realize;
- k->romfile = VGABIOS_CIRRUS_FILENAME;
- k->vendor_id = PCI_VENDOR_ID_CIRRUS;
- k->device_id = CIRRUS_ID_CLGD5446;
- k->class_id = PCI_CLASS_DISPLAY_VGA;
- set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
- dc->desc = "Cirrus CLGD 54xx VGA";
- dc->vmsd = &vmstate_pci_cirrus_vga;
- dc->props = pci_vga_cirrus_properties;
- dc->hotpluggable = false;
-}
-
-static const TypeInfo cirrus_vga_info = {
- .name = TYPE_PCI_CIRRUS_VGA,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(PCICirrusVGAState),
- .class_init = cirrus_vga_class_init,
-};
-
-static void cirrus_vga_register_types(void)
-{
- type_register_static(&isa_cirrus_vga_info);
- type_register_static(&cirrus_vga_info);
-}
-
-type_init(cirrus_vga_register_types)
diff --git a/qemu/hw/display/cirrus_vga_rop.h b/qemu/hw/display/cirrus_vga_rop.h
deleted file mode 100644
index 0925a009f..000000000
--- a/qemu/hw/display/cirrus_vga_rop.h
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * QEMU Cirrus CLGD 54xx VGA Emulator.
- *
- * Copyright (c) 2004 Fabrice Bellard
- *
- * 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.
- */
-
-static inline void glue(rop_8_,ROP_NAME)(uint8_t *dst, uint8_t src)
-{
- *dst = ROP_FN(*dst, src);
-}
-
-static inline void glue(rop_16_,ROP_NAME)(uint16_t *dst, uint16_t src)
-{
- *dst = ROP_FN(*dst, src);
-}
-
-static inline void glue(rop_32_,ROP_NAME)(uint32_t *dst, uint32_t src)
-{
- *dst = ROP_FN(*dst, src);
-}
-
-#define ROP_OP(d, s) glue(rop_8_,ROP_NAME)(d, s)
-#define ROP_OP_16(d, s) glue(rop_16_,ROP_NAME)(d, s)
-#define ROP_OP_32(d, s) glue(rop_32_,ROP_NAME)(d, s)
-#undef ROP_FN
-
-static void
-glue(cirrus_bitblt_rop_fwd_, ROP_NAME)(CirrusVGAState *s,
- uint8_t *dst,const uint8_t *src,
- int dstpitch,int srcpitch,
- int bltwidth,int bltheight)
-{
- int x,y;
- dstpitch -= bltwidth;
- srcpitch -= bltwidth;
-
- if (bltheight > 1 && (dstpitch < 0 || srcpitch < 0)) {
- return;
- }
-
- for (y = 0; y < bltheight; y++) {
- for (x = 0; x < bltwidth; x++) {
- ROP_OP(dst, *src);
- dst++;
- src++;
- }
- dst += dstpitch;
- src += srcpitch;
- }
-}
-
-static void
-glue(cirrus_bitblt_rop_bkwd_, ROP_NAME)(CirrusVGAState *s,
- uint8_t *dst,const uint8_t *src,
- int dstpitch,int srcpitch,
- int bltwidth,int bltheight)
-{
- int x,y;
- dstpitch += bltwidth;
- srcpitch += bltwidth;
- for (y = 0; y < bltheight; y++) {
- for (x = 0; x < bltwidth; x++) {
- ROP_OP(dst, *src);
- dst--;
- src--;
- }
- dst += dstpitch;
- src += srcpitch;
- }
-}
-
-static void
-glue(glue(cirrus_bitblt_rop_fwd_transp_, ROP_NAME),_8)(CirrusVGAState *s,
- uint8_t *dst,const uint8_t *src,
- int dstpitch,int srcpitch,
- int bltwidth,int bltheight)
-{
- int x,y;
- uint8_t p;
- dstpitch -= bltwidth;
- srcpitch -= bltwidth;
- for (y = 0; y < bltheight; y++) {
- for (x = 0; x < bltwidth; x++) {
- p = *dst;
- ROP_OP(&p, *src);
- if (p != s->vga.gr[0x34]) *dst = p;
- dst++;
- src++;
- }
- dst += dstpitch;
- src += srcpitch;
- }
-}
-
-static void
-glue(glue(cirrus_bitblt_rop_bkwd_transp_, ROP_NAME),_8)(CirrusVGAState *s,
- uint8_t *dst,const uint8_t *src,
- int dstpitch,int srcpitch,
- int bltwidth,int bltheight)
-{
- int x,y;
- uint8_t p;
- dstpitch += bltwidth;
- srcpitch += bltwidth;
- for (y = 0; y < bltheight; y++) {
- for (x = 0; x < bltwidth; x++) {
- p = *dst;
- ROP_OP(&p, *src);
- if (p != s->vga.gr[0x34]) *dst = p;
- dst--;
- src--;
- }
- dst += dstpitch;
- src += srcpitch;
- }
-}
-
-static void
-glue(glue(cirrus_bitblt_rop_fwd_transp_, ROP_NAME),_16)(CirrusVGAState *s,
- uint8_t *dst,const uint8_t *src,
- int dstpitch,int srcpitch,
- int bltwidth,int bltheight)
-{
- int x,y;
- uint8_t p1, p2;
- dstpitch -= bltwidth;
- srcpitch -= bltwidth;
- for (y = 0; y < bltheight; y++) {
- for (x = 0; x < bltwidth; x+=2) {
- p1 = *dst;
- p2 = *(dst+1);
- ROP_OP(&p1, *src);
- ROP_OP(&p2, *(src + 1));
- if ((p1 != s->vga.gr[0x34]) || (p2 != s->vga.gr[0x35])) {
- *dst = p1;
- *(dst+1) = p2;
- }
- dst+=2;
- src+=2;
- }
- dst += dstpitch;
- src += srcpitch;
- }
-}
-
-static void
-glue(glue(cirrus_bitblt_rop_bkwd_transp_, ROP_NAME),_16)(CirrusVGAState *s,
- uint8_t *dst,const uint8_t *src,
- int dstpitch,int srcpitch,
- int bltwidth,int bltheight)
-{
- int x,y;
- uint8_t p1, p2;
- dstpitch += bltwidth;
- srcpitch += bltwidth;
- for (y = 0; y < bltheight; y++) {
- for (x = 0; x < bltwidth; x+=2) {
- p1 = *(dst-1);
- p2 = *dst;
- ROP_OP(&p1, *(src - 1));
- ROP_OP(&p2, *src);
- if ((p1 != s->vga.gr[0x34]) || (p2 != s->vga.gr[0x35])) {
- *(dst-1) = p1;
- *dst = p2;
- }
- dst-=2;
- src-=2;
- }
- dst += dstpitch;
- src += srcpitch;
- }
-}
-
-#define DEPTH 8
-#include "cirrus_vga_rop2.h"
-
-#define DEPTH 16
-#include "cirrus_vga_rop2.h"
-
-#define DEPTH 24
-#include "cirrus_vga_rop2.h"
-
-#define DEPTH 32
-#include "cirrus_vga_rop2.h"
-
-#undef ROP_NAME
-#undef ROP_OP
-#undef ROP_OP_16
-#undef ROP_OP_32
diff --git a/qemu/hw/display/cirrus_vga_rop2.h b/qemu/hw/display/cirrus_vga_rop2.h
deleted file mode 100644
index d28bcc6f2..000000000
--- a/qemu/hw/display/cirrus_vga_rop2.h
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * QEMU Cirrus CLGD 54xx VGA Emulator.
- *
- * Copyright (c) 2004 Fabrice Bellard
- *
- * 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 DEPTH == 8
-#define PUTPIXEL() ROP_OP(&d[0], col)
-#elif DEPTH == 16
-#define PUTPIXEL() ROP_OP_16((uint16_t *)&d[0], col)
-#elif DEPTH == 24
-#define PUTPIXEL() ROP_OP(&d[0], col); \
- ROP_OP(&d[1], (col >> 8)); \
- ROP_OP(&d[2], (col >> 16))
-#elif DEPTH == 32
-#define PUTPIXEL() ROP_OP_32(((uint32_t *)&d[0]), col)
-#else
-#error unsupported DEPTH
-#endif
-
-static void
-glue(glue(glue(cirrus_patternfill_, ROP_NAME), _),DEPTH)
- (CirrusVGAState * s, uint8_t * dst,
- const uint8_t * src,
- int dstpitch, int srcpitch,
- int bltwidth, int bltheight)
-{
- uint8_t *d;
- int x, y, pattern_y, pattern_pitch, pattern_x;
- unsigned int col;
- const uint8_t *src1;
-#if DEPTH == 24
- int skipleft = s->vga.gr[0x2f] & 0x1f;
-#else
- int skipleft = (s->vga.gr[0x2f] & 0x07) * (DEPTH / 8);
-#endif
-
-#if DEPTH == 8
- pattern_pitch = 8;
-#elif DEPTH == 16
- pattern_pitch = 16;
-#else
- pattern_pitch = 32;
-#endif
- pattern_y = s->cirrus_blt_srcaddr & 7;
- for(y = 0; y < bltheight; y++) {
- pattern_x = skipleft;
- d = dst + skipleft;
- src1 = src + pattern_y * pattern_pitch;
- for (x = skipleft; x < bltwidth; x += (DEPTH / 8)) {
-#if DEPTH == 8
- col = src1[pattern_x];
- pattern_x = (pattern_x + 1) & 7;
-#elif DEPTH == 16
- col = ((uint16_t *)(src1 + pattern_x))[0];
- pattern_x = (pattern_x + 2) & 15;
-#elif DEPTH == 24
- {
- const uint8_t *src2 = src1 + pattern_x * 3;
- col = src2[0] | (src2[1] << 8) | (src2[2] << 16);
- pattern_x = (pattern_x + 1) & 7;
- }
-#else
- col = ((uint32_t *)(src1 + pattern_x))[0];
- pattern_x = (pattern_x + 4) & 31;
-#endif
- PUTPIXEL();
- d += (DEPTH / 8);
- }
- pattern_y = (pattern_y + 1) & 7;
- dst += dstpitch;
- }
-}
-
-/* NOTE: srcpitch is ignored */
-static void
-glue(glue(glue(cirrus_colorexpand_transp_, ROP_NAME), _),DEPTH)
- (CirrusVGAState * s, uint8_t * dst,
- const uint8_t * src,
- int dstpitch, int srcpitch,
- int bltwidth, int bltheight)
-{
- uint8_t *d;
- int x, y;
- unsigned bits, bits_xor;
- unsigned int col;
- unsigned bitmask;
- unsigned index;
-#if DEPTH == 24
- int dstskipleft = s->vga.gr[0x2f] & 0x1f;
- int srcskipleft = dstskipleft / 3;
-#else
- int srcskipleft = s->vga.gr[0x2f] & 0x07;
- int dstskipleft = srcskipleft * (DEPTH / 8);
-#endif
-
- if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) {
- bits_xor = 0xff;
- col = s->cirrus_blt_bgcol;
- } else {
- bits_xor = 0x00;
- col = s->cirrus_blt_fgcol;
- }
-
- for(y = 0; y < bltheight; y++) {
- bitmask = 0x80 >> srcskipleft;
- bits = *src++ ^ bits_xor;
- d = dst + dstskipleft;
- for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
- if ((bitmask & 0xff) == 0) {
- bitmask = 0x80;
- bits = *src++ ^ bits_xor;
- }
- index = (bits & bitmask);
- if (index) {
- PUTPIXEL();
- }
- d += (DEPTH / 8);
- bitmask >>= 1;
- }
- dst += dstpitch;
- }
-}
-
-static void
-glue(glue(glue(cirrus_colorexpand_, ROP_NAME), _),DEPTH)
- (CirrusVGAState * s, uint8_t * dst,
- const uint8_t * src,
- int dstpitch, int srcpitch,
- int bltwidth, int bltheight)
-{
- uint32_t colors[2];
- uint8_t *d;
- int x, y;
- unsigned bits;
- unsigned int col;
- unsigned bitmask;
- int srcskipleft = s->vga.gr[0x2f] & 0x07;
- int dstskipleft = srcskipleft * (DEPTH / 8);
-
- colors[0] = s->cirrus_blt_bgcol;
- colors[1] = s->cirrus_blt_fgcol;
- for(y = 0; y < bltheight; y++) {
- bitmask = 0x80 >> srcskipleft;
- bits = *src++;
- d = dst + dstskipleft;
- for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
- if ((bitmask & 0xff) == 0) {
- bitmask = 0x80;
- bits = *src++;
- }
- col = colors[!!(bits & bitmask)];
- PUTPIXEL();
- d += (DEPTH / 8);
- bitmask >>= 1;
- }
- dst += dstpitch;
- }
-}
-
-static void
-glue(glue(glue(cirrus_colorexpand_pattern_transp_, ROP_NAME), _),DEPTH)
- (CirrusVGAState * s, uint8_t * dst,
- const uint8_t * src,
- int dstpitch, int srcpitch,
- int bltwidth, int bltheight)
-{
- uint8_t *d;
- int x, y, bitpos, pattern_y;
- unsigned int bits, bits_xor;
- unsigned int col;
-#if DEPTH == 24
- int dstskipleft = s->vga.gr[0x2f] & 0x1f;
- int srcskipleft = dstskipleft / 3;
-#else
- int srcskipleft = s->vga.gr[0x2f] & 0x07;
- int dstskipleft = srcskipleft * (DEPTH / 8);
-#endif
-
- if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) {
- bits_xor = 0xff;
- col = s->cirrus_blt_bgcol;
- } else {
- bits_xor = 0x00;
- col = s->cirrus_blt_fgcol;
- }
- pattern_y = s->cirrus_blt_srcaddr & 7;
-
- for(y = 0; y < bltheight; y++) {
- bits = src[pattern_y] ^ bits_xor;
- bitpos = 7 - srcskipleft;
- d = dst + dstskipleft;
- for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
- if ((bits >> bitpos) & 1) {
- PUTPIXEL();
- }
- d += (DEPTH / 8);
- bitpos = (bitpos - 1) & 7;
- }
- pattern_y = (pattern_y + 1) & 7;
- dst += dstpitch;
- }
-}
-
-static void
-glue(glue(glue(cirrus_colorexpand_pattern_, ROP_NAME), _),DEPTH)
- (CirrusVGAState * s, uint8_t * dst,
- const uint8_t * src,
- int dstpitch, int srcpitch,
- int bltwidth, int bltheight)
-{
- uint32_t colors[2];
- uint8_t *d;
- int x, y, bitpos, pattern_y;
- unsigned int bits;
- unsigned int col;
- int srcskipleft = s->vga.gr[0x2f] & 0x07;
- int dstskipleft = srcskipleft * (DEPTH / 8);
-
- colors[0] = s->cirrus_blt_bgcol;
- colors[1] = s->cirrus_blt_fgcol;
- pattern_y = s->cirrus_blt_srcaddr & 7;
-
- for(y = 0; y < bltheight; y++) {
- bits = src[pattern_y];
- bitpos = 7 - srcskipleft;
- d = dst + dstskipleft;
- for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
- col = colors[(bits >> bitpos) & 1];
- PUTPIXEL();
- d += (DEPTH / 8);
- bitpos = (bitpos - 1) & 7;
- }
- pattern_y = (pattern_y + 1) & 7;
- dst += dstpitch;
- }
-}
-
-static void
-glue(glue(glue(cirrus_fill_, ROP_NAME), _),DEPTH)
- (CirrusVGAState *s,
- uint8_t *dst, int dst_pitch,
- int width, int height)
-{
- uint8_t *d, *d1;
- uint32_t col;
- int x, y;
-
- col = s->cirrus_blt_fgcol;
-
- d1 = dst;
- for(y = 0; y < height; y++) {
- d = d1;
- for(x = 0; x < width; x += (DEPTH / 8)) {
- PUTPIXEL();
- d += (DEPTH / 8);
- }
- d1 += dst_pitch;
- }
-}
-
-#undef DEPTH
-#undef PUTPIXEL
diff --git a/qemu/hw/display/exynos4210_fimd.c b/qemu/hw/display/exynos4210_fimd.c
deleted file mode 100644
index 728eb214a..000000000
--- a/qemu/hw/display/exynos4210_fimd.c
+++ /dev/null
@@ -1,1952 +0,0 @@
-/*
- * Samsung exynos4210 Display Controller (FIMD)
- *
- * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
- * All rights reserved.
- * Based on LCD controller for Samsung S5PC1xx-based board emulation
- * by Kirill Batuzov <batuzovk@ispras.ru>
- *
- * Contributed by Mitsyanko Igor <i.mitsyanko@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "hw/sysbus.h"
-#include "ui/console.h"
-#include "ui/pixel_ops.h"
-#include "qemu/bswap.h"
-
-/* Debug messages configuration */
-#define EXYNOS4210_FIMD_DEBUG 0
-#define EXYNOS4210_FIMD_MODE_TRACE 0
-
-#if EXYNOS4210_FIMD_DEBUG == 0
- #define DPRINT_L1(fmt, args...) do { } while (0)
- #define DPRINT_L2(fmt, args...) do { } while (0)
- #define DPRINT_ERROR(fmt, args...) do { } while (0)
-#elif EXYNOS4210_FIMD_DEBUG == 1
- #define DPRINT_L1(fmt, args...) \
- do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0)
- #define DPRINT_L2(fmt, args...) do { } while (0)
- #define DPRINT_ERROR(fmt, args...) \
- do {fprintf(stderr, "QEMU FIMD ERROR: "fmt, ## args); } while (0)
-#else
- #define DPRINT_L1(fmt, args...) \
- do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0)
- #define DPRINT_L2(fmt, args...) \
- do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0)
- #define DPRINT_ERROR(fmt, args...) \
- do {fprintf(stderr, "QEMU FIMD ERROR: "fmt, ## args); } while (0)
-#endif
-
-#if EXYNOS4210_FIMD_MODE_TRACE == 0
- #define DPRINT_TRACE(fmt, args...) do { } while (0)
-#else
- #define DPRINT_TRACE(fmt, args...) \
- do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0)
-#endif
-
-#define NUM_OF_WINDOWS 5
-#define FIMD_REGS_SIZE 0x4114
-
-/* Video main control registers */
-#define FIMD_VIDCON0 0x0000
-#define FIMD_VIDCON1 0x0004
-#define FIMD_VIDCON2 0x0008
-#define FIMD_VIDCON3 0x000C
-#define FIMD_VIDCON0_ENVID_F (1 << 0)
-#define FIMD_VIDCON0_ENVID (1 << 1)
-#define FIMD_VIDCON0_ENVID_MASK ((1 << 0) | (1 << 1))
-#define FIMD_VIDCON1_ROMASK 0x07FFE000
-
-/* Video time control registers */
-#define FIMD_VIDTCON_START 0x10
-#define FIMD_VIDTCON_END 0x1C
-#define FIMD_VIDTCON2_SIZE_MASK 0x07FF
-#define FIMD_VIDTCON2_HOR_SHIFT 0
-#define FIMD_VIDTCON2_VER_SHIFT 11
-
-/* Window control registers */
-#define FIMD_WINCON_START 0x0020
-#define FIMD_WINCON_END 0x0030
-#define FIMD_WINCON_ROMASK 0x82200000
-#define FIMD_WINCON_ENWIN (1 << 0)
-#define FIMD_WINCON_BLD_PIX (1 << 6)
-#define FIMD_WINCON_ALPHA_MUL (1 << 7)
-#define FIMD_WINCON_ALPHA_SEL (1 << 1)
-#define FIMD_WINCON_SWAP 0x078000
-#define FIMD_WINCON_SWAP_SHIFT 15
-#define FIMD_WINCON_SWAP_WORD 0x1
-#define FIMD_WINCON_SWAP_HWORD 0x2
-#define FIMD_WINCON_SWAP_BYTE 0x4
-#define FIMD_WINCON_SWAP_BITS 0x8
-#define FIMD_WINCON_BUFSTAT_L (1 << 21)
-#define FIMD_WINCON_BUFSTAT_H (1 << 31)
-#define FIMD_WINCON_BUFSTATUS ((1 << 21) | (1 << 31))
-#define FIMD_WINCON_BUF0_STAT ((0 << 21) | (0 << 31))
-#define FIMD_WINCON_BUF1_STAT ((1 << 21) | (0 << 31))
-#define FIMD_WINCON_BUF2_STAT ((0 << 21) | (1 << 31))
-#define FIMD_WINCON_BUFSELECT ((1 << 20) | (1 << 30))
-#define FIMD_WINCON_BUF0_SEL ((0 << 20) | (0 << 30))
-#define FIMD_WINCON_BUF1_SEL ((1 << 20) | (0 << 30))
-#define FIMD_WINCON_BUF2_SEL ((0 << 20) | (1 << 30))
-#define FIMD_WINCON_BUFMODE (1 << 14)
-#define IS_PALETTIZED_MODE(w) (w->wincon & 0xC)
-#define PAL_MODE_WITH_ALPHA(x) ((x) == 7)
-#define WIN_BPP_MODE(w) ((w->wincon >> 2) & 0xF)
-#define WIN_BPP_MODE_WITH_ALPHA(w) \
- (WIN_BPP_MODE(w) == 0xD || WIN_BPP_MODE(w) == 0xE)
-
-/* Shadow control register */
-#define FIMD_SHADOWCON 0x0034
-#define FIMD_WINDOW_PROTECTED(s, w) ((s) & (1 << (10 + (w))))
-/* Channel mapping control register */
-#define FIMD_WINCHMAP 0x003C
-
-/* Window position control registers */
-#define FIMD_VIDOSD_START 0x0040
-#define FIMD_VIDOSD_END 0x0088
-#define FIMD_VIDOSD_COORD_MASK 0x07FF
-#define FIMD_VIDOSD_HOR_SHIFT 11
-#define FIMD_VIDOSD_VER_SHIFT 0
-#define FIMD_VIDOSD_ALPHA_AEN0 0xFFF000
-#define FIMD_VIDOSD_AEN0_SHIFT 12
-#define FIMD_VIDOSD_ALPHA_AEN1 0x000FFF
-
-/* Frame buffer address registers */
-#define FIMD_VIDWADD0_START 0x00A0
-#define FIMD_VIDWADD0_END 0x00C4
-#define FIMD_VIDWADD0_END 0x00C4
-#define FIMD_VIDWADD1_START 0x00D0
-#define FIMD_VIDWADD1_END 0x00F4
-#define FIMD_VIDWADD2_START 0x0100
-#define FIMD_VIDWADD2_END 0x0110
-#define FIMD_VIDWADD2_PAGEWIDTH 0x1FFF
-#define FIMD_VIDWADD2_OFFSIZE 0x1FFF
-#define FIMD_VIDWADD2_OFFSIZE_SHIFT 13
-#define FIMD_VIDW0ADD0_B2 0x20A0
-#define FIMD_VIDW4ADD0_B2 0x20C0
-
-/* Video interrupt control registers */
-#define FIMD_VIDINTCON0 0x130
-#define FIMD_VIDINTCON1 0x134
-
-/* Window color key registers */
-#define FIMD_WKEYCON_START 0x140
-#define FIMD_WKEYCON_END 0x15C
-#define FIMD_WKEYCON0_COMPKEY 0x00FFFFFF
-#define FIMD_WKEYCON0_CTL_SHIFT 24
-#define FIMD_WKEYCON0_DIRCON (1 << 24)
-#define FIMD_WKEYCON0_KEYEN (1 << 25)
-#define FIMD_WKEYCON0_KEYBLEN (1 << 26)
-/* Window color key alpha control register */
-#define FIMD_WKEYALPHA_START 0x160
-#define FIMD_WKEYALPHA_END 0x16C
-
-/* Dithering control register */
-#define FIMD_DITHMODE 0x170
-
-/* Window alpha control registers */
-#define FIMD_VIDALPHA_ALPHA_LOWER 0x000F0F0F
-#define FIMD_VIDALPHA_ALPHA_UPPER 0x00F0F0F0
-#define FIMD_VIDWALPHA_START 0x21C
-#define FIMD_VIDWALPHA_END 0x240
-
-/* Window color map registers */
-#define FIMD_WINMAP_START 0x180
-#define FIMD_WINMAP_END 0x190
-#define FIMD_WINMAP_EN (1 << 24)
-#define FIMD_WINMAP_COLOR_MASK 0x00FFFFFF
-
-/* Window palette control registers */
-#define FIMD_WPALCON_HIGH 0x019C
-#define FIMD_WPALCON_LOW 0x01A0
-#define FIMD_WPALCON_UPDATEEN (1 << 9)
-#define FIMD_WPAL_W0PAL_L 0x07
-#define FIMD_WPAL_W0PAL_L_SHT 0
-#define FIMD_WPAL_W1PAL_L 0x07
-#define FIMD_WPAL_W1PAL_L_SHT 3
-#define FIMD_WPAL_W2PAL_L 0x01
-#define FIMD_WPAL_W2PAL_L_SHT 6
-#define FIMD_WPAL_W2PAL_H 0x06
-#define FIMD_WPAL_W2PAL_H_SHT 8
-#define FIMD_WPAL_W3PAL_L 0x01
-#define FIMD_WPAL_W3PAL_L_SHT 7
-#define FIMD_WPAL_W3PAL_H 0x06
-#define FIMD_WPAL_W3PAL_H_SHT 12
-#define FIMD_WPAL_W4PAL_L 0x01
-#define FIMD_WPAL_W4PAL_L_SHT 8
-#define FIMD_WPAL_W4PAL_H 0x06
-#define FIMD_WPAL_W4PAL_H_SHT 16
-
-/* Trigger control registers */
-#define FIMD_TRIGCON 0x01A4
-#define FIMD_TRIGCON_ROMASK 0x00000004
-
-/* LCD I80 Interface Control */
-#define FIMD_I80IFCON_START 0x01B0
-#define FIMD_I80IFCON_END 0x01BC
-/* Color gain control register */
-#define FIMD_COLORGAINCON 0x01C0
-/* LCD i80 Interface Command Control */
-#define FIMD_LDI_CMDCON0 0x01D0
-#define FIMD_LDI_CMDCON1 0x01D4
-/* I80 System Interface Manual Command Control */
-#define FIMD_SIFCCON0 0x01E0
-#define FIMD_SIFCCON2 0x01E8
-
-/* Hue Control Registers */
-#define FIMD_HUECOEFCR_START 0x01EC
-#define FIMD_HUECOEFCR_END 0x01F4
-#define FIMD_HUECOEFCB_START 0x01FC
-#define FIMD_HUECOEFCB_END 0x0208
-#define FIMD_HUEOFFSET 0x020C
-
-/* Video interrupt control registers */
-#define FIMD_VIDINT_INTFIFOPEND (1 << 0)
-#define FIMD_VIDINT_INTFRMPEND (1 << 1)
-#define FIMD_VIDINT_INTI80PEND (1 << 2)
-#define FIMD_VIDINT_INTEN (1 << 0)
-#define FIMD_VIDINT_INTFIFOEN (1 << 1)
-#define FIMD_VIDINT_INTFRMEN (1 << 12)
-#define FIMD_VIDINT_I80IFDONE (1 << 17)
-
-/* Window blend equation control registers */
-#define FIMD_BLENDEQ_START 0x0244
-#define FIMD_BLENDEQ_END 0x0250
-#define FIMD_BLENDCON 0x0260
-#define FIMD_ALPHA_8BIT (1 << 0)
-#define FIMD_BLENDEQ_COEF_MASK 0xF
-
-/* Window RTQOS Control Registers */
-#define FIMD_WRTQOSCON_START 0x0264
-#define FIMD_WRTQOSCON_END 0x0274
-
-/* LCD I80 Interface Command */
-#define FIMD_I80IFCMD_START 0x0280
-#define FIMD_I80IFCMD_END 0x02AC
-
-/* Shadow windows control registers */
-#define FIMD_SHD_ADD0_START 0x40A0
-#define FIMD_SHD_ADD0_END 0x40C0
-#define FIMD_SHD_ADD1_START 0x40D0
-#define FIMD_SHD_ADD1_END 0x40F0
-#define FIMD_SHD_ADD2_START 0x4100
-#define FIMD_SHD_ADD2_END 0x4110
-
-/* Palette memory */
-#define FIMD_PAL_MEM_START 0x2400
-#define FIMD_PAL_MEM_END 0x37FC
-/* Palette memory aliases for windows 0 and 1 */
-#define FIMD_PALMEM_AL_START 0x0400
-#define FIMD_PALMEM_AL_END 0x0BFC
-
-typedef struct {
- uint8_t r, g, b;
- /* D[31..24]dummy, D[23..16]rAlpha, D[15..8]gAlpha, D[7..0]bAlpha */
- uint32_t a;
-} rgba;
-#define RGBA_SIZE 7
-
-typedef void pixel_to_rgb_func(uint32_t pixel, rgba *p);
-typedef struct Exynos4210fimdWindow Exynos4210fimdWindow;
-
-struct Exynos4210fimdWindow {
- uint32_t wincon; /* Window control register */
- uint32_t buf_start[3]; /* Start address for video frame buffer */
- uint32_t buf_end[3]; /* End address for video frame buffer */
- uint32_t keycon[2]; /* Window color key registers */
- uint32_t keyalpha; /* Color key alpha control register */
- uint32_t winmap; /* Window color map register */
- uint32_t blendeq; /* Window blending equation control register */
- uint32_t rtqoscon; /* Window RTQOS Control Registers */
- uint32_t palette[256]; /* Palette RAM */
- uint32_t shadow_buf_start; /* Start address of shadow frame buffer */
- uint32_t shadow_buf_end; /* End address of shadow frame buffer */
- uint32_t shadow_buf_size; /* Virtual shadow screen width */
-
- pixel_to_rgb_func *pixel_to_rgb;
- void (*draw_line)(Exynos4210fimdWindow *w, uint8_t *src, uint8_t *dst,
- bool blend);
- uint32_t (*get_alpha)(Exynos4210fimdWindow *w, uint32_t pix_a);
- uint16_t lefttop_x, lefttop_y; /* VIDOSD0 register */
- uint16_t rightbot_x, rightbot_y; /* VIDOSD1 register */
- uint32_t osdsize; /* VIDOSD2&3 register */
- uint32_t alpha_val[2]; /* VIDOSD2&3, VIDWALPHA registers */
- uint16_t virtpage_width; /* VIDWADD2 register */
- uint16_t virtpage_offsize; /* VIDWADD2 register */
- MemoryRegionSection mem_section; /* RAM fragment containing framebuffer */
- uint8_t *host_fb_addr; /* Host pointer to window's framebuffer */
- hwaddr fb_len; /* Framebuffer length */
-};
-
-#define TYPE_EXYNOS4210_FIMD "exynos4210.fimd"
-#define EXYNOS4210_FIMD(obj) \
- OBJECT_CHECK(Exynos4210fimdState, (obj), TYPE_EXYNOS4210_FIMD)
-
-typedef struct {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- QemuConsole *console;
- qemu_irq irq[3];
-
- uint32_t vidcon[4]; /* Video main control registers 0-3 */
- uint32_t vidtcon[4]; /* Video time control registers 0-3 */
- uint32_t shadowcon; /* Window shadow control register */
- uint32_t winchmap; /* Channel mapping control register */
- uint32_t vidintcon[2]; /* Video interrupt control registers */
- uint32_t dithmode; /* Dithering control register */
- uint32_t wpalcon[2]; /* Window palette control registers */
- uint32_t trigcon; /* Trigger control register */
- uint32_t i80ifcon[4]; /* I80 interface control registers */
- uint32_t colorgaincon; /* Color gain control register */
- uint32_t ldi_cmdcon[2]; /* LCD I80 interface command control */
- uint32_t sifccon[3]; /* I80 System Interface Manual Command Control */
- uint32_t huecoef_cr[4]; /* Hue control registers */
- uint32_t huecoef_cb[4]; /* Hue control registers */
- uint32_t hueoffset; /* Hue offset control register */
- uint32_t blendcon; /* Blending control register */
- uint32_t i80ifcmd[12]; /* LCD I80 Interface Command */
-
- Exynos4210fimdWindow window[5]; /* Window-specific registers */
- uint8_t *ifb; /* Internal frame buffer */
- bool invalidate; /* Image needs to be redrawn */
- bool enabled; /* Display controller is enabled */
-} Exynos4210fimdState;
-
-/* Perform byte/halfword/word swap of data according to WINCON */
-static inline void fimd_swap_data(unsigned int swap_ctl, uint64_t *data)
-{
- int i;
- uint64_t res;
- uint64_t x = *data;
-
- if (swap_ctl & FIMD_WINCON_SWAP_BITS) {
- res = 0;
- for (i = 0; i < 64; i++) {
- if (x & (1ULL << (63 - i))) {
- res |= (1ULL << i);
- }
- }
- x = res;
- }
-
- if (swap_ctl & FIMD_WINCON_SWAP_BYTE) {
- x = bswap64(x);
- }
-
- if (swap_ctl & FIMD_WINCON_SWAP_HWORD) {
- x = ((x & 0x000000000000FFFFULL) << 48) |
- ((x & 0x00000000FFFF0000ULL) << 16) |
- ((x & 0x0000FFFF00000000ULL) >> 16) |
- ((x & 0xFFFF000000000000ULL) >> 48);
- }
-
- if (swap_ctl & FIMD_WINCON_SWAP_WORD) {
- x = ((x & 0x00000000FFFFFFFFULL) << 32) |
- ((x & 0xFFFFFFFF00000000ULL) >> 32);
- }
-
- *data = x;
-}
-
-/* Conversion routines of Pixel data from frame buffer area to internal RGBA
- * pixel representation.
- * Every color component internally represented as 8-bit value. If original
- * data has less than 8 bit for component, data is extended to 8 bit. For
- * example, if blue component has only two possible values 0 and 1 it will be
- * extended to 0 and 0xFF */
-
-/* One bit for alpha representation */
-#define DEF_PIXEL_TO_RGB_A1(N, R, G, B) \
-static void N(uint32_t pixel, rgba *p) \
-{ \
- p->b = ((pixel & ((1 << (B)) - 1)) << (8 - (B))) | \
- ((pixel >> (2 * (B) - 8)) & ((1 << (8 - (B))) - 1)); \
- pixel >>= (B); \
- p->g = (pixel & ((1 << (G)) - 1)) << (8 - (G)) | \
- ((pixel >> (2 * (G) - 8)) & ((1 << (8 - (G))) - 1)); \
- pixel >>= (G); \
- p->r = (pixel & ((1 << (R)) - 1)) << (8 - (R)) | \
- ((pixel >> (2 * (R) - 8)) & ((1 << (8 - (R))) - 1)); \
- pixel >>= (R); \
- p->a = (pixel & 0x1); \
-}
-
-DEF_PIXEL_TO_RGB_A1(pixel_a444_to_rgb, 4, 4, 4)
-DEF_PIXEL_TO_RGB_A1(pixel_a555_to_rgb, 5, 5, 5)
-DEF_PIXEL_TO_RGB_A1(pixel_a666_to_rgb, 6, 6, 6)
-DEF_PIXEL_TO_RGB_A1(pixel_a665_to_rgb, 6, 6, 5)
-DEF_PIXEL_TO_RGB_A1(pixel_a888_to_rgb, 8, 8, 8)
-DEF_PIXEL_TO_RGB_A1(pixel_a887_to_rgb, 8, 8, 7)
-
-/* Alpha component is always zero */
-#define DEF_PIXEL_TO_RGB_A0(N, R, G, B) \
-static void N(uint32_t pixel, rgba *p) \
-{ \
- p->b = ((pixel & ((1 << (B)) - 1)) << (8 - (B))) | \
- ((pixel >> (2 * (B) - 8)) & ((1 << (8 - (B))) - 1)); \
- pixel >>= (B); \
- p->g = (pixel & ((1 << (G)) - 1)) << (8 - (G)) | \
- ((pixel >> (2 * (G) - 8)) & ((1 << (8 - (G))) - 1)); \
- pixel >>= (G); \
- p->r = (pixel & ((1 << (R)) - 1)) << (8 - (R)) | \
- ((pixel >> (2 * (R) - 8)) & ((1 << (8 - (R))) - 1)); \
- p->a = 0x0; \
-}
-
-DEF_PIXEL_TO_RGB_A0(pixel_565_to_rgb, 5, 6, 5)
-DEF_PIXEL_TO_RGB_A0(pixel_555_to_rgb, 5, 5, 5)
-DEF_PIXEL_TO_RGB_A0(pixel_666_to_rgb, 6, 6, 6)
-DEF_PIXEL_TO_RGB_A0(pixel_888_to_rgb, 8, 8, 8)
-
-/* Alpha component has some meaningful value */
-#define DEF_PIXEL_TO_RGB_A(N, R, G, B, A) \
-static void N(uint32_t pixel, rgba *p) \
-{ \
- p->b = ((pixel & ((1 << (B)) - 1)) << (8 - (B))) | \
- ((pixel >> (2 * (B) - 8)) & ((1 << (8 - (B))) - 1)); \
- pixel >>= (B); \
- p->g = (pixel & ((1 << (G)) - 1)) << (8 - (G)) | \
- ((pixel >> (2 * (G) - 8)) & ((1 << (8 - (G))) - 1)); \
- pixel >>= (G); \
- p->r = (pixel & ((1 << (R)) - 1)) << (8 - (R)) | \
- ((pixel >> (2 * (R) - 8)) & ((1 << (8 - (R))) - 1)); \
- pixel >>= (R); \
- p->a = (pixel & ((1 << (A)) - 1)) << (8 - (A)) | \
- ((pixel >> (2 * (A) - 8)) & ((1 << (8 - (A))) - 1)); \
- p->a = p->a | (p->a << 8) | (p->a << 16); \
-}
-
-DEF_PIXEL_TO_RGB_A(pixel_4444_to_rgb, 4, 4, 4, 4)
-DEF_PIXEL_TO_RGB_A(pixel_8888_to_rgb, 8, 8, 8, 8)
-
-/* Lookup table to extent 2-bit color component to 8 bit */
-static const uint8_t pixel_lutable_2b[4] = {
- 0x0, 0x55, 0xAA, 0xFF
-};
-/* Lookup table to extent 3-bit color component to 8 bit */
-static const uint8_t pixel_lutable_3b[8] = {
- 0x0, 0x24, 0x49, 0x6D, 0x92, 0xB6, 0xDB, 0xFF
-};
-/* Special case for a232 bpp mode */
-static void pixel_a232_to_rgb(uint32_t pixel, rgba *p)
-{
- p->b = pixel_lutable_2b[(pixel & 0x3)];
- pixel >>= 2;
- p->g = pixel_lutable_3b[(pixel & 0x7)];
- pixel >>= 3;
- p->r = pixel_lutable_2b[(pixel & 0x3)];
- pixel >>= 2;
- p->a = (pixel & 0x1);
-}
-
-/* Special case for (5+1, 5+1, 5+1) mode. Data bit 15 is common LSB
- * for all three color components */
-static void pixel_1555_to_rgb(uint32_t pixel, rgba *p)
-{
- uint8_t comm = (pixel >> 15) & 1;
- p->b = ((((pixel & 0x1F) << 1) | comm) << 2) | ((pixel >> 3) & 0x3);
- pixel >>= 5;
- p->g = ((((pixel & 0x1F) << 1) | comm) << 2) | ((pixel >> 3) & 0x3);
- pixel >>= 5;
- p->r = ((((pixel & 0x1F) << 1) | comm) << 2) | ((pixel >> 3) & 0x3);
- p->a = 0x0;
-}
-
-/* Put/get pixel to/from internal LCD Controller framebuffer */
-
-static int put_pixel_ifb(const rgba p, uint8_t *d)
-{
- *(uint8_t *)d++ = p.r;
- *(uint8_t *)d++ = p.g;
- *(uint8_t *)d++ = p.b;
- *(uint32_t *)d = p.a;
- return RGBA_SIZE;
-}
-
-static int get_pixel_ifb(const uint8_t *s, rgba *p)
-{
- p->r = *(uint8_t *)s++;
- p->g = *(uint8_t *)s++;
- p->b = *(uint8_t *)s++;
- p->a = (*(uint32_t *)s) & 0x00FFFFFF;
- return RGBA_SIZE;
-}
-
-static pixel_to_rgb_func *palette_data_format[8] = {
- [0] = pixel_565_to_rgb,
- [1] = pixel_a555_to_rgb,
- [2] = pixel_666_to_rgb,
- [3] = pixel_a665_to_rgb,
- [4] = pixel_a666_to_rgb,
- [5] = pixel_888_to_rgb,
- [6] = pixel_a888_to_rgb,
- [7] = pixel_8888_to_rgb
-};
-
-/* Returns Index in palette data formats table for given window number WINDOW */
-static uint32_t
-exynos4210_fimd_palette_format(Exynos4210fimdState *s, int window)
-{
- uint32_t ret;
-
- switch (window) {
- case 0:
- ret = (s->wpalcon[1] >> FIMD_WPAL_W0PAL_L_SHT) & FIMD_WPAL_W0PAL_L;
- if (ret != 7) {
- ret = 6 - ret;
- }
- break;
- case 1:
- ret = (s->wpalcon[1] >> FIMD_WPAL_W1PAL_L_SHT) & FIMD_WPAL_W1PAL_L;
- if (ret != 7) {
- ret = 6 - ret;
- }
- break;
- case 2:
- ret = ((s->wpalcon[0] >> FIMD_WPAL_W2PAL_H_SHT) & FIMD_WPAL_W2PAL_H) |
- ((s->wpalcon[1] >> FIMD_WPAL_W2PAL_L_SHT) & FIMD_WPAL_W2PAL_L);
- break;
- case 3:
- ret = ((s->wpalcon[0] >> FIMD_WPAL_W3PAL_H_SHT) & FIMD_WPAL_W3PAL_H) |
- ((s->wpalcon[1] >> FIMD_WPAL_W3PAL_L_SHT) & FIMD_WPAL_W3PAL_L);
- break;
- case 4:
- ret = ((s->wpalcon[0] >> FIMD_WPAL_W4PAL_H_SHT) & FIMD_WPAL_W4PAL_H) |
- ((s->wpalcon[1] >> FIMD_WPAL_W4PAL_L_SHT) & FIMD_WPAL_W4PAL_L);
- break;
- default:
- hw_error("exynos4210.fimd: incorrect window number %d\n", window);
- ret = 0;
- break;
- }
- return ret;
-}
-
-#define FIMD_1_MINUS_COLOR(x) \
- ((0xFF - ((x) & 0xFF)) | (0xFF00 - ((x) & 0xFF00)) | \
- (0xFF0000 - ((x) & 0xFF0000)))
-#define EXTEND_LOWER_HALFBYTE(x) (((x) & 0xF0F0F) | (((x) << 4) & 0xF0F0F0))
-#define EXTEND_UPPER_HALFBYTE(x) (((x) & 0xF0F0F0) | (((x) >> 4) & 0xF0F0F))
-
-/* Multiply three lower bytes of two 32-bit words with each other.
- * Each byte with values 0-255 is considered as a number with possible values
- * in a range [0 - 1] */
-static inline uint32_t fimd_mult_each_byte(uint32_t a, uint32_t b)
-{
- uint32_t tmp;
- uint32_t ret;
-
- ret = ((tmp = (((a & 0xFF) * (b & 0xFF)) / 0xFF)) > 0xFF) ? 0xFF : tmp;
- ret |= ((tmp = ((((a >> 8) & 0xFF) * ((b >> 8) & 0xFF)) / 0xFF)) > 0xFF) ?
- 0xFF00 : tmp << 8;
- ret |= ((tmp = ((((a >> 16) & 0xFF) * ((b >> 16) & 0xFF)) / 0xFF)) > 0xFF) ?
- 0xFF0000 : tmp << 16;
- return ret;
-}
-
-/* For each corresponding bytes of two 32-bit words: (a*b + c*d)
- * Byte values 0-255 are mapped to a range [0 .. 1] */
-static inline uint32_t
-fimd_mult_and_sum_each_byte(uint32_t a, uint32_t b, uint32_t c, uint32_t d)
-{
- uint32_t tmp;
- uint32_t ret;
-
- ret = ((tmp = (((a & 0xFF) * (b & 0xFF) + (c & 0xFF) * (d & 0xFF)) / 0xFF))
- > 0xFF) ? 0xFF : tmp;
- ret |= ((tmp = ((((a >> 8) & 0xFF) * ((b >> 8) & 0xFF) + ((c >> 8) & 0xFF) *
- ((d >> 8) & 0xFF)) / 0xFF)) > 0xFF) ? 0xFF00 : tmp << 8;
- ret |= ((tmp = ((((a >> 16) & 0xFF) * ((b >> 16) & 0xFF) +
- ((c >> 16) & 0xFF) * ((d >> 16) & 0xFF)) / 0xFF)) > 0xFF) ?
- 0xFF0000 : tmp << 16;
- return ret;
-}
-
-/* These routines cover all possible sources of window's transparent factor
- * used in blending equation. Choice of routine is affected by WPALCON
- * registers, BLENDCON register and window's WINCON register */
-
-static uint32_t fimd_get_alpha_pix(Exynos4210fimdWindow *w, uint32_t pix_a)
-{
- return pix_a;
-}
-
-static uint32_t
-fimd_get_alpha_pix_extlow(Exynos4210fimdWindow *w, uint32_t pix_a)
-{
- return EXTEND_LOWER_HALFBYTE(pix_a);
-}
-
-static uint32_t
-fimd_get_alpha_pix_exthigh(Exynos4210fimdWindow *w, uint32_t pix_a)
-{
- return EXTEND_UPPER_HALFBYTE(pix_a);
-}
-
-static uint32_t fimd_get_alpha_mult(Exynos4210fimdWindow *w, uint32_t pix_a)
-{
- return fimd_mult_each_byte(pix_a, w->alpha_val[0]);
-}
-
-static uint32_t fimd_get_alpha_mult_ext(Exynos4210fimdWindow *w, uint32_t pix_a)
-{
- return fimd_mult_each_byte(EXTEND_LOWER_HALFBYTE(pix_a),
- EXTEND_UPPER_HALFBYTE(w->alpha_val[0]));
-}
-
-static uint32_t fimd_get_alpha_aen(Exynos4210fimdWindow *w, uint32_t pix_a)
-{
- return w->alpha_val[pix_a];
-}
-
-static uint32_t fimd_get_alpha_aen_ext(Exynos4210fimdWindow *w, uint32_t pix_a)
-{
- return EXTEND_UPPER_HALFBYTE(w->alpha_val[pix_a]);
-}
-
-static uint32_t fimd_get_alpha_sel(Exynos4210fimdWindow *w, uint32_t pix_a)
-{
- return w->alpha_val[(w->wincon & FIMD_WINCON_ALPHA_SEL) ? 1 : 0];
-}
-
-static uint32_t fimd_get_alpha_sel_ext(Exynos4210fimdWindow *w, uint32_t pix_a)
-{
- return EXTEND_UPPER_HALFBYTE(w->alpha_val[(w->wincon &
- FIMD_WINCON_ALPHA_SEL) ? 1 : 0]);
-}
-
-/* Updates currently active alpha value get function for specified window */
-static void fimd_update_get_alpha(Exynos4210fimdState *s, int win)
-{
- Exynos4210fimdWindow *w = &s->window[win];
- const bool alpha_is_8bit = s->blendcon & FIMD_ALPHA_8BIT;
-
- if (w->wincon & FIMD_WINCON_BLD_PIX) {
- if ((w->wincon & FIMD_WINCON_ALPHA_SEL) && WIN_BPP_MODE_WITH_ALPHA(w)) {
- /* In this case, alpha component contains meaningful value */
- if (w->wincon & FIMD_WINCON_ALPHA_MUL) {
- w->get_alpha = alpha_is_8bit ?
- fimd_get_alpha_mult : fimd_get_alpha_mult_ext;
- } else {
- w->get_alpha = alpha_is_8bit ?
- fimd_get_alpha_pix : fimd_get_alpha_pix_extlow;
- }
- } else {
- if (IS_PALETTIZED_MODE(w) &&
- PAL_MODE_WITH_ALPHA(exynos4210_fimd_palette_format(s, win))) {
- /* Alpha component has 8-bit numeric value */
- w->get_alpha = alpha_is_8bit ?
- fimd_get_alpha_pix : fimd_get_alpha_pix_exthigh;
- } else {
- /* Alpha has only two possible values (AEN) */
- w->get_alpha = alpha_is_8bit ?
- fimd_get_alpha_aen : fimd_get_alpha_aen_ext;
- }
- }
- } else {
- w->get_alpha = alpha_is_8bit ? fimd_get_alpha_sel :
- fimd_get_alpha_sel_ext;
- }
-}
-
-/* Blends current window's (w) pixel (foreground pixel *ret) with background
- * window (w_blend) pixel p_bg according to formula:
- * NEW_COLOR = a_coef x FG_PIXEL_COLOR + b_coef x BG_PIXEL_COLOR
- * NEW_ALPHA = p_coef x FG_ALPHA + q_coef x BG_ALPHA
- */
-static void
-exynos4210_fimd_blend_pixel(Exynos4210fimdWindow *w, rgba p_bg, rgba *ret)
-{
- rgba p_fg = *ret;
- uint32_t bg_color = ((p_bg.r & 0xFF) << 16) | ((p_bg.g & 0xFF) << 8) |
- (p_bg.b & 0xFF);
- uint32_t fg_color = ((p_fg.r & 0xFF) << 16) | ((p_fg.g & 0xFF) << 8) |
- (p_fg.b & 0xFF);
- uint32_t alpha_fg = p_fg.a;
- int i;
- /* It is possible that blending equation parameters a and b do not
- * depend on window BLENEQ register. Account for this with first_coef */
- enum { A_COEF = 0, B_COEF = 1, P_COEF = 2, Q_COEF = 3, COEF_NUM = 4};
- uint32_t first_coef = A_COEF;
- uint32_t blend_param[COEF_NUM];
-
- if (w->keycon[0] & FIMD_WKEYCON0_KEYEN) {
- uint32_t colorkey = (w->keycon[1] &
- ~(w->keycon[0] & FIMD_WKEYCON0_COMPKEY)) & FIMD_WKEYCON0_COMPKEY;
-
- if ((w->keycon[0] & FIMD_WKEYCON0_DIRCON) &&
- (bg_color & ~(w->keycon[0] & FIMD_WKEYCON0_COMPKEY)) == colorkey) {
- /* Foreground pixel is displayed */
- if (w->keycon[0] & FIMD_WKEYCON0_KEYBLEN) {
- alpha_fg = w->keyalpha;
- blend_param[A_COEF] = alpha_fg;
- blend_param[B_COEF] = FIMD_1_MINUS_COLOR(alpha_fg);
- } else {
- alpha_fg = 0;
- blend_param[A_COEF] = 0xFFFFFF;
- blend_param[B_COEF] = 0x0;
- }
- first_coef = P_COEF;
- } else if ((w->keycon[0] & FIMD_WKEYCON0_DIRCON) == 0 &&
- (fg_color & ~(w->keycon[0] & FIMD_WKEYCON0_COMPKEY)) == colorkey) {
- /* Background pixel is displayed */
- if (w->keycon[0] & FIMD_WKEYCON0_KEYBLEN) {
- alpha_fg = w->keyalpha;
- blend_param[A_COEF] = alpha_fg;
- blend_param[B_COEF] = FIMD_1_MINUS_COLOR(alpha_fg);
- } else {
- alpha_fg = 0;
- blend_param[A_COEF] = 0x0;
- blend_param[B_COEF] = 0xFFFFFF;
- }
- first_coef = P_COEF;
- }
- }
-
- for (i = first_coef; i < COEF_NUM; i++) {
- switch ((w->blendeq >> i * 6) & FIMD_BLENDEQ_COEF_MASK) {
- case 0:
- blend_param[i] = 0;
- break;
- case 1:
- blend_param[i] = 0xFFFFFF;
- break;
- case 2:
- blend_param[i] = alpha_fg;
- break;
- case 3:
- blend_param[i] = FIMD_1_MINUS_COLOR(alpha_fg);
- break;
- case 4:
- blend_param[i] = p_bg.a;
- break;
- case 5:
- blend_param[i] = FIMD_1_MINUS_COLOR(p_bg.a);
- break;
- case 6:
- blend_param[i] = w->alpha_val[0];
- break;
- case 10:
- blend_param[i] = fg_color;
- break;
- case 11:
- blend_param[i] = FIMD_1_MINUS_COLOR(fg_color);
- break;
- case 12:
- blend_param[i] = bg_color;
- break;
- case 13:
- blend_param[i] = FIMD_1_MINUS_COLOR(bg_color);
- break;
- default:
- hw_error("exynos4210.fimd: blend equation coef illegal value\n");
- break;
- }
- }
-
- fg_color = fimd_mult_and_sum_each_byte(bg_color, blend_param[B_COEF],
- fg_color, blend_param[A_COEF]);
- ret->b = fg_color & 0xFF;
- fg_color >>= 8;
- ret->g = fg_color & 0xFF;
- fg_color >>= 8;
- ret->r = fg_color & 0xFF;
- ret->a = fimd_mult_and_sum_each_byte(alpha_fg, blend_param[P_COEF],
- p_bg.a, blend_param[Q_COEF]);
-}
-
-/* These routines read data from video frame buffer in system RAM, convert
- * this data to display controller internal representation, if necessary,
- * perform pixel blending with data, currently presented in internal buffer.
- * Result is stored in display controller internal frame buffer. */
-
-/* Draw line with index in palette table in RAM frame buffer data */
-#define DEF_DRAW_LINE_PALETTE(N) \
-static void glue(draw_line_palette_, N)(Exynos4210fimdWindow *w, uint8_t *src, \
- uint8_t *dst, bool blend) \
-{ \
- int width = w->rightbot_x - w->lefttop_x + 1; \
- uint8_t *ifb = dst; \
- uint8_t swap = (w->wincon & FIMD_WINCON_SWAP) >> FIMD_WINCON_SWAP_SHIFT; \
- uint64_t data; \
- rgba p, p_old; \
- int i; \
- do { \
- memcpy(&data, src, sizeof(data)); \
- src += 8; \
- fimd_swap_data(swap, &data); \
- for (i = (64 / (N) - 1); i >= 0; i--) { \
- w->pixel_to_rgb(w->palette[(data >> ((N) * i)) & \
- ((1ULL << (N)) - 1)], &p); \
- p.a = w->get_alpha(w, p.a); \
- if (blend) { \
- ifb += get_pixel_ifb(ifb, &p_old); \
- exynos4210_fimd_blend_pixel(w, p_old, &p); \
- } \
- dst += put_pixel_ifb(p, dst); \
- } \
- width -= (64 / (N)); \
- } while (width > 0); \
-}
-
-/* Draw line with direct color value in RAM frame buffer data */
-#define DEF_DRAW_LINE_NOPALETTE(N) \
-static void glue(draw_line_, N)(Exynos4210fimdWindow *w, uint8_t *src, \
- uint8_t *dst, bool blend) \
-{ \
- int width = w->rightbot_x - w->lefttop_x + 1; \
- uint8_t *ifb = dst; \
- uint8_t swap = (w->wincon & FIMD_WINCON_SWAP) >> FIMD_WINCON_SWAP_SHIFT; \
- uint64_t data; \
- rgba p, p_old; \
- int i; \
- do { \
- memcpy(&data, src, sizeof(data)); \
- src += 8; \
- fimd_swap_data(swap, &data); \
- for (i = (64 / (N) - 1); i >= 0; i--) { \
- w->pixel_to_rgb((data >> ((N) * i)) & ((1ULL << (N)) - 1), &p); \
- p.a = w->get_alpha(w, p.a); \
- if (blend) { \
- ifb += get_pixel_ifb(ifb, &p_old); \
- exynos4210_fimd_blend_pixel(w, p_old, &p); \
- } \
- dst += put_pixel_ifb(p, dst); \
- } \
- width -= (64 / (N)); \
- } while (width > 0); \
-}
-
-DEF_DRAW_LINE_PALETTE(1)
-DEF_DRAW_LINE_PALETTE(2)
-DEF_DRAW_LINE_PALETTE(4)
-DEF_DRAW_LINE_PALETTE(8)
-DEF_DRAW_LINE_NOPALETTE(8) /* 8bpp mode has palette and non-palette versions */
-DEF_DRAW_LINE_NOPALETTE(16)
-DEF_DRAW_LINE_NOPALETTE(32)
-
-/* Special draw line routine for window color map case */
-static void draw_line_mapcolor(Exynos4210fimdWindow *w, uint8_t *src,
- uint8_t *dst, bool blend)
-{
- rgba p, p_old;
- uint8_t *ifb = dst;
- int width = w->rightbot_x - w->lefttop_x + 1;
- uint32_t map_color = w->winmap & FIMD_WINMAP_COLOR_MASK;
-
- do {
- pixel_888_to_rgb(map_color, &p);
- p.a = w->get_alpha(w, p.a);
- if (blend) {
- ifb += get_pixel_ifb(ifb, &p_old);
- exynos4210_fimd_blend_pixel(w, p_old, &p);
- }
- dst += put_pixel_ifb(p, dst);
- } while (--width);
-}
-
-/* Write RGB to QEMU's GraphicConsole framebuffer */
-
-static int put_to_qemufb_pixel8(const rgba p, uint8_t *d)
-{
- uint32_t pixel = rgb_to_pixel8(p.r, p.g, p.b);
- *(uint8_t *)d = pixel;
- return 1;
-}
-
-static int put_to_qemufb_pixel15(const rgba p, uint8_t *d)
-{
- uint32_t pixel = rgb_to_pixel15(p.r, p.g, p.b);
- *(uint16_t *)d = pixel;
- return 2;
-}
-
-static int put_to_qemufb_pixel16(const rgba p, uint8_t *d)
-{
- uint32_t pixel = rgb_to_pixel16(p.r, p.g, p.b);
- *(uint16_t *)d = pixel;
- return 2;
-}
-
-static int put_to_qemufb_pixel24(const rgba p, uint8_t *d)
-{
- uint32_t pixel = rgb_to_pixel24(p.r, p.g, p.b);
- *(uint8_t *)d++ = (pixel >> 0) & 0xFF;
- *(uint8_t *)d++ = (pixel >> 8) & 0xFF;
- *(uint8_t *)d++ = (pixel >> 16) & 0xFF;
- return 3;
-}
-
-static int put_to_qemufb_pixel32(const rgba p, uint8_t *d)
-{
- uint32_t pixel = rgb_to_pixel24(p.r, p.g, p.b);
- *(uint32_t *)d = pixel;
- return 4;
-}
-
-/* Routine to copy pixel from internal buffer to QEMU buffer */
-static int (*put_pixel_toqemu)(const rgba p, uint8_t *pixel);
-static inline void fimd_update_putpix_qemu(int bpp)
-{
- switch (bpp) {
- case 8:
- put_pixel_toqemu = put_to_qemufb_pixel8;
- break;
- case 15:
- put_pixel_toqemu = put_to_qemufb_pixel15;
- break;
- case 16:
- put_pixel_toqemu = put_to_qemufb_pixel16;
- break;
- case 24:
- put_pixel_toqemu = put_to_qemufb_pixel24;
- break;
- case 32:
- put_pixel_toqemu = put_to_qemufb_pixel32;
- break;
- default:
- hw_error("exynos4210.fimd: unsupported BPP (%d)", bpp);
- break;
- }
-}
-
-/* Routine to copy a line from internal frame buffer to QEMU display */
-static void fimd_copy_line_toqemu(int width, uint8_t *src, uint8_t *dst)
-{
- rgba p;
-
- do {
- src += get_pixel_ifb(src, &p);
- dst += put_pixel_toqemu(p, dst);
- } while (--width);
-}
-
-/* Parse BPPMODE_F = WINCON1[5:2] bits */
-static void exynos4210_fimd_update_win_bppmode(Exynos4210fimdState *s, int win)
-{
- Exynos4210fimdWindow *w = &s->window[win];
-
- if (w->winmap & FIMD_WINMAP_EN) {
- w->draw_line = draw_line_mapcolor;
- return;
- }
-
- switch (WIN_BPP_MODE(w)) {
- case 0:
- w->draw_line = draw_line_palette_1;
- w->pixel_to_rgb =
- palette_data_format[exynos4210_fimd_palette_format(s, win)];
- break;
- case 1:
- w->draw_line = draw_line_palette_2;
- w->pixel_to_rgb =
- palette_data_format[exynos4210_fimd_palette_format(s, win)];
- break;
- case 2:
- w->draw_line = draw_line_palette_4;
- w->pixel_to_rgb =
- palette_data_format[exynos4210_fimd_palette_format(s, win)];
- break;
- case 3:
- w->draw_line = draw_line_palette_8;
- w->pixel_to_rgb =
- palette_data_format[exynos4210_fimd_palette_format(s, win)];
- break;
- case 4:
- w->draw_line = draw_line_8;
- w->pixel_to_rgb = pixel_a232_to_rgb;
- break;
- case 5:
- w->draw_line = draw_line_16;
- w->pixel_to_rgb = pixel_565_to_rgb;
- break;
- case 6:
- w->draw_line = draw_line_16;
- w->pixel_to_rgb = pixel_a555_to_rgb;
- break;
- case 7:
- w->draw_line = draw_line_16;
- w->pixel_to_rgb = pixel_1555_to_rgb;
- break;
- case 8:
- w->draw_line = draw_line_32;
- w->pixel_to_rgb = pixel_666_to_rgb;
- break;
- case 9:
- w->draw_line = draw_line_32;
- w->pixel_to_rgb = pixel_a665_to_rgb;
- break;
- case 10:
- w->draw_line = draw_line_32;
- w->pixel_to_rgb = pixel_a666_to_rgb;
- break;
- case 11:
- w->draw_line = draw_line_32;
- w->pixel_to_rgb = pixel_888_to_rgb;
- break;
- case 12:
- w->draw_line = draw_line_32;
- w->pixel_to_rgb = pixel_a887_to_rgb;
- break;
- case 13:
- w->draw_line = draw_line_32;
- if ((w->wincon & FIMD_WINCON_BLD_PIX) && (w->wincon &
- FIMD_WINCON_ALPHA_SEL)) {
- w->pixel_to_rgb = pixel_8888_to_rgb;
- } else {
- w->pixel_to_rgb = pixel_a888_to_rgb;
- }
- break;
- case 14:
- w->draw_line = draw_line_16;
- if ((w->wincon & FIMD_WINCON_BLD_PIX) && (w->wincon &
- FIMD_WINCON_ALPHA_SEL)) {
- w->pixel_to_rgb = pixel_4444_to_rgb;
- } else {
- w->pixel_to_rgb = pixel_a444_to_rgb;
- }
- break;
- case 15:
- w->draw_line = draw_line_16;
- w->pixel_to_rgb = pixel_555_to_rgb;
- break;
- }
-}
-
-#if EXYNOS4210_FIMD_MODE_TRACE > 0
-static const char *exynos4210_fimd_get_bppmode(int mode_code)
-{
- switch (mode_code) {
- case 0:
- return "1 bpp";
- case 1:
- return "2 bpp";
- case 2:
- return "4 bpp";
- case 3:
- return "8 bpp (palettized)";
- case 4:
- return "8 bpp (non-palettized, A: 1-R:2-G:3-B:2)";
- case 5:
- return "16 bpp (non-palettized, R:5-G:6-B:5)";
- case 6:
- return "16 bpp (non-palettized, A:1-R:5-G:5-B:5)";
- case 7:
- return "16 bpp (non-palettized, I :1-R:5-G:5-B:5)";
- case 8:
- return "Unpacked 18 bpp (non-palettized, R:6-G:6-B:6)";
- case 9:
- return "Unpacked 18bpp (non-palettized,A:1-R:6-G:6-B:5)";
- case 10:
- return "Unpacked 19bpp (non-palettized,A:1-R:6-G:6-B:6)";
- case 11:
- return "Unpacked 24 bpp (non-palettized R:8-G:8-B:8)";
- case 12:
- return "Unpacked 24 bpp (non-palettized A:1-R:8-G:8-B:7)";
- case 13:
- return "Unpacked 25 bpp (non-palettized A:1-R:8-G:8-B:8)";
- case 14:
- return "Unpacked 13 bpp (non-palettized A:1-R:4-G:4-B:4)";
- case 15:
- return "Unpacked 15 bpp (non-palettized R:5-G:5-B:5)";
- default:
- return "Non-existing bpp mode";
- }
-}
-
-static inline void exynos4210_fimd_trace_bppmode(Exynos4210fimdState *s,
- int win_num, uint32_t val)
-{
- Exynos4210fimdWindow *w = &s->window[win_num];
-
- if (w->winmap & FIMD_WINMAP_EN) {
- printf("QEMU FIMD: Window %d is mapped with MAPCOLOR=0x%x\n",
- win_num, w->winmap & 0xFFFFFF);
- return;
- }
-
- if ((val != 0xFFFFFFFF) && ((w->wincon >> 2) & 0xF) == ((val >> 2) & 0xF)) {
- return;
- }
- printf("QEMU FIMD: Window %d BPP mode set to %s\n", win_num,
- exynos4210_fimd_get_bppmode((val >> 2) & 0xF));
-}
-#else
-static inline void exynos4210_fimd_trace_bppmode(Exynos4210fimdState *s,
- int win_num, uint32_t val)
-{
-
-}
-#endif
-
-static inline int fimd_get_buffer_id(Exynos4210fimdWindow *w)
-{
- switch (w->wincon & FIMD_WINCON_BUFSTATUS) {
- case FIMD_WINCON_BUF0_STAT:
- return 0;
- case FIMD_WINCON_BUF1_STAT:
- return 1;
- case FIMD_WINCON_BUF2_STAT:
- return 2;
- default:
- DPRINT_ERROR("Non-existent buffer index\n");
- return 0;
- }
-}
-
-static void exynos4210_fimd_invalidate(void *opaque)
-{
- Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
- s->invalidate = true;
-}
-
-/* Updates specified window's MemorySection based on values of WINCON,
- * VIDOSDA, VIDOSDB, VIDWADDx and SHADOWCON registers */
-static void fimd_update_memory_section(Exynos4210fimdState *s, unsigned win)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(s);
- Exynos4210fimdWindow *w = &s->window[win];
- hwaddr fb_start_addr, fb_mapped_len;
-
- if (!s->enabled || !(w->wincon & FIMD_WINCON_ENWIN) ||
- FIMD_WINDOW_PROTECTED(s->shadowcon, win)) {
- return;
- }
-
- if (w->host_fb_addr) {
- cpu_physical_memory_unmap(w->host_fb_addr, w->fb_len, 0, 0);
- w->host_fb_addr = NULL;
- w->fb_len = 0;
- }
-
- fb_start_addr = w->buf_start[fimd_get_buffer_id(w)];
- /* Total number of bytes of virtual screen used by current window */
- w->fb_len = fb_mapped_len = (w->virtpage_width + w->virtpage_offsize) *
- (w->rightbot_y - w->lefttop_y + 1);
-
- /* TODO: add .exit and unref the region there. Not needed yet since sysbus
- * does not support hot-unplug.
- */
- if (w->mem_section.mr) {
- memory_region_set_log(w->mem_section.mr, false, DIRTY_MEMORY_VGA);
- memory_region_unref(w->mem_section.mr);
- }
-
- w->mem_section = memory_region_find(sysbus_address_space(sbd),
- fb_start_addr, w->fb_len);
- assert(w->mem_section.mr);
- assert(w->mem_section.offset_within_address_space == fb_start_addr);
- DPRINT_TRACE("Window %u framebuffer changed: address=0x%08x, len=0x%x\n",
- win, fb_start_addr, w->fb_len);
-
- if (int128_get64(w->mem_section.size) != w->fb_len ||
- !memory_region_is_ram(w->mem_section.mr)) {
- DPRINT_ERROR("Failed to find window %u framebuffer region\n", win);
- goto error_return;
- }
-
- w->host_fb_addr = cpu_physical_memory_map(fb_start_addr, &fb_mapped_len, 0);
- if (!w->host_fb_addr) {
- DPRINT_ERROR("Failed to map window %u framebuffer\n", win);
- goto error_return;
- }
-
- if (fb_mapped_len != w->fb_len) {
- DPRINT_ERROR("Window %u mapped framebuffer length is less then "
- "expected\n", win);
- cpu_physical_memory_unmap(w->host_fb_addr, fb_mapped_len, 0, 0);
- goto error_return;
- }
- memory_region_set_log(w->mem_section.mr, true, DIRTY_MEMORY_VGA);
- exynos4210_fimd_invalidate(s);
- return;
-
-error_return:
- memory_region_unref(w->mem_section.mr);
- w->mem_section.mr = NULL;
- w->mem_section.size = int128_zero();
- w->host_fb_addr = NULL;
- w->fb_len = 0;
-}
-
-static void exynos4210_fimd_enable(Exynos4210fimdState *s, bool enabled)
-{
- if (enabled && !s->enabled) {
- unsigned w;
- s->enabled = true;
- for (w = 0; w < NUM_OF_WINDOWS; w++) {
- fimd_update_memory_section(s, w);
- }
- }
- s->enabled = enabled;
- DPRINT_TRACE("display controller %s\n", enabled ? "enabled" : "disabled");
-}
-
-static inline uint32_t unpack_upper_4(uint32_t x)
-{
- return ((x & 0xF00) << 12) | ((x & 0xF0) << 8) | ((x & 0xF) << 4);
-}
-
-static inline uint32_t pack_upper_4(uint32_t x)
-{
- return (((x & 0xF00000) >> 12) | ((x & 0xF000) >> 8) |
- ((x & 0xF0) >> 4)) & 0xFFF;
-}
-
-static void exynos4210_fimd_update_irq(Exynos4210fimdState *s)
-{
- if (!(s->vidintcon[0] & FIMD_VIDINT_INTEN)) {
- qemu_irq_lower(s->irq[0]);
- qemu_irq_lower(s->irq[1]);
- qemu_irq_lower(s->irq[2]);
- return;
- }
- if ((s->vidintcon[0] & FIMD_VIDINT_INTFIFOEN) &&
- (s->vidintcon[1] & FIMD_VIDINT_INTFIFOPEND)) {
- qemu_irq_raise(s->irq[0]);
- } else {
- qemu_irq_lower(s->irq[0]);
- }
- if ((s->vidintcon[0] & FIMD_VIDINT_INTFRMEN) &&
- (s->vidintcon[1] & FIMD_VIDINT_INTFRMPEND)) {
- qemu_irq_raise(s->irq[1]);
- } else {
- qemu_irq_lower(s->irq[1]);
- }
- if ((s->vidintcon[0] & FIMD_VIDINT_I80IFDONE) &&
- (s->vidintcon[1] & FIMD_VIDINT_INTI80PEND)) {
- qemu_irq_raise(s->irq[2]);
- } else {
- qemu_irq_lower(s->irq[2]);
- }
-}
-
-static void exynos4210_update_resolution(Exynos4210fimdState *s)
-{
- DisplaySurface *surface = qemu_console_surface(s->console);
-
- /* LCD resolution is stored in VIDEO TIME CONTROL REGISTER 2 */
- uint32_t width = ((s->vidtcon[2] >> FIMD_VIDTCON2_HOR_SHIFT) &
- FIMD_VIDTCON2_SIZE_MASK) + 1;
- uint32_t height = ((s->vidtcon[2] >> FIMD_VIDTCON2_VER_SHIFT) &
- FIMD_VIDTCON2_SIZE_MASK) + 1;
-
- if (s->ifb == NULL || surface_width(surface) != width ||
- surface_height(surface) != height) {
- DPRINT_L1("Resolution changed from %ux%u to %ux%u\n",
- surface_width(surface), surface_height(surface), width, height);
- qemu_console_resize(s->console, width, height);
- s->ifb = g_realloc(s->ifb, width * height * RGBA_SIZE + 1);
- memset(s->ifb, 0, width * height * RGBA_SIZE + 1);
- exynos4210_fimd_invalidate(s);
- }
-}
-
-static void exynos4210_fimd_update(void *opaque)
-{
- Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
- DisplaySurface *surface;
- Exynos4210fimdWindow *w;
- int i, line;
- hwaddr fb_line_addr, inc_size;
- int scrn_height;
- int first_line = -1, last_line = -1, scrn_width;
- bool blend = false;
- uint8_t *host_fb_addr;
- bool is_dirty = false;
- const int global_width = (s->vidtcon[2] & FIMD_VIDTCON2_SIZE_MASK) + 1;
- const int global_height = ((s->vidtcon[2] >> FIMD_VIDTCON2_VER_SHIFT) &
- FIMD_VIDTCON2_SIZE_MASK) + 1;
-
- if (!s || !s->console || !s->enabled ||
- surface_bits_per_pixel(qemu_console_surface(s->console)) == 0) {
- return;
- }
- exynos4210_update_resolution(s);
- surface = qemu_console_surface(s->console);
-
- for (i = 0; i < NUM_OF_WINDOWS; i++) {
- w = &s->window[i];
- if ((w->wincon & FIMD_WINCON_ENWIN) && w->host_fb_addr) {
- scrn_height = w->rightbot_y - w->lefttop_y + 1;
- scrn_width = w->virtpage_width;
- /* Total width of virtual screen page in bytes */
- inc_size = scrn_width + w->virtpage_offsize;
- memory_region_sync_dirty_bitmap(w->mem_section.mr);
- host_fb_addr = w->host_fb_addr;
- fb_line_addr = w->mem_section.offset_within_region;
-
- for (line = 0; line < scrn_height; line++) {
- is_dirty = memory_region_get_dirty(w->mem_section.mr,
- fb_line_addr, scrn_width, DIRTY_MEMORY_VGA);
-
- if (s->invalidate || is_dirty) {
- if (first_line == -1) {
- first_line = line;
- }
- last_line = line;
- w->draw_line(w, host_fb_addr, s->ifb +
- w->lefttop_x * RGBA_SIZE + (w->lefttop_y + line) *
- global_width * RGBA_SIZE, blend);
- }
- host_fb_addr += inc_size;
- fb_line_addr += inc_size;
- is_dirty = false;
- }
- memory_region_reset_dirty(w->mem_section.mr,
- w->mem_section.offset_within_region,
- w->fb_len, DIRTY_MEMORY_VGA);
- blend = true;
- }
- }
-
- /* Copy resulting image to QEMU_CONSOLE. */
- if (first_line >= 0) {
- uint8_t *d;
- int bpp;
-
- bpp = surface_bits_per_pixel(surface);
- fimd_update_putpix_qemu(bpp);
- bpp = (bpp + 1) >> 3;
- d = surface_data(surface);
- for (line = first_line; line <= last_line; line++) {
- fimd_copy_line_toqemu(global_width, s->ifb + global_width * line *
- RGBA_SIZE, d + global_width * line * bpp);
- }
- dpy_gfx_update(s->console, 0, 0, global_width, global_height);
- }
- s->invalidate = false;
- s->vidintcon[1] |= FIMD_VIDINT_INTFRMPEND;
- if ((s->vidcon[0] & FIMD_VIDCON0_ENVID_F) == 0) {
- exynos4210_fimd_enable(s, false);
- }
- exynos4210_fimd_update_irq(s);
-}
-
-static void exynos4210_fimd_reset(DeviceState *d)
-{
- Exynos4210fimdState *s = EXYNOS4210_FIMD(d);
- unsigned w;
-
- DPRINT_TRACE("Display controller reset\n");
- /* Set all display controller registers to 0 */
- memset(&s->vidcon, 0, (uint8_t *)&s->window - (uint8_t *)&s->vidcon);
- for (w = 0; w < NUM_OF_WINDOWS; w++) {
- memset(&s->window[w], 0, sizeof(Exynos4210fimdWindow));
- s->window[w].blendeq = 0xC2;
- exynos4210_fimd_update_win_bppmode(s, w);
- exynos4210_fimd_trace_bppmode(s, w, 0xFFFFFFFF);
- fimd_update_get_alpha(s, w);
- }
-
- g_free(s->ifb);
- s->ifb = NULL;
-
- exynos4210_fimd_invalidate(s);
- exynos4210_fimd_enable(s, false);
- /* Some registers have non-zero initial values */
- s->winchmap = 0x7D517D51;
- s->colorgaincon = 0x10040100;
- s->huecoef_cr[0] = s->huecoef_cr[3] = 0x01000100;
- s->huecoef_cb[0] = s->huecoef_cb[3] = 0x01000100;
- s->hueoffset = 0x01800080;
-}
-
-static void exynos4210_fimd_write(void *opaque, hwaddr offset,
- uint64_t val, unsigned size)
-{
- Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
- unsigned w, i;
- uint32_t old_value;
-
- DPRINT_L2("write offset 0x%08x, value=%llu(0x%08llx)\n", offset,
- (long long unsigned int)val, (long long unsigned int)val);
-
- switch (offset) {
- case FIMD_VIDCON0:
- if ((val & FIMD_VIDCON0_ENVID_MASK) == FIMD_VIDCON0_ENVID_MASK) {
- exynos4210_fimd_enable(s, true);
- } else {
- if ((val & FIMD_VIDCON0_ENVID) == 0) {
- exynos4210_fimd_enable(s, false);
- }
- }
- s->vidcon[0] = val;
- break;
- case FIMD_VIDCON1:
- /* Leave read-only bits as is */
- val = (val & (~FIMD_VIDCON1_ROMASK)) |
- (s->vidcon[1] & FIMD_VIDCON1_ROMASK);
- s->vidcon[1] = val;
- break;
- case FIMD_VIDCON2 ... FIMD_VIDCON3:
- s->vidcon[(offset) >> 2] = val;
- break;
- case FIMD_VIDTCON_START ... FIMD_VIDTCON_END:
- s->vidtcon[(offset - FIMD_VIDTCON_START) >> 2] = val;
- break;
- case FIMD_WINCON_START ... FIMD_WINCON_END:
- w = (offset - FIMD_WINCON_START) >> 2;
- /* Window's current buffer ID */
- i = fimd_get_buffer_id(&s->window[w]);
- old_value = s->window[w].wincon;
- val = (val & ~FIMD_WINCON_ROMASK) |
- (s->window[w].wincon & FIMD_WINCON_ROMASK);
- if (w == 0) {
- /* Window 0 wincon ALPHA_MUL bit must always be 0 */
- val &= ~FIMD_WINCON_ALPHA_MUL;
- }
- exynos4210_fimd_trace_bppmode(s, w, val);
- switch (val & FIMD_WINCON_BUFSELECT) {
- case FIMD_WINCON_BUF0_SEL:
- val &= ~FIMD_WINCON_BUFSTATUS;
- break;
- case FIMD_WINCON_BUF1_SEL:
- val = (val & ~FIMD_WINCON_BUFSTAT_H) | FIMD_WINCON_BUFSTAT_L;
- break;
- case FIMD_WINCON_BUF2_SEL:
- if (val & FIMD_WINCON_BUFMODE) {
- val = (val & ~FIMD_WINCON_BUFSTAT_L) | FIMD_WINCON_BUFSTAT_H;
- }
- break;
- default:
- break;
- }
- s->window[w].wincon = val;
- exynos4210_fimd_update_win_bppmode(s, w);
- fimd_update_get_alpha(s, w);
- if ((i != fimd_get_buffer_id(&s->window[w])) ||
- (!(old_value & FIMD_WINCON_ENWIN) && (s->window[w].wincon &
- FIMD_WINCON_ENWIN))) {
- fimd_update_memory_section(s, w);
- }
- break;
- case FIMD_SHADOWCON:
- old_value = s->shadowcon;
- s->shadowcon = val;
- for (w = 0; w < NUM_OF_WINDOWS; w++) {
- if (FIMD_WINDOW_PROTECTED(old_value, w) &&
- !FIMD_WINDOW_PROTECTED(s->shadowcon, w)) {
- fimd_update_memory_section(s, w);
- }
- }
- break;
- case FIMD_WINCHMAP:
- s->winchmap = val;
- break;
- case FIMD_VIDOSD_START ... FIMD_VIDOSD_END:
- w = (offset - FIMD_VIDOSD_START) >> 4;
- i = ((offset - FIMD_VIDOSD_START) & 0xF) >> 2;
- switch (i) {
- case 0:
- old_value = s->window[w].lefttop_y;
- s->window[w].lefttop_x = (val >> FIMD_VIDOSD_HOR_SHIFT) &
- FIMD_VIDOSD_COORD_MASK;
- s->window[w].lefttop_y = (val >> FIMD_VIDOSD_VER_SHIFT) &
- FIMD_VIDOSD_COORD_MASK;
- if (s->window[w].lefttop_y != old_value) {
- fimd_update_memory_section(s, w);
- }
- break;
- case 1:
- old_value = s->window[w].rightbot_y;
- s->window[w].rightbot_x = (val >> FIMD_VIDOSD_HOR_SHIFT) &
- FIMD_VIDOSD_COORD_MASK;
- s->window[w].rightbot_y = (val >> FIMD_VIDOSD_VER_SHIFT) &
- FIMD_VIDOSD_COORD_MASK;
- if (s->window[w].rightbot_y != old_value) {
- fimd_update_memory_section(s, w);
- }
- break;
- case 2:
- if (w == 0) {
- s->window[w].osdsize = val;
- } else {
- s->window[w].alpha_val[0] =
- unpack_upper_4((val & FIMD_VIDOSD_ALPHA_AEN0) >>
- FIMD_VIDOSD_AEN0_SHIFT) |
- (s->window[w].alpha_val[0] & FIMD_VIDALPHA_ALPHA_LOWER);
- s->window[w].alpha_val[1] =
- unpack_upper_4(val & FIMD_VIDOSD_ALPHA_AEN1) |
- (s->window[w].alpha_val[1] & FIMD_VIDALPHA_ALPHA_LOWER);
- }
- break;
- case 3:
- if (w != 1 && w != 2) {
- DPRINT_ERROR("Bad write offset 0x%08x\n", offset);
- return;
- }
- s->window[w].osdsize = val;
- break;
- }
- break;
- case FIMD_VIDWADD0_START ... FIMD_VIDWADD0_END:
- w = (offset - FIMD_VIDWADD0_START) >> 3;
- i = ((offset - FIMD_VIDWADD0_START) >> 2) & 1;
- if (i == fimd_get_buffer_id(&s->window[w]) &&
- s->window[w].buf_start[i] != val) {
- s->window[w].buf_start[i] = val;
- fimd_update_memory_section(s, w);
- break;
- }
- s->window[w].buf_start[i] = val;
- break;
- case FIMD_VIDWADD1_START ... FIMD_VIDWADD1_END:
- w = (offset - FIMD_VIDWADD1_START) >> 3;
- i = ((offset - FIMD_VIDWADD1_START) >> 2) & 1;
- s->window[w].buf_end[i] = val;
- break;
- case FIMD_VIDWADD2_START ... FIMD_VIDWADD2_END:
- w = (offset - FIMD_VIDWADD2_START) >> 2;
- if (((val & FIMD_VIDWADD2_PAGEWIDTH) != s->window[w].virtpage_width) ||
- (((val >> FIMD_VIDWADD2_OFFSIZE_SHIFT) & FIMD_VIDWADD2_OFFSIZE) !=
- s->window[w].virtpage_offsize)) {
- s->window[w].virtpage_width = val & FIMD_VIDWADD2_PAGEWIDTH;
- s->window[w].virtpage_offsize =
- (val >> FIMD_VIDWADD2_OFFSIZE_SHIFT) & FIMD_VIDWADD2_OFFSIZE;
- fimd_update_memory_section(s, w);
- }
- break;
- case FIMD_VIDINTCON0:
- s->vidintcon[0] = val;
- break;
- case FIMD_VIDINTCON1:
- s->vidintcon[1] &= ~(val & 7);
- exynos4210_fimd_update_irq(s);
- break;
- case FIMD_WKEYCON_START ... FIMD_WKEYCON_END:
- w = ((offset - FIMD_WKEYCON_START) >> 3) + 1;
- i = ((offset - FIMD_WKEYCON_START) >> 2) & 1;
- s->window[w].keycon[i] = val;
- break;
- case FIMD_WKEYALPHA_START ... FIMD_WKEYALPHA_END:
- w = ((offset - FIMD_WKEYALPHA_START) >> 2) + 1;
- s->window[w].keyalpha = val;
- break;
- case FIMD_DITHMODE:
- s->dithmode = val;
- break;
- case FIMD_WINMAP_START ... FIMD_WINMAP_END:
- w = (offset - FIMD_WINMAP_START) >> 2;
- old_value = s->window[w].winmap;
- s->window[w].winmap = val;
- if ((val & FIMD_WINMAP_EN) ^ (old_value & FIMD_WINMAP_EN)) {
- exynos4210_fimd_invalidate(s);
- exynos4210_fimd_update_win_bppmode(s, w);
- exynos4210_fimd_trace_bppmode(s, w, 0xFFFFFFFF);
- exynos4210_fimd_update(s);
- }
- break;
- case FIMD_WPALCON_HIGH ... FIMD_WPALCON_LOW:
- i = (offset - FIMD_WPALCON_HIGH) >> 2;
- s->wpalcon[i] = val;
- if (s->wpalcon[1] & FIMD_WPALCON_UPDATEEN) {
- for (w = 0; w < NUM_OF_WINDOWS; w++) {
- exynos4210_fimd_update_win_bppmode(s, w);
- fimd_update_get_alpha(s, w);
- }
- }
- break;
- case FIMD_TRIGCON:
- val = (val & ~FIMD_TRIGCON_ROMASK) | (s->trigcon & FIMD_TRIGCON_ROMASK);
- s->trigcon = val;
- break;
- case FIMD_I80IFCON_START ... FIMD_I80IFCON_END:
- s->i80ifcon[(offset - FIMD_I80IFCON_START) >> 2] = val;
- break;
- case FIMD_COLORGAINCON:
- s->colorgaincon = val;
- break;
- case FIMD_LDI_CMDCON0 ... FIMD_LDI_CMDCON1:
- s->ldi_cmdcon[(offset - FIMD_LDI_CMDCON0) >> 2] = val;
- break;
- case FIMD_SIFCCON0 ... FIMD_SIFCCON2:
- i = (offset - FIMD_SIFCCON0) >> 2;
- if (i != 2) {
- s->sifccon[i] = val;
- }
- break;
- case FIMD_HUECOEFCR_START ... FIMD_HUECOEFCR_END:
- i = (offset - FIMD_HUECOEFCR_START) >> 2;
- s->huecoef_cr[i] = val;
- break;
- case FIMD_HUECOEFCB_START ... FIMD_HUECOEFCB_END:
- i = (offset - FIMD_HUECOEFCB_START) >> 2;
- s->huecoef_cb[i] = val;
- break;
- case FIMD_HUEOFFSET:
- s->hueoffset = val;
- break;
- case FIMD_VIDWALPHA_START ... FIMD_VIDWALPHA_END:
- w = ((offset - FIMD_VIDWALPHA_START) >> 3);
- i = ((offset - FIMD_VIDWALPHA_START) >> 2) & 1;
- if (w == 0) {
- s->window[w].alpha_val[i] = val;
- } else {
- s->window[w].alpha_val[i] = (val & FIMD_VIDALPHA_ALPHA_LOWER) |
- (s->window[w].alpha_val[i] & FIMD_VIDALPHA_ALPHA_UPPER);
- }
- break;
- case FIMD_BLENDEQ_START ... FIMD_BLENDEQ_END:
- s->window[(offset - FIMD_BLENDEQ_START) >> 2].blendeq = val;
- break;
- case FIMD_BLENDCON:
- old_value = s->blendcon;
- s->blendcon = val;
- if ((s->blendcon & FIMD_ALPHA_8BIT) != (old_value & FIMD_ALPHA_8BIT)) {
- for (w = 0; w < NUM_OF_WINDOWS; w++) {
- fimd_update_get_alpha(s, w);
- }
- }
- break;
- case FIMD_WRTQOSCON_START ... FIMD_WRTQOSCON_END:
- s->window[(offset - FIMD_WRTQOSCON_START) >> 2].rtqoscon = val;
- break;
- case FIMD_I80IFCMD_START ... FIMD_I80IFCMD_END:
- s->i80ifcmd[(offset - FIMD_I80IFCMD_START) >> 2] = val;
- break;
- case FIMD_VIDW0ADD0_B2 ... FIMD_VIDW4ADD0_B2:
- if (offset & 0x0004) {
- DPRINT_ERROR("bad write offset 0x%08x\n", offset);
- break;
- }
- w = (offset - FIMD_VIDW0ADD0_B2) >> 3;
- if (fimd_get_buffer_id(&s->window[w]) == 2 &&
- s->window[w].buf_start[2] != val) {
- s->window[w].buf_start[2] = val;
- fimd_update_memory_section(s, w);
- break;
- }
- s->window[w].buf_start[2] = val;
- break;
- case FIMD_SHD_ADD0_START ... FIMD_SHD_ADD0_END:
- if (offset & 0x0004) {
- DPRINT_ERROR("bad write offset 0x%08x\n", offset);
- break;
- }
- s->window[(offset - FIMD_SHD_ADD0_START) >> 3].shadow_buf_start = val;
- break;
- case FIMD_SHD_ADD1_START ... FIMD_SHD_ADD1_END:
- if (offset & 0x0004) {
- DPRINT_ERROR("bad write offset 0x%08x\n", offset);
- break;
- }
- s->window[(offset - FIMD_SHD_ADD1_START) >> 3].shadow_buf_end = val;
- break;
- case FIMD_SHD_ADD2_START ... FIMD_SHD_ADD2_END:
- s->window[(offset - FIMD_SHD_ADD2_START) >> 2].shadow_buf_size = val;
- break;
- case FIMD_PAL_MEM_START ... FIMD_PAL_MEM_END:
- w = (offset - FIMD_PAL_MEM_START) >> 10;
- i = ((offset - FIMD_PAL_MEM_START) >> 2) & 0xFF;
- s->window[w].palette[i] = val;
- break;
- case FIMD_PALMEM_AL_START ... FIMD_PALMEM_AL_END:
- /* Palette memory aliases for windows 0 and 1 */
- w = (offset - FIMD_PALMEM_AL_START) >> 10;
- i = ((offset - FIMD_PALMEM_AL_START) >> 2) & 0xFF;
- s->window[w].palette[i] = val;
- break;
- default:
- DPRINT_ERROR("bad write offset 0x%08x\n", offset);
- break;
- }
-}
-
-static uint64_t exynos4210_fimd_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
- int w, i;
- uint32_t ret = 0;
-
- DPRINT_L2("read offset 0x%08x\n", offset);
-
- switch (offset) {
- case FIMD_VIDCON0 ... FIMD_VIDCON3:
- return s->vidcon[(offset - FIMD_VIDCON0) >> 2];
- case FIMD_VIDTCON_START ... FIMD_VIDTCON_END:
- return s->vidtcon[(offset - FIMD_VIDTCON_START) >> 2];
- case FIMD_WINCON_START ... FIMD_WINCON_END:
- return s->window[(offset - FIMD_WINCON_START) >> 2].wincon;
- case FIMD_SHADOWCON:
- return s->shadowcon;
- case FIMD_WINCHMAP:
- return s->winchmap;
- case FIMD_VIDOSD_START ... FIMD_VIDOSD_END:
- w = (offset - FIMD_VIDOSD_START) >> 4;
- i = ((offset - FIMD_VIDOSD_START) & 0xF) >> 2;
- switch (i) {
- case 0:
- ret = ((s->window[w].lefttop_x & FIMD_VIDOSD_COORD_MASK) <<
- FIMD_VIDOSD_HOR_SHIFT) |
- (s->window[w].lefttop_y & FIMD_VIDOSD_COORD_MASK);
- break;
- case 1:
- ret = ((s->window[w].rightbot_x & FIMD_VIDOSD_COORD_MASK) <<
- FIMD_VIDOSD_HOR_SHIFT) |
- (s->window[w].rightbot_y & FIMD_VIDOSD_COORD_MASK);
- break;
- case 2:
- if (w == 0) {
- ret = s->window[w].osdsize;
- } else {
- ret = (pack_upper_4(s->window[w].alpha_val[0]) <<
- FIMD_VIDOSD_AEN0_SHIFT) |
- pack_upper_4(s->window[w].alpha_val[1]);
- }
- break;
- case 3:
- if (w != 1 && w != 2) {
- DPRINT_ERROR("bad read offset 0x%08x\n", offset);
- return 0xBAADBAAD;
- }
- ret = s->window[w].osdsize;
- break;
- }
- return ret;
- case FIMD_VIDWADD0_START ... FIMD_VIDWADD0_END:
- w = (offset - FIMD_VIDWADD0_START) >> 3;
- i = ((offset - FIMD_VIDWADD0_START) >> 2) & 1;
- return s->window[w].buf_start[i];
- case FIMD_VIDWADD1_START ... FIMD_VIDWADD1_END:
- w = (offset - FIMD_VIDWADD1_START) >> 3;
- i = ((offset - FIMD_VIDWADD1_START) >> 2) & 1;
- return s->window[w].buf_end[i];
- case FIMD_VIDWADD2_START ... FIMD_VIDWADD2_END:
- w = (offset - FIMD_VIDWADD2_START) >> 2;
- return s->window[w].virtpage_width | (s->window[w].virtpage_offsize <<
- FIMD_VIDWADD2_OFFSIZE_SHIFT);
- case FIMD_VIDINTCON0 ... FIMD_VIDINTCON1:
- return s->vidintcon[(offset - FIMD_VIDINTCON0) >> 2];
- case FIMD_WKEYCON_START ... FIMD_WKEYCON_END:
- w = ((offset - FIMD_WKEYCON_START) >> 3) + 1;
- i = ((offset - FIMD_WKEYCON_START) >> 2) & 1;
- return s->window[w].keycon[i];
- case FIMD_WKEYALPHA_START ... FIMD_WKEYALPHA_END:
- w = ((offset - FIMD_WKEYALPHA_START) >> 2) + 1;
- return s->window[w].keyalpha;
- case FIMD_DITHMODE:
- return s->dithmode;
- case FIMD_WINMAP_START ... FIMD_WINMAP_END:
- return s->window[(offset - FIMD_WINMAP_START) >> 2].winmap;
- case FIMD_WPALCON_HIGH ... FIMD_WPALCON_LOW:
- return s->wpalcon[(offset - FIMD_WPALCON_HIGH) >> 2];
- case FIMD_TRIGCON:
- return s->trigcon;
- case FIMD_I80IFCON_START ... FIMD_I80IFCON_END:
- return s->i80ifcon[(offset - FIMD_I80IFCON_START) >> 2];
- case FIMD_COLORGAINCON:
- return s->colorgaincon;
- case FIMD_LDI_CMDCON0 ... FIMD_LDI_CMDCON1:
- return s->ldi_cmdcon[(offset - FIMD_LDI_CMDCON0) >> 2];
- case FIMD_SIFCCON0 ... FIMD_SIFCCON2:
- i = (offset - FIMD_SIFCCON0) >> 2;
- return s->sifccon[i];
- case FIMD_HUECOEFCR_START ... FIMD_HUECOEFCR_END:
- i = (offset - FIMD_HUECOEFCR_START) >> 2;
- return s->huecoef_cr[i];
- case FIMD_HUECOEFCB_START ... FIMD_HUECOEFCB_END:
- i = (offset - FIMD_HUECOEFCB_START) >> 2;
- return s->huecoef_cb[i];
- case FIMD_HUEOFFSET:
- return s->hueoffset;
- case FIMD_VIDWALPHA_START ... FIMD_VIDWALPHA_END:
- w = ((offset - FIMD_VIDWALPHA_START) >> 3);
- i = ((offset - FIMD_VIDWALPHA_START) >> 2) & 1;
- return s->window[w].alpha_val[i] &
- (w == 0 ? 0xFFFFFF : FIMD_VIDALPHA_ALPHA_LOWER);
- case FIMD_BLENDEQ_START ... FIMD_BLENDEQ_END:
- return s->window[(offset - FIMD_BLENDEQ_START) >> 2].blendeq;
- case FIMD_BLENDCON:
- return s->blendcon;
- case FIMD_WRTQOSCON_START ... FIMD_WRTQOSCON_END:
- return s->window[(offset - FIMD_WRTQOSCON_START) >> 2].rtqoscon;
- case FIMD_I80IFCMD_START ... FIMD_I80IFCMD_END:
- return s->i80ifcmd[(offset - FIMD_I80IFCMD_START) >> 2];
- case FIMD_VIDW0ADD0_B2 ... FIMD_VIDW4ADD0_B2:
- if (offset & 0x0004) {
- break;
- }
- return s->window[(offset - FIMD_VIDW0ADD0_B2) >> 3].buf_start[2];
- case FIMD_SHD_ADD0_START ... FIMD_SHD_ADD0_END:
- if (offset & 0x0004) {
- break;
- }
- return s->window[(offset - FIMD_SHD_ADD0_START) >> 3].shadow_buf_start;
- case FIMD_SHD_ADD1_START ... FIMD_SHD_ADD1_END:
- if (offset & 0x0004) {
- break;
- }
- return s->window[(offset - FIMD_SHD_ADD1_START) >> 3].shadow_buf_end;
- case FIMD_SHD_ADD2_START ... FIMD_SHD_ADD2_END:
- return s->window[(offset - FIMD_SHD_ADD2_START) >> 2].shadow_buf_size;
- case FIMD_PAL_MEM_START ... FIMD_PAL_MEM_END:
- w = (offset - FIMD_PAL_MEM_START) >> 10;
- i = ((offset - FIMD_PAL_MEM_START) >> 2) & 0xFF;
- return s->window[w].palette[i];
- case FIMD_PALMEM_AL_START ... FIMD_PALMEM_AL_END:
- /* Palette aliases for win 0,1 */
- w = (offset - FIMD_PALMEM_AL_START) >> 10;
- i = ((offset - FIMD_PALMEM_AL_START) >> 2) & 0xFF;
- return s->window[w].palette[i];
- }
-
- DPRINT_ERROR("bad read offset 0x%08x\n", offset);
- return 0xBAADBAAD;
-}
-
-static const MemoryRegionOps exynos4210_fimd_mmio_ops = {
- .read = exynos4210_fimd_read,
- .write = exynos4210_fimd_write,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- .unaligned = false
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int exynos4210_fimd_load(void *opaque, int version_id)
-{
- Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
- int w;
-
- if (version_id != 1) {
- return -EINVAL;
- }
-
- for (w = 0; w < NUM_OF_WINDOWS; w++) {
- exynos4210_fimd_update_win_bppmode(s, w);
- fimd_update_get_alpha(s, w);
- fimd_update_memory_section(s, w);
- }
-
- /* Redraw the whole screen */
- exynos4210_update_resolution(s);
- exynos4210_fimd_invalidate(s);
- exynos4210_fimd_enable(s, (s->vidcon[0] & FIMD_VIDCON0_ENVID_MASK) ==
- FIMD_VIDCON0_ENVID_MASK);
- return 0;
-}
-
-static const VMStateDescription exynos4210_fimd_window_vmstate = {
- .name = "exynos4210.fimd_window",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(wincon, Exynos4210fimdWindow),
- VMSTATE_UINT32_ARRAY(buf_start, Exynos4210fimdWindow, 3),
- VMSTATE_UINT32_ARRAY(buf_end, Exynos4210fimdWindow, 3),
- VMSTATE_UINT32_ARRAY(keycon, Exynos4210fimdWindow, 2),
- VMSTATE_UINT32(keyalpha, Exynos4210fimdWindow),
- VMSTATE_UINT32(winmap, Exynos4210fimdWindow),
- VMSTATE_UINT32(blendeq, Exynos4210fimdWindow),
- VMSTATE_UINT32(rtqoscon, Exynos4210fimdWindow),
- VMSTATE_UINT32_ARRAY(palette, Exynos4210fimdWindow, 256),
- VMSTATE_UINT32(shadow_buf_start, Exynos4210fimdWindow),
- VMSTATE_UINT32(shadow_buf_end, Exynos4210fimdWindow),
- VMSTATE_UINT32(shadow_buf_size, Exynos4210fimdWindow),
- VMSTATE_UINT16(lefttop_x, Exynos4210fimdWindow),
- VMSTATE_UINT16(lefttop_y, Exynos4210fimdWindow),
- VMSTATE_UINT16(rightbot_x, Exynos4210fimdWindow),
- VMSTATE_UINT16(rightbot_y, Exynos4210fimdWindow),
- VMSTATE_UINT32(osdsize, Exynos4210fimdWindow),
- VMSTATE_UINT32_ARRAY(alpha_val, Exynos4210fimdWindow, 2),
- VMSTATE_UINT16(virtpage_width, Exynos4210fimdWindow),
- VMSTATE_UINT16(virtpage_offsize, Exynos4210fimdWindow),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription exynos4210_fimd_vmstate = {
- .name = "exynos4210.fimd",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = exynos4210_fimd_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(vidcon, Exynos4210fimdState, 4),
- VMSTATE_UINT32_ARRAY(vidtcon, Exynos4210fimdState, 4),
- VMSTATE_UINT32(shadowcon, Exynos4210fimdState),
- VMSTATE_UINT32(winchmap, Exynos4210fimdState),
- VMSTATE_UINT32_ARRAY(vidintcon, Exynos4210fimdState, 2),
- VMSTATE_UINT32(dithmode, Exynos4210fimdState),
- VMSTATE_UINT32_ARRAY(wpalcon, Exynos4210fimdState, 2),
- VMSTATE_UINT32(trigcon, Exynos4210fimdState),
- VMSTATE_UINT32_ARRAY(i80ifcon, Exynos4210fimdState, 4),
- VMSTATE_UINT32(colorgaincon, Exynos4210fimdState),
- VMSTATE_UINT32_ARRAY(ldi_cmdcon, Exynos4210fimdState, 2),
- VMSTATE_UINT32_ARRAY(sifccon, Exynos4210fimdState, 3),
- VMSTATE_UINT32_ARRAY(huecoef_cr, Exynos4210fimdState, 4),
- VMSTATE_UINT32_ARRAY(huecoef_cb, Exynos4210fimdState, 4),
- VMSTATE_UINT32(hueoffset, Exynos4210fimdState),
- VMSTATE_UINT32_ARRAY(i80ifcmd, Exynos4210fimdState, 12),
- VMSTATE_UINT32(blendcon, Exynos4210fimdState),
- VMSTATE_STRUCT_ARRAY(window, Exynos4210fimdState, 5, 1,
- exynos4210_fimd_window_vmstate, Exynos4210fimdWindow),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const GraphicHwOps exynos4210_fimd_ops = {
- .invalidate = exynos4210_fimd_invalidate,
- .gfx_update = exynos4210_fimd_update,
-};
-
-static int exynos4210_fimd_init(SysBusDevice *dev)
-{
- Exynos4210fimdState *s = EXYNOS4210_FIMD(dev);
-
- s->ifb = NULL;
-
- sysbus_init_irq(dev, &s->irq[0]);
- sysbus_init_irq(dev, &s->irq[1]);
- sysbus_init_irq(dev, &s->irq[2]);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &exynos4210_fimd_mmio_ops, s,
- "exynos4210.fimd", FIMD_REGS_SIZE);
- sysbus_init_mmio(dev, &s->iomem);
- s->console = graphic_console_init(DEVICE(dev), 0, &exynos4210_fimd_ops, s);
-
- return 0;
-}
-
-static void exynos4210_fimd_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- dc->vmsd = &exynos4210_fimd_vmstate;
- dc->reset = exynos4210_fimd_reset;
- k->init = exynos4210_fimd_init;
-}
-
-static const TypeInfo exynos4210_fimd_info = {
- .name = TYPE_EXYNOS4210_FIMD,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(Exynos4210fimdState),
- .class_init = exynos4210_fimd_class_init,
-};
-
-static void exynos4210_fimd_register_types(void)
-{
- type_register_static(&exynos4210_fimd_info);
-}
-
-type_init(exynos4210_fimd_register_types)
diff --git a/qemu/hw/display/framebuffer.c b/qemu/hw/display/framebuffer.c
deleted file mode 100644
index df51358e7..000000000
--- a/qemu/hw/display/framebuffer.c
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Framebuffer device helper routines
- *
- * Copyright (c) 2009 CodeSourcery
- * Written by Paul Brook <paul@codesourcery.com>
- *
- * This code is licensed under the GNU GPLv2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-/* TODO:
- - Do something similar for framebuffers with local ram
- - Handle rotation here instead of hacking dest_pitch
- - Use common pixel conversion routines instead of per-device drawfn
- - Remove all DisplayState knowledge from devices.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "ui/console.h"
-#include "framebuffer.h"
-
-void framebuffer_update_memory_section(
- MemoryRegionSection *mem_section,
- MemoryRegion *root,
- hwaddr base,
- unsigned rows,
- unsigned src_width)
-{
- hwaddr src_len = (hwaddr)rows * src_width;
-
- if (mem_section->mr) {
- memory_region_set_log(mem_section->mr, false, DIRTY_MEMORY_VGA);
- memory_region_unref(mem_section->mr);
- mem_section->mr = NULL;
- }
-
- *mem_section = memory_region_find(root, base, src_len);
- if (!mem_section->mr) {
- return;
- }
-
- if (int128_get64(mem_section->size) < src_len ||
- !memory_region_is_ram(mem_section->mr)) {
- memory_region_unref(mem_section->mr);
- mem_section->mr = NULL;
- return;
- }
-
- memory_region_set_log(mem_section->mr, true, DIRTY_MEMORY_VGA);
-}
-
-/* Render an image from a shared memory framebuffer. */
-void framebuffer_update_display(
- DisplaySurface *ds,
- MemoryRegionSection *mem_section,
- int cols, /* Width in pixels. */
- int rows, /* Height in pixels. */
- int src_width, /* Length of source line, in bytes. */
- int dest_row_pitch, /* Bytes between adjacent horizontal output pixels. */
- int dest_col_pitch, /* Bytes between adjacent vertical output pixels. */
- int invalidate, /* nonzero to redraw the whole image. */
- drawfn fn,
- void *opaque,
- int *first_row, /* Input and output. */
- int *last_row /* Output only */)
-{
- hwaddr src_len;
- uint8_t *dest;
- uint8_t *src;
- int first, last = 0;
- int dirty;
- int i;
- ram_addr_t addr;
- MemoryRegion *mem;
-
- i = *first_row;
- *first_row = -1;
- src_len = src_width * rows;
-
- mem = mem_section->mr;
- if (!mem) {
- return;
- }
- memory_region_sync_dirty_bitmap(mem);
-
- addr = mem_section->offset_within_region;
- src = memory_region_get_ram_ptr(mem) + addr;
-
- dest = surface_data(ds);
- if (dest_col_pitch < 0) {
- dest -= dest_col_pitch * (cols - 1);
- }
- if (dest_row_pitch < 0) {
- dest -= dest_row_pitch * (rows - 1);
- }
- first = -1;
-
- addr += i * src_width;
- src += i * src_width;
- dest += i * dest_row_pitch;
-
- for (; i < rows; i++) {
- dirty = memory_region_get_dirty(mem, addr, src_width,
- DIRTY_MEMORY_VGA);
- if (dirty || invalidate) {
- fn(opaque, dest, src, cols, dest_col_pitch);
- if (first == -1)
- first = i;
- last = i;
- }
- addr += src_width;
- src += src_width;
- dest += dest_row_pitch;
- }
- if (first < 0) {
- return;
- }
- memory_region_reset_dirty(mem, mem_section->offset_within_region, src_len,
- DIRTY_MEMORY_VGA);
- *first_row = first;
- *last_row = last;
-}
diff --git a/qemu/hw/display/framebuffer.h b/qemu/hw/display/framebuffer.h
deleted file mode 100644
index 38fa0dcec..000000000
--- a/qemu/hw/display/framebuffer.h
+++ /dev/null
@@ -1,65 +0,0 @@
-#ifndef QEMU_FRAMEBUFFER_H
-#define QEMU_FRAMEBUFFER_H
-
-#include "exec/memory.h"
-
-/* Framebuffer device helper routines. */
-
-typedef void (*drawfn)(void *, uint8_t *, const uint8_t *, int, int);
-
-/* framebuffer_update_memory_section: Update framebuffer
- * #MemoryRegionSection, for example if the framebuffer is switched to
- * a different memory area.
- *
- * @mem_section: Output #MemoryRegionSection, to be passed to
- * framebuffer_update_display().
- * @root: #MemoryRegion within which the framebuffer lies
- * @base: Base address of the framebuffer within @root.
- * @rows: Height of the screen.
- * @src_width: Number of bytes in framebuffer memory between two rows.
- */
-void framebuffer_update_memory_section(
- MemoryRegionSection *mem_section,
- MemoryRegion *root,
- hwaddr base,
- unsigned rows,
- unsigned src_width);
-
-/* framebuffer_update_display: Draw the framebuffer on a surface.
- *
- * @ds: #DisplaySurface to draw to.
- * @mem_section: #MemoryRegionSection provided by
- * framebuffer_update_memory_section().
- * @cols: Width the screen.
- * @rows: Height of the screen.
- * @src_width: Number of bytes in framebuffer memory between two rows.
- * @dest_row_pitch: Number of bytes in the surface data between two rows.
- * Negative if the framebuffer is stored in the opposite order (e.g.
- * bottom-to-top) compared to the framebuffer.
- * @dest_col_pitch: Number of bytes in the surface data between two pixels.
- * Negative if the framebuffer is stored in the opposite order (e.g.
- * right-to-left) compared to the framebuffer.
- * @invalidate: True if the function should redraw the whole screen
- * without checking the DIRTY_MEMORY_VGA dirty bitmap.
- * @fn: Drawing function to be called for each row that has to be drawn.
- * @opaque: Opaque pointer passed to @fn.
- * @first_row: Pointer to an integer, receives the number of the first row
- * that was drawn (either the first dirty row, or 0 if @invalidate is true).
- * @last_row: Pointer to an integer, receives the number of the last row that
- * was drawn (either the last dirty row, or @rows-1 if @invalidate is true).
- */
-void framebuffer_update_display(
- DisplaySurface *ds,
- MemoryRegionSection *mem_section,
- int cols,
- int rows,
- int src_width,
- int dest_row_pitch,
- int dest_col_pitch,
- int invalidate,
- drawfn fn,
- void *opaque,
- int *first_row,
- int *last_row);
-
-#endif
diff --git a/qemu/hw/display/g364fb.c b/qemu/hw/display/g364fb.c
deleted file mode 100644
index 70ef2c745..000000000
--- a/qemu/hw/display/g364fb.c
+++ /dev/null
@@ -1,559 +0,0 @@
-/*
- * QEMU G364 framebuffer Emulator.
- *
- * Copyright (c) 2007-2011 Herve Poussineau
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "qemu/error-report.h"
-#include "ui/console.h"
-#include "ui/pixel_ops.h"
-#include "trace.h"
-#include "hw/sysbus.h"
-
-typedef struct G364State {
- /* hardware */
- uint8_t *vram;
- uint32_t vram_size;
- qemu_irq irq;
- MemoryRegion mem_vram;
- MemoryRegion mem_ctrl;
- /* registers */
- uint8_t color_palette[256][3];
- uint8_t cursor_palette[3][3];
- uint16_t cursor[512];
- uint32_t cursor_position;
- uint32_t ctla;
- uint32_t top_of_screen;
- uint32_t width, height; /* in pixels */
- /* display refresh support */
- QemuConsole *con;
- int depth;
- int blanked;
-} G364State;
-
-#define REG_BOOT 0x000000
-#define REG_DISPLAY 0x000118
-#define REG_VDISPLAY 0x000150
-#define REG_CTLA 0x000300
-#define REG_TOP 0x000400
-#define REG_CURS_PAL 0x000508
-#define REG_CURS_POS 0x000638
-#define REG_CLR_PAL 0x000800
-#define REG_CURS_PAT 0x001000
-#define REG_RESET 0x100000
-
-#define CTLA_FORCE_BLANK 0x00000400
-#define CTLA_NO_CURSOR 0x00800000
-
-#define G364_PAGE_SIZE 4096
-
-static inline int check_dirty(G364State *s, ram_addr_t page)
-{
- return memory_region_get_dirty(&s->mem_vram, page, G364_PAGE_SIZE,
- DIRTY_MEMORY_VGA);
-}
-
-static inline void reset_dirty(G364State *s,
- ram_addr_t page_min, ram_addr_t page_max)
-{
- memory_region_reset_dirty(&s->mem_vram,
- page_min,
- page_max + G364_PAGE_SIZE - page_min - 1,
- DIRTY_MEMORY_VGA);
-}
-
-static void g364fb_draw_graphic8(G364State *s)
-{
- DisplaySurface *surface = qemu_console_surface(s->con);
- int i, w;
- uint8_t *vram;
- uint8_t *data_display, *dd;
- ram_addr_t page, page_min, page_max;
- int x, y;
- int xmin, xmax;
- int ymin, ymax;
- int xcursor, ycursor;
- unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g, unsigned int b);
-
- switch (surface_bits_per_pixel(surface)) {
- case 8:
- rgb_to_pixel = rgb_to_pixel8;
- w = 1;
- break;
- case 15:
- rgb_to_pixel = rgb_to_pixel15;
- w = 2;
- break;
- case 16:
- rgb_to_pixel = rgb_to_pixel16;
- w = 2;
- break;
- case 32:
- rgb_to_pixel = rgb_to_pixel32;
- w = 4;
- break;
- default:
- hw_error("g364: unknown host depth %d",
- surface_bits_per_pixel(surface));
- return;
- }
-
- page = 0;
- page_min = (ram_addr_t)-1;
- page_max = 0;
-
- x = y = 0;
- xmin = s->width;
- xmax = 0;
- ymin = s->height;
- ymax = 0;
-
- if (!(s->ctla & CTLA_NO_CURSOR)) {
- xcursor = s->cursor_position >> 12;
- ycursor = s->cursor_position & 0xfff;
- } else {
- xcursor = ycursor = -65;
- }
-
- vram = s->vram + s->top_of_screen;
- /* XXX: out of range in vram? */
- data_display = dd = surface_data(surface);
- while (y < s->height) {
- if (check_dirty(s, page)) {
- if (y < ymin)
- ymin = ymax = y;
- if (page_min == (ram_addr_t)-1)
- page_min = page;
- page_max = page;
- if (x < xmin)
- xmin = x;
- for (i = 0; i < G364_PAGE_SIZE; i++) {
- uint8_t index;
- unsigned int color;
- if (unlikely((y >= ycursor && y < ycursor + 64) &&
- (x >= xcursor && x < xcursor + 64))) {
- /* pointer area */
- int xdiff = x - xcursor;
- uint16_t curs = s->cursor[(y - ycursor) * 8 + xdiff / 8];
- int op = (curs >> ((xdiff & 7) * 2)) & 3;
- if (likely(op == 0)) {
- /* transparent */
- index = *vram;
- color = (*rgb_to_pixel)(
- s->color_palette[index][0],
- s->color_palette[index][1],
- s->color_palette[index][2]);
- } else {
- /* get cursor color */
- index = op - 1;
- color = (*rgb_to_pixel)(
- s->cursor_palette[index][0],
- s->cursor_palette[index][1],
- s->cursor_palette[index][2]);
- }
- } else {
- /* normal area */
- index = *vram;
- color = (*rgb_to_pixel)(
- s->color_palette[index][0],
- s->color_palette[index][1],
- s->color_palette[index][2]);
- }
- memcpy(dd, &color, w);
- dd += w;
- x++;
- vram++;
- if (x == s->width) {
- xmax = s->width - 1;
- y++;
- if (y == s->height) {
- ymax = s->height - 1;
- goto done;
- }
- data_display = dd = data_display + surface_stride(surface);
- xmin = 0;
- x = 0;
- }
- }
- if (x > xmax)
- xmax = x;
- if (y > ymax)
- ymax = y;
- } else {
- int dy;
- if (page_min != (ram_addr_t)-1) {
- reset_dirty(s, page_min, page_max);
- page_min = (ram_addr_t)-1;
- page_max = 0;
- dpy_gfx_update(s->con, xmin, ymin,
- xmax - xmin + 1, ymax - ymin + 1);
- xmin = s->width;
- xmax = 0;
- ymin = s->height;
- ymax = 0;
- }
- x += G364_PAGE_SIZE;
- dy = x / s->width;
- x = x % s->width;
- y += dy;
- vram += G364_PAGE_SIZE;
- data_display += dy * surface_stride(surface);
- dd = data_display + x * w;
- }
- page += G364_PAGE_SIZE;
- }
-
-done:
- if (page_min != (ram_addr_t)-1) {
- dpy_gfx_update(s->con, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1);
- reset_dirty(s, page_min, page_max);
- }
-}
-
-static void g364fb_draw_blank(G364State *s)
-{
- DisplaySurface *surface = qemu_console_surface(s->con);
- int i, w;
- uint8_t *d;
-
- if (s->blanked) {
- /* Screen is already blank. No need to redraw it */
- return;
- }
-
- w = s->width * surface_bytes_per_pixel(surface);
- d = surface_data(surface);
- for (i = 0; i < s->height; i++) {
- memset(d, 0, w);
- d += surface_stride(surface);
- }
-
- dpy_gfx_update(s->con, 0, 0, s->width, s->height);
- s->blanked = 1;
-}
-
-static void g364fb_update_display(void *opaque)
-{
- G364State *s = opaque;
- DisplaySurface *surface = qemu_console_surface(s->con);
-
- qemu_flush_coalesced_mmio_buffer();
-
- if (s->width == 0 || s->height == 0)
- return;
-
- if (s->width != surface_width(surface) ||
- s->height != surface_height(surface)) {
- qemu_console_resize(s->con, s->width, s->height);
- }
-
- memory_region_sync_dirty_bitmap(&s->mem_vram);
- if (s->ctla & CTLA_FORCE_BLANK) {
- g364fb_draw_blank(s);
- } else if (s->depth == 8) {
- g364fb_draw_graphic8(s);
- } else {
- error_report("g364: unknown guest depth %d", s->depth);
- }
-
- qemu_irq_raise(s->irq);
-}
-
-static inline void g364fb_invalidate_display(void *opaque)
-{
- G364State *s = opaque;
-
- s->blanked = 0;
- memory_region_set_dirty(&s->mem_vram, 0, s->vram_size);
-}
-
-static void g364fb_reset(G364State *s)
-{
- qemu_irq_lower(s->irq);
-
- memset(s->color_palette, 0, sizeof(s->color_palette));
- memset(s->cursor_palette, 0, sizeof(s->cursor_palette));
- memset(s->cursor, 0, sizeof(s->cursor));
- s->cursor_position = 0;
- s->ctla = 0;
- s->top_of_screen = 0;
- s->width = s->height = 0;
- memset(s->vram, 0, s->vram_size);
- g364fb_invalidate_display(s);
-}
-
-/* called for accesses to io ports */
-static uint64_t g364fb_ctrl_read(void *opaque,
- hwaddr addr,
- unsigned int size)
-{
- G364State *s = opaque;
- uint32_t val;
-
- if (addr >= REG_CURS_PAT && addr < REG_CURS_PAT + 0x1000) {
- /* cursor pattern */
- int idx = (addr - REG_CURS_PAT) >> 3;
- val = s->cursor[idx];
- } else if (addr >= REG_CURS_PAL && addr < REG_CURS_PAL + 0x18) {
- /* cursor palette */
- int idx = (addr - REG_CURS_PAL) >> 3;
- val = ((uint32_t)s->cursor_palette[idx][0] << 16);
- val |= ((uint32_t)s->cursor_palette[idx][1] << 8);
- val |= ((uint32_t)s->cursor_palette[idx][2] << 0);
- } else {
- switch (addr) {
- case REG_DISPLAY:
- val = s->width / 4;
- break;
- case REG_VDISPLAY:
- val = s->height * 2;
- break;
- case REG_CTLA:
- val = s->ctla;
- break;
- default:
- {
- error_report("g364: invalid read at [" TARGET_FMT_plx "]",
- addr);
- val = 0;
- break;
- }
- }
- }
-
- trace_g364fb_read(addr, val);
-
- return val;
-}
-
-static void g364fb_update_depth(G364State *s)
-{
- static const int depths[8] = { 1, 2, 4, 8, 15, 16, 0 };
- s->depth = depths[(s->ctla & 0x00700000) >> 20];
-}
-
-static void g364_invalidate_cursor_position(G364State *s)
-{
- DisplaySurface *surface = qemu_console_surface(s->con);
- int ymin, ymax, start, end;
-
- /* invalidate only near the cursor */
- ymin = s->cursor_position & 0xfff;
- ymax = MIN(s->height, ymin + 64);
- start = ymin * surface_stride(surface);
- end = (ymax + 1) * surface_stride(surface);
-
- memory_region_set_dirty(&s->mem_vram, start, end - start);
-}
-
-static void g364fb_ctrl_write(void *opaque,
- hwaddr addr,
- uint64_t val,
- unsigned int size)
-{
- G364State *s = opaque;
-
- trace_g364fb_write(addr, val);
-
- if (addr >= REG_CLR_PAL && addr < REG_CLR_PAL + 0x800) {
- /* color palette */
- int idx = (addr - REG_CLR_PAL) >> 3;
- s->color_palette[idx][0] = (val >> 16) & 0xff;
- s->color_palette[idx][1] = (val >> 8) & 0xff;
- s->color_palette[idx][2] = val & 0xff;
- g364fb_invalidate_display(s);
- } else if (addr >= REG_CURS_PAT && addr < REG_CURS_PAT + 0x1000) {
- /* cursor pattern */
- int idx = (addr - REG_CURS_PAT) >> 3;
- s->cursor[idx] = val;
- g364fb_invalidate_display(s);
- } else if (addr >= REG_CURS_PAL && addr < REG_CURS_PAL + 0x18) {
- /* cursor palette */
- int idx = (addr - REG_CURS_PAL) >> 3;
- s->cursor_palette[idx][0] = (val >> 16) & 0xff;
- s->cursor_palette[idx][1] = (val >> 8) & 0xff;
- s->cursor_palette[idx][2] = val & 0xff;
- g364fb_invalidate_display(s);
- } else {
- switch (addr) {
- case REG_BOOT: /* Boot timing */
- case 0x00108: /* Line timing: half sync */
- case 0x00110: /* Line timing: back porch */
- case 0x00120: /* Line timing: short display */
- case 0x00128: /* Frame timing: broad pulse */
- case 0x00130: /* Frame timing: v sync */
- case 0x00138: /* Frame timing: v preequalise */
- case 0x00140: /* Frame timing: v postequalise */
- case 0x00148: /* Frame timing: v blank */
- case 0x00158: /* Line timing: line time */
- case 0x00160: /* Frame store: line start */
- case 0x00168: /* vram cycle: mem init */
- case 0x00170: /* vram cycle: transfer delay */
- case 0x00200: /* vram cycle: mask register */
- /* ignore */
- break;
- case REG_TOP:
- s->top_of_screen = val;
- g364fb_invalidate_display(s);
- break;
- case REG_DISPLAY:
- s->width = val * 4;
- break;
- case REG_VDISPLAY:
- s->height = val / 2;
- break;
- case REG_CTLA:
- s->ctla = val;
- g364fb_update_depth(s);
- g364fb_invalidate_display(s);
- break;
- case REG_CURS_POS:
- g364_invalidate_cursor_position(s);
- s->cursor_position = val;
- g364_invalidate_cursor_position(s);
- break;
- case REG_RESET:
- g364fb_reset(s);
- break;
- default:
- error_report("g364: invalid write of 0x%" PRIx64
- " at [" TARGET_FMT_plx "]", val, addr);
- break;
- }
- }
- qemu_irq_lower(s->irq);
-}
-
-static const MemoryRegionOps g364fb_ctrl_ops = {
- .read = g364fb_ctrl_read,
- .write = g364fb_ctrl_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .impl.min_access_size = 4,
- .impl.max_access_size = 4,
-};
-
-static int g364fb_post_load(void *opaque, int version_id)
-{
- G364State *s = opaque;
-
- /* force refresh */
- g364fb_update_depth(s);
- g364fb_invalidate_display(s);
-
- return 0;
-}
-
-static const VMStateDescription vmstate_g364fb = {
- .name = "g364fb",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = g364fb_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_VBUFFER_UINT32(vram, G364State, 1, NULL, 0, vram_size),
- VMSTATE_BUFFER_UNSAFE(color_palette, G364State, 0, 256 * 3),
- VMSTATE_BUFFER_UNSAFE(cursor_palette, G364State, 0, 9),
- VMSTATE_UINT16_ARRAY(cursor, G364State, 512),
- VMSTATE_UINT32(cursor_position, G364State),
- VMSTATE_UINT32(ctla, G364State),
- VMSTATE_UINT32(top_of_screen, G364State),
- VMSTATE_UINT32(width, G364State),
- VMSTATE_UINT32(height, G364State),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const GraphicHwOps g364fb_ops = {
- .invalidate = g364fb_invalidate_display,
- .gfx_update = g364fb_update_display,
-};
-
-static void g364fb_init(DeviceState *dev, G364State *s)
-{
- s->vram = g_malloc0(s->vram_size);
-
- s->con = graphic_console_init(dev, 0, &g364fb_ops, s);
-
- memory_region_init_io(&s->mem_ctrl, NULL, &g364fb_ctrl_ops, s, "ctrl", 0x180000);
- memory_region_init_ram_ptr(&s->mem_vram, NULL, "vram",
- s->vram_size, s->vram);
- vmstate_register_ram(&s->mem_vram, dev);
- memory_region_set_log(&s->mem_vram, true, DIRTY_MEMORY_VGA);
-}
-
-#define TYPE_G364 "sysbus-g364"
-#define G364(obj) OBJECT_CHECK(G364SysBusState, (obj), TYPE_G364)
-
-typedef struct {
- SysBusDevice parent_obj;
-
- G364State g364;
-} G364SysBusState;
-
-static int g364fb_sysbus_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- G364SysBusState *sbs = G364(dev);
- G364State *s = &sbs->g364;
-
- g364fb_init(dev, s);
- sysbus_init_irq(sbd, &s->irq);
- sysbus_init_mmio(sbd, &s->mem_ctrl);
- sysbus_init_mmio(sbd, &s->mem_vram);
-
- return 0;
-}
-
-static void g364fb_sysbus_reset(DeviceState *d)
-{
- G364SysBusState *s = G364(d);
-
- g364fb_reset(&s->g364);
-}
-
-static Property g364fb_sysbus_properties[] = {
- DEFINE_PROP_UINT32("vram_size", G364SysBusState, g364.vram_size,
- 8 * 1024 * 1024),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void g364fb_sysbus_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = g364fb_sysbus_init;
- set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
- dc->desc = "G364 framebuffer";
- dc->reset = g364fb_sysbus_reset;
- dc->vmsd = &vmstate_g364fb;
- dc->props = g364fb_sysbus_properties;
-}
-
-static const TypeInfo g364fb_sysbus_info = {
- .name = TYPE_G364,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(G364SysBusState),
- .class_init = g364fb_sysbus_class_init,
-};
-
-static void g364fb_register_types(void)
-{
- type_register_static(&g364fb_sysbus_info);
-}
-
-type_init(g364fb_register_types)
diff --git a/qemu/hw/display/jazz_led.c b/qemu/hw/display/jazz_led.c
deleted file mode 100644
index 09dcdb46a..000000000
--- a/qemu/hw/display/jazz_led.c
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * QEMU JAZZ LED emulator.
- *
- * Copyright (c) 2007-2012 Herve Poussineau
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "ui/console.h"
-#include "ui/pixel_ops.h"
-#include "trace.h"
-#include "hw/sysbus.h"
-
-typedef enum {
- REDRAW_NONE = 0, REDRAW_SEGMENTS = 1, REDRAW_BACKGROUND = 2,
-} screen_state_t;
-
-#define TYPE_JAZZ_LED "jazz-led"
-#define JAZZ_LED(obj) OBJECT_CHECK(LedState, (obj), TYPE_JAZZ_LED)
-
-typedef struct LedState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- uint8_t segments;
- QemuConsole *con;
- screen_state_t state;
-} LedState;
-
-static uint64_t jazz_led_read(void *opaque, hwaddr addr,
- unsigned int size)
-{
- LedState *s = opaque;
- uint8_t val;
-
- val = s->segments;
- trace_jazz_led_read(addr, val);
-
- return val;
-}
-
-static void jazz_led_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned int size)
-{
- LedState *s = opaque;
- uint8_t new_val = val & 0xff;
-
- trace_jazz_led_write(addr, new_val);
-
- s->segments = new_val;
- s->state |= REDRAW_SEGMENTS;
-}
-
-static const MemoryRegionOps led_ops = {
- .read = jazz_led_read,
- .write = jazz_led_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .impl.min_access_size = 1,
- .impl.max_access_size = 1,
-};
-
-/***********************************************************/
-/* jazz_led display */
-
-static void draw_horizontal_line(DisplaySurface *ds,
- int posy, int posx1, int posx2,
- uint32_t color)
-{
- uint8_t *d;
- int x, bpp;
-
- bpp = (surface_bits_per_pixel(ds) + 7) >> 3;
- d = surface_data(ds) + surface_stride(ds) * posy + bpp * posx1;
- switch(bpp) {
- case 1:
- for (x = posx1; x <= posx2; x++) {
- *((uint8_t *)d) = color;
- d++;
- }
- break;
- case 2:
- for (x = posx1; x <= posx2; x++) {
- *((uint16_t *)d) = color;
- d += 2;
- }
- break;
- case 4:
- for (x = posx1; x <= posx2; x++) {
- *((uint32_t *)d) = color;
- d += 4;
- }
- break;
- }
-}
-
-static void draw_vertical_line(DisplaySurface *ds,
- int posx, int posy1, int posy2,
- uint32_t color)
-{
- uint8_t *d;
- int y, bpp;
-
- bpp = (surface_bits_per_pixel(ds) + 7) >> 3;
- d = surface_data(ds) + surface_stride(ds) * posy1 + bpp * posx;
- switch(bpp) {
- case 1:
- for (y = posy1; y <= posy2; y++) {
- *((uint8_t *)d) = color;
- d += surface_stride(ds);
- }
- break;
- case 2:
- for (y = posy1; y <= posy2; y++) {
- *((uint16_t *)d) = color;
- d += surface_stride(ds);
- }
- break;
- case 4:
- for (y = posy1; y <= posy2; y++) {
- *((uint32_t *)d) = color;
- d += surface_stride(ds);
- }
- break;
- }
-}
-
-static void jazz_led_update_display(void *opaque)
-{
- LedState *s = opaque;
- DisplaySurface *surface = qemu_console_surface(s->con);
- uint8_t *d1;
- uint32_t color_segment, color_led;
- int y, bpp;
-
- if (s->state & REDRAW_BACKGROUND) {
- /* clear screen */
- bpp = (surface_bits_per_pixel(surface) + 7) >> 3;
- d1 = surface_data(surface);
- for (y = 0; y < surface_height(surface); y++) {
- memset(d1, 0x00, surface_width(surface) * bpp);
- d1 += surface_stride(surface);
- }
- }
-
- if (s->state & REDRAW_SEGMENTS) {
- /* set colors according to bpp */
- switch (surface_bits_per_pixel(surface)) {
- case 8:
- color_segment = rgb_to_pixel8(0xaa, 0xaa, 0xaa);
- color_led = rgb_to_pixel8(0x00, 0xff, 0x00);
- break;
- case 15:
- color_segment = rgb_to_pixel15(0xaa, 0xaa, 0xaa);
- color_led = rgb_to_pixel15(0x00, 0xff, 0x00);
- break;
- case 16:
- color_segment = rgb_to_pixel16(0xaa, 0xaa, 0xaa);
- color_led = rgb_to_pixel16(0x00, 0xff, 0x00);
- break;
- case 24:
- color_segment = rgb_to_pixel24(0xaa, 0xaa, 0xaa);
- color_led = rgb_to_pixel24(0x00, 0xff, 0x00);
- break;
- case 32:
- color_segment = rgb_to_pixel32(0xaa, 0xaa, 0xaa);
- color_led = rgb_to_pixel32(0x00, 0xff, 0x00);
- break;
- default:
- return;
- }
-
- /* display segments */
- draw_horizontal_line(surface, 40, 10, 40,
- (s->segments & 0x02) ? color_segment : 0);
- draw_vertical_line(surface, 10, 10, 40,
- (s->segments & 0x04) ? color_segment : 0);
- draw_vertical_line(surface, 10, 40, 70,
- (s->segments & 0x08) ? color_segment : 0);
- draw_horizontal_line(surface, 70, 10, 40,
- (s->segments & 0x10) ? color_segment : 0);
- draw_vertical_line(surface, 40, 40, 70,
- (s->segments & 0x20) ? color_segment : 0);
- draw_vertical_line(surface, 40, 10, 40,
- (s->segments & 0x40) ? color_segment : 0);
- draw_horizontal_line(surface, 10, 10, 40,
- (s->segments & 0x80) ? color_segment : 0);
-
- /* display led */
- if (!(s->segments & 0x01))
- color_led = 0; /* black */
- draw_horizontal_line(surface, 68, 50, 50, color_led);
- draw_horizontal_line(surface, 69, 49, 51, color_led);
- draw_horizontal_line(surface, 70, 48, 52, color_led);
- draw_horizontal_line(surface, 71, 49, 51, color_led);
- draw_horizontal_line(surface, 72, 50, 50, color_led);
- }
-
- s->state = REDRAW_NONE;
- dpy_gfx_update(s->con, 0, 0,
- surface_width(surface), surface_height(surface));
-}
-
-static void jazz_led_invalidate_display(void *opaque)
-{
- LedState *s = opaque;
- s->state |= REDRAW_SEGMENTS | REDRAW_BACKGROUND;
-}
-
-static void jazz_led_text_update(void *opaque, console_ch_t *chardata)
-{
- LedState *s = opaque;
- char buf[2];
-
- dpy_text_cursor(s->con, -1, -1);
- qemu_console_resize(s->con, 2, 1);
-
- /* TODO: draw the segments */
- snprintf(buf, 2, "%02hhx\n", s->segments);
- console_write_ch(chardata++, ATTR2CHTYPE(buf[0], QEMU_COLOR_BLUE,
- QEMU_COLOR_BLACK, 1));
- console_write_ch(chardata++, ATTR2CHTYPE(buf[1], QEMU_COLOR_BLUE,
- QEMU_COLOR_BLACK, 1));
-
- dpy_text_update(s->con, 0, 0, 2, 1);
-}
-
-static int jazz_led_post_load(void *opaque, int version_id)
-{
- /* force refresh */
- jazz_led_invalidate_display(opaque);
-
- return 0;
-}
-
-static const VMStateDescription vmstate_jazz_led = {
- .name = "jazz-led",
- .version_id = 0,
- .minimum_version_id = 0,
- .post_load = jazz_led_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(segments, LedState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const GraphicHwOps jazz_led_ops = {
- .invalidate = jazz_led_invalidate_display,
- .gfx_update = jazz_led_update_display,
- .text_update = jazz_led_text_update,
-};
-
-static int jazz_led_init(SysBusDevice *dev)
-{
- LedState *s = JAZZ_LED(dev);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &led_ops, s, "led", 1);
- sysbus_init_mmio(dev, &s->iomem);
-
- s->con = graphic_console_init(DEVICE(dev), 0, &jazz_led_ops, s);
-
- return 0;
-}
-
-static void jazz_led_reset(DeviceState *d)
-{
- LedState *s = JAZZ_LED(d);
-
- s->segments = 0;
- s->state = REDRAW_SEGMENTS | REDRAW_BACKGROUND;
- qemu_console_resize(s->con, 60, 80);
-}
-
-static void jazz_led_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = jazz_led_init;
- dc->desc = "Jazz LED display",
- dc->vmsd = &vmstate_jazz_led;
- dc->reset = jazz_led_reset;
-}
-
-static const TypeInfo jazz_led_info = {
- .name = TYPE_JAZZ_LED,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(LedState),
- .class_init = jazz_led_class_init,
-};
-
-static void jazz_led_register(void)
-{
- type_register_static(&jazz_led_info);
-}
-
-type_init(jazz_led_register);
diff --git a/qemu/hw/display/milkymist-tmu2.c b/qemu/hw/display/milkymist-tmu2.c
deleted file mode 100644
index 9bc88f93b..000000000
--- a/qemu/hw/display/milkymist-tmu2.c
+++ /dev/null
@@ -1,495 +0,0 @@
-/*
- * QEMU model of the Milkymist texture mapping unit.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- * Copyright (c) 2010 Sebastien Bourdeauducq
- * <sebastien.bourdeauducq@lekernel.net>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * Specification available at:
- * http://www.milkymist.org/socdoc/tmu2.pdf
- *
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "qemu/error-report.h"
-
-#include <X11/Xlib.h>
-#include <epoxy/gl.h>
-#include <epoxy/glx.h>
-
-enum {
- R_CTL = 0,
- R_HMESHLAST,
- R_VMESHLAST,
- R_BRIGHTNESS,
- R_CHROMAKEY,
- R_VERTICESADDR,
- R_TEXFBUF,
- R_TEXHRES,
- R_TEXVRES,
- R_TEXHMASK,
- R_TEXVMASK,
- R_DSTFBUF,
- R_DSTHRES,
- R_DSTVRES,
- R_DSTHOFFSET,
- R_DSTVOFFSET,
- R_DSTSQUAREW,
- R_DSTSQUAREH,
- R_ALPHA,
- R_MAX
-};
-
-enum {
- CTL_START_BUSY = (1<<0),
- CTL_CHROMAKEY = (1<<1),
-};
-
-enum {
- MAX_BRIGHTNESS = 63,
- MAX_ALPHA = 63,
-};
-
-enum {
- MESH_MAXSIZE = 128,
-};
-
-struct vertex {
- int x;
- int y;
-} QEMU_PACKED;
-
-#define TYPE_MILKYMIST_TMU2 "milkymist-tmu2"
-#define MILKYMIST_TMU2(obj) \
- OBJECT_CHECK(MilkymistTMU2State, (obj), TYPE_MILKYMIST_TMU2)
-
-struct MilkymistTMU2State {
- SysBusDevice parent_obj;
-
- MemoryRegion regs_region;
- CharDriverState *chr;
- qemu_irq irq;
-
- uint32_t regs[R_MAX];
-
- Display *dpy;
- GLXFBConfig glx_fb_config;
- GLXContext glx_context;
-};
-typedef struct MilkymistTMU2State MilkymistTMU2State;
-
-static const int glx_fbconfig_attr[] = {
- GLX_GREEN_SIZE, 5,
- GLX_GREEN_SIZE, 6,
- GLX_BLUE_SIZE, 5,
- None
-};
-
-static int tmu2_glx_init(MilkymistTMU2State *s)
-{
- GLXFBConfig *configs;
- int nelements;
-
- s->dpy = XOpenDisplay(NULL); /* FIXME: call XCloseDisplay() */
- if (s->dpy == NULL) {
- return 1;
- }
-
- configs = glXChooseFBConfig(s->dpy, 0, glx_fbconfig_attr, &nelements);
- if (configs == NULL) {
- return 1;
- }
-
- s->glx_fb_config = *configs;
- XFree(configs);
-
- /* FIXME: call glXDestroyContext() */
- s->glx_context = glXCreateNewContext(s->dpy, s->glx_fb_config,
- GLX_RGBA_TYPE, NULL, 1);
- if (s->glx_context == NULL) {
- return 1;
- }
-
- return 0;
-}
-
-static void tmu2_gl_map(struct vertex *mesh, int texhres, int texvres,
- int hmeshlast, int vmeshlast, int ho, int vo, int sw, int sh)
-{
- int x, y;
- int x0, y0, x1, y1;
- int u0, v0, u1, v1, u2, v2, u3, v3;
- double xscale = 1.0 / ((double)(64 * texhres));
- double yscale = 1.0 / ((double)(64 * texvres));
-
- glLoadIdentity();
- glTranslatef(ho, vo, 0);
- glEnable(GL_TEXTURE_2D);
- glBegin(GL_QUADS);
-
- for (y = 0; y < vmeshlast; y++) {
- y0 = y * sh;
- y1 = y0 + sh;
- for (x = 0; x < hmeshlast; x++) {
- x0 = x * sw;
- x1 = x0 + sw;
-
- u0 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x].x);
- v0 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x].y);
- u1 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x + 1].x);
- v1 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x + 1].y);
- u2 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x + 1].x);
- v2 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x + 1].y);
- u3 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x].x);
- v3 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x].y);
-
- glTexCoord2d(((double)u0) * xscale, ((double)v0) * yscale);
- glVertex3i(x0, y0, 0);
- glTexCoord2d(((double)u1) * xscale, ((double)v1) * yscale);
- glVertex3i(x1, y0, 0);
- glTexCoord2d(((double)u2) * xscale, ((double)v2) * yscale);
- glVertex3i(x1, y1, 0);
- glTexCoord2d(((double)u3) * xscale, ((double)v3) * yscale);
- glVertex3i(x0, y1, 0);
- }
- }
-
- glEnd();
-}
-
-static void tmu2_start(MilkymistTMU2State *s)
-{
- int pbuffer_attrib[6] = {
- GLX_PBUFFER_WIDTH,
- 0,
- GLX_PBUFFER_HEIGHT,
- 0,
- GLX_PRESERVED_CONTENTS,
- True
- };
-
- GLXPbuffer pbuffer;
- GLuint texture;
- void *fb;
- hwaddr fb_len;
- void *mesh;
- hwaddr mesh_len;
- float m;
-
- trace_milkymist_tmu2_start();
-
- /* Create and set up a suitable OpenGL context */
- pbuffer_attrib[1] = s->regs[R_DSTHRES];
- pbuffer_attrib[3] = s->regs[R_DSTVRES];
- pbuffer = glXCreatePbuffer(s->dpy, s->glx_fb_config, pbuffer_attrib);
- glXMakeContextCurrent(s->dpy, pbuffer, pbuffer, s->glx_context);
-
- /* Fixup endianness. TODO: would it work on BE hosts? */
- glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
- glPixelStorei(GL_PACK_SWAP_BYTES, 1);
-
- /* Row alignment */
- glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
- glPixelStorei(GL_PACK_ALIGNMENT, 2);
-
- /* Read the QEMU source framebuffer into an OpenGL texture */
- glGenTextures(1, &texture);
- glBindTexture(GL_TEXTURE_2D, texture);
- fb_len = 2*s->regs[R_TEXHRES]*s->regs[R_TEXVRES];
- fb = cpu_physical_memory_map(s->regs[R_TEXFBUF], &fb_len, 0);
- if (fb == NULL) {
- glDeleteTextures(1, &texture);
- glXMakeContextCurrent(s->dpy, None, None, NULL);
- glXDestroyPbuffer(s->dpy, pbuffer);
- return;
- }
- glTexImage2D(GL_TEXTURE_2D, 0, 3, s->regs[R_TEXHRES], s->regs[R_TEXVRES],
- 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, fb);
- cpu_physical_memory_unmap(fb, fb_len, 0, fb_len);
-
- /* Set up texturing options */
- /* WARNING:
- * Many cases of TMU2 masking are not supported by OpenGL.
- * We only implement the most common ones:
- * - full bilinear filtering vs. nearest texel
- * - texture clamping vs. texture wrapping
- */
- if ((s->regs[R_TEXHMASK] & 0x3f) > 0x20) {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- } else {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- }
- if ((s->regs[R_TEXHMASK] >> 6) & s->regs[R_TEXHRES]) {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
- } else {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- }
- if ((s->regs[R_TEXVMASK] >> 6) & s->regs[R_TEXVRES]) {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
- } else {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- }
-
- /* Translucency and decay */
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- m = (float)(s->regs[R_BRIGHTNESS] + 1) / 64.0f;
- glColor4f(m, m, m, (float)(s->regs[R_ALPHA] + 1) / 64.0f);
-
- /* Read the QEMU dest. framebuffer into the OpenGL framebuffer */
- fb_len = 2 * s->regs[R_DSTHRES] * s->regs[R_DSTVRES];
- fb = cpu_physical_memory_map(s->regs[R_DSTFBUF], &fb_len, 0);
- if (fb == NULL) {
- glDeleteTextures(1, &texture);
- glXMakeContextCurrent(s->dpy, None, None, NULL);
- glXDestroyPbuffer(s->dpy, pbuffer);
- return;
- }
-
- glDrawPixels(s->regs[R_DSTHRES], s->regs[R_DSTVRES], GL_RGB,
- GL_UNSIGNED_SHORT_5_6_5, fb);
- cpu_physical_memory_unmap(fb, fb_len, 0, fb_len);
- glViewport(0, 0, s->regs[R_DSTHRES], s->regs[R_DSTVRES]);
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glOrtho(0.0, s->regs[R_DSTHRES], 0.0, s->regs[R_DSTVRES], -1.0, 1.0);
- glMatrixMode(GL_MODELVIEW);
-
- /* Map the texture */
- mesh_len = MESH_MAXSIZE*MESH_MAXSIZE*sizeof(struct vertex);
- mesh = cpu_physical_memory_map(s->regs[R_VERTICESADDR], &mesh_len, 0);
- if (mesh == NULL) {
- glDeleteTextures(1, &texture);
- glXMakeContextCurrent(s->dpy, None, None, NULL);
- glXDestroyPbuffer(s->dpy, pbuffer);
- return;
- }
-
- tmu2_gl_map((struct vertex *)mesh,
- s->regs[R_TEXHRES], s->regs[R_TEXVRES],
- s->regs[R_HMESHLAST], s->regs[R_VMESHLAST],
- s->regs[R_DSTHOFFSET], s->regs[R_DSTVOFFSET],
- s->regs[R_DSTSQUAREW], s->regs[R_DSTSQUAREH]);
- cpu_physical_memory_unmap(mesh, mesh_len, 0, mesh_len);
-
- /* Write back the OpenGL framebuffer to the QEMU framebuffer */
- fb_len = 2 * s->regs[R_DSTHRES] * s->regs[R_DSTVRES];
- fb = cpu_physical_memory_map(s->regs[R_DSTFBUF], &fb_len, 1);
- if (fb == NULL) {
- glDeleteTextures(1, &texture);
- glXMakeContextCurrent(s->dpy, None, None, NULL);
- glXDestroyPbuffer(s->dpy, pbuffer);
- return;
- }
-
- glReadPixels(0, 0, s->regs[R_DSTHRES], s->regs[R_DSTVRES], GL_RGB,
- GL_UNSIGNED_SHORT_5_6_5, fb);
- cpu_physical_memory_unmap(fb, fb_len, 1, fb_len);
-
- /* Free OpenGL allocs */
- glDeleteTextures(1, &texture);
- glXMakeContextCurrent(s->dpy, None, None, NULL);
- glXDestroyPbuffer(s->dpy, pbuffer);
-
- s->regs[R_CTL] &= ~CTL_START_BUSY;
-
- trace_milkymist_tmu2_pulse_irq();
- qemu_irq_pulse(s->irq);
-}
-
-static uint64_t tmu2_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- MilkymistTMU2State *s = opaque;
- uint32_t r = 0;
-
- addr >>= 2;
- switch (addr) {
- case R_CTL:
- case R_HMESHLAST:
- case R_VMESHLAST:
- case R_BRIGHTNESS:
- case R_CHROMAKEY:
- case R_VERTICESADDR:
- case R_TEXFBUF:
- case R_TEXHRES:
- case R_TEXVRES:
- case R_TEXHMASK:
- case R_TEXVMASK:
- case R_DSTFBUF:
- case R_DSTHRES:
- case R_DSTVRES:
- case R_DSTHOFFSET:
- case R_DSTVOFFSET:
- case R_DSTSQUAREW:
- case R_DSTSQUAREH:
- case R_ALPHA:
- r = s->regs[addr];
- break;
-
- default:
- error_report("milkymist_tmu2: read access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-
- trace_milkymist_tmu2_memory_read(addr << 2, r);
-
- return r;
-}
-
-static void tmu2_check_registers(MilkymistTMU2State *s)
-{
- if (s->regs[R_BRIGHTNESS] > MAX_BRIGHTNESS) {
- error_report("milkymist_tmu2: max brightness is %d", MAX_BRIGHTNESS);
- }
-
- if (s->regs[R_ALPHA] > MAX_ALPHA) {
- error_report("milkymist_tmu2: max alpha is %d", MAX_ALPHA);
- }
-
- if (s->regs[R_VERTICESADDR] & 0x07) {
- error_report("milkymist_tmu2: vertex mesh address has to be 64-bit "
- "aligned");
- }
-
- if (s->regs[R_TEXFBUF] & 0x01) {
- error_report("milkymist_tmu2: texture buffer address has to be "
- "16-bit aligned");
- }
-}
-
-static void tmu2_write(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
- MilkymistTMU2State *s = opaque;
-
- trace_milkymist_tmu2_memory_write(addr, value);
-
- addr >>= 2;
- switch (addr) {
- case R_CTL:
- s->regs[addr] = value;
- if (value & CTL_START_BUSY) {
- tmu2_start(s);
- }
- break;
- case R_BRIGHTNESS:
- case R_HMESHLAST:
- case R_VMESHLAST:
- case R_CHROMAKEY:
- case R_VERTICESADDR:
- case R_TEXFBUF:
- case R_TEXHRES:
- case R_TEXVRES:
- case R_TEXHMASK:
- case R_TEXVMASK:
- case R_DSTFBUF:
- case R_DSTHRES:
- case R_DSTVRES:
- case R_DSTHOFFSET:
- case R_DSTVOFFSET:
- case R_DSTSQUAREW:
- case R_DSTSQUAREH:
- case R_ALPHA:
- s->regs[addr] = value;
- break;
-
- default:
- error_report("milkymist_tmu2: write access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-
- tmu2_check_registers(s);
-}
-
-static const MemoryRegionOps tmu2_mmio_ops = {
- .read = tmu2_read,
- .write = tmu2_write,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void milkymist_tmu2_reset(DeviceState *d)
-{
- MilkymistTMU2State *s = MILKYMIST_TMU2(d);
- int i;
-
- for (i = 0; i < R_MAX; i++) {
- s->regs[i] = 0;
- }
-}
-
-static int milkymist_tmu2_init(SysBusDevice *dev)
-{
- MilkymistTMU2State *s = MILKYMIST_TMU2(dev);
-
- if (tmu2_glx_init(s)) {
- return 1;
- }
-
- sysbus_init_irq(dev, &s->irq);
-
- memory_region_init_io(&s->regs_region, OBJECT(s), &tmu2_mmio_ops, s,
- "milkymist-tmu2", R_MAX * 4);
- sysbus_init_mmio(dev, &s->regs_region);
-
- return 0;
-}
-
-static const VMStateDescription vmstate_milkymist_tmu2 = {
- .name = "milkymist-tmu2",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, MilkymistTMU2State, R_MAX),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void milkymist_tmu2_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = milkymist_tmu2_init;
- dc->reset = milkymist_tmu2_reset;
- dc->vmsd = &vmstate_milkymist_tmu2;
-}
-
-static const TypeInfo milkymist_tmu2_info = {
- .name = TYPE_MILKYMIST_TMU2,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(MilkymistTMU2State),
- .class_init = milkymist_tmu2_class_init,
-};
-
-static void milkymist_tmu2_register_types(void)
-{
- type_register_static(&milkymist_tmu2_info);
-}
-
-type_init(milkymist_tmu2_register_types)
diff --git a/qemu/hw/display/milkymist-vgafb.c b/qemu/hw/display/milkymist-vgafb.c
deleted file mode 100644
index 19ca25647..000000000
--- a/qemu/hw/display/milkymist-vgafb.c
+++ /dev/null
@@ -1,354 +0,0 @@
-
-/*
- * QEMU model of the Milkymist VGA framebuffer.
- *
- * Copyright (c) 2010-2012 Michael Walle <michael@walle.cc>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * Specification available at:
- * http://www.milkymist.org/socdoc/vgafb.pdf
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "ui/console.h"
-#include "framebuffer.h"
-#include "ui/pixel_ops.h"
-#include "qemu/error-report.h"
-
-#define BITS 8
-#include "milkymist-vgafb_template.h"
-#define BITS 15
-#include "milkymist-vgafb_template.h"
-#define BITS 16
-#include "milkymist-vgafb_template.h"
-#define BITS 24
-#include "milkymist-vgafb_template.h"
-#define BITS 32
-#include "milkymist-vgafb_template.h"
-
-enum {
- R_CTRL = 0,
- R_HRES,
- R_HSYNC_START,
- R_HSYNC_END,
- R_HSCAN,
- R_VRES,
- R_VSYNC_START,
- R_VSYNC_END,
- R_VSCAN,
- R_BASEADDRESS,
- R_BASEADDRESS_ACT,
- R_BURST_COUNT,
- R_DDC,
- R_SOURCE_CLOCK,
- R_MAX
-};
-
-enum {
- CTRL_RESET = (1<<0),
-};
-
-#define TYPE_MILKYMIST_VGAFB "milkymist-vgafb"
-#define MILKYMIST_VGAFB(obj) \
- OBJECT_CHECK(MilkymistVgafbState, (obj), TYPE_MILKYMIST_VGAFB)
-
-struct MilkymistVgafbState {
- SysBusDevice parent_obj;
-
- MemoryRegion regs_region;
- MemoryRegionSection fbsection;
- QemuConsole *con;
-
- int invalidate;
- uint32_t fb_offset;
- uint32_t fb_mask;
-
- uint32_t regs[R_MAX];
-};
-typedef struct MilkymistVgafbState MilkymistVgafbState;
-
-static int vgafb_enabled(MilkymistVgafbState *s)
-{
- return !(s->regs[R_CTRL] & CTRL_RESET);
-}
-
-static void vgafb_update_display(void *opaque)
-{
- MilkymistVgafbState *s = opaque;
- SysBusDevice *sbd;
- DisplaySurface *surface = qemu_console_surface(s->con);
- int src_width;
- int first = 0;
- int last = 0;
- drawfn fn;
-
- if (!vgafb_enabled(s)) {
- return;
- }
-
- sbd = SYS_BUS_DEVICE(s);
- int dest_width = s->regs[R_HRES];
-
- switch (surface_bits_per_pixel(surface)) {
- case 0:
- return;
- case 8:
- fn = draw_line_8;
- break;
- case 15:
- fn = draw_line_15;
- dest_width *= 2;
- break;
- case 16:
- fn = draw_line_16;
- dest_width *= 2;
- break;
- case 24:
- fn = draw_line_24;
- dest_width *= 3;
- break;
- case 32:
- fn = draw_line_32;
- dest_width *= 4;
- break;
- default:
- hw_error("milkymist_vgafb: bad color depth\n");
- break;
- }
-
- src_width = s->regs[R_HRES] * 2;
- if (s->invalidate) {
- framebuffer_update_memory_section(&s->fbsection,
- sysbus_address_space(sbd),
- s->regs[R_BASEADDRESS] + s->fb_offset,
- s->regs[R_VRES], src_width);
- }
-
- framebuffer_update_display(surface, &s->fbsection,
- s->regs[R_HRES],
- s->regs[R_VRES],
- src_width,
- dest_width,
- 0,
- s->invalidate,
- fn,
- NULL,
- &first, &last);
-
- if (first >= 0) {
- dpy_gfx_update(s->con, 0, first, s->regs[R_HRES], last - first + 1);
- }
- s->invalidate = 0;
-}
-
-static void vgafb_invalidate_display(void *opaque)
-{
- MilkymistVgafbState *s = opaque;
- s->invalidate = 1;
-}
-
-static void vgafb_resize(MilkymistVgafbState *s)
-{
- if (!vgafb_enabled(s)) {
- return;
- }
-
- qemu_console_resize(s->con, s->regs[R_HRES], s->regs[R_VRES]);
- s->invalidate = 1;
-}
-
-static uint64_t vgafb_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- MilkymistVgafbState *s = opaque;
- uint32_t r = 0;
-
- addr >>= 2;
- switch (addr) {
- case R_CTRL:
- case R_HRES:
- case R_HSYNC_START:
- case R_HSYNC_END:
- case R_HSCAN:
- case R_VRES:
- case R_VSYNC_START:
- case R_VSYNC_END:
- case R_VSCAN:
- case R_BASEADDRESS:
- case R_BURST_COUNT:
- case R_DDC:
- case R_SOURCE_CLOCK:
- r = s->regs[addr];
- break;
- case R_BASEADDRESS_ACT:
- r = s->regs[R_BASEADDRESS];
- break;
-
- default:
- error_report("milkymist_vgafb: read access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-
- trace_milkymist_vgafb_memory_read(addr << 2, r);
-
- return r;
-}
-
-static void vgafb_write(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
- MilkymistVgafbState *s = opaque;
-
- trace_milkymist_vgafb_memory_write(addr, value);
-
- addr >>= 2;
- switch (addr) {
- case R_CTRL:
- s->regs[addr] = value;
- vgafb_resize(s);
- break;
- case R_HSYNC_START:
- case R_HSYNC_END:
- case R_HSCAN:
- case R_VSYNC_START:
- case R_VSYNC_END:
- case R_VSCAN:
- case R_BURST_COUNT:
- case R_DDC:
- case R_SOURCE_CLOCK:
- s->regs[addr] = value;
- break;
- case R_BASEADDRESS:
- if (value & 0x1f) {
- error_report("milkymist_vgafb: framebuffer base address have to "
- "be 32 byte aligned");
- break;
- }
- s->regs[addr] = value & s->fb_mask;
- s->invalidate = 1;
- break;
- case R_HRES:
- case R_VRES:
- s->regs[addr] = value;
- vgafb_resize(s);
- break;
- case R_BASEADDRESS_ACT:
- error_report("milkymist_vgafb: write to read-only register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
-
- default:
- error_report("milkymist_vgafb: write access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-}
-
-static const MemoryRegionOps vgafb_mmio_ops = {
- .read = vgafb_read,
- .write = vgafb_write,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void milkymist_vgafb_reset(DeviceState *d)
-{
- MilkymistVgafbState *s = MILKYMIST_VGAFB(d);
- int i;
-
- for (i = 0; i < R_MAX; i++) {
- s->regs[i] = 0;
- }
-
- /* defaults */
- s->regs[R_CTRL] = CTRL_RESET;
- s->regs[R_HRES] = 640;
- s->regs[R_VRES] = 480;
- s->regs[R_BASEADDRESS] = 0;
-}
-
-static const GraphicHwOps vgafb_ops = {
- .invalidate = vgafb_invalidate_display,
- .gfx_update = vgafb_update_display,
-};
-
-static int milkymist_vgafb_init(SysBusDevice *dev)
-{
- MilkymistVgafbState *s = MILKYMIST_VGAFB(dev);
-
- memory_region_init_io(&s->regs_region, OBJECT(s), &vgafb_mmio_ops, s,
- "milkymist-vgafb", R_MAX * 4);
- sysbus_init_mmio(dev, &s->regs_region);
-
- s->con = graphic_console_init(DEVICE(dev), 0, &vgafb_ops, s);
-
- return 0;
-}
-
-static int vgafb_post_load(void *opaque, int version_id)
-{
- vgafb_invalidate_display(opaque);
- return 0;
-}
-
-static const VMStateDescription vmstate_milkymist_vgafb = {
- .name = "milkymist-vgafb",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = vgafb_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, MilkymistVgafbState, R_MAX),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property milkymist_vgafb_properties[] = {
- DEFINE_PROP_UINT32("fb_offset", MilkymistVgafbState, fb_offset, 0x0),
- DEFINE_PROP_UINT32("fb_mask", MilkymistVgafbState, fb_mask, 0xffffffff),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void milkymist_vgafb_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = milkymist_vgafb_init;
- dc->reset = milkymist_vgafb_reset;
- dc->vmsd = &vmstate_milkymist_vgafb;
- dc->props = milkymist_vgafb_properties;
-}
-
-static const TypeInfo milkymist_vgafb_info = {
- .name = TYPE_MILKYMIST_VGAFB,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(MilkymistVgafbState),
- .class_init = milkymist_vgafb_class_init,
-};
-
-static void milkymist_vgafb_register_types(void)
-{
- type_register_static(&milkymist_vgafb_info);
-}
-
-type_init(milkymist_vgafb_register_types)
diff --git a/qemu/hw/display/milkymist-vgafb_template.h b/qemu/hw/display/milkymist-vgafb_template.h
deleted file mode 100644
index 48837809e..000000000
--- a/qemu/hw/display/milkymist-vgafb_template.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * QEMU model of the Milkymist VGA framebuffer.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#if BITS == 8
-#define COPY_PIXEL(to, r, g, b) \
- do { \
- *to = rgb_to_pixel8(r, g, b); \
- to += 1; \
- } while (0)
-#elif BITS == 15
-#define COPY_PIXEL(to, r, g, b) \
- do { \
- *(uint16_t *)to = rgb_to_pixel15(r, g, b); \
- to += 2; \
- } while (0)
-#elif BITS == 16
-#define COPY_PIXEL(to, r, g, b) \
- do { \
- *(uint16_t *)to = rgb_to_pixel16(r, g, b); \
- to += 2; \
- } while (0)
-#elif BITS == 24
-#define COPY_PIXEL(to, r, g, b) \
- do { \
- uint32_t tmp = rgb_to_pixel24(r, g, b); \
- *(to++) = tmp & 0xff; \
- *(to++) = (tmp >> 8) & 0xff; \
- *(to++) = (tmp >> 16) & 0xff; \
- } while (0)
-#elif BITS == 32
-#define COPY_PIXEL(to, r, g, b) \
- do { \
- *(uint32_t *)to = rgb_to_pixel32(r, g, b); \
- to += 4; \
- } while (0)
-#else
-#error unknown bit depth
-#endif
-
-static void glue(draw_line_, BITS)(void *opaque, uint8_t *d, const uint8_t *s,
- int width, int deststep)
-{
- uint16_t rgb565;
- uint8_t r, g, b;
-
- while (width--) {
- rgb565 = lduw_be_p(s);
- r = ((rgb565 >> 11) & 0x1f) << 3;
- g = ((rgb565 >> 5) & 0x3f) << 2;
- b = ((rgb565 >> 0) & 0x1f) << 3;
- COPY_PIXEL(d, r, g, b);
- s += 2;
- }
-}
-
-#undef BITS
-#undef COPY_PIXEL
diff --git a/qemu/hw/display/omap_dss.c b/qemu/hw/display/omap_dss.c
deleted file mode 100644
index 783e9e131..000000000
--- a/qemu/hw/display/omap_dss.c
+++ /dev/null
@@ -1,1091 +0,0 @@
-/*
- * OMAP2 Display Subsystem.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "ui/console.h"
-#include "hw/arm/omap.h"
-
-struct omap_dss_s {
- qemu_irq irq;
- qemu_irq drq;
- DisplayState *state;
- MemoryRegion iomem_diss1, iomem_disc1, iomem_rfbi1, iomem_venc1, iomem_im3;
-
- int autoidle;
- int control;
- int enable;
-
- struct omap_dss_panel_s {
- int enable;
- int nx;
- int ny;
-
- int x;
- int y;
- } dig, lcd;
-
- struct {
- uint32_t idlemode;
- uint32_t irqst;
- uint32_t irqen;
- uint32_t control;
- uint32_t config;
- uint32_t capable;
- uint32_t timing[4];
- int line;
- uint32_t bg[2];
- uint32_t trans[2];
-
- struct omap_dss_plane_s {
- int enable;
- int bpp;
- int posx;
- int posy;
- int nx;
- int ny;
-
- hwaddr addr[3];
-
- uint32_t attr;
- uint32_t tresh;
- int rowinc;
- int colinc;
- int wininc;
- } l[3];
-
- int invalidate;
- uint16_t palette[256];
- } dispc;
-
- struct {
- int idlemode;
- uint32_t control;
- int enable;
- int pixels;
- int busy;
- int skiplines;
- uint16_t rxbuf;
- uint32_t config[2];
- uint32_t time[4];
- uint32_t data[6];
- uint16_t vsync;
- uint16_t hsync;
- struct rfbi_chip_s *chip[2];
- } rfbi;
-};
-
-static void omap_dispc_interrupt_update(struct omap_dss_s *s)
-{
- qemu_set_irq(s->irq, s->dispc.irqst & s->dispc.irqen);
-}
-
-static void omap_rfbi_reset(struct omap_dss_s *s)
-{
- s->rfbi.idlemode = 0;
- s->rfbi.control = 2;
- s->rfbi.enable = 0;
- s->rfbi.pixels = 0;
- s->rfbi.skiplines = 0;
- s->rfbi.busy = 0;
- s->rfbi.config[0] = 0x00310000;
- s->rfbi.config[1] = 0x00310000;
- s->rfbi.time[0] = 0;
- s->rfbi.time[1] = 0;
- s->rfbi.time[2] = 0;
- s->rfbi.time[3] = 0;
- s->rfbi.data[0] = 0;
- s->rfbi.data[1] = 0;
- s->rfbi.data[2] = 0;
- s->rfbi.data[3] = 0;
- s->rfbi.data[4] = 0;
- s->rfbi.data[5] = 0;
- s->rfbi.vsync = 0;
- s->rfbi.hsync = 0;
-}
-
-void omap_dss_reset(struct omap_dss_s *s)
-{
- s->autoidle = 0;
- s->control = 0;
- s->enable = 0;
-
- s->dig.enable = 0;
- s->dig.nx = 1;
- s->dig.ny = 1;
-
- s->lcd.enable = 0;
- s->lcd.nx = 1;
- s->lcd.ny = 1;
-
- s->dispc.idlemode = 0;
- s->dispc.irqst = 0;
- s->dispc.irqen = 0;
- s->dispc.control = 0;
- s->dispc.config = 0;
- s->dispc.capable = 0x161;
- s->dispc.timing[0] = 0;
- s->dispc.timing[1] = 0;
- s->dispc.timing[2] = 0;
- s->dispc.timing[3] = 0;
- s->dispc.line = 0;
- s->dispc.bg[0] = 0;
- s->dispc.bg[1] = 0;
- s->dispc.trans[0] = 0;
- s->dispc.trans[1] = 0;
-
- s->dispc.l[0].enable = 0;
- s->dispc.l[0].bpp = 0;
- s->dispc.l[0].addr[0] = 0;
- s->dispc.l[0].addr[1] = 0;
- s->dispc.l[0].addr[2] = 0;
- s->dispc.l[0].posx = 0;
- s->dispc.l[0].posy = 0;
- s->dispc.l[0].nx = 1;
- s->dispc.l[0].ny = 1;
- s->dispc.l[0].attr = 0;
- s->dispc.l[0].tresh = 0;
- s->dispc.l[0].rowinc = 1;
- s->dispc.l[0].colinc = 1;
- s->dispc.l[0].wininc = 0;
-
- omap_rfbi_reset(s);
- omap_dispc_interrupt_update(s);
-}
-
-static uint64_t omap_diss_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_dss_s *s = (struct omap_dss_s *) opaque;
-
- if (size != 4) {
- return omap_badwidth_read32(opaque, addr);
- }
-
- switch (addr) {
- case 0x00: /* DSS_REVISIONNUMBER */
- return 0x20;
-
- case 0x10: /* DSS_SYSCONFIG */
- return s->autoidle;
-
- case 0x14: /* DSS_SYSSTATUS */
- return 1; /* RESETDONE */
-
- case 0x40: /* DSS_CONTROL */
- return s->control;
-
- case 0x50: /* DSS_PSA_LCD_REG_1 */
- case 0x54: /* DSS_PSA_LCD_REG_2 */
- case 0x58: /* DSS_PSA_VIDEO_REG */
- /* TODO: fake some values when appropriate s->control bits are set */
- return 0;
-
- case 0x5c: /* DSS_STATUS */
- return 1 + (s->control & 1);
-
- default:
- break;
- }
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_diss_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_dss_s *s = (struct omap_dss_s *) opaque;
-
- if (size != 4) {
- omap_badwidth_write32(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x00: /* DSS_REVISIONNUMBER */
- case 0x14: /* DSS_SYSSTATUS */
- case 0x50: /* DSS_PSA_LCD_REG_1 */
- case 0x54: /* DSS_PSA_LCD_REG_2 */
- case 0x58: /* DSS_PSA_VIDEO_REG */
- case 0x5c: /* DSS_STATUS */
- OMAP_RO_REG(addr);
- break;
-
- case 0x10: /* DSS_SYSCONFIG */
- if (value & 2) /* SOFTRESET */
- omap_dss_reset(s);
- s->autoidle = value & 1;
- break;
-
- case 0x40: /* DSS_CONTROL */
- s->control = value & 0x3dd;
- break;
-
- default:
- OMAP_BAD_REG(addr);
- }
-}
-
-static const MemoryRegionOps omap_diss_ops = {
- .read = omap_diss_read,
- .write = omap_diss_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static uint64_t omap_disc_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_dss_s *s = (struct omap_dss_s *) opaque;
-
- if (size != 4) {
- return omap_badwidth_read32(opaque, addr);
- }
-
- switch (addr) {
- case 0x000: /* DISPC_REVISION */
- return 0x20;
-
- case 0x010: /* DISPC_SYSCONFIG */
- return s->dispc.idlemode;
-
- case 0x014: /* DISPC_SYSSTATUS */
- return 1; /* RESETDONE */
-
- case 0x018: /* DISPC_IRQSTATUS */
- return s->dispc.irqst;
-
- case 0x01c: /* DISPC_IRQENABLE */
- return s->dispc.irqen;
-
- case 0x040: /* DISPC_CONTROL */
- return s->dispc.control;
-
- case 0x044: /* DISPC_CONFIG */
- return s->dispc.config;
-
- case 0x048: /* DISPC_CAPABLE */
- return s->dispc.capable;
-
- case 0x04c: /* DISPC_DEFAULT_COLOR0 */
- return s->dispc.bg[0];
- case 0x050: /* DISPC_DEFAULT_COLOR1 */
- return s->dispc.bg[1];
- case 0x054: /* DISPC_TRANS_COLOR0 */
- return s->dispc.trans[0];
- case 0x058: /* DISPC_TRANS_COLOR1 */
- return s->dispc.trans[1];
-
- case 0x05c: /* DISPC_LINE_STATUS */
- return 0x7ff;
- case 0x060: /* DISPC_LINE_NUMBER */
- return s->dispc.line;
-
- case 0x064: /* DISPC_TIMING_H */
- return s->dispc.timing[0];
- case 0x068: /* DISPC_TIMING_V */
- return s->dispc.timing[1];
- case 0x06c: /* DISPC_POL_FREQ */
- return s->dispc.timing[2];
- case 0x070: /* DISPC_DIVISOR */
- return s->dispc.timing[3];
-
- case 0x078: /* DISPC_SIZE_DIG */
- return ((s->dig.ny - 1) << 16) | (s->dig.nx - 1);
- case 0x07c: /* DISPC_SIZE_LCD */
- return ((s->lcd.ny - 1) << 16) | (s->lcd.nx - 1);
-
- case 0x080: /* DISPC_GFX_BA0 */
- return s->dispc.l[0].addr[0];
- case 0x084: /* DISPC_GFX_BA1 */
- return s->dispc.l[0].addr[1];
- case 0x088: /* DISPC_GFX_POSITION */
- return (s->dispc.l[0].posy << 16) | s->dispc.l[0].posx;
- case 0x08c: /* DISPC_GFX_SIZE */
- return ((s->dispc.l[0].ny - 1) << 16) | (s->dispc.l[0].nx - 1);
- case 0x0a0: /* DISPC_GFX_ATTRIBUTES */
- return s->dispc.l[0].attr;
- case 0x0a4: /* DISPC_GFX_FIFO_TRESHOLD */
- return s->dispc.l[0].tresh;
- case 0x0a8: /* DISPC_GFX_FIFO_SIZE_STATUS */
- return 256;
- case 0x0ac: /* DISPC_GFX_ROW_INC */
- return s->dispc.l[0].rowinc;
- case 0x0b0: /* DISPC_GFX_PIXEL_INC */
- return s->dispc.l[0].colinc;
- case 0x0b4: /* DISPC_GFX_WINDOW_SKIP */
- return s->dispc.l[0].wininc;
- case 0x0b8: /* DISPC_GFX_TABLE_BA */
- return s->dispc.l[0].addr[2];
-
- case 0x0bc: /* DISPC_VID1_BA0 */
- case 0x0c0: /* DISPC_VID1_BA1 */
- case 0x0c4: /* DISPC_VID1_POSITION */
- case 0x0c8: /* DISPC_VID1_SIZE */
- case 0x0cc: /* DISPC_VID1_ATTRIBUTES */
- case 0x0d0: /* DISPC_VID1_FIFO_TRESHOLD */
- case 0x0d4: /* DISPC_VID1_FIFO_SIZE_STATUS */
- case 0x0d8: /* DISPC_VID1_ROW_INC */
- case 0x0dc: /* DISPC_VID1_PIXEL_INC */
- case 0x0e0: /* DISPC_VID1_FIR */
- case 0x0e4: /* DISPC_VID1_PICTURE_SIZE */
- case 0x0e8: /* DISPC_VID1_ACCU0 */
- case 0x0ec: /* DISPC_VID1_ACCU1 */
- case 0x0f0 ... 0x140: /* DISPC_VID1_FIR_COEF, DISPC_VID1_CONV_COEF */
- case 0x14c: /* DISPC_VID2_BA0 */
- case 0x150: /* DISPC_VID2_BA1 */
- case 0x154: /* DISPC_VID2_POSITION */
- case 0x158: /* DISPC_VID2_SIZE */
- case 0x15c: /* DISPC_VID2_ATTRIBUTES */
- case 0x160: /* DISPC_VID2_FIFO_TRESHOLD */
- case 0x164: /* DISPC_VID2_FIFO_SIZE_STATUS */
- case 0x168: /* DISPC_VID2_ROW_INC */
- case 0x16c: /* DISPC_VID2_PIXEL_INC */
- case 0x170: /* DISPC_VID2_FIR */
- case 0x174: /* DISPC_VID2_PICTURE_SIZE */
- case 0x178: /* DISPC_VID2_ACCU0 */
- case 0x17c: /* DISPC_VID2_ACCU1 */
- case 0x180 ... 0x1d0: /* DISPC_VID2_FIR_COEF, DISPC_VID2_CONV_COEF */
- case 0x1d4: /* DISPC_DATA_CYCLE1 */
- case 0x1d8: /* DISPC_DATA_CYCLE2 */
- case 0x1dc: /* DISPC_DATA_CYCLE3 */
- return 0;
-
- default:
- break;
- }
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_disc_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_dss_s *s = (struct omap_dss_s *) opaque;
-
- if (size != 4) {
- omap_badwidth_write32(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x010: /* DISPC_SYSCONFIG */
- if (value & 2) /* SOFTRESET */
- omap_dss_reset(s);
- s->dispc.idlemode = value & 0x301b;
- break;
-
- case 0x018: /* DISPC_IRQSTATUS */
- s->dispc.irqst &= ~value;
- omap_dispc_interrupt_update(s);
- break;
-
- case 0x01c: /* DISPC_IRQENABLE */
- s->dispc.irqen = value & 0xffff;
- omap_dispc_interrupt_update(s);
- break;
-
- case 0x040: /* DISPC_CONTROL */
- s->dispc.control = value & 0x07ff9fff;
- s->dig.enable = (value >> 1) & 1;
- s->lcd.enable = (value >> 0) & 1;
- if (value & (1 << 12)) /* OVERLAY_OPTIMIZATION */
- if (!((s->dispc.l[1].attr | s->dispc.l[2].attr) & 1)) {
- fprintf(stderr, "%s: Overlay Optimization when no overlay "
- "region effectively exists leads to "
- "unpredictable behaviour!\n", __func__);
- }
- if (value & (1 << 6)) { /* GODIGITAL */
- /* XXX: Shadowed fields are:
- * s->dispc.config
- * s->dispc.capable
- * s->dispc.bg[0]
- * s->dispc.bg[1]
- * s->dispc.trans[0]
- * s->dispc.trans[1]
- * s->dispc.line
- * s->dispc.timing[0]
- * s->dispc.timing[1]
- * s->dispc.timing[2]
- * s->dispc.timing[3]
- * s->lcd.nx
- * s->lcd.ny
- * s->dig.nx
- * s->dig.ny
- * s->dispc.l[0].addr[0]
- * s->dispc.l[0].addr[1]
- * s->dispc.l[0].addr[2]
- * s->dispc.l[0].posx
- * s->dispc.l[0].posy
- * s->dispc.l[0].nx
- * s->dispc.l[0].ny
- * s->dispc.l[0].tresh
- * s->dispc.l[0].rowinc
- * s->dispc.l[0].colinc
- * s->dispc.l[0].wininc
- * All they need to be loaded here from their shadow registers.
- */
- }
- if (value & (1 << 5)) { /* GOLCD */
- /* XXX: Likewise for LCD here. */
- }
- s->dispc.invalidate = 1;
- break;
-
- case 0x044: /* DISPC_CONFIG */
- s->dispc.config = value & 0x3fff;
- /* XXX:
- * bits 2:1 (LOADMODE) reset to 0 after set to 1 and palette loaded
- * bits 2:1 (LOADMODE) reset to 2 after set to 3 and palette loaded
- */
- s->dispc.invalidate = 1;
- break;
-
- case 0x048: /* DISPC_CAPABLE */
- s->dispc.capable = value & 0x3ff;
- break;
-
- case 0x04c: /* DISPC_DEFAULT_COLOR0 */
- s->dispc.bg[0] = value & 0xffffff;
- s->dispc.invalidate = 1;
- break;
- case 0x050: /* DISPC_DEFAULT_COLOR1 */
- s->dispc.bg[1] = value & 0xffffff;
- s->dispc.invalidate = 1;
- break;
- case 0x054: /* DISPC_TRANS_COLOR0 */
- s->dispc.trans[0] = value & 0xffffff;
- s->dispc.invalidate = 1;
- break;
- case 0x058: /* DISPC_TRANS_COLOR1 */
- s->dispc.trans[1] = value & 0xffffff;
- s->dispc.invalidate = 1;
- break;
-
- case 0x060: /* DISPC_LINE_NUMBER */
- s->dispc.line = value & 0x7ff;
- break;
-
- case 0x064: /* DISPC_TIMING_H */
- s->dispc.timing[0] = value & 0x0ff0ff3f;
- break;
- case 0x068: /* DISPC_TIMING_V */
- s->dispc.timing[1] = value & 0x0ff0ff3f;
- break;
- case 0x06c: /* DISPC_POL_FREQ */
- s->dispc.timing[2] = value & 0x0003ffff;
- break;
- case 0x070: /* DISPC_DIVISOR */
- s->dispc.timing[3] = value & 0x00ff00ff;
- break;
-
- case 0x078: /* DISPC_SIZE_DIG */
- s->dig.nx = ((value >> 0) & 0x7ff) + 1; /* PPL */
- s->dig.ny = ((value >> 16) & 0x7ff) + 1; /* LPP */
- s->dispc.invalidate = 1;
- break;
- case 0x07c: /* DISPC_SIZE_LCD */
- s->lcd.nx = ((value >> 0) & 0x7ff) + 1; /* PPL */
- s->lcd.ny = ((value >> 16) & 0x7ff) + 1; /* LPP */
- s->dispc.invalidate = 1;
- break;
- case 0x080: /* DISPC_GFX_BA0 */
- s->dispc.l[0].addr[0] = (hwaddr) value;
- s->dispc.invalidate = 1;
- break;
- case 0x084: /* DISPC_GFX_BA1 */
- s->dispc.l[0].addr[1] = (hwaddr) value;
- s->dispc.invalidate = 1;
- break;
- case 0x088: /* DISPC_GFX_POSITION */
- s->dispc.l[0].posx = ((value >> 0) & 0x7ff); /* GFXPOSX */
- s->dispc.l[0].posy = ((value >> 16) & 0x7ff); /* GFXPOSY */
- s->dispc.invalidate = 1;
- break;
- case 0x08c: /* DISPC_GFX_SIZE */
- s->dispc.l[0].nx = ((value >> 0) & 0x7ff) + 1; /* GFXSIZEX */
- s->dispc.l[0].ny = ((value >> 16) & 0x7ff) + 1; /* GFXSIZEY */
- s->dispc.invalidate = 1;
- break;
- case 0x0a0: /* DISPC_GFX_ATTRIBUTES */
- s->dispc.l[0].attr = value & 0x7ff;
- if (value & (3 << 9))
- fprintf(stderr, "%s: Big-endian pixel format not supported\n",
- __FUNCTION__);
- s->dispc.l[0].enable = value & 1;
- s->dispc.l[0].bpp = (value >> 1) & 0xf;
- s->dispc.invalidate = 1;
- break;
- case 0x0a4: /* DISPC_GFX_FIFO_TRESHOLD */
- s->dispc.l[0].tresh = value & 0x01ff01ff;
- break;
- case 0x0ac: /* DISPC_GFX_ROW_INC */
- s->dispc.l[0].rowinc = value;
- s->dispc.invalidate = 1;
- break;
- case 0x0b0: /* DISPC_GFX_PIXEL_INC */
- s->dispc.l[0].colinc = value;
- s->dispc.invalidate = 1;
- break;
- case 0x0b4: /* DISPC_GFX_WINDOW_SKIP */
- s->dispc.l[0].wininc = value;
- break;
- case 0x0b8: /* DISPC_GFX_TABLE_BA */
- s->dispc.l[0].addr[2] = (hwaddr) value;
- s->dispc.invalidate = 1;
- break;
-
- case 0x0bc: /* DISPC_VID1_BA0 */
- case 0x0c0: /* DISPC_VID1_BA1 */
- case 0x0c4: /* DISPC_VID1_POSITION */
- case 0x0c8: /* DISPC_VID1_SIZE */
- case 0x0cc: /* DISPC_VID1_ATTRIBUTES */
- case 0x0d0: /* DISPC_VID1_FIFO_TRESHOLD */
- case 0x0d8: /* DISPC_VID1_ROW_INC */
- case 0x0dc: /* DISPC_VID1_PIXEL_INC */
- case 0x0e0: /* DISPC_VID1_FIR */
- case 0x0e4: /* DISPC_VID1_PICTURE_SIZE */
- case 0x0e8: /* DISPC_VID1_ACCU0 */
- case 0x0ec: /* DISPC_VID1_ACCU1 */
- case 0x0f0 ... 0x140: /* DISPC_VID1_FIR_COEF, DISPC_VID1_CONV_COEF */
- case 0x14c: /* DISPC_VID2_BA0 */
- case 0x150: /* DISPC_VID2_BA1 */
- case 0x154: /* DISPC_VID2_POSITION */
- case 0x158: /* DISPC_VID2_SIZE */
- case 0x15c: /* DISPC_VID2_ATTRIBUTES */
- case 0x160: /* DISPC_VID2_FIFO_TRESHOLD */
- case 0x168: /* DISPC_VID2_ROW_INC */
- case 0x16c: /* DISPC_VID2_PIXEL_INC */
- case 0x170: /* DISPC_VID2_FIR */
- case 0x174: /* DISPC_VID2_PICTURE_SIZE */
- case 0x178: /* DISPC_VID2_ACCU0 */
- case 0x17c: /* DISPC_VID2_ACCU1 */
- case 0x180 ... 0x1d0: /* DISPC_VID2_FIR_COEF, DISPC_VID2_CONV_COEF */
- case 0x1d4: /* DISPC_DATA_CYCLE1 */
- case 0x1d8: /* DISPC_DATA_CYCLE2 */
- case 0x1dc: /* DISPC_DATA_CYCLE3 */
- break;
-
- default:
- OMAP_BAD_REG(addr);
- }
-}
-
-static const MemoryRegionOps omap_disc_ops = {
- .read = omap_disc_read,
- .write = omap_disc_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void omap_rfbi_transfer_stop(struct omap_dss_s *s)
-{
- if (!s->rfbi.busy)
- return;
-
- /* TODO: in non-Bypass mode we probably need to just deassert the DRQ. */
-
- s->rfbi.busy = 0;
-}
-
-static void omap_rfbi_transfer_start(struct omap_dss_s *s)
-{
- void *data;
- hwaddr len;
- hwaddr data_addr;
- int pitch;
- static void *bounce_buffer;
- static hwaddr bounce_len;
-
- if (!s->rfbi.enable || s->rfbi.busy)
- return;
-
- if (s->rfbi.control & (1 << 1)) { /* BYPASS */
- /* TODO: in non-Bypass mode we probably need to just assert the
- * DRQ and wait for DMA to write the pixels. */
- fprintf(stderr, "%s: Bypass mode unimplemented\n", __FUNCTION__);
- return;
- }
-
- if (!(s->dispc.control & (1 << 11))) /* RFBIMODE */
- return;
- /* TODO: check that LCD output is enabled in DISPC. */
-
- s->rfbi.busy = 1;
-
- len = s->rfbi.pixels * 2;
-
- data_addr = s->dispc.l[0].addr[0];
- data = cpu_physical_memory_map(data_addr, &len, 0);
- if (data && len != s->rfbi.pixels * 2) {
- cpu_physical_memory_unmap(data, len, 0, 0);
- data = NULL;
- len = s->rfbi.pixels * 2;
- }
- if (!data) {
- if (len > bounce_len) {
- bounce_buffer = g_realloc(bounce_buffer, len);
- }
- data = bounce_buffer;
- cpu_physical_memory_read(data_addr, data, len);
- }
-
- /* TODO bpp */
- s->rfbi.pixels = 0;
-
- /* TODO: negative values */
- pitch = s->dispc.l[0].nx + (s->dispc.l[0].rowinc - 1) / 2;
-
- if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
- s->rfbi.chip[0]->block(s->rfbi.chip[0]->opaque, 1, data, len, pitch);
- if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
- s->rfbi.chip[1]->block(s->rfbi.chip[1]->opaque, 1, data, len, pitch);
-
- if (data != bounce_buffer) {
- cpu_physical_memory_unmap(data, len, 0, len);
- }
-
- omap_rfbi_transfer_stop(s);
-
- /* TODO */
- s->dispc.irqst |= 1; /* FRAMEDONE */
- omap_dispc_interrupt_update(s);
-}
-
-static uint64_t omap_rfbi_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_dss_s *s = (struct omap_dss_s *) opaque;
-
- if (size != 4) {
- return omap_badwidth_read32(opaque, addr);
- }
-
- switch (addr) {
- case 0x00: /* RFBI_REVISION */
- return 0x10;
-
- case 0x10: /* RFBI_SYSCONFIG */
- return s->rfbi.idlemode;
-
- case 0x14: /* RFBI_SYSSTATUS */
- return 1 | (s->rfbi.busy << 8); /* RESETDONE */
-
- case 0x40: /* RFBI_CONTROL */
- return s->rfbi.control;
-
- case 0x44: /* RFBI_PIXELCNT */
- return s->rfbi.pixels;
-
- case 0x48: /* RFBI_LINE_NUMBER */
- return s->rfbi.skiplines;
-
- case 0x58: /* RFBI_READ */
- case 0x5c: /* RFBI_STATUS */
- return s->rfbi.rxbuf;
-
- case 0x60: /* RFBI_CONFIG0 */
- return s->rfbi.config[0];
- case 0x64: /* RFBI_ONOFF_TIME0 */
- return s->rfbi.time[0];
- case 0x68: /* RFBI_CYCLE_TIME0 */
- return s->rfbi.time[1];
- case 0x6c: /* RFBI_DATA_CYCLE1_0 */
- return s->rfbi.data[0];
- case 0x70: /* RFBI_DATA_CYCLE2_0 */
- return s->rfbi.data[1];
- case 0x74: /* RFBI_DATA_CYCLE3_0 */
- return s->rfbi.data[2];
-
- case 0x78: /* RFBI_CONFIG1 */
- return s->rfbi.config[1];
- case 0x7c: /* RFBI_ONOFF_TIME1 */
- return s->rfbi.time[2];
- case 0x80: /* RFBI_CYCLE_TIME1 */
- return s->rfbi.time[3];
- case 0x84: /* RFBI_DATA_CYCLE1_1 */
- return s->rfbi.data[3];
- case 0x88: /* RFBI_DATA_CYCLE2_1 */
- return s->rfbi.data[4];
- case 0x8c: /* RFBI_DATA_CYCLE3_1 */
- return s->rfbi.data[5];
-
- case 0x90: /* RFBI_VSYNC_WIDTH */
- return s->rfbi.vsync;
- case 0x94: /* RFBI_HSYNC_WIDTH */
- return s->rfbi.hsync;
- }
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_rfbi_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_dss_s *s = (struct omap_dss_s *) opaque;
-
- if (size != 4) {
- omap_badwidth_write32(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x10: /* RFBI_SYSCONFIG */
- if (value & 2) /* SOFTRESET */
- omap_rfbi_reset(s);
- s->rfbi.idlemode = value & 0x19;
- break;
-
- case 0x40: /* RFBI_CONTROL */
- s->rfbi.control = value & 0xf;
- s->rfbi.enable = value & 1;
- if (value & (1 << 4) && /* ITE */
- !(s->rfbi.config[0] & s->rfbi.config[1] & 0xc))
- omap_rfbi_transfer_start(s);
- break;
-
- case 0x44: /* RFBI_PIXELCNT */
- s->rfbi.pixels = value;
- break;
-
- case 0x48: /* RFBI_LINE_NUMBER */
- s->rfbi.skiplines = value & 0x7ff;
- break;
-
- case 0x4c: /* RFBI_CMD */
- if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
- s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 0, value & 0xffff);
- if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
- s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 0, value & 0xffff);
- break;
- case 0x50: /* RFBI_PARAM */
- if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
- s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value & 0xffff);
- if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
- s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value & 0xffff);
- break;
- case 0x54: /* RFBI_DATA */
- /* TODO: take into account the format set up in s->rfbi.config[?] and
- * s->rfbi.data[?], but special-case the most usual scenario so that
- * speed doesn't suffer. */
- if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0]) {
- s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value & 0xffff);
- s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value >> 16);
- }
- if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1]) {
- s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value & 0xffff);
- s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value >> 16);
- }
- if (!-- s->rfbi.pixels)
- omap_rfbi_transfer_stop(s);
- break;
- case 0x58: /* RFBI_READ */
- if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
- s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 1);
- else if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
- s->rfbi.rxbuf = s->rfbi.chip[1]->read(s->rfbi.chip[1]->opaque, 1);
- if (!-- s->rfbi.pixels)
- omap_rfbi_transfer_stop(s);
- break;
-
- case 0x5c: /* RFBI_STATUS */
- if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
- s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 0);
- else if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
- s->rfbi.rxbuf = s->rfbi.chip[1]->read(s->rfbi.chip[1]->opaque, 0);
- if (!-- s->rfbi.pixels)
- omap_rfbi_transfer_stop(s);
- break;
-
- case 0x60: /* RFBI_CONFIG0 */
- s->rfbi.config[0] = value & 0x003f1fff;
- break;
-
- case 0x64: /* RFBI_ONOFF_TIME0 */
- s->rfbi.time[0] = value & 0x3fffffff;
- break;
- case 0x68: /* RFBI_CYCLE_TIME0 */
- s->rfbi.time[1] = value & 0x0fffffff;
- break;
- case 0x6c: /* RFBI_DATA_CYCLE1_0 */
- s->rfbi.data[0] = value & 0x0f1f0f1f;
- break;
- case 0x70: /* RFBI_DATA_CYCLE2_0 */
- s->rfbi.data[1] = value & 0x0f1f0f1f;
- break;
- case 0x74: /* RFBI_DATA_CYCLE3_0 */
- s->rfbi.data[2] = value & 0x0f1f0f1f;
- break;
- case 0x78: /* RFBI_CONFIG1 */
- s->rfbi.config[1] = value & 0x003f1fff;
- break;
-
- case 0x7c: /* RFBI_ONOFF_TIME1 */
- s->rfbi.time[2] = value & 0x3fffffff;
- break;
- case 0x80: /* RFBI_CYCLE_TIME1 */
- s->rfbi.time[3] = value & 0x0fffffff;
- break;
- case 0x84: /* RFBI_DATA_CYCLE1_1 */
- s->rfbi.data[3] = value & 0x0f1f0f1f;
- break;
- case 0x88: /* RFBI_DATA_CYCLE2_1 */
- s->rfbi.data[4] = value & 0x0f1f0f1f;
- break;
- case 0x8c: /* RFBI_DATA_CYCLE3_1 */
- s->rfbi.data[5] = value & 0x0f1f0f1f;
- break;
-
- case 0x90: /* RFBI_VSYNC_WIDTH */
- s->rfbi.vsync = value & 0xffff;
- break;
- case 0x94: /* RFBI_HSYNC_WIDTH */
- s->rfbi.hsync = value & 0xffff;
- break;
-
- default:
- OMAP_BAD_REG(addr);
- }
-}
-
-static const MemoryRegionOps omap_rfbi_ops = {
- .read = omap_rfbi_read,
- .write = omap_rfbi_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static uint64_t omap_venc_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- if (size != 4) {
- return omap_badwidth_read32(opaque, addr);
- }
-
- switch (addr) {
- case 0x00: /* REV_ID */
- case 0x04: /* STATUS */
- case 0x08: /* F_CONTROL */
- case 0x10: /* VIDOUT_CTRL */
- case 0x14: /* SYNC_CTRL */
- case 0x1c: /* LLEN */
- case 0x20: /* FLENS */
- case 0x24: /* HFLTR_CTRL */
- case 0x28: /* CC_CARR_WSS_CARR */
- case 0x2c: /* C_PHASE */
- case 0x30: /* GAIN_U */
- case 0x34: /* GAIN_V */
- case 0x38: /* GAIN_Y */
- case 0x3c: /* BLACK_LEVEL */
- case 0x40: /* BLANK_LEVEL */
- case 0x44: /* X_COLOR */
- case 0x48: /* M_CONTROL */
- case 0x4c: /* BSTAMP_WSS_DATA */
- case 0x50: /* S_CARR */
- case 0x54: /* LINE21 */
- case 0x58: /* LN_SEL */
- case 0x5c: /* L21__WC_CTL */
- case 0x60: /* HTRIGGER_VTRIGGER */
- case 0x64: /* SAVID__EAVID */
- case 0x68: /* FLEN__FAL */
- case 0x6c: /* LAL__PHASE_RESET */
- case 0x70: /* HS_INT_START_STOP_X */
- case 0x74: /* HS_EXT_START_STOP_X */
- case 0x78: /* VS_INT_START_X */
- case 0x7c: /* VS_INT_STOP_X__VS_INT_START_Y */
- case 0x80: /* VS_INT_STOP_Y__VS_INT_START_X */
- case 0x84: /* VS_EXT_STOP_X__VS_EXT_START_Y */
- case 0x88: /* VS_EXT_STOP_Y */
- case 0x90: /* AVID_START_STOP_X */
- case 0x94: /* AVID_START_STOP_Y */
- case 0xa0: /* FID_INT_START_X__FID_INT_START_Y */
- case 0xa4: /* FID_INT_OFFSET_Y__FID_EXT_START_X */
- case 0xa8: /* FID_EXT_START_Y__FID_EXT_OFFSET_Y */
- case 0xb0: /* TVDETGP_INT_START_STOP_X */
- case 0xb4: /* TVDETGP_INT_START_STOP_Y */
- case 0xb8: /* GEN_CTRL */
- case 0xc4: /* DAC_TST__DAC_A */
- case 0xc8: /* DAC_B__DAC_C */
- return 0;
-
- default:
- break;
- }
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_venc_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- if (size != 4) {
- omap_badwidth_write32(opaque, addr, size);
- return;
- }
-
- switch (addr) {
- case 0x08: /* F_CONTROL */
- case 0x10: /* VIDOUT_CTRL */
- case 0x14: /* SYNC_CTRL */
- case 0x1c: /* LLEN */
- case 0x20: /* FLENS */
- case 0x24: /* HFLTR_CTRL */
- case 0x28: /* CC_CARR_WSS_CARR */
- case 0x2c: /* C_PHASE */
- case 0x30: /* GAIN_U */
- case 0x34: /* GAIN_V */
- case 0x38: /* GAIN_Y */
- case 0x3c: /* BLACK_LEVEL */
- case 0x40: /* BLANK_LEVEL */
- case 0x44: /* X_COLOR */
- case 0x48: /* M_CONTROL */
- case 0x4c: /* BSTAMP_WSS_DATA */
- case 0x50: /* S_CARR */
- case 0x54: /* LINE21 */
- case 0x58: /* LN_SEL */
- case 0x5c: /* L21__WC_CTL */
- case 0x60: /* HTRIGGER_VTRIGGER */
- case 0x64: /* SAVID__EAVID */
- case 0x68: /* FLEN__FAL */
- case 0x6c: /* LAL__PHASE_RESET */
- case 0x70: /* HS_INT_START_STOP_X */
- case 0x74: /* HS_EXT_START_STOP_X */
- case 0x78: /* VS_INT_START_X */
- case 0x7c: /* VS_INT_STOP_X__VS_INT_START_Y */
- case 0x80: /* VS_INT_STOP_Y__VS_INT_START_X */
- case 0x84: /* VS_EXT_STOP_X__VS_EXT_START_Y */
- case 0x88: /* VS_EXT_STOP_Y */
- case 0x90: /* AVID_START_STOP_X */
- case 0x94: /* AVID_START_STOP_Y */
- case 0xa0: /* FID_INT_START_X__FID_INT_START_Y */
- case 0xa4: /* FID_INT_OFFSET_Y__FID_EXT_START_X */
- case 0xa8: /* FID_EXT_START_Y__FID_EXT_OFFSET_Y */
- case 0xb0: /* TVDETGP_INT_START_STOP_X */
- case 0xb4: /* TVDETGP_INT_START_STOP_Y */
- case 0xb8: /* GEN_CTRL */
- case 0xc4: /* DAC_TST__DAC_A */
- case 0xc8: /* DAC_B__DAC_C */
- break;
-
- default:
- OMAP_BAD_REG(addr);
- }
-}
-
-static const MemoryRegionOps omap_venc_ops = {
- .read = omap_venc_read,
- .write = omap_venc_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static uint64_t omap_im3_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- if (size != 4) {
- return omap_badwidth_read32(opaque, addr);
- }
-
- switch (addr) {
- case 0x0a8: /* SBIMERRLOGA */
- case 0x0b0: /* SBIMERRLOG */
- case 0x190: /* SBIMSTATE */
- case 0x198: /* SBTMSTATE_L */
- case 0x19c: /* SBTMSTATE_H */
- case 0x1a8: /* SBIMCONFIG_L */
- case 0x1ac: /* SBIMCONFIG_H */
- case 0x1f8: /* SBID_L */
- case 0x1fc: /* SBID_H */
- return 0;
-
- default:
- break;
- }
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_im3_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- if (size != 4) {
- omap_badwidth_write32(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x0b0: /* SBIMERRLOG */
- case 0x190: /* SBIMSTATE */
- case 0x198: /* SBTMSTATE_L */
- case 0x19c: /* SBTMSTATE_H */
- case 0x1a8: /* SBIMCONFIG_L */
- case 0x1ac: /* SBIMCONFIG_H */
- break;
-
- default:
- OMAP_BAD_REG(addr);
- }
-}
-
-static const MemoryRegionOps omap_im3_ops = {
- .read = omap_im3_read,
- .write = omap_im3_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct omap_dss_s *omap_dss_init(struct omap_target_agent_s *ta,
- MemoryRegion *sysmem,
- hwaddr l3_base,
- qemu_irq irq, qemu_irq drq,
- omap_clk fck1, omap_clk fck2, omap_clk ck54m,
- omap_clk ick1, omap_clk ick2)
-{
- struct omap_dss_s *s = g_new0(struct omap_dss_s, 1);
-
- s->irq = irq;
- s->drq = drq;
- omap_dss_reset(s);
-
- memory_region_init_io(&s->iomem_diss1, NULL, &omap_diss_ops, s, "omap.diss1",
- omap_l4_region_size(ta, 0));
- memory_region_init_io(&s->iomem_disc1, NULL, &omap_disc_ops, s, "omap.disc1",
- omap_l4_region_size(ta, 1));
- memory_region_init_io(&s->iomem_rfbi1, NULL, &omap_rfbi_ops, s, "omap.rfbi1",
- omap_l4_region_size(ta, 2));
- memory_region_init_io(&s->iomem_venc1, NULL, &omap_venc_ops, s, "omap.venc1",
- omap_l4_region_size(ta, 3));
- memory_region_init_io(&s->iomem_im3, NULL, &omap_im3_ops, s,
- "omap.im3", 0x1000);
-
- omap_l4_attach(ta, 0, &s->iomem_diss1);
- omap_l4_attach(ta, 1, &s->iomem_disc1);
- omap_l4_attach(ta, 2, &s->iomem_rfbi1);
- omap_l4_attach(ta, 3, &s->iomem_venc1);
- memory_region_add_subregion(sysmem, l3_base, &s->iomem_im3);
-
-#if 0
- s->state = graphic_console_init(omap_update_display,
- omap_invalidate_display, omap_screen_dump, s);
-#endif
-
- return s;
-}
-
-void omap_rfbi_attach(struct omap_dss_s *s, int cs, struct rfbi_chip_s *chip)
-{
- if (cs < 0 || cs > 1)
- hw_error("%s: wrong CS %i\n", __FUNCTION__, cs);
- s->rfbi.chip[cs] = chip;
-}
diff --git a/qemu/hw/display/omap_lcd_template.h b/qemu/hw/display/omap_lcd_template.h
deleted file mode 100644
index f0ce71fd6..000000000
--- a/qemu/hw/display/omap_lcd_template.h
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * QEMU OMAP LCD Emulator templates
- *
- * Copyright (c) 2006 Andrzej Zaborowski <balrog@zabor.org>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#if DEPTH == 8
-# define BPP 1
-# define PIXEL_TYPE uint8_t
-#elif DEPTH == 15 || DEPTH == 16
-# define BPP 2
-# define PIXEL_TYPE uint16_t
-#elif DEPTH == 32
-# define BPP 4
-# define PIXEL_TYPE uint32_t
-#else
-# error unsupport depth
-#endif
-
-/*
- * 2-bit colour
- */
-static void glue(draw_line2_, DEPTH)(void *opaque,
- uint8_t *d, const uint8_t *s, int width, int deststep)
-{
- uint16_t *pal = opaque;
- uint8_t v, r, g, b;
-
- do {
- v = ldub_p((void *) s);
- r = (pal[v & 3] >> 4) & 0xf0;
- g = pal[v & 3] & 0xf0;
- b = (pal[v & 3] << 4) & 0xf0;
- ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
- d += BPP;
- v >>= 2;
- r = (pal[v & 3] >> 4) & 0xf0;
- g = pal[v & 3] & 0xf0;
- b = (pal[v & 3] << 4) & 0xf0;
- ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
- d += BPP;
- v >>= 2;
- r = (pal[v & 3] >> 4) & 0xf0;
- g = pal[v & 3] & 0xf0;
- b = (pal[v & 3] << 4) & 0xf0;
- ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
- d += BPP;
- v >>= 2;
- r = (pal[v & 3] >> 4) & 0xf0;
- g = pal[v & 3] & 0xf0;
- b = (pal[v & 3] << 4) & 0xf0;
- ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
- d += BPP;
- s ++;
- width -= 4;
- } while (width > 0);
-}
-
-/*
- * 4-bit colour
- */
-static void glue(draw_line4_, DEPTH)(void *opaque,
- uint8_t *d, const uint8_t *s, int width, int deststep)
-{
- uint16_t *pal = opaque;
- uint8_t v, r, g, b;
-
- do {
- v = ldub_p((void *) s);
- r = (pal[v & 0xf] >> 4) & 0xf0;
- g = pal[v & 0xf] & 0xf0;
- b = (pal[v & 0xf] << 4) & 0xf0;
- ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
- d += BPP;
- v >>= 4;
- r = (pal[v & 0xf] >> 4) & 0xf0;
- g = pal[v & 0xf] & 0xf0;
- b = (pal[v & 0xf] << 4) & 0xf0;
- ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
- d += BPP;
- s ++;
- width -= 2;
- } while (width > 0);
-}
-
-/*
- * 8-bit colour
- */
-static void glue(draw_line8_, DEPTH)(void *opaque,
- uint8_t *d, const uint8_t *s, int width, int deststep)
-{
- uint16_t *pal = opaque;
- uint8_t v, r, g, b;
-
- do {
- v = ldub_p((void *) s);
- r = (pal[v] >> 4) & 0xf0;
- g = pal[v] & 0xf0;
- b = (pal[v] << 4) & 0xf0;
- ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
- s ++;
- d += BPP;
- } while (-- width != 0);
-}
-
-/*
- * 12-bit colour
- */
-static void glue(draw_line12_, DEPTH)(void *opaque,
- uint8_t *d, const uint8_t *s, int width, int deststep)
-{
- uint16_t v;
- uint8_t r, g, b;
-
- do {
- v = lduw_le_p((void *) s);
- r = (v >> 4) & 0xf0;
- g = v & 0xf0;
- b = (v << 4) & 0xf0;
- ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
- s += 2;
- d += BPP;
- } while (-- width != 0);
-}
-
-/*
- * 16-bit colour
- */
-static void glue(draw_line16_, DEPTH)(void *opaque,
- uint8_t *d, const uint8_t *s, int width, int deststep)
-{
-#if DEPTH == 16 && defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
- memcpy(d, s, width * 2);
-#else
- uint16_t v;
- uint8_t r, g, b;
-
- do {
- v = lduw_le_p((void *) s);
- r = (v >> 8) & 0xf8;
- g = (v >> 3) & 0xfc;
- b = (v << 3) & 0xf8;
- ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
- s += 2;
- d += BPP;
- } while (-- width != 0);
-#endif
-}
-
-#undef DEPTH
-#undef BPP
-#undef PIXEL_TYPE
diff --git a/qemu/hw/display/omap_lcdc.c b/qemu/hw/display/omap_lcdc.c
deleted file mode 100644
index ce1058bf8..000000000
--- a/qemu/hw/display/omap_lcdc.c
+++ /dev/null
@@ -1,420 +0,0 @@
-/*
- * OMAP LCD controller.
- *
- * Copyright (C) 2006-2007 Andrzej Zaborowski <balrog@zabor.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "ui/console.h"
-#include "hw/arm/omap.h"
-#include "framebuffer.h"
-#include "ui/pixel_ops.h"
-
-struct omap_lcd_panel_s {
- MemoryRegion *sysmem;
- MemoryRegion iomem;
- MemoryRegionSection fbsection;
- qemu_irq irq;
- QemuConsole *con;
-
- int plm;
- int tft;
- int mono;
- int enable;
- int width;
- int height;
- int interrupts;
- uint32_t timing[3];
- uint32_t subpanel;
- uint32_t ctrl;
-
- struct omap_dma_lcd_channel_s *dma;
- uint16_t palette[256];
- int palette_done;
- int frame_done;
- int invalidate;
- int sync_error;
-};
-
-static void omap_lcd_interrupts(struct omap_lcd_panel_s *s)
-{
- if (s->frame_done && (s->interrupts & 1)) {
- qemu_irq_raise(s->irq);
- return;
- }
-
- if (s->palette_done && (s->interrupts & 2)) {
- qemu_irq_raise(s->irq);
- return;
- }
-
- if (s->sync_error) {
- qemu_irq_raise(s->irq);
- return;
- }
-
- qemu_irq_lower(s->irq);
-}
-
-#define draw_line_func drawfn
-
-#define DEPTH 8
-#include "omap_lcd_template.h"
-#define DEPTH 15
-#include "omap_lcd_template.h"
-#define DEPTH 16
-#include "omap_lcd_template.h"
-#define DEPTH 32
-#include "omap_lcd_template.h"
-
-static draw_line_func draw_line_table2[33] = {
- [0 ... 32] = NULL,
- [8] = draw_line2_8,
- [15] = draw_line2_15,
- [16] = draw_line2_16,
- [32] = draw_line2_32,
-}, draw_line_table4[33] = {
- [0 ... 32] = NULL,
- [8] = draw_line4_8,
- [15] = draw_line4_15,
- [16] = draw_line4_16,
- [32] = draw_line4_32,
-}, draw_line_table8[33] = {
- [0 ... 32] = NULL,
- [8] = draw_line8_8,
- [15] = draw_line8_15,
- [16] = draw_line8_16,
- [32] = draw_line8_32,
-}, draw_line_table12[33] = {
- [0 ... 32] = NULL,
- [8] = draw_line12_8,
- [15] = draw_line12_15,
- [16] = draw_line12_16,
- [32] = draw_line12_32,
-}, draw_line_table16[33] = {
- [0 ... 32] = NULL,
- [8] = draw_line16_8,
- [15] = draw_line16_15,
- [16] = draw_line16_16,
- [32] = draw_line16_32,
-};
-
-static void omap_update_display(void *opaque)
-{
- struct omap_lcd_panel_s *omap_lcd = (struct omap_lcd_panel_s *) opaque;
- DisplaySurface *surface = qemu_console_surface(omap_lcd->con);
- draw_line_func draw_line;
- int size, height, first, last;
- int width, linesize, step, bpp, frame_offset;
- hwaddr frame_base;
-
- if (!omap_lcd || omap_lcd->plm == 1 || !omap_lcd->enable ||
- !surface_bits_per_pixel(surface)) {
- return;
- }
-
- frame_offset = 0;
- if (omap_lcd->plm != 2) {
- cpu_physical_memory_read(omap_lcd->dma->phys_framebuffer[
- omap_lcd->dma->current_frame],
- (void *)omap_lcd->palette, 0x200);
- switch (omap_lcd->palette[0] >> 12 & 7) {
- case 3 ... 7:
- frame_offset += 0x200;
- break;
- default:
- frame_offset += 0x20;
- }
- }
-
- /* Colour depth */
- switch ((omap_lcd->palette[0] >> 12) & 7) {
- case 1:
- draw_line = draw_line_table2[surface_bits_per_pixel(surface)];
- bpp = 2;
- break;
-
- case 2:
- draw_line = draw_line_table4[surface_bits_per_pixel(surface)];
- bpp = 4;
- break;
-
- case 3:
- draw_line = draw_line_table8[surface_bits_per_pixel(surface)];
- bpp = 8;
- break;
-
- case 4 ... 7:
- if (!omap_lcd->tft)
- draw_line = draw_line_table12[surface_bits_per_pixel(surface)];
- else
- draw_line = draw_line_table16[surface_bits_per_pixel(surface)];
- bpp = 16;
- break;
-
- default:
- /* Unsupported at the moment. */
- return;
- }
-
- /* Resolution */
- width = omap_lcd->width;
- if (width != surface_width(surface) ||
- omap_lcd->height != surface_height(surface)) {
- qemu_console_resize(omap_lcd->con,
- omap_lcd->width, omap_lcd->height);
- surface = qemu_console_surface(omap_lcd->con);
- omap_lcd->invalidate = 1;
- }
-
- if (omap_lcd->dma->current_frame == 0)
- size = omap_lcd->dma->src_f1_bottom - omap_lcd->dma->src_f1_top;
- else
- size = omap_lcd->dma->src_f2_bottom - omap_lcd->dma->src_f2_top;
-
- if (frame_offset + ((width * omap_lcd->height * bpp) >> 3) > size + 2) {
- omap_lcd->sync_error = 1;
- omap_lcd_interrupts(omap_lcd);
- omap_lcd->enable = 0;
- return;
- }
-
- /* Content */
- frame_base = omap_lcd->dma->phys_framebuffer[
- omap_lcd->dma->current_frame] + frame_offset;
- omap_lcd->dma->condition |= 1 << omap_lcd->dma->current_frame;
- if (omap_lcd->dma->interrupts & 1)
- qemu_irq_raise(omap_lcd->dma->irq);
- if (omap_lcd->dma->dual)
- omap_lcd->dma->current_frame ^= 1;
-
- if (!surface_bits_per_pixel(surface)) {
- return;
- }
-
- first = 0;
- height = omap_lcd->height;
- if (omap_lcd->subpanel & (1 << 31)) {
- if (omap_lcd->subpanel & (1 << 29))
- first = (omap_lcd->subpanel >> 16) & 0x3ff;
- else
- height = (omap_lcd->subpanel >> 16) & 0x3ff;
- /* TODO: fill the rest of the panel with DPD */
- }
-
- step = width * bpp >> 3;
- linesize = surface_stride(surface);
- if (omap_lcd->invalidate) {
- framebuffer_update_memory_section(&omap_lcd->fbsection,
- omap_lcd->sysmem, frame_base,
- height, step);
- }
-
- framebuffer_update_display(surface, &omap_lcd->fbsection,
- width, height,
- step, linesize, 0,
- omap_lcd->invalidate,
- draw_line, omap_lcd->palette,
- &first, &last);
-
- if (first >= 0) {
- dpy_gfx_update(omap_lcd->con, 0, first, width, last - first + 1);
- }
- omap_lcd->invalidate = 0;
-}
-
-static void omap_invalidate_display(void *opaque) {
- struct omap_lcd_panel_s *omap_lcd = opaque;
- omap_lcd->invalidate = 1;
-}
-
-static void omap_lcd_update(struct omap_lcd_panel_s *s) {
- if (!s->enable) {
- s->dma->current_frame = -1;
- s->sync_error = 0;
- if (s->plm != 1)
- s->frame_done = 1;
- omap_lcd_interrupts(s);
- return;
- }
-
- if (s->dma->current_frame == -1) {
- s->frame_done = 0;
- s->palette_done = 0;
- s->dma->current_frame = 0;
- }
-
- if (!s->dma->mpu->port[s->dma->src].addr_valid(s->dma->mpu,
- s->dma->src_f1_top) ||
- !s->dma->mpu->port[
- s->dma->src].addr_valid(s->dma->mpu,
- s->dma->src_f1_bottom) ||
- (s->dma->dual &&
- (!s->dma->mpu->port[
- s->dma->src].addr_valid(s->dma->mpu,
- s->dma->src_f2_top) ||
- !s->dma->mpu->port[
- s->dma->src].addr_valid(s->dma->mpu,
- s->dma->src_f2_bottom)))) {
- s->dma->condition |= 1 << 2;
- if (s->dma->interrupts & (1 << 1))
- qemu_irq_raise(s->dma->irq);
- s->enable = 0;
- return;
- }
-
- s->dma->phys_framebuffer[0] = s->dma->src_f1_top;
- s->dma->phys_framebuffer[1] = s->dma->src_f2_top;
-
- if (s->plm != 2 && !s->palette_done) {
- cpu_physical_memory_read(
- s->dma->phys_framebuffer[s->dma->current_frame],
- (void *)s->palette, 0x200);
- s->palette_done = 1;
- omap_lcd_interrupts(s);
- }
-}
-
-static uint64_t omap_lcdc_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *) opaque;
-
- switch (addr) {
- case 0x00: /* LCD_CONTROL */
- return (s->tft << 23) | (s->plm << 20) |
- (s->tft << 7) | (s->interrupts << 3) |
- (s->mono << 1) | s->enable | s->ctrl | 0xfe000c34;
-
- case 0x04: /* LCD_TIMING0 */
- return (s->timing[0] << 10) | (s->width - 1) | 0x0000000f;
-
- case 0x08: /* LCD_TIMING1 */
- return (s->timing[1] << 10) | (s->height - 1);
-
- case 0x0c: /* LCD_TIMING2 */
- return s->timing[2] | 0xfc000000;
-
- case 0x10: /* LCD_STATUS */
- return (s->palette_done << 6) | (s->sync_error << 2) | s->frame_done;
-
- case 0x14: /* LCD_SUBPANEL */
- return s->subpanel;
-
- default:
- break;
- }
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_lcdc_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *) opaque;
-
- switch (addr) {
- case 0x00: /* LCD_CONTROL */
- s->plm = (value >> 20) & 3;
- s->tft = (value >> 7) & 1;
- s->interrupts = (value >> 3) & 3;
- s->mono = (value >> 1) & 1;
- s->ctrl = value & 0x01cff300;
- if (s->enable != (value & 1)) {
- s->enable = value & 1;
- omap_lcd_update(s);
- }
- break;
-
- case 0x04: /* LCD_TIMING0 */
- s->timing[0] = value >> 10;
- s->width = (value & 0x3ff) + 1;
- break;
-
- case 0x08: /* LCD_TIMING1 */
- s->timing[1] = value >> 10;
- s->height = (value & 0x3ff) + 1;
- break;
-
- case 0x0c: /* LCD_TIMING2 */
- s->timing[2] = value;
- break;
-
- case 0x10: /* LCD_STATUS */
- break;
-
- case 0x14: /* LCD_SUBPANEL */
- s->subpanel = value & 0xa1ffffff;
- break;
-
- default:
- OMAP_BAD_REG(addr);
- }
-}
-
-static const MemoryRegionOps omap_lcdc_ops = {
- .read = omap_lcdc_read,
- .write = omap_lcdc_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-void omap_lcdc_reset(struct omap_lcd_panel_s *s)
-{
- s->dma->current_frame = -1;
- s->plm = 0;
- s->tft = 0;
- s->mono = 0;
- s->enable = 0;
- s->width = 0;
- s->height = 0;
- s->interrupts = 0;
- s->timing[0] = 0;
- s->timing[1] = 0;
- s->timing[2] = 0;
- s->subpanel = 0;
- s->palette_done = 0;
- s->frame_done = 0;
- s->sync_error = 0;
- s->invalidate = 1;
- s->subpanel = 0;
- s->ctrl = 0;
-}
-
-static const GraphicHwOps omap_ops = {
- .invalidate = omap_invalidate_display,
- .gfx_update = omap_update_display,
-};
-
-struct omap_lcd_panel_s *omap_lcdc_init(MemoryRegion *sysmem,
- hwaddr base,
- qemu_irq irq,
- struct omap_dma_lcd_channel_s *dma,
- omap_clk clk)
-{
- struct omap_lcd_panel_s *s = g_new0(struct omap_lcd_panel_s, 1);
-
- s->irq = irq;
- s->dma = dma;
- s->sysmem = sysmem;
- omap_lcdc_reset(s);
-
- memory_region_init_io(&s->iomem, NULL, &omap_lcdc_ops, s, "omap.lcdc", 0x100);
- memory_region_add_subregion(sysmem, base, &s->iomem);
-
- s->con = graphic_console_init(NULL, 0, &omap_ops, s);
-
- return s;
-}
diff --git a/qemu/hw/display/pl110.c b/qemu/hw/display/pl110.c
deleted file mode 100644
index d589959f1..000000000
--- a/qemu/hw/display/pl110.c
+++ /dev/null
@@ -1,539 +0,0 @@
-/*
- * Arm PrimeCell PL110 Color LCD Controller
- *
- * Copyright (c) 2005-2009 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GNU LGPL
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "ui/console.h"
-#include "framebuffer.h"
-#include "ui/pixel_ops.h"
-
-#define PL110_CR_EN 0x001
-#define PL110_CR_BGR 0x100
-#define PL110_CR_BEBO 0x200
-#define PL110_CR_BEPO 0x400
-#define PL110_CR_PWR 0x800
-
-enum pl110_bppmode
-{
- BPP_1,
- BPP_2,
- BPP_4,
- BPP_8,
- BPP_16,
- BPP_32,
- BPP_16_565, /* PL111 only */
- BPP_12 /* PL111 only */
-};
-
-
-/* The Versatile/PB uses a slightly modified PL110 controller. */
-enum pl110_version
-{
- PL110,
- PL110_VERSATILE,
- PL111
-};
-
-#define TYPE_PL110 "pl110"
-#define PL110(obj) OBJECT_CHECK(PL110State, (obj), TYPE_PL110)
-
-typedef struct PL110State {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- MemoryRegionSection fbsection;
- QemuConsole *con;
-
- int version;
- uint32_t timing[4];
- uint32_t cr;
- uint32_t upbase;
- uint32_t lpbase;
- uint32_t int_status;
- uint32_t int_mask;
- int cols;
- int rows;
- enum pl110_bppmode bpp;
- int invalidate;
- uint32_t mux_ctrl;
- uint32_t palette[256];
- uint32_t raw_palette[128];
- qemu_irq irq;
-} PL110State;
-
-static int vmstate_pl110_post_load(void *opaque, int version_id);
-
-static const VMStateDescription vmstate_pl110 = {
- .name = "pl110",
- .version_id = 2,
- .minimum_version_id = 1,
- .post_load = vmstate_pl110_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_INT32(version, PL110State),
- VMSTATE_UINT32_ARRAY(timing, PL110State, 4),
- VMSTATE_UINT32(cr, PL110State),
- VMSTATE_UINT32(upbase, PL110State),
- VMSTATE_UINT32(lpbase, PL110State),
- VMSTATE_UINT32(int_status, PL110State),
- VMSTATE_UINT32(int_mask, PL110State),
- VMSTATE_INT32(cols, PL110State),
- VMSTATE_INT32(rows, PL110State),
- VMSTATE_UINT32(bpp, PL110State),
- VMSTATE_INT32(invalidate, PL110State),
- VMSTATE_UINT32_ARRAY(palette, PL110State, 256),
- VMSTATE_UINT32_ARRAY(raw_palette, PL110State, 128),
- VMSTATE_UINT32_V(mux_ctrl, PL110State, 2),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const unsigned char pl110_id[] =
-{ 0x10, 0x11, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
-
-static const unsigned char pl111_id[] = {
- 0x11, 0x11, 0x24, 0x00, 0x0d, 0xf0, 0x05, 0xb1
-};
-
-
-/* Indexed by pl110_version */
-static const unsigned char *idregs[] = {
- pl110_id,
- /* The ARM documentation (DDI0224C) says the CLCDC on the Versatile board
- * has a different ID (0x93, 0x10, 0x04, 0x00, ...). However the hardware
- * itself has the same ID values as a stock PL110, and guests (in
- * particular Linux) rely on this. We emulate what the hardware does,
- * rather than what the docs claim it ought to do.
- */
- pl110_id,
- pl111_id
-};
-
-#define BITS 8
-#include "pl110_template.h"
-#define BITS 15
-#include "pl110_template.h"
-#define BITS 16
-#include "pl110_template.h"
-#define BITS 24
-#include "pl110_template.h"
-#define BITS 32
-#include "pl110_template.h"
-
-static int pl110_enabled(PL110State *s)
-{
- return (s->cr & PL110_CR_EN) && (s->cr & PL110_CR_PWR);
-}
-
-static void pl110_update_display(void *opaque)
-{
- PL110State *s = (PL110State *)opaque;
- SysBusDevice *sbd;
- DisplaySurface *surface = qemu_console_surface(s->con);
- drawfn* fntable;
- drawfn fn;
- int dest_width;
- int src_width;
- int bpp_offset;
- int first;
- int last;
-
- if (!pl110_enabled(s)) {
- return;
- }
-
- sbd = SYS_BUS_DEVICE(s);
-
- switch (surface_bits_per_pixel(surface)) {
- case 0:
- return;
- case 8:
- fntable = pl110_draw_fn_8;
- dest_width = 1;
- break;
- case 15:
- fntable = pl110_draw_fn_15;
- dest_width = 2;
- break;
- case 16:
- fntable = pl110_draw_fn_16;
- dest_width = 2;
- break;
- case 24:
- fntable = pl110_draw_fn_24;
- dest_width = 3;
- break;
- case 32:
- fntable = pl110_draw_fn_32;
- dest_width = 4;
- break;
- default:
- fprintf(stderr, "pl110: Bad color depth\n");
- exit(1);
- }
- if (s->cr & PL110_CR_BGR)
- bpp_offset = 0;
- else
- bpp_offset = 24;
-
- if ((s->version != PL111) && (s->bpp == BPP_16)) {
- /* The PL110's native 16 bit mode is 5551; however
- * most boards with a PL110 implement an external
- * mux which allows bits to be reshuffled to give
- * 565 format. The mux is typically controlled by
- * an external system register.
- * This is controlled by a GPIO input pin
- * so boards can wire it up to their register.
- *
- * The PL111 straightforwardly implements both
- * 5551 and 565 under control of the bpp field
- * in the LCDControl register.
- */
- switch (s->mux_ctrl) {
- case 3: /* 565 BGR */
- bpp_offset = (BPP_16_565 - BPP_16);
- break;
- case 1: /* 5551 */
- break;
- case 0: /* 888; also if we have loaded vmstate from an old version */
- case 2: /* 565 RGB */
- default:
- /* treat as 565 but honour BGR bit */
- bpp_offset += (BPP_16_565 - BPP_16);
- break;
- }
- }
-
- if (s->cr & PL110_CR_BEBO)
- fn = fntable[s->bpp + 8 + bpp_offset];
- else if (s->cr & PL110_CR_BEPO)
- fn = fntable[s->bpp + 16 + bpp_offset];
- else
- fn = fntable[s->bpp + bpp_offset];
-
- src_width = s->cols;
- switch (s->bpp) {
- case BPP_1:
- src_width >>= 3;
- break;
- case BPP_2:
- src_width >>= 2;
- break;
- case BPP_4:
- src_width >>= 1;
- break;
- case BPP_8:
- break;
- case BPP_16:
- case BPP_16_565:
- case BPP_12:
- src_width <<= 1;
- break;
- case BPP_32:
- src_width <<= 2;
- break;
- }
- dest_width *= s->cols;
- first = 0;
- if (s->invalidate) {
- framebuffer_update_memory_section(&s->fbsection,
- sysbus_address_space(sbd),
- s->upbase,
- s->rows, src_width);
- }
-
- framebuffer_update_display(surface, &s->fbsection,
- s->cols, s->rows,
- src_width, dest_width, 0,
- s->invalidate,
- fn, s->palette,
- &first, &last);
-
- if (first >= 0) {
- dpy_gfx_update(s->con, 0, first, s->cols, last - first + 1);
- }
- s->invalidate = 0;
-}
-
-static void pl110_invalidate_display(void * opaque)
-{
- PL110State *s = (PL110State *)opaque;
- s->invalidate = 1;
- if (pl110_enabled(s)) {
- qemu_console_resize(s->con, s->cols, s->rows);
- }
-}
-
-static void pl110_update_palette(PL110State *s, int n)
-{
- DisplaySurface *surface = qemu_console_surface(s->con);
- int i;
- uint32_t raw;
- unsigned int r, g, b;
-
- raw = s->raw_palette[n];
- n <<= 1;
- for (i = 0; i < 2; i++) {
- r = (raw & 0x1f) << 3;
- raw >>= 5;
- g = (raw & 0x1f) << 3;
- raw >>= 5;
- b = (raw & 0x1f) << 3;
- /* The I bit is ignored. */
- raw >>= 6;
- switch (surface_bits_per_pixel(surface)) {
- case 8:
- s->palette[n] = rgb_to_pixel8(r, g, b);
- break;
- case 15:
- s->palette[n] = rgb_to_pixel15(r, g, b);
- break;
- case 16:
- s->palette[n] = rgb_to_pixel16(r, g, b);
- break;
- case 24:
- case 32:
- s->palette[n] = rgb_to_pixel32(r, g, b);
- break;
- }
- n++;
- }
-}
-
-static void pl110_resize(PL110State *s, int width, int height)
-{
- if (width != s->cols || height != s->rows) {
- if (pl110_enabled(s)) {
- qemu_console_resize(s->con, width, height);
- }
- }
- s->cols = width;
- s->rows = height;
-}
-
-/* Update interrupts. */
-static void pl110_update(PL110State *s)
-{
- /* TODO: Implement interrupts. */
-}
-
-static uint64_t pl110_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- PL110State *s = (PL110State *)opaque;
-
- if (offset >= 0xfe0 && offset < 0x1000) {
- return idregs[s->version][(offset - 0xfe0) >> 2];
- }
- if (offset >= 0x200 && offset < 0x400) {
- return s->raw_palette[(offset - 0x200) >> 2];
- }
- switch (offset >> 2) {
- case 0: /* LCDTiming0 */
- return s->timing[0];
- case 1: /* LCDTiming1 */
- return s->timing[1];
- case 2: /* LCDTiming2 */
- return s->timing[2];
- case 3: /* LCDTiming3 */
- return s->timing[3];
- case 4: /* LCDUPBASE */
- return s->upbase;
- case 5: /* LCDLPBASE */
- return s->lpbase;
- case 6: /* LCDIMSC */
- if (s->version != PL110) {
- return s->cr;
- }
- return s->int_mask;
- case 7: /* LCDControl */
- if (s->version != PL110) {
- return s->int_mask;
- }
- return s->cr;
- case 8: /* LCDRIS */
- return s->int_status;
- case 9: /* LCDMIS */
- return s->int_status & s->int_mask;
- case 11: /* LCDUPCURR */
- /* TODO: Implement vertical refresh. */
- return s->upbase;
- case 12: /* LCDLPCURR */
- return s->lpbase;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "pl110_read: Bad offset %x\n", (int)offset);
- return 0;
- }
-}
-
-static void pl110_write(void *opaque, hwaddr offset,
- uint64_t val, unsigned size)
-{
- PL110State *s = (PL110State *)opaque;
- int n;
-
- /* For simplicity invalidate the display whenever a control register
- is written to. */
- s->invalidate = 1;
- if (offset >= 0x200 && offset < 0x400) {
- /* Palette. */
- n = (offset - 0x200) >> 2;
- s->raw_palette[(offset - 0x200) >> 2] = val;
- pl110_update_palette(s, n);
- return;
- }
- switch (offset >> 2) {
- case 0: /* LCDTiming0 */
- s->timing[0] = val;
- n = ((val & 0xfc) + 4) * 4;
- pl110_resize(s, n, s->rows);
- break;
- case 1: /* LCDTiming1 */
- s->timing[1] = val;
- n = (val & 0x3ff) + 1;
- pl110_resize(s, s->cols, n);
- break;
- case 2: /* LCDTiming2 */
- s->timing[2] = val;
- break;
- case 3: /* LCDTiming3 */
- s->timing[3] = val;
- break;
- case 4: /* LCDUPBASE */
- s->upbase = val;
- break;
- case 5: /* LCDLPBASE */
- s->lpbase = val;
- break;
- case 6: /* LCDIMSC */
- if (s->version != PL110) {
- goto control;
- }
- imsc:
- s->int_mask = val;
- pl110_update(s);
- break;
- case 7: /* LCDControl */
- if (s->version != PL110) {
- goto imsc;
- }
- control:
- s->cr = val;
- s->bpp = (val >> 1) & 7;
- if (pl110_enabled(s)) {
- qemu_console_resize(s->con, s->cols, s->rows);
- }
- break;
- case 10: /* LCDICR */
- s->int_status &= ~val;
- pl110_update(s);
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "pl110_write: Bad offset %x\n", (int)offset);
- }
-}
-
-static const MemoryRegionOps pl110_ops = {
- .read = pl110_read,
- .write = pl110_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void pl110_mux_ctrl_set(void *opaque, int line, int level)
-{
- PL110State *s = (PL110State *)opaque;
- s->mux_ctrl = level;
-}
-
-static int vmstate_pl110_post_load(void *opaque, int version_id)
-{
- PL110State *s = opaque;
- /* Make sure we redraw, and at the right size */
- pl110_invalidate_display(s);
- return 0;
-}
-
-static const GraphicHwOps pl110_gfx_ops = {
- .invalidate = pl110_invalidate_display,
- .gfx_update = pl110_update_display,
-};
-
-static int pl110_initfn(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- PL110State *s = PL110(dev);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &pl110_ops, s, "pl110", 0x1000);
- sysbus_init_mmio(sbd, &s->iomem);
- sysbus_init_irq(sbd, &s->irq);
- qdev_init_gpio_in(dev, pl110_mux_ctrl_set, 1);
- s->con = graphic_console_init(dev, 0, &pl110_gfx_ops, s);
- return 0;
-}
-
-static void pl110_init(Object *obj)
-{
- PL110State *s = PL110(obj);
-
- s->version = PL110;
-}
-
-static void pl110_versatile_init(Object *obj)
-{
- PL110State *s = PL110(obj);
-
- s->version = PL110_VERSATILE;
-}
-
-static void pl111_init(Object *obj)
-{
- PL110State *s = PL110(obj);
-
- s->version = PL111;
-}
-
-static void pl110_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = pl110_initfn;
- set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
- dc->vmsd = &vmstate_pl110;
-}
-
-static const TypeInfo pl110_info = {
- .name = TYPE_PL110,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PL110State),
- .instance_init = pl110_init,
- .class_init = pl110_class_init,
-};
-
-static const TypeInfo pl110_versatile_info = {
- .name = "pl110_versatile",
- .parent = TYPE_PL110,
- .instance_init = pl110_versatile_init,
-};
-
-static const TypeInfo pl111_info = {
- .name = "pl111",
- .parent = TYPE_PL110,
- .instance_init = pl111_init,
-};
-
-static void pl110_register_types(void)
-{
- type_register_static(&pl110_info);
- type_register_static(&pl110_versatile_info);
- type_register_static(&pl111_info);
-}
-
-type_init(pl110_register_types)
diff --git a/qemu/hw/display/pl110_template.h b/qemu/hw/display/pl110_template.h
deleted file mode 100644
index 36ba791c6..000000000
--- a/qemu/hw/display/pl110_template.h
+++ /dev/null
@@ -1,399 +0,0 @@
-/*
- * Arm PrimeCell PL110 Color LCD Controller
- *
- * Copyright (c) 2005 CodeSourcery, LLC.
- * Written by Paul Brook
- *
- * This code is licensed under the GNU LGPL
- *
- * Framebuffer format conversion routines.
- */
-
-#ifndef ORDER
-
-#if BITS == 8
-#define COPY_PIXEL(to, from) *(to++) = from
-#elif BITS == 15 || BITS == 16
-#define COPY_PIXEL(to, from) do { *(uint16_t *)to = from; to += 2; } while (0)
-#elif BITS == 24
-#define COPY_PIXEL(to, from) \
- do { \
- *(to++) = from; \
- *(to++) = (from) >> 8; \
- *(to++) = (from) >> 16; \
- } while (0)
-#elif BITS == 32
-#define COPY_PIXEL(to, from) do { *(uint32_t *)to = from; to += 4; } while (0)
-#else
-#error unknown bit depth
-#endif
-
-#undef RGB
-#define BORDER bgr
-#define ORDER 0
-#include "pl110_template.h"
-#define ORDER 1
-#include "pl110_template.h"
-#define ORDER 2
-#include "pl110_template.h"
-#undef BORDER
-#define RGB
-#define BORDER rgb
-#define ORDER 0
-#include "pl110_template.h"
-#define ORDER 1
-#include "pl110_template.h"
-#define ORDER 2
-#include "pl110_template.h"
-#undef BORDER
-
-static drawfn glue(pl110_draw_fn_,BITS)[48] =
-{
- glue(pl110_draw_line1_lblp_bgr,BITS),
- glue(pl110_draw_line2_lblp_bgr,BITS),
- glue(pl110_draw_line4_lblp_bgr,BITS),
- glue(pl110_draw_line8_lblp_bgr,BITS),
- glue(pl110_draw_line16_555_lblp_bgr,BITS),
- glue(pl110_draw_line32_lblp_bgr,BITS),
- glue(pl110_draw_line16_lblp_bgr,BITS),
- glue(pl110_draw_line12_lblp_bgr,BITS),
-
- glue(pl110_draw_line1_bbbp_bgr,BITS),
- glue(pl110_draw_line2_bbbp_bgr,BITS),
- glue(pl110_draw_line4_bbbp_bgr,BITS),
- glue(pl110_draw_line8_bbbp_bgr,BITS),
- glue(pl110_draw_line16_555_bbbp_bgr,BITS),
- glue(pl110_draw_line32_bbbp_bgr,BITS),
- glue(pl110_draw_line16_bbbp_bgr,BITS),
- glue(pl110_draw_line12_bbbp_bgr,BITS),
-
- glue(pl110_draw_line1_lbbp_bgr,BITS),
- glue(pl110_draw_line2_lbbp_bgr,BITS),
- glue(pl110_draw_line4_lbbp_bgr,BITS),
- glue(pl110_draw_line8_lbbp_bgr,BITS),
- glue(pl110_draw_line16_555_lbbp_bgr,BITS),
- glue(pl110_draw_line32_lbbp_bgr,BITS),
- glue(pl110_draw_line16_lbbp_bgr,BITS),
- glue(pl110_draw_line12_lbbp_bgr,BITS),
-
- glue(pl110_draw_line1_lblp_rgb,BITS),
- glue(pl110_draw_line2_lblp_rgb,BITS),
- glue(pl110_draw_line4_lblp_rgb,BITS),
- glue(pl110_draw_line8_lblp_rgb,BITS),
- glue(pl110_draw_line16_555_lblp_rgb,BITS),
- glue(pl110_draw_line32_lblp_rgb,BITS),
- glue(pl110_draw_line16_lblp_rgb,BITS),
- glue(pl110_draw_line12_lblp_rgb,BITS),
-
- glue(pl110_draw_line1_bbbp_rgb,BITS),
- glue(pl110_draw_line2_bbbp_rgb,BITS),
- glue(pl110_draw_line4_bbbp_rgb,BITS),
- glue(pl110_draw_line8_bbbp_rgb,BITS),
- glue(pl110_draw_line16_555_bbbp_rgb,BITS),
- glue(pl110_draw_line32_bbbp_rgb,BITS),
- glue(pl110_draw_line16_bbbp_rgb,BITS),
- glue(pl110_draw_line12_bbbp_rgb,BITS),
-
- glue(pl110_draw_line1_lbbp_rgb,BITS),
- glue(pl110_draw_line2_lbbp_rgb,BITS),
- glue(pl110_draw_line4_lbbp_rgb,BITS),
- glue(pl110_draw_line8_lbbp_rgb,BITS),
- glue(pl110_draw_line16_555_lbbp_rgb,BITS),
- glue(pl110_draw_line32_lbbp_rgb,BITS),
- glue(pl110_draw_line16_lbbp_rgb,BITS),
- glue(pl110_draw_line12_lbbp_rgb,BITS),
-};
-
-#undef BITS
-#undef COPY_PIXEL
-
-#else
-
-#if ORDER == 0
-#define NAME glue(glue(lblp_, BORDER), BITS)
-#ifdef HOST_WORDS_BIGENDIAN
-#define SWAP_WORDS 1
-#endif
-#elif ORDER == 1
-#define NAME glue(glue(bbbp_, BORDER), BITS)
-#ifndef HOST_WORDS_BIGENDIAN
-#define SWAP_WORDS 1
-#endif
-#else
-#define SWAP_PIXELS 1
-#define NAME glue(glue(lbbp_, BORDER), BITS)
-#ifdef HOST_WORDS_BIGENDIAN
-#define SWAP_WORDS 1
-#endif
-#endif
-
-#define FN_2(x, y) FN(x, y) FN(x+1, y)
-#define FN_4(x, y) FN_2(x, y) FN_2(x+2, y)
-#define FN_8(y) FN_4(0, y) FN_4(4, y)
-
-static void glue(pl110_draw_line1_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
-{
- uint32_t *palette = opaque;
- uint32_t data;
- while (width > 0) {
- data = *(uint32_t *)src;
-#ifdef SWAP_PIXELS
-#define FN(x, y) COPY_PIXEL(d, palette[(data >> (y + 7 - (x))) & 1]);
-#else
-#define FN(x, y) COPY_PIXEL(d, palette[(data >> ((x) + y)) & 1]);
-#endif
-#ifdef SWAP_WORDS
- FN_8(24)
- FN_8(16)
- FN_8(8)
- FN_8(0)
-#else
- FN_8(0)
- FN_8(8)
- FN_8(16)
- FN_8(24)
-#endif
-#undef FN
- width -= 32;
- src += 4;
- }
-}
-
-static void glue(pl110_draw_line2_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
-{
- uint32_t *palette = opaque;
- uint32_t data;
- while (width > 0) {
- data = *(uint32_t *)src;
-#ifdef SWAP_PIXELS
-#define FN(x, y) COPY_PIXEL(d, palette[(data >> (y + 6 - (x)*2)) & 3]);
-#else
-#define FN(x, y) COPY_PIXEL(d, palette[(data >> ((x)*2 + y)) & 3]);
-#endif
-#ifdef SWAP_WORDS
- FN_4(0, 24)
- FN_4(0, 16)
- FN_4(0, 8)
- FN_4(0, 0)
-#else
- FN_4(0, 0)
- FN_4(0, 8)
- FN_4(0, 16)
- FN_4(0, 24)
-#endif
-#undef FN
- width -= 16;
- src += 4;
- }
-}
-
-static void glue(pl110_draw_line4_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
-{
- uint32_t *palette = opaque;
- uint32_t data;
- while (width > 0) {
- data = *(uint32_t *)src;
-#ifdef SWAP_PIXELS
-#define FN(x, y) COPY_PIXEL(d, palette[(data >> (y + 4 - (x)*4)) & 0xf]);
-#else
-#define FN(x, y) COPY_PIXEL(d, palette[(data >> ((x)*4 + y)) & 0xf]);
-#endif
-#ifdef SWAP_WORDS
- FN_2(0, 24)
- FN_2(0, 16)
- FN_2(0, 8)
- FN_2(0, 0)
-#else
- FN_2(0, 0)
- FN_2(0, 8)
- FN_2(0, 16)
- FN_2(0, 24)
-#endif
-#undef FN
- width -= 8;
- src += 4;
- }
-}
-
-static void glue(pl110_draw_line8_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
-{
- uint32_t *palette = opaque;
- uint32_t data;
- while (width > 0) {
- data = *(uint32_t *)src;
-#define FN(x) COPY_PIXEL(d, palette[(data >> (x)) & 0xff]);
-#ifdef SWAP_WORDS
- FN(24)
- FN(16)
- FN(8)
- FN(0)
-#else
- FN(0)
- FN(8)
- FN(16)
- FN(24)
-#endif
-#undef FN
- width -= 4;
- src += 4;
- }
-}
-
-static void glue(pl110_draw_line16_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
-{
- uint32_t data;
- unsigned int r, g, b;
- while (width > 0) {
- data = *(uint32_t *)src;
-#ifdef SWAP_WORDS
- data = bswap32(data);
-#endif
-#ifdef RGB
-#define LSB r
-#define MSB b
-#else
-#define LSB b
-#define MSB r
-#endif
-#if 0
- LSB = data & 0x1f;
- data >>= 5;
- g = data & 0x3f;
- data >>= 6;
- MSB = data & 0x1f;
- data >>= 5;
-#else
- LSB = (data & 0x1f) << 3;
- data >>= 5;
- g = (data & 0x3f) << 2;
- data >>= 6;
- MSB = (data & 0x1f) << 3;
- data >>= 5;
-#endif
- COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b));
- LSB = (data & 0x1f) << 3;
- data >>= 5;
- g = (data & 0x3f) << 2;
- data >>= 6;
- MSB = (data & 0x1f) << 3;
- data >>= 5;
- COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b));
-#undef MSB
-#undef LSB
- width -= 2;
- src += 4;
- }
-}
-
-static void glue(pl110_draw_line32_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
-{
- uint32_t data;
- unsigned int r, g, b;
- while (width > 0) {
- data = *(uint32_t *)src;
-#ifdef RGB
-#define LSB r
-#define MSB b
-#else
-#define LSB b
-#define MSB r
-#endif
-#ifndef SWAP_WORDS
- LSB = data & 0xff;
- g = (data >> 8) & 0xff;
- MSB = (data >> 16) & 0xff;
-#else
- LSB = (data >> 24) & 0xff;
- g = (data >> 16) & 0xff;
- MSB = (data >> 8) & 0xff;
-#endif
- COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b));
-#undef MSB
-#undef LSB
- width--;
- src += 4;
- }
-}
-
-static void glue(pl110_draw_line16_555_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
-{
- /* RGB 555 plus an intensity bit (which we ignore) */
- uint32_t data;
- unsigned int r, g, b;
- while (width > 0) {
- data = *(uint32_t *)src;
-#ifdef SWAP_WORDS
- data = bswap32(data);
-#endif
-#ifdef RGB
-#define LSB r
-#define MSB b
-#else
-#define LSB b
-#define MSB r
-#endif
- LSB = (data & 0x1f) << 3;
- data >>= 5;
- g = (data & 0x1f) << 3;
- data >>= 5;
- MSB = (data & 0x1f) << 3;
- data >>= 5;
- COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b));
- LSB = (data & 0x1f) << 3;
- data >>= 5;
- g = (data & 0x1f) << 3;
- data >>= 5;
- MSB = (data & 0x1f) << 3;
- data >>= 6;
- COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b));
-#undef MSB
-#undef LSB
- width -= 2;
- src += 4;
- }
-}
-
-static void glue(pl110_draw_line12_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
-{
- /* RGB 444 with 4 bits of zeroes at the top of each halfword */
- uint32_t data;
- unsigned int r, g, b;
- while (width > 0) {
- data = *(uint32_t *)src;
-#ifdef SWAP_WORDS
- data = bswap32(data);
-#endif
-#ifdef RGB
-#define LSB r
-#define MSB b
-#else
-#define LSB b
-#define MSB r
-#endif
- LSB = (data & 0xf) << 4;
- data >>= 4;
- g = (data & 0xf) << 4;
- data >>= 4;
- MSB = (data & 0xf) << 4;
- data >>= 8;
- COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b));
- LSB = (data & 0xf) << 4;
- data >>= 4;
- g = (data & 0xf) << 4;
- data >>= 4;
- MSB = (data & 0xf) << 4;
- data >>= 8;
- COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b));
-#undef MSB
-#undef LSB
- width -= 2;
- src += 4;
- }
-}
-
-#undef SWAP_PIXELS
-#undef NAME
-#undef SWAP_WORDS
-#undef ORDER
-
-#endif
diff --git a/qemu/hw/display/pxa2xx_lcd.c b/qemu/hw/display/pxa2xx_lcd.c
deleted file mode 100644
index 845521c5b..000000000
--- a/qemu/hw/display/pxa2xx_lcd.c
+++ /dev/null
@@ -1,1065 +0,0 @@
-/*
- * Intel XScale PXA255/270 LCDC emulation.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GPLv2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "ui/console.h"
-#include "hw/arm/pxa.h"
-#include "ui/pixel_ops.h"
-/* FIXME: For graphic_rotate. Should probably be done in common code. */
-#include "sysemu/sysemu.h"
-#include "framebuffer.h"
-
-struct DMAChannel {
- uint32_t branch;
- uint8_t up;
- uint8_t palette[1024];
- uint8_t pbuffer[1024];
- void (*redraw)(PXA2xxLCDState *s, hwaddr addr,
- int *miny, int *maxy);
-
- uint32_t descriptor;
- uint32_t source;
- uint32_t id;
- uint32_t command;
-};
-
-struct PXA2xxLCDState {
- MemoryRegion *sysmem;
- MemoryRegion iomem;
- MemoryRegionSection fbsection;
- qemu_irq irq;
- int irqlevel;
-
- int invalidated;
- QemuConsole *con;
- drawfn *line_fn[2];
- int dest_width;
- int xres, yres;
- int pal_for;
- int transp;
- enum {
- pxa_lcdc_2bpp = 1,
- pxa_lcdc_4bpp = 2,
- pxa_lcdc_8bpp = 3,
- pxa_lcdc_16bpp = 4,
- pxa_lcdc_18bpp = 5,
- pxa_lcdc_18pbpp = 6,
- pxa_lcdc_19bpp = 7,
- pxa_lcdc_19pbpp = 8,
- pxa_lcdc_24bpp = 9,
- pxa_lcdc_25bpp = 10,
- } bpp;
-
- uint32_t control[6];
- uint32_t status[2];
- uint32_t ovl1c[2];
- uint32_t ovl2c[2];
- uint32_t ccr;
- uint32_t cmdcr;
- uint32_t trgbr;
- uint32_t tcr;
- uint32_t liidr;
- uint8_t bscntr;
-
- struct DMAChannel dma_ch[7];
-
- qemu_irq vsync_cb;
- int orientation;
-};
-
-typedef struct QEMU_PACKED {
- uint32_t fdaddr;
- uint32_t fsaddr;
- uint32_t fidr;
- uint32_t ldcmd;
-} PXAFrameDescriptor;
-
-#define LCCR0 0x000 /* LCD Controller Control register 0 */
-#define LCCR1 0x004 /* LCD Controller Control register 1 */
-#define LCCR2 0x008 /* LCD Controller Control register 2 */
-#define LCCR3 0x00c /* LCD Controller Control register 3 */
-#define LCCR4 0x010 /* LCD Controller Control register 4 */
-#define LCCR5 0x014 /* LCD Controller Control register 5 */
-
-#define FBR0 0x020 /* DMA Channel 0 Frame Branch register */
-#define FBR1 0x024 /* DMA Channel 1 Frame Branch register */
-#define FBR2 0x028 /* DMA Channel 2 Frame Branch register */
-#define FBR3 0x02c /* DMA Channel 3 Frame Branch register */
-#define FBR4 0x030 /* DMA Channel 4 Frame Branch register */
-#define FBR5 0x110 /* DMA Channel 5 Frame Branch register */
-#define FBR6 0x114 /* DMA Channel 6 Frame Branch register */
-
-#define LCSR1 0x034 /* LCD Controller Status register 1 */
-#define LCSR0 0x038 /* LCD Controller Status register 0 */
-#define LIIDR 0x03c /* LCD Controller Interrupt ID register */
-
-#define TRGBR 0x040 /* TMED RGB Seed register */
-#define TCR 0x044 /* TMED Control register */
-
-#define OVL1C1 0x050 /* Overlay 1 Control register 1 */
-#define OVL1C2 0x060 /* Overlay 1 Control register 2 */
-#define OVL2C1 0x070 /* Overlay 2 Control register 1 */
-#define OVL2C2 0x080 /* Overlay 2 Control register 2 */
-#define CCR 0x090 /* Cursor Control register */
-
-#define CMDCR 0x100 /* Command Control register */
-#define PRSR 0x104 /* Panel Read Status register */
-
-#define PXA_LCDDMA_CHANS 7
-#define DMA_FDADR 0x00 /* Frame Descriptor Address register */
-#define DMA_FSADR 0x04 /* Frame Source Address register */
-#define DMA_FIDR 0x08 /* Frame ID register */
-#define DMA_LDCMD 0x0c /* Command register */
-
-/* LCD Buffer Strength Control register */
-#define BSCNTR 0x04000054
-
-/* Bitfield masks */
-#define LCCR0_ENB (1 << 0)
-#define LCCR0_CMS (1 << 1)
-#define LCCR0_SDS (1 << 2)
-#define LCCR0_LDM (1 << 3)
-#define LCCR0_SOFM0 (1 << 4)
-#define LCCR0_IUM (1 << 5)
-#define LCCR0_EOFM0 (1 << 6)
-#define LCCR0_PAS (1 << 7)
-#define LCCR0_DPD (1 << 9)
-#define LCCR0_DIS (1 << 10)
-#define LCCR0_QDM (1 << 11)
-#define LCCR0_PDD (0xff << 12)
-#define LCCR0_BSM0 (1 << 20)
-#define LCCR0_OUM (1 << 21)
-#define LCCR0_LCDT (1 << 22)
-#define LCCR0_RDSTM (1 << 23)
-#define LCCR0_CMDIM (1 << 24)
-#define LCCR0_OUC (1 << 25)
-#define LCCR0_LDDALT (1 << 26)
-#define LCCR1_PPL(x) ((x) & 0x3ff)
-#define LCCR2_LPP(x) ((x) & 0x3ff)
-#define LCCR3_API (15 << 16)
-#define LCCR3_BPP(x) ((((x) >> 24) & 7) | (((x) >> 26) & 8))
-#define LCCR3_PDFOR(x) (((x) >> 30) & 3)
-#define LCCR4_K1(x) (((x) >> 0) & 7)
-#define LCCR4_K2(x) (((x) >> 3) & 7)
-#define LCCR4_K3(x) (((x) >> 6) & 7)
-#define LCCR4_PALFOR(x) (((x) >> 15) & 3)
-#define LCCR5_SOFM(ch) (1 << (ch - 1))
-#define LCCR5_EOFM(ch) (1 << (ch + 7))
-#define LCCR5_BSM(ch) (1 << (ch + 15))
-#define LCCR5_IUM(ch) (1 << (ch + 23))
-#define OVLC1_EN (1 << 31)
-#define CCR_CEN (1 << 31)
-#define FBR_BRA (1 << 0)
-#define FBR_BINT (1 << 1)
-#define FBR_SRCADDR (0xfffffff << 4)
-#define LCSR0_LDD (1 << 0)
-#define LCSR0_SOF0 (1 << 1)
-#define LCSR0_BER (1 << 2)
-#define LCSR0_ABC (1 << 3)
-#define LCSR0_IU0 (1 << 4)
-#define LCSR0_IU1 (1 << 5)
-#define LCSR0_OU (1 << 6)
-#define LCSR0_QD (1 << 7)
-#define LCSR0_EOF0 (1 << 8)
-#define LCSR0_BS0 (1 << 9)
-#define LCSR0_SINT (1 << 10)
-#define LCSR0_RDST (1 << 11)
-#define LCSR0_CMDINT (1 << 12)
-#define LCSR0_BERCH(x) (((x) & 7) << 28)
-#define LCSR1_SOF(ch) (1 << (ch - 1))
-#define LCSR1_EOF(ch) (1 << (ch + 7))
-#define LCSR1_BS(ch) (1 << (ch + 15))
-#define LCSR1_IU(ch) (1 << (ch + 23))
-#define LDCMD_LENGTH(x) ((x) & 0x001ffffc)
-#define LDCMD_EOFINT (1 << 21)
-#define LDCMD_SOFINT (1 << 22)
-#define LDCMD_PAL (1 << 26)
-
-/* Route internal interrupt lines to the global IC */
-static void pxa2xx_lcdc_int_update(PXA2xxLCDState *s)
-{
- int level = 0;
- level |= (s->status[0] & LCSR0_LDD) && !(s->control[0] & LCCR0_LDM);
- level |= (s->status[0] & LCSR0_SOF0) && !(s->control[0] & LCCR0_SOFM0);
- level |= (s->status[0] & LCSR0_IU0) && !(s->control[0] & LCCR0_IUM);
- level |= (s->status[0] & LCSR0_IU1) && !(s->control[5] & LCCR5_IUM(1));
- level |= (s->status[0] & LCSR0_OU) && !(s->control[0] & LCCR0_OUM);
- level |= (s->status[0] & LCSR0_QD) && !(s->control[0] & LCCR0_QDM);
- level |= (s->status[0] & LCSR0_EOF0) && !(s->control[0] & LCCR0_EOFM0);
- level |= (s->status[0] & LCSR0_BS0) && !(s->control[0] & LCCR0_BSM0);
- level |= (s->status[0] & LCSR0_RDST) && !(s->control[0] & LCCR0_RDSTM);
- level |= (s->status[0] & LCSR0_CMDINT) && !(s->control[0] & LCCR0_CMDIM);
- level |= (s->status[1] & ~s->control[5]);
-
- qemu_set_irq(s->irq, !!level);
- s->irqlevel = level;
-}
-
-/* Set Branch Status interrupt high and poke associated registers */
-static inline void pxa2xx_dma_bs_set(PXA2xxLCDState *s, int ch)
-{
- int unmasked;
- if (ch == 0) {
- s->status[0] |= LCSR0_BS0;
- unmasked = !(s->control[0] & LCCR0_BSM0);
- } else {
- s->status[1] |= LCSR1_BS(ch);
- unmasked = !(s->control[5] & LCCR5_BSM(ch));
- }
-
- if (unmasked) {
- if (s->irqlevel)
- s->status[0] |= LCSR0_SINT;
- else
- s->liidr = s->dma_ch[ch].id;
- }
-}
-
-/* Set Start Of Frame Status interrupt high and poke associated registers */
-static inline void pxa2xx_dma_sof_set(PXA2xxLCDState *s, int ch)
-{
- int unmasked;
- if (!(s->dma_ch[ch].command & LDCMD_SOFINT))
- return;
-
- if (ch == 0) {
- s->status[0] |= LCSR0_SOF0;
- unmasked = !(s->control[0] & LCCR0_SOFM0);
- } else {
- s->status[1] |= LCSR1_SOF(ch);
- unmasked = !(s->control[5] & LCCR5_SOFM(ch));
- }
-
- if (unmasked) {
- if (s->irqlevel)
- s->status[0] |= LCSR0_SINT;
- else
- s->liidr = s->dma_ch[ch].id;
- }
-}
-
-/* Set End Of Frame Status interrupt high and poke associated registers */
-static inline void pxa2xx_dma_eof_set(PXA2xxLCDState *s, int ch)
-{
- int unmasked;
- if (!(s->dma_ch[ch].command & LDCMD_EOFINT))
- return;
-
- if (ch == 0) {
- s->status[0] |= LCSR0_EOF0;
- unmasked = !(s->control[0] & LCCR0_EOFM0);
- } else {
- s->status[1] |= LCSR1_EOF(ch);
- unmasked = !(s->control[5] & LCCR5_EOFM(ch));
- }
-
- if (unmasked) {
- if (s->irqlevel)
- s->status[0] |= LCSR0_SINT;
- else
- s->liidr = s->dma_ch[ch].id;
- }
-}
-
-/* Set Bus Error Status interrupt high and poke associated registers */
-static inline void pxa2xx_dma_ber_set(PXA2xxLCDState *s, int ch)
-{
- s->status[0] |= LCSR0_BERCH(ch) | LCSR0_BER;
- if (s->irqlevel)
- s->status[0] |= LCSR0_SINT;
- else
- s->liidr = s->dma_ch[ch].id;
-}
-
-/* Load new Frame Descriptors from DMA */
-static void pxa2xx_descriptor_load(PXA2xxLCDState *s)
-{
- PXAFrameDescriptor desc;
- hwaddr descptr;
- int i;
-
- for (i = 0; i < PXA_LCDDMA_CHANS; i ++) {
- s->dma_ch[i].source = 0;
-
- if (!s->dma_ch[i].up)
- continue;
-
- if (s->dma_ch[i].branch & FBR_BRA) {
- descptr = s->dma_ch[i].branch & FBR_SRCADDR;
- if (s->dma_ch[i].branch & FBR_BINT)
- pxa2xx_dma_bs_set(s, i);
- s->dma_ch[i].branch &= ~FBR_BRA;
- } else
- descptr = s->dma_ch[i].descriptor;
-
- if (!((descptr >= PXA2XX_SDRAM_BASE && descptr +
- sizeof(desc) <= PXA2XX_SDRAM_BASE + ram_size) ||
- (descptr >= PXA2XX_INTERNAL_BASE && descptr + sizeof(desc) <=
- PXA2XX_INTERNAL_BASE + PXA2XX_INTERNAL_SIZE))) {
- continue;
- }
-
- cpu_physical_memory_read(descptr, &desc, sizeof(desc));
- s->dma_ch[i].descriptor = le32_to_cpu(desc.fdaddr);
- s->dma_ch[i].source = le32_to_cpu(desc.fsaddr);
- s->dma_ch[i].id = le32_to_cpu(desc.fidr);
- s->dma_ch[i].command = le32_to_cpu(desc.ldcmd);
- }
-}
-
-static uint64_t pxa2xx_lcdc_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
- int ch;
-
- switch (offset) {
- case LCCR0:
- return s->control[0];
- case LCCR1:
- return s->control[1];
- case LCCR2:
- return s->control[2];
- case LCCR3:
- return s->control[3];
- case LCCR4:
- return s->control[4];
- case LCCR5:
- return s->control[5];
-
- case OVL1C1:
- return s->ovl1c[0];
- case OVL1C2:
- return s->ovl1c[1];
- case OVL2C1:
- return s->ovl2c[0];
- case OVL2C2:
- return s->ovl2c[1];
-
- case CCR:
- return s->ccr;
-
- case CMDCR:
- return s->cmdcr;
-
- case TRGBR:
- return s->trgbr;
- case TCR:
- return s->tcr;
-
- case 0x200 ... 0x1000: /* DMA per-channel registers */
- ch = (offset - 0x200) >> 4;
- if (!(ch >= 0 && ch < PXA_LCDDMA_CHANS))
- goto fail;
-
- switch (offset & 0xf) {
- case DMA_FDADR:
- return s->dma_ch[ch].descriptor;
- case DMA_FSADR:
- return s->dma_ch[ch].source;
- case DMA_FIDR:
- return s->dma_ch[ch].id;
- case DMA_LDCMD:
- return s->dma_ch[ch].command;
- default:
- goto fail;
- }
-
- case FBR0:
- return s->dma_ch[0].branch;
- case FBR1:
- return s->dma_ch[1].branch;
- case FBR2:
- return s->dma_ch[2].branch;
- case FBR3:
- return s->dma_ch[3].branch;
- case FBR4:
- return s->dma_ch[4].branch;
- case FBR5:
- return s->dma_ch[5].branch;
- case FBR6:
- return s->dma_ch[6].branch;
-
- case BSCNTR:
- return s->bscntr;
-
- case PRSR:
- return 0;
-
- case LCSR0:
- return s->status[0];
- case LCSR1:
- return s->status[1];
- case LIIDR:
- return s->liidr;
-
- default:
- fail:
- hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
- }
-
- return 0;
-}
-
-static void pxa2xx_lcdc_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
- int ch;
-
- switch (offset) {
- case LCCR0:
- /* ACK Quick Disable done */
- if ((s->control[0] & LCCR0_ENB) && !(value & LCCR0_ENB))
- s->status[0] |= LCSR0_QD;
-
- if (!(s->control[0] & LCCR0_LCDT) && (value & LCCR0_LCDT))
- printf("%s: internal frame buffer unsupported\n", __FUNCTION__);
-
- if ((s->control[3] & LCCR3_API) &&
- (value & LCCR0_ENB) && !(value & LCCR0_LCDT))
- s->status[0] |= LCSR0_ABC;
-
- s->control[0] = value & 0x07ffffff;
- pxa2xx_lcdc_int_update(s);
-
- s->dma_ch[0].up = !!(value & LCCR0_ENB);
- s->dma_ch[1].up = (s->ovl1c[0] & OVLC1_EN) || (value & LCCR0_SDS);
- break;
-
- case LCCR1:
- s->control[1] = value;
- break;
-
- case LCCR2:
- s->control[2] = value;
- break;
-
- case LCCR3:
- s->control[3] = value & 0xefffffff;
- s->bpp = LCCR3_BPP(value);
- break;
-
- case LCCR4:
- s->control[4] = value & 0x83ff81ff;
- break;
-
- case LCCR5:
- s->control[5] = value & 0x3f3f3f3f;
- break;
-
- case OVL1C1:
- if (!(s->ovl1c[0] & OVLC1_EN) && (value & OVLC1_EN))
- printf("%s: Overlay 1 not supported\n", __FUNCTION__);
-
- s->ovl1c[0] = value & 0x80ffffff;
- s->dma_ch[1].up = (value & OVLC1_EN) || (s->control[0] & LCCR0_SDS);
- break;
-
- case OVL1C2:
- s->ovl1c[1] = value & 0x000fffff;
- break;
-
- case OVL2C1:
- if (!(s->ovl2c[0] & OVLC1_EN) && (value & OVLC1_EN))
- printf("%s: Overlay 2 not supported\n", __FUNCTION__);
-
- s->ovl2c[0] = value & 0x80ffffff;
- s->dma_ch[2].up = !!(value & OVLC1_EN);
- s->dma_ch[3].up = !!(value & OVLC1_EN);
- s->dma_ch[4].up = !!(value & OVLC1_EN);
- break;
-
- case OVL2C2:
- s->ovl2c[1] = value & 0x007fffff;
- break;
-
- case CCR:
- if (!(s->ccr & CCR_CEN) && (value & CCR_CEN))
- printf("%s: Hardware cursor unimplemented\n", __FUNCTION__);
-
- s->ccr = value & 0x81ffffe7;
- s->dma_ch[5].up = !!(value & CCR_CEN);
- break;
-
- case CMDCR:
- s->cmdcr = value & 0xff;
- break;
-
- case TRGBR:
- s->trgbr = value & 0x00ffffff;
- break;
-
- case TCR:
- s->tcr = value & 0x7fff;
- break;
-
- case 0x200 ... 0x1000: /* DMA per-channel registers */
- ch = (offset - 0x200) >> 4;
- if (!(ch >= 0 && ch < PXA_LCDDMA_CHANS))
- goto fail;
-
- switch (offset & 0xf) {
- case DMA_FDADR:
- s->dma_ch[ch].descriptor = value & 0xfffffff0;
- break;
-
- default:
- goto fail;
- }
- break;
-
- case FBR0:
- s->dma_ch[0].branch = value & 0xfffffff3;
- break;
- case FBR1:
- s->dma_ch[1].branch = value & 0xfffffff3;
- break;
- case FBR2:
- s->dma_ch[2].branch = value & 0xfffffff3;
- break;
- case FBR3:
- s->dma_ch[3].branch = value & 0xfffffff3;
- break;
- case FBR4:
- s->dma_ch[4].branch = value & 0xfffffff3;
- break;
- case FBR5:
- s->dma_ch[5].branch = value & 0xfffffff3;
- break;
- case FBR6:
- s->dma_ch[6].branch = value & 0xfffffff3;
- break;
-
- case BSCNTR:
- s->bscntr = value & 0xf;
- break;
-
- case PRSR:
- break;
-
- case LCSR0:
- s->status[0] &= ~(value & 0xfff);
- if (value & LCSR0_BER)
- s->status[0] &= ~LCSR0_BERCH(7);
- break;
-
- case LCSR1:
- s->status[1] &= ~(value & 0x3e3f3f);
- break;
-
- default:
- fail:
- hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
- }
-}
-
-static const MemoryRegionOps pxa2xx_lcdc_ops = {
- .read = pxa2xx_lcdc_read,
- .write = pxa2xx_lcdc_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-/* Load new palette for a given DMA channel, convert to internal format */
-static void pxa2xx_palette_parse(PXA2xxLCDState *s, int ch, int bpp)
-{
- DisplaySurface *surface = qemu_console_surface(s->con);
- int i, n, format, r, g, b, alpha;
- uint32_t *dest;
- uint8_t *src;
- s->pal_for = LCCR4_PALFOR(s->control[4]);
- format = s->pal_for;
-
- switch (bpp) {
- case pxa_lcdc_2bpp:
- n = 4;
- break;
- case pxa_lcdc_4bpp:
- n = 16;
- break;
- case pxa_lcdc_8bpp:
- n = 256;
- break;
- default:
- format = 0;
- return;
- }
-
- src = (uint8_t *) s->dma_ch[ch].pbuffer;
- dest = (uint32_t *) s->dma_ch[ch].palette;
- alpha = r = g = b = 0;
-
- for (i = 0; i < n; i ++) {
- switch (format) {
- case 0: /* 16 bpp, no transparency */
- alpha = 0;
- if (s->control[0] & LCCR0_CMS) {
- r = g = b = *(uint16_t *) src & 0xff;
- }
- else {
- r = (*(uint16_t *) src & 0xf800) >> 8;
- g = (*(uint16_t *) src & 0x07e0) >> 3;
- b = (*(uint16_t *) src & 0x001f) << 3;
- }
- src += 2;
- break;
- case 1: /* 16 bpp plus transparency */
- alpha = *(uint32_t *) src & (1 << 24);
- if (s->control[0] & LCCR0_CMS)
- r = g = b = *(uint32_t *) src & 0xff;
- else {
- r = (*(uint32_t *) src & 0xf80000) >> 16;
- g = (*(uint32_t *) src & 0x00fc00) >> 8;
- b = (*(uint32_t *) src & 0x0000f8);
- }
- src += 4;
- break;
- case 2: /* 18 bpp plus transparency */
- alpha = *(uint32_t *) src & (1 << 24);
- if (s->control[0] & LCCR0_CMS)
- r = g = b = *(uint32_t *) src & 0xff;
- else {
- r = (*(uint32_t *) src & 0xfc0000) >> 16;
- g = (*(uint32_t *) src & 0x00fc00) >> 8;
- b = (*(uint32_t *) src & 0x0000fc);
- }
- src += 4;
- break;
- case 3: /* 24 bpp plus transparency */
- alpha = *(uint32_t *) src & (1 << 24);
- if (s->control[0] & LCCR0_CMS)
- r = g = b = *(uint32_t *) src & 0xff;
- else {
- r = (*(uint32_t *) src & 0xff0000) >> 16;
- g = (*(uint32_t *) src & 0x00ff00) >> 8;
- b = (*(uint32_t *) src & 0x0000ff);
- }
- src += 4;
- break;
- }
- switch (surface_bits_per_pixel(surface)) {
- case 8:
- *dest = rgb_to_pixel8(r, g, b) | alpha;
- break;
- case 15:
- *dest = rgb_to_pixel15(r, g, b) | alpha;
- break;
- case 16:
- *dest = rgb_to_pixel16(r, g, b) | alpha;
- break;
- case 24:
- *dest = rgb_to_pixel24(r, g, b) | alpha;
- break;
- case 32:
- *dest = rgb_to_pixel32(r, g, b) | alpha;
- break;
- }
- dest ++;
- }
-}
-
-static void pxa2xx_lcdc_dma0_redraw_rot0(PXA2xxLCDState *s,
- hwaddr addr, int *miny, int *maxy)
-{
- DisplaySurface *surface = qemu_console_surface(s->con);
- int src_width, dest_width;
- drawfn fn = NULL;
- if (s->dest_width)
- fn = s->line_fn[s->transp][s->bpp];
- if (!fn)
- return;
-
- src_width = (s->xres + 3) & ~3; /* Pad to a 4 pixels multiple */
- if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp)
- src_width *= 3;
- else if (s->bpp > pxa_lcdc_16bpp)
- src_width *= 4;
- else if (s->bpp > pxa_lcdc_8bpp)
- src_width *= 2;
-
- dest_width = s->xres * s->dest_width;
- *miny = 0;
- if (s->invalidated) {
- framebuffer_update_memory_section(&s->fbsection, s->sysmem,
- addr, s->yres, src_width);
- }
- framebuffer_update_display(surface, &s->fbsection, s->xres, s->yres,
- src_width, dest_width, s->dest_width,
- s->invalidated,
- fn, s->dma_ch[0].palette, miny, maxy);
-}
-
-static void pxa2xx_lcdc_dma0_redraw_rot90(PXA2xxLCDState *s,
- hwaddr addr, int *miny, int *maxy)
-{
- DisplaySurface *surface = qemu_console_surface(s->con);
- int src_width, dest_width;
- drawfn fn = NULL;
- if (s->dest_width)
- fn = s->line_fn[s->transp][s->bpp];
- if (!fn)
- return;
-
- src_width = (s->xres + 3) & ~3; /* Pad to a 4 pixels multiple */
- if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp)
- src_width *= 3;
- else if (s->bpp > pxa_lcdc_16bpp)
- src_width *= 4;
- else if (s->bpp > pxa_lcdc_8bpp)
- src_width *= 2;
-
- dest_width = s->yres * s->dest_width;
- *miny = 0;
- if (s->invalidated) {
- framebuffer_update_memory_section(&s->fbsection, s->sysmem,
- addr, s->yres, src_width);
- }
- framebuffer_update_display(surface, &s->fbsection, s->xres, s->yres,
- src_width, s->dest_width, -dest_width,
- s->invalidated,
- fn, s->dma_ch[0].palette,
- miny, maxy);
-}
-
-static void pxa2xx_lcdc_dma0_redraw_rot180(PXA2xxLCDState *s,
- hwaddr addr, int *miny, int *maxy)
-{
- DisplaySurface *surface = qemu_console_surface(s->con);
- int src_width, dest_width;
- drawfn fn = NULL;
- if (s->dest_width) {
- fn = s->line_fn[s->transp][s->bpp];
- }
- if (!fn) {
- return;
- }
-
- src_width = (s->xres + 3) & ~3; /* Pad to a 4 pixels multiple */
- if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp) {
- src_width *= 3;
- } else if (s->bpp > pxa_lcdc_16bpp) {
- src_width *= 4;
- } else if (s->bpp > pxa_lcdc_8bpp) {
- src_width *= 2;
- }
-
- dest_width = s->xres * s->dest_width;
- *miny = 0;
- if (s->invalidated) {
- framebuffer_update_memory_section(&s->fbsection, s->sysmem,
- addr, s->yres, src_width);
- }
- framebuffer_update_display(surface, &s->fbsection, s->xres, s->yres,
- src_width, -dest_width, -s->dest_width,
- s->invalidated,
- fn, s->dma_ch[0].palette, miny, maxy);
-}
-
-static void pxa2xx_lcdc_dma0_redraw_rot270(PXA2xxLCDState *s,
- hwaddr addr, int *miny, int *maxy)
-{
- DisplaySurface *surface = qemu_console_surface(s->con);
- int src_width, dest_width;
- drawfn fn = NULL;
- if (s->dest_width) {
- fn = s->line_fn[s->transp][s->bpp];
- }
- if (!fn) {
- return;
- }
-
- src_width = (s->xres + 3) & ~3; /* Pad to a 4 pixels multiple */
- if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp) {
- src_width *= 3;
- } else if (s->bpp > pxa_lcdc_16bpp) {
- src_width *= 4;
- } else if (s->bpp > pxa_lcdc_8bpp) {
- src_width *= 2;
- }
-
- dest_width = s->yres * s->dest_width;
- *miny = 0;
- if (s->invalidated) {
- framebuffer_update_memory_section(&s->fbsection, s->sysmem,
- addr, s->yres, src_width);
- }
- framebuffer_update_display(surface, &s->fbsection, s->xres, s->yres,
- src_width, -s->dest_width, dest_width,
- s->invalidated,
- fn, s->dma_ch[0].palette,
- miny, maxy);
-}
-
-static void pxa2xx_lcdc_resize(PXA2xxLCDState *s)
-{
- int width, height;
- if (!(s->control[0] & LCCR0_ENB))
- return;
-
- width = LCCR1_PPL(s->control[1]) + 1;
- height = LCCR2_LPP(s->control[2]) + 1;
-
- if (width != s->xres || height != s->yres) {
- if (s->orientation == 90 || s->orientation == 270) {
- qemu_console_resize(s->con, height, width);
- } else {
- qemu_console_resize(s->con, width, height);
- }
- s->invalidated = 1;
- s->xres = width;
- s->yres = height;
- }
-}
-
-static void pxa2xx_update_display(void *opaque)
-{
- PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
- hwaddr fbptr;
- int miny, maxy;
- int ch;
- if (!(s->control[0] & LCCR0_ENB))
- return;
-
- pxa2xx_descriptor_load(s);
-
- pxa2xx_lcdc_resize(s);
- miny = s->yres;
- maxy = 0;
- s->transp = s->dma_ch[2].up || s->dma_ch[3].up;
- /* Note: With overlay planes the order depends on LCCR0 bit 25. */
- for (ch = 0; ch < PXA_LCDDMA_CHANS; ch ++)
- if (s->dma_ch[ch].up) {
- if (!s->dma_ch[ch].source) {
- pxa2xx_dma_ber_set(s, ch);
- continue;
- }
- fbptr = s->dma_ch[ch].source;
- if (!((fbptr >= PXA2XX_SDRAM_BASE &&
- fbptr <= PXA2XX_SDRAM_BASE + ram_size) ||
- (fbptr >= PXA2XX_INTERNAL_BASE &&
- fbptr <= PXA2XX_INTERNAL_BASE + PXA2XX_INTERNAL_SIZE))) {
- pxa2xx_dma_ber_set(s, ch);
- continue;
- }
-
- if (s->dma_ch[ch].command & LDCMD_PAL) {
- cpu_physical_memory_read(fbptr, s->dma_ch[ch].pbuffer,
- MAX(LDCMD_LENGTH(s->dma_ch[ch].command),
- sizeof(s->dma_ch[ch].pbuffer)));
- pxa2xx_palette_parse(s, ch, s->bpp);
- } else {
- /* Do we need to reparse palette */
- if (LCCR4_PALFOR(s->control[4]) != s->pal_for)
- pxa2xx_palette_parse(s, ch, s->bpp);
-
- /* ACK frame start */
- pxa2xx_dma_sof_set(s, ch);
-
- s->dma_ch[ch].redraw(s, fbptr, &miny, &maxy);
- s->invalidated = 0;
-
- /* ACK frame completed */
- pxa2xx_dma_eof_set(s, ch);
- }
- }
-
- if (s->control[0] & LCCR0_DIS) {
- /* ACK last frame completed */
- s->control[0] &= ~LCCR0_ENB;
- s->status[0] |= LCSR0_LDD;
- }
-
- if (miny >= 0) {
- switch (s->orientation) {
- case 0:
- dpy_gfx_update(s->con, 0, miny, s->xres, maxy - miny + 1);
- break;
- case 90:
- dpy_gfx_update(s->con, miny, 0, maxy - miny + 1, s->xres);
- break;
- case 180:
- maxy = s->yres - maxy - 1;
- miny = s->yres - miny - 1;
- dpy_gfx_update(s->con, 0, maxy, s->xres, miny - maxy + 1);
- break;
- case 270:
- maxy = s->yres - maxy - 1;
- miny = s->yres - miny - 1;
- dpy_gfx_update(s->con, maxy, 0, miny - maxy + 1, s->xres);
- break;
- }
- }
- pxa2xx_lcdc_int_update(s);
-
- qemu_irq_raise(s->vsync_cb);
-}
-
-static void pxa2xx_invalidate_display(void *opaque)
-{
- PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
- s->invalidated = 1;
-}
-
-static void pxa2xx_lcdc_orientation(void *opaque, int angle)
-{
- PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
-
- switch (angle) {
- case 0:
- s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot0;
- break;
- case 90:
- s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot90;
- break;
- case 180:
- s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot180;
- break;
- case 270:
- s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot270;
- break;
- }
-
- s->orientation = angle;
- s->xres = s->yres = -1;
- pxa2xx_lcdc_resize(s);
-}
-
-static const VMStateDescription vmstate_dma_channel = {
- .name = "dma_channel",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(branch, struct DMAChannel),
- VMSTATE_UINT8(up, struct DMAChannel),
- VMSTATE_BUFFER(pbuffer, struct DMAChannel),
- VMSTATE_UINT32(descriptor, struct DMAChannel),
- VMSTATE_UINT32(source, struct DMAChannel),
- VMSTATE_UINT32(id, struct DMAChannel),
- VMSTATE_UINT32(command, struct DMAChannel),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static int pxa2xx_lcdc_post_load(void *opaque, int version_id)
-{
- PXA2xxLCDState *s = opaque;
-
- s->bpp = LCCR3_BPP(s->control[3]);
- s->xres = s->yres = s->pal_for = -1;
-
- return 0;
-}
-
-static const VMStateDescription vmstate_pxa2xx_lcdc = {
- .name = "pxa2xx_lcdc",
- .version_id = 0,
- .minimum_version_id = 0,
- .post_load = pxa2xx_lcdc_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_INT32(irqlevel, PXA2xxLCDState),
- VMSTATE_INT32(transp, PXA2xxLCDState),
- VMSTATE_UINT32_ARRAY(control, PXA2xxLCDState, 6),
- VMSTATE_UINT32_ARRAY(status, PXA2xxLCDState, 2),
- VMSTATE_UINT32_ARRAY(ovl1c, PXA2xxLCDState, 2),
- VMSTATE_UINT32_ARRAY(ovl2c, PXA2xxLCDState, 2),
- VMSTATE_UINT32(ccr, PXA2xxLCDState),
- VMSTATE_UINT32(cmdcr, PXA2xxLCDState),
- VMSTATE_UINT32(trgbr, PXA2xxLCDState),
- VMSTATE_UINT32(tcr, PXA2xxLCDState),
- VMSTATE_UINT32(liidr, PXA2xxLCDState),
- VMSTATE_UINT8(bscntr, PXA2xxLCDState),
- VMSTATE_STRUCT_ARRAY(dma_ch, PXA2xxLCDState, 7, 0,
- vmstate_dma_channel, struct DMAChannel),
- VMSTATE_END_OF_LIST()
- }
-};
-
-#define BITS 8
-#include "pxa2xx_template.h"
-#define BITS 15
-#include "pxa2xx_template.h"
-#define BITS 16
-#include "pxa2xx_template.h"
-#define BITS 24
-#include "pxa2xx_template.h"
-#define BITS 32
-#include "pxa2xx_template.h"
-
-static const GraphicHwOps pxa2xx_ops = {
- .invalidate = pxa2xx_invalidate_display,
- .gfx_update = pxa2xx_update_display,
-};
-
-PXA2xxLCDState *pxa2xx_lcdc_init(MemoryRegion *sysmem,
- hwaddr base, qemu_irq irq)
-{
- PXA2xxLCDState *s;
- DisplaySurface *surface;
-
- s = (PXA2xxLCDState *) g_malloc0(sizeof(PXA2xxLCDState));
- s->invalidated = 1;
- s->irq = irq;
- s->sysmem = sysmem;
-
- pxa2xx_lcdc_orientation(s, graphic_rotate);
-
- memory_region_init_io(&s->iomem, NULL, &pxa2xx_lcdc_ops, s,
- "pxa2xx-lcd-controller", 0x00100000);
- memory_region_add_subregion(sysmem, base, &s->iomem);
-
- s->con = graphic_console_init(NULL, 0, &pxa2xx_ops, s);
- surface = qemu_console_surface(s->con);
-
- switch (surface_bits_per_pixel(surface)) {
- case 0:
- s->dest_width = 0;
- break;
- case 8:
- s->line_fn[0] = pxa2xx_draw_fn_8;
- s->line_fn[1] = pxa2xx_draw_fn_8t;
- s->dest_width = 1;
- break;
- case 15:
- s->line_fn[0] = pxa2xx_draw_fn_15;
- s->line_fn[1] = pxa2xx_draw_fn_15t;
- s->dest_width = 2;
- break;
- case 16:
- s->line_fn[0] = pxa2xx_draw_fn_16;
- s->line_fn[1] = pxa2xx_draw_fn_16t;
- s->dest_width = 2;
- break;
- case 24:
- s->line_fn[0] = pxa2xx_draw_fn_24;
- s->line_fn[1] = pxa2xx_draw_fn_24t;
- s->dest_width = 3;
- break;
- case 32:
- s->line_fn[0] = pxa2xx_draw_fn_32;
- s->line_fn[1] = pxa2xx_draw_fn_32t;
- s->dest_width = 4;
- break;
- default:
- fprintf(stderr, "%s: Bad color depth\n", __FUNCTION__);
- exit(1);
- }
-
- vmstate_register(NULL, 0, &vmstate_pxa2xx_lcdc, s);
-
- return s;
-}
-
-void pxa2xx_lcd_vsync_notifier(PXA2xxLCDState *s, qemu_irq handler)
-{
- s->vsync_cb = handler;
-}
diff --git a/qemu/hw/display/pxa2xx_template.h b/qemu/hw/display/pxa2xx_template.h
deleted file mode 100644
index c64eebc4b..000000000
--- a/qemu/hw/display/pxa2xx_template.h
+++ /dev/null
@@ -1,447 +0,0 @@
-/*
- * Intel XScale PXA255/270 LCDC emulation.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GPLv2.
- *
- * Framebuffer format conversion routines.
- */
-
-# define SKIP_PIXEL(to) to += deststep
-#if BITS == 8
-# define COPY_PIXEL(to, from) do { *to = from; SKIP_PIXEL(to); } while (0)
-#elif BITS == 15 || BITS == 16
-# define COPY_PIXEL(to, from) \
- do { \
- *(uint16_t *) to = from; \
- SKIP_PIXEL(to); \
- } while (0)
-#elif BITS == 24
-# define COPY_PIXEL(to, from) \
- do { \
- *(uint16_t *) to = from; \
- *(to + 2) = (from) >> 16; \
- SKIP_PIXEL(to); \
- } while (0)
-#elif BITS == 32
-# define COPY_PIXEL(to, from) \
- do { \
- *(uint32_t *) to = from; \
- SKIP_PIXEL(to); \
- } while (0)
-#else
-# error unknown bit depth
-#endif
-
-#ifdef HOST_WORDS_BIGENDIAN
-# define SWAP_WORDS 1
-#endif
-
-#define FN_2(x) FN(x + 1) FN(x)
-#define FN_4(x) FN_2(x + 2) FN_2(x)
-
-static void glue(pxa2xx_draw_line2_, BITS)(void *opaque,
- uint8_t *dest, const uint8_t *src, int width, int deststep)
-{
- uint32_t *palette = opaque;
- uint32_t data;
- while (width > 0) {
- data = *(uint32_t *) src;
-#define FN(x) COPY_PIXEL(dest, palette[(data >> ((x) * 2)) & 3]);
-#ifdef SWAP_WORDS
- FN_4(12)
- FN_4(8)
- FN_4(4)
- FN_4(0)
-#else
- FN_4(0)
- FN_4(4)
- FN_4(8)
- FN_4(12)
-#endif
-#undef FN
- width -= 16;
- src += 4;
- }
-}
-
-static void glue(pxa2xx_draw_line4_, BITS)(void *opaque,
- uint8_t *dest, const uint8_t *src, int width, int deststep)
-{
- uint32_t *palette = opaque;
- uint32_t data;
- while (width > 0) {
- data = *(uint32_t *) src;
-#define FN(x) COPY_PIXEL(dest, palette[(data >> ((x) * 4)) & 0xf]);
-#ifdef SWAP_WORDS
- FN_2(6)
- FN_2(4)
- FN_2(2)
- FN_2(0)
-#else
- FN_2(0)
- FN_2(2)
- FN_2(4)
- FN_2(6)
-#endif
-#undef FN
- width -= 8;
- src += 4;
- }
-}
-
-static void glue(pxa2xx_draw_line8_, BITS)(void *opaque,
- uint8_t *dest, const uint8_t *src, int width, int deststep)
-{
- uint32_t *palette = opaque;
- uint32_t data;
- while (width > 0) {
- data = *(uint32_t *) src;
-#define FN(x) COPY_PIXEL(dest, palette[(data >> (x)) & 0xff]);
-#ifdef SWAP_WORDS
- FN(24)
- FN(16)
- FN(8)
- FN(0)
-#else
- FN(0)
- FN(8)
- FN(16)
- FN(24)
-#endif
-#undef FN
- width -= 4;
- src += 4;
- }
-}
-
-static void glue(pxa2xx_draw_line16_, BITS)(void *opaque,
- uint8_t *dest, const uint8_t *src, int width, int deststep)
-{
- uint32_t data;
- unsigned int r, g, b;
- while (width > 0) {
- data = *(uint32_t *) src;
-#ifdef SWAP_WORDS
- data = bswap32(data);
-#endif
- b = (data & 0x1f) << 3;
- data >>= 5;
- g = (data & 0x3f) << 2;
- data >>= 6;
- r = (data & 0x1f) << 3;
- data >>= 5;
- COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
- b = (data & 0x1f) << 3;
- data >>= 5;
- g = (data & 0x3f) << 2;
- data >>= 6;
- r = (data & 0x1f) << 3;
- COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
- width -= 2;
- src += 4;
- }
-}
-
-static void glue(pxa2xx_draw_line16t_, BITS)(void *opaque,
- uint8_t *dest, const uint8_t *src, int width, int deststep)
-{
- uint32_t data;
- unsigned int r, g, b;
- while (width > 0) {
- data = *(uint32_t *) src;
-#ifdef SWAP_WORDS
- data = bswap32(data);
-#endif
- b = (data & 0x1f) << 3;
- data >>= 5;
- g = (data & 0x1f) << 3;
- data >>= 5;
- r = (data & 0x1f) << 3;
- data >>= 5;
- if (data & 1)
- SKIP_PIXEL(dest);
- else
- COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
- data >>= 1;
- b = (data & 0x1f) << 3;
- data >>= 5;
- g = (data & 0x1f) << 3;
- data >>= 5;
- r = (data & 0x1f) << 3;
- data >>= 5;
- if (data & 1)
- SKIP_PIXEL(dest);
- else
- COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
- width -= 2;
- src += 4;
- }
-}
-
-static void glue(pxa2xx_draw_line18_, BITS)(void *opaque,
- uint8_t *dest, const uint8_t *src, int width, int deststep)
-{
- uint32_t data;
- unsigned int r, g, b;
- while (width > 0) {
- data = *(uint32_t *) src;
-#ifdef SWAP_WORDS
- data = bswap32(data);
-#endif
- b = (data & 0x3f) << 2;
- data >>= 6;
- g = (data & 0x3f) << 2;
- data >>= 6;
- r = (data & 0x3f) << 2;
- COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
- width -= 1;
- src += 4;
- }
-}
-
-/* The wicked packed format */
-static void glue(pxa2xx_draw_line18p_, BITS)(void *opaque,
- uint8_t *dest, const uint8_t *src, int width, int deststep)
-{
- uint32_t data[3];
- unsigned int r, g, b;
- while (width > 0) {
- data[0] = *(uint32_t *) src;
- src += 4;
- data[1] = *(uint32_t *) src;
- src += 4;
- data[2] = *(uint32_t *) src;
- src += 4;
-#ifdef SWAP_WORDS
- data[0] = bswap32(data[0]);
- data[1] = bswap32(data[1]);
- data[2] = bswap32(data[2]);
-#endif
- b = (data[0] & 0x3f) << 2;
- data[0] >>= 6;
- g = (data[0] & 0x3f) << 2;
- data[0] >>= 6;
- r = (data[0] & 0x3f) << 2;
- data[0] >>= 12;
- COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
- b = (data[0] & 0x3f) << 2;
- data[0] >>= 6;
- g = ((data[1] & 0xf) << 4) | (data[0] << 2);
- data[1] >>= 4;
- r = (data[1] & 0x3f) << 2;
- data[1] >>= 12;
- COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
- b = (data[1] & 0x3f) << 2;
- data[1] >>= 6;
- g = (data[1] & 0x3f) << 2;
- data[1] >>= 6;
- r = ((data[2] & 0x3) << 6) | (data[1] << 2);
- data[2] >>= 8;
- COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
- b = (data[2] & 0x3f) << 2;
- data[2] >>= 6;
- g = (data[2] & 0x3f) << 2;
- data[2] >>= 6;
- r = data[2] << 2;
- COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
- width -= 4;
- }
-}
-
-static void glue(pxa2xx_draw_line19_, BITS)(void *opaque,
- uint8_t *dest, const uint8_t *src, int width, int deststep)
-{
- uint32_t data;
- unsigned int r, g, b;
- while (width > 0) {
- data = *(uint32_t *) src;
-#ifdef SWAP_WORDS
- data = bswap32(data);
-#endif
- b = (data & 0x3f) << 2;
- data >>= 6;
- g = (data & 0x3f) << 2;
- data >>= 6;
- r = (data & 0x3f) << 2;
- data >>= 6;
- if (data & 1)
- SKIP_PIXEL(dest);
- else
- COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
- width -= 1;
- src += 4;
- }
-}
-
-/* The wicked packed format */
-static void glue(pxa2xx_draw_line19p_, BITS)(void *opaque,
- uint8_t *dest, const uint8_t *src, int width, int deststep)
-{
- uint32_t data[3];
- unsigned int r, g, b;
- while (width > 0) {
- data[0] = *(uint32_t *) src;
- src += 4;
- data[1] = *(uint32_t *) src;
- src += 4;
- data[2] = *(uint32_t *) src;
- src += 4;
-# ifdef SWAP_WORDS
- data[0] = bswap32(data[0]);
- data[1] = bswap32(data[1]);
- data[2] = bswap32(data[2]);
-# endif
- b = (data[0] & 0x3f) << 2;
- data[0] >>= 6;
- g = (data[0] & 0x3f) << 2;
- data[0] >>= 6;
- r = (data[0] & 0x3f) << 2;
- data[0] >>= 6;
- if (data[0] & 1)
- SKIP_PIXEL(dest);
- else
- COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
- data[0] >>= 6;
- b = (data[0] & 0x3f) << 2;
- data[0] >>= 6;
- g = ((data[1] & 0xf) << 4) | (data[0] << 2);
- data[1] >>= 4;
- r = (data[1] & 0x3f) << 2;
- data[1] >>= 6;
- if (data[1] & 1)
- SKIP_PIXEL(dest);
- else
- COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
- data[1] >>= 6;
- b = (data[1] & 0x3f) << 2;
- data[1] >>= 6;
- g = (data[1] & 0x3f) << 2;
- data[1] >>= 6;
- r = ((data[2] & 0x3) << 6) | (data[1] << 2);
- data[2] >>= 2;
- if (data[2] & 1)
- SKIP_PIXEL(dest);
- else
- COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
- data[2] >>= 6;
- b = (data[2] & 0x3f) << 2;
- data[2] >>= 6;
- g = (data[2] & 0x3f) << 2;
- data[2] >>= 6;
- r = data[2] << 2;
- data[2] >>= 6;
- if (data[2] & 1)
- SKIP_PIXEL(dest);
- else
- COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
- width -= 4;
- }
-}
-
-static void glue(pxa2xx_draw_line24_, BITS)(void *opaque,
- uint8_t *dest, const uint8_t *src, int width, int deststep)
-{
- uint32_t data;
- unsigned int r, g, b;
- while (width > 0) {
- data = *(uint32_t *) src;
-#ifdef SWAP_WORDS
- data = bswap32(data);
-#endif
- b = data & 0xff;
- data >>= 8;
- g = data & 0xff;
- data >>= 8;
- r = data & 0xff;
- COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
- width -= 1;
- src += 4;
- }
-}
-
-static void glue(pxa2xx_draw_line24t_, BITS)(void *opaque,
- uint8_t *dest, const uint8_t *src, int width, int deststep)
-{
- uint32_t data;
- unsigned int r, g, b;
- while (width > 0) {
- data = *(uint32_t *) src;
-#ifdef SWAP_WORDS
- data = bswap32(data);
-#endif
- b = (data & 0x7f) << 1;
- data >>= 7;
- g = data & 0xff;
- data >>= 8;
- r = data & 0xff;
- data >>= 8;
- if (data & 1)
- SKIP_PIXEL(dest);
- else
- COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
- width -= 1;
- src += 4;
- }
-}
-
-static void glue(pxa2xx_draw_line25_, BITS)(void *opaque,
- uint8_t *dest, const uint8_t *src, int width, int deststep)
-{
- uint32_t data;
- unsigned int r, g, b;
- while (width > 0) {
- data = *(uint32_t *) src;
-#ifdef SWAP_WORDS
- data = bswap32(data);
-#endif
- b = data & 0xff;
- data >>= 8;
- g = data & 0xff;
- data >>= 8;
- r = data & 0xff;
- data >>= 8;
- if (data & 1)
- SKIP_PIXEL(dest);
- else
- COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
- width -= 1;
- src += 4;
- }
-}
-
-/* Overlay planes disabled, no transparency */
-static drawfn glue(pxa2xx_draw_fn_, BITS)[16] =
-{
- [0 ... 0xf] = NULL,
- [pxa_lcdc_2bpp] = glue(pxa2xx_draw_line2_, BITS),
- [pxa_lcdc_4bpp] = glue(pxa2xx_draw_line4_, BITS),
- [pxa_lcdc_8bpp] = glue(pxa2xx_draw_line8_, BITS),
- [pxa_lcdc_16bpp] = glue(pxa2xx_draw_line16_, BITS),
- [pxa_lcdc_18bpp] = glue(pxa2xx_draw_line18_, BITS),
- [pxa_lcdc_18pbpp] = glue(pxa2xx_draw_line18p_, BITS),
- [pxa_lcdc_24bpp] = glue(pxa2xx_draw_line24_, BITS),
-};
-
-/* Overlay planes enabled, transparency used */
-static drawfn glue(glue(pxa2xx_draw_fn_, BITS), t)[16] =
-{
- [0 ... 0xf] = NULL,
- [pxa_lcdc_4bpp] = glue(pxa2xx_draw_line4_, BITS),
- [pxa_lcdc_8bpp] = glue(pxa2xx_draw_line8_, BITS),
- [pxa_lcdc_16bpp] = glue(pxa2xx_draw_line16t_, BITS),
- [pxa_lcdc_19bpp] = glue(pxa2xx_draw_line19_, BITS),
- [pxa_lcdc_19pbpp] = glue(pxa2xx_draw_line19p_, BITS),
- [pxa_lcdc_24bpp] = glue(pxa2xx_draw_line24t_, BITS),
- [pxa_lcdc_25bpp] = glue(pxa2xx_draw_line25_, BITS),
-};
-
-#undef BITS
-#undef COPY_PIXEL
-#undef SKIP_PIXEL
-
-#ifdef SWAP_WORDS
-# undef SWAP_WORDS
-#endif
diff --git a/qemu/hw/display/qxl-logger.c b/qemu/hw/display/qxl-logger.c
deleted file mode 100644
index 2ec6d8fa3..000000000
--- a/qemu/hw/display/qxl-logger.c
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * qxl command logging -- for debug purposes
- *
- * Copyright (C) 2010 Red Hat, Inc.
- *
- * maintained by Gerd Hoffmann <kraxel@redhat.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qemu/timer.h"
-#include "qxl.h"
-
-static const char *const qxl_type[] = {
- [ QXL_CMD_NOP ] = "nop",
- [ QXL_CMD_DRAW ] = "draw",
- [ QXL_CMD_UPDATE ] = "update",
- [ QXL_CMD_CURSOR ] = "cursor",
- [ QXL_CMD_MESSAGE ] = "message",
- [ QXL_CMD_SURFACE ] = "surface",
-};
-
-static const char *const qxl_draw_type[] = {
- [ QXL_DRAW_NOP ] = "nop",
- [ QXL_DRAW_FILL ] = "fill",
- [ QXL_DRAW_OPAQUE ] = "opaque",
- [ QXL_DRAW_COPY ] = "copy",
- [ QXL_COPY_BITS ] = "copy-bits",
- [ QXL_DRAW_BLEND ] = "blend",
- [ QXL_DRAW_BLACKNESS ] = "blackness",
- [ QXL_DRAW_WHITENESS ] = "whitemess",
- [ QXL_DRAW_INVERS ] = "invers",
- [ QXL_DRAW_ROP3 ] = "rop3",
- [ QXL_DRAW_STROKE ] = "stroke",
- [ QXL_DRAW_TEXT ] = "text",
- [ QXL_DRAW_TRANSPARENT ] = "transparent",
- [ QXL_DRAW_ALPHA_BLEND ] = "alpha-blend",
-};
-
-static const char *const qxl_draw_effect[] = {
- [ QXL_EFFECT_BLEND ] = "blend",
- [ QXL_EFFECT_OPAQUE ] = "opaque",
- [ QXL_EFFECT_REVERT_ON_DUP ] = "revert-on-dup",
- [ QXL_EFFECT_BLACKNESS_ON_DUP ] = "blackness-on-dup",
- [ QXL_EFFECT_WHITENESS_ON_DUP ] = "whiteness-on-dup",
- [ QXL_EFFECT_NOP_ON_DUP ] = "nop-on-dup",
- [ QXL_EFFECT_NOP ] = "nop",
- [ QXL_EFFECT_OPAQUE_BRUSH ] = "opaque-brush",
-};
-
-static const char *const qxl_surface_cmd[] = {
- [ QXL_SURFACE_CMD_CREATE ] = "create",
- [ QXL_SURFACE_CMD_DESTROY ] = "destroy",
-};
-
-static const char *const spice_surface_fmt[] = {
- [ SPICE_SURFACE_FMT_INVALID ] = "invalid",
- [ SPICE_SURFACE_FMT_1_A ] = "alpha/1",
- [ SPICE_SURFACE_FMT_8_A ] = "alpha/8",
- [ SPICE_SURFACE_FMT_16_555 ] = "555/16",
- [ SPICE_SURFACE_FMT_16_565 ] = "565/16",
- [ SPICE_SURFACE_FMT_32_xRGB ] = "xRGB/32",
- [ SPICE_SURFACE_FMT_32_ARGB ] = "ARGB/32",
-};
-
-static const char *const qxl_cursor_cmd[] = {
- [ QXL_CURSOR_SET ] = "set",
- [ QXL_CURSOR_MOVE ] = "move",
- [ QXL_CURSOR_HIDE ] = "hide",
- [ QXL_CURSOR_TRAIL ] = "trail",
-};
-
-static const char *const spice_cursor_type[] = {
- [ SPICE_CURSOR_TYPE_ALPHA ] = "alpha",
- [ SPICE_CURSOR_TYPE_MONO ] = "mono",
- [ SPICE_CURSOR_TYPE_COLOR4 ] = "color4",
- [ SPICE_CURSOR_TYPE_COLOR8 ] = "color8",
- [ SPICE_CURSOR_TYPE_COLOR16 ] = "color16",
- [ SPICE_CURSOR_TYPE_COLOR24 ] = "color24",
- [ SPICE_CURSOR_TYPE_COLOR32 ] = "color32",
-};
-
-static const char *qxl_v2n(const char *const n[], size_t l, int v)
-{
- if (v >= l || !n[v]) {
- return "???";
- }
- return n[v];
-}
-#define qxl_name(_list, _value) qxl_v2n(_list, ARRAY_SIZE(_list), _value)
-
-static int qxl_log_image(PCIQXLDevice *qxl, QXLPHYSICAL addr, int group_id)
-{
- QXLImage *image;
- QXLImageDescriptor *desc;
-
- image = qxl_phys2virt(qxl, addr, group_id);
- if (!image) {
- return 1;
- }
- desc = &image->descriptor;
- fprintf(stderr, " (id %" PRIx64 " type %d flags %d width %d height %d",
- desc->id, desc->type, desc->flags, desc->width, desc->height);
- switch (desc->type) {
- case SPICE_IMAGE_TYPE_BITMAP:
- fprintf(stderr, ", fmt %d flags %d x %d y %d stride %d"
- " palette %" PRIx64 " data %" PRIx64,
- image->bitmap.format, image->bitmap.flags,
- image->bitmap.x, image->bitmap.y,
- image->bitmap.stride,
- image->bitmap.palette, image->bitmap.data);
- break;
- }
- fprintf(stderr, ")");
- return 0;
-}
-
-static void qxl_log_rect(QXLRect *rect)
-{
- fprintf(stderr, " %dx%d+%d+%d",
- rect->right - rect->left,
- rect->bottom - rect->top,
- rect->left, rect->top);
-}
-
-static int qxl_log_cmd_draw_copy(PCIQXLDevice *qxl, QXLCopy *copy,
- int group_id)
-{
- int ret;
-
- fprintf(stderr, " src %" PRIx64,
- copy->src_bitmap);
- ret = qxl_log_image(qxl, copy->src_bitmap, group_id);
- if (ret != 0) {
- return ret;
- }
- fprintf(stderr, " area");
- qxl_log_rect(&copy->src_area);
- fprintf(stderr, " rop %d", copy->rop_descriptor);
- return 0;
-}
-
-static int qxl_log_cmd_draw(PCIQXLDevice *qxl, QXLDrawable *draw, int group_id)
-{
- fprintf(stderr, ": surface_id %d type %s effect %s",
- draw->surface_id,
- qxl_name(qxl_draw_type, draw->type),
- qxl_name(qxl_draw_effect, draw->effect));
- switch (draw->type) {
- case QXL_DRAW_COPY:
- return qxl_log_cmd_draw_copy(qxl, &draw->u.copy, group_id);
- break;
- }
- return 0;
-}
-
-static int qxl_log_cmd_draw_compat(PCIQXLDevice *qxl, QXLCompatDrawable *draw,
- int group_id)
-{
- fprintf(stderr, ": type %s effect %s",
- qxl_name(qxl_draw_type, draw->type),
- qxl_name(qxl_draw_effect, draw->effect));
- if (draw->bitmap_offset) {
- fprintf(stderr, ": bitmap %d",
- draw->bitmap_offset);
- qxl_log_rect(&draw->bitmap_area);
- }
- switch (draw->type) {
- case QXL_DRAW_COPY:
- return qxl_log_cmd_draw_copy(qxl, &draw->u.copy, group_id);
- break;
- }
- return 0;
-}
-
-static void qxl_log_cmd_surface(PCIQXLDevice *qxl, QXLSurfaceCmd *cmd)
-{
- fprintf(stderr, ": %s id %d",
- qxl_name(qxl_surface_cmd, cmd->type),
- cmd->surface_id);
- if (cmd->type == QXL_SURFACE_CMD_CREATE) {
- fprintf(stderr, " size %dx%d stride %d format %s (count %d, max %d)",
- cmd->u.surface_create.width,
- cmd->u.surface_create.height,
- cmd->u.surface_create.stride,
- qxl_name(spice_surface_fmt, cmd->u.surface_create.format),
- qxl->guest_surfaces.count, qxl->guest_surfaces.max);
- }
- if (cmd->type == QXL_SURFACE_CMD_DESTROY) {
- fprintf(stderr, " (count %d)", qxl->guest_surfaces.count);
- }
-}
-
-int qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id)
-{
- QXLCursor *cursor;
-
- fprintf(stderr, ": %s",
- qxl_name(qxl_cursor_cmd, cmd->type));
- switch (cmd->type) {
- case QXL_CURSOR_SET:
- fprintf(stderr, " +%d+%d visible %s, shape @ 0x%" PRIx64,
- cmd->u.set.position.x,
- cmd->u.set.position.y,
- cmd->u.set.visible ? "yes" : "no",
- cmd->u.set.shape);
- cursor = qxl_phys2virt(qxl, cmd->u.set.shape, group_id);
- if (!cursor) {
- return 1;
- }
- fprintf(stderr, " type %s size %dx%d hot-spot +%d+%d"
- " unique 0x%" PRIx64 " data-size %d",
- qxl_name(spice_cursor_type, cursor->header.type),
- cursor->header.width, cursor->header.height,
- cursor->header.hot_spot_x, cursor->header.hot_spot_y,
- cursor->header.unique, cursor->data_size);
- break;
- case QXL_CURSOR_MOVE:
- fprintf(stderr, " +%d+%d", cmd->u.position.x, cmd->u.position.y);
- break;
- }
- return 0;
-}
-
-int qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext)
-{
- bool compat = ext->flags & QXL_COMMAND_FLAG_COMPAT;
- void *data;
- int ret;
-
- if (!qxl->cmdlog) {
- return 0;
- }
- fprintf(stderr, "%" PRId64 " qxl-%d/%s:", qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
- qxl->id, ring);
- fprintf(stderr, " cmd @ 0x%" PRIx64 " %s%s", ext->cmd.data,
- qxl_name(qxl_type, ext->cmd.type),
- compat ? "(compat)" : "");
-
- data = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
- if (!data) {
- return 1;
- }
- switch (ext->cmd.type) {
- case QXL_CMD_DRAW:
- if (!compat) {
- ret = qxl_log_cmd_draw(qxl, data, ext->group_id);
- } else {
- ret = qxl_log_cmd_draw_compat(qxl, data, ext->group_id);
- }
- if (ret) {
- return ret;
- }
- break;
- case QXL_CMD_SURFACE:
- qxl_log_cmd_surface(qxl, data);
- break;
- case QXL_CMD_CURSOR:
- qxl_log_cmd_cursor(qxl, data, ext->group_id);
- break;
- }
- fprintf(stderr, "\n");
- return 0;
-}
diff --git a/qemu/hw/display/qxl-render.c b/qemu/hw/display/qxl-render.c
deleted file mode 100644
index 9ad9d9e0f..000000000
--- a/qemu/hw/display/qxl-render.c
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * qxl local rendering (aka display on sdl/vnc)
- *
- * Copyright (C) 2010 Red Hat, Inc.
- *
- * maintained by Gerd Hoffmann <kraxel@redhat.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qxl.h"
-#include "trace.h"
-
-static void qxl_blit(PCIQXLDevice *qxl, QXLRect *rect)
-{
- DisplaySurface *surface = qemu_console_surface(qxl->vga.con);
- uint8_t *dst = surface_data(surface);
- uint8_t *src;
- int len, i;
-
- if (is_buffer_shared(surface)) {
- return;
- }
- trace_qxl_render_blit(qxl->guest_primary.qxl_stride,
- rect->left, rect->right, rect->top, rect->bottom);
- src = qxl->guest_primary.data;
- if (qxl->guest_primary.qxl_stride < 0) {
- /* qxl surface is upside down, walk src scanlines
- * in reverse order to flip it */
- src += (qxl->guest_primary.surface.height - rect->top - 1) *
- qxl->guest_primary.abs_stride;
- } else {
- src += rect->top * qxl->guest_primary.abs_stride;
- }
- dst += rect->top * qxl->guest_primary.abs_stride;
- src += rect->left * qxl->guest_primary.bytes_pp;
- dst += rect->left * qxl->guest_primary.bytes_pp;
- len = (rect->right - rect->left) * qxl->guest_primary.bytes_pp;
-
- for (i = rect->top; i < rect->bottom; i++) {
- memcpy(dst, src, len);
- dst += qxl->guest_primary.abs_stride;
- src += qxl->guest_primary.qxl_stride;
- }
-}
-
-void qxl_render_resize(PCIQXLDevice *qxl)
-{
- QXLSurfaceCreate *sc = &qxl->guest_primary.surface;
-
- qxl->guest_primary.qxl_stride = sc->stride;
- qxl->guest_primary.abs_stride = abs(sc->stride);
- qxl->guest_primary.resized++;
- switch (sc->format) {
- case SPICE_SURFACE_FMT_16_555:
- qxl->guest_primary.bytes_pp = 2;
- qxl->guest_primary.bits_pp = 15;
- break;
- case SPICE_SURFACE_FMT_16_565:
- qxl->guest_primary.bytes_pp = 2;
- qxl->guest_primary.bits_pp = 16;
- break;
- case SPICE_SURFACE_FMT_32_xRGB:
- case SPICE_SURFACE_FMT_32_ARGB:
- qxl->guest_primary.bytes_pp = 4;
- qxl->guest_primary.bits_pp = 32;
- break;
- default:
- fprintf(stderr, "%s: unhandled format: %x\n", __FUNCTION__,
- qxl->guest_primary.surface.format);
- qxl->guest_primary.bytes_pp = 4;
- qxl->guest_primary.bits_pp = 32;
- break;
- }
-}
-
-static void qxl_set_rect_to_surface(PCIQXLDevice *qxl, QXLRect *area)
-{
- area->left = 0;
- area->right = qxl->guest_primary.surface.width;
- area->top = 0;
- area->bottom = qxl->guest_primary.surface.height;
-}
-
-static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl)
-{
- VGACommonState *vga = &qxl->vga;
- DisplaySurface *surface;
- int i;
-
- if (qxl->guest_primary.resized) {
- qxl->guest_primary.resized = 0;
- qxl->guest_primary.data = qxl_phys2virt(qxl,
- qxl->guest_primary.surface.mem,
- MEMSLOT_GROUP_GUEST);
- if (!qxl->guest_primary.data) {
- return;
- }
- qxl_set_rect_to_surface(qxl, &qxl->dirty[0]);
- qxl->num_dirty_rects = 1;
- trace_qxl_render_guest_primary_resized(
- qxl->guest_primary.surface.width,
- qxl->guest_primary.surface.height,
- qxl->guest_primary.qxl_stride,
- qxl->guest_primary.bytes_pp,
- qxl->guest_primary.bits_pp);
- if (qxl->guest_primary.qxl_stride > 0) {
- pixman_format_code_t format =
- qemu_default_pixman_format(qxl->guest_primary.bits_pp, true);
- surface = qemu_create_displaysurface_from
- (qxl->guest_primary.surface.width,
- qxl->guest_primary.surface.height,
- format,
- qxl->guest_primary.abs_stride,
- qxl->guest_primary.data);
- } else {
- surface = qemu_create_displaysurface
- (qxl->guest_primary.surface.width,
- qxl->guest_primary.surface.height);
- }
- dpy_gfx_replace_surface(vga->con, surface);
- }
-
- if (!qxl->guest_primary.data) {
- return;
- }
- for (i = 0; i < qxl->num_dirty_rects; i++) {
- if (qemu_spice_rect_is_empty(qxl->dirty+i)) {
- break;
- }
- if (qxl->dirty[i].left < 0 ||
- qxl->dirty[i].top < 0 ||
- qxl->dirty[i].left > qxl->dirty[i].right ||
- qxl->dirty[i].top > qxl->dirty[i].bottom ||
- qxl->dirty[i].right > qxl->guest_primary.surface.width ||
- qxl->dirty[i].bottom > qxl->guest_primary.surface.height) {
- continue;
- }
- qxl_blit(qxl, qxl->dirty+i);
- dpy_gfx_update(vga->con,
- qxl->dirty[i].left, qxl->dirty[i].top,
- qxl->dirty[i].right - qxl->dirty[i].left,
- qxl->dirty[i].bottom - qxl->dirty[i].top);
- }
- qxl->num_dirty_rects = 0;
-}
-
-/*
- * use ssd.lock to protect render_update_cookie_num.
- * qxl_render_update is called by io thread or vcpu thread, and the completion
- * callbacks are called by spice_server thread, deferring to bh called from the
- * io thread.
- */
-void qxl_render_update(PCIQXLDevice *qxl)
-{
- QXLCookie *cookie;
-
- qemu_mutex_lock(&qxl->ssd.lock);
-
- if (!runstate_is_running() || !qxl->guest_primary.commands) {
- qxl_render_update_area_unlocked(qxl);
- qemu_mutex_unlock(&qxl->ssd.lock);
- return;
- }
-
- qxl->guest_primary.commands = 0;
- qxl->render_update_cookie_num++;
- qemu_mutex_unlock(&qxl->ssd.lock);
- cookie = qxl_cookie_new(QXL_COOKIE_TYPE_RENDER_UPDATE_AREA,
- 0);
- qxl_set_rect_to_surface(qxl, &cookie->u.render.area);
- qxl_spice_update_area(qxl, 0, &cookie->u.render.area, NULL,
- 0, 1 /* clear_dirty_region */, QXL_ASYNC, cookie);
-}
-
-void qxl_render_update_area_bh(void *opaque)
-{
- PCIQXLDevice *qxl = opaque;
-
- qemu_mutex_lock(&qxl->ssd.lock);
- qxl_render_update_area_unlocked(qxl);
- qemu_mutex_unlock(&qxl->ssd.lock);
-}
-
-void qxl_render_update_area_done(PCIQXLDevice *qxl, QXLCookie *cookie)
-{
- qemu_mutex_lock(&qxl->ssd.lock);
- trace_qxl_render_update_area_done(cookie);
- qemu_bh_schedule(qxl->update_area_bh);
- qxl->render_update_cookie_num--;
- qemu_mutex_unlock(&qxl->ssd.lock);
- g_free(cookie);
-}
-
-static QEMUCursor *qxl_cursor(PCIQXLDevice *qxl, QXLCursor *cursor)
-{
- QEMUCursor *c;
- uint8_t *image, *mask;
- size_t size;
-
- c = cursor_alloc(cursor->header.width, cursor->header.height);
- c->hot_x = cursor->header.hot_spot_x;
- c->hot_y = cursor->header.hot_spot_y;
- switch (cursor->header.type) {
- case SPICE_CURSOR_TYPE_ALPHA:
- size = sizeof(uint32_t) * cursor->header.width * cursor->header.height;
- memcpy(c->data, cursor->chunk.data, size);
- if (qxl->debug > 2) {
- cursor_print_ascii_art(c, "qxl/alpha");
- }
- break;
- case SPICE_CURSOR_TYPE_MONO:
- mask = cursor->chunk.data;
- image = mask + cursor_get_mono_bpl(c) * c->width;
- cursor_set_mono(c, 0xffffff, 0x000000, image, 1, mask);
- if (qxl->debug > 2) {
- cursor_print_ascii_art(c, "qxl/mono");
- }
- break;
- default:
- fprintf(stderr, "%s: not implemented: type %d\n",
- __FUNCTION__, cursor->header.type);
- goto fail;
- }
- return c;
-
-fail:
- cursor_put(c);
- return NULL;
-}
-
-
-/* called from spice server thread context only */
-int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext)
-{
- QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
- QXLCursor *cursor;
- QEMUCursor *c;
-
- if (!cmd) {
- return 1;
- }
-
- if (!dpy_cursor_define_supported(qxl->vga.con)) {
- return 0;
- }
-
- if (qxl->debug > 1 && cmd->type != QXL_CURSOR_MOVE) {
- fprintf(stderr, "%s", __FUNCTION__);
- qxl_log_cmd_cursor(qxl, cmd, ext->group_id);
- fprintf(stderr, "\n");
- }
- switch (cmd->type) {
- case QXL_CURSOR_SET:
- cursor = qxl_phys2virt(qxl, cmd->u.set.shape, ext->group_id);
- if (!cursor) {
- return 1;
- }
- if (cursor->chunk.data_size != cursor->data_size) {
- fprintf(stderr, "%s: multiple chunks\n", __FUNCTION__);
- return 1;
- }
- c = qxl_cursor(qxl, cursor);
- if (c == NULL) {
- c = cursor_builtin_left_ptr();
- }
- qemu_mutex_lock(&qxl->ssd.lock);
- if (qxl->ssd.cursor) {
- cursor_put(qxl->ssd.cursor);
- }
- qxl->ssd.cursor = c;
- qxl->ssd.mouse_x = cmd->u.set.position.x;
- qxl->ssd.mouse_y = cmd->u.set.position.y;
- qemu_mutex_unlock(&qxl->ssd.lock);
- qemu_bh_schedule(qxl->ssd.cursor_bh);
- break;
- case QXL_CURSOR_MOVE:
- qemu_mutex_lock(&qxl->ssd.lock);
- qxl->ssd.mouse_x = cmd->u.position.x;
- qxl->ssd.mouse_y = cmd->u.position.y;
- qemu_mutex_unlock(&qxl->ssd.lock);
- qemu_bh_schedule(qxl->ssd.cursor_bh);
- break;
- }
- return 0;
-}
diff --git a/qemu/hw/display/qxl.c b/qemu/hw/display/qxl.c
deleted file mode 100644
index 919dc5cd3..000000000
--- a/qemu/hw/display/qxl.c
+++ /dev/null
@@ -1,2359 +0,0 @@
-/*
- * Copyright (C) 2010 Red Hat, Inc.
- *
- * written by Yaniv Kamay, Izik Eidus, Gerd Hoffmann
- * maintained by Gerd Hoffmann <kraxel@redhat.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include <zlib.h>
-
-#include "qemu-common.h"
-#include "qemu/timer.h"
-#include "qemu/queue.h"
-#include "qemu/atomic.h"
-#include "sysemu/sysemu.h"
-#include "trace.h"
-
-#include "qxl.h"
-
-/*
- * NOTE: SPICE_RING_PROD_ITEM accesses memory on the pci bar and as
- * such can be changed by the guest, so to avoid a guest trigerrable
- * abort we just qxl_set_guest_bug and set the return to NULL. Still
- * it may happen as a result of emulator bug as well.
- */
-#undef SPICE_RING_PROD_ITEM
-#define SPICE_RING_PROD_ITEM(qxl, r, ret) { \
- uint32_t prod = (r)->prod & SPICE_RING_INDEX_MASK(r); \
- if (prod >= ARRAY_SIZE((r)->items)) { \
- qxl_set_guest_bug(qxl, "SPICE_RING_PROD_ITEM indices mismatch " \
- "%u >= %zu", prod, ARRAY_SIZE((r)->items)); \
- ret = NULL; \
- } else { \
- ret = &(r)->items[prod].el; \
- } \
- }
-
-#undef SPICE_RING_CONS_ITEM
-#define SPICE_RING_CONS_ITEM(qxl, r, ret) { \
- uint32_t cons = (r)->cons & SPICE_RING_INDEX_MASK(r); \
- if (cons >= ARRAY_SIZE((r)->items)) { \
- qxl_set_guest_bug(qxl, "SPICE_RING_CONS_ITEM indices mismatch " \
- "%u >= %zu", cons, ARRAY_SIZE((r)->items)); \
- ret = NULL; \
- } else { \
- ret = &(r)->items[cons].el; \
- } \
- }
-
-#undef ALIGN
-#define ALIGN(a, b) (((a) + ((b) - 1)) & ~((b) - 1))
-
-#define PIXEL_SIZE 0.2936875 //1280x1024 is 14.8" x 11.9"
-
-#define QXL_MODE(_x, _y, _b, _o) \
- { .x_res = _x, \
- .y_res = _y, \
- .bits = _b, \
- .stride = (_x) * (_b) / 8, \
- .x_mili = PIXEL_SIZE * (_x), \
- .y_mili = PIXEL_SIZE * (_y), \
- .orientation = _o, \
- }
-
-#define QXL_MODE_16_32(x_res, y_res, orientation) \
- QXL_MODE(x_res, y_res, 16, orientation), \
- QXL_MODE(x_res, y_res, 32, orientation)
-
-#define QXL_MODE_EX(x_res, y_res) \
- QXL_MODE_16_32(x_res, y_res, 0), \
- QXL_MODE_16_32(x_res, y_res, 1)
-
-static QXLMode qxl_modes[] = {
- QXL_MODE_EX(640, 480),
- QXL_MODE_EX(800, 480),
- QXL_MODE_EX(800, 600),
- QXL_MODE_EX(832, 624),
- QXL_MODE_EX(960, 640),
- QXL_MODE_EX(1024, 600),
- QXL_MODE_EX(1024, 768),
- QXL_MODE_EX(1152, 864),
- QXL_MODE_EX(1152, 870),
- QXL_MODE_EX(1280, 720),
- QXL_MODE_EX(1280, 760),
- QXL_MODE_EX(1280, 768),
- QXL_MODE_EX(1280, 800),
- QXL_MODE_EX(1280, 960),
- QXL_MODE_EX(1280, 1024),
- QXL_MODE_EX(1360, 768),
- QXL_MODE_EX(1366, 768),
- QXL_MODE_EX(1400, 1050),
- QXL_MODE_EX(1440, 900),
- QXL_MODE_EX(1600, 900),
- QXL_MODE_EX(1600, 1200),
- QXL_MODE_EX(1680, 1050),
- QXL_MODE_EX(1920, 1080),
- /* these modes need more than 8 MB video memory */
- QXL_MODE_EX(1920, 1200),
- QXL_MODE_EX(1920, 1440),
- QXL_MODE_EX(2000, 2000),
- QXL_MODE_EX(2048, 1536),
- QXL_MODE_EX(2048, 2048),
- QXL_MODE_EX(2560, 1440),
- QXL_MODE_EX(2560, 1600),
- /* these modes need more than 16 MB video memory */
- QXL_MODE_EX(2560, 2048),
- QXL_MODE_EX(2800, 2100),
- QXL_MODE_EX(3200, 2400),
- /* these modes need more than 32 MB video memory */
- QXL_MODE_EX(3840, 2160), /* 4k mainstream */
- QXL_MODE_EX(4096, 2160), /* 4k */
- /* these modes need more than 64 MB video memory */
- QXL_MODE_EX(7680, 4320), /* 8k mainstream */
- /* these modes need more than 128 MB video memory */
- QXL_MODE_EX(8192, 4320), /* 8k */
-};
-
-static void qxl_send_events(PCIQXLDevice *d, uint32_t events);
-static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async);
-static void qxl_reset_memslots(PCIQXLDevice *d);
-static void qxl_reset_surfaces(PCIQXLDevice *d);
-static void qxl_ring_set_dirty(PCIQXLDevice *qxl);
-
-static void qxl_hw_update(void *opaque);
-
-void qxl_set_guest_bug(PCIQXLDevice *qxl, const char *msg, ...)
-{
- trace_qxl_set_guest_bug(qxl->id);
- qxl_send_events(qxl, QXL_INTERRUPT_ERROR);
- qxl->guest_bug = 1;
- if (qxl->guestdebug) {
- va_list ap;
- va_start(ap, msg);
- fprintf(stderr, "qxl-%d: guest bug: ", qxl->id);
- vfprintf(stderr, msg, ap);
- fprintf(stderr, "\n");
- va_end(ap);
- }
-}
-
-static void qxl_clear_guest_bug(PCIQXLDevice *qxl)
-{
- qxl->guest_bug = 0;
-}
-
-void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
- struct QXLRect *area, struct QXLRect *dirty_rects,
- uint32_t num_dirty_rects,
- uint32_t clear_dirty_region,
- qxl_async_io async, struct QXLCookie *cookie)
-{
- trace_qxl_spice_update_area(qxl->id, surface_id, area->left, area->right,
- area->top, area->bottom);
- trace_qxl_spice_update_area_rest(qxl->id, num_dirty_rects,
- clear_dirty_region);
- if (async == QXL_SYNC) {
- spice_qxl_update_area(&qxl->ssd.qxl, surface_id, area,
- dirty_rects, num_dirty_rects, clear_dirty_region);
- } else {
- assert(cookie != NULL);
- spice_qxl_update_area_async(&qxl->ssd.qxl, surface_id, area,
- clear_dirty_region, (uintptr_t)cookie);
- }
-}
-
-static void qxl_spice_destroy_surface_wait_complete(PCIQXLDevice *qxl,
- uint32_t id)
-{
- trace_qxl_spice_destroy_surface_wait_complete(qxl->id, id);
- qemu_mutex_lock(&qxl->track_lock);
- qxl->guest_surfaces.cmds[id] = 0;
- qxl->guest_surfaces.count--;
- qemu_mutex_unlock(&qxl->track_lock);
-}
-
-static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id,
- qxl_async_io async)
-{
- QXLCookie *cookie;
-
- trace_qxl_spice_destroy_surface_wait(qxl->id, id, async);
- if (async) {
- cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO,
- QXL_IO_DESTROY_SURFACE_ASYNC);
- cookie->u.surface_id = id;
- spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id, (uintptr_t)cookie);
- } else {
- spice_qxl_destroy_surface_wait(&qxl->ssd.qxl, id);
- qxl_spice_destroy_surface_wait_complete(qxl, id);
- }
-}
-
-static void qxl_spice_flush_surfaces_async(PCIQXLDevice *qxl)
-{
- trace_qxl_spice_flush_surfaces_async(qxl->id, qxl->guest_surfaces.count,
- qxl->num_free_res);
- spice_qxl_flush_surfaces_async(&qxl->ssd.qxl,
- (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
- QXL_IO_FLUSH_SURFACES_ASYNC));
-}
-
-void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext,
- uint32_t count)
-{
- trace_qxl_spice_loadvm_commands(qxl->id, ext, count);
- spice_qxl_loadvm_commands(&qxl->ssd.qxl, ext, count);
-}
-
-void qxl_spice_oom(PCIQXLDevice *qxl)
-{
- trace_qxl_spice_oom(qxl->id);
- spice_qxl_oom(&qxl->ssd.qxl);
-}
-
-void qxl_spice_reset_memslots(PCIQXLDevice *qxl)
-{
- trace_qxl_spice_reset_memslots(qxl->id);
- spice_qxl_reset_memslots(&qxl->ssd.qxl);
-}
-
-static void qxl_spice_destroy_surfaces_complete(PCIQXLDevice *qxl)
-{
- trace_qxl_spice_destroy_surfaces_complete(qxl->id);
- qemu_mutex_lock(&qxl->track_lock);
- memset(qxl->guest_surfaces.cmds, 0,
- sizeof(qxl->guest_surfaces.cmds[0]) * qxl->ssd.num_surfaces);
- qxl->guest_surfaces.count = 0;
- qemu_mutex_unlock(&qxl->track_lock);
-}
-
-static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async)
-{
- trace_qxl_spice_destroy_surfaces(qxl->id, async);
- if (async) {
- spice_qxl_destroy_surfaces_async(&qxl->ssd.qxl,
- (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
- QXL_IO_DESTROY_ALL_SURFACES_ASYNC));
- } else {
- spice_qxl_destroy_surfaces(&qxl->ssd.qxl);
- qxl_spice_destroy_surfaces_complete(qxl);
- }
-}
-
-static void qxl_spice_monitors_config_async(PCIQXLDevice *qxl, int replay)
-{
- trace_qxl_spice_monitors_config(qxl->id);
- if (replay) {
- /*
- * don't use QXL_COOKIE_TYPE_IO:
- * - we are not running yet (post_load), we will assert
- * in send_events
- * - this is not a guest io, but a reply, so async_io isn't set.
- */
- spice_qxl_monitors_config_async(&qxl->ssd.qxl,
- qxl->guest_monitors_config,
- MEMSLOT_GROUP_GUEST,
- (uintptr_t)qxl_cookie_new(
- QXL_COOKIE_TYPE_POST_LOAD_MONITORS_CONFIG,
- 0));
- } else {
-#if SPICE_SERVER_VERSION >= 0x000c06 /* release 0.12.6 */
- if (qxl->max_outputs) {
- spice_qxl_set_max_monitors(&qxl->ssd.qxl, qxl->max_outputs);
- }
-#endif
- qxl->guest_monitors_config = qxl->ram->monitors_config;
- spice_qxl_monitors_config_async(&qxl->ssd.qxl,
- qxl->ram->monitors_config,
- MEMSLOT_GROUP_GUEST,
- (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
- QXL_IO_MONITORS_CONFIG_ASYNC));
- }
-}
-
-void qxl_spice_reset_image_cache(PCIQXLDevice *qxl)
-{
- trace_qxl_spice_reset_image_cache(qxl->id);
- spice_qxl_reset_image_cache(&qxl->ssd.qxl);
-}
-
-void qxl_spice_reset_cursor(PCIQXLDevice *qxl)
-{
- trace_qxl_spice_reset_cursor(qxl->id);
- spice_qxl_reset_cursor(&qxl->ssd.qxl);
- qemu_mutex_lock(&qxl->track_lock);
- qxl->guest_cursor = 0;
- qemu_mutex_unlock(&qxl->track_lock);
- if (qxl->ssd.cursor) {
- cursor_put(qxl->ssd.cursor);
- }
- qxl->ssd.cursor = cursor_builtin_hidden();
-}
-
-static ram_addr_t qxl_rom_size(void)
-{
- uint32_t required_rom_size = sizeof(QXLRom) + sizeof(QXLModes) +
- sizeof(qxl_modes);
- uint32_t rom_size = 8192; /* two pages */
-
- QEMU_BUILD_BUG_ON(required_rom_size > rom_size);
- return rom_size;
-}
-
-static void init_qxl_rom(PCIQXLDevice *d)
-{
- QXLRom *rom = memory_region_get_ram_ptr(&d->rom_bar);
- QXLModes *modes = (QXLModes *)(rom + 1);
- uint32_t ram_header_size;
- uint32_t surface0_area_size;
- uint32_t num_pages;
- uint32_t fb;
- int i, n;
-
- memset(rom, 0, d->rom_size);
-
- rom->magic = cpu_to_le32(QXL_ROM_MAGIC);
- rom->id = cpu_to_le32(d->id);
- rom->log_level = cpu_to_le32(d->guestdebug);
- rom->modes_offset = cpu_to_le32(sizeof(QXLRom));
-
- rom->slot_gen_bits = MEMSLOT_GENERATION_BITS;
- rom->slot_id_bits = MEMSLOT_SLOT_BITS;
- rom->slots_start = 1;
- rom->slots_end = NUM_MEMSLOTS - 1;
- rom->n_surfaces = cpu_to_le32(d->ssd.num_surfaces);
-
- for (i = 0, n = 0; i < ARRAY_SIZE(qxl_modes); i++) {
- fb = qxl_modes[i].y_res * qxl_modes[i].stride;
- if (fb > d->vgamem_size) {
- continue;
- }
- modes->modes[n].id = cpu_to_le32(i);
- modes->modes[n].x_res = cpu_to_le32(qxl_modes[i].x_res);
- modes->modes[n].y_res = cpu_to_le32(qxl_modes[i].y_res);
- modes->modes[n].bits = cpu_to_le32(qxl_modes[i].bits);
- modes->modes[n].stride = cpu_to_le32(qxl_modes[i].stride);
- modes->modes[n].x_mili = cpu_to_le32(qxl_modes[i].x_mili);
- modes->modes[n].y_mili = cpu_to_le32(qxl_modes[i].y_mili);
- modes->modes[n].orientation = cpu_to_le32(qxl_modes[i].orientation);
- n++;
- }
- modes->n_modes = cpu_to_le32(n);
-
- ram_header_size = ALIGN(sizeof(QXLRam), 4096);
- surface0_area_size = ALIGN(d->vgamem_size, 4096);
- num_pages = d->vga.vram_size;
- num_pages -= ram_header_size;
- num_pages -= surface0_area_size;
- num_pages = num_pages / QXL_PAGE_SIZE;
-
- assert(ram_header_size + surface0_area_size <= d->vga.vram_size);
-
- rom->draw_area_offset = cpu_to_le32(0);
- rom->surface0_area_size = cpu_to_le32(surface0_area_size);
- rom->pages_offset = cpu_to_le32(surface0_area_size);
- rom->num_pages = cpu_to_le32(num_pages);
- rom->ram_header_offset = cpu_to_le32(d->vga.vram_size - ram_header_size);
-
- d->shadow_rom = *rom;
- d->rom = rom;
- d->modes = modes;
-}
-
-static void init_qxl_ram(PCIQXLDevice *d)
-{
- uint8_t *buf;
- uint64_t *item;
-
- buf = d->vga.vram_ptr;
- d->ram = (QXLRam *)(buf + le32_to_cpu(d->shadow_rom.ram_header_offset));
- d->ram->magic = cpu_to_le32(QXL_RAM_MAGIC);
- d->ram->int_pending = cpu_to_le32(0);
- d->ram->int_mask = cpu_to_le32(0);
- d->ram->update_surface = 0;
- d->ram->monitors_config = 0;
- SPICE_RING_INIT(&d->ram->cmd_ring);
- SPICE_RING_INIT(&d->ram->cursor_ring);
- SPICE_RING_INIT(&d->ram->release_ring);
- SPICE_RING_PROD_ITEM(d, &d->ram->release_ring, item);
- assert(item);
- *item = 0;
- qxl_ring_set_dirty(d);
-}
-
-/* can be called from spice server thread context */
-static void qxl_set_dirty(MemoryRegion *mr, ram_addr_t addr, ram_addr_t end)
-{
- memory_region_set_dirty(mr, addr, end - addr);
-}
-
-static void qxl_rom_set_dirty(PCIQXLDevice *qxl)
-{
- qxl_set_dirty(&qxl->rom_bar, 0, qxl->rom_size);
-}
-
-/* called from spice server thread context only */
-static void qxl_ram_set_dirty(PCIQXLDevice *qxl, void *ptr)
-{
- void *base = qxl->vga.vram_ptr;
- intptr_t offset;
-
- offset = ptr - base;
- assert(offset < qxl->vga.vram_size);
- qxl_set_dirty(&qxl->vga.vram, offset, offset + 3);
-}
-
-/* can be called from spice server thread context */
-static void qxl_ring_set_dirty(PCIQXLDevice *qxl)
-{
- ram_addr_t addr = qxl->shadow_rom.ram_header_offset;
- ram_addr_t end = qxl->vga.vram_size;
- qxl_set_dirty(&qxl->vga.vram, addr, end);
-}
-
-/*
- * keep track of some command state, for savevm/loadvm.
- * called from spice server thread context only
- */
-static int qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext)
-{
- switch (le32_to_cpu(ext->cmd.type)) {
- case QXL_CMD_SURFACE:
- {
- QXLSurfaceCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
-
- if (!cmd) {
- return 1;
- }
- uint32_t id = le32_to_cpu(cmd->surface_id);
-
- if (id >= qxl->ssd.num_surfaces) {
- qxl_set_guest_bug(qxl, "QXL_CMD_SURFACE id %d >= %d", id,
- qxl->ssd.num_surfaces);
- return 1;
- }
- if (cmd->type == QXL_SURFACE_CMD_CREATE &&
- (cmd->u.surface_create.stride & 0x03) != 0) {
- qxl_set_guest_bug(qxl, "QXL_CMD_SURFACE stride = %d %% 4 != 0\n",
- cmd->u.surface_create.stride);
- return 1;
- }
- qemu_mutex_lock(&qxl->track_lock);
- if (cmd->type == QXL_SURFACE_CMD_CREATE) {
- qxl->guest_surfaces.cmds[id] = ext->cmd.data;
- qxl->guest_surfaces.count++;
- if (qxl->guest_surfaces.max < qxl->guest_surfaces.count)
- qxl->guest_surfaces.max = qxl->guest_surfaces.count;
- }
- if (cmd->type == QXL_SURFACE_CMD_DESTROY) {
- qxl->guest_surfaces.cmds[id] = 0;
- qxl->guest_surfaces.count--;
- }
- qemu_mutex_unlock(&qxl->track_lock);
- break;
- }
- case QXL_CMD_CURSOR:
- {
- QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
-
- if (!cmd) {
- return 1;
- }
- if (cmd->type == QXL_CURSOR_SET) {
- qemu_mutex_lock(&qxl->track_lock);
- qxl->guest_cursor = ext->cmd.data;
- qemu_mutex_unlock(&qxl->track_lock);
- }
- break;
- }
- }
- return 0;
-}
-
-/* spice display interface callbacks */
-
-static void interface_attach_worker(QXLInstance *sin, QXLWorker *qxl_worker)
-{
- PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
-
- trace_qxl_interface_attach_worker(qxl->id);
- qxl->ssd.worker = qxl_worker;
-}
-
-static void interface_set_compression_level(QXLInstance *sin, int level)
-{
- PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
-
- trace_qxl_interface_set_compression_level(qxl->id, level);
- qxl->shadow_rom.compression_level = cpu_to_le32(level);
- qxl->rom->compression_level = cpu_to_le32(level);
- qxl_rom_set_dirty(qxl);
-}
-
-static void interface_set_mm_time(QXLInstance *sin, uint32_t mm_time)
-{
- PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
-
- if (!qemu_spice_display_is_running(&qxl->ssd)) {
- return;
- }
-
- trace_qxl_interface_set_mm_time(qxl->id, mm_time);
- qxl->shadow_rom.mm_clock = cpu_to_le32(mm_time);
- qxl->rom->mm_clock = cpu_to_le32(mm_time);
- qxl_rom_set_dirty(qxl);
-}
-
-static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info)
-{
- PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
-
- trace_qxl_interface_get_init_info(qxl->id);
- info->memslot_gen_bits = MEMSLOT_GENERATION_BITS;
- info->memslot_id_bits = MEMSLOT_SLOT_BITS;
- info->num_memslots = NUM_MEMSLOTS;
- info->num_memslots_groups = NUM_MEMSLOTS_GROUPS;
- info->internal_groupslot_id = 0;
- info->qxl_ram_size =
- le32_to_cpu(qxl->shadow_rom.num_pages) << QXL_PAGE_BITS;
- info->n_surfaces = qxl->ssd.num_surfaces;
-}
-
-static const char *qxl_mode_to_string(int mode)
-{
- switch (mode) {
- case QXL_MODE_COMPAT:
- return "compat";
- case QXL_MODE_NATIVE:
- return "native";
- case QXL_MODE_UNDEFINED:
- return "undefined";
- case QXL_MODE_VGA:
- return "vga";
- }
- return "INVALID";
-}
-
-static const char *io_port_to_string(uint32_t io_port)
-{
- if (io_port >= QXL_IO_RANGE_SIZE) {
- return "out of range";
- }
- static const char *io_port_to_string[QXL_IO_RANGE_SIZE + 1] = {
- [QXL_IO_NOTIFY_CMD] = "QXL_IO_NOTIFY_CMD",
- [QXL_IO_NOTIFY_CURSOR] = "QXL_IO_NOTIFY_CURSOR",
- [QXL_IO_UPDATE_AREA] = "QXL_IO_UPDATE_AREA",
- [QXL_IO_UPDATE_IRQ] = "QXL_IO_UPDATE_IRQ",
- [QXL_IO_NOTIFY_OOM] = "QXL_IO_NOTIFY_OOM",
- [QXL_IO_RESET] = "QXL_IO_RESET",
- [QXL_IO_SET_MODE] = "QXL_IO_SET_MODE",
- [QXL_IO_LOG] = "QXL_IO_LOG",
- [QXL_IO_MEMSLOT_ADD] = "QXL_IO_MEMSLOT_ADD",
- [QXL_IO_MEMSLOT_DEL] = "QXL_IO_MEMSLOT_DEL",
- [QXL_IO_DETACH_PRIMARY] = "QXL_IO_DETACH_PRIMARY",
- [QXL_IO_ATTACH_PRIMARY] = "QXL_IO_ATTACH_PRIMARY",
- [QXL_IO_CREATE_PRIMARY] = "QXL_IO_CREATE_PRIMARY",
- [QXL_IO_DESTROY_PRIMARY] = "QXL_IO_DESTROY_PRIMARY",
- [QXL_IO_DESTROY_SURFACE_WAIT] = "QXL_IO_DESTROY_SURFACE_WAIT",
- [QXL_IO_DESTROY_ALL_SURFACES] = "QXL_IO_DESTROY_ALL_SURFACES",
- [QXL_IO_UPDATE_AREA_ASYNC] = "QXL_IO_UPDATE_AREA_ASYNC",
- [QXL_IO_MEMSLOT_ADD_ASYNC] = "QXL_IO_MEMSLOT_ADD_ASYNC",
- [QXL_IO_CREATE_PRIMARY_ASYNC] = "QXL_IO_CREATE_PRIMARY_ASYNC",
- [QXL_IO_DESTROY_PRIMARY_ASYNC] = "QXL_IO_DESTROY_PRIMARY_ASYNC",
- [QXL_IO_DESTROY_SURFACE_ASYNC] = "QXL_IO_DESTROY_SURFACE_ASYNC",
- [QXL_IO_DESTROY_ALL_SURFACES_ASYNC]
- = "QXL_IO_DESTROY_ALL_SURFACES_ASYNC",
- [QXL_IO_FLUSH_SURFACES_ASYNC] = "QXL_IO_FLUSH_SURFACES_ASYNC",
- [QXL_IO_FLUSH_RELEASE] = "QXL_IO_FLUSH_RELEASE",
- [QXL_IO_MONITORS_CONFIG_ASYNC] = "QXL_IO_MONITORS_CONFIG_ASYNC",
- };
- return io_port_to_string[io_port];
-}
-
-/* called from spice server thread context only */
-static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
-{
- PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
- SimpleSpiceUpdate *update;
- QXLCommandRing *ring;
- QXLCommand *cmd;
- int notify, ret;
-
- trace_qxl_ring_command_check(qxl->id, qxl_mode_to_string(qxl->mode));
-
- switch (qxl->mode) {
- case QXL_MODE_VGA:
- ret = false;
- qemu_mutex_lock(&qxl->ssd.lock);
- update = QTAILQ_FIRST(&qxl->ssd.updates);
- if (update != NULL) {
- QTAILQ_REMOVE(&qxl->ssd.updates, update, next);
- *ext = update->ext;
- ret = true;
- }
- qemu_mutex_unlock(&qxl->ssd.lock);
- if (ret) {
- trace_qxl_ring_command_get(qxl->id, qxl_mode_to_string(qxl->mode));
- qxl_log_command(qxl, "vga", ext);
- }
- return ret;
- case QXL_MODE_COMPAT:
- case QXL_MODE_NATIVE:
- case QXL_MODE_UNDEFINED:
- ring = &qxl->ram->cmd_ring;
- if (qxl->guest_bug || SPICE_RING_IS_EMPTY(ring)) {
- return false;
- }
- SPICE_RING_CONS_ITEM(qxl, ring, cmd);
- if (!cmd) {
- return false;
- }
- ext->cmd = *cmd;
- ext->group_id = MEMSLOT_GROUP_GUEST;
- ext->flags = qxl->cmdflags;
- SPICE_RING_POP(ring, notify);
- qxl_ring_set_dirty(qxl);
- if (notify) {
- qxl_send_events(qxl, QXL_INTERRUPT_DISPLAY);
- }
- qxl->guest_primary.commands++;
- qxl_track_command(qxl, ext);
- qxl_log_command(qxl, "cmd", ext);
- trace_qxl_ring_command_get(qxl->id, qxl_mode_to_string(qxl->mode));
- return true;
- default:
- return false;
- }
-}
-
-/* called from spice server thread context only */
-static int interface_req_cmd_notification(QXLInstance *sin)
-{
- PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
- int wait = 1;
-
- trace_qxl_ring_command_req_notification(qxl->id);
- switch (qxl->mode) {
- case QXL_MODE_COMPAT:
- case QXL_MODE_NATIVE:
- case QXL_MODE_UNDEFINED:
- SPICE_RING_CONS_WAIT(&qxl->ram->cmd_ring, wait);
- qxl_ring_set_dirty(qxl);
- break;
- default:
- /* nothing */
- break;
- }
- return wait;
-}
-
-/* called from spice server thread context only */
-static inline void qxl_push_free_res(PCIQXLDevice *d, int flush)
-{
- QXLReleaseRing *ring = &d->ram->release_ring;
- uint64_t *item;
- int notify;
-
-#define QXL_FREE_BUNCH_SIZE 32
-
- if (ring->prod - ring->cons + 1 == ring->num_items) {
- /* ring full -- can't push */
- return;
- }
- if (!flush && d->oom_running) {
- /* collect everything from oom handler before pushing */
- return;
- }
- if (!flush && d->num_free_res < QXL_FREE_BUNCH_SIZE) {
- /* collect a bit more before pushing */
- return;
- }
-
- SPICE_RING_PUSH(ring, notify);
- trace_qxl_ring_res_push(d->id, qxl_mode_to_string(d->mode),
- d->guest_surfaces.count, d->num_free_res,
- d->last_release, notify ? "yes" : "no");
- trace_qxl_ring_res_push_rest(d->id, ring->prod - ring->cons,
- ring->num_items, ring->prod, ring->cons);
- if (notify) {
- qxl_send_events(d, QXL_INTERRUPT_DISPLAY);
- }
- SPICE_RING_PROD_ITEM(d, ring, item);
- if (!item) {
- return;
- }
- *item = 0;
- d->num_free_res = 0;
- d->last_release = NULL;
- qxl_ring_set_dirty(d);
-}
-
-/* called from spice server thread context only */
-static void interface_release_resource(QXLInstance *sin,
- QXLReleaseInfoExt ext)
-{
- PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
- QXLReleaseRing *ring;
- uint64_t *item, id;
-
- if (ext.group_id == MEMSLOT_GROUP_HOST) {
- /* host group -> vga mode update request */
- QXLCommandExt *cmdext = (void *)(intptr_t)(ext.info->id);
- SimpleSpiceUpdate *update;
- g_assert(cmdext->cmd.type == QXL_CMD_DRAW);
- update = container_of(cmdext, SimpleSpiceUpdate, ext);
- qemu_spice_destroy_update(&qxl->ssd, update);
- return;
- }
-
- /*
- * ext->info points into guest-visible memory
- * pci bar 0, $command.release_info
- */
- ring = &qxl->ram->release_ring;
- SPICE_RING_PROD_ITEM(qxl, ring, item);
- if (!item) {
- return;
- }
- if (*item == 0) {
- /* stick head into the ring */
- id = ext.info->id;
- ext.info->next = 0;
- qxl_ram_set_dirty(qxl, &ext.info->next);
- *item = id;
- qxl_ring_set_dirty(qxl);
- } else {
- /* append item to the list */
- qxl->last_release->next = ext.info->id;
- qxl_ram_set_dirty(qxl, &qxl->last_release->next);
- ext.info->next = 0;
- qxl_ram_set_dirty(qxl, &ext.info->next);
- }
- qxl->last_release = ext.info;
- qxl->num_free_res++;
- trace_qxl_ring_res_put(qxl->id, qxl->num_free_res);
- qxl_push_free_res(qxl, 0);
-}
-
-/* called from spice server thread context only */
-static int interface_get_cursor_command(QXLInstance *sin, struct QXLCommandExt *ext)
-{
- PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
- QXLCursorRing *ring;
- QXLCommand *cmd;
- int notify;
-
- trace_qxl_ring_cursor_check(qxl->id, qxl_mode_to_string(qxl->mode));
-
- switch (qxl->mode) {
- case QXL_MODE_COMPAT:
- case QXL_MODE_NATIVE:
- case QXL_MODE_UNDEFINED:
- ring = &qxl->ram->cursor_ring;
- if (SPICE_RING_IS_EMPTY(ring)) {
- return false;
- }
- SPICE_RING_CONS_ITEM(qxl, ring, cmd);
- if (!cmd) {
- return false;
- }
- ext->cmd = *cmd;
- ext->group_id = MEMSLOT_GROUP_GUEST;
- ext->flags = qxl->cmdflags;
- SPICE_RING_POP(ring, notify);
- qxl_ring_set_dirty(qxl);
- if (notify) {
- qxl_send_events(qxl, QXL_INTERRUPT_CURSOR);
- }
- qxl->guest_primary.commands++;
- qxl_track_command(qxl, ext);
- qxl_log_command(qxl, "csr", ext);
- if (qxl->id == 0) {
- qxl_render_cursor(qxl, ext);
- }
- trace_qxl_ring_cursor_get(qxl->id, qxl_mode_to_string(qxl->mode));
- return true;
- default:
- return false;
- }
-}
-
-/* called from spice server thread context only */
-static int interface_req_cursor_notification(QXLInstance *sin)
-{
- PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
- int wait = 1;
-
- trace_qxl_ring_cursor_req_notification(qxl->id);
- switch (qxl->mode) {
- case QXL_MODE_COMPAT:
- case QXL_MODE_NATIVE:
- case QXL_MODE_UNDEFINED:
- SPICE_RING_CONS_WAIT(&qxl->ram->cursor_ring, wait);
- qxl_ring_set_dirty(qxl);
- break;
- default:
- /* nothing */
- break;
- }
- return wait;
-}
-
-/* called from spice server thread context */
-static void interface_notify_update(QXLInstance *sin, uint32_t update_id)
-{
- /*
- * Called by spice-server as a result of a QXL_CMD_UPDATE which is not in
- * use by xf86-video-qxl and is defined out in the qxl windows driver.
- * Probably was at some earlier version that is prior to git start (2009),
- * and is still guest trigerrable.
- */
- fprintf(stderr, "%s: deprecated\n", __func__);
-}
-
-/* called from spice server thread context only */
-static int interface_flush_resources(QXLInstance *sin)
-{
- PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
- int ret;
-
- ret = qxl->num_free_res;
- if (ret) {
- qxl_push_free_res(qxl, 1);
- }
- return ret;
-}
-
-static void qxl_create_guest_primary_complete(PCIQXLDevice *d);
-
-/* called from spice server thread context only */
-static void interface_async_complete_io(PCIQXLDevice *qxl, QXLCookie *cookie)
-{
- uint32_t current_async;
-
- qemu_mutex_lock(&qxl->async_lock);
- current_async = qxl->current_async;
- qxl->current_async = QXL_UNDEFINED_IO;
- qemu_mutex_unlock(&qxl->async_lock);
-
- trace_qxl_interface_async_complete_io(qxl->id, current_async, cookie);
- if (!cookie) {
- fprintf(stderr, "qxl: %s: error, cookie is NULL\n", __func__);
- return;
- }
- if (cookie && current_async != cookie->io) {
- fprintf(stderr,
- "qxl: %s: error: current_async = %d != %"
- PRId64 " = cookie->io\n", __func__, current_async, cookie->io);
- }
- switch (current_async) {
- case QXL_IO_MEMSLOT_ADD_ASYNC:
- case QXL_IO_DESTROY_PRIMARY_ASYNC:
- case QXL_IO_UPDATE_AREA_ASYNC:
- case QXL_IO_FLUSH_SURFACES_ASYNC:
- case QXL_IO_MONITORS_CONFIG_ASYNC:
- break;
- case QXL_IO_CREATE_PRIMARY_ASYNC:
- qxl_create_guest_primary_complete(qxl);
- break;
- case QXL_IO_DESTROY_ALL_SURFACES_ASYNC:
- qxl_spice_destroy_surfaces_complete(qxl);
- break;
- case QXL_IO_DESTROY_SURFACE_ASYNC:
- qxl_spice_destroy_surface_wait_complete(qxl, cookie->u.surface_id);
- break;
- default:
- fprintf(stderr, "qxl: %s: unexpected current_async %d\n", __func__,
- current_async);
- }
- qxl_send_events(qxl, QXL_INTERRUPT_IO_CMD);
-}
-
-/* called from spice server thread context only */
-static void interface_update_area_complete(QXLInstance *sin,
- uint32_t surface_id,
- QXLRect *dirty, uint32_t num_updated_rects)
-{
- PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
- int i;
- int qxl_i;
-
- qemu_mutex_lock(&qxl->ssd.lock);
- if (surface_id != 0 || !qxl->render_update_cookie_num) {
- qemu_mutex_unlock(&qxl->ssd.lock);
- return;
- }
- trace_qxl_interface_update_area_complete(qxl->id, surface_id, dirty->left,
- dirty->right, dirty->top, dirty->bottom);
- trace_qxl_interface_update_area_complete_rest(qxl->id, num_updated_rects);
- if (qxl->num_dirty_rects + num_updated_rects > QXL_NUM_DIRTY_RECTS) {
- /*
- * overflow - treat this as a full update. Not expected to be common.
- */
- trace_qxl_interface_update_area_complete_overflow(qxl->id,
- QXL_NUM_DIRTY_RECTS);
- qxl->guest_primary.resized = 1;
- }
- if (qxl->guest_primary.resized) {
- /*
- * Don't bother copying or scheduling the bh since we will flip
- * the whole area anyway on completion of the update_area async call
- */
- qemu_mutex_unlock(&qxl->ssd.lock);
- return;
- }
- qxl_i = qxl->num_dirty_rects;
- for (i = 0; i < num_updated_rects; i++) {
- qxl->dirty[qxl_i++] = dirty[i];
- }
- qxl->num_dirty_rects += num_updated_rects;
- trace_qxl_interface_update_area_complete_schedule_bh(qxl->id,
- qxl->num_dirty_rects);
- qemu_bh_schedule(qxl->update_area_bh);
- qemu_mutex_unlock(&qxl->ssd.lock);
-}
-
-/* called from spice server thread context only */
-static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token)
-{
- PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
- QXLCookie *cookie = (QXLCookie *)(uintptr_t)cookie_token;
-
- switch (cookie->type) {
- case QXL_COOKIE_TYPE_IO:
- interface_async_complete_io(qxl, cookie);
- g_free(cookie);
- break;
- case QXL_COOKIE_TYPE_RENDER_UPDATE_AREA:
- qxl_render_update_area_done(qxl, cookie);
- break;
- case QXL_COOKIE_TYPE_POST_LOAD_MONITORS_CONFIG:
- break;
- default:
- fprintf(stderr, "qxl: %s: unexpected cookie type %d\n",
- __func__, cookie->type);
- g_free(cookie);
- }
-}
-
-/* called from spice server thread context only */
-static void interface_set_client_capabilities(QXLInstance *sin,
- uint8_t client_present,
- uint8_t caps[58])
-{
- 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;
- }
-
- qxl->shadow_rom.client_present = client_present;
- memcpy(qxl->shadow_rom.client_capabilities, caps,
- sizeof(qxl->shadow_rom.client_capabilities));
- qxl->rom->client_present = client_present;
- memcpy(qxl->rom->client_capabilities, caps,
- sizeof(qxl->rom->client_capabilities));
- qxl_rom_set_dirty(qxl);
-
- qxl_send_events(qxl, QXL_INTERRUPT_CLIENT);
-}
-
-static uint32_t qxl_crc32(const uint8_t *p, unsigned len)
-{
- /*
- * zlib xors the seed with 0xffffffff, and xors the result
- * again with 0xffffffff; Both are not done with linux's crc32,
- * which we want to be compatible with, so undo that.
- */
- return crc32(0xffffffff, p, len) ^ 0xffffffff;
-}
-
-/* called from main context only */
-static int interface_client_monitors_config(QXLInstance *sin,
- VDAgentMonitorsConfig *monitors_config)
-{
- PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
- QXLRom *rom = memory_region_get_ram_ptr(&qxl->rom_bar);
- int i;
- unsigned max_outputs = ARRAY_SIZE(rom->client_monitors_config.heads);
-
- 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
- * handled. However, they are old, so clearly they don't support this
- * interrupt
- */
- if (qxl->ram->int_mask == 0 || qxl->ram->int_mask == ~0 ||
- !(qxl->ram->int_mask & QXL_INTERRUPT_CLIENT_MONITORS_CONFIG)) {
- trace_qxl_client_monitors_config_unsupported_by_guest(qxl->id,
- qxl->ram->int_mask,
- monitors_config);
- return 0;
- }
- if (!monitors_config) {
- return 1;
- }
-
-#if SPICE_SERVER_VERSION >= 0x000c06 /* release 0.12.6 */
- /* limit number of outputs based on setting limit */
- if (qxl->max_outputs && qxl->max_outputs <= max_outputs) {
- max_outputs = qxl->max_outputs;
- }
-#endif
-
- memset(&rom->client_monitors_config, 0,
- sizeof(rom->client_monitors_config));
- rom->client_monitors_config.count = monitors_config->num_of_monitors;
- /* monitors_config->flags ignored */
- if (rom->client_monitors_config.count >= max_outputs) {
- trace_qxl_client_monitors_config_capped(qxl->id,
- monitors_config->num_of_monitors,
- max_outputs);
- rom->client_monitors_config.count = max_outputs;
- }
- for (i = 0 ; i < rom->client_monitors_config.count ; ++i) {
- VDAgentMonConfig *monitor = &monitors_config->monitors[i];
- QXLURect *rect = &rom->client_monitors_config.heads[i];
- /* monitor->depth ignored */
- rect->left = monitor->x;
- rect->top = monitor->y;
- rect->right = monitor->x + monitor->width;
- rect->bottom = monitor->y + monitor->height;
- }
- rom->client_monitors_config_crc = qxl_crc32(
- (const uint8_t *)&rom->client_monitors_config,
- sizeof(rom->client_monitors_config));
- trace_qxl_client_monitors_config_crc(qxl->id,
- sizeof(rom->client_monitors_config),
- rom->client_monitors_config_crc);
-
- trace_qxl_interrupt_client_monitors_config(qxl->id,
- rom->client_monitors_config.count,
- rom->client_monitors_config.heads);
- qxl_send_events(qxl, QXL_INTERRUPT_CLIENT_MONITORS_CONFIG);
- return 1;
-}
-
-static const QXLInterface qxl_interface = {
- .base.type = SPICE_INTERFACE_QXL,
- .base.description = "qxl gpu",
- .base.major_version = SPICE_INTERFACE_QXL_MAJOR,
- .base.minor_version = SPICE_INTERFACE_QXL_MINOR,
-
- .attache_worker = interface_attach_worker,
- .set_compression_level = interface_set_compression_level,
- .set_mm_time = interface_set_mm_time,
- .get_init_info = interface_get_init_info,
-
- /* the callbacks below are called from spice server thread context */
- .get_command = interface_get_command,
- .req_cmd_notification = interface_req_cmd_notification,
- .release_resource = interface_release_resource,
- .get_cursor_command = interface_get_cursor_command,
- .req_cursor_notification = interface_req_cursor_notification,
- .notify_update = interface_notify_update,
- .flush_resources = interface_flush_resources,
- .async_complete = interface_async_complete,
- .update_area_complete = interface_update_area_complete,
- .set_client_capabilities = interface_set_client_capabilities,
- .client_monitors_config = interface_client_monitors_config,
-};
-
-static const GraphicHwOps qxl_ops = {
- .gfx_update = qxl_hw_update,
-};
-
-static void qxl_enter_vga_mode(PCIQXLDevice *d)
-{
- if (d->mode == QXL_MODE_VGA) {
- return;
- }
- trace_qxl_enter_vga_mode(d->id);
-#if SPICE_SERVER_VERSION >= 0x000c03 /* release 0.12.3 */
- spice_qxl_driver_unload(&d->ssd.qxl);
-#endif
- graphic_console_set_hwops(d->ssd.dcl.con, d->vga.hw_ops, &d->vga);
- update_displaychangelistener(&d->ssd.dcl, GUI_REFRESH_INTERVAL_DEFAULT);
- qemu_spice_create_host_primary(&d->ssd);
- d->mode = QXL_MODE_VGA;
- vga_dirty_log_start(&d->vga);
- graphic_hw_update(d->vga.con);
-}
-
-static void qxl_exit_vga_mode(PCIQXLDevice *d)
-{
- if (d->mode != QXL_MODE_VGA) {
- return;
- }
- trace_qxl_exit_vga_mode(d->id);
- graphic_console_set_hwops(d->ssd.dcl.con, &qxl_ops, d);
- update_displaychangelistener(&d->ssd.dcl, GUI_REFRESH_INTERVAL_IDLE);
- vga_dirty_log_stop(&d->vga);
- qxl_destroy_primary(d, QXL_SYNC);
-}
-
-static void qxl_update_irq(PCIQXLDevice *d)
-{
- uint32_t pending = le32_to_cpu(d->ram->int_pending);
- uint32_t mask = le32_to_cpu(d->ram->int_mask);
- int level = !!(pending & mask);
- pci_set_irq(&d->pci, level);
- qxl_ring_set_dirty(d);
-}
-
-static void qxl_check_state(PCIQXLDevice *d)
-{
- QXLRam *ram = d->ram;
- int spice_display_running = qemu_spice_display_is_running(&d->ssd);
-
- assert(!spice_display_running || SPICE_RING_IS_EMPTY(&ram->cmd_ring));
- assert(!spice_display_running || SPICE_RING_IS_EMPTY(&ram->cursor_ring));
-}
-
-static void qxl_reset_state(PCIQXLDevice *d)
-{
- QXLRom *rom = d->rom;
-
- qxl_check_state(d);
- d->shadow_rom.update_id = cpu_to_le32(0);
- *rom = d->shadow_rom;
- qxl_rom_set_dirty(d);
- init_qxl_ram(d);
- d->num_free_res = 0;
- d->last_release = NULL;
- memset(&d->ssd.dirty, 0, sizeof(d->ssd.dirty));
- qxl_update_irq(d);
-}
-
-static void qxl_soft_reset(PCIQXLDevice *d)
-{
- trace_qxl_soft_reset(d->id);
- qxl_check_state(d);
- qxl_clear_guest_bug(d);
- qemu_mutex_lock(&d->async_lock);
- d->current_async = QXL_UNDEFINED_IO;
- qemu_mutex_unlock(&d->async_lock);
-
- if (d->id == 0) {
- qxl_enter_vga_mode(d);
- } else {
- d->mode = QXL_MODE_UNDEFINED;
- }
-}
-
-static void qxl_hard_reset(PCIQXLDevice *d, int loadvm)
-{
- bool startstop = qemu_spice_display_is_running(&d->ssd);
-
- trace_qxl_hard_reset(d->id, loadvm);
-
- if (startstop) {
- qemu_spice_display_stop();
- }
-
- qxl_spice_reset_cursor(d);
- qxl_spice_reset_image_cache(d);
- qxl_reset_surfaces(d);
- qxl_reset_memslots(d);
-
- /* pre loadvm reset must not touch QXLRam. This lives in
- * device memory, is migrated together with RAM and thus
- * already loaded at this point */
- if (!loadvm) {
- qxl_reset_state(d);
- }
- qemu_spice_create_host_memslot(&d->ssd);
- qxl_soft_reset(d);
-
- if (startstop) {
- qemu_spice_display_start();
- }
-}
-
-static void qxl_reset_handler(DeviceState *dev)
-{
- PCIQXLDevice *d = PCI_QXL(PCI_DEVICE(dev));
-
- qxl_hard_reset(d, 0);
-}
-
-static void qxl_vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
-{
- VGACommonState *vga = opaque;
- PCIQXLDevice *qxl = container_of(vga, PCIQXLDevice, vga);
-
- trace_qxl_io_write_vga(qxl->id, qxl_mode_to_string(qxl->mode), addr, val);
- if (qxl->mode != QXL_MODE_VGA) {
- qxl_destroy_primary(qxl, QXL_SYNC);
- qxl_soft_reset(qxl);
- }
- vga_ioport_write(opaque, addr, val);
-}
-
-static const MemoryRegionPortio qxl_vga_portio_list[] = {
- { 0x04, 2, 1, .read = vga_ioport_read,
- .write = qxl_vga_ioport_write }, /* 3b4 */
- { 0x0a, 1, 1, .read = vga_ioport_read,
- .write = qxl_vga_ioport_write }, /* 3ba */
- { 0x10, 16, 1, .read = vga_ioport_read,
- .write = qxl_vga_ioport_write }, /* 3c0 */
- { 0x24, 2, 1, .read = vga_ioport_read,
- .write = qxl_vga_ioport_write }, /* 3d4 */
- { 0x2a, 1, 1, .read = vga_ioport_read,
- .write = qxl_vga_ioport_write }, /* 3da */
- PORTIO_END_OF_LIST(),
-};
-
-static int qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta,
- qxl_async_io async)
-{
- static const int regions[] = {
- QXL_RAM_RANGE_INDEX,
- QXL_VRAM_RANGE_INDEX,
- QXL_VRAM64_RANGE_INDEX,
- };
- uint64_t guest_start;
- uint64_t guest_end;
- int pci_region;
- pcibus_t pci_start;
- pcibus_t pci_end;
- intptr_t virt_start;
- QXLDevMemSlot memslot;
- int i;
-
- guest_start = le64_to_cpu(d->guest_slots[slot_id].slot.mem_start);
- guest_end = le64_to_cpu(d->guest_slots[slot_id].slot.mem_end);
-
- trace_qxl_memslot_add_guest(d->id, slot_id, guest_start, guest_end);
-
- if (slot_id >= NUM_MEMSLOTS) {
- qxl_set_guest_bug(d, "%s: slot_id >= NUM_MEMSLOTS %d >= %d", __func__,
- slot_id, NUM_MEMSLOTS);
- return 1;
- }
- if (guest_start > guest_end) {
- qxl_set_guest_bug(d, "%s: guest_start > guest_end 0x%" PRIx64
- " > 0x%" PRIx64, __func__, guest_start, guest_end);
- return 1;
- }
-
- for (i = 0; i < ARRAY_SIZE(regions); i++) {
- pci_region = regions[i];
- pci_start = d->pci.io_regions[pci_region].addr;
- pci_end = pci_start + d->pci.io_regions[pci_region].size;
- /* mapped? */
- if (pci_start == -1) {
- continue;
- }
- /* start address in range ? */
- if (guest_start < pci_start || guest_start > pci_end) {
- continue;
- }
- /* end address in range ? */
- if (guest_end > pci_end) {
- continue;
- }
- /* passed */
- break;
- }
- if (i == ARRAY_SIZE(regions)) {
- qxl_set_guest_bug(d, "%s: finished loop without match", __func__);
- return 1;
- }
-
- switch (pci_region) {
- case QXL_RAM_RANGE_INDEX:
- virt_start = (intptr_t)memory_region_get_ram_ptr(&d->vga.vram);
- break;
- case QXL_VRAM_RANGE_INDEX:
- case 4 /* vram 64bit */:
- virt_start = (intptr_t)memory_region_get_ram_ptr(&d->vram_bar);
- break;
- default:
- /* should not happen */
- qxl_set_guest_bug(d, "%s: pci_region = %d", __func__, pci_region);
- return 1;
- }
-
- memslot.slot_id = slot_id;
- memslot.slot_group_id = MEMSLOT_GROUP_GUEST; /* guest group */
- memslot.virt_start = virt_start + (guest_start - pci_start);
- memslot.virt_end = virt_start + (guest_end - pci_start);
- memslot.addr_delta = memslot.virt_start - delta;
- memslot.generation = d->rom->slot_generation = 0;
- qxl_rom_set_dirty(d);
-
- qemu_spice_add_memslot(&d->ssd, &memslot, async);
- d->guest_slots[slot_id].ptr = (void*)memslot.virt_start;
- d->guest_slots[slot_id].size = memslot.virt_end - memslot.virt_start;
- d->guest_slots[slot_id].delta = delta;
- d->guest_slots[slot_id].active = 1;
- return 0;
-}
-
-static void qxl_del_memslot(PCIQXLDevice *d, uint32_t slot_id)
-{
- qemu_spice_del_memslot(&d->ssd, MEMSLOT_GROUP_HOST, slot_id);
- d->guest_slots[slot_id].active = 0;
-}
-
-static void qxl_reset_memslots(PCIQXLDevice *d)
-{
- qxl_spice_reset_memslots(d);
- memset(&d->guest_slots, 0, sizeof(d->guest_slots));
-}
-
-static void qxl_reset_surfaces(PCIQXLDevice *d)
-{
- trace_qxl_reset_surfaces(d->id);
- d->mode = QXL_MODE_UNDEFINED;
- qxl_spice_destroy_surfaces(d, QXL_SYNC);
-}
-
-/* can be also called from spice server thread context */
-void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id)
-{
- uint64_t phys = le64_to_cpu(pqxl);
- uint32_t slot = (phys >> (64 - 8)) & 0xff;
- uint64_t offset = phys & 0xffffffffffff;
-
- switch (group_id) {
- case MEMSLOT_GROUP_HOST:
- return (void *)(intptr_t)offset;
- case MEMSLOT_GROUP_GUEST:
- if (slot >= NUM_MEMSLOTS) {
- qxl_set_guest_bug(qxl, "slot too large %d >= %d", slot,
- NUM_MEMSLOTS);
- return NULL;
- }
- if (!qxl->guest_slots[slot].active) {
- qxl_set_guest_bug(qxl, "inactive slot %d\n", slot);
- return NULL;
- }
- if (offset < qxl->guest_slots[slot].delta) {
- qxl_set_guest_bug(qxl,
- "slot %d offset %"PRIu64" < delta %"PRIu64"\n",
- slot, offset, qxl->guest_slots[slot].delta);
- return NULL;
- }
- offset -= qxl->guest_slots[slot].delta;
- if (offset > qxl->guest_slots[slot].size) {
- qxl_set_guest_bug(qxl,
- "slot %d offset %"PRIu64" > size %"PRIu64"\n",
- slot, offset, qxl->guest_slots[slot].size);
- return NULL;
- }
- return qxl->guest_slots[slot].ptr + offset;
- }
- return NULL;
-}
-
-static void qxl_create_guest_primary_complete(PCIQXLDevice *qxl)
-{
- /* for local rendering */
- qxl_render_resize(qxl);
-}
-
-static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm,
- qxl_async_io async)
-{
- QXLDevSurfaceCreate surface;
- QXLSurfaceCreate *sc = &qxl->guest_primary.surface;
- uint32_t requested_height = le32_to_cpu(sc->height);
- int requested_stride = le32_to_cpu(sc->stride);
-
- if (requested_stride == INT32_MIN ||
- abs(requested_stride) * (uint64_t)requested_height
- > qxl->vgamem_size) {
- qxl_set_guest_bug(qxl, "%s: requested primary larger than framebuffer"
- " stride %d x height %" PRIu32 " > %" PRIu32,
- __func__, requested_stride, requested_height,
- qxl->vgamem_size);
- return;
- }
-
- if (qxl->mode == QXL_MODE_NATIVE) {
- qxl_set_guest_bug(qxl, "%s: nop since already in QXL_MODE_NATIVE",
- __func__);
- }
- qxl_exit_vga_mode(qxl);
-
- surface.format = le32_to_cpu(sc->format);
- surface.height = le32_to_cpu(sc->height);
- surface.mem = le64_to_cpu(sc->mem);
- surface.position = le32_to_cpu(sc->position);
- surface.stride = le32_to_cpu(sc->stride);
- surface.width = le32_to_cpu(sc->width);
- surface.type = le32_to_cpu(sc->type);
- surface.flags = le32_to_cpu(sc->flags);
- trace_qxl_create_guest_primary(qxl->id, sc->width, sc->height, sc->mem,
- sc->format, sc->position);
- trace_qxl_create_guest_primary_rest(qxl->id, sc->stride, sc->type,
- sc->flags);
-
- if ((surface.stride & 0x3) != 0) {
- qxl_set_guest_bug(qxl, "primary surface stride = %d %% 4 != 0",
- surface.stride);
- return;
- }
-
- surface.mouse_mode = true;
- surface.group_id = MEMSLOT_GROUP_GUEST;
- if (loadvm) {
- surface.flags |= QXL_SURF_FLAG_KEEP_DATA;
- }
-
- qxl->mode = QXL_MODE_NATIVE;
- qxl->cmdflags = 0;
- qemu_spice_create_primary_surface(&qxl->ssd, 0, &surface, async);
-
- if (async == QXL_SYNC) {
- qxl_create_guest_primary_complete(qxl);
- }
-}
-
-/* return 1 if surface destoy was initiated (in QXL_ASYNC case) or
- * done (in QXL_SYNC case), 0 otherwise. */
-static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async)
-{
- if (d->mode == QXL_MODE_UNDEFINED) {
- return 0;
- }
- trace_qxl_destroy_primary(d->id);
- d->mode = QXL_MODE_UNDEFINED;
- qemu_spice_destroy_primary_surface(&d->ssd, 0, async);
- qxl_spice_reset_cursor(d);
- return 1;
-}
-
-static void qxl_set_mode(PCIQXLDevice *d, unsigned int modenr, int loadvm)
-{
- pcibus_t start = d->pci.io_regions[QXL_RAM_RANGE_INDEX].addr;
- pcibus_t end = d->pci.io_regions[QXL_RAM_RANGE_INDEX].size + start;
- QXLMode *mode = d->modes->modes + modenr;
- uint64_t devmem = d->pci.io_regions[QXL_RAM_RANGE_INDEX].addr;
- QXLMemSlot slot = {
- .mem_start = start,
- .mem_end = end
- };
-
- if (modenr >= d->modes->n_modes) {
- qxl_set_guest_bug(d, "mode number out of range");
- return;
- }
-
- QXLSurfaceCreate surface = {
- .width = mode->x_res,
- .height = mode->y_res,
- .stride = -mode->x_res * 4,
- .format = SPICE_SURFACE_FMT_32_xRGB,
- .flags = loadvm ? QXL_SURF_FLAG_KEEP_DATA : 0,
- .mouse_mode = true,
- .mem = devmem + d->shadow_rom.draw_area_offset,
- };
-
- trace_qxl_set_mode(d->id, modenr, mode->x_res, mode->y_res, mode->bits,
- devmem);
- if (!loadvm) {
- qxl_hard_reset(d, 0);
- }
-
- d->guest_slots[0].slot = slot;
- assert(qxl_add_memslot(d, 0, devmem, QXL_SYNC) == 0);
-
- d->guest_primary.surface = surface;
- qxl_create_guest_primary(d, 0, QXL_SYNC);
-
- d->mode = QXL_MODE_COMPAT;
- d->cmdflags = QXL_COMMAND_FLAG_COMPAT;
- if (mode->bits == 16) {
- d->cmdflags |= QXL_COMMAND_FLAG_COMPAT_16BPP;
- }
- d->shadow_rom.mode = cpu_to_le32(modenr);
- d->rom->mode = cpu_to_le32(modenr);
- qxl_rom_set_dirty(d);
-}
-
-static void ioport_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- PCIQXLDevice *d = opaque;
- uint32_t io_port = addr;
- qxl_async_io async = QXL_SYNC;
- uint32_t orig_io_port = io_port;
-
- if (d->guest_bug && io_port != QXL_IO_RESET) {
- return;
- }
-
- if (d->revision <= QXL_REVISION_STABLE_V10 &&
- io_port > QXL_IO_FLUSH_RELEASE) {
- qxl_set_guest_bug(d, "unsupported io %d for revision %d\n",
- io_port, d->revision);
- return;
- }
-
- switch (io_port) {
- case QXL_IO_RESET:
- case QXL_IO_SET_MODE:
- case QXL_IO_MEMSLOT_ADD:
- case QXL_IO_MEMSLOT_DEL:
- case QXL_IO_CREATE_PRIMARY:
- case QXL_IO_UPDATE_IRQ:
- case QXL_IO_LOG:
- case QXL_IO_MEMSLOT_ADD_ASYNC:
- case QXL_IO_CREATE_PRIMARY_ASYNC:
- break;
- default:
- if (d->mode != QXL_MODE_VGA) {
- break;
- }
- trace_qxl_io_unexpected_vga_mode(d->id,
- addr, val, io_port_to_string(io_port));
- /* be nice to buggy guest drivers */
- if (io_port >= QXL_IO_UPDATE_AREA_ASYNC &&
- io_port < QXL_IO_RANGE_SIZE) {
- qxl_send_events(d, QXL_INTERRUPT_IO_CMD);
- }
- return;
- }
-
- /* we change the io_port to avoid ifdeffery in the main switch */
- orig_io_port = io_port;
- switch (io_port) {
- case QXL_IO_UPDATE_AREA_ASYNC:
- io_port = QXL_IO_UPDATE_AREA;
- goto async_common;
- case QXL_IO_MEMSLOT_ADD_ASYNC:
- io_port = QXL_IO_MEMSLOT_ADD;
- goto async_common;
- case QXL_IO_CREATE_PRIMARY_ASYNC:
- io_port = QXL_IO_CREATE_PRIMARY;
- goto async_common;
- case QXL_IO_DESTROY_PRIMARY_ASYNC:
- io_port = QXL_IO_DESTROY_PRIMARY;
- goto async_common;
- case QXL_IO_DESTROY_SURFACE_ASYNC:
- io_port = QXL_IO_DESTROY_SURFACE_WAIT;
- goto async_common;
- case QXL_IO_DESTROY_ALL_SURFACES_ASYNC:
- io_port = QXL_IO_DESTROY_ALL_SURFACES;
- goto async_common;
- case QXL_IO_FLUSH_SURFACES_ASYNC:
- case QXL_IO_MONITORS_CONFIG_ASYNC:
-async_common:
- async = QXL_ASYNC;
- qemu_mutex_lock(&d->async_lock);
- if (d->current_async != QXL_UNDEFINED_IO) {
- qxl_set_guest_bug(d, "%d async started before last (%d) complete",
- io_port, d->current_async);
- qemu_mutex_unlock(&d->async_lock);
- return;
- }
- d->current_async = orig_io_port;
- qemu_mutex_unlock(&d->async_lock);
- break;
- default:
- break;
- }
- trace_qxl_io_write(d->id, qxl_mode_to_string(d->mode),
- addr, io_port_to_string(addr),
- val, size, async);
-
- switch (io_port) {
- case QXL_IO_UPDATE_AREA:
- {
- QXLCookie *cookie = NULL;
- QXLRect update = d->ram->update_area;
-
- if (d->ram->update_surface > d->ssd.num_surfaces) {
- qxl_set_guest_bug(d, "QXL_IO_UPDATE_AREA: invalid surface id %d\n",
- d->ram->update_surface);
- break;
- }
- if (update.left >= update.right || update.top >= update.bottom ||
- update.left < 0 || update.top < 0) {
- qxl_set_guest_bug(d,
- "QXL_IO_UPDATE_AREA: invalid area (%ux%u)x(%ux%u)\n",
- update.left, update.top, update.right, update.bottom);
- if (update.left == update.right || update.top == update.bottom) {
- /* old drivers may provide empty area, keep going */
- qxl_clear_guest_bug(d);
- goto cancel_async;
- }
- break;
- }
- if (async == QXL_ASYNC) {
- cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO,
- QXL_IO_UPDATE_AREA_ASYNC);
- cookie->u.area = update;
- }
- qxl_spice_update_area(d, d->ram->update_surface,
- cookie ? &cookie->u.area : &update,
- NULL, 0, 0, async, cookie);
- break;
- }
- case QXL_IO_NOTIFY_CMD:
- qemu_spice_wakeup(&d->ssd);
- break;
- case QXL_IO_NOTIFY_CURSOR:
- qemu_spice_wakeup(&d->ssd);
- break;
- case QXL_IO_UPDATE_IRQ:
- qxl_update_irq(d);
- break;
- case QXL_IO_NOTIFY_OOM:
- if (!SPICE_RING_IS_EMPTY(&d->ram->release_ring)) {
- break;
- }
- d->oom_running = 1;
- qxl_spice_oom(d);
- d->oom_running = 0;
- break;
- case QXL_IO_SET_MODE:
- qxl_set_mode(d, val, 0);
- break;
- case QXL_IO_LOG:
- trace_qxl_io_log(d->id, d->ram->log_buf);
- if (d->guestdebug) {
- fprintf(stderr, "qxl/guest-%d: %" PRId64 ": %s", d->id,
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), d->ram->log_buf);
- }
- break;
- case QXL_IO_RESET:
- qxl_hard_reset(d, 0);
- break;
- case QXL_IO_MEMSLOT_ADD:
- if (val >= NUM_MEMSLOTS) {
- qxl_set_guest_bug(d, "QXL_IO_MEMSLOT_ADD: val out of range");
- break;
- }
- if (d->guest_slots[val].active) {
- qxl_set_guest_bug(d,
- "QXL_IO_MEMSLOT_ADD: memory slot already active");
- break;
- }
- d->guest_slots[val].slot = d->ram->mem_slot;
- qxl_add_memslot(d, val, 0, async);
- break;
- case QXL_IO_MEMSLOT_DEL:
- if (val >= NUM_MEMSLOTS) {
- qxl_set_guest_bug(d, "QXL_IO_MEMSLOT_DEL: val out of range");
- break;
- }
- qxl_del_memslot(d, val);
- break;
- case QXL_IO_CREATE_PRIMARY:
- if (val != 0) {
- qxl_set_guest_bug(d, "QXL_IO_CREATE_PRIMARY (async=%d): val != 0",
- async);
- goto cancel_async;
- }
- d->guest_primary.surface = d->ram->create_surface;
- qxl_create_guest_primary(d, 0, async);
- break;
- case QXL_IO_DESTROY_PRIMARY:
- if (val != 0) {
- qxl_set_guest_bug(d, "QXL_IO_DESTROY_PRIMARY (async=%d): val != 0",
- async);
- goto cancel_async;
- }
- if (!qxl_destroy_primary(d, async)) {
- trace_qxl_io_destroy_primary_ignored(d->id,
- qxl_mode_to_string(d->mode));
- goto cancel_async;
- }
- break;
- case QXL_IO_DESTROY_SURFACE_WAIT:
- if (val >= d->ssd.num_surfaces) {
- qxl_set_guest_bug(d, "QXL_IO_DESTROY_SURFACE (async=%d):"
- "%" PRIu64 " >= NUM_SURFACES", async, val);
- goto cancel_async;
- }
- qxl_spice_destroy_surface_wait(d, val, async);
- break;
- case QXL_IO_FLUSH_RELEASE: {
- QXLReleaseRing *ring = &d->ram->release_ring;
- if (ring->prod - ring->cons + 1 == ring->num_items) {
- fprintf(stderr,
- "ERROR: no flush, full release ring [p%d,%dc]\n",
- ring->prod, ring->cons);
- }
- qxl_push_free_res(d, 1 /* flush */);
- break;
- }
- case QXL_IO_FLUSH_SURFACES_ASYNC:
- qxl_spice_flush_surfaces_async(d);
- break;
- case QXL_IO_DESTROY_ALL_SURFACES:
- d->mode = QXL_MODE_UNDEFINED;
- qxl_spice_destroy_surfaces(d, async);
- break;
- case QXL_IO_MONITORS_CONFIG_ASYNC:
- qxl_spice_monitors_config_async(d, 0);
- break;
- default:
- qxl_set_guest_bug(d, "%s: unexpected ioport=0x%x\n", __func__, io_port);
- }
- return;
-cancel_async:
- if (async) {
- qxl_send_events(d, QXL_INTERRUPT_IO_CMD);
- qemu_mutex_lock(&d->async_lock);
- d->current_async = QXL_UNDEFINED_IO;
- qemu_mutex_unlock(&d->async_lock);
- }
-}
-
-static uint64_t ioport_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- PCIQXLDevice *qxl = opaque;
-
- trace_qxl_io_read_unexpected(qxl->id);
- return 0xff;
-}
-
-static const MemoryRegionOps qxl_io_ops = {
- .read = ioport_read,
- .write = ioport_write,
- .valid = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
-};
-
-static void qxl_update_irq_bh(void *opaque)
-{
- PCIQXLDevice *d = opaque;
- qxl_update_irq(d);
-}
-
-static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
-{
- uint32_t old_pending;
- uint32_t le_events = cpu_to_le32(events);
-
- trace_qxl_send_events(d->id, events);
- if (!qemu_spice_display_is_running(&d->ssd)) {
- /* spice-server tracks guest running state and should not do this */
- fprintf(stderr, "%s: spice-server bug: guest stopped, ignoring\n",
- __func__);
- trace_qxl_send_events_vm_stopped(d->id, events);
- return;
- }
- old_pending = atomic_fetch_or(&d->ram->int_pending, le_events);
- if ((old_pending & le_events) == le_events) {
- return;
- }
- qemu_bh_schedule(d->update_irq);
-}
-
-/* graphics console */
-
-static void qxl_hw_update(void *opaque)
-{
- PCIQXLDevice *qxl = opaque;
-
- qxl_render_update(qxl);
-}
-
-static void qxl_dirty_surfaces(PCIQXLDevice *qxl)
-{
- uintptr_t vram_start;
- int i;
-
- if (qxl->mode != QXL_MODE_NATIVE && qxl->mode != QXL_MODE_COMPAT) {
- return;
- }
-
- /* dirty the primary surface */
- qxl_set_dirty(&qxl->vga.vram, qxl->shadow_rom.draw_area_offset,
- qxl->shadow_rom.surface0_area_size);
-
- vram_start = (uintptr_t)memory_region_get_ram_ptr(&qxl->vram_bar);
-
- /* dirty the off-screen surfaces */
- for (i = 0; i < qxl->ssd.num_surfaces; i++) {
- QXLSurfaceCmd *cmd;
- intptr_t surface_offset;
- int surface_size;
-
- if (qxl->guest_surfaces.cmds[i] == 0) {
- continue;
- }
-
- cmd = qxl_phys2virt(qxl, qxl->guest_surfaces.cmds[i],
- MEMSLOT_GROUP_GUEST);
- assert(cmd);
- assert(cmd->type == QXL_SURFACE_CMD_CREATE);
- surface_offset = (intptr_t)qxl_phys2virt(qxl,
- cmd->u.surface_create.data,
- MEMSLOT_GROUP_GUEST);
- assert(surface_offset);
- surface_offset -= vram_start;
- surface_size = cmd->u.surface_create.height *
- abs(cmd->u.surface_create.stride);
- trace_qxl_surfaces_dirty(qxl->id, i, (int)surface_offset, surface_size);
- qxl_set_dirty(&qxl->vram_bar, surface_offset, surface_size);
- }
-}
-
-static void qxl_vm_change_state_handler(void *opaque, int running,
- RunState state)
-{
- PCIQXLDevice *qxl = opaque;
-
- if (running) {
- /*
- * if qxl_send_events was called from spice server context before
- * migration ended, qxl_update_irq for these events might not have been
- * called
- */
- qxl_update_irq(qxl);
- } else {
- /* make sure surfaces are saved before migration */
- qxl_dirty_surfaces(qxl);
- }
-}
-
-/* display change listener */
-
-static void display_update(DisplayChangeListener *dcl,
- int x, int y, int w, int h)
-{
- PCIQXLDevice *qxl = container_of(dcl, PCIQXLDevice, ssd.dcl);
-
- if (qxl->mode == QXL_MODE_VGA) {
- qemu_spice_display_update(&qxl->ssd, x, y, w, h);
- }
-}
-
-static void display_switch(DisplayChangeListener *dcl,
- struct DisplaySurface *surface)
-{
- PCIQXLDevice *qxl = container_of(dcl, PCIQXLDevice, ssd.dcl);
-
- qxl->ssd.ds = surface;
- if (qxl->mode == QXL_MODE_VGA) {
- qemu_spice_display_switch(&qxl->ssd, surface);
- }
-}
-
-static void display_refresh(DisplayChangeListener *dcl)
-{
- PCIQXLDevice *qxl = container_of(dcl, PCIQXLDevice, ssd.dcl);
-
- if (qxl->mode == QXL_MODE_VGA) {
- qemu_spice_display_refresh(&qxl->ssd);
- }
-}
-
-static DisplayChangeListenerOps display_listener_ops = {
- .dpy_name = "spice/qxl",
- .dpy_gfx_update = display_update,
- .dpy_gfx_switch = display_switch,
- .dpy_refresh = display_refresh,
-};
-
-static void qxl_init_ramsize(PCIQXLDevice *qxl)
-{
- /* vga mode framebuffer / primary surface (bar 0, first part) */
- if (qxl->vgamem_size_mb < 8) {
- qxl->vgamem_size_mb = 8;
- }
- /* XXX: we round vgamem_size_mb up to a nearest power of two and it must be
- * less than vga_common_init()'s maximum on qxl->vga.vram_size (512 now).
- */
- if (qxl->vgamem_size_mb > 256) {
- qxl->vgamem_size_mb = 256;
- }
- qxl->vgamem_size = qxl->vgamem_size_mb * 1024 * 1024;
-
- /* vga ram (bar 0, total) */
- if (qxl->ram_size_mb != -1) {
- qxl->vga.vram_size = qxl->ram_size_mb * 1024 * 1024;
- }
- if (qxl->vga.vram_size < qxl->vgamem_size * 2) {
- qxl->vga.vram_size = qxl->vgamem_size * 2;
- }
-
- /* vram32 (surfaces, 32bit, bar 1) */
- if (qxl->vram32_size_mb != -1) {
- qxl->vram32_size = qxl->vram32_size_mb * 1024 * 1024;
- }
- if (qxl->vram32_size < 4096) {
- qxl->vram32_size = 4096;
- }
-
- /* vram (surfaces, 64bit, bar 4+5) */
- if (qxl->vram_size_mb != -1) {
- qxl->vram_size = qxl->vram_size_mb * 1024 * 1024;
- }
- if (qxl->vram_size < qxl->vram32_size) {
- qxl->vram_size = qxl->vram32_size;
- }
-
- if (qxl->revision == 1) {
- qxl->vram32_size = 4096;
- qxl->vram_size = 4096;
- }
- qxl->vgamem_size = pow2ceil(qxl->vgamem_size);
- qxl->vga.vram_size = pow2ceil(qxl->vga.vram_size);
- qxl->vram32_size = pow2ceil(qxl->vram32_size);
- qxl->vram_size = pow2ceil(qxl->vram_size);
-}
-
-static void qxl_realize_common(PCIQXLDevice *qxl, Error **errp)
-{
- uint8_t* config = qxl->pci.config;
- uint32_t pci_device_rev;
- uint32_t io_size;
-
- qxl->mode = QXL_MODE_UNDEFINED;
- qxl->generation = 1;
- qxl->num_memslots = NUM_MEMSLOTS;
- qemu_mutex_init(&qxl->track_lock);
- qemu_mutex_init(&qxl->async_lock);
- qxl->current_async = QXL_UNDEFINED_IO;
- qxl->guest_bug = 0;
-
- switch (qxl->revision) {
- case 1: /* spice 0.4 -- qxl-1 */
- pci_device_rev = QXL_REVISION_STABLE_V04;
- io_size = 8;
- break;
- case 2: /* spice 0.6 -- qxl-2 */
- pci_device_rev = QXL_REVISION_STABLE_V06;
- io_size = 16;
- break;
- case 3: /* qxl-3 */
- pci_device_rev = QXL_REVISION_STABLE_V10;
- io_size = 32; /* PCI region size must be pow2 */
- break;
- case 4: /* qxl-4 */
- pci_device_rev = QXL_REVISION_STABLE_V12;
- io_size = pow2ceil(QXL_IO_RANGE_SIZE);
- break;
- default:
- error_setg(errp, "Invalid revision %d for qxl device (max %d)",
- qxl->revision, QXL_DEFAULT_REVISION);
- return;
- }
-
- pci_set_byte(&config[PCI_REVISION_ID], pci_device_rev);
- pci_set_byte(&config[PCI_INTERRUPT_PIN], 1);
-
- qxl->rom_size = qxl_rom_size();
- memory_region_init_ram(&qxl->rom_bar, OBJECT(qxl), "qxl.vrom",
- qxl->rom_size, &error_fatal);
- vmstate_register_ram(&qxl->rom_bar, &qxl->pci.qdev);
- init_qxl_rom(qxl);
- init_qxl_ram(qxl);
-
- qxl->guest_surfaces.cmds = g_new0(QXLPHYSICAL, qxl->ssd.num_surfaces);
- memory_region_init_ram(&qxl->vram_bar, OBJECT(qxl), "qxl.vram",
- qxl->vram_size, &error_fatal);
- vmstate_register_ram(&qxl->vram_bar, &qxl->pci.qdev);
- memory_region_init_alias(&qxl->vram32_bar, OBJECT(qxl), "qxl.vram32",
- &qxl->vram_bar, 0, qxl->vram32_size);
-
- memory_region_init_io(&qxl->io_bar, OBJECT(qxl), &qxl_io_ops, qxl,
- "qxl-ioports", io_size);
- if (qxl->id == 0) {
- vga_dirty_log_start(&qxl->vga);
- }
- memory_region_set_flush_coalesced(&qxl->io_bar);
-
-
- pci_register_bar(&qxl->pci, QXL_IO_RANGE_INDEX,
- PCI_BASE_ADDRESS_SPACE_IO, &qxl->io_bar);
-
- pci_register_bar(&qxl->pci, QXL_ROM_RANGE_INDEX,
- PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->rom_bar);
-
- pci_register_bar(&qxl->pci, QXL_RAM_RANGE_INDEX,
- PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->vga.vram);
-
- pci_register_bar(&qxl->pci, QXL_VRAM_RANGE_INDEX,
- PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->vram32_bar);
-
- if (qxl->vram32_size < qxl->vram_size) {
- /*
- * Make the 64bit vram bar show up only in case it is
- * configured to be larger than the 32bit vram bar.
- */
- pci_register_bar(&qxl->pci, QXL_VRAM64_RANGE_INDEX,
- PCI_BASE_ADDRESS_SPACE_MEMORY |
- PCI_BASE_ADDRESS_MEM_TYPE_64 |
- PCI_BASE_ADDRESS_MEM_PREFETCH,
- &qxl->vram_bar);
- }
-
- /* print pci bar details */
- dprint(qxl, 1, "ram/%s: %d MB [region 0]\n",
- qxl->id == 0 ? "pri" : "sec",
- qxl->vga.vram_size / (1024*1024));
- dprint(qxl, 1, "vram/32: %d MB [region 1]\n",
- qxl->vram32_size / (1024*1024));
- dprint(qxl, 1, "vram/64: %d MB %s\n",
- qxl->vram_size / (1024*1024),
- qxl->vram32_size < qxl->vram_size ? "[region 4]" : "[unmapped]");
-
- qxl->ssd.qxl.base.sif = &qxl_interface.base;
- if (qemu_spice_add_display_interface(&qxl->ssd.qxl, qxl->vga.con) != 0) {
- error_setg(errp, "qxl interface %d.%d not supported by spice-server",
- SPICE_INTERFACE_QXL_MAJOR, SPICE_INTERFACE_QXL_MINOR);
- return;
- }
- qemu_add_vm_change_state_handler(qxl_vm_change_state_handler, qxl);
-
- qxl->update_irq = qemu_bh_new(qxl_update_irq_bh, qxl);
- qxl_reset_state(qxl);
-
- qxl->update_area_bh = qemu_bh_new(qxl_render_update_area_bh, qxl);
- qxl->ssd.cursor_bh = qemu_bh_new(qemu_spice_cursor_refresh_bh, &qxl->ssd);
-}
-
-static void qxl_realize_primary(PCIDevice *dev, Error **errp)
-{
- PCIQXLDevice *qxl = PCI_QXL(dev);
- VGACommonState *vga = &qxl->vga;
- Error *local_err = NULL;
-
- qxl->id = 0;
- qxl_init_ramsize(qxl);
- vga->vbe_size = qxl->vgamem_size;
- vga->vram_size_mb = qxl->vga.vram_size >> 20;
- vga_common_init(vga, OBJECT(dev), true);
- vga_init(vga, OBJECT(dev),
- pci_address_space(dev), pci_address_space_io(dev), false);
- portio_list_init(&qxl->vga_port_list, OBJECT(dev), qxl_vga_portio_list,
- vga, "vga");
- portio_list_set_flush_coalesced(&qxl->vga_port_list);
- portio_list_add(&qxl->vga_port_list, pci_address_space_io(dev), 0x3b0);
-
- vga->con = graphic_console_init(DEVICE(dev), 0, &qxl_ops, qxl);
- qemu_spice_display_init_common(&qxl->ssd);
-
- qxl_realize_common(qxl, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- qxl->ssd.dcl.ops = &display_listener_ops;
- qxl->ssd.dcl.con = vga->con;
- register_displaychangelistener(&qxl->ssd.dcl);
-}
-
-static void qxl_realize_secondary(PCIDevice *dev, Error **errp)
-{
- static int device_id = 1;
- PCIQXLDevice *qxl = PCI_QXL(dev);
-
- qxl->id = device_id++;
- qxl_init_ramsize(qxl);
- memory_region_init_ram(&qxl->vga.vram, OBJECT(dev), "qxl.vgavram",
- qxl->vga.vram_size, &error_fatal);
- vmstate_register_ram(&qxl->vga.vram, &qxl->pci.qdev);
- qxl->vga.vram_ptr = memory_region_get_ram_ptr(&qxl->vga.vram);
- qxl->vga.con = graphic_console_init(DEVICE(dev), 0, &qxl_ops, qxl);
-
- qxl_realize_common(qxl, errp);
-}
-
-static void qxl_pre_save(void *opaque)
-{
- PCIQXLDevice* d = opaque;
- uint8_t *ram_start = d->vga.vram_ptr;
-
- trace_qxl_pre_save(d->id);
- if (d->last_release == NULL) {
- d->last_release_offset = 0;
- } else {
- d->last_release_offset = (uint8_t *)d->last_release - ram_start;
- }
- assert(d->last_release_offset < d->vga.vram_size);
-}
-
-static int qxl_pre_load(void *opaque)
-{
- PCIQXLDevice* d = opaque;
-
- trace_qxl_pre_load(d->id);
- qxl_hard_reset(d, 1);
- qxl_exit_vga_mode(d);
- return 0;
-}
-
-static void qxl_create_memslots(PCIQXLDevice *d)
-{
- int i;
-
- for (i = 0; i < NUM_MEMSLOTS; i++) {
- if (!d->guest_slots[i].active) {
- continue;
- }
- qxl_add_memslot(d, i, 0, QXL_SYNC);
- }
-}
-
-static int qxl_post_load(void *opaque, int version)
-{
- PCIQXLDevice* d = opaque;
- uint8_t *ram_start = d->vga.vram_ptr;
- QXLCommandExt *cmds;
- int in, out, newmode;
-
- assert(d->last_release_offset < d->vga.vram_size);
- if (d->last_release_offset == 0) {
- d->last_release = NULL;
- } else {
- d->last_release = (QXLReleaseInfo *)(ram_start + d->last_release_offset);
- }
-
- d->modes = (QXLModes*)((uint8_t*)d->rom + d->rom->modes_offset);
-
- trace_qxl_post_load(d->id, qxl_mode_to_string(d->mode));
- newmode = d->mode;
- d->mode = QXL_MODE_UNDEFINED;
-
- switch (newmode) {
- case QXL_MODE_UNDEFINED:
- qxl_create_memslots(d);
- break;
- case QXL_MODE_VGA:
- qxl_create_memslots(d);
- qxl_enter_vga_mode(d);
- break;
- case QXL_MODE_NATIVE:
- qxl_create_memslots(d);
- qxl_create_guest_primary(d, 1, QXL_SYNC);
-
- /* replay surface-create and cursor-set commands */
- cmds = g_new0(QXLCommandExt, d->ssd.num_surfaces + 1);
- for (in = 0, out = 0; in < d->ssd.num_surfaces; in++) {
- if (d->guest_surfaces.cmds[in] == 0) {
- continue;
- }
- cmds[out].cmd.data = d->guest_surfaces.cmds[in];
- cmds[out].cmd.type = QXL_CMD_SURFACE;
- cmds[out].group_id = MEMSLOT_GROUP_GUEST;
- out++;
- }
- if (d->guest_cursor) {
- cmds[out].cmd.data = d->guest_cursor;
- cmds[out].cmd.type = QXL_CMD_CURSOR;
- cmds[out].group_id = MEMSLOT_GROUP_GUEST;
- out++;
- }
- qxl_spice_loadvm_commands(d, cmds, out);
- g_free(cmds);
- if (d->guest_monitors_config) {
- qxl_spice_monitors_config_async(d, 1);
- }
- break;
- case QXL_MODE_COMPAT:
- /* note: no need to call qxl_create_memslots, qxl_set_mode
- * creates the mem slot. */
- qxl_set_mode(d, d->shadow_rom.mode, 1);
- break;
- }
- return 0;
-}
-
-#define QXL_SAVE_VERSION 21
-
-static bool qxl_monitors_config_needed(void *opaque)
-{
- PCIQXLDevice *qxl = opaque;
-
- return qxl->guest_monitors_config != 0;
-}
-
-
-static VMStateDescription qxl_memslot = {
- .name = "qxl-memslot",
- .version_id = QXL_SAVE_VERSION,
- .minimum_version_id = QXL_SAVE_VERSION,
- .fields = (VMStateField[]) {
- VMSTATE_UINT64(slot.mem_start, struct guest_slots),
- VMSTATE_UINT64(slot.mem_end, struct guest_slots),
- VMSTATE_UINT32(active, struct guest_slots),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static VMStateDescription qxl_surface = {
- .name = "qxl-surface",
- .version_id = QXL_SAVE_VERSION,
- .minimum_version_id = QXL_SAVE_VERSION,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(width, QXLSurfaceCreate),
- VMSTATE_UINT32(height, QXLSurfaceCreate),
- VMSTATE_INT32(stride, QXLSurfaceCreate),
- VMSTATE_UINT32(format, QXLSurfaceCreate),
- VMSTATE_UINT32(position, QXLSurfaceCreate),
- VMSTATE_UINT32(mouse_mode, QXLSurfaceCreate),
- VMSTATE_UINT32(flags, QXLSurfaceCreate),
- VMSTATE_UINT32(type, QXLSurfaceCreate),
- VMSTATE_UINT64(mem, QXLSurfaceCreate),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static VMStateDescription qxl_vmstate_monitors_config = {
- .name = "qxl/monitors-config",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = qxl_monitors_config_needed,
- .fields = (VMStateField[]) {
- VMSTATE_UINT64(guest_monitors_config, PCIQXLDevice),
- VMSTATE_END_OF_LIST()
- },
-};
-
-static VMStateDescription qxl_vmstate = {
- .name = "qxl",
- .version_id = QXL_SAVE_VERSION,
- .minimum_version_id = QXL_SAVE_VERSION,
- .pre_save = qxl_pre_save,
- .pre_load = qxl_pre_load,
- .post_load = qxl_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(pci, PCIQXLDevice),
- VMSTATE_STRUCT(vga, PCIQXLDevice, 0, vmstate_vga_common, VGACommonState),
- VMSTATE_UINT32(shadow_rom.mode, PCIQXLDevice),
- VMSTATE_UINT32(num_free_res, PCIQXLDevice),
- VMSTATE_UINT32(last_release_offset, PCIQXLDevice),
- VMSTATE_UINT32(mode, PCIQXLDevice),
- VMSTATE_UINT32(ssd.unique, PCIQXLDevice),
- VMSTATE_INT32_EQUAL(num_memslots, PCIQXLDevice),
- VMSTATE_STRUCT_ARRAY(guest_slots, PCIQXLDevice, NUM_MEMSLOTS, 0,
- qxl_memslot, struct guest_slots),
- VMSTATE_STRUCT(guest_primary.surface, PCIQXLDevice, 0,
- qxl_surface, QXLSurfaceCreate),
- VMSTATE_INT32_EQUAL(ssd.num_surfaces, PCIQXLDevice),
- VMSTATE_VARRAY_INT32(guest_surfaces.cmds, PCIQXLDevice,
- ssd.num_surfaces, 0,
- vmstate_info_uint64, uint64_t),
- VMSTATE_UINT64(guest_cursor, PCIQXLDevice),
- VMSTATE_END_OF_LIST()
- },
- .subsections = (const VMStateDescription*[]) {
- &qxl_vmstate_monitors_config,
- NULL
- }
-};
-
-static Property qxl_properties[] = {
- DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size,
- 64 * 1024 * 1024),
- DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram32_size,
- 64 * 1024 * 1024),
- DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision,
- QXL_DEFAULT_REVISION),
- DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0),
- DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0),
- DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0),
- DEFINE_PROP_UINT32("ram_size_mb", PCIQXLDevice, ram_size_mb, -1),
- DEFINE_PROP_UINT32("vram_size_mb", PCIQXLDevice, vram32_size_mb, -1),
- DEFINE_PROP_UINT32("vram64_size_mb", PCIQXLDevice, vram_size_mb, -1),
- DEFINE_PROP_UINT32("vgamem_mb", PCIQXLDevice, vgamem_size_mb, 16),
- DEFINE_PROP_INT32("surfaces", PCIQXLDevice, ssd.num_surfaces, 1024),
-#if SPICE_SERVER_VERSION >= 0x000c06 /* release 0.12.6 */
- DEFINE_PROP_UINT16("max_outputs", PCIQXLDevice, max_outputs, 0),
-#endif
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void qxl_pci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->vendor_id = REDHAT_PCI_VENDOR_ID;
- k->device_id = QXL_DEVICE_ID_STABLE;
- set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
- dc->reset = qxl_reset_handler;
- dc->vmsd = &qxl_vmstate;
- dc->props = qxl_properties;
-}
-
-static const TypeInfo qxl_pci_type_info = {
- .name = TYPE_PCI_QXL,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(PCIQXLDevice),
- .abstract = true,
- .class_init = qxl_pci_class_init,
-};
-
-static void qxl_primary_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = qxl_realize_primary;
- k->romfile = "vgabios-qxl.bin";
- k->class_id = PCI_CLASS_DISPLAY_VGA;
- dc->desc = "Spice QXL GPU (primary, vga compatible)";
- dc->hotpluggable = false;
-}
-
-static const TypeInfo qxl_primary_info = {
- .name = "qxl-vga",
- .parent = TYPE_PCI_QXL,
- .class_init = qxl_primary_class_init,
-};
-
-static void qxl_secondary_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = qxl_realize_secondary;
- k->class_id = PCI_CLASS_DISPLAY_OTHER;
- dc->desc = "Spice QXL GPU (secondary)";
-}
-
-static const TypeInfo qxl_secondary_info = {
- .name = "qxl",
- .parent = TYPE_PCI_QXL,
- .class_init = qxl_secondary_class_init,
-};
-
-static void qxl_register_types(void)
-{
- type_register_static(&qxl_pci_type_info);
- type_register_static(&qxl_primary_info);
- type_register_static(&qxl_secondary_info);
-}
-
-type_init(qxl_register_types)
diff --git a/qemu/hw/display/qxl.h b/qemu/hw/display/qxl.h
deleted file mode 100644
index 2ddf065e1..000000000
--- a/qemu/hw/display/qxl.h
+++ /dev/null
@@ -1,174 +0,0 @@
-#ifndef HW_QXL_H
-#define HW_QXL_H 1
-
-#include "qemu-common.h"
-
-#include "ui/console.h"
-#include "hw/hw.h"
-#include "hw/pci/pci.h"
-#include "vga_int.h"
-#include "qemu/thread.h"
-
-#include "ui/qemu-spice.h"
-#include "ui/spice-display.h"
-
-enum qxl_mode {
- QXL_MODE_UNDEFINED,
- QXL_MODE_VGA,
- QXL_MODE_COMPAT, /* spice 0.4.x */
- QXL_MODE_NATIVE,
-};
-
-#ifndef QXL_VRAM64_RANGE_INDEX
-#define QXL_VRAM64_RANGE_INDEX 4
-#endif
-
-#define QXL_UNDEFINED_IO UINT32_MAX
-
-#define QXL_NUM_DIRTY_RECTS 64
-
-#define QXL_PAGE_BITS 12
-#define QXL_PAGE_SIZE (1 << QXL_PAGE_BITS);
-
-typedef struct PCIQXLDevice {
- PCIDevice pci;
- PortioList vga_port_list;
- SimpleSpiceDisplay ssd;
- int id;
- uint32_t debug;
- uint32_t guestdebug;
- uint32_t cmdlog;
-
- uint32_t guest_bug;
-
- enum qxl_mode mode;
- uint32_t cmdflags;
- int generation;
- uint32_t revision;
-
- int32_t num_memslots;
-
- uint32_t current_async;
- QemuMutex async_lock;
-
- struct guest_slots {
- QXLMemSlot slot;
- void *ptr;
- uint64_t size;
- uint64_t delta;
- uint32_t active;
- } guest_slots[NUM_MEMSLOTS];
-
- struct guest_primary {
- QXLSurfaceCreate surface;
- uint32_t commands;
- uint32_t resized;
- int32_t qxl_stride;
- uint32_t abs_stride;
- uint32_t bits_pp;
- uint32_t bytes_pp;
- uint8_t *data;
- } guest_primary;
-
- struct surfaces {
- QXLPHYSICAL *cmds;
- uint32_t count;
- uint32_t max;
- } guest_surfaces;
- QXLPHYSICAL guest_cursor;
-
- QXLPHYSICAL guest_monitors_config;
-
- QemuMutex track_lock;
-
- /* thread signaling */
- QEMUBH *update_irq;
-
- /* ram pci bar */
- QXLRam *ram;
- VGACommonState vga;
- uint32_t num_free_res;
- QXLReleaseInfo *last_release;
- uint32_t last_release_offset;
- uint32_t oom_running;
- uint32_t vgamem_size;
-
- /* rom pci bar */
- QXLRom shadow_rom;
- QXLRom *rom;
- QXLModes *modes;
- uint32_t rom_size;
- MemoryRegion rom_bar;
-#if SPICE_SERVER_VERSION >= 0x000c06 /* release 0.12.6 */
- uint16_t max_outputs;
-#endif
-
- /* vram pci bar */
- uint32_t vram_size;
- MemoryRegion vram_bar;
- uint32_t vram32_size;
- MemoryRegion vram32_bar;
-
- /* io bar */
- MemoryRegion io_bar;
-
- /* user-friendly properties (in megabytes) */
- uint32_t ram_size_mb;
- uint32_t vram_size_mb;
- uint32_t vram32_size_mb;
- uint32_t vgamem_size_mb;
-
- /* qxl_render_update state */
- int render_update_cookie_num;
- int num_dirty_rects;
- QXLRect dirty[QXL_NUM_DIRTY_RECTS];
- QEMUBH *update_area_bh;
-} PCIQXLDevice;
-
-#define TYPE_PCI_QXL "pci-qxl"
-#define PCI_QXL(obj) OBJECT_CHECK(PCIQXLDevice, (obj), TYPE_PCI_QXL)
-
-#define PANIC_ON(x) if ((x)) { \
- printf("%s: PANIC %s failed\n", __FUNCTION__, #x); \
- abort(); \
-}
-
-#define dprint(_qxl, _level, _fmt, ...) \
- do { \
- if (_qxl->debug >= _level) { \
- fprintf(stderr, "qxl-%d: ", _qxl->id); \
- fprintf(stderr, _fmt, ## __VA_ARGS__); \
- } \
- } while (0)
-
-#define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V12
-
-/* qxl.c */
-void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id);
-void qxl_set_guest_bug(PCIQXLDevice *qxl, const char *msg, ...)
- GCC_FMT_ATTR(2, 3);
-
-void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
- struct QXLRect *area, struct QXLRect *dirty_rects,
- uint32_t num_dirty_rects,
- uint32_t clear_dirty_region,
- qxl_async_io async, QXLCookie *cookie);
-void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext,
- uint32_t count);
-void qxl_spice_oom(PCIQXLDevice *qxl);
-void qxl_spice_reset_memslots(PCIQXLDevice *qxl);
-void qxl_spice_reset_image_cache(PCIQXLDevice *qxl);
-void qxl_spice_reset_cursor(PCIQXLDevice *qxl);
-
-/* qxl-logger.c */
-int qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id);
-int qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext);
-
-/* qxl-render.c */
-void qxl_render_resize(PCIQXLDevice *qxl);
-void qxl_render_update(PCIQXLDevice *qxl);
-int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext);
-void qxl_render_update_area_done(PCIQXLDevice *qxl, QXLCookie *cookie);
-void qxl_render_update_area_bh(void *opaque);
-
-#endif
diff --git a/qemu/hw/display/sm501.c b/qemu/hw/display/sm501.c
deleted file mode 100644
index 5f7101210..000000000
--- a/qemu/hw/display/sm501.c
+++ /dev/null
@@ -1,1458 +0,0 @@
-/*
- * QEMU SM501 Device
- *
- * Copyright (c) 2008 Shin-ichiro KAWASAKI
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/hw.h"
-#include "hw/char/serial.h"
-#include "ui/console.h"
-#include "hw/devices.h"
-#include "hw/sysbus.h"
-#include "qemu/range.h"
-#include "ui/pixel_ops.h"
-#include "exec/address-spaces.h"
-
-/*
- * Status: 2010/05/07
- * - Minimum implementation for Linux console : mmio regs and CRT layer.
- * - 2D grapihcs acceleration partially supported : only fill rectangle.
- *
- * TODO:
- * - Panel support
- * - Touch panel support
- * - USB support
- * - UART support
- * - More 2D graphics engine support
- * - Performance tuning
- */
-
-//#define DEBUG_SM501
-//#define DEBUG_BITBLT
-
-#ifdef DEBUG_SM501
-#define SM501_DPRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
-#else
-#define SM501_DPRINTF(fmt, ...) do {} while(0)
-#endif
-
-
-#define MMIO_BASE_OFFSET 0x3e00000
-
-/* SM501 register definitions taken from "linux/include/linux/sm501-regs.h" */
-
-/* System Configuration area */
-/* System config base */
-#define SM501_SYS_CONFIG (0x000000)
-
-/* config 1 */
-#define SM501_SYSTEM_CONTROL (0x000000)
-
-#define SM501_SYSCTRL_PANEL_TRISTATE (1<<0)
-#define SM501_SYSCTRL_MEM_TRISTATE (1<<1)
-#define SM501_SYSCTRL_CRT_TRISTATE (1<<2)
-
-#define SM501_SYSCTRL_PCI_SLAVE_BURST_MASK (3<<4)
-#define SM501_SYSCTRL_PCI_SLAVE_BURST_1 (0<<4)
-#define SM501_SYSCTRL_PCI_SLAVE_BURST_2 (1<<4)
-#define SM501_SYSCTRL_PCI_SLAVE_BURST_4 (2<<4)
-#define SM501_SYSCTRL_PCI_SLAVE_BURST_8 (3<<4)
-
-#define SM501_SYSCTRL_PCI_CLOCK_RUN_EN (1<<6)
-#define SM501_SYSCTRL_PCI_RETRY_DISABLE (1<<7)
-#define SM501_SYSCTRL_PCI_SUBSYS_LOCK (1<<11)
-#define SM501_SYSCTRL_PCI_BURST_READ_EN (1<<15)
-
-/* miscellaneous control */
-
-#define SM501_MISC_CONTROL (0x000004)
-
-#define SM501_MISC_BUS_SH (0x0)
-#define SM501_MISC_BUS_PCI (0x1)
-#define SM501_MISC_BUS_XSCALE (0x2)
-#define SM501_MISC_BUS_NEC (0x6)
-#define SM501_MISC_BUS_MASK (0x7)
-
-#define SM501_MISC_VR_62MB (1<<3)
-#define SM501_MISC_CDR_RESET (1<<7)
-#define SM501_MISC_USB_LB (1<<8)
-#define SM501_MISC_USB_SLAVE (1<<9)
-#define SM501_MISC_BL_1 (1<<10)
-#define SM501_MISC_MC (1<<11)
-#define SM501_MISC_DAC_POWER (1<<12)
-#define SM501_MISC_IRQ_INVERT (1<<16)
-#define SM501_MISC_SH (1<<17)
-
-#define SM501_MISC_HOLD_EMPTY (0<<18)
-#define SM501_MISC_HOLD_8 (1<<18)
-#define SM501_MISC_HOLD_16 (2<<18)
-#define SM501_MISC_HOLD_24 (3<<18)
-#define SM501_MISC_HOLD_32 (4<<18)
-#define SM501_MISC_HOLD_MASK (7<<18)
-
-#define SM501_MISC_FREQ_12 (1<<24)
-#define SM501_MISC_PNL_24BIT (1<<25)
-#define SM501_MISC_8051_LE (1<<26)
-
-
-
-#define SM501_GPIO31_0_CONTROL (0x000008)
-#define SM501_GPIO63_32_CONTROL (0x00000C)
-#define SM501_DRAM_CONTROL (0x000010)
-
-/* command list */
-#define SM501_ARBTRTN_CONTROL (0x000014)
-
-/* command list */
-#define SM501_COMMAND_LIST_STATUS (0x000024)
-
-/* interrupt debug */
-#define SM501_RAW_IRQ_STATUS (0x000028)
-#define SM501_RAW_IRQ_CLEAR (0x000028)
-#define SM501_IRQ_STATUS (0x00002C)
-#define SM501_IRQ_MASK (0x000030)
-#define SM501_DEBUG_CONTROL (0x000034)
-
-/* power management */
-#define SM501_POWERMODE_P2X_SRC (1<<29)
-#define SM501_POWERMODE_V2X_SRC (1<<20)
-#define SM501_POWERMODE_M_SRC (1<<12)
-#define SM501_POWERMODE_M1_SRC (1<<4)
-
-#define SM501_CURRENT_GATE (0x000038)
-#define SM501_CURRENT_CLOCK (0x00003C)
-#define SM501_POWER_MODE_0_GATE (0x000040)
-#define SM501_POWER_MODE_0_CLOCK (0x000044)
-#define SM501_POWER_MODE_1_GATE (0x000048)
-#define SM501_POWER_MODE_1_CLOCK (0x00004C)
-#define SM501_SLEEP_MODE_GATE (0x000050)
-#define SM501_POWER_MODE_CONTROL (0x000054)
-
-/* power gates for units within the 501 */
-#define SM501_GATE_HOST (0)
-#define SM501_GATE_MEMORY (1)
-#define SM501_GATE_DISPLAY (2)
-#define SM501_GATE_2D_ENGINE (3)
-#define SM501_GATE_CSC (4)
-#define SM501_GATE_ZVPORT (5)
-#define SM501_GATE_GPIO (6)
-#define SM501_GATE_UART0 (7)
-#define SM501_GATE_UART1 (8)
-#define SM501_GATE_SSP (10)
-#define SM501_GATE_USB_HOST (11)
-#define SM501_GATE_USB_GADGET (12)
-#define SM501_GATE_UCONTROLLER (17)
-#define SM501_GATE_AC97 (18)
-
-/* panel clock */
-#define SM501_CLOCK_P2XCLK (24)
-/* crt clock */
-#define SM501_CLOCK_V2XCLK (16)
-/* main clock */
-#define SM501_CLOCK_MCLK (8)
-/* SDRAM controller clock */
-#define SM501_CLOCK_M1XCLK (0)
-
-/* config 2 */
-#define SM501_PCI_MASTER_BASE (0x000058)
-#define SM501_ENDIAN_CONTROL (0x00005C)
-#define SM501_DEVICEID (0x000060)
-/* 0x050100A0 */
-
-#define SM501_DEVICEID_SM501 (0x05010000)
-#define SM501_DEVICEID_IDMASK (0xffff0000)
-#define SM501_DEVICEID_REVMASK (0x000000ff)
-
-#define SM501_PLLCLOCK_COUNT (0x000064)
-#define SM501_MISC_TIMING (0x000068)
-#define SM501_CURRENT_SDRAM_CLOCK (0x00006C)
-
-#define SM501_PROGRAMMABLE_PLL_CONTROL (0x000074)
-
-/* GPIO base */
-#define SM501_GPIO (0x010000)
-#define SM501_GPIO_DATA_LOW (0x00)
-#define SM501_GPIO_DATA_HIGH (0x04)
-#define SM501_GPIO_DDR_LOW (0x08)
-#define SM501_GPIO_DDR_HIGH (0x0C)
-#define SM501_GPIO_IRQ_SETUP (0x10)
-#define SM501_GPIO_IRQ_STATUS (0x14)
-#define SM501_GPIO_IRQ_RESET (0x14)
-
-/* I2C controller base */
-#define SM501_I2C (0x010040)
-#define SM501_I2C_BYTE_COUNT (0x00)
-#define SM501_I2C_CONTROL (0x01)
-#define SM501_I2C_STATUS (0x02)
-#define SM501_I2C_RESET (0x02)
-#define SM501_I2C_SLAVE_ADDRESS (0x03)
-#define SM501_I2C_DATA (0x04)
-
-/* SSP base */
-#define SM501_SSP (0x020000)
-
-/* Uart 0 base */
-#define SM501_UART0 (0x030000)
-
-/* Uart 1 base */
-#define SM501_UART1 (0x030020)
-
-/* USB host port base */
-#define SM501_USB_HOST (0x040000)
-
-/* USB slave/gadget base */
-#define SM501_USB_GADGET (0x060000)
-
-/* USB slave/gadget data port base */
-#define SM501_USB_GADGET_DATA (0x070000)
-
-/* Display controller/video engine base */
-#define SM501_DC (0x080000)
-
-/* common defines for the SM501 address registers */
-#define SM501_ADDR_FLIP (1<<31)
-#define SM501_ADDR_EXT (1<<27)
-#define SM501_ADDR_CS1 (1<<26)
-#define SM501_ADDR_MASK (0x3f << 26)
-
-#define SM501_FIFO_MASK (0x3 << 16)
-#define SM501_FIFO_1 (0x0 << 16)
-#define SM501_FIFO_3 (0x1 << 16)
-#define SM501_FIFO_7 (0x2 << 16)
-#define SM501_FIFO_11 (0x3 << 16)
-
-/* common registers for panel and the crt */
-#define SM501_OFF_DC_H_TOT (0x000)
-#define SM501_OFF_DC_V_TOT (0x008)
-#define SM501_OFF_DC_H_SYNC (0x004)
-#define SM501_OFF_DC_V_SYNC (0x00C)
-
-#define SM501_DC_PANEL_CONTROL (0x000)
-
-#define SM501_DC_PANEL_CONTROL_FPEN (1<<27)
-#define SM501_DC_PANEL_CONTROL_BIAS (1<<26)
-#define SM501_DC_PANEL_CONTROL_DATA (1<<25)
-#define SM501_DC_PANEL_CONTROL_VDD (1<<24)
-#define SM501_DC_PANEL_CONTROL_DP (1<<23)
-
-#define SM501_DC_PANEL_CONTROL_TFT_888 (0<<21)
-#define SM501_DC_PANEL_CONTROL_TFT_333 (1<<21)
-#define SM501_DC_PANEL_CONTROL_TFT_444 (2<<21)
-
-#define SM501_DC_PANEL_CONTROL_DE (1<<20)
-
-#define SM501_DC_PANEL_CONTROL_LCD_TFT (0<<18)
-#define SM501_DC_PANEL_CONTROL_LCD_STN8 (1<<18)
-#define SM501_DC_PANEL_CONTROL_LCD_STN12 (2<<18)
-
-#define SM501_DC_PANEL_CONTROL_CP (1<<14)
-#define SM501_DC_PANEL_CONTROL_VSP (1<<13)
-#define SM501_DC_PANEL_CONTROL_HSP (1<<12)
-#define SM501_DC_PANEL_CONTROL_CK (1<<9)
-#define SM501_DC_PANEL_CONTROL_TE (1<<8)
-#define SM501_DC_PANEL_CONTROL_VPD (1<<7)
-#define SM501_DC_PANEL_CONTROL_VP (1<<6)
-#define SM501_DC_PANEL_CONTROL_HPD (1<<5)
-#define SM501_DC_PANEL_CONTROL_HP (1<<4)
-#define SM501_DC_PANEL_CONTROL_GAMMA (1<<3)
-#define SM501_DC_PANEL_CONTROL_EN (1<<2)
-
-#define SM501_DC_PANEL_CONTROL_8BPP (0<<0)
-#define SM501_DC_PANEL_CONTROL_16BPP (1<<0)
-#define SM501_DC_PANEL_CONTROL_32BPP (2<<0)
-
-
-#define SM501_DC_PANEL_PANNING_CONTROL (0x004)
-#define SM501_DC_PANEL_COLOR_KEY (0x008)
-#define SM501_DC_PANEL_FB_ADDR (0x00C)
-#define SM501_DC_PANEL_FB_OFFSET (0x010)
-#define SM501_DC_PANEL_FB_WIDTH (0x014)
-#define SM501_DC_PANEL_FB_HEIGHT (0x018)
-#define SM501_DC_PANEL_TL_LOC (0x01C)
-#define SM501_DC_PANEL_BR_LOC (0x020)
-#define SM501_DC_PANEL_H_TOT (0x024)
-#define SM501_DC_PANEL_H_SYNC (0x028)
-#define SM501_DC_PANEL_V_TOT (0x02C)
-#define SM501_DC_PANEL_V_SYNC (0x030)
-#define SM501_DC_PANEL_CUR_LINE (0x034)
-
-#define SM501_DC_VIDEO_CONTROL (0x040)
-#define SM501_DC_VIDEO_FB0_ADDR (0x044)
-#define SM501_DC_VIDEO_FB_WIDTH (0x048)
-#define SM501_DC_VIDEO_FB0_LAST_ADDR (0x04C)
-#define SM501_DC_VIDEO_TL_LOC (0x050)
-#define SM501_DC_VIDEO_BR_LOC (0x054)
-#define SM501_DC_VIDEO_SCALE (0x058)
-#define SM501_DC_VIDEO_INIT_SCALE (0x05C)
-#define SM501_DC_VIDEO_YUV_CONSTANTS (0x060)
-#define SM501_DC_VIDEO_FB1_ADDR (0x064)
-#define SM501_DC_VIDEO_FB1_LAST_ADDR (0x068)
-
-#define SM501_DC_VIDEO_ALPHA_CONTROL (0x080)
-#define SM501_DC_VIDEO_ALPHA_FB_ADDR (0x084)
-#define SM501_DC_VIDEO_ALPHA_FB_OFFSET (0x088)
-#define SM501_DC_VIDEO_ALPHA_FB_LAST_ADDR (0x08C)
-#define SM501_DC_VIDEO_ALPHA_TL_LOC (0x090)
-#define SM501_DC_VIDEO_ALPHA_BR_LOC (0x094)
-#define SM501_DC_VIDEO_ALPHA_SCALE (0x098)
-#define SM501_DC_VIDEO_ALPHA_INIT_SCALE (0x09C)
-#define SM501_DC_VIDEO_ALPHA_CHROMA_KEY (0x0A0)
-#define SM501_DC_VIDEO_ALPHA_COLOR_LOOKUP (0x0A4)
-
-#define SM501_DC_PANEL_HWC_BASE (0x0F0)
-#define SM501_DC_PANEL_HWC_ADDR (0x0F0)
-#define SM501_DC_PANEL_HWC_LOC (0x0F4)
-#define SM501_DC_PANEL_HWC_COLOR_1_2 (0x0F8)
-#define SM501_DC_PANEL_HWC_COLOR_3 (0x0FC)
-
-#define SM501_HWC_EN (1<<31)
-
-#define SM501_OFF_HWC_ADDR (0x00)
-#define SM501_OFF_HWC_LOC (0x04)
-#define SM501_OFF_HWC_COLOR_1_2 (0x08)
-#define SM501_OFF_HWC_COLOR_3 (0x0C)
-
-#define SM501_DC_ALPHA_CONTROL (0x100)
-#define SM501_DC_ALPHA_FB_ADDR (0x104)
-#define SM501_DC_ALPHA_FB_OFFSET (0x108)
-#define SM501_DC_ALPHA_TL_LOC (0x10C)
-#define SM501_DC_ALPHA_BR_LOC (0x110)
-#define SM501_DC_ALPHA_CHROMA_KEY (0x114)
-#define SM501_DC_ALPHA_COLOR_LOOKUP (0x118)
-
-#define SM501_DC_CRT_CONTROL (0x200)
-
-#define SM501_DC_CRT_CONTROL_TVP (1<<15)
-#define SM501_DC_CRT_CONTROL_CP (1<<14)
-#define SM501_DC_CRT_CONTROL_VSP (1<<13)
-#define SM501_DC_CRT_CONTROL_HSP (1<<12)
-#define SM501_DC_CRT_CONTROL_VS (1<<11)
-#define SM501_DC_CRT_CONTROL_BLANK (1<<10)
-#define SM501_DC_CRT_CONTROL_SEL (1<<9)
-#define SM501_DC_CRT_CONTROL_TE (1<<8)
-#define SM501_DC_CRT_CONTROL_PIXEL_MASK (0xF << 4)
-#define SM501_DC_CRT_CONTROL_GAMMA (1<<3)
-#define SM501_DC_CRT_CONTROL_ENABLE (1<<2)
-
-#define SM501_DC_CRT_CONTROL_8BPP (0<<0)
-#define SM501_DC_CRT_CONTROL_16BPP (1<<0)
-#define SM501_DC_CRT_CONTROL_32BPP (2<<0)
-
-#define SM501_DC_CRT_FB_ADDR (0x204)
-#define SM501_DC_CRT_FB_OFFSET (0x208)
-#define SM501_DC_CRT_H_TOT (0x20C)
-#define SM501_DC_CRT_H_SYNC (0x210)
-#define SM501_DC_CRT_V_TOT (0x214)
-#define SM501_DC_CRT_V_SYNC (0x218)
-#define SM501_DC_CRT_SIGNATURE_ANALYZER (0x21C)
-#define SM501_DC_CRT_CUR_LINE (0x220)
-#define SM501_DC_CRT_MONITOR_DETECT (0x224)
-
-#define SM501_DC_CRT_HWC_BASE (0x230)
-#define SM501_DC_CRT_HWC_ADDR (0x230)
-#define SM501_DC_CRT_HWC_LOC (0x234)
-#define SM501_DC_CRT_HWC_COLOR_1_2 (0x238)
-#define SM501_DC_CRT_HWC_COLOR_3 (0x23C)
-
-#define SM501_DC_PANEL_PALETTE (0x400)
-
-#define SM501_DC_VIDEO_PALETTE (0x800)
-
-#define SM501_DC_CRT_PALETTE (0xC00)
-
-/* Zoom Video port base */
-#define SM501_ZVPORT (0x090000)
-
-/* AC97/I2S base */
-#define SM501_AC97 (0x0A0000)
-
-/* 8051 micro controller base */
-#define SM501_UCONTROLLER (0x0B0000)
-
-/* 8051 micro controller SRAM base */
-#define SM501_UCONTROLLER_SRAM (0x0C0000)
-
-/* DMA base */
-#define SM501_DMA (0x0D0000)
-
-/* 2d engine base */
-#define SM501_2D_ENGINE (0x100000)
-#define SM501_2D_SOURCE (0x00)
-#define SM501_2D_DESTINATION (0x04)
-#define SM501_2D_DIMENSION (0x08)
-#define SM501_2D_CONTROL (0x0C)
-#define SM501_2D_PITCH (0x10)
-#define SM501_2D_FOREGROUND (0x14)
-#define SM501_2D_BACKGROUND (0x18)
-#define SM501_2D_STRETCH (0x1C)
-#define SM501_2D_COLOR_COMPARE (0x20)
-#define SM501_2D_COLOR_COMPARE_MASK (0x24)
-#define SM501_2D_MASK (0x28)
-#define SM501_2D_CLIP_TL (0x2C)
-#define SM501_2D_CLIP_BR (0x30)
-#define SM501_2D_MONO_PATTERN_LOW (0x34)
-#define SM501_2D_MONO_PATTERN_HIGH (0x38)
-#define SM501_2D_WINDOW_WIDTH (0x3C)
-#define SM501_2D_SOURCE_BASE (0x40)
-#define SM501_2D_DESTINATION_BASE (0x44)
-#define SM501_2D_ALPHA (0x48)
-#define SM501_2D_WRAP (0x4C)
-#define SM501_2D_STATUS (0x50)
-
-#define SM501_CSC_Y_SOURCE_BASE (0xC8)
-#define SM501_CSC_CONSTANTS (0xCC)
-#define SM501_CSC_Y_SOURCE_X (0xD0)
-#define SM501_CSC_Y_SOURCE_Y (0xD4)
-#define SM501_CSC_U_SOURCE_BASE (0xD8)
-#define SM501_CSC_V_SOURCE_BASE (0xDC)
-#define SM501_CSC_SOURCE_DIMENSION (0xE0)
-#define SM501_CSC_SOURCE_PITCH (0xE4)
-#define SM501_CSC_DESTINATION (0xE8)
-#define SM501_CSC_DESTINATION_DIMENSION (0xEC)
-#define SM501_CSC_DESTINATION_PITCH (0xF0)
-#define SM501_CSC_SCALE_FACTOR (0xF4)
-#define SM501_CSC_DESTINATION_BASE (0xF8)
-#define SM501_CSC_CONTROL (0xFC)
-
-/* 2d engine data port base */
-#define SM501_2D_ENGINE_DATA (0x110000)
-
-/* end of register definitions */
-
-#define SM501_HWC_WIDTH (64)
-#define SM501_HWC_HEIGHT (64)
-
-/* SM501 local memory size taken from "linux/drivers/mfd/sm501.c" */
-static const uint32_t sm501_mem_local_size[] = {
- [0] = 4*1024*1024,
- [1] = 8*1024*1024,
- [2] = 16*1024*1024,
- [3] = 32*1024*1024,
- [4] = 64*1024*1024,
- [5] = 2*1024*1024,
-};
-#define get_local_mem_size(s) sm501_mem_local_size[(s)->local_mem_size_index]
-
-typedef struct SM501State {
- /* graphic console status */
- QemuConsole *con;
-
- /* status & internal resources */
- hwaddr base;
- uint32_t local_mem_size_index;
- uint8_t * local_mem;
- MemoryRegion local_mem_region;
- uint32_t last_width;
- uint32_t last_height;
-
- /* mmio registers */
- uint32_t system_control;
- uint32_t misc_control;
- uint32_t gpio_31_0_control;
- uint32_t gpio_63_32_control;
- uint32_t dram_control;
- uint32_t irq_mask;
- uint32_t misc_timing;
- uint32_t power_mode_control;
-
- uint32_t uart0_ier;
- uint32_t uart0_lcr;
- uint32_t uart0_mcr;
- uint32_t uart0_scr;
-
- uint8_t dc_palette[0x400 * 3];
-
- uint32_t dc_panel_control;
- uint32_t dc_panel_panning_control;
- uint32_t dc_panel_fb_addr;
- uint32_t dc_panel_fb_offset;
- uint32_t dc_panel_fb_width;
- uint32_t dc_panel_fb_height;
- uint32_t dc_panel_tl_location;
- uint32_t dc_panel_br_location;
- uint32_t dc_panel_h_total;
- uint32_t dc_panel_h_sync;
- uint32_t dc_panel_v_total;
- uint32_t dc_panel_v_sync;
-
- uint32_t dc_panel_hwc_addr;
- uint32_t dc_panel_hwc_location;
- uint32_t dc_panel_hwc_color_1_2;
- uint32_t dc_panel_hwc_color_3;
-
- uint32_t dc_crt_control;
- uint32_t dc_crt_fb_addr;
- uint32_t dc_crt_fb_offset;
- uint32_t dc_crt_h_total;
- uint32_t dc_crt_h_sync;
- uint32_t dc_crt_v_total;
- uint32_t dc_crt_v_sync;
-
- uint32_t dc_crt_hwc_addr;
- uint32_t dc_crt_hwc_location;
- uint32_t dc_crt_hwc_color_1_2;
- uint32_t dc_crt_hwc_color_3;
-
- uint32_t twoD_source;
- uint32_t twoD_destination;
- uint32_t twoD_dimension;
- uint32_t twoD_control;
- uint32_t twoD_pitch;
- uint32_t twoD_foreground;
- uint32_t twoD_stretch;
- uint32_t twoD_color_compare_mask;
- uint32_t twoD_mask;
- uint32_t twoD_window_width;
- uint32_t twoD_source_base;
- uint32_t twoD_destination_base;
-
-} SM501State;
-
-static uint32_t get_local_mem_size_index(uint32_t size)
-{
- uint32_t norm_size = 0;
- int i, index = 0;
-
- for (i = 0; i < ARRAY_SIZE(sm501_mem_local_size); i++) {
- uint32_t new_size = sm501_mem_local_size[i];
- if (new_size >= size) {
- if (norm_size == 0 || norm_size > new_size) {
- norm_size = new_size;
- index = i;
- }
- }
- }
-
- return index;
-}
-
-/**
- * Check the availability of hardware cursor.
- * @param crt 0 for PANEL, 1 for CRT.
- */
-static inline int is_hwc_enabled(SM501State *state, int crt)
-{
- uint32_t addr = crt ? state->dc_crt_hwc_addr : state->dc_panel_hwc_addr;
- return addr & 0x80000000;
-}
-
-/**
- * Get the address which holds cursor pattern data.
- * @param crt 0 for PANEL, 1 for CRT.
- */
-static inline uint32_t get_hwc_address(SM501State *state, int crt)
-{
- uint32_t addr = crt ? state->dc_crt_hwc_addr : state->dc_panel_hwc_addr;
- return (addr & 0x03FFFFF0)/* >> 4*/;
-}
-
-/**
- * Get the cursor position in y coordinate.
- * @param crt 0 for PANEL, 1 for CRT.
- */
-static inline uint32_t get_hwc_y(SM501State *state, int crt)
-{
- uint32_t location = crt ? state->dc_crt_hwc_location
- : state->dc_panel_hwc_location;
- return (location & 0x07FF0000) >> 16;
-}
-
-/**
- * Get the cursor position in x coordinate.
- * @param crt 0 for PANEL, 1 for CRT.
- */
-static inline uint32_t get_hwc_x(SM501State *state, int crt)
-{
- uint32_t location = crt ? state->dc_crt_hwc_location
- : state->dc_panel_hwc_location;
- return location & 0x000007FF;
-}
-
-/**
- * Get the cursor position in x coordinate.
- * @param crt 0 for PANEL, 1 for CRT.
- * @param index 0, 1, 2 or 3 which specifies color of corsor dot.
- */
-static inline uint16_t get_hwc_color(SM501State *state, int crt, int index)
-{
- uint32_t color_reg = 0;
- uint16_t color_565 = 0;
-
- if (index == 0) {
- return 0;
- }
-
- switch (index) {
- case 1:
- case 2:
- color_reg = crt ? state->dc_crt_hwc_color_1_2
- : state->dc_panel_hwc_color_1_2;
- break;
- case 3:
- color_reg = crt ? state->dc_crt_hwc_color_3
- : state->dc_panel_hwc_color_3;
- break;
- default:
- printf("invalid hw cursor color.\n");
- abort();
- }
-
- switch (index) {
- case 1:
- case 3:
- color_565 = (uint16_t)(color_reg & 0xFFFF);
- break;
- case 2:
- color_565 = (uint16_t)((color_reg >> 16) & 0xFFFF);
- break;
- }
- return color_565;
-}
-
-static int within_hwc_y_range(SM501State *state, int y, int crt)
-{
- int hwc_y = get_hwc_y(state, crt);
- return (hwc_y <= y && y < hwc_y + SM501_HWC_HEIGHT);
-}
-
-static void sm501_2d_operation(SM501State * s)
-{
- /* obtain operation parameters */
- int operation = (s->twoD_control >> 16) & 0x1f;
- int rtl = s->twoD_control & 0x8000000;
- int src_x = (s->twoD_source >> 16) & 0x01FFF;
- int src_y = s->twoD_source & 0xFFFF;
- int dst_x = (s->twoD_destination >> 16) & 0x01FFF;
- int dst_y = s->twoD_destination & 0xFFFF;
- int operation_width = (s->twoD_dimension >> 16) & 0x1FFF;
- int operation_height = s->twoD_dimension & 0xFFFF;
- uint32_t color = s->twoD_foreground;
- int format_flags = (s->twoD_stretch >> 20) & 0x3;
- int addressing = (s->twoD_stretch >> 16) & 0xF;
-
- /* get frame buffer info */
- uint8_t * src = s->local_mem + (s->twoD_source_base & 0x03FFFFFF);
- uint8_t * dst = s->local_mem + (s->twoD_destination_base & 0x03FFFFFF);
- int src_width = (s->dc_crt_h_total & 0x00000FFF) + 1;
- int dst_width = (s->dc_crt_h_total & 0x00000FFF) + 1;
-
- if (addressing != 0x0) {
- printf("%s: only XY addressing is supported.\n", __func__);
- abort();
- }
-
- if ((s->twoD_source_base & 0x08000000) ||
- (s->twoD_destination_base & 0x08000000)) {
- printf("%s: only local memory is supported.\n", __func__);
- abort();
- }
-
- switch (operation) {
- case 0x00: /* copy area */
-#define COPY_AREA(_bpp, _pixel_type, rtl) { \
- int y, x, index_d, index_s; \
- for (y = 0; y < operation_height; y++) { \
- for (x = 0; x < operation_width; x++) { \
- if (rtl) { \
- index_s = ((src_y - y) * src_width + src_x - x) * _bpp; \
- index_d = ((dst_y - y) * dst_width + dst_x - x) * _bpp; \
- } else { \
- index_s = ((src_y + y) * src_width + src_x + x) * _bpp; \
- index_d = ((dst_y + y) * dst_width + dst_x + x) * _bpp; \
- } \
- *(_pixel_type*)&dst[index_d] = *(_pixel_type*)&src[index_s];\
- } \
- } \
- }
- switch (format_flags) {
- case 0:
- COPY_AREA(1, uint8_t, rtl);
- break;
- case 1:
- COPY_AREA(2, uint16_t, rtl);
- break;
- case 2:
- COPY_AREA(4, uint32_t, rtl);
- break;
- }
- break;
-
- case 0x01: /* fill rectangle */
-#define FILL_RECT(_bpp, _pixel_type) { \
- int y, x; \
- for (y = 0; y < operation_height; y++) { \
- for (x = 0; x < operation_width; x++) { \
- int index = ((dst_y + y) * dst_width + dst_x + x) * _bpp; \
- *(_pixel_type*)&dst[index] = (_pixel_type)color; \
- } \
- } \
- }
-
- switch (format_flags) {
- case 0:
- FILL_RECT(1, uint8_t);
- break;
- case 1:
- FILL_RECT(2, uint16_t);
- break;
- case 2:
- FILL_RECT(4, uint32_t);
- break;
- }
- break;
-
- default:
- printf("non-implemented SM501 2D operation. %d\n", operation);
- abort();
- break;
- }
-}
-
-static uint64_t sm501_system_config_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- SM501State * s = (SM501State *)opaque;
- uint32_t ret = 0;
- SM501_DPRINTF("sm501 system config regs : read addr=%x\n", (int)addr);
-
- switch(addr) {
- case SM501_SYSTEM_CONTROL:
- ret = s->system_control;
- break;
- case SM501_MISC_CONTROL:
- ret = s->misc_control;
- break;
- case SM501_GPIO31_0_CONTROL:
- ret = s->gpio_31_0_control;
- break;
- case SM501_GPIO63_32_CONTROL:
- ret = s->gpio_63_32_control;
- break;
- case SM501_DEVICEID:
- ret = 0x050100A0;
- break;
- case SM501_DRAM_CONTROL:
- ret = (s->dram_control & 0x07F107C0) | s->local_mem_size_index << 13;
- break;
- case SM501_IRQ_MASK:
- ret = s->irq_mask;
- break;
- case SM501_MISC_TIMING:
- /* TODO : simulate gate control */
- ret = s->misc_timing;
- break;
- case SM501_CURRENT_GATE:
- /* TODO : simulate gate control */
- ret = 0x00021807;
- break;
- case SM501_CURRENT_CLOCK:
- ret = 0x2A1A0A09;
- break;
- case SM501_POWER_MODE_CONTROL:
- ret = s->power_mode_control;
- break;
-
- default:
- printf("sm501 system config : not implemented register read."
- " addr=%x\n", (int)addr);
- abort();
- }
-
- return ret;
-}
-
-static void sm501_system_config_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- SM501State * s = (SM501State *)opaque;
- SM501_DPRINTF("sm501 system config regs : write addr=%x, val=%x\n",
- (uint32_t)addr, (uint32_t)value);
-
- switch(addr) {
- case SM501_SYSTEM_CONTROL:
- s->system_control = value & 0xE300B8F7;
- break;
- case SM501_MISC_CONTROL:
- s->misc_control = value & 0xFF7FFF20;
- break;
- case SM501_GPIO31_0_CONTROL:
- s->gpio_31_0_control = value;
- break;
- case SM501_GPIO63_32_CONTROL:
- s->gpio_63_32_control = value;
- break;
- case SM501_DRAM_CONTROL:
- s->local_mem_size_index = (value >> 13) & 0x7;
- /* rODO : check validity of size change */
- s->dram_control |= value & 0x7FFFFFC3;
- break;
- case SM501_IRQ_MASK:
- s->irq_mask = value;
- break;
- case SM501_MISC_TIMING:
- s->misc_timing = value & 0xF31F1FFF;
- break;
- case SM501_POWER_MODE_0_GATE:
- case SM501_POWER_MODE_1_GATE:
- case SM501_POWER_MODE_0_CLOCK:
- case SM501_POWER_MODE_1_CLOCK:
- /* TODO : simulate gate & clock control */
- break;
- case SM501_POWER_MODE_CONTROL:
- s->power_mode_control = value & 0x00000003;
- break;
-
- default:
- printf("sm501 system config : not implemented register write."
- " addr=%x, val=%x\n", (int)addr, (uint32_t)value);
- abort();
- }
-}
-
-static const MemoryRegionOps sm501_system_config_ops = {
- .read = sm501_system_config_read,
- .write = sm501_system_config_write,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static uint32_t sm501_palette_read(void *opaque, hwaddr addr)
-{
- SM501State * s = (SM501State *)opaque;
- SM501_DPRINTF("sm501 palette read addr=%x\n", (int)addr);
-
- /* TODO : consider BYTE/WORD access */
- /* TODO : consider endian */
-
- assert(range_covers_byte(0, 0x400 * 3, addr));
- return *(uint32_t*)&s->dc_palette[addr];
-}
-
-static void sm501_palette_write(void *opaque,
- hwaddr addr, uint32_t value)
-{
- SM501State * s = (SM501State *)opaque;
- SM501_DPRINTF("sm501 palette write addr=%x, val=%x\n",
- (int)addr, value);
-
- /* TODO : consider BYTE/WORD access */
- /* TODO : consider endian */
-
- assert(range_covers_byte(0, 0x400 * 3, addr));
- *(uint32_t*)&s->dc_palette[addr] = value;
-}
-
-static uint64_t sm501_disp_ctrl_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- SM501State * s = (SM501State *)opaque;
- uint32_t ret = 0;
- SM501_DPRINTF("sm501 disp ctrl regs : read addr=%x\n", (int)addr);
-
- switch(addr) {
-
- case SM501_DC_PANEL_CONTROL:
- ret = s->dc_panel_control;
- break;
- case SM501_DC_PANEL_PANNING_CONTROL:
- ret = s->dc_panel_panning_control;
- break;
- case SM501_DC_PANEL_FB_ADDR:
- ret = s->dc_panel_fb_addr;
- break;
- case SM501_DC_PANEL_FB_OFFSET:
- ret = s->dc_panel_fb_offset;
- break;
- case SM501_DC_PANEL_FB_WIDTH:
- ret = s->dc_panel_fb_width;
- break;
- case SM501_DC_PANEL_FB_HEIGHT:
- ret = s->dc_panel_fb_height;
- break;
- case SM501_DC_PANEL_TL_LOC:
- ret = s->dc_panel_tl_location;
- break;
- case SM501_DC_PANEL_BR_LOC:
- ret = s->dc_panel_br_location;
- break;
-
- case SM501_DC_PANEL_H_TOT:
- ret = s->dc_panel_h_total;
- break;
- case SM501_DC_PANEL_H_SYNC:
- ret = s->dc_panel_h_sync;
- break;
- case SM501_DC_PANEL_V_TOT:
- ret = s->dc_panel_v_total;
- break;
- case SM501_DC_PANEL_V_SYNC:
- ret = s->dc_panel_v_sync;
- break;
-
- case SM501_DC_CRT_CONTROL:
- ret = s->dc_crt_control;
- break;
- case SM501_DC_CRT_FB_ADDR:
- ret = s->dc_crt_fb_addr;
- break;
- case SM501_DC_CRT_FB_OFFSET:
- ret = s->dc_crt_fb_offset;
- break;
- case SM501_DC_CRT_H_TOT:
- ret = s->dc_crt_h_total;
- break;
- case SM501_DC_CRT_H_SYNC:
- ret = s->dc_crt_h_sync;
- break;
- case SM501_DC_CRT_V_TOT:
- ret = s->dc_crt_v_total;
- break;
- case SM501_DC_CRT_V_SYNC:
- ret = s->dc_crt_v_sync;
- break;
-
- case SM501_DC_CRT_HWC_ADDR:
- ret = s->dc_crt_hwc_addr;
- break;
- case SM501_DC_CRT_HWC_LOC:
- ret = s->dc_crt_hwc_location;
- break;
- case SM501_DC_CRT_HWC_COLOR_1_2:
- ret = s->dc_crt_hwc_color_1_2;
- break;
- case SM501_DC_CRT_HWC_COLOR_3:
- ret = s->dc_crt_hwc_color_3;
- break;
-
- case SM501_DC_PANEL_PALETTE ... SM501_DC_PANEL_PALETTE + 0x400*3 - 4:
- ret = sm501_palette_read(opaque, addr - SM501_DC_PANEL_PALETTE);
- break;
-
- default:
- printf("sm501 disp ctrl : not implemented register read."
- " addr=%x\n", (int)addr);
- abort();
- }
-
- return ret;
-}
-
-static void sm501_disp_ctrl_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- SM501State * s = (SM501State *)opaque;
- SM501_DPRINTF("sm501 disp ctrl regs : write addr=%x, val=%x\n",
- (unsigned)addr, (unsigned)value);
-
- switch(addr) {
- case SM501_DC_PANEL_CONTROL:
- s->dc_panel_control = value & 0x0FFF73FF;
- break;
- case SM501_DC_PANEL_PANNING_CONTROL:
- s->dc_panel_panning_control = value & 0xFF3FFF3F;
- break;
- case SM501_DC_PANEL_FB_ADDR:
- s->dc_panel_fb_addr = value & 0x8FFFFFF0;
- break;
- case SM501_DC_PANEL_FB_OFFSET:
- s->dc_panel_fb_offset = value & 0x3FF03FF0;
- break;
- case SM501_DC_PANEL_FB_WIDTH:
- s->dc_panel_fb_width = value & 0x0FFF0FFF;
- break;
- case SM501_DC_PANEL_FB_HEIGHT:
- s->dc_panel_fb_height = value & 0x0FFF0FFF;
- break;
- case SM501_DC_PANEL_TL_LOC:
- s->dc_panel_tl_location = value & 0x07FF07FF;
- break;
- case SM501_DC_PANEL_BR_LOC:
- s->dc_panel_br_location = value & 0x07FF07FF;
- break;
-
- case SM501_DC_PANEL_H_TOT:
- s->dc_panel_h_total = value & 0x0FFF0FFF;
- break;
- case SM501_DC_PANEL_H_SYNC:
- s->dc_panel_h_sync = value & 0x00FF0FFF;
- break;
- case SM501_DC_PANEL_V_TOT:
- s->dc_panel_v_total = value & 0x0FFF0FFF;
- break;
- case SM501_DC_PANEL_V_SYNC:
- s->dc_panel_v_sync = value & 0x003F0FFF;
- break;
-
- case SM501_DC_PANEL_HWC_ADDR:
- s->dc_panel_hwc_addr = value & 0x8FFFFFF0;
- break;
- case SM501_DC_PANEL_HWC_LOC:
- s->dc_panel_hwc_location = value & 0x0FFF0FFF;
- break;
- case SM501_DC_PANEL_HWC_COLOR_1_2:
- s->dc_panel_hwc_color_1_2 = value;
- break;
- case SM501_DC_PANEL_HWC_COLOR_3:
- s->dc_panel_hwc_color_3 = value & 0x0000FFFF;
- break;
-
- case SM501_DC_CRT_CONTROL:
- s->dc_crt_control = value & 0x0003FFFF;
- break;
- case SM501_DC_CRT_FB_ADDR:
- s->dc_crt_fb_addr = value & 0x8FFFFFF0;
- break;
- case SM501_DC_CRT_FB_OFFSET:
- s->dc_crt_fb_offset = value & 0x3FF03FF0;
- break;
- case SM501_DC_CRT_H_TOT:
- s->dc_crt_h_total = value & 0x0FFF0FFF;
- break;
- case SM501_DC_CRT_H_SYNC:
- s->dc_crt_h_sync = value & 0x00FF0FFF;
- break;
- case SM501_DC_CRT_V_TOT:
- s->dc_crt_v_total = value & 0x0FFF0FFF;
- break;
- case SM501_DC_CRT_V_SYNC:
- s->dc_crt_v_sync = value & 0x003F0FFF;
- break;
-
- case SM501_DC_CRT_HWC_ADDR:
- s->dc_crt_hwc_addr = value & 0x8FFFFFF0;
- break;
- case SM501_DC_CRT_HWC_LOC:
- s->dc_crt_hwc_location = value & 0x0FFF0FFF;
- break;
- case SM501_DC_CRT_HWC_COLOR_1_2:
- s->dc_crt_hwc_color_1_2 = value;
- break;
- case SM501_DC_CRT_HWC_COLOR_3:
- s->dc_crt_hwc_color_3 = value & 0x0000FFFF;
- break;
-
- case SM501_DC_PANEL_PALETTE ... SM501_DC_PANEL_PALETTE + 0x400*3 - 4:
- sm501_palette_write(opaque, addr - SM501_DC_PANEL_PALETTE, value);
- break;
-
- default:
- printf("sm501 disp ctrl : not implemented register write."
- " addr=%x, val=%x\n", (int)addr, (unsigned)value);
- abort();
- }
-}
-
-static const MemoryRegionOps sm501_disp_ctrl_ops = {
- .read = sm501_disp_ctrl_read,
- .write = sm501_disp_ctrl_write,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static uint64_t sm501_2d_engine_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- SM501State * s = (SM501State *)opaque;
- uint32_t ret = 0;
- SM501_DPRINTF("sm501 2d engine regs : read addr=%x\n", (int)addr);
-
- switch(addr) {
- case SM501_2D_SOURCE_BASE:
- ret = s->twoD_source_base;
- break;
- default:
- printf("sm501 disp ctrl : not implemented register read."
- " addr=%x\n", (int)addr);
- abort();
- }
-
- return ret;
-}
-
-static void sm501_2d_engine_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- SM501State * s = (SM501State *)opaque;
- SM501_DPRINTF("sm501 2d engine regs : write addr=%x, val=%x\n",
- (unsigned)addr, (unsigned)value);
-
- switch(addr) {
- case SM501_2D_SOURCE:
- s->twoD_source = value;
- break;
- case SM501_2D_DESTINATION:
- s->twoD_destination = value;
- break;
- case SM501_2D_DIMENSION:
- s->twoD_dimension = value;
- break;
- case SM501_2D_CONTROL:
- s->twoD_control = value;
-
- /* do 2d operation if start flag is set. */
- if (value & 0x80000000) {
- sm501_2d_operation(s);
- s->twoD_control &= ~0x80000000; /* start flag down */
- }
-
- break;
- case SM501_2D_PITCH:
- s->twoD_pitch = value;
- break;
- case SM501_2D_FOREGROUND:
- s->twoD_foreground = value;
- break;
- case SM501_2D_STRETCH:
- s->twoD_stretch = value;
- break;
- case SM501_2D_COLOR_COMPARE_MASK:
- s->twoD_color_compare_mask = value;
- break;
- case SM501_2D_MASK:
- s->twoD_mask = value;
- break;
- case SM501_2D_WINDOW_WIDTH:
- s->twoD_window_width = value;
- break;
- case SM501_2D_SOURCE_BASE:
- s->twoD_source_base = value;
- break;
- case SM501_2D_DESTINATION_BASE:
- s->twoD_destination_base = value;
- break;
- default:
- printf("sm501 2d engine : not implemented register write."
- " addr=%x, val=%x\n", (int)addr, (unsigned)value);
- abort();
- }
-}
-
-static const MemoryRegionOps sm501_2d_engine_ops = {
- .read = sm501_2d_engine_read,
- .write = sm501_2d_engine_write,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-/* draw line functions for all console modes */
-
-typedef void draw_line_func(uint8_t *d, const uint8_t *s,
- int width, const uint32_t *pal);
-
-typedef void draw_hwc_line_func(SM501State * s, int crt, uint8_t * palette,
- int c_y, uint8_t *d, int width);
-
-#define DEPTH 8
-#include "sm501_template.h"
-
-#define DEPTH 15
-#include "sm501_template.h"
-
-#define BGR_FORMAT
-#define DEPTH 15
-#include "sm501_template.h"
-
-#define DEPTH 16
-#include "sm501_template.h"
-
-#define BGR_FORMAT
-#define DEPTH 16
-#include "sm501_template.h"
-
-#define DEPTH 32
-#include "sm501_template.h"
-
-#define BGR_FORMAT
-#define DEPTH 32
-#include "sm501_template.h"
-
-static draw_line_func * draw_line8_funcs[] = {
- draw_line8_8,
- draw_line8_15,
- draw_line8_16,
- draw_line8_32,
- draw_line8_32bgr,
- draw_line8_15bgr,
- draw_line8_16bgr,
-};
-
-static draw_line_func * draw_line16_funcs[] = {
- draw_line16_8,
- draw_line16_15,
- draw_line16_16,
- draw_line16_32,
- draw_line16_32bgr,
- draw_line16_15bgr,
- draw_line16_16bgr,
-};
-
-static draw_line_func * draw_line32_funcs[] = {
- draw_line32_8,
- draw_line32_15,
- draw_line32_16,
- draw_line32_32,
- draw_line32_32bgr,
- draw_line32_15bgr,
- draw_line32_16bgr,
-};
-
-static draw_hwc_line_func * draw_hwc_line_funcs[] = {
- draw_hwc_line_8,
- draw_hwc_line_15,
- draw_hwc_line_16,
- draw_hwc_line_32,
- draw_hwc_line_32bgr,
- draw_hwc_line_15bgr,
- draw_hwc_line_16bgr,
-};
-
-static inline int get_depth_index(DisplaySurface *surface)
-{
- switch (surface_bits_per_pixel(surface)) {
- default:
- case 8:
- return 0;
- case 15:
- return 1;
- case 16:
- return 2;
- case 32:
- if (is_surface_bgr(surface)) {
- return 4;
- } else {
- return 3;
- }
- }
-}
-
-static void sm501_draw_crt(SM501State * s)
-{
- DisplaySurface *surface = qemu_console_surface(s->con);
- int y;
- int width = (s->dc_crt_h_total & 0x00000FFF) + 1;
- int height = (s->dc_crt_v_total & 0x00000FFF) + 1;
-
- uint8_t * src = s->local_mem;
- int src_bpp = 0;
- int dst_bpp = surface_bytes_per_pixel(surface);
- uint32_t * palette = (uint32_t *)&s->dc_palette[SM501_DC_CRT_PALETTE
- - SM501_DC_PANEL_PALETTE];
- uint8_t hwc_palette[3 * 3];
- int ds_depth_index = get_depth_index(surface);
- draw_line_func * draw_line = NULL;
- draw_hwc_line_func * draw_hwc_line = NULL;
- int full_update = 0;
- int y_start = -1;
- ram_addr_t page_min = ~0l;
- ram_addr_t page_max = 0l;
- ram_addr_t offset = 0;
-
- /* choose draw_line function */
- switch (s->dc_crt_control & 3) {
- case SM501_DC_CRT_CONTROL_8BPP:
- src_bpp = 1;
- draw_line = draw_line8_funcs[ds_depth_index];
- break;
- case SM501_DC_CRT_CONTROL_16BPP:
- src_bpp = 2;
- draw_line = draw_line16_funcs[ds_depth_index];
- break;
- case SM501_DC_CRT_CONTROL_32BPP:
- src_bpp = 4;
- draw_line = draw_line32_funcs[ds_depth_index];
- break;
- default:
- printf("sm501 draw crt : invalid DC_CRT_CONTROL=%x.\n",
- s->dc_crt_control);
- abort();
- break;
- }
-
- /* set up to draw hardware cursor */
- if (is_hwc_enabled(s, 1)) {
- int i;
-
- /* get cursor palette */
- for (i = 0; i < 3; i++) {
- uint16_t rgb565 = get_hwc_color(s, 1, i + 1);
- hwc_palette[i * 3 + 0] = (rgb565 & 0xf800) >> 8; /* red */
- hwc_palette[i * 3 + 1] = (rgb565 & 0x07e0) >> 3; /* green */
- hwc_palette[i * 3 + 2] = (rgb565 & 0x001f) << 3; /* blue */
- }
-
- /* choose cursor draw line function */
- draw_hwc_line = draw_hwc_line_funcs[ds_depth_index];
- }
-
- /* adjust console size */
- if (s->last_width != width || s->last_height != height) {
- qemu_console_resize(s->con, width, height);
- surface = qemu_console_surface(s->con);
- s->last_width = width;
- s->last_height = height;
- full_update = 1;
- }
-
- /* draw each line according to conditions */
- memory_region_sync_dirty_bitmap(&s->local_mem_region);
- for (y = 0; y < height; y++) {
- int update_hwc = draw_hwc_line ? within_hwc_y_range(s, y, 1) : 0;
- int update = full_update || update_hwc;
- ram_addr_t page0 = offset;
- ram_addr_t page1 = offset + width * src_bpp - 1;
-
- /* check dirty flags for each line */
- update = memory_region_get_dirty(&s->local_mem_region, page0,
- page1 - page0, DIRTY_MEMORY_VGA);
-
- /* draw line and change status */
- if (update) {
- uint8_t *d = surface_data(surface);
- d += y * width * dst_bpp;
-
- /* draw graphics layer */
- draw_line(d, src, width, palette);
-
- /* draw haredware cursor */
- if (update_hwc) {
- draw_hwc_line(s, 1, hwc_palette, y - get_hwc_y(s, 1), d, width);
- }
-
- if (y_start < 0)
- y_start = y;
- if (page0 < page_min)
- page_min = page0;
- if (page1 > page_max)
- page_max = page1;
- } else {
- if (y_start >= 0) {
- /* flush to display */
- dpy_gfx_update(s->con, 0, y_start, width, y - y_start);
- y_start = -1;
- }
- }
-
- src += width * src_bpp;
- offset += width * src_bpp;
- }
-
- /* complete flush to display */
- if (y_start >= 0)
- dpy_gfx_update(s->con, 0, y_start, width, y - y_start);
-
- /* clear dirty flags */
- if (page_min != ~0l) {
- memory_region_reset_dirty(&s->local_mem_region,
- page_min, page_max + TARGET_PAGE_SIZE,
- DIRTY_MEMORY_VGA);
- }
-}
-
-static void sm501_update_display(void *opaque)
-{
- SM501State * s = (SM501State *)opaque;
-
- if (s->dc_crt_control & SM501_DC_CRT_CONTROL_ENABLE)
- sm501_draw_crt(s);
-}
-
-static const GraphicHwOps sm501_ops = {
- .gfx_update = sm501_update_display,
-};
-
-void sm501_init(MemoryRegion *address_space_mem, uint32_t base,
- uint32_t local_mem_bytes, qemu_irq irq, CharDriverState *chr)
-{
- SM501State * s;
- DeviceState *dev;
- MemoryRegion *sm501_system_config = g_new(MemoryRegion, 1);
- MemoryRegion *sm501_disp_ctrl = g_new(MemoryRegion, 1);
- MemoryRegion *sm501_2d_engine = g_new(MemoryRegion, 1);
-
- /* allocate management data region */
- s = (SM501State *)g_malloc0(sizeof(SM501State));
- s->base = base;
- s->local_mem_size_index
- = get_local_mem_size_index(local_mem_bytes);
- SM501_DPRINTF("local mem size=%x. index=%d\n", get_local_mem_size(s),
- s->local_mem_size_index);
- s->system_control = 0x00100000;
- s->misc_control = 0x00001000; /* assumes SH, active=low */
- s->dc_panel_control = 0x00010000;
- s->dc_crt_control = 0x00010000;
-
- /* allocate local memory */
- memory_region_init_ram(&s->local_mem_region, NULL, "sm501.local",
- local_mem_bytes, &error_fatal);
- vmstate_register_ram_global(&s->local_mem_region);
- memory_region_set_log(&s->local_mem_region, true, DIRTY_MEMORY_VGA);
- s->local_mem = memory_region_get_ram_ptr(&s->local_mem_region);
- memory_region_add_subregion(address_space_mem, base, &s->local_mem_region);
-
- /* map mmio */
- memory_region_init_io(sm501_system_config, NULL, &sm501_system_config_ops, s,
- "sm501-system-config", 0x6c);
- memory_region_add_subregion(address_space_mem, base + MMIO_BASE_OFFSET,
- sm501_system_config);
- memory_region_init_io(sm501_disp_ctrl, NULL, &sm501_disp_ctrl_ops, s,
- "sm501-disp-ctrl", 0x1000);
- memory_region_add_subregion(address_space_mem,
- base + MMIO_BASE_OFFSET + SM501_DC,
- sm501_disp_ctrl);
- memory_region_init_io(sm501_2d_engine, NULL, &sm501_2d_engine_ops, s,
- "sm501-2d-engine", 0x54);
- memory_region_add_subregion(address_space_mem,
- base + MMIO_BASE_OFFSET + SM501_2D_ENGINE,
- sm501_2d_engine);
-
- /* bridge to usb host emulation module */
- dev = qdev_create(NULL, "sysbus-ohci");
- qdev_prop_set_uint32(dev, "num-ports", 2);
- qdev_prop_set_uint64(dev, "dma-offset", base);
- qdev_init_nofail(dev);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0,
- base + MMIO_BASE_OFFSET + SM501_USB_HOST);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
-
- /* bridge to serial emulation module */
- if (chr) {
- serial_mm_init(address_space_mem,
- base + MMIO_BASE_OFFSET + SM501_UART0, 2,
- NULL, /* TODO : chain irq to IRL */
- 115200, chr, DEVICE_NATIVE_ENDIAN);
- }
-
- /* create qemu graphic console */
- s->con = graphic_console_init(DEVICE(dev), 0, &sm501_ops, s);
-}
diff --git a/qemu/hw/display/sm501_template.h b/qemu/hw/display/sm501_template.h
deleted file mode 100644
index f33e499be..000000000
--- a/qemu/hw/display/sm501_template.h
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Pixel drawing function templates for QEMU SM501 Device
- *
- * Copyright (c) 2008 Shin-ichiro KAWASAKI
- *
- * 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 DEPTH == 8
-#define BPP 1
-#define PIXEL_TYPE uint8_t
-#elif DEPTH == 15 || DEPTH == 16
-#define BPP 2
-#define PIXEL_TYPE uint16_t
-#elif DEPTH == 32
-#define BPP 4
-#define PIXEL_TYPE uint32_t
-#else
-#error unsupport depth
-#endif
-
-#ifdef BGR_FORMAT
-#define PIXEL_NAME glue(DEPTH, bgr)
-#else
-#define PIXEL_NAME DEPTH
-#endif /* BGR_FORMAT */
-
-
-static void glue(draw_line8_, PIXEL_NAME)(
- uint8_t *d, const uint8_t *s, int width, const uint32_t *pal)
-{
- uint8_t v, r, g, b;
- do {
- v = ldub_p(s);
- r = (pal[v] >> 16) & 0xff;
- g = (pal[v] >> 8) & 0xff;
- b = (pal[v] >> 0) & 0xff;
- ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
- s ++;
- d += BPP;
- } while (-- width != 0);
-}
-
-static void glue(draw_line16_, PIXEL_NAME)(
- uint8_t *d, const uint8_t *s, int width, const uint32_t *pal)
-{
- uint16_t rgb565;
- uint8_t r, g, b;
-
- do {
- rgb565 = lduw_p(s);
- r = ((rgb565 >> 11) & 0x1f) << 3;
- g = ((rgb565 >> 5) & 0x3f) << 2;
- b = ((rgb565 >> 0) & 0x1f) << 3;
- ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
- s += 2;
- d += BPP;
- } while (-- width != 0);
-}
-
-static void glue(draw_line32_, PIXEL_NAME)(
- uint8_t *d, const uint8_t *s, int width, const uint32_t *pal)
-{
- uint8_t r, g, b;
-
- do {
- ldub_p(s);
-#if defined(TARGET_WORDS_BIGENDIAN)
- r = s[1];
- g = s[2];
- b = s[3];
-#else
- b = s[0];
- g = s[1];
- r = s[2];
-#endif
- ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
- s += 4;
- d += BPP;
- } while (-- width != 0);
-}
-
-/**
- * Draw hardware cursor image on the given line.
- */
-static void glue(draw_hwc_line_, PIXEL_NAME)(SM501State * s, int crt,
- uint8_t * palette, int c_y, uint8_t *d, int width)
-{
- int x, i;
- uint8_t bitset = 0;
-
- /* get hardware cursor pattern */
- uint32_t cursor_addr = get_hwc_address(s, crt);
- assert(0 <= c_y && c_y < SM501_HWC_HEIGHT);
- cursor_addr += 64 * c_y / 4; /* 4 pixels per byte */
- cursor_addr += s->base;
-
- /* get cursor position */
- x = get_hwc_x(s, crt);
- d += x * BPP;
-
- for (i = 0; i < SM501_HWC_WIDTH && x + i < width; i++) {
- uint8_t v;
-
- /* get pixel value */
- if (i % 4 == 0) {
- bitset = ldub_phys(&address_space_memory, cursor_addr);
- cursor_addr++;
- }
- v = bitset & 3;
- bitset >>= 2;
-
- /* write pixel */
- if (v) {
- v--;
- uint8_t r = palette[v * 3 + 0];
- uint8_t g = palette[v * 3 + 1];
- uint8_t b = palette[v * 3 + 2];
- ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
- }
- d += BPP;
- }
-}
-
-#undef DEPTH
-#undef BPP
-#undef PIXEL_TYPE
-#undef PIXEL_NAME
-#undef BGR_FORMAT
diff --git a/qemu/hw/display/ssd0303.c b/qemu/hw/display/ssd0303.c
deleted file mode 100644
index d3017563f..000000000
--- a/qemu/hw/display/ssd0303.c
+++ /dev/null
@@ -1,331 +0,0 @@
-/*
- * SSD0303 OLED controller with OSRAM Pictiva 96x16 display.
- *
- * Copyright (c) 2006-2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-/* The controller can support a variety of different displays, but we only
- implement one. Most of the commends relating to brightness and geometry
- setup are ignored. */
-#include "qemu/osdep.h"
-#include "hw/i2c/i2c.h"
-#include "ui/console.h"
-
-//#define DEBUG_SSD0303 1
-
-#ifdef DEBUG_SSD0303
-#define DPRINTF(fmt, ...) \
-do { printf("ssd0303: " fmt , ## __VA_ARGS__); } while (0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "ssd0303: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "ssd0303: error: " fmt , ## __VA_ARGS__);} while (0)
-#endif
-
-/* Scaling factor for pixels. */
-#define MAGNIFY 4
-
-enum ssd0303_mode
-{
- SSD0303_IDLE,
- SSD0303_DATA,
- SSD0303_CMD
-};
-
-enum ssd0303_cmd {
- SSD0303_CMD_NONE,
- SSD0303_CMD_SKIP1
-};
-
-#define TYPE_SSD0303 "ssd0303"
-#define SSD0303(obj) OBJECT_CHECK(ssd0303_state, (obj), TYPE_SSD0303)
-
-typedef struct {
- I2CSlave parent_obj;
-
- QemuConsole *con;
- int row;
- int col;
- int start_line;
- int mirror;
- int flash;
- int enabled;
- int inverse;
- int redraw;
- enum ssd0303_mode mode;
- enum ssd0303_cmd cmd_state;
- uint8_t framebuffer[132*8];
-} ssd0303_state;
-
-static int ssd0303_recv(I2CSlave *i2c)
-{
- BADF("Reads not implemented\n");
- return -1;
-}
-
-static int ssd0303_send(I2CSlave *i2c, uint8_t data)
-{
- ssd0303_state *s = SSD0303(i2c);
- enum ssd0303_cmd old_cmd_state;
-
- switch (s->mode) {
- case SSD0303_IDLE:
- DPRINTF("byte 0x%02x\n", data);
- if (data == 0x80)
- s->mode = SSD0303_CMD;
- else if (data == 0x40)
- s->mode = SSD0303_DATA;
- else
- BADF("Unexpected byte 0x%x\n", data);
- break;
- case SSD0303_DATA:
- DPRINTF("data 0x%02x\n", data);
- if (s->col < 132) {
- s->framebuffer[s->col + s->row * 132] = data;
- s->col++;
- s->redraw = 1;
- }
- break;
- case SSD0303_CMD:
- old_cmd_state = s->cmd_state;
- s->cmd_state = SSD0303_CMD_NONE;
- switch (old_cmd_state) {
- case SSD0303_CMD_NONE:
- DPRINTF("cmd 0x%02x\n", data);
- s->mode = SSD0303_IDLE;
- switch (data) {
- case 0x00 ... 0x0f: /* Set lower column address. */
- s->col = (s->col & 0xf0) | (data & 0xf);
- break;
- case 0x10 ... 0x20: /* Set higher column address. */
- s->col = (s->col & 0x0f) | ((data & 0xf) << 4);
- break;
- case 0x40 ... 0x7f: /* Set start line. */
- s->start_line = 0;
- break;
- case 0x81: /* Set contrast (Ignored). */
- s->cmd_state = SSD0303_CMD_SKIP1;
- break;
- case 0xa0: /* Mirror off. */
- s->mirror = 0;
- break;
- case 0xa1: /* Mirror off. */
- s->mirror = 1;
- break;
- case 0xa4: /* Entire display off. */
- s->flash = 0;
- break;
- case 0xa5: /* Entire display on. */
- s->flash = 1;
- break;
- case 0xa6: /* Inverse off. */
- s->inverse = 0;
- break;
- case 0xa7: /* Inverse on. */
- s->inverse = 1;
- break;
- case 0xa8: /* Set multiplied ratio (Ignored). */
- s->cmd_state = SSD0303_CMD_SKIP1;
- break;
- case 0xad: /* DC-DC power control. */
- s->cmd_state = SSD0303_CMD_SKIP1;
- break;
- case 0xae: /* Display off. */
- s->enabled = 0;
- break;
- case 0xaf: /* Display on. */
- s->enabled = 1;
- break;
- case 0xb0 ... 0xbf: /* Set Page address. */
- s->row = data & 7;
- break;
- case 0xc0 ... 0xc8: /* Set COM output direction (Ignored). */
- break;
- case 0xd3: /* Set display offset (Ignored). */
- s->cmd_state = SSD0303_CMD_SKIP1;
- break;
- case 0xd5: /* Set display clock (Ignored). */
- s->cmd_state = SSD0303_CMD_SKIP1;
- break;
- case 0xd8: /* Set color and power mode (Ignored). */
- s->cmd_state = SSD0303_CMD_SKIP1;
- break;
- case 0xd9: /* Set pre-charge period (Ignored). */
- s->cmd_state = SSD0303_CMD_SKIP1;
- break;
- case 0xda: /* Set COM pin configuration (Ignored). */
- s->cmd_state = SSD0303_CMD_SKIP1;
- break;
- case 0xdb: /* Set VCOM dselect level (Ignored). */
- s->cmd_state = SSD0303_CMD_SKIP1;
- break;
- case 0xe3: /* no-op. */
- break;
- default:
- BADF("Unknown command: 0x%x\n", data);
- }
- break;
- case SSD0303_CMD_SKIP1:
- DPRINTF("skip 0x%02x\n", data);
- break;
- }
- break;
- }
- return 0;
-}
-
-static void ssd0303_event(I2CSlave *i2c, enum i2c_event event)
-{
- ssd0303_state *s = SSD0303(i2c);
-
- switch (event) {
- case I2C_FINISH:
- s->mode = SSD0303_IDLE;
- break;
- case I2C_START_RECV:
- case I2C_START_SEND:
- case I2C_NACK:
- /* Nothing to do. */
- break;
- }
-}
-
-static void ssd0303_update_display(void *opaque)
-{
- ssd0303_state *s = (ssd0303_state *)opaque;
- DisplaySurface *surface = qemu_console_surface(s->con);
- uint8_t *dest;
- uint8_t *src;
- int x;
- int y;
- int line;
- char *colors[2];
- char colortab[MAGNIFY * 8];
- int dest_width;
- uint8_t mask;
-
- if (!s->redraw)
- return;
-
- switch (surface_bits_per_pixel(surface)) {
- case 0:
- return;
- case 15:
- dest_width = 2;
- break;
- case 16:
- dest_width = 2;
- break;
- case 24:
- dest_width = 3;
- break;
- case 32:
- dest_width = 4;
- break;
- default:
- BADF("Bad color depth\n");
- return;
- }
- dest_width *= MAGNIFY;
- memset(colortab, 0xff, dest_width);
- memset(colortab + dest_width, 0, dest_width);
- if (s->flash) {
- colors[0] = colortab;
- colors[1] = colortab;
- } else if (s->inverse) {
- colors[0] = colortab;
- colors[1] = colortab + dest_width;
- } else {
- colors[0] = colortab + dest_width;
- colors[1] = colortab;
- }
- dest = surface_data(surface);
- for (y = 0; y < 16; y++) {
- line = (y + s->start_line) & 63;
- src = s->framebuffer + 132 * (line >> 3) + 36;
- mask = 1 << (line & 7);
- for (x = 0; x < 96; x++) {
- memcpy(dest, colors[(*src & mask) != 0], dest_width);
- dest += dest_width;
- src++;
- }
- for (x = 1; x < MAGNIFY; x++) {
- memcpy(dest, dest - dest_width * 96, dest_width * 96);
- dest += dest_width * 96;
- }
- }
- s->redraw = 0;
- dpy_gfx_update(s->con, 0, 0, 96 * MAGNIFY, 16 * MAGNIFY);
-}
-
-static void ssd0303_invalidate_display(void * opaque)
-{
- ssd0303_state *s = (ssd0303_state *)opaque;
- s->redraw = 1;
-}
-
-static const VMStateDescription vmstate_ssd0303 = {
- .name = "ssd0303_oled",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_INT32(row, ssd0303_state),
- VMSTATE_INT32(col, ssd0303_state),
- VMSTATE_INT32(start_line, ssd0303_state),
- VMSTATE_INT32(mirror, ssd0303_state),
- VMSTATE_INT32(flash, ssd0303_state),
- VMSTATE_INT32(enabled, ssd0303_state),
- VMSTATE_INT32(inverse, ssd0303_state),
- VMSTATE_INT32(redraw, ssd0303_state),
- VMSTATE_UINT32(mode, ssd0303_state),
- VMSTATE_UINT32(cmd_state, ssd0303_state),
- VMSTATE_BUFFER(framebuffer, ssd0303_state),
- VMSTATE_I2C_SLAVE(parent_obj, ssd0303_state),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const GraphicHwOps ssd0303_ops = {
- .invalidate = ssd0303_invalidate_display,
- .gfx_update = ssd0303_update_display,
-};
-
-static int ssd0303_init(I2CSlave *i2c)
-{
- ssd0303_state *s = SSD0303(i2c);
-
- s->con = graphic_console_init(DEVICE(i2c), 0, &ssd0303_ops, s);
- qemu_console_resize(s->con, 96 * MAGNIFY, 16 * MAGNIFY);
- return 0;
-}
-
-static void ssd0303_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
-
- k->init = ssd0303_init;
- k->event = ssd0303_event;
- k->recv = ssd0303_recv;
- k->send = ssd0303_send;
- dc->vmsd = &vmstate_ssd0303;
-}
-
-static const TypeInfo ssd0303_info = {
- .name = TYPE_SSD0303,
- .parent = TYPE_I2C_SLAVE,
- .instance_size = sizeof(ssd0303_state),
- .class_init = ssd0303_class_init,
-};
-
-static void ssd0303_register_types(void)
-{
- type_register_static(&ssd0303_info);
-}
-
-type_init(ssd0303_register_types)
diff --git a/qemu/hw/display/ssd0323.c b/qemu/hw/display/ssd0323.c
deleted file mode 100644
index 14c1bf339..000000000
--- a/qemu/hw/display/ssd0323.c
+++ /dev/null
@@ -1,402 +0,0 @@
-/*
- * SSD0323 OLED controller with OSRAM Pictiva 128x64 display.
- *
- * Copyright (c) 2006-2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-/* The controller can support a variety of different displays, but we only
- implement one. Most of the commends relating to brightness and geometry
- setup are ignored. */
-#include "qemu/osdep.h"
-#include "hw/ssi/ssi.h"
-#include "ui/console.h"
-
-//#define DEBUG_SSD0323 1
-
-#ifdef DEBUG_SSD0323
-#define DPRINTF(fmt, ...) \
-do { printf("ssd0323: " fmt , ## __VA_ARGS__); } while (0)
-#define BADF(fmt, ...) \
-do { \
- fprintf(stderr, "ssd0323: error: " fmt , ## __VA_ARGS__); abort(); \
-} while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "ssd0323: error: " fmt , ## __VA_ARGS__);} while (0)
-#endif
-
-/* Scaling factor for pixels. */
-#define MAGNIFY 4
-
-#define REMAP_SWAP_COLUMN 0x01
-#define REMAP_SWAP_NYBBLE 0x02
-#define REMAP_VERTICAL 0x04
-#define REMAP_SWAP_COM 0x10
-#define REMAP_SPLIT_COM 0x40
-
-enum ssd0323_mode
-{
- SSD0323_CMD,
- SSD0323_DATA
-};
-
-typedef struct {
- SSISlave ssidev;
- QemuConsole *con;
-
- int cmd_len;
- int cmd;
- int cmd_data[8];
- int row;
- int row_start;
- int row_end;
- int col;
- int col_start;
- int col_end;
- int redraw;
- int remap;
- enum ssd0323_mode mode;
- uint8_t framebuffer[128 * 80 / 2];
-} ssd0323_state;
-
-static uint32_t ssd0323_transfer(SSISlave *dev, uint32_t data)
-{
- ssd0323_state *s = FROM_SSI_SLAVE(ssd0323_state, dev);
-
- switch (s->mode) {
- case SSD0323_DATA:
- DPRINTF("data 0x%02x\n", data);
- s->framebuffer[s->col + s->row * 64] = data;
- if (s->remap & REMAP_VERTICAL) {
- s->row++;
- if (s->row > s->row_end) {
- s->row = s->row_start;
- s->col++;
- }
- if (s->col > s->col_end) {
- s->col = s->col_start;
- }
- } else {
- s->col++;
- if (s->col > s->col_end) {
- s->row++;
- s->col = s->col_start;
- }
- if (s->row > s->row_end) {
- s->row = s->row_start;
- }
- }
- s->redraw = 1;
- break;
- case SSD0323_CMD:
- DPRINTF("cmd 0x%02x\n", data);
- if (s->cmd_len == 0) {
- s->cmd = data;
- } else {
- s->cmd_data[s->cmd_len - 1] = data;
- }
- s->cmd_len++;
- switch (s->cmd) {
-#define DATA(x) if (s->cmd_len <= (x)) return 0
- case 0x15: /* Set column. */
- DATA(2);
- s->col = s->col_start = s->cmd_data[0] % 64;
- s->col_end = s->cmd_data[1] % 64;
- break;
- case 0x75: /* Set row. */
- DATA(2);
- s->row = s->row_start = s->cmd_data[0] % 80;
- s->row_end = s->cmd_data[1] % 80;
- break;
- case 0x81: /* Set contrast */
- DATA(1);
- break;
- case 0x84: case 0x85: case 0x86: /* Max current. */
- DATA(0);
- break;
- case 0xa0: /* Set remapping. */
- /* FIXME: Implement this. */
- DATA(1);
- s->remap = s->cmd_data[0];
- break;
- case 0xa1: /* Set display start line. */
- case 0xa2: /* Set display offset. */
- /* FIXME: Implement these. */
- DATA(1);
- break;
- case 0xa4: /* Normal mode. */
- case 0xa5: /* All on. */
- case 0xa6: /* All off. */
- case 0xa7: /* Inverse. */
- /* FIXME: Implement these. */
- DATA(0);
- break;
- case 0xa8: /* Set multiplex ratio. */
- case 0xad: /* Set DC-DC converter. */
- DATA(1);
- /* Ignored. Don't care. */
- break;
- case 0xae: /* Display off. */
- case 0xaf: /* Display on. */
- DATA(0);
- /* TODO: Implement power control. */
- break;
- case 0xb1: /* Set phase length. */
- case 0xb2: /* Set row period. */
- case 0xb3: /* Set clock rate. */
- case 0xbc: /* Set precharge. */
- case 0xbe: /* Set VCOMH. */
- case 0xbf: /* Set segment low. */
- DATA(1);
- /* Ignored. Don't care. */
- break;
- case 0xb8: /* Set grey scale table. */
- /* FIXME: Implement this. */
- DATA(8);
- break;
- case 0xe3: /* NOP. */
- DATA(0);
- break;
- case 0xff: /* Nasty hack because we don't handle chip selects
- properly. */
- break;
- default:
- BADF("Unknown command: 0x%x\n", data);
- }
- s->cmd_len = 0;
- return 0;
- }
- return 0;
-}
-
-static void ssd0323_update_display(void *opaque)
-{
- ssd0323_state *s = (ssd0323_state *)opaque;
- DisplaySurface *surface = qemu_console_surface(s->con);
- uint8_t *dest;
- uint8_t *src;
- int x;
- int y;
- int i;
- int line;
- char *colors[16];
- char colortab[MAGNIFY * 64];
- char *p;
- int dest_width;
-
- if (!s->redraw)
- return;
-
- switch (surface_bits_per_pixel(surface)) {
- case 0:
- return;
- case 15:
- dest_width = 2;
- break;
- case 16:
- dest_width = 2;
- break;
- case 24:
- dest_width = 3;
- break;
- case 32:
- dest_width = 4;
- break;
- default:
- BADF("Bad color depth\n");
- return;
- }
- p = colortab;
- for (i = 0; i < 16; i++) {
- int n;
- colors[i] = p;
- switch (surface_bits_per_pixel(surface)) {
- case 15:
- n = i * 2 + (i >> 3);
- p[0] = n | (n << 5);
- p[1] = (n << 2) | (n >> 3);
- break;
- case 16:
- n = i * 2 + (i >> 3);
- p[0] = n | (n << 6) | ((n << 1) & 0x20);
- p[1] = (n << 3) | (n >> 2);
- break;
- case 24:
- case 32:
- n = (i << 4) | i;
- p[0] = p[1] = p[2] = n;
- break;
- default:
- BADF("Bad color depth\n");
- return;
- }
- p += dest_width;
- }
- /* TODO: Implement row/column remapping. */
- dest = surface_data(surface);
- for (y = 0; y < 64; y++) {
- line = y;
- src = s->framebuffer + 64 * line;
- for (x = 0; x < 64; x++) {
- int val;
- val = *src >> 4;
- for (i = 0; i < MAGNIFY; i++) {
- memcpy(dest, colors[val], dest_width);
- dest += dest_width;
- }
- val = *src & 0xf;
- for (i = 0; i < MAGNIFY; i++) {
- memcpy(dest, colors[val], dest_width);
- dest += dest_width;
- }
- src++;
- }
- for (i = 1; i < MAGNIFY; i++) {
- memcpy(dest, dest - dest_width * MAGNIFY * 128,
- dest_width * 128 * MAGNIFY);
- dest += dest_width * 128 * MAGNIFY;
- }
- }
- s->redraw = 0;
- dpy_gfx_update(s->con, 0, 0, 128 * MAGNIFY, 64 * MAGNIFY);
-}
-
-static void ssd0323_invalidate_display(void * opaque)
-{
- ssd0323_state *s = (ssd0323_state *)opaque;
- s->redraw = 1;
-}
-
-/* Command/data input. */
-static void ssd0323_cd(void *opaque, int n, int level)
-{
- ssd0323_state *s = (ssd0323_state *)opaque;
- DPRINTF("%s mode\n", level ? "Data" : "Command");
- s->mode = level ? SSD0323_DATA : SSD0323_CMD;
-}
-
-static void ssd0323_save(QEMUFile *f, void *opaque)
-{
- SSISlave *ss = SSI_SLAVE(opaque);
- ssd0323_state *s = (ssd0323_state *)opaque;
- int i;
-
- qemu_put_be32(f, s->cmd_len);
- qemu_put_be32(f, s->cmd);
- for (i = 0; i < 8; i++)
- qemu_put_be32(f, s->cmd_data[i]);
- qemu_put_be32(f, s->row);
- qemu_put_be32(f, s->row_start);
- qemu_put_be32(f, s->row_end);
- qemu_put_be32(f, s->col);
- qemu_put_be32(f, s->col_start);
- qemu_put_be32(f, s->col_end);
- qemu_put_be32(f, s->redraw);
- qemu_put_be32(f, s->remap);
- qemu_put_be32(f, s->mode);
- qemu_put_buffer(f, s->framebuffer, sizeof(s->framebuffer));
-
- qemu_put_be32(f, ss->cs);
-}
-
-static int ssd0323_load(QEMUFile *f, void *opaque, int version_id)
-{
- SSISlave *ss = SSI_SLAVE(opaque);
- ssd0323_state *s = (ssd0323_state *)opaque;
- int i;
-
- if (version_id != 1)
- return -EINVAL;
-
- s->cmd_len = qemu_get_be32(f);
- if (s->cmd_len < 0 || s->cmd_len > ARRAY_SIZE(s->cmd_data)) {
- return -EINVAL;
- }
- s->cmd = qemu_get_be32(f);
- for (i = 0; i < 8; i++)
- s->cmd_data[i] = qemu_get_be32(f);
- s->row = qemu_get_be32(f);
- if (s->row < 0 || s->row >= 80) {
- return -EINVAL;
- }
- s->row_start = qemu_get_be32(f);
- if (s->row_start < 0 || s->row_start >= 80) {
- return -EINVAL;
- }
- s->row_end = qemu_get_be32(f);
- if (s->row_end < 0 || s->row_end >= 80) {
- return -EINVAL;
- }
- s->col = qemu_get_be32(f);
- if (s->col < 0 || s->col >= 64) {
- return -EINVAL;
- }
- s->col_start = qemu_get_be32(f);
- if (s->col_start < 0 || s->col_start >= 64) {
- return -EINVAL;
- }
- s->col_end = qemu_get_be32(f);
- if (s->col_end < 0 || s->col_end >= 64) {
- return -EINVAL;
- }
- s->redraw = qemu_get_be32(f);
- s->remap = qemu_get_be32(f);
- s->mode = qemu_get_be32(f);
- if (s->mode != SSD0323_CMD && s->mode != SSD0323_DATA) {
- return -EINVAL;
- }
- qemu_get_buffer(f, s->framebuffer, sizeof(s->framebuffer));
-
- ss->cs = qemu_get_be32(f);
-
- return 0;
-}
-
-static const GraphicHwOps ssd0323_ops = {
- .invalidate = ssd0323_invalidate_display,
- .gfx_update = ssd0323_update_display,
-};
-
-static int ssd0323_init(SSISlave *d)
-{
- DeviceState *dev = DEVICE(d);
- ssd0323_state *s = FROM_SSI_SLAVE(ssd0323_state, d);
-
- s->col_end = 63;
- s->row_end = 79;
- s->con = graphic_console_init(dev, 0, &ssd0323_ops, s);
- qemu_console_resize(s->con, 128 * MAGNIFY, 64 * MAGNIFY);
-
- qdev_init_gpio_in(dev, ssd0323_cd, 1);
-
- register_savevm(dev, "ssd0323_oled", -1, 1,
- ssd0323_save, ssd0323_load, s);
- return 0;
-}
-
-static void ssd0323_class_init(ObjectClass *klass, void *data)
-{
- SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
-
- k->init = ssd0323_init;
- k->transfer = ssd0323_transfer;
- k->cs_polarity = SSI_CS_HIGH;
-}
-
-static const TypeInfo ssd0323_info = {
- .name = "ssd0323",
- .parent = TYPE_SSI_SLAVE,
- .instance_size = sizeof(ssd0323_state),
- .class_init = ssd0323_class_init,
-};
-
-static void ssd03232_register_types(void)
-{
- type_register_static(&ssd0323_info);
-}
-
-type_init(ssd03232_register_types)
diff --git a/qemu/hw/display/tc6393xb.c b/qemu/hw/display/tc6393xb.c
deleted file mode 100644
index da3ceceb0..000000000
--- a/qemu/hw/display/tc6393xb.c
+++ /dev/null
@@ -1,598 +0,0 @@
-/*
- * Toshiba TC6393XB I/O Controller.
- * Found in Sharp Zaurus SL-6000 (tosa) or some
- * Toshiba e-Series PDAs.
- *
- * Most features are currently unsupported!!!
- *
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/hw.h"
-#include "hw/devices.h"
-#include "hw/block/flash.h"
-#include "ui/console.h"
-#include "ui/pixel_ops.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
-
-#define IRQ_TC6393_NAND 0
-#define IRQ_TC6393_MMC 1
-#define IRQ_TC6393_OHCI 2
-#define IRQ_TC6393_SERIAL 3
-#define IRQ_TC6393_FB 4
-
-#define TC6393XB_NR_IRQS 8
-
-#define TC6393XB_GPIOS 16
-
-#define SCR_REVID 0x08 /* b Revision ID */
-#define SCR_ISR 0x50 /* b Interrupt Status */
-#define SCR_IMR 0x52 /* b Interrupt Mask */
-#define SCR_IRR 0x54 /* b Interrupt Routing */
-#define SCR_GPER 0x60 /* w GP Enable */
-#define SCR_GPI_SR(i) (0x64 + (i)) /* b3 GPI Status */
-#define SCR_GPI_IMR(i) (0x68 + (i)) /* b3 GPI INT Mask */
-#define SCR_GPI_EDER(i) (0x6c + (i)) /* b3 GPI Edge Detect Enable */
-#define SCR_GPI_LIR(i) (0x70 + (i)) /* b3 GPI Level Invert */
-#define SCR_GPO_DSR(i) (0x78 + (i)) /* b3 GPO Data Set */
-#define SCR_GPO_DOECR(i) (0x7c + (i)) /* b3 GPO Data OE Control */
-#define SCR_GP_IARCR(i) (0x80 + (i)) /* b3 GP Internal Active Register Control */
-#define SCR_GP_IARLCR(i) (0x84 + (i)) /* b3 GP INTERNAL Active Register Level Control */
-#define SCR_GPI_BCR(i) (0x88 + (i)) /* b3 GPI Buffer Control */
-#define SCR_GPA_IARCR 0x8c /* w GPa Internal Active Register Control */
-#define SCR_GPA_IARLCR 0x90 /* w GPa Internal Active Register Level Control */
-#define SCR_GPA_BCR 0x94 /* w GPa Buffer Control */
-#define SCR_CCR 0x98 /* w Clock Control */
-#define SCR_PLL2CR 0x9a /* w PLL2 Control */
-#define SCR_PLL1CR 0x9c /* l PLL1 Control */
-#define SCR_DIARCR 0xa0 /* b Device Internal Active Register Control */
-#define SCR_DBOCR 0xa1 /* b Device Buffer Off Control */
-#define SCR_FER 0xe0 /* b Function Enable */
-#define SCR_MCR 0xe4 /* w Mode Control */
-#define SCR_CONFIG 0xfc /* b Configuration Control */
-#define SCR_DEBUG 0xff /* b Debug */
-
-#define NAND_CFG_COMMAND 0x04 /* w Command */
-#define NAND_CFG_BASE 0x10 /* l Control Base Address */
-#define NAND_CFG_INTP 0x3d /* b Interrupt Pin */
-#define NAND_CFG_INTE 0x48 /* b Int Enable */
-#define NAND_CFG_EC 0x4a /* b Event Control */
-#define NAND_CFG_ICC 0x4c /* b Internal Clock Control */
-#define NAND_CFG_ECCC 0x5b /* b ECC Control */
-#define NAND_CFG_NFTC 0x60 /* b NAND Flash Transaction Control */
-#define NAND_CFG_NFM 0x61 /* b NAND Flash Monitor */
-#define NAND_CFG_NFPSC 0x62 /* b NAND Flash Power Supply Control */
-#define NAND_CFG_NFDC 0x63 /* b NAND Flash Detect Control */
-
-#define NAND_DATA 0x00 /* l Data */
-#define NAND_MODE 0x04 /* b Mode */
-#define NAND_STATUS 0x05 /* b Status */
-#define NAND_ISR 0x06 /* b Interrupt Status */
-#define NAND_IMR 0x07 /* b Interrupt Mask */
-
-#define NAND_MODE_WP 0x80
-#define NAND_MODE_CE 0x10
-#define NAND_MODE_ALE 0x02
-#define NAND_MODE_CLE 0x01
-#define NAND_MODE_ECC_MASK 0x60
-#define NAND_MODE_ECC_EN 0x20
-#define NAND_MODE_ECC_READ 0x40
-#define NAND_MODE_ECC_RST 0x60
-
-struct TC6393xbState {
- MemoryRegion iomem;
- qemu_irq irq;
- qemu_irq *sub_irqs;
- struct {
- uint8_t ISR;
- uint8_t IMR;
- uint8_t IRR;
- uint16_t GPER;
- uint8_t GPI_SR[3];
- uint8_t GPI_IMR[3];
- uint8_t GPI_EDER[3];
- uint8_t GPI_LIR[3];
- uint8_t GP_IARCR[3];
- uint8_t GP_IARLCR[3];
- uint8_t GPI_BCR[3];
- uint16_t GPA_IARCR;
- uint16_t GPA_IARLCR;
- uint16_t CCR;
- uint16_t PLL2CR;
- uint32_t PLL1CR;
- uint8_t DIARCR;
- uint8_t DBOCR;
- uint8_t FER;
- uint16_t MCR;
- uint8_t CONFIG;
- uint8_t DEBUG;
- } scr;
- uint32_t gpio_dir;
- uint32_t gpio_level;
- uint32_t prev_level;
- qemu_irq handler[TC6393XB_GPIOS];
- qemu_irq *gpio_in;
-
- struct {
- uint8_t mode;
- uint8_t isr;
- uint8_t imr;
- } nand;
- int nand_enable;
- uint32_t nand_phys;
- DeviceState *flash;
- ECCState ecc;
-
- QemuConsole *con;
- MemoryRegion vram;
- uint16_t *vram_ptr;
- uint32_t scr_width, scr_height; /* in pixels */
- qemu_irq l3v;
- unsigned blank : 1,
- blanked : 1;
-};
-
-qemu_irq *tc6393xb_gpio_in_get(TC6393xbState *s)
-{
- return s->gpio_in;
-}
-
-static void tc6393xb_gpio_set(void *opaque, int line, int level)
-{
-// TC6393xbState *s = opaque;
-
- if (line > TC6393XB_GPIOS) {
- printf("%s: No GPIO pin %i\n", __FUNCTION__, line);
- return;
- }
-
- // FIXME: how does the chip reflect the GPIO input level change?
-}
-
-void tc6393xb_gpio_out_set(TC6393xbState *s, int line,
- qemu_irq handler)
-{
- if (line >= TC6393XB_GPIOS) {
- fprintf(stderr, "TC6393xb: no GPIO pin %d\n", line);
- return;
- }
-
- s->handler[line] = handler;
-}
-
-static void tc6393xb_gpio_handler_update(TC6393xbState *s)
-{
- uint32_t level, diff;
- int bit;
-
- level = s->gpio_level & s->gpio_dir;
-
- for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) {
- bit = ctz32(diff);
- qemu_set_irq(s->handler[bit], (level >> bit) & 1);
- }
-
- s->prev_level = level;
-}
-
-qemu_irq tc6393xb_l3v_get(TC6393xbState *s)
-{
- return s->l3v;
-}
-
-static void tc6393xb_l3v(void *opaque, int line, int level)
-{
- TC6393xbState *s = opaque;
- s->blank = !level;
- fprintf(stderr, "L3V: %d\n", level);
-}
-
-static void tc6393xb_sub_irq(void *opaque, int line, int level) {
- TC6393xbState *s = opaque;
- uint8_t isr = s->scr.ISR;
- if (level)
- isr |= 1 << line;
- else
- isr &= ~(1 << line);
- s->scr.ISR = isr;
- qemu_set_irq(s->irq, isr & s->scr.IMR);
-}
-
-#define SCR_REG_B(N) \
- case SCR_ ##N: return s->scr.N
-#define SCR_REG_W(N) \
- case SCR_ ##N: return s->scr.N; \
- case SCR_ ##N + 1: return s->scr.N >> 8;
-#define SCR_REG_L(N) \
- case SCR_ ##N: return s->scr.N; \
- case SCR_ ##N + 1: return s->scr.N >> 8; \
- case SCR_ ##N + 2: return s->scr.N >> 16; \
- case SCR_ ##N + 3: return s->scr.N >> 24;
-#define SCR_REG_A(N) \
- case SCR_ ##N(0): return s->scr.N[0]; \
- case SCR_ ##N(1): return s->scr.N[1]; \
- case SCR_ ##N(2): return s->scr.N[2]
-
-static uint32_t tc6393xb_scr_readb(TC6393xbState *s, hwaddr addr)
-{
- switch (addr) {
- case SCR_REVID:
- return 3;
- case SCR_REVID+1:
- return 0;
- SCR_REG_B(ISR);
- SCR_REG_B(IMR);
- SCR_REG_B(IRR);
- SCR_REG_W(GPER);
- SCR_REG_A(GPI_SR);
- SCR_REG_A(GPI_IMR);
- SCR_REG_A(GPI_EDER);
- SCR_REG_A(GPI_LIR);
- case SCR_GPO_DSR(0):
- case SCR_GPO_DSR(1):
- case SCR_GPO_DSR(2):
- return (s->gpio_level >> ((addr - SCR_GPO_DSR(0)) * 8)) & 0xff;
- case SCR_GPO_DOECR(0):
- case SCR_GPO_DOECR(1):
- case SCR_GPO_DOECR(2):
- return (s->gpio_dir >> ((addr - SCR_GPO_DOECR(0)) * 8)) & 0xff;
- SCR_REG_A(GP_IARCR);
- SCR_REG_A(GP_IARLCR);
- SCR_REG_A(GPI_BCR);
- SCR_REG_W(GPA_IARCR);
- SCR_REG_W(GPA_IARLCR);
- SCR_REG_W(CCR);
- SCR_REG_W(PLL2CR);
- SCR_REG_L(PLL1CR);
- SCR_REG_B(DIARCR);
- SCR_REG_B(DBOCR);
- SCR_REG_B(FER);
- SCR_REG_W(MCR);
- SCR_REG_B(CONFIG);
- SCR_REG_B(DEBUG);
- }
- fprintf(stderr, "tc6393xb_scr: unhandled read at %08x\n", (uint32_t) addr);
- return 0;
-}
-#undef SCR_REG_B
-#undef SCR_REG_W
-#undef SCR_REG_L
-#undef SCR_REG_A
-
-#define SCR_REG_B(N) \
- case SCR_ ##N: s->scr.N = value; return;
-#define SCR_REG_W(N) \
- case SCR_ ##N: s->scr.N = (s->scr.N & ~0xff) | (value & 0xff); return; \
- case SCR_ ##N + 1: s->scr.N = (s->scr.N & 0xff) | (value << 8); return
-#define SCR_REG_L(N) \
- case SCR_ ##N: s->scr.N = (s->scr.N & ~0xff) | (value & 0xff); return; \
- case SCR_ ##N + 1: s->scr.N = (s->scr.N & ~(0xff << 8)) | (value & (0xff << 8)); return; \
- case SCR_ ##N + 2: s->scr.N = (s->scr.N & ~(0xff << 16)) | (value & (0xff << 16)); return; \
- case SCR_ ##N + 3: s->scr.N = (s->scr.N & ~(0xff << 24)) | (value & (0xff << 24)); return;
-#define SCR_REG_A(N) \
- case SCR_ ##N(0): s->scr.N[0] = value; return; \
- case SCR_ ##N(1): s->scr.N[1] = value; return; \
- case SCR_ ##N(2): s->scr.N[2] = value; return
-
-static void tc6393xb_scr_writeb(TC6393xbState *s, hwaddr addr, uint32_t value)
-{
- switch (addr) {
- SCR_REG_B(ISR);
- SCR_REG_B(IMR);
- SCR_REG_B(IRR);
- SCR_REG_W(GPER);
- SCR_REG_A(GPI_SR);
- SCR_REG_A(GPI_IMR);
- SCR_REG_A(GPI_EDER);
- SCR_REG_A(GPI_LIR);
- case SCR_GPO_DSR(0):
- case SCR_GPO_DSR(1):
- case SCR_GPO_DSR(2):
- s->gpio_level = (s->gpio_level & ~(0xff << ((addr - SCR_GPO_DSR(0))*8))) | ((value & 0xff) << ((addr - SCR_GPO_DSR(0))*8));
- tc6393xb_gpio_handler_update(s);
- return;
- case SCR_GPO_DOECR(0):
- case SCR_GPO_DOECR(1):
- case SCR_GPO_DOECR(2):
- s->gpio_dir = (s->gpio_dir & ~(0xff << ((addr - SCR_GPO_DOECR(0))*8))) | ((value & 0xff) << ((addr - SCR_GPO_DOECR(0))*8));
- tc6393xb_gpio_handler_update(s);
- return;
- SCR_REG_A(GP_IARCR);
- SCR_REG_A(GP_IARLCR);
- SCR_REG_A(GPI_BCR);
- SCR_REG_W(GPA_IARCR);
- SCR_REG_W(GPA_IARLCR);
- SCR_REG_W(CCR);
- SCR_REG_W(PLL2CR);
- SCR_REG_L(PLL1CR);
- SCR_REG_B(DIARCR);
- SCR_REG_B(DBOCR);
- SCR_REG_B(FER);
- SCR_REG_W(MCR);
- SCR_REG_B(CONFIG);
- SCR_REG_B(DEBUG);
- }
- fprintf(stderr, "tc6393xb_scr: unhandled write at %08x: %02x\n",
- (uint32_t) addr, value & 0xff);
-}
-#undef SCR_REG_B
-#undef SCR_REG_W
-#undef SCR_REG_L
-#undef SCR_REG_A
-
-static void tc6393xb_nand_irq(TC6393xbState *s) {
- qemu_set_irq(s->sub_irqs[IRQ_TC6393_NAND],
- (s->nand.imr & 0x80) && (s->nand.imr & s->nand.isr));
-}
-
-static uint32_t tc6393xb_nand_cfg_readb(TC6393xbState *s, hwaddr addr) {
- switch (addr) {
- case NAND_CFG_COMMAND:
- return s->nand_enable ? 2 : 0;
- case NAND_CFG_BASE:
- case NAND_CFG_BASE + 1:
- case NAND_CFG_BASE + 2:
- case NAND_CFG_BASE + 3:
- return s->nand_phys >> (addr - NAND_CFG_BASE);
- }
- fprintf(stderr, "tc6393xb_nand_cfg: unhandled read at %08x\n", (uint32_t) addr);
- return 0;
-}
-static void tc6393xb_nand_cfg_writeb(TC6393xbState *s, hwaddr addr, uint32_t value) {
- switch (addr) {
- case NAND_CFG_COMMAND:
- s->nand_enable = (value & 0x2);
- return;
- case NAND_CFG_BASE:
- case NAND_CFG_BASE + 1:
- case NAND_CFG_BASE + 2:
- case NAND_CFG_BASE + 3:
- s->nand_phys &= ~(0xff << ((addr - NAND_CFG_BASE) * 8));
- s->nand_phys |= (value & 0xff) << ((addr - NAND_CFG_BASE) * 8);
- return;
- }
- fprintf(stderr, "tc6393xb_nand_cfg: unhandled write at %08x: %02x\n",
- (uint32_t) addr, value & 0xff);
-}
-
-static uint32_t tc6393xb_nand_readb(TC6393xbState *s, hwaddr addr) {
- switch (addr) {
- case NAND_DATA + 0:
- case NAND_DATA + 1:
- case NAND_DATA + 2:
- case NAND_DATA + 3:
- return nand_getio(s->flash);
- case NAND_MODE:
- return s->nand.mode;
- case NAND_STATUS:
- return 0x14;
- case NAND_ISR:
- return s->nand.isr;
- case NAND_IMR:
- return s->nand.imr;
- }
- fprintf(stderr, "tc6393xb_nand: unhandled read at %08x\n", (uint32_t) addr);
- return 0;
-}
-static void tc6393xb_nand_writeb(TC6393xbState *s, hwaddr addr, uint32_t value) {
-// fprintf(stderr, "tc6393xb_nand: write at %08x: %02x\n",
-// (uint32_t) addr, value & 0xff);
- switch (addr) {
- case NAND_DATA + 0:
- case NAND_DATA + 1:
- case NAND_DATA + 2:
- case NAND_DATA + 3:
- nand_setio(s->flash, value);
- s->nand.isr |= 1;
- tc6393xb_nand_irq(s);
- return;
- case NAND_MODE:
- s->nand.mode = value;
- nand_setpins(s->flash,
- value & NAND_MODE_CLE,
- value & NAND_MODE_ALE,
- !(value & NAND_MODE_CE),
- value & NAND_MODE_WP,
- 0); // FIXME: gnd
- switch (value & NAND_MODE_ECC_MASK) {
- case NAND_MODE_ECC_RST:
- ecc_reset(&s->ecc);
- break;
- case NAND_MODE_ECC_READ:
- // FIXME
- break;
- case NAND_MODE_ECC_EN:
- ecc_reset(&s->ecc);
- }
- return;
- case NAND_ISR:
- s->nand.isr = value;
- tc6393xb_nand_irq(s);
- return;
- case NAND_IMR:
- s->nand.imr = value;
- tc6393xb_nand_irq(s);
- return;
- }
- fprintf(stderr, "tc6393xb_nand: unhandled write at %08x: %02x\n",
- (uint32_t) addr, value & 0xff);
-}
-
-#define BITS 8
-#include "tc6393xb_template.h"
-#define BITS 15
-#include "tc6393xb_template.h"
-#define BITS 16
-#include "tc6393xb_template.h"
-#define BITS 24
-#include "tc6393xb_template.h"
-#define BITS 32
-#include "tc6393xb_template.h"
-
-static void tc6393xb_draw_graphic(TC6393xbState *s, int full_update)
-{
- DisplaySurface *surface = qemu_console_surface(s->con);
-
- switch (surface_bits_per_pixel(surface)) {
- case 8:
- tc6393xb_draw_graphic8(s);
- break;
- case 15:
- tc6393xb_draw_graphic15(s);
- break;
- case 16:
- tc6393xb_draw_graphic16(s);
- break;
- case 24:
- tc6393xb_draw_graphic24(s);
- break;
- case 32:
- tc6393xb_draw_graphic32(s);
- break;
- default:
- printf("tc6393xb: unknown depth %d\n",
- surface_bits_per_pixel(surface));
- return;
- }
-
- dpy_gfx_update(s->con, 0, 0, s->scr_width, s->scr_height);
-}
-
-static void tc6393xb_draw_blank(TC6393xbState *s, int full_update)
-{
- DisplaySurface *surface = qemu_console_surface(s->con);
- int i, w;
- uint8_t *d;
-
- if (!full_update)
- return;
-
- w = s->scr_width * surface_bytes_per_pixel(surface);
- d = surface_data(surface);
- for(i = 0; i < s->scr_height; i++) {
- memset(d, 0, w);
- d += surface_stride(surface);
- }
-
- dpy_gfx_update(s->con, 0, 0, s->scr_width, s->scr_height);
-}
-
-static void tc6393xb_update_display(void *opaque)
-{
- TC6393xbState *s = opaque;
- DisplaySurface *surface = qemu_console_surface(s->con);
- int full_update;
-
- if (s->scr_width == 0 || s->scr_height == 0)
- return;
-
- full_update = 0;
- if (s->blanked != s->blank) {
- s->blanked = s->blank;
- full_update = 1;
- }
- if (s->scr_width != surface_width(surface) ||
- s->scr_height != surface_height(surface)) {
- qemu_console_resize(s->con, s->scr_width, s->scr_height);
- full_update = 1;
- }
- if (s->blanked)
- tc6393xb_draw_blank(s, full_update);
- else
- tc6393xb_draw_graphic(s, full_update);
-}
-
-
-static uint64_t tc6393xb_readb(void *opaque, hwaddr addr,
- unsigned size)
-{
- TC6393xbState *s = opaque;
-
- switch (addr >> 8) {
- case 0:
- return tc6393xb_scr_readb(s, addr & 0xff);
- case 1:
- return tc6393xb_nand_cfg_readb(s, addr & 0xff);
- };
-
- if ((addr &~0xff) == s->nand_phys && s->nand_enable) {
-// return tc6393xb_nand_readb(s, addr & 0xff);
- uint8_t d = tc6393xb_nand_readb(s, addr & 0xff);
-// fprintf(stderr, "tc6393xb_nand: read at %08x: %02hhx\n", (uint32_t) addr, d);
- return d;
- }
-
-// fprintf(stderr, "tc6393xb: unhandled read at %08x\n", (uint32_t) addr);
- return 0;
-}
-
-static void tc6393xb_writeb(void *opaque, hwaddr addr,
- uint64_t value, unsigned size) {
- TC6393xbState *s = opaque;
-
- switch (addr >> 8) {
- case 0:
- tc6393xb_scr_writeb(s, addr & 0xff, value);
- return;
- case 1:
- tc6393xb_nand_cfg_writeb(s, addr & 0xff, value);
- return;
- };
-
- if ((addr &~0xff) == s->nand_phys && s->nand_enable)
- tc6393xb_nand_writeb(s, addr & 0xff, value);
- else
- fprintf(stderr, "tc6393xb: unhandled write at %08x: %02x\n",
- (uint32_t) addr, (int)value & 0xff);
-}
-
-static const GraphicHwOps tc6393xb_gfx_ops = {
- .gfx_update = tc6393xb_update_display,
-};
-
-TC6393xbState *tc6393xb_init(MemoryRegion *sysmem, uint32_t base, qemu_irq irq)
-{
- TC6393xbState *s;
- DriveInfo *nand;
- static const MemoryRegionOps tc6393xb_ops = {
- .read = tc6393xb_readb,
- .write = tc6393xb_writeb,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
- };
-
- s = (TC6393xbState *) g_malloc0(sizeof(TC6393xbState));
- s->irq = irq;
- s->gpio_in = qemu_allocate_irqs(tc6393xb_gpio_set, s, TC6393XB_GPIOS);
-
- s->l3v = qemu_allocate_irq(tc6393xb_l3v, s, 0);
- s->blanked = 1;
-
- s->sub_irqs = qemu_allocate_irqs(tc6393xb_sub_irq, s, TC6393XB_NR_IRQS);
-
- nand = drive_get(IF_MTD, 0, 0);
- s->flash = nand_init(nand ? blk_by_legacy_dinfo(nand) : NULL,
- NAND_MFR_TOSHIBA, 0x76);
-
- memory_region_init_io(&s->iomem, NULL, &tc6393xb_ops, s, "tc6393xb", 0x10000);
- memory_region_add_subregion(sysmem, base, &s->iomem);
-
- memory_region_init_ram(&s->vram, NULL, "tc6393xb.vram", 0x100000,
- &error_fatal);
- vmstate_register_ram_global(&s->vram);
- s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
- memory_region_add_subregion(sysmem, base + 0x100000, &s->vram);
- s->scr_width = 480;
- s->scr_height = 640;
- s->con = graphic_console_init(NULL, 0, &tc6393xb_gfx_ops, s);
-
- return s;
-}
diff --git a/qemu/hw/display/tc6393xb_template.h b/qemu/hw/display/tc6393xb_template.h
deleted file mode 100644
index 78629c07f..000000000
--- a/qemu/hw/display/tc6393xb_template.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Toshiba TC6393XB I/O Controller.
- * Found in Sharp Zaurus SL-6000 (tosa) or some
- * Toshiba e-Series PDAs.
- *
- * FB support code. Based on G364 fb emulator
- *
- * Copyright (c) 2007 Hervé Poussineau
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#if BITS == 8
-# define SET_PIXEL(addr, color) (*(uint8_t *)addr = color)
-#elif BITS == 15 || BITS == 16
-# define SET_PIXEL(addr, color) (*(uint16_t *)addr = color)
-#elif BITS == 24
-# define SET_PIXEL(addr, color) \
- do { \
- addr[0] = color; \
- addr[1] = (color) >> 8; \
- addr[2] = (color) >> 16; \
- } while (0)
-#elif BITS == 32
-# define SET_PIXEL(addr, color) (*(uint32_t *)addr = color)
-#else
-# error unknown bit depth
-#endif
-
-
-static void glue(tc6393xb_draw_graphic, BITS)(TC6393xbState *s)
-{
- DisplaySurface *surface = qemu_console_surface(s->con);
- int i;
- uint16_t *data_buffer;
- uint8_t *data_display;
-
- data_buffer = s->vram_ptr;
- data_display = surface_data(surface);
- for(i = 0; i < s->scr_height; i++) {
-#if (BITS == 16)
- memcpy(data_display, data_buffer, s->scr_width * 2);
- data_buffer += s->scr_width;
- data_display += surface_stride(surface);
-#else
- int j;
- for (j = 0; j < s->scr_width; j++, data_display += BITS / 8, data_buffer++) {
- uint16_t color = *data_buffer;
- uint32_t dest_color = glue(rgb_to_pixel, BITS)(
- ((color & 0xf800) * 0x108) >> 11,
- ((color & 0x7e0) * 0x41) >> 9,
- ((color & 0x1f) * 0x21) >> 2
- );
- SET_PIXEL(data_display, dest_color);
- }
-#endif
- }
-}
-
-#undef BITS
-#undef SET_PIXEL
diff --git a/qemu/hw/display/tcx.c b/qemu/hw/display/tcx.c
deleted file mode 100644
index 8e26aae80..000000000
--- a/qemu/hw/display/tcx.c
+++ /dev/null
@@ -1,1106 +0,0 @@
-/*
- * QEMU TCX Frame buffer
- *
- * Copyright (c) 2003-2005 Fabrice Bellard
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h" /* FIXME shouldn't use TARGET_PAGE_SIZE */
-#include "ui/console.h"
-#include "ui/pixel_ops.h"
-#include "hw/loader.h"
-#include "hw/sysbus.h"
-#include "qemu/error-report.h"
-
-#define TCX_ROM_FILE "QEMU,tcx.bin"
-#define FCODE_MAX_ROM_SIZE 0x10000
-
-#define MAXX 1024
-#define MAXY 768
-#define TCX_DAC_NREGS 16
-#define TCX_THC_NREGS 0x1000
-#define TCX_DHC_NREGS 0x4000
-#define TCX_TEC_NREGS 0x1000
-#define TCX_ALT_NREGS 0x8000
-#define TCX_STIP_NREGS 0x800000
-#define TCX_BLIT_NREGS 0x800000
-#define TCX_RSTIP_NREGS 0x800000
-#define TCX_RBLIT_NREGS 0x800000
-
-#define TCX_THC_MISC 0x818
-#define TCX_THC_CURSXY 0x8fc
-#define TCX_THC_CURSMASK 0x900
-#define TCX_THC_CURSBITS 0x980
-
-#define TYPE_TCX "SUNW,tcx"
-#define TCX(obj) OBJECT_CHECK(TCXState, (obj), TYPE_TCX)
-
-typedef struct TCXState {
- SysBusDevice parent_obj;
-
- QemuConsole *con;
- qemu_irq irq;
- uint8_t *vram;
- uint32_t *vram24, *cplane;
- hwaddr prom_addr;
- MemoryRegion rom;
- MemoryRegion vram_mem;
- MemoryRegion vram_8bit;
- MemoryRegion vram_24bit;
- MemoryRegion stip;
- MemoryRegion blit;
- MemoryRegion vram_cplane;
- MemoryRegion rstip;
- MemoryRegion rblit;
- MemoryRegion tec;
- MemoryRegion dac;
- MemoryRegion thc;
- MemoryRegion dhc;
- MemoryRegion alt;
- MemoryRegion thc24;
-
- ram_addr_t vram24_offset, cplane_offset;
- uint32_t tmpblit;
- uint32_t vram_size;
- uint32_t palette[260];
- uint8_t r[260], g[260], b[260];
- uint16_t width, height, depth;
- uint8_t dac_index, dac_state;
- uint32_t thcmisc;
- uint32_t cursmask[32];
- uint32_t cursbits[32];
- uint16_t cursx;
- uint16_t cursy;
-} TCXState;
-
-static void tcx_set_dirty(TCXState *s)
-{
- memory_region_set_dirty(&s->vram_mem, 0, MAXX * MAXY);
-}
-
-static inline int tcx24_check_dirty(TCXState *s, ram_addr_t page,
- ram_addr_t page24, ram_addr_t cpage)
-{
- int ret;
-
- ret = memory_region_get_dirty(&s->vram_mem, page, TARGET_PAGE_SIZE,
- DIRTY_MEMORY_VGA);
- ret |= memory_region_get_dirty(&s->vram_mem, page24, TARGET_PAGE_SIZE * 4,
- DIRTY_MEMORY_VGA);
- ret |= memory_region_get_dirty(&s->vram_mem, cpage, TARGET_PAGE_SIZE * 4,
- DIRTY_MEMORY_VGA);
- return ret;
-}
-
-static inline void tcx24_reset_dirty(TCXState *ts, ram_addr_t page_min,
- ram_addr_t page_max, ram_addr_t page24,
- ram_addr_t cpage)
-{
- memory_region_reset_dirty(&ts->vram_mem,
- page_min,
- (page_max - page_min) + TARGET_PAGE_SIZE,
- DIRTY_MEMORY_VGA);
- memory_region_reset_dirty(&ts->vram_mem,
- page24 + page_min * 4,
- (page_max - page_min) * 4 + TARGET_PAGE_SIZE,
- DIRTY_MEMORY_VGA);
- memory_region_reset_dirty(&ts->vram_mem,
- cpage + page_min * 4,
- (page_max - page_min) * 4 + TARGET_PAGE_SIZE,
- DIRTY_MEMORY_VGA);
-}
-
-static void update_palette_entries(TCXState *s, int start, int end)
-{
- DisplaySurface *surface = qemu_console_surface(s->con);
- int i;
-
- for (i = start; i < end; i++) {
- switch (surface_bits_per_pixel(surface)) {
- default:
- case 8:
- s->palette[i] = rgb_to_pixel8(s->r[i], s->g[i], s->b[i]);
- break;
- case 15:
- s->palette[i] = rgb_to_pixel15(s->r[i], s->g[i], s->b[i]);
- break;
- case 16:
- s->palette[i] = rgb_to_pixel16(s->r[i], s->g[i], s->b[i]);
- break;
- case 32:
- if (is_surface_bgr(surface)) {
- s->palette[i] = rgb_to_pixel32bgr(s->r[i], s->g[i], s->b[i]);
- } else {
- s->palette[i] = rgb_to_pixel32(s->r[i], s->g[i], s->b[i]);
- }
- break;
- }
- }
- tcx_set_dirty(s);
-}
-
-static void tcx_draw_line32(TCXState *s1, uint8_t *d,
- const uint8_t *s, int width)
-{
- int x;
- uint8_t val;
- uint32_t *p = (uint32_t *)d;
-
- for (x = 0; x < width; x++) {
- val = *s++;
- *p++ = s1->palette[val];
- }
-}
-
-static void tcx_draw_line16(TCXState *s1, uint8_t *d,
- const uint8_t *s, int width)
-{
- int x;
- uint8_t val;
- uint16_t *p = (uint16_t *)d;
-
- for (x = 0; x < width; x++) {
- val = *s++;
- *p++ = s1->palette[val];
- }
-}
-
-static void tcx_draw_line8(TCXState *s1, uint8_t *d,
- const uint8_t *s, int width)
-{
- int x;
- uint8_t val;
-
- for(x = 0; x < width; x++) {
- val = *s++;
- *d++ = s1->palette[val];
- }
-}
-
-static void tcx_draw_cursor32(TCXState *s1, uint8_t *d,
- int y, int width)
-{
- int x, len;
- uint32_t mask, bits;
- uint32_t *p = (uint32_t *)d;
-
- y = y - s1->cursy;
- mask = s1->cursmask[y];
- bits = s1->cursbits[y];
- len = MIN(width - s1->cursx, 32);
- p = &p[s1->cursx];
- for (x = 0; x < len; x++) {
- if (mask & 0x80000000) {
- if (bits & 0x80000000) {
- *p = s1->palette[259];
- } else {
- *p = s1->palette[258];
- }
- }
- p++;
- mask <<= 1;
- bits <<= 1;
- }
-}
-
-static void tcx_draw_cursor16(TCXState *s1, uint8_t *d,
- int y, int width)
-{
- int x, len;
- uint32_t mask, bits;
- uint16_t *p = (uint16_t *)d;
-
- y = y - s1->cursy;
- mask = s1->cursmask[y];
- bits = s1->cursbits[y];
- len = MIN(width - s1->cursx, 32);
- p = &p[s1->cursx];
- for (x = 0; x < len; x++) {
- if (mask & 0x80000000) {
- if (bits & 0x80000000) {
- *p = s1->palette[259];
- } else {
- *p = s1->palette[258];
- }
- }
- p++;
- mask <<= 1;
- bits <<= 1;
- }
-}
-
-static void tcx_draw_cursor8(TCXState *s1, uint8_t *d,
- int y, int width)
-{
- int x, len;
- uint32_t mask, bits;
-
- y = y - s1->cursy;
- mask = s1->cursmask[y];
- bits = s1->cursbits[y];
- len = MIN(width - s1->cursx, 32);
- d = &d[s1->cursx];
- for (x = 0; x < len; x++) {
- if (mask & 0x80000000) {
- if (bits & 0x80000000) {
- *d = s1->palette[259];
- } else {
- *d = s1->palette[258];
- }
- }
- d++;
- mask <<= 1;
- bits <<= 1;
- }
-}
-
-/*
- XXX Could be much more optimal:
- * detect if line/page/whole screen is in 24 bit mode
- * if destination is also BGR, use memcpy
- */
-static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d,
- const uint8_t *s, int width,
- const uint32_t *cplane,
- const uint32_t *s24)
-{
- DisplaySurface *surface = qemu_console_surface(s1->con);
- int x, bgr, r, g, b;
- uint8_t val, *p8;
- uint32_t *p = (uint32_t *)d;
- uint32_t dval;
- bgr = is_surface_bgr(surface);
- for(x = 0; x < width; x++, s++, s24++) {
- if (be32_to_cpu(*cplane) & 0x03000000) {
- /* 24-bit direct, BGR order */
- p8 = (uint8_t *)s24;
- p8++;
- b = *p8++;
- g = *p8++;
- r = *p8;
- if (bgr)
- dval = rgb_to_pixel32bgr(r, g, b);
- else
- dval = rgb_to_pixel32(r, g, b);
- } else {
- /* 8-bit pseudocolor */
- val = *s;
- dval = s1->palette[val];
- }
- *p++ = dval;
- cplane++;
- }
-}
-
-/* Fixed line length 1024 allows us to do nice tricks not possible on
- VGA... */
-
-static void tcx_update_display(void *opaque)
-{
- TCXState *ts = opaque;
- DisplaySurface *surface = qemu_console_surface(ts->con);
- ram_addr_t page, page_min, page_max;
- int y, y_start, dd, ds;
- uint8_t *d, *s;
- void (*f)(TCXState *s1, uint8_t *dst, const uint8_t *src, int width);
- void (*fc)(TCXState *s1, uint8_t *dst, int y, int width);
-
- if (surface_bits_per_pixel(surface) == 0) {
- return;
- }
-
- page = 0;
- y_start = -1;
- page_min = -1;
- page_max = 0;
- d = surface_data(surface);
- s = ts->vram;
- dd = surface_stride(surface);
- ds = 1024;
-
- switch (surface_bits_per_pixel(surface)) {
- case 32:
- f = tcx_draw_line32;
- fc = tcx_draw_cursor32;
- break;
- case 15:
- case 16:
- f = tcx_draw_line16;
- fc = tcx_draw_cursor16;
- break;
- default:
- case 8:
- f = tcx_draw_line8;
- fc = tcx_draw_cursor8;
- break;
- case 0:
- return;
- }
-
- memory_region_sync_dirty_bitmap(&ts->vram_mem);
- for (y = 0; y < ts->height; page += TARGET_PAGE_SIZE) {
- if (memory_region_get_dirty(&ts->vram_mem, page, TARGET_PAGE_SIZE,
- DIRTY_MEMORY_VGA)) {
- if (y_start < 0)
- y_start = y;
- if (page < page_min)
- page_min = page;
- if (page > page_max)
- page_max = page;
-
- f(ts, d, s, ts->width);
- if (y >= ts->cursy && y < ts->cursy + 32 && ts->cursx < ts->width) {
- fc(ts, d, y, ts->width);
- }
- d += dd;
- s += ds;
- y++;
-
- f(ts, d, s, ts->width);
- if (y >= ts->cursy && y < ts->cursy + 32 && ts->cursx < ts->width) {
- fc(ts, d, y, ts->width);
- }
- d += dd;
- s += ds;
- y++;
-
- f(ts, d, s, ts->width);
- if (y >= ts->cursy && y < ts->cursy + 32 && ts->cursx < ts->width) {
- fc(ts, d, y, ts->width);
- }
- d += dd;
- s += ds;
- y++;
-
- f(ts, d, s, ts->width);
- if (y >= ts->cursy && y < ts->cursy + 32 && ts->cursx < ts->width) {
- fc(ts, d, y, ts->width);
- }
- d += dd;
- s += ds;
- y++;
- } else {
- if (y_start >= 0) {
- /* flush to display */
- dpy_gfx_update(ts->con, 0, y_start,
- ts->width, y - y_start);
- y_start = -1;
- }
- d += dd * 4;
- s += ds * 4;
- y += 4;
- }
- }
- if (y_start >= 0) {
- /* flush to display */
- dpy_gfx_update(ts->con, 0, y_start,
- ts->width, y - y_start);
- }
- /* reset modified pages */
- if (page_max >= page_min) {
- memory_region_reset_dirty(&ts->vram_mem,
- page_min,
- (page_max - page_min) + TARGET_PAGE_SIZE,
- DIRTY_MEMORY_VGA);
- }
-}
-
-static void tcx24_update_display(void *opaque)
-{
- TCXState *ts = opaque;
- DisplaySurface *surface = qemu_console_surface(ts->con);
- ram_addr_t page, page_min, page_max, cpage, page24;
- int y, y_start, dd, ds;
- uint8_t *d, *s;
- uint32_t *cptr, *s24;
-
- if (surface_bits_per_pixel(surface) != 32) {
- return;
- }
-
- page = 0;
- page24 = ts->vram24_offset;
- cpage = ts->cplane_offset;
- y_start = -1;
- page_min = -1;
- page_max = 0;
- d = surface_data(surface);
- s = ts->vram;
- s24 = ts->vram24;
- cptr = ts->cplane;
- dd = surface_stride(surface);
- ds = 1024;
-
- memory_region_sync_dirty_bitmap(&ts->vram_mem);
- for (y = 0; y < ts->height; page += TARGET_PAGE_SIZE,
- page24 += TARGET_PAGE_SIZE, cpage += TARGET_PAGE_SIZE) {
- if (tcx24_check_dirty(ts, page, page24, cpage)) {
- if (y_start < 0)
- y_start = y;
- if (page < page_min)
- page_min = page;
- if (page > page_max)
- page_max = page;
- tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
- if (y >= ts->cursy && y < ts->cursy+32 && ts->cursx < ts->width) {
- tcx_draw_cursor32(ts, d, y, ts->width);
- }
- d += dd;
- s += ds;
- cptr += ds;
- s24 += ds;
- y++;
- tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
- if (y >= ts->cursy && y < ts->cursy+32 && ts->cursx < ts->width) {
- tcx_draw_cursor32(ts, d, y, ts->width);
- }
- d += dd;
- s += ds;
- cptr += ds;
- s24 += ds;
- y++;
- tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
- if (y >= ts->cursy && y < ts->cursy+32 && ts->cursx < ts->width) {
- tcx_draw_cursor32(ts, d, y, ts->width);
- }
- d += dd;
- s += ds;
- cptr += ds;
- s24 += ds;
- y++;
- tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
- if (y >= ts->cursy && y < ts->cursy+32 && ts->cursx < ts->width) {
- tcx_draw_cursor32(ts, d, y, ts->width);
- }
- d += dd;
- s += ds;
- cptr += ds;
- s24 += ds;
- y++;
- } else {
- if (y_start >= 0) {
- /* flush to display */
- dpy_gfx_update(ts->con, 0, y_start,
- ts->width, y - y_start);
- y_start = -1;
- }
- d += dd * 4;
- s += ds * 4;
- cptr += ds * 4;
- s24 += ds * 4;
- y += 4;
- }
- }
- if (y_start >= 0) {
- /* flush to display */
- dpy_gfx_update(ts->con, 0, y_start,
- ts->width, y - y_start);
- }
- /* reset modified pages */
- if (page_max >= page_min) {
- tcx24_reset_dirty(ts, page_min, page_max, page24, cpage);
- }
-}
-
-static void tcx_invalidate_display(void *opaque)
-{
- TCXState *s = opaque;
-
- tcx_set_dirty(s);
- qemu_console_resize(s->con, s->width, s->height);
-}
-
-static void tcx24_invalidate_display(void *opaque)
-{
- TCXState *s = opaque;
-
- tcx_set_dirty(s);
- qemu_console_resize(s->con, s->width, s->height);
-}
-
-static int vmstate_tcx_post_load(void *opaque, int version_id)
-{
- TCXState *s = opaque;
-
- update_palette_entries(s, 0, 256);
- tcx_set_dirty(s);
- return 0;
-}
-
-static const VMStateDescription vmstate_tcx = {
- .name ="tcx",
- .version_id = 4,
- .minimum_version_id = 4,
- .post_load = vmstate_tcx_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT16(height, TCXState),
- VMSTATE_UINT16(width, TCXState),
- VMSTATE_UINT16(depth, TCXState),
- VMSTATE_BUFFER(r, TCXState),
- VMSTATE_BUFFER(g, TCXState),
- VMSTATE_BUFFER(b, TCXState),
- VMSTATE_UINT8(dac_index, TCXState),
- VMSTATE_UINT8(dac_state, TCXState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void tcx_reset(DeviceState *d)
-{
- TCXState *s = TCX(d);
-
- /* Initialize palette */
- memset(s->r, 0, 260);
- memset(s->g, 0, 260);
- memset(s->b, 0, 260);
- s->r[255] = s->g[255] = s->b[255] = 255;
- s->r[256] = s->g[256] = s->b[256] = 255;
- s->r[258] = s->g[258] = s->b[258] = 255;
- update_palette_entries(s, 0, 260);
- memset(s->vram, 0, MAXX*MAXY);
- memory_region_reset_dirty(&s->vram_mem, 0, MAXX * MAXY * (1 + 4 + 4),
- DIRTY_MEMORY_VGA);
- s->dac_index = 0;
- s->dac_state = 0;
- s->cursx = 0xf000; /* Put cursor off screen */
- s->cursy = 0xf000;
-}
-
-static uint64_t tcx_dac_readl(void *opaque, hwaddr addr,
- unsigned size)
-{
- TCXState *s = opaque;
- uint32_t val = 0;
-
- switch (s->dac_state) {
- case 0:
- val = s->r[s->dac_index] << 24;
- s->dac_state++;
- break;
- case 1:
- val = s->g[s->dac_index] << 24;
- s->dac_state++;
- break;
- case 2:
- val = s->b[s->dac_index] << 24;
- s->dac_index = (s->dac_index + 1) & 0xff; /* Index autoincrement */
- default:
- s->dac_state = 0;
- break;
- }
-
- return val;
-}
-
-static void tcx_dac_writel(void *opaque, hwaddr addr, uint64_t val,
- unsigned size)
-{
- TCXState *s = opaque;
- unsigned index;
-
- switch (addr) {
- case 0: /* Address */
- s->dac_index = val >> 24;
- s->dac_state = 0;
- break;
- case 4: /* Pixel colours */
- case 12: /* Overlay (cursor) colours */
- if (addr & 8) {
- index = (s->dac_index & 3) + 256;
- } else {
- index = s->dac_index;
- }
- switch (s->dac_state) {
- case 0:
- s->r[index] = val >> 24;
- update_palette_entries(s, index, index + 1);
- s->dac_state++;
- break;
- case 1:
- s->g[index] = val >> 24;
- update_palette_entries(s, index, index + 1);
- s->dac_state++;
- break;
- case 2:
- s->b[index] = val >> 24;
- update_palette_entries(s, index, index + 1);
- s->dac_index = (s->dac_index + 1) & 0xff; /* Index autoincrement */
- default:
- s->dac_state = 0;
- break;
- }
- break;
- default: /* Control registers */
- break;
- }
-}
-
-static const MemoryRegionOps tcx_dac_ops = {
- .read = tcx_dac_readl,
- .write = tcx_dac_writel,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static uint64_t tcx_stip_readl(void *opaque, hwaddr addr,
- unsigned size)
-{
- return 0;
-}
-
-static void tcx_stip_writel(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- TCXState *s = opaque;
- int i;
- uint32_t col;
-
- if (!(addr & 4)) {
- s->tmpblit = val;
- } else {
- addr = (addr >> 3) & 0xfffff;
- col = cpu_to_be32(s->tmpblit);
- if (s->depth == 24) {
- for (i = 0; i < 32; i++) {
- if (val & 0x80000000) {
- s->vram[addr + i] = s->tmpblit;
- s->vram24[addr + i] = col;
- }
- val <<= 1;
- }
- } else {
- for (i = 0; i < 32; i++) {
- if (val & 0x80000000) {
- s->vram[addr + i] = s->tmpblit;
- }
- val <<= 1;
- }
- }
- memory_region_set_dirty(&s->vram_mem, addr, 32);
- }
-}
-
-static void tcx_rstip_writel(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- TCXState *s = opaque;
- int i;
- uint32_t col;
-
- if (!(addr & 4)) {
- s->tmpblit = val;
- } else {
- addr = (addr >> 3) & 0xfffff;
- col = cpu_to_be32(s->tmpblit);
- if (s->depth == 24) {
- for (i = 0; i < 32; i++) {
- if (val & 0x80000000) {
- s->vram[addr + i] = s->tmpblit;
- s->vram24[addr + i] = col;
- s->cplane[addr + i] = col;
- }
- val <<= 1;
- }
- } else {
- for (i = 0; i < 32; i++) {
- if (val & 0x80000000) {
- s->vram[addr + i] = s->tmpblit;
- }
- val <<= 1;
- }
- }
- memory_region_set_dirty(&s->vram_mem, addr, 32);
- }
-}
-
-static const MemoryRegionOps tcx_stip_ops = {
- .read = tcx_stip_readl,
- .write = tcx_stip_writel,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static const MemoryRegionOps tcx_rstip_ops = {
- .read = tcx_stip_readl,
- .write = tcx_rstip_writel,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static uint64_t tcx_blit_readl(void *opaque, hwaddr addr,
- unsigned size)
-{
- return 0;
-}
-
-static void tcx_blit_writel(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- TCXState *s = opaque;
- uint32_t adsr, len;
- int i;
-
- if (!(addr & 4)) {
- s->tmpblit = val;
- } else {
- addr = (addr >> 3) & 0xfffff;
- adsr = val & 0xffffff;
- len = ((val >> 24) & 0x1f) + 1;
- if (adsr == 0xffffff) {
- memset(&s->vram[addr], s->tmpblit, len);
- if (s->depth == 24) {
- val = s->tmpblit & 0xffffff;
- val = cpu_to_be32(val);
- for (i = 0; i < len; i++) {
- s->vram24[addr + i] = val;
- }
- }
- } else {
- memcpy(&s->vram[addr], &s->vram[adsr], len);
- if (s->depth == 24) {
- memcpy(&s->vram24[addr], &s->vram24[adsr], len * 4);
- }
- }
- memory_region_set_dirty(&s->vram_mem, addr, len);
- }
-}
-
-static void tcx_rblit_writel(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- TCXState *s = opaque;
- uint32_t adsr, len;
- int i;
-
- if (!(addr & 4)) {
- s->tmpblit = val;
- } else {
- addr = (addr >> 3) & 0xfffff;
- adsr = val & 0xffffff;
- len = ((val >> 24) & 0x1f) + 1;
- if (adsr == 0xffffff) {
- memset(&s->vram[addr], s->tmpblit, len);
- if (s->depth == 24) {
- val = s->tmpblit & 0xffffff;
- val = cpu_to_be32(val);
- for (i = 0; i < len; i++) {
- s->vram24[addr + i] = val;
- s->cplane[addr + i] = val;
- }
- }
- } else {
- memcpy(&s->vram[addr], &s->vram[adsr], len);
- if (s->depth == 24) {
- memcpy(&s->vram24[addr], &s->vram24[adsr], len * 4);
- memcpy(&s->cplane[addr], &s->cplane[adsr], len * 4);
- }
- }
- memory_region_set_dirty(&s->vram_mem, addr, len);
- }
-}
-
-static const MemoryRegionOps tcx_blit_ops = {
- .read = tcx_blit_readl,
- .write = tcx_blit_writel,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static const MemoryRegionOps tcx_rblit_ops = {
- .read = tcx_blit_readl,
- .write = tcx_rblit_writel,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static void tcx_invalidate_cursor_position(TCXState *s)
-{
- int ymin, ymax, start, end;
-
- /* invalidate only near the cursor */
- ymin = s->cursy;
- if (ymin >= s->height) {
- return;
- }
- ymax = MIN(s->height, ymin + 32);
- start = ymin * 1024;
- end = ymax * 1024;
-
- memory_region_set_dirty(&s->vram_mem, start, end-start);
-}
-
-static uint64_t tcx_thc_readl(void *opaque, hwaddr addr,
- unsigned size)
-{
- TCXState *s = opaque;
- uint64_t val;
-
- if (addr == TCX_THC_MISC) {
- val = s->thcmisc | 0x02000000;
- } else {
- val = 0;
- }
- return val;
-}
-
-static void tcx_thc_writel(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- TCXState *s = opaque;
-
- if (addr == TCX_THC_CURSXY) {
- tcx_invalidate_cursor_position(s);
- s->cursx = val >> 16;
- s->cursy = val;
- tcx_invalidate_cursor_position(s);
- } else if (addr >= TCX_THC_CURSMASK && addr < TCX_THC_CURSMASK + 128) {
- s->cursmask[(addr - TCX_THC_CURSMASK) >> 2] = val;
- tcx_invalidate_cursor_position(s);
- } else if (addr >= TCX_THC_CURSBITS && addr < TCX_THC_CURSBITS + 128) {
- s->cursbits[(addr - TCX_THC_CURSBITS) >> 2] = val;
- tcx_invalidate_cursor_position(s);
- } else if (addr == TCX_THC_MISC) {
- s->thcmisc = val;
- }
-
-}
-
-static const MemoryRegionOps tcx_thc_ops = {
- .read = tcx_thc_readl,
- .write = tcx_thc_writel,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static uint64_t tcx_dummy_readl(void *opaque, hwaddr addr,
- unsigned size)
-{
- return 0;
-}
-
-static void tcx_dummy_writel(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- return;
-}
-
-static const MemoryRegionOps tcx_dummy_ops = {
- .read = tcx_dummy_readl,
- .write = tcx_dummy_writel,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static const GraphicHwOps tcx_ops = {
- .invalidate = tcx_invalidate_display,
- .gfx_update = tcx_update_display,
-};
-
-static const GraphicHwOps tcx24_ops = {
- .invalidate = tcx24_invalidate_display,
- .gfx_update = tcx24_update_display,
-};
-
-static void tcx_initfn(Object *obj)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- TCXState *s = TCX(obj);
-
- memory_region_init_ram(&s->rom, obj, "tcx.prom", FCODE_MAX_ROM_SIZE,
- &error_fatal);
- memory_region_set_readonly(&s->rom, true);
- sysbus_init_mmio(sbd, &s->rom);
-
- /* 2/STIP : Stippler */
- memory_region_init_io(&s->stip, obj, &tcx_stip_ops, s, "tcx.stip",
- TCX_STIP_NREGS);
- sysbus_init_mmio(sbd, &s->stip);
-
- /* 3/BLIT : Blitter */
- memory_region_init_io(&s->blit, obj, &tcx_blit_ops, s, "tcx.blit",
- TCX_BLIT_NREGS);
- sysbus_init_mmio(sbd, &s->blit);
-
- /* 5/RSTIP : Raw Stippler */
- memory_region_init_io(&s->rstip, obj, &tcx_rstip_ops, s, "tcx.rstip",
- TCX_RSTIP_NREGS);
- sysbus_init_mmio(sbd, &s->rstip);
-
- /* 6/RBLIT : Raw Blitter */
- memory_region_init_io(&s->rblit, obj, &tcx_rblit_ops, s, "tcx.rblit",
- TCX_RBLIT_NREGS);
- sysbus_init_mmio(sbd, &s->rblit);
-
- /* 7/TEC : ??? */
- memory_region_init_io(&s->tec, obj, &tcx_dummy_ops, s, "tcx.tec",
- TCX_TEC_NREGS);
- sysbus_init_mmio(sbd, &s->tec);
-
- /* 8/CMAP : DAC */
- memory_region_init_io(&s->dac, obj, &tcx_dac_ops, s, "tcx.dac",
- TCX_DAC_NREGS);
- sysbus_init_mmio(sbd, &s->dac);
-
- /* 9/THC : Cursor */
- memory_region_init_io(&s->thc, obj, &tcx_thc_ops, s, "tcx.thc",
- TCX_THC_NREGS);
- sysbus_init_mmio(sbd, &s->thc);
-
- /* 11/DHC : ??? */
- memory_region_init_io(&s->dhc, obj, &tcx_dummy_ops, s, "tcx.dhc",
- TCX_DHC_NREGS);
- sysbus_init_mmio(sbd, &s->dhc);
-
- /* 12/ALT : ??? */
- memory_region_init_io(&s->alt, obj, &tcx_dummy_ops, s, "tcx.alt",
- TCX_ALT_NREGS);
- sysbus_init_mmio(sbd, &s->alt);
-}
-
-static void tcx_realizefn(DeviceState *dev, Error **errp)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- TCXState *s = TCX(dev);
- ram_addr_t vram_offset = 0;
- int size, ret;
- uint8_t *vram_base;
- char *fcode_filename;
-
- memory_region_init_ram(&s->vram_mem, OBJECT(s), "tcx.vram",
- s->vram_size * (1 + 4 + 4), &error_fatal);
- vmstate_register_ram_global(&s->vram_mem);
- memory_region_set_log(&s->vram_mem, true, DIRTY_MEMORY_VGA);
- vram_base = memory_region_get_ram_ptr(&s->vram_mem);
-
- /* 10/ROM : FCode ROM */
- vmstate_register_ram_global(&s->rom);
- fcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, TCX_ROM_FILE);
- if (fcode_filename) {
- ret = load_image_targphys(fcode_filename, s->prom_addr,
- FCODE_MAX_ROM_SIZE);
- g_free(fcode_filename);
- if (ret < 0 || ret > FCODE_MAX_ROM_SIZE) {
- error_report("tcx: could not load prom '%s'", TCX_ROM_FILE);
- }
- }
-
- /* 0/DFB8 : 8-bit plane */
- s->vram = vram_base;
- size = s->vram_size;
- memory_region_init_alias(&s->vram_8bit, OBJECT(s), "tcx.vram.8bit",
- &s->vram_mem, vram_offset, size);
- sysbus_init_mmio(sbd, &s->vram_8bit);
- vram_offset += size;
- vram_base += size;
-
- /* 1/DFB24 : 24bit plane */
- size = s->vram_size * 4;
- s->vram24 = (uint32_t *)vram_base;
- s->vram24_offset = vram_offset;
- memory_region_init_alias(&s->vram_24bit, OBJECT(s), "tcx.vram.24bit",
- &s->vram_mem, vram_offset, size);
- sysbus_init_mmio(sbd, &s->vram_24bit);
- vram_offset += size;
- vram_base += size;
-
- /* 4/RDFB32 : Raw Framebuffer */
- size = s->vram_size * 4;
- s->cplane = (uint32_t *)vram_base;
- s->cplane_offset = vram_offset;
- memory_region_init_alias(&s->vram_cplane, OBJECT(s), "tcx.vram.cplane",
- &s->vram_mem, vram_offset, size);
- sysbus_init_mmio(sbd, &s->vram_cplane);
-
- /* 9/THC24bits : NetBSD writes here even with 8-bit display: dummy */
- if (s->depth == 8) {
- memory_region_init_io(&s->thc24, OBJECT(s), &tcx_dummy_ops, s,
- "tcx.thc24", TCX_THC_NREGS);
- sysbus_init_mmio(sbd, &s->thc24);
- }
-
- sysbus_init_irq(sbd, &s->irq);
-
- if (s->depth == 8) {
- s->con = graphic_console_init(DEVICE(dev), 0, &tcx_ops, s);
- } else {
- s->con = graphic_console_init(DEVICE(dev), 0, &tcx24_ops, s);
- }
- s->thcmisc = 0;
-
- qemu_console_resize(s->con, s->width, s->height);
-}
-
-static Property tcx_properties[] = {
- DEFINE_PROP_UINT32("vram_size", TCXState, vram_size, -1),
- DEFINE_PROP_UINT16("width", TCXState, width, -1),
- DEFINE_PROP_UINT16("height", TCXState, height, -1),
- DEFINE_PROP_UINT16("depth", TCXState, depth, -1),
- DEFINE_PROP_UINT64("prom_addr", TCXState, prom_addr, -1),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void tcx_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = tcx_realizefn;
- dc->reset = tcx_reset;
- dc->vmsd = &vmstate_tcx;
- dc->props = tcx_properties;
-}
-
-static const TypeInfo tcx_info = {
- .name = TYPE_TCX,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(TCXState),
- .instance_init = tcx_initfn,
- .class_init = tcx_class_init,
-};
-
-static void tcx_register_types(void)
-{
- type_register_static(&tcx_info);
-}
-
-type_init(tcx_register_types)
diff --git a/qemu/hw/display/vga-helpers.h b/qemu/hw/display/vga-helpers.h
deleted file mode 100644
index 94f6de204..000000000
--- a/qemu/hw/display/vga-helpers.h
+++ /dev/null
@@ -1,439 +0,0 @@
-/*
- * QEMU VGA Emulator templates
- *
- * Copyright (c) 2003 Fabrice Bellard
- *
- * 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.
- */
-
-static inline void vga_draw_glyph_line(uint8_t *d, uint32_t font_data,
- uint32_t xorcol, uint32_t bgcol)
-{
- ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
- ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
- ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
- ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
- ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
- ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
- ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
- ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
-}
-
-static void vga_draw_glyph8(uint8_t *d, int linesize,
- const uint8_t *font_ptr, int h,
- uint32_t fgcol, uint32_t bgcol)
-{
- uint32_t font_data, xorcol;
-
- xorcol = bgcol ^ fgcol;
- do {
- font_data = font_ptr[0];
- vga_draw_glyph_line(d, font_data, xorcol, bgcol);
- font_ptr += 4;
- d += linesize;
- } while (--h);
-}
-
-static void vga_draw_glyph16(uint8_t *d, int linesize,
- const uint8_t *font_ptr, int h,
- uint32_t fgcol, uint32_t bgcol)
-{
- uint32_t font_data, xorcol;
-
- xorcol = bgcol ^ fgcol;
- do {
- font_data = font_ptr[0];
- vga_draw_glyph_line(d, expand4to8[font_data >> 4],
- xorcol, bgcol);
- vga_draw_glyph_line(d + 32, expand4to8[font_data & 0x0f],
- xorcol, bgcol);
- font_ptr += 4;
- d += linesize;
- } while (--h);
-}
-
-static void vga_draw_glyph9(uint8_t *d, int linesize,
- const uint8_t *font_ptr, int h,
- uint32_t fgcol, uint32_t bgcol, int dup9)
-{
- uint32_t font_data, xorcol, v;
-
- xorcol = bgcol ^ fgcol;
- do {
- font_data = font_ptr[0];
- ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
- ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
- ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
- ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
- ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
- ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
- ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
- v = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
- ((uint32_t *)d)[7] = v;
- if (dup9)
- ((uint32_t *)d)[8] = v;
- else
- ((uint32_t *)d)[8] = bgcol;
- font_ptr += 4;
- d += linesize;
- } while (--h);
-}
-
-/*
- * 4 color mode
- */
-static void vga_draw_line2(VGACommonState *s1, uint8_t *d,
- const uint8_t *s, int width)
-{
- uint32_t plane_mask, *palette, data, v;
- int x;
-
- palette = s1->last_palette;
- plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
- width >>= 3;
- for(x = 0; x < width; x++) {
- data = ((uint32_t *)s)[0];
- data &= plane_mask;
- v = expand2[GET_PLANE(data, 0)];
- v |= expand2[GET_PLANE(data, 2)] << 2;
- ((uint32_t *)d)[0] = palette[v >> 12];
- ((uint32_t *)d)[1] = palette[(v >> 8) & 0xf];
- ((uint32_t *)d)[2] = palette[(v >> 4) & 0xf];
- ((uint32_t *)d)[3] = palette[(v >> 0) & 0xf];
-
- v = expand2[GET_PLANE(data, 1)];
- v |= expand2[GET_PLANE(data, 3)] << 2;
- ((uint32_t *)d)[4] = palette[v >> 12];
- ((uint32_t *)d)[5] = palette[(v >> 8) & 0xf];
- ((uint32_t *)d)[6] = palette[(v >> 4) & 0xf];
- ((uint32_t *)d)[7] = palette[(v >> 0) & 0xf];
- d += 32;
- s += 4;
- }
-}
-
-#define PUT_PIXEL2(d, n, v) \
-((uint32_t *)d)[2*(n)] = ((uint32_t *)d)[2*(n)+1] = (v)
-
-/*
- * 4 color mode, dup2 horizontal
- */
-static void vga_draw_line2d2(VGACommonState *s1, uint8_t *d,
- const uint8_t *s, int width)
-{
- uint32_t plane_mask, *palette, data, v;
- int x;
-
- palette = s1->last_palette;
- plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
- width >>= 3;
- for(x = 0; x < width; x++) {
- data = ((uint32_t *)s)[0];
- data &= plane_mask;
- v = expand2[GET_PLANE(data, 0)];
- v |= expand2[GET_PLANE(data, 2)] << 2;
- PUT_PIXEL2(d, 0, palette[v >> 12]);
- PUT_PIXEL2(d, 1, palette[(v >> 8) & 0xf]);
- PUT_PIXEL2(d, 2, palette[(v >> 4) & 0xf]);
- PUT_PIXEL2(d, 3, palette[(v >> 0) & 0xf]);
-
- v = expand2[GET_PLANE(data, 1)];
- v |= expand2[GET_PLANE(data, 3)] << 2;
- PUT_PIXEL2(d, 4, palette[v >> 12]);
- PUT_PIXEL2(d, 5, palette[(v >> 8) & 0xf]);
- PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]);
- PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]);
- d += 64;
- s += 4;
- }
-}
-
-/*
- * 16 color mode
- */
-static void vga_draw_line4(VGACommonState *s1, uint8_t *d,
- const uint8_t *s, int width)
-{
- uint32_t plane_mask, data, v, *palette;
- int x;
-
- palette = s1->last_palette;
- plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
- width >>= 3;
- for(x = 0; x < width; x++) {
- data = ((uint32_t *)s)[0];
- data &= plane_mask;
- v = expand4[GET_PLANE(data, 0)];
- v |= expand4[GET_PLANE(data, 1)] << 1;
- v |= expand4[GET_PLANE(data, 2)] << 2;
- v |= expand4[GET_PLANE(data, 3)] << 3;
- ((uint32_t *)d)[0] = palette[v >> 28];
- ((uint32_t *)d)[1] = palette[(v >> 24) & 0xf];
- ((uint32_t *)d)[2] = palette[(v >> 20) & 0xf];
- ((uint32_t *)d)[3] = palette[(v >> 16) & 0xf];
- ((uint32_t *)d)[4] = palette[(v >> 12) & 0xf];
- ((uint32_t *)d)[5] = palette[(v >> 8) & 0xf];
- ((uint32_t *)d)[6] = palette[(v >> 4) & 0xf];
- ((uint32_t *)d)[7] = palette[(v >> 0) & 0xf];
- d += 32;
- s += 4;
- }
-}
-
-/*
- * 16 color mode, dup2 horizontal
- */
-static void vga_draw_line4d2(VGACommonState *s1, uint8_t *d,
- const uint8_t *s, int width)
-{
- uint32_t plane_mask, data, v, *palette;
- int x;
-
- palette = s1->last_palette;
- plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
- width >>= 3;
- for(x = 0; x < width; x++) {
- data = ((uint32_t *)s)[0];
- data &= plane_mask;
- v = expand4[GET_PLANE(data, 0)];
- v |= expand4[GET_PLANE(data, 1)] << 1;
- v |= expand4[GET_PLANE(data, 2)] << 2;
- v |= expand4[GET_PLANE(data, 3)] << 3;
- PUT_PIXEL2(d, 0, palette[v >> 28]);
- PUT_PIXEL2(d, 1, palette[(v >> 24) & 0xf]);
- PUT_PIXEL2(d, 2, palette[(v >> 20) & 0xf]);
- PUT_PIXEL2(d, 3, palette[(v >> 16) & 0xf]);
- PUT_PIXEL2(d, 4, palette[(v >> 12) & 0xf]);
- PUT_PIXEL2(d, 5, palette[(v >> 8) & 0xf]);
- PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]);
- PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]);
- d += 64;
- s += 4;
- }
-}
-
-/*
- * 256 color mode, double pixels
- *
- * XXX: add plane_mask support (never used in standard VGA modes)
- */
-static void vga_draw_line8d2(VGACommonState *s1, uint8_t *d,
- const uint8_t *s, int width)
-{
- uint32_t *palette;
- int x;
-
- palette = s1->last_palette;
- width >>= 3;
- for(x = 0; x < width; x++) {
- PUT_PIXEL2(d, 0, palette[s[0]]);
- PUT_PIXEL2(d, 1, palette[s[1]]);
- PUT_PIXEL2(d, 2, palette[s[2]]);
- PUT_PIXEL2(d, 3, palette[s[3]]);
- d += 32;
- s += 4;
- }
-}
-
-/*
- * standard 256 color mode
- *
- * XXX: add plane_mask support (never used in standard VGA modes)
- */
-static void vga_draw_line8(VGACommonState *s1, uint8_t *d,
- const uint8_t *s, int width)
-{
- uint32_t *palette;
- int x;
-
- palette = s1->last_palette;
- width >>= 3;
- for(x = 0; x < width; x++) {
- ((uint32_t *)d)[0] = palette[s[0]];
- ((uint32_t *)d)[1] = palette[s[1]];
- ((uint32_t *)d)[2] = palette[s[2]];
- ((uint32_t *)d)[3] = palette[s[3]];
- ((uint32_t *)d)[4] = palette[s[4]];
- ((uint32_t *)d)[5] = palette[s[5]];
- ((uint32_t *)d)[6] = palette[s[6]];
- ((uint32_t *)d)[7] = palette[s[7]];
- d += 32;
- s += 8;
- }
-}
-
-/*
- * 15 bit color
- */
-static void vga_draw_line15_le(VGACommonState *s1, uint8_t *d,
- const uint8_t *s, int width)
-{
- int w;
- uint32_t v, r, g, b;
-
- w = width;
- do {
- v = lduw_le_p((void *)s);
- r = (v >> 7) & 0xf8;
- g = (v >> 2) & 0xf8;
- b = (v << 3) & 0xf8;
- ((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b);
- s += 2;
- d += 4;
- } while (--w != 0);
-}
-
-static void vga_draw_line15_be(VGACommonState *s1, uint8_t *d,
- const uint8_t *s, int width)
-{
- int w;
- uint32_t v, r, g, b;
-
- w = width;
- do {
- v = lduw_be_p((void *)s);
- r = (v >> 7) & 0xf8;
- g = (v >> 2) & 0xf8;
- b = (v << 3) & 0xf8;
- ((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b);
- s += 2;
- d += 4;
- } while (--w != 0);
-}
-
-/*
- * 16 bit color
- */
-static void vga_draw_line16_le(VGACommonState *s1, uint8_t *d,
- const uint8_t *s, int width)
-{
- int w;
- uint32_t v, r, g, b;
-
- w = width;
- do {
- v = lduw_le_p((void *)s);
- r = (v >> 8) & 0xf8;
- g = (v >> 3) & 0xfc;
- b = (v << 3) & 0xf8;
- ((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b);
- s += 2;
- d += 4;
- } while (--w != 0);
-}
-
-static void vga_draw_line16_be(VGACommonState *s1, uint8_t *d,
- const uint8_t *s, int width)
-{
- int w;
- uint32_t v, r, g, b;
-
- w = width;
- do {
- v = lduw_be_p((void *)s);
- r = (v >> 8) & 0xf8;
- g = (v >> 3) & 0xfc;
- b = (v << 3) & 0xf8;
- ((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b);
- s += 2;
- d += 4;
- } while (--w != 0);
-}
-
-/*
- * 24 bit color
- */
-static void vga_draw_line24_le(VGACommonState *s1, uint8_t *d,
- const uint8_t *s, int width)
-{
- int w;
- uint32_t r, g, b;
-
- w = width;
- do {
- b = s[0];
- g = s[1];
- r = s[2];
- ((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b);
- s += 3;
- d += 4;
- } while (--w != 0);
-}
-
-static void vga_draw_line24_be(VGACommonState *s1, uint8_t *d,
- const uint8_t *s, int width)
-{
- int w;
- uint32_t r, g, b;
-
- w = width;
- do {
- r = s[0];
- g = s[1];
- b = s[2];
- ((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b);
- s += 3;
- d += 4;
- } while (--w != 0);
-}
-
-/*
- * 32 bit color
- */
-static void vga_draw_line32_le(VGACommonState *s1, uint8_t *d,
- const uint8_t *s, int width)
-{
-#ifndef HOST_WORDS_BIGENDIAN
- memcpy(d, s, width * 4);
-#else
- int w;
- uint32_t r, g, b;
-
- w = width;
- do {
- b = s[0];
- g = s[1];
- r = s[2];
- ((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b);
- s += 4;
- d += 4;
- } while (--w != 0);
-#endif
-}
-
-static void vga_draw_line32_be(VGACommonState *s1, uint8_t *d,
- const uint8_t *s, int width)
-{
-#ifdef HOST_WORDS_BIGENDIAN
- memcpy(d, s, width * 4);
-#else
- int w;
- uint32_t r, g, b;
-
- w = width;
- do {
- r = s[1];
- g = s[2];
- b = s[3];
- ((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b);
- s += 4;
- d += 4;
- } while (--w != 0);
-#endif
-}
diff --git a/qemu/hw/display/vga-isa-mm.c b/qemu/hw/display/vga-isa-mm.c
deleted file mode 100644
index 51ccbccc4..000000000
--- a/qemu/hw/display/vga-isa-mm.c
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * QEMU ISA MM VGA Emulator.
- *
- * Copyright (c) 2003 Fabrice Bellard
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "ui/console.h"
-#include "hw/i386/pc.h"
-#include "vga_int.h"
-#include "ui/pixel_ops.h"
-#include "qemu/timer.h"
-
-#define VGA_RAM_SIZE (8192 * 1024)
-
-typedef struct ISAVGAMMState {
- VGACommonState vga;
- int it_shift;
-} ISAVGAMMState;
-
-/* Memory mapped interface */
-static uint32_t vga_mm_readb (void *opaque, hwaddr addr)
-{
- ISAVGAMMState *s = opaque;
-
- return vga_ioport_read(&s->vga, addr >> s->it_shift) & 0xff;
-}
-
-static void vga_mm_writeb (void *opaque,
- hwaddr addr, uint32_t value)
-{
- ISAVGAMMState *s = opaque;
-
- vga_ioport_write(&s->vga, addr >> s->it_shift, value & 0xff);
-}
-
-static uint32_t vga_mm_readw (void *opaque, hwaddr addr)
-{
- ISAVGAMMState *s = opaque;
-
- return vga_ioport_read(&s->vga, addr >> s->it_shift) & 0xffff;
-}
-
-static void vga_mm_writew (void *opaque,
- hwaddr addr, uint32_t value)
-{
- ISAVGAMMState *s = opaque;
-
- vga_ioport_write(&s->vga, addr >> s->it_shift, value & 0xffff);
-}
-
-static uint32_t vga_mm_readl (void *opaque, hwaddr addr)
-{
- ISAVGAMMState *s = opaque;
-
- return vga_ioport_read(&s->vga, addr >> s->it_shift);
-}
-
-static void vga_mm_writel (void *opaque,
- hwaddr addr, uint32_t value)
-{
- ISAVGAMMState *s = opaque;
-
- vga_ioport_write(&s->vga, addr >> s->it_shift, value);
-}
-
-static const MemoryRegionOps vga_mm_ctrl_ops = {
- .old_mmio = {
- .read = {
- vga_mm_readb,
- vga_mm_readw,
- vga_mm_readl,
- },
- .write = {
- vga_mm_writeb,
- vga_mm_writew,
- vga_mm_writel,
- },
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void vga_mm_init(ISAVGAMMState *s, hwaddr vram_base,
- hwaddr ctrl_base, int it_shift,
- MemoryRegion *address_space)
-{
- MemoryRegion *s_ioport_ctrl, *vga_io_memory;
-
- s->it_shift = it_shift;
- s_ioport_ctrl = g_malloc(sizeof(*s_ioport_ctrl));
- memory_region_init_io(s_ioport_ctrl, NULL, &vga_mm_ctrl_ops, s,
- "vga-mm-ctrl", 0x100000);
- memory_region_set_flush_coalesced(s_ioport_ctrl);
-
- vga_io_memory = g_malloc(sizeof(*vga_io_memory));
- /* XXX: endianness? */
- memory_region_init_io(vga_io_memory, NULL, &vga_mem_ops, &s->vga,
- "vga-mem", 0x20000);
-
- vmstate_register(NULL, 0, &vmstate_vga_common, s);
-
- memory_region_add_subregion(address_space, ctrl_base, s_ioport_ctrl);
- s->vga.bank_offset = 0;
- memory_region_add_subregion(address_space,
- vram_base + 0x000a0000, vga_io_memory);
- memory_region_set_coalescing(vga_io_memory);
-}
-
-int isa_vga_mm_init(hwaddr vram_base,
- hwaddr ctrl_base, int it_shift,
- MemoryRegion *address_space)
-{
- ISAVGAMMState *s;
-
- s = g_malloc0(sizeof(*s));
-
- s->vga.vram_size_mb = VGA_RAM_SIZE >> 20;
- vga_common_init(&s->vga, NULL, true);
- vga_mm_init(s, vram_base, ctrl_base, it_shift, address_space);
-
- s->vga.con = graphic_console_init(NULL, 0, s->vga.hw_ops, s);
-
- vga_init_vbe(&s->vga, NULL, address_space);
- return 0;
-}
diff --git a/qemu/hw/display/vga-isa.c b/qemu/hw/display/vga-isa.c
deleted file mode 100644
index f5aff1cbe..000000000
--- a/qemu/hw/display/vga-isa.c
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * QEMU ISA VGA Emulator.
- *
- * see docs/specs/standard-vga.txt for virtual hardware specs.
- *
- * Copyright (c) 2003 Fabrice Bellard
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "ui/console.h"
-#include "hw/i386/pc.h"
-#include "vga_int.h"
-#include "ui/pixel_ops.h"
-#include "qemu/timer.h"
-#include "hw/loader.h"
-
-#define TYPE_ISA_VGA "isa-vga"
-#define ISA_VGA(obj) OBJECT_CHECK(ISAVGAState, (obj), TYPE_ISA_VGA)
-
-typedef struct ISAVGAState {
- ISADevice parent_obj;
-
- struct VGACommonState state;
-} ISAVGAState;
-
-static void vga_isa_reset(DeviceState *dev)
-{
- ISAVGAState *d = ISA_VGA(dev);
- VGACommonState *s = &d->state;
-
- vga_common_reset(s);
-}
-
-static void vga_isa_realizefn(DeviceState *dev, Error **errp)
-{
- ISADevice *isadev = ISA_DEVICE(dev);
- ISAVGAState *d = ISA_VGA(dev);
- VGACommonState *s = &d->state;
- MemoryRegion *vga_io_memory;
- const MemoryRegionPortio *vga_ports, *vbe_ports;
-
- vga_common_init(s, OBJECT(dev), true);
- s->legacy_address_space = isa_address_space(isadev);
- vga_io_memory = vga_init_io(s, OBJECT(dev), &vga_ports, &vbe_ports);
- isa_register_portio_list(isadev, 0x3b0, vga_ports, s, "vga");
- if (vbe_ports) {
- isa_register_portio_list(isadev, 0x1ce, vbe_ports, s, "vbe");
- }
- memory_region_add_subregion_overlap(isa_address_space(isadev),
- 0x000a0000,
- vga_io_memory, 1);
- memory_region_set_coalescing(vga_io_memory);
- s->con = graphic_console_init(DEVICE(dev), 0, s->hw_ops, s);
-
- vga_init_vbe(s, OBJECT(dev), isa_address_space(isadev));
- /* ROM BIOS */
- rom_add_vga(VGABIOS_FILENAME);
-}
-
-static Property vga_isa_properties[] = {
- DEFINE_PROP_UINT32("vgamem_mb", ISAVGAState, state.vram_size_mb, 8),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void vga_isa_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = vga_isa_realizefn;
- dc->reset = vga_isa_reset;
- dc->vmsd = &vmstate_vga_common;
- dc->props = vga_isa_properties;
- set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
-}
-
-static const TypeInfo vga_isa_info = {
- .name = TYPE_ISA_VGA,
- .parent = TYPE_ISA_DEVICE,
- .instance_size = sizeof(ISAVGAState),
- .class_init = vga_isa_class_initfn,
-};
-
-static void vga_isa_register_types(void)
-{
- type_register_static(&vga_isa_info);
-}
-
-type_init(vga_isa_register_types)
diff --git a/qemu/hw/display/vga-pci.c b/qemu/hw/display/vga-pci.c
deleted file mode 100644
index ac9a76499..000000000
--- a/qemu/hw/display/vga-pci.c
+++ /dev/null
@@ -1,387 +0,0 @@
-/*
- * QEMU PCI VGA Emulator.
- *
- * see docs/specs/standard-vga.txt for virtual hardware specs.
- *
- * Copyright (c) 2003 Fabrice Bellard
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "ui/console.h"
-#include "hw/pci/pci.h"
-#include "vga_int.h"
-#include "ui/pixel_ops.h"
-#include "qemu/timer.h"
-#include "hw/loader.h"
-
-#define PCI_VGA_IOPORT_OFFSET 0x400
-#define PCI_VGA_IOPORT_SIZE (0x3e0 - 0x3c0)
-#define PCI_VGA_BOCHS_OFFSET 0x500
-#define PCI_VGA_BOCHS_SIZE (0x0b * 2)
-#define PCI_VGA_QEXT_OFFSET 0x600
-#define PCI_VGA_QEXT_SIZE (2 * 4)
-#define PCI_VGA_MMIO_SIZE 0x1000
-
-#define PCI_VGA_QEXT_REG_SIZE (0 * 4)
-#define PCI_VGA_QEXT_REG_BYTEORDER (1 * 4)
-#define PCI_VGA_QEXT_LITTLE_ENDIAN 0x1e1e1e1e
-#define PCI_VGA_QEXT_BIG_ENDIAN 0xbebebebe
-
-enum vga_pci_flags {
- PCI_VGA_FLAG_ENABLE_MMIO = 1,
- PCI_VGA_FLAG_ENABLE_QEXT = 2,
-};
-
-typedef struct PCIVGAState {
- PCIDevice dev;
- VGACommonState vga;
- uint32_t flags;
- MemoryRegion mmio;
- MemoryRegion mrs[3];
-} PCIVGAState;
-
-#define TYPE_PCI_VGA "pci-vga"
-#define PCI_VGA(obj) OBJECT_CHECK(PCIVGAState, (obj), TYPE_PCI_VGA)
-
-static const VMStateDescription vmstate_vga_pci = {
- .name = "vga",
- .version_id = 2,
- .minimum_version_id = 2,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(dev, PCIVGAState),
- VMSTATE_STRUCT(vga, PCIVGAState, 0, vmstate_vga_common, VGACommonState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static uint64_t pci_vga_ioport_read(void *ptr, hwaddr addr,
- unsigned size)
-{
- VGACommonState *s = ptr;
- uint64_t ret = 0;
-
- switch (size) {
- case 1:
- ret = vga_ioport_read(s, addr + 0x3c0);
- break;
- case 2:
- ret = vga_ioport_read(s, addr + 0x3c0);
- ret |= vga_ioport_read(s, addr + 0x3c1) << 8;
- break;
- }
- return ret;
-}
-
-static void pci_vga_ioport_write(void *ptr, hwaddr addr,
- uint64_t val, unsigned size)
-{
- VGACommonState *s = ptr;
-
- switch (size) {
- case 1:
- vga_ioport_write(s, addr + 0x3c0, val);
- break;
- case 2:
- /*
- * Update bytes in little endian order. Allows to update
- * indexed registers with a single word write because the
- * index byte is updated first.
- */
- vga_ioport_write(s, addr + 0x3c0, val & 0xff);
- vga_ioport_write(s, addr + 0x3c1, (val >> 8) & 0xff);
- break;
- }
-}
-
-static const MemoryRegionOps pci_vga_ioport_ops = {
- .read = pci_vga_ioport_read,
- .write = pci_vga_ioport_write,
- .valid.min_access_size = 1,
- .valid.max_access_size = 4,
- .impl.min_access_size = 1,
- .impl.max_access_size = 2,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static uint64_t pci_vga_bochs_read(void *ptr, hwaddr addr,
- unsigned size)
-{
- VGACommonState *s = ptr;
- int index = addr >> 1;
-
- vbe_ioport_write_index(s, 0, index);
- return vbe_ioport_read_data(s, 0);
-}
-
-static void pci_vga_bochs_write(void *ptr, hwaddr addr,
- uint64_t val, unsigned size)
-{
- VGACommonState *s = ptr;
- int index = addr >> 1;
-
- vbe_ioport_write_index(s, 0, index);
- vbe_ioport_write_data(s, 0, val);
-}
-
-static const MemoryRegionOps pci_vga_bochs_ops = {
- .read = pci_vga_bochs_read,
- .write = pci_vga_bochs_write,
- .valid.min_access_size = 1,
- .valid.max_access_size = 4,
- .impl.min_access_size = 2,
- .impl.max_access_size = 2,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static uint64_t pci_vga_qext_read(void *ptr, hwaddr addr, unsigned size)
-{
- VGACommonState *s = ptr;
-
- switch (addr) {
- case PCI_VGA_QEXT_REG_SIZE:
- return PCI_VGA_QEXT_SIZE;
- case PCI_VGA_QEXT_REG_BYTEORDER:
- return s->big_endian_fb ?
- PCI_VGA_QEXT_BIG_ENDIAN : PCI_VGA_QEXT_LITTLE_ENDIAN;
- default:
- return 0;
- }
-}
-
-static void pci_vga_qext_write(void *ptr, hwaddr addr,
- uint64_t val, unsigned size)
-{
- VGACommonState *s = ptr;
-
- switch (addr) {
- case PCI_VGA_QEXT_REG_BYTEORDER:
- if (val == PCI_VGA_QEXT_BIG_ENDIAN) {
- s->big_endian_fb = true;
- }
- if (val == PCI_VGA_QEXT_LITTLE_ENDIAN) {
- s->big_endian_fb = false;
- }
- break;
- }
-}
-
-static bool vga_get_big_endian_fb(Object *obj, Error **errp)
-{
- PCIVGAState *d = PCI_VGA(PCI_DEVICE(obj));
-
- return d->vga.big_endian_fb;
-}
-
-static void vga_set_big_endian_fb(Object *obj, bool value, Error **errp)
-{
- PCIVGAState *d = PCI_VGA(PCI_DEVICE(obj));
-
- d->vga.big_endian_fb = value;
-}
-
-static const MemoryRegionOps pci_vga_qext_ops = {
- .read = pci_vga_qext_read,
- .write = pci_vga_qext_write,
- .valid.min_access_size = 4,
- .valid.max_access_size = 4,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-void pci_std_vga_mmio_region_init(VGACommonState *s,
- MemoryRegion *parent,
- MemoryRegion *subs,
- bool qext)
-{
- memory_region_init_io(&subs[0], NULL, &pci_vga_ioport_ops, s,
- "vga ioports remapped", PCI_VGA_IOPORT_SIZE);
- memory_region_add_subregion(parent, PCI_VGA_IOPORT_OFFSET,
- &subs[0]);
-
- memory_region_init_io(&subs[1], NULL, &pci_vga_bochs_ops, s,
- "bochs dispi interface", PCI_VGA_BOCHS_SIZE);
- memory_region_add_subregion(parent, PCI_VGA_BOCHS_OFFSET,
- &subs[1]);
-
- if (qext) {
- memory_region_init_io(&subs[2], NULL, &pci_vga_qext_ops, s,
- "qemu extended regs", PCI_VGA_QEXT_SIZE);
- memory_region_add_subregion(parent, PCI_VGA_QEXT_OFFSET,
- &subs[2]);
- }
-}
-
-static void pci_std_vga_realize(PCIDevice *dev, Error **errp)
-{
- PCIVGAState *d = PCI_VGA(dev);
- VGACommonState *s = &d->vga;
- bool qext = false;
-
- /* vga + console init */
- vga_common_init(s, OBJECT(dev), true);
- vga_init(s, OBJECT(dev), pci_address_space(dev), pci_address_space_io(dev),
- true);
-
- s->con = graphic_console_init(DEVICE(dev), 0, s->hw_ops, s);
-
- /* XXX: VGA_RAM_SIZE must be a power of two */
- pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram);
-
- /* mmio bar for vga register access */
- if (d->flags & (1 << PCI_VGA_FLAG_ENABLE_MMIO)) {
- memory_region_init(&d->mmio, NULL, "vga.mmio", 4096);
-
- if (d->flags & (1 << PCI_VGA_FLAG_ENABLE_QEXT)) {
- qext = true;
- pci_set_byte(&d->dev.config[PCI_REVISION_ID], 2);
- }
- pci_std_vga_mmio_region_init(s, &d->mmio, d->mrs, qext);
-
- pci_register_bar(&d->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio);
- }
-
- if (!dev->rom_bar) {
- /* compatibility with pc-0.13 and older */
- vga_init_vbe(s, OBJECT(dev), pci_address_space(dev));
- }
-}
-
-static void pci_std_vga_init(Object *obj)
-{
- /* Expose framebuffer byteorder via QOM */
- object_property_add_bool(obj, "big-endian-framebuffer",
- vga_get_big_endian_fb, vga_set_big_endian_fb, NULL);
-}
-
-static void pci_secondary_vga_realize(PCIDevice *dev, Error **errp)
-{
- PCIVGAState *d = PCI_VGA(dev);
- VGACommonState *s = &d->vga;
- bool qext = false;
-
- /* vga + console init */
- vga_common_init(s, OBJECT(dev), false);
- s->con = graphic_console_init(DEVICE(dev), 0, s->hw_ops, s);
-
- /* mmio bar */
- memory_region_init(&d->mmio, OBJECT(dev), "vga.mmio", 4096);
-
- if (d->flags & (1 << PCI_VGA_FLAG_ENABLE_QEXT)) {
- qext = true;
- pci_set_byte(&d->dev.config[PCI_REVISION_ID], 2);
- }
- pci_std_vga_mmio_region_init(s, &d->mmio, d->mrs, qext);
-
- pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram);
- pci_register_bar(&d->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio);
-}
-
-static void pci_secondary_vga_init(Object *obj)
-{
- /* Expose framebuffer byteorder via QOM */
- object_property_add_bool(obj, "big-endian-framebuffer",
- vga_get_big_endian_fb, vga_set_big_endian_fb, NULL);
-}
-
-static void pci_secondary_vga_reset(DeviceState *dev)
-{
- PCIVGAState *d = PCI_VGA(PCI_DEVICE(dev));
- vga_common_reset(&d->vga);
-}
-
-static Property vga_pci_properties[] = {
- DEFINE_PROP_UINT32("vgamem_mb", PCIVGAState, vga.vram_size_mb, 16),
- DEFINE_PROP_BIT("mmio", PCIVGAState, flags, PCI_VGA_FLAG_ENABLE_MMIO, true),
- DEFINE_PROP_BIT("qemu-extended-regs",
- PCIVGAState, flags, PCI_VGA_FLAG_ENABLE_QEXT, true),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static Property secondary_pci_properties[] = {
- DEFINE_PROP_UINT32("vgamem_mb", PCIVGAState, vga.vram_size_mb, 16),
- DEFINE_PROP_BIT("qemu-extended-regs",
- PCIVGAState, flags, PCI_VGA_FLAG_ENABLE_QEXT, true),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void vga_pci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->vendor_id = PCI_VENDOR_ID_QEMU;
- k->device_id = PCI_DEVICE_ID_QEMU_VGA;
- dc->vmsd = &vmstate_vga_pci;
- set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
-}
-
-static const TypeInfo vga_pci_type_info = {
- .name = TYPE_PCI_VGA,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(PCIVGAState),
- .abstract = true,
- .class_init = vga_pci_class_init,
-};
-
-static void vga_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = pci_std_vga_realize;
- k->romfile = "vgabios-stdvga.bin";
- k->class_id = PCI_CLASS_DISPLAY_VGA;
- dc->props = vga_pci_properties;
- dc->hotpluggable = false;
-}
-
-static void secondary_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = pci_secondary_vga_realize;
- k->class_id = PCI_CLASS_DISPLAY_OTHER;
- dc->props = secondary_pci_properties;
- dc->reset = pci_secondary_vga_reset;
-}
-
-static const TypeInfo vga_info = {
- .name = "VGA",
- .parent = TYPE_PCI_VGA,
- .instance_init = pci_std_vga_init,
- .class_init = vga_class_init,
-};
-
-static const TypeInfo secondary_info = {
- .name = "secondary-vga",
- .parent = TYPE_PCI_VGA,
- .instance_init = pci_secondary_vga_init,
- .class_init = secondary_class_init,
-};
-
-static void vga_register_types(void)
-{
- type_register_static(&vga_pci_type_info);
- type_register_static(&vga_info);
- type_register_static(&secondary_info);
-}
-
-type_init(vga_register_types)
diff --git a/qemu/hw/display/vga.c b/qemu/hw/display/vga.c
deleted file mode 100644
index 4a55ec6db..000000000
--- a/qemu/hw/display/vga.c
+++ /dev/null
@@ -1,2289 +0,0 @@
-/*
- * QEMU VGA Emulator.
- *
- * Copyright (c) 2003 Fabrice Bellard
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/hw.h"
-#include "vga.h"
-#include "ui/console.h"
-#include "hw/i386/pc.h"
-#include "hw/pci/pci.h"
-#include "vga_int.h"
-#include "ui/pixel_ops.h"
-#include "qemu/timer.h"
-#include "hw/xen/xen.h"
-#include "trace.h"
-
-//#define DEBUG_VGA
-//#define DEBUG_VGA_MEM
-//#define DEBUG_VGA_REG
-
-//#define DEBUG_BOCHS_VBE
-
-/* 16 state changes per vertical frame @60 Hz */
-#define VGA_TEXT_CURSOR_PERIOD_MS (1000 * 2 * 16 / 60)
-
-/*
- * Video Graphics Array (VGA)
- *
- * Chipset docs for original IBM VGA:
- * http://www.mcamafia.de/pdf/ibm_vgaxga_trm2.pdf
- *
- * FreeVGA site:
- * http://www.osdever.net/FreeVGA/home.htm
- *
- * Standard VGA features and Bochs VBE extensions are implemented.
- */
-
-/* force some bits to zero */
-const uint8_t sr_mask[8] = {
- 0x03,
- 0x3d,
- 0x0f,
- 0x3f,
- 0x0e,
- 0x00,
- 0x00,
- 0xff,
-};
-
-const uint8_t gr_mask[16] = {
- 0x0f, /* 0x00 */
- 0x0f, /* 0x01 */
- 0x0f, /* 0x02 */
- 0x1f, /* 0x03 */
- 0x03, /* 0x04 */
- 0x7b, /* 0x05 */
- 0x0f, /* 0x06 */
- 0x0f, /* 0x07 */
- 0xff, /* 0x08 */
- 0x00, /* 0x09 */
- 0x00, /* 0x0a */
- 0x00, /* 0x0b */
- 0x00, /* 0x0c */
- 0x00, /* 0x0d */
- 0x00, /* 0x0e */
- 0x00, /* 0x0f */
-};
-
-#define cbswap_32(__x) \
-((uint32_t)( \
- (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
- (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
- (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
- (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
-
-#ifdef HOST_WORDS_BIGENDIAN
-#define PAT(x) cbswap_32(x)
-#else
-#define PAT(x) (x)
-#endif
-
-#ifdef HOST_WORDS_BIGENDIAN
-#define BIG 1
-#else
-#define BIG 0
-#endif
-
-#ifdef HOST_WORDS_BIGENDIAN
-#define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
-#else
-#define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
-#endif
-
-static const uint32_t mask16[16] = {
- PAT(0x00000000),
- PAT(0x000000ff),
- PAT(0x0000ff00),
- PAT(0x0000ffff),
- PAT(0x00ff0000),
- PAT(0x00ff00ff),
- PAT(0x00ffff00),
- PAT(0x00ffffff),
- PAT(0xff000000),
- PAT(0xff0000ff),
- PAT(0xff00ff00),
- PAT(0xff00ffff),
- PAT(0xffff0000),
- PAT(0xffff00ff),
- PAT(0xffffff00),
- PAT(0xffffffff),
-};
-
-#undef PAT
-
-#ifdef HOST_WORDS_BIGENDIAN
-#define PAT(x) (x)
-#else
-#define PAT(x) cbswap_32(x)
-#endif
-
-static uint32_t expand4[256];
-static uint16_t expand2[256];
-static uint8_t expand4to8[16];
-
-static void vbe_update_vgaregs(VGACommonState *s);
-
-static inline bool vbe_enabled(VGACommonState *s)
-{
- return s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED;
-}
-
-static void vga_update_memory_access(VGACommonState *s)
-{
- hwaddr base, offset, size;
-
- if (s->legacy_address_space == NULL) {
- return;
- }
-
- if (s->has_chain4_alias) {
- memory_region_del_subregion(s->legacy_address_space, &s->chain4_alias);
- object_unparent(OBJECT(&s->chain4_alias));
- s->has_chain4_alias = false;
- s->plane_updated = 0xf;
- }
- if ((s->sr[VGA_SEQ_PLANE_WRITE] & VGA_SR02_ALL_PLANES) ==
- VGA_SR02_ALL_PLANES && s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
- offset = 0;
- switch ((s->gr[VGA_GFX_MISC] >> 2) & 3) {
- case 0:
- base = 0xa0000;
- size = 0x20000;
- break;
- case 1:
- base = 0xa0000;
- size = 0x10000;
- offset = s->bank_offset;
- break;
- case 2:
- base = 0xb0000;
- size = 0x8000;
- break;
- case 3:
- default:
- base = 0xb8000;
- size = 0x8000;
- break;
- }
- assert(offset + size <= s->vram_size);
- memory_region_init_alias(&s->chain4_alias, memory_region_owner(&s->vram),
- "vga.chain4", &s->vram, offset, size);
- memory_region_add_subregion_overlap(s->legacy_address_space, base,
- &s->chain4_alias, 2);
- s->has_chain4_alias = true;
- }
-}
-
-static void vga_dumb_update_retrace_info(VGACommonState *s)
-{
- (void) s;
-}
-
-static void vga_precise_update_retrace_info(VGACommonState *s)
-{
- int htotal_chars;
- int hretr_start_char;
- int hretr_skew_chars;
- int hretr_end_char;
-
- int vtotal_lines;
- int vretr_start_line;
- int vretr_end_line;
-
- int dots;
-#if 0
- int div2, sldiv2;
-#endif
- int clocking_mode;
- int clock_sel;
- const int clk_hz[] = {25175000, 28322000, 25175000, 25175000};
- int64_t chars_per_sec;
- struct vga_precise_retrace *r = &s->retrace_info.precise;
-
- htotal_chars = s->cr[VGA_CRTC_H_TOTAL] + 5;
- hretr_start_char = s->cr[VGA_CRTC_H_SYNC_START];
- hretr_skew_chars = (s->cr[VGA_CRTC_H_SYNC_END] >> 5) & 3;
- hretr_end_char = s->cr[VGA_CRTC_H_SYNC_END] & 0x1f;
-
- vtotal_lines = (s->cr[VGA_CRTC_V_TOTAL] |
- (((s->cr[VGA_CRTC_OVERFLOW] & 1) |
- ((s->cr[VGA_CRTC_OVERFLOW] >> 4) & 2)) << 8)) + 2;
- vretr_start_line = s->cr[VGA_CRTC_V_SYNC_START] |
- ((((s->cr[VGA_CRTC_OVERFLOW] >> 2) & 1) |
- ((s->cr[VGA_CRTC_OVERFLOW] >> 6) & 2)) << 8);
- vretr_end_line = s->cr[VGA_CRTC_V_SYNC_END] & 0xf;
-
- clocking_mode = (s->sr[VGA_SEQ_CLOCK_MODE] >> 3) & 1;
- clock_sel = (s->msr >> 2) & 3;
- dots = (s->msr & 1) ? 8 : 9;
-
- chars_per_sec = clk_hz[clock_sel] / dots;
-
- htotal_chars <<= clocking_mode;
-
- r->total_chars = vtotal_lines * htotal_chars;
- if (r->freq) {
- r->ticks_per_char = NANOSECONDS_PER_SECOND / (r->total_chars * r->freq);
- } else {
- r->ticks_per_char = NANOSECONDS_PER_SECOND / chars_per_sec;
- }
-
- r->vstart = vretr_start_line;
- r->vend = r->vstart + vretr_end_line + 1;
-
- r->hstart = hretr_start_char + hretr_skew_chars;
- r->hend = r->hstart + hretr_end_char + 1;
- r->htotal = htotal_chars;
-
-#if 0
- div2 = (s->cr[VGA_CRTC_MODE] >> 2) & 1;
- sldiv2 = (s->cr[VGA_CRTC_MODE] >> 3) & 1;
- printf (
- "hz=%f\n"
- "htotal = %d\n"
- "hretr_start = %d\n"
- "hretr_skew = %d\n"
- "hretr_end = %d\n"
- "vtotal = %d\n"
- "vretr_start = %d\n"
- "vretr_end = %d\n"
- "div2 = %d sldiv2 = %d\n"
- "clocking_mode = %d\n"
- "clock_sel = %d %d\n"
- "dots = %d\n"
- "ticks/char = %" PRId64 "\n"
- "\n",
- (double) NANOSECONDS_PER_SECOND / (r->ticks_per_char * r->total_chars),
- htotal_chars,
- hretr_start_char,
- hretr_skew_chars,
- hretr_end_char,
- vtotal_lines,
- vretr_start_line,
- vretr_end_line,
- div2, sldiv2,
- clocking_mode,
- clock_sel,
- clk_hz[clock_sel],
- dots,
- r->ticks_per_char
- );
-#endif
-}
-
-static uint8_t vga_precise_retrace(VGACommonState *s)
-{
- struct vga_precise_retrace *r = &s->retrace_info.precise;
- uint8_t val = s->st01 & ~(ST01_V_RETRACE | ST01_DISP_ENABLE);
-
- if (r->total_chars) {
- int cur_line, cur_line_char, cur_char;
- int64_t cur_tick;
-
- cur_tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-
- cur_char = (cur_tick / r->ticks_per_char) % r->total_chars;
- cur_line = cur_char / r->htotal;
-
- if (cur_line >= r->vstart && cur_line <= r->vend) {
- val |= ST01_V_RETRACE | ST01_DISP_ENABLE;
- } else {
- cur_line_char = cur_char % r->htotal;
- if (cur_line_char >= r->hstart && cur_line_char <= r->hend) {
- val |= ST01_DISP_ENABLE;
- }
- }
-
- return val;
- } else {
- return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
- }
-}
-
-static uint8_t vga_dumb_retrace(VGACommonState *s)
-{
- return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
-}
-
-int vga_ioport_invalid(VGACommonState *s, uint32_t addr)
-{
- if (s->msr & VGA_MIS_COLOR) {
- /* Color */
- return (addr >= 0x3b0 && addr <= 0x3bf);
- } else {
- /* Monochrome */
- return (addr >= 0x3d0 && addr <= 0x3df);
- }
-}
-
-uint32_t vga_ioport_read(void *opaque, uint32_t addr)
-{
- VGACommonState *s = opaque;
- int val, index;
-
- if (vga_ioport_invalid(s, addr)) {
- val = 0xff;
- } else {
- switch(addr) {
- case VGA_ATT_W:
- if (s->ar_flip_flop == 0) {
- val = s->ar_index;
- } else {
- val = 0;
- }
- break;
- case VGA_ATT_R:
- index = s->ar_index & 0x1f;
- if (index < VGA_ATT_C) {
- val = s->ar[index];
- } else {
- val = 0;
- }
- break;
- case VGA_MIS_W:
- val = s->st00;
- break;
- case VGA_SEQ_I:
- val = s->sr_index;
- break;
- case VGA_SEQ_D:
- val = s->sr[s->sr_index];
-#ifdef DEBUG_VGA_REG
- printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
-#endif
- break;
- case VGA_PEL_IR:
- val = s->dac_state;
- break;
- case VGA_PEL_IW:
- val = s->dac_write_index;
- break;
- case VGA_PEL_D:
- val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
- if (++s->dac_sub_index == 3) {
- s->dac_sub_index = 0;
- s->dac_read_index++;
- }
- break;
- case VGA_FTC_R:
- val = s->fcr;
- break;
- case VGA_MIS_R:
- val = s->msr;
- break;
- case VGA_GFX_I:
- val = s->gr_index;
- break;
- case VGA_GFX_D:
- val = s->gr[s->gr_index];
-#ifdef DEBUG_VGA_REG
- printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
-#endif
- break;
- case VGA_CRT_IM:
- case VGA_CRT_IC:
- val = s->cr_index;
- break;
- case VGA_CRT_DM:
- case VGA_CRT_DC:
- val = s->cr[s->cr_index];
-#ifdef DEBUG_VGA_REG
- printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
-#endif
- break;
- case VGA_IS1_RM:
- case VGA_IS1_RC:
- /* just toggle to fool polling */
- val = s->st01 = s->retrace(s);
- s->ar_flip_flop = 0;
- break;
- default:
- val = 0x00;
- break;
- }
- }
-#if defined(DEBUG_VGA)
- printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
-#endif
- return val;
-}
-
-void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
-{
- VGACommonState *s = opaque;
- int index;
-
- /* check port range access depending on color/monochrome mode */
- if (vga_ioport_invalid(s, addr)) {
- return;
- }
-#ifdef DEBUG_VGA
- printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
-#endif
-
- switch(addr) {
- case VGA_ATT_W:
- if (s->ar_flip_flop == 0) {
- val &= 0x3f;
- s->ar_index = val;
- } else {
- index = s->ar_index & 0x1f;
- switch(index) {
- case VGA_ATC_PALETTE0 ... VGA_ATC_PALETTEF:
- s->ar[index] = val & 0x3f;
- break;
- case VGA_ATC_MODE:
- s->ar[index] = val & ~0x10;
- break;
- case VGA_ATC_OVERSCAN:
- s->ar[index] = val;
- break;
- case VGA_ATC_PLANE_ENABLE:
- s->ar[index] = val & ~0xc0;
- break;
- case VGA_ATC_PEL:
- s->ar[index] = val & ~0xf0;
- break;
- case VGA_ATC_COLOR_PAGE:
- s->ar[index] = val & ~0xf0;
- break;
- default:
- break;
- }
- }
- s->ar_flip_flop ^= 1;
- break;
- case VGA_MIS_W:
- s->msr = val & ~0x10;
- s->update_retrace_info(s);
- break;
- case VGA_SEQ_I:
- s->sr_index = val & 7;
- break;
- case VGA_SEQ_D:
-#ifdef DEBUG_VGA_REG
- printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
-#endif
- s->sr[s->sr_index] = val & sr_mask[s->sr_index];
- vbe_update_vgaregs(s);
- if (s->sr_index == VGA_SEQ_CLOCK_MODE) {
- s->update_retrace_info(s);
- }
- vga_update_memory_access(s);
- break;
- case VGA_PEL_IR:
- s->dac_read_index = val;
- s->dac_sub_index = 0;
- s->dac_state = 3;
- break;
- case VGA_PEL_IW:
- s->dac_write_index = val;
- s->dac_sub_index = 0;
- s->dac_state = 0;
- break;
- case VGA_PEL_D:
- s->dac_cache[s->dac_sub_index] = val;
- if (++s->dac_sub_index == 3) {
- memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
- s->dac_sub_index = 0;
- s->dac_write_index++;
- }
- break;
- case VGA_GFX_I:
- s->gr_index = val & 0x0f;
- break;
- case VGA_GFX_D:
-#ifdef DEBUG_VGA_REG
- printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
-#endif
- s->gr[s->gr_index] = val & gr_mask[s->gr_index];
- vbe_update_vgaregs(s);
- vga_update_memory_access(s);
- break;
- case VGA_CRT_IM:
- case VGA_CRT_IC:
- s->cr_index = val;
- break;
- case VGA_CRT_DM:
- case VGA_CRT_DC:
-#ifdef DEBUG_VGA_REG
- printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
-#endif
- /* handle CR0-7 protection */
- if ((s->cr[VGA_CRTC_V_SYNC_END] & VGA_CR11_LOCK_CR0_CR7) &&
- s->cr_index <= VGA_CRTC_OVERFLOW) {
- /* can always write bit 4 of CR7 */
- if (s->cr_index == VGA_CRTC_OVERFLOW) {
- s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x10) |
- (val & 0x10);
- vbe_update_vgaregs(s);
- }
- return;
- }
- s->cr[s->cr_index] = val;
- vbe_update_vgaregs(s);
-
- switch(s->cr_index) {
- case VGA_CRTC_H_TOTAL:
- case VGA_CRTC_H_SYNC_START:
- case VGA_CRTC_H_SYNC_END:
- case VGA_CRTC_V_TOTAL:
- case VGA_CRTC_OVERFLOW:
- case VGA_CRTC_V_SYNC_END:
- case VGA_CRTC_MODE:
- s->update_retrace_info(s);
- break;
- }
- break;
- case VGA_IS1_RM:
- case VGA_IS1_RC:
- s->fcr = val & 0x10;
- break;
- }
-}
-
-/*
- * Sanity check vbe register writes.
- *
- * As we don't have a way to signal errors to the guest in the bochs
- * dispi interface we'll go adjust the registers to the closest valid
- * value.
- */
-static void vbe_fixup_regs(VGACommonState *s)
-{
- uint16_t *r = s->vbe_regs;
- uint32_t bits, linelength, maxy, offset;
-
- if (!vbe_enabled(s)) {
- /* vbe is turned off -- nothing to do */
- return;
- }
-
- /* check depth */
- switch (r[VBE_DISPI_INDEX_BPP]) {
- case 4:
- case 8:
- case 16:
- case 24:
- case 32:
- bits = r[VBE_DISPI_INDEX_BPP];
- break;
- case 15:
- bits = 16;
- break;
- default:
- bits = r[VBE_DISPI_INDEX_BPP] = 8;
- break;
- }
-
- /* check width */
- r[VBE_DISPI_INDEX_XRES] &= ~7u;
- if (r[VBE_DISPI_INDEX_XRES] == 0) {
- r[VBE_DISPI_INDEX_XRES] = 8;
- }
- if (r[VBE_DISPI_INDEX_XRES] > VBE_DISPI_MAX_XRES) {
- r[VBE_DISPI_INDEX_XRES] = VBE_DISPI_MAX_XRES;
- }
- r[VBE_DISPI_INDEX_VIRT_WIDTH] &= ~7u;
- if (r[VBE_DISPI_INDEX_VIRT_WIDTH] > VBE_DISPI_MAX_XRES) {
- r[VBE_DISPI_INDEX_VIRT_WIDTH] = VBE_DISPI_MAX_XRES;
- }
- if (r[VBE_DISPI_INDEX_VIRT_WIDTH] < r[VBE_DISPI_INDEX_XRES]) {
- r[VBE_DISPI_INDEX_VIRT_WIDTH] = r[VBE_DISPI_INDEX_XRES];
- }
-
- /* check height */
- linelength = r[VBE_DISPI_INDEX_VIRT_WIDTH] * bits / 8;
- maxy = s->vbe_size / linelength;
- if (r[VBE_DISPI_INDEX_YRES] == 0) {
- r[VBE_DISPI_INDEX_YRES] = 1;
- }
- if (r[VBE_DISPI_INDEX_YRES] > VBE_DISPI_MAX_YRES) {
- r[VBE_DISPI_INDEX_YRES] = VBE_DISPI_MAX_YRES;
- }
- if (r[VBE_DISPI_INDEX_YRES] > maxy) {
- r[VBE_DISPI_INDEX_YRES] = maxy;
- }
-
- /* check offset */
- if (r[VBE_DISPI_INDEX_X_OFFSET] > VBE_DISPI_MAX_XRES) {
- r[VBE_DISPI_INDEX_X_OFFSET] = VBE_DISPI_MAX_XRES;
- }
- if (r[VBE_DISPI_INDEX_Y_OFFSET] > VBE_DISPI_MAX_YRES) {
- r[VBE_DISPI_INDEX_Y_OFFSET] = VBE_DISPI_MAX_YRES;
- }
- offset = r[VBE_DISPI_INDEX_X_OFFSET] * bits / 8;
- offset += r[VBE_DISPI_INDEX_Y_OFFSET] * linelength;
- if (offset + r[VBE_DISPI_INDEX_YRES] * linelength > s->vbe_size) {
- r[VBE_DISPI_INDEX_Y_OFFSET] = 0;
- offset = r[VBE_DISPI_INDEX_X_OFFSET] * bits / 8;
- if (offset + r[VBE_DISPI_INDEX_YRES] * linelength > s->vbe_size) {
- r[VBE_DISPI_INDEX_X_OFFSET] = 0;
- offset = 0;
- }
- }
-
- /* update vga state */
- r[VBE_DISPI_INDEX_VIRT_HEIGHT] = maxy;
- s->vbe_line_offset = linelength;
- s->vbe_start_addr = offset / 4;
-}
-
-/* we initialize the VGA graphic mode */
-static void vbe_update_vgaregs(VGACommonState *s)
-{
- int h, shift_control;
-
- if (!vbe_enabled(s)) {
- /* vbe is turned off -- nothing to do */
- return;
- }
-
- /* graphic mode + memory map 1 */
- s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 |
- VGA_GR06_GRAPHICS_MODE;
- s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */
- s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3;
- /* width */
- s->cr[VGA_CRTC_H_DISP] =
- (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
- /* height (only meaningful if < 1024) */
- h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
- s->cr[VGA_CRTC_V_DISP_END] = h;
- s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) |
- ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
- /* line compare to 1023 */
- s->cr[VGA_CRTC_LINE_COMPARE] = 0xff;
- s->cr[VGA_CRTC_OVERFLOW] |= 0x10;
- s->cr[VGA_CRTC_MAX_SCAN] |= 0x40;
-
- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
- shift_control = 0;
- s->sr[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */
- } else {
- shift_control = 2;
- /* set chain 4 mode */
- s->sr[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M;
- /* activate all planes */
- s->sr[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES;
- }
- s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) |
- (shift_control << 5);
- s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */
-}
-
-static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
-{
- VGACommonState *s = opaque;
- uint32_t val;
- val = s->vbe_index;
- return val;
-}
-
-uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
-{
- VGACommonState *s = opaque;
- uint32_t val;
-
- if (s->vbe_index < VBE_DISPI_INDEX_NB) {
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) {
- switch(s->vbe_index) {
- /* XXX: do not hardcode ? */
- case VBE_DISPI_INDEX_XRES:
- val = VBE_DISPI_MAX_XRES;
- break;
- case VBE_DISPI_INDEX_YRES:
- val = VBE_DISPI_MAX_YRES;
- break;
- case VBE_DISPI_INDEX_BPP:
- val = VBE_DISPI_MAX_BPP;
- break;
- default:
- val = s->vbe_regs[s->vbe_index];
- break;
- }
- } else {
- val = s->vbe_regs[s->vbe_index];
- }
- } else if (s->vbe_index == VBE_DISPI_INDEX_VIDEO_MEMORY_64K) {
- val = s->vbe_size / (64 * 1024);
- } else {
- val = 0;
- }
-#ifdef DEBUG_BOCHS_VBE
- printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
-#endif
- return val;
-}
-
-void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
-{
- VGACommonState *s = opaque;
- s->vbe_index = val;
-}
-
-void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
-{
- VGACommonState *s = opaque;
-
- if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
-#ifdef DEBUG_BOCHS_VBE
- printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
-#endif
- switch(s->vbe_index) {
- case VBE_DISPI_INDEX_ID:
- if (val == VBE_DISPI_ID0 ||
- val == VBE_DISPI_ID1 ||
- val == VBE_DISPI_ID2 ||
- val == VBE_DISPI_ID3 ||
- val == VBE_DISPI_ID4) {
- s->vbe_regs[s->vbe_index] = val;
- }
- break;
- case VBE_DISPI_INDEX_XRES:
- case VBE_DISPI_INDEX_YRES:
- case VBE_DISPI_INDEX_BPP:
- case VBE_DISPI_INDEX_VIRT_WIDTH:
- case VBE_DISPI_INDEX_X_OFFSET:
- case VBE_DISPI_INDEX_Y_OFFSET:
- s->vbe_regs[s->vbe_index] = val;
- vbe_fixup_regs(s);
- vbe_update_vgaregs(s);
- break;
- case VBE_DISPI_INDEX_BANK:
- val &= s->vbe_bank_mask;
- s->vbe_regs[s->vbe_index] = val;
- s->bank_offset = (val << 16);
- vga_update_memory_access(s);
- break;
- case VBE_DISPI_INDEX_ENABLE:
- if ((val & VBE_DISPI_ENABLED) &&
- !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
-
- s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = 0;
- s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
- s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
- s->vbe_regs[VBE_DISPI_INDEX_ENABLE] |= VBE_DISPI_ENABLED;
- vbe_fixup_regs(s);
- vbe_update_vgaregs(s);
-
- /* clear the screen */
- if (!(val & VBE_DISPI_NOCLEARMEM)) {
- memset(s->vram_ptr, 0,
- s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
- }
- } else {
- s->bank_offset = 0;
- }
- s->dac_8bit = (val & VBE_DISPI_8BIT_DAC) > 0;
- s->vbe_regs[s->vbe_index] = val;
- vga_update_memory_access(s);
- break;
- default:
- break;
- }
- }
-}
-
-/* called for accesses between 0xa0000 and 0xc0000 */
-uint32_t vga_mem_readb(VGACommonState *s, hwaddr addr)
-{
- int memory_map_mode, plane;
- uint32_t ret;
-
- /* convert to VGA memory offset */
- memory_map_mode = (s->gr[VGA_GFX_MISC] >> 2) & 3;
- addr &= 0x1ffff;
- switch(memory_map_mode) {
- case 0:
- break;
- case 1:
- if (addr >= 0x10000)
- return 0xff;
- addr += s->bank_offset;
- break;
- case 2:
- addr -= 0x10000;
- if (addr >= 0x8000)
- return 0xff;
- break;
- default:
- case 3:
- addr -= 0x18000;
- if (addr >= 0x8000)
- return 0xff;
- break;
- }
-
- if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
- /* chain 4 mode : simplest access */
- assert(addr < s->vram_size);
- ret = s->vram_ptr[addr];
- } else if (s->gr[VGA_GFX_MODE] & 0x10) {
- /* odd/even mode (aka text mode mapping) */
- plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
- addr = ((addr & ~1) << 1) | plane;
- if (addr >= s->vram_size) {
- return 0xff;
- }
- ret = s->vram_ptr[addr];
- } else {
- /* standard VGA latched access */
- if (addr * sizeof(uint32_t) >= s->vram_size) {
- return 0xff;
- }
- s->latch = ((uint32_t *)s->vram_ptr)[addr];
-
- if (!(s->gr[VGA_GFX_MODE] & 0x08)) {
- /* read mode 0 */
- plane = s->gr[VGA_GFX_PLANE_READ];
- ret = GET_PLANE(s->latch, plane);
- } else {
- /* read mode 1 */
- ret = (s->latch ^ mask16[s->gr[VGA_GFX_COMPARE_VALUE]]) &
- mask16[s->gr[VGA_GFX_COMPARE_MASK]];
- ret |= ret >> 16;
- ret |= ret >> 8;
- ret = (~ret) & 0xff;
- }
- }
- return ret;
-}
-
-/* called for accesses between 0xa0000 and 0xc0000 */
-void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
-{
- int memory_map_mode, plane, write_mode, b, func_select, mask;
- uint32_t write_mask, bit_mask, set_mask;
-
-#ifdef DEBUG_VGA_MEM
- printf("vga: [0x" TARGET_FMT_plx "] = 0x%02x\n", addr, val);
-#endif
- /* convert to VGA memory offset */
- memory_map_mode = (s->gr[VGA_GFX_MISC] >> 2) & 3;
- addr &= 0x1ffff;
- switch(memory_map_mode) {
- case 0:
- break;
- case 1:
- if (addr >= 0x10000)
- return;
- addr += s->bank_offset;
- break;
- case 2:
- addr -= 0x10000;
- if (addr >= 0x8000)
- return;
- break;
- default:
- case 3:
- addr -= 0x18000;
- if (addr >= 0x8000)
- return;
- break;
- }
-
- if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
- /* chain 4 mode : simplest access */
- plane = addr & 3;
- mask = (1 << plane);
- if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
- assert(addr < s->vram_size);
- s->vram_ptr[addr] = val;
-#ifdef DEBUG_VGA_MEM
- printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
-#endif
- s->plane_updated |= mask; /* only used to detect font change */
- memory_region_set_dirty(&s->vram, addr, 1);
- }
- } else if (s->gr[VGA_GFX_MODE] & 0x10) {
- /* odd/even mode (aka text mode mapping) */
- plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
- mask = (1 << plane);
- if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
- addr = ((addr & ~1) << 1) | plane;
- if (addr >= s->vram_size) {
- return;
- }
- s->vram_ptr[addr] = val;
-#ifdef DEBUG_VGA_MEM
- printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
-#endif
- s->plane_updated |= mask; /* only used to detect font change */
- memory_region_set_dirty(&s->vram, addr, 1);
- }
- } else {
- /* standard VGA latched access */
- write_mode = s->gr[VGA_GFX_MODE] & 3;
- switch(write_mode) {
- default:
- case 0:
- /* rotate */
- b = s->gr[VGA_GFX_DATA_ROTATE] & 7;
- val = ((val >> b) | (val << (8 - b))) & 0xff;
- val |= val << 8;
- val |= val << 16;
-
- /* apply set/reset mask */
- set_mask = mask16[s->gr[VGA_GFX_SR_ENABLE]];
- val = (val & ~set_mask) |
- (mask16[s->gr[VGA_GFX_SR_VALUE]] & set_mask);
- bit_mask = s->gr[VGA_GFX_BIT_MASK];
- break;
- case 1:
- val = s->latch;
- goto do_write;
- case 2:
- val = mask16[val & 0x0f];
- bit_mask = s->gr[VGA_GFX_BIT_MASK];
- break;
- case 3:
- /* rotate */
- b = s->gr[VGA_GFX_DATA_ROTATE] & 7;
- val = (val >> b) | (val << (8 - b));
-
- bit_mask = s->gr[VGA_GFX_BIT_MASK] & val;
- val = mask16[s->gr[VGA_GFX_SR_VALUE]];
- break;
- }
-
- /* apply logical operation */
- func_select = s->gr[VGA_GFX_DATA_ROTATE] >> 3;
- switch(func_select) {
- case 0:
- default:
- /* nothing to do */
- break;
- case 1:
- /* and */
- val &= s->latch;
- break;
- case 2:
- /* or */
- val |= s->latch;
- break;
- case 3:
- /* xor */
- val ^= s->latch;
- break;
- }
-
- /* apply bit mask */
- bit_mask |= bit_mask << 8;
- bit_mask |= bit_mask << 16;
- val = (val & bit_mask) | (s->latch & ~bit_mask);
-
- do_write:
- /* mask data according to sr[2] */
- mask = s->sr[VGA_SEQ_PLANE_WRITE];
- s->plane_updated |= mask; /* only used to detect font change */
- write_mask = mask16[mask];
- if (addr * sizeof(uint32_t) >= s->vram_size) {
- return;
- }
- ((uint32_t *)s->vram_ptr)[addr] =
- (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
- (val & write_mask);
-#ifdef DEBUG_VGA_MEM
- printf("vga: latch: [0x" TARGET_FMT_plx "] mask=0x%08x val=0x%08x\n",
- addr * 4, write_mask, val);
-#endif
- memory_region_set_dirty(&s->vram, addr << 2, sizeof(uint32_t));
- }
-}
-
-typedef void vga_draw_line_func(VGACommonState *s1, uint8_t *d,
- const uint8_t *s, int width);
-
-#include "vga-helpers.h"
-
-/* return true if the palette was modified */
-static int update_palette16(VGACommonState *s)
-{
- int full_update, i;
- uint32_t v, col, *palette;
-
- full_update = 0;
- palette = s->last_palette;
- for(i = 0; i < 16; i++) {
- v = s->ar[i];
- if (s->ar[VGA_ATC_MODE] & 0x80) {
- v = ((s->ar[VGA_ATC_COLOR_PAGE] & 0xf) << 4) | (v & 0xf);
- } else {
- v = ((s->ar[VGA_ATC_COLOR_PAGE] & 0xc) << 4) | (v & 0x3f);
- }
- v = v * 3;
- col = rgb_to_pixel32(c6_to_8(s->palette[v]),
- c6_to_8(s->palette[v + 1]),
- c6_to_8(s->palette[v + 2]));
- if (col != palette[i]) {
- full_update = 1;
- palette[i] = col;
- }
- }
- return full_update;
-}
-
-/* return true if the palette was modified */
-static int update_palette256(VGACommonState *s)
-{
- int full_update, i;
- uint32_t v, col, *palette;
-
- full_update = 0;
- palette = s->last_palette;
- v = 0;
- for(i = 0; i < 256; i++) {
- if (s->dac_8bit) {
- col = rgb_to_pixel32(s->palette[v],
- s->palette[v + 1],
- s->palette[v + 2]);
- } else {
- col = rgb_to_pixel32(c6_to_8(s->palette[v]),
- c6_to_8(s->palette[v + 1]),
- c6_to_8(s->palette[v + 2]));
- }
- if (col != palette[i]) {
- full_update = 1;
- palette[i] = col;
- }
- v += 3;
- }
- return full_update;
-}
-
-static void vga_get_offsets(VGACommonState *s,
- uint32_t *pline_offset,
- uint32_t *pstart_addr,
- uint32_t *pline_compare)
-{
- uint32_t start_addr, line_offset, line_compare;
-
- if (vbe_enabled(s)) {
- line_offset = s->vbe_line_offset;
- start_addr = s->vbe_start_addr;
- line_compare = 65535;
- } else {
- /* compute line_offset in bytes */
- line_offset = s->cr[VGA_CRTC_OFFSET];
- line_offset <<= 3;
-
- /* starting address */
- start_addr = s->cr[VGA_CRTC_START_LO] |
- (s->cr[VGA_CRTC_START_HI] << 8);
-
- /* line compare */
- line_compare = s->cr[VGA_CRTC_LINE_COMPARE] |
- ((s->cr[VGA_CRTC_OVERFLOW] & 0x10) << 4) |
- ((s->cr[VGA_CRTC_MAX_SCAN] & 0x40) << 3);
- }
- *pline_offset = line_offset;
- *pstart_addr = start_addr;
- *pline_compare = line_compare;
-}
-
-/* update start_addr and line_offset. Return TRUE if modified */
-static int update_basic_params(VGACommonState *s)
-{
- int full_update;
- uint32_t start_addr, line_offset, line_compare;
-
- full_update = 0;
-
- s->get_offsets(s, &line_offset, &start_addr, &line_compare);
-
- if (line_offset != s->line_offset ||
- start_addr != s->start_addr ||
- line_compare != s->line_compare) {
- s->line_offset = line_offset;
- s->start_addr = start_addr;
- s->line_compare = line_compare;
- full_update = 1;
- }
- return full_update;
-}
-
-
-static const uint8_t cursor_glyph[32 * 4] = {
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-};
-
-static void vga_get_text_resolution(VGACommonState *s, int *pwidth, int *pheight,
- int *pcwidth, int *pcheight)
-{
- int width, cwidth, height, cheight;
-
- /* total width & height */
- cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1;
- cwidth = 8;
- if (!(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) {
- cwidth = 9;
- }
- if (s->sr[VGA_SEQ_CLOCK_MODE] & 0x08) {
- cwidth = 16; /* NOTE: no 18 pixel wide */
- }
- width = (s->cr[VGA_CRTC_H_DISP] + 1);
- if (s->cr[VGA_CRTC_V_TOTAL] == 100) {
- /* ugly hack for CGA 160x100x16 - explain me the logic */
- height = 100;
- } else {
- height = s->cr[VGA_CRTC_V_DISP_END] |
- ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
- ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
- height = (height + 1) / cheight;
- }
-
- *pwidth = width;
- *pheight = height;
- *pcwidth = cwidth;
- *pcheight = cheight;
-}
-
-/*
- * Text mode update
- * Missing:
- * - double scan
- * - double width
- * - underline
- * - flashing
- */
-static void vga_draw_text(VGACommonState *s, int full_update)
-{
- DisplaySurface *surface = qemu_console_surface(s->con);
- int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
- int cx_min, cx_max, linesize, x_incr, line, line1;
- uint32_t offset, fgcol, bgcol, v, cursor_offset;
- uint8_t *d1, *d, *src, *dest, *cursor_ptr;
- const uint8_t *font_ptr, *font_base[2];
- int dup9, line_offset;
- uint32_t *palette;
- uint32_t *ch_attr_ptr;
- int64_t now = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
-
- /* compute font data address (in plane 2) */
- v = s->sr[VGA_SEQ_CHARACTER_MAP];
- offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
- if (offset != s->font_offsets[0]) {
- s->font_offsets[0] = offset;
- full_update = 1;
- }
- font_base[0] = s->vram_ptr + offset;
-
- offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
- font_base[1] = s->vram_ptr + offset;
- if (offset != s->font_offsets[1]) {
- s->font_offsets[1] = offset;
- full_update = 1;
- }
- if (s->plane_updated & (1 << 2) || s->has_chain4_alias) {
- /* if the plane 2 was modified since the last display, it
- indicates the font may have been modified */
- s->plane_updated = 0;
- full_update = 1;
- }
- full_update |= update_basic_params(s);
-
- line_offset = s->line_offset;
-
- vga_get_text_resolution(s, &width, &height, &cw, &cheight);
- if ((height * width) <= 1) {
- /* better than nothing: exit if transient size is too small */
- return;
- }
- if ((height * width) > CH_ATTR_SIZE) {
- /* better than nothing: exit if transient size is too big */
- return;
- }
-
- if (width != s->last_width || height != s->last_height ||
- cw != s->last_cw || cheight != s->last_ch || s->last_depth) {
- s->last_scr_width = width * cw;
- s->last_scr_height = height * cheight;
- qemu_console_resize(s->con, s->last_scr_width, s->last_scr_height);
- surface = qemu_console_surface(s->con);
- dpy_text_resize(s->con, width, height);
- s->last_depth = 0;
- s->last_width = width;
- s->last_height = height;
- s->last_ch = cheight;
- s->last_cw = cw;
- full_update = 1;
- }
- full_update |= update_palette16(s);
- palette = s->last_palette;
- x_incr = cw * surface_bytes_per_pixel(surface);
-
- if (full_update) {
- s->full_update_text = 1;
- }
- if (s->full_update_gfx) {
- s->full_update_gfx = 0;
- full_update |= 1;
- }
-
- cursor_offset = ((s->cr[VGA_CRTC_CURSOR_HI] << 8) |
- s->cr[VGA_CRTC_CURSOR_LO]) - s->start_addr;
- if (cursor_offset != s->cursor_offset ||
- s->cr[VGA_CRTC_CURSOR_START] != s->cursor_start ||
- s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end) {
- /* if the cursor position changed, we update the old and new
- chars */
- if (s->cursor_offset < CH_ATTR_SIZE)
- s->last_ch_attr[s->cursor_offset] = -1;
- if (cursor_offset < CH_ATTR_SIZE)
- s->last_ch_attr[cursor_offset] = -1;
- s->cursor_offset = cursor_offset;
- s->cursor_start = s->cr[VGA_CRTC_CURSOR_START];
- s->cursor_end = s->cr[VGA_CRTC_CURSOR_END];
- }
- cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
- if (now >= s->cursor_blink_time) {
- s->cursor_blink_time = now + VGA_TEXT_CURSOR_PERIOD_MS / 2;
- s->cursor_visible_phase = !s->cursor_visible_phase;
- }
-
- dest = surface_data(surface);
- linesize = surface_stride(surface);
- ch_attr_ptr = s->last_ch_attr;
- line = 0;
- offset = s->start_addr * 4;
- for(cy = 0; cy < height; cy++) {
- d1 = dest;
- src = s->vram_ptr + offset;
- cx_min = width;
- cx_max = -1;
- for(cx = 0; cx < width; cx++) {
- ch_attr = *(uint16_t *)src;
- if (full_update || ch_attr != *ch_attr_ptr || src == cursor_ptr) {
- if (cx < cx_min)
- cx_min = cx;
- if (cx > cx_max)
- cx_max = cx;
- *ch_attr_ptr = ch_attr;
-#ifdef HOST_WORDS_BIGENDIAN
- ch = ch_attr >> 8;
- cattr = ch_attr & 0xff;
-#else
- ch = ch_attr & 0xff;
- cattr = ch_attr >> 8;
-#endif
- font_ptr = font_base[(cattr >> 3) & 1];
- font_ptr += 32 * 4 * ch;
- bgcol = palette[cattr >> 4];
- fgcol = palette[cattr & 0x0f];
- if (cw == 16) {
- vga_draw_glyph16(d1, linesize,
- font_ptr, cheight, fgcol, bgcol);
- } else if (cw != 9) {
- vga_draw_glyph8(d1, linesize,
- font_ptr, cheight, fgcol, bgcol);
- } else {
- dup9 = 0;
- if (ch >= 0xb0 && ch <= 0xdf &&
- (s->ar[VGA_ATC_MODE] & 0x04)) {
- dup9 = 1;
- }
- vga_draw_glyph9(d1, linesize,
- font_ptr, cheight, fgcol, bgcol, dup9);
- }
- if (src == cursor_ptr &&
- !(s->cr[VGA_CRTC_CURSOR_START] & 0x20) &&
- s->cursor_visible_phase) {
- int line_start, line_last, h;
- /* draw the cursor */
- line_start = s->cr[VGA_CRTC_CURSOR_START] & 0x1f;
- line_last = s->cr[VGA_CRTC_CURSOR_END] & 0x1f;
- /* XXX: check that */
- if (line_last > cheight - 1)
- line_last = cheight - 1;
- if (line_last >= line_start && line_start < cheight) {
- h = line_last - line_start + 1;
- d = d1 + linesize * line_start;
- if (cw == 16) {
- vga_draw_glyph16(d, linesize,
- cursor_glyph, h, fgcol, bgcol);
- } else if (cw != 9) {
- vga_draw_glyph8(d, linesize,
- cursor_glyph, h, fgcol, bgcol);
- } else {
- vga_draw_glyph9(d, linesize,
- cursor_glyph, h, fgcol, bgcol, 1);
- }
- }
- }
- }
- d1 += x_incr;
- src += 4;
- ch_attr_ptr++;
- }
- if (cx_max != -1) {
- dpy_gfx_update(s->con, cx_min * cw, cy * cheight,
- (cx_max - cx_min + 1) * cw, cheight);
- }
- dest += linesize * cheight;
- line1 = line + cheight;
- offset += line_offset;
- if (line < s->line_compare && line1 >= s->line_compare) {
- offset = 0;
- }
- line = line1;
- }
-}
-
-enum {
- VGA_DRAW_LINE2,
- VGA_DRAW_LINE2D2,
- VGA_DRAW_LINE4,
- VGA_DRAW_LINE4D2,
- VGA_DRAW_LINE8D2,
- VGA_DRAW_LINE8,
- VGA_DRAW_LINE15_LE,
- VGA_DRAW_LINE16_LE,
- VGA_DRAW_LINE24_LE,
- VGA_DRAW_LINE32_LE,
- VGA_DRAW_LINE15_BE,
- VGA_DRAW_LINE16_BE,
- VGA_DRAW_LINE24_BE,
- VGA_DRAW_LINE32_BE,
- VGA_DRAW_LINE_NB,
-};
-
-static vga_draw_line_func * const vga_draw_line_table[VGA_DRAW_LINE_NB] = {
- vga_draw_line2,
- vga_draw_line2d2,
- vga_draw_line4,
- vga_draw_line4d2,
- vga_draw_line8d2,
- vga_draw_line8,
- vga_draw_line15_le,
- vga_draw_line16_le,
- vga_draw_line24_le,
- vga_draw_line32_le,
- vga_draw_line15_be,
- vga_draw_line16_be,
- vga_draw_line24_be,
- vga_draw_line32_be,
-};
-
-static int vga_get_bpp(VGACommonState *s)
-{
- int ret;
-
- if (vbe_enabled(s)) {
- ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
- } else {
- ret = 0;
- }
- return ret;
-}
-
-static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
-{
- int width, height;
-
- if (vbe_enabled(s)) {
- width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
- height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
- } else {
- width = (s->cr[VGA_CRTC_H_DISP] + 1) * 8;
- height = s->cr[VGA_CRTC_V_DISP_END] |
- ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
- ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
- height = (height + 1);
- }
- *pwidth = width;
- *pheight = height;
-}
-
-void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2)
-{
- int y;
- if (y1 >= VGA_MAX_HEIGHT)
- return;
- if (y2 >= VGA_MAX_HEIGHT)
- y2 = VGA_MAX_HEIGHT;
- for(y = y1; y < y2; y++) {
- s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
- }
-}
-
-void vga_sync_dirty_bitmap(VGACommonState *s)
-{
- memory_region_sync_dirty_bitmap(&s->vram);
-}
-
-void vga_dirty_log_start(VGACommonState *s)
-{
- memory_region_set_log(&s->vram, true, DIRTY_MEMORY_VGA);
-}
-
-void vga_dirty_log_stop(VGACommonState *s)
-{
- memory_region_set_log(&s->vram, false, DIRTY_MEMORY_VGA);
-}
-
-/*
- * graphic modes
- */
-static void vga_draw_graphic(VGACommonState *s, int full_update)
-{
- DisplaySurface *surface = qemu_console_surface(s->con);
- int y1, y, update, linesize, y_start, double_scan, mask, depth;
- int width, height, shift_control, line_offset, bwidth, bits;
- ram_addr_t page0, page1, page_min, page_max;
- int disp_width, multi_scan, multi_run;
- uint8_t *d;
- uint32_t v, addr1, addr;
- vga_draw_line_func *vga_draw_line = NULL;
- bool share_surface;
- pixman_format_code_t format;
-#ifdef HOST_WORDS_BIGENDIAN
- bool byteswap = !s->big_endian_fb;
-#else
- bool byteswap = s->big_endian_fb;
-#endif
-
- full_update |= update_basic_params(s);
-
- if (!full_update)
- vga_sync_dirty_bitmap(s);
-
- s->get_resolution(s, &width, &height);
- disp_width = width;
-
- shift_control = (s->gr[VGA_GFX_MODE] >> 5) & 3;
- double_scan = (s->cr[VGA_CRTC_MAX_SCAN] >> 7);
- if (shift_control != 1) {
- multi_scan = (((s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1) << double_scan)
- - 1;
- } else {
- /* in CGA modes, multi_scan is ignored */
- /* XXX: is it correct ? */
- multi_scan = double_scan;
- }
- multi_run = multi_scan;
- if (shift_control != s->shift_control ||
- double_scan != s->double_scan) {
- full_update = 1;
- s->shift_control = shift_control;
- s->double_scan = double_scan;
- }
-
- if (shift_control == 0) {
- if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
- disp_width <<= 1;
- }
- } else if (shift_control == 1) {
- if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
- disp_width <<= 1;
- }
- }
-
- depth = s->get_bpp(s);
-
- /*
- * Check whether we can share the surface with the backend
- * or whether we need a shadow surface. We share native
- * endian surfaces for 15bpp and above and byteswapped
- * surfaces for 24bpp and above.
- */
- format = qemu_default_pixman_format(depth, !byteswap);
- if (format) {
- share_surface = dpy_gfx_check_format(s->con, format)
- && !s->force_shadow;
- } else {
- share_surface = false;
- }
- if (s->line_offset != s->last_line_offset ||
- disp_width != s->last_width ||
- height != s->last_height ||
- s->last_depth != depth ||
- s->last_byteswap != byteswap ||
- share_surface != is_buffer_shared(surface)) {
- if (share_surface) {
- surface = qemu_create_displaysurface_from(disp_width,
- height, format, s->line_offset,
- s->vram_ptr + (s->start_addr * 4));
- dpy_gfx_replace_surface(s->con, surface);
-#ifdef DEBUG_VGA
- printf("VGA: Using shared surface for depth=%d swap=%d\n",
- depth, byteswap);
-#endif
- } else {
- qemu_console_resize(s->con, disp_width, height);
- surface = qemu_console_surface(s->con);
-#ifdef DEBUG_VGA
- printf("VGA: Using shadow surface for depth=%d swap=%d\n",
- depth, byteswap);
-#endif
- }
- s->last_scr_width = disp_width;
- s->last_scr_height = height;
- s->last_width = disp_width;
- s->last_height = height;
- s->last_line_offset = s->line_offset;
- s->last_depth = depth;
- s->last_byteswap = byteswap;
- full_update = 1;
- } else if (is_buffer_shared(surface) &&
- (full_update || surface_data(surface) != s->vram_ptr
- + (s->start_addr * 4))) {
- pixman_format_code_t format =
- qemu_default_pixman_format(depth, !byteswap);
- surface = qemu_create_displaysurface_from(disp_width,
- height, format, s->line_offset,
- s->vram_ptr + (s->start_addr * 4));
- dpy_gfx_replace_surface(s->con, surface);
- }
-
- if (shift_control == 0) {
- full_update |= update_palette16(s);
- if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
- v = VGA_DRAW_LINE4D2;
- } else {
- v = VGA_DRAW_LINE4;
- }
- bits = 4;
- } else if (shift_control == 1) {
- full_update |= update_palette16(s);
- if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
- v = VGA_DRAW_LINE2D2;
- } else {
- v = VGA_DRAW_LINE2;
- }
- bits = 4;
- } else {
- switch(s->get_bpp(s)) {
- default:
- case 0:
- full_update |= update_palette256(s);
- v = VGA_DRAW_LINE8D2;
- bits = 4;
- break;
- case 8:
- full_update |= update_palette256(s);
- v = VGA_DRAW_LINE8;
- bits = 8;
- break;
- case 15:
- v = s->big_endian_fb ? VGA_DRAW_LINE15_BE : VGA_DRAW_LINE15_LE;
- bits = 16;
- break;
- case 16:
- v = s->big_endian_fb ? VGA_DRAW_LINE16_BE : VGA_DRAW_LINE16_LE;
- bits = 16;
- break;
- case 24:
- v = s->big_endian_fb ? VGA_DRAW_LINE24_BE : VGA_DRAW_LINE24_LE;
- bits = 24;
- break;
- case 32:
- v = s->big_endian_fb ? VGA_DRAW_LINE32_BE : VGA_DRAW_LINE32_LE;
- bits = 32;
- break;
- }
- }
- vga_draw_line = vga_draw_line_table[v];
-
- if (!is_buffer_shared(surface) && s->cursor_invalidate) {
- s->cursor_invalidate(s);
- }
-
- line_offset = s->line_offset;
-#if 0
- printf("w=%d h=%d v=%d line_offset=%d cr[0x09]=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=0x%02x\n",
- width, height, v, line_offset, s->cr[9], s->cr[VGA_CRTC_MODE],
- s->line_compare, s->sr[VGA_SEQ_CLOCK_MODE]);
-#endif
- addr1 = (s->start_addr * 4);
- bwidth = (width * bits + 7) / 8;
- y_start = -1;
- page_min = -1;
- page_max = 0;
- d = surface_data(surface);
- linesize = surface_stride(surface);
- y1 = 0;
- for(y = 0; y < height; y++) {
- addr = addr1;
- if (!(s->cr[VGA_CRTC_MODE] & 1)) {
- int shift;
- /* CGA compatibility handling */
- shift = 14 + ((s->cr[VGA_CRTC_MODE] >> 6) & 1);
- addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
- }
- if (!(s->cr[VGA_CRTC_MODE] & 2)) {
- addr = (addr & ~0x8000) | ((y1 & 2) << 14);
- }
- update = full_update;
- page0 = addr;
- page1 = addr + bwidth - 1;
- update |= memory_region_get_dirty(&s->vram, page0, page1 - page0,
- DIRTY_MEMORY_VGA);
- /* explicit invalidation for the hardware cursor */
- update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
- if (update) {
- if (y_start < 0)
- y_start = y;
- if (page0 < page_min)
- page_min = page0;
- if (page1 > page_max)
- page_max = page1;
- if (!(is_buffer_shared(surface))) {
- vga_draw_line(s, d, s->vram_ptr + addr, width);
- if (s->cursor_draw_line)
- s->cursor_draw_line(s, d, y);
- }
- } else {
- if (y_start >= 0) {
- /* flush to display */
- dpy_gfx_update(s->con, 0, y_start,
- disp_width, y - y_start);
- y_start = -1;
- }
- }
- if (!multi_run) {
- mask = (s->cr[VGA_CRTC_MODE] & 3) ^ 3;
- if ((y1 & mask) == mask)
- addr1 += line_offset;
- y1++;
- multi_run = multi_scan;
- } else {
- multi_run--;
- }
- /* line compare acts on the displayed lines */
- if (y == s->line_compare)
- addr1 = 0;
- d += linesize;
- }
- if (y_start >= 0) {
- /* flush to display */
- dpy_gfx_update(s->con, 0, y_start,
- disp_width, y - y_start);
- }
- /* reset modified pages */
- if (page_max >= page_min) {
- memory_region_reset_dirty(&s->vram,
- page_min,
- page_max - page_min,
- DIRTY_MEMORY_VGA);
- }
- memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
-}
-
-static void vga_draw_blank(VGACommonState *s, int full_update)
-{
- DisplaySurface *surface = qemu_console_surface(s->con);
- int i, w;
- uint8_t *d;
-
- if (!full_update)
- return;
- if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
- return;
-
- w = s->last_scr_width * surface_bytes_per_pixel(surface);
- d = surface_data(surface);
- for(i = 0; i < s->last_scr_height; i++) {
- memset(d, 0, w);
- d += surface_stride(surface);
- }
- dpy_gfx_update(s->con, 0, 0,
- s->last_scr_width, s->last_scr_height);
-}
-
-#define GMODE_TEXT 0
-#define GMODE_GRAPH 1
-#define GMODE_BLANK 2
-
-static void vga_update_display(void *opaque)
-{
- VGACommonState *s = opaque;
- DisplaySurface *surface = qemu_console_surface(s->con);
- int full_update, graphic_mode;
-
- qemu_flush_coalesced_mmio_buffer();
-
- if (surface_bits_per_pixel(surface) == 0) {
- /* nothing to do */
- } else {
- full_update = 0;
- if (!(s->ar_index & 0x20)) {
- graphic_mode = GMODE_BLANK;
- } else {
- graphic_mode = s->gr[VGA_GFX_MISC] & VGA_GR06_GRAPHICS_MODE;
- }
- if (graphic_mode != s->graphic_mode) {
- s->graphic_mode = graphic_mode;
- s->cursor_blink_time = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
- full_update = 1;
- }
- switch(graphic_mode) {
- case GMODE_TEXT:
- vga_draw_text(s, full_update);
- break;
- case GMODE_GRAPH:
- vga_draw_graphic(s, full_update);
- break;
- case GMODE_BLANK:
- default:
- vga_draw_blank(s, full_update);
- break;
- }
- }
-}
-
-/* force a full display refresh */
-static void vga_invalidate_display(void *opaque)
-{
- VGACommonState *s = opaque;
-
- s->last_width = -1;
- s->last_height = -1;
-}
-
-void vga_common_reset(VGACommonState *s)
-{
- s->sr_index = 0;
- memset(s->sr, '\0', sizeof(s->sr));
- s->gr_index = 0;
- memset(s->gr, '\0', sizeof(s->gr));
- s->ar_index = 0;
- memset(s->ar, '\0', sizeof(s->ar));
- s->ar_flip_flop = 0;
- s->cr_index = 0;
- memset(s->cr, '\0', sizeof(s->cr));
- s->msr = 0;
- s->fcr = 0;
- s->st00 = 0;
- s->st01 = 0;
- s->dac_state = 0;
- s->dac_sub_index = 0;
- s->dac_read_index = 0;
- s->dac_write_index = 0;
- memset(s->dac_cache, '\0', sizeof(s->dac_cache));
- s->dac_8bit = 0;
- memset(s->palette, '\0', sizeof(s->palette));
- s->bank_offset = 0;
- s->vbe_index = 0;
- memset(s->vbe_regs, '\0', sizeof(s->vbe_regs));
- s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID5;
- s->vbe_start_addr = 0;
- s->vbe_line_offset = 0;
- s->vbe_bank_mask = (s->vram_size >> 16) - 1;
- memset(s->font_offsets, '\0', sizeof(s->font_offsets));
- s->graphic_mode = -1; /* force full update */
- s->shift_control = 0;
- s->double_scan = 0;
- s->line_offset = 0;
- s->line_compare = 0;
- s->start_addr = 0;
- s->plane_updated = 0;
- s->last_cw = 0;
- s->last_ch = 0;
- s->last_width = 0;
- s->last_height = 0;
- s->last_scr_width = 0;
- s->last_scr_height = 0;
- s->cursor_start = 0;
- s->cursor_end = 0;
- s->cursor_offset = 0;
- s->big_endian_fb = s->default_endian_fb;
- memset(s->invalidated_y_table, '\0', sizeof(s->invalidated_y_table));
- memset(s->last_palette, '\0', sizeof(s->last_palette));
- memset(s->last_ch_attr, '\0', sizeof(s->last_ch_attr));
- switch (vga_retrace_method) {
- case VGA_RETRACE_DUMB:
- break;
- case VGA_RETRACE_PRECISE:
- memset(&s->retrace_info, 0, sizeof (s->retrace_info));
- break;
- }
- vga_update_memory_access(s);
-}
-
-static void vga_reset(void *opaque)
-{
- VGACommonState *s = opaque;
- vga_common_reset(s);
-}
-
-#define TEXTMODE_X(x) ((x) % width)
-#define TEXTMODE_Y(x) ((x) / width)
-#define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
- ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
-/* relay text rendering to the display driver
- * instead of doing a full vga_update_display() */
-static void vga_update_text(void *opaque, console_ch_t *chardata)
-{
- VGACommonState *s = opaque;
- int graphic_mode, i, cursor_offset, cursor_visible;
- int cw, cheight, width, height, size, c_min, c_max;
- uint32_t *src;
- console_ch_t *dst, val;
- char msg_buffer[80];
- int full_update = 0;
-
- qemu_flush_coalesced_mmio_buffer();
-
- if (!(s->ar_index & 0x20)) {
- graphic_mode = GMODE_BLANK;
- } else {
- graphic_mode = s->gr[VGA_GFX_MISC] & VGA_GR06_GRAPHICS_MODE;
- }
- if (graphic_mode != s->graphic_mode) {
- s->graphic_mode = graphic_mode;
- full_update = 1;
- }
- if (s->last_width == -1) {
- s->last_width = 0;
- full_update = 1;
- }
-
- switch (graphic_mode) {
- case GMODE_TEXT:
- /* TODO: update palette */
- full_update |= update_basic_params(s);
-
- /* total width & height */
- cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1;
- cw = 8;
- if (!(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) {
- cw = 9;
- }
- if (s->sr[VGA_SEQ_CLOCK_MODE] & 0x08) {
- cw = 16; /* NOTE: no 18 pixel wide */
- }
- width = (s->cr[VGA_CRTC_H_DISP] + 1);
- if (s->cr[VGA_CRTC_V_TOTAL] == 100) {
- /* ugly hack for CGA 160x100x16 - explain me the logic */
- height = 100;
- } else {
- height = s->cr[VGA_CRTC_V_DISP_END] |
- ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
- ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
- height = (height + 1) / cheight;
- }
-
- size = (height * width);
- if (size > CH_ATTR_SIZE) {
- if (!full_update)
- return;
-
- snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Text mode",
- width, height);
- break;
- }
-
- if (width != s->last_width || height != s->last_height ||
- cw != s->last_cw || cheight != s->last_ch) {
- s->last_scr_width = width * cw;
- s->last_scr_height = height * cheight;
- qemu_console_resize(s->con, s->last_scr_width, s->last_scr_height);
- dpy_text_resize(s->con, width, height);
- s->last_depth = 0;
- s->last_width = width;
- s->last_height = height;
- s->last_ch = cheight;
- s->last_cw = cw;
- full_update = 1;
- }
-
- if (full_update) {
- s->full_update_gfx = 1;
- }
- if (s->full_update_text) {
- s->full_update_text = 0;
- full_update |= 1;
- }
-
- /* Update "hardware" cursor */
- cursor_offset = ((s->cr[VGA_CRTC_CURSOR_HI] << 8) |
- s->cr[VGA_CRTC_CURSOR_LO]) - s->start_addr;
- if (cursor_offset != s->cursor_offset ||
- s->cr[VGA_CRTC_CURSOR_START] != s->cursor_start ||
- s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end || full_update) {
- cursor_visible = !(s->cr[VGA_CRTC_CURSOR_START] & 0x20);
- if (cursor_visible && cursor_offset < size && cursor_offset >= 0)
- dpy_text_cursor(s->con,
- TEXTMODE_X(cursor_offset),
- TEXTMODE_Y(cursor_offset));
- else
- dpy_text_cursor(s->con, -1, -1);
- s->cursor_offset = cursor_offset;
- s->cursor_start = s->cr[VGA_CRTC_CURSOR_START];
- s->cursor_end = s->cr[VGA_CRTC_CURSOR_END];
- }
-
- src = (uint32_t *) s->vram_ptr + s->start_addr;
- dst = chardata;
-
- if (full_update) {
- for (i = 0; i < size; src ++, dst ++, i ++)
- console_write_ch(dst, VMEM2CHTYPE(le32_to_cpu(*src)));
-
- dpy_text_update(s->con, 0, 0, width, height);
- } else {
- c_max = 0;
-
- for (i = 0; i < size; src ++, dst ++, i ++) {
- console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
- if (*dst != val) {
- *dst = val;
- c_max = i;
- break;
- }
- }
- c_min = i;
- for (; i < size; src ++, dst ++, i ++) {
- console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
- if (*dst != val) {
- *dst = val;
- c_max = i;
- }
- }
-
- if (c_min <= c_max) {
- i = TEXTMODE_Y(c_min);
- dpy_text_update(s->con, 0, i, width, TEXTMODE_Y(c_max) - i + 1);
- }
- }
-
- return;
- case GMODE_GRAPH:
- if (!full_update)
- return;
-
- s->get_resolution(s, &width, &height);
- snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Graphic mode",
- width, height);
- break;
- case GMODE_BLANK:
- default:
- if (!full_update)
- return;
-
- snprintf(msg_buffer, sizeof(msg_buffer), "VGA Blank mode");
- break;
- }
-
- /* Display a message */
- s->last_width = 60;
- s->last_height = height = 3;
- dpy_text_cursor(s->con, -1, -1);
- dpy_text_resize(s->con, s->last_width, height);
-
- for (dst = chardata, i = 0; i < s->last_width * height; i ++)
- console_write_ch(dst ++, ' ');
-
- size = strlen(msg_buffer);
- width = (s->last_width - size) / 2;
- dst = chardata + s->last_width + width;
- for (i = 0; i < size; i ++)
- console_write_ch(dst ++, ATTR2CHTYPE(msg_buffer[i], QEMU_COLOR_BLUE,
- QEMU_COLOR_BLACK, 1));
-
- dpy_text_update(s->con, 0, 0, s->last_width, height);
-}
-
-static uint64_t vga_mem_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- VGACommonState *s = opaque;
-
- return vga_mem_readb(s, addr);
-}
-
-static void vga_mem_write(void *opaque, hwaddr addr,
- uint64_t data, unsigned size)
-{
- VGACommonState *s = opaque;
-
- vga_mem_writeb(s, addr, data);
-}
-
-const MemoryRegionOps vga_mem_ops = {
- .read = vga_mem_read,
- .write = vga_mem_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
-};
-
-static int vga_common_post_load(void *opaque, int version_id)
-{
- VGACommonState *s = opaque;
-
- /* force refresh */
- s->graphic_mode = -1;
- return 0;
-}
-
-static bool vga_endian_state_needed(void *opaque)
-{
- VGACommonState *s = opaque;
-
- /*
- * Only send the endian state if it's different from the
- * default one, thus ensuring backward compatibility for
- * migration of the common case
- */
- return s->default_endian_fb != s->big_endian_fb;
-}
-
-static const VMStateDescription vmstate_vga_endian = {
- .name = "vga.endian",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = vga_endian_state_needed,
- .fields = (VMStateField[]) {
- VMSTATE_BOOL(big_endian_fb, VGACommonState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-const VMStateDescription vmstate_vga_common = {
- .name = "vga",
- .version_id = 2,
- .minimum_version_id = 2,
- .post_load = vga_common_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(latch, VGACommonState),
- VMSTATE_UINT8(sr_index, VGACommonState),
- VMSTATE_PARTIAL_BUFFER(sr, VGACommonState, 8),
- VMSTATE_UINT8(gr_index, VGACommonState),
- VMSTATE_PARTIAL_BUFFER(gr, VGACommonState, 16),
- VMSTATE_UINT8(ar_index, VGACommonState),
- VMSTATE_BUFFER(ar, VGACommonState),
- VMSTATE_INT32(ar_flip_flop, VGACommonState),
- VMSTATE_UINT8(cr_index, VGACommonState),
- VMSTATE_BUFFER(cr, VGACommonState),
- VMSTATE_UINT8(msr, VGACommonState),
- VMSTATE_UINT8(fcr, VGACommonState),
- VMSTATE_UINT8(st00, VGACommonState),
- VMSTATE_UINT8(st01, VGACommonState),
-
- VMSTATE_UINT8(dac_state, VGACommonState),
- VMSTATE_UINT8(dac_sub_index, VGACommonState),
- VMSTATE_UINT8(dac_read_index, VGACommonState),
- VMSTATE_UINT8(dac_write_index, VGACommonState),
- VMSTATE_BUFFER(dac_cache, VGACommonState),
- VMSTATE_BUFFER(palette, VGACommonState),
-
- VMSTATE_INT32(bank_offset, VGACommonState),
- VMSTATE_UINT8_EQUAL(is_vbe_vmstate, VGACommonState),
- VMSTATE_UINT16(vbe_index, VGACommonState),
- VMSTATE_UINT16_ARRAY(vbe_regs, VGACommonState, VBE_DISPI_INDEX_NB),
- VMSTATE_UINT32(vbe_start_addr, VGACommonState),
- VMSTATE_UINT32(vbe_line_offset, VGACommonState),
- VMSTATE_UINT32(vbe_bank_mask, VGACommonState),
- VMSTATE_END_OF_LIST()
- },
- .subsections = (const VMStateDescription*[]) {
- &vmstate_vga_endian,
- NULL
- }
-};
-
-static const GraphicHwOps vga_ops = {
- .invalidate = vga_invalidate_display,
- .gfx_update = vga_update_display,
- .text_update = vga_update_text,
-};
-
-static inline uint32_t uint_clamp(uint32_t val, uint32_t vmin, uint32_t vmax)
-{
- if (val < vmin) {
- return vmin;
- }
- if (val > vmax) {
- return vmax;
- }
- return val;
-}
-
-void vga_common_init(VGACommonState *s, Object *obj, bool global_vmstate)
-{
- int i, j, v, b;
-
- for(i = 0;i < 256; i++) {
- v = 0;
- for(j = 0; j < 8; j++) {
- v |= ((i >> j) & 1) << (j * 4);
- }
- expand4[i] = v;
-
- v = 0;
- for(j = 0; j < 4; j++) {
- v |= ((i >> (2 * j)) & 3) << (j * 4);
- }
- expand2[i] = v;
- }
- for(i = 0; i < 16; i++) {
- v = 0;
- for(j = 0; j < 4; j++) {
- b = ((i >> j) & 1);
- v |= b << (2 * j);
- v |= b << (2 * j + 1);
- }
- expand4to8[i] = v;
- }
-
- s->vram_size_mb = uint_clamp(s->vram_size_mb, 1, 512);
- s->vram_size_mb = pow2ceil(s->vram_size_mb);
- s->vram_size = s->vram_size_mb << 20;
-
- if (!s->vbe_size) {
- s->vbe_size = s->vram_size;
- }
-
- s->is_vbe_vmstate = 1;
- memory_region_init_ram(&s->vram, obj, "vga.vram", s->vram_size,
- &error_fatal);
- vmstate_register_ram(&s->vram, global_vmstate ? NULL : DEVICE(obj));
- xen_register_framebuffer(&s->vram);
- s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
- s->get_bpp = vga_get_bpp;
- s->get_offsets = vga_get_offsets;
- s->get_resolution = vga_get_resolution;
- s->hw_ops = &vga_ops;
- switch (vga_retrace_method) {
- case VGA_RETRACE_DUMB:
- s->retrace = vga_dumb_retrace;
- s->update_retrace_info = vga_dumb_update_retrace_info;
- break;
-
- case VGA_RETRACE_PRECISE:
- s->retrace = vga_precise_retrace;
- s->update_retrace_info = vga_precise_update_retrace_info;
- break;
- }
-
- /*
- * Set default fb endian based on target, could probably be turned
- * into a device attribute set by the machine/platform to remove
- * all target endian dependencies from this file.
- */
-#ifdef TARGET_WORDS_BIGENDIAN
- s->default_endian_fb = true;
-#else
- s->default_endian_fb = false;
-#endif
- vga_dirty_log_start(s);
-}
-
-static const MemoryRegionPortio vga_portio_list[] = {
- { 0x04, 2, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3b4 */
- { 0x0a, 1, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3ba */
- { 0x10, 16, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3c0 */
- { 0x24, 2, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3d4 */
- { 0x2a, 1, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3da */
- PORTIO_END_OF_LIST(),
-};
-
-static const MemoryRegionPortio vbe_portio_list[] = {
- { 0, 1, 2, .read = vbe_ioport_read_index, .write = vbe_ioport_write_index },
-# ifdef TARGET_I386
- { 1, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
-# endif
- { 2, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
- PORTIO_END_OF_LIST(),
-};
-
-/* Used by both ISA and PCI */
-MemoryRegion *vga_init_io(VGACommonState *s, Object *obj,
- const MemoryRegionPortio **vga_ports,
- const MemoryRegionPortio **vbe_ports)
-{
- MemoryRegion *vga_mem;
-
- *vga_ports = vga_portio_list;
- *vbe_ports = vbe_portio_list;
-
- vga_mem = g_malloc(sizeof(*vga_mem));
- memory_region_init_io(vga_mem, obj, &vga_mem_ops, s,
- "vga-lowmem", 0x20000);
- memory_region_set_flush_coalesced(vga_mem);
-
- return vga_mem;
-}
-
-void vga_init(VGACommonState *s, Object *obj, MemoryRegion *address_space,
- MemoryRegion *address_space_io, bool init_vga_ports)
-{
- MemoryRegion *vga_io_memory;
- const MemoryRegionPortio *vga_ports, *vbe_ports;
-
- qemu_register_reset(vga_reset, s);
-
- s->bank_offset = 0;
-
- s->legacy_address_space = address_space;
-
- vga_io_memory = vga_init_io(s, obj, &vga_ports, &vbe_ports);
- memory_region_add_subregion_overlap(address_space,
- 0x000a0000,
- vga_io_memory,
- 1);
- memory_region_set_coalescing(vga_io_memory);
- if (init_vga_ports) {
- portio_list_init(&s->vga_port_list, obj, vga_ports, s, "vga");
- portio_list_set_flush_coalesced(&s->vga_port_list);
- portio_list_add(&s->vga_port_list, address_space_io, 0x3b0);
- }
- if (vbe_ports) {
- portio_list_init(&s->vbe_port_list, obj, vbe_ports, s, "vbe");
- portio_list_add(&s->vbe_port_list, address_space_io, 0x1ce);
- }
-}
-
-void vga_init_vbe(VGACommonState *s, Object *obj, MemoryRegion *system_memory)
-{
- /* With pc-0.12 and below we map both the PCI BAR and the fixed VBE region,
- * so use an alias to avoid double-mapping the same region.
- */
- memory_region_init_alias(&s->vram_vbe, obj, "vram.vbe",
- &s->vram, 0, memory_region_size(&s->vram));
- /* XXX: use optimized standard vga accesses */
- memory_region_add_subregion(system_memory,
- VBE_DISPI_LFB_PHYSICAL_ADDRESS,
- &s->vram_vbe);
- s->vbe_mapped = 1;
-}
diff --git a/qemu/hw/display/vga.h b/qemu/hw/display/vga.h
deleted file mode 100644
index d917046da..000000000
--- a/qemu/hw/display/vga.h
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * linux/include/video/vga.h -- standard VGA chipset interaction
- *
- * Copyright 1999 Jeff Garzik <jgarzik@pobox.com>
- *
- * Copyright history from vga16fb.c:
- * Copyright 1999 Ben Pfaff and Petr Vandrovec
- * Based on VGA info at http://www.osdever.net/FreeVGA/home.htm
- * Based on VESA framebuffer (c) 1998 Gerd Knorr
- *
- * This file is subject to the terms and conditions of the GNU General
- * Public License. See the file COPYING in the main directory of this
- * archive for more details.
- *
- */
-
-#ifndef __linux_video_vga_h__
-#define __linux_video_vga_h__
-
-/* Some of the code below is taken from SVGAlib. The original,
- unmodified copyright notice for that code is below. */
-/* VGAlib version 1.2 - (c) 1993 Tommy Frandsen */
-/* */
-/* This library is free software; you can redistribute it and/or */
-/* modify it without any restrictions. This library is distributed */
-/* in the hope that it will be useful, but without any warranty. */
-
-/* Multi-chipset support Copyright 1993 Harm Hanemaayer */
-/* partially copyrighted (C) 1993 by Hartmut Schirmer */
-
-/* VGA data register ports */
-#define VGA_CRT_DC 0x3D5 /* CRT Controller Data Register - color emulation */
-#define VGA_CRT_DM 0x3B5 /* CRT Controller Data Register - mono emulation */
-#define VGA_ATT_R 0x3C1 /* Attribute Controller Data Read Register */
-#define VGA_ATT_W 0x3C0 /* Attribute Controller Data Write Register */
-#define VGA_GFX_D 0x3CF /* Graphics Controller Data Register */
-#define VGA_SEQ_D 0x3C5 /* Sequencer Data Register */
-#define VGA_MIS_R 0x3CC /* Misc Output Read Register */
-#define VGA_MIS_W 0x3C2 /* Misc Output Write Register */
-#define VGA_FTC_R 0x3CA /* Feature Control Read Register */
-#define VGA_IS1_RC 0x3DA /* Input Status Register 1 - color emulation */
-#define VGA_IS1_RM 0x3BA /* Input Status Register 1 - mono emulation */
-#define VGA_PEL_D 0x3C9 /* PEL Data Register */
-#define VGA_PEL_MSK 0x3C6 /* PEL mask register */
-
-/* EGA-specific registers */
-#define EGA_GFX_E0 0x3CC /* Graphics enable processor 0 */
-#define EGA_GFX_E1 0x3CA /* Graphics enable processor 1 */
-
-/* VGA index register ports */
-#define VGA_CRT_IC 0x3D4 /* CRT Controller Index - color emulation */
-#define VGA_CRT_IM 0x3B4 /* CRT Controller Index - mono emulation */
-#define VGA_ATT_IW 0x3C0 /* Attribute Controller Index & Data Write Register */
-#define VGA_GFX_I 0x3CE /* Graphics Controller Index */
-#define VGA_SEQ_I 0x3C4 /* Sequencer Index */
-#define VGA_PEL_IW 0x3C8 /* PEL Write Index */
-#define VGA_PEL_IR 0x3C7 /* PEL Read Index */
-
-/* standard VGA indexes max counts */
-#define VGA_CRT_C 0x19 /* Number of CRT Controller Registers */
-#define VGA_ATT_C 0x15 /* Number of Attribute Controller Registers */
-#define VGA_GFX_C 0x09 /* Number of Graphics Controller Registers */
-#define VGA_SEQ_C 0x05 /* Number of Sequencer Registers */
-#define VGA_MIS_C 0x01 /* Number of Misc Output Register */
-
-/* VGA misc register bit masks */
-#define VGA_MIS_COLOR 0x01
-#define VGA_MIS_ENB_MEM_ACCESS 0x02
-#define VGA_MIS_DCLK_28322_720 0x04
-#define VGA_MIS_ENB_PLL_LOAD (0x04 | 0x08)
-#define VGA_MIS_SEL_HIGH_PAGE 0x20
-
-/* VGA CRT controller register indices */
-#define VGA_CRTC_H_TOTAL 0
-#define VGA_CRTC_H_DISP 1
-#define VGA_CRTC_H_BLANK_START 2
-#define VGA_CRTC_H_BLANK_END 3
-#define VGA_CRTC_H_SYNC_START 4
-#define VGA_CRTC_H_SYNC_END 5
-#define VGA_CRTC_V_TOTAL 6
-#define VGA_CRTC_OVERFLOW 7
-#define VGA_CRTC_PRESET_ROW 8
-#define VGA_CRTC_MAX_SCAN 9
-#define VGA_CRTC_CURSOR_START 0x0A
-#define VGA_CRTC_CURSOR_END 0x0B
-#define VGA_CRTC_START_HI 0x0C
-#define VGA_CRTC_START_LO 0x0D
-#define VGA_CRTC_CURSOR_HI 0x0E
-#define VGA_CRTC_CURSOR_LO 0x0F
-#define VGA_CRTC_V_SYNC_START 0x10
-#define VGA_CRTC_V_SYNC_END 0x11
-#define VGA_CRTC_V_DISP_END 0x12
-#define VGA_CRTC_OFFSET 0x13
-#define VGA_CRTC_UNDERLINE 0x14
-#define VGA_CRTC_V_BLANK_START 0x15
-#define VGA_CRTC_V_BLANK_END 0x16
-#define VGA_CRTC_MODE 0x17
-#define VGA_CRTC_LINE_COMPARE 0x18
-#define VGA_CRTC_REGS VGA_CRT_C
-
-/* VGA CRT controller bit masks */
-#define VGA_CR11_LOCK_CR0_CR7 0x80 /* lock writes to CR0 - CR7 */
-#define VGA_CR17_H_V_SIGNALS_ENABLED 0x80
-
-/* VGA attribute controller register indices */
-#define VGA_ATC_PALETTE0 0x00
-#define VGA_ATC_PALETTE1 0x01
-#define VGA_ATC_PALETTE2 0x02
-#define VGA_ATC_PALETTE3 0x03
-#define VGA_ATC_PALETTE4 0x04
-#define VGA_ATC_PALETTE5 0x05
-#define VGA_ATC_PALETTE6 0x06
-#define VGA_ATC_PALETTE7 0x07
-#define VGA_ATC_PALETTE8 0x08
-#define VGA_ATC_PALETTE9 0x09
-#define VGA_ATC_PALETTEA 0x0A
-#define VGA_ATC_PALETTEB 0x0B
-#define VGA_ATC_PALETTEC 0x0C
-#define VGA_ATC_PALETTED 0x0D
-#define VGA_ATC_PALETTEE 0x0E
-#define VGA_ATC_PALETTEF 0x0F
-#define VGA_ATC_MODE 0x10
-#define VGA_ATC_OVERSCAN 0x11
-#define VGA_ATC_PLANE_ENABLE 0x12
-#define VGA_ATC_PEL 0x13
-#define VGA_ATC_COLOR_PAGE 0x14
-
-#define VGA_AR_ENABLE_DISPLAY 0x20
-
-/* VGA sequencer register indices */
-#define VGA_SEQ_RESET 0x00
-#define VGA_SEQ_CLOCK_MODE 0x01
-#define VGA_SEQ_PLANE_WRITE 0x02
-#define VGA_SEQ_CHARACTER_MAP 0x03
-#define VGA_SEQ_MEMORY_MODE 0x04
-
-/* VGA sequencer register bit masks */
-#define VGA_SR01_CHAR_CLK_8DOTS 0x01 /* bit 0: character clocks 8 dots wide are generated */
-#define VGA_SR01_SCREEN_OFF 0x20 /* bit 5: Screen is off */
-#define VGA_SR02_ALL_PLANES 0x0F /* bits 3-0: enable access to all planes */
-#define VGA_SR04_EXT_MEM 0x02 /* bit 1: allows complete mem access to 256K */
-#define VGA_SR04_SEQ_MODE 0x04 /* bit 2: directs system to use a sequential addressing mode */
-#define VGA_SR04_CHN_4M 0x08 /* bit 3: selects modulo 4 addressing for CPU access to display memory */
-
-/* VGA graphics controller register indices */
-#define VGA_GFX_SR_VALUE 0x00
-#define VGA_GFX_SR_ENABLE 0x01
-#define VGA_GFX_COMPARE_VALUE 0x02
-#define VGA_GFX_DATA_ROTATE 0x03
-#define VGA_GFX_PLANE_READ 0x04
-#define VGA_GFX_MODE 0x05
-#define VGA_GFX_MISC 0x06
-#define VGA_GFX_COMPARE_MASK 0x07
-#define VGA_GFX_BIT_MASK 0x08
-
-/* VGA graphics controller bit masks */
-#define VGA_GR06_GRAPHICS_MODE 0x01
-
-#endif /* __linux_video_vga_h__ */
diff --git a/qemu/hw/display/vga_int.h b/qemu/hw/display/vga_int.h
deleted file mode 100644
index bdb43a5a3..000000000
--- a/qemu/hw/display/vga_int.h
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * QEMU internal VGA defines.
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- *
- * 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.
- */
-#ifndef HW_VGA_INT_H
-#define HW_VGA_INT_H 1
-
-#include <hw/hw.h>
-#include "exec/memory.h"
-
-#define ST01_V_RETRACE 0x08
-#define ST01_DISP_ENABLE 0x01
-
-#define VBE_DISPI_MAX_XRES 16000
-#define VBE_DISPI_MAX_YRES 12000
-#define VBE_DISPI_MAX_BPP 32
-
-#define VBE_DISPI_INDEX_ID 0x0
-#define VBE_DISPI_INDEX_XRES 0x1
-#define VBE_DISPI_INDEX_YRES 0x2
-#define VBE_DISPI_INDEX_BPP 0x3
-#define VBE_DISPI_INDEX_ENABLE 0x4
-#define VBE_DISPI_INDEX_BANK 0x5
-#define VBE_DISPI_INDEX_VIRT_WIDTH 0x6
-#define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7
-#define VBE_DISPI_INDEX_X_OFFSET 0x8
-#define VBE_DISPI_INDEX_Y_OFFSET 0x9
-#define VBE_DISPI_INDEX_NB 0xa /* size of vbe_regs[] */
-#define VBE_DISPI_INDEX_VIDEO_MEMORY_64K 0xa /* read-only, not in vbe_regs */
-
-#define VBE_DISPI_ID0 0xB0C0
-#define VBE_DISPI_ID1 0xB0C1
-#define VBE_DISPI_ID2 0xB0C2
-#define VBE_DISPI_ID3 0xB0C3
-#define VBE_DISPI_ID4 0xB0C4
-#define VBE_DISPI_ID5 0xB0C5
-
-#define VBE_DISPI_DISABLED 0x00
-#define VBE_DISPI_ENABLED 0x01
-#define VBE_DISPI_GETCAPS 0x02
-#define VBE_DISPI_8BIT_DAC 0x20
-#define VBE_DISPI_LFB_ENABLED 0x40
-#define VBE_DISPI_NOCLEARMEM 0x80
-
-#define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000
-
-#define CH_ATTR_SIZE (160 * 100)
-#define VGA_MAX_HEIGHT 2048
-
-struct vga_precise_retrace {
- int64_t ticks_per_char;
- int64_t total_chars;
- int htotal;
- int hstart;
- int hend;
- int vstart;
- int vend;
- int freq;
-};
-
-union vga_retrace {
- struct vga_precise_retrace precise;
-};
-
-struct VGACommonState;
-typedef uint8_t (* vga_retrace_fn)(struct VGACommonState *s);
-typedef void (* vga_update_retrace_info_fn)(struct VGACommonState *s);
-
-typedef struct VGACommonState {
- MemoryRegion *legacy_address_space;
- uint8_t *vram_ptr;
- MemoryRegion vram;
- MemoryRegion vram_vbe;
- uint32_t vram_size;
- uint32_t vram_size_mb; /* property */
- uint32_t vbe_size;
- uint32_t latch;
- bool has_chain4_alias;
- MemoryRegion chain4_alias;
- uint8_t sr_index;
- uint8_t sr[256];
- uint8_t gr_index;
- uint8_t gr[256];
- uint8_t ar_index;
- uint8_t ar[21];
- int ar_flip_flop;
- uint8_t cr_index;
- uint8_t cr[256]; /* CRT registers */
- uint8_t msr; /* Misc Output Register */
- uint8_t fcr; /* Feature Control Register */
- uint8_t st00; /* status 0 */
- uint8_t st01; /* status 1 */
- uint8_t dac_state;
- uint8_t dac_sub_index;
- uint8_t dac_read_index;
- uint8_t dac_write_index;
- uint8_t dac_cache[3]; /* used when writing */
- int dac_8bit;
- uint8_t palette[768];
- int32_t bank_offset;
- int (*get_bpp)(struct VGACommonState *s);
- void (*get_offsets)(struct VGACommonState *s,
- uint32_t *pline_offset,
- uint32_t *pstart_addr,
- uint32_t *pline_compare);
- void (*get_resolution)(struct VGACommonState *s,
- int *pwidth,
- int *pheight);
- PortioList vga_port_list;
- PortioList vbe_port_list;
- /* bochs vbe state */
- uint16_t vbe_index;
- uint16_t vbe_regs[VBE_DISPI_INDEX_NB];
- uint32_t vbe_start_addr;
- uint32_t vbe_line_offset;
- uint32_t vbe_bank_mask;
- int vbe_mapped;
- /* display refresh support */
- QemuConsole *con;
- uint32_t font_offsets[2];
- int graphic_mode;
- uint8_t shift_control;
- uint8_t double_scan;
- uint32_t line_offset;
- uint32_t line_compare;
- uint32_t start_addr;
- uint32_t plane_updated;
- uint32_t last_line_offset;
- uint8_t last_cw, last_ch;
- uint32_t last_width, last_height; /* in chars or pixels */
- uint32_t last_scr_width, last_scr_height; /* in pixels */
- uint32_t last_depth; /* in bits */
- bool last_byteswap;
- bool force_shadow;
- uint8_t cursor_start, cursor_end;
- bool cursor_visible_phase;
- int64_t cursor_blink_time;
- uint32_t cursor_offset;
- const GraphicHwOps *hw_ops;
- bool full_update_text;
- bool full_update_gfx;
- bool big_endian_fb;
- bool default_endian_fb;
- /* hardware mouse cursor support */
- uint32_t invalidated_y_table[VGA_MAX_HEIGHT / 32];
- uint32_t hw_cursor_x;
- uint32_t hw_cursor_y;
- void (*cursor_invalidate)(struct VGACommonState *s);
- void (*cursor_draw_line)(struct VGACommonState *s, uint8_t *d, int y);
- /* tell for each page if it has been updated since the last time */
- uint32_t last_palette[256];
- uint32_t last_ch_attr[CH_ATTR_SIZE]; /* XXX: make it dynamic */
- /* retrace */
- vga_retrace_fn retrace;
- vga_update_retrace_info_fn update_retrace_info;
- union vga_retrace retrace_info;
- uint8_t is_vbe_vmstate;
-} VGACommonState;
-
-static inline int c6_to_8(int v)
-{
- int b;
- v &= 0x3f;
- b = v & 1;
- return (v << 2) | (b << 1) | b;
-}
-
-void vga_common_init(VGACommonState *s, Object *obj, bool global_vmstate);
-void vga_init(VGACommonState *s, Object *obj, MemoryRegion *address_space,
- MemoryRegion *address_space_io, bool init_vga_ports);
-MemoryRegion *vga_init_io(VGACommonState *s, Object *obj,
- const MemoryRegionPortio **vga_ports,
- const MemoryRegionPortio **vbe_ports);
-void vga_common_reset(VGACommonState *s);
-
-void vga_sync_dirty_bitmap(VGACommonState *s);
-void vga_dirty_log_start(VGACommonState *s);
-void vga_dirty_log_stop(VGACommonState *s);
-
-extern const VMStateDescription vmstate_vga_common;
-uint32_t vga_ioport_read(void *opaque, uint32_t addr);
-void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val);
-uint32_t vga_mem_readb(VGACommonState *s, hwaddr addr);
-void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val);
-void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2);
-
-int vga_ioport_invalid(VGACommonState *s, uint32_t addr);
-
-void vga_init_vbe(VGACommonState *s, Object *obj, MemoryRegion *address_space);
-uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr);
-void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val);
-void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val);
-
-extern const uint8_t sr_mask[8];
-extern const uint8_t gr_mask[16];
-
-#define VGABIOS_FILENAME "vgabios.bin"
-#define VGABIOS_CIRRUS_FILENAME "vgabios-cirrus.bin"
-
-extern const MemoryRegionOps vga_mem_ops;
-
-/* vga-pci.c */
-void pci_std_vga_mmio_region_init(VGACommonState *s,
- MemoryRegion *parent,
- MemoryRegion *subs,
- bool qext);
-
-#endif
diff --git a/qemu/hw/display/virtio-gpu-3d.c b/qemu/hw/display/virtio-gpu-3d.c
deleted file mode 100644
index fa192946a..000000000
--- a/qemu/hw/display/virtio-gpu-3d.c
+++ /dev/null
@@ -1,606 +0,0 @@
-/*
- * Virtio GPU Device
- *
- * Copyright Red Hat, Inc. 2013-2014
- *
- * Authors:
- * Dave Airlie <airlied@redhat.com>
- * Gerd Hoffmann <kraxel@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "qemu/iov.h"
-#include "trace.h"
-#include "hw/virtio/virtio.h"
-#include "hw/virtio/virtio-gpu.h"
-
-#ifdef CONFIG_VIRGL
-
-#include "virglrenderer.h"
-
-static struct virgl_renderer_callbacks virtio_gpu_3d_cbs;
-
-static void virgl_cmd_create_resource_2d(VirtIOGPU *g,
- struct virtio_gpu_ctrl_command *cmd)
-{
- struct virtio_gpu_resource_create_2d c2d;
- struct virgl_renderer_resource_create_args args;
-
- VIRTIO_GPU_FILL_CMD(c2d);
- trace_virtio_gpu_cmd_res_create_2d(c2d.resource_id, c2d.format,
- c2d.width, c2d.height);
-
- args.handle = c2d.resource_id;
- args.target = 2;
- args.format = c2d.format;
- args.bind = (1 << 1);
- args.width = c2d.width;
- args.height = c2d.height;
- args.depth = 1;
- args.array_size = 1;
- args.last_level = 0;
- args.nr_samples = 0;
- args.flags = VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP;
- virgl_renderer_resource_create(&args, NULL, 0);
-}
-
-static void virgl_cmd_create_resource_3d(VirtIOGPU *g,
- struct virtio_gpu_ctrl_command *cmd)
-{
- struct virtio_gpu_resource_create_3d c3d;
- struct virgl_renderer_resource_create_args args;
-
- VIRTIO_GPU_FILL_CMD(c3d);
- trace_virtio_gpu_cmd_res_create_3d(c3d.resource_id, c3d.format,
- c3d.width, c3d.height, c3d.depth);
-
- args.handle = c3d.resource_id;
- args.target = c3d.target;
- args.format = c3d.format;
- args.bind = c3d.bind;
- args.width = c3d.width;
- args.height = c3d.height;
- args.depth = c3d.depth;
- args.array_size = c3d.array_size;
- args.last_level = c3d.last_level;
- args.nr_samples = c3d.nr_samples;
- args.flags = c3d.flags;
- virgl_renderer_resource_create(&args, NULL, 0);
-}
-
-static void virgl_cmd_resource_unref(VirtIOGPU *g,
- struct virtio_gpu_ctrl_command *cmd)
-{
- struct virtio_gpu_resource_unref unref;
-
- VIRTIO_GPU_FILL_CMD(unref);
- trace_virtio_gpu_cmd_res_unref(unref.resource_id);
-
- virgl_renderer_resource_unref(unref.resource_id);
-}
-
-static void virgl_cmd_context_create(VirtIOGPU *g,
- struct virtio_gpu_ctrl_command *cmd)
-{
- struct virtio_gpu_ctx_create cc;
-
- VIRTIO_GPU_FILL_CMD(cc);
- trace_virtio_gpu_cmd_ctx_create(cc.hdr.ctx_id,
- cc.debug_name);
-
- virgl_renderer_context_create(cc.hdr.ctx_id, cc.nlen,
- cc.debug_name);
-}
-
-static void virgl_cmd_context_destroy(VirtIOGPU *g,
- struct virtio_gpu_ctrl_command *cmd)
-{
- struct virtio_gpu_ctx_destroy cd;
-
- VIRTIO_GPU_FILL_CMD(cd);
- trace_virtio_gpu_cmd_ctx_destroy(cd.hdr.ctx_id);
-
- virgl_renderer_context_destroy(cd.hdr.ctx_id);
-}
-
-static void virtio_gpu_rect_update(VirtIOGPU *g, int idx, int x, int y,
- int width, int height)
-{
- if (!g->scanout[idx].con) {
- return;
- }
-
- dpy_gl_update(g->scanout[idx].con, x, y, width, height);
-}
-
-static void virgl_cmd_resource_flush(VirtIOGPU *g,
- struct virtio_gpu_ctrl_command *cmd)
-{
- struct virtio_gpu_resource_flush rf;
- int i;
-
- VIRTIO_GPU_FILL_CMD(rf);
- trace_virtio_gpu_cmd_res_flush(rf.resource_id,
- rf.r.width, rf.r.height, rf.r.x, rf.r.y);
-
- for (i = 0; i < VIRTIO_GPU_MAX_SCANOUT; i++) {
- if (g->scanout[i].resource_id != rf.resource_id) {
- continue;
- }
- virtio_gpu_rect_update(g, i, rf.r.x, rf.r.y, rf.r.width, rf.r.height);
- }
-}
-
-static void virgl_cmd_set_scanout(VirtIOGPU *g,
- struct virtio_gpu_ctrl_command *cmd)
-{
- struct virtio_gpu_set_scanout ss;
- struct virgl_renderer_resource_info info;
- int ret;
-
- VIRTIO_GPU_FILL_CMD(ss);
- trace_virtio_gpu_cmd_set_scanout(ss.scanout_id, ss.resource_id,
- ss.r.width, ss.r.height, ss.r.x, ss.r.y);
-
- if (ss.scanout_id >= VIRTIO_GPU_MAX_SCANOUT) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout id specified %d",
- __func__, ss.scanout_id);
- cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID;
- return;
- }
- g->enable = 1;
-
- memset(&info, 0, sizeof(info));
-
- if (ss.resource_id && ss.r.width && ss.r.height) {
- ret = virgl_renderer_resource_get_info(ss.resource_id, &info);
- if (ret == -1) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: illegal resource specified %d\n",
- __func__, ss.resource_id);
- cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
- return;
- }
- qemu_console_resize(g->scanout[ss.scanout_id].con,
- ss.r.width, ss.r.height);
- virgl_renderer_force_ctx_0();
- dpy_gl_scanout(g->scanout[ss.scanout_id].con, info.tex_id,
- info.flags & 1 /* FIXME: Y_0_TOP */,
- ss.r.x, ss.r.y, ss.r.width, ss.r.height);
- } else {
- if (ss.scanout_id != 0) {
- dpy_gfx_replace_surface(g->scanout[ss.scanout_id].con, NULL);
- }
- dpy_gl_scanout(g->scanout[ss.scanout_id].con, 0, false,
- 0, 0, 0, 0);
- }
- g->scanout[ss.scanout_id].resource_id = ss.resource_id;
-}
-
-static void virgl_cmd_submit_3d(VirtIOGPU *g,
- struct virtio_gpu_ctrl_command *cmd)
-{
- struct virtio_gpu_cmd_submit cs;
- void *buf;
- size_t s;
-
- VIRTIO_GPU_FILL_CMD(cs);
- trace_virtio_gpu_cmd_ctx_submit(cs.hdr.ctx_id, cs.size);
-
- buf = g_malloc(cs.size);
- s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num,
- sizeof(cs), buf, cs.size);
- if (s != cs.size) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: size mismatch (%zd/%d)",
- __func__, s, cs.size);
- cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
- goto out;
- }
-
- if (virtio_gpu_stats_enabled(g->conf)) {
- g->stats.req_3d++;
- g->stats.bytes_3d += cs.size;
- }
-
- virgl_renderer_submit_cmd(buf, cs.hdr.ctx_id, cs.size / 4);
-
-out:
- g_free(buf);
-}
-
-static void virgl_cmd_transfer_to_host_2d(VirtIOGPU *g,
- struct virtio_gpu_ctrl_command *cmd)
-{
- struct virtio_gpu_transfer_to_host_2d t2d;
- struct virtio_gpu_box box;
-
- VIRTIO_GPU_FILL_CMD(t2d);
- trace_virtio_gpu_cmd_res_xfer_toh_2d(t2d.resource_id);
-
- box.x = t2d.r.x;
- box.y = t2d.r.y;
- box.z = 0;
- box.w = t2d.r.width;
- box.h = t2d.r.height;
- box.d = 1;
-
- virgl_renderer_transfer_write_iov(t2d.resource_id,
- 0,
- 0,
- 0,
- 0,
- (struct virgl_box *)&box,
- t2d.offset, NULL, 0);
-}
-
-static void virgl_cmd_transfer_to_host_3d(VirtIOGPU *g,
- struct virtio_gpu_ctrl_command *cmd)
-{
- struct virtio_gpu_transfer_host_3d t3d;
-
- VIRTIO_GPU_FILL_CMD(t3d);
- trace_virtio_gpu_cmd_res_xfer_toh_3d(t3d.resource_id);
-
- virgl_renderer_transfer_write_iov(t3d.resource_id,
- t3d.hdr.ctx_id,
- t3d.level,
- t3d.stride,
- t3d.layer_stride,
- (struct virgl_box *)&t3d.box,
- t3d.offset, NULL, 0);
-}
-
-static void
-virgl_cmd_transfer_from_host_3d(VirtIOGPU *g,
- struct virtio_gpu_ctrl_command *cmd)
-{
- struct virtio_gpu_transfer_host_3d tf3d;
-
- VIRTIO_GPU_FILL_CMD(tf3d);
- trace_virtio_gpu_cmd_res_xfer_fromh_3d(tf3d.resource_id);
-
- virgl_renderer_transfer_read_iov(tf3d.resource_id,
- tf3d.hdr.ctx_id,
- tf3d.level,
- tf3d.stride,
- tf3d.layer_stride,
- (struct virgl_box *)&tf3d.box,
- tf3d.offset, NULL, 0);
-}
-
-
-static void virgl_resource_attach_backing(VirtIOGPU *g,
- struct virtio_gpu_ctrl_command *cmd)
-{
- struct virtio_gpu_resource_attach_backing att_rb;
- struct iovec *res_iovs;
- int ret;
-
- VIRTIO_GPU_FILL_CMD(att_rb);
- trace_virtio_gpu_cmd_res_back_attach(att_rb.resource_id);
-
- ret = virtio_gpu_create_mapping_iov(&att_rb, cmd, &res_iovs);
- if (ret != 0) {
- cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
- return;
- }
-
- virgl_renderer_resource_attach_iov(att_rb.resource_id,
- res_iovs, att_rb.nr_entries);
-}
-
-static void virgl_resource_detach_backing(VirtIOGPU *g,
- struct virtio_gpu_ctrl_command *cmd)
-{
- struct virtio_gpu_resource_detach_backing detach_rb;
- struct iovec *res_iovs = NULL;
- int num_iovs = 0;
-
- VIRTIO_GPU_FILL_CMD(detach_rb);
- trace_virtio_gpu_cmd_res_back_detach(detach_rb.resource_id);
-
- virgl_renderer_resource_detach_iov(detach_rb.resource_id,
- &res_iovs,
- &num_iovs);
- if (res_iovs == NULL || num_iovs == 0) {
- return;
- }
- virtio_gpu_cleanup_mapping_iov(res_iovs, num_iovs);
-}
-
-
-static void virgl_cmd_ctx_attach_resource(VirtIOGPU *g,
- struct virtio_gpu_ctrl_command *cmd)
-{
- struct virtio_gpu_ctx_resource att_res;
-
- VIRTIO_GPU_FILL_CMD(att_res);
- trace_virtio_gpu_cmd_ctx_res_attach(att_res.hdr.ctx_id,
- att_res.resource_id);
-
- virgl_renderer_ctx_attach_resource(att_res.hdr.ctx_id, att_res.resource_id);
-}
-
-static void virgl_cmd_ctx_detach_resource(VirtIOGPU *g,
- struct virtio_gpu_ctrl_command *cmd)
-{
- struct virtio_gpu_ctx_resource det_res;
-
- VIRTIO_GPU_FILL_CMD(det_res);
- trace_virtio_gpu_cmd_ctx_res_detach(det_res.hdr.ctx_id,
- det_res.resource_id);
-
- virgl_renderer_ctx_detach_resource(det_res.hdr.ctx_id, det_res.resource_id);
-}
-
-static void virgl_cmd_get_capset_info(VirtIOGPU *g,
- struct virtio_gpu_ctrl_command *cmd)
-{
- struct virtio_gpu_get_capset_info info;
- struct virtio_gpu_resp_capset_info resp;
-
- VIRTIO_GPU_FILL_CMD(info);
-
- if (info.capset_index == 0) {
- resp.capset_id = VIRTIO_GPU_CAPSET_VIRGL;
- virgl_renderer_get_cap_set(resp.capset_id,
- &resp.capset_max_version,
- &resp.capset_max_size);
- } else {
- resp.capset_max_version = 0;
- resp.capset_max_size = 0;
- }
- resp.hdr.type = VIRTIO_GPU_RESP_OK_CAPSET_INFO;
- virtio_gpu_ctrl_response(g, cmd, &resp.hdr, sizeof(resp));
-}
-
-static void virgl_cmd_get_capset(VirtIOGPU *g,
- struct virtio_gpu_ctrl_command *cmd)
-{
- struct virtio_gpu_get_capset gc;
- struct virtio_gpu_resp_capset *resp;
- uint32_t max_ver, max_size;
- VIRTIO_GPU_FILL_CMD(gc);
-
- virgl_renderer_get_cap_set(gc.capset_id, &max_ver,
- &max_size);
- resp = g_malloc(sizeof(*resp) + max_size);
-
- resp->hdr.type = VIRTIO_GPU_RESP_OK_CAPSET;
- virgl_renderer_fill_caps(gc.capset_id,
- gc.capset_version,
- (void *)resp->capset_data);
- virtio_gpu_ctrl_response(g, cmd, &resp->hdr, sizeof(*resp) + max_size);
- g_free(resp);
-}
-
-void virtio_gpu_virgl_process_cmd(VirtIOGPU *g,
- struct virtio_gpu_ctrl_command *cmd)
-{
- VIRTIO_GPU_FILL_CMD(cmd->cmd_hdr);
-
- cmd->waiting = g->renderer_blocked;
- if (cmd->waiting) {
- return;
- }
-
- virgl_renderer_force_ctx_0();
- switch (cmd->cmd_hdr.type) {
- case VIRTIO_GPU_CMD_CTX_CREATE:
- virgl_cmd_context_create(g, cmd);
- break;
- case VIRTIO_GPU_CMD_CTX_DESTROY:
- virgl_cmd_context_destroy(g, cmd);
- break;
- case VIRTIO_GPU_CMD_RESOURCE_CREATE_2D:
- virgl_cmd_create_resource_2d(g, cmd);
- break;
- case VIRTIO_GPU_CMD_RESOURCE_CREATE_3D:
- virgl_cmd_create_resource_3d(g, cmd);
- break;
- case VIRTIO_GPU_CMD_SUBMIT_3D:
- virgl_cmd_submit_3d(g, cmd);
- break;
- case VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D:
- virgl_cmd_transfer_to_host_2d(g, cmd);
- break;
- case VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D:
- virgl_cmd_transfer_to_host_3d(g, cmd);
- break;
- case VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D:
- virgl_cmd_transfer_from_host_3d(g, cmd);
- break;
- case VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING:
- virgl_resource_attach_backing(g, cmd);
- break;
- case VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING:
- virgl_resource_detach_backing(g, cmd);
- break;
- case VIRTIO_GPU_CMD_SET_SCANOUT:
- virgl_cmd_set_scanout(g, cmd);
- break;
- case VIRTIO_GPU_CMD_RESOURCE_FLUSH:
- virgl_cmd_resource_flush(g, cmd);
- break;
- case VIRTIO_GPU_CMD_RESOURCE_UNREF:
- virgl_cmd_resource_unref(g, cmd);
- break;
- case VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE:
- /* TODO add security */
- virgl_cmd_ctx_attach_resource(g, cmd);
- break;
- case VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE:
- /* TODO add security */
- virgl_cmd_ctx_detach_resource(g, cmd);
- break;
- case VIRTIO_GPU_CMD_GET_CAPSET_INFO:
- virgl_cmd_get_capset_info(g, cmd);
- break;
- case VIRTIO_GPU_CMD_GET_CAPSET:
- virgl_cmd_get_capset(g, cmd);
- break;
-
- case VIRTIO_GPU_CMD_GET_DISPLAY_INFO:
- virtio_gpu_get_display_info(g, cmd);
- break;
- default:
- cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
- break;
- }
-
- if (cmd->finished) {
- return;
- }
- if (cmd->error) {
- fprintf(stderr, "%s: ctrl 0x%x, error 0x%x\n", __func__,
- cmd->cmd_hdr.type, cmd->error);
- virtio_gpu_ctrl_response_nodata(g, cmd, cmd->error);
- return;
- }
- if (!(cmd->cmd_hdr.flags & VIRTIO_GPU_FLAG_FENCE)) {
- virtio_gpu_ctrl_response_nodata(g, cmd, VIRTIO_GPU_RESP_OK_NODATA);
- return;
- }
-
- trace_virtio_gpu_fence_ctrl(cmd->cmd_hdr.fence_id, cmd->cmd_hdr.type);
- virgl_renderer_create_fence(cmd->cmd_hdr.fence_id, cmd->cmd_hdr.type);
-}
-
-static void virgl_write_fence(void *opaque, uint32_t fence)
-{
- VirtIOGPU *g = opaque;
- struct virtio_gpu_ctrl_command *cmd, *tmp;
-
- QTAILQ_FOREACH_SAFE(cmd, &g->fenceq, next, tmp) {
- /*
- * the guest can end up emitting fences out of order
- * so we should check all fenced cmds not just the first one.
- */
- if (cmd->cmd_hdr.fence_id > fence) {
- continue;
- }
- trace_virtio_gpu_fence_resp(cmd->cmd_hdr.fence_id);
- virtio_gpu_ctrl_response_nodata(g, cmd, VIRTIO_GPU_RESP_OK_NODATA);
- QTAILQ_REMOVE(&g->fenceq, cmd, next);
- g_free(cmd);
- g->inflight--;
- if (virtio_gpu_stats_enabled(g->conf)) {
- fprintf(stderr, "inflight: %3d (-)\r", g->inflight);
- }
- }
-}
-
-static virgl_renderer_gl_context
-virgl_create_context(void *opaque, int scanout_idx,
- struct virgl_renderer_gl_ctx_param *params)
-{
- VirtIOGPU *g = opaque;
- QEMUGLContext ctx;
- QEMUGLParams qparams;
-
- qparams.major_ver = params->major_ver;
- qparams.minor_ver = params->minor_ver;
-
- ctx = dpy_gl_ctx_create(g->scanout[scanout_idx].con, &qparams);
- return (virgl_renderer_gl_context)ctx;
-}
-
-static void virgl_destroy_context(void *opaque, virgl_renderer_gl_context ctx)
-{
- VirtIOGPU *g = opaque;
- QEMUGLContext qctx = (QEMUGLContext)ctx;
-
- dpy_gl_ctx_destroy(g->scanout[0].con, qctx);
-}
-
-static int virgl_make_context_current(void *opaque, int scanout_idx,
- virgl_renderer_gl_context ctx)
-{
- VirtIOGPU *g = opaque;
- QEMUGLContext qctx = (QEMUGLContext)ctx;
-
- return dpy_gl_ctx_make_current(g->scanout[scanout_idx].con, qctx);
-}
-
-static struct virgl_renderer_callbacks virtio_gpu_3d_cbs = {
- .version = 1,
- .write_fence = virgl_write_fence,
- .create_gl_context = virgl_create_context,
- .destroy_gl_context = virgl_destroy_context,
- .make_current = virgl_make_context_current,
-};
-
-static void virtio_gpu_print_stats(void *opaque)
-{
- VirtIOGPU *g = opaque;
-
- if (g->stats.requests) {
- fprintf(stderr, "stats: vq req %4d, %3d -- 3D %4d (%5d)\n",
- g->stats.requests,
- g->stats.max_inflight,
- g->stats.req_3d,
- g->stats.bytes_3d);
- g->stats.requests = 0;
- g->stats.max_inflight = 0;
- g->stats.req_3d = 0;
- g->stats.bytes_3d = 0;
- } else {
- fprintf(stderr, "stats: idle\r");
- }
- timer_mod(g->print_stats, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 1000);
-}
-
-static void virtio_gpu_fence_poll(void *opaque)
-{
- VirtIOGPU *g = opaque;
-
- virgl_renderer_poll();
- virtio_gpu_process_cmdq(g);
- if (!QTAILQ_EMPTY(&g->cmdq) || !QTAILQ_EMPTY(&g->fenceq)) {
- timer_mod(g->fence_poll, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 10);
- }
-}
-
-void virtio_gpu_virgl_fence_poll(VirtIOGPU *g)
-{
- virtio_gpu_fence_poll(g);
-}
-
-void virtio_gpu_virgl_reset(VirtIOGPU *g)
-{
- int i;
-
- /* virgl_renderer_reset() ??? */
- for (i = 0; i < g->conf.max_outputs; i++) {
- if (i != 0) {
- dpy_gfx_replace_surface(g->scanout[i].con, NULL);
- }
- dpy_gl_scanout(g->scanout[i].con, 0, false, 0, 0, 0, 0);
- }
-}
-
-int virtio_gpu_virgl_init(VirtIOGPU *g)
-{
- int ret;
-
- ret = virgl_renderer_init(g, 0, &virtio_gpu_3d_cbs);
- if (ret != 0) {
- return ret;
- }
-
- g->fence_poll = timer_new_ms(QEMU_CLOCK_VIRTUAL,
- virtio_gpu_fence_poll, g);
-
- if (virtio_gpu_stats_enabled(g->conf)) {
- g->print_stats = timer_new_ms(QEMU_CLOCK_VIRTUAL,
- virtio_gpu_print_stats, g);
- timer_mod(g->print_stats, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 1000);
- }
- return 0;
-}
-
-#endif /* CONFIG_VIRGL */
diff --git a/qemu/hw/display/virtio-gpu-pci.c b/qemu/hw/display/virtio-gpu-pci.c
deleted file mode 100644
index a71b230d3..000000000
--- a/qemu/hw/display/virtio-gpu-pci.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Virtio video device
- *
- * Copyright Red Hat
- *
- * Authors:
- * Dave Airlie
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- */
-#include "qemu/osdep.h"
-#include "hw/pci/pci.h"
-#include "hw/virtio/virtio.h"
-#include "hw/virtio/virtio-bus.h"
-#include "hw/virtio/virtio-pci.h"
-#include "hw/virtio/virtio-gpu.h"
-
-static Property virtio_gpu_pci_properties[] = {
- DEFINE_VIRTIO_GPU_PCI_PROPERTIES(VirtIOPCIProxy),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_gpu_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
-{
- VirtIOGPUPCI *vgpu = VIRTIO_GPU_PCI(vpci_dev);
- VirtIOGPU *g = &vgpu->vdev;
- DeviceState *vdev = DEVICE(&vgpu->vdev);
- int i;
-
- qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
- /* force virtio-1.0 */
- vpci_dev->flags &= ~VIRTIO_PCI_FLAG_DISABLE_MODERN;
- vpci_dev->flags |= VIRTIO_PCI_FLAG_DISABLE_LEGACY;
- object_property_set_bool(OBJECT(vdev), true, "realized", errp);
-
- for (i = 0; i < g->conf.max_outputs; i++) {
- object_property_set_link(OBJECT(g->scanout[i].con),
- OBJECT(vpci_dev),
- "device", errp);
- }
-}
-
-static void virtio_gpu_pci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
- PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
-
- set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
- dc->props = virtio_gpu_pci_properties;
- k->realize = virtio_gpu_pci_realize;
- pcidev_k->class_id = PCI_CLASS_DISPLAY_OTHER;
-}
-
-static void virtio_gpu_initfn(Object *obj)
-{
- VirtIOGPUPCI *dev = VIRTIO_GPU_PCI(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VIRTIO_GPU);
-}
-
-static const TypeInfo virtio_gpu_pci_info = {
- .name = TYPE_VIRTIO_GPU_PCI,
- .parent = TYPE_VIRTIO_PCI,
- .instance_size = sizeof(VirtIOGPUPCI),
- .instance_init = virtio_gpu_initfn,
- .class_init = virtio_gpu_pci_class_init,
-};
-
-static void virtio_gpu_pci_register_types(void)
-{
- type_register_static(&virtio_gpu_pci_info);
-}
-type_init(virtio_gpu_pci_register_types)
diff --git a/qemu/hw/display/virtio-gpu.c b/qemu/hw/display/virtio-gpu.c
deleted file mode 100644
index c181fb364..000000000
--- a/qemu/hw/display/virtio-gpu.c
+++ /dev/null
@@ -1,1087 +0,0 @@
-/*
- * Virtio GPU Device
- *
- * Copyright Red Hat, Inc. 2013-2014
- *
- * Authors:
- * Dave Airlie <airlied@redhat.com>
- * Gerd Hoffmann <kraxel@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "qemu/iov.h"
-#include "ui/console.h"
-#include "trace.h"
-#include "hw/virtio/virtio.h"
-#include "hw/virtio/virtio-gpu.h"
-#include "hw/virtio/virtio-bus.h"
-
-static struct virtio_gpu_simple_resource*
-virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id);
-
-#ifdef CONFIG_VIRGL
-#include "virglrenderer.h"
-#define VIRGL(_g, _virgl, _simple, ...) \
- do { \
- if (_g->use_virgl_renderer) { \
- _virgl(__VA_ARGS__); \
- } else { \
- _simple(__VA_ARGS__); \
- } \
- } while (0)
-#else
-#define VIRGL(_g, _virgl, _simple, ...) \
- do { \
- _simple(__VA_ARGS__); \
- } while (0)
-#endif
-
-static void update_cursor_data_simple(VirtIOGPU *g,
- struct virtio_gpu_scanout *s,
- uint32_t resource_id)
-{
- struct virtio_gpu_simple_resource *res;
- uint32_t pixels;
-
- res = virtio_gpu_find_resource(g, resource_id);
- if (!res) {
- return;
- }
-
- if (pixman_image_get_width(res->image) != s->current_cursor->width ||
- pixman_image_get_height(res->image) != s->current_cursor->height) {
- return;
- }
-
- pixels = s->current_cursor->width * s->current_cursor->height;
- memcpy(s->current_cursor->data,
- pixman_image_get_data(res->image),
- pixels * sizeof(uint32_t));
-}
-
-#ifdef CONFIG_VIRGL
-
-static void update_cursor_data_virgl(VirtIOGPU *g,
- struct virtio_gpu_scanout *s,
- uint32_t resource_id)
-{
- uint32_t width, height;
- uint32_t pixels, *data;
-
- data = virgl_renderer_get_cursor_data(resource_id, &width, &height);
- if (!data) {
- return;
- }
-
- if (width != s->current_cursor->width ||
- height != s->current_cursor->height) {
- return;
- }
-
- pixels = s->current_cursor->width * s->current_cursor->height;
- memcpy(s->current_cursor->data, data, pixels * sizeof(uint32_t));
- free(data);
-}
-
-#endif
-
-static void update_cursor(VirtIOGPU *g, struct virtio_gpu_update_cursor *cursor)
-{
- struct virtio_gpu_scanout *s;
- bool move = cursor->hdr.type != VIRTIO_GPU_CMD_MOVE_CURSOR;
-
- if (cursor->pos.scanout_id >= g->conf.max_outputs) {
- return;
- }
- s = &g->scanout[cursor->pos.scanout_id];
-
- trace_virtio_gpu_update_cursor(cursor->pos.scanout_id,
- cursor->pos.x,
- cursor->pos.y,
- move ? "move" : "update",
- cursor->resource_id);
-
- if (move) {
- if (!s->current_cursor) {
- s->current_cursor = cursor_alloc(64, 64);
- }
-
- s->current_cursor->hot_x = cursor->hot_x;
- s->current_cursor->hot_y = cursor->hot_y;
-
- if (cursor->resource_id > 0) {
- VIRGL(g, update_cursor_data_virgl, update_cursor_data_simple,
- g, s, cursor->resource_id);
- }
- dpy_cursor_define(s->con, s->current_cursor);
- }
- dpy_mouse_set(s->con, cursor->pos.x, cursor->pos.y,
- cursor->resource_id ? 1 : 0);
-}
-
-static void virtio_gpu_get_config(VirtIODevice *vdev, uint8_t *config)
-{
- VirtIOGPU *g = VIRTIO_GPU(vdev);
- memcpy(config, &g->virtio_config, sizeof(g->virtio_config));
-}
-
-static void virtio_gpu_set_config(VirtIODevice *vdev, const uint8_t *config)
-{
- VirtIOGPU *g = VIRTIO_GPU(vdev);
- struct virtio_gpu_config vgconfig;
-
- memcpy(&vgconfig, config, sizeof(g->virtio_config));
-
- if (vgconfig.events_clear) {
- g->virtio_config.events_read &= ~vgconfig.events_clear;
- }
-}
-
-static uint64_t virtio_gpu_get_features(VirtIODevice *vdev, uint64_t features,
- Error **errp)
-{
- VirtIOGPU *g = VIRTIO_GPU(vdev);
-
- if (virtio_gpu_virgl_enabled(g->conf)) {
- features |= (1 << VIRTIO_GPU_F_VIRGL);
- }
- return features;
-}
-
-static void virtio_gpu_set_features(VirtIODevice *vdev, uint64_t features)
-{
- static const uint32_t virgl = (1 << VIRTIO_GPU_F_VIRGL);
- VirtIOGPU *g = VIRTIO_GPU(vdev);
-
- g->use_virgl_renderer = ((features & virgl) == virgl);
- trace_virtio_gpu_features(g->use_virgl_renderer);
-}
-
-static void virtio_gpu_notify_event(VirtIOGPU *g, uint32_t event_type)
-{
- g->virtio_config.events_read |= event_type;
- virtio_notify_config(&g->parent_obj);
-}
-
-static struct virtio_gpu_simple_resource *
-virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id)
-{
- struct virtio_gpu_simple_resource *res;
-
- QTAILQ_FOREACH(res, &g->reslist, next) {
- if (res->resource_id == resource_id) {
- return res;
- }
- }
- return NULL;
-}
-
-void virtio_gpu_ctrl_response(VirtIOGPU *g,
- struct virtio_gpu_ctrl_command *cmd,
- struct virtio_gpu_ctrl_hdr *resp,
- size_t resp_len)
-{
- size_t s;
-
- if (cmd->cmd_hdr.flags & VIRTIO_GPU_FLAG_FENCE) {
- resp->flags |= VIRTIO_GPU_FLAG_FENCE;
- resp->fence_id = cmd->cmd_hdr.fence_id;
- resp->ctx_id = cmd->cmd_hdr.ctx_id;
- }
- s = iov_from_buf(cmd->elem.in_sg, cmd->elem.in_num, 0, resp, resp_len);
- if (s != resp_len) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: response size incorrect %zu vs %zu\n",
- __func__, s, resp_len);
- }
- virtqueue_push(cmd->vq, &cmd->elem, s);
- virtio_notify(VIRTIO_DEVICE(g), cmd->vq);
- cmd->finished = true;
-}
-
-void virtio_gpu_ctrl_response_nodata(VirtIOGPU *g,
- struct virtio_gpu_ctrl_command *cmd,
- enum virtio_gpu_ctrl_type type)
-{
- struct virtio_gpu_ctrl_hdr resp;
-
- memset(&resp, 0, sizeof(resp));
- resp.type = type;
- virtio_gpu_ctrl_response(g, cmd, &resp, sizeof(resp));
-}
-
-static void
-virtio_gpu_fill_display_info(VirtIOGPU *g,
- struct virtio_gpu_resp_display_info *dpy_info)
-{
- int i;
-
- for (i = 0; i < g->conf.max_outputs; i++) {
- if (g->enabled_output_bitmask & (1 << i)) {
- dpy_info->pmodes[i].enabled = 1;
- dpy_info->pmodes[i].r.width = g->req_state[i].width;
- dpy_info->pmodes[i].r.height = g->req_state[i].height;
- }
- }
-}
-
-void virtio_gpu_get_display_info(VirtIOGPU *g,
- struct virtio_gpu_ctrl_command *cmd)
-{
- struct virtio_gpu_resp_display_info display_info;
-
- trace_virtio_gpu_cmd_get_display_info();
- memset(&display_info, 0, sizeof(display_info));
- display_info.hdr.type = VIRTIO_GPU_RESP_OK_DISPLAY_INFO;
- virtio_gpu_fill_display_info(g, &display_info);
- virtio_gpu_ctrl_response(g, cmd, &display_info.hdr,
- sizeof(display_info));
-}
-
-static pixman_format_code_t get_pixman_format(uint32_t virtio_gpu_format)
-{
- switch (virtio_gpu_format) {
-#ifdef HOST_WORDS_BIGENDIAN
- case VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM:
- return PIXMAN_b8g8r8x8;
- case VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM:
- return PIXMAN_b8g8r8a8;
- case VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM:
- return PIXMAN_x8r8g8b8;
- case VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM:
- return PIXMAN_a8r8g8b8;
- case VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM:
- return PIXMAN_r8g8b8x8;
- case VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM:
- return PIXMAN_r8g8b8a8;
- case VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM:
- return PIXMAN_x8b8g8r8;
- case VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM:
- return PIXMAN_a8b8g8r8;
-#else
- case VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM:
- return PIXMAN_x8r8g8b8;
- case VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM:
- return PIXMAN_a8r8g8b8;
- case VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM:
- return PIXMAN_b8g8r8x8;
- case VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM:
- return PIXMAN_b8g8r8a8;
- case VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM:
- return PIXMAN_x8b8g8r8;
- case VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM:
- return PIXMAN_a8b8g8r8;
- case VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM:
- return PIXMAN_r8g8b8x8;
- case VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM:
- return PIXMAN_r8g8b8a8;
-#endif
- default:
- return 0;
- }
-}
-
-static void virtio_gpu_resource_create_2d(VirtIOGPU *g,
- struct virtio_gpu_ctrl_command *cmd)
-{
- pixman_format_code_t pformat;
- struct virtio_gpu_simple_resource *res;
- struct virtio_gpu_resource_create_2d c2d;
-
- VIRTIO_GPU_FILL_CMD(c2d);
- trace_virtio_gpu_cmd_res_create_2d(c2d.resource_id, c2d.format,
- c2d.width, c2d.height);
-
- if (c2d.resource_id == 0) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: resource id 0 is not allowed\n",
- __func__);
- cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
- return;
- }
-
- res = virtio_gpu_find_resource(g, c2d.resource_id);
- if (res) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: resource already exists %d\n",
- __func__, c2d.resource_id);
- cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
- return;
- }
-
- res = g_new0(struct virtio_gpu_simple_resource, 1);
-
- res->width = c2d.width;
- res->height = c2d.height;
- res->format = c2d.format;
- res->resource_id = c2d.resource_id;
-
- pformat = get_pixman_format(c2d.format);
- if (!pformat) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: host couldn't handle guest format %d\n",
- __func__, c2d.format);
- cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
- return;
- }
- res->image = pixman_image_create_bits(pformat,
- c2d.width,
- c2d.height,
- NULL, 0);
-
- if (!res->image) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: resource creation failed %d %d %d\n",
- __func__, c2d.resource_id, c2d.width, c2d.height);
- g_free(res);
- cmd->error = VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY;
- return;
- }
-
- QTAILQ_INSERT_HEAD(&g->reslist, res, next);
-}
-
-static void virtio_gpu_resource_destroy(VirtIOGPU *g,
- struct virtio_gpu_simple_resource *res)
-{
- pixman_image_unref(res->image);
- QTAILQ_REMOVE(&g->reslist, res, next);
- g_free(res);
-}
-
-static void virtio_gpu_resource_unref(VirtIOGPU *g,
- struct virtio_gpu_ctrl_command *cmd)
-{
- struct virtio_gpu_simple_resource *res;
- struct virtio_gpu_resource_unref unref;
-
- VIRTIO_GPU_FILL_CMD(unref);
- trace_virtio_gpu_cmd_res_unref(unref.resource_id);
-
- res = virtio_gpu_find_resource(g, unref.resource_id);
- if (!res) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n",
- __func__, unref.resource_id);
- cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
- return;
- }
- virtio_gpu_resource_destroy(g, res);
-}
-
-static void virtio_gpu_transfer_to_host_2d(VirtIOGPU *g,
- struct virtio_gpu_ctrl_command *cmd)
-{
- struct virtio_gpu_simple_resource *res;
- int h;
- uint32_t src_offset, dst_offset, stride;
- int bpp;
- pixman_format_code_t format;
- struct virtio_gpu_transfer_to_host_2d t2d;
-
- VIRTIO_GPU_FILL_CMD(t2d);
- trace_virtio_gpu_cmd_res_xfer_toh_2d(t2d.resource_id);
-
- res = virtio_gpu_find_resource(g, t2d.resource_id);
- if (!res || !res->iov) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n",
- __func__, t2d.resource_id);
- cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
- return;
- }
-
- if (t2d.r.x > res->width ||
- t2d.r.y > res->height ||
- t2d.r.width > res->width ||
- t2d.r.height > res->height ||
- t2d.r.x + t2d.r.width > res->width ||
- t2d.r.y + t2d.r.height > res->height) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: transfer bounds outside resource"
- " bounds for resource %d: %d %d %d %d vs %d %d\n",
- __func__, t2d.resource_id, t2d.r.x, t2d.r.y,
- t2d.r.width, t2d.r.height, res->width, res->height);
- cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
- return;
- }
-
- format = pixman_image_get_format(res->image);
- bpp = (PIXMAN_FORMAT_BPP(format) + 7) / 8;
- stride = pixman_image_get_stride(res->image);
-
- if (t2d.offset || t2d.r.x || t2d.r.y ||
- t2d.r.width != pixman_image_get_width(res->image)) {
- void *img_data = pixman_image_get_data(res->image);
- for (h = 0; h < t2d.r.height; h++) {
- src_offset = t2d.offset + stride * h;
- dst_offset = (t2d.r.y + h) * stride + (t2d.r.x * bpp);
-
- iov_to_buf(res->iov, res->iov_cnt, src_offset,
- (uint8_t *)img_data
- + dst_offset, t2d.r.width * bpp);
- }
- } else {
- iov_to_buf(res->iov, res->iov_cnt, 0,
- pixman_image_get_data(res->image),
- pixman_image_get_stride(res->image)
- * pixman_image_get_height(res->image));
- }
-}
-
-static void virtio_gpu_resource_flush(VirtIOGPU *g,
- struct virtio_gpu_ctrl_command *cmd)
-{
- struct virtio_gpu_simple_resource *res;
- struct virtio_gpu_resource_flush rf;
- pixman_region16_t flush_region;
- int i;
-
- VIRTIO_GPU_FILL_CMD(rf);
- trace_virtio_gpu_cmd_res_flush(rf.resource_id,
- rf.r.width, rf.r.height, rf.r.x, rf.r.y);
-
- res = virtio_gpu_find_resource(g, rf.resource_id);
- if (!res) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n",
- __func__, rf.resource_id);
- cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
- return;
- }
-
- if (rf.r.x > res->width ||
- rf.r.y > res->height ||
- rf.r.width > res->width ||
- rf.r.height > res->height ||
- rf.r.x + rf.r.width > res->width ||
- rf.r.y + rf.r.height > res->height) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: flush bounds outside resource"
- " bounds for resource %d: %d %d %d %d vs %d %d\n",
- __func__, rf.resource_id, rf.r.x, rf.r.y,
- rf.r.width, rf.r.height, res->width, res->height);
- cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
- return;
- }
-
- pixman_region_init_rect(&flush_region,
- rf.r.x, rf.r.y, rf.r.width, rf.r.height);
- for (i = 0; i < VIRTIO_GPU_MAX_SCANOUT; i++) {
- struct virtio_gpu_scanout *scanout;
- pixman_region16_t region, finalregion;
- pixman_box16_t *extents;
-
- if (!(res->scanout_bitmask & (1 << i))) {
- continue;
- }
- scanout = &g->scanout[i];
-
- pixman_region_init(&finalregion);
- pixman_region_init_rect(&region, scanout->x, scanout->y,
- scanout->width, scanout->height);
-
- pixman_region_intersect(&finalregion, &flush_region, &region);
- pixman_region_translate(&finalregion, -scanout->x, -scanout->y);
- extents = pixman_region_extents(&finalregion);
- /* work out the area we need to update for each console */
- dpy_gfx_update(g->scanout[i].con,
- extents->x1, extents->y1,
- extents->x2 - extents->x1,
- extents->y2 - extents->y1);
-
- pixman_region_fini(&region);
- pixman_region_fini(&finalregion);
- }
- pixman_region_fini(&flush_region);
-}
-
-static void virtio_gpu_set_scanout(VirtIOGPU *g,
- struct virtio_gpu_ctrl_command *cmd)
-{
- struct virtio_gpu_simple_resource *res;
- struct virtio_gpu_scanout *scanout;
- pixman_format_code_t format;
- uint32_t offset;
- int bpp;
- struct virtio_gpu_set_scanout ss;
-
- VIRTIO_GPU_FILL_CMD(ss);
- trace_virtio_gpu_cmd_set_scanout(ss.scanout_id, ss.resource_id,
- ss.r.width, ss.r.height, ss.r.x, ss.r.y);
-
- g->enable = 1;
- if (ss.resource_id == 0) {
- scanout = &g->scanout[ss.scanout_id];
- if (scanout->resource_id) {
- res = virtio_gpu_find_resource(g, scanout->resource_id);
- if (res) {
- res->scanout_bitmask &= ~(1 << ss.scanout_id);
- }
- }
- if (ss.scanout_id == 0 ||
- ss.scanout_id >= g->conf.max_outputs) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: illegal scanout id specified %d",
- __func__, ss.scanout_id);
- cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID;
- return;
- }
- dpy_gfx_replace_surface(g->scanout[ss.scanout_id].con, NULL);
- scanout->ds = NULL;
- scanout->width = 0;
- scanout->height = 0;
- return;
- }
-
- /* create a surface for this scanout */
- if (ss.scanout_id >= VIRTIO_GPU_MAX_SCANOUT ||
- ss.scanout_id >= g->conf.max_outputs) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout id specified %d",
- __func__, ss.scanout_id);
- cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID;
- return;
- }
-
- res = virtio_gpu_find_resource(g, ss.resource_id);
- if (!res) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n",
- __func__, ss.resource_id);
- cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
- return;
- }
-
- if (ss.r.x > res->width ||
- ss.r.y > res->height ||
- ss.r.width > res->width ||
- ss.r.height > res->height ||
- ss.r.x + ss.r.width > res->width ||
- ss.r.y + ss.r.height > res->height) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout %d bounds for"
- " resource %d, (%d,%d)+%d,%d vs %d %d\n",
- __func__, ss.scanout_id, ss.resource_id, ss.r.x, ss.r.y,
- ss.r.width, ss.r.height, res->width, res->height);
- cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
- return;
- }
-
- scanout = &g->scanout[ss.scanout_id];
-
- format = pixman_image_get_format(res->image);
- bpp = (PIXMAN_FORMAT_BPP(format) + 7) / 8;
- offset = (ss.r.x * bpp) + ss.r.y * pixman_image_get_stride(res->image);
- if (!scanout->ds || surface_data(scanout->ds)
- != ((uint8_t *)pixman_image_get_data(res->image) + offset) ||
- scanout->width != ss.r.width ||
- scanout->height != ss.r.height) {
- /* realloc the surface ptr */
- scanout->ds = qemu_create_displaysurface_pixman(res->image);
- if (!scanout->ds) {
- cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
- return;
- }
- dpy_gfx_replace_surface(g->scanout[ss.scanout_id].con, scanout->ds);
- }
-
- res->scanout_bitmask |= (1 << ss.scanout_id);
- scanout->resource_id = ss.resource_id;
- scanout->x = ss.r.x;
- scanout->y = ss.r.y;
- scanout->width = ss.r.width;
- scanout->height = ss.r.height;
-}
-
-int virtio_gpu_create_mapping_iov(struct virtio_gpu_resource_attach_backing *ab,
- struct virtio_gpu_ctrl_command *cmd,
- struct iovec **iov)
-{
- struct virtio_gpu_mem_entry *ents;
- size_t esize, s;
- int i;
-
- if (ab->nr_entries > 16384) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: nr_entries is too big (%d > 16384)\n",
- __func__, ab->nr_entries);
- return -1;
- }
-
- esize = sizeof(*ents) * ab->nr_entries;
- ents = g_malloc(esize);
- s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num,
- sizeof(*ab), ents, esize);
- if (s != esize) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: command data size incorrect %zu vs %zu\n",
- __func__, s, esize);
- g_free(ents);
- return -1;
- }
-
- *iov = g_malloc0(sizeof(struct iovec) * ab->nr_entries);
- for (i = 0; i < ab->nr_entries; i++) {
- hwaddr len = ents[i].length;
- (*iov)[i].iov_len = ents[i].length;
- (*iov)[i].iov_base = cpu_physical_memory_map(ents[i].addr, &len, 1);
- if (!(*iov)[i].iov_base || len != ents[i].length) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to map MMIO memory for"
- " resource %d element %d\n",
- __func__, ab->resource_id, i);
- virtio_gpu_cleanup_mapping_iov(*iov, i);
- g_free(ents);
- *iov = NULL;
- return -1;
- }
- }
- g_free(ents);
- return 0;
-}
-
-void virtio_gpu_cleanup_mapping_iov(struct iovec *iov, uint32_t count)
-{
- int i;
-
- for (i = 0; i < count; i++) {
- cpu_physical_memory_unmap(iov[i].iov_base, iov[i].iov_len, 1,
- iov[i].iov_len);
- }
- g_free(iov);
-}
-
-static void virtio_gpu_cleanup_mapping(struct virtio_gpu_simple_resource *res)
-{
- virtio_gpu_cleanup_mapping_iov(res->iov, res->iov_cnt);
- res->iov = NULL;
- res->iov_cnt = 0;
-}
-
-static void
-virtio_gpu_resource_attach_backing(VirtIOGPU *g,
- struct virtio_gpu_ctrl_command *cmd)
-{
- struct virtio_gpu_simple_resource *res;
- struct virtio_gpu_resource_attach_backing ab;
- int ret;
-
- VIRTIO_GPU_FILL_CMD(ab);
- trace_virtio_gpu_cmd_res_back_attach(ab.resource_id);
-
- res = virtio_gpu_find_resource(g, ab.resource_id);
- if (!res) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n",
- __func__, ab.resource_id);
- cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
- return;
- }
-
- ret = virtio_gpu_create_mapping_iov(&ab, cmd, &res->iov);
- if (ret != 0) {
- cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
- return;
- }
-
- res->iov_cnt = ab.nr_entries;
-}
-
-static void
-virtio_gpu_resource_detach_backing(VirtIOGPU *g,
- struct virtio_gpu_ctrl_command *cmd)
-{
- struct virtio_gpu_simple_resource *res;
- struct virtio_gpu_resource_detach_backing detach;
-
- VIRTIO_GPU_FILL_CMD(detach);
- trace_virtio_gpu_cmd_res_back_detach(detach.resource_id);
-
- res = virtio_gpu_find_resource(g, detach.resource_id);
- if (!res || !res->iov) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n",
- __func__, detach.resource_id);
- cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
- return;
- }
- virtio_gpu_cleanup_mapping(res);
-}
-
-static void virtio_gpu_simple_process_cmd(VirtIOGPU *g,
- struct virtio_gpu_ctrl_command *cmd)
-{
- VIRTIO_GPU_FILL_CMD(cmd->cmd_hdr);
-
- switch (cmd->cmd_hdr.type) {
- case VIRTIO_GPU_CMD_GET_DISPLAY_INFO:
- virtio_gpu_get_display_info(g, cmd);
- break;
- case VIRTIO_GPU_CMD_RESOURCE_CREATE_2D:
- virtio_gpu_resource_create_2d(g, cmd);
- break;
- case VIRTIO_GPU_CMD_RESOURCE_UNREF:
- virtio_gpu_resource_unref(g, cmd);
- break;
- case VIRTIO_GPU_CMD_RESOURCE_FLUSH:
- virtio_gpu_resource_flush(g, cmd);
- break;
- case VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D:
- virtio_gpu_transfer_to_host_2d(g, cmd);
- break;
- case VIRTIO_GPU_CMD_SET_SCANOUT:
- virtio_gpu_set_scanout(g, cmd);
- break;
- case VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING:
- virtio_gpu_resource_attach_backing(g, cmd);
- break;
- case VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING:
- virtio_gpu_resource_detach_backing(g, cmd);
- break;
- default:
- cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
- break;
- }
- if (!cmd->finished) {
- virtio_gpu_ctrl_response_nodata(g, cmd, cmd->error ? cmd->error :
- VIRTIO_GPU_RESP_OK_NODATA);
- }
-}
-
-static void virtio_gpu_handle_ctrl_cb(VirtIODevice *vdev, VirtQueue *vq)
-{
- VirtIOGPU *g = VIRTIO_GPU(vdev);
- qemu_bh_schedule(g->ctrl_bh);
-}
-
-static void virtio_gpu_handle_cursor_cb(VirtIODevice *vdev, VirtQueue *vq)
-{
- VirtIOGPU *g = VIRTIO_GPU(vdev);
- qemu_bh_schedule(g->cursor_bh);
-}
-
-void virtio_gpu_process_cmdq(VirtIOGPU *g)
-{
- struct virtio_gpu_ctrl_command *cmd;
-
- while (!QTAILQ_EMPTY(&g->cmdq)) {
- cmd = QTAILQ_FIRST(&g->cmdq);
-
- /* process command */
- VIRGL(g, virtio_gpu_virgl_process_cmd, virtio_gpu_simple_process_cmd,
- g, cmd);
- if (cmd->waiting) {
- break;
- }
- QTAILQ_REMOVE(&g->cmdq, cmd, next);
- if (virtio_gpu_stats_enabled(g->conf)) {
- g->stats.requests++;
- }
-
- if (!cmd->finished) {
- QTAILQ_INSERT_TAIL(&g->fenceq, cmd, next);
- g->inflight++;
- if (virtio_gpu_stats_enabled(g->conf)) {
- if (g->stats.max_inflight < g->inflight) {
- g->stats.max_inflight = g->inflight;
- }
- fprintf(stderr, "inflight: %3d (+)\r", g->inflight);
- }
- } else {
- g_free(cmd);
- }
- }
-}
-
-static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
-{
- VirtIOGPU *g = VIRTIO_GPU(vdev);
- struct virtio_gpu_ctrl_command *cmd;
-
- if (!virtio_queue_ready(vq)) {
- return;
- }
-
-#ifdef CONFIG_VIRGL
- if (!g->renderer_inited && g->use_virgl_renderer) {
- virtio_gpu_virgl_init(g);
- g->renderer_inited = true;
- }
-#endif
-
- cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command));
- while (cmd) {
- cmd->vq = vq;
- cmd->error = 0;
- cmd->finished = false;
- cmd->waiting = false;
- QTAILQ_INSERT_TAIL(&g->cmdq, cmd, next);
- cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command));
- }
-
- virtio_gpu_process_cmdq(g);
-
-#ifdef CONFIG_VIRGL
- if (g->use_virgl_renderer) {
- virtio_gpu_virgl_fence_poll(g);
- }
-#endif
-}
-
-static void virtio_gpu_ctrl_bh(void *opaque)
-{
- VirtIOGPU *g = opaque;
- virtio_gpu_handle_ctrl(&g->parent_obj, g->ctrl_vq);
-}
-
-static void virtio_gpu_handle_cursor(VirtIODevice *vdev, VirtQueue *vq)
-{
- VirtIOGPU *g = VIRTIO_GPU(vdev);
- VirtQueueElement *elem;
- size_t s;
- struct virtio_gpu_update_cursor cursor_info;
-
- if (!virtio_queue_ready(vq)) {
- return;
- }
- for (;;) {
- elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
- if (!elem) {
- break;
- }
-
- s = iov_to_buf(elem->out_sg, elem->out_num, 0,
- &cursor_info, sizeof(cursor_info));
- if (s != sizeof(cursor_info)) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: cursor size incorrect %zu vs %zu\n",
- __func__, s, sizeof(cursor_info));
- } else {
- update_cursor(g, &cursor_info);
- }
- virtqueue_push(vq, elem, 0);
- virtio_notify(vdev, vq);
- g_free(elem);
- }
-}
-
-static void virtio_gpu_cursor_bh(void *opaque)
-{
- VirtIOGPU *g = opaque;
- virtio_gpu_handle_cursor(&g->parent_obj, g->cursor_vq);
-}
-
-static void virtio_gpu_invalidate_display(void *opaque)
-{
-}
-
-static void virtio_gpu_update_display(void *opaque)
-{
-}
-
-static void virtio_gpu_text_update(void *opaque, console_ch_t *chardata)
-{
-}
-
-static int virtio_gpu_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info)
-{
- VirtIOGPU *g = opaque;
-
- if (idx > g->conf.max_outputs) {
- return -1;
- }
-
- g->req_state[idx].x = info->xoff;
- g->req_state[idx].y = info->yoff;
- g->req_state[idx].width = info->width;
- g->req_state[idx].height = info->height;
-
- if (info->width && info->height) {
- g->enabled_output_bitmask |= (1 << idx);
- } else {
- g->enabled_output_bitmask &= ~(1 << idx);
- }
-
- /* send event to guest */
- virtio_gpu_notify_event(g, VIRTIO_GPU_EVENT_DISPLAY);
- return 0;
-}
-
-static void virtio_gpu_gl_block(void *opaque, bool block)
-{
- VirtIOGPU *g = opaque;
-
- g->renderer_blocked = block;
- if (!block) {
- virtio_gpu_process_cmdq(g);
- }
-}
-
-const GraphicHwOps virtio_gpu_ops = {
- .invalidate = virtio_gpu_invalidate_display,
- .gfx_update = virtio_gpu_update_display,
- .text_update = virtio_gpu_text_update,
- .ui_info = virtio_gpu_ui_info,
- .gl_block = virtio_gpu_gl_block,
-};
-
-static const VMStateDescription vmstate_virtio_gpu_unmigratable = {
- .name = "virtio-gpu",
- .unmigratable = 1,
-};
-
-static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
- VirtIOGPU *g = VIRTIO_GPU(qdev);
- bool have_virgl;
- int i;
-
- g->config_size = sizeof(struct virtio_gpu_config);
- g->virtio_config.num_scanouts = g->conf.max_outputs;
- virtio_init(VIRTIO_DEVICE(g), "virtio-gpu", VIRTIO_ID_GPU,
- g->config_size);
-
- g->req_state[0].width = 1024;
- g->req_state[0].height = 768;
-
- g->use_virgl_renderer = false;
-#if !defined(CONFIG_VIRGL) || defined(HOST_WORDS_BIGENDIAN)
- have_virgl = false;
-#else
- have_virgl = display_opengl;
-#endif
- if (!have_virgl) {
- g->conf.flags &= ~(1 << VIRTIO_GPU_FLAG_VIRGL_ENABLED);
- }
-
- if (virtio_gpu_virgl_enabled(g->conf)) {
- /* use larger control queue in 3d mode */
- g->ctrl_vq = virtio_add_queue(vdev, 256, virtio_gpu_handle_ctrl_cb);
- g->cursor_vq = virtio_add_queue(vdev, 16, virtio_gpu_handle_cursor_cb);
- g->virtio_config.num_capsets = 1;
- } else {
- g->ctrl_vq = virtio_add_queue(vdev, 64, virtio_gpu_handle_ctrl_cb);
- g->cursor_vq = virtio_add_queue(vdev, 16, virtio_gpu_handle_cursor_cb);
- }
-
- g->ctrl_bh = qemu_bh_new(virtio_gpu_ctrl_bh, g);
- g->cursor_bh = qemu_bh_new(virtio_gpu_cursor_bh, g);
- QTAILQ_INIT(&g->reslist);
- QTAILQ_INIT(&g->cmdq);
- QTAILQ_INIT(&g->fenceq);
-
- g->enabled_output_bitmask = 1;
- g->qdev = qdev;
-
- for (i = 0; i < g->conf.max_outputs; i++) {
- g->scanout[i].con =
- graphic_console_init(DEVICE(g), i, &virtio_gpu_ops, g);
- if (i > 0) {
- dpy_gfx_replace_surface(g->scanout[i].con, NULL);
- }
- }
-
- vmstate_register(qdev, -1, &vmstate_virtio_gpu_unmigratable, g);
-}
-
-static void virtio_gpu_instance_init(Object *obj)
-{
-}
-
-static void virtio_gpu_reset(VirtIODevice *vdev)
-{
- VirtIOGPU *g = VIRTIO_GPU(vdev);
- struct virtio_gpu_simple_resource *res, *tmp;
- int i;
-
- g->enable = 0;
-
- QTAILQ_FOREACH_SAFE(res, &g->reslist, next, tmp) {
- virtio_gpu_resource_destroy(g, res);
- }
- for (i = 0; i < g->conf.max_outputs; i++) {
-#if 0
- g->req_state[i].x = 0;
- g->req_state[i].y = 0;
- if (i == 0) {
- g->req_state[0].width = 1024;
- g->req_state[0].height = 768;
- } else {
- g->req_state[i].width = 0;
- g->req_state[i].height = 0;
- }
-#endif
- g->scanout[i].resource_id = 0;
- g->scanout[i].width = 0;
- g->scanout[i].height = 0;
- g->scanout[i].x = 0;
- g->scanout[i].y = 0;
- g->scanout[i].ds = NULL;
- }
- g->enabled_output_bitmask = 1;
-
-#ifdef CONFIG_VIRGL
- if (g->use_virgl_renderer) {
- virtio_gpu_virgl_reset(g);
- g->use_virgl_renderer = 0;
- }
-#endif
-}
-
-static Property virtio_gpu_properties[] = {
- DEFINE_PROP_UINT32("max_outputs", VirtIOGPU, conf.max_outputs, 1),
-#ifdef CONFIG_VIRGL
- DEFINE_PROP_BIT("virgl", VirtIOGPU, conf.flags,
- VIRTIO_GPU_FLAG_VIRGL_ENABLED, true),
- DEFINE_PROP_BIT("stats", VirtIOGPU, conf.flags,
- VIRTIO_GPU_FLAG_STATS_ENABLED, false),
-#endif
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_gpu_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
-
- vdc->realize = virtio_gpu_device_realize;
- vdc->get_config = virtio_gpu_get_config;
- vdc->set_config = virtio_gpu_set_config;
- vdc->get_features = virtio_gpu_get_features;
- vdc->set_features = virtio_gpu_set_features;
-
- vdc->reset = virtio_gpu_reset;
-
- dc->props = virtio_gpu_properties;
-}
-
-static const TypeInfo virtio_gpu_info = {
- .name = TYPE_VIRTIO_GPU,
- .parent = TYPE_VIRTIO_DEVICE,
- .instance_size = sizeof(VirtIOGPU),
- .instance_init = virtio_gpu_instance_init,
- .class_init = virtio_gpu_class_init,
-};
-
-static void virtio_register_types(void)
-{
- type_register_static(&virtio_gpu_info);
-}
-
-type_init(virtio_register_types)
-
-QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctrl_hdr) != 24);
-QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_update_cursor) != 56);
-QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_unref) != 32);
-QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_create_2d) != 40);
-QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_set_scanout) != 48);
-QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_flush) != 48);
-QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_transfer_to_host_2d) != 56);
-QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_mem_entry) != 16);
-QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_attach_backing) != 32);
-QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_detach_backing) != 32);
-QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_display_info) != 408);
-
-QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_transfer_host_3d) != 72);
-QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_create_3d) != 72);
-QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_create) != 96);
-QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_destroy) != 24);
-QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_resource) != 32);
-QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_cmd_submit) != 32);
-QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_get_capset_info) != 32);
-QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_capset_info) != 40);
-QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_get_capset) != 32);
-QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_capset) != 24);
diff --git a/qemu/hw/display/virtio-vga.c b/qemu/hw/display/virtio-vga.c
deleted file mode 100644
index e58b165ae..000000000
--- a/qemu/hw/display/virtio-vga.c
+++ /dev/null
@@ -1,193 +0,0 @@
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/pci/pci.h"
-#include "ui/console.h"
-#include "vga_int.h"
-#include "hw/virtio/virtio-pci.h"
-
-/*
- * virtio-vga: This extends VirtioPCIProxy.
- */
-#define TYPE_VIRTIO_VGA "virtio-vga"
-#define VIRTIO_VGA(obj) \
- OBJECT_CHECK(VirtIOVGA, (obj), TYPE_VIRTIO_VGA)
-
-typedef struct VirtIOVGA {
- VirtIOPCIProxy parent_obj;
- VirtIOGPU vdev;
- VGACommonState vga;
- MemoryRegion vga_mrs[3];
-} VirtIOVGA;
-
-static void virtio_vga_invalidate_display(void *opaque)
-{
- VirtIOVGA *vvga = opaque;
-
- if (vvga->vdev.enable) {
- virtio_gpu_ops.invalidate(&vvga->vdev);
- } else {
- vvga->vga.hw_ops->invalidate(&vvga->vga);
- }
-}
-
-static void virtio_vga_update_display(void *opaque)
-{
- VirtIOVGA *vvga = opaque;
-
- if (vvga->vdev.enable) {
- virtio_gpu_ops.gfx_update(&vvga->vdev);
- } else {
- vvga->vga.hw_ops->gfx_update(&vvga->vga);
- }
-}
-
-static void virtio_vga_text_update(void *opaque, console_ch_t *chardata)
-{
- VirtIOVGA *vvga = opaque;
-
- if (vvga->vdev.enable) {
- if (virtio_gpu_ops.text_update) {
- virtio_gpu_ops.text_update(&vvga->vdev, chardata);
- }
- } else {
- if (vvga->vga.hw_ops->text_update) {
- vvga->vga.hw_ops->text_update(&vvga->vga, chardata);
- }
- }
-}
-
-static int virtio_vga_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info)
-{
- VirtIOVGA *vvga = opaque;
-
- if (virtio_gpu_ops.ui_info) {
- return virtio_gpu_ops.ui_info(&vvga->vdev, idx, info);
- }
- return -1;
-}
-
-static void virtio_vga_gl_block(void *opaque, bool block)
-{
- VirtIOVGA *vvga = opaque;
-
- if (virtio_gpu_ops.gl_block) {
- virtio_gpu_ops.gl_block(&vvga->vdev, block);
- }
-}
-
-static const GraphicHwOps virtio_vga_ops = {
- .invalidate = virtio_vga_invalidate_display,
- .gfx_update = virtio_vga_update_display,
- .text_update = virtio_vga_text_update,
- .ui_info = virtio_vga_ui_info,
- .gl_block = virtio_vga_gl_block,
-};
-
-/* VGA device wrapper around PCI device around virtio GPU */
-static void virtio_vga_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
-{
- VirtIOVGA *vvga = VIRTIO_VGA(vpci_dev);
- VirtIOGPU *g = &vvga->vdev;
- VGACommonState *vga = &vvga->vga;
- uint32_t offset;
- int i;
-
- /* init vga compat bits */
- vga->vram_size_mb = 8;
- vga_common_init(vga, OBJECT(vpci_dev), false);
- vga_init(vga, OBJECT(vpci_dev), pci_address_space(&vpci_dev->pci_dev),
- pci_address_space_io(&vpci_dev->pci_dev), true);
- pci_register_bar(&vpci_dev->pci_dev, 0,
- PCI_BASE_ADDRESS_MEM_PREFETCH, &vga->vram);
-
- /*
- * Configure virtio bar and regions
- *
- * We use bar #2 for the mmio regions, to be compatible with stdvga.
- * virtio regions are moved to the end of bar #2, to make room for
- * the stdvga mmio registers at the start of bar #2.
- */
- vpci_dev->modern_mem_bar = 2;
- vpci_dev->msix_bar = 4;
- offset = memory_region_size(&vpci_dev->modern_bar);
- offset -= vpci_dev->notify.size;
- vpci_dev->notify.offset = offset;
- offset -= vpci_dev->device.size;
- vpci_dev->device.offset = offset;
- offset -= vpci_dev->isr.size;
- vpci_dev->isr.offset = offset;
- offset -= vpci_dev->common.size;
- vpci_dev->common.offset = offset;
-
- /* init virtio bits */
- qdev_set_parent_bus(DEVICE(g), BUS(&vpci_dev->bus));
- /* force virtio-1.0 */
- vpci_dev->flags &= ~VIRTIO_PCI_FLAG_DISABLE_MODERN;
- vpci_dev->flags |= VIRTIO_PCI_FLAG_DISABLE_LEGACY;
- object_property_set_bool(OBJECT(g), true, "realized", errp);
-
- /* add stdvga mmio regions */
- pci_std_vga_mmio_region_init(vga, &vpci_dev->modern_bar,
- vvga->vga_mrs, true);
-
- vga->con = g->scanout[0].con;
- graphic_console_set_hwops(vga->con, &virtio_vga_ops, vvga);
-
- for (i = 0; i < g->conf.max_outputs; i++) {
- object_property_set_link(OBJECT(g->scanout[i].con),
- OBJECT(vpci_dev),
- "device", errp);
- }
-}
-
-static void virtio_vga_reset(DeviceState *dev)
-{
- VirtIOVGA *vvga = VIRTIO_VGA(dev);
- vvga->vdev.enable = 0;
-
- vga_dirty_log_start(&vvga->vga);
-}
-
-static Property virtio_vga_properties[] = {
- DEFINE_VIRTIO_GPU_PCI_PROPERTIES(VirtIOPCIProxy),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_vga_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
- PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
-
- set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
- dc->props = virtio_vga_properties;
- dc->reset = virtio_vga_reset;
- dc->hotpluggable = false;
-
- k->realize = virtio_vga_realize;
- pcidev_k->romfile = "vgabios-virtio.bin";
- pcidev_k->class_id = PCI_CLASS_DISPLAY_VGA;
-}
-
-static void virtio_vga_inst_initfn(Object *obj)
-{
- VirtIOVGA *dev = VIRTIO_VGA(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VIRTIO_GPU);
-}
-
-static TypeInfo virtio_vga_info = {
- .name = TYPE_VIRTIO_VGA,
- .parent = TYPE_VIRTIO_PCI,
- .instance_size = sizeof(struct VirtIOVGA),
- .instance_init = virtio_vga_inst_initfn,
- .class_init = virtio_vga_class_init,
-};
-
-static void virtio_vga_register_types(void)
-{
- type_register_static(&virtio_vga_info);
-}
-
-type_init(virtio_vga_register_types)
diff --git a/qemu/hw/display/vmware_vga.c b/qemu/hw/display/vmware_vga.c
deleted file mode 100644
index 0c63fa851..000000000
--- a/qemu/hw/display/vmware_vga.c
+++ /dev/null
@@ -1,1370 +0,0 @@
-/*
- * QEMU VMware-SVGA "chipset".
- *
- * Copyright (c) 2007 Andrzej Zaborowski <balrog@zabor.org>
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/hw.h"
-#include "hw/loader.h"
-#include "trace.h"
-#include "ui/console.h"
-#include "ui/vnc.h"
-#include "hw/pci/pci.h"
-
-#undef VERBOSE
-#define HW_RECT_ACCEL
-#define HW_FILL_ACCEL
-#define HW_MOUSE_ACCEL
-
-#include "vga_int.h"
-
-/* See http://vmware-svga.sf.net/ for some documentation on VMWare SVGA */
-
-struct vmsvga_state_s {
- VGACommonState vga;
-
- int invalidated;
- int enable;
- int config;
- struct {
- int id;
- int x;
- int y;
- int on;
- } cursor;
-
- int index;
- int scratch_size;
- uint32_t *scratch;
- int new_width;
- int new_height;
- int new_depth;
- uint32_t guest;
- uint32_t svgaid;
- int syncing;
-
- MemoryRegion fifo_ram;
- uint8_t *fifo_ptr;
- unsigned int fifo_size;
-
- union {
- uint32_t *fifo;
- struct QEMU_PACKED {
- uint32_t min;
- uint32_t max;
- uint32_t next_cmd;
- uint32_t stop;
- /* Add registers here when adding capabilities. */
- uint32_t fifo[0];
- } *cmd;
- };
-
-#define REDRAW_FIFO_LEN 512
- struct vmsvga_rect_s {
- int x, y, w, h;
- } redraw_fifo[REDRAW_FIFO_LEN];
- int redraw_fifo_first, redraw_fifo_last;
-};
-
-#define TYPE_VMWARE_SVGA "vmware-svga"
-
-#define VMWARE_SVGA(obj) \
- OBJECT_CHECK(struct pci_vmsvga_state_s, (obj), TYPE_VMWARE_SVGA)
-
-struct pci_vmsvga_state_s {
- /*< private >*/
- PCIDevice parent_obj;
- /*< public >*/
-
- struct vmsvga_state_s chip;
- MemoryRegion io_bar;
-};
-
-#define SVGA_MAGIC 0x900000UL
-#define SVGA_MAKE_ID(ver) (SVGA_MAGIC << 8 | (ver))
-#define SVGA_ID_0 SVGA_MAKE_ID(0)
-#define SVGA_ID_1 SVGA_MAKE_ID(1)
-#define SVGA_ID_2 SVGA_MAKE_ID(2)
-
-#define SVGA_LEGACY_BASE_PORT 0x4560
-#define SVGA_INDEX_PORT 0x0
-#define SVGA_VALUE_PORT 0x1
-#define SVGA_BIOS_PORT 0x2
-
-#define SVGA_VERSION_2
-
-#ifdef SVGA_VERSION_2
-# define SVGA_ID SVGA_ID_2
-# define SVGA_IO_BASE SVGA_LEGACY_BASE_PORT
-# define SVGA_IO_MUL 1
-# define SVGA_FIFO_SIZE 0x10000
-# define SVGA_PCI_DEVICE_ID PCI_DEVICE_ID_VMWARE_SVGA2
-#else
-# define SVGA_ID SVGA_ID_1
-# define SVGA_IO_BASE SVGA_LEGACY_BASE_PORT
-# define SVGA_IO_MUL 4
-# define SVGA_FIFO_SIZE 0x10000
-# define SVGA_PCI_DEVICE_ID PCI_DEVICE_ID_VMWARE_SVGA
-#endif
-
-enum {
- /* ID 0, 1 and 2 registers */
- SVGA_REG_ID = 0,
- SVGA_REG_ENABLE = 1,
- SVGA_REG_WIDTH = 2,
- SVGA_REG_HEIGHT = 3,
- SVGA_REG_MAX_WIDTH = 4,
- SVGA_REG_MAX_HEIGHT = 5,
- SVGA_REG_DEPTH = 6,
- SVGA_REG_BITS_PER_PIXEL = 7, /* Current bpp in the guest */
- SVGA_REG_PSEUDOCOLOR = 8,
- SVGA_REG_RED_MASK = 9,
- SVGA_REG_GREEN_MASK = 10,
- SVGA_REG_BLUE_MASK = 11,
- SVGA_REG_BYTES_PER_LINE = 12,
- SVGA_REG_FB_START = 13,
- SVGA_REG_FB_OFFSET = 14,
- SVGA_REG_VRAM_SIZE = 15,
- SVGA_REG_FB_SIZE = 16,
-
- /* ID 1 and 2 registers */
- SVGA_REG_CAPABILITIES = 17,
- SVGA_REG_MEM_START = 18, /* Memory for command FIFO */
- SVGA_REG_MEM_SIZE = 19,
- SVGA_REG_CONFIG_DONE = 20, /* Set when memory area configured */
- SVGA_REG_SYNC = 21, /* Write to force synchronization */
- SVGA_REG_BUSY = 22, /* Read to check if sync is done */
- SVGA_REG_GUEST_ID = 23, /* Set guest OS identifier */
- SVGA_REG_CURSOR_ID = 24, /* ID of cursor */
- SVGA_REG_CURSOR_X = 25, /* Set cursor X position */
- SVGA_REG_CURSOR_Y = 26, /* Set cursor Y position */
- SVGA_REG_CURSOR_ON = 27, /* Turn cursor on/off */
- SVGA_REG_HOST_BITS_PER_PIXEL = 28, /* Current bpp in the host */
- SVGA_REG_SCRATCH_SIZE = 29, /* Number of scratch registers */
- SVGA_REG_MEM_REGS = 30, /* Number of FIFO registers */
- SVGA_REG_NUM_DISPLAYS = 31, /* Number of guest displays */
- SVGA_REG_PITCHLOCK = 32, /* Fixed pitch for all modes */
-
- SVGA_PALETTE_BASE = 1024, /* Base of SVGA color map */
- SVGA_PALETTE_END = SVGA_PALETTE_BASE + 767,
- SVGA_SCRATCH_BASE = SVGA_PALETTE_BASE + 768,
-};
-
-#define SVGA_CAP_NONE 0
-#define SVGA_CAP_RECT_FILL (1 << 0)
-#define SVGA_CAP_RECT_COPY (1 << 1)
-#define SVGA_CAP_RECT_PAT_FILL (1 << 2)
-#define SVGA_CAP_LEGACY_OFFSCREEN (1 << 3)
-#define SVGA_CAP_RASTER_OP (1 << 4)
-#define SVGA_CAP_CURSOR (1 << 5)
-#define SVGA_CAP_CURSOR_BYPASS (1 << 6)
-#define SVGA_CAP_CURSOR_BYPASS_2 (1 << 7)
-#define SVGA_CAP_8BIT_EMULATION (1 << 8)
-#define SVGA_CAP_ALPHA_CURSOR (1 << 9)
-#define SVGA_CAP_GLYPH (1 << 10)
-#define SVGA_CAP_GLYPH_CLIPPING (1 << 11)
-#define SVGA_CAP_OFFSCREEN_1 (1 << 12)
-#define SVGA_CAP_ALPHA_BLEND (1 << 13)
-#define SVGA_CAP_3D (1 << 14)
-#define SVGA_CAP_EXTENDED_FIFO (1 << 15)
-#define SVGA_CAP_MULTIMON (1 << 16)
-#define SVGA_CAP_PITCHLOCK (1 << 17)
-
-/*
- * FIFO offsets (seen as an array of 32-bit words)
- */
-enum {
- /*
- * The original defined FIFO offsets
- */
- SVGA_FIFO_MIN = 0,
- SVGA_FIFO_MAX, /* The distance from MIN to MAX must be at least 10K */
- SVGA_FIFO_NEXT_CMD,
- SVGA_FIFO_STOP,
-
- /*
- * Additional offsets added as of SVGA_CAP_EXTENDED_FIFO
- */
- SVGA_FIFO_CAPABILITIES = 4,
- SVGA_FIFO_FLAGS,
- SVGA_FIFO_FENCE,
- SVGA_FIFO_3D_HWVERSION,
- SVGA_FIFO_PITCHLOCK,
-};
-
-#define SVGA_FIFO_CAP_NONE 0
-#define SVGA_FIFO_CAP_FENCE (1 << 0)
-#define SVGA_FIFO_CAP_ACCELFRONT (1 << 1)
-#define SVGA_FIFO_CAP_PITCHLOCK (1 << 2)
-
-#define SVGA_FIFO_FLAG_NONE 0
-#define SVGA_FIFO_FLAG_ACCELFRONT (1 << 0)
-
-/* These values can probably be changed arbitrarily. */
-#define SVGA_SCRATCH_SIZE 0x8000
-#define SVGA_MAX_WIDTH ROUND_UP(2360, VNC_DIRTY_PIXELS_PER_BIT)
-#define SVGA_MAX_HEIGHT 1770
-
-#ifdef VERBOSE
-# define GUEST_OS_BASE 0x5001
-static const char *vmsvga_guest_id[] = {
- [0x00] = "Dos",
- [0x01] = "Windows 3.1",
- [0x02] = "Windows 95",
- [0x03] = "Windows 98",
- [0x04] = "Windows ME",
- [0x05] = "Windows NT",
- [0x06] = "Windows 2000",
- [0x07] = "Linux",
- [0x08] = "OS/2",
- [0x09] = "an unknown OS",
- [0x0a] = "BSD",
- [0x0b] = "Whistler",
- [0x0c] = "an unknown OS",
- [0x0d] = "an unknown OS",
- [0x0e] = "an unknown OS",
- [0x0f] = "an unknown OS",
- [0x10] = "an unknown OS",
- [0x11] = "an unknown OS",
- [0x12] = "an unknown OS",
- [0x13] = "an unknown OS",
- [0x14] = "an unknown OS",
- [0x15] = "Windows 2003",
-};
-#endif
-
-enum {
- SVGA_CMD_INVALID_CMD = 0,
- SVGA_CMD_UPDATE = 1,
- SVGA_CMD_RECT_FILL = 2,
- SVGA_CMD_RECT_COPY = 3,
- SVGA_CMD_DEFINE_BITMAP = 4,
- SVGA_CMD_DEFINE_BITMAP_SCANLINE = 5,
- SVGA_CMD_DEFINE_PIXMAP = 6,
- SVGA_CMD_DEFINE_PIXMAP_SCANLINE = 7,
- SVGA_CMD_RECT_BITMAP_FILL = 8,
- SVGA_CMD_RECT_PIXMAP_FILL = 9,
- SVGA_CMD_RECT_BITMAP_COPY = 10,
- SVGA_CMD_RECT_PIXMAP_COPY = 11,
- SVGA_CMD_FREE_OBJECT = 12,
- SVGA_CMD_RECT_ROP_FILL = 13,
- SVGA_CMD_RECT_ROP_COPY = 14,
- SVGA_CMD_RECT_ROP_BITMAP_FILL = 15,
- SVGA_CMD_RECT_ROP_PIXMAP_FILL = 16,
- SVGA_CMD_RECT_ROP_BITMAP_COPY = 17,
- SVGA_CMD_RECT_ROP_PIXMAP_COPY = 18,
- SVGA_CMD_DEFINE_CURSOR = 19,
- SVGA_CMD_DISPLAY_CURSOR = 20,
- SVGA_CMD_MOVE_CURSOR = 21,
- SVGA_CMD_DEFINE_ALPHA_CURSOR = 22,
- SVGA_CMD_DRAW_GLYPH = 23,
- SVGA_CMD_DRAW_GLYPH_CLIPPED = 24,
- SVGA_CMD_UPDATE_VERBOSE = 25,
- SVGA_CMD_SURFACE_FILL = 26,
- SVGA_CMD_SURFACE_COPY = 27,
- SVGA_CMD_SURFACE_ALPHA_BLEND = 28,
- SVGA_CMD_FRONT_ROP_FILL = 29,
- SVGA_CMD_FENCE = 30,
-};
-
-/* Legal values for the SVGA_REG_CURSOR_ON register in cursor bypass mode */
-enum {
- SVGA_CURSOR_ON_HIDE = 0,
- SVGA_CURSOR_ON_SHOW = 1,
- SVGA_CURSOR_ON_REMOVE_FROM_FB = 2,
- SVGA_CURSOR_ON_RESTORE_TO_FB = 3,
-};
-
-static inline bool vmsvga_verify_rect(DisplaySurface *surface,
- const char *name,
- int x, int y, int w, int h)
-{
- if (x < 0) {
- fprintf(stderr, "%s: x was < 0 (%d)\n", name, x);
- return false;
- }
- if (x > SVGA_MAX_WIDTH) {
- fprintf(stderr, "%s: x was > %d (%d)\n", name, SVGA_MAX_WIDTH, x);
- return false;
- }
- if (w < 0) {
- fprintf(stderr, "%s: w was < 0 (%d)\n", name, w);
- return false;
- }
- if (w > SVGA_MAX_WIDTH) {
- fprintf(stderr, "%s: w was > %d (%d)\n", name, SVGA_MAX_WIDTH, w);
- return false;
- }
- if (x + w > surface_width(surface)) {
- fprintf(stderr, "%s: width was > %d (x: %d, w: %d)\n",
- name, surface_width(surface), x, w);
- return false;
- }
-
- if (y < 0) {
- fprintf(stderr, "%s: y was < 0 (%d)\n", name, y);
- return false;
- }
- if (y > SVGA_MAX_HEIGHT) {
- fprintf(stderr, "%s: y was > %d (%d)\n", name, SVGA_MAX_HEIGHT, y);
- return false;
- }
- if (h < 0) {
- fprintf(stderr, "%s: h was < 0 (%d)\n", name, h);
- return false;
- }
- if (h > SVGA_MAX_HEIGHT) {
- fprintf(stderr, "%s: h was > %d (%d)\n", name, SVGA_MAX_HEIGHT, h);
- return false;
- }
- if (y + h > surface_height(surface)) {
- fprintf(stderr, "%s: update height > %d (y: %d, h: %d)\n",
- name, surface_height(surface), y, h);
- return false;
- }
-
- return true;
-}
-
-static inline void vmsvga_update_rect(struct vmsvga_state_s *s,
- int x, int y, int w, int h)
-{
- DisplaySurface *surface = qemu_console_surface(s->vga.con);
- int line;
- int bypl;
- int width;
- int start;
- uint8_t *src;
- uint8_t *dst;
-
- if (!vmsvga_verify_rect(surface, __func__, x, y, w, h)) {
- /* go for a fullscreen update as fallback */
- x = 0;
- y = 0;
- w = surface_width(surface);
- h = surface_height(surface);
- }
-
- bypl = surface_stride(surface);
- width = surface_bytes_per_pixel(surface) * w;
- start = surface_bytes_per_pixel(surface) * x + bypl * y;
- src = s->vga.vram_ptr + start;
- dst = surface_data(surface) + start;
-
- for (line = h; line > 0; line--, src += bypl, dst += bypl) {
- memcpy(dst, src, width);
- }
- dpy_gfx_update(s->vga.con, x, y, w, h);
-}
-
-static inline void vmsvga_update_rect_delayed(struct vmsvga_state_s *s,
- int x, int y, int w, int h)
-{
- struct vmsvga_rect_s *rect = &s->redraw_fifo[s->redraw_fifo_last++];
-
- s->redraw_fifo_last &= REDRAW_FIFO_LEN - 1;
- rect->x = x;
- rect->y = y;
- rect->w = w;
- rect->h = h;
-}
-
-static inline void vmsvga_update_rect_flush(struct vmsvga_state_s *s)
-{
- struct vmsvga_rect_s *rect;
-
- if (s->invalidated) {
- s->redraw_fifo_first = s->redraw_fifo_last;
- return;
- }
- /* Overlapping region updates can be optimised out here - if someone
- * knows a smart algorithm to do that, please share. */
- while (s->redraw_fifo_first != s->redraw_fifo_last) {
- rect = &s->redraw_fifo[s->redraw_fifo_first++];
- s->redraw_fifo_first &= REDRAW_FIFO_LEN - 1;
- vmsvga_update_rect(s, rect->x, rect->y, rect->w, rect->h);
- }
-}
-
-#ifdef HW_RECT_ACCEL
-static inline int vmsvga_copy_rect(struct vmsvga_state_s *s,
- int x0, int y0, int x1, int y1, int w, int h)
-{
- DisplaySurface *surface = qemu_console_surface(s->vga.con);
- uint8_t *vram = s->vga.vram_ptr;
- int bypl = surface_stride(surface);
- int bypp = surface_bytes_per_pixel(surface);
- int width = bypp * w;
- int line = h;
- uint8_t *ptr[2];
-
- if (!vmsvga_verify_rect(surface, "vmsvga_copy_rect/src", x0, y0, w, h)) {
- return -1;
- }
- if (!vmsvga_verify_rect(surface, "vmsvga_copy_rect/dst", x1, y1, w, h)) {
- return -1;
- }
-
- if (y1 > y0) {
- ptr[0] = vram + bypp * x0 + bypl * (y0 + h - 1);
- ptr[1] = vram + bypp * x1 + bypl * (y1 + h - 1);
- for (; line > 0; line --, ptr[0] -= bypl, ptr[1] -= bypl) {
- memmove(ptr[1], ptr[0], width);
- }
- } else {
- ptr[0] = vram + bypp * x0 + bypl * y0;
- ptr[1] = vram + bypp * x1 + bypl * y1;
- for (; line > 0; line --, ptr[0] += bypl, ptr[1] += bypl) {
- memmove(ptr[1], ptr[0], width);
- }
- }
-
- vmsvga_update_rect_delayed(s, x1, y1, w, h);
- return 0;
-}
-#endif
-
-#ifdef HW_FILL_ACCEL
-static inline int vmsvga_fill_rect(struct vmsvga_state_s *s,
- uint32_t c, int x, int y, int w, int h)
-{
- DisplaySurface *surface = qemu_console_surface(s->vga.con);
- int bypl = surface_stride(surface);
- int width = surface_bytes_per_pixel(surface) * w;
- int line = h;
- int column;
- uint8_t *fst;
- uint8_t *dst;
- uint8_t *src;
- uint8_t col[4];
-
- if (!vmsvga_verify_rect(surface, __func__, x, y, w, h)) {
- return -1;
- }
-
- col[0] = c;
- col[1] = c >> 8;
- col[2] = c >> 16;
- col[3] = c >> 24;
-
- fst = s->vga.vram_ptr + surface_bytes_per_pixel(surface) * x + bypl * y;
-
- if (line--) {
- dst = fst;
- src = col;
- for (column = width; column > 0; column--) {
- *(dst++) = *(src++);
- if (src - col == surface_bytes_per_pixel(surface)) {
- src = col;
- }
- }
- dst = fst;
- for (; line > 0; line--) {
- dst += bypl;
- memcpy(dst, fst, width);
- }
- }
-
- vmsvga_update_rect_delayed(s, x, y, w, h);
- return 0;
-}
-#endif
-
-struct vmsvga_cursor_definition_s {
- uint32_t width;
- uint32_t height;
- int id;
- uint32_t bpp;
- int hot_x;
- int hot_y;
- uint32_t mask[1024];
- uint32_t image[4096];
-};
-
-#define SVGA_BITMAP_SIZE(w, h) ((((w) + 31) >> 5) * (h))
-#define SVGA_PIXMAP_SIZE(w, h, bpp) (((((w) * (bpp)) + 31) >> 5) * (h))
-
-#ifdef HW_MOUSE_ACCEL
-static inline void vmsvga_cursor_define(struct vmsvga_state_s *s,
- struct vmsvga_cursor_definition_s *c)
-{
- QEMUCursor *qc;
- int i, pixels;
-
- qc = cursor_alloc(c->width, c->height);
- qc->hot_x = c->hot_x;
- qc->hot_y = c->hot_y;
- switch (c->bpp) {
- case 1:
- cursor_set_mono(qc, 0xffffff, 0x000000, (void *)c->image,
- 1, (void *)c->mask);
-#ifdef DEBUG
- cursor_print_ascii_art(qc, "vmware/mono");
-#endif
- break;
- case 32:
- /* fill alpha channel from mask, set color to zero */
- cursor_set_mono(qc, 0x000000, 0x000000, (void *)c->mask,
- 1, (void *)c->mask);
- /* add in rgb values */
- pixels = c->width * c->height;
- for (i = 0; i < pixels; i++) {
- qc->data[i] |= c->image[i] & 0xffffff;
- }
-#ifdef DEBUG
- cursor_print_ascii_art(qc, "vmware/32bit");
-#endif
- break;
- default:
- fprintf(stderr, "%s: unhandled bpp %d, using fallback cursor\n",
- __func__, c->bpp);
- cursor_put(qc);
- qc = cursor_builtin_left_ptr();
- }
-
- dpy_cursor_define(s->vga.con, qc);
- cursor_put(qc);
-}
-#endif
-
-#define CMD(f) le32_to_cpu(s->cmd->f)
-
-static inline int vmsvga_fifo_length(struct vmsvga_state_s *s)
-{
- int num;
-
- if (!s->config || !s->enable) {
- return 0;
- }
- num = CMD(next_cmd) - CMD(stop);
- if (num < 0) {
- num += CMD(max) - CMD(min);
- }
- return num >> 2;
-}
-
-static inline uint32_t vmsvga_fifo_read_raw(struct vmsvga_state_s *s)
-{
- uint32_t cmd = s->fifo[CMD(stop) >> 2];
-
- s->cmd->stop = cpu_to_le32(CMD(stop) + 4);
- if (CMD(stop) >= CMD(max)) {
- s->cmd->stop = s->cmd->min;
- }
- return cmd;
-}
-
-static inline uint32_t vmsvga_fifo_read(struct vmsvga_state_s *s)
-{
- return le32_to_cpu(vmsvga_fifo_read_raw(s));
-}
-
-static void vmsvga_fifo_run(struct vmsvga_state_s *s)
-{
- uint32_t cmd, colour;
- int args, len;
- int x, y, dx, dy, width, height;
- struct vmsvga_cursor_definition_s cursor;
- uint32_t cmd_start;
-
- len = vmsvga_fifo_length(s);
- while (len > 0) {
- /* May need to go back to the start of the command if incomplete */
- cmd_start = s->cmd->stop;
-
- switch (cmd = vmsvga_fifo_read(s)) {
- case SVGA_CMD_UPDATE:
- case SVGA_CMD_UPDATE_VERBOSE:
- len -= 5;
- if (len < 0) {
- goto rewind;
- }
-
- x = vmsvga_fifo_read(s);
- y = vmsvga_fifo_read(s);
- width = vmsvga_fifo_read(s);
- height = vmsvga_fifo_read(s);
- vmsvga_update_rect_delayed(s, x, y, width, height);
- break;
-
- case SVGA_CMD_RECT_FILL:
- len -= 6;
- if (len < 0) {
- goto rewind;
- }
-
- colour = vmsvga_fifo_read(s);
- x = vmsvga_fifo_read(s);
- y = vmsvga_fifo_read(s);
- width = vmsvga_fifo_read(s);
- height = vmsvga_fifo_read(s);
-#ifdef HW_FILL_ACCEL
- if (vmsvga_fill_rect(s, colour, x, y, width, height) == 0) {
- break;
- }
-#endif
- args = 0;
- goto badcmd;
-
- case SVGA_CMD_RECT_COPY:
- len -= 7;
- if (len < 0) {
- goto rewind;
- }
-
- x = vmsvga_fifo_read(s);
- y = vmsvga_fifo_read(s);
- dx = vmsvga_fifo_read(s);
- dy = vmsvga_fifo_read(s);
- width = vmsvga_fifo_read(s);
- height = vmsvga_fifo_read(s);
-#ifdef HW_RECT_ACCEL
- if (vmsvga_copy_rect(s, x, y, dx, dy, width, height) == 0) {
- break;
- }
-#endif
- args = 0;
- goto badcmd;
-
- case SVGA_CMD_DEFINE_CURSOR:
- len -= 8;
- if (len < 0) {
- goto rewind;
- }
-
- cursor.id = vmsvga_fifo_read(s);
- cursor.hot_x = vmsvga_fifo_read(s);
- cursor.hot_y = vmsvga_fifo_read(s);
- cursor.width = x = vmsvga_fifo_read(s);
- cursor.height = y = vmsvga_fifo_read(s);
- vmsvga_fifo_read(s);
- cursor.bpp = vmsvga_fifo_read(s);
-
- args = SVGA_BITMAP_SIZE(x, y) + SVGA_PIXMAP_SIZE(x, y, cursor.bpp);
- if (cursor.width > 256 ||
- cursor.height > 256 ||
- cursor.bpp > 32 ||
- SVGA_BITMAP_SIZE(x, y) > sizeof cursor.mask ||
- SVGA_PIXMAP_SIZE(x, y, cursor.bpp) > sizeof cursor.image) {
- goto badcmd;
- }
-
- len -= args;
- if (len < 0) {
- goto rewind;
- }
-
- for (args = 0; args < SVGA_BITMAP_SIZE(x, y); args++) {
- cursor.mask[args] = vmsvga_fifo_read_raw(s);
- }
- for (args = 0; args < SVGA_PIXMAP_SIZE(x, y, cursor.bpp); args++) {
- cursor.image[args] = vmsvga_fifo_read_raw(s);
- }
-#ifdef HW_MOUSE_ACCEL
- vmsvga_cursor_define(s, &cursor);
- break;
-#else
- args = 0;
- goto badcmd;
-#endif
-
- /*
- * Other commands that we at least know the number of arguments
- * for so we can avoid FIFO desync if driver uses them illegally.
- */
- case SVGA_CMD_DEFINE_ALPHA_CURSOR:
- len -= 6;
- if (len < 0) {
- goto rewind;
- }
- vmsvga_fifo_read(s);
- vmsvga_fifo_read(s);
- vmsvga_fifo_read(s);
- x = vmsvga_fifo_read(s);
- y = vmsvga_fifo_read(s);
- args = x * y;
- goto badcmd;
- case SVGA_CMD_RECT_ROP_FILL:
- args = 6;
- goto badcmd;
- case SVGA_CMD_RECT_ROP_COPY:
- args = 7;
- goto badcmd;
- case SVGA_CMD_DRAW_GLYPH_CLIPPED:
- len -= 4;
- if (len < 0) {
- goto rewind;
- }
- vmsvga_fifo_read(s);
- vmsvga_fifo_read(s);
- args = 7 + (vmsvga_fifo_read(s) >> 2);
- goto badcmd;
- case SVGA_CMD_SURFACE_ALPHA_BLEND:
- args = 12;
- goto badcmd;
-
- /*
- * Other commands that are not listed as depending on any
- * CAPABILITIES bits, but are not described in the README either.
- */
- case SVGA_CMD_SURFACE_FILL:
- case SVGA_CMD_SURFACE_COPY:
- case SVGA_CMD_FRONT_ROP_FILL:
- case SVGA_CMD_FENCE:
- case SVGA_CMD_INVALID_CMD:
- break; /* Nop */
-
- default:
- args = 0;
- badcmd:
- len -= args;
- if (len < 0) {
- goto rewind;
- }
- while (args--) {
- vmsvga_fifo_read(s);
- }
- printf("%s: Unknown command 0x%02x in SVGA command FIFO\n",
- __func__, cmd);
- break;
-
- rewind:
- s->cmd->stop = cmd_start;
- break;
- }
- }
-
- s->syncing = 0;
-}
-
-static uint32_t vmsvga_index_read(void *opaque, uint32_t address)
-{
- struct vmsvga_state_s *s = opaque;
-
- return s->index;
-}
-
-static void vmsvga_index_write(void *opaque, uint32_t address, uint32_t index)
-{
- struct vmsvga_state_s *s = opaque;
-
- s->index = index;
-}
-
-static uint32_t vmsvga_value_read(void *opaque, uint32_t address)
-{
- uint32_t caps;
- struct vmsvga_state_s *s = opaque;
- DisplaySurface *surface = qemu_console_surface(s->vga.con);
- PixelFormat pf;
- uint32_t ret;
-
- switch (s->index) {
- case SVGA_REG_ID:
- ret = s->svgaid;
- break;
-
- case SVGA_REG_ENABLE:
- ret = s->enable;
- break;
-
- case SVGA_REG_WIDTH:
- ret = s->new_width ? s->new_width : surface_width(surface);
- break;
-
- case SVGA_REG_HEIGHT:
- ret = s->new_height ? s->new_height : surface_height(surface);
- break;
-
- case SVGA_REG_MAX_WIDTH:
- ret = SVGA_MAX_WIDTH;
- break;
-
- case SVGA_REG_MAX_HEIGHT:
- ret = SVGA_MAX_HEIGHT;
- break;
-
- case SVGA_REG_DEPTH:
- ret = (s->new_depth == 32) ? 24 : s->new_depth;
- break;
-
- case SVGA_REG_BITS_PER_PIXEL:
- case SVGA_REG_HOST_BITS_PER_PIXEL:
- ret = s->new_depth;
- break;
-
- case SVGA_REG_PSEUDOCOLOR:
- ret = 0x0;
- break;
-
- case SVGA_REG_RED_MASK:
- pf = qemu_default_pixelformat(s->new_depth);
- ret = pf.rmask;
- break;
-
- case SVGA_REG_GREEN_MASK:
- pf = qemu_default_pixelformat(s->new_depth);
- ret = pf.gmask;
- break;
-
- case SVGA_REG_BLUE_MASK:
- pf = qemu_default_pixelformat(s->new_depth);
- ret = pf.bmask;
- break;
-
- case SVGA_REG_BYTES_PER_LINE:
- if (s->new_width) {
- ret = (s->new_depth * s->new_width) / 8;
- } else {
- ret = surface_stride(surface);
- }
- break;
-
- case SVGA_REG_FB_START: {
- struct pci_vmsvga_state_s *pci_vmsvga
- = container_of(s, struct pci_vmsvga_state_s, chip);
- ret = pci_get_bar_addr(PCI_DEVICE(pci_vmsvga), 1);
- break;
- }
-
- case SVGA_REG_FB_OFFSET:
- ret = 0x0;
- break;
-
- case SVGA_REG_VRAM_SIZE:
- ret = s->vga.vram_size; /* No physical VRAM besides the framebuffer */
- break;
-
- case SVGA_REG_FB_SIZE:
- ret = s->vga.vram_size;
- break;
-
- case SVGA_REG_CAPABILITIES:
- caps = SVGA_CAP_NONE;
-#ifdef HW_RECT_ACCEL
- caps |= SVGA_CAP_RECT_COPY;
-#endif
-#ifdef HW_FILL_ACCEL
- caps |= SVGA_CAP_RECT_FILL;
-#endif
-#ifdef HW_MOUSE_ACCEL
- if (dpy_cursor_define_supported(s->vga.con)) {
- caps |= SVGA_CAP_CURSOR | SVGA_CAP_CURSOR_BYPASS_2 |
- SVGA_CAP_CURSOR_BYPASS;
- }
-#endif
- ret = caps;
- break;
-
- case SVGA_REG_MEM_START: {
- struct pci_vmsvga_state_s *pci_vmsvga
- = container_of(s, struct pci_vmsvga_state_s, chip);
- ret = pci_get_bar_addr(PCI_DEVICE(pci_vmsvga), 2);
- break;
- }
-
- case SVGA_REG_MEM_SIZE:
- ret = s->fifo_size;
- break;
-
- case SVGA_REG_CONFIG_DONE:
- ret = s->config;
- break;
-
- case SVGA_REG_SYNC:
- case SVGA_REG_BUSY:
- ret = s->syncing;
- break;
-
- case SVGA_REG_GUEST_ID:
- ret = s->guest;
- break;
-
- case SVGA_REG_CURSOR_ID:
- ret = s->cursor.id;
- break;
-
- case SVGA_REG_CURSOR_X:
- ret = s->cursor.x;
- break;
-
- case SVGA_REG_CURSOR_Y:
- ret = s->cursor.y;
- break;
-
- case SVGA_REG_CURSOR_ON:
- ret = s->cursor.on;
- break;
-
- case SVGA_REG_SCRATCH_SIZE:
- ret = s->scratch_size;
- break;
-
- case SVGA_REG_MEM_REGS:
- case SVGA_REG_NUM_DISPLAYS:
- case SVGA_REG_PITCHLOCK:
- case SVGA_PALETTE_BASE ... SVGA_PALETTE_END:
- ret = 0;
- break;
-
- default:
- if (s->index >= SVGA_SCRATCH_BASE &&
- s->index < SVGA_SCRATCH_BASE + s->scratch_size) {
- ret = s->scratch[s->index - SVGA_SCRATCH_BASE];
- break;
- }
- printf("%s: Bad register %02x\n", __func__, s->index);
- ret = 0;
- break;
- }
-
- if (s->index >= SVGA_SCRATCH_BASE) {
- trace_vmware_scratch_read(s->index, ret);
- } else if (s->index >= SVGA_PALETTE_BASE) {
- trace_vmware_palette_read(s->index, ret);
- } else {
- trace_vmware_value_read(s->index, ret);
- }
- return ret;
-}
-
-static void vmsvga_value_write(void *opaque, uint32_t address, uint32_t value)
-{
- struct vmsvga_state_s *s = opaque;
-
- if (s->index >= SVGA_SCRATCH_BASE) {
- trace_vmware_scratch_write(s->index, value);
- } else if (s->index >= SVGA_PALETTE_BASE) {
- trace_vmware_palette_write(s->index, value);
- } else {
- trace_vmware_value_write(s->index, value);
- }
- switch (s->index) {
- case SVGA_REG_ID:
- if (value == SVGA_ID_2 || value == SVGA_ID_1 || value == SVGA_ID_0) {
- s->svgaid = value;
- }
- break;
-
- case SVGA_REG_ENABLE:
- s->enable = !!value;
- s->invalidated = 1;
- s->vga.hw_ops->invalidate(&s->vga);
- if (s->enable && s->config) {
- vga_dirty_log_stop(&s->vga);
- } else {
- vga_dirty_log_start(&s->vga);
- }
- break;
-
- case SVGA_REG_WIDTH:
- if (value <= SVGA_MAX_WIDTH) {
- s->new_width = value;
- s->invalidated = 1;
- } else {
- printf("%s: Bad width: %i\n", __func__, value);
- }
- break;
-
- case SVGA_REG_HEIGHT:
- if (value <= SVGA_MAX_HEIGHT) {
- s->new_height = value;
- s->invalidated = 1;
- } else {
- printf("%s: Bad height: %i\n", __func__, value);
- }
- break;
-
- case SVGA_REG_BITS_PER_PIXEL:
- if (value != 32) {
- printf("%s: Bad bits per pixel: %i bits\n", __func__, value);
- s->config = 0;
- s->invalidated = 1;
- }
- break;
-
- case SVGA_REG_CONFIG_DONE:
- if (value) {
- s->fifo = (uint32_t *) s->fifo_ptr;
- /* Check range and alignment. */
- if ((CMD(min) | CMD(max) | CMD(next_cmd) | CMD(stop)) & 3) {
- break;
- }
- if (CMD(min) < (uint8_t *) s->cmd->fifo - (uint8_t *) s->fifo) {
- break;
- }
- if (CMD(max) > SVGA_FIFO_SIZE) {
- break;
- }
- if (CMD(max) < CMD(min) + 10 * 1024) {
- break;
- }
- vga_dirty_log_stop(&s->vga);
- }
- s->config = !!value;
- break;
-
- case SVGA_REG_SYNC:
- s->syncing = 1;
- vmsvga_fifo_run(s); /* Or should we just wait for update_display? */
- break;
-
- case SVGA_REG_GUEST_ID:
- s->guest = value;
-#ifdef VERBOSE
- if (value >= GUEST_OS_BASE && value < GUEST_OS_BASE +
- ARRAY_SIZE(vmsvga_guest_id)) {
- printf("%s: guest runs %s.\n", __func__,
- vmsvga_guest_id[value - GUEST_OS_BASE]);
- }
-#endif
- break;
-
- case SVGA_REG_CURSOR_ID:
- s->cursor.id = value;
- break;
-
- case SVGA_REG_CURSOR_X:
- s->cursor.x = value;
- break;
-
- case SVGA_REG_CURSOR_Y:
- s->cursor.y = value;
- break;
-
- case SVGA_REG_CURSOR_ON:
- s->cursor.on |= (value == SVGA_CURSOR_ON_SHOW);
- s->cursor.on &= (value != SVGA_CURSOR_ON_HIDE);
-#ifdef HW_MOUSE_ACCEL
- if (value <= SVGA_CURSOR_ON_SHOW) {
- dpy_mouse_set(s->vga.con, s->cursor.x, s->cursor.y, s->cursor.on);
- }
-#endif
- break;
-
- case SVGA_REG_DEPTH:
- case SVGA_REG_MEM_REGS:
- case SVGA_REG_NUM_DISPLAYS:
- case SVGA_REG_PITCHLOCK:
- case SVGA_PALETTE_BASE ... SVGA_PALETTE_END:
- break;
-
- default:
- if (s->index >= SVGA_SCRATCH_BASE &&
- s->index < SVGA_SCRATCH_BASE + s->scratch_size) {
- s->scratch[s->index - SVGA_SCRATCH_BASE] = value;
- break;
- }
- printf("%s: Bad register %02x\n", __func__, s->index);
- }
-}
-
-static uint32_t vmsvga_bios_read(void *opaque, uint32_t address)
-{
- printf("%s: what are we supposed to return?\n", __func__);
- return 0xcafe;
-}
-
-static void vmsvga_bios_write(void *opaque, uint32_t address, uint32_t data)
-{
- printf("%s: what are we supposed to do with (%08x)?\n", __func__, data);
-}
-
-static inline void vmsvga_check_size(struct vmsvga_state_s *s)
-{
- DisplaySurface *surface = qemu_console_surface(s->vga.con);
-
- if (s->new_width != surface_width(surface) ||
- s->new_height != surface_height(surface) ||
- s->new_depth != surface_bits_per_pixel(surface)) {
- int stride = (s->new_depth * s->new_width) / 8;
- pixman_format_code_t format =
- qemu_default_pixman_format(s->new_depth, true);
- trace_vmware_setmode(s->new_width, s->new_height, s->new_depth);
- surface = qemu_create_displaysurface_from(s->new_width, s->new_height,
- format, stride,
- s->vga.vram_ptr);
- dpy_gfx_replace_surface(s->vga.con, surface);
- s->invalidated = 1;
- }
-}
-
-static void vmsvga_update_display(void *opaque)
-{
- struct vmsvga_state_s *s = opaque;
- DisplaySurface *surface;
- bool dirty = false;
-
- if (!s->enable) {
- s->vga.hw_ops->gfx_update(&s->vga);
- return;
- }
-
- vmsvga_check_size(s);
- surface = qemu_console_surface(s->vga.con);
-
- vmsvga_fifo_run(s);
- vmsvga_update_rect_flush(s);
-
- /*
- * Is it more efficient to look at vram VGA-dirty bits or wait
- * for the driver to issue SVGA_CMD_UPDATE?
- */
- if (memory_region_is_logging(&s->vga.vram, DIRTY_MEMORY_VGA)) {
- vga_sync_dirty_bitmap(&s->vga);
- dirty = memory_region_get_dirty(&s->vga.vram, 0,
- surface_stride(surface) * surface_height(surface),
- DIRTY_MEMORY_VGA);
- }
- if (s->invalidated || dirty) {
- s->invalidated = 0;
- dpy_gfx_update(s->vga.con, 0, 0,
- surface_width(surface), surface_height(surface));
- }
- if (dirty) {
- memory_region_reset_dirty(&s->vga.vram, 0,
- surface_stride(surface) * surface_height(surface),
- DIRTY_MEMORY_VGA);
- }
-}
-
-static void vmsvga_reset(DeviceState *dev)
-{
- struct pci_vmsvga_state_s *pci = VMWARE_SVGA(dev);
- struct vmsvga_state_s *s = &pci->chip;
-
- s->index = 0;
- s->enable = 0;
- s->config = 0;
- s->svgaid = SVGA_ID;
- s->cursor.on = 0;
- s->redraw_fifo_first = 0;
- s->redraw_fifo_last = 0;
- s->syncing = 0;
-
- vga_dirty_log_start(&s->vga);
-}
-
-static void vmsvga_invalidate_display(void *opaque)
-{
- struct vmsvga_state_s *s = opaque;
- if (!s->enable) {
- s->vga.hw_ops->invalidate(&s->vga);
- return;
- }
-
- s->invalidated = 1;
-}
-
-static void vmsvga_text_update(void *opaque, console_ch_t *chardata)
-{
- struct vmsvga_state_s *s = opaque;
-
- if (s->vga.hw_ops->text_update) {
- s->vga.hw_ops->text_update(&s->vga, chardata);
- }
-}
-
-static int vmsvga_post_load(void *opaque, int version_id)
-{
- struct vmsvga_state_s *s = opaque;
-
- s->invalidated = 1;
- if (s->config) {
- s->fifo = (uint32_t *) s->fifo_ptr;
- }
- return 0;
-}
-
-static const VMStateDescription vmstate_vmware_vga_internal = {
- .name = "vmware_vga_internal",
- .version_id = 0,
- .minimum_version_id = 0,
- .post_load = vmsvga_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_INT32_EQUAL(new_depth, struct vmsvga_state_s),
- VMSTATE_INT32(enable, struct vmsvga_state_s),
- VMSTATE_INT32(config, struct vmsvga_state_s),
- VMSTATE_INT32(cursor.id, struct vmsvga_state_s),
- VMSTATE_INT32(cursor.x, struct vmsvga_state_s),
- VMSTATE_INT32(cursor.y, struct vmsvga_state_s),
- VMSTATE_INT32(cursor.on, struct vmsvga_state_s),
- VMSTATE_INT32(index, struct vmsvga_state_s),
- VMSTATE_VARRAY_INT32(scratch, struct vmsvga_state_s,
- scratch_size, 0, vmstate_info_uint32, uint32_t),
- VMSTATE_INT32(new_width, struct vmsvga_state_s),
- VMSTATE_INT32(new_height, struct vmsvga_state_s),
- VMSTATE_UINT32(guest, struct vmsvga_state_s),
- VMSTATE_UINT32(svgaid, struct vmsvga_state_s),
- VMSTATE_INT32(syncing, struct vmsvga_state_s),
- VMSTATE_UNUSED(4), /* was fb_size */
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_vmware_vga = {
- .name = "vmware_vga",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(parent_obj, struct pci_vmsvga_state_s),
- VMSTATE_STRUCT(chip, struct pci_vmsvga_state_s, 0,
- vmstate_vmware_vga_internal, struct vmsvga_state_s),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const GraphicHwOps vmsvga_ops = {
- .invalidate = vmsvga_invalidate_display,
- .gfx_update = vmsvga_update_display,
- .text_update = vmsvga_text_update,
-};
-
-static void vmsvga_init(DeviceState *dev, struct vmsvga_state_s *s,
- MemoryRegion *address_space, MemoryRegion *io)
-{
- s->scratch_size = SVGA_SCRATCH_SIZE;
- s->scratch = g_malloc(s->scratch_size * 4);
-
- s->vga.con = graphic_console_init(dev, 0, &vmsvga_ops, s);
-
- s->fifo_size = SVGA_FIFO_SIZE;
- memory_region_init_ram(&s->fifo_ram, NULL, "vmsvga.fifo", s->fifo_size,
- &error_fatal);
- vmstate_register_ram_global(&s->fifo_ram);
- s->fifo_ptr = memory_region_get_ram_ptr(&s->fifo_ram);
-
- vga_common_init(&s->vga, OBJECT(dev), true);
- vga_init(&s->vga, OBJECT(dev), address_space, io, true);
- vmstate_register(NULL, 0, &vmstate_vga_common, &s->vga);
- s->new_depth = 32;
-}
-
-static uint64_t vmsvga_io_read(void *opaque, hwaddr addr, unsigned size)
-{
- struct vmsvga_state_s *s = opaque;
-
- switch (addr) {
- case SVGA_IO_MUL * SVGA_INDEX_PORT: return vmsvga_index_read(s, addr);
- case SVGA_IO_MUL * SVGA_VALUE_PORT: return vmsvga_value_read(s, addr);
- case SVGA_IO_MUL * SVGA_BIOS_PORT: return vmsvga_bios_read(s, addr);
- default: return -1u;
- }
-}
-
-static void vmsvga_io_write(void *opaque, hwaddr addr,
- uint64_t data, unsigned size)
-{
- struct vmsvga_state_s *s = opaque;
-
- switch (addr) {
- case SVGA_IO_MUL * SVGA_INDEX_PORT:
- vmsvga_index_write(s, addr, data);
- break;
- case SVGA_IO_MUL * SVGA_VALUE_PORT:
- vmsvga_value_write(s, addr, data);
- break;
- case SVGA_IO_MUL * SVGA_BIOS_PORT:
- vmsvga_bios_write(s, addr, data);
- break;
- }
-}
-
-static const MemoryRegionOps vmsvga_io_ops = {
- .read = vmsvga_io_read,
- .write = vmsvga_io_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- .unaligned = true,
- },
- .impl = {
- .unaligned = true,
- },
-};
-
-static void pci_vmsvga_realize(PCIDevice *dev, Error **errp)
-{
- struct pci_vmsvga_state_s *s = VMWARE_SVGA(dev);
-
- dev->config[PCI_CACHE_LINE_SIZE] = 0x08;
- dev->config[PCI_LATENCY_TIMER] = 0x40;
- dev->config[PCI_INTERRUPT_LINE] = 0xff; /* End */
-
- memory_region_init_io(&s->io_bar, NULL, &vmsvga_io_ops, &s->chip,
- "vmsvga-io", 0x10);
- memory_region_set_flush_coalesced(&s->io_bar);
- pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_bar);
-
- vmsvga_init(DEVICE(dev), &s->chip,
- pci_address_space(dev), pci_address_space_io(dev));
-
- pci_register_bar(dev, 1, PCI_BASE_ADDRESS_MEM_PREFETCH,
- &s->chip.vga.vram);
- pci_register_bar(dev, 2, PCI_BASE_ADDRESS_MEM_PREFETCH,
- &s->chip.fifo_ram);
-
- if (!dev->rom_bar) {
- /* compatibility with pc-0.13 and older */
- vga_init_vbe(&s->chip.vga, OBJECT(dev), pci_address_space(dev));
- }
-}
-
-static Property vga_vmware_properties[] = {
- DEFINE_PROP_UINT32("vgamem_mb", struct pci_vmsvga_state_s,
- chip.vga.vram_size_mb, 16),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void vmsvga_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = pci_vmsvga_realize;
- k->romfile = "vgabios-vmware.bin";
- k->vendor_id = PCI_VENDOR_ID_VMWARE;
- k->device_id = SVGA_PCI_DEVICE_ID;
- k->class_id = PCI_CLASS_DISPLAY_VGA;
- k->subsystem_vendor_id = PCI_VENDOR_ID_VMWARE;
- k->subsystem_id = SVGA_PCI_DEVICE_ID;
- dc->reset = vmsvga_reset;
- dc->vmsd = &vmstate_vmware_vga;
- dc->props = vga_vmware_properties;
- dc->hotpluggable = false;
- set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
-}
-
-static const TypeInfo vmsvga_info = {
- .name = TYPE_VMWARE_SVGA,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(struct pci_vmsvga_state_s),
- .class_init = vmsvga_class_init,
-};
-
-static void vmsvga_register_types(void)
-{
- type_register_static(&vmsvga_info);
-}
-
-type_init(vmsvga_register_types)
diff --git a/qemu/hw/display/xenfb.c b/qemu/hw/display/xenfb.c
deleted file mode 100644
index 9866dfda5..000000000
--- a/qemu/hw/display/xenfb.c
+++ /dev/null
@@ -1,1004 +0,0 @@
-/*
- * xen paravirt framebuffer backend
- *
- * Copyright IBM, Corp. 2005-2006
- * Copyright Red Hat, Inc. 2006-2008
- *
- * Authors:
- * Anthony Liguori <aliguori@us.ibm.com>,
- * Markus Armbruster <armbru@redhat.com>,
- * Daniel P. Berrange <berrange@redhat.com>,
- * Pat Campbell <plc@novell.com>,
- * Gerd Hoffmann <kraxel@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; under version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include <sys/mman.h>
-
-#include "hw/hw.h"
-#include "ui/console.h"
-#include "sysemu/char.h"
-#include "hw/xen/xen_backend.h"
-
-#include <xen/event_channel.h>
-#include <xen/io/fbif.h>
-#include <xen/io/kbdif.h>
-#include <xen/io/protocols.h>
-
-#include "trace.h"
-
-#ifndef BTN_LEFT
-#define BTN_LEFT 0x110 /* from <linux/input.h> */
-#endif
-
-/* -------------------------------------------------------------------- */
-
-struct common {
- struct XenDevice xendev; /* must be first */
- void *page;
- QemuConsole *con;
-};
-
-struct XenInput {
- struct common c;
- int abs_pointer_wanted; /* Whether guest supports absolute pointer */
- int button_state; /* Last seen pointer button state */
- int extended;
- QEMUPutMouseEntry *qmouse;
-};
-
-#define UP_QUEUE 8
-
-struct XenFB {
- struct common c;
- size_t fb_len;
- int row_stride;
- int depth;
- int width;
- int height;
- int offset;
- void *pixels;
- int fbpages;
- int feature_update;
- int bug_trigger;
- int have_console;
- int do_resize;
-
- struct {
- int x,y,w,h;
- } up_rects[UP_QUEUE];
- int up_count;
- int up_fullscreen;
-};
-
-/* -------------------------------------------------------------------- */
-
-static int common_bind(struct common *c)
-{
- uint64_t val;
- xen_pfn_t mfn;
-
- if (xenstore_read_fe_uint64(&c->xendev, "page-ref", &val) == -1)
- return -1;
- mfn = (xen_pfn_t)val;
- assert(val == mfn);
-
- if (xenstore_read_fe_int(&c->xendev, "event-channel", &c->xendev.remote_port) == -1)
- return -1;
-
- c->page = xenforeignmemory_map(xen_fmem, c->xendev.dom,
- PROT_READ | PROT_WRITE, 1, &mfn, NULL);
- if (c->page == NULL)
- return -1;
-
- xen_be_bind_evtchn(&c->xendev);
- xen_be_printf(&c->xendev, 1, "ring mfn %"PRI_xen_pfn", remote-port %d, local-port %d\n",
- mfn, c->xendev.remote_port, c->xendev.local_port);
-
- return 0;
-}
-
-static void common_unbind(struct common *c)
-{
- xen_be_unbind_evtchn(&c->xendev);
- if (c->page) {
- xenforeignmemory_unmap(xen_fmem, c->page, 1);
- c->page = NULL;
- }
-}
-
-/* -------------------------------------------------------------------- */
-
-#if 0
-/*
- * These two tables are not needed any more, but left in here
- * intentionally as documentation, to show how scancode2linux[]
- * was generated.
- *
- * Tables to map from scancode to Linux input layer keycode.
- * Scancodes are hardware-specific. These maps assumes a
- * standard AT or PS/2 keyboard which is what QEMU feeds us.
- */
-const unsigned char atkbd_set2_keycode[512] = {
-
- 0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41,117,
- 0, 56, 42, 93, 29, 16, 2, 0, 0, 0, 44, 31, 30, 17, 3, 0,
- 0, 46, 45, 32, 18, 5, 4, 95, 0, 57, 47, 33, 20, 19, 6,183,
- 0, 49, 48, 35, 34, 21, 7,184, 0, 0, 50, 36, 22, 8, 9,185,
- 0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0,
- 0, 89, 40, 0, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0, 85,
- 0, 86, 91, 90, 92, 0, 14, 94, 0, 79,124, 75, 71,121, 0, 0,
- 82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
-
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 217,100,255, 0, 97,165, 0, 0,156, 0, 0, 0, 0, 0, 0,125,
- 173,114, 0,113, 0, 0, 0,126,128, 0, 0,140, 0, 0, 0,127,
- 159, 0,115, 0,164, 0, 0,116,158, 0,150,166, 0, 0, 0,142,
- 157, 0, 0, 0, 0, 0, 0, 0,155, 0, 98, 0, 0,163, 0, 0,
- 226, 0, 0, 0, 0, 0, 0, 0, 0,255, 96, 0, 0, 0,143, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,107, 0,105,102, 0, 0,112,
- 110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119, 0,
-
-};
-
-const unsigned char atkbd_unxlate_table[128] = {
-
- 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
- 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
- 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
- 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3,
- 11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105,
- 114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63,
- 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,
- 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110
-
-};
-#endif
-
-/*
- * for (i = 0; i < 128; i++) {
- * scancode2linux[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
- * scancode2linux[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
- * }
- */
-static const unsigned char scancode2linux[512] = {
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
- 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
- 80, 81, 82, 83, 99, 0, 86, 87, 88,117, 0, 0, 95,183,184,185,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 93, 0, 0, 89, 0, 0, 85, 91, 90, 92, 0, 94, 0,124,121, 0,
-
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 165, 0, 0, 0, 0, 0, 0, 0, 0,163, 0, 0, 96, 97, 0, 0,
- 113,140,164, 0,166, 0, 0, 0, 0, 0,255, 0, 0, 0,114, 0,
- 115, 0,150, 0, 0, 98,255, 99,100, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,119,119,102,103,104, 0,105,112,106,118,107,
- 108,109,110,111, 0, 0, 0, 0, 0, 0, 0,125,126,127,116,142,
- 0, 0, 0,143, 0,217,156,173,128,159,158,157,155,226, 0,112,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-};
-
-/* Send an event to the keyboard frontend driver */
-static int xenfb_kbd_event(struct XenInput *xenfb,
- union xenkbd_in_event *event)
-{
- struct xenkbd_page *page = xenfb->c.page;
- uint32_t prod;
-
- if (xenfb->c.xendev.be_state != XenbusStateConnected)
- return 0;
- if (!page)
- return 0;
-
- prod = page->in_prod;
- if (prod - page->in_cons == XENKBD_IN_RING_LEN) {
- errno = EAGAIN;
- return -1;
- }
-
- xen_mb(); /* ensure ring space available */
- XENKBD_IN_RING_REF(page, prod) = *event;
- xen_wmb(); /* ensure ring contents visible */
- page->in_prod = prod + 1;
- return xen_be_send_notify(&xenfb->c.xendev);
-}
-
-/* Send a keyboard (or mouse button) event */
-static int xenfb_send_key(struct XenInput *xenfb, bool down, int keycode)
-{
- union xenkbd_in_event event;
-
- memset(&event, 0, XENKBD_IN_EVENT_SIZE);
- event.type = XENKBD_TYPE_KEY;
- event.key.pressed = down ? 1 : 0;
- event.key.keycode = keycode;
-
- return xenfb_kbd_event(xenfb, &event);
-}
-
-/* Send a relative mouse movement event */
-static int xenfb_send_motion(struct XenInput *xenfb,
- int rel_x, int rel_y, int rel_z)
-{
- union xenkbd_in_event event;
-
- memset(&event, 0, XENKBD_IN_EVENT_SIZE);
- event.type = XENKBD_TYPE_MOTION;
- event.motion.rel_x = rel_x;
- event.motion.rel_y = rel_y;
- event.motion.rel_z = rel_z;
-
- return xenfb_kbd_event(xenfb, &event);
-}
-
-/* Send an absolute mouse movement event */
-static int xenfb_send_position(struct XenInput *xenfb,
- int abs_x, int abs_y, int z)
-{
- union xenkbd_in_event event;
-
- memset(&event, 0, XENKBD_IN_EVENT_SIZE);
- event.type = XENKBD_TYPE_POS;
- event.pos.abs_x = abs_x;
- event.pos.abs_y = abs_y;
- event.pos.rel_z = z;
-
- return xenfb_kbd_event(xenfb, &event);
-}
-
-/*
- * Send a key event from the client to the guest OS
- * QEMU gives us a raw scancode from an AT / PS/2 style keyboard.
- * We have to turn this into a Linux Input layer keycode.
- *
- * Extra complexity from the fact that with extended scancodes
- * (like those produced by arrow keys) this method gets called
- * twice, but we only want to send a single event. So we have to
- * track the '0xe0' scancode state & collapse the extended keys
- * as needed.
- *
- * Wish we could just send scancodes straight to the guest which
- * already has code for dealing with this...
- */
-static void xenfb_key_event(void *opaque, int scancode)
-{
- struct XenInput *xenfb = opaque;
- int down = 1;
-
- if (scancode == 0xe0) {
- xenfb->extended = 1;
- return;
- } else if (scancode & 0x80) {
- scancode &= 0x7f;
- down = 0;
- }
- if (xenfb->extended) {
- scancode |= 0x80;
- xenfb->extended = 0;
- }
- xenfb_send_key(xenfb, down, scancode2linux[scancode]);
-}
-
-/*
- * Send a mouse event from the client to the guest OS
- *
- * The QEMU mouse can be in either relative, or absolute mode.
- * Movement is sent separately from button state, which has to
- * be encoded as virtual key events. We also don't actually get
- * given any button up/down events, so have to track changes in
- * the button state.
- */
-static void xenfb_mouse_event(void *opaque,
- int dx, int dy, int dz, int button_state)
-{
- struct XenInput *xenfb = opaque;
- DisplaySurface *surface = qemu_console_surface(xenfb->c.con);
- int dw = surface_width(surface);
- int dh = surface_height(surface);
- int i;
-
- trace_xenfb_mouse_event(opaque, dx, dy, dz, button_state,
- xenfb->abs_pointer_wanted);
- if (xenfb->abs_pointer_wanted)
- xenfb_send_position(xenfb,
- dx * (dw - 1) / 0x7fff,
- dy * (dh - 1) / 0x7fff,
- dz);
- else
- xenfb_send_motion(xenfb, dx, dy, dz);
-
- for (i = 0 ; i < 8 ; i++) {
- int lastDown = xenfb->button_state & (1 << i);
- int down = button_state & (1 << i);
- if (down == lastDown)
- continue;
-
- if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0)
- return;
- }
- xenfb->button_state = button_state;
-}
-
-static int input_init(struct XenDevice *xendev)
-{
- xenstore_write_be_int(xendev, "feature-abs-pointer", 1);
- return 0;
-}
-
-static int input_initialise(struct XenDevice *xendev)
-{
- struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
- int rc;
-
- if (!in->c.con) {
- xen_be_printf(xendev, 1, "ds not set (yet)\n");
- return -1;
- }
-
- rc = common_bind(&in->c);
- if (rc != 0)
- return rc;
-
- qemu_add_kbd_event_handler(xenfb_key_event, in);
- return 0;
-}
-
-static void input_connected(struct XenDevice *xendev)
-{
- struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
-
- if (xenstore_read_fe_int(xendev, "request-abs-pointer",
- &in->abs_pointer_wanted) == -1) {
- in->abs_pointer_wanted = 0;
- }
-
- if (in->qmouse) {
- qemu_remove_mouse_event_handler(in->qmouse);
- }
- trace_xenfb_input_connected(xendev, in->abs_pointer_wanted);
- in->qmouse = qemu_add_mouse_event_handler(xenfb_mouse_event, in,
- in->abs_pointer_wanted,
- "Xen PVFB Mouse");
-}
-
-static void input_disconnect(struct XenDevice *xendev)
-{
- struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
-
- if (in->qmouse) {
- qemu_remove_mouse_event_handler(in->qmouse);
- in->qmouse = NULL;
- }
- qemu_add_kbd_event_handler(NULL, NULL);
- common_unbind(&in->c);
-}
-
-static void input_event(struct XenDevice *xendev)
-{
- struct XenInput *xenfb = container_of(xendev, struct XenInput, c.xendev);
- struct xenkbd_page *page = xenfb->c.page;
-
- /* We don't understand any keyboard events, so just ignore them. */
- if (page->out_prod == page->out_cons)
- return;
- page->out_cons = page->out_prod;
- xen_be_send_notify(&xenfb->c.xendev);
-}
-
-/* -------------------------------------------------------------------- */
-
-static void xenfb_copy_mfns(int mode, int count, xen_pfn_t *dst, void *src)
-{
- uint32_t *src32 = src;
- uint64_t *src64 = src;
- int i;
-
- for (i = 0; i < count; i++)
- dst[i] = (mode == 32) ? src32[i] : src64[i];
-}
-
-static int xenfb_map_fb(struct XenFB *xenfb)
-{
- struct xenfb_page *page = xenfb->c.page;
- char *protocol = xenfb->c.xendev.protocol;
- int n_fbdirs;
- xen_pfn_t *pgmfns = NULL;
- xen_pfn_t *fbmfns = NULL;
- void *map, *pd;
- int mode, ret = -1;
-
- /* default to native */
- pd = page->pd;
- mode = sizeof(unsigned long) * 8;
-
- if (!protocol) {
- /*
- * Undefined protocol, some guesswork needed.
- *
- * Old frontends which don't set the protocol use
- * one page directory only, thus pd[1] must be zero.
- * pd[1] of the 32bit struct layout and the lower
- * 32 bits of pd[0] of the 64bit struct layout have
- * the same location, so we can check that ...
- */
- uint32_t *ptr32 = NULL;
- uint32_t *ptr64 = NULL;
-#if defined(__i386__)
- ptr32 = (void*)page->pd;
- ptr64 = ((void*)page->pd) + 4;
-#elif defined(__x86_64__)
- ptr32 = ((void*)page->pd) - 4;
- ptr64 = (void*)page->pd;
-#endif
- if (ptr32) {
- if (ptr32[1] == 0) {
- mode = 32;
- pd = ptr32;
- } else {
- mode = 64;
- pd = ptr64;
- }
- }
-#if defined(__x86_64__)
- } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_32) == 0) {
- /* 64bit dom0, 32bit domU */
- mode = 32;
- pd = ((void*)page->pd) - 4;
-#elif defined(__i386__)
- } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_64) == 0) {
- /* 32bit dom0, 64bit domU */
- mode = 64;
- pd = ((void*)page->pd) + 4;
-#endif
- }
-
- if (xenfb->pixels) {
- munmap(xenfb->pixels, xenfb->fbpages * XC_PAGE_SIZE);
- xenfb->pixels = NULL;
- }
-
- xenfb->fbpages = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
- n_fbdirs = xenfb->fbpages * mode / 8;
- n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
-
- pgmfns = g_malloc0(sizeof(xen_pfn_t) * n_fbdirs);
- fbmfns = g_malloc0(sizeof(xen_pfn_t) * xenfb->fbpages);
-
- xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd);
- map = xenforeignmemory_map(xen_fmem, xenfb->c.xendev.dom,
- PROT_READ, n_fbdirs, pgmfns, NULL);
- if (map == NULL)
- goto out;
- xenfb_copy_mfns(mode, xenfb->fbpages, fbmfns, map);
- xenforeignmemory_unmap(xen_fmem, map, n_fbdirs);
-
- xenfb->pixels = xenforeignmemory_map(xen_fmem, xenfb->c.xendev.dom,
- PROT_READ, xenfb->fbpages, fbmfns, NULL);
- if (xenfb->pixels == NULL)
- goto out;
-
- ret = 0; /* all is fine */
-
-out:
- g_free(pgmfns);
- g_free(fbmfns);
- return ret;
-}
-
-static int xenfb_configure_fb(struct XenFB *xenfb, size_t fb_len_lim,
- int width, int height, int depth,
- size_t fb_len, int offset, int row_stride)
-{
- size_t mfn_sz = sizeof(*((struct xenfb_page *)0)->pd);
- size_t pd_len = sizeof(((struct xenfb_page *)0)->pd) / mfn_sz;
- size_t fb_pages = pd_len * XC_PAGE_SIZE / mfn_sz;
- size_t fb_len_max = fb_pages * XC_PAGE_SIZE;
- int max_width, max_height;
-
- if (fb_len_lim > fb_len_max) {
- xen_be_printf(&xenfb->c.xendev, 0, "fb size limit %zu exceeds %zu, corrected\n",
- fb_len_lim, fb_len_max);
- fb_len_lim = fb_len_max;
- }
- if (fb_len_lim && fb_len > fb_len_lim) {
- xen_be_printf(&xenfb->c.xendev, 0, "frontend fb size %zu limited to %zu\n",
- fb_len, fb_len_lim);
- fb_len = fb_len_lim;
- }
- if (depth != 8 && depth != 16 && depth != 24 && depth != 32) {
- xen_be_printf(&xenfb->c.xendev, 0, "can't handle frontend fb depth %d\n",
- depth);
- return -1;
- }
- if (row_stride <= 0 || row_stride > fb_len) {
- xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend stride %d\n", row_stride);
- return -1;
- }
- max_width = row_stride / (depth / 8);
- if (width < 0 || width > max_width) {
- xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend width %d limited to %d\n",
- width, max_width);
- width = max_width;
- }
- if (offset < 0 || offset >= fb_len) {
- xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend offset %d (max %zu)\n",
- offset, fb_len - 1);
- return -1;
- }
- max_height = (fb_len - offset) / row_stride;
- if (height < 0 || height > max_height) {
- xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend height %d limited to %d\n",
- height, max_height);
- height = max_height;
- }
- xenfb->fb_len = fb_len;
- xenfb->row_stride = row_stride;
- xenfb->depth = depth;
- xenfb->width = width;
- xenfb->height = height;
- xenfb->offset = offset;
- xenfb->up_fullscreen = 1;
- xenfb->do_resize = 1;
- xen_be_printf(&xenfb->c.xendev, 1, "framebuffer %dx%dx%d offset %d stride %d\n",
- width, height, depth, offset, row_stride);
- return 0;
-}
-
-/* A convenient function for munging pixels between different depths */
-#define BLT(SRC_T,DST_T,RSB,GSB,BSB,RDB,GDB,BDB) \
- for (line = y ; line < (y+h) ; line++) { \
- SRC_T *src = (SRC_T *)(xenfb->pixels \
- + xenfb->offset \
- + (line * xenfb->row_stride) \
- + (x * xenfb->depth / 8)); \
- DST_T *dst = (DST_T *)(data \
- + (line * linesize) \
- + (x * bpp / 8)); \
- int col; \
- const int RSS = 32 - (RSB + GSB + BSB); \
- const int GSS = 32 - (GSB + BSB); \
- const int BSS = 32 - (BSB); \
- const uint32_t RSM = (~0U) << (32 - RSB); \
- const uint32_t GSM = (~0U) << (32 - GSB); \
- const uint32_t BSM = (~0U) << (32 - BSB); \
- const int RDS = 32 - (RDB + GDB + BDB); \
- const int GDS = 32 - (GDB + BDB); \
- const int BDS = 32 - (BDB); \
- const uint32_t RDM = (~0U) << (32 - RDB); \
- const uint32_t GDM = (~0U) << (32 - GDB); \
- const uint32_t BDM = (~0U) << (32 - BDB); \
- for (col = x ; col < (x+w) ; col++) { \
- uint32_t spix = *src; \
- *dst = (((spix << RSS) & RSM & RDM) >> RDS) | \
- (((spix << GSS) & GSM & GDM) >> GDS) | \
- (((spix << BSS) & BSM & BDM) >> BDS); \
- src = (SRC_T *) ((unsigned long) src + xenfb->depth / 8); \
- dst = (DST_T *) ((unsigned long) dst + bpp / 8); \
- } \
- }
-
-
-/*
- * This copies data from the guest framebuffer region, into QEMU's
- * displaysurface. qemu uses 16 or 32 bpp. In case the pv framebuffer
- * uses something else we must convert and copy, otherwise we can
- * supply the buffer directly and no thing here.
- */
-static void xenfb_guest_copy(struct XenFB *xenfb, int x, int y, int w, int h)
-{
- DisplaySurface *surface = qemu_console_surface(xenfb->c.con);
- int line, oops = 0;
- int bpp = surface_bits_per_pixel(surface);
- int linesize = surface_stride(surface);
- uint8_t *data = surface_data(surface);
-
- if (!is_buffer_shared(surface)) {
- switch (xenfb->depth) {
- case 8:
- if (bpp == 16) {
- BLT(uint8_t, uint16_t, 3, 3, 2, 5, 6, 5);
- } else if (bpp == 32) {
- BLT(uint8_t, uint32_t, 3, 3, 2, 8, 8, 8);
- } else {
- oops = 1;
- }
- break;
- case 24:
- if (bpp == 16) {
- BLT(uint32_t, uint16_t, 8, 8, 8, 5, 6, 5);
- } else if (bpp == 32) {
- BLT(uint32_t, uint32_t, 8, 8, 8, 8, 8, 8);
- } else {
- oops = 1;
- }
- break;
- default:
- oops = 1;
- }
- }
- if (oops) /* should not happen */
- xen_be_printf(&xenfb->c.xendev, 0, "%s: oops: convert %d -> %d bpp?\n",
- __FUNCTION__, xenfb->depth, bpp);
-
- dpy_gfx_update(xenfb->c.con, x, y, w, h);
-}
-
-#ifdef XENFB_TYPE_REFRESH_PERIOD
-static int xenfb_queue_full(struct XenFB *xenfb)
-{
- struct xenfb_page *page = xenfb->c.page;
- uint32_t cons, prod;
-
- if (!page)
- return 1;
-
- prod = page->in_prod;
- cons = page->in_cons;
- return prod - cons == XENFB_IN_RING_LEN;
-}
-
-static void xenfb_send_event(struct XenFB *xenfb, union xenfb_in_event *event)
-{
- uint32_t prod;
- struct xenfb_page *page = xenfb->c.page;
-
- prod = page->in_prod;
- /* caller ensures !xenfb_queue_full() */
- xen_mb(); /* ensure ring space available */
- XENFB_IN_RING_REF(page, prod) = *event;
- xen_wmb(); /* ensure ring contents visible */
- page->in_prod = prod + 1;
-
- xen_be_send_notify(&xenfb->c.xendev);
-}
-
-static void xenfb_send_refresh_period(struct XenFB *xenfb, int period)
-{
- union xenfb_in_event event;
-
- memset(&event, 0, sizeof(event));
- event.type = XENFB_TYPE_REFRESH_PERIOD;
- event.refresh_period.period = period;
- xenfb_send_event(xenfb, &event);
-}
-#endif
-
-/*
- * Periodic update of display.
- * Also transmit the refresh interval to the frontend.
- *
- * Never ever do any qemu display operations
- * (resize, screen update) outside this function.
- * Our screen might be inactive. When asked for
- * an update we know it is active.
- */
-static void xenfb_update(void *opaque)
-{
- struct XenFB *xenfb = opaque;
- DisplaySurface *surface;
- int i;
-
- if (xenfb->c.xendev.be_state != XenbusStateConnected)
- return;
-
- if (!xenfb->feature_update) {
- /* we don't get update notifications, thus use the
- * sledge hammer approach ... */
- xenfb->up_fullscreen = 1;
- }
-
- /* resize if needed */
- if (xenfb->do_resize) {
- pixman_format_code_t format;
-
- xenfb->do_resize = 0;
- switch (xenfb->depth) {
- case 16:
- case 32:
- /* console.c supported depth -> buffer can be used directly */
- format = qemu_default_pixman_format(xenfb->depth, true);
- surface = qemu_create_displaysurface_from
- (xenfb->width, xenfb->height, format,
- xenfb->row_stride, xenfb->pixels + xenfb->offset);
- break;
- default:
- /* we must convert stuff */
- surface = qemu_create_displaysurface(xenfb->width, xenfb->height);
- break;
- }
- dpy_gfx_replace_surface(xenfb->c.con, surface);
- xen_be_printf(&xenfb->c.xendev, 1, "update: resizing: %dx%d @ %d bpp%s\n",
- xenfb->width, xenfb->height, xenfb->depth,
- is_buffer_shared(surface) ? " (shared)" : "");
- xenfb->up_fullscreen = 1;
- }
-
- /* run queued updates */
- if (xenfb->up_fullscreen) {
- xen_be_printf(&xenfb->c.xendev, 3, "update: fullscreen\n");
- xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height);
- } else if (xenfb->up_count) {
- xen_be_printf(&xenfb->c.xendev, 3, "update: %d rects\n", xenfb->up_count);
- for (i = 0; i < xenfb->up_count; i++)
- xenfb_guest_copy(xenfb,
- xenfb->up_rects[i].x,
- xenfb->up_rects[i].y,
- xenfb->up_rects[i].w,
- xenfb->up_rects[i].h);
- } else {
- xen_be_printf(&xenfb->c.xendev, 3, "update: nothing\n");
- }
- xenfb->up_count = 0;
- xenfb->up_fullscreen = 0;
-}
-
-static void xenfb_update_interval(void *opaque, uint64_t interval)
-{
- struct XenFB *xenfb = opaque;
-
- if (xenfb->feature_update) {
-#ifdef XENFB_TYPE_REFRESH_PERIOD
- if (xenfb_queue_full(xenfb)) {
- return;
- }
- xenfb_send_refresh_period(xenfb, interval);
-#endif
- }
-}
-
-/* QEMU display state changed, so refresh the framebuffer copy */
-static void xenfb_invalidate(void *opaque)
-{
- struct XenFB *xenfb = opaque;
- xenfb->up_fullscreen = 1;
-}
-
-static void xenfb_handle_events(struct XenFB *xenfb)
-{
- uint32_t prod, cons, out_cons;
- struct xenfb_page *page = xenfb->c.page;
-
- prod = page->out_prod;
- out_cons = page->out_cons;
- if (prod - out_cons > XENFB_OUT_RING_LEN) {
- return;
- }
- xen_rmb(); /* ensure we see ring contents up to prod */
- for (cons = out_cons; cons != prod; cons++) {
- union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons);
- uint8_t type = event->type;
- int x, y, w, h;
-
- switch (type) {
- case XENFB_TYPE_UPDATE:
- if (xenfb->up_count == UP_QUEUE)
- xenfb->up_fullscreen = 1;
- if (xenfb->up_fullscreen)
- break;
- x = MAX(event->update.x, 0);
- y = MAX(event->update.y, 0);
- w = MIN(event->update.width, xenfb->width - x);
- h = MIN(event->update.height, xenfb->height - y);
- if (w < 0 || h < 0) {
- xen_be_printf(&xenfb->c.xendev, 1, "bogus update ignored\n");
- break;
- }
- if (x != event->update.x ||
- y != event->update.y ||
- w != event->update.width ||
- h != event->update.height) {
- xen_be_printf(&xenfb->c.xendev, 1, "bogus update clipped\n");
- }
- if (w == xenfb->width && h > xenfb->height / 2) {
- /* scroll detector: updated more than 50% of the lines,
- * don't bother keeping track of the rectangles then */
- xenfb->up_fullscreen = 1;
- } else {
- xenfb->up_rects[xenfb->up_count].x = x;
- xenfb->up_rects[xenfb->up_count].y = y;
- xenfb->up_rects[xenfb->up_count].w = w;
- xenfb->up_rects[xenfb->up_count].h = h;
- xenfb->up_count++;
- }
- break;
-#ifdef XENFB_TYPE_RESIZE
- case XENFB_TYPE_RESIZE:
- if (xenfb_configure_fb(xenfb, xenfb->fb_len,
- event->resize.width,
- event->resize.height,
- event->resize.depth,
- xenfb->fb_len,
- event->resize.offset,
- event->resize.stride) < 0)
- break;
- xenfb_invalidate(xenfb);
- break;
-#endif
- }
- }
- xen_mb(); /* ensure we're done with ring contents */
- page->out_cons = cons;
-}
-
-static int fb_init(struct XenDevice *xendev)
-{
-#ifdef XENFB_TYPE_RESIZE
- xenstore_write_be_int(xendev, "feature-resize", 1);
-#endif
- return 0;
-}
-
-static int fb_initialise(struct XenDevice *xendev)
-{
- struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
- struct xenfb_page *fb_page;
- int videoram;
- int rc;
-
- if (xenstore_read_fe_int(xendev, "videoram", &videoram) == -1)
- videoram = 0;
-
- rc = common_bind(&fb->c);
- if (rc != 0)
- return rc;
-
- fb_page = fb->c.page;
- rc = xenfb_configure_fb(fb, videoram * 1024 * 1024U,
- fb_page->width, fb_page->height, fb_page->depth,
- fb_page->mem_length, 0, fb_page->line_length);
- if (rc != 0)
- return rc;
-
- rc = xenfb_map_fb(fb);
- if (rc != 0)
- return rc;
-
-#if 0 /* handled in xen_init_display() for now */
- if (!fb->have_console) {
- fb->c.ds = graphic_console_init(xenfb_update,
- xenfb_invalidate,
- NULL,
- NULL,
- fb);
- fb->have_console = 1;
- }
-#endif
-
- if (xenstore_read_fe_int(xendev, "feature-update", &fb->feature_update) == -1)
- fb->feature_update = 0;
- if (fb->feature_update)
- xenstore_write_be_int(xendev, "request-update", 1);
-
- xen_be_printf(xendev, 1, "feature-update=%d, videoram=%d\n",
- fb->feature_update, videoram);
- return 0;
-}
-
-static void fb_disconnect(struct XenDevice *xendev)
-{
- struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
-
- /*
- * FIXME: qemu can't un-init gfx display (yet?).
- * Replacing the framebuffer with anonymous shared memory
- * instead. This releases the guest pages and keeps qemu happy.
- */
- xenforeignmemory_unmap(xen_fmem, fb->pixels, fb->fbpages);
- fb->pixels = mmap(fb->pixels, fb->fbpages * XC_PAGE_SIZE,
- PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON,
- -1, 0);
- if (fb->pixels == MAP_FAILED) {
- xen_be_printf(xendev, 0,
- "Couldn't replace the framebuffer with anonymous memory errno=%d\n",
- errno);
- }
- common_unbind(&fb->c);
- fb->feature_update = 0;
- fb->bug_trigger = 0;
-}
-
-static void fb_frontend_changed(struct XenDevice *xendev, const char *node)
-{
- struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
-
- /*
- * Set state to Connected *again* once the frontend switched
- * to connected. We must trigger the watch a second time to
- * workaround a frontend bug.
- */
- if (fb->bug_trigger == 0 && strcmp(node, "state") == 0 &&
- xendev->fe_state == XenbusStateConnected &&
- xendev->be_state == XenbusStateConnected) {
- xen_be_printf(xendev, 2, "re-trigger connected (frontend bug)\n");
- xen_be_set_state(xendev, XenbusStateConnected);
- fb->bug_trigger = 1; /* only once */
- }
-}
-
-static void fb_event(struct XenDevice *xendev)
-{
- struct XenFB *xenfb = container_of(xendev, struct XenFB, c.xendev);
-
- xenfb_handle_events(xenfb);
- xen_be_send_notify(&xenfb->c.xendev);
-}
-
-/* -------------------------------------------------------------------- */
-
-struct XenDevOps xen_kbdmouse_ops = {
- .size = sizeof(struct XenInput),
- .init = input_init,
- .initialise = input_initialise,
- .connected = input_connected,
- .disconnect = input_disconnect,
- .event = input_event,
-};
-
-struct XenDevOps xen_framebuffer_ops = {
- .size = sizeof(struct XenFB),
- .init = fb_init,
- .initialise = fb_initialise,
- .disconnect = fb_disconnect,
- .event = fb_event,
- .frontend_changed = fb_frontend_changed,
-};
-
-static const GraphicHwOps xenfb_ops = {
- .invalidate = xenfb_invalidate,
- .gfx_update = xenfb_update,
- .update_interval = xenfb_update_interval,
-};
-
-/*
- * FIXME/TODO: Kill this.
- * Temporary needed while DisplayState reorganization is in flight.
- */
-void xen_init_display(int domid)
-{
- struct XenDevice *xfb, *xin;
- struct XenFB *fb;
- struct XenInput *in;
- int i = 0;
-
-wait_more:
- i++;
- main_loop_wait(true);
- xfb = xen_be_find_xendev("vfb", domid, 0);
- xin = xen_be_find_xendev("vkbd", domid, 0);
- if (!xfb || !xin) {
- if (i < 256) {
- usleep(10000);
- goto wait_more;
- }
- xen_be_printf(NULL, 1, "displaystate setup failed\n");
- return;
- }
-
- /* vfb */
- fb = container_of(xfb, struct XenFB, c.xendev);
- fb->c.con = graphic_console_init(NULL, 0, &xenfb_ops, fb);
- fb->have_console = 1;
-
- /* vkbd */
- in = container_of(xin, struct XenInput, c.xendev);
- in->c.con = fb->c.con;
-
- /* retry ->init() */
- xen_be_check_state(xin);
- xen_be_check_state(xfb);
-}
diff --git a/qemu/hw/dma/Makefile.objs b/qemu/hw/dma/Makefile.objs
deleted file mode 100644
index a1abbcf74..000000000
--- a/qemu/hw/dma/Makefile.objs
+++ /dev/null
@@ -1,14 +0,0 @@
-common-obj-$(CONFIG_PUV3) += puv3_dma.o
-common-obj-$(CONFIG_RC4030) += rc4030.o
-common-obj-$(CONFIG_PL080) += pl080.o
-common-obj-$(CONFIG_PL330) += pl330.o
-common-obj-$(CONFIG_I82374) += i82374.o
-common-obj-$(CONFIG_I8257) += i8257.o
-common-obj-$(CONFIG_XILINX_AXI) += xilinx_axidma.o
-common-obj-$(CONFIG_ETRAXFS) += etraxfs_dma.o
-common-obj-$(CONFIG_STP2000) += sparc32_dma.o
-common-obj-$(CONFIG_SUN4M) += sun4m_iommu.o
-
-obj-$(CONFIG_OMAP) += omap_dma.o soc_dma.o
-obj-$(CONFIG_PXA2XX) += pxa2xx_dma.o
-obj-$(CONFIG_RASPI) += bcm2835_dma.o
diff --git a/qemu/hw/dma/bcm2835_dma.c b/qemu/hw/dma/bcm2835_dma.c
deleted file mode 100644
index 542117599..000000000
--- a/qemu/hw/dma/bcm2835_dma.c
+++ /dev/null
@@ -1,409 +0,0 @@
-/*
- * Raspberry Pi emulation (c) 2012 Gregory Estrade
- * This code is licensed under the GNU GPLv2 and later.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/dma/bcm2835_dma.h"
-
-/* DMA CS Control and Status bits */
-#define BCM2708_DMA_ACTIVE (1 << 0)
-#define BCM2708_DMA_END (1 << 1) /* GE */
-#define BCM2708_DMA_INT (1 << 2)
-#define BCM2708_DMA_ISPAUSED (1 << 4) /* Pause requested or not active */
-#define BCM2708_DMA_ISHELD (1 << 5) /* Is held by DREQ flow control */
-#define BCM2708_DMA_ERR (1 << 8)
-#define BCM2708_DMA_ABORT (1 << 30) /* stop current CB, go to next, WO */
-#define BCM2708_DMA_RESET (1 << 31) /* WO, self clearing */
-
-/* DMA control block "info" field bits */
-#define BCM2708_DMA_INT_EN (1 << 0)
-#define BCM2708_DMA_TDMODE (1 << 1)
-#define BCM2708_DMA_WAIT_RESP (1 << 3)
-#define BCM2708_DMA_D_INC (1 << 4)
-#define BCM2708_DMA_D_WIDTH (1 << 5)
-#define BCM2708_DMA_D_DREQ (1 << 6)
-#define BCM2708_DMA_D_IGNORE (1 << 7)
-#define BCM2708_DMA_S_INC (1 << 8)
-#define BCM2708_DMA_S_WIDTH (1 << 9)
-#define BCM2708_DMA_S_DREQ (1 << 10)
-#define BCM2708_DMA_S_IGNORE (1 << 11)
-
-/* Register offsets */
-#define BCM2708_DMA_CS 0x00 /* Control and Status */
-#define BCM2708_DMA_ADDR 0x04 /* Control block address */
-/* the current control block appears in the following registers - read only */
-#define BCM2708_DMA_INFO 0x08
-#define BCM2708_DMA_SOURCE_AD 0x0c
-#define BCM2708_DMA_DEST_AD 0x10
-#define BCM2708_DMA_TXFR_LEN 0x14
-#define BCM2708_DMA_STRIDE 0x18
-#define BCM2708_DMA_NEXTCB 0x1C
-#define BCM2708_DMA_DEBUG 0x20
-
-#define BCM2708_DMA_INT_STATUS 0xfe0 /* Interrupt status of each channel */
-#define BCM2708_DMA_ENABLE 0xff0 /* Global enable bits for each channel */
-
-#define BCM2708_DMA_CS_RW_MASK 0x30ff0001 /* All RW bits in DMA_CS */
-
-static void bcm2835_dma_update(BCM2835DMAState *s, unsigned c)
-{
- BCM2835DMAChan *ch = &s->chan[c];
- uint32_t data, xlen, ylen;
- int16_t dst_stride, src_stride;
-
- if (!(s->enable & (1 << c))) {
- return;
- }
-
- while ((s->enable & (1 << c)) && (ch->conblk_ad != 0)) {
- /* CB fetch */
- ch->ti = ldl_le_phys(&s->dma_as, ch->conblk_ad);
- ch->source_ad = ldl_le_phys(&s->dma_as, ch->conblk_ad + 4);
- ch->dest_ad = ldl_le_phys(&s->dma_as, ch->conblk_ad + 8);
- ch->txfr_len = ldl_le_phys(&s->dma_as, ch->conblk_ad + 12);
- ch->stride = ldl_le_phys(&s->dma_as, ch->conblk_ad + 16);
- ch->nextconbk = ldl_le_phys(&s->dma_as, ch->conblk_ad + 20);
-
- if (ch->ti & BCM2708_DMA_TDMODE) {
- /* 2D transfer mode */
- ylen = (ch->txfr_len >> 16) & 0x3fff;
- xlen = ch->txfr_len & 0xffff;
- dst_stride = ch->stride >> 16;
- src_stride = ch->stride & 0xffff;
- } else {
- ylen = 1;
- xlen = ch->txfr_len;
- dst_stride = 0;
- src_stride = 0;
- }
-
- while (ylen != 0) {
- /* Normal transfer mode */
- while (xlen != 0) {
- if (ch->ti & BCM2708_DMA_S_IGNORE) {
- /* Ignore reads */
- data = 0;
- } else {
- data = ldl_le_phys(&s->dma_as, ch->source_ad);
- }
- if (ch->ti & BCM2708_DMA_S_INC) {
- ch->source_ad += 4;
- }
-
- if (ch->ti & BCM2708_DMA_D_IGNORE) {
- /* Ignore writes */
- } else {
- stl_le_phys(&s->dma_as, ch->dest_ad, data);
- }
- if (ch->ti & BCM2708_DMA_D_INC) {
- ch->dest_ad += 4;
- }
-
- /* update remaining transfer length */
- xlen -= 4;
- if (ch->ti & BCM2708_DMA_TDMODE) {
- ch->txfr_len = (ylen << 16) | xlen;
- } else {
- ch->txfr_len = xlen;
- }
- }
-
- if (--ylen != 0) {
- ch->source_ad += src_stride;
- ch->dest_ad += dst_stride;
- }
- }
- ch->cs |= BCM2708_DMA_END;
- if (ch->ti & BCM2708_DMA_INT_EN) {
- ch->cs |= BCM2708_DMA_INT;
- s->int_status |= (1 << c);
- qemu_set_irq(ch->irq, 1);
- }
-
- /* Process next CB */
- ch->conblk_ad = ch->nextconbk;
- }
-
- ch->cs &= ~BCM2708_DMA_ACTIVE;
- ch->cs |= BCM2708_DMA_ISPAUSED;
-}
-
-static void bcm2835_dma_chan_reset(BCM2835DMAChan *ch)
-{
- ch->cs = 0;
- ch->conblk_ad = 0;
-}
-
-static uint64_t bcm2835_dma_read(BCM2835DMAState *s, hwaddr offset,
- unsigned size, unsigned c)
-{
- BCM2835DMAChan *ch;
- uint32_t res = 0;
-
- assert(size == 4);
- assert(c < BCM2835_DMA_NCHANS);
-
- ch = &s->chan[c];
-
- switch (offset) {
- case BCM2708_DMA_CS:
- res = ch->cs;
- break;
- case BCM2708_DMA_ADDR:
- res = ch->conblk_ad;
- break;
- case BCM2708_DMA_INFO:
- res = ch->ti;
- break;
- case BCM2708_DMA_SOURCE_AD:
- res = ch->source_ad;
- break;
- case BCM2708_DMA_DEST_AD:
- res = ch->dest_ad;
- break;
- case BCM2708_DMA_TXFR_LEN:
- res = ch->txfr_len;
- break;
- case BCM2708_DMA_STRIDE:
- res = ch->stride;
- break;
- case BCM2708_DMA_NEXTCB:
- res = ch->nextconbk;
- break;
- case BCM2708_DMA_DEBUG:
- res = ch->debug;
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
- __func__, offset);
- break;
- }
- return res;
-}
-
-static void bcm2835_dma_write(BCM2835DMAState *s, hwaddr offset,
- uint64_t value, unsigned size, unsigned c)
-{
- BCM2835DMAChan *ch;
- uint32_t oldcs;
-
- assert(size == 4);
- assert(c < BCM2835_DMA_NCHANS);
-
- ch = &s->chan[c];
-
- switch (offset) {
- case BCM2708_DMA_CS:
- oldcs = ch->cs;
- if (value & BCM2708_DMA_RESET) {
- bcm2835_dma_chan_reset(ch);
- }
- if (value & BCM2708_DMA_ABORT) {
- /* abort is a no-op, since we always run to completion */
- }
- if (value & BCM2708_DMA_END) {
- ch->cs &= ~BCM2708_DMA_END;
- }
- if (value & BCM2708_DMA_INT) {
- ch->cs &= ~BCM2708_DMA_INT;
- s->int_status &= ~(1 << c);
- qemu_set_irq(ch->irq, 0);
- }
- ch->cs &= ~BCM2708_DMA_CS_RW_MASK;
- ch->cs |= (value & BCM2708_DMA_CS_RW_MASK);
- if (!(oldcs & BCM2708_DMA_ACTIVE) && (ch->cs & BCM2708_DMA_ACTIVE)) {
- bcm2835_dma_update(s, c);
- }
- break;
- case BCM2708_DMA_ADDR:
- ch->conblk_ad = value;
- break;
- case BCM2708_DMA_DEBUG:
- ch->debug = value;
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
- __func__, offset);
- break;
- }
-}
-
-static uint64_t bcm2835_dma0_read(void *opaque, hwaddr offset, unsigned size)
-{
- BCM2835DMAState *s = opaque;
-
- if (offset < 0xf00) {
- return bcm2835_dma_read(s, (offset & 0xff), size, (offset >> 8) & 0xf);
- } else {
- switch (offset) {
- case BCM2708_DMA_INT_STATUS:
- return s->int_status;
- case BCM2708_DMA_ENABLE:
- return s->enable;
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
- __func__, offset);
- return 0;
- }
- }
-}
-
-static uint64_t bcm2835_dma15_read(void *opaque, hwaddr offset, unsigned size)
-{
- return bcm2835_dma_read(opaque, (offset & 0xff), size, 15);
-}
-
-static void bcm2835_dma0_write(void *opaque, hwaddr offset, uint64_t value,
- unsigned size)
-{
- BCM2835DMAState *s = opaque;
-
- if (offset < 0xf00) {
- bcm2835_dma_write(s, (offset & 0xff), value, size, (offset >> 8) & 0xf);
- } else {
- switch (offset) {
- case BCM2708_DMA_INT_STATUS:
- break;
- case BCM2708_DMA_ENABLE:
- s->enable = (value & 0xffff);
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
- __func__, offset);
- }
- }
-
-}
-
-static void bcm2835_dma15_write(void *opaque, hwaddr offset, uint64_t value,
- unsigned size)
-{
- bcm2835_dma_write(opaque, (offset & 0xff), value, size, 15);
-}
-
-static const MemoryRegionOps bcm2835_dma0_ops = {
- .read = bcm2835_dma0_read,
- .write = bcm2835_dma0_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid.min_access_size = 4,
- .valid.max_access_size = 4,
-};
-
-static const MemoryRegionOps bcm2835_dma15_ops = {
- .read = bcm2835_dma15_read,
- .write = bcm2835_dma15_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid.min_access_size = 4,
- .valid.max_access_size = 4,
-};
-
-static const VMStateDescription vmstate_bcm2835_dma_chan = {
- .name = TYPE_BCM2835_DMA "-chan",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(cs, BCM2835DMAChan),
- VMSTATE_UINT32(conblk_ad, BCM2835DMAChan),
- VMSTATE_UINT32(ti, BCM2835DMAChan),
- VMSTATE_UINT32(source_ad, BCM2835DMAChan),
- VMSTATE_UINT32(dest_ad, BCM2835DMAChan),
- VMSTATE_UINT32(txfr_len, BCM2835DMAChan),
- VMSTATE_UINT32(stride, BCM2835DMAChan),
- VMSTATE_UINT32(nextconbk, BCM2835DMAChan),
- VMSTATE_UINT32(debug, BCM2835DMAChan),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_bcm2835_dma = {
- .name = TYPE_BCM2835_DMA,
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT_ARRAY(chan, BCM2835DMAState, BCM2835_DMA_NCHANS, 1,
- vmstate_bcm2835_dma_chan, BCM2835DMAChan),
- VMSTATE_UINT32(int_status, BCM2835DMAState),
- VMSTATE_UINT32(enable, BCM2835DMAState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void bcm2835_dma_init(Object *obj)
-{
- BCM2835DMAState *s = BCM2835_DMA(obj);
- int n;
-
- /* DMA channels 0-14 occupy a contiguous block of IO memory, along
- * with the global enable and interrupt status bits. Channel 15
- * has the same register map, but is mapped at a discontiguous
- * address in a separate IO block.
- */
- memory_region_init_io(&s->iomem0, OBJECT(s), &bcm2835_dma0_ops, s,
- TYPE_BCM2835_DMA, 0x1000);
- sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem0);
-
- memory_region_init_io(&s->iomem15, OBJECT(s), &bcm2835_dma15_ops, s,
- TYPE_BCM2835_DMA "-chan15", 0x100);
- sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem15);
-
- for (n = 0; n < 16; n++) {
- sysbus_init_irq(SYS_BUS_DEVICE(s), &s->chan[n].irq);
- }
-}
-
-static void bcm2835_dma_reset(DeviceState *dev)
-{
- BCM2835DMAState *s = BCM2835_DMA(dev);
- int n;
-
- s->enable = 0xffff;
- s->int_status = 0;
- for (n = 0; n < BCM2835_DMA_NCHANS; n++) {
- bcm2835_dma_chan_reset(&s->chan[n]);
- }
-}
-
-static void bcm2835_dma_realize(DeviceState *dev, Error **errp)
-{
- BCM2835DMAState *s = BCM2835_DMA(dev);
- Error *err = NULL;
- Object *obj;
-
- obj = object_property_get_link(OBJECT(dev), "dma-mr", &err);
- if (obj == NULL) {
- error_setg(errp, "%s: required dma-mr link not found: %s",
- __func__, error_get_pretty(err));
- return;
- }
-
- s->dma_mr = MEMORY_REGION(obj);
- address_space_init(&s->dma_as, s->dma_mr, NULL);
-
- bcm2835_dma_reset(dev);
-}
-
-static void bcm2835_dma_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = bcm2835_dma_realize;
- dc->reset = bcm2835_dma_reset;
- dc->vmsd = &vmstate_bcm2835_dma;
-}
-
-static TypeInfo bcm2835_dma_info = {
- .name = TYPE_BCM2835_DMA,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(BCM2835DMAState),
- .class_init = bcm2835_dma_class_init,
- .instance_init = bcm2835_dma_init,
-};
-
-static void bcm2835_dma_register_types(void)
-{
- type_register_static(&bcm2835_dma_info);
-}
-
-type_init(bcm2835_dma_register_types)
diff --git a/qemu/hw/dma/etraxfs_dma.c b/qemu/hw/dma/etraxfs_dma.c
deleted file mode 100644
index d5650eb88..000000000
--- a/qemu/hw/dma/etraxfs_dma.c
+++ /dev/null
@@ -1,783 +0,0 @@
-/*
- * QEMU ETRAX DMA Controller.
- *
- * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "exec/address-spaces.h"
-#include "qemu-common.h"
-#include "sysemu/sysemu.h"
-
-#include "hw/cris/etraxfs_dma.h"
-
-#define D(x)
-
-#define RW_DATA (0x0 / 4)
-#define RW_SAVED_DATA (0x58 / 4)
-#define RW_SAVED_DATA_BUF (0x5c / 4)
-#define RW_GROUP (0x60 / 4)
-#define RW_GROUP_DOWN (0x7c / 4)
-#define RW_CMD (0x80 / 4)
-#define RW_CFG (0x84 / 4)
-#define RW_STAT (0x88 / 4)
-#define RW_INTR_MASK (0x8c / 4)
-#define RW_ACK_INTR (0x90 / 4)
-#define R_INTR (0x94 / 4)
-#define R_MASKED_INTR (0x98 / 4)
-#define RW_STREAM_CMD (0x9c / 4)
-
-#define DMA_REG_MAX (0x100 / 4)
-
-/* descriptors */
-
-// ------------------------------------------------------------ dma_descr_group
-typedef struct dma_descr_group {
- uint32_t next;
- unsigned eol : 1;
- unsigned tol : 1;
- unsigned bol : 1;
- unsigned : 1;
- unsigned intr : 1;
- unsigned : 2;
- unsigned en : 1;
- unsigned : 7;
- unsigned dis : 1;
- unsigned md : 16;
- struct dma_descr_group *up;
- union {
- struct dma_descr_context *context;
- struct dma_descr_group *group;
- } down;
-} dma_descr_group;
-
-// ---------------------------------------------------------- dma_descr_context
-typedef struct dma_descr_context {
- uint32_t next;
- unsigned eol : 1;
- unsigned : 3;
- unsigned intr : 1;
- unsigned : 1;
- unsigned store_mode : 1;
- unsigned en : 1;
- unsigned : 7;
- unsigned dis : 1;
- unsigned md0 : 16;
- unsigned md1;
- unsigned md2;
- unsigned md3;
- unsigned md4;
- uint32_t saved_data;
- uint32_t saved_data_buf;
-} dma_descr_context;
-
-// ------------------------------------------------------------- dma_descr_data
-typedef struct dma_descr_data {
- uint32_t next;
- uint32_t buf;
- unsigned eol : 1;
- unsigned : 2;
- unsigned out_eop : 1;
- unsigned intr : 1;
- unsigned wait : 1;
- unsigned : 2;
- unsigned : 3;
- unsigned in_eop : 1;
- unsigned : 4;
- unsigned md : 16;
- uint32_t after;
-} dma_descr_data;
-
-/* Constants */
-enum {
- regk_dma_ack_pkt = 0x00000100,
- regk_dma_anytime = 0x00000001,
- regk_dma_array = 0x00000008,
- regk_dma_burst = 0x00000020,
- regk_dma_client = 0x00000002,
- regk_dma_copy_next = 0x00000010,
- regk_dma_copy_up = 0x00000020,
- regk_dma_data_at_eol = 0x00000001,
- regk_dma_dis_c = 0x00000010,
- regk_dma_dis_g = 0x00000020,
- regk_dma_idle = 0x00000001,
- regk_dma_intern = 0x00000004,
- regk_dma_load_c = 0x00000200,
- regk_dma_load_c_n = 0x00000280,
- regk_dma_load_c_next = 0x00000240,
- regk_dma_load_d = 0x00000140,
- regk_dma_load_g = 0x00000300,
- regk_dma_load_g_down = 0x000003c0,
- regk_dma_load_g_next = 0x00000340,
- regk_dma_load_g_up = 0x00000380,
- regk_dma_next_en = 0x00000010,
- regk_dma_next_pkt = 0x00000010,
- regk_dma_no = 0x00000000,
- regk_dma_only_at_wait = 0x00000000,
- regk_dma_restore = 0x00000020,
- regk_dma_rst = 0x00000001,
- regk_dma_running = 0x00000004,
- regk_dma_rw_cfg_default = 0x00000000,
- regk_dma_rw_cmd_default = 0x00000000,
- regk_dma_rw_intr_mask_default = 0x00000000,
- regk_dma_rw_stat_default = 0x00000101,
- regk_dma_rw_stream_cmd_default = 0x00000000,
- regk_dma_save_down = 0x00000020,
- regk_dma_save_up = 0x00000020,
- regk_dma_set_reg = 0x00000050,
- regk_dma_set_w_size1 = 0x00000190,
- regk_dma_set_w_size2 = 0x000001a0,
- regk_dma_set_w_size4 = 0x000001c0,
- regk_dma_stopped = 0x00000002,
- regk_dma_store_c = 0x00000002,
- regk_dma_store_descr = 0x00000000,
- regk_dma_store_g = 0x00000004,
- regk_dma_store_md = 0x00000001,
- regk_dma_sw = 0x00000008,
- regk_dma_update_down = 0x00000020,
- regk_dma_yes = 0x00000001
-};
-
-enum dma_ch_state
-{
- RST = 1,
- STOPPED = 2,
- RUNNING = 4
-};
-
-struct fs_dma_channel
-{
- qemu_irq irq;
- struct etraxfs_dma_client *client;
-
- /* Internal status. */
- int stream_cmd_src;
- enum dma_ch_state state;
-
- unsigned int input : 1;
- unsigned int eol : 1;
-
- struct dma_descr_group current_g;
- struct dma_descr_context current_c;
- struct dma_descr_data current_d;
-
- /* Control registers. */
- uint32_t regs[DMA_REG_MAX];
-};
-
-struct fs_dma_ctrl
-{
- MemoryRegion mmio;
- int nr_channels;
- struct fs_dma_channel *channels;
-
- QEMUBH *bh;
-};
-
-static void DMA_run(void *opaque);
-static int channel_out_run(struct fs_dma_ctrl *ctrl, int c);
-
-static inline uint32_t channel_reg(struct fs_dma_ctrl *ctrl, int c, int reg)
-{
- return ctrl->channels[c].regs[reg];
-}
-
-static inline int channel_stopped(struct fs_dma_ctrl *ctrl, int c)
-{
- return channel_reg(ctrl, c, RW_CFG) & 2;
-}
-
-static inline int channel_en(struct fs_dma_ctrl *ctrl, int c)
-{
- return (channel_reg(ctrl, c, RW_CFG) & 1)
- && ctrl->channels[c].client;
-}
-
-static inline int fs_channel(hwaddr addr)
-{
- /* Every channel has a 0x2000 ctrl register map. */
- return addr >> 13;
-}
-
-#ifdef USE_THIS_DEAD_CODE
-static void channel_load_g(struct fs_dma_ctrl *ctrl, int c)
-{
- hwaddr addr = channel_reg(ctrl, c, RW_GROUP);
-
- /* Load and decode. FIXME: handle endianness. */
- cpu_physical_memory_read (addr,
- (void *) &ctrl->channels[c].current_g,
- sizeof ctrl->channels[c].current_g);
-}
-
-static void dump_c(int ch, struct dma_descr_context *c)
-{
- printf("%s ch=%d\n", __func__, ch);
- printf("next=%x\n", c->next);
- printf("saved_data=%x\n", c->saved_data);
- printf("saved_data_buf=%x\n", c->saved_data_buf);
- printf("eol=%x\n", (uint32_t) c->eol);
-}
-
-static void dump_d(int ch, struct dma_descr_data *d)
-{
- printf("%s ch=%d\n", __func__, ch);
- printf("next=%x\n", d->next);
- printf("buf=%x\n", d->buf);
- printf("after=%x\n", d->after);
- printf("intr=%x\n", (uint32_t) d->intr);
- printf("out_eop=%x\n", (uint32_t) d->out_eop);
- printf("in_eop=%x\n", (uint32_t) d->in_eop);
- printf("eol=%x\n", (uint32_t) d->eol);
-}
-#endif
-
-static void channel_load_c(struct fs_dma_ctrl *ctrl, int c)
-{
- hwaddr addr = channel_reg(ctrl, c, RW_GROUP_DOWN);
-
- /* Load and decode. FIXME: handle endianness. */
- cpu_physical_memory_read (addr,
- (void *) &ctrl->channels[c].current_c,
- sizeof ctrl->channels[c].current_c);
-
- D(dump_c(c, &ctrl->channels[c].current_c));
- /* I guess this should update the current pos. */
- ctrl->channels[c].regs[RW_SAVED_DATA] =
- (uint32_t)(unsigned long)ctrl->channels[c].current_c.saved_data;
- ctrl->channels[c].regs[RW_SAVED_DATA_BUF] =
- (uint32_t)(unsigned long)ctrl->channels[c].current_c.saved_data_buf;
-}
-
-static void channel_load_d(struct fs_dma_ctrl *ctrl, int c)
-{
- hwaddr addr = channel_reg(ctrl, c, RW_SAVED_DATA);
-
- /* Load and decode. FIXME: handle endianness. */
- D(printf("%s ch=%d addr=" TARGET_FMT_plx "\n", __func__, c, addr));
- cpu_physical_memory_read (addr,
- (void *) &ctrl->channels[c].current_d,
- sizeof ctrl->channels[c].current_d);
-
- D(dump_d(c, &ctrl->channels[c].current_d));
- ctrl->channels[c].regs[RW_DATA] = addr;
-}
-
-static void channel_store_c(struct fs_dma_ctrl *ctrl, int c)
-{
- hwaddr addr = channel_reg(ctrl, c, RW_GROUP_DOWN);
-
- /* Encode and store. FIXME: handle endianness. */
- D(printf("%s ch=%d addr=" TARGET_FMT_plx "\n", __func__, c, addr));
- D(dump_d(c, &ctrl->channels[c].current_d));
- cpu_physical_memory_write (addr,
- (void *) &ctrl->channels[c].current_c,
- sizeof ctrl->channels[c].current_c);
-}
-
-static void channel_store_d(struct fs_dma_ctrl *ctrl, int c)
-{
- hwaddr addr = channel_reg(ctrl, c, RW_SAVED_DATA);
-
- /* Encode and store. FIXME: handle endianness. */
- D(printf("%s ch=%d addr=" TARGET_FMT_plx "\n", __func__, c, addr));
- cpu_physical_memory_write (addr,
- (void *) &ctrl->channels[c].current_d,
- sizeof ctrl->channels[c].current_d);
-}
-
-static inline void channel_stop(struct fs_dma_ctrl *ctrl, int c)
-{
- /* FIXME: */
-}
-
-static inline void channel_start(struct fs_dma_ctrl *ctrl, int c)
-{
- if (ctrl->channels[c].client)
- {
- ctrl->channels[c].eol = 0;
- ctrl->channels[c].state = RUNNING;
- if (!ctrl->channels[c].input)
- channel_out_run(ctrl, c);
- } else
- printf("WARNING: starting DMA ch %d with no client\n", c);
-
- qemu_bh_schedule_idle(ctrl->bh);
-}
-
-static void channel_continue(struct fs_dma_ctrl *ctrl, int c)
-{
- if (!channel_en(ctrl, c)
- || channel_stopped(ctrl, c)
- || ctrl->channels[c].state != RUNNING
- /* Only reload the current data descriptor if it has eol set. */
- || !ctrl->channels[c].current_d.eol) {
- D(printf("continue failed ch=%d state=%d stopped=%d en=%d eol=%d\n",
- c, ctrl->channels[c].state,
- channel_stopped(ctrl, c),
- channel_en(ctrl,c),
- ctrl->channels[c].eol));
- D(dump_d(c, &ctrl->channels[c].current_d));
- return;
- }
-
- /* Reload the current descriptor. */
- channel_load_d(ctrl, c);
-
- /* If the current descriptor cleared the eol flag and we had already
- reached eol state, do the continue. */
- if (!ctrl->channels[c].current_d.eol && ctrl->channels[c].eol) {
- D(printf("continue %d ok %x\n", c,
- ctrl->channels[c].current_d.next));
- ctrl->channels[c].regs[RW_SAVED_DATA] =
- (uint32_t)(unsigned long)ctrl->channels[c].current_d.next;
- channel_load_d(ctrl, c);
- ctrl->channels[c].regs[RW_SAVED_DATA_BUF] =
- (uint32_t)(unsigned long)ctrl->channels[c].current_d.buf;
-
- channel_start(ctrl, c);
- }
- ctrl->channels[c].regs[RW_SAVED_DATA_BUF] =
- (uint32_t)(unsigned long)ctrl->channels[c].current_d.buf;
-}
-
-static void channel_stream_cmd(struct fs_dma_ctrl *ctrl, int c, uint32_t v)
-{
- unsigned int cmd = v & ((1 << 10) - 1);
-
- D(printf("%s ch=%d cmd=%x\n",
- __func__, c, cmd));
- if (cmd & regk_dma_load_d) {
- channel_load_d(ctrl, c);
- if (cmd & regk_dma_burst)
- channel_start(ctrl, c);
- }
-
- if (cmd & regk_dma_load_c) {
- channel_load_c(ctrl, c);
- }
-}
-
-static void channel_update_irq(struct fs_dma_ctrl *ctrl, int c)
-{
- D(printf("%s %d\n", __func__, c));
- ctrl->channels[c].regs[R_INTR] &=
- ~(ctrl->channels[c].regs[RW_ACK_INTR]);
-
- ctrl->channels[c].regs[R_MASKED_INTR] =
- ctrl->channels[c].regs[R_INTR]
- & ctrl->channels[c].regs[RW_INTR_MASK];
-
- D(printf("%s: chan=%d masked_intr=%x\n", __func__,
- c,
- ctrl->channels[c].regs[R_MASKED_INTR]));
-
- qemu_set_irq(ctrl->channels[c].irq,
- !!ctrl->channels[c].regs[R_MASKED_INTR]);
-}
-
-static int channel_out_run(struct fs_dma_ctrl *ctrl, int c)
-{
- uint32_t len;
- uint32_t saved_data_buf;
- unsigned char buf[2 * 1024];
-
- struct dma_context_metadata meta;
- bool send_context = true;
-
- if (ctrl->channels[c].eol)
- return 0;
-
- do {
- bool out_eop;
- D(printf("ch=%d buf=%x after=%x\n",
- c,
- (uint32_t)ctrl->channels[c].current_d.buf,
- (uint32_t)ctrl->channels[c].current_d.after));
-
- if (send_context) {
- if (ctrl->channels[c].client->client.metadata_push) {
- meta.metadata = ctrl->channels[c].current_d.md;
- ctrl->channels[c].client->client.metadata_push(
- ctrl->channels[c].client->client.opaque,
- &meta);
- }
- send_context = false;
- }
-
- channel_load_d(ctrl, c);
- saved_data_buf = channel_reg(ctrl, c, RW_SAVED_DATA_BUF);
- len = (uint32_t)(unsigned long)
- ctrl->channels[c].current_d.after;
- len -= saved_data_buf;
-
- if (len > sizeof buf)
- len = sizeof buf;
- cpu_physical_memory_read (saved_data_buf, buf, len);
-
- out_eop = ((saved_data_buf + len) ==
- ctrl->channels[c].current_d.after) &&
- ctrl->channels[c].current_d.out_eop;
-
- D(printf("channel %d pushes %x %u bytes eop=%u\n", c,
- saved_data_buf, len, out_eop));
-
- if (ctrl->channels[c].client->client.push) {
- if (len > 0) {
- ctrl->channels[c].client->client.push(
- ctrl->channels[c].client->client.opaque,
- buf, len, out_eop);
- }
- } else {
- printf("WARNING: DMA ch%d dataloss,"
- " no attached client.\n", c);
- }
-
- saved_data_buf += len;
-
- if (saved_data_buf == (uint32_t)(unsigned long)
- ctrl->channels[c].current_d.after) {
- /* Done. Step to next. */
- if (ctrl->channels[c].current_d.out_eop) {
- send_context = true;
- }
- if (ctrl->channels[c].current_d.intr) {
- /* data intr. */
- D(printf("signal intr %d eol=%d\n",
- len, ctrl->channels[c].current_d.eol));
- ctrl->channels[c].regs[R_INTR] |= (1 << 2);
- channel_update_irq(ctrl, c);
- }
- channel_store_d(ctrl, c);
- if (ctrl->channels[c].current_d.eol) {
- D(printf("channel %d EOL\n", c));
- ctrl->channels[c].eol = 1;
-
- /* Mark the context as disabled. */
- ctrl->channels[c].current_c.dis = 1;
- channel_store_c(ctrl, c);
-
- channel_stop(ctrl, c);
- } else {
- ctrl->channels[c].regs[RW_SAVED_DATA] =
- (uint32_t)(unsigned long)ctrl->
- channels[c].current_d.next;
- /* Load new descriptor. */
- channel_load_d(ctrl, c);
- saved_data_buf = (uint32_t)(unsigned long)
- ctrl->channels[c].current_d.buf;
- }
-
- ctrl->channels[c].regs[RW_SAVED_DATA_BUF] =
- saved_data_buf;
- D(dump_d(c, &ctrl->channels[c].current_d));
- }
- ctrl->channels[c].regs[RW_SAVED_DATA_BUF] = saved_data_buf;
- } while (!ctrl->channels[c].eol);
- return 1;
-}
-
-static int channel_in_process(struct fs_dma_ctrl *ctrl, int c,
- unsigned char *buf, int buflen, int eop)
-{
- uint32_t len;
- uint32_t saved_data_buf;
-
- if (ctrl->channels[c].eol == 1)
- return 0;
-
- channel_load_d(ctrl, c);
- saved_data_buf = channel_reg(ctrl, c, RW_SAVED_DATA_BUF);
- len = (uint32_t)(unsigned long)ctrl->channels[c].current_d.after;
- len -= saved_data_buf;
-
- if (len > buflen)
- len = buflen;
-
- cpu_physical_memory_write (saved_data_buf, buf, len);
- saved_data_buf += len;
-
- if (saved_data_buf ==
- (uint32_t)(unsigned long)ctrl->channels[c].current_d.after
- || eop) {
- uint32_t r_intr = ctrl->channels[c].regs[R_INTR];
-
- D(printf("in dscr end len=%d\n",
- ctrl->channels[c].current_d.after
- - ctrl->channels[c].current_d.buf));
- ctrl->channels[c].current_d.after = saved_data_buf;
-
- /* Done. Step to next. */
- if (ctrl->channels[c].current_d.intr) {
- /* TODO: signal eop to the client. */
- /* data intr. */
- ctrl->channels[c].regs[R_INTR] |= 3;
- }
- if (eop) {
- ctrl->channels[c].current_d.in_eop = 1;
- ctrl->channels[c].regs[R_INTR] |= 8;
- }
- if (r_intr != ctrl->channels[c].regs[R_INTR])
- channel_update_irq(ctrl, c);
-
- channel_store_d(ctrl, c);
- D(dump_d(c, &ctrl->channels[c].current_d));
-
- if (ctrl->channels[c].current_d.eol) {
- D(printf("channel %d EOL\n", c));
- ctrl->channels[c].eol = 1;
-
- /* Mark the context as disabled. */
- ctrl->channels[c].current_c.dis = 1;
- channel_store_c(ctrl, c);
-
- channel_stop(ctrl, c);
- } else {
- ctrl->channels[c].regs[RW_SAVED_DATA] =
- (uint32_t)(unsigned long)ctrl->
- channels[c].current_d.next;
- /* Load new descriptor. */
- channel_load_d(ctrl, c);
- saved_data_buf = (uint32_t)(unsigned long)
- ctrl->channels[c].current_d.buf;
- }
- }
-
- ctrl->channels[c].regs[RW_SAVED_DATA_BUF] = saved_data_buf;
- return len;
-}
-
-static inline int channel_in_run(struct fs_dma_ctrl *ctrl, int c)
-{
- if (ctrl->channels[c].client->client.pull) {
- ctrl->channels[c].client->client.pull(
- ctrl->channels[c].client->client.opaque);
- return 1;
- } else
- return 0;
-}
-
-static uint32_t dma_rinvalid (void *opaque, hwaddr addr)
-{
- hw_error("Unsupported short raccess. reg=" TARGET_FMT_plx "\n", addr);
- return 0;
-}
-
-static uint64_t
-dma_read(void *opaque, hwaddr addr, unsigned int size)
-{
- struct fs_dma_ctrl *ctrl = opaque;
- int c;
- uint32_t r = 0;
-
- if (size != 4) {
- dma_rinvalid(opaque, addr);
- }
-
- /* Make addr relative to this channel and bounded to nr regs. */
- c = fs_channel(addr);
- addr &= 0xff;
- addr >>= 2;
- switch (addr)
- {
- case RW_STAT:
- r = ctrl->channels[c].state & 7;
- r |= ctrl->channels[c].eol << 5;
- r |= ctrl->channels[c].stream_cmd_src << 8;
- break;
-
- default:
- r = ctrl->channels[c].regs[addr];
- D(printf ("%s c=%d addr=" TARGET_FMT_plx "\n",
- __func__, c, addr));
- break;
- }
- return r;
-}
-
-static void
-dma_winvalid (void *opaque, hwaddr addr, uint32_t value)
-{
- hw_error("Unsupported short waccess. reg=" TARGET_FMT_plx "\n", addr);
-}
-
-static void
-dma_update_state(struct fs_dma_ctrl *ctrl, int c)
-{
- if (ctrl->channels[c].regs[RW_CFG] & 2)
- ctrl->channels[c].state = STOPPED;
- if (!(ctrl->channels[c].regs[RW_CFG] & 1))
- ctrl->channels[c].state = RST;
-}
-
-static void
-dma_write(void *opaque, hwaddr addr,
- uint64_t val64, unsigned int size)
-{
- struct fs_dma_ctrl *ctrl = opaque;
- uint32_t value = val64;
- int c;
-
- if (size != 4) {
- dma_winvalid(opaque, addr, value);
- }
-
- /* Make addr relative to this channel and bounded to nr regs. */
- c = fs_channel(addr);
- addr &= 0xff;
- addr >>= 2;
- switch (addr)
- {
- case RW_DATA:
- ctrl->channels[c].regs[addr] = value;
- break;
-
- case RW_CFG:
- ctrl->channels[c].regs[addr] = value;
- dma_update_state(ctrl, c);
- break;
- case RW_CMD:
- /* continue. */
- if (value & ~1)
- printf("Invalid store to ch=%d RW_CMD %x\n",
- c, value);
- ctrl->channels[c].regs[addr] = value;
- channel_continue(ctrl, c);
- break;
-
- case RW_SAVED_DATA:
- case RW_SAVED_DATA_BUF:
- case RW_GROUP:
- case RW_GROUP_DOWN:
- ctrl->channels[c].regs[addr] = value;
- break;
-
- case RW_ACK_INTR:
- case RW_INTR_MASK:
- ctrl->channels[c].regs[addr] = value;
- channel_update_irq(ctrl, c);
- if (addr == RW_ACK_INTR)
- ctrl->channels[c].regs[RW_ACK_INTR] = 0;
- break;
-
- case RW_STREAM_CMD:
- if (value & ~1023)
- printf("Invalid store to ch=%d "
- "RW_STREAMCMD %x\n",
- c, value);
- ctrl->channels[c].regs[addr] = value;
- D(printf("stream_cmd ch=%d\n", c));
- channel_stream_cmd(ctrl, c, value);
- break;
-
- default:
- D(printf ("%s c=%d " TARGET_FMT_plx "\n",
- __func__, c, addr));
- break;
- }
-}
-
-static const MemoryRegionOps dma_ops = {
- .read = dma_read,
- .write = dma_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 1,
- .max_access_size = 4
- }
-};
-
-static int etraxfs_dmac_run(void *opaque)
-{
- struct fs_dma_ctrl *ctrl = opaque;
- int i;
- int p = 0;
-
- for (i = 0;
- i < ctrl->nr_channels;
- i++)
- {
- if (ctrl->channels[i].state == RUNNING)
- {
- if (ctrl->channels[i].input) {
- p += channel_in_run(ctrl, i);
- } else {
- p += channel_out_run(ctrl, i);
- }
- }
- }
- return p;
-}
-
-int etraxfs_dmac_input(struct etraxfs_dma_client *client,
- void *buf, int len, int eop)
-{
- return channel_in_process(client->ctrl, client->channel,
- buf, len, eop);
-}
-
-/* Connect an IRQ line with a channel. */
-void etraxfs_dmac_connect(void *opaque, int c, qemu_irq *line, int input)
-{
- struct fs_dma_ctrl *ctrl = opaque;
- ctrl->channels[c].irq = *line;
- ctrl->channels[c].input = input;
-}
-
-void etraxfs_dmac_connect_client(void *opaque, int c,
- struct etraxfs_dma_client *cl)
-{
- struct fs_dma_ctrl *ctrl = opaque;
- cl->ctrl = ctrl;
- cl->channel = c;
- ctrl->channels[c].client = cl;
-}
-
-
-static void DMA_run(void *opaque)
-{
- struct fs_dma_ctrl *etraxfs_dmac = opaque;
- int p = 1;
-
- if (runstate_is_running())
- p = etraxfs_dmac_run(etraxfs_dmac);
-
- if (p)
- qemu_bh_schedule_idle(etraxfs_dmac->bh);
-}
-
-void *etraxfs_dmac_init(hwaddr base, int nr_channels)
-{
- struct fs_dma_ctrl *ctrl = NULL;
-
- ctrl = g_malloc0(sizeof *ctrl);
-
- ctrl->bh = qemu_bh_new(DMA_run, ctrl);
-
- ctrl->nr_channels = nr_channels;
- ctrl->channels = g_malloc0(sizeof ctrl->channels[0] * nr_channels);
-
- memory_region_init_io(&ctrl->mmio, NULL, &dma_ops, ctrl, "etraxfs-dma",
- nr_channels * 0x2000);
- memory_region_add_subregion(get_system_memory(), base, &ctrl->mmio);
-
- return ctrl;
-}
diff --git a/qemu/hw/dma/i82374.c b/qemu/hw/dma/i82374.c
deleted file mode 100644
index 6c0f975df..000000000
--- a/qemu/hw/dma/i82374.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * QEMU Intel 82374 emulation (Enhanced DMA controller)
- *
- * Copyright (c) 2010 Hervé Poussineau
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/isa/isa.h"
-
-#define TYPE_I82374 "i82374"
-#define I82374(obj) OBJECT_CHECK(I82374State, (obj), TYPE_I82374)
-
-//#define DEBUG_I82374
-
-#ifdef DEBUG_I82374
-#define DPRINTF(fmt, ...) \
-do { fprintf(stderr, "i82374: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) \
-do {} while (0)
-#endif
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "i82374 ERROR: " fmt , ## __VA_ARGS__); } while (0)
-
-typedef struct I82374State {
- ISADevice parent_obj;
-
- uint32_t iobase;
- uint8_t commands[8];
- PortioList port_list;
-} I82374State;
-
-static const VMStateDescription vmstate_i82374 = {
- .name = "i82374",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8_ARRAY(commands, I82374State, 8),
- VMSTATE_END_OF_LIST()
- },
-};
-
-static uint32_t i82374_read_isr(void *opaque, uint32_t nport)
-{
- uint32_t val = 0;
-
- BADF("%s: %08x\n", __func__, nport);
-
- DPRINTF("%s: %08x=%08x\n", __func__, nport, val);
- return val;
-}
-
-static void i82374_write_command(void *opaque, uint32_t nport, uint32_t data)
-{
- DPRINTF("%s: %08x=%08x\n", __func__, nport, data);
-
- if (data != 0x42) {
- /* Not Stop S/G command */
- BADF("%s: %08x=%08x\n", __func__, nport, data);
- }
-}
-
-static uint32_t i82374_read_status(void *opaque, uint32_t nport)
-{
- uint32_t val = 0;
-
- BADF("%s: %08x\n", __func__, nport);
-
- DPRINTF("%s: %08x=%08x\n", __func__, nport, val);
- return val;
-}
-
-static void i82374_write_descriptor(void *opaque, uint32_t nport, uint32_t data)
-{
- DPRINTF("%s: %08x=%08x\n", __func__, nport, data);
-
- BADF("%s: %08x=%08x\n", __func__, nport, data);
-}
-
-static uint32_t i82374_read_descriptor(void *opaque, uint32_t nport)
-{
- uint32_t val = 0;
-
- BADF("%s: %08x\n", __func__, nport);
-
- DPRINTF("%s: %08x=%08x\n", __func__, nport, val);
- return val;
-}
-
-static const MemoryRegionPortio i82374_portio_list[] = {
- { 0x0A, 1, 1, .read = i82374_read_isr, },
- { 0x10, 8, 1, .write = i82374_write_command, },
- { 0x18, 8, 1, .read = i82374_read_status, },
- { 0x20, 0x20, 1,
- .write = i82374_write_descriptor, .read = i82374_read_descriptor, },
- PORTIO_END_OF_LIST(),
-};
-
-static void i82374_realize(DeviceState *dev, Error **errp)
-{
- I82374State *s = I82374(dev);
-
- portio_list_init(&s->port_list, OBJECT(s), i82374_portio_list, s,
- "i82374");
- portio_list_add(&s->port_list, isa_address_space_io(&s->parent_obj),
- s->iobase);
-
- DMA_init(isa_bus_from_device(ISA_DEVICE(dev)), 1);
- memset(s->commands, 0, sizeof(s->commands));
-}
-
-static Property i82374_properties[] = {
- DEFINE_PROP_UINT32("iobase", I82374State, iobase, 0x400),
- DEFINE_PROP_END_OF_LIST()
-};
-
-static void i82374_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = i82374_realize;
- dc->vmsd = &vmstate_i82374;
- dc->props = i82374_properties;
-}
-
-static const TypeInfo i82374_info = {
- .name = TYPE_I82374,
- .parent = TYPE_ISA_DEVICE,
- .instance_size = sizeof(I82374State),
- .class_init = i82374_class_init,
-};
-
-static void i82374_register_types(void)
-{
- type_register_static(&i82374_info);
-}
-
-type_init(i82374_register_types)
diff --git a/qemu/hw/dma/i8257.c b/qemu/hw/dma/i8257.c
deleted file mode 100644
index f345c5476..000000000
--- a/qemu/hw/dma/i8257.c
+++ /dev/null
@@ -1,643 +0,0 @@
-/*
- * QEMU DMA emulation
- *
- * Copyright (c) 2003-2004 Vassili Karpov (malc)
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/isa/isa.h"
-#include "hw/isa/i8257.h"
-#include "qemu/main-loop.h"
-#include "trace.h"
-
-#define I8257(obj) \
- OBJECT_CHECK(I8257State, (obj), TYPE_I8257)
-
-/* #define DEBUG_DMA */
-
-#define dolog(...) fprintf (stderr, "dma: " __VA_ARGS__)
-#ifdef DEBUG_DMA
-#define linfo(...) fprintf (stderr, "dma: " __VA_ARGS__)
-#define ldebug(...) fprintf (stderr, "dma: " __VA_ARGS__)
-#else
-#define linfo(...)
-#define ldebug(...)
-#endif
-
-#define ADDR 0
-#define COUNT 1
-
-enum {
- CMD_MEMORY_TO_MEMORY = 0x01,
- CMD_FIXED_ADDRESS = 0x02,
- CMD_BLOCK_CONTROLLER = 0x04,
- CMD_COMPRESSED_TIME = 0x08,
- CMD_CYCLIC_PRIORITY = 0x10,
- CMD_EXTENDED_WRITE = 0x20,
- CMD_LOW_DREQ = 0x40,
- CMD_LOW_DACK = 0x80,
- CMD_NOT_SUPPORTED = CMD_MEMORY_TO_MEMORY | CMD_FIXED_ADDRESS
- | CMD_COMPRESSED_TIME | CMD_CYCLIC_PRIORITY | CMD_EXTENDED_WRITE
- | CMD_LOW_DREQ | CMD_LOW_DACK
-
-};
-
-static void i8257_dma_run(void *opaque);
-
-static const int channels[8] = {-1, 2, 3, 1, -1, -1, -1, 0};
-
-static void i8257_write_page(void *opaque, uint32_t nport, uint32_t data)
-{
- I8257State *d = opaque;
- int ichan;
-
- ichan = channels[nport & 7];
- if (-1 == ichan) {
- dolog ("invalid channel %#x %#x\n", nport, data);
- return;
- }
- d->regs[ichan].page = data;
-}
-
-static void i8257_write_pageh(void *opaque, uint32_t nport, uint32_t data)
-{
- I8257State *d = opaque;
- int ichan;
-
- ichan = channels[nport & 7];
- if (-1 == ichan) {
- dolog ("invalid channel %#x %#x\n", nport, data);
- return;
- }
- d->regs[ichan].pageh = data;
-}
-
-static uint32_t i8257_read_page(void *opaque, uint32_t nport)
-{
- I8257State *d = opaque;
- int ichan;
-
- ichan = channels[nport & 7];
- if (-1 == ichan) {
- dolog ("invalid channel read %#x\n", nport);
- return 0;
- }
- return d->regs[ichan].page;
-}
-
-static uint32_t i8257_read_pageh(void *opaque, uint32_t nport)
-{
- I8257State *d = opaque;
- int ichan;
-
- ichan = channels[nport & 7];
- if (-1 == ichan) {
- dolog ("invalid channel read %#x\n", nport);
- return 0;
- }
- return d->regs[ichan].pageh;
-}
-
-static inline void i8257_init_chan(I8257State *d, int ichan)
-{
- I8257Regs *r;
-
- r = d->regs + ichan;
- r->now[ADDR] = r->base[ADDR] << d->dshift;
- r->now[COUNT] = 0;
-}
-
-static inline int i8257_getff(I8257State *d)
-{
- int ff;
-
- ff = d->flip_flop;
- d->flip_flop = !ff;
- return ff;
-}
-
-static uint64_t i8257_read_chan(void *opaque, hwaddr nport, unsigned size)
-{
- I8257State *d = opaque;
- int ichan, nreg, iport, ff, val, dir;
- I8257Regs *r;
-
- iport = (nport >> d->dshift) & 0x0f;
- ichan = iport >> 1;
- nreg = iport & 1;
- r = d->regs + ichan;
-
- dir = ((r->mode >> 5) & 1) ? -1 : 1;
- ff = i8257_getff(d);
- if (nreg)
- val = (r->base[COUNT] << d->dshift) - r->now[COUNT];
- else
- val = r->now[ADDR] + r->now[COUNT] * dir;
-
- ldebug ("read_chan %#x -> %d\n", iport, val);
- return (val >> (d->dshift + (ff << 3))) & 0xff;
-}
-
-static void i8257_write_chan(void *opaque, hwaddr nport, uint64_t data,
- unsigned int size)
-{
- I8257State *d = opaque;
- int iport, ichan, nreg;
- I8257Regs *r;
-
- iport = (nport >> d->dshift) & 0x0f;
- ichan = iport >> 1;
- nreg = iport & 1;
- r = d->regs + ichan;
- if (i8257_getff(d)) {
- r->base[nreg] = (r->base[nreg] & 0xff) | ((data << 8) & 0xff00);
- i8257_init_chan(d, ichan);
- } else {
- r->base[nreg] = (r->base[nreg] & 0xff00) | (data & 0xff);
- }
-}
-
-static void i8257_write_cont(void *opaque, hwaddr nport, uint64_t data,
- unsigned int size)
-{
- I8257State *d = opaque;
- int iport, ichan = 0;
-
- iport = (nport >> d->dshift) & 0x0f;
- switch (iport) {
- case 0x00: /* command */
- if ((data != 0) && (data & CMD_NOT_SUPPORTED)) {
- dolog("command %"PRIx64" not supported\n", data);
- return;
- }
- d->command = data;
- break;
-
- case 0x01:
- ichan = data & 3;
- if (data & 4) {
- d->status |= 1 << (ichan + 4);
- }
- else {
- d->status &= ~(1 << (ichan + 4));
- }
- d->status &= ~(1 << ichan);
- i8257_dma_run(d);
- break;
-
- case 0x02: /* single mask */
- if (data & 4)
- d->mask |= 1 << (data & 3);
- else
- d->mask &= ~(1 << (data & 3));
- i8257_dma_run(d);
- break;
-
- case 0x03: /* mode */
- {
- ichan = data & 3;
-#ifdef DEBUG_DMA
- {
- int op, ai, dir, opmode;
- op = (data >> 2) & 3;
- ai = (data >> 4) & 1;
- dir = (data >> 5) & 1;
- opmode = (data >> 6) & 3;
-
- linfo ("ichan %d, op %d, ai %d, dir %d, opmode %d\n",
- ichan, op, ai, dir, opmode);
- }
-#endif
- d->regs[ichan].mode = data;
- break;
- }
-
- case 0x04: /* clear flip flop */
- d->flip_flop = 0;
- break;
-
- case 0x05: /* reset */
- d->flip_flop = 0;
- d->mask = ~0;
- d->status = 0;
- d->command = 0;
- break;
-
- case 0x06: /* clear mask for all channels */
- d->mask = 0;
- i8257_dma_run(d);
- break;
-
- case 0x07: /* write mask for all channels */
- d->mask = data;
- i8257_dma_run(d);
- break;
-
- default:
- dolog ("unknown iport %#x\n", iport);
- break;
- }
-
-#ifdef DEBUG_DMA
- if (0xc != iport) {
- linfo ("write_cont: nport %#06x, ichan % 2d, val %#06x\n",
- nport, ichan, data);
- }
-#endif
-}
-
-static uint64_t i8257_read_cont(void *opaque, hwaddr nport, unsigned size)
-{
- I8257State *d = opaque;
- int iport, val;
-
- iport = (nport >> d->dshift) & 0x0f;
- switch (iport) {
- case 0x00: /* status */
- val = d->status;
- d->status &= 0xf0;
- break;
- case 0x01: /* mask */
- val = d->mask;
- break;
- default:
- val = 0;
- break;
- }
-
- ldebug ("read_cont: nport %#06x, iport %#04x val %#x\n", nport, iport, val);
- return val;
-}
-
-static IsaDmaTransferMode i8257_dma_get_transfer_mode(IsaDma *obj, int nchan)
-{
- I8257State *d = I8257(obj);
- return (d->regs[nchan & 3].mode >> 2) & 3;
-}
-
-static bool i8257_dma_has_autoinitialization(IsaDma *obj, int nchan)
-{
- I8257State *d = I8257(obj);
- return (d->regs[nchan & 3].mode >> 4) & 1;
-}
-
-static void i8257_dma_hold_DREQ(IsaDma *obj, int nchan)
-{
- I8257State *d = I8257(obj);
- int ichan;
-
- ichan = nchan & 3;
- d->status |= 1 << (ichan + 4);
- i8257_dma_run(d);
-}
-
-static void i8257_dma_release_DREQ(IsaDma *obj, int nchan)
-{
- I8257State *d = I8257(obj);
- int ichan;
-
- ichan = nchan & 3;
- d->status &= ~(1 << (ichan + 4));
- i8257_dma_run(d);
-}
-
-static void i8257_channel_run(I8257State *d, int ichan)
-{
- int ncont = d->dshift;
- int n;
- I8257Regs *r = &d->regs[ichan];
-#ifdef DEBUG_DMA
- int dir, opmode;
-
- dir = (r->mode >> 5) & 1;
- opmode = (r->mode >> 6) & 3;
-
- if (dir) {
- dolog ("DMA in address decrement mode\n");
- }
- if (opmode != 1) {
- dolog ("DMA not in single mode select %#x\n", opmode);
- }
-#endif
-
- n = r->transfer_handler (r->opaque, ichan + (ncont << 2),
- r->now[COUNT], (r->base[COUNT] + 1) << ncont);
- r->now[COUNT] = n;
- ldebug ("dma_pos %d size %d\n", n, (r->base[COUNT] + 1) << ncont);
- if (n == (r->base[COUNT] + 1) << ncont) {
- ldebug("transfer done\n");
- d->status |= (1 << ichan);
- }
-}
-
-static void i8257_dma_run(void *opaque)
-{
- I8257State *d = opaque;
- int ichan;
- int rearm = 0;
-
- if (d->running) {
- rearm = 1;
- goto out;
- } else {
- d->running = 1;
- }
-
- for (ichan = 0; ichan < 4; ichan++) {
- int mask;
-
- mask = 1 << ichan;
-
- if ((0 == (d->mask & mask)) && (0 != (d->status & (mask << 4)))) {
- i8257_channel_run(d, ichan);
- rearm = 1;
- }
- }
-
- d->running = 0;
-out:
- if (rearm) {
- qemu_bh_schedule_idle(d->dma_bh);
- d->dma_bh_scheduled = true;
- }
-}
-
-static void i8257_dma_register_channel(IsaDma *obj, int nchan,
- IsaDmaTransferHandler transfer_handler,
- void *opaque)
-{
- I8257State *d = I8257(obj);
- I8257Regs *r;
- int ichan;
-
- ichan = nchan & 3;
-
- r = d->regs + ichan;
- r->transfer_handler = transfer_handler;
- r->opaque = opaque;
-}
-
-static int i8257_dma_read_memory(IsaDma *obj, int nchan, void *buf, int pos,
- int len)
-{
- I8257State *d = I8257(obj);
- I8257Regs *r = &d->regs[nchan & 3];
- hwaddr addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
-
- if (r->mode & 0x20) {
- int i;
- uint8_t *p = buf;
-
- cpu_physical_memory_read (addr - pos - len, buf, len);
- /* What about 16bit transfers? */
- for (i = 0; i < len >> 1; i++) {
- uint8_t b = p[len - i - 1];
- p[i] = b;
- }
- }
- else
- cpu_physical_memory_read (addr + pos, buf, len);
-
- return len;
-}
-
-static int i8257_dma_write_memory(IsaDma *obj, int nchan, void *buf, int pos,
- int len)
-{
- I8257State *s = I8257(obj);
- I8257Regs *r = &s->regs[nchan & 3];
- hwaddr addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
-
- if (r->mode & 0x20) {
- int i;
- uint8_t *p = buf;
-
- cpu_physical_memory_write (addr - pos - len, buf, len);
- /* What about 16bit transfers? */
- for (i = 0; i < len; i++) {
- uint8_t b = p[len - i - 1];
- p[i] = b;
- }
- }
- else
- cpu_physical_memory_write (addr + pos, buf, len);
-
- return len;
-}
-
-/* request the emulator to transfer a new DMA memory block ASAP (even
- * if the idle bottom half would not have exited the iothread yet).
- */
-static void i8257_dma_schedule(IsaDma *obj)
-{
- I8257State *d = I8257(obj);
- if (d->dma_bh_scheduled) {
- qemu_notify_event();
- }
-}
-
-static void i8257_reset(DeviceState *dev)
-{
- I8257State *d = I8257(dev);
- i8257_write_cont(d, (0x05 << d->dshift), 0, 1);
-}
-
-static int i8257_phony_handler(void *opaque, int nchan, int dma_pos,
- int dma_len)
-{
- trace_i8257_unregistered_dma(nchan, dma_pos, dma_len);
- return dma_pos;
-}
-
-
-static const MemoryRegionOps channel_io_ops = {
- .read = i8257_read_chan,
- .write = i8257_write_chan,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
-};
-
-/* IOport from page_base */
-static const MemoryRegionPortio page_portio_list[] = {
- { 0x01, 3, 1, .write = i8257_write_page, .read = i8257_read_page, },
- { 0x07, 1, 1, .write = i8257_write_page, .read = i8257_read_page, },
- PORTIO_END_OF_LIST(),
-};
-
-/* IOport from pageh_base */
-static const MemoryRegionPortio pageh_portio_list[] = {
- { 0x01, 3, 1, .write = i8257_write_pageh, .read = i8257_read_pageh, },
- { 0x07, 3, 1, .write = i8257_write_pageh, .read = i8257_read_pageh, },
- PORTIO_END_OF_LIST(),
-};
-
-static const MemoryRegionOps cont_io_ops = {
- .read = i8257_read_cont,
- .write = i8257_write_cont,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
-};
-
-static const VMStateDescription vmstate_i8257_regs = {
- .name = "dma_regs",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_INT32_ARRAY(now, I8257Regs, 2),
- VMSTATE_UINT16_ARRAY(base, I8257Regs, 2),
- VMSTATE_UINT8(mode, I8257Regs),
- VMSTATE_UINT8(page, I8257Regs),
- VMSTATE_UINT8(pageh, I8257Regs),
- VMSTATE_UINT8(dack, I8257Regs),
- VMSTATE_UINT8(eop, I8257Regs),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static int i8257_post_load(void *opaque, int version_id)
-{
- I8257State *d = opaque;
- i8257_dma_run(d);
-
- return 0;
-}
-
-static const VMStateDescription vmstate_i8257 = {
- .name = "dma",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = i8257_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(command, I8257State),
- VMSTATE_UINT8(mask, I8257State),
- VMSTATE_UINT8(flip_flop, I8257State),
- VMSTATE_INT32(dshift, I8257State),
- VMSTATE_STRUCT_ARRAY(regs, I8257State, 4, 1, vmstate_i8257_regs,
- I8257Regs),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void i8257_realize(DeviceState *dev, Error **errp)
-{
- ISADevice *isa = ISA_DEVICE(dev);
- I8257State *d = I8257(dev);
- int i;
-
- memory_region_init_io(&d->channel_io, NULL, &channel_io_ops, d,
- "dma-chan", 8 << d->dshift);
- memory_region_add_subregion(isa_address_space_io(isa),
- d->base, &d->channel_io);
-
- isa_register_portio_list(isa, d->page_base, page_portio_list, d,
- "dma-page");
- if (d->pageh_base >= 0) {
- isa_register_portio_list(isa, d->pageh_base, pageh_portio_list, d,
- "dma-pageh");
- }
-
- memory_region_init_io(&d->cont_io, OBJECT(isa), &cont_io_ops, d,
- "dma-cont", 8 << d->dshift);
- memory_region_add_subregion(isa_address_space_io(isa),
- d->base + (8 << d->dshift), &d->cont_io);
-
- for (i = 0; i < ARRAY_SIZE(d->regs); ++i) {
- d->regs[i].transfer_handler = i8257_phony_handler;
- }
-
- d->dma_bh = qemu_bh_new(i8257_dma_run, d);
-}
-
-static Property i8257_properties[] = {
- DEFINE_PROP_INT32("base", I8257State, base, 0x00),
- DEFINE_PROP_INT32("page-base", I8257State, page_base, 0x80),
- DEFINE_PROP_INT32("pageh-base", I8257State, pageh_base, 0x480),
- DEFINE_PROP_INT32("dshift", I8257State, dshift, 0),
- DEFINE_PROP_END_OF_LIST()
-};
-
-static void i8257_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- IsaDmaClass *idc = ISADMA_CLASS(klass);
-
- dc->realize = i8257_realize;
- dc->reset = i8257_reset;
- dc->vmsd = &vmstate_i8257;
- dc->props = i8257_properties;
-
- idc->get_transfer_mode = i8257_dma_get_transfer_mode;
- idc->has_autoinitialization = i8257_dma_has_autoinitialization;
- idc->read_memory = i8257_dma_read_memory;
- idc->write_memory = i8257_dma_write_memory;
- idc->hold_DREQ = i8257_dma_hold_DREQ;
- idc->release_DREQ = i8257_dma_release_DREQ;
- idc->schedule = i8257_dma_schedule;
- idc->register_channel = i8257_dma_register_channel;
-}
-
-static const TypeInfo i8257_info = {
- .name = TYPE_I8257,
- .parent = TYPE_ISA_DEVICE,
- .instance_size = sizeof(I8257State),
- .class_init = i8257_class_init,
- .interfaces = (InterfaceInfo[]) {
- { TYPE_ISADMA },
- { }
- }
-};
-
-static void i8257_register_types(void)
-{
- type_register_static(&i8257_info);
-}
-
-type_init(i8257_register_types)
-
-void DMA_init(ISABus *bus, int high_page_enable)
-{
- ISADevice *isa1, *isa2;
- DeviceState *d;
-
- isa1 = isa_create(bus, TYPE_I8257);
- d = DEVICE(isa1);
- qdev_prop_set_int32(d, "base", 0x00);
- qdev_prop_set_int32(d, "page-base", 0x80);
- qdev_prop_set_int32(d, "pageh-base", high_page_enable ? 0x480 : -1);
- qdev_prop_set_int32(d, "dshift", 0);
- qdev_init_nofail(d);
-
- isa2 = isa_create(bus, TYPE_I8257);
- d = DEVICE(isa2);
- qdev_prop_set_int32(d, "base", 0xc0);
- qdev_prop_set_int32(d, "page-base", 0x88);
- qdev_prop_set_int32(d, "pageh-base", high_page_enable ? 0x488 : -1);
- qdev_prop_set_int32(d, "dshift", 1);
- qdev_init_nofail(d);
-
- isa_bus_dma(bus, ISADMA(isa1), ISADMA(isa2));
-}
diff --git a/qemu/hw/dma/omap_dma.c b/qemu/hw/dma/omap_dma.c
deleted file mode 100644
index 700cd6b43..000000000
--- a/qemu/hw/dma/omap_dma.c
+++ /dev/null
@@ -1,2103 +0,0 @@
-/*
- * TI OMAP DMA gigacell.
- *
- * Copyright (C) 2006-2008 Andrzej Zaborowski <balrog@zabor.org>
- * Copyright (C) 2007-2008 Lauro Ramos Venancio <lauro.venancio@indt.org.br>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "qemu/timer.h"
-#include "hw/arm/omap.h"
-#include "hw/irq.h"
-#include "hw/arm/soc_dma.h"
-
-struct omap_dma_channel_s {
- /* transfer data */
- int burst[2];
- int pack[2];
- int endian[2];
- int endian_lock[2];
- int translate[2];
- enum omap_dma_port port[2];
- hwaddr addr[2];
- omap_dma_addressing_t mode[2];
- uint32_t elements;
- uint16_t frames;
- int32_t frame_index[2];
- int16_t element_index[2];
- int data_type;
-
- /* transfer type */
- int transparent_copy;
- int constant_fill;
- uint32_t color;
- int prefetch;
-
- /* auto init and linked channel data */
- int end_prog;
- int repeat;
- int auto_init;
- int link_enabled;
- int link_next_ch;
-
- /* interruption data */
- int interrupts;
- int status;
- int cstatus;
-
- /* state data */
- int active;
- int enable;
- int sync;
- int src_sync;
- int pending_request;
- int waiting_end_prog;
- uint16_t cpc;
- int set_update;
-
- /* sync type */
- int fs;
- int bs;
-
- /* compatibility */
- int omap_3_1_compatible_disable;
-
- qemu_irq irq;
- struct omap_dma_channel_s *sibling;
-
- struct omap_dma_reg_set_s {
- hwaddr src, dest;
- int frame;
- int element;
- int pck_element;
- int frame_delta[2];
- int elem_delta[2];
- int frames;
- int elements;
- int pck_elements;
- } active_set;
-
- struct soc_dma_ch_s *dma;
-
- /* unused parameters */
- int write_mode;
- int priority;
- int interleave_disabled;
- int type;
- int suspend;
- int buf_disable;
-};
-
-struct omap_dma_s {
- struct soc_dma_s *dma;
- MemoryRegion iomem;
-
- struct omap_mpu_state_s *mpu;
- omap_clk clk;
- qemu_irq irq[4];
- void (*intr_update)(struct omap_dma_s *s);
- enum omap_dma_model model;
- int omap_3_1_mapping_disabled;
-
- uint32_t gcr;
- uint32_t ocp;
- uint32_t caps[5];
- uint32_t irqen[4];
- uint32_t irqstat[4];
-
- int chans;
- struct omap_dma_channel_s ch[32];
- struct omap_dma_lcd_channel_s lcd_ch;
-};
-
-/* Interrupts */
-#define TIMEOUT_INTR (1 << 0)
-#define EVENT_DROP_INTR (1 << 1)
-#define HALF_FRAME_INTR (1 << 2)
-#define END_FRAME_INTR (1 << 3)
-#define LAST_FRAME_INTR (1 << 4)
-#define END_BLOCK_INTR (1 << 5)
-#define SYNC (1 << 6)
-#define END_PKT_INTR (1 << 7)
-#define TRANS_ERR_INTR (1 << 8)
-#define MISALIGN_INTR (1 << 11)
-
-static inline void omap_dma_interrupts_update(struct omap_dma_s *s)
-{
- s->intr_update(s);
-}
-
-static void omap_dma_channel_load(struct omap_dma_channel_s *ch)
-{
- struct omap_dma_reg_set_s *a = &ch->active_set;
- int i, normal;
- int omap_3_1 = !ch->omap_3_1_compatible_disable;
-
- /*
- * TODO: verify address ranges and alignment
- * TODO: port endianness
- */
-
- a->src = ch->addr[0];
- a->dest = ch->addr[1];
- a->frames = ch->frames;
- a->elements = ch->elements;
- a->pck_elements = ch->frame_index[!ch->src_sync];
- a->frame = 0;
- a->element = 0;
- a->pck_element = 0;
-
- if (unlikely(!ch->elements || !ch->frames)) {
- printf("%s: bad DMA request\n", __FUNCTION__);
- return;
- }
-
- for (i = 0; i < 2; i ++)
- switch (ch->mode[i]) {
- case constant:
- a->elem_delta[i] = 0;
- a->frame_delta[i] = 0;
- break;
- case post_incremented:
- a->elem_delta[i] = ch->data_type;
- a->frame_delta[i] = 0;
- break;
- case single_index:
- a->elem_delta[i] = ch->data_type +
- ch->element_index[omap_3_1 ? 0 : i] - 1;
- a->frame_delta[i] = 0;
- break;
- case double_index:
- a->elem_delta[i] = ch->data_type +
- ch->element_index[omap_3_1 ? 0 : i] - 1;
- a->frame_delta[i] = ch->frame_index[omap_3_1 ? 0 : i] -
- ch->element_index[omap_3_1 ? 0 : i];
- break;
- default:
- break;
- }
-
- normal = !ch->transparent_copy && !ch->constant_fill &&
- /* FIFO is big-endian so either (ch->endian[n] == 1) OR
- * (ch->endian_lock[n] == 1) mean no endianism conversion. */
- (ch->endian[0] | ch->endian_lock[0]) ==
- (ch->endian[1] | ch->endian_lock[1]);
- for (i = 0; i < 2; i ++) {
- /* TODO: for a->frame_delta[i] > 0 still use the fast path, just
- * limit min_elems in omap_dma_transfer_setup to the nearest frame
- * end. */
- if (!a->elem_delta[i] && normal &&
- (a->frames == 1 || !a->frame_delta[i]))
- ch->dma->type[i] = soc_dma_access_const;
- else if (a->elem_delta[i] == ch->data_type && normal &&
- (a->frames == 1 || !a->frame_delta[i]))
- ch->dma->type[i] = soc_dma_access_linear;
- else
- ch->dma->type[i] = soc_dma_access_other;
-
- ch->dma->vaddr[i] = ch->addr[i];
- }
- soc_dma_ch_update(ch->dma);
-}
-
-static void omap_dma_activate_channel(struct omap_dma_s *s,
- struct omap_dma_channel_s *ch)
-{
- if (!ch->active) {
- if (ch->set_update) {
- /* It's not clear when the active set is supposed to be
- * loaded from registers. We're already loading it when the
- * channel is enabled, and for some guests this is not enough
- * but that may be also because of a race condition (no
- * delays in qemu) in the guest code, which we're just
- * working around here. */
- omap_dma_channel_load(ch);
- ch->set_update = 0;
- }
-
- ch->active = 1;
- soc_dma_set_request(ch->dma, 1);
- if (ch->sync)
- ch->status |= SYNC;
- }
-}
-
-static void omap_dma_deactivate_channel(struct omap_dma_s *s,
- struct omap_dma_channel_s *ch)
-{
- /* Update cpc */
- ch->cpc = ch->active_set.dest & 0xffff;
-
- if (ch->pending_request && !ch->waiting_end_prog && ch->enable) {
- /* Don't deactivate the channel */
- ch->pending_request = 0;
- return;
- }
-
- /* Don't deactive the channel if it is synchronized and the DMA request is
- active */
- if (ch->sync && ch->enable && (s->dma->drqbmp & (1ULL << ch->sync)))
- return;
-
- if (ch->active) {
- ch->active = 0;
- ch->status &= ~SYNC;
- soc_dma_set_request(ch->dma, 0);
- }
-}
-
-static void omap_dma_enable_channel(struct omap_dma_s *s,
- struct omap_dma_channel_s *ch)
-{
- if (!ch->enable) {
- ch->enable = 1;
- ch->waiting_end_prog = 0;
- omap_dma_channel_load(ch);
- /* TODO: theoretically if ch->sync && ch->prefetch &&
- * !s->dma->drqbmp[ch->sync], we should also activate and fetch
- * from source and then stall until signalled. */
- if ((!ch->sync) || (s->dma->drqbmp & (1ULL << ch->sync))) {
- omap_dma_activate_channel(s, ch);
- }
- }
-}
-
-static void omap_dma_disable_channel(struct omap_dma_s *s,
- struct omap_dma_channel_s *ch)
-{
- if (ch->enable) {
- ch->enable = 0;
- /* Discard any pending request */
- ch->pending_request = 0;
- omap_dma_deactivate_channel(s, ch);
- }
-}
-
-static void omap_dma_channel_end_prog(struct omap_dma_s *s,
- struct omap_dma_channel_s *ch)
-{
- if (ch->waiting_end_prog) {
- ch->waiting_end_prog = 0;
- if (!ch->sync || ch->pending_request) {
- ch->pending_request = 0;
- omap_dma_activate_channel(s, ch);
- }
- }
-}
-
-static void omap_dma_interrupts_3_1_update(struct omap_dma_s *s)
-{
- struct omap_dma_channel_s *ch = s->ch;
-
- /* First three interrupts are shared between two channels each. */
- if (ch[0].status | ch[6].status)
- qemu_irq_raise(ch[0].irq);
- if (ch[1].status | ch[7].status)
- qemu_irq_raise(ch[1].irq);
- if (ch[2].status | ch[8].status)
- qemu_irq_raise(ch[2].irq);
- if (ch[3].status)
- qemu_irq_raise(ch[3].irq);
- if (ch[4].status)
- qemu_irq_raise(ch[4].irq);
- if (ch[5].status)
- qemu_irq_raise(ch[5].irq);
-}
-
-static void omap_dma_interrupts_3_2_update(struct omap_dma_s *s)
-{
- struct omap_dma_channel_s *ch = s->ch;
- int i;
-
- for (i = s->chans; i; ch ++, i --)
- if (ch->status)
- qemu_irq_raise(ch->irq);
-}
-
-static void omap_dma_enable_3_1_mapping(struct omap_dma_s *s)
-{
- s->omap_3_1_mapping_disabled = 0;
- s->chans = 9;
- s->intr_update = omap_dma_interrupts_3_1_update;
-}
-
-static void omap_dma_disable_3_1_mapping(struct omap_dma_s *s)
-{
- s->omap_3_1_mapping_disabled = 1;
- s->chans = 16;
- s->intr_update = omap_dma_interrupts_3_2_update;
-}
-
-static void omap_dma_process_request(struct omap_dma_s *s, int request)
-{
- int channel;
- int drop_event = 0;
- struct omap_dma_channel_s *ch = s->ch;
-
- for (channel = 0; channel < s->chans; channel ++, ch ++) {
- if (ch->enable && ch->sync == request) {
- if (!ch->active)
- omap_dma_activate_channel(s, ch);
- else if (!ch->pending_request)
- ch->pending_request = 1;
- else {
- /* Request collision */
- /* Second request received while processing other request */
- ch->status |= EVENT_DROP_INTR;
- drop_event = 1;
- }
- }
- }
-
- if (drop_event)
- omap_dma_interrupts_update(s);
-}
-
-static void omap_dma_transfer_generic(struct soc_dma_ch_s *dma)
-{
- uint8_t value[4];
- struct omap_dma_channel_s *ch = dma->opaque;
- struct omap_dma_reg_set_s *a = &ch->active_set;
- int bytes = dma->bytes;
-#ifdef MULTI_REQ
- uint16_t status = ch->status;
-#endif
-
- do {
- /* Transfer a single element */
- /* FIXME: check the endianness */
- if (!ch->constant_fill)
- cpu_physical_memory_read(a->src, value, ch->data_type);
- else
- *(uint32_t *) value = ch->color;
-
- if (!ch->transparent_copy || *(uint32_t *) value != ch->color)
- cpu_physical_memory_write(a->dest, value, ch->data_type);
-
- a->src += a->elem_delta[0];
- a->dest += a->elem_delta[1];
- a->element ++;
-
-#ifndef MULTI_REQ
- if (a->element == a->elements) {
- /* End of Frame */
- a->element = 0;
- a->src += a->frame_delta[0];
- a->dest += a->frame_delta[1];
- a->frame ++;
-
- /* If the channel is async, update cpc */
- if (!ch->sync)
- ch->cpc = a->dest & 0xffff;
- }
- } while ((bytes -= ch->data_type));
-#else
- /* If the channel is element synchronized, deactivate it */
- if (ch->sync && !ch->fs && !ch->bs)
- omap_dma_deactivate_channel(s, ch);
-
- /* If it is the last frame, set the LAST_FRAME interrupt */
- if (a->element == 1 && a->frame == a->frames - 1)
- if (ch->interrupts & LAST_FRAME_INTR)
- ch->status |= LAST_FRAME_INTR;
-
- /* If the half of the frame was reached, set the HALF_FRAME
- interrupt */
- if (a->element == (a->elements >> 1))
- if (ch->interrupts & HALF_FRAME_INTR)
- ch->status |= HALF_FRAME_INTR;
-
- if (ch->fs && ch->bs) {
- a->pck_element ++;
- /* Check if a full packet has beed transferred. */
- if (a->pck_element == a->pck_elements) {
- a->pck_element = 0;
-
- /* Set the END_PKT interrupt */
- if ((ch->interrupts & END_PKT_INTR) && !ch->src_sync)
- ch->status |= END_PKT_INTR;
-
- /* If the channel is packet-synchronized, deactivate it */
- if (ch->sync)
- omap_dma_deactivate_channel(s, ch);
- }
- }
-
- if (a->element == a->elements) {
- /* End of Frame */
- a->element = 0;
- a->src += a->frame_delta[0];
- a->dest += a->frame_delta[1];
- a->frame ++;
-
- /* If the channel is frame synchronized, deactivate it */
- if (ch->sync && ch->fs && !ch->bs)
- omap_dma_deactivate_channel(s, ch);
-
- /* If the channel is async, update cpc */
- if (!ch->sync)
- ch->cpc = a->dest & 0xffff;
-
- /* Set the END_FRAME interrupt */
- if (ch->interrupts & END_FRAME_INTR)
- ch->status |= END_FRAME_INTR;
-
- if (a->frame == a->frames) {
- /* End of Block */
- /* Disable the channel */
-
- if (ch->omap_3_1_compatible_disable) {
- omap_dma_disable_channel(s, ch);
- if (ch->link_enabled)
- omap_dma_enable_channel(s,
- &s->ch[ch->link_next_ch]);
- } else {
- if (!ch->auto_init)
- omap_dma_disable_channel(s, ch);
- else if (ch->repeat || ch->end_prog)
- omap_dma_channel_load(ch);
- else {
- ch->waiting_end_prog = 1;
- omap_dma_deactivate_channel(s, ch);
- }
- }
-
- if (ch->interrupts & END_BLOCK_INTR)
- ch->status |= END_BLOCK_INTR;
- }
- }
- } while (status == ch->status && ch->active);
-
- omap_dma_interrupts_update(s);
-#endif
-}
-
-enum {
- omap_dma_intr_element_sync,
- omap_dma_intr_last_frame,
- omap_dma_intr_half_frame,
- omap_dma_intr_frame,
- omap_dma_intr_frame_sync,
- omap_dma_intr_packet,
- omap_dma_intr_packet_sync,
- omap_dma_intr_block,
- __omap_dma_intr_last,
-};
-
-static void omap_dma_transfer_setup(struct soc_dma_ch_s *dma)
-{
- struct omap_dma_port_if_s *src_p, *dest_p;
- struct omap_dma_reg_set_s *a;
- struct omap_dma_channel_s *ch = dma->opaque;
- struct omap_dma_s *s = dma->dma->opaque;
- int frames, min_elems, elements[__omap_dma_intr_last];
-
- a = &ch->active_set;
-
- src_p = &s->mpu->port[ch->port[0]];
- dest_p = &s->mpu->port[ch->port[1]];
- if ((!ch->constant_fill && !src_p->addr_valid(s->mpu, a->src)) ||
- (!dest_p->addr_valid(s->mpu, a->dest))) {
-#if 0
- /* Bus time-out */
- if (ch->interrupts & TIMEOUT_INTR)
- ch->status |= TIMEOUT_INTR;
- omap_dma_deactivate_channel(s, ch);
- continue;
-#endif
- printf("%s: Bus time-out in DMA%i operation\n",
- __FUNCTION__, dma->num);
- }
-
- min_elems = INT_MAX;
-
- /* Check all the conditions that terminate the transfer starting
- * with those that can occur the soonest. */
-#define INTR_CHECK(cond, id, nelements) \
- if (cond) { \
- elements[id] = nelements; \
- if (elements[id] < min_elems) \
- min_elems = elements[id]; \
- } else \
- elements[id] = INT_MAX;
-
- /* Elements */
- INTR_CHECK(
- ch->sync && !ch->fs && !ch->bs,
- omap_dma_intr_element_sync,
- 1)
-
- /* Frames */
- /* TODO: for transfers where entire frames can be read and written
- * using memcpy() but a->frame_delta is non-zero, try to still do
- * transfers using soc_dma but limit min_elems to a->elements - ...
- * See also the TODO in omap_dma_channel_load. */
- INTR_CHECK(
- (ch->interrupts & LAST_FRAME_INTR) &&
- ((a->frame < a->frames - 1) || !a->element),
- omap_dma_intr_last_frame,
- (a->frames - a->frame - 2) * a->elements +
- (a->elements - a->element + 1))
- INTR_CHECK(
- ch->interrupts & HALF_FRAME_INTR,
- omap_dma_intr_half_frame,
- (a->elements >> 1) +
- (a->element >= (a->elements >> 1) ? a->elements : 0) -
- a->element)
- INTR_CHECK(
- ch->sync && ch->fs && (ch->interrupts & END_FRAME_INTR),
- omap_dma_intr_frame,
- a->elements - a->element)
- INTR_CHECK(
- ch->sync && ch->fs && !ch->bs,
- omap_dma_intr_frame_sync,
- a->elements - a->element)
-
- /* Packets */
- INTR_CHECK(
- ch->fs && ch->bs &&
- (ch->interrupts & END_PKT_INTR) && !ch->src_sync,
- omap_dma_intr_packet,
- a->pck_elements - a->pck_element)
- INTR_CHECK(
- ch->fs && ch->bs && ch->sync,
- omap_dma_intr_packet_sync,
- a->pck_elements - a->pck_element)
-
- /* Blocks */
- INTR_CHECK(
- 1,
- omap_dma_intr_block,
- (a->frames - a->frame - 1) * a->elements +
- (a->elements - a->element))
-
- dma->bytes = min_elems * ch->data_type;
-
- /* Set appropriate interrupts and/or deactivate channels */
-
-#ifdef MULTI_REQ
- /* TODO: should all of this only be done if dma->update, and otherwise
- * inside omap_dma_transfer_generic below - check what's faster. */
- if (dma->update) {
-#endif
-
- /* If the channel is element synchronized, deactivate it */
- if (min_elems == elements[omap_dma_intr_element_sync])
- omap_dma_deactivate_channel(s, ch);
-
- /* If it is the last frame, set the LAST_FRAME interrupt */
- if (min_elems == elements[omap_dma_intr_last_frame])
- ch->status |= LAST_FRAME_INTR;
-
- /* If exactly half of the frame was reached, set the HALF_FRAME
- interrupt */
- if (min_elems == elements[omap_dma_intr_half_frame])
- ch->status |= HALF_FRAME_INTR;
-
- /* If a full packet has been transferred, set the END_PKT interrupt */
- if (min_elems == elements[omap_dma_intr_packet])
- ch->status |= END_PKT_INTR;
-
- /* If the channel is packet-synchronized, deactivate it */
- if (min_elems == elements[omap_dma_intr_packet_sync])
- omap_dma_deactivate_channel(s, ch);
-
- /* If the channel is frame synchronized, deactivate it */
- if (min_elems == elements[omap_dma_intr_frame_sync])
- omap_dma_deactivate_channel(s, ch);
-
- /* Set the END_FRAME interrupt */
- if (min_elems == elements[omap_dma_intr_frame])
- ch->status |= END_FRAME_INTR;
-
- if (min_elems == elements[omap_dma_intr_block]) {
- /* End of Block */
- /* Disable the channel */
-
- if (ch->omap_3_1_compatible_disable) {
- omap_dma_disable_channel(s, ch);
- if (ch->link_enabled)
- omap_dma_enable_channel(s, &s->ch[ch->link_next_ch]);
- } else {
- if (!ch->auto_init)
- omap_dma_disable_channel(s, ch);
- else if (ch->repeat || ch->end_prog)
- omap_dma_channel_load(ch);
- else {
- ch->waiting_end_prog = 1;
- omap_dma_deactivate_channel(s, ch);
- }
- }
-
- if (ch->interrupts & END_BLOCK_INTR)
- ch->status |= END_BLOCK_INTR;
- }
-
- /* Update packet number */
- if (ch->fs && ch->bs) {
- a->pck_element += min_elems;
- a->pck_element %= a->pck_elements;
- }
-
- /* TODO: check if we really need to update anything here or perhaps we
- * can skip part of this. */
-#ifndef MULTI_REQ
- if (dma->update) {
-#endif
- a->element += min_elems;
-
- frames = a->element / a->elements;
- a->element = a->element % a->elements;
- a->frame += frames;
- a->src += min_elems * a->elem_delta[0] + frames * a->frame_delta[0];
- a->dest += min_elems * a->elem_delta[1] + frames * a->frame_delta[1];
-
- /* If the channel is async, update cpc */
- if (!ch->sync && frames)
- ch->cpc = a->dest & 0xffff;
-
- /* TODO: if the destination port is IMIF or EMIFF, set the dirty
- * bits on it. */
-#ifndef MULTI_REQ
- }
-#else
- }
-#endif
-
- omap_dma_interrupts_update(s);
-}
-
-void omap_dma_reset(struct soc_dma_s *dma)
-{
- int i;
- struct omap_dma_s *s = dma->opaque;
-
- soc_dma_reset(s->dma);
- if (s->model < omap_dma_4)
- s->gcr = 0x0004;
- else
- s->gcr = 0x00010010;
- s->ocp = 0x00000000;
- memset(&s->irqstat, 0, sizeof(s->irqstat));
- memset(&s->irqen, 0, sizeof(s->irqen));
- s->lcd_ch.src = emiff;
- s->lcd_ch.condition = 0;
- s->lcd_ch.interrupts = 0;
- s->lcd_ch.dual = 0;
- if (s->model < omap_dma_4)
- omap_dma_enable_3_1_mapping(s);
- for (i = 0; i < s->chans; i ++) {
- s->ch[i].suspend = 0;
- s->ch[i].prefetch = 0;
- s->ch[i].buf_disable = 0;
- s->ch[i].src_sync = 0;
- memset(&s->ch[i].burst, 0, sizeof(s->ch[i].burst));
- memset(&s->ch[i].port, 0, sizeof(s->ch[i].port));
- memset(&s->ch[i].mode, 0, sizeof(s->ch[i].mode));
- memset(&s->ch[i].frame_index, 0, sizeof(s->ch[i].frame_index));
- memset(&s->ch[i].element_index, 0, sizeof(s->ch[i].element_index));
- memset(&s->ch[i].endian, 0, sizeof(s->ch[i].endian));
- memset(&s->ch[i].endian_lock, 0, sizeof(s->ch[i].endian_lock));
- memset(&s->ch[i].translate, 0, sizeof(s->ch[i].translate));
- s->ch[i].write_mode = 0;
- s->ch[i].data_type = 0;
- s->ch[i].transparent_copy = 0;
- s->ch[i].constant_fill = 0;
- s->ch[i].color = 0x00000000;
- s->ch[i].end_prog = 0;
- s->ch[i].repeat = 0;
- s->ch[i].auto_init = 0;
- s->ch[i].link_enabled = 0;
- if (s->model < omap_dma_4)
- s->ch[i].interrupts = 0x0003;
- else
- s->ch[i].interrupts = 0x0000;
- s->ch[i].status = 0;
- s->ch[i].cstatus = 0;
- s->ch[i].active = 0;
- s->ch[i].enable = 0;
- s->ch[i].sync = 0;
- s->ch[i].pending_request = 0;
- s->ch[i].waiting_end_prog = 0;
- s->ch[i].cpc = 0x0000;
- s->ch[i].fs = 0;
- s->ch[i].bs = 0;
- s->ch[i].omap_3_1_compatible_disable = 0;
- memset(&s->ch[i].active_set, 0, sizeof(s->ch[i].active_set));
- s->ch[i].priority = 0;
- s->ch[i].interleave_disabled = 0;
- s->ch[i].type = 0;
- }
-}
-
-static int omap_dma_ch_reg_read(struct omap_dma_s *s,
- struct omap_dma_channel_s *ch, int reg, uint16_t *value)
-{
- switch (reg) {
- case 0x00: /* SYS_DMA_CSDP_CH0 */
- *value = (ch->burst[1] << 14) |
- (ch->pack[1] << 13) |
- (ch->port[1] << 9) |
- (ch->burst[0] << 7) |
- (ch->pack[0] << 6) |
- (ch->port[0] << 2) |
- (ch->data_type >> 1);
- break;
-
- case 0x02: /* SYS_DMA_CCR_CH0 */
- if (s->model <= omap_dma_3_1)
- *value = 0 << 10; /* FIFO_FLUSH reads as 0 */
- else
- *value = ch->omap_3_1_compatible_disable << 10;
- *value |= (ch->mode[1] << 14) |
- (ch->mode[0] << 12) |
- (ch->end_prog << 11) |
- (ch->repeat << 9) |
- (ch->auto_init << 8) |
- (ch->enable << 7) |
- (ch->priority << 6) |
- (ch->fs << 5) | ch->sync;
- break;
-
- case 0x04: /* SYS_DMA_CICR_CH0 */
- *value = ch->interrupts;
- break;
-
- case 0x06: /* SYS_DMA_CSR_CH0 */
- *value = ch->status;
- ch->status &= SYNC;
- if (!ch->omap_3_1_compatible_disable && ch->sibling) {
- *value |= (ch->sibling->status & 0x3f) << 6;
- ch->sibling->status &= SYNC;
- }
- qemu_irq_lower(ch->irq);
- break;
-
- case 0x08: /* SYS_DMA_CSSA_L_CH0 */
- *value = ch->addr[0] & 0x0000ffff;
- break;
-
- case 0x0a: /* SYS_DMA_CSSA_U_CH0 */
- *value = ch->addr[0] >> 16;
- break;
-
- case 0x0c: /* SYS_DMA_CDSA_L_CH0 */
- *value = ch->addr[1] & 0x0000ffff;
- break;
-
- case 0x0e: /* SYS_DMA_CDSA_U_CH0 */
- *value = ch->addr[1] >> 16;
- break;
-
- case 0x10: /* SYS_DMA_CEN_CH0 */
- *value = ch->elements;
- break;
-
- case 0x12: /* SYS_DMA_CFN_CH0 */
- *value = ch->frames;
- break;
-
- case 0x14: /* SYS_DMA_CFI_CH0 */
- *value = ch->frame_index[0];
- break;
-
- case 0x16: /* SYS_DMA_CEI_CH0 */
- *value = ch->element_index[0];
- break;
-
- case 0x18: /* SYS_DMA_CPC_CH0 or DMA_CSAC */
- if (ch->omap_3_1_compatible_disable)
- *value = ch->active_set.src & 0xffff; /* CSAC */
- else
- *value = ch->cpc;
- break;
-
- case 0x1a: /* DMA_CDAC */
- *value = ch->active_set.dest & 0xffff; /* CDAC */
- break;
-
- case 0x1c: /* DMA_CDEI */
- *value = ch->element_index[1];
- break;
-
- case 0x1e: /* DMA_CDFI */
- *value = ch->frame_index[1];
- break;
-
- case 0x20: /* DMA_COLOR_L */
- *value = ch->color & 0xffff;
- break;
-
- case 0x22: /* DMA_COLOR_U */
- *value = ch->color >> 16;
- break;
-
- case 0x24: /* DMA_CCR2 */
- *value = (ch->bs << 2) |
- (ch->transparent_copy << 1) |
- ch->constant_fill;
- break;
-
- case 0x28: /* DMA_CLNK_CTRL */
- *value = (ch->link_enabled << 15) |
- (ch->link_next_ch & 0xf);
- break;
-
- case 0x2a: /* DMA_LCH_CTRL */
- *value = (ch->interleave_disabled << 15) |
- ch->type;
- break;
-
- default:
- return 1;
- }
- return 0;
-}
-
-static int omap_dma_ch_reg_write(struct omap_dma_s *s,
- struct omap_dma_channel_s *ch, int reg, uint16_t value)
-{
- switch (reg) {
- case 0x00: /* SYS_DMA_CSDP_CH0 */
- ch->burst[1] = (value & 0xc000) >> 14;
- ch->pack[1] = (value & 0x2000) >> 13;
- ch->port[1] = (enum omap_dma_port) ((value & 0x1e00) >> 9);
- ch->burst[0] = (value & 0x0180) >> 7;
- ch->pack[0] = (value & 0x0040) >> 6;
- ch->port[0] = (enum omap_dma_port) ((value & 0x003c) >> 2);
- ch->data_type = 1 << (value & 3);
- if (ch->port[0] >= __omap_dma_port_last)
- printf("%s: invalid DMA port %i\n", __FUNCTION__,
- ch->port[0]);
- if (ch->port[1] >= __omap_dma_port_last)
- printf("%s: invalid DMA port %i\n", __FUNCTION__,
- ch->port[1]);
- if ((value & 3) == 3)
- printf("%s: bad data_type for DMA channel\n", __FUNCTION__);
- break;
-
- case 0x02: /* SYS_DMA_CCR_CH0 */
- ch->mode[1] = (omap_dma_addressing_t) ((value & 0xc000) >> 14);
- ch->mode[0] = (omap_dma_addressing_t) ((value & 0x3000) >> 12);
- ch->end_prog = (value & 0x0800) >> 11;
- if (s->model >= omap_dma_3_2)
- ch->omap_3_1_compatible_disable = (value >> 10) & 0x1;
- ch->repeat = (value & 0x0200) >> 9;
- ch->auto_init = (value & 0x0100) >> 8;
- ch->priority = (value & 0x0040) >> 6;
- ch->fs = (value & 0x0020) >> 5;
- ch->sync = value & 0x001f;
-
- if (value & 0x0080)
- omap_dma_enable_channel(s, ch);
- else
- omap_dma_disable_channel(s, ch);
-
- if (ch->end_prog)
- omap_dma_channel_end_prog(s, ch);
-
- break;
-
- case 0x04: /* SYS_DMA_CICR_CH0 */
- ch->interrupts = value & 0x3f;
- break;
-
- case 0x06: /* SYS_DMA_CSR_CH0 */
- OMAP_RO_REG((hwaddr) reg);
- break;
-
- case 0x08: /* SYS_DMA_CSSA_L_CH0 */
- ch->addr[0] &= 0xffff0000;
- ch->addr[0] |= value;
- break;
-
- case 0x0a: /* SYS_DMA_CSSA_U_CH0 */
- ch->addr[0] &= 0x0000ffff;
- ch->addr[0] |= (uint32_t) value << 16;
- break;
-
- case 0x0c: /* SYS_DMA_CDSA_L_CH0 */
- ch->addr[1] &= 0xffff0000;
- ch->addr[1] |= value;
- break;
-
- case 0x0e: /* SYS_DMA_CDSA_U_CH0 */
- ch->addr[1] &= 0x0000ffff;
- ch->addr[1] |= (uint32_t) value << 16;
- break;
-
- case 0x10: /* SYS_DMA_CEN_CH0 */
- ch->elements = value;
- break;
-
- case 0x12: /* SYS_DMA_CFN_CH0 */
- ch->frames = value;
- break;
-
- case 0x14: /* SYS_DMA_CFI_CH0 */
- ch->frame_index[0] = (int16_t) value;
- break;
-
- case 0x16: /* SYS_DMA_CEI_CH0 */
- ch->element_index[0] = (int16_t) value;
- break;
-
- case 0x18: /* SYS_DMA_CPC_CH0 or DMA_CSAC */
- OMAP_RO_REG((hwaddr) reg);
- break;
-
- case 0x1c: /* DMA_CDEI */
- ch->element_index[1] = (int16_t) value;
- break;
-
- case 0x1e: /* DMA_CDFI */
- ch->frame_index[1] = (int16_t) value;
- break;
-
- case 0x20: /* DMA_COLOR_L */
- ch->color &= 0xffff0000;
- ch->color |= value;
- break;
-
- case 0x22: /* DMA_COLOR_U */
- ch->color &= 0xffff;
- ch->color |= (uint32_t)value << 16;
- break;
-
- case 0x24: /* DMA_CCR2 */
- ch->bs = (value >> 2) & 0x1;
- ch->transparent_copy = (value >> 1) & 0x1;
- ch->constant_fill = value & 0x1;
- break;
-
- case 0x28: /* DMA_CLNK_CTRL */
- ch->link_enabled = (value >> 15) & 0x1;
- if (value & (1 << 14)) { /* Stop_Lnk */
- ch->link_enabled = 0;
- omap_dma_disable_channel(s, ch);
- }
- ch->link_next_ch = value & 0x1f;
- break;
-
- case 0x2a: /* DMA_LCH_CTRL */
- ch->interleave_disabled = (value >> 15) & 0x1;
- ch->type = value & 0xf;
- break;
-
- default:
- return 1;
- }
- return 0;
-}
-
-static int omap_dma_3_2_lcd_write(struct omap_dma_lcd_channel_s *s, int offset,
- uint16_t value)
-{
- switch (offset) {
- case 0xbc0: /* DMA_LCD_CSDP */
- s->brust_f2 = (value >> 14) & 0x3;
- s->pack_f2 = (value >> 13) & 0x1;
- s->data_type_f2 = (1 << ((value >> 11) & 0x3));
- s->brust_f1 = (value >> 7) & 0x3;
- s->pack_f1 = (value >> 6) & 0x1;
- s->data_type_f1 = (1 << ((value >> 0) & 0x3));
- break;
-
- case 0xbc2: /* DMA_LCD_CCR */
- s->mode_f2 = (value >> 14) & 0x3;
- s->mode_f1 = (value >> 12) & 0x3;
- s->end_prog = (value >> 11) & 0x1;
- s->omap_3_1_compatible_disable = (value >> 10) & 0x1;
- s->repeat = (value >> 9) & 0x1;
- s->auto_init = (value >> 8) & 0x1;
- s->running = (value >> 7) & 0x1;
- s->priority = (value >> 6) & 0x1;
- s->bs = (value >> 4) & 0x1;
- break;
-
- case 0xbc4: /* DMA_LCD_CTRL */
- s->dst = (value >> 8) & 0x1;
- s->src = ((value >> 6) & 0x3) << 1;
- s->condition = 0;
- /* Assume no bus errors and thus no BUS_ERROR irq bits. */
- s->interrupts = (value >> 1) & 1;
- s->dual = value & 1;
- break;
-
- case 0xbc8: /* TOP_B1_L */
- s->src_f1_top &= 0xffff0000;
- s->src_f1_top |= 0x0000ffff & value;
- break;
-
- case 0xbca: /* TOP_B1_U */
- s->src_f1_top &= 0x0000ffff;
- s->src_f1_top |= (uint32_t)value << 16;
- break;
-
- case 0xbcc: /* BOT_B1_L */
- s->src_f1_bottom &= 0xffff0000;
- s->src_f1_bottom |= 0x0000ffff & value;
- break;
-
- case 0xbce: /* BOT_B1_U */
- s->src_f1_bottom &= 0x0000ffff;
- s->src_f1_bottom |= (uint32_t) value << 16;
- break;
-
- case 0xbd0: /* TOP_B2_L */
- s->src_f2_top &= 0xffff0000;
- s->src_f2_top |= 0x0000ffff & value;
- break;
-
- case 0xbd2: /* TOP_B2_U */
- s->src_f2_top &= 0x0000ffff;
- s->src_f2_top |= (uint32_t) value << 16;
- break;
-
- case 0xbd4: /* BOT_B2_L */
- s->src_f2_bottom &= 0xffff0000;
- s->src_f2_bottom |= 0x0000ffff & value;
- break;
-
- case 0xbd6: /* BOT_B2_U */
- s->src_f2_bottom &= 0x0000ffff;
- s->src_f2_bottom |= (uint32_t) value << 16;
- break;
-
- case 0xbd8: /* DMA_LCD_SRC_EI_B1 */
- s->element_index_f1 = value;
- break;
-
- case 0xbda: /* DMA_LCD_SRC_FI_B1_L */
- s->frame_index_f1 &= 0xffff0000;
- s->frame_index_f1 |= 0x0000ffff & value;
- break;
-
- case 0xbf4: /* DMA_LCD_SRC_FI_B1_U */
- s->frame_index_f1 &= 0x0000ffff;
- s->frame_index_f1 |= (uint32_t) value << 16;
- break;
-
- case 0xbdc: /* DMA_LCD_SRC_EI_B2 */
- s->element_index_f2 = value;
- break;
-
- case 0xbde: /* DMA_LCD_SRC_FI_B2_L */
- s->frame_index_f2 &= 0xffff0000;
- s->frame_index_f2 |= 0x0000ffff & value;
- break;
-
- case 0xbf6: /* DMA_LCD_SRC_FI_B2_U */
- s->frame_index_f2 &= 0x0000ffff;
- s->frame_index_f2 |= (uint32_t) value << 16;
- break;
-
- case 0xbe0: /* DMA_LCD_SRC_EN_B1 */
- s->elements_f1 = value;
- break;
-
- case 0xbe4: /* DMA_LCD_SRC_FN_B1 */
- s->frames_f1 = value;
- break;
-
- case 0xbe2: /* DMA_LCD_SRC_EN_B2 */
- s->elements_f2 = value;
- break;
-
- case 0xbe6: /* DMA_LCD_SRC_FN_B2 */
- s->frames_f2 = value;
- break;
-
- case 0xbea: /* DMA_LCD_LCH_CTRL */
- s->lch_type = value & 0xf;
- break;
-
- default:
- return 1;
- }
- return 0;
-}
-
-static int omap_dma_3_2_lcd_read(struct omap_dma_lcd_channel_s *s, int offset,
- uint16_t *ret)
-{
- switch (offset) {
- case 0xbc0: /* DMA_LCD_CSDP */
- *ret = (s->brust_f2 << 14) |
- (s->pack_f2 << 13) |
- ((s->data_type_f2 >> 1) << 11) |
- (s->brust_f1 << 7) |
- (s->pack_f1 << 6) |
- ((s->data_type_f1 >> 1) << 0);
- break;
-
- case 0xbc2: /* DMA_LCD_CCR */
- *ret = (s->mode_f2 << 14) |
- (s->mode_f1 << 12) |
- (s->end_prog << 11) |
- (s->omap_3_1_compatible_disable << 10) |
- (s->repeat << 9) |
- (s->auto_init << 8) |
- (s->running << 7) |
- (s->priority << 6) |
- (s->bs << 4);
- break;
-
- case 0xbc4: /* DMA_LCD_CTRL */
- qemu_irq_lower(s->irq);
- *ret = (s->dst << 8) |
- ((s->src & 0x6) << 5) |
- (s->condition << 3) |
- (s->interrupts << 1) |
- s->dual;
- break;
-
- case 0xbc8: /* TOP_B1_L */
- *ret = s->src_f1_top & 0xffff;
- break;
-
- case 0xbca: /* TOP_B1_U */
- *ret = s->src_f1_top >> 16;
- break;
-
- case 0xbcc: /* BOT_B1_L */
- *ret = s->src_f1_bottom & 0xffff;
- break;
-
- case 0xbce: /* BOT_B1_U */
- *ret = s->src_f1_bottom >> 16;
- break;
-
- case 0xbd0: /* TOP_B2_L */
- *ret = s->src_f2_top & 0xffff;
- break;
-
- case 0xbd2: /* TOP_B2_U */
- *ret = s->src_f2_top >> 16;
- break;
-
- case 0xbd4: /* BOT_B2_L */
- *ret = s->src_f2_bottom & 0xffff;
- break;
-
- case 0xbd6: /* BOT_B2_U */
- *ret = s->src_f2_bottom >> 16;
- break;
-
- case 0xbd8: /* DMA_LCD_SRC_EI_B1 */
- *ret = s->element_index_f1;
- break;
-
- case 0xbda: /* DMA_LCD_SRC_FI_B1_L */
- *ret = s->frame_index_f1 & 0xffff;
- break;
-
- case 0xbf4: /* DMA_LCD_SRC_FI_B1_U */
- *ret = s->frame_index_f1 >> 16;
- break;
-
- case 0xbdc: /* DMA_LCD_SRC_EI_B2 */
- *ret = s->element_index_f2;
- break;
-
- case 0xbde: /* DMA_LCD_SRC_FI_B2_L */
- *ret = s->frame_index_f2 & 0xffff;
- break;
-
- case 0xbf6: /* DMA_LCD_SRC_FI_B2_U */
- *ret = s->frame_index_f2 >> 16;
- break;
-
- case 0xbe0: /* DMA_LCD_SRC_EN_B1 */
- *ret = s->elements_f1;
- break;
-
- case 0xbe4: /* DMA_LCD_SRC_FN_B1 */
- *ret = s->frames_f1;
- break;
-
- case 0xbe2: /* DMA_LCD_SRC_EN_B2 */
- *ret = s->elements_f2;
- break;
-
- case 0xbe6: /* DMA_LCD_SRC_FN_B2 */
- *ret = s->frames_f2;
- break;
-
- case 0xbea: /* DMA_LCD_LCH_CTRL */
- *ret = s->lch_type;
- break;
-
- default:
- return 1;
- }
- return 0;
-}
-
-static int omap_dma_3_1_lcd_write(struct omap_dma_lcd_channel_s *s, int offset,
- uint16_t value)
-{
- switch (offset) {
- case 0x300: /* SYS_DMA_LCD_CTRL */
- s->src = (value & 0x40) ? imif : emiff;
- s->condition = 0;
- /* Assume no bus errors and thus no BUS_ERROR irq bits. */
- s->interrupts = (value >> 1) & 1;
- s->dual = value & 1;
- break;
-
- case 0x302: /* SYS_DMA_LCD_TOP_F1_L */
- s->src_f1_top &= 0xffff0000;
- s->src_f1_top |= 0x0000ffff & value;
- break;
-
- case 0x304: /* SYS_DMA_LCD_TOP_F1_U */
- s->src_f1_top &= 0x0000ffff;
- s->src_f1_top |= (uint32_t)value << 16;
- break;
-
- case 0x306: /* SYS_DMA_LCD_BOT_F1_L */
- s->src_f1_bottom &= 0xffff0000;
- s->src_f1_bottom |= 0x0000ffff & value;
- break;
-
- case 0x308: /* SYS_DMA_LCD_BOT_F1_U */
- s->src_f1_bottom &= 0x0000ffff;
- s->src_f1_bottom |= (uint32_t)value << 16;
- break;
-
- case 0x30a: /* SYS_DMA_LCD_TOP_F2_L */
- s->src_f2_top &= 0xffff0000;
- s->src_f2_top |= 0x0000ffff & value;
- break;
-
- case 0x30c: /* SYS_DMA_LCD_TOP_F2_U */
- s->src_f2_top &= 0x0000ffff;
- s->src_f2_top |= (uint32_t)value << 16;
- break;
-
- case 0x30e: /* SYS_DMA_LCD_BOT_F2_L */
- s->src_f2_bottom &= 0xffff0000;
- s->src_f2_bottom |= 0x0000ffff & value;
- break;
-
- case 0x310: /* SYS_DMA_LCD_BOT_F2_U */
- s->src_f2_bottom &= 0x0000ffff;
- s->src_f2_bottom |= (uint32_t)value << 16;
- break;
-
- default:
- return 1;
- }
- return 0;
-}
-
-static int omap_dma_3_1_lcd_read(struct omap_dma_lcd_channel_s *s, int offset,
- uint16_t *ret)
-{
- int i;
-
- switch (offset) {
- case 0x300: /* SYS_DMA_LCD_CTRL */
- i = s->condition;
- s->condition = 0;
- qemu_irq_lower(s->irq);
- *ret = ((s->src == imif) << 6) | (i << 3) |
- (s->interrupts << 1) | s->dual;
- break;
-
- case 0x302: /* SYS_DMA_LCD_TOP_F1_L */
- *ret = s->src_f1_top & 0xffff;
- break;
-
- case 0x304: /* SYS_DMA_LCD_TOP_F1_U */
- *ret = s->src_f1_top >> 16;
- break;
-
- case 0x306: /* SYS_DMA_LCD_BOT_F1_L */
- *ret = s->src_f1_bottom & 0xffff;
- break;
-
- case 0x308: /* SYS_DMA_LCD_BOT_F1_U */
- *ret = s->src_f1_bottom >> 16;
- break;
-
- case 0x30a: /* SYS_DMA_LCD_TOP_F2_L */
- *ret = s->src_f2_top & 0xffff;
- break;
-
- case 0x30c: /* SYS_DMA_LCD_TOP_F2_U */
- *ret = s->src_f2_top >> 16;
- break;
-
- case 0x30e: /* SYS_DMA_LCD_BOT_F2_L */
- *ret = s->src_f2_bottom & 0xffff;
- break;
-
- case 0x310: /* SYS_DMA_LCD_BOT_F2_U */
- *ret = s->src_f2_bottom >> 16;
- break;
-
- default:
- return 1;
- }
- return 0;
-}
-
-static int omap_dma_sys_write(struct omap_dma_s *s, int offset, uint16_t value)
-{
- switch (offset) {
- case 0x400: /* SYS_DMA_GCR */
- s->gcr = value;
- break;
-
- case 0x404: /* DMA_GSCR */
- if (value & 0x8)
- omap_dma_disable_3_1_mapping(s);
- else
- omap_dma_enable_3_1_mapping(s);
- break;
-
- case 0x408: /* DMA_GRST */
- if (value & 0x1)
- omap_dma_reset(s->dma);
- break;
-
- default:
- return 1;
- }
- return 0;
-}
-
-static int omap_dma_sys_read(struct omap_dma_s *s, int offset,
- uint16_t *ret)
-{
- switch (offset) {
- case 0x400: /* SYS_DMA_GCR */
- *ret = s->gcr;
- break;
-
- case 0x404: /* DMA_GSCR */
- *ret = s->omap_3_1_mapping_disabled << 3;
- break;
-
- case 0x408: /* DMA_GRST */
- *ret = 0;
- break;
-
- case 0x442: /* DMA_HW_ID */
- case 0x444: /* DMA_PCh2_ID */
- case 0x446: /* DMA_PCh0_ID */
- case 0x448: /* DMA_PCh1_ID */
- case 0x44a: /* DMA_PChG_ID */
- case 0x44c: /* DMA_PChD_ID */
- *ret = 1;
- break;
-
- case 0x44e: /* DMA_CAPS_0_U */
- *ret = (s->caps[0] >> 16) & 0xffff;
- break;
- case 0x450: /* DMA_CAPS_0_L */
- *ret = (s->caps[0] >> 0) & 0xffff;
- break;
-
- case 0x452: /* DMA_CAPS_1_U */
- *ret = (s->caps[1] >> 16) & 0xffff;
- break;
- case 0x454: /* DMA_CAPS_1_L */
- *ret = (s->caps[1] >> 0) & 0xffff;
- break;
-
- case 0x456: /* DMA_CAPS_2 */
- *ret = s->caps[2];
- break;
-
- case 0x458: /* DMA_CAPS_3 */
- *ret = s->caps[3];
- break;
-
- case 0x45a: /* DMA_CAPS_4 */
- *ret = s->caps[4];
- break;
-
- case 0x460: /* DMA_PCh2_SR */
- case 0x480: /* DMA_PCh0_SR */
- case 0x482: /* DMA_PCh1_SR */
- case 0x4c0: /* DMA_PChD_SR_0 */
- printf("%s: Physical Channel Status Registers not implemented.\n",
- __FUNCTION__);
- *ret = 0xff;
- break;
-
- default:
- return 1;
- }
- return 0;
-}
-
-static uint64_t omap_dma_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_dma_s *s = (struct omap_dma_s *) opaque;
- int reg, ch;
- uint16_t ret;
-
- if (size != 2) {
- return omap_badwidth_read16(opaque, addr);
- }
-
- switch (addr) {
- case 0x300 ... 0x3fe:
- if (s->model <= omap_dma_3_1 || !s->omap_3_1_mapping_disabled) {
- if (omap_dma_3_1_lcd_read(&s->lcd_ch, addr, &ret))
- break;
- return ret;
- }
- /* Fall through. */
- case 0x000 ... 0x2fe:
- reg = addr & 0x3f;
- ch = (addr >> 6) & 0x0f;
- if (omap_dma_ch_reg_read(s, &s->ch[ch], reg, &ret))
- break;
- return ret;
-
- case 0x404 ... 0x4fe:
- if (s->model <= omap_dma_3_1)
- break;
- /* Fall through. */
- case 0x400:
- if (omap_dma_sys_read(s, addr, &ret))
- break;
- return ret;
-
- case 0xb00 ... 0xbfe:
- if (s->model == omap_dma_3_2 && s->omap_3_1_mapping_disabled) {
- if (omap_dma_3_2_lcd_read(&s->lcd_ch, addr, &ret))
- break;
- return ret;
- }
- break;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_dma_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_dma_s *s = (struct omap_dma_s *) opaque;
- int reg, ch;
-
- if (size != 2) {
- omap_badwidth_write16(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x300 ... 0x3fe:
- if (s->model <= omap_dma_3_1 || !s->omap_3_1_mapping_disabled) {
- if (omap_dma_3_1_lcd_write(&s->lcd_ch, addr, value))
- break;
- return;
- }
- /* Fall through. */
- case 0x000 ... 0x2fe:
- reg = addr & 0x3f;
- ch = (addr >> 6) & 0x0f;
- if (omap_dma_ch_reg_write(s, &s->ch[ch], reg, value))
- break;
- return;
-
- case 0x404 ... 0x4fe:
- if (s->model <= omap_dma_3_1)
- break;
- case 0x400:
- /* Fall through. */
- if (omap_dma_sys_write(s, addr, value))
- break;
- return;
-
- case 0xb00 ... 0xbfe:
- if (s->model == omap_dma_3_2 && s->omap_3_1_mapping_disabled) {
- if (omap_dma_3_2_lcd_write(&s->lcd_ch, addr, value))
- break;
- return;
- }
- break;
- }
-
- OMAP_BAD_REG(addr);
-}
-
-static const MemoryRegionOps omap_dma_ops = {
- .read = omap_dma_read,
- .write = omap_dma_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void omap_dma_request(void *opaque, int drq, int req)
-{
- struct omap_dma_s *s = (struct omap_dma_s *) opaque;
- /* The request pins are level triggered in QEMU. */
- if (req) {
- if (~s->dma->drqbmp & (1ULL << drq)) {
- s->dma->drqbmp |= 1ULL << drq;
- omap_dma_process_request(s, drq);
- }
- } else
- s->dma->drqbmp &= ~(1ULL << drq);
-}
-
-/* XXX: this won't be needed once soc_dma knows about clocks. */
-static void omap_dma_clk_update(void *opaque, int line, int on)
-{
- struct omap_dma_s *s = (struct omap_dma_s *) opaque;
- int i;
-
- s->dma->freq = omap_clk_getrate(s->clk);
-
- for (i = 0; i < s->chans; i ++)
- if (s->ch[i].active)
- soc_dma_set_request(s->ch[i].dma, on);
-}
-
-static void omap_dma_setcaps(struct omap_dma_s *s)
-{
- switch (s->model) {
- default:
- case omap_dma_3_1:
- break;
- case omap_dma_3_2:
- case omap_dma_4:
- /* XXX Only available for sDMA */
- s->caps[0] =
- (1 << 19) | /* Constant Fill Capability */
- (1 << 18); /* Transparent BLT Capability */
- s->caps[1] =
- (1 << 1); /* 1-bit palettized capability (DMA 3.2 only) */
- s->caps[2] =
- (1 << 8) | /* SEPARATE_SRC_AND_DST_INDEX_CPBLTY */
- (1 << 7) | /* DST_DOUBLE_INDEX_ADRS_CPBLTY */
- (1 << 6) | /* DST_SINGLE_INDEX_ADRS_CPBLTY */
- (1 << 5) | /* DST_POST_INCRMNT_ADRS_CPBLTY */
- (1 << 4) | /* DST_CONST_ADRS_CPBLTY */
- (1 << 3) | /* SRC_DOUBLE_INDEX_ADRS_CPBLTY */
- (1 << 2) | /* SRC_SINGLE_INDEX_ADRS_CPBLTY */
- (1 << 1) | /* SRC_POST_INCRMNT_ADRS_CPBLTY */
- (1 << 0); /* SRC_CONST_ADRS_CPBLTY */
- s->caps[3] =
- (1 << 6) | /* BLOCK_SYNCHR_CPBLTY (DMA 4 only) */
- (1 << 7) | /* PKT_SYNCHR_CPBLTY (DMA 4 only) */
- (1 << 5) | /* CHANNEL_CHAINING_CPBLTY */
- (1 << 4) | /* LCh_INTERLEAVE_CPBLTY */
- (1 << 3) | /* AUTOINIT_REPEAT_CPBLTY (DMA 3.2 only) */
- (1 << 2) | /* AUTOINIT_ENDPROG_CPBLTY (DMA 3.2 only) */
- (1 << 1) | /* FRAME_SYNCHR_CPBLTY */
- (1 << 0); /* ELMNT_SYNCHR_CPBLTY */
- s->caps[4] =
- (1 << 7) | /* PKT_INTERRUPT_CPBLTY (DMA 4 only) */
- (1 << 6) | /* SYNC_STATUS_CPBLTY */
- (1 << 5) | /* BLOCK_INTERRUPT_CPBLTY */
- (1 << 4) | /* LAST_FRAME_INTERRUPT_CPBLTY */
- (1 << 3) | /* FRAME_INTERRUPT_CPBLTY */
- (1 << 2) | /* HALF_FRAME_INTERRUPT_CPBLTY */
- (1 << 1) | /* EVENT_DROP_INTERRUPT_CPBLTY */
- (1 << 0); /* TIMEOUT_INTERRUPT_CPBLTY (DMA 3.2 only) */
- break;
- }
-}
-
-struct soc_dma_s *omap_dma_init(hwaddr base, qemu_irq *irqs,
- MemoryRegion *sysmem,
- qemu_irq lcd_irq, struct omap_mpu_state_s *mpu, omap_clk clk,
- enum omap_dma_model model)
-{
- int num_irqs, memsize, i;
- struct omap_dma_s *s = g_new0(struct omap_dma_s, 1);
-
- if (model <= omap_dma_3_1) {
- num_irqs = 6;
- memsize = 0x800;
- } else {
- num_irqs = 16;
- memsize = 0xc00;
- }
- s->model = model;
- s->mpu = mpu;
- s->clk = clk;
- s->lcd_ch.irq = lcd_irq;
- s->lcd_ch.mpu = mpu;
-
- s->dma = soc_dma_init((model <= omap_dma_3_1) ? 9 : 16);
- s->dma->freq = omap_clk_getrate(clk);
- s->dma->transfer_fn = omap_dma_transfer_generic;
- s->dma->setup_fn = omap_dma_transfer_setup;
- s->dma->drq = qemu_allocate_irqs(omap_dma_request, s, 32);
- s->dma->opaque = s;
-
- while (num_irqs --)
- s->ch[num_irqs].irq = irqs[num_irqs];
- for (i = 0; i < 3; i ++) {
- s->ch[i].sibling = &s->ch[i + 6];
- s->ch[i + 6].sibling = &s->ch[i];
- }
- for (i = (model <= omap_dma_3_1) ? 8 : 15; i >= 0; i --) {
- s->ch[i].dma = &s->dma->ch[i];
- s->dma->ch[i].opaque = &s->ch[i];
- }
-
- omap_dma_setcaps(s);
- omap_clk_adduser(s->clk, qemu_allocate_irq(omap_dma_clk_update, s, 0));
- omap_dma_reset(s->dma);
- omap_dma_clk_update(s, 0, 1);
-
- memory_region_init_io(&s->iomem, NULL, &omap_dma_ops, s, "omap.dma", memsize);
- memory_region_add_subregion(sysmem, base, &s->iomem);
-
- mpu->drq = s->dma->drq;
-
- return s->dma;
-}
-
-static void omap_dma_interrupts_4_update(struct omap_dma_s *s)
-{
- struct omap_dma_channel_s *ch = s->ch;
- uint32_t bmp, bit;
-
- for (bmp = 0, bit = 1; bit; ch ++, bit <<= 1)
- if (ch->status) {
- bmp |= bit;
- ch->cstatus |= ch->status;
- ch->status = 0;
- }
- if ((s->irqstat[0] |= s->irqen[0] & bmp))
- qemu_irq_raise(s->irq[0]);
- if ((s->irqstat[1] |= s->irqen[1] & bmp))
- qemu_irq_raise(s->irq[1]);
- if ((s->irqstat[2] |= s->irqen[2] & bmp))
- qemu_irq_raise(s->irq[2]);
- if ((s->irqstat[3] |= s->irqen[3] & bmp))
- qemu_irq_raise(s->irq[3]);
-}
-
-static uint64_t omap_dma4_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_dma_s *s = (struct omap_dma_s *) opaque;
- int irqn = 0, chnum;
- struct omap_dma_channel_s *ch;
-
- if (size == 1) {
- return omap_badwidth_read16(opaque, addr);
- }
-
- switch (addr) {
- case 0x00: /* DMA4_REVISION */
- return 0x40;
-
- 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];
-
- case 0x28: /* DMA4_SYSSTATUS */
- return 1; /* RESETDONE */
-
- case 0x2c: /* DMA4_OCP_SYSCONFIG */
- return s->ocp;
-
- case 0x64: /* DMA4_CAPS_0 */
- return s->caps[0];
- case 0x6c: /* DMA4_CAPS_2 */
- return s->caps[2];
- case 0x70: /* DMA4_CAPS_3 */
- return s->caps[3];
- case 0x74: /* DMA4_CAPS_4 */
- return s->caps[4];
-
- case 0x78: /* DMA4_GCR */
- return s->gcr;
-
- case 0x80 ... 0xfff:
- addr -= 0x80;
- chnum = addr / 0x60;
- ch = s->ch + chnum;
- addr -= chnum * 0x60;
- break;
-
- default:
- OMAP_BAD_REG(addr);
- return 0;
- }
-
- /* Per-channel registers */
- switch (addr) {
- case 0x00: /* DMA4_CCR */
- return (ch->buf_disable << 25) |
- (ch->src_sync << 24) |
- (ch->prefetch << 23) |
- ((ch->sync & 0x60) << 14) |
- (ch->bs << 18) |
- (ch->transparent_copy << 17) |
- (ch->constant_fill << 16) |
- (ch->mode[1] << 14) |
- (ch->mode[0] << 12) |
- (0 << 10) | (0 << 9) |
- (ch->suspend << 8) |
- (ch->enable << 7) |
- (ch->priority << 6) |
- (ch->fs << 5) | (ch->sync & 0x1f);
-
- case 0x04: /* DMA4_CLNK_CTRL */
- return (ch->link_enabled << 15) | ch->link_next_ch;
-
- case 0x08: /* DMA4_CICR */
- return ch->interrupts;
-
- case 0x0c: /* DMA4_CSR */
- return ch->cstatus;
-
- case 0x10: /* DMA4_CSDP */
- return (ch->endian[0] << 21) |
- (ch->endian_lock[0] << 20) |
- (ch->endian[1] << 19) |
- (ch->endian_lock[1] << 18) |
- (ch->write_mode << 16) |
- (ch->burst[1] << 14) |
- (ch->pack[1] << 13) |
- (ch->translate[1] << 9) |
- (ch->burst[0] << 7) |
- (ch->pack[0] << 6) |
- (ch->translate[0] << 2) |
- (ch->data_type >> 1);
-
- case 0x14: /* DMA4_CEN */
- return ch->elements;
-
- case 0x18: /* DMA4_CFN */
- return ch->frames;
-
- case 0x1c: /* DMA4_CSSA */
- return ch->addr[0];
-
- case 0x20: /* DMA4_CDSA */
- return ch->addr[1];
-
- case 0x24: /* DMA4_CSEI */
- return ch->element_index[0];
-
- case 0x28: /* DMA4_CSFI */
- return ch->frame_index[0];
-
- case 0x2c: /* DMA4_CDEI */
- return ch->element_index[1];
-
- case 0x30: /* DMA4_CDFI */
- return ch->frame_index[1];
-
- case 0x34: /* DMA4_CSAC */
- return ch->active_set.src & 0xffff;
-
- case 0x38: /* DMA4_CDAC */
- return ch->active_set.dest & 0xffff;
-
- case 0x3c: /* DMA4_CCEN */
- return ch->active_set.element;
-
- case 0x40: /* DMA4_CCFN */
- return ch->active_set.frame;
-
- case 0x44: /* DMA4_COLOR */
- /* XXX only in sDMA */
- return ch->color;
-
- default:
- OMAP_BAD_REG(addr);
- return 0;
- }
-}
-
-static void omap_dma4_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_dma_s *s = (struct omap_dma_s *) opaque;
- int chnum, irqn = 0;
- struct omap_dma_channel_s *ch;
-
- if (size == 1) {
- omap_badwidth_write16(opaque, addr, value);
- return;
- }
-
- 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])
- qemu_irq_lower(s->irq[irqn]);
- return;
-
- 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;
-
- case 0x2c: /* DMA4_OCP_SYSCONFIG */
- if (value & 2) /* SOFTRESET */
- omap_dma_reset(s->dma);
- s->ocp = value & 0x3321;
- if (((s->ocp >> 12) & 3) == 3) /* MIDLEMODE */
- fprintf(stderr, "%s: invalid DMA power mode\n", __FUNCTION__);
- return;
-
- case 0x78: /* DMA4_GCR */
- s->gcr = value & 0x00ff00ff;
- if ((value & 0xff) == 0x00) /* MAX_CHANNEL_FIFO_DEPTH */
- fprintf(stderr, "%s: wrong FIFO depth in GCR\n", __FUNCTION__);
- return;
-
- case 0x80 ... 0xfff:
- addr -= 0x80;
- chnum = addr / 0x60;
- ch = s->ch + chnum;
- addr -= chnum * 0x60;
- break;
-
- case 0x00: /* DMA4_REVISION */
- case 0x28: /* DMA4_SYSSTATUS */
- case 0x64: /* DMA4_CAPS_0 */
- case 0x6c: /* DMA4_CAPS_2 */
- case 0x70: /* DMA4_CAPS_3 */
- case 0x74: /* DMA4_CAPS_4 */
- OMAP_RO_REG(addr);
- return;
-
- default:
- OMAP_BAD_REG(addr);
- return;
- }
-
- /* Per-channel registers */
- switch (addr) {
- case 0x00: /* DMA4_CCR */
- ch->buf_disable = (value >> 25) & 1;
- ch->src_sync = (value >> 24) & 1; /* XXX For CamDMA must be 1 */
- if (ch->buf_disable && !ch->src_sync)
- fprintf(stderr, "%s: Buffering disable is not allowed in "
- "destination synchronised mode\n", __FUNCTION__);
- ch->prefetch = (value >> 23) & 1;
- ch->bs = (value >> 18) & 1;
- ch->transparent_copy = (value >> 17) & 1;
- ch->constant_fill = (value >> 16) & 1;
- ch->mode[1] = (omap_dma_addressing_t) ((value & 0xc000) >> 14);
- ch->mode[0] = (omap_dma_addressing_t) ((value & 0x3000) >> 12);
- ch->suspend = (value & 0x0100) >> 8;
- ch->priority = (value & 0x0040) >> 6;
- ch->fs = (value & 0x0020) >> 5;
- if (ch->fs && ch->bs && ch->mode[0] && ch->mode[1])
- fprintf(stderr, "%s: For a packet transfer at least one port "
- "must be constant-addressed\n", __FUNCTION__);
- ch->sync = (value & 0x001f) | ((value >> 14) & 0x0060);
- /* XXX must be 0x01 for CamDMA */
-
- if (value & 0x0080)
- omap_dma_enable_channel(s, ch);
- else
- omap_dma_disable_channel(s, ch);
-
- break;
-
- case 0x04: /* DMA4_CLNK_CTRL */
- ch->link_enabled = (value >> 15) & 0x1;
- ch->link_next_ch = value & 0x1f;
- break;
-
- case 0x08: /* DMA4_CICR */
- ch->interrupts = value & 0x09be;
- break;
-
- case 0x0c: /* DMA4_CSR */
- ch->cstatus &= ~value;
- break;
-
- case 0x10: /* DMA4_CSDP */
- ch->endian[0] =(value >> 21) & 1;
- ch->endian_lock[0] =(value >> 20) & 1;
- ch->endian[1] =(value >> 19) & 1;
- ch->endian_lock[1] =(value >> 18) & 1;
- if (ch->endian[0] != ch->endian[1])
- fprintf(stderr, "%s: DMA endiannes conversion enable attempt\n",
- __FUNCTION__);
- ch->write_mode = (value >> 16) & 3;
- ch->burst[1] = (value & 0xc000) >> 14;
- ch->pack[1] = (value & 0x2000) >> 13;
- ch->translate[1] = (value & 0x1e00) >> 9;
- ch->burst[0] = (value & 0x0180) >> 7;
- ch->pack[0] = (value & 0x0040) >> 6;
- ch->translate[0] = (value & 0x003c) >> 2;
- if (ch->translate[0] | ch->translate[1])
- fprintf(stderr, "%s: bad MReqAddressTranslate sideband signal\n",
- __FUNCTION__);
- ch->data_type = 1 << (value & 3);
- if ((value & 3) == 3)
- printf("%s: bad data_type for DMA channel\n", __FUNCTION__);
- break;
-
- case 0x14: /* DMA4_CEN */
- ch->set_update = 1;
- ch->elements = value & 0xffffff;
- break;
-
- case 0x18: /* DMA4_CFN */
- ch->frames = value & 0xffff;
- ch->set_update = 1;
- break;
-
- case 0x1c: /* DMA4_CSSA */
- ch->addr[0] = (hwaddr) (uint32_t) value;
- ch->set_update = 1;
- break;
-
- case 0x20: /* DMA4_CDSA */
- ch->addr[1] = (hwaddr) (uint32_t) value;
- ch->set_update = 1;
- break;
-
- case 0x24: /* DMA4_CSEI */
- ch->element_index[0] = (int16_t) value;
- ch->set_update = 1;
- break;
-
- case 0x28: /* DMA4_CSFI */
- ch->frame_index[0] = (int32_t) value;
- ch->set_update = 1;
- break;
-
- case 0x2c: /* DMA4_CDEI */
- ch->element_index[1] = (int16_t) value;
- ch->set_update = 1;
- break;
-
- case 0x30: /* DMA4_CDFI */
- ch->frame_index[1] = (int32_t) value;
- ch->set_update = 1;
- break;
-
- case 0x44: /* DMA4_COLOR */
- /* XXX only in sDMA */
- ch->color = value;
- break;
-
- case 0x34: /* DMA4_CSAC */
- case 0x38: /* DMA4_CDAC */
- case 0x3c: /* DMA4_CCEN */
- case 0x40: /* DMA4_CCFN */
- OMAP_RO_REG(addr);
- break;
-
- default:
- OMAP_BAD_REG(addr);
- }
-}
-
-static const MemoryRegionOps omap_dma4_ops = {
- .read = omap_dma4_read,
- .write = omap_dma4_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct soc_dma_s *omap_dma4_init(hwaddr base, qemu_irq *irqs,
- MemoryRegion *sysmem,
- struct omap_mpu_state_s *mpu, int fifo,
- int chans, omap_clk iclk, omap_clk fclk)
-{
- int i;
- struct omap_dma_s *s = g_new0(struct omap_dma_s, 1);
-
- s->model = omap_dma_4;
- s->chans = chans;
- s->mpu = mpu;
- s->clk = fclk;
-
- s->dma = soc_dma_init(s->chans);
- s->dma->freq = omap_clk_getrate(fclk);
- s->dma->transfer_fn = omap_dma_transfer_generic;
- s->dma->setup_fn = omap_dma_transfer_setup;
- s->dma->drq = qemu_allocate_irqs(omap_dma_request, s, 64);
- s->dma->opaque = s;
- for (i = 0; i < s->chans; i ++) {
- s->ch[i].dma = &s->dma->ch[i];
- s->dma->ch[i].opaque = &s->ch[i];
- }
-
- memcpy(&s->irq, irqs, sizeof(s->irq));
- s->intr_update = omap_dma_interrupts_4_update;
-
- omap_dma_setcaps(s);
- omap_clk_adduser(s->clk, qemu_allocate_irq(omap_dma_clk_update, s, 0));
- omap_dma_reset(s->dma);
- omap_dma_clk_update(s, 0, !!s->dma->freq);
-
- memory_region_init_io(&s->iomem, NULL, &omap_dma4_ops, s, "omap.dma4", 0x1000);
- memory_region_add_subregion(sysmem, base, &s->iomem);
-
- mpu->drq = s->dma->drq;
-
- return s->dma;
-}
-
-struct omap_dma_lcd_channel_s *omap_dma_get_lcdch(struct soc_dma_s *dma)
-{
- struct omap_dma_s *s = dma->opaque;
-
- return &s->lcd_ch;
-}
diff --git a/qemu/hw/dma/pl080.c b/qemu/hw/dma/pl080.c
deleted file mode 100644
index 9318108b8..000000000
--- a/qemu/hw/dma/pl080.c
+++ /dev/null
@@ -1,423 +0,0 @@
-/*
- * Arm PrimeCell PL080/PL081 DMA controller
- *
- * Copyright (c) 2006 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "exec/address-spaces.h"
-
-#define PL080_MAX_CHANNELS 8
-#define PL080_CONF_E 0x1
-#define PL080_CONF_M1 0x2
-#define PL080_CONF_M2 0x4
-
-#define PL080_CCONF_H 0x40000
-#define PL080_CCONF_A 0x20000
-#define PL080_CCONF_L 0x10000
-#define PL080_CCONF_ITC 0x08000
-#define PL080_CCONF_IE 0x04000
-#define PL080_CCONF_E 0x00001
-
-#define PL080_CCTRL_I 0x80000000
-#define PL080_CCTRL_DI 0x08000000
-#define PL080_CCTRL_SI 0x04000000
-#define PL080_CCTRL_D 0x02000000
-#define PL080_CCTRL_S 0x01000000
-
-typedef struct {
- uint32_t src;
- uint32_t dest;
- uint32_t lli;
- uint32_t ctrl;
- uint32_t conf;
-} pl080_channel;
-
-#define TYPE_PL080 "pl080"
-#define PL080(obj) OBJECT_CHECK(PL080State, (obj), TYPE_PL080)
-
-typedef struct PL080State {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- uint8_t tc_int;
- uint8_t tc_mask;
- uint8_t err_int;
- uint8_t err_mask;
- uint32_t conf;
- uint32_t sync;
- uint32_t req_single;
- uint32_t req_burst;
- pl080_channel chan[PL080_MAX_CHANNELS];
- int nchannels;
- /* Flag to avoid recursive DMA invocations. */
- int running;
- qemu_irq irq;
-} PL080State;
-
-static const VMStateDescription vmstate_pl080_channel = {
- .name = "pl080_channel",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(src, pl080_channel),
- VMSTATE_UINT32(dest, pl080_channel),
- VMSTATE_UINT32(lli, pl080_channel),
- VMSTATE_UINT32(ctrl, pl080_channel),
- VMSTATE_UINT32(conf, pl080_channel),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_pl080 = {
- .name = "pl080",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(tc_int, PL080State),
- VMSTATE_UINT8(tc_mask, PL080State),
- VMSTATE_UINT8(err_int, PL080State),
- VMSTATE_UINT8(err_mask, PL080State),
- VMSTATE_UINT32(conf, PL080State),
- VMSTATE_UINT32(sync, PL080State),
- VMSTATE_UINT32(req_single, PL080State),
- VMSTATE_UINT32(req_burst, PL080State),
- VMSTATE_UINT8(tc_int, PL080State),
- VMSTATE_UINT8(tc_int, PL080State),
- VMSTATE_UINT8(tc_int, PL080State),
- VMSTATE_STRUCT_ARRAY(chan, PL080State, PL080_MAX_CHANNELS,
- 1, vmstate_pl080_channel, pl080_channel),
- VMSTATE_INT32(running, PL080State),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const unsigned char pl080_id[] =
-{ 0x80, 0x10, 0x04, 0x0a, 0x0d, 0xf0, 0x05, 0xb1 };
-
-static const unsigned char pl081_id[] =
-{ 0x81, 0x10, 0x04, 0x0a, 0x0d, 0xf0, 0x05, 0xb1 };
-
-static void pl080_update(PL080State *s)
-{
- if ((s->tc_int & s->tc_mask)
- || (s->err_int & s->err_mask))
- qemu_irq_raise(s->irq);
- else
- qemu_irq_lower(s->irq);
-}
-
-static void pl080_run(PL080State *s)
-{
- int c;
- int flow;
- pl080_channel *ch;
- int swidth;
- int dwidth;
- int xsize;
- int n;
- int src_id;
- int dest_id;
- int size;
- uint8_t buff[4];
- uint32_t req;
-
- s->tc_mask = 0;
- for (c = 0; c < s->nchannels; c++) {
- if (s->chan[c].conf & PL080_CCONF_ITC)
- s->tc_mask |= 1 << c;
- if (s->chan[c].conf & PL080_CCONF_IE)
- s->err_mask |= 1 << c;
- }
-
- if ((s->conf & PL080_CONF_E) == 0)
- return;
-
-hw_error("DMA active\n");
- /* If we are already in the middle of a DMA operation then indicate that
- there may be new DMA requests and return immediately. */
- if (s->running) {
- s->running++;
- return;
- }
- s->running = 1;
- while (s->running) {
- for (c = 0; c < s->nchannels; c++) {
- ch = &s->chan[c];
-again:
- /* Test if thiws channel has any pending DMA requests. */
- if ((ch->conf & (PL080_CCONF_H | PL080_CCONF_E))
- != PL080_CCONF_E)
- continue;
- flow = (ch->conf >> 11) & 7;
- if (flow >= 4) {
- hw_error(
- "pl080_run: Peripheral flow control not implemented\n");
- }
- src_id = (ch->conf >> 1) & 0x1f;
- dest_id = (ch->conf >> 6) & 0x1f;
- size = ch->ctrl & 0xfff;
- req = s->req_single | s->req_burst;
- switch (flow) {
- case 0:
- break;
- case 1:
- if ((req & (1u << dest_id)) == 0)
- size = 0;
- break;
- case 2:
- if ((req & (1u << src_id)) == 0)
- size = 0;
- break;
- case 3:
- if ((req & (1u << src_id)) == 0
- || (req & (1u << dest_id)) == 0)
- size = 0;
- break;
- }
- if (!size)
- continue;
-
- /* Transfer one element. */
- /* ??? Should transfer multiple elements for a burst request. */
- /* ??? Unclear what the proper behavior is when source and
- destination widths are different. */
- swidth = 1 << ((ch->ctrl >> 18) & 7);
- dwidth = 1 << ((ch->ctrl >> 21) & 7);
- for (n = 0; n < dwidth; n+= swidth) {
- cpu_physical_memory_read(ch->src, buff + n, swidth);
- if (ch->ctrl & PL080_CCTRL_SI)
- ch->src += swidth;
- }
- xsize = (dwidth < swidth) ? swidth : dwidth;
- /* ??? This may pad the value incorrectly for dwidth < 32. */
- for (n = 0; n < xsize; n += dwidth) {
- cpu_physical_memory_write(ch->dest + n, buff + n, dwidth);
- if (ch->ctrl & PL080_CCTRL_DI)
- ch->dest += swidth;
- }
-
- size--;
- ch->ctrl = (ch->ctrl & 0xfffff000) | size;
- if (size == 0) {
- /* Transfer complete. */
- if (ch->lli) {
- ch->src = address_space_ldl_le(&address_space_memory,
- ch->lli,
- MEMTXATTRS_UNSPECIFIED,
- NULL);
- ch->dest = address_space_ldl_le(&address_space_memory,
- ch->lli + 4,
- MEMTXATTRS_UNSPECIFIED,
- NULL);
- ch->ctrl = address_space_ldl_le(&address_space_memory,
- ch->lli + 12,
- MEMTXATTRS_UNSPECIFIED,
- NULL);
- ch->lli = address_space_ldl_le(&address_space_memory,
- ch->lli + 8,
- MEMTXATTRS_UNSPECIFIED,
- NULL);
- } else {
- ch->conf &= ~PL080_CCONF_E;
- }
- if (ch->ctrl & PL080_CCTRL_I) {
- s->tc_int |= 1 << c;
- }
- }
- goto again;
- }
- if (--s->running)
- s->running = 1;
- }
-}
-
-static uint64_t pl080_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- PL080State *s = (PL080State *)opaque;
- uint32_t i;
- uint32_t mask;
-
- if (offset >= 0xfe0 && offset < 0x1000) {
- if (s->nchannels == 8) {
- return pl080_id[(offset - 0xfe0) >> 2];
- } else {
- return pl081_id[(offset - 0xfe0) >> 2];
- }
- }
- if (offset >= 0x100 && offset < 0x200) {
- i = (offset & 0xe0) >> 5;
- if (i >= s->nchannels)
- goto bad_offset;
- switch (offset >> 2) {
- case 0: /* SrcAddr */
- return s->chan[i].src;
- case 1: /* DestAddr */
- return s->chan[i].dest;
- case 2: /* LLI */
- return s->chan[i].lli;
- case 3: /* Control */
- return s->chan[i].ctrl;
- case 4: /* Configuration */
- return s->chan[i].conf;
- default:
- goto bad_offset;
- }
- }
- switch (offset >> 2) {
- case 0: /* IntStatus */
- return (s->tc_int & s->tc_mask) | (s->err_int & s->err_mask);
- case 1: /* IntTCStatus */
- return (s->tc_int & s->tc_mask);
- case 3: /* IntErrorStatus */
- return (s->err_int & s->err_mask);
- case 5: /* RawIntTCStatus */
- return s->tc_int;
- case 6: /* RawIntErrorStatus */
- return s->err_int;
- case 7: /* EnbldChns */
- mask = 0;
- for (i = 0; i < s->nchannels; i++) {
- if (s->chan[i].conf & PL080_CCONF_E)
- mask |= 1 << i;
- }
- return mask;
- case 8: /* SoftBReq */
- case 9: /* SoftSReq */
- case 10: /* SoftLBReq */
- case 11: /* SoftLSReq */
- /* ??? Implement these. */
- return 0;
- case 12: /* Configuration */
- return s->conf;
- case 13: /* Sync */
- return s->sync;
- default:
- bad_offset:
- qemu_log_mask(LOG_GUEST_ERROR,
- "pl080_read: Bad offset %x\n", (int)offset);
- return 0;
- }
-}
-
-static void pl080_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PL080State *s = (PL080State *)opaque;
- int i;
-
- if (offset >= 0x100 && offset < 0x200) {
- i = (offset & 0xe0) >> 5;
- if (i >= s->nchannels)
- goto bad_offset;
- switch (offset >> 2) {
- case 0: /* SrcAddr */
- s->chan[i].src = value;
- break;
- case 1: /* DestAddr */
- s->chan[i].dest = value;
- break;
- case 2: /* LLI */
- s->chan[i].lli = value;
- break;
- case 3: /* Control */
- s->chan[i].ctrl = value;
- break;
- case 4: /* Configuration */
- s->chan[i].conf = value;
- pl080_run(s);
- break;
- }
- }
- switch (offset >> 2) {
- case 2: /* IntTCClear */
- s->tc_int &= ~value;
- break;
- case 4: /* IntErrorClear */
- s->err_int &= ~value;
- break;
- case 8: /* SoftBReq */
- case 9: /* SoftSReq */
- case 10: /* SoftLBReq */
- case 11: /* SoftLSReq */
- /* ??? Implement these. */
- qemu_log_mask(LOG_UNIMP, "pl080_write: Soft DMA not implemented\n");
- break;
- case 12: /* Configuration */
- s->conf = value;
- if (s->conf & (PL080_CONF_M1 | PL080_CONF_M1)) {
- qemu_log_mask(LOG_UNIMP,
- "pl080_write: Big-endian DMA not implemented\n");
- }
- pl080_run(s);
- break;
- case 13: /* Sync */
- s->sync = value;
- break;
- default:
- bad_offset:
- qemu_log_mask(LOG_GUEST_ERROR,
- "pl080_write: Bad offset %x\n", (int)offset);
- }
- pl080_update(s);
-}
-
-static const MemoryRegionOps pl080_ops = {
- .read = pl080_read,
- .write = pl080_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void pl080_init(Object *obj)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- PL080State *s = PL080(obj);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &pl080_ops, s, "pl080", 0x1000);
- sysbus_init_mmio(sbd, &s->iomem);
- sysbus_init_irq(sbd, &s->irq);
- s->nchannels = 8;
-}
-
-static void pl081_init(Object *obj)
-{
- PL080State *s = PL080(obj);
-
- s->nchannels = 2;
-}
-
-static void pl080_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- dc->vmsd = &vmstate_pl080;
-}
-
-static const TypeInfo pl080_info = {
- .name = TYPE_PL080,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PL080State),
- .instance_init = pl080_init,
- .class_init = pl080_class_init,
-};
-
-static const TypeInfo pl081_info = {
- .name = "pl081",
- .parent = TYPE_PL080,
- .instance_init = pl081_init,
-};
-
-/* The PL080 and PL081 are the same except for the number of channels
- they implement (8 and 2 respectively). */
-static void pl080_register_types(void)
-{
- type_register_static(&pl080_info);
- type_register_static(&pl081_info);
-}
-
-type_init(pl080_register_types)
diff --git a/qemu/hw/dma/pl330.c b/qemu/hw/dma/pl330.c
deleted file mode 100644
index ea89ecb00..000000000
--- a/qemu/hw/dma/pl330.c
+++ /dev/null
@@ -1,1668 +0,0 @@
-/*
- * ARM PrimeCell PL330 DMA Controller
- *
- * Copyright (c) 2009 Samsung Electronics.
- * Contributed by Kirill Batuzov <batuzovk@ispras.ru>
- * Copyright (c) 2012 Peter A.G. Crosthwaite (peter.crosthwaite@petalogix.com)
- * Copyright (c) 2012 PetaLogix Pty Ltd.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; version 2 or later.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "qapi/error.h"
-#include "qemu/timer.h"
-#include "sysemu/dma.h"
-
-#ifndef PL330_ERR_DEBUG
-#define PL330_ERR_DEBUG 0
-#endif
-
-#define DB_PRINT_L(lvl, fmt, args...) do {\
- if (PL330_ERR_DEBUG >= lvl) {\
- fprintf(stderr, "PL330: %s:" fmt, __func__, ## args);\
- } \
-} while (0);
-
-#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args)
-
-#define PL330_PERIPH_NUM 32
-#define PL330_MAX_BURST_LEN 128
-#define PL330_INSN_MAXSIZE 6
-
-#define PL330_FIFO_OK 0
-#define PL330_FIFO_STALL 1
-#define PL330_FIFO_ERR (-1)
-
-#define PL330_FAULT_UNDEF_INSTR (1 << 0)
-#define PL330_FAULT_OPERAND_INVALID (1 << 1)
-#define PL330_FAULT_DMAGO_ERR (1 << 4)
-#define PL330_FAULT_EVENT_ERR (1 << 5)
-#define PL330_FAULT_CH_PERIPH_ERR (1 << 6)
-#define PL330_FAULT_CH_RDWR_ERR (1 << 7)
-#define PL330_FAULT_ST_DATA_UNAVAILABLE (1 << 12)
-#define PL330_FAULT_FIFOEMPTY_ERR (1 << 13)
-#define PL330_FAULT_INSTR_FETCH_ERR (1 << 16)
-#define PL330_FAULT_DATA_WRITE_ERR (1 << 17)
-#define PL330_FAULT_DATA_READ_ERR (1 << 18)
-#define PL330_FAULT_DBG_INSTR (1 << 30)
-#define PL330_FAULT_LOCKUP_ERR (1 << 31)
-
-#define PL330_UNTAGGED 0xff
-
-#define PL330_SINGLE 0x0
-#define PL330_BURST 0x1
-
-#define PL330_WATCHDOG_LIMIT 1024
-
-/* IOMEM mapped registers */
-#define PL330_REG_DSR 0x000
-#define PL330_REG_DPC 0x004
-#define PL330_REG_INTEN 0x020
-#define PL330_REG_INT_EVENT_RIS 0x024
-#define PL330_REG_INTMIS 0x028
-#define PL330_REG_INTCLR 0x02C
-#define PL330_REG_FSRD 0x030
-#define PL330_REG_FSRC 0x034
-#define PL330_REG_FTRD 0x038
-#define PL330_REG_FTR_BASE 0x040
-#define PL330_REG_CSR_BASE 0x100
-#define PL330_REG_CPC_BASE 0x104
-#define PL330_REG_CHANCTRL 0x400
-#define PL330_REG_DBGSTATUS 0xD00
-#define PL330_REG_DBGCMD 0xD04
-#define PL330_REG_DBGINST0 0xD08
-#define PL330_REG_DBGINST1 0xD0C
-#define PL330_REG_CR0_BASE 0xE00
-#define PL330_REG_PERIPH_ID 0xFE0
-
-#define PL330_IOMEM_SIZE 0x1000
-
-#define CFG_BOOT_ADDR 2
-#define CFG_INS 3
-#define CFG_PNS 4
-#define CFG_CRD 5
-
-static const uint32_t pl330_id[] = {
- 0x30, 0x13, 0x24, 0x00, 0x0D, 0xF0, 0x05, 0xB1
-};
-
-/* DMA channel states as they are described in PL330 Technical Reference Manual
- * Most of them will not be used in emulation.
- */
-typedef enum {
- pl330_chan_stopped = 0,
- pl330_chan_executing = 1,
- pl330_chan_cache_miss = 2,
- pl330_chan_updating_pc = 3,
- pl330_chan_waiting_event = 4,
- pl330_chan_at_barrier = 5,
- pl330_chan_queue_busy = 6,
- pl330_chan_waiting_periph = 7,
- pl330_chan_killing = 8,
- pl330_chan_completing = 9,
- pl330_chan_fault_completing = 14,
- pl330_chan_fault = 15,
-} PL330ChanState;
-
-typedef struct PL330State PL330State;
-
-typedef struct PL330Chan {
- uint32_t src;
- uint32_t dst;
- uint32_t pc;
- uint32_t control;
- uint32_t status;
- uint32_t lc[2];
- uint32_t fault_type;
- uint32_t watchdog_timer;
-
- bool ns;
- uint8_t request_flag;
- uint8_t wakeup;
- uint8_t wfp_sbp;
-
- uint8_t state;
- uint8_t stall;
-
- bool is_manager;
- PL330State *parent;
- uint8_t tag;
-} PL330Chan;
-
-static const VMStateDescription vmstate_pl330_chan = {
- .name = "pl330_chan",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(src, PL330Chan),
- VMSTATE_UINT32(dst, PL330Chan),
- VMSTATE_UINT32(pc, PL330Chan),
- VMSTATE_UINT32(control, PL330Chan),
- VMSTATE_UINT32(status, PL330Chan),
- VMSTATE_UINT32_ARRAY(lc, PL330Chan, 2),
- VMSTATE_UINT32(fault_type, PL330Chan),
- VMSTATE_UINT32(watchdog_timer, PL330Chan),
- VMSTATE_BOOL(ns, PL330Chan),
- VMSTATE_UINT8(request_flag, PL330Chan),
- VMSTATE_UINT8(wakeup, PL330Chan),
- VMSTATE_UINT8(wfp_sbp, PL330Chan),
- VMSTATE_UINT8(state, PL330Chan),
- VMSTATE_UINT8(stall, PL330Chan),
- VMSTATE_END_OF_LIST()
- }
-};
-
-typedef struct PL330Fifo {
- uint8_t *buf;
- uint8_t *tag;
- uint32_t head;
- uint32_t num;
- uint32_t buf_size;
-} PL330Fifo;
-
-static const VMStateDescription vmstate_pl330_fifo = {
- .name = "pl330_chan",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_VBUFFER_UINT32(buf, PL330Fifo, 1, NULL, 0, buf_size),
- VMSTATE_VBUFFER_UINT32(tag, PL330Fifo, 1, NULL, 0, buf_size),
- VMSTATE_UINT32(head, PL330Fifo),
- VMSTATE_UINT32(num, PL330Fifo),
- VMSTATE_UINT32(buf_size, PL330Fifo),
- VMSTATE_END_OF_LIST()
- }
-};
-
-typedef struct PL330QueueEntry {
- uint32_t addr;
- uint32_t len;
- uint8_t n;
- bool inc;
- bool z;
- uint8_t tag;
- uint8_t seqn;
-} PL330QueueEntry;
-
-static const VMStateDescription vmstate_pl330_queue_entry = {
- .name = "pl330_queue_entry",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(addr, PL330QueueEntry),
- VMSTATE_UINT32(len, PL330QueueEntry),
- VMSTATE_UINT8(n, PL330QueueEntry),
- VMSTATE_BOOL(inc, PL330QueueEntry),
- VMSTATE_BOOL(z, PL330QueueEntry),
- VMSTATE_UINT8(tag, PL330QueueEntry),
- VMSTATE_UINT8(seqn, PL330QueueEntry),
- VMSTATE_END_OF_LIST()
- }
-};
-
-typedef struct PL330Queue {
- PL330State *parent;
- PL330QueueEntry *queue;
- uint32_t queue_size;
-} PL330Queue;
-
-static const VMStateDescription vmstate_pl330_queue = {
- .name = "pl330_queue",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT_VARRAY_UINT32(queue, PL330Queue, queue_size, 1,
- vmstate_pl330_queue_entry, PL330QueueEntry),
- VMSTATE_END_OF_LIST()
- }
-};
-
-struct PL330State {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- qemu_irq irq_abort;
- qemu_irq *irq;
-
- /* Config registers. cfg[5] = CfgDn. */
- uint32_t cfg[6];
-#define EVENT_SEC_STATE 3
-#define PERIPH_SEC_STATE 4
- /* cfg 0 bits and pieces */
- uint32_t num_chnls;
- uint8_t num_periph_req;
- uint8_t num_events;
- uint8_t mgr_ns_at_rst;
- /* cfg 1 bits and pieces */
- uint8_t i_cache_len;
- uint8_t num_i_cache_lines;
- /* CRD bits and pieces */
- uint8_t data_width;
- uint8_t wr_cap;
- uint8_t wr_q_dep;
- uint8_t rd_cap;
- uint8_t rd_q_dep;
- uint16_t data_buffer_dep;
-
- PL330Chan manager;
- PL330Chan *chan;
- PL330Fifo fifo;
- PL330Queue read_queue;
- PL330Queue write_queue;
- uint8_t *lo_seqn;
- uint8_t *hi_seqn;
- QEMUTimer *timer; /* is used for restore dma. */
-
- uint32_t inten;
- uint32_t int_status;
- uint32_t ev_status;
- uint32_t dbg[2];
- uint8_t debug_status;
- uint8_t num_faulting;
- uint8_t periph_busy[PL330_PERIPH_NUM];
-
-};
-
-#define TYPE_PL330 "pl330"
-#define PL330(obj) OBJECT_CHECK(PL330State, (obj), TYPE_PL330)
-
-static const VMStateDescription vmstate_pl330 = {
- .name = "pl330",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT(manager, PL330State, 0, vmstate_pl330_chan, PL330Chan),
- VMSTATE_STRUCT_VARRAY_UINT32(chan, PL330State, num_chnls, 0,
- vmstate_pl330_chan, PL330Chan),
- VMSTATE_VBUFFER_UINT32(lo_seqn, PL330State, 1, NULL, 0, num_chnls),
- VMSTATE_VBUFFER_UINT32(hi_seqn, PL330State, 1, NULL, 0, num_chnls),
- VMSTATE_STRUCT(fifo, PL330State, 0, vmstate_pl330_fifo, PL330Fifo),
- VMSTATE_STRUCT(read_queue, PL330State, 0, vmstate_pl330_queue,
- PL330Queue),
- VMSTATE_STRUCT(write_queue, PL330State, 0, vmstate_pl330_queue,
- PL330Queue),
- VMSTATE_TIMER_PTR(timer, PL330State),
- VMSTATE_UINT32(inten, PL330State),
- VMSTATE_UINT32(int_status, PL330State),
- VMSTATE_UINT32(ev_status, PL330State),
- VMSTATE_UINT32_ARRAY(dbg, PL330State, 2),
- VMSTATE_UINT8(debug_status, PL330State),
- VMSTATE_UINT8(num_faulting, PL330State),
- VMSTATE_UINT8_ARRAY(periph_busy, PL330State, PL330_PERIPH_NUM),
- VMSTATE_END_OF_LIST()
- }
-};
-
-typedef struct PL330InsnDesc {
- /* OPCODE of the instruction */
- uint8_t opcode;
- /* Mask so we can select several sibling instructions, such as
- DMALD, DMALDS and DMALDB */
- uint8_t opmask;
- /* Size of instruction in bytes */
- uint8_t size;
- /* Interpreter */
- void (*exec)(PL330Chan *, uint8_t opcode, uint8_t *args, int len);
-} PL330InsnDesc;
-
-
-/* MFIFO Implementation
- *
- * MFIFO is implemented as a cyclic buffer of BUF_SIZE size. Tagged bytes are
- * stored in this buffer. Data is stored in BUF field, tags - in the
- * corresponding array elements of TAG field.
- */
-
-/* Initialize queue. */
-
-static void pl330_fifo_init(PL330Fifo *s, uint32_t size)
-{
- s->buf = g_malloc0(size);
- s->tag = g_malloc0(size);
- s->buf_size = size;
-}
-
-/* Cyclic increment */
-
-static inline int pl330_fifo_inc(PL330Fifo *s, int x)
-{
- return (x + 1) % s->buf_size;
-}
-
-/* Number of empty bytes in MFIFO */
-
-static inline int pl330_fifo_num_free(PL330Fifo *s)
-{
- return s->buf_size - s->num;
-}
-
-/* Push LEN bytes of data stored in BUF to MFIFO and tag it with TAG.
- * Zero returned on success, PL330_FIFO_STALL if there is no enough free
- * space in MFIFO to store requested amount of data. If push was unsuccessful
- * no data is stored to MFIFO.
- */
-
-static int pl330_fifo_push(PL330Fifo *s, uint8_t *buf, int len, uint8_t tag)
-{
- int i;
-
- if (s->buf_size - s->num < len) {
- return PL330_FIFO_STALL;
- }
- for (i = 0; i < len; i++) {
- int push_idx = (s->head + s->num + i) % s->buf_size;
- s->buf[push_idx] = buf[i];
- s->tag[push_idx] = tag;
- }
- s->num += len;
- return PL330_FIFO_OK;
-}
-
-/* Get LEN bytes of data from MFIFO and store it to BUF. Tag value of each
- * byte is verified. Zero returned on success, PL330_FIFO_ERR on tag mismatch
- * and PL330_FIFO_STALL if there is no enough data in MFIFO. If get was
- * unsuccessful no data is removed from MFIFO.
- */
-
-static int pl330_fifo_get(PL330Fifo *s, uint8_t *buf, int len, uint8_t tag)
-{
- int i;
-
- if (s->num < len) {
- return PL330_FIFO_STALL;
- }
- for (i = 0; i < len; i++) {
- if (s->tag[s->head] == tag) {
- int get_idx = (s->head + i) % s->buf_size;
- buf[i] = s->buf[get_idx];
- } else { /* Tag mismatch - Rollback transaction */
- return PL330_FIFO_ERR;
- }
- }
- s->head = (s->head + len) % s->buf_size;
- s->num -= len;
- return PL330_FIFO_OK;
-}
-
-/* Reset MFIFO. This completely erases all data in it. */
-
-static inline void pl330_fifo_reset(PL330Fifo *s)
-{
- s->head = 0;
- s->num = 0;
-}
-
-/* Return tag of the first byte stored in MFIFO. If MFIFO is empty
- * PL330_UNTAGGED is returned.
- */
-
-static inline uint8_t pl330_fifo_tag(PL330Fifo *s)
-{
- return (!s->num) ? PL330_UNTAGGED : s->tag[s->head];
-}
-
-/* Returns non-zero if tag TAG is present in fifo or zero otherwise */
-
-static int pl330_fifo_has_tag(PL330Fifo *s, uint8_t tag)
-{
- int i, n;
-
- i = s->head;
- for (n = 0; n < s->num; n++) {
- if (s->tag[i] == tag) {
- return 1;
- }
- i = pl330_fifo_inc(s, i);
- }
- return 0;
-}
-
-/* Remove all entry tagged with TAG from MFIFO */
-
-static void pl330_fifo_tagged_remove(PL330Fifo *s, uint8_t tag)
-{
- int i, t, n;
-
- t = i = s->head;
- for (n = 0; n < s->num; n++) {
- if (s->tag[i] != tag) {
- s->buf[t] = s->buf[i];
- s->tag[t] = s->tag[i];
- t = pl330_fifo_inc(s, t);
- } else {
- s->num = s->num - 1;
- }
- i = pl330_fifo_inc(s, i);
- }
-}
-
-/* Read-Write Queue implementation
- *
- * A Read-Write Queue stores up to QUEUE_SIZE instructions (loads or stores).
- * Each instruction is described by source (for loads) or destination (for
- * stores) address ADDR, width of data to be loaded/stored LEN, number of
- * stores/loads to be performed N, INC bit, Z bit and TAG to identify channel
- * this instruction belongs to. Queue does not store any information about
- * nature of the instruction: is it load or store. PL330 has different queues
- * for loads and stores so this is already known at the top level where it
- * matters.
- *
- * Queue works as FIFO for instructions with equivalent tags, but can issue
- * instructions with different tags in arbitrary order. SEQN field attached to
- * each instruction helps to achieve this. For each TAG queue contains
- * instructions with consecutive SEQN values ranging from LO_SEQN[TAG] to
- * HI_SEQN[TAG]-1 inclusive. SEQN is 8-bit unsigned integer, so SEQN=255 is
- * followed by SEQN=0.
- *
- * Z bit indicates that zeroes should be stored. No MFIFO fetches are performed
- * in this case.
- */
-
-static void pl330_queue_reset(PL330Queue *s)
-{
- int i;
-
- for (i = 0; i < s->queue_size; i++) {
- s->queue[i].tag = PL330_UNTAGGED;
- }
-}
-
-/* Initialize queue */
-static void pl330_queue_init(PL330Queue *s, int size, PL330State *parent)
-{
- s->parent = parent;
- s->queue = g_new0(PL330QueueEntry, size);
- s->queue_size = size;
-}
-
-/* Returns pointer to an empty slot or NULL if queue is full */
-static PL330QueueEntry *pl330_queue_find_empty(PL330Queue *s)
-{
- int i;
-
- for (i = 0; i < s->queue_size; i++) {
- if (s->queue[i].tag == PL330_UNTAGGED) {
- return &s->queue[i];
- }
- }
- return NULL;
-}
-
-/* Put instruction in queue.
- * Return value:
- * - zero - OK
- * - non-zero - queue is full
- */
-
-static int pl330_queue_put_insn(PL330Queue *s, uint32_t addr,
- int len, int n, bool inc, bool z, uint8_t tag)
-{
- PL330QueueEntry *entry = pl330_queue_find_empty(s);
-
- if (!entry) {
- return 1;
- }
- entry->tag = tag;
- entry->addr = addr;
- entry->len = len;
- entry->n = n;
- entry->z = z;
- entry->inc = inc;
- entry->seqn = s->parent->hi_seqn[tag];
- s->parent->hi_seqn[tag]++;
- return 0;
-}
-
-/* Returns a pointer to queue slot containing instruction which satisfies
- * following conditions:
- * - it has valid tag value (not PL330_UNTAGGED)
- * - if enforce_seq is set it has to be issuable without violating queue
- * logic (see above)
- * - if TAG argument is not PL330_UNTAGGED this instruction has tag value
- * equivalent to the argument TAG value.
- * If such instruction cannot be found NULL is returned.
- */
-
-static PL330QueueEntry *pl330_queue_find_insn(PL330Queue *s, uint8_t tag,
- bool enforce_seq)
-{
- int i;
-
- for (i = 0; i < s->queue_size; i++) {
- if (s->queue[i].tag != PL330_UNTAGGED) {
- if ((!enforce_seq ||
- s->queue[i].seqn == s->parent->lo_seqn[s->queue[i].tag]) &&
- (s->queue[i].tag == tag || tag == PL330_UNTAGGED ||
- s->queue[i].z)) {
- return &s->queue[i];
- }
- }
- }
- return NULL;
-}
-
-/* Removes instruction from queue. */
-
-static inline void pl330_queue_remove_insn(PL330Queue *s, PL330QueueEntry *e)
-{
- s->parent->lo_seqn[e->tag]++;
- e->tag = PL330_UNTAGGED;
-}
-
-/* Removes all instructions tagged with TAG from queue. */
-
-static inline void pl330_queue_remove_tagged(PL330Queue *s, uint8_t tag)
-{
- int i;
-
- for (i = 0; i < s->queue_size; i++) {
- if (s->queue[i].tag == tag) {
- s->queue[i].tag = PL330_UNTAGGED;
- }
- }
-}
-
-/* DMA instruction execution engine */
-
-/* Moves DMA channel to the FAULT state and updates it's status. */
-
-static inline void pl330_fault(PL330Chan *ch, uint32_t flags)
-{
- DB_PRINT("ch: %p, flags: %" PRIx32 "\n", ch, flags);
- ch->fault_type |= flags;
- if (ch->state == pl330_chan_fault) {
- return;
- }
- ch->state = pl330_chan_fault;
- ch->parent->num_faulting++;
- if (ch->parent->num_faulting == 1) {
- DB_PRINT("abort interrupt raised\n");
- qemu_irq_raise(ch->parent->irq_abort);
- }
-}
-
-/*
- * For information about instructions see PL330 Technical Reference Manual.
- *
- * Arguments:
- * CH - channel executing the instruction
- * OPCODE - opcode
- * ARGS - array of 8-bit arguments
- * LEN - number of elements in ARGS array
- */
-
-static void pl330_dmaadxh(PL330Chan *ch, uint8_t *args, bool ra, bool neg)
-{
- uint32_t im = (args[1] << 8) | args[0];
- if (neg) {
- im |= 0xffffu << 16;
- }
-
- if (ch->is_manager) {
- pl330_fault(ch, PL330_FAULT_UNDEF_INSTR);
- return;
- }
- if (ra) {
- ch->dst += im;
- } else {
- ch->src += im;
- }
-}
-
-static void pl330_dmaaddh(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
-{
- pl330_dmaadxh(ch, args, extract32(opcode, 1, 1), false);
-}
-
-static void pl330_dmaadnh(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
-{
- pl330_dmaadxh(ch, args, extract32(opcode, 1, 1), true);
-}
-
-static void pl330_dmaend(PL330Chan *ch, uint8_t opcode,
- uint8_t *args, int len)
-{
- PL330State *s = ch->parent;
-
- if (ch->state == pl330_chan_executing && !ch->is_manager) {
- /* Wait for all transfers to complete */
- if (pl330_fifo_has_tag(&s->fifo, ch->tag) ||
- pl330_queue_find_insn(&s->read_queue, ch->tag, false) != NULL ||
- pl330_queue_find_insn(&s->write_queue, ch->tag, false) != NULL) {
-
- ch->stall = 1;
- return;
- }
- }
- DB_PRINT("DMA ending!\n");
- pl330_fifo_tagged_remove(&s->fifo, ch->tag);
- pl330_queue_remove_tagged(&s->read_queue, ch->tag);
- pl330_queue_remove_tagged(&s->write_queue, ch->tag);
- ch->state = pl330_chan_stopped;
-}
-
-static void pl330_dmaflushp(PL330Chan *ch, uint8_t opcode,
- uint8_t *args, int len)
-{
- uint8_t periph_id;
-
- if (args[0] & 7) {
- pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
- return;
- }
- periph_id = (args[0] >> 3) & 0x1f;
- if (periph_id >= ch->parent->num_periph_req) {
- pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
- return;
- }
- if (ch->ns && !(ch->parent->cfg[CFG_PNS] & (1 << periph_id))) {
- pl330_fault(ch, PL330_FAULT_CH_PERIPH_ERR);
- return;
- }
- /* Do nothing */
-}
-
-static void pl330_dmago(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
-{
- uint8_t chan_id;
- uint8_t ns;
- uint32_t pc;
- PL330Chan *s;
-
- DB_PRINT("\n");
-
- if (!ch->is_manager) {
- pl330_fault(ch, PL330_FAULT_UNDEF_INSTR);
- return;
- }
- ns = !!(opcode & 2);
- chan_id = args[0] & 7;
- if ((args[0] >> 3)) {
- pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
- return;
- }
- if (chan_id >= ch->parent->num_chnls) {
- pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
- return;
- }
- pc = (((uint32_t)args[4]) << 24) | (((uint32_t)args[3]) << 16) |
- (((uint32_t)args[2]) << 8) | (((uint32_t)args[1]));
- if (ch->parent->chan[chan_id].state != pl330_chan_stopped) {
- pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
- return;
- }
- if (ch->ns && !ns) {
- pl330_fault(ch, PL330_FAULT_DMAGO_ERR);
- return;
- }
- s = &ch->parent->chan[chan_id];
- s->ns = ns;
- s->pc = pc;
- s->state = pl330_chan_executing;
-}
-
-static void pl330_dmald(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
-{
- uint8_t bs = opcode & 3;
- uint32_t size, num;
- bool inc;
-
- if (bs == 2) {
- pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
- return;
- }
- if ((bs == 1 && ch->request_flag == PL330_BURST) ||
- (bs == 3 && ch->request_flag == PL330_SINGLE)) {
- /* Perform NOP */
- return;
- }
- if (bs == 1 && ch->request_flag == PL330_SINGLE) {
- num = 1;
- } else {
- num = ((ch->control >> 4) & 0xf) + 1;
- }
- size = (uint32_t)1 << ((ch->control >> 1) & 0x7);
- inc = !!(ch->control & 1);
- ch->stall = pl330_queue_put_insn(&ch->parent->read_queue, ch->src,
- size, num, inc, 0, ch->tag);
- if (!ch->stall) {
- DB_PRINT("channel:%" PRId8 " address:%08" PRIx32 " size:%" PRIx32
- " num:%" PRId32 " %c\n",
- ch->tag, ch->src, size, num, inc ? 'Y' : 'N');
- ch->src += inc ? size * num - (ch->src & (size - 1)) : 0;
- }
-}
-
-static void pl330_dmaldp(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
-{
- uint8_t periph_id;
-
- if (args[0] & 7) {
- pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
- return;
- }
- periph_id = (args[0] >> 3) & 0x1f;
- if (periph_id >= ch->parent->num_periph_req) {
- pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
- return;
- }
- if (ch->ns && !(ch->parent->cfg[CFG_PNS] & (1 << periph_id))) {
- pl330_fault(ch, PL330_FAULT_CH_PERIPH_ERR);
- return;
- }
- pl330_dmald(ch, opcode, args, len);
-}
-
-static void pl330_dmalp(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
-{
- uint8_t lc = (opcode & 2) >> 1;
-
- ch->lc[lc] = args[0];
-}
-
-static void pl330_dmakill(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
-{
- if (ch->state == pl330_chan_fault ||
- ch->state == pl330_chan_fault_completing) {
- /* This is the only way for a channel to leave the faulting state */
- ch->fault_type = 0;
- ch->parent->num_faulting--;
- if (ch->parent->num_faulting == 0) {
- DB_PRINT("abort interrupt lowered\n");
- qemu_irq_lower(ch->parent->irq_abort);
- }
- }
- ch->state = pl330_chan_killing;
- pl330_fifo_tagged_remove(&ch->parent->fifo, ch->tag);
- pl330_queue_remove_tagged(&ch->parent->read_queue, ch->tag);
- pl330_queue_remove_tagged(&ch->parent->write_queue, ch->tag);
- ch->state = pl330_chan_stopped;
-}
-
-static void pl330_dmalpend(PL330Chan *ch, uint8_t opcode,
- uint8_t *args, int len)
-{
- uint8_t nf = (opcode & 0x10) >> 4;
- uint8_t bs = opcode & 3;
- uint8_t lc = (opcode & 4) >> 2;
-
- if (bs == 2) {
- pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
- return;
- }
- if ((bs == 1 && ch->request_flag == PL330_BURST) ||
- (bs == 3 && ch->request_flag == PL330_SINGLE)) {
- /* Perform NOP */
- return;
- }
- if (!nf || ch->lc[lc]) {
- if (nf) {
- ch->lc[lc]--;
- }
- DB_PRINT("loop reiteration\n");
- ch->pc -= args[0];
- ch->pc -= len + 1;
- /* "ch->pc -= args[0] + len + 1" is incorrect when args[0] == 256 */
- } else {
- DB_PRINT("loop fallthrough\n");
- }
-}
-
-
-static void pl330_dmamov(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
-{
- uint8_t rd = args[0] & 7;
- uint32_t im;
-
- if ((args[0] >> 3)) {
- pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
- return;
- }
- im = (((uint32_t)args[4]) << 24) | (((uint32_t)args[3]) << 16) |
- (((uint32_t)args[2]) << 8) | (((uint32_t)args[1]));
- switch (rd) {
- case 0:
- ch->src = im;
- break;
- case 1:
- ch->control = im;
- break;
- case 2:
- ch->dst = im;
- break;
- default:
- pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
- return;
- }
-}
-
-static void pl330_dmanop(PL330Chan *ch, uint8_t opcode,
- uint8_t *args, int len)
-{
- /* NOP is NOP. */
-}
-
-static void pl330_dmarmb(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
-{
- if (pl330_queue_find_insn(&ch->parent->read_queue, ch->tag, false)) {
- ch->state = pl330_chan_at_barrier;
- ch->stall = 1;
- return;
- } else {
- ch->state = pl330_chan_executing;
- }
-}
-
-static void pl330_dmasev(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
-{
- uint8_t ev_id;
-
- if (args[0] & 7) {
- pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
- return;
- }
- ev_id = (args[0] >> 3) & 0x1f;
- if (ev_id >= ch->parent->num_events) {
- pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
- return;
- }
- if (ch->ns && !(ch->parent->cfg[CFG_INS] & (1 << ev_id))) {
- pl330_fault(ch, PL330_FAULT_EVENT_ERR);
- return;
- }
- if (ch->parent->inten & (1 << ev_id)) {
- ch->parent->int_status |= (1 << ev_id);
- DB_PRINT("event interrupt raised %" PRId8 "\n", ev_id);
- qemu_irq_raise(ch->parent->irq[ev_id]);
- }
- DB_PRINT("event raised %" PRId8 "\n", ev_id);
- ch->parent->ev_status |= (1 << ev_id);
-}
-
-static void pl330_dmast(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
-{
- uint8_t bs = opcode & 3;
- uint32_t size, num;
- bool inc;
-
- if (bs == 2) {
- pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
- return;
- }
- if ((bs == 1 && ch->request_flag == PL330_BURST) ||
- (bs == 3 && ch->request_flag == PL330_SINGLE)) {
- /* Perform NOP */
- return;
- }
- num = ((ch->control >> 18) & 0xf) + 1;
- size = (uint32_t)1 << ((ch->control >> 15) & 0x7);
- inc = !!((ch->control >> 14) & 1);
- ch->stall = pl330_queue_put_insn(&ch->parent->write_queue, ch->dst,
- size, num, inc, 0, ch->tag);
- if (!ch->stall) {
- DB_PRINT("channel:%" PRId8 " address:%08" PRIx32 " size:%" PRIx32
- " num:%" PRId32 " %c\n",
- ch->tag, ch->dst, size, num, inc ? 'Y' : 'N');
- ch->dst += inc ? size * num - (ch->dst & (size - 1)) : 0;
- }
-}
-
-static void pl330_dmastp(PL330Chan *ch, uint8_t opcode,
- uint8_t *args, int len)
-{
- uint8_t periph_id;
-
- if (args[0] & 7) {
- pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
- return;
- }
- periph_id = (args[0] >> 3) & 0x1f;
- if (periph_id >= ch->parent->num_periph_req) {
- pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
- return;
- }
- if (ch->ns && !(ch->parent->cfg[CFG_PNS] & (1 << periph_id))) {
- pl330_fault(ch, PL330_FAULT_CH_PERIPH_ERR);
- return;
- }
- pl330_dmast(ch, opcode, args, len);
-}
-
-static void pl330_dmastz(PL330Chan *ch, uint8_t opcode,
- uint8_t *args, int len)
-{
- uint32_t size, num;
- bool inc;
-
- num = ((ch->control >> 18) & 0xf) + 1;
- size = (uint32_t)1 << ((ch->control >> 15) & 0x7);
- inc = !!((ch->control >> 14) & 1);
- ch->stall = pl330_queue_put_insn(&ch->parent->write_queue, ch->dst,
- size, num, inc, 1, ch->tag);
- if (inc) {
- ch->dst += size * num;
- }
-}
-
-static void pl330_dmawfe(PL330Chan *ch, uint8_t opcode,
- uint8_t *args, int len)
-{
- uint8_t ev_id;
- int i;
-
- if (args[0] & 5) {
- pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
- return;
- }
- ev_id = (args[0] >> 3) & 0x1f;
- if (ev_id >= ch->parent->num_events) {
- pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
- return;
- }
- if (ch->ns && !(ch->parent->cfg[CFG_INS] & (1 << ev_id))) {
- pl330_fault(ch, PL330_FAULT_EVENT_ERR);
- return;
- }
- ch->wakeup = ev_id;
- ch->state = pl330_chan_waiting_event;
- if (~ch->parent->inten & ch->parent->ev_status & 1 << ev_id) {
- ch->state = pl330_chan_executing;
- /* If anyone else is currently waiting on the same event, let them
- * clear the ev_status so they pick up event as well
- */
- for (i = 0; i < ch->parent->num_chnls; ++i) {
- PL330Chan *peer = &ch->parent->chan[i];
- if (peer->state == pl330_chan_waiting_event &&
- peer->wakeup == ev_id) {
- return;
- }
- }
- ch->parent->ev_status &= ~(1 << ev_id);
- DB_PRINT("event lowered %" PRIx8 "\n", ev_id);
- } else {
- ch->stall = 1;
- }
-}
-
-static void pl330_dmawfp(PL330Chan *ch, uint8_t opcode,
- uint8_t *args, int len)
-{
- uint8_t bs = opcode & 3;
- uint8_t periph_id;
-
- if (args[0] & 7) {
- pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
- return;
- }
- periph_id = (args[0] >> 3) & 0x1f;
- if (periph_id >= ch->parent->num_periph_req) {
- pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
- return;
- }
- if (ch->ns && !(ch->parent->cfg[CFG_PNS] & (1 << periph_id))) {
- pl330_fault(ch, PL330_FAULT_CH_PERIPH_ERR);
- return;
- }
- switch (bs) {
- case 0: /* S */
- ch->request_flag = PL330_SINGLE;
- ch->wfp_sbp = 0;
- break;
- case 1: /* P */
- ch->request_flag = PL330_BURST;
- ch->wfp_sbp = 2;
- break;
- case 2: /* B */
- ch->request_flag = PL330_BURST;
- ch->wfp_sbp = 1;
- break;
- default:
- pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
- return;
- }
-
- if (ch->parent->periph_busy[periph_id]) {
- ch->state = pl330_chan_waiting_periph;
- ch->stall = 1;
- } else if (ch->state == pl330_chan_waiting_periph) {
- ch->state = pl330_chan_executing;
- }
-}
-
-static void pl330_dmawmb(PL330Chan *ch, uint8_t opcode,
- uint8_t *args, int len)
-{
- if (pl330_queue_find_insn(&ch->parent->write_queue, ch->tag, false)) {
- ch->state = pl330_chan_at_barrier;
- ch->stall = 1;
- return;
- } else {
- ch->state = pl330_chan_executing;
- }
-}
-
-/* NULL terminated array of the instruction descriptions. */
-static const PL330InsnDesc insn_desc[] = {
- { .opcode = 0x54, .opmask = 0xFD, .size = 3, .exec = pl330_dmaaddh, },
- { .opcode = 0x5c, .opmask = 0xFD, .size = 3, .exec = pl330_dmaadnh, },
- { .opcode = 0x00, .opmask = 0xFF, .size = 1, .exec = pl330_dmaend, },
- { .opcode = 0x35, .opmask = 0xFF, .size = 2, .exec = pl330_dmaflushp, },
- { .opcode = 0xA0, .opmask = 0xFD, .size = 6, .exec = pl330_dmago, },
- { .opcode = 0x04, .opmask = 0xFC, .size = 1, .exec = pl330_dmald, },
- { .opcode = 0x25, .opmask = 0xFD, .size = 2, .exec = pl330_dmaldp, },
- { .opcode = 0x20, .opmask = 0xFD, .size = 2, .exec = pl330_dmalp, },
- /* dmastp must be before dmalpend in this list, because their maps
- * are overlapping
- */
- { .opcode = 0x29, .opmask = 0xFD, .size = 2, .exec = pl330_dmastp, },
- { .opcode = 0x28, .opmask = 0xE8, .size = 2, .exec = pl330_dmalpend, },
- { .opcode = 0x01, .opmask = 0xFF, .size = 1, .exec = pl330_dmakill, },
- { .opcode = 0xBC, .opmask = 0xFF, .size = 6, .exec = pl330_dmamov, },
- { .opcode = 0x18, .opmask = 0xFF, .size = 1, .exec = pl330_dmanop, },
- { .opcode = 0x12, .opmask = 0xFF, .size = 1, .exec = pl330_dmarmb, },
- { .opcode = 0x34, .opmask = 0xFF, .size = 2, .exec = pl330_dmasev, },
- { .opcode = 0x08, .opmask = 0xFC, .size = 1, .exec = pl330_dmast, },
- { .opcode = 0x0C, .opmask = 0xFF, .size = 1, .exec = pl330_dmastz, },
- { .opcode = 0x36, .opmask = 0xFF, .size = 2, .exec = pl330_dmawfe, },
- { .opcode = 0x30, .opmask = 0xFC, .size = 2, .exec = pl330_dmawfp, },
- { .opcode = 0x13, .opmask = 0xFF, .size = 1, .exec = pl330_dmawmb, },
- { .opcode = 0x00, .opmask = 0x00, .size = 0, .exec = NULL, }
-};
-
-/* Instructions which can be issued via debug registers. */
-static const PL330InsnDesc debug_insn_desc[] = {
- { .opcode = 0xA0, .opmask = 0xFD, .size = 6, .exec = pl330_dmago, },
- { .opcode = 0x01, .opmask = 0xFF, .size = 1, .exec = pl330_dmakill, },
- { .opcode = 0x34, .opmask = 0xFF, .size = 2, .exec = pl330_dmasev, },
- { .opcode = 0x00, .opmask = 0x00, .size = 0, .exec = NULL, }
-};
-
-static inline const PL330InsnDesc *pl330_fetch_insn(PL330Chan *ch)
-{
- uint8_t opcode;
- int i;
-
- dma_memory_read(&address_space_memory, ch->pc, &opcode, 1);
- for (i = 0; insn_desc[i].size; i++) {
- if ((opcode & insn_desc[i].opmask) == insn_desc[i].opcode) {
- return &insn_desc[i];
- }
- }
- return NULL;
-}
-
-static inline void pl330_exec_insn(PL330Chan *ch, const PL330InsnDesc *insn)
-{
- uint8_t buf[PL330_INSN_MAXSIZE];
-
- assert(insn->size <= PL330_INSN_MAXSIZE);
- dma_memory_read(&address_space_memory, ch->pc, buf, insn->size);
- insn->exec(ch, buf[0], &buf[1], insn->size - 1);
-}
-
-static inline void pl330_update_pc(PL330Chan *ch,
- const PL330InsnDesc *insn)
-{
- ch->pc += insn->size;
-}
-
-/* Try to execute current instruction in channel CH. Number of executed
- instructions is returned (0 or 1). */
-static int pl330_chan_exec(PL330Chan *ch)
-{
- const PL330InsnDesc *insn;
-
- if (ch->state != pl330_chan_executing &&
- ch->state != pl330_chan_waiting_periph &&
- ch->state != pl330_chan_at_barrier &&
- ch->state != pl330_chan_waiting_event) {
- return 0;
- }
- ch->stall = 0;
- insn = pl330_fetch_insn(ch);
- if (!insn) {
- DB_PRINT("pl330 undefined instruction\n");
- pl330_fault(ch, PL330_FAULT_UNDEF_INSTR);
- return 0;
- }
- pl330_exec_insn(ch, insn);
- if (!ch->stall) {
- pl330_update_pc(ch, insn);
- ch->watchdog_timer = 0;
- return 1;
- /* WDT only active in exec state */
- } else if (ch->state == pl330_chan_executing) {
- ch->watchdog_timer++;
- if (ch->watchdog_timer >= PL330_WATCHDOG_LIMIT) {
- pl330_fault(ch, PL330_FAULT_LOCKUP_ERR);
- }
- }
- return 0;
-}
-
-/* Try to execute 1 instruction in each channel, one instruction from read
- queue and one instruction from write queue. Number of successfully executed
- instructions is returned. */
-static int pl330_exec_cycle(PL330Chan *channel)
-{
- PL330State *s = channel->parent;
- PL330QueueEntry *q;
- int i;
- int num_exec = 0;
- int fifo_res = 0;
- uint8_t buf[PL330_MAX_BURST_LEN];
-
- /* Execute one instruction in each channel */
- num_exec += pl330_chan_exec(channel);
-
- /* Execute one instruction from read queue */
- q = pl330_queue_find_insn(&s->read_queue, PL330_UNTAGGED, true);
- if (q != NULL && q->len <= pl330_fifo_num_free(&s->fifo)) {
- int len = q->len - (q->addr & (q->len - 1));
-
- dma_memory_read(&address_space_memory, q->addr, buf, len);
- if (PL330_ERR_DEBUG > 1) {
- DB_PRINT("PL330 read from memory @%08" PRIx32 " (size = %08x):\n",
- q->addr, len);
- qemu_hexdump((char *)buf, stderr, "", len);
- }
- fifo_res = pl330_fifo_push(&s->fifo, buf, len, q->tag);
- if (fifo_res == PL330_FIFO_OK) {
- if (q->inc) {
- q->addr += len;
- }
- q->n--;
- if (!q->n) {
- pl330_queue_remove_insn(&s->read_queue, q);
- }
- num_exec++;
- }
- }
-
- /* Execute one instruction from write queue. */
- q = pl330_queue_find_insn(&s->write_queue, pl330_fifo_tag(&s->fifo), true);
- if (q != NULL) {
- int len = q->len - (q->addr & (q->len - 1));
-
- if (q->z) {
- for (i = 0; i < len; i++) {
- buf[i] = 0;
- }
- } else {
- fifo_res = pl330_fifo_get(&s->fifo, buf, len, q->tag);
- }
- if (fifo_res == PL330_FIFO_OK || q->z) {
- dma_memory_write(&address_space_memory, q->addr, buf, len);
- if (PL330_ERR_DEBUG > 1) {
- DB_PRINT("PL330 read from memory @%08" PRIx32
- " (size = %08x):\n", q->addr, len);
- qemu_hexdump((char *)buf, stderr, "", len);
- }
- if (q->inc) {
- q->addr += len;
- }
- num_exec++;
- } else if (fifo_res == PL330_FIFO_STALL) {
- pl330_fault(&channel->parent->chan[q->tag],
- PL330_FAULT_FIFOEMPTY_ERR);
- }
- q->n--;
- if (!q->n) {
- pl330_queue_remove_insn(&s->write_queue, q);
- }
- }
-
- return num_exec;
-}
-
-static int pl330_exec_channel(PL330Chan *channel)
-{
- int insr_exec = 0;
-
- /* TODO: Is it all right to execute everything or should we do per-cycle
- simulation? */
- while (pl330_exec_cycle(channel)) {
- insr_exec++;
- }
-
- /* Detect deadlock */
- if (channel->state == pl330_chan_executing) {
- pl330_fault(channel, PL330_FAULT_LOCKUP_ERR);
- }
- /* Situation when one of the queues has deadlocked but all channels
- * have finished their programs should be impossible.
- */
-
- return insr_exec;
-}
-
-static inline void pl330_exec(PL330State *s)
-{
- DB_PRINT("\n");
- int i, insr_exec;
- do {
- insr_exec = pl330_exec_channel(&s->manager);
-
- for (i = 0; i < s->num_chnls; i++) {
- insr_exec += pl330_exec_channel(&s->chan[i]);
- }
- } while (insr_exec);
-}
-
-static void pl330_exec_cycle_timer(void *opaque)
-{
- PL330State *s = (PL330State *)opaque;
- pl330_exec(s);
-}
-
-/* Stop or restore dma operations */
-
-static void pl330_dma_stop_irq(void *opaque, int irq, int level)
-{
- PL330State *s = (PL330State *)opaque;
-
- if (s->periph_busy[irq] != level) {
- s->periph_busy[irq] = level;
- timer_mod(s->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
- }
-}
-
-static void pl330_debug_exec(PL330State *s)
-{
- uint8_t args[5];
- uint8_t opcode;
- uint8_t chan_id;
- int i;
- PL330Chan *ch;
- const PL330InsnDesc *insn;
-
- s->debug_status = 1;
- chan_id = (s->dbg[0] >> 8) & 0x07;
- opcode = (s->dbg[0] >> 16) & 0xff;
- args[0] = (s->dbg[0] >> 24) & 0xff;
- args[1] = (s->dbg[1] >> 0) & 0xff;
- args[2] = (s->dbg[1] >> 8) & 0xff;
- args[3] = (s->dbg[1] >> 16) & 0xff;
- args[4] = (s->dbg[1] >> 24) & 0xff;
- DB_PRINT("chan id: %" PRIx8 "\n", chan_id);
- if (s->dbg[0] & 1) {
- ch = &s->chan[chan_id];
- } else {
- ch = &s->manager;
- }
- insn = NULL;
- for (i = 0; debug_insn_desc[i].size; i++) {
- if ((opcode & debug_insn_desc[i].opmask) == debug_insn_desc[i].opcode) {
- insn = &debug_insn_desc[i];
- }
- }
- if (!insn) {
- pl330_fault(ch, PL330_FAULT_UNDEF_INSTR | PL330_FAULT_DBG_INSTR);
- return ;
- }
- ch->stall = 0;
- insn->exec(ch, opcode, args, insn->size - 1);
- if (ch->fault_type) {
- ch->fault_type |= PL330_FAULT_DBG_INSTR;
- }
- if (ch->stall) {
- qemu_log_mask(LOG_UNIMP, "pl330: stall of debug instruction not "
- "implemented\n");
- }
- s->debug_status = 0;
-}
-
-/* IOMEM mapped registers */
-
-static void pl330_iomem_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PL330State *s = (PL330State *) opaque;
- int i;
-
- DB_PRINT("addr: %08x data: %08x\n", (unsigned)offset, (unsigned)value);
-
- switch (offset) {
- case PL330_REG_INTEN:
- s->inten = value;
- break;
- case PL330_REG_INTCLR:
- for (i = 0; i < s->num_events; i++) {
- if (s->int_status & s->inten & value & (1 << i)) {
- DB_PRINT("event interrupt lowered %d\n", i);
- qemu_irq_lower(s->irq[i]);
- }
- }
- s->ev_status &= ~(value & s->inten);
- s->int_status &= ~(value & s->inten);
- break;
- case PL330_REG_DBGCMD:
- if ((value & 3) == 0) {
- pl330_debug_exec(s);
- pl330_exec(s);
- } else {
- qemu_log_mask(LOG_GUEST_ERROR, "pl330: write of illegal value %u "
- "for offset " TARGET_FMT_plx "\n", (unsigned)value,
- offset);
- }
- break;
- case PL330_REG_DBGINST0:
- DB_PRINT("s->dbg[0] = %08x\n", (unsigned)value);
- s->dbg[0] = value;
- break;
- case PL330_REG_DBGINST1:
- DB_PRINT("s->dbg[1] = %08x\n", (unsigned)value);
- s->dbg[1] = value;
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad write offset " TARGET_FMT_plx
- "\n", offset);
- break;
- }
-}
-
-static inline uint32_t pl330_iomem_read_imp(void *opaque,
- hwaddr offset)
-{
- PL330State *s = (PL330State *)opaque;
- int chan_id;
- int i;
- uint32_t res;
-
- if (offset >= PL330_REG_PERIPH_ID && offset < PL330_REG_PERIPH_ID + 32) {
- return pl330_id[(offset - PL330_REG_PERIPH_ID) >> 2];
- }
- if (offset >= PL330_REG_CR0_BASE && offset < PL330_REG_CR0_BASE + 24) {
- return s->cfg[(offset - PL330_REG_CR0_BASE) >> 2];
- }
- if (offset >= PL330_REG_CHANCTRL && offset < PL330_REG_DBGSTATUS) {
- offset -= PL330_REG_CHANCTRL;
- chan_id = offset >> 5;
- if (chan_id >= s->num_chnls) {
- qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad read offset "
- TARGET_FMT_plx "\n", offset);
- return 0;
- }
- switch (offset & 0x1f) {
- case 0x00:
- return s->chan[chan_id].src;
- case 0x04:
- return s->chan[chan_id].dst;
- case 0x08:
- return s->chan[chan_id].control;
- case 0x0C:
- return s->chan[chan_id].lc[0];
- case 0x10:
- return s->chan[chan_id].lc[1];
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad read offset "
- TARGET_FMT_plx "\n", offset);
- return 0;
- }
- }
- if (offset >= PL330_REG_CSR_BASE && offset < 0x400) {
- offset -= PL330_REG_CSR_BASE;
- chan_id = offset >> 3;
- if (chan_id >= s->num_chnls) {
- qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad read offset "
- TARGET_FMT_plx "\n", offset);
- return 0;
- }
- switch ((offset >> 2) & 1) {
- case 0x0:
- res = (s->chan[chan_id].ns << 21) |
- (s->chan[chan_id].wakeup << 4) |
- (s->chan[chan_id].state) |
- (s->chan[chan_id].wfp_sbp << 14);
- return res;
- case 0x1:
- return s->chan[chan_id].pc;
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "pl330: read error\n");
- return 0;
- }
- }
- if (offset >= PL330_REG_FTR_BASE && offset < 0x100) {
- offset -= PL330_REG_FTR_BASE;
- chan_id = offset >> 2;
- if (chan_id >= s->num_chnls) {
- qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad read offset "
- TARGET_FMT_plx "\n", offset);
- return 0;
- }
- return s->chan[chan_id].fault_type;
- }
- switch (offset) {
- case PL330_REG_DSR:
- return (s->manager.ns << 9) | (s->manager.wakeup << 4) |
- (s->manager.state & 0xf);
- case PL330_REG_DPC:
- return s->manager.pc;
- case PL330_REG_INTEN:
- return s->inten;
- case PL330_REG_INT_EVENT_RIS:
- return s->ev_status;
- case PL330_REG_INTMIS:
- return s->int_status;
- case PL330_REG_INTCLR:
- /* Documentation says that we can't read this register
- * but linux kernel does it
- */
- return 0;
- case PL330_REG_FSRD:
- return s->manager.state ? 1 : 0;
- case PL330_REG_FSRC:
- res = 0;
- for (i = 0; i < s->num_chnls; i++) {
- if (s->chan[i].state == pl330_chan_fault ||
- s->chan[i].state == pl330_chan_fault_completing) {
- res |= 1 << i;
- }
- }
- return res;
- case PL330_REG_FTRD:
- return s->manager.fault_type;
- case PL330_REG_DBGSTATUS:
- return s->debug_status;
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad read offset "
- TARGET_FMT_plx "\n", offset);
- }
- return 0;
-}
-
-static uint64_t pl330_iomem_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- uint32_t ret = pl330_iomem_read_imp(opaque, offset);
- DB_PRINT("addr: %08" HWADDR_PRIx " data: %08" PRIx32 "\n", offset, ret);
- return ret;
-}
-
-static const MemoryRegionOps pl330_ops = {
- .read = pl330_iomem_read,
- .write = pl330_iomem_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .impl = {
- .min_access_size = 4,
- .max_access_size = 4,
- }
-};
-
-/* Controller logic and initialization */
-
-static void pl330_chan_reset(PL330Chan *ch)
-{
- ch->src = 0;
- ch->dst = 0;
- ch->pc = 0;
- ch->state = pl330_chan_stopped;
- ch->watchdog_timer = 0;
- ch->stall = 0;
- ch->control = 0;
- ch->status = 0;
- ch->fault_type = 0;
-}
-
-static void pl330_reset(DeviceState *d)
-{
- int i;
- PL330State *s = PL330(d);
-
- s->inten = 0;
- s->int_status = 0;
- s->ev_status = 0;
- s->debug_status = 0;
- s->num_faulting = 0;
- s->manager.ns = s->mgr_ns_at_rst;
- pl330_fifo_reset(&s->fifo);
- pl330_queue_reset(&s->read_queue);
- pl330_queue_reset(&s->write_queue);
-
- for (i = 0; i < s->num_chnls; i++) {
- pl330_chan_reset(&s->chan[i]);
- }
- for (i = 0; i < s->num_periph_req; i++) {
- s->periph_busy[i] = 0;
- }
-
- timer_del(s->timer);
-}
-
-static void pl330_realize(DeviceState *dev, Error **errp)
-{
- int i;
- PL330State *s = PL330(dev);
-
- sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq_abort);
- memory_region_init_io(&s->iomem, OBJECT(s), &pl330_ops, s,
- "dma", PL330_IOMEM_SIZE);
- sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
-
- s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, pl330_exec_cycle_timer, s);
-
- s->cfg[0] = (s->mgr_ns_at_rst ? 0x4 : 0) |
- (s->num_periph_req > 0 ? 1 : 0) |
- ((s->num_chnls - 1) & 0x7) << 4 |
- ((s->num_periph_req - 1) & 0x1f) << 12 |
- ((s->num_events - 1) & 0x1f) << 17;
-
- switch (s->i_cache_len) {
- case (4):
- s->cfg[1] |= 2;
- break;
- case (8):
- s->cfg[1] |= 3;
- break;
- case (16):
- s->cfg[1] |= 4;
- break;
- case (32):
- s->cfg[1] |= 5;
- break;
- default:
- error_setg(errp, "Bad value for i-cache_len property: %" PRIx8,
- s->i_cache_len);
- return;
- }
- s->cfg[1] |= ((s->num_i_cache_lines - 1) & 0xf) << 4;
-
- s->chan = g_new0(PL330Chan, s->num_chnls);
- s->hi_seqn = g_new0(uint8_t, s->num_chnls);
- s->lo_seqn = g_new0(uint8_t, s->num_chnls);
- for (i = 0; i < s->num_chnls; i++) {
- s->chan[i].parent = s;
- s->chan[i].tag = (uint8_t)i;
- }
- s->manager.parent = s;
- s->manager.tag = s->num_chnls;
- s->manager.is_manager = true;
-
- s->irq = g_new0(qemu_irq, s->num_events);
- for (i = 0; i < s->num_events; i++) {
- sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[i]);
- }
-
- qdev_init_gpio_in(dev, pl330_dma_stop_irq, PL330_PERIPH_NUM);
-
- switch (s->data_width) {
- case (32):
- s->cfg[CFG_CRD] |= 0x2;
- break;
- case (64):
- s->cfg[CFG_CRD] |= 0x3;
- break;
- case (128):
- s->cfg[CFG_CRD] |= 0x4;
- break;
- default:
- error_setg(errp, "Bad value for data_width property: %" PRIx8,
- s->data_width);
- return;
- }
-
- s->cfg[CFG_CRD] |= ((s->wr_cap - 1) & 0x7) << 4 |
- ((s->wr_q_dep - 1) & 0xf) << 8 |
- ((s->rd_cap - 1) & 0x7) << 12 |
- ((s->rd_q_dep - 1) & 0xf) << 16 |
- ((s->data_buffer_dep - 1) & 0x1ff) << 20;
-
- pl330_queue_init(&s->read_queue, s->rd_q_dep, s);
- pl330_queue_init(&s->write_queue, s->wr_q_dep, s);
- pl330_fifo_init(&s->fifo, s->data_width / 4 * s->data_buffer_dep);
-}
-
-static Property pl330_properties[] = {
- /* CR0 */
- DEFINE_PROP_UINT32("num_chnls", PL330State, num_chnls, 8),
- DEFINE_PROP_UINT8("num_periph_req", PL330State, num_periph_req, 4),
- DEFINE_PROP_UINT8("num_events", PL330State, num_events, 16),
- DEFINE_PROP_UINT8("mgr_ns_at_rst", PL330State, mgr_ns_at_rst, 0),
- /* CR1 */
- DEFINE_PROP_UINT8("i-cache_len", PL330State, i_cache_len, 4),
- DEFINE_PROP_UINT8("num_i-cache_lines", PL330State, num_i_cache_lines, 8),
- /* CR2-4 */
- DEFINE_PROP_UINT32("boot_addr", PL330State, cfg[CFG_BOOT_ADDR], 0),
- DEFINE_PROP_UINT32("INS", PL330State, cfg[CFG_INS], 0),
- DEFINE_PROP_UINT32("PNS", PL330State, cfg[CFG_PNS], 0),
- /* CRD */
- DEFINE_PROP_UINT8("data_width", PL330State, data_width, 64),
- DEFINE_PROP_UINT8("wr_cap", PL330State, wr_cap, 8),
- DEFINE_PROP_UINT8("wr_q_dep", PL330State, wr_q_dep, 16),
- DEFINE_PROP_UINT8("rd_cap", PL330State, rd_cap, 8),
- DEFINE_PROP_UINT8("rd_q_dep", PL330State, rd_q_dep, 16),
- DEFINE_PROP_UINT16("data_buffer_dep", PL330State, data_buffer_dep, 256),
-
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pl330_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = pl330_realize;
- dc->reset = pl330_reset;
- dc->props = pl330_properties;
- dc->vmsd = &vmstate_pl330;
-}
-
-static const TypeInfo pl330_type_info = {
- .name = TYPE_PL330,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PL330State),
- .class_init = pl330_class_init,
-};
-
-static void pl330_register_types(void)
-{
- type_register_static(&pl330_type_info);
-}
-
-type_init(pl330_register_types)
diff --git a/qemu/hw/dma/puv3_dma.c b/qemu/hw/dma/puv3_dma.c
deleted file mode 100644
index b97a6c176..000000000
--- a/qemu/hw/dma/puv3_dma.c
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * DMA device simulation in PKUnity SoC
- *
- * Copyright (C) 2010-2012 Guan Xuetao
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation, or any later version.
- * See the COPYING file in the top-level directory.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-
-#undef DEBUG_PUV3
-#include "hw/unicore32/puv3.h"
-
-#define PUV3_DMA_CH_NR (6)
-#define PUV3_DMA_CH_MASK (0xff)
-#define PUV3_DMA_CH(offset) ((offset) >> 8)
-
-#define TYPE_PUV3_DMA "puv3_dma"
-#define PUV3_DMA(obj) OBJECT_CHECK(PUV3DMAState, (obj), TYPE_PUV3_DMA)
-
-typedef struct PUV3DMAState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- uint32_t reg_CFG[PUV3_DMA_CH_NR];
-} PUV3DMAState;
-
-static uint64_t puv3_dma_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- PUV3DMAState *s = opaque;
- uint32_t ret = 0;
-
- assert(PUV3_DMA_CH(offset) < PUV3_DMA_CH_NR);
-
- switch (offset & PUV3_DMA_CH_MASK) {
- case 0x10:
- ret = s->reg_CFG[PUV3_DMA_CH(offset)];
- break;
- default:
- DPRINTF("Bad offset 0x%x\n", offset);
- }
- DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
-
- return ret;
-}
-
-static void puv3_dma_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PUV3DMAState *s = opaque;
-
- assert(PUV3_DMA_CH(offset) < PUV3_DMA_CH_NR);
-
- switch (offset & PUV3_DMA_CH_MASK) {
- case 0x10:
- s->reg_CFG[PUV3_DMA_CH(offset)] = value;
- break;
- default:
- DPRINTF("Bad offset 0x%x\n", offset);
- }
- DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
-}
-
-static const MemoryRegionOps puv3_dma_ops = {
- .read = puv3_dma_read,
- .write = puv3_dma_write,
- .impl = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int puv3_dma_init(SysBusDevice *dev)
-{
- PUV3DMAState *s = PUV3_DMA(dev);
- int i;
-
- for (i = 0; i < PUV3_DMA_CH_NR; i++) {
- s->reg_CFG[i] = 0x0;
- }
-
- memory_region_init_io(&s->iomem, OBJECT(s), &puv3_dma_ops, s, "puv3_dma",
- PUV3_REGS_OFFSET);
- sysbus_init_mmio(dev, &s->iomem);
-
- return 0;
-}
-
-static void puv3_dma_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
- sdc->init = puv3_dma_init;
-}
-
-static const TypeInfo puv3_dma_info = {
- .name = TYPE_PUV3_DMA,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PUV3DMAState),
- .class_init = puv3_dma_class_init,
-};
-
-static void puv3_dma_register_type(void)
-{
- type_register_static(&puv3_dma_info);
-}
-
-type_init(puv3_dma_register_type)
diff --git a/qemu/hw/dma/pxa2xx_dma.c b/qemu/hw/dma/pxa2xx_dma.c
deleted file mode 100644
index 2306abc35..000000000
--- a/qemu/hw/dma/pxa2xx_dma.c
+++ /dev/null
@@ -1,576 +0,0 @@
-/*
- * Intel XScale PXA255/270 DMA controller.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Copyright (c) 2006 Thorsten Zitterell
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GPL.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/arm/pxa.h"
-#include "hw/sysbus.h"
-
-#define PXA255_DMA_NUM_CHANNELS 16
-#define PXA27X_DMA_NUM_CHANNELS 32
-
-#define PXA2XX_DMA_NUM_REQUESTS 75
-
-typedef struct {
- uint32_t descr;
- uint32_t src;
- uint32_t dest;
- uint32_t cmd;
- uint32_t state;
- int request;
-} PXA2xxDMAChannel;
-
-#define TYPE_PXA2XX_DMA "pxa2xx-dma"
-#define PXA2XX_DMA(obj) OBJECT_CHECK(PXA2xxDMAState, (obj), TYPE_PXA2XX_DMA)
-
-typedef struct PXA2xxDMAState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- qemu_irq irq;
-
- uint32_t stopintr;
- uint32_t eorintr;
- uint32_t rasintr;
- uint32_t startintr;
- uint32_t endintr;
-
- uint32_t align;
- uint32_t pio;
-
- int channels;
- PXA2xxDMAChannel *chan;
-
- uint8_t req[PXA2XX_DMA_NUM_REQUESTS];
-
- /* Flag to avoid recursive DMA invocations. */
- int running;
-} PXA2xxDMAState;
-
-#define DCSR0 0x0000 /* DMA Control / Status register for Channel 0 */
-#define DCSR31 0x007c /* DMA Control / Status register for Channel 31 */
-#define DALGN 0x00a0 /* DMA Alignment register */
-#define DPCSR 0x00a4 /* DMA Programmed I/O Control Status register */
-#define DRQSR0 0x00e0 /* DMA DREQ<0> Status register */
-#define DRQSR1 0x00e4 /* DMA DREQ<1> Status register */
-#define DRQSR2 0x00e8 /* DMA DREQ<2> Status register */
-#define DINT 0x00f0 /* DMA Interrupt register */
-#define DRCMR0 0x0100 /* Request to Channel Map register 0 */
-#define DRCMR63 0x01fc /* Request to Channel Map register 63 */
-#define D_CH0 0x0200 /* Channel 0 Descriptor start */
-#define DRCMR64 0x1100 /* Request to Channel Map register 64 */
-#define DRCMR74 0x1128 /* Request to Channel Map register 74 */
-
-/* Per-channel register */
-#define DDADR 0x00
-#define DSADR 0x01
-#define DTADR 0x02
-#define DCMD 0x03
-
-/* Bit-field masks */
-#define DRCMR_CHLNUM 0x1f
-#define DRCMR_MAPVLD (1 << 7)
-#define DDADR_STOP (1 << 0)
-#define DDADR_BREN (1 << 1)
-#define DCMD_LEN 0x1fff
-#define DCMD_WIDTH(x) (1 << ((((x) >> 14) & 3) - 1))
-#define DCMD_SIZE(x) (4 << (((x) >> 16) & 3))
-#define DCMD_FLYBYT (1 << 19)
-#define DCMD_FLYBYS (1 << 20)
-#define DCMD_ENDIRQEN (1 << 21)
-#define DCMD_STARTIRQEN (1 << 22)
-#define DCMD_CMPEN (1 << 25)
-#define DCMD_FLOWTRG (1 << 28)
-#define DCMD_FLOWSRC (1 << 29)
-#define DCMD_INCTRGADDR (1 << 30)
-#define DCMD_INCSRCADDR (1 << 31)
-#define DCSR_BUSERRINTR (1 << 0)
-#define DCSR_STARTINTR (1 << 1)
-#define DCSR_ENDINTR (1 << 2)
-#define DCSR_STOPINTR (1 << 3)
-#define DCSR_RASINTR (1 << 4)
-#define DCSR_REQPEND (1 << 8)
-#define DCSR_EORINT (1 << 9)
-#define DCSR_CMPST (1 << 10)
-#define DCSR_MASKRUN (1 << 22)
-#define DCSR_RASIRQEN (1 << 23)
-#define DCSR_CLRCMPST (1 << 24)
-#define DCSR_SETCMPST (1 << 25)
-#define DCSR_EORSTOPEN (1 << 26)
-#define DCSR_EORJMPEN (1 << 27)
-#define DCSR_EORIRQEN (1 << 28)
-#define DCSR_STOPIRQEN (1 << 29)
-#define DCSR_NODESCFETCH (1 << 30)
-#define DCSR_RUN (1 << 31)
-
-static inline void pxa2xx_dma_update(PXA2xxDMAState *s, int ch)
-{
- if (ch >= 0) {
- if ((s->chan[ch].state & DCSR_STOPIRQEN) &&
- (s->chan[ch].state & DCSR_STOPINTR))
- s->stopintr |= 1 << ch;
- else
- s->stopintr &= ~(1 << ch);
-
- if ((s->chan[ch].state & DCSR_EORIRQEN) &&
- (s->chan[ch].state & DCSR_EORINT))
- s->eorintr |= 1 << ch;
- else
- s->eorintr &= ~(1 << ch);
-
- if ((s->chan[ch].state & DCSR_RASIRQEN) &&
- (s->chan[ch].state & DCSR_RASINTR))
- s->rasintr |= 1 << ch;
- else
- s->rasintr &= ~(1 << ch);
-
- if (s->chan[ch].state & DCSR_STARTINTR)
- s->startintr |= 1 << ch;
- else
- s->startintr &= ~(1 << ch);
-
- if (s->chan[ch].state & DCSR_ENDINTR)
- s->endintr |= 1 << ch;
- else
- s->endintr &= ~(1 << ch);
- }
-
- if (s->stopintr | s->eorintr | s->rasintr | s->startintr | s->endintr)
- qemu_irq_raise(s->irq);
- else
- qemu_irq_lower(s->irq);
-}
-
-static inline void pxa2xx_dma_descriptor_fetch(
- PXA2xxDMAState *s, int ch)
-{
- uint32_t desc[4];
- hwaddr daddr = s->chan[ch].descr & ~0xf;
- if ((s->chan[ch].descr & DDADR_BREN) && (s->chan[ch].state & DCSR_CMPST))
- daddr += 32;
-
- cpu_physical_memory_read(daddr, desc, 16);
- s->chan[ch].descr = desc[DDADR];
- s->chan[ch].src = desc[DSADR];
- s->chan[ch].dest = desc[DTADR];
- s->chan[ch].cmd = desc[DCMD];
-
- if (s->chan[ch].cmd & DCMD_FLOWSRC)
- s->chan[ch].src &= ~3;
- if (s->chan[ch].cmd & DCMD_FLOWTRG)
- s->chan[ch].dest &= ~3;
-
- if (s->chan[ch].cmd & (DCMD_CMPEN | DCMD_FLYBYS | DCMD_FLYBYT))
- printf("%s: unsupported mode in channel %i\n", __FUNCTION__, ch);
-
- if (s->chan[ch].cmd & DCMD_STARTIRQEN)
- s->chan[ch].state |= DCSR_STARTINTR;
-}
-
-static void pxa2xx_dma_run(PXA2xxDMAState *s)
-{
- int c, srcinc, destinc;
- uint32_t n, size;
- uint32_t width;
- uint32_t length;
- uint8_t buffer[32];
- PXA2xxDMAChannel *ch;
-
- if (s->running ++)
- return;
-
- while (s->running) {
- s->running = 1;
- for (c = 0; c < s->channels; c ++) {
- ch = &s->chan[c];
-
- while ((ch->state & DCSR_RUN) && !(ch->state & DCSR_STOPINTR)) {
- /* Test for pending requests */
- if ((ch->cmd & (DCMD_FLOWSRC | DCMD_FLOWTRG)) && !ch->request)
- break;
-
- length = ch->cmd & DCMD_LEN;
- size = DCMD_SIZE(ch->cmd);
- width = DCMD_WIDTH(ch->cmd);
-
- srcinc = (ch->cmd & DCMD_INCSRCADDR) ? width : 0;
- destinc = (ch->cmd & DCMD_INCTRGADDR) ? width : 0;
-
- while (length) {
- size = MIN(length, size);
-
- for (n = 0; n < size; n += width) {
- cpu_physical_memory_read(ch->src, buffer + n, width);
- ch->src += srcinc;
- }
-
- for (n = 0; n < size; n += width) {
- cpu_physical_memory_write(ch->dest, buffer + n, width);
- ch->dest += destinc;
- }
-
- length -= size;
-
- if ((ch->cmd & (DCMD_FLOWSRC | DCMD_FLOWTRG)) &&
- !ch->request) {
- ch->state |= DCSR_EORINT;
- if (ch->state & DCSR_EORSTOPEN)
- ch->state |= DCSR_STOPINTR;
- if ((ch->state & DCSR_EORJMPEN) &&
- !(ch->state & DCSR_NODESCFETCH))
- pxa2xx_dma_descriptor_fetch(s, c);
- break;
- }
- }
-
- ch->cmd = (ch->cmd & ~DCMD_LEN) | length;
-
- /* Is the transfer complete now? */
- if (!length) {
- if (ch->cmd & DCMD_ENDIRQEN)
- ch->state |= DCSR_ENDINTR;
-
- if ((ch->state & DCSR_NODESCFETCH) ||
- (ch->descr & DDADR_STOP) ||
- (ch->state & DCSR_EORSTOPEN)) {
- ch->state |= DCSR_STOPINTR;
- ch->state &= ~DCSR_RUN;
-
- break;
- }
-
- ch->state |= DCSR_STOPINTR;
- break;
- }
- }
- }
-
- s->running --;
- }
-}
-
-static uint64_t pxa2xx_dma_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- PXA2xxDMAState *s = (PXA2xxDMAState *) opaque;
- unsigned int channel;
-
- if (size != 4) {
- hw_error("%s: Bad access width\n", __FUNCTION__);
- return 5;
- }
-
- switch (offset) {
- case DRCMR64 ... DRCMR74:
- offset -= DRCMR64 - DRCMR0 - (64 << 2);
- /* Fall through */
- case DRCMR0 ... DRCMR63:
- channel = (offset - DRCMR0) >> 2;
- return s->req[channel];
-
- case DRQSR0:
- case DRQSR1:
- case DRQSR2:
- return 0;
-
- case DCSR0 ... DCSR31:
- channel = offset >> 2;
- if (s->chan[channel].request)
- return s->chan[channel].state | DCSR_REQPEND;
- return s->chan[channel].state;
-
- case DINT:
- return s->stopintr | s->eorintr | s->rasintr |
- s->startintr | s->endintr;
-
- case DALGN:
- return s->align;
-
- case DPCSR:
- return s->pio;
- }
-
- if (offset >= D_CH0 && offset < D_CH0 + (s->channels << 4)) {
- channel = (offset - D_CH0) >> 4;
- switch ((offset & 0x0f) >> 2) {
- case DDADR:
- return s->chan[channel].descr;
- case DSADR:
- return s->chan[channel].src;
- case DTADR:
- return s->chan[channel].dest;
- case DCMD:
- return s->chan[channel].cmd;
- }
- }
-
- hw_error("%s: Bad offset 0x" TARGET_FMT_plx "\n", __FUNCTION__, offset);
- return 7;
-}
-
-static void pxa2xx_dma_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PXA2xxDMAState *s = (PXA2xxDMAState *) opaque;
- unsigned int channel;
-
- if (size != 4) {
- hw_error("%s: Bad access width\n", __FUNCTION__);
- return;
- }
-
- switch (offset) {
- case DRCMR64 ... DRCMR74:
- offset -= DRCMR64 - DRCMR0 - (64 << 2);
- /* Fall through */
- case DRCMR0 ... DRCMR63:
- channel = (offset - DRCMR0) >> 2;
-
- if (value & DRCMR_MAPVLD)
- if ((value & DRCMR_CHLNUM) > s->channels)
- hw_error("%s: Bad DMA channel %i\n",
- __FUNCTION__, (unsigned)value & DRCMR_CHLNUM);
-
- s->req[channel] = value;
- break;
-
- case DRQSR0:
- case DRQSR1:
- case DRQSR2:
- /* Nothing to do */
- break;
-
- case DCSR0 ... DCSR31:
- channel = offset >> 2;
- s->chan[channel].state &= 0x0000071f & ~(value &
- (DCSR_EORINT | DCSR_ENDINTR |
- DCSR_STARTINTR | DCSR_BUSERRINTR));
- s->chan[channel].state |= value & 0xfc800000;
-
- if (s->chan[channel].state & DCSR_STOPIRQEN)
- s->chan[channel].state &= ~DCSR_STOPINTR;
-
- if (value & DCSR_NODESCFETCH) {
- /* No-descriptor-fetch mode */
- if (value & DCSR_RUN) {
- s->chan[channel].state &= ~DCSR_STOPINTR;
- pxa2xx_dma_run(s);
- }
- } else {
- /* Descriptor-fetch mode */
- if (value & DCSR_RUN) {
- s->chan[channel].state &= ~DCSR_STOPINTR;
- pxa2xx_dma_descriptor_fetch(s, channel);
- pxa2xx_dma_run(s);
- }
- }
-
- /* Shouldn't matter as our DMA is synchronous. */
- if (!(value & (DCSR_RUN | DCSR_MASKRUN)))
- s->chan[channel].state |= DCSR_STOPINTR;
-
- if (value & DCSR_CLRCMPST)
- s->chan[channel].state &= ~DCSR_CMPST;
- if (value & DCSR_SETCMPST)
- s->chan[channel].state |= DCSR_CMPST;
-
- pxa2xx_dma_update(s, channel);
- break;
-
- case DALGN:
- s->align = value;
- break;
-
- case DPCSR:
- s->pio = value & 0x80000001;
- break;
-
- default:
- if (offset >= D_CH0 && offset < D_CH0 + (s->channels << 4)) {
- channel = (offset - D_CH0) >> 4;
- switch ((offset & 0x0f) >> 2) {
- case DDADR:
- s->chan[channel].descr = value;
- break;
- case DSADR:
- s->chan[channel].src = value;
- break;
- case DTADR:
- s->chan[channel].dest = value;
- break;
- case DCMD:
- s->chan[channel].cmd = value;
- break;
- default:
- goto fail;
- }
-
- break;
- }
- fail:
- hw_error("%s: Bad offset " TARGET_FMT_plx "\n", __FUNCTION__, offset);
- }
-}
-
-static const MemoryRegionOps pxa2xx_dma_ops = {
- .read = pxa2xx_dma_read,
- .write = pxa2xx_dma_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void pxa2xx_dma_request(void *opaque, int req_num, int on)
-{
- PXA2xxDMAState *s = opaque;
- int ch;
- if (req_num < 0 || req_num >= PXA2XX_DMA_NUM_REQUESTS)
- hw_error("%s: Bad DMA request %i\n", __FUNCTION__, req_num);
-
- if (!(s->req[req_num] & DRCMR_MAPVLD))
- return;
- ch = s->req[req_num] & DRCMR_CHLNUM;
-
- if (!s->chan[ch].request && on)
- s->chan[ch].state |= DCSR_RASINTR;
- else
- s->chan[ch].state &= ~DCSR_RASINTR;
- if (s->chan[ch].request && !on)
- s->chan[ch].state |= DCSR_EORINT;
-
- s->chan[ch].request = on;
- if (on) {
- pxa2xx_dma_run(s);
- pxa2xx_dma_update(s, ch);
- }
-}
-
-static int pxa2xx_dma_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- PXA2xxDMAState *s = PXA2XX_DMA(dev);
- int i;
-
- if (s->channels <= 0) {
- return -1;
- }
-
- s->chan = g_new0(PXA2xxDMAChannel, s->channels);
-
- for (i = 0; i < s->channels; i ++)
- s->chan[i].state = DCSR_STOPINTR;
-
- memset(s->req, 0, sizeof(uint8_t) * PXA2XX_DMA_NUM_REQUESTS);
-
- qdev_init_gpio_in(dev, pxa2xx_dma_request, PXA2XX_DMA_NUM_REQUESTS);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &pxa2xx_dma_ops, s,
- "pxa2xx.dma", 0x00010000);
- sysbus_init_mmio(sbd, &s->iomem);
- sysbus_init_irq(sbd, &s->irq);
-
- return 0;
-}
-
-DeviceState *pxa27x_dma_init(hwaddr base, qemu_irq irq)
-{
- DeviceState *dev;
-
- dev = qdev_create(NULL, "pxa2xx-dma");
- qdev_prop_set_int32(dev, "channels", PXA27X_DMA_NUM_CHANNELS);
- qdev_init_nofail(dev);
-
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
-
- return dev;
-}
-
-DeviceState *pxa255_dma_init(hwaddr base, qemu_irq irq)
-{
- DeviceState *dev;
-
- dev = qdev_create(NULL, "pxa2xx-dma");
- qdev_prop_set_int32(dev, "channels", PXA27X_DMA_NUM_CHANNELS);
- qdev_init_nofail(dev);
-
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
-
- return dev;
-}
-
-static bool is_version_0(void *opaque, int version_id)
-{
- return version_id == 0;
-}
-
-static VMStateDescription vmstate_pxa2xx_dma_chan = {
- .name = "pxa2xx_dma_chan",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(descr, PXA2xxDMAChannel),
- VMSTATE_UINT32(src, PXA2xxDMAChannel),
- VMSTATE_UINT32(dest, PXA2xxDMAChannel),
- VMSTATE_UINT32(cmd, PXA2xxDMAChannel),
- VMSTATE_UINT32(state, PXA2xxDMAChannel),
- VMSTATE_INT32(request, PXA2xxDMAChannel),
- VMSTATE_END_OF_LIST(),
- },
-};
-
-static VMStateDescription vmstate_pxa2xx_dma = {
- .name = "pxa2xx_dma",
- .version_id = 1,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_UNUSED_TEST(is_version_0, 4),
- VMSTATE_UINT32(stopintr, PXA2xxDMAState),
- VMSTATE_UINT32(eorintr, PXA2xxDMAState),
- VMSTATE_UINT32(rasintr, PXA2xxDMAState),
- VMSTATE_UINT32(startintr, PXA2xxDMAState),
- VMSTATE_UINT32(endintr, PXA2xxDMAState),
- VMSTATE_UINT32(align, PXA2xxDMAState),
- VMSTATE_UINT32(pio, PXA2xxDMAState),
- VMSTATE_BUFFER(req, PXA2xxDMAState),
- VMSTATE_STRUCT_VARRAY_POINTER_INT32(chan, PXA2xxDMAState, channels,
- vmstate_pxa2xx_dma_chan, PXA2xxDMAChannel),
- VMSTATE_END_OF_LIST(),
- },
-};
-
-static Property pxa2xx_dma_properties[] = {
- DEFINE_PROP_INT32("channels", PXA2xxDMAState, channels, -1),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pxa2xx_dma_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = pxa2xx_dma_init;
- dc->desc = "PXA2xx DMA controller";
- dc->vmsd = &vmstate_pxa2xx_dma;
- dc->props = pxa2xx_dma_properties;
-}
-
-static const TypeInfo pxa2xx_dma_info = {
- .name = TYPE_PXA2XX_DMA,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PXA2xxDMAState),
- .class_init = pxa2xx_dma_class_init,
-};
-
-static void pxa2xx_dma_register_types(void)
-{
- type_register_static(&pxa2xx_dma_info);
-}
-
-type_init(pxa2xx_dma_register_types)
diff --git a/qemu/hw/dma/rc4030.c b/qemu/hw/dma/rc4030.c
deleted file mode 100644
index a06c2359a..000000000
--- a/qemu/hw/dma/rc4030.c
+++ /dev/null
@@ -1,842 +0,0 @@
-/*
- * QEMU JAZZ RC4030 chipset
- *
- * Copyright (c) 2007-2013 Hervé Poussineau
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/mips/mips.h"
-#include "hw/sysbus.h"
-#include "qemu/timer.h"
-#include "exec/address-spaces.h"
-#include "trace.h"
-
-/********************************************************/
-/* rc4030 emulation */
-
-#define MAX_TL_ENTRIES 512
-
-typedef struct dma_pagetable_entry {
- int32_t frame;
- int32_t owner;
-} QEMU_PACKED dma_pagetable_entry;
-
-#define DMA_PAGESIZE 4096
-#define DMA_REG_ENABLE 1
-#define DMA_REG_COUNT 2
-#define DMA_REG_ADDRESS 3
-
-#define DMA_FLAG_ENABLE 0x0001
-#define DMA_FLAG_MEM_TO_DEV 0x0002
-#define DMA_FLAG_TC_INTR 0x0100
-#define DMA_FLAG_MEM_INTR 0x0200
-#define DMA_FLAG_ADDR_INTR 0x0400
-
-#define TYPE_RC4030 "rc4030"
-#define RC4030(obj) \
- OBJECT_CHECK(rc4030State, (obj), TYPE_RC4030)
-
-typedef struct rc4030State
-{
- SysBusDevice parent;
-
- uint32_t config; /* 0x0000: RC4030 config register */
- uint32_t revision; /* 0x0008: RC4030 Revision register */
- uint32_t invalid_address_register; /* 0x0010: Invalid Address register */
-
- /* DMA */
- uint32_t dma_regs[8][4];
- uint32_t dma_tl_base; /* 0x0018: DMA transl. table base */
- uint32_t dma_tl_limit; /* 0x0020: DMA transl. table limit */
-
- /* cache */
- uint32_t cache_maint; /* 0x0030: Cache Maintenance */
- uint32_t remote_failed_address; /* 0x0038: Remote Failed Address */
- uint32_t memory_failed_address; /* 0x0040: Memory Failed Address */
- uint32_t cache_ptag; /* 0x0048: I/O Cache Physical Tag */
- uint32_t cache_ltag; /* 0x0050: I/O Cache Logical Tag */
- uint32_t cache_bmask; /* 0x0058: I/O Cache Byte Mask */
-
- uint32_t nmi_interrupt; /* 0x0200: interrupt source */
- uint32_t memory_refresh_rate; /* 0x0210: memory refresh rate */
- uint32_t nvram_protect; /* 0x0220: NV ram protect register */
- uint32_t rem_speed[16];
- uint32_t imr_jazz; /* Local bus int enable mask */
- uint32_t isr_jazz; /* Local bus int source */
-
- /* timer */
- QEMUTimer *periodic_timer;
- uint32_t itr; /* Interval timer reload */
-
- qemu_irq timer_irq;
- qemu_irq jazz_bus_irq;
-
- /* biggest translation table */
- MemoryRegion dma_tt;
- /* translation table memory region alias, added to system RAM */
- MemoryRegion dma_tt_alias;
- /* whole DMA memory region, root of DMA address space */
- MemoryRegion dma_mr;
- /* translation table entry aliases, added to DMA memory region */
- MemoryRegion dma_mrs[MAX_TL_ENTRIES];
- AddressSpace dma_as;
-
- MemoryRegion iomem_chipset;
- MemoryRegion iomem_jazzio;
-} rc4030State;
-
-static void set_next_tick(rc4030State *s)
-{
- qemu_irq_lower(s->timer_irq);
- uint32_t tm_hz;
-
- tm_hz = 1000 / (s->itr + 1);
-
- timer_mod(s->periodic_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- NANOSECONDS_PER_SECOND / tm_hz);
-}
-
-/* called for accesses to rc4030 */
-static uint64_t rc4030_read(void *opaque, hwaddr addr, unsigned int size)
-{
- rc4030State *s = opaque;
- uint32_t val;
-
- addr &= 0x3fff;
- switch (addr & ~0x3) {
- /* Global config register */
- case 0x0000:
- val = s->config;
- break;
- /* Revision register */
- case 0x0008:
- val = s->revision;
- break;
- /* Invalid Address register */
- case 0x0010:
- val = s->invalid_address_register;
- break;
- /* DMA transl. table base */
- case 0x0018:
- val = s->dma_tl_base;
- break;
- /* DMA transl. table limit */
- case 0x0020:
- val = s->dma_tl_limit;
- break;
- /* Remote Failed Address */
- case 0x0038:
- val = s->remote_failed_address;
- break;
- /* Memory Failed Address */
- case 0x0040:
- val = s->memory_failed_address;
- break;
- /* I/O Cache Byte Mask */
- case 0x0058:
- val = s->cache_bmask;
- /* HACK */
- if (s->cache_bmask == (uint32_t)-1)
- s->cache_bmask = 0;
- break;
- /* Remote Speed Registers */
- case 0x0070:
- case 0x0078:
- case 0x0080:
- case 0x0088:
- case 0x0090:
- case 0x0098:
- case 0x00a0:
- case 0x00a8:
- case 0x00b0:
- case 0x00b8:
- case 0x00c0:
- case 0x00c8:
- case 0x00d0:
- case 0x00d8:
- case 0x00e0:
- case 0x00e8:
- val = s->rem_speed[(addr - 0x0070) >> 3];
- break;
- /* DMA channel base address */
- case 0x0100:
- case 0x0108:
- case 0x0110:
- case 0x0118:
- case 0x0120:
- case 0x0128:
- case 0x0130:
- case 0x0138:
- case 0x0140:
- case 0x0148:
- case 0x0150:
- case 0x0158:
- case 0x0160:
- case 0x0168:
- case 0x0170:
- case 0x0178:
- case 0x0180:
- case 0x0188:
- case 0x0190:
- case 0x0198:
- case 0x01a0:
- case 0x01a8:
- case 0x01b0:
- case 0x01b8:
- case 0x01c0:
- case 0x01c8:
- case 0x01d0:
- case 0x01d8:
- case 0x01e0:
- case 0x01e8:
- case 0x01f0:
- case 0x01f8:
- {
- int entry = (addr - 0x0100) >> 5;
- int idx = (addr & 0x1f) >> 3;
- val = s->dma_regs[entry][idx];
- }
- break;
- /* Interrupt source */
- case 0x0200:
- val = s->nmi_interrupt;
- break;
- /* Error type */
- case 0x0208:
- val = 0;
- break;
- /* Memory refresh rate */
- case 0x0210:
- val = s->memory_refresh_rate;
- break;
- /* NV ram protect register */
- case 0x0220:
- val = s->nvram_protect;
- break;
- /* Interval timer count */
- case 0x0230:
- val = 0;
- qemu_irq_lower(s->timer_irq);
- break;
- /* EISA interrupt */
- case 0x0238:
- val = 7; /* FIXME: should be read from EISA controller */
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "rc4030: invalid read at 0x%x", (int)addr);
- val = 0;
- break;
- }
-
- if ((addr & ~3) != 0x230) {
- trace_rc4030_read(addr, val);
- }
-
- return val;
-}
-
-static void rc4030_dma_as_update_one(rc4030State *s, int index, uint32_t frame)
-{
- if (index < MAX_TL_ENTRIES) {
- memory_region_set_enabled(&s->dma_mrs[index], false);
- }
-
- if (!frame) {
- return;
- }
-
- if (index >= MAX_TL_ENTRIES) {
- qemu_log_mask(LOG_UNIMP,
- "rc4030: trying to use too high "
- "translation table entry %d (max allowed=%d)",
- index, MAX_TL_ENTRIES);
- return;
- }
- memory_region_set_alias_offset(&s->dma_mrs[index], frame);
- memory_region_set_enabled(&s->dma_mrs[index], true);
-}
-
-static void rc4030_dma_tt_write(void *opaque, hwaddr addr, uint64_t data,
- unsigned int size)
-{
- rc4030State *s = opaque;
-
- /* write memory */
- memcpy(memory_region_get_ram_ptr(&s->dma_tt) + addr, &data, size);
-
- /* update dma address space (only if frame field has been written) */
- if (addr % sizeof(dma_pagetable_entry) == 0) {
- int index = addr / sizeof(dma_pagetable_entry);
- memory_region_transaction_begin();
- rc4030_dma_as_update_one(s, index, (uint32_t)data);
- memory_region_transaction_commit();
- }
-}
-
-static const MemoryRegionOps rc4030_dma_tt_ops = {
- .write = rc4030_dma_tt_write,
- .impl.min_access_size = 4,
- .impl.max_access_size = 4,
-};
-
-static void rc4030_dma_tt_update(rc4030State *s, uint32_t new_tl_base,
- uint32_t new_tl_limit)
-{
- int entries, i;
- dma_pagetable_entry *dma_tl_contents;
-
- if (s->dma_tl_limit) {
- /* write old dma tl table to physical memory */
- memory_region_del_subregion(get_system_memory(), &s->dma_tt_alias);
- cpu_physical_memory_write(s->dma_tl_limit & 0x7fffffff,
- memory_region_get_ram_ptr(&s->dma_tt),
- memory_region_size(&s->dma_tt_alias));
- }
- object_unparent(OBJECT(&s->dma_tt_alias));
-
- s->dma_tl_base = new_tl_base;
- s->dma_tl_limit = new_tl_limit;
- new_tl_base &= 0x7fffffff;
-
- if (s->dma_tl_limit) {
- uint64_t dma_tt_size;
- if (s->dma_tl_limit <= memory_region_size(&s->dma_tt)) {
- dma_tt_size = s->dma_tl_limit;
- } else {
- dma_tt_size = memory_region_size(&s->dma_tt);
- }
- memory_region_init_alias(&s->dma_tt_alias, OBJECT(s),
- "dma-table-alias",
- &s->dma_tt, 0, dma_tt_size);
- dma_tl_contents = memory_region_get_ram_ptr(&s->dma_tt);
- cpu_physical_memory_read(new_tl_base, dma_tl_contents, dma_tt_size);
-
- memory_region_transaction_begin();
- entries = dma_tt_size / sizeof(dma_pagetable_entry);
- for (i = 0; i < entries; i++) {
- rc4030_dma_as_update_one(s, i, dma_tl_contents[i].frame);
- }
- memory_region_add_subregion(get_system_memory(), new_tl_base,
- &s->dma_tt_alias);
- memory_region_transaction_commit();
- } else {
- memory_region_init(&s->dma_tt_alias, OBJECT(s),
- "dma-table-alias", 0);
- }
-}
-
-static void rc4030_write(void *opaque, hwaddr addr, uint64_t data,
- unsigned int size)
-{
- rc4030State *s = opaque;
- uint32_t val = data;
- addr &= 0x3fff;
-
- trace_rc4030_write(addr, val);
-
- switch (addr & ~0x3) {
- /* Global config register */
- case 0x0000:
- s->config = val;
- break;
- /* DMA transl. table base */
- case 0x0018:
- rc4030_dma_tt_update(s, val, s->dma_tl_limit);
- break;
- /* DMA transl. table limit */
- case 0x0020:
- rc4030_dma_tt_update(s, s->dma_tl_base, val);
- break;
- /* DMA transl. table invalidated */
- case 0x0028:
- break;
- /* Cache Maintenance */
- case 0x0030:
- s->cache_maint = val;
- break;
- /* I/O Cache Physical Tag */
- case 0x0048:
- s->cache_ptag = val;
- break;
- /* I/O Cache Logical Tag */
- case 0x0050:
- s->cache_ltag = val;
- break;
- /* I/O Cache Byte Mask */
- case 0x0058:
- s->cache_bmask |= val; /* HACK */
- break;
- /* I/O Cache Buffer Window */
- case 0x0060:
- /* HACK */
- if (s->cache_ltag == 0x80000001 && s->cache_bmask == 0xf0f0f0f) {
- hwaddr dest = s->cache_ptag & ~0x1;
- dest += (s->cache_maint & 0x3) << 3;
- cpu_physical_memory_write(dest, &val, 4);
- }
- break;
- /* Remote Speed Registers */
- case 0x0070:
- case 0x0078:
- case 0x0080:
- case 0x0088:
- case 0x0090:
- case 0x0098:
- case 0x00a0:
- case 0x00a8:
- case 0x00b0:
- case 0x00b8:
- case 0x00c0:
- case 0x00c8:
- case 0x00d0:
- case 0x00d8:
- case 0x00e0:
- case 0x00e8:
- s->rem_speed[(addr - 0x0070) >> 3] = val;
- break;
- /* DMA channel base address */
- case 0x0100:
- case 0x0108:
- case 0x0110:
- case 0x0118:
- case 0x0120:
- case 0x0128:
- case 0x0130:
- case 0x0138:
- case 0x0140:
- case 0x0148:
- case 0x0150:
- case 0x0158:
- case 0x0160:
- case 0x0168:
- case 0x0170:
- case 0x0178:
- case 0x0180:
- case 0x0188:
- case 0x0190:
- case 0x0198:
- case 0x01a0:
- case 0x01a8:
- case 0x01b0:
- case 0x01b8:
- case 0x01c0:
- case 0x01c8:
- case 0x01d0:
- case 0x01d8:
- case 0x01e0:
- case 0x01e8:
- case 0x01f0:
- case 0x01f8:
- {
- int entry = (addr - 0x0100) >> 5;
- int idx = (addr & 0x1f) >> 3;
- s->dma_regs[entry][idx] = val;
- }
- break;
- /* Memory refresh rate */
- case 0x0210:
- s->memory_refresh_rate = val;
- break;
- /* Interval timer reload */
- case 0x0228:
- s->itr = val;
- qemu_irq_lower(s->timer_irq);
- set_next_tick(s);
- break;
- /* EISA interrupt */
- case 0x0238:
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "rc4030: invalid write of 0x%02x at 0x%x",
- val, (int)addr);
- break;
- }
-}
-
-static const MemoryRegionOps rc4030_ops = {
- .read = rc4030_read,
- .write = rc4030_write,
- .impl.min_access_size = 4,
- .impl.max_access_size = 4,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void update_jazz_irq(rc4030State *s)
-{
- uint16_t pending;
-
- pending = s->isr_jazz & s->imr_jazz;
-
- if (pending != 0)
- qemu_irq_raise(s->jazz_bus_irq);
- else
- qemu_irq_lower(s->jazz_bus_irq);
-}
-
-static void rc4030_irq_jazz_request(void *opaque, int irq, int level)
-{
- rc4030State *s = opaque;
-
- if (level) {
- s->isr_jazz |= 1 << irq;
- } else {
- s->isr_jazz &= ~(1 << irq);
- }
-
- update_jazz_irq(s);
-}
-
-static void rc4030_periodic_timer(void *opaque)
-{
- rc4030State *s = opaque;
-
- set_next_tick(s);
- qemu_irq_raise(s->timer_irq);
-}
-
-static uint64_t jazzio_read(void *opaque, hwaddr addr, unsigned int size)
-{
- rc4030State *s = opaque;
- uint32_t val;
- uint32_t irq;
- addr &= 0xfff;
-
- switch (addr) {
- /* Local bus int source */
- case 0x00: {
- uint32_t pending = s->isr_jazz & s->imr_jazz;
- val = 0;
- irq = 0;
- while (pending) {
- if (pending & 1) {
- val = (irq + 1) << 2;
- break;
- }
- irq++;
- pending >>= 1;
- }
- break;
- }
- /* Local bus int enable mask */
- case 0x02:
- val = s->imr_jazz;
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "rc4030/jazzio: invalid read at 0x%x", (int)addr);
- val = 0;
- break;
- }
-
- trace_jazzio_read(addr, val);
-
- return val;
-}
-
-static void jazzio_write(void *opaque, hwaddr addr, uint64_t data,
- unsigned int size)
-{
- rc4030State *s = opaque;
- uint32_t val = data;
- addr &= 0xfff;
-
- trace_jazzio_write(addr, val);
-
- switch (addr) {
- /* Local bus int enable mask */
- case 0x02:
- s->imr_jazz = val;
- update_jazz_irq(s);
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "rc4030/jazzio: invalid write of 0x%02x at 0x%x",
- val, (int)addr);
- break;
- }
-}
-
-static const MemoryRegionOps jazzio_ops = {
- .read = jazzio_read,
- .write = jazzio_write,
- .impl.min_access_size = 2,
- .impl.max_access_size = 2,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void rc4030_reset(DeviceState *dev)
-{
- rc4030State *s = RC4030(dev);
- int i;
-
- s->config = 0x410; /* some boards seem to accept 0x104 too */
- s->revision = 1;
- s->invalid_address_register = 0;
-
- memset(s->dma_regs, 0, sizeof(s->dma_regs));
- rc4030_dma_tt_update(s, 0, 0);
-
- s->remote_failed_address = s->memory_failed_address = 0;
- s->cache_maint = 0;
- s->cache_ptag = s->cache_ltag = 0;
- s->cache_bmask = 0;
-
- s->memory_refresh_rate = 0x18186;
- s->nvram_protect = 7;
- for (i = 0; i < 15; i++)
- s->rem_speed[i] = 7;
- s->imr_jazz = 0x10; /* XXX: required by firmware, but why? */
- s->isr_jazz = 0;
-
- s->itr = 0;
-
- qemu_irq_lower(s->timer_irq);
- qemu_irq_lower(s->jazz_bus_irq);
-}
-
-static int rc4030_load(QEMUFile *f, void *opaque, int version_id)
-{
- rc4030State* s = opaque;
- int i, j;
-
- if (version_id != 2)
- return -EINVAL;
-
- s->config = qemu_get_be32(f);
- s->invalid_address_register = qemu_get_be32(f);
- for (i = 0; i < 8; i++)
- for (j = 0; j < 4; j++)
- s->dma_regs[i][j] = qemu_get_be32(f);
- s->dma_tl_base = qemu_get_be32(f);
- s->dma_tl_limit = qemu_get_be32(f);
- s->cache_maint = qemu_get_be32(f);
- s->remote_failed_address = qemu_get_be32(f);
- s->memory_failed_address = qemu_get_be32(f);
- s->cache_ptag = qemu_get_be32(f);
- s->cache_ltag = qemu_get_be32(f);
- s->cache_bmask = qemu_get_be32(f);
- s->memory_refresh_rate = qemu_get_be32(f);
- s->nvram_protect = qemu_get_be32(f);
- for (i = 0; i < 15; i++)
- s->rem_speed[i] = qemu_get_be32(f);
- s->imr_jazz = qemu_get_be32(f);
- s->isr_jazz = qemu_get_be32(f);
- s->itr = qemu_get_be32(f);
-
- set_next_tick(s);
- update_jazz_irq(s);
-
- return 0;
-}
-
-static void rc4030_save(QEMUFile *f, void *opaque)
-{
- rc4030State* s = opaque;
- int i, j;
-
- qemu_put_be32(f, s->config);
- qemu_put_be32(f, s->invalid_address_register);
- for (i = 0; i < 8; i++)
- for (j = 0; j < 4; j++)
- qemu_put_be32(f, s->dma_regs[i][j]);
- qemu_put_be32(f, s->dma_tl_base);
- qemu_put_be32(f, s->dma_tl_limit);
- qemu_put_be32(f, s->cache_maint);
- qemu_put_be32(f, s->remote_failed_address);
- qemu_put_be32(f, s->memory_failed_address);
- qemu_put_be32(f, s->cache_ptag);
- qemu_put_be32(f, s->cache_ltag);
- qemu_put_be32(f, s->cache_bmask);
- qemu_put_be32(f, s->memory_refresh_rate);
- qemu_put_be32(f, s->nvram_protect);
- for (i = 0; i < 15; i++)
- qemu_put_be32(f, s->rem_speed[i]);
- qemu_put_be32(f, s->imr_jazz);
- qemu_put_be32(f, s->isr_jazz);
- qemu_put_be32(f, s->itr);
-}
-
-static void rc4030_do_dma(void *opaque, int n, uint8_t *buf, int len, int is_write)
-{
- rc4030State *s = opaque;
- hwaddr dma_addr;
- int dev_to_mem;
-
- s->dma_regs[n][DMA_REG_ENABLE] &= ~(DMA_FLAG_TC_INTR | DMA_FLAG_MEM_INTR | DMA_FLAG_ADDR_INTR);
-
- /* Check DMA channel consistency */
- dev_to_mem = (s->dma_regs[n][DMA_REG_ENABLE] & DMA_FLAG_MEM_TO_DEV) ? 0 : 1;
- if (!(s->dma_regs[n][DMA_REG_ENABLE] & DMA_FLAG_ENABLE) ||
- (is_write != dev_to_mem)) {
- s->dma_regs[n][DMA_REG_ENABLE] |= DMA_FLAG_MEM_INTR;
- s->nmi_interrupt |= 1 << n;
- return;
- }
-
- /* Get start address and len */
- if (len > s->dma_regs[n][DMA_REG_COUNT])
- len = s->dma_regs[n][DMA_REG_COUNT];
- dma_addr = s->dma_regs[n][DMA_REG_ADDRESS];
-
- /* Read/write data at right place */
- address_space_rw(&s->dma_as, dma_addr, MEMTXATTRS_UNSPECIFIED,
- buf, len, is_write);
-
- s->dma_regs[n][DMA_REG_ENABLE] |= DMA_FLAG_TC_INTR;
- s->dma_regs[n][DMA_REG_COUNT] -= len;
-}
-
-struct rc4030DMAState {
- void *opaque;
- int n;
-};
-
-void rc4030_dma_read(void *dma, uint8_t *buf, int len)
-{
- rc4030_dma s = dma;
- rc4030_do_dma(s->opaque, s->n, buf, len, 0);
-}
-
-void rc4030_dma_write(void *dma, uint8_t *buf, int len)
-{
- rc4030_dma s = dma;
- rc4030_do_dma(s->opaque, s->n, buf, len, 1);
-}
-
-static rc4030_dma *rc4030_allocate_dmas(void *opaque, int n)
-{
- rc4030_dma *s;
- struct rc4030DMAState *p;
- int i;
-
- s = (rc4030_dma *)g_malloc0(sizeof(rc4030_dma) * n);
- p = (struct rc4030DMAState *)g_malloc0(sizeof(struct rc4030DMAState) * n);
- for (i = 0; i < n; i++) {
- p->opaque = opaque;
- p->n = i;
- s[i] = p;
- p++;
- }
- return s;
-}
-
-static void rc4030_initfn(Object *obj)
-{
- DeviceState *dev = DEVICE(obj);
- rc4030State *s = RC4030(obj);
- SysBusDevice *sysbus = SYS_BUS_DEVICE(obj);
-
- qdev_init_gpio_in(dev, rc4030_irq_jazz_request, 16);
-
- sysbus_init_irq(sysbus, &s->timer_irq);
- sysbus_init_irq(sysbus, &s->jazz_bus_irq);
-
- register_savevm(NULL, "rc4030", 0, 2, rc4030_save, rc4030_load, s);
-
- sysbus_init_mmio(sysbus, &s->iomem_chipset);
- sysbus_init_mmio(sysbus, &s->iomem_jazzio);
-}
-
-static void rc4030_realize(DeviceState *dev, Error **errp)
-{
- rc4030State *s = RC4030(dev);
- Object *o = OBJECT(dev);
- int i;
-
- s->periodic_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
- rc4030_periodic_timer, s);
-
- memory_region_init_io(&s->iomem_chipset, NULL, &rc4030_ops, s,
- "rc4030.chipset", 0x300);
- memory_region_init_io(&s->iomem_jazzio, NULL, &jazzio_ops, s,
- "rc4030.jazzio", 0x00001000);
-
- memory_region_init_rom_device(&s->dma_tt, o,
- &rc4030_dma_tt_ops, s, "dma-table",
- MAX_TL_ENTRIES * sizeof(dma_pagetable_entry),
- NULL);
- memory_region_init(&s->dma_tt_alias, o, "dma-table-alias", 0);
- memory_region_init(&s->dma_mr, o, "dma", INT32_MAX);
- for (i = 0; i < MAX_TL_ENTRIES; ++i) {
- memory_region_init_alias(&s->dma_mrs[i], o, "dma-alias",
- get_system_memory(), 0, DMA_PAGESIZE);
- memory_region_set_enabled(&s->dma_mrs[i], false);
- memory_region_add_subregion(&s->dma_mr, i * DMA_PAGESIZE,
- &s->dma_mrs[i]);
- }
- address_space_init(&s->dma_as, &s->dma_mr, "rc4030-dma");
-}
-
-static void rc4030_unrealize(DeviceState *dev, Error **errp)
-{
- rc4030State *s = RC4030(dev);
- int i;
-
- timer_free(s->periodic_timer);
-
- address_space_destroy(&s->dma_as);
- object_unparent(OBJECT(&s->dma_tt));
- object_unparent(OBJECT(&s->dma_tt_alias));
- object_unparent(OBJECT(&s->dma_mr));
- for (i = 0; i < MAX_TL_ENTRIES; ++i) {
- memory_region_del_subregion(&s->dma_mr, &s->dma_mrs[i]);
- object_unparent(OBJECT(&s->dma_mrs[i]));
- }
-}
-
-static void rc4030_class_init(ObjectClass *klass, void *class_data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = rc4030_realize;
- dc->unrealize = rc4030_unrealize;
- dc->reset = rc4030_reset;
-}
-
-static const TypeInfo rc4030_info = {
- .name = TYPE_RC4030,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(rc4030State),
- .instance_init = rc4030_initfn,
- .class_init = rc4030_class_init,
-};
-
-static void rc4030_register_types(void)
-{
- type_register_static(&rc4030_info);
-}
-
-type_init(rc4030_register_types)
-
-DeviceState *rc4030_init(rc4030_dma **dmas, MemoryRegion **dma_mr)
-{
- DeviceState *dev;
-
- dev = qdev_create(NULL, TYPE_RC4030);
- qdev_init_nofail(dev);
-
- *dmas = rc4030_allocate_dmas(dev, 4);
- *dma_mr = &RC4030(dev)->dma_mr;
- return dev;
-}
diff --git a/qemu/hw/dma/soc_dma.c b/qemu/hw/dma/soc_dma.c
deleted file mode 100644
index 9bb499bf9..000000000
--- a/qemu/hw/dma/soc_dma.c
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- * On-chip DMA controller framework.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "qemu/timer.h"
-#include "hw/arm/soc_dma.h"
-
-static void transfer_mem2mem(struct soc_dma_ch_s *ch)
-{
- memcpy(ch->paddr[0], ch->paddr[1], ch->bytes);
- ch->paddr[0] += ch->bytes;
- ch->paddr[1] += ch->bytes;
-}
-
-static void transfer_mem2fifo(struct soc_dma_ch_s *ch)
-{
- ch->io_fn[1](ch->io_opaque[1], ch->paddr[0], ch->bytes);
- ch->paddr[0] += ch->bytes;
-}
-
-static void transfer_fifo2mem(struct soc_dma_ch_s *ch)
-{
- ch->io_fn[0](ch->io_opaque[0], ch->paddr[1], ch->bytes);
- ch->paddr[1] += ch->bytes;
-}
-
-/* This is further optimisable but isn't very important because often
- * DMA peripherals forbid this kind of transfers and even when they don't,
- * oprating systems may not need to use them. */
-static void *fifo_buf;
-static int fifo_size;
-static void transfer_fifo2fifo(struct soc_dma_ch_s *ch)
-{
- if (ch->bytes > fifo_size)
- fifo_buf = g_realloc(fifo_buf, fifo_size = ch->bytes);
-
- /* Implement as transfer_fifo2linear + transfer_linear2fifo. */
- ch->io_fn[0](ch->io_opaque[0], fifo_buf, ch->bytes);
- ch->io_fn[1](ch->io_opaque[1], fifo_buf, ch->bytes);
-}
-
-struct dma_s {
- struct soc_dma_s soc;
- int chnum;
- uint64_t ch_enable_mask;
- int64_t channel_freq;
- int enabled_count;
-
- struct memmap_entry_s {
- enum soc_dma_port_type type;
- hwaddr addr;
- union {
- struct {
- void *opaque;
- soc_dma_io_t fn;
- int out;
- } fifo;
- struct {
- void *base;
- size_t size;
- } mem;
- } u;
- } *memmap;
- int memmap_size;
-
- struct soc_dma_ch_s ch[0];
-};
-
-static void soc_dma_ch_schedule(struct soc_dma_ch_s *ch, int delay_bytes)
-{
- int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- struct dma_s *dma = (struct dma_s *) ch->dma;
-
- timer_mod(ch->timer, now + delay_bytes / dma->channel_freq);
-}
-
-static void soc_dma_ch_run(void *opaque)
-{
- struct soc_dma_ch_s *ch = (struct soc_dma_ch_s *) opaque;
-
- ch->running = 1;
- ch->dma->setup_fn(ch);
- ch->transfer_fn(ch);
- ch->running = 0;
-
- if (ch->enable)
- soc_dma_ch_schedule(ch, ch->bytes);
- ch->bytes = 0;
-}
-
-static inline struct memmap_entry_s *soc_dma_lookup(struct dma_s *dma,
- hwaddr addr)
-{
- struct memmap_entry_s *lo;
- int hi;
-
- lo = dma->memmap;
- hi = dma->memmap_size;
-
- while (hi > 1) {
- hi /= 2;
- if (lo[hi].addr <= addr)
- lo += hi;
- }
-
- return lo;
-}
-
-static inline enum soc_dma_port_type soc_dma_ch_update_type(
- struct soc_dma_ch_s *ch, int port)
-{
- struct dma_s *dma = (struct dma_s *) ch->dma;
- struct memmap_entry_s *entry = soc_dma_lookup(dma, ch->vaddr[port]);
-
- if (entry->type == soc_dma_port_fifo) {
- while (entry < dma->memmap + dma->memmap_size &&
- entry->u.fifo.out != port)
- entry ++;
- if (entry->addr != ch->vaddr[port] || entry->u.fifo.out != port)
- return soc_dma_port_other;
-
- if (ch->type[port] != soc_dma_access_const)
- return soc_dma_port_other;
-
- ch->io_fn[port] = entry->u.fifo.fn;
- ch->io_opaque[port] = entry->u.fifo.opaque;
- return soc_dma_port_fifo;
- } else if (entry->type == soc_dma_port_mem) {
- if (entry->addr > ch->vaddr[port] ||
- entry->addr + entry->u.mem.size <= ch->vaddr[port])
- return soc_dma_port_other;
-
- /* TODO: support constant memory address for source port as used for
- * drawing solid rectangles by PalmOS(R). */
- if (ch->type[port] != soc_dma_access_const)
- return soc_dma_port_other;
-
- ch->paddr[port] = (uint8_t *) entry->u.mem.base +
- (ch->vaddr[port] - entry->addr);
- /* TODO: save bytes left to the end of the mapping somewhere so we
- * can check we're not reading beyond it. */
- return soc_dma_port_mem;
- } else
- return soc_dma_port_other;
-}
-
-void soc_dma_ch_update(struct soc_dma_ch_s *ch)
-{
- enum soc_dma_port_type src, dst;
-
- src = soc_dma_ch_update_type(ch, 0);
- if (src == soc_dma_port_other) {
- ch->update = 0;
- ch->transfer_fn = ch->dma->transfer_fn;
- return;
- }
- dst = soc_dma_ch_update_type(ch, 1);
-
- /* TODO: use src and dst as array indices. */
- if (src == soc_dma_port_mem && dst == soc_dma_port_mem)
- ch->transfer_fn = transfer_mem2mem;
- else if (src == soc_dma_port_mem && dst == soc_dma_port_fifo)
- ch->transfer_fn = transfer_mem2fifo;
- else if (src == soc_dma_port_fifo && dst == soc_dma_port_mem)
- ch->transfer_fn = transfer_fifo2mem;
- else if (src == soc_dma_port_fifo && dst == soc_dma_port_fifo)
- ch->transfer_fn = transfer_fifo2fifo;
- else
- ch->transfer_fn = ch->dma->transfer_fn;
-
- ch->update = (dst != soc_dma_port_other);
-}
-
-static void soc_dma_ch_freq_update(struct dma_s *s)
-{
- if (s->enabled_count)
- /* We completely ignore channel priorities and stuff */
- s->channel_freq = s->soc.freq / s->enabled_count;
- else {
- /* TODO: Signal that we want to disable the functional clock and let
- * the platform code decide what to do with it, i.e. check that
- * auto-idle is enabled in the clock controller and if we are stopping
- * the clock, do the same with any parent clocks that had only one
- * user keeping them on and auto-idle enabled. */
- }
-}
-
-void soc_dma_set_request(struct soc_dma_ch_s *ch, int level)
-{
- struct dma_s *dma = (struct dma_s *) ch->dma;
-
- dma->enabled_count += level - ch->enable;
-
- if (level)
- dma->ch_enable_mask |= 1 << ch->num;
- else
- dma->ch_enable_mask &= ~(1 << ch->num);
-
- if (level != ch->enable) {
- soc_dma_ch_freq_update(dma);
- ch->enable = level;
-
- if (!ch->enable)
- timer_del(ch->timer);
- else if (!ch->running)
- soc_dma_ch_run(ch);
- else
- soc_dma_ch_schedule(ch, 1);
- }
-}
-
-void soc_dma_reset(struct soc_dma_s *soc)
-{
- struct dma_s *s = (struct dma_s *) soc;
-
- s->soc.drqbmp = 0;
- s->ch_enable_mask = 0;
- s->enabled_count = 0;
- soc_dma_ch_freq_update(s);
-}
-
-/* TODO: take a functional-clock argument */
-struct soc_dma_s *soc_dma_init(int n)
-{
- int i;
- struct dma_s *s = g_malloc0(sizeof(*s) + n * sizeof(*s->ch));
-
- s->chnum = n;
- s->soc.ch = s->ch;
- for (i = 0; i < n; i ++) {
- s->ch[i].dma = &s->soc;
- s->ch[i].num = i;
- s->ch[i].timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, soc_dma_ch_run, &s->ch[i]);
- }
-
- soc_dma_reset(&s->soc);
- fifo_size = 0;
-
- return &s->soc;
-}
-
-void soc_dma_port_add_fifo(struct soc_dma_s *soc, hwaddr virt_base,
- soc_dma_io_t fn, void *opaque, int out)
-{
- struct memmap_entry_s *entry;
- struct dma_s *dma = (struct dma_s *) soc;
-
- dma->memmap = g_realloc(dma->memmap, sizeof(*entry) *
- (dma->memmap_size + 1));
- entry = soc_dma_lookup(dma, virt_base);
-
- if (dma->memmap_size) {
- if (entry->type == soc_dma_port_mem) {
- if (entry->addr <= virt_base &&
- entry->addr + entry->u.mem.size > virt_base) {
- fprintf(stderr, "%s: FIFO at %"PRIx64
- " collides with RAM region at %"PRIx64
- "-%"PRIx64 "\n", __func__,
- virt_base, entry->addr,
- (entry->addr + entry->u.mem.size));
- exit(-1);
- }
-
- if (entry->addr <= virt_base)
- entry ++;
- } else
- while (entry < dma->memmap + dma->memmap_size &&
- entry->addr <= virt_base) {
- if (entry->addr == virt_base && entry->u.fifo.out == out) {
- fprintf(stderr, "%s: FIFO at %"PRIx64
- " collides FIFO at %"PRIx64 "\n",
- __func__, virt_base, entry->addr);
- exit(-1);
- }
-
- entry ++;
- }
-
- memmove(entry + 1, entry,
- (uint8_t *) (dma->memmap + dma->memmap_size ++) -
- (uint8_t *) entry);
- } else
- dma->memmap_size ++;
-
- entry->addr = virt_base;
- entry->type = soc_dma_port_fifo;
- entry->u.fifo.fn = fn;
- entry->u.fifo.opaque = opaque;
- entry->u.fifo.out = out;
-}
-
-void soc_dma_port_add_mem(struct soc_dma_s *soc, uint8_t *phys_base,
- hwaddr virt_base, size_t size)
-{
- struct memmap_entry_s *entry;
- struct dma_s *dma = (struct dma_s *) soc;
-
- dma->memmap = g_realloc(dma->memmap, sizeof(*entry) *
- (dma->memmap_size + 1));
- entry = soc_dma_lookup(dma, virt_base);
-
- if (dma->memmap_size) {
- if (entry->type == soc_dma_port_mem) {
- if ((entry->addr >= virt_base && entry->addr < virt_base + size) ||
- (entry->addr <= virt_base &&
- entry->addr + entry->u.mem.size > virt_base)) {
- fprintf(stderr, "%s: RAM at %"PRIx64 "-%"PRIx64
- " collides with RAM region at %"PRIx64
- "-%"PRIx64 "\n", __func__,
- virt_base, virt_base + size,
- entry->addr, entry->addr + entry->u.mem.size);
- exit(-1);
- }
-
- if (entry->addr <= virt_base)
- entry ++;
- } else {
- if (entry->addr >= virt_base &&
- entry->addr < virt_base + size) {
- fprintf(stderr, "%s: RAM at %"PRIx64 "-%"PRIx64
- " collides with FIFO at %"PRIx64
- "\n", __func__,
- virt_base, virt_base + size,
- entry->addr);
- exit(-1);
- }
-
- while (entry < dma->memmap + dma->memmap_size &&
- entry->addr <= virt_base)
- entry ++;
- }
-
- memmove(entry + 1, entry,
- (uint8_t *) (dma->memmap + dma->memmap_size ++) -
- (uint8_t *) entry);
- } else
- dma->memmap_size ++;
-
- entry->addr = virt_base;
- entry->type = soc_dma_port_mem;
- entry->u.mem.base = phys_base;
- entry->u.mem.size = size;
-}
-
-/* TODO: port removal for ports like PCMCIA memory */
diff --git a/qemu/hw/dma/sparc32_dma.c b/qemu/hw/dma/sparc32_dma.c
deleted file mode 100644
index 9d545e412..000000000
--- a/qemu/hw/dma/sparc32_dma.c
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- * QEMU Sparc32 DMA controller emulation
- *
- * Copyright (c) 2006 Fabrice Bellard
- *
- * Modifications:
- * 2010-Feb-14 Artyom Tarasenko : reworked irq generation
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/sparc/sparc32_dma.h"
-#include "hw/sparc/sun4m.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-
-/*
- * This is the DMA controller part of chip STP2000 (Master I/O), also
- * produced as NCR89C100. See
- * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt
- * and
- * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/DMA2.txt
- */
-
-#define DMA_REGS 4
-#define DMA_SIZE (4 * sizeof(uint32_t))
-/* We need the mask, because one instance of the device is not page
- aligned (ledma, start address 0x0010) */
-#define DMA_MASK (DMA_SIZE - 1)
-/* OBP says 0x20 bytes for ledma, the extras are aliased to espdma */
-#define DMA_ETH_SIZE (8 * sizeof(uint32_t))
-#define DMA_MAX_REG_OFFSET (2 * DMA_SIZE - 1)
-
-#define DMA_VER 0xa0000000
-#define DMA_INTR 1
-#define DMA_INTREN 0x10
-#define DMA_WRITE_MEM 0x100
-#define DMA_EN 0x200
-#define DMA_LOADED 0x04000000
-#define DMA_DRAIN_FIFO 0x40
-#define DMA_RESET 0x80
-
-/* XXX SCSI and ethernet should have different read-only bit masks */
-#define DMA_CSR_RO_MASK 0xfe000007
-
-#define TYPE_SPARC32_DMA "sparc32_dma"
-#define SPARC32_DMA(obj) OBJECT_CHECK(DMAState, (obj), TYPE_SPARC32_DMA)
-
-typedef struct DMAState DMAState;
-
-struct DMAState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- uint32_t dmaregs[DMA_REGS];
- qemu_irq irq;
- void *iommu;
- qemu_irq gpio[2];
- uint32_t is_ledma;
-};
-
-enum {
- GPIO_RESET = 0,
- GPIO_DMA,
-};
-
-/* Note: on sparc, the lance 16 bit bus is swapped */
-void ledma_memory_read(void *opaque, hwaddr addr,
- uint8_t *buf, int len, int do_bswap)
-{
- DMAState *s = opaque;
- int i;
-
- addr |= s->dmaregs[3];
- trace_ledma_memory_read(addr);
- if (do_bswap) {
- sparc_iommu_memory_read(s->iommu, addr, buf, len);
- } else {
- addr &= ~1;
- len &= ~1;
- sparc_iommu_memory_read(s->iommu, addr, buf, len);
- for(i = 0; i < len; i += 2) {
- bswap16s((uint16_t *)(buf + i));
- }
- }
-}
-
-void ledma_memory_write(void *opaque, hwaddr addr,
- uint8_t *buf, int len, int do_bswap)
-{
- DMAState *s = opaque;
- int l, i;
- uint16_t tmp_buf[32];
-
- addr |= s->dmaregs[3];
- trace_ledma_memory_write(addr);
- if (do_bswap) {
- sparc_iommu_memory_write(s->iommu, addr, buf, len);
- } else {
- addr &= ~1;
- len &= ~1;
- while (len > 0) {
- l = len;
- if (l > sizeof(tmp_buf))
- l = sizeof(tmp_buf);
- for(i = 0; i < l; i += 2) {
- tmp_buf[i >> 1] = bswap16(*(uint16_t *)(buf + i));
- }
- sparc_iommu_memory_write(s->iommu, addr, (uint8_t *)tmp_buf, l);
- len -= l;
- buf += l;
- addr += l;
- }
- }
-}
-
-static void dma_set_irq(void *opaque, int irq, int level)
-{
- DMAState *s = opaque;
- if (level) {
- s->dmaregs[0] |= DMA_INTR;
- if (s->dmaregs[0] & DMA_INTREN) {
- trace_sparc32_dma_set_irq_raise();
- qemu_irq_raise(s->irq);
- }
- } else {
- if (s->dmaregs[0] & DMA_INTR) {
- s->dmaregs[0] &= ~DMA_INTR;
- if (s->dmaregs[0] & DMA_INTREN) {
- trace_sparc32_dma_set_irq_lower();
- qemu_irq_lower(s->irq);
- }
- }
- }
-}
-
-void espdma_memory_read(void *opaque, uint8_t *buf, int len)
-{
- DMAState *s = opaque;
-
- trace_espdma_memory_read(s->dmaregs[1]);
- sparc_iommu_memory_read(s->iommu, s->dmaregs[1], buf, len);
- s->dmaregs[1] += len;
-}
-
-void espdma_memory_write(void *opaque, uint8_t *buf, int len)
-{
- DMAState *s = opaque;
-
- trace_espdma_memory_write(s->dmaregs[1]);
- sparc_iommu_memory_write(s->iommu, s->dmaregs[1], buf, len);
- s->dmaregs[1] += len;
-}
-
-static uint64_t dma_mem_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- DMAState *s = opaque;
- uint32_t saddr;
-
- if (s->is_ledma && (addr > DMA_MAX_REG_OFFSET)) {
- /* aliased to espdma, but we can't get there from here */
- /* buggy driver if using undocumented behavior, just return 0 */
- trace_sparc32_dma_mem_readl(addr, 0);
- return 0;
- }
- saddr = (addr & DMA_MASK) >> 2;
- trace_sparc32_dma_mem_readl(addr, s->dmaregs[saddr]);
- return s->dmaregs[saddr];
-}
-
-static void dma_mem_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- DMAState *s = opaque;
- uint32_t saddr;
-
- if (s->is_ledma && (addr > DMA_MAX_REG_OFFSET)) {
- /* aliased to espdma, but we can't get there from here */
- trace_sparc32_dma_mem_writel(addr, 0, val);
- return;
- }
- saddr = (addr & DMA_MASK) >> 2;
- trace_sparc32_dma_mem_writel(addr, s->dmaregs[saddr], val);
- switch (saddr) {
- case 0:
- if (val & DMA_INTREN) {
- if (s->dmaregs[0] & DMA_INTR) {
- trace_sparc32_dma_set_irq_raise();
- qemu_irq_raise(s->irq);
- }
- } else {
- if (s->dmaregs[0] & (DMA_INTR | DMA_INTREN)) {
- trace_sparc32_dma_set_irq_lower();
- qemu_irq_lower(s->irq);
- }
- }
- if (val & DMA_RESET) {
- qemu_irq_raise(s->gpio[GPIO_RESET]);
- qemu_irq_lower(s->gpio[GPIO_RESET]);
- } else if (val & DMA_DRAIN_FIFO) {
- val &= ~DMA_DRAIN_FIFO;
- } else if (val == 0)
- val = DMA_DRAIN_FIFO;
-
- if (val & DMA_EN && !(s->dmaregs[0] & DMA_EN)) {
- trace_sparc32_dma_enable_raise();
- qemu_irq_raise(s->gpio[GPIO_DMA]);
- } else if (!(val & DMA_EN) && !!(s->dmaregs[0] & DMA_EN)) {
- trace_sparc32_dma_enable_lower();
- qemu_irq_lower(s->gpio[GPIO_DMA]);
- }
-
- val &= ~DMA_CSR_RO_MASK;
- val |= DMA_VER;
- s->dmaregs[0] = (s->dmaregs[0] & DMA_CSR_RO_MASK) | val;
- break;
- case 1:
- s->dmaregs[0] |= DMA_LOADED;
- /* fall through */
- default:
- s->dmaregs[saddr] = val;
- break;
- }
-}
-
-static const MemoryRegionOps dma_mem_ops = {
- .read = dma_mem_read,
- .write = dma_mem_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static void dma_reset(DeviceState *d)
-{
- DMAState *s = SPARC32_DMA(d);
-
- memset(s->dmaregs, 0, DMA_SIZE);
- s->dmaregs[0] = DMA_VER;
-}
-
-static const VMStateDescription vmstate_dma = {
- .name ="sparc32_dma",
- .version_id = 2,
- .minimum_version_id = 2,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(dmaregs, DMAState, DMA_REGS),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static int sparc32_dma_init1(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- DMAState *s = SPARC32_DMA(dev);
- int reg_size;
-
- sysbus_init_irq(sbd, &s->irq);
-
- reg_size = s->is_ledma ? DMA_ETH_SIZE : DMA_SIZE;
- memory_region_init_io(&s->iomem, OBJECT(s), &dma_mem_ops, s,
- "dma", reg_size);
- sysbus_init_mmio(sbd, &s->iomem);
-
- qdev_init_gpio_in(dev, dma_set_irq, 1);
- qdev_init_gpio_out(dev, s->gpio, 2);
-
- return 0;
-}
-
-static Property sparc32_dma_properties[] = {
- DEFINE_PROP_PTR("iommu_opaque", DMAState, iommu),
- DEFINE_PROP_UINT32("is_ledma", DMAState, is_ledma, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void sparc32_dma_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = sparc32_dma_init1;
- dc->reset = dma_reset;
- dc->vmsd = &vmstate_dma;
- dc->props = sparc32_dma_properties;
- /* Reason: pointer property "iommu_opaque" */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo sparc32_dma_info = {
- .name = TYPE_SPARC32_DMA,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(DMAState),
- .class_init = sparc32_dma_class_init,
-};
-
-static void sparc32_dma_register_types(void)
-{
- type_register_static(&sparc32_dma_info);
-}
-
-type_init(sparc32_dma_register_types)
diff --git a/qemu/hw/dma/sun4m_iommu.c b/qemu/hw/dma/sun4m_iommu.c
deleted file mode 100644
index b3cbc54c2..000000000
--- a/qemu/hw/dma/sun4m_iommu.c
+++ /dev/null
@@ -1,393 +0,0 @@
-/*
- * QEMU Sun4m iommu emulation
- *
- * Copyright (c) 2003-2005 Fabrice Bellard
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sparc/sun4m.h"
-#include "hw/sysbus.h"
-#include "exec/address-spaces.h"
-#include "trace.h"
-
-/*
- * I/O MMU used by Sun4m systems
- *
- * Chipset docs:
- * "Sun-4M System Architecture (revision 2.0) by Chuck Narad", 950-1373-01,
- * http://mediacast.sun.com/users/Barton808/media/Sun4M_SystemArchitecture_edited2.pdf
- */
-
-#define IOMMU_NREGS (4*4096/4)
-#define IOMMU_CTRL (0x0000 >> 2)
-#define IOMMU_CTRL_IMPL 0xf0000000 /* Implementation */
-#define IOMMU_CTRL_VERS 0x0f000000 /* Version */
-#define IOMMU_CTRL_RNGE 0x0000001c /* Mapping RANGE */
-#define IOMMU_RNGE_16MB 0x00000000 /* 0xff000000 -> 0xffffffff */
-#define IOMMU_RNGE_32MB 0x00000004 /* 0xfe000000 -> 0xffffffff */
-#define IOMMU_RNGE_64MB 0x00000008 /* 0xfc000000 -> 0xffffffff */
-#define IOMMU_RNGE_128MB 0x0000000c /* 0xf8000000 -> 0xffffffff */
-#define IOMMU_RNGE_256MB 0x00000010 /* 0xf0000000 -> 0xffffffff */
-#define IOMMU_RNGE_512MB 0x00000014 /* 0xe0000000 -> 0xffffffff */
-#define IOMMU_RNGE_1GB 0x00000018 /* 0xc0000000 -> 0xffffffff */
-#define IOMMU_RNGE_2GB 0x0000001c /* 0x80000000 -> 0xffffffff */
-#define IOMMU_CTRL_ENAB 0x00000001 /* IOMMU Enable */
-#define IOMMU_CTRL_MASK 0x0000001d
-
-#define IOMMU_BASE (0x0004 >> 2)
-#define IOMMU_BASE_MASK 0x07fffc00
-
-#define IOMMU_TLBFLUSH (0x0014 >> 2)
-#define IOMMU_TLBFLUSH_MASK 0xffffffff
-
-#define IOMMU_PGFLUSH (0x0018 >> 2)
-#define IOMMU_PGFLUSH_MASK 0xffffffff
-
-#define IOMMU_AFSR (0x1000 >> 2)
-#define IOMMU_AFSR_ERR 0x80000000 /* LE, TO, or BE asserted */
-#define IOMMU_AFSR_LE 0x40000000 /* SBUS reports error after
- transaction */
-#define IOMMU_AFSR_TO 0x20000000 /* Write access took more than
- 12.8 us. */
-#define IOMMU_AFSR_BE 0x10000000 /* Write access received error
- acknowledge */
-#define IOMMU_AFSR_SIZE 0x0e000000 /* Size of transaction causing error */
-#define IOMMU_AFSR_S 0x01000000 /* Sparc was in supervisor mode */
-#define IOMMU_AFSR_RESV 0x00800000 /* Reserved, forced to 0x8 by
- hardware */
-#define IOMMU_AFSR_ME 0x00080000 /* Multiple errors occurred */
-#define IOMMU_AFSR_RD 0x00040000 /* A read operation was in progress */
-#define IOMMU_AFSR_FAV 0x00020000 /* IOMMU afar has valid contents */
-#define IOMMU_AFSR_MASK 0xff0fffff
-
-#define IOMMU_AFAR (0x1004 >> 2)
-
-#define IOMMU_AER (0x1008 >> 2) /* Arbiter Enable Register */
-#define IOMMU_AER_EN_P0_ARB 0x00000001 /* MBus master 0x8 (Always 1) */
-#define IOMMU_AER_EN_P1_ARB 0x00000002 /* MBus master 0x9 */
-#define IOMMU_AER_EN_P2_ARB 0x00000004 /* MBus master 0xa */
-#define IOMMU_AER_EN_P3_ARB 0x00000008 /* MBus master 0xb */
-#define IOMMU_AER_EN_0 0x00010000 /* SBus slot 0 */
-#define IOMMU_AER_EN_1 0x00020000 /* SBus slot 1 */
-#define IOMMU_AER_EN_2 0x00040000 /* SBus slot 2 */
-#define IOMMU_AER_EN_3 0x00080000 /* SBus slot 3 */
-#define IOMMU_AER_EN_F 0x00100000 /* SBus on-board */
-#define IOMMU_AER_SBW 0x80000000 /* S-to-M asynchronous writes */
-#define IOMMU_AER_MASK 0x801f000f
-
-#define IOMMU_SBCFG0 (0x1010 >> 2) /* SBUS configration per-slot */
-#define IOMMU_SBCFG1 (0x1014 >> 2) /* SBUS configration per-slot */
-#define IOMMU_SBCFG2 (0x1018 >> 2) /* SBUS configration per-slot */
-#define IOMMU_SBCFG3 (0x101c >> 2) /* SBUS configration per-slot */
-#define IOMMU_SBCFG_SAB30 0x00010000 /* Phys-address bit 30 when
- bypass enabled */
-#define IOMMU_SBCFG_BA16 0x00000004 /* Slave supports 16 byte bursts */
-#define IOMMU_SBCFG_BA8 0x00000002 /* Slave supports 8 byte bursts */
-#define IOMMU_SBCFG_BYPASS 0x00000001 /* Bypass IOMMU, treat all addresses
- produced by this device as pure
- physical. */
-#define IOMMU_SBCFG_MASK 0x00010003
-
-#define IOMMU_ARBEN (0x2000 >> 2) /* SBUS arbitration enable */
-#define IOMMU_ARBEN_MASK 0x001f0000
-#define IOMMU_MID 0x00000008
-
-#define IOMMU_MASK_ID (0x3018 >> 2) /* Mask ID */
-#define IOMMU_MASK_ID_MASK 0x00ffffff
-
-#define IOMMU_MSII_MASK 0x26000000 /* microSPARC II mask number */
-#define IOMMU_TS_MASK 0x23000000 /* turboSPARC mask number */
-
-/* The format of an iopte in the page tables */
-#define IOPTE_PAGE 0xffffff00 /* Physical page number (PA[35:12]) */
-#define IOPTE_CACHE 0x00000080 /* Cached (in vme IOCACHE or
- Viking/MXCC) */
-#define IOPTE_WRITE 0x00000004 /* Writable */
-#define IOPTE_VALID 0x00000002 /* IOPTE is valid */
-#define IOPTE_WAZ 0x00000001 /* Write as zeros */
-
-#define IOMMU_PAGE_SHIFT 12
-#define IOMMU_PAGE_SIZE (1 << IOMMU_PAGE_SHIFT)
-#define IOMMU_PAGE_MASK ~(IOMMU_PAGE_SIZE - 1)
-
-#define TYPE_SUN4M_IOMMU "iommu"
-#define SUN4M_IOMMU(obj) OBJECT_CHECK(IOMMUState, (obj), TYPE_SUN4M_IOMMU)
-
-typedef struct IOMMUState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- uint32_t regs[IOMMU_NREGS];
- hwaddr iostart;
- qemu_irq irq;
- uint32_t version;
-} IOMMUState;
-
-static uint64_t iommu_mem_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- IOMMUState *s = opaque;
- hwaddr saddr;
- uint32_t ret;
-
- saddr = addr >> 2;
- switch (saddr) {
- default:
- ret = s->regs[saddr];
- break;
- case IOMMU_AFAR:
- case IOMMU_AFSR:
- ret = s->regs[saddr];
- qemu_irq_lower(s->irq);
- break;
- }
- trace_sun4m_iommu_mem_readl(saddr, ret);
- return ret;
-}
-
-static void iommu_mem_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- IOMMUState *s = opaque;
- hwaddr saddr;
-
- saddr = addr >> 2;
- trace_sun4m_iommu_mem_writel(saddr, val);
- switch (saddr) {
- case IOMMU_CTRL:
- switch (val & IOMMU_CTRL_RNGE) {
- case IOMMU_RNGE_16MB:
- s->iostart = 0xffffffffff000000ULL;
- break;
- case IOMMU_RNGE_32MB:
- s->iostart = 0xfffffffffe000000ULL;
- break;
- case IOMMU_RNGE_64MB:
- s->iostart = 0xfffffffffc000000ULL;
- break;
- case IOMMU_RNGE_128MB:
- s->iostart = 0xfffffffff8000000ULL;
- break;
- case IOMMU_RNGE_256MB:
- s->iostart = 0xfffffffff0000000ULL;
- break;
- case IOMMU_RNGE_512MB:
- s->iostart = 0xffffffffe0000000ULL;
- break;
- case IOMMU_RNGE_1GB:
- s->iostart = 0xffffffffc0000000ULL;
- break;
- default:
- case IOMMU_RNGE_2GB:
- s->iostart = 0xffffffff80000000ULL;
- break;
- }
- trace_sun4m_iommu_mem_writel_ctrl(s->iostart);
- s->regs[saddr] = ((val & IOMMU_CTRL_MASK) | s->version);
- break;
- case IOMMU_BASE:
- s->regs[saddr] = val & IOMMU_BASE_MASK;
- break;
- case IOMMU_TLBFLUSH:
- trace_sun4m_iommu_mem_writel_tlbflush(val);
- s->regs[saddr] = val & IOMMU_TLBFLUSH_MASK;
- break;
- case IOMMU_PGFLUSH:
- trace_sun4m_iommu_mem_writel_pgflush(val);
- s->regs[saddr] = val & IOMMU_PGFLUSH_MASK;
- break;
- case IOMMU_AFAR:
- s->regs[saddr] = val;
- qemu_irq_lower(s->irq);
- break;
- case IOMMU_AER:
- s->regs[saddr] = (val & IOMMU_AER_MASK) | IOMMU_AER_EN_P0_ARB;
- break;
- case IOMMU_AFSR:
- s->regs[saddr] = (val & IOMMU_AFSR_MASK) | IOMMU_AFSR_RESV;
- qemu_irq_lower(s->irq);
- break;
- case IOMMU_SBCFG0:
- case IOMMU_SBCFG1:
- case IOMMU_SBCFG2:
- case IOMMU_SBCFG3:
- s->regs[saddr] = val & IOMMU_SBCFG_MASK;
- break;
- case IOMMU_ARBEN:
- // XXX implement SBus probing: fault when reading unmapped
- // addresses, fault cause and address stored to MMU/IOMMU
- s->regs[saddr] = (val & IOMMU_ARBEN_MASK) | IOMMU_MID;
- break;
- case IOMMU_MASK_ID:
- s->regs[saddr] |= val & IOMMU_MASK_ID_MASK;
- break;
- default:
- s->regs[saddr] = val;
- break;
- }
-}
-
-static const MemoryRegionOps iommu_mem_ops = {
- .read = iommu_mem_read,
- .write = iommu_mem_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static uint32_t iommu_page_get_flags(IOMMUState *s, hwaddr addr)
-{
- uint32_t ret;
- hwaddr iopte;
- hwaddr pa = addr;
-
- iopte = s->regs[IOMMU_BASE] << 4;
- addr &= ~s->iostart;
- iopte += (addr >> (IOMMU_PAGE_SHIFT - 2)) & ~3;
- ret = address_space_ldl_be(&address_space_memory, iopte,
- MEMTXATTRS_UNSPECIFIED, NULL);
- trace_sun4m_iommu_page_get_flags(pa, iopte, ret);
- return ret;
-}
-
-static hwaddr iommu_translate_pa(hwaddr addr,
- uint32_t pte)
-{
- hwaddr pa;
-
- pa = ((pte & IOPTE_PAGE) << 4) + (addr & ~IOMMU_PAGE_MASK);
- trace_sun4m_iommu_translate_pa(addr, pa, pte);
- return pa;
-}
-
-static void iommu_bad_addr(IOMMUState *s, hwaddr addr,
- int is_write)
-{
- trace_sun4m_iommu_bad_addr(addr);
- s->regs[IOMMU_AFSR] = IOMMU_AFSR_ERR | IOMMU_AFSR_LE | IOMMU_AFSR_RESV |
- IOMMU_AFSR_FAV;
- if (!is_write)
- s->regs[IOMMU_AFSR] |= IOMMU_AFSR_RD;
- s->regs[IOMMU_AFAR] = addr;
- qemu_irq_raise(s->irq);
-}
-
-void sparc_iommu_memory_rw(void *opaque, hwaddr addr,
- uint8_t *buf, int len, int is_write)
-{
- int l;
- uint32_t flags;
- hwaddr page, phys_addr;
-
- while (len > 0) {
- page = addr & IOMMU_PAGE_MASK;
- l = (page + IOMMU_PAGE_SIZE) - addr;
- if (l > len)
- l = len;
- flags = iommu_page_get_flags(opaque, page);
- if (!(flags & IOPTE_VALID)) {
- iommu_bad_addr(opaque, page, is_write);
- return;
- }
- phys_addr = iommu_translate_pa(addr, flags);
- if (is_write) {
- if (!(flags & IOPTE_WRITE)) {
- iommu_bad_addr(opaque, page, is_write);
- return;
- }
- cpu_physical_memory_write(phys_addr, buf, l);
- } else {
- cpu_physical_memory_read(phys_addr, buf, l);
- }
- len -= l;
- buf += l;
- addr += l;
- }
-}
-
-static const VMStateDescription vmstate_iommu = {
- .name ="iommu",
- .version_id = 2,
- .minimum_version_id = 2,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, IOMMUState, IOMMU_NREGS),
- VMSTATE_UINT64(iostart, IOMMUState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void iommu_reset(DeviceState *d)
-{
- IOMMUState *s = SUN4M_IOMMU(d);
-
- memset(s->regs, 0, IOMMU_NREGS * 4);
- s->iostart = 0;
- s->regs[IOMMU_CTRL] = s->version;
- s->regs[IOMMU_ARBEN] = IOMMU_MID;
- s->regs[IOMMU_AFSR] = IOMMU_AFSR_RESV;
- s->regs[IOMMU_AER] = IOMMU_AER_EN_P0_ARB | IOMMU_AER_EN_P1_ARB;
- s->regs[IOMMU_MASK_ID] = IOMMU_TS_MASK;
-}
-
-static int iommu_init1(SysBusDevice *dev)
-{
- IOMMUState *s = SUN4M_IOMMU(dev);
-
- sysbus_init_irq(dev, &s->irq);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &iommu_mem_ops, s, "iommu",
- IOMMU_NREGS * sizeof(uint32_t));
- sysbus_init_mmio(dev, &s->iomem);
-
- return 0;
-}
-
-static Property iommu_properties[] = {
- DEFINE_PROP_UINT32("version", IOMMUState, version, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void iommu_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = iommu_init1;
- dc->reset = iommu_reset;
- dc->vmsd = &vmstate_iommu;
- dc->props = iommu_properties;
-}
-
-static const TypeInfo iommu_info = {
- .name = TYPE_SUN4M_IOMMU,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(IOMMUState),
- .class_init = iommu_class_init,
-};
-
-static void iommu_register_types(void)
-{
- type_register_static(&iommu_info);
-}
-
-type_init(iommu_register_types)
diff --git a/qemu/hw/dma/xilinx_axidma.c b/qemu/hw/dma/xilinx_axidma.c
deleted file mode 100644
index a4753e55a..000000000
--- a/qemu/hw/dma/xilinx_axidma.c
+++ /dev/null
@@ -1,666 +0,0 @@
-/*
- * QEMU model of Xilinx AXI-DMA block.
- *
- * Copyright (c) 2011 Edgar E. Iglesias.
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "qapi/error.h"
-#include "qemu/timer.h"
-#include "hw/ptimer.h"
-#include "qemu/log.h"
-#include "qemu/main-loop.h"
-
-#include "hw/stream.h"
-
-#define D(x)
-
-#define TYPE_XILINX_AXI_DMA "xlnx.axi-dma"
-#define TYPE_XILINX_AXI_DMA_DATA_STREAM "xilinx-axi-dma-data-stream"
-#define TYPE_XILINX_AXI_DMA_CONTROL_STREAM "xilinx-axi-dma-control-stream"
-
-#define XILINX_AXI_DMA(obj) \
- OBJECT_CHECK(XilinxAXIDMA, (obj), TYPE_XILINX_AXI_DMA)
-
-#define XILINX_AXI_DMA_DATA_STREAM(obj) \
- OBJECT_CHECK(XilinxAXIDMAStreamSlave, (obj),\
- TYPE_XILINX_AXI_DMA_DATA_STREAM)
-
-#define XILINX_AXI_DMA_CONTROL_STREAM(obj) \
- OBJECT_CHECK(XilinxAXIDMAStreamSlave, (obj),\
- TYPE_XILINX_AXI_DMA_CONTROL_STREAM)
-
-#define R_DMACR (0x00 / 4)
-#define R_DMASR (0x04 / 4)
-#define R_CURDESC (0x08 / 4)
-#define R_TAILDESC (0x10 / 4)
-#define R_MAX (0x30 / 4)
-
-#define CONTROL_PAYLOAD_WORDS 5
-#define CONTROL_PAYLOAD_SIZE (CONTROL_PAYLOAD_WORDS * (sizeof(uint32_t)))
-
-typedef struct XilinxAXIDMA XilinxAXIDMA;
-typedef struct XilinxAXIDMAStreamSlave XilinxAXIDMAStreamSlave;
-
-enum {
- DMACR_RUNSTOP = 1,
- DMACR_TAILPTR_MODE = 2,
- DMACR_RESET = 4
-};
-
-enum {
- DMASR_HALTED = 1,
- DMASR_IDLE = 2,
- DMASR_IOC_IRQ = 1 << 12,
- DMASR_DLY_IRQ = 1 << 13,
-
- DMASR_IRQ_MASK = 7 << 12
-};
-
-struct SDesc {
- uint64_t nxtdesc;
- uint64_t buffer_address;
- uint64_t reserved;
- uint32_t control;
- uint32_t status;
- uint8_t app[CONTROL_PAYLOAD_SIZE];
-};
-
-enum {
- SDESC_CTRL_EOF = (1 << 26),
- SDESC_CTRL_SOF = (1 << 27),
-
- SDESC_CTRL_LEN_MASK = (1 << 23) - 1
-};
-
-enum {
- SDESC_STATUS_EOF = (1 << 26),
- SDESC_STATUS_SOF_BIT = 27,
- SDESC_STATUS_SOF = (1 << SDESC_STATUS_SOF_BIT),
- SDESC_STATUS_COMPLETE = (1 << 31)
-};
-
-struct Stream {
- QEMUBH *bh;
- ptimer_state *ptimer;
- qemu_irq irq;
-
- int nr;
-
- struct SDesc desc;
- int pos;
- unsigned int complete_cnt;
- uint32_t regs[R_MAX];
- uint8_t app[20];
-};
-
-struct XilinxAXIDMAStreamSlave {
- Object parent;
-
- struct XilinxAXIDMA *dma;
-};
-
-struct XilinxAXIDMA {
- SysBusDevice busdev;
- MemoryRegion iomem;
- uint32_t freqhz;
- StreamSlave *tx_data_dev;
- StreamSlave *tx_control_dev;
- XilinxAXIDMAStreamSlave rx_data_dev;
- XilinxAXIDMAStreamSlave rx_control_dev;
-
- struct Stream streams[2];
-
- StreamCanPushNotifyFn notify;
- void *notify_opaque;
-};
-
-/*
- * Helper calls to extract info from descriptors and other trivial
- * state from regs.
- */
-static inline int stream_desc_sof(struct SDesc *d)
-{
- return d->control & SDESC_CTRL_SOF;
-}
-
-static inline int stream_desc_eof(struct SDesc *d)
-{
- return d->control & SDESC_CTRL_EOF;
-}
-
-static inline int stream_resetting(struct Stream *s)
-{
- return !!(s->regs[R_DMACR] & DMACR_RESET);
-}
-
-static inline int stream_running(struct Stream *s)
-{
- return s->regs[R_DMACR] & DMACR_RUNSTOP;
-}
-
-static inline int stream_idle(struct Stream *s)
-{
- return !!(s->regs[R_DMASR] & DMASR_IDLE);
-}
-
-static void stream_reset(struct Stream *s)
-{
- s->regs[R_DMASR] = DMASR_HALTED; /* starts up halted. */
- s->regs[R_DMACR] = 1 << 16; /* Starts with one in compl threshold. */
-}
-
-/* Map an offset addr into a channel index. */
-static inline int streamid_from_addr(hwaddr addr)
-{
- int sid;
-
- sid = addr / (0x30);
- sid &= 1;
- return sid;
-}
-
-static void stream_desc_load(struct Stream *s, hwaddr addr)
-{
- struct SDesc *d = &s->desc;
-
- cpu_physical_memory_read(addr, d, sizeof *d);
-
- /* Convert from LE into host endianness. */
- d->buffer_address = le64_to_cpu(d->buffer_address);
- d->nxtdesc = le64_to_cpu(d->nxtdesc);
- d->control = le32_to_cpu(d->control);
- d->status = le32_to_cpu(d->status);
-}
-
-static void stream_desc_store(struct Stream *s, hwaddr addr)
-{
- struct SDesc *d = &s->desc;
-
- /* Convert from host endianness into LE. */
- d->buffer_address = cpu_to_le64(d->buffer_address);
- d->nxtdesc = cpu_to_le64(d->nxtdesc);
- d->control = cpu_to_le32(d->control);
- d->status = cpu_to_le32(d->status);
- cpu_physical_memory_write(addr, d, sizeof *d);
-}
-
-static void stream_update_irq(struct Stream *s)
-{
- unsigned int pending, mask, irq;
-
- pending = s->regs[R_DMASR] & DMASR_IRQ_MASK;
- mask = s->regs[R_DMACR] & DMASR_IRQ_MASK;
-
- irq = pending & mask;
-
- qemu_set_irq(s->irq, !!irq);
-}
-
-static void stream_reload_complete_cnt(struct Stream *s)
-{
- unsigned int comp_th;
- comp_th = (s->regs[R_DMACR] >> 16) & 0xff;
- s->complete_cnt = comp_th;
-}
-
-static void timer_hit(void *opaque)
-{
- struct Stream *s = opaque;
-
- stream_reload_complete_cnt(s);
- s->regs[R_DMASR] |= DMASR_DLY_IRQ;
- stream_update_irq(s);
-}
-
-static void stream_complete(struct Stream *s)
-{
- unsigned int comp_delay;
-
- /* Start the delayed timer. */
- comp_delay = s->regs[R_DMACR] >> 24;
- if (comp_delay) {
- ptimer_stop(s->ptimer);
- ptimer_set_count(s->ptimer, comp_delay);
- ptimer_run(s->ptimer, 1);
- }
-
- s->complete_cnt--;
- if (s->complete_cnt == 0) {
- /* Raise the IOC irq. */
- s->regs[R_DMASR] |= DMASR_IOC_IRQ;
- stream_reload_complete_cnt(s);
- }
-}
-
-static void stream_process_mem2s(struct Stream *s, StreamSlave *tx_data_dev,
- StreamSlave *tx_control_dev)
-{
- uint32_t prev_d;
- unsigned char txbuf[16 * 1024];
- unsigned int txlen;
-
- if (!stream_running(s) || stream_idle(s)) {
- return;
- }
-
- while (1) {
- stream_desc_load(s, s->regs[R_CURDESC]);
-
- if (s->desc.status & SDESC_STATUS_COMPLETE) {
- s->regs[R_DMASR] |= DMASR_HALTED;
- break;
- }
-
- if (stream_desc_sof(&s->desc)) {
- s->pos = 0;
- stream_push(tx_control_dev, s->desc.app, sizeof(s->desc.app));
- }
-
- txlen = s->desc.control & SDESC_CTRL_LEN_MASK;
- if ((txlen + s->pos) > sizeof txbuf) {
- hw_error("%s: too small internal txbuf! %d\n", __func__,
- txlen + s->pos);
- }
-
- cpu_physical_memory_read(s->desc.buffer_address,
- txbuf + s->pos, txlen);
- s->pos += txlen;
-
- if (stream_desc_eof(&s->desc)) {
- stream_push(tx_data_dev, txbuf, s->pos);
- s->pos = 0;
- stream_complete(s);
- }
-
- /* Update the descriptor. */
- s->desc.status = txlen | SDESC_STATUS_COMPLETE;
- stream_desc_store(s, s->regs[R_CURDESC]);
-
- /* Advance. */
- prev_d = s->regs[R_CURDESC];
- s->regs[R_CURDESC] = s->desc.nxtdesc;
- if (prev_d == s->regs[R_TAILDESC]) {
- s->regs[R_DMASR] |= DMASR_IDLE;
- break;
- }
- }
-}
-
-static size_t stream_process_s2mem(struct Stream *s, unsigned char *buf,
- size_t len)
-{
- uint32_t prev_d;
- unsigned int rxlen;
- size_t pos = 0;
- int sof = 1;
-
- if (!stream_running(s) || stream_idle(s)) {
- return 0;
- }
-
- while (len) {
- stream_desc_load(s, s->regs[R_CURDESC]);
-
- if (s->desc.status & SDESC_STATUS_COMPLETE) {
- s->regs[R_DMASR] |= DMASR_HALTED;
- break;
- }
-
- rxlen = s->desc.control & SDESC_CTRL_LEN_MASK;
- if (rxlen > len) {
- /* It fits. */
- rxlen = len;
- }
-
- cpu_physical_memory_write(s->desc.buffer_address, buf + pos, rxlen);
- len -= rxlen;
- pos += rxlen;
-
- /* Update the descriptor. */
- if (!len) {
- stream_complete(s);
- memcpy(s->desc.app, s->app, sizeof(s->desc.app));
- s->desc.status |= SDESC_STATUS_EOF;
- }
-
- s->desc.status |= sof << SDESC_STATUS_SOF_BIT;
- s->desc.status |= SDESC_STATUS_COMPLETE;
- stream_desc_store(s, s->regs[R_CURDESC]);
- sof = 0;
-
- /* Advance. */
- prev_d = s->regs[R_CURDESC];
- s->regs[R_CURDESC] = s->desc.nxtdesc;
- if (prev_d == s->regs[R_TAILDESC]) {
- s->regs[R_DMASR] |= DMASR_IDLE;
- break;
- }
- }
-
- return pos;
-}
-
-static void xilinx_axidma_reset(DeviceState *dev)
-{
- int i;
- XilinxAXIDMA *s = XILINX_AXI_DMA(dev);
-
- for (i = 0; i < 2; i++) {
- stream_reset(&s->streams[i]);
- }
-}
-
-static size_t
-xilinx_axidma_control_stream_push(StreamSlave *obj, unsigned char *buf,
- size_t len)
-{
- XilinxAXIDMAStreamSlave *cs = XILINX_AXI_DMA_CONTROL_STREAM(obj);
- struct Stream *s = &cs->dma->streams[1];
-
- if (len != CONTROL_PAYLOAD_SIZE) {
- hw_error("AXI DMA requires %d byte control stream payload\n",
- (int)CONTROL_PAYLOAD_SIZE);
- }
-
- memcpy(s->app, buf, len);
- return len;
-}
-
-static bool
-xilinx_axidma_data_stream_can_push(StreamSlave *obj,
- StreamCanPushNotifyFn notify,
- void *notify_opaque)
-{
- XilinxAXIDMAStreamSlave *ds = XILINX_AXI_DMA_DATA_STREAM(obj);
- struct Stream *s = &ds->dma->streams[1];
-
- if (!stream_running(s) || stream_idle(s)) {
- ds->dma->notify = notify;
- ds->dma->notify_opaque = notify_opaque;
- return false;
- }
-
- return true;
-}
-
-static size_t
-xilinx_axidma_data_stream_push(StreamSlave *obj, unsigned char *buf, size_t len)
-{
- XilinxAXIDMAStreamSlave *ds = XILINX_AXI_DMA_DATA_STREAM(obj);
- struct Stream *s = &ds->dma->streams[1];
- size_t ret;
-
- ret = stream_process_s2mem(s, buf, len);
- stream_update_irq(s);
- return ret;
-}
-
-static uint64_t axidma_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- XilinxAXIDMA *d = opaque;
- struct Stream *s;
- uint32_t r = 0;
- int sid;
-
- sid = streamid_from_addr(addr);
- s = &d->streams[sid];
-
- addr = addr % 0x30;
- addr >>= 2;
- switch (addr) {
- case R_DMACR:
- /* Simulate one cycles reset delay. */
- s->regs[addr] &= ~DMACR_RESET;
- r = s->regs[addr];
- break;
- case R_DMASR:
- s->regs[addr] &= 0xffff;
- s->regs[addr] |= (s->complete_cnt & 0xff) << 16;
- s->regs[addr] |= (ptimer_get_count(s->ptimer) & 0xff) << 24;
- r = s->regs[addr];
- break;
- default:
- r = s->regs[addr];
- D(qemu_log("%s ch=%d addr=" TARGET_FMT_plx " v=%x\n",
- __func__, sid, addr * 4, r));
- break;
- }
- return r;
-
-}
-
-static void axidma_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- XilinxAXIDMA *d = opaque;
- struct Stream *s;
- int sid;
-
- sid = streamid_from_addr(addr);
- s = &d->streams[sid];
-
- addr = addr % 0x30;
- addr >>= 2;
- switch (addr) {
- case R_DMACR:
- /* Tailptr mode is always on. */
- value |= DMACR_TAILPTR_MODE;
- /* Remember our previous reset state. */
- value |= (s->regs[addr] & DMACR_RESET);
- s->regs[addr] = value;
-
- if (value & DMACR_RESET) {
- stream_reset(s);
- }
-
- if ((value & 1) && !stream_resetting(s)) {
- /* Start processing. */
- s->regs[R_DMASR] &= ~(DMASR_HALTED | DMASR_IDLE);
- }
- stream_reload_complete_cnt(s);
- break;
-
- case R_DMASR:
- /* Mask away write to clear irq lines. */
- value &= ~(value & DMASR_IRQ_MASK);
- s->regs[addr] = value;
- break;
-
- case R_TAILDESC:
- s->regs[addr] = value;
- s->regs[R_DMASR] &= ~DMASR_IDLE; /* Not idle. */
- if (!sid) {
- stream_process_mem2s(s, d->tx_data_dev, d->tx_control_dev);
- }
- break;
- default:
- D(qemu_log("%s: ch=%d addr=" TARGET_FMT_plx " v=%x\n",
- __func__, sid, addr * 4, (unsigned)value));
- s->regs[addr] = value;
- break;
- }
- if (sid == 1 && d->notify) {
- StreamCanPushNotifyFn notifytmp = d->notify;
- d->notify = NULL;
- notifytmp(d->notify_opaque);
- }
- stream_update_irq(s);
-}
-
-static const MemoryRegionOps axidma_ops = {
- .read = axidma_read,
- .write = axidma_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void xilinx_axidma_realize(DeviceState *dev, Error **errp)
-{
- XilinxAXIDMA *s = XILINX_AXI_DMA(dev);
- XilinxAXIDMAStreamSlave *ds = XILINX_AXI_DMA_DATA_STREAM(&s->rx_data_dev);
- XilinxAXIDMAStreamSlave *cs = XILINX_AXI_DMA_CONTROL_STREAM(
- &s->rx_control_dev);
- Error *local_err = NULL;
-
- object_property_add_link(OBJECT(ds), "dma", TYPE_XILINX_AXI_DMA,
- (Object **)&ds->dma,
- object_property_allow_set_link,
- OBJ_PROP_LINK_UNREF_ON_RELEASE,
- &local_err);
- object_property_add_link(OBJECT(cs), "dma", TYPE_XILINX_AXI_DMA,
- (Object **)&cs->dma,
- object_property_allow_set_link,
- OBJ_PROP_LINK_UNREF_ON_RELEASE,
- &local_err);
- if (local_err) {
- goto xilinx_axidma_realize_fail;
- }
- object_property_set_link(OBJECT(ds), OBJECT(s), "dma", &local_err);
- object_property_set_link(OBJECT(cs), OBJECT(s), "dma", &local_err);
- if (local_err) {
- goto xilinx_axidma_realize_fail;
- }
-
- int i;
-
- for (i = 0; i < 2; i++) {
- struct Stream *st = &s->streams[i];
-
- st->nr = i;
- st->bh = qemu_bh_new(timer_hit, st);
- st->ptimer = ptimer_init(st->bh);
- ptimer_set_freq(st->ptimer, s->freqhz);
- }
- return;
-
-xilinx_axidma_realize_fail:
- if (!*errp) {
- *errp = local_err;
- }
-}
-
-static void xilinx_axidma_init(Object *obj)
-{
- XilinxAXIDMA *s = XILINX_AXI_DMA(obj);
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
-
- object_property_add_link(obj, "axistream-connected", TYPE_STREAM_SLAVE,
- (Object **)&s->tx_data_dev,
- qdev_prop_allow_set_link_before_realize,
- OBJ_PROP_LINK_UNREF_ON_RELEASE,
- &error_abort);
- object_property_add_link(obj, "axistream-control-connected",
- TYPE_STREAM_SLAVE,
- (Object **)&s->tx_control_dev,
- qdev_prop_allow_set_link_before_realize,
- OBJ_PROP_LINK_UNREF_ON_RELEASE,
- &error_abort);
-
- object_initialize(&s->rx_data_dev, sizeof(s->rx_data_dev),
- TYPE_XILINX_AXI_DMA_DATA_STREAM);
- object_initialize(&s->rx_control_dev, sizeof(s->rx_control_dev),
- TYPE_XILINX_AXI_DMA_CONTROL_STREAM);
- object_property_add_child(OBJECT(s), "axistream-connected-target",
- (Object *)&s->rx_data_dev, &error_abort);
- object_property_add_child(OBJECT(s), "axistream-control-connected-target",
- (Object *)&s->rx_control_dev, &error_abort);
-
- sysbus_init_irq(sbd, &s->streams[0].irq);
- sysbus_init_irq(sbd, &s->streams[1].irq);
-
- memory_region_init_io(&s->iomem, obj, &axidma_ops, s,
- "xlnx.axi-dma", R_MAX * 4 * 2);
- sysbus_init_mmio(sbd, &s->iomem);
-}
-
-static Property axidma_properties[] = {
- DEFINE_PROP_UINT32("freqhz", XilinxAXIDMA, freqhz, 50000000),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void axidma_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = xilinx_axidma_realize,
- dc->reset = xilinx_axidma_reset;
- dc->props = axidma_properties;
-}
-
-static StreamSlaveClass xilinx_axidma_data_stream_class = {
- .push = xilinx_axidma_data_stream_push,
- .can_push = xilinx_axidma_data_stream_can_push,
-};
-
-static StreamSlaveClass xilinx_axidma_control_stream_class = {
- .push = xilinx_axidma_control_stream_push,
-};
-
-static void xilinx_axidma_stream_class_init(ObjectClass *klass, void *data)
-{
- StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(klass);
-
- ssc->push = ((StreamSlaveClass *)data)->push;
- ssc->can_push = ((StreamSlaveClass *)data)->can_push;
-}
-
-static const TypeInfo axidma_info = {
- .name = TYPE_XILINX_AXI_DMA,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(XilinxAXIDMA),
- .class_init = axidma_class_init,
- .instance_init = xilinx_axidma_init,
-};
-
-static const TypeInfo xilinx_axidma_data_stream_info = {
- .name = TYPE_XILINX_AXI_DMA_DATA_STREAM,
- .parent = TYPE_OBJECT,
- .instance_size = sizeof(struct XilinxAXIDMAStreamSlave),
- .class_init = xilinx_axidma_stream_class_init,
- .class_data = &xilinx_axidma_data_stream_class,
- .interfaces = (InterfaceInfo[]) {
- { TYPE_STREAM_SLAVE },
- { }
- }
-};
-
-static const TypeInfo xilinx_axidma_control_stream_info = {
- .name = TYPE_XILINX_AXI_DMA_CONTROL_STREAM,
- .parent = TYPE_OBJECT,
- .instance_size = sizeof(struct XilinxAXIDMAStreamSlave),
- .class_init = xilinx_axidma_stream_class_init,
- .class_data = &xilinx_axidma_control_stream_class,
- .interfaces = (InterfaceInfo[]) {
- { TYPE_STREAM_SLAVE },
- { }
- }
-};
-
-static void xilinx_axidma_register_types(void)
-{
- type_register_static(&axidma_info);
- type_register_static(&xilinx_axidma_data_stream_info);
- type_register_static(&xilinx_axidma_control_stream_info);
-}
-
-type_init(xilinx_axidma_register_types)
diff --git a/qemu/hw/gpio/Makefile.objs b/qemu/hw/gpio/Makefile.objs
deleted file mode 100644
index a43c7cf44..000000000
--- a/qemu/hw/gpio/Makefile.objs
+++ /dev/null
@@ -1,9 +0,0 @@
-common-obj-$(CONFIG_MAX7310) += max7310.o
-common-obj-$(CONFIG_PL061) += pl061.o
-common-obj-$(CONFIG_PUV3) += puv3_gpio.o
-common-obj-$(CONFIG_ZAURUS) += zaurus.o
-common-obj-$(CONFIG_E500) += mpc8xxx.o
-common-obj-$(CONFIG_GPIO_KEY) += gpio_key.o
-
-obj-$(CONFIG_OMAP) += omap_gpio.o
-obj-$(CONFIG_IMX) += imx_gpio.o
diff --git a/qemu/hw/gpio/gpio_key.c b/qemu/hw/gpio/gpio_key.c
deleted file mode 100644
index ef287727b..000000000
--- a/qemu/hw/gpio/gpio_key.c
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * GPIO key
- *
- * Copyright (c) 2016 Linaro Limited
- *
- * Author: Shannon Zhao <shannon.zhao@linaro.org>
- *
- * Emulate a (human) keypress -- when the key is triggered by
- * setting the incoming gpio line, the outbound irq line is
- * raised for 100ms before being dropped again.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-
-#define TYPE_GPIOKEY "gpio-key"
-#define GPIOKEY(obj) OBJECT_CHECK(GPIOKEYState, (obj), TYPE_GPIOKEY)
-#define GPIO_KEY_LATENCY 100 /* 100ms */
-
-typedef struct GPIOKEYState {
- SysBusDevice parent_obj;
-
- QEMUTimer *timer;
- qemu_irq irq;
-} GPIOKEYState;
-
-static const VMStateDescription vmstate_gpio_key = {
- .name = "gpio-key",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_TIMER_PTR(timer, GPIOKEYState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void gpio_key_reset(DeviceState *dev)
-{
- GPIOKEYState *s = GPIOKEY(dev);
-
- timer_del(s->timer);
-}
-
-static void gpio_key_timer_expired(void *opaque)
-{
- GPIOKEYState *s = (GPIOKEYState *)opaque;
-
- qemu_set_irq(s->irq, 0);
- timer_del(s->timer);
-}
-
-static void gpio_key_set_irq(void *opaque, int irq, int level)
-{
- GPIOKEYState *s = (GPIOKEYState *)opaque;
-
- qemu_set_irq(s->irq, 1);
- timer_mod(s->timer,
- qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + GPIO_KEY_LATENCY);
-}
-
-static void gpio_key_realize(DeviceState *dev, Error **errp)
-{
- GPIOKEYState *s = GPIOKEY(dev);
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
-
- sysbus_init_irq(sbd, &s->irq);
- qdev_init_gpio_in(dev, gpio_key_set_irq, 1);
- s->timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, gpio_key_timer_expired, s);
-}
-
-static void gpio_key_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = gpio_key_realize;
- dc->vmsd = &vmstate_gpio_key;
- dc->reset = &gpio_key_reset;
-}
-
-static const TypeInfo gpio_key_info = {
- .name = TYPE_GPIOKEY,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(GPIOKEYState),
- .class_init = gpio_key_class_init,
-};
-
-static void gpio_key_register_types(void)
-{
- type_register_static(&gpio_key_info);
-}
-
-type_init(gpio_key_register_types)
diff --git a/qemu/hw/gpio/imx_gpio.c b/qemu/hw/gpio/imx_gpio.c
deleted file mode 100644
index ed7e247f5..000000000
--- a/qemu/hw/gpio/imx_gpio.c
+++ /dev/null
@@ -1,350 +0,0 @@
-/*
- * i.MX processors GPIO emulation.
- *
- * Copyright (C) 2015 Jean-Christophe Dubois <jcd@tribudubois.net>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/gpio/imx_gpio.h"
-
-#ifndef DEBUG_IMX_GPIO
-#define DEBUG_IMX_GPIO 0
-#endif
-
-typedef enum IMXGPIOLevel {
- IMX_GPIO_LEVEL_LOW = 0,
- IMX_GPIO_LEVEL_HIGH = 1,
-} IMXGPIOLevel;
-
-#define DPRINTF(fmt, args...) \
- do { \
- if (DEBUG_IMX_GPIO) { \
- fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_GPIO, \
- __func__, ##args); \
- } \
- } while (0)
-
-static const char *imx_gpio_reg_name(uint32_t reg)
-{
- switch (reg) {
- case DR_ADDR:
- return "DR";
- case GDIR_ADDR:
- return "GDIR";
- case PSR_ADDR:
- return "PSR";
- case ICR1_ADDR:
- return "ICR1";
- case ICR2_ADDR:
- return "ICR2";
- case IMR_ADDR:
- return "IMR";
- case ISR_ADDR:
- return "ISR";
- case EDGE_SEL_ADDR:
- return "EDGE_SEL";
- default:
- return "[?]";
- }
-}
-
-static void imx_gpio_update_int(IMXGPIOState *s)
-{
- if (s->has_upper_pin_irq) {
- qemu_set_irq(s->irq[0], (s->isr & s->imr & 0x0000FFFF) ? 1 : 0);
- qemu_set_irq(s->irq[1], (s->isr & s->imr & 0xFFFF0000) ? 1 : 0);
- } else {
- qemu_set_irq(s->irq[0], (s->isr & s->imr) ? 1 : 0);
- }
-}
-
-static void imx_gpio_set_int_line(IMXGPIOState *s, int line, IMXGPIOLevel level)
-{
- /* if this signal isn't configured as an input signal, nothing to do */
- if (!extract32(s->gdir, line, 1)) {
- return;
- }
-
- /* When set, EDGE_SEL overrides the ICR config */
- if (extract32(s->edge_sel, line, 1)) {
- /* we detect interrupt on rising and falling edge */
- if (extract32(s->psr, line, 1) != level) {
- /* level changed */
- s->isr = deposit32(s->isr, line, 1, 1);
- }
- } else if (extract64(s->icr, 2*line + 1, 1)) {
- /* interrupt is edge sensitive */
- if (extract32(s->psr, line, 1) != level) {
- /* level changed */
- if (extract64(s->icr, 2*line, 1) != level) {
- s->isr = deposit32(s->isr, line, 1, 1);
- }
- }
- } else {
- /* interrupt is level sensitive */
- if (extract64(s->icr, 2*line, 1) == level) {
- s->isr = deposit32(s->isr, line, 1, 1);
- }
- }
-}
-
-static void imx_gpio_set(void *opaque, int line, int level)
-{
- IMXGPIOState *s = IMX_GPIO(opaque);
- IMXGPIOLevel imx_level = level ? IMX_GPIO_LEVEL_HIGH : IMX_GPIO_LEVEL_LOW;
-
- imx_gpio_set_int_line(s, line, imx_level);
-
- /* this is an input signal, so set PSR */
- s->psr = deposit32(s->psr, line, 1, imx_level);
-
- imx_gpio_update_int(s);
-}
-
-static void imx_gpio_set_all_int_lines(IMXGPIOState *s)
-{
- int i;
-
- for (i = 0; i < IMX_GPIO_PIN_COUNT; i++) {
- IMXGPIOLevel imx_level = extract32(s->psr, i, 1);
- imx_gpio_set_int_line(s, i, imx_level);
- }
-
- imx_gpio_update_int(s);
-}
-
-static inline void imx_gpio_set_all_output_lines(IMXGPIOState *s)
-{
- int i;
-
- for (i = 0; i < IMX_GPIO_PIN_COUNT; i++) {
- /*
- * if the line is set as output, then forward the line
- * level to its user.
- */
- if (extract32(s->gdir, i, 1) && s->output[i]) {
- qemu_set_irq(s->output[i], extract32(s->dr, i, 1));
- }
- }
-}
-
-static uint64_t imx_gpio_read(void *opaque, hwaddr offset, unsigned size)
-{
- IMXGPIOState *s = IMX_GPIO(opaque);
- uint32_t reg_value = 0;
-
- switch (offset) {
- case DR_ADDR:
- /*
- * depending on the "line" configuration, the bit values
- * are coming either from DR or PSR
- */
- reg_value = (s->dr & s->gdir) | (s->psr & ~s->gdir);
- break;
-
- case GDIR_ADDR:
- reg_value = s->gdir;
- break;
-
- case PSR_ADDR:
- reg_value = s->psr & ~s->gdir;
- break;
-
- case ICR1_ADDR:
- reg_value = extract64(s->icr, 0, 32);
- break;
-
- case ICR2_ADDR:
- reg_value = extract64(s->icr, 32, 32);
- break;
-
- case IMR_ADDR:
- reg_value = s->imr;
- break;
-
- case ISR_ADDR:
- reg_value = s->isr;
- break;
-
- case EDGE_SEL_ADDR:
- if (s->has_edge_sel) {
- reg_value = s->edge_sel;
- } else {
- qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: EDGE_SEL register not "
- "present on this version of GPIO device\n",
- TYPE_IMX_GPIO, __func__);
- }
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
- HWADDR_PRIx "\n", TYPE_IMX_GPIO, __func__, offset);
- break;
- }
-
- DPRINTF("(%s) = 0x%" PRIx32 "\n", imx_gpio_reg_name(offset), reg_value);
-
- return reg_value;
-}
-
-static void imx_gpio_write(void *opaque, hwaddr offset, uint64_t value,
- unsigned size)
-{
- IMXGPIOState *s = IMX_GPIO(opaque);
-
- DPRINTF("(%s, value = 0x%" PRIx32 ")\n", imx_gpio_reg_name(offset),
- (uint32_t)value);
-
- switch (offset) {
- case DR_ADDR:
- s->dr = value;
- imx_gpio_set_all_output_lines(s);
- break;
-
- case GDIR_ADDR:
- s->gdir = value;
- imx_gpio_set_all_output_lines(s);
- imx_gpio_set_all_int_lines(s);
- break;
-
- case ICR1_ADDR:
- s->icr = deposit64(s->icr, 0, 32, value);
- imx_gpio_set_all_int_lines(s);
- break;
-
- case ICR2_ADDR:
- s->icr = deposit64(s->icr, 32, 32, value);
- imx_gpio_set_all_int_lines(s);
- break;
-
- case IMR_ADDR:
- s->imr = value;
- imx_gpio_update_int(s);
- break;
-
- case ISR_ADDR:
- s->isr |= ~value;
- imx_gpio_set_all_int_lines(s);
- break;
-
- case EDGE_SEL_ADDR:
- if (s->has_edge_sel) {
- s->edge_sel = value;
- imx_gpio_set_all_int_lines(s);
- } else {
- qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: EDGE_SEL register not "
- "present on this version of GPIO device\n",
- TYPE_IMX_GPIO, __func__);
- }
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
- HWADDR_PRIx "\n", TYPE_IMX_GPIO, __func__, offset);
- break;
- }
-
- return;
-}
-
-static const MemoryRegionOps imx_gpio_ops = {
- .read = imx_gpio_read,
- .write = imx_gpio_write,
- .valid.min_access_size = 4,
- .valid.max_access_size = 4,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_imx_gpio = {
- .name = TYPE_IMX_GPIO,
- .version_id = 1,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(dr, IMXGPIOState),
- VMSTATE_UINT32(gdir, IMXGPIOState),
- VMSTATE_UINT32(psr, IMXGPIOState),
- VMSTATE_UINT64(icr, IMXGPIOState),
- VMSTATE_UINT32(imr, IMXGPIOState),
- VMSTATE_UINT32(isr, IMXGPIOState),
- VMSTATE_BOOL(has_edge_sel, IMXGPIOState),
- VMSTATE_UINT32(edge_sel, IMXGPIOState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property imx_gpio_properties[] = {
- DEFINE_PROP_BOOL("has-edge-sel", IMXGPIOState, has_edge_sel, true),
- DEFINE_PROP_BOOL("has-upper-pin-irq", IMXGPIOState, has_upper_pin_irq,
- false),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void imx_gpio_reset(DeviceState *dev)
-{
- IMXGPIOState *s = IMX_GPIO(dev);
-
- s->dr = 0;
- s->gdir = 0;
- s->psr = 0;
- s->icr = 0;
- s->imr = 0;
- s->isr = 0;
- s->edge_sel = 0;
-
- imx_gpio_set_all_output_lines(s);
- imx_gpio_update_int(s);
-}
-
-static void imx_gpio_realize(DeviceState *dev, Error **errp)
-{
- IMXGPIOState *s = IMX_GPIO(dev);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &imx_gpio_ops, s,
- TYPE_IMX_GPIO, IMX_GPIO_MEM_SIZE);
-
- qdev_init_gpio_in(DEVICE(s), imx_gpio_set, IMX_GPIO_PIN_COUNT);
- qdev_init_gpio_out(DEVICE(s), s->output, IMX_GPIO_PIN_COUNT);
-
- sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[0]);
- sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[1]);
- sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
-}
-
-static void imx_gpio_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = imx_gpio_realize;
- dc->reset = imx_gpio_reset;
- dc->props = imx_gpio_properties;
- dc->vmsd = &vmstate_imx_gpio;
- dc->desc = "i.MX GPIO controller";
-}
-
-static const TypeInfo imx_gpio_info = {
- .name = TYPE_IMX_GPIO,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(IMXGPIOState),
- .class_init = imx_gpio_class_init,
-};
-
-static void imx_gpio_register_types(void)
-{
- type_register_static(&imx_gpio_info);
-}
-
-type_init(imx_gpio_register_types)
diff --git a/qemu/hw/gpio/max7310.c b/qemu/hw/gpio/max7310.c
deleted file mode 100644
index 1bd5eaf91..000000000
--- a/qemu/hw/gpio/max7310.c
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * MAX7310 8-port GPIO expansion chip.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This file is licensed under GNU GPL.
- */
-
-#include "qemu/osdep.h"
-#include "hw/i2c/i2c.h"
-
-#define TYPE_MAX7310 "max7310"
-#define MAX7310(obj) OBJECT_CHECK(MAX7310State, (obj), TYPE_MAX7310)
-
-typedef struct MAX7310State {
- I2CSlave parent_obj;
-
- int i2c_command_byte;
- int len;
-
- uint8_t level;
- uint8_t direction;
- uint8_t polarity;
- uint8_t status;
- uint8_t command;
- qemu_irq handler[8];
- qemu_irq *gpio_in;
-} MAX7310State;
-
-static void max7310_reset(DeviceState *dev)
-{
- MAX7310State *s = MAX7310(dev);
-
- s->level &= s->direction;
- s->direction = 0xff;
- s->polarity = 0xf0;
- s->status = 0x01;
- s->command = 0x00;
-}
-
-static int max7310_rx(I2CSlave *i2c)
-{
- MAX7310State *s = MAX7310(i2c);
-
- switch (s->command) {
- case 0x00: /* Input port */
- return s->level ^ s->polarity;
- break;
-
- case 0x01: /* Output port */
- return s->level & ~s->direction;
- break;
-
- case 0x02: /* Polarity inversion */
- return s->polarity;
-
- case 0x03: /* Configuration */
- return s->direction;
-
- case 0x04: /* Timeout */
- return s->status;
- break;
-
- case 0xff: /* Reserved */
- return 0xff;
-
- default:
-#ifdef VERBOSE
- printf("%s: unknown register %02x\n", __FUNCTION__, s->command);
-#endif
- break;
- }
- return 0xff;
-}
-
-static int max7310_tx(I2CSlave *i2c, uint8_t data)
-{
- MAX7310State *s = MAX7310(i2c);
- uint8_t diff;
- int line;
-
- if (s->len ++ > 1) {
-#ifdef VERBOSE
- printf("%s: message too long (%i bytes)\n", __FUNCTION__, s->len);
-#endif
- return 1;
- }
-
- if (s->i2c_command_byte) {
- s->command = data;
- s->i2c_command_byte = 0;
- return 0;
- }
-
- switch (s->command) {
- case 0x01: /* Output port */
- for (diff = (data ^ s->level) & ~s->direction; diff;
- diff &= ~(1 << line)) {
- line = ctz32(diff);
- if (s->handler[line])
- qemu_set_irq(s->handler[line], (data >> line) & 1);
- }
- s->level = (s->level & s->direction) | (data & ~s->direction);
- break;
-
- case 0x02: /* Polarity inversion */
- s->polarity = data;
- break;
-
- case 0x03: /* Configuration */
- s->level &= ~(s->direction ^ data);
- s->direction = data;
- break;
-
- case 0x04: /* Timeout */
- s->status = data;
- break;
-
- case 0x00: /* Input port - ignore writes */
- break;
- default:
-#ifdef VERBOSE
- printf("%s: unknown register %02x\n", __FUNCTION__, s->command);
-#endif
- return 1;
- }
-
- return 0;
-}
-
-static void max7310_event(I2CSlave *i2c, enum i2c_event event)
-{
- MAX7310State *s = MAX7310(i2c);
- s->len = 0;
-
- switch (event) {
- case I2C_START_SEND:
- s->i2c_command_byte = 1;
- break;
- case I2C_FINISH:
-#ifdef VERBOSE
- if (s->len == 1)
- printf("%s: message too short (%i bytes)\n", __FUNCTION__, s->len);
-#endif
- break;
- default:
- break;
- }
-}
-
-static const VMStateDescription vmstate_max7310 = {
- .name = "max7310",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_INT32(i2c_command_byte, MAX7310State),
- VMSTATE_INT32(len, MAX7310State),
- VMSTATE_UINT8(level, MAX7310State),
- VMSTATE_UINT8(direction, MAX7310State),
- VMSTATE_UINT8(polarity, MAX7310State),
- VMSTATE_UINT8(status, MAX7310State),
- VMSTATE_UINT8(command, MAX7310State),
- VMSTATE_I2C_SLAVE(parent_obj, MAX7310State),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void max7310_gpio_set(void *opaque, int line, int level)
-{
- MAX7310State *s = (MAX7310State *) opaque;
- if (line >= ARRAY_SIZE(s->handler) || line < 0)
- hw_error("bad GPIO line");
-
- if (level)
- s->level |= s->direction & (1 << line);
- else
- s->level &= ~(s->direction & (1 << line));
-}
-
-/* MAX7310 is SMBus-compatible (can be used with only SMBus protocols),
- * but also accepts sequences that are not SMBus so return an I2C device. */
-static int max7310_init(I2CSlave *i2c)
-{
- MAX7310State *s = MAX7310(i2c);
-
- qdev_init_gpio_in(&i2c->qdev, max7310_gpio_set, 8);
- qdev_init_gpio_out(&i2c->qdev, s->handler, 8);
-
- return 0;
-}
-
-static void max7310_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
-
- k->init = max7310_init;
- k->event = max7310_event;
- k->recv = max7310_rx;
- k->send = max7310_tx;
- dc->reset = max7310_reset;
- dc->vmsd = &vmstate_max7310;
-}
-
-static const TypeInfo max7310_info = {
- .name = TYPE_MAX7310,
- .parent = TYPE_I2C_SLAVE,
- .instance_size = sizeof(MAX7310State),
- .class_init = max7310_class_init,
-};
-
-static void max7310_register_types(void)
-{
- type_register_static(&max7310_info);
-}
-
-type_init(max7310_register_types)
diff --git a/qemu/hw/gpio/mpc8xxx.c b/qemu/hw/gpio/mpc8xxx.c
deleted file mode 100644
index d14971946..000000000
--- a/qemu/hw/gpio/mpc8xxx.c
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * GPIO Controller for a lot of Freescale SoCs
- *
- * Copyright (C) 2014 Freescale Semiconductor, Inc. All rights reserved.
- *
- * Author: Alexander Graf, <agraf@suse.de>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-
-#define TYPE_MPC8XXX_GPIO "mpc8xxx_gpio"
-#define MPC8XXX_GPIO(obj) OBJECT_CHECK(MPC8XXXGPIOState, (obj), TYPE_MPC8XXX_GPIO)
-
-typedef struct MPC8XXXGPIOState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- qemu_irq irq;
- qemu_irq out[32];
-
- uint32_t dir;
- uint32_t odr;
- uint32_t dat;
- uint32_t ier;
- uint32_t imr;
- uint32_t icr;
-} MPC8XXXGPIOState;
-
-static const VMStateDescription vmstate_mpc8xxx_gpio = {
- .name = "mpc8xxx_gpio",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(dir, MPC8XXXGPIOState),
- VMSTATE_UINT32(odr, MPC8XXXGPIOState),
- VMSTATE_UINT32(dat, MPC8XXXGPIOState),
- VMSTATE_UINT32(ier, MPC8XXXGPIOState),
- VMSTATE_UINT32(imr, MPC8XXXGPIOState),
- VMSTATE_UINT32(icr, MPC8XXXGPIOState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void mpc8xxx_gpio_update(MPC8XXXGPIOState *s)
-{
- qemu_set_irq(s->irq, !!(s->ier & s->imr));
-}
-
-static uint64_t mpc8xxx_gpio_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- MPC8XXXGPIOState *s = (MPC8XXXGPIOState *)opaque;
-
- if (size != 4) {
- /* All registers are 32bit */
- return 0;
- }
-
- switch (offset) {
- case 0x0: /* Direction */
- return s->dir;
- case 0x4: /* Open Drain */
- return s->odr;
- case 0x8: /* Data */
- return s->dat;
- case 0xC: /* Interrupt Event */
- return s->ier;
- case 0x10: /* Interrupt Mask */
- return s->imr;
- case 0x14: /* Interrupt Control */
- return s->icr;
- default:
- return 0;
- }
-}
-
-static void mpc8xxx_write_data(MPC8XXXGPIOState *s, uint32_t new_data)
-{
- uint32_t old_data = s->dat;
- uint32_t diff = old_data ^ new_data;
- int i;
-
- for (i = 0; i < 32; i++) {
- uint32_t mask = 0x80000000 >> i;
- if (!(diff & mask)) {
- continue;
- }
-
- if (s->dir & mask) {
- /* Output */
- qemu_set_irq(s->out[i], (new_data & mask) != 0);
- }
- }
-
- s->dat = new_data;
-}
-
-static void mpc8xxx_gpio_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- MPC8XXXGPIOState *s = (MPC8XXXGPIOState *)opaque;
-
- if (size != 4) {
- /* All registers are 32bit */
- return;
- }
-
- switch (offset) {
- case 0x0: /* Direction */
- s->dir = value;
- break;
- case 0x4: /* Open Drain */
- s->odr = value;
- break;
- case 0x8: /* Data */
- mpc8xxx_write_data(s, value);
- break;
- case 0xC: /* Interrupt Event */
- s->ier &= ~value;
- break;
- case 0x10: /* Interrupt Mask */
- s->imr = value;
- break;
- case 0x14: /* Interrupt Control */
- s->icr = value;
- break;
- }
-
- mpc8xxx_gpio_update(s);
-}
-
-static void mpc8xxx_gpio_reset(MPC8XXXGPIOState *s)
-{
- s->dir = 0;
- s->odr = 0;
- s->dat = 0;
- s->ier = 0;
- s->imr = 0;
- s->icr = 0;
-}
-
-static void mpc8xxx_gpio_set_irq(void * opaque, int irq, int level)
-{
- MPC8XXXGPIOState *s = (MPC8XXXGPIOState *)opaque;
- uint32_t mask;
-
- mask = 0x80000000 >> irq;
- if ((s->dir & mask) == 0) {
- uint32_t old_value = s->dat & mask;
-
- s->dat &= ~mask;
- if (level)
- s->dat |= mask;
-
- if (!(s->icr & irq) || (old_value && !level)) {
- s->ier |= mask;
- }
-
- mpc8xxx_gpio_update(s);
- }
-}
-
-static const MemoryRegionOps mpc8xxx_gpio_ops = {
- .read = mpc8xxx_gpio_read,
- .write = mpc8xxx_gpio_write,
- .endianness = DEVICE_BIG_ENDIAN,
-};
-
-static int mpc8xxx_gpio_initfn(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- MPC8XXXGPIOState *s = MPC8XXX_GPIO(dev);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &mpc8xxx_gpio_ops, s, "mpc8xxx_gpio", 0x1000);
- sysbus_init_mmio(sbd, &s->iomem);
- sysbus_init_irq(sbd, &s->irq);
- qdev_init_gpio_in(dev, mpc8xxx_gpio_set_irq, 32);
- qdev_init_gpio_out(dev, s->out, 32);
- mpc8xxx_gpio_reset(s);
- return 0;
-}
-
-static void mpc8xxx_gpio_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = mpc8xxx_gpio_initfn;
- dc->vmsd = &vmstate_mpc8xxx_gpio;
-}
-
-static const TypeInfo mpc8xxx_gpio_info = {
- .name = TYPE_MPC8XXX_GPIO,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(MPC8XXXGPIOState),
- .class_init = mpc8xxx_gpio_class_init,
-};
-
-static void mpc8xxx_gpio_register_types(void)
-{
- type_register_static(&mpc8xxx_gpio_info);
-}
-
-type_init(mpc8xxx_gpio_register_types)
diff --git a/qemu/hw/gpio/omap_gpio.c b/qemu/hw/gpio/omap_gpio.c
deleted file mode 100644
index 9b1b004fc..000000000
--- a/qemu/hw/gpio/omap_gpio.c
+++ /dev/null
@@ -1,822 +0,0 @@
-/*
- * TI OMAP processors GPIO emulation.
- *
- * Copyright (C) 2006-2008 Andrzej Zaborowski <balrog@zabor.org>
- * Copyright (C) 2007-2009 Nokia Corporation
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/arm/omap.h"
-#include "hw/sysbus.h"
-#include "qemu/error-report.h"
-
-struct omap_gpio_s {
- qemu_irq irq;
- qemu_irq handler[16];
-
- uint16_t inputs;
- uint16_t outputs;
- uint16_t dir;
- uint16_t edge;
- uint16_t mask;
- uint16_t ints;
- uint16_t pins;
-};
-
-#define TYPE_OMAP1_GPIO "omap-gpio"
-#define OMAP1_GPIO(obj) \
- OBJECT_CHECK(struct omap_gpif_s, (obj), TYPE_OMAP1_GPIO)
-
-struct omap_gpif_s {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- int mpu_model;
- void *clk;
- struct omap_gpio_s omap1;
-};
-
-/* General-Purpose I/O of OMAP1 */
-static void omap_gpio_set(void *opaque, int line, int level)
-{
- struct omap_gpio_s *s = &((struct omap_gpif_s *) opaque)->omap1;
- uint16_t prev = s->inputs;
-
- if (level)
- s->inputs |= 1 << line;
- else
- s->inputs &= ~(1 << line);
-
- if (((s->edge & s->inputs & ~prev) | (~s->edge & ~s->inputs & prev)) &
- (1 << line) & s->dir & ~s->mask) {
- s->ints |= 1 << line;
- qemu_irq_raise(s->irq);
- }
-}
-
-static uint64_t omap_gpio_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_gpio_s *s = (struct omap_gpio_s *) opaque;
- int offset = addr & OMAP_MPUI_REG_MASK;
-
- if (size != 2) {
- return omap_badwidth_read16(opaque, addr);
- }
-
- switch (offset) {
- case 0x00: /* DATA_INPUT */
- return s->inputs & s->pins;
-
- case 0x04: /* DATA_OUTPUT */
- return s->outputs;
-
- case 0x08: /* DIRECTION_CONTROL */
- return s->dir;
-
- case 0x0c: /* INTERRUPT_CONTROL */
- return s->edge;
-
- case 0x10: /* INTERRUPT_MASK */
- return s->mask;
-
- case 0x14: /* INTERRUPT_STATUS */
- return s->ints;
-
- case 0x18: /* PIN_CONTROL (not in OMAP310) */
- OMAP_BAD_REG(addr);
- return s->pins;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_gpio_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_gpio_s *s = (struct omap_gpio_s *) opaque;
- int offset = addr & OMAP_MPUI_REG_MASK;
- uint16_t diff;
- int ln;
-
- if (size != 2) {
- omap_badwidth_write16(opaque, addr, value);
- return;
- }
-
- switch (offset) {
- case 0x00: /* DATA_INPUT */
- OMAP_RO_REG(addr);
- return;
-
- case 0x04: /* DATA_OUTPUT */
- diff = (s->outputs ^ value) & ~s->dir;
- s->outputs = value;
- while ((ln = ctz32(diff)) != 32) {
- if (s->handler[ln])
- qemu_set_irq(s->handler[ln], (value >> ln) & 1);
- diff &= ~(1 << ln);
- }
- break;
-
- case 0x08: /* DIRECTION_CONTROL */
- diff = s->outputs & (s->dir ^ value);
- s->dir = value;
-
- value = s->outputs & ~s->dir;
- while ((ln = ctz32(diff)) != 32) {
- if (s->handler[ln])
- qemu_set_irq(s->handler[ln], (value >> ln) & 1);
- diff &= ~(1 << ln);
- }
- break;
-
- case 0x0c: /* INTERRUPT_CONTROL */
- s->edge = value;
- break;
-
- case 0x10: /* INTERRUPT_MASK */
- s->mask = value;
- break;
-
- case 0x14: /* INTERRUPT_STATUS */
- s->ints &= ~value;
- if (!s->ints)
- qemu_irq_lower(s->irq);
- break;
-
- case 0x18: /* PIN_CONTROL (not in OMAP310 TRM) */
- OMAP_BAD_REG(addr);
- s->pins = value;
- break;
-
- default:
- OMAP_BAD_REG(addr);
- return;
- }
-}
-
-/* *Some* sources say the memory region is 32-bit. */
-static const MemoryRegionOps omap_gpio_ops = {
- .read = omap_gpio_read,
- .write = omap_gpio_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void omap_gpio_reset(struct omap_gpio_s *s)
-{
- s->inputs = 0;
- s->outputs = ~0;
- s->dir = ~0;
- s->edge = ~0;
- s->mask = ~0;
- s->ints = 0;
- s->pins = ~0;
-}
-
-struct omap2_gpio_s {
- qemu_irq irq[2];
- qemu_irq wkup;
- qemu_irq *handler;
- MemoryRegion iomem;
-
- uint8_t revision;
- uint8_t config[2];
- uint32_t inputs;
- uint32_t outputs;
- uint32_t dir;
- uint32_t level[2];
- uint32_t edge[2];
- uint32_t mask[2];
- uint32_t wumask;
- uint32_t ints[2];
- uint32_t debounce;
- uint8_t delay;
-};
-
-#define TYPE_OMAP2_GPIO "omap2-gpio"
-#define OMAP2_GPIO(obj) \
- OBJECT_CHECK(struct omap2_gpif_s, (obj), TYPE_OMAP2_GPIO)
-
-struct omap2_gpif_s {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- int mpu_model;
- void *iclk;
- void *fclk[6];
- int modulecount;
- struct omap2_gpio_s *modules;
- qemu_irq *handler;
- int autoidle;
- int gpo;
-};
-
-/* General-Purpose Interface of OMAP2/3 */
-static inline void omap2_gpio_module_int_update(struct omap2_gpio_s *s,
- int line)
-{
- qemu_set_irq(s->irq[line], s->ints[line] & s->mask[line]);
-}
-
-static void omap2_gpio_module_wake(struct omap2_gpio_s *s, int line)
-{
- if (!(s->config[0] & (1 << 2))) /* ENAWAKEUP */
- return;
- if (!(s->config[0] & (3 << 3))) /* Force Idle */
- return;
- if (!(s->wumask & (1 << line)))
- return;
-
- qemu_irq_raise(s->wkup);
-}
-
-static inline void omap2_gpio_module_out_update(struct omap2_gpio_s *s,
- uint32_t diff)
-{
- int ln;
-
- s->outputs ^= diff;
- diff &= ~s->dir;
- while ((ln = ctz32(diff)) != 32) {
- qemu_set_irq(s->handler[ln], (s->outputs >> ln) & 1);
- diff &= ~(1 << ln);
- }
-}
-
-static void omap2_gpio_module_level_update(struct omap2_gpio_s *s, int line)
-{
- s->ints[line] |= s->dir &
- ((s->inputs & s->level[1]) | (~s->inputs & s->level[0]));
- omap2_gpio_module_int_update(s, line);
-}
-
-static inline void omap2_gpio_module_int(struct omap2_gpio_s *s, int line)
-{
- s->ints[0] |= 1 << line;
- omap2_gpio_module_int_update(s, 0);
- s->ints[1] |= 1 << line;
- omap2_gpio_module_int_update(s, 1);
- omap2_gpio_module_wake(s, line);
-}
-
-static void omap2_gpio_set(void *opaque, int line, int level)
-{
- struct omap2_gpif_s *p = opaque;
- struct omap2_gpio_s *s = &p->modules[line >> 5];
-
- line &= 31;
- if (level) {
- if (s->dir & (1 << line) & ((~s->inputs & s->edge[0]) | s->level[1]))
- omap2_gpio_module_int(s, line);
- s->inputs |= 1 << line;
- } else {
- if (s->dir & (1 << line) & ((s->inputs & s->edge[1]) | s->level[0]))
- omap2_gpio_module_int(s, line);
- s->inputs &= ~(1 << line);
- }
-}
-
-static void omap2_gpio_module_reset(struct omap2_gpio_s *s)
-{
- s->config[0] = 0;
- s->config[1] = 2;
- s->ints[0] = 0;
- s->ints[1] = 0;
- s->mask[0] = 0;
- s->mask[1] = 0;
- s->wumask = 0;
- s->dir = ~0;
- s->level[0] = 0;
- s->level[1] = 0;
- s->edge[0] = 0;
- s->edge[1] = 0;
- s->debounce = 0;
- s->delay = 0;
-}
-
-static uint32_t omap2_gpio_module_read(void *opaque, hwaddr addr)
-{
- struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque;
-
- switch (addr) {
- case 0x00: /* GPIO_REVISION */
- return s->revision;
-
- case 0x10: /* GPIO_SYSCONFIG */
- return s->config[0];
-
- case 0x14: /* GPIO_SYSSTATUS */
- return 0x01;
-
- case 0x18: /* GPIO_IRQSTATUS1 */
- return s->ints[0];
-
- case 0x1c: /* GPIO_IRQENABLE1 */
- case 0x60: /* GPIO_CLEARIRQENABLE1 */
- case 0x64: /* GPIO_SETIRQENABLE1 */
- return s->mask[0];
-
- case 0x20: /* GPIO_WAKEUPENABLE */
- case 0x80: /* GPIO_CLEARWKUENA */
- case 0x84: /* GPIO_SETWKUENA */
- return s->wumask;
-
- case 0x28: /* GPIO_IRQSTATUS2 */
- return s->ints[1];
-
- case 0x2c: /* GPIO_IRQENABLE2 */
- case 0x70: /* GPIO_CLEARIRQENABLE2 */
- case 0x74: /* GPIO_SETIREQNEABLE2 */
- return s->mask[1];
-
- case 0x30: /* GPIO_CTRL */
- return s->config[1];
-
- case 0x34: /* GPIO_OE */
- return s->dir;
-
- case 0x38: /* GPIO_DATAIN */
- return s->inputs;
-
- case 0x3c: /* GPIO_DATAOUT */
- case 0x90: /* GPIO_CLEARDATAOUT */
- case 0x94: /* GPIO_SETDATAOUT */
- return s->outputs;
-
- case 0x40: /* GPIO_LEVELDETECT0 */
- return s->level[0];
-
- case 0x44: /* GPIO_LEVELDETECT1 */
- return s->level[1];
-
- case 0x48: /* GPIO_RISINGDETECT */
- return s->edge[0];
-
- case 0x4c: /* GPIO_FALLINGDETECT */
- return s->edge[1];
-
- case 0x50: /* GPIO_DEBOUNCENABLE */
- return s->debounce;
-
- case 0x54: /* GPIO_DEBOUNCINGTIME */
- return s->delay;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap2_gpio_module_write(void *opaque, hwaddr addr,
- uint32_t value)
-{
- struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque;
- uint32_t diff;
- int ln;
-
- switch (addr) {
- case 0x00: /* GPIO_REVISION */
- case 0x14: /* GPIO_SYSSTATUS */
- case 0x38: /* GPIO_DATAIN */
- OMAP_RO_REG(addr);
- break;
-
- case 0x10: /* GPIO_SYSCONFIG */
- if (((value >> 3) & 3) == 3)
- fprintf(stderr, "%s: bad IDLEMODE value\n", __FUNCTION__);
- if (value & 2)
- omap2_gpio_module_reset(s);
- s->config[0] = value & 0x1d;
- break;
-
- case 0x18: /* GPIO_IRQSTATUS1 */
- if (s->ints[0] & value) {
- s->ints[0] &= ~value;
- omap2_gpio_module_level_update(s, 0);
- }
- break;
-
- case 0x1c: /* GPIO_IRQENABLE1 */
- s->mask[0] = value;
- omap2_gpio_module_int_update(s, 0);
- break;
-
- case 0x20: /* GPIO_WAKEUPENABLE */
- s->wumask = value;
- break;
-
- case 0x28: /* GPIO_IRQSTATUS2 */
- if (s->ints[1] & value) {
- s->ints[1] &= ~value;
- omap2_gpio_module_level_update(s, 1);
- }
- break;
-
- case 0x2c: /* GPIO_IRQENABLE2 */
- s->mask[1] = value;
- omap2_gpio_module_int_update(s, 1);
- break;
-
- case 0x30: /* GPIO_CTRL */
- s->config[1] = value & 7;
- break;
-
- case 0x34: /* GPIO_OE */
- diff = s->outputs & (s->dir ^ value);
- s->dir = value;
-
- value = s->outputs & ~s->dir;
- while ((ln = ctz32(diff)) != 32) {
- diff &= ~(1 << ln);
- qemu_set_irq(s->handler[ln], (value >> ln) & 1);
- }
-
- omap2_gpio_module_level_update(s, 0);
- omap2_gpio_module_level_update(s, 1);
- break;
-
- case 0x3c: /* GPIO_DATAOUT */
- omap2_gpio_module_out_update(s, s->outputs ^ value);
- break;
-
- case 0x40: /* GPIO_LEVELDETECT0 */
- s->level[0] = value;
- omap2_gpio_module_level_update(s, 0);
- omap2_gpio_module_level_update(s, 1);
- break;
-
- case 0x44: /* GPIO_LEVELDETECT1 */
- s->level[1] = value;
- omap2_gpio_module_level_update(s, 0);
- omap2_gpio_module_level_update(s, 1);
- break;
-
- case 0x48: /* GPIO_RISINGDETECT */
- s->edge[0] = value;
- break;
-
- case 0x4c: /* GPIO_FALLINGDETECT */
- s->edge[1] = value;
- break;
-
- case 0x50: /* GPIO_DEBOUNCENABLE */
- s->debounce = value;
- break;
-
- case 0x54: /* GPIO_DEBOUNCINGTIME */
- s->delay = value;
- break;
-
- case 0x60: /* GPIO_CLEARIRQENABLE1 */
- s->mask[0] &= ~value;
- omap2_gpio_module_int_update(s, 0);
- break;
-
- case 0x64: /* GPIO_SETIRQENABLE1 */
- s->mask[0] |= value;
- omap2_gpio_module_int_update(s, 0);
- break;
-
- case 0x70: /* GPIO_CLEARIRQENABLE2 */
- s->mask[1] &= ~value;
- omap2_gpio_module_int_update(s, 1);
- break;
-
- case 0x74: /* GPIO_SETIREQNEABLE2 */
- s->mask[1] |= value;
- omap2_gpio_module_int_update(s, 1);
- break;
-
- case 0x80: /* GPIO_CLEARWKUENA */
- s->wumask &= ~value;
- break;
-
- case 0x84: /* GPIO_SETWKUENA */
- s->wumask |= value;
- break;
-
- case 0x90: /* GPIO_CLEARDATAOUT */
- omap2_gpio_module_out_update(s, s->outputs & value);
- break;
-
- case 0x94: /* GPIO_SETDATAOUT */
- omap2_gpio_module_out_update(s, ~s->outputs & value);
- break;
-
- default:
- OMAP_BAD_REG(addr);
- return;
- }
-}
-
-static uint32_t omap2_gpio_module_readp(void *opaque, hwaddr addr)
-{
- return omap2_gpio_module_read(opaque, addr & ~3) >> ((addr & 3) << 3);
-}
-
-static void omap2_gpio_module_writep(void *opaque, hwaddr addr,
- uint32_t value)
-{
- uint32_t cur = 0;
- uint32_t mask = 0xffff;
-
- switch (addr & ~3) {
- case 0x00: /* GPIO_REVISION */
- case 0x14: /* GPIO_SYSSTATUS */
- case 0x38: /* GPIO_DATAIN */
- OMAP_RO_REG(addr);
- break;
-
- case 0x10: /* GPIO_SYSCONFIG */
- case 0x1c: /* GPIO_IRQENABLE1 */
- case 0x20: /* GPIO_WAKEUPENABLE */
- case 0x2c: /* GPIO_IRQENABLE2 */
- case 0x30: /* GPIO_CTRL */
- case 0x34: /* GPIO_OE */
- case 0x3c: /* GPIO_DATAOUT */
- case 0x40: /* GPIO_LEVELDETECT0 */
- case 0x44: /* GPIO_LEVELDETECT1 */
- case 0x48: /* GPIO_RISINGDETECT */
- case 0x4c: /* GPIO_FALLINGDETECT */
- case 0x50: /* GPIO_DEBOUNCENABLE */
- case 0x54: /* GPIO_DEBOUNCINGTIME */
- cur = omap2_gpio_module_read(opaque, addr & ~3) &
- ~(mask << ((addr & 3) << 3));
-
- /* Fall through. */
- case 0x18: /* GPIO_IRQSTATUS1 */
- case 0x28: /* GPIO_IRQSTATUS2 */
- case 0x60: /* GPIO_CLEARIRQENABLE1 */
- case 0x64: /* GPIO_SETIRQENABLE1 */
- case 0x70: /* GPIO_CLEARIRQENABLE2 */
- case 0x74: /* GPIO_SETIREQNEABLE2 */
- case 0x80: /* GPIO_CLEARWKUENA */
- case 0x84: /* GPIO_SETWKUENA */
- case 0x90: /* GPIO_CLEARDATAOUT */
- case 0x94: /* GPIO_SETDATAOUT */
- value <<= (addr & 3) << 3;
- omap2_gpio_module_write(opaque, addr, cur | value);
- break;
-
- default:
- OMAP_BAD_REG(addr);
- return;
- }
-}
-
-static const MemoryRegionOps omap2_gpio_module_ops = {
- .old_mmio = {
- .read = {
- omap2_gpio_module_readp,
- omap2_gpio_module_readp,
- omap2_gpio_module_read,
- },
- .write = {
- omap2_gpio_module_writep,
- omap2_gpio_module_writep,
- omap2_gpio_module_write,
- },
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void omap_gpif_reset(DeviceState *dev)
-{
- struct omap_gpif_s *s = OMAP1_GPIO(dev);
-
- omap_gpio_reset(&s->omap1);
-}
-
-static void omap2_gpif_reset(DeviceState *dev)
-{
- struct omap2_gpif_s *s = OMAP2_GPIO(dev);
- int i;
-
- for (i = 0; i < s->modulecount; i++) {
- omap2_gpio_module_reset(&s->modules[i]);
- }
- s->autoidle = 0;
- s->gpo = 0;
-}
-
-static uint64_t omap2_gpif_top_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap2_gpif_s *s = (struct omap2_gpif_s *) opaque;
-
- switch (addr) {
- case 0x00: /* IPGENERICOCPSPL_REVISION */
- return 0x18;
-
- case 0x10: /* IPGENERICOCPSPL_SYSCONFIG */
- return s->autoidle;
-
- case 0x14: /* IPGENERICOCPSPL_SYSSTATUS */
- return 0x01;
-
- case 0x18: /* IPGENERICOCPSPL_IRQSTATUS */
- return 0x00;
-
- case 0x40: /* IPGENERICOCPSPL_GPO */
- return s->gpo;
-
- case 0x50: /* IPGENERICOCPSPL_GPI */
- return 0x00;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap2_gpif_top_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap2_gpif_s *s = (struct omap2_gpif_s *) opaque;
-
- switch (addr) {
- case 0x00: /* IPGENERICOCPSPL_REVISION */
- case 0x14: /* IPGENERICOCPSPL_SYSSTATUS */
- case 0x18: /* IPGENERICOCPSPL_IRQSTATUS */
- case 0x50: /* IPGENERICOCPSPL_GPI */
- OMAP_RO_REG(addr);
- break;
-
- case 0x10: /* IPGENERICOCPSPL_SYSCONFIG */
- if (value & (1 << 1)) /* SOFTRESET */
- omap2_gpif_reset(DEVICE(s));
- s->autoidle = value & 1;
- break;
-
- case 0x40: /* IPGENERICOCPSPL_GPO */
- s->gpo = value & 1;
- break;
-
- default:
- OMAP_BAD_REG(addr);
- return;
- }
-}
-
-static const MemoryRegionOps omap2_gpif_top_ops = {
- .read = omap2_gpif_top_read,
- .write = omap2_gpif_top_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int omap_gpio_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- struct omap_gpif_s *s = OMAP1_GPIO(dev);
-
- if (!s->clk) {
- error_report("omap-gpio: clk not connected");
- return -1;
- }
- qdev_init_gpio_in(dev, omap_gpio_set, 16);
- qdev_init_gpio_out(dev, s->omap1.handler, 16);
- sysbus_init_irq(sbd, &s->omap1.irq);
- memory_region_init_io(&s->iomem, OBJECT(s), &omap_gpio_ops, &s->omap1,
- "omap.gpio", 0x1000);
- sysbus_init_mmio(sbd, &s->iomem);
- return 0;
-}
-
-static int omap2_gpio_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- struct omap2_gpif_s *s = OMAP2_GPIO(dev);
- int i;
-
- if (!s->iclk) {
- error_report("omap2-gpio: iclk not connected");
- return -1;
- }
-
- s->modulecount = s->mpu_model < omap2430 ? 4
- : s->mpu_model < omap3430 ? 5
- : 6;
-
- for (i = 0; i < s->modulecount; i++) {
- if (!s->fclk[i]) {
- error_report("omap2-gpio: fclk%d not connected", i);
- return -1;
- }
- }
-
- if (s->mpu_model < omap3430) {
- memory_region_init_io(&s->iomem, OBJECT(s), &omap2_gpif_top_ops, s,
- "omap2.gpio", 0x1000);
- sysbus_init_mmio(sbd, &s->iomem);
- }
-
- s->modules = g_new0(struct omap2_gpio_s, s->modulecount);
- s->handler = g_new0(qemu_irq, s->modulecount * 32);
- qdev_init_gpio_in(dev, omap2_gpio_set, s->modulecount * 32);
- qdev_init_gpio_out(dev, s->handler, s->modulecount * 32);
-
- for (i = 0; i < s->modulecount; i++) {
- struct omap2_gpio_s *m = &s->modules[i];
-
- m->revision = (s->mpu_model < omap3430) ? 0x18 : 0x25;
- m->handler = &s->handler[i * 32];
- sysbus_init_irq(sbd, &m->irq[0]); /* mpu irq */
- sysbus_init_irq(sbd, &m->irq[1]); /* dsp irq */
- sysbus_init_irq(sbd, &m->wkup);
- memory_region_init_io(&m->iomem, OBJECT(s), &omap2_gpio_module_ops, m,
- "omap.gpio-module", 0x1000);
- sysbus_init_mmio(sbd, &m->iomem);
- }
-
- return 0;
-}
-
-/* Using qdev pointer properties for the clocks is not ideal.
- * qdev should support a generic means of defining a 'port' with
- * an arbitrary interface for connecting two devices. Then we
- * could reframe the omap clock API in terms of clock ports,
- * and get some type safety. For now the best qdev provides is
- * passing an arbitrary pointer.
- * (It's not possible to pass in the string which is the clock
- * name, because this device does not have the necessary information
- * (ie the struct omap_mpu_state_s*) to do the clockname to pointer
- * translation.)
- */
-
-static Property omap_gpio_properties[] = {
- DEFINE_PROP_INT32("mpu_model", struct omap_gpif_s, mpu_model, 0),
- DEFINE_PROP_PTR("clk", struct omap_gpif_s, clk),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void omap_gpio_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = omap_gpio_init;
- dc->reset = omap_gpif_reset;
- dc->props = omap_gpio_properties;
- /* Reason: pointer property "clk" */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo omap_gpio_info = {
- .name = TYPE_OMAP1_GPIO,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(struct omap_gpif_s),
- .class_init = omap_gpio_class_init,
-};
-
-static Property omap2_gpio_properties[] = {
- DEFINE_PROP_INT32("mpu_model", struct omap2_gpif_s, mpu_model, 0),
- DEFINE_PROP_PTR("iclk", struct omap2_gpif_s, iclk),
- DEFINE_PROP_PTR("fclk0", struct omap2_gpif_s, fclk[0]),
- DEFINE_PROP_PTR("fclk1", struct omap2_gpif_s, fclk[1]),
- DEFINE_PROP_PTR("fclk2", struct omap2_gpif_s, fclk[2]),
- DEFINE_PROP_PTR("fclk3", struct omap2_gpif_s, fclk[3]),
- DEFINE_PROP_PTR("fclk4", struct omap2_gpif_s, fclk[4]),
- DEFINE_PROP_PTR("fclk5", struct omap2_gpif_s, fclk[5]),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void omap2_gpio_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = omap2_gpio_init;
- dc->reset = omap2_gpif_reset;
- dc->props = omap2_gpio_properties;
- /* Reason: pointer properties "iclk", "fclk0", ..., "fclk5" */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo omap2_gpio_info = {
- .name = TYPE_OMAP2_GPIO,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(struct omap2_gpif_s),
- .class_init = omap2_gpio_class_init,
-};
-
-static void omap_gpio_register_types(void)
-{
- type_register_static(&omap_gpio_info);
- type_register_static(&omap2_gpio_info);
-}
-
-type_init(omap_gpio_register_types)
diff --git a/qemu/hw/gpio/pl061.c b/qemu/hw/gpio/pl061.c
deleted file mode 100644
index 29dc7fc38..000000000
--- a/qemu/hw/gpio/pl061.c
+++ /dev/null
@@ -1,403 +0,0 @@
-/*
- * Arm PrimeCell PL061 General Purpose IO with additional
- * Luminary Micro Stellaris bits.
- *
- * Copyright (c) 2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-
-//#define DEBUG_PL061 1
-
-#ifdef DEBUG_PL061
-#define DPRINTF(fmt, ...) \
-do { printf("pl061: " fmt , ## __VA_ARGS__); } while (0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "pl061: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "pl061: error: " fmt , ## __VA_ARGS__);} while (0)
-#endif
-
-static const uint8_t pl061_id[12] =
- { 0x00, 0x00, 0x00, 0x00, 0x61, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
-static const uint8_t pl061_id_luminary[12] =
- { 0x00, 0x00, 0x00, 0x00, 0x61, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 };
-
-#define TYPE_PL061 "pl061"
-#define PL061(obj) OBJECT_CHECK(PL061State, (obj), TYPE_PL061)
-
-typedef struct PL061State {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- uint32_t locked;
- uint32_t data;
- uint32_t old_out_data;
- uint32_t old_in_data;
- uint32_t dir;
- uint32_t isense;
- uint32_t ibe;
- uint32_t iev;
- uint32_t im;
- uint32_t istate;
- uint32_t afsel;
- uint32_t dr2r;
- uint32_t dr4r;
- uint32_t dr8r;
- uint32_t odr;
- uint32_t pur;
- uint32_t pdr;
- uint32_t slr;
- uint32_t den;
- uint32_t cr;
- uint32_t amsel;
- qemu_irq irq;
- qemu_irq out[8];
- const unsigned char *id;
- uint32_t rsvd_start; /* reserved area: [rsvd_start, 0xfcc] */
-} PL061State;
-
-static const VMStateDescription vmstate_pl061 = {
- .name = "pl061",
- .version_id = 4,
- .minimum_version_id = 4,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(locked, PL061State),
- VMSTATE_UINT32(data, PL061State),
- VMSTATE_UINT32(old_out_data, PL061State),
- VMSTATE_UINT32(old_in_data, PL061State),
- VMSTATE_UINT32(dir, PL061State),
- VMSTATE_UINT32(isense, PL061State),
- VMSTATE_UINT32(ibe, PL061State),
- VMSTATE_UINT32(iev, PL061State),
- VMSTATE_UINT32(im, PL061State),
- VMSTATE_UINT32(istate, PL061State),
- VMSTATE_UINT32(afsel, PL061State),
- VMSTATE_UINT32(dr2r, PL061State),
- VMSTATE_UINT32(dr4r, PL061State),
- VMSTATE_UINT32(dr8r, PL061State),
- VMSTATE_UINT32(odr, PL061State),
- VMSTATE_UINT32(pur, PL061State),
- VMSTATE_UINT32(pdr, PL061State),
- VMSTATE_UINT32(slr, PL061State),
- VMSTATE_UINT32(den, PL061State),
- VMSTATE_UINT32(cr, PL061State),
- VMSTATE_UINT32_V(amsel, PL061State, 2),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void pl061_update(PL061State *s)
-{
- uint8_t changed;
- uint8_t mask;
- uint8_t out;
- int i;
-
- DPRINTF("dir = %d, data = %d\n", s->dir, s->data);
-
- /* Outputs float high. */
- /* FIXME: This is board dependent. */
- out = (s->data & s->dir) | ~s->dir;
- changed = s->old_out_data ^ out;
- if (changed) {
- s->old_out_data = out;
- for (i = 0; i < 8; i++) {
- mask = 1 << i;
- if (changed & mask) {
- DPRINTF("Set output %d = %d\n", i, (out & mask) != 0);
- qemu_set_irq(s->out[i], (out & mask) != 0);
- }
- }
- }
-
- /* Inputs */
- changed = (s->old_in_data ^ s->data) & ~s->dir;
- if (changed) {
- s->old_in_data = s->data;
- for (i = 0; i < 8; i++) {
- mask = 1 << i;
- if (changed & mask) {
- DPRINTF("Changed input %d = %d\n", i, (s->data & mask) != 0);
-
- if (!(s->isense & mask)) {
- /* Edge interrupt */
- if (s->ibe & mask) {
- /* Any edge triggers the interrupt */
- s->istate |= mask;
- } else {
- /* Edge is selected by IEV */
- s->istate |= ~(s->data ^ s->iev) & mask;
- }
- }
- }
- }
- }
-
- /* Level interrupt */
- s->istate |= ~(s->data ^ s->iev) & s->isense;
-
- DPRINTF("istate = %02X\n", s->istate);
-
- qemu_set_irq(s->irq, (s->istate & s->im) != 0);
-}
-
-static uint64_t pl061_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- PL061State *s = (PL061State *)opaque;
-
- if (offset < 0x400) {
- return s->data & (offset >> 2);
- }
- if (offset >= s->rsvd_start && offset <= 0xfcc) {
- goto err_out;
- }
- if (offset >= 0xfd0 && offset < 0x1000) {
- return s->id[(offset - 0xfd0) >> 2];
- }
- switch (offset) {
- case 0x400: /* Direction */
- return s->dir;
- case 0x404: /* Interrupt sense */
- return s->isense;
- case 0x408: /* Interrupt both edges */
- return s->ibe;
- case 0x40c: /* Interrupt event */
- return s->iev;
- case 0x410: /* Interrupt mask */
- return s->im;
- case 0x414: /* Raw interrupt status */
- return s->istate;
- case 0x418: /* Masked interrupt status */
- return s->istate & s->im;
- case 0x420: /* Alternate function select */
- return s->afsel;
- case 0x500: /* 2mA drive */
- return s->dr2r;
- case 0x504: /* 4mA drive */
- return s->dr4r;
- case 0x508: /* 8mA drive */
- return s->dr8r;
- case 0x50c: /* Open drain */
- return s->odr;
- case 0x510: /* Pull-up */
- return s->pur;
- case 0x514: /* Pull-down */
- return s->pdr;
- case 0x518: /* Slew rate control */
- return s->slr;
- case 0x51c: /* Digital enable */
- return s->den;
- case 0x520: /* Lock */
- return s->locked;
- case 0x524: /* Commit */
- return s->cr;
- case 0x528: /* Analog mode select */
- return s->amsel;
- default:
- break;
- }
-err_out:
- qemu_log_mask(LOG_GUEST_ERROR,
- "pl061_read: Bad offset %x\n", (int)offset);
- return 0;
-}
-
-static void pl061_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PL061State *s = (PL061State *)opaque;
- uint8_t mask;
-
- if (offset < 0x400) {
- mask = (offset >> 2) & s->dir;
- s->data = (s->data & ~mask) | (value & mask);
- pl061_update(s);
- return;
- }
- if (offset >= s->rsvd_start) {
- goto err_out;
- }
- switch (offset) {
- case 0x400: /* Direction */
- s->dir = value & 0xff;
- break;
- case 0x404: /* Interrupt sense */
- s->isense = value & 0xff;
- break;
- case 0x408: /* Interrupt both edges */
- s->ibe = value & 0xff;
- break;
- case 0x40c: /* Interrupt event */
- s->iev = value & 0xff;
- break;
- case 0x410: /* Interrupt mask */
- s->im = value & 0xff;
- break;
- case 0x41c: /* Interrupt clear */
- s->istate &= ~value;
- break;
- case 0x420: /* Alternate function select */
- mask = s->cr;
- s->afsel = (s->afsel & ~mask) | (value & mask);
- break;
- case 0x500: /* 2mA drive */
- s->dr2r = value & 0xff;
- break;
- case 0x504: /* 4mA drive */
- s->dr4r = value & 0xff;
- break;
- case 0x508: /* 8mA drive */
- s->dr8r = value & 0xff;
- break;
- case 0x50c: /* Open drain */
- s->odr = value & 0xff;
- break;
- case 0x510: /* Pull-up */
- s->pur = value & 0xff;
- break;
- case 0x514: /* Pull-down */
- s->pdr = value & 0xff;
- break;
- case 0x518: /* Slew rate control */
- s->slr = value & 0xff;
- break;
- case 0x51c: /* Digital enable */
- s->den = value & 0xff;
- break;
- case 0x520: /* Lock */
- s->locked = (value != 0xacce551);
- break;
- case 0x524: /* Commit */
- if (!s->locked)
- s->cr = value & 0xff;
- break;
- case 0x528:
- s->amsel = value & 0xff;
- break;
- default:
- goto err_out;
- }
- pl061_update(s);
- return;
-err_out:
- qemu_log_mask(LOG_GUEST_ERROR,
- "pl061_write: Bad offset %x\n", (int)offset);
-}
-
-static void pl061_reset(DeviceState *dev)
-{
- PL061State *s = PL061(dev);
-
- /* reset values from PL061 TRM, Stellaris LM3S5P31 & LM3S8962 Data Sheet */
- s->data = 0;
- s->old_out_data = 0;
- s->old_in_data = 0;
- s->dir = 0;
- s->isense = 0;
- s->ibe = 0;
- s->iev = 0;
- s->im = 0;
- s->istate = 0;
- s->afsel = 0;
- s->dr2r = 0xff;
- s->dr4r = 0;
- s->dr8r = 0;
- s->odr = 0;
- s->pur = 0;
- s->pdr = 0;
- s->slr = 0;
- s->den = 0;
- s->locked = 1;
- s->cr = 0xff;
- s->amsel = 0;
-}
-
-static void pl061_set_irq(void * opaque, int irq, int level)
-{
- PL061State *s = (PL061State *)opaque;
- uint8_t mask;
-
- mask = 1 << irq;
- if ((s->dir & mask) == 0) {
- s->data &= ~mask;
- if (level)
- s->data |= mask;
- pl061_update(s);
- }
-}
-
-static const MemoryRegionOps pl061_ops = {
- .read = pl061_read,
- .write = pl061_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int pl061_initfn(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- PL061State *s = PL061(dev);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &pl061_ops, s, "pl061", 0x1000);
- sysbus_init_mmio(sbd, &s->iomem);
- sysbus_init_irq(sbd, &s->irq);
- qdev_init_gpio_in(dev, pl061_set_irq, 8);
- qdev_init_gpio_out(dev, s->out, 8);
-
- return 0;
-}
-
-static void pl061_luminary_init(Object *obj)
-{
- PL061State *s = PL061(obj);
-
- s->id = pl061_id_luminary;
- s->rsvd_start = 0x52c;
-}
-
-static void pl061_init(Object *obj)
-{
- PL061State *s = PL061(obj);
-
- s->id = pl061_id;
- s->rsvd_start = 0x424;
-}
-
-static void pl061_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = pl061_initfn;
- dc->vmsd = &vmstate_pl061;
- dc->reset = &pl061_reset;
-}
-
-static const TypeInfo pl061_info = {
- .name = TYPE_PL061,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PL061State),
- .instance_init = pl061_init,
- .class_init = pl061_class_init,
-};
-
-static const TypeInfo pl061_luminary_info = {
- .name = "pl061_luminary",
- .parent = TYPE_PL061,
- .instance_init = pl061_luminary_init,
-};
-
-static void pl061_register_types(void)
-{
- type_register_static(&pl061_info);
- type_register_static(&pl061_luminary_info);
-}
-
-type_init(pl061_register_types)
diff --git a/qemu/hw/gpio/puv3_gpio.c b/qemu/hw/gpio/puv3_gpio.c
deleted file mode 100644
index 445afccf9..000000000
--- a/qemu/hw/gpio/puv3_gpio.c
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * GPIO device simulation in PKUnity SoC
- *
- * Copyright (C) 2010-2012 Guan Xuetao
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation, or any later version.
- * See the COPYING file in the top-level directory.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-
-#undef DEBUG_PUV3
-#include "hw/unicore32/puv3.h"
-
-#define TYPE_PUV3_GPIO "puv3_gpio"
-#define PUV3_GPIO(obj) OBJECT_CHECK(PUV3GPIOState, (obj), TYPE_PUV3_GPIO)
-
-typedef struct PUV3GPIOState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- qemu_irq irq[9];
-
- uint32_t reg_GPLR;
- uint32_t reg_GPDR;
- uint32_t reg_GPIR;
-} PUV3GPIOState;
-
-static uint64_t puv3_gpio_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- PUV3GPIOState *s = opaque;
- uint32_t ret = 0;
-
- switch (offset) {
- case 0x00:
- ret = s->reg_GPLR;
- break;
- case 0x04:
- ret = s->reg_GPDR;
- break;
- case 0x20:
- ret = s->reg_GPIR;
- break;
- default:
- DPRINTF("Bad offset 0x%x\n", offset);
- }
- DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
-
- return ret;
-}
-
-static void puv3_gpio_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PUV3GPIOState *s = opaque;
-
- DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
- switch (offset) {
- case 0x04:
- s->reg_GPDR = value;
- break;
- case 0x08:
- if (s->reg_GPDR & value) {
- s->reg_GPLR |= value;
- } else {
- DPRINTF("Write gpio input port error!");
- }
- break;
- case 0x0c:
- if (s->reg_GPDR & value) {
- s->reg_GPLR &= ~value;
- } else {
- DPRINTF("Write gpio input port error!");
- }
- break;
- case 0x10: /* GRER */
- case 0x14: /* GFER */
- case 0x18: /* GEDR */
- break;
- case 0x20: /* GPIR */
- s->reg_GPIR = value;
- break;
- default:
- DPRINTF("Bad offset 0x%x\n", offset);
- }
-}
-
-static const MemoryRegionOps puv3_gpio_ops = {
- .read = puv3_gpio_read,
- .write = puv3_gpio_write,
- .impl = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int puv3_gpio_init(SysBusDevice *dev)
-{
- PUV3GPIOState *s = PUV3_GPIO(dev);
-
- s->reg_GPLR = 0;
- s->reg_GPDR = 0;
-
- /* FIXME: these irqs not handled yet */
- sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW0]);
- sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW1]);
- sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW2]);
- sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW3]);
- sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW4]);
- sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW5]);
- sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW6]);
- sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW7]);
- sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOHIGH]);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &puv3_gpio_ops, s, "puv3_gpio",
- PUV3_REGS_OFFSET);
- sysbus_init_mmio(dev, &s->iomem);
-
- return 0;
-}
-
-static void puv3_gpio_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
- sdc->init = puv3_gpio_init;
-}
-
-static const TypeInfo puv3_gpio_info = {
- .name = TYPE_PUV3_GPIO,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PUV3GPIOState),
- .class_init = puv3_gpio_class_init,
-};
-
-static void puv3_gpio_register_type(void)
-{
- type_register_static(&puv3_gpio_info);
-}
-
-type_init(puv3_gpio_register_type)
diff --git a/qemu/hw/gpio/zaurus.c b/qemu/hw/gpio/zaurus.c
deleted file mode 100644
index 555da281c..000000000
--- a/qemu/hw/gpio/zaurus.c
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * Copyright (c) 2006-2008 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/arm/sharpsl.h"
-#include "hw/sysbus.h"
-
-#undef REG_FMT
-#define REG_FMT "0x%02lx"
-
-/* SCOOP devices */
-
-#define TYPE_SCOOP "scoop"
-#define SCOOP(obj) OBJECT_CHECK(ScoopInfo, (obj), TYPE_SCOOP)
-
-typedef struct ScoopInfo ScoopInfo;
-struct ScoopInfo {
- SysBusDevice parent_obj;
-
- qemu_irq handler[16];
- MemoryRegion iomem;
- uint16_t status;
- uint16_t power;
- uint32_t gpio_level;
- uint32_t gpio_dir;
- uint32_t prev_level;
-
- uint16_t mcr;
- uint16_t cdr;
- uint16_t ccr;
- uint16_t irr;
- uint16_t imr;
- uint16_t isr;
-};
-
-#define SCOOP_MCR 0x00
-#define SCOOP_CDR 0x04
-#define SCOOP_CSR 0x08
-#define SCOOP_CPR 0x0c
-#define SCOOP_CCR 0x10
-#define SCOOP_IRR_IRM 0x14
-#define SCOOP_IMR 0x18
-#define SCOOP_ISR 0x1c
-#define SCOOP_GPCR 0x20
-#define SCOOP_GPWR 0x24
-#define SCOOP_GPRR 0x28
-
-static inline void scoop_gpio_handler_update(ScoopInfo *s) {
- uint32_t level, diff;
- int bit;
- level = s->gpio_level & s->gpio_dir;
-
- for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) {
- bit = ctz32(diff);
- qemu_set_irq(s->handler[bit], (level >> bit) & 1);
- }
-
- s->prev_level = level;
-}
-
-static uint64_t scoop_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- ScoopInfo *s = (ScoopInfo *) opaque;
-
- switch (addr & 0x3f) {
- case SCOOP_MCR:
- return s->mcr;
- case SCOOP_CDR:
- return s->cdr;
- case SCOOP_CSR:
- return s->status;
- case SCOOP_CPR:
- return s->power;
- case SCOOP_CCR:
- return s->ccr;
- case SCOOP_IRR_IRM:
- return s->irr;
- case SCOOP_IMR:
- return s->imr;
- case SCOOP_ISR:
- return s->isr;
- case SCOOP_GPCR:
- return s->gpio_dir;
- case SCOOP_GPWR:
- case SCOOP_GPRR:
- return s->gpio_level;
- default:
- zaurus_printf("Bad register offset " REG_FMT "\n", (unsigned long)addr);
- }
-
- return 0;
-}
-
-static void scoop_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- ScoopInfo *s = (ScoopInfo *) opaque;
- value &= 0xffff;
-
- switch (addr & 0x3f) {
- case SCOOP_MCR:
- s->mcr = value;
- break;
- case SCOOP_CDR:
- s->cdr = value;
- break;
- case SCOOP_CPR:
- s->power = value;
- if (value & 0x80)
- s->power |= 0x8040;
- break;
- case SCOOP_CCR:
- s->ccr = value;
- break;
- case SCOOP_IRR_IRM:
- s->irr = value;
- break;
- case SCOOP_IMR:
- s->imr = value;
- break;
- case SCOOP_ISR:
- s->isr = value;
- break;
- case SCOOP_GPCR:
- s->gpio_dir = value;
- scoop_gpio_handler_update(s);
- break;
- case SCOOP_GPWR:
- case SCOOP_GPRR: /* GPRR is probably R/O in real HW */
- s->gpio_level = value & s->gpio_dir;
- scoop_gpio_handler_update(s);
- break;
- default:
- zaurus_printf("Bad register offset " REG_FMT "\n", (unsigned long)addr);
- }
-}
-
-static const MemoryRegionOps scoop_ops = {
- .read = scoop_read,
- .write = scoop_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void scoop_gpio_set(void *opaque, int line, int level)
-{
- ScoopInfo *s = (ScoopInfo *) opaque;
-
- if (level)
- s->gpio_level |= (1 << line);
- else
- s->gpio_level &= ~(1 << line);
-}
-
-static int scoop_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- ScoopInfo *s = SCOOP(dev);
-
- s->status = 0x02;
- qdev_init_gpio_out(dev, s->handler, 16);
- qdev_init_gpio_in(dev, scoop_gpio_set, 16);
- memory_region_init_io(&s->iomem, OBJECT(s), &scoop_ops, s, "scoop", 0x1000);
-
- sysbus_init_mmio(sbd, &s->iomem);
-
- return 0;
-}
-
-static int scoop_post_load(void *opaque, int version_id)
-{
- ScoopInfo *s = (ScoopInfo *) opaque;
- int i;
- uint32_t level;
-
- level = s->gpio_level & s->gpio_dir;
-
- for (i = 0; i < 16; i++) {
- qemu_set_irq(s->handler[i], (level >> i) & 1);
- }
-
- s->prev_level = level;
-
- return 0;
-}
-
-static bool is_version_0 (void *opaque, int version_id)
-{
- return version_id == 0;
-}
-
-static bool vmstate_scoop_validate(void *opaque, int version_id)
-{
- ScoopInfo *s = opaque;
-
- return !(s->prev_level & 0xffff0000) &&
- !(s->gpio_level & 0xffff0000) &&
- !(s->gpio_dir & 0xffff0000);
-}
-
-static const VMStateDescription vmstate_scoop_regs = {
- .name = "scoop",
- .version_id = 1,
- .minimum_version_id = 0,
- .post_load = scoop_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT16(status, ScoopInfo),
- VMSTATE_UINT16(power, ScoopInfo),
- VMSTATE_UINT32(gpio_level, ScoopInfo),
- VMSTATE_UINT32(gpio_dir, ScoopInfo),
- VMSTATE_UINT32(prev_level, ScoopInfo),
- VMSTATE_VALIDATE("irq levels are 16 bit", vmstate_scoop_validate),
- VMSTATE_UINT16(mcr, ScoopInfo),
- VMSTATE_UINT16(cdr, ScoopInfo),
- VMSTATE_UINT16(ccr, ScoopInfo),
- VMSTATE_UINT16(irr, ScoopInfo),
- VMSTATE_UINT16(imr, ScoopInfo),
- VMSTATE_UINT16(isr, ScoopInfo),
- VMSTATE_UNUSED_TEST(is_version_0, 2),
- VMSTATE_END_OF_LIST(),
- },
-};
-
-static void scoop_sysbus_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = scoop_init;
- dc->desc = "Scoop2 Sharp custom ASIC";
- dc->vmsd = &vmstate_scoop_regs;
-}
-
-static const TypeInfo scoop_sysbus_info = {
- .name = TYPE_SCOOP,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(ScoopInfo),
- .class_init = scoop_sysbus_class_init,
-};
-
-static void scoop_register_types(void)
-{
- type_register_static(&scoop_sysbus_info);
-}
-
-type_init(scoop_register_types)
-
-/* Write the bootloader parameters memory area. */
-
-#define MAGIC_CHG(a, b, c, d) ((d << 24) | (c << 16) | (b << 8) | a)
-
-static struct QEMU_PACKED sl_param_info {
- uint32_t comadj_keyword;
- int32_t comadj;
-
- uint32_t uuid_keyword;
- char uuid[16];
-
- uint32_t touch_keyword;
- int32_t touch_xp;
- int32_t touch_yp;
- int32_t touch_xd;
- int32_t touch_yd;
-
- uint32_t adadj_keyword;
- int32_t adadj;
-
- uint32_t phad_keyword;
- int32_t phadadj;
-} zaurus_bootparam = {
- .comadj_keyword = MAGIC_CHG('C', 'M', 'A', 'D'),
- .comadj = 125,
- .uuid_keyword = MAGIC_CHG('U', 'U', 'I', 'D'),
- .uuid = { -1 },
- .touch_keyword = MAGIC_CHG('T', 'U', 'C', 'H'),
- .touch_xp = -1,
- .adadj_keyword = MAGIC_CHG('B', 'V', 'A', 'D'),
- .adadj = -1,
- .phad_keyword = MAGIC_CHG('P', 'H', 'A', 'D'),
- .phadadj = 0x01,
-};
-
-void sl_bootparam_write(hwaddr ptr)
-{
- cpu_physical_memory_write(ptr, &zaurus_bootparam,
- sizeof(struct sl_param_info));
-}
diff --git a/qemu/hw/i2c/Makefile.objs b/qemu/hw/i2c/Makefile.objs
deleted file mode 100644
index aeb8f38d7..000000000
--- a/qemu/hw/i2c/Makefile.objs
+++ /dev/null
@@ -1,8 +0,0 @@
-common-obj-y += core.o smbus.o smbus_eeprom.o
-common-obj-$(CONFIG_VERSATILE_I2C) += versatile_i2c.o
-common-obj-$(CONFIG_ACPI_X86) += smbus_ich9.o
-common-obj-$(CONFIG_APM) += pm_smbus.o
-common-obj-$(CONFIG_BITBANG_I2C) += bitbang_i2c.o
-common-obj-$(CONFIG_EXYNOS4) += exynos4210_i2c.o
-common-obj-$(CONFIG_IMX_I2C) += imx_i2c.o
-obj-$(CONFIG_OMAP) += omap_i2c.o
diff --git a/qemu/hw/i2c/bitbang_i2c.c b/qemu/hw/i2c/bitbang_i2c.c
deleted file mode 100644
index 6ed206020..000000000
--- a/qemu/hw/i2c/bitbang_i2c.c
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
- * Bit-Bang i2c emulation extracted from
- * Marvell MV88W8618 / Freecom MusicPal emulation.
- *
- * Copyright (c) 2008 Jan Kiszka
- *
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "bitbang_i2c.h"
-#include "hw/sysbus.h"
-
-//#define DEBUG_BITBANG_I2C
-
-#ifdef DEBUG_BITBANG_I2C
-#define DPRINTF(fmt, ...) \
-do { printf("bitbang_i2c: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#endif
-
-typedef enum bitbang_i2c_state {
- STOPPED = 0,
- SENDING_BIT7,
- SENDING_BIT6,
- SENDING_BIT5,
- SENDING_BIT4,
- SENDING_BIT3,
- SENDING_BIT2,
- SENDING_BIT1,
- SENDING_BIT0,
- WAITING_FOR_ACK,
- RECEIVING_BIT7,
- RECEIVING_BIT6,
- RECEIVING_BIT5,
- RECEIVING_BIT4,
- RECEIVING_BIT3,
- RECEIVING_BIT2,
- RECEIVING_BIT1,
- RECEIVING_BIT0,
- SENDING_ACK,
- SENT_NACK
-} bitbang_i2c_state;
-
-struct bitbang_i2c_interface {
- I2CBus *bus;
- bitbang_i2c_state state;
- int last_data;
- int last_clock;
- int device_out;
- uint8_t buffer;
- int current_addr;
-};
-
-static void bitbang_i2c_enter_stop(bitbang_i2c_interface *i2c)
-{
- DPRINTF("STOP\n");
- if (i2c->current_addr >= 0)
- i2c_end_transfer(i2c->bus);
- i2c->current_addr = -1;
- i2c->state = STOPPED;
-}
-
-/* Set device data pin. */
-static int bitbang_i2c_ret(bitbang_i2c_interface *i2c, int level)
-{
- i2c->device_out = level;
- //DPRINTF("%d %d %d\n", i2c->last_clock, i2c->last_data, i2c->device_out);
- return level & i2c->last_data;
-}
-
-/* Leave device data pin unodified. */
-static int bitbang_i2c_nop(bitbang_i2c_interface *i2c)
-{
- return bitbang_i2c_ret(i2c, i2c->device_out);
-}
-
-/* Returns data line level. */
-int bitbang_i2c_set(bitbang_i2c_interface *i2c, int line, int level)
-{
- int data;
-
- if (level != 0 && level != 1) {
- abort();
- }
-
- if (line == BITBANG_I2C_SDA) {
- if (level == i2c->last_data) {
- return bitbang_i2c_nop(i2c);
- }
- i2c->last_data = level;
- if (i2c->last_clock == 0) {
- return bitbang_i2c_nop(i2c);
- }
- if (level == 0) {
- DPRINTF("START\n");
- /* START condition. */
- i2c->state = SENDING_BIT7;
- i2c->current_addr = -1;
- } else {
- /* STOP condition. */
- bitbang_i2c_enter_stop(i2c);
- }
- return bitbang_i2c_ret(i2c, 1);
- }
-
- data = i2c->last_data;
- if (i2c->last_clock == level) {
- return bitbang_i2c_nop(i2c);
- }
- i2c->last_clock = level;
- if (level == 0) {
- /* State is set/read at the start of the clock pulse.
- release the data line at the end. */
- return bitbang_i2c_ret(i2c, 1);
- }
- switch (i2c->state) {
- case STOPPED:
- case SENT_NACK:
- return bitbang_i2c_ret(i2c, 1);
-
- case SENDING_BIT7 ... SENDING_BIT0:
- i2c->buffer = (i2c->buffer << 1) | data;
- /* will end up in WAITING_FOR_ACK */
- i2c->state++;
- return bitbang_i2c_ret(i2c, 1);
-
- case WAITING_FOR_ACK:
- if (i2c->current_addr < 0) {
- i2c->current_addr = i2c->buffer;
- DPRINTF("Address 0x%02x\n", i2c->current_addr);
- i2c_start_transfer(i2c->bus, i2c->current_addr >> 1,
- i2c->current_addr & 1);
- } else {
- DPRINTF("Sent 0x%02x\n", i2c->buffer);
- i2c_send(i2c->bus, i2c->buffer);
- }
- if (i2c->current_addr & 1) {
- i2c->state = RECEIVING_BIT7;
- } else {
- i2c->state = SENDING_BIT7;
- }
- return bitbang_i2c_ret(i2c, 0);
-
- case RECEIVING_BIT7:
- i2c->buffer = i2c_recv(i2c->bus);
- DPRINTF("RX byte 0x%02x\n", i2c->buffer);
- /* Fall through... */
- case RECEIVING_BIT6 ... RECEIVING_BIT0:
- data = i2c->buffer >> 7;
- /* will end up in SENDING_ACK */
- i2c->state++;
- i2c->buffer <<= 1;
- return bitbang_i2c_ret(i2c, data);
-
- case SENDING_ACK:
- i2c->state = RECEIVING_BIT7;
- if (data != 0) {
- DPRINTF("NACKED\n");
- i2c->state = SENT_NACK;
- i2c_nack(i2c->bus);
- } else {
- DPRINTF("ACKED\n");
- }
- return bitbang_i2c_ret(i2c, 1);
- }
- abort();
-}
-
-bitbang_i2c_interface *bitbang_i2c_init(I2CBus *bus)
-{
- bitbang_i2c_interface *s;
-
- s = g_malloc0(sizeof(bitbang_i2c_interface));
-
- s->bus = bus;
- s->last_data = 1;
- s->last_clock = 1;
- s->device_out = 1;
-
- return s;
-}
-
-/* GPIO interface. */
-
-#define TYPE_GPIO_I2C "gpio_i2c"
-#define GPIO_I2C(obj) OBJECT_CHECK(GPIOI2CState, (obj), TYPE_GPIO_I2C)
-
-typedef struct GPIOI2CState {
- SysBusDevice parent_obj;
-
- MemoryRegion dummy_iomem;
- bitbang_i2c_interface *bitbang;
- int last_level;
- qemu_irq out;
-} GPIOI2CState;
-
-static void bitbang_i2c_gpio_set(void *opaque, int irq, int level)
-{
- GPIOI2CState *s = opaque;
-
- level = bitbang_i2c_set(s->bitbang, irq, level);
- if (level != s->last_level) {
- s->last_level = level;
- qemu_set_irq(s->out, level);
- }
-}
-
-static int gpio_i2c_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- GPIOI2CState *s = GPIO_I2C(dev);
- I2CBus *bus;
-
- memory_region_init(&s->dummy_iomem, OBJECT(s), "gpio_i2c", 0);
- sysbus_init_mmio(sbd, &s->dummy_iomem);
-
- bus = i2c_init_bus(dev, "i2c");
- s->bitbang = bitbang_i2c_init(bus);
-
- qdev_init_gpio_in(dev, bitbang_i2c_gpio_set, 2);
- qdev_init_gpio_out(dev, &s->out, 1);
-
- return 0;
-}
-
-static void gpio_i2c_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = gpio_i2c_init;
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
- dc->desc = "Virtual GPIO to I2C bridge";
-}
-
-static const TypeInfo gpio_i2c_info = {
- .name = TYPE_GPIO_I2C,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(GPIOI2CState),
- .class_init = gpio_i2c_class_init,
-};
-
-static void bitbang_i2c_register_types(void)
-{
- type_register_static(&gpio_i2c_info);
-}
-
-type_init(bitbang_i2c_register_types)
diff --git a/qemu/hw/i2c/bitbang_i2c.h b/qemu/hw/i2c/bitbang_i2c.h
deleted file mode 100644
index 3a7126d5d..000000000
--- a/qemu/hw/i2c/bitbang_i2c.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef BITBANG_I2C_H
-#define BITBANG_I2C_H
-
-#include "hw/i2c/i2c.h"
-
-typedef struct bitbang_i2c_interface bitbang_i2c_interface;
-
-#define BITBANG_I2C_SDA 0
-#define BITBANG_I2C_SCL 1
-
-bitbang_i2c_interface *bitbang_i2c_init(I2CBus *bus);
-int bitbang_i2c_set(bitbang_i2c_interface *i2c, int line, int level);
-
-#endif
diff --git a/qemu/hw/i2c/core.c b/qemu/hw/i2c/core.c
deleted file mode 100644
index ba22104af..000000000
--- a/qemu/hw/i2c/core.c
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * QEMU I2C bus interface.
- *
- * Copyright (c) 2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the LGPL.
- */
-
-#include "qemu/osdep.h"
-#include "hw/i2c/i2c.h"
-
-struct I2CBus
-{
- BusState qbus;
- I2CSlave *current_dev;
- I2CSlave *dev;
- uint8_t saved_address;
-};
-
-static Property i2c_props[] = {
- DEFINE_PROP_UINT8("address", struct I2CSlave, address, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-#define TYPE_I2C_BUS "i2c-bus"
-#define I2C_BUS(obj) OBJECT_CHECK(I2CBus, (obj), TYPE_I2C_BUS)
-
-static const TypeInfo i2c_bus_info = {
- .name = TYPE_I2C_BUS,
- .parent = TYPE_BUS,
- .instance_size = sizeof(I2CBus),
-};
-
-static void i2c_bus_pre_save(void *opaque)
-{
- I2CBus *bus = opaque;
-
- bus->saved_address = bus->current_dev ? bus->current_dev->address : -1;
-}
-
-static int i2c_bus_post_load(void *opaque, int version_id)
-{
- I2CBus *bus = opaque;
-
- /* The bus is loaded before attached devices, so load and save the
- current device id. Devices will check themselves as loaded. */
- bus->current_dev = NULL;
- return 0;
-}
-
-static const VMStateDescription vmstate_i2c_bus = {
- .name = "i2c_bus",
- .version_id = 1,
- .minimum_version_id = 1,
- .pre_save = i2c_bus_pre_save,
- .post_load = i2c_bus_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(saved_address, I2CBus),
- VMSTATE_END_OF_LIST()
- }
-};
-
-/* Create a new I2C bus. */
-I2CBus *i2c_init_bus(DeviceState *parent, const char *name)
-{
- I2CBus *bus;
-
- bus = I2C_BUS(qbus_create(TYPE_I2C_BUS, parent, name));
- vmstate_register(NULL, -1, &vmstate_i2c_bus, bus);
- return bus;
-}
-
-void i2c_set_slave_address(I2CSlave *dev, uint8_t address)
-{
- dev->address = address;
-}
-
-/* Return nonzero if bus is busy. */
-int i2c_bus_busy(I2CBus *bus)
-{
- return bus->current_dev != NULL;
-}
-
-/* Returns non-zero if the address is not valid. */
-/* TODO: Make this handle multiple masters. */
-int i2c_start_transfer(I2CBus *bus, uint8_t address, int recv)
-{
- BusChild *kid;
- I2CSlave *slave = NULL;
- I2CSlaveClass *sc;
-
- QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) {
- DeviceState *qdev = kid->child;
- I2CSlave *candidate = I2C_SLAVE(qdev);
- if (candidate->address == address) {
- slave = candidate;
- break;
- }
- }
-
- if (!slave) {
- return 1;
- }
-
- sc = I2C_SLAVE_GET_CLASS(slave);
- /* If the bus is already busy, assume this is a repeated
- start condition. */
- bus->current_dev = slave;
- if (sc->event) {
- sc->event(slave, recv ? I2C_START_RECV : I2C_START_SEND);
- }
- return 0;
-}
-
-void i2c_end_transfer(I2CBus *bus)
-{
- I2CSlave *dev = bus->current_dev;
- I2CSlaveClass *sc;
-
- if (!dev) {
- return;
- }
-
- sc = I2C_SLAVE_GET_CLASS(dev);
- if (sc->event) {
- sc->event(dev, I2C_FINISH);
- }
-
- bus->current_dev = NULL;
-}
-
-int i2c_send(I2CBus *bus, uint8_t data)
-{
- I2CSlave *dev = bus->current_dev;
- I2CSlaveClass *sc;
-
- if (!dev) {
- return -1;
- }
-
- sc = I2C_SLAVE_GET_CLASS(dev);
- if (sc->send) {
- return sc->send(dev, data);
- }
-
- return -1;
-}
-
-int i2c_recv(I2CBus *bus)
-{
- I2CSlave *dev = bus->current_dev;
- I2CSlaveClass *sc;
-
- if (!dev) {
- return -1;
- }
-
- sc = I2C_SLAVE_GET_CLASS(dev);
- if (sc->recv) {
- return sc->recv(dev);
- }
-
- return -1;
-}
-
-void i2c_nack(I2CBus *bus)
-{
- I2CSlave *dev = bus->current_dev;
- I2CSlaveClass *sc;
-
- if (!dev) {
- return;
- }
-
- sc = I2C_SLAVE_GET_CLASS(dev);
- if (sc->event) {
- sc->event(dev, I2C_NACK);
- }
-}
-
-static int i2c_slave_post_load(void *opaque, int version_id)
-{
- I2CSlave *dev = opaque;
- I2CBus *bus;
- bus = I2C_BUS(qdev_get_parent_bus(DEVICE(dev)));
- if (bus->saved_address == dev->address) {
- bus->current_dev = dev;
- }
- return 0;
-}
-
-const VMStateDescription vmstate_i2c_slave = {
- .name = "I2CSlave",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = i2c_slave_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(address, I2CSlave),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static int i2c_slave_qdev_init(DeviceState *dev)
-{
- I2CSlave *s = I2C_SLAVE(dev);
- I2CSlaveClass *sc = I2C_SLAVE_GET_CLASS(s);
-
- return sc->init(s);
-}
-
-DeviceState *i2c_create_slave(I2CBus *bus, const char *name, uint8_t addr)
-{
- DeviceState *dev;
-
- dev = qdev_create(&bus->qbus, name);
- qdev_prop_set_uint8(dev, "address", addr);
- qdev_init_nofail(dev);
- return dev;
-}
-
-static void i2c_slave_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *k = DEVICE_CLASS(klass);
- k->init = i2c_slave_qdev_init;
- set_bit(DEVICE_CATEGORY_MISC, k->categories);
- k->bus_type = TYPE_I2C_BUS;
- k->props = i2c_props;
-}
-
-static const TypeInfo i2c_slave_type_info = {
- .name = TYPE_I2C_SLAVE,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(I2CSlave),
- .abstract = true,
- .class_size = sizeof(I2CSlaveClass),
- .class_init = i2c_slave_class_init,
-};
-
-static void i2c_slave_register_types(void)
-{
- type_register_static(&i2c_bus_info);
- type_register_static(&i2c_slave_type_info);
-}
-
-type_init(i2c_slave_register_types)
diff --git a/qemu/hw/i2c/exynos4210_i2c.c b/qemu/hw/i2c/exynos4210_i2c.c
deleted file mode 100644
index 8c2a2c163..000000000
--- a/qemu/hw/i2c/exynos4210_i2c.c
+++ /dev/null
@@ -1,337 +0,0 @@
-/*
- * Exynos4210 I2C Bus Serial Interface Emulation
- *
- * Copyright (C) 2012 Samsung Electronics Co Ltd.
- * Maksim Kozlov, <m.kozlov@samsung.com>
- * Igor Mitsyanko, <i.mitsyanko@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "qemu/osdep.h"
-#include "qemu/timer.h"
-#include "hw/sysbus.h"
-#include "hw/i2c/i2c.h"
-
-#ifndef EXYNOS4_I2C_DEBUG
-#define EXYNOS4_I2C_DEBUG 0
-#endif
-
-#define TYPE_EXYNOS4_I2C "exynos4210.i2c"
-#define EXYNOS4_I2C(obj) \
- OBJECT_CHECK(Exynos4210I2CState, (obj), TYPE_EXYNOS4_I2C)
-
-/* Exynos4210 I2C memory map */
-#define EXYNOS4_I2C_MEM_SIZE 0x14
-#define I2CCON_ADDR 0x00 /* control register */
-#define I2CSTAT_ADDR 0x04 /* control/status register */
-#define I2CADD_ADDR 0x08 /* address register */
-#define I2CDS_ADDR 0x0c /* data shift register */
-#define I2CLC_ADDR 0x10 /* line control register */
-
-#define I2CCON_ACK_GEN (1 << 7)
-#define I2CCON_INTRS_EN (1 << 5)
-#define I2CCON_INT_PEND (1 << 4)
-
-#define EXYNOS4_I2C_MODE(reg) (((reg) >> 6) & 3)
-#define I2C_IN_MASTER_MODE(reg) (((reg) >> 6) & 2)
-#define I2CMODE_MASTER_Rx 0x2
-#define I2CMODE_MASTER_Tx 0x3
-#define I2CSTAT_LAST_BIT (1 << 0)
-#define I2CSTAT_OUTPUT_EN (1 << 4)
-#define I2CSTAT_START_BUSY (1 << 5)
-
-
-#if EXYNOS4_I2C_DEBUG
-#define DPRINT(fmt, args...) \
- do { fprintf(stderr, "QEMU I2C: "fmt, ## args); } while (0)
-
-static const char *exynos4_i2c_get_regname(unsigned offset)
-{
- switch (offset) {
- case I2CCON_ADDR:
- return "I2CCON";
- case I2CSTAT_ADDR:
- return "I2CSTAT";
- case I2CADD_ADDR:
- return "I2CADD";
- case I2CDS_ADDR:
- return "I2CDS";
- case I2CLC_ADDR:
- return "I2CLC";
- default:
- return "[?]";
- }
-}
-
-#else
-#define DPRINT(fmt, args...) do { } while (0)
-#endif
-
-typedef struct Exynos4210I2CState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- I2CBus *bus;
- qemu_irq irq;
-
- uint8_t i2ccon;
- uint8_t i2cstat;
- uint8_t i2cadd;
- uint8_t i2cds;
- uint8_t i2clc;
- bool scl_free;
-} Exynos4210I2CState;
-
-static inline void exynos4210_i2c_raise_interrupt(Exynos4210I2CState *s)
-{
- if (s->i2ccon & I2CCON_INTRS_EN) {
- s->i2ccon |= I2CCON_INT_PEND;
- qemu_irq_raise(s->irq);
- }
-}
-
-static void exynos4210_i2c_data_receive(void *opaque)
-{
- Exynos4210I2CState *s = (Exynos4210I2CState *)opaque;
- int ret;
-
- s->i2cstat &= ~I2CSTAT_LAST_BIT;
- s->scl_free = false;
- ret = i2c_recv(s->bus);
- if (ret < 0 && (s->i2ccon & I2CCON_ACK_GEN)) {
- s->i2cstat |= I2CSTAT_LAST_BIT; /* Data is not acknowledged */
- } else {
- s->i2cds = ret;
- }
- exynos4210_i2c_raise_interrupt(s);
-}
-
-static void exynos4210_i2c_data_send(void *opaque)
-{
- Exynos4210I2CState *s = (Exynos4210I2CState *)opaque;
-
- s->i2cstat &= ~I2CSTAT_LAST_BIT;
- s->scl_free = false;
- if (i2c_send(s->bus, s->i2cds) < 0 && (s->i2ccon & I2CCON_ACK_GEN)) {
- s->i2cstat |= I2CSTAT_LAST_BIT;
- }
- exynos4210_i2c_raise_interrupt(s);
-}
-
-static uint64_t exynos4210_i2c_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- Exynos4210I2CState *s = (Exynos4210I2CState *)opaque;
- uint8_t value;
-
- switch (offset) {
- case I2CCON_ADDR:
- value = s->i2ccon;
- break;
- case I2CSTAT_ADDR:
- value = s->i2cstat;
- break;
- case I2CADD_ADDR:
- value = s->i2cadd;
- break;
- case I2CDS_ADDR:
- value = s->i2cds;
- s->scl_free = true;
- if (EXYNOS4_I2C_MODE(s->i2cstat) == I2CMODE_MASTER_Rx &&
- (s->i2cstat & I2CSTAT_START_BUSY) &&
- !(s->i2ccon & I2CCON_INT_PEND)) {
- exynos4210_i2c_data_receive(s);
- }
- break;
- case I2CLC_ADDR:
- value = s->i2clc;
- break;
- default:
- value = 0;
- DPRINT("ERROR: Bad read offset 0x%x\n", (unsigned int)offset);
- break;
- }
-
- DPRINT("read %s [0x%02x] -> 0x%02x\n", exynos4_i2c_get_regname(offset),
- (unsigned int)offset, value);
- return value;
-}
-
-static void exynos4210_i2c_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- Exynos4210I2CState *s = (Exynos4210I2CState *)opaque;
- uint8_t v = value & 0xff;
-
- DPRINT("write %s [0x%02x] <- 0x%02x\n", exynos4_i2c_get_regname(offset),
- (unsigned int)offset, v);
-
- switch (offset) {
- case I2CCON_ADDR:
- s->i2ccon = (v & ~I2CCON_INT_PEND) | (s->i2ccon & I2CCON_INT_PEND);
- if ((s->i2ccon & I2CCON_INT_PEND) && !(v & I2CCON_INT_PEND)) {
- s->i2ccon &= ~I2CCON_INT_PEND;
- qemu_irq_lower(s->irq);
- if (!(s->i2ccon & I2CCON_INTRS_EN)) {
- s->i2cstat &= ~I2CSTAT_START_BUSY;
- }
-
- if (s->i2cstat & I2CSTAT_START_BUSY) {
- if (s->scl_free) {
- if (EXYNOS4_I2C_MODE(s->i2cstat) == I2CMODE_MASTER_Tx) {
- exynos4210_i2c_data_send(s);
- } else if (EXYNOS4_I2C_MODE(s->i2cstat) ==
- I2CMODE_MASTER_Rx) {
- exynos4210_i2c_data_receive(s);
- }
- } else {
- s->i2ccon |= I2CCON_INT_PEND;
- qemu_irq_raise(s->irq);
- }
- }
- }
- break;
- case I2CSTAT_ADDR:
- s->i2cstat =
- (s->i2cstat & I2CSTAT_START_BUSY) | (v & ~I2CSTAT_START_BUSY);
-
- if (!(s->i2cstat & I2CSTAT_OUTPUT_EN)) {
- s->i2cstat &= ~I2CSTAT_START_BUSY;
- s->scl_free = true;
- qemu_irq_lower(s->irq);
- break;
- }
-
- /* Nothing to do if in i2c slave mode */
- if (!I2C_IN_MASTER_MODE(s->i2cstat)) {
- break;
- }
-
- if (v & I2CSTAT_START_BUSY) {
- s->i2cstat &= ~I2CSTAT_LAST_BIT;
- s->i2cstat |= I2CSTAT_START_BUSY; /* Line is busy */
- s->scl_free = false;
-
- /* Generate start bit and send slave address */
- if (i2c_start_transfer(s->bus, s->i2cds >> 1, s->i2cds & 0x1) &&
- (s->i2ccon & I2CCON_ACK_GEN)) {
- s->i2cstat |= I2CSTAT_LAST_BIT;
- } else if (EXYNOS4_I2C_MODE(s->i2cstat) == I2CMODE_MASTER_Rx) {
- exynos4210_i2c_data_receive(s);
- }
- exynos4210_i2c_raise_interrupt(s);
- } else {
- i2c_end_transfer(s->bus);
- if (!(s->i2ccon & I2CCON_INT_PEND)) {
- s->i2cstat &= ~I2CSTAT_START_BUSY;
- }
- s->scl_free = true;
- }
- break;
- case I2CADD_ADDR:
- if ((s->i2cstat & I2CSTAT_OUTPUT_EN) == 0) {
- s->i2cadd = v;
- }
- break;
- case I2CDS_ADDR:
- if (s->i2cstat & I2CSTAT_OUTPUT_EN) {
- s->i2cds = v;
- s->scl_free = true;
- if (EXYNOS4_I2C_MODE(s->i2cstat) == I2CMODE_MASTER_Tx &&
- (s->i2cstat & I2CSTAT_START_BUSY) &&
- !(s->i2ccon & I2CCON_INT_PEND)) {
- exynos4210_i2c_data_send(s);
- }
- }
- break;
- case I2CLC_ADDR:
- s->i2clc = v;
- break;
- default:
- DPRINT("ERROR: Bad write offset 0x%x\n", (unsigned int)offset);
- break;
- }
-}
-
-static const MemoryRegionOps exynos4210_i2c_ops = {
- .read = exynos4210_i2c_read,
- .write = exynos4210_i2c_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription exynos4210_i2c_vmstate = {
- .name = "exynos4210.i2c",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(i2ccon, Exynos4210I2CState),
- VMSTATE_UINT8(i2cstat, Exynos4210I2CState),
- VMSTATE_UINT8(i2cds, Exynos4210I2CState),
- VMSTATE_UINT8(i2cadd, Exynos4210I2CState),
- VMSTATE_UINT8(i2clc, Exynos4210I2CState),
- VMSTATE_BOOL(scl_free, Exynos4210I2CState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void exynos4210_i2c_reset(DeviceState *d)
-{
- Exynos4210I2CState *s = EXYNOS4_I2C(d);
-
- s->i2ccon = 0x00;
- s->i2cstat = 0x00;
- s->i2cds = 0xFF;
- s->i2clc = 0x00;
- s->i2cadd = 0xFF;
- s->scl_free = true;
-}
-
-static int exynos4210_i2c_realize(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- Exynos4210I2CState *s = EXYNOS4_I2C(dev);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &exynos4210_i2c_ops, s,
- TYPE_EXYNOS4_I2C, EXYNOS4_I2C_MEM_SIZE);
- sysbus_init_mmio(sbd, &s->iomem);
- sysbus_init_irq(sbd, &s->irq);
- s->bus = i2c_init_bus(dev, "i2c");
- return 0;
-}
-
-static void exynos4210_i2c_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *sbdc = SYS_BUS_DEVICE_CLASS(klass);
-
- dc->vmsd = &exynos4210_i2c_vmstate;
- dc->reset = exynos4210_i2c_reset;
- sbdc->init = exynos4210_i2c_realize;
-}
-
-static const TypeInfo exynos4210_i2c_type_info = {
- .name = TYPE_EXYNOS4_I2C,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(Exynos4210I2CState),
- .class_init = exynos4210_i2c_class_init,
-};
-
-static void exynos4210_i2c_register_types(void)
-{
- type_register_static(&exynos4210_i2c_type_info);
-}
-
-type_init(exynos4210_i2c_register_types)
diff --git a/qemu/hw/i2c/imx_i2c.c b/qemu/hw/i2c/imx_i2c.c
deleted file mode 100644
index a01e43ebe..000000000
--- a/qemu/hw/i2c/imx_i2c.c
+++ /dev/null
@@ -1,337 +0,0 @@
-/*
- * i.MX I2C Bus Serial Interface Emulation
- *
- * Copyright (C) 2013 Jean-Christophe Dubois. <jcd@tribudubois.net>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "qemu/osdep.h"
-#include "hw/i2c/imx_i2c.h"
-#include "hw/i2c/i2c.h"
-
-#ifndef DEBUG_IMX_I2C
-#define DEBUG_IMX_I2C 0
-#endif
-
-#define DPRINTF(fmt, args...) \
- do { \
- if (DEBUG_IMX_I2C) { \
- fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_I2C, \
- __func__, ##args); \
- } \
- } while (0)
-
-static const char *imx_i2c_get_regname(unsigned offset)
-{
- switch (offset) {
- case IADR_ADDR:
- return "IADR";
- case IFDR_ADDR:
- return "IFDR";
- case I2CR_ADDR:
- return "I2CR";
- case I2SR_ADDR:
- return "I2SR";
- case I2DR_ADDR:
- return "I2DR";
- default:
- return "[?]";
- }
-}
-
-static inline bool imx_i2c_is_enabled(IMXI2CState *s)
-{
- return s->i2cr & I2CR_IEN;
-}
-
-static inline bool imx_i2c_interrupt_is_enabled(IMXI2CState *s)
-{
- return s->i2cr & I2CR_IIEN;
-}
-
-static inline bool imx_i2c_is_master(IMXI2CState *s)
-{
- return s->i2cr & I2CR_MSTA;
-}
-
-static void imx_i2c_reset(DeviceState *dev)
-{
- IMXI2CState *s = IMX_I2C(dev);
-
- if (s->address != ADDR_RESET) {
- i2c_end_transfer(s->bus);
- }
-
- s->address = ADDR_RESET;
- s->iadr = IADR_RESET;
- s->ifdr = IFDR_RESET;
- s->i2cr = I2CR_RESET;
- s->i2sr = I2SR_RESET;
- s->i2dr_read = I2DR_RESET;
- s->i2dr_write = I2DR_RESET;
-}
-
-static inline void imx_i2c_raise_interrupt(IMXI2CState *s)
-{
- /*
- * raise an interrupt if the device is enabled and it is configured
- * to generate some interrupts.
- */
- if (imx_i2c_is_enabled(s) && imx_i2c_interrupt_is_enabled(s)) {
- s->i2sr |= I2SR_IIF;
- qemu_irq_raise(s->irq);
- }
-}
-
-static uint64_t imx_i2c_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- uint16_t value;
- IMXI2CState *s = IMX_I2C(opaque);
-
- switch (offset) {
- case IADR_ADDR:
- value = s->iadr;
- break;
- case IFDR_ADDR:
- value = s->ifdr;
- break;
- case I2CR_ADDR:
- value = s->i2cr;
- break;
- case I2SR_ADDR:
- value = s->i2sr;
- break;
- case I2DR_ADDR:
- value = s->i2dr_read;
-
- if (imx_i2c_is_master(s)) {
- int ret = 0xff;
-
- if (s->address == ADDR_RESET) {
- /* something is wrong as the address is not set */
- qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Trying to read "
- "without specifying the slave address\n",
- TYPE_IMX_I2C, __func__);
- } else if (s->i2cr & I2CR_MTX) {
- qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Trying to read "
- "but MTX is set\n", TYPE_IMX_I2C, __func__);
- } else {
- /* get the next byte */
- ret = i2c_recv(s->bus);
-
- if (ret >= 0) {
- imx_i2c_raise_interrupt(s);
- } else {
- qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: read failed "
- "for device 0x%02x\n", TYPE_IMX_I2C,
- __func__, s->address);
- ret = 0xff;
- }
- }
-
- s->i2dr_read = ret;
- } else {
- qemu_log_mask(LOG_UNIMP, "[%s]%s: slave mode not implemented\n",
- TYPE_IMX_I2C, __func__);
- }
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad address at offset 0x%"
- HWADDR_PRIx "\n", TYPE_IMX_I2C, __func__, offset);
- value = 0;
- break;
- }
-
- DPRINTF("read %s [0x%" HWADDR_PRIx "] -> 0x%02x\n",
- imx_i2c_get_regname(offset), offset, value);
-
- return (uint64_t)value;
-}
-
-static void imx_i2c_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- IMXI2CState *s = IMX_I2C(opaque);
-
- DPRINTF("write %s [0x%" HWADDR_PRIx "] <- 0x%02x\n",
- imx_i2c_get_regname(offset), offset, (int)value);
-
- value &= 0xff;
-
- switch (offset) {
- case IADR_ADDR:
- s->iadr = value & IADR_MASK;
- /* i2c_set_slave_address(s->bus, (uint8_t)s->iadr); */
- break;
- case IFDR_ADDR:
- s->ifdr = value & IFDR_MASK;
- break;
- case I2CR_ADDR:
- if (imx_i2c_is_enabled(s) && ((value & I2CR_IEN) == 0)) {
- /* This is a soft reset. IADR is preserved during soft resets */
- uint16_t iadr = s->iadr;
- imx_i2c_reset(DEVICE(s));
- s->iadr = iadr;
- } else { /* normal write */
- s->i2cr = value & I2CR_MASK;
-
- if (imx_i2c_is_master(s)) {
- /* set the bus to busy */
- s->i2sr |= I2SR_IBB;
- } else { /* slave mode */
- /* bus is not busy anymore */
- s->i2sr &= ~I2SR_IBB;
-
- /*
- * if we unset the master mode then it ends the ongoing
- * transfer if any
- */
- if (s->address != ADDR_RESET) {
- i2c_end_transfer(s->bus);
- s->address = ADDR_RESET;
- }
- }
-
- if (s->i2cr & I2CR_RSTA) { /* Restart */
- /* if this is a restart then it ends the ongoing transfer */
- if (s->address != ADDR_RESET) {
- i2c_end_transfer(s->bus);
- s->address = ADDR_RESET;
- s->i2cr &= ~I2CR_RSTA;
- }
- }
- }
- break;
- case I2SR_ADDR:
- /*
- * if the user writes 0 to IIF then lower the interrupt and
- * reset the bit
- */
- if ((s->i2sr & I2SR_IIF) && !(value & I2SR_IIF)) {
- s->i2sr &= ~I2SR_IIF;
- qemu_irq_lower(s->irq);
- }
-
- /*
- * if the user writes 0 to IAL, reset the bit
- */
- if ((s->i2sr & I2SR_IAL) && !(value & I2SR_IAL)) {
- s->i2sr &= ~I2SR_IAL;
- }
-
- break;
- case I2DR_ADDR:
- /* if the device is not enabled, nothing to do */
- if (!imx_i2c_is_enabled(s)) {
- break;
- }
-
- s->i2dr_write = value & I2DR_MASK;
-
- if (imx_i2c_is_master(s)) {
- /* If this is the first write cycle then it is the slave addr */
- if (s->address == ADDR_RESET) {
- if (i2c_start_transfer(s->bus, extract32(s->i2dr_write, 1, 7),
- extract32(s->i2dr_write, 0, 1))) {
- /* if non zero is returned, the adress is not valid */
- s->i2sr |= I2SR_RXAK;
- } else {
- s->address = s->i2dr_write;
- s->i2sr &= ~I2SR_RXAK;
- imx_i2c_raise_interrupt(s);
- }
- } else { /* This is a normal data write */
- if (i2c_send(s->bus, s->i2dr_write)) {
- /* if the target return non zero then end the transfer */
- s->i2sr |= I2SR_RXAK;
- s->address = ADDR_RESET;
- i2c_end_transfer(s->bus);
- } else {
- s->i2sr &= ~I2SR_RXAK;
- imx_i2c_raise_interrupt(s);
- }
- }
- } else {
- qemu_log_mask(LOG_UNIMP, "[%s]%s: slave mode not implemented\n",
- TYPE_IMX_I2C, __func__);
- }
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad address at offset 0x%"
- HWADDR_PRIx "\n", TYPE_IMX_I2C, __func__, offset);
- break;
- }
-}
-
-static const MemoryRegionOps imx_i2c_ops = {
- .read = imx_i2c_read,
- .write = imx_i2c_write,
- .valid.min_access_size = 1,
- .valid.max_access_size = 2,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription imx_i2c_vmstate = {
- .name = TYPE_IMX_I2C,
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT16(address, IMXI2CState),
- VMSTATE_UINT16(iadr, IMXI2CState),
- VMSTATE_UINT16(ifdr, IMXI2CState),
- VMSTATE_UINT16(i2cr, IMXI2CState),
- VMSTATE_UINT16(i2sr, IMXI2CState),
- VMSTATE_UINT16(i2dr_read, IMXI2CState),
- VMSTATE_UINT16(i2dr_write, IMXI2CState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void imx_i2c_realize(DeviceState *dev, Error **errp)
-{
- IMXI2CState *s = IMX_I2C(dev);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &imx_i2c_ops, s, TYPE_IMX_I2C,
- IMX_I2C_MEM_SIZE);
- sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
- sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
- s->bus = i2c_init_bus(DEVICE(dev), "i2c");
-}
-
-static void imx_i2c_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->vmsd = &imx_i2c_vmstate;
- dc->reset = imx_i2c_reset;
- dc->realize = imx_i2c_realize;
- dc->desc = "i.MX I2C Controller";
-}
-
-static const TypeInfo imx_i2c_type_info = {
- .name = TYPE_IMX_I2C,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(IMXI2CState),
- .class_init = imx_i2c_class_init,
-};
-
-static void imx_i2c_register_types(void)
-{
- type_register_static(&imx_i2c_type_info);
-}
-
-type_init(imx_i2c_register_types)
diff --git a/qemu/hw/i2c/omap_i2c.c b/qemu/hw/i2c/omap_i2c.c
deleted file mode 100644
index 67fbbff8e..000000000
--- a/qemu/hw/i2c/omap_i2c.c
+++ /dev/null
@@ -1,509 +0,0 @@
-/*
- * TI OMAP on-chip I2C controller. Only "new I2C" mode supported.
- *
- * Copyright (C) 2007 Andrzej Zaborowski <balrog@zabor.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/i2c/i2c.h"
-#include "hw/arm/omap.h"
-#include "hw/sysbus.h"
-#include "qemu/error-report.h"
-
-#define TYPE_OMAP_I2C "omap_i2c"
-#define OMAP_I2C(obj) OBJECT_CHECK(OMAPI2CState, (obj), TYPE_OMAP_I2C)
-
-typedef struct OMAPI2CState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- qemu_irq irq;
- qemu_irq drq[2];
- I2CBus *bus;
-
- uint8_t revision;
- void *iclk;
- void *fclk;
-
- uint8_t mask;
- uint16_t stat;
- uint16_t dma;
- uint16_t count;
- int count_cur;
- uint32_t fifo;
- int rxlen;
- int txlen;
- uint16_t control;
- uint16_t addr[2];
- uint8_t divider;
- uint8_t times[2];
- uint16_t test;
-} OMAPI2CState;
-
-#define OMAP2_INTR_REV 0x34
-#define OMAP2_GC_REV 0x34
-
-static void omap_i2c_interrupts_update(OMAPI2CState *s)
-{
- qemu_set_irq(s->irq, s->stat & s->mask);
- if ((s->dma >> 15) & 1) /* RDMA_EN */
- qemu_set_irq(s->drq[0], (s->stat >> 3) & 1); /* RRDY */
- if ((s->dma >> 7) & 1) /* XDMA_EN */
- qemu_set_irq(s->drq[1], (s->stat >> 4) & 1); /* XRDY */
-}
-
-static void omap_i2c_fifo_run(OMAPI2CState *s)
-{
- int ack = 1;
-
- if (!i2c_bus_busy(s->bus))
- return;
-
- if ((s->control >> 2) & 1) { /* RM */
- if ((s->control >> 1) & 1) { /* STP */
- i2c_end_transfer(s->bus);
- s->control &= ~(1 << 1); /* STP */
- s->count_cur = s->count;
- s->txlen = 0;
- } else if ((s->control >> 9) & 1) { /* TRX */
- while (ack && s->txlen)
- ack = (i2c_send(s->bus,
- (s->fifo >> ((-- s->txlen) << 3)) &
- 0xff) >= 0);
- s->stat |= 1 << 4; /* XRDY */
- } else {
- while (s->rxlen < 4)
- s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3);
- s->stat |= 1 << 3; /* RRDY */
- }
- } else {
- if ((s->control >> 9) & 1) { /* TRX */
- while (ack && s->count_cur && s->txlen) {
- ack = (i2c_send(s->bus,
- (s->fifo >> ((-- s->txlen) << 3)) &
- 0xff) >= 0);
- s->count_cur --;
- }
- if (ack && s->count_cur)
- s->stat |= 1 << 4; /* XRDY */
- else
- s->stat &= ~(1 << 4); /* XRDY */
- if (!s->count_cur) {
- s->stat |= 1 << 2; /* ARDY */
- s->control &= ~(1 << 10); /* MST */
- }
- } else {
- while (s->count_cur && s->rxlen < 4) {
- s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3);
- s->count_cur --;
- }
- if (s->rxlen)
- s->stat |= 1 << 3; /* RRDY */
- else
- s->stat &= ~(1 << 3); /* RRDY */
- }
- if (!s->count_cur) {
- if ((s->control >> 1) & 1) { /* STP */
- i2c_end_transfer(s->bus);
- s->control &= ~(1 << 1); /* STP */
- s->count_cur = s->count;
- s->txlen = 0;
- } else {
- s->stat |= 1 << 2; /* ARDY */
- s->control &= ~(1 << 10); /* MST */
- }
- }
- }
-
- s->stat |= (!ack) << 1; /* NACK */
- if (!ack)
- s->control &= ~(1 << 1); /* STP */
-}
-
-static void omap_i2c_reset(DeviceState *dev)
-{
- OMAPI2CState *s = OMAP_I2C(dev);
-
- s->mask = 0;
- s->stat = 0;
- s->dma = 0;
- s->count = 0;
- s->count_cur = 0;
- s->fifo = 0;
- s->rxlen = 0;
- s->txlen = 0;
- s->control = 0;
- s->addr[0] = 0;
- s->addr[1] = 0;
- s->divider = 0;
- s->times[0] = 0;
- s->times[1] = 0;
- s->test = 0;
-}
-
-static uint32_t omap_i2c_read(void *opaque, hwaddr addr)
-{
- OMAPI2CState *s = opaque;
- int offset = addr & OMAP_MPUI_REG_MASK;
- uint16_t ret;
-
- switch (offset) {
- case 0x00: /* I2C_REV */
- return s->revision; /* REV */
-
- case 0x04: /* I2C_IE */
- return s->mask;
-
- case 0x08: /* I2C_STAT */
- return s->stat | (i2c_bus_busy(s->bus) << 12);
-
- case 0x0c: /* I2C_IV */
- if (s->revision >= OMAP2_INTR_REV)
- break;
- ret = ctz32(s->stat & s->mask);
- if (ret != 32) {
- s->stat ^= 1 << ret;
- ret++;
- } else {
- ret = 0;
- }
- omap_i2c_interrupts_update(s);
- return ret;
-
- case 0x10: /* I2C_SYSS */
- return (s->control >> 15) & 1; /* I2C_EN */
-
- case 0x14: /* I2C_BUF */
- return s->dma;
-
- case 0x18: /* I2C_CNT */
- return s->count_cur; /* DCOUNT */
-
- case 0x1c: /* I2C_DATA */
- ret = 0;
- if (s->control & (1 << 14)) { /* BE */
- ret |= ((s->fifo >> 0) & 0xff) << 8;
- ret |= ((s->fifo >> 8) & 0xff) << 0;
- } else {
- ret |= ((s->fifo >> 8) & 0xff) << 8;
- ret |= ((s->fifo >> 0) & 0xff) << 0;
- }
- if (s->rxlen == 1) {
- s->stat |= 1 << 15; /* SBD */
- s->rxlen = 0;
- } else if (s->rxlen > 1) {
- if (s->rxlen > 2)
- s->fifo >>= 16;
- s->rxlen -= 2;
- } else {
- /* XXX: remote access (qualifier) error - what's that? */
- }
- if (!s->rxlen) {
- s->stat &= ~(1 << 3); /* RRDY */
- if (((s->control >> 10) & 1) && /* MST */
- ((~s->control >> 9) & 1)) { /* TRX */
- s->stat |= 1 << 2; /* ARDY */
- s->control &= ~(1 << 10); /* MST */
- }
- }
- s->stat &= ~(1 << 11); /* ROVR */
- omap_i2c_fifo_run(s);
- omap_i2c_interrupts_update(s);
- return ret;
-
- case 0x20: /* I2C_SYSC */
- return 0;
-
- case 0x24: /* I2C_CON */
- return s->control;
-
- case 0x28: /* I2C_OA */
- return s->addr[0];
-
- case 0x2c: /* I2C_SA */
- return s->addr[1];
-
- case 0x30: /* I2C_PSC */
- return s->divider;
-
- case 0x34: /* I2C_SCLL */
- return s->times[0];
-
- case 0x38: /* I2C_SCLH */
- return s->times[1];
-
- case 0x3c: /* I2C_SYSTEST */
- if (s->test & (1 << 15)) { /* ST_EN */
- s->test ^= 0xa;
- return s->test;
- } else
- return s->test & ~0x300f;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_i2c_write(void *opaque, hwaddr addr,
- uint32_t value)
-{
- OMAPI2CState *s = opaque;
- int offset = addr & OMAP_MPUI_REG_MASK;
- int nack;
-
- switch (offset) {
- case 0x00: /* I2C_REV */
- case 0x0c: /* I2C_IV */
- case 0x10: /* I2C_SYSS */
- OMAP_RO_REG(addr);
- return;
-
- case 0x04: /* I2C_IE */
- s->mask = value & (s->revision < OMAP2_GC_REV ? 0x1f : 0x3f);
- break;
-
- case 0x08: /* I2C_STAT */
- if (s->revision < OMAP2_INTR_REV) {
- OMAP_RO_REG(addr);
- return;
- }
-
- /* RRDY and XRDY are reset by hardware. (in all versions???) */
- s->stat &= ~(value & 0x27);
- omap_i2c_interrupts_update(s);
- break;
-
- case 0x14: /* I2C_BUF */
- s->dma = value & 0x8080;
- if (value & (1 << 15)) /* RDMA_EN */
- s->mask &= ~(1 << 3); /* RRDY_IE */
- if (value & (1 << 7)) /* XDMA_EN */
- s->mask &= ~(1 << 4); /* XRDY_IE */
- break;
-
- case 0x18: /* I2C_CNT */
- s->count = value; /* DCOUNT */
- break;
-
- case 0x1c: /* I2C_DATA */
- if (s->txlen > 2) {
- /* XXX: remote access (qualifier) error - what's that? */
- break;
- }
- s->fifo <<= 16;
- s->txlen += 2;
- if (s->control & (1 << 14)) { /* BE */
- s->fifo |= ((value >> 8) & 0xff) << 8;
- s->fifo |= ((value >> 0) & 0xff) << 0;
- } else {
- s->fifo |= ((value >> 0) & 0xff) << 8;
- s->fifo |= ((value >> 8) & 0xff) << 0;
- }
- s->stat &= ~(1 << 10); /* XUDF */
- if (s->txlen > 2)
- s->stat &= ~(1 << 4); /* XRDY */
- omap_i2c_fifo_run(s);
- omap_i2c_interrupts_update(s);
- break;
-
- case 0x20: /* I2C_SYSC */
- if (s->revision < OMAP2_INTR_REV) {
- OMAP_BAD_REG(addr);
- return;
- }
-
- if (value & 2) {
- omap_i2c_reset(DEVICE(s));
- }
- break;
-
- case 0x24: /* I2C_CON */
- s->control = value & 0xcf87;
- if (~value & (1 << 15)) { /* I2C_EN */
- if (s->revision < OMAP2_INTR_REV) {
- omap_i2c_reset(DEVICE(s));
- }
- break;
- }
- if ((value & (1 << 15)) && !(value & (1 << 10))) { /* MST */
- fprintf(stderr, "%s: I^2C slave mode not supported\n",
- __FUNCTION__);
- break;
- }
- if ((value & (1 << 15)) && value & (1 << 8)) { /* XA */
- fprintf(stderr, "%s: 10-bit addressing mode not supported\n",
- __FUNCTION__);
- break;
- }
- if ((value & (1 << 15)) && value & (1 << 0)) { /* STT */
- nack = !!i2c_start_transfer(s->bus, s->addr[1], /* SA */
- (~value >> 9) & 1); /* TRX */
- s->stat |= nack << 1; /* NACK */
- s->control &= ~(1 << 0); /* STT */
- s->fifo = 0;
- if (nack)
- s->control &= ~(1 << 1); /* STP */
- else {
- s->count_cur = s->count;
- omap_i2c_fifo_run(s);
- }
- omap_i2c_interrupts_update(s);
- }
- break;
-
- case 0x28: /* I2C_OA */
- s->addr[0] = value & 0x3ff;
- break;
-
- case 0x2c: /* I2C_SA */
- s->addr[1] = value & 0x3ff;
- break;
-
- case 0x30: /* I2C_PSC */
- s->divider = value;
- break;
-
- case 0x34: /* I2C_SCLL */
- s->times[0] = value;
- break;
-
- case 0x38: /* I2C_SCLH */
- s->times[1] = value;
- break;
-
- case 0x3c: /* I2C_SYSTEST */
- s->test = value & 0xf80f;
- if (value & (1 << 11)) /* SBB */
- if (s->revision >= OMAP2_INTR_REV) {
- s->stat |= 0x3f;
- omap_i2c_interrupts_update(s);
- }
- if (value & (1 << 15)) /* ST_EN */
- fprintf(stderr, "%s: System Test not supported\n", __FUNCTION__);
- break;
-
- default:
- OMAP_BAD_REG(addr);
- return;
- }
-}
-
-static void omap_i2c_writeb(void *opaque, hwaddr addr,
- uint32_t value)
-{
- OMAPI2CState *s = opaque;
- int offset = addr & OMAP_MPUI_REG_MASK;
-
- switch (offset) {
- case 0x1c: /* I2C_DATA */
- if (s->txlen > 2) {
- /* XXX: remote access (qualifier) error - what's that? */
- break;
- }
- s->fifo <<= 8;
- s->txlen += 1;
- s->fifo |= value & 0xff;
- s->stat &= ~(1 << 10); /* XUDF */
- if (s->txlen > 2)
- s->stat &= ~(1 << 4); /* XRDY */
- omap_i2c_fifo_run(s);
- omap_i2c_interrupts_update(s);
- break;
-
- default:
- OMAP_BAD_REG(addr);
- return;
- }
-}
-
-static const MemoryRegionOps omap_i2c_ops = {
- .old_mmio = {
- .read = {
- omap_badwidth_read16,
- omap_i2c_read,
- omap_badwidth_read16,
- },
- .write = {
- omap_i2c_writeb, /* Only the last fifo write can be 8 bit. */
- omap_i2c_write,
- omap_badwidth_write16,
- },
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int omap_i2c_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- OMAPI2CState *s = OMAP_I2C(dev);
-
- if (!s->fclk) {
- error_report("omap_i2c: fclk not connected");
- return -1;
- }
- if (s->revision >= OMAP2_INTR_REV && !s->iclk) {
- /* Note that OMAP1 doesn't have a separate interface clock */
- error_report("omap_i2c: iclk not connected");
- return -1;
- }
-
- sysbus_init_irq(sbd, &s->irq);
- sysbus_init_irq(sbd, &s->drq[0]);
- sysbus_init_irq(sbd, &s->drq[1]);
- memory_region_init_io(&s->iomem, OBJECT(s), &omap_i2c_ops, s, "omap.i2c",
- (s->revision < OMAP2_INTR_REV) ? 0x800 : 0x1000);
- sysbus_init_mmio(sbd, &s->iomem);
- s->bus = i2c_init_bus(dev, NULL);
- return 0;
-}
-
-static Property omap_i2c_properties[] = {
- DEFINE_PROP_UINT8("revision", OMAPI2CState, revision, 0),
- DEFINE_PROP_PTR("iclk", OMAPI2CState, iclk),
- DEFINE_PROP_PTR("fclk", OMAPI2CState, fclk),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void omap_i2c_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- k->init = omap_i2c_init;
- dc->props = omap_i2c_properties;
- dc->reset = omap_i2c_reset;
- /* Reason: pointer properties "iclk", "fclk" */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo omap_i2c_info = {
- .name = TYPE_OMAP_I2C,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(OMAPI2CState),
- .class_init = omap_i2c_class_init,
-};
-
-static void omap_i2c_register_types(void)
-{
- type_register_static(&omap_i2c_info);
-}
-
-I2CBus *omap_i2c_bus(DeviceState *omap_i2c)
-{
- OMAPI2CState *s = OMAP_I2C(omap_i2c);
- return s->bus;
-}
-
-type_init(omap_i2c_register_types)
diff --git a/qemu/hw/i2c/pm_smbus.c b/qemu/hw/i2c/pm_smbus.c
deleted file mode 100644
index 6fc3923f5..000000000
--- a/qemu/hw/i2c/pm_smbus.c
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * PC SMBus implementation
- * splitted from acpi.c
- *
- * Copyright (c) 2006 Fabrice Bellard
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2 as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see
- * <http://www.gnu.org/licenses/>.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/i386/pc.h"
-#include "hw/i2c/pm_smbus.h"
-#include "hw/i2c/smbus.h"
-
-/* no save/load? */
-
-#define SMBHSTSTS 0x00
-#define SMBHSTCNT 0x02
-#define SMBHSTCMD 0x03
-#define SMBHSTADD 0x04
-#define SMBHSTDAT0 0x05
-#define SMBHSTDAT1 0x06
-#define SMBBLKDAT 0x07
-
-#define STS_HOST_BUSY (1)
-#define STS_INTR (1<<1)
-#define STS_DEV_ERR (1<<2)
-#define STS_BUS_ERR (1<<3)
-#define STS_FAILED (1<<4)
-#define STS_SMBALERT (1<<5)
-#define STS_INUSE_STS (1<<6)
-#define STS_BYTE_DONE (1<<7)
-/* Signs of successfully transaction end :
-* ByteDoneStatus = 1 (STS_BYTE_DONE) and INTR = 1 (STS_INTR )
-*/
-
-//#define DEBUG
-
-#ifdef DEBUG
-# define SMBUS_DPRINTF(format, ...) printf(format, ## __VA_ARGS__)
-#else
-# define SMBUS_DPRINTF(format, ...) do { } while (0)
-#endif
-
-
-static void smb_transaction(PMSMBus *s)
-{
- uint8_t prot = (s->smb_ctl >> 2) & 0x07;
- uint8_t read = s->smb_addr & 0x01;
- uint8_t cmd = s->smb_cmd;
- uint8_t addr = s->smb_addr >> 1;
- I2CBus *bus = s->smbus;
- int ret;
-
- SMBUS_DPRINTF("SMBus trans addr=0x%02x prot=0x%02x\n", addr, prot);
- /* Transaction isn't exec if STS_DEV_ERR bit set */
- if ((s->smb_stat & STS_DEV_ERR) != 0) {
- goto error;
- }
- switch(prot) {
- case 0x0:
- ret = smbus_quick_command(bus, addr, read);
- goto done;
- case 0x1:
- if (read) {
- ret = smbus_receive_byte(bus, addr);
- goto data8;
- } else {
- ret = smbus_send_byte(bus, addr, cmd);
- goto done;
- }
- case 0x2:
- if (read) {
- ret = smbus_read_byte(bus, addr, cmd);
- goto data8;
- } else {
- ret = smbus_write_byte(bus, addr, cmd, s->smb_data0);
- goto done;
- }
- break;
- case 0x3:
- if (read) {
- ret = smbus_read_word(bus, addr, cmd);
- goto data16;
- } else {
- ret = smbus_write_word(bus, addr, cmd, (s->smb_data1 << 8) | s->smb_data0);
- goto done;
- }
- break;
- case 0x5:
- if (read) {
- ret = smbus_read_block(bus, addr, cmd, s->smb_data);
- goto data8;
- } else {
- ret = smbus_write_block(bus, addr, cmd, s->smb_data, s->smb_data0);
- goto done;
- }
- break;
- default:
- goto error;
- }
- abort();
-
-data16:
- if (ret < 0) {
- goto error;
- }
- s->smb_data1 = ret >> 8;
-data8:
- if (ret < 0) {
- goto error;
- }
- s->smb_data0 = ret;
-done:
- if (ret < 0) {
- goto error;
- }
- s->smb_stat |= STS_BYTE_DONE | STS_INTR;
- return;
-
-error:
- s->smb_stat |= STS_DEV_ERR;
- return;
-
-}
-
-static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val,
- unsigned width)
-{
- PMSMBus *s = opaque;
-
- SMBUS_DPRINTF("SMB writeb port=0x%04" HWADDR_PRIx
- " val=0x%02" PRIx64 "\n", addr, val);
- switch(addr) {
- case SMBHSTSTS:
- s->smb_stat = (~(val & 0xff)) & s->smb_stat;
- s->smb_index = 0;
- break;
- case SMBHSTCNT:
- s->smb_ctl = val;
- if (val & 0x40)
- smb_transaction(s);
- break;
- case SMBHSTCMD:
- s->smb_cmd = val;
- break;
- case SMBHSTADD:
- s->smb_addr = val;
- break;
- case SMBHSTDAT0:
- s->smb_data0 = val;
- break;
- case SMBHSTDAT1:
- s->smb_data1 = val;
- break;
- case SMBBLKDAT:
- s->smb_data[s->smb_index++] = val;
- if (s->smb_index > 31)
- s->smb_index = 0;
- break;
- default:
- break;
- }
-}
-
-static uint64_t smb_ioport_readb(void *opaque, hwaddr addr, unsigned width)
-{
- PMSMBus *s = opaque;
- uint32_t val;
-
- switch(addr) {
- case SMBHSTSTS:
- val = s->smb_stat;
- break;
- case SMBHSTCNT:
- s->smb_index = 0;
- val = s->smb_ctl & 0x1f;
- break;
- case SMBHSTCMD:
- val = s->smb_cmd;
- break;
- case SMBHSTADD:
- val = s->smb_addr;
- break;
- case SMBHSTDAT0:
- val = s->smb_data0;
- break;
- case SMBHSTDAT1:
- val = s->smb_data1;
- break;
- case SMBBLKDAT:
- val = s->smb_data[s->smb_index++];
- if (s->smb_index > 31)
- s->smb_index = 0;
- break;
- default:
- val = 0;
- break;
- }
- SMBUS_DPRINTF("SMB readb port=0x%04" HWADDR_PRIx " val=0x%02x\n", addr, val);
- return val;
-}
-
-static const MemoryRegionOps pm_smbus_ops = {
- .read = smb_ioport_readb,
- .write = smb_ioport_writeb,
- .valid.min_access_size = 1,
- .valid.max_access_size = 1,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-void pm_smbus_init(DeviceState *parent, PMSMBus *smb)
-{
- smb->smbus = i2c_init_bus(parent, "i2c");
- memory_region_init_io(&smb->io, OBJECT(parent), &pm_smbus_ops, smb,
- "pm-smbus", 64);
-}
diff --git a/qemu/hw/i2c/smbus.c b/qemu/hw/i2c/smbus.c
deleted file mode 100644
index 3979b3dad..000000000
--- a/qemu/hw/i2c/smbus.c
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- * QEMU SMBus device emulation.
- *
- * Copyright (c) 2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the LGPL.
- */
-
-/* TODO: Implement PEC. */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/i2c/i2c.h"
-#include "hw/i2c/smbus.h"
-
-//#define DEBUG_SMBUS 1
-
-#ifdef DEBUG_SMBUS
-#define DPRINTF(fmt, ...) \
-do { printf("smbus(%02x): " fmt , dev->i2c.address, ## __VA_ARGS__); } while (0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "smbus: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "smbus: error: " fmt , ## __VA_ARGS__);} while (0)
-#endif
-
-enum {
- SMBUS_IDLE,
- SMBUS_WRITE_DATA,
- SMBUS_RECV_BYTE,
- SMBUS_READ_DATA,
- SMBUS_DONE,
- SMBUS_CONFUSED = -1
-};
-
-static void smbus_do_quick_cmd(SMBusDevice *dev, int recv)
-{
- SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
-
- DPRINTF("Quick Command %d\n", recv);
- if (sc->quick_cmd) {
- sc->quick_cmd(dev, recv);
- }
-}
-
-static void smbus_do_write(SMBusDevice *dev)
-{
- SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
-
- if (dev->data_len == 0) {
- smbus_do_quick_cmd(dev, 0);
- } else if (dev->data_len == 1) {
- DPRINTF("Send Byte\n");
- if (sc->send_byte) {
- sc->send_byte(dev, dev->data_buf[0]);
- }
- } else {
- dev->command = dev->data_buf[0];
- DPRINTF("Command %d len %d\n", dev->command, dev->data_len - 1);
- if (sc->write_data) {
- sc->write_data(dev, dev->command, dev->data_buf + 1,
- dev->data_len - 1);
- }
- }
-}
-
-static void smbus_i2c_event(I2CSlave *s, enum i2c_event event)
-{
- SMBusDevice *dev = SMBUS_DEVICE(s);
-
- switch (event) {
- case I2C_START_SEND:
- switch (dev->mode) {
- case SMBUS_IDLE:
- DPRINTF("Incoming data\n");
- dev->mode = SMBUS_WRITE_DATA;
- break;
- default:
- BADF("Unexpected send start condition in state %d\n", dev->mode);
- dev->mode = SMBUS_CONFUSED;
- break;
- }
- break;
-
- case I2C_START_RECV:
- switch (dev->mode) {
- case SMBUS_IDLE:
- DPRINTF("Read mode\n");
- dev->mode = SMBUS_RECV_BYTE;
- break;
- case SMBUS_WRITE_DATA:
- if (dev->data_len == 0) {
- BADF("Read after write with no data\n");
- dev->mode = SMBUS_CONFUSED;
- } else {
- if (dev->data_len > 1) {
- smbus_do_write(dev);
- } else {
- dev->command = dev->data_buf[0];
- DPRINTF("%02x: Command %d\n", dev->i2c.address,
- dev->command);
- }
- DPRINTF("Read mode\n");
- dev->data_len = 0;
- dev->mode = SMBUS_READ_DATA;
- }
- break;
- default:
- BADF("Unexpected recv start condition in state %d\n", dev->mode);
- dev->mode = SMBUS_CONFUSED;
- break;
- }
- break;
-
- case I2C_FINISH:
- switch (dev->mode) {
- case SMBUS_WRITE_DATA:
- smbus_do_write(dev);
- break;
- case SMBUS_RECV_BYTE:
- smbus_do_quick_cmd(dev, 1);
- break;
- case SMBUS_READ_DATA:
- BADF("Unexpected stop during receive\n");
- break;
- default:
- /* Nothing to do. */
- break;
- }
- dev->mode = SMBUS_IDLE;
- dev->data_len = 0;
- break;
-
- case I2C_NACK:
- switch (dev->mode) {
- case SMBUS_DONE:
- /* Nothing to do. */
- break;
- case SMBUS_READ_DATA:
- dev->mode = SMBUS_DONE;
- break;
- default:
- BADF("Unexpected NACK in state %d\n", dev->mode);
- dev->mode = SMBUS_CONFUSED;
- break;
- }
- }
-}
-
-static int smbus_i2c_recv(I2CSlave *s)
-{
- SMBusDevice *dev = SMBUS_DEVICE(s);
- SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
- int ret;
-
- switch (dev->mode) {
- case SMBUS_RECV_BYTE:
- if (sc->receive_byte) {
- ret = sc->receive_byte(dev);
- } else {
- ret = 0;
- }
- DPRINTF("Receive Byte %02x\n", ret);
- dev->mode = SMBUS_DONE;
- break;
- case SMBUS_READ_DATA:
- if (sc->read_data) {
- ret = sc->read_data(dev, dev->command, dev->data_len);
- dev->data_len++;
- } else {
- ret = 0;
- }
- DPRINTF("Read data %02x\n", ret);
- break;
- default:
- BADF("Unexpected read in state %d\n", dev->mode);
- dev->mode = SMBUS_CONFUSED;
- ret = 0;
- break;
- }
- return ret;
-}
-
-static int smbus_i2c_send(I2CSlave *s, uint8_t data)
-{
- SMBusDevice *dev = SMBUS_DEVICE(s);
-
- switch (dev->mode) {
- case SMBUS_WRITE_DATA:
- DPRINTF("Write data %02x\n", data);
- dev->data_buf[dev->data_len++] = data;
- break;
- default:
- BADF("Unexpected write in state %d\n", dev->mode);
- break;
- }
- return 0;
-}
-
-static int smbus_device_init(I2CSlave *i2c)
-{
- SMBusDevice *dev = SMBUS_DEVICE(i2c);
- SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
-
- return sc->init(dev);
-}
-
-/* Master device commands. */
-int smbus_quick_command(I2CBus *bus, uint8_t addr, int read)
-{
- if (i2c_start_transfer(bus, addr, read)) {
- return -1;
- }
- i2c_end_transfer(bus);
- return 0;
-}
-
-int smbus_receive_byte(I2CBus *bus, uint8_t addr)
-{
- uint8_t data;
-
- if (i2c_start_transfer(bus, addr, 1)) {
- return -1;
- }
- data = i2c_recv(bus);
- i2c_nack(bus);
- i2c_end_transfer(bus);
- return data;
-}
-
-int smbus_send_byte(I2CBus *bus, uint8_t addr, uint8_t data)
-{
- if (i2c_start_transfer(bus, addr, 0)) {
- return -1;
- }
- i2c_send(bus, data);
- i2c_end_transfer(bus);
- return 0;
-}
-
-int smbus_read_byte(I2CBus *bus, uint8_t addr, uint8_t command)
-{
- uint8_t data;
- if (i2c_start_transfer(bus, addr, 0)) {
- return -1;
- }
- i2c_send(bus, command);
- i2c_start_transfer(bus, addr, 1);
- data = i2c_recv(bus);
- i2c_nack(bus);
- i2c_end_transfer(bus);
- return data;
-}
-
-int smbus_write_byte(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t data)
-{
- if (i2c_start_transfer(bus, addr, 0)) {
- return -1;
- }
- i2c_send(bus, command);
- i2c_send(bus, data);
- i2c_end_transfer(bus);
- return 0;
-}
-
-int smbus_read_word(I2CBus *bus, uint8_t addr, uint8_t command)
-{
- uint16_t data;
- if (i2c_start_transfer(bus, addr, 0)) {
- return -1;
- }
- i2c_send(bus, command);
- i2c_start_transfer(bus, addr, 1);
- data = i2c_recv(bus);
- data |= i2c_recv(bus) << 8;
- i2c_nack(bus);
- i2c_end_transfer(bus);
- return data;
-}
-
-int smbus_write_word(I2CBus *bus, uint8_t addr, uint8_t command, uint16_t data)
-{
- if (i2c_start_transfer(bus, addr, 0)) {
- return -1;
- }
- i2c_send(bus, command);
- i2c_send(bus, data & 0xff);
- i2c_send(bus, data >> 8);
- i2c_end_transfer(bus);
- return 0;
-}
-
-int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data)
-{
- int len;
- int i;
-
- if (i2c_start_transfer(bus, addr, 0)) {
- return -1;
- }
- i2c_send(bus, command);
- i2c_start_transfer(bus, addr, 1);
- len = i2c_recv(bus);
- if (len > 32) {
- len = 0;
- }
- for (i = 0; i < len; i++) {
- data[i] = i2c_recv(bus);
- }
- i2c_nack(bus);
- i2c_end_transfer(bus);
- return len;
-}
-
-int smbus_write_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data,
- int len)
-{
- int i;
-
- if (len > 32)
- len = 32;
-
- if (i2c_start_transfer(bus, addr, 0)) {
- return -1;
- }
- i2c_send(bus, command);
- i2c_send(bus, len);
- for (i = 0; i < len; i++) {
- i2c_send(bus, data[i]);
- }
- i2c_end_transfer(bus);
- return 0;
-}
-
-static void smbus_device_class_init(ObjectClass *klass, void *data)
-{
- I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
-
- sc->init = smbus_device_init;
- sc->event = smbus_i2c_event;
- sc->recv = smbus_i2c_recv;
- sc->send = smbus_i2c_send;
-}
-
-static const TypeInfo smbus_device_type_info = {
- .name = TYPE_SMBUS_DEVICE,
- .parent = TYPE_I2C_SLAVE,
- .instance_size = sizeof(SMBusDevice),
- .abstract = true,
- .class_size = sizeof(SMBusDeviceClass),
- .class_init = smbus_device_class_init,
-};
-
-static void smbus_device_register_types(void)
-{
- type_register_static(&smbus_device_type_info);
-}
-
-type_init(smbus_device_register_types)
diff --git a/qemu/hw/i2c/smbus_eeprom.c b/qemu/hw/i2c/smbus_eeprom.c
deleted file mode 100644
index 5b7bd891b..000000000
--- a/qemu/hw/i2c/smbus_eeprom.c
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * QEMU SMBus EEPROM device
- *
- * Copyright (c) 2007 Arastra, Inc.
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/i2c/i2c.h"
-#include "hw/i2c/smbus.h"
-
-//#define DEBUG
-
-typedef struct SMBusEEPROMDevice {
- SMBusDevice smbusdev;
- void *data;
- uint8_t offset;
-} SMBusEEPROMDevice;
-
-static void eeprom_quick_cmd(SMBusDevice *dev, uint8_t read)
-{
-#ifdef DEBUG
- printf("eeprom_quick_cmd: addr=0x%02x read=%d\n", dev->i2c.address, read);
-#endif
-}
-
-static void eeprom_send_byte(SMBusDevice *dev, uint8_t val)
-{
- SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev;
-#ifdef DEBUG
- printf("eeprom_send_byte: addr=0x%02x val=0x%02x\n",
- dev->i2c.address, val);
-#endif
- eeprom->offset = val;
-}
-
-static uint8_t eeprom_receive_byte(SMBusDevice *dev)
-{
- SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev;
- uint8_t *data = eeprom->data;
- uint8_t val = data[eeprom->offset++];
-#ifdef DEBUG
- printf("eeprom_receive_byte: addr=0x%02x val=0x%02x\n",
- dev->i2c.address, val);
-#endif
- return val;
-}
-
-static void eeprom_write_data(SMBusDevice *dev, uint8_t cmd, uint8_t *buf, int len)
-{
- SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev;
- int n;
-#ifdef DEBUG
- printf("eeprom_write_byte: addr=0x%02x cmd=0x%02x val=0x%02x\n",
- dev->i2c.address, cmd, buf[0]);
-#endif
- /* A page write operation is not a valid SMBus command.
- It is a block write without a length byte. Fortunately we
- get the full block anyway. */
- /* TODO: Should this set the current location? */
- if (cmd + len > 256)
- n = 256 - cmd;
- else
- n = len;
- memcpy(eeprom->data + cmd, buf, n);
- len -= n;
- if (len)
- memcpy(eeprom->data, buf + n, len);
-}
-
-static uint8_t eeprom_read_data(SMBusDevice *dev, uint8_t cmd, int n)
-{
- SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev;
- /* If this is the first byte then set the current position. */
- if (n == 0)
- eeprom->offset = cmd;
- /* As with writes, we implement block reads without the
- SMBus length byte. */
- return eeprom_receive_byte(dev);
-}
-
-static int smbus_eeprom_initfn(SMBusDevice *dev)
-{
- SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *)dev;
-
- eeprom->offset = 0;
- return 0;
-}
-
-static Property smbus_eeprom_properties[] = {
- DEFINE_PROP_PTR("data", SMBusEEPROMDevice, data),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void smbus_eeprom_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SMBusDeviceClass *sc = SMBUS_DEVICE_CLASS(klass);
-
- sc->init = smbus_eeprom_initfn;
- sc->quick_cmd = eeprom_quick_cmd;
- sc->send_byte = eeprom_send_byte;
- sc->receive_byte = eeprom_receive_byte;
- sc->write_data = eeprom_write_data;
- sc->read_data = eeprom_read_data;
- dc->props = smbus_eeprom_properties;
- /* Reason: pointer property "data" */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo smbus_eeprom_info = {
- .name = "smbus-eeprom",
- .parent = TYPE_SMBUS_DEVICE,
- .instance_size = sizeof(SMBusEEPROMDevice),
- .class_init = smbus_eeprom_class_initfn,
-};
-
-static void smbus_eeprom_register_types(void)
-{
- type_register_static(&smbus_eeprom_info);
-}
-
-type_init(smbus_eeprom_register_types)
-
-void smbus_eeprom_init(I2CBus *smbus, int nb_eeprom,
- const uint8_t *eeprom_spd, int eeprom_spd_size)
-{
- int i;
- uint8_t *eeprom_buf = g_malloc0(8 * 256); /* XXX: make this persistent */
- if (eeprom_spd_size > 0) {
- memcpy(eeprom_buf, eeprom_spd, eeprom_spd_size);
- }
-
- for (i = 0; i < nb_eeprom; i++) {
- DeviceState *eeprom;
- eeprom = qdev_create((BusState *)smbus, "smbus-eeprom");
- qdev_prop_set_uint8(eeprom, "address", 0x50 + i);
- qdev_prop_set_ptr(eeprom, "data", eeprom_buf + (i * 256));
- qdev_init_nofail(eeprom);
- }
-}
diff --git a/qemu/hw/i2c/smbus_ich9.c b/qemu/hw/i2c/smbus_ich9.c
deleted file mode 100644
index 498f03e83..000000000
--- a/qemu/hw/i2c/smbus_ich9.c
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * ACPI implementation
- *
- * Copyright (c) 2006 Fabrice Bellard
- * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
- * VA Linux Systems Japan K.K.
- * Copyright (C) 2012 Jason Baron <jbaron@redhat.com>
- *
- * This is based on acpi.c, but heavily rewritten.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2 as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- *
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/i386/pc.h"
-#include "hw/i2c/pm_smbus.h"
-#include "hw/pci/pci.h"
-#include "sysemu/sysemu.h"
-#include "hw/i2c/i2c.h"
-#include "hw/i2c/smbus.h"
-
-#include "hw/i386/ich9.h"
-
-#define TYPE_ICH9_SMB_DEVICE "ICH9 SMB"
-#define ICH9_SMB_DEVICE(obj) \
- OBJECT_CHECK(ICH9SMBState, (obj), TYPE_ICH9_SMB_DEVICE)
-
-typedef struct ICH9SMBState {
- PCIDevice dev;
-
- PMSMBus smb;
-} ICH9SMBState;
-
-static const VMStateDescription vmstate_ich9_smbus = {
- .name = "ich9_smb",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(dev, struct ICH9SMBState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void ich9_smbus_write_config(PCIDevice *d, uint32_t address,
- uint32_t val, int len)
-{
- ICH9SMBState *s = ICH9_SMB_DEVICE(d);
-
- pci_default_write_config(d, address, val, len);
- if (range_covers_byte(address, len, ICH9_SMB_HOSTC)) {
- uint8_t hostc = s->dev.config[ICH9_SMB_HOSTC];
- if ((hostc & ICH9_SMB_HOSTC_HST_EN) &&
- !(hostc & ICH9_SMB_HOSTC_I2C_EN)) {
- memory_region_set_enabled(&s->smb.io, true);
- } else {
- memory_region_set_enabled(&s->smb.io, false);
- }
- }
-}
-
-static void ich9_smbus_realize(PCIDevice *d, Error **errp)
-{
- ICH9SMBState *s = ICH9_SMB_DEVICE(d);
-
- /* TODO? D31IP.SMIP in chipset configuration space */
- pci_config_set_interrupt_pin(d->config, 0x01); /* interrupt pin 1 */
-
- pci_set_byte(d->config + ICH9_SMB_HOSTC, 0);
- /* TODO bar0, bar1: 64bit BAR support*/
-
- pm_smbus_init(&d->qdev, &s->smb);
- pci_register_bar(d, ICH9_SMB_SMB_BASE_BAR, PCI_BASE_ADDRESS_SPACE_IO,
- &s->smb.io);
-}
-
-static void ich9_smb_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->vendor_id = PCI_VENDOR_ID_INTEL;
- k->device_id = PCI_DEVICE_ID_INTEL_ICH9_6;
- k->revision = ICH9_A2_SMB_REVISION;
- k->class_id = PCI_CLASS_SERIAL_SMBUS;
- dc->vmsd = &vmstate_ich9_smbus;
- dc->desc = "ICH9 SMBUS Bridge";
- k->realize = ich9_smbus_realize;
- k->config_write = ich9_smbus_write_config;
- /*
- * Reason: part of ICH9 southbridge, needs to be wired up by
- * pc_q35_init()
- */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-I2CBus *ich9_smb_init(PCIBus *bus, int devfn, uint32_t smb_io_base)
-{
- PCIDevice *d =
- pci_create_simple_multifunction(bus, devfn, true, TYPE_ICH9_SMB_DEVICE);
- ICH9SMBState *s = ICH9_SMB_DEVICE(d);
- return s->smb.smbus;
-}
-
-static const TypeInfo ich9_smb_info = {
- .name = TYPE_ICH9_SMB_DEVICE,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(ICH9SMBState),
- .class_init = ich9_smb_class_init,
-};
-
-static void ich9_smb_register(void)
-{
- type_register_static(&ich9_smb_info);
-}
-
-type_init(ich9_smb_register);
diff --git a/qemu/hw/i2c/versatile_i2c.c b/qemu/hw/i2c/versatile_i2c.c
deleted file mode 100644
index fee3bc761..000000000
--- a/qemu/hw/i2c/versatile_i2c.c
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * ARM Versatile I2C controller
- *
- * Copyright (c) 2006-2007 CodeSourcery.
- * Copyright (c) 2012 Oskar Andero <oskar.andero@gmail.com>
- *
- * This file is derived from hw/realview.c by Paul Brook
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "bitbang_i2c.h"
-
-#define TYPE_VERSATILE_I2C "versatile_i2c"
-#define VERSATILE_I2C(obj) \
- OBJECT_CHECK(VersatileI2CState, (obj), TYPE_VERSATILE_I2C)
-
-typedef struct VersatileI2CState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- bitbang_i2c_interface *bitbang;
- int out;
- int in;
-} VersatileI2CState;
-
-static uint64_t versatile_i2c_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- VersatileI2CState *s = (VersatileI2CState *)opaque;
-
- if (offset == 0) {
- return (s->out & 1) | (s->in << 1);
- } else {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad offset 0x%x\n", __func__, (int)offset);
- return -1;
- }
-}
-
-static void versatile_i2c_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- VersatileI2CState *s = (VersatileI2CState *)opaque;
-
- switch (offset) {
- case 0:
- s->out |= value & 3;
- break;
- case 4:
- s->out &= ~value;
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad offset 0x%x\n", __func__, (int)offset);
- }
- bitbang_i2c_set(s->bitbang, BITBANG_I2C_SCL, (s->out & 1) != 0);
- s->in = bitbang_i2c_set(s->bitbang, BITBANG_I2C_SDA, (s->out & 2) != 0);
-}
-
-static const MemoryRegionOps versatile_i2c_ops = {
- .read = versatile_i2c_read,
- .write = versatile_i2c_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int versatile_i2c_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- VersatileI2CState *s = VERSATILE_I2C(dev);
- I2CBus *bus;
-
- bus = i2c_init_bus(dev, "i2c");
- s->bitbang = bitbang_i2c_init(bus);
- memory_region_init_io(&s->iomem, OBJECT(s), &versatile_i2c_ops, s,
- "versatile_i2c", 0x1000);
- sysbus_init_mmio(sbd, &s->iomem);
- return 0;
-}
-
-static void versatile_i2c_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = versatile_i2c_init;
-}
-
-static const TypeInfo versatile_i2c_info = {
- .name = TYPE_VERSATILE_I2C,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(VersatileI2CState),
- .class_init = versatile_i2c_class_init,
-};
-
-static void versatile_i2c_register_types(void)
-{
- type_register_static(&versatile_i2c_info);
-}
-
-type_init(versatile_i2c_register_types)
diff --git a/qemu/hw/i386/Makefile.objs b/qemu/hw/i386/Makefile.objs
deleted file mode 100644
index b52d5b875..000000000
--- a/qemu/hw/i386/Makefile.objs
+++ /dev/null
@@ -1,10 +0,0 @@
-obj-$(CONFIG_KVM) += kvm/
-obj-y += multiboot.o
-obj-y += pc.o pc_piix.o pc_q35.o
-obj-y += pc_sysfw.o
-obj-y += intel_iommu.o
-obj-$(CONFIG_XEN) += ../xenpv/ xen/
-
-obj-y += kvmvapic.o
-obj-y += acpi-build.o
-obj-y += pci-assign-load-rom.o
diff --git a/qemu/hw/i386/acpi-build.c b/qemu/hw/i386/acpi-build.c
deleted file mode 100644
index 64770034f..000000000
--- a/qemu/hw/i386/acpi-build.c
+++ /dev/null
@@ -1,2950 +0,0 @@
-/* Support for generating ACPI tables and passing them to Guests
- *
- * Copyright (C) 2008-2010 Kevin O'Connor <kevin@koconnor.net>
- * Copyright (C) 2006 Fabrice Bellard
- * Copyright (C) 2013 Red Hat Inc
- *
- * Author: Michael S. Tsirkin <mst@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "acpi-build.h"
-#include <glib.h>
-#include "qemu-common.h"
-#include "qemu/bitmap.h"
-#include "qemu/error-report.h"
-#include "hw/pci/pci.h"
-#include "qom/cpu.h"
-#include "hw/i386/pc.h"
-#include "target-i386/cpu.h"
-#include "hw/timer/hpet.h"
-#include "hw/acpi/acpi-defs.h"
-#include "hw/acpi/acpi.h"
-#include "hw/nvram/fw_cfg.h"
-#include "hw/acpi/bios-linker-loader.h"
-#include "hw/loader.h"
-#include "hw/isa/isa.h"
-#include "hw/block/fdc.h"
-#include "hw/acpi/memory_hotplug.h"
-#include "sysemu/tpm.h"
-#include "hw/acpi/tpm.h"
-#include "sysemu/tpm_backend.h"
-#include "hw/timer/mc146818rtc_regs.h"
-
-/* Supported chipsets: */
-#include "hw/acpi/piix4.h"
-#include "hw/acpi/pcihp.h"
-#include "hw/i386/ich9.h"
-#include "hw/pci/pci_bus.h"
-#include "hw/pci-host/q35.h"
-#include "hw/i386/intel_iommu.h"
-#include "hw/timer/hpet.h"
-
-#include "hw/acpi/aml-build.h"
-
-#include "qapi/qmp/qint.h"
-#include "qom/qom-qobject.h"
-
-/* These are used to size the ACPI tables for -M pc-i440fx-1.7 and
- * -M pc-i440fx-2.0. Even if the actual amount of AML generated grows
- * a little bit, there should be plenty of free space since the DSDT
- * shrunk by ~1.5k between QEMU 2.0 and QEMU 2.1.
- */
-#define ACPI_BUILD_LEGACY_CPU_AML_SIZE 97
-#define ACPI_BUILD_ALIGN_SIZE 0x1000
-
-#define ACPI_BUILD_TABLE_SIZE 0x20000
-
-/* #define DEBUG_ACPI_BUILD */
-#ifdef DEBUG_ACPI_BUILD
-#define ACPI_BUILD_DPRINTF(fmt, ...) \
- do {printf("ACPI_BUILD: " fmt, ## __VA_ARGS__); } while (0)
-#else
-#define ACPI_BUILD_DPRINTF(fmt, ...)
-#endif
-
-typedef struct AcpiMcfgInfo {
- uint64_t mcfg_base;
- uint32_t mcfg_size;
-} AcpiMcfgInfo;
-
-typedef struct AcpiPmInfo {
- bool s3_disabled;
- bool s4_disabled;
- bool pcihp_bridge_en;
- uint8_t s4_val;
- uint16_t sci_int;
- uint8_t acpi_enable_cmd;
- uint8_t acpi_disable_cmd;
- uint32_t gpe0_blk;
- uint32_t gpe0_blk_len;
- uint32_t io_base;
- uint16_t cpu_hp_io_base;
- uint16_t cpu_hp_io_len;
- uint16_t mem_hp_io_base;
- uint16_t mem_hp_io_len;
- uint16_t pcihp_io_base;
- uint16_t pcihp_io_len;
-} AcpiPmInfo;
-
-typedef struct AcpiMiscInfo {
- bool is_piix4;
- bool has_hpet;
- TPMVersion tpm_version;
- const unsigned char *dsdt_code;
- unsigned dsdt_size;
- uint16_t pvpanic_port;
- uint16_t applesmc_io_base;
-} AcpiMiscInfo;
-
-typedef struct AcpiBuildPciBusHotplugState {
- GArray *device_table;
- GArray *notify_table;
- struct AcpiBuildPciBusHotplugState *parent;
- bool pcihp_bridge_en;
-} AcpiBuildPciBusHotplugState;
-
-static void acpi_get_pm_info(AcpiPmInfo *pm)
-{
- Object *piix = piix4_pm_find();
- Object *lpc = ich9_lpc_find();
- Object *obj = NULL;
- QObject *o;
-
- pm->cpu_hp_io_base = 0;
- pm->pcihp_io_base = 0;
- pm->pcihp_io_len = 0;
- if (piix) {
- obj = piix;
- pm->cpu_hp_io_base = PIIX4_CPU_HOTPLUG_IO_BASE;
- pm->pcihp_io_base =
- object_property_get_int(obj, ACPI_PCIHP_IO_BASE_PROP, NULL);
- pm->pcihp_io_len =
- object_property_get_int(obj, ACPI_PCIHP_IO_LEN_PROP, NULL);
- }
- if (lpc) {
- obj = lpc;
- pm->cpu_hp_io_base = ICH9_CPU_HOTPLUG_IO_BASE;
- }
- assert(obj);
-
- pm->cpu_hp_io_len = ACPI_GPE_PROC_LEN;
- pm->mem_hp_io_base = ACPI_MEMORY_HOTPLUG_BASE;
- pm->mem_hp_io_len = ACPI_MEMORY_HOTPLUG_IO_LEN;
-
- /* Fill in optional s3/s4 related properties */
- o = object_property_get_qobject(obj, ACPI_PM_PROP_S3_DISABLED, NULL);
- if (o) {
- pm->s3_disabled = qint_get_int(qobject_to_qint(o));
- } else {
- pm->s3_disabled = false;
- }
- qobject_decref(o);
- o = object_property_get_qobject(obj, ACPI_PM_PROP_S4_DISABLED, NULL);
- if (o) {
- pm->s4_disabled = qint_get_int(qobject_to_qint(o));
- } else {
- pm->s4_disabled = false;
- }
- qobject_decref(o);
- o = object_property_get_qobject(obj, ACPI_PM_PROP_S4_VAL, NULL);
- if (o) {
- pm->s4_val = qint_get_int(qobject_to_qint(o));
- } else {
- pm->s4_val = false;
- }
- qobject_decref(o);
-
- /* Fill in mandatory properties */
- pm->sci_int = object_property_get_int(obj, ACPI_PM_PROP_SCI_INT, NULL);
-
- pm->acpi_enable_cmd = object_property_get_int(obj,
- ACPI_PM_PROP_ACPI_ENABLE_CMD,
- NULL);
- pm->acpi_disable_cmd = object_property_get_int(obj,
- ACPI_PM_PROP_ACPI_DISABLE_CMD,
- NULL);
- pm->io_base = object_property_get_int(obj, ACPI_PM_PROP_PM_IO_BASE,
- NULL);
- pm->gpe0_blk = object_property_get_int(obj, ACPI_PM_PROP_GPE0_BLK,
- NULL);
- pm->gpe0_blk_len = object_property_get_int(obj, ACPI_PM_PROP_GPE0_BLK_LEN,
- NULL);
- pm->pcihp_bridge_en =
- object_property_get_bool(obj, "acpi-pci-hotplug-with-bridge-support",
- NULL);
-}
-
-static void acpi_get_misc_info(AcpiMiscInfo *info)
-{
- Object *piix = piix4_pm_find();
- Object *lpc = ich9_lpc_find();
- assert(!!piix != !!lpc);
-
- if (piix) {
- info->is_piix4 = true;
- }
- if (lpc) {
- info->is_piix4 = false;
- }
-
- info->has_hpet = hpet_find();
- info->tpm_version = tpm_get_version();
- info->pvpanic_port = pvpanic_port();
- info->applesmc_io_base = applesmc_port();
-}
-
-/*
- * Because of the PXB hosts we cannot simply query TYPE_PCI_HOST_BRIDGE.
- * On i386 arch we only have two pci hosts, so we can look only for them.
- */
-static Object *acpi_get_i386_pci_host(void)
-{
- PCIHostState *host;
-
- host = OBJECT_CHECK(PCIHostState,
- object_resolve_path("/machine/i440fx", NULL),
- TYPE_PCI_HOST_BRIDGE);
- if (!host) {
- host = OBJECT_CHECK(PCIHostState,
- object_resolve_path("/machine/q35", NULL),
- TYPE_PCI_HOST_BRIDGE);
- }
-
- return OBJECT(host);
-}
-
-static void acpi_get_pci_info(PcPciInfo *info)
-{
- Object *pci_host;
-
-
- pci_host = acpi_get_i386_pci_host();
- g_assert(pci_host);
-
- info->w32.begin = object_property_get_int(pci_host,
- PCI_HOST_PROP_PCI_HOLE_START,
- NULL);
- info->w32.end = object_property_get_int(pci_host,
- PCI_HOST_PROP_PCI_HOLE_END,
- NULL);
- info->w64.begin = object_property_get_int(pci_host,
- PCI_HOST_PROP_PCI_HOLE64_START,
- NULL);
- info->w64.end = object_property_get_int(pci_host,
- PCI_HOST_PROP_PCI_HOLE64_END,
- NULL);
-}
-
-#define ACPI_PORT_SMI_CMD 0x00b2 /* TODO: this is APM_CNT_IOPORT */
-
-static void acpi_align_size(GArray *blob, unsigned align)
-{
- /* Align size to multiple of given size. This reduces the chance
- * we need to change size in the future (breaking cross version migration).
- */
- g_array_set_size(blob, ROUND_UP(acpi_data_len(blob), align));
-}
-
-/* FACS */
-static void
-build_facs(GArray *table_data, GArray *linker)
-{
- AcpiFacsDescriptorRev1 *facs = acpi_data_push(table_data, sizeof *facs);
- memcpy(&facs->signature, "FACS", 4);
- facs->length = cpu_to_le32(sizeof(*facs));
-}
-
-/* Load chipset information in FADT */
-static void fadt_setup(AcpiFadtDescriptorRev1 *fadt, AcpiPmInfo *pm)
-{
- fadt->model = 1;
- fadt->reserved1 = 0;
- fadt->sci_int = cpu_to_le16(pm->sci_int);
- fadt->smi_cmd = cpu_to_le32(ACPI_PORT_SMI_CMD);
- fadt->acpi_enable = pm->acpi_enable_cmd;
- fadt->acpi_disable = pm->acpi_disable_cmd;
- /* EVT, CNT, TMR offset matches hw/acpi/core.c */
- fadt->pm1a_evt_blk = cpu_to_le32(pm->io_base);
- fadt->pm1a_cnt_blk = cpu_to_le32(pm->io_base + 0x04);
- fadt->pm_tmr_blk = cpu_to_le32(pm->io_base + 0x08);
- fadt->gpe0_blk = cpu_to_le32(pm->gpe0_blk);
- /* EVT, CNT, TMR length matches hw/acpi/core.c */
- fadt->pm1_evt_len = 4;
- fadt->pm1_cnt_len = 2;
- fadt->pm_tmr_len = 4;
- fadt->gpe0_blk_len = pm->gpe0_blk_len;
- fadt->plvl2_lat = cpu_to_le16(0xfff); /* C2 state not supported */
- fadt->plvl3_lat = cpu_to_le16(0xfff); /* C3 state not supported */
- fadt->flags = cpu_to_le32((1 << ACPI_FADT_F_WBINVD) |
- (1 << ACPI_FADT_F_PROC_C1) |
- (1 << ACPI_FADT_F_SLP_BUTTON) |
- (1 << ACPI_FADT_F_RTC_S4));
- fadt->flags |= cpu_to_le32(1 << ACPI_FADT_F_USE_PLATFORM_CLOCK);
- /* APIC destination mode ("Flat Logical") has an upper limit of 8 CPUs
- * For more than 8 CPUs, "Clustered Logical" mode has to be used
- */
- if (max_cpus > 8) {
- fadt->flags |= cpu_to_le32(1 << ACPI_FADT_F_FORCE_APIC_CLUSTER_MODEL);
- }
- fadt->century = RTC_CENTURY;
-}
-
-
-/* FADT */
-static void
-build_fadt(GArray *table_data, GArray *linker, AcpiPmInfo *pm,
- unsigned facs, unsigned dsdt,
- const char *oem_id, const char *oem_table_id)
-{
- AcpiFadtDescriptorRev1 *fadt = acpi_data_push(table_data, sizeof(*fadt));
-
- fadt->firmware_ctrl = cpu_to_le32(facs);
- /* FACS address to be filled by Guest linker */
- bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE,
- ACPI_BUILD_TABLE_FILE,
- table_data, &fadt->firmware_ctrl,
- sizeof fadt->firmware_ctrl);
-
- fadt->dsdt = cpu_to_le32(dsdt);
- /* DSDT address to be filled by Guest linker */
- bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE,
- ACPI_BUILD_TABLE_FILE,
- table_data, &fadt->dsdt,
- sizeof fadt->dsdt);
-
- fadt_setup(fadt, pm);
-
- build_header(linker, table_data,
- (void *)fadt, "FACP", sizeof(*fadt), 1, oem_id, oem_table_id);
-}
-
-static void
-build_madt(GArray *table_data, GArray *linker, PCMachineState *pcms)
-{
- MachineClass *mc = MACHINE_GET_CLASS(pcms);
- CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids(MACHINE(pcms));
- int madt_start = table_data->len;
-
- AcpiMultipleApicTable *madt;
- AcpiMadtIoApic *io_apic;
- AcpiMadtIntsrcovr *intsrcovr;
- AcpiMadtLocalNmi *local_nmi;
- int i;
-
- madt = acpi_data_push(table_data, sizeof *madt);
- madt->local_apic_address = cpu_to_le32(APIC_DEFAULT_ADDRESS);
- madt->flags = cpu_to_le32(1);
-
- for (i = 0; i < apic_ids->len; i++) {
- AcpiMadtProcessorApic *apic = acpi_data_push(table_data, sizeof *apic);
- int apic_id = apic_ids->cpus[i].arch_id;
-
- apic->type = ACPI_APIC_PROCESSOR;
- apic->length = sizeof(*apic);
- apic->processor_id = apic_id;
- apic->local_apic_id = apic_id;
- if (apic_ids->cpus[i].cpu != NULL) {
- apic->flags = cpu_to_le32(1);
- } else {
- /* ACPI spec says that LAPIC entry for non present
- * CPU may be omitted from MADT or it must be marked
- * as disabled. However omitting non present CPU from
- * MADT breaks hotplug on linux. So possible CPUs
- * should be put in MADT but kept disabled.
- */
- apic->flags = cpu_to_le32(0);
- }
- }
- g_free(apic_ids);
-
- io_apic = acpi_data_push(table_data, sizeof *io_apic);
- io_apic->type = ACPI_APIC_IO;
- io_apic->length = sizeof(*io_apic);
-#define ACPI_BUILD_IOAPIC_ID 0x0
- io_apic->io_apic_id = ACPI_BUILD_IOAPIC_ID;
- io_apic->address = cpu_to_le32(IO_APIC_DEFAULT_ADDRESS);
- io_apic->interrupt = cpu_to_le32(0);
-
- if (pcms->apic_xrupt_override) {
- intsrcovr = acpi_data_push(table_data, sizeof *intsrcovr);
- intsrcovr->type = ACPI_APIC_XRUPT_OVERRIDE;
- intsrcovr->length = sizeof(*intsrcovr);
- intsrcovr->source = 0;
- intsrcovr->gsi = cpu_to_le32(2);
- intsrcovr->flags = cpu_to_le16(0); /* conforms to bus specifications */
- }
- for (i = 1; i < 16; i++) {
-#define ACPI_BUILD_PCI_IRQS ((1<<5) | (1<<9) | (1<<10) | (1<<11))
- if (!(ACPI_BUILD_PCI_IRQS & (1 << i))) {
- /* No need for a INT source override structure. */
- continue;
- }
- intsrcovr = acpi_data_push(table_data, sizeof *intsrcovr);
- intsrcovr->type = ACPI_APIC_XRUPT_OVERRIDE;
- intsrcovr->length = sizeof(*intsrcovr);
- intsrcovr->source = i;
- intsrcovr->gsi = cpu_to_le32(i);
- intsrcovr->flags = cpu_to_le16(0xd); /* active high, level triggered */
- }
-
- local_nmi = acpi_data_push(table_data, sizeof *local_nmi);
- local_nmi->type = ACPI_APIC_LOCAL_NMI;
- local_nmi->length = sizeof(*local_nmi);
- local_nmi->processor_id = 0xff; /* all processors */
- local_nmi->flags = cpu_to_le16(0);
- local_nmi->lint = 1; /* ACPI_LINT1 */
-
- build_header(linker, table_data,
- (void *)(table_data->data + madt_start), "APIC",
- table_data->len - madt_start, 1, NULL, NULL);
-}
-
-/* Assign BSEL property to all buses. In the future, this can be changed
- * to only assign to buses that support hotplug.
- */
-static void *acpi_set_bsel(PCIBus *bus, void *opaque)
-{
- unsigned *bsel_alloc = opaque;
- unsigned *bus_bsel;
-
- if (qbus_is_hotpluggable(BUS(bus))) {
- bus_bsel = g_malloc(sizeof *bus_bsel);
-
- *bus_bsel = (*bsel_alloc)++;
- object_property_add_uint32_ptr(OBJECT(bus), ACPI_PCIHP_PROP_BSEL,
- bus_bsel, NULL);
- }
-
- return bsel_alloc;
-}
-
-static void acpi_set_pci_info(void)
-{
- PCIBus *bus = find_i440fx(); /* TODO: Q35 support */
- unsigned bsel_alloc = 0;
-
- if (bus) {
- /* Scan all PCI buses. Set property to enable acpi based hotplug. */
- pci_for_each_bus_depth_first(bus, acpi_set_bsel, NULL, &bsel_alloc);
- }
-}
-
-static void build_append_pcihp_notify_entry(Aml *method, int slot)
-{
- Aml *if_ctx;
- int32_t devfn = PCI_DEVFN(slot, 0);
-
- if_ctx = aml_if(aml_and(aml_arg(0), aml_int(0x1U << slot), NULL));
- aml_append(if_ctx, aml_notify(aml_name("S%.02X", devfn), aml_arg(1)));
- aml_append(method, if_ctx);
-}
-
-static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus,
- bool pcihp_bridge_en)
-{
- Aml *dev, *notify_method, *method;
- QObject *bsel;
- PCIBus *sec;
- int i;
-
- bsel = object_property_get_qobject(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, NULL);
- if (bsel) {
- int64_t bsel_val = qint_get_int(qobject_to_qint(bsel));
-
- aml_append(parent_scope, aml_name_decl("BSEL", aml_int(bsel_val)));
- notify_method = aml_method("DVNT", 2, AML_NOTSERIALIZED);
- }
-
- for (i = 0; i < ARRAY_SIZE(bus->devices); i += PCI_FUNC_MAX) {
- DeviceClass *dc;
- PCIDeviceClass *pc;
- PCIDevice *pdev = bus->devices[i];
- int slot = PCI_SLOT(i);
- bool hotplug_enabled_dev;
- bool bridge_in_acpi;
-
- if (!pdev) {
- if (bsel) { /* add hotplug slots for non present devices */
- dev = aml_device("S%.02X", PCI_DEVFN(slot, 0));
- aml_append(dev, aml_name_decl("_SUN", aml_int(slot)));
- aml_append(dev, aml_name_decl("_ADR", aml_int(slot << 16)));
- method = aml_method("_EJ0", 1, AML_NOTSERIALIZED);
- aml_append(method,
- aml_call2("PCEJ", aml_name("BSEL"), aml_name("_SUN"))
- );
- aml_append(dev, method);
- aml_append(parent_scope, dev);
-
- build_append_pcihp_notify_entry(notify_method, slot);
- }
- continue;
- }
-
- pc = PCI_DEVICE_GET_CLASS(pdev);
- dc = DEVICE_GET_CLASS(pdev);
-
- /* When hotplug for bridges is enabled, bridges are
- * described in ACPI separately (see build_pci_bus_end).
- * In this case they aren't themselves hot-pluggable.
- * Hotplugged bridges *are* hot-pluggable.
- */
- bridge_in_acpi = pc->is_bridge && pcihp_bridge_en &&
- !DEVICE(pdev)->hotplugged;
-
- hotplug_enabled_dev = bsel && dc->hotpluggable && !bridge_in_acpi;
-
- if (pc->class_id == PCI_CLASS_BRIDGE_ISA) {
- continue;
- }
-
- /* start to compose PCI slot descriptor */
- dev = aml_device("S%.02X", PCI_DEVFN(slot, 0));
- aml_append(dev, aml_name_decl("_ADR", aml_int(slot << 16)));
-
- if (pc->class_id == PCI_CLASS_DISPLAY_VGA) {
- /* add VGA specific AML methods */
- int s3d;
-
- if (object_dynamic_cast(OBJECT(pdev), "qxl-vga")) {
- s3d = 3;
- } else {
- s3d = 0;
- }
-
- method = aml_method("_S1D", 0, AML_NOTSERIALIZED);
- aml_append(method, aml_return(aml_int(0)));
- aml_append(dev, method);
-
- method = aml_method("_S2D", 0, AML_NOTSERIALIZED);
- aml_append(method, aml_return(aml_int(0)));
- aml_append(dev, method);
-
- method = aml_method("_S3D", 0, AML_NOTSERIALIZED);
- aml_append(method, aml_return(aml_int(s3d)));
- aml_append(dev, method);
- } else if (hotplug_enabled_dev) {
- /* add _SUN/_EJ0 to make slot hotpluggable */
- aml_append(dev, aml_name_decl("_SUN", aml_int(slot)));
-
- method = aml_method("_EJ0", 1, AML_NOTSERIALIZED);
- aml_append(method,
- aml_call2("PCEJ", aml_name("BSEL"), aml_name("_SUN"))
- );
- aml_append(dev, method);
-
- if (bsel) {
- build_append_pcihp_notify_entry(notify_method, slot);
- }
- } else if (bridge_in_acpi) {
- /*
- * device is coldplugged bridge,
- * add child device descriptions into its scope
- */
- PCIBus *sec_bus = pci_bridge_get_sec_bus(PCI_BRIDGE(pdev));
-
- build_append_pci_bus_devices(dev, sec_bus, pcihp_bridge_en);
- }
- /* slot descriptor has been composed, add it into parent context */
- aml_append(parent_scope, dev);
- }
-
- if (bsel) {
- aml_append(parent_scope, notify_method);
- }
-
- /* Append PCNT method to notify about events on local and child buses.
- * Add unconditionally for root since DSDT expects it.
- */
- method = aml_method("PCNT", 0, AML_NOTSERIALIZED);
-
- /* If bus supports hotplug select it and notify about local events */
- if (bsel) {
- int64_t bsel_val = qint_get_int(qobject_to_qint(bsel));
- aml_append(method, aml_store(aml_int(bsel_val), aml_name("BNUM")));
- aml_append(method,
- aml_call2("DVNT", aml_name("PCIU"), aml_int(1) /* Device Check */)
- );
- aml_append(method,
- aml_call2("DVNT", aml_name("PCID"), aml_int(3)/* Eject Request */)
- );
- }
-
- /* Notify about child bus events in any case */
- if (pcihp_bridge_en) {
- QLIST_FOREACH(sec, &bus->child, sibling) {
- int32_t devfn = sec->parent_dev->devfn;
-
- aml_append(method, aml_name("^S%.02X.PCNT", devfn));
- }
- }
- aml_append(parent_scope, method);
- qobject_decref(bsel);
-}
-
-/**
- * build_prt_entry:
- * @link_name: link name for PCI route entry
- *
- * build AML package containing a PCI route entry for @link_name
- */
-static Aml *build_prt_entry(const char *link_name)
-{
- Aml *a_zero = aml_int(0);
- Aml *pkg = aml_package(4);
- aml_append(pkg, a_zero);
- aml_append(pkg, a_zero);
- aml_append(pkg, aml_name("%s", link_name));
- aml_append(pkg, a_zero);
- return pkg;
-}
-
-/*
- * initialize_route - Initialize the interrupt routing rule
- * through a specific LINK:
- * if (lnk_idx == idx)
- * route using link 'link_name'
- */
-static Aml *initialize_route(Aml *route, const char *link_name,
- Aml *lnk_idx, int idx)
-{
- Aml *if_ctx = aml_if(aml_equal(lnk_idx, aml_int(idx)));
- Aml *pkg = build_prt_entry(link_name);
-
- aml_append(if_ctx, aml_store(pkg, route));
-
- return if_ctx;
-}
-
-/*
- * build_prt - Define interrupt rounting rules
- *
- * Returns an array of 128 routes, one for each device,
- * based on device location.
- * The main goal is to equaly distribute the interrupts
- * over the 4 existing ACPI links (works only for i440fx).
- * The hash function is (slot + pin) & 3 -> "LNK[D|A|B|C]".
- *
- */
-static Aml *build_prt(bool is_pci0_prt)
-{
- Aml *method, *while_ctx, *pin, *res;
-
- method = aml_method("_PRT", 0, AML_NOTSERIALIZED);
- res = aml_local(0);
- pin = aml_local(1);
- aml_append(method, aml_store(aml_package(128), res));
- aml_append(method, aml_store(aml_int(0), pin));
-
- /* while (pin < 128) */
- while_ctx = aml_while(aml_lless(pin, aml_int(128)));
- {
- Aml *slot = aml_local(2);
- Aml *lnk_idx = aml_local(3);
- Aml *route = aml_local(4);
-
- /* slot = pin >> 2 */
- aml_append(while_ctx,
- aml_store(aml_shiftright(pin, aml_int(2), NULL), slot));
- /* lnk_idx = (slot + pin) & 3 */
- aml_append(while_ctx,
- aml_store(aml_and(aml_add(pin, slot, NULL), aml_int(3), NULL),
- lnk_idx));
-
- /* route[2] = "LNK[D|A|B|C]", selection based on pin % 3 */
- aml_append(while_ctx, initialize_route(route, "LNKD", lnk_idx, 0));
- if (is_pci0_prt) {
- Aml *if_device_1, *if_pin_4, *else_pin_4;
-
- /* device 1 is the power-management device, needs SCI */
- if_device_1 = aml_if(aml_equal(lnk_idx, aml_int(1)));
- {
- if_pin_4 = aml_if(aml_equal(pin, aml_int(4)));
- {
- aml_append(if_pin_4,
- aml_store(build_prt_entry("LNKS"), route));
- }
- aml_append(if_device_1, if_pin_4);
- else_pin_4 = aml_else();
- {
- aml_append(else_pin_4,
- aml_store(build_prt_entry("LNKA"), route));
- }
- aml_append(if_device_1, else_pin_4);
- }
- aml_append(while_ctx, if_device_1);
- } else {
- aml_append(while_ctx, initialize_route(route, "LNKA", lnk_idx, 1));
- }
- aml_append(while_ctx, initialize_route(route, "LNKB", lnk_idx, 2));
- aml_append(while_ctx, initialize_route(route, "LNKC", lnk_idx, 3));
-
- /* route[0] = 0x[slot]FFFF */
- aml_append(while_ctx,
- aml_store(aml_or(aml_shiftleft(slot, aml_int(16)), aml_int(0xFFFF),
- NULL),
- aml_index(route, aml_int(0))));
- /* route[1] = pin & 3 */
- aml_append(while_ctx,
- aml_store(aml_and(pin, aml_int(3), NULL),
- aml_index(route, aml_int(1))));
- /* res[pin] = route */
- aml_append(while_ctx, aml_store(route, aml_index(res, pin)));
- /* pin++ */
- aml_append(while_ctx, aml_increment(pin));
- }
- aml_append(method, while_ctx);
- /* return res*/
- aml_append(method, aml_return(res));
-
- return method;
-}
-
-typedef struct CrsRangeEntry {
- uint64_t base;
- uint64_t limit;
-} CrsRangeEntry;
-
-static void crs_range_insert(GPtrArray *ranges, uint64_t base, uint64_t limit)
-{
- CrsRangeEntry *entry;
-
- entry = g_malloc(sizeof(*entry));
- entry->base = base;
- entry->limit = limit;
-
- g_ptr_array_add(ranges, entry);
-}
-
-static void crs_range_free(gpointer data)
-{
- CrsRangeEntry *entry = (CrsRangeEntry *)data;
- g_free(entry);
-}
-
-static gint crs_range_compare(gconstpointer a, gconstpointer b)
-{
- CrsRangeEntry *entry_a = *(CrsRangeEntry **)a;
- CrsRangeEntry *entry_b = *(CrsRangeEntry **)b;
-
- return (int64_t)entry_a->base - (int64_t)entry_b->base;
-}
-
-/*
- * crs_replace_with_free_ranges - given the 'used' ranges within [start - end]
- * interval, computes the 'free' ranges from the same interval.
- * Example: If the input array is { [a1 - a2],[b1 - b2] }, the function
- * will return { [base - a1], [a2 - b1], [b2 - limit] }.
- */
-static void crs_replace_with_free_ranges(GPtrArray *ranges,
- uint64_t start, uint64_t end)
-{
- GPtrArray *free_ranges = g_ptr_array_new_with_free_func(crs_range_free);
- uint64_t free_base = start;
- int i;
-
- g_ptr_array_sort(ranges, crs_range_compare);
- for (i = 0; i < ranges->len; i++) {
- CrsRangeEntry *used = g_ptr_array_index(ranges, i);
-
- if (free_base < used->base) {
- crs_range_insert(free_ranges, free_base, used->base - 1);
- }
-
- free_base = used->limit + 1;
- }
-
- if (free_base < end) {
- crs_range_insert(free_ranges, free_base, end);
- }
-
- g_ptr_array_set_size(ranges, 0);
- for (i = 0; i < free_ranges->len; i++) {
- g_ptr_array_add(ranges, g_ptr_array_index(free_ranges, i));
- }
-
- g_ptr_array_free(free_ranges, false);
-}
-
-/*
- * crs_range_merge - merges adjacent ranges in the given array.
- * Array elements are deleted and replaced with the merged ranges.
- */
-static void crs_range_merge(GPtrArray *range)
-{
- GPtrArray *tmp = g_ptr_array_new_with_free_func(crs_range_free);
- CrsRangeEntry *entry;
- uint64_t range_base, range_limit;
- int i;
-
- if (!range->len) {
- return;
- }
-
- g_ptr_array_sort(range, crs_range_compare);
-
- entry = g_ptr_array_index(range, 0);
- range_base = entry->base;
- range_limit = entry->limit;
- for (i = 1; i < range->len; i++) {
- entry = g_ptr_array_index(range, i);
- if (entry->base - 1 == range_limit) {
- range_limit = entry->limit;
- } else {
- crs_range_insert(tmp, range_base, range_limit);
- range_base = entry->base;
- range_limit = entry->limit;
- }
- }
- crs_range_insert(tmp, range_base, range_limit);
-
- g_ptr_array_set_size(range, 0);
- for (i = 0; i < tmp->len; i++) {
- entry = g_ptr_array_index(tmp, i);
- crs_range_insert(range, entry->base, entry->limit);
- }
- g_ptr_array_free(tmp, true);
-}
-
-static Aml *build_crs(PCIHostState *host,
- GPtrArray *io_ranges, GPtrArray *mem_ranges)
-{
- Aml *crs = aml_resource_template();
- GPtrArray *host_io_ranges = g_ptr_array_new_with_free_func(crs_range_free);
- GPtrArray *host_mem_ranges = g_ptr_array_new_with_free_func(crs_range_free);
- CrsRangeEntry *entry;
- uint8_t max_bus = pci_bus_num(host->bus);
- uint8_t type;
- int devfn;
- int i;
-
- for (devfn = 0; devfn < ARRAY_SIZE(host->bus->devices); devfn++) {
- uint64_t range_base, range_limit;
- PCIDevice *dev = host->bus->devices[devfn];
-
- if (!dev) {
- continue;
- }
-
- for (i = 0; i < PCI_NUM_REGIONS; i++) {
- PCIIORegion *r = &dev->io_regions[i];
-
- range_base = r->addr;
- range_limit = r->addr + r->size - 1;
-
- /*
- * Work-around for old bioses
- * that do not support multiple root buses
- */
- if (!range_base || range_base > range_limit) {
- continue;
- }
-
- if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
- crs_range_insert(host_io_ranges, range_base, range_limit);
- } else { /* "memory" */
- crs_range_insert(host_mem_ranges, range_base, range_limit);
- }
- }
-
- type = dev->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION;
- if (type == PCI_HEADER_TYPE_BRIDGE) {
- uint8_t subordinate = dev->config[PCI_SUBORDINATE_BUS];
- if (subordinate > max_bus) {
- max_bus = subordinate;
- }
-
- range_base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO);
- range_limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_IO);
-
- /*
- * Work-around for old bioses
- * that do not support multiple root buses
- */
- if (range_base && range_base <= range_limit) {
- crs_range_insert(host_io_ranges, range_base, range_limit);
- }
-
- range_base =
- pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY);
- range_limit =
- pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY);
-
- /*
- * Work-around for old bioses
- * that do not support multiple root buses
- */
- if (range_base && range_base <= range_limit) {
- crs_range_insert(host_mem_ranges, range_base, range_limit);
- }
-
- range_base =
- pci_bridge_get_base(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
- range_limit =
- pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
-
- /*
- * Work-around for old bioses
- * that do not support multiple root buses
- */
- if (range_base && range_base <= range_limit) {
- crs_range_insert(host_mem_ranges, range_base, range_limit);
- }
- }
- }
-
- crs_range_merge(host_io_ranges);
- for (i = 0; i < host_io_ranges->len; i++) {
- entry = g_ptr_array_index(host_io_ranges, i);
- aml_append(crs,
- aml_word_io(AML_MIN_FIXED, AML_MAX_FIXED,
- AML_POS_DECODE, AML_ENTIRE_RANGE,
- 0, entry->base, entry->limit, 0,
- entry->limit - entry->base + 1));
- crs_range_insert(io_ranges, entry->base, entry->limit);
- }
- g_ptr_array_free(host_io_ranges, true);
-
- crs_range_merge(host_mem_ranges);
- for (i = 0; i < host_mem_ranges->len; i++) {
- entry = g_ptr_array_index(host_mem_ranges, i);
- aml_append(crs,
- aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED,
- AML_MAX_FIXED, AML_NON_CACHEABLE,
- AML_READ_WRITE,
- 0, entry->base, entry->limit, 0,
- entry->limit - entry->base + 1));
- crs_range_insert(mem_ranges, entry->base, entry->limit);
- }
- g_ptr_array_free(host_mem_ranges, true);
-
- aml_append(crs,
- aml_word_bus_number(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE,
- 0,
- pci_bus_num(host->bus),
- max_bus,
- 0,
- max_bus - pci_bus_num(host->bus) + 1));
-
- return crs;
-}
-
-static void build_processor_devices(Aml *sb_scope, MachineState *machine,
- AcpiPmInfo *pm)
-{
- int i, apic_idx;
- Aml *dev;
- Aml *crs;
- Aml *pkg;
- Aml *field;
- Aml *ifctx;
- Aml *method;
- MachineClass *mc = MACHINE_GET_CLASS(machine);
- CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids(machine);
- PCMachineState *pcms = PC_MACHINE(machine);
-
- /* The current AML generator can cover the APIC ID range [0..255],
- * inclusive, for VCPU hotplug. */
- QEMU_BUILD_BUG_ON(ACPI_CPU_HOTPLUG_ID_LIMIT > 256);
- g_assert(pcms->apic_id_limit <= ACPI_CPU_HOTPLUG_ID_LIMIT);
-
- /* create PCI0.PRES device and its _CRS to reserve CPU hotplug MMIO */
- dev = aml_device("PCI0." stringify(CPU_HOTPLUG_RESOURCE_DEVICE));
- aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A06")));
- aml_append(dev,
- aml_name_decl("_UID", aml_string("CPU Hotplug resources"))
- );
- /* device present, functioning, decoding, not shown in UI */
- aml_append(dev, aml_name_decl("_STA", aml_int(0xB)));
- crs = aml_resource_template();
- aml_append(crs,
- aml_io(AML_DECODE16, pm->cpu_hp_io_base, pm->cpu_hp_io_base, 1,
- pm->cpu_hp_io_len)
- );
- aml_append(dev, aml_name_decl("_CRS", crs));
- aml_append(sb_scope, dev);
- /* declare CPU hotplug MMIO region and PRS field to access it */
- aml_append(sb_scope, aml_operation_region(
- "PRST", AML_SYSTEM_IO, aml_int(pm->cpu_hp_io_base), pm->cpu_hp_io_len));
- field = aml_field("PRST", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE);
- aml_append(field, aml_named_field("PRS", 256));
- aml_append(sb_scope, field);
-
- /* build Processor object for each processor */
- for (i = 0; i < apic_ids->len; i++) {
- int apic_id = apic_ids->cpus[i].arch_id;
-
- assert(apic_id < ACPI_CPU_HOTPLUG_ID_LIMIT);
-
- dev = aml_processor(apic_id, 0, 0, "CP%.02X", apic_id);
-
- method = aml_method("_MAT", 0, AML_NOTSERIALIZED);
- aml_append(method,
- aml_return(aml_call1(CPU_MAT_METHOD, aml_int(apic_id))));
- aml_append(dev, method);
-
- method = aml_method("_STA", 0, AML_NOTSERIALIZED);
- aml_append(method,
- aml_return(aml_call1(CPU_STATUS_METHOD, aml_int(apic_id))));
- aml_append(dev, method);
-
- method = aml_method("_EJ0", 1, AML_NOTSERIALIZED);
- aml_append(method,
- aml_return(aml_call2(CPU_EJECT_METHOD, aml_int(apic_id),
- aml_arg(0)))
- );
- aml_append(dev, method);
-
- aml_append(sb_scope, dev);
- }
-
- /* build this code:
- * Method(NTFY, 2) {If (LEqual(Arg0, 0x00)) {Notify(CP00, Arg1)} ...}
- */
- /* Arg0 = Processor ID = APIC ID */
- method = aml_method(AML_NOTIFY_METHOD, 2, AML_NOTSERIALIZED);
- for (i = 0; i < apic_ids->len; i++) {
- int apic_id = apic_ids->cpus[i].arch_id;
-
- ifctx = aml_if(aml_equal(aml_arg(0), aml_int(apic_id)));
- aml_append(ifctx,
- aml_notify(aml_name("CP%.02X", apic_id), aml_arg(1))
- );
- aml_append(method, ifctx);
- }
- aml_append(sb_scope, method);
-
- /* build "Name(CPON, Package() { One, One, ..., Zero, Zero, ... })"
- *
- * Note: The ability to create variable-sized packages was first
- * introduced in ACPI 2.0. ACPI 1.0 only allowed fixed-size packages
- * ith up to 255 elements. Windows guests up to win2k8 fail when
- * VarPackageOp is used.
- */
- pkg = pcms->apic_id_limit <= 255 ? aml_package(pcms->apic_id_limit) :
- aml_varpackage(pcms->apic_id_limit);
-
- for (i = 0, apic_idx = 0; i < apic_ids->len; i++) {
- int apic_id = apic_ids->cpus[i].arch_id;
-
- for (; apic_idx < apic_id; apic_idx++) {
- aml_append(pkg, aml_int(0));
- }
- aml_append(pkg, aml_int(apic_ids->cpus[i].cpu ? 1 : 0));
- apic_idx = apic_id + 1;
- }
- aml_append(sb_scope, aml_name_decl(CPU_ON_BITMAP, pkg));
- g_free(apic_ids);
-}
-
-static void build_memory_devices(Aml *sb_scope, int nr_mem,
- uint16_t io_base, uint16_t io_len)
-{
- int i;
- Aml *scope;
- Aml *crs;
- Aml *field;
- Aml *dev;
- Aml *method;
- Aml *ifctx;
-
- /* build memory devices */
- assert(nr_mem <= ACPI_MAX_RAM_SLOTS);
- scope = aml_scope("\\_SB.PCI0." MEMORY_HOTPLUG_DEVICE);
- aml_append(scope,
- aml_name_decl(MEMORY_SLOTS_NUMBER, aml_int(nr_mem))
- );
-
- crs = aml_resource_template();
- aml_append(crs,
- aml_io(AML_DECODE16, io_base, io_base, 0, io_len)
- );
- aml_append(scope, aml_name_decl("_CRS", crs));
-
- aml_append(scope, aml_operation_region(
- MEMORY_HOTPLUG_IO_REGION, AML_SYSTEM_IO,
- aml_int(io_base), io_len)
- );
-
- field = aml_field(MEMORY_HOTPLUG_IO_REGION, AML_DWORD_ACC,
- AML_NOLOCK, AML_PRESERVE);
- aml_append(field, /* read only */
- aml_named_field(MEMORY_SLOT_ADDR_LOW, 32));
- aml_append(field, /* read only */
- aml_named_field(MEMORY_SLOT_ADDR_HIGH, 32));
- aml_append(field, /* read only */
- aml_named_field(MEMORY_SLOT_SIZE_LOW, 32));
- aml_append(field, /* read only */
- aml_named_field(MEMORY_SLOT_SIZE_HIGH, 32));
- aml_append(field, /* read only */
- aml_named_field(MEMORY_SLOT_PROXIMITY, 32));
- aml_append(scope, field);
-
- field = aml_field(MEMORY_HOTPLUG_IO_REGION, AML_BYTE_ACC,
- AML_NOLOCK, AML_WRITE_AS_ZEROS);
- aml_append(field, aml_reserved_field(160 /* bits, Offset(20) */));
- aml_append(field, /* 1 if enabled, read only */
- aml_named_field(MEMORY_SLOT_ENABLED, 1));
- aml_append(field,
- /*(read) 1 if has a insert event. (write) 1 to clear event */
- aml_named_field(MEMORY_SLOT_INSERT_EVENT, 1));
- aml_append(field,
- /* (read) 1 if has a remove event. (write) 1 to clear event */
- aml_named_field(MEMORY_SLOT_REMOVE_EVENT, 1));
- aml_append(field,
- /* initiates device eject, write only */
- aml_named_field(MEMORY_SLOT_EJECT, 1));
- aml_append(scope, field);
-
- field = aml_field(MEMORY_HOTPLUG_IO_REGION, AML_DWORD_ACC,
- AML_NOLOCK, AML_PRESERVE);
- aml_append(field, /* DIMM selector, write only */
- aml_named_field(MEMORY_SLOT_SLECTOR, 32));
- aml_append(field, /* _OST event code, write only */
- aml_named_field(MEMORY_SLOT_OST_EVENT, 32));
- aml_append(field, /* _OST status code, write only */
- aml_named_field(MEMORY_SLOT_OST_STATUS, 32));
- aml_append(scope, field);
- aml_append(sb_scope, scope);
-
- for (i = 0; i < nr_mem; i++) {
- #define BASEPATH "\\_SB.PCI0." MEMORY_HOTPLUG_DEVICE "."
- const char *s;
-
- dev = aml_device("MP%02X", i);
- aml_append(dev, aml_name_decl("_UID", aml_string("0x%02X", i)));
- aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C80")));
-
- method = aml_method("_CRS", 0, AML_NOTSERIALIZED);
- s = BASEPATH MEMORY_SLOT_CRS_METHOD;
- aml_append(method, aml_return(aml_call1(s, aml_name("_UID"))));
- aml_append(dev, method);
-
- method = aml_method("_STA", 0, AML_NOTSERIALIZED);
- s = BASEPATH MEMORY_SLOT_STATUS_METHOD;
- aml_append(method, aml_return(aml_call1(s, aml_name("_UID"))));
- aml_append(dev, method);
-
- method = aml_method("_PXM", 0, AML_NOTSERIALIZED);
- s = BASEPATH MEMORY_SLOT_PROXIMITY_METHOD;
- aml_append(method, aml_return(aml_call1(s, aml_name("_UID"))));
- aml_append(dev, method);
-
- method = aml_method("_OST", 3, AML_NOTSERIALIZED);
- s = BASEPATH MEMORY_SLOT_OST_METHOD;
-
- aml_append(method, aml_return(aml_call4(
- s, aml_name("_UID"), aml_arg(0), aml_arg(1), aml_arg(2)
- )));
- aml_append(dev, method);
-
- method = aml_method("_EJ0", 1, AML_NOTSERIALIZED);
- s = BASEPATH MEMORY_SLOT_EJECT_METHOD;
- aml_append(method, aml_return(aml_call2(
- s, aml_name("_UID"), aml_arg(0))));
- aml_append(dev, method);
-
- aml_append(sb_scope, dev);
- }
-
- /* build Method(MEMORY_SLOT_NOTIFY_METHOD, 2) {
- * If (LEqual(Arg0, 0x00)) {Notify(MP00, Arg1)} ... }
- */
- method = aml_method(MEMORY_SLOT_NOTIFY_METHOD, 2, AML_NOTSERIALIZED);
- for (i = 0; i < nr_mem; i++) {
- ifctx = aml_if(aml_equal(aml_arg(0), aml_int(i)));
- aml_append(ifctx,
- aml_notify(aml_name("MP%.02X", i), aml_arg(1))
- );
- aml_append(method, ifctx);
- }
- aml_append(sb_scope, method);
-}
-
-static void build_hpet_aml(Aml *table)
-{
- Aml *crs;
- Aml *field;
- Aml *method;
- Aml *if_ctx;
- Aml *scope = aml_scope("_SB");
- Aml *dev = aml_device("HPET");
- Aml *zero = aml_int(0);
- Aml *id = aml_local(0);
- Aml *period = aml_local(1);
-
- aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0103")));
- aml_append(dev, aml_name_decl("_UID", zero));
-
- aml_append(dev,
- aml_operation_region("HPTM", AML_SYSTEM_MEMORY, aml_int(HPET_BASE),
- HPET_LEN));
- field = aml_field("HPTM", AML_DWORD_ACC, AML_LOCK, AML_PRESERVE);
- aml_append(field, aml_named_field("VEND", 32));
- aml_append(field, aml_named_field("PRD", 32));
- aml_append(dev, field);
-
- method = aml_method("_STA", 0, AML_NOTSERIALIZED);
- aml_append(method, aml_store(aml_name("VEND"), id));
- aml_append(method, aml_store(aml_name("PRD"), period));
- aml_append(method, aml_shiftright(id, aml_int(16), id));
- if_ctx = aml_if(aml_lor(aml_equal(id, zero),
- aml_equal(id, aml_int(0xffff))));
- {
- aml_append(if_ctx, aml_return(zero));
- }
- aml_append(method, if_ctx);
-
- if_ctx = aml_if(aml_lor(aml_equal(period, zero),
- aml_lgreater(period, aml_int(100000000))));
- {
- aml_append(if_ctx, aml_return(zero));
- }
- aml_append(method, if_ctx);
-
- aml_append(method, aml_return(aml_int(0x0F)));
- aml_append(dev, method);
-
- crs = aml_resource_template();
- aml_append(crs, aml_memory32_fixed(HPET_BASE, HPET_LEN, AML_READ_ONLY));
- aml_append(dev, aml_name_decl("_CRS", crs));
-
- aml_append(scope, dev);
- aml_append(table, scope);
-}
-
-static Aml *build_fdinfo_aml(int idx, FloppyDriveType type)
-{
- Aml *dev, *fdi;
- uint8_t maxc, maxh, maxs;
-
- isa_fdc_get_drive_max_chs(type, &maxc, &maxh, &maxs);
-
- dev = aml_device("FLP%c", 'A' + idx);
-
- aml_append(dev, aml_name_decl("_ADR", aml_int(idx)));
-
- fdi = aml_package(16);
- aml_append(fdi, aml_int(idx)); /* Drive Number */
- aml_append(fdi,
- aml_int(cmos_get_fd_drive_type(type))); /* Device Type */
- /*
- * the values below are the limits of the drive, and are thus independent
- * of the inserted media
- */
- aml_append(fdi, aml_int(maxc)); /* Maximum Cylinder Number */
- aml_append(fdi, aml_int(maxs)); /* Maximum Sector Number */
- aml_append(fdi, aml_int(maxh)); /* Maximum Head Number */
- /*
- * SeaBIOS returns the below values for int 0x13 func 0x08 regardless of
- * the drive type, so shall we
- */
- aml_append(fdi, aml_int(0xAF)); /* disk_specify_1 */
- aml_append(fdi, aml_int(0x02)); /* disk_specify_2 */
- aml_append(fdi, aml_int(0x25)); /* disk_motor_wait */
- aml_append(fdi, aml_int(0x02)); /* disk_sector_siz */
- aml_append(fdi, aml_int(0x12)); /* disk_eot */
- aml_append(fdi, aml_int(0x1B)); /* disk_rw_gap */
- aml_append(fdi, aml_int(0xFF)); /* disk_dtl */
- aml_append(fdi, aml_int(0x6C)); /* disk_formt_gap */
- aml_append(fdi, aml_int(0xF6)); /* disk_fill */
- aml_append(fdi, aml_int(0x0F)); /* disk_head_sttl */
- aml_append(fdi, aml_int(0x08)); /* disk_motor_strt */
-
- aml_append(dev, aml_name_decl("_FDI", fdi));
- return dev;
-}
-
-static Aml *build_fdc_device_aml(ISADevice *fdc)
-{
- int i;
- Aml *dev;
- Aml *crs;
-
-#define ACPI_FDE_MAX_FD 4
- uint32_t fde_buf[5] = {
- 0, 0, 0, 0, /* presence of floppy drives #0 - #3 */
- cpu_to_le32(2) /* tape presence (2 == never present) */
- };
-
- dev = aml_device("FDC0");
- aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0700")));
-
- crs = aml_resource_template();
- aml_append(crs, aml_io(AML_DECODE16, 0x03F2, 0x03F2, 0x00, 0x04));
- aml_append(crs, aml_io(AML_DECODE16, 0x03F7, 0x03F7, 0x00, 0x01));
- aml_append(crs, aml_irq_no_flags(6));
- aml_append(crs,
- aml_dma(AML_COMPATIBILITY, AML_NOTBUSMASTER, AML_TRANSFER8, 2));
- aml_append(dev, aml_name_decl("_CRS", crs));
-
- for (i = 0; i < MIN(MAX_FD, ACPI_FDE_MAX_FD); i++) {
- FloppyDriveType type = isa_fdc_get_drive_type(fdc, i);
-
- if (type < FLOPPY_DRIVE_TYPE_NONE) {
- fde_buf[i] = cpu_to_le32(1); /* drive present */
- aml_append(dev, build_fdinfo_aml(i, type));
- }
- }
- aml_append(dev, aml_name_decl("_FDE",
- aml_buffer(sizeof(fde_buf), (uint8_t *)fde_buf)));
-
- return dev;
-}
-
-static Aml *build_rtc_device_aml(void)
-{
- Aml *dev;
- Aml *crs;
-
- dev = aml_device("RTC");
- aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0B00")));
- crs = aml_resource_template();
- aml_append(crs, aml_io(AML_DECODE16, 0x0070, 0x0070, 0x10, 0x02));
- aml_append(crs, aml_irq_no_flags(8));
- aml_append(crs, aml_io(AML_DECODE16, 0x0072, 0x0072, 0x02, 0x06));
- aml_append(dev, aml_name_decl("_CRS", crs));
-
- return dev;
-}
-
-static Aml *build_kbd_device_aml(void)
-{
- Aml *dev;
- Aml *crs;
- Aml *method;
-
- dev = aml_device("KBD");
- aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0303")));
-
- method = aml_method("_STA", 0, AML_NOTSERIALIZED);
- aml_append(method, aml_return(aml_int(0x0f)));
- aml_append(dev, method);
-
- crs = aml_resource_template();
- aml_append(crs, aml_io(AML_DECODE16, 0x0060, 0x0060, 0x01, 0x01));
- aml_append(crs, aml_io(AML_DECODE16, 0x0064, 0x0064, 0x01, 0x01));
- aml_append(crs, aml_irq_no_flags(1));
- aml_append(dev, aml_name_decl("_CRS", crs));
-
- return dev;
-}
-
-static Aml *build_mouse_device_aml(void)
-{
- Aml *dev;
- Aml *crs;
- Aml *method;
-
- dev = aml_device("MOU");
- aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0F13")));
-
- method = aml_method("_STA", 0, AML_NOTSERIALIZED);
- aml_append(method, aml_return(aml_int(0x0f)));
- aml_append(dev, method);
-
- crs = aml_resource_template();
- aml_append(crs, aml_irq_no_flags(12));
- aml_append(dev, aml_name_decl("_CRS", crs));
-
- return dev;
-}
-
-static Aml *build_lpt_device_aml(void)
-{
- Aml *dev;
- Aml *crs;
- Aml *method;
- Aml *if_ctx;
- Aml *else_ctx;
- Aml *zero = aml_int(0);
- Aml *is_present = aml_local(0);
-
- dev = aml_device("LPT");
- aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0400")));
-
- method = aml_method("_STA", 0, AML_NOTSERIALIZED);
- aml_append(method, aml_store(aml_name("LPEN"), is_present));
- if_ctx = aml_if(aml_equal(is_present, zero));
- {
- aml_append(if_ctx, aml_return(aml_int(0x00)));
- }
- aml_append(method, if_ctx);
- else_ctx = aml_else();
- {
- aml_append(else_ctx, aml_return(aml_int(0x0f)));
- }
- aml_append(method, else_ctx);
- aml_append(dev, method);
-
- crs = aml_resource_template();
- aml_append(crs, aml_io(AML_DECODE16, 0x0378, 0x0378, 0x08, 0x08));
- aml_append(crs, aml_irq_no_flags(7));
- aml_append(dev, aml_name_decl("_CRS", crs));
-
- return dev;
-}
-
-static Aml *build_com_device_aml(uint8_t uid)
-{
- Aml *dev;
- Aml *crs;
- Aml *method;
- Aml *if_ctx;
- Aml *else_ctx;
- Aml *zero = aml_int(0);
- Aml *is_present = aml_local(0);
- const char *enabled_field = "CAEN";
- uint8_t irq = 4;
- uint16_t io_port = 0x03F8;
-
- assert(uid == 1 || uid == 2);
- if (uid == 2) {
- enabled_field = "CBEN";
- irq = 3;
- io_port = 0x02F8;
- }
-
- dev = aml_device("COM%d", uid);
- aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0501")));
- aml_append(dev, aml_name_decl("_UID", aml_int(uid)));
-
- method = aml_method("_STA", 0, AML_NOTSERIALIZED);
- aml_append(method, aml_store(aml_name("%s", enabled_field), is_present));
- if_ctx = aml_if(aml_equal(is_present, zero));
- {
- aml_append(if_ctx, aml_return(aml_int(0x00)));
- }
- aml_append(method, if_ctx);
- else_ctx = aml_else();
- {
- aml_append(else_ctx, aml_return(aml_int(0x0f)));
- }
- aml_append(method, else_ctx);
- aml_append(dev, method);
-
- crs = aml_resource_template();
- aml_append(crs, aml_io(AML_DECODE16, io_port, io_port, 0x00, 0x08));
- aml_append(crs, aml_irq_no_flags(irq));
- aml_append(dev, aml_name_decl("_CRS", crs));
-
- return dev;
-}
-
-static void build_isa_devices_aml(Aml *table)
-{
- ISADevice *fdc = pc_find_fdc0();
-
- Aml *scope = aml_scope("_SB.PCI0.ISA");
-
- aml_append(scope, build_rtc_device_aml());
- aml_append(scope, build_kbd_device_aml());
- aml_append(scope, build_mouse_device_aml());
- if (fdc) {
- aml_append(scope, build_fdc_device_aml(fdc));
- }
- aml_append(scope, build_lpt_device_aml());
- aml_append(scope, build_com_device_aml(1));
- aml_append(scope, build_com_device_aml(2));
-
- aml_append(table, scope);
-}
-
-static void build_dbg_aml(Aml *table)
-{
- Aml *field;
- Aml *method;
- Aml *while_ctx;
- Aml *scope = aml_scope("\\");
- Aml *buf = aml_local(0);
- Aml *len = aml_local(1);
- Aml *idx = aml_local(2);
-
- aml_append(scope,
- aml_operation_region("DBG", AML_SYSTEM_IO, aml_int(0x0402), 0x01));
- field = aml_field("DBG", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE);
- aml_append(field, aml_named_field("DBGB", 8));
- aml_append(scope, field);
-
- method = aml_method("DBUG", 1, AML_NOTSERIALIZED);
-
- aml_append(method, aml_to_hexstring(aml_arg(0), buf));
- aml_append(method, aml_to_buffer(buf, buf));
- aml_append(method, aml_subtract(aml_sizeof(buf), aml_int(1), len));
- aml_append(method, aml_store(aml_int(0), idx));
-
- while_ctx = aml_while(aml_lless(idx, len));
- aml_append(while_ctx,
- aml_store(aml_derefof(aml_index(buf, idx)), aml_name("DBGB")));
- aml_append(while_ctx, aml_increment(idx));
- aml_append(method, while_ctx);
-
- aml_append(method, aml_store(aml_int(0x0A), aml_name("DBGB")));
- aml_append(scope, method);
-
- aml_append(table, scope);
-}
-
-static Aml *build_link_dev(const char *name, uint8_t uid, Aml *reg)
-{
- Aml *dev;
- Aml *crs;
- Aml *method;
- uint32_t irqs[] = {5, 10, 11};
-
- dev = aml_device("%s", name);
- aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C0F")));
- aml_append(dev, aml_name_decl("_UID", aml_int(uid)));
-
- crs = aml_resource_template();
- aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
- AML_SHARED, irqs, ARRAY_SIZE(irqs)));
- aml_append(dev, aml_name_decl("_PRS", crs));
-
- method = aml_method("_STA", 0, AML_NOTSERIALIZED);
- aml_append(method, aml_return(aml_call1("IQST", reg)));
- aml_append(dev, method);
-
- method = aml_method("_DIS", 0, AML_NOTSERIALIZED);
- aml_append(method, aml_or(reg, aml_int(0x80), reg));
- aml_append(dev, method);
-
- method = aml_method("_CRS", 0, AML_NOTSERIALIZED);
- aml_append(method, aml_return(aml_call1("IQCR", reg)));
- aml_append(dev, method);
-
- method = aml_method("_SRS", 1, AML_NOTSERIALIZED);
- aml_append(method, aml_create_dword_field(aml_arg(0), aml_int(5), "PRRI"));
- aml_append(method, aml_store(aml_name("PRRI"), reg));
- aml_append(dev, method);
-
- return dev;
- }
-
-static Aml *build_gsi_link_dev(const char *name, uint8_t uid, uint8_t gsi)
-{
- Aml *dev;
- Aml *crs;
- Aml *method;
- uint32_t irqs;
-
- dev = aml_device("%s", name);
- aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C0F")));
- aml_append(dev, aml_name_decl("_UID", aml_int(uid)));
-
- crs = aml_resource_template();
- irqs = gsi;
- aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
- AML_SHARED, &irqs, 1));
- aml_append(dev, aml_name_decl("_PRS", crs));
-
- aml_append(dev, aml_name_decl("_CRS", crs));
-
- /*
- * _DIS can be no-op because the interrupt cannot be disabled.
- */
- method = aml_method("_DIS", 0, AML_NOTSERIALIZED);
- aml_append(dev, method);
-
- method = aml_method("_SRS", 1, AML_NOTSERIALIZED);
- aml_append(dev, method);
-
- return dev;
-}
-
-/* _CRS method - get current settings */
-static Aml *build_iqcr_method(bool is_piix4)
-{
- Aml *if_ctx;
- uint32_t irqs;
- Aml *method = aml_method("IQCR", 1, AML_SERIALIZED);
- Aml *crs = aml_resource_template();
-
- irqs = 0;
- aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL,
- AML_ACTIVE_HIGH, AML_SHARED, &irqs, 1));
- aml_append(method, aml_name_decl("PRR0", crs));
-
- aml_append(method,
- aml_create_dword_field(aml_name("PRR0"), aml_int(5), "PRRI"));
-
- if (is_piix4) {
- if_ctx = aml_if(aml_lless(aml_arg(0), aml_int(0x80)));
- aml_append(if_ctx, aml_store(aml_arg(0), aml_name("PRRI")));
- aml_append(method, if_ctx);
- } else {
- aml_append(method,
- aml_store(aml_and(aml_arg(0), aml_int(0xF), NULL),
- aml_name("PRRI")));
- }
-
- aml_append(method, aml_return(aml_name("PRR0")));
- return method;
-}
-
-/* _STA method - get status */
-static Aml *build_irq_status_method(void)
-{
- Aml *if_ctx;
- Aml *method = aml_method("IQST", 1, AML_NOTSERIALIZED);
-
- if_ctx = aml_if(aml_and(aml_int(0x80), aml_arg(0), NULL));
- aml_append(if_ctx, aml_return(aml_int(0x09)));
- aml_append(method, if_ctx);
- aml_append(method, aml_return(aml_int(0x0B)));
- return method;
-}
-
-static void build_piix4_pci0_int(Aml *table)
-{
- Aml *dev;
- Aml *crs;
- Aml *field;
- Aml *method;
- uint32_t irqs;
- Aml *sb_scope = aml_scope("_SB");
- Aml *pci0_scope = aml_scope("PCI0");
-
- aml_append(pci0_scope, build_prt(true));
- aml_append(sb_scope, pci0_scope);
-
- field = aml_field("PCI0.ISA.P40C", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE);
- aml_append(field, aml_named_field("PRQ0", 8));
- aml_append(field, aml_named_field("PRQ1", 8));
- aml_append(field, aml_named_field("PRQ2", 8));
- aml_append(field, aml_named_field("PRQ3", 8));
- aml_append(sb_scope, field);
-
- aml_append(sb_scope, build_irq_status_method());
- aml_append(sb_scope, build_iqcr_method(true));
-
- aml_append(sb_scope, build_link_dev("LNKA", 0, aml_name("PRQ0")));
- aml_append(sb_scope, build_link_dev("LNKB", 1, aml_name("PRQ1")));
- aml_append(sb_scope, build_link_dev("LNKC", 2, aml_name("PRQ2")));
- aml_append(sb_scope, build_link_dev("LNKD", 3, aml_name("PRQ3")));
-
- dev = aml_device("LNKS");
- {
- aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C0F")));
- aml_append(dev, aml_name_decl("_UID", aml_int(4)));
-
- crs = aml_resource_template();
- irqs = 9;
- aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL,
- AML_ACTIVE_HIGH, AML_SHARED,
- &irqs, 1));
- aml_append(dev, aml_name_decl("_PRS", crs));
-
- /* The SCI cannot be disabled and is always attached to GSI 9,
- * so these are no-ops. We only need this link to override the
- * polarity to active high and match the content of the MADT.
- */
- method = aml_method("_STA", 0, AML_NOTSERIALIZED);
- aml_append(method, aml_return(aml_int(0x0b)));
- aml_append(dev, method);
-
- method = aml_method("_DIS", 0, AML_NOTSERIALIZED);
- aml_append(dev, method);
-
- method = aml_method("_CRS", 0, AML_NOTSERIALIZED);
- aml_append(method, aml_return(aml_name("_PRS")));
- aml_append(dev, method);
-
- method = aml_method("_SRS", 1, AML_NOTSERIALIZED);
- aml_append(dev, method);
- }
- aml_append(sb_scope, dev);
-
- aml_append(table, sb_scope);
-}
-
-static void append_q35_prt_entry(Aml *ctx, uint32_t nr, const char *name)
-{
- int i;
- int head;
- Aml *pkg;
- char base = name[3] < 'E' ? 'A' : 'E';
- char *s = g_strdup(name);
- Aml *a_nr = aml_int((nr << 16) | 0xffff);
-
- assert(strlen(s) == 4);
-
- head = name[3] - base;
- for (i = 0; i < 4; i++) {
- if (head + i > 3) {
- head = i * -1;
- }
- s[3] = base + head + i;
- pkg = aml_package(4);
- aml_append(pkg, a_nr);
- aml_append(pkg, aml_int(i));
- aml_append(pkg, aml_name("%s", s));
- aml_append(pkg, aml_int(0));
- aml_append(ctx, pkg);
- }
- g_free(s);
-}
-
-static Aml *build_q35_routing_table(const char *str)
-{
- int i;
- Aml *pkg;
- char *name = g_strdup_printf("%s ", str);
-
- pkg = aml_package(128);
- for (i = 0; i < 0x18; i++) {
- name[3] = 'E' + (i & 0x3);
- append_q35_prt_entry(pkg, i, name);
- }
-
- name[3] = 'E';
- append_q35_prt_entry(pkg, 0x18, name);
-
- /* INTA -> PIRQA for slot 25 - 31, see the default value of D<N>IR */
- for (i = 0x0019; i < 0x1e; i++) {
- name[3] = 'A';
- append_q35_prt_entry(pkg, i, name);
- }
-
- /* PCIe->PCI bridge. use PIRQ[E-H] */
- name[3] = 'E';
- append_q35_prt_entry(pkg, 0x1e, name);
- name[3] = 'A';
- append_q35_prt_entry(pkg, 0x1f, name);
-
- g_free(name);
- return pkg;
-}
-
-static void build_q35_pci0_int(Aml *table)
-{
- Aml *field;
- Aml *method;
- Aml *sb_scope = aml_scope("_SB");
- Aml *pci0_scope = aml_scope("PCI0");
-
- /* Zero => PIC mode, One => APIC Mode */
- aml_append(table, aml_name_decl("PICF", aml_int(0)));
- method = aml_method("_PIC", 1, AML_NOTSERIALIZED);
- {
- aml_append(method, aml_store(aml_arg(0), aml_name("PICF")));
- }
- aml_append(table, method);
-
- aml_append(pci0_scope,
- aml_name_decl("PRTP", build_q35_routing_table("LNK")));
- aml_append(pci0_scope,
- aml_name_decl("PRTA", build_q35_routing_table("GSI")));
-
- method = aml_method("_PRT", 0, AML_NOTSERIALIZED);
- {
- Aml *if_ctx;
- Aml *else_ctx;
-
- /* PCI IRQ routing table, example from ACPI 2.0a specification,
- section 6.2.8.1 */
- /* Note: we provide the same info as the PCI routing
- table of the Bochs BIOS */
- if_ctx = aml_if(aml_equal(aml_name("PICF"), aml_int(0)));
- aml_append(if_ctx, aml_return(aml_name("PRTP")));
- aml_append(method, if_ctx);
- else_ctx = aml_else();
- aml_append(else_ctx, aml_return(aml_name("PRTA")));
- aml_append(method, else_ctx);
- }
- aml_append(pci0_scope, method);
- aml_append(sb_scope, pci0_scope);
-
- field = aml_field("PCI0.ISA.PIRQ", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE);
- aml_append(field, aml_named_field("PRQA", 8));
- aml_append(field, aml_named_field("PRQB", 8));
- aml_append(field, aml_named_field("PRQC", 8));
- aml_append(field, aml_named_field("PRQD", 8));
- aml_append(field, aml_reserved_field(0x20));
- aml_append(field, aml_named_field("PRQE", 8));
- aml_append(field, aml_named_field("PRQF", 8));
- aml_append(field, aml_named_field("PRQG", 8));
- aml_append(field, aml_named_field("PRQH", 8));
- aml_append(sb_scope, field);
-
- aml_append(sb_scope, build_irq_status_method());
- aml_append(sb_scope, build_iqcr_method(false));
-
- aml_append(sb_scope, build_link_dev("LNKA", 0, aml_name("PRQA")));
- aml_append(sb_scope, build_link_dev("LNKB", 1, aml_name("PRQB")));
- aml_append(sb_scope, build_link_dev("LNKC", 2, aml_name("PRQC")));
- aml_append(sb_scope, build_link_dev("LNKD", 3, aml_name("PRQD")));
- aml_append(sb_scope, build_link_dev("LNKE", 4, aml_name("PRQE")));
- aml_append(sb_scope, build_link_dev("LNKF", 5, aml_name("PRQF")));
- aml_append(sb_scope, build_link_dev("LNKG", 6, aml_name("PRQG")));
- aml_append(sb_scope, build_link_dev("LNKH", 7, aml_name("PRQH")));
-
- aml_append(sb_scope, build_gsi_link_dev("GSIA", 0x10, 0x10));
- aml_append(sb_scope, build_gsi_link_dev("GSIB", 0x11, 0x11));
- aml_append(sb_scope, build_gsi_link_dev("GSIC", 0x12, 0x12));
- aml_append(sb_scope, build_gsi_link_dev("GSID", 0x13, 0x13));
- aml_append(sb_scope, build_gsi_link_dev("GSIE", 0x14, 0x14));
- aml_append(sb_scope, build_gsi_link_dev("GSIF", 0x15, 0x15));
- aml_append(sb_scope, build_gsi_link_dev("GSIG", 0x16, 0x16));
- aml_append(sb_scope, build_gsi_link_dev("GSIH", 0x17, 0x17));
-
- aml_append(table, sb_scope);
-}
-
-static void build_q35_isa_bridge(Aml *table)
-{
- Aml *dev;
- Aml *scope;
- Aml *field;
-
- scope = aml_scope("_SB.PCI0");
- dev = aml_device("ISA");
- aml_append(dev, aml_name_decl("_ADR", aml_int(0x001F0000)));
-
- /* ICH9 PCI to ISA irq remapping */
- aml_append(dev, aml_operation_region("PIRQ", AML_PCI_CONFIG,
- aml_int(0x60), 0x0C));
-
- aml_append(dev, aml_operation_region("LPCD", AML_PCI_CONFIG,
- aml_int(0x80), 0x02));
- field = aml_field("LPCD", AML_ANY_ACC, AML_NOLOCK, AML_PRESERVE);
- aml_append(field, aml_named_field("COMA", 3));
- aml_append(field, aml_reserved_field(1));
- aml_append(field, aml_named_field("COMB", 3));
- aml_append(field, aml_reserved_field(1));
- aml_append(field, aml_named_field("LPTD", 2));
- aml_append(dev, field);
-
- aml_append(dev, aml_operation_region("LPCE", AML_PCI_CONFIG,
- aml_int(0x82), 0x02));
- /* enable bits */
- field = aml_field("LPCE", AML_ANY_ACC, AML_NOLOCK, AML_PRESERVE);
- aml_append(field, aml_named_field("CAEN", 1));
- aml_append(field, aml_named_field("CBEN", 1));
- aml_append(field, aml_named_field("LPEN", 1));
- aml_append(dev, field);
-
- aml_append(scope, dev);
- aml_append(table, scope);
-}
-
-static void build_piix4_pm(Aml *table)
-{
- Aml *dev;
- Aml *scope;
-
- scope = aml_scope("_SB.PCI0");
- dev = aml_device("PX13");
- aml_append(dev, aml_name_decl("_ADR", aml_int(0x00010003)));
-
- aml_append(dev, aml_operation_region("P13C", AML_PCI_CONFIG,
- aml_int(0x00), 0xff));
- aml_append(scope, dev);
- aml_append(table, scope);
-}
-
-static void build_piix4_isa_bridge(Aml *table)
-{
- Aml *dev;
- Aml *scope;
- Aml *field;
-
- scope = aml_scope("_SB.PCI0");
- dev = aml_device("ISA");
- aml_append(dev, aml_name_decl("_ADR", aml_int(0x00010000)));
-
- /* PIIX PCI to ISA irq remapping */
- aml_append(dev, aml_operation_region("P40C", AML_PCI_CONFIG,
- aml_int(0x60), 0x04));
- /* enable bits */
- field = aml_field("^PX13.P13C", AML_ANY_ACC, AML_NOLOCK, AML_PRESERVE);
- /* Offset(0x5f),, 7, */
- aml_append(field, aml_reserved_field(0x2f8));
- aml_append(field, aml_reserved_field(7));
- aml_append(field, aml_named_field("LPEN", 1));
- /* Offset(0x67),, 3, */
- aml_append(field, aml_reserved_field(0x38));
- aml_append(field, aml_reserved_field(3));
- aml_append(field, aml_named_field("CAEN", 1));
- aml_append(field, aml_reserved_field(3));
- aml_append(field, aml_named_field("CBEN", 1));
- aml_append(dev, field);
-
- aml_append(scope, dev);
- aml_append(table, scope);
-}
-
-static void build_piix4_pci_hotplug(Aml *table)
-{
- Aml *scope;
- Aml *field;
- Aml *method;
-
- scope = aml_scope("_SB.PCI0");
-
- aml_append(scope,
- aml_operation_region("PCST", AML_SYSTEM_IO, aml_int(0xae00), 0x08));
- field = aml_field("PCST", AML_DWORD_ACC, AML_NOLOCK, AML_WRITE_AS_ZEROS);
- aml_append(field, aml_named_field("PCIU", 32));
- aml_append(field, aml_named_field("PCID", 32));
- aml_append(scope, field);
-
- aml_append(scope,
- aml_operation_region("SEJ", AML_SYSTEM_IO, aml_int(0xae08), 0x04));
- field = aml_field("SEJ", AML_DWORD_ACC, AML_NOLOCK, AML_WRITE_AS_ZEROS);
- aml_append(field, aml_named_field("B0EJ", 32));
- aml_append(scope, field);
-
- aml_append(scope,
- aml_operation_region("BNMR", AML_SYSTEM_IO, aml_int(0xae10), 0x04));
- field = aml_field("BNMR", AML_DWORD_ACC, AML_NOLOCK, AML_WRITE_AS_ZEROS);
- aml_append(field, aml_named_field("BNUM", 32));
- aml_append(scope, field);
-
- aml_append(scope, aml_mutex("BLCK", 0));
-
- method = aml_method("PCEJ", 2, AML_NOTSERIALIZED);
- aml_append(method, aml_acquire(aml_name("BLCK"), 0xFFFF));
- aml_append(method, aml_store(aml_arg(0), aml_name("BNUM")));
- aml_append(method,
- aml_store(aml_shiftleft(aml_int(1), aml_arg(1)), aml_name("B0EJ")));
- aml_append(method, aml_release(aml_name("BLCK")));
- aml_append(method, aml_return(aml_int(0)));
- aml_append(scope, method);
-
- aml_append(table, scope);
-}
-
-static Aml *build_q35_osc_method(void)
-{
- Aml *if_ctx;
- Aml *if_ctx2;
- Aml *else_ctx;
- Aml *method;
- Aml *a_cwd1 = aml_name("CDW1");
- Aml *a_ctrl = aml_name("CTRL");
-
- method = aml_method("_OSC", 4, AML_NOTSERIALIZED);
- aml_append(method, aml_create_dword_field(aml_arg(3), aml_int(0), "CDW1"));
-
- if_ctx = aml_if(aml_equal(
- aml_arg(0), aml_touuid("33DB4D5B-1FF7-401C-9657-7441C03DD766")));
- aml_append(if_ctx, aml_create_dword_field(aml_arg(3), aml_int(4), "CDW2"));
- aml_append(if_ctx, aml_create_dword_field(aml_arg(3), aml_int(8), "CDW3"));
-
- aml_append(if_ctx, aml_store(aml_name("CDW2"), aml_name("SUPP")));
- aml_append(if_ctx, aml_store(aml_name("CDW3"), a_ctrl));
-
- /*
- * Always allow native PME, AER (no dependencies)
- * Never allow SHPC (no SHPC controller in this system)
- */
- aml_append(if_ctx, aml_and(a_ctrl, aml_int(0x1D), a_ctrl));
-
- if_ctx2 = aml_if(aml_lnot(aml_equal(aml_arg(1), aml_int(1))));
- /* Unknown revision */
- aml_append(if_ctx2, aml_or(a_cwd1, aml_int(0x08), a_cwd1));
- aml_append(if_ctx, if_ctx2);
-
- if_ctx2 = aml_if(aml_lnot(aml_equal(aml_name("CDW3"), a_ctrl)));
- /* Capabilities bits were masked */
- aml_append(if_ctx2, aml_or(a_cwd1, aml_int(0x10), a_cwd1));
- aml_append(if_ctx, if_ctx2);
-
- /* Update DWORD3 in the buffer */
- aml_append(if_ctx, aml_store(a_ctrl, aml_name("CDW3")));
- aml_append(method, if_ctx);
-
- else_ctx = aml_else();
- /* Unrecognized UUID */
- aml_append(else_ctx, aml_or(a_cwd1, aml_int(4), a_cwd1));
- aml_append(method, else_ctx);
-
- aml_append(method, aml_return(aml_arg(3)));
- return method;
-}
-
-static void
-build_dsdt(GArray *table_data, GArray *linker,
- AcpiPmInfo *pm, AcpiMiscInfo *misc,
- PcPciInfo *pci, MachineState *machine)
-{
- CrsRangeEntry *entry;
- Aml *dsdt, *sb_scope, *scope, *dev, *method, *field, *pkg, *crs;
- GPtrArray *mem_ranges = g_ptr_array_new_with_free_func(crs_range_free);
- GPtrArray *io_ranges = g_ptr_array_new_with_free_func(crs_range_free);
- PCMachineState *pcms = PC_MACHINE(machine);
- uint32_t nr_mem = machine->ram_slots;
- int root_bus_limit = 0xFF;
- PCIBus *bus = NULL;
- int i;
-
- dsdt = init_aml_allocator();
-
- /* Reserve space for header */
- acpi_data_push(dsdt->buf, sizeof(AcpiTableHeader));
-
- build_dbg_aml(dsdt);
- if (misc->is_piix4) {
- sb_scope = aml_scope("_SB");
- dev = aml_device("PCI0");
- aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A03")));
- aml_append(dev, aml_name_decl("_ADR", aml_int(0)));
- aml_append(dev, aml_name_decl("_UID", aml_int(1)));
- aml_append(sb_scope, dev);
- aml_append(dsdt, sb_scope);
-
- build_hpet_aml(dsdt);
- build_piix4_pm(dsdt);
- build_piix4_isa_bridge(dsdt);
- build_isa_devices_aml(dsdt);
- build_piix4_pci_hotplug(dsdt);
- build_piix4_pci0_int(dsdt);
- } else {
- sb_scope = aml_scope("_SB");
- aml_append(sb_scope,
- aml_operation_region("PCST", AML_SYSTEM_IO, aml_int(0xae00), 0x0c));
- aml_append(sb_scope,
- aml_operation_region("PCSB", AML_SYSTEM_IO, aml_int(0xae0c), 0x01));
- field = aml_field("PCSB", AML_ANY_ACC, AML_NOLOCK, AML_WRITE_AS_ZEROS);
- aml_append(field, aml_named_field("PCIB", 8));
- aml_append(sb_scope, field);
- aml_append(dsdt, sb_scope);
-
- sb_scope = aml_scope("_SB");
- dev = aml_device("PCI0");
- aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A08")));
- aml_append(dev, aml_name_decl("_CID", aml_eisaid("PNP0A03")));
- aml_append(dev, aml_name_decl("_ADR", aml_int(0)));
- aml_append(dev, aml_name_decl("_UID", aml_int(1)));
- aml_append(dev, aml_name_decl("SUPP", aml_int(0)));
- aml_append(dev, aml_name_decl("CTRL", aml_int(0)));
- aml_append(dev, build_q35_osc_method());
- aml_append(sb_scope, dev);
- aml_append(dsdt, sb_scope);
-
- build_hpet_aml(dsdt);
- build_q35_isa_bridge(dsdt);
- build_isa_devices_aml(dsdt);
- build_q35_pci0_int(dsdt);
- }
-
- build_cpu_hotplug_aml(dsdt);
- build_memory_hotplug_aml(dsdt, nr_mem, pm->mem_hp_io_base,
- pm->mem_hp_io_len);
-
- scope = aml_scope("_GPE");
- {
- aml_append(scope, aml_name_decl("_HID", aml_string("ACPI0006")));
-
- aml_append(scope, aml_method("_L00", 0, AML_NOTSERIALIZED));
-
- if (misc->is_piix4) {
- method = aml_method("_E01", 0, AML_NOTSERIALIZED);
- aml_append(method,
- aml_acquire(aml_name("\\_SB.PCI0.BLCK"), 0xFFFF));
- aml_append(method, aml_call0("\\_SB.PCI0.PCNT"));
- aml_append(method, aml_release(aml_name("\\_SB.PCI0.BLCK")));
- aml_append(scope, method);
- } else {
- aml_append(scope, aml_method("_L01", 0, AML_NOTSERIALIZED));
- }
-
- method = aml_method("_E02", 0, AML_NOTSERIALIZED);
- aml_append(method, aml_call0("\\_SB." CPU_SCAN_METHOD));
- aml_append(scope, method);
-
- method = aml_method("_E03", 0, AML_NOTSERIALIZED);
- aml_append(method, aml_call0(MEMORY_HOTPLUG_HANDLER_PATH));
- aml_append(scope, method);
-
- aml_append(scope, aml_method("_L04", 0, AML_NOTSERIALIZED));
- aml_append(scope, aml_method("_L05", 0, AML_NOTSERIALIZED));
- aml_append(scope, aml_method("_L06", 0, AML_NOTSERIALIZED));
- aml_append(scope, aml_method("_L07", 0, AML_NOTSERIALIZED));
- aml_append(scope, aml_method("_L08", 0, AML_NOTSERIALIZED));
- aml_append(scope, aml_method("_L09", 0, AML_NOTSERIALIZED));
- aml_append(scope, aml_method("_L0A", 0, AML_NOTSERIALIZED));
- aml_append(scope, aml_method("_L0B", 0, AML_NOTSERIALIZED));
- aml_append(scope, aml_method("_L0C", 0, AML_NOTSERIALIZED));
- aml_append(scope, aml_method("_L0D", 0, AML_NOTSERIALIZED));
- aml_append(scope, aml_method("_L0E", 0, AML_NOTSERIALIZED));
- aml_append(scope, aml_method("_L0F", 0, AML_NOTSERIALIZED));
- }
- aml_append(dsdt, scope);
-
- bus = PC_MACHINE(machine)->bus;
- if (bus) {
- QLIST_FOREACH(bus, &bus->child, sibling) {
- uint8_t bus_num = pci_bus_num(bus);
- uint8_t numa_node = pci_bus_numa_node(bus);
-
- /* look only for expander root buses */
- if (!pci_bus_is_root(bus)) {
- continue;
- }
-
- if (bus_num < root_bus_limit) {
- root_bus_limit = bus_num - 1;
- }
-
- scope = aml_scope("\\_SB");
- dev = aml_device("PC%.02X", bus_num);
- aml_append(dev, aml_name_decl("_UID", aml_int(bus_num)));
- aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A03")));
- aml_append(dev, aml_name_decl("_BBN", aml_int(bus_num)));
-
- if (numa_node != NUMA_NODE_UNASSIGNED) {
- aml_append(dev, aml_name_decl("_PXM", aml_int(numa_node)));
- }
-
- aml_append(dev, build_prt(false));
- crs = build_crs(PCI_HOST_BRIDGE(BUS(bus)->parent),
- io_ranges, mem_ranges);
- aml_append(dev, aml_name_decl("_CRS", crs));
- aml_append(scope, dev);
- aml_append(dsdt, scope);
- }
- }
-
- scope = aml_scope("\\_SB.PCI0");
- /* build PCI0._CRS */
- crs = aml_resource_template();
- aml_append(crs,
- aml_word_bus_number(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE,
- 0x0000, 0x0, root_bus_limit,
- 0x0000, root_bus_limit + 1));
- aml_append(crs, aml_io(AML_DECODE16, 0x0CF8, 0x0CF8, 0x01, 0x08));
-
- aml_append(crs,
- aml_word_io(AML_MIN_FIXED, AML_MAX_FIXED,
- AML_POS_DECODE, AML_ENTIRE_RANGE,
- 0x0000, 0x0000, 0x0CF7, 0x0000, 0x0CF8));
-
- crs_replace_with_free_ranges(io_ranges, 0x0D00, 0xFFFF);
- for (i = 0; i < io_ranges->len; i++) {
- entry = g_ptr_array_index(io_ranges, i);
- aml_append(crs,
- aml_word_io(AML_MIN_FIXED, AML_MAX_FIXED,
- AML_POS_DECODE, AML_ENTIRE_RANGE,
- 0x0000, entry->base, entry->limit,
- 0x0000, entry->limit - entry->base + 1));
- }
-
- aml_append(crs,
- aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
- AML_CACHEABLE, AML_READ_WRITE,
- 0, 0x000A0000, 0x000BFFFF, 0, 0x00020000));
-
- crs_replace_with_free_ranges(mem_ranges, pci->w32.begin, pci->w32.end - 1);
- for (i = 0; i < mem_ranges->len; i++) {
- entry = g_ptr_array_index(mem_ranges, i);
- aml_append(crs,
- aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
- AML_NON_CACHEABLE, AML_READ_WRITE,
- 0, entry->base, entry->limit,
- 0, entry->limit - entry->base + 1));
- }
-
- if (pci->w64.begin) {
- aml_append(crs,
- aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
- AML_CACHEABLE, AML_READ_WRITE,
- 0, pci->w64.begin, pci->w64.end - 1, 0,
- pci->w64.end - pci->w64.begin));
- }
-
- if (misc->tpm_version != TPM_VERSION_UNSPEC) {
- aml_append(crs, aml_memory32_fixed(TPM_TIS_ADDR_BASE,
- TPM_TIS_ADDR_SIZE, AML_READ_WRITE));
- }
- aml_append(scope, aml_name_decl("_CRS", crs));
-
- /* reserve GPE0 block resources */
- dev = aml_device("GPE0");
- aml_append(dev, aml_name_decl("_HID", aml_string("PNP0A06")));
- aml_append(dev, aml_name_decl("_UID", aml_string("GPE0 resources")));
- /* device present, functioning, decoding, not shown in UI */
- aml_append(dev, aml_name_decl("_STA", aml_int(0xB)));
- crs = aml_resource_template();
- aml_append(crs,
- aml_io(AML_DECODE16, pm->gpe0_blk, pm->gpe0_blk, 1, pm->gpe0_blk_len)
- );
- aml_append(dev, aml_name_decl("_CRS", crs));
- aml_append(scope, dev);
-
- g_ptr_array_free(io_ranges, true);
- g_ptr_array_free(mem_ranges, true);
-
- /* reserve PCIHP resources */
- if (pm->pcihp_io_len) {
- dev = aml_device("PHPR");
- aml_append(dev, aml_name_decl("_HID", aml_string("PNP0A06")));
- aml_append(dev,
- aml_name_decl("_UID", aml_string("PCI Hotplug resources")));
- /* device present, functioning, decoding, not shown in UI */
- aml_append(dev, aml_name_decl("_STA", aml_int(0xB)));
- crs = aml_resource_template();
- aml_append(crs,
- aml_io(AML_DECODE16, pm->pcihp_io_base, pm->pcihp_io_base, 1,
- pm->pcihp_io_len)
- );
- aml_append(dev, aml_name_decl("_CRS", crs));
- aml_append(scope, dev);
- }
- aml_append(dsdt, scope);
-
- /* create S3_ / S4_ / S5_ packages if necessary */
- scope = aml_scope("\\");
- if (!pm->s3_disabled) {
- pkg = aml_package(4);
- aml_append(pkg, aml_int(1)); /* PM1a_CNT.SLP_TYP */
- aml_append(pkg, aml_int(1)); /* PM1b_CNT.SLP_TYP, FIXME: not impl. */
- aml_append(pkg, aml_int(0)); /* reserved */
- aml_append(pkg, aml_int(0)); /* reserved */
- aml_append(scope, aml_name_decl("_S3", pkg));
- }
-
- if (!pm->s4_disabled) {
- pkg = aml_package(4);
- aml_append(pkg, aml_int(pm->s4_val)); /* PM1a_CNT.SLP_TYP */
- /* PM1b_CNT.SLP_TYP, FIXME: not impl. */
- aml_append(pkg, aml_int(pm->s4_val));
- aml_append(pkg, aml_int(0)); /* reserved */
- aml_append(pkg, aml_int(0)); /* reserved */
- aml_append(scope, aml_name_decl("_S4", pkg));
- }
-
- pkg = aml_package(4);
- aml_append(pkg, aml_int(0)); /* PM1a_CNT.SLP_TYP */
- aml_append(pkg, aml_int(0)); /* PM1b_CNT.SLP_TYP not impl. */
- aml_append(pkg, aml_int(0)); /* reserved */
- aml_append(pkg, aml_int(0)); /* reserved */
- aml_append(scope, aml_name_decl("_S5", pkg));
- aml_append(dsdt, scope);
-
- /* create fw_cfg node, unconditionally */
- {
- /* when using port i/o, the 8-bit data register *always* overlaps
- * with half of the 16-bit control register. Hence, the total size
- * of the i/o region used is FW_CFG_CTL_SIZE; when using DMA, the
- * DMA control register is located at FW_CFG_DMA_IO_BASE + 4 */
- uint8_t io_size = object_property_get_bool(OBJECT(pcms->fw_cfg),
- "dma_enabled", NULL) ?
- ROUND_UP(FW_CFG_CTL_SIZE, 4) + sizeof(dma_addr_t) :
- FW_CFG_CTL_SIZE;
-
- scope = aml_scope("\\_SB.PCI0");
- dev = aml_device("FWCF");
-
- aml_append(dev, aml_name_decl("_HID", aml_string("QEMU0002")));
-
- /* device present, functioning, decoding, not shown in UI */
- aml_append(dev, aml_name_decl("_STA", aml_int(0xB)));
-
- crs = aml_resource_template();
- aml_append(crs,
- aml_io(AML_DECODE16, FW_CFG_IO_BASE, FW_CFG_IO_BASE, 0x01, io_size)
- );
- aml_append(dev, aml_name_decl("_CRS", crs));
-
- aml_append(scope, dev);
- aml_append(dsdt, scope);
- }
-
- if (misc->applesmc_io_base) {
- scope = aml_scope("\\_SB.PCI0.ISA");
- dev = aml_device("SMC");
-
- aml_append(dev, aml_name_decl("_HID", aml_eisaid("APP0001")));
- /* device present, functioning, decoding, not shown in UI */
- aml_append(dev, aml_name_decl("_STA", aml_int(0xB)));
-
- crs = aml_resource_template();
- aml_append(crs,
- aml_io(AML_DECODE16, misc->applesmc_io_base, misc->applesmc_io_base,
- 0x01, APPLESMC_MAX_DATA_LENGTH)
- );
- aml_append(crs, aml_irq_no_flags(6));
- aml_append(dev, aml_name_decl("_CRS", crs));
-
- aml_append(scope, dev);
- aml_append(dsdt, scope);
- }
-
- if (misc->pvpanic_port) {
- scope = aml_scope("\\_SB.PCI0.ISA");
-
- dev = aml_device("PEVT");
- aml_append(dev, aml_name_decl("_HID", aml_string("QEMU0001")));
-
- crs = aml_resource_template();
- aml_append(crs,
- aml_io(AML_DECODE16, misc->pvpanic_port, misc->pvpanic_port, 1, 1)
- );
- aml_append(dev, aml_name_decl("_CRS", crs));
-
- aml_append(dev, aml_operation_region("PEOR", AML_SYSTEM_IO,
- aml_int(misc->pvpanic_port), 1));
- field = aml_field("PEOR", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE);
- aml_append(field, aml_named_field("PEPT", 8));
- aml_append(dev, field);
-
- /* device present, functioning, decoding, shown in UI */
- aml_append(dev, aml_name_decl("_STA", aml_int(0xF)));
-
- method = aml_method("RDPT", 0, AML_NOTSERIALIZED);
- aml_append(method, aml_store(aml_name("PEPT"), aml_local(0)));
- aml_append(method, aml_return(aml_local(0)));
- aml_append(dev, method);
-
- method = aml_method("WRPT", 1, AML_NOTSERIALIZED);
- aml_append(method, aml_store(aml_arg(0), aml_name("PEPT")));
- aml_append(dev, method);
-
- aml_append(scope, dev);
- aml_append(dsdt, scope);
- }
-
- sb_scope = aml_scope("\\_SB");
- {
- build_processor_devices(sb_scope, machine, pm);
-
- build_memory_devices(sb_scope, nr_mem, pm->mem_hp_io_base,
- pm->mem_hp_io_len);
-
- {
- Object *pci_host;
- PCIBus *bus = NULL;
-
- pci_host = acpi_get_i386_pci_host();
- if (pci_host) {
- bus = PCI_HOST_BRIDGE(pci_host)->bus;
- }
-
- if (bus) {
- Aml *scope = aml_scope("PCI0");
- /* Scan all PCI buses. Generate tables to support hotplug. */
- build_append_pci_bus_devices(scope, bus, pm->pcihp_bridge_en);
-
- if (misc->tpm_version != TPM_VERSION_UNSPEC) {
- dev = aml_device("ISA.TPM");
- aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C31")));
- aml_append(dev, aml_name_decl("_STA", aml_int(0xF)));
- crs = aml_resource_template();
- aml_append(crs, aml_memory32_fixed(TPM_TIS_ADDR_BASE,
- TPM_TIS_ADDR_SIZE, AML_READ_WRITE));
- /*
- FIXME: TPM_TIS_IRQ=5 conflicts with PNP0C0F irqs,
- Rewrite to take IRQ from TPM device model and
- fix default IRQ value there to use some unused IRQ
- */
- /* aml_append(crs, aml_irq_no_flags(TPM_TIS_IRQ)); */
- aml_append(dev, aml_name_decl("_CRS", crs));
- aml_append(scope, dev);
- }
-
- aml_append(sb_scope, scope);
- }
- }
- aml_append(dsdt, sb_scope);
- }
-
- /* copy AML table into ACPI tables blob and patch header there */
- g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len);
- build_header(linker, table_data,
- (void *)(table_data->data + table_data->len - dsdt->buf->len),
- "DSDT", dsdt->buf->len, 1, NULL, NULL);
- free_aml_allocator();
-}
-
-static void
-build_hpet(GArray *table_data, GArray *linker)
-{
- Acpi20Hpet *hpet;
-
- hpet = acpi_data_push(table_data, sizeof(*hpet));
- /* Note timer_block_id value must be kept in sync with value advertised by
- * emulated hpet
- */
- hpet->timer_block_id = cpu_to_le32(0x8086a201);
- hpet->addr.address = cpu_to_le64(HPET_BASE);
- build_header(linker, table_data,
- (void *)hpet, "HPET", sizeof(*hpet), 1, NULL, NULL);
-}
-
-static void
-build_tpm_tcpa(GArray *table_data, GArray *linker, GArray *tcpalog)
-{
- Acpi20Tcpa *tcpa = acpi_data_push(table_data, sizeof *tcpa);
- uint64_t log_area_start_address = acpi_data_len(tcpalog);
-
- tcpa->platform_class = cpu_to_le16(TPM_TCPA_ACPI_CLASS_CLIENT);
- tcpa->log_area_minimum_length = cpu_to_le32(TPM_LOG_AREA_MINIMUM_SIZE);
- tcpa->log_area_start_address = cpu_to_le64(log_area_start_address);
-
- bios_linker_loader_alloc(linker, ACPI_BUILD_TPMLOG_FILE, 1,
- false /* high memory */);
-
- /* log area start address to be filled by Guest linker */
- bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE,
- ACPI_BUILD_TPMLOG_FILE,
- table_data, &tcpa->log_area_start_address,
- sizeof(tcpa->log_area_start_address));
-
- build_header(linker, table_data,
- (void *)tcpa, "TCPA", sizeof(*tcpa), 2, NULL, NULL);
-
- acpi_data_push(tcpalog, TPM_LOG_AREA_MINIMUM_SIZE);
-}
-
-static void
-build_tpm2(GArray *table_data, GArray *linker)
-{
- Acpi20TPM2 *tpm2_ptr;
-
- tpm2_ptr = acpi_data_push(table_data, sizeof *tpm2_ptr);
-
- tpm2_ptr->platform_class = cpu_to_le16(TPM2_ACPI_CLASS_CLIENT);
- tpm2_ptr->control_area_address = cpu_to_le64(0);
- tpm2_ptr->start_method = cpu_to_le32(TPM2_START_METHOD_MMIO);
-
- build_header(linker, table_data,
- (void *)tpm2_ptr, "TPM2", sizeof(*tpm2_ptr), 4, NULL, NULL);
-}
-
-typedef enum {
- MEM_AFFINITY_NOFLAGS = 0,
- MEM_AFFINITY_ENABLED = (1 << 0),
- MEM_AFFINITY_HOTPLUGGABLE = (1 << 1),
- MEM_AFFINITY_NON_VOLATILE = (1 << 2),
-} MemoryAffinityFlags;
-
-static void
-acpi_build_srat_memory(AcpiSratMemoryAffinity *numamem, uint64_t base,
- uint64_t len, int node, MemoryAffinityFlags flags)
-{
- numamem->type = ACPI_SRAT_MEMORY;
- numamem->length = sizeof(*numamem);
- memset(numamem->proximity, 0, 4);
- numamem->proximity[0] = node;
- numamem->flags = cpu_to_le32(flags);
- numamem->base_addr = cpu_to_le64(base);
- numamem->range_length = cpu_to_le64(len);
-}
-
-static void
-build_srat(GArray *table_data, GArray *linker, MachineState *machine)
-{
- AcpiSystemResourceAffinityTable *srat;
- AcpiSratProcessorAffinity *core;
- AcpiSratMemoryAffinity *numamem;
-
- int i;
- uint64_t curnode;
- int srat_start, numa_start, slots;
- uint64_t mem_len, mem_base, next_base;
- MachineClass *mc = MACHINE_GET_CLASS(machine);
- CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids(machine);
- PCMachineState *pcms = PC_MACHINE(machine);
- ram_addr_t hotplugabble_address_space_size =
- object_property_get_int(OBJECT(pcms), PC_MACHINE_MEMHP_REGION_SIZE,
- NULL);
-
- srat_start = table_data->len;
-
- srat = acpi_data_push(table_data, sizeof *srat);
- srat->reserved1 = cpu_to_le32(1);
-
- for (i = 0; i < apic_ids->len; i++) {
- int apic_id = apic_ids->cpus[i].arch_id;
-
- core = acpi_data_push(table_data, sizeof *core);
- core->type = ACPI_SRAT_PROCESSOR;
- core->length = sizeof(*core);
- core->local_apic_id = apic_id;
- curnode = pcms->node_cpu[apic_id];
- core->proximity_lo = curnode;
- memset(core->proximity_hi, 0, 3);
- core->local_sapic_eid = 0;
- core->flags = cpu_to_le32(1);
- }
-
-
- /* the memory map is a bit tricky, it contains at least one hole
- * from 640k-1M and possibly another one from 3.5G-4G.
- */
- next_base = 0;
- numa_start = table_data->len;
-
- numamem = acpi_data_push(table_data, sizeof *numamem);
- acpi_build_srat_memory(numamem, 0, 640*1024, 0, MEM_AFFINITY_ENABLED);
- next_base = 1024 * 1024;
- for (i = 1; i < pcms->numa_nodes + 1; ++i) {
- mem_base = next_base;
- mem_len = pcms->node_mem[i - 1];
- if (i == 1) {
- mem_len -= 1024 * 1024;
- }
- next_base = mem_base + mem_len;
-
- /* Cut out the ACPI_PCI hole */
- if (mem_base <= pcms->below_4g_mem_size &&
- next_base > pcms->below_4g_mem_size) {
- mem_len -= next_base - pcms->below_4g_mem_size;
- if (mem_len > 0) {
- numamem = acpi_data_push(table_data, sizeof *numamem);
- acpi_build_srat_memory(numamem, mem_base, mem_len, i - 1,
- MEM_AFFINITY_ENABLED);
- }
- mem_base = 1ULL << 32;
- mem_len = next_base - pcms->below_4g_mem_size;
- next_base += (1ULL << 32) - pcms->below_4g_mem_size;
- }
- numamem = acpi_data_push(table_data, sizeof *numamem);
- acpi_build_srat_memory(numamem, mem_base, mem_len, i - 1,
- MEM_AFFINITY_ENABLED);
- }
- slots = (table_data->len - numa_start) / sizeof *numamem;
- for (; slots < pcms->numa_nodes + 2; slots++) {
- numamem = acpi_data_push(table_data, sizeof *numamem);
- acpi_build_srat_memory(numamem, 0, 0, 0, MEM_AFFINITY_NOFLAGS);
- }
-
- /*
- * Entry is required for Windows to enable memory hotplug in OS.
- * Memory devices may override proximity set by this entry,
- * providing _PXM method if necessary.
- */
- if (hotplugabble_address_space_size) {
- numamem = acpi_data_push(table_data, sizeof *numamem);
- acpi_build_srat_memory(numamem, pcms->hotplug_memory.base,
- hotplugabble_address_space_size, 0,
- MEM_AFFINITY_HOTPLUGGABLE |
- MEM_AFFINITY_ENABLED);
- }
-
- build_header(linker, table_data,
- (void *)(table_data->data + srat_start),
- "SRAT",
- table_data->len - srat_start, 1, NULL, NULL);
- g_free(apic_ids);
-}
-
-static void
-build_mcfg_q35(GArray *table_data, GArray *linker, AcpiMcfgInfo *info)
-{
- AcpiTableMcfg *mcfg;
- const char *sig;
- int len = sizeof(*mcfg) + 1 * sizeof(mcfg->allocation[0]);
-
- mcfg = acpi_data_push(table_data, len);
- mcfg->allocation[0].address = cpu_to_le64(info->mcfg_base);
- /* Only a single allocation so no need to play with segments */
- mcfg->allocation[0].pci_segment = cpu_to_le16(0);
- mcfg->allocation[0].start_bus_number = 0;
- mcfg->allocation[0].end_bus_number = PCIE_MMCFG_BUS(info->mcfg_size - 1);
-
- /* MCFG is used for ECAM which can be enabled or disabled by guest.
- * To avoid table size changes (which create migration issues),
- * always create the table even if there are no allocations,
- * but set the signature to a reserved value in this case.
- * ACPI spec requires OSPMs to ignore such tables.
- */
- if (info->mcfg_base == PCIE_BASE_ADDR_UNMAPPED) {
- /* Reserved signature: ignored by OSPM */
- sig = "QEMU";
- } else {
- sig = "MCFG";
- }
- build_header(linker, table_data, (void *)mcfg, sig, len, 1, NULL, NULL);
-}
-
-static void
-build_dmar_q35(GArray *table_data, GArray *linker)
-{
- int dmar_start = table_data->len;
-
- AcpiTableDmar *dmar;
- AcpiDmarHardwareUnit *drhd;
-
- dmar = acpi_data_push(table_data, sizeof(*dmar));
- dmar->host_address_width = VTD_HOST_ADDRESS_WIDTH - 1;
- dmar->flags = 0; /* No intr_remap for now */
-
- /* DMAR Remapping Hardware Unit Definition structure */
- drhd = acpi_data_push(table_data, sizeof(*drhd));
- drhd->type = cpu_to_le16(ACPI_DMAR_TYPE_HARDWARE_UNIT);
- drhd->length = cpu_to_le16(sizeof(*drhd)); /* No device scope now */
- drhd->flags = ACPI_DMAR_INCLUDE_PCI_ALL;
- drhd->pci_segment = cpu_to_le16(0);
- drhd->address = cpu_to_le64(Q35_HOST_BRIDGE_IOMMU_ADDR);
-
- build_header(linker, table_data, (void *)(table_data->data + dmar_start),
- "DMAR", table_data->len - dmar_start, 1, NULL, NULL);
-}
-
-static GArray *
-build_rsdp(GArray *rsdp_table, GArray *linker, unsigned rsdt)
-{
- AcpiRsdpDescriptor *rsdp = acpi_data_push(rsdp_table, sizeof *rsdp);
-
- bios_linker_loader_alloc(linker, ACPI_BUILD_RSDP_FILE, 16,
- true /* fseg memory */);
-
- memcpy(&rsdp->signature, "RSD PTR ", 8);
- memcpy(rsdp->oem_id, ACPI_BUILD_APPNAME6, 6);
- rsdp->rsdt_physical_address = cpu_to_le32(rsdt);
- /* Address to be filled by Guest linker */
- bios_linker_loader_add_pointer(linker, ACPI_BUILD_RSDP_FILE,
- ACPI_BUILD_TABLE_FILE,
- rsdp_table, &rsdp->rsdt_physical_address,
- sizeof rsdp->rsdt_physical_address);
- rsdp->checksum = 0;
- /* Checksum to be filled by Guest linker */
- bios_linker_loader_add_checksum(linker, ACPI_BUILD_RSDP_FILE,
- rsdp_table, rsdp, sizeof *rsdp,
- &rsdp->checksum);
-
- return rsdp_table;
-}
-
-typedef
-struct AcpiBuildState {
- /* Copy of table in RAM (for patching). */
- MemoryRegion *table_mr;
- /* Is table patched? */
- uint8_t patched;
- void *rsdp;
- MemoryRegion *rsdp_mr;
- MemoryRegion *linker_mr;
-} AcpiBuildState;
-
-static bool acpi_get_mcfg(AcpiMcfgInfo *mcfg)
-{
- Object *pci_host;
- QObject *o;
-
- pci_host = acpi_get_i386_pci_host();
- g_assert(pci_host);
-
- o = object_property_get_qobject(pci_host, PCIE_HOST_MCFG_BASE, NULL);
- if (!o) {
- return false;
- }
- mcfg->mcfg_base = qint_get_int(qobject_to_qint(o));
- qobject_decref(o);
-
- o = object_property_get_qobject(pci_host, PCIE_HOST_MCFG_SIZE, NULL);
- assert(o);
- mcfg->mcfg_size = qint_get_int(qobject_to_qint(o));
- qobject_decref(o);
- return true;
-}
-
-static bool acpi_has_iommu(void)
-{
- bool ambiguous;
- Object *intel_iommu;
-
- intel_iommu = object_resolve_path_type("", TYPE_INTEL_IOMMU_DEVICE,
- &ambiguous);
- return intel_iommu && !ambiguous;
-}
-
-static
-void acpi_build(AcpiBuildTables *tables, MachineState *machine)
-{
- PCMachineState *pcms = PC_MACHINE(machine);
- PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
- GArray *table_offsets;
- unsigned facs, dsdt, rsdt, fadt;
- AcpiPmInfo pm;
- AcpiMiscInfo misc;
- AcpiMcfgInfo mcfg;
- PcPciInfo pci;
- uint8_t *u;
- size_t aml_len = 0;
- GArray *tables_blob = tables->table_data;
- AcpiSlicOem slic_oem = { .id = NULL, .table_id = NULL };
-
- acpi_get_pm_info(&pm);
- acpi_get_misc_info(&misc);
- acpi_get_pci_info(&pci);
- acpi_get_slic_oem(&slic_oem);
-
- table_offsets = g_array_new(false, true /* clear */,
- sizeof(uint32_t));
- ACPI_BUILD_DPRINTF("init ACPI tables\n");
-
- bios_linker_loader_alloc(tables->linker, ACPI_BUILD_TABLE_FILE,
- 64 /* Ensure FACS is aligned */,
- false /* high memory */);
-
- /*
- * FACS is pointed to by FADT.
- * We place it first since it's the only table that has alignment
- * requirements.
- */
- facs = tables_blob->len;
- build_facs(tables_blob, tables->linker);
-
- /* DSDT is pointed to by FADT */
- dsdt = tables_blob->len;
- build_dsdt(tables_blob, tables->linker, &pm, &misc, &pci, machine);
-
- /* Count the size of the DSDT and SSDT, we will need it for legacy
- * sizing of ACPI tables.
- */
- aml_len += tables_blob->len - dsdt;
-
- /* ACPI tables pointed to by RSDT */
- fadt = tables_blob->len;
- acpi_add_table(table_offsets, tables_blob);
- build_fadt(tables_blob, tables->linker, &pm, facs, dsdt,
- slic_oem.id, slic_oem.table_id);
- aml_len += tables_blob->len - fadt;
-
- acpi_add_table(table_offsets, tables_blob);
- build_madt(tables_blob, tables->linker, pcms);
-
- if (misc.has_hpet) {
- acpi_add_table(table_offsets, tables_blob);
- build_hpet(tables_blob, tables->linker);
- }
- if (misc.tpm_version != TPM_VERSION_UNSPEC) {
- acpi_add_table(table_offsets, tables_blob);
- build_tpm_tcpa(tables_blob, tables->linker, tables->tcpalog);
-
- if (misc.tpm_version == TPM_VERSION_2_0) {
- acpi_add_table(table_offsets, tables_blob);
- build_tpm2(tables_blob, tables->linker);
- }
- }
- if (pcms->numa_nodes) {
- acpi_add_table(table_offsets, tables_blob);
- build_srat(tables_blob, tables->linker, machine);
- }
- if (acpi_get_mcfg(&mcfg)) {
- acpi_add_table(table_offsets, tables_blob);
- build_mcfg_q35(tables_blob, tables->linker, &mcfg);
- }
- if (acpi_has_iommu()) {
- acpi_add_table(table_offsets, tables_blob);
- build_dmar_q35(tables_blob, tables->linker);
- }
- if (pcms->acpi_nvdimm_state.is_enabled) {
- nvdimm_build_acpi(table_offsets, tables_blob, tables->linker);
- }
-
- /* Add tables supplied by user (if any) */
- for (u = acpi_table_first(); u; u = acpi_table_next(u)) {
- unsigned len = acpi_table_len(u);
-
- acpi_add_table(table_offsets, tables_blob);
- g_array_append_vals(tables_blob, u, len);
- }
-
- /* RSDT is pointed to by RSDP */
- rsdt = tables_blob->len;
- build_rsdt(tables_blob, tables->linker, table_offsets,
- slic_oem.id, slic_oem.table_id);
-
- /* RSDP is in FSEG memory, so allocate it separately */
- build_rsdp(tables->rsdp, tables->linker, rsdt);
-
- /* We'll expose it all to Guest so we want to reduce
- * chance of size changes.
- *
- * We used to align the tables to 4k, but of course this would
- * too simple to be enough. 4k turned out to be too small an
- * alignment very soon, and in fact it is almost impossible to
- * keep the table size stable for all (max_cpus, max_memory_slots)
- * combinations. So the table size is always 64k for pc-i440fx-2.1
- * and we give an error if the table grows beyond that limit.
- *
- * We still have the problem of migrating from "-M pc-i440fx-2.0". For
- * that, we exploit the fact that QEMU 2.1 generates _smaller_ tables
- * than 2.0 and we can always pad the smaller tables with zeros. We can
- * then use the exact size of the 2.0 tables.
- *
- * All this is for PIIX4, since QEMU 2.0 didn't support Q35 migration.
- */
- if (pcmc->legacy_acpi_table_size) {
- /* Subtracting aml_len gives the size of fixed tables. Then add the
- * size of the PIIX4 DSDT/SSDT in QEMU 2.0.
- */
- int legacy_aml_len =
- pcmc->legacy_acpi_table_size +
- ACPI_BUILD_LEGACY_CPU_AML_SIZE * max_cpus;
- int legacy_table_size =
- ROUND_UP(tables_blob->len - aml_len + legacy_aml_len,
- ACPI_BUILD_ALIGN_SIZE);
- if (tables_blob->len > legacy_table_size) {
- /* Should happen only with PCI bridges and -M pc-i440fx-2.0. */
- error_report("Warning: migration may not work.");
- }
- g_array_set_size(tables_blob, legacy_table_size);
- } else {
- /* Make sure we have a buffer in case we need to resize the tables. */
- if (tables_blob->len > ACPI_BUILD_TABLE_SIZE / 2) {
- /* As of QEMU 2.1, this fires with 160 VCPUs and 255 memory slots. */
- error_report("Warning: ACPI tables are larger than 64k.");
- error_report("Warning: migration may not work.");
- error_report("Warning: please remove CPUs, NUMA nodes, "
- "memory slots or PCI bridges.");
- }
- acpi_align_size(tables_blob, ACPI_BUILD_TABLE_SIZE);
- }
-
- acpi_align_size(tables->linker, ACPI_BUILD_ALIGN_SIZE);
-
- /* Cleanup memory that's no longer used. */
- g_array_free(table_offsets, true);
-}
-
-static void acpi_ram_update(MemoryRegion *mr, GArray *data)
-{
- uint32_t size = acpi_data_len(data);
-
- /* Make sure RAM size is correct - in case it got changed e.g. by migration */
- memory_region_ram_resize(mr, size, &error_abort);
-
- memcpy(memory_region_get_ram_ptr(mr), data->data, size);
- memory_region_set_dirty(mr, 0, size);
-}
-
-static void acpi_build_update(void *build_opaque)
-{
- AcpiBuildState *build_state = build_opaque;
- AcpiBuildTables tables;
-
- /* No state to update or already patched? Nothing to do. */
- if (!build_state || build_state->patched) {
- return;
- }
- build_state->patched = 1;
-
- acpi_build_tables_init(&tables);
-
- acpi_build(&tables, MACHINE(qdev_get_machine()));
-
- acpi_ram_update(build_state->table_mr, tables.table_data);
-
- if (build_state->rsdp) {
- memcpy(build_state->rsdp, tables.rsdp->data, acpi_data_len(tables.rsdp));
- } else {
- acpi_ram_update(build_state->rsdp_mr, tables.rsdp);
- }
-
- acpi_ram_update(build_state->linker_mr, tables.linker);
- acpi_build_tables_cleanup(&tables, true);
-}
-
-static void acpi_build_reset(void *build_opaque)
-{
- AcpiBuildState *build_state = build_opaque;
- build_state->patched = 0;
-}
-
-static MemoryRegion *acpi_add_rom_blob(AcpiBuildState *build_state,
- GArray *blob, const char *name,
- uint64_t max_size)
-{
- return rom_add_blob(name, blob->data, acpi_data_len(blob), max_size, -1,
- name, acpi_build_update, build_state);
-}
-
-static const VMStateDescription vmstate_acpi_build = {
- .name = "acpi_build",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(patched, AcpiBuildState),
- VMSTATE_END_OF_LIST()
- },
-};
-
-void acpi_setup(void)
-{
- PCMachineState *pcms = PC_MACHINE(qdev_get_machine());
- PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
- AcpiBuildTables tables;
- AcpiBuildState *build_state;
-
- if (!pcms->fw_cfg) {
- ACPI_BUILD_DPRINTF("No fw cfg. Bailing out.\n");
- return;
- }
-
- if (!pcmc->has_acpi_build) {
- ACPI_BUILD_DPRINTF("ACPI build disabled. Bailing out.\n");
- return;
- }
-
- if (!acpi_enabled) {
- ACPI_BUILD_DPRINTF("ACPI disabled. Bailing out.\n");
- return;
- }
-
- build_state = g_malloc0(sizeof *build_state);
-
- acpi_set_pci_info();
-
- acpi_build_tables_init(&tables);
- acpi_build(&tables, MACHINE(pcms));
-
- /* Now expose it all to Guest */
- build_state->table_mr = acpi_add_rom_blob(build_state, tables.table_data,
- ACPI_BUILD_TABLE_FILE,
- ACPI_BUILD_TABLE_MAX_SIZE);
- assert(build_state->table_mr != NULL);
-
- build_state->linker_mr =
- acpi_add_rom_blob(build_state, tables.linker, "etc/table-loader", 0);
-
- fw_cfg_add_file(pcms->fw_cfg, ACPI_BUILD_TPMLOG_FILE,
- tables.tcpalog->data, acpi_data_len(tables.tcpalog));
-
- if (!pcmc->rsdp_in_ram) {
- /*
- * Keep for compatibility with old machine types.
- * Though RSDP is small, its contents isn't immutable, so
- * we'll update it along with the rest of tables on guest access.
- */
- uint32_t rsdp_size = acpi_data_len(tables.rsdp);
-
- build_state->rsdp = g_memdup(tables.rsdp->data, rsdp_size);
- fw_cfg_add_file_callback(pcms->fw_cfg, ACPI_BUILD_RSDP_FILE,
- acpi_build_update, build_state,
- build_state->rsdp, rsdp_size);
- build_state->rsdp_mr = NULL;
- } else {
- build_state->rsdp = NULL;
- build_state->rsdp_mr = acpi_add_rom_blob(build_state, tables.rsdp,
- ACPI_BUILD_RSDP_FILE, 0);
- }
-
- qemu_register_reset(acpi_build_reset, build_state);
- acpi_build_reset(build_state);
- vmstate_register(NULL, 0, &vmstate_acpi_build, build_state);
-
- /* Cleanup tables but don't free the memory: we track it
- * in build_state.
- */
- acpi_build_tables_cleanup(&tables, false);
-}
diff --git a/qemu/hw/i386/acpi-build.h b/qemu/hw/i386/acpi-build.h
deleted file mode 100644
index 007332e51..000000000
--- a/qemu/hw/i386/acpi-build.h
+++ /dev/null
@@ -1,7 +0,0 @@
-
-#ifndef HW_I386_ACPI_BUILD_H
-#define HW_I386_ACPI_BUILD_H
-
-void acpi_setup(void);
-
-#endif
diff --git a/qemu/hw/i386/intel_iommu.c b/qemu/hw/i386/intel_iommu.c
deleted file mode 100644
index 347718f93..000000000
--- a/qemu/hw/i386/intel_iommu.c
+++ /dev/null
@@ -1,2057 +0,0 @@
-/*
- * QEMU emulation of an Intel IOMMU (VT-d)
- * (DMA Remapping device)
- *
- * Copyright (C) 2013 Knut Omang, Oracle <knut.omang@oracle.com>
- * Copyright (C) 2014 Le Tan, <tamlokveer@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "exec/address-spaces.h"
-#include "intel_iommu_internal.h"
-#include "hw/pci/pci.h"
-
-/*#define DEBUG_INTEL_IOMMU*/
-#ifdef DEBUG_INTEL_IOMMU
-enum {
- DEBUG_GENERAL, DEBUG_CSR, DEBUG_INV, DEBUG_MMU, DEBUG_FLOG,
- DEBUG_CACHE,
-};
-#define VTD_DBGBIT(x) (1 << DEBUG_##x)
-static int vtd_dbgflags = VTD_DBGBIT(GENERAL) | VTD_DBGBIT(CSR);
-
-#define VTD_DPRINTF(what, fmt, ...) do { \
- if (vtd_dbgflags & VTD_DBGBIT(what)) { \
- fprintf(stderr, "(vtd)%s: " fmt "\n", __func__, \
- ## __VA_ARGS__); } \
- } while (0)
-#else
-#define VTD_DPRINTF(what, fmt, ...) do {} while (0)
-#endif
-
-static void vtd_define_quad(IntelIOMMUState *s, hwaddr addr, uint64_t val,
- uint64_t wmask, uint64_t w1cmask)
-{
- stq_le_p(&s->csr[addr], val);
- stq_le_p(&s->wmask[addr], wmask);
- stq_le_p(&s->w1cmask[addr], w1cmask);
-}
-
-static void vtd_define_quad_wo(IntelIOMMUState *s, hwaddr addr, uint64_t mask)
-{
- stq_le_p(&s->womask[addr], mask);
-}
-
-static void vtd_define_long(IntelIOMMUState *s, hwaddr addr, uint32_t val,
- uint32_t wmask, uint32_t w1cmask)
-{
- stl_le_p(&s->csr[addr], val);
- stl_le_p(&s->wmask[addr], wmask);
- stl_le_p(&s->w1cmask[addr], w1cmask);
-}
-
-static void vtd_define_long_wo(IntelIOMMUState *s, hwaddr addr, uint32_t mask)
-{
- stl_le_p(&s->womask[addr], mask);
-}
-
-/* "External" get/set operations */
-static void vtd_set_quad(IntelIOMMUState *s, hwaddr addr, uint64_t val)
-{
- uint64_t oldval = ldq_le_p(&s->csr[addr]);
- uint64_t wmask = ldq_le_p(&s->wmask[addr]);
- uint64_t w1cmask = ldq_le_p(&s->w1cmask[addr]);
- stq_le_p(&s->csr[addr],
- ((oldval & ~wmask) | (val & wmask)) & ~(w1cmask & val));
-}
-
-static void vtd_set_long(IntelIOMMUState *s, hwaddr addr, uint32_t val)
-{
- uint32_t oldval = ldl_le_p(&s->csr[addr]);
- uint32_t wmask = ldl_le_p(&s->wmask[addr]);
- uint32_t w1cmask = ldl_le_p(&s->w1cmask[addr]);
- stl_le_p(&s->csr[addr],
- ((oldval & ~wmask) | (val & wmask)) & ~(w1cmask & val));
-}
-
-static uint64_t vtd_get_quad(IntelIOMMUState *s, hwaddr addr)
-{
- uint64_t val = ldq_le_p(&s->csr[addr]);
- uint64_t womask = ldq_le_p(&s->womask[addr]);
- return val & ~womask;
-}
-
-static uint32_t vtd_get_long(IntelIOMMUState *s, hwaddr addr)
-{
- uint32_t val = ldl_le_p(&s->csr[addr]);
- uint32_t womask = ldl_le_p(&s->womask[addr]);
- return val & ~womask;
-}
-
-/* "Internal" get/set operations */
-static uint64_t vtd_get_quad_raw(IntelIOMMUState *s, hwaddr addr)
-{
- return ldq_le_p(&s->csr[addr]);
-}
-
-static uint32_t vtd_get_long_raw(IntelIOMMUState *s, hwaddr addr)
-{
- return ldl_le_p(&s->csr[addr]);
-}
-
-static void vtd_set_quad_raw(IntelIOMMUState *s, hwaddr addr, uint64_t val)
-{
- stq_le_p(&s->csr[addr], val);
-}
-
-static uint32_t vtd_set_clear_mask_long(IntelIOMMUState *s, hwaddr addr,
- uint32_t clear, uint32_t mask)
-{
- uint32_t new_val = (ldl_le_p(&s->csr[addr]) & ~clear) | mask;
- stl_le_p(&s->csr[addr], new_val);
- return new_val;
-}
-
-static uint64_t vtd_set_clear_mask_quad(IntelIOMMUState *s, hwaddr addr,
- uint64_t clear, uint64_t mask)
-{
- uint64_t new_val = (ldq_le_p(&s->csr[addr]) & ~clear) | mask;
- stq_le_p(&s->csr[addr], new_val);
- return new_val;
-}
-
-/* GHashTable functions */
-static gboolean vtd_uint64_equal(gconstpointer v1, gconstpointer v2)
-{
- return *((const uint64_t *)v1) == *((const uint64_t *)v2);
-}
-
-static guint vtd_uint64_hash(gconstpointer v)
-{
- return (guint)*(const uint64_t *)v;
-}
-
-static gboolean vtd_hash_remove_by_domain(gpointer key, gpointer value,
- gpointer user_data)
-{
- VTDIOTLBEntry *entry = (VTDIOTLBEntry *)value;
- uint16_t domain_id = *(uint16_t *)user_data;
- return entry->domain_id == domain_id;
-}
-
-/* The shift of an addr for a certain level of paging structure */
-static inline uint32_t vtd_slpt_level_shift(uint32_t level)
-{
- return VTD_PAGE_SHIFT_4K + (level - 1) * VTD_SL_LEVEL_BITS;
-}
-
-static inline uint64_t vtd_slpt_level_page_mask(uint32_t level)
-{
- return ~((1ULL << vtd_slpt_level_shift(level)) - 1);
-}
-
-static gboolean vtd_hash_remove_by_page(gpointer key, gpointer value,
- gpointer user_data)
-{
- VTDIOTLBEntry *entry = (VTDIOTLBEntry *)value;
- VTDIOTLBPageInvInfo *info = (VTDIOTLBPageInvInfo *)user_data;
- uint64_t gfn = (info->addr >> VTD_PAGE_SHIFT_4K) & info->mask;
- uint64_t gfn_tlb = (info->addr & entry->mask) >> VTD_PAGE_SHIFT_4K;
- return (entry->domain_id == info->domain_id) &&
- (((entry->gfn & info->mask) == gfn) ||
- (entry->gfn == gfn_tlb));
-}
-
-/* Reset all the gen of VTDAddressSpace to zero and set the gen of
- * IntelIOMMUState to 1.
- */
-static void vtd_reset_context_cache(IntelIOMMUState *s)
-{
- VTDAddressSpace *vtd_as;
- VTDBus *vtd_bus;
- GHashTableIter bus_it;
- uint32_t devfn_it;
-
- g_hash_table_iter_init(&bus_it, s->vtd_as_by_busptr);
-
- VTD_DPRINTF(CACHE, "global context_cache_gen=1");
- while (g_hash_table_iter_next (&bus_it, NULL, (void**)&vtd_bus)) {
- for (devfn_it = 0; devfn_it < VTD_PCI_DEVFN_MAX; ++devfn_it) {
- vtd_as = vtd_bus->dev_as[devfn_it];
- if (!vtd_as) {
- continue;
- }
- vtd_as->context_cache_entry.context_cache_gen = 0;
- }
- }
- s->context_cache_gen = 1;
-}
-
-static void vtd_reset_iotlb(IntelIOMMUState *s)
-{
- assert(s->iotlb);
- g_hash_table_remove_all(s->iotlb);
-}
-
-static uint64_t vtd_get_iotlb_key(uint64_t gfn, uint8_t source_id,
- uint32_t level)
-{
- return gfn | ((uint64_t)(source_id) << VTD_IOTLB_SID_SHIFT) |
- ((uint64_t)(level) << VTD_IOTLB_LVL_SHIFT);
-}
-
-static uint64_t vtd_get_iotlb_gfn(hwaddr addr, uint32_t level)
-{
- return (addr & vtd_slpt_level_page_mask(level)) >> VTD_PAGE_SHIFT_4K;
-}
-
-static VTDIOTLBEntry *vtd_lookup_iotlb(IntelIOMMUState *s, uint16_t source_id,
- hwaddr addr)
-{
- VTDIOTLBEntry *entry;
- uint64_t key;
- int level;
-
- for (level = VTD_SL_PT_LEVEL; level < VTD_SL_PML4_LEVEL; level++) {
- key = vtd_get_iotlb_key(vtd_get_iotlb_gfn(addr, level),
- source_id, level);
- entry = g_hash_table_lookup(s->iotlb, &key);
- if (entry) {
- goto out;
- }
- }
-
-out:
- return entry;
-}
-
-static void vtd_update_iotlb(IntelIOMMUState *s, uint16_t source_id,
- uint16_t domain_id, hwaddr addr, uint64_t slpte,
- bool read_flags, bool write_flags,
- uint32_t level)
-{
- VTDIOTLBEntry *entry = g_malloc(sizeof(*entry));
- uint64_t *key = g_malloc(sizeof(*key));
- uint64_t gfn = vtd_get_iotlb_gfn(addr, level);
-
- VTD_DPRINTF(CACHE, "update iotlb sid 0x%"PRIx16 " gpa 0x%"PRIx64
- " slpte 0x%"PRIx64 " did 0x%"PRIx16, source_id, addr, slpte,
- domain_id);
- if (g_hash_table_size(s->iotlb) >= VTD_IOTLB_MAX_SIZE) {
- VTD_DPRINTF(CACHE, "iotlb exceeds size limit, forced to reset");
- vtd_reset_iotlb(s);
- }
-
- entry->gfn = gfn;
- entry->domain_id = domain_id;
- entry->slpte = slpte;
- entry->read_flags = read_flags;
- entry->write_flags = write_flags;
- entry->mask = vtd_slpt_level_page_mask(level);
- *key = vtd_get_iotlb_key(gfn, source_id, level);
- g_hash_table_replace(s->iotlb, key, entry);
-}
-
-/* Given the reg addr of both the message data and address, generate an
- * interrupt via MSI.
- */
-static void vtd_generate_interrupt(IntelIOMMUState *s, hwaddr mesg_addr_reg,
- hwaddr mesg_data_reg)
-{
- hwaddr addr;
- uint32_t data;
-
- assert(mesg_data_reg < DMAR_REG_SIZE);
- assert(mesg_addr_reg < DMAR_REG_SIZE);
-
- addr = vtd_get_long_raw(s, mesg_addr_reg);
- data = vtd_get_long_raw(s, mesg_data_reg);
-
- VTD_DPRINTF(FLOG, "msi: addr 0x%"PRIx64 " data 0x%"PRIx32, addr, data);
- address_space_stl_le(&address_space_memory, addr, data,
- MEMTXATTRS_UNSPECIFIED, NULL);
-}
-
-/* Generate a fault event to software via MSI if conditions are met.
- * Notice that the value of FSTS_REG being passed to it should be the one
- * before any update.
- */
-static void vtd_generate_fault_event(IntelIOMMUState *s, uint32_t pre_fsts)
-{
- if (pre_fsts & VTD_FSTS_PPF || pre_fsts & VTD_FSTS_PFO ||
- pre_fsts & VTD_FSTS_IQE) {
- VTD_DPRINTF(FLOG, "there are previous interrupt conditions "
- "to be serviced by software, fault event is not generated "
- "(FSTS_REG 0x%"PRIx32 ")", pre_fsts);
- return;
- }
- vtd_set_clear_mask_long(s, DMAR_FECTL_REG, 0, VTD_FECTL_IP);
- if (vtd_get_long_raw(s, DMAR_FECTL_REG) & VTD_FECTL_IM) {
- VTD_DPRINTF(FLOG, "Interrupt Mask set, fault event is not generated");
- } else {
- vtd_generate_interrupt(s, DMAR_FEADDR_REG, DMAR_FEDATA_REG);
- vtd_set_clear_mask_long(s, DMAR_FECTL_REG, VTD_FECTL_IP, 0);
- }
-}
-
-/* Check if the Fault (F) field of the Fault Recording Register referenced by
- * @index is Set.
- */
-static bool vtd_is_frcd_set(IntelIOMMUState *s, uint16_t index)
-{
- /* Each reg is 128-bit */
- hwaddr addr = DMAR_FRCD_REG_OFFSET + (((uint64_t)index) << 4);
- addr += 8; /* Access the high 64-bit half */
-
- assert(index < DMAR_FRCD_REG_NR);
-
- return vtd_get_quad_raw(s, addr) & VTD_FRCD_F;
-}
-
-/* Update the PPF field of Fault Status Register.
- * Should be called whenever change the F field of any fault recording
- * registers.
- */
-static void vtd_update_fsts_ppf(IntelIOMMUState *s)
-{
- uint32_t i;
- uint32_t ppf_mask = 0;
-
- for (i = 0; i < DMAR_FRCD_REG_NR; i++) {
- if (vtd_is_frcd_set(s, i)) {
- ppf_mask = VTD_FSTS_PPF;
- break;
- }
- }
- vtd_set_clear_mask_long(s, DMAR_FSTS_REG, VTD_FSTS_PPF, ppf_mask);
- VTD_DPRINTF(FLOG, "set PPF of FSTS_REG to %d", ppf_mask ? 1 : 0);
-}
-
-static void vtd_set_frcd_and_update_ppf(IntelIOMMUState *s, uint16_t index)
-{
- /* Each reg is 128-bit */
- hwaddr addr = DMAR_FRCD_REG_OFFSET + (((uint64_t)index) << 4);
- addr += 8; /* Access the high 64-bit half */
-
- assert(index < DMAR_FRCD_REG_NR);
-
- vtd_set_clear_mask_quad(s, addr, 0, VTD_FRCD_F);
- vtd_update_fsts_ppf(s);
-}
-
-/* Must not update F field now, should be done later */
-static void vtd_record_frcd(IntelIOMMUState *s, uint16_t index,
- uint16_t source_id, hwaddr addr,
- VTDFaultReason fault, bool is_write)
-{
- uint64_t hi = 0, lo;
- hwaddr frcd_reg_addr = DMAR_FRCD_REG_OFFSET + (((uint64_t)index) << 4);
-
- assert(index < DMAR_FRCD_REG_NR);
-
- lo = VTD_FRCD_FI(addr);
- hi = VTD_FRCD_SID(source_id) | VTD_FRCD_FR(fault);
- if (!is_write) {
- hi |= VTD_FRCD_T;
- }
- vtd_set_quad_raw(s, frcd_reg_addr, lo);
- vtd_set_quad_raw(s, frcd_reg_addr + 8, hi);
- VTD_DPRINTF(FLOG, "record to FRCD_REG #%"PRIu16 ": hi 0x%"PRIx64
- ", lo 0x%"PRIx64, index, hi, lo);
-}
-
-/* Try to collapse multiple pending faults from the same requester */
-static bool vtd_try_collapse_fault(IntelIOMMUState *s, uint16_t source_id)
-{
- uint32_t i;
- uint64_t frcd_reg;
- hwaddr addr = DMAR_FRCD_REG_OFFSET + 8; /* The high 64-bit half */
-
- for (i = 0; i < DMAR_FRCD_REG_NR; i++) {
- frcd_reg = vtd_get_quad_raw(s, addr);
- VTD_DPRINTF(FLOG, "frcd_reg #%d 0x%"PRIx64, i, frcd_reg);
- if ((frcd_reg & VTD_FRCD_F) &&
- ((frcd_reg & VTD_FRCD_SID_MASK) == source_id)) {
- return true;
- }
- addr += 16; /* 128-bit for each */
- }
- return false;
-}
-
-/* Log and report an DMAR (address translation) fault to software */
-static void vtd_report_dmar_fault(IntelIOMMUState *s, uint16_t source_id,
- hwaddr addr, VTDFaultReason fault,
- bool is_write)
-{
- uint32_t fsts_reg = vtd_get_long_raw(s, DMAR_FSTS_REG);
-
- assert(fault < VTD_FR_MAX);
-
- if (fault == VTD_FR_RESERVED_ERR) {
- /* This is not a normal fault reason case. Drop it. */
- return;
- }
- VTD_DPRINTF(FLOG, "sid 0x%"PRIx16 ", fault %d, addr 0x%"PRIx64
- ", is_write %d", source_id, fault, addr, is_write);
- if (fsts_reg & VTD_FSTS_PFO) {
- VTD_DPRINTF(FLOG, "new fault is not recorded due to "
- "Primary Fault Overflow");
- return;
- }
- if (vtd_try_collapse_fault(s, source_id)) {
- VTD_DPRINTF(FLOG, "new fault is not recorded due to "
- "compression of faults");
- return;
- }
- if (vtd_is_frcd_set(s, s->next_frcd_reg)) {
- VTD_DPRINTF(FLOG, "Primary Fault Overflow and "
- "new fault is not recorded, set PFO field");
- vtd_set_clear_mask_long(s, DMAR_FSTS_REG, 0, VTD_FSTS_PFO);
- return;
- }
-
- vtd_record_frcd(s, s->next_frcd_reg, source_id, addr, fault, is_write);
-
- if (fsts_reg & VTD_FSTS_PPF) {
- VTD_DPRINTF(FLOG, "there are pending faults already, "
- "fault event is not generated");
- vtd_set_frcd_and_update_ppf(s, s->next_frcd_reg);
- s->next_frcd_reg++;
- if (s->next_frcd_reg == DMAR_FRCD_REG_NR) {
- s->next_frcd_reg = 0;
- }
- } else {
- vtd_set_clear_mask_long(s, DMAR_FSTS_REG, VTD_FSTS_FRI_MASK,
- VTD_FSTS_FRI(s->next_frcd_reg));
- vtd_set_frcd_and_update_ppf(s, s->next_frcd_reg); /* Will set PPF */
- s->next_frcd_reg++;
- if (s->next_frcd_reg == DMAR_FRCD_REG_NR) {
- s->next_frcd_reg = 0;
- }
- /* This case actually cause the PPF to be Set.
- * So generate fault event (interrupt).
- */
- vtd_generate_fault_event(s, fsts_reg);
- }
-}
-
-/* Handle Invalidation Queue Errors of queued invalidation interface error
- * conditions.
- */
-static void vtd_handle_inv_queue_error(IntelIOMMUState *s)
-{
- uint32_t fsts_reg = vtd_get_long_raw(s, DMAR_FSTS_REG);
-
- vtd_set_clear_mask_long(s, DMAR_FSTS_REG, 0, VTD_FSTS_IQE);
- vtd_generate_fault_event(s, fsts_reg);
-}
-
-/* Set the IWC field and try to generate an invalidation completion interrupt */
-static void vtd_generate_completion_event(IntelIOMMUState *s)
-{
- VTD_DPRINTF(INV, "completes an invalidation wait command with "
- "Interrupt Flag");
- if (vtd_get_long_raw(s, DMAR_ICS_REG) & VTD_ICS_IWC) {
- VTD_DPRINTF(INV, "there is a previous interrupt condition to be "
- "serviced by software, "
- "new invalidation event is not generated");
- return;
- }
- vtd_set_clear_mask_long(s, DMAR_ICS_REG, 0, VTD_ICS_IWC);
- vtd_set_clear_mask_long(s, DMAR_IECTL_REG, 0, VTD_IECTL_IP);
- if (vtd_get_long_raw(s, DMAR_IECTL_REG) & VTD_IECTL_IM) {
- VTD_DPRINTF(INV, "IM filed in IECTL_REG is set, new invalidation "
- "event is not generated");
- return;
- } else {
- /* Generate the interrupt event */
- vtd_generate_interrupt(s, DMAR_IEADDR_REG, DMAR_IEDATA_REG);
- vtd_set_clear_mask_long(s, DMAR_IECTL_REG, VTD_IECTL_IP, 0);
- }
-}
-
-static inline bool vtd_root_entry_present(VTDRootEntry *root)
-{
- return root->val & VTD_ROOT_ENTRY_P;
-}
-
-static int vtd_get_root_entry(IntelIOMMUState *s, uint8_t index,
- VTDRootEntry *re)
-{
- dma_addr_t addr;
-
- addr = s->root + index * sizeof(*re);
- if (dma_memory_read(&address_space_memory, addr, re, sizeof(*re))) {
- VTD_DPRINTF(GENERAL, "error: fail to access root-entry at 0x%"PRIx64
- " + %"PRIu8, s->root, index);
- re->val = 0;
- return -VTD_FR_ROOT_TABLE_INV;
- }
- re->val = le64_to_cpu(re->val);
- return 0;
-}
-
-static inline bool vtd_context_entry_present(VTDContextEntry *context)
-{
- return context->lo & VTD_CONTEXT_ENTRY_P;
-}
-
-static int vtd_get_context_entry_from_root(VTDRootEntry *root, uint8_t index,
- VTDContextEntry *ce)
-{
- dma_addr_t addr;
-
- if (!vtd_root_entry_present(root)) {
- VTD_DPRINTF(GENERAL, "error: root-entry is not present");
- return -VTD_FR_ROOT_ENTRY_P;
- }
- addr = (root->val & VTD_ROOT_ENTRY_CTP) + index * sizeof(*ce);
- if (dma_memory_read(&address_space_memory, addr, ce, sizeof(*ce))) {
- VTD_DPRINTF(GENERAL, "error: fail to access context-entry at 0x%"PRIx64
- " + %"PRIu8,
- (uint64_t)(root->val & VTD_ROOT_ENTRY_CTP), index);
- return -VTD_FR_CONTEXT_TABLE_INV;
- }
- ce->lo = le64_to_cpu(ce->lo);
- ce->hi = le64_to_cpu(ce->hi);
- return 0;
-}
-
-static inline dma_addr_t vtd_get_slpt_base_from_context(VTDContextEntry *ce)
-{
- return ce->lo & VTD_CONTEXT_ENTRY_SLPTPTR;
-}
-
-static inline uint64_t vtd_get_slpte_addr(uint64_t slpte)
-{
- return slpte & VTD_SL_PT_BASE_ADDR_MASK;
-}
-
-/* Whether the pte indicates the address of the page frame */
-static inline bool vtd_is_last_slpte(uint64_t slpte, uint32_t level)
-{
- return level == VTD_SL_PT_LEVEL || (slpte & VTD_SL_PT_PAGE_SIZE_MASK);
-}
-
-/* Get the content of a spte located in @base_addr[@index] */
-static uint64_t vtd_get_slpte(dma_addr_t base_addr, uint32_t index)
-{
- uint64_t slpte;
-
- assert(index < VTD_SL_PT_ENTRY_NR);
-
- if (dma_memory_read(&address_space_memory,
- base_addr + index * sizeof(slpte), &slpte,
- sizeof(slpte))) {
- slpte = (uint64_t)-1;
- return slpte;
- }
- slpte = le64_to_cpu(slpte);
- return slpte;
-}
-
-/* Given a gpa and the level of paging structure, return the offset of current
- * level.
- */
-static inline uint32_t vtd_gpa_level_offset(uint64_t gpa, uint32_t level)
-{
- return (gpa >> vtd_slpt_level_shift(level)) &
- ((1ULL << VTD_SL_LEVEL_BITS) - 1);
-}
-
-/* Check Capability Register to see if the @level of page-table is supported */
-static inline bool vtd_is_level_supported(IntelIOMMUState *s, uint32_t level)
-{
- return VTD_CAP_SAGAW_MASK & s->cap &
- (1ULL << (level - 2 + VTD_CAP_SAGAW_SHIFT));
-}
-
-/* Get the page-table level that hardware should use for the second-level
- * page-table walk from the Address Width field of context-entry.
- */
-static inline uint32_t vtd_get_level_from_context_entry(VTDContextEntry *ce)
-{
- return 2 + (ce->hi & VTD_CONTEXT_ENTRY_AW);
-}
-
-static inline uint32_t vtd_get_agaw_from_context_entry(VTDContextEntry *ce)
-{
- return 30 + (ce->hi & VTD_CONTEXT_ENTRY_AW) * 9;
-}
-
-static const uint64_t vtd_paging_entry_rsvd_field[] = {
- [0] = ~0ULL,
- /* For not large page */
- [1] = 0x800ULL | ~(VTD_HAW_MASK | VTD_SL_IGN_COM),
- [2] = 0x800ULL | ~(VTD_HAW_MASK | VTD_SL_IGN_COM),
- [3] = 0x800ULL | ~(VTD_HAW_MASK | VTD_SL_IGN_COM),
- [4] = 0x880ULL | ~(VTD_HAW_MASK | VTD_SL_IGN_COM),
- /* For large page */
- [5] = 0x800ULL | ~(VTD_HAW_MASK | VTD_SL_IGN_COM),
- [6] = 0x1ff800ULL | ~(VTD_HAW_MASK | VTD_SL_IGN_COM),
- [7] = 0x3ffff800ULL | ~(VTD_HAW_MASK | VTD_SL_IGN_COM),
- [8] = 0x880ULL | ~(VTD_HAW_MASK | VTD_SL_IGN_COM),
-};
-
-static bool vtd_slpte_nonzero_rsvd(uint64_t slpte, uint32_t level)
-{
- if (slpte & VTD_SL_PT_PAGE_SIZE_MASK) {
- /* Maybe large page */
- return slpte & vtd_paging_entry_rsvd_field[level + 4];
- } else {
- return slpte & vtd_paging_entry_rsvd_field[level];
- }
-}
-
-/* Given the @gpa, get relevant @slptep. @slpte_level will be the last level
- * of the translation, can be used for deciding the size of large page.
- */
-static int vtd_gpa_to_slpte(VTDContextEntry *ce, uint64_t gpa, bool is_write,
- uint64_t *slptep, uint32_t *slpte_level,
- bool *reads, bool *writes)
-{
- dma_addr_t addr = vtd_get_slpt_base_from_context(ce);
- uint32_t level = vtd_get_level_from_context_entry(ce);
- uint32_t offset;
- uint64_t slpte;
- uint32_t ce_agaw = vtd_get_agaw_from_context_entry(ce);
- uint64_t access_right_check;
-
- /* Check if @gpa is above 2^X-1, where X is the minimum of MGAW in CAP_REG
- * and AW in context-entry.
- */
- if (gpa & ~((1ULL << MIN(ce_agaw, VTD_MGAW)) - 1)) {
- VTD_DPRINTF(GENERAL, "error: gpa 0x%"PRIx64 " exceeds limits", gpa);
- return -VTD_FR_ADDR_BEYOND_MGAW;
- }
-
- /* FIXME: what is the Atomics request here? */
- access_right_check = is_write ? VTD_SL_W : VTD_SL_R;
-
- while (true) {
- offset = vtd_gpa_level_offset(gpa, level);
- slpte = vtd_get_slpte(addr, offset);
-
- if (slpte == (uint64_t)-1) {
- VTD_DPRINTF(GENERAL, "error: fail to access second-level paging "
- "entry at level %"PRIu32 " for gpa 0x%"PRIx64,
- level, gpa);
- if (level == vtd_get_level_from_context_entry(ce)) {
- /* Invalid programming of context-entry */
- return -VTD_FR_CONTEXT_ENTRY_INV;
- } else {
- return -VTD_FR_PAGING_ENTRY_INV;
- }
- }
- *reads = (*reads) && (slpte & VTD_SL_R);
- *writes = (*writes) && (slpte & VTD_SL_W);
- if (!(slpte & access_right_check)) {
- VTD_DPRINTF(GENERAL, "error: lack of %s permission for "
- "gpa 0x%"PRIx64 " slpte 0x%"PRIx64,
- (is_write ? "write" : "read"), gpa, slpte);
- return is_write ? -VTD_FR_WRITE : -VTD_FR_READ;
- }
- if (vtd_slpte_nonzero_rsvd(slpte, level)) {
- VTD_DPRINTF(GENERAL, "error: non-zero reserved field in second "
- "level paging entry level %"PRIu32 " slpte 0x%"PRIx64,
- level, slpte);
- return -VTD_FR_PAGING_ENTRY_RSVD;
- }
-
- if (vtd_is_last_slpte(slpte, level)) {
- *slptep = slpte;
- *slpte_level = level;
- return 0;
- }
- addr = vtd_get_slpte_addr(slpte);
- level--;
- }
-}
-
-/* Map a device to its corresponding domain (context-entry) */
-static int vtd_dev_to_context_entry(IntelIOMMUState *s, uint8_t bus_num,
- uint8_t devfn, VTDContextEntry *ce)
-{
- VTDRootEntry re;
- int ret_fr;
-
- ret_fr = vtd_get_root_entry(s, bus_num, &re);
- if (ret_fr) {
- return ret_fr;
- }
-
- if (!vtd_root_entry_present(&re)) {
- VTD_DPRINTF(GENERAL, "error: root-entry #%"PRIu8 " is not present",
- bus_num);
- return -VTD_FR_ROOT_ENTRY_P;
- } else if (re.rsvd || (re.val & VTD_ROOT_ENTRY_RSVD)) {
- VTD_DPRINTF(GENERAL, "error: non-zero reserved field in root-entry "
- "hi 0x%"PRIx64 " lo 0x%"PRIx64, re.rsvd, re.val);
- return -VTD_FR_ROOT_ENTRY_RSVD;
- }
-
- ret_fr = vtd_get_context_entry_from_root(&re, devfn, ce);
- if (ret_fr) {
- return ret_fr;
- }
-
- if (!vtd_context_entry_present(ce)) {
- VTD_DPRINTF(GENERAL,
- "error: context-entry #%"PRIu8 "(bus #%"PRIu8 ") "
- "is not present", devfn, bus_num);
- return -VTD_FR_CONTEXT_ENTRY_P;
- } else if ((ce->hi & VTD_CONTEXT_ENTRY_RSVD_HI) ||
- (ce->lo & VTD_CONTEXT_ENTRY_RSVD_LO)) {
- VTD_DPRINTF(GENERAL,
- "error: non-zero reserved field in context-entry "
- "hi 0x%"PRIx64 " lo 0x%"PRIx64, ce->hi, ce->lo);
- return -VTD_FR_CONTEXT_ENTRY_RSVD;
- }
- /* Check if the programming of context-entry is valid */
- if (!vtd_is_level_supported(s, vtd_get_level_from_context_entry(ce))) {
- VTD_DPRINTF(GENERAL, "error: unsupported Address Width value in "
- "context-entry hi 0x%"PRIx64 " lo 0x%"PRIx64,
- ce->hi, ce->lo);
- return -VTD_FR_CONTEXT_ENTRY_INV;
- } else if (ce->lo & VTD_CONTEXT_ENTRY_TT) {
- VTD_DPRINTF(GENERAL, "error: unsupported Translation Type in "
- "context-entry hi 0x%"PRIx64 " lo 0x%"PRIx64,
- ce->hi, ce->lo);
- return -VTD_FR_CONTEXT_ENTRY_INV;
- }
- return 0;
-}
-
-static inline uint16_t vtd_make_source_id(uint8_t bus_num, uint8_t devfn)
-{
- return ((bus_num & 0xffUL) << 8) | (devfn & 0xffUL);
-}
-
-static const bool vtd_qualified_faults[] = {
- [VTD_FR_RESERVED] = false,
- [VTD_FR_ROOT_ENTRY_P] = false,
- [VTD_FR_CONTEXT_ENTRY_P] = true,
- [VTD_FR_CONTEXT_ENTRY_INV] = true,
- [VTD_FR_ADDR_BEYOND_MGAW] = true,
- [VTD_FR_WRITE] = true,
- [VTD_FR_READ] = true,
- [VTD_FR_PAGING_ENTRY_INV] = true,
- [VTD_FR_ROOT_TABLE_INV] = false,
- [VTD_FR_CONTEXT_TABLE_INV] = false,
- [VTD_FR_ROOT_ENTRY_RSVD] = false,
- [VTD_FR_PAGING_ENTRY_RSVD] = true,
- [VTD_FR_CONTEXT_ENTRY_TT] = true,
- [VTD_FR_RESERVED_ERR] = false,
- [VTD_FR_MAX] = false,
-};
-
-/* To see if a fault condition is "qualified", which is reported to software
- * only if the FPD field in the context-entry used to process the faulting
- * request is 0.
- */
-static inline bool vtd_is_qualified_fault(VTDFaultReason fault)
-{
- return vtd_qualified_faults[fault];
-}
-
-static inline bool vtd_is_interrupt_addr(hwaddr addr)
-{
- return VTD_INTERRUPT_ADDR_FIRST <= addr && addr <= VTD_INTERRUPT_ADDR_LAST;
-}
-
-/* Map dev to context-entry then do a paging-structures walk to do a iommu
- * translation.
- *
- * Called from RCU critical section.
- *
- * @bus_num: The bus number
- * @devfn: The devfn, which is the combined of device and function number
- * @is_write: The access is a write operation
- * @entry: IOMMUTLBEntry that contain the addr to be translated and result
- */
-static void vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus,
- uint8_t devfn, hwaddr addr, bool is_write,
- IOMMUTLBEntry *entry)
-{
- IntelIOMMUState *s = vtd_as->iommu_state;
- VTDContextEntry ce;
- uint8_t bus_num = pci_bus_num(bus);
- VTDContextCacheEntry *cc_entry = &vtd_as->context_cache_entry;
- uint64_t slpte, page_mask;
- uint32_t level;
- uint16_t source_id = vtd_make_source_id(bus_num, devfn);
- int ret_fr;
- bool is_fpd_set = false;
- bool reads = true;
- bool writes = true;
- VTDIOTLBEntry *iotlb_entry;
-
- /* Check if the request is in interrupt address range */
- if (vtd_is_interrupt_addr(addr)) {
- if (is_write) {
- /* FIXME: since we don't know the length of the access here, we
- * treat Non-DWORD length write requests without PASID as
- * interrupt requests, too. Withoud interrupt remapping support,
- * we just use 1:1 mapping.
- */
- VTD_DPRINTF(MMU, "write request to interrupt address "
- "gpa 0x%"PRIx64, addr);
- entry->iova = addr & VTD_PAGE_MASK_4K;
- entry->translated_addr = addr & VTD_PAGE_MASK_4K;
- entry->addr_mask = ~VTD_PAGE_MASK_4K;
- entry->perm = IOMMU_WO;
- return;
- } else {
- VTD_DPRINTF(GENERAL, "error: read request from interrupt address "
- "gpa 0x%"PRIx64, addr);
- vtd_report_dmar_fault(s, source_id, addr, VTD_FR_READ, is_write);
- return;
- }
- }
- /* Try to fetch slpte form IOTLB */
- iotlb_entry = vtd_lookup_iotlb(s, source_id, addr);
- if (iotlb_entry) {
- VTD_DPRINTF(CACHE, "hit iotlb sid 0x%"PRIx16 " gpa 0x%"PRIx64
- " slpte 0x%"PRIx64 " did 0x%"PRIx16, source_id, addr,
- iotlb_entry->slpte, iotlb_entry->domain_id);
- slpte = iotlb_entry->slpte;
- reads = iotlb_entry->read_flags;
- writes = iotlb_entry->write_flags;
- page_mask = iotlb_entry->mask;
- goto out;
- }
- /* Try to fetch context-entry from cache first */
- if (cc_entry->context_cache_gen == s->context_cache_gen) {
- VTD_DPRINTF(CACHE, "hit context-cache bus %d devfn %d "
- "(hi %"PRIx64 " lo %"PRIx64 " gen %"PRIu32 ")",
- bus_num, devfn, cc_entry->context_entry.hi,
- cc_entry->context_entry.lo, cc_entry->context_cache_gen);
- ce = cc_entry->context_entry;
- is_fpd_set = ce.lo & VTD_CONTEXT_ENTRY_FPD;
- } else {
- ret_fr = vtd_dev_to_context_entry(s, bus_num, devfn, &ce);
- is_fpd_set = ce.lo & VTD_CONTEXT_ENTRY_FPD;
- if (ret_fr) {
- ret_fr = -ret_fr;
- if (is_fpd_set && vtd_is_qualified_fault(ret_fr)) {
- VTD_DPRINTF(FLOG, "fault processing is disabled for DMA "
- "requests through this context-entry "
- "(with FPD Set)");
- } else {
- vtd_report_dmar_fault(s, source_id, addr, ret_fr, is_write);
- }
- return;
- }
- /* Update context-cache */
- VTD_DPRINTF(CACHE, "update context-cache bus %d devfn %d "
- "(hi %"PRIx64 " lo %"PRIx64 " gen %"PRIu32 "->%"PRIu32 ")",
- bus_num, devfn, ce.hi, ce.lo,
- cc_entry->context_cache_gen, s->context_cache_gen);
- cc_entry->context_entry = ce;
- cc_entry->context_cache_gen = s->context_cache_gen;
- }
-
- ret_fr = vtd_gpa_to_slpte(&ce, addr, is_write, &slpte, &level,
- &reads, &writes);
- if (ret_fr) {
- ret_fr = -ret_fr;
- if (is_fpd_set && vtd_is_qualified_fault(ret_fr)) {
- VTD_DPRINTF(FLOG, "fault processing is disabled for DMA requests "
- "through this context-entry (with FPD Set)");
- } else {
- vtd_report_dmar_fault(s, source_id, addr, ret_fr, is_write);
- }
- return;
- }
-
- page_mask = vtd_slpt_level_page_mask(level);
- vtd_update_iotlb(s, source_id, VTD_CONTEXT_ENTRY_DID(ce.hi), addr, slpte,
- reads, writes, level);
-out:
- entry->iova = addr & page_mask;
- entry->translated_addr = vtd_get_slpte_addr(slpte) & page_mask;
- entry->addr_mask = ~page_mask;
- entry->perm = (writes ? 2 : 0) + (reads ? 1 : 0);
-}
-
-static void vtd_root_table_setup(IntelIOMMUState *s)
-{
- s->root = vtd_get_quad_raw(s, DMAR_RTADDR_REG);
- s->root_extended = s->root & VTD_RTADDR_RTT;
- s->root &= VTD_RTADDR_ADDR_MASK;
-
- VTD_DPRINTF(CSR, "root_table addr 0x%"PRIx64 " %s", s->root,
- (s->root_extended ? "(extended)" : ""));
-}
-
-static void vtd_context_global_invalidate(IntelIOMMUState *s)
-{
- s->context_cache_gen++;
- if (s->context_cache_gen == VTD_CONTEXT_CACHE_GEN_MAX) {
- vtd_reset_context_cache(s);
- }
-}
-
-
-/* Find the VTD address space currently associated with a given bus number,
- */
-static VTDBus *vtd_find_as_from_bus_num(IntelIOMMUState *s, uint8_t bus_num)
-{
- VTDBus *vtd_bus = s->vtd_as_by_bus_num[bus_num];
- if (!vtd_bus) {
- /* Iterate over the registered buses to find the one
- * which currently hold this bus number, and update the bus_num lookup table:
- */
- GHashTableIter iter;
-
- g_hash_table_iter_init(&iter, s->vtd_as_by_busptr);
- while (g_hash_table_iter_next (&iter, NULL, (void**)&vtd_bus)) {
- if (pci_bus_num(vtd_bus->bus) == bus_num) {
- s->vtd_as_by_bus_num[bus_num] = vtd_bus;
- return vtd_bus;
- }
- }
- }
- return vtd_bus;
-}
-
-/* Do a context-cache device-selective invalidation.
- * @func_mask: FM field after shifting
- */
-static void vtd_context_device_invalidate(IntelIOMMUState *s,
- uint16_t source_id,
- uint16_t func_mask)
-{
- uint16_t mask;
- VTDBus *vtd_bus;
- VTDAddressSpace *vtd_as;
- uint16_t devfn;
- uint16_t devfn_it;
-
- switch (func_mask & 3) {
- case 0:
- mask = 0; /* No bits in the SID field masked */
- break;
- case 1:
- mask = 4; /* Mask bit 2 in the SID field */
- break;
- case 2:
- mask = 6; /* Mask bit 2:1 in the SID field */
- break;
- case 3:
- mask = 7; /* Mask bit 2:0 in the SID field */
- break;
- }
- VTD_DPRINTF(INV, "device-selective invalidation source 0x%"PRIx16
- " mask %"PRIu16, source_id, mask);
- vtd_bus = vtd_find_as_from_bus_num(s, VTD_SID_TO_BUS(source_id));
- if (vtd_bus) {
- devfn = VTD_SID_TO_DEVFN(source_id);
- for (devfn_it = 0; devfn_it < VTD_PCI_DEVFN_MAX; ++devfn_it) {
- vtd_as = vtd_bus->dev_as[devfn_it];
- if (vtd_as && ((devfn_it & mask) == (devfn & mask))) {
- VTD_DPRINTF(INV, "invalidate context-cahce of devfn 0x%"PRIx16,
- devfn_it);
- vtd_as->context_cache_entry.context_cache_gen = 0;
- }
- }
- }
-}
-
-/* Context-cache invalidation
- * Returns the Context Actual Invalidation Granularity.
- * @val: the content of the CCMD_REG
- */
-static uint64_t vtd_context_cache_invalidate(IntelIOMMUState *s, uint64_t val)
-{
- uint64_t caig;
- uint64_t type = val & VTD_CCMD_CIRG_MASK;
-
- switch (type) {
- case VTD_CCMD_DOMAIN_INVL:
- VTD_DPRINTF(INV, "domain-selective invalidation domain 0x%"PRIx16,
- (uint16_t)VTD_CCMD_DID(val));
- /* Fall through */
- case VTD_CCMD_GLOBAL_INVL:
- VTD_DPRINTF(INV, "global invalidation");
- caig = VTD_CCMD_GLOBAL_INVL_A;
- vtd_context_global_invalidate(s);
- break;
-
- case VTD_CCMD_DEVICE_INVL:
- caig = VTD_CCMD_DEVICE_INVL_A;
- vtd_context_device_invalidate(s, VTD_CCMD_SID(val), VTD_CCMD_FM(val));
- break;
-
- default:
- VTD_DPRINTF(GENERAL, "error: invalid granularity");
- caig = 0;
- }
- return caig;
-}
-
-static void vtd_iotlb_global_invalidate(IntelIOMMUState *s)
-{
- vtd_reset_iotlb(s);
-}
-
-static void vtd_iotlb_domain_invalidate(IntelIOMMUState *s, uint16_t domain_id)
-{
- g_hash_table_foreach_remove(s->iotlb, vtd_hash_remove_by_domain,
- &domain_id);
-}
-
-static void vtd_iotlb_page_invalidate(IntelIOMMUState *s, uint16_t domain_id,
- hwaddr addr, uint8_t am)
-{
- VTDIOTLBPageInvInfo info;
-
- assert(am <= VTD_MAMV);
- info.domain_id = domain_id;
- info.addr = addr;
- info.mask = ~((1 << am) - 1);
- g_hash_table_foreach_remove(s->iotlb, vtd_hash_remove_by_page, &info);
-}
-
-/* Flush IOTLB
- * Returns the IOTLB Actual Invalidation Granularity.
- * @val: the content of the IOTLB_REG
- */
-static uint64_t vtd_iotlb_flush(IntelIOMMUState *s, uint64_t val)
-{
- uint64_t iaig;
- uint64_t type = val & VTD_TLB_FLUSH_GRANU_MASK;
- uint16_t domain_id;
- hwaddr addr;
- uint8_t am;
-
- switch (type) {
- case VTD_TLB_GLOBAL_FLUSH:
- VTD_DPRINTF(INV, "global invalidation");
- iaig = VTD_TLB_GLOBAL_FLUSH_A;
- vtd_iotlb_global_invalidate(s);
- break;
-
- case VTD_TLB_DSI_FLUSH:
- domain_id = VTD_TLB_DID(val);
- VTD_DPRINTF(INV, "domain-selective invalidation domain 0x%"PRIx16,
- domain_id);
- iaig = VTD_TLB_DSI_FLUSH_A;
- vtd_iotlb_domain_invalidate(s, domain_id);
- break;
-
- case VTD_TLB_PSI_FLUSH:
- domain_id = VTD_TLB_DID(val);
- addr = vtd_get_quad_raw(s, DMAR_IVA_REG);
- am = VTD_IVA_AM(addr);
- addr = VTD_IVA_ADDR(addr);
- VTD_DPRINTF(INV, "page-selective invalidation domain 0x%"PRIx16
- " addr 0x%"PRIx64 " mask %"PRIu8, domain_id, addr, am);
- if (am > VTD_MAMV) {
- VTD_DPRINTF(GENERAL, "error: supported max address mask value is "
- "%"PRIu8, (uint8_t)VTD_MAMV);
- iaig = 0;
- break;
- }
- iaig = VTD_TLB_PSI_FLUSH_A;
- vtd_iotlb_page_invalidate(s, domain_id, addr, am);
- break;
-
- default:
- VTD_DPRINTF(GENERAL, "error: invalid granularity");
- iaig = 0;
- }
- return iaig;
-}
-
-static inline bool vtd_queued_inv_enable_check(IntelIOMMUState *s)
-{
- return s->iq_tail == 0;
-}
-
-static inline bool vtd_queued_inv_disable_check(IntelIOMMUState *s)
-{
- return s->qi_enabled && (s->iq_tail == s->iq_head) &&
- (s->iq_last_desc_type == VTD_INV_DESC_WAIT);
-}
-
-static void vtd_handle_gcmd_qie(IntelIOMMUState *s, bool en)
-{
- uint64_t iqa_val = vtd_get_quad_raw(s, DMAR_IQA_REG);
-
- VTD_DPRINTF(INV, "Queued Invalidation Enable %s", (en ? "on" : "off"));
- if (en) {
- if (vtd_queued_inv_enable_check(s)) {
- s->iq = iqa_val & VTD_IQA_IQA_MASK;
- /* 2^(x+8) entries */
- s->iq_size = 1UL << ((iqa_val & VTD_IQA_QS) + 8);
- s->qi_enabled = true;
- VTD_DPRINTF(INV, "DMAR_IQA_REG 0x%"PRIx64, iqa_val);
- VTD_DPRINTF(INV, "Invalidation Queue addr 0x%"PRIx64 " size %d",
- s->iq, s->iq_size);
- /* Ok - report back to driver */
- vtd_set_clear_mask_long(s, DMAR_GSTS_REG, 0, VTD_GSTS_QIES);
- } else {
- VTD_DPRINTF(GENERAL, "error: can't enable Queued Invalidation: "
- "tail %"PRIu16, s->iq_tail);
- }
- } else {
- if (vtd_queued_inv_disable_check(s)) {
- /* disable Queued Invalidation */
- vtd_set_quad_raw(s, DMAR_IQH_REG, 0);
- s->iq_head = 0;
- s->qi_enabled = false;
- /* Ok - report back to driver */
- vtd_set_clear_mask_long(s, DMAR_GSTS_REG, VTD_GSTS_QIES, 0);
- } else {
- VTD_DPRINTF(GENERAL, "error: can't disable Queued Invalidation: "
- "head %"PRIu16 ", tail %"PRIu16
- ", last_descriptor %"PRIu8,
- s->iq_head, s->iq_tail, s->iq_last_desc_type);
- }
- }
-}
-
-/* Set Root Table Pointer */
-static void vtd_handle_gcmd_srtp(IntelIOMMUState *s)
-{
- VTD_DPRINTF(CSR, "set Root Table Pointer");
-
- vtd_root_table_setup(s);
- /* Ok - report back to driver */
- vtd_set_clear_mask_long(s, DMAR_GSTS_REG, 0, VTD_GSTS_RTPS);
-}
-
-/* Handle Translation Enable/Disable */
-static void vtd_handle_gcmd_te(IntelIOMMUState *s, bool en)
-{
- VTD_DPRINTF(CSR, "Translation Enable %s", (en ? "on" : "off"));
-
- if (en) {
- s->dmar_enabled = true;
- /* Ok - report back to driver */
- vtd_set_clear_mask_long(s, DMAR_GSTS_REG, 0, VTD_GSTS_TES);
- } else {
- s->dmar_enabled = false;
-
- /* Clear the index of Fault Recording Register */
- s->next_frcd_reg = 0;
- /* Ok - report back to driver */
- vtd_set_clear_mask_long(s, DMAR_GSTS_REG, VTD_GSTS_TES, 0);
- }
-}
-
-/* Handle write to Global Command Register */
-static void vtd_handle_gcmd_write(IntelIOMMUState *s)
-{
- uint32_t status = vtd_get_long_raw(s, DMAR_GSTS_REG);
- uint32_t val = vtd_get_long_raw(s, DMAR_GCMD_REG);
- uint32_t changed = status ^ val;
-
- VTD_DPRINTF(CSR, "value 0x%"PRIx32 " status 0x%"PRIx32, val, status);
- if (changed & VTD_GCMD_TE) {
- /* Translation enable/disable */
- vtd_handle_gcmd_te(s, val & VTD_GCMD_TE);
- }
- if (val & VTD_GCMD_SRTP) {
- /* Set/update the root-table pointer */
- vtd_handle_gcmd_srtp(s);
- }
- if (changed & VTD_GCMD_QIE) {
- /* Queued Invalidation Enable */
- vtd_handle_gcmd_qie(s, val & VTD_GCMD_QIE);
- }
-}
-
-/* Handle write to Context Command Register */
-static void vtd_handle_ccmd_write(IntelIOMMUState *s)
-{
- uint64_t ret;
- uint64_t val = vtd_get_quad_raw(s, DMAR_CCMD_REG);
-
- /* Context-cache invalidation request */
- if (val & VTD_CCMD_ICC) {
- if (s->qi_enabled) {
- VTD_DPRINTF(GENERAL, "error: Queued Invalidation enabled, "
- "should not use register-based invalidation");
- return;
- }
- ret = vtd_context_cache_invalidate(s, val);
- /* Invalidation completed. Change something to show */
- vtd_set_clear_mask_quad(s, DMAR_CCMD_REG, VTD_CCMD_ICC, 0ULL);
- ret = vtd_set_clear_mask_quad(s, DMAR_CCMD_REG, VTD_CCMD_CAIG_MASK,
- ret);
- VTD_DPRINTF(INV, "CCMD_REG write-back val: 0x%"PRIx64, ret);
- }
-}
-
-/* Handle write to IOTLB Invalidation Register */
-static void vtd_handle_iotlb_write(IntelIOMMUState *s)
-{
- uint64_t ret;
- uint64_t val = vtd_get_quad_raw(s, DMAR_IOTLB_REG);
-
- /* IOTLB invalidation request */
- if (val & VTD_TLB_IVT) {
- if (s->qi_enabled) {
- VTD_DPRINTF(GENERAL, "error: Queued Invalidation enabled, "
- "should not use register-based invalidation");
- return;
- }
- ret = vtd_iotlb_flush(s, val);
- /* Invalidation completed. Change something to show */
- vtd_set_clear_mask_quad(s, DMAR_IOTLB_REG, VTD_TLB_IVT, 0ULL);
- ret = vtd_set_clear_mask_quad(s, DMAR_IOTLB_REG,
- VTD_TLB_FLUSH_GRANU_MASK_A, ret);
- VTD_DPRINTF(INV, "IOTLB_REG write-back val: 0x%"PRIx64, ret);
- }
-}
-
-/* Fetch an Invalidation Descriptor from the Invalidation Queue */
-static bool vtd_get_inv_desc(dma_addr_t base_addr, uint32_t offset,
- VTDInvDesc *inv_desc)
-{
- dma_addr_t addr = base_addr + offset * sizeof(*inv_desc);
- if (dma_memory_read(&address_space_memory, addr, inv_desc,
- sizeof(*inv_desc))) {
- VTD_DPRINTF(GENERAL, "error: fail to fetch Invalidation Descriptor "
- "base_addr 0x%"PRIx64 " offset %"PRIu32, base_addr, offset);
- inv_desc->lo = 0;
- inv_desc->hi = 0;
-
- return false;
- }
- inv_desc->lo = le64_to_cpu(inv_desc->lo);
- inv_desc->hi = le64_to_cpu(inv_desc->hi);
- return true;
-}
-
-static bool vtd_process_wait_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc)
-{
- if ((inv_desc->hi & VTD_INV_DESC_WAIT_RSVD_HI) ||
- (inv_desc->lo & VTD_INV_DESC_WAIT_RSVD_LO)) {
- VTD_DPRINTF(GENERAL, "error: non-zero reserved field in Invalidation "
- "Wait Descriptor hi 0x%"PRIx64 " lo 0x%"PRIx64,
- inv_desc->hi, inv_desc->lo);
- return false;
- }
- if (inv_desc->lo & VTD_INV_DESC_WAIT_SW) {
- /* Status Write */
- uint32_t status_data = (uint32_t)(inv_desc->lo >>
- VTD_INV_DESC_WAIT_DATA_SHIFT);
-
- assert(!(inv_desc->lo & VTD_INV_DESC_WAIT_IF));
-
- /* FIXME: need to be masked with HAW? */
- dma_addr_t status_addr = inv_desc->hi;
- VTD_DPRINTF(INV, "status data 0x%x, status addr 0x%"PRIx64,
- status_data, status_addr);
- status_data = cpu_to_le32(status_data);
- if (dma_memory_write(&address_space_memory, status_addr, &status_data,
- sizeof(status_data))) {
- VTD_DPRINTF(GENERAL, "error: fail to perform a coherent write");
- return false;
- }
- } else if (inv_desc->lo & VTD_INV_DESC_WAIT_IF) {
- /* Interrupt flag */
- VTD_DPRINTF(INV, "Invalidation Wait Descriptor interrupt completion");
- vtd_generate_completion_event(s);
- } else {
- VTD_DPRINTF(GENERAL, "error: invalid Invalidation Wait Descriptor: "
- "hi 0x%"PRIx64 " lo 0x%"PRIx64, inv_desc->hi, inv_desc->lo);
- return false;
- }
- return true;
-}
-
-static bool vtd_process_context_cache_desc(IntelIOMMUState *s,
- VTDInvDesc *inv_desc)
-{
- if ((inv_desc->lo & VTD_INV_DESC_CC_RSVD) || inv_desc->hi) {
- VTD_DPRINTF(GENERAL, "error: non-zero reserved field in Context-cache "
- "Invalidate Descriptor");
- return false;
- }
- switch (inv_desc->lo & VTD_INV_DESC_CC_G) {
- case VTD_INV_DESC_CC_DOMAIN:
- VTD_DPRINTF(INV, "domain-selective invalidation domain 0x%"PRIx16,
- (uint16_t)VTD_INV_DESC_CC_DID(inv_desc->lo));
- /* Fall through */
- case VTD_INV_DESC_CC_GLOBAL:
- VTD_DPRINTF(INV, "global invalidation");
- vtd_context_global_invalidate(s);
- break;
-
- case VTD_INV_DESC_CC_DEVICE:
- vtd_context_device_invalidate(s, VTD_INV_DESC_CC_SID(inv_desc->lo),
- VTD_INV_DESC_CC_FM(inv_desc->lo));
- break;
-
- default:
- VTD_DPRINTF(GENERAL, "error: invalid granularity in Context-cache "
- "Invalidate Descriptor hi 0x%"PRIx64 " lo 0x%"PRIx64,
- inv_desc->hi, inv_desc->lo);
- return false;
- }
- return true;
-}
-
-static bool vtd_process_iotlb_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc)
-{
- uint16_t domain_id;
- uint8_t am;
- hwaddr addr;
-
- if ((inv_desc->lo & VTD_INV_DESC_IOTLB_RSVD_LO) ||
- (inv_desc->hi & VTD_INV_DESC_IOTLB_RSVD_HI)) {
- VTD_DPRINTF(GENERAL, "error: non-zero reserved field in IOTLB "
- "Invalidate Descriptor hi 0x%"PRIx64 " lo 0x%"PRIx64,
- inv_desc->hi, inv_desc->lo);
- return false;
- }
-
- switch (inv_desc->lo & VTD_INV_DESC_IOTLB_G) {
- case VTD_INV_DESC_IOTLB_GLOBAL:
- VTD_DPRINTF(INV, "global invalidation");
- vtd_iotlb_global_invalidate(s);
- break;
-
- case VTD_INV_DESC_IOTLB_DOMAIN:
- domain_id = VTD_INV_DESC_IOTLB_DID(inv_desc->lo);
- VTD_DPRINTF(INV, "domain-selective invalidation domain 0x%"PRIx16,
- domain_id);
- vtd_iotlb_domain_invalidate(s, domain_id);
- break;
-
- case VTD_INV_DESC_IOTLB_PAGE:
- domain_id = VTD_INV_DESC_IOTLB_DID(inv_desc->lo);
- addr = VTD_INV_DESC_IOTLB_ADDR(inv_desc->hi);
- am = VTD_INV_DESC_IOTLB_AM(inv_desc->hi);
- VTD_DPRINTF(INV, "page-selective invalidation domain 0x%"PRIx16
- " addr 0x%"PRIx64 " mask %"PRIu8, domain_id, addr, am);
- if (am > VTD_MAMV) {
- VTD_DPRINTF(GENERAL, "error: supported max address mask value is "
- "%"PRIu8, (uint8_t)VTD_MAMV);
- return false;
- }
- vtd_iotlb_page_invalidate(s, domain_id, addr, am);
- break;
-
- default:
- VTD_DPRINTF(GENERAL, "error: invalid granularity in IOTLB Invalidate "
- "Descriptor hi 0x%"PRIx64 " lo 0x%"PRIx64,
- inv_desc->hi, inv_desc->lo);
- return false;
- }
- return true;
-}
-
-static bool vtd_process_inv_desc(IntelIOMMUState *s)
-{
- VTDInvDesc inv_desc;
- uint8_t desc_type;
-
- VTD_DPRINTF(INV, "iq head %"PRIu16, s->iq_head);
- if (!vtd_get_inv_desc(s->iq, s->iq_head, &inv_desc)) {
- s->iq_last_desc_type = VTD_INV_DESC_NONE;
- return false;
- }
- desc_type = inv_desc.lo & VTD_INV_DESC_TYPE;
- /* FIXME: should update at first or at last? */
- s->iq_last_desc_type = desc_type;
-
- switch (desc_type) {
- case VTD_INV_DESC_CC:
- VTD_DPRINTF(INV, "Context-cache Invalidate Descriptor hi 0x%"PRIx64
- " lo 0x%"PRIx64, inv_desc.hi, inv_desc.lo);
- if (!vtd_process_context_cache_desc(s, &inv_desc)) {
- return false;
- }
- break;
-
- case VTD_INV_DESC_IOTLB:
- VTD_DPRINTF(INV, "IOTLB Invalidate Descriptor hi 0x%"PRIx64
- " lo 0x%"PRIx64, inv_desc.hi, inv_desc.lo);
- if (!vtd_process_iotlb_desc(s, &inv_desc)) {
- return false;
- }
- break;
-
- case VTD_INV_DESC_WAIT:
- VTD_DPRINTF(INV, "Invalidation Wait Descriptor hi 0x%"PRIx64
- " lo 0x%"PRIx64, inv_desc.hi, inv_desc.lo);
- if (!vtd_process_wait_desc(s, &inv_desc)) {
- return false;
- }
- break;
-
- default:
- VTD_DPRINTF(GENERAL, "error: unkonw Invalidation Descriptor type "
- "hi 0x%"PRIx64 " lo 0x%"PRIx64 " type %"PRIu8,
- inv_desc.hi, inv_desc.lo, desc_type);
- return false;
- }
- s->iq_head++;
- if (s->iq_head == s->iq_size) {
- s->iq_head = 0;
- }
- return true;
-}
-
-/* Try to fetch and process more Invalidation Descriptors */
-static void vtd_fetch_inv_desc(IntelIOMMUState *s)
-{
- VTD_DPRINTF(INV, "fetch Invalidation Descriptors");
- if (s->iq_tail >= s->iq_size) {
- /* Detects an invalid Tail pointer */
- VTD_DPRINTF(GENERAL, "error: iq_tail is %"PRIu16
- " while iq_size is %"PRIu16, s->iq_tail, s->iq_size);
- vtd_handle_inv_queue_error(s);
- return;
- }
- while (s->iq_head != s->iq_tail) {
- if (!vtd_process_inv_desc(s)) {
- /* Invalidation Queue Errors */
- vtd_handle_inv_queue_error(s);
- break;
- }
- /* Must update the IQH_REG in time */
- vtd_set_quad_raw(s, DMAR_IQH_REG,
- (((uint64_t)(s->iq_head)) << VTD_IQH_QH_SHIFT) &
- VTD_IQH_QH_MASK);
- }
-}
-
-/* Handle write to Invalidation Queue Tail Register */
-static void vtd_handle_iqt_write(IntelIOMMUState *s)
-{
- uint64_t val = vtd_get_quad_raw(s, DMAR_IQT_REG);
-
- s->iq_tail = VTD_IQT_QT(val);
- VTD_DPRINTF(INV, "set iq tail %"PRIu16, s->iq_tail);
- if (s->qi_enabled && !(vtd_get_long_raw(s, DMAR_FSTS_REG) & VTD_FSTS_IQE)) {
- /* Process Invalidation Queue here */
- vtd_fetch_inv_desc(s);
- }
-}
-
-static void vtd_handle_fsts_write(IntelIOMMUState *s)
-{
- uint32_t fsts_reg = vtd_get_long_raw(s, DMAR_FSTS_REG);
- uint32_t fectl_reg = vtd_get_long_raw(s, DMAR_FECTL_REG);
- uint32_t status_fields = VTD_FSTS_PFO | VTD_FSTS_PPF | VTD_FSTS_IQE;
-
- if ((fectl_reg & VTD_FECTL_IP) && !(fsts_reg & status_fields)) {
- vtd_set_clear_mask_long(s, DMAR_FECTL_REG, VTD_FECTL_IP, 0);
- VTD_DPRINTF(FLOG, "all pending interrupt conditions serviced, clear "
- "IP field of FECTL_REG");
- }
- /* FIXME: when IQE is Clear, should we try to fetch some Invalidation
- * Descriptors if there are any when Queued Invalidation is enabled?
- */
-}
-
-static void vtd_handle_fectl_write(IntelIOMMUState *s)
-{
- uint32_t fectl_reg;
- /* FIXME: when software clears the IM field, check the IP field. But do we
- * need to compare the old value and the new value to conclude that
- * software clears the IM field? Or just check if the IM field is zero?
- */
- fectl_reg = vtd_get_long_raw(s, DMAR_FECTL_REG);
- if ((fectl_reg & VTD_FECTL_IP) && !(fectl_reg & VTD_FECTL_IM)) {
- vtd_generate_interrupt(s, DMAR_FEADDR_REG, DMAR_FEDATA_REG);
- vtd_set_clear_mask_long(s, DMAR_FECTL_REG, VTD_FECTL_IP, 0);
- VTD_DPRINTF(FLOG, "IM field is cleared, generate "
- "fault event interrupt");
- }
-}
-
-static void vtd_handle_ics_write(IntelIOMMUState *s)
-{
- uint32_t ics_reg = vtd_get_long_raw(s, DMAR_ICS_REG);
- uint32_t iectl_reg = vtd_get_long_raw(s, DMAR_IECTL_REG);
-
- if ((iectl_reg & VTD_IECTL_IP) && !(ics_reg & VTD_ICS_IWC)) {
- vtd_set_clear_mask_long(s, DMAR_IECTL_REG, VTD_IECTL_IP, 0);
- VTD_DPRINTF(INV, "pending completion interrupt condition serviced, "
- "clear IP field of IECTL_REG");
- }
-}
-
-static void vtd_handle_iectl_write(IntelIOMMUState *s)
-{
- uint32_t iectl_reg;
- /* FIXME: when software clears the IM field, check the IP field. But do we
- * need to compare the old value and the new value to conclude that
- * software clears the IM field? Or just check if the IM field is zero?
- */
- iectl_reg = vtd_get_long_raw(s, DMAR_IECTL_REG);
- if ((iectl_reg & VTD_IECTL_IP) && !(iectl_reg & VTD_IECTL_IM)) {
- vtd_generate_interrupt(s, DMAR_IEADDR_REG, DMAR_IEDATA_REG);
- vtd_set_clear_mask_long(s, DMAR_IECTL_REG, VTD_IECTL_IP, 0);
- VTD_DPRINTF(INV, "IM field is cleared, generate "
- "invalidation event interrupt");
- }
-}
-
-static uint64_t vtd_mem_read(void *opaque, hwaddr addr, unsigned size)
-{
- IntelIOMMUState *s = opaque;
- uint64_t val;
-
- if (addr + size > DMAR_REG_SIZE) {
- VTD_DPRINTF(GENERAL, "error: addr outside region: max 0x%"PRIx64
- ", got 0x%"PRIx64 " %d",
- (uint64_t)DMAR_REG_SIZE, addr, size);
- return (uint64_t)-1;
- }
-
- switch (addr) {
- /* Root Table Address Register, 64-bit */
- case DMAR_RTADDR_REG:
- if (size == 4) {
- val = s->root & ((1ULL << 32) - 1);
- } else {
- val = s->root;
- }
- break;
-
- case DMAR_RTADDR_REG_HI:
- assert(size == 4);
- val = s->root >> 32;
- break;
-
- /* Invalidation Queue Address Register, 64-bit */
- case DMAR_IQA_REG:
- val = s->iq | (vtd_get_quad(s, DMAR_IQA_REG) & VTD_IQA_QS);
- if (size == 4) {
- val = val & ((1ULL << 32) - 1);
- }
- break;
-
- case DMAR_IQA_REG_HI:
- assert(size == 4);
- val = s->iq >> 32;
- break;
-
- default:
- if (size == 4) {
- val = vtd_get_long(s, addr);
- } else {
- val = vtd_get_quad(s, addr);
- }
- }
- VTD_DPRINTF(CSR, "addr 0x%"PRIx64 " size %d val 0x%"PRIx64,
- addr, size, val);
- return val;
-}
-
-static void vtd_mem_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- IntelIOMMUState *s = opaque;
-
- if (addr + size > DMAR_REG_SIZE) {
- VTD_DPRINTF(GENERAL, "error: addr outside region: max 0x%"PRIx64
- ", got 0x%"PRIx64 " %d",
- (uint64_t)DMAR_REG_SIZE, addr, size);
- return;
- }
-
- switch (addr) {
- /* Global Command Register, 32-bit */
- case DMAR_GCMD_REG:
- VTD_DPRINTF(CSR, "DMAR_GCMD_REG write addr 0x%"PRIx64
- ", size %d, val 0x%"PRIx64, addr, size, val);
- vtd_set_long(s, addr, val);
- vtd_handle_gcmd_write(s);
- break;
-
- /* Context Command Register, 64-bit */
- case DMAR_CCMD_REG:
- VTD_DPRINTF(CSR, "DMAR_CCMD_REG write addr 0x%"PRIx64
- ", size %d, val 0x%"PRIx64, addr, size, val);
- if (size == 4) {
- vtd_set_long(s, addr, val);
- } else {
- vtd_set_quad(s, addr, val);
- vtd_handle_ccmd_write(s);
- }
- break;
-
- case DMAR_CCMD_REG_HI:
- VTD_DPRINTF(CSR, "DMAR_CCMD_REG_HI write addr 0x%"PRIx64
- ", size %d, val 0x%"PRIx64, addr, size, val);
- assert(size == 4);
- vtd_set_long(s, addr, val);
- vtd_handle_ccmd_write(s);
- break;
-
- /* IOTLB Invalidation Register, 64-bit */
- case DMAR_IOTLB_REG:
- VTD_DPRINTF(INV, "DMAR_IOTLB_REG write addr 0x%"PRIx64
- ", size %d, val 0x%"PRIx64, addr, size, val);
- if (size == 4) {
- vtd_set_long(s, addr, val);
- } else {
- vtd_set_quad(s, addr, val);
- vtd_handle_iotlb_write(s);
- }
- break;
-
- case DMAR_IOTLB_REG_HI:
- VTD_DPRINTF(INV, "DMAR_IOTLB_REG_HI write addr 0x%"PRIx64
- ", size %d, val 0x%"PRIx64, addr, size, val);
- assert(size == 4);
- vtd_set_long(s, addr, val);
- vtd_handle_iotlb_write(s);
- break;
-
- /* Invalidate Address Register, 64-bit */
- case DMAR_IVA_REG:
- VTD_DPRINTF(INV, "DMAR_IVA_REG write addr 0x%"PRIx64
- ", size %d, val 0x%"PRIx64, addr, size, val);
- if (size == 4) {
- vtd_set_long(s, addr, val);
- } else {
- vtd_set_quad(s, addr, val);
- }
- break;
-
- case DMAR_IVA_REG_HI:
- VTD_DPRINTF(INV, "DMAR_IVA_REG_HI write addr 0x%"PRIx64
- ", size %d, val 0x%"PRIx64, addr, size, val);
- assert(size == 4);
- vtd_set_long(s, addr, val);
- break;
-
- /* Fault Status Register, 32-bit */
- case DMAR_FSTS_REG:
- VTD_DPRINTF(FLOG, "DMAR_FSTS_REG write addr 0x%"PRIx64
- ", size %d, val 0x%"PRIx64, addr, size, val);
- assert(size == 4);
- vtd_set_long(s, addr, val);
- vtd_handle_fsts_write(s);
- break;
-
- /* Fault Event Control Register, 32-bit */
- case DMAR_FECTL_REG:
- VTD_DPRINTF(FLOG, "DMAR_FECTL_REG write addr 0x%"PRIx64
- ", size %d, val 0x%"PRIx64, addr, size, val);
- assert(size == 4);
- vtd_set_long(s, addr, val);
- vtd_handle_fectl_write(s);
- break;
-
- /* Fault Event Data Register, 32-bit */
- case DMAR_FEDATA_REG:
- VTD_DPRINTF(FLOG, "DMAR_FEDATA_REG write addr 0x%"PRIx64
- ", size %d, val 0x%"PRIx64, addr, size, val);
- assert(size == 4);
- vtd_set_long(s, addr, val);
- break;
-
- /* Fault Event Address Register, 32-bit */
- case DMAR_FEADDR_REG:
- VTD_DPRINTF(FLOG, "DMAR_FEADDR_REG write addr 0x%"PRIx64
- ", size %d, val 0x%"PRIx64, addr, size, val);
- assert(size == 4);
- vtd_set_long(s, addr, val);
- break;
-
- /* Fault Event Upper Address Register, 32-bit */
- case DMAR_FEUADDR_REG:
- VTD_DPRINTF(FLOG, "DMAR_FEUADDR_REG write addr 0x%"PRIx64
- ", size %d, val 0x%"PRIx64, addr, size, val);
- assert(size == 4);
- vtd_set_long(s, addr, val);
- break;
-
- /* Protected Memory Enable Register, 32-bit */
- case DMAR_PMEN_REG:
- VTD_DPRINTF(CSR, "DMAR_PMEN_REG write addr 0x%"PRIx64
- ", size %d, val 0x%"PRIx64, addr, size, val);
- assert(size == 4);
- vtd_set_long(s, addr, val);
- break;
-
- /* Root Table Address Register, 64-bit */
- case DMAR_RTADDR_REG:
- VTD_DPRINTF(CSR, "DMAR_RTADDR_REG write addr 0x%"PRIx64
- ", size %d, val 0x%"PRIx64, addr, size, val);
- if (size == 4) {
- vtd_set_long(s, addr, val);
- } else {
- vtd_set_quad(s, addr, val);
- }
- break;
-
- case DMAR_RTADDR_REG_HI:
- VTD_DPRINTF(CSR, "DMAR_RTADDR_REG_HI write addr 0x%"PRIx64
- ", size %d, val 0x%"PRIx64, addr, size, val);
- assert(size == 4);
- vtd_set_long(s, addr, val);
- break;
-
- /* Invalidation Queue Tail Register, 64-bit */
- case DMAR_IQT_REG:
- VTD_DPRINTF(INV, "DMAR_IQT_REG write addr 0x%"PRIx64
- ", size %d, val 0x%"PRIx64, addr, size, val);
- if (size == 4) {
- vtd_set_long(s, addr, val);
- } else {
- vtd_set_quad(s, addr, val);
- }
- vtd_handle_iqt_write(s);
- break;
-
- case DMAR_IQT_REG_HI:
- VTD_DPRINTF(INV, "DMAR_IQT_REG_HI write addr 0x%"PRIx64
- ", size %d, val 0x%"PRIx64, addr, size, val);
- assert(size == 4);
- vtd_set_long(s, addr, val);
- /* 19:63 of IQT_REG is RsvdZ, do nothing here */
- break;
-
- /* Invalidation Queue Address Register, 64-bit */
- case DMAR_IQA_REG:
- VTD_DPRINTF(INV, "DMAR_IQA_REG write addr 0x%"PRIx64
- ", size %d, val 0x%"PRIx64, addr, size, val);
- if (size == 4) {
- vtd_set_long(s, addr, val);
- } else {
- vtd_set_quad(s, addr, val);
- }
- break;
-
- case DMAR_IQA_REG_HI:
- VTD_DPRINTF(INV, "DMAR_IQA_REG_HI write addr 0x%"PRIx64
- ", size %d, val 0x%"PRIx64, addr, size, val);
- assert(size == 4);
- vtd_set_long(s, addr, val);
- break;
-
- /* Invalidation Completion Status Register, 32-bit */
- case DMAR_ICS_REG:
- VTD_DPRINTF(INV, "DMAR_ICS_REG write addr 0x%"PRIx64
- ", size %d, val 0x%"PRIx64, addr, size, val);
- assert(size == 4);
- vtd_set_long(s, addr, val);
- vtd_handle_ics_write(s);
- break;
-
- /* Invalidation Event Control Register, 32-bit */
- case DMAR_IECTL_REG:
- VTD_DPRINTF(INV, "DMAR_IECTL_REG write addr 0x%"PRIx64
- ", size %d, val 0x%"PRIx64, addr, size, val);
- assert(size == 4);
- vtd_set_long(s, addr, val);
- vtd_handle_iectl_write(s);
- break;
-
- /* Invalidation Event Data Register, 32-bit */
- case DMAR_IEDATA_REG:
- VTD_DPRINTF(INV, "DMAR_IEDATA_REG write addr 0x%"PRIx64
- ", size %d, val 0x%"PRIx64, addr, size, val);
- assert(size == 4);
- vtd_set_long(s, addr, val);
- break;
-
- /* Invalidation Event Address Register, 32-bit */
- case DMAR_IEADDR_REG:
- VTD_DPRINTF(INV, "DMAR_IEADDR_REG write addr 0x%"PRIx64
- ", size %d, val 0x%"PRIx64, addr, size, val);
- assert(size == 4);
- vtd_set_long(s, addr, val);
- break;
-
- /* Invalidation Event Upper Address Register, 32-bit */
- case DMAR_IEUADDR_REG:
- VTD_DPRINTF(INV, "DMAR_IEUADDR_REG write addr 0x%"PRIx64
- ", size %d, val 0x%"PRIx64, addr, size, val);
- assert(size == 4);
- vtd_set_long(s, addr, val);
- break;
-
- /* Fault Recording Registers, 128-bit */
- case DMAR_FRCD_REG_0_0:
- VTD_DPRINTF(FLOG, "DMAR_FRCD_REG_0_0 write addr 0x%"PRIx64
- ", size %d, val 0x%"PRIx64, addr, size, val);
- if (size == 4) {
- vtd_set_long(s, addr, val);
- } else {
- vtd_set_quad(s, addr, val);
- }
- break;
-
- case DMAR_FRCD_REG_0_1:
- VTD_DPRINTF(FLOG, "DMAR_FRCD_REG_0_1 write addr 0x%"PRIx64
- ", size %d, val 0x%"PRIx64, addr, size, val);
- assert(size == 4);
- vtd_set_long(s, addr, val);
- break;
-
- case DMAR_FRCD_REG_0_2:
- VTD_DPRINTF(FLOG, "DMAR_FRCD_REG_0_2 write addr 0x%"PRIx64
- ", size %d, val 0x%"PRIx64, addr, size, val);
- if (size == 4) {
- vtd_set_long(s, addr, val);
- } else {
- vtd_set_quad(s, addr, val);
- /* May clear bit 127 (Fault), update PPF */
- vtd_update_fsts_ppf(s);
- }
- break;
-
- case DMAR_FRCD_REG_0_3:
- VTD_DPRINTF(FLOG, "DMAR_FRCD_REG_0_3 write addr 0x%"PRIx64
- ", size %d, val 0x%"PRIx64, addr, size, val);
- assert(size == 4);
- vtd_set_long(s, addr, val);
- /* May clear bit 127 (Fault), update PPF */
- vtd_update_fsts_ppf(s);
- break;
-
- default:
- VTD_DPRINTF(GENERAL, "error: unhandled reg write addr 0x%"PRIx64
- ", size %d, val 0x%"PRIx64, addr, size, val);
- if (size == 4) {
- vtd_set_long(s, addr, val);
- } else {
- vtd_set_quad(s, addr, val);
- }
- }
-}
-
-static IOMMUTLBEntry vtd_iommu_translate(MemoryRegion *iommu, hwaddr addr,
- bool is_write)
-{
- VTDAddressSpace *vtd_as = container_of(iommu, VTDAddressSpace, iommu);
- IntelIOMMUState *s = vtd_as->iommu_state;
- IOMMUTLBEntry ret = {
- .target_as = &address_space_memory,
- .iova = addr,
- .translated_addr = 0,
- .addr_mask = ~(hwaddr)0,
- .perm = IOMMU_NONE,
- };
-
- if (!s->dmar_enabled) {
- /* DMAR disabled, passthrough, use 4k-page*/
- ret.iova = addr & VTD_PAGE_MASK_4K;
- ret.translated_addr = addr & VTD_PAGE_MASK_4K;
- ret.addr_mask = ~VTD_PAGE_MASK_4K;
- ret.perm = IOMMU_RW;
- return ret;
- }
-
- vtd_do_iommu_translate(vtd_as, vtd_as->bus, vtd_as->devfn, addr,
- is_write, &ret);
- VTD_DPRINTF(MMU,
- "bus %"PRIu8 " slot %"PRIu8 " func %"PRIu8 " devfn %"PRIu8
- " gpa 0x%"PRIx64 " hpa 0x%"PRIx64, pci_bus_num(vtd_as->bus),
- VTD_PCI_SLOT(vtd_as->devfn), VTD_PCI_FUNC(vtd_as->devfn),
- vtd_as->devfn, addr, ret.translated_addr);
- return ret;
-}
-
-static const VMStateDescription vtd_vmstate = {
- .name = "iommu-intel",
- .unmigratable = 1,
-};
-
-static const MemoryRegionOps vtd_mem_ops = {
- .read = vtd_mem_read,
- .write = vtd_mem_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .impl = {
- .min_access_size = 4,
- .max_access_size = 8,
- },
- .valid = {
- .min_access_size = 4,
- .max_access_size = 8,
- },
-};
-
-static Property vtd_properties[] = {
- DEFINE_PROP_UINT32("version", IntelIOMMUState, version, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-
-VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn)
-{
- uintptr_t key = (uintptr_t)bus;
- VTDBus *vtd_bus = g_hash_table_lookup(s->vtd_as_by_busptr, &key);
- VTDAddressSpace *vtd_dev_as;
-
- if (!vtd_bus) {
- /* No corresponding free() */
- vtd_bus = g_malloc0(sizeof(VTDBus) + sizeof(VTDAddressSpace *) * VTD_PCI_DEVFN_MAX);
- vtd_bus->bus = bus;
- key = (uintptr_t)bus;
- g_hash_table_insert(s->vtd_as_by_busptr, &key, vtd_bus);
- }
-
- vtd_dev_as = vtd_bus->dev_as[devfn];
-
- if (!vtd_dev_as) {
- vtd_bus->dev_as[devfn] = vtd_dev_as = g_malloc0(sizeof(VTDAddressSpace));
-
- vtd_dev_as->bus = bus;
- vtd_dev_as->devfn = (uint8_t)devfn;
- vtd_dev_as->iommu_state = s;
- vtd_dev_as->context_cache_entry.context_cache_gen = 0;
- memory_region_init_iommu(&vtd_dev_as->iommu, OBJECT(s),
- &s->iommu_ops, "intel_iommu", UINT64_MAX);
- address_space_init(&vtd_dev_as->as,
- &vtd_dev_as->iommu, "intel_iommu");
- }
- return vtd_dev_as;
-}
-
-/* Do the initialization. It will also be called when reset, so pay
- * attention when adding new initialization stuff.
- */
-static void vtd_init(IntelIOMMUState *s)
-{
- memset(s->csr, 0, DMAR_REG_SIZE);
- memset(s->wmask, 0, DMAR_REG_SIZE);
- memset(s->w1cmask, 0, DMAR_REG_SIZE);
- memset(s->womask, 0, DMAR_REG_SIZE);
-
- s->iommu_ops.translate = vtd_iommu_translate;
- s->root = 0;
- s->root_extended = false;
- s->dmar_enabled = false;
- s->iq_head = 0;
- s->iq_tail = 0;
- s->iq = 0;
- s->iq_size = 0;
- s->qi_enabled = false;
- s->iq_last_desc_type = VTD_INV_DESC_NONE;
- s->next_frcd_reg = 0;
- s->cap = VTD_CAP_FRO | VTD_CAP_NFR | VTD_CAP_ND | VTD_CAP_MGAW |
- VTD_CAP_SAGAW | VTD_CAP_MAMV | VTD_CAP_PSI | VTD_CAP_SLLPS;
- s->ecap = VTD_ECAP_QI | VTD_ECAP_IRO;
-
- vtd_reset_context_cache(s);
- vtd_reset_iotlb(s);
-
- /* Define registers with default values and bit semantics */
- vtd_define_long(s, DMAR_VER_REG, 0x10UL, 0, 0);
- vtd_define_quad(s, DMAR_CAP_REG, s->cap, 0, 0);
- vtd_define_quad(s, DMAR_ECAP_REG, s->ecap, 0, 0);
- vtd_define_long(s, DMAR_GCMD_REG, 0, 0xff800000UL, 0);
- vtd_define_long_wo(s, DMAR_GCMD_REG, 0xff800000UL);
- vtd_define_long(s, DMAR_GSTS_REG, 0, 0, 0);
- vtd_define_quad(s, DMAR_RTADDR_REG, 0, 0xfffffffffffff000ULL, 0);
- vtd_define_quad(s, DMAR_CCMD_REG, 0, 0xe0000003ffffffffULL, 0);
- vtd_define_quad_wo(s, DMAR_CCMD_REG, 0x3ffff0000ULL);
-
- /* Advanced Fault Logging not supported */
- vtd_define_long(s, DMAR_FSTS_REG, 0, 0, 0x11UL);
- vtd_define_long(s, DMAR_FECTL_REG, 0x80000000UL, 0x80000000UL, 0);
- vtd_define_long(s, DMAR_FEDATA_REG, 0, 0x0000ffffUL, 0);
- vtd_define_long(s, DMAR_FEADDR_REG, 0, 0xfffffffcUL, 0);
-
- /* Treated as RsvdZ when EIM in ECAP_REG is not supported
- * vtd_define_long(s, DMAR_FEUADDR_REG, 0, 0xffffffffUL, 0);
- */
- vtd_define_long(s, DMAR_FEUADDR_REG, 0, 0, 0);
-
- /* Treated as RO for implementations that PLMR and PHMR fields reported
- * as Clear in the CAP_REG.
- * vtd_define_long(s, DMAR_PMEN_REG, 0, 0x80000000UL, 0);
- */
- vtd_define_long(s, DMAR_PMEN_REG, 0, 0, 0);
-
- vtd_define_quad(s, DMAR_IQH_REG, 0, 0, 0);
- vtd_define_quad(s, DMAR_IQT_REG, 0, 0x7fff0ULL, 0);
- vtd_define_quad(s, DMAR_IQA_REG, 0, 0xfffffffffffff007ULL, 0);
- vtd_define_long(s, DMAR_ICS_REG, 0, 0, 0x1UL);
- vtd_define_long(s, DMAR_IECTL_REG, 0x80000000UL, 0x80000000UL, 0);
- vtd_define_long(s, DMAR_IEDATA_REG, 0, 0xffffffffUL, 0);
- vtd_define_long(s, DMAR_IEADDR_REG, 0, 0xfffffffcUL, 0);
- /* Treadted as RsvdZ when EIM in ECAP_REG is not supported */
- vtd_define_long(s, DMAR_IEUADDR_REG, 0, 0, 0);
-
- /* IOTLB registers */
- vtd_define_quad(s, DMAR_IOTLB_REG, 0, 0Xb003ffff00000000ULL, 0);
- vtd_define_quad(s, DMAR_IVA_REG, 0, 0xfffffffffffff07fULL, 0);
- vtd_define_quad_wo(s, DMAR_IVA_REG, 0xfffffffffffff07fULL);
-
- /* Fault Recording Registers, 128-bit */
- vtd_define_quad(s, DMAR_FRCD_REG_0_0, 0, 0, 0);
- vtd_define_quad(s, DMAR_FRCD_REG_0_2, 0, 0, 0x8000000000000000ULL);
-}
-
-/* Should not reset address_spaces when reset because devices will still use
- * the address space they got at first (won't ask the bus again).
- */
-static void vtd_reset(DeviceState *dev)
-{
- IntelIOMMUState *s = INTEL_IOMMU_DEVICE(dev);
-
- VTD_DPRINTF(GENERAL, "");
- vtd_init(s);
-}
-
-static void vtd_realize(DeviceState *dev, Error **errp)
-{
- IntelIOMMUState *s = INTEL_IOMMU_DEVICE(dev);
-
- VTD_DPRINTF(GENERAL, "");
- memset(s->vtd_as_by_bus_num, 0, sizeof(s->vtd_as_by_bus_num));
- memory_region_init_io(&s->csrmem, OBJECT(s), &vtd_mem_ops, s,
- "intel_iommu", DMAR_REG_SIZE);
- sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->csrmem);
- /* No corresponding destroy */
- s->iotlb = g_hash_table_new_full(vtd_uint64_hash, vtd_uint64_equal,
- g_free, g_free);
- s->vtd_as_by_busptr = g_hash_table_new_full(vtd_uint64_hash, vtd_uint64_equal,
- g_free, g_free);
- vtd_init(s);
-}
-
-static void vtd_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->reset = vtd_reset;
- dc->realize = vtd_realize;
- dc->vmsd = &vtd_vmstate;
- dc->props = vtd_properties;
-}
-
-static const TypeInfo vtd_info = {
- .name = TYPE_INTEL_IOMMU_DEVICE,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(IntelIOMMUState),
- .class_init = vtd_class_init,
-};
-
-static void vtd_register_types(void)
-{
- VTD_DPRINTF(GENERAL, "");
- type_register_static(&vtd_info);
-}
-
-type_init(vtd_register_types)
diff --git a/qemu/hw/i386/intel_iommu_internal.h b/qemu/hw/i386/intel_iommu_internal.h
deleted file mode 100644
index e5f514c6e..000000000
--- a/qemu/hw/i386/intel_iommu_internal.h
+++ /dev/null
@@ -1,391 +0,0 @@
-/*
- * QEMU emulation of an Intel IOMMU (VT-d)
- * (DMA Remapping device)
- *
- * Copyright (C) 2013 Knut Omang, Oracle <knut.omang@oracle.com>
- * Copyright (C) 2014 Le Tan, <tamlokveer@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- * Lots of defines copied from kernel/include/linux/intel-iommu.h:
- * Copyright (C) 2006-2008 Intel Corporation
- * Author: Ashok Raj <ashok.raj@intel.com>
- * Author: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
- *
- */
-
-#ifndef HW_I386_INTEL_IOMMU_INTERNAL_H
-#define HW_I386_INTEL_IOMMU_INTERNAL_H
-#include "hw/i386/intel_iommu.h"
-
-/*
- * Intel IOMMU register specification
- */
-#define DMAR_VER_REG 0x0 /* Arch version supported by this IOMMU */
-#define DMAR_CAP_REG 0x8 /* Hardware supported capabilities */
-#define DMAR_CAP_REG_HI 0xc /* High 32-bit of DMAR_CAP_REG */
-#define DMAR_ECAP_REG 0x10 /* Extended capabilities supported */
-#define DMAR_ECAP_REG_HI 0X14
-#define DMAR_GCMD_REG 0x18 /* Global command */
-#define DMAR_GSTS_REG 0x1c /* Global status */
-#define DMAR_RTADDR_REG 0x20 /* Root entry table */
-#define DMAR_RTADDR_REG_HI 0X24
-#define DMAR_CCMD_REG 0x28 /* Context command */
-#define DMAR_CCMD_REG_HI 0x2c
-#define DMAR_FSTS_REG 0x34 /* Fault status */
-#define DMAR_FECTL_REG 0x38 /* Fault control */
-#define DMAR_FEDATA_REG 0x3c /* Fault event interrupt data */
-#define DMAR_FEADDR_REG 0x40 /* Fault event interrupt addr */
-#define DMAR_FEUADDR_REG 0x44 /* Upper address */
-#define DMAR_AFLOG_REG 0x58 /* Advanced fault control */
-#define DMAR_AFLOG_REG_HI 0X5c
-#define DMAR_PMEN_REG 0x64 /* Enable protected memory region */
-#define DMAR_PLMBASE_REG 0x68 /* PMRR low addr */
-#define DMAR_PLMLIMIT_REG 0x6c /* PMRR low limit */
-#define DMAR_PHMBASE_REG 0x70 /* PMRR high base addr */
-#define DMAR_PHMBASE_REG_HI 0X74
-#define DMAR_PHMLIMIT_REG 0x78 /* PMRR high limit */
-#define DMAR_PHMLIMIT_REG_HI 0x7c
-#define DMAR_IQH_REG 0x80 /* Invalidation queue head */
-#define DMAR_IQH_REG_HI 0X84
-#define DMAR_IQT_REG 0x88 /* Invalidation queue tail */
-#define DMAR_IQT_REG_HI 0X8c
-#define DMAR_IQA_REG 0x90 /* Invalidation queue addr */
-#define DMAR_IQA_REG_HI 0x94
-#define DMAR_ICS_REG 0x9c /* Invalidation complete status */
-#define DMAR_IRTA_REG 0xb8 /* Interrupt remapping table addr */
-#define DMAR_IRTA_REG_HI 0xbc
-#define DMAR_IECTL_REG 0xa0 /* Invalidation event control */
-#define DMAR_IEDATA_REG 0xa4 /* Invalidation event data */
-#define DMAR_IEADDR_REG 0xa8 /* Invalidation event address */
-#define DMAR_IEUADDR_REG 0xac /* Invalidation event address */
-#define DMAR_PQH_REG 0xc0 /* Page request queue head */
-#define DMAR_PQH_REG_HI 0xc4
-#define DMAR_PQT_REG 0xc8 /* Page request queue tail*/
-#define DMAR_PQT_REG_HI 0xcc
-#define DMAR_PQA_REG 0xd0 /* Page request queue address */
-#define DMAR_PQA_REG_HI 0xd4
-#define DMAR_PRS_REG 0xdc /* Page request status */
-#define DMAR_PECTL_REG 0xe0 /* Page request event control */
-#define DMAR_PEDATA_REG 0xe4 /* Page request event data */
-#define DMAR_PEADDR_REG 0xe8 /* Page request event address */
-#define DMAR_PEUADDR_REG 0xec /* Page event upper address */
-#define DMAR_MTRRCAP_REG 0x100 /* MTRR capability */
-#define DMAR_MTRRCAP_REG_HI 0x104
-#define DMAR_MTRRDEF_REG 0x108 /* MTRR default type */
-#define DMAR_MTRRDEF_REG_HI 0x10c
-
-/* IOTLB registers */
-#define DMAR_IOTLB_REG_OFFSET 0xf0 /* Offset to the IOTLB registers */
-#define DMAR_IVA_REG DMAR_IOTLB_REG_OFFSET /* Invalidate address */
-#define DMAR_IVA_REG_HI (DMAR_IVA_REG + 4)
-/* IOTLB invalidate register */
-#define DMAR_IOTLB_REG (DMAR_IOTLB_REG_OFFSET + 0x8)
-#define DMAR_IOTLB_REG_HI (DMAR_IOTLB_REG + 4)
-
-/* FRCD */
-#define DMAR_FRCD_REG_OFFSET 0x220 /* Offset to the fault recording regs */
-/* NOTICE: If you change the DMAR_FRCD_REG_NR, please remember to change the
- * DMAR_REG_SIZE in include/hw/i386/intel_iommu.h.
- * #define DMAR_REG_SIZE (DMAR_FRCD_REG_OFFSET + 16 * DMAR_FRCD_REG_NR)
- */
-#define DMAR_FRCD_REG_NR 1ULL /* Num of fault recording regs */
-
-#define DMAR_FRCD_REG_0_0 0x220 /* The 0th fault recording regs */
-#define DMAR_FRCD_REG_0_1 0x224
-#define DMAR_FRCD_REG_0_2 0x228
-#define DMAR_FRCD_REG_0_3 0x22c
-
-/* Interrupt Address Range */
-#define VTD_INTERRUPT_ADDR_FIRST 0xfee00000ULL
-#define VTD_INTERRUPT_ADDR_LAST 0xfeefffffULL
-
-/* The shift of source_id in the key of IOTLB hash table */
-#define VTD_IOTLB_SID_SHIFT 36
-#define VTD_IOTLB_LVL_SHIFT 44
-#define VTD_IOTLB_MAX_SIZE 1024 /* Max size of the hash table */
-
-/* IOTLB_REG */
-#define VTD_TLB_GLOBAL_FLUSH (1ULL << 60) /* Global invalidation */
-#define VTD_TLB_DSI_FLUSH (2ULL << 60) /* Domain-selective */
-#define VTD_TLB_PSI_FLUSH (3ULL << 60) /* Page-selective */
-#define VTD_TLB_FLUSH_GRANU_MASK (3ULL << 60)
-#define VTD_TLB_GLOBAL_FLUSH_A (1ULL << 57)
-#define VTD_TLB_DSI_FLUSH_A (2ULL << 57)
-#define VTD_TLB_PSI_FLUSH_A (3ULL << 57)
-#define VTD_TLB_FLUSH_GRANU_MASK_A (3ULL << 57)
-#define VTD_TLB_IVT (1ULL << 63)
-#define VTD_TLB_DID(val) (((val) >> 32) & VTD_DOMAIN_ID_MASK)
-
-/* IVA_REG */
-#define VTD_IVA_ADDR(val) ((val) & ~0xfffULL & ((1ULL << VTD_MGAW) - 1))
-#define VTD_IVA_AM(val) ((val) & 0x3fULL)
-
-/* GCMD_REG */
-#define VTD_GCMD_TE (1UL << 31)
-#define VTD_GCMD_SRTP (1UL << 30)
-#define VTD_GCMD_SFL (1UL << 29)
-#define VTD_GCMD_EAFL (1UL << 28)
-#define VTD_GCMD_WBF (1UL << 27)
-#define VTD_GCMD_QIE (1UL << 26)
-#define VTD_GCMD_IRE (1UL << 25)
-#define VTD_GCMD_SIRTP (1UL << 24)
-#define VTD_GCMD_CFI (1UL << 23)
-
-/* GSTS_REG */
-#define VTD_GSTS_TES (1UL << 31)
-#define VTD_GSTS_RTPS (1UL << 30)
-#define VTD_GSTS_FLS (1UL << 29)
-#define VTD_GSTS_AFLS (1UL << 28)
-#define VTD_GSTS_WBFS (1UL << 27)
-#define VTD_GSTS_QIES (1UL << 26)
-#define VTD_GSTS_IRES (1UL << 25)
-#define VTD_GSTS_IRTPS (1UL << 24)
-#define VTD_GSTS_CFIS (1UL << 23)
-
-/* CCMD_REG */
-#define VTD_CCMD_ICC (1ULL << 63)
-#define VTD_CCMD_GLOBAL_INVL (1ULL << 61)
-#define VTD_CCMD_DOMAIN_INVL (2ULL << 61)
-#define VTD_CCMD_DEVICE_INVL (3ULL << 61)
-#define VTD_CCMD_CIRG_MASK (3ULL << 61)
-#define VTD_CCMD_GLOBAL_INVL_A (1ULL << 59)
-#define VTD_CCMD_DOMAIN_INVL_A (2ULL << 59)
-#define VTD_CCMD_DEVICE_INVL_A (3ULL << 59)
-#define VTD_CCMD_CAIG_MASK (3ULL << 59)
-#define VTD_CCMD_DID(val) ((val) & VTD_DOMAIN_ID_MASK)
-#define VTD_CCMD_SID(val) (((val) >> 16) & 0xffffULL)
-#define VTD_CCMD_FM(val) (((val) >> 32) & 3ULL)
-
-/* RTADDR_REG */
-#define VTD_RTADDR_RTT (1ULL << 11)
-#define VTD_RTADDR_ADDR_MASK (VTD_HAW_MASK ^ 0xfffULL)
-
-/* ECAP_REG */
-/* (offset >> 4) << 8 */
-#define VTD_ECAP_IRO (DMAR_IOTLB_REG_OFFSET << 4)
-#define VTD_ECAP_QI (1ULL << 1)
-
-/* CAP_REG */
-/* (offset >> 4) << 24 */
-#define VTD_CAP_FRO (DMAR_FRCD_REG_OFFSET << 20)
-#define VTD_CAP_NFR ((DMAR_FRCD_REG_NR - 1) << 40)
-#define VTD_DOMAIN_ID_SHIFT 16 /* 16-bit domain id for 64K domains */
-#define VTD_DOMAIN_ID_MASK ((1UL << VTD_DOMAIN_ID_SHIFT) - 1)
-#define VTD_CAP_ND (((VTD_DOMAIN_ID_SHIFT - 4) / 2) & 7ULL)
-#define VTD_MGAW 39 /* Maximum Guest Address Width */
-#define VTD_CAP_MGAW (((VTD_MGAW - 1) & 0x3fULL) << 16)
-#define VTD_MAMV 18ULL
-#define VTD_CAP_MAMV (VTD_MAMV << 48)
-#define VTD_CAP_PSI (1ULL << 39)
-#define VTD_CAP_SLLPS ((1ULL << 34) | (1ULL << 35))
-
-/* Supported Adjusted Guest Address Widths */
-#define VTD_CAP_SAGAW_SHIFT 8
-#define VTD_CAP_SAGAW_MASK (0x1fULL << VTD_CAP_SAGAW_SHIFT)
- /* 39-bit AGAW, 3-level page-table */
-#define VTD_CAP_SAGAW_39bit (0x2ULL << VTD_CAP_SAGAW_SHIFT)
- /* 48-bit AGAW, 4-level page-table */
-#define VTD_CAP_SAGAW_48bit (0x4ULL << VTD_CAP_SAGAW_SHIFT)
-#define VTD_CAP_SAGAW VTD_CAP_SAGAW_39bit
-
-/* IQT_REG */
-#define VTD_IQT_QT(val) (((val) >> 4) & 0x7fffULL)
-
-/* IQA_REG */
-#define VTD_IQA_IQA_MASK (VTD_HAW_MASK ^ 0xfffULL)
-#define VTD_IQA_QS 0x7ULL
-
-/* IQH_REG */
-#define VTD_IQH_QH_SHIFT 4
-#define VTD_IQH_QH_MASK 0x7fff0ULL
-
-/* ICS_REG */
-#define VTD_ICS_IWC 1UL
-
-/* IECTL_REG */
-#define VTD_IECTL_IM (1UL << 31)
-#define VTD_IECTL_IP (1UL << 30)
-
-/* FSTS_REG */
-#define VTD_FSTS_FRI_MASK 0xff00UL
-#define VTD_FSTS_FRI(val) ((((uint32_t)(val)) << 8) & VTD_FSTS_FRI_MASK)
-#define VTD_FSTS_IQE (1UL << 4)
-#define VTD_FSTS_PPF (1UL << 1)
-#define VTD_FSTS_PFO 1UL
-
-/* FECTL_REG */
-#define VTD_FECTL_IM (1UL << 31)
-#define VTD_FECTL_IP (1UL << 30)
-
-/* Fault Recording Register */
-/* For the high 64-bit of 128-bit */
-#define VTD_FRCD_F (1ULL << 63)
-#define VTD_FRCD_T (1ULL << 62)
-#define VTD_FRCD_FR(val) (((val) & 0xffULL) << 32)
-#define VTD_FRCD_SID_MASK 0xffffULL
-#define VTD_FRCD_SID(val) ((val) & VTD_FRCD_SID_MASK)
-/* For the low 64-bit of 128-bit */
-#define VTD_FRCD_FI(val) ((val) & (((1ULL << VTD_MGAW) - 1) ^ 0xfffULL))
-
-/* DMA Remapping Fault Conditions */
-typedef enum VTDFaultReason {
- VTD_FR_RESERVED = 0, /* Reserved for Advanced Fault logging */
- VTD_FR_ROOT_ENTRY_P = 1, /* The Present(P) field of root-entry is 0 */
- VTD_FR_CONTEXT_ENTRY_P, /* The Present(P) field of context-entry is 0 */
- VTD_FR_CONTEXT_ENTRY_INV, /* Invalid programming of a context-entry */
- VTD_FR_ADDR_BEYOND_MGAW, /* Input-address above (2^x-1) */
- VTD_FR_WRITE, /* No write permission */
- VTD_FR_READ, /* No read permission */
- /* Fail to access a second-level paging entry (not SL_PML4E) */
- VTD_FR_PAGING_ENTRY_INV,
- VTD_FR_ROOT_TABLE_INV, /* Fail to access a root-entry */
- VTD_FR_CONTEXT_TABLE_INV, /* Fail to access a context-entry */
- /* Non-zero reserved field in a present root-entry */
- VTD_FR_ROOT_ENTRY_RSVD,
- /* Non-zero reserved field in a present context-entry */
- VTD_FR_CONTEXT_ENTRY_RSVD,
- /* Non-zero reserved field in a second-level paging entry with at lease one
- * Read(R) and Write(W) or Execute(E) field is Set.
- */
- VTD_FR_PAGING_ENTRY_RSVD,
- /* Translation request or translated request explicitly blocked dut to the
- * programming of the Translation Type (T) field in the present
- * context-entry.
- */
- VTD_FR_CONTEXT_ENTRY_TT,
- /* This is not a normal fault reason. We use this to indicate some faults
- * that are not referenced by the VT-d specification.
- * Fault event with such reason should not be recorded.
- */
- VTD_FR_RESERVED_ERR,
- VTD_FR_MAX, /* Guard */
-} VTDFaultReason;
-
-#define VTD_CONTEXT_CACHE_GEN_MAX 0xffffffffUL
-
-/* Queued Invalidation Descriptor */
-struct VTDInvDesc {
- uint64_t lo;
- uint64_t hi;
-};
-typedef struct VTDInvDesc VTDInvDesc;
-
-/* Masks for struct VTDInvDesc */
-#define VTD_INV_DESC_TYPE 0xf
-#define VTD_INV_DESC_CC 0x1 /* Context-cache Invalidate Desc */
-#define VTD_INV_DESC_IOTLB 0x2
-#define VTD_INV_DESC_WAIT 0x5 /* Invalidation Wait Descriptor */
-#define VTD_INV_DESC_NONE 0 /* Not an Invalidate Descriptor */
-
-/* Masks for Invalidation Wait Descriptor*/
-#define VTD_INV_DESC_WAIT_SW (1ULL << 5)
-#define VTD_INV_DESC_WAIT_IF (1ULL << 4)
-#define VTD_INV_DESC_WAIT_FN (1ULL << 6)
-#define VTD_INV_DESC_WAIT_DATA_SHIFT 32
-#define VTD_INV_DESC_WAIT_RSVD_LO 0Xffffff80ULL
-#define VTD_INV_DESC_WAIT_RSVD_HI 3ULL
-
-/* Masks for Context-cache Invalidation Descriptor */
-#define VTD_INV_DESC_CC_G (3ULL << 4)
-#define VTD_INV_DESC_CC_GLOBAL (1ULL << 4)
-#define VTD_INV_DESC_CC_DOMAIN (2ULL << 4)
-#define VTD_INV_DESC_CC_DEVICE (3ULL << 4)
-#define VTD_INV_DESC_CC_DID(val) (((val) >> 16) & VTD_DOMAIN_ID_MASK)
-#define VTD_INV_DESC_CC_SID(val) (((val) >> 32) & 0xffffUL)
-#define VTD_INV_DESC_CC_FM(val) (((val) >> 48) & 3UL)
-#define VTD_INV_DESC_CC_RSVD 0xfffc00000000ffc0ULL
-
-/* Masks for IOTLB Invalidate Descriptor */
-#define VTD_INV_DESC_IOTLB_G (3ULL << 4)
-#define VTD_INV_DESC_IOTLB_GLOBAL (1ULL << 4)
-#define VTD_INV_DESC_IOTLB_DOMAIN (2ULL << 4)
-#define VTD_INV_DESC_IOTLB_PAGE (3ULL << 4)
-#define VTD_INV_DESC_IOTLB_DID(val) (((val) >> 16) & VTD_DOMAIN_ID_MASK)
-#define VTD_INV_DESC_IOTLB_ADDR(val) ((val) & ~0xfffULL & \
- ((1ULL << VTD_MGAW) - 1))
-#define VTD_INV_DESC_IOTLB_AM(val) ((val) & 0x3fULL)
-#define VTD_INV_DESC_IOTLB_RSVD_LO 0xffffffff0000ff00ULL
-#define VTD_INV_DESC_IOTLB_RSVD_HI 0xf80ULL
-
-/* Information about page-selective IOTLB invalidate */
-struct VTDIOTLBPageInvInfo {
- uint16_t domain_id;
- uint64_t addr;
- uint8_t mask;
-};
-typedef struct VTDIOTLBPageInvInfo VTDIOTLBPageInvInfo;
-
-/* Pagesize of VTD paging structures, including root and context tables */
-#define VTD_PAGE_SHIFT 12
-#define VTD_PAGE_SIZE (1ULL << VTD_PAGE_SHIFT)
-
-#define VTD_PAGE_SHIFT_4K 12
-#define VTD_PAGE_MASK_4K (~((1ULL << VTD_PAGE_SHIFT_4K) - 1))
-#define VTD_PAGE_SHIFT_2M 21
-#define VTD_PAGE_MASK_2M (~((1ULL << VTD_PAGE_SHIFT_2M) - 1))
-#define VTD_PAGE_SHIFT_1G 30
-#define VTD_PAGE_MASK_1G (~((1ULL << VTD_PAGE_SHIFT_1G) - 1))
-
-struct VTDRootEntry {
- uint64_t val;
- uint64_t rsvd;
-};
-typedef struct VTDRootEntry VTDRootEntry;
-
-/* Masks for struct VTDRootEntry */
-#define VTD_ROOT_ENTRY_P 1ULL
-#define VTD_ROOT_ENTRY_CTP (~0xfffULL)
-
-#define VTD_ROOT_ENTRY_NR (VTD_PAGE_SIZE / sizeof(VTDRootEntry))
-#define VTD_ROOT_ENTRY_RSVD (0xffeULL | ~VTD_HAW_MASK)
-
-/* Masks for struct VTDContextEntry */
-/* lo */
-#define VTD_CONTEXT_ENTRY_P (1ULL << 0)
-#define VTD_CONTEXT_ENTRY_FPD (1ULL << 1) /* Fault Processing Disable */
-#define VTD_CONTEXT_ENTRY_TT (3ULL << 2) /* Translation Type */
-#define VTD_CONTEXT_TT_MULTI_LEVEL 0
-#define VTD_CONTEXT_TT_DEV_IOTLB 1
-#define VTD_CONTEXT_TT_PASS_THROUGH 2
-/* Second Level Page Translation Pointer*/
-#define VTD_CONTEXT_ENTRY_SLPTPTR (~0xfffULL)
-#define VTD_CONTEXT_ENTRY_RSVD_LO (0xff0ULL | ~VTD_HAW_MASK)
-/* hi */
-#define VTD_CONTEXT_ENTRY_AW 7ULL /* Adjusted guest-address-width */
-#define VTD_CONTEXT_ENTRY_DID(val) (((val) >> 8) & VTD_DOMAIN_ID_MASK)
-#define VTD_CONTEXT_ENTRY_RSVD_HI 0xffffffffff000080ULL
-
-#define VTD_CONTEXT_ENTRY_NR (VTD_PAGE_SIZE / sizeof(VTDContextEntry))
-
-/* Paging Structure common */
-#define VTD_SL_PT_PAGE_SIZE_MASK (1ULL << 7)
-/* Bits to decide the offset for each level */
-#define VTD_SL_LEVEL_BITS 9
-
-/* Second Level Paging Structure */
-#define VTD_SL_PML4_LEVEL 4
-#define VTD_SL_PDP_LEVEL 3
-#define VTD_SL_PD_LEVEL 2
-#define VTD_SL_PT_LEVEL 1
-#define VTD_SL_PT_ENTRY_NR 512
-
-/* Masks for Second Level Paging Entry */
-#define VTD_SL_RW_MASK 3ULL
-#define VTD_SL_R 1ULL
-#define VTD_SL_W (1ULL << 1)
-#define VTD_SL_PT_BASE_ADDR_MASK (~(VTD_PAGE_SIZE - 1) & VTD_HAW_MASK)
-#define VTD_SL_IGN_COM 0xbff0000000000000ULL
-
-#endif
diff --git a/qemu/hw/i386/kvm/Makefile.objs b/qemu/hw/i386/kvm/Makefile.objs
deleted file mode 100644
index d8bce209b..000000000
--- a/qemu/hw/i386/kvm/Makefile.objs
+++ /dev/null
@@ -1 +0,0 @@
-obj-y += clock.o apic.o i8259.o ioapic.o i8254.o pci-assign.o
diff --git a/qemu/hw/i386/kvm/apic.c b/qemu/hw/i386/kvm/apic.c
deleted file mode 100644
index 3c7c8fa00..000000000
--- a/qemu/hw/i386/kvm/apic.c
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * KVM in-kernel APIC support
- *
- * Copyright (c) 2011 Siemens AG
- *
- * Authors:
- * Jan Kiszka <jan.kiszka@siemens.com>
- *
- * This work is licensed under the terms of the GNU GPL version 2.
- * See the COPYING file in the top-level directory.
- */
-#include "qemu/osdep.h"
-#include "hw/i386/apic_internal.h"
-#include "hw/pci/msi.h"
-#include "sysemu/kvm.h"
-
-static inline void kvm_apic_set_reg(struct kvm_lapic_state *kapic,
- int reg_id, uint32_t val)
-{
- *((uint32_t *)(kapic->regs + (reg_id << 4))) = val;
-}
-
-static inline uint32_t kvm_apic_get_reg(struct kvm_lapic_state *kapic,
- int reg_id)
-{
- return *((uint32_t *)(kapic->regs + (reg_id << 4)));
-}
-
-void kvm_put_apic_state(DeviceState *dev, struct kvm_lapic_state *kapic)
-{
- APICCommonState *s = APIC_COMMON(dev);
- int i;
-
- memset(kapic, 0, sizeof(*kapic));
- kvm_apic_set_reg(kapic, 0x2, s->id << 24);
- kvm_apic_set_reg(kapic, 0x8, s->tpr);
- kvm_apic_set_reg(kapic, 0xd, s->log_dest << 24);
- kvm_apic_set_reg(kapic, 0xe, s->dest_mode << 28 | 0x0fffffff);
- kvm_apic_set_reg(kapic, 0xf, s->spurious_vec);
- for (i = 0; i < 8; i++) {
- kvm_apic_set_reg(kapic, 0x10 + i, s->isr[i]);
- kvm_apic_set_reg(kapic, 0x18 + i, s->tmr[i]);
- kvm_apic_set_reg(kapic, 0x20 + i, s->irr[i]);
- }
- kvm_apic_set_reg(kapic, 0x28, s->esr);
- kvm_apic_set_reg(kapic, 0x30, s->icr[0]);
- kvm_apic_set_reg(kapic, 0x31, s->icr[1]);
- for (i = 0; i < APIC_LVT_NB; i++) {
- kvm_apic_set_reg(kapic, 0x32 + i, s->lvt[i]);
- }
- kvm_apic_set_reg(kapic, 0x38, s->initial_count);
- kvm_apic_set_reg(kapic, 0x3e, s->divide_conf);
-}
-
-void kvm_get_apic_state(DeviceState *dev, struct kvm_lapic_state *kapic)
-{
- APICCommonState *s = APIC_COMMON(dev);
- int i, v;
-
- s->id = kvm_apic_get_reg(kapic, 0x2) >> 24;
- s->tpr = kvm_apic_get_reg(kapic, 0x8);
- s->arb_id = kvm_apic_get_reg(kapic, 0x9);
- s->log_dest = kvm_apic_get_reg(kapic, 0xd) >> 24;
- s->dest_mode = kvm_apic_get_reg(kapic, 0xe) >> 28;
- s->spurious_vec = kvm_apic_get_reg(kapic, 0xf);
- for (i = 0; i < 8; i++) {
- s->isr[i] = kvm_apic_get_reg(kapic, 0x10 + i);
- s->tmr[i] = kvm_apic_get_reg(kapic, 0x18 + i);
- s->irr[i] = kvm_apic_get_reg(kapic, 0x20 + i);
- }
- s->esr = kvm_apic_get_reg(kapic, 0x28);
- s->icr[0] = kvm_apic_get_reg(kapic, 0x30);
- s->icr[1] = kvm_apic_get_reg(kapic, 0x31);
- for (i = 0; i < APIC_LVT_NB; i++) {
- s->lvt[i] = kvm_apic_get_reg(kapic, 0x32 + i);
- }
- s->initial_count = kvm_apic_get_reg(kapic, 0x38);
- s->divide_conf = kvm_apic_get_reg(kapic, 0x3e);
-
- v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4);
- s->count_shift = (v + 1) & 7;
-
- s->initial_count_load_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- apic_next_timer(s, s->initial_count_load_time);
-}
-
-static void kvm_apic_set_base(APICCommonState *s, uint64_t val)
-{
- s->apicbase = val;
-}
-
-static void kvm_apic_set_tpr(APICCommonState *s, uint8_t val)
-{
- s->tpr = (val & 0x0f) << 4;
-}
-
-static uint8_t kvm_apic_get_tpr(APICCommonState *s)
-{
- return s->tpr >> 4;
-}
-
-static void kvm_apic_enable_tpr_reporting(APICCommonState *s, bool enable)
-{
- struct kvm_tpr_access_ctl ctl = {
- .enabled = enable
- };
-
- kvm_vcpu_ioctl(CPU(s->cpu), KVM_TPR_ACCESS_REPORTING, &ctl);
-}
-
-static void kvm_apic_vapic_base_update(APICCommonState *s)
-{
- struct kvm_vapic_addr vapid_addr = {
- .vapic_addr = s->vapic_paddr,
- };
- int ret;
-
- ret = kvm_vcpu_ioctl(CPU(s->cpu), KVM_SET_VAPIC_ADDR, &vapid_addr);
- if (ret < 0) {
- fprintf(stderr, "KVM: setting VAPIC address failed (%s)\n",
- strerror(-ret));
- abort();
- }
-}
-
-static void do_inject_external_nmi(void *data)
-{
- APICCommonState *s = data;
- CPUState *cpu = CPU(s->cpu);
- uint32_t lvt;
- int ret;
-
- cpu_synchronize_state(cpu);
-
- lvt = s->lvt[APIC_LVT_LINT1];
- if (!(lvt & APIC_LVT_MASKED) && ((lvt >> 8) & 7) == APIC_DM_NMI) {
- ret = kvm_vcpu_ioctl(cpu, KVM_NMI);
- if (ret < 0) {
- fprintf(stderr, "KVM: injection failed, NMI lost (%s)\n",
- strerror(-ret));
- }
- }
-}
-
-static void kvm_apic_external_nmi(APICCommonState *s)
-{
- run_on_cpu(CPU(s->cpu), do_inject_external_nmi, s);
-}
-
-static uint64_t kvm_apic_mem_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- return ~(uint64_t)0;
-}
-
-static void kvm_apic_mem_write(void *opaque, hwaddr addr,
- uint64_t data, unsigned size)
-{
- MSIMessage msg = { .address = addr, .data = data };
- int ret;
-
- ret = kvm_irqchip_send_msi(kvm_state, msg);
- if (ret < 0) {
- fprintf(stderr, "KVM: injection failed, MSI lost (%s)\n",
- strerror(-ret));
- }
-}
-
-static const MemoryRegionOps kvm_apic_io_ops = {
- .read = kvm_apic_mem_read,
- .write = kvm_apic_mem_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void kvm_apic_reset(APICCommonState *s)
-{
- /* Not used by KVM, which uses the CPU mp_state instead. */
- s->wait_for_sipi = 0;
-}
-
-static void kvm_apic_realize(DeviceState *dev, Error **errp)
-{
- APICCommonState *s = APIC_COMMON(dev);
-
- memory_region_init_io(&s->io_memory, NULL, &kvm_apic_io_ops, s, "kvm-apic-msi",
- APIC_SPACE_SIZE);
-
- if (kvm_has_gsi_routing()) {
- msi_nonbroken = true;
- }
-}
-
-static void kvm_apic_class_init(ObjectClass *klass, void *data)
-{
- APICCommonClass *k = APIC_COMMON_CLASS(klass);
-
- k->realize = kvm_apic_realize;
- k->reset = kvm_apic_reset;
- k->set_base = kvm_apic_set_base;
- k->set_tpr = kvm_apic_set_tpr;
- k->get_tpr = kvm_apic_get_tpr;
- k->enable_tpr_reporting = kvm_apic_enable_tpr_reporting;
- k->vapic_base_update = kvm_apic_vapic_base_update;
- k->external_nmi = kvm_apic_external_nmi;
-}
-
-static const TypeInfo kvm_apic_info = {
- .name = "kvm-apic",
- .parent = TYPE_APIC_COMMON,
- .instance_size = sizeof(APICCommonState),
- .class_init = kvm_apic_class_init,
-};
-
-static void kvm_apic_register_types(void)
-{
- type_register_static(&kvm_apic_info);
-}
-
-type_init(kvm_apic_register_types)
diff --git a/qemu/hw/i386/kvm/clock.c b/qemu/hw/i386/kvm/clock.c
deleted file mode 100644
index a3b300cad..000000000
--- a/qemu/hw/i386/kvm/clock.c
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * QEMU KVM support, paravirtual clock device
- *
- * Copyright (C) 2011 Siemens AG
- *
- * Authors:
- * Jan Kiszka <jan.kiszka@siemens.com>
- *
- * This work is licensed under the terms of the GNU GPL version 2.
- * See the COPYING file in the top-level directory.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "qemu/host-utils.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/kvm.h"
-#include "kvm_i386.h"
-#include "hw/sysbus.h"
-#include "hw/kvm/clock.h"
-
-#include <linux/kvm.h>
-#include <linux/kvm_para.h>
-
-#define TYPE_KVM_CLOCK "kvmclock"
-#define KVM_CLOCK(obj) OBJECT_CHECK(KVMClockState, (obj), TYPE_KVM_CLOCK)
-
-typedef struct KVMClockState {
- /*< private >*/
- SysBusDevice busdev;
- /*< public >*/
-
- uint64_t clock;
- bool clock_valid;
-} KVMClockState;
-
-struct pvclock_vcpu_time_info {
- uint32_t version;
- uint32_t pad0;
- uint64_t tsc_timestamp;
- uint64_t system_time;
- uint32_t tsc_to_system_mul;
- int8_t tsc_shift;
- uint8_t flags;
- uint8_t pad[2];
-} __attribute__((__packed__)); /* 32 bytes */
-
-static uint64_t kvmclock_current_nsec(KVMClockState *s)
-{
- CPUState *cpu = first_cpu;
- CPUX86State *env = cpu->env_ptr;
- hwaddr kvmclock_struct_pa = env->system_time_msr & ~1ULL;
- uint64_t migration_tsc = env->tsc;
- struct pvclock_vcpu_time_info time;
- uint64_t delta;
- uint64_t nsec_lo;
- uint64_t nsec_hi;
- uint64_t nsec;
-
- if (!(env->system_time_msr & 1ULL)) {
- /* KVM clock not active */
- return 0;
- }
-
- cpu_physical_memory_read(kvmclock_struct_pa, &time, sizeof(time));
-
- assert(time.tsc_timestamp <= migration_tsc);
- delta = migration_tsc - time.tsc_timestamp;
- if (time.tsc_shift < 0) {
- delta >>= -time.tsc_shift;
- } else {
- delta <<= time.tsc_shift;
- }
-
- mulu64(&nsec_lo, &nsec_hi, delta, time.tsc_to_system_mul);
- nsec = (nsec_lo >> 32) | (nsec_hi << 32);
- return nsec + time.system_time;
-}
-
-static void kvmclock_vm_state_change(void *opaque, int running,
- RunState state)
-{
- KVMClockState *s = opaque;
- CPUState *cpu;
- int cap_clock_ctrl = kvm_check_extension(kvm_state, KVM_CAP_KVMCLOCK_CTRL);
- int ret;
-
- if (running) {
- struct kvm_clock_data data = {};
- uint64_t time_at_migration = kvmclock_current_nsec(s);
-
- s->clock_valid = false;
-
- /* We can't rely on the migrated clock value, just discard it */
- if (time_at_migration) {
- s->clock = time_at_migration;
- }
-
- data.clock = s->clock;
- ret = kvm_vm_ioctl(kvm_state, KVM_SET_CLOCK, &data);
- if (ret < 0) {
- fprintf(stderr, "KVM_SET_CLOCK failed: %s\n", strerror(ret));
- abort();
- }
-
- if (!cap_clock_ctrl) {
- return;
- }
- CPU_FOREACH(cpu) {
- ret = kvm_vcpu_ioctl(cpu, KVM_KVMCLOCK_CTRL, 0);
- if (ret) {
- if (ret != -EINVAL) {
- fprintf(stderr, "%s: %s\n", __func__, strerror(-ret));
- }
- return;
- }
- }
- } else {
- struct kvm_clock_data data;
- int ret;
-
- if (s->clock_valid) {
- return;
- }
-
- kvm_synchronize_all_tsc();
-
- ret = kvm_vm_ioctl(kvm_state, KVM_GET_CLOCK, &data);
- if (ret < 0) {
- fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret));
- abort();
- }
- s->clock = data.clock;
-
- /*
- * If the VM is stopped, declare the clock state valid to
- * avoid re-reading it on next vmsave (which would return
- * a different value). Will be reset when the VM is continued.
- */
- s->clock_valid = true;
- }
-}
-
-static void kvmclock_realize(DeviceState *dev, Error **errp)
-{
- KVMClockState *s = KVM_CLOCK(dev);
-
- qemu_add_vm_change_state_handler(kvmclock_vm_state_change, s);
-}
-
-static const VMStateDescription kvmclock_vmsd = {
- .name = "kvmclock",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT64(clock, KVMClockState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void kvmclock_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = kvmclock_realize;
- dc->vmsd = &kvmclock_vmsd;
-}
-
-static const TypeInfo kvmclock_info = {
- .name = TYPE_KVM_CLOCK,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(KVMClockState),
- .class_init = kvmclock_class_init,
-};
-
-/* Note: Must be called after VCPU initialization. */
-void kvmclock_create(void)
-{
- X86CPU *cpu = X86_CPU(first_cpu);
-
- if (kvm_enabled() &&
- cpu->env.features[FEAT_KVM] & ((1ULL << KVM_FEATURE_CLOCKSOURCE) |
- (1ULL << KVM_FEATURE_CLOCKSOURCE2))) {
- sysbus_create_simple(TYPE_KVM_CLOCK, -1, NULL);
- }
-}
-
-static void kvmclock_register_types(void)
-{
- type_register_static(&kvmclock_info);
-}
-
-type_init(kvmclock_register_types)
diff --git a/qemu/hw/i386/kvm/i8254.c b/qemu/hw/i386/kvm/i8254.c
deleted file mode 100644
index a4462e5ca..000000000
--- a/qemu/hw/i386/kvm/i8254.c
+++ /dev/null
@@ -1,337 +0,0 @@
-/*
- * KVM in-kernel PIT (i8254) support
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- * Copyright (c) 2012 Jan Kiszka, Siemens AG
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu/timer.h"
-#include "sysemu/sysemu.h"
-#include "hw/timer/i8254.h"
-#include "hw/timer/i8254_internal.h"
-#include "sysemu/kvm.h"
-
-#define KVM_PIT_REINJECT_BIT 0
-
-#define CALIBRATION_ROUNDS 3
-
-#define KVM_PIT(obj) OBJECT_CHECK(KVMPITState, (obj), TYPE_KVM_I8254)
-#define KVM_PIT_CLASS(class) \
- OBJECT_CLASS_CHECK(KVMPITClass, (class), TYPE_KVM_I8254)
-#define KVM_PIT_GET_CLASS(obj) \
- OBJECT_GET_CLASS(KVMPITClass, (obj), TYPE_KVM_I8254)
-
-typedef struct KVMPITState {
- PITCommonState parent_obj;
-
- LostTickPolicy lost_tick_policy;
- bool vm_stopped;
- int64_t kernel_clock_offset;
-} KVMPITState;
-
-typedef struct KVMPITClass {
- PITCommonClass parent_class;
-
- DeviceRealize parent_realize;
-} KVMPITClass;
-
-static int64_t abs64(int64_t v)
-{
- return v < 0 ? -v : v;
-}
-
-static void kvm_pit_update_clock_offset(KVMPITState *s)
-{
- int64_t offset, clock_offset;
- struct timespec ts;
- int i;
-
- /*
- * Measure the delta between CLOCK_MONOTONIC, the base used for
- * kvm_pit_channel_state::count_load_time, and QEMU_CLOCK_VIRTUAL. Take the
- * minimum of several samples to filter out scheduling noise.
- */
- clock_offset = INT64_MAX;
- for (i = 0; i < CALIBRATION_ROUNDS; i++) {
- offset = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- clock_gettime(CLOCK_MONOTONIC, &ts);
- offset -= ts.tv_nsec;
- offset -= (int64_t)ts.tv_sec * 1000000000;
- if (abs64(offset) < abs64(clock_offset)) {
- clock_offset = offset;
- }
- }
- s->kernel_clock_offset = clock_offset;
-}
-
-static void kvm_pit_get(PITCommonState *pit)
-{
- KVMPITState *s = KVM_PIT(pit);
- struct kvm_pit_state2 kpit;
- struct kvm_pit_channel_state *kchan;
- struct PITChannelState *sc;
- int i, ret;
-
- /* No need to re-read the state if VM is stopped. */
- if (s->vm_stopped) {
- return;
- }
-
- if (kvm_has_pit_state2()) {
- ret = kvm_vm_ioctl(kvm_state, KVM_GET_PIT2, &kpit);
- if (ret < 0) {
- fprintf(stderr, "KVM_GET_PIT2 failed: %s\n", strerror(ret));
- abort();
- }
- pit->channels[0].irq_disabled = kpit.flags & KVM_PIT_FLAGS_HPET_LEGACY;
- } else {
- /*
- * kvm_pit_state2 is superset of kvm_pit_state struct,
- * so we can use it for KVM_GET_PIT as well.
- */
- ret = kvm_vm_ioctl(kvm_state, KVM_GET_PIT, &kpit);
- if (ret < 0) {
- fprintf(stderr, "KVM_GET_PIT failed: %s\n", strerror(ret));
- abort();
- }
- }
- for (i = 0; i < 3; i++) {
- kchan = &kpit.channels[i];
- sc = &pit->channels[i];
- sc->count = kchan->count;
- sc->latched_count = kchan->latched_count;
- sc->count_latched = kchan->count_latched;
- sc->status_latched = kchan->status_latched;
- sc->status = kchan->status;
- sc->read_state = kchan->read_state;
- sc->write_state = kchan->write_state;
- sc->write_latch = kchan->write_latch;
- sc->rw_mode = kchan->rw_mode;
- sc->mode = kchan->mode;
- sc->bcd = kchan->bcd;
- sc->gate = kchan->gate;
- sc->count_load_time = kchan->count_load_time + s->kernel_clock_offset;
- }
-
- sc = &pit->channels[0];
- sc->next_transition_time =
- pit_get_next_transition_time(sc, sc->count_load_time);
-}
-
-static void kvm_pit_put(PITCommonState *pit)
-{
- KVMPITState *s = KVM_PIT(pit);
- struct kvm_pit_state2 kpit = {};
- struct kvm_pit_channel_state *kchan;
- struct PITChannelState *sc;
- int i, ret;
-
- /* The offset keeps changing as long as the VM is stopped. */
- if (s->vm_stopped) {
- kvm_pit_update_clock_offset(s);
- }
-
- kpit.flags = pit->channels[0].irq_disabled ? KVM_PIT_FLAGS_HPET_LEGACY : 0;
- for (i = 0; i < 3; i++) {
- kchan = &kpit.channels[i];
- sc = &pit->channels[i];
- kchan->count = sc->count;
- kchan->latched_count = sc->latched_count;
- kchan->count_latched = sc->count_latched;
- kchan->status_latched = sc->status_latched;
- kchan->status = sc->status;
- kchan->read_state = sc->read_state;
- kchan->write_state = sc->write_state;
- kchan->write_latch = sc->write_latch;
- kchan->rw_mode = sc->rw_mode;
- kchan->mode = sc->mode;
- kchan->bcd = sc->bcd;
- kchan->gate = sc->gate;
- kchan->count_load_time = sc->count_load_time - s->kernel_clock_offset;
- }
-
- ret = kvm_vm_ioctl(kvm_state,
- kvm_has_pit_state2() ? KVM_SET_PIT2 : KVM_SET_PIT,
- &kpit);
- if (ret < 0) {
- fprintf(stderr, "%s failed: %s\n",
- kvm_has_pit_state2() ? "KVM_SET_PIT2" : "KVM_SET_PIT",
- strerror(ret));
- abort();
- }
-}
-
-static void kvm_pit_set_gate(PITCommonState *s, PITChannelState *sc, int val)
-{
- kvm_pit_get(s);
-
- switch (sc->mode) {
- default:
- case 0:
- case 4:
- /* XXX: just disable/enable counting */
- break;
- case 1:
- case 2:
- case 3:
- case 5:
- if (sc->gate < val) {
- /* restart counting on rising edge */
- sc->count_load_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- }
- break;
- }
- sc->gate = val;
-
- kvm_pit_put(s);
-}
-
-static void kvm_pit_get_channel_info(PITCommonState *s, PITChannelState *sc,
- PITChannelInfo *info)
-{
- kvm_pit_get(s);
-
- pit_get_channel_info_common(s, sc, info);
-}
-
-static void kvm_pit_reset(DeviceState *dev)
-{
- PITCommonState *s = PIT_COMMON(dev);
-
- pit_reset_common(s);
-
- kvm_pit_put(s);
-}
-
-static void kvm_pit_irq_control(void *opaque, int n, int enable)
-{
- PITCommonState *pit = opaque;
- PITChannelState *s = &pit->channels[0];
-
- kvm_pit_get(pit);
-
- s->irq_disabled = !enable;
-
- kvm_pit_put(pit);
-}
-
-static void kvm_pit_vm_state_change(void *opaque, int running,
- RunState state)
-{
- KVMPITState *s = opaque;
-
- if (running) {
- kvm_pit_update_clock_offset(s);
- kvm_pit_put(PIT_COMMON(s));
- s->vm_stopped = false;
- } else {
- kvm_pit_update_clock_offset(s);
- kvm_pit_get(PIT_COMMON(s));
- s->vm_stopped = true;
- }
-}
-
-static void kvm_pit_realizefn(DeviceState *dev, Error **errp)
-{
- PITCommonState *pit = PIT_COMMON(dev);
- KVMPITClass *kpc = KVM_PIT_GET_CLASS(dev);
- KVMPITState *s = KVM_PIT(pit);
- struct kvm_pit_config config = {
- .flags = 0,
- };
- int ret;
-
- if (kvm_check_extension(kvm_state, KVM_CAP_PIT2)) {
- ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_PIT2, &config);
- } else {
- ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_PIT);
- }
- if (ret < 0) {
- error_setg(errp, "Create kernel PIC irqchip failed: %s",
- strerror(ret));
- return;
- }
- switch (s->lost_tick_policy) {
- case LOST_TICK_POLICY_DELAY:
- break; /* enabled by default */
- case LOST_TICK_POLICY_DISCARD:
- if (kvm_check_extension(kvm_state, KVM_CAP_REINJECT_CONTROL)) {
- struct kvm_reinject_control control = { .pit_reinject = 0 };
-
- ret = kvm_vm_ioctl(kvm_state, KVM_REINJECT_CONTROL, &control);
- if (ret < 0) {
- error_setg(errp,
- "Can't disable in-kernel PIT reinjection: %s",
- strerror(ret));
- return;
- }
- }
- break;
- default:
- error_setg(errp, "Lost tick policy not supported.");
- return;
- }
-
- memory_region_init_reservation(&pit->ioports, NULL, "kvm-pit", 4);
-
- qdev_init_gpio_in(dev, kvm_pit_irq_control, 1);
-
- qemu_add_vm_change_state_handler(kvm_pit_vm_state_change, s);
-
- kpc->parent_realize(dev, errp);
-}
-
-static Property kvm_pit_properties[] = {
- DEFINE_PROP_UINT32("iobase", PITCommonState, iobase, -1),
- DEFINE_PROP_LOSTTICKPOLICY("lost_tick_policy", KVMPITState,
- lost_tick_policy, LOST_TICK_POLICY_DELAY),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void kvm_pit_class_init(ObjectClass *klass, void *data)
-{
- KVMPITClass *kpc = KVM_PIT_CLASS(klass);
- PITCommonClass *k = PIT_COMMON_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- kpc->parent_realize = dc->realize;
- dc->realize = kvm_pit_realizefn;
- k->set_channel_gate = kvm_pit_set_gate;
- k->get_channel_info = kvm_pit_get_channel_info;
- dc->reset = kvm_pit_reset;
- dc->props = kvm_pit_properties;
-}
-
-static const TypeInfo kvm_pit_info = {
- .name = TYPE_KVM_I8254,
- .parent = TYPE_PIT_COMMON,
- .instance_size = sizeof(KVMPITState),
- .class_init = kvm_pit_class_init,
- .class_size = sizeof(KVMPITClass),
-};
-
-static void kvm_pit_register(void)
-{
- type_register_static(&kvm_pit_info);
-}
-
-type_init(kvm_pit_register)
diff --git a/qemu/hw/i386/kvm/i8259.c b/qemu/hw/i386/kvm/i8259.c
deleted file mode 100644
index 2b207de01..000000000
--- a/qemu/hw/i386/kvm/i8259.c
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * KVM in-kernel PIC (i8259) support
- *
- * Copyright (c) 2011 Siemens AG
- *
- * Authors:
- * Jan Kiszka <jan.kiszka@siemens.com>
- *
- * This work is licensed under the terms of the GNU GPL version 2.
- * See the COPYING file in the top-level directory.
- */
-#include "qemu/osdep.h"
-#include "hw/isa/i8259_internal.h"
-#include "hw/i386/apic_internal.h"
-#include "sysemu/kvm.h"
-
-#define TYPE_KVM_I8259 "kvm-i8259"
-#define KVM_PIC_CLASS(class) \
- OBJECT_CLASS_CHECK(KVMPICClass, (class), TYPE_KVM_I8259)
-#define KVM_PIC_GET_CLASS(obj) \
- OBJECT_GET_CLASS(KVMPICClass, (obj), TYPE_KVM_I8259)
-
-/**
- * KVMPICClass:
- * @parent_realize: The parent's realizefn.
- */
-typedef struct KVMPICClass {
- PICCommonClass parent_class;
-
- DeviceRealize parent_realize;
-} KVMPICClass;
-
-static void kvm_pic_get(PICCommonState *s)
-{
- struct kvm_irqchip chip;
- struct kvm_pic_state *kpic;
- int ret;
-
- chip.chip_id = s->master ? KVM_IRQCHIP_PIC_MASTER : KVM_IRQCHIP_PIC_SLAVE;
- ret = kvm_vm_ioctl(kvm_state, KVM_GET_IRQCHIP, &chip);
- if (ret < 0) {
- fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret));
- abort();
- }
-
- kpic = &chip.chip.pic;
-
- s->last_irr = kpic->last_irr;
- s->irr = kpic->irr;
- s->imr = kpic->imr;
- s->isr = kpic->isr;
- s->priority_add = kpic->priority_add;
- s->irq_base = kpic->irq_base;
- s->read_reg_select = kpic->read_reg_select;
- s->poll = kpic->poll;
- s->special_mask = kpic->special_mask;
- s->init_state = kpic->init_state;
- s->auto_eoi = kpic->auto_eoi;
- s->rotate_on_auto_eoi = kpic->rotate_on_auto_eoi;
- s->special_fully_nested_mode = kpic->special_fully_nested_mode;
- s->init4 = kpic->init4;
- s->elcr = kpic->elcr;
- s->elcr_mask = kpic->elcr_mask;
-}
-
-static void kvm_pic_put(PICCommonState *s)
-{
- struct kvm_irqchip chip;
- struct kvm_pic_state *kpic;
- int ret;
-
- chip.chip_id = s->master ? KVM_IRQCHIP_PIC_MASTER : KVM_IRQCHIP_PIC_SLAVE;
-
- kpic = &chip.chip.pic;
-
- kpic->last_irr = s->last_irr;
- kpic->irr = s->irr;
- kpic->imr = s->imr;
- kpic->isr = s->isr;
- kpic->priority_add = s->priority_add;
- kpic->irq_base = s->irq_base;
- kpic->read_reg_select = s->read_reg_select;
- kpic->poll = s->poll;
- kpic->special_mask = s->special_mask;
- kpic->init_state = s->init_state;
- kpic->auto_eoi = s->auto_eoi;
- kpic->rotate_on_auto_eoi = s->rotate_on_auto_eoi;
- kpic->special_fully_nested_mode = s->special_fully_nested_mode;
- kpic->init4 = s->init4;
- kpic->elcr = s->elcr;
- kpic->elcr_mask = s->elcr_mask;
-
- ret = kvm_vm_ioctl(kvm_state, KVM_SET_IRQCHIP, &chip);
- if (ret < 0) {
- fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret));
- abort();
- }
-}
-
-static void kvm_pic_reset(DeviceState *dev)
-{
- PICCommonState *s = PIC_COMMON(dev);
-
- s->elcr = 0;
- pic_reset_common(s);
-
- kvm_pic_put(s);
-}
-
-static void kvm_pic_set_irq(void *opaque, int irq, int level)
-{
- int delivered;
-
- delivered = kvm_set_irq(kvm_state, irq, level);
- apic_report_irq_delivered(delivered);
-}
-
-static void kvm_pic_realize(DeviceState *dev, Error **errp)
-{
- PICCommonState *s = PIC_COMMON(dev);
- KVMPICClass *kpc = KVM_PIC_GET_CLASS(dev);
-
- memory_region_init_reservation(&s->base_io, NULL, "kvm-pic", 2);
- memory_region_init_reservation(&s->elcr_io, NULL, "kvm-elcr", 1);
-
- kpc->parent_realize(dev, errp);
-}
-
-qemu_irq *kvm_i8259_init(ISABus *bus)
-{
- i8259_init_chip(TYPE_KVM_I8259, bus, true);
- i8259_init_chip(TYPE_KVM_I8259, bus, false);
-
- return qemu_allocate_irqs(kvm_pic_set_irq, NULL, ISA_NUM_IRQS);
-}
-
-static void kvm_i8259_class_init(ObjectClass *klass, void *data)
-{
- KVMPICClass *kpc = KVM_PIC_CLASS(klass);
- PICCommonClass *k = PIC_COMMON_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->reset = kvm_pic_reset;
- kpc->parent_realize = dc->realize;
- dc->realize = kvm_pic_realize;
- k->pre_save = kvm_pic_get;
- k->post_load = kvm_pic_put;
-}
-
-static const TypeInfo kvm_i8259_info = {
- .name = TYPE_KVM_I8259,
- .parent = TYPE_PIC_COMMON,
- .instance_size = sizeof(PICCommonState),
- .class_init = kvm_i8259_class_init,
- .class_size = sizeof(KVMPICClass),
-};
-
-static void kvm_pic_register_types(void)
-{
- type_register_static(&kvm_i8259_info);
-}
-
-type_init(kvm_pic_register_types)
diff --git a/qemu/hw/i386/kvm/ioapic.c b/qemu/hw/i386/kvm/ioapic.c
deleted file mode 100644
index 8eb2c7a70..000000000
--- a/qemu/hw/i386/kvm/ioapic.c
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * KVM in-kernel IOPIC support
- *
- * Copyright (c) 2011 Siemens AG
- *
- * Authors:
- * Jan Kiszka <jan.kiszka@siemens.com>
- *
- * This work is licensed under the terms of the GNU GPL version 2.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "monitor/monitor.h"
-#include "hw/i386/pc.h"
-#include "hw/i386/ioapic_internal.h"
-#include "hw/i386/apic_internal.h"
-#include "sysemu/kvm.h"
-
-/* PC Utility function */
-void kvm_pc_setup_irq_routing(bool pci_enabled)
-{
- KVMState *s = kvm_state;
- int i;
-
- if (kvm_check_extension(s, KVM_CAP_IRQ_ROUTING)) {
- for (i = 0; i < 8; ++i) {
- if (i == 2) {
- continue;
- }
- kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_PIC_MASTER, i);
- }
- for (i = 8; i < 16; ++i) {
- kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_PIC_SLAVE, i - 8);
- }
- if (pci_enabled) {
- for (i = 0; i < 24; ++i) {
- if (i == 0) {
- kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_IOAPIC, 2);
- } else if (i != 2) {
- kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_IOAPIC, i);
- }
- }
- }
- kvm_irqchip_commit_routes(s);
- }
-}
-
-void kvm_pc_gsi_handler(void *opaque, int n, int level)
-{
- GSIState *s = opaque;
-
- if (n < ISA_NUM_IRQS) {
- /* Kernel will forward to both PIC and IOAPIC */
- qemu_set_irq(s->i8259_irq[n], level);
- } else {
- qemu_set_irq(s->ioapic_irq[n], level);
- }
-}
-
-typedef struct KVMIOAPICState KVMIOAPICState;
-
-struct KVMIOAPICState {
- IOAPICCommonState ioapic;
- uint32_t kvm_gsi_base;
-};
-
-static void kvm_ioapic_get(IOAPICCommonState *s)
-{
- struct kvm_irqchip chip;
- struct kvm_ioapic_state *kioapic;
- int ret, i;
-
- chip.chip_id = KVM_IRQCHIP_IOAPIC;
- ret = kvm_vm_ioctl(kvm_state, KVM_GET_IRQCHIP, &chip);
- if (ret < 0) {
- fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret));
- abort();
- }
-
- kioapic = &chip.chip.ioapic;
-
- s->id = kioapic->id;
- s->ioregsel = kioapic->ioregsel;
- s->irr = kioapic->irr;
- for (i = 0; i < IOAPIC_NUM_PINS; i++) {
- s->ioredtbl[i] = kioapic->redirtbl[i].bits;
- }
-}
-
-static void kvm_ioapic_put(IOAPICCommonState *s)
-{
- struct kvm_irqchip chip;
- struct kvm_ioapic_state *kioapic;
- int ret, i;
-
- chip.chip_id = KVM_IRQCHIP_IOAPIC;
- kioapic = &chip.chip.ioapic;
-
- kioapic->id = s->id;
- kioapic->ioregsel = s->ioregsel;
- kioapic->base_address = s->busdev.mmio[0].addr;
- kioapic->irr = s->irr;
- for (i = 0; i < IOAPIC_NUM_PINS; i++) {
- kioapic->redirtbl[i].bits = s->ioredtbl[i];
- }
-
- ret = kvm_vm_ioctl(kvm_state, KVM_SET_IRQCHIP, &chip);
- if (ret < 0) {
- fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret));
- abort();
- }
-}
-
-void kvm_ioapic_dump_state(Monitor *mon, const QDict *qdict)
-{
- IOAPICCommonState s;
-
- kvm_ioapic_get(&s);
-
- ioapic_print_redtbl(mon, &s);
-}
-
-static void kvm_ioapic_reset(DeviceState *dev)
-{
- IOAPICCommonState *s = IOAPIC_COMMON(dev);
-
- ioapic_reset_common(dev);
- kvm_ioapic_put(s);
-}
-
-static void kvm_ioapic_set_irq(void *opaque, int irq, int level)
-{
- KVMIOAPICState *s = opaque;
- int delivered;
-
- delivered = kvm_set_irq(kvm_state, s->kvm_gsi_base + irq, level);
- apic_report_irq_delivered(delivered);
-}
-
-static void kvm_ioapic_realize(DeviceState *dev, Error **errp)
-{
- IOAPICCommonState *s = IOAPIC_COMMON(dev);
-
- memory_region_init_reservation(&s->io_memory, NULL, "kvm-ioapic", 0x1000);
-
- qdev_init_gpio_in(dev, kvm_ioapic_set_irq, IOAPIC_NUM_PINS);
-}
-
-static Property kvm_ioapic_properties[] = {
- DEFINE_PROP_UINT32("gsi_base", KVMIOAPICState, kvm_gsi_base, 0),
- DEFINE_PROP_END_OF_LIST()
-};
-
-static void kvm_ioapic_class_init(ObjectClass *klass, void *data)
-{
- IOAPICCommonClass *k = IOAPIC_COMMON_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- k->realize = kvm_ioapic_realize;
- k->pre_save = kvm_ioapic_get;
- k->post_load = kvm_ioapic_put;
- dc->reset = kvm_ioapic_reset;
- dc->props = kvm_ioapic_properties;
-}
-
-static const TypeInfo kvm_ioapic_info = {
- .name = "kvm-ioapic",
- .parent = TYPE_IOAPIC_COMMON,
- .instance_size = sizeof(KVMIOAPICState),
- .class_init = kvm_ioapic_class_init,
-};
-
-static void kvm_ioapic_register_types(void)
-{
- type_register_static(&kvm_ioapic_info);
-}
-
-type_init(kvm_ioapic_register_types)
diff --git a/qemu/hw/i386/kvm/pci-assign.c b/qemu/hw/i386/kvm/pci-assign.c
deleted file mode 100644
index bf425a2b9..000000000
--- a/qemu/hw/i386/kvm/pci-assign.c
+++ /dev/null
@@ -1,1898 +0,0 @@
-/*
- * Copyright (c) 2007, Neocleus Corporation.
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- *
- * Assign a PCI device from the host to a guest VM.
- *
- * This implementation uses the classic device assignment interface of KVM
- * and is only available on x86 hosts. It is expected to be obsoleted by VFIO
- * based device assignment.
- *
- * Adapted for KVM (qemu-kvm) by Qumranet. QEMU version was based on qemu-kvm
- * revision 4144fe9d48. See its repository for the history.
- *
- * Copyright (c) 2007, Neocleus, Alex Novik (alex@neocleus.com)
- * Copyright (c) 2007, Neocleus, Guy Zana (guy@neocleus.com)
- * Copyright (C) 2008, Qumranet, Amit Shah (amit.shah@qumranet.com)
- * Copyright (C) 2008, Red Hat, Amit Shah (amit.shah@redhat.com)
- * Copyright (C) 2008, IBM, Muli Ben-Yehuda (muli@il.ibm.com)
- */
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include <sys/mman.h>
-#include "hw/hw.h"
-#include "hw/i386/pc.h"
-#include "qemu/error-report.h"
-#include "ui/console.h"
-#include "hw/loader.h"
-#include "monitor/monitor.h"
-#include "qemu/range.h"
-#include "sysemu/sysemu.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/msi.h"
-#include "kvm_i386.h"
-#include "hw/pci/pci-assign.h"
-
-#define MSIX_PAGE_SIZE 0x1000
-
-/* From linux/ioport.h */
-#define IORESOURCE_IO 0x00000100 /* Resource type */
-#define IORESOURCE_MEM 0x00000200
-#define IORESOURCE_IRQ 0x00000400
-#define IORESOURCE_DMA 0x00000800
-#define IORESOURCE_PREFETCH 0x00002000 /* No side effects */
-#define IORESOURCE_MEM_64 0x00100000
-
-typedef struct PCIRegion {
- int type; /* Memory or port I/O */
- int valid;
- uint64_t base_addr;
- uint64_t size; /* size of the region */
- int resource_fd;
-} PCIRegion;
-
-typedef struct PCIDevRegions {
- uint8_t bus, dev, func; /* Bus inside domain, device and function */
- int irq; /* IRQ number */
- uint16_t region_number; /* number of active regions */
-
- /* Port I/O or MMIO Regions */
- PCIRegion regions[PCI_NUM_REGIONS - 1];
- int config_fd;
-} PCIDevRegions;
-
-typedef struct AssignedDevRegion {
- MemoryRegion container;
- MemoryRegion real_iomem;
- union {
- uint8_t *r_virtbase; /* mmapped access address for memory regions */
- uint32_t r_baseport; /* the base guest port for I/O regions */
- } u;
- pcibus_t e_size; /* emulated size of region in bytes */
- pcibus_t r_size; /* real size of region in bytes */
- PCIRegion *region;
-} AssignedDevRegion;
-
-#define ASSIGNED_DEVICE_PREFER_MSI_BIT 0
-#define ASSIGNED_DEVICE_SHARE_INTX_BIT 1
-
-#define ASSIGNED_DEVICE_PREFER_MSI_MASK (1 << ASSIGNED_DEVICE_PREFER_MSI_BIT)
-#define ASSIGNED_DEVICE_SHARE_INTX_MASK (1 << ASSIGNED_DEVICE_SHARE_INTX_BIT)
-
-typedef struct MSIXTableEntry {
- uint32_t addr_lo;
- uint32_t addr_hi;
- uint32_t data;
- uint32_t ctrl;
-} MSIXTableEntry;
-
-typedef enum AssignedIRQType {
- ASSIGNED_IRQ_NONE = 0,
- ASSIGNED_IRQ_INTX_HOST_INTX,
- ASSIGNED_IRQ_INTX_HOST_MSI,
- ASSIGNED_IRQ_MSI,
- ASSIGNED_IRQ_MSIX
-} AssignedIRQType;
-
-typedef struct AssignedDevice {
- PCIDevice dev;
- PCIHostDeviceAddress host;
- uint32_t dev_id;
- uint32_t features;
- int intpin;
- AssignedDevRegion v_addrs[PCI_NUM_REGIONS - 1];
- PCIDevRegions real_device;
- PCIINTxRoute intx_route;
- AssignedIRQType assigned_irq_type;
- struct {
-#define ASSIGNED_DEVICE_CAP_MSI (1 << 0)
-#define ASSIGNED_DEVICE_CAP_MSIX (1 << 1)
- uint32_t available;
-#define ASSIGNED_DEVICE_MSI_ENABLED (1 << 0)
-#define ASSIGNED_DEVICE_MSIX_ENABLED (1 << 1)
-#define ASSIGNED_DEVICE_MSIX_MASKED (1 << 2)
- uint32_t state;
- } cap;
- uint8_t emulate_config_read[PCI_CONFIG_SPACE_SIZE];
- uint8_t emulate_config_write[PCI_CONFIG_SPACE_SIZE];
- int msi_virq_nr;
- int *msi_virq;
- MSIXTableEntry *msix_table;
- hwaddr msix_table_addr;
- uint16_t msix_max;
- MemoryRegion mmio;
- char *configfd_name;
- int32_t bootindex;
-} AssignedDevice;
-
-#define TYPE_PCI_ASSIGN "kvm-pci-assign"
-#define PCI_ASSIGN(obj) OBJECT_CHECK(AssignedDevice, (obj), TYPE_PCI_ASSIGN)
-
-static void assigned_dev_update_irq_routing(PCIDevice *dev);
-
-static void assigned_dev_load_option_rom(AssignedDevice *dev);
-
-static void assigned_dev_unregister_msix_mmio(AssignedDevice *dev);
-
-static uint64_t assigned_dev_ioport_rw(AssignedDevRegion *dev_region,
- hwaddr addr, int size,
- uint64_t *data)
-{
- uint64_t val = 0;
- int fd = dev_region->region->resource_fd;
-
- if (data) {
- DEBUG("pwrite data=%" PRIx64 ", size=%d, e_phys=" TARGET_FMT_plx
- ", addr="TARGET_FMT_plx"\n", *data, size, addr, addr);
- if (pwrite(fd, data, size, addr) != size) {
- error_report("%s - pwrite failed %s", __func__, strerror(errno));
- }
- } else {
- if (pread(fd, &val, size, addr) != size) {
- error_report("%s - pread failed %s", __func__, strerror(errno));
- val = (1UL << (size * 8)) - 1;
- }
- DEBUG("pread val=%" PRIx64 ", size=%d, e_phys=" TARGET_FMT_plx
- ", addr=" TARGET_FMT_plx "\n", val, size, addr, addr);
- }
- return val;
-}
-
-static void assigned_dev_ioport_write(void *opaque, hwaddr addr,
- uint64_t data, unsigned size)
-{
- assigned_dev_ioport_rw(opaque, addr, size, &data);
-}
-
-static uint64_t assigned_dev_ioport_read(void *opaque,
- hwaddr addr, unsigned size)
-{
- return assigned_dev_ioport_rw(opaque, addr, size, NULL);
-}
-
-static uint32_t slow_bar_readb(void *opaque, hwaddr addr)
-{
- AssignedDevRegion *d = opaque;
- uint8_t *in = d->u.r_virtbase + addr;
- uint32_t r;
-
- r = *in;
- DEBUG("addr=0x" TARGET_FMT_plx " val=0x%08x\n", addr, r);
-
- return r;
-}
-
-static uint32_t slow_bar_readw(void *opaque, hwaddr addr)
-{
- AssignedDevRegion *d = opaque;
- uint16_t *in = (uint16_t *)(d->u.r_virtbase + addr);
- uint32_t r;
-
- r = *in;
- DEBUG("addr=0x" TARGET_FMT_plx " val=0x%08x\n", addr, r);
-
- return r;
-}
-
-static uint32_t slow_bar_readl(void *opaque, hwaddr addr)
-{
- AssignedDevRegion *d = opaque;
- uint32_t *in = (uint32_t *)(d->u.r_virtbase + addr);
- uint32_t r;
-
- r = *in;
- DEBUG("addr=0x" TARGET_FMT_plx " val=0x%08x\n", addr, r);
-
- return r;
-}
-
-static void slow_bar_writeb(void *opaque, hwaddr addr, uint32_t val)
-{
- AssignedDevRegion *d = opaque;
- uint8_t *out = d->u.r_virtbase + addr;
-
- DEBUG("addr=0x" TARGET_FMT_plx " val=0x%02x\n", addr, val);
- *out = val;
-}
-
-static void slow_bar_writew(void *opaque, hwaddr addr, uint32_t val)
-{
- AssignedDevRegion *d = opaque;
- uint16_t *out = (uint16_t *)(d->u.r_virtbase + addr);
-
- DEBUG("addr=0x" TARGET_FMT_plx " val=0x%04x\n", addr, val);
- *out = val;
-}
-
-static void slow_bar_writel(void *opaque, hwaddr addr, uint32_t val)
-{
- AssignedDevRegion *d = opaque;
- uint32_t *out = (uint32_t *)(d->u.r_virtbase + addr);
-
- DEBUG("addr=0x" TARGET_FMT_plx " val=0x%08x\n", addr, val);
- *out = val;
-}
-
-static const MemoryRegionOps slow_bar_ops = {
- .old_mmio = {
- .read = { slow_bar_readb, slow_bar_readw, slow_bar_readl, },
- .write = { slow_bar_writeb, slow_bar_writew, slow_bar_writel, },
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void assigned_dev_iomem_setup(PCIDevice *pci_dev, int region_num,
- pcibus_t e_size)
-{
- AssignedDevice *r_dev = PCI_ASSIGN(pci_dev);
- AssignedDevRegion *region = &r_dev->v_addrs[region_num];
- PCIRegion *real_region = &r_dev->real_device.regions[region_num];
-
- if (e_size > 0) {
- memory_region_init(&region->container, OBJECT(pci_dev),
- "assigned-dev-container", e_size);
- memory_region_add_subregion(&region->container, 0, &region->real_iomem);
-
- /* deal with MSI-X MMIO page */
- if (real_region->base_addr <= r_dev->msix_table_addr &&
- real_region->base_addr + real_region->size >
- r_dev->msix_table_addr) {
- uint64_t offset = r_dev->msix_table_addr - real_region->base_addr;
-
- memory_region_add_subregion_overlap(&region->container,
- offset,
- &r_dev->mmio,
- 1);
- }
- }
-}
-
-static const MemoryRegionOps assigned_dev_ioport_ops = {
- .read = assigned_dev_ioport_read,
- .write = assigned_dev_ioport_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void assigned_dev_ioport_setup(PCIDevice *pci_dev, int region_num,
- pcibus_t size)
-{
- AssignedDevice *r_dev = PCI_ASSIGN(pci_dev);
- AssignedDevRegion *region = &r_dev->v_addrs[region_num];
-
- region->e_size = size;
- memory_region_init(&region->container, OBJECT(pci_dev),
- "assigned-dev-container", size);
- memory_region_init_io(&region->real_iomem, OBJECT(pci_dev),
- &assigned_dev_ioport_ops, r_dev->v_addrs + region_num,
- "assigned-dev-iomem", size);
- memory_region_add_subregion(&region->container, 0, &region->real_iomem);
-}
-
-static uint32_t assigned_dev_pci_read(PCIDevice *d, int pos, int len)
-{
- AssignedDevice *pci_dev = PCI_ASSIGN(d);
- uint32_t val;
- ssize_t ret;
- int fd = pci_dev->real_device.config_fd;
-
-again:
- ret = pread(fd, &val, len, pos);
- if (ret != len) {
- if ((ret < 0) && (errno == EINTR || errno == EAGAIN)) {
- goto again;
- }
-
- hw_error("pci read failed, ret = %zd errno = %d\n", ret, errno);
- }
-
- return val;
-}
-
-static uint8_t assigned_dev_pci_read_byte(PCIDevice *d, int pos)
-{
- return (uint8_t)assigned_dev_pci_read(d, pos, 1);
-}
-
-static void assigned_dev_pci_write(PCIDevice *d, int pos, uint32_t val, int len)
-{
- AssignedDevice *pci_dev = PCI_ASSIGN(d);
- ssize_t ret;
- int fd = pci_dev->real_device.config_fd;
-
-again:
- ret = pwrite(fd, &val, len, pos);
- if (ret != len) {
- if ((ret < 0) && (errno == EINTR || errno == EAGAIN)) {
- goto again;
- }
-
- hw_error("pci write failed, ret = %zd errno = %d\n", ret, errno);
- }
-}
-
-static void assigned_dev_emulate_config_read(AssignedDevice *dev,
- uint32_t offset, uint32_t len)
-{
- memset(dev->emulate_config_read + offset, 0xff, len);
-}
-
-static void assigned_dev_direct_config_read(AssignedDevice *dev,
- uint32_t offset, uint32_t len)
-{
- memset(dev->emulate_config_read + offset, 0, len);
-}
-
-static void assigned_dev_direct_config_write(AssignedDevice *dev,
- uint32_t offset, uint32_t len)
-{
- memset(dev->emulate_config_write + offset, 0, len);
-}
-
-static uint8_t pci_find_cap_offset(PCIDevice *d, uint8_t cap, uint8_t start)
-{
- int id;
- int max_cap = 48;
- int pos = start ? start : PCI_CAPABILITY_LIST;
- int status;
-
- status = assigned_dev_pci_read_byte(d, PCI_STATUS);
- if ((status & PCI_STATUS_CAP_LIST) == 0) {
- return 0;
- }
-
- while (max_cap--) {
- pos = assigned_dev_pci_read_byte(d, pos);
- if (pos < 0x40) {
- break;
- }
-
- pos &= ~3;
- id = assigned_dev_pci_read_byte(d, pos + PCI_CAP_LIST_ID);
-
- if (id == 0xff) {
- break;
- }
- if (id == cap) {
- return pos;
- }
-
- pos += PCI_CAP_LIST_NEXT;
- }
- return 0;
-}
-
-static void assigned_dev_register_regions(PCIRegion *io_regions,
- unsigned long regions_num,
- AssignedDevice *pci_dev,
- Error **errp)
-{
- uint32_t i;
- PCIRegion *cur_region = io_regions;
-
- for (i = 0; i < regions_num; i++, cur_region++) {
- if (!cur_region->valid) {
- continue;
- }
-
- /* handle memory io regions */
- if (cur_region->type & IORESOURCE_MEM) {
- int t = PCI_BASE_ADDRESS_SPACE_MEMORY;
- if (cur_region->type & IORESOURCE_PREFETCH) {
- t |= PCI_BASE_ADDRESS_MEM_PREFETCH;
- }
- if (cur_region->type & IORESOURCE_MEM_64) {
- t |= PCI_BASE_ADDRESS_MEM_TYPE_64;
- }
-
- /* map physical memory */
- pci_dev->v_addrs[i].u.r_virtbase = mmap(NULL, cur_region->size,
- PROT_WRITE | PROT_READ,
- MAP_SHARED,
- cur_region->resource_fd,
- (off_t)0);
-
- if (pci_dev->v_addrs[i].u.r_virtbase == MAP_FAILED) {
- pci_dev->v_addrs[i].u.r_virtbase = NULL;
- error_setg_errno(errp, errno, "Couldn't mmap 0x%" PRIx64 "!",
- cur_region->base_addr);
- return;
- }
-
- pci_dev->v_addrs[i].r_size = cur_region->size;
- pci_dev->v_addrs[i].e_size = 0;
-
- /* add offset */
- pci_dev->v_addrs[i].u.r_virtbase +=
- (cur_region->base_addr & 0xFFF);
-
- if (cur_region->size & 0xFFF) {
- error_report("PCI region %d at address 0x%" PRIx64 " has "
- "size 0x%" PRIx64 ", which is not a multiple of "
- "4K. You might experience some performance hit "
- "due to that.",
- i, cur_region->base_addr, cur_region->size);
- memory_region_init_io(&pci_dev->v_addrs[i].real_iomem,
- OBJECT(pci_dev), &slow_bar_ops,
- &pci_dev->v_addrs[i],
- "assigned-dev-slow-bar",
- cur_region->size);
- } else {
- void *virtbase = pci_dev->v_addrs[i].u.r_virtbase;
- char name[32];
- snprintf(name, sizeof(name), "%s.bar%d",
- object_get_typename(OBJECT(pci_dev)), i);
- memory_region_init_ram_ptr(&pci_dev->v_addrs[i].real_iomem,
- OBJECT(pci_dev), name,
- cur_region->size, virtbase);
- vmstate_register_ram(&pci_dev->v_addrs[i].real_iomem,
- &pci_dev->dev.qdev);
- }
-
- assigned_dev_iomem_setup(&pci_dev->dev, i, cur_region->size);
- pci_register_bar((PCIDevice *) pci_dev, i, t,
- &pci_dev->v_addrs[i].container);
- continue;
- } else {
- /* handle port io regions */
- uint32_t val;
- int ret;
-
- /* Test kernel support for ioport resource read/write. Old
- * kernels return EIO. New kernels only allow 1/2/4 byte reads
- * so should return EINVAL for a 3 byte read */
- ret = pread(pci_dev->v_addrs[i].region->resource_fd, &val, 3, 0);
- if (ret >= 0) {
- error_report("Unexpected return from I/O port read: %d", ret);
- abort();
- } else if (errno != EINVAL) {
- error_report("Kernel doesn't support ioport resource "
- "access, hiding this region.");
- close(pci_dev->v_addrs[i].region->resource_fd);
- cur_region->valid = 0;
- continue;
- }
-
- pci_dev->v_addrs[i].u.r_baseport = cur_region->base_addr;
- pci_dev->v_addrs[i].r_size = cur_region->size;
- pci_dev->v_addrs[i].e_size = 0;
-
- assigned_dev_ioport_setup(&pci_dev->dev, i, cur_region->size);
- pci_register_bar((PCIDevice *) pci_dev, i,
- PCI_BASE_ADDRESS_SPACE_IO,
- &pci_dev->v_addrs[i].container);
- }
- }
-
- /* success */
-}
-
-static void get_real_id(const char *devpath, const char *idname, uint16_t *val,
- Error **errp)
-{
- FILE *f;
- char name[128];
- long id;
-
- snprintf(name, sizeof(name), "%s%s", devpath, idname);
- f = fopen(name, "r");
- if (f == NULL) {
- error_setg_file_open(errp, errno, name);
- return;
- }
- if (fscanf(f, "%li\n", &id) == 1) {
- *val = id;
- } else {
- error_setg(errp, "Failed to parse contents of '%s'", name);
- }
- fclose(f);
-}
-
-static void get_real_vendor_id(const char *devpath, uint16_t *val,
- Error **errp)
-{
- get_real_id(devpath, "vendor", val, errp);
-}
-
-static void get_real_device_id(const char *devpath, uint16_t *val,
- Error **errp)
-{
- get_real_id(devpath, "device", val, errp);
-}
-
-static void get_real_device(AssignedDevice *pci_dev, Error **errp)
-{
- char dir[128], name[128];
- int fd, r = 0;
- FILE *f;
- uint64_t start, end, size, flags;
- uint16_t id;
- PCIRegion *rp;
- PCIDevRegions *dev = &pci_dev->real_device;
- Error *local_err = NULL;
-
- dev->region_number = 0;
-
- snprintf(dir, sizeof(dir), "/sys/bus/pci/devices/%04x:%02x:%02x.%x/",
- pci_dev->host.domain, pci_dev->host.bus,
- pci_dev->host.slot, pci_dev->host.function);
-
- snprintf(name, sizeof(name), "%sconfig", dir);
-
- if (pci_dev->configfd_name && *pci_dev->configfd_name) {
- dev->config_fd = monitor_fd_param(cur_mon, pci_dev->configfd_name,
- &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
- } else {
- dev->config_fd = open(name, O_RDWR);
-
- if (dev->config_fd == -1) {
- error_setg_file_open(errp, errno, name);
- return;
- }
- }
-again:
- r = read(dev->config_fd, pci_dev->dev.config,
- pci_config_size(&pci_dev->dev));
- if (r < 0) {
- if (errno == EINTR || errno == EAGAIN) {
- goto again;
- }
- error_setg_errno(errp, errno, "read(\"%s\")",
- (pci_dev->configfd_name && *pci_dev->configfd_name) ?
- pci_dev->configfd_name : name);
- return;
- }
-
- /* Restore or clear multifunction, this is always controlled by qemu */
- if (pci_dev->dev.cap_present & QEMU_PCI_CAP_MULTIFUNCTION) {
- pci_dev->dev.config[PCI_HEADER_TYPE] |= PCI_HEADER_TYPE_MULTI_FUNCTION;
- } else {
- pci_dev->dev.config[PCI_HEADER_TYPE] &= ~PCI_HEADER_TYPE_MULTI_FUNCTION;
- }
-
- /* Clear host resource mapping info. If we choose not to register a
- * BAR, such as might be the case with the option ROM, we can get
- * confusing, unwritable, residual addresses from the host here. */
- memset(&pci_dev->dev.config[PCI_BASE_ADDRESS_0], 0, 24);
- memset(&pci_dev->dev.config[PCI_ROM_ADDRESS], 0, 4);
-
- snprintf(name, sizeof(name), "%sresource", dir);
-
- f = fopen(name, "r");
- if (f == NULL) {
- error_setg_file_open(errp, errno, name);
- return;
- }
-
- for (r = 0; r < PCI_ROM_SLOT; r++) {
- if (fscanf(f, "%" SCNi64 " %" SCNi64 " %" SCNi64 "\n",
- &start, &end, &flags) != 3) {
- break;
- }
-
- rp = dev->regions + r;
- rp->valid = 0;
- rp->resource_fd = -1;
- size = end - start + 1;
- flags &= IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH
- | IORESOURCE_MEM_64;
- if (size == 0 || (flags & ~IORESOURCE_PREFETCH) == 0) {
- continue;
- }
- if (flags & IORESOURCE_MEM) {
- flags &= ~IORESOURCE_IO;
- } else {
- flags &= ~IORESOURCE_PREFETCH;
- }
- snprintf(name, sizeof(name), "%sresource%d", dir, r);
- fd = open(name, O_RDWR);
- if (fd == -1) {
- continue;
- }
- rp->resource_fd = fd;
-
- rp->type = flags;
- rp->valid = 1;
- rp->base_addr = start;
- rp->size = size;
- pci_dev->v_addrs[r].region = rp;
- DEBUG("region %d size %" PRIu64 " start 0x%" PRIx64
- " type %d resource_fd %d\n",
- r, rp->size, start, rp->type, rp->resource_fd);
- }
-
- fclose(f);
-
- /* read and fill vendor ID */
- get_real_vendor_id(dir, &id, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
- pci_dev->dev.config[0] = id & 0xff;
- pci_dev->dev.config[1] = (id & 0xff00) >> 8;
-
- /* read and fill device ID */
- get_real_device_id(dir, &id, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
- pci_dev->dev.config[2] = id & 0xff;
- pci_dev->dev.config[3] = (id & 0xff00) >> 8;
-
- pci_word_test_and_clear_mask(pci_dev->emulate_config_write + PCI_COMMAND,
- PCI_COMMAND_MASTER | PCI_COMMAND_INTX_DISABLE);
-
- dev->region_number = r;
-}
-
-static void free_msi_virqs(AssignedDevice *dev)
-{
- int i;
-
- for (i = 0; i < dev->msi_virq_nr; i++) {
- if (dev->msi_virq[i] >= 0) {
- kvm_irqchip_release_virq(kvm_state, dev->msi_virq[i]);
- dev->msi_virq[i] = -1;
- }
- }
- g_free(dev->msi_virq);
- dev->msi_virq = NULL;
- dev->msi_virq_nr = 0;
-}
-
-static void free_assigned_device(AssignedDevice *dev)
-{
- int i;
-
- if (dev->cap.available & ASSIGNED_DEVICE_CAP_MSIX) {
- assigned_dev_unregister_msix_mmio(dev);
- }
- for (i = 0; i < dev->real_device.region_number; i++) {
- PCIRegion *pci_region = &dev->real_device.regions[i];
- AssignedDevRegion *region = &dev->v_addrs[i];
-
- if (!pci_region->valid) {
- continue;
- }
- if (pci_region->type & IORESOURCE_IO) {
- if (region->u.r_baseport) {
- memory_region_del_subregion(&region->container,
- &region->real_iomem);
- }
- } else if (pci_region->type & IORESOURCE_MEM) {
- if (region->u.r_virtbase) {
- memory_region_del_subregion(&region->container,
- &region->real_iomem);
-
- /* Remove MSI-X table subregion */
- if (pci_region->base_addr <= dev->msix_table_addr &&
- pci_region->base_addr + pci_region->size >
- dev->msix_table_addr) {
- memory_region_del_subregion(&region->container,
- &dev->mmio);
- }
- if (munmap(region->u.r_virtbase,
- (pci_region->size + 0xFFF) & 0xFFFFF000)) {
- error_report("Failed to unmap assigned device region: %s",
- strerror(errno));
- }
- }
- }
- if (pci_region->resource_fd >= 0) {
- close(pci_region->resource_fd);
- }
- }
-
- if (dev->real_device.config_fd >= 0) {
- close(dev->real_device.config_fd);
- }
-
- free_msi_virqs(dev);
-}
-
-/* This function tries to determine the cause of the PCI assignment failure. It
- * always returns the cause as a dynamically allocated, human readable string.
- * If the function fails to determine the cause for any internal reason, then
- * the returned string will state that fact.
- */
-static char *assign_failed_examine(const AssignedDevice *dev)
-{
- char name[PATH_MAX], dir[PATH_MAX], driver[PATH_MAX] = {}, *ns;
- uint16_t vendor_id, device_id;
- int r;
- Error *local_err = NULL;
-
- snprintf(dir, sizeof(dir), "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/",
- dev->host.domain, dev->host.bus, dev->host.slot,
- dev->host.function);
-
- snprintf(name, sizeof(name), "%sdriver", dir);
-
- r = readlink(name, driver, sizeof(driver));
- if ((r <= 0) || r >= sizeof(driver)) {
- goto fail;
- }
-
- driver[r] = 0;
- ns = strrchr(driver, '/');
- if (!ns) {
- goto fail;
- }
-
- ns++;
-
- if ((get_real_vendor_id(dir, &vendor_id, &local_err), local_err) ||
- (get_real_device_id(dir, &device_id, &local_err), local_err)) {
- /* We're already analyzing an assignment error, so we suppress this
- * one just like the others above.
- */
- error_free(local_err);
- goto fail;
- }
-
- return g_strdup_printf(
- "*** The driver '%s' is occupying your device %04x:%02x:%02x.%x.\n"
- "***\n"
- "*** You can try the following commands to free it:\n"
- "***\n"
- "*** $ echo \"%04x %04x\" > /sys/bus/pci/drivers/pci-stub/new_id\n"
- "*** $ echo \"%04x:%02x:%02x.%x\" > /sys/bus/pci/drivers/%s/unbind\n"
- "*** $ echo \"%04x:%02x:%02x.%x\" > /sys/bus/pci/drivers/"
- "pci-stub/bind\n"
- "*** $ echo \"%04x %04x\" > /sys/bus/pci/drivers/pci-stub/remove_id\n"
- "***\n",
- ns, dev->host.domain, dev->host.bus, dev->host.slot,
- dev->host.function, vendor_id, device_id,
- dev->host.domain, dev->host.bus, dev->host.slot, dev->host.function,
- ns, dev->host.domain, dev->host.bus, dev->host.slot,
- dev->host.function, vendor_id, device_id);
-
-fail:
- return g_strdup("Couldn't find out why.\n");
-}
-
-static void assign_device(AssignedDevice *dev, Error **errp)
-{
- uint32_t flags = KVM_DEV_ASSIGN_ENABLE_IOMMU;
- int r;
-
- /* Only pass non-zero PCI segment to capable module */
- if (!kvm_check_extension(kvm_state, KVM_CAP_PCI_SEGMENT) &&
- dev->host.domain) {
- error_setg(errp, "Can't assign device inside non-zero PCI segment "
- "as this KVM module doesn't support it.");
- return;
- }
-
- if (!kvm_check_extension(kvm_state, KVM_CAP_IOMMU)) {
- error_setg(errp, "No IOMMU found. Unable to assign device \"%s\"",
- dev->dev.qdev.id);
- return;
- }
-
- if (dev->features & ASSIGNED_DEVICE_SHARE_INTX_MASK &&
- kvm_has_intx_set_mask()) {
- flags |= KVM_DEV_ASSIGN_PCI_2_3;
- }
-
- r = kvm_device_pci_assign(kvm_state, &dev->host, flags, &dev->dev_id);
- if (r < 0) {
- switch (r) {
- case -EBUSY: {
- char *cause;
-
- cause = assign_failed_examine(dev);
- error_setg_errno(errp, -r, "Failed to assign device \"%s\"",
- dev->dev.qdev.id);
- error_append_hint(errp, "%s", cause);
- g_free(cause);
- break;
- }
- default:
- error_setg_errno(errp, -r, "Failed to assign device \"%s\"",
- dev->dev.qdev.id);
- break;
- }
- }
-}
-
-static void verify_irqchip_in_kernel(Error **errp)
-{
- if (kvm_irqchip_in_kernel()) {
- return;
- }
- error_setg(errp, "pci-assign requires KVM with in-kernel irqchip enabled");
-}
-
-static int assign_intx(AssignedDevice *dev, Error **errp)
-{
- AssignedIRQType new_type;
- PCIINTxRoute intx_route;
- bool intx_host_msi;
- int r;
- Error *local_err = NULL;
-
- /* Interrupt PIN 0 means don't use INTx */
- if (assigned_dev_pci_read_byte(&dev->dev, PCI_INTERRUPT_PIN) == 0) {
- pci_device_set_intx_routing_notifier(&dev->dev, NULL);
- return 0;
- }
-
- verify_irqchip_in_kernel(&local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return -ENOTSUP;
- }
-
- pci_device_set_intx_routing_notifier(&dev->dev,
- assigned_dev_update_irq_routing);
-
- intx_route = pci_device_route_intx_to_irq(&dev->dev, dev->intpin);
- assert(intx_route.mode != PCI_INTX_INVERTED);
-
- if (!pci_intx_route_changed(&dev->intx_route, &intx_route)) {
- return 0;
- }
-
- switch (dev->assigned_irq_type) {
- case ASSIGNED_IRQ_INTX_HOST_INTX:
- case ASSIGNED_IRQ_INTX_HOST_MSI:
- intx_host_msi = dev->assigned_irq_type == ASSIGNED_IRQ_INTX_HOST_MSI;
- r = kvm_device_intx_deassign(kvm_state, dev->dev_id, intx_host_msi);
- break;
- case ASSIGNED_IRQ_MSI:
- r = kvm_device_msi_deassign(kvm_state, dev->dev_id);
- break;
- case ASSIGNED_IRQ_MSIX:
- r = kvm_device_msix_deassign(kvm_state, dev->dev_id);
- break;
- default:
- r = 0;
- break;
- }
- if (r) {
- perror("assign_intx: deassignment of previous interrupt failed");
- }
- dev->assigned_irq_type = ASSIGNED_IRQ_NONE;
-
- if (intx_route.mode == PCI_INTX_DISABLED) {
- dev->intx_route = intx_route;
- return 0;
- }
-
-retry:
- if (dev->features & ASSIGNED_DEVICE_PREFER_MSI_MASK &&
- dev->cap.available & ASSIGNED_DEVICE_CAP_MSI) {
- intx_host_msi = true;
- new_type = ASSIGNED_IRQ_INTX_HOST_MSI;
- } else {
- intx_host_msi = false;
- new_type = ASSIGNED_IRQ_INTX_HOST_INTX;
- }
-
- r = kvm_device_intx_assign(kvm_state, dev->dev_id, intx_host_msi,
- intx_route.irq);
- if (r < 0) {
- if (r == -EIO && !(dev->features & ASSIGNED_DEVICE_PREFER_MSI_MASK) &&
- dev->cap.available & ASSIGNED_DEVICE_CAP_MSI) {
- /* Retry with host-side MSI. There might be an IRQ conflict and
- * either the kernel or the device doesn't support sharing. */
- error_report("Host-side INTx sharing not supported, "
- "using MSI instead");
- error_printf("Some devices do not work properly in this mode.\n");
- dev->features |= ASSIGNED_DEVICE_PREFER_MSI_MASK;
- goto retry;
- }
- error_setg_errno(errp, -r, "Failed to assign irq for \"%s\"",
- dev->dev.qdev.id);
- error_append_hint(errp, "Perhaps you are assigning a device "
- "that shares an IRQ with another device?\n");
- return r;
- }
-
- dev->intx_route = intx_route;
- dev->assigned_irq_type = new_type;
- return r;
-}
-
-static void deassign_device(AssignedDevice *dev)
-{
- int r;
-
- r = kvm_device_pci_deassign(kvm_state, dev->dev_id);
- assert(r == 0);
-}
-
-/* The pci config space got updated. Check if irq numbers have changed
- * for our devices
- */
-static void assigned_dev_update_irq_routing(PCIDevice *dev)
-{
- AssignedDevice *assigned_dev = PCI_ASSIGN(dev);
- Error *err = NULL;
- int r;
-
- r = assign_intx(assigned_dev, &err);
- if (r < 0) {
- error_report_err(err);
- err = NULL;
- qdev_unplug(&dev->qdev, &err);
- assert(!err);
- }
-}
-
-static void assigned_dev_update_msi(PCIDevice *pci_dev)
-{
- AssignedDevice *assigned_dev = PCI_ASSIGN(pci_dev);
- uint8_t ctrl_byte = pci_get_byte(pci_dev->config + pci_dev->msi_cap +
- PCI_MSI_FLAGS);
- int r;
-
- /* Some guests gratuitously disable MSI even if they're not using it,
- * try to catch this by only deassigning irqs if the guest is using
- * MSI or intends to start. */
- if (assigned_dev->assigned_irq_type == ASSIGNED_IRQ_MSI ||
- (ctrl_byte & PCI_MSI_FLAGS_ENABLE)) {
- r = kvm_device_msi_deassign(kvm_state, assigned_dev->dev_id);
- /* -ENXIO means no assigned irq */
- if (r && r != -ENXIO) {
- perror("assigned_dev_update_msi: deassign irq");
- }
-
- free_msi_virqs(assigned_dev);
-
- assigned_dev->assigned_irq_type = ASSIGNED_IRQ_NONE;
- pci_device_set_intx_routing_notifier(pci_dev, NULL);
- }
-
- if (ctrl_byte & PCI_MSI_FLAGS_ENABLE) {
- MSIMessage msg = msi_get_message(pci_dev, 0);
- int virq;
-
- virq = kvm_irqchip_add_msi_route(kvm_state, msg, pci_dev);
- if (virq < 0) {
- perror("assigned_dev_update_msi: kvm_irqchip_add_msi_route");
- return;
- }
-
- assigned_dev->msi_virq = g_malloc(sizeof(*assigned_dev->msi_virq));
- assigned_dev->msi_virq_nr = 1;
- assigned_dev->msi_virq[0] = virq;
- if (kvm_device_msi_assign(kvm_state, assigned_dev->dev_id, virq) < 0) {
- perror("assigned_dev_update_msi: kvm_device_msi_assign");
- }
-
- assigned_dev->intx_route.mode = PCI_INTX_DISABLED;
- assigned_dev->intx_route.irq = -1;
- assigned_dev->assigned_irq_type = ASSIGNED_IRQ_MSI;
- } else {
- Error *local_err = NULL;
-
- assign_intx(assigned_dev, &local_err);
- if (local_err) {
- error_report_err(local_err);
- }
- }
-}
-
-static void assigned_dev_update_msi_msg(PCIDevice *pci_dev)
-{
- AssignedDevice *assigned_dev = PCI_ASSIGN(pci_dev);
- uint8_t ctrl_byte = pci_get_byte(pci_dev->config + pci_dev->msi_cap +
- PCI_MSI_FLAGS);
-
- if (assigned_dev->assigned_irq_type != ASSIGNED_IRQ_MSI ||
- !(ctrl_byte & PCI_MSI_FLAGS_ENABLE)) {
- return;
- }
-
- kvm_irqchip_update_msi_route(kvm_state, assigned_dev->msi_virq[0],
- msi_get_message(pci_dev, 0), pci_dev);
-}
-
-static bool assigned_dev_msix_masked(MSIXTableEntry *entry)
-{
- return (entry->ctrl & cpu_to_le32(0x1)) != 0;
-}
-
-/*
- * When MSI-X is first enabled the vector table typically has all the
- * vectors masked, so we can't use that as the obvious test to figure out
- * how many vectors to initially enable. Instead we look at the data field
- * because this is what worked for pci-assign for a long time. This makes
- * sure the physical MSI-X state tracks the guest's view, which is important
- * for some VF/PF and PF/fw communication channels.
- */
-static bool assigned_dev_msix_skipped(MSIXTableEntry *entry)
-{
- return !entry->data;
-}
-
-static int assigned_dev_update_msix_mmio(PCIDevice *pci_dev)
-{
- AssignedDevice *adev = PCI_ASSIGN(pci_dev);
- uint16_t entries_nr = 0;
- int i, r = 0;
- MSIXTableEntry *entry = adev->msix_table;
- MSIMessage msg;
-
- /* Get the usable entry number for allocating */
- for (i = 0; i < adev->msix_max; i++, entry++) {
- if (assigned_dev_msix_skipped(entry)) {
- continue;
- }
- entries_nr++;
- }
-
- DEBUG("MSI-X entries: %d\n", entries_nr);
-
- /* It's valid to enable MSI-X with all entries masked */
- if (!entries_nr) {
- return 0;
- }
-
- r = kvm_device_msix_init_vectors(kvm_state, adev->dev_id, entries_nr);
- if (r != 0) {
- error_report("fail to set MSI-X entry number for MSIX! %s",
- strerror(-r));
- return r;
- }
-
- free_msi_virqs(adev);
-
- adev->msi_virq_nr = adev->msix_max;
- adev->msi_virq = g_malloc(adev->msix_max * sizeof(*adev->msi_virq));
-
- entry = adev->msix_table;
- for (i = 0; i < adev->msix_max; i++, entry++) {
- adev->msi_virq[i] = -1;
-
- if (assigned_dev_msix_skipped(entry)) {
- continue;
- }
-
- msg.address = entry->addr_lo | ((uint64_t)entry->addr_hi << 32);
- msg.data = entry->data;
- r = kvm_irqchip_add_msi_route(kvm_state, msg, pci_dev);
- if (r < 0) {
- return r;
- }
- adev->msi_virq[i] = r;
-
- DEBUG("MSI-X vector %d, gsi %d, addr %08x_%08x, data %08x\n", i,
- r, entry->addr_hi, entry->addr_lo, entry->data);
-
- r = kvm_device_msix_set_vector(kvm_state, adev->dev_id, i,
- adev->msi_virq[i]);
- if (r) {
- error_report("fail to set MSI-X entry! %s", strerror(-r));
- break;
- }
- }
-
- return r;
-}
-
-static void assigned_dev_update_msix(PCIDevice *pci_dev)
-{
- AssignedDevice *assigned_dev = PCI_ASSIGN(pci_dev);
- uint16_t ctrl_word = pci_get_word(pci_dev->config + pci_dev->msix_cap +
- PCI_MSIX_FLAGS);
- int r;
-
- /* Some guests gratuitously disable MSIX even if they're not using it,
- * try to catch this by only deassigning irqs if the guest is using
- * MSIX or intends to start. */
- if ((assigned_dev->assigned_irq_type == ASSIGNED_IRQ_MSIX) ||
- (ctrl_word & PCI_MSIX_FLAGS_ENABLE)) {
- r = kvm_device_msix_deassign(kvm_state, assigned_dev->dev_id);
- /* -ENXIO means no assigned irq */
- if (r && r != -ENXIO) {
- perror("assigned_dev_update_msix: deassign irq");
- }
-
- free_msi_virqs(assigned_dev);
-
- assigned_dev->assigned_irq_type = ASSIGNED_IRQ_NONE;
- pci_device_set_intx_routing_notifier(pci_dev, NULL);
- }
-
- if (ctrl_word & PCI_MSIX_FLAGS_ENABLE) {
- if (assigned_dev_update_msix_mmio(pci_dev) < 0) {
- perror("assigned_dev_update_msix_mmio");
- return;
- }
-
- if (assigned_dev->msi_virq_nr > 0) {
- if (kvm_device_msix_assign(kvm_state, assigned_dev->dev_id) < 0) {
- perror("assigned_dev_enable_msix: assign irq");
- return;
- }
- }
- assigned_dev->intx_route.mode = PCI_INTX_DISABLED;
- assigned_dev->intx_route.irq = -1;
- assigned_dev->assigned_irq_type = ASSIGNED_IRQ_MSIX;
- } else {
- Error *local_err = NULL;
-
- assign_intx(assigned_dev, &local_err);
- if (local_err) {
- error_report_err(local_err);
- }
- }
-}
-
-static uint32_t assigned_dev_pci_read_config(PCIDevice *pci_dev,
- uint32_t address, int len)
-{
- AssignedDevice *assigned_dev = PCI_ASSIGN(pci_dev);
- uint32_t virt_val = pci_default_read_config(pci_dev, address, len);
- uint32_t real_val, emulate_mask, full_emulation_mask;
-
- emulate_mask = 0;
- memcpy(&emulate_mask, assigned_dev->emulate_config_read + address, len);
- emulate_mask = le32_to_cpu(emulate_mask);
-
- full_emulation_mask = 0xffffffff >> (32 - len * 8);
-
- if (emulate_mask != full_emulation_mask) {
- real_val = assigned_dev_pci_read(pci_dev, address, len);
- return (virt_val & emulate_mask) | (real_val & ~emulate_mask);
- } else {
- return virt_val;
- }
-}
-
-static void assigned_dev_pci_write_config(PCIDevice *pci_dev, uint32_t address,
- uint32_t val, int len)
-{
- AssignedDevice *assigned_dev = PCI_ASSIGN(pci_dev);
- uint16_t old_cmd = pci_get_word(pci_dev->config + PCI_COMMAND);
- uint32_t emulate_mask, full_emulation_mask;
- int ret;
-
- pci_default_write_config(pci_dev, address, val, len);
-
- if (kvm_has_intx_set_mask() &&
- range_covers_byte(address, len, PCI_COMMAND + 1)) {
- bool intx_masked = (pci_get_word(pci_dev->config + PCI_COMMAND) &
- PCI_COMMAND_INTX_DISABLE);
-
- if (intx_masked != !!(old_cmd & PCI_COMMAND_INTX_DISABLE)) {
- ret = kvm_device_intx_set_mask(kvm_state, assigned_dev->dev_id,
- intx_masked);
- if (ret) {
- perror("assigned_dev_pci_write_config: set intx mask");
- }
- }
- }
- if (assigned_dev->cap.available & ASSIGNED_DEVICE_CAP_MSI) {
- if (range_covers_byte(address, len,
- pci_dev->msi_cap + PCI_MSI_FLAGS)) {
- assigned_dev_update_msi(pci_dev);
- } else if (ranges_overlap(address, len, /* 32bit MSI only */
- pci_dev->msi_cap + PCI_MSI_ADDRESS_LO, 6)) {
- assigned_dev_update_msi_msg(pci_dev);
- }
- }
- if (assigned_dev->cap.available & ASSIGNED_DEVICE_CAP_MSIX) {
- if (range_covers_byte(address, len,
- pci_dev->msix_cap + PCI_MSIX_FLAGS + 1)) {
- assigned_dev_update_msix(pci_dev);
- }
- }
-
- emulate_mask = 0;
- memcpy(&emulate_mask, assigned_dev->emulate_config_write + address, len);
- emulate_mask = le32_to_cpu(emulate_mask);
-
- full_emulation_mask = 0xffffffff >> (32 - len * 8);
-
- if (emulate_mask != full_emulation_mask) {
- if (emulate_mask) {
- val &= ~emulate_mask;
- val |= assigned_dev_pci_read(pci_dev, address, len) & emulate_mask;
- }
- assigned_dev_pci_write(pci_dev, address, val, len);
- }
-}
-
-static void assigned_dev_setup_cap_read(AssignedDevice *dev, uint32_t offset,
- uint32_t len)
-{
- assigned_dev_direct_config_read(dev, offset, len);
- assigned_dev_emulate_config_read(dev, offset + PCI_CAP_LIST_NEXT, 1);
-}
-
-static int assigned_device_pci_cap_init(PCIDevice *pci_dev, Error **errp)
-{
- AssignedDevice *dev = PCI_ASSIGN(pci_dev);
- PCIRegion *pci_region = dev->real_device.regions;
- int ret, pos;
- Error *local_err = NULL;
-
- /* Clear initial capabilities pointer and status copied from hw */
- pci_set_byte(pci_dev->config + PCI_CAPABILITY_LIST, 0);
- pci_set_word(pci_dev->config + PCI_STATUS,
- pci_get_word(pci_dev->config + PCI_STATUS) &
- ~PCI_STATUS_CAP_LIST);
-
- /* Expose MSI capability
- * MSI capability is the 1st capability in capability config */
- pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_MSI, 0);
- if (pos != 0 && kvm_check_extension(kvm_state, KVM_CAP_ASSIGN_DEV_IRQ)) {
- verify_irqchip_in_kernel(&local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return -ENOTSUP;
- }
- dev->cap.available |= ASSIGNED_DEVICE_CAP_MSI;
- /* Only 32-bit/no-mask currently supported */
- ret = pci_add_capability2(pci_dev, PCI_CAP_ID_MSI, pos, 10,
- &local_err);
- if (ret < 0) {
- error_propagate(errp, local_err);
- return ret;
- }
- pci_dev->msi_cap = pos;
-
- pci_set_word(pci_dev->config + pos + PCI_MSI_FLAGS,
- pci_get_word(pci_dev->config + pos + PCI_MSI_FLAGS) &
- PCI_MSI_FLAGS_QMASK);
- pci_set_long(pci_dev->config + pos + PCI_MSI_ADDRESS_LO, 0);
- pci_set_word(pci_dev->config + pos + PCI_MSI_DATA_32, 0);
-
- /* Set writable fields */
- pci_set_word(pci_dev->wmask + pos + PCI_MSI_FLAGS,
- PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE);
- pci_set_long(pci_dev->wmask + pos + PCI_MSI_ADDRESS_LO, 0xfffffffc);
- pci_set_word(pci_dev->wmask + pos + PCI_MSI_DATA_32, 0xffff);
- }
- /* Expose MSI-X capability */
- pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_MSIX, 0);
- if (pos != 0 && kvm_device_msix_supported(kvm_state)) {
- int bar_nr;
- uint32_t msix_table_entry;
- uint16_t msix_max;
-
- verify_irqchip_in_kernel(&local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return -ENOTSUP;
- }
- dev->cap.available |= ASSIGNED_DEVICE_CAP_MSIX;
- ret = pci_add_capability2(pci_dev, PCI_CAP_ID_MSIX, pos, 12,
- &local_err);
- if (ret < 0) {
- error_propagate(errp, local_err);
- return ret;
- }
- pci_dev->msix_cap = pos;
-
- msix_max = (pci_get_word(pci_dev->config + pos + PCI_MSIX_FLAGS) &
- PCI_MSIX_FLAGS_QSIZE) + 1;
- msix_max = MIN(msix_max, KVM_MAX_MSIX_PER_DEV);
- pci_set_word(pci_dev->config + pos + PCI_MSIX_FLAGS, msix_max - 1);
-
- /* Only enable and function mask bits are writable */
- pci_set_word(pci_dev->wmask + pos + PCI_MSIX_FLAGS,
- PCI_MSIX_FLAGS_ENABLE | PCI_MSIX_FLAGS_MASKALL);
-
- msix_table_entry = pci_get_long(pci_dev->config + pos + PCI_MSIX_TABLE);
- bar_nr = msix_table_entry & PCI_MSIX_FLAGS_BIRMASK;
- msix_table_entry &= ~PCI_MSIX_FLAGS_BIRMASK;
- dev->msix_table_addr = pci_region[bar_nr].base_addr + msix_table_entry;
- dev->msix_max = msix_max;
- }
-
- /* Minimal PM support, nothing writable, device appears to NAK changes */
- pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_PM, 0);
- if (pos) {
- uint16_t pmc;
-
- ret = pci_add_capability2(pci_dev, PCI_CAP_ID_PM, pos, PCI_PM_SIZEOF,
- &local_err);
- if (ret < 0) {
- error_propagate(errp, local_err);
- return ret;
- }
-
- assigned_dev_setup_cap_read(dev, pos, PCI_PM_SIZEOF);
-
- pmc = pci_get_word(pci_dev->config + pos + PCI_CAP_FLAGS);
- pmc &= (PCI_PM_CAP_VER_MASK | PCI_PM_CAP_DSI);
- pci_set_word(pci_dev->config + pos + PCI_CAP_FLAGS, pmc);
-
- /* assign_device will bring the device up to D0, so we don't need
- * to worry about doing that ourselves here. */
- pci_set_word(pci_dev->config + pos + PCI_PM_CTRL,
- PCI_PM_CTRL_NO_SOFT_RESET);
-
- pci_set_byte(pci_dev->config + pos + PCI_PM_PPB_EXTENSIONS, 0);
- pci_set_byte(pci_dev->config + pos + PCI_PM_DATA_REGISTER, 0);
- }
-
- pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_EXP, 0);
- if (pos) {
- uint8_t version, size = 0;
- uint16_t type, devctl, lnksta;
- uint32_t devcap, lnkcap;
-
- version = pci_get_byte(pci_dev->config + pos + PCI_EXP_FLAGS);
- version &= PCI_EXP_FLAGS_VERS;
- if (version == 1) {
- size = 0x14;
- } else if (version == 2) {
- /*
- * Check for non-std size, accept reduced size to 0x34,
- * which is what bcm5761 implemented, violating the
- * PCIe v3.0 spec that regs should exist and be read as 0,
- * not optionally provided and shorten the struct size.
- */
- size = MIN(0x3c, PCI_CONFIG_SPACE_SIZE - pos);
- if (size < 0x34) {
- error_setg(errp, "Invalid size PCIe cap-id 0x%x",
- PCI_CAP_ID_EXP);
- return -EINVAL;
- } else if (size != 0x3c) {
- error_report("WARNING, %s: PCIe cap-id 0x%x has "
- "non-standard size 0x%x; std size should be 0x3c",
- __func__, PCI_CAP_ID_EXP, size);
- }
- } else if (version == 0) {
- uint16_t vid, did;
- vid = pci_get_word(pci_dev->config + PCI_VENDOR_ID);
- did = pci_get_word(pci_dev->config + PCI_DEVICE_ID);
- if (vid == PCI_VENDOR_ID_INTEL && did == 0x10ed) {
- /*
- * quirk for Intel 82599 VF with invalid PCIe capability
- * version, should really be version 2 (same as PF)
- */
- size = 0x3c;
- }
- }
-
- if (size == 0) {
- error_setg(errp, "Unsupported PCI express capability version %d",
- version);
- return -EINVAL;
- }
-
- ret = pci_add_capability2(pci_dev, PCI_CAP_ID_EXP, pos, size,
- &local_err);
- if (ret < 0) {
- error_propagate(errp, local_err);
- return ret;
- }
-
- assigned_dev_setup_cap_read(dev, pos, size);
-
- type = pci_get_word(pci_dev->config + pos + PCI_EXP_FLAGS);
- type = (type & PCI_EXP_FLAGS_TYPE) >> 4;
- if (type != PCI_EXP_TYPE_ENDPOINT &&
- type != PCI_EXP_TYPE_LEG_END && type != PCI_EXP_TYPE_RC_END) {
- error_setg(errp, "Device assignment only supports endpoint "
- "assignment, device type %d", type);
- return -EINVAL;
- }
-
- /* capabilities, pass existing read-only copy
- * PCI_EXP_FLAGS_IRQ: updated by hardware, should be direct read */
-
- /* device capabilities: hide FLR */
- devcap = pci_get_long(pci_dev->config + pos + PCI_EXP_DEVCAP);
- devcap &= ~PCI_EXP_DEVCAP_FLR;
- pci_set_long(pci_dev->config + pos + PCI_EXP_DEVCAP, devcap);
-
- /* device control: clear all error reporting enable bits, leaving
- * only a few host values. Note, these are
- * all writable, but not passed to hw.
- */
- devctl = pci_get_word(pci_dev->config + pos + PCI_EXP_DEVCTL);
- devctl = (devctl & (PCI_EXP_DEVCTL_READRQ | PCI_EXP_DEVCTL_PAYLOAD)) |
- PCI_EXP_DEVCTL_RELAX_EN | PCI_EXP_DEVCTL_NOSNOOP_EN;
- pci_set_word(pci_dev->config + pos + PCI_EXP_DEVCTL, devctl);
- devctl = PCI_EXP_DEVCTL_BCR_FLR | PCI_EXP_DEVCTL_AUX_PME;
- pci_set_word(pci_dev->wmask + pos + PCI_EXP_DEVCTL, ~devctl);
-
- /* Clear device status */
- pci_set_word(pci_dev->config + pos + PCI_EXP_DEVSTA, 0);
-
- /* Link capabilities, expose links and latencues, clear reporting */
- lnkcap = pci_get_long(pci_dev->config + pos + PCI_EXP_LNKCAP);
- lnkcap &= (PCI_EXP_LNKCAP_SLS | PCI_EXP_LNKCAP_MLW |
- PCI_EXP_LNKCAP_ASPMS | PCI_EXP_LNKCAP_L0SEL |
- PCI_EXP_LNKCAP_L1EL);
- pci_set_long(pci_dev->config + pos + PCI_EXP_LNKCAP, lnkcap);
-
- /* Link control, pass existing read-only copy. Should be writable? */
-
- /* Link status, only expose current speed and width */
- lnksta = pci_get_word(pci_dev->config + pos + PCI_EXP_LNKSTA);
- lnksta &= (PCI_EXP_LNKSTA_CLS | PCI_EXP_LNKSTA_NLW);
- pci_set_word(pci_dev->config + pos + PCI_EXP_LNKSTA, lnksta);
-
- if (version >= 2) {
- /* Slot capabilities, control, status - not needed for endpoints */
- pci_set_long(pci_dev->config + pos + PCI_EXP_SLTCAP, 0);
- pci_set_word(pci_dev->config + pos + PCI_EXP_SLTCTL, 0);
- pci_set_word(pci_dev->config + pos + PCI_EXP_SLTSTA, 0);
-
- /* Root control, capabilities, status - not needed for endpoints */
- pci_set_word(pci_dev->config + pos + PCI_EXP_RTCTL, 0);
- pci_set_word(pci_dev->config + pos + PCI_EXP_RTCAP, 0);
- pci_set_long(pci_dev->config + pos + PCI_EXP_RTSTA, 0);
-
- /* Device capabilities/control 2, pass existing read-only copy */
- /* Link control 2, pass existing read-only copy */
- }
- }
-
- pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_PCIX, 0);
- if (pos) {
- uint16_t cmd;
- uint32_t status;
-
- /* Only expose the minimum, 8 byte capability */
- ret = pci_add_capability2(pci_dev, PCI_CAP_ID_PCIX, pos, 8,
- &local_err);
- if (ret < 0) {
- error_propagate(errp, local_err);
- return ret;
- }
-
- assigned_dev_setup_cap_read(dev, pos, 8);
-
- /* Command register, clear upper bits, including extended modes */
- cmd = pci_get_word(pci_dev->config + pos + PCI_X_CMD);
- cmd &= (PCI_X_CMD_DPERR_E | PCI_X_CMD_ERO | PCI_X_CMD_MAX_READ |
- PCI_X_CMD_MAX_SPLIT);
- pci_set_word(pci_dev->config + pos + PCI_X_CMD, cmd);
-
- /* Status register, update with emulated PCI bus location, clear
- * error bits, leave the rest. */
- status = pci_get_long(pci_dev->config + pos + PCI_X_STATUS);
- status &= ~(PCI_X_STATUS_BUS | PCI_X_STATUS_DEVFN);
- status |= pci_requester_id(pci_dev);
- status &= ~(PCI_X_STATUS_SPL_DISC | PCI_X_STATUS_UNX_SPL |
- PCI_X_STATUS_SPL_ERR);
- pci_set_long(pci_dev->config + pos + PCI_X_STATUS, status);
- }
-
- pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_VPD, 0);
- if (pos) {
- /* Direct R/W passthrough */
- ret = pci_add_capability2(pci_dev, PCI_CAP_ID_VPD, pos, 8,
- &local_err);
- if (ret < 0) {
- error_propagate(errp, local_err);
- return ret;
- }
-
- assigned_dev_setup_cap_read(dev, pos, 8);
-
- /* direct write for cap content */
- assigned_dev_direct_config_write(dev, pos + 2, 6);
- }
-
- /* Devices can have multiple vendor capabilities, get them all */
- for (pos = 0; (pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_VNDR, pos));
- pos += PCI_CAP_LIST_NEXT) {
- uint8_t len = pci_get_byte(pci_dev->config + pos + PCI_CAP_FLAGS);
- /* Direct R/W passthrough */
- ret = pci_add_capability2(pci_dev, PCI_CAP_ID_VNDR, pos, len,
- &local_err);
- if (ret < 0) {
- error_propagate(errp, local_err);
- return ret;
- }
-
- assigned_dev_setup_cap_read(dev, pos, len);
-
- /* direct write for cap content */
- assigned_dev_direct_config_write(dev, pos + 2, len - 2);
- }
-
- /* If real and virtual capability list status bits differ, virtualize the
- * access. */
- if ((pci_get_word(pci_dev->config + PCI_STATUS) & PCI_STATUS_CAP_LIST) !=
- (assigned_dev_pci_read_byte(pci_dev, PCI_STATUS) &
- PCI_STATUS_CAP_LIST)) {
- dev->emulate_config_read[PCI_STATUS] |= PCI_STATUS_CAP_LIST;
- }
-
- return 0;
-}
-
-static uint64_t
-assigned_dev_msix_mmio_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- AssignedDevice *adev = opaque;
- uint64_t val;
-
- memcpy(&val, (void *)((uint8_t *)adev->msix_table + addr), size);
-
- return val;
-}
-
-static void assigned_dev_msix_mmio_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- AssignedDevice *adev = opaque;
- PCIDevice *pdev = &adev->dev;
- uint16_t ctrl;
- MSIXTableEntry orig;
- int i = addr >> 4;
-
- if (i >= adev->msix_max) {
- return; /* Drop write */
- }
-
- ctrl = pci_get_word(pdev->config + pdev->msix_cap + PCI_MSIX_FLAGS);
-
- DEBUG("write to MSI-X table offset 0x%lx, val 0x%lx\n", addr, val);
-
- if (ctrl & PCI_MSIX_FLAGS_ENABLE) {
- orig = adev->msix_table[i];
- }
-
- memcpy((uint8_t *)adev->msix_table + addr, &val, size);
-
- if (ctrl & PCI_MSIX_FLAGS_ENABLE) {
- MSIXTableEntry *entry = &adev->msix_table[i];
-
- if (!assigned_dev_msix_masked(&orig) &&
- assigned_dev_msix_masked(entry)) {
- /*
- * Vector masked, disable it
- *
- * XXX It's not clear if we can or should actually attempt
- * to mask or disable the interrupt. KVM doesn't have
- * support for pending bits and kvm_assign_set_msix_entry
- * doesn't modify the device hardware mask. Interrupts
- * while masked are simply not injected to the guest, so
- * are lost. Can we get away with always injecting an
- * interrupt on unmask?
- */
- } else if (assigned_dev_msix_masked(&orig) &&
- !assigned_dev_msix_masked(entry)) {
- /* Vector unmasked */
- if (i >= adev->msi_virq_nr || adev->msi_virq[i] < 0) {
- /* Previously unassigned vector, start from scratch */
- assigned_dev_update_msix(pdev);
- return;
- } else {
- /* Update an existing, previously masked vector */
- MSIMessage msg;
- int ret;
-
- msg.address = entry->addr_lo |
- ((uint64_t)entry->addr_hi << 32);
- msg.data = entry->data;
-
- ret = kvm_irqchip_update_msi_route(kvm_state,
- adev->msi_virq[i], msg,
- pdev);
- if (ret) {
- error_report("Error updating irq routing entry (%d)", ret);
- }
- }
- }
- }
-}
-
-static const MemoryRegionOps assigned_dev_msix_mmio_ops = {
- .read = assigned_dev_msix_mmio_read,
- .write = assigned_dev_msix_mmio_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 8,
- },
- .impl = {
- .min_access_size = 4,
- .max_access_size = 8,
- },
-};
-
-static void assigned_dev_msix_reset(AssignedDevice *dev)
-{
- MSIXTableEntry *entry;
- int i;
-
- if (!dev->msix_table) {
- return;
- }
-
- memset(dev->msix_table, 0, MSIX_PAGE_SIZE);
-
- for (i = 0, entry = dev->msix_table; i < dev->msix_max; i++, entry++) {
- entry->ctrl = cpu_to_le32(0x1); /* Masked */
- }
-}
-
-static void assigned_dev_register_msix_mmio(AssignedDevice *dev, Error **errp)
-{
- dev->msix_table = mmap(NULL, MSIX_PAGE_SIZE, PROT_READ|PROT_WRITE,
- MAP_ANONYMOUS|MAP_PRIVATE, 0, 0);
- if (dev->msix_table == MAP_FAILED) {
- error_setg_errno(errp, errno, "failed to allocate msix_table");
- dev->msix_table = NULL;
- return;
- }
-
- assigned_dev_msix_reset(dev);
-
- memory_region_init_io(&dev->mmio, OBJECT(dev), &assigned_dev_msix_mmio_ops,
- dev, "assigned-dev-msix", MSIX_PAGE_SIZE);
-}
-
-static void assigned_dev_unregister_msix_mmio(AssignedDevice *dev)
-{
- if (!dev->msix_table) {
- return;
- }
-
- if (munmap(dev->msix_table, MSIX_PAGE_SIZE) == -1) {
- error_report("error unmapping msix_table! %s", strerror(errno));
- }
- dev->msix_table = NULL;
-}
-
-static const VMStateDescription vmstate_assigned_device = {
- .name = "pci-assign",
- .unmigratable = 1,
-};
-
-static void reset_assigned_device(DeviceState *dev)
-{
- PCIDevice *pci_dev = PCI_DEVICE(dev);
- AssignedDevice *adev = PCI_ASSIGN(pci_dev);
- char reset_file[64];
- const char reset[] = "1";
- int fd, ret;
-
- /*
- * If a guest is reset without being shutdown, MSI/MSI-X can still
- * be running. We want to return the device to a known state on
- * reset, so disable those here. We especially do not want MSI-X
- * enabled since it lives in MMIO space, which is about to get
- * disabled.
- */
- if (adev->assigned_irq_type == ASSIGNED_IRQ_MSIX) {
- uint16_t ctrl = pci_get_word(pci_dev->config +
- pci_dev->msix_cap + PCI_MSIX_FLAGS);
-
- pci_set_word(pci_dev->config + pci_dev->msix_cap + PCI_MSIX_FLAGS,
- ctrl & ~PCI_MSIX_FLAGS_ENABLE);
- assigned_dev_update_msix(pci_dev);
- } else if (adev->assigned_irq_type == ASSIGNED_IRQ_MSI) {
- uint8_t ctrl = pci_get_byte(pci_dev->config +
- pci_dev->msi_cap + PCI_MSI_FLAGS);
-
- pci_set_byte(pci_dev->config + pci_dev->msi_cap + PCI_MSI_FLAGS,
- ctrl & ~PCI_MSI_FLAGS_ENABLE);
- assigned_dev_update_msi(pci_dev);
- }
-
- snprintf(reset_file, sizeof(reset_file),
- "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/reset",
- adev->host.domain, adev->host.bus, adev->host.slot,
- adev->host.function);
-
- /*
- * Issue a device reset via pci-sysfs. Note that we use write(2) here
- * and ignore the return value because some kernels have a bug that
- * returns 0 rather than bytes written on success, sending us into an
- * infinite retry loop using other write mechanisms.
- */
- fd = open(reset_file, O_WRONLY);
- if (fd != -1) {
- ret = write(fd, reset, strlen(reset));
- (void)ret;
- close(fd);
- }
-
- /*
- * When a 0 is written to the bus master register, the device is logically
- * disconnected from the PCI bus. This avoids further DMA transfers.
- */
- assigned_dev_pci_write_config(pci_dev, PCI_COMMAND, 0, 1);
-}
-
-static void assigned_realize(struct PCIDevice *pci_dev, Error **errp)
-{
- AssignedDevice *dev = PCI_ASSIGN(pci_dev);
- uint8_t e_intx;
- int r;
- Error *local_err = NULL;
-
- if (!kvm_enabled()) {
- error_setg(&local_err, "pci-assign requires KVM support");
- goto exit_with_error;
- }
-
- if (!dev->host.domain && !dev->host.bus && !dev->host.slot &&
- !dev->host.function) {
- error_setg(&local_err, "no host device specified");
- goto exit_with_error;
- }
-
- /*
- * Set up basic config space access control. Will be further refined during
- * device initialization.
- */
- assigned_dev_emulate_config_read(dev, 0, PCI_CONFIG_SPACE_SIZE);
- assigned_dev_direct_config_read(dev, PCI_STATUS, 2);
- assigned_dev_direct_config_read(dev, PCI_REVISION_ID, 1);
- assigned_dev_direct_config_read(dev, PCI_CLASS_PROG, 3);
- assigned_dev_direct_config_read(dev, PCI_CACHE_LINE_SIZE, 1);
- assigned_dev_direct_config_read(dev, PCI_LATENCY_TIMER, 1);
- assigned_dev_direct_config_read(dev, PCI_BIST, 1);
- assigned_dev_direct_config_read(dev, PCI_CARDBUS_CIS, 4);
- assigned_dev_direct_config_read(dev, PCI_SUBSYSTEM_VENDOR_ID, 2);
- assigned_dev_direct_config_read(dev, PCI_SUBSYSTEM_ID, 2);
- assigned_dev_direct_config_read(dev, PCI_CAPABILITY_LIST + 1, 7);
- assigned_dev_direct_config_read(dev, PCI_MIN_GNT, 1);
- assigned_dev_direct_config_read(dev, PCI_MAX_LAT, 1);
- memcpy(dev->emulate_config_write, dev->emulate_config_read,
- sizeof(dev->emulate_config_read));
-
- get_real_device(dev, &local_err);
- if (local_err) {
- goto out;
- }
-
- if (assigned_device_pci_cap_init(pci_dev, &local_err) < 0) {
- goto out;
- }
-
- /* intercept MSI-X entry page in the MMIO */
- if (dev->cap.available & ASSIGNED_DEVICE_CAP_MSIX) {
- assigned_dev_register_msix_mmio(dev, &local_err);
- if (local_err) {
- goto out;
- }
- }
-
- /* handle real device's MMIO/PIO BARs */
- assigned_dev_register_regions(dev->real_device.regions,
- dev->real_device.region_number, dev,
- &local_err);
- if (local_err) {
- goto out;
- }
-
- /* handle interrupt routing */
- e_intx = dev->dev.config[PCI_INTERRUPT_PIN] - 1;
- dev->intpin = e_intx;
- dev->intx_route.mode = PCI_INTX_DISABLED;
- dev->intx_route.irq = -1;
-
- /* assign device to guest */
- assign_device(dev, &local_err);
- if (local_err) {
- goto out;
- }
-
- /* assign legacy INTx to the device */
- r = assign_intx(dev, &local_err);
- if (r < 0) {
- goto assigned_out;
- }
-
- assigned_dev_load_option_rom(dev);
-
- return;
-
-assigned_out:
- deassign_device(dev);
-
-out:
- free_assigned_device(dev);
-
-exit_with_error:
- assert(local_err);
- error_propagate(errp, local_err);
-}
-
-static void assigned_exitfn(struct PCIDevice *pci_dev)
-{
- AssignedDevice *dev = PCI_ASSIGN(pci_dev);
-
- deassign_device(dev);
- free_assigned_device(dev);
-}
-
-static void assigned_dev_instance_init(Object *obj)
-{
- PCIDevice *pci_dev = PCI_DEVICE(obj);
- AssignedDevice *d = PCI_ASSIGN(pci_dev);
-
- device_add_bootindex_property(obj, &d->bootindex,
- "bootindex", NULL,
- &pci_dev->qdev, NULL);
-}
-
-static Property assigned_dev_properties[] = {
- DEFINE_PROP_PCI_HOST_DEVADDR("host", AssignedDevice, host),
- DEFINE_PROP_BIT("prefer_msi", AssignedDevice, features,
- ASSIGNED_DEVICE_PREFER_MSI_BIT, false),
- DEFINE_PROP_BIT("share_intx", AssignedDevice, features,
- ASSIGNED_DEVICE_SHARE_INTX_BIT, true),
- DEFINE_PROP_STRING("configfd", AssignedDevice, configfd_name),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void assign_class_init(ObjectClass *klass, void *data)
-{
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- k->realize = assigned_realize;
- k->exit = assigned_exitfn;
- k->config_read = assigned_dev_pci_read_config;
- k->config_write = assigned_dev_pci_write_config;
- dc->props = assigned_dev_properties;
- dc->vmsd = &vmstate_assigned_device;
- dc->reset = reset_assigned_device;
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- dc->desc = "KVM-based PCI passthrough";
-}
-
-static const TypeInfo assign_info = {
- .name = TYPE_PCI_ASSIGN,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(AssignedDevice),
- .class_init = assign_class_init,
- .instance_init = assigned_dev_instance_init,
-};
-
-static void assign_register_types(void)
-{
- type_register_static(&assign_info);
-}
-
-type_init(assign_register_types)
-
-static void assigned_dev_load_option_rom(AssignedDevice *dev)
-{
- int size = 0;
-
- pci_assign_dev_load_option_rom(&dev->dev, OBJECT(dev), &size,
- dev->host.domain, dev->host.bus,
- dev->host.slot, dev->host.function);
-
- if (!size) {
- error_report("pci-assign: Invalid ROM.");
- }
-}
diff --git a/qemu/hw/i386/kvmvapic.c b/qemu/hw/i386/kvmvapic.c
deleted file mode 100644
index c69f37404..000000000
--- a/qemu/hw/i386/kvmvapic.c
+++ /dev/null
@@ -1,866 +0,0 @@
-/*
- * TPR optimization for 32-bit Windows guests (XP and Server 2003)
- *
- * Copyright (C) 2007-2008 Qumranet Technologies
- * Copyright (C) 2012 Jan Kiszka, Siemens AG
- *
- * This work is licensed under the terms of the GNU GPL version 2, or
- * (at your option) any later version. See the COPYING file in the
- * top-level directory.
- */
-#include "qemu/osdep.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/cpus.h"
-#include "sysemu/kvm.h"
-#include "hw/i386/apic_internal.h"
-#include "hw/sysbus.h"
-
-#define VAPIC_IO_PORT 0x7e
-
-#define VAPIC_CPU_SHIFT 7
-
-#define ROM_BLOCK_SIZE 512
-#define ROM_BLOCK_MASK (~(ROM_BLOCK_SIZE - 1))
-
-typedef enum VAPICMode {
- VAPIC_INACTIVE = 0,
- VAPIC_ACTIVE = 1,
- VAPIC_STANDBY = 2,
-} VAPICMode;
-
-typedef struct VAPICHandlers {
- uint32_t set_tpr;
- uint32_t set_tpr_eax;
- uint32_t get_tpr[8];
- uint32_t get_tpr_stack;
-} QEMU_PACKED VAPICHandlers;
-
-typedef struct GuestROMState {
- char signature[8];
- uint32_t vaddr;
- uint32_t fixup_start;
- uint32_t fixup_end;
- uint32_t vapic_vaddr;
- uint32_t vapic_size;
- uint32_t vcpu_shift;
- uint32_t real_tpr_addr;
- VAPICHandlers up;
- VAPICHandlers mp;
-} QEMU_PACKED GuestROMState;
-
-typedef struct VAPICROMState {
- SysBusDevice busdev;
- MemoryRegion io;
- MemoryRegion rom;
- uint32_t state;
- uint32_t rom_state_paddr;
- uint32_t rom_state_vaddr;
- uint32_t vapic_paddr;
- uint32_t real_tpr_addr;
- GuestROMState rom_state;
- size_t rom_size;
- bool rom_mapped_writable;
- VMChangeStateEntry *vmsentry;
-} VAPICROMState;
-
-#define TYPE_VAPIC "kvmvapic"
-#define VAPIC(obj) OBJECT_CHECK(VAPICROMState, (obj), TYPE_VAPIC)
-
-#define TPR_INSTR_ABS_MODRM 0x1
-#define TPR_INSTR_MATCH_MODRM_REG 0x2
-
-typedef struct TPRInstruction {
- uint8_t opcode;
- uint8_t modrm_reg;
- unsigned int flags;
- TPRAccess access;
- size_t length;
- off_t addr_offset;
-} TPRInstruction;
-
-/* must be sorted by length, shortest first */
-static const TPRInstruction tpr_instr[] = {
- { /* mov abs to eax */
- .opcode = 0xa1,
- .access = TPR_ACCESS_READ,
- .length = 5,
- .addr_offset = 1,
- },
- { /* mov eax to abs */
- .opcode = 0xa3,
- .access = TPR_ACCESS_WRITE,
- .length = 5,
- .addr_offset = 1,
- },
- { /* mov r32 to r/m32 */
- .opcode = 0x89,
- .flags = TPR_INSTR_ABS_MODRM,
- .access = TPR_ACCESS_WRITE,
- .length = 6,
- .addr_offset = 2,
- },
- { /* mov r/m32 to r32 */
- .opcode = 0x8b,
- .flags = TPR_INSTR_ABS_MODRM,
- .access = TPR_ACCESS_READ,
- .length = 6,
- .addr_offset = 2,
- },
- { /* push r/m32 */
- .opcode = 0xff,
- .modrm_reg = 6,
- .flags = TPR_INSTR_ABS_MODRM | TPR_INSTR_MATCH_MODRM_REG,
- .access = TPR_ACCESS_READ,
- .length = 6,
- .addr_offset = 2,
- },
- { /* mov imm32, r/m32 (c7/0) */
- .opcode = 0xc7,
- .modrm_reg = 0,
- .flags = TPR_INSTR_ABS_MODRM | TPR_INSTR_MATCH_MODRM_REG,
- .access = TPR_ACCESS_WRITE,
- .length = 10,
- .addr_offset = 2,
- },
-};
-
-static void read_guest_rom_state(VAPICROMState *s)
-{
- cpu_physical_memory_read(s->rom_state_paddr, &s->rom_state,
- sizeof(GuestROMState));
-}
-
-static void write_guest_rom_state(VAPICROMState *s)
-{
- cpu_physical_memory_write(s->rom_state_paddr, &s->rom_state,
- sizeof(GuestROMState));
-}
-
-static void update_guest_rom_state(VAPICROMState *s)
-{
- read_guest_rom_state(s);
-
- s->rom_state.real_tpr_addr = cpu_to_le32(s->real_tpr_addr);
- s->rom_state.vcpu_shift = cpu_to_le32(VAPIC_CPU_SHIFT);
-
- write_guest_rom_state(s);
-}
-
-static int find_real_tpr_addr(VAPICROMState *s, CPUX86State *env)
-{
- CPUState *cs = CPU(x86_env_get_cpu(env));
- hwaddr paddr;
- target_ulong addr;
-
- if (s->state == VAPIC_ACTIVE) {
- return 0;
- }
- /*
- * If there is no prior TPR access instruction we could analyze (which is
- * the case after resume from hibernation), we need to scan the possible
- * virtual address space for the APIC mapping.
- */
- for (addr = 0xfffff000; addr >= 0x80000000; addr -= TARGET_PAGE_SIZE) {
- paddr = cpu_get_phys_page_debug(cs, addr);
- if (paddr != APIC_DEFAULT_ADDRESS) {
- continue;
- }
- s->real_tpr_addr = addr + 0x80;
- update_guest_rom_state(s);
- return 0;
- }
- return -1;
-}
-
-static uint8_t modrm_reg(uint8_t modrm)
-{
- return (modrm >> 3) & 7;
-}
-
-static bool is_abs_modrm(uint8_t modrm)
-{
- return (modrm & 0xc7) == 0x05;
-}
-
-static bool opcode_matches(uint8_t *opcode, const TPRInstruction *instr)
-{
- return opcode[0] == instr->opcode &&
- (!(instr->flags & TPR_INSTR_ABS_MODRM) || is_abs_modrm(opcode[1])) &&
- (!(instr->flags & TPR_INSTR_MATCH_MODRM_REG) ||
- modrm_reg(opcode[1]) == instr->modrm_reg);
-}
-
-static int evaluate_tpr_instruction(VAPICROMState *s, X86CPU *cpu,
- target_ulong *pip, TPRAccess access)
-{
- CPUState *cs = CPU(cpu);
- const TPRInstruction *instr;
- target_ulong ip = *pip;
- uint8_t opcode[2];
- uint32_t real_tpr_addr;
- int i;
-
- if ((ip & 0xf0000000ULL) != 0x80000000ULL &&
- (ip & 0xf0000000ULL) != 0xe0000000ULL) {
- return -1;
- }
-
- /*
- * Early Windows 2003 SMP initialization contains a
- *
- * mov imm32, r/m32
- *
- * instruction that is patched by TPR optimization. The problem is that
- * RSP, used by the patched instruction, is zero, so the guest gets a
- * double fault and dies.
- */
- if (cpu->env.regs[R_ESP] == 0) {
- return -1;
- }
-
- if (kvm_enabled() && !kvm_irqchip_in_kernel()) {
- /*
- * KVM without kernel-based TPR access reporting will pass an IP that
- * points after the accessing instruction. So we need to look backward
- * to find the reason.
- */
- for (i = 0; i < ARRAY_SIZE(tpr_instr); i++) {
- instr = &tpr_instr[i];
- if (instr->access != access) {
- continue;
- }
- if (cpu_memory_rw_debug(cs, ip - instr->length, opcode,
- sizeof(opcode), 0) < 0) {
- return -1;
- }
- if (opcode_matches(opcode, instr)) {
- ip -= instr->length;
- goto instruction_ok;
- }
- }
- return -1;
- } else {
- if (cpu_memory_rw_debug(cs, ip, opcode, sizeof(opcode), 0) < 0) {
- return -1;
- }
- for (i = 0; i < ARRAY_SIZE(tpr_instr); i++) {
- instr = &tpr_instr[i];
- if (opcode_matches(opcode, instr)) {
- goto instruction_ok;
- }
- }
- return -1;
- }
-
-instruction_ok:
- /*
- * Grab the virtual TPR address from the instruction
- * and update the cached values.
- */
- if (cpu_memory_rw_debug(cs, ip + instr->addr_offset,
- (void *)&real_tpr_addr,
- sizeof(real_tpr_addr), 0) < 0) {
- return -1;
- }
- real_tpr_addr = le32_to_cpu(real_tpr_addr);
- if ((real_tpr_addr & 0xfff) != 0x80) {
- return -1;
- }
- s->real_tpr_addr = real_tpr_addr;
- update_guest_rom_state(s);
-
- *pip = ip;
- return 0;
-}
-
-static int update_rom_mapping(VAPICROMState *s, CPUX86State *env, target_ulong ip)
-{
- CPUState *cs = CPU(x86_env_get_cpu(env));
- hwaddr paddr;
- uint32_t rom_state_vaddr;
- uint32_t pos, patch, offset;
-
- /* nothing to do if already activated */
- if (s->state == VAPIC_ACTIVE) {
- return 0;
- }
-
- /* bail out if ROM init code was not executed (missing ROM?) */
- if (s->state == VAPIC_INACTIVE) {
- return -1;
- }
-
- /* find out virtual address of the ROM */
- rom_state_vaddr = s->rom_state_paddr + (ip & 0xf0000000);
- paddr = cpu_get_phys_page_debug(cs, rom_state_vaddr);
- if (paddr == -1) {
- return -1;
- }
- paddr += rom_state_vaddr & ~TARGET_PAGE_MASK;
- if (paddr != s->rom_state_paddr) {
- return -1;
- }
- read_guest_rom_state(s);
- if (memcmp(s->rom_state.signature, "kvm aPiC", 8) != 0) {
- return -1;
- }
- s->rom_state_vaddr = rom_state_vaddr;
-
- /* fixup addresses in ROM if needed */
- if (rom_state_vaddr == le32_to_cpu(s->rom_state.vaddr)) {
- return 0;
- }
- for (pos = le32_to_cpu(s->rom_state.fixup_start);
- pos < le32_to_cpu(s->rom_state.fixup_end);
- pos += 4) {
- cpu_physical_memory_read(paddr + pos - s->rom_state.vaddr,
- &offset, sizeof(offset));
- offset = le32_to_cpu(offset);
- cpu_physical_memory_read(paddr + offset, &patch, sizeof(patch));
- patch = le32_to_cpu(patch);
- patch += rom_state_vaddr - le32_to_cpu(s->rom_state.vaddr);
- patch = cpu_to_le32(patch);
- cpu_physical_memory_write(paddr + offset, &patch, sizeof(patch));
- }
- read_guest_rom_state(s);
- s->vapic_paddr = paddr + le32_to_cpu(s->rom_state.vapic_vaddr) -
- le32_to_cpu(s->rom_state.vaddr);
-
- return 0;
-}
-
-/*
- * Tries to read the unique processor number from the Kernel Processor Control
- * Region (KPCR) of 32-bit Windows XP and Server 2003. Returns -1 if the KPCR
- * cannot be accessed or is considered invalid. This also ensures that we are
- * not patching the wrong guest.
- */
-static int get_kpcr_number(X86CPU *cpu)
-{
- CPUX86State *env = &cpu->env;
- struct kpcr {
- uint8_t fill1[0x1c];
- uint32_t self;
- uint8_t fill2[0x31];
- uint8_t number;
- } QEMU_PACKED kpcr;
-
- if (cpu_memory_rw_debug(CPU(cpu), env->segs[R_FS].base,
- (void *)&kpcr, sizeof(kpcr), 0) < 0 ||
- kpcr.self != env->segs[R_FS].base) {
- return -1;
- }
- return kpcr.number;
-}
-
-static int vapic_enable(VAPICROMState *s, X86CPU *cpu)
-{
- int cpu_number = get_kpcr_number(cpu);
- hwaddr vapic_paddr;
- static const uint8_t enabled = 1;
-
- if (cpu_number < 0) {
- return -1;
- }
- vapic_paddr = s->vapic_paddr +
- (((hwaddr)cpu_number) << VAPIC_CPU_SHIFT);
- cpu_physical_memory_write(vapic_paddr + offsetof(VAPICState, enabled),
- &enabled, sizeof(enabled));
- apic_enable_vapic(cpu->apic_state, vapic_paddr);
-
- s->state = VAPIC_ACTIVE;
-
- return 0;
-}
-
-static void patch_byte(X86CPU *cpu, target_ulong addr, uint8_t byte)
-{
- cpu_memory_rw_debug(CPU(cpu), addr, &byte, 1, 1);
-}
-
-static void patch_call(VAPICROMState *s, X86CPU *cpu, target_ulong ip,
- uint32_t target)
-{
- uint32_t offset;
-
- offset = cpu_to_le32(target - ip - 5);
- patch_byte(cpu, ip, 0xe8); /* call near */
- cpu_memory_rw_debug(CPU(cpu), ip + 1, (void *)&offset, sizeof(offset), 1);
-}
-
-static void patch_instruction(VAPICROMState *s, X86CPU *cpu, target_ulong ip)
-{
- CPUState *cs = CPU(cpu);
- CPUX86State *env = &cpu->env;
- VAPICHandlers *handlers;
- uint8_t opcode[2];
- uint32_t imm32;
- target_ulong current_pc = 0;
- target_ulong current_cs_base = 0;
- int current_flags = 0;
-
- if (smp_cpus == 1) {
- handlers = &s->rom_state.up;
- } else {
- handlers = &s->rom_state.mp;
- }
-
- if (!kvm_enabled()) {
- cpu_get_tb_cpu_state(env, &current_pc, &current_cs_base,
- &current_flags);
- }
-
- pause_all_vcpus();
-
- cpu_memory_rw_debug(cs, ip, opcode, sizeof(opcode), 0);
-
- switch (opcode[0]) {
- case 0x89: /* mov r32 to r/m32 */
- patch_byte(cpu, ip, 0x50 + modrm_reg(opcode[1])); /* push reg */
- patch_call(s, cpu, ip + 1, handlers->set_tpr);
- break;
- case 0x8b: /* mov r/m32 to r32 */
- patch_byte(cpu, ip, 0x90);
- patch_call(s, cpu, ip + 1, handlers->get_tpr[modrm_reg(opcode[1])]);
- break;
- case 0xa1: /* mov abs to eax */
- patch_call(s, cpu, ip, handlers->get_tpr[0]);
- break;
- case 0xa3: /* mov eax to abs */
- patch_call(s, cpu, ip, handlers->set_tpr_eax);
- break;
- case 0xc7: /* mov imm32, r/m32 (c7/0) */
- patch_byte(cpu, ip, 0x68); /* push imm32 */
- cpu_memory_rw_debug(cs, ip + 6, (void *)&imm32, sizeof(imm32), 0);
- cpu_memory_rw_debug(cs, ip + 1, (void *)&imm32, sizeof(imm32), 1);
- patch_call(s, cpu, ip + 5, handlers->set_tpr);
- break;
- case 0xff: /* push r/m32 */
- patch_byte(cpu, ip, 0x50); /* push eax */
- patch_call(s, cpu, ip + 1, handlers->get_tpr_stack);
- break;
- default:
- abort();
- }
-
- resume_all_vcpus();
-
- if (!kvm_enabled()) {
- cs->current_tb = NULL;
- tb_gen_code(cs, current_pc, current_cs_base, current_flags, 1);
- cpu_resume_from_signal(cs, NULL);
- }
-}
-
-void vapic_report_tpr_access(DeviceState *dev, CPUState *cs, target_ulong ip,
- TPRAccess access)
-{
- VAPICROMState *s = VAPIC(dev);
- X86CPU *cpu = X86_CPU(cs);
- CPUX86State *env = &cpu->env;
-
- cpu_synchronize_state(cs);
-
- if (evaluate_tpr_instruction(s, cpu, &ip, access) < 0) {
- if (s->state == VAPIC_ACTIVE) {
- vapic_enable(s, cpu);
- }
- return;
- }
- if (update_rom_mapping(s, env, ip) < 0) {
- return;
- }
- if (vapic_enable(s, cpu) < 0) {
- return;
- }
- patch_instruction(s, cpu, ip);
-}
-
-typedef struct VAPICEnableTPRReporting {
- DeviceState *apic;
- bool enable;
-} VAPICEnableTPRReporting;
-
-static void vapic_do_enable_tpr_reporting(void *data)
-{
- VAPICEnableTPRReporting *info = data;
-
- apic_enable_tpr_access_reporting(info->apic, info->enable);
-}
-
-static void vapic_enable_tpr_reporting(bool enable)
-{
- VAPICEnableTPRReporting info = {
- .enable = enable,
- };
- CPUState *cs;
- X86CPU *cpu;
-
- CPU_FOREACH(cs) {
- cpu = X86_CPU(cs);
- info.apic = cpu->apic_state;
- run_on_cpu(cs, vapic_do_enable_tpr_reporting, &info);
- }
-}
-
-static void vapic_reset(DeviceState *dev)
-{
- VAPICROMState *s = VAPIC(dev);
-
- s->state = VAPIC_INACTIVE;
- s->rom_state_paddr = 0;
- vapic_enable_tpr_reporting(false);
-}
-
-/*
- * Set the IRQ polling hypercalls to the supported variant:
- * - vmcall if using KVM in-kernel irqchip
- * - 32-bit VAPIC port write otherwise
- */
-static int patch_hypercalls(VAPICROMState *s)
-{
- hwaddr rom_paddr = s->rom_state_paddr & ROM_BLOCK_MASK;
- static const uint8_t vmcall_pattern[] = { /* vmcall */
- 0xb8, 0x1, 0, 0, 0, 0xf, 0x1, 0xc1
- };
- static const uint8_t outl_pattern[] = { /* nop; outl %eax,0x7e */
- 0xb8, 0x1, 0, 0, 0, 0x90, 0xe7, 0x7e
- };
- uint8_t alternates[2];
- const uint8_t *pattern;
- const uint8_t *patch;
- int patches = 0;
- off_t pos;
- uint8_t *rom;
-
- rom = g_malloc(s->rom_size);
- cpu_physical_memory_read(rom_paddr, rom, s->rom_size);
-
- for (pos = 0; pos < s->rom_size - sizeof(vmcall_pattern); pos++) {
- if (kvm_irqchip_in_kernel()) {
- pattern = outl_pattern;
- alternates[0] = outl_pattern[7];
- alternates[1] = outl_pattern[7];
- patch = &vmcall_pattern[5];
- } else {
- pattern = vmcall_pattern;
- alternates[0] = vmcall_pattern[7];
- alternates[1] = 0xd9; /* AMD's VMMCALL */
- patch = &outl_pattern[5];
- }
- if (memcmp(rom + pos, pattern, 7) == 0 &&
- (rom[pos + 7] == alternates[0] || rom[pos + 7] == alternates[1])) {
- cpu_physical_memory_write(rom_paddr + pos + 5, patch, 3);
- /*
- * Don't flush the tb here. Under ordinary conditions, the patched
- * calls are miles away from the current IP. Under malicious
- * conditions, the guest could trick us to crash.
- */
- }
- }
-
- g_free(rom);
-
- if (patches != 0 && patches != 2) {
- return -1;
- }
-
- return 0;
-}
-
-/*
- * For TCG mode or the time KVM honors read-only memory regions, we need to
- * enable write access to the option ROM so that variables can be updated by
- * the guest.
- */
-static int vapic_map_rom_writable(VAPICROMState *s)
-{
- hwaddr rom_paddr = s->rom_state_paddr & ROM_BLOCK_MASK;
- MemoryRegionSection section;
- MemoryRegion *as;
- size_t rom_size;
- uint8_t *ram;
-
- as = sysbus_address_space(&s->busdev);
-
- if (s->rom_mapped_writable) {
- memory_region_del_subregion(as, &s->rom);
- object_unparent(OBJECT(&s->rom));
- }
-
- /* grab RAM memory region (region @rom_paddr may still be pc.rom) */
- section = memory_region_find(as, 0, 1);
-
- /* read ROM size from RAM region */
- if (rom_paddr + 2 >= memory_region_size(section.mr)) {
- return -1;
- }
- ram = memory_region_get_ram_ptr(section.mr);
- rom_size = ram[rom_paddr + 2] * ROM_BLOCK_SIZE;
- if (rom_size == 0) {
- return -1;
- }
- s->rom_size = rom_size;
-
- /* We need to round to avoid creating subpages
- * from which we cannot run code. */
- rom_size += rom_paddr & ~TARGET_PAGE_MASK;
- rom_paddr &= TARGET_PAGE_MASK;
- rom_size = TARGET_PAGE_ALIGN(rom_size);
-
- memory_region_init_alias(&s->rom, OBJECT(s), "kvmvapic-rom", section.mr,
- rom_paddr, rom_size);
- memory_region_add_subregion_overlap(as, rom_paddr, &s->rom, 1000);
- s->rom_mapped_writable = true;
- memory_region_unref(section.mr);
-
- return 0;
-}
-
-static int vapic_prepare(VAPICROMState *s)
-{
- if (vapic_map_rom_writable(s) < 0) {
- return -1;
- }
-
- if (patch_hypercalls(s) < 0) {
- return -1;
- }
-
- vapic_enable_tpr_reporting(true);
-
- return 0;
-}
-
-static void vapic_write(void *opaque, hwaddr addr, uint64_t data,
- unsigned int size)
-{
- VAPICROMState *s = opaque;
- X86CPU *cpu;
- CPUX86State *env;
- hwaddr rom_paddr;
-
- if (!current_cpu) {
- return;
- }
-
- cpu_synchronize_state(current_cpu);
- cpu = X86_CPU(current_cpu);
- env = &cpu->env;
-
- /*
- * The VAPIC supports two PIO-based hypercalls, both via port 0x7E.
- * o 16-bit write access:
- * Reports the option ROM initialization to the hypervisor. Written
- * value is the offset of the state structure in the ROM.
- * o 8-bit write access:
- * Reactivates the VAPIC after a guest hibernation, i.e. after the
- * option ROM content has been re-initialized by a guest power cycle.
- * o 32-bit write access:
- * Poll for pending IRQs, considering the current VAPIC state.
- */
- switch (size) {
- case 2:
- if (s->state == VAPIC_INACTIVE) {
- rom_paddr = (env->segs[R_CS].base + env->eip) & ROM_BLOCK_MASK;
- s->rom_state_paddr = rom_paddr + data;
-
- s->state = VAPIC_STANDBY;
- }
- if (vapic_prepare(s) < 0) {
- s->state = VAPIC_INACTIVE;
- s->rom_state_paddr = 0;
- break;
- }
- break;
- case 1:
- if (kvm_enabled()) {
- /*
- * Disable triggering instruction in ROM by writing a NOP.
- *
- * We cannot do this in TCG mode as the reported IP is not
- * accurate.
- */
- pause_all_vcpus();
- patch_byte(cpu, env->eip - 2, 0x66);
- patch_byte(cpu, env->eip - 1, 0x90);
- resume_all_vcpus();
- }
-
- if (s->state == VAPIC_ACTIVE) {
- break;
- }
- if (update_rom_mapping(s, env, env->eip) < 0) {
- break;
- }
- if (find_real_tpr_addr(s, env) < 0) {
- break;
- }
- vapic_enable(s, cpu);
- break;
- default:
- case 4:
- if (!kvm_irqchip_in_kernel()) {
- apic_poll_irq(cpu->apic_state);
- }
- break;
- }
-}
-
-static uint64_t vapic_read(void *opaque, hwaddr addr, unsigned size)
-{
- return 0xffffffff;
-}
-
-static const MemoryRegionOps vapic_ops = {
- .write = vapic_write,
- .read = vapic_read,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void vapic_realize(DeviceState *dev, Error **errp)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- VAPICROMState *s = VAPIC(dev);
-
- memory_region_init_io(&s->io, OBJECT(s), &vapic_ops, s, "kvmvapic", 2);
- sysbus_add_io(sbd, VAPIC_IO_PORT, &s->io);
- sysbus_init_ioports(sbd, VAPIC_IO_PORT, 2);
-
- option_rom[nb_option_roms].name = "kvmvapic.bin";
- option_rom[nb_option_roms].bootindex = -1;
- nb_option_roms++;
-}
-
-static void do_vapic_enable(void *data)
-{
- VAPICROMState *s = data;
- X86CPU *cpu = X86_CPU(first_cpu);
-
- static const uint8_t enabled = 1;
- cpu_physical_memory_write(s->vapic_paddr + offsetof(VAPICState, enabled),
- &enabled, sizeof(enabled));
- apic_enable_vapic(cpu->apic_state, s->vapic_paddr);
- s->state = VAPIC_ACTIVE;
-}
-
-static void kvmvapic_vm_state_change(void *opaque, int running,
- RunState state)
-{
- VAPICROMState *s = opaque;
- uint8_t *zero;
-
- if (!running) {
- return;
- }
-
- if (s->state == VAPIC_ACTIVE) {
- if (smp_cpus == 1) {
- run_on_cpu(first_cpu, do_vapic_enable, s);
- } else {
- zero = g_malloc0(s->rom_state.vapic_size);
- cpu_physical_memory_write(s->vapic_paddr, zero,
- s->rom_state.vapic_size);
- g_free(zero);
- }
- }
-
- qemu_del_vm_change_state_handler(s->vmsentry);
-}
-
-static int vapic_post_load(void *opaque, int version_id)
-{
- VAPICROMState *s = opaque;
-
- /*
- * The old implementation of qemu-kvm did not provide the state
- * VAPIC_STANDBY. Reconstruct it.
- */
- if (s->state == VAPIC_INACTIVE && s->rom_state_paddr != 0) {
- s->state = VAPIC_STANDBY;
- }
-
- if (s->state != VAPIC_INACTIVE) {
- if (vapic_prepare(s) < 0) {
- return -1;
- }
- }
-
- if (!s->vmsentry) {
- s->vmsentry =
- qemu_add_vm_change_state_handler(kvmvapic_vm_state_change, s);
- }
- return 0;
-}
-
-static const VMStateDescription vmstate_handlers = {
- .name = "kvmvapic-handlers",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(set_tpr, VAPICHandlers),
- VMSTATE_UINT32(set_tpr_eax, VAPICHandlers),
- VMSTATE_UINT32_ARRAY(get_tpr, VAPICHandlers, 8),
- VMSTATE_UINT32(get_tpr_stack, VAPICHandlers),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_guest_rom = {
- .name = "kvmvapic-guest-rom",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UNUSED(8), /* signature */
- VMSTATE_UINT32(vaddr, GuestROMState),
- VMSTATE_UINT32(fixup_start, GuestROMState),
- VMSTATE_UINT32(fixup_end, GuestROMState),
- VMSTATE_UINT32(vapic_vaddr, GuestROMState),
- VMSTATE_UINT32(vapic_size, GuestROMState),
- VMSTATE_UINT32(vcpu_shift, GuestROMState),
- VMSTATE_UINT32(real_tpr_addr, GuestROMState),
- VMSTATE_STRUCT(up, GuestROMState, 0, vmstate_handlers, VAPICHandlers),
- VMSTATE_STRUCT(mp, GuestROMState, 0, vmstate_handlers, VAPICHandlers),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_vapic = {
- .name = "kvm-tpr-opt", /* compatible with qemu-kvm VAPIC */
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = vapic_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT(rom_state, VAPICROMState, 0, vmstate_guest_rom,
- GuestROMState),
- VMSTATE_UINT32(state, VAPICROMState),
- VMSTATE_UINT32(real_tpr_addr, VAPICROMState),
- VMSTATE_UINT32(rom_state_vaddr, VAPICROMState),
- VMSTATE_UINT32(vapic_paddr, VAPICROMState),
- VMSTATE_UINT32(rom_state_paddr, VAPICROMState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void vapic_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->reset = vapic_reset;
- dc->vmsd = &vmstate_vapic;
- dc->realize = vapic_realize;
-}
-
-static const TypeInfo vapic_type = {
- .name = TYPE_VAPIC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(VAPICROMState),
- .class_init = vapic_class_init,
-};
-
-static void vapic_register(void)
-{
- type_register_static(&vapic_type);
-}
-
-type_init(vapic_register);
diff --git a/qemu/hw/i386/multiboot.c b/qemu/hw/i386/multiboot.c
deleted file mode 100644
index 387caa67d..000000000
--- a/qemu/hw/i386/multiboot.c
+++ /dev/null
@@ -1,375 +0,0 @@
-/*
- * QEMU PC System Emulator
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/hw.h"
-#include "hw/nvram/fw_cfg.h"
-#include "multiboot.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "sysemu/sysemu.h"
-
-/* Show multiboot debug output */
-//#define DEBUG_MULTIBOOT
-
-#ifdef DEBUG_MULTIBOOT
-#define mb_debug(a...) fprintf(stderr, ## a)
-#else
-#define mb_debug(a...)
-#endif
-
-#define MULTIBOOT_STRUCT_ADDR 0x9000
-
-#if MULTIBOOT_STRUCT_ADDR > 0xf0000
-#error multiboot struct needs to fit in 16 bit real mode
-#endif
-
-enum {
- /* Multiboot info */
- MBI_FLAGS = 0,
- MBI_MEM_LOWER = 4,
- MBI_MEM_UPPER = 8,
- MBI_BOOT_DEVICE = 12,
- MBI_CMDLINE = 16,
- MBI_MODS_COUNT = 20,
- MBI_MODS_ADDR = 24,
- MBI_MMAP_ADDR = 48,
- MBI_BOOTLOADER = 64,
-
- MBI_SIZE = 88,
-
- /* Multiboot modules */
- MB_MOD_START = 0,
- MB_MOD_END = 4,
- MB_MOD_CMDLINE = 8,
-
- MB_MOD_SIZE = 16,
-
- /* Region offsets */
- ADDR_E820_MAP = MULTIBOOT_STRUCT_ADDR + 0,
- ADDR_MBI = ADDR_E820_MAP + 0x500,
-
- /* Multiboot flags */
- MULTIBOOT_FLAGS_MEMORY = 1 << 0,
- MULTIBOOT_FLAGS_BOOT_DEVICE = 1 << 1,
- MULTIBOOT_FLAGS_CMDLINE = 1 << 2,
- MULTIBOOT_FLAGS_MODULES = 1 << 3,
- MULTIBOOT_FLAGS_MMAP = 1 << 6,
- MULTIBOOT_FLAGS_BOOTLOADER = 1 << 9,
-};
-
-typedef struct {
- /* buffer holding kernel, cmdlines and mb_infos */
- void *mb_buf;
- /* address in target */
- hwaddr mb_buf_phys;
- /* size of mb_buf in bytes */
- unsigned mb_buf_size;
- /* offset of mb-info's in bytes */
- hwaddr offset_mbinfo;
- /* offset in buffer for cmdlines in bytes */
- hwaddr offset_cmdlines;
- /* offset in buffer for bootloader name in bytes */
- hwaddr offset_bootloader;
- /* offset of modules in bytes */
- hwaddr offset_mods;
- /* available slots for mb modules infos */
- int mb_mods_avail;
- /* currently used slots of mb modules */
- int mb_mods_count;
-} MultibootState;
-
-const char *bootloader_name = "qemu";
-
-static uint32_t mb_add_cmdline(MultibootState *s, const char *cmdline)
-{
- hwaddr p = s->offset_cmdlines;
- char *b = (char *)s->mb_buf + p;
-
- get_opt_value(b, strlen(cmdline) + 1, cmdline);
- s->offset_cmdlines += strlen(b) + 1;
- return s->mb_buf_phys + p;
-}
-
-static uint32_t mb_add_bootloader(MultibootState *s, const char *bootloader)
-{
- hwaddr p = s->offset_bootloader;
- char *b = (char *)s->mb_buf + p;
-
- memcpy(b, bootloader, strlen(bootloader) + 1);
- s->offset_bootloader += strlen(b) + 1;
- return s->mb_buf_phys + p;
-}
-
-static void mb_add_mod(MultibootState *s,
- hwaddr start, hwaddr end,
- hwaddr cmdline_phys)
-{
- char *p;
- assert(s->mb_mods_count < s->mb_mods_avail);
-
- p = (char *)s->mb_buf + s->offset_mbinfo + MB_MOD_SIZE * s->mb_mods_count;
-
- stl_p(p + MB_MOD_START, start);
- stl_p(p + MB_MOD_END, end);
- stl_p(p + MB_MOD_CMDLINE, cmdline_phys);
-
- mb_debug("mod%02d: "TARGET_FMT_plx" - "TARGET_FMT_plx"\n",
- s->mb_mods_count, start, end);
-
- s->mb_mods_count++;
-}
-
-int load_multiboot(FWCfgState *fw_cfg,
- FILE *f,
- const char *kernel_filename,
- const char *initrd_filename,
- const char *kernel_cmdline,
- int kernel_file_size,
- uint8_t *header)
-{
- int i, is_multiboot = 0;
- uint32_t flags = 0;
- uint32_t mh_entry_addr;
- uint32_t mh_load_addr;
- uint32_t mb_kernel_size;
- MultibootState mbs;
- uint8_t bootinfo[MBI_SIZE];
- uint8_t *mb_bootinfo_data;
- uint32_t cmdline_len;
-
- /* Ok, let's see if it is a multiboot image.
- The header is 12x32bit long, so the latest entry may be 8192 - 48. */
- for (i = 0; i < (8192 - 48); i += 4) {
- if (ldl_p(header+i) == 0x1BADB002) {
- uint32_t checksum = ldl_p(header+i+8);
- flags = ldl_p(header+i+4);
- checksum += flags;
- checksum += (uint32_t)0x1BADB002;
- if (!checksum) {
- is_multiboot = 1;
- break;
- }
- }
- }
-
- if (!is_multiboot)
- return 0; /* no multiboot */
-
- mb_debug("qemu: I believe we found a multiboot image!\n");
- memset(bootinfo, 0, sizeof(bootinfo));
- memset(&mbs, 0, sizeof(mbs));
-
- if (flags & 0x00000004) { /* MULTIBOOT_HEADER_HAS_VBE */
- fprintf(stderr, "qemu: multiboot knows VBE. we don't.\n");
- }
- if (!(flags & 0x00010000)) { /* MULTIBOOT_HEADER_HAS_ADDR */
- uint64_t elf_entry;
- uint64_t elf_low, elf_high;
- int kernel_size;
- fclose(f);
-
- if (((struct elf64_hdr*)header)->e_machine == EM_X86_64) {
- fprintf(stderr, "Cannot load x86-64 image, give a 32bit one.\n");
- exit(1);
- }
-
- kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry,
- &elf_low, &elf_high, 0, I386_ELF_MACHINE,
- 0, 0);
- if (kernel_size < 0) {
- fprintf(stderr, "Error while loading elf kernel\n");
- exit(1);
- }
- mh_load_addr = elf_low;
- mb_kernel_size = elf_high - elf_low;
- mh_entry_addr = elf_entry;
-
- mbs.mb_buf = g_malloc(mb_kernel_size);
- if (rom_copy(mbs.mb_buf, mh_load_addr, mb_kernel_size) != mb_kernel_size) {
- fprintf(stderr, "Error while fetching elf kernel from rom\n");
- exit(1);
- }
-
- mb_debug("qemu: loading multiboot-elf kernel (%#x bytes) with entry %#zx\n",
- mb_kernel_size, (size_t)mh_entry_addr);
- } else {
- /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_ADDR. */
- uint32_t mh_header_addr = ldl_p(header+i+12);
- uint32_t mh_load_end_addr = ldl_p(header+i+20);
- uint32_t mh_bss_end_addr = ldl_p(header+i+24);
- mh_load_addr = ldl_p(header+i+16);
- uint32_t mb_kernel_text_offset = i - (mh_header_addr - mh_load_addr);
- uint32_t mb_load_size = 0;
- mh_entry_addr = ldl_p(header+i+28);
-
- if (mh_load_end_addr) {
- mb_kernel_size = mh_bss_end_addr - mh_load_addr;
- mb_load_size = mh_load_end_addr - mh_load_addr;
- } else {
- mb_kernel_size = kernel_file_size - mb_kernel_text_offset;
- mb_load_size = mb_kernel_size;
- }
-
- /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_VBE.
- uint32_t mh_mode_type = ldl_p(header+i+32);
- uint32_t mh_width = ldl_p(header+i+36);
- uint32_t mh_height = ldl_p(header+i+40);
- uint32_t mh_depth = ldl_p(header+i+44); */
-
- mb_debug("multiboot: mh_header_addr = %#x\n", mh_header_addr);
- mb_debug("multiboot: mh_load_addr = %#x\n", mh_load_addr);
- mb_debug("multiboot: mh_load_end_addr = %#x\n", mh_load_end_addr);
- mb_debug("multiboot: mh_bss_end_addr = %#x\n", mh_bss_end_addr);
- mb_debug("qemu: loading multiboot kernel (%#x bytes) at %#x\n",
- mb_load_size, mh_load_addr);
-
- mbs.mb_buf = g_malloc(mb_kernel_size);
- fseek(f, mb_kernel_text_offset, SEEK_SET);
- if (fread(mbs.mb_buf, 1, mb_load_size, f) != mb_load_size) {
- fprintf(stderr, "fread() failed\n");
- exit(1);
- }
- memset(mbs.mb_buf + mb_load_size, 0, mb_kernel_size - mb_load_size);
- fclose(f);
- }
-
- mbs.mb_buf_phys = mh_load_addr;
-
- mbs.mb_buf_size = TARGET_PAGE_ALIGN(mb_kernel_size);
- mbs.offset_mbinfo = mbs.mb_buf_size;
-
- /* Calculate space for cmdlines, bootloader name, and mb_mods */
- cmdline_len = strlen(kernel_filename) + 1;
- cmdline_len += strlen(kernel_cmdline) + 1;
- if (initrd_filename) {
- const char *r = initrd_filename;
- cmdline_len += strlen(r) + 1;
- mbs.mb_mods_avail = 1;
- while (*(r = get_opt_value(NULL, 0, r))) {
- mbs.mb_mods_avail++;
- r++;
- }
- }
-
- mbs.mb_buf_size += cmdline_len;
- mbs.mb_buf_size += MB_MOD_SIZE * mbs.mb_mods_avail;
- mbs.mb_buf_size += strlen(bootloader_name) + 1;
-
- mbs.mb_buf_size = TARGET_PAGE_ALIGN(mbs.mb_buf_size);
-
- /* enlarge mb_buf to hold cmdlines, bootloader, mb-info structs */
- mbs.mb_buf = g_realloc(mbs.mb_buf, mbs.mb_buf_size);
- mbs.offset_cmdlines = mbs.offset_mbinfo + mbs.mb_mods_avail * MB_MOD_SIZE;
- mbs.offset_bootloader = mbs.offset_cmdlines + cmdline_len;
-
- if (initrd_filename) {
- char *next_initrd, not_last;
-
- mbs.offset_mods = mbs.mb_buf_size;
-
- do {
- char *next_space;
- int mb_mod_length;
- uint32_t offs = mbs.mb_buf_size;
-
- next_initrd = (char *)get_opt_value(NULL, 0, initrd_filename);
- not_last = *next_initrd;
- *next_initrd = '\0';
- /* if a space comes after the module filename, treat everything
- after that as parameters */
- hwaddr c = mb_add_cmdline(&mbs, initrd_filename);
- if ((next_space = strchr(initrd_filename, ' ')))
- *next_space = '\0';
- mb_debug("multiboot loading module: %s\n", initrd_filename);
- mb_mod_length = get_image_size(initrd_filename);
- if (mb_mod_length < 0) {
- fprintf(stderr, "Failed to open file '%s'\n", initrd_filename);
- exit(1);
- }
-
- mbs.mb_buf_size = TARGET_PAGE_ALIGN(mb_mod_length + mbs.mb_buf_size);
- mbs.mb_buf = g_realloc(mbs.mb_buf, mbs.mb_buf_size);
-
- load_image(initrd_filename, (unsigned char *)mbs.mb_buf + offs);
- mb_add_mod(&mbs, mbs.mb_buf_phys + offs,
- mbs.mb_buf_phys + offs + mb_mod_length, c);
-
- mb_debug("mod_start: %p\nmod_end: %p\n cmdline: "TARGET_FMT_plx"\n",
- (char *)mbs.mb_buf + offs,
- (char *)mbs.mb_buf + offs + mb_mod_length, c);
- initrd_filename = next_initrd+1;
- } while (not_last);
- }
-
- /* Commandline support */
- char kcmdline[strlen(kernel_filename) + strlen(kernel_cmdline) + 2];
- snprintf(kcmdline, sizeof(kcmdline), "%s %s",
- kernel_filename, kernel_cmdline);
- stl_p(bootinfo + MBI_CMDLINE, mb_add_cmdline(&mbs, kcmdline));
-
- stl_p(bootinfo + MBI_BOOTLOADER, mb_add_bootloader(&mbs, bootloader_name));
-
- stl_p(bootinfo + MBI_MODS_ADDR, mbs.mb_buf_phys + mbs.offset_mbinfo);
- stl_p(bootinfo + MBI_MODS_COUNT, mbs.mb_mods_count); /* mods_count */
-
- /* the kernel is where we want it to be now */
- stl_p(bootinfo + MBI_FLAGS, MULTIBOOT_FLAGS_MEMORY
- | MULTIBOOT_FLAGS_BOOT_DEVICE
- | MULTIBOOT_FLAGS_CMDLINE
- | MULTIBOOT_FLAGS_MODULES
- | MULTIBOOT_FLAGS_MMAP
- | MULTIBOOT_FLAGS_BOOTLOADER);
- stl_p(bootinfo + MBI_BOOT_DEVICE, 0x8000ffff); /* XXX: use the -boot switch? */
- stl_p(bootinfo + MBI_MMAP_ADDR, ADDR_E820_MAP);
-
- mb_debug("multiboot: mh_entry_addr = %#x\n", mh_entry_addr);
- mb_debug(" mb_buf_phys = "TARGET_FMT_plx"\n", mbs.mb_buf_phys);
- mb_debug(" mod_start = "TARGET_FMT_plx"\n", mbs.mb_buf_phys + mbs.offset_mods);
- mb_debug(" mb_mods_count = %d\n", mbs.mb_mods_count);
-
- /* save bootinfo off the stack */
- mb_bootinfo_data = g_malloc(sizeof(bootinfo));
- memcpy(mb_bootinfo_data, bootinfo, sizeof(bootinfo));
-
- /* Pass variables to option rom */
- fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ENTRY, mh_entry_addr);
- fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, mh_load_addr);
- fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, mbs.mb_buf_size);
- fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA,
- mbs.mb_buf, mbs.mb_buf_size);
-
- fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, ADDR_MBI);
- fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, sizeof(bootinfo));
- fw_cfg_add_bytes(fw_cfg, FW_CFG_INITRD_DATA, mb_bootinfo_data,
- sizeof(bootinfo));
-
- option_rom[nb_option_roms].name = "multiboot.bin";
- option_rom[nb_option_roms].bootindex = 0;
- nb_option_roms++;
-
- return 1; /* yes, we are multiboot */
-}
diff --git a/qemu/hw/i386/multiboot.h b/qemu/hw/i386/multiboot.h
deleted file mode 100644
index 60de309cd..000000000
--- a/qemu/hw/i386/multiboot.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef QEMU_MULTIBOOT_H
-#define QEMU_MULTIBOOT_H
-
-#include "hw/nvram/fw_cfg.h"
-
-int load_multiboot(FWCfgState *fw_cfg,
- FILE *f,
- const char *kernel_filename,
- const char *initrd_filename,
- const char *kernel_cmdline,
- int kernel_file_size,
- uint8_t *header);
-
-#endif
diff --git a/qemu/hw/i386/pc.c b/qemu/hw/i386/pc.c
deleted file mode 100644
index 99437e0b7..000000000
--- a/qemu/hw/i386/pc.c
+++ /dev/null
@@ -1,2017 +0,0 @@
-/*
- * QEMU PC System Emulator
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/i386/pc.h"
-#include "hw/char/serial.h"
-#include "hw/i386/apic.h"
-#include "hw/i386/topology.h"
-#include "sysemu/cpus.h"
-#include "hw/block/fdc.h"
-#include "hw/ide.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/pci_bus.h"
-#include "hw/nvram/fw_cfg.h"
-#include "hw/timer/hpet.h"
-#include "hw/smbios/smbios.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "multiboot.h"
-#include "hw/timer/mc146818rtc.h"
-#include "hw/timer/i8254.h"
-#include "hw/audio/pcspk.h"
-#include "hw/pci/msi.h"
-#include "hw/sysbus.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/numa.h"
-#include "sysemu/kvm.h"
-#include "sysemu/qtest.h"
-#include "kvm_i386.h"
-#include "hw/xen/xen.h"
-#include "sysemu/block-backend.h"
-#include "hw/block/block.h"
-#include "ui/qemu-spice.h"
-#include "exec/memory.h"
-#include "exec/address-spaces.h"
-#include "sysemu/arch_init.h"
-#include "qemu/bitmap.h"
-#include "qemu/config-file.h"
-#include "qemu/error-report.h"
-#include "hw/acpi/acpi.h"
-#include "hw/acpi/cpu_hotplug.h"
-#include "hw/boards.h"
-#include "hw/pci/pci_host.h"
-#include "acpi-build.h"
-#include "hw/mem/pc-dimm.h"
-#include "qapi/visitor.h"
-#include "qapi-visit.h"
-#include "qom/cpu.h"
-
-/* debug PC/ISA interrupts */
-//#define DEBUG_IRQ
-
-#ifdef DEBUG_IRQ
-#define DPRINTF(fmt, ...) \
- do { printf("CPUIRQ: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...)
-#endif
-
-#define FW_CFG_ACPI_TABLES (FW_CFG_ARCH_LOCAL + 0)
-#define FW_CFG_SMBIOS_ENTRIES (FW_CFG_ARCH_LOCAL + 1)
-#define FW_CFG_IRQ0_OVERRIDE (FW_CFG_ARCH_LOCAL + 2)
-#define FW_CFG_E820_TABLE (FW_CFG_ARCH_LOCAL + 3)
-#define FW_CFG_HPET (FW_CFG_ARCH_LOCAL + 4)
-
-#define E820_NR_ENTRIES 16
-
-struct e820_entry {
- uint64_t address;
- uint64_t length;
- uint32_t type;
-} QEMU_PACKED __attribute((__aligned__(4)));
-
-struct e820_table {
- uint32_t count;
- struct e820_entry entry[E820_NR_ENTRIES];
-} QEMU_PACKED __attribute((__aligned__(4)));
-
-static struct e820_table e820_reserve;
-static struct e820_entry *e820_table;
-static unsigned e820_entries;
-struct hpet_fw_config hpet_cfg = {.count = UINT8_MAX};
-
-void gsi_handler(void *opaque, int n, int level)
-{
- GSIState *s = opaque;
-
- DPRINTF("pc: %s GSI %d\n", level ? "raising" : "lowering", n);
- if (n < ISA_NUM_IRQS) {
- qemu_set_irq(s->i8259_irq[n], level);
- }
- qemu_set_irq(s->ioapic_irq[n], level);
-}
-
-static void ioport80_write(void *opaque, hwaddr addr, uint64_t data,
- unsigned size)
-{
-}
-
-static uint64_t ioport80_read(void *opaque, hwaddr addr, unsigned size)
-{
- return 0xffffffffffffffffULL;
-}
-
-/* MSDOS compatibility mode FPU exception support */
-static qemu_irq ferr_irq;
-
-void pc_register_ferr_irq(qemu_irq irq)
-{
- ferr_irq = irq;
-}
-
-/* XXX: add IGNNE support */
-void cpu_set_ferr(CPUX86State *s)
-{
- qemu_irq_raise(ferr_irq);
-}
-
-static void ioportF0_write(void *opaque, hwaddr addr, uint64_t data,
- unsigned size)
-{
- qemu_irq_lower(ferr_irq);
-}
-
-static uint64_t ioportF0_read(void *opaque, hwaddr addr, unsigned size)
-{
- return 0xffffffffffffffffULL;
-}
-
-/* TSC handling */
-uint64_t cpu_get_tsc(CPUX86State *env)
-{
- return cpu_get_ticks();
-}
-
-/* IRQ handling */
-int cpu_get_pic_interrupt(CPUX86State *env)
-{
- X86CPU *cpu = x86_env_get_cpu(env);
- int intno;
-
- intno = apic_get_interrupt(cpu->apic_state);
- if (intno >= 0) {
- return intno;
- }
- /* read the irq from the PIC */
- if (!apic_accept_pic_intr(cpu->apic_state)) {
- return -1;
- }
-
- intno = pic_read_irq(isa_pic);
- return intno;
-}
-
-static void pic_irq_request(void *opaque, int irq, int level)
-{
- CPUState *cs = first_cpu;
- X86CPU *cpu = X86_CPU(cs);
-
- DPRINTF("pic_irqs: %s irq %d\n", level? "raise" : "lower", irq);
- if (cpu->apic_state) {
- CPU_FOREACH(cs) {
- cpu = X86_CPU(cs);
- if (apic_accept_pic_intr(cpu->apic_state)) {
- apic_deliver_pic_intr(cpu->apic_state, level);
- }
- }
- } else {
- if (level) {
- cpu_interrupt(cs, CPU_INTERRUPT_HARD);
- } else {
- cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
- }
- }
-}
-
-/* PC cmos mappings */
-
-#define REG_EQUIPMENT_BYTE 0x14
-
-int cmos_get_fd_drive_type(FloppyDriveType fd0)
-{
- int val;
-
- switch (fd0) {
- case FLOPPY_DRIVE_TYPE_144:
- /* 1.44 Mb 3"5 drive */
- val = 4;
- break;
- case FLOPPY_DRIVE_TYPE_288:
- /* 2.88 Mb 3"5 drive */
- val = 5;
- break;
- case FLOPPY_DRIVE_TYPE_120:
- /* 1.2 Mb 5"5 drive */
- val = 2;
- break;
- case FLOPPY_DRIVE_TYPE_NONE:
- default:
- val = 0;
- break;
- }
- return val;
-}
-
-static void cmos_init_hd(ISADevice *s, int type_ofs, int info_ofs,
- int16_t cylinders, int8_t heads, int8_t sectors)
-{
- rtc_set_memory(s, type_ofs, 47);
- rtc_set_memory(s, info_ofs, cylinders);
- rtc_set_memory(s, info_ofs + 1, cylinders >> 8);
- rtc_set_memory(s, info_ofs + 2, heads);
- rtc_set_memory(s, info_ofs + 3, 0xff);
- rtc_set_memory(s, info_ofs + 4, 0xff);
- rtc_set_memory(s, info_ofs + 5, 0xc0 | ((heads > 8) << 3));
- rtc_set_memory(s, info_ofs + 6, cylinders);
- rtc_set_memory(s, info_ofs + 7, cylinders >> 8);
- rtc_set_memory(s, info_ofs + 8, sectors);
-}
-
-/* convert boot_device letter to something recognizable by the bios */
-static int boot_device2nibble(char boot_device)
-{
- switch(boot_device) {
- case 'a':
- case 'b':
- return 0x01; /* floppy boot */
- case 'c':
- return 0x02; /* hard drive boot */
- case 'd':
- return 0x03; /* CD-ROM boot */
- case 'n':
- return 0x04; /* Network boot */
- }
- return 0;
-}
-
-static void set_boot_dev(ISADevice *s, const char *boot_device, Error **errp)
-{
-#define PC_MAX_BOOT_DEVICES 3
- int nbds, bds[3] = { 0, };
- int i;
-
- nbds = strlen(boot_device);
- if (nbds > PC_MAX_BOOT_DEVICES) {
- error_setg(errp, "Too many boot devices for PC");
- return;
- }
- for (i = 0; i < nbds; i++) {
- bds[i] = boot_device2nibble(boot_device[i]);
- if (bds[i] == 0) {
- error_setg(errp, "Invalid boot device for PC: '%c'",
- boot_device[i]);
- return;
- }
- }
- rtc_set_memory(s, 0x3d, (bds[1] << 4) | bds[0]);
- rtc_set_memory(s, 0x38, (bds[2] << 4) | (fd_bootchk ? 0x0 : 0x1));
-}
-
-static void pc_boot_set(void *opaque, const char *boot_device, Error **errp)
-{
- set_boot_dev(opaque, boot_device, errp);
-}
-
-static void pc_cmos_init_floppy(ISADevice *rtc_state, ISADevice *floppy)
-{
- int val, nb, i;
- FloppyDriveType fd_type[2] = { FLOPPY_DRIVE_TYPE_NONE,
- FLOPPY_DRIVE_TYPE_NONE };
-
- /* floppy type */
- if (floppy) {
- for (i = 0; i < 2; i++) {
- fd_type[i] = isa_fdc_get_drive_type(floppy, i);
- }
- }
- val = (cmos_get_fd_drive_type(fd_type[0]) << 4) |
- cmos_get_fd_drive_type(fd_type[1]);
- rtc_set_memory(rtc_state, 0x10, val);
-
- val = rtc_get_memory(rtc_state, REG_EQUIPMENT_BYTE);
- nb = 0;
- if (fd_type[0] != FLOPPY_DRIVE_TYPE_NONE) {
- nb++;
- }
- if (fd_type[1] != FLOPPY_DRIVE_TYPE_NONE) {
- nb++;
- }
- switch (nb) {
- case 0:
- break;
- case 1:
- val |= 0x01; /* 1 drive, ready for boot */
- break;
- case 2:
- val |= 0x41; /* 2 drives, ready for boot */
- break;
- }
- rtc_set_memory(rtc_state, REG_EQUIPMENT_BYTE, val);
-}
-
-typedef struct pc_cmos_init_late_arg {
- ISADevice *rtc_state;
- BusState *idebus[2];
-} pc_cmos_init_late_arg;
-
-typedef struct check_fdc_state {
- ISADevice *floppy;
- bool multiple;
-} CheckFdcState;
-
-static int check_fdc(Object *obj, void *opaque)
-{
- CheckFdcState *state = opaque;
- Object *fdc;
- uint32_t iobase;
- Error *local_err = NULL;
-
- fdc = object_dynamic_cast(obj, TYPE_ISA_FDC);
- if (!fdc) {
- return 0;
- }
-
- iobase = object_property_get_int(obj, "iobase", &local_err);
- if (local_err || iobase != 0x3f0) {
- error_free(local_err);
- return 0;
- }
-
- if (state->floppy) {
- state->multiple = true;
- } else {
- state->floppy = ISA_DEVICE(obj);
- }
- return 0;
-}
-
-static const char * const fdc_container_path[] = {
- "/unattached", "/peripheral", "/peripheral-anon"
-};
-
-/*
- * Locate the FDC at IO address 0x3f0, in order to configure the CMOS registers
- * and ACPI objects.
- */
-ISADevice *pc_find_fdc0(void)
-{
- int i;
- Object *container;
- CheckFdcState state = { 0 };
-
- for (i = 0; i < ARRAY_SIZE(fdc_container_path); i++) {
- container = container_get(qdev_get_machine(), fdc_container_path[i]);
- object_child_foreach(container, check_fdc, &state);
- }
-
- if (state.multiple) {
- error_report("warning: multiple floppy disk controllers with "
- "iobase=0x3f0 have been found");
- error_printf("the one being picked for CMOS setup might not reflect "
- "your intent");
- }
-
- return state.floppy;
-}
-
-static void pc_cmos_init_late(void *opaque)
-{
- pc_cmos_init_late_arg *arg = opaque;
- ISADevice *s = arg->rtc_state;
- int16_t cylinders;
- int8_t heads, sectors;
- int val;
- int i, trans;
-
- val = 0;
- if (ide_get_geometry(arg->idebus[0], 0,
- &cylinders, &heads, &sectors) >= 0) {
- cmos_init_hd(s, 0x19, 0x1b, cylinders, heads, sectors);
- val |= 0xf0;
- }
- if (ide_get_geometry(arg->idebus[0], 1,
- &cylinders, &heads, &sectors) >= 0) {
- cmos_init_hd(s, 0x1a, 0x24, cylinders, heads, sectors);
- val |= 0x0f;
- }
- rtc_set_memory(s, 0x12, val);
-
- val = 0;
- for (i = 0; i < 4; i++) {
- /* NOTE: ide_get_geometry() returns the physical
- geometry. It is always such that: 1 <= sects <= 63, 1
- <= heads <= 16, 1 <= cylinders <= 16383. The BIOS
- geometry can be different if a translation is done. */
- if (ide_get_geometry(arg->idebus[i / 2], i % 2,
- &cylinders, &heads, &sectors) >= 0) {
- trans = ide_get_bios_chs_trans(arg->idebus[i / 2], i % 2) - 1;
- assert((trans & ~3) == 0);
- val |= trans << (i * 2);
- }
- }
- rtc_set_memory(s, 0x39, val);
-
- pc_cmos_init_floppy(s, pc_find_fdc0());
-
- qemu_unregister_reset(pc_cmos_init_late, opaque);
-}
-
-void pc_cmos_init(PCMachineState *pcms,
- BusState *idebus0, BusState *idebus1,
- ISADevice *s)
-{
- int val;
- static pc_cmos_init_late_arg arg;
-
- /* various important CMOS locations needed by PC/Bochs bios */
-
- /* memory size */
- /* base memory (first MiB) */
- val = MIN(pcms->below_4g_mem_size / 1024, 640);
- rtc_set_memory(s, 0x15, val);
- rtc_set_memory(s, 0x16, val >> 8);
- /* extended memory (next 64MiB) */
- if (pcms->below_4g_mem_size > 1024 * 1024) {
- val = (pcms->below_4g_mem_size - 1024 * 1024) / 1024;
- } else {
- val = 0;
- }
- if (val > 65535)
- val = 65535;
- rtc_set_memory(s, 0x17, val);
- rtc_set_memory(s, 0x18, val >> 8);
- rtc_set_memory(s, 0x30, val);
- rtc_set_memory(s, 0x31, val >> 8);
- /* memory between 16MiB and 4GiB */
- if (pcms->below_4g_mem_size > 16 * 1024 * 1024) {
- val = (pcms->below_4g_mem_size - 16 * 1024 * 1024) / 65536;
- } else {
- val = 0;
- }
- if (val > 65535)
- val = 65535;
- rtc_set_memory(s, 0x34, val);
- rtc_set_memory(s, 0x35, val >> 8);
- /* memory above 4GiB */
- val = pcms->above_4g_mem_size / 65536;
- rtc_set_memory(s, 0x5b, val);
- rtc_set_memory(s, 0x5c, val >> 8);
- rtc_set_memory(s, 0x5d, val >> 16);
-
- /* set the number of CPU */
- rtc_set_memory(s, 0x5f, smp_cpus - 1);
-
- object_property_add_link(OBJECT(pcms), "rtc_state",
- TYPE_ISA_DEVICE,
- (Object **)&pcms->rtc,
- object_property_allow_set_link,
- OBJ_PROP_LINK_UNREF_ON_RELEASE, &error_abort);
- object_property_set_link(OBJECT(pcms), OBJECT(s),
- "rtc_state", &error_abort);
-
- set_boot_dev(s, MACHINE(pcms)->boot_order, &error_fatal);
-
- val = 0;
- val |= 0x02; /* FPU is there */
- val |= 0x04; /* PS/2 mouse installed */
- rtc_set_memory(s, REG_EQUIPMENT_BYTE, val);
-
- /* hard drives and FDC */
- arg.rtc_state = s;
- arg.idebus[0] = idebus0;
- arg.idebus[1] = idebus1;
- qemu_register_reset(pc_cmos_init_late, &arg);
-}
-
-#define TYPE_PORT92 "port92"
-#define PORT92(obj) OBJECT_CHECK(Port92State, (obj), TYPE_PORT92)
-
-/* port 92 stuff: could be split off */
-typedef struct Port92State {
- ISADevice parent_obj;
-
- MemoryRegion io;
- uint8_t outport;
- qemu_irq *a20_out;
-} Port92State;
-
-static void port92_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned size)
-{
- Port92State *s = opaque;
- int oldval = s->outport;
-
- DPRINTF("port92: write 0x%02" PRIx64 "\n", val);
- s->outport = val;
- qemu_set_irq(*s->a20_out, (val >> 1) & 1);
- if ((val & 1) && !(oldval & 1)) {
- qemu_system_reset_request();
- }
-}
-
-static uint64_t port92_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- Port92State *s = opaque;
- uint32_t ret;
-
- ret = s->outport;
- DPRINTF("port92: read 0x%02x\n", ret);
- return ret;
-}
-
-static void port92_init(ISADevice *dev, qemu_irq *a20_out)
-{
- Port92State *s = PORT92(dev);
-
- s->a20_out = a20_out;
-}
-
-static const VMStateDescription vmstate_port92_isa = {
- .name = "port92",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(outport, Port92State),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void port92_reset(DeviceState *d)
-{
- Port92State *s = PORT92(d);
-
- s->outport &= ~1;
-}
-
-static const MemoryRegionOps port92_ops = {
- .read = port92_read,
- .write = port92_write,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void port92_initfn(Object *obj)
-{
- Port92State *s = PORT92(obj);
-
- memory_region_init_io(&s->io, OBJECT(s), &port92_ops, s, "port92", 1);
-
- s->outport = 0;
-}
-
-static void port92_realizefn(DeviceState *dev, Error **errp)
-{
- ISADevice *isadev = ISA_DEVICE(dev);
- Port92State *s = PORT92(dev);
-
- isa_register_ioport(isadev, &s->io, 0x92);
-}
-
-static void port92_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = port92_realizefn;
- dc->reset = port92_reset;
- dc->vmsd = &vmstate_port92_isa;
- /*
- * Reason: unlike ordinary ISA devices, this one needs additional
- * wiring: its A20 output line needs to be wired up by
- * port92_init().
- */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo port92_info = {
- .name = TYPE_PORT92,
- .parent = TYPE_ISA_DEVICE,
- .instance_size = sizeof(Port92State),
- .instance_init = port92_initfn,
- .class_init = port92_class_initfn,
-};
-
-static void port92_register_types(void)
-{
- type_register_static(&port92_info);
-}
-
-type_init(port92_register_types)
-
-static void handle_a20_line_change(void *opaque, int irq, int level)
-{
- X86CPU *cpu = opaque;
-
- /* XXX: send to all CPUs ? */
- /* XXX: add logic to handle multiple A20 line sources */
- x86_cpu_set_a20(cpu, level);
-}
-
-int e820_add_entry(uint64_t address, uint64_t length, uint32_t type)
-{
- int index = le32_to_cpu(e820_reserve.count);
- struct e820_entry *entry;
-
- if (type != E820_RAM) {
- /* old FW_CFG_E820_TABLE entry -- reservations only */
- if (index >= E820_NR_ENTRIES) {
- return -EBUSY;
- }
- entry = &e820_reserve.entry[index++];
-
- entry->address = cpu_to_le64(address);
- entry->length = cpu_to_le64(length);
- entry->type = cpu_to_le32(type);
-
- e820_reserve.count = cpu_to_le32(index);
- }
-
- /* new "etc/e820" file -- include ram too */
- e820_table = g_renew(struct e820_entry, e820_table, e820_entries + 1);
- e820_table[e820_entries].address = cpu_to_le64(address);
- e820_table[e820_entries].length = cpu_to_le64(length);
- e820_table[e820_entries].type = cpu_to_le32(type);
- e820_entries++;
-
- return e820_entries;
-}
-
-int e820_get_num_entries(void)
-{
- return e820_entries;
-}
-
-bool e820_get_entry(int idx, uint32_t type, uint64_t *address, uint64_t *length)
-{
- if (idx < e820_entries && e820_table[idx].type == cpu_to_le32(type)) {
- *address = le64_to_cpu(e820_table[idx].address);
- *length = le64_to_cpu(e820_table[idx].length);
- return true;
- }
- return false;
-}
-
-/* Enables contiguous-apic-ID mode, for compatibility */
-static bool compat_apic_id_mode;
-
-void enable_compat_apic_id_mode(void)
-{
- compat_apic_id_mode = true;
-}
-
-/* Calculates initial APIC ID for a specific CPU index
- *
- * Currently we need to be able to calculate the APIC ID from the CPU index
- * alone (without requiring a CPU object), as the QEMU<->Seabios interfaces have
- * no concept of "CPU index", and the NUMA tables on fw_cfg need the APIC ID of
- * all CPUs up to max_cpus.
- */
-static uint32_t x86_cpu_apic_id_from_index(unsigned int cpu_index)
-{
- uint32_t correct_id;
- static bool warned;
-
- correct_id = x86_apicid_from_cpu_idx(smp_cores, smp_threads, cpu_index);
- if (compat_apic_id_mode) {
- if (cpu_index != correct_id && !warned && !qtest_enabled()) {
- error_report("APIC IDs set in compatibility mode, "
- "CPU topology won't match the configuration");
- warned = true;
- }
- return cpu_index;
- } else {
- return correct_id;
- }
-}
-
-static void pc_build_smbios(FWCfgState *fw_cfg)
-{
- uint8_t *smbios_tables, *smbios_anchor;
- size_t smbios_tables_len, smbios_anchor_len;
- struct smbios_phys_mem_area *mem_array;
- unsigned i, array_count;
-
- smbios_tables = smbios_get_table_legacy(&smbios_tables_len);
- if (smbios_tables) {
- fw_cfg_add_bytes(fw_cfg, FW_CFG_SMBIOS_ENTRIES,
- smbios_tables, smbios_tables_len);
- }
-
- /* build the array of physical mem area from e820 table */
- mem_array = g_malloc0(sizeof(*mem_array) * e820_get_num_entries());
- for (i = 0, array_count = 0; i < e820_get_num_entries(); i++) {
- uint64_t addr, len;
-
- if (e820_get_entry(i, E820_RAM, &addr, &len)) {
- mem_array[array_count].address = addr;
- mem_array[array_count].length = len;
- array_count++;
- }
- }
- smbios_get_tables(mem_array, array_count,
- &smbios_tables, &smbios_tables_len,
- &smbios_anchor, &smbios_anchor_len);
- g_free(mem_array);
-
- if (smbios_anchor) {
- fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-tables",
- smbios_tables, smbios_tables_len);
- fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-anchor",
- smbios_anchor, smbios_anchor_len);
- }
-}
-
-static FWCfgState *bochs_bios_init(AddressSpace *as, PCMachineState *pcms)
-{
- FWCfgState *fw_cfg;
- uint64_t *numa_fw_cfg;
- int i, j;
-
- fw_cfg = fw_cfg_init_io_dma(FW_CFG_IO_BASE, FW_CFG_IO_BASE + 4, as);
-
- /* 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)pcms->apic_id_limit);
- fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
- fw_cfg_add_bytes(fw_cfg, FW_CFG_ACPI_TABLES,
- acpi_tables, acpi_tables_len);
- fw_cfg_add_i32(fw_cfg, FW_CFG_IRQ0_OVERRIDE, kvm_allows_irq0_override());
-
- pc_build_smbios(fw_cfg);
-
- fw_cfg_add_bytes(fw_cfg, FW_CFG_E820_TABLE,
- &e820_reserve, sizeof(e820_reserve));
- fw_cfg_add_file(fw_cfg, "etc/e820", e820_table,
- sizeof(struct e820_entry) * e820_entries);
-
- fw_cfg_add_bytes(fw_cfg, FW_CFG_HPET, &hpet_cfg, sizeof(hpet_cfg));
- /* allocate memory for the NUMA channel: one (64bit) word for the number
- * 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 + pcms->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 < pcms->apic_id_limit);
- for (j = 0; j < nb_numa_nodes; j++) {
- if (test_bit(i, numa_info[j].node_cpu)) {
- numa_fw_cfg[apic_id + 1] = cpu_to_le64(j);
- break;
- }
- }
- }
- for (i = 0; i < nb_numa_nodes; i++) {
- numa_fw_cfg[pcms->apic_id_limit + 1 + i] =
- cpu_to_le64(numa_info[i].node_mem);
- }
- fw_cfg_add_bytes(fw_cfg, FW_CFG_NUMA, numa_fw_cfg,
- (1 + pcms->apic_id_limit + nb_numa_nodes) *
- sizeof(*numa_fw_cfg));
-
- return fw_cfg;
-}
-
-static long get_file_size(FILE *f)
-{
- long where, size;
-
- /* XXX: on Unix systems, using fstat() probably makes more sense */
-
- where = ftell(f);
- fseek(f, 0, SEEK_END);
- size = ftell(f);
- fseek(f, where, SEEK_SET);
-
- return size;
-}
-
-static void load_linux(PCMachineState *pcms,
- FWCfgState *fw_cfg)
-{
- uint16_t protocol;
- int setup_size, kernel_size, initrd_size = 0, cmdline_size;
- uint32_t initrd_max;
- uint8_t header[8192], *setup, *kernel, *initrd_data;
- hwaddr real_addr, prot_addr, cmdline_addr, initrd_addr = 0;
- FILE *f;
- char *vmode;
- MachineState *machine = MACHINE(pcms);
- PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
- const char *kernel_filename = machine->kernel_filename;
- const char *initrd_filename = machine->initrd_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
-
- /* Align to 16 bytes as a paranoia measure */
- cmdline_size = (strlen(kernel_cmdline)+16) & ~15;
-
- /* load the kernel header */
- f = fopen(kernel_filename, "rb");
- if (!f || !(kernel_size = get_file_size(f)) ||
- fread(header, 1, MIN(ARRAY_SIZE(header), kernel_size), f) !=
- MIN(ARRAY_SIZE(header), kernel_size)) {
- fprintf(stderr, "qemu: could not load kernel '%s': %s\n",
- kernel_filename, strerror(errno));
- exit(1);
- }
-
- /* kernel protocol version */
-#if 0
- fprintf(stderr, "header magic: %#x\n", ldl_p(header+0x202));
-#endif
- if (ldl_p(header+0x202) == 0x53726448) {
- protocol = lduw_p(header+0x206);
- } else {
- /* This looks like a multiboot kernel. If it is, let's stop
- treating it like a Linux kernel. */
- if (load_multiboot(fw_cfg, f, kernel_filename, initrd_filename,
- kernel_cmdline, kernel_size, header)) {
- return;
- }
- protocol = 0;
- }
-
- if (protocol < 0x200 || !(header[0x211] & 0x01)) {
- /* Low kernel */
- real_addr = 0x90000;
- cmdline_addr = 0x9a000 - cmdline_size;
- prot_addr = 0x10000;
- } else if (protocol < 0x202) {
- /* High but ancient kernel */
- real_addr = 0x90000;
- cmdline_addr = 0x9a000 - cmdline_size;
- prot_addr = 0x100000;
- } else {
- /* High and recent kernel */
- real_addr = 0x10000;
- cmdline_addr = 0x20000;
- prot_addr = 0x100000;
- }
-
-#if 0
- fprintf(stderr,
- "qemu: real_addr = 0x" TARGET_FMT_plx "\n"
- "qemu: cmdline_addr = 0x" TARGET_FMT_plx "\n"
- "qemu: prot_addr = 0x" TARGET_FMT_plx "\n",
- real_addr,
- cmdline_addr,
- prot_addr);
-#endif
-
- /* highest address for loading the initrd */
- if (protocol >= 0x203) {
- initrd_max = ldl_p(header+0x22c);
- } else {
- initrd_max = 0x37ffffff;
- }
-
- if (initrd_max >= pcms->below_4g_mem_size - pcmc->acpi_data_size) {
- initrd_max = pcms->below_4g_mem_size - pcmc->acpi_data_size - 1;
- }
-
- fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_ADDR, cmdline_addr);
- fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, strlen(kernel_cmdline)+1);
- fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline);
-
- if (protocol >= 0x202) {
- stl_p(header+0x228, cmdline_addr);
- } else {
- stw_p(header+0x20, 0xA33F);
- stw_p(header+0x22, cmdline_addr-real_addr);
- }
-
- /* handle vga= parameter */
- vmode = strstr(kernel_cmdline, "vga=");
- if (vmode) {
- unsigned int video_mode;
- /* skip "vga=" */
- vmode += 4;
- if (!strncmp(vmode, "normal", 6)) {
- video_mode = 0xffff;
- } else if (!strncmp(vmode, "ext", 3)) {
- video_mode = 0xfffe;
- } else if (!strncmp(vmode, "ask", 3)) {
- video_mode = 0xfffd;
- } else {
- video_mode = strtol(vmode, NULL, 0);
- }
- stw_p(header+0x1fa, video_mode);
- }
-
- /* loader type */
- /* High nybble = B reserved for QEMU; low nybble is revision number.
- If this code is substantially changed, you may want to consider
- incrementing the revision. */
- if (protocol >= 0x200) {
- header[0x210] = 0xB0;
- }
- /* heap */
- if (protocol >= 0x201) {
- header[0x211] |= 0x80; /* CAN_USE_HEAP */
- stw_p(header+0x224, cmdline_addr-real_addr-0x200);
- }
-
- /* load initrd */
- if (initrd_filename) {
- if (protocol < 0x200) {
- fprintf(stderr, "qemu: linux kernel too old to load a ram disk\n");
- exit(1);
- }
-
- initrd_size = get_image_size(initrd_filename);
- if (initrd_size < 0) {
- fprintf(stderr, "qemu: error reading initrd %s: %s\n",
- initrd_filename, strerror(errno));
- exit(1);
- }
-
- initrd_addr = (initrd_max-initrd_size) & ~4095;
-
- initrd_data = g_malloc(initrd_size);
- load_image(initrd_filename, initrd_data);
-
- fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, initrd_addr);
- fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size);
- fw_cfg_add_bytes(fw_cfg, FW_CFG_INITRD_DATA, initrd_data, initrd_size);
-
- stl_p(header+0x218, initrd_addr);
- stl_p(header+0x21c, initrd_size);
- }
-
- /* load kernel and setup */
- setup_size = header[0x1f1];
- if (setup_size == 0) {
- setup_size = 4;
- }
- setup_size = (setup_size+1)*512;
- if (setup_size > kernel_size) {
- fprintf(stderr, "qemu: invalid kernel header\n");
- exit(1);
- }
- kernel_size -= setup_size;
-
- setup = g_malloc(setup_size);
- kernel = g_malloc(kernel_size);
- fseek(f, 0, SEEK_SET);
- if (fread(setup, 1, setup_size, f) != setup_size) {
- fprintf(stderr, "fread() failed\n");
- exit(1);
- }
- if (fread(kernel, 1, kernel_size, f) != kernel_size) {
- fprintf(stderr, "fread() failed\n");
- exit(1);
- }
- fclose(f);
- memcpy(setup, header, MIN(sizeof(header), setup_size));
-
- fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, prot_addr);
- fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
- fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA, kernel, kernel_size);
-
- fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_ADDR, real_addr);
- fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_SIZE, setup_size);
- fw_cfg_add_bytes(fw_cfg, FW_CFG_SETUP_DATA, setup, setup_size);
-
- option_rom[nb_option_roms].name = "linuxboot.bin";
- option_rom[nb_option_roms].bootindex = 0;
- nb_option_roms++;
-}
-
-#define NE2000_NB_MAX 6
-
-static const int ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360,
- 0x280, 0x380 };
-static const int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 };
-
-void pc_init_ne2k_isa(ISABus *bus, NICInfo *nd)
-{
- static int nb_ne2k = 0;
-
- if (nb_ne2k == NE2000_NB_MAX)
- return;
- isa_ne2000_init(bus, ne2000_io[nb_ne2k],
- ne2000_irq[nb_ne2k], nd);
- nb_ne2k++;
-}
-
-DeviceState *cpu_get_current_apic(void)
-{
- if (current_cpu) {
- X86CPU *cpu = X86_CPU(current_cpu);
- return cpu->apic_state;
- } else {
- return NULL;
- }
-}
-
-void pc_acpi_smi_interrupt(void *opaque, int irq, int level)
-{
- X86CPU *cpu = opaque;
-
- if (level) {
- cpu_interrupt(CPU(cpu), CPU_INTERRUPT_SMI);
- }
-}
-
-static X86CPU *pc_new_cpu(const char *cpu_model, int64_t apic_id,
- Error **errp)
-{
- X86CPU *cpu = NULL;
- Error *local_err = NULL;
-
- cpu = cpu_x86_create(cpu_model, &local_err);
- if (local_err != NULL) {
- goto out;
- }
-
- object_property_set_int(OBJECT(cpu), apic_id, "apic-id", &local_err);
- object_property_set_bool(OBJECT(cpu), true, "realized", &local_err);
-
-out:
- if (local_err) {
- error_propagate(errp, local_err);
- object_unref(OBJECT(cpu));
- cpu = NULL;
- }
- return cpu;
-}
-
-void pc_hot_add_cpu(const int64_t id, Error **errp)
-{
- X86CPU *cpu;
- MachineState *machine = MACHINE(qdev_get_machine());
- int64_t apic_id = x86_cpu_apic_id_from_index(id);
- Error *local_err = NULL;
-
- if (id < 0) {
- error_setg(errp, "Invalid CPU id: %" PRIi64, id);
- return;
- }
-
- if (cpu_exists(apic_id)) {
- error_setg(errp, "Unable to add CPU: %" PRIi64
- ", it already exists", id);
- return;
- }
-
- if (id >= max_cpus) {
- error_setg(errp, "Unable to add CPU: %" PRIi64
- ", max allowed: %d", id, max_cpus - 1);
- return;
- }
-
- if (apic_id >= ACPI_CPU_HOTPLUG_ID_LIMIT) {
- error_setg(errp, "Unable to add CPU: %" PRIi64
- ", resulting APIC ID (%" PRIi64 ") is too large",
- id, apic_id);
- return;
- }
-
- cpu = pc_new_cpu(machine->cpu_model, apic_id, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
- object_unref(OBJECT(cpu));
-}
-
-void pc_cpus_init(PCMachineState *pcms)
-{
- int i;
- X86CPU *cpu = NULL;
- MachineState *machine = MACHINE(pcms);
-
- /* init CPUs */
- if (machine->cpu_model == NULL) {
-#ifdef TARGET_X86_64
- machine->cpu_model = "qemu64";
-#else
- machine->cpu_model = "qemu32";
-#endif
- }
-
- /* Calculates the limit to CPU APIC ID values
- *
- * Limit for the APIC ID value, so that all
- * CPU APIC IDs are < pcms->apic_id_limit.
- *
- * This is used for FW_CFG_MAX_CPUS. See comments on bochs_bios_init().
- */
- pcms->apic_id_limit = x86_cpu_apic_id_from_index(max_cpus - 1) + 1;
- if (pcms->apic_id_limit > ACPI_CPU_HOTPLUG_ID_LIMIT) {
- error_report("max_cpus is too large. APIC ID of last CPU is %u",
- pcms->apic_id_limit - 1);
- exit(1);
- }
-
- pcms->possible_cpus = g_malloc0(sizeof(CPUArchIdList) +
- sizeof(CPUArchId) * max_cpus);
- for (i = 0; i < max_cpus; i++) {
- pcms->possible_cpus->cpus[i].arch_id = x86_cpu_apic_id_from_index(i);
- pcms->possible_cpus->len++;
- if (i < smp_cpus) {
- cpu = pc_new_cpu(machine->cpu_model, x86_cpu_apic_id_from_index(i),
- &error_fatal);
- pcms->possible_cpus->cpus[i].cpu = CPU(cpu);
- object_unref(OBJECT(cpu));
- }
- }
-
- /* tell smbios about cpuid version and features */
- smbios_set_cpuid(cpu->env.cpuid_version, cpu->env.features[FEAT_1_EDX]);
-}
-
-/* pci-info ROM file. Little endian format */
-typedef struct PcRomPciInfo {
- uint64_t w32_min;
- uint64_t w32_max;
- uint64_t w64_min;
- uint64_t w64_max;
-} PcRomPciInfo;
-
-static
-void pc_machine_done(Notifier *notifier, void *data)
-{
- PCMachineState *pcms = container_of(notifier,
- PCMachineState, machine_done);
- PCIBus *bus = pcms->bus;
-
- if (bus) {
- int extra_hosts = 0;
-
- QLIST_FOREACH(bus, &bus->child, sibling) {
- /* look for expander root buses */
- if (pci_bus_is_root(bus)) {
- extra_hosts++;
- }
- }
- if (extra_hosts && pcms->fw_cfg) {
- uint64_t *val = g_malloc(sizeof(*val));
- *val = cpu_to_le64(extra_hosts);
- fw_cfg_add_file(pcms->fw_cfg,
- "etc/extra-pci-roots", val, sizeof(*val));
- }
- }
-
- acpi_setup();
-}
-
-void pc_guest_info_init(PCMachineState *pcms)
-{
- int i, j;
-
- pcms->apic_xrupt_override = kvm_allows_irq0_override();
- pcms->numa_nodes = nb_numa_nodes;
- pcms->node_mem = g_malloc0(pcms->numa_nodes *
- sizeof *pcms->node_mem);
- for (i = 0; i < nb_numa_nodes; i++) {
- pcms->node_mem[i] = numa_info[i].node_mem;
- }
-
- pcms->node_cpu = g_malloc0(pcms->apic_id_limit *
- sizeof *pcms->node_cpu);
-
- for (i = 0; i < max_cpus; i++) {
- unsigned int apic_id = x86_cpu_apic_id_from_index(i);
- assert(apic_id < pcms->apic_id_limit);
- for (j = 0; j < nb_numa_nodes; j++) {
- if (test_bit(i, numa_info[j].node_cpu)) {
- pcms->node_cpu[apic_id] = j;
- break;
- }
- }
- }
-
- pcms->machine_done.notify = pc_machine_done;
- qemu_add_machine_init_done_notifier(&pcms->machine_done);
-}
-
-/* setup pci memory address space mapping into system address space */
-void pc_pci_as_mapping_init(Object *owner, MemoryRegion *system_memory,
- MemoryRegion *pci_address_space)
-{
- /* Set to lower priority than RAM */
- memory_region_add_subregion_overlap(system_memory, 0x0,
- pci_address_space, -1);
-}
-
-void pc_acpi_init(const char *default_dsdt)
-{
- char *filename;
-
- if (acpi_tables != NULL) {
- /* manually set via -acpitable, leave it alone */
- return;
- }
-
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, default_dsdt);
- if (filename == NULL) {
- fprintf(stderr, "WARNING: failed to find %s\n", default_dsdt);
- } else {
- QemuOpts *opts = qemu_opts_create(qemu_find_opts("acpi"), NULL, 0,
- &error_abort);
- Error *err = NULL;
-
- qemu_opt_set(opts, "file", filename, &error_abort);
-
- acpi_table_add_builtin(opts, &err);
- if (err) {
- error_reportf_err(err, "WARNING: failed to load %s: ",
- filename);
- }
- g_free(filename);
- }
-}
-
-void xen_load_linux(PCMachineState *pcms)
-{
- int i;
- FWCfgState *fw_cfg;
-
- assert(MACHINE(pcms)->kernel_filename != NULL);
-
- fw_cfg = fw_cfg_init_io(FW_CFG_IO_BASE);
- rom_set_fw(fw_cfg);
-
- load_linux(pcms, fw_cfg);
- for (i = 0; i < nb_option_roms; i++) {
- assert(!strcmp(option_rom[i].name, "linuxboot.bin") ||
- !strcmp(option_rom[i].name, "multiboot.bin"));
- rom_add_option(option_rom[i].name, option_rom[i].bootindex);
- }
- pcms->fw_cfg = fw_cfg;
-}
-
-void pc_memory_init(PCMachineState *pcms,
- MemoryRegion *system_memory,
- MemoryRegion *rom_memory,
- MemoryRegion **ram_memory)
-{
- int linux_boot, i;
- MemoryRegion *ram, *option_rom_mr;
- MemoryRegion *ram_below_4g, *ram_above_4g;
- FWCfgState *fw_cfg;
- MachineState *machine = MACHINE(pcms);
- PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
-
- assert(machine->ram_size == pcms->below_4g_mem_size +
- pcms->above_4g_mem_size);
-
- linux_boot = (machine->kernel_filename != NULL);
-
- /* Allocate RAM. We allocate it as a single memory region and use
- * aliases to address portions of it, mostly for backwards compatibility
- * with older qemus that used qemu_ram_alloc().
- */
- ram = g_malloc(sizeof(*ram));
- memory_region_allocate_system_memory(ram, NULL, "pc.ram",
- machine->ram_size);
- *ram_memory = ram;
- ram_below_4g = g_malloc(sizeof(*ram_below_4g));
- memory_region_init_alias(ram_below_4g, NULL, "ram-below-4g", ram,
- 0, pcms->below_4g_mem_size);
- memory_region_add_subregion(system_memory, 0, ram_below_4g);
- e820_add_entry(0, pcms->below_4g_mem_size, E820_RAM);
- if (pcms->above_4g_mem_size > 0) {
- ram_above_4g = g_malloc(sizeof(*ram_above_4g));
- memory_region_init_alias(ram_above_4g, NULL, "ram-above-4g", ram,
- pcms->below_4g_mem_size,
- pcms->above_4g_mem_size);
- memory_region_add_subregion(system_memory, 0x100000000ULL,
- ram_above_4g);
- e820_add_entry(0x100000000ULL, pcms->above_4g_mem_size, E820_RAM);
- }
-
- if (!pcmc->has_reserved_memory &&
- (machine->ram_slots ||
- (machine->maxram_size > machine->ram_size))) {
- MachineClass *mc = MACHINE_GET_CLASS(machine);
-
- error_report("\"-memory 'slots|maxmem'\" is not supported by: %s",
- mc->name);
- exit(EXIT_FAILURE);
- }
-
- /* initialize hotplug memory address space */
- if (pcmc->has_reserved_memory &&
- (machine->ram_size < machine->maxram_size)) {
- ram_addr_t hotplug_mem_size =
- machine->maxram_size - machine->ram_size;
-
- if (machine->ram_slots > ACPI_MAX_RAM_SLOTS) {
- error_report("unsupported amount of memory slots: %"PRIu64,
- machine->ram_slots);
- exit(EXIT_FAILURE);
- }
-
- if (QEMU_ALIGN_UP(machine->maxram_size,
- TARGET_PAGE_SIZE) != machine->maxram_size) {
- error_report("maximum memory size must by aligned to multiple of "
- "%d bytes", TARGET_PAGE_SIZE);
- exit(EXIT_FAILURE);
- }
-
- pcms->hotplug_memory.base =
- ROUND_UP(0x100000000ULL + pcms->above_4g_mem_size, 1ULL << 30);
-
- if (pcmc->enforce_aligned_dimm) {
- /* size hotplug region assuming 1G page max alignment per slot */
- hotplug_mem_size += (1ULL << 30) * machine->ram_slots;
- }
-
- if ((pcms->hotplug_memory.base + hotplug_mem_size) <
- hotplug_mem_size) {
- error_report("unsupported amount of maximum memory: " RAM_ADDR_FMT,
- machine->maxram_size);
- exit(EXIT_FAILURE);
- }
-
- memory_region_init(&pcms->hotplug_memory.mr, OBJECT(pcms),
- "hotplug-memory", hotplug_mem_size);
- memory_region_add_subregion(system_memory, pcms->hotplug_memory.base,
- &pcms->hotplug_memory.mr);
- }
-
- /* Initialize PC system firmware */
- pc_system_firmware_init(rom_memory, !pcmc->pci_enabled);
-
- option_rom_mr = g_malloc(sizeof(*option_rom_mr));
- memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE,
- &error_fatal);
- vmstate_register_ram_global(option_rom_mr);
- memory_region_add_subregion_overlap(rom_memory,
- PC_ROM_MIN_VGA,
- option_rom_mr,
- 1);
-
- fw_cfg = bochs_bios_init(&address_space_memory, pcms);
-
- rom_set_fw(fw_cfg);
-
- if (pcmc->has_reserved_memory && pcms->hotplug_memory.base) {
- uint64_t *val = g_malloc(sizeof(*val));
- PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
- uint64_t res_mem_end = pcms->hotplug_memory.base;
-
- if (!pcmc->broken_reserved_end) {
- res_mem_end += memory_region_size(&pcms->hotplug_memory.mr);
- }
- *val = cpu_to_le64(ROUND_UP(res_mem_end, 0x1ULL << 30));
- fw_cfg_add_file(fw_cfg, "etc/reserved-memory-end", val, sizeof(*val));
- }
-
- if (linux_boot) {
- load_linux(pcms, fw_cfg);
- }
-
- for (i = 0; i < nb_option_roms; i++) {
- rom_add_option(option_rom[i].name, option_rom[i].bootindex);
- }
- pcms->fw_cfg = fw_cfg;
-}
-
-qemu_irq pc_allocate_cpu_irq(void)
-{
- return qemu_allocate_irq(pic_irq_request, NULL, 0);
-}
-
-DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus)
-{
- DeviceState *dev = NULL;
-
- rom_set_order_override(FW_CFG_ORDER_OVERRIDE_VGA);
- if (pci_bus) {
- PCIDevice *pcidev = pci_vga_init(pci_bus);
- dev = pcidev ? &pcidev->qdev : NULL;
- } else if (isa_bus) {
- ISADevice *isadev = isa_vga_init(isa_bus);
- dev = isadev ? DEVICE(isadev) : NULL;
- }
- rom_reset_order_override();
- return dev;
-}
-
-static const MemoryRegionOps ioport80_io_ops = {
- .write = ioport80_write,
- .read = ioport80_read,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
-};
-
-static const MemoryRegionOps ioportF0_io_ops = {
- .write = ioportF0_write,
- .read = ioportF0_read,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
-};
-
-void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
- ISADevice **rtc_state,
- bool create_fdctrl,
- bool no_vmport,
- uint32_t hpet_irqs)
-{
- int i;
- DriveInfo *fd[MAX_FD];
- DeviceState *hpet = NULL;
- int pit_isa_irq = 0;
- qemu_irq pit_alt_irq = NULL;
- qemu_irq rtc_irq = NULL;
- qemu_irq *a20_line;
- ISADevice *i8042, *port92, *vmmouse, *pit = NULL;
- MemoryRegion *ioport80_io = g_new(MemoryRegion, 1);
- MemoryRegion *ioportF0_io = g_new(MemoryRegion, 1);
-
- memory_region_init_io(ioport80_io, NULL, &ioport80_io_ops, NULL, "ioport80", 1);
- memory_region_add_subregion(isa_bus->address_space_io, 0x80, ioport80_io);
-
- memory_region_init_io(ioportF0_io, NULL, &ioportF0_io_ops, NULL, "ioportF0", 1);
- memory_region_add_subregion(isa_bus->address_space_io, 0xf0, ioportF0_io);
-
- /*
- * Check if an HPET shall be created.
- *
- * Without KVM_CAP_PIT_STATE2, we cannot switch off the in-kernel PIT
- * when the HPET wants to take over. Thus we have to disable the latter.
- */
- if (!no_hpet && (!kvm_irqchip_in_kernel() || kvm_has_pit_state2())) {
- /* In order to set property, here not using sysbus_try_create_simple */
- hpet = qdev_try_create(NULL, TYPE_HPET);
- if (hpet) {
- /* For pc-piix-*, hpet's intcap is always IRQ2. For pc-q35-1.7
- * and earlier, use IRQ2 for compat. Otherwise, use IRQ16~23,
- * IRQ8 and IRQ2.
- */
- uint8_t compat = object_property_get_int(OBJECT(hpet),
- HPET_INTCAP, NULL);
- if (!compat) {
- qdev_prop_set_uint32(hpet, HPET_INTCAP, hpet_irqs);
- }
- qdev_init_nofail(hpet);
- sysbus_mmio_map(SYS_BUS_DEVICE(hpet), 0, HPET_BASE);
-
- for (i = 0; i < GSI_NUM_PINS; i++) {
- sysbus_connect_irq(SYS_BUS_DEVICE(hpet), i, gsi[i]);
- }
- pit_isa_irq = -1;
- pit_alt_irq = qdev_get_gpio_in(hpet, HPET_LEGACY_PIT_INT);
- rtc_irq = qdev_get_gpio_in(hpet, HPET_LEGACY_RTC_INT);
- }
- }
- *rtc_state = rtc_init(isa_bus, 2000, rtc_irq);
-
- qemu_register_boot_set(pc_boot_set, *rtc_state);
-
- if (!xen_enabled()) {
- if (kvm_pit_in_kernel()) {
- pit = kvm_pit_init(isa_bus, 0x40);
- } else {
- pit = pit_init(isa_bus, 0x40, pit_isa_irq, pit_alt_irq);
- }
- if (hpet) {
- /* connect PIT to output control line of the HPET */
- qdev_connect_gpio_out(hpet, 0, qdev_get_gpio_in(DEVICE(pit), 0));
- }
- pcspk_init(isa_bus, pit);
- }
-
- serial_hds_isa_init(isa_bus, MAX_SERIAL_PORTS);
- parallel_hds_isa_init(isa_bus, MAX_PARALLEL_PORTS);
-
- a20_line = qemu_allocate_irqs(handle_a20_line_change, first_cpu, 2);
- i8042 = isa_create_simple(isa_bus, "i8042");
- i8042_setup_a20_line(i8042, &a20_line[0]);
- if (!no_vmport) {
- vmport_init(isa_bus);
- vmmouse = isa_try_create(isa_bus, "vmmouse");
- } else {
- vmmouse = NULL;
- }
- if (vmmouse) {
- DeviceState *dev = DEVICE(vmmouse);
- qdev_prop_set_ptr(dev, "ps2_mouse", i8042);
- qdev_init_nofail(dev);
- }
- port92 = isa_create_simple(isa_bus, "port92");
- port92_init(port92, &a20_line[1]);
-
- DMA_init(isa_bus, 0);
-
- for(i = 0; i < MAX_FD; i++) {
- fd[i] = drive_get(IF_FLOPPY, 0, i);
- create_fdctrl |= !!fd[i];
- }
- if (create_fdctrl) {
- fdctrl_init_isa(isa_bus, fd);
- }
-}
-
-void pc_nic_init(ISABus *isa_bus, PCIBus *pci_bus)
-{
- int i;
-
- rom_set_order_override(FW_CFG_ORDER_OVERRIDE_NIC);
- for (i = 0; i < nb_nics; i++) {
- NICInfo *nd = &nd_table[i];
-
- if (!pci_bus || (nd->model && strcmp(nd->model, "ne2k_isa") == 0)) {
- pc_init_ne2k_isa(isa_bus, nd);
- } else {
- pci_nic_init_nofail(nd, pci_bus, "e1000", NULL);
- }
- }
- rom_reset_order_override();
-}
-
-void pc_pci_device_init(PCIBus *pci_bus)
-{
- int max_bus;
- int bus;
-
- max_bus = drive_get_max_bus(IF_SCSI);
- for (bus = 0; bus <= max_bus; bus++) {
- pci_create_simple(pci_bus, -1, "lsi53c895a");
- }
-}
-
-void ioapic_init_gsi(GSIState *gsi_state, const char *parent_name)
-{
- DeviceState *dev;
- SysBusDevice *d;
- unsigned int i;
-
- if (kvm_ioapic_in_kernel()) {
- dev = qdev_create(NULL, "kvm-ioapic");
- } else {
- dev = qdev_create(NULL, "ioapic");
- }
- if (parent_name) {
- object_property_add_child(object_resolve_path(parent_name, NULL),
- "ioapic", OBJECT(dev), NULL);
- }
- qdev_init_nofail(dev);
- d = SYS_BUS_DEVICE(dev);
- sysbus_mmio_map(d, 0, IO_APIC_DEFAULT_ADDRESS);
-
- for (i = 0; i < IOAPIC_NUM_PINS; i++) {
- gsi_state->ioapic_irq[i] = qdev_get_gpio_in(dev, i);
- }
-}
-
-static void pc_dimm_plug(HotplugHandler *hotplug_dev,
- DeviceState *dev, Error **errp)
-{
- HotplugHandlerClass *hhc;
- Error *local_err = NULL;
- PCMachineState *pcms = PC_MACHINE(hotplug_dev);
- PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
- PCDIMMDevice *dimm = PC_DIMM(dev);
- PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm);
- MemoryRegion *mr = ddc->get_memory_region(dimm);
- uint64_t align = TARGET_PAGE_SIZE;
-
- if (memory_region_get_alignment(mr) && pcmc->enforce_aligned_dimm) {
- align = memory_region_get_alignment(mr);
- }
-
- if (!pcms->acpi_dev) {
- error_setg(&local_err,
- "memory hotplug is not enabled: missing acpi device");
- goto out;
- }
-
- pc_dimm_memory_plug(dev, &pcms->hotplug_memory, mr, align, &local_err);
- if (local_err) {
- goto out;
- }
-
- hhc = HOTPLUG_HANDLER_GET_CLASS(pcms->acpi_dev);
- hhc->plug(HOTPLUG_HANDLER(pcms->acpi_dev), dev, &error_abort);
-out:
- error_propagate(errp, local_err);
-}
-
-static void pc_dimm_unplug_request(HotplugHandler *hotplug_dev,
- DeviceState *dev, Error **errp)
-{
- HotplugHandlerClass *hhc;
- Error *local_err = NULL;
- PCMachineState *pcms = PC_MACHINE(hotplug_dev);
-
- if (!pcms->acpi_dev) {
- error_setg(&local_err,
- "memory hotplug is not enabled: missing acpi device");
- goto out;
- }
-
- hhc = HOTPLUG_HANDLER_GET_CLASS(pcms->acpi_dev);
- hhc->unplug_request(HOTPLUG_HANDLER(pcms->acpi_dev), dev, &local_err);
-
-out:
- error_propagate(errp, local_err);
-}
-
-static void pc_dimm_unplug(HotplugHandler *hotplug_dev,
- DeviceState *dev, Error **errp)
-{
- PCMachineState *pcms = PC_MACHINE(hotplug_dev);
- PCDIMMDevice *dimm = PC_DIMM(dev);
- PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm);
- MemoryRegion *mr = ddc->get_memory_region(dimm);
- HotplugHandlerClass *hhc;
- Error *local_err = NULL;
-
- hhc = HOTPLUG_HANDLER_GET_CLASS(pcms->acpi_dev);
- hhc->unplug(HOTPLUG_HANDLER(pcms->acpi_dev), dev, &local_err);
-
- if (local_err) {
- goto out;
- }
-
- pc_dimm_memory_unplug(dev, &pcms->hotplug_memory, mr);
- object_unparent(OBJECT(dev));
-
- out:
- error_propagate(errp, local_err);
-}
-
-static int pc_apic_cmp(const void *a, const void *b)
-{
- CPUArchId *apic_a = (CPUArchId *)a;
- CPUArchId *apic_b = (CPUArchId *)b;
-
- return apic_a->arch_id - apic_b->arch_id;
-}
-
-static void pc_cpu_plug(HotplugHandler *hotplug_dev,
- DeviceState *dev, Error **errp)
-{
- CPUClass *cc = CPU_GET_CLASS(dev);
- CPUArchId apic_id, *found_cpu;
- HotplugHandlerClass *hhc;
- Error *local_err = NULL;
- PCMachineState *pcms = PC_MACHINE(hotplug_dev);
-
- if (!dev->hotplugged) {
- goto out;
- }
-
- if (!pcms->acpi_dev) {
- error_setg(&local_err,
- "cpu hotplug is not enabled: missing acpi device");
- goto out;
- }
-
- hhc = HOTPLUG_HANDLER_GET_CLASS(pcms->acpi_dev);
- hhc->plug(HOTPLUG_HANDLER(pcms->acpi_dev), dev, &local_err);
- if (local_err) {
- goto out;
- }
-
- /* increment the number of CPUs */
- rtc_set_memory(pcms->rtc, 0x5f, rtc_get_memory(pcms->rtc, 0x5f) + 1);
-
- apic_id.arch_id = cc->get_arch_id(CPU(dev));
- found_cpu = bsearch(&apic_id, pcms->possible_cpus->cpus,
- pcms->possible_cpus->len, sizeof(*pcms->possible_cpus->cpus),
- pc_apic_cmp);
- assert(found_cpu);
- found_cpu->cpu = CPU(dev);
-out:
- error_propagate(errp, local_err);
-}
-
-static void pc_machine_device_plug_cb(HotplugHandler *hotplug_dev,
- DeviceState *dev, Error **errp)
-{
- if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
- pc_dimm_plug(hotplug_dev, dev, errp);
- } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
- pc_cpu_plug(hotplug_dev, dev, errp);
- }
-}
-
-static void pc_machine_device_unplug_request_cb(HotplugHandler *hotplug_dev,
- DeviceState *dev, Error **errp)
-{
- if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
- pc_dimm_unplug_request(hotplug_dev, dev, errp);
- } else {
- error_setg(errp, "acpi: device unplug request for not supported device"
- " type: %s", object_get_typename(OBJECT(dev)));
- }
-}
-
-static void pc_machine_device_unplug_cb(HotplugHandler *hotplug_dev,
- DeviceState *dev, Error **errp)
-{
- if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
- pc_dimm_unplug(hotplug_dev, dev, errp);
- } else {
- error_setg(errp, "acpi: device unplug for not supported device"
- " type: %s", object_get_typename(OBJECT(dev)));
- }
-}
-
-static HotplugHandler *pc_get_hotpug_handler(MachineState *machine,
- DeviceState *dev)
-{
- PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(machine);
-
- if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) ||
- object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
- return HOTPLUG_HANDLER(machine);
- }
-
- return pcmc->get_hotplug_handler ?
- pcmc->get_hotplug_handler(machine, dev) : NULL;
-}
-
-static void
-pc_machine_get_hotplug_memory_region_size(Object *obj, Visitor *v,
- const char *name, void *opaque,
- Error **errp)
-{
- PCMachineState *pcms = PC_MACHINE(obj);
- int64_t value = memory_region_size(&pcms->hotplug_memory.mr);
-
- visit_type_int(v, name, &value, errp);
-}
-
-static void pc_machine_get_max_ram_below_4g(Object *obj, Visitor *v,
- const char *name, void *opaque,
- Error **errp)
-{
- PCMachineState *pcms = PC_MACHINE(obj);
- uint64_t value = pcms->max_ram_below_4g;
-
- visit_type_size(v, name, &value, errp);
-}
-
-static void pc_machine_set_max_ram_below_4g(Object *obj, Visitor *v,
- const char *name, void *opaque,
- Error **errp)
-{
- PCMachineState *pcms = PC_MACHINE(obj);
- Error *error = NULL;
- uint64_t value;
-
- visit_type_size(v, name, &value, &error);
- if (error) {
- error_propagate(errp, error);
- return;
- }
- if (value > (1ULL << 32)) {
- error_setg(&error,
- "Machine option 'max-ram-below-4g=%"PRIu64
- "' expects size less than or equal to 4G", value);
- error_propagate(errp, error);
- return;
- }
-
- if (value < (1ULL << 20)) {
- error_report("Warning: small max_ram_below_4g(%"PRIu64
- ") less than 1M. BIOS may not work..",
- value);
- }
-
- pcms->max_ram_below_4g = value;
-}
-
-static void pc_machine_get_vmport(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- PCMachineState *pcms = PC_MACHINE(obj);
- OnOffAuto vmport = pcms->vmport;
-
- visit_type_OnOffAuto(v, name, &vmport, errp);
-}
-
-static void pc_machine_set_vmport(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- PCMachineState *pcms = PC_MACHINE(obj);
-
- visit_type_OnOffAuto(v, name, &pcms->vmport, errp);
-}
-
-bool pc_machine_is_smm_enabled(PCMachineState *pcms)
-{
- bool smm_available = false;
-
- if (pcms->smm == ON_OFF_AUTO_OFF) {
- return false;
- }
-
- if (tcg_enabled() || qtest_enabled()) {
- smm_available = true;
- } else if (kvm_enabled()) {
- smm_available = kvm_has_smm();
- }
-
- if (smm_available) {
- return true;
- }
-
- if (pcms->smm == ON_OFF_AUTO_ON) {
- error_report("System Management Mode not supported by this hypervisor.");
- exit(1);
- }
- return false;
-}
-
-static void pc_machine_get_smm(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- PCMachineState *pcms = PC_MACHINE(obj);
- OnOffAuto smm = pcms->smm;
-
- visit_type_OnOffAuto(v, name, &smm, errp);
-}
-
-static void pc_machine_set_smm(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- PCMachineState *pcms = PC_MACHINE(obj);
-
- visit_type_OnOffAuto(v, name, &pcms->smm, errp);
-}
-
-static bool pc_machine_get_nvdimm(Object *obj, Error **errp)
-{
- PCMachineState *pcms = PC_MACHINE(obj);
-
- return pcms->acpi_nvdimm_state.is_enabled;
-}
-
-static void pc_machine_set_nvdimm(Object *obj, bool value, Error **errp)
-{
- PCMachineState *pcms = PC_MACHINE(obj);
-
- pcms->acpi_nvdimm_state.is_enabled = value;
-}
-
-static void pc_machine_initfn(Object *obj)
-{
- PCMachineState *pcms = PC_MACHINE(obj);
-
- object_property_add(obj, PC_MACHINE_MEMHP_REGION_SIZE, "int",
- pc_machine_get_hotplug_memory_region_size,
- NULL, NULL, NULL, &error_abort);
-
- pcms->max_ram_below_4g = 1ULL << 32; /* 4G */
- object_property_add(obj, PC_MACHINE_MAX_RAM_BELOW_4G, "size",
- pc_machine_get_max_ram_below_4g,
- pc_machine_set_max_ram_below_4g,
- NULL, NULL, &error_abort);
- object_property_set_description(obj, PC_MACHINE_MAX_RAM_BELOW_4G,
- "Maximum ram below the 4G boundary (32bit boundary)",
- &error_abort);
-
- pcms->smm = ON_OFF_AUTO_AUTO;
- object_property_add(obj, PC_MACHINE_SMM, "OnOffAuto",
- pc_machine_get_smm,
- pc_machine_set_smm,
- NULL, NULL, &error_abort);
- object_property_set_description(obj, PC_MACHINE_SMM,
- "Enable SMM (pc & q35)",
- &error_abort);
-
- pcms->vmport = ON_OFF_AUTO_AUTO;
- object_property_add(obj, PC_MACHINE_VMPORT, "OnOffAuto",
- pc_machine_get_vmport,
- pc_machine_set_vmport,
- NULL, NULL, &error_abort);
- object_property_set_description(obj, PC_MACHINE_VMPORT,
- "Enable vmport (pc & q35)",
- &error_abort);
-
- /* nvdimm is disabled on default. */
- pcms->acpi_nvdimm_state.is_enabled = false;
- object_property_add_bool(obj, PC_MACHINE_NVDIMM, pc_machine_get_nvdimm,
- pc_machine_set_nvdimm, &error_abort);
-}
-
-static void pc_machine_reset(void)
-{
- CPUState *cs;
- X86CPU *cpu;
-
- qemu_devices_reset();
-
- /* Reset APIC after devices have been reset to cancel
- * any changes that qemu_devices_reset() might have done.
- */
- CPU_FOREACH(cs) {
- cpu = X86_CPU(cs);
-
- if (cpu->apic_state) {
- device_reset(cpu->apic_state);
- }
- }
-}
-
-static unsigned pc_cpu_index_to_socket_id(unsigned cpu_index)
-{
- X86CPUTopoInfo topo;
- x86_topo_ids_from_idx(smp_cores, smp_threads, cpu_index,
- &topo);
- return topo.pkg_id;
-}
-
-static CPUArchIdList *pc_possible_cpu_arch_ids(MachineState *machine)
-{
- PCMachineState *pcms = PC_MACHINE(machine);
- int len = sizeof(CPUArchIdList) +
- sizeof(CPUArchId) * (pcms->possible_cpus->len);
- CPUArchIdList *list = g_malloc(len);
-
- memcpy(list, pcms->possible_cpus, len);
- return list;
-}
-
-static void pc_machine_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
- PCMachineClass *pcmc = PC_MACHINE_CLASS(oc);
- HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
-
- pcmc->get_hotplug_handler = mc->get_hotplug_handler;
- pcmc->pci_enabled = true;
- pcmc->has_acpi_build = true;
- pcmc->rsdp_in_ram = true;
- pcmc->smbios_defaults = true;
- pcmc->smbios_uuid_encoded = true;
- pcmc->gigabyte_align = true;
- pcmc->has_reserved_memory = true;
- pcmc->kvmclock_enabled = true;
- pcmc->enforce_aligned_dimm = true;
- /* BIOS ACPI tables: 128K. Other BIOS datastructures: less than 4K reported
- * to be used at the moment, 32K should be enough for a while. */
- pcmc->acpi_data_size = 0x20000 + 0x8000;
- pcmc->save_tsc_khz = true;
- mc->get_hotplug_handler = pc_get_hotpug_handler;
- mc->cpu_index_to_socket_id = pc_cpu_index_to_socket_id;
- mc->possible_cpu_arch_ids = pc_possible_cpu_arch_ids;
- mc->default_boot_order = "cad";
- mc->hot_add_cpu = pc_hot_add_cpu;
- mc->max_cpus = 255;
- mc->reset = pc_machine_reset;
- hc->plug = pc_machine_device_plug_cb;
- hc->unplug_request = pc_machine_device_unplug_request_cb;
- hc->unplug = pc_machine_device_unplug_cb;
-}
-
-static const TypeInfo pc_machine_info = {
- .name = TYPE_PC_MACHINE,
- .parent = TYPE_MACHINE,
- .abstract = true,
- .instance_size = sizeof(PCMachineState),
- .instance_init = pc_machine_initfn,
- .class_size = sizeof(PCMachineClass),
- .class_init = pc_machine_class_init,
- .interfaces = (InterfaceInfo[]) {
- { TYPE_HOTPLUG_HANDLER },
- { }
- },
-};
-
-static void pc_machine_register_types(void)
-{
- type_register_static(&pc_machine_info);
-}
-
-type_init(pc_machine_register_types)
diff --git a/qemu/hw/i386/pc_piix.c b/qemu/hw/i386/pc_piix.c
deleted file mode 100644
index 7f50116bc..000000000
--- a/qemu/hw/i386/pc_piix.c
+++ /dev/null
@@ -1,1062 +0,0 @@
-/*
- * QEMU PC System Emulator
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include <glib.h>
-
-#include "hw/hw.h"
-#include "hw/loader.h"
-#include "hw/i386/pc.h"
-#include "hw/i386/apic.h"
-#include "hw/smbios/smbios.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/pci_ids.h"
-#include "hw/usb.h"
-#include "net/net.h"
-#include "hw/boards.h"
-#include "hw/ide.h"
-#include "sysemu/kvm.h"
-#include "hw/kvm/clock.h"
-#include "sysemu/sysemu.h"
-#include "hw/sysbus.h"
-#include "sysemu/arch_init.h"
-#include "sysemu/block-backend.h"
-#include "hw/i2c/smbus.h"
-#include "hw/xen/xen.h"
-#include "exec/memory.h"
-#include "exec/address-spaces.h"
-#include "hw/acpi/acpi.h"
-#include "cpu.h"
-#include "qemu/error-report.h"
-#ifdef CONFIG_XEN
-#include <xen/hvm/hvm_info_table.h>
-#include "hw/xen/xen_pt.h"
-#endif
-#include "migration/migration.h"
-#include "kvm_i386.h"
-
-#define MAX_IDE_BUS 2
-
-static const int ide_iobase[MAX_IDE_BUS] = { 0x1f0, 0x170 };
-static const int ide_iobase2[MAX_IDE_BUS] = { 0x3f6, 0x376 };
-static const int ide_irq[MAX_IDE_BUS] = { 14, 15 };
-
-/* PC hardware initialisation */
-static void pc_init1(MachineState *machine,
- const char *host_type, const char *pci_type)
-{
- PCMachineState *pcms = PC_MACHINE(machine);
- PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
- MemoryRegion *system_memory = get_system_memory();
- MemoryRegion *system_io = get_system_io();
- int i;
- PCIBus *pci_bus;
- ISABus *isa_bus;
- PCII440FXState *i440fx_state;
- int piix3_devfn = -1;
- qemu_irq *gsi;
- qemu_irq *i8259;
- qemu_irq smi_irq;
- GSIState *gsi_state;
- DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
- BusState *idebus[MAX_IDE_BUS];
- ISADevice *rtc_state;
- MemoryRegion *ram_memory;
- MemoryRegion *pci_memory;
- MemoryRegion *rom_memory;
- ram_addr_t lowmem;
-
- /* Check whether RAM fits below 4G (leaving 1/2 GByte for IO memory).
- * If it doesn't, we need to split it in chunks below and above 4G.
- * In any case, try to make sure that guest addresses aligned at
- * 1G boundaries get mapped to host addresses aligned at 1G boundaries.
- * For old machine types, use whatever split we used historically to avoid
- * breaking migration.
- */
- if (machine->ram_size >= 0xe0000000) {
- lowmem = pcmc->gigabyte_align ? 0xc0000000 : 0xe0000000;
- } else {
- lowmem = 0xe0000000;
- }
-
- /* Handle the machine opt max-ram-below-4g. It is basically doing
- * min(qemu limit, user limit).
- */
- if (lowmem > pcms->max_ram_below_4g) {
- lowmem = pcms->max_ram_below_4g;
- if (machine->ram_size - lowmem > lowmem &&
- lowmem & ((1ULL << 30) - 1)) {
- error_report("Warning: Large machine and max_ram_below_4g(%"PRIu64
- ") not a multiple of 1G; possible bad performance.",
- pcms->max_ram_below_4g);
- }
- }
-
- if (machine->ram_size >= lowmem) {
- pcms->above_4g_mem_size = machine->ram_size - lowmem;
- pcms->below_4g_mem_size = lowmem;
- } else {
- pcms->above_4g_mem_size = 0;
- pcms->below_4g_mem_size = machine->ram_size;
- }
-
- if (xen_enabled()) {
- xen_hvm_init(pcms, &ram_memory);
- }
-
- pc_cpus_init(pcms);
-
- if (kvm_enabled() && pcmc->kvmclock_enabled) {
- kvmclock_create();
- }
-
- if (pcmc->pci_enabled) {
- pci_memory = g_new(MemoryRegion, 1);
- memory_region_init(pci_memory, NULL, "pci", UINT64_MAX);
- rom_memory = pci_memory;
- } else {
- pci_memory = NULL;
- rom_memory = system_memory;
- }
-
- pc_guest_info_init(pcms);
-
- if (pcmc->smbios_defaults) {
- MachineClass *mc = MACHINE_GET_CLASS(machine);
- /* These values are guest ABI, do not change */
- smbios_set_defaults("QEMU", "Standard PC (i440FX + PIIX, 1996)",
- mc->name, pcmc->smbios_legacy_mode,
- pcmc->smbios_uuid_encoded,
- SMBIOS_ENTRY_POINT_21);
- }
-
- /* allocate ram and load rom/bios */
- if (!xen_enabled()) {
- pc_memory_init(pcms, system_memory,
- rom_memory, &ram_memory);
- } else if (machine->kernel_filename != NULL) {
- /* For xen HVM direct kernel boot, load linux here */
- xen_load_linux(pcms);
- }
-
- gsi_state = g_malloc0(sizeof(*gsi_state));
- if (kvm_ioapic_in_kernel()) {
- kvm_pc_setup_irq_routing(pcmc->pci_enabled);
- gsi = qemu_allocate_irqs(kvm_pc_gsi_handler, gsi_state,
- GSI_NUM_PINS);
- } else {
- gsi = qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS);
- }
-
- if (pcmc->pci_enabled) {
- pci_bus = i440fx_init(host_type,
- pci_type,
- &i440fx_state, &piix3_devfn, &isa_bus, gsi,
- system_memory, system_io, machine->ram_size,
- pcms->below_4g_mem_size,
- pcms->above_4g_mem_size,
- pci_memory, ram_memory);
- pcms->bus = pci_bus;
- } else {
- pci_bus = NULL;
- i440fx_state = NULL;
- isa_bus = isa_bus_new(NULL, get_system_memory(), system_io,
- &error_abort);
- no_hpet = 1;
- }
- isa_bus_irqs(isa_bus, gsi);
-
- if (kvm_pic_in_kernel()) {
- i8259 = kvm_i8259_init(isa_bus);
- } else if (xen_enabled()) {
- i8259 = xen_interrupt_controller_init();
- } else {
- i8259 = i8259_init(isa_bus, pc_allocate_cpu_irq());
- }
-
- for (i = 0; i < ISA_NUM_IRQS; i++) {
- gsi_state->i8259_irq[i] = i8259[i];
- }
- g_free(i8259);
- if (pcmc->pci_enabled) {
- ioapic_init_gsi(gsi_state, "i440fx");
- }
-
- pc_register_ferr_irq(gsi[13]);
-
- pc_vga_init(isa_bus, pcmc->pci_enabled ? pci_bus : NULL);
-
- assert(pcms->vmport != ON_OFF_AUTO__MAX);
- if (pcms->vmport == ON_OFF_AUTO_AUTO) {
- pcms->vmport = xen_enabled() ? ON_OFF_AUTO_OFF : ON_OFF_AUTO_ON;
- }
-
- /* init basic PC hardware */
- pc_basic_device_init(isa_bus, gsi, &rtc_state, true,
- (pcms->vmport != ON_OFF_AUTO_ON), 0x4);
-
- pc_nic_init(isa_bus, pci_bus);
-
- ide_drive_get(hd, ARRAY_SIZE(hd));
- if (pcmc->pci_enabled) {
- PCIDevice *dev;
- if (xen_enabled()) {
- dev = pci_piix3_xen_ide_init(pci_bus, hd, piix3_devfn + 1);
- } else {
- dev = pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1);
- }
- idebus[0] = qdev_get_child_bus(&dev->qdev, "ide.0");
- idebus[1] = qdev_get_child_bus(&dev->qdev, "ide.1");
- } else {
- for(i = 0; i < MAX_IDE_BUS; i++) {
- ISADevice *dev;
- char busname[] = "ide.0";
- dev = isa_ide_init(isa_bus, ide_iobase[i], ide_iobase2[i],
- ide_irq[i],
- hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]);
- /*
- * The ide bus name is ide.0 for the first bus and ide.1 for the
- * second one.
- */
- busname[4] = '0' + i;
- idebus[i] = qdev_get_child_bus(DEVICE(dev), busname);
- }
- }
-
- pc_cmos_init(pcms, idebus[0], idebus[1], rtc_state);
-
- if (pcmc->pci_enabled && usb_enabled()) {
- pci_create_simple(pci_bus, piix3_devfn + 2, "piix3-usb-uhci");
- }
-
- if (pcmc->pci_enabled && acpi_enabled) {
- DeviceState *piix4_pm;
- I2CBus *smbus;
-
- smi_irq = qemu_allocate_irq(pc_acpi_smi_interrupt, first_cpu, 0);
- /* TODO: Populate SPD eeprom data. */
- smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100,
- gsi[9], smi_irq,
- pc_machine_is_smm_enabled(pcms),
- &piix4_pm);
- smbus_eeprom_init(smbus, 8, NULL, 0);
-
- object_property_add_link(OBJECT(machine), PC_MACHINE_ACPI_DEVICE_PROP,
- TYPE_HOTPLUG_HANDLER,
- (Object **)&pcms->acpi_dev,
- object_property_allow_set_link,
- OBJ_PROP_LINK_UNREF_ON_RELEASE, &error_abort);
- object_property_set_link(OBJECT(machine), OBJECT(piix4_pm),
- PC_MACHINE_ACPI_DEVICE_PROP, &error_abort);
- }
-
- if (pcmc->pci_enabled) {
- pc_pci_device_init(pci_bus);
- }
-
- if (pcms->acpi_nvdimm_state.is_enabled) {
- nvdimm_init_acpi_state(&pcms->acpi_nvdimm_state, system_io,
- pcms->fw_cfg, OBJECT(pcms));
- }
-}
-
-/* Looking for a pc_compat_2_4() function? It doesn't exist.
- * pc_compat_*() functions that run on machine-init time and
- * change global QEMU state are deprecated. Please don't create
- * one, and implement any pc-*-2.4 (and newer) compat code in
- * HW_COMPAT_*, PC_COMPAT_*, or * pc_*_machine_options().
- */
-
-static void pc_compat_2_3(MachineState *machine)
-{
- PCMachineState *pcms = PC_MACHINE(machine);
- savevm_skip_section_footers();
- if (kvm_enabled()) {
- pcms->smm = ON_OFF_AUTO_OFF;
- }
- global_state_set_optional();
- savevm_skip_configuration();
-}
-
-static void pc_compat_2_2(MachineState *machine)
-{
- pc_compat_2_3(machine);
- machine->suppress_vmdesc = true;
-}
-
-static void pc_compat_2_1(MachineState *machine)
-{
- pc_compat_2_2(machine);
- x86_cpu_change_kvm_default("svm", NULL);
-}
-
-static void pc_compat_2_0(MachineState *machine)
-{
- pc_compat_2_1(machine);
-}
-
-static void pc_compat_1_7(MachineState *machine)
-{
- pc_compat_2_0(machine);
- x86_cpu_change_kvm_default("x2apic", NULL);
-}
-
-static void pc_compat_1_6(MachineState *machine)
-{
- pc_compat_1_7(machine);
-}
-
-static void pc_compat_1_5(MachineState *machine)
-{
- pc_compat_1_6(machine);
-}
-
-static void pc_compat_1_4(MachineState *machine)
-{
- pc_compat_1_5(machine);
-}
-
-static void pc_compat_1_3(MachineState *machine)
-{
- pc_compat_1_4(machine);
- enable_compat_apic_id_mode();
-}
-
-/* PC compat function for pc-0.14 to pc-1.2 */
-static void pc_compat_1_2(MachineState *machine)
-{
- pc_compat_1_3(machine);
- x86_cpu_change_kvm_default("kvm-pv-eoi", NULL);
-}
-
-/* PC compat function for pc-0.10 to pc-0.13 */
-static void pc_compat_0_13(MachineState *machine)
-{
- pc_compat_1_2(machine);
-}
-
-static void pc_init_isa(MachineState *machine)
-{
- if (!machine->cpu_model) {
- machine->cpu_model = "486";
- }
- x86_cpu_change_kvm_default("kvm-pv-eoi", NULL);
- enable_compat_apic_id_mode();
- pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, TYPE_I440FX_PCI_DEVICE);
-}
-
-#ifdef CONFIG_XEN
-static void pc_xen_hvm_init_pci(MachineState *machine)
-{
- const char *pci_type = has_igd_gfx_passthru ?
- TYPE_IGD_PASSTHROUGH_I440FX_PCI_DEVICE : TYPE_I440FX_PCI_DEVICE;
-
- pc_init1(machine,
- TYPE_I440FX_PCI_HOST_BRIDGE,
- pci_type);
-}
-
-static void pc_xen_hvm_init(MachineState *machine)
-{
- PCIBus *bus;
-
- if (!xen_enabled()) {
- error_report("xenfv machine requires the xen accelerator");
- exit(1);
- }
-
- pc_xen_hvm_init_pci(machine);
-
- bus = pci_find_primary_bus();
- if (bus != NULL) {
- pci_create_simple(bus, -1, "xen-platform");
- }
-}
-#endif
-
-#define DEFINE_I440FX_MACHINE(suffix, name, compatfn, optionfn) \
- static void pc_init_##suffix(MachineState *machine) \
- { \
- void (*compat)(MachineState *m) = (compatfn); \
- if (compat) { \
- compat(machine); \
- } \
- pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, \
- TYPE_I440FX_PCI_DEVICE); \
- } \
- DEFINE_PC_MACHINE(suffix, name, pc_init_##suffix, optionfn)
-
-static void pc_i440fx_machine_options(MachineClass *m)
-{
- m->family = "pc_piix";
- m->desc = "Standard PC (i440FX + PIIX, 1996)";
- m->hot_add_cpu = pc_hot_add_cpu;
- m->default_machine_opts = "firmware=bios-256k.bin";
- m->default_display = "std";
-}
-
-static void pc_i440fx_2_6_machine_options(MachineClass *m)
-{
- pc_i440fx_machine_options(m);
- m->alias = "pc";
- m->is_default = 1;
-}
-
-DEFINE_I440FX_MACHINE(v2_6, "pc-i440fx-2.6", NULL,
- pc_i440fx_2_6_machine_options);
-
-
-static void pc_i440fx_2_5_machine_options(MachineClass *m)
-{
- PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
- pc_i440fx_2_6_machine_options(m);
- m->alias = NULL;
- m->is_default = 0;
- pcmc->save_tsc_khz = false;
- m->legacy_fw_cfg_order = 1;
- SET_MACHINE_COMPAT(m, PC_COMPAT_2_5);
-}
-
-DEFINE_I440FX_MACHINE(v2_5, "pc-i440fx-2.5", NULL,
- pc_i440fx_2_5_machine_options);
-
-
-static void pc_i440fx_2_4_machine_options(MachineClass *m)
-{
- PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
- pc_i440fx_2_5_machine_options(m);
- m->hw_version = "2.4.0";
- pcmc->broken_reserved_end = true;
- SET_MACHINE_COMPAT(m, PC_COMPAT_2_4);
-}
-
-DEFINE_I440FX_MACHINE(v2_4, "pc-i440fx-2.4", NULL,
- pc_i440fx_2_4_machine_options)
-
-
-static void pc_i440fx_2_3_machine_options(MachineClass *m)
-{
- pc_i440fx_2_4_machine_options(m);
- m->hw_version = "2.3.0";
- SET_MACHINE_COMPAT(m, PC_COMPAT_2_3);
-}
-
-DEFINE_I440FX_MACHINE(v2_3, "pc-i440fx-2.3", pc_compat_2_3,
- pc_i440fx_2_3_machine_options);
-
-
-static void pc_i440fx_2_2_machine_options(MachineClass *m)
-{
- PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
- pc_i440fx_2_3_machine_options(m);
- m->hw_version = "2.2.0";
- SET_MACHINE_COMPAT(m, PC_COMPAT_2_2);
- pcmc->rsdp_in_ram = false;
-}
-
-DEFINE_I440FX_MACHINE(v2_2, "pc-i440fx-2.2", pc_compat_2_2,
- pc_i440fx_2_2_machine_options);
-
-
-static void pc_i440fx_2_1_machine_options(MachineClass *m)
-{
- PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
- pc_i440fx_2_2_machine_options(m);
- m->hw_version = "2.1.0";
- m->default_display = NULL;
- SET_MACHINE_COMPAT(m, PC_COMPAT_2_1);
- pcmc->smbios_uuid_encoded = false;
- pcmc->enforce_aligned_dimm = false;
-}
-
-DEFINE_I440FX_MACHINE(v2_1, "pc-i440fx-2.1", pc_compat_2_1,
- pc_i440fx_2_1_machine_options);
-
-
-
-static void pc_i440fx_2_0_machine_options(MachineClass *m)
-{
- PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
- pc_i440fx_2_1_machine_options(m);
- m->hw_version = "2.0.0";
- SET_MACHINE_COMPAT(m, PC_COMPAT_2_0);
- pcmc->smbios_legacy_mode = true;
- pcmc->has_reserved_memory = false;
- /* This value depends on the actual DSDT and SSDT compiled into
- * the source QEMU; unfortunately it depends on the binary and
- * not on the machine type, so we cannot make pc-i440fx-1.7 work on
- * both QEMU 1.7 and QEMU 2.0.
- *
- * Large variations cause migration to fail for more than one
- * consecutive value of the "-smp" maxcpus option.
- *
- * For small variations of the kind caused by different iasl versions,
- * the 4k rounding usually leaves slack. However, there could be still
- * one or two values that break. For QEMU 1.7 and QEMU 2.0 the
- * slack is only ~10 bytes before one "-smp maxcpus" value breaks!
- *
- * 6652 is valid for QEMU 2.0, the right value for pc-i440fx-1.7 on
- * QEMU 1.7 it is 6414. For RHEL/CentOS 7.0 it is 6418.
- */
- pcmc->legacy_acpi_table_size = 6652;
- pcmc->acpi_data_size = 0x10000;
-}
-
-DEFINE_I440FX_MACHINE(v2_0, "pc-i440fx-2.0", pc_compat_2_0,
- pc_i440fx_2_0_machine_options);
-
-
-static void pc_i440fx_1_7_machine_options(MachineClass *m)
-{
- PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
- pc_i440fx_2_0_machine_options(m);
- m->hw_version = "1.7.0";
- m->default_machine_opts = NULL;
- m->option_rom_has_mr = true;
- SET_MACHINE_COMPAT(m, PC_COMPAT_1_7);
- pcmc->smbios_defaults = false;
- pcmc->gigabyte_align = false;
- pcmc->legacy_acpi_table_size = 6414;
-}
-
-DEFINE_I440FX_MACHINE(v1_7, "pc-i440fx-1.7", pc_compat_1_7,
- pc_i440fx_1_7_machine_options);
-
-
-static void pc_i440fx_1_6_machine_options(MachineClass *m)
-{
- PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
- pc_i440fx_1_7_machine_options(m);
- m->hw_version = "1.6.0";
- m->rom_file_has_mr = false;
- SET_MACHINE_COMPAT(m, PC_COMPAT_1_6);
- pcmc->has_acpi_build = false;
-}
-
-DEFINE_I440FX_MACHINE(v1_6, "pc-i440fx-1.6", pc_compat_1_6,
- pc_i440fx_1_6_machine_options);
-
-
-static void pc_i440fx_1_5_machine_options(MachineClass *m)
-{
- pc_i440fx_1_6_machine_options(m);
- m->hw_version = "1.5.0";
- SET_MACHINE_COMPAT(m, PC_COMPAT_1_5);
-}
-
-DEFINE_I440FX_MACHINE(v1_5, "pc-i440fx-1.5", pc_compat_1_5,
- pc_i440fx_1_5_machine_options);
-
-
-static void pc_i440fx_1_4_machine_options(MachineClass *m)
-{
- pc_i440fx_1_5_machine_options(m);
- m->hw_version = "1.4.0";
- m->hot_add_cpu = NULL;
- SET_MACHINE_COMPAT(m, PC_COMPAT_1_4);
-}
-
-DEFINE_I440FX_MACHINE(v1_4, "pc-i440fx-1.4", pc_compat_1_4,
- pc_i440fx_1_4_machine_options);
-
-
-#define PC_COMPAT_1_3 \
- PC_COMPAT_1_4 \
- {\
- .driver = "usb-tablet",\
- .property = "usb_version",\
- .value = stringify(1),\
- },{\
- .driver = "virtio-net-pci",\
- .property = "ctrl_mac_addr",\
- .value = "off", \
- },{ \
- .driver = "virtio-net-pci", \
- .property = "mq", \
- .value = "off", \
- }, {\
- .driver = "e1000",\
- .property = "autonegotiation",\
- .value = "off",\
- },
-
-
-static void pc_i440fx_1_3_machine_options(MachineClass *m)
-{
- pc_i440fx_1_4_machine_options(m);
- m->hw_version = "1.3.0";
- SET_MACHINE_COMPAT(m, PC_COMPAT_1_3);
-}
-
-DEFINE_I440FX_MACHINE(v1_3, "pc-1.3", pc_compat_1_3,
- pc_i440fx_1_3_machine_options);
-
-
-#define PC_COMPAT_1_2 \
- PC_COMPAT_1_3 \
- {\
- .driver = "nec-usb-xhci",\
- .property = "msi",\
- .value = "off",\
- },{\
- .driver = "nec-usb-xhci",\
- .property = "msix",\
- .value = "off",\
- },{\
- .driver = "ivshmem",\
- .property = "use64",\
- .value = "0",\
- },{\
- .driver = "qxl",\
- .property = "revision",\
- .value = stringify(3),\
- },{\
- .driver = "qxl-vga",\
- .property = "revision",\
- .value = stringify(3),\
- },{\
- .driver = "VGA",\
- .property = "mmio",\
- .value = "off",\
- },
-
-static void pc_i440fx_1_2_machine_options(MachineClass *m)
-{
- pc_i440fx_1_3_machine_options(m);
- m->hw_version = "1.2.0";
- SET_MACHINE_COMPAT(m, PC_COMPAT_1_2);
-}
-
-DEFINE_I440FX_MACHINE(v1_2, "pc-1.2", pc_compat_1_2,
- pc_i440fx_1_2_machine_options);
-
-
-#define PC_COMPAT_1_1 \
- PC_COMPAT_1_2 \
- {\
- .driver = "virtio-scsi-pci",\
- .property = "hotplug",\
- .value = "off",\
- },{\
- .driver = "virtio-scsi-pci",\
- .property = "param_change",\
- .value = "off",\
- },{\
- .driver = "VGA",\
- .property = "vgamem_mb",\
- .value = stringify(8),\
- },{\
- .driver = "vmware-svga",\
- .property = "vgamem_mb",\
- .value = stringify(8),\
- },{\
- .driver = "qxl-vga",\
- .property = "vgamem_mb",\
- .value = stringify(8),\
- },{\
- .driver = "qxl",\
- .property = "vgamem_mb",\
- .value = stringify(8),\
- },{\
- .driver = "virtio-blk-pci",\
- .property = "config-wce",\
- .value = "off",\
- },
-
-static void pc_i440fx_1_1_machine_options(MachineClass *m)
-{
- pc_i440fx_1_2_machine_options(m);
- m->hw_version = "1.1.0";
- SET_MACHINE_COMPAT(m, PC_COMPAT_1_1);
-}
-
-DEFINE_I440FX_MACHINE(v1_1, "pc-1.1", pc_compat_1_2,
- pc_i440fx_1_1_machine_options);
-
-
-#define PC_COMPAT_1_0 \
- PC_COMPAT_1_1 \
- {\
- .driver = TYPE_ISA_FDC,\
- .property = "check_media_rate",\
- .value = "off",\
- }, {\
- .driver = "virtio-balloon-pci",\
- .property = "class",\
- .value = stringify(PCI_CLASS_MEMORY_RAM),\
- },{\
- .driver = "apic-common",\
- .property = "vapic",\
- .value = "off",\
- },{\
- .driver = TYPE_USB_DEVICE,\
- .property = "full-path",\
- .value = "no",\
- },
-
-static void pc_i440fx_1_0_machine_options(MachineClass *m)
-{
- pc_i440fx_1_1_machine_options(m);
- m->hw_version = "1.0";
- SET_MACHINE_COMPAT(m, PC_COMPAT_1_0);
-}
-
-DEFINE_I440FX_MACHINE(v1_0, "pc-1.0", pc_compat_1_2,
- pc_i440fx_1_0_machine_options);
-
-
-#define PC_COMPAT_0_15 \
- PC_COMPAT_1_0
-
-static void pc_i440fx_0_15_machine_options(MachineClass *m)
-{
- pc_i440fx_1_0_machine_options(m);
- m->hw_version = "0.15";
- SET_MACHINE_COMPAT(m, PC_COMPAT_0_15);
-}
-
-DEFINE_I440FX_MACHINE(v0_15, "pc-0.15", pc_compat_1_2,
- pc_i440fx_0_15_machine_options);
-
-
-#define PC_COMPAT_0_14 \
- PC_COMPAT_0_15 \
- {\
- .driver = "virtio-blk-pci",\
- .property = "event_idx",\
- .value = "off",\
- },{\
- .driver = "virtio-serial-pci",\
- .property = "event_idx",\
- .value = "off",\
- },{\
- .driver = "virtio-net-pci",\
- .property = "event_idx",\
- .value = "off",\
- },{\
- .driver = "virtio-balloon-pci",\
- .property = "event_idx",\
- .value = "off",\
- },{\
- .driver = "qxl",\
- .property = "revision",\
- .value = stringify(2),\
- },{\
- .driver = "qxl-vga",\
- .property = "revision",\
- .value = stringify(2),\
- },
-
-static void pc_i440fx_0_14_machine_options(MachineClass *m)
-{
- pc_i440fx_0_15_machine_options(m);
- m->hw_version = "0.14";
- SET_MACHINE_COMPAT(m, PC_COMPAT_0_14);
-}
-
-DEFINE_I440FX_MACHINE(v0_14, "pc-0.14", pc_compat_1_2,
- pc_i440fx_0_14_machine_options);
-
-
-#define PC_COMPAT_0_13 \
- PC_COMPAT_0_14 \
- {\
- .driver = TYPE_PCI_DEVICE,\
- .property = "command_serr_enable",\
- .value = "off",\
- },{\
- .driver = "AC97",\
- .property = "use_broken_id",\
- .value = stringify(1),\
- },{\
- .driver = "virtio-9p-pci",\
- .property = "vectors",\
- .value = stringify(0),\
- },{\
- .driver = "VGA",\
- .property = "rombar",\
- .value = stringify(0),\
- },{\
- .driver = "vmware-svga",\
- .property = "rombar",\
- .value = stringify(0),\
- },
-
-static void pc_i440fx_0_13_machine_options(MachineClass *m)
-{
- PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
- pc_i440fx_0_14_machine_options(m);
- m->hw_version = "0.13";
- SET_MACHINE_COMPAT(m, PC_COMPAT_0_13);
- pcmc->kvmclock_enabled = false;
-}
-
-DEFINE_I440FX_MACHINE(v0_13, "pc-0.13", pc_compat_0_13,
- pc_i440fx_0_13_machine_options);
-
-
-#define PC_COMPAT_0_12 \
- PC_COMPAT_0_13 \
- {\
- .driver = "virtio-serial-pci",\
- .property = "max_ports",\
- .value = stringify(1),\
- },{\
- .driver = "virtio-serial-pci",\
- .property = "vectors",\
- .value = stringify(0),\
- },{\
- .driver = "usb-mouse",\
- .property = "serial",\
- .value = "1",\
- },{\
- .driver = "usb-tablet",\
- .property = "serial",\
- .value = "1",\
- },{\
- .driver = "usb-kbd",\
- .property = "serial",\
- .value = "1",\
- },
-
-static void pc_i440fx_0_12_machine_options(MachineClass *m)
-{
- pc_i440fx_0_13_machine_options(m);
- m->hw_version = "0.12";
- SET_MACHINE_COMPAT(m, PC_COMPAT_0_12);
-}
-
-DEFINE_I440FX_MACHINE(v0_12, "pc-0.12", pc_compat_0_13,
- pc_i440fx_0_12_machine_options);
-
-
-#define PC_COMPAT_0_11 \
- PC_COMPAT_0_12 \
- {\
- .driver = "virtio-blk-pci",\
- .property = "vectors",\
- .value = stringify(0),\
- },{\
- .driver = TYPE_PCI_DEVICE,\
- .property = "rombar",\
- .value = stringify(0),\
- },{\
- .driver = "ide-drive",\
- .property = "ver",\
- .value = "0.11",\
- },{\
- .driver = "scsi-disk",\
- .property = "ver",\
- .value = "0.11",\
- },
-
-static void pc_i440fx_0_11_machine_options(MachineClass *m)
-{
- pc_i440fx_0_12_machine_options(m);
- m->hw_version = "0.11";
- SET_MACHINE_COMPAT(m, PC_COMPAT_0_11);
-}
-
-DEFINE_I440FX_MACHINE(v0_11, "pc-0.11", pc_compat_0_13,
- pc_i440fx_0_11_machine_options);
-
-
-#define PC_COMPAT_0_10 \
- PC_COMPAT_0_11 \
- {\
- .driver = "virtio-blk-pci",\
- .property = "class",\
- .value = stringify(PCI_CLASS_STORAGE_OTHER),\
- },{\
- .driver = "virtio-serial-pci",\
- .property = "class",\
- .value = stringify(PCI_CLASS_DISPLAY_OTHER),\
- },{\
- .driver = "virtio-net-pci",\
- .property = "vectors",\
- .value = stringify(0),\
- },{\
- .driver = "ide-drive",\
- .property = "ver",\
- .value = "0.10",\
- },{\
- .driver = "scsi-disk",\
- .property = "ver",\
- .value = "0.10",\
- },
-
-static void pc_i440fx_0_10_machine_options(MachineClass *m)
-{
- pc_i440fx_0_11_machine_options(m);
- m->hw_version = "0.10";
- SET_MACHINE_COMPAT(m, PC_COMPAT_0_10);
-}
-
-DEFINE_I440FX_MACHINE(v0_10, "pc-0.10", pc_compat_0_13,
- pc_i440fx_0_10_machine_options);
-
-typedef struct {
- uint16_t gpu_device_id;
- uint16_t pch_device_id;
- uint8_t pch_revision_id;
-} IGDDeviceIDInfo;
-
-/* In real world different GPU should have different PCH. But actually
- * the different PCH DIDs likely map to different PCH SKUs. We do the
- * same thing for the GPU. For PCH, the different SKUs are going to be
- * all the same silicon design and implementation, just different
- * features turn on and off with fuses. The SW interfaces should be
- * consistent across all SKUs in a given family (eg LPT). But just same
- * features may not be supported.
- *
- * Most of these different PCH features probably don't matter to the
- * Gfx driver, but obviously any difference in display port connections
- * will so it should be fine with any PCH in case of passthrough.
- *
- * So currently use one PCH version, 0x8c4e, to cover all HSW(Haswell)
- * scenarios, 0x9cc3 for BDW(Broadwell).
- */
-static const IGDDeviceIDInfo igd_combo_id_infos[] = {
- /* HSW Classic */
- {0x0402, 0x8c4e, 0x04}, /* HSWGT1D, HSWD_w7 */
- {0x0406, 0x8c4e, 0x04}, /* HSWGT1M, HSWM_w7 */
- {0x0412, 0x8c4e, 0x04}, /* HSWGT2D, HSWD_w7 */
- {0x0416, 0x8c4e, 0x04}, /* HSWGT2M, HSWM_w7 */
- {0x041E, 0x8c4e, 0x04}, /* HSWGT15D, HSWD_w7 */
- /* HSW ULT */
- {0x0A06, 0x8c4e, 0x04}, /* HSWGT1UT, HSWM_w7 */
- {0x0A16, 0x8c4e, 0x04}, /* HSWGT2UT, HSWM_w7 */
- {0x0A26, 0x8c4e, 0x06}, /* HSWGT3UT, HSWM_w7 */
- {0x0A2E, 0x8c4e, 0x04}, /* HSWGT3UT28W, HSWM_w7 */
- {0x0A1E, 0x8c4e, 0x04}, /* HSWGT2UX, HSWM_w7 */
- {0x0A0E, 0x8c4e, 0x04}, /* HSWGT1ULX, HSWM_w7 */
- /* HSW CRW */
- {0x0D26, 0x8c4e, 0x04}, /* HSWGT3CW, HSWM_w7 */
- {0x0D22, 0x8c4e, 0x04}, /* HSWGT3CWDT, HSWD_w7 */
- /* HSW Server */
- {0x041A, 0x8c4e, 0x04}, /* HSWSVGT2, HSWD_w7 */
- /* HSW SRVR */
- {0x040A, 0x8c4e, 0x04}, /* HSWSVGT1, HSWD_w7 */
- /* BSW */
- {0x1606, 0x9cc3, 0x03}, /* BDWULTGT1, BDWM_w7 */
- {0x1616, 0x9cc3, 0x03}, /* BDWULTGT2, BDWM_w7 */
- {0x1626, 0x9cc3, 0x03}, /* BDWULTGT3, BDWM_w7 */
- {0x160E, 0x9cc3, 0x03}, /* BDWULXGT1, BDWM_w7 */
- {0x161E, 0x9cc3, 0x03}, /* BDWULXGT2, BDWM_w7 */
- {0x1602, 0x9cc3, 0x03}, /* BDWHALOGT1, BDWM_w7 */
- {0x1612, 0x9cc3, 0x03}, /* BDWHALOGT2, BDWM_w7 */
- {0x1622, 0x9cc3, 0x03}, /* BDWHALOGT3, BDWM_w7 */
- {0x162B, 0x9cc3, 0x03}, /* BDWHALO28W, BDWM_w7 */
- {0x162A, 0x9cc3, 0x03}, /* BDWGT3WRKS, BDWM_w7 */
- {0x162D, 0x9cc3, 0x03}, /* BDWGT3SRVR, BDWM_w7 */
-};
-
-static void isa_bridge_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- dc->desc = "ISA bridge faked to support IGD PT";
- k->vendor_id = PCI_VENDOR_ID_INTEL;
- k->class_id = PCI_CLASS_BRIDGE_ISA;
-};
-
-static TypeInfo isa_bridge_info = {
- .name = "igd-passthrough-isa-bridge",
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(PCIDevice),
- .class_init = isa_bridge_class_init,
-};
-
-static void pt_graphics_register_types(void)
-{
- type_register_static(&isa_bridge_info);
-}
-type_init(pt_graphics_register_types)
-
-void igd_passthrough_isa_bridge_create(PCIBus *bus, uint16_t gpu_dev_id)
-{
- struct PCIDevice *bridge_dev;
- int i, num;
- uint16_t pch_dev_id = 0xffff;
- uint8_t pch_rev_id;
-
- num = ARRAY_SIZE(igd_combo_id_infos);
- for (i = 0; i < num; i++) {
- if (gpu_dev_id == igd_combo_id_infos[i].gpu_device_id) {
- pch_dev_id = igd_combo_id_infos[i].pch_device_id;
- pch_rev_id = igd_combo_id_infos[i].pch_revision_id;
- }
- }
-
- if (pch_dev_id == 0xffff) {
- return;
- }
-
- /* Currently IGD drivers always need to access PCH by 1f.0. */
- bridge_dev = pci_create_simple(bus, PCI_DEVFN(0x1f, 0),
- "igd-passthrough-isa-bridge");
-
- /*
- * Note that vendor id is always PCI_VENDOR_ID_INTEL.
- */
- if (!bridge_dev) {
- fprintf(stderr, "set igd-passthrough-isa-bridge failed!\n");
- return;
- }
- pci_config_set_device_id(bridge_dev->config, pch_dev_id);
- pci_config_set_revision(bridge_dev->config, pch_rev_id);
-}
-
-static void isapc_machine_options(MachineClass *m)
-{
- PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
- m->desc = "ISA-only PC";
- m->max_cpus = 1;
- m->option_rom_has_mr = true;
- m->rom_file_has_mr = false;
- pcmc->pci_enabled = false;
- pcmc->has_acpi_build = false;
- pcmc->smbios_defaults = false;
- pcmc->gigabyte_align = false;
- pcmc->smbios_legacy_mode = true;
- pcmc->has_reserved_memory = false;
-}
-
-DEFINE_PC_MACHINE(isapc, "isapc", pc_init_isa,
- isapc_machine_options);
-
-
-#ifdef CONFIG_XEN
-static void xenfv_machine_options(MachineClass *m)
-{
- m->desc = "Xen Fully-virtualized PC";
- m->max_cpus = HVM_MAX_VCPUS;
- m->default_machine_opts = "accel=xen";
- m->hot_add_cpu = pc_hot_add_cpu;
-}
-
-DEFINE_PC_MACHINE(xenfv, "xenfv", pc_xen_hvm_init,
- xenfv_machine_options);
-#endif
diff --git a/qemu/hw/i386/pc_q35.c b/qemu/hw/i386/pc_q35.c
deleted file mode 100644
index 04aae8958..000000000
--- a/qemu/hw/i386/pc_q35.c
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * Q35 chipset based pc system emulator
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- * Copyright (c) 2009, 2010
- * Isaku Yamahata <yamahata at valinux co jp>
- * VA Linux Systems Japan K.K.
- * Copyright (C) 2012 Jason Baron <jbaron@redhat.com>
- *
- * This is based on pc.c, but heavily modified.
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/loader.h"
-#include "sysemu/arch_init.h"
-#include "hw/i2c/smbus.h"
-#include "hw/boards.h"
-#include "hw/timer/mc146818rtc.h"
-#include "hw/xen/xen.h"
-#include "sysemu/kvm.h"
-#include "hw/kvm/clock.h"
-#include "hw/pci-host/q35.h"
-#include "exec/address-spaces.h"
-#include "hw/i386/pc.h"
-#include "hw/i386/ich9.h"
-#include "hw/smbios/smbios.h"
-#include "hw/ide/pci.h"
-#include "hw/ide/ahci.h"
-#include "hw/usb.h"
-#include "qemu/error-report.h"
-#include "migration/migration.h"
-
-/* ICH9 AHCI has 6 ports */
-#define MAX_SATA_PORTS 6
-
-/* PC hardware initialisation */
-static void pc_q35_init(MachineState *machine)
-{
- PCMachineState *pcms = PC_MACHINE(machine);
- PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
- Q35PCIHost *q35_host;
- PCIHostState *phb;
- PCIBus *host_bus;
- PCIDevice *lpc;
- BusState *idebus[MAX_SATA_PORTS];
- ISADevice *rtc_state;
- MemoryRegion *system_io = get_system_io();
- MemoryRegion *pci_memory;
- MemoryRegion *rom_memory;
- MemoryRegion *ram_memory;
- GSIState *gsi_state;
- ISABus *isa_bus;
- qemu_irq *gsi;
- qemu_irq *i8259;
- int i;
- ICH9LPCState *ich9_lpc;
- PCIDevice *ahci;
- ram_addr_t lowmem;
- DriveInfo *hd[MAX_SATA_PORTS];
- MachineClass *mc = MACHINE_GET_CLASS(machine);
-
- /* Check whether RAM fits below 4G (leaving 1/2 GByte for IO memory
- * and 256 Mbytes for PCI Express Enhanced Configuration Access Mapping
- * also known as MMCFG).
- * If it doesn't, we need to split it in chunks below and above 4G.
- * In any case, try to make sure that guest addresses aligned at
- * 1G boundaries get mapped to host addresses aligned at 1G boundaries.
- */
- if (machine->ram_size >= 0xb0000000) {
- lowmem = 0x80000000;
- } else {
- lowmem = 0xb0000000;
- }
-
- /* Handle the machine opt max-ram-below-4g. It is basically doing
- * min(qemu limit, user limit).
- */
- if (lowmem > pcms->max_ram_below_4g) {
- lowmem = pcms->max_ram_below_4g;
- if (machine->ram_size - lowmem > lowmem &&
- lowmem & ((1ULL << 30) - 1)) {
- error_report("Warning: Large machine and max_ram_below_4g(%"PRIu64
- ") not a multiple of 1G; possible bad performance.",
- pcms->max_ram_below_4g);
- }
- }
-
- if (machine->ram_size >= lowmem) {
- pcms->above_4g_mem_size = machine->ram_size - lowmem;
- pcms->below_4g_mem_size = lowmem;
- } else {
- pcms->above_4g_mem_size = 0;
- pcms->below_4g_mem_size = machine->ram_size;
- }
-
- if (xen_enabled()) {
- xen_hvm_init(pcms, &ram_memory);
- }
-
- pc_cpus_init(pcms);
-
- kvmclock_create();
-
- /* pci enabled */
- if (pcmc->pci_enabled) {
- pci_memory = g_new(MemoryRegion, 1);
- memory_region_init(pci_memory, NULL, "pci", UINT64_MAX);
- rom_memory = pci_memory;
- } else {
- pci_memory = NULL;
- rom_memory = get_system_memory();
- }
-
- pc_guest_info_init(pcms);
-
- if (pcmc->smbios_defaults) {
- /* These values are guest ABI, do not change */
- smbios_set_defaults("QEMU", "Standard PC (Q35 + ICH9, 2009)",
- mc->name, pcmc->smbios_legacy_mode,
- pcmc->smbios_uuid_encoded,
- SMBIOS_ENTRY_POINT_21);
- }
-
- /* allocate ram and load rom/bios */
- if (!xen_enabled()) {
- pc_memory_init(pcms, get_system_memory(),
- rom_memory, &ram_memory);
- }
-
- /* irq lines */
- gsi_state = g_malloc0(sizeof(*gsi_state));
- if (kvm_ioapic_in_kernel()) {
- kvm_pc_setup_irq_routing(pcmc->pci_enabled);
- gsi = qemu_allocate_irqs(kvm_pc_gsi_handler, gsi_state,
- GSI_NUM_PINS);
- } else {
- gsi = qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS);
- }
-
- /* create pci host bus */
- q35_host = Q35_HOST_DEVICE(qdev_create(NULL, TYPE_Q35_HOST_DEVICE));
-
- object_property_add_child(qdev_get_machine(), "q35", OBJECT(q35_host), NULL);
- q35_host->mch.ram_memory = ram_memory;
- q35_host->mch.pci_address_space = pci_memory;
- q35_host->mch.system_memory = get_system_memory();
- q35_host->mch.address_space_io = system_io;
- q35_host->mch.below_4g_mem_size = pcms->below_4g_mem_size;
- q35_host->mch.above_4g_mem_size = pcms->above_4g_mem_size;
- /* pci */
- qdev_init_nofail(DEVICE(q35_host));
- phb = PCI_HOST_BRIDGE(q35_host);
- host_bus = phb->bus;
- pcms->bus = phb->bus;
- /* create ISA bus */
- lpc = pci_create_simple_multifunction(host_bus, PCI_DEVFN(ICH9_LPC_DEV,
- ICH9_LPC_FUNC), true,
- TYPE_ICH9_LPC_DEVICE);
-
- object_property_add_link(OBJECT(machine), PC_MACHINE_ACPI_DEVICE_PROP,
- TYPE_HOTPLUG_HANDLER,
- (Object **)&pcms->acpi_dev,
- object_property_allow_set_link,
- OBJ_PROP_LINK_UNREF_ON_RELEASE, &error_abort);
- object_property_set_link(OBJECT(machine), OBJECT(lpc),
- PC_MACHINE_ACPI_DEVICE_PROP, &error_abort);
-
- ich9_lpc = ICH9_LPC_DEVICE(lpc);
- ich9_lpc->pic = gsi;
- ich9_lpc->ioapic = gsi_state->ioapic_irq;
- pci_bus_irqs(host_bus, ich9_lpc_set_irq, ich9_lpc_map_irq, ich9_lpc,
- ICH9_LPC_NB_PIRQS);
- pci_bus_set_route_irq_fn(host_bus, ich9_route_intx_pin_to_irq);
- isa_bus = ich9_lpc->isa_bus;
-
- /*end early*/
- isa_bus_irqs(isa_bus, gsi);
-
- if (kvm_pic_in_kernel()) {
- i8259 = kvm_i8259_init(isa_bus);
- } else if (xen_enabled()) {
- i8259 = xen_interrupt_controller_init();
- } else {
- i8259 = i8259_init(isa_bus, pc_allocate_cpu_irq());
- }
-
- for (i = 0; i < ISA_NUM_IRQS; i++) {
- gsi_state->i8259_irq[i] = i8259[i];
- }
- if (pcmc->pci_enabled) {
- ioapic_init_gsi(gsi_state, "q35");
- }
-
- pc_register_ferr_irq(gsi[13]);
-
- assert(pcms->vmport != ON_OFF_AUTO__MAX);
- if (pcms->vmport == ON_OFF_AUTO_AUTO) {
- pcms->vmport = xen_enabled() ? ON_OFF_AUTO_OFF : ON_OFF_AUTO_ON;
- }
-
- /* init basic PC hardware */
- pc_basic_device_init(isa_bus, gsi, &rtc_state, !mc->no_floppy,
- (pcms->vmport != ON_OFF_AUTO_ON), 0xff0104);
-
- /* connect pm stuff to lpc */
- ich9_lpc_pm_init(lpc, pc_machine_is_smm_enabled(pcms));
-
- /* ahci and SATA device, for q35 1 ahci controller is built-in */
- ahci = pci_create_simple_multifunction(host_bus,
- PCI_DEVFN(ICH9_SATA1_DEV,
- ICH9_SATA1_FUNC),
- true, "ich9-ahci");
- idebus[0] = qdev_get_child_bus(&ahci->qdev, "ide.0");
- idebus[1] = qdev_get_child_bus(&ahci->qdev, "ide.1");
- g_assert(MAX_SATA_PORTS == ICH_AHCI(ahci)->ahci.ports);
- ide_drive_get(hd, ICH_AHCI(ahci)->ahci.ports);
- ahci_ide_create_devs(ahci, hd);
-
- if (usb_enabled()) {
- /* Should we create 6 UHCI according to ich9 spec? */
- ehci_create_ich9_with_companions(host_bus, 0x1d);
- }
-
- /* TODO: Populate SPD eeprom data. */
- smbus_eeprom_init(ich9_smb_init(host_bus,
- PCI_DEVFN(ICH9_SMB_DEV, ICH9_SMB_FUNC),
- 0xb100),
- 8, NULL, 0);
-
- pc_cmos_init(pcms, idebus[0], idebus[1], rtc_state);
-
- /* the rest devices to which pci devfn is automatically assigned */
- pc_vga_init(isa_bus, host_bus);
- pc_nic_init(isa_bus, host_bus);
- if (pcmc->pci_enabled) {
- pc_pci_device_init(host_bus);
- }
-
- if (pcms->acpi_nvdimm_state.is_enabled) {
- nvdimm_init_acpi_state(&pcms->acpi_nvdimm_state, system_io,
- pcms->fw_cfg, OBJECT(pcms));
- }
-}
-
-#define DEFINE_Q35_MACHINE(suffix, name, compatfn, optionfn) \
- static void pc_init_##suffix(MachineState *machine) \
- { \
- void (*compat)(MachineState *m) = (compatfn); \
- if (compat) { \
- compat(machine); \
- } \
- pc_q35_init(machine); \
- } \
- DEFINE_PC_MACHINE(suffix, name, pc_init_##suffix, optionfn)
-
-
-static void pc_q35_machine_options(MachineClass *m)
-{
- m->family = "pc_q35";
- m->desc = "Standard PC (Q35 + ICH9, 2009)";
- m->hot_add_cpu = pc_hot_add_cpu;
- m->units_per_default_bus = 1;
- m->default_machine_opts = "firmware=bios-256k.bin";
- m->default_display = "std";
- m->no_floppy = 1;
-}
-
-static void pc_q35_2_6_machine_options(MachineClass *m)
-{
- pc_q35_machine_options(m);
- m->alias = "q35";
-}
-
-DEFINE_Q35_MACHINE(v2_6, "pc-q35-2.6", NULL,
- pc_q35_2_6_machine_options);
-
-static void pc_q35_2_5_machine_options(MachineClass *m)
-{
- PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
- pc_q35_2_6_machine_options(m);
- m->alias = NULL;
- pcmc->save_tsc_khz = false;
- m->legacy_fw_cfg_order = 1;
- SET_MACHINE_COMPAT(m, PC_COMPAT_2_5);
-}
-
-DEFINE_Q35_MACHINE(v2_5, "pc-q35-2.5", NULL,
- pc_q35_2_5_machine_options);
-
-static void pc_q35_2_4_machine_options(MachineClass *m)
-{
- PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
- pc_q35_2_5_machine_options(m);
- m->hw_version = "2.4.0";
- pcmc->broken_reserved_end = true;
- SET_MACHINE_COMPAT(m, PC_COMPAT_2_4);
-}
-
-DEFINE_Q35_MACHINE(v2_4, "pc-q35-2.4", NULL,
- pc_q35_2_4_machine_options);
diff --git a/qemu/hw/i386/pc_sysfw.c b/qemu/hw/i386/pc_sysfw.c
deleted file mode 100644
index f915ad0a3..000000000
--- a/qemu/hw/i386/pc_sysfw.c
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
- * QEMU PC System Firmware
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- * Copyright (c) 2011-2012 Intel Corporation
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "sysemu/block-backend.h"
-#include "qemu/error-report.h"
-#include "hw/sysbus.h"
-#include "hw/hw.h"
-#include "hw/i386/pc.h"
-#include "hw/boards.h"
-#include "hw/loader.h"
-#include "sysemu/sysemu.h"
-#include "hw/block/flash.h"
-#include "sysemu/kvm.h"
-
-#define BIOS_FILENAME "bios.bin"
-
-typedef struct PcSysFwDevice {
- SysBusDevice busdev;
- uint8_t isapc_ram_fw;
-} PcSysFwDevice;
-
-static void pc_isa_bios_init(MemoryRegion *rom_memory,
- MemoryRegion *flash_mem,
- int ram_size)
-{
- int isa_bios_size;
- MemoryRegion *isa_bios;
- uint64_t flash_size;
- void *flash_ptr, *isa_bios_ptr;
-
- flash_size = memory_region_size(flash_mem);
-
- /* map the last 128KB of the BIOS in ISA space */
- isa_bios_size = MIN(flash_size, 128 * 1024);
- isa_bios = g_malloc(sizeof(*isa_bios));
- memory_region_init_ram(isa_bios, NULL, "isa-bios", isa_bios_size,
- &error_fatal);
- vmstate_register_ram_global(isa_bios);
- memory_region_add_subregion_overlap(rom_memory,
- 0x100000 - isa_bios_size,
- isa_bios,
- 1);
-
- /* copy ISA rom image from top of flash memory */
- flash_ptr = memory_region_get_ram_ptr(flash_mem);
- isa_bios_ptr = memory_region_get_ram_ptr(isa_bios);
- memcpy(isa_bios_ptr,
- ((uint8_t*)flash_ptr) + (flash_size - isa_bios_size),
- isa_bios_size);
-
- memory_region_set_readonly(isa_bios, true);
-}
-
-#define FLASH_MAP_UNIT_MAX 2
-
-/* We don't have a theoretically justifiable exact lower bound on the base
- * address of any flash mapping. In practice, the IO-APIC MMIO range is
- * [0xFEE00000..0xFEE01000[ -- see IO_APIC_DEFAULT_ADDRESS --, leaving free
- * only 18MB-4KB below 4G. For now, restrict the cumulative mapping to 8MB in
- * size.
- */
-#define FLASH_MAP_BASE_MIN ((hwaddr)(0x100000000ULL - 8*1024*1024))
-
-/* This function maps flash drives from 4G downward, in order of their unit
- * numbers. The mapping starts at unit#0, with unit number increments of 1, and
- * stops before the first missing flash drive, or before
- * unit#FLASH_MAP_UNIT_MAX, whichever is reached first.
- *
- * Addressing within one flash drive is of course not reversed.
- *
- * An error message is printed and the process exits if:
- * - the size of the backing file for a flash drive is non-positive, or not a
- * multiple of the required sector size, or
- * - the current mapping's base address would fall below FLASH_MAP_BASE_MIN.
- *
- * The drive with unit#0 (if available) is mapped at the highest address, and
- * it is passed to pc_isa_bios_init(). Merging several drives for isa-bios is
- * not supported.
- */
-static void pc_system_flash_init(MemoryRegion *rom_memory)
-{
- int unit;
- DriveInfo *pflash_drv;
- BlockBackend *blk;
- int64_t size;
- char *fatal_errmsg = NULL;
- hwaddr phys_addr = 0x100000000ULL;
- int sector_bits, sector_size;
- pflash_t *system_flash;
- MemoryRegion *flash_mem;
- char name[64];
-
- sector_bits = 12;
- sector_size = 1 << sector_bits;
-
- for (unit = 0;
- (unit < FLASH_MAP_UNIT_MAX &&
- (pflash_drv = drive_get(IF_PFLASH, 0, unit)) != NULL);
- ++unit) {
- blk = blk_by_legacy_dinfo(pflash_drv);
- size = blk_getlength(blk);
- if (size < 0) {
- fatal_errmsg = g_strdup_printf("failed to get backing file size");
- } else if (size == 0) {
- fatal_errmsg = g_strdup_printf("PC system firmware (pflash) "
- "cannot have zero size");
- } else if ((size % sector_size) != 0) {
- fatal_errmsg = g_strdup_printf("PC system firmware (pflash) "
- "must be a multiple of 0x%x", sector_size);
- } else if (phys_addr < size || phys_addr - size < FLASH_MAP_BASE_MIN) {
- fatal_errmsg = g_strdup_printf("oversized backing file, pflash "
- "segments cannot be mapped under "
- TARGET_FMT_plx, FLASH_MAP_BASE_MIN);
- }
- if (fatal_errmsg != NULL) {
- Location loc;
-
- /* push a new, "none" location on the location stack; overwrite its
- * contents with the location saved in the option; print the error
- * (includes location); pop the top
- */
- loc_push_none(&loc);
- if (pflash_drv->opts != NULL) {
- qemu_opts_loc_restore(pflash_drv->opts);
- }
- error_report("%s", fatal_errmsg);
- loc_pop(&loc);
- g_free(fatal_errmsg);
- exit(1);
- }
-
- phys_addr -= size;
-
- /* pflash_cfi01_register() creates a deep copy of the name */
- snprintf(name, sizeof name, "system.flash%d", unit);
- system_flash = pflash_cfi01_register(phys_addr, NULL /* qdev */, name,
- size, blk, sector_size,
- size >> sector_bits,
- 1 /* width */,
- 0x0000 /* id0 */,
- 0x0000 /* id1 */,
- 0x0000 /* id2 */,
- 0x0000 /* id3 */,
- 0 /* be */);
- if (unit == 0) {
- flash_mem = pflash_cfi01_get_memory(system_flash);
- pc_isa_bios_init(rom_memory, flash_mem, size);
- }
- }
-}
-
-static void old_pc_system_rom_init(MemoryRegion *rom_memory, bool isapc_ram_fw)
-{
- char *filename;
- MemoryRegion *bios, *isa_bios;
- int bios_size, isa_bios_size;
- int ret;
-
- /* BIOS load */
- if (bios_name == NULL) {
- bios_name = BIOS_FILENAME;
- }
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
- if (filename) {
- bios_size = get_image_size(filename);
- } else {
- bios_size = -1;
- }
- if (bios_size <= 0 ||
- (bios_size % 65536) != 0) {
- goto bios_error;
- }
- bios = g_malloc(sizeof(*bios));
- memory_region_init_ram(bios, NULL, "pc.bios", bios_size, &error_fatal);
- vmstate_register_ram_global(bios);
- if (!isapc_ram_fw) {
- memory_region_set_readonly(bios, true);
- }
- ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size), -1);
- if (ret != 0) {
- bios_error:
- fprintf(stderr, "qemu: could not load PC BIOS '%s'\n", bios_name);
- exit(1);
- }
- g_free(filename);
-
- /* map the last 128KB of the BIOS in ISA space */
- isa_bios_size = bios_size;
- if (isa_bios_size > (128 * 1024)) {
- isa_bios_size = 128 * 1024;
- }
- isa_bios = g_malloc(sizeof(*isa_bios));
- memory_region_init_alias(isa_bios, NULL, "isa-bios", bios,
- bios_size - isa_bios_size, isa_bios_size);
- memory_region_add_subregion_overlap(rom_memory,
- 0x100000 - isa_bios_size,
- isa_bios,
- 1);
- if (!isapc_ram_fw) {
- memory_region_set_readonly(isa_bios, true);
- }
-
- /* map all the bios at the top of memory */
- memory_region_add_subregion(rom_memory,
- (uint32_t)(-bios_size),
- bios);
-}
-
-void pc_system_firmware_init(MemoryRegion *rom_memory, bool isapc_ram_fw)
-{
- DriveInfo *pflash_drv;
-
- pflash_drv = drive_get(IF_PFLASH, 0, 0);
-
- if (isapc_ram_fw || pflash_drv == NULL) {
- /* When a pflash drive is not found, use rom-mode */
- old_pc_system_rom_init(rom_memory, isapc_ram_fw);
- return;
- }
-
- if (kvm_enabled() && !kvm_readonly_mem_enabled()) {
- /* Older KVM cannot execute from device memory. So, flash memory
- * cannot be used unless the readonly memory kvm capability is present. */
- fprintf(stderr, "qemu: pflash with kvm requires KVM readonly memory support\n");
- exit(1);
- }
-
- pc_system_flash_init(rom_memory);
-}
diff --git a/qemu/hw/i386/pci-assign-load-rom.c b/qemu/hw/i386/pci-assign-load-rom.c
deleted file mode 100644
index 4bbb08c95..000000000
--- a/qemu/hw/i386/pci-assign-load-rom.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * This is splited from hw/i386/kvm/pci-assign.c
- */
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/hw.h"
-#include "hw/i386/pc.h"
-#include "qemu/error-report.h"
-#include "ui/console.h"
-#include "hw/loader.h"
-#include "monitor/monitor.h"
-#include "qemu/range.h"
-#include "sysemu/sysemu.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/pci-assign.h"
-
-/*
- * Scan the assigned devices for the devices that have an option ROM, and then
- * load the corresponding ROM data to RAM. If an error occurs while loading an
- * option ROM, we just ignore that option ROM and continue with the next one.
- */
-void *pci_assign_dev_load_option_rom(PCIDevice *dev, struct Object *owner,
- int *size, unsigned int domain,
- unsigned int bus, unsigned int slot,
- unsigned int function)
-{
- char name[32], rom_file[64];
- FILE *fp;
- uint8_t val;
- struct stat st;
- void *ptr = NULL;
-
- /* If loading ROM from file, pci handles it */
- if (dev->romfile || !dev->rom_bar) {
- return NULL;
- }
-
- snprintf(rom_file, sizeof(rom_file),
- "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/rom",
- domain, bus, slot, function);
-
- if (stat(rom_file, &st)) {
- return NULL;
- }
-
- /* Write "1" to the ROM file to enable it */
- fp = fopen(rom_file, "r+");
- if (fp == NULL) {
- error_report("pci-assign: Cannot open %s: %s", rom_file, strerror(errno));
- return NULL;
- }
- val = 1;
- if (fwrite(&val, 1, 1, fp) != 1) {
- goto close_rom;
- }
- fseek(fp, 0, SEEK_SET);
-
- snprintf(name, sizeof(name), "%s.rom", object_get_typename(owner));
- memory_region_init_ram(&dev->rom, owner, name, st.st_size, &error_abort);
- vmstate_register_ram(&dev->rom, &dev->qdev);
- ptr = memory_region_get_ram_ptr(&dev->rom);
- memset(ptr, 0xff, st.st_size);
-
- if (!fread(ptr, 1, st.st_size, fp)) {
- error_report("pci-assign: Cannot read from host %s", rom_file);
- error_printf("Device option ROM contents are probably invalid "
- "(check dmesg).\nSkip option ROM probe with rombar=0, "
- "or load from file with romfile=\n");
- goto close_rom;
- }
-
- pci_register_bar(dev, PCI_ROM_SLOT, 0, &dev->rom);
- dev->has_rom = true;
- *size = st.st_size;
-close_rom:
- /* Write "0" to disable ROM */
- fseek(fp, 0, SEEK_SET);
- val = 0;
- if (!fwrite(&val, 1, 1, fp)) {
- DEBUG("%s\n", "Failed to disable pci-sysfs rom file");
- }
- fclose(fp);
-
- return ptr;
-}
diff --git a/qemu/hw/i386/xen/Makefile.objs b/qemu/hw/i386/xen/Makefile.objs
deleted file mode 100644
index 801a68d32..000000000
--- a/qemu/hw/i386/xen/Makefile.objs
+++ /dev/null
@@ -1 +0,0 @@
-obj-y += xen_platform.o xen_apic.o xen_pvdevice.o
diff --git a/qemu/hw/i386/xen/xen_apic.c b/qemu/hw/i386/xen/xen_apic.c
deleted file mode 100644
index 21d68ee04..000000000
--- a/qemu/hw/i386/xen/xen_apic.c
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Xen basic APIC support
- *
- * Copyright (c) 2012 Citrix
- *
- * Authors:
- * Wei Liu <wei.liu2@citrix.com>
- *
- * This work is licensed under the terms of the GNU GPL version 2 or
- * later. See the COPYING file in the top-level directory.
- */
-#include "qemu/osdep.h"
-#include "hw/i386/apic_internal.h"
-#include "hw/pci/msi.h"
-#include "hw/xen/xen.h"
-
-static uint64_t xen_apic_mem_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- return ~(uint64_t)0;
-}
-
-static void xen_apic_mem_write(void *opaque, hwaddr addr,
- uint64_t data, unsigned size)
-{
- if (size != sizeof(uint32_t)) {
- fprintf(stderr, "Xen: APIC write data size = %d, invalid\n", size);
- return;
- }
-
- xen_hvm_inject_msi(addr, data);
-}
-
-static const MemoryRegionOps xen_apic_io_ops = {
- .read = xen_apic_mem_read,
- .write = xen_apic_mem_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void xen_apic_realize(DeviceState *dev, Error **errp)
-{
- APICCommonState *s = APIC_COMMON(dev);
-
- s->vapic_control = 0;
- memory_region_init_io(&s->io_memory, OBJECT(s), &xen_apic_io_ops, s,
- "xen-apic-msi", APIC_SPACE_SIZE);
- msi_nonbroken = true;
-}
-
-static void xen_apic_set_base(APICCommonState *s, uint64_t val)
-{
-}
-
-static void xen_apic_set_tpr(APICCommonState *s, uint8_t val)
-{
-}
-
-static uint8_t xen_apic_get_tpr(APICCommonState *s)
-{
- return 0;
-}
-
-static void xen_apic_vapic_base_update(APICCommonState *s)
-{
-}
-
-static void xen_apic_external_nmi(APICCommonState *s)
-{
-}
-
-static void xen_apic_class_init(ObjectClass *klass, void *data)
-{
- APICCommonClass *k = APIC_COMMON_CLASS(klass);
-
- k->realize = xen_apic_realize;
- k->set_base = xen_apic_set_base;
- k->set_tpr = xen_apic_set_tpr;
- k->get_tpr = xen_apic_get_tpr;
- k->vapic_base_update = xen_apic_vapic_base_update;
- k->external_nmi = xen_apic_external_nmi;
-}
-
-static const TypeInfo xen_apic_info = {
- .name = "xen-apic",
- .parent = TYPE_APIC_COMMON,
- .instance_size = sizeof(APICCommonState),
- .class_init = xen_apic_class_init,
-};
-
-static void xen_apic_register_types(void)
-{
- type_register_static(&xen_apic_info);
-}
-
-type_init(xen_apic_register_types)
diff --git a/qemu/hw/i386/xen/xen_platform.c b/qemu/hw/i386/xen/xen_platform.c
deleted file mode 100644
index aa7839324..000000000
--- a/qemu/hw/i386/xen/xen_platform.c
+++ /dev/null
@@ -1,455 +0,0 @@
-/*
- * XEN platform pci device, formerly known as the event channel device
- *
- * Copyright (c) 2003-2004 Intel Corp.
- * Copyright (c) 2006 XenSource
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/hw.h"
-#include "hw/i386/pc.h"
-#include "hw/ide.h"
-#include "hw/pci/pci.h"
-#include "hw/irq.h"
-#include "hw/xen/xen_common.h"
-#include "hw/xen/xen_backend.h"
-#include "trace.h"
-#include "exec/address-spaces.h"
-#include "sysemu/block-backend.h"
-#include "qemu/error-report.h"
-
-#include <xenguest.h>
-
-//#define DEBUG_PLATFORM
-
-#ifdef DEBUG_PLATFORM
-#define DPRINTF(fmt, ...) do { \
- fprintf(stderr, "xen_platform: " fmt, ## __VA_ARGS__); \
-} while (0)
-#else
-#define DPRINTF(fmt, ...) do { } while (0)
-#endif
-
-#define PFFLAG_ROM_LOCK 1 /* Sets whether ROM memory area is RW or RO */
-
-typedef struct PCIXenPlatformState {
- /*< private >*/
- PCIDevice parent_obj;
- /*< public >*/
-
- MemoryRegion fixed_io;
- MemoryRegion bar;
- MemoryRegion mmio_bar;
- uint8_t flags; /* used only for version_id == 2 */
- int drivers_blacklisted;
- uint16_t driver_product_version;
-
- /* Log from guest drivers */
- char log_buffer[4096];
- int log_buffer_off;
-} PCIXenPlatformState;
-
-#define TYPE_XEN_PLATFORM "xen-platform"
-#define XEN_PLATFORM(obj) \
- OBJECT_CHECK(PCIXenPlatformState, (obj), TYPE_XEN_PLATFORM)
-
-#define XEN_PLATFORM_IOPORT 0x10
-
-/* Send bytes to syslog */
-static void log_writeb(PCIXenPlatformState *s, char val)
-{
- if (val == '\n' || s->log_buffer_off == sizeof(s->log_buffer) - 1) {
- /* Flush buffer */
- s->log_buffer[s->log_buffer_off] = 0;
- trace_xen_platform_log(s->log_buffer);
- s->log_buffer_off = 0;
- } else {
- s->log_buffer[s->log_buffer_off++] = val;
- }
-}
-
-/* Xen Platform, Fixed IOPort */
-#define UNPLUG_ALL_IDE_DISKS 1
-#define UNPLUG_ALL_NICS 2
-#define UNPLUG_AUX_IDE_DISKS 4
-
-static void unplug_nic(PCIBus *b, PCIDevice *d, void *o)
-{
- /* We have to ignore passthrough devices */
- if (pci_get_word(d->config + PCI_CLASS_DEVICE) ==
- PCI_CLASS_NETWORK_ETHERNET
- && strcmp(d->name, "xen-pci-passthrough") != 0) {
- object_unparent(OBJECT(d));
- }
-}
-
-static void pci_unplug_nics(PCIBus *bus)
-{
- pci_for_each_device(bus, 0, unplug_nic, NULL);
-}
-
-static void unplug_disks(PCIBus *b, PCIDevice *d, void *o)
-{
- /* We have to ignore passthrough devices */
- if (pci_get_word(d->config + PCI_CLASS_DEVICE) ==
- PCI_CLASS_STORAGE_IDE
- && strcmp(d->name, "xen-pci-passthrough") != 0) {
- pci_piix3_xen_ide_unplug(DEVICE(d));
- }
-}
-
-static void pci_unplug_disks(PCIBus *bus)
-{
- pci_for_each_device(bus, 0, unplug_disks, NULL);
-}
-
-static void platform_fixed_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
-{
- PCIXenPlatformState *s = opaque;
-
- switch (addr) {
- case 0: {
- PCIDevice *pci_dev = PCI_DEVICE(s);
- /* Unplug devices. Value is a bitmask of which devices to
- unplug, with bit 0 the IDE devices, bit 1 the network
- devices, and bit 2 the non-primary-master IDE devices. */
- if (val & UNPLUG_ALL_IDE_DISKS) {
- DPRINTF("unplug disks\n");
- blk_drain_all();
- blk_flush_all();
- pci_unplug_disks(pci_dev->bus);
- }
- if (val & UNPLUG_ALL_NICS) {
- DPRINTF("unplug nics\n");
- pci_unplug_nics(pci_dev->bus);
- }
- if (val & UNPLUG_AUX_IDE_DISKS) {
- DPRINTF("unplug auxiliary disks not supported\n");
- }
- break;
- }
- case 2:
- switch (val) {
- case 1:
- DPRINTF("Citrix Windows PV drivers loaded in guest\n");
- break;
- case 0:
- DPRINTF("Guest claimed to be running PV product 0?\n");
- break;
- default:
- DPRINTF("Unknown PV product %d loaded in guest\n", val);
- break;
- }
- s->driver_product_version = val;
- break;
- }
-}
-
-static void platform_fixed_ioport_writel(void *opaque, uint32_t addr,
- uint32_t val)
-{
- switch (addr) {
- case 0:
- /* PV driver version */
- break;
- }
-}
-
-static void platform_fixed_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
-{
- PCIXenPlatformState *s = opaque;
-
- switch (addr) {
- case 0: /* Platform flags */ {
- hvmmem_type_t mem_type = (val & PFFLAG_ROM_LOCK) ?
- HVMMEM_ram_ro : HVMMEM_ram_rw;
- if (xc_hvm_set_mem_type(xen_xc, xen_domid, mem_type, 0xc0, 0x40)) {
- DPRINTF("unable to change ro/rw state of ROM memory area!\n");
- } else {
- s->flags = val & PFFLAG_ROM_LOCK;
- DPRINTF("changed ro/rw state of ROM memory area. now is %s state.\n",
- (mem_type == HVMMEM_ram_ro ? "ro":"rw"));
- }
- break;
- }
- case 2:
- log_writeb(s, val);
- break;
- }
-}
-
-static uint32_t platform_fixed_ioport_readw(void *opaque, uint32_t addr)
-{
- PCIXenPlatformState *s = opaque;
-
- switch (addr) {
- case 0:
- if (s->drivers_blacklisted) {
- /* The drivers will recognise this magic number and refuse
- * to do anything. */
- return 0xd249;
- } else {
- /* Magic value so that you can identify the interface. */
- return 0x49d2;
- }
- default:
- return 0xffff;
- }
-}
-
-static uint32_t platform_fixed_ioport_readb(void *opaque, uint32_t addr)
-{
- PCIXenPlatformState *s = opaque;
-
- switch (addr) {
- case 0:
- /* Platform flags */
- return s->flags;
- case 2:
- /* Version number */
- return 1;
- default:
- return 0xff;
- }
-}
-
-static void platform_fixed_ioport_reset(void *opaque)
-{
- PCIXenPlatformState *s = opaque;
-
- platform_fixed_ioport_writeb(s, 0, 0);
-}
-
-static uint64_t platform_fixed_ioport_read(void *opaque,
- hwaddr addr,
- unsigned size)
-{
- switch (size) {
- case 1:
- return platform_fixed_ioport_readb(opaque, addr);
- case 2:
- return platform_fixed_ioport_readw(opaque, addr);
- default:
- return -1;
- }
-}
-
-static void platform_fixed_ioport_write(void *opaque, hwaddr addr,
-
- uint64_t val, unsigned size)
-{
- switch (size) {
- case 1:
- platform_fixed_ioport_writeb(opaque, addr, val);
- break;
- case 2:
- platform_fixed_ioport_writew(opaque, addr, val);
- break;
- case 4:
- platform_fixed_ioport_writel(opaque, addr, val);
- break;
- }
-}
-
-
-static const MemoryRegionOps platform_fixed_io_ops = {
- .read = platform_fixed_ioport_read,
- .write = platform_fixed_ioport_write,
- .valid = {
- .unaligned = true,
- },
- .impl = {
- .min_access_size = 1,
- .max_access_size = 4,
- .unaligned = true,
- },
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void platform_fixed_ioport_init(PCIXenPlatformState* s)
-{
- memory_region_init_io(&s->fixed_io, OBJECT(s), &platform_fixed_io_ops, s,
- "xen-fixed", 16);
- memory_region_add_subregion(get_system_io(), XEN_PLATFORM_IOPORT,
- &s->fixed_io);
-}
-
-/* Xen Platform PCI Device */
-
-static uint64_t xen_platform_ioport_readb(void *opaque, hwaddr addr,
- unsigned int size)
-{
- if (addr == 0) {
- return platform_fixed_ioport_readb(opaque, 0);
- } else {
- return ~0u;
- }
-}
-
-static void xen_platform_ioport_writeb(void *opaque, hwaddr addr,
- uint64_t val, unsigned int size)
-{
- PCIXenPlatformState *s = opaque;
-
- switch (addr) {
- case 0: /* Platform flags */
- platform_fixed_ioport_writeb(opaque, 0, (uint32_t)val);
- break;
- case 8:
- log_writeb(s, (uint32_t)val);
- break;
- default:
- break;
- }
-}
-
-static const MemoryRegionOps xen_pci_io_ops = {
- .read = xen_platform_ioport_readb,
- .write = xen_platform_ioport_writeb,
- .impl.min_access_size = 1,
- .impl.max_access_size = 1,
-};
-
-static void platform_ioport_bar_setup(PCIXenPlatformState *d)
-{
- memory_region_init_io(&d->bar, OBJECT(d), &xen_pci_io_ops, d,
- "xen-pci", 0x100);
-}
-
-static uint64_t platform_mmio_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- DPRINTF("Warning: attempted read from physical address "
- "0x" TARGET_FMT_plx " in xen platform mmio space\n", addr);
-
- return 0;
-}
-
-static void platform_mmio_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- DPRINTF("Warning: attempted write of 0x%"PRIx64" to physical "
- "address 0x" TARGET_FMT_plx " in xen platform mmio space\n",
- val, addr);
-}
-
-static const MemoryRegionOps platform_mmio_handler = {
- .read = &platform_mmio_read,
- .write = &platform_mmio_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void platform_mmio_setup(PCIXenPlatformState *d)
-{
- memory_region_init_io(&d->mmio_bar, OBJECT(d), &platform_mmio_handler, d,
- "xen-mmio", 0x1000000);
-}
-
-static int xen_platform_post_load(void *opaque, int version_id)
-{
- PCIXenPlatformState *s = opaque;
-
- platform_fixed_ioport_writeb(s, 0, s->flags);
-
- return 0;
-}
-
-static const VMStateDescription vmstate_xen_platform = {
- .name = "platform",
- .version_id = 4,
- .minimum_version_id = 4,
- .post_load = xen_platform_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(parent_obj, PCIXenPlatformState),
- VMSTATE_UINT8(flags, PCIXenPlatformState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void xen_platform_realize(PCIDevice *dev, Error **errp)
-{
- PCIXenPlatformState *d = XEN_PLATFORM(dev);
- uint8_t *pci_conf;
-
- /* Device will crash on reset if xen is not initialized */
- if (!xen_enabled()) {
- error_setg(errp, "xen-platform device requires the Xen accelerator");
- return;
- }
-
- pci_conf = dev->config;
-
- pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
-
- pci_config_set_prog_interface(pci_conf, 0);
-
- pci_conf[PCI_INTERRUPT_PIN] = 1;
-
- platform_ioport_bar_setup(d);
- pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &d->bar);
-
- /* reserve 16MB mmio address for share memory*/
- platform_mmio_setup(d);
- pci_register_bar(dev, 1, PCI_BASE_ADDRESS_MEM_PREFETCH,
- &d->mmio_bar);
-
- platform_fixed_ioport_init(d);
-}
-
-static void platform_reset(DeviceState *dev)
-{
- PCIXenPlatformState *s = XEN_PLATFORM(dev);
-
- platform_fixed_ioport_reset(s);
-}
-
-static void xen_platform_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = xen_platform_realize;
- k->vendor_id = PCI_VENDOR_ID_XEN;
- k->device_id = PCI_DEVICE_ID_XEN_PLATFORM;
- k->class_id = PCI_CLASS_OTHERS << 8 | 0x80;
- k->subsystem_vendor_id = PCI_VENDOR_ID_XEN;
- k->subsystem_id = PCI_DEVICE_ID_XEN_PLATFORM;
- k->revision = 1;
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- dc->desc = "XEN platform pci device";
- dc->reset = platform_reset;
- dc->vmsd = &vmstate_xen_platform;
-}
-
-static const TypeInfo xen_platform_info = {
- .name = TYPE_XEN_PLATFORM,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(PCIXenPlatformState),
- .class_init = xen_platform_class_init,
-};
-
-static void xen_platform_register_types(void)
-{
- type_register_static(&xen_platform_info);
-}
-
-type_init(xen_platform_register_types)
diff --git a/qemu/hw/i386/xen/xen_pvdevice.c b/qemu/hw/i386/xen/xen_pvdevice.c
deleted file mode 100644
index c093b3445..000000000
--- a/qemu/hw/i386/xen/xen_pvdevice.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/* Copyright (c) Citrix Systems Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms,
- * with or without modification, are permitted provided
- * that the following conditions are met:
- *
- * * Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the
- * following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the
- * following disclaimer in the documentation and/or other
- * materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/hw.h"
-#include "hw/pci/pci.h"
-#include "trace.h"
-
-#define TYPE_XEN_PV_DEVICE "xen-pvdevice"
-
-#define XEN_PV_DEVICE(obj) \
- OBJECT_CHECK(XenPVDevice, (obj), TYPE_XEN_PV_DEVICE)
-
-typedef struct XenPVDevice {
- /*< private >*/
- PCIDevice parent_obj;
- /*< public >*/
- uint16_t vendor_id;
- uint16_t device_id;
- uint8_t revision;
- uint32_t size;
- MemoryRegion mmio;
-} XenPVDevice;
-
-static uint64_t xen_pv_mmio_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- trace_xen_pv_mmio_read(addr);
-
- return ~(uint64_t)0;
-}
-
-static void xen_pv_mmio_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- trace_xen_pv_mmio_write(addr);
-}
-
-static const MemoryRegionOps xen_pv_mmio_ops = {
- .read = &xen_pv_mmio_read,
- .write = &xen_pv_mmio_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void xen_pv_realize(PCIDevice *pci_dev, Error **errp)
-{
- XenPVDevice *d = XEN_PV_DEVICE(pci_dev);
- uint8_t *pci_conf;
-
- /* device-id property must always be supplied */
- if (d->device_id == 0xffff) {
- error_setg(errp, "Device ID invalid, it must always be supplied");
- return;
- }
-
- pci_conf = pci_dev->config;
-
- pci_set_word(pci_conf + PCI_VENDOR_ID, d->vendor_id);
- pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, d->vendor_id);
- pci_set_word(pci_conf + PCI_DEVICE_ID, d->device_id);
- pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, d->device_id);
- pci_set_byte(pci_conf + PCI_REVISION_ID, d->revision);
-
- pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_MEMORY);
-
- pci_config_set_prog_interface(pci_conf, 0);
-
- pci_conf[PCI_INTERRUPT_PIN] = 1;
-
- memory_region_init_io(&d->mmio, NULL, &xen_pv_mmio_ops, d,
- "mmio", d->size);
-
- pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_MEM_PREFETCH,
- &d->mmio);
-}
-
-static Property xen_pv_props[] = {
- DEFINE_PROP_UINT16("vendor-id", XenPVDevice, vendor_id, PCI_VENDOR_ID_XEN),
- DEFINE_PROP_UINT16("device-id", XenPVDevice, device_id, 0xffff),
- DEFINE_PROP_UINT8("revision", XenPVDevice, revision, 0x01),
- DEFINE_PROP_UINT32("size", XenPVDevice, size, 0x400000),
- DEFINE_PROP_END_OF_LIST()
-};
-
-static void xen_pv_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = xen_pv_realize;
- k->class_id = PCI_CLASS_SYSTEM_OTHER;
- dc->desc = "Xen PV Device";
- dc->props = xen_pv_props;
-}
-
-static const TypeInfo xen_pv_type_info = {
- .name = TYPE_XEN_PV_DEVICE,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(XenPVDevice),
- .class_init = xen_pv_class_init,
-};
-
-static void xen_pv_register_types(void)
-{
- type_register_static(&xen_pv_type_info);
-}
-
-type_init(xen_pv_register_types)
diff --git a/qemu/hw/ide/Makefile.objs b/qemu/hw/ide/Makefile.objs
deleted file mode 100644
index 729e9bd0d..000000000
--- a/qemu/hw/ide/Makefile.objs
+++ /dev/null
@@ -1,12 +0,0 @@
-common-obj-$(CONFIG_IDE_CORE) += core.o atapi.o
-common-obj-$(CONFIG_IDE_QDEV) += qdev.o
-common-obj-$(CONFIG_IDE_PCI) += pci.o
-common-obj-$(CONFIG_IDE_ISA) += isa.o
-common-obj-$(CONFIG_IDE_PIIX) += piix.o
-common-obj-$(CONFIG_IDE_CMD646) += cmd646.o
-common-obj-$(CONFIG_IDE_MACIO) += macio.o
-common-obj-$(CONFIG_IDE_MMIO) += mmio.o
-common-obj-$(CONFIG_IDE_VIA) += via.o
-common-obj-$(CONFIG_MICRODRIVE) += microdrive.o
-common-obj-$(CONFIG_AHCI) += ahci.o
-common-obj-$(CONFIG_AHCI) += ich.o
diff --git a/qemu/hw/ide/ahci.c b/qemu/hw/ide/ahci.c
deleted file mode 100644
index f244bc01c..000000000
--- a/qemu/hw/ide/ahci.c
+++ /dev/null
@@ -1,1832 +0,0 @@
-/*
- * QEMU AHCI Emulation
- *
- * Copyright (c) 2010 qiaochong@loongson.cn
- * Copyright (c) 2010 Roland Elek <elek.roland@gmail.com>
- * Copyright (c) 2010 Sebastian Herbszt <herbszt@gmx.de>
- * Copyright (c) 2010 Alexander Graf <agraf@suse.de>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "qemu/osdep.h"
-#include <hw/hw.h>
-#include <hw/pci/msi.h>
-#include <hw/i386/pc.h>
-#include <hw/pci/pci.h>
-
-#include "qemu/error-report.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/dma.h"
-#include "internal.h"
-#include <hw/ide/pci.h>
-#include <hw/ide/ahci.h>
-
-#define DEBUG_AHCI 0
-
-#define DPRINTF(port, fmt, ...) \
-do { \
- if (DEBUG_AHCI) { \
- fprintf(stderr, "ahci: %s: [%d] ", __func__, port); \
- fprintf(stderr, fmt, ## __VA_ARGS__); \
- } \
-} while (0)
-
-static void check_cmd(AHCIState *s, int port);
-static int handle_cmd(AHCIState *s, int port, uint8_t slot);
-static void ahci_reset_port(AHCIState *s, int port);
-static bool ahci_write_fis_d2h(AHCIDevice *ad);
-static void ahci_init_d2h(AHCIDevice *ad);
-static int ahci_dma_prepare_buf(IDEDMA *dma, int32_t limit);
-static bool ahci_map_clb_address(AHCIDevice *ad);
-static bool ahci_map_fis_address(AHCIDevice *ad);
-static void ahci_unmap_clb_address(AHCIDevice *ad);
-static void ahci_unmap_fis_address(AHCIDevice *ad);
-
-
-static uint32_t ahci_port_read(AHCIState *s, int port, int offset)
-{
- uint32_t val;
- AHCIPortRegs *pr;
- pr = &s->dev[port].port_regs;
-
- switch (offset) {
- case PORT_LST_ADDR:
- val = pr->lst_addr;
- break;
- case PORT_LST_ADDR_HI:
- val = pr->lst_addr_hi;
- break;
- case PORT_FIS_ADDR:
- val = pr->fis_addr;
- break;
- case PORT_FIS_ADDR_HI:
- val = pr->fis_addr_hi;
- break;
- case PORT_IRQ_STAT:
- val = pr->irq_stat;
- break;
- case PORT_IRQ_MASK:
- val = pr->irq_mask;
- break;
- case PORT_CMD:
- val = pr->cmd;
- break;
- case PORT_TFDATA:
- val = pr->tfdata;
- break;
- case PORT_SIG:
- val = pr->sig;
- break;
- case PORT_SCR_STAT:
- if (s->dev[port].port.ifs[0].blk) {
- val = SATA_SCR_SSTATUS_DET_DEV_PRESENT_PHY_UP |
- SATA_SCR_SSTATUS_SPD_GEN1 | SATA_SCR_SSTATUS_IPM_ACTIVE;
- } else {
- val = SATA_SCR_SSTATUS_DET_NODEV;
- }
- break;
- case PORT_SCR_CTL:
- val = pr->scr_ctl;
- break;
- case PORT_SCR_ERR:
- val = pr->scr_err;
- break;
- case PORT_SCR_ACT:
- val = pr->scr_act;
- break;
- case PORT_CMD_ISSUE:
- val = pr->cmd_issue;
- break;
- case PORT_RESERVED:
- default:
- val = 0;
- }
- DPRINTF(port, "offset: 0x%x val: 0x%x\n", offset, val);
- return val;
-
-}
-
-static void ahci_irq_raise(AHCIState *s, AHCIDevice *dev)
-{
- DeviceState *dev_state = s->container;
- PCIDevice *pci_dev = (PCIDevice *) object_dynamic_cast(OBJECT(dev_state),
- TYPE_PCI_DEVICE);
-
- DPRINTF(0, "raise irq\n");
-
- if (pci_dev && msi_enabled(pci_dev)) {
- msi_notify(pci_dev, 0);
- } else {
- qemu_irq_raise(s->irq);
- }
-}
-
-static void ahci_irq_lower(AHCIState *s, AHCIDevice *dev)
-{
- DeviceState *dev_state = s->container;
- PCIDevice *pci_dev = (PCIDevice *) object_dynamic_cast(OBJECT(dev_state),
- TYPE_PCI_DEVICE);
-
- DPRINTF(0, "lower irq\n");
-
- if (!pci_dev || !msi_enabled(pci_dev)) {
- qemu_irq_lower(s->irq);
- }
-}
-
-static void ahci_check_irq(AHCIState *s)
-{
- int i;
-
- DPRINTF(-1, "check irq %#x\n", s->control_regs.irqstatus);
-
- s->control_regs.irqstatus = 0;
- for (i = 0; i < s->ports; i++) {
- AHCIPortRegs *pr = &s->dev[i].port_regs;
- if (pr->irq_stat & pr->irq_mask) {
- s->control_regs.irqstatus |= (1 << i);
- }
- }
-
- if (s->control_regs.irqstatus &&
- (s->control_regs.ghc & HOST_CTL_IRQ_EN)) {
- ahci_irq_raise(s, NULL);
- } else {
- ahci_irq_lower(s, NULL);
- }
-}
-
-static void ahci_trigger_irq(AHCIState *s, AHCIDevice *d,
- int irq_type)
-{
- DPRINTF(d->port_no, "trigger irq %#x -> %x\n",
- irq_type, d->port_regs.irq_mask & irq_type);
-
- d->port_regs.irq_stat |= irq_type;
- ahci_check_irq(s);
-}
-
-static void map_page(AddressSpace *as, uint8_t **ptr, uint64_t addr,
- uint32_t wanted)
-{
- hwaddr len = wanted;
-
- if (*ptr) {
- dma_memory_unmap(as, *ptr, len, DMA_DIRECTION_FROM_DEVICE, len);
- }
-
- *ptr = dma_memory_map(as, addr, &len, DMA_DIRECTION_FROM_DEVICE);
- if (len < wanted) {
- dma_memory_unmap(as, *ptr, len, DMA_DIRECTION_FROM_DEVICE, len);
- *ptr = NULL;
- }
-}
-
-/**
- * Check the cmd register to see if we should start or stop
- * the DMA or FIS RX engines.
- *
- * @ad: Device to dis/engage.
- *
- * @return 0 on success, -1 on error.
- */
-static int ahci_cond_start_engines(AHCIDevice *ad)
-{
- AHCIPortRegs *pr = &ad->port_regs;
- bool cmd_start = pr->cmd & PORT_CMD_START;
- bool cmd_on = pr->cmd & PORT_CMD_LIST_ON;
- bool fis_start = pr->cmd & PORT_CMD_FIS_RX;
- bool fis_on = pr->cmd & PORT_CMD_FIS_ON;
-
- if (cmd_start && !cmd_on) {
- if (!ahci_map_clb_address(ad)) {
- pr->cmd &= ~PORT_CMD_START;
- error_report("AHCI: Failed to start DMA engine: "
- "bad command list buffer address");
- return -1;
- }
- } else if (!cmd_start && cmd_on) {
- ahci_unmap_clb_address(ad);
- }
-
- if (fis_start && !fis_on) {
- if (!ahci_map_fis_address(ad)) {
- pr->cmd &= ~PORT_CMD_FIS_RX;
- error_report("AHCI: Failed to start FIS receive engine: "
- "bad FIS receive buffer address");
- return -1;
- }
- } else if (!fis_start && fis_on) {
- ahci_unmap_fis_address(ad);
- }
-
- return 0;
-}
-
-static void ahci_port_write(AHCIState *s, int port, int offset, uint32_t val)
-{
- AHCIPortRegs *pr = &s->dev[port].port_regs;
-
- DPRINTF(port, "offset: 0x%x val: 0x%x\n", offset, val);
- switch (offset) {
- case PORT_LST_ADDR:
- pr->lst_addr = val;
- break;
- case PORT_LST_ADDR_HI:
- pr->lst_addr_hi = val;
- break;
- case PORT_FIS_ADDR:
- pr->fis_addr = val;
- break;
- case PORT_FIS_ADDR_HI:
- pr->fis_addr_hi = val;
- break;
- case PORT_IRQ_STAT:
- pr->irq_stat &= ~val;
- ahci_check_irq(s);
- break;
- case PORT_IRQ_MASK:
- pr->irq_mask = val & 0xfdc000ff;
- ahci_check_irq(s);
- break;
- case PORT_CMD:
- /* Block any Read-only fields from being set;
- * including LIST_ON and FIS_ON.
- * The spec requires to set ICC bits to zero after the ICC change
- * is done. We don't support ICC state changes, therefore always
- * force the ICC bits to zero.
- */
- pr->cmd = (pr->cmd & PORT_CMD_RO_MASK) |
- (val & ~(PORT_CMD_RO_MASK|PORT_CMD_ICC_MASK));
-
- /* Check FIS RX and CLB engines */
- ahci_cond_start_engines(&s->dev[port]);
-
- /* XXX usually the FIS would be pending on the bus here and
- issuing deferred until the OS enables FIS receival.
- Instead, we only submit it once - which works in most
- cases, but is a hack. */
- if ((pr->cmd & PORT_CMD_FIS_ON) &&
- !s->dev[port].init_d2h_sent) {
- ahci_init_d2h(&s->dev[port]);
- }
-
- check_cmd(s, port);
- break;
- case PORT_TFDATA:
- /* Read Only. */
- break;
- case PORT_SIG:
- /* Read Only */
- break;
- case PORT_SCR_STAT:
- /* Read Only */
- break;
- case PORT_SCR_CTL:
- if (((pr->scr_ctl & AHCI_SCR_SCTL_DET) == 1) &&
- ((val & AHCI_SCR_SCTL_DET) == 0)) {
- ahci_reset_port(s, port);
- }
- pr->scr_ctl = val;
- break;
- case PORT_SCR_ERR:
- pr->scr_err &= ~val;
- break;
- case PORT_SCR_ACT:
- /* RW1 */
- pr->scr_act |= val;
- break;
- case PORT_CMD_ISSUE:
- pr->cmd_issue |= val;
- check_cmd(s, port);
- break;
- default:
- break;
- }
-}
-
-static uint64_t ahci_mem_read_32(void *opaque, hwaddr addr)
-{
- AHCIState *s = opaque;
- uint32_t val = 0;
-
- if (addr < AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR) {
- switch (addr) {
- case HOST_CAP:
- val = s->control_regs.cap;
- break;
- case HOST_CTL:
- val = s->control_regs.ghc;
- break;
- case HOST_IRQ_STAT:
- val = s->control_regs.irqstatus;
- break;
- case HOST_PORTS_IMPL:
- val = s->control_regs.impl;
- break;
- case HOST_VERSION:
- val = s->control_regs.version;
- break;
- }
-
- DPRINTF(-1, "(addr 0x%08X), val 0x%08X\n", (unsigned) addr, val);
- } else if ((addr >= AHCI_PORT_REGS_START_ADDR) &&
- (addr < (AHCI_PORT_REGS_START_ADDR +
- (s->ports * AHCI_PORT_ADDR_OFFSET_LEN)))) {
- val = ahci_port_read(s, (addr - AHCI_PORT_REGS_START_ADDR) >> 7,
- addr & AHCI_PORT_ADDR_OFFSET_MASK);
- }
-
- return val;
-}
-
-
-/**
- * AHCI 1.3 section 3 ("HBA Memory Registers")
- * Support unaligned 8/16/32 bit reads, and 64 bit aligned reads.
- * Caller is responsible for masking unwanted higher order bytes.
- */
-static uint64_t ahci_mem_read(void *opaque, hwaddr addr, unsigned size)
-{
- hwaddr aligned = addr & ~0x3;
- int ofst = addr - aligned;
- uint64_t lo = ahci_mem_read_32(opaque, aligned);
- uint64_t hi;
- uint64_t val;
-
- /* if < 8 byte read does not cross 4 byte boundary */
- if (ofst + size <= 4) {
- val = lo >> (ofst * 8);
- } else {
- g_assert_cmpint(size, >, 1);
-
- /* If the 64bit read is unaligned, we will produce undefined
- * results. AHCI does not support unaligned 64bit reads. */
- hi = ahci_mem_read_32(opaque, aligned + 4);
- val = (hi << 32 | lo) >> (ofst * 8);
- }
-
- DPRINTF(-1, "addr=0x%" HWADDR_PRIx " val=0x%" PRIx64 ", size=%d\n",
- addr, val, size);
- return val;
-}
-
-
-static void ahci_mem_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- AHCIState *s = opaque;
-
- DPRINTF(-1, "addr=0x%" HWADDR_PRIx " val=0x%" PRIx64 ", size=%d\n",
- addr, val, size);
-
- /* Only aligned reads are allowed on AHCI */
- if (addr & 3) {
- fprintf(stderr, "ahci: Mis-aligned write to addr 0x"
- TARGET_FMT_plx "\n", addr);
- return;
- }
-
- if (addr < AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR) {
- DPRINTF(-1, "(addr 0x%08X), val 0x%08"PRIX64"\n", (unsigned) addr, val);
-
- switch (addr) {
- case HOST_CAP: /* R/WO, RO */
- /* FIXME handle R/WO */
- break;
- case HOST_CTL: /* R/W */
- if (val & HOST_CTL_RESET) {
- DPRINTF(-1, "HBA Reset\n");
- ahci_reset(s);
- } else {
- s->control_regs.ghc = (val & 0x3) | HOST_CTL_AHCI_EN;
- ahci_check_irq(s);
- }
- break;
- case HOST_IRQ_STAT: /* R/WC, RO */
- s->control_regs.irqstatus &= ~val;
- ahci_check_irq(s);
- break;
- case HOST_PORTS_IMPL: /* R/WO, RO */
- /* FIXME handle R/WO */
- break;
- case HOST_VERSION: /* RO */
- /* FIXME report write? */
- break;
- default:
- DPRINTF(-1, "write to unknown register 0x%x\n", (unsigned)addr);
- }
- } else if ((addr >= AHCI_PORT_REGS_START_ADDR) &&
- (addr < (AHCI_PORT_REGS_START_ADDR +
- (s->ports * AHCI_PORT_ADDR_OFFSET_LEN)))) {
- ahci_port_write(s, (addr - AHCI_PORT_REGS_START_ADDR) >> 7,
- addr & AHCI_PORT_ADDR_OFFSET_MASK, val);
- }
-
-}
-
-static const MemoryRegionOps ahci_mem_ops = {
- .read = ahci_mem_read,
- .write = ahci_mem_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static uint64_t ahci_idp_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- AHCIState *s = opaque;
-
- if (addr == s->idp_offset) {
- /* index register */
- return s->idp_index;
- } else if (addr == s->idp_offset + 4) {
- /* data register - do memory read at location selected by index */
- return ahci_mem_read(opaque, s->idp_index, size);
- } else {
- return 0;
- }
-}
-
-static void ahci_idp_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- AHCIState *s = opaque;
-
- if (addr == s->idp_offset) {
- /* index register - mask off reserved bits */
- s->idp_index = (uint32_t)val & ((AHCI_MEM_BAR_SIZE - 1) & ~3);
- } else if (addr == s->idp_offset + 4) {
- /* data register - do memory write at location selected by index */
- ahci_mem_write(opaque, s->idp_index, val, size);
- }
-}
-
-static const MemoryRegionOps ahci_idp_ops = {
- .read = ahci_idp_read,
- .write = ahci_idp_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-
-static void ahci_reg_init(AHCIState *s)
-{
- int i;
-
- s->control_regs.cap = (s->ports - 1) |
- (AHCI_NUM_COMMAND_SLOTS << 8) |
- (AHCI_SUPPORTED_SPEED_GEN1 << AHCI_SUPPORTED_SPEED) |
- HOST_CAP_NCQ | HOST_CAP_AHCI;
-
- s->control_regs.impl = (1 << s->ports) - 1;
-
- s->control_regs.version = AHCI_VERSION_1_0;
-
- for (i = 0; i < s->ports; i++) {
- s->dev[i].port_state = STATE_RUN;
- }
-}
-
-static void check_cmd(AHCIState *s, int port)
-{
- AHCIPortRegs *pr = &s->dev[port].port_regs;
- uint8_t slot;
-
- if ((pr->cmd & PORT_CMD_START) && pr->cmd_issue) {
- for (slot = 0; (slot < 32) && pr->cmd_issue; slot++) {
- if ((pr->cmd_issue & (1U << slot)) &&
- !handle_cmd(s, port, slot)) {
- pr->cmd_issue &= ~(1U << slot);
- }
- }
- }
-}
-
-static void ahci_check_cmd_bh(void *opaque)
-{
- AHCIDevice *ad = opaque;
-
- qemu_bh_delete(ad->check_bh);
- ad->check_bh = NULL;
-
- if ((ad->busy_slot != -1) &&
- !(ad->port.ifs[0].status & (BUSY_STAT|DRQ_STAT))) {
- /* no longer busy */
- ad->port_regs.cmd_issue &= ~(1 << ad->busy_slot);
- ad->busy_slot = -1;
- }
-
- check_cmd(ad->hba, ad->port_no);
-}
-
-static void ahci_init_d2h(AHCIDevice *ad)
-{
- IDEState *ide_state = &ad->port.ifs[0];
- AHCIPortRegs *pr = &ad->port_regs;
-
- if (ad->init_d2h_sent) {
- return;
- }
-
- if (ahci_write_fis_d2h(ad)) {
- ad->init_d2h_sent = true;
- /* We're emulating receiving the first Reg H2D Fis from the device;
- * Update the SIG register, but otherwise proceed as normal. */
- pr->sig = ((uint32_t)ide_state->hcyl << 24) |
- (ide_state->lcyl << 16) |
- (ide_state->sector << 8) |
- (ide_state->nsector & 0xFF);
- }
-}
-
-static void ahci_set_signature(AHCIDevice *ad, uint32_t sig)
-{
- IDEState *s = &ad->port.ifs[0];
- s->hcyl = sig >> 24 & 0xFF;
- s->lcyl = sig >> 16 & 0xFF;
- s->sector = sig >> 8 & 0xFF;
- s->nsector = sig & 0xFF;
-
- DPRINTF(ad->port_no, "set hcyl:lcyl:sect:nsect = 0x%08x\n", sig);
-}
-
-static void ahci_reset_port(AHCIState *s, int port)
-{
- AHCIDevice *d = &s->dev[port];
- AHCIPortRegs *pr = &d->port_regs;
- IDEState *ide_state = &d->port.ifs[0];
- int i;
-
- DPRINTF(port, "reset port\n");
-
- ide_bus_reset(&d->port);
- ide_state->ncq_queues = AHCI_MAX_CMDS;
-
- pr->scr_stat = 0;
- pr->scr_err = 0;
- pr->scr_act = 0;
- pr->tfdata = 0x7F;
- pr->sig = 0xFFFFFFFF;
- d->busy_slot = -1;
- d->init_d2h_sent = false;
-
- ide_state = &s->dev[port].port.ifs[0];
- if (!ide_state->blk) {
- return;
- }
-
- /* reset ncq queue */
- for (i = 0; i < AHCI_MAX_CMDS; i++) {
- NCQTransferState *ncq_tfs = &s->dev[port].ncq_tfs[i];
- ncq_tfs->halt = false;
- if (!ncq_tfs->used) {
- continue;
- }
-
- if (ncq_tfs->aiocb) {
- blk_aio_cancel(ncq_tfs->aiocb);
- ncq_tfs->aiocb = NULL;
- }
-
- /* Maybe we just finished the request thanks to blk_aio_cancel() */
- if (!ncq_tfs->used) {
- continue;
- }
-
- qemu_sglist_destroy(&ncq_tfs->sglist);
- ncq_tfs->used = 0;
- }
-
- s->dev[port].port_state = STATE_RUN;
- if (ide_state->drive_kind == IDE_CD) {
- ahci_set_signature(d, SATA_SIGNATURE_CDROM);\
- ide_state->status = SEEK_STAT | WRERR_STAT | READY_STAT;
- } else {
- ahci_set_signature(d, SATA_SIGNATURE_DISK);
- ide_state->status = SEEK_STAT | WRERR_STAT;
- }
-
- ide_state->error = 1;
- ahci_init_d2h(d);
-}
-
-static void debug_print_fis(uint8_t *fis, int cmd_len)
-{
-#if DEBUG_AHCI
- int i;
-
- fprintf(stderr, "fis:");
- for (i = 0; i < cmd_len; i++) {
- if ((i & 0xf) == 0) {
- fprintf(stderr, "\n%02x:",i);
- }
- fprintf(stderr, "%02x ",fis[i]);
- }
- fprintf(stderr, "\n");
-#endif
-}
-
-static bool ahci_map_fis_address(AHCIDevice *ad)
-{
- AHCIPortRegs *pr = &ad->port_regs;
- map_page(ad->hba->as, &ad->res_fis,
- ((uint64_t)pr->fis_addr_hi << 32) | pr->fis_addr, 256);
- if (ad->res_fis != NULL) {
- pr->cmd |= PORT_CMD_FIS_ON;
- return true;
- }
-
- pr->cmd &= ~PORT_CMD_FIS_ON;
- return false;
-}
-
-static void ahci_unmap_fis_address(AHCIDevice *ad)
-{
- if (ad->res_fis == NULL) {
- DPRINTF(ad->port_no, "Attempt to unmap NULL FIS address\n");
- return;
- }
- ad->port_regs.cmd &= ~PORT_CMD_FIS_ON;
- dma_memory_unmap(ad->hba->as, ad->res_fis, 256,
- DMA_DIRECTION_FROM_DEVICE, 256);
- ad->res_fis = NULL;
-}
-
-static bool ahci_map_clb_address(AHCIDevice *ad)
-{
- AHCIPortRegs *pr = &ad->port_regs;
- ad->cur_cmd = NULL;
- map_page(ad->hba->as, &ad->lst,
- ((uint64_t)pr->lst_addr_hi << 32) | pr->lst_addr, 1024);
- if (ad->lst != NULL) {
- pr->cmd |= PORT_CMD_LIST_ON;
- return true;
- }
-
- pr->cmd &= ~PORT_CMD_LIST_ON;
- return false;
-}
-
-static void ahci_unmap_clb_address(AHCIDevice *ad)
-{
- if (ad->lst == NULL) {
- DPRINTF(ad->port_no, "Attempt to unmap NULL CLB address\n");
- return;
- }
- ad->port_regs.cmd &= ~PORT_CMD_LIST_ON;
- dma_memory_unmap(ad->hba->as, ad->lst, 1024,
- DMA_DIRECTION_FROM_DEVICE, 1024);
- ad->lst = NULL;
-}
-
-static void ahci_write_fis_sdb(AHCIState *s, NCQTransferState *ncq_tfs)
-{
- AHCIDevice *ad = ncq_tfs->drive;
- AHCIPortRegs *pr = &ad->port_regs;
- IDEState *ide_state;
- SDBFIS *sdb_fis;
-
- if (!ad->res_fis ||
- !(pr->cmd & PORT_CMD_FIS_RX)) {
- return;
- }
-
- sdb_fis = (SDBFIS *)&ad->res_fis[RES_FIS_SDBFIS];
- ide_state = &ad->port.ifs[0];
-
- sdb_fis->type = SATA_FIS_TYPE_SDB;
- /* Interrupt pending & Notification bit */
- sdb_fis->flags = 0x40; /* Interrupt bit, always 1 for NCQ */
- sdb_fis->status = ide_state->status & 0x77;
- sdb_fis->error = ide_state->error;
- /* update SAct field in SDB_FIS */
- sdb_fis->payload = cpu_to_le32(ad->finished);
-
- /* Update shadow registers (except BSY 0x80 and DRQ 0x08) */
- pr->tfdata = (ad->port.ifs[0].error << 8) |
- (ad->port.ifs[0].status & 0x77) |
- (pr->tfdata & 0x88);
- pr->scr_act &= ~ad->finished;
- ad->finished = 0;
-
- /* Trigger IRQ if interrupt bit is set (which currently, it always is) */
- if (sdb_fis->flags & 0x40) {
- ahci_trigger_irq(s, ad, PORT_IRQ_SDB_FIS);
- }
-}
-
-static void ahci_write_fis_pio(AHCIDevice *ad, uint16_t len)
-{
- AHCIPortRegs *pr = &ad->port_regs;
- uint8_t *pio_fis;
- IDEState *s = &ad->port.ifs[0];
-
- if (!ad->res_fis || !(pr->cmd & PORT_CMD_FIS_RX)) {
- return;
- }
-
- pio_fis = &ad->res_fis[RES_FIS_PSFIS];
-
- pio_fis[0] = SATA_FIS_TYPE_PIO_SETUP;
- pio_fis[1] = (ad->hba->control_regs.irqstatus ? (1 << 6) : 0);
- pio_fis[2] = s->status;
- pio_fis[3] = s->error;
-
- pio_fis[4] = s->sector;
- pio_fis[5] = s->lcyl;
- pio_fis[6] = s->hcyl;
- pio_fis[7] = s->select;
- pio_fis[8] = s->hob_sector;
- pio_fis[9] = s->hob_lcyl;
- pio_fis[10] = s->hob_hcyl;
- pio_fis[11] = 0;
- pio_fis[12] = s->nsector & 0xFF;
- pio_fis[13] = (s->nsector >> 8) & 0xFF;
- pio_fis[14] = 0;
- pio_fis[15] = s->status;
- pio_fis[16] = len & 255;
- pio_fis[17] = len >> 8;
- pio_fis[18] = 0;
- pio_fis[19] = 0;
-
- /* Update shadow registers: */
- pr->tfdata = (ad->port.ifs[0].error << 8) |
- ad->port.ifs[0].status;
-
- if (pio_fis[2] & ERR_STAT) {
- ahci_trigger_irq(ad->hba, ad, PORT_IRQ_TF_ERR);
- }
-
- ahci_trigger_irq(ad->hba, ad, PORT_IRQ_PIOS_FIS);
-}
-
-static bool ahci_write_fis_d2h(AHCIDevice *ad)
-{
- AHCIPortRegs *pr = &ad->port_regs;
- uint8_t *d2h_fis;
- int i;
- IDEState *s = &ad->port.ifs[0];
-
- if (!ad->res_fis || !(pr->cmd & PORT_CMD_FIS_RX)) {
- return false;
- }
-
- d2h_fis = &ad->res_fis[RES_FIS_RFIS];
-
- d2h_fis[0] = SATA_FIS_TYPE_REGISTER_D2H;
- d2h_fis[1] = (ad->hba->control_regs.irqstatus ? (1 << 6) : 0);
- d2h_fis[2] = s->status;
- d2h_fis[3] = s->error;
-
- d2h_fis[4] = s->sector;
- d2h_fis[5] = s->lcyl;
- d2h_fis[6] = s->hcyl;
- d2h_fis[7] = s->select;
- d2h_fis[8] = s->hob_sector;
- d2h_fis[9] = s->hob_lcyl;
- d2h_fis[10] = s->hob_hcyl;
- d2h_fis[11] = 0;
- d2h_fis[12] = s->nsector & 0xFF;
- d2h_fis[13] = (s->nsector >> 8) & 0xFF;
- for (i = 14; i < 20; i++) {
- d2h_fis[i] = 0;
- }
-
- /* Update shadow registers: */
- pr->tfdata = (ad->port.ifs[0].error << 8) |
- ad->port.ifs[0].status;
-
- if (d2h_fis[2] & ERR_STAT) {
- ahci_trigger_irq(ad->hba, ad, PORT_IRQ_TF_ERR);
- }
-
- ahci_trigger_irq(ad->hba, ad, PORT_IRQ_D2H_REG_FIS);
- return true;
-}
-
-static int prdt_tbl_entry_size(const AHCI_SG *tbl)
-{
- /* flags_size is zero-based */
- return (le32_to_cpu(tbl->flags_size) & AHCI_PRDT_SIZE_MASK) + 1;
-}
-
-/**
- * Fetch entries in a guest-provided PRDT and convert it into a QEMU SGlist.
- * @ad: The AHCIDevice for whom we are building the SGList.
- * @sglist: The SGList target to add PRD entries to.
- * @cmd: The AHCI Command Header that describes where the PRDT is.
- * @limit: The remaining size of the S/ATA transaction, in bytes.
- * @offset: The number of bytes already transferred, in bytes.
- *
- * The AHCI PRDT can describe up to 256GiB. S/ATA only support transactions of
- * up to 32MiB as of ATA8-ACS3 rev 1b, assuming a 512 byte sector size. We stop
- * building the sglist from the PRDT as soon as we hit @limit bytes,
- * which is <= INT32_MAX/2GiB.
- */
-static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist,
- AHCICmdHdr *cmd, int64_t limit, uint64_t offset)
-{
- uint16_t opts = le16_to_cpu(cmd->opts);
- uint16_t prdtl = le16_to_cpu(cmd->prdtl);
- uint64_t cfis_addr = le64_to_cpu(cmd->tbl_addr);
- uint64_t prdt_addr = cfis_addr + 0x80;
- dma_addr_t prdt_len = (prdtl * sizeof(AHCI_SG));
- dma_addr_t real_prdt_len = prdt_len;
- uint8_t *prdt;
- int i;
- int r = 0;
- uint64_t sum = 0;
- int off_idx = -1;
- int64_t off_pos = -1;
- int tbl_entry_size;
- IDEBus *bus = &ad->port;
- BusState *qbus = BUS(bus);
-
- if (!prdtl) {
- DPRINTF(ad->port_no, "no sg list given by guest: 0x%08x\n", opts);
- return -1;
- }
-
- /* map PRDT */
- if (!(prdt = dma_memory_map(ad->hba->as, prdt_addr, &prdt_len,
- DMA_DIRECTION_TO_DEVICE))){
- DPRINTF(ad->port_no, "map failed\n");
- return -1;
- }
-
- if (prdt_len < real_prdt_len) {
- DPRINTF(ad->port_no, "mapped less than expected\n");
- r = -1;
- goto out;
- }
-
- /* Get entries in the PRDT, init a qemu sglist accordingly */
- if (prdtl > 0) {
- AHCI_SG *tbl = (AHCI_SG *)prdt;
- sum = 0;
- for (i = 0; i < prdtl; i++) {
- tbl_entry_size = prdt_tbl_entry_size(&tbl[i]);
- if (offset < (sum + tbl_entry_size)) {
- off_idx = i;
- off_pos = offset - sum;
- break;
- }
- sum += tbl_entry_size;
- }
- if ((off_idx == -1) || (off_pos < 0) || (off_pos > tbl_entry_size)) {
- DPRINTF(ad->port_no, "%s: Incorrect offset! "
- "off_idx: %d, off_pos: %"PRId64"\n",
- __func__, off_idx, off_pos);
- r = -1;
- goto out;
- }
-
- qemu_sglist_init(sglist, qbus->parent, (prdtl - off_idx),
- ad->hba->as);
- qemu_sglist_add(sglist, le64_to_cpu(tbl[off_idx].addr) + off_pos,
- MIN(prdt_tbl_entry_size(&tbl[off_idx]) - off_pos,
- limit));
-
- for (i = off_idx + 1; i < prdtl && sglist->size < limit; i++) {
- qemu_sglist_add(sglist, le64_to_cpu(tbl[i].addr),
- MIN(prdt_tbl_entry_size(&tbl[i]),
- limit - sglist->size));
- }
- }
-
-out:
- dma_memory_unmap(ad->hba->as, prdt, prdt_len,
- DMA_DIRECTION_TO_DEVICE, prdt_len);
- return r;
-}
-
-static void ncq_err(NCQTransferState *ncq_tfs)
-{
- IDEState *ide_state = &ncq_tfs->drive->port.ifs[0];
-
- ide_state->error = ABRT_ERR;
- ide_state->status = READY_STAT | ERR_STAT;
- ncq_tfs->drive->port_regs.scr_err |= (1 << ncq_tfs->tag);
- ncq_tfs->used = 0;
-}
-
-static void ncq_finish(NCQTransferState *ncq_tfs)
-{
- /* If we didn't error out, set our finished bit. Errored commands
- * do not get a bit set for the SDB FIS ACT register, nor do they
- * clear the outstanding bit in scr_act (PxSACT). */
- if (!(ncq_tfs->drive->port_regs.scr_err & (1 << ncq_tfs->tag))) {
- ncq_tfs->drive->finished |= (1 << ncq_tfs->tag);
- }
-
- ahci_write_fis_sdb(ncq_tfs->drive->hba, ncq_tfs);
-
- DPRINTF(ncq_tfs->drive->port_no, "NCQ transfer tag %d finished\n",
- ncq_tfs->tag);
-
- block_acct_done(blk_get_stats(ncq_tfs->drive->port.ifs[0].blk),
- &ncq_tfs->acct);
- qemu_sglist_destroy(&ncq_tfs->sglist);
- ncq_tfs->used = 0;
-}
-
-static void ncq_cb(void *opaque, int ret)
-{
- NCQTransferState *ncq_tfs = (NCQTransferState *)opaque;
- IDEState *ide_state = &ncq_tfs->drive->port.ifs[0];
-
- if (ret == -ECANCELED) {
- return;
- }
-
- if (ret < 0) {
- bool is_read = ncq_tfs->cmd == READ_FPDMA_QUEUED;
- BlockErrorAction action = blk_get_error_action(ide_state->blk,
- is_read, -ret);
- if (action == BLOCK_ERROR_ACTION_STOP) {
- ncq_tfs->halt = true;
- ide_state->bus->error_status = IDE_RETRY_HBA;
- } else if (action == BLOCK_ERROR_ACTION_REPORT) {
- ncq_err(ncq_tfs);
- }
- blk_error_action(ide_state->blk, action, is_read, -ret);
- } else {
- ide_state->status = READY_STAT | SEEK_STAT;
- }
-
- if (!ncq_tfs->halt) {
- ncq_finish(ncq_tfs);
- }
-}
-
-static int is_ncq(uint8_t ata_cmd)
-{
- /* Based on SATA 3.2 section 13.6.3.2 */
- switch (ata_cmd) {
- case READ_FPDMA_QUEUED:
- case WRITE_FPDMA_QUEUED:
- case NCQ_NON_DATA:
- case RECEIVE_FPDMA_QUEUED:
- case SEND_FPDMA_QUEUED:
- return 1;
- default:
- return 0;
- }
-}
-
-static void execute_ncq_command(NCQTransferState *ncq_tfs)
-{
- AHCIDevice *ad = ncq_tfs->drive;
- IDEState *ide_state = &ad->port.ifs[0];
- int port = ad->port_no;
-
- g_assert(is_ncq(ncq_tfs->cmd));
- ncq_tfs->halt = false;
-
- switch (ncq_tfs->cmd) {
- case READ_FPDMA_QUEUED:
- DPRINTF(port, "NCQ reading %d sectors from LBA %"PRId64", tag %d\n",
- ncq_tfs->sector_count, ncq_tfs->lba, ncq_tfs->tag);
-
- DPRINTF(port, "tag %d aio read %"PRId64"\n",
- ncq_tfs->tag, ncq_tfs->lba);
-
- dma_acct_start(ide_state->blk, &ncq_tfs->acct,
- &ncq_tfs->sglist, BLOCK_ACCT_READ);
- ncq_tfs->aiocb = dma_blk_read(ide_state->blk, &ncq_tfs->sglist,
- ncq_tfs->lba, ncq_cb, ncq_tfs);
- break;
- case WRITE_FPDMA_QUEUED:
- DPRINTF(port, "NCQ writing %d sectors to LBA %"PRId64", tag %d\n",
- ncq_tfs->sector_count, ncq_tfs->lba, ncq_tfs->tag);
-
- DPRINTF(port, "tag %d aio write %"PRId64"\n",
- ncq_tfs->tag, ncq_tfs->lba);
-
- dma_acct_start(ide_state->blk, &ncq_tfs->acct,
- &ncq_tfs->sglist, BLOCK_ACCT_WRITE);
- ncq_tfs->aiocb = dma_blk_write(ide_state->blk, &ncq_tfs->sglist,
- ncq_tfs->lba, ncq_cb, ncq_tfs);
- break;
- default:
- DPRINTF(port, "error: unsupported NCQ command (0x%02x) received\n",
- ncq_tfs->cmd);
- qemu_sglist_destroy(&ncq_tfs->sglist);
- ncq_err(ncq_tfs);
- }
-}
-
-
-static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis,
- uint8_t slot)
-{
- AHCIDevice *ad = &s->dev[port];
- IDEState *ide_state = &ad->port.ifs[0];
- NCQFrame *ncq_fis = (NCQFrame*)cmd_fis;
- uint8_t tag = ncq_fis->tag >> 3;
- NCQTransferState *ncq_tfs = &ad->ncq_tfs[tag];
- size_t size;
-
- g_assert(is_ncq(ncq_fis->command));
- if (ncq_tfs->used) {
- /* error - already in use */
- fprintf(stderr, "%s: tag %d already used\n", __FUNCTION__, tag);
- return;
- }
-
- ncq_tfs->used = 1;
- ncq_tfs->drive = ad;
- ncq_tfs->slot = slot;
- ncq_tfs->cmdh = &((AHCICmdHdr *)ad->lst)[slot];
- ncq_tfs->cmd = ncq_fis->command;
- ncq_tfs->lba = ((uint64_t)ncq_fis->lba5 << 40) |
- ((uint64_t)ncq_fis->lba4 << 32) |
- ((uint64_t)ncq_fis->lba3 << 24) |
- ((uint64_t)ncq_fis->lba2 << 16) |
- ((uint64_t)ncq_fis->lba1 << 8) |
- (uint64_t)ncq_fis->lba0;
- ncq_tfs->tag = tag;
-
- /* Sanity-check the NCQ packet */
- if (tag != slot) {
- DPRINTF(port, "Warn: NCQ slot (%d) did not match the given tag (%d)\n",
- slot, tag);
- }
-
- if (ncq_fis->aux0 || ncq_fis->aux1 || ncq_fis->aux2 || ncq_fis->aux3) {
- DPRINTF(port, "Warn: Attempt to use NCQ auxiliary fields.\n");
- }
- if (ncq_fis->prio || ncq_fis->icc) {
- DPRINTF(port, "Warn: Unsupported attempt to use PRIO/ICC fields\n");
- }
- if (ncq_fis->fua & NCQ_FIS_FUA_MASK) {
- DPRINTF(port, "Warn: Unsupported attempt to use Force Unit Access\n");
- }
- if (ncq_fis->tag & NCQ_FIS_RARC_MASK) {
- DPRINTF(port, "Warn: Unsupported attempt to use Rebuild Assist\n");
- }
-
- ncq_tfs->sector_count = ((ncq_fis->sector_count_high << 8) |
- ncq_fis->sector_count_low);
- if (!ncq_tfs->sector_count) {
- ncq_tfs->sector_count = 0x10000;
- }
- size = ncq_tfs->sector_count * 512;
- ahci_populate_sglist(ad, &ncq_tfs->sglist, ncq_tfs->cmdh, size, 0);
-
- if (ncq_tfs->sglist.size < size) {
- error_report("ahci: PRDT length for NCQ command (0x%zx) "
- "is smaller than the requested size (0x%zx)",
- ncq_tfs->sglist.size, size);
- qemu_sglist_destroy(&ncq_tfs->sglist);
- ncq_err(ncq_tfs);
- ahci_trigger_irq(ad->hba, ad, PORT_IRQ_OVERFLOW);
- return;
- } else if (ncq_tfs->sglist.size != size) {
- DPRINTF(port, "Warn: PRDTL (0x%zx)"
- " does not match requested size (0x%zx)",
- ncq_tfs->sglist.size, size);
- }
-
- DPRINTF(port, "NCQ transfer LBA from %"PRId64" to %"PRId64", "
- "drive max %"PRId64"\n",
- ncq_tfs->lba, ncq_tfs->lba + ncq_tfs->sector_count - 1,
- ide_state->nb_sectors - 1);
-
- execute_ncq_command(ncq_tfs);
-}
-
-static AHCICmdHdr *get_cmd_header(AHCIState *s, uint8_t port, uint8_t slot)
-{
- if (port >= s->ports || slot >= AHCI_MAX_CMDS) {
- return NULL;
- }
-
- return s->dev[port].lst ? &((AHCICmdHdr *)s->dev[port].lst)[slot] : NULL;
-}
-
-static void handle_reg_h2d_fis(AHCIState *s, int port,
- uint8_t slot, uint8_t *cmd_fis)
-{
- IDEState *ide_state = &s->dev[port].port.ifs[0];
- AHCICmdHdr *cmd = get_cmd_header(s, port, slot);
- uint16_t opts = le16_to_cpu(cmd->opts);
-
- if (cmd_fis[1] & 0x0F) {
- DPRINTF(port, "Port Multiplier not supported."
- " cmd_fis[0]=%02x cmd_fis[1]=%02x cmd_fis[2]=%02x\n",
- cmd_fis[0], cmd_fis[1], cmd_fis[2]);
- return;
- }
-
- if (cmd_fis[1] & 0x70) {
- DPRINTF(port, "Reserved flags set in H2D Register FIS."
- " cmd_fis[0]=%02x cmd_fis[1]=%02x cmd_fis[2]=%02x\n",
- cmd_fis[0], cmd_fis[1], cmd_fis[2]);
- return;
- }
-
- if (!(cmd_fis[1] & SATA_FIS_REG_H2D_UPDATE_COMMAND_REGISTER)) {
- switch (s->dev[port].port_state) {
- case STATE_RUN:
- if (cmd_fis[15] & ATA_SRST) {
- s->dev[port].port_state = STATE_RESET;
- }
- break;
- case STATE_RESET:
- if (!(cmd_fis[15] & ATA_SRST)) {
- ahci_reset_port(s, port);
- }
- break;
- }
- return;
- }
-
- /* Check for NCQ command */
- if (is_ncq(cmd_fis[2])) {
- process_ncq_command(s, port, cmd_fis, slot);
- return;
- }
-
- /* Decompose the FIS:
- * AHCI does not interpret FIS packets, it only forwards them.
- * SATA 1.0 describes how to decode LBA28 and CHS FIS packets.
- * Later specifications, e.g, SATA 3.2, describe LBA48 FIS packets.
- *
- * ATA4 describes sector number for LBA28/CHS commands.
- * ATA6 describes sector number for LBA48 commands.
- * ATA8 deprecates CHS fully, describing only LBA28/48.
- *
- * We dutifully convert the FIS into IDE registers, and allow the
- * core layer to interpret them as needed. */
- ide_state->feature = cmd_fis[3];
- ide_state->sector = cmd_fis[4]; /* LBA 7:0 */
- ide_state->lcyl = cmd_fis[5]; /* LBA 15:8 */
- ide_state->hcyl = cmd_fis[6]; /* LBA 23:16 */
- ide_state->select = cmd_fis[7]; /* LBA 27:24 (LBA28) */
- ide_state->hob_sector = cmd_fis[8]; /* LBA 31:24 */
- ide_state->hob_lcyl = cmd_fis[9]; /* LBA 39:32 */
- ide_state->hob_hcyl = cmd_fis[10]; /* LBA 47:40 */
- ide_state->hob_feature = cmd_fis[11];
- ide_state->nsector = (int64_t)((cmd_fis[13] << 8) | cmd_fis[12]);
- /* 14, 16, 17, 18, 19: Reserved (SATA 1.0) */
- /* 15: Only valid when UPDATE_COMMAND not set. */
-
- /* Copy the ACMD field (ATAPI packet, if any) from the AHCI command
- * table to ide_state->io_buffer */
- if (opts & AHCI_CMD_ATAPI) {
- memcpy(ide_state->io_buffer, &cmd_fis[AHCI_COMMAND_TABLE_ACMD], 0x10);
- debug_print_fis(ide_state->io_buffer, 0x10);
- s->dev[port].done_atapi_packet = false;
- /* XXX send PIO setup FIS */
- }
-
- ide_state->error = 0;
-
- /* Reset transferred byte counter */
- cmd->status = 0;
-
- /* We're ready to process the command in FIS byte 2. */
- ide_exec_cmd(&s->dev[port].port, cmd_fis[2]);
-}
-
-static int handle_cmd(AHCIState *s, int port, uint8_t slot)
-{
- IDEState *ide_state;
- uint64_t tbl_addr;
- AHCICmdHdr *cmd;
- uint8_t *cmd_fis;
- dma_addr_t cmd_len;
-
- if (s->dev[port].port.ifs[0].status & (BUSY_STAT|DRQ_STAT)) {
- /* Engine currently busy, try again later */
- DPRINTF(port, "engine busy\n");
- return -1;
- }
-
- if (!s->dev[port].lst) {
- DPRINTF(port, "error: lst not given but cmd handled");
- return -1;
- }
- cmd = get_cmd_header(s, port, slot);
- /* remember current slot handle for later */
- s->dev[port].cur_cmd = cmd;
-
- /* The device we are working for */
- ide_state = &s->dev[port].port.ifs[0];
- if (!ide_state->blk) {
- DPRINTF(port, "error: guest accessed unused port");
- return -1;
- }
-
- tbl_addr = le64_to_cpu(cmd->tbl_addr);
- cmd_len = 0x80;
- cmd_fis = dma_memory_map(s->as, tbl_addr, &cmd_len,
- DMA_DIRECTION_FROM_DEVICE);
- if (!cmd_fis) {
- DPRINTF(port, "error: guest passed us an invalid cmd fis\n");
- return -1;
- } else if (cmd_len != 0x80) {
- ahci_trigger_irq(s, &s->dev[port], PORT_IRQ_HBUS_ERR);
- DPRINTF(port, "error: dma_memory_map failed: "
- "(len(%02"PRIx64") != 0x80)\n",
- cmd_len);
- goto out;
- }
- debug_print_fis(cmd_fis, 0x80);
-
- switch (cmd_fis[0]) {
- case SATA_FIS_TYPE_REGISTER_H2D:
- handle_reg_h2d_fis(s, port, slot, cmd_fis);
- break;
- default:
- DPRINTF(port, "unknown command cmd_fis[0]=%02x cmd_fis[1]=%02x "
- "cmd_fis[2]=%02x\n", cmd_fis[0], cmd_fis[1],
- cmd_fis[2]);
- break;
- }
-
-out:
- dma_memory_unmap(s->as, cmd_fis, cmd_len, DMA_DIRECTION_FROM_DEVICE,
- cmd_len);
-
- if (s->dev[port].port.ifs[0].status & (BUSY_STAT|DRQ_STAT)) {
- /* async command, complete later */
- s->dev[port].busy_slot = slot;
- return -1;
- }
-
- /* done handling the command */
- return 0;
-}
-
-/* DMA dev <-> ram */
-static void ahci_start_transfer(IDEDMA *dma)
-{
- AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
- IDEState *s = &ad->port.ifs[0];
- uint32_t size = (uint32_t)(s->data_end - s->data_ptr);
- /* write == ram -> device */
- uint16_t opts = le16_to_cpu(ad->cur_cmd->opts);
- int is_write = opts & AHCI_CMD_WRITE;
- int is_atapi = opts & AHCI_CMD_ATAPI;
- int has_sglist = 0;
-
- if (is_atapi && !ad->done_atapi_packet) {
- /* already prepopulated iobuffer */
- ad->done_atapi_packet = true;
- size = 0;
- goto out;
- }
-
- if (ahci_dma_prepare_buf(dma, size)) {
- has_sglist = 1;
- }
-
- DPRINTF(ad->port_no, "%sing %d bytes on %s w/%s sglist\n",
- is_write ? "writ" : "read", size, is_atapi ? "atapi" : "ata",
- has_sglist ? "" : "o");
-
- if (has_sglist && size) {
- if (is_write) {
- dma_buf_write(s->data_ptr, size, &s->sg);
- } else {
- dma_buf_read(s->data_ptr, size, &s->sg);
- }
- }
-
-out:
- /* declare that we processed everything */
- s->data_ptr = s->data_end;
-
- /* Update number of transferred bytes, destroy sglist */
- dma_buf_commit(s, size);
-
- s->end_transfer_func(s);
-
- if (!(s->status & DRQ_STAT)) {
- /* done with PIO send/receive */
- ahci_write_fis_pio(ad, le32_to_cpu(ad->cur_cmd->status));
- }
-}
-
-static void ahci_start_dma(IDEDMA *dma, IDEState *s,
- BlockCompletionFunc *dma_cb)
-{
- AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
- DPRINTF(ad->port_no, "\n");
- s->io_buffer_offset = 0;
- dma_cb(s, 0);
-}
-
-static void ahci_restart_dma(IDEDMA *dma)
-{
- /* Nothing to do, ahci_start_dma already resets s->io_buffer_offset. */
-}
-
-/**
- * IDE/PIO restarts are handled by the core layer, but NCQ commands
- * need an extra kick from the AHCI HBA.
- */
-static void ahci_restart(IDEDMA *dma)
-{
- AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
- int i;
-
- for (i = 0; i < AHCI_MAX_CMDS; i++) {
- NCQTransferState *ncq_tfs = &ad->ncq_tfs[i];
- if (ncq_tfs->halt) {
- execute_ncq_command(ncq_tfs);
- }
- }
-}
-
-/**
- * Called in DMA and PIO R/W chains to read the PRDT.
- * Not shared with NCQ pathways.
- */
-static int32_t ahci_dma_prepare_buf(IDEDMA *dma, int32_t limit)
-{
- AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
- IDEState *s = &ad->port.ifs[0];
-
- if (ahci_populate_sglist(ad, &s->sg, ad->cur_cmd,
- limit, s->io_buffer_offset) == -1) {
- DPRINTF(ad->port_no, "ahci_dma_prepare_buf failed.\n");
- return -1;
- }
- s->io_buffer_size = s->sg.size;
-
- DPRINTF(ad->port_no, "len=%#x\n", s->io_buffer_size);
- return s->io_buffer_size;
-}
-
-/**
- * Updates the command header with a bytes-read value.
- * Called via dma_buf_commit, for both DMA and PIO paths.
- * sglist destruction is handled within dma_buf_commit.
- */
-static void ahci_commit_buf(IDEDMA *dma, uint32_t tx_bytes)
-{
- AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
-
- tx_bytes += le32_to_cpu(ad->cur_cmd->status);
- ad->cur_cmd->status = cpu_to_le32(tx_bytes);
-}
-
-static int ahci_dma_rw_buf(IDEDMA *dma, int is_write)
-{
- AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
- IDEState *s = &ad->port.ifs[0];
- uint8_t *p = s->io_buffer + s->io_buffer_index;
- int l = s->io_buffer_size - s->io_buffer_index;
-
- if (ahci_populate_sglist(ad, &s->sg, ad->cur_cmd, l, s->io_buffer_offset)) {
- return 0;
- }
-
- if (is_write) {
- dma_buf_read(p, l, &s->sg);
- } else {
- dma_buf_write(p, l, &s->sg);
- }
-
- /* free sglist, update byte count */
- dma_buf_commit(s, l);
-
- s->io_buffer_index += l;
-
- DPRINTF(ad->port_no, "len=%#x\n", l);
-
- return 1;
-}
-
-static void ahci_cmd_done(IDEDMA *dma)
-{
- AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
-
- DPRINTF(ad->port_no, "cmd done\n");
-
- /* update d2h status */
- ahci_write_fis_d2h(ad);
-
- if (!ad->check_bh) {
- /* maybe we still have something to process, check later */
- ad->check_bh = qemu_bh_new(ahci_check_cmd_bh, ad);
- qemu_bh_schedule(ad->check_bh);
- }
-}
-
-static void ahci_irq_set(void *opaque, int n, int level)
-{
-}
-
-static const IDEDMAOps ahci_dma_ops = {
- .start_dma = ahci_start_dma,
- .restart = ahci_restart,
- .restart_dma = ahci_restart_dma,
- .start_transfer = ahci_start_transfer,
- .prepare_buf = ahci_dma_prepare_buf,
- .commit_buf = ahci_commit_buf,
- .rw_buf = ahci_dma_rw_buf,
- .cmd_done = ahci_cmd_done,
-};
-
-void ahci_init(AHCIState *s, DeviceState *qdev)
-{
- s->container = qdev;
- /* XXX BAR size should be 1k, but that breaks, so bump it to 4k for now */
- memory_region_init_io(&s->mem, OBJECT(qdev), &ahci_mem_ops, s,
- "ahci", AHCI_MEM_BAR_SIZE);
- memory_region_init_io(&s->idp, OBJECT(qdev), &ahci_idp_ops, s,
- "ahci-idp", 32);
-}
-
-void ahci_realize(AHCIState *s, DeviceState *qdev, AddressSpace *as, int ports)
-{
- qemu_irq *irqs;
- int i;
-
- s->as = as;
- s->ports = ports;
- s->dev = g_new0(AHCIDevice, ports);
- ahci_reg_init(s);
- irqs = qemu_allocate_irqs(ahci_irq_set, s, s->ports);
- for (i = 0; i < s->ports; i++) {
- AHCIDevice *ad = &s->dev[i];
-
- ide_bus_new(&ad->port, sizeof(ad->port), qdev, i, 1);
- ide_init2(&ad->port, irqs[i]);
-
- ad->hba = s;
- ad->port_no = i;
- ad->port.dma = &ad->dma;
- ad->port.dma->ops = &ahci_dma_ops;
- ide_register_restart_cb(&ad->port);
- }
-}
-
-void ahci_uninit(AHCIState *s)
-{
- g_free(s->dev);
-}
-
-void ahci_reset(AHCIState *s)
-{
- AHCIPortRegs *pr;
- int i;
-
- s->control_regs.irqstatus = 0;
- /* AHCI Enable (AE)
- * The implementation of this bit is dependent upon the value of the
- * CAP.SAM bit. If CAP.SAM is '0', then GHC.AE shall be read-write and
- * shall have a reset value of '0'. If CAP.SAM is '1', then AE shall be
- * read-only and shall have a reset value of '1'.
- *
- * We set HOST_CAP_AHCI so we must enable AHCI at reset.
- */
- s->control_regs.ghc = HOST_CTL_AHCI_EN;
-
- for (i = 0; i < s->ports; i++) {
- pr = &s->dev[i].port_regs;
- pr->irq_stat = 0;
- pr->irq_mask = 0;
- pr->scr_ctl = 0;
- pr->cmd = PORT_CMD_SPIN_UP | PORT_CMD_POWER_ON;
- ahci_reset_port(s, i);
- }
-}
-
-static const VMStateDescription vmstate_ncq_tfs = {
- .name = "ncq state",
- .version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(sector_count, NCQTransferState),
- VMSTATE_UINT64(lba, NCQTransferState),
- VMSTATE_UINT8(tag, NCQTransferState),
- VMSTATE_UINT8(cmd, NCQTransferState),
- VMSTATE_UINT8(slot, NCQTransferState),
- VMSTATE_BOOL(used, NCQTransferState),
- VMSTATE_BOOL(halt, NCQTransferState),
- VMSTATE_END_OF_LIST()
- },
-};
-
-static const VMStateDescription vmstate_ahci_device = {
- .name = "ahci port",
- .version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_IDE_BUS(port, AHCIDevice),
- VMSTATE_IDE_DRIVE(port.ifs[0], 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_STRUCT_ARRAY(ncq_tfs, AHCIDevice, AHCI_MAX_CMDS,
- 1, vmstate_ncq_tfs, NCQTransferState),
- VMSTATE_END_OF_LIST()
- },
-};
-
-static int ahci_state_post_load(void *opaque, int version_id)
-{
- int i, j;
- struct AHCIDevice *ad;
- NCQTransferState *ncq_tfs;
- AHCIPortRegs *pr;
- AHCIState *s = opaque;
-
- for (i = 0; i < s->ports; i++) {
- ad = &s->dev[i];
- pr = &ad->port_regs;
-
- if (!(pr->cmd & PORT_CMD_START) && (pr->cmd & PORT_CMD_LIST_ON)) {
- error_report("AHCI: DMA engine should be off, but status bit "
- "indicates it is still running.");
- return -1;
- }
- if (!(pr->cmd & PORT_CMD_FIS_RX) && (pr->cmd & PORT_CMD_FIS_ON)) {
- error_report("AHCI: FIS RX engine should be off, but status bit "
- "indicates it is still running.");
- return -1;
- }
-
- /* After a migrate, the DMA/FIS engines are "off" and
- * need to be conditionally restarted */
- pr->cmd &= ~(PORT_CMD_LIST_ON | PORT_CMD_FIS_ON);
- if (ahci_cond_start_engines(ad) != 0) {
- return -1;
- }
-
- for (j = 0; j < AHCI_MAX_CMDS; j++) {
- ncq_tfs = &ad->ncq_tfs[j];
- ncq_tfs->drive = ad;
-
- if (ncq_tfs->used != ncq_tfs->halt) {
- return -1;
- }
- if (!ncq_tfs->halt) {
- continue;
- }
- if (!is_ncq(ncq_tfs->cmd)) {
- return -1;
- }
- if (ncq_tfs->slot != ncq_tfs->tag) {
- return -1;
- }
- /* If ncq_tfs->halt is justly set, the engine should be engaged,
- * and the command list buffer should be mapped. */
- ncq_tfs->cmdh = get_cmd_header(s, i, ncq_tfs->slot);
- if (!ncq_tfs->cmdh) {
- return -1;
- }
- ahci_populate_sglist(ncq_tfs->drive, &ncq_tfs->sglist,
- ncq_tfs->cmdh, ncq_tfs->sector_count * 512,
- 0);
- if (ncq_tfs->sector_count != ncq_tfs->sglist.size >> 9) {
- return -1;
- }
- }
-
-
- /*
- * If an error is present, ad->busy_slot will be valid and not -1.
- * In this case, an operation is waiting to resume and will re-check
- * for additional AHCI commands to execute upon completion.
- *
- * In the case where no error was present, busy_slot will be -1,
- * and we should check to see if there are additional commands waiting.
- */
- if (ad->busy_slot == -1) {
- check_cmd(s, i);
- } else {
- /* We are in the middle of a command, and may need to access
- * the command header in guest memory again. */
- if (ad->busy_slot < 0 || ad->busy_slot >= AHCI_MAX_CMDS) {
- return -1;
- }
- ad->cur_cmd = get_cmd_header(s, i, ad->busy_slot);
- }
- }
-
- 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_EQUAL(ports, AHCIState),
- VMSTATE_END_OF_LIST()
- },
-};
-
-static const VMStateDescription vmstate_sysbus_ahci = {
- .name = "sysbus-ahci",
- .fields = (VMStateField[]) {
- VMSTATE_AHCI(ahci, SysbusAHCIState),
- VMSTATE_END_OF_LIST()
- },
-};
-
-static void sysbus_ahci_reset(DeviceState *dev)
-{
- SysbusAHCIState *s = SYSBUS_AHCI(dev);
-
- ahci_reset(&s->ahci);
-}
-
-static void sysbus_ahci_init(Object *obj)
-{
- SysbusAHCIState *s = SYSBUS_AHCI(obj);
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
-
- ahci_init(&s->ahci, DEVICE(obj));
-
- sysbus_init_mmio(sbd, &s->ahci.mem);
- sysbus_init_irq(sbd, &s->ahci.irq);
-}
-
-static void sysbus_ahci_realize(DeviceState *dev, Error **errp)
-{
- SysbusAHCIState *s = SYSBUS_AHCI(dev);
-
- ahci_realize(&s->ahci, dev, &address_space_memory, s->num_ports);
-}
-
-static Property sysbus_ahci_properties[] = {
- DEFINE_PROP_UINT32("num-ports", SysbusAHCIState, num_ports, 1),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void sysbus_ahci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = sysbus_ahci_realize;
- dc->vmsd = &vmstate_sysbus_ahci;
- dc->props = sysbus_ahci_properties;
- dc->reset = sysbus_ahci_reset;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
-}
-
-static const TypeInfo sysbus_ahci_info = {
- .name = TYPE_SYSBUS_AHCI,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(SysbusAHCIState),
- .instance_init = sysbus_ahci_init,
- .class_init = sysbus_ahci_class_init,
-};
-
-#define ALLWINNER_AHCI_BISTAFR ((0xa0 - ALLWINNER_AHCI_MMIO_OFF) / 4)
-#define ALLWINNER_AHCI_BISTCR ((0xa4 - ALLWINNER_AHCI_MMIO_OFF) / 4)
-#define ALLWINNER_AHCI_BISTFCTR ((0xa8 - ALLWINNER_AHCI_MMIO_OFF) / 4)
-#define ALLWINNER_AHCI_BISTSR ((0xac - ALLWINNER_AHCI_MMIO_OFF) / 4)
-#define ALLWINNER_AHCI_BISTDECR ((0xb0 - ALLWINNER_AHCI_MMIO_OFF) / 4)
-#define ALLWINNER_AHCI_DIAGNR0 ((0xb4 - ALLWINNER_AHCI_MMIO_OFF) / 4)
-#define ALLWINNER_AHCI_DIAGNR1 ((0xb8 - ALLWINNER_AHCI_MMIO_OFF) / 4)
-#define ALLWINNER_AHCI_OOBR ((0xbc - ALLWINNER_AHCI_MMIO_OFF) / 4)
-#define ALLWINNER_AHCI_PHYCS0R ((0xc0 - ALLWINNER_AHCI_MMIO_OFF) / 4)
-#define ALLWINNER_AHCI_PHYCS1R ((0xc4 - ALLWINNER_AHCI_MMIO_OFF) / 4)
-#define ALLWINNER_AHCI_PHYCS2R ((0xc8 - ALLWINNER_AHCI_MMIO_OFF) / 4)
-#define ALLWINNER_AHCI_TIMER1MS ((0xe0 - ALLWINNER_AHCI_MMIO_OFF) / 4)
-#define ALLWINNER_AHCI_GPARAM1R ((0xe8 - ALLWINNER_AHCI_MMIO_OFF) / 4)
-#define ALLWINNER_AHCI_GPARAM2R ((0xec - ALLWINNER_AHCI_MMIO_OFF) / 4)
-#define ALLWINNER_AHCI_PPARAMR ((0xf0 - ALLWINNER_AHCI_MMIO_OFF) / 4)
-#define ALLWINNER_AHCI_TESTR ((0xf4 - ALLWINNER_AHCI_MMIO_OFF) / 4)
-#define ALLWINNER_AHCI_VERSIONR ((0xf8 - ALLWINNER_AHCI_MMIO_OFF) / 4)
-#define ALLWINNER_AHCI_IDR ((0xfc - ALLWINNER_AHCI_MMIO_OFF) / 4)
-#define ALLWINNER_AHCI_RWCR ((0xfc - ALLWINNER_AHCI_MMIO_OFF) / 4)
-
-static uint64_t allwinner_ahci_mem_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- AllwinnerAHCIState *a = opaque;
- uint64_t val = a->regs[addr/4];
-
- switch (addr / 4) {
- case ALLWINNER_AHCI_PHYCS0R:
- val |= 0x2 << 28;
- break;
- case ALLWINNER_AHCI_PHYCS2R:
- val &= ~(0x1 << 24);
- break;
- }
- DPRINTF(-1, "addr=0x%" HWADDR_PRIx " val=0x%" PRIx64 ", size=%d\n",
- addr, val, size);
- return val;
-}
-
-static void allwinner_ahci_mem_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- AllwinnerAHCIState *a = opaque;
-
- DPRINTF(-1, "addr=0x%" HWADDR_PRIx " val=0x%" PRIx64 ", size=%d\n",
- addr, val, size);
- a->regs[addr/4] = val;
-}
-
-static const MemoryRegionOps allwinner_ahci_mem_ops = {
- .read = allwinner_ahci_mem_read,
- .write = allwinner_ahci_mem_write,
- .valid.min_access_size = 4,
- .valid.max_access_size = 4,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void allwinner_ahci_init(Object *obj)
-{
- SysbusAHCIState *s = SYSBUS_AHCI(obj);
- AllwinnerAHCIState *a = ALLWINNER_AHCI(obj);
-
- memory_region_init_io(&a->mmio, OBJECT(obj), &allwinner_ahci_mem_ops, a,
- "allwinner-ahci", ALLWINNER_AHCI_MMIO_SIZE);
- memory_region_add_subregion(&s->ahci.mem, ALLWINNER_AHCI_MMIO_OFF,
- &a->mmio);
-}
-
-static const VMStateDescription vmstate_allwinner_ahci = {
- .name = "allwinner-ahci",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, AllwinnerAHCIState,
- ALLWINNER_AHCI_MMIO_SIZE/4),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void allwinner_ahci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->vmsd = &vmstate_allwinner_ahci;
-}
-
-static const TypeInfo allwinner_ahci_info = {
- .name = TYPE_ALLWINNER_AHCI,
- .parent = TYPE_SYSBUS_AHCI,
- .instance_size = sizeof(AllwinnerAHCIState),
- .instance_init = allwinner_ahci_init,
- .class_init = allwinner_ahci_class_init,
-};
-
-static void sysbus_ahci_register_types(void)
-{
- type_register_static(&sysbus_ahci_info);
- type_register_static(&allwinner_ahci_info);
-}
-
-type_init(sysbus_ahci_register_types)
-
-void ahci_ide_create_devs(PCIDevice *dev, DriveInfo **hd)
-{
- AHCIPCIState *d = ICH_AHCI(dev);
- AHCIState *ahci = &d->ahci;
- int i;
-
- for (i = 0; i < ahci->ports; i++) {
- if (hd[i] == NULL) {
- continue;
- }
- ide_create_drive(&ahci->dev[i].port, 0, hd[i]);
- }
-
-}
diff --git a/qemu/hw/ide/ahci.h b/qemu/hw/ide/ahci.h
deleted file mode 100644
index bc777ed5c..000000000
--- a/qemu/hw/ide/ahci.h
+++ /dev/null
@@ -1,405 +0,0 @@
-/*
- * QEMU AHCI Emulation
- *
- * Copyright (c) 2010 qiaochong@loongson.cn
- * Copyright (c) 2010 Roland Elek <elek.roland@gmail.com>
- * Copyright (c) 2010 Sebastian Herbszt <herbszt@gmx.de>
- * Copyright (c) 2010 Alexander Graf <agraf@suse.de>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef HW_IDE_AHCI_H
-#define HW_IDE_AHCI_H
-
-#include <hw/sysbus.h>
-
-#define AHCI_MEM_BAR_SIZE 0x1000
-#define AHCI_MAX_PORTS 32
-#define AHCI_MAX_SG 168 /* hardware max is 64K */
-#define AHCI_DMA_BOUNDARY 0xffffffff
-#define AHCI_USE_CLUSTERING 0
-#define AHCI_MAX_CMDS 32
-#define AHCI_CMD_SZ 32
-#define AHCI_CMD_SLOT_SZ (AHCI_MAX_CMDS * AHCI_CMD_SZ)
-#define AHCI_RX_FIS_SZ 256
-#define AHCI_CMD_TBL_CDB 0x40
-#define AHCI_CMD_TBL_HDR_SZ 0x80
-#define AHCI_CMD_TBL_SZ (AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16))
-#define AHCI_CMD_TBL_AR_SZ (AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS)
-#define AHCI_PORT_PRIV_DMA_SZ (AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ + \
- AHCI_RX_FIS_SZ)
-
-#define AHCI_IRQ_ON_SG (1U << 31)
-#define AHCI_CMD_ATAPI (1 << 5)
-#define AHCI_CMD_WRITE (1 << 6)
-#define AHCI_CMD_PREFETCH (1 << 7)
-#define AHCI_CMD_RESET (1 << 8)
-#define AHCI_CMD_CLR_BUSY (1 << 10)
-
-#define RX_FIS_D2H_REG 0x40 /* offset of D2H Register FIS data */
-#define RX_FIS_SDB 0x58 /* offset of SDB FIS data */
-#define RX_FIS_UNK 0x60 /* offset of Unknown FIS data */
-
-/* global controller registers */
-#define HOST_CAP 0x00 /* host capabilities */
-#define HOST_CTL 0x04 /* global host control */
-#define HOST_IRQ_STAT 0x08 /* interrupt status */
-#define HOST_PORTS_IMPL 0x0c /* bitmap of implemented ports */
-#define HOST_VERSION 0x10 /* AHCI spec. version compliancy */
-
-/* HOST_CTL bits */
-#define HOST_CTL_RESET (1 << 0) /* reset controller; self-clear */
-#define HOST_CTL_IRQ_EN (1 << 1) /* global IRQ enable */
-#define HOST_CTL_AHCI_EN (1U << 31) /* AHCI enabled */
-
-/* HOST_CAP bits */
-#define HOST_CAP_SSC (1 << 14) /* Slumber capable */
-#define HOST_CAP_AHCI (1 << 18) /* AHCI only */
-#define HOST_CAP_CLO (1 << 24) /* Command List Override support */
-#define HOST_CAP_SSS (1 << 27) /* Staggered Spin-up */
-#define HOST_CAP_NCQ (1 << 30) /* Native Command Queueing */
-#define HOST_CAP_64 (1U << 31) /* PCI DAC (64-bit DMA) support */
-
-/* registers for each SATA port */
-#define PORT_LST_ADDR 0x00 /* command list DMA addr */
-#define PORT_LST_ADDR_HI 0x04 /* command list DMA addr hi */
-#define PORT_FIS_ADDR 0x08 /* FIS rx buf addr */
-#define PORT_FIS_ADDR_HI 0x0c /* FIS rx buf addr hi */
-#define PORT_IRQ_STAT 0x10 /* interrupt status */
-#define PORT_IRQ_MASK 0x14 /* interrupt enable/disable mask */
-#define PORT_CMD 0x18 /* port command */
-#define PORT_TFDATA 0x20 /* taskfile data */
-#define PORT_SIG 0x24 /* device TF signature */
-#define PORT_SCR_STAT 0x28 /* SATA phy register: SStatus */
-#define PORT_SCR_CTL 0x2c /* SATA phy register: SControl */
-#define PORT_SCR_ERR 0x30 /* SATA phy register: SError */
-#define PORT_SCR_ACT 0x34 /* SATA phy register: SActive */
-#define PORT_CMD_ISSUE 0x38 /* command issue */
-#define PORT_RESERVED 0x3c /* reserved */
-
-/* PORT_IRQ_{STAT,MASK} bits */
-#define PORT_IRQ_COLD_PRES (1U << 31) /* cold presence detect */
-#define PORT_IRQ_TF_ERR (1 << 30) /* task file error */
-#define PORT_IRQ_HBUS_ERR (1 << 29) /* host bus fatal error */
-#define PORT_IRQ_HBUS_DATA_ERR (1 << 28) /* host bus data error */
-#define PORT_IRQ_IF_ERR (1 << 27) /* interface fatal error */
-#define PORT_IRQ_IF_NONFATAL (1 << 26) /* interface non-fatal error */
-#define PORT_IRQ_OVERFLOW (1 << 24) /* xfer exhausted available S/G */
-#define PORT_IRQ_BAD_PMP (1 << 23) /* incorrect port multiplier */
-
-#define PORT_IRQ_PHYRDY (1 << 22) /* PhyRdy changed */
-#define PORT_IRQ_DEV_ILCK (1 << 7) /* device interlock */
-#define PORT_IRQ_CONNECT (1 << 6) /* port connect change status */
-#define PORT_IRQ_SG_DONE (1 << 5) /* descriptor processed */
-#define PORT_IRQ_UNK_FIS (1 << 4) /* unknown FIS rx'd */
-#define PORT_IRQ_SDB_FIS (1 << 3) /* Set Device Bits FIS rx'd */
-#define PORT_IRQ_DMAS_FIS (1 << 2) /* DMA Setup FIS rx'd */
-#define PORT_IRQ_PIOS_FIS (1 << 1) /* PIO Setup FIS rx'd */
-#define PORT_IRQ_D2H_REG_FIS (1 << 0) /* D2H Register FIS rx'd */
-
-#define PORT_IRQ_FREEZE (PORT_IRQ_HBUS_ERR | PORT_IRQ_IF_ERR | \
- PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY | \
- PORT_IRQ_UNK_FIS)
-#define PORT_IRQ_ERROR (PORT_IRQ_FREEZE | PORT_IRQ_TF_ERR | \
- PORT_IRQ_HBUS_DATA_ERR)
-#define DEF_PORT_IRQ (PORT_IRQ_ERROR | PORT_IRQ_SG_DONE | \
- PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS | \
- PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS)
-
-/* PORT_CMD bits */
-#define PORT_CMD_ATAPI (1 << 24) /* Device is ATAPI */
-#define PORT_CMD_LIST_ON (1 << 15) /* cmd list DMA engine running */
-#define PORT_CMD_FIS_ON (1 << 14) /* FIS DMA engine running */
-#define PORT_CMD_FIS_RX (1 << 4) /* Enable FIS receive DMA engine */
-#define PORT_CMD_CLO (1 << 3) /* Command list override */
-#define PORT_CMD_POWER_ON (1 << 2) /* Power up device */
-#define PORT_CMD_SPIN_UP (1 << 1) /* Spin up device */
-#define PORT_CMD_START (1 << 0) /* Enable port DMA engine */
-
-#define PORT_CMD_ICC_MASK (0xfU << 28) /* i/f ICC state mask */
-#define PORT_CMD_ICC_ACTIVE (0x1 << 28) /* Put i/f in active state */
-#define PORT_CMD_ICC_PARTIAL (0x2 << 28) /* Put i/f in partial state */
-#define PORT_CMD_ICC_SLUMBER (0x6 << 28) /* Put i/f in slumber state */
-
-#define PORT_CMD_RO_MASK 0x007dffe0 /* Which CMD bits are read only? */
-
-/* ap->flags bits */
-#define AHCI_FLAG_NO_NCQ (1 << 24)
-#define AHCI_FLAG_IGN_IRQ_IF_ERR (1 << 25) /* ignore IRQ_IF_ERR */
-#define AHCI_FLAG_HONOR_PI (1 << 26) /* honor PORTS_IMPL */
-#define AHCI_FLAG_IGN_SERR_INTERNAL (1 << 27) /* ignore SERR_INTERNAL */
-#define AHCI_FLAG_32BIT_ONLY (1 << 28) /* force 32bit */
-
-#define ATA_SRST (1 << 2) /* software reset */
-
-#define STATE_RUN 0
-#define STATE_RESET 1
-
-#define SATA_SCR_SSTATUS_DET_NODEV 0x0
-#define SATA_SCR_SSTATUS_DET_DEV_PRESENT_PHY_UP 0x3
-
-#define SATA_SCR_SSTATUS_SPD_NODEV 0x00
-#define SATA_SCR_SSTATUS_SPD_GEN1 0x10
-
-#define SATA_SCR_SSTATUS_IPM_NODEV 0x000
-#define SATA_SCR_SSTATUS_IPM_ACTIVE 0X100
-
-#define AHCI_SCR_SCTL_DET 0xf
-
-#define SATA_FIS_TYPE_REGISTER_H2D 0x27
-#define SATA_FIS_REG_H2D_UPDATE_COMMAND_REGISTER 0x80
-#define SATA_FIS_TYPE_REGISTER_D2H 0x34
-#define SATA_FIS_TYPE_PIO_SETUP 0x5f
-#define SATA_FIS_TYPE_SDB 0xA1
-
-#define AHCI_CMD_HDR_CMD_FIS_LEN 0x1f
-#define AHCI_CMD_HDR_PRDT_LEN 16
-
-#define SATA_SIGNATURE_CDROM 0xeb140101
-#define SATA_SIGNATURE_DISK 0x00000101
-
-#define AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR 0x20
- /* Shouldn't this be 0x2c? */
-
-#define AHCI_PORT_REGS_START_ADDR 0x100
-#define AHCI_PORT_ADDR_OFFSET_MASK 0x7f
-#define AHCI_PORT_ADDR_OFFSET_LEN 0x80
-
-#define AHCI_NUM_COMMAND_SLOTS 31
-#define AHCI_SUPPORTED_SPEED 20
-#define AHCI_SUPPORTED_SPEED_GEN1 1
-#define AHCI_VERSION_1_0 0x10000
-
-#define AHCI_PROGMODE_MAJOR_REV_1 1
-
-#define AHCI_COMMAND_TABLE_ACMD 0x40
-
-#define AHCI_PRDT_SIZE_MASK 0x3fffff
-
-#define IDE_FEATURE_DMA 1
-
-#define READ_FPDMA_QUEUED 0x60
-#define WRITE_FPDMA_QUEUED 0x61
-#define NCQ_NON_DATA 0x63
-#define RECEIVE_FPDMA_QUEUED 0x65
-#define SEND_FPDMA_QUEUED 0x64
-
-#define NCQ_FIS_FUA_MASK 0x80
-#define NCQ_FIS_RARC_MASK 0x01
-
-#define RES_FIS_DSFIS 0x00
-#define RES_FIS_PSFIS 0x20
-#define RES_FIS_RFIS 0x40
-#define RES_FIS_SDBFIS 0x58
-#define RES_FIS_UFIS 0x60
-
-#define SATA_CAP_SIZE 0x8
-#define SATA_CAP_REV 0x2
-#define SATA_CAP_BAR 0x4
-
-typedef struct AHCIControlRegs {
- uint32_t cap;
- uint32_t ghc;
- uint32_t irqstatus;
- uint32_t impl;
- uint32_t version;
-} AHCIControlRegs;
-
-typedef struct AHCIPortRegs {
- uint32_t lst_addr;
- uint32_t lst_addr_hi;
- uint32_t fis_addr;
- uint32_t fis_addr_hi;
- uint32_t irq_stat;
- uint32_t irq_mask;
- uint32_t cmd;
- uint32_t unused0;
- uint32_t tfdata;
- uint32_t sig;
- uint32_t scr_stat;
- uint32_t scr_ctl;
- uint32_t scr_err;
- uint32_t scr_act;
- uint32_t cmd_issue;
- uint32_t reserved;
-} AHCIPortRegs;
-
-typedef struct AHCICmdHdr {
- uint16_t opts;
- uint16_t prdtl;
- uint32_t status;
- uint64_t tbl_addr;
- uint32_t reserved[4];
-} QEMU_PACKED AHCICmdHdr;
-
-typedef struct AHCI_SG {
- uint64_t addr;
- uint32_t reserved;
- uint32_t flags_size;
-} QEMU_PACKED AHCI_SG;
-
-typedef struct AHCIDevice AHCIDevice;
-
-typedef struct NCQTransferState {
- AHCIDevice *drive;
- BlockAIOCB *aiocb;
- AHCICmdHdr *cmdh;
- QEMUSGList sglist;
- BlockAcctCookie acct;
- uint32_t sector_count;
- uint64_t lba;
- uint8_t tag;
- uint8_t cmd;
- uint8_t slot;
- bool used;
- bool halt;
-} NCQTransferState;
-
-struct AHCIDevice {
- IDEDMA dma;
- IDEBus port;
- int port_no;
- uint32_t port_state;
- uint32_t finished;
- AHCIPortRegs port_regs;
- struct AHCIState *hba;
- QEMUBH *check_bh;
- uint8_t *lst;
- uint8_t *res_fis;
- bool done_atapi_packet;
- int32_t busy_slot;
- bool init_d2h_sent;
- AHCICmdHdr *cur_cmd;
- NCQTransferState ncq_tfs[AHCI_MAX_CMDS];
-};
-
-typedef struct AHCIState {
- DeviceState *container;
-
- AHCIDevice *dev;
- AHCIControlRegs control_regs;
- MemoryRegion mem;
- 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 */
- int32_t ports;
- qemu_irq irq;
- AddressSpace *as;
-} AHCIState;
-
-typedef struct AHCIPCIState {
- /*< private >*/
- PCIDevice parent_obj;
- /*< public >*/
-
- AHCIState ahci;
-} AHCIPCIState;
-
-#define TYPE_ICH9_AHCI "ich9-ahci"
-
-#define ICH_AHCI(obj) \
- OBJECT_CHECK(AHCIPCIState, (obj), TYPE_ICH9_AHCI)
-
-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), \
-}
-
-/**
- * NCQFrame is the same as a Register H2D FIS (described in SATA 3.2),
- * but some fields have been re-mapped and re-purposed, as seen in
- * SATA 3.2 section 13.6.4.1 ("READ FPDMA QUEUED")
- *
- * cmd_fis[3], feature 7:0, becomes sector count 7:0.
- * cmd_fis[7], device 7:0, uses bit 7 as the Force Unit Access bit.
- * cmd_fis[11], feature 15:8, becomes sector count 15:8.
- * cmd_fis[12], count 7:0, becomes the NCQ TAG (7:3) and RARC bit (0)
- * cmd_fis[13], count 15:8, becomes the priority value (7:6)
- * bytes 16-19 become an le32 "auxiliary" field.
- */
-typedef struct NCQFrame {
- uint8_t fis_type;
- uint8_t c;
- uint8_t command;
- uint8_t sector_count_low; /* (feature 7:0) */
- uint8_t lba0;
- uint8_t lba1;
- uint8_t lba2;
- uint8_t fua; /* (device 7:0) */
- uint8_t lba3;
- uint8_t lba4;
- uint8_t lba5;
- uint8_t sector_count_high; /* (feature 15:8) */
- uint8_t tag; /* (count 0:7) */
- uint8_t prio; /* (count 15:8) */
- uint8_t icc;
- uint8_t control;
- uint8_t aux0;
- uint8_t aux1;
- uint8_t aux2;
- uint8_t aux3;
-} QEMU_PACKED NCQFrame;
-
-typedef struct SDBFIS {
- uint8_t type;
- uint8_t flags;
- uint8_t status;
- uint8_t error;
- uint32_t payload;
-} QEMU_PACKED SDBFIS;
-
-void ahci_realize(AHCIState *s, DeviceState *qdev, AddressSpace *as, int ports);
-void ahci_init(AHCIState *s, DeviceState *qdev);
-void ahci_uninit(AHCIState *s);
-
-void ahci_reset(AHCIState *s);
-
-void ahci_ide_create_devs(PCIDevice *dev, DriveInfo **hd);
-
-#define TYPE_SYSBUS_AHCI "sysbus-ahci"
-#define SYSBUS_AHCI(obj) OBJECT_CHECK(SysbusAHCIState, (obj), TYPE_SYSBUS_AHCI)
-
-typedef struct SysbusAHCIState {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- AHCIState ahci;
- uint32_t num_ports;
-} SysbusAHCIState;
-
-#define TYPE_ALLWINNER_AHCI "allwinner-ahci"
-#define ALLWINNER_AHCI(obj) OBJECT_CHECK(AllwinnerAHCIState, (obj), \
- TYPE_ALLWINNER_AHCI)
-
-#define ALLWINNER_AHCI_MMIO_OFF 0x80
-#define ALLWINNER_AHCI_MMIO_SIZE 0x80
-
-struct AllwinnerAHCIState {
- /*< private >*/
- SysbusAHCIState parent_obj;
- /*< public >*/
-
- MemoryRegion mmio;
- uint32_t regs[ALLWINNER_AHCI_MMIO_SIZE/4];
-};
-
-#endif /* HW_IDE_AHCI_H */
diff --git a/qemu/hw/ide/atapi.c b/qemu/hw/ide/atapi.c
deleted file mode 100644
index 2bb606c1c..000000000
--- a/qemu/hw/ide/atapi.c
+++ /dev/null
@@ -1,1367 +0,0 @@
-/*
- * QEMU ATAPI Emulation
- *
- * Copyright (c) 2003 Fabrice Bellard
- * Copyright (c) 2006 Openedhand Ltd.
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/ide/internal.h"
-#include "hw/scsi/scsi.h"
-#include "sysemu/block-backend.h"
-
-static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret);
-
-static void padstr8(uint8_t *buf, int buf_size, const char *src)
-{
- int i;
- for(i = 0; i < buf_size; i++) {
- if (*src)
- buf[i] = *src++;
- else
- buf[i] = ' ';
- }
-}
-
-static inline void cpu_to_ube16(uint8_t *buf, int val)
-{
- buf[0] = val >> 8;
- buf[1] = val & 0xff;
-}
-
-static inline void cpu_to_ube32(uint8_t *buf, unsigned int val)
-{
- buf[0] = val >> 24;
- buf[1] = val >> 16;
- buf[2] = val >> 8;
- buf[3] = val & 0xff;
-}
-
-static inline int ube16_to_cpu(const uint8_t *buf)
-{
- return (buf[0] << 8) | buf[1];
-}
-
-static inline int ube32_to_cpu(const uint8_t *buf)
-{
- return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
-}
-
-static void lba_to_msf(uint8_t *buf, int lba)
-{
- lba += 150;
- buf[0] = (lba / 75) / 60;
- buf[1] = (lba / 75) % 60;
- buf[2] = lba % 75;
-}
-
-static inline int media_present(IDEState *s)
-{
- return !s->tray_open && s->nb_sectors > 0;
-}
-
-/* XXX: DVDs that could fit on a CD will be reported as a CD */
-static inline int media_is_dvd(IDEState *s)
-{
- return (media_present(s) && s->nb_sectors > CD_MAX_SECTORS);
-}
-
-static inline int media_is_cd(IDEState *s)
-{
- return (media_present(s) && s->nb_sectors <= CD_MAX_SECTORS);
-}
-
-static void cd_data_to_raw(uint8_t *buf, int lba)
-{
- /* sync bytes */
- buf[0] = 0x00;
- memset(buf + 1, 0xff, 10);
- buf[11] = 0x00;
- buf += 12;
- /* MSF */
- lba_to_msf(buf, lba);
- buf[3] = 0x01; /* mode 1 data */
- buf += 4;
- /* data */
- buf += 2048;
- /* XXX: ECC not computed */
- memset(buf, 0, 288);
-}
-
-static int
-cd_read_sector_sync(IDEState *s)
-{
- int ret;
- block_acct_start(blk_get_stats(s->blk), &s->acct,
- 4 * BDRV_SECTOR_SIZE, BLOCK_ACCT_READ);
-
-#ifdef DEBUG_IDE_ATAPI
- printf("cd_read_sector_sync: lba=%d\n", s->lba);
-#endif
-
- switch (s->cd_sector_size) {
- case 2048:
- ret = blk_read(s->blk, (int64_t)s->lba << 2,
- s->io_buffer, 4);
- break;
- case 2352:
- ret = blk_read(s->blk, (int64_t)s->lba << 2,
- s->io_buffer + 16, 4);
- if (ret >= 0) {
- cd_data_to_raw(s->io_buffer, s->lba);
- }
- break;
- default:
- block_acct_invalid(blk_get_stats(s->blk), BLOCK_ACCT_READ);
- return -EIO;
- }
-
- if (ret < 0) {
- block_acct_failed(blk_get_stats(s->blk), &s->acct);
- } else {
- block_acct_done(blk_get_stats(s->blk), &s->acct);
- s->lba++;
- s->io_buffer_index = 0;
- }
-
- return ret;
-}
-
-static void cd_read_sector_cb(void *opaque, int ret)
-{
- IDEState *s = opaque;
-
-#ifdef DEBUG_IDE_ATAPI
- printf("cd_read_sector_cb: lba=%d ret=%d\n", s->lba, ret);
-#endif
-
- if (ret < 0) {
- block_acct_failed(blk_get_stats(s->blk), &s->acct);
- ide_atapi_io_error(s, ret);
- return;
- }
-
- block_acct_done(blk_get_stats(s->blk), &s->acct);
-
- if (s->cd_sector_size == 2352) {
- cd_data_to_raw(s->io_buffer, s->lba);
- }
-
- s->lba++;
- s->io_buffer_index = 0;
- s->status &= ~BUSY_STAT;
-
- ide_atapi_cmd_reply_end(s);
-}
-
-static int cd_read_sector(IDEState *s)
-{
- if (s->cd_sector_size != 2048 && s->cd_sector_size != 2352) {
- block_acct_invalid(blk_get_stats(s->blk), BLOCK_ACCT_READ);
- return -EINVAL;
- }
-
- s->iov.iov_base = (s->cd_sector_size == 2352) ?
- s->io_buffer + 16 : s->io_buffer;
-
- s->iov.iov_len = 4 * BDRV_SECTOR_SIZE;
- qemu_iovec_init_external(&s->qiov, &s->iov, 1);
-
-#ifdef DEBUG_IDE_ATAPI
- printf("cd_read_sector: lba=%d\n", s->lba);
-#endif
-
- block_acct_start(blk_get_stats(s->blk), &s->acct,
- 4 * BDRV_SECTOR_SIZE, BLOCK_ACCT_READ);
-
- ide_buffered_readv(s, (int64_t)s->lba << 2, &s->qiov, 4,
- cd_read_sector_cb, s);
-
- s->status |= BUSY_STAT;
- return 0;
-}
-
-void ide_atapi_cmd_ok(IDEState *s)
-{
- s->error = 0;
- s->status = READY_STAT | SEEK_STAT;
- s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
- ide_transfer_stop(s);
- ide_set_irq(s->bus);
-}
-
-void ide_atapi_cmd_error(IDEState *s, int sense_key, int asc)
-{
-#ifdef DEBUG_IDE_ATAPI
- printf("atapi_cmd_error: sense=0x%x asc=0x%x\n", sense_key, asc);
-#endif
- s->error = sense_key << 4;
- s->status = READY_STAT | ERR_STAT;
- s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
- s->sense_key = sense_key;
- s->asc = asc;
- ide_transfer_stop(s);
- ide_set_irq(s->bus);
-}
-
-void ide_atapi_io_error(IDEState *s, int ret)
-{
- /* XXX: handle more errors */
- if (ret == -ENOMEDIUM) {
- ide_atapi_cmd_error(s, NOT_READY,
- ASC_MEDIUM_NOT_PRESENT);
- } else {
- ide_atapi_cmd_error(s, ILLEGAL_REQUEST,
- ASC_LOGICAL_BLOCK_OOR);
- }
-}
-
-static uint16_t atapi_byte_count_limit(IDEState *s)
-{
- uint16_t bcl;
-
- bcl = s->lcyl | (s->hcyl << 8);
- if (bcl == 0xffff) {
- return 0xfffe;
- }
- return bcl;
-}
-
-/* The whole ATAPI transfer logic is handled in this function */
-void ide_atapi_cmd_reply_end(IDEState *s)
-{
- int byte_count_limit, size, ret;
-#ifdef DEBUG_IDE_ATAPI
- printf("reply: tx_size=%d elem_tx_size=%d index=%d\n",
- s->packet_transfer_size,
- s->elementary_transfer_size,
- s->io_buffer_index);
-#endif
- if (s->packet_transfer_size <= 0) {
- /* end of transfer */
- ide_atapi_cmd_ok(s);
- ide_set_irq(s->bus);
-#ifdef DEBUG_IDE_ATAPI
- printf("end of transfer, status=0x%x\n", s->status);
-#endif
- } else {
- /* see if a new sector must be read */
- if (s->lba != -1 && s->io_buffer_index >= s->cd_sector_size) {
- if (!s->elementary_transfer_size) {
- ret = cd_read_sector(s);
- if (ret < 0) {
- ide_atapi_io_error(s, ret);
- }
- return;
- } else {
- /* rebuffering within an elementary transfer is
- * only possible with a sync request because we
- * end up with a race condition otherwise */
- ret = cd_read_sector_sync(s);
- if (ret < 0) {
- ide_atapi_io_error(s, ret);
- return;
- }
- }
- }
- if (s->elementary_transfer_size > 0) {
- /* there are some data left to transmit in this elementary
- transfer */
- size = s->cd_sector_size - s->io_buffer_index;
- if (size > s->elementary_transfer_size)
- size = s->elementary_transfer_size;
- s->packet_transfer_size -= size;
- s->elementary_transfer_size -= size;
- s->io_buffer_index += size;
- ide_transfer_start(s, s->io_buffer + s->io_buffer_index - size,
- size, ide_atapi_cmd_reply_end);
- } else {
- /* a new transfer is needed */
- s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO;
- byte_count_limit = atapi_byte_count_limit(s);
-#ifdef DEBUG_IDE_ATAPI
- printf("byte_count_limit=%d\n", byte_count_limit);
-#endif
- size = s->packet_transfer_size;
- if (size > byte_count_limit) {
- /* byte count limit must be even if this case */
- if (byte_count_limit & 1)
- byte_count_limit--;
- size = byte_count_limit;
- }
- s->lcyl = size;
- s->hcyl = size >> 8;
- s->elementary_transfer_size = size;
- /* we cannot transmit more than one sector at a time */
- if (s->lba != -1) {
- if (size > (s->cd_sector_size - s->io_buffer_index))
- size = (s->cd_sector_size - s->io_buffer_index);
- }
- s->packet_transfer_size -= size;
- s->elementary_transfer_size -= size;
- s->io_buffer_index += size;
- ide_transfer_start(s, s->io_buffer + s->io_buffer_index - size,
- size, ide_atapi_cmd_reply_end);
- ide_set_irq(s->bus);
-#ifdef DEBUG_IDE_ATAPI
- printf("status=0x%x\n", s->status);
-#endif
- }
- }
-}
-
-/* send a reply of 'size' bytes in s->io_buffer to an ATAPI command */
-static void ide_atapi_cmd_reply(IDEState *s, int size, int max_size)
-{
- if (size > max_size)
- size = max_size;
- s->lba = -1; /* no sector read */
- s->packet_transfer_size = size;
- s->io_buffer_size = size; /* dma: send the reply data as one chunk */
- s->elementary_transfer_size = 0;
-
- if (s->atapi_dma) {
- block_acct_start(blk_get_stats(s->blk), &s->acct, size,
- BLOCK_ACCT_READ);
- s->status = READY_STAT | SEEK_STAT | DRQ_STAT;
- ide_start_dma(s, ide_atapi_cmd_read_dma_cb);
- } else {
- s->status = READY_STAT | SEEK_STAT;
- s->io_buffer_index = 0;
- ide_atapi_cmd_reply_end(s);
- }
-}
-
-/* start a CD-CDROM read command */
-static void ide_atapi_cmd_read_pio(IDEState *s, int lba, int nb_sectors,
- int sector_size)
-{
- s->lba = lba;
- s->packet_transfer_size = nb_sectors * sector_size;
- s->elementary_transfer_size = 0;
- s->io_buffer_index = sector_size;
- s->cd_sector_size = sector_size;
-
- ide_atapi_cmd_reply_end(s);
-}
-
-static void ide_atapi_cmd_check_status(IDEState *s)
-{
-#ifdef DEBUG_IDE_ATAPI
- printf("atapi_cmd_check_status\n");
-#endif
- s->error = MC_ERR | (UNIT_ATTENTION << 4);
- s->status = ERR_STAT;
- s->nsector = 0;
- ide_set_irq(s->bus);
-}
-/* ATAPI DMA support */
-
-static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret)
-{
- IDEState *s = opaque;
- int data_offset, n;
-
- if (ret < 0) {
- if (ide_handle_rw_error(s, -ret, ide_dma_cmd_to_retry(s->dma_cmd))) {
- if (s->bus->error_status) {
- return;
- }
- goto eot;
- }
- }
-
- if (s->io_buffer_size > 0) {
- /*
- * For a cdrom read sector command (s->lba != -1),
- * adjust the lba for the next s->io_buffer_size chunk
- * and dma the current chunk.
- * For a command != read (s->lba == -1), just transfer
- * the reply data.
- */
- if (s->lba != -1) {
- if (s->cd_sector_size == 2352) {
- n = 1;
- cd_data_to_raw(s->io_buffer, s->lba);
- } else {
- n = s->io_buffer_size >> 11;
- }
- s->lba += n;
- }
- s->packet_transfer_size -= s->io_buffer_size;
- if (s->bus->dma->ops->rw_buf(s->bus->dma, 1) == 0)
- goto eot;
- }
-
- if (s->packet_transfer_size <= 0) {
- s->status = READY_STAT | SEEK_STAT;
- s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
- ide_set_irq(s->bus);
- goto eot;
- }
-
- s->io_buffer_index = 0;
- if (s->cd_sector_size == 2352) {
- n = 1;
- s->io_buffer_size = s->cd_sector_size;
- data_offset = 16;
- } else {
- n = s->packet_transfer_size >> 11;
- if (n > (IDE_DMA_BUF_SECTORS / 4))
- n = (IDE_DMA_BUF_SECTORS / 4);
- s->io_buffer_size = n * 2048;
- data_offset = 0;
- }
-#ifdef DEBUG_AIO
- printf("aio_read_cd: lba=%u n=%d\n", s->lba, n);
-#endif
-
- s->bus->dma->iov.iov_base = (void *)(s->io_buffer + data_offset);
- s->bus->dma->iov.iov_len = n * 4 * 512;
- qemu_iovec_init_external(&s->bus->dma->qiov, &s->bus->dma->iov, 1);
-
- s->bus->dma->aiocb = ide_buffered_readv(s, (int64_t)s->lba << 2,
- &s->bus->dma->qiov, n * 4,
- ide_atapi_cmd_read_dma_cb, s);
- return;
-
-eot:
- if (ret < 0) {
- block_acct_failed(blk_get_stats(s->blk), &s->acct);
- } else {
- block_acct_done(blk_get_stats(s->blk), &s->acct);
- }
- ide_set_inactive(s, false);
-}
-
-/* start a CD-CDROM read command with DMA */
-/* XXX: test if DMA is available */
-static void ide_atapi_cmd_read_dma(IDEState *s, int lba, int nb_sectors,
- int sector_size)
-{
- s->lba = lba;
- s->packet_transfer_size = nb_sectors * sector_size;
- s->io_buffer_size = 0;
- s->cd_sector_size = sector_size;
-
- block_acct_start(blk_get_stats(s->blk), &s->acct, s->packet_transfer_size,
- BLOCK_ACCT_READ);
-
- /* XXX: check if BUSY_STAT should be set */
- s->status = READY_STAT | SEEK_STAT | DRQ_STAT | BUSY_STAT;
- ide_start_dma(s, ide_atapi_cmd_read_dma_cb);
-}
-
-static void ide_atapi_cmd_read(IDEState *s, int lba, int nb_sectors,
- int sector_size)
-{
-#ifdef DEBUG_IDE_ATAPI
- printf("read %s: LBA=%d nb_sectors=%d\n", s->atapi_dma ? "dma" : "pio",
- lba, nb_sectors);
-#endif
- if (s->atapi_dma) {
- ide_atapi_cmd_read_dma(s, lba, nb_sectors, sector_size);
- } else {
- ide_atapi_cmd_read_pio(s, lba, nb_sectors, sector_size);
- }
-}
-
-void ide_atapi_dma_restart(IDEState *s)
-{
- /*
- * At this point we can just re-evaluate the packet command and start over.
- * The presence of ->dma_cb callback in the pre_save ensures that the packet
- * command has been completely sent and we can safely restart command.
- */
- s->unit = s->bus->retry_unit;
- s->bus->dma->ops->restart_dma(s->bus->dma);
- ide_atapi_cmd(s);
-}
-
-static inline uint8_t ide_atapi_set_profile(uint8_t *buf, uint8_t *index,
- uint16_t profile)
-{
- uint8_t *buf_profile = buf + 12; /* start of profiles */
-
- buf_profile += ((*index) * 4); /* start of indexed profile */
- cpu_to_ube16 (buf_profile, profile);
- buf_profile[2] = ((buf_profile[0] == buf[6]) && (buf_profile[1] == buf[7]));
-
- /* each profile adds 4 bytes to the response */
- (*index)++;
- buf[11] += 4; /* Additional Length */
-
- return 4;
-}
-
-static int ide_dvd_read_structure(IDEState *s, int format,
- const uint8_t *packet, uint8_t *buf)
-{
- switch (format) {
- case 0x0: /* Physical format information */
- {
- int layer = packet[6];
- uint64_t total_sectors;
-
- if (layer != 0)
- return -ASC_INV_FIELD_IN_CMD_PACKET;
-
- total_sectors = s->nb_sectors >> 2;
- if (total_sectors == 0) {
- return -ASC_MEDIUM_NOT_PRESENT;
- }
-
- buf[4] = 1; /* DVD-ROM, part version 1 */
- buf[5] = 0xf; /* 120mm disc, minimum rate unspecified */
- buf[6] = 1; /* one layer, read-only (per MMC-2 spec) */
- buf[7] = 0; /* default densities */
-
- /* FIXME: 0x30000 per spec? */
- cpu_to_ube32(buf + 8, 0); /* start sector */
- cpu_to_ube32(buf + 12, total_sectors - 1); /* end sector */
- cpu_to_ube32(buf + 16, total_sectors - 1); /* l0 end sector */
-
- /* Size of buffer, not including 2 byte size field */
- stw_be_p(buf, 2048 + 2);
-
- /* 2k data + 4 byte header */
- return (2048 + 4);
- }
-
- case 0x01: /* DVD copyright information */
- buf[4] = 0; /* no copyright data */
- buf[5] = 0; /* no region restrictions */
-
- /* Size of buffer, not including 2 byte size field */
- stw_be_p(buf, 4 + 2);
-
- /* 4 byte header + 4 byte data */
- return (4 + 4);
-
- case 0x03: /* BCA information - invalid field for no BCA info */
- return -ASC_INV_FIELD_IN_CMD_PACKET;
-
- case 0x04: /* DVD disc manufacturing information */
- /* Size of buffer, not including 2 byte size field */
- stw_be_p(buf, 2048 + 2);
-
- /* 2k data + 4 byte header */
- return (2048 + 4);
-
- case 0xff:
- /*
- * This lists all the command capabilities above. Add new ones
- * in order and update the length and buffer return values.
- */
-
- buf[4] = 0x00; /* Physical format */
- buf[5] = 0x40; /* Not writable, is readable */
- stw_be_p(buf + 6, 2048 + 4);
-
- buf[8] = 0x01; /* Copyright info */
- buf[9] = 0x40; /* Not writable, is readable */
- stw_be_p(buf + 10, 4 + 4);
-
- buf[12] = 0x03; /* BCA info */
- buf[13] = 0x40; /* Not writable, is readable */
- stw_be_p(buf + 14, 188 + 4);
-
- buf[16] = 0x04; /* Manufacturing info */
- buf[17] = 0x40; /* Not writable, is readable */
- stw_be_p(buf + 18, 2048 + 4);
-
- /* Size of buffer, not including 2 byte size field */
- stw_be_p(buf, 16 + 2);
-
- /* data written + 4 byte header */
- return (16 + 4);
-
- default: /* TODO: formats beyond DVD-ROM requires */
- return -ASC_INV_FIELD_IN_CMD_PACKET;
- }
-}
-
-static unsigned int event_status_media(IDEState *s,
- uint8_t *buf)
-{
- uint8_t event_code, media_status;
-
- media_status = 0;
- if (s->tray_open) {
- media_status = MS_TRAY_OPEN;
- } else if (blk_is_inserted(s->blk)) {
- media_status = MS_MEDIA_PRESENT;
- }
-
- /* Event notification descriptor */
- event_code = MEC_NO_CHANGE;
- if (media_status != MS_TRAY_OPEN) {
- if (s->events.new_media) {
- event_code = MEC_NEW_MEDIA;
- s->events.new_media = false;
- } else if (s->events.eject_request) {
- event_code = MEC_EJECT_REQUESTED;
- s->events.eject_request = false;
- }
- }
-
- buf[4] = event_code;
- buf[5] = media_status;
-
- /* These fields are reserved, just clear them. */
- buf[6] = 0;
- buf[7] = 0;
-
- return 8; /* We wrote to 4 extra bytes from the header */
-}
-
-static void cmd_get_event_status_notification(IDEState *s,
- uint8_t *buf)
-{
- const uint8_t *packet = buf;
-
- struct {
- uint8_t opcode;
- uint8_t polled; /* lsb bit is polled; others are reserved */
- uint8_t reserved2[2];
- uint8_t class;
- uint8_t reserved3[2];
- uint16_t len;
- uint8_t control;
- } QEMU_PACKED *gesn_cdb;
-
- struct {
- uint16_t len;
- uint8_t notification_class;
- uint8_t supported_events;
- } QEMU_PACKED *gesn_event_header;
- unsigned int max_len, used_len;
-
- gesn_cdb = (void *)packet;
- gesn_event_header = (void *)buf;
-
- max_len = be16_to_cpu(gesn_cdb->len);
-
- /* It is fine by the MMC spec to not support async mode operations */
- if (!(gesn_cdb->polled & 0x01)) { /* asynchronous mode */
- /* Only polling is supported, asynchronous mode is not. */
- ide_atapi_cmd_error(s, ILLEGAL_REQUEST,
- ASC_INV_FIELD_IN_CMD_PACKET);
- return;
- }
-
- /* polling mode operation */
-
- /*
- * These are the supported events.
- *
- * We currently only support requests of the 'media' type.
- * Notification class requests and supported event classes are bitmasks,
- * but they are build from the same values as the "notification class"
- * field.
- */
- gesn_event_header->supported_events = 1 << GESN_MEDIA;
-
- /*
- * We use |= below to set the class field; other bits in this byte
- * are reserved now but this is useful to do if we have to use the
- * reserved fields later.
- */
- gesn_event_header->notification_class = 0;
-
- /*
- * Responses to requests are to be based on request priority. The
- * notification_class_request_type enum above specifies the
- * priority: upper elements are higher prio than lower ones.
- */
- if (gesn_cdb->class & (1 << GESN_MEDIA)) {
- gesn_event_header->notification_class |= GESN_MEDIA;
- used_len = event_status_media(s, buf);
- } else {
- gesn_event_header->notification_class = 0x80; /* No event available */
- used_len = sizeof(*gesn_event_header);
- }
- gesn_event_header->len = cpu_to_be16(used_len
- - sizeof(*gesn_event_header));
- ide_atapi_cmd_reply(s, used_len, max_len);
-}
-
-static void cmd_request_sense(IDEState *s, uint8_t *buf)
-{
- int max_len = buf[4];
-
- memset(buf, 0, 18);
- buf[0] = 0x70 | (1 << 7);
- buf[2] = s->sense_key;
- buf[7] = 10;
- buf[12] = s->asc;
-
- if (s->sense_key == UNIT_ATTENTION) {
- s->sense_key = NO_SENSE;
- }
-
- ide_atapi_cmd_reply(s, 18, max_len);
-}
-
-static void cmd_inquiry(IDEState *s, uint8_t *buf)
-{
- uint8_t page_code = buf[2];
- int max_len = buf[4];
-
- unsigned idx = 0;
- unsigned size_idx;
- unsigned preamble_len;
-
- /* If the EVPD (Enable Vital Product Data) bit is set in byte 1,
- * we are being asked for a specific page of info indicated by byte 2. */
- if (buf[1] & 0x01) {
- preamble_len = 4;
- size_idx = 3;
-
- buf[idx++] = 0x05; /* CD-ROM */
- buf[idx++] = page_code; /* Page Code */
- buf[idx++] = 0x00; /* reserved */
- idx++; /* length (set later) */
-
- switch (page_code) {
- case 0x00:
- /* Supported Pages: List of supported VPD responses. */
- buf[idx++] = 0x00; /* 0x00: Supported Pages, and: */
- buf[idx++] = 0x83; /* 0x83: Device Identification. */
- break;
-
- case 0x83:
- /* Device Identification. Each entry is optional, but the entries
- * included here are modeled after libata's VPD responses.
- * If the response is given, at least one entry must be present. */
-
- /* Entry 1: Serial */
- if (idx + 24 > max_len) {
- /* Not enough room for even the first entry: */
- /* 4 byte header + 20 byte string */
- ide_atapi_cmd_error(s, ILLEGAL_REQUEST,
- ASC_DATA_PHASE_ERROR);
- return;
- }
- buf[idx++] = 0x02; /* Ascii */
- buf[idx++] = 0x00; /* Vendor Specific */
- buf[idx++] = 0x00;
- buf[idx++] = 20; /* Remaining length */
- padstr8(buf + idx, 20, s->drive_serial_str);
- idx += 20;
-
- /* Entry 2: Drive Model and Serial */
- if (idx + 72 > max_len) {
- /* 4 (header) + 8 (vendor) + 60 (model & serial) */
- goto out;
- }
- buf[idx++] = 0x02; /* Ascii */
- buf[idx++] = 0x01; /* T10 Vendor */
- buf[idx++] = 0x00;
- buf[idx++] = 68;
- padstr8(buf + idx, 8, "ATA"); /* Generic T10 vendor */
- idx += 8;
- padstr8(buf + idx, 40, s->drive_model_str);
- idx += 40;
- padstr8(buf + idx, 20, s->drive_serial_str);
- idx += 20;
-
- /* Entry 3: WWN */
- if (s->wwn && (idx + 12 <= max_len)) {
- /* 4 byte header + 8 byte wwn */
- buf[idx++] = 0x01; /* Binary */
- buf[idx++] = 0x03; /* NAA */
- buf[idx++] = 0x00;
- buf[idx++] = 0x08;
- stq_be_p(&buf[idx], s->wwn);
- idx += 8;
- }
- break;
-
- default:
- /* SPC-3, revision 23 sec. 6.4 */
- ide_atapi_cmd_error(s, ILLEGAL_REQUEST,
- ASC_INV_FIELD_IN_CMD_PACKET);
- return;
- }
- } else {
- preamble_len = 5;
- size_idx = 4;
-
- buf[0] = 0x05; /* CD-ROM */
- buf[1] = 0x80; /* removable */
- buf[2] = 0x00; /* ISO */
- buf[3] = 0x21; /* ATAPI-2 (XXX: put ATAPI-4 ?) */
- /* buf[size_idx] set below. */
- buf[5] = 0; /* reserved */
- buf[6] = 0; /* reserved */
- buf[7] = 0; /* reserved */
- padstr8(buf + 8, 8, "QEMU");
- padstr8(buf + 16, 16, "QEMU DVD-ROM");
- padstr8(buf + 32, 4, s->version);
- idx = 36;
- }
-
- out:
- buf[size_idx] = idx - preamble_len;
- ide_atapi_cmd_reply(s, idx, max_len);
-}
-
-static void cmd_get_configuration(IDEState *s, uint8_t *buf)
-{
- uint32_t len;
- uint8_t index = 0;
- int max_len;
-
- /* only feature 0 is supported */
- if (buf[2] != 0 || buf[3] != 0) {
- ide_atapi_cmd_error(s, ILLEGAL_REQUEST,
- ASC_INV_FIELD_IN_CMD_PACKET);
- return;
- }
-
- /* XXX: could result in alignment problems in some architectures */
- max_len = ube16_to_cpu(buf + 7);
-
- /*
- * XXX: avoid overflow for io_buffer if max_len is bigger than
- * the size of that buffer (dimensioned to max number of
- * sectors to transfer at once)
- *
- * Only a problem if the feature/profiles grow.
- */
- if (max_len > 512) {
- /* XXX: assume 1 sector */
- max_len = 512;
- }
-
- memset(buf, 0, max_len);
- /*
- * the number of sectors from the media tells us which profile
- * to use as current. 0 means there is no media
- */
- if (media_is_dvd(s)) {
- cpu_to_ube16(buf + 6, MMC_PROFILE_DVD_ROM);
- } else if (media_is_cd(s)) {
- cpu_to_ube16(buf + 6, MMC_PROFILE_CD_ROM);
- }
-
- buf[10] = 0x02 | 0x01; /* persistent and current */
- len = 12; /* headers: 8 + 4 */
- len += ide_atapi_set_profile(buf, &index, MMC_PROFILE_DVD_ROM);
- len += ide_atapi_set_profile(buf, &index, MMC_PROFILE_CD_ROM);
- cpu_to_ube32(buf, len - 4); /* data length */
-
- ide_atapi_cmd_reply(s, len, max_len);
-}
-
-static void cmd_mode_sense(IDEState *s, uint8_t *buf)
-{
- int action, code;
- int max_len;
-
- max_len = ube16_to_cpu(buf + 7);
- action = buf[2] >> 6;
- code = buf[2] & 0x3f;
-
- switch(action) {
- case 0: /* current values */
- switch(code) {
- case MODE_PAGE_R_W_ERROR: /* error recovery */
- cpu_to_ube16(&buf[0], 16 - 2);
- buf[2] = 0x70;
- buf[3] = 0;
- buf[4] = 0;
- buf[5] = 0;
- buf[6] = 0;
- buf[7] = 0;
-
- buf[8] = MODE_PAGE_R_W_ERROR;
- buf[9] = 16 - 10;
- buf[10] = 0x00;
- buf[11] = 0x05;
- buf[12] = 0x00;
- buf[13] = 0x00;
- buf[14] = 0x00;
- buf[15] = 0x00;
- ide_atapi_cmd_reply(s, 16, max_len);
- break;
- case MODE_PAGE_AUDIO_CTL:
- cpu_to_ube16(&buf[0], 24 - 2);
- buf[2] = 0x70;
- buf[3] = 0;
- buf[4] = 0;
- buf[5] = 0;
- buf[6] = 0;
- buf[7] = 0;
-
- buf[8] = MODE_PAGE_AUDIO_CTL;
- buf[9] = 24 - 10;
- /* Fill with CDROM audio volume */
- buf[17] = 0;
- buf[19] = 0;
- buf[21] = 0;
- buf[23] = 0;
-
- ide_atapi_cmd_reply(s, 24, max_len);
- break;
- case MODE_PAGE_CAPABILITIES:
- cpu_to_ube16(&buf[0], 30 - 2);
- buf[2] = 0x70;
- buf[3] = 0;
- buf[4] = 0;
- buf[5] = 0;
- buf[6] = 0;
- buf[7] = 0;
-
- buf[8] = MODE_PAGE_CAPABILITIES;
- buf[9] = 30 - 10;
- buf[10] = 0x3b; /* read CDR/CDRW/DVDROM/DVDR/DVDRAM */
- buf[11] = 0x00;
-
- /* Claim PLAY_AUDIO capability (0x01) since some Linux
- code checks for this to automount media. */
- buf[12] = 0x71;
- buf[13] = 3 << 5;
- buf[14] = (1 << 0) | (1 << 3) | (1 << 5);
- if (s->tray_locked) {
- buf[14] |= 1 << 1;
- }
- buf[15] = 0x00; /* No volume & mute control, no changer */
- cpu_to_ube16(&buf[16], 704); /* 4x read speed */
- buf[18] = 0; /* Two volume levels */
- buf[19] = 2;
- cpu_to_ube16(&buf[20], 512); /* 512k buffer */
- cpu_to_ube16(&buf[22], 704); /* 4x read speed current */
- buf[24] = 0;
- buf[25] = 0;
- buf[26] = 0;
- buf[27] = 0;
- buf[28] = 0;
- buf[29] = 0;
- ide_atapi_cmd_reply(s, 30, max_len);
- break;
- default:
- goto error_cmd;
- }
- break;
- case 1: /* changeable values */
- goto error_cmd;
- case 2: /* default values */
- goto error_cmd;
- default:
- case 3: /* saved values */
- ide_atapi_cmd_error(s, ILLEGAL_REQUEST,
- ASC_SAVING_PARAMETERS_NOT_SUPPORTED);
- break;
- }
- return;
-
-error_cmd:
- ide_atapi_cmd_error(s, ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET);
-}
-
-static void cmd_test_unit_ready(IDEState *s, uint8_t *buf)
-{
- /* Not Ready Conditions are already handled in ide_atapi_cmd(), so if we
- * come here, we know that it's ready. */
- ide_atapi_cmd_ok(s);
-}
-
-static void cmd_prevent_allow_medium_removal(IDEState *s, uint8_t* buf)
-{
- s->tray_locked = buf[4] & 1;
- blk_lock_medium(s->blk, buf[4] & 1);
- ide_atapi_cmd_ok(s);
-}
-
-static void cmd_read(IDEState *s, uint8_t* buf)
-{
- int nb_sectors, lba;
-
- if (buf[0] == GPCMD_READ_10) {
- nb_sectors = ube16_to_cpu(buf + 7);
- } else {
- nb_sectors = ube32_to_cpu(buf + 6);
- }
-
- lba = ube32_to_cpu(buf + 2);
- if (nb_sectors == 0) {
- ide_atapi_cmd_ok(s);
- return;
- }
-
- ide_atapi_cmd_read(s, lba, nb_sectors, 2048);
-}
-
-static void cmd_read_cd(IDEState *s, uint8_t* buf)
-{
- int nb_sectors, lba, transfer_request;
-
- nb_sectors = (buf[6] << 16) | (buf[7] << 8) | buf[8];
- lba = ube32_to_cpu(buf + 2);
-
- if (nb_sectors == 0) {
- ide_atapi_cmd_ok(s);
- return;
- }
-
- transfer_request = buf[9];
- switch(transfer_request & 0xf8) {
- case 0x00:
- /* nothing */
- ide_atapi_cmd_ok(s);
- break;
- case 0x10:
- /* normal read */
- ide_atapi_cmd_read(s, lba, nb_sectors, 2048);
- break;
- case 0xf8:
- /* read all data */
- ide_atapi_cmd_read(s, lba, nb_sectors, 2352);
- break;
- default:
- ide_atapi_cmd_error(s, ILLEGAL_REQUEST,
- ASC_INV_FIELD_IN_CMD_PACKET);
- break;
- }
-}
-
-static void cmd_seek(IDEState *s, uint8_t* buf)
-{
- unsigned int lba;
- uint64_t total_sectors = s->nb_sectors >> 2;
-
- lba = ube32_to_cpu(buf + 2);
- if (lba >= total_sectors) {
- ide_atapi_cmd_error(s, ILLEGAL_REQUEST, ASC_LOGICAL_BLOCK_OOR);
- return;
- }
-
- ide_atapi_cmd_ok(s);
-}
-
-static void cmd_start_stop_unit(IDEState *s, uint8_t* buf)
-{
- int sense;
- bool start = buf[4] & 1;
- bool loej = buf[4] & 2; /* load on start, eject on !start */
- int pwrcnd = buf[4] & 0xf0;
-
- if (pwrcnd) {
- /* eject/load only happens for power condition == 0 */
- ide_atapi_cmd_ok(s);
- return;
- }
-
- if (loej) {
- if (!start && !s->tray_open && s->tray_locked) {
- sense = blk_is_inserted(s->blk)
- ? NOT_READY : ILLEGAL_REQUEST;
- ide_atapi_cmd_error(s, sense, ASC_MEDIA_REMOVAL_PREVENTED);
- return;
- }
-
- if (s->tray_open != !start) {
- blk_eject(s->blk, !start);
- s->tray_open = !start;
- }
- }
-
- ide_atapi_cmd_ok(s);
-}
-
-static void cmd_mechanism_status(IDEState *s, uint8_t* buf)
-{
- int max_len = ube16_to_cpu(buf + 8);
-
- cpu_to_ube16(buf, 0);
- /* no current LBA */
- buf[2] = 0;
- buf[3] = 0;
- buf[4] = 0;
- buf[5] = 1;
- cpu_to_ube16(buf + 6, 0);
- ide_atapi_cmd_reply(s, 8, max_len);
-}
-
-static void cmd_read_toc_pma_atip(IDEState *s, uint8_t* buf)
-{
- int format, msf, start_track, len;
- int max_len;
- uint64_t total_sectors = s->nb_sectors >> 2;
-
- max_len = ube16_to_cpu(buf + 7);
- format = buf[9] >> 6;
- msf = (buf[1] >> 1) & 1;
- start_track = buf[6];
-
- switch(format) {
- case 0:
- len = cdrom_read_toc(total_sectors, buf, msf, start_track);
- if (len < 0)
- goto error_cmd;
- ide_atapi_cmd_reply(s, len, max_len);
- break;
- case 1:
- /* multi session : only a single session defined */
- memset(buf, 0, 12);
- buf[1] = 0x0a;
- buf[2] = 0x01;
- buf[3] = 0x01;
- ide_atapi_cmd_reply(s, 12, max_len);
- break;
- case 2:
- len = cdrom_read_toc_raw(total_sectors, buf, msf, start_track);
- if (len < 0)
- goto error_cmd;
- ide_atapi_cmd_reply(s, len, max_len);
- break;
- default:
- error_cmd:
- ide_atapi_cmd_error(s, ILLEGAL_REQUEST,
- ASC_INV_FIELD_IN_CMD_PACKET);
- }
-}
-
-static void cmd_read_cdvd_capacity(IDEState *s, uint8_t* buf)
-{
- uint64_t total_sectors = s->nb_sectors >> 2;
-
- /* NOTE: it is really the number of sectors minus 1 */
- cpu_to_ube32(buf, total_sectors - 1);
- cpu_to_ube32(buf + 4, 2048);
- ide_atapi_cmd_reply(s, 8, 8);
-}
-
-static void cmd_read_disc_information(IDEState *s, uint8_t* buf)
-{
- uint8_t type = buf[1] & 7;
- uint32_t max_len = ube16_to_cpu(buf + 7);
-
- /* Types 1/2 are only defined for Blu-Ray. */
- if (type != 0) {
- ide_atapi_cmd_error(s, ILLEGAL_REQUEST,
- ASC_INV_FIELD_IN_CMD_PACKET);
- return;
- }
-
- memset(buf, 0, 34);
- buf[1] = 32;
- buf[2] = 0xe; /* last session complete, disc finalized */
- buf[3] = 1; /* first track on disc */
- buf[4] = 1; /* # of sessions */
- buf[5] = 1; /* first track of last session */
- buf[6] = 1; /* last track of last session */
- buf[7] = 0x20; /* unrestricted use */
- buf[8] = 0x00; /* CD-ROM or DVD-ROM */
- /* 9-10-11: most significant byte corresponding bytes 4-5-6 */
- /* 12-23: not meaningful for CD-ROM or DVD-ROM */
- /* 24-31: disc bar code */
- /* 32: disc application code */
- /* 33: number of OPC tables */
-
- ide_atapi_cmd_reply(s, 34, max_len);
-}
-
-static void cmd_read_dvd_structure(IDEState *s, uint8_t* buf)
-{
- int max_len;
- int media = buf[1];
- int format = buf[7];
- int ret;
-
- max_len = ube16_to_cpu(buf + 8);
-
- if (format < 0xff) {
- if (media_is_cd(s)) {
- ide_atapi_cmd_error(s, ILLEGAL_REQUEST,
- ASC_INCOMPATIBLE_FORMAT);
- return;
- } else if (!media_present(s)) {
- ide_atapi_cmd_error(s, ILLEGAL_REQUEST,
- ASC_INV_FIELD_IN_CMD_PACKET);
- return;
- }
- }
-
- memset(buf, 0, max_len > IDE_DMA_BUF_SECTORS * 512 + 4 ?
- IDE_DMA_BUF_SECTORS * 512 + 4 : max_len);
-
- switch (format) {
- case 0x00 ... 0x7f:
- case 0xff:
- if (media == 0) {
- ret = ide_dvd_read_structure(s, format, buf, buf);
-
- if (ret < 0) {
- ide_atapi_cmd_error(s, ILLEGAL_REQUEST, -ret);
- } else {
- ide_atapi_cmd_reply(s, ret, max_len);
- }
-
- break;
- }
- /* TODO: BD support, fall through for now */
-
- /* Generic disk structures */
- case 0x80: /* TODO: AACS volume identifier */
- case 0x81: /* TODO: AACS media serial number */
- case 0x82: /* TODO: AACS media identifier */
- case 0x83: /* TODO: AACS media key block */
- case 0x90: /* TODO: List of recognized format layers */
- case 0xc0: /* TODO: Write protection status */
- default:
- ide_atapi_cmd_error(s, ILLEGAL_REQUEST,
- ASC_INV_FIELD_IN_CMD_PACKET);
- break;
- }
-}
-
-static void cmd_set_speed(IDEState *s, uint8_t* buf)
-{
- ide_atapi_cmd_ok(s);
-}
-
-enum {
- /*
- * Only commands flagged as ALLOW_UA are allowed to run under a
- * unit attention condition. (See MMC-5, section 4.1.6.1)
- */
- ALLOW_UA = 0x01,
-
- /*
- * Commands flagged with CHECK_READY can only execute if a medium is present.
- * Otherwise they report the Not Ready Condition. (See MMC-5, section
- * 4.1.8)
- */
- CHECK_READY = 0x02,
-
- /*
- * Commands flagged with NONDATA do not in any circumstances return
- * any data via ide_atapi_cmd_reply. These commands are exempt from
- * the normal byte_count_limit constraints.
- * See ATA8-ACS3 "7.21.5 Byte Count Limit"
- */
- NONDATA = 0x04,
-};
-
-static const struct AtapiCmd {
- void (*handler)(IDEState *s, uint8_t *buf);
- int flags;
-} atapi_cmd_table[0x100] = {
- [ 0x00 ] = { cmd_test_unit_ready, CHECK_READY | NONDATA },
- [ 0x03 ] = { cmd_request_sense, ALLOW_UA },
- [ 0x12 ] = { cmd_inquiry, ALLOW_UA },
- [ 0x1b ] = { cmd_start_stop_unit, NONDATA }, /* [1] */
- [ 0x1e ] = { cmd_prevent_allow_medium_removal, NONDATA },
- [ 0x25 ] = { cmd_read_cdvd_capacity, CHECK_READY },
- [ 0x28 ] = { cmd_read, /* (10) */ CHECK_READY },
- [ 0x2b ] = { cmd_seek, CHECK_READY | NONDATA },
- [ 0x43 ] = { cmd_read_toc_pma_atip, CHECK_READY },
- [ 0x46 ] = { cmd_get_configuration, ALLOW_UA },
- [ 0x4a ] = { cmd_get_event_status_notification, ALLOW_UA },
- [ 0x51 ] = { cmd_read_disc_information, CHECK_READY },
- [ 0x5a ] = { cmd_mode_sense, /* (10) */ 0 },
- [ 0xa8 ] = { cmd_read, /* (12) */ CHECK_READY },
- [ 0xad ] = { cmd_read_dvd_structure, CHECK_READY },
- [ 0xbb ] = { cmd_set_speed, NONDATA },
- [ 0xbd ] = { cmd_mechanism_status, 0 },
- [ 0xbe ] = { cmd_read_cd, CHECK_READY },
- /* [1] handler detects and reports not ready condition itself */
-};
-
-void ide_atapi_cmd(IDEState *s)
-{
- uint8_t *buf = s->io_buffer;
- const struct AtapiCmd *cmd = &atapi_cmd_table[s->io_buffer[0]];
-
-#ifdef DEBUG_IDE_ATAPI
- {
- int i;
- printf("ATAPI limit=0x%x packet:", s->lcyl | (s->hcyl << 8));
- for(i = 0; i < ATAPI_PACKET_SIZE; i++) {
- printf(" %02x", buf[i]);
- }
- printf("\n");
- }
-#endif
-
- /*
- * If there's a UNIT_ATTENTION condition pending, only command flagged with
- * ALLOW_UA are allowed to complete. with other commands getting a CHECK
- * condition response unless a higher priority status, defined by the drive
- * here, is pending.
- */
- if (s->sense_key == UNIT_ATTENTION && !(cmd->flags & ALLOW_UA)) {
- ide_atapi_cmd_check_status(s);
- return;
- }
- /*
- * When a CD gets changed, we have to report an ejected state and
- * then a loaded state to guests so that they detect tray
- * open/close and media change events. Guests that do not use
- * GET_EVENT_STATUS_NOTIFICATION to detect such tray open/close
- * states rely on this behavior.
- */
- if (!(cmd->flags & ALLOW_UA) &&
- !s->tray_open && blk_is_inserted(s->blk) && s->cdrom_changed) {
-
- if (s->cdrom_changed == 1) {
- ide_atapi_cmd_error(s, NOT_READY, ASC_MEDIUM_NOT_PRESENT);
- s->cdrom_changed = 2;
- } else {
- ide_atapi_cmd_error(s, UNIT_ATTENTION, ASC_MEDIUM_MAY_HAVE_CHANGED);
- s->cdrom_changed = 0;
- }
-
- return;
- }
-
- /* Report a Not Ready condition if appropriate for the command */
- if ((cmd->flags & CHECK_READY) &&
- (!media_present(s) || !blk_is_inserted(s->blk)))
- {
- ide_atapi_cmd_error(s, NOT_READY, ASC_MEDIUM_NOT_PRESENT);
- return;
- }
-
- /* Nondata commands permit the byte_count_limit to be 0.
- * If this is a data-transferring PIO command and BCL is 0,
- * we abort at the /ATA/ level, not the ATAPI level.
- * See ATA8 ACS3 section 7.17.6.49 and 7.21.5 */
- if (cmd->handler && !(cmd->flags & NONDATA)) {
- /* TODO: Check IDENTIFY data word 125 for default BCL (currently 0) */
- if (!(atapi_byte_count_limit(s) || s->atapi_dma)) {
- /* TODO: Move abort back into core.c and make static inline again */
- ide_abort_command(s);
- return;
- }
- }
-
- /* Execute the command */
- if (cmd->handler) {
- cmd->handler(s, buf);
- return;
- }
-
- ide_atapi_cmd_error(s, ILLEGAL_REQUEST, ASC_ILLEGAL_OPCODE);
-}
diff --git a/qemu/hw/ide/cmd646.c b/qemu/hw/ide/cmd646.c
deleted file mode 100644
index 49294a531..000000000
--- a/qemu/hw/ide/cmd646.c
+++ /dev/null
@@ -1,435 +0,0 @@
-/*
- * QEMU IDE Emulation: PCI cmd646 support.
- *
- * Copyright (c) 2003 Fabrice Bellard
- * Copyright (c) 2006 Openedhand Ltd.
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include <hw/hw.h>
-#include <hw/i386/pc.h>
-#include <hw/pci/pci.h>
-#include <hw/isa/isa.h>
-#include "sysemu/block-backend.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/dma.h"
-
-#include <hw/ide/pci.h>
-
-/* CMD646 specific */
-#define CFR 0x50
-#define CFR_INTR_CH0 0x04
-#define CNTRL 0x51
-#define CNTRL_EN_CH0 0x04
-#define CNTRL_EN_CH1 0x08
-#define ARTTIM23 0x57
-#define ARTTIM23_INTR_CH1 0x10
-#define MRDMODE 0x71
-#define MRDMODE_INTR_CH0 0x04
-#define MRDMODE_INTR_CH1 0x08
-#define MRDMODE_BLK_CH0 0x10
-#define MRDMODE_BLK_CH1 0x20
-#define UDIDETCR0 0x73
-#define UDIDETCR1 0x7B
-
-static void cmd646_update_irq(PCIDevice *pd);
-
-static uint64_t cmd646_cmd_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- CMD646BAR *cmd646bar = opaque;
-
- if (addr != 2 || size != 1) {
- return ((uint64_t)1 << (size * 8)) - 1;
- }
- return ide_status_read(cmd646bar->bus, addr + 2);
-}
-
-static void cmd646_cmd_write(void *opaque, hwaddr addr,
- uint64_t data, unsigned size)
-{
- CMD646BAR *cmd646bar = opaque;
-
- if (addr != 2 || size != 1) {
- return;
- }
- ide_cmd_write(cmd646bar->bus, addr + 2, data);
-}
-
-static const MemoryRegionOps cmd646_cmd_ops = {
- .read = cmd646_cmd_read,
- .write = cmd646_cmd_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static uint64_t cmd646_data_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- CMD646BAR *cmd646bar = opaque;
-
- if (size == 1) {
- return ide_ioport_read(cmd646bar->bus, addr);
- } else if (addr == 0) {
- if (size == 2) {
- return ide_data_readw(cmd646bar->bus, addr);
- } else {
- return ide_data_readl(cmd646bar->bus, addr);
- }
- }
- return ((uint64_t)1 << (size * 8)) - 1;
-}
-
-static void cmd646_data_write(void *opaque, hwaddr addr,
- uint64_t data, unsigned size)
-{
- CMD646BAR *cmd646bar = opaque;
-
- if (size == 1) {
- ide_ioport_write(cmd646bar->bus, addr, data);
- } else if (addr == 0) {
- if (size == 2) {
- ide_data_writew(cmd646bar->bus, addr, data);
- } else {
- ide_data_writel(cmd646bar->bus, addr, data);
- }
- }
-}
-
-static const MemoryRegionOps cmd646_data_ops = {
- .read = cmd646_data_read,
- .write = cmd646_data_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void setup_cmd646_bar(PCIIDEState *d, int bus_num)
-{
- IDEBus *bus = &d->bus[bus_num];
- CMD646BAR *bar = &d->cmd646_bar[bus_num];
-
- bar->bus = bus;
- bar->pci_dev = d;
- memory_region_init_io(&bar->cmd, OBJECT(d), &cmd646_cmd_ops, bar,
- "cmd646-cmd", 4);
- memory_region_init_io(&bar->data, OBJECT(d), &cmd646_data_ops, bar,
- "cmd646-data", 8);
-}
-
-static void cmd646_update_dma_interrupts(PCIDevice *pd)
-{
- /* Sync DMA interrupt status from UDMA interrupt status */
- if (pd->config[MRDMODE] & MRDMODE_INTR_CH0) {
- pd->config[CFR] |= CFR_INTR_CH0;
- } else {
- pd->config[CFR] &= ~CFR_INTR_CH0;
- }
-
- if (pd->config[MRDMODE] & MRDMODE_INTR_CH1) {
- pd->config[ARTTIM23] |= ARTTIM23_INTR_CH1;
- } else {
- pd->config[ARTTIM23] &= ~ARTTIM23_INTR_CH1;
- }
-}
-
-static void cmd646_update_udma_interrupts(PCIDevice *pd)
-{
- /* Sync UDMA interrupt status from DMA interrupt status */
- if (pd->config[CFR] & CFR_INTR_CH0) {
- pd->config[MRDMODE] |= MRDMODE_INTR_CH0;
- } else {
- pd->config[MRDMODE] &= ~MRDMODE_INTR_CH0;
- }
-
- if (pd->config[ARTTIM23] & ARTTIM23_INTR_CH1) {
- pd->config[MRDMODE] |= MRDMODE_INTR_CH1;
- } else {
- pd->config[MRDMODE] &= ~MRDMODE_INTR_CH1;
- }
-}
-
-static uint64_t bmdma_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- BMDMAState *bm = opaque;
- PCIDevice *pci_dev = PCI_DEVICE(bm->pci_dev);
- uint32_t val;
-
- if (size != 1) {
- return ((uint64_t)1 << (size * 8)) - 1;
- }
-
- switch(addr & 3) {
- case 0:
- val = bm->cmd;
- break;
- case 1:
- val = pci_dev->config[MRDMODE];
- break;
- case 2:
- val = bm->status;
- break;
- case 3:
- if (bm == &bm->pci_dev->bmdma[0]) {
- val = pci_dev->config[UDIDETCR0];
- } else {
- val = pci_dev->config[UDIDETCR1];
- }
- break;
- default:
- val = 0xff;
- break;
- }
-#ifdef DEBUG_IDE
- printf("bmdma: readb " TARGET_FMT_plx " : 0x%02x\n", addr, val);
-#endif
- return val;
-}
-
-static void bmdma_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- BMDMAState *bm = opaque;
- PCIDevice *pci_dev = PCI_DEVICE(bm->pci_dev);
-
- if (size != 1) {
- return;
- }
-
-#ifdef DEBUG_IDE
- printf("bmdma: writeb " TARGET_FMT_plx " : 0x%" PRIx64 "\n", addr, val);
-#endif
- switch(addr & 3) {
- case 0:
- bmdma_cmd_writeb(bm, val);
- break;
- case 1:
- pci_dev->config[MRDMODE] =
- (pci_dev->config[MRDMODE] & ~0x30) | (val & 0x30);
- cmd646_update_dma_interrupts(pci_dev);
- cmd646_update_irq(pci_dev);
- break;
- case 2:
- bm->status = (val & 0x60) | (bm->status & 1) | (bm->status & ~val & 0x06);
- break;
- case 3:
- if (bm == &bm->pci_dev->bmdma[0]) {
- pci_dev->config[UDIDETCR0] = val;
- } else {
- pci_dev->config[UDIDETCR1] = val;
- }
- break;
- }
-}
-
-static const MemoryRegionOps cmd646_bmdma_ops = {
- .read = bmdma_read,
- .write = bmdma_write,
-};
-
-static void bmdma_setup_bar(PCIIDEState *d)
-{
- BMDMAState *bm;
- int i;
-
- memory_region_init(&d->bmdma_bar, OBJECT(d), "cmd646-bmdma", 16);
- for(i = 0;i < 2; i++) {
- bm = &d->bmdma[i];
- memory_region_init_io(&bm->extra_io, OBJECT(d), &cmd646_bmdma_ops, bm,
- "cmd646-bmdma-bus", 4);
- memory_region_add_subregion(&d->bmdma_bar, i * 8, &bm->extra_io);
- memory_region_init_io(&bm->addr_ioport, OBJECT(d),
- &bmdma_addr_ioport_ops, bm,
- "cmd646-bmdma-ioport", 4);
- memory_region_add_subregion(&d->bmdma_bar, i * 8 + 4, &bm->addr_ioport);
- }
-}
-
-static void cmd646_update_irq(PCIDevice *pd)
-{
- int pci_level;
-
- pci_level = ((pd->config[MRDMODE] & MRDMODE_INTR_CH0) &&
- !(pd->config[MRDMODE] & MRDMODE_BLK_CH0)) ||
- ((pd->config[MRDMODE] & MRDMODE_INTR_CH1) &&
- !(pd->config[MRDMODE] & MRDMODE_BLK_CH1));
- pci_set_irq(pd, pci_level);
-}
-
-/* the PCI irq level is the logical OR of the two channels */
-static void cmd646_set_irq(void *opaque, int channel, int level)
-{
- PCIIDEState *d = opaque;
- PCIDevice *pd = PCI_DEVICE(d);
- int irq_mask;
-
- irq_mask = MRDMODE_INTR_CH0 << channel;
- if (level) {
- pd->config[MRDMODE] |= irq_mask;
- } else {
- pd->config[MRDMODE] &= ~irq_mask;
- }
- cmd646_update_dma_interrupts(pd);
- cmd646_update_irq(pd);
-}
-
-static void cmd646_reset(void *opaque)
-{
- PCIIDEState *d = opaque;
- unsigned int i;
-
- for (i = 0; i < 2; i++) {
- ide_bus_reset(&d->bus[i]);
- }
-}
-
-static uint32_t cmd646_pci_config_read(PCIDevice *d,
- uint32_t address, int len)
-{
- return pci_default_read_config(d, address, len);
-}
-
-static void cmd646_pci_config_write(PCIDevice *d, uint32_t addr, uint32_t val,
- int l)
-{
- uint32_t i;
-
- pci_default_write_config(d, addr, val, l);
-
- for (i = addr; i < addr + l; i++) {
- switch (i) {
- case CFR:
- case ARTTIM23:
- cmd646_update_udma_interrupts(d);
- break;
- case MRDMODE:
- cmd646_update_dma_interrupts(d);
- break;
- }
- }
-
- cmd646_update_irq(d);
-}
-
-/* CMD646 PCI IDE controller */
-static void pci_cmd646_ide_realize(PCIDevice *dev, Error **errp)
-{
- PCIIDEState *d = PCI_IDE(dev);
- uint8_t *pci_conf = dev->config;
- qemu_irq *irq;
- int i;
-
- pci_conf[PCI_CLASS_PROG] = 0x8f;
-
- pci_conf[CNTRL] = CNTRL_EN_CH0; // enable IDE0
- if (d->secondary) {
- /* XXX: if not enabled, really disable the seconday IDE controller */
- pci_conf[CNTRL] |= CNTRL_EN_CH1; /* enable IDE1 */
- }
-
- /* Set write-to-clear interrupt bits */
- dev->wmask[CFR] = 0x0;
- dev->w1cmask[CFR] = CFR_INTR_CH0;
- dev->wmask[ARTTIM23] = 0x0;
- dev->w1cmask[ARTTIM23] = ARTTIM23_INTR_CH1;
- dev->wmask[MRDMODE] = 0x0;
- dev->w1cmask[MRDMODE] = MRDMODE_INTR_CH0 | MRDMODE_INTR_CH1;
-
- setup_cmd646_bar(d, 0);
- setup_cmd646_bar(d, 1);
- pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &d->cmd646_bar[0].data);
- pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &d->cmd646_bar[0].cmd);
- pci_register_bar(dev, 2, PCI_BASE_ADDRESS_SPACE_IO, &d->cmd646_bar[1].data);
- pci_register_bar(dev, 3, PCI_BASE_ADDRESS_SPACE_IO, &d->cmd646_bar[1].cmd);
- bmdma_setup_bar(d);
- pci_register_bar(dev, 4, PCI_BASE_ADDRESS_SPACE_IO, &d->bmdma_bar);
-
- /* TODO: RST# value should be 0 */
- pci_conf[PCI_INTERRUPT_PIN] = 0x01; // interrupt on pin 1
-
- irq = qemu_allocate_irqs(cmd646_set_irq, d, 2);
- for (i = 0; i < 2; i++) {
- ide_bus_new(&d->bus[i], sizeof(d->bus[i]), DEVICE(dev), i, 2);
- ide_init2(&d->bus[i], irq[i]);
-
- bmdma_init(&d->bus[i], &d->bmdma[i], d);
- d->bmdma[i].bus = &d->bus[i];
- ide_register_restart_cb(&d->bus[i]);
- }
-
- vmstate_register(DEVICE(dev), 0, &vmstate_ide_pci, d);
- qemu_register_reset(cmd646_reset, d);
-}
-
-static void pci_cmd646_ide_exitfn(PCIDevice *dev)
-{
- PCIIDEState *d = PCI_IDE(dev);
- unsigned i;
-
- for (i = 0; i < 2; ++i) {
- memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].extra_io);
- memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].addr_ioport);
- }
-}
-
-void pci_cmd646_ide_init(PCIBus *bus, DriveInfo **hd_table,
- int secondary_ide_enabled)
-{
- PCIDevice *dev;
-
- dev = pci_create(bus, -1, "cmd646-ide");
- qdev_prop_set_uint32(&dev->qdev, "secondary", secondary_ide_enabled);
- qdev_init_nofail(&dev->qdev);
-
- pci_ide_create_devs(dev, hd_table);
-}
-
-static Property cmd646_ide_properties[] = {
- DEFINE_PROP_UINT32("secondary", PCIIDEState, secondary, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void cmd646_ide_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = pci_cmd646_ide_realize;
- k->exit = pci_cmd646_ide_exitfn;
- k->vendor_id = PCI_VENDOR_ID_CMD;
- k->device_id = PCI_DEVICE_ID_CMD_646;
- k->revision = 0x07;
- k->class_id = PCI_CLASS_STORAGE_IDE;
- k->config_read = cmd646_pci_config_read;
- k->config_write = cmd646_pci_config_write;
- dc->props = cmd646_ide_properties;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
-}
-
-static const TypeInfo cmd646_ide_info = {
- .name = "cmd646-ide",
- .parent = TYPE_PCI_IDE,
- .class_init = cmd646_ide_class_init,
-};
-
-static void cmd646_ide_register_types(void)
-{
- type_register_static(&cmd646_ide_info);
-}
-
-type_init(cmd646_ide_register_types)
diff --git a/qemu/hw/ide/core.c b/qemu/hw/ide/core.c
deleted file mode 100644
index 41e6a2dc4..000000000
--- a/qemu/hw/ide/core.c
+++ /dev/null
@@ -1,2842 +0,0 @@
-/*
- * QEMU IDE disk and CD/DVD-ROM Emulator
- *
- * Copyright (c) 2003 Fabrice Bellard
- * Copyright (c) 2006 Openedhand Ltd.
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include <hw/hw.h>
-#include <hw/i386/pc.h>
-#include <hw/pci/pci.h>
-#include <hw/isa/isa.h>
-#include "qemu/error-report.h"
-#include "qemu/timer.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/dma.h"
-#include "hw/block/block.h"
-#include "sysemu/block-backend.h"
-#include "qemu/cutils.h"
-
-#include <hw/ide/internal.h>
-
-/* These values were based on a Seagate ST3500418AS but have been modified
- to make more sense in QEMU */
-static const int smart_attributes[][12] = {
- /* id, flags, hflags, val, wrst, raw (6 bytes), threshold */
- /* raw read error rate*/
- { 0x01, 0x03, 0x00, 0x64, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06},
- /* spin up */
- { 0x03, 0x03, 0x00, 0x64, 0x64, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- /* start stop count */
- { 0x04, 0x02, 0x00, 0x64, 0x64, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14},
- /* remapped sectors */
- { 0x05, 0x03, 0x00, 0x64, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24},
- /* power on hours */
- { 0x09, 0x03, 0x00, 0x64, 0x64, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- /* power cycle count */
- { 0x0c, 0x03, 0x00, 0x64, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- /* airflow-temperature-celsius */
- { 190, 0x03, 0x00, 0x45, 0x45, 0x1f, 0x00, 0x1f, 0x1f, 0x00, 0x00, 0x32},
-};
-
-static void ide_dummy_transfer_stop(IDEState *s);
-
-static void padstr(char *str, const char *src, int len)
-{
- int i, v;
- for(i = 0; i < len; i++) {
- if (*src)
- v = *src++;
- else
- v = ' ';
- str[i^1] = v;
- }
-}
-
-static void put_le16(uint16_t *p, unsigned int v)
-{
- *p = cpu_to_le16(v);
-}
-
-static void ide_identify_size(IDEState *s)
-{
- uint16_t *p = (uint16_t *)s->identify_data;
- put_le16(p + 60, s->nb_sectors);
- put_le16(p + 61, s->nb_sectors >> 16);
- put_le16(p + 100, s->nb_sectors);
- put_le16(p + 101, s->nb_sectors >> 16);
- put_le16(p + 102, s->nb_sectors >> 32);
- put_le16(p + 103, s->nb_sectors >> 48);
-}
-
-static void ide_identify(IDEState *s)
-{
- uint16_t *p;
- unsigned int oldsize;
- IDEDevice *dev = s->unit ? s->bus->slave : s->bus->master;
-
- p = (uint16_t *)s->identify_data;
- if (s->identify_set) {
- goto fill_buffer;
- }
- memset(p, 0, sizeof(s->identify_data));
-
- put_le16(p + 0, 0x0040);
- put_le16(p + 1, s->cylinders);
- put_le16(p + 3, s->heads);
- put_le16(p + 4, 512 * s->sectors); /* XXX: retired, remove ? */
- put_le16(p + 5, 512); /* XXX: retired, remove ? */
- put_le16(p + 6, s->sectors);
- padstr((char *)(p + 10), s->drive_serial_str, 20); /* serial number */
- put_le16(p + 20, 3); /* XXX: retired, remove ? */
- put_le16(p + 21, 512); /* cache size in sectors */
- put_le16(p + 22, 4); /* ecc bytes */
- padstr((char *)(p + 23), s->version, 8); /* firmware version */
- padstr((char *)(p + 27), s->drive_model_str, 40); /* model */
-#if MAX_MULT_SECTORS > 1
- put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS);
-#endif
- put_le16(p + 48, 1); /* dword I/O */
- put_le16(p + 49, (1 << 11) | (1 << 9) | (1 << 8)); /* DMA and LBA supported */
- put_le16(p + 51, 0x200); /* PIO transfer cycle */
- put_le16(p + 52, 0x200); /* DMA transfer cycle */
- put_le16(p + 53, 1 | (1 << 1) | (1 << 2)); /* words 54-58,64-70,88 are valid */
- put_le16(p + 54, s->cylinders);
- put_le16(p + 55, s->heads);
- put_le16(p + 56, s->sectors);
- oldsize = s->cylinders * s->heads * s->sectors;
- put_le16(p + 57, oldsize);
- put_le16(p + 58, oldsize >> 16);
- if (s->mult_sectors)
- put_le16(p + 59, 0x100 | s->mult_sectors);
- /* *(p + 60) := nb_sectors -- see ide_identify_size */
- /* *(p + 61) := nb_sectors >> 16 -- see ide_identify_size */
- put_le16(p + 62, 0x07); /* single word dma0-2 supported */
- put_le16(p + 63, 0x07); /* mdma0-2 supported */
- put_le16(p + 64, 0x03); /* pio3-4 supported */
- put_le16(p + 65, 120);
- put_le16(p + 66, 120);
- put_le16(p + 67, 120);
- put_le16(p + 68, 120);
- if (dev && dev->conf.discard_granularity) {
- put_le16(p + 69, (1 << 14)); /* determinate TRIM behavior */
- }
-
- if (s->ncq_queues) {
- put_le16(p + 75, s->ncq_queues - 1);
- /* NCQ supported */
- put_le16(p + 76, (1 << 8));
- }
-
- put_le16(p + 80, 0xf0); /* ata3 -> ata6 supported */
- put_le16(p + 81, 0x16); /* conforms to ata5 */
- /* 14=NOP supported, 5=WCACHE supported, 0=SMART supported */
- put_le16(p + 82, (1 << 14) | (1 << 5) | 1);
- /* 13=flush_cache_ext,12=flush_cache,10=lba48 */
- put_le16(p + 83, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10));
- /* 14=set to 1, 8=has WWN, 1=SMART self test, 0=SMART error logging */
- if (s->wwn) {
- put_le16(p + 84, (1 << 14) | (1 << 8) | 0);
- } else {
- put_le16(p + 84, (1 << 14) | 0);
- }
- /* 14 = NOP supported, 5=WCACHE enabled, 0=SMART feature set enabled */
- if (blk_enable_write_cache(s->blk)) {
- put_le16(p + 85, (1 << 14) | (1 << 5) | 1);
- } else {
- put_le16(p + 85, (1 << 14) | 1);
- }
- /* 13=flush_cache_ext,12=flush_cache,10=lba48 */
- put_le16(p + 86, (1 << 13) | (1 <<12) | (1 << 10));
- /* 14=set to 1, 8=has WWN, 1=SMART self test, 0=SMART error logging */
- if (s->wwn) {
- put_le16(p + 87, (1 << 14) | (1 << 8) | 0);
- } else {
- put_le16(p + 87, (1 << 14) | 0);
- }
- put_le16(p + 88, 0x3f | (1 << 13)); /* udma5 set and supported */
- put_le16(p + 93, 1 | (1 << 14) | 0x2000);
- /* *(p + 100) := nb_sectors -- see ide_identify_size */
- /* *(p + 101) := nb_sectors >> 16 -- see ide_identify_size */
- /* *(p + 102) := nb_sectors >> 32 -- see ide_identify_size */
- /* *(p + 103) := nb_sectors >> 48 -- see ide_identify_size */
-
- if (dev && dev->conf.physical_block_size)
- put_le16(p + 106, 0x6000 | get_physical_block_exp(&dev->conf));
- if (s->wwn) {
- /* LE 16-bit words 111-108 contain 64-bit World Wide Name */
- put_le16(p + 108, s->wwn >> 48);
- put_le16(p + 109, s->wwn >> 32);
- put_le16(p + 110, s->wwn >> 16);
- put_le16(p + 111, s->wwn);
- }
- if (dev && dev->conf.discard_granularity) {
- put_le16(p + 169, 1); /* TRIM support */
- }
-
- ide_identify_size(s);
- s->identify_set = 1;
-
-fill_buffer:
- memcpy(s->io_buffer, p, sizeof(s->identify_data));
-}
-
-static void ide_atapi_identify(IDEState *s)
-{
- uint16_t *p;
-
- p = (uint16_t *)s->identify_data;
- if (s->identify_set) {
- goto fill_buffer;
- }
- memset(p, 0, sizeof(s->identify_data));
-
- /* Removable CDROM, 50us response, 12 byte packets */
- put_le16(p + 0, (2 << 14) | (5 << 8) | (1 << 7) | (2 << 5) | (0 << 0));
- padstr((char *)(p + 10), s->drive_serial_str, 20); /* serial number */
- put_le16(p + 20, 3); /* buffer type */
- put_le16(p + 21, 512); /* cache size in sectors */
- put_le16(p + 22, 4); /* ecc bytes */
- padstr((char *)(p + 23), s->version, 8); /* firmware version */
- padstr((char *)(p + 27), s->drive_model_str, 40); /* model */
- put_le16(p + 48, 1); /* dword I/O (XXX: should not be set on CDROM) */
-#ifdef USE_DMA_CDROM
- put_le16(p + 49, 1 << 9 | 1 << 8); /* DMA and LBA supported */
- put_le16(p + 53, 7); /* words 64-70, 54-58, 88 valid */
- put_le16(p + 62, 7); /* single word dma0-2 supported */
- put_le16(p + 63, 7); /* mdma0-2 supported */
-#else
- put_le16(p + 49, 1 << 9); /* LBA supported, no DMA */
- put_le16(p + 53, 3); /* words 64-70, 54-58 valid */
- put_le16(p + 63, 0x103); /* DMA modes XXX: may be incorrect */
-#endif
- put_le16(p + 64, 3); /* pio3-4 supported */
- put_le16(p + 65, 0xb4); /* minimum DMA multiword tx cycle time */
- put_le16(p + 66, 0xb4); /* recommended DMA multiword tx cycle time */
- put_le16(p + 67, 0x12c); /* minimum PIO cycle time without flow control */
- put_le16(p + 68, 0xb4); /* minimum PIO cycle time with IORDY flow control */
-
- put_le16(p + 71, 30); /* in ns */
- put_le16(p + 72, 30); /* in ns */
-
- if (s->ncq_queues) {
- put_le16(p + 75, s->ncq_queues - 1);
- /* NCQ supported */
- put_le16(p + 76, (1 << 8));
- }
-
- put_le16(p + 80, 0x1e); /* support up to ATA/ATAPI-4 */
- if (s->wwn) {
- put_le16(p + 84, (1 << 8)); /* supports WWN for words 108-111 */
- put_le16(p + 87, (1 << 8)); /* WWN enabled */
- }
-
-#ifdef USE_DMA_CDROM
- put_le16(p + 88, 0x3f | (1 << 13)); /* udma5 set and supported */
-#endif
-
- if (s->wwn) {
- /* LE 16-bit words 111-108 contain 64-bit World Wide Name */
- put_le16(p + 108, s->wwn >> 48);
- put_le16(p + 109, s->wwn >> 32);
- put_le16(p + 110, s->wwn >> 16);
- put_le16(p + 111, s->wwn);
- }
-
- s->identify_set = 1;
-
-fill_buffer:
- memcpy(s->io_buffer, p, sizeof(s->identify_data));
-}
-
-static void ide_cfata_identify_size(IDEState *s)
-{
- uint16_t *p = (uint16_t *)s->identify_data;
- put_le16(p + 7, s->nb_sectors >> 16); /* Sectors per card */
- put_le16(p + 8, s->nb_sectors); /* Sectors per card */
- put_le16(p + 60, s->nb_sectors); /* Total LBA sectors */
- put_le16(p + 61, s->nb_sectors >> 16); /* Total LBA sectors */
-}
-
-static void ide_cfata_identify(IDEState *s)
-{
- uint16_t *p;
- uint32_t cur_sec;
-
- p = (uint16_t *)s->identify_data;
- if (s->identify_set) {
- goto fill_buffer;
- }
- memset(p, 0, sizeof(s->identify_data));
-
- cur_sec = s->cylinders * s->heads * s->sectors;
-
- put_le16(p + 0, 0x848a); /* CF Storage Card signature */
- put_le16(p + 1, s->cylinders); /* Default cylinders */
- put_le16(p + 3, s->heads); /* Default heads */
- put_le16(p + 6, s->sectors); /* Default sectors per track */
- /* *(p + 7) := nb_sectors >> 16 -- see ide_cfata_identify_size */
- /* *(p + 8) := nb_sectors -- see ide_cfata_identify_size */
- padstr((char *)(p + 10), s->drive_serial_str, 20); /* serial number */
- put_le16(p + 22, 0x0004); /* ECC bytes */
- padstr((char *) (p + 23), s->version, 8); /* Firmware Revision */
- padstr((char *) (p + 27), s->drive_model_str, 40);/* Model number */
-#if MAX_MULT_SECTORS > 1
- put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS);
-#else
- put_le16(p + 47, 0x0000);
-#endif
- put_le16(p + 49, 0x0f00); /* Capabilities */
- put_le16(p + 51, 0x0002); /* PIO cycle timing mode */
- put_le16(p + 52, 0x0001); /* DMA cycle timing mode */
- put_le16(p + 53, 0x0003); /* Translation params valid */
- put_le16(p + 54, s->cylinders); /* Current cylinders */
- put_le16(p + 55, s->heads); /* Current heads */
- put_le16(p + 56, s->sectors); /* Current sectors */
- put_le16(p + 57, cur_sec); /* Current capacity */
- put_le16(p + 58, cur_sec >> 16); /* Current capacity */
- if (s->mult_sectors) /* Multiple sector setting */
- put_le16(p + 59, 0x100 | s->mult_sectors);
- /* *(p + 60) := nb_sectors -- see ide_cfata_identify_size */
- /* *(p + 61) := nb_sectors >> 16 -- see ide_cfata_identify_size */
- put_le16(p + 63, 0x0203); /* Multiword DMA capability */
- put_le16(p + 64, 0x0001); /* Flow Control PIO support */
- put_le16(p + 65, 0x0096); /* Min. Multiword DMA cycle */
- put_le16(p + 66, 0x0096); /* Rec. Multiword DMA cycle */
- put_le16(p + 68, 0x00b4); /* Min. PIO cycle time */
- put_le16(p + 82, 0x400c); /* Command Set supported */
- put_le16(p + 83, 0x7068); /* Command Set supported */
- put_le16(p + 84, 0x4000); /* Features supported */
- put_le16(p + 85, 0x000c); /* Command Set enabled */
- put_le16(p + 86, 0x7044); /* Command Set enabled */
- put_le16(p + 87, 0x4000); /* Features enabled */
- put_le16(p + 91, 0x4060); /* Current APM level */
- put_le16(p + 129, 0x0002); /* Current features option */
- put_le16(p + 130, 0x0005); /* Reassigned sectors */
- put_le16(p + 131, 0x0001); /* Initial power mode */
- put_le16(p + 132, 0x0000); /* User signature */
- put_le16(p + 160, 0x8100); /* Power requirement */
- put_le16(p + 161, 0x8001); /* CF command set */
-
- ide_cfata_identify_size(s);
- s->identify_set = 1;
-
-fill_buffer:
- memcpy(s->io_buffer, p, sizeof(s->identify_data));
-}
-
-static void ide_set_signature(IDEState *s)
-{
- s->select &= 0xf0; /* clear head */
- /* put signature */
- s->nsector = 1;
- s->sector = 1;
- if (s->drive_kind == IDE_CD) {
- s->lcyl = 0x14;
- s->hcyl = 0xeb;
- } else if (s->blk) {
- s->lcyl = 0;
- s->hcyl = 0;
- } else {
- s->lcyl = 0xff;
- s->hcyl = 0xff;
- }
-}
-
-typedef struct TrimAIOCB {
- BlockAIOCB common;
- BlockBackend *blk;
- QEMUBH *bh;
- int ret;
- QEMUIOVector *qiov;
- BlockAIOCB *aiocb;
- int i, j;
-} TrimAIOCB;
-
-static void trim_aio_cancel(BlockAIOCB *acb)
-{
- TrimAIOCB *iocb = container_of(acb, TrimAIOCB, common);
-
- /* Exit the loop so ide_issue_trim_cb will not continue */
- iocb->j = iocb->qiov->niov - 1;
- iocb->i = (iocb->qiov->iov[iocb->j].iov_len / 8) - 1;
-
- iocb->ret = -ECANCELED;
-
- if (iocb->aiocb) {
- blk_aio_cancel_async(iocb->aiocb);
- iocb->aiocb = NULL;
- }
-}
-
-static const AIOCBInfo trim_aiocb_info = {
- .aiocb_size = sizeof(TrimAIOCB),
- .cancel_async = trim_aio_cancel,
-};
-
-static void ide_trim_bh_cb(void *opaque)
-{
- TrimAIOCB *iocb = opaque;
-
- iocb->common.cb(iocb->common.opaque, iocb->ret);
-
- qemu_bh_delete(iocb->bh);
- iocb->bh = NULL;
- qemu_aio_unref(iocb);
-}
-
-static void ide_issue_trim_cb(void *opaque, int ret)
-{
- TrimAIOCB *iocb = opaque;
- if (ret >= 0) {
- while (iocb->j < iocb->qiov->niov) {
- int j = iocb->j;
- while (++iocb->i < iocb->qiov->iov[j].iov_len / 8) {
- int i = iocb->i;
- uint64_t *buffer = iocb->qiov->iov[j].iov_base;
-
- /* 6-byte LBA + 2-byte range per entry */
- uint64_t entry = le64_to_cpu(buffer[i]);
- uint64_t sector = entry & 0x0000ffffffffffffULL;
- uint16_t count = entry >> 48;
-
- if (count == 0) {
- continue;
- }
-
- /* Got an entry! Submit and exit. */
- iocb->aiocb = blk_aio_discard(iocb->blk, sector, count,
- ide_issue_trim_cb, opaque);
- return;
- }
-
- iocb->j++;
- iocb->i = -1;
- }
- } else {
- iocb->ret = ret;
- }
-
- iocb->aiocb = NULL;
- if (iocb->bh) {
- qemu_bh_schedule(iocb->bh);
- }
-}
-
-BlockAIOCB *ide_issue_trim(BlockBackend *blk,
- int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
- BlockCompletionFunc *cb, void *opaque)
-{
- TrimAIOCB *iocb;
-
- iocb = blk_aio_get(&trim_aiocb_info, blk, cb, opaque);
- iocb->blk = blk;
- iocb->bh = qemu_bh_new(ide_trim_bh_cb, iocb);
- iocb->ret = 0;
- iocb->qiov = qiov;
- iocb->i = -1;
- iocb->j = 0;
- ide_issue_trim_cb(iocb, 0);
- return &iocb->common;
-}
-
-void ide_abort_command(IDEState *s)
-{
- ide_transfer_stop(s);
- s->status = READY_STAT | ERR_STAT;
- s->error = ABRT_ERR;
-}
-
-/* prepare data transfer and tell what to do after */
-void ide_transfer_start(IDEState *s, uint8_t *buf, int size,
- EndTransferFunc *end_transfer_func)
-{
- s->end_transfer_func = end_transfer_func;
- s->data_ptr = buf;
- s->data_end = buf + size;
- if (!(s->status & ERR_STAT)) {
- s->status |= DRQ_STAT;
- }
- if (s->bus->dma->ops->start_transfer) {
- s->bus->dma->ops->start_transfer(s->bus->dma);
- }
-}
-
-static void ide_cmd_done(IDEState *s)
-{
- if (s->bus->dma->ops->cmd_done) {
- s->bus->dma->ops->cmd_done(s->bus->dma);
- }
-}
-
-static void ide_transfer_halt(IDEState *s,
- void(*end_transfer_func)(IDEState *),
- bool notify)
-{
- s->end_transfer_func = end_transfer_func;
- s->data_ptr = s->io_buffer;
- s->data_end = s->io_buffer;
- s->status &= ~DRQ_STAT;
- if (notify) {
- ide_cmd_done(s);
- }
-}
-
-void ide_transfer_stop(IDEState *s)
-{
- ide_transfer_halt(s, ide_transfer_stop, true);
-}
-
-static void ide_transfer_cancel(IDEState *s)
-{
- ide_transfer_halt(s, ide_transfer_cancel, false);
-}
-
-int64_t ide_get_sector(IDEState *s)
-{
- int64_t sector_num;
- if (s->select & 0x40) {
- /* lba */
- if (!s->lba48) {
- sector_num = ((s->select & 0x0f) << 24) | (s->hcyl << 16) |
- (s->lcyl << 8) | s->sector;
- } else {
- sector_num = ((int64_t)s->hob_hcyl << 40) |
- ((int64_t) s->hob_lcyl << 32) |
- ((int64_t) s->hob_sector << 24) |
- ((int64_t) s->hcyl << 16) |
- ((int64_t) s->lcyl << 8) | s->sector;
- }
- } else {
- sector_num = ((s->hcyl << 8) | s->lcyl) * s->heads * s->sectors +
- (s->select & 0x0f) * s->sectors + (s->sector - 1);
- }
- return sector_num;
-}
-
-void ide_set_sector(IDEState *s, int64_t sector_num)
-{
- unsigned int cyl, r;
- if (s->select & 0x40) {
- if (!s->lba48) {
- s->select = (s->select & 0xf0) | (sector_num >> 24);
- s->hcyl = (sector_num >> 16);
- s->lcyl = (sector_num >> 8);
- s->sector = (sector_num);
- } else {
- s->sector = sector_num;
- s->lcyl = sector_num >> 8;
- s->hcyl = sector_num >> 16;
- s->hob_sector = sector_num >> 24;
- s->hob_lcyl = sector_num >> 32;
- s->hob_hcyl = sector_num >> 40;
- }
- } else {
- cyl = sector_num / (s->heads * s->sectors);
- r = sector_num % (s->heads * s->sectors);
- s->hcyl = cyl >> 8;
- s->lcyl = cyl;
- s->select = (s->select & 0xf0) | ((r / s->sectors) & 0x0f);
- s->sector = (r % s->sectors) + 1;
- }
-}
-
-static void ide_rw_error(IDEState *s) {
- ide_abort_command(s);
- ide_set_irq(s->bus);
-}
-
-static bool ide_sect_range_ok(IDEState *s,
- uint64_t sector, uint64_t nb_sectors)
-{
- uint64_t total_sectors;
-
- blk_get_geometry(s->blk, &total_sectors);
- if (sector > total_sectors || nb_sectors > total_sectors - sector) {
- return false;
- }
- return true;
-}
-
-static void ide_buffered_readv_cb(void *opaque, int ret)
-{
- IDEBufferedRequest *req = opaque;
- if (!req->orphaned) {
- if (!ret) {
- qemu_iovec_from_buf(req->original_qiov, 0, req->iov.iov_base,
- req->original_qiov->size);
- }
- req->original_cb(req->original_opaque, ret);
- }
- QLIST_REMOVE(req, list);
- qemu_vfree(req->iov.iov_base);
- g_free(req);
-}
-
-#define MAX_BUFFERED_REQS 16
-
-BlockAIOCB *ide_buffered_readv(IDEState *s, int64_t sector_num,
- QEMUIOVector *iov, int nb_sectors,
- BlockCompletionFunc *cb, void *opaque)
-{
- BlockAIOCB *aioreq;
- IDEBufferedRequest *req;
- int c = 0;
-
- QLIST_FOREACH(req, &s->buffered_requests, list) {
- c++;
- }
- if (c > MAX_BUFFERED_REQS) {
- return blk_abort_aio_request(s->blk, cb, opaque, -EIO);
- }
-
- req = g_new0(IDEBufferedRequest, 1);
- req->original_qiov = iov;
- req->original_cb = cb;
- req->original_opaque = opaque;
- req->iov.iov_base = qemu_blockalign(blk_bs(s->blk), iov->size);
- req->iov.iov_len = iov->size;
- qemu_iovec_init_external(&req->qiov, &req->iov, 1);
-
- aioreq = blk_aio_readv(s->blk, sector_num, &req->qiov, nb_sectors,
- ide_buffered_readv_cb, req);
-
- QLIST_INSERT_HEAD(&s->buffered_requests, req, list);
- return aioreq;
-}
-
-/**
- * Cancel all pending DMA requests.
- * Any buffered DMA requests are instantly canceled,
- * but any pending unbuffered DMA requests must be waited on.
- */
-void ide_cancel_dma_sync(IDEState *s)
-{
- IDEBufferedRequest *req;
-
- /* First invoke the callbacks of all buffered requests
- * and flag those requests as orphaned. Ideally there
- * are no unbuffered (Scatter Gather DMA Requests or
- * write requests) pending and we can avoid to drain. */
- QLIST_FOREACH(req, &s->buffered_requests, list) {
- if (!req->orphaned) {
-#ifdef DEBUG_IDE
- printf("%s: invoking cb %p of buffered request %p with"
- " -ECANCELED\n", __func__, req->original_cb, req);
-#endif
- req->original_cb(req->original_opaque, -ECANCELED);
- }
- req->orphaned = true;
- }
-
- /*
- * We can't cancel Scatter Gather DMA in the middle of the
- * operation or a partial (not full) DMA transfer would reach
- * the storage so we wait for completion instead (we beahve
- * like if the DMA was completed by the time the guest trying
- * to cancel dma with bmdma_cmd_writeb with BM_CMD_START not
- * set).
- *
- * In the future we'll be able to safely cancel the I/O if the
- * whole DMA operation will be submitted to disk with a single
- * aio operation with preadv/pwritev.
- */
- if (s->bus->dma->aiocb) {
-#ifdef DEBUG_IDE
- printf("%s: draining all remaining requests", __func__);
-#endif
- blk_drain(s->blk);
- assert(s->bus->dma->aiocb == NULL);
- }
-}
-
-static void ide_sector_read(IDEState *s);
-
-static void ide_sector_read_cb(void *opaque, int ret)
-{
- IDEState *s = opaque;
- int n;
-
- s->pio_aiocb = NULL;
- s->status &= ~BUSY_STAT;
-
- if (ret == -ECANCELED) {
- return;
- }
- if (ret != 0) {
- if (ide_handle_rw_error(s, -ret, IDE_RETRY_PIO |
- IDE_RETRY_READ)) {
- return;
- }
- }
-
- block_acct_done(blk_get_stats(s->blk), &s->acct);
-
- n = s->nsector;
- if (n > s->req_nb_sectors) {
- n = s->req_nb_sectors;
- }
-
- ide_set_sector(s, ide_get_sector(s) + n);
- s->nsector -= n;
- /* Allow the guest to read the io_buffer */
- ide_transfer_start(s, s->io_buffer, n * BDRV_SECTOR_SIZE, ide_sector_read);
- ide_set_irq(s->bus);
-}
-
-static void ide_sector_read(IDEState *s)
-{
- int64_t sector_num;
- int n;
-
- s->status = READY_STAT | SEEK_STAT;
- s->error = 0; /* not needed by IDE spec, but needed by Windows */
- sector_num = ide_get_sector(s);
- n = s->nsector;
-
- if (n == 0) {
- ide_transfer_stop(s);
- return;
- }
-
- s->status |= BUSY_STAT;
-
- if (n > s->req_nb_sectors) {
- n = s->req_nb_sectors;
- }
-
-#if defined(DEBUG_IDE)
- printf("sector=%" PRId64 "\n", sector_num);
-#endif
-
- if (!ide_sect_range_ok(s, sector_num, n)) {
- ide_rw_error(s);
- block_acct_invalid(blk_get_stats(s->blk), BLOCK_ACCT_READ);
- return;
- }
-
- s->iov.iov_base = s->io_buffer;
- s->iov.iov_len = n * BDRV_SECTOR_SIZE;
- qemu_iovec_init_external(&s->qiov, &s->iov, 1);
-
- block_acct_start(blk_get_stats(s->blk), &s->acct,
- n * BDRV_SECTOR_SIZE, BLOCK_ACCT_READ);
- s->pio_aiocb = ide_buffered_readv(s, sector_num, &s->qiov, n,
- ide_sector_read_cb, s);
-}
-
-void dma_buf_commit(IDEState *s, uint32_t tx_bytes)
-{
- if (s->bus->dma->ops->commit_buf) {
- s->bus->dma->ops->commit_buf(s->bus->dma, tx_bytes);
- }
- s->io_buffer_offset += tx_bytes;
- qemu_sglist_destroy(&s->sg);
-}
-
-void ide_set_inactive(IDEState *s, bool more)
-{
- s->bus->dma->aiocb = NULL;
- s->bus->retry_unit = -1;
- s->bus->retry_sector_num = 0;
- s->bus->retry_nsector = 0;
- if (s->bus->dma->ops->set_inactive) {
- s->bus->dma->ops->set_inactive(s->bus->dma, more);
- }
- ide_cmd_done(s);
-}
-
-void ide_dma_error(IDEState *s)
-{
- dma_buf_commit(s, 0);
- ide_abort_command(s);
- ide_set_inactive(s, false);
- ide_set_irq(s->bus);
-}
-
-int ide_handle_rw_error(IDEState *s, int error, int op)
-{
- bool is_read = (op & IDE_RETRY_READ) != 0;
- BlockErrorAction action = blk_get_error_action(s->blk, is_read, error);
-
- if (action == BLOCK_ERROR_ACTION_STOP) {
- assert(s->bus->retry_unit == s->unit);
- s->bus->error_status = op;
- } else if (action == BLOCK_ERROR_ACTION_REPORT) {
- block_acct_failed(blk_get_stats(s->blk), &s->acct);
- if (IS_IDE_RETRY_DMA(op)) {
- ide_dma_error(s);
- } else if (IS_IDE_RETRY_ATAPI(op)) {
- ide_atapi_io_error(s, -error);
- } else {
- ide_rw_error(s);
- }
- }
- blk_error_action(s->blk, action, is_read, error);
- return action != BLOCK_ERROR_ACTION_IGNORE;
-}
-
-static void ide_dma_cb(void *opaque, int ret)
-{
- IDEState *s = opaque;
- int n;
- int64_t sector_num;
- bool stay_active = false;
-
- if (ret == -ECANCELED) {
- return;
- }
- if (ret < 0) {
- if (ide_handle_rw_error(s, -ret, ide_dma_cmd_to_retry(s->dma_cmd))) {
- return;
- }
- }
-
- n = s->io_buffer_size >> 9;
- if (n > s->nsector) {
- /* The PRDs were longer than needed for this request. Shorten them so
- * we don't get a negative remainder. The Active bit must remain set
- * after the request completes. */
- n = s->nsector;
- stay_active = true;
- }
-
- sector_num = ide_get_sector(s);
- if (n > 0) {
- assert(n * 512 == s->sg.size);
- dma_buf_commit(s, s->sg.size);
- sector_num += n;
- ide_set_sector(s, sector_num);
- s->nsector -= n;
- }
-
- /* end of transfer ? */
- if (s->nsector == 0) {
- s->status = READY_STAT | SEEK_STAT;
- ide_set_irq(s->bus);
- goto eot;
- }
-
- /* launch next transfer */
- n = s->nsector;
- s->io_buffer_index = 0;
- s->io_buffer_size = n * 512;
- if (s->bus->dma->ops->prepare_buf(s->bus->dma, s->io_buffer_size) < 512) {
- /* The PRDs were too short. Reset the Active bit, but don't raise an
- * interrupt. */
- s->status = READY_STAT | SEEK_STAT;
- dma_buf_commit(s, 0);
- goto eot;
- }
-
-#ifdef DEBUG_AIO
- printf("ide_dma_cb: sector_num=%" PRId64 " n=%d, cmd_cmd=%d\n",
- sector_num, n, s->dma_cmd);
-#endif
-
- if ((s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) &&
- !ide_sect_range_ok(s, sector_num, n)) {
- ide_dma_error(s);
- block_acct_invalid(blk_get_stats(s->blk), s->acct.type);
- return;
- }
-
- switch (s->dma_cmd) {
- case IDE_DMA_READ:
- s->bus->dma->aiocb = dma_blk_read(s->blk, &s->sg, sector_num,
- ide_dma_cb, s);
- break;
- case IDE_DMA_WRITE:
- s->bus->dma->aiocb = dma_blk_write(s->blk, &s->sg, sector_num,
- ide_dma_cb, s);
- break;
- case IDE_DMA_TRIM:
- s->bus->dma->aiocb = dma_blk_io(s->blk, &s->sg, sector_num,
- ide_issue_trim, ide_dma_cb, s,
- DMA_DIRECTION_TO_DEVICE);
- break;
- default:
- abort();
- }
- return;
-
-eot:
- if (s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) {
- block_acct_done(blk_get_stats(s->blk), &s->acct);
- }
- ide_set_inactive(s, stay_active);
-}
-
-static void ide_sector_start_dma(IDEState *s, enum ide_dma_cmd dma_cmd)
-{
- s->status = READY_STAT | SEEK_STAT | DRQ_STAT | BUSY_STAT;
- s->io_buffer_size = 0;
- s->dma_cmd = dma_cmd;
-
- switch (dma_cmd) {
- case IDE_DMA_READ:
- block_acct_start(blk_get_stats(s->blk), &s->acct,
- s->nsector * BDRV_SECTOR_SIZE, BLOCK_ACCT_READ);
- break;
- case IDE_DMA_WRITE:
- block_acct_start(blk_get_stats(s->blk), &s->acct,
- s->nsector * BDRV_SECTOR_SIZE, BLOCK_ACCT_WRITE);
- break;
- default:
- break;
- }
-
- ide_start_dma(s, ide_dma_cb);
-}
-
-void ide_start_dma(IDEState *s, BlockCompletionFunc *cb)
-{
- s->io_buffer_index = 0;
- s->bus->retry_unit = s->unit;
- s->bus->retry_sector_num = ide_get_sector(s);
- s->bus->retry_nsector = s->nsector;
- if (s->bus->dma->ops->start_dma) {
- s->bus->dma->ops->start_dma(s->bus->dma, s, cb);
- }
-}
-
-static void ide_sector_write(IDEState *s);
-
-static void ide_sector_write_timer_cb(void *opaque)
-{
- IDEState *s = opaque;
- ide_set_irq(s->bus);
-}
-
-static void ide_sector_write_cb(void *opaque, int ret)
-{
- IDEState *s = opaque;
- int n;
-
- if (ret == -ECANCELED) {
- return;
- }
-
- s->pio_aiocb = NULL;
- s->status &= ~BUSY_STAT;
-
- if (ret != 0) {
- if (ide_handle_rw_error(s, -ret, IDE_RETRY_PIO)) {
- return;
- }
- }
-
- block_acct_done(blk_get_stats(s->blk), &s->acct);
-
- n = s->nsector;
- if (n > s->req_nb_sectors) {
- n = s->req_nb_sectors;
- }
- s->nsector -= n;
-
- ide_set_sector(s, ide_get_sector(s) + n);
- if (s->nsector == 0) {
- /* no more sectors to write */
- ide_transfer_stop(s);
- } else {
- int n1 = s->nsector;
- if (n1 > s->req_nb_sectors) {
- n1 = s->req_nb_sectors;
- }
- ide_transfer_start(s, s->io_buffer, n1 * BDRV_SECTOR_SIZE,
- ide_sector_write);
- }
-
- if (win2k_install_hack && ((++s->irq_count % 16) == 0)) {
- /* It seems there is a bug in the Windows 2000 installer HDD
- IDE driver which fills the disk with empty logs when the
- IDE write IRQ comes too early. This hack tries to correct
- that at the expense of slower write performances. Use this
- option _only_ to install Windows 2000. You must disable it
- for normal use. */
- timer_mod(s->sector_write_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- (NANOSECONDS_PER_SECOND / 1000));
- } else {
- ide_set_irq(s->bus);
- }
-}
-
-static void ide_sector_write(IDEState *s)
-{
- int64_t sector_num;
- int n;
-
- s->status = READY_STAT | SEEK_STAT | BUSY_STAT;
- sector_num = ide_get_sector(s);
-#if defined(DEBUG_IDE)
- printf("sector=%" PRId64 "\n", sector_num);
-#endif
- n = s->nsector;
- if (n > s->req_nb_sectors) {
- n = s->req_nb_sectors;
- }
-
- if (!ide_sect_range_ok(s, sector_num, n)) {
- ide_rw_error(s);
- block_acct_invalid(blk_get_stats(s->blk), BLOCK_ACCT_WRITE);
- return;
- }
-
- s->iov.iov_base = s->io_buffer;
- s->iov.iov_len = n * BDRV_SECTOR_SIZE;
- qemu_iovec_init_external(&s->qiov, &s->iov, 1);
-
- block_acct_start(blk_get_stats(s->blk), &s->acct,
- n * BDRV_SECTOR_SIZE, BLOCK_ACCT_WRITE);
- s->pio_aiocb = blk_aio_writev(s->blk, sector_num, &s->qiov, n,
- ide_sector_write_cb, s);
-}
-
-static void ide_flush_cb(void *opaque, int ret)
-{
- IDEState *s = opaque;
-
- s->pio_aiocb = NULL;
-
- if (ret == -ECANCELED) {
- return;
- }
- if (ret < 0) {
- /* XXX: What sector number to set here? */
- if (ide_handle_rw_error(s, -ret, IDE_RETRY_FLUSH)) {
- return;
- }
- }
-
- if (s->blk) {
- block_acct_done(blk_get_stats(s->blk), &s->acct);
- }
- s->status = READY_STAT | SEEK_STAT;
- ide_cmd_done(s);
- ide_set_irq(s->bus);
-}
-
-static void ide_flush_cache(IDEState *s)
-{
- if (s->blk == NULL) {
- ide_flush_cb(s, 0);
- return;
- }
-
- s->status |= BUSY_STAT;
- block_acct_start(blk_get_stats(s->blk), &s->acct, 0, BLOCK_ACCT_FLUSH);
- s->pio_aiocb = blk_aio_flush(s->blk, ide_flush_cb, s);
-}
-
-static void ide_cfata_metadata_inquiry(IDEState *s)
-{
- uint16_t *p;
- uint32_t spd;
-
- p = (uint16_t *) s->io_buffer;
- memset(p, 0, 0x200);
- spd = ((s->mdata_size - 1) >> 9) + 1;
-
- put_le16(p + 0, 0x0001); /* Data format revision */
- put_le16(p + 1, 0x0000); /* Media property: silicon */
- put_le16(p + 2, s->media_changed); /* Media status */
- put_le16(p + 3, s->mdata_size & 0xffff); /* Capacity in bytes (low) */
- put_le16(p + 4, s->mdata_size >> 16); /* Capacity in bytes (high) */
- put_le16(p + 5, spd & 0xffff); /* Sectors per device (low) */
- put_le16(p + 6, spd >> 16); /* Sectors per device (high) */
-}
-
-static void ide_cfata_metadata_read(IDEState *s)
-{
- uint16_t *p;
-
- if (((s->hcyl << 16) | s->lcyl) << 9 > s->mdata_size + 2) {
- s->status = ERR_STAT;
- s->error = ABRT_ERR;
- return;
- }
-
- p = (uint16_t *) s->io_buffer;
- memset(p, 0, 0x200);
-
- put_le16(p + 0, s->media_changed); /* Media status */
- memcpy(p + 1, s->mdata_storage + (((s->hcyl << 16) | s->lcyl) << 9),
- MIN(MIN(s->mdata_size - (((s->hcyl << 16) | s->lcyl) << 9),
- s->nsector << 9), 0x200 - 2));
-}
-
-static void ide_cfata_metadata_write(IDEState *s)
-{
- if (((s->hcyl << 16) | s->lcyl) << 9 > s->mdata_size + 2) {
- s->status = ERR_STAT;
- s->error = ABRT_ERR;
- return;
- }
-
- s->media_changed = 0;
-
- memcpy(s->mdata_storage + (((s->hcyl << 16) | s->lcyl) << 9),
- s->io_buffer + 2,
- MIN(MIN(s->mdata_size - (((s->hcyl << 16) | s->lcyl) << 9),
- s->nsector << 9), 0x200 - 2));
-}
-
-/* called when the inserted state of the media has changed */
-static void ide_cd_change_cb(void *opaque, bool load)
-{
- IDEState *s = opaque;
- uint64_t nb_sectors;
-
- s->tray_open = !load;
- blk_get_geometry(s->blk, &nb_sectors);
- s->nb_sectors = nb_sectors;
-
- /*
- * First indicate to the guest that a CD has been removed. That's
- * done on the next command the guest sends us.
- *
- * Then we set UNIT_ATTENTION, by which the guest will
- * detect a new CD in the drive. See ide_atapi_cmd() for details.
- */
- s->cdrom_changed = 1;
- s->events.new_media = true;
- s->events.eject_request = false;
- ide_set_irq(s->bus);
-}
-
-static void ide_cd_eject_request_cb(void *opaque, bool force)
-{
- IDEState *s = opaque;
-
- s->events.eject_request = true;
- if (force) {
- s->tray_locked = false;
- }
- ide_set_irq(s->bus);
-}
-
-static void ide_cmd_lba48_transform(IDEState *s, int lba48)
-{
- s->lba48 = lba48;
-
- /* handle the 'magic' 0 nsector count conversion here. to avoid
- * fiddling with the rest of the read logic, we just store the
- * full sector count in ->nsector and ignore ->hob_nsector from now
- */
- if (!s->lba48) {
- if (!s->nsector)
- s->nsector = 256;
- } else {
- if (!s->nsector && !s->hob_nsector)
- s->nsector = 65536;
- else {
- int lo = s->nsector;
- int hi = s->hob_nsector;
-
- s->nsector = (hi << 8) | lo;
- }
- }
-}
-
-static void ide_clear_hob(IDEBus *bus)
-{
- /* any write clears HOB high bit of device control register */
- bus->ifs[0].select &= ~(1 << 7);
- bus->ifs[1].select &= ~(1 << 7);
-}
-
-void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
-{
- IDEBus *bus = opaque;
-
-#ifdef DEBUG_IDE
- printf("IDE: write addr=0x%x val=0x%02x\n", addr, val);
-#endif
-
- addr &= 7;
-
- /* ignore writes to command block while busy with previous command */
- if (addr != 7 && (idebus_active_if(bus)->status & (BUSY_STAT|DRQ_STAT)))
- return;
-
- switch(addr) {
- case 0:
- break;
- case 1:
- ide_clear_hob(bus);
- /* NOTE: data is written to the two drives */
- bus->ifs[0].hob_feature = bus->ifs[0].feature;
- bus->ifs[1].hob_feature = bus->ifs[1].feature;
- bus->ifs[0].feature = val;
- bus->ifs[1].feature = val;
- break;
- case 2:
- ide_clear_hob(bus);
- bus->ifs[0].hob_nsector = bus->ifs[0].nsector;
- bus->ifs[1].hob_nsector = bus->ifs[1].nsector;
- bus->ifs[0].nsector = val;
- bus->ifs[1].nsector = val;
- break;
- case 3:
- ide_clear_hob(bus);
- bus->ifs[0].hob_sector = bus->ifs[0].sector;
- bus->ifs[1].hob_sector = bus->ifs[1].sector;
- bus->ifs[0].sector = val;
- bus->ifs[1].sector = val;
- break;
- case 4:
- ide_clear_hob(bus);
- bus->ifs[0].hob_lcyl = bus->ifs[0].lcyl;
- bus->ifs[1].hob_lcyl = bus->ifs[1].lcyl;
- bus->ifs[0].lcyl = val;
- bus->ifs[1].lcyl = val;
- break;
- case 5:
- ide_clear_hob(bus);
- bus->ifs[0].hob_hcyl = bus->ifs[0].hcyl;
- bus->ifs[1].hob_hcyl = bus->ifs[1].hcyl;
- bus->ifs[0].hcyl = val;
- bus->ifs[1].hcyl = val;
- break;
- case 6:
- /* FIXME: HOB readback uses bit 7 */
- bus->ifs[0].select = (val & ~0x10) | 0xa0;
- bus->ifs[1].select = (val | 0x10) | 0xa0;
- /* select drive */
- bus->unit = (val >> 4) & 1;
- break;
- default:
- case 7:
- /* command */
- ide_exec_cmd(bus, val);
- break;
- }
-}
-
-static void ide_reset(IDEState *s)
-{
-#ifdef DEBUG_IDE
- printf("ide: reset\n");
-#endif
-
- if (s->pio_aiocb) {
- blk_aio_cancel(s->pio_aiocb);
- s->pio_aiocb = NULL;
- }
-
- if (s->drive_kind == IDE_CFATA)
- s->mult_sectors = 0;
- else
- s->mult_sectors = MAX_MULT_SECTORS;
- /* ide regs */
- s->feature = 0;
- s->error = 0;
- s->nsector = 0;
- s->sector = 0;
- s->lcyl = 0;
- s->hcyl = 0;
-
- /* lba48 */
- s->hob_feature = 0;
- s->hob_sector = 0;
- s->hob_nsector = 0;
- s->hob_lcyl = 0;
- s->hob_hcyl = 0;
-
- s->select = 0xa0;
- s->status = READY_STAT | SEEK_STAT;
-
- s->lba48 = 0;
-
- /* ATAPI specific */
- s->sense_key = 0;
- s->asc = 0;
- s->cdrom_changed = 0;
- s->packet_transfer_size = 0;
- s->elementary_transfer_size = 0;
- s->io_buffer_index = 0;
- s->cd_sector_size = 0;
- s->atapi_dma = 0;
- s->tray_locked = 0;
- s->tray_open = 0;
- /* ATA DMA state */
- s->io_buffer_size = 0;
- s->req_nb_sectors = 0;
-
- ide_set_signature(s);
- /* init the transfer handler so that 0xffff is returned on data
- accesses */
- s->end_transfer_func = ide_dummy_transfer_stop;
- ide_dummy_transfer_stop(s);
- s->media_changed = 0;
-}
-
-static bool cmd_nop(IDEState *s, uint8_t cmd)
-{
- return true;
-}
-
-static bool cmd_device_reset(IDEState *s, uint8_t cmd)
-{
- /* Halt PIO (in the DRQ phase), then DMA */
- ide_transfer_cancel(s);
- ide_cancel_dma_sync(s);
-
- /* Reset any PIO commands, reset signature, etc */
- ide_reset(s);
-
- /* RESET: ATA8-ACS3 7.10.4 "Normal Outputs";
- * ATA8-ACS3 Table 184 "Device Signatures for Normal Output" */
- s->status = 0x00;
-
- /* Do not overwrite status register */
- return false;
-}
-
-static bool cmd_data_set_management(IDEState *s, uint8_t cmd)
-{
- switch (s->feature) {
- case DSM_TRIM:
- if (s->blk) {
- ide_sector_start_dma(s, IDE_DMA_TRIM);
- return false;
- }
- break;
- }
-
- ide_abort_command(s);
- return true;
-}
-
-static bool cmd_identify(IDEState *s, uint8_t cmd)
-{
- if (s->blk && s->drive_kind != IDE_CD) {
- if (s->drive_kind != IDE_CFATA) {
- ide_identify(s);
- } else {
- ide_cfata_identify(s);
- }
- s->status = READY_STAT | SEEK_STAT;
- ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop);
- ide_set_irq(s->bus);
- return false;
- } else {
- if (s->drive_kind == IDE_CD) {
- ide_set_signature(s);
- }
- ide_abort_command(s);
- }
-
- return true;
-}
-
-static bool cmd_verify(IDEState *s, uint8_t cmd)
-{
- bool lba48 = (cmd == WIN_VERIFY_EXT);
-
- /* do sector number check ? */
- ide_cmd_lba48_transform(s, lba48);
-
- return true;
-}
-
-static bool cmd_set_multiple_mode(IDEState *s, uint8_t cmd)
-{
- if (s->drive_kind == IDE_CFATA && s->nsector == 0) {
- /* Disable Read and Write Multiple */
- s->mult_sectors = 0;
- } else if ((s->nsector & 0xff) != 0 &&
- ((s->nsector & 0xff) > MAX_MULT_SECTORS ||
- (s->nsector & (s->nsector - 1)) != 0)) {
- ide_abort_command(s);
- } else {
- s->mult_sectors = s->nsector & 0xff;
- }
-
- return true;
-}
-
-static bool cmd_read_multiple(IDEState *s, uint8_t cmd)
-{
- bool lba48 = (cmd == WIN_MULTREAD_EXT);
-
- if (!s->blk || !s->mult_sectors) {
- ide_abort_command(s);
- return true;
- }
-
- ide_cmd_lba48_transform(s, lba48);
- s->req_nb_sectors = s->mult_sectors;
- ide_sector_read(s);
- return false;
-}
-
-static bool cmd_write_multiple(IDEState *s, uint8_t cmd)
-{
- bool lba48 = (cmd == WIN_MULTWRITE_EXT);
- int n;
-
- if (!s->blk || !s->mult_sectors) {
- ide_abort_command(s);
- return true;
- }
-
- ide_cmd_lba48_transform(s, lba48);
-
- s->req_nb_sectors = s->mult_sectors;
- n = MIN(s->nsector, s->req_nb_sectors);
-
- s->status = SEEK_STAT | READY_STAT;
- ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_write);
-
- s->media_changed = 1;
-
- return false;
-}
-
-static bool cmd_read_pio(IDEState *s, uint8_t cmd)
-{
- bool lba48 = (cmd == WIN_READ_EXT);
-
- if (s->drive_kind == IDE_CD) {
- ide_set_signature(s); /* odd, but ATA4 8.27.5.2 requires it */
- ide_abort_command(s);
- return true;
- }
-
- if (!s->blk) {
- ide_abort_command(s);
- return true;
- }
-
- ide_cmd_lba48_transform(s, lba48);
- s->req_nb_sectors = 1;
- ide_sector_read(s);
-
- return false;
-}
-
-static bool cmd_write_pio(IDEState *s, uint8_t cmd)
-{
- bool lba48 = (cmd == WIN_WRITE_EXT);
-
- if (!s->blk) {
- ide_abort_command(s);
- return true;
- }
-
- ide_cmd_lba48_transform(s, lba48);
-
- s->req_nb_sectors = 1;
- s->status = SEEK_STAT | READY_STAT;
- ide_transfer_start(s, s->io_buffer, 512, ide_sector_write);
-
- s->media_changed = 1;
-
- return false;
-}
-
-static bool cmd_read_dma(IDEState *s, uint8_t cmd)
-{
- bool lba48 = (cmd == WIN_READDMA_EXT);
-
- if (!s->blk) {
- ide_abort_command(s);
- return true;
- }
-
- ide_cmd_lba48_transform(s, lba48);
- ide_sector_start_dma(s, IDE_DMA_READ);
-
- return false;
-}
-
-static bool cmd_write_dma(IDEState *s, uint8_t cmd)
-{
- bool lba48 = (cmd == WIN_WRITEDMA_EXT);
-
- if (!s->blk) {
- ide_abort_command(s);
- return true;
- }
-
- ide_cmd_lba48_transform(s, lba48);
- ide_sector_start_dma(s, IDE_DMA_WRITE);
-
- s->media_changed = 1;
-
- return false;
-}
-
-static bool cmd_flush_cache(IDEState *s, uint8_t cmd)
-{
- ide_flush_cache(s);
- return false;
-}
-
-static bool cmd_seek(IDEState *s, uint8_t cmd)
-{
- /* XXX: Check that seek is within bounds */
- return true;
-}
-
-static bool cmd_read_native_max(IDEState *s, uint8_t cmd)
-{
- bool lba48 = (cmd == WIN_READ_NATIVE_MAX_EXT);
-
- /* Refuse if no sectors are addressable (e.g. medium not inserted) */
- if (s->nb_sectors == 0) {
- ide_abort_command(s);
- return true;
- }
-
- ide_cmd_lba48_transform(s, lba48);
- ide_set_sector(s, s->nb_sectors - 1);
-
- return true;
-}
-
-static bool cmd_check_power_mode(IDEState *s, uint8_t cmd)
-{
- s->nsector = 0xff; /* device active or idle */
- return true;
-}
-
-static bool cmd_set_features(IDEState *s, uint8_t cmd)
-{
- uint16_t *identify_data;
-
- if (!s->blk) {
- ide_abort_command(s);
- return true;
- }
-
- /* XXX: valid for CDROM ? */
- switch (s->feature) {
- case 0x02: /* write cache enable */
- blk_set_enable_write_cache(s->blk, true);
- identify_data = (uint16_t *)s->identify_data;
- put_le16(identify_data + 85, (1 << 14) | (1 << 5) | 1);
- return true;
- case 0x82: /* write cache disable */
- blk_set_enable_write_cache(s->blk, false);
- identify_data = (uint16_t *)s->identify_data;
- put_le16(identify_data + 85, (1 << 14) | 1);
- ide_flush_cache(s);
- return false;
- case 0xcc: /* reverting to power-on defaults enable */
- case 0x66: /* reverting to power-on defaults disable */
- case 0xaa: /* read look-ahead enable */
- case 0x55: /* read look-ahead disable */
- case 0x05: /* set advanced power management mode */
- case 0x85: /* disable advanced power management mode */
- case 0x69: /* NOP */
- case 0x67: /* NOP */
- case 0x96: /* NOP */
- case 0x9a: /* NOP */
- case 0x42: /* enable Automatic Acoustic Mode */
- case 0xc2: /* disable Automatic Acoustic Mode */
- return true;
- case 0x03: /* set transfer mode */
- {
- uint8_t val = s->nsector & 0x07;
- identify_data = (uint16_t *)s->identify_data;
-
- switch (s->nsector >> 3) {
- case 0x00: /* pio default */
- case 0x01: /* pio mode */
- put_le16(identify_data + 62, 0x07);
- put_le16(identify_data + 63, 0x07);
- put_le16(identify_data + 88, 0x3f);
- break;
- case 0x02: /* sigle word dma mode*/
- put_le16(identify_data + 62, 0x07 | (1 << (val + 8)));
- put_le16(identify_data + 63, 0x07);
- put_le16(identify_data + 88, 0x3f);
- break;
- case 0x04: /* mdma mode */
- put_le16(identify_data + 62, 0x07);
- put_le16(identify_data + 63, 0x07 | (1 << (val + 8)));
- put_le16(identify_data + 88, 0x3f);
- break;
- case 0x08: /* udma mode */
- put_le16(identify_data + 62, 0x07);
- put_le16(identify_data + 63, 0x07);
- put_le16(identify_data + 88, 0x3f | (1 << (val + 8)));
- break;
- default:
- goto abort_cmd;
- }
- return true;
- }
- }
-
-abort_cmd:
- ide_abort_command(s);
- return true;
-}
-
-
-/*** ATAPI commands ***/
-
-static bool cmd_identify_packet(IDEState *s, uint8_t cmd)
-{
- ide_atapi_identify(s);
- s->status = READY_STAT | SEEK_STAT;
- ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop);
- ide_set_irq(s->bus);
- return false;
-}
-
-static bool cmd_exec_dev_diagnostic(IDEState *s, uint8_t cmd)
-{
- ide_set_signature(s);
-
- if (s->drive_kind == IDE_CD) {
- s->status = 0; /* ATAPI spec (v6) section 9.10 defines packet
- * devices to return a clear status register
- * with READY_STAT *not* set. */
- s->error = 0x01;
- } else {
- s->status = READY_STAT | SEEK_STAT;
- /* The bits of the error register are not as usual for this command!
- * They are part of the regular output (this is why ERR_STAT isn't set)
- * Device 0 passed, Device 1 passed or not present. */
- s->error = 0x01;
- ide_set_irq(s->bus);
- }
-
- return false;
-}
-
-static bool cmd_packet(IDEState *s, uint8_t cmd)
-{
- /* overlapping commands not supported */
- if (s->feature & 0x02) {
- ide_abort_command(s);
- return true;
- }
-
- s->status = READY_STAT | SEEK_STAT;
- s->atapi_dma = s->feature & 1;
- if (s->atapi_dma) {
- s->dma_cmd = IDE_DMA_ATAPI;
- }
- s->nsector = 1;
- ide_transfer_start(s, s->io_buffer, ATAPI_PACKET_SIZE,
- ide_atapi_cmd);
- return false;
-}
-
-
-/*** CF-ATA commands ***/
-
-static bool cmd_cfa_req_ext_error_code(IDEState *s, uint8_t cmd)
-{
- s->error = 0x09; /* miscellaneous error */
- s->status = READY_STAT | SEEK_STAT;
- ide_set_irq(s->bus);
-
- return false;
-}
-
-static bool cmd_cfa_erase_sectors(IDEState *s, uint8_t cmd)
-{
- /* WIN_SECURITY_FREEZE_LOCK has the same ID as CFA_WEAR_LEVEL and is
- * required for Windows 8 to work with AHCI */
-
- if (cmd == CFA_WEAR_LEVEL) {
- s->nsector = 0;
- }
-
- if (cmd == CFA_ERASE_SECTORS) {
- s->media_changed = 1;
- }
-
- return true;
-}
-
-static bool cmd_cfa_translate_sector(IDEState *s, uint8_t cmd)
-{
- s->status = READY_STAT | SEEK_STAT;
-
- memset(s->io_buffer, 0, 0x200);
- s->io_buffer[0x00] = s->hcyl; /* Cyl MSB */
- s->io_buffer[0x01] = s->lcyl; /* Cyl LSB */
- s->io_buffer[0x02] = s->select; /* Head */
- s->io_buffer[0x03] = s->sector; /* Sector */
- s->io_buffer[0x04] = ide_get_sector(s) >> 16; /* LBA MSB */
- s->io_buffer[0x05] = ide_get_sector(s) >> 8; /* LBA */
- s->io_buffer[0x06] = ide_get_sector(s) >> 0; /* LBA LSB */
- s->io_buffer[0x13] = 0x00; /* Erase flag */
- s->io_buffer[0x18] = 0x00; /* Hot count */
- s->io_buffer[0x19] = 0x00; /* Hot count */
- s->io_buffer[0x1a] = 0x01; /* Hot count */
-
- ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
- ide_set_irq(s->bus);
-
- return false;
-}
-
-static bool cmd_cfa_access_metadata_storage(IDEState *s, uint8_t cmd)
-{
- switch (s->feature) {
- case 0x02: /* Inquiry Metadata Storage */
- ide_cfata_metadata_inquiry(s);
- break;
- case 0x03: /* Read Metadata Storage */
- ide_cfata_metadata_read(s);
- break;
- case 0x04: /* Write Metadata Storage */
- ide_cfata_metadata_write(s);
- break;
- default:
- ide_abort_command(s);
- return true;
- }
-
- ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
- s->status = 0x00; /* NOTE: READY is _not_ set */
- ide_set_irq(s->bus);
-
- return false;
-}
-
-static bool cmd_ibm_sense_condition(IDEState *s, uint8_t cmd)
-{
- switch (s->feature) {
- case 0x01: /* sense temperature in device */
- s->nsector = 0x50; /* +20 C */
- break;
- default:
- ide_abort_command(s);
- return true;
- }
-
- return true;
-}
-
-
-/*** SMART commands ***/
-
-static bool cmd_smart(IDEState *s, uint8_t cmd)
-{
- int n;
-
- if (s->hcyl != 0xc2 || s->lcyl != 0x4f) {
- goto abort_cmd;
- }
-
- if (!s->smart_enabled && s->feature != SMART_ENABLE) {
- goto abort_cmd;
- }
-
- switch (s->feature) {
- case SMART_DISABLE:
- s->smart_enabled = 0;
- return true;
-
- case SMART_ENABLE:
- s->smart_enabled = 1;
- return true;
-
- case SMART_ATTR_AUTOSAVE:
- switch (s->sector) {
- case 0x00:
- s->smart_autosave = 0;
- break;
- case 0xf1:
- s->smart_autosave = 1;
- break;
- default:
- goto abort_cmd;
- }
- return true;
-
- case SMART_STATUS:
- if (!s->smart_errors) {
- s->hcyl = 0xc2;
- s->lcyl = 0x4f;
- } else {
- s->hcyl = 0x2c;
- s->lcyl = 0xf4;
- }
- return true;
-
- case SMART_READ_THRESH:
- memset(s->io_buffer, 0, 0x200);
- s->io_buffer[0] = 0x01; /* smart struct version */
-
- for (n = 0; n < ARRAY_SIZE(smart_attributes); n++) {
- s->io_buffer[2 + 0 + (n * 12)] = smart_attributes[n][0];
- s->io_buffer[2 + 1 + (n * 12)] = smart_attributes[n][11];
- }
-
- /* checksum */
- for (n = 0; n < 511; n++) {
- s->io_buffer[511] += s->io_buffer[n];
- }
- s->io_buffer[511] = 0x100 - s->io_buffer[511];
-
- s->status = READY_STAT | SEEK_STAT;
- ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
- ide_set_irq(s->bus);
- return false;
-
- case SMART_READ_DATA:
- memset(s->io_buffer, 0, 0x200);
- s->io_buffer[0] = 0x01; /* smart struct version */
-
- for (n = 0; n < ARRAY_SIZE(smart_attributes); n++) {
- int i;
- for (i = 0; i < 11; i++) {
- s->io_buffer[2 + i + (n * 12)] = smart_attributes[n][i];
- }
- }
-
- s->io_buffer[362] = 0x02 | (s->smart_autosave ? 0x80 : 0x00);
- if (s->smart_selftest_count == 0) {
- s->io_buffer[363] = 0;
- } else {
- s->io_buffer[363] =
- s->smart_selftest_data[3 +
- (s->smart_selftest_count - 1) *
- 24];
- }
- s->io_buffer[364] = 0x20;
- s->io_buffer[365] = 0x01;
- /* offline data collection capacity: execute + self-test*/
- s->io_buffer[367] = (1 << 4 | 1 << 3 | 1);
- s->io_buffer[368] = 0x03; /* smart capability (1) */
- s->io_buffer[369] = 0x00; /* smart capability (2) */
- s->io_buffer[370] = 0x01; /* error logging supported */
- s->io_buffer[372] = 0x02; /* minutes for poll short test */
- s->io_buffer[373] = 0x36; /* minutes for poll ext test */
- s->io_buffer[374] = 0x01; /* minutes for poll conveyance */
-
- for (n = 0; n < 511; n++) {
- s->io_buffer[511] += s->io_buffer[n];
- }
- s->io_buffer[511] = 0x100 - s->io_buffer[511];
-
- s->status = READY_STAT | SEEK_STAT;
- ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
- ide_set_irq(s->bus);
- return false;
-
- case SMART_READ_LOG:
- switch (s->sector) {
- case 0x01: /* summary smart error log */
- memset(s->io_buffer, 0, 0x200);
- s->io_buffer[0] = 0x01;
- s->io_buffer[1] = 0x00; /* no error entries */
- s->io_buffer[452] = s->smart_errors & 0xff;
- s->io_buffer[453] = (s->smart_errors & 0xff00) >> 8;
-
- for (n = 0; n < 511; n++) {
- s->io_buffer[511] += s->io_buffer[n];
- }
- s->io_buffer[511] = 0x100 - s->io_buffer[511];
- break;
- case 0x06: /* smart self test log */
- memset(s->io_buffer, 0, 0x200);
- s->io_buffer[0] = 0x01;
- if (s->smart_selftest_count == 0) {
- s->io_buffer[508] = 0;
- } else {
- s->io_buffer[508] = s->smart_selftest_count;
- for (n = 2; n < 506; n++) {
- s->io_buffer[n] = s->smart_selftest_data[n];
- }
- }
-
- for (n = 0; n < 511; n++) {
- s->io_buffer[511] += s->io_buffer[n];
- }
- s->io_buffer[511] = 0x100 - s->io_buffer[511];
- break;
- default:
- goto abort_cmd;
- }
- s->status = READY_STAT | SEEK_STAT;
- ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
- ide_set_irq(s->bus);
- return false;
-
- case SMART_EXECUTE_OFFLINE:
- switch (s->sector) {
- case 0: /* off-line routine */
- case 1: /* short self test */
- case 2: /* extended self test */
- s->smart_selftest_count++;
- if (s->smart_selftest_count > 21) {
- s->smart_selftest_count = 1;
- }
- n = 2 + (s->smart_selftest_count - 1) * 24;
- s->smart_selftest_data[n] = s->sector;
- s->smart_selftest_data[n + 1] = 0x00; /* OK and finished */
- s->smart_selftest_data[n + 2] = 0x34; /* hour count lsb */
- s->smart_selftest_data[n + 3] = 0x12; /* hour count msb */
- break;
- default:
- goto abort_cmd;
- }
- return true;
- }
-
-abort_cmd:
- ide_abort_command(s);
- return true;
-}
-
-#define HD_OK (1u << IDE_HD)
-#define CD_OK (1u << IDE_CD)
-#define CFA_OK (1u << IDE_CFATA)
-#define HD_CFA_OK (HD_OK | CFA_OK)
-#define ALL_OK (HD_OK | CD_OK | CFA_OK)
-
-/* Set the Disk Seek Completed status bit during completion */
-#define SET_DSC (1u << 8)
-
-/* See ACS-2 T13/2015-D Table B.2 Command codes */
-static const struct {
- /* Returns true if the completion code should be run */
- bool (*handler)(IDEState *s, uint8_t cmd);
- int flags;
-} ide_cmd_table[0x100] = {
- /* NOP not implemented, mandatory for CD */
- [CFA_REQ_EXT_ERROR_CODE] = { cmd_cfa_req_ext_error_code, CFA_OK },
- [WIN_DSM] = { cmd_data_set_management, HD_CFA_OK },
- [WIN_DEVICE_RESET] = { cmd_device_reset, CD_OK },
- [WIN_RECAL] = { cmd_nop, HD_CFA_OK | SET_DSC},
- [WIN_READ] = { cmd_read_pio, ALL_OK },
- [WIN_READ_ONCE] = { cmd_read_pio, HD_CFA_OK },
- [WIN_READ_EXT] = { cmd_read_pio, HD_CFA_OK },
- [WIN_READDMA_EXT] = { cmd_read_dma, HD_CFA_OK },
- [WIN_READ_NATIVE_MAX_EXT] = { cmd_read_native_max, HD_CFA_OK | SET_DSC },
- [WIN_MULTREAD_EXT] = { cmd_read_multiple, HD_CFA_OK },
- [WIN_WRITE] = { cmd_write_pio, HD_CFA_OK },
- [WIN_WRITE_ONCE] = { cmd_write_pio, HD_CFA_OK },
- [WIN_WRITE_EXT] = { cmd_write_pio, HD_CFA_OK },
- [WIN_WRITEDMA_EXT] = { cmd_write_dma, HD_CFA_OK },
- [CFA_WRITE_SECT_WO_ERASE] = { cmd_write_pio, CFA_OK },
- [WIN_MULTWRITE_EXT] = { cmd_write_multiple, HD_CFA_OK },
- [WIN_WRITE_VERIFY] = { cmd_write_pio, HD_CFA_OK },
- [WIN_VERIFY] = { cmd_verify, HD_CFA_OK | SET_DSC },
- [WIN_VERIFY_ONCE] = { cmd_verify, HD_CFA_OK | SET_DSC },
- [WIN_VERIFY_EXT] = { cmd_verify, HD_CFA_OK | SET_DSC },
- [WIN_SEEK] = { cmd_seek, HD_CFA_OK | SET_DSC },
- [CFA_TRANSLATE_SECTOR] = { cmd_cfa_translate_sector, CFA_OK },
- [WIN_DIAGNOSE] = { cmd_exec_dev_diagnostic, ALL_OK },
- [WIN_SPECIFY] = { cmd_nop, HD_CFA_OK | SET_DSC },
- [WIN_STANDBYNOW2] = { cmd_nop, HD_CFA_OK },
- [WIN_IDLEIMMEDIATE2] = { cmd_nop, HD_CFA_OK },
- [WIN_STANDBY2] = { cmd_nop, HD_CFA_OK },
- [WIN_SETIDLE2] = { cmd_nop, HD_CFA_OK },
- [WIN_CHECKPOWERMODE2] = { cmd_check_power_mode, HD_CFA_OK | SET_DSC },
- [WIN_SLEEPNOW2] = { cmd_nop, HD_CFA_OK },
- [WIN_PACKETCMD] = { cmd_packet, CD_OK },
- [WIN_PIDENTIFY] = { cmd_identify_packet, CD_OK },
- [WIN_SMART] = { cmd_smart, HD_CFA_OK | SET_DSC },
- [CFA_ACCESS_METADATA_STORAGE] = { cmd_cfa_access_metadata_storage, CFA_OK },
- [CFA_ERASE_SECTORS] = { cmd_cfa_erase_sectors, CFA_OK | SET_DSC },
- [WIN_MULTREAD] = { cmd_read_multiple, HD_CFA_OK },
- [WIN_MULTWRITE] = { cmd_write_multiple, HD_CFA_OK },
- [WIN_SETMULT] = { cmd_set_multiple_mode, HD_CFA_OK | SET_DSC },
- [WIN_READDMA] = { cmd_read_dma, HD_CFA_OK },
- [WIN_READDMA_ONCE] = { cmd_read_dma, HD_CFA_OK },
- [WIN_WRITEDMA] = { cmd_write_dma, HD_CFA_OK },
- [WIN_WRITEDMA_ONCE] = { cmd_write_dma, HD_CFA_OK },
- [CFA_WRITE_MULTI_WO_ERASE] = { cmd_write_multiple, CFA_OK },
- [WIN_STANDBYNOW1] = { cmd_nop, HD_CFA_OK },
- [WIN_IDLEIMMEDIATE] = { cmd_nop, HD_CFA_OK },
- [WIN_STANDBY] = { cmd_nop, HD_CFA_OK },
- [WIN_SETIDLE1] = { cmd_nop, HD_CFA_OK },
- [WIN_CHECKPOWERMODE1] = { cmd_check_power_mode, HD_CFA_OK | SET_DSC },
- [WIN_SLEEPNOW1] = { cmd_nop, HD_CFA_OK },
- [WIN_FLUSH_CACHE] = { cmd_flush_cache, ALL_OK },
- [WIN_FLUSH_CACHE_EXT] = { cmd_flush_cache, HD_CFA_OK },
- [WIN_IDENTIFY] = { cmd_identify, ALL_OK },
- [WIN_SETFEATURES] = { cmd_set_features, ALL_OK | SET_DSC },
- [IBM_SENSE_CONDITION] = { cmd_ibm_sense_condition, CFA_OK | SET_DSC },
- [CFA_WEAR_LEVEL] = { cmd_cfa_erase_sectors, HD_CFA_OK | SET_DSC },
- [WIN_READ_NATIVE_MAX] = { cmd_read_native_max, HD_CFA_OK | SET_DSC },
-};
-
-static bool ide_cmd_permitted(IDEState *s, uint32_t cmd)
-{
- return cmd < ARRAY_SIZE(ide_cmd_table)
- && (ide_cmd_table[cmd].flags & (1u << s->drive_kind));
-}
-
-void ide_exec_cmd(IDEBus *bus, uint32_t val)
-{
- IDEState *s;
- bool complete;
-
-#if defined(DEBUG_IDE)
- printf("ide: CMD=%02x\n", val);
-#endif
- s = idebus_active_if(bus);
- /* ignore commands to non existent slave */
- if (s != bus->ifs && !s->blk) {
- return;
- }
-
- /* Only RESET is allowed while BSY and/or DRQ are set,
- * and only to ATAPI devices. */
- if (s->status & (BUSY_STAT|DRQ_STAT)) {
- if (val != WIN_DEVICE_RESET || s->drive_kind != IDE_CD) {
- return;
- }
- }
-
- if (!ide_cmd_permitted(s, val)) {
- ide_abort_command(s);
- ide_set_irq(s->bus);
- return;
- }
-
- s->status = READY_STAT | BUSY_STAT;
- s->error = 0;
- s->io_buffer_offset = 0;
-
- complete = ide_cmd_table[val].handler(s, val);
- if (complete) {
- s->status &= ~BUSY_STAT;
- assert(!!s->error == !!(s->status & ERR_STAT));
-
- if ((ide_cmd_table[val].flags & SET_DSC) && !s->error) {
- s->status |= SEEK_STAT;
- }
-
- ide_cmd_done(s);
- ide_set_irq(s->bus);
- }
-}
-
-uint32_t ide_ioport_read(void *opaque, uint32_t addr1)
-{
- IDEBus *bus = opaque;
- IDEState *s = idebus_active_if(bus);
- uint32_t addr;
- int ret, hob;
-
- addr = addr1 & 7;
- /* FIXME: HOB readback uses bit 7, but it's always set right now */
- //hob = s->select & (1 << 7);
- hob = 0;
- switch(addr) {
- case 0:
- ret = 0xff;
- break;
- case 1:
- if ((!bus->ifs[0].blk && !bus->ifs[1].blk) ||
- (s != bus->ifs && !s->blk)) {
- ret = 0;
- } else if (!hob) {
- ret = s->error;
- } else {
- ret = s->hob_feature;
- }
- break;
- case 2:
- if (!bus->ifs[0].blk && !bus->ifs[1].blk) {
- ret = 0;
- } else if (!hob) {
- ret = s->nsector & 0xff;
- } else {
- ret = s->hob_nsector;
- }
- break;
- case 3:
- if (!bus->ifs[0].blk && !bus->ifs[1].blk) {
- ret = 0;
- } else if (!hob) {
- ret = s->sector;
- } else {
- ret = s->hob_sector;
- }
- break;
- case 4:
- if (!bus->ifs[0].blk && !bus->ifs[1].blk) {
- ret = 0;
- } else if (!hob) {
- ret = s->lcyl;
- } else {
- ret = s->hob_lcyl;
- }
- break;
- case 5:
- if (!bus->ifs[0].blk && !bus->ifs[1].blk) {
- ret = 0;
- } else if (!hob) {
- ret = s->hcyl;
- } else {
- ret = s->hob_hcyl;
- }
- break;
- case 6:
- if (!bus->ifs[0].blk && !bus->ifs[1].blk) {
- ret = 0;
- } else {
- ret = s->select;
- }
- break;
- default:
- case 7:
- if ((!bus->ifs[0].blk && !bus->ifs[1].blk) ||
- (s != bus->ifs && !s->blk)) {
- ret = 0;
- } else {
- ret = s->status;
- }
- qemu_irq_lower(bus->irq);
- break;
- }
-#ifdef DEBUG_IDE
- printf("ide: read addr=0x%x val=%02x\n", addr1, ret);
-#endif
- return ret;
-}
-
-uint32_t ide_status_read(void *opaque, uint32_t addr)
-{
- IDEBus *bus = opaque;
- IDEState *s = idebus_active_if(bus);
- int ret;
-
- if ((!bus->ifs[0].blk && !bus->ifs[1].blk) ||
- (s != bus->ifs && !s->blk)) {
- ret = 0;
- } else {
- ret = s->status;
- }
-#ifdef DEBUG_IDE
- printf("ide: read status addr=0x%x val=%02x\n", addr, ret);
-#endif
- return ret;
-}
-
-void ide_cmd_write(void *opaque, uint32_t addr, uint32_t val)
-{
- IDEBus *bus = opaque;
- IDEState *s;
- int i;
-
-#ifdef DEBUG_IDE
- printf("ide: write control addr=0x%x val=%02x\n", addr, val);
-#endif
- /* common for both drives */
- if (!(bus->cmd & IDE_CMD_RESET) &&
- (val & IDE_CMD_RESET)) {
- /* reset low to high */
- for(i = 0;i < 2; i++) {
- s = &bus->ifs[i];
- s->status = BUSY_STAT | SEEK_STAT;
- s->error = 0x01;
- }
- } else if ((bus->cmd & IDE_CMD_RESET) &&
- !(val & IDE_CMD_RESET)) {
- /* high to low */
- for(i = 0;i < 2; i++) {
- s = &bus->ifs[i];
- if (s->drive_kind == IDE_CD)
- s->status = 0x00; /* NOTE: READY is _not_ set */
- else
- s->status = READY_STAT | SEEK_STAT;
- ide_set_signature(s);
- }
- }
-
- bus->cmd = val;
-}
-
-/*
- * Returns true if the running PIO transfer is a PIO out (i.e. data is
- * transferred from the device to the guest), false if it's a PIO in
- */
-static bool ide_is_pio_out(IDEState *s)
-{
- if (s->end_transfer_func == ide_sector_write ||
- s->end_transfer_func == ide_atapi_cmd) {
- return false;
- } else if (s->end_transfer_func == ide_sector_read ||
- s->end_transfer_func == ide_transfer_stop ||
- s->end_transfer_func == ide_atapi_cmd_reply_end ||
- s->end_transfer_func == ide_dummy_transfer_stop) {
- return true;
- }
-
- abort();
-}
-
-void ide_data_writew(void *opaque, uint32_t addr, uint32_t val)
-{
- IDEBus *bus = opaque;
- IDEState *s = idebus_active_if(bus);
- uint8_t *p;
-
- /* PIO data access allowed only when DRQ bit is set. The result of a write
- * during PIO out is indeterminate, just ignore it. */
- if (!(s->status & DRQ_STAT) || ide_is_pio_out(s)) {
- return;
- }
-
- p = s->data_ptr;
- if (p + 2 > s->data_end) {
- return;
- }
-
- *(uint16_t *)p = le16_to_cpu(val);
- p += 2;
- s->data_ptr = p;
- if (p >= s->data_end) {
- s->status &= ~DRQ_STAT;
- s->end_transfer_func(s);
- }
-}
-
-uint32_t ide_data_readw(void *opaque, uint32_t addr)
-{
- IDEBus *bus = opaque;
- IDEState *s = idebus_active_if(bus);
- uint8_t *p;
- int ret;
-
- /* PIO data access allowed only when DRQ bit is set. The result of a read
- * during PIO in is indeterminate, return 0 and don't move forward. */
- if (!(s->status & DRQ_STAT) || !ide_is_pio_out(s)) {
- return 0;
- }
-
- p = s->data_ptr;
- if (p + 2 > s->data_end) {
- return 0;
- }
-
- ret = cpu_to_le16(*(uint16_t *)p);
- p += 2;
- s->data_ptr = p;
- if (p >= s->data_end) {
- s->status &= ~DRQ_STAT;
- s->end_transfer_func(s);
- }
- return ret;
-}
-
-void ide_data_writel(void *opaque, uint32_t addr, uint32_t val)
-{
- IDEBus *bus = opaque;
- IDEState *s = idebus_active_if(bus);
- uint8_t *p;
-
- /* PIO data access allowed only when DRQ bit is set. The result of a write
- * during PIO out is indeterminate, just ignore it. */
- if (!(s->status & DRQ_STAT) || ide_is_pio_out(s)) {
- return;
- }
-
- p = s->data_ptr;
- if (p + 4 > s->data_end) {
- return;
- }
-
- *(uint32_t *)p = le32_to_cpu(val);
- p += 4;
- s->data_ptr = p;
- if (p >= s->data_end) {
- s->status &= ~DRQ_STAT;
- s->end_transfer_func(s);
- }
-}
-
-uint32_t ide_data_readl(void *opaque, uint32_t addr)
-{
- IDEBus *bus = opaque;
- IDEState *s = idebus_active_if(bus);
- uint8_t *p;
- int ret;
-
- /* PIO data access allowed only when DRQ bit is set. The result of a read
- * during PIO in is indeterminate, return 0 and don't move forward. */
- if (!(s->status & DRQ_STAT) || !ide_is_pio_out(s)) {
- return 0;
- }
-
- p = s->data_ptr;
- if (p + 4 > s->data_end) {
- return 0;
- }
-
- ret = cpu_to_le32(*(uint32_t *)p);
- p += 4;
- s->data_ptr = p;
- if (p >= s->data_end) {
- s->status &= ~DRQ_STAT;
- s->end_transfer_func(s);
- }
- return ret;
-}
-
-static void ide_dummy_transfer_stop(IDEState *s)
-{
- s->data_ptr = s->io_buffer;
- s->data_end = s->io_buffer;
- s->io_buffer[0] = 0xff;
- s->io_buffer[1] = 0xff;
- s->io_buffer[2] = 0xff;
- s->io_buffer[3] = 0xff;
-}
-
-void ide_bus_reset(IDEBus *bus)
-{
- bus->unit = 0;
- bus->cmd = 0;
- ide_reset(&bus->ifs[0]);
- ide_reset(&bus->ifs[1]);
- ide_clear_hob(bus);
-
- /* pending async DMA */
- if (bus->dma->aiocb) {
-#ifdef DEBUG_AIO
- printf("aio_cancel\n");
-#endif
- blk_aio_cancel(bus->dma->aiocb);
- bus->dma->aiocb = NULL;
- }
-
- /* reset dma provider too */
- if (bus->dma->ops->reset) {
- bus->dma->ops->reset(bus->dma);
- }
-}
-
-static bool ide_cd_is_tray_open(void *opaque)
-{
- return ((IDEState *)opaque)->tray_open;
-}
-
-static bool ide_cd_is_medium_locked(void *opaque)
-{
- return ((IDEState *)opaque)->tray_locked;
-}
-
-static void ide_resize_cb(void *opaque)
-{
- IDEState *s = opaque;
- uint64_t nb_sectors;
-
- if (!s->identify_set) {
- return;
- }
-
- blk_get_geometry(s->blk, &nb_sectors);
- s->nb_sectors = nb_sectors;
-
- /* Update the identify data buffer. */
- if (s->drive_kind == IDE_CFATA) {
- ide_cfata_identify_size(s);
- } else {
- /* IDE_CD uses a different set of callbacks entirely. */
- assert(s->drive_kind != IDE_CD);
- ide_identify_size(s);
- }
-}
-
-static const BlockDevOps ide_cd_block_ops = {
- .change_media_cb = ide_cd_change_cb,
- .eject_request_cb = ide_cd_eject_request_cb,
- .is_tray_open = ide_cd_is_tray_open,
- .is_medium_locked = ide_cd_is_medium_locked,
-};
-
-static const BlockDevOps ide_hd_block_ops = {
- .resize_cb = ide_resize_cb,
-};
-
-int ide_init_drive(IDEState *s, BlockBackend *blk, IDEDriveKind kind,
- const char *version, const char *serial, const char *model,
- uint64_t wwn,
- uint32_t cylinders, uint32_t heads, uint32_t secs,
- int chs_trans)
-{
- uint64_t nb_sectors;
-
- s->blk = blk;
- s->drive_kind = kind;
-
- blk_get_geometry(blk, &nb_sectors);
- s->cylinders = cylinders;
- s->heads = heads;
- s->sectors = secs;
- s->chs_trans = chs_trans;
- s->nb_sectors = nb_sectors;
- s->wwn = wwn;
- /* The SMART values should be preserved across power cycles
- but they aren't. */
- s->smart_enabled = 1;
- s->smart_autosave = 1;
- s->smart_errors = 0;
- s->smart_selftest_count = 0;
- if (kind == IDE_CD) {
- blk_set_dev_ops(blk, &ide_cd_block_ops, s);
- blk_set_guest_block_size(blk, 2048);
- } else {
- if (!blk_is_inserted(s->blk)) {
- error_report("Device needs media, but drive is empty");
- return -1;
- }
- if (blk_is_read_only(blk)) {
- error_report("Can't use a read-only drive");
- return -1;
- }
- blk_set_dev_ops(blk, &ide_hd_block_ops, s);
- }
- if (serial) {
- pstrcpy(s->drive_serial_str, sizeof(s->drive_serial_str), serial);
- } else {
- snprintf(s->drive_serial_str, sizeof(s->drive_serial_str),
- "QM%05d", s->drive_serial);
- }
- if (model) {
- pstrcpy(s->drive_model_str, sizeof(s->drive_model_str), model);
- } else {
- switch (kind) {
- case IDE_CD:
- strcpy(s->drive_model_str, "QEMU DVD-ROM");
- break;
- case IDE_CFATA:
- strcpy(s->drive_model_str, "QEMU MICRODRIVE");
- break;
- default:
- strcpy(s->drive_model_str, "QEMU HARDDISK");
- break;
- }
- }
-
- if (version) {
- pstrcpy(s->version, sizeof(s->version), version);
- } else {
- pstrcpy(s->version, sizeof(s->version), qemu_hw_version());
- }
-
- ide_reset(s);
- blk_iostatus_enable(blk);
- return 0;
-}
-
-static void ide_init1(IDEBus *bus, int unit)
-{
- static int drive_serial = 1;
- IDEState *s = &bus->ifs[unit];
-
- s->bus = bus;
- s->unit = unit;
- s->drive_serial = drive_serial++;
- /* we need at least 2k alignment for accessing CDROMs using O_DIRECT */
- s->io_buffer_total_len = IDE_DMA_BUF_SECTORS*512 + 4;
- s->io_buffer = qemu_memalign(2048, s->io_buffer_total_len);
- memset(s->io_buffer, 0, s->io_buffer_total_len);
-
- s->smart_selftest_data = blk_blockalign(s->blk, 512);
- memset(s->smart_selftest_data, 0, 512);
-
- s->sector_write_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
- ide_sector_write_timer_cb, s);
-}
-
-static int ide_nop_int(IDEDMA *dma, int x)
-{
- return 0;
-}
-
-static void ide_nop(IDEDMA *dma)
-{
-}
-
-static int32_t ide_nop_int32(IDEDMA *dma, int32_t l)
-{
- return 0;
-}
-
-static const IDEDMAOps ide_dma_nop_ops = {
- .prepare_buf = ide_nop_int32,
- .restart_dma = ide_nop,
- .rw_buf = ide_nop_int,
-};
-
-static void ide_restart_dma(IDEState *s, enum ide_dma_cmd dma_cmd)
-{
- s->unit = s->bus->retry_unit;
- ide_set_sector(s, s->bus->retry_sector_num);
- s->nsector = s->bus->retry_nsector;
- s->bus->dma->ops->restart_dma(s->bus->dma);
- s->io_buffer_size = 0;
- s->dma_cmd = dma_cmd;
- ide_start_dma(s, ide_dma_cb);
-}
-
-static void ide_restart_bh(void *opaque)
-{
- IDEBus *bus = opaque;
- IDEState *s;
- bool is_read;
- int error_status;
-
- qemu_bh_delete(bus->bh);
- bus->bh = NULL;
-
- error_status = bus->error_status;
- if (bus->error_status == 0) {
- return;
- }
-
- s = idebus_active_if(bus);
- is_read = (bus->error_status & IDE_RETRY_READ) != 0;
-
- /* The error status must be cleared before resubmitting the request: The
- * request may fail again, and this case can only be distinguished if the
- * called function can set a new error status. */
- bus->error_status = 0;
-
- /* The HBA has generically asked to be kicked on retry */
- if (error_status & IDE_RETRY_HBA) {
- if (s->bus->dma->ops->restart) {
- s->bus->dma->ops->restart(s->bus->dma);
- }
- } else if (IS_IDE_RETRY_DMA(error_status)) {
- if (error_status & IDE_RETRY_TRIM) {
- ide_restart_dma(s, IDE_DMA_TRIM);
- } else {
- ide_restart_dma(s, is_read ? IDE_DMA_READ : IDE_DMA_WRITE);
- }
- } else if (IS_IDE_RETRY_PIO(error_status)) {
- if (is_read) {
- ide_sector_read(s);
- } else {
- ide_sector_write(s);
- }
- } else if (error_status & IDE_RETRY_FLUSH) {
- ide_flush_cache(s);
- } else if (IS_IDE_RETRY_ATAPI(error_status)) {
- assert(s->end_transfer_func == ide_atapi_cmd);
- ide_atapi_dma_restart(s);
- } else {
- abort();
- }
-}
-
-static void ide_restart_cb(void *opaque, int running, RunState state)
-{
- IDEBus *bus = opaque;
-
- if (!running)
- return;
-
- if (!bus->bh) {
- bus->bh = qemu_bh_new(ide_restart_bh, bus);
- qemu_bh_schedule(bus->bh);
- }
-}
-
-void ide_register_restart_cb(IDEBus *bus)
-{
- if (bus->dma->ops->restart_dma) {
- qemu_add_vm_change_state_handler(ide_restart_cb, bus);
- }
-}
-
-static IDEDMA ide_dma_nop = {
- .ops = &ide_dma_nop_ops,
- .aiocb = NULL,
-};
-
-void ide_init2(IDEBus *bus, qemu_irq irq)
-{
- int i;
-
- for(i = 0; i < 2; i++) {
- ide_init1(bus, i);
- ide_reset(&bus->ifs[i]);
- }
- bus->irq = irq;
- bus->dma = &ide_dma_nop;
-}
-
-static const MemoryRegionPortio ide_portio_list[] = {
- { 0, 8, 1, .read = ide_ioport_read, .write = ide_ioport_write },
- { 0, 1, 2, .read = ide_data_readw, .write = ide_data_writew },
- { 0, 1, 4, .read = ide_data_readl, .write = ide_data_writel },
- PORTIO_END_OF_LIST(),
-};
-
-static const MemoryRegionPortio ide_portio2_list[] = {
- { 0, 1, 1, .read = ide_status_read, .write = ide_cmd_write },
- PORTIO_END_OF_LIST(),
-};
-
-void ide_init_ioport(IDEBus *bus, ISADevice *dev, int iobase, int iobase2)
-{
- /* ??? Assume only ISA and PCI configurations, and that the PCI-ISA
- bridge has been setup properly to always register with ISA. */
- isa_register_portio_list(dev, iobase, ide_portio_list, bus, "ide");
-
- if (iobase2) {
- isa_register_portio_list(dev, iobase2, ide_portio2_list, bus, "ide");
- }
-}
-
-static bool is_identify_set(void *opaque, int version_id)
-{
- IDEState *s = opaque;
-
- return s->identify_set != 0;
-}
-
-static EndTransferFunc* transfer_end_table[] = {
- ide_sector_read,
- ide_sector_write,
- ide_transfer_stop,
- ide_atapi_cmd_reply_end,
- ide_atapi_cmd,
- ide_dummy_transfer_stop,
-};
-
-static int transfer_end_table_idx(EndTransferFunc *fn)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(transfer_end_table); i++)
- if (transfer_end_table[i] == fn)
- return i;
-
- return -1;
-}
-
-static int ide_drive_post_load(void *opaque, int version_id)
-{
- IDEState *s = opaque;
-
- if (s->blk && s->identify_set) {
- blk_set_enable_write_cache(s->blk, !!(s->identify_data[85] & (1 << 5)));
- }
- return 0;
-}
-
-static int ide_drive_pio_post_load(void *opaque, int version_id)
-{
- IDEState *s = opaque;
-
- if (s->end_transfer_fn_idx >= ARRAY_SIZE(transfer_end_table)) {
- return -EINVAL;
- }
- s->end_transfer_func = transfer_end_table[s->end_transfer_fn_idx];
- s->data_ptr = s->io_buffer + s->cur_io_buffer_offset;
- s->data_end = s->data_ptr + s->cur_io_buffer_len;
- s->atapi_dma = s->feature & 1; /* as per cmd_packet */
-
- return 0;
-}
-
-static void ide_drive_pio_pre_save(void *opaque)
-{
- IDEState *s = opaque;
- int idx;
-
- s->cur_io_buffer_offset = s->data_ptr - s->io_buffer;
- s->cur_io_buffer_len = s->data_end - s->data_ptr;
-
- idx = transfer_end_table_idx(s->end_transfer_func);
- if (idx == -1) {
- fprintf(stderr, "%s: invalid end_transfer_func for DRQ_STAT\n",
- __func__);
- s->end_transfer_fn_idx = 2;
- } else {
- s->end_transfer_fn_idx = idx;
- }
-}
-
-static bool ide_drive_pio_state_needed(void *opaque)
-{
- IDEState *s = opaque;
-
- return ((s->status & DRQ_STAT) != 0)
- || (s->bus->error_status & IDE_RETRY_PIO);
-}
-
-static bool ide_tray_state_needed(void *opaque)
-{
- IDEState *s = opaque;
-
- return s->tray_open || s->tray_locked;
-}
-
-static bool ide_atapi_gesn_needed(void *opaque)
-{
- IDEState *s = opaque;
-
- return s->events.new_media || s->events.eject_request;
-}
-
-static bool ide_error_needed(void *opaque)
-{
- IDEBus *bus = opaque;
-
- return (bus->error_status != 0);
-}
-
-/* Fields for GET_EVENT_STATUS_NOTIFICATION ATAPI command */
-static const VMStateDescription vmstate_ide_atapi_gesn_state = {
- .name ="ide_drive/atapi/gesn_state",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = ide_atapi_gesn_needed,
- .fields = (VMStateField[]) {
- VMSTATE_BOOL(events.new_media, IDEState),
- VMSTATE_BOOL(events.eject_request, IDEState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_ide_tray_state = {
- .name = "ide_drive/tray_state",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = ide_tray_state_needed,
- .fields = (VMStateField[]) {
- VMSTATE_BOOL(tray_open, IDEState),
- VMSTATE_BOOL(tray_locked, IDEState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_ide_drive_pio_state = {
- .name = "ide_drive/pio_state",
- .version_id = 1,
- .minimum_version_id = 1,
- .pre_save = ide_drive_pio_pre_save,
- .post_load = ide_drive_pio_post_load,
- .needed = ide_drive_pio_state_needed,
- .fields = (VMStateField[]) {
- VMSTATE_INT32(req_nb_sectors, IDEState),
- VMSTATE_VARRAY_INT32(io_buffer, IDEState, io_buffer_total_len, 1,
- vmstate_info_uint8, uint8_t),
- VMSTATE_INT32(cur_io_buffer_offset, IDEState),
- VMSTATE_INT32(cur_io_buffer_len, IDEState),
- VMSTATE_UINT8(end_transfer_fn_idx, IDEState),
- VMSTATE_INT32(elementary_transfer_size, IDEState),
- VMSTATE_INT32(packet_transfer_size, IDEState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-const VMStateDescription vmstate_ide_drive = {
- .name = "ide_drive",
- .version_id = 3,
- .minimum_version_id = 0,
- .post_load = ide_drive_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_INT32(mult_sectors, IDEState),
- VMSTATE_INT32(identify_set, IDEState),
- VMSTATE_BUFFER_TEST(identify_data, IDEState, is_identify_set),
- VMSTATE_UINT8(feature, IDEState),
- VMSTATE_UINT8(error, IDEState),
- VMSTATE_UINT32(nsector, IDEState),
- VMSTATE_UINT8(sector, IDEState),
- VMSTATE_UINT8(lcyl, IDEState),
- VMSTATE_UINT8(hcyl, IDEState),
- VMSTATE_UINT8(hob_feature, IDEState),
- VMSTATE_UINT8(hob_sector, IDEState),
- VMSTATE_UINT8(hob_nsector, IDEState),
- VMSTATE_UINT8(hob_lcyl, IDEState),
- VMSTATE_UINT8(hob_hcyl, IDEState),
- VMSTATE_UINT8(select, IDEState),
- VMSTATE_UINT8(status, IDEState),
- VMSTATE_UINT8(lba48, IDEState),
- VMSTATE_UINT8(sense_key, IDEState),
- VMSTATE_UINT8(asc, IDEState),
- VMSTATE_UINT8_V(cdrom_changed, IDEState, 3),
- VMSTATE_END_OF_LIST()
- },
- .subsections = (const VMStateDescription*[]) {
- &vmstate_ide_drive_pio_state,
- &vmstate_ide_tray_state,
- &vmstate_ide_atapi_gesn_state,
- NULL
- }
-};
-
-static const VMStateDescription vmstate_ide_error_status = {
- .name ="ide_bus/error",
- .version_id = 2,
- .minimum_version_id = 1,
- .needed = ide_error_needed,
- .fields = (VMStateField[]) {
- VMSTATE_INT32(error_status, IDEBus),
- VMSTATE_INT64_V(retry_sector_num, IDEBus, 2),
- VMSTATE_UINT32_V(retry_nsector, IDEBus, 2),
- VMSTATE_UINT8_V(retry_unit, IDEBus, 2),
- VMSTATE_END_OF_LIST()
- }
-};
-
-const VMStateDescription vmstate_ide_bus = {
- .name = "ide_bus",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(cmd, IDEBus),
- VMSTATE_UINT8(unit, IDEBus),
- VMSTATE_END_OF_LIST()
- },
- .subsections = (const VMStateDescription*[]) {
- &vmstate_ide_error_status,
- NULL
- }
-};
-
-void ide_drive_get(DriveInfo **hd, int n)
-{
- int i;
- int highest_bus = drive_get_max_bus(IF_IDE) + 1;
- int max_devs = drive_get_max_devs(IF_IDE);
- int n_buses = max_devs ? (n / max_devs) : n;
-
- /*
- * Note: The number of actual buses available is not known.
- * We compute this based on the size of the DriveInfo* array, n.
- * If it is less than max_devs * <num_real_buses>,
- * We will stop looking for drives prematurely instead of overfilling
- * the array.
- */
-
- if (highest_bus > n_buses) {
- error_report("Too many IDE buses defined (%d > %d)",
- highest_bus, n_buses);
- exit(1);
- }
-
- for (i = 0; i < n; i++) {
- hd[i] = drive_get_by_index(IF_IDE, i);
- }
-}
diff --git a/qemu/hw/ide/ich.c b/qemu/hw/ide/ich.c
deleted file mode 100644
index 0a13334ba..000000000
--- a/qemu/hw/ide/ich.c
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * QEMU ICH Emulation
- *
- * Copyright (c) 2010 Sebastian Herbszt <herbszt@gmx.de>
- * Copyright (c) 2010 Alexander Graf <agraf@suse.de>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * lspci dump of a ICH-9 real device
- *
- * 00:1f.2 SATA controller [0106]: Intel Corporation 82801IR/IO/IH (ICH9R/DO/DH) 6 port SATA AHCI Controller [8086:2922] (rev 02) (prog-if 01 [AHCI 1.0])
- * Subsystem: Intel Corporation 82801IR/IO/IH (ICH9R/DO/DH) 6 port SATA AHCI Controller [8086:2922]
- * Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx+
- * Status: Cap+ 66MHz+ UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
- * Latency: 0
- * Interrupt: pin B routed to IRQ 222
- * Region 0: I/O ports at d000 [size=8]
- * Region 1: I/O ports at cc00 [size=4]
- * Region 2: I/O ports at c880 [size=8]
- * Region 3: I/O ports at c800 [size=4]
- * Region 4: I/O ports at c480 [size=32]
- * Region 5: Memory at febf9000 (32-bit, non-prefetchable) [size=2K]
- * Capabilities: [80] Message Signalled Interrupts: Mask- 64bit- Count=1/16 Enable+
- * Address: fee0f00c Data: 41d9
- * Capabilities: [70] Power Management version 3
- * Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot+,D3cold-)
- * Status: D0 PME-Enable- DSel=0 DScale=0 PME-
- * Capabilities: [a8] SATA HBA <?>
- * Capabilities: [b0] Vendor Specific Information <?>
- * Kernel driver in use: ahci
- * Kernel modules: ahci
- * 00: 86 80 22 29 07 04 b0 02 02 01 06 01 00 00 00 00
- * 10: 01 d0 00 00 01 cc 00 00 81 c8 00 00 01 c8 00 00
- * 20: 81 c4 00 00 00 90 bf fe 00 00 00 00 86 80 22 29
- * 30: 00 00 00 00 80 00 00 00 00 00 00 00 0f 02 00 00
- * 40: 00 80 00 80 00 00 00 00 00 00 00 00 00 00 00 00
- * 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 70: 01 a8 03 40 08 00 00 00 00 00 00 00 00 00 00 00
- * 80: 05 70 09 00 0c f0 e0 fe d9 41 00 00 00 00 00 00
- * 90: 40 00 0f 82 93 01 00 00 00 00 00 00 00 00 00 00
- * a0: ac 00 00 00 0a 00 12 00 12 b0 10 00 48 00 00 00
- * b0: 09 00 06 20 00 00 00 00 00 00 00 00 00 00 00 00
- * c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * f0: 00 00 00 00 00 00 00 00 86 0f 02 00 00 00 00 00
- *
- */
-
-#include "qemu/osdep.h"
-#include <hw/hw.h>
-#include <hw/pci/msi.h>
-#include <hw/i386/pc.h>
-#include <hw/pci/pci.h>
-#include <hw/isa/isa.h>
-#include "sysemu/block-backend.h"
-#include "sysemu/dma.h"
-
-#include <hw/ide/pci.h>
-#include <hw/ide/ahci.h>
-
-#define ICH9_MSI_CAP_OFFSET 0x80
-#define ICH9_SATA_CAP_OFFSET 0xA8
-
-#define ICH9_IDP_BAR 4
-#define ICH9_MEM_BAR 5
-
-#define ICH9_IDP_INDEX 0x10
-#define ICH9_IDP_INDEX_LOG2 0x04
-
-static const VMStateDescription vmstate_ich9_ahci = {
- .name = "ich9_ahci",
- .version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(parent_obj, AHCIPCIState),
- VMSTATE_AHCI(ahci, AHCIPCIState),
- VMSTATE_END_OF_LIST()
- },
-};
-
-static void pci_ich9_reset(DeviceState *dev)
-{
- AHCIPCIState *d = ICH_AHCI(dev);
-
- ahci_reset(&d->ahci);
-}
-
-static void pci_ich9_ahci_init(Object *obj)
-{
- struct AHCIPCIState *d = ICH_AHCI(obj);
-
- ahci_init(&d->ahci, DEVICE(obj));
-}
-
-static void pci_ich9_ahci_realize(PCIDevice *dev, Error **errp)
-{
- struct AHCIPCIState *d;
- int sata_cap_offset;
- uint8_t *sata_cap;
- d = ICH_AHCI(dev);
-
- ahci_realize(&d->ahci, DEVICE(dev), pci_get_address_space(dev), 6);
-
- pci_config_set_prog_interface(dev->config, AHCI_PROGMODE_MAJOR_REV_1);
-
- dev->config[PCI_CACHE_LINE_SIZE] = 0x08; /* Cache line size */
- dev->config[PCI_LATENCY_TIMER] = 0x00; /* Latency timer */
- pci_config_set_interrupt_pin(dev->config, 1);
-
- /* XXX Software should program this register */
- dev->config[0x90] = 1 << 6; /* Address Map Register - AHCI mode */
-
- d->ahci.irq = pci_allocate_irq(dev);
-
- pci_register_bar(dev, ICH9_IDP_BAR, PCI_BASE_ADDRESS_SPACE_IO,
- &d->ahci.idp);
- pci_register_bar(dev, ICH9_MEM_BAR, PCI_BASE_ADDRESS_SPACE_MEMORY,
- &d->ahci.mem);
-
- sata_cap_offset = pci_add_capability2(dev, PCI_CAP_ID_SATA,
- ICH9_SATA_CAP_OFFSET, SATA_CAP_SIZE,
- errp);
- if (sata_cap_offset < 0) {
- return;
- }
-
- sata_cap = dev->config + sata_cap_offset;
- pci_set_word(sata_cap + SATA_CAP_REV, 0x10);
- pci_set_long(sata_cap + SATA_CAP_BAR,
- (ICH9_IDP_BAR + 0x4) | (ICH9_IDP_INDEX_LOG2 << 4));
- d->ahci.idp_offset = ICH9_IDP_INDEX;
-
- /* Although the AHCI 1.3 specification states that the first capability
- * should be PMCAP, the Intel ICH9 data sheet specifies that the ICH9
- * AHCI device puts the MSI capability first, pointing to 0x80. */
- msi_init(dev, ICH9_MSI_CAP_OFFSET, 1, true, false);
-}
-
-static void pci_ich9_uninit(PCIDevice *dev)
-{
- struct AHCIPCIState *d;
- d = ICH_AHCI(dev);
-
- msi_uninit(dev);
- ahci_uninit(&d->ahci);
- qemu_free_irq(d->ahci.irq);
-}
-
-static void ich_ahci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = pci_ich9_ahci_realize;
- k->exit = pci_ich9_uninit;
- k->vendor_id = PCI_VENDOR_ID_INTEL;
- k->device_id = PCI_DEVICE_ID_INTEL_82801IR;
- k->revision = 0x02;
- k->class_id = PCI_CLASS_STORAGE_SATA;
- dc->vmsd = &vmstate_ich9_ahci;
- dc->reset = pci_ich9_reset;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
-}
-
-static const TypeInfo ich_ahci_info = {
- .name = TYPE_ICH9_AHCI,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(AHCIPCIState),
- .instance_init = pci_ich9_ahci_init,
- .class_init = ich_ahci_class_init,
-};
-
-static void ich_ahci_register_types(void)
-{
- type_register_static(&ich_ahci_info);
-}
-
-type_init(ich_ahci_register_types)
diff --git a/qemu/hw/ide/internal.h b/qemu/hw/ide/internal.h
deleted file mode 100644
index d2c458f57..000000000
--- a/qemu/hw/ide/internal.h
+++ /dev/null
@@ -1,635 +0,0 @@
-#ifndef HW_IDE_INTERNAL_H
-#define HW_IDE_INTERNAL_H
-
-/*
- * QEMU IDE Emulation -- internal header file
- * only files in hw/ide/ are supposed to include this file.
- * non-internal declarations are in hw/ide.h
- */
-#include <hw/ide.h>
-#include <hw/isa/isa.h>
-#include "sysemu/dma.h"
-#include "sysemu/sysemu.h"
-#include "hw/block/block.h"
-#include "block/scsi.h"
-
-/* debug IDE devices */
-//#define DEBUG_IDE
-//#define DEBUG_IDE_ATAPI
-//#define DEBUG_AIO
-#define USE_DMA_CDROM
-
-typedef struct IDEBus IDEBus;
-typedef struct IDEDevice IDEDevice;
-typedef struct IDEState IDEState;
-typedef struct IDEDMA IDEDMA;
-typedef struct IDEDMAOps IDEDMAOps;
-
-#define TYPE_IDE_BUS "IDE"
-#define IDE_BUS(obj) OBJECT_CHECK(IDEBus, (obj), TYPE_IDE_BUS)
-
-/* Bits of HD_STATUS */
-#define ERR_STAT 0x01
-#define INDEX_STAT 0x02
-#define ECC_STAT 0x04 /* Corrected error */
-#define DRQ_STAT 0x08
-#define SEEK_STAT 0x10
-#define SRV_STAT 0x10
-#define WRERR_STAT 0x20
-#define READY_STAT 0x40
-#define BUSY_STAT 0x80
-
-/* Bits for HD_ERROR */
-#define MARK_ERR 0x01 /* Bad address mark */
-#define TRK0_ERR 0x02 /* couldn't find track 0 */
-#define ABRT_ERR 0x04 /* Command aborted */
-#define MCR_ERR 0x08 /* media change request */
-#define ID_ERR 0x10 /* ID field not found */
-#define MC_ERR 0x20 /* media changed */
-#define ECC_ERR 0x40 /* Uncorrectable ECC error */
-#define BBD_ERR 0x80 /* pre-EIDE meaning: block marked bad */
-#define ICRC_ERR 0x80 /* new meaning: CRC error during transfer */
-
-/* Bits of HD_NSECTOR */
-#define CD 0x01
-#define IO 0x02
-#define REL 0x04
-#define TAG_MASK 0xf8
-
-#define IDE_CMD_RESET 0x04
-#define IDE_CMD_DISABLE_IRQ 0x02
-
-/* ACS-2 T13/2015-D Table B.2 Command codes */
-#define WIN_NOP 0x00
-/* reserved 0x01..0x02 */
-#define CFA_REQ_EXT_ERROR_CODE 0x03 /* CFA Request Extended Error Code */
-/* reserved 0x04..0x05 */
-#define WIN_DSM 0x06
-/* reserved 0x07 */
-#define WIN_DEVICE_RESET 0x08
-/* reserved 0x09..0x0a */
-/* REQUEST SENSE DATA EXT 0x0B */
-/* reserved 0x0C..0x0F */
-#define WIN_RECAL 0x10 /* obsolete since ATA4 */
-/* obsolete since ATA3, retired in ATA4 0x11..0x1F */
-#define WIN_READ 0x20 /* 28-Bit */
-#define WIN_READ_ONCE 0x21 /* 28-Bit w/o retries, obsolete since ATA5 */
-/* obsolete since ATA4 0x22..0x23 */
-#define WIN_READ_EXT 0x24 /* 48-Bit */
-#define WIN_READDMA_EXT 0x25 /* 48-Bit */
-#define WIN_READDMA_QUEUED_EXT 0x26 /* 48-Bit, obsolete since ACS2 */
-#define WIN_READ_NATIVE_MAX_EXT 0x27 /* 48-Bit */
-/* reserved 0x28 */
-#define WIN_MULTREAD_EXT 0x29 /* 48-Bit */
-/* READ STREAM DMA EXT 0x2A */
-/* READ STREAM EXT 0x2B */
-/* reserved 0x2C..0x2E */
-/* READ LOG EXT 0x2F */
-#define WIN_WRITE 0x30 /* 28-Bit */
-#define WIN_WRITE_ONCE 0x31 /* 28-Bit w/o retries, obsolete since ATA5 */
-/* obsolete since ATA4 0x32..0x33 */
-#define WIN_WRITE_EXT 0x34 /* 48-Bit */
-#define WIN_WRITEDMA_EXT 0x35 /* 48-Bit */
-#define WIN_WRITEDMA_QUEUED_EXT 0x36 /* 48-Bit */
-#define WIN_SET_MAX_EXT 0x37 /* 48-Bit, obsolete since ACS2 */
-#define WIN_SET_MAX_EXT 0x37 /* 48-Bit */
-#define CFA_WRITE_SECT_WO_ERASE 0x38 /* CFA Write Sectors without erase */
-#define WIN_MULTWRITE_EXT 0x39 /* 48-Bit */
-/* WRITE STREAM DMA EXT 0x3A */
-/* WRITE STREAM EXT 0x3B */
-#define WIN_WRITE_VERIFY 0x3C /* 28-Bit, obsolete since ATA4 */
-/* WRITE DMA FUA EXT 0x3D */
-/* obsolete since ACS2 0x3E */
-/* WRITE LOG EXT 0x3F */
-#define WIN_VERIFY 0x40 /* 28-Bit - Read Verify Sectors */
-#define WIN_VERIFY_ONCE 0x41 /* 28-Bit - w/o retries, obsolete since ATA5 */
-#define WIN_VERIFY_EXT 0x42 /* 48-Bit */
-/* reserved 0x43..0x44 */
-/* WRITE UNCORRECTABLE EXT 0x45 */
-/* reserved 0x46 */
-/* READ LOG DMA EXT 0x47 */
-/* reserved 0x48..0x4F */
-/* obsolete since ATA4 0x50 */
-/* CONFIGURE STREAM 0x51 */
-/* reserved 0x52..0x56 */
-/* WRITE LOG DMA EXT 0x57 */
-/* reserved 0x58..0x5A */
-/* TRUSTED NON DATA 0x5B */
-/* TRUSTED RECEIVE 0x5C */
-/* TRUSTED RECEIVE DMA 0x5D */
-/* TRUSTED SEND 0x5E */
-/* TRUSTED SEND DMA 0x5F */
-/* READ FPDMA QUEUED 0x60 */
-/* WRITE FPDMA QUEUED 0x61 */
-/* reserved 0x62->0x6F */
-#define WIN_SEEK 0x70 /* obsolete since ATA7 */
-/* reserved 0x71-0x7F */
-/* vendor specific 0x80-0x86 */
-#define CFA_TRANSLATE_SECTOR 0x87 /* CFA Translate Sector */
-/* vendor specific 0x88-0x8F */
-#define WIN_DIAGNOSE 0x90
-#define WIN_SPECIFY 0x91 /* set drive geometry translation, obsolete since ATA6 */
-#define WIN_DOWNLOAD_MICROCODE 0x92
-/* DOWNLOAD MICROCODE DMA 0x93 */
-#define WIN_STANDBYNOW2 0x94 /* retired in ATA4 */
-#define WIN_IDLEIMMEDIATE2 0x95 /* force drive to become "ready", retired in ATA4 */
-#define WIN_STANDBY2 0x96 /* retired in ATA4 */
-#define WIN_SETIDLE2 0x97 /* retired in ATA4 */
-#define WIN_CHECKPOWERMODE2 0x98 /* retired in ATA4 */
-#define WIN_SLEEPNOW2 0x99 /* retired in ATA4 */
-/* vendor specific 0x9A */
-/* reserved 0x9B..0x9F */
-#define WIN_PACKETCMD 0xA0 /* Send a packet command. */
-#define WIN_PIDENTIFY 0xA1 /* identify ATAPI device */
-#define WIN_QUEUED_SERVICE 0xA2 /* obsolete since ACS2 */
-/* reserved 0xA3..0xAF */
-#define WIN_SMART 0xB0 /* self-monitoring and reporting */
-/* Device Configuration Overlay 0xB1 */
-/* reserved 0xB2..0xB3 */
-/* Sanitize Device 0xB4 */
-/* reserved 0xB5 */
-/* NV Cache 0xB6 */
-/* reserved for CFA 0xB7..0xBB */
-#define CFA_ACCESS_METADATA_STORAGE 0xB8
-/* reserved 0xBC..0xBF */
-#define CFA_ERASE_SECTORS 0xC0 /* microdrives implement as NOP */
-/* vendor specific 0xC1..0xC3 */
-#define WIN_MULTREAD 0xC4 /* read sectors using multiple mode*/
-#define WIN_MULTWRITE 0xC5 /* write sectors using multiple mode */
-#define WIN_SETMULT 0xC6 /* enable/disable multiple mode */
-#define WIN_READDMA_QUEUED 0xC7 /* read sectors using Queued DMA transfers, obsolete since ACS2 */
-#define WIN_READDMA 0xC8 /* read sectors using DMA transfers */
-#define WIN_READDMA_ONCE 0xC9 /* 28-Bit - w/o retries, obsolete since ATA5 */
-#define WIN_WRITEDMA 0xCA /* write sectors using DMA transfers */
-#define WIN_WRITEDMA_ONCE 0xCB /* 28-Bit - w/o retries, obsolete since ATA5 */
-#define WIN_WRITEDMA_QUEUED 0xCC /* write sectors using Queued DMA transfers, obsolete since ACS2 */
-#define CFA_WRITE_MULTI_WO_ERASE 0xCD /* CFA Write multiple without erase */
-/* WRITE MULTIPLE FUA EXT 0xCE */
-/* reserved 0xCF..0xDO */
-/* CHECK MEDIA CARD TYPE 0xD1 */
-/* reserved for media card pass through 0xD2..0xD4 */
-/* reserved 0xD5..0xD9 */
-#define WIN_GETMEDIASTATUS 0xDA /* obsolete since ATA8 */
-/* obsolete since ATA3, retired in ATA4 0xDB..0xDD */
-#define WIN_DOORLOCK 0xDE /* lock door on removable drives, obsolete since ATA8 */
-#define WIN_DOORUNLOCK 0xDF /* unlock door on removable drives, obsolete since ATA8 */
-#define WIN_STANDBYNOW1 0xE0
-#define WIN_IDLEIMMEDIATE 0xE1 /* force drive to become "ready" */
-#define WIN_STANDBY 0xE2 /* Set device in Standby Mode */
-#define WIN_SETIDLE1 0xE3
-#define WIN_READ_BUFFER 0xE4 /* force read only 1 sector */
-#define WIN_CHECKPOWERMODE1 0xE5
-#define WIN_SLEEPNOW1 0xE6
-#define WIN_FLUSH_CACHE 0xE7
-#define WIN_WRITE_BUFFER 0xE8 /* force write only 1 sector */
-/* READ BUFFER DMA 0xE9 */
-#define WIN_FLUSH_CACHE_EXT 0xEA /* 48-Bit */
-/* WRITE BUFFER DMA 0xEB */
-#define WIN_IDENTIFY 0xEC /* ask drive to identify itself */
-#define WIN_MEDIAEJECT 0xED /* obsolete since ATA8 */
-/* obsolete since ATA4 0xEE */
-#define WIN_SETFEATURES 0xEF /* set special drive features */
-#define IBM_SENSE_CONDITION 0xF0 /* measure disk temperature, vendor specific */
-#define WIN_SECURITY_SET_PASS 0xF1
-#define WIN_SECURITY_UNLOCK 0xF2
-#define WIN_SECURITY_ERASE_PREPARE 0xF3
-#define WIN_SECURITY_ERASE_UNIT 0xF4
-#define WIN_SECURITY_FREEZE_LOCK 0xF5
-#define CFA_WEAR_LEVEL 0xF5 /* microdrives implement as NOP; not specified in T13! */
-#define WIN_SECURITY_DISABLE 0xF6
-/* vendor specific 0xF7 */
-#define WIN_READ_NATIVE_MAX 0xF8 /* return the native maximum address */
-#define WIN_SET_MAX 0xF9
-/* vendor specific 0xFA..0xFF */
-
-/* set to 1 set disable mult support */
-#define MAX_MULT_SECTORS 16
-
-#define IDE_DMA_BUF_SECTORS 256
-
-/* feature values for Data Set Management */
-#define DSM_TRIM 0x01
-
-#if (IDE_DMA_BUF_SECTORS < MAX_MULT_SECTORS)
-#error "IDE_DMA_BUF_SECTORS must be bigger or equal to MAX_MULT_SECTORS"
-#endif
-
-/* ATAPI defines */
-
-#define ATAPI_PACKET_SIZE 12
-
-/* The generic packet command opcodes for CD/DVD Logical Units,
- * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
-#define GPCMD_BLANK 0xa1
-#define GPCMD_CLOSE_TRACK 0x5b
-#define GPCMD_FLUSH_CACHE 0x35
-#define GPCMD_FORMAT_UNIT 0x04
-#define GPCMD_GET_CONFIGURATION 0x46
-#define GPCMD_GET_EVENT_STATUS_NOTIFICATION 0x4a
-#define GPCMD_GET_PERFORMANCE 0xac
-#define GPCMD_INQUIRY 0x12
-#define GPCMD_LOAD_UNLOAD 0xa6
-#define GPCMD_MECHANISM_STATUS 0xbd
-#define GPCMD_MODE_SELECT_10 0x55
-#define GPCMD_MODE_SENSE_10 0x5a
-#define GPCMD_PAUSE_RESUME 0x4b
-#define GPCMD_PLAY_AUDIO_10 0x45
-#define GPCMD_PLAY_AUDIO_MSF 0x47
-#define GPCMD_PLAY_AUDIO_TI 0x48
-#define GPCMD_PLAY_CD 0xbc
-#define GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e
-#define GPCMD_READ_10 0x28
-#define GPCMD_READ_12 0xa8
-#define GPCMD_READ_CDVD_CAPACITY 0x25
-#define GPCMD_READ_CD 0xbe
-#define GPCMD_READ_CD_MSF 0xb9
-#define GPCMD_READ_DISC_INFO 0x51
-#define GPCMD_READ_DVD_STRUCTURE 0xad
-#define GPCMD_READ_FORMAT_CAPACITIES 0x23
-#define GPCMD_READ_HEADER 0x44
-#define GPCMD_READ_TRACK_RZONE_INFO 0x52
-#define GPCMD_READ_SUBCHANNEL 0x42
-#define GPCMD_READ_TOC_PMA_ATIP 0x43
-#define GPCMD_REPAIR_RZONE_TRACK 0x58
-#define GPCMD_REPORT_KEY 0xa4
-#define GPCMD_REQUEST_SENSE 0x03
-#define GPCMD_RESERVE_RZONE_TRACK 0x53
-#define GPCMD_SCAN 0xba
-#define GPCMD_SEEK 0x2b
-#define GPCMD_SEND_DVD_STRUCTURE 0xad
-#define GPCMD_SEND_EVENT 0xa2
-#define GPCMD_SEND_KEY 0xa3
-#define GPCMD_SEND_OPC 0x54
-#define GPCMD_SET_READ_AHEAD 0xa7
-#define GPCMD_SET_STREAMING 0xb6
-#define GPCMD_START_STOP_UNIT 0x1b
-#define GPCMD_STOP_PLAY_SCAN 0x4e
-#define GPCMD_TEST_UNIT_READY 0x00
-#define GPCMD_VERIFY_10 0x2f
-#define GPCMD_WRITE_10 0x2a
-#define GPCMD_WRITE_AND_VERIFY_10 0x2e
-/* This is listed as optional in ATAPI 2.6, but is (curiously)
- * missing from Mt. Fuji, Table 57. It _is_ mentioned in Mt. Fuji
- * Table 377 as an MMC command for SCSi devices though... Most ATAPI
- * drives support it. */
-#define GPCMD_SET_SPEED 0xbb
-/* This seems to be a SCSI specific CD-ROM opcode
- * to play data at track/index */
-#define GPCMD_PLAYAUDIO_TI 0x48
-/*
- * From MS Media Status Notification Support Specification. For
- * older drives only.
- */
-#define GPCMD_GET_MEDIA_STATUS 0xda
-#define GPCMD_MODE_SENSE_6 0x1a
-
-#define ATAPI_INT_REASON_CD 0x01 /* 0 = data transfer */
-#define ATAPI_INT_REASON_IO 0x02 /* 1 = transfer to the host */
-#define ATAPI_INT_REASON_REL 0x04
-#define ATAPI_INT_REASON_TAG 0xf8
-
-/* same constants as bochs */
-#define ASC_NO_SEEK_COMPLETE 0x02
-#define ASC_ILLEGAL_OPCODE 0x20
-#define ASC_LOGICAL_BLOCK_OOR 0x21
-#define ASC_INV_FIELD_IN_CMD_PACKET 0x24
-#define ASC_MEDIUM_MAY_HAVE_CHANGED 0x28
-#define ASC_INCOMPATIBLE_FORMAT 0x30
-#define ASC_MEDIUM_NOT_PRESENT 0x3a
-#define ASC_SAVING_PARAMETERS_NOT_SUPPORTED 0x39
-#define ASC_DATA_PHASE_ERROR 0x4b
-#define ASC_MEDIA_REMOVAL_PREVENTED 0x53
-
-#define CFA_NO_ERROR 0x00
-#define CFA_MISC_ERROR 0x09
-#define CFA_INVALID_COMMAND 0x20
-#define CFA_INVALID_ADDRESS 0x21
-#define CFA_ADDRESS_OVERFLOW 0x2f
-
-#define SMART_READ_DATA 0xd0
-#define SMART_READ_THRESH 0xd1
-#define SMART_ATTR_AUTOSAVE 0xd2
-#define SMART_SAVE_ATTR 0xd3
-#define SMART_EXECUTE_OFFLINE 0xd4
-#define SMART_READ_LOG 0xd5
-#define SMART_WRITE_LOG 0xd6
-#define SMART_ENABLE 0xd8
-#define SMART_DISABLE 0xd9
-#define SMART_STATUS 0xda
-
-typedef enum { IDE_HD, IDE_CD, IDE_CFATA } IDEDriveKind;
-
-typedef void EndTransferFunc(IDEState *);
-
-typedef void DMAStartFunc(IDEDMA *, IDEState *, BlockCompletionFunc *);
-typedef void DMAVoidFunc(IDEDMA *);
-typedef int DMAIntFunc(IDEDMA *, int);
-typedef int32_t DMAInt32Func(IDEDMA *, int32_t len);
-typedef void DMAu32Func(IDEDMA *, uint32_t);
-typedef void DMAStopFunc(IDEDMA *, bool);
-typedef void DMARestartFunc(void *, int, RunState);
-
-struct unreported_events {
- bool eject_request;
- bool new_media;
-};
-
-enum ide_dma_cmd {
- IDE_DMA_READ,
- IDE_DMA_WRITE,
- IDE_DMA_TRIM,
- IDE_DMA_ATAPI,
-};
-
-#define ide_cmd_is_read(s) \
- ((s)->dma_cmd == IDE_DMA_READ)
-
-typedef struct IDEBufferedRequest {
- QLIST_ENTRY(IDEBufferedRequest) list;
- struct iovec iov;
- QEMUIOVector qiov;
- QEMUIOVector *original_qiov;
- BlockCompletionFunc *original_cb;
- void *original_opaque;
- bool orphaned;
-} IDEBufferedRequest;
-
-/* NOTE: IDEState represents in fact one drive */
-struct IDEState {
- IDEBus *bus;
- uint8_t unit;
- /* ide config */
- IDEDriveKind drive_kind;
- int cylinders, heads, sectors, chs_trans;
- int64_t nb_sectors;
- int mult_sectors;
- int identify_set;
- uint8_t identify_data[512];
- int drive_serial;
- char drive_serial_str[21];
- char drive_model_str[41];
- uint64_t wwn;
- /* ide regs */
- uint8_t feature;
- uint8_t error;
- uint32_t nsector;
- uint8_t sector;
- uint8_t lcyl;
- uint8_t hcyl;
- /* other part of tf for lba48 support */
- uint8_t hob_feature;
- uint8_t hob_nsector;
- uint8_t hob_sector;
- uint8_t hob_lcyl;
- uint8_t hob_hcyl;
-
- uint8_t select;
- uint8_t status;
-
- /* set for lba48 access */
- uint8_t lba48;
- BlockBackend *blk;
- char version[9];
- /* ATAPI specific */
- struct unreported_events events;
- uint8_t sense_key;
- uint8_t asc;
- bool tray_open;
- bool tray_locked;
- uint8_t cdrom_changed;
- int packet_transfer_size;
- int elementary_transfer_size;
- int32_t io_buffer_index;
- int lba;
- int cd_sector_size;
- int atapi_dma; /* true if dma is requested for the packet cmd */
- BlockAcctCookie acct;
- BlockAIOCB *pio_aiocb;
- struct iovec iov;
- QEMUIOVector qiov;
- QLIST_HEAD(, IDEBufferedRequest) buffered_requests;
- /* ATA DMA state */
- uint64_t io_buffer_offset;
- int32_t io_buffer_size;
- QEMUSGList sg;
- /* PIO transfer handling */
- int req_nb_sectors; /* number of sectors per interrupt */
- EndTransferFunc *end_transfer_func;
- uint8_t *data_ptr;
- uint8_t *data_end;
- uint8_t *io_buffer;
- /* PIO save/restore */
- int32_t io_buffer_total_len;
- int32_t cur_io_buffer_offset;
- int32_t cur_io_buffer_len;
- uint8_t end_transfer_fn_idx;
- QEMUTimer *sector_write_timer; /* only used for win2k install hack */
- uint32_t irq_count; /* counts IRQs when using win2k install hack */
- /* CF-ATA extended error */
- uint8_t ext_error;
- /* CF-ATA metadata storage */
- uint32_t mdata_size;
- uint8_t *mdata_storage;
- int media_changed;
- enum ide_dma_cmd dma_cmd;
- /* SMART */
- uint8_t smart_enabled;
- uint8_t smart_autosave;
- int smart_errors;
- uint8_t smart_selftest_count;
- uint8_t *smart_selftest_data;
- /* AHCI */
- int ncq_queues;
-};
-
-struct IDEDMAOps {
- DMAStartFunc *start_dma;
- DMAVoidFunc *start_transfer;
- DMAInt32Func *prepare_buf;
- DMAu32Func *commit_buf;
- DMAIntFunc *rw_buf;
- DMAVoidFunc *restart;
- DMAVoidFunc *restart_dma;
- DMAStopFunc *set_inactive;
- DMAVoidFunc *cmd_done;
- DMAVoidFunc *reset;
-};
-
-struct IDEDMA {
- const struct IDEDMAOps *ops;
- struct iovec iov;
- QEMUIOVector qiov;
- BlockAIOCB *aiocb;
-};
-
-struct IDEBus {
- BusState qbus;
- IDEDevice *master;
- IDEDevice *slave;
- IDEState ifs[2];
- QEMUBH *bh;
-
- int bus_id;
- int max_units;
- IDEDMA *dma;
- uint8_t unit;
- uint8_t cmd;
- qemu_irq irq;
-
- int error_status;
- uint8_t retry_unit;
- int64_t retry_sector_num;
- uint32_t retry_nsector;
-};
-
-#define TYPE_IDE_DEVICE "ide-device"
-#define IDE_DEVICE(obj) \
- OBJECT_CHECK(IDEDevice, (obj), TYPE_IDE_DEVICE)
-#define IDE_DEVICE_CLASS(klass) \
- OBJECT_CLASS_CHECK(IDEDeviceClass, (klass), TYPE_IDE_DEVICE)
-#define IDE_DEVICE_GET_CLASS(obj) \
- OBJECT_GET_CLASS(IDEDeviceClass, (obj), TYPE_IDE_DEVICE)
-
-typedef struct IDEDeviceClass {
- DeviceClass parent_class;
- int (*init)(IDEDevice *dev);
-} IDEDeviceClass;
-
-struct IDEDevice {
- DeviceState qdev;
- uint32_t unit;
- BlockConf conf;
- int chs_trans;
- char *version;
- char *serial;
- char *model;
- uint64_t wwn;
-};
-
-/* These are used for the error_status field of IDEBus */
-#define IDE_RETRY_MASK 0xf8
-#define IDE_RETRY_DMA 0x08
-#define IDE_RETRY_PIO 0x10
-#define IDE_RETRY_ATAPI 0x20 /* reused IDE_RETRY_READ bit */
-#define IDE_RETRY_READ 0x20
-#define IDE_RETRY_FLUSH 0x40
-#define IDE_RETRY_TRIM 0x80
-#define IDE_RETRY_HBA 0x100
-
-#define IS_IDE_RETRY_DMA(_status) \
- ((_status) & IDE_RETRY_DMA)
-
-#define IS_IDE_RETRY_PIO(_status) \
- ((_status) & IDE_RETRY_PIO)
-
-/*
- * The method of the IDE_RETRY_ATAPI determination is to use a previously
- * impossible bit combination as a new status value.
- */
-#define IS_IDE_RETRY_ATAPI(_status) \
- (((_status) & IDE_RETRY_MASK) == IDE_RETRY_ATAPI)
-
-static inline uint8_t ide_dma_cmd_to_retry(uint8_t dma_cmd)
-{
- switch (dma_cmd) {
- case IDE_DMA_READ:
- return IDE_RETRY_DMA | IDE_RETRY_READ;
- case IDE_DMA_WRITE:
- return IDE_RETRY_DMA;
- case IDE_DMA_TRIM:
- return IDE_RETRY_DMA | IDE_RETRY_TRIM;
- case IDE_DMA_ATAPI:
- return IDE_RETRY_ATAPI;
- default:
- break;
- }
- return 0;
-}
-
-static inline IDEState *idebus_active_if(IDEBus *bus)
-{
- return bus->ifs + bus->unit;
-}
-
-static inline void ide_set_irq(IDEBus *bus)
-{
- if (!(bus->cmd & IDE_CMD_DISABLE_IRQ)) {
- qemu_irq_raise(bus->irq);
- }
-}
-
-/* hw/ide/core.c */
-extern const VMStateDescription vmstate_ide_bus;
-
-#define VMSTATE_IDE_BUS(_field, _state) \
- VMSTATE_STRUCT(_field, _state, 1, vmstate_ide_bus, IDEBus)
-
-#define VMSTATE_IDE_BUS_ARRAY(_field, _state, _num) \
- VMSTATE_STRUCT_ARRAY(_field, _state, _num, 1, vmstate_ide_bus, IDEBus)
-
-extern const VMStateDescription vmstate_ide_drive;
-
-#define VMSTATE_IDE_DRIVES(_field, _state) \
- VMSTATE_STRUCT_ARRAY(_field, _state, 2, 3, vmstate_ide_drive, IDEState)
-
-#define VMSTATE_IDE_DRIVE(_field, _state) \
- VMSTATE_STRUCT(_field, _state, 1, vmstate_ide_drive, IDEState)
-
-void ide_bus_reset(IDEBus *bus);
-int64_t ide_get_sector(IDEState *s);
-void ide_set_sector(IDEState *s, int64_t sector_num);
-
-void ide_start_dma(IDEState *s, BlockCompletionFunc *cb);
-void dma_buf_commit(IDEState *s, uint32_t tx_bytes);
-void ide_dma_error(IDEState *s);
-void ide_abort_command(IDEState *s);
-
-void ide_atapi_cmd_ok(IDEState *s);
-void ide_atapi_cmd_error(IDEState *s, int sense_key, int asc);
-void ide_atapi_dma_restart(IDEState *s);
-void ide_atapi_io_error(IDEState *s, int ret);
-
-void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val);
-uint32_t ide_ioport_read(void *opaque, uint32_t addr1);
-uint32_t ide_status_read(void *opaque, uint32_t addr);
-void ide_cmd_write(void *opaque, uint32_t addr, uint32_t val);
-void ide_data_writew(void *opaque, uint32_t addr, uint32_t val);
-uint32_t ide_data_readw(void *opaque, uint32_t addr);
-void ide_data_writel(void *opaque, uint32_t addr, uint32_t val);
-uint32_t ide_data_readl(void *opaque, uint32_t addr);
-
-int ide_init_drive(IDEState *s, BlockBackend *blk, IDEDriveKind kind,
- const char *version, const char *serial, const char *model,
- uint64_t wwn,
- uint32_t cylinders, uint32_t heads, uint32_t secs,
- int chs_trans);
-void ide_init2(IDEBus *bus, qemu_irq irq);
-void ide_init_ioport(IDEBus *bus, ISADevice *isa, int iobase, int iobase2);
-void ide_register_restart_cb(IDEBus *bus);
-
-void ide_exec_cmd(IDEBus *bus, uint32_t val);
-
-void ide_transfer_start(IDEState *s, uint8_t *buf, int size,
- EndTransferFunc *end_transfer_func);
-void ide_transfer_stop(IDEState *s);
-void ide_set_inactive(IDEState *s, bool more);
-BlockAIOCB *ide_issue_trim(BlockBackend *blk,
- int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
- BlockCompletionFunc *cb, void *opaque);
-BlockAIOCB *ide_buffered_readv(IDEState *s, int64_t sector_num,
- QEMUIOVector *iov, int nb_sectors,
- BlockCompletionFunc *cb, void *opaque);
-void ide_cancel_dma_sync(IDEState *s);
-
-/* hw/ide/atapi.c */
-void ide_atapi_cmd(IDEState *s);
-void ide_atapi_cmd_reply_end(IDEState *s);
-
-/* hw/ide/qdev.c */
-void ide_bus_new(IDEBus *idebus, size_t idebus_size, DeviceState *dev,
- int bus_id, int max_units);
-IDEDevice *ide_create_drive(IDEBus *bus, int unit, DriveInfo *drive);
-
-int ide_handle_rw_error(IDEState *s, int error, int op);
-
-#endif /* HW_IDE_INTERNAL_H */
diff --git a/qemu/hw/ide/isa.c b/qemu/hw/ide/isa.c
deleted file mode 100644
index eba567c87..000000000
--- a/qemu/hw/ide/isa.c
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * QEMU IDE Emulation: ISA Bus support.
- *
- * Copyright (c) 2003 Fabrice Bellard
- * Copyright (c) 2006 Openedhand Ltd.
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include <hw/hw.h>
-#include <hw/i386/pc.h>
-#include <hw/isa/isa.h>
-#include "sysemu/block-backend.h"
-#include "sysemu/dma.h"
-
-#include <hw/ide/internal.h>
-
-/***********************************************************/
-/* ISA IDE definitions */
-
-#define TYPE_ISA_IDE "isa-ide"
-#define ISA_IDE(obj) OBJECT_CHECK(ISAIDEState, (obj), TYPE_ISA_IDE)
-
-typedef struct ISAIDEState {
- ISADevice parent_obj;
-
- IDEBus bus;
- uint32_t iobase;
- uint32_t iobase2;
- uint32_t isairq;
- qemu_irq irq;
-} ISAIDEState;
-
-static void isa_ide_reset(DeviceState *d)
-{
- ISAIDEState *s = ISA_IDE(d);
-
- ide_bus_reset(&s->bus);
-}
-
-static const VMStateDescription vmstate_ide_isa = {
- .name = "isa-ide",
- .version_id = 3,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_IDE_BUS(bus, ISAIDEState),
- VMSTATE_IDE_DRIVES(bus.ifs, ISAIDEState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void isa_ide_realizefn(DeviceState *dev, Error **errp)
-{
- ISADevice *isadev = ISA_DEVICE(dev);
- ISAIDEState *s = ISA_IDE(dev);
-
- ide_bus_new(&s->bus, sizeof(s->bus), dev, 0, 2);
- ide_init_ioport(&s->bus, isadev, s->iobase, s->iobase2);
- isa_init_irq(isadev, &s->irq, s->isairq);
- ide_init2(&s->bus, s->irq);
- vmstate_register(dev, 0, &vmstate_ide_isa, s);
- ide_register_restart_cb(&s->bus);
-}
-
-ISADevice *isa_ide_init(ISABus *bus, int iobase, int iobase2, int isairq,
- DriveInfo *hd0, DriveInfo *hd1)
-{
- DeviceState *dev;
- ISADevice *isadev;
- ISAIDEState *s;
-
- isadev = isa_create(bus, TYPE_ISA_IDE);
- dev = DEVICE(isadev);
- qdev_prop_set_uint32(dev, "iobase", iobase);
- qdev_prop_set_uint32(dev, "iobase2", iobase2);
- qdev_prop_set_uint32(dev, "irq", isairq);
- qdev_init_nofail(dev);
-
- s = ISA_IDE(dev);
- if (hd0) {
- ide_create_drive(&s->bus, 0, hd0);
- }
- if (hd1) {
- ide_create_drive(&s->bus, 1, hd1);
- }
- return isadev;
-}
-
-static Property isa_ide_properties[] = {
- DEFINE_PROP_UINT32("iobase", ISAIDEState, iobase, 0x1f0),
- DEFINE_PROP_UINT32("iobase2", ISAIDEState, iobase2, 0x3f6),
- DEFINE_PROP_UINT32("irq", ISAIDEState, isairq, 14),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void isa_ide_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = isa_ide_realizefn;
- dc->fw_name = "ide";
- dc->reset = isa_ide_reset;
- dc->props = isa_ide_properties;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
-}
-
-static const TypeInfo isa_ide_info = {
- .name = TYPE_ISA_IDE,
- .parent = TYPE_ISA_DEVICE,
- .instance_size = sizeof(ISAIDEState),
- .class_init = isa_ide_class_initfn,
-};
-
-static void isa_ide_register_types(void)
-{
- type_register_static(&isa_ide_info);
-}
-
-type_init(isa_ide_register_types)
diff --git a/qemu/hw/ide/macio.c b/qemu/hw/ide/macio.c
deleted file mode 100644
index 76256eb8a..000000000
--- a/qemu/hw/ide/macio.c
+++ /dev/null
@@ -1,642 +0,0 @@
-/*
- * QEMU IDE Emulation: MacIO support.
- *
- * Copyright (c) 2003 Fabrice Bellard
- * Copyright (c) 2006 Openedhand Ltd.
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/ppc/mac.h"
-#include "hw/ppc/mac_dbdma.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/dma.h"
-
-#include <hw/ide/internal.h>
-
-/* debug MACIO */
-// #define DEBUG_MACIO
-
-#ifdef DEBUG_MACIO
-static const int debug_macio = 1;
-#else
-static const int debug_macio = 0;
-#endif
-
-#define MACIO_DPRINTF(fmt, ...) do { \
- if (debug_macio) { \
- printf(fmt , ## __VA_ARGS__); \
- } \
- } while (0)
-
-
-/***********************************************************/
-/* MacIO based PowerPC IDE */
-
-#define MACIO_PAGE_SIZE 4096
-
-/*
- * Unaligned DMA read/write access functions required for OS X/Darwin which
- * don't perform DMA transactions on sector boundaries. These functions are
- * modelled on bdrv_co_do_preadv()/bdrv_co_do_pwritev() and so should be
- * easy to remove if the unaligned block APIs are ever exposed.
- */
-
-static void pmac_dma_read(BlockBackend *blk,
- int64_t offset, unsigned int bytes,
- void (*cb)(void *opaque, int ret), void *opaque)
-{
- DBDMA_io *io = opaque;
- MACIOIDEState *m = io->opaque;
- IDEState *s = idebus_active_if(&m->bus);
- dma_addr_t dma_addr, dma_len;
- void *mem;
- int64_t sector_num;
- int nsector;
- uint64_t align = BDRV_SECTOR_SIZE;
- size_t head_bytes, tail_bytes;
-
- qemu_iovec_destroy(&io->iov);
- qemu_iovec_init(&io->iov, io->len / MACIO_PAGE_SIZE + 1);
-
- sector_num = (offset >> 9);
- nsector = (io->len >> 9);
-
- MACIO_DPRINTF("--- DMA read transfer (0x%" HWADDR_PRIx ",0x%x): "
- "sector_num: %" PRId64 ", nsector: %d\n", io->addr, io->len,
- sector_num, nsector);
-
- dma_addr = io->addr;
- dma_len = io->len;
- mem = dma_memory_map(&address_space_memory, dma_addr, &dma_len,
- DMA_DIRECTION_FROM_DEVICE);
-
- if (offset & (align - 1)) {
- head_bytes = offset & (align - 1);
-
- MACIO_DPRINTF("--- DMA unaligned head: sector %" PRId64 ", "
- "discarding %zu bytes\n", sector_num, head_bytes);
-
- qemu_iovec_add(&io->iov, &io->head_remainder, head_bytes);
-
- bytes += offset & (align - 1);
- offset = offset & ~(align - 1);
- }
-
- qemu_iovec_add(&io->iov, mem, io->len);
-
- if ((offset + bytes) & (align - 1)) {
- tail_bytes = (offset + bytes) & (align - 1);
-
- MACIO_DPRINTF("--- DMA unaligned tail: sector %" PRId64 ", "
- "discarding bytes %zu\n", sector_num, tail_bytes);
-
- qemu_iovec_add(&io->iov, &io->tail_remainder, align - tail_bytes);
- bytes = ROUND_UP(bytes, align);
- }
-
- s->io_buffer_size -= io->len;
- s->io_buffer_index += io->len;
-
- io->len = 0;
-
- MACIO_DPRINTF("--- Block read transfer - sector_num: %" PRIx64 " "
- "nsector: %x\n", (offset >> 9), (bytes >> 9));
-
- s->bus->dma->aiocb = blk_aio_readv(blk, (offset >> 9), &io->iov,
- (bytes >> 9), cb, io);
-}
-
-static void pmac_dma_write(BlockBackend *blk,
- int64_t offset, int bytes,
- void (*cb)(void *opaque, int ret), void *opaque)
-{
- DBDMA_io *io = opaque;
- MACIOIDEState *m = io->opaque;
- IDEState *s = idebus_active_if(&m->bus);
- dma_addr_t dma_addr, dma_len;
- void *mem;
- int64_t sector_num;
- int nsector;
- uint64_t align = BDRV_SECTOR_SIZE;
- size_t head_bytes, tail_bytes;
- bool unaligned_head = false, unaligned_tail = false;
-
- qemu_iovec_destroy(&io->iov);
- qemu_iovec_init(&io->iov, io->len / MACIO_PAGE_SIZE + 1);
-
- sector_num = (offset >> 9);
- nsector = (io->len >> 9);
-
- MACIO_DPRINTF("--- DMA write transfer (0x%" HWADDR_PRIx ",0x%x): "
- "sector_num: %" PRId64 ", nsector: %d\n", io->addr, io->len,
- sector_num, nsector);
-
- dma_addr = io->addr;
- dma_len = io->len;
- mem = dma_memory_map(&address_space_memory, dma_addr, &dma_len,
- DMA_DIRECTION_TO_DEVICE);
-
- if (offset & (align - 1)) {
- head_bytes = offset & (align - 1);
- sector_num = ((offset & ~(align - 1)) >> 9);
-
- MACIO_DPRINTF("--- DMA unaligned head: pre-reading head sector %"
- PRId64 "\n", sector_num);
-
- blk_pread(s->blk, (sector_num << 9), &io->head_remainder, align);
-
- qemu_iovec_add(&io->iov, &io->head_remainder, head_bytes);
- qemu_iovec_add(&io->iov, mem, io->len);
-
- bytes += offset & (align - 1);
- offset = offset & ~(align - 1);
-
- unaligned_head = true;
- }
-
- if ((offset + bytes) & (align - 1)) {
- tail_bytes = (offset + bytes) & (align - 1);
- sector_num = (((offset + bytes) & ~(align - 1)) >> 9);
-
- MACIO_DPRINTF("--- DMA unaligned tail: pre-reading tail sector %"
- PRId64 "\n", sector_num);
-
- blk_pread(s->blk, (sector_num << 9), &io->tail_remainder, align);
-
- if (!unaligned_head) {
- qemu_iovec_add(&io->iov, mem, io->len);
- }
-
- qemu_iovec_add(&io->iov, &io->tail_remainder + tail_bytes,
- align - tail_bytes);
-
- bytes = ROUND_UP(bytes, align);
-
- unaligned_tail = true;
- }
-
- if (!unaligned_head && !unaligned_tail) {
- qemu_iovec_add(&io->iov, mem, io->len);
- }
-
- s->io_buffer_size -= io->len;
- s->io_buffer_index += io->len;
-
- io->len = 0;
-
- MACIO_DPRINTF("--- Block write transfer - sector_num: %" PRIx64 " "
- "nsector: %x\n", (offset >> 9), (bytes >> 9));
-
- s->bus->dma->aiocb = blk_aio_writev(blk, (offset >> 9), &io->iov,
- (bytes >> 9), cb, io);
-}
-
-static void pmac_dma_trim(BlockBackend *blk,
- int64_t offset, int bytes,
- void (*cb)(void *opaque, int ret), void *opaque)
-{
- DBDMA_io *io = opaque;
- MACIOIDEState *m = io->opaque;
- IDEState *s = idebus_active_if(&m->bus);
- dma_addr_t dma_addr, dma_len;
- void *mem;
-
- qemu_iovec_destroy(&io->iov);
- qemu_iovec_init(&io->iov, io->len / MACIO_PAGE_SIZE + 1);
-
- dma_addr = io->addr;
- dma_len = io->len;
- mem = dma_memory_map(&address_space_memory, dma_addr, &dma_len,
- DMA_DIRECTION_TO_DEVICE);
-
- qemu_iovec_add(&io->iov, mem, io->len);
- s->io_buffer_size -= io->len;
- s->io_buffer_index += io->len;
- io->len = 0;
-
- s->bus->dma->aiocb = ide_issue_trim(blk, (offset >> 9), &io->iov,
- (bytes >> 9), cb, io);
-}
-
-static void pmac_ide_atapi_transfer_cb(void *opaque, int ret)
-{
- DBDMA_io *io = opaque;
- MACIOIDEState *m = io->opaque;
- IDEState *s = idebus_active_if(&m->bus);
- int64_t offset;
-
- MACIO_DPRINTF("pmac_ide_atapi_transfer_cb\n");
-
- if (ret < 0) {
- MACIO_DPRINTF("DMA error: %d\n", ret);
- ide_atapi_io_error(s, ret);
- goto done;
- }
-
- if (!m->dma_active) {
- MACIO_DPRINTF("waiting for data (%#x - %#x - %x)\n",
- s->nsector, io->len, s->status);
- /* data not ready yet, wait for the channel to get restarted */
- io->processing = false;
- return;
- }
-
- if (s->io_buffer_size <= 0) {
- MACIO_DPRINTF("End of IDE transfer\n");
- ide_atapi_cmd_ok(s);
- m->dma_active = false;
- goto done;
- }
-
- if (io->len == 0) {
- MACIO_DPRINTF("End of DMA transfer\n");
- goto done;
- }
-
- if (s->lba == -1) {
- /* Non-block ATAPI transfer - just copy to RAM */
- s->io_buffer_size = MIN(s->io_buffer_size, io->len);
- cpu_physical_memory_write(io->addr, s->io_buffer, s->io_buffer_size);
- ide_atapi_cmd_ok(s);
- m->dma_active = false;
- goto done;
- }
-
- /* Calculate current offset */
- offset = ((int64_t)s->lba << 11) + s->io_buffer_index;
-
- pmac_dma_read(s->blk, offset, io->len, pmac_ide_atapi_transfer_cb, io);
- return;
-
-done:
- if (ret < 0) {
- block_acct_failed(blk_get_stats(s->blk), &s->acct);
- } else {
- block_acct_done(blk_get_stats(s->blk), &s->acct);
- }
-
- ide_set_inactive(s, false);
- io->dma_end(opaque);
-}
-
-static void pmac_ide_transfer_cb(void *opaque, int ret)
-{
- DBDMA_io *io = opaque;
- MACIOIDEState *m = io->opaque;
- IDEState *s = idebus_active_if(&m->bus);
- int64_t offset;
-
- MACIO_DPRINTF("pmac_ide_transfer_cb\n");
-
- if (ret < 0) {
- MACIO_DPRINTF("DMA error: %d\n", ret);
- ide_dma_error(s);
- goto done;
- }
-
- if (!m->dma_active) {
- MACIO_DPRINTF("waiting for data (%#x - %#x - %x)\n",
- s->nsector, io->len, s->status);
- /* data not ready yet, wait for the channel to get restarted */
- io->processing = false;
- return;
- }
-
- if (s->io_buffer_size <= 0) {
- MACIO_DPRINTF("End of IDE transfer\n");
- s->status = READY_STAT | SEEK_STAT;
- ide_set_irq(s->bus);
- m->dma_active = false;
- goto done;
- }
-
- if (io->len == 0) {
- MACIO_DPRINTF("End of DMA transfer\n");
- goto done;
- }
-
- /* Calculate number of sectors */
- offset = (ide_get_sector(s) << 9) + s->io_buffer_index;
-
- switch (s->dma_cmd) {
- case IDE_DMA_READ:
- pmac_dma_read(s->blk, offset, io->len, pmac_ide_transfer_cb, io);
- break;
- case IDE_DMA_WRITE:
- pmac_dma_write(s->blk, offset, io->len, pmac_ide_transfer_cb, io);
- break;
- case IDE_DMA_TRIM:
- pmac_dma_trim(s->blk, offset, io->len, pmac_ide_transfer_cb, io);
- break;
- default:
- abort();
- }
-
- return;
-
-done:
- if (s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) {
- if (ret < 0) {
- block_acct_failed(blk_get_stats(s->blk), &s->acct);
- } else {
- block_acct_done(blk_get_stats(s->blk), &s->acct);
- }
- }
-
- ide_set_inactive(s, false);
- io->dma_end(opaque);
-}
-
-static void pmac_ide_transfer(DBDMA_io *io)
-{
- MACIOIDEState *m = io->opaque;
- IDEState *s = idebus_active_if(&m->bus);
-
- MACIO_DPRINTF("\n");
-
- if (s->drive_kind == IDE_CD) {
- block_acct_start(blk_get_stats(s->blk), &s->acct, io->len,
- BLOCK_ACCT_READ);
-
- pmac_ide_atapi_transfer_cb(io, 0);
- return;
- }
-
- switch (s->dma_cmd) {
- case IDE_DMA_READ:
- block_acct_start(blk_get_stats(s->blk), &s->acct, io->len,
- BLOCK_ACCT_READ);
- break;
- case IDE_DMA_WRITE:
- block_acct_start(blk_get_stats(s->blk), &s->acct, io->len,
- BLOCK_ACCT_WRITE);
- break;
- default:
- break;
- }
-
- pmac_ide_transfer_cb(io, 0);
-}
-
-static void pmac_ide_flush(DBDMA_io *io)
-{
- MACIOIDEState *m = io->opaque;
- IDEState *s = idebus_active_if(&m->bus);
-
- if (s->bus->dma->aiocb) {
- blk_drain_all();
- }
-}
-
-/* PowerMac IDE memory IO */
-static void pmac_ide_writeb (void *opaque,
- hwaddr addr, uint32_t val)
-{
- MACIOIDEState *d = opaque;
-
- addr = (addr & 0xFFF) >> 4;
- switch (addr) {
- case 1 ... 7:
- ide_ioport_write(&d->bus, addr, val);
- break;
- case 8:
- case 22:
- ide_cmd_write(&d->bus, 0, val);
- break;
- default:
- break;
- }
-}
-
-static uint32_t pmac_ide_readb (void *opaque,hwaddr addr)
-{
- uint8_t retval;
- MACIOIDEState *d = opaque;
-
- addr = (addr & 0xFFF) >> 4;
- switch (addr) {
- case 1 ... 7:
- retval = ide_ioport_read(&d->bus, addr);
- break;
- case 8:
- case 22:
- retval = ide_status_read(&d->bus, 0);
- break;
- default:
- retval = 0xFF;
- break;
- }
- return retval;
-}
-
-static void pmac_ide_writew (void *opaque,
- hwaddr addr, uint32_t val)
-{
- MACIOIDEState *d = opaque;
-
- addr = (addr & 0xFFF) >> 4;
- val = bswap16(val);
- if (addr == 0) {
- ide_data_writew(&d->bus, 0, val);
- }
-}
-
-static uint32_t pmac_ide_readw (void *opaque,hwaddr addr)
-{
- uint16_t retval;
- MACIOIDEState *d = opaque;
-
- addr = (addr & 0xFFF) >> 4;
- if (addr == 0) {
- retval = ide_data_readw(&d->bus, 0);
- } else {
- retval = 0xFFFF;
- }
- retval = bswap16(retval);
- return retval;
-}
-
-static void pmac_ide_writel (void *opaque,
- hwaddr addr, uint32_t val)
-{
- MACIOIDEState *d = opaque;
-
- addr = (addr & 0xFFF) >> 4;
- val = bswap32(val);
- if (addr == 0) {
- ide_data_writel(&d->bus, 0, val);
- }
-}
-
-static uint32_t pmac_ide_readl (void *opaque,hwaddr addr)
-{
- uint32_t retval;
- MACIOIDEState *d = opaque;
-
- addr = (addr & 0xFFF) >> 4;
- if (addr == 0) {
- retval = ide_data_readl(&d->bus, 0);
- } else {
- retval = 0xFFFFFFFF;
- }
- retval = bswap32(retval);
- return retval;
-}
-
-static const MemoryRegionOps pmac_ide_ops = {
- .old_mmio = {
- .write = {
- pmac_ide_writeb,
- pmac_ide_writew,
- pmac_ide_writel,
- },
- .read = {
- pmac_ide_readb,
- pmac_ide_readw,
- pmac_ide_readl,
- },
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_pmac = {
- .name = "ide",
- .version_id = 4,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_IDE_BUS(bus, MACIOIDEState),
- VMSTATE_IDE_DRIVES(bus.ifs, MACIOIDEState),
- VMSTATE_BOOL(dma_active, MACIOIDEState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void macio_ide_reset(DeviceState *dev)
-{
- MACIOIDEState *d = MACIO_IDE(dev);
-
- ide_bus_reset(&d->bus);
-}
-
-static int ide_nop_int(IDEDMA *dma, int x)
-{
- return 0;
-}
-
-static int32_t ide_nop_int32(IDEDMA *dma, int32_t l)
-{
- return 0;
-}
-
-static void ide_dbdma_start(IDEDMA *dma, IDEState *s,
- BlockCompletionFunc *cb)
-{
- MACIOIDEState *m = container_of(dma, MACIOIDEState, dma);
-
- s->io_buffer_index = 0;
- if (s->drive_kind == IDE_CD) {
- s->io_buffer_size = s->packet_transfer_size;
- } else {
- s->io_buffer_size = s->nsector * BDRV_SECTOR_SIZE;
- }
-
- MACIO_DPRINTF("\n\n------------ IDE transfer\n");
- MACIO_DPRINTF("buffer_size: %x buffer_index: %x\n",
- s->io_buffer_size, s->io_buffer_index);
- MACIO_DPRINTF("lba: %x size: %x\n", s->lba, s->io_buffer_size);
- MACIO_DPRINTF("-------------------------\n");
-
- m->dma_active = true;
- DBDMA_kick(m->dbdma);
-}
-
-static const IDEDMAOps dbdma_ops = {
- .start_dma = ide_dbdma_start,
- .prepare_buf = ide_nop_int32,
- .rw_buf = ide_nop_int,
-};
-
-static void macio_ide_realizefn(DeviceState *dev, Error **errp)
-{
- MACIOIDEState *s = MACIO_IDE(dev);
-
- ide_init2(&s->bus, s->irq);
-
- /* Register DMA callbacks */
- s->dma.ops = &dbdma_ops;
- s->bus.dma = &s->dma;
-}
-
-static void macio_ide_initfn(Object *obj)
-{
- SysBusDevice *d = SYS_BUS_DEVICE(obj);
- MACIOIDEState *s = MACIO_IDE(obj);
-
- ide_bus_new(&s->bus, sizeof(s->bus), DEVICE(obj), 0, 2);
- memory_region_init_io(&s->mem, obj, &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;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
-}
-
-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,
-};
-
-static void macio_ide_register_types(void)
-{
- type_register_static(&macio_ide_type_info);
-}
-
-/* hd_table must contain 2 block drivers */
-void macio_ide_init_drives(MACIOIDEState *s, DriveInfo **hd_table)
-{
- int i;
-
- 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)
-{
- s->dbdma = dbdma;
- DBDMA_register_channel(dbdma, channel, s->dma_irq,
- pmac_ide_transfer, pmac_ide_flush, s);
-}
-
-type_init(macio_ide_register_types)
diff --git a/qemu/hw/ide/microdrive.c b/qemu/hw/ide/microdrive.c
deleted file mode 100644
index 5c9db8047..000000000
--- a/qemu/hw/ide/microdrive.c
+++ /dev/null
@@ -1,638 +0,0 @@
-/*
- * QEMU IDE Emulation: microdrive (CF / PCMCIA)
- *
- * Copyright (c) 2003 Fabrice Bellard
- * Copyright (c) 2006 Openedhand Ltd.
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include <hw/hw.h>
-#include <hw/i386/pc.h>
-#include <hw/pcmcia.h>
-#include "sysemu/block-backend.h"
-#include "sysemu/dma.h"
-
-#include <hw/ide/internal.h>
-
-#define TYPE_MICRODRIVE "microdrive"
-#define MICRODRIVE(obj) OBJECT_CHECK(MicroDriveState, (obj), TYPE_MICRODRIVE)
-
-/***********************************************************/
-/* CF-ATA Microdrive */
-
-#define METADATA_SIZE 0x20
-
-/* DSCM-1XXXX Microdrive hard disk with CF+ II / PCMCIA interface. */
-
-typedef struct MicroDriveState {
- /*< private >*/
- PCMCIACardState parent_obj;
- /*< public >*/
-
- IDEBus bus;
- uint32_t attr_base;
- uint32_t io_base;
-
- /* Card state */
- uint8_t opt;
- uint8_t stat;
- uint8_t pins;
-
- uint8_t ctrl;
- uint16_t io;
- uint8_t cycle;
-} MicroDriveState;
-
-/* Register bitfields */
-enum md_opt {
- OPT_MODE_MMAP = 0,
- OPT_MODE_IOMAP16 = 1,
- OPT_MODE_IOMAP1 = 2,
- OPT_MODE_IOMAP2 = 3,
- OPT_MODE = 0x3f,
- OPT_LEVIREQ = 0x40,
- OPT_SRESET = 0x80,
-};
-enum md_cstat {
- STAT_INT = 0x02,
- STAT_PWRDWN = 0x04,
- STAT_XE = 0x10,
- STAT_IOIS8 = 0x20,
- STAT_SIGCHG = 0x40,
- STAT_CHANGED = 0x80,
-};
-enum md_pins {
- PINS_MRDY = 0x02,
- PINS_CRDY = 0x20,
-};
-enum md_ctrl {
- CTRL_IEN = 0x02,
- CTRL_SRST = 0x04,
-};
-
-static inline void md_interrupt_update(MicroDriveState *s)
-{
- PCMCIACardState *card = PCMCIA_CARD(s);
-
- if (card->slot == NULL) {
- return;
- }
-
- qemu_set_irq(card->slot->irq,
- !(s->stat & STAT_INT) && /* Inverted */
- !(s->ctrl & (CTRL_IEN | CTRL_SRST)) &&
- !(s->opt & OPT_SRESET));
-}
-
-static void md_set_irq(void *opaque, int irq, int level)
-{
- MicroDriveState *s = opaque;
-
- if (level) {
- s->stat |= STAT_INT;
- } else {
- s->stat &= ~STAT_INT;
- }
-
- md_interrupt_update(s);
-}
-
-static void md_reset(DeviceState *dev)
-{
- MicroDriveState *s = MICRODRIVE(dev);
-
- s->opt = OPT_MODE_MMAP;
- s->stat = 0;
- s->pins = 0;
- s->cycle = 0;
- s->ctrl = 0;
- ide_bus_reset(&s->bus);
-}
-
-static uint8_t md_attr_read(PCMCIACardState *card, uint32_t at)
-{
- MicroDriveState *s = MICRODRIVE(card);
- PCMCIACardClass *pcc = PCMCIA_CARD_GET_CLASS(card);
-
- if (at < s->attr_base) {
- if (at < pcc->cis_len) {
- return pcc->cis[at];
- } else {
- return 0x00;
- }
- }
-
- at -= s->attr_base;
-
- switch (at) {
- case 0x00: /* Configuration Option Register */
- return s->opt;
- case 0x02: /* Card Configuration Status Register */
- if (s->ctrl & CTRL_IEN) {
- return s->stat & ~STAT_INT;
- } else {
- return s->stat;
- }
- case 0x04: /* Pin Replacement Register */
- return (s->pins & PINS_CRDY) | 0x0c;
- case 0x06: /* Socket and Copy Register */
- return 0x00;
-#ifdef VERBOSE
- default:
- printf("%s: Bad attribute space register %02x\n", __FUNCTION__, at);
-#endif
- }
-
- return 0;
-}
-
-static void md_attr_write(PCMCIACardState *card, uint32_t at, uint8_t value)
-{
- MicroDriveState *s = MICRODRIVE(card);
-
- at -= s->attr_base;
-
- switch (at) {
- case 0x00: /* Configuration Option Register */
- s->opt = value & 0xcf;
- if (value & OPT_SRESET) {
- device_reset(DEVICE(s));
- }
- md_interrupt_update(s);
- break;
- case 0x02: /* Card Configuration Status Register */
- if ((s->stat ^ value) & STAT_PWRDWN) {
- s->pins |= PINS_CRDY;
- }
- s->stat &= 0x82;
- s->stat |= value & 0x74;
- md_interrupt_update(s);
- /* Word 170 in Identify Device must be equal to STAT_XE */
- break;
- case 0x04: /* Pin Replacement Register */
- s->pins &= PINS_CRDY;
- s->pins |= value & PINS_MRDY;
- break;
- case 0x06: /* Socket and Copy Register */
- break;
- default:
- printf("%s: Bad attribute space register %02x\n", __FUNCTION__, at);
- }
-}
-
-static uint16_t md_common_read(PCMCIACardState *card, uint32_t at)
-{
- MicroDriveState *s = MICRODRIVE(card);
- IDEState *ifs;
- uint16_t ret;
- at -= s->io_base;
-
- switch (s->opt & OPT_MODE) {
- case OPT_MODE_MMAP:
- if ((at & ~0x3ff) == 0x400) {
- at = 0;
- }
- break;
- case OPT_MODE_IOMAP16:
- at &= 0xf;
- break;
- case OPT_MODE_IOMAP1:
- if ((at & ~0xf) == 0x3f0) {
- at -= 0x3e8;
- } else if ((at & ~0xf) == 0x1f0) {
- at -= 0x1f0;
- }
- break;
- case OPT_MODE_IOMAP2:
- if ((at & ~0xf) == 0x370) {
- at -= 0x368;
- } else if ((at & ~0xf) == 0x170) {
- at -= 0x170;
- }
- }
-
- switch (at) {
- case 0x0: /* Even RD Data */
- case 0x8:
- return ide_data_readw(&s->bus, 0);
-
- /* TODO: 8-bit accesses */
- if (s->cycle) {
- ret = s->io >> 8;
- } else {
- s->io = ide_data_readw(&s->bus, 0);
- ret = s->io & 0xff;
- }
- s->cycle = !s->cycle;
- return ret;
- case 0x9: /* Odd RD Data */
- return s->io >> 8;
- case 0xd: /* Error */
- return ide_ioport_read(&s->bus, 0x1);
- case 0xe: /* Alternate Status */
- ifs = idebus_active_if(&s->bus);
- if (ifs->blk) {
- return ifs->status;
- } else {
- return 0;
- }
- case 0xf: /* Device Address */
- ifs = idebus_active_if(&s->bus);
- return 0xc2 | ((~ifs->select << 2) & 0x3c);
- default:
- return ide_ioport_read(&s->bus, at);
- }
-
- return 0;
-}
-
-static void md_common_write(PCMCIACardState *card, uint32_t at, uint16_t value)
-{
- MicroDriveState *s = MICRODRIVE(card);
- at -= s->io_base;
-
- switch (s->opt & OPT_MODE) {
- case OPT_MODE_MMAP:
- if ((at & ~0x3ff) == 0x400) {
- at = 0;
- }
- break;
- case OPT_MODE_IOMAP16:
- at &= 0xf;
- break;
- case OPT_MODE_IOMAP1:
- if ((at & ~0xf) == 0x3f0) {
- at -= 0x3e8;
- } else if ((at & ~0xf) == 0x1f0) {
- at -= 0x1f0;
- }
- break;
- case OPT_MODE_IOMAP2:
- if ((at & ~0xf) == 0x370) {
- at -= 0x368;
- } else if ((at & ~0xf) == 0x170) {
- at -= 0x170;
- }
- }
-
- switch (at) {
- case 0x0: /* Even WR Data */
- case 0x8:
- ide_data_writew(&s->bus, 0, value);
- break;
-
- /* TODO: 8-bit accesses */
- if (s->cycle) {
- ide_data_writew(&s->bus, 0, s->io | (value << 8));
- } else {
- s->io = value & 0xff;
- }
- s->cycle = !s->cycle;
- break;
- case 0x9:
- s->io = value & 0xff;
- s->cycle = !s->cycle;
- break;
- case 0xd: /* Features */
- ide_ioport_write(&s->bus, 0x1, value);
- break;
- case 0xe: /* Device Control */
- s->ctrl = value;
- if (value & CTRL_SRST) {
- device_reset(DEVICE(s));
- }
- md_interrupt_update(s);
- break;
- default:
- if (s->stat & STAT_PWRDWN) {
- s->pins |= PINS_CRDY;
- s->stat &= ~STAT_PWRDWN;
- }
- ide_ioport_write(&s->bus, at, value);
- }
-}
-
-static const VMStateDescription vmstate_microdrive = {
- .name = "microdrive",
- .version_id = 3,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(opt, MicroDriveState),
- VMSTATE_UINT8(stat, MicroDriveState),
- VMSTATE_UINT8(pins, MicroDriveState),
- VMSTATE_UINT8(ctrl, MicroDriveState),
- VMSTATE_UINT16(io, MicroDriveState),
- VMSTATE_UINT8(cycle, MicroDriveState),
- VMSTATE_IDE_BUS(bus, MicroDriveState),
- VMSTATE_IDE_DRIVES(bus.ifs, MicroDriveState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const uint8_t dscm1xxxx_cis[0x14a] = {
- [0x000] = CISTPL_DEVICE, /* 5V Device Information */
- [0x002] = 0x03, /* Tuple length = 4 bytes */
- [0x004] = 0xdb, /* ID: DTYPE_FUNCSPEC, non WP, DSPEED_150NS */
- [0x006] = 0x01, /* Size = 2K bytes */
- [0x008] = CISTPL_ENDMARK,
-
- [0x00a] = CISTPL_DEVICE_OC, /* Additional Device Information */
- [0x00c] = 0x04, /* Tuple length = 4 byest */
- [0x00e] = 0x03, /* Conditions: Ext = 0, Vcc 3.3V, MWAIT = 1 */
- [0x010] = 0xdb, /* ID: DTYPE_FUNCSPEC, non WP, DSPEED_150NS */
- [0x012] = 0x01, /* Size = 2K bytes */
- [0x014] = CISTPL_ENDMARK,
-
- [0x016] = CISTPL_JEDEC_C, /* JEDEC ID */
- [0x018] = 0x02, /* Tuple length = 2 bytes */
- [0x01a] = 0xdf, /* PC Card ATA with no Vpp required */
- [0x01c] = 0x01,
-
- [0x01e] = CISTPL_MANFID, /* Manufacture ID */
- [0x020] = 0x04, /* Tuple length = 4 bytes */
- [0x022] = 0xa4, /* TPLMID_MANF = 00a4 (IBM) */
- [0x024] = 0x00,
- [0x026] = 0x00, /* PLMID_CARD = 0000 */
- [0x028] = 0x00,
-
- [0x02a] = CISTPL_VERS_1, /* Level 1 Version */
- [0x02c] = 0x12, /* Tuple length = 23 bytes */
- [0x02e] = 0x04, /* Major Version = JEIDA 4.2 / PCMCIA 2.1 */
- [0x030] = 0x01, /* Minor Version = 1 */
- [0x032] = 'I',
- [0x034] = 'B',
- [0x036] = 'M',
- [0x038] = 0x00,
- [0x03a] = 'm',
- [0x03c] = 'i',
- [0x03e] = 'c',
- [0x040] = 'r',
- [0x042] = 'o',
- [0x044] = 'd',
- [0x046] = 'r',
- [0x048] = 'i',
- [0x04a] = 'v',
- [0x04c] = 'e',
- [0x04e] = 0x00,
- [0x050] = CISTPL_ENDMARK,
-
- [0x052] = CISTPL_FUNCID, /* Function ID */
- [0x054] = 0x02, /* Tuple length = 2 bytes */
- [0x056] = 0x04, /* TPLFID_FUNCTION = Fixed Disk */
- [0x058] = 0x01, /* TPLFID_SYSINIT: POST = 1, ROM = 0 */
-
- [0x05a] = CISTPL_FUNCE, /* Function Extension */
- [0x05c] = 0x02, /* Tuple length = 2 bytes */
- [0x05e] = 0x01, /* TPLFE_TYPE = Disk Device Interface */
- [0x060] = 0x01, /* TPLFE_DATA = PC Card ATA Interface */
-
- [0x062] = CISTPL_FUNCE, /* Function Extension */
- [0x064] = 0x03, /* Tuple length = 3 bytes */
- [0x066] = 0x02, /* TPLFE_TYPE = Basic PC Card ATA Interface */
- [0x068] = 0x08, /* TPLFE_DATA: Rotating, Unique, Single */
- [0x06a] = 0x0f, /* TPLFE_DATA: Sleep, Standby, Idle, Auto */
-
- [0x06c] = CISTPL_CONFIG, /* Configuration */
- [0x06e] = 0x05, /* Tuple length = 5 bytes */
- [0x070] = 0x01, /* TPCC_RASZ = 2 bytes, TPCC_RMSZ = 1 byte */
- [0x072] = 0x07, /* TPCC_LAST = 7 */
- [0x074] = 0x00, /* TPCC_RADR = 0200 */
- [0x076] = 0x02,
- [0x078] = 0x0f, /* TPCC_RMSK = 200, 202, 204, 206 */
-
- [0x07a] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */
- [0x07c] = 0x0b, /* Tuple length = 11 bytes */
- [0x07e] = 0xc0, /* TPCE_INDX = Memory Mode, Default, Iface */
- [0x080] = 0xc0, /* TPCE_IF = Memory, no BVDs, no WP, READY */
- [0x082] = 0xa1, /* TPCE_FS = Vcc only, no I/O, Memory, Misc */
- [0x084] = 0x27, /* NomV = 1, MinV = 1, MaxV = 1, Peakl = 1 */
- [0x086] = 0x55, /* NomV: 5.0 V */
- [0x088] = 0x4d, /* MinV: 4.5 V */
- [0x08a] = 0x5d, /* MaxV: 5.5 V */
- [0x08c] = 0x4e, /* Peakl: 450 mA */
- [0x08e] = 0x08, /* TPCE_MS = 1 window, 1 byte, Host address */
- [0x090] = 0x00, /* Window descriptor: Window length = 0 */
- [0x092] = 0x20, /* TPCE_MI: support power down mode, RW */
-
- [0x094] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */
- [0x096] = 0x06, /* Tuple length = 6 bytes */
- [0x098] = 0x00, /* TPCE_INDX = Memory Mode, no Default */
- [0x09a] = 0x01, /* TPCE_FS = Vcc only, no I/O, no Memory */
- [0x09c] = 0x21, /* NomV = 1, MinV = 0, MaxV = 0, Peakl = 1 */
- [0x09e] = 0xb5, /* NomV: 3.3 V */
- [0x0a0] = 0x1e,
- [0x0a2] = 0x3e, /* Peakl: 350 mA */
-
- [0x0a4] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */
- [0x0a6] = 0x0d, /* Tuple length = 13 bytes */
- [0x0a8] = 0xc1, /* TPCE_INDX = I/O and Memory Mode, Default */
- [0x0aa] = 0x41, /* TPCE_IF = I/O and Memory, no BVD, no WP */
- [0x0ac] = 0x99, /* TPCE_FS = Vcc only, I/O, Interrupt, Misc */
- [0x0ae] = 0x27, /* NomV = 1, MinV = 1, MaxV = 1, Peakl = 1 */
- [0x0b0] = 0x55, /* NomV: 5.0 V */
- [0x0b2] = 0x4d, /* MinV: 4.5 V */
- [0x0b4] = 0x5d, /* MaxV: 5.5 V */
- [0x0b6] = 0x4e, /* Peakl: 450 mA */
- [0x0b8] = 0x64, /* TPCE_IO = 16-byte boundary, 16/8 accesses */
- [0x0ba] = 0xf0, /* TPCE_IR = MASK, Level, Pulse, Share */
- [0x0bc] = 0xff, /* IRQ0..IRQ7 supported */
- [0x0be] = 0xff, /* IRQ8..IRQ15 supported */
- [0x0c0] = 0x20, /* TPCE_MI = support power down mode */
-
- [0x0c2] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */
- [0x0c4] = 0x06, /* Tuple length = 6 bytes */
- [0x0c6] = 0x01, /* TPCE_INDX = I/O and Memory Mode */
- [0x0c8] = 0x01, /* TPCE_FS = Vcc only, no I/O, no Memory */
- [0x0ca] = 0x21, /* NomV = 1, MinV = 0, MaxV = 0, Peakl = 1 */
- [0x0cc] = 0xb5, /* NomV: 3.3 V */
- [0x0ce] = 0x1e,
- [0x0d0] = 0x3e, /* Peakl: 350 mA */
-
- [0x0d2] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */
- [0x0d4] = 0x12, /* Tuple length = 18 bytes */
- [0x0d6] = 0xc2, /* TPCE_INDX = I/O Primary Mode */
- [0x0d8] = 0x41, /* TPCE_IF = I/O and Memory, no BVD, no WP */
- [0x0da] = 0x99, /* TPCE_FS = Vcc only, I/O, Interrupt, Misc */
- [0x0dc] = 0x27, /* NomV = 1, MinV = 1, MaxV = 1, Peakl = 1 */
- [0x0de] = 0x55, /* NomV: 5.0 V */
- [0x0e0] = 0x4d, /* MinV: 4.5 V */
- [0x0e2] = 0x5d, /* MaxV: 5.5 V */
- [0x0e4] = 0x4e, /* Peakl: 450 mA */
- [0x0e6] = 0xea, /* TPCE_IO = 1K boundary, 16/8 access, Range */
- [0x0e8] = 0x61, /* Range: 2 fields, 2 bytes addr, 1 byte len */
- [0x0ea] = 0xf0, /* Field 1 address = 0x01f0 */
- [0x0ec] = 0x01,
- [0x0ee] = 0x07, /* Address block length = 8 */
- [0x0f0] = 0xf6, /* Field 2 address = 0x03f6 */
- [0x0f2] = 0x03,
- [0x0f4] = 0x01, /* Address block length = 2 */
- [0x0f6] = 0xee, /* TPCE_IR = IRQ E, Level, Pulse, Share */
- [0x0f8] = 0x20, /* TPCE_MI = support power down mode */
-
- [0x0fa] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */
- [0x0fc] = 0x06, /* Tuple length = 6 bytes */
- [0x0fe] = 0x02, /* TPCE_INDX = I/O Primary Mode, no Default */
- [0x100] = 0x01, /* TPCE_FS = Vcc only, no I/O, no Memory */
- [0x102] = 0x21, /* NomV = 1, MinV = 0, MaxV = 0, Peakl = 1 */
- [0x104] = 0xb5, /* NomV: 3.3 V */
- [0x106] = 0x1e,
- [0x108] = 0x3e, /* Peakl: 350 mA */
-
- [0x10a] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */
- [0x10c] = 0x12, /* Tuple length = 18 bytes */
- [0x10e] = 0xc3, /* TPCE_INDX = I/O Secondary Mode, Default */
- [0x110] = 0x41, /* TPCE_IF = I/O and Memory, no BVD, no WP */
- [0x112] = 0x99, /* TPCE_FS = Vcc only, I/O, Interrupt, Misc */
- [0x114] = 0x27, /* NomV = 1, MinV = 1, MaxV = 1, Peakl = 1 */
- [0x116] = 0x55, /* NomV: 5.0 V */
- [0x118] = 0x4d, /* MinV: 4.5 V */
- [0x11a] = 0x5d, /* MaxV: 5.5 V */
- [0x11c] = 0x4e, /* Peakl: 450 mA */
- [0x11e] = 0xea, /* TPCE_IO = 1K boundary, 16/8 access, Range */
- [0x120] = 0x61, /* Range: 2 fields, 2 byte addr, 1 byte len */
- [0x122] = 0x70, /* Field 1 address = 0x0170 */
- [0x124] = 0x01,
- [0x126] = 0x07, /* Address block length = 8 */
- [0x128] = 0x76, /* Field 2 address = 0x0376 */
- [0x12a] = 0x03,
- [0x12c] = 0x01, /* Address block length = 2 */
- [0x12e] = 0xee, /* TPCE_IR = IRQ E, Level, Pulse, Share */
- [0x130] = 0x20, /* TPCE_MI = support power down mode */
-
- [0x132] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */
- [0x134] = 0x06, /* Tuple length = 6 bytes */
- [0x136] = 0x03, /* TPCE_INDX = I/O Secondary Mode */
- [0x138] = 0x01, /* TPCE_FS = Vcc only, no I/O, no Memory */
- [0x13a] = 0x21, /* NomV = 1, MinV = 0, MaxV = 0, Peakl = 1 */
- [0x13c] = 0xb5, /* NomV: 3.3 V */
- [0x13e] = 0x1e,
- [0x140] = 0x3e, /* Peakl: 350 mA */
-
- [0x142] = CISTPL_NO_LINK, /* No Link */
- [0x144] = 0x00, /* Tuple length = 0 bytes */
-
- [0x146] = CISTPL_END, /* Tuple End */
-};
-
-#define TYPE_DSCM1XXXX "dscm1xxxx"
-
-static int dscm1xxxx_attach(PCMCIACardState *card)
-{
- MicroDriveState *md = MICRODRIVE(card);
- PCMCIACardClass *pcc = PCMCIA_CARD_GET_CLASS(card);
-
- md->attr_base = pcc->cis[0x74] | (pcc->cis[0x76] << 8);
- md->io_base = 0x0;
-
- device_reset(DEVICE(md));
- md_interrupt_update(md);
-
- return 0;
-}
-
-static int dscm1xxxx_detach(PCMCIACardState *card)
-{
- MicroDriveState *md = MICRODRIVE(card);
-
- device_reset(DEVICE(md));
- return 0;
-}
-
-PCMCIACardState *dscm1xxxx_init(DriveInfo *dinfo)
-{
- MicroDriveState *md;
-
- md = MICRODRIVE(object_new(TYPE_DSCM1XXXX));
- qdev_init_nofail(DEVICE(md));
-
- if (dinfo != NULL) {
- ide_create_drive(&md->bus, 0, dinfo);
- }
- md->bus.ifs[0].drive_kind = IDE_CFATA;
- md->bus.ifs[0].mdata_size = METADATA_SIZE;
- md->bus.ifs[0].mdata_storage = g_malloc0(METADATA_SIZE);
-
- return PCMCIA_CARD(md);
-}
-
-static void dscm1xxxx_class_init(ObjectClass *oc, void *data)
-{
- PCMCIACardClass *pcc = PCMCIA_CARD_CLASS(oc);
-
- pcc->cis = dscm1xxxx_cis;
- pcc->cis_len = sizeof(dscm1xxxx_cis);
-
- pcc->attach = dscm1xxxx_attach;
- pcc->detach = dscm1xxxx_detach;
-}
-
-static const TypeInfo dscm1xxxx_type_info = {
- .name = TYPE_DSCM1XXXX,
- .parent = TYPE_MICRODRIVE,
- .class_init = dscm1xxxx_class_init,
-};
-
-static void microdrive_realize(DeviceState *dev, Error **errp)
-{
- MicroDriveState *md = MICRODRIVE(dev);
-
- ide_init2(&md->bus, qemu_allocate_irq(md_set_irq, md, 0));
-}
-
-static void microdrive_init(Object *obj)
-{
- MicroDriveState *md = MICRODRIVE(obj);
-
- ide_bus_new(&md->bus, sizeof(md->bus), DEVICE(obj), 0, 1);
-}
-
-static void microdrive_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
- PCMCIACardClass *pcc = PCMCIA_CARD_CLASS(oc);
-
- pcc->attr_read = md_attr_read;
- pcc->attr_write = md_attr_write;
- pcc->common_read = md_common_read;
- pcc->common_write = md_common_write;
- pcc->io_read = md_common_read;
- pcc->io_write = md_common_write;
-
- dc->realize = microdrive_realize;
- dc->reset = md_reset;
- dc->vmsd = &vmstate_microdrive;
-}
-
-static const TypeInfo microdrive_type_info = {
- .name = TYPE_MICRODRIVE,
- .parent = TYPE_PCMCIA_CARD,
- .instance_size = sizeof(MicroDriveState),
- .instance_init = microdrive_init,
- .abstract = true,
- .class_init = microdrive_class_init,
-};
-
-static void microdrive_register_types(void)
-{
- type_register_static(&microdrive_type_info);
- type_register_static(&dscm1xxxx_type_info);
-}
-
-type_init(microdrive_register_types)
diff --git a/qemu/hw/ide/mmio.c b/qemu/hw/ide/mmio.c
deleted file mode 100644
index 493f65a1d..000000000
--- a/qemu/hw/ide/mmio.c
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * QEMU IDE Emulation: mmio support (for embedded).
- *
- * Copyright (c) 2003 Fabrice Bellard
- * Copyright (c) 2006 Openedhand Ltd.
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/dma.h"
-
-#include <hw/ide/internal.h>
-
-/***********************************************************/
-/* MMIO based ide port
- * This emulates IDE device connected directly to the CPU bus without
- * dedicated ide controller, which is often seen on embedded boards.
- */
-
-#define TYPE_MMIO_IDE "mmio-ide"
-#define MMIO_IDE(obj) OBJECT_CHECK(MMIOState, (obj), TYPE_MMIO_IDE)
-
-typedef struct MMIOIDEState {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- IDEBus bus;
-
- uint32_t shift;
- qemu_irq irq;
- MemoryRegion iomem1, iomem2;
-} MMIOState;
-
-static void mmio_ide_reset(DeviceState *dev)
-{
- MMIOState *s = MMIO_IDE(dev);
-
- ide_bus_reset(&s->bus);
-}
-
-static uint64_t mmio_ide_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- MMIOState *s = opaque;
- addr >>= s->shift;
- if (addr & 7)
- return ide_ioport_read(&s->bus, addr);
- else
- return ide_data_readw(&s->bus, 0);
-}
-
-static void mmio_ide_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- MMIOState *s = opaque;
- addr >>= s->shift;
- if (addr & 7)
- ide_ioport_write(&s->bus, addr, val);
- else
- ide_data_writew(&s->bus, 0, val);
-}
-
-static const MemoryRegionOps mmio_ide_ops = {
- .read = mmio_ide_read,
- .write = mmio_ide_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static uint64_t mmio_ide_status_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- MMIOState *s= opaque;
- return ide_status_read(&s->bus, 0);
-}
-
-static void mmio_ide_cmd_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- MMIOState *s = opaque;
- ide_cmd_write(&s->bus, 0, val);
-}
-
-static const MemoryRegionOps mmio_ide_cs_ops = {
- .read = mmio_ide_status_read,
- .write = mmio_ide_cmd_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_ide_mmio = {
- .name = "mmio-ide",
- .version_id = 3,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_IDE_BUS(bus, MMIOState),
- VMSTATE_IDE_DRIVES(bus.ifs, MMIOState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void mmio_ide_realizefn(DeviceState *dev, Error **errp)
-{
- SysBusDevice *d = SYS_BUS_DEVICE(dev);
- MMIOState *s = MMIO_IDE(dev);
-
- ide_init2(&s->bus, s->irq);
-
- memory_region_init_io(&s->iomem1, OBJECT(s), &mmio_ide_ops, s,
- "ide-mmio.1", 16 << s->shift);
- memory_region_init_io(&s->iomem2, OBJECT(s), &mmio_ide_cs_ops, s,
- "ide-mmio.2", 2 << s->shift);
- sysbus_init_mmio(d, &s->iomem1);
- sysbus_init_mmio(d, &s->iomem2);
-}
-
-static void mmio_ide_initfn(Object *obj)
-{
- SysBusDevice *d = SYS_BUS_DEVICE(obj);
- MMIOState *s = MMIO_IDE(obj);
-
- ide_bus_new(&s->bus, sizeof(s->bus), DEVICE(obj), 0, 2);
- sysbus_init_irq(d, &s->irq);
-}
-
-static Property mmio_ide_properties[] = {
- DEFINE_PROP_UINT32("shift", MMIOState, shift, 0),
- DEFINE_PROP_END_OF_LIST()
-};
-
-static void mmio_ide_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- dc->realize = mmio_ide_realizefn;
- dc->reset = mmio_ide_reset;
- dc->props = mmio_ide_properties;
- dc->vmsd = &vmstate_ide_mmio;
-}
-
-static const TypeInfo mmio_ide_type_info = {
- .name = TYPE_MMIO_IDE,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(MMIOState),
- .instance_init = mmio_ide_initfn,
- .class_init = mmio_ide_class_init,
-};
-
-static void mmio_ide_register_types(void)
-{
- type_register_static(&mmio_ide_type_info);
-}
-
-void mmio_ide_init_drives(DeviceState *dev, DriveInfo *hd0, DriveInfo *hd1)
-{
- MMIOState *s = MMIO_IDE(dev);
-
- if (hd0 != NULL) {
- ide_create_drive(&s->bus, 0, hd0);
- }
- if (hd1 != NULL) {
- ide_create_drive(&s->bus, 1, hd1);
- }
-}
-
-type_init(mmio_ide_register_types)
diff --git a/qemu/hw/ide/pci.c b/qemu/hw/ide/pci.c
deleted file mode 100644
index 8d56a00b1..000000000
--- a/qemu/hw/ide/pci.c
+++ /dev/null
@@ -1,468 +0,0 @@
-/*
- * QEMU IDE Emulation: PCI Bus support.
- *
- * Copyright (c) 2003 Fabrice Bellard
- * Copyright (c) 2006 Openedhand Ltd.
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include <hw/hw.h>
-#include <hw/i386/pc.h>
-#include <hw/pci/pci.h>
-#include <hw/isa/isa.h>
-#include "sysemu/block-backend.h"
-#include "sysemu/dma.h"
-#include "qemu/error-report.h"
-#include <hw/ide/pci.h>
-
-#define BMDMA_PAGE_SIZE 4096
-
-#define BM_MIGRATION_COMPAT_STATUS_BITS \
- (IDE_RETRY_DMA | IDE_RETRY_PIO | \
- IDE_RETRY_READ | IDE_RETRY_FLUSH)
-
-static void bmdma_start_dma(IDEDMA *dma, IDEState *s,
- BlockCompletionFunc *dma_cb)
-{
- BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma);
-
- bm->dma_cb = dma_cb;
- bm->cur_prd_last = 0;
- bm->cur_prd_addr = 0;
- bm->cur_prd_len = 0;
-
- if (bm->status & BM_STATUS_DMAING) {
- bm->dma_cb(bmdma_active_if(bm), 0);
- }
-}
-
-/**
- * Prepare an sglist based on available PRDs.
- * @limit: How many bytes to prepare total.
- *
- * Returns the number of bytes prepared, -1 on error.
- * IDEState.io_buffer_size will contain the number of bytes described
- * by the PRDs, whether or not we added them to the sglist.
- */
-static int32_t bmdma_prepare_buf(IDEDMA *dma, int32_t limit)
-{
- BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma);
- IDEState *s = bmdma_active_if(bm);
- PCIDevice *pci_dev = PCI_DEVICE(bm->pci_dev);
- struct {
- uint32_t addr;
- uint32_t size;
- } prd;
- int l, len;
-
- pci_dma_sglist_init(&s->sg, pci_dev,
- s->nsector / (BMDMA_PAGE_SIZE / 512) + 1);
- s->io_buffer_size = 0;
- for(;;) {
- if (bm->cur_prd_len == 0) {
- /* end of table (with a fail safe of one page) */
- if (bm->cur_prd_last ||
- (bm->cur_addr - bm->addr) >= BMDMA_PAGE_SIZE) {
- return s->sg.size;
- }
- pci_dma_read(pci_dev, bm->cur_addr, &prd, 8);
- bm->cur_addr += 8;
- prd.addr = le32_to_cpu(prd.addr);
- prd.size = le32_to_cpu(prd.size);
- len = prd.size & 0xfffe;
- if (len == 0)
- len = 0x10000;
- bm->cur_prd_len = len;
- bm->cur_prd_addr = prd.addr;
- bm->cur_prd_last = (prd.size & 0x80000000);
- }
- l = bm->cur_prd_len;
- if (l > 0) {
- uint64_t sg_len;
-
- /* Don't add extra bytes to the SGList; consume any remaining
- * PRDs from the guest, but ignore them. */
- sg_len = MIN(limit - s->sg.size, bm->cur_prd_len);
- if (sg_len) {
- qemu_sglist_add(&s->sg, bm->cur_prd_addr, sg_len);
- }
-
- bm->cur_prd_addr += l;
- bm->cur_prd_len -= l;
- s->io_buffer_size += l;
- }
- }
-
- qemu_sglist_destroy(&s->sg);
- s->io_buffer_size = 0;
- return -1;
-}
-
-/* return 0 if buffer completed */
-static int bmdma_rw_buf(IDEDMA *dma, int is_write)
-{
- BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma);
- IDEState *s = bmdma_active_if(bm);
- PCIDevice *pci_dev = PCI_DEVICE(bm->pci_dev);
- struct {
- uint32_t addr;
- uint32_t size;
- } prd;
- int l, len;
-
- for(;;) {
- l = s->io_buffer_size - s->io_buffer_index;
- if (l <= 0)
- break;
- if (bm->cur_prd_len == 0) {
- /* end of table (with a fail safe of one page) */
- if (bm->cur_prd_last ||
- (bm->cur_addr - bm->addr) >= BMDMA_PAGE_SIZE)
- return 0;
- pci_dma_read(pci_dev, bm->cur_addr, &prd, 8);
- bm->cur_addr += 8;
- prd.addr = le32_to_cpu(prd.addr);
- prd.size = le32_to_cpu(prd.size);
- len = prd.size & 0xfffe;
- if (len == 0)
- len = 0x10000;
- bm->cur_prd_len = len;
- bm->cur_prd_addr = prd.addr;
- bm->cur_prd_last = (prd.size & 0x80000000);
- }
- if (l > bm->cur_prd_len)
- l = bm->cur_prd_len;
- if (l > 0) {
- if (is_write) {
- pci_dma_write(pci_dev, bm->cur_prd_addr,
- s->io_buffer + s->io_buffer_index, l);
- } else {
- pci_dma_read(pci_dev, bm->cur_prd_addr,
- s->io_buffer + s->io_buffer_index, l);
- }
- bm->cur_prd_addr += l;
- bm->cur_prd_len -= l;
- s->io_buffer_index += l;
- }
- }
- return 1;
-}
-
-static void bmdma_set_inactive(IDEDMA *dma, bool more)
-{
- BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma);
-
- bm->dma_cb = NULL;
- if (more) {
- bm->status |= BM_STATUS_DMAING;
- } else {
- bm->status &= ~BM_STATUS_DMAING;
- }
-}
-
-static void bmdma_restart_dma(IDEDMA *dma)
-{
- BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma);
-
- bm->cur_addr = bm->addr;
-}
-
-static void bmdma_cancel(BMDMAState *bm)
-{
- if (bm->status & BM_STATUS_DMAING) {
- /* cancel DMA request */
- bmdma_set_inactive(&bm->dma, false);
- }
-}
-
-static void bmdma_reset(IDEDMA *dma)
-{
- BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma);
-
-#ifdef DEBUG_IDE
- printf("ide: dma_reset\n");
-#endif
- bmdma_cancel(bm);
- bm->cmd = 0;
- bm->status = 0;
- bm->addr = 0;
- bm->cur_addr = 0;
- bm->cur_prd_last = 0;
- bm->cur_prd_addr = 0;
- bm->cur_prd_len = 0;
-}
-
-static void bmdma_irq(void *opaque, int n, int level)
-{
- BMDMAState *bm = opaque;
-
- if (!level) {
- /* pass through lower */
- qemu_set_irq(bm->irq, level);
- return;
- }
-
- bm->status |= BM_STATUS_INT;
-
- /* trigger the real irq */
- qemu_set_irq(bm->irq, level);
-}
-
-void bmdma_cmd_writeb(BMDMAState *bm, uint32_t val)
-{
-#ifdef DEBUG_IDE
- printf("%s: 0x%08x\n", __func__, val);
-#endif
-
- /* Ignore writes to SSBM if it keeps the old value */
- if ((val & BM_CMD_START) != (bm->cmd & BM_CMD_START)) {
- if (!(val & BM_CMD_START)) {
- ide_cancel_dma_sync(idebus_active_if(bm->bus));
- bm->status &= ~BM_STATUS_DMAING;
- } else {
- bm->cur_addr = bm->addr;
- if (!(bm->status & BM_STATUS_DMAING)) {
- bm->status |= BM_STATUS_DMAING;
- /* start dma transfer if possible */
- if (bm->dma_cb)
- bm->dma_cb(bmdma_active_if(bm), 0);
- }
- }
- }
-
- bm->cmd = val & 0x09;
-}
-
-static uint64_t bmdma_addr_read(void *opaque, hwaddr addr,
- unsigned width)
-{
- BMDMAState *bm = opaque;
- uint32_t mask = (1ULL << (width * 8)) - 1;
- uint64_t data;
-
- data = (bm->addr >> (addr * 8)) & mask;
-#ifdef DEBUG_IDE
- printf("%s: 0x%08x\n", __func__, (unsigned)data);
-#endif
- return data;
-}
-
-static void bmdma_addr_write(void *opaque, hwaddr addr,
- uint64_t data, unsigned width)
-{
- BMDMAState *bm = opaque;
- int shift = addr * 8;
- uint32_t mask = (1ULL << (width * 8)) - 1;
-
-#ifdef DEBUG_IDE
- printf("%s: 0x%08x\n", __func__, (unsigned)data);
-#endif
- bm->addr &= ~(mask << shift);
- bm->addr |= ((data & mask) << shift) & ~3;
-}
-
-MemoryRegionOps bmdma_addr_ioport_ops = {
- .read = bmdma_addr_read,
- .write = bmdma_addr_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static bool ide_bmdma_current_needed(void *opaque)
-{
- BMDMAState *bm = opaque;
-
- return (bm->cur_prd_len != 0);
-}
-
-static bool ide_bmdma_status_needed(void *opaque)
-{
- BMDMAState *bm = opaque;
-
- /* Older versions abused some bits in the status register for internal
- * error state. If any of these bits are set, we must add a subsection to
- * transfer the real status register */
- uint8_t abused_bits = BM_MIGRATION_COMPAT_STATUS_BITS;
-
- return ((bm->status & abused_bits) != 0);
-}
-
-static void ide_bmdma_pre_save(void *opaque)
-{
- BMDMAState *bm = opaque;
- uint8_t abused_bits = BM_MIGRATION_COMPAT_STATUS_BITS;
-
- if (!(bm->status & BM_STATUS_DMAING) && bm->dma_cb) {
- bm->bus->error_status =
- ide_dma_cmd_to_retry(bmdma_active_if(bm)->dma_cmd);
- }
- bm->migration_retry_unit = bm->bus->retry_unit;
- bm->migration_retry_sector_num = bm->bus->retry_sector_num;
- bm->migration_retry_nsector = bm->bus->retry_nsector;
- bm->migration_compat_status =
- (bm->status & ~abused_bits) | (bm->bus->error_status & abused_bits);
-}
-
-/* This function accesses bm->bus->error_status which is loaded only after
- * BMDMA itself. This is why the function is called from ide_pci_post_load
- * instead of being registered with VMState where it would run too early. */
-static int ide_bmdma_post_load(void *opaque, int version_id)
-{
- BMDMAState *bm = opaque;
- uint8_t abused_bits = BM_MIGRATION_COMPAT_STATUS_BITS;
-
- if (bm->status == 0) {
- bm->status = bm->migration_compat_status & ~abused_bits;
- bm->bus->error_status |= bm->migration_compat_status & abused_bits;
- }
- if (bm->bus->error_status) {
- bm->bus->retry_sector_num = bm->migration_retry_sector_num;
- bm->bus->retry_nsector = bm->migration_retry_nsector;
- bm->bus->retry_unit = bm->migration_retry_unit;
- }
-
- return 0;
-}
-
-static const VMStateDescription vmstate_bmdma_current = {
- .name = "ide bmdma_current",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = ide_bmdma_current_needed,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(cur_addr, BMDMAState),
- VMSTATE_UINT32(cur_prd_last, BMDMAState),
- VMSTATE_UINT32(cur_prd_addr, BMDMAState),
- VMSTATE_UINT32(cur_prd_len, BMDMAState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_bmdma_status = {
- .name ="ide bmdma/status",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = ide_bmdma_status_needed,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(status, BMDMAState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_bmdma = {
- .name = "ide bmdma",
- .version_id = 3,
- .minimum_version_id = 0,
- .pre_save = ide_bmdma_pre_save,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(cmd, BMDMAState),
- VMSTATE_UINT8(migration_compat_status, BMDMAState),
- VMSTATE_UINT32(addr, BMDMAState),
- VMSTATE_INT64(migration_retry_sector_num, BMDMAState),
- VMSTATE_UINT32(migration_retry_nsector, BMDMAState),
- VMSTATE_UINT8(migration_retry_unit, BMDMAState),
- VMSTATE_END_OF_LIST()
- },
- .subsections = (const VMStateDescription*[]) {
- &vmstate_bmdma_current,
- &vmstate_bmdma_status,
- NULL
- }
-};
-
-static int ide_pci_post_load(void *opaque, int version_id)
-{
- PCIIDEState *d = opaque;
- int i;
-
- for(i = 0; i < 2; i++) {
- /* current versions always store 0/1, but older version
- stored bigger values. We only need last bit */
- d->bmdma[i].migration_retry_unit &= 1;
- ide_bmdma_post_load(&d->bmdma[i], -1);
- }
-
- return 0;
-}
-
-const VMStateDescription vmstate_ide_pci = {
- .name = "ide",
- .version_id = 3,
- .minimum_version_id = 0,
- .post_load = ide_pci_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(parent_obj, PCIIDEState),
- VMSTATE_STRUCT_ARRAY(bmdma, PCIIDEState, 2, 0,
- vmstate_bmdma, BMDMAState),
- VMSTATE_IDE_BUS_ARRAY(bus, PCIIDEState, 2),
- VMSTATE_IDE_DRIVES(bus[0].ifs, PCIIDEState),
- VMSTATE_IDE_DRIVES(bus[1].ifs, PCIIDEState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-void pci_ide_create_devs(PCIDevice *dev, DriveInfo **hd_table)
-{
- PCIIDEState *d = PCI_IDE(dev);
- static const int bus[4] = { 0, 0, 1, 1 };
- static const int unit[4] = { 0, 1, 0, 1 };
- int i;
-
- for (i = 0; i < 4; i++) {
- if (hd_table[i] == NULL)
- continue;
- ide_create_drive(d->bus+bus[i], unit[i], hd_table[i]);
- }
-}
-
-static const struct IDEDMAOps bmdma_ops = {
- .start_dma = bmdma_start_dma,
- .prepare_buf = bmdma_prepare_buf,
- .rw_buf = bmdma_rw_buf,
- .restart_dma = bmdma_restart_dma,
- .set_inactive = bmdma_set_inactive,
- .reset = bmdma_reset,
-};
-
-void bmdma_init(IDEBus *bus, BMDMAState *bm, PCIIDEState *d)
-{
- if (bus->dma == &bm->dma) {
- return;
- }
-
- bm->dma.ops = &bmdma_ops;
- bus->dma = &bm->dma;
- bm->irq = bus->irq;
- bus->irq = qemu_allocate_irq(bmdma_irq, bm, 0);
- bm->pci_dev = d;
-}
-
-static const TypeInfo pci_ide_type_info = {
- .name = TYPE_PCI_IDE,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(PCIIDEState),
- .abstract = true,
-};
-
-static void pci_ide_register_types(void)
-{
- type_register_static(&pci_ide_type_info);
-}
-
-type_init(pci_ide_register_types)
diff --git a/qemu/hw/ide/pci.h b/qemu/hw/ide/pci.h
deleted file mode 100644
index 0f2d4b91a..000000000
--- a/qemu/hw/ide/pci.h
+++ /dev/null
@@ -1,76 +0,0 @@
-#ifndef HW_IDE_PCI_H
-#define HW_IDE_PCI_H
-
-#include <hw/ide/internal.h>
-
-#define BM_STATUS_DMAING 0x01
-#define BM_STATUS_ERROR 0x02
-#define BM_STATUS_INT 0x04
-
-#define BM_CMD_START 0x01
-#define BM_CMD_READ 0x08
-
-typedef struct BMDMAState {
- IDEDMA dma;
- uint8_t cmd;
- uint8_t status;
- uint32_t addr;
-
- IDEBus *bus;
- /* current transfer state */
- uint32_t cur_addr;
- uint32_t cur_prd_last;
- uint32_t cur_prd_addr;
- uint32_t cur_prd_len;
- BlockCompletionFunc *dma_cb;
- MemoryRegion addr_ioport;
- MemoryRegion extra_io;
- qemu_irq irq;
-
- /* Bit 0-2 and 7: BM status register
- * Bit 3-6: bus->error_status */
- uint8_t migration_compat_status;
- uint8_t migration_retry_unit;
- int64_t migration_retry_sector_num;
- uint32_t migration_retry_nsector;
-
- struct PCIIDEState *pci_dev;
-} BMDMAState;
-
-typedef struct CMD646BAR {
- MemoryRegion cmd;
- MemoryRegion data;
- IDEBus *bus;
- struct PCIIDEState *pci_dev;
-} CMD646BAR;
-
-#define TYPE_PCI_IDE "pci-ide"
-#define PCI_IDE(obj) OBJECT_CHECK(PCIIDEState, (obj), TYPE_PCI_IDE)
-
-typedef struct PCIIDEState {
- /*< private >*/
- PCIDevice parent_obj;
- /*< public >*/
-
- IDEBus bus[2];
- BMDMAState bmdma[2];
- uint32_t secondary; /* used only for cmd646 */
- MemoryRegion bmdma_bar;
- CMD646BAR cmd646_bar[2]; /* used only for cmd646 */
-} PCIIDEState;
-
-
-static inline IDEState *bmdma_active_if(BMDMAState *bmdma)
-{
- assert(bmdma->bus->retry_unit != (uint8_t)-1);
- return bmdma->bus->ifs + bmdma->bus->retry_unit;
-}
-
-
-void bmdma_init(IDEBus *bus, BMDMAState *bm, PCIIDEState *d);
-void bmdma_cmd_writeb(BMDMAState *bm, uint32_t val);
-extern MemoryRegionOps bmdma_addr_ioport_ops;
-void pci_ide_create_devs(PCIDevice *dev, DriveInfo **hd_table);
-
-extern const VMStateDescription vmstate_ide_pci;
-#endif
diff --git a/qemu/hw/ide/piix.c b/qemu/hw/ide/piix.c
deleted file mode 100644
index 6d76ce980..000000000
--- a/qemu/hw/ide/piix.c
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- * QEMU IDE Emulation: PCI PIIX3/4 support.
- *
- * Copyright (c) 2003 Fabrice Bellard
- * Copyright (c) 2006 Openedhand Ltd.
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include <hw/hw.h>
-#include <hw/i386/pc.h>
-#include <hw/pci/pci.h>
-#include <hw/isa/isa.h>
-#include "sysemu/block-backend.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/dma.h"
-
-#include <hw/ide/pci.h>
-
-static uint64_t bmdma_read(void *opaque, hwaddr addr, unsigned size)
-{
- BMDMAState *bm = opaque;
- uint32_t val;
-
- if (size != 1) {
- return ((uint64_t)1 << (size * 8)) - 1;
- }
-
- switch(addr & 3) {
- case 0:
- val = bm->cmd;
- break;
- case 2:
- val = bm->status;
- break;
- default:
- val = 0xff;
- break;
- }
-#ifdef DEBUG_IDE
- printf("bmdma: readb 0x%02x : 0x%02x\n", (uint8_t)addr, val);
-#endif
- return val;
-}
-
-static void bmdma_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- BMDMAState *bm = opaque;
-
- if (size != 1) {
- return;
- }
-
-#ifdef DEBUG_IDE
- printf("bmdma: writeb 0x%02x : 0x%02x\n", (uint8_t)addr, (uint8_t)val);
-#endif
- switch(addr & 3) {
- case 0:
- bmdma_cmd_writeb(bm, val);
- break;
- case 2:
- bm->status = (val & 0x60) | (bm->status & 1) | (bm->status & ~val & 0x06);
- break;
- }
-}
-
-static const MemoryRegionOps piix_bmdma_ops = {
- .read = bmdma_read,
- .write = bmdma_write,
-};
-
-static void bmdma_setup_bar(PCIIDEState *d)
-{
- int i;
-
- memory_region_init(&d->bmdma_bar, OBJECT(d), "piix-bmdma-container", 16);
- for(i = 0;i < 2; i++) {
- BMDMAState *bm = &d->bmdma[i];
-
- memory_region_init_io(&bm->extra_io, OBJECT(d), &piix_bmdma_ops, bm,
- "piix-bmdma", 4);
- memory_region_add_subregion(&d->bmdma_bar, i * 8, &bm->extra_io);
- memory_region_init_io(&bm->addr_ioport, OBJECT(d),
- &bmdma_addr_ioport_ops, bm, "bmdma", 4);
- memory_region_add_subregion(&d->bmdma_bar, i * 8 + 4, &bm->addr_ioport);
- }
-}
-
-static void piix3_reset(void *opaque)
-{
- PCIIDEState *d = opaque;
- PCIDevice *pd = PCI_DEVICE(d);
- uint8_t *pci_conf = pd->config;
- int i;
-
- for (i = 0; i < 2; i++) {
- ide_bus_reset(&d->bus[i]);
- }
-
- /* TODO: this is the default. do not override. */
- pci_conf[PCI_COMMAND] = 0x00;
- /* TODO: this is the default. do not override. */
- pci_conf[PCI_COMMAND + 1] = 0x00;
- /* TODO: use pci_set_word */
- pci_conf[PCI_STATUS] = PCI_STATUS_FAST_BACK;
- pci_conf[PCI_STATUS + 1] = PCI_STATUS_DEVSEL_MEDIUM >> 8;
- pci_conf[0x20] = 0x01; /* BMIBA: 20-23h */
-}
-
-static void pci_piix_init_ports(PCIIDEState *d) {
- static const struct {
- int iobase;
- int iobase2;
- int isairq;
- } port_info[] = {
- {0x1f0, 0x3f6, 14},
- {0x170, 0x376, 15},
- };
- int i;
-
- for (i = 0; i < 2; i++) {
- ide_bus_new(&d->bus[i], sizeof(d->bus[i]), DEVICE(d), i, 2);
- ide_init_ioport(&d->bus[i], NULL, port_info[i].iobase,
- port_info[i].iobase2);
- ide_init2(&d->bus[i], isa_get_irq(NULL, port_info[i].isairq));
-
- bmdma_init(&d->bus[i], &d->bmdma[i], d);
- d->bmdma[i].bus = &d->bus[i];
- ide_register_restart_cb(&d->bus[i]);
- }
-}
-
-static void pci_piix_ide_realize(PCIDevice *dev, Error **errp)
-{
- PCIIDEState *d = PCI_IDE(dev);
- uint8_t *pci_conf = dev->config;
-
- pci_conf[PCI_CLASS_PROG] = 0x80; // legacy ATA mode
-
- qemu_register_reset(piix3_reset, d);
-
- bmdma_setup_bar(d);
- pci_register_bar(dev, 4, PCI_BASE_ADDRESS_SPACE_IO, &d->bmdma_bar);
-
- vmstate_register(DEVICE(dev), 0, &vmstate_ide_pci, d);
-
- pci_piix_init_ports(d);
-}
-
-int pci_piix3_xen_ide_unplug(DeviceState *dev)
-{
- PCIIDEState *pci_ide;
- DriveInfo *di;
- int i;
- IDEDevice *idedev;
-
- pci_ide = PCI_IDE(dev);
-
- for (i = 0; i < 4; i++) {
- di = drive_get_by_index(IF_IDE, i);
- if (di != NULL && !di->media_cd) {
- BlockBackend *blk = blk_by_legacy_dinfo(di);
- DeviceState *ds = blk_get_attached_dev(blk);
- if (ds) {
- blk_detach_dev(blk, ds);
- }
- pci_ide->bus[di->bus].ifs[di->unit].blk = NULL;
- if (!(i % 2)) {
- idedev = pci_ide->bus[di->bus].master;
- } else {
- idedev = pci_ide->bus[di->bus].slave;
- }
- idedev->conf.blk = NULL;
- monitor_remove_blk(blk);
- blk_unref(blk);
- }
- }
- qdev_reset_all(DEVICE(dev));
- return 0;
-}
-
-PCIDevice *pci_piix3_xen_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
-{
- PCIDevice *dev;
-
- dev = pci_create_simple(bus, devfn, "piix3-ide-xen");
- pci_ide_create_devs(dev, hd_table);
- return dev;
-}
-
-static void pci_piix_ide_exitfn(PCIDevice *dev)
-{
- PCIIDEState *d = PCI_IDE(dev);
- unsigned i;
-
- for (i = 0; i < 2; ++i) {
- memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].extra_io);
- memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].addr_ioport);
- }
-}
-
-/* hd_table must contain 4 block drivers */
-/* NOTE: for the PIIX3, the IRQs and IOports are hardcoded */
-PCIDevice *pci_piix3_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
-{
- PCIDevice *dev;
-
- dev = pci_create_simple(bus, devfn, "piix3-ide");
- pci_ide_create_devs(dev, hd_table);
- return dev;
-}
-
-/* hd_table must contain 4 block drivers */
-/* NOTE: for the PIIX4, the IRQs and IOports are hardcoded */
-PCIDevice *pci_piix4_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
-{
- PCIDevice *dev;
-
- dev = pci_create_simple(bus, devfn, "piix4-ide");
- pci_ide_create_devs(dev, hd_table);
- return dev;
-}
-
-static void piix3_ide_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = pci_piix_ide_realize;
- k->exit = pci_piix_ide_exitfn;
- k->vendor_id = PCI_VENDOR_ID_INTEL;
- k->device_id = PCI_DEVICE_ID_INTEL_82371SB_1;
- k->class_id = PCI_CLASS_STORAGE_IDE;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
- dc->hotpluggable = false;
-}
-
-static const TypeInfo piix3_ide_info = {
- .name = "piix3-ide",
- .parent = TYPE_PCI_IDE,
- .class_init = piix3_ide_class_init,
-};
-
-static const TypeInfo piix3_ide_xen_info = {
- .name = "piix3-ide-xen",
- .parent = TYPE_PCI_IDE,
- .class_init = piix3_ide_class_init,
-};
-
-static void piix4_ide_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = pci_piix_ide_realize;
- k->exit = pci_piix_ide_exitfn;
- k->vendor_id = PCI_VENDOR_ID_INTEL;
- k->device_id = PCI_DEVICE_ID_INTEL_82371AB;
- k->class_id = PCI_CLASS_STORAGE_IDE;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
- dc->hotpluggable = false;
-}
-
-static const TypeInfo piix4_ide_info = {
- .name = "piix4-ide",
- .parent = TYPE_PCI_IDE,
- .class_init = piix4_ide_class_init,
-};
-
-static void piix_ide_register_types(void)
-{
- type_register_static(&piix3_ide_info);
- type_register_static(&piix3_ide_xen_info);
- type_register_static(&piix4_ide_info);
-}
-
-type_init(piix_ide_register_types)
diff --git a/qemu/hw/ide/qdev.c b/qemu/hw/ide/qdev.c
deleted file mode 100644
index 4bc74a32d..000000000
--- a/qemu/hw/ide/qdev.c
+++ /dev/null
@@ -1,370 +0,0 @@
-/*
- * ide bus support for qdev.
- *
- * Copyright (c) 2009 Gerd Hoffmann <kraxel@redhat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "qemu/osdep.h"
-#include <hw/hw.h>
-#include "sysemu/dma.h"
-#include "qapi/error.h"
-#include "qemu/error-report.h"
-#include <hw/ide/internal.h>
-#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
-#include "hw/block/block.h"
-#include "sysemu/sysemu.h"
-#include "qapi/visitor.h"
-
-/* --------------------------------- */
-
-static char *idebus_get_fw_dev_path(DeviceState *dev);
-
-static Property ide_props[] = {
- DEFINE_PROP_UINT32("unit", IDEDevice, unit, -1),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void ide_bus_class_init(ObjectClass *klass, void *data)
-{
- BusClass *k = BUS_CLASS(klass);
-
- k->get_fw_dev_path = idebus_get_fw_dev_path;
-}
-
-static const TypeInfo ide_bus_info = {
- .name = TYPE_IDE_BUS,
- .parent = TYPE_BUS,
- .instance_size = sizeof(IDEBus),
- .class_init = ide_bus_class_init,
-};
-
-void ide_bus_new(IDEBus *idebus, size_t idebus_size, DeviceState *dev,
- int bus_id, int max_units)
-{
- qbus_create_inplace(idebus, idebus_size, TYPE_IDE_BUS, dev, NULL);
- idebus->bus_id = bus_id;
- idebus->max_units = max_units;
-}
-
-static char *idebus_get_fw_dev_path(DeviceState *dev)
-{
- char path[30];
-
- snprintf(path, sizeof(path), "%s@%x", qdev_fw_name(dev),
- ((IDEBus*)dev->parent_bus)->bus_id);
-
- return g_strdup(path);
-}
-
-static int ide_qdev_init(DeviceState *qdev)
-{
- IDEDevice *dev = IDE_DEVICE(qdev);
- IDEDeviceClass *dc = IDE_DEVICE_GET_CLASS(dev);
- IDEBus *bus = DO_UPCAST(IDEBus, qbus, qdev->parent_bus);
-
- if (!dev->conf.blk) {
- error_report("No drive specified");
- goto err;
- }
- if (dev->unit == -1) {
- dev->unit = bus->master ? 1 : 0;
- }
-
- if (dev->unit >= bus->max_units) {
- error_report("Can't create IDE unit %d, bus supports only %d units",
- dev->unit, bus->max_units);
- goto err;
- }
-
- switch (dev->unit) {
- case 0:
- if (bus->master) {
- error_report("IDE unit %d is in use", dev->unit);
- goto err;
- }
- bus->master = dev;
- break;
- case 1:
- if (bus->slave) {
- error_report("IDE unit %d is in use", dev->unit);
- goto err;
- }
- bus->slave = dev;
- break;
- default:
- error_report("Invalid IDE unit %d", dev->unit);
- goto err;
- }
- return dc->init(dev);
-
-err:
- return -1;
-}
-
-IDEDevice *ide_create_drive(IDEBus *bus, int unit, DriveInfo *drive)
-{
- DeviceState *dev;
-
- dev = qdev_create(&bus->qbus, drive->media_cd ? "ide-cd" : "ide-hd");
- qdev_prop_set_uint32(dev, "unit", unit);
- qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(drive),
- &error_fatal);
- qdev_init_nofail(dev);
- return DO_UPCAST(IDEDevice, qdev, dev);
-}
-
-int ide_get_geometry(BusState *bus, int unit,
- int16_t *cyls, int8_t *heads, int8_t *secs)
-{
- IDEState *s = &DO_UPCAST(IDEBus, qbus, bus)->ifs[unit];
-
- if (s->drive_kind != IDE_HD || !s->blk) {
- return -1;
- }
-
- *cyls = s->cylinders;
- *heads = s->heads;
- *secs = s->sectors;
- return 0;
-}
-
-int ide_get_bios_chs_trans(BusState *bus, int unit)
-{
- return DO_UPCAST(IDEBus, qbus, bus)->ifs[unit].chs_trans;
-}
-
-/* --------------------------------- */
-
-typedef struct IDEDrive {
- IDEDevice dev;
-} IDEDrive;
-
-static int ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind)
-{
- IDEBus *bus = DO_UPCAST(IDEBus, qbus, dev->qdev.parent_bus);
- IDEState *s = bus->ifs + dev->unit;
- Error *err = NULL;
-
- if (dev->conf.discard_granularity == -1) {
- dev->conf.discard_granularity = 512;
- } else if (dev->conf.discard_granularity &&
- dev->conf.discard_granularity != 512) {
- error_report("discard_granularity must be 512 for ide");
- return -1;
- }
-
- blkconf_blocksizes(&dev->conf);
- if (dev->conf.logical_block_size != 512) {
- error_report("logical_block_size must be 512 for IDE");
- return -1;
- }
-
- blkconf_serial(&dev->conf, &dev->serial);
- if (kind != IDE_CD) {
- blkconf_geometry(&dev->conf, &dev->chs_trans, 65535, 16, 255, &err);
- if (err) {
- error_report_err(err);
- return -1;
- }
- }
-
- if (ide_init_drive(s, dev->conf.blk, kind,
- dev->version, dev->serial, dev->model, dev->wwn,
- dev->conf.cyls, dev->conf.heads, dev->conf.secs,
- dev->chs_trans) < 0) {
- return -1;
- }
-
- if (!dev->version) {
- dev->version = g_strdup(s->version);
- }
- if (!dev->serial) {
- dev->serial = g_strdup(s->drive_serial_str);
- }
-
- add_boot_device_path(dev->conf.bootindex, &dev->qdev,
- dev->unit ? "/disk@1" : "/disk@0");
-
- return 0;
-}
-
-static void ide_dev_get_bootindex(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- IDEDevice *d = IDE_DEVICE(obj);
-
- visit_type_int32(v, name, &d->conf.bootindex, errp);
-}
-
-static void ide_dev_set_bootindex(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- IDEDevice *d = IDE_DEVICE(obj);
- int32_t boot_index;
- Error *local_err = NULL;
-
- visit_type_int32(v, name, &boot_index, &local_err);
- if (local_err) {
- goto out;
- }
- /* check whether bootindex is present in fw_boot_order list */
- check_boot_index(boot_index, &local_err);
- if (local_err) {
- goto out;
- }
- /* change bootindex to a new one */
- d->conf.bootindex = boot_index;
-
- if (d->unit != -1) {
- add_boot_device_path(d->conf.bootindex, &d->qdev,
- d->unit ? "/disk@1" : "/disk@0");
- }
-out:
- if (local_err) {
- error_propagate(errp, local_err);
- }
-}
-
-static void ide_dev_instance_init(Object *obj)
-{
- object_property_add(obj, "bootindex", "int32",
- ide_dev_get_bootindex,
- ide_dev_set_bootindex, NULL, NULL, NULL);
- object_property_set_int(obj, -1, "bootindex", NULL);
-}
-
-static int ide_hd_initfn(IDEDevice *dev)
-{
- return ide_dev_initfn(dev, IDE_HD);
-}
-
-static int ide_cd_initfn(IDEDevice *dev)
-{
- return ide_dev_initfn(dev, IDE_CD);
-}
-
-static int ide_drive_initfn(IDEDevice *dev)
-{
- DriveInfo *dinfo = blk_legacy_dinfo(dev->conf.blk);
-
- return ide_dev_initfn(dev, dinfo && dinfo->media_cd ? IDE_CD : IDE_HD);
-}
-
-#define DEFINE_IDE_DEV_PROPERTIES() \
- DEFINE_BLOCK_PROPERTIES(IDEDrive, dev.conf), \
- DEFINE_PROP_STRING("ver", IDEDrive, dev.version), \
- DEFINE_PROP_UINT64("wwn", IDEDrive, dev.wwn, 0), \
- DEFINE_PROP_STRING("serial", IDEDrive, dev.serial),\
- DEFINE_PROP_STRING("model", IDEDrive, dev.model)
-
-static Property ide_hd_properties[] = {
- DEFINE_IDE_DEV_PROPERTIES(),
- DEFINE_BLOCK_CHS_PROPERTIES(IDEDrive, dev.conf),
- DEFINE_PROP_BIOS_CHS_TRANS("bios-chs-trans",
- IDEDrive, dev.chs_trans, BIOS_ATA_TRANSLATION_AUTO),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void ide_hd_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- IDEDeviceClass *k = IDE_DEVICE_CLASS(klass);
- k->init = ide_hd_initfn;
- dc->fw_name = "drive";
- dc->desc = "virtual IDE disk";
- dc->props = ide_hd_properties;
-}
-
-static const TypeInfo ide_hd_info = {
- .name = "ide-hd",
- .parent = TYPE_IDE_DEVICE,
- .instance_size = sizeof(IDEDrive),
- .class_init = ide_hd_class_init,
-};
-
-static Property ide_cd_properties[] = {
- DEFINE_IDE_DEV_PROPERTIES(),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void ide_cd_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- IDEDeviceClass *k = IDE_DEVICE_CLASS(klass);
- k->init = ide_cd_initfn;
- dc->fw_name = "drive";
- dc->desc = "virtual IDE CD-ROM";
- dc->props = ide_cd_properties;
-}
-
-static const TypeInfo ide_cd_info = {
- .name = "ide-cd",
- .parent = TYPE_IDE_DEVICE,
- .instance_size = sizeof(IDEDrive),
- .class_init = ide_cd_class_init,
-};
-
-static Property ide_drive_properties[] = {
- DEFINE_IDE_DEV_PROPERTIES(),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void ide_drive_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- IDEDeviceClass *k = IDE_DEVICE_CLASS(klass);
- k->init = ide_drive_initfn;
- dc->fw_name = "drive";
- dc->desc = "virtual IDE disk or CD-ROM (legacy)";
- dc->props = ide_drive_properties;
-}
-
-static const TypeInfo ide_drive_info = {
- .name = "ide-drive",
- .parent = TYPE_IDE_DEVICE,
- .instance_size = sizeof(IDEDrive),
- .class_init = ide_drive_class_init,
-};
-
-static void ide_device_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *k = DEVICE_CLASS(klass);
- k->init = ide_qdev_init;
- set_bit(DEVICE_CATEGORY_STORAGE, k->categories);
- k->bus_type = TYPE_IDE_BUS;
- k->props = ide_props;
-}
-
-static const TypeInfo ide_device_type_info = {
- .name = TYPE_IDE_DEVICE,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(IDEDevice),
- .abstract = true,
- .class_size = sizeof(IDEDeviceClass),
- .class_init = ide_device_class_init,
- .instance_init = ide_dev_instance_init,
-};
-
-static void ide_register_types(void)
-{
- type_register_static(&ide_bus_info);
- type_register_static(&ide_hd_info);
- type_register_static(&ide_cd_info);
- type_register_static(&ide_drive_info);
- type_register_static(&ide_device_type_info);
-}
-
-type_init(ide_register_types)
diff --git a/qemu/hw/ide/via.c b/qemu/hw/ide/via.c
deleted file mode 100644
index d3f72267a..000000000
--- a/qemu/hw/ide/via.c
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * QEMU IDE Emulation: PCI VIA82C686B support.
- *
- * Copyright (c) 2003 Fabrice Bellard
- * Copyright (c) 2006 Openedhand Ltd.
- * Copyright (c) 2010 Huacai Chen <zltjiangshi@gmail.com>
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include <hw/hw.h>
-#include <hw/i386/pc.h>
-#include <hw/pci/pci.h>
-#include <hw/isa/isa.h>
-#include "sysemu/block-backend.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/dma.h"
-
-#include <hw/ide/pci.h>
-
-static uint64_t bmdma_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- BMDMAState *bm = opaque;
- uint32_t val;
-
- if (size != 1) {
- return ((uint64_t)1 << (size * 8)) - 1;
- }
-
- switch (addr & 3) {
- case 0:
- val = bm->cmd;
- break;
- case 2:
- val = bm->status;
- break;
- default:
- val = 0xff;
- break;
- }
-#ifdef DEBUG_IDE
- printf("bmdma: readb 0x%02x : 0x%02x\n", addr, val);
-#endif
- return val;
-}
-
-static void bmdma_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- BMDMAState *bm = opaque;
-
- if (size != 1) {
- return;
- }
-
-#ifdef DEBUG_IDE
- printf("bmdma: writeb 0x%02x : 0x%02x\n", addr, val);
-#endif
- switch (addr & 3) {
- case 0:
- bmdma_cmd_writeb(bm, val);
- break;
- case 2:
- bm->status = (val & 0x60) | (bm->status & 1) | (bm->status & ~val & 0x06);
- break;
- default:;
- }
-}
-
-static const MemoryRegionOps via_bmdma_ops = {
- .read = bmdma_read,
- .write = bmdma_write,
-};
-
-static void bmdma_setup_bar(PCIIDEState *d)
-{
- int i;
-
- memory_region_init(&d->bmdma_bar, OBJECT(d), "via-bmdma-container", 16);
- for(i = 0;i < 2; i++) {
- BMDMAState *bm = &d->bmdma[i];
-
- memory_region_init_io(&bm->extra_io, OBJECT(d), &via_bmdma_ops, bm,
- "via-bmdma", 4);
- memory_region_add_subregion(&d->bmdma_bar, i * 8, &bm->extra_io);
- memory_region_init_io(&bm->addr_ioport, OBJECT(d),
- &bmdma_addr_ioport_ops, bm, "bmdma", 4);
- memory_region_add_subregion(&d->bmdma_bar, i * 8 + 4, &bm->addr_ioport);
- }
-}
-
-static void via_reset(void *opaque)
-{
- PCIIDEState *d = opaque;
- PCIDevice *pd = PCI_DEVICE(d);
- uint8_t *pci_conf = pd->config;
- int i;
-
- for (i = 0; i < 2; i++) {
- ide_bus_reset(&d->bus[i]);
- }
-
- pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_WAIT);
- pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_FAST_BACK |
- PCI_STATUS_DEVSEL_MEDIUM);
-
- pci_set_long(pci_conf + PCI_BASE_ADDRESS_0, 0x000001f0);
- pci_set_long(pci_conf + PCI_BASE_ADDRESS_1, 0x000003f4);
- pci_set_long(pci_conf + PCI_BASE_ADDRESS_2, 0x00000170);
- pci_set_long(pci_conf + PCI_BASE_ADDRESS_3, 0x00000374);
- pci_set_long(pci_conf + PCI_BASE_ADDRESS_4, 0x0000cc01); /* BMIBA: 20-23h */
- pci_set_long(pci_conf + PCI_INTERRUPT_LINE, 0x0000010e);
-
- /* IDE chip enable, IDE configuration 1/2, IDE FIFO Configuration*/
- pci_set_long(pci_conf + 0x40, 0x0a090600);
- /* IDE misc configuration 1/2/3 */
- pci_set_long(pci_conf + 0x44, 0x00c00068);
- /* IDE Timing control */
- pci_set_long(pci_conf + 0x48, 0xa8a8a8a8);
- /* IDE Address Setup Time */
- pci_set_long(pci_conf + 0x4c, 0x000000ff);
- /* UltraDMA Extended Timing Control*/
- pci_set_long(pci_conf + 0x50, 0x07070707);
- /* UltraDMA FIFO Control */
- pci_set_long(pci_conf + 0x54, 0x00000004);
- /* IDE primary sector size */
- pci_set_long(pci_conf + 0x60, 0x00000200);
- /* IDE secondary sector size */
- pci_set_long(pci_conf + 0x68, 0x00000200);
- /* PCI PM Block */
- pci_set_long(pci_conf + 0xc0, 0x00020001);
-}
-
-static void vt82c686b_init_ports(PCIIDEState *d) {
- static const struct {
- int iobase;
- int iobase2;
- int isairq;
- } port_info[] = {
- {0x1f0, 0x3f6, 14},
- {0x170, 0x376, 15},
- };
- int i;
-
- for (i = 0; i < 2; i++) {
- ide_bus_new(&d->bus[i], sizeof(d->bus[i]), DEVICE(d), i, 2);
- ide_init_ioport(&d->bus[i], NULL, port_info[i].iobase,
- port_info[i].iobase2);
- ide_init2(&d->bus[i], isa_get_irq(NULL, port_info[i].isairq));
-
- bmdma_init(&d->bus[i], &d->bmdma[i], d);
- d->bmdma[i].bus = &d->bus[i];
- ide_register_restart_cb(&d->bus[i]);
- }
-}
-
-/* via ide func */
-static void vt82c686b_ide_realize(PCIDevice *dev, Error **errp)
-{
- PCIIDEState *d = PCI_IDE(dev);
- uint8_t *pci_conf = dev->config;
-
- pci_config_set_prog_interface(pci_conf, 0x8a); /* legacy ATA mode */
- pci_set_long(pci_conf + PCI_CAPABILITY_LIST, 0x000000c0);
-
- qemu_register_reset(via_reset, d);
- bmdma_setup_bar(d);
- pci_register_bar(dev, 4, PCI_BASE_ADDRESS_SPACE_IO, &d->bmdma_bar);
-
- vmstate_register(DEVICE(dev), 0, &vmstate_ide_pci, d);
-
- vt82c686b_init_ports(d);
-}
-
-static void vt82c686b_ide_exitfn(PCIDevice *dev)
-{
- PCIIDEState *d = PCI_IDE(dev);
- unsigned i;
-
- for (i = 0; i < 2; ++i) {
- memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].extra_io);
- memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].addr_ioport);
- }
-}
-
-void vt82c686b_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
-{
- PCIDevice *dev;
-
- dev = pci_create_simple(bus, devfn, "via-ide");
- pci_ide_create_devs(dev, hd_table);
-}
-
-static void via_ide_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = vt82c686b_ide_realize;
- k->exit = vt82c686b_ide_exitfn;
- k->vendor_id = PCI_VENDOR_ID_VIA;
- k->device_id = PCI_DEVICE_ID_VIA_IDE;
- k->revision = 0x06;
- k->class_id = PCI_CLASS_STORAGE_IDE;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
-}
-
-static const TypeInfo via_ide_info = {
- .name = "via-ide",
- .parent = TYPE_PCI_IDE,
- .class_init = via_ide_class_init,
-};
-
-static void via_ide_register_types(void)
-{
- type_register_static(&via_ide_info);
-}
-
-type_init(via_ide_register_types)
diff --git a/qemu/hw/input/Makefile.objs b/qemu/hw/input/Makefile.objs
deleted file mode 100644
index 7715d7230..000000000
--- a/qemu/hw/input/Makefile.objs
+++ /dev/null
@@ -1,19 +0,0 @@
-common-obj-$(CONFIG_ADB) += adb.o
-common-obj-y += hid.o
-common-obj-$(CONFIG_LM832X) += lm832x.o
-common-obj-$(CONFIG_PCKBD) += pckbd.o
-common-obj-$(CONFIG_PL050) += pl050.o
-common-obj-y += ps2.o
-common-obj-$(CONFIG_STELLARIS_INPUT) += stellaris_input.o
-common-obj-$(CONFIG_TSC2005) += tsc2005.o
-common-obj-$(CONFIG_VMMOUSE) += vmmouse.o
-
-common-obj-$(CONFIG_VIRTIO) += virtio-input.o
-common-obj-$(CONFIG_VIRTIO) += virtio-input-hid.o
-ifeq ($(CONFIG_LINUX),y)
-common-obj-$(CONFIG_VIRTIO) += virtio-input-host.o
-endif
-
-obj-$(CONFIG_MILKYMIST) += milkymist-softusb.o
-obj-$(CONFIG_PXA2XX) += pxa2xx_keypad.o
-obj-$(CONFIG_TSC210X) += tsc210x.o
diff --git a/qemu/hw/input/adb.c b/qemu/hw/input/adb.c
deleted file mode 100644
index f0ad0d447..000000000
--- a/qemu/hw/input/adb.c
+++ /dev/null
@@ -1,598 +0,0 @@
-/*
- * QEMU ADB support
- *
- * Copyright (c) 2004 Fabrice Bellard
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/input/adb.h"
-#include "ui/console.h"
-
-/* debug ADB */
-//#define DEBUG_ADB
-
-#ifdef DEBUG_ADB
-#define ADB_DPRINTF(fmt, ...) \
-do { printf("ADB: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define ADB_DPRINTF(fmt, ...)
-#endif
-
-/* ADB commands */
-#define ADB_BUSRESET 0x00
-#define ADB_FLUSH 0x01
-#define ADB_WRITEREG 0x08
-#define ADB_READREG 0x0c
-
-/* ADB device commands */
-#define ADB_CMD_SELF_TEST 0xff
-#define ADB_CMD_CHANGE_ID 0xfe
-#define ADB_CMD_CHANGE_ID_AND_ACT 0xfd
-#define ADB_CMD_CHANGE_ID_AND_ENABLE 0x00
-
-/* ADB default device IDs (upper 4 bits of ADB command byte) */
-#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;
- int devaddr, cmd, i;
-
- cmd = buf[0] & 0xf;
- if (cmd == ADB_BUSRESET) {
- for(i = 0; i < s->nb_devices; i++) {
- 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];
- if (d->devaddr == devaddr) {
- ADBDeviceClass *adc = ADB_DEVICE_GET_CLASS(d);
- return adc->devreq(d, obuf, buf, len);
- }
- }
- return ADB_RET_NOTPRESENT;
-}
-
-/* XXX: move that to cuda ? */
-int adb_poll(ADBBusState *s, uint8_t *obuf, uint16_t poll_mask)
-{
- ADBDevice *d;
- int olen, i;
- uint8_t buf[1];
-
- olen = 0;
- 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];
- if ((1 << d->devaddr) & poll_mask) {
- 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 */
- if (olen > 0) {
- obuf[0] = buf[0];
- olen++;
- break;
- }
- }
- s->poll_index++;
- }
- return olen;
-}
-
-static const TypeInfo adb_bus_type_info = {
- .name = TYPE_ADB_BUS,
- .parent = TYPE_BUS,
- .instance_size = sizeof(ADBBusState),
-};
-
-static const VMStateDescription vmstate_adb_device = {
- .name = "adb_device",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_INT32(devaddr, ADBDevice),
- VMSTATE_INT32(handler, ADBDevice),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void adb_device_realizefn(DeviceState *dev, Error **errp)
-{
- 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,
- 2, 3, 5, 4, 38, 40, 37, 41, 39, 50, 56, 42, 6, 7, 8, 9,
- 11, 45, 46, 43, 47, 44,123, 67, 58, 49, 57,122,120, 99,118, 96,
- 97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83,
- 84, 85, 82, 65, 0, 0, 10,103,111, 0, 0,110, 81, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 94, 0, 93, 0, 0, 0, 0, 0, 0,104,102, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 76,125, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,105, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 75, 0, 0,124, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,115, 62,116, 0, 59, 0, 60, 0,119,
- 61,121,114,117, 0, 0, 0, 0, 0, 0, 0, 55,126, 0,127, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-};
-
-static void adb_kbd_put_keycode(void *opaque, int keycode)
-{
- KBDState *s = opaque;
-
- if (s->count < sizeof(s->data)) {
- s->data[s->wptr] = keycode;
- if (++s->wptr == sizeof(s->data))
- s->wptr = 0;
- s->count++;
- }
-}
-
-static int adb_kbd_poll(ADBDevice *d, uint8_t *obuf)
-{
- static int ext_keycode;
- KBDState *s = ADB_KEYBOARD(d);
- int adb_keycode, keycode;
- int olen;
-
- olen = 0;
- for(;;) {
- if (s->count == 0)
- break;
- keycode = s->data[s->rptr];
- if (++s->rptr == sizeof(s->data))
- s->rptr = 0;
- s->count--;
-
- if (keycode == 0xe0) {
- ext_keycode = 1;
- } else {
- if (ext_keycode)
- adb_keycode = pc_to_adb_keycode[keycode | 0x80];
- else
- adb_keycode = pc_to_adb_keycode[keycode & 0x7f];
- obuf[0] = adb_keycode | (keycode & 0x80);
- /* NOTE: could put a second keycode if needed */
- obuf[1] = 0xff;
- olen = 2;
- ext_keycode = 0;
- break;
- }
- }
- return olen;
-}
-
-static int adb_kbd_request(ADBDevice *d, uint8_t *obuf,
- const uint8_t *buf, int len)
-{
- KBDState *s = ADB_KEYBOARD(d);
- int cmd, reg, olen;
-
- if ((buf[0] & 0x0f) == ADB_FLUSH) {
- /* flush keyboard fifo */
- s->wptr = s->rptr = s->count = 0;
- return 0;
- }
-
- cmd = buf[0] & 0xc;
- reg = buf[0] & 0x3;
- olen = 0;
- switch(cmd) {
- case ADB_WRITEREG:
- switch(reg) {
- case 2:
- /* LED status */
- break;
- case 3:
- switch(buf[2]) {
- case ADB_CMD_SELF_TEST:
- break;
- case ADB_CMD_CHANGE_ID:
- case ADB_CMD_CHANGE_ID_AND_ACT:
- case ADB_CMD_CHANGE_ID_AND_ENABLE:
- d->devaddr = buf[1] & 0xf;
- break;
- default:
- /* XXX: check this */
- d->devaddr = buf[1] & 0xf;
- d->handler = buf[2];
- break;
- }
- }
- break;
- case ADB_READREG:
- switch(reg) {
- case 0:
- olen = adb_kbd_poll(d, obuf);
- break;
- case 1:
- break;
- case 2:
- obuf[0] = 0x00; /* XXX: check this */
- obuf[1] = 0x07; /* led status */
- olen = 2;
- break;
- case 3:
- obuf[0] = d->handler;
- obuf[1] = d->devaddr;
- olen = 2;
- break;
- }
- break;
- }
- return olen;
-}
-
-static const VMStateDescription vmstate_adb_kbd = {
- .name = "adb_kbd",
- .version_id = 2,
- .minimum_version_id = 2,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT(parent_obj, KBDState, 0, vmstate_adb_device, ADBDevice),
- VMSTATE_BUFFER(data, KBDState),
- VMSTATE_INT32(rptr, KBDState),
- VMSTATE_INT32(wptr, KBDState),
- VMSTATE_INT32(count, KBDState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void adb_kbd_reset(DeviceState *dev)
-{
- ADBDevice *d = ADB_DEVICE(dev);
- KBDState *s = ADB_KEYBOARD(dev);
-
- d->handler = 1;
- d->devaddr = ADB_DEVID_KEYBOARD;
- memset(s->data, 0, sizeof(s->data));
- s->rptr = 0;
- s->wptr = 0;
- s->count = 0;
-}
-
-static void adb_kbd_realizefn(DeviceState *dev, Error **errp)
-{
- 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);
-}
-
-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;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
-
- 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)
-{
- MouseState *s = opaque;
-
- s->dx += dx1;
- s->dy += dy1;
- s->dz += dz1;
- s->buttons_state = buttons_state;
-}
-
-
-static int adb_mouse_poll(ADBDevice *d, uint8_t *obuf)
-{
- MouseState *s = ADB_MOUSE(d);
- int dx, dy;
-
- if (s->last_buttons_state == s->buttons_state &&
- s->dx == 0 && s->dy == 0)
- return 0;
-
- dx = s->dx;
- if (dx < -63)
- dx = -63;
- else if (dx > 63)
- dx = 63;
-
- dy = s->dy;
- if (dy < -63)
- dy = -63;
- else if (dy > 63)
- dy = 63;
-
- s->dx -= dx;
- s->dy -= dy;
- s->last_buttons_state = s->buttons_state;
-
- dx &= 0x7f;
- dy &= 0x7f;
-
- if (!(s->buttons_state & MOUSE_EVENT_LBUTTON))
- dy |= 0x80;
- if (!(s->buttons_state & MOUSE_EVENT_RBUTTON))
- dx |= 0x80;
-
- obuf[0] = dy;
- obuf[1] = dx;
- return 2;
-}
-
-static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
- const uint8_t *buf, int len)
-{
- MouseState *s = ADB_MOUSE(d);
- int cmd, reg, olen;
-
- if ((buf[0] & 0x0f) == ADB_FLUSH) {
- /* flush mouse fifo */
- s->buttons_state = s->last_buttons_state;
- s->dx = 0;
- s->dy = 0;
- s->dz = 0;
- return 0;
- }
-
- cmd = buf[0] & 0xc;
- reg = buf[0] & 0x3;
- olen = 0;
- switch(cmd) {
- case ADB_WRITEREG:
- ADB_DPRINTF("write reg %d val 0x%2.2x\n", reg, buf[1]);
- switch(reg) {
- case 2:
- break;
- case 3:
- switch(buf[2]) {
- case ADB_CMD_SELF_TEST:
- break;
- case ADB_CMD_CHANGE_ID:
- case ADB_CMD_CHANGE_ID_AND_ACT:
- case ADB_CMD_CHANGE_ID_AND_ENABLE:
- d->devaddr = buf[1] & 0xf;
- break;
- default:
- /* XXX: check this */
- d->devaddr = buf[1] & 0xf;
- break;
- }
- }
- break;
- case ADB_READREG:
- switch(reg) {
- case 0:
- olen = adb_mouse_poll(d, obuf);
- break;
- case 1:
- break;
- case 3:
- obuf[0] = d->handler;
- obuf[1] = d->devaddr;
- olen = 2;
- break;
- }
- ADB_DPRINTF("read reg %d obuf[0] 0x%2.2x obuf[1] 0x%2.2x\n", reg,
- obuf[0], obuf[1]);
- break;
- }
- return olen;
-}
-
-static void adb_mouse_reset(DeviceState *dev)
-{
- ADBDevice *d = ADB_DEVICE(dev);
- MouseState *s = ADB_MOUSE(dev);
-
- d->handler = 2;
- 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 = {
- .name = "adb_mouse",
- .version_id = 2,
- .minimum_version_id = 2,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT(parent_obj, MouseState, 0, vmstate_adb_device,
- ADBDevice),
- VMSTATE_INT32(buttons_state, MouseState),
- VMSTATE_INT32(last_buttons_state, MouseState),
- VMSTATE_INT32(dx, MouseState),
- VMSTATE_INT32(dy, MouseState),
- VMSTATE_INT32(dz, MouseState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void adb_mouse_realizefn(DeviceState *dev, Error **errp)
-{
- 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;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
-
- 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/qemu/hw/input/hid.c b/qemu/hw/input/hid.c
deleted file mode 100644
index d92c7463b..000000000
--- a/qemu/hw/input/hid.c
+++ /dev/null
@@ -1,618 +0,0 @@
-/*
- * QEMU HID devices
- *
- * Copyright (c) 2005 Fabrice Bellard
- * Copyright (c) 2007 OpenMoko, Inc. (andrew@openedhand.com)
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "ui/console.h"
-#include "qemu/timer.h"
-#include "hw/input/hid.h"
-
-#define HID_USAGE_ERROR_ROLLOVER 0x01
-#define HID_USAGE_POSTFAIL 0x02
-#define HID_USAGE_ERROR_UNDEFINED 0x03
-
-/* Indices are QEMU keycodes, values are from HID Usage Table. Indices
- * above 0x80 are for keys that come after 0xe0 or 0xe1+0x1d or 0xe1+0x9d. */
-static const uint8_t hid_usage_keys[0x100] = {
- 0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
- 0x24, 0x25, 0x26, 0x27, 0x2d, 0x2e, 0x2a, 0x2b,
- 0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c,
- 0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16,
- 0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33,
- 0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19,
- 0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55,
- 0xe2, 0x2c, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
- 0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f,
- 0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59,
- 0x5a, 0x5b, 0x62, 0x63, 0x00, 0x00, 0x64, 0x44,
- 0x45, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
- 0xe8, 0xe9, 0x71, 0x72, 0x73, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65,
-
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46,
- 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x4a,
- 0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d,
- 0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
-
-bool hid_has_events(HIDState *hs)
-{
- return hs->n > 0 || hs->idle_pending;
-}
-
-static void hid_idle_timer(void *opaque)
-{
- HIDState *hs = opaque;
-
- hs->idle_pending = true;
- hs->event(hs);
-}
-
-static void hid_del_idle_timer(HIDState *hs)
-{
- if (hs->idle_timer) {
- timer_del(hs->idle_timer);
- timer_free(hs->idle_timer);
- hs->idle_timer = NULL;
- }
-}
-
-void hid_set_next_idle(HIDState *hs)
-{
- if (hs->idle) {
- uint64_t expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- NANOSECONDS_PER_SECOND * hs->idle * 4 / 1000;
- if (!hs->idle_timer) {
- hs->idle_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, hid_idle_timer, hs);
- }
- timer_mod_ns(hs->idle_timer, expire_time);
- } else {
- hid_del_idle_timer(hs);
- }
-}
-
-static void hid_pointer_event(DeviceState *dev, QemuConsole *src,
- InputEvent *evt)
-{
- static const int bmap[INPUT_BUTTON__MAX] = {
- [INPUT_BUTTON_LEFT] = 0x01,
- [INPUT_BUTTON_RIGHT] = 0x02,
- [INPUT_BUTTON_MIDDLE] = 0x04,
- };
- HIDState *hs = (HIDState *)dev;
- HIDPointerEvent *e;
- InputMoveEvent *move;
- InputBtnEvent *btn;
-
- assert(hs->n < QUEUE_LENGTH);
- e = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK];
-
- switch (evt->type) {
- case INPUT_EVENT_KIND_REL:
- move = evt->u.rel.data;
- if (move->axis == INPUT_AXIS_X) {
- e->xdx += move->value;
- } else if (move->axis == INPUT_AXIS_Y) {
- e->ydy += move->value;
- }
- break;
-
- case INPUT_EVENT_KIND_ABS:
- move = evt->u.abs.data;
- if (move->axis == INPUT_AXIS_X) {
- e->xdx = move->value;
- } else if (move->axis == INPUT_AXIS_Y) {
- e->ydy = move->value;
- }
- break;
-
- case INPUT_EVENT_KIND_BTN:
- btn = evt->u.btn.data;
- if (btn->down) {
- e->buttons_state |= bmap[btn->button];
- if (btn->button == INPUT_BUTTON_WHEEL_UP) {
- e->dz--;
- } else if (btn->button == INPUT_BUTTON_WHEEL_DOWN) {
- e->dz++;
- }
- } else {
- e->buttons_state &= ~bmap[btn->button];
- }
- break;
-
- default:
- /* keep gcc happy */
- break;
- }
-
-}
-
-static void hid_pointer_sync(DeviceState *dev)
-{
- HIDState *hs = (HIDState *)dev;
- HIDPointerEvent *prev, *curr, *next;
- bool event_compression = false;
-
- if (hs->n == QUEUE_LENGTH-1) {
- /*
- * Queue full. We are losing information, but we at least
- * keep track of most recent button state.
- */
- return;
- }
-
- prev = &hs->ptr.queue[(hs->head + hs->n - 1) & QUEUE_MASK];
- curr = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK];
- next = &hs->ptr.queue[(hs->head + hs->n + 1) & QUEUE_MASK];
-
- if (hs->n > 0) {
- /*
- * No button state change between previous and current event
- * (and previous wasn't seen by the guest yet), so there is
- * motion information only and we can combine the two event
- * into one.
- */
- if (curr->buttons_state == prev->buttons_state) {
- event_compression = true;
- }
- }
-
- if (event_compression) {
- /* add current motion to previous, clear current */
- if (hs->kind == HID_MOUSE) {
- prev->xdx += curr->xdx;
- curr->xdx = 0;
- prev->ydy += curr->ydy;
- curr->ydy = 0;
- } else {
- prev->xdx = curr->xdx;
- prev->ydy = curr->ydy;
- }
- prev->dz += curr->dz;
- curr->dz = 0;
- } else {
- /* prepate next (clear rel, copy abs + btns) */
- if (hs->kind == HID_MOUSE) {
- next->xdx = 0;
- next->ydy = 0;
- } else {
- next->xdx = curr->xdx;
- next->ydy = curr->ydy;
- }
- next->dz = 0;
- next->buttons_state = curr->buttons_state;
- /* make current guest visible, notify guest */
- hs->n++;
- hs->event(hs);
- }
-}
-
-static void hid_keyboard_event(DeviceState *dev, QemuConsole *src,
- InputEvent *evt)
-{
- HIDState *hs = (HIDState *)dev;
- int scancodes[3], i, count;
- int slot;
- InputKeyEvent *key = evt->u.key.data;
-
- count = qemu_input_key_value_to_scancode(key->key,
- key->down,
- scancodes);
- if (hs->n + count > QUEUE_LENGTH) {
- fprintf(stderr, "usb-kbd: warning: key event queue full\n");
- return;
- }
- for (i = 0; i < count; i++) {
- slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++;
- hs->kbd.keycodes[slot] = scancodes[i];
- }
- hs->event(hs);
-}
-
-static void hid_keyboard_process_keycode(HIDState *hs)
-{
- uint8_t hid_code, index, key;
- int i, keycode, slot;
-
- if (hs->n == 0) {
- return;
- }
- slot = hs->head & QUEUE_MASK; QUEUE_INCR(hs->head); hs->n--;
- keycode = hs->kbd.keycodes[slot];
-
- key = keycode & 0x7f;
- index = key | ((hs->kbd.modifiers & (1 << 8)) >> 1);
- hid_code = hid_usage_keys[index];
- hs->kbd.modifiers &= ~(1 << 8);
-
- switch (hid_code) {
- case 0x00:
- return;
-
- case 0xe0:
- assert(key == 0x1d);
- if (hs->kbd.modifiers & (1 << 9)) {
- /* The hid_codes for the 0xe1/0x1d scancode sequence are 0xe9/0xe0.
- * Here we're processing the second hid_code. By dropping bit 9
- * and setting bit 8, the scancode after 0x1d will access the
- * second half of the table.
- */
- hs->kbd.modifiers ^= (1 << 8) | (1 << 9);
- return;
- }
- /* fall through to process Ctrl_L */
- case 0xe1 ... 0xe7:
- /* Ctrl_L/Ctrl_R, Shift_L/Shift_R, Alt_L/Alt_R, Win_L/Win_R.
- * Handle releases here, or fall through to process presses.
- */
- if (keycode & (1 << 7)) {
- hs->kbd.modifiers &= ~(1 << (hid_code & 0x0f));
- return;
- }
- /* fall through */
- case 0xe8 ... 0xe9:
- /* USB modifiers are just 1 byte long. Bits 8 and 9 of
- * hs->kbd.modifiers implement a state machine that detects the
- * 0xe0 and 0xe1/0x1d sequences. These bits do not follow the
- * usual rules where bit 7 marks released keys; they are cleared
- * elsewhere in the function as the state machine dictates.
- */
- hs->kbd.modifiers |= 1 << (hid_code & 0x0f);
- return;
-
- case 0xea ... 0xef:
- abort();
-
- default:
- break;
- }
-
- if (keycode & (1 << 7)) {
- for (i = hs->kbd.keys - 1; i >= 0; i--) {
- if (hs->kbd.key[i] == hid_code) {
- hs->kbd.key[i] = hs->kbd.key[-- hs->kbd.keys];
- hs->kbd.key[hs->kbd.keys] = 0x00;
- break;
- }
- }
- if (i < 0) {
- return;
- }
- } else {
- for (i = hs->kbd.keys - 1; i >= 0; i--) {
- if (hs->kbd.key[i] == hid_code) {
- break;
- }
- }
- if (i < 0) {
- if (hs->kbd.keys < sizeof(hs->kbd.key)) {
- hs->kbd.key[hs->kbd.keys++] = hid_code;
- }
- } else {
- return;
- }
- }
-}
-
-static inline int int_clamp(int val, int vmin, int vmax)
-{
- if (val < vmin) {
- return vmin;
- } else if (val > vmax) {
- return vmax;
- } else {
- return val;
- }
-}
-
-void hid_pointer_activate(HIDState *hs)
-{
- if (!hs->ptr.mouse_grabbed) {
- qemu_input_handler_activate(hs->s);
- hs->ptr.mouse_grabbed = 1;
- }
-}
-
-int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
-{
- int dx, dy, dz, l;
- int index;
- HIDPointerEvent *e;
-
- hs->idle_pending = false;
-
- hid_pointer_activate(hs);
-
- /* When the buffer is empty, return the last event. Relative
- movements will all be zero. */
- index = (hs->n ? hs->head : hs->head - 1);
- e = &hs->ptr.queue[index & QUEUE_MASK];
-
- if (hs->kind == HID_MOUSE) {
- dx = int_clamp(e->xdx, -127, 127);
- dy = int_clamp(e->ydy, -127, 127);
- e->xdx -= dx;
- e->ydy -= dy;
- } else {
- dx = e->xdx;
- dy = e->ydy;
- }
- dz = int_clamp(e->dz, -127, 127);
- e->dz -= dz;
-
- if (hs->n &&
- !e->dz &&
- (hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) {
- /* that deals with this event */
- QUEUE_INCR(hs->head);
- hs->n--;
- }
-
- /* Appears we have to invert the wheel direction */
- dz = 0 - dz;
- l = 0;
- switch (hs->kind) {
- case HID_MOUSE:
- if (len > l) {
- buf[l++] = e->buttons_state;
- }
- if (len > l) {
- buf[l++] = dx;
- }
- if (len > l) {
- buf[l++] = dy;
- }
- if (len > l) {
- buf[l++] = dz;
- }
- break;
-
- case HID_TABLET:
- if (len > l) {
- buf[l++] = e->buttons_state;
- }
- if (len > l) {
- buf[l++] = dx & 0xff;
- }
- if (len > l) {
- buf[l++] = dx >> 8;
- }
- if (len > l) {
- buf[l++] = dy & 0xff;
- }
- if (len > l) {
- buf[l++] = dy >> 8;
- }
- if (len > l) {
- buf[l++] = dz;
- }
- break;
-
- default:
- abort();
- }
-
- return l;
-}
-
-int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len)
-{
- hs->idle_pending = false;
-
- if (len < 2) {
- return 0;
- }
-
- hid_keyboard_process_keycode(hs);
-
- buf[0] = hs->kbd.modifiers & 0xff;
- buf[1] = 0;
- if (hs->kbd.keys > 6) {
- memset(buf + 2, HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2);
- } else {
- memcpy(buf + 2, hs->kbd.key, MIN(8, len) - 2);
- }
-
- return MIN(8, len);
-}
-
-int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len)
-{
- if (len > 0) {
- int ledstate = 0;
- /* 0x01: Num Lock LED
- * 0x02: Caps Lock LED
- * 0x04: Scroll Lock LED
- * 0x08: Compose LED
- * 0x10: Kana LED */
- hs->kbd.leds = buf[0];
- if (hs->kbd.leds & 0x04) {
- ledstate |= QEMU_SCROLL_LOCK_LED;
- }
- if (hs->kbd.leds & 0x01) {
- ledstate |= QEMU_NUM_LOCK_LED;
- }
- if (hs->kbd.leds & 0x02) {
- ledstate |= QEMU_CAPS_LOCK_LED;
- }
- kbd_put_ledstate(ledstate);
- }
- return 0;
-}
-
-void hid_reset(HIDState *hs)
-{
- switch (hs->kind) {
- case HID_KEYBOARD:
- memset(hs->kbd.keycodes, 0, sizeof(hs->kbd.keycodes));
- memset(hs->kbd.key, 0, sizeof(hs->kbd.key));
- hs->kbd.keys = 0;
- break;
- case HID_MOUSE:
- case HID_TABLET:
- memset(hs->ptr.queue, 0, sizeof(hs->ptr.queue));
- break;
- }
- hs->head = 0;
- hs->n = 0;
- hs->protocol = 1;
- hs->idle = 0;
- hs->idle_pending = false;
- hid_del_idle_timer(hs);
-}
-
-void hid_free(HIDState *hs)
-{
- qemu_input_handler_unregister(hs->s);
- hid_del_idle_timer(hs);
-}
-
-static QemuInputHandler hid_keyboard_handler = {
- .name = "QEMU HID Keyboard",
- .mask = INPUT_EVENT_MASK_KEY,
- .event = hid_keyboard_event,
-};
-
-static QemuInputHandler hid_mouse_handler = {
- .name = "QEMU HID Mouse",
- .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
- .event = hid_pointer_event,
- .sync = hid_pointer_sync,
-};
-
-static QemuInputHandler hid_tablet_handler = {
- .name = "QEMU HID Tablet",
- .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS,
- .event = hid_pointer_event,
- .sync = hid_pointer_sync,
-};
-
-void hid_init(HIDState *hs, int kind, HIDEventFunc event)
-{
- hs->kind = kind;
- hs->event = event;
-
- if (hs->kind == HID_KEYBOARD) {
- hs->s = qemu_input_handler_register((DeviceState *)hs,
- &hid_keyboard_handler);
- qemu_input_handler_activate(hs->s);
- } else if (hs->kind == HID_MOUSE) {
- hs->s = qemu_input_handler_register((DeviceState *)hs,
- &hid_mouse_handler);
- } else if (hs->kind == HID_TABLET) {
- hs->s = qemu_input_handler_register((DeviceState *)hs,
- &hid_tablet_handler);
- }
-}
-
-static int hid_post_load(void *opaque, int version_id)
-{
- HIDState *s = opaque;
-
- hid_set_next_idle(s);
-
- if (s->n == QUEUE_LENGTH && (s->kind == HID_TABLET ||
- s->kind == HID_MOUSE)) {
- /*
- * Handle ptr device migration from old qemu with full queue.
- *
- * Throw away everything but the last event, so we propagate
- * at least the current button state to the guest. Also keep
- * current position for the tablet, signal "no motion" for the
- * mouse.
- */
- HIDPointerEvent evt;
- evt = s->ptr.queue[(s->head+s->n) & QUEUE_MASK];
- if (s->kind == HID_MOUSE) {
- evt.xdx = 0;
- evt.ydy = 0;
- }
- s->ptr.queue[0] = evt;
- s->head = 0;
- s->n = 1;
- }
- return 0;
-}
-
-static const VMStateDescription vmstate_hid_ptr_queue = {
- .name = "HIDPointerEventQueue",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_INT32(xdx, HIDPointerEvent),
- VMSTATE_INT32(ydy, HIDPointerEvent),
- VMSTATE_INT32(dz, HIDPointerEvent),
- VMSTATE_INT32(buttons_state, HIDPointerEvent),
- VMSTATE_END_OF_LIST()
- }
-};
-
-const VMStateDescription vmstate_hid_ptr_device = {
- .name = "HIDPointerDevice",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = hid_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT_ARRAY(ptr.queue, HIDState, QUEUE_LENGTH, 0,
- vmstate_hid_ptr_queue, HIDPointerEvent),
- VMSTATE_UINT32(head, HIDState),
- VMSTATE_UINT32(n, HIDState),
- VMSTATE_INT32(protocol, HIDState),
- VMSTATE_UINT8(idle, HIDState),
- VMSTATE_END_OF_LIST(),
- }
-};
-
-const VMStateDescription vmstate_hid_keyboard_device = {
- .name = "HIDKeyboardDevice",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = hid_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(kbd.keycodes, HIDState, QUEUE_LENGTH),
- VMSTATE_UINT32(head, HIDState),
- VMSTATE_UINT32(n, HIDState),
- VMSTATE_UINT16(kbd.modifiers, HIDState),
- VMSTATE_UINT8(kbd.leds, HIDState),
- VMSTATE_UINT8_ARRAY(kbd.key, HIDState, 16),
- VMSTATE_INT32(kbd.keys, HIDState),
- VMSTATE_INT32(protocol, HIDState),
- VMSTATE_UINT8(idle, HIDState),
- VMSTATE_END_OF_LIST(),
- }
-};
diff --git a/qemu/hw/input/lm832x.c b/qemu/hw/input/lm832x.c
deleted file mode 100644
index 539682cac..000000000
--- a/qemu/hw/input/lm832x.c
+++ /dev/null
@@ -1,525 +0,0 @@
-/*
- * National Semiconductor LM8322/8323 GPIO keyboard & PWM chips.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/i2c/i2c.h"
-#include "qemu/timer.h"
-#include "ui/console.h"
-
-#define TYPE_LM8323 "lm8323"
-#define LM8323(obj) OBJECT_CHECK(LM823KbdState, (obj), TYPE_LM8323)
-
-typedef struct {
- I2CSlave parent_obj;
-
- uint8_t i2c_dir;
- uint8_t i2c_cycle;
- uint8_t reg;
-
- qemu_irq nirq;
- uint16_t model;
-
- struct {
- qemu_irq out[2];
- int in[2][2];
- } mux;
-
- uint8_t config;
- uint8_t status;
- uint8_t acttime;
- uint8_t error;
- uint8_t clock;
-
- struct {
- uint16_t pull;
- uint16_t mask;
- uint16_t dir;
- uint16_t level;
- qemu_irq out[16];
- } gpio;
-
- struct {
- uint8_t dbnctime;
- uint8_t size;
- uint8_t start;
- uint8_t len;
- uint8_t fifo[16];
- } kbd;
-
- struct {
- uint16_t file[256];
- uint8_t faddr;
- uint8_t addr[3];
- QEMUTimer *tm[3];
- } pwm;
-} LM823KbdState;
-
-#define INT_KEYPAD (1 << 0)
-#define INT_ERROR (1 << 3)
-#define INT_NOINIT (1 << 4)
-#define INT_PWMEND(n) (1 << (5 + n))
-
-#define ERR_BADPAR (1 << 0)
-#define ERR_CMDUNK (1 << 1)
-#define ERR_KEYOVR (1 << 2)
-#define ERR_FIFOOVR (1 << 6)
-
-static void lm_kbd_irq_update(LM823KbdState *s)
-{
- qemu_set_irq(s->nirq, !s->status);
-}
-
-static void lm_kbd_gpio_update(LM823KbdState *s)
-{
-}
-
-static void lm_kbd_reset(LM823KbdState *s)
-{
- s->config = 0x80;
- s->status = INT_NOINIT;
- s->acttime = 125;
- s->kbd.dbnctime = 3;
- s->kbd.size = 0x33;
- s->clock = 0x08;
-
- lm_kbd_irq_update(s);
- lm_kbd_gpio_update(s);
-}
-
-static void lm_kbd_error(LM823KbdState *s, int err)
-{
- s->error |= err;
- s->status |= INT_ERROR;
- lm_kbd_irq_update(s);
-}
-
-static void lm_kbd_pwm_tick(LM823KbdState *s, int line)
-{
-}
-
-static void lm_kbd_pwm_start(LM823KbdState *s, int line)
-{
- lm_kbd_pwm_tick(s, line);
-}
-
-static void lm_kbd_pwm0_tick(void *opaque)
-{
- lm_kbd_pwm_tick(opaque, 0);
-}
-static void lm_kbd_pwm1_tick(void *opaque)
-{
- lm_kbd_pwm_tick(opaque, 1);
-}
-static void lm_kbd_pwm2_tick(void *opaque)
-{
- lm_kbd_pwm_tick(opaque, 2);
-}
-
-enum {
- LM832x_CMD_READ_ID = 0x80, /* Read chip ID. */
- LM832x_CMD_WRITE_CFG = 0x81, /* Set configuration item. */
- LM832x_CMD_READ_INT = 0x82, /* Get interrupt status. */
- LM832x_CMD_RESET = 0x83, /* Reset, same as external one */
- LM823x_CMD_WRITE_PULL_DOWN = 0x84, /* Select GPIO pull-up/down. */
- LM832x_CMD_WRITE_PORT_SEL = 0x85, /* Select GPIO in/out. */
- LM832x_CMD_WRITE_PORT_STATE = 0x86, /* Set GPIO pull-up/down. */
- LM832x_CMD_READ_PORT_SEL = 0x87, /* Get GPIO in/out. */
- LM832x_CMD_READ_PORT_STATE = 0x88, /* Get GPIO pull-up/down. */
- LM832x_CMD_READ_FIFO = 0x89, /* Read byte from FIFO. */
- LM832x_CMD_RPT_READ_FIFO = 0x8a, /* Read FIFO (no increment). */
- LM832x_CMD_SET_ACTIVE = 0x8b, /* Set active time. */
- LM832x_CMD_READ_ERROR = 0x8c, /* Get error status. */
- LM832x_CMD_READ_ROTATOR = 0x8e, /* Read rotator status. */
- LM832x_CMD_SET_DEBOUNCE = 0x8f, /* Set debouncing time. */
- LM832x_CMD_SET_KEY_SIZE = 0x90, /* Set keypad size. */
- LM832x_CMD_READ_KEY_SIZE = 0x91, /* Get keypad size. */
- LM832x_CMD_READ_CFG = 0x92, /* Get configuration item. */
- LM832x_CMD_WRITE_CLOCK = 0x93, /* Set clock config. */
- LM832x_CMD_READ_CLOCK = 0x94, /* Get clock config. */
- LM832x_CMD_PWM_WRITE = 0x95, /* Write PWM script. */
- LM832x_CMD_PWM_START = 0x96, /* Start PWM engine. */
- LM832x_CMD_PWM_STOP = 0x97, /* Stop PWM engine. */
- LM832x_GENERAL_ERROR = 0xff, /* There was one error.
- Previously was represented by -1
- This is not a command */
-};
-
-#define LM832x_MAX_KPX 8
-#define LM832x_MAX_KPY 12
-
-static uint8_t lm_kbd_read(LM823KbdState *s, int reg, int byte)
-{
- int ret;
-
- switch (reg) {
- case LM832x_CMD_READ_ID:
- ret = 0x0400;
- break;
-
- case LM832x_CMD_READ_INT:
- ret = s->status;
- if (!(s->status & INT_NOINIT)) {
- s->status = 0;
- lm_kbd_irq_update(s);
- }
- break;
-
- case LM832x_CMD_READ_PORT_SEL:
- ret = s->gpio.dir;
- break;
- case LM832x_CMD_READ_PORT_STATE:
- ret = s->gpio.mask;
- break;
-
- case LM832x_CMD_READ_FIFO:
- if (s->kbd.len <= 1)
- return 0x00;
-
- /* Example response from the two commands after a INT_KEYPAD
- * interrupt caused by the key 0x3c being pressed:
- * RPT_READ_FIFO: 55 bc 00 4e ff 0a 50 08 00 29 d9 08 01 c9 01
- * READ_FIFO: bc 00 00 4e ff 0a 50 08 00 29 d9 08 01 c9 01
- * RPT_READ_FIFO: bc 00 00 4e ff 0a 50 08 00 29 d9 08 01 c9 01
- *
- * 55 is the code of the key release event serviced in the previous
- * interrupt handling.
- *
- * TODO: find out whether the FIFO is advanced a single character
- * before reading every byte or the whole size of the FIFO at the
- * last LM832x_CMD_READ_FIFO. This affects LM832x_CMD_RPT_READ_FIFO
- * output in cases where there are more than one event in the FIFO.
- * Assume 0xbc and 0x3c events are in the FIFO:
- * RPT_READ_FIFO: 55 bc 3c 00 4e ff 0a 50 08 00 29 d9 08 01 c9
- * READ_FIFO: bc 3c 00 00 4e ff 0a 50 08 00 29 d9 08 01 c9
- * Does RPT_READ_FIFO now return 0xbc and 0x3c or only 0x3c?
- */
- s->kbd.start ++;
- s->kbd.start &= sizeof(s->kbd.fifo) - 1;
- s->kbd.len --;
-
- return s->kbd.fifo[s->kbd.start];
- case LM832x_CMD_RPT_READ_FIFO:
- if (byte >= s->kbd.len)
- return 0x00;
-
- return s->kbd.fifo[(s->kbd.start + byte) & (sizeof(s->kbd.fifo) - 1)];
-
- case LM832x_CMD_READ_ERROR:
- return s->error;
-
- case LM832x_CMD_READ_ROTATOR:
- return 0;
-
- case LM832x_CMD_READ_KEY_SIZE:
- return s->kbd.size;
-
- case LM832x_CMD_READ_CFG:
- return s->config & 0xf;
-
- case LM832x_CMD_READ_CLOCK:
- return (s->clock & 0xfc) | 2;
-
- default:
- lm_kbd_error(s, ERR_CMDUNK);
- fprintf(stderr, "%s: unknown command %02x\n", __FUNCTION__, reg);
- return 0x00;
- }
-
- return ret >> (byte << 3);
-}
-
-static void lm_kbd_write(LM823KbdState *s, int reg, int byte, uint8_t value)
-{
- switch (reg) {
- case LM832x_CMD_WRITE_CFG:
- s->config = value;
- /* This must be done whenever s->mux.in is updated (never). */
- if ((s->config >> 1) & 1) /* MUX1EN */
- qemu_set_irq(s->mux.out[0], s->mux.in[0][(s->config >> 0) & 1]);
- if ((s->config >> 3) & 1) /* MUX2EN */
- qemu_set_irq(s->mux.out[0], s->mux.in[0][(s->config >> 2) & 1]);
- /* TODO: check that this is issued only following the chip reset
- * and not in the middle of operation and that it is followed by
- * the GPIO ports re-resablishing through WRITE_PORT_SEL and
- * WRITE_PORT_STATE (using a timer perhaps) and otherwise output
- * warnings. */
- s->status = 0;
- lm_kbd_irq_update(s);
- s->kbd.len = 0;
- s->kbd.start = 0;
- s->reg = LM832x_GENERAL_ERROR;
- break;
-
- case LM832x_CMD_RESET:
- if (value == 0xaa)
- lm_kbd_reset(s);
- else
- lm_kbd_error(s, ERR_BADPAR);
- s->reg = LM832x_GENERAL_ERROR;
- break;
-
- case LM823x_CMD_WRITE_PULL_DOWN:
- if (!byte)
- s->gpio.pull = value;
- else {
- s->gpio.pull |= value << 8;
- lm_kbd_gpio_update(s);
- s->reg = LM832x_GENERAL_ERROR;
- }
- break;
- case LM832x_CMD_WRITE_PORT_SEL:
- if (!byte)
- s->gpio.dir = value;
- else {
- s->gpio.dir |= value << 8;
- lm_kbd_gpio_update(s);
- s->reg = LM832x_GENERAL_ERROR;
- }
- break;
- case LM832x_CMD_WRITE_PORT_STATE:
- if (!byte)
- s->gpio.mask = value;
- else {
- s->gpio.mask |= value << 8;
- lm_kbd_gpio_update(s);
- s->reg = LM832x_GENERAL_ERROR;
- }
- break;
-
- case LM832x_CMD_SET_ACTIVE:
- s->acttime = value;
- s->reg = LM832x_GENERAL_ERROR;
- break;
-
- case LM832x_CMD_SET_DEBOUNCE:
- s->kbd.dbnctime = value;
- s->reg = LM832x_GENERAL_ERROR;
- if (!value)
- lm_kbd_error(s, ERR_BADPAR);
- break;
-
- case LM832x_CMD_SET_KEY_SIZE:
- s->kbd.size = value;
- s->reg = LM832x_GENERAL_ERROR;
- if (
- (value & 0xf) < 3 || (value & 0xf) > LM832x_MAX_KPY ||
- (value >> 4) < 3 || (value >> 4) > LM832x_MAX_KPX)
- lm_kbd_error(s, ERR_BADPAR);
- break;
-
- case LM832x_CMD_WRITE_CLOCK:
- s->clock = value;
- s->reg = LM832x_GENERAL_ERROR;
- if ((value & 3) && (value & 3) != 3) {
- lm_kbd_error(s, ERR_BADPAR);
- fprintf(stderr, "%s: invalid clock setting in RCPWM\n",
- __FUNCTION__);
- }
- /* TODO: Validate that the command is only issued once */
- break;
-
- case LM832x_CMD_PWM_WRITE:
- if (byte == 0) {
- if (!(value & 3) || (value >> 2) > 59) {
- lm_kbd_error(s, ERR_BADPAR);
- s->reg = LM832x_GENERAL_ERROR;
- break;
- }
-
- s->pwm.faddr = value;
- s->pwm.file[s->pwm.faddr] = 0;
- } else if (byte == 1) {
- s->pwm.file[s->pwm.faddr] |= value << 8;
- } else if (byte == 2) {
- s->pwm.file[s->pwm.faddr] |= value << 0;
- s->reg = LM832x_GENERAL_ERROR;
- }
- break;
- case LM832x_CMD_PWM_START:
- s->reg = LM832x_GENERAL_ERROR;
- if (!(value & 3) || (value >> 2) > 59) {
- lm_kbd_error(s, ERR_BADPAR);
- break;
- }
-
- s->pwm.addr[(value & 3) - 1] = value >> 2;
- lm_kbd_pwm_start(s, (value & 3) - 1);
- break;
- case LM832x_CMD_PWM_STOP:
- s->reg = LM832x_GENERAL_ERROR;
- if (!(value & 3)) {
- lm_kbd_error(s, ERR_BADPAR);
- break;
- }
-
- timer_del(s->pwm.tm[(value & 3) - 1]);
- break;
-
- case LM832x_GENERAL_ERROR:
- lm_kbd_error(s, ERR_BADPAR);
- break;
- default:
- lm_kbd_error(s, ERR_CMDUNK);
- fprintf(stderr, "%s: unknown command %02x\n", __FUNCTION__, reg);
- break;
- }
-}
-
-static void lm_i2c_event(I2CSlave *i2c, enum i2c_event event)
-{
- LM823KbdState *s = LM8323(i2c);
-
- switch (event) {
- case I2C_START_RECV:
- case I2C_START_SEND:
- s->i2c_cycle = 0;
- s->i2c_dir = (event == I2C_START_SEND);
- break;
-
- default:
- break;
- }
-}
-
-static int lm_i2c_rx(I2CSlave *i2c)
-{
- LM823KbdState *s = LM8323(i2c);
-
- return lm_kbd_read(s, s->reg, s->i2c_cycle ++);
-}
-
-static int lm_i2c_tx(I2CSlave *i2c, uint8_t data)
-{
- LM823KbdState *s = LM8323(i2c);
-
- if (!s->i2c_cycle)
- s->reg = data;
- else
- lm_kbd_write(s, s->reg, s->i2c_cycle - 1, data);
- s->i2c_cycle ++;
-
- return 0;
-}
-
-static int lm_kbd_post_load(void *opaque, int version_id)
-{
- LM823KbdState *s = opaque;
-
- lm_kbd_irq_update(s);
- lm_kbd_gpio_update(s);
-
- return 0;
-}
-
-static const VMStateDescription vmstate_lm_kbd = {
- .name = "LM8323",
- .version_id = 0,
- .minimum_version_id = 0,
- .post_load = lm_kbd_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_I2C_SLAVE(parent_obj, LM823KbdState),
- VMSTATE_UINT8(i2c_dir, LM823KbdState),
- VMSTATE_UINT8(i2c_cycle, LM823KbdState),
- VMSTATE_UINT8(reg, LM823KbdState),
- VMSTATE_UINT8(config, LM823KbdState),
- VMSTATE_UINT8(status, LM823KbdState),
- VMSTATE_UINT8(acttime, LM823KbdState),
- VMSTATE_UINT8(error, LM823KbdState),
- VMSTATE_UINT8(clock, LM823KbdState),
- VMSTATE_UINT16(gpio.pull, LM823KbdState),
- VMSTATE_UINT16(gpio.mask, LM823KbdState),
- VMSTATE_UINT16(gpio.dir, LM823KbdState),
- VMSTATE_UINT16(gpio.level, LM823KbdState),
- VMSTATE_UINT8(kbd.dbnctime, LM823KbdState),
- VMSTATE_UINT8(kbd.size, LM823KbdState),
- VMSTATE_UINT8(kbd.start, LM823KbdState),
- VMSTATE_UINT8(kbd.len, LM823KbdState),
- VMSTATE_BUFFER(kbd.fifo, LM823KbdState),
- VMSTATE_UINT16_ARRAY(pwm.file, LM823KbdState, 256),
- VMSTATE_UINT8(pwm.faddr, LM823KbdState),
- VMSTATE_BUFFER(pwm.addr, LM823KbdState),
- VMSTATE_TIMER_PTR_ARRAY(pwm.tm, LM823KbdState, 3),
- VMSTATE_END_OF_LIST()
- }
-};
-
-
-static int lm8323_init(I2CSlave *i2c)
-{
- LM823KbdState *s = LM8323(i2c);
-
- s->model = 0x8323;
- s->pwm.tm[0] = timer_new_ns(QEMU_CLOCK_VIRTUAL, lm_kbd_pwm0_tick, s);
- s->pwm.tm[1] = timer_new_ns(QEMU_CLOCK_VIRTUAL, lm_kbd_pwm1_tick, s);
- s->pwm.tm[2] = timer_new_ns(QEMU_CLOCK_VIRTUAL, lm_kbd_pwm2_tick, s);
- qdev_init_gpio_out(DEVICE(i2c), &s->nirq, 1);
-
- lm_kbd_reset(s);
-
- qemu_register_reset((void *) lm_kbd_reset, s);
- return 0;
-}
-
-void lm832x_key_event(DeviceState *dev, int key, int state)
-{
- LM823KbdState *s = LM8323(dev);
-
- if ((s->status & INT_ERROR) && (s->error & ERR_FIFOOVR))
- return;
-
- if (s->kbd.len >= sizeof(s->kbd.fifo)) {
- lm_kbd_error(s, ERR_FIFOOVR);
- return;
- }
-
- s->kbd.fifo[(s->kbd.start + s->kbd.len ++) & (sizeof(s->kbd.fifo) - 1)] =
- key | (state << 7);
-
- /* We never set ERR_KEYOVR because we support multiple keys fine. */
- s->status |= INT_KEYPAD;
- lm_kbd_irq_update(s);
-}
-
-static void lm8323_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
-
- k->init = lm8323_init;
- k->event = lm_i2c_event;
- k->recv = lm_i2c_rx;
- k->send = lm_i2c_tx;
- dc->vmsd = &vmstate_lm_kbd;
-}
-
-static const TypeInfo lm8323_info = {
- .name = TYPE_LM8323,
- .parent = TYPE_I2C_SLAVE,
- .instance_size = sizeof(LM823KbdState),
- .class_init = lm8323_class_init,
-};
-
-static void lm832x_register_types(void)
-{
- type_register_static(&lm8323_info);
-}
-
-type_init(lm832x_register_types)
diff --git a/qemu/hw/input/milkymist-softusb.c b/qemu/hw/input/milkymist-softusb.c
deleted file mode 100644
index 40dfca157..000000000
--- a/qemu/hw/input/milkymist-softusb.c
+++ /dev/null
@@ -1,319 +0,0 @@
-/*
- * QEMU model of the Milkymist SoftUSB block.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * Specification available at:
- * not available yet
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "ui/console.h"
-#include "hw/input/hid.h"
-#include "qemu/error-report.h"
-
-enum {
- R_CTRL = 0,
- R_MAX
-};
-
-enum {
- CTRL_RESET = (1<<0),
-};
-
-#define COMLOC_DEBUG_PRODUCE 0x1000
-#define COMLOC_DEBUG_BASE 0x1001
-#define COMLOC_MEVT_PRODUCE 0x1101
-#define COMLOC_MEVT_BASE 0x1102
-#define COMLOC_KEVT_PRODUCE 0x1142
-#define COMLOC_KEVT_BASE 0x1143
-
-#define TYPE_MILKYMIST_SOFTUSB "milkymist-softusb"
-#define MILKYMIST_SOFTUSB(obj) \
- OBJECT_CHECK(MilkymistSoftUsbState, (obj), TYPE_MILKYMIST_SOFTUSB)
-
-struct MilkymistSoftUsbState {
- SysBusDevice parent_obj;
-
- HIDState hid_kbd;
- HIDState hid_mouse;
-
- MemoryRegion regs_region;
- MemoryRegion pmem;
- MemoryRegion dmem;
- qemu_irq irq;
-
- void *pmem_ptr;
- void *dmem_ptr;
-
- /* device properties */
- uint32_t pmem_size;
- uint32_t dmem_size;
-
- /* device registers */
- uint32_t regs[R_MAX];
-
- /* mouse state */
- uint8_t mouse_hid_buffer[4];
-
- /* keyboard state */
- uint8_t kbd_hid_buffer[8];
-};
-typedef struct MilkymistSoftUsbState MilkymistSoftUsbState;
-
-static uint64_t softusb_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- MilkymistSoftUsbState *s = opaque;
- uint32_t r = 0;
-
- addr >>= 2;
- switch (addr) {
- case R_CTRL:
- r = s->regs[addr];
- break;
-
- default:
- error_report("milkymist_softusb: read access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-
- trace_milkymist_softusb_memory_read(addr << 2, r);
-
- return r;
-}
-
-static void
-softusb_write(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
- MilkymistSoftUsbState *s = opaque;
-
- trace_milkymist_softusb_memory_write(addr, value);
-
- addr >>= 2;
- switch (addr) {
- case R_CTRL:
- s->regs[addr] = value;
- break;
-
- default:
- error_report("milkymist_softusb: write access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-}
-
-static const MemoryRegionOps softusb_mmio_ops = {
- .read = softusb_read,
- .write = softusb_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static inline void softusb_read_dmem(MilkymistSoftUsbState *s,
- uint32_t offset, uint8_t *buf, uint32_t len)
-{
- if (offset + len >= s->dmem_size) {
- error_report("milkymist_softusb: read dmem out of bounds "
- "at offset 0x%x, len %d", offset, len);
- memset(buf, 0, len);
- return;
- }
-
- memcpy(buf, s->dmem_ptr + offset, len);
-}
-
-static inline void softusb_write_dmem(MilkymistSoftUsbState *s,
- uint32_t offset, uint8_t *buf, uint32_t len)
-{
- if (offset + len >= s->dmem_size) {
- error_report("milkymist_softusb: write dmem out of bounds "
- "at offset 0x%x, len %d", offset, len);
- return;
- }
-
- memcpy(s->dmem_ptr + offset, buf, len);
-}
-
-static void softusb_mouse_changed(MilkymistSoftUsbState *s)
-{
- uint8_t m;
-
- softusb_read_dmem(s, COMLOC_MEVT_PRODUCE, &m, 1);
- trace_milkymist_softusb_mevt(m);
- softusb_write_dmem(s, COMLOC_MEVT_BASE + 4 * m, s->mouse_hid_buffer, 4);
- m = (m + 1) & 0xf;
- softusb_write_dmem(s, COMLOC_MEVT_PRODUCE, &m, 1);
-
- trace_milkymist_softusb_pulse_irq();
- qemu_irq_pulse(s->irq);
-}
-
-static void softusb_kbd_changed(MilkymistSoftUsbState *s)
-{
- uint8_t m;
-
- softusb_read_dmem(s, COMLOC_KEVT_PRODUCE, &m, 1);
- trace_milkymist_softusb_kevt(m);
- softusb_write_dmem(s, COMLOC_KEVT_BASE + 8 * m, s->kbd_hid_buffer, 8);
- m = (m + 1) & 0x7;
- softusb_write_dmem(s, COMLOC_KEVT_PRODUCE, &m, 1);
-
- trace_milkymist_softusb_pulse_irq();
- qemu_irq_pulse(s->irq);
-}
-
-static void softusb_kbd_hid_datain(HIDState *hs)
-{
- MilkymistSoftUsbState *s = container_of(hs, MilkymistSoftUsbState, hid_kbd);
- int len;
-
- /* if device is in reset, do nothing */
- if (s->regs[R_CTRL] & CTRL_RESET) {
- return;
- }
-
- while (hid_has_events(hs)) {
- len = hid_keyboard_poll(hs, s->kbd_hid_buffer,
- sizeof(s->kbd_hid_buffer));
-
- if (len == 8) {
- softusb_kbd_changed(s);
- }
- }
-}
-
-static void softusb_mouse_hid_datain(HIDState *hs)
-{
- MilkymistSoftUsbState *s =
- container_of(hs, MilkymistSoftUsbState, hid_mouse);
- int len;
-
- /* if device is in reset, do nothing */
- if (s->regs[R_CTRL] & CTRL_RESET) {
- return;
- }
-
- while (hid_has_events(hs)) {
- len = hid_pointer_poll(hs, s->mouse_hid_buffer,
- sizeof(s->mouse_hid_buffer));
-
- if (len == 4) {
- softusb_mouse_changed(s);
- }
- }
-}
-
-static void milkymist_softusb_reset(DeviceState *d)
-{
- MilkymistSoftUsbState *s = MILKYMIST_SOFTUSB(d);
- int i;
-
- for (i = 0; i < R_MAX; i++) {
- s->regs[i] = 0;
- }
- memset(s->kbd_hid_buffer, 0, sizeof(s->kbd_hid_buffer));
- memset(s->mouse_hid_buffer, 0, sizeof(s->mouse_hid_buffer));
-
- hid_reset(&s->hid_kbd);
- hid_reset(&s->hid_mouse);
-
- /* defaults */
- s->regs[R_CTRL] = CTRL_RESET;
-}
-
-static int milkymist_softusb_init(SysBusDevice *dev)
-{
- MilkymistSoftUsbState *s = MILKYMIST_SOFTUSB(dev);
-
- sysbus_init_irq(dev, &s->irq);
-
- memory_region_init_io(&s->regs_region, OBJECT(s), &softusb_mmio_ops, s,
- "milkymist-softusb", R_MAX * 4);
- sysbus_init_mmio(dev, &s->regs_region);
-
- /* register pmem and dmem */
- memory_region_init_ram(&s->pmem, OBJECT(s), "milkymist-softusb.pmem",
- s->pmem_size, &error_fatal);
- vmstate_register_ram_global(&s->pmem);
- s->pmem_ptr = memory_region_get_ram_ptr(&s->pmem);
- sysbus_init_mmio(dev, &s->pmem);
- memory_region_init_ram(&s->dmem, OBJECT(s), "milkymist-softusb.dmem",
- s->dmem_size, &error_fatal);
- vmstate_register_ram_global(&s->dmem);
- s->dmem_ptr = memory_region_get_ram_ptr(&s->dmem);
- sysbus_init_mmio(dev, &s->dmem);
-
- hid_init(&s->hid_kbd, HID_KEYBOARD, softusb_kbd_hid_datain);
- hid_init(&s->hid_mouse, HID_MOUSE, softusb_mouse_hid_datain);
-
- return 0;
-}
-
-static const VMStateDescription vmstate_milkymist_softusb = {
- .name = "milkymist-softusb",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, MilkymistSoftUsbState, R_MAX),
- VMSTATE_HID_KEYBOARD_DEVICE(hid_kbd, MilkymistSoftUsbState),
- VMSTATE_HID_POINTER_DEVICE(hid_mouse, MilkymistSoftUsbState),
- VMSTATE_BUFFER(kbd_hid_buffer, MilkymistSoftUsbState),
- VMSTATE_BUFFER(mouse_hid_buffer, MilkymistSoftUsbState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property milkymist_softusb_properties[] = {
- DEFINE_PROP_UINT32("pmem_size", MilkymistSoftUsbState, pmem_size, 0x00001000),
- DEFINE_PROP_UINT32("dmem_size", MilkymistSoftUsbState, dmem_size, 0x00002000),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void milkymist_softusb_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = milkymist_softusb_init;
- dc->reset = milkymist_softusb_reset;
- dc->vmsd = &vmstate_milkymist_softusb;
- dc->props = milkymist_softusb_properties;
-}
-
-static const TypeInfo milkymist_softusb_info = {
- .name = TYPE_MILKYMIST_SOFTUSB,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(MilkymistSoftUsbState),
- .class_init = milkymist_softusb_class_init,
-};
-
-static void milkymist_softusb_register_types(void)
-{
- type_register_static(&milkymist_softusb_info);
-}
-
-type_init(milkymist_softusb_register_types)
diff --git a/qemu/hw/input/pckbd.c b/qemu/hw/input/pckbd.c
deleted file mode 100644
index 1d932ec19..000000000
--- a/qemu/hw/input/pckbd.c
+++ /dev/null
@@ -1,595 +0,0 @@
-/*
- * QEMU PC keyboard emulation
- *
- * Copyright (c) 2003 Fabrice Bellard
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/isa/isa.h"
-#include "hw/i386/pc.h"
-#include "hw/input/ps2.h"
-#include "sysemu/sysemu.h"
-
-/* debug PC keyboard */
-//#define DEBUG_KBD
-#ifdef DEBUG_KBD
-#define DPRINTF(fmt, ...) \
- do { printf("KBD: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...)
-#endif
-
-/* Keyboard Controller Commands */
-#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */
-#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */
-#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */
-#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */
-#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */
-#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */
-#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */
-#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */
-#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */
-#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */
-#define KBD_CCMD_READ_INPORT 0xC0 /* read input port */
-#define KBD_CCMD_READ_OUTPORT 0xD0 /* read output port */
-#define KBD_CCMD_WRITE_OUTPORT 0xD1 /* write output port */
-#define KBD_CCMD_WRITE_OBUF 0xD2
-#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if
- initiated by the auxiliary device */
-#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */
-#define KBD_CCMD_DISABLE_A20 0xDD /* HP vectra only ? */
-#define KBD_CCMD_ENABLE_A20 0xDF /* HP vectra only ? */
-#define KBD_CCMD_PULSE_BITS_3_0 0xF0 /* Pulse bits 3-0 of the output port P2. */
-#define KBD_CCMD_RESET 0xFE /* Pulse bit 0 of the output port P2 = CPU reset. */
-#define KBD_CCMD_NO_OP 0xFF /* Pulse no bits of the output port P2. */
-
-/* Keyboard Commands */
-#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */
-#define KBD_CMD_ECHO 0xEE
-#define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */
-#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */
-#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */
-#define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */
-#define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */
-#define KBD_CMD_RESET 0xFF /* Reset */
-
-/* Keyboard Replies */
-#define KBD_REPLY_POR 0xAA /* Power on reset */
-#define KBD_REPLY_ACK 0xFA /* Command ACK */
-#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */
-
-/* Status Register Bits */
-#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */
-#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */
-#define KBD_STAT_SELFTEST 0x04 /* Self test successful */
-#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */
-#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */
-#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */
-#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */
-#define KBD_STAT_PERR 0x80 /* Parity error */
-
-/* Controller Mode Register Bits */
-#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */
-#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */
-#define KBD_MODE_SYS 0x04 /* The system flag (?) */
-#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */
-#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */
-#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */
-#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */
-#define KBD_MODE_RFU 0x80
-
-/* Output Port Bits */
-#define KBD_OUT_RESET 0x01 /* 1=normal mode, 0=reset */
-#define KBD_OUT_A20 0x02 /* x86 only */
-#define KBD_OUT_OBF 0x10 /* Keyboard output buffer full */
-#define KBD_OUT_MOUSE_OBF 0x20 /* Mouse output buffer full */
-
-/* OSes typically write 0xdd/0xdf to turn the A20 line off and on.
- * We make the default value of the outport include these four bits,
- * so that the subsection is rarely necessary.
- */
-#define KBD_OUT_ONES 0xcc
-
-/* Mouse Commands */
-#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */
-#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */
-#define AUX_SET_RES 0xE8 /* Set resolution */
-#define AUX_GET_SCALE 0xE9 /* Get scaling factor */
-#define AUX_SET_STREAM 0xEA /* Set stream mode */
-#define AUX_POLL 0xEB /* Poll */
-#define AUX_RESET_WRAP 0xEC /* Reset wrap mode */
-#define AUX_SET_WRAP 0xEE /* Set wrap mode */
-#define AUX_SET_REMOTE 0xF0 /* Set remote mode */
-#define AUX_GET_TYPE 0xF2 /* Get type */
-#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */
-#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */
-#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */
-#define AUX_SET_DEFAULT 0xF6
-#define AUX_RESET 0xFF /* Reset aux device */
-#define AUX_ACK 0xFA /* Command byte ACK. */
-
-#define MOUSE_STATUS_REMOTE 0x40
-#define MOUSE_STATUS_ENABLED 0x20
-#define MOUSE_STATUS_SCALE21 0x10
-
-#define KBD_PENDING_KBD 1
-#define KBD_PENDING_AUX 2
-
-typedef struct KBDState {
- uint8_t write_cmd; /* if non zero, write data to port 60 is expected */
- uint8_t status;
- uint8_t mode;
- uint8_t outport;
- bool outport_present;
- /* Bitmask of devices with data available. */
- uint8_t pending;
- void *kbd;
- void *mouse;
-
- qemu_irq irq_kbd;
- qemu_irq irq_mouse;
- qemu_irq *a20_out;
- hwaddr mask;
-} KBDState;
-
-/* update irq and KBD_STAT_[MOUSE_]OBF */
-/* XXX: not generating the irqs if KBD_MODE_DISABLE_KBD is set may be
- incorrect, but it avoids having to simulate exact delays */
-static void kbd_update_irq(KBDState *s)
-{
- int irq_kbd_level, irq_mouse_level;
-
- irq_kbd_level = 0;
- irq_mouse_level = 0;
- s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF);
- s->outport &= ~(KBD_OUT_OBF | KBD_OUT_MOUSE_OBF);
- if (s->pending) {
- s->status |= KBD_STAT_OBF;
- s->outport |= KBD_OUT_OBF;
- /* kbd data takes priority over aux data. */
- if (s->pending == KBD_PENDING_AUX) {
- s->status |= KBD_STAT_MOUSE_OBF;
- s->outport |= KBD_OUT_MOUSE_OBF;
- if (s->mode & KBD_MODE_MOUSE_INT)
- irq_mouse_level = 1;
- } else {
- if ((s->mode & KBD_MODE_KBD_INT) &&
- !(s->mode & KBD_MODE_DISABLE_KBD))
- irq_kbd_level = 1;
- }
- }
- qemu_set_irq(s->irq_kbd, irq_kbd_level);
- qemu_set_irq(s->irq_mouse, irq_mouse_level);
-}
-
-static void kbd_update_kbd_irq(void *opaque, int level)
-{
- KBDState *s = (KBDState *)opaque;
-
- if (level)
- s->pending |= KBD_PENDING_KBD;
- else
- s->pending &= ~KBD_PENDING_KBD;
- kbd_update_irq(s);
-}
-
-static void kbd_update_aux_irq(void *opaque, int level)
-{
- KBDState *s = (KBDState *)opaque;
-
- if (level)
- s->pending |= KBD_PENDING_AUX;
- else
- s->pending &= ~KBD_PENDING_AUX;
- kbd_update_irq(s);
-}
-
-static uint64_t kbd_read_status(void *opaque, hwaddr addr,
- unsigned size)
-{
- KBDState *s = opaque;
- int val;
- val = s->status;
- DPRINTF("kbd: read status=0x%02x\n", val);
- return val;
-}
-
-static void kbd_queue(KBDState *s, int b, int aux)
-{
- if (aux)
- ps2_queue(s->mouse, b);
- else
- ps2_queue(s->kbd, b);
-}
-
-static void outport_write(KBDState *s, uint32_t val)
-{
- DPRINTF("kbd: write outport=0x%02x\n", val);
- s->outport = val;
- if (s->a20_out) {
- qemu_set_irq(*s->a20_out, (val >> 1) & 1);
- }
- if (!(val & 1)) {
- qemu_system_reset_request();
- }
-}
-
-static void kbd_write_command(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- KBDState *s = opaque;
-
- DPRINTF("kbd: write cmd=0x%02" PRIx64 "\n", val);
-
- /* Bits 3-0 of the output port P2 of the keyboard controller may be pulsed
- * low for approximately 6 micro seconds. Bits 3-0 of the KBD_CCMD_PULSE
- * command specify the output port bits to be pulsed.
- * 0: Bit should be pulsed. 1: Bit should not be modified.
- * The only useful version of this command is pulsing bit 0,
- * which does a CPU reset.
- */
- if((val & KBD_CCMD_PULSE_BITS_3_0) == KBD_CCMD_PULSE_BITS_3_0) {
- if(!(val & 1))
- val = KBD_CCMD_RESET;
- else
- val = KBD_CCMD_NO_OP;
- }
-
- switch(val) {
- case KBD_CCMD_READ_MODE:
- kbd_queue(s, s->mode, 0);
- break;
- case KBD_CCMD_WRITE_MODE:
- case KBD_CCMD_WRITE_OBUF:
- case KBD_CCMD_WRITE_AUX_OBUF:
- case KBD_CCMD_WRITE_MOUSE:
- case KBD_CCMD_WRITE_OUTPORT:
- s->write_cmd = val;
- break;
- case KBD_CCMD_MOUSE_DISABLE:
- s->mode |= KBD_MODE_DISABLE_MOUSE;
- break;
- case KBD_CCMD_MOUSE_ENABLE:
- s->mode &= ~KBD_MODE_DISABLE_MOUSE;
- break;
- case KBD_CCMD_TEST_MOUSE:
- kbd_queue(s, 0x00, 0);
- break;
- case KBD_CCMD_SELF_TEST:
- s->status |= KBD_STAT_SELFTEST;
- kbd_queue(s, 0x55, 0);
- break;
- case KBD_CCMD_KBD_TEST:
- kbd_queue(s, 0x00, 0);
- break;
- case KBD_CCMD_KBD_DISABLE:
- s->mode |= KBD_MODE_DISABLE_KBD;
- kbd_update_irq(s);
- break;
- case KBD_CCMD_KBD_ENABLE:
- s->mode &= ~KBD_MODE_DISABLE_KBD;
- kbd_update_irq(s);
- break;
- case KBD_CCMD_READ_INPORT:
- kbd_queue(s, 0x80, 0);
- break;
- case KBD_CCMD_READ_OUTPORT:
- kbd_queue(s, s->outport, 0);
- break;
- case KBD_CCMD_ENABLE_A20:
- if (s->a20_out) {
- qemu_irq_raise(*s->a20_out);
- }
- s->outport |= KBD_OUT_A20;
- break;
- case KBD_CCMD_DISABLE_A20:
- if (s->a20_out) {
- qemu_irq_lower(*s->a20_out);
- }
- s->outport &= ~KBD_OUT_A20;
- break;
- case KBD_CCMD_RESET:
- qemu_system_reset_request();
- break;
- case KBD_CCMD_NO_OP:
- /* ignore that */
- break;
- default:
- fprintf(stderr, "qemu: unsupported keyboard cmd=0x%02x\n", (int)val);
- break;
- }
-}
-
-static uint64_t kbd_read_data(void *opaque, hwaddr addr,
- unsigned size)
-{
- KBDState *s = opaque;
- uint32_t val;
-
- if (s->pending == KBD_PENDING_AUX)
- val = ps2_read_data(s->mouse);
- else
- val = ps2_read_data(s->kbd);
-
- DPRINTF("kbd: read data=0x%02x\n", val);
- return val;
-}
-
-static void kbd_write_data(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- KBDState *s = opaque;
-
- DPRINTF("kbd: write data=0x%02" PRIx64 "\n", val);
-
- switch(s->write_cmd) {
- case 0:
- ps2_write_keyboard(s->kbd, val);
- break;
- case KBD_CCMD_WRITE_MODE:
- s->mode = val;
- ps2_keyboard_set_translation(s->kbd, (s->mode & KBD_MODE_KCC) != 0);
- /* ??? */
- kbd_update_irq(s);
- break;
- case KBD_CCMD_WRITE_OBUF:
- kbd_queue(s, val, 0);
- break;
- case KBD_CCMD_WRITE_AUX_OBUF:
- kbd_queue(s, val, 1);
- break;
- case KBD_CCMD_WRITE_OUTPORT:
- outport_write(s, val);
- break;
- case KBD_CCMD_WRITE_MOUSE:
- ps2_write_mouse(s->mouse, val);
- break;
- default:
- break;
- }
- s->write_cmd = 0;
-}
-
-static void kbd_reset(void *opaque)
-{
- KBDState *s = opaque;
-
- s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT;
- s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED;
- s->outport = KBD_OUT_RESET | KBD_OUT_A20 | KBD_OUT_ONES;
- s->outport_present = false;
-}
-
-static uint8_t kbd_outport_default(KBDState *s)
-{
- return KBD_OUT_RESET | KBD_OUT_A20 | KBD_OUT_ONES
- | (s->status & KBD_STAT_OBF ? KBD_OUT_OBF : 0)
- | (s->status & KBD_STAT_MOUSE_OBF ? KBD_OUT_MOUSE_OBF : 0);
-}
-
-static int kbd_outport_post_load(void *opaque, int version_id)
-{
- KBDState *s = opaque;
- s->outport_present = true;
- return 0;
-}
-
-static bool kbd_outport_needed(void *opaque)
-{
- KBDState *s = opaque;
- return s->outport != kbd_outport_default(s);
-}
-
-static const VMStateDescription vmstate_kbd_outport = {
- .name = "pckbd_outport",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = kbd_outport_post_load,
- .needed = kbd_outport_needed,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(outport, KBDState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static int kbd_post_load(void *opaque, int version_id)
-{
- KBDState *s = opaque;
- if (!s->outport_present) {
- s->outport = kbd_outport_default(s);
- }
- s->outport_present = false;
- return 0;
-}
-
-static const VMStateDescription vmstate_kbd = {
- .name = "pckbd",
- .version_id = 3,
- .minimum_version_id = 3,
- .post_load = kbd_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(write_cmd, KBDState),
- VMSTATE_UINT8(status, KBDState),
- VMSTATE_UINT8(mode, KBDState),
- VMSTATE_UINT8(pending, KBDState),
- VMSTATE_END_OF_LIST()
- },
- .subsections = (const VMStateDescription*[]) {
- &vmstate_kbd_outport,
- NULL
- }
-};
-
-/* Memory mapped interface */
-static uint32_t kbd_mm_readb (void *opaque, hwaddr addr)
-{
- KBDState *s = opaque;
-
- if (addr & s->mask)
- return kbd_read_status(s, 0, 1) & 0xff;
- else
- return kbd_read_data(s, 0, 1) & 0xff;
-}
-
-static void kbd_mm_writeb (void *opaque, hwaddr addr, uint32_t value)
-{
- KBDState *s = opaque;
-
- if (addr & s->mask)
- kbd_write_command(s, 0, value & 0xff, 1);
- else
- kbd_write_data(s, 0, value & 0xff, 1);
-}
-
-static const MemoryRegionOps i8042_mmio_ops = {
- .endianness = DEVICE_NATIVE_ENDIAN,
- .old_mmio = {
- .read = { kbd_mm_readb, kbd_mm_readb, kbd_mm_readb },
- .write = { kbd_mm_writeb, kbd_mm_writeb, kbd_mm_writeb },
- },
-};
-
-void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq,
- MemoryRegion *region, ram_addr_t size,
- hwaddr mask)
-{
- KBDState *s = g_malloc0(sizeof(KBDState));
-
- s->irq_kbd = kbd_irq;
- s->irq_mouse = mouse_irq;
- s->mask = mask;
-
- vmstate_register(NULL, 0, &vmstate_kbd, s);
-
- memory_region_init_io(region, NULL, &i8042_mmio_ops, s, "i8042", size);
-
- s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
- s->mouse = ps2_mouse_init(kbd_update_aux_irq, s);
- qemu_register_reset(kbd_reset, s);
-}
-
-#define TYPE_I8042 "i8042"
-#define I8042(obj) OBJECT_CHECK(ISAKBDState, (obj), TYPE_I8042)
-
-typedef struct ISAKBDState {
- ISADevice parent_obj;
-
- KBDState kbd;
- MemoryRegion io[2];
-} ISAKBDState;
-
-void i8042_isa_mouse_fake_event(void *opaque)
-{
- ISADevice *dev = opaque;
- ISAKBDState *isa = I8042(dev);
- KBDState *s = &isa->kbd;
-
- ps2_mouse_fake_event(s->mouse);
-}
-
-void i8042_setup_a20_line(ISADevice *dev, qemu_irq *a20_out)
-{
- ISAKBDState *isa = I8042(dev);
- KBDState *s = &isa->kbd;
-
- s->a20_out = a20_out;
-}
-
-static const VMStateDescription vmstate_kbd_isa = {
- .name = "pckbd",
- .version_id = 3,
- .minimum_version_id = 3,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT(kbd, ISAKBDState, 0, vmstate_kbd, KBDState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const MemoryRegionOps i8042_data_ops = {
- .read = kbd_read_data,
- .write = kbd_write_data,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static const MemoryRegionOps i8042_cmd_ops = {
- .read = kbd_read_status,
- .write = kbd_write_command,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void i8042_initfn(Object *obj)
-{
- ISAKBDState *isa_s = I8042(obj);
- KBDState *s = &isa_s->kbd;
-
- memory_region_init_io(isa_s->io + 0, obj, &i8042_data_ops, s,
- "i8042-data", 1);
- memory_region_init_io(isa_s->io + 1, obj, &i8042_cmd_ops, s,
- "i8042-cmd", 1);
-}
-
-static void i8042_realizefn(DeviceState *dev, Error **errp)
-{
- ISADevice *isadev = ISA_DEVICE(dev);
- ISAKBDState *isa_s = I8042(dev);
- KBDState *s = &isa_s->kbd;
-
- isa_init_irq(isadev, &s->irq_kbd, 1);
- isa_init_irq(isadev, &s->irq_mouse, 12);
-
- isa_register_ioport(isadev, isa_s->io + 0, 0x60);
- isa_register_ioport(isadev, isa_s->io + 1, 0x64);
-
- s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
- s->mouse = ps2_mouse_init(kbd_update_aux_irq, s);
- qemu_register_reset(kbd_reset, s);
-}
-
-static void i8042_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = i8042_realizefn;
- dc->vmsd = &vmstate_kbd_isa;
-}
-
-static const TypeInfo i8042_info = {
- .name = TYPE_I8042,
- .parent = TYPE_ISA_DEVICE,
- .instance_size = sizeof(ISAKBDState),
- .instance_init = i8042_initfn,
- .class_init = i8042_class_initfn,
-};
-
-static void i8042_register_types(void)
-{
- type_register_static(&i8042_info);
-}
-
-type_init(i8042_register_types)
diff --git a/qemu/hw/input/pl050.c b/qemu/hw/input/pl050.c
deleted file mode 100644
index 3092b0fe3..000000000
--- a/qemu/hw/input/pl050.c
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Arm PrimeCell PL050 Keyboard / Mouse Interface
- *
- * Copyright (c) 2006-2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "hw/input/ps2.h"
-
-#define TYPE_PL050 "pl050"
-#define PL050(obj) OBJECT_CHECK(PL050State, (obj), TYPE_PL050)
-
-typedef struct PL050State {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- void *dev;
- uint32_t cr;
- uint32_t clk;
- uint32_t last;
- int pending;
- qemu_irq irq;
- bool is_mouse;
-} PL050State;
-
-static const VMStateDescription vmstate_pl050 = {
- .name = "pl050",
- .version_id = 2,
- .minimum_version_id = 2,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(cr, PL050State),
- VMSTATE_UINT32(clk, PL050State),
- VMSTATE_UINT32(last, PL050State),
- VMSTATE_INT32(pending, PL050State),
- VMSTATE_END_OF_LIST()
- }
-};
-
-#define PL050_TXEMPTY (1 << 6)
-#define PL050_TXBUSY (1 << 5)
-#define PL050_RXFULL (1 << 4)
-#define PL050_RXBUSY (1 << 3)
-#define PL050_RXPARITY (1 << 2)
-#define PL050_KMIC (1 << 1)
-#define PL050_KMID (1 << 0)
-
-static const unsigned char pl050_id[] =
-{ 0x50, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
-
-static void pl050_update(void *opaque, int level)
-{
- PL050State *s = (PL050State *)opaque;
- int raise;
-
- s->pending = level;
- raise = (s->pending && (s->cr & 0x10) != 0)
- || (s->cr & 0x08) != 0;
- qemu_set_irq(s->irq, raise);
-}
-
-static uint64_t pl050_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- PL050State *s = (PL050State *)opaque;
- if (offset >= 0xfe0 && offset < 0x1000)
- return pl050_id[(offset - 0xfe0) >> 2];
-
- switch (offset >> 2) {
- case 0: /* KMICR */
- return s->cr;
- case 1: /* KMISTAT */
- {
- uint8_t val;
- uint32_t stat;
-
- val = s->last;
- val = val ^ (val >> 4);
- val = val ^ (val >> 2);
- val = (val ^ (val >> 1)) & 1;
-
- stat = PL050_TXEMPTY;
- if (val)
- stat |= PL050_RXPARITY;
- if (s->pending)
- stat |= PL050_RXFULL;
-
- return stat;
- }
- case 2: /* KMIDATA */
- if (s->pending)
- s->last = ps2_read_data(s->dev);
- return s->last;
- case 3: /* KMICLKDIV */
- return s->clk;
- case 4: /* KMIIR */
- return s->pending | 2;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "pl050_read: Bad offset %x\n", (int)offset);
- return 0;
- }
-}
-
-static void pl050_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PL050State *s = (PL050State *)opaque;
- switch (offset >> 2) {
- case 0: /* KMICR */
- s->cr = value;
- pl050_update(s, s->pending);
- /* ??? Need to implement the enable/disable bit. */
- break;
- case 2: /* KMIDATA */
- /* ??? This should toggle the TX interrupt line. */
- /* ??? This means kbd/mouse can block each other. */
- if (s->is_mouse) {
- ps2_write_mouse(s->dev, value);
- } else {
- ps2_write_keyboard(s->dev, value);
- }
- break;
- case 3: /* KMICLKDIV */
- s->clk = value;
- return;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "pl050_write: Bad offset %x\n", (int)offset);
- }
-}
-static const MemoryRegionOps pl050_ops = {
- .read = pl050_read,
- .write = pl050_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int pl050_initfn(SysBusDevice *dev)
-{
- PL050State *s = PL050(dev);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &pl050_ops, s, "pl050", 0x1000);
- sysbus_init_mmio(dev, &s->iomem);
- sysbus_init_irq(dev, &s->irq);
- if (s->is_mouse) {
- s->dev = ps2_mouse_init(pl050_update, s);
- } else {
- s->dev = ps2_kbd_init(pl050_update, s);
- }
- return 0;
-}
-
-static void pl050_keyboard_init(Object *obj)
-{
- PL050State *s = PL050(obj);
-
- s->is_mouse = false;
-}
-
-static void pl050_mouse_init(Object *obj)
-{
- PL050State *s = PL050(obj);
-
- s->is_mouse = true;
-}
-
-static const TypeInfo pl050_kbd_info = {
- .name = "pl050_keyboard",
- .parent = TYPE_PL050,
- .instance_init = pl050_keyboard_init,
-};
-
-static const TypeInfo pl050_mouse_info = {
- .name = "pl050_mouse",
- .parent = TYPE_PL050,
- .instance_init = pl050_mouse_init,
-};
-
-static void pl050_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
- SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(oc);
-
- sdc->init = pl050_initfn;
- dc->vmsd = &vmstate_pl050;
-}
-
-static const TypeInfo pl050_type_info = {
- .name = TYPE_PL050,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PL050State),
- .abstract = true,
- .class_init = pl050_class_init,
-};
-
-static void pl050_register_types(void)
-{
- type_register_static(&pl050_type_info);
- type_register_static(&pl050_kbd_info);
- type_register_static(&pl050_mouse_info);
-}
-
-type_init(pl050_register_types)
diff --git a/qemu/hw/input/ps2.c b/qemu/hw/input/ps2.c
deleted file mode 100644
index a8aa36f5c..000000000
--- a/qemu/hw/input/ps2.c
+++ /dev/null
@@ -1,813 +0,0 @@
-/*
- * QEMU PS/2 keyboard/mouse emulation
- *
- * Copyright (c) 2003 Fabrice Bellard
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/input/ps2.h"
-#include "ui/console.h"
-#include "ui/input.h"
-#include "sysemu/sysemu.h"
-
-#include "trace.h"
-
-/* debug PC keyboard */
-//#define DEBUG_KBD
-
-/* debug PC keyboard : only mouse */
-//#define DEBUG_MOUSE
-
-/* Keyboard Commands */
-#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */
-#define KBD_CMD_ECHO 0xEE
-#define KBD_CMD_SCANCODE 0xF0 /* Get/set scancode set */
-#define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */
-#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */
-#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */
-#define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */
-#define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */
-#define KBD_CMD_RESET 0xFF /* Reset */
-
-/* Keyboard Replies */
-#define KBD_REPLY_POR 0xAA /* Power on reset */
-#define KBD_REPLY_ID 0xAB /* Keyboard ID */
-#define KBD_REPLY_ACK 0xFA /* Command ACK */
-#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */
-
-/* Mouse Commands */
-#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */
-#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */
-#define AUX_SET_RES 0xE8 /* Set resolution */
-#define AUX_GET_SCALE 0xE9 /* Get scaling factor */
-#define AUX_SET_STREAM 0xEA /* Set stream mode */
-#define AUX_POLL 0xEB /* Poll */
-#define AUX_RESET_WRAP 0xEC /* Reset wrap mode */
-#define AUX_SET_WRAP 0xEE /* Set wrap mode */
-#define AUX_SET_REMOTE 0xF0 /* Set remote mode */
-#define AUX_GET_TYPE 0xF2 /* Get type */
-#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */
-#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */
-#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */
-#define AUX_SET_DEFAULT 0xF6
-#define AUX_RESET 0xFF /* Reset aux device */
-#define AUX_ACK 0xFA /* Command byte ACK. */
-
-#define MOUSE_STATUS_REMOTE 0x40
-#define MOUSE_STATUS_ENABLED 0x20
-#define MOUSE_STATUS_SCALE21 0x10
-
-#define PS2_QUEUE_SIZE 16 /* Buffer size required by PS/2 protocol */
-
-typedef struct {
- /* Keep the data array 256 bytes long, which compatibility
- with older qemu versions. */
- uint8_t data[256];
- int rptr, wptr, count;
-} PS2Queue;
-
-typedef struct {
- PS2Queue queue;
- int32_t write_cmd;
- void (*update_irq)(void *, int);
- void *update_arg;
-} PS2State;
-
-typedef struct {
- PS2State common;
- int scan_enabled;
- /* QEMU uses translated PC scancodes internally. To avoid multiple
- conversions we do the translation (if any) in the PS/2 emulation
- not the keyboard controller. */
- int translate;
- int scancode_set; /* 1=XT, 2=AT, 3=PS/2 */
- int ledstate;
-} PS2KbdState;
-
-typedef struct {
- PS2State common;
- uint8_t mouse_status;
- uint8_t mouse_resolution;
- uint8_t mouse_sample_rate;
- uint8_t mouse_wrap;
- uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
- uint8_t mouse_detect_state;
- int mouse_dx; /* current values, needed for 'poll' mode */
- int mouse_dy;
- int mouse_dz;
- uint8_t mouse_buttons;
-} PS2MouseState;
-
-/* Table to convert from PC scancodes to raw scancodes. */
-static const unsigned char ps2_raw_keycode[128] = {
- 0, 118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85, 102, 13,
- 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
- 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
- 50, 49, 58, 65, 73, 74, 89, 124, 17, 41, 88, 5, 6, 4, 12, 3,
- 11, 2, 10, 1, 9, 119, 126, 108, 117, 125, 123, 107, 115, 116, 121, 105,
-114, 122, 112, 113, 127, 96, 97, 120, 7, 15, 23, 31, 39, 47, 55, 63,
- 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87, 111,
- 19, 25, 57, 81, 83, 92, 95, 98, 99, 100, 101, 103, 104, 106, 109, 110
-};
-static const unsigned char ps2_raw_keycode_set3[128] = {
- 0, 8, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85, 102, 13,
- 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 17, 28, 27,
- 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 92, 26, 34, 33, 42,
- 50, 49, 58, 65, 73, 74, 89, 126, 25, 41, 20, 7, 15, 23, 31, 39,
- 47, 2, 63, 71, 79, 118, 95, 108, 117, 125, 132, 107, 115, 116, 124, 105,
-114, 122, 112, 113, 127, 96, 97, 86, 94, 15, 23, 31, 39, 47, 55, 63,
- 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87, 111,
- 19, 25, 57, 81, 83, 92, 95, 98, 99, 100, 101, 103, 104, 106, 109, 110
-};
-
-void ps2_queue(void *opaque, int b)
-{
- PS2State *s = (PS2State *)opaque;
- PS2Queue *q = &s->queue;
-
- if (q->count >= PS2_QUEUE_SIZE - 1)
- return;
- q->data[q->wptr] = b;
- if (++q->wptr == PS2_QUEUE_SIZE)
- q->wptr = 0;
- q->count++;
- s->update_irq(s->update_arg, 1);
-}
-
-/*
- keycode is expressed as follow:
- bit 7 - 0 key pressed, 1 = key released
- bits 6-0 - translated scancode set 2
- */
-static void ps2_put_keycode(void *opaque, int keycode)
-{
- PS2KbdState *s = opaque;
-
- trace_ps2_put_keycode(opaque, keycode);
- qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
- /* XXX: add support for scancode set 1 */
- if (!s->translate && keycode < 0xe0 && s->scancode_set > 1) {
- if (keycode & 0x80) {
- ps2_queue(&s->common, 0xf0);
- }
- if (s->scancode_set == 2) {
- keycode = ps2_raw_keycode[keycode & 0x7f];
- } else if (s->scancode_set == 3) {
- keycode = ps2_raw_keycode_set3[keycode & 0x7f];
- }
- }
- ps2_queue(&s->common, keycode);
-}
-
-static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
- InputEvent *evt)
-{
- PS2KbdState *s = (PS2KbdState *)dev;
- int scancodes[3], i, count;
- InputKeyEvent *key = evt->u.key.data;
-
- qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
- count = qemu_input_key_value_to_scancode(key->key,
- key->down,
- scancodes);
- for (i = 0; i < count; i++) {
- ps2_put_keycode(s, scancodes[i]);
- }
-}
-
-uint32_t ps2_read_data(void *opaque)
-{
- PS2State *s = (PS2State *)opaque;
- PS2Queue *q;
- int val, index;
-
- trace_ps2_read_data(opaque);
- q = &s->queue;
- if (q->count == 0) {
- /* NOTE: if no data left, we return the last keyboard one
- (needed for EMM386) */
- /* XXX: need a timer to do things correctly */
- index = q->rptr - 1;
- if (index < 0)
- index = PS2_QUEUE_SIZE - 1;
- val = q->data[index];
- } else {
- val = q->data[q->rptr];
- if (++q->rptr == PS2_QUEUE_SIZE)
- q->rptr = 0;
- q->count--;
- /* reading deasserts IRQ */
- s->update_irq(s->update_arg, 0);
- /* reassert IRQs if data left */
- s->update_irq(s->update_arg, q->count != 0);
- }
- return val;
-}
-
-static void ps2_set_ledstate(PS2KbdState *s, int ledstate)
-{
- trace_ps2_set_ledstate(s, ledstate);
- s->ledstate = ledstate;
- kbd_put_ledstate(ledstate);
-}
-
-static void ps2_reset_keyboard(PS2KbdState *s)
-{
- trace_ps2_reset_keyboard(s);
- s->scan_enabled = 1;
- s->scancode_set = 2;
- ps2_set_ledstate(s, 0);
-}
-
-void ps2_write_keyboard(void *opaque, int val)
-{
- PS2KbdState *s = (PS2KbdState *)opaque;
-
- trace_ps2_write_keyboard(opaque, val);
- switch(s->common.write_cmd) {
- default:
- case -1:
- switch(val) {
- case 0x00:
- ps2_queue(&s->common, KBD_REPLY_ACK);
- break;
- case 0x05:
- ps2_queue(&s->common, KBD_REPLY_RESEND);
- break;
- case KBD_CMD_GET_ID:
- ps2_queue(&s->common, KBD_REPLY_ACK);
- /* We emulate a MF2 AT keyboard here */
- ps2_queue(&s->common, KBD_REPLY_ID);
- if (s->translate)
- ps2_queue(&s->common, 0x41);
- else
- ps2_queue(&s->common, 0x83);
- break;
- case KBD_CMD_ECHO:
- ps2_queue(&s->common, KBD_CMD_ECHO);
- break;
- case KBD_CMD_ENABLE:
- s->scan_enabled = 1;
- ps2_queue(&s->common, KBD_REPLY_ACK);
- break;
- case KBD_CMD_SCANCODE:
- case KBD_CMD_SET_LEDS:
- case KBD_CMD_SET_RATE:
- s->common.write_cmd = val;
- ps2_queue(&s->common, KBD_REPLY_ACK);
- break;
- case KBD_CMD_RESET_DISABLE:
- ps2_reset_keyboard(s);
- s->scan_enabled = 0;
- ps2_queue(&s->common, KBD_REPLY_ACK);
- break;
- case KBD_CMD_RESET_ENABLE:
- ps2_reset_keyboard(s);
- s->scan_enabled = 1;
- ps2_queue(&s->common, KBD_REPLY_ACK);
- break;
- case KBD_CMD_RESET:
- ps2_reset_keyboard(s);
- ps2_queue(&s->common, KBD_REPLY_ACK);
- ps2_queue(&s->common, KBD_REPLY_POR);
- break;
- default:
- ps2_queue(&s->common, KBD_REPLY_ACK);
- break;
- }
- break;
- case KBD_CMD_SCANCODE:
- if (val == 0) {
- if (s->scancode_set == 1)
- ps2_put_keycode(s, 0x43);
- else if (s->scancode_set == 2)
- ps2_put_keycode(s, 0x41);
- else if (s->scancode_set == 3)
- ps2_put_keycode(s, 0x3f);
- } else {
- if (val >= 1 && val <= 3)
- s->scancode_set = val;
- ps2_queue(&s->common, KBD_REPLY_ACK);
- }
- s->common.write_cmd = -1;
- break;
- case KBD_CMD_SET_LEDS:
- ps2_set_ledstate(s, val);
- ps2_queue(&s->common, KBD_REPLY_ACK);
- s->common.write_cmd = -1;
- break;
- case KBD_CMD_SET_RATE:
- ps2_queue(&s->common, KBD_REPLY_ACK);
- s->common.write_cmd = -1;
- break;
- }
-}
-
-/* Set the scancode translation mode.
- 0 = raw scancodes.
- 1 = translated scancodes (used by qemu internally). */
-
-void ps2_keyboard_set_translation(void *opaque, int mode)
-{
- PS2KbdState *s = (PS2KbdState *)opaque;
- trace_ps2_keyboard_set_translation(opaque, mode);
- s->translate = mode;
-}
-
-static void ps2_mouse_send_packet(PS2MouseState *s)
-{
- unsigned int b;
- int dx1, dy1, dz1;
-
- dx1 = s->mouse_dx;
- dy1 = s->mouse_dy;
- dz1 = s->mouse_dz;
- /* XXX: increase range to 8 bits ? */
- if (dx1 > 127)
- dx1 = 127;
- else if (dx1 < -127)
- dx1 = -127;
- if (dy1 > 127)
- dy1 = 127;
- else if (dy1 < -127)
- dy1 = -127;
- b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
- ps2_queue(&s->common, b);
- ps2_queue(&s->common, dx1 & 0xff);
- ps2_queue(&s->common, dy1 & 0xff);
- /* extra byte for IMPS/2 or IMEX */
- switch(s->mouse_type) {
- default:
- break;
- case 3:
- if (dz1 > 127)
- dz1 = 127;
- else if (dz1 < -127)
- dz1 = -127;
- ps2_queue(&s->common, dz1 & 0xff);
- break;
- case 4:
- if (dz1 > 7)
- dz1 = 7;
- else if (dz1 < -7)
- dz1 = -7;
- b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
- ps2_queue(&s->common, b);
- break;
- }
-
- trace_ps2_mouse_send_packet(s, dx1, dy1, dz1, b);
- /* update deltas */
- s->mouse_dx -= dx1;
- s->mouse_dy -= dy1;
- s->mouse_dz -= dz1;
-}
-
-static void ps2_mouse_event(DeviceState *dev, QemuConsole *src,
- InputEvent *evt)
-{
- static const int bmap[INPUT_BUTTON__MAX] = {
- [INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON,
- [INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON,
- [INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON,
- };
- PS2MouseState *s = (PS2MouseState *)dev;
- InputMoveEvent *move;
- InputBtnEvent *btn;
-
- /* check if deltas are recorded when disabled */
- if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
- return;
-
- switch (evt->type) {
- case INPUT_EVENT_KIND_REL:
- move = evt->u.rel.data;
- if (move->axis == INPUT_AXIS_X) {
- s->mouse_dx += move->value;
- } else if (move->axis == INPUT_AXIS_Y) {
- s->mouse_dy -= move->value;
- }
- break;
-
- case INPUT_EVENT_KIND_BTN:
- btn = evt->u.btn.data;
- if (btn->down) {
- s->mouse_buttons |= bmap[btn->button];
- if (btn->button == INPUT_BUTTON_WHEEL_UP) {
- s->mouse_dz--;
- } else if (btn->button == INPUT_BUTTON_WHEEL_DOWN) {
- s->mouse_dz++;
- }
- } else {
- s->mouse_buttons &= ~bmap[btn->button];
- }
- break;
-
- default:
- /* keep gcc happy */
- break;
- }
-}
-
-static void ps2_mouse_sync(DeviceState *dev)
-{
- PS2MouseState *s = (PS2MouseState *)dev;
-
- if (s->mouse_buttons) {
- qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
- }
- if (!(s->mouse_status & MOUSE_STATUS_REMOTE)) {
- while (s->common.queue.count < PS2_QUEUE_SIZE - 4) {
- /* if not remote, send event. Multiple events are sent if
- too big deltas */
- ps2_mouse_send_packet(s);
- if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
- break;
- }
- }
-}
-
-void ps2_mouse_fake_event(void *opaque)
-{
- PS2MouseState *s = opaque;
- trace_ps2_mouse_fake_event(opaque);
- s->mouse_dx++;
- ps2_mouse_sync(opaque);
-}
-
-void ps2_write_mouse(void *opaque, int val)
-{
- PS2MouseState *s = (PS2MouseState *)opaque;
-
- trace_ps2_write_mouse(opaque, val);
-#ifdef DEBUG_MOUSE
- printf("kbd: write mouse 0x%02x\n", val);
-#endif
- switch(s->common.write_cmd) {
- default:
- case -1:
- /* mouse command */
- if (s->mouse_wrap) {
- if (val == AUX_RESET_WRAP) {
- s->mouse_wrap = 0;
- ps2_queue(&s->common, AUX_ACK);
- return;
- } else if (val != AUX_RESET) {
- ps2_queue(&s->common, val);
- return;
- }
- }
- switch(val) {
- case AUX_SET_SCALE11:
- s->mouse_status &= ~MOUSE_STATUS_SCALE21;
- ps2_queue(&s->common, AUX_ACK);
- break;
- case AUX_SET_SCALE21:
- s->mouse_status |= MOUSE_STATUS_SCALE21;
- ps2_queue(&s->common, AUX_ACK);
- break;
- case AUX_SET_STREAM:
- s->mouse_status &= ~MOUSE_STATUS_REMOTE;
- ps2_queue(&s->common, AUX_ACK);
- break;
- case AUX_SET_WRAP:
- s->mouse_wrap = 1;
- ps2_queue(&s->common, AUX_ACK);
- break;
- case AUX_SET_REMOTE:
- s->mouse_status |= MOUSE_STATUS_REMOTE;
- ps2_queue(&s->common, AUX_ACK);
- break;
- case AUX_GET_TYPE:
- ps2_queue(&s->common, AUX_ACK);
- ps2_queue(&s->common, s->mouse_type);
- break;
- case AUX_SET_RES:
- case AUX_SET_SAMPLE:
- s->common.write_cmd = val;
- ps2_queue(&s->common, AUX_ACK);
- break;
- case AUX_GET_SCALE:
- ps2_queue(&s->common, AUX_ACK);
- ps2_queue(&s->common, s->mouse_status);
- ps2_queue(&s->common, s->mouse_resolution);
- ps2_queue(&s->common, s->mouse_sample_rate);
- break;
- case AUX_POLL:
- ps2_queue(&s->common, AUX_ACK);
- ps2_mouse_send_packet(s);
- break;
- case AUX_ENABLE_DEV:
- s->mouse_status |= MOUSE_STATUS_ENABLED;
- ps2_queue(&s->common, AUX_ACK);
- break;
- case AUX_DISABLE_DEV:
- s->mouse_status &= ~MOUSE_STATUS_ENABLED;
- ps2_queue(&s->common, AUX_ACK);
- break;
- case AUX_SET_DEFAULT:
- s->mouse_sample_rate = 100;
- s->mouse_resolution = 2;
- s->mouse_status = 0;
- ps2_queue(&s->common, AUX_ACK);
- break;
- case AUX_RESET:
- s->mouse_sample_rate = 100;
- s->mouse_resolution = 2;
- s->mouse_status = 0;
- s->mouse_type = 0;
- ps2_queue(&s->common, AUX_ACK);
- ps2_queue(&s->common, 0xaa);
- ps2_queue(&s->common, s->mouse_type);
- break;
- default:
- break;
- }
- break;
- case AUX_SET_SAMPLE:
- s->mouse_sample_rate = val;
- /* detect IMPS/2 or IMEX */
- switch(s->mouse_detect_state) {
- default:
- case 0:
- if (val == 200)
- s->mouse_detect_state = 1;
- break;
- case 1:
- if (val == 100)
- s->mouse_detect_state = 2;
- else if (val == 200)
- s->mouse_detect_state = 3;
- else
- s->mouse_detect_state = 0;
- break;
- case 2:
- if (val == 80)
- s->mouse_type = 3; /* IMPS/2 */
- s->mouse_detect_state = 0;
- break;
- case 3:
- if (val == 80)
- s->mouse_type = 4; /* IMEX */
- s->mouse_detect_state = 0;
- break;
- }
- ps2_queue(&s->common, AUX_ACK);
- s->common.write_cmd = -1;
- break;
- case AUX_SET_RES:
- s->mouse_resolution = val;
- ps2_queue(&s->common, AUX_ACK);
- s->common.write_cmd = -1;
- break;
- }
-}
-
-static void ps2_common_reset(PS2State *s)
-{
- PS2Queue *q;
- s->write_cmd = -1;
- q = &s->queue;
- q->rptr = 0;
- q->wptr = 0;
- q->count = 0;
- s->update_irq(s->update_arg, 0);
-}
-
-static void ps2_common_post_load(PS2State *s)
-{
- PS2Queue *q = &s->queue;
- int size;
- int i;
- int tmp_data[PS2_QUEUE_SIZE];
-
- /* set the useful data buffer queue size, < PS2_QUEUE_SIZE */
- size = q->count > PS2_QUEUE_SIZE ? 0 : q->count;
-
- /* move the queue elements to the start of data array */
- if (size > 0) {
- for (i = 0; i < size; i++) {
- /* move the queue elements to the temporary buffer */
- tmp_data[i] = q->data[q->rptr];
- if (++q->rptr == 256) {
- q->rptr = 0;
- }
- }
- memcpy(q->data, tmp_data, size);
- }
- /* reset rptr/wptr/count */
- q->rptr = 0;
- q->wptr = size;
- q->count = size;
- s->update_irq(s->update_arg, q->count != 0);
-}
-
-static void ps2_kbd_reset(void *opaque)
-{
- PS2KbdState *s = (PS2KbdState *) opaque;
-
- trace_ps2_kbd_reset(opaque);
- ps2_common_reset(&s->common);
- s->scan_enabled = 0;
- s->translate = 0;
- s->scancode_set = 2;
-}
-
-static void ps2_mouse_reset(void *opaque)
-{
- PS2MouseState *s = (PS2MouseState *) opaque;
-
- trace_ps2_mouse_reset(opaque);
- ps2_common_reset(&s->common);
- s->mouse_status = 0;
- s->mouse_resolution = 0;
- s->mouse_sample_rate = 0;
- s->mouse_wrap = 0;
- s->mouse_type = 0;
- s->mouse_detect_state = 0;
- s->mouse_dx = 0;
- s->mouse_dy = 0;
- s->mouse_dz = 0;
- s->mouse_buttons = 0;
-}
-
-static const VMStateDescription vmstate_ps2_common = {
- .name = "PS2 Common State",
- .version_id = 3,
- .minimum_version_id = 2,
- .fields = (VMStateField[]) {
- VMSTATE_INT32(write_cmd, PS2State),
- VMSTATE_INT32(queue.rptr, PS2State),
- VMSTATE_INT32(queue.wptr, PS2State),
- VMSTATE_INT32(queue.count, PS2State),
- VMSTATE_BUFFER(queue.data, PS2State),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static bool ps2_keyboard_ledstate_needed(void *opaque)
-{
- PS2KbdState *s = opaque;
-
- return s->ledstate != 0; /* 0 is default state */
-}
-
-static int ps2_kbd_ledstate_post_load(void *opaque, int version_id)
-{
- PS2KbdState *s = opaque;
-
- kbd_put_ledstate(s->ledstate);
- return 0;
-}
-
-static const VMStateDescription vmstate_ps2_keyboard_ledstate = {
- .name = "ps2kbd/ledstate",
- .version_id = 3,
- .minimum_version_id = 2,
- .post_load = ps2_kbd_ledstate_post_load,
- .needed = ps2_keyboard_ledstate_needed,
- .fields = (VMStateField[]) {
- VMSTATE_INT32(ledstate, PS2KbdState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static int ps2_kbd_post_load(void* opaque, int version_id)
-{
- PS2KbdState *s = (PS2KbdState*)opaque;
- PS2State *ps2 = &s->common;
-
- if (version_id == 2)
- s->scancode_set=2;
-
- ps2_common_post_load(ps2);
-
- return 0;
-}
-
-static void ps2_kbd_pre_save(void *opaque)
-{
- PS2KbdState *s = (PS2KbdState *)opaque;
- PS2State *ps2 = &s->common;
-
- ps2_common_post_load(ps2);
-}
-
-static const VMStateDescription vmstate_ps2_keyboard = {
- .name = "ps2kbd",
- .version_id = 3,
- .minimum_version_id = 2,
- .post_load = ps2_kbd_post_load,
- .pre_save = ps2_kbd_pre_save,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT(common, PS2KbdState, 0, vmstate_ps2_common, PS2State),
- VMSTATE_INT32(scan_enabled, PS2KbdState),
- VMSTATE_INT32(translate, PS2KbdState),
- VMSTATE_INT32_V(scancode_set, PS2KbdState,3),
- VMSTATE_END_OF_LIST()
- },
- .subsections = (const VMStateDescription*[]) {
- &vmstate_ps2_keyboard_ledstate,
- NULL
- }
-};
-
-static int ps2_mouse_post_load(void *opaque, int version_id)
-{
- PS2MouseState *s = (PS2MouseState *)opaque;
- PS2State *ps2 = &s->common;
-
- ps2_common_post_load(ps2);
-
- return 0;
-}
-
-static void ps2_mouse_pre_save(void *opaque)
-{
- PS2MouseState *s = (PS2MouseState *)opaque;
- PS2State *ps2 = &s->common;
-
- ps2_common_post_load(ps2);
-}
-
-static const VMStateDescription vmstate_ps2_mouse = {
- .name = "ps2mouse",
- .version_id = 2,
- .minimum_version_id = 2,
- .post_load = ps2_mouse_post_load,
- .pre_save = ps2_mouse_pre_save,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT(common, PS2MouseState, 0, vmstate_ps2_common, PS2State),
- VMSTATE_UINT8(mouse_status, PS2MouseState),
- VMSTATE_UINT8(mouse_resolution, PS2MouseState),
- VMSTATE_UINT8(mouse_sample_rate, PS2MouseState),
- VMSTATE_UINT8(mouse_wrap, PS2MouseState),
- VMSTATE_UINT8(mouse_type, PS2MouseState),
- VMSTATE_UINT8(mouse_detect_state, PS2MouseState),
- VMSTATE_INT32(mouse_dx, PS2MouseState),
- VMSTATE_INT32(mouse_dy, PS2MouseState),
- VMSTATE_INT32(mouse_dz, PS2MouseState),
- VMSTATE_UINT8(mouse_buttons, PS2MouseState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static QemuInputHandler ps2_keyboard_handler = {
- .name = "QEMU PS/2 Keyboard",
- .mask = INPUT_EVENT_MASK_KEY,
- .event = ps2_keyboard_event,
-};
-
-void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg)
-{
- PS2KbdState *s = (PS2KbdState *)g_malloc0(sizeof(PS2KbdState));
-
- trace_ps2_kbd_init(s);
- s->common.update_irq = update_irq;
- s->common.update_arg = update_arg;
- s->scancode_set = 2;
- vmstate_register(NULL, 0, &vmstate_ps2_keyboard, s);
- qemu_input_handler_register((DeviceState *)s,
- &ps2_keyboard_handler);
- qemu_register_reset(ps2_kbd_reset, s);
- return s;
-}
-
-static QemuInputHandler ps2_mouse_handler = {
- .name = "QEMU PS/2 Mouse",
- .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
- .event = ps2_mouse_event,
- .sync = ps2_mouse_sync,
-};
-
-void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg)
-{
- PS2MouseState *s = (PS2MouseState *)g_malloc0(sizeof(PS2MouseState));
-
- trace_ps2_mouse_init(s);
- s->common.update_irq = update_irq;
- s->common.update_arg = update_arg;
- vmstate_register(NULL, 0, &vmstate_ps2_mouse, s);
- qemu_input_handler_register((DeviceState *)s,
- &ps2_mouse_handler);
- qemu_register_reset(ps2_mouse_reset, s);
- return s;
-}
diff --git a/qemu/hw/input/pxa2xx_keypad.c b/qemu/hw/input/pxa2xx_keypad.c
deleted file mode 100644
index 2b70bbb95..000000000
--- a/qemu/hw/input/pxa2xx_keypad.c
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * Intel PXA27X Keypad Controller emulation.
- *
- * Copyright (c) 2007 MontaVista Software, Inc
- * Written by Armin Kuster <akuster@kama-aina.net>
- * or <Akuster@mvista.com>
- *
- * This code is licensed under the GPLv2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/arm/pxa.h"
-#include "ui/console.h"
-
-/*
- * Keypad
- */
-#define KPC 0x00 /* Keypad Interface Control register */
-#define KPDK 0x08 /* Keypad Interface Direct Key register */
-#define KPREC 0x10 /* Keypad Interface Rotary Encoder register */
-#define KPMK 0x18 /* Keypad Interface Matrix Key register */
-#define KPAS 0x20 /* Keypad Interface Automatic Scan register */
-#define KPASMKP0 0x28 /* Keypad Interface Automatic Scan Multiple
- Key Presser register 0 */
-#define KPASMKP1 0x30 /* Keypad Interface Automatic Scan Multiple
- Key Presser register 1 */
-#define KPASMKP2 0x38 /* Keypad Interface Automatic Scan Multiple
- Key Presser register 2 */
-#define KPASMKP3 0x40 /* Keypad Interface Automatic Scan Multiple
- Key Presser register 3 */
-#define KPKDI 0x48 /* Keypad Interface Key Debounce Interval
- register */
-
-/* Keypad defines */
-#define KPC_AS (0x1 << 30) /* Automatic Scan bit */
-#define KPC_ASACT (0x1 << 29) /* Automatic Scan on Activity */
-#define KPC_MI (0x1 << 22) /* Matrix interrupt bit */
-#define KPC_IMKP (0x1 << 21) /* Ignore Multiple Key Press */
-#define KPC_MS7 (0x1 << 20) /* Matrix scan line 7 */
-#define KPC_MS6 (0x1 << 19) /* Matrix scan line 6 */
-#define KPC_MS5 (0x1 << 18) /* Matrix scan line 5 */
-#define KPC_MS4 (0x1 << 17) /* Matrix scan line 4 */
-#define KPC_MS3 (0x1 << 16) /* Matrix scan line 3 */
-#define KPC_MS2 (0x1 << 15) /* Matrix scan line 2 */
-#define KPC_MS1 (0x1 << 14) /* Matrix scan line 1 */
-#define KPC_MS0 (0x1 << 13) /* Matrix scan line 0 */
-#define KPC_ME (0x1 << 12) /* Matrix Keypad Enable */
-#define KPC_MIE (0x1 << 11) /* Matrix Interrupt Enable */
-#define KPC_DK_DEB_SEL (0x1 << 9) /* Direct Keypad Debounce Select */
-#define KPC_DI (0x1 << 5) /* Direct key interrupt bit */
-#define KPC_RE_ZERO_DEB (0x1 << 4) /* Rotary Encoder Zero Debounce */
-#define KPC_REE1 (0x1 << 3) /* Rotary Encoder1 Enable */
-#define KPC_REE0 (0x1 << 2) /* Rotary Encoder0 Enable */
-#define KPC_DE (0x1 << 1) /* Direct Keypad Enable */
-#define KPC_DIE (0x1 << 0) /* Direct Keypad interrupt Enable */
-
-#define KPDK_DKP (0x1 << 31)
-#define KPDK_DK7 (0x1 << 7)
-#define KPDK_DK6 (0x1 << 6)
-#define KPDK_DK5 (0x1 << 5)
-#define KPDK_DK4 (0x1 << 4)
-#define KPDK_DK3 (0x1 << 3)
-#define KPDK_DK2 (0x1 << 2)
-#define KPDK_DK1 (0x1 << 1)
-#define KPDK_DK0 (0x1 << 0)
-
-#define KPREC_OF1 (0x1 << 31)
-#define KPREC_UF1 (0x1 << 30)
-#define KPREC_OF0 (0x1 << 15)
-#define KPREC_UF0 (0x1 << 14)
-
-#define KPMK_MKP (0x1 << 31)
-#define KPAS_SO (0x1 << 31)
-#define KPASMKPx_SO (0x1 << 31)
-
-
-#define KPASMKPx_MKC(row, col) (1 << (row + 16 * (col % 2)))
-
-#define PXAKBD_MAXROW 8
-#define PXAKBD_MAXCOL 8
-
-struct PXA2xxKeyPadState {
- MemoryRegion iomem;
- qemu_irq irq;
- const struct keymap *map;
- int pressed_cnt;
- int alt_code;
-
- uint32_t kpc;
- uint32_t kpdk;
- uint32_t kprec;
- uint32_t kpmk;
- uint32_t kpas;
- uint32_t kpasmkp[4];
- uint32_t kpkdi;
-};
-
-static void pxa27x_keypad_find_pressed_key(PXA2xxKeyPadState *kp, int *row, int *col)
-{
- int i;
- for (i = 0; i < 4; i++)
- {
- *col = i * 2;
- for (*row = 0; *row < 8; (*row)++) {
- if (kp->kpasmkp[i] & (1 << *row))
- return;
- }
- *col = i * 2 + 1;
- for (*row = 0; *row < 8; (*row)++) {
- if (kp->kpasmkp[i] & (1 << (*row + 16)))
- return;
- }
- }
-}
-
-static void pxa27x_keyboard_event (PXA2xxKeyPadState *kp, int keycode)
-{
- int row, col, rel, assert_irq = 0;
- uint32_t val;
-
- if (keycode == 0xe0) {
- kp->alt_code = 1;
- return;
- }
-
- if(!(kp->kpc & KPC_ME)) /* skip if not enabled */
- return;
-
- rel = (keycode & 0x80) ? 1 : 0; /* key release from qemu */
- keycode &= ~0x80; /* strip qemu key release bit */
- if (kp->alt_code) {
- keycode |= 0x80;
- kp->alt_code = 0;
- }
-
- row = kp->map[keycode].row;
- col = kp->map[keycode].column;
- if (row == -1 || col == -1) {
- return;
- }
-
- val = KPASMKPx_MKC(row, col);
- if (rel) {
- if (kp->kpasmkp[col / 2] & val) {
- kp->kpasmkp[col / 2] &= ~val;
- kp->pressed_cnt--;
- assert_irq = 1;
- }
- } else {
- if (!(kp->kpasmkp[col / 2] & val)) {
- kp->kpasmkp[col / 2] |= val;
- kp->pressed_cnt++;
- assert_irq = 1;
- }
- }
- kp->kpas = ((kp->pressed_cnt & 0x1f) << 26) | (0xf << 4) | 0xf;
- if (kp->pressed_cnt == 1) {
- kp->kpas &= ~((0xf << 4) | 0xf);
- if (rel) {
- pxa27x_keypad_find_pressed_key(kp, &row, &col);
- }
- kp->kpas |= ((row & 0xf) << 4) | (col & 0xf);
- }
-
- if (!(kp->kpc & (KPC_AS | KPC_ASACT)))
- assert_irq = 0;
-
- if (assert_irq && (kp->kpc & KPC_MIE)) {
- kp->kpc |= KPC_MI;
- qemu_irq_raise(kp->irq);
- }
-}
-
-static uint64_t pxa2xx_keypad_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- PXA2xxKeyPadState *s = (PXA2xxKeyPadState *) opaque;
- uint32_t tmp;
-
- switch (offset) {
- case KPC:
- tmp = s->kpc;
- if(tmp & KPC_MI)
- s->kpc &= ~(KPC_MI);
- if(tmp & KPC_DI)
- s->kpc &= ~(KPC_DI);
- qemu_irq_lower(s->irq);
- return tmp;
- break;
- case KPDK:
- return s->kpdk;
- break;
- case KPREC:
- tmp = s->kprec;
- if(tmp & KPREC_OF1)
- s->kprec &= ~(KPREC_OF1);
- if(tmp & KPREC_UF1)
- s->kprec &= ~(KPREC_UF1);
- if(tmp & KPREC_OF0)
- s->kprec &= ~(KPREC_OF0);
- if(tmp & KPREC_UF0)
- s->kprec &= ~(KPREC_UF0);
- return tmp;
- break;
- case KPMK:
- tmp = s->kpmk;
- if(tmp & KPMK_MKP)
- s->kpmk &= ~(KPMK_MKP);
- return tmp;
- break;
- case KPAS:
- return s->kpas;
- break;
- case KPASMKP0:
- return s->kpasmkp[0];
- break;
- case KPASMKP1:
- return s->kpasmkp[1];
- break;
- case KPASMKP2:
- return s->kpasmkp[2];
- break;
- case KPASMKP3:
- return s->kpasmkp[3];
- break;
- case KPKDI:
- return s->kpkdi;
- break;
- default:
- hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
- }
-
- return 0;
-}
-
-static void pxa2xx_keypad_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PXA2xxKeyPadState *s = (PXA2xxKeyPadState *) opaque;
-
- switch (offset) {
- case KPC:
- s->kpc = value;
- if (s->kpc & KPC_AS) {
- s->kpc &= ~(KPC_AS);
- }
- break;
- case KPDK:
- s->kpdk = value;
- break;
- case KPREC:
- s->kprec = value;
- break;
- case KPMK:
- s->kpmk = value;
- break;
- case KPAS:
- s->kpas = value;
- break;
- case KPASMKP0:
- s->kpasmkp[0] = value;
- break;
- case KPASMKP1:
- s->kpasmkp[1] = value;
- break;
- case KPASMKP2:
- s->kpasmkp[2] = value;
- break;
- case KPASMKP3:
- s->kpasmkp[3] = value;
- break;
- case KPKDI:
- s->kpkdi = value;
- break;
-
- default:
- hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
- }
-}
-
-static const MemoryRegionOps pxa2xx_keypad_ops = {
- .read = pxa2xx_keypad_read,
- .write = pxa2xx_keypad_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_pxa2xx_keypad = {
- .name = "pxa2xx_keypad",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(kpc, PXA2xxKeyPadState),
- VMSTATE_UINT32(kpdk, PXA2xxKeyPadState),
- VMSTATE_UINT32(kprec, PXA2xxKeyPadState),
- VMSTATE_UINT32(kpmk, PXA2xxKeyPadState),
- VMSTATE_UINT32(kpas, PXA2xxKeyPadState),
- VMSTATE_UINT32_ARRAY(kpasmkp, PXA2xxKeyPadState, 4),
- VMSTATE_UINT32(kpkdi, PXA2xxKeyPadState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-PXA2xxKeyPadState *pxa27x_keypad_init(MemoryRegion *sysmem,
- hwaddr base,
- qemu_irq irq)
-{
- PXA2xxKeyPadState *s;
-
- s = (PXA2xxKeyPadState *) g_malloc0(sizeof(PXA2xxKeyPadState));
- s->irq = irq;
-
- memory_region_init_io(&s->iomem, NULL, &pxa2xx_keypad_ops, s,
- "pxa2xx-keypad", 0x00100000);
- memory_region_add_subregion(sysmem, base, &s->iomem);
-
- vmstate_register(NULL, 0, &vmstate_pxa2xx_keypad, s);
-
- return s;
-}
-
-void pxa27x_register_keypad(PXA2xxKeyPadState *kp,
- const struct keymap *map, int size)
-{
- if(!map || size < 0x80) {
- fprintf(stderr, "%s - No PXA keypad map defined\n", __FUNCTION__);
- exit(-1);
- }
-
- kp->map = map;
- qemu_add_kbd_event_handler((QEMUPutKBDEvent *) pxa27x_keyboard_event, kp);
-}
diff --git a/qemu/hw/input/stellaris_input.c b/qemu/hw/input/stellaris_input.c
deleted file mode 100644
index 99168bfee..000000000
--- a/qemu/hw/input/stellaris_input.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Gamepad style buttons connected to IRQ/GPIO lines
- *
- * Copyright (c) 2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/devices.h"
-#include "ui/console.h"
-
-typedef struct {
- qemu_irq irq;
- int keycode;
- uint8_t pressed;
-} gamepad_button;
-
-typedef struct {
- gamepad_button *buttons;
- int num_buttons;
- int extension;
-} gamepad_state;
-
-static void stellaris_gamepad_put_key(void * opaque, int keycode)
-{
- gamepad_state *s = (gamepad_state *)opaque;
- int i;
- int down;
-
- if (keycode == 0xe0 && !s->extension) {
- s->extension = 0x80;
- return;
- }
-
- down = (keycode & 0x80) == 0;
- keycode = (keycode & 0x7f) | s->extension;
-
- for (i = 0; i < s->num_buttons; i++) {
- if (s->buttons[i].keycode == keycode
- && s->buttons[i].pressed != down) {
- s->buttons[i].pressed = down;
- qemu_set_irq(s->buttons[i].irq, down);
- }
- }
-
- s->extension = 0;
-}
-
-static const VMStateDescription vmstate_stellaris_button = {
- .name = "stellaris_button",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(pressed, gamepad_button),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_stellaris_gamepad = {
- .name = "stellaris_gamepad",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_INT32(extension, gamepad_state),
- VMSTATE_STRUCT_VARRAY_INT32(buttons, gamepad_state, num_buttons, 0,
- vmstate_stellaris_button, gamepad_button),
- VMSTATE_END_OF_LIST()
- }
-};
-
-/* Returns an array of 5 output slots. */
-void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode)
-{
- gamepad_state *s;
- int i;
-
- s = g_new0(gamepad_state, 1);
- s->buttons = g_new0(gamepad_button, n);
- for (i = 0; i < n; i++) {
- s->buttons[i].irq = irq[i];
- s->buttons[i].keycode = keycode[i];
- }
- s->num_buttons = n;
- qemu_add_kbd_event_handler(stellaris_gamepad_put_key, s);
- vmstate_register(NULL, -1, &vmstate_stellaris_gamepad, s);
-}
diff --git a/qemu/hw/input/tsc2005.c b/qemu/hw/input/tsc2005.c
deleted file mode 100644
index 9b359aaec..000000000
--- a/qemu/hw/input/tsc2005.c
+++ /dev/null
@@ -1,595 +0,0 @@
-/*
- * TI TSC2005 emulator.
- *
- * Copyright (c) 2006 Andrzej Zaborowski <balrog@zabor.org>
- * Copyright (C) 2008 Nokia Corporation
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "qemu/timer.h"
-#include "ui/console.h"
-#include "hw/devices.h"
-
-#define TSC_CUT_RESOLUTION(value, p) ((value) >> (16 - (p ? 12 : 10)))
-
-typedef struct {
- qemu_irq pint; /* Combination of the nPENIRQ and DAV signals */
- QEMUTimer *timer;
- uint16_t model;
-
- int x, y;
- int pressure;
-
- int state, reg, irq, command;
- uint16_t data, dav;
-
- int busy;
- int enabled;
- int host_mode;
- int function;
- int nextfunction;
- int precision;
- int nextprecision;
- int filter;
- int pin_func;
- int timing[2];
- int noise;
- int reset;
- int pdst;
- int pnd0;
- uint16_t temp_thr[2];
- uint16_t aux_thr[2];
-
- int tr[8];
-} TSC2005State;
-
-enum {
- TSC_MODE_XYZ_SCAN = 0x0,
- TSC_MODE_XY_SCAN,
- TSC_MODE_X,
- TSC_MODE_Y,
- TSC_MODE_Z,
- TSC_MODE_AUX,
- TSC_MODE_TEMP1,
- TSC_MODE_TEMP2,
- TSC_MODE_AUX_SCAN,
- TSC_MODE_X_TEST,
- TSC_MODE_Y_TEST,
- TSC_MODE_TS_TEST,
- TSC_MODE_RESERVED,
- TSC_MODE_XX_DRV,
- TSC_MODE_YY_DRV,
- TSC_MODE_YX_DRV,
-};
-
-static const uint16_t mode_regs[16] = {
- 0xf000, /* X, Y, Z scan */
- 0xc000, /* X, Y scan */
- 0x8000, /* X */
- 0x4000, /* Y */
- 0x3000, /* Z */
- 0x0800, /* AUX */
- 0x0400, /* TEMP1 */
- 0x0200, /* TEMP2 */
- 0x0800, /* AUX scan */
- 0x0040, /* X test */
- 0x0020, /* Y test */
- 0x0080, /* Short-circuit test */
- 0x0000, /* Reserved */
- 0x0000, /* X+, X- drivers */
- 0x0000, /* Y+, Y- drivers */
- 0x0000, /* Y+, X- drivers */
-};
-
-#define X_TRANSFORM(s) \
- ((s->y * s->tr[0] - s->x * s->tr[1]) / s->tr[2] + s->tr[3])
-#define Y_TRANSFORM(s) \
- ((s->y * s->tr[4] - s->x * s->tr[5]) / s->tr[6] + s->tr[7])
-#define Z1_TRANSFORM(s) \
- ((400 - ((s)->x >> 7) + ((s)->pressure << 10)) << 4)
-#define Z2_TRANSFORM(s) \
- ((4000 + ((s)->y >> 7) - ((s)->pressure << 10)) << 4)
-
-#define AUX_VAL (700 << 4) /* +/- 3 at 12-bit */
-#define TEMP1_VAL (1264 << 4) /* +/- 5 at 12-bit */
-#define TEMP2_VAL (1531 << 4) /* +/- 5 at 12-bit */
-
-static uint16_t tsc2005_read(TSC2005State *s, int reg)
-{
- uint16_t ret;
-
- switch (reg) {
- case 0x0: /* X */
- s->dav &= ~mode_regs[TSC_MODE_X];
- return TSC_CUT_RESOLUTION(X_TRANSFORM(s), s->precision) +
- (s->noise & 3);
- case 0x1: /* Y */
- s->dav &= ~mode_regs[TSC_MODE_Y];
- s->noise ++;
- return TSC_CUT_RESOLUTION(Y_TRANSFORM(s), s->precision) ^
- (s->noise & 3);
- case 0x2: /* Z1 */
- s->dav &= 0xdfff;
- return TSC_CUT_RESOLUTION(Z1_TRANSFORM(s), s->precision) -
- (s->noise & 3);
- case 0x3: /* Z2 */
- s->dav &= 0xefff;
- return TSC_CUT_RESOLUTION(Z2_TRANSFORM(s), s->precision) |
- (s->noise & 3);
-
- case 0x4: /* AUX */
- s->dav &= ~mode_regs[TSC_MODE_AUX];
- return TSC_CUT_RESOLUTION(AUX_VAL, s->precision);
-
- case 0x5: /* TEMP1 */
- s->dav &= ~mode_regs[TSC_MODE_TEMP1];
- return TSC_CUT_RESOLUTION(TEMP1_VAL, s->precision) -
- (s->noise & 5);
- case 0x6: /* TEMP2 */
- s->dav &= 0xdfff;
- s->dav &= ~mode_regs[TSC_MODE_TEMP2];
- return TSC_CUT_RESOLUTION(TEMP2_VAL, s->precision) ^
- (s->noise & 3);
-
- case 0x7: /* Status */
- ret = s->dav | (s->reset << 7) | (s->pdst << 2) | 0x0;
- s->dav &= ~(mode_regs[TSC_MODE_X_TEST] | mode_regs[TSC_MODE_Y_TEST] |
- mode_regs[TSC_MODE_TS_TEST]);
- s->reset = 1;
- return ret;
-
- case 0x8: /* AUX high treshold */
- return s->aux_thr[1];
- case 0x9: /* AUX low treshold */
- return s->aux_thr[0];
-
- case 0xa: /* TEMP high treshold */
- return s->temp_thr[1];
- case 0xb: /* TEMP low treshold */
- return s->temp_thr[0];
-
- case 0xc: /* CFR0 */
- return (s->pressure << 15) | ((!s->busy) << 14) |
- (s->nextprecision << 13) | s->timing[0];
- case 0xd: /* CFR1 */
- return s->timing[1];
- case 0xe: /* CFR2 */
- return (s->pin_func << 14) | s->filter;
-
- case 0xf: /* Function select status */
- return s->function >= 0 ? 1 << s->function : 0;
- }
-
- /* Never gets here */
- return 0xffff;
-}
-
-static void tsc2005_write(TSC2005State *s, int reg, uint16_t data)
-{
- switch (reg) {
- case 0x8: /* AUX high treshold */
- s->aux_thr[1] = data;
- break;
- case 0x9: /* AUX low treshold */
- s->aux_thr[0] = data;
- break;
-
- case 0xa: /* TEMP high treshold */
- s->temp_thr[1] = data;
- break;
- case 0xb: /* TEMP low treshold */
- s->temp_thr[0] = data;
- break;
-
- case 0xc: /* CFR0 */
- s->host_mode = data >> 15;
- if (s->enabled != !(data & 0x4000)) {
- s->enabled = !(data & 0x4000);
- fprintf(stderr, "%s: touchscreen sense %sabled\n",
- __FUNCTION__, s->enabled ? "en" : "dis");
- if (s->busy && !s->enabled)
- timer_del(s->timer);
- s->busy &= s->enabled;
- }
- s->nextprecision = (data >> 13) & 1;
- s->timing[0] = data & 0x1fff;
- if ((s->timing[0] >> 11) == 3)
- fprintf(stderr, "%s: illegal conversion clock setting\n",
- __FUNCTION__);
- break;
- case 0xd: /* CFR1 */
- s->timing[1] = data & 0xf07;
- break;
- case 0xe: /* CFR2 */
- s->pin_func = (data >> 14) & 3;
- s->filter = data & 0x3fff;
- break;
-
- default:
- fprintf(stderr, "%s: write into read-only register %x\n",
- __FUNCTION__, reg);
- }
-}
-
-/* This handles most of the chip's logic. */
-static void tsc2005_pin_update(TSC2005State *s)
-{
- int64_t expires;
- int pin_state;
-
- switch (s->pin_func) {
- case 0:
- pin_state = !s->pressure && !!s->dav;
- break;
- case 1:
- case 3:
- default:
- pin_state = !s->dav;
- break;
- case 2:
- pin_state = !s->pressure;
- }
-
- if (pin_state != s->irq) {
- s->irq = pin_state;
- qemu_set_irq(s->pint, s->irq);
- }
-
- switch (s->nextfunction) {
- case TSC_MODE_XYZ_SCAN:
- case TSC_MODE_XY_SCAN:
- if (!s->host_mode && s->dav)
- s->enabled = 0;
- if (!s->pressure)
- return;
- /* Fall through */
- case TSC_MODE_AUX_SCAN:
- break;
-
- case TSC_MODE_X:
- case TSC_MODE_Y:
- case TSC_MODE_Z:
- if (!s->pressure)
- return;
- /* Fall through */
- case TSC_MODE_AUX:
- case TSC_MODE_TEMP1:
- case TSC_MODE_TEMP2:
- case TSC_MODE_X_TEST:
- case TSC_MODE_Y_TEST:
- case TSC_MODE_TS_TEST:
- if (s->dav)
- s->enabled = 0;
- break;
-
- case TSC_MODE_RESERVED:
- case TSC_MODE_XX_DRV:
- case TSC_MODE_YY_DRV:
- case TSC_MODE_YX_DRV:
- default:
- return;
- }
-
- if (!s->enabled || s->busy)
- return;
-
- s->busy = 1;
- s->precision = s->nextprecision;
- s->function = s->nextfunction;
- s->pdst = !s->pnd0; /* Synchronised on internal clock */
- expires = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- (NANOSECONDS_PER_SECOND >> 7);
- timer_mod(s->timer, expires);
-}
-
-static void tsc2005_reset(TSC2005State *s)
-{
- s->state = 0;
- s->pin_func = 0;
- s->enabled = 0;
- s->busy = 0;
- s->nextprecision = 0;
- s->nextfunction = 0;
- s->timing[0] = 0;
- s->timing[1] = 0;
- s->irq = 0;
- s->dav = 0;
- s->reset = 0;
- s->pdst = 1;
- s->pnd0 = 0;
- s->function = -1;
- s->temp_thr[0] = 0x000;
- s->temp_thr[1] = 0xfff;
- s->aux_thr[0] = 0x000;
- s->aux_thr[1] = 0xfff;
-
- tsc2005_pin_update(s);
-}
-
-static uint8_t tsc2005_txrx_word(void *opaque, uint8_t value)
-{
- TSC2005State *s = opaque;
- uint32_t ret = 0;
-
- switch (s->state ++) {
- case 0:
- if (value & 0x80) {
- /* Command */
- if (value & (1 << 1))
- tsc2005_reset(s);
- else {
- s->nextfunction = (value >> 3) & 0xf;
- s->nextprecision = (value >> 2) & 1;
- if (s->enabled != !(value & 1)) {
- s->enabled = !(value & 1);
- fprintf(stderr, "%s: touchscreen sense %sabled\n",
- __FUNCTION__, s->enabled ? "en" : "dis");
- if (s->busy && !s->enabled)
- timer_del(s->timer);
- s->busy &= s->enabled;
- }
- tsc2005_pin_update(s);
- }
-
- s->state = 0;
- } else if (value) {
- /* Data transfer */
- s->reg = (value >> 3) & 0xf;
- s->pnd0 = (value >> 1) & 1;
- s->command = value & 1;
-
- if (s->command) {
- /* Read */
- s->data = tsc2005_read(s, s->reg);
- tsc2005_pin_update(s);
- } else
- s->data = 0;
- } else
- s->state = 0;
- break;
-
- case 1:
- if (s->command)
- ret = (s->data >> 8) & 0xff;
- else
- s->data |= value << 8;
- break;
-
- case 2:
- if (s->command)
- ret = s->data & 0xff;
- else {
- s->data |= value;
- tsc2005_write(s, s->reg, s->data);
- tsc2005_pin_update(s);
- }
-
- s->state = 0;
- break;
- }
-
- return ret;
-}
-
-uint32_t tsc2005_txrx(void *opaque, uint32_t value, int len)
-{
- uint32_t ret = 0;
-
- len &= ~7;
- while (len > 0) {
- len -= 8;
- ret |= tsc2005_txrx_word(opaque, (value >> len) & 0xff) << len;
- }
-
- return ret;
-}
-
-static void tsc2005_timer_tick(void *opaque)
-{
- TSC2005State *s = opaque;
-
- /* Timer ticked -- a set of conversions has been finished. */
-
- if (!s->busy)
- return;
-
- s->busy = 0;
- s->dav |= mode_regs[s->function];
- s->function = -1;
- tsc2005_pin_update(s);
-}
-
-static void tsc2005_touchscreen_event(void *opaque,
- int x, int y, int z, int buttons_state)
-{
- TSC2005State *s = opaque;
- int p = s->pressure;
-
- if (buttons_state) {
- s->x = x;
- s->y = y;
- }
- s->pressure = !!buttons_state;
-
- /*
- * Note: We would get better responsiveness in the guest by
- * signaling TS events immediately, but for now we simulate
- * the first conversion delay for sake of correctness.
- */
- if (p != s->pressure)
- tsc2005_pin_update(s);
-}
-
-static void tsc2005_save(QEMUFile *f, void *opaque)
-{
- TSC2005State *s = (TSC2005State *) opaque;
- int i;
-
- qemu_put_be16(f, s->x);
- qemu_put_be16(f, s->y);
- qemu_put_byte(f, s->pressure);
-
- qemu_put_byte(f, s->state);
- qemu_put_byte(f, s->reg);
- qemu_put_byte(f, s->command);
-
- qemu_put_byte(f, s->irq);
- qemu_put_be16s(f, &s->dav);
- qemu_put_be16s(f, &s->data);
-
- timer_put(f, s->timer);
- qemu_put_byte(f, s->enabled);
- qemu_put_byte(f, s->host_mode);
- qemu_put_byte(f, s->function);
- qemu_put_byte(f, s->nextfunction);
- qemu_put_byte(f, s->precision);
- qemu_put_byte(f, s->nextprecision);
- qemu_put_be16(f, s->filter);
- qemu_put_byte(f, s->pin_func);
- qemu_put_be16(f, s->timing[0]);
- qemu_put_be16(f, s->timing[1]);
- qemu_put_be16s(f, &s->temp_thr[0]);
- qemu_put_be16s(f, &s->temp_thr[1]);
- qemu_put_be16s(f, &s->aux_thr[0]);
- qemu_put_be16s(f, &s->aux_thr[1]);
- qemu_put_be32(f, s->noise);
- qemu_put_byte(f, s->reset);
- qemu_put_byte(f, s->pdst);
- qemu_put_byte(f, s->pnd0);
-
- for (i = 0; i < 8; i ++)
- qemu_put_be32(f, s->tr[i]);
-}
-
-static int tsc2005_load(QEMUFile *f, void *opaque, int version_id)
-{
- TSC2005State *s = (TSC2005State *) opaque;
- int i;
-
- s->x = qemu_get_be16(f);
- s->y = qemu_get_be16(f);
- s->pressure = qemu_get_byte(f);
-
- s->state = qemu_get_byte(f);
- s->reg = qemu_get_byte(f);
- s->command = qemu_get_byte(f);
-
- s->irq = qemu_get_byte(f);
- qemu_get_be16s(f, &s->dav);
- qemu_get_be16s(f, &s->data);
-
- timer_get(f, s->timer);
- s->enabled = qemu_get_byte(f);
- s->host_mode = qemu_get_byte(f);
- s->function = qemu_get_byte(f);
- s->nextfunction = qemu_get_byte(f);
- s->precision = qemu_get_byte(f);
- s->nextprecision = qemu_get_byte(f);
- s->filter = qemu_get_be16(f);
- s->pin_func = qemu_get_byte(f);
- s->timing[0] = qemu_get_be16(f);
- s->timing[1] = qemu_get_be16(f);
- qemu_get_be16s(f, &s->temp_thr[0]);
- qemu_get_be16s(f, &s->temp_thr[1]);
- qemu_get_be16s(f, &s->aux_thr[0]);
- qemu_get_be16s(f, &s->aux_thr[1]);
- s->noise = qemu_get_be32(f);
- s->reset = qemu_get_byte(f);
- s->pdst = qemu_get_byte(f);
- s->pnd0 = qemu_get_byte(f);
-
- for (i = 0; i < 8; i ++)
- s->tr[i] = qemu_get_be32(f);
-
- s->busy = timer_pending(s->timer);
- tsc2005_pin_update(s);
-
- return 0;
-}
-
-void *tsc2005_init(qemu_irq pintdav)
-{
- TSC2005State *s;
-
- s = (TSC2005State *)
- g_malloc0(sizeof(TSC2005State));
- s->x = 400;
- s->y = 240;
- s->pressure = 0;
- s->precision = s->nextprecision = 0;
- s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tsc2005_timer_tick, s);
- s->pint = pintdav;
- s->model = 0x2005;
-
- s->tr[0] = 0;
- s->tr[1] = 1;
- s->tr[2] = 1;
- s->tr[3] = 0;
- s->tr[4] = 1;
- s->tr[5] = 0;
- s->tr[6] = 1;
- s->tr[7] = 0;
-
- tsc2005_reset(s);
-
- qemu_add_mouse_event_handler(tsc2005_touchscreen_event, s, 1,
- "QEMU TSC2005-driven Touchscreen");
-
- qemu_register_reset((void *) tsc2005_reset, s);
- register_savevm(NULL, "tsc2005", -1, 0, tsc2005_save, tsc2005_load, s);
-
- return s;
-}
-
-/*
- * Use tslib generated calibration data to generate ADC input values
- * from the touchscreen. Assuming 12-bit precision was used during
- * tslib calibration.
- */
-void tsc2005_set_transform(void *opaque, MouseTransformInfo *info)
-{
- TSC2005State *s = (TSC2005State *) opaque;
-
- /* This version assumes touchscreen X & Y axis are parallel or
- * perpendicular to LCD's X & Y axis in some way. */
- if (abs(info->a[0]) > abs(info->a[1])) {
- s->tr[0] = 0;
- s->tr[1] = -info->a[6] * info->x;
- s->tr[2] = info->a[0];
- s->tr[3] = -info->a[2] / info->a[0];
- s->tr[4] = info->a[6] * info->y;
- s->tr[5] = 0;
- s->tr[6] = info->a[4];
- s->tr[7] = -info->a[5] / info->a[4];
- } else {
- s->tr[0] = info->a[6] * info->y;
- s->tr[1] = 0;
- s->tr[2] = info->a[1];
- s->tr[3] = -info->a[2] / info->a[1];
- s->tr[4] = 0;
- s->tr[5] = -info->a[6] * info->x;
- s->tr[6] = info->a[3];
- s->tr[7] = -info->a[5] / info->a[3];
- }
-
- s->tr[0] >>= 11;
- s->tr[1] >>= 11;
- s->tr[3] <<= 4;
- s->tr[4] >>= 11;
- s->tr[5] >>= 11;
- s->tr[7] <<= 4;
-}
diff --git a/qemu/hw/input/tsc210x.c b/qemu/hw/input/tsc210x.c
deleted file mode 100644
index 93ca374fc..000000000
--- a/qemu/hw/input/tsc210x.c
+++ /dev/null
@@ -1,1273 +0,0 @@
-/*
- * TI TSC2102 (touchscreen/sensors/audio controller) emulator.
- * TI TSC2301 (touchscreen/sensors/keypad).
- *
- * Copyright (c) 2006 Andrzej Zaborowski <balrog@zabor.org>
- * Copyright (C) 2008 Nokia Corporation
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "audio/audio.h"
-#include "qemu/timer.h"
-#include "ui/console.h"
-#include "hw/arm/omap.h" /* For I2SCodec and uWireSlave */
-#include "hw/devices.h"
-
-#define TSC_DATA_REGISTERS_PAGE 0x0
-#define TSC_CONTROL_REGISTERS_PAGE 0x1
-#define TSC_AUDIO_REGISTERS_PAGE 0x2
-
-#define TSC_VERBOSE
-
-#define TSC_CUT_RESOLUTION(value, p) ((value) >> (16 - resolution[p]))
-
-typedef struct {
- qemu_irq pint;
- qemu_irq kbint;
- qemu_irq davint;
- QEMUTimer *timer;
- QEMUSoundCard card;
- uWireSlave chip;
- I2SCodec codec;
- uint8_t in_fifo[16384];
- uint8_t out_fifo[16384];
- uint16_t model;
-
- int x, y;
- int pressure;
-
- int state, page, offset, irq;
- uint16_t command, dav;
-
- int busy;
- int enabled;
- int host_mode;
- int function;
- int nextfunction;
- int precision;
- int nextprecision;
- int filter;
- int pin_func;
- int ref;
- int timing;
- int noise;
-
- uint16_t audio_ctrl1;
- uint16_t audio_ctrl2;
- uint16_t audio_ctrl3;
- uint16_t pll[3];
- uint16_t volume;
- int64_t volume_change;
- int softstep;
- uint16_t dac_power;
- int64_t powerdown;
- uint16_t filter_data[0x14];
-
- const char *name;
- SWVoiceIn *adc_voice[1];
- SWVoiceOut *dac_voice[1];
- int i2s_rx_rate;
- int i2s_tx_rate;
-
- int tr[8];
-
- struct {
- uint16_t down;
- uint16_t mask;
- int scan;
- int debounce;
- int mode;
- int intr;
- } kb;
-} TSC210xState;
-
-static const int resolution[4] = { 12, 8, 10, 12 };
-
-#define TSC_MODE_NO_SCAN 0x0
-#define TSC_MODE_XY_SCAN 0x1
-#define TSC_MODE_XYZ_SCAN 0x2
-#define TSC_MODE_X 0x3
-#define TSC_MODE_Y 0x4
-#define TSC_MODE_Z 0x5
-#define TSC_MODE_BAT1 0x6
-#define TSC_MODE_BAT2 0x7
-#define TSC_MODE_AUX 0x8
-#define TSC_MODE_AUX_SCAN 0x9
-#define TSC_MODE_TEMP1 0xa
-#define TSC_MODE_PORT_SCAN 0xb
-#define TSC_MODE_TEMP2 0xc
-#define TSC_MODE_XX_DRV 0xd
-#define TSC_MODE_YY_DRV 0xe
-#define TSC_MODE_YX_DRV 0xf
-
-static const uint16_t mode_regs[16] = {
- 0x0000, /* No scan */
- 0x0600, /* X, Y scan */
- 0x0780, /* X, Y, Z scan */
- 0x0400, /* X */
- 0x0200, /* Y */
- 0x0180, /* Z */
- 0x0040, /* BAT1 */
- 0x0030, /* BAT2 */
- 0x0010, /* AUX */
- 0x0010, /* AUX scan */
- 0x0004, /* TEMP1 */
- 0x0070, /* Port scan */
- 0x0002, /* TEMP2 */
- 0x0000, /* X+, X- drivers */
- 0x0000, /* Y+, Y- drivers */
- 0x0000, /* Y+, X- drivers */
-};
-
-#define X_TRANSFORM(s) \
- ((s->y * s->tr[0] - s->x * s->tr[1]) / s->tr[2] + s->tr[3])
-#define Y_TRANSFORM(s) \
- ((s->y * s->tr[4] - s->x * s->tr[5]) / s->tr[6] + s->tr[7])
-#define Z1_TRANSFORM(s) \
- ((400 - ((s)->x >> 7) + ((s)->pressure << 10)) << 4)
-#define Z2_TRANSFORM(s) \
- ((4000 + ((s)->y >> 7) - ((s)->pressure << 10)) << 4)
-
-#define BAT1_VAL 0x8660
-#define BAT2_VAL 0x0000
-#define AUX1_VAL 0x35c0
-#define AUX2_VAL 0xffff
-#define TEMP1_VAL 0x8c70
-#define TEMP2_VAL 0xa5b0
-
-#define TSC_POWEROFF_DELAY 50
-#define TSC_SOFTSTEP_DELAY 50
-
-static void tsc210x_reset(TSC210xState *s)
-{
- s->state = 0;
- s->pin_func = 2;
- s->enabled = 0;
- s->busy = 0;
- s->nextfunction = 0;
- s->ref = 0;
- s->timing = 0;
- s->irq = 0;
- s->dav = 0;
-
- s->audio_ctrl1 = 0x0000;
- s->audio_ctrl2 = 0x4410;
- s->audio_ctrl3 = 0x0000;
- s->pll[0] = 0x1004;
- s->pll[1] = 0x0000;
- s->pll[2] = 0x1fff;
- s->volume = 0xffff;
- s->dac_power = 0x8540;
- s->softstep = 1;
- s->volume_change = 0;
- s->powerdown = 0;
- s->filter_data[0x00] = 0x6be3;
- s->filter_data[0x01] = 0x9666;
- s->filter_data[0x02] = 0x675d;
- s->filter_data[0x03] = 0x6be3;
- s->filter_data[0x04] = 0x9666;
- s->filter_data[0x05] = 0x675d;
- s->filter_data[0x06] = 0x7d83;
- s->filter_data[0x07] = 0x84ee;
- s->filter_data[0x08] = 0x7d83;
- s->filter_data[0x09] = 0x84ee;
- s->filter_data[0x0a] = 0x6be3;
- s->filter_data[0x0b] = 0x9666;
- s->filter_data[0x0c] = 0x675d;
- s->filter_data[0x0d] = 0x6be3;
- s->filter_data[0x0e] = 0x9666;
- s->filter_data[0x0f] = 0x675d;
- s->filter_data[0x10] = 0x7d83;
- s->filter_data[0x11] = 0x84ee;
- s->filter_data[0x12] = 0x7d83;
- s->filter_data[0x13] = 0x84ee;
-
- s->i2s_tx_rate = 0;
- s->i2s_rx_rate = 0;
-
- s->kb.scan = 1;
- s->kb.debounce = 0;
- s->kb.mask = 0x0000;
- s->kb.mode = 3;
- s->kb.intr = 0;
-
- qemu_set_irq(s->pint, !s->irq);
- qemu_set_irq(s->davint, !s->dav);
- qemu_irq_raise(s->kbint);
-}
-
-typedef struct {
- int rate;
- int dsor;
- int fsref;
-} TSC210xRateInfo;
-
-/* { rate, dsor, fsref } */
-static const TSC210xRateInfo tsc2102_rates[] = {
- /* Fsref / 6.0 */
- { 7350, 63, 1 },
- { 8000, 63, 0 },
- /* Fsref / 6.0 */
- { 7350, 54, 1 },
- { 8000, 54, 0 },
- /* Fsref / 5.0 */
- { 8820, 45, 1 },
- { 9600, 45, 0 },
- /* Fsref / 4.0 */
- { 11025, 36, 1 },
- { 12000, 36, 0 },
- /* Fsref / 3.0 */
- { 14700, 27, 1 },
- { 16000, 27, 0 },
- /* Fsref / 2.0 */
- { 22050, 18, 1 },
- { 24000, 18, 0 },
- /* Fsref / 1.5 */
- { 29400, 9, 1 },
- { 32000, 9, 0 },
- /* Fsref */
- { 44100, 0, 1 },
- { 48000, 0, 0 },
-
- { 0, 0, 0 },
-};
-
-static inline void tsc210x_out_flush(TSC210xState *s, int len)
-{
- uint8_t *data = s->codec.out.fifo + s->codec.out.start;
- uint8_t *end = data + len;
-
- while (data < end)
- data += AUD_write(s->dac_voice[0], data, end - data) ?: (end - data);
-
- s->codec.out.len -= len;
- if (s->codec.out.len)
- memmove(s->codec.out.fifo, end, s->codec.out.len);
- s->codec.out.start = 0;
-}
-
-static void tsc210x_audio_out_cb(TSC210xState *s, int free_b)
-{
- if (s->codec.out.len >= free_b) {
- tsc210x_out_flush(s, free_b);
- return;
- }
-
- s->codec.out.size = MIN(free_b, 16384);
- qemu_irq_raise(s->codec.tx_start);
-}
-
-static void tsc2102_audio_rate_update(TSC210xState *s)
-{
- const TSC210xRateInfo *rate;
-
- s->codec.tx_rate = 0;
- s->codec.rx_rate = 0;
- if (s->dac_power & (1 << 15)) /* PWDNC */
- return;
-
- for (rate = tsc2102_rates; rate->rate; rate ++)
- if (rate->dsor == (s->audio_ctrl1 & 0x3f) && /* DACFS */
- rate->fsref == ((s->audio_ctrl3 >> 13) & 1))/* REFFS */
- break;
- if (!rate->rate) {
- printf("%s: unknown sampling rate configured\n", __FUNCTION__);
- return;
- }
-
- s->codec.tx_rate = rate->rate;
-}
-
-static void tsc2102_audio_output_update(TSC210xState *s)
-{
- int enable;
- struct audsettings fmt;
-
- if (s->dac_voice[0]) {
- tsc210x_out_flush(s, s->codec.out.len);
- s->codec.out.size = 0;
- AUD_set_active_out(s->dac_voice[0], 0);
- AUD_close_out(&s->card, s->dac_voice[0]);
- s->dac_voice[0] = NULL;
- }
- s->codec.cts = 0;
-
- enable =
- (~s->dac_power & (1 << 15)) && /* PWDNC */
- (~s->dac_power & (1 << 10)); /* DAPWDN */
- if (!enable || !s->codec.tx_rate)
- return;
-
- /* Force our own sampling rate even in slave DAC mode */
- fmt.endianness = 0;
- fmt.nchannels = 2;
- fmt.freq = s->codec.tx_rate;
- fmt.fmt = AUD_FMT_S16;
-
- s->dac_voice[0] = AUD_open_out(&s->card, s->dac_voice[0],
- "tsc2102.sink", s, (void *) tsc210x_audio_out_cb, &fmt);
- if (s->dac_voice[0]) {
- s->codec.cts = 1;
- AUD_set_active_out(s->dac_voice[0], 1);
- }
-}
-
-static uint16_t tsc2102_data_register_read(TSC210xState *s, int reg)
-{
- switch (reg) {
- case 0x00: /* X */
- s->dav &= 0xfbff;
- return TSC_CUT_RESOLUTION(X_TRANSFORM(s), s->precision) +
- (s->noise & 3);
-
- case 0x01: /* Y */
- s->noise ++;
- s->dav &= 0xfdff;
- return TSC_CUT_RESOLUTION(Y_TRANSFORM(s), s->precision) ^
- (s->noise & 3);
-
- case 0x02: /* Z1 */
- s->dav &= 0xfeff;
- return TSC_CUT_RESOLUTION(Z1_TRANSFORM(s), s->precision) -
- (s->noise & 3);
-
- case 0x03: /* Z2 */
- s->dav &= 0xff7f;
- return TSC_CUT_RESOLUTION(Z2_TRANSFORM(s), s->precision) |
- (s->noise & 3);
-
- case 0x04: /* KPData */
- if ((s->model & 0xff00) == 0x2300) {
- if (s->kb.intr && (s->kb.mode & 2)) {
- s->kb.intr = 0;
- qemu_irq_raise(s->kbint);
- }
- return s->kb.down;
- }
-
- return 0xffff;
-
- case 0x05: /* BAT1 */
- s->dav &= 0xffbf;
- return TSC_CUT_RESOLUTION(BAT1_VAL, s->precision) +
- (s->noise & 6);
-
- case 0x06: /* BAT2 */
- s->dav &= 0xffdf;
- return TSC_CUT_RESOLUTION(BAT2_VAL, s->precision);
-
- case 0x07: /* AUX1 */
- s->dav &= 0xffef;
- return TSC_CUT_RESOLUTION(AUX1_VAL, s->precision);
-
- case 0x08: /* AUX2 */
- s->dav &= 0xfff7;
- return 0xffff;
-
- case 0x09: /* TEMP1 */
- s->dav &= 0xfffb;
- return TSC_CUT_RESOLUTION(TEMP1_VAL, s->precision) -
- (s->noise & 5);
-
- case 0x0a: /* TEMP2 */
- s->dav &= 0xfffd;
- return TSC_CUT_RESOLUTION(TEMP2_VAL, s->precision) ^
- (s->noise & 3);
-
- case 0x0b: /* DAC */
- s->dav &= 0xfffe;
- return 0xffff;
-
- default:
-#ifdef TSC_VERBOSE
- fprintf(stderr, "tsc2102_data_register_read: "
- "no such register: 0x%02x\n", reg);
-#endif
- return 0xffff;
- }
-}
-
-static uint16_t tsc2102_control_register_read(
- TSC210xState *s, int reg)
-{
- switch (reg) {
- case 0x00: /* TSC ADC */
- return (s->pressure << 15) | ((!s->busy) << 14) |
- (s->nextfunction << 10) | (s->nextprecision << 8) | s->filter;
-
- case 0x01: /* Status / Keypad Control */
- if ((s->model & 0xff00) == 0x2100)
- return (s->pin_func << 14) | ((!s->enabled) << 13) |
- (s->host_mode << 12) | ((!!s->dav) << 11) | s->dav;
- else
- return (s->kb.intr << 15) | ((s->kb.scan || !s->kb.down) << 14) |
- (s->kb.debounce << 11);
-
- case 0x02: /* DAC Control */
- if ((s->model & 0xff00) == 0x2300)
- return s->dac_power & 0x8000;
- else
- goto bad_reg;
-
- case 0x03: /* Reference */
- return s->ref;
-
- case 0x04: /* Reset */
- return 0xffff;
-
- case 0x05: /* Configuration */
- return s->timing;
-
- case 0x06: /* Secondary configuration */
- if ((s->model & 0xff00) == 0x2100)
- goto bad_reg;
- return ((!s->dav) << 15) | ((s->kb.mode & 1) << 14) | s->pll[2];
-
- case 0x10: /* Keypad Mask */
- if ((s->model & 0xff00) == 0x2100)
- goto bad_reg;
- return s->kb.mask;
-
- default:
- bad_reg:
-#ifdef TSC_VERBOSE
- fprintf(stderr, "tsc2102_control_register_read: "
- "no such register: 0x%02x\n", reg);
-#endif
- return 0xffff;
- }
-}
-
-static uint16_t tsc2102_audio_register_read(TSC210xState *s, int reg)
-{
- int l_ch, r_ch;
- uint16_t val;
-
- switch (reg) {
- case 0x00: /* Audio Control 1 */
- return s->audio_ctrl1;
-
- case 0x01:
- return 0xff00;
-
- case 0x02: /* DAC Volume Control */
- return s->volume;
-
- case 0x03:
- return 0x8b00;
-
- case 0x04: /* Audio Control 2 */
- l_ch = 1;
- r_ch = 1;
- if (s->softstep && !(s->dac_power & (1 << 10))) {
- l_ch = (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) >
- s->volume_change + TSC_SOFTSTEP_DELAY);
- r_ch = (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) >
- s->volume_change + TSC_SOFTSTEP_DELAY);
- }
-
- return s->audio_ctrl2 | (l_ch << 3) | (r_ch << 2);
-
- case 0x05: /* Stereo DAC Power Control */
- return 0x2aa0 | s->dac_power |
- (((s->dac_power & (1 << 10)) &&
- (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) >
- s->powerdown + TSC_POWEROFF_DELAY)) << 6);
-
- case 0x06: /* Audio Control 3 */
- val = s->audio_ctrl3 | 0x0001;
- s->audio_ctrl3 &= 0xff3f;
- return val;
-
- case 0x07: /* LCH_BASS_BOOST_N0 */
- case 0x08: /* LCH_BASS_BOOST_N1 */
- case 0x09: /* LCH_BASS_BOOST_N2 */
- case 0x0a: /* LCH_BASS_BOOST_N3 */
- case 0x0b: /* LCH_BASS_BOOST_N4 */
- case 0x0c: /* LCH_BASS_BOOST_N5 */
- case 0x0d: /* LCH_BASS_BOOST_D1 */
- case 0x0e: /* LCH_BASS_BOOST_D2 */
- case 0x0f: /* LCH_BASS_BOOST_D4 */
- case 0x10: /* LCH_BASS_BOOST_D5 */
- case 0x11: /* RCH_BASS_BOOST_N0 */
- case 0x12: /* RCH_BASS_BOOST_N1 */
- case 0x13: /* RCH_BASS_BOOST_N2 */
- case 0x14: /* RCH_BASS_BOOST_N3 */
- case 0x15: /* RCH_BASS_BOOST_N4 */
- case 0x16: /* RCH_BASS_BOOST_N5 */
- case 0x17: /* RCH_BASS_BOOST_D1 */
- case 0x18: /* RCH_BASS_BOOST_D2 */
- case 0x19: /* RCH_BASS_BOOST_D4 */
- case 0x1a: /* RCH_BASS_BOOST_D5 */
- return s->filter_data[reg - 0x07];
-
- case 0x1b: /* PLL Programmability 1 */
- return s->pll[0];
-
- case 0x1c: /* PLL Programmability 2 */
- return s->pll[1];
-
- case 0x1d: /* Audio Control 4 */
- return (!s->softstep) << 14;
-
- default:
-#ifdef TSC_VERBOSE
- fprintf(stderr, "tsc2102_audio_register_read: "
- "no such register: 0x%02x\n", reg);
-#endif
- return 0xffff;
- }
-}
-
-static void tsc2102_data_register_write(
- TSC210xState *s, int reg, uint16_t value)
-{
- switch (reg) {
- case 0x00: /* X */
- case 0x01: /* Y */
- case 0x02: /* Z1 */
- case 0x03: /* Z2 */
- case 0x05: /* BAT1 */
- case 0x06: /* BAT2 */
- case 0x07: /* AUX1 */
- case 0x08: /* AUX2 */
- case 0x09: /* TEMP1 */
- case 0x0a: /* TEMP2 */
- return;
-
- default:
-#ifdef TSC_VERBOSE
- fprintf(stderr, "tsc2102_data_register_write: "
- "no such register: 0x%02x\n", reg);
-#endif
- }
-}
-
-static void tsc2102_control_register_write(
- TSC210xState *s, int reg, uint16_t value)
-{
- switch (reg) {
- case 0x00: /* TSC ADC */
- s->host_mode = value >> 15;
- s->enabled = !(value & 0x4000);
- if (s->busy && !s->enabled)
- timer_del(s->timer);
- s->busy &= s->enabled;
- s->nextfunction = (value >> 10) & 0xf;
- s->nextprecision = (value >> 8) & 3;
- s->filter = value & 0xff;
- return;
-
- case 0x01: /* Status / Keypad Control */
- if ((s->model & 0xff00) == 0x2100)
- s->pin_func = value >> 14;
- else {
- s->kb.scan = (value >> 14) & 1;
- s->kb.debounce = (value >> 11) & 7;
- if (s->kb.intr && s->kb.scan) {
- s->kb.intr = 0;
- qemu_irq_raise(s->kbint);
- }
- }
- return;
-
- case 0x02: /* DAC Control */
- if ((s->model & 0xff00) == 0x2300) {
- s->dac_power &= 0x7fff;
- s->dac_power |= 0x8000 & value;
- } else
- goto bad_reg;
- break;
-
- case 0x03: /* Reference */
- s->ref = value & 0x1f;
- return;
-
- case 0x04: /* Reset */
- if (value == 0xbb00) {
- if (s->busy)
- timer_del(s->timer);
- tsc210x_reset(s);
-#ifdef TSC_VERBOSE
- } else {
- fprintf(stderr, "tsc2102_control_register_write: "
- "wrong value written into RESET\n");
-#endif
- }
- return;
-
- case 0x05: /* Configuration */
- s->timing = value & 0x3f;
-#ifdef TSC_VERBOSE
- if (value & ~0x3f)
- fprintf(stderr, "tsc2102_control_register_write: "
- "wrong value written into CONFIG\n");
-#endif
- return;
-
- case 0x06: /* Secondary configuration */
- if ((s->model & 0xff00) == 0x2100)
- goto bad_reg;
- s->kb.mode = value >> 14;
- s->pll[2] = value & 0x3ffff;
- return;
-
- case 0x10: /* Keypad Mask */
- if ((s->model & 0xff00) == 0x2100)
- goto bad_reg;
- s->kb.mask = value;
- return;
-
- default:
- bad_reg:
-#ifdef TSC_VERBOSE
- fprintf(stderr, "tsc2102_control_register_write: "
- "no such register: 0x%02x\n", reg);
-#endif
- }
-}
-
-static void tsc2102_audio_register_write(
- TSC210xState *s, int reg, uint16_t value)
-{
- switch (reg) {
- case 0x00: /* Audio Control 1 */
- s->audio_ctrl1 = value & 0x0f3f;
-#ifdef TSC_VERBOSE
- if ((value & ~0x0f3f) || ((value & 7) != ((value >> 3) & 7)))
- fprintf(stderr, "tsc2102_audio_register_write: "
- "wrong value written into Audio 1\n");
-#endif
- tsc2102_audio_rate_update(s);
- tsc2102_audio_output_update(s);
- return;
-
- case 0x01:
-#ifdef TSC_VERBOSE
- if (value != 0xff00)
- fprintf(stderr, "tsc2102_audio_register_write: "
- "wrong value written into reg 0x01\n");
-#endif
- return;
-
- case 0x02: /* DAC Volume Control */
- s->volume = value;
- s->volume_change = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- return;
-
- case 0x03:
-#ifdef TSC_VERBOSE
- if (value != 0x8b00)
- fprintf(stderr, "tsc2102_audio_register_write: "
- "wrong value written into reg 0x03\n");
-#endif
- return;
-
- case 0x04: /* Audio Control 2 */
- s->audio_ctrl2 = value & 0xf7f2;
-#ifdef TSC_VERBOSE
- if (value & ~0xf7fd)
- fprintf(stderr, "tsc2102_audio_register_write: "
- "wrong value written into Audio 2\n");
-#endif
- return;
-
- case 0x05: /* Stereo DAC Power Control */
- if ((value & ~s->dac_power) & (1 << 10))
- s->powerdown = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-
- s->dac_power = value & 0x9543;
-#ifdef TSC_VERBOSE
- if ((value & ~0x9543) != 0x2aa0)
- fprintf(stderr, "tsc2102_audio_register_write: "
- "wrong value written into Power\n");
-#endif
- tsc2102_audio_rate_update(s);
- tsc2102_audio_output_update(s);
- return;
-
- case 0x06: /* Audio Control 3 */
- s->audio_ctrl3 &= 0x00c0;
- s->audio_ctrl3 |= value & 0xf800;
-#ifdef TSC_VERBOSE
- if (value & ~0xf8c7)
- fprintf(stderr, "tsc2102_audio_register_write: "
- "wrong value written into Audio 3\n");
-#endif
- tsc2102_audio_output_update(s);
- return;
-
- case 0x07: /* LCH_BASS_BOOST_N0 */
- case 0x08: /* LCH_BASS_BOOST_N1 */
- case 0x09: /* LCH_BASS_BOOST_N2 */
- case 0x0a: /* LCH_BASS_BOOST_N3 */
- case 0x0b: /* LCH_BASS_BOOST_N4 */
- case 0x0c: /* LCH_BASS_BOOST_N5 */
- case 0x0d: /* LCH_BASS_BOOST_D1 */
- case 0x0e: /* LCH_BASS_BOOST_D2 */
- case 0x0f: /* LCH_BASS_BOOST_D4 */
- case 0x10: /* LCH_BASS_BOOST_D5 */
- case 0x11: /* RCH_BASS_BOOST_N0 */
- case 0x12: /* RCH_BASS_BOOST_N1 */
- case 0x13: /* RCH_BASS_BOOST_N2 */
- case 0x14: /* RCH_BASS_BOOST_N3 */
- case 0x15: /* RCH_BASS_BOOST_N4 */
- case 0x16: /* RCH_BASS_BOOST_N5 */
- case 0x17: /* RCH_BASS_BOOST_D1 */
- case 0x18: /* RCH_BASS_BOOST_D2 */
- case 0x19: /* RCH_BASS_BOOST_D4 */
- case 0x1a: /* RCH_BASS_BOOST_D5 */
- s->filter_data[reg - 0x07] = value;
- return;
-
- case 0x1b: /* PLL Programmability 1 */
- s->pll[0] = value & 0xfffc;
-#ifdef TSC_VERBOSE
- if (value & ~0xfffc)
- fprintf(stderr, "tsc2102_audio_register_write: "
- "wrong value written into PLL 1\n");
-#endif
- return;
-
- case 0x1c: /* PLL Programmability 2 */
- s->pll[1] = value & 0xfffc;
-#ifdef TSC_VERBOSE
- if (value & ~0xfffc)
- fprintf(stderr, "tsc2102_audio_register_write: "
- "wrong value written into PLL 2\n");
-#endif
- return;
-
- case 0x1d: /* Audio Control 4 */
- s->softstep = !(value & 0x4000);
-#ifdef TSC_VERBOSE
- if (value & ~0x4000)
- fprintf(stderr, "tsc2102_audio_register_write: "
- "wrong value written into Audio 4\n");
-#endif
- return;
-
- default:
-#ifdef TSC_VERBOSE
- fprintf(stderr, "tsc2102_audio_register_write: "
- "no such register: 0x%02x\n", reg);
-#endif
- }
-}
-
-/* This handles most of the chip logic. */
-static void tsc210x_pin_update(TSC210xState *s)
-{
- int64_t expires;
- int pin_state;
-
- switch (s->pin_func) {
- case 0:
- pin_state = s->pressure;
- break;
- case 1:
- pin_state = !!s->dav;
- break;
- case 2:
- default:
- pin_state = s->pressure && !s->dav;
- }
-
- if (!s->enabled)
- pin_state = 0;
-
- if (pin_state != s->irq) {
- s->irq = pin_state;
- qemu_set_irq(s->pint, !s->irq);
- }
-
- switch (s->nextfunction) {
- case TSC_MODE_XY_SCAN:
- case TSC_MODE_XYZ_SCAN:
- if (!s->pressure)
- return;
- break;
-
- case TSC_MODE_X:
- case TSC_MODE_Y:
- case TSC_MODE_Z:
- if (!s->pressure)
- return;
- /* Fall through */
- case TSC_MODE_BAT1:
- case TSC_MODE_BAT2:
- case TSC_MODE_AUX:
- case TSC_MODE_TEMP1:
- case TSC_MODE_TEMP2:
- if (s->dav)
- s->enabled = 0;
- break;
-
- case TSC_MODE_AUX_SCAN:
- case TSC_MODE_PORT_SCAN:
- break;
-
- case TSC_MODE_NO_SCAN:
- case TSC_MODE_XX_DRV:
- case TSC_MODE_YY_DRV:
- case TSC_MODE_YX_DRV:
- default:
- return;
- }
-
- if (!s->enabled || s->busy || s->dav)
- return;
-
- s->busy = 1;
- s->precision = s->nextprecision;
- s->function = s->nextfunction;
- expires = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- (NANOSECONDS_PER_SECOND >> 10);
- timer_mod(s->timer, expires);
-}
-
-static uint16_t tsc210x_read(TSC210xState *s)
-{
- uint16_t ret = 0x0000;
-
- if (!s->command)
- fprintf(stderr, "tsc210x_read: SPI underrun!\n");
-
- switch (s->page) {
- case TSC_DATA_REGISTERS_PAGE:
- ret = tsc2102_data_register_read(s, s->offset);
- if (!s->dav)
- qemu_irq_raise(s->davint);
- break;
- case TSC_CONTROL_REGISTERS_PAGE:
- ret = tsc2102_control_register_read(s, s->offset);
- break;
- case TSC_AUDIO_REGISTERS_PAGE:
- ret = tsc2102_audio_register_read(s, s->offset);
- break;
- default:
- hw_error("tsc210x_read: wrong memory page\n");
- }
-
- tsc210x_pin_update(s);
-
- /* Allow sequential reads. */
- s->offset ++;
- s->state = 0;
- return ret;
-}
-
-static void tsc210x_write(TSC210xState *s, uint16_t value)
-{
- /*
- * This is a two-state state machine for reading
- * command and data every second time.
- */
- if (!s->state) {
- s->command = value >> 15;
- s->page = (value >> 11) & 0x0f;
- s->offset = (value >> 5) & 0x3f;
- s->state = 1;
- } else {
- if (s->command)
- fprintf(stderr, "tsc210x_write: SPI overrun!\n");
- else
- switch (s->page) {
- case TSC_DATA_REGISTERS_PAGE:
- tsc2102_data_register_write(s, s->offset, value);
- break;
- case TSC_CONTROL_REGISTERS_PAGE:
- tsc2102_control_register_write(s, s->offset, value);
- break;
- case TSC_AUDIO_REGISTERS_PAGE:
- tsc2102_audio_register_write(s, s->offset, value);
- break;
- default:
- hw_error("tsc210x_write: wrong memory page\n");
- }
-
- tsc210x_pin_update(s);
- s->state = 0;
- }
-}
-
-uint32_t tsc210x_txrx(void *opaque, uint32_t value, int len)
-{
- TSC210xState *s = opaque;
- uint32_t ret = 0;
-
- if (len != 16)
- hw_error("%s: FIXME: bad SPI word width %i\n", __FUNCTION__, len);
-
- /* TODO: sequential reads etc - how do we make sure the host doesn't
- * unintentionally read out a conversion result from a register while
- * transmitting the command word of the next command? */
- if (!value || (s->state && s->command))
- ret = tsc210x_read(s);
- if (value || (s->state && !s->command))
- tsc210x_write(s, value);
-
- return ret;
-}
-
-static void tsc210x_timer_tick(void *opaque)
-{
- TSC210xState *s = opaque;
-
- /* Timer ticked -- a set of conversions has been finished. */
-
- if (!s->busy)
- return;
-
- s->busy = 0;
- s->dav |= mode_regs[s->function];
- tsc210x_pin_update(s);
- qemu_irq_lower(s->davint);
-}
-
-static void tsc210x_touchscreen_event(void *opaque,
- int x, int y, int z, int buttons_state)
-{
- TSC210xState *s = opaque;
- int p = s->pressure;
-
- if (buttons_state) {
- s->x = x;
- s->y = y;
- }
- s->pressure = !!buttons_state;
-
- /*
- * Note: We would get better responsiveness in the guest by
- * signaling TS events immediately, but for now we simulate
- * the first conversion delay for sake of correctness.
- */
- if (p != s->pressure)
- tsc210x_pin_update(s);
-}
-
-static void tsc210x_i2s_swallow(TSC210xState *s)
-{
- if (s->dac_voice[0])
- tsc210x_out_flush(s, s->codec.out.len);
- else
- s->codec.out.len = 0;
-}
-
-static void tsc210x_i2s_set_rate(TSC210xState *s, int in, int out)
-{
- s->i2s_tx_rate = out;
- s->i2s_rx_rate = in;
-}
-
-static void tsc210x_save(QEMUFile *f, void *opaque)
-{
- TSC210xState *s = (TSC210xState *) opaque;
- int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- int i;
-
- qemu_put_be16(f, s->x);
- qemu_put_be16(f, s->y);
- qemu_put_byte(f, s->pressure);
-
- qemu_put_byte(f, s->state);
- qemu_put_byte(f, s->page);
- qemu_put_byte(f, s->offset);
- qemu_put_byte(f, s->command);
-
- qemu_put_byte(f, s->irq);
- qemu_put_be16s(f, &s->dav);
-
- timer_put(f, s->timer);
- qemu_put_byte(f, s->enabled);
- qemu_put_byte(f, s->host_mode);
- qemu_put_byte(f, s->function);
- qemu_put_byte(f, s->nextfunction);
- qemu_put_byte(f, s->precision);
- qemu_put_byte(f, s->nextprecision);
- qemu_put_byte(f, s->filter);
- qemu_put_byte(f, s->pin_func);
- qemu_put_byte(f, s->ref);
- qemu_put_byte(f, s->timing);
- qemu_put_be32(f, s->noise);
-
- qemu_put_be16s(f, &s->audio_ctrl1);
- qemu_put_be16s(f, &s->audio_ctrl2);
- qemu_put_be16s(f, &s->audio_ctrl3);
- qemu_put_be16s(f, &s->pll[0]);
- qemu_put_be16s(f, &s->pll[1]);
- qemu_put_be16s(f, &s->volume);
- qemu_put_sbe64(f, (s->volume_change - now));
- qemu_put_sbe64(f, (s->powerdown - now));
- qemu_put_byte(f, s->softstep);
- qemu_put_be16s(f, &s->dac_power);
-
- for (i = 0; i < 0x14; i ++)
- qemu_put_be16s(f, &s->filter_data[i]);
-}
-
-static int tsc210x_load(QEMUFile *f, void *opaque, int version_id)
-{
- TSC210xState *s = (TSC210xState *) opaque;
- int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- int i;
-
- s->x = qemu_get_be16(f);
- s->y = qemu_get_be16(f);
- s->pressure = qemu_get_byte(f);
-
- s->state = qemu_get_byte(f);
- s->page = qemu_get_byte(f);
- s->offset = qemu_get_byte(f);
- s->command = qemu_get_byte(f);
-
- s->irq = qemu_get_byte(f);
- qemu_get_be16s(f, &s->dav);
-
- timer_get(f, s->timer);
- s->enabled = qemu_get_byte(f);
- s->host_mode = qemu_get_byte(f);
- s->function = qemu_get_byte(f);
- if (s->function < 0 || s->function >= ARRAY_SIZE(mode_regs)) {
- return -EINVAL;
- }
- s->nextfunction = qemu_get_byte(f);
- if (s->nextfunction < 0 || s->nextfunction >= ARRAY_SIZE(mode_regs)) {
- return -EINVAL;
- }
- s->precision = qemu_get_byte(f);
- if (s->precision < 0 || s->precision >= ARRAY_SIZE(resolution)) {
- return -EINVAL;
- }
- s->nextprecision = qemu_get_byte(f);
- if (s->nextprecision < 0 || s->nextprecision >= ARRAY_SIZE(resolution)) {
- return -EINVAL;
- }
- s->filter = qemu_get_byte(f);
- s->pin_func = qemu_get_byte(f);
- s->ref = qemu_get_byte(f);
- s->timing = qemu_get_byte(f);
- s->noise = qemu_get_be32(f);
-
- qemu_get_be16s(f, &s->audio_ctrl1);
- qemu_get_be16s(f, &s->audio_ctrl2);
- qemu_get_be16s(f, &s->audio_ctrl3);
- qemu_get_be16s(f, &s->pll[0]);
- qemu_get_be16s(f, &s->pll[1]);
- qemu_get_be16s(f, &s->volume);
- s->volume_change = qemu_get_sbe64(f) + now;
- s->powerdown = qemu_get_sbe64(f) + now;
- s->softstep = qemu_get_byte(f);
- qemu_get_be16s(f, &s->dac_power);
-
- for (i = 0; i < 0x14; i ++)
- qemu_get_be16s(f, &s->filter_data[i]);
-
- s->busy = timer_pending(s->timer);
- qemu_set_irq(s->pint, !s->irq);
- qemu_set_irq(s->davint, !s->dav);
-
- return 0;
-}
-
-uWireSlave *tsc2102_init(qemu_irq pint)
-{
- TSC210xState *s;
-
- s = g_new0(TSC210xState, 1);
- s->x = 160;
- s->y = 160;
- s->pressure = 0;
- s->precision = s->nextprecision = 0;
- s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tsc210x_timer_tick, s);
- s->pint = pint;
- s->model = 0x2102;
- s->name = "tsc2102";
-
- s->tr[0] = 0;
- s->tr[1] = 1;
- s->tr[2] = 1;
- s->tr[3] = 0;
- s->tr[4] = 1;
- s->tr[5] = 0;
- s->tr[6] = 1;
- s->tr[7] = 0;
-
- s->chip.opaque = s;
- s->chip.send = (void *) tsc210x_write;
- s->chip.receive = (void *) tsc210x_read;
-
- s->codec.opaque = s;
- s->codec.tx_swallow = (void *) tsc210x_i2s_swallow;
- s->codec.set_rate = (void *) tsc210x_i2s_set_rate;
- s->codec.in.fifo = s->in_fifo;
- s->codec.out.fifo = s->out_fifo;
-
- tsc210x_reset(s);
-
- qemu_add_mouse_event_handler(tsc210x_touchscreen_event, s, 1,
- "QEMU TSC2102-driven Touchscreen");
-
- AUD_register_card(s->name, &s->card);
-
- qemu_register_reset((void *) tsc210x_reset, s);
- register_savevm(NULL, s->name, -1, 0,
- tsc210x_save, tsc210x_load, s);
-
- return &s->chip;
-}
-
-uWireSlave *tsc2301_init(qemu_irq penirq, qemu_irq kbirq, qemu_irq dav)
-{
- TSC210xState *s;
-
- s = g_new0(TSC210xState, 1);
- s->x = 400;
- s->y = 240;
- s->pressure = 0;
- s->precision = s->nextprecision = 0;
- s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tsc210x_timer_tick, s);
- s->pint = penirq;
- s->kbint = kbirq;
- s->davint = dav;
- s->model = 0x2301;
- s->name = "tsc2301";
-
- s->tr[0] = 0;
- s->tr[1] = 1;
- s->tr[2] = 1;
- s->tr[3] = 0;
- s->tr[4] = 1;
- s->tr[5] = 0;
- s->tr[6] = 1;
- s->tr[7] = 0;
-
- s->chip.opaque = s;
- s->chip.send = (void *) tsc210x_write;
- s->chip.receive = (void *) tsc210x_read;
-
- s->codec.opaque = s;
- s->codec.tx_swallow = (void *) tsc210x_i2s_swallow;
- s->codec.set_rate = (void *) tsc210x_i2s_set_rate;
- s->codec.in.fifo = s->in_fifo;
- s->codec.out.fifo = s->out_fifo;
-
- tsc210x_reset(s);
-
- qemu_add_mouse_event_handler(tsc210x_touchscreen_event, s, 1,
- "QEMU TSC2301-driven Touchscreen");
-
- AUD_register_card(s->name, &s->card);
-
- qemu_register_reset((void *) tsc210x_reset, s);
- register_savevm(NULL, s->name, -1, 0, tsc210x_save, tsc210x_load, s);
-
- return &s->chip;
-}
-
-I2SCodec *tsc210x_codec(uWireSlave *chip)
-{
- TSC210xState *s = (TSC210xState *) chip->opaque;
-
- return &s->codec;
-}
-
-/*
- * Use tslib generated calibration data to generate ADC input values
- * from the touchscreen. Assuming 12-bit precision was used during
- * tslib calibration.
- */
-void tsc210x_set_transform(uWireSlave *chip,
- MouseTransformInfo *info)
-{
- TSC210xState *s = (TSC210xState *) chip->opaque;
-#if 0
- int64_t ltr[8];
-
- ltr[0] = (int64_t) info->a[1] * info->y;
- ltr[1] = (int64_t) info->a[4] * info->x;
- ltr[2] = (int64_t) info->a[1] * info->a[3] -
- (int64_t) info->a[4] * info->a[0];
- ltr[3] = (int64_t) info->a[2] * info->a[4] -
- (int64_t) info->a[5] * info->a[1];
- ltr[4] = (int64_t) info->a[0] * info->y;
- ltr[5] = (int64_t) info->a[3] * info->x;
- ltr[6] = (int64_t) info->a[4] * info->a[0] -
- (int64_t) info->a[1] * info->a[3];
- ltr[7] = (int64_t) info->a[2] * info->a[3] -
- (int64_t) info->a[5] * info->a[0];
-
- /* Avoid integer overflow */
- s->tr[0] = ltr[0] >> 11;
- s->tr[1] = ltr[1] >> 11;
- s->tr[2] = muldiv64(ltr[2], 1, info->a[6]);
- s->tr[3] = muldiv64(ltr[3], 1 << 4, ltr[2]);
- s->tr[4] = ltr[4] >> 11;
- s->tr[5] = ltr[5] >> 11;
- s->tr[6] = muldiv64(ltr[6], 1, info->a[6]);
- s->tr[7] = muldiv64(ltr[7], 1 << 4, ltr[6]);
-#else
-
- /* This version assumes touchscreen X & Y axis are parallel or
- * perpendicular to LCD's X & Y axis in some way. */
- if (abs(info->a[0]) > abs(info->a[1])) {
- s->tr[0] = 0;
- s->tr[1] = -info->a[6] * info->x;
- s->tr[2] = info->a[0];
- s->tr[3] = -info->a[2] / info->a[0];
- s->tr[4] = info->a[6] * info->y;
- s->tr[5] = 0;
- s->tr[6] = info->a[4];
- s->tr[7] = -info->a[5] / info->a[4];
- } else {
- s->tr[0] = info->a[6] * info->y;
- s->tr[1] = 0;
- s->tr[2] = info->a[1];
- s->tr[3] = -info->a[2] / info->a[1];
- s->tr[4] = 0;
- s->tr[5] = -info->a[6] * info->x;
- s->tr[6] = info->a[3];
- s->tr[7] = -info->a[5] / info->a[3];
- }
-
- s->tr[0] >>= 11;
- s->tr[1] >>= 11;
- s->tr[3] <<= 4;
- s->tr[4] >>= 11;
- s->tr[5] >>= 11;
- s->tr[7] <<= 4;
-#endif
-}
-
-void tsc210x_key_event(uWireSlave *chip, int key, int down)
-{
- TSC210xState *s = (TSC210xState *) chip->opaque;
-
- if (down)
- s->kb.down |= 1 << key;
- else
- s->kb.down &= ~(1 << key);
-
- if (down && (s->kb.down & ~s->kb.mask) && !s->kb.intr) {
- s->kb.intr = 1;
- qemu_irq_lower(s->kbint);
- } else if (s->kb.intr && !(s->kb.down & ~s->kb.mask) &&
- !(s->kb.mode & 1)) {
- s->kb.intr = 0;
- qemu_irq_raise(s->kbint);
- }
-}
diff --git a/qemu/hw/input/virtio-input-hid.c b/qemu/hw/input/virtio-input-hid.c
deleted file mode 100644
index 3ee0c1814..000000000
--- a/qemu/hw/input/virtio-input-hid.c
+++ /dev/null
@@ -1,525 +0,0 @@
-/*
- * This work is licensed under the terms of the GNU GPL, version 2 or
- * (at your option) any later version. See the COPYING file in the
- * top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "qemu/iov.h"
-
-#include "hw/qdev.h"
-#include "hw/virtio/virtio.h"
-#include "hw/virtio/virtio-input.h"
-
-#undef CONFIG_CURSES
-#include "ui/console.h"
-
-#include "standard-headers/linux/input.h"
-
-#define VIRTIO_ID_NAME_KEYBOARD "QEMU Virtio Keyboard"
-#define VIRTIO_ID_NAME_MOUSE "QEMU Virtio Mouse"
-#define VIRTIO_ID_NAME_TABLET "QEMU Virtio Tablet"
-
-/* ----------------------------------------------------------------- */
-
-static const unsigned int keymap_qcode[Q_KEY_CODE__MAX] = {
- [Q_KEY_CODE_ESC] = KEY_ESC,
- [Q_KEY_CODE_1] = KEY_1,
- [Q_KEY_CODE_2] = KEY_2,
- [Q_KEY_CODE_3] = KEY_3,
- [Q_KEY_CODE_4] = KEY_4,
- [Q_KEY_CODE_5] = KEY_5,
- [Q_KEY_CODE_6] = KEY_6,
- [Q_KEY_CODE_7] = KEY_7,
- [Q_KEY_CODE_8] = KEY_8,
- [Q_KEY_CODE_9] = KEY_9,
- [Q_KEY_CODE_0] = KEY_0,
- [Q_KEY_CODE_MINUS] = KEY_MINUS,
- [Q_KEY_CODE_EQUAL] = KEY_EQUAL,
- [Q_KEY_CODE_BACKSPACE] = KEY_BACKSPACE,
-
- [Q_KEY_CODE_TAB] = KEY_TAB,
- [Q_KEY_CODE_Q] = KEY_Q,
- [Q_KEY_CODE_W] = KEY_W,
- [Q_KEY_CODE_E] = KEY_E,
- [Q_KEY_CODE_R] = KEY_R,
- [Q_KEY_CODE_T] = KEY_T,
- [Q_KEY_CODE_Y] = KEY_Y,
- [Q_KEY_CODE_U] = KEY_U,
- [Q_KEY_CODE_I] = KEY_I,
- [Q_KEY_CODE_O] = KEY_O,
- [Q_KEY_CODE_P] = KEY_P,
- [Q_KEY_CODE_BRACKET_LEFT] = KEY_LEFTBRACE,
- [Q_KEY_CODE_BRACKET_RIGHT] = KEY_RIGHTBRACE,
- [Q_KEY_CODE_RET] = KEY_ENTER,
-
- [Q_KEY_CODE_CTRL] = KEY_LEFTCTRL,
- [Q_KEY_CODE_A] = KEY_A,
- [Q_KEY_CODE_S] = KEY_S,
- [Q_KEY_CODE_D] = KEY_D,
- [Q_KEY_CODE_F] = KEY_F,
- [Q_KEY_CODE_G] = KEY_G,
- [Q_KEY_CODE_H] = KEY_H,
- [Q_KEY_CODE_J] = KEY_J,
- [Q_KEY_CODE_K] = KEY_K,
- [Q_KEY_CODE_L] = KEY_L,
- [Q_KEY_CODE_SEMICOLON] = KEY_SEMICOLON,
- [Q_KEY_CODE_APOSTROPHE] = KEY_APOSTROPHE,
- [Q_KEY_CODE_GRAVE_ACCENT] = KEY_GRAVE,
-
- [Q_KEY_CODE_SHIFT] = KEY_LEFTSHIFT,
- [Q_KEY_CODE_BACKSLASH] = KEY_BACKSLASH,
- [Q_KEY_CODE_LESS] = KEY_102ND,
- [Q_KEY_CODE_Z] = KEY_Z,
- [Q_KEY_CODE_X] = KEY_X,
- [Q_KEY_CODE_C] = KEY_C,
- [Q_KEY_CODE_V] = KEY_V,
- [Q_KEY_CODE_B] = KEY_B,
- [Q_KEY_CODE_N] = KEY_N,
- [Q_KEY_CODE_M] = KEY_M,
- [Q_KEY_CODE_COMMA] = KEY_COMMA,
- [Q_KEY_CODE_DOT] = KEY_DOT,
- [Q_KEY_CODE_SLASH] = KEY_SLASH,
- [Q_KEY_CODE_SHIFT_R] = KEY_RIGHTSHIFT,
-
- [Q_KEY_CODE_ALT] = KEY_LEFTALT,
- [Q_KEY_CODE_SPC] = KEY_SPACE,
- [Q_KEY_CODE_CAPS_LOCK] = KEY_CAPSLOCK,
-
- [Q_KEY_CODE_F1] = KEY_F1,
- [Q_KEY_CODE_F2] = KEY_F2,
- [Q_KEY_CODE_F3] = KEY_F3,
- [Q_KEY_CODE_F4] = KEY_F4,
- [Q_KEY_CODE_F5] = KEY_F5,
- [Q_KEY_CODE_F6] = KEY_F6,
- [Q_KEY_CODE_F7] = KEY_F7,
- [Q_KEY_CODE_F8] = KEY_F8,
- [Q_KEY_CODE_F9] = KEY_F9,
- [Q_KEY_CODE_F10] = KEY_F10,
- [Q_KEY_CODE_NUM_LOCK] = KEY_NUMLOCK,
- [Q_KEY_CODE_SCROLL_LOCK] = KEY_SCROLLLOCK,
-
- [Q_KEY_CODE_KP_0] = KEY_KP0,
- [Q_KEY_CODE_KP_1] = KEY_KP1,
- [Q_KEY_CODE_KP_2] = KEY_KP2,
- [Q_KEY_CODE_KP_3] = KEY_KP3,
- [Q_KEY_CODE_KP_4] = KEY_KP4,
- [Q_KEY_CODE_KP_5] = KEY_KP5,
- [Q_KEY_CODE_KP_6] = KEY_KP6,
- [Q_KEY_CODE_KP_7] = KEY_KP7,
- [Q_KEY_CODE_KP_8] = KEY_KP8,
- [Q_KEY_CODE_KP_9] = KEY_KP9,
- [Q_KEY_CODE_KP_SUBTRACT] = KEY_KPMINUS,
- [Q_KEY_CODE_KP_ADD] = KEY_KPPLUS,
- [Q_KEY_CODE_KP_DECIMAL] = KEY_KPDOT,
- [Q_KEY_CODE_KP_ENTER] = KEY_KPENTER,
- [Q_KEY_CODE_KP_DIVIDE] = KEY_KPSLASH,
- [Q_KEY_CODE_KP_MULTIPLY] = KEY_KPASTERISK,
-
- [Q_KEY_CODE_F11] = KEY_F11,
- [Q_KEY_CODE_F12] = KEY_F12,
-
- [Q_KEY_CODE_CTRL_R] = KEY_RIGHTCTRL,
- [Q_KEY_CODE_SYSRQ] = KEY_SYSRQ,
- [Q_KEY_CODE_PRINT] = KEY_SYSRQ,
- [Q_KEY_CODE_PAUSE] = KEY_PAUSE,
- [Q_KEY_CODE_ALT_R] = KEY_RIGHTALT,
-
- [Q_KEY_CODE_HOME] = KEY_HOME,
- [Q_KEY_CODE_UP] = KEY_UP,
- [Q_KEY_CODE_PGUP] = KEY_PAGEUP,
- [Q_KEY_CODE_LEFT] = KEY_LEFT,
- [Q_KEY_CODE_RIGHT] = KEY_RIGHT,
- [Q_KEY_CODE_END] = KEY_END,
- [Q_KEY_CODE_DOWN] = KEY_DOWN,
- [Q_KEY_CODE_PGDN] = KEY_PAGEDOWN,
- [Q_KEY_CODE_INSERT] = KEY_INSERT,
- [Q_KEY_CODE_DELETE] = KEY_DELETE,
-
- [Q_KEY_CODE_META_L] = KEY_LEFTMETA,
- [Q_KEY_CODE_META_R] = KEY_RIGHTMETA,
- [Q_KEY_CODE_MENU] = KEY_MENU,
-};
-
-static const unsigned int keymap_button[INPUT_BUTTON__MAX] = {
- [INPUT_BUTTON_LEFT] = BTN_LEFT,
- [INPUT_BUTTON_RIGHT] = BTN_RIGHT,
- [INPUT_BUTTON_MIDDLE] = BTN_MIDDLE,
- [INPUT_BUTTON_WHEEL_UP] = BTN_GEAR_UP,
- [INPUT_BUTTON_WHEEL_DOWN] = BTN_GEAR_DOWN,
-};
-
-static const unsigned int axismap_rel[INPUT_AXIS__MAX] = {
- [INPUT_AXIS_X] = REL_X,
- [INPUT_AXIS_Y] = REL_Y,
-};
-
-static const unsigned int axismap_abs[INPUT_AXIS__MAX] = {
- [INPUT_AXIS_X] = ABS_X,
- [INPUT_AXIS_Y] = ABS_Y,
-};
-
-/* ----------------------------------------------------------------- */
-
-static void virtio_input_key_config(VirtIOInput *vinput,
- const unsigned int *keymap,
- size_t mapsize)
-{
- virtio_input_config keys;
- int i, bit, byte, bmax = 0;
-
- memset(&keys, 0, sizeof(keys));
- for (i = 0; i < mapsize; i++) {
- bit = keymap[i];
- if (!bit) {
- continue;
- }
- byte = bit / 8;
- bit = bit % 8;
- keys.u.bitmap[byte] |= (1 << bit);
- if (bmax < byte+1) {
- bmax = byte+1;
- }
- }
- keys.select = VIRTIO_INPUT_CFG_EV_BITS;
- keys.subsel = EV_KEY;
- keys.size = bmax;
- virtio_input_add_config(vinput, &keys);
-}
-
-static void virtio_input_handle_event(DeviceState *dev, QemuConsole *src,
- InputEvent *evt)
-{
- VirtIOInput *vinput = VIRTIO_INPUT(dev);
- virtio_input_event event;
- int qcode;
- InputKeyEvent *key;
- InputMoveEvent *move;
- InputBtnEvent *btn;
-
- switch (evt->type) {
- case INPUT_EVENT_KIND_KEY:
- key = evt->u.key.data;
- qcode = qemu_input_key_value_to_qcode(key->key);
- if (qcode && keymap_qcode[qcode]) {
- event.type = cpu_to_le16(EV_KEY);
- event.code = cpu_to_le16(keymap_qcode[qcode]);
- event.value = cpu_to_le32(key->down ? 1 : 0);
- virtio_input_send(vinput, &event);
- } else {
- if (key->down) {
- fprintf(stderr, "%s: unmapped key: %d [%s]\n", __func__,
- qcode, QKeyCode_lookup[qcode]);
- }
- }
- break;
- case INPUT_EVENT_KIND_BTN:
- btn = evt->u.btn.data;
- if (keymap_button[btn->button]) {
- event.type = cpu_to_le16(EV_KEY);
- event.code = cpu_to_le16(keymap_button[btn->button]);
- event.value = cpu_to_le32(btn->down ? 1 : 0);
- virtio_input_send(vinput, &event);
- } else {
- if (btn->down) {
- fprintf(stderr, "%s: unmapped button: %d [%s]\n", __func__,
- btn->button,
- InputButton_lookup[btn->button]);
- }
- }
- break;
- case INPUT_EVENT_KIND_REL:
- move = evt->u.rel.data;
- event.type = cpu_to_le16(EV_REL);
- event.code = cpu_to_le16(axismap_rel[move->axis]);
- event.value = cpu_to_le32(move->value);
- virtio_input_send(vinput, &event);
- break;
- case INPUT_EVENT_KIND_ABS:
- move = evt->u.abs.data;
- event.type = cpu_to_le16(EV_ABS);
- event.code = cpu_to_le16(axismap_abs[move->axis]);
- event.value = cpu_to_le32(move->value);
- virtio_input_send(vinput, &event);
- break;
- default:
- /* keep gcc happy */
- break;
- }
-}
-
-static void virtio_input_handle_sync(DeviceState *dev)
-{
- VirtIOInput *vinput = VIRTIO_INPUT(dev);
- virtio_input_event event = {
- .type = cpu_to_le16(EV_SYN),
- .code = cpu_to_le16(SYN_REPORT),
- .value = 0,
- };
-
- virtio_input_send(vinput, &event);
-}
-
-static void virtio_input_hid_realize(DeviceState *dev, Error **errp)
-{
- VirtIOInputHID *vhid = VIRTIO_INPUT_HID(dev);
-
- vhid->hs = qemu_input_handler_register(dev, vhid->handler);
- if (vhid->display && vhid->hs) {
- qemu_input_handler_bind(vhid->hs, vhid->display, vhid->head, NULL);
- }
-}
-
-static void virtio_input_hid_unrealize(DeviceState *dev, Error **errp)
-{
- VirtIOInputHID *vhid = VIRTIO_INPUT_HID(dev);
- qemu_input_handler_unregister(vhid->hs);
-}
-
-static void virtio_input_hid_change_active(VirtIOInput *vinput)
-{
- VirtIOInputHID *vhid = VIRTIO_INPUT_HID(vinput);
-
- if (vinput->active) {
- qemu_input_handler_activate(vhid->hs);
- } else {
- qemu_input_handler_deactivate(vhid->hs);
- }
-}
-
-static void virtio_input_hid_handle_status(VirtIOInput *vinput,
- virtio_input_event *event)
-{
- VirtIOInputHID *vhid = VIRTIO_INPUT_HID(vinput);
- int ledbit = 0;
-
- switch (le16_to_cpu(event->type)) {
- case EV_LED:
- if (event->code == LED_NUML) {
- ledbit = QEMU_NUM_LOCK_LED;
- } else if (event->code == LED_CAPSL) {
- ledbit = QEMU_CAPS_LOCK_LED;
- } else if (event->code == LED_SCROLLL) {
- ledbit = QEMU_SCROLL_LOCK_LED;
- }
- if (event->value) {
- vhid->ledstate |= ledbit;
- } else {
- vhid->ledstate &= ~ledbit;
- }
- kbd_put_ledstate(vhid->ledstate);
- break;
- default:
- fprintf(stderr, "%s: unknown type %d\n", __func__,
- le16_to_cpu(event->type));
- break;
- }
-}
-
-static Property virtio_input_hid_properties[] = {
- DEFINE_PROP_STRING("display", VirtIOInputHID, display),
- DEFINE_PROP_UINT32("head", VirtIOInputHID, head, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_input_hid_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtIOInputClass *vic = VIRTIO_INPUT_CLASS(klass);
-
- dc->props = virtio_input_hid_properties;
- vic->realize = virtio_input_hid_realize;
- vic->unrealize = virtio_input_hid_unrealize;
- vic->change_active = virtio_input_hid_change_active;
- vic->handle_status = virtio_input_hid_handle_status;
-}
-
-static const TypeInfo virtio_input_hid_info = {
- .name = TYPE_VIRTIO_INPUT_HID,
- .parent = TYPE_VIRTIO_INPUT,
- .instance_size = sizeof(VirtIOInputHID),
- .class_init = virtio_input_hid_class_init,
- .abstract = true,
-};
-
-/* ----------------------------------------------------------------- */
-
-static QemuInputHandler virtio_keyboard_handler = {
- .name = VIRTIO_ID_NAME_KEYBOARD,
- .mask = INPUT_EVENT_MASK_KEY,
- .event = virtio_input_handle_event,
- .sync = virtio_input_handle_sync,
-};
-
-static struct virtio_input_config virtio_keyboard_config[] = {
- {
- .select = VIRTIO_INPUT_CFG_ID_NAME,
- .size = sizeof(VIRTIO_ID_NAME_KEYBOARD),
- .u.string = VIRTIO_ID_NAME_KEYBOARD,
- },{
- .select = VIRTIO_INPUT_CFG_ID_DEVIDS,
- .size = sizeof(struct virtio_input_devids),
- .u.ids = {
- .bustype = const_le16(BUS_VIRTUAL),
- .vendor = const_le16(0x0627), /* same we use for usb hid devices */
- .product = const_le16(0x0001),
- .version = const_le16(0x0001),
- },
- },{
- .select = VIRTIO_INPUT_CFG_EV_BITS,
- .subsel = EV_REP,
- .size = 1,
- },{
- .select = VIRTIO_INPUT_CFG_EV_BITS,
- .subsel = EV_LED,
- .size = 1,
- .u.bitmap = {
- (1 << LED_NUML) | (1 << LED_CAPSL) | (1 << LED_SCROLLL),
- },
- },
- { /* end of list */ },
-};
-
-static void virtio_keyboard_init(Object *obj)
-{
- VirtIOInputHID *vhid = VIRTIO_INPUT_HID(obj);
- VirtIOInput *vinput = VIRTIO_INPUT(obj);
-
- vhid->handler = &virtio_keyboard_handler;
- virtio_input_init_config(vinput, virtio_keyboard_config);
- virtio_input_key_config(vinput, keymap_qcode,
- ARRAY_SIZE(keymap_qcode));
-}
-
-static const TypeInfo virtio_keyboard_info = {
- .name = TYPE_VIRTIO_KEYBOARD,
- .parent = TYPE_VIRTIO_INPUT_HID,
- .instance_size = sizeof(VirtIOInputHID),
- .instance_init = virtio_keyboard_init,
-};
-
-/* ----------------------------------------------------------------- */
-
-static QemuInputHandler virtio_mouse_handler = {
- .name = VIRTIO_ID_NAME_MOUSE,
- .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
- .event = virtio_input_handle_event,
- .sync = virtio_input_handle_sync,
-};
-
-static struct virtio_input_config virtio_mouse_config[] = {
- {
- .select = VIRTIO_INPUT_CFG_ID_NAME,
- .size = sizeof(VIRTIO_ID_NAME_MOUSE),
- .u.string = VIRTIO_ID_NAME_MOUSE,
- },{
- .select = VIRTIO_INPUT_CFG_ID_DEVIDS,
- .size = sizeof(struct virtio_input_devids),
- .u.ids = {
- .bustype = const_le16(BUS_VIRTUAL),
- .vendor = const_le16(0x0627), /* same we use for usb hid devices */
- .product = const_le16(0x0002),
- .version = const_le16(0x0001),
- },
- },{
- .select = VIRTIO_INPUT_CFG_EV_BITS,
- .subsel = EV_REL,
- .size = 1,
- .u.bitmap = {
- (1 << REL_X) | (1 << REL_Y),
- },
- },
- { /* end of list */ },
-};
-
-static void virtio_mouse_init(Object *obj)
-{
- VirtIOInputHID *vhid = VIRTIO_INPUT_HID(obj);
- VirtIOInput *vinput = VIRTIO_INPUT(obj);
-
- vhid->handler = &virtio_mouse_handler;
- virtio_input_init_config(vinput, virtio_mouse_config);
- virtio_input_key_config(vinput, keymap_button,
- ARRAY_SIZE(keymap_button));
-}
-
-static const TypeInfo virtio_mouse_info = {
- .name = TYPE_VIRTIO_MOUSE,
- .parent = TYPE_VIRTIO_INPUT_HID,
- .instance_size = sizeof(VirtIOInputHID),
- .instance_init = virtio_mouse_init,
-};
-
-/* ----------------------------------------------------------------- */
-
-static QemuInputHandler virtio_tablet_handler = {
- .name = VIRTIO_ID_NAME_TABLET,
- .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS,
- .event = virtio_input_handle_event,
- .sync = virtio_input_handle_sync,
-};
-
-static struct virtio_input_config virtio_tablet_config[] = {
- {
- .select = VIRTIO_INPUT_CFG_ID_NAME,
- .size = sizeof(VIRTIO_ID_NAME_TABLET),
- .u.string = VIRTIO_ID_NAME_TABLET,
- },{
- .select = VIRTIO_INPUT_CFG_ID_DEVIDS,
- .size = sizeof(struct virtio_input_devids),
- .u.ids = {
- .bustype = const_le16(BUS_VIRTUAL),
- .vendor = const_le16(0x0627), /* same we use for usb hid devices */
- .product = const_le16(0x0003),
- .version = const_le16(0x0001),
- },
- },{
- .select = VIRTIO_INPUT_CFG_EV_BITS,
- .subsel = EV_ABS,
- .size = 1,
- .u.bitmap = {
- (1 << ABS_X) | (1 << ABS_Y),
- },
- },{
- .select = VIRTIO_INPUT_CFG_ABS_INFO,
- .subsel = ABS_X,
- .size = sizeof(virtio_input_absinfo),
- .u.abs.max = const_le32(INPUT_EVENT_ABS_SIZE - 1),
- },{
- .select = VIRTIO_INPUT_CFG_ABS_INFO,
- .subsel = ABS_Y,
- .size = sizeof(virtio_input_absinfo),
- .u.abs.max = const_le32(INPUT_EVENT_ABS_SIZE - 1),
- },
- { /* end of list */ },
-};
-
-static void virtio_tablet_init(Object *obj)
-{
- VirtIOInputHID *vhid = VIRTIO_INPUT_HID(obj);
- VirtIOInput *vinput = VIRTIO_INPUT(obj);
-
- vhid->handler = &virtio_tablet_handler;
- virtio_input_init_config(vinput, virtio_tablet_config);
- virtio_input_key_config(vinput, keymap_button,
- ARRAY_SIZE(keymap_button));
-}
-
-static const TypeInfo virtio_tablet_info = {
- .name = TYPE_VIRTIO_TABLET,
- .parent = TYPE_VIRTIO_INPUT_HID,
- .instance_size = sizeof(VirtIOInputHID),
- .instance_init = virtio_tablet_init,
-};
-
-/* ----------------------------------------------------------------- */
-
-static void virtio_register_types(void)
-{
- type_register_static(&virtio_input_hid_info);
- type_register_static(&virtio_keyboard_info);
- type_register_static(&virtio_mouse_info);
- type_register_static(&virtio_tablet_info);
-}
-
-type_init(virtio_register_types)
diff --git a/qemu/hw/input/virtio-input-host.c b/qemu/hw/input/virtio-input-host.c
deleted file mode 100644
index cb79e8002..000000000
--- a/qemu/hw/input/virtio-input-host.c
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * This work is licensed under the terms of the GNU GPL, version 2 or
- * (at your option) any later version. See the COPYING file in the
- * top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "qemu/sockets.h"
-
-#include "hw/qdev.h"
-#include "hw/virtio/virtio.h"
-#include "hw/virtio/virtio-input.h"
-
-#include <sys/ioctl.h>
-#include "standard-headers/linux/input.h"
-
-/* ----------------------------------------------------------------- */
-
-static struct virtio_input_config virtio_input_host_config[] = {
- { /* empty list */ },
-};
-
-static void virtio_input_host_event(void *opaque)
-{
- VirtIOInputHost *vih = opaque;
- VirtIOInput *vinput = VIRTIO_INPUT(vih);
- struct virtio_input_event virtio;
- struct input_event evdev;
- int rc;
-
- for (;;) {
- rc = read(vih->fd, &evdev, sizeof(evdev));
- if (rc != sizeof(evdev)) {
- break;
- }
-
- virtio.type = cpu_to_le16(evdev.type);
- virtio.code = cpu_to_le16(evdev.code);
- virtio.value = cpu_to_le32(evdev.value);
- virtio_input_send(vinput, &virtio);
- }
-}
-
-static void virtio_input_bits_config(VirtIOInputHost *vih,
- int type, int count)
-{
- virtio_input_config bits;
- int rc, i, size = 0;
-
- memset(&bits, 0, sizeof(bits));
- rc = ioctl(vih->fd, EVIOCGBIT(type, count/8), bits.u.bitmap);
- if (rc < 0) {
- return;
- }
-
- for (i = 0; i < count/8; i++) {
- if (bits.u.bitmap[i]) {
- size = i+1;
- }
- }
- if (size == 0) {
- return;
- }
-
- bits.select = VIRTIO_INPUT_CFG_EV_BITS;
- bits.subsel = type;
- bits.size = size;
- virtio_input_add_config(VIRTIO_INPUT(vih), &bits);
-}
-
-static void virtio_input_abs_config(VirtIOInputHost *vih, int axis)
-{
- virtio_input_config config;
- struct input_absinfo absinfo;
- int rc;
-
- rc = ioctl(vih->fd, EVIOCGABS(axis), &absinfo);
- if (rc < 0) {
- return;
- }
-
- memset(&config, 0, sizeof(config));
- config.select = VIRTIO_INPUT_CFG_ABS_INFO;
- config.subsel = axis;
- config.size = sizeof(virtio_input_absinfo);
-
- config.u.abs.min = cpu_to_le32(absinfo.minimum);
- config.u.abs.max = cpu_to_le32(absinfo.maximum);
- config.u.abs.fuzz = cpu_to_le32(absinfo.fuzz);
- config.u.abs.flat = cpu_to_le32(absinfo.flat);
- config.u.abs.res = cpu_to_le32(absinfo.resolution);
-
- virtio_input_add_config(VIRTIO_INPUT(vih), &config);
-}
-
-static void virtio_input_host_realize(DeviceState *dev, Error **errp)
-{
- VirtIOInputHost *vih = VIRTIO_INPUT_HOST(dev);
- VirtIOInput *vinput = VIRTIO_INPUT(dev);
- virtio_input_config id, *abs;
- struct input_id ids;
- int rc, ver, i, axis;
- uint8_t byte;
-
- if (!vih->evdev) {
- error_setg(errp, "evdev property is required");
- return;
- }
-
- vih->fd = open(vih->evdev, O_RDWR);
- if (vih->fd < 0) {
- error_setg_file_open(errp, errno, vih->evdev);
- return;
- }
- qemu_set_nonblock(vih->fd);
-
- rc = ioctl(vih->fd, EVIOCGVERSION, &ver);
- if (rc < 0) {
- error_setg(errp, "%s: is not an evdev device", vih->evdev);
- goto err_close;
- }
-
- rc = ioctl(vih->fd, EVIOCGRAB, 1);
- if (rc < 0) {
- error_setg_errno(errp, errno, "%s: failed to get exclusive access",
- vih->evdev);
- goto err_close;
- }
-
- memset(&id, 0, sizeof(id));
- ioctl(vih->fd, EVIOCGNAME(sizeof(id.u.string)-1), id.u.string);
- id.select = VIRTIO_INPUT_CFG_ID_NAME;
- id.size = strlen(id.u.string);
- virtio_input_add_config(vinput, &id);
-
- if (ioctl(vih->fd, EVIOCGID, &ids) == 0) {
- memset(&id, 0, sizeof(id));
- id.select = VIRTIO_INPUT_CFG_ID_DEVIDS;
- id.size = sizeof(struct virtio_input_devids);
- id.u.ids.bustype = cpu_to_le16(ids.bustype);
- id.u.ids.vendor = cpu_to_le16(ids.vendor);
- id.u.ids.product = cpu_to_le16(ids.product);
- id.u.ids.version = cpu_to_le16(ids.version);
- virtio_input_add_config(vinput, &id);
- }
-
- virtio_input_bits_config(vih, EV_KEY, KEY_CNT);
- virtio_input_bits_config(vih, EV_REL, REL_CNT);
- virtio_input_bits_config(vih, EV_ABS, ABS_CNT);
- virtio_input_bits_config(vih, EV_MSC, MSC_CNT);
- virtio_input_bits_config(vih, EV_SW, SW_CNT);
- virtio_input_bits_config(vih, EV_LED, LED_CNT);
-
- abs = virtio_input_find_config(VIRTIO_INPUT(vih),
- VIRTIO_INPUT_CFG_EV_BITS, EV_ABS);
- if (abs) {
- for (i = 0; i < abs->size; i++) {
- byte = abs->u.bitmap[i];
- axis = 8 * i;
- while (byte) {
- if (byte & 1) {
- virtio_input_abs_config(vih, axis);
- }
- axis++;
- byte >>= 1;
- }
- }
- }
-
- qemu_set_fd_handler(vih->fd, virtio_input_host_event, NULL, vih);
- return;
-
-err_close:
- close(vih->fd);
- vih->fd = -1;
- return;
-}
-
-static void virtio_input_host_unrealize(DeviceState *dev, Error **errp)
-{
- VirtIOInputHost *vih = VIRTIO_INPUT_HOST(dev);
-
- if (vih->fd > 0) {
- qemu_set_fd_handler(vih->fd, NULL, NULL, NULL);
- close(vih->fd);
- }
-}
-
-static void virtio_input_host_handle_status(VirtIOInput *vinput,
- virtio_input_event *event)
-{
- VirtIOInputHost *vih = VIRTIO_INPUT_HOST(vinput);
- struct input_event evdev;
- int rc;
-
- if (gettimeofday(&evdev.time, NULL)) {
- perror("virtio_input_host_handle_status: gettimeofday");
- return;
- }
-
- evdev.type = le16_to_cpu(event->type);
- evdev.code = le16_to_cpu(event->code);
- evdev.value = le32_to_cpu(event->value);
-
- rc = write(vih->fd, &evdev, sizeof(evdev));
- if (rc == -1) {
- perror("virtio_input_host_handle_status: write");
- }
-}
-
-static const VMStateDescription vmstate_virtio_input_host = {
- .name = "virtio-input-host",
- .unmigratable = 1,
-};
-
-static Property virtio_input_host_properties[] = {
- DEFINE_PROP_STRING("evdev", VirtIOInputHost, evdev),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_input_host_class_init(ObjectClass *klass, void *data)
-{
- VirtIOInputClass *vic = VIRTIO_INPUT_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->vmsd = &vmstate_virtio_input_host;
- dc->props = virtio_input_host_properties;
- vic->realize = virtio_input_host_realize;
- vic->unrealize = virtio_input_host_unrealize;
- vic->handle_status = virtio_input_host_handle_status;
-}
-
-static void virtio_input_host_init(Object *obj)
-{
- VirtIOInput *vinput = VIRTIO_INPUT(obj);
-
- virtio_input_init_config(vinput, virtio_input_host_config);
-}
-
-static const TypeInfo virtio_input_host_info = {
- .name = TYPE_VIRTIO_INPUT_HOST,
- .parent = TYPE_VIRTIO_INPUT,
- .instance_size = sizeof(VirtIOInputHost),
- .instance_init = virtio_input_host_init,
- .class_init = virtio_input_host_class_init,
-};
-
-/* ----------------------------------------------------------------- */
-
-static void virtio_register_types(void)
-{
- type_register_static(&virtio_input_host_info);
-}
-
-type_init(virtio_register_types)
diff --git a/qemu/hw/input/virtio-input.c b/qemu/hw/input/virtio-input.c
deleted file mode 100644
index f59749a94..000000000
--- a/qemu/hw/input/virtio-input.c
+++ /dev/null
@@ -1,343 +0,0 @@
-/*
- * This work is licensed under the terms of the GNU GPL, version 2 or
- * (at your option) any later version. See the COPYING file in the
- * top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu/iov.h"
-
-#include "hw/qdev.h"
-#include "hw/virtio/virtio.h"
-#include "hw/virtio/virtio-input.h"
-
-#include "standard-headers/linux/input.h"
-
-#define VIRTIO_INPUT_VM_VERSION 1
-
-/* ----------------------------------------------------------------- */
-
-void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event)
-{
- VirtQueueElement *elem;
- unsigned have, need;
- int i, len;
-
- if (!vinput->active) {
- return;
- }
-
- /* queue up events ... */
- if (vinput->qindex == vinput->qsize) {
- vinput->qsize++;
- vinput->queue = realloc(vinput->queue, vinput->qsize *
- sizeof(virtio_input_event));
- }
- vinput->queue[vinput->qindex++] = *event;
-
- /* ... until we see a report sync ... */
- if (event->type != cpu_to_le16(EV_SYN) ||
- event->code != cpu_to_le16(SYN_REPORT)) {
- return;
- }
-
- /* ... then check available space ... */
- need = sizeof(virtio_input_event) * vinput->qindex;
- virtqueue_get_avail_bytes(vinput->evt, &have, NULL, need, 0);
- if (have < need) {
- vinput->qindex = 0;
- fprintf(stderr, "%s: ENOSPC in vq, dropping events\n", __func__);
- return;
- }
-
- /* ... and finally pass them to the guest */
- for (i = 0; i < vinput->qindex; i++) {
- elem = virtqueue_pop(vinput->evt, sizeof(VirtQueueElement));
- if (!elem) {
- /* should not happen, we've checked for space beforehand */
- fprintf(stderr, "%s: Huh? No vq elem available ...\n", __func__);
- return;
- }
- len = iov_from_buf(elem->in_sg, elem->in_num,
- 0, vinput->queue+i, sizeof(virtio_input_event));
- virtqueue_push(vinput->evt, elem, len);
- g_free(elem);
- }
- virtio_notify(VIRTIO_DEVICE(vinput), vinput->evt);
- vinput->qindex = 0;
-}
-
-static void virtio_input_handle_evt(VirtIODevice *vdev, VirtQueue *vq)
-{
- /* nothing */
-}
-
-static void virtio_input_handle_sts(VirtIODevice *vdev, VirtQueue *vq)
-{
- VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(vdev);
- VirtIOInput *vinput = VIRTIO_INPUT(vdev);
- virtio_input_event event;
- VirtQueueElement *elem;
- int len;
-
- for (;;) {
- elem = virtqueue_pop(vinput->sts, sizeof(VirtQueueElement));
- if (!elem) {
- break;
- }
-
- memset(&event, 0, sizeof(event));
- len = iov_to_buf(elem->out_sg, elem->out_num,
- 0, &event, sizeof(event));
- if (vic->handle_status) {
- vic->handle_status(vinput, &event);
- }
- virtqueue_push(vinput->sts, elem, len);
- g_free(elem);
- }
- virtio_notify(vdev, vinput->sts);
-}
-
-virtio_input_config *virtio_input_find_config(VirtIOInput *vinput,
- uint8_t select,
- uint8_t subsel)
-{
- VirtIOInputConfig *cfg;
-
- QTAILQ_FOREACH(cfg, &vinput->cfg_list, node) {
- if (select == cfg->config.select &&
- subsel == cfg->config.subsel) {
- return &cfg->config;
- }
- }
- return NULL;
-}
-
-void virtio_input_add_config(VirtIOInput *vinput,
- virtio_input_config *config)
-{
- VirtIOInputConfig *cfg;
-
- if (virtio_input_find_config(vinput, config->select, config->subsel)) {
- /* should not happen */
- fprintf(stderr, "%s: duplicate config: %d/%d\n",
- __func__, config->select, config->subsel);
- abort();
- }
-
- cfg = g_new0(VirtIOInputConfig, 1);
- cfg->config = *config;
- QTAILQ_INSERT_TAIL(&vinput->cfg_list, cfg, node);
-}
-
-void virtio_input_init_config(VirtIOInput *vinput,
- virtio_input_config *config)
-{
- int i = 0;
-
- QTAILQ_INIT(&vinput->cfg_list);
- while (config[i].select) {
- virtio_input_add_config(vinput, config + i);
- i++;
- }
-}
-
-void virtio_input_idstr_config(VirtIOInput *vinput,
- uint8_t select, const char *string)
-{
- virtio_input_config id;
-
- if (!string) {
- return;
- }
- memset(&id, 0, sizeof(id));
- id.select = select;
- id.size = snprintf(id.u.string, sizeof(id.u.string), "%s", string);
- virtio_input_add_config(vinput, &id);
-}
-
-static void virtio_input_get_config(VirtIODevice *vdev, uint8_t *config_data)
-{
- VirtIOInput *vinput = VIRTIO_INPUT(vdev);
- virtio_input_config *config;
-
- config = virtio_input_find_config(vinput, vinput->cfg_select,
- vinput->cfg_subsel);
- if (config) {
- memcpy(config_data, config, vinput->cfg_size);
- } else {
- memset(config_data, 0, vinput->cfg_size);
- }
-}
-
-static void virtio_input_set_config(VirtIODevice *vdev,
- const uint8_t *config_data)
-{
- VirtIOInput *vinput = VIRTIO_INPUT(vdev);
- virtio_input_config *config = (virtio_input_config *)config_data;
-
- vinput->cfg_select = config->select;
- vinput->cfg_subsel = config->subsel;
- virtio_notify_config(vdev);
-}
-
-static uint64_t virtio_input_get_features(VirtIODevice *vdev, uint64_t f,
- Error **errp)
-{
- return f;
-}
-
-static void virtio_input_set_status(VirtIODevice *vdev, uint8_t val)
-{
- VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(vdev);
- VirtIOInput *vinput = VIRTIO_INPUT(vdev);
-
- if (val & VIRTIO_CONFIG_S_DRIVER_OK) {
- if (!vinput->active) {
- vinput->active = true;
- if (vic->change_active) {
- vic->change_active(vinput);
- }
- }
- }
-}
-
-static void virtio_input_reset(VirtIODevice *vdev)
-{
- VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(vdev);
- VirtIOInput *vinput = VIRTIO_INPUT(vdev);
-
- if (vinput->active) {
- vinput->active = false;
- if (vic->change_active) {
- vic->change_active(vinput);
- }
- }
-}
-
-static void virtio_input_save(QEMUFile *f, void *opaque)
-{
- VirtIOInput *vinput = opaque;
- VirtIODevice *vdev = VIRTIO_DEVICE(vinput);
-
- virtio_save(vdev, f);
-}
-
-static int virtio_input_load(QEMUFile *f, void *opaque, int version_id)
-{
- VirtIOInput *vinput = opaque;
- VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(vinput);
- VirtIODevice *vdev = VIRTIO_DEVICE(vinput);
- int ret;
-
- if (version_id != VIRTIO_INPUT_VM_VERSION) {
- return -EINVAL;
- }
-
- ret = virtio_load(vdev, f, version_id);
- if (ret) {
- return ret;
- }
-
- /* post_load() */
- vinput->active = vdev->status & VIRTIO_CONFIG_S_DRIVER_OK;
- if (vic->change_active) {
- vic->change_active(vinput);
- }
- return 0;
-}
-
-static void virtio_input_device_realize(DeviceState *dev, Error **errp)
-{
- VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(dev);
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
- VirtIOInput *vinput = VIRTIO_INPUT(dev);
- VirtIOInputConfig *cfg;
- Error *local_err = NULL;
-
- if (vic->realize) {
- vic->realize(dev, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
- }
-
- virtio_input_idstr_config(vinput, VIRTIO_INPUT_CFG_ID_SERIAL,
- vinput->serial);
-
- QTAILQ_FOREACH(cfg, &vinput->cfg_list, node) {
- if (vinput->cfg_size < cfg->config.size) {
- vinput->cfg_size = cfg->config.size;
- }
- }
- vinput->cfg_size += 8;
- assert(vinput->cfg_size <= sizeof(virtio_input_config));
-
- virtio_init(vdev, "virtio-input", VIRTIO_ID_INPUT,
- vinput->cfg_size);
- vinput->evt = virtio_add_queue(vdev, 64, virtio_input_handle_evt);
- vinput->sts = virtio_add_queue(vdev, 64, virtio_input_handle_sts);
-
- register_savevm(dev, "virtio-input", -1, VIRTIO_INPUT_VM_VERSION,
- virtio_input_save, virtio_input_load, vinput);
-}
-
-static void virtio_input_device_unrealize(DeviceState *dev, Error **errp)
-{
- VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(dev);
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
- VirtIOInput *vinput = VIRTIO_INPUT(dev);
- Error *local_err = NULL;
-
- unregister_savevm(dev, "virtio-input", vinput);
-
- if (vic->unrealize) {
- vic->unrealize(dev, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
- }
- virtio_cleanup(vdev);
-}
-
-static Property virtio_input_properties[] = {
- DEFINE_PROP_STRING("serial", VirtIOInput, serial),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_input_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
-
- dc->props = virtio_input_properties;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
- vdc->realize = virtio_input_device_realize;
- vdc->unrealize = virtio_input_device_unrealize;
- vdc->get_config = virtio_input_get_config;
- vdc->set_config = virtio_input_set_config;
- vdc->get_features = virtio_input_get_features;
- vdc->set_status = virtio_input_set_status;
- vdc->reset = virtio_input_reset;
-}
-
-static const TypeInfo virtio_input_info = {
- .name = TYPE_VIRTIO_INPUT,
- .parent = TYPE_VIRTIO_DEVICE,
- .instance_size = sizeof(VirtIOInput),
- .class_size = sizeof(VirtIOInputClass),
- .class_init = virtio_input_class_init,
- .abstract = true,
-};
-
-/* ----------------------------------------------------------------- */
-
-static void virtio_register_types(void)
-{
- type_register_static(&virtio_input_info);
-}
-
-type_init(virtio_register_types)
diff --git a/qemu/hw/input/vmmouse.c b/qemu/hw/input/vmmouse.c
deleted file mode 100644
index 6d15a887c..000000000
--- a/qemu/hw/input/vmmouse.c
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * QEMU VMMouse emulation
- *
- * Copyright (C) 2007 Anthony Liguori <anthony@codemonkey.ws>
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "ui/console.h"
-#include "hw/input/ps2.h"
-#include "hw/i386/pc.h"
-#include "hw/qdev.h"
-
-/* debug only vmmouse */
-//#define DEBUG_VMMOUSE
-
-/* VMMouse Commands */
-#define VMMOUSE_GETVERSION 10
-#define VMMOUSE_DATA 39
-#define VMMOUSE_STATUS 40
-#define VMMOUSE_COMMAND 41
-
-#define VMMOUSE_READ_ID 0x45414552
-#define VMMOUSE_DISABLE 0x000000f5
-#define VMMOUSE_REQUEST_RELATIVE 0x4c455252
-#define VMMOUSE_REQUEST_ABSOLUTE 0x53424152
-
-#define VMMOUSE_QUEUE_SIZE 1024
-
-#define VMMOUSE_VERSION 0x3442554a
-
-#ifdef DEBUG_VMMOUSE
-#define DPRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
-#else
-#define DPRINTF(fmt, ...) do { } while (0)
-#endif
-
-#define TYPE_VMMOUSE "vmmouse"
-#define VMMOUSE(obj) OBJECT_CHECK(VMMouseState, (obj), TYPE_VMMOUSE)
-
-typedef struct VMMouseState
-{
- ISADevice parent_obj;
-
- uint32_t queue[VMMOUSE_QUEUE_SIZE];
- int32_t queue_size;
- uint16_t nb_queue;
- uint16_t status;
- uint8_t absolute;
- QEMUPutMouseEntry *entry;
- void *ps2_mouse;
-} VMMouseState;
-
-static uint32_t vmmouse_get_status(VMMouseState *s)
-{
- DPRINTF("vmmouse_get_status()\n");
- return (s->status << 16) | s->nb_queue;
-}
-
-static void vmmouse_mouse_event(void *opaque, int x, int y, int dz, int buttons_state)
-{
- VMMouseState *s = opaque;
- int buttons = 0;
-
- if (s->nb_queue > (VMMOUSE_QUEUE_SIZE - 4))
- return;
-
- DPRINTF("vmmouse_mouse_event(%d, %d, %d, %d)\n",
- x, y, dz, buttons_state);
-
- if ((buttons_state & MOUSE_EVENT_LBUTTON))
- buttons |= 0x20;
- if ((buttons_state & MOUSE_EVENT_RBUTTON))
- buttons |= 0x10;
- if ((buttons_state & MOUSE_EVENT_MBUTTON))
- buttons |= 0x08;
-
- if (s->absolute) {
- x <<= 1;
- y <<= 1;
- }
-
- s->queue[s->nb_queue++] = buttons;
- s->queue[s->nb_queue++] = x;
- s->queue[s->nb_queue++] = y;
- s->queue[s->nb_queue++] = dz;
-
- /* need to still generate PS2 events to notify driver to
- read from queue */
- i8042_isa_mouse_fake_event(s->ps2_mouse);
-}
-
-static void vmmouse_remove_handler(VMMouseState *s)
-{
- if (s->entry) {
- qemu_remove_mouse_event_handler(s->entry);
- s->entry = NULL;
- }
-}
-
-static void vmmouse_update_handler(VMMouseState *s, int absolute)
-{
- if (s->status != 0) {
- return;
- }
- if (s->absolute != absolute) {
- s->absolute = absolute;
- vmmouse_remove_handler(s);
- }
- if (s->entry == NULL) {
- s->entry = qemu_add_mouse_event_handler(vmmouse_mouse_event,
- s, s->absolute,
- "vmmouse");
- qemu_activate_mouse_event_handler(s->entry);
- }
-}
-
-static void vmmouse_read_id(VMMouseState *s)
-{
- DPRINTF("vmmouse_read_id()\n");
-
- if (s->nb_queue == VMMOUSE_QUEUE_SIZE)
- return;
-
- s->queue[s->nb_queue++] = VMMOUSE_VERSION;
- s->status = 0;
-}
-
-static void vmmouse_request_relative(VMMouseState *s)
-{
- DPRINTF("vmmouse_request_relative()\n");
- vmmouse_update_handler(s, 0);
-}
-
-static void vmmouse_request_absolute(VMMouseState *s)
-{
- DPRINTF("vmmouse_request_absolute()\n");
- vmmouse_update_handler(s, 1);
-}
-
-static void vmmouse_disable(VMMouseState *s)
-{
- DPRINTF("vmmouse_disable()\n");
- s->status = 0xffff;
- vmmouse_remove_handler(s);
-}
-
-static void vmmouse_data(VMMouseState *s, uint32_t *data, uint32_t size)
-{
- int i;
-
- DPRINTF("vmmouse_data(%d)\n", size);
-
- if (size == 0 || size > 6 || size > s->nb_queue) {
- printf("vmmouse: driver requested too much data %d\n", size);
- s->status = 0xffff;
- vmmouse_remove_handler(s);
- return;
- }
-
- for (i = 0; i < size; i++)
- data[i] = s->queue[i];
-
- s->nb_queue -= size;
- if (s->nb_queue)
- memmove(s->queue, &s->queue[size], sizeof(s->queue[0]) * s->nb_queue);
-}
-
-static uint32_t vmmouse_ioport_read(void *opaque, uint32_t addr)
-{
- VMMouseState *s = opaque;
- uint32_t data[6];
- uint16_t command;
-
- vmmouse_get_data(data);
-
- command = data[2] & 0xFFFF;
-
- switch (command) {
- case VMMOUSE_STATUS:
- data[0] = vmmouse_get_status(s);
- break;
- case VMMOUSE_COMMAND:
- switch (data[1]) {
- case VMMOUSE_DISABLE:
- vmmouse_disable(s);
- break;
- case VMMOUSE_READ_ID:
- vmmouse_read_id(s);
- break;
- case VMMOUSE_REQUEST_RELATIVE:
- vmmouse_request_relative(s);
- break;
- case VMMOUSE_REQUEST_ABSOLUTE:
- vmmouse_request_absolute(s);
- break;
- default:
- printf("vmmouse: unknown command %x\n", data[1]);
- break;
- }
- break;
- case VMMOUSE_DATA:
- vmmouse_data(s, data, data[1]);
- break;
- default:
- printf("vmmouse: unknown command %x\n", command);
- break;
- }
-
- vmmouse_set_data(data);
- return data[0];
-}
-
-static int vmmouse_post_load(void *opaque, int version_id)
-{
- VMMouseState *s = opaque;
-
- vmmouse_remove_handler(s);
- vmmouse_update_handler(s, s->absolute);
- return 0;
-}
-
-static const VMStateDescription vmstate_vmmouse = {
- .name = "vmmouse",
- .version_id = 0,
- .minimum_version_id = 0,
- .post_load = vmmouse_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_INT32_EQUAL(queue_size, VMMouseState),
- VMSTATE_UINT32_ARRAY(queue, VMMouseState, VMMOUSE_QUEUE_SIZE),
- VMSTATE_UINT16(nb_queue, VMMouseState),
- VMSTATE_UINT16(status, VMMouseState),
- VMSTATE_UINT8(absolute, VMMouseState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void vmmouse_reset(DeviceState *d)
-{
- VMMouseState *s = VMMOUSE(d);
-
- s->queue_size = VMMOUSE_QUEUE_SIZE;
-
- vmmouse_disable(s);
-}
-
-static void vmmouse_realizefn(DeviceState *dev, Error **errp)
-{
- VMMouseState *s = VMMOUSE(dev);
-
- DPRINTF("vmmouse_init\n");
-
- vmport_register(VMMOUSE_STATUS, vmmouse_ioport_read, s);
- vmport_register(VMMOUSE_COMMAND, vmmouse_ioport_read, s);
- vmport_register(VMMOUSE_DATA, vmmouse_ioport_read, s);
-}
-
-static Property vmmouse_properties[] = {
- DEFINE_PROP_PTR("ps2_mouse", VMMouseState, ps2_mouse),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void vmmouse_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = vmmouse_realizefn;
- dc->reset = vmmouse_reset;
- dc->vmsd = &vmstate_vmmouse;
- dc->props = vmmouse_properties;
- /* Reason: pointer property "ps2_mouse" */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo vmmouse_info = {
- .name = TYPE_VMMOUSE,
- .parent = TYPE_ISA_DEVICE,
- .instance_size = sizeof(VMMouseState),
- .class_init = vmmouse_class_initfn,
-};
-
-static void vmmouse_register_types(void)
-{
- type_register_static(&vmmouse_info);
-}
-
-type_init(vmmouse_register_types)
diff --git a/qemu/hw/intc/Makefile.objs b/qemu/hw/intc/Makefile.objs
deleted file mode 100644
index 0e47f0f9e..000000000
--- a/qemu/hw/intc/Makefile.objs
+++ /dev/null
@@ -1,34 +0,0 @@
-common-obj-$(CONFIG_HEATHROW_PIC) += heathrow_pic.o
-common-obj-$(CONFIG_I8259) += i8259_common.o i8259.o
-common-obj-$(CONFIG_PL190) += pl190.o
-common-obj-$(CONFIG_PUV3) += puv3_intc.o
-common-obj-$(CONFIG_XILINX) += xilinx_intc.o
-common-obj-$(CONFIG_ETRAXFS) += etraxfs_pic.o
-common-obj-$(CONFIG_IMX) += imx_avic.o
-common-obj-$(CONFIG_LM32) += lm32_pic.o
-common-obj-$(CONFIG_REALVIEW) += realview_gic.o
-common-obj-$(CONFIG_SLAVIO) += slavio_intctl.o
-common-obj-$(CONFIG_IOAPIC) += ioapic_common.o
-common-obj-$(CONFIG_ARM_GIC) += arm_gic_common.o
-common-obj-$(CONFIG_ARM_GIC) += arm_gic.o
-common-obj-$(CONFIG_ARM_GIC) += arm_gicv2m.o
-common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_common.o
-common-obj-$(CONFIG_OPENPIC) += openpic.o
-
-obj-$(CONFIG_APIC) += apic.o apic_common.o
-obj-$(CONFIG_ARM_GIC_KVM) += arm_gic_kvm.o
-obj-$(call land,$(CONFIG_ARM_GIC_KVM),$(TARGET_AARCH64)) += arm_gicv3_kvm.o
-obj-$(CONFIG_STELLARIS) += armv7m_nvic.o
-obj-$(CONFIG_EXYNOS4) += exynos4210_gic.o exynos4210_combiner.o
-obj-$(CONFIG_GRLIB) += grlib_irqmp.o
-obj-$(CONFIG_IOAPIC) += ioapic.o
-obj-$(CONFIG_OMAP) += omap_intc.o
-obj-$(CONFIG_OPENPIC_KVM) += openpic_kvm.o
-obj-$(CONFIG_RASPI) += bcm2835_ic.o bcm2836_control.o
-obj-$(CONFIG_SH4) += sh_intc.o
-obj-$(CONFIG_XICS) += xics.o
-obj-$(CONFIG_XICS_KVM) += xics_kvm.o
-obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o
-obj-$(CONFIG_S390_FLIC) += s390_flic.o
-obj-$(CONFIG_S390_FLIC_KVM) += s390_flic_kvm.o
-obj-$(CONFIG_ASPEED_SOC) += aspeed_vic.o
diff --git a/qemu/hw/intc/allwinner-a10-pic.c b/qemu/hw/intc/allwinner-a10-pic.c
deleted file mode 100644
index dc971a160..000000000
--- a/qemu/hw/intc/allwinner-a10-pic.c
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Allwinner A10 interrupt controller device emulation
- *
- * Copyright (C) 2013 Li Guang
- * Written by Li Guang <lig.fnst@cn.fujitsu.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "hw/devices.h"
-#include "sysemu/sysemu.h"
-#include "hw/intc/allwinner-a10-pic.h"
-
-static void aw_a10_pic_update(AwA10PICState *s)
-{
- uint8_t i;
- int irq = 0, fiq = 0, zeroes;
-
- s->vector = 0;
-
- for (i = 0; i < AW_A10_PIC_REG_NUM; i++) {
- irq |= s->irq_pending[i] & ~s->mask[i];
- fiq |= s->select[i] & s->irq_pending[i] & ~s->mask[i];
-
- if (!s->vector) {
- zeroes = ctz32(s->irq_pending[i] & ~s->mask[i]);
- if (zeroes != 32) {
- s->vector = (i * 32 + zeroes) * 4;
- }
- }
- }
-
- qemu_set_irq(s->parent_irq, !!irq);
- qemu_set_irq(s->parent_fiq, !!fiq);
-}
-
-static void aw_a10_pic_set_irq(void *opaque, int irq, int level)
-{
- AwA10PICState *s = opaque;
-
- if (level) {
- set_bit(irq % 32, (void *)&s->irq_pending[irq / 32]);
- } else {
- clear_bit(irq % 32, (void *)&s->irq_pending[irq / 32]);
- }
- aw_a10_pic_update(s);
-}
-
-static uint64_t aw_a10_pic_read(void *opaque, hwaddr offset, unsigned size)
-{
- AwA10PICState *s = opaque;
- uint8_t index = (offset & 0xc) / 4;
-
- switch (offset) {
- case AW_A10_PIC_VECTOR:
- return s->vector;
- case AW_A10_PIC_BASE_ADDR:
- return s->base_addr;
- case AW_A10_PIC_PROTECT:
- return s->protect;
- case AW_A10_PIC_NMI:
- return s->nmi;
- case AW_A10_PIC_IRQ_PENDING ... AW_A10_PIC_IRQ_PENDING + 8:
- return s->irq_pending[index];
- case AW_A10_PIC_FIQ_PENDING ... AW_A10_PIC_FIQ_PENDING + 8:
- return s->fiq_pending[index];
- case AW_A10_PIC_SELECT ... AW_A10_PIC_SELECT + 8:
- return s->select[index];
- case AW_A10_PIC_ENABLE ... AW_A10_PIC_ENABLE + 8:
- return s->enable[index];
- case AW_A10_PIC_MASK ... AW_A10_PIC_MASK + 8:
- return s->mask[index];
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad offset 0x%x\n", __func__, (int)offset);
- break;
- }
-
- return 0;
-}
-
-static void aw_a10_pic_write(void *opaque, hwaddr offset, uint64_t value,
- unsigned size)
-{
- AwA10PICState *s = opaque;
- uint8_t index = (offset & 0xc) / 4;
-
- switch (offset) {
- case AW_A10_PIC_BASE_ADDR:
- s->base_addr = value & ~0x3;
- break;
- case AW_A10_PIC_PROTECT:
- s->protect = value;
- break;
- case AW_A10_PIC_NMI:
- s->nmi = value;
- break;
- case AW_A10_PIC_IRQ_PENDING ... AW_A10_PIC_IRQ_PENDING + 8:
- /*
- * The register is read-only; nevertheless, Linux (including
- * the version originally shipped by Allwinner) pretends to
- * write to the register. Just ignore it.
- */
- break;
- case AW_A10_PIC_FIQ_PENDING ... AW_A10_PIC_FIQ_PENDING + 8:
- s->fiq_pending[index] &= ~value;
- break;
- case AW_A10_PIC_SELECT ... AW_A10_PIC_SELECT + 8:
- s->select[index] = value;
- break;
- case AW_A10_PIC_ENABLE ... AW_A10_PIC_ENABLE + 8:
- s->enable[index] = value;
- break;
- case AW_A10_PIC_MASK ... AW_A10_PIC_MASK + 8:
- s->mask[index] = value;
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad offset 0x%x\n", __func__, (int)offset);
- break;
- }
-
- aw_a10_pic_update(s);
-}
-
-static const MemoryRegionOps aw_a10_pic_ops = {
- .read = aw_a10_pic_read,
- .write = aw_a10_pic_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_aw_a10_pic = {
- .name = "a10.pic",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(vector, AwA10PICState),
- VMSTATE_UINT32(base_addr, AwA10PICState),
- VMSTATE_UINT32(protect, AwA10PICState),
- VMSTATE_UINT32(nmi, AwA10PICState),
- VMSTATE_UINT32_ARRAY(irq_pending, AwA10PICState, AW_A10_PIC_REG_NUM),
- VMSTATE_UINT32_ARRAY(fiq_pending, AwA10PICState, AW_A10_PIC_REG_NUM),
- VMSTATE_UINT32_ARRAY(enable, AwA10PICState, AW_A10_PIC_REG_NUM),
- VMSTATE_UINT32_ARRAY(select, AwA10PICState, AW_A10_PIC_REG_NUM),
- VMSTATE_UINT32_ARRAY(mask, AwA10PICState, AW_A10_PIC_REG_NUM),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void aw_a10_pic_init(Object *obj)
-{
- AwA10PICState *s = AW_A10_PIC(obj);
- SysBusDevice *dev = SYS_BUS_DEVICE(obj);
-
- qdev_init_gpio_in(DEVICE(dev), aw_a10_pic_set_irq, AW_A10_PIC_INT_NR);
- sysbus_init_irq(dev, &s->parent_irq);
- sysbus_init_irq(dev, &s->parent_fiq);
- memory_region_init_io(&s->iomem, OBJECT(s), &aw_a10_pic_ops, s,
- TYPE_AW_A10_PIC, 0x400);
- sysbus_init_mmio(dev, &s->iomem);
-}
-
-static void aw_a10_pic_reset(DeviceState *d)
-{
- AwA10PICState *s = AW_A10_PIC(d);
- uint8_t i;
-
- s->base_addr = 0;
- s->protect = 0;
- s->nmi = 0;
- s->vector = 0;
- for (i = 0; i < AW_A10_PIC_REG_NUM; i++) {
- s->irq_pending[i] = 0;
- s->fiq_pending[i] = 0;
- s->select[i] = 0;
- s->enable[i] = 0;
- s->mask[i] = 0;
- }
-}
-
-static void aw_a10_pic_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->reset = aw_a10_pic_reset;
- dc->desc = "allwinner a10 pic";
- dc->vmsd = &vmstate_aw_a10_pic;
- }
-
-static const TypeInfo aw_a10_pic_info = {
- .name = TYPE_AW_A10_PIC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(AwA10PICState),
- .instance_init = aw_a10_pic_init,
- .class_init = aw_a10_pic_class_init,
-};
-
-static void aw_a10_register_types(void)
-{
- type_register_static(&aw_a10_pic_info);
-}
-
-type_init(aw_a10_register_types);
diff --git a/qemu/hw/intc/apic.c b/qemu/hw/intc/apic.c
deleted file mode 100644
index 28c2ea540..000000000
--- a/qemu/hw/intc/apic.c
+++ /dev/null
@@ -1,906 +0,0 @@
-/*
- * APIC support
- *
- * Copyright (c) 2004-2005 Fabrice Bellard
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>
- */
-#include "qemu/osdep.h"
-#include "qemu/thread.h"
-#include "hw/i386/apic_internal.h"
-#include "hw/i386/apic.h"
-#include "hw/i386/ioapic.h"
-#include "hw/pci/msi.h"
-#include "qemu/host-utils.h"
-#include "trace.h"
-#include "hw/i386/pc.h"
-#include "hw/i386/apic-msidef.h"
-
-#define MAX_APIC_WORDS 8
-
-#define SYNC_FROM_VAPIC 0x1
-#define SYNC_TO_VAPIC 0x2
-#define SYNC_ISR_IRR_TO_VAPIC 0x4
-
-static APICCommonState *local_apics[MAX_APICS + 1];
-
-static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode);
-static void apic_update_irq(APICCommonState *s);
-static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
- uint8_t dest, uint8_t dest_mode);
-
-/* Find first bit starting from msb */
-static int apic_fls_bit(uint32_t value)
-{
- return 31 - clz32(value);
-}
-
-/* Find first bit starting from lsb */
-static int apic_ffs_bit(uint32_t value)
-{
- return ctz32(value);
-}
-
-static inline void apic_reset_bit(uint32_t *tab, int index)
-{
- int i, mask;
- i = index >> 5;
- mask = 1 << (index & 0x1f);
- tab[i] &= ~mask;
-}
-
-/* return -1 if no bit is set */
-static int get_highest_priority_int(uint32_t *tab)
-{
- int i;
- for (i = 7; i >= 0; i--) {
- if (tab[i] != 0) {
- return i * 32 + apic_fls_bit(tab[i]);
- }
- }
- return -1;
-}
-
-static void apic_sync_vapic(APICCommonState *s, int sync_type)
-{
- VAPICState vapic_state;
- size_t length;
- off_t start;
- int vector;
-
- if (!s->vapic_paddr) {
- return;
- }
- if (sync_type & SYNC_FROM_VAPIC) {
- cpu_physical_memory_read(s->vapic_paddr, &vapic_state,
- sizeof(vapic_state));
- s->tpr = vapic_state.tpr;
- }
- if (sync_type & (SYNC_TO_VAPIC | SYNC_ISR_IRR_TO_VAPIC)) {
- start = offsetof(VAPICState, isr);
- length = offsetof(VAPICState, enabled) - offsetof(VAPICState, isr);
-
- if (sync_type & SYNC_TO_VAPIC) {
- assert(qemu_cpu_is_self(CPU(s->cpu)));
-
- vapic_state.tpr = s->tpr;
- vapic_state.enabled = 1;
- start = 0;
- length = sizeof(VAPICState);
- }
-
- vector = get_highest_priority_int(s->isr);
- if (vector < 0) {
- vector = 0;
- }
- vapic_state.isr = vector & 0xf0;
-
- vapic_state.zero = 0;
-
- vector = get_highest_priority_int(s->irr);
- if (vector < 0) {
- vector = 0;
- }
- vapic_state.irr = vector & 0xff;
-
- cpu_physical_memory_write_rom(&address_space_memory,
- s->vapic_paddr + start,
- ((void *)&vapic_state) + start, length);
- }
-}
-
-static void apic_vapic_base_update(APICCommonState *s)
-{
- apic_sync_vapic(s, SYNC_TO_VAPIC);
-}
-
-static void apic_local_deliver(APICCommonState *s, int vector)
-{
- uint32_t lvt = s->lvt[vector];
- int trigger_mode;
-
- trace_apic_local_deliver(vector, (lvt >> 8) & 7);
-
- if (lvt & APIC_LVT_MASKED)
- return;
-
- switch ((lvt >> 8) & 7) {
- case APIC_DM_SMI:
- cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_SMI);
- break;
-
- case APIC_DM_NMI:
- cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_NMI);
- break;
-
- case APIC_DM_EXTINT:
- cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_HARD);
- break;
-
- case APIC_DM_FIXED:
- trigger_mode = APIC_TRIGGER_EDGE;
- if ((vector == APIC_LVT_LINT0 || vector == APIC_LVT_LINT1) &&
- (lvt & APIC_LVT_LEVEL_TRIGGER))
- trigger_mode = APIC_TRIGGER_LEVEL;
- apic_set_irq(s, lvt & 0xff, trigger_mode);
- }
-}
-
-void apic_deliver_pic_intr(DeviceState *dev, int level)
-{
- APICCommonState *s = APIC_COMMON(dev);
-
- if (level) {
- apic_local_deliver(s, APIC_LVT_LINT0);
- } else {
- uint32_t lvt = s->lvt[APIC_LVT_LINT0];
-
- switch ((lvt >> 8) & 7) {
- case APIC_DM_FIXED:
- if (!(lvt & APIC_LVT_LEVEL_TRIGGER))
- break;
- apic_reset_bit(s->irr, lvt & 0xff);
- /* fall through */
- case APIC_DM_EXTINT:
- apic_update_irq(s);
- break;
- }
- }
-}
-
-static void apic_external_nmi(APICCommonState *s)
-{
- apic_local_deliver(s, APIC_LVT_LINT1);
-}
-
-#define foreach_apic(apic, deliver_bitmask, code) \
-{\
- int __i, __j;\
- for(__i = 0; __i < MAX_APIC_WORDS; __i++) {\
- uint32_t __mask = deliver_bitmask[__i];\
- if (__mask) {\
- for(__j = 0; __j < 32; __j++) {\
- if (__mask & (1U << __j)) {\
- apic = local_apics[__i * 32 + __j];\
- if (apic) {\
- code;\
- }\
- }\
- }\
- }\
- }\
-}
-
-static void apic_bus_deliver(const uint32_t *deliver_bitmask,
- uint8_t delivery_mode, uint8_t vector_num,
- uint8_t trigger_mode)
-{
- APICCommonState *apic_iter;
-
- switch (delivery_mode) {
- case APIC_DM_LOWPRI:
- /* XXX: search for focus processor, arbitration */
- {
- int i, d;
- d = -1;
- for(i = 0; i < MAX_APIC_WORDS; i++) {
- if (deliver_bitmask[i]) {
- d = i * 32 + apic_ffs_bit(deliver_bitmask[i]);
- break;
- }
- }
- if (d >= 0) {
- apic_iter = local_apics[d];
- if (apic_iter) {
- apic_set_irq(apic_iter, vector_num, trigger_mode);
- }
- }
- }
- return;
-
- case APIC_DM_FIXED:
- break;
-
- case APIC_DM_SMI:
- foreach_apic(apic_iter, deliver_bitmask,
- cpu_interrupt(CPU(apic_iter->cpu), CPU_INTERRUPT_SMI)
- );
- return;
-
- case APIC_DM_NMI:
- foreach_apic(apic_iter, deliver_bitmask,
- cpu_interrupt(CPU(apic_iter->cpu), CPU_INTERRUPT_NMI)
- );
- return;
-
- case APIC_DM_INIT:
- /* normal INIT IPI sent to processors */
- foreach_apic(apic_iter, deliver_bitmask,
- cpu_interrupt(CPU(apic_iter->cpu),
- CPU_INTERRUPT_INIT)
- );
- return;
-
- case APIC_DM_EXTINT:
- /* handled in I/O APIC code */
- break;
-
- default:
- return;
- }
-
- foreach_apic(apic_iter, deliver_bitmask,
- apic_set_irq(apic_iter, vector_num, trigger_mode) );
-}
-
-void apic_deliver_irq(uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode,
- uint8_t vector_num, uint8_t trigger_mode)
-{
- uint32_t deliver_bitmask[MAX_APIC_WORDS];
-
- trace_apic_deliver_irq(dest, dest_mode, delivery_mode, vector_num,
- trigger_mode);
-
- apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode);
- apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, trigger_mode);
-}
-
-static void apic_set_base(APICCommonState *s, uint64_t val)
-{
- s->apicbase = (val & 0xfffff000) |
- (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
- /* if disabled, cannot be enabled again */
- if (!(val & MSR_IA32_APICBASE_ENABLE)) {
- s->apicbase &= ~MSR_IA32_APICBASE_ENABLE;
- cpu_clear_apic_feature(&s->cpu->env);
- s->spurious_vec &= ~APIC_SV_ENABLE;
- }
-}
-
-static void apic_set_tpr(APICCommonState *s, uint8_t val)
-{
- /* Updates from cr8 are ignored while the VAPIC is active */
- if (!s->vapic_paddr) {
- s->tpr = val << 4;
- apic_update_irq(s);
- }
-}
-
-static uint8_t apic_get_tpr(APICCommonState *s)
-{
- apic_sync_vapic(s, SYNC_FROM_VAPIC);
- return s->tpr >> 4;
-}
-
-int apic_get_ppr(APICCommonState *s)
-{
- int tpr, isrv, ppr;
-
- tpr = (s->tpr >> 4);
- isrv = get_highest_priority_int(s->isr);
- if (isrv < 0)
- isrv = 0;
- isrv >>= 4;
- if (tpr >= isrv)
- ppr = s->tpr;
- else
- ppr = isrv << 4;
- return ppr;
-}
-
-static int apic_get_arb_pri(APICCommonState *s)
-{
- /* XXX: arbitration */
- return 0;
-}
-
-
-/*
- * <0 - low prio interrupt,
- * 0 - no interrupt,
- * >0 - interrupt number
- */
-static int apic_irq_pending(APICCommonState *s)
-{
- int irrv, ppr;
-
- if (!(s->spurious_vec & APIC_SV_ENABLE)) {
- return 0;
- }
-
- irrv = get_highest_priority_int(s->irr);
- if (irrv < 0) {
- return 0;
- }
- ppr = apic_get_ppr(s);
- if (ppr && (irrv & 0xf0) <= (ppr & 0xf0)) {
- return -1;
- }
-
- return irrv;
-}
-
-/* signal the CPU if an irq is pending */
-static void apic_update_irq(APICCommonState *s)
-{
- CPUState *cpu;
- DeviceState *dev = (DeviceState *)s;
-
- cpu = CPU(s->cpu);
- if (!qemu_cpu_is_self(cpu)) {
- cpu_interrupt(cpu, CPU_INTERRUPT_POLL);
- } else if (apic_irq_pending(s) > 0) {
- cpu_interrupt(cpu, CPU_INTERRUPT_HARD);
- } else if (!apic_accept_pic_intr(dev) || !pic_get_output(isa_pic)) {
- cpu_reset_interrupt(cpu, CPU_INTERRUPT_HARD);
- }
-}
-
-void apic_poll_irq(DeviceState *dev)
-{
- APICCommonState *s = APIC_COMMON(dev);
-
- apic_sync_vapic(s, SYNC_FROM_VAPIC);
- apic_update_irq(s);
-}
-
-static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode)
-{
- apic_report_irq_delivered(!apic_get_bit(s->irr, vector_num));
-
- apic_set_bit(s->irr, vector_num);
- if (trigger_mode)
- apic_set_bit(s->tmr, vector_num);
- else
- apic_reset_bit(s->tmr, vector_num);
- if (s->vapic_paddr) {
- apic_sync_vapic(s, SYNC_ISR_IRR_TO_VAPIC);
- /*
- * The vcpu thread needs to see the new IRR before we pull its current
- * TPR value. That way, if we miss a lowering of the TRP, the guest
- * has the chance to notice the new IRR and poll for IRQs on its own.
- */
- smp_wmb();
- apic_sync_vapic(s, SYNC_FROM_VAPIC);
- }
- apic_update_irq(s);
-}
-
-static void apic_eoi(APICCommonState *s)
-{
- int isrv;
- isrv = get_highest_priority_int(s->isr);
- if (isrv < 0)
- return;
- apic_reset_bit(s->isr, isrv);
- if (!(s->spurious_vec & APIC_SV_DIRECTED_IO) && apic_get_bit(s->tmr, isrv)) {
- ioapic_eoi_broadcast(isrv);
- }
- apic_sync_vapic(s, SYNC_FROM_VAPIC | SYNC_TO_VAPIC);
- apic_update_irq(s);
-}
-
-static int apic_find_dest(uint8_t dest)
-{
- APICCommonState *apic = local_apics[dest];
- int i;
-
- if (apic && apic->id == dest)
- return dest; /* shortcut in case apic->id == apic->idx */
-
- for (i = 0; i < MAX_APICS; i++) {
- apic = local_apics[i];
- if (apic && apic->id == dest)
- return i;
- if (!apic)
- break;
- }
-
- return -1;
-}
-
-static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
- uint8_t dest, uint8_t dest_mode)
-{
- APICCommonState *apic_iter;
- int i;
-
- if (dest_mode == 0) {
- if (dest == 0xff) {
- memset(deliver_bitmask, 0xff, MAX_APIC_WORDS * sizeof(uint32_t));
- } else {
- int idx = apic_find_dest(dest);
- memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t));
- if (idx >= 0)
- apic_set_bit(deliver_bitmask, idx);
- }
- } else {
- /* XXX: cluster mode */
- memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t));
- for(i = 0; i < MAX_APICS; i++) {
- apic_iter = local_apics[i];
- if (apic_iter) {
- if (apic_iter->dest_mode == 0xf) {
- if (dest & apic_iter->log_dest)
- apic_set_bit(deliver_bitmask, i);
- } else if (apic_iter->dest_mode == 0x0) {
- if ((dest & 0xf0) == (apic_iter->log_dest & 0xf0) &&
- (dest & apic_iter->log_dest & 0x0f)) {
- apic_set_bit(deliver_bitmask, i);
- }
- }
- } else {
- break;
- }
- }
- }
-}
-
-static void apic_startup(APICCommonState *s, int vector_num)
-{
- s->sipi_vector = vector_num;
- cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_SIPI);
-}
-
-void apic_sipi(DeviceState *dev)
-{
- APICCommonState *s = APIC_COMMON(dev);
-
- cpu_reset_interrupt(CPU(s->cpu), CPU_INTERRUPT_SIPI);
-
- if (!s->wait_for_sipi)
- return;
- cpu_x86_load_seg_cache_sipi(s->cpu, s->sipi_vector);
- s->wait_for_sipi = 0;
-}
-
-static void apic_deliver(DeviceState *dev, uint8_t dest, uint8_t dest_mode,
- uint8_t delivery_mode, uint8_t vector_num,
- uint8_t trigger_mode)
-{
- APICCommonState *s = APIC_COMMON(dev);
- uint32_t deliver_bitmask[MAX_APIC_WORDS];
- int dest_shorthand = (s->icr[0] >> 18) & 3;
- APICCommonState *apic_iter;
-
- switch (dest_shorthand) {
- case 0:
- apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode);
- break;
- case 1:
- memset(deliver_bitmask, 0x00, sizeof(deliver_bitmask));
- apic_set_bit(deliver_bitmask, s->idx);
- break;
- case 2:
- memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask));
- break;
- case 3:
- memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask));
- apic_reset_bit(deliver_bitmask, s->idx);
- break;
- }
-
- switch (delivery_mode) {
- case APIC_DM_INIT:
- {
- int trig_mode = (s->icr[0] >> 15) & 1;
- int level = (s->icr[0] >> 14) & 1;
- if (level == 0 && trig_mode == 1) {
- foreach_apic(apic_iter, deliver_bitmask,
- apic_iter->arb_id = apic_iter->id );
- return;
- }
- }
- break;
-
- case APIC_DM_SIPI:
- foreach_apic(apic_iter, deliver_bitmask,
- apic_startup(apic_iter, vector_num) );
- return;
- }
-
- apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, trigger_mode);
-}
-
-static bool apic_check_pic(APICCommonState *s)
-{
- DeviceState *dev = (DeviceState *)s;
-
- if (!apic_accept_pic_intr(dev) || !pic_get_output(isa_pic)) {
- return false;
- }
- apic_deliver_pic_intr(dev, 1);
- return true;
-}
-
-int apic_get_interrupt(DeviceState *dev)
-{
- APICCommonState *s = APIC_COMMON(dev);
- int intno;
-
- /* if the APIC is installed or enabled, we let the 8259 handle the
- IRQs */
- if (!s)
- return -1;
- if (!(s->spurious_vec & APIC_SV_ENABLE))
- return -1;
-
- apic_sync_vapic(s, SYNC_FROM_VAPIC);
- intno = apic_irq_pending(s);
-
- /* if there is an interrupt from the 8259, let the caller handle
- * that first since ExtINT interrupts ignore the priority.
- */
- if (intno == 0 || apic_check_pic(s)) {
- apic_sync_vapic(s, SYNC_TO_VAPIC);
- return -1;
- } else if (intno < 0) {
- apic_sync_vapic(s, SYNC_TO_VAPIC);
- return s->spurious_vec & 0xff;
- }
- apic_reset_bit(s->irr, intno);
- apic_set_bit(s->isr, intno);
- apic_sync_vapic(s, SYNC_TO_VAPIC);
-
- apic_update_irq(s);
-
- return intno;
-}
-
-int apic_accept_pic_intr(DeviceState *dev)
-{
- APICCommonState *s = APIC_COMMON(dev);
- uint32_t lvt0;
-
- if (!s)
- return -1;
-
- lvt0 = s->lvt[APIC_LVT_LINT0];
-
- if ((s->apicbase & MSR_IA32_APICBASE_ENABLE) == 0 ||
- (lvt0 & APIC_LVT_MASKED) == 0)
- return 1;
-
- return 0;
-}
-
-static uint32_t apic_get_current_count(APICCommonState *s)
-{
- int64_t d;
- uint32_t val;
- d = (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - s->initial_count_load_time) >>
- s->count_shift;
- if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
- /* periodic */
- val = s->initial_count - (d % ((uint64_t)s->initial_count + 1));
- } else {
- if (d >= s->initial_count)
- val = 0;
- else
- val = s->initial_count - d;
- }
- return val;
-}
-
-static void apic_timer_update(APICCommonState *s, int64_t current_time)
-{
- if (apic_next_timer(s, current_time)) {
- timer_mod(s->timer, s->next_time);
- } else {
- timer_del(s->timer);
- }
-}
-
-static void apic_timer(void *opaque)
-{
- APICCommonState *s = opaque;
-
- apic_local_deliver(s, APIC_LVT_TIMER);
- apic_timer_update(s, s->next_time);
-}
-
-static uint32_t apic_mem_readb(void *opaque, hwaddr addr)
-{
- return 0;
-}
-
-static uint32_t apic_mem_readw(void *opaque, hwaddr addr)
-{
- return 0;
-}
-
-static void apic_mem_writeb(void *opaque, hwaddr addr, uint32_t val)
-{
-}
-
-static void apic_mem_writew(void *opaque, hwaddr addr, uint32_t val)
-{
-}
-
-static uint32_t apic_mem_readl(void *opaque, hwaddr addr)
-{
- DeviceState *dev;
- APICCommonState *s;
- uint32_t val;
- int index;
-
- dev = cpu_get_current_apic();
- if (!dev) {
- return 0;
- }
- s = APIC_COMMON(dev);
-
- index = (addr >> 4) & 0xff;
- switch(index) {
- case 0x02: /* id */
- val = s->id << 24;
- break;
- case 0x03: /* version */
- val = s->version | ((APIC_LVT_NB - 1) << 16);
- break;
- case 0x08:
- apic_sync_vapic(s, SYNC_FROM_VAPIC);
- if (apic_report_tpr_access) {
- cpu_report_tpr_access(&s->cpu->env, TPR_ACCESS_READ);
- }
- val = s->tpr;
- break;
- case 0x09:
- val = apic_get_arb_pri(s);
- break;
- case 0x0a:
- /* ppr */
- val = apic_get_ppr(s);
- break;
- case 0x0b:
- val = 0;
- break;
- case 0x0d:
- val = s->log_dest << 24;
- break;
- case 0x0e:
- val = (s->dest_mode << 28) | 0xfffffff;
- break;
- case 0x0f:
- val = s->spurious_vec;
- break;
- case 0x10 ... 0x17:
- val = s->isr[index & 7];
- break;
- case 0x18 ... 0x1f:
- val = s->tmr[index & 7];
- break;
- case 0x20 ... 0x27:
- val = s->irr[index & 7];
- break;
- case 0x28:
- val = s->esr;
- break;
- case 0x30:
- case 0x31:
- val = s->icr[index & 1];
- break;
- case 0x32 ... 0x37:
- val = s->lvt[index - 0x32];
- break;
- case 0x38:
- val = s->initial_count;
- break;
- case 0x39:
- val = apic_get_current_count(s);
- break;
- case 0x3e:
- val = s->divide_conf;
- break;
- default:
- s->esr |= APIC_ESR_ILLEGAL_ADDRESS;
- val = 0;
- break;
- }
- trace_apic_mem_readl(addr, val);
- return val;
-}
-
-static void apic_send_msi(hwaddr addr, uint32_t data)
-{
- uint8_t dest = (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT;
- uint8_t vector = (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT;
- uint8_t dest_mode = (addr >> MSI_ADDR_DEST_MODE_SHIFT) & 0x1;
- uint8_t trigger_mode = (data >> MSI_DATA_TRIGGER_SHIFT) & 0x1;
- uint8_t delivery = (data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 0x7;
- /* XXX: Ignore redirection hint. */
- apic_deliver_irq(dest, dest_mode, delivery, vector, trigger_mode);
-}
-
-static void apic_mem_writel(void *opaque, hwaddr addr, uint32_t val)
-{
- DeviceState *dev;
- APICCommonState *s;
- int index = (addr >> 4) & 0xff;
- if (addr > 0xfff || !index) {
- /* MSI and MMIO APIC are at the same memory location,
- * but actually not on the global bus: MSI is on PCI bus
- * APIC is connected directly to the CPU.
- * Mapping them on the global bus happens to work because
- * MSI registers are reserved in APIC MMIO and vice versa. */
- apic_send_msi(addr, val);
- return;
- }
-
- dev = cpu_get_current_apic();
- if (!dev) {
- return;
- }
- s = APIC_COMMON(dev);
-
- trace_apic_mem_writel(addr, val);
-
- switch(index) {
- case 0x02:
- s->id = (val >> 24);
- break;
- case 0x03:
- break;
- case 0x08:
- if (apic_report_tpr_access) {
- cpu_report_tpr_access(&s->cpu->env, TPR_ACCESS_WRITE);
- }
- s->tpr = val;
- apic_sync_vapic(s, SYNC_TO_VAPIC);
- apic_update_irq(s);
- break;
- case 0x09:
- case 0x0a:
- break;
- case 0x0b: /* EOI */
- apic_eoi(s);
- break;
- case 0x0d:
- s->log_dest = val >> 24;
- break;
- case 0x0e:
- s->dest_mode = val >> 28;
- break;
- case 0x0f:
- s->spurious_vec = val & 0x1ff;
- apic_update_irq(s);
- break;
- case 0x10 ... 0x17:
- case 0x18 ... 0x1f:
- case 0x20 ... 0x27:
- case 0x28:
- break;
- case 0x30:
- s->icr[0] = val;
- apic_deliver(dev, (s->icr[1] >> 24) & 0xff, (s->icr[0] >> 11) & 1,
- (s->icr[0] >> 8) & 7, (s->icr[0] & 0xff),
- (s->icr[0] >> 15) & 1);
- break;
- case 0x31:
- s->icr[1] = val;
- break;
- case 0x32 ... 0x37:
- {
- int n = index - 0x32;
- s->lvt[n] = val;
- if (n == APIC_LVT_TIMER) {
- apic_timer_update(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
- } else if (n == APIC_LVT_LINT0 && apic_check_pic(s)) {
- apic_update_irq(s);
- }
- }
- break;
- case 0x38:
- s->initial_count = val;
- s->initial_count_load_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- apic_timer_update(s, s->initial_count_load_time);
- break;
- case 0x39:
- break;
- case 0x3e:
- {
- int v;
- s->divide_conf = val & 0xb;
- v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4);
- s->count_shift = (v + 1) & 7;
- }
- break;
- default:
- s->esr |= APIC_ESR_ILLEGAL_ADDRESS;
- break;
- }
-}
-
-static void apic_pre_save(APICCommonState *s)
-{
- apic_sync_vapic(s, SYNC_FROM_VAPIC);
-}
-
-static void apic_post_load(APICCommonState *s)
-{
- if (s->timer_expiry != -1) {
- timer_mod(s->timer, s->timer_expiry);
- } else {
- timer_del(s->timer);
- }
-}
-
-static const MemoryRegionOps apic_io_ops = {
- .old_mmio = {
- .read = { apic_mem_readb, apic_mem_readw, apic_mem_readl, },
- .write = { apic_mem_writeb, apic_mem_writew, apic_mem_writel, },
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void apic_realize(DeviceState *dev, Error **errp)
-{
- APICCommonState *s = APIC_COMMON(dev);
-
- memory_region_init_io(&s->io_memory, OBJECT(s), &apic_io_ops, s, "apic-msi",
- APIC_SPACE_SIZE);
-
- s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, apic_timer, s);
- local_apics[s->idx] = s;
-
- msi_nonbroken = true;
-}
-
-static void apic_class_init(ObjectClass *klass, void *data)
-{
- APICCommonClass *k = APIC_COMMON_CLASS(klass);
-
- k->realize = apic_realize;
- k->set_base = apic_set_base;
- k->set_tpr = apic_set_tpr;
- k->get_tpr = apic_get_tpr;
- k->vapic_base_update = apic_vapic_base_update;
- k->external_nmi = apic_external_nmi;
- k->pre_save = apic_pre_save;
- k->post_load = apic_post_load;
-}
-
-static const TypeInfo apic_info = {
- .name = "apic",
- .instance_size = sizeof(APICCommonState),
- .parent = TYPE_APIC_COMMON,
- .class_init = apic_class_init,
-};
-
-static void apic_register_types(void)
-{
- type_register_static(&apic_info);
-}
-
-type_init(apic_register_types)
diff --git a/qemu/hw/intc/apic_common.c b/qemu/hw/intc/apic_common.c
deleted file mode 100644
index 4abe145c6..000000000
--- a/qemu/hw/intc/apic_common.c
+++ /dev/null
@@ -1,451 +0,0 @@
-/*
- * APIC support - common bits of emulated and KVM kernel model
- *
- * Copyright (c) 2004-2005 Fabrice Bellard
- * Copyright (c) 2011 Jan Kiszka, Siemens AG
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>
- */
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/i386/apic.h"
-#include "hw/i386/apic_internal.h"
-#include "trace.h"
-#include "sysemu/kvm.h"
-#include "hw/qdev.h"
-#include "hw/sysbus.h"
-
-static int apic_irq_delivered;
-bool apic_report_tpr_access;
-
-void cpu_set_apic_base(DeviceState *dev, uint64_t val)
-{
- trace_cpu_set_apic_base(val);
-
- if (dev) {
- APICCommonState *s = APIC_COMMON(dev);
- APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
- info->set_base(s, val);
- }
-}
-
-uint64_t cpu_get_apic_base(DeviceState *dev)
-{
- if (dev) {
- APICCommonState *s = APIC_COMMON(dev);
- trace_cpu_get_apic_base((uint64_t)s->apicbase);
- return s->apicbase;
- } else {
- trace_cpu_get_apic_base(MSR_IA32_APICBASE_BSP);
- return MSR_IA32_APICBASE_BSP;
- }
-}
-
-void cpu_set_apic_tpr(DeviceState *dev, uint8_t val)
-{
- APICCommonState *s;
- APICCommonClass *info;
-
- if (!dev) {
- return;
- }
-
- s = APIC_COMMON(dev);
- info = APIC_COMMON_GET_CLASS(s);
-
- info->set_tpr(s, val);
-}
-
-uint8_t cpu_get_apic_tpr(DeviceState *dev)
-{
- APICCommonState *s;
- APICCommonClass *info;
-
- if (!dev) {
- return 0;
- }
-
- s = APIC_COMMON(dev);
- info = APIC_COMMON_GET_CLASS(s);
-
- return info->get_tpr(s);
-}
-
-void apic_enable_tpr_access_reporting(DeviceState *dev, bool enable)
-{
- APICCommonState *s = APIC_COMMON(dev);
- APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
-
- apic_report_tpr_access = enable;
- if (info->enable_tpr_reporting) {
- info->enable_tpr_reporting(s, enable);
- }
-}
-
-void apic_enable_vapic(DeviceState *dev, hwaddr paddr)
-{
- APICCommonState *s = APIC_COMMON(dev);
- APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
-
- s->vapic_paddr = paddr;
- info->vapic_base_update(s);
-}
-
-void apic_handle_tpr_access_report(DeviceState *dev, target_ulong ip,
- TPRAccess access)
-{
- APICCommonState *s = APIC_COMMON(dev);
-
- vapic_report_tpr_access(s->vapic, CPU(s->cpu), ip, access);
-}
-
-void apic_report_irq_delivered(int delivered)
-{
- apic_irq_delivered += delivered;
-
- trace_apic_report_irq_delivered(apic_irq_delivered);
-}
-
-void apic_reset_irq_delivered(void)
-{
- /* Copy this into a local variable to encourage gcc to emit a plain
- * register for a sys/sdt.h marker. For details on this workaround, see:
- * https://sourceware.org/bugzilla/show_bug.cgi?id=13296
- */
- volatile int a_i_d = apic_irq_delivered;
- trace_apic_reset_irq_delivered(a_i_d);
-
- apic_irq_delivered = 0;
-}
-
-int apic_get_irq_delivered(void)
-{
- trace_apic_get_irq_delivered(apic_irq_delivered);
-
- return apic_irq_delivered;
-}
-
-void apic_deliver_nmi(DeviceState *dev)
-{
- APICCommonState *s = APIC_COMMON(dev);
- APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
-
- info->external_nmi(s);
-}
-
-bool apic_next_timer(APICCommonState *s, int64_t current_time)
-{
- int64_t d;
-
- /* We need to store the timer state separately to support APIC
- * implementations that maintain a non-QEMU timer, e.g. inside the
- * host kernel. This open-coded state allows us to migrate between
- * both models. */
- s->timer_expiry = -1;
-
- if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED) {
- return false;
- }
-
- d = (current_time - s->initial_count_load_time) >> s->count_shift;
-
- if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
- if (!s->initial_count) {
- return false;
- }
- d = ((d / ((uint64_t)s->initial_count + 1)) + 1) *
- ((uint64_t)s->initial_count + 1);
- } else {
- if (d >= s->initial_count) {
- return false;
- }
- d = (uint64_t)s->initial_count + 1;
- }
- s->next_time = s->initial_count_load_time + (d << s->count_shift);
- s->timer_expiry = s->next_time;
- return true;
-}
-
-void apic_init_reset(DeviceState *dev)
-{
- APICCommonState *s;
- APICCommonClass *info;
- int i;
-
- if (!dev) {
- return;
- }
- s = APIC_COMMON(dev);
- s->tpr = 0;
- s->spurious_vec = 0xff;
- s->log_dest = 0;
- s->dest_mode = 0xf;
- memset(s->isr, 0, sizeof(s->isr));
- memset(s->tmr, 0, sizeof(s->tmr));
- memset(s->irr, 0, sizeof(s->irr));
- for (i = 0; i < APIC_LVT_NB; i++) {
- s->lvt[i] = APIC_LVT_MASKED;
- }
- s->esr = 0;
- memset(s->icr, 0, sizeof(s->icr));
- s->divide_conf = 0;
- s->count_shift = 0;
- s->initial_count = 0;
- s->initial_count_load_time = 0;
- s->next_time = 0;
- s->wait_for_sipi = !cpu_is_bsp(s->cpu);
-
- if (s->timer) {
- timer_del(s->timer);
- }
- s->timer_expiry = -1;
-
- info = APIC_COMMON_GET_CLASS(s);
- if (info->reset) {
- info->reset(s);
- }
-}
-
-void apic_designate_bsp(DeviceState *dev, bool bsp)
-{
- if (dev == NULL) {
- return;
- }
-
- APICCommonState *s = APIC_COMMON(dev);
- if (bsp) {
- s->apicbase |= MSR_IA32_APICBASE_BSP;
- } else {
- s->apicbase &= ~MSR_IA32_APICBASE_BSP;
- }
-}
-
-static void apic_reset_common(DeviceState *dev)
-{
- APICCommonState *s = APIC_COMMON(dev);
- APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
- uint32_t bsp;
-
- bsp = s->apicbase & MSR_IA32_APICBASE_BSP;
- s->apicbase = APIC_DEFAULT_ADDRESS | bsp | MSR_IA32_APICBASE_ENABLE;
-
- s->vapic_paddr = 0;
- info->vapic_base_update(s);
-
- apic_init_reset(dev);
-}
-
-/* This function is only used for old state version 1 and 2 */
-static int apic_load_old(QEMUFile *f, void *opaque, int version_id)
-{
- APICCommonState *s = opaque;
- APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
- int i;
-
- if (version_id > 2) {
- return -EINVAL;
- }
-
- /* XXX: what if the base changes? (registered memory regions) */
- qemu_get_be32s(f, &s->apicbase);
- qemu_get_8s(f, &s->id);
- qemu_get_8s(f, &s->arb_id);
- qemu_get_8s(f, &s->tpr);
- qemu_get_be32s(f, &s->spurious_vec);
- qemu_get_8s(f, &s->log_dest);
- qemu_get_8s(f, &s->dest_mode);
- for (i = 0; i < 8; i++) {
- qemu_get_be32s(f, &s->isr[i]);
- qemu_get_be32s(f, &s->tmr[i]);
- qemu_get_be32s(f, &s->irr[i]);
- }
- for (i = 0; i < APIC_LVT_NB; i++) {
- qemu_get_be32s(f, &s->lvt[i]);
- }
- qemu_get_be32s(f, &s->esr);
- qemu_get_be32s(f, &s->icr[0]);
- qemu_get_be32s(f, &s->icr[1]);
- qemu_get_be32s(f, &s->divide_conf);
- s->count_shift = qemu_get_be32(f);
- qemu_get_be32s(f, &s->initial_count);
- s->initial_count_load_time = qemu_get_be64(f);
- s->next_time = qemu_get_be64(f);
-
- if (version_id >= 2) {
- s->timer_expiry = qemu_get_be64(f);
- }
-
- if (info->post_load) {
- info->post_load(s);
- }
- return 0;
-}
-
-static void apic_common_realize(DeviceState *dev, Error **errp)
-{
- APICCommonState *s = APIC_COMMON(dev);
- APICCommonClass *info;
- static DeviceState *vapic;
- static int apic_no;
-
- if (apic_no >= MAX_APICS) {
- error_setg(errp, "%s initialization failed.",
- object_get_typename(OBJECT(dev)));
- return;
- }
- s->idx = apic_no++;
-
- info = APIC_COMMON_GET_CLASS(s);
- info->realize(dev, errp);
-
- /* Note: We need at least 1M to map the VAPIC option ROM */
- if (!vapic && s->vapic_control & VAPIC_ENABLE_MASK &&
- ram_size >= 1024 * 1024) {
- vapic = sysbus_create_simple("kvmvapic", -1, NULL);
- }
- s->vapic = vapic;
- if (apic_report_tpr_access && info->enable_tpr_reporting) {
- info->enable_tpr_reporting(s, true);
- }
-
-}
-
-static int apic_pre_load(void *opaque)
-{
- APICCommonState *s = APIC_COMMON(opaque);
-
- /* The default is !cpu_is_bsp(s->cpu), but the common value is 0
- * so that's what apic_common_sipi_needed checks for. Reset to
- * the value that is assumed when the apic_sipi subsection is
- * absent.
- */
- s->wait_for_sipi = 0;
- return 0;
-}
-
-static void apic_dispatch_pre_save(void *opaque)
-{
- APICCommonState *s = APIC_COMMON(opaque);
- APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
-
- if (info->pre_save) {
- info->pre_save(s);
- }
-}
-
-static int apic_dispatch_post_load(void *opaque, int version_id)
-{
- APICCommonState *s = APIC_COMMON(opaque);
- APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
-
- if (info->post_load) {
- info->post_load(s);
- }
- return 0;
-}
-
-static bool apic_common_sipi_needed(void *opaque)
-{
- APICCommonState *s = APIC_COMMON(opaque);
- return s->wait_for_sipi != 0;
-}
-
-static const VMStateDescription vmstate_apic_common_sipi = {
- .name = "apic_sipi",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = apic_common_sipi_needed,
- .fields = (VMStateField[]) {
- VMSTATE_INT32(sipi_vector, APICCommonState),
- VMSTATE_INT32(wait_for_sipi, APICCommonState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_apic_common = {
- .name = "apic",
- .version_id = 3,
- .minimum_version_id = 3,
- .minimum_version_id_old = 1,
- .load_state_old = apic_load_old,
- .pre_load = apic_pre_load,
- .pre_save = apic_dispatch_pre_save,
- .post_load = apic_dispatch_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(apicbase, APICCommonState),
- VMSTATE_UINT8(id, APICCommonState),
- VMSTATE_UINT8(arb_id, APICCommonState),
- VMSTATE_UINT8(tpr, APICCommonState),
- VMSTATE_UINT32(spurious_vec, APICCommonState),
- VMSTATE_UINT8(log_dest, APICCommonState),
- VMSTATE_UINT8(dest_mode, APICCommonState),
- VMSTATE_UINT32_ARRAY(isr, APICCommonState, 8),
- VMSTATE_UINT32_ARRAY(tmr, APICCommonState, 8),
- VMSTATE_UINT32_ARRAY(irr, APICCommonState, 8),
- VMSTATE_UINT32_ARRAY(lvt, APICCommonState, APIC_LVT_NB),
- VMSTATE_UINT32(esr, APICCommonState),
- VMSTATE_UINT32_ARRAY(icr, APICCommonState, 2),
- VMSTATE_UINT32(divide_conf, APICCommonState),
- VMSTATE_INT32(count_shift, APICCommonState),
- VMSTATE_UINT32(initial_count, APICCommonState),
- VMSTATE_INT64(initial_count_load_time, APICCommonState),
- VMSTATE_INT64(next_time, APICCommonState),
- VMSTATE_INT64(timer_expiry,
- APICCommonState), /* open-coded timer state */
- VMSTATE_END_OF_LIST()
- },
- .subsections = (const VMStateDescription*[]) {
- &vmstate_apic_common_sipi,
- NULL
- }
-};
-
-static Property apic_properties_common[] = {
- DEFINE_PROP_UINT8("id", APICCommonState, id, -1),
- DEFINE_PROP_UINT8("version", APICCommonState, version, 0x14),
- DEFINE_PROP_BIT("vapic", APICCommonState, vapic_control, VAPIC_ENABLE_BIT,
- true),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void apic_common_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->vmsd = &vmstate_apic_common;
- dc->reset = apic_reset_common;
- dc->props = apic_properties_common;
- dc->realize = apic_common_realize;
- /*
- * Reason: APIC and CPU need to be wired up by
- * x86_cpu_apic_create()
- */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo apic_common_type = {
- .name = TYPE_APIC_COMMON,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(APICCommonState),
- .class_size = sizeof(APICCommonClass),
- .class_init = apic_common_class_init,
- .abstract = true,
-};
-
-static void apic_common_register_types(void)
-{
- type_register_static(&apic_common_type);
-}
-
-type_init(apic_common_register_types)
diff --git a/qemu/hw/intc/arm_gic.c b/qemu/hw/intc/arm_gic.c
deleted file mode 100644
index f55124174..000000000
--- a/qemu/hw/intc/arm_gic.c
+++ /dev/null
@@ -1,1385 +0,0 @@
-/*
- * ARM Generic/Distributed Interrupt Controller
- *
- * Copyright (c) 2006-2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-/* This file contains implementation code for the RealView EB interrupt
- * controller, MPCore distributed interrupt controller and ARMv7-M
- * Nested Vectored Interrupt Controller.
- * It is compiled in two ways:
- * (1) as a standalone file to produce a sysbus device which is a GIC
- * that can be used on the realview board and as one of the builtin
- * private peripherals for the ARM MP CPUs (11MPCore, A9, etc)
- * (2) by being directly #included into armv7m_nvic.c to produce the
- * armv7m_nvic device.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "gic_internal.h"
-#include "qapi/error.h"
-#include "qom/cpu.h"
-
-//#define DEBUG_GIC
-
-#ifdef DEBUG_GIC
-#define DPRINTF(fmt, ...) \
-do { fprintf(stderr, "arm_gic: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#endif
-
-static const uint8_t gic_id_11mpcore[] = {
- 0x00, 0x00, 0x00, 0x00, 0x90, 0x13, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1
-};
-
-static const uint8_t gic_id_gicv1[] = {
- 0x04, 0x00, 0x00, 0x00, 0x90, 0xb3, 0x1b, 0x00, 0x0d, 0xf0, 0x05, 0xb1
-};
-
-static const uint8_t gic_id_gicv2[] = {
- 0x04, 0x00, 0x00, 0x00, 0x90, 0xb4, 0x2b, 0x00, 0x0d, 0xf0, 0x05, 0xb1
-};
-
-static inline int gic_get_current_cpu(GICState *s)
-{
- if (s->num_cpu > 1) {
- return current_cpu->cpu_index;
- }
- return 0;
-}
-
-/* Return true if this GIC config has interrupt groups, which is
- * true if we're a GICv2, or a GICv1 with the security extensions.
- */
-static inline bool gic_has_groups(GICState *s)
-{
- return s->revision == 2 || s->security_extn;
-}
-
-/* TODO: Many places that call this routine could be optimized. */
-/* Update interrupt status after enabled or pending bits have been changed. */
-void gic_update(GICState *s)
-{
- int best_irq;
- int best_prio;
- int irq;
- int irq_level, fiq_level;
- int cpu;
- int cm;
-
- for (cpu = 0; cpu < s->num_cpu; cpu++) {
- cm = 1 << cpu;
- s->current_pending[cpu] = 1023;
- if (!(s->ctlr & (GICD_CTLR_EN_GRP0 | GICD_CTLR_EN_GRP1))
- || !(s->cpu_ctlr[cpu] & (GICC_CTLR_EN_GRP0 | GICC_CTLR_EN_GRP1))) {
- qemu_irq_lower(s->parent_irq[cpu]);
- qemu_irq_lower(s->parent_fiq[cpu]);
- continue;
- }
- best_prio = 0x100;
- best_irq = 1023;
- for (irq = 0; irq < s->num_irq; irq++) {
- if (GIC_TEST_ENABLED(irq, cm) && gic_test_pending(s, irq, cm) &&
- (irq < GIC_INTERNAL || GIC_TARGET(irq) & cm)) {
- if (GIC_GET_PRIORITY(irq, cpu) < best_prio) {
- best_prio = GIC_GET_PRIORITY(irq, cpu);
- best_irq = irq;
- }
- }
- }
-
- irq_level = fiq_level = 0;
-
- if (best_prio < s->priority_mask[cpu]) {
- s->current_pending[cpu] = best_irq;
- if (best_prio < s->running_priority[cpu]) {
- int group = GIC_TEST_GROUP(best_irq, cm);
-
- if (extract32(s->ctlr, group, 1) &&
- extract32(s->cpu_ctlr[cpu], group, 1)) {
- if (group == 0 && s->cpu_ctlr[cpu] & GICC_CTLR_FIQ_EN) {
- DPRINTF("Raised pending FIQ %d (cpu %d)\n",
- best_irq, cpu);
- fiq_level = 1;
- } else {
- DPRINTF("Raised pending IRQ %d (cpu %d)\n",
- best_irq, cpu);
- irq_level = 1;
- }
- }
- }
- }
-
- qemu_set_irq(s->parent_irq[cpu], irq_level);
- qemu_set_irq(s->parent_fiq[cpu], fiq_level);
- }
-}
-
-void gic_set_pending_private(GICState *s, int cpu, int irq)
-{
- int cm = 1 << cpu;
-
- if (gic_test_pending(s, irq, cm)) {
- return;
- }
-
- DPRINTF("Set %d pending cpu %d\n", irq, cpu);
- GIC_SET_PENDING(irq, cm);
- gic_update(s);
-}
-
-static void gic_set_irq_11mpcore(GICState *s, int irq, int level,
- int cm, int target)
-{
- if (level) {
- GIC_SET_LEVEL(irq, cm);
- if (GIC_TEST_EDGE_TRIGGER(irq) || GIC_TEST_ENABLED(irq, cm)) {
- DPRINTF("Set %d pending mask %x\n", irq, target);
- GIC_SET_PENDING(irq, target);
- }
- } else {
- GIC_CLEAR_LEVEL(irq, cm);
- }
-}
-
-static void gic_set_irq_generic(GICState *s, int irq, int level,
- int cm, int target)
-{
- if (level) {
- GIC_SET_LEVEL(irq, cm);
- DPRINTF("Set %d pending mask %x\n", irq, target);
- if (GIC_TEST_EDGE_TRIGGER(irq)) {
- GIC_SET_PENDING(irq, target);
- }
- } else {
- GIC_CLEAR_LEVEL(irq, cm);
- }
-}
-
-/* Process a change in an external IRQ input. */
-static void gic_set_irq(void *opaque, int irq, int level)
-{
- /* Meaning of the 'irq' parameter:
- * [0..N-1] : external interrupts
- * [N..N+31] : PPI (internal) interrupts for CPU 0
- * [N+32..N+63] : PPI (internal interrupts for CPU 1
- * ...
- */
- GICState *s = (GICState *)opaque;
- int cm, target;
- if (irq < (s->num_irq - GIC_INTERNAL)) {
- /* The first external input line is internal interrupt 32. */
- cm = ALL_CPU_MASK;
- irq += GIC_INTERNAL;
- target = GIC_TARGET(irq);
- } else {
- int cpu;
- irq -= (s->num_irq - GIC_INTERNAL);
- cpu = irq / GIC_INTERNAL;
- irq %= GIC_INTERNAL;
- cm = 1 << cpu;
- target = cm;
- }
-
- assert(irq >= GIC_NR_SGIS);
-
- if (level == GIC_TEST_LEVEL(irq, cm)) {
- return;
- }
-
- if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) {
- gic_set_irq_11mpcore(s, irq, level, cm, target);
- } else {
- gic_set_irq_generic(s, irq, level, cm, target);
- }
-
- gic_update(s);
-}
-
-static uint16_t gic_get_current_pending_irq(GICState *s, int cpu,
- MemTxAttrs attrs)
-{
- uint16_t pending_irq = s->current_pending[cpu];
-
- if (pending_irq < GIC_MAXIRQ && gic_has_groups(s)) {
- int group = GIC_TEST_GROUP(pending_irq, (1 << cpu));
- /* On a GIC without the security extensions, reading this register
- * behaves in the same way as a secure access to a GIC with them.
- */
- bool secure = !s->security_extn || attrs.secure;
-
- if (group == 0 && !secure) {
- /* Group0 interrupts hidden from Non-secure access */
- return 1023;
- }
- if (group == 1 && secure && !(s->cpu_ctlr[cpu] & GICC_CTLR_ACK_CTL)) {
- /* Group1 interrupts only seen by Secure access if
- * AckCtl bit set.
- */
- return 1022;
- }
- }
- return pending_irq;
-}
-
-static int gic_get_group_priority(GICState *s, int cpu, int irq)
-{
- /* Return the group priority of the specified interrupt
- * (which is the top bits of its priority, with the number
- * of bits masked determined by the applicable binary point register).
- */
- int bpr;
- uint32_t mask;
-
- if (gic_has_groups(s) &&
- !(s->cpu_ctlr[cpu] & GICC_CTLR_CBPR) &&
- GIC_TEST_GROUP(irq, (1 << cpu))) {
- bpr = s->abpr[cpu];
- } else {
- bpr = s->bpr[cpu];
- }
-
- /* a BPR of 0 means the group priority bits are [7:1];
- * a BPR of 1 means they are [7:2], and so on down to
- * a BPR of 7 meaning no group priority bits at all.
- */
- mask = ~0U << ((bpr & 7) + 1);
-
- return GIC_GET_PRIORITY(irq, cpu) & mask;
-}
-
-static void gic_activate_irq(GICState *s, int cpu, int irq)
-{
- /* Set the appropriate Active Priority Register bit for this IRQ,
- * and update the running priority.
- */
- int prio = gic_get_group_priority(s, cpu, irq);
- int preemption_level = prio >> (GIC_MIN_BPR + 1);
- int regno = preemption_level / 32;
- int bitno = preemption_level % 32;
-
- if (gic_has_groups(s) && GIC_TEST_GROUP(irq, (1 << cpu))) {
- s->nsapr[regno][cpu] |= (1 << bitno);
- } else {
- s->apr[regno][cpu] |= (1 << bitno);
- }
-
- s->running_priority[cpu] = prio;
- GIC_SET_ACTIVE(irq, 1 << cpu);
-}
-
-static int gic_get_prio_from_apr_bits(GICState *s, int cpu)
-{
- /* Recalculate the current running priority for this CPU based
- * on the set bits in the Active Priority Registers.
- */
- int i;
- for (i = 0; i < GIC_NR_APRS; i++) {
- uint32_t apr = s->apr[i][cpu] | s->nsapr[i][cpu];
- if (!apr) {
- continue;
- }
- return (i * 32 + ctz32(apr)) << (GIC_MIN_BPR + 1);
- }
- return 0x100;
-}
-
-static void gic_drop_prio(GICState *s, int cpu, int group)
-{
- /* Drop the priority of the currently active interrupt in the
- * specified group.
- *
- * Note that we can guarantee (because of the requirement to nest
- * GICC_IAR reads [which activate an interrupt and raise priority]
- * with GICC_EOIR writes [which drop the priority for the interrupt])
- * that the interrupt we're being called for is the highest priority
- * active interrupt, meaning that it has the lowest set bit in the
- * APR registers.
- *
- * If the guest does not honour the ordering constraints then the
- * behaviour of the GIC is UNPREDICTABLE, which for us means that
- * the values of the APR registers might become incorrect and the
- * running priority will be wrong, so interrupts that should preempt
- * might not do so, and interrupts that should not preempt might do so.
- */
- int i;
-
- for (i = 0; i < GIC_NR_APRS; i++) {
- uint32_t *papr = group ? &s->nsapr[i][cpu] : &s->apr[i][cpu];
- if (!*papr) {
- continue;
- }
- /* Clear lowest set bit */
- *papr &= *papr - 1;
- break;
- }
-
- s->running_priority[cpu] = gic_get_prio_from_apr_bits(s, cpu);
-}
-
-uint32_t gic_acknowledge_irq(GICState *s, int cpu, MemTxAttrs attrs)
-{
- int ret, irq, src;
- int cm = 1 << cpu;
-
- /* gic_get_current_pending_irq() will return 1022 or 1023 appropriately
- * for the case where this GIC supports grouping and the pending interrupt
- * is in the wrong group.
- */
- irq = gic_get_current_pending_irq(s, cpu, attrs);
-
- if (irq >= GIC_MAXIRQ) {
- DPRINTF("ACK, no pending interrupt or it is hidden: %d\n", irq);
- return irq;
- }
-
- if (GIC_GET_PRIORITY(irq, cpu) >= s->running_priority[cpu]) {
- DPRINTF("ACK, pending interrupt (%d) has insufficient priority\n", irq);
- return 1023;
- }
-
- if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) {
- /* Clear pending flags for both level and edge triggered interrupts.
- * Level triggered IRQs will be reasserted once they become inactive.
- */
- GIC_CLEAR_PENDING(irq, GIC_TEST_MODEL(irq) ? ALL_CPU_MASK : cm);
- ret = irq;
- } else {
- if (irq < GIC_NR_SGIS) {
- /* Lookup the source CPU for the SGI and clear this in the
- * sgi_pending map. Return the src and clear the overall pending
- * state on this CPU if the SGI is not pending from any CPUs.
- */
- assert(s->sgi_pending[irq][cpu] != 0);
- src = ctz32(s->sgi_pending[irq][cpu]);
- s->sgi_pending[irq][cpu] &= ~(1 << src);
- if (s->sgi_pending[irq][cpu] == 0) {
- GIC_CLEAR_PENDING(irq, GIC_TEST_MODEL(irq) ? ALL_CPU_MASK : cm);
- }
- ret = irq | ((src & 0x7) << 10);
- } else {
- /* Clear pending state for both level and edge triggered
- * interrupts. (level triggered interrupts with an active line
- * remain pending, see gic_test_pending)
- */
- GIC_CLEAR_PENDING(irq, GIC_TEST_MODEL(irq) ? ALL_CPU_MASK : cm);
- ret = irq;
- }
- }
-
- gic_activate_irq(s, cpu, irq);
- gic_update(s);
- DPRINTF("ACK %d\n", irq);
- return ret;
-}
-
-void gic_set_priority(GICState *s, int cpu, int irq, uint8_t val,
- MemTxAttrs attrs)
-{
- if (s->security_extn && !attrs.secure) {
- if (!GIC_TEST_GROUP(irq, (1 << cpu))) {
- return; /* Ignore Non-secure access of Group0 IRQ */
- }
- val = 0x80 | (val >> 1); /* Non-secure view */
- }
-
- if (irq < GIC_INTERNAL) {
- s->priority1[irq][cpu] = val;
- } else {
- s->priority2[(irq) - GIC_INTERNAL] = val;
- }
-}
-
-static uint32_t gic_get_priority(GICState *s, int cpu, int irq,
- MemTxAttrs attrs)
-{
- uint32_t prio = GIC_GET_PRIORITY(irq, cpu);
-
- if (s->security_extn && !attrs.secure) {
- if (!GIC_TEST_GROUP(irq, (1 << cpu))) {
- return 0; /* Non-secure access cannot read priority of Group0 IRQ */
- }
- prio = (prio << 1) & 0xff; /* Non-secure view */
- }
- return prio;
-}
-
-static void gic_set_priority_mask(GICState *s, int cpu, uint8_t pmask,
- MemTxAttrs attrs)
-{
- if (s->security_extn && !attrs.secure) {
- if (s->priority_mask[cpu] & 0x80) {
- /* Priority Mask in upper half */
- pmask = 0x80 | (pmask >> 1);
- } else {
- /* Non-secure write ignored if priority mask is in lower half */
- return;
- }
- }
- s->priority_mask[cpu] = pmask;
-}
-
-static uint32_t gic_get_priority_mask(GICState *s, int cpu, MemTxAttrs attrs)
-{
- uint32_t pmask = s->priority_mask[cpu];
-
- if (s->security_extn && !attrs.secure) {
- if (pmask & 0x80) {
- /* Priority Mask in upper half, return Non-secure view */
- pmask = (pmask << 1) & 0xff;
- } else {
- /* Priority Mask in lower half, RAZ */
- pmask = 0;
- }
- }
- return pmask;
-}
-
-static uint32_t gic_get_cpu_control(GICState *s, int cpu, MemTxAttrs attrs)
-{
- uint32_t ret = s->cpu_ctlr[cpu];
-
- if (s->security_extn && !attrs.secure) {
- /* Construct the NS banked view of GICC_CTLR from the correct
- * bits of the S banked view. We don't need to move the bypass
- * control bits because we don't implement that (IMPDEF) part
- * of the GIC architecture.
- */
- ret = (ret & (GICC_CTLR_EN_GRP1 | GICC_CTLR_EOIMODE_NS)) >> 1;
- }
- return ret;
-}
-
-static void gic_set_cpu_control(GICState *s, int cpu, uint32_t value,
- MemTxAttrs attrs)
-{
- uint32_t mask;
-
- if (s->security_extn && !attrs.secure) {
- /* The NS view can only write certain bits in the register;
- * the rest are unchanged
- */
- mask = GICC_CTLR_EN_GRP1;
- if (s->revision == 2) {
- mask |= GICC_CTLR_EOIMODE_NS;
- }
- s->cpu_ctlr[cpu] &= ~mask;
- s->cpu_ctlr[cpu] |= (value << 1) & mask;
- } else {
- if (s->revision == 2) {
- mask = s->security_extn ? GICC_CTLR_V2_S_MASK : GICC_CTLR_V2_MASK;
- } else {
- mask = s->security_extn ? GICC_CTLR_V1_S_MASK : GICC_CTLR_V1_MASK;
- }
- s->cpu_ctlr[cpu] = value & mask;
- }
- DPRINTF("CPU Interface %d: Group0 Interrupts %sabled, "
- "Group1 Interrupts %sabled\n", cpu,
- (s->cpu_ctlr[cpu] & GICC_CTLR_EN_GRP0) ? "En" : "Dis",
- (s->cpu_ctlr[cpu] & GICC_CTLR_EN_GRP1) ? "En" : "Dis");
-}
-
-static uint8_t gic_get_running_priority(GICState *s, int cpu, MemTxAttrs attrs)
-{
- if (s->security_extn && !attrs.secure) {
- if (s->running_priority[cpu] & 0x80) {
- /* Running priority in upper half of range: return the Non-secure
- * view of the priority.
- */
- return s->running_priority[cpu] << 1;
- } else {
- /* Running priority in lower half of range: RAZ */
- return 0;
- }
- } else {
- return s->running_priority[cpu];
- }
-}
-
-/* Return true if we should split priority drop and interrupt deactivation,
- * ie whether the relevant EOIMode bit is set.
- */
-static bool gic_eoi_split(GICState *s, int cpu, MemTxAttrs attrs)
-{
- if (s->revision != 2) {
- /* Before GICv2 prio-drop and deactivate are not separable */
- return false;
- }
- if (s->security_extn && !attrs.secure) {
- return s->cpu_ctlr[cpu] & GICC_CTLR_EOIMODE_NS;
- }
- return s->cpu_ctlr[cpu] & GICC_CTLR_EOIMODE;
-}
-
-static void gic_deactivate_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs)
-{
- int cm = 1 << cpu;
- int group = gic_has_groups(s) && GIC_TEST_GROUP(irq, cm);
-
- if (!gic_eoi_split(s, cpu, attrs)) {
- /* This is UNPREDICTABLE; we choose to ignore it */
- qemu_log_mask(LOG_GUEST_ERROR,
- "gic_deactivate_irq: GICC_DIR write when EOIMode clear");
- return;
- }
-
- if (s->security_extn && !attrs.secure && !group) {
- DPRINTF("Non-secure DI for Group0 interrupt %d ignored\n", irq);
- return;
- }
-
- GIC_CLEAR_ACTIVE(irq, cm);
-}
-
-void gic_complete_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs)
-{
- int cm = 1 << cpu;
- int group;
-
- DPRINTF("EOI %d\n", irq);
- if (irq >= s->num_irq) {
- /* This handles two cases:
- * 1. If software writes the ID of a spurious interrupt [ie 1023]
- * to the GICC_EOIR, the GIC ignores that write.
- * 2. If software writes the number of a non-existent interrupt
- * this must be a subcase of "value written does not match the last
- * valid interrupt value read from the Interrupt Acknowledge
- * register" and so this is UNPREDICTABLE. We choose to ignore it.
- */
- return;
- }
- if (s->running_priority[cpu] == 0x100) {
- return; /* No active IRQ. */
- }
-
- if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) {
- /* Mark level triggered interrupts as pending if they are still
- raised. */
- if (!GIC_TEST_EDGE_TRIGGER(irq) && GIC_TEST_ENABLED(irq, cm)
- && GIC_TEST_LEVEL(irq, cm) && (GIC_TARGET(irq) & cm) != 0) {
- DPRINTF("Set %d pending mask %x\n", irq, cm);
- GIC_SET_PENDING(irq, cm);
- }
- }
-
- group = gic_has_groups(s) && GIC_TEST_GROUP(irq, cm);
-
- if (s->security_extn && !attrs.secure && !group) {
- DPRINTF("Non-secure EOI for Group0 interrupt %d ignored\n", irq);
- return;
- }
-
- /* Secure EOI with GICC_CTLR.AckCtl == 0 when the IRQ is a Group 1
- * interrupt is UNPREDICTABLE. We choose to handle it as if AckCtl == 1,
- * i.e. go ahead and complete the irq anyway.
- */
-
- gic_drop_prio(s, cpu, group);
-
- /* In GICv2 the guest can choose to split priority-drop and deactivate */
- if (!gic_eoi_split(s, cpu, attrs)) {
- GIC_CLEAR_ACTIVE(irq, cm);
- }
- gic_update(s);
-}
-
-static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs)
-{
- GICState *s = (GICState *)opaque;
- uint32_t res;
- int irq;
- int i;
- int cpu;
- int cm;
- int mask;
-
- cpu = gic_get_current_cpu(s);
- cm = 1 << cpu;
- if (offset < 0x100) {
- if (offset == 0) { /* GICD_CTLR */
- if (s->security_extn && !attrs.secure) {
- /* The NS bank of this register is just an alias of the
- * EnableGrp1 bit in the S bank version.
- */
- return extract32(s->ctlr, 1, 1);
- } else {
- return s->ctlr;
- }
- }
- if (offset == 4)
- /* Interrupt Controller Type Register */
- return ((s->num_irq / 32) - 1)
- | ((s->num_cpu - 1) << 5)
- | (s->security_extn << 10);
- if (offset < 0x08)
- return 0;
- if (offset >= 0x80) {
- /* Interrupt Group Registers: these RAZ/WI if this is an NS
- * access to a GIC with the security extensions, or if the GIC
- * doesn't have groups at all.
- */
- res = 0;
- if (!(s->security_extn && !attrs.secure) && gic_has_groups(s)) {
- /* Every byte offset holds 8 group status bits */
- irq = (offset - 0x080) * 8 + GIC_BASE_IRQ;
- if (irq >= s->num_irq) {
- goto bad_reg;
- }
- for (i = 0; i < 8; i++) {
- if (GIC_TEST_GROUP(irq + i, cm)) {
- res |= (1 << i);
- }
- }
- }
- return res;
- }
- goto bad_reg;
- } else if (offset < 0x200) {
- /* Interrupt Set/Clear Enable. */
- if (offset < 0x180)
- irq = (offset - 0x100) * 8;
- else
- irq = (offset - 0x180) * 8;
- irq += GIC_BASE_IRQ;
- if (irq >= s->num_irq)
- goto bad_reg;
- res = 0;
- for (i = 0; i < 8; i++) {
- if (GIC_TEST_ENABLED(irq + i, cm)) {
- res |= (1 << i);
- }
- }
- } else if (offset < 0x300) {
- /* Interrupt Set/Clear Pending. */
- if (offset < 0x280)
- irq = (offset - 0x200) * 8;
- else
- irq = (offset - 0x280) * 8;
- irq += GIC_BASE_IRQ;
- if (irq >= s->num_irq)
- goto bad_reg;
- res = 0;
- mask = (irq < GIC_INTERNAL) ? cm : ALL_CPU_MASK;
- for (i = 0; i < 8; i++) {
- if (gic_test_pending(s, irq + i, mask)) {
- res |= (1 << i);
- }
- }
- } else if (offset < 0x400) {
- /* Interrupt Active. */
- irq = (offset - 0x300) * 8 + GIC_BASE_IRQ;
- if (irq >= s->num_irq)
- goto bad_reg;
- res = 0;
- mask = (irq < GIC_INTERNAL) ? cm : ALL_CPU_MASK;
- for (i = 0; i < 8; i++) {
- if (GIC_TEST_ACTIVE(irq + i, mask)) {
- res |= (1 << i);
- }
- }
- } else if (offset < 0x800) {
- /* Interrupt Priority. */
- irq = (offset - 0x400) + GIC_BASE_IRQ;
- if (irq >= s->num_irq)
- goto bad_reg;
- res = gic_get_priority(s, cpu, irq, attrs);
- } else if (offset < 0xc00) {
- /* Interrupt CPU Target. */
- if (s->num_cpu == 1 && s->revision != REV_11MPCORE) {
- /* For uniprocessor GICs these RAZ/WI */
- res = 0;
- } else {
- irq = (offset - 0x800) + GIC_BASE_IRQ;
- if (irq >= s->num_irq) {
- goto bad_reg;
- }
- if (irq >= 29 && irq <= 31) {
- res = cm;
- } else {
- res = GIC_TARGET(irq);
- }
- }
- } else if (offset < 0xf00) {
- /* Interrupt Configuration. */
- irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ;
- if (irq >= s->num_irq)
- goto bad_reg;
- res = 0;
- for (i = 0; i < 4; i++) {
- if (GIC_TEST_MODEL(irq + i))
- res |= (1 << (i * 2));
- if (GIC_TEST_EDGE_TRIGGER(irq + i))
- res |= (2 << (i * 2));
- }
- } else if (offset < 0xf10) {
- goto bad_reg;
- } else if (offset < 0xf30) {
- if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) {
- goto bad_reg;
- }
-
- if (offset < 0xf20) {
- /* GICD_CPENDSGIRn */
- irq = (offset - 0xf10);
- } else {
- irq = (offset - 0xf20);
- /* GICD_SPENDSGIRn */
- }
-
- res = s->sgi_pending[irq][cpu];
- } else if (offset < 0xfd0) {
- goto bad_reg;
- } else if (offset < 0x1000) {
- if (offset & 3) {
- res = 0;
- } else {
- switch (s->revision) {
- case REV_11MPCORE:
- res = gic_id_11mpcore[(offset - 0xfd0) >> 2];
- break;
- case 1:
- res = gic_id_gicv1[(offset - 0xfd0) >> 2];
- break;
- case 2:
- res = gic_id_gicv2[(offset - 0xfd0) >> 2];
- break;
- case REV_NVIC:
- /* Shouldn't be able to get here */
- abort();
- default:
- res = 0;
- }
- }
- } else {
- g_assert_not_reached();
- }
- return res;
-bad_reg:
- qemu_log_mask(LOG_GUEST_ERROR,
- "gic_dist_readb: Bad offset %x\n", (int)offset);
- return 0;
-}
-
-static MemTxResult gic_dist_read(void *opaque, hwaddr offset, uint64_t *data,
- unsigned size, MemTxAttrs attrs)
-{
- switch (size) {
- case 1:
- *data = gic_dist_readb(opaque, offset, attrs);
- return MEMTX_OK;
- case 2:
- *data = gic_dist_readb(opaque, offset, attrs);
- *data |= gic_dist_readb(opaque, offset + 1, attrs) << 8;
- return MEMTX_OK;
- case 4:
- *data = gic_dist_readb(opaque, offset, attrs);
- *data |= gic_dist_readb(opaque, offset + 1, attrs) << 8;
- *data |= gic_dist_readb(opaque, offset + 2, attrs) << 16;
- *data |= gic_dist_readb(opaque, offset + 3, attrs) << 24;
- return MEMTX_OK;
- default:
- return MEMTX_ERROR;
- }
-}
-
-static void gic_dist_writeb(void *opaque, hwaddr offset,
- uint32_t value, MemTxAttrs attrs)
-{
- GICState *s = (GICState *)opaque;
- int irq;
- int i;
- int cpu;
-
- cpu = gic_get_current_cpu(s);
- if (offset < 0x100) {
- if (offset == 0) {
- if (s->security_extn && !attrs.secure) {
- /* NS version is just an alias of the S version's bit 1 */
- s->ctlr = deposit32(s->ctlr, 1, 1, value);
- } else if (gic_has_groups(s)) {
- s->ctlr = value & (GICD_CTLR_EN_GRP0 | GICD_CTLR_EN_GRP1);
- } else {
- s->ctlr = value & GICD_CTLR_EN_GRP0;
- }
- DPRINTF("Distributor: Group0 %sabled; Group 1 %sabled\n",
- s->ctlr & GICD_CTLR_EN_GRP0 ? "En" : "Dis",
- s->ctlr & GICD_CTLR_EN_GRP1 ? "En" : "Dis");
- } else if (offset < 4) {
- /* ignored. */
- } else if (offset >= 0x80) {
- /* Interrupt Group Registers: RAZ/WI for NS access to secure
- * GIC, or for GICs without groups.
- */
- if (!(s->security_extn && !attrs.secure) && gic_has_groups(s)) {
- /* Every byte offset holds 8 group status bits */
- irq = (offset - 0x80) * 8 + GIC_BASE_IRQ;
- if (irq >= s->num_irq) {
- goto bad_reg;
- }
- for (i = 0; i < 8; i++) {
- /* Group bits are banked for private interrupts */
- int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK;
- if (value & (1 << i)) {
- /* Group1 (Non-secure) */
- GIC_SET_GROUP(irq + i, cm);
- } else {
- /* Group0 (Secure) */
- GIC_CLEAR_GROUP(irq + i, cm);
- }
- }
- }
- } else {
- goto bad_reg;
- }
- } else if (offset < 0x180) {
- /* Interrupt Set Enable. */
- irq = (offset - 0x100) * 8 + GIC_BASE_IRQ;
- if (irq >= s->num_irq)
- goto bad_reg;
- if (irq < GIC_NR_SGIS) {
- value = 0xff;
- }
-
- for (i = 0; i < 8; i++) {
- if (value & (1 << i)) {
- int mask =
- (irq < GIC_INTERNAL) ? (1 << cpu) : GIC_TARGET(irq + i);
- int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK;
-
- if (!GIC_TEST_ENABLED(irq + i, cm)) {
- DPRINTF("Enabled IRQ %d\n", irq + i);
- }
- GIC_SET_ENABLED(irq + i, cm);
- /* If a raised level triggered IRQ enabled then mark
- is as pending. */
- if (GIC_TEST_LEVEL(irq + i, mask)
- && !GIC_TEST_EDGE_TRIGGER(irq + i)) {
- DPRINTF("Set %d pending mask %x\n", irq + i, mask);
- GIC_SET_PENDING(irq + i, mask);
- }
- }
- }
- } else if (offset < 0x200) {
- /* Interrupt Clear Enable. */
- irq = (offset - 0x180) * 8 + GIC_BASE_IRQ;
- if (irq >= s->num_irq)
- goto bad_reg;
- if (irq < GIC_NR_SGIS) {
- value = 0;
- }
-
- for (i = 0; i < 8; i++) {
- if (value & (1 << i)) {
- int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK;
-
- if (GIC_TEST_ENABLED(irq + i, cm)) {
- DPRINTF("Disabled IRQ %d\n", irq + i);
- }
- GIC_CLEAR_ENABLED(irq + i, cm);
- }
- }
- } else if (offset < 0x280) {
- /* Interrupt Set Pending. */
- irq = (offset - 0x200) * 8 + GIC_BASE_IRQ;
- if (irq >= s->num_irq)
- goto bad_reg;
- if (irq < GIC_NR_SGIS) {
- value = 0;
- }
-
- for (i = 0; i < 8; i++) {
- if (value & (1 << i)) {
- GIC_SET_PENDING(irq + i, GIC_TARGET(irq + i));
- }
- }
- } else if (offset < 0x300) {
- /* Interrupt Clear Pending. */
- irq = (offset - 0x280) * 8 + GIC_BASE_IRQ;
- if (irq >= s->num_irq)
- goto bad_reg;
- if (irq < GIC_NR_SGIS) {
- value = 0;
- }
-
- for (i = 0; i < 8; i++) {
- /* ??? This currently clears the pending bit for all CPUs, even
- for per-CPU interrupts. It's unclear whether this is the
- corect behavior. */
- if (value & (1 << i)) {
- GIC_CLEAR_PENDING(irq + i, ALL_CPU_MASK);
- }
- }
- } else if (offset < 0x400) {
- /* Interrupt Active. */
- goto bad_reg;
- } else if (offset < 0x800) {
- /* Interrupt Priority. */
- irq = (offset - 0x400) + GIC_BASE_IRQ;
- if (irq >= s->num_irq)
- goto bad_reg;
- gic_set_priority(s, cpu, irq, value, attrs);
- } else if (offset < 0xc00) {
- /* Interrupt CPU Target. RAZ/WI on uniprocessor GICs, with the
- * annoying exception of the 11MPCore's GIC.
- */
- if (s->num_cpu != 1 || s->revision == REV_11MPCORE) {
- irq = (offset - 0x800) + GIC_BASE_IRQ;
- if (irq >= s->num_irq) {
- goto bad_reg;
- }
- if (irq < 29) {
- value = 0;
- } else if (irq < GIC_INTERNAL) {
- value = ALL_CPU_MASK;
- }
- s->irq_target[irq] = value & ALL_CPU_MASK;
- }
- } else if (offset < 0xf00) {
- /* Interrupt Configuration. */
- irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ;
- if (irq >= s->num_irq)
- goto bad_reg;
- if (irq < GIC_NR_SGIS)
- value |= 0xaa;
- for (i = 0; i < 4; i++) {
- if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) {
- if (value & (1 << (i * 2))) {
- GIC_SET_MODEL(irq + i);
- } else {
- GIC_CLEAR_MODEL(irq + i);
- }
- }
- if (value & (2 << (i * 2))) {
- GIC_SET_EDGE_TRIGGER(irq + i);
- } else {
- GIC_CLEAR_EDGE_TRIGGER(irq + i);
- }
- }
- } else if (offset < 0xf10) {
- /* 0xf00 is only handled for 32-bit writes. */
- goto bad_reg;
- } else if (offset < 0xf20) {
- /* GICD_CPENDSGIRn */
- if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) {
- goto bad_reg;
- }
- irq = (offset - 0xf10);
-
- s->sgi_pending[irq][cpu] &= ~value;
- if (s->sgi_pending[irq][cpu] == 0) {
- GIC_CLEAR_PENDING(irq, 1 << cpu);
- }
- } else if (offset < 0xf30) {
- /* GICD_SPENDSGIRn */
- if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) {
- goto bad_reg;
- }
- irq = (offset - 0xf20);
-
- GIC_SET_PENDING(irq, 1 << cpu);
- s->sgi_pending[irq][cpu] |= value;
- } else {
- goto bad_reg;
- }
- gic_update(s);
- return;
-bad_reg:
- qemu_log_mask(LOG_GUEST_ERROR,
- "gic_dist_writeb: Bad offset %x\n", (int)offset);
-}
-
-static void gic_dist_writew(void *opaque, hwaddr offset,
- uint32_t value, MemTxAttrs attrs)
-{
- gic_dist_writeb(opaque, offset, value & 0xff, attrs);
- gic_dist_writeb(opaque, offset + 1, value >> 8, attrs);
-}
-
-static void gic_dist_writel(void *opaque, hwaddr offset,
- uint32_t value, MemTxAttrs attrs)
-{
- GICState *s = (GICState *)opaque;
- if (offset == 0xf00) {
- int cpu;
- int irq;
- int mask;
- int target_cpu;
-
- cpu = gic_get_current_cpu(s);
- irq = value & 0x3ff;
- switch ((value >> 24) & 3) {
- case 0:
- mask = (value >> 16) & ALL_CPU_MASK;
- break;
- case 1:
- mask = ALL_CPU_MASK ^ (1 << cpu);
- break;
- case 2:
- mask = 1 << cpu;
- break;
- default:
- DPRINTF("Bad Soft Int target filter\n");
- mask = ALL_CPU_MASK;
- break;
- }
- GIC_SET_PENDING(irq, mask);
- target_cpu = ctz32(mask);
- while (target_cpu < GIC_NCPU) {
- s->sgi_pending[irq][target_cpu] |= (1 << cpu);
- mask &= ~(1 << target_cpu);
- target_cpu = ctz32(mask);
- }
- gic_update(s);
- return;
- }
- gic_dist_writew(opaque, offset, value & 0xffff, attrs);
- gic_dist_writew(opaque, offset + 2, value >> 16, attrs);
-}
-
-static MemTxResult gic_dist_write(void *opaque, hwaddr offset, uint64_t data,
- unsigned size, MemTxAttrs attrs)
-{
- switch (size) {
- case 1:
- gic_dist_writeb(opaque, offset, data, attrs);
- return MEMTX_OK;
- case 2:
- gic_dist_writew(opaque, offset, data, attrs);
- return MEMTX_OK;
- case 4:
- gic_dist_writel(opaque, offset, data, attrs);
- return MEMTX_OK;
- default:
- return MEMTX_ERROR;
- }
-}
-
-static inline uint32_t gic_apr_ns_view(GICState *s, int cpu, int regno)
-{
- /* Return the Nonsecure view of GICC_APR<regno>. This is the
- * second half of GICC_NSAPR.
- */
- switch (GIC_MIN_BPR) {
- case 0:
- if (regno < 2) {
- return s->nsapr[regno + 2][cpu];
- }
- break;
- case 1:
- if (regno == 0) {
- return s->nsapr[regno + 1][cpu];
- }
- break;
- case 2:
- if (regno == 0) {
- return extract32(s->nsapr[0][cpu], 16, 16);
- }
- break;
- case 3:
- if (regno == 0) {
- return extract32(s->nsapr[0][cpu], 8, 8);
- }
- break;
- default:
- g_assert_not_reached();
- }
- return 0;
-}
-
-static inline void gic_apr_write_ns_view(GICState *s, int cpu, int regno,
- uint32_t value)
-{
- /* Write the Nonsecure view of GICC_APR<regno>. */
- switch (GIC_MIN_BPR) {
- case 0:
- if (regno < 2) {
- s->nsapr[regno + 2][cpu] = value;
- }
- break;
- case 1:
- if (regno == 0) {
- s->nsapr[regno + 1][cpu] = value;
- }
- break;
- case 2:
- if (regno == 0) {
- s->nsapr[0][cpu] = deposit32(s->nsapr[0][cpu], 16, 16, value);
- }
- break;
- case 3:
- if (regno == 0) {
- s->nsapr[0][cpu] = deposit32(s->nsapr[0][cpu], 8, 8, value);
- }
- break;
- default:
- g_assert_not_reached();
- }
-}
-
-static MemTxResult gic_cpu_read(GICState *s, int cpu, int offset,
- uint64_t *data, MemTxAttrs attrs)
-{
- switch (offset) {
- case 0x00: /* Control */
- *data = gic_get_cpu_control(s, cpu, attrs);
- break;
- case 0x04: /* Priority mask */
- *data = gic_get_priority_mask(s, cpu, attrs);
- break;
- case 0x08: /* Binary Point */
- if (s->security_extn && !attrs.secure) {
- /* BPR is banked. Non-secure copy stored in ABPR. */
- *data = s->abpr[cpu];
- } else {
- *data = s->bpr[cpu];
- }
- break;
- case 0x0c: /* Acknowledge */
- *data = gic_acknowledge_irq(s, cpu, attrs);
- break;
- case 0x14: /* Running Priority */
- *data = gic_get_running_priority(s, cpu, attrs);
- break;
- case 0x18: /* Highest Pending Interrupt */
- *data = gic_get_current_pending_irq(s, cpu, attrs);
- break;
- case 0x1c: /* Aliased Binary Point */
- /* GIC v2, no security: ABPR
- * GIC v1, no security: not implemented (RAZ/WI)
- * With security extensions, secure access: ABPR (alias of NS BPR)
- * With security extensions, nonsecure access: RAZ/WI
- */
- if (!gic_has_groups(s) || (s->security_extn && !attrs.secure)) {
- *data = 0;
- } else {
- *data = s->abpr[cpu];
- }
- break;
- case 0xd0: case 0xd4: case 0xd8: case 0xdc:
- {
- int regno = (offset - 0xd0) / 4;
-
- if (regno >= GIC_NR_APRS || s->revision != 2) {
- *data = 0;
- } else if (s->security_extn && !attrs.secure) {
- /* NS view of GICC_APR<n> is the top half of GIC_NSAPR<n> */
- *data = gic_apr_ns_view(s, regno, cpu);
- } else {
- *data = s->apr[regno][cpu];
- }
- break;
- }
- case 0xe0: case 0xe4: case 0xe8: case 0xec:
- {
- int regno = (offset - 0xe0) / 4;
-
- if (regno >= GIC_NR_APRS || s->revision != 2 || !gic_has_groups(s) ||
- (s->security_extn && !attrs.secure)) {
- *data = 0;
- } else {
- *data = s->nsapr[regno][cpu];
- }
- break;
- }
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "gic_cpu_read: Bad offset %x\n", (int)offset);
- return MEMTX_ERROR;
- }
- return MEMTX_OK;
-}
-
-static MemTxResult gic_cpu_write(GICState *s, int cpu, int offset,
- uint32_t value, MemTxAttrs attrs)
-{
- switch (offset) {
- case 0x00: /* Control */
- gic_set_cpu_control(s, cpu, value, attrs);
- break;
- case 0x04: /* Priority mask */
- gic_set_priority_mask(s, cpu, value, attrs);
- break;
- case 0x08: /* Binary Point */
- if (s->security_extn && !attrs.secure) {
- s->abpr[cpu] = MAX(value & 0x7, GIC_MIN_ABPR);
- } else {
- s->bpr[cpu] = MAX(value & 0x7, GIC_MIN_BPR);
- }
- break;
- case 0x10: /* End Of Interrupt */
- gic_complete_irq(s, cpu, value & 0x3ff, attrs);
- return MEMTX_OK;
- case 0x1c: /* Aliased Binary Point */
- if (!gic_has_groups(s) || (s->security_extn && !attrs.secure)) {
- /* unimplemented, or NS access: RAZ/WI */
- return MEMTX_OK;
- } else {
- s->abpr[cpu] = MAX(value & 0x7, GIC_MIN_ABPR);
- }
- break;
- case 0xd0: case 0xd4: case 0xd8: case 0xdc:
- {
- int regno = (offset - 0xd0) / 4;
-
- if (regno >= GIC_NR_APRS || s->revision != 2) {
- return MEMTX_OK;
- }
- if (s->security_extn && !attrs.secure) {
- /* NS view of GICC_APR<n> is the top half of GIC_NSAPR<n> */
- gic_apr_write_ns_view(s, regno, cpu, value);
- } else {
- s->apr[regno][cpu] = value;
- }
- break;
- }
- case 0xe0: case 0xe4: case 0xe8: case 0xec:
- {
- int regno = (offset - 0xe0) / 4;
-
- if (regno >= GIC_NR_APRS || s->revision != 2) {
- return MEMTX_OK;
- }
- if (!gic_has_groups(s) || (s->security_extn && !attrs.secure)) {
- return MEMTX_OK;
- }
- s->nsapr[regno][cpu] = value;
- break;
- }
- case 0x1000:
- /* GICC_DIR */
- gic_deactivate_irq(s, cpu, value & 0x3ff, attrs);
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "gic_cpu_write: Bad offset %x\n", (int)offset);
- return MEMTX_ERROR;
- }
- gic_update(s);
- return MEMTX_OK;
-}
-
-/* Wrappers to read/write the GIC CPU interface for the current CPU */
-static MemTxResult gic_thiscpu_read(void *opaque, hwaddr addr, uint64_t *data,
- unsigned size, MemTxAttrs attrs)
-{
- GICState *s = (GICState *)opaque;
- return gic_cpu_read(s, gic_get_current_cpu(s), addr, data, attrs);
-}
-
-static MemTxResult gic_thiscpu_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size,
- MemTxAttrs attrs)
-{
- GICState *s = (GICState *)opaque;
- return gic_cpu_write(s, gic_get_current_cpu(s), addr, value, attrs);
-}
-
-/* Wrappers to read/write the GIC CPU interface for a specific CPU.
- * These just decode the opaque pointer into GICState* + cpu id.
- */
-static MemTxResult gic_do_cpu_read(void *opaque, hwaddr addr, uint64_t *data,
- unsigned size, MemTxAttrs attrs)
-{
- GICState **backref = (GICState **)opaque;
- GICState *s = *backref;
- int id = (backref - s->backref);
- return gic_cpu_read(s, id, addr, data, attrs);
-}
-
-static MemTxResult gic_do_cpu_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size,
- MemTxAttrs attrs)
-{
- GICState **backref = (GICState **)opaque;
- GICState *s = *backref;
- int id = (backref - s->backref);
- return gic_cpu_write(s, id, addr, value, attrs);
-}
-
-static const MemoryRegionOps gic_ops[2] = {
- {
- .read_with_attrs = gic_dist_read,
- .write_with_attrs = gic_dist_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- },
- {
- .read_with_attrs = gic_thiscpu_read,
- .write_with_attrs = gic_thiscpu_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- }
-};
-
-static const MemoryRegionOps gic_cpu_ops = {
- .read_with_attrs = gic_do_cpu_read,
- .write_with_attrs = gic_do_cpu_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-/* This function is used by nvic model */
-void gic_init_irqs_and_distributor(GICState *s)
-{
- gic_init_irqs_and_mmio(s, gic_set_irq, gic_ops);
-}
-
-static void arm_gic_realize(DeviceState *dev, Error **errp)
-{
- /* Device instance realize function for the GIC sysbus device */
- int i;
- GICState *s = ARM_GIC(dev);
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- ARMGICClass *agc = ARM_GIC_GET_CLASS(s);
- Error *local_err = NULL;
-
- agc->parent_realize(dev, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- /* This creates distributor and main CPU interface (s->cpuiomem[0]) */
- gic_init_irqs_and_mmio(s, gic_set_irq, gic_ops);
-
- /* Extra core-specific regions for the CPU interfaces. This is
- * necessary for "franken-GIC" implementations, for example on
- * Exynos 4.
- * NB that the memory region size of 0x100 applies for the 11MPCore
- * and also cores following the GIC v1 spec (ie A9).
- * GIC v2 defines a larger memory region (0x1000) so this will need
- * to be extended when we implement A15.
- */
- for (i = 0; i < s->num_cpu; i++) {
- s->backref[i] = s;
- memory_region_init_io(&s->cpuiomem[i+1], OBJECT(s), &gic_cpu_ops,
- &s->backref[i], "gic_cpu", 0x100);
- sysbus_init_mmio(sbd, &s->cpuiomem[i+1]);
- }
-}
-
-static void arm_gic_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- ARMGICClass *agc = ARM_GIC_CLASS(klass);
-
- agc->parent_realize = dc->realize;
- dc->realize = arm_gic_realize;
-}
-
-static const TypeInfo arm_gic_info = {
- .name = TYPE_ARM_GIC,
- .parent = TYPE_ARM_GIC_COMMON,
- .instance_size = sizeof(GICState),
- .class_init = arm_gic_class_init,
- .class_size = sizeof(ARMGICClass),
-};
-
-static void arm_gic_register_types(void)
-{
- type_register_static(&arm_gic_info);
-}
-
-type_init(arm_gic_register_types)
diff --git a/qemu/hw/intc/arm_gic_common.c b/qemu/hw/intc/arm_gic_common.c
deleted file mode 100644
index 0a1f56af1..000000000
--- a/qemu/hw/intc/arm_gic_common.c
+++ /dev/null
@@ -1,290 +0,0 @@
-/*
- * ARM GIC support - common bits of emulated and KVM kernel model
- *
- * Copyright (c) 2012 Linaro Limited
- * Written by Peter Maydell
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "gic_internal.h"
-#include "hw/arm/linux-boot-if.h"
-
-static void gic_pre_save(void *opaque)
-{
- GICState *s = (GICState *)opaque;
- ARMGICCommonClass *c = ARM_GIC_COMMON_GET_CLASS(s);
-
- if (c->pre_save) {
- c->pre_save(s);
- }
-}
-
-static int gic_post_load(void *opaque, int version_id)
-{
- GICState *s = (GICState *)opaque;
- ARMGICCommonClass *c = ARM_GIC_COMMON_GET_CLASS(s);
-
- if (c->post_load) {
- c->post_load(s);
- }
- return 0;
-}
-
-static const VMStateDescription vmstate_gic_irq_state = {
- .name = "arm_gic_irq_state",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(enabled, gic_irq_state),
- VMSTATE_UINT8(pending, gic_irq_state),
- VMSTATE_UINT8(active, gic_irq_state),
- VMSTATE_UINT8(level, gic_irq_state),
- VMSTATE_BOOL(model, gic_irq_state),
- VMSTATE_BOOL(edge_trigger, gic_irq_state),
- VMSTATE_UINT8(group, gic_irq_state),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_gic = {
- .name = "arm_gic",
- .version_id = 12,
- .minimum_version_id = 12,
- .pre_save = gic_pre_save,
- .post_load = gic_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(ctlr, GICState),
- VMSTATE_UINT32_ARRAY(cpu_ctlr, GICState, GIC_NCPU),
- VMSTATE_STRUCT_ARRAY(irq_state, GICState, GIC_MAXIRQ, 1,
- vmstate_gic_irq_state, gic_irq_state),
- VMSTATE_UINT8_ARRAY(irq_target, GICState, GIC_MAXIRQ),
- VMSTATE_UINT8_2DARRAY(priority1, GICState, GIC_INTERNAL, GIC_NCPU),
- VMSTATE_UINT8_ARRAY(priority2, GICState, GIC_MAXIRQ - GIC_INTERNAL),
- VMSTATE_UINT8_2DARRAY(sgi_pending, GICState, GIC_NR_SGIS, GIC_NCPU),
- VMSTATE_UINT16_ARRAY(priority_mask, GICState, GIC_NCPU),
- VMSTATE_UINT16_ARRAY(running_priority, GICState, GIC_NCPU),
- VMSTATE_UINT16_ARRAY(current_pending, GICState, GIC_NCPU),
- VMSTATE_UINT8_ARRAY(bpr, GICState, GIC_NCPU),
- VMSTATE_UINT8_ARRAY(abpr, GICState, GIC_NCPU),
- VMSTATE_UINT32_2DARRAY(apr, GICState, GIC_NR_APRS, GIC_NCPU),
- VMSTATE_UINT32_2DARRAY(nsapr, GICState, GIC_NR_APRS, GIC_NCPU),
- VMSTATE_END_OF_LIST()
- }
-};
-
-void gic_init_irqs_and_mmio(GICState *s, qemu_irq_handler handler,
- const MemoryRegionOps *ops)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(s);
- int i = s->num_irq - GIC_INTERNAL;
-
- /* For the GIC, also expose incoming GPIO lines for PPIs for each CPU.
- * GPIO array layout is thus:
- * [0..N-1] SPIs
- * [N..N+31] PPIs for CPU 0
- * [N+32..N+63] PPIs for CPU 1
- * ...
- */
- if (s->revision != REV_NVIC) {
- i += (GIC_INTERNAL * s->num_cpu);
- }
- qdev_init_gpio_in(DEVICE(s), handler, i);
-
- for (i = 0; i < s->num_cpu; i++) {
- sysbus_init_irq(sbd, &s->parent_irq[i]);
- }
- for (i = 0; i < s->num_cpu; i++) {
- sysbus_init_irq(sbd, &s->parent_fiq[i]);
- }
-
- /* Distributor */
- memory_region_init_io(&s->iomem, OBJECT(s), ops, s, "gic_dist", 0x1000);
- sysbus_init_mmio(sbd, &s->iomem);
-
- if (s->revision != REV_NVIC) {
- /* This is the main CPU interface "for this core". It is always
- * present because it is required by both software emulation and KVM.
- * NVIC is not handled here because its CPU interface is different,
- * neither it can use KVM.
- */
- memory_region_init_io(&s->cpuiomem[0], OBJECT(s), ops ? &ops[1] : NULL,
- s, "gic_cpu", s->revision == 2 ? 0x2000 : 0x100);
- sysbus_init_mmio(sbd, &s->cpuiomem[0]);
- }
-}
-
-static void arm_gic_common_realize(DeviceState *dev, Error **errp)
-{
- GICState *s = ARM_GIC_COMMON(dev);
- int num_irq = s->num_irq;
-
- if (s->num_cpu > GIC_NCPU) {
- error_setg(errp, "requested %u CPUs exceeds GIC maximum %d",
- s->num_cpu, GIC_NCPU);
- return;
- }
- s->num_irq += GIC_BASE_IRQ;
- if (s->num_irq > GIC_MAXIRQ) {
- error_setg(errp,
- "requested %u interrupt lines exceeds GIC maximum %d",
- num_irq, GIC_MAXIRQ);
- return;
- }
- /* ITLinesNumber is represented as (N / 32) - 1 (see
- * gic_dist_readb) so this is an implementation imposed
- * restriction, not an architectural one:
- */
- if (s->num_irq < 32 || (s->num_irq % 32)) {
- error_setg(errp,
- "%d interrupt lines unsupported: not divisible by 32",
- num_irq);
- return;
- }
-
- if (s->security_extn &&
- (s->revision == REV_11MPCORE || s->revision == REV_NVIC)) {
- error_setg(errp, "this GIC revision does not implement "
- "the security extensions");
- return;
- }
-}
-
-static void arm_gic_common_reset(DeviceState *dev)
-{
- GICState *s = ARM_GIC_COMMON(dev);
- int i, j;
- int resetprio;
-
- /* If we're resetting a TZ-aware GIC as if secure firmware
- * had set it up ready to start a kernel in non-secure,
- * we need to set interrupt priorities to a "zero for the
- * NS view" value. This is particularly critical for the
- * priority_mask[] values, because if they are zero then NS
- * code cannot ever rewrite the priority to anything else.
- */
- if (s->security_extn && s->irq_reset_nonsecure) {
- resetprio = 0x80;
- } else {
- resetprio = 0;
- }
-
- memset(s->irq_state, 0, GIC_MAXIRQ * sizeof(gic_irq_state));
- for (i = 0 ; i < s->num_cpu; i++) {
- if (s->revision == REV_11MPCORE) {
- s->priority_mask[i] = 0xf0;
- } else {
- s->priority_mask[i] = resetprio;
- }
- s->current_pending[i] = 1023;
- s->running_priority[i] = 0x100;
- s->cpu_ctlr[i] = 0;
- s->bpr[i] = GIC_MIN_BPR;
- s->abpr[i] = GIC_MIN_ABPR;
- for (j = 0; j < GIC_INTERNAL; j++) {
- s->priority1[j][i] = resetprio;
- }
- for (j = 0; j < GIC_NR_SGIS; j++) {
- s->sgi_pending[j][i] = 0;
- }
- }
- for (i = 0; i < GIC_NR_SGIS; i++) {
- GIC_SET_ENABLED(i, ALL_CPU_MASK);
- GIC_SET_EDGE_TRIGGER(i);
- }
-
- for (i = 0; i < ARRAY_SIZE(s->priority2); i++) {
- s->priority2[i] = resetprio;
- }
-
- for (i = 0; i < GIC_MAXIRQ; i++) {
- /* For uniprocessor GICs all interrupts always target the sole CPU */
- if (s->num_cpu == 1) {
- s->irq_target[i] = 1;
- } else {
- s->irq_target[i] = 0;
- }
- }
- if (s->security_extn && s->irq_reset_nonsecure) {
- for (i = 0; i < GIC_MAXIRQ; i++) {
- GIC_SET_GROUP(i, ALL_CPU_MASK);
- }
- }
-
- s->ctlr = 0;
-}
-
-static void arm_gic_common_linux_init(ARMLinuxBootIf *obj,
- bool secure_boot)
-{
- GICState *s = ARM_GIC_COMMON(obj);
-
- if (s->security_extn && !secure_boot) {
- /* We're directly booting a kernel into NonSecure. If this GIC
- * implements the security extensions then we must configure it
- * to have all the interrupts be NonSecure (this is a job that
- * is done by the Secure boot firmware in real hardware, and in
- * this mode QEMU is acting as a minimalist firmware-and-bootloader
- * equivalent).
- */
- s->irq_reset_nonsecure = true;
- }
-}
-
-static Property arm_gic_common_properties[] = {
- DEFINE_PROP_UINT32("num-cpu", GICState, num_cpu, 1),
- DEFINE_PROP_UINT32("num-irq", GICState, num_irq, 32),
- /* Revision can be 1 or 2 for GIC architecture specification
- * versions 1 or 2, or 0 to indicate the legacy 11MPCore GIC.
- * (Internally, 0xffffffff also indicates "not a GIC but an NVIC".)
- */
- DEFINE_PROP_UINT32("revision", GICState, revision, 1),
- /* True if the GIC should implement the security extensions */
- DEFINE_PROP_BOOL("has-security-extensions", GICState, security_extn, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void arm_gic_common_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- ARMLinuxBootIfClass *albifc = ARM_LINUX_BOOT_IF_CLASS(klass);
-
- dc->reset = arm_gic_common_reset;
- dc->realize = arm_gic_common_realize;
- dc->props = arm_gic_common_properties;
- dc->vmsd = &vmstate_gic;
- albifc->arm_linux_init = arm_gic_common_linux_init;
-}
-
-static const TypeInfo arm_gic_common_type = {
- .name = TYPE_ARM_GIC_COMMON,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(GICState),
- .class_size = sizeof(ARMGICCommonClass),
- .class_init = arm_gic_common_class_init,
- .abstract = true,
- .interfaces = (InterfaceInfo []) {
- { TYPE_ARM_LINUX_BOOT_IF },
- { },
- },
-};
-
-static void register_types(void)
-{
- type_register_static(&arm_gic_common_type);
-}
-
-type_init(register_types)
diff --git a/qemu/hw/intc/arm_gic_kvm.c b/qemu/hw/intc/arm_gic_kvm.c
deleted file mode 100644
index bc85ab769..000000000
--- a/qemu/hw/intc/arm_gic_kvm.c
+++ /dev/null
@@ -1,607 +0,0 @@
-/*
- * ARM Generic Interrupt Controller using KVM in-kernel support
- *
- * Copyright (c) 2012 Linaro Limited
- * Written by Peter Maydell
- * Save/Restore logic added by Christoffer Dall.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/sysbus.h"
-#include "migration/migration.h"
-#include "sysemu/kvm.h"
-#include "kvm_arm.h"
-#include "gic_internal.h"
-#include "vgic_common.h"
-
-//#define DEBUG_GIC_KVM
-
-#ifdef DEBUG_GIC_KVM
-static const int debug_gic_kvm = 1;
-#else
-static const int debug_gic_kvm = 0;
-#endif
-
-#define DPRINTF(fmt, ...) do { \
- if (debug_gic_kvm) { \
- printf("arm_gic: " fmt , ## __VA_ARGS__); \
- } \
- } while (0)
-
-#define TYPE_KVM_ARM_GIC "kvm-arm-gic"
-#define KVM_ARM_GIC(obj) \
- OBJECT_CHECK(GICState, (obj), TYPE_KVM_ARM_GIC)
-#define KVM_ARM_GIC_CLASS(klass) \
- OBJECT_CLASS_CHECK(KVMARMGICClass, (klass), TYPE_KVM_ARM_GIC)
-#define KVM_ARM_GIC_GET_CLASS(obj) \
- OBJECT_GET_CLASS(KVMARMGICClass, (obj), TYPE_KVM_ARM_GIC)
-
-typedef struct KVMARMGICClass {
- ARMGICCommonClass parent_class;
- DeviceRealize parent_realize;
- void (*parent_reset)(DeviceState *dev);
-} KVMARMGICClass;
-
-void kvm_arm_gic_set_irq(uint32_t num_irq, int irq, int level)
-{
- /* Meaning of the 'irq' parameter:
- * [0..N-1] : external interrupts
- * [N..N+31] : PPI (internal) interrupts for CPU 0
- * [N+32..N+63] : PPI (internal interrupts for CPU 1
- * ...
- * Convert this to the kernel's desired encoding, which
- * has separate fields in the irq number for type,
- * CPU number and interrupt number.
- */
- int kvm_irq, irqtype, cpu;
-
- if (irq < (num_irq - GIC_INTERNAL)) {
- /* External interrupt. The kernel numbers these like the GIC
- * hardware, with external interrupt IDs starting after the
- * internal ones.
- */
- irqtype = KVM_ARM_IRQ_TYPE_SPI;
- cpu = 0;
- irq += GIC_INTERNAL;
- } else {
- /* Internal interrupt: decode into (cpu, interrupt id) */
- irqtype = KVM_ARM_IRQ_TYPE_PPI;
- irq -= (num_irq - GIC_INTERNAL);
- cpu = irq / GIC_INTERNAL;
- irq %= GIC_INTERNAL;
- }
- kvm_irq = (irqtype << KVM_ARM_IRQ_TYPE_SHIFT)
- | (cpu << KVM_ARM_IRQ_VCPU_SHIFT) | irq;
-
- kvm_set_irq(kvm_state, kvm_irq, !!level);
-}
-
-static void kvm_arm_gicv2_set_irq(void *opaque, int irq, int level)
-{
- GICState *s = (GICState *)opaque;
-
- kvm_arm_gic_set_irq(s->num_irq, irq, level);
-}
-
-static bool kvm_arm_gic_can_save_restore(GICState *s)
-{
- return s->dev_fd >= 0;
-}
-
-#define KVM_VGIC_ATTR(offset, cpu) \
- ((((uint64_t)(cpu) << KVM_DEV_ARM_VGIC_CPUID_SHIFT) & \
- KVM_DEV_ARM_VGIC_CPUID_MASK) | \
- (((uint64_t)(offset) << KVM_DEV_ARM_VGIC_OFFSET_SHIFT) & \
- KVM_DEV_ARM_VGIC_OFFSET_MASK))
-
-static void kvm_gicd_access(GICState *s, int offset, int cpu,
- uint32_t *val, bool write)
-{
- kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_DIST_REGS,
- KVM_VGIC_ATTR(offset, cpu), val, write);
-}
-
-static void kvm_gicc_access(GICState *s, int offset, int cpu,
- uint32_t *val, bool write)
-{
- kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CPU_REGS,
- KVM_VGIC_ATTR(offset, cpu), val, write);
-}
-
-#define for_each_irq_reg(_ctr, _max_irq, _field_width) \
- for (_ctr = 0; _ctr < ((_max_irq) / (32 / (_field_width))); _ctr++)
-
-/*
- * Translate from the in-kernel field for an IRQ value to/from the qemu
- * representation.
- */
-typedef void (*vgic_translate_fn)(GICState *s, int irq, int cpu,
- uint32_t *field, bool to_kernel);
-
-/* synthetic translate function used for clear/set registers to completely
- * clear a setting using a clear-register before setting the remaining bits
- * using a set-register */
-static void translate_clear(GICState *s, int irq, int cpu,
- uint32_t *field, bool to_kernel)
-{
- if (to_kernel) {
- *field = ~0;
- } else {
- /* does not make sense: qemu model doesn't use set/clear regs */
- abort();
- }
-}
-
-static void translate_group(GICState *s, int irq, int cpu,
- uint32_t *field, bool to_kernel)
-{
- int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK;
-
- if (to_kernel) {
- *field = GIC_TEST_GROUP(irq, cm);
- } else {
- if (*field & 1) {
- GIC_SET_GROUP(irq, cm);
- }
- }
-}
-
-static void translate_enabled(GICState *s, int irq, int cpu,
- uint32_t *field, bool to_kernel)
-{
- int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK;
-
- if (to_kernel) {
- *field = GIC_TEST_ENABLED(irq, cm);
- } else {
- if (*field & 1) {
- GIC_SET_ENABLED(irq, cm);
- }
- }
-}
-
-static void translate_pending(GICState *s, int irq, int cpu,
- uint32_t *field, bool to_kernel)
-{
- int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK;
-
- if (to_kernel) {
- *field = gic_test_pending(s, irq, cm);
- } else {
- if (*field & 1) {
- GIC_SET_PENDING(irq, cm);
- /* TODO: Capture is level-line is held high in the kernel */
- }
- }
-}
-
-static void translate_active(GICState *s, int irq, int cpu,
- uint32_t *field, bool to_kernel)
-{
- int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK;
-
- if (to_kernel) {
- *field = GIC_TEST_ACTIVE(irq, cm);
- } else {
- if (*field & 1) {
- GIC_SET_ACTIVE(irq, cm);
- }
- }
-}
-
-static void translate_trigger(GICState *s, int irq, int cpu,
- uint32_t *field, bool to_kernel)
-{
- if (to_kernel) {
- *field = (GIC_TEST_EDGE_TRIGGER(irq)) ? 0x2 : 0x0;
- } else {
- if (*field & 0x2) {
- GIC_SET_EDGE_TRIGGER(irq);
- }
- }
-}
-
-static void translate_priority(GICState *s, int irq, int cpu,
- uint32_t *field, bool to_kernel)
-{
- if (to_kernel) {
- *field = GIC_GET_PRIORITY(irq, cpu) & 0xff;
- } else {
- gic_set_priority(s, cpu, irq, *field & 0xff, MEMTXATTRS_UNSPECIFIED);
- }
-}
-
-static void translate_targets(GICState *s, int irq, int cpu,
- uint32_t *field, bool to_kernel)
-{
- if (to_kernel) {
- *field = s->irq_target[irq] & 0xff;
- } else {
- s->irq_target[irq] = *field & 0xff;
- }
-}
-
-static void translate_sgisource(GICState *s, int irq, int cpu,
- uint32_t *field, bool to_kernel)
-{
- if (to_kernel) {
- *field = s->sgi_pending[irq][cpu] & 0xff;
- } else {
- s->sgi_pending[irq][cpu] = *field & 0xff;
- }
-}
-
-/* Read a register group from the kernel VGIC */
-static void kvm_dist_get(GICState *s, uint32_t offset, int width,
- int maxirq, vgic_translate_fn translate_fn)
-{
- uint32_t reg;
- int i;
- int j;
- int irq;
- int cpu;
- int regsz = 32 / width; /* irqs per kernel register */
- uint32_t field;
-
- for_each_irq_reg(i, maxirq, width) {
- irq = i * regsz;
- cpu = 0;
- while ((cpu < s->num_cpu && irq < GIC_INTERNAL) || cpu == 0) {
- kvm_gicd_access(s, offset, cpu, &reg, false);
- for (j = 0; j < regsz; j++) {
- field = extract32(reg, j * width, width);
- translate_fn(s, irq + j, cpu, &field, false);
- }
-
- cpu++;
- }
- offset += 4;
- }
-}
-
-/* Write a register group to the kernel VGIC */
-static void kvm_dist_put(GICState *s, uint32_t offset, int width,
- int maxirq, vgic_translate_fn translate_fn)
-{
- uint32_t reg;
- int i;
- int j;
- int irq;
- int cpu;
- int regsz = 32 / width; /* irqs per kernel register */
- uint32_t field;
-
- for_each_irq_reg(i, maxirq, width) {
- irq = i * regsz;
- cpu = 0;
- while ((cpu < s->num_cpu && irq < GIC_INTERNAL) || cpu == 0) {
- reg = 0;
- for (j = 0; j < regsz; j++) {
- translate_fn(s, irq + j, cpu, &field, true);
- reg = deposit32(reg, j * width, width, field);
- }
- kvm_gicd_access(s, offset, cpu, &reg, true);
-
- cpu++;
- }
- offset += 4;
- }
-}
-
-static void kvm_arm_gic_put(GICState *s)
-{
- uint32_t reg;
- int i;
- int cpu;
- int num_cpu;
- int num_irq;
-
- /* Note: We do the restore in a slightly different order than the save
- * (where the order doesn't matter and is simply ordered according to the
- * register offset values */
-
- /*****************************************************************
- * Distributor State
- */
-
- /* s->ctlr -> GICD_CTLR */
- reg = s->ctlr;
- kvm_gicd_access(s, 0x0, 0, &reg, true);
-
- /* Sanity checking on GICD_TYPER and s->num_irq, s->num_cpu */
- kvm_gicd_access(s, 0x4, 0, &reg, false);
- num_irq = ((reg & 0x1f) + 1) * 32;
- num_cpu = ((reg & 0xe0) >> 5) + 1;
-
- if (num_irq < s->num_irq) {
- fprintf(stderr, "Restoring %u IRQs, but kernel supports max %d\n",
- s->num_irq, num_irq);
- abort();
- } else if (num_cpu != s->num_cpu) {
- fprintf(stderr, "Restoring %u CPU interfaces, kernel only has %d\n",
- s->num_cpu, num_cpu);
- /* Did we not create the VCPUs in the kernel yet? */
- abort();
- }
-
- /* TODO: Consider checking compatibility with the IIDR ? */
-
- /* irq_state[n].enabled -> GICD_ISENABLERn */
- kvm_dist_put(s, 0x180, 1, s->num_irq, translate_clear);
- kvm_dist_put(s, 0x100, 1, s->num_irq, translate_enabled);
-
- /* irq_state[n].group -> GICD_IGROUPRn */
- kvm_dist_put(s, 0x80, 1, s->num_irq, translate_group);
-
- /* s->irq_target[irq] -> GICD_ITARGETSRn
- * (restore targets before pending to ensure the pending state is set on
- * the appropriate CPU interfaces in the kernel) */
- kvm_dist_put(s, 0x800, 8, s->num_irq, translate_targets);
-
- /* irq_state[n].trigger -> GICD_ICFGRn
- * (restore configuration registers before pending IRQs so we treat
- * level/edge correctly) */
- kvm_dist_put(s, 0xc00, 2, s->num_irq, translate_trigger);
-
- /* irq_state[n].pending + irq_state[n].level -> GICD_ISPENDRn */
- kvm_dist_put(s, 0x280, 1, s->num_irq, translate_clear);
- kvm_dist_put(s, 0x200, 1, s->num_irq, translate_pending);
-
- /* irq_state[n].active -> GICD_ISACTIVERn */
- kvm_dist_put(s, 0x380, 1, s->num_irq, translate_clear);
- kvm_dist_put(s, 0x300, 1, s->num_irq, translate_active);
-
-
- /* s->priorityX[irq] -> ICD_IPRIORITYRn */
- kvm_dist_put(s, 0x400, 8, s->num_irq, translate_priority);
-
- /* s->sgi_pending -> ICD_CPENDSGIRn */
- kvm_dist_put(s, 0xf10, 8, GIC_NR_SGIS, translate_clear);
- kvm_dist_put(s, 0xf20, 8, GIC_NR_SGIS, translate_sgisource);
-
-
- /*****************************************************************
- * CPU Interface(s) State
- */
-
- for (cpu = 0; cpu < s->num_cpu; cpu++) {
- /* s->cpu_ctlr[cpu] -> GICC_CTLR */
- reg = s->cpu_ctlr[cpu];
- kvm_gicc_access(s, 0x00, cpu, &reg, true);
-
- /* s->priority_mask[cpu] -> GICC_PMR */
- reg = (s->priority_mask[cpu] & 0xff);
- kvm_gicc_access(s, 0x04, cpu, &reg, true);
-
- /* s->bpr[cpu] -> GICC_BPR */
- reg = (s->bpr[cpu] & 0x7);
- kvm_gicc_access(s, 0x08, cpu, &reg, true);
-
- /* s->abpr[cpu] -> GICC_ABPR */
- reg = (s->abpr[cpu] & 0x7);
- kvm_gicc_access(s, 0x1c, cpu, &reg, true);
-
- /* s->apr[n][cpu] -> GICC_APRn */
- for (i = 0; i < 4; i++) {
- reg = s->apr[i][cpu];
- kvm_gicc_access(s, 0xd0 + i * 4, cpu, &reg, true);
- }
- }
-}
-
-static void kvm_arm_gic_get(GICState *s)
-{
- uint32_t reg;
- int i;
- int cpu;
-
- /*****************************************************************
- * Distributor State
- */
-
- /* GICD_CTLR -> s->ctlr */
- kvm_gicd_access(s, 0x0, 0, &reg, false);
- s->ctlr = reg;
-
- /* Sanity checking on GICD_TYPER -> s->num_irq, s->num_cpu */
- kvm_gicd_access(s, 0x4, 0, &reg, false);
- s->num_irq = ((reg & 0x1f) + 1) * 32;
- s->num_cpu = ((reg & 0xe0) >> 5) + 1;
-
- if (s->num_irq > GIC_MAXIRQ) {
- fprintf(stderr, "Too many IRQs reported from the kernel: %d\n",
- s->num_irq);
- abort();
- }
-
- /* GICD_IIDR -> ? */
- kvm_gicd_access(s, 0x8, 0, &reg, false);
-
- /* Clear all the IRQ settings */
- for (i = 0; i < s->num_irq; i++) {
- memset(&s->irq_state[i], 0, sizeof(s->irq_state[0]));
- }
-
- /* GICD_IGROUPRn -> irq_state[n].group */
- kvm_dist_get(s, 0x80, 1, s->num_irq, translate_group);
-
- /* GICD_ISENABLERn -> irq_state[n].enabled */
- kvm_dist_get(s, 0x100, 1, s->num_irq, translate_enabled);
-
- /* GICD_ISPENDRn -> irq_state[n].pending + irq_state[n].level */
- kvm_dist_get(s, 0x200, 1, s->num_irq, translate_pending);
-
- /* GICD_ISACTIVERn -> irq_state[n].active */
- kvm_dist_get(s, 0x300, 1, s->num_irq, translate_active);
-
- /* GICD_ICFRn -> irq_state[n].trigger */
- kvm_dist_get(s, 0xc00, 2, s->num_irq, translate_trigger);
-
- /* GICD_IPRIORITYRn -> s->priorityX[irq] */
- kvm_dist_get(s, 0x400, 8, s->num_irq, translate_priority);
-
- /* GICD_ITARGETSRn -> s->irq_target[irq] */
- kvm_dist_get(s, 0x800, 8, s->num_irq, translate_targets);
-
- /* GICD_CPENDSGIRn -> s->sgi_pending */
- kvm_dist_get(s, 0xf10, 8, GIC_NR_SGIS, translate_sgisource);
-
-
- /*****************************************************************
- * CPU Interface(s) State
- */
-
- for (cpu = 0; cpu < s->num_cpu; cpu++) {
- /* GICC_CTLR -> s->cpu_ctlr[cpu] */
- kvm_gicc_access(s, 0x00, cpu, &reg, false);
- s->cpu_ctlr[cpu] = reg;
-
- /* GICC_PMR -> s->priority_mask[cpu] */
- kvm_gicc_access(s, 0x04, cpu, &reg, false);
- s->priority_mask[cpu] = (reg & 0xff);
-
- /* GICC_BPR -> s->bpr[cpu] */
- kvm_gicc_access(s, 0x08, cpu, &reg, false);
- s->bpr[cpu] = (reg & 0x7);
-
- /* GICC_ABPR -> s->abpr[cpu] */
- kvm_gicc_access(s, 0x1c, cpu, &reg, false);
- s->abpr[cpu] = (reg & 0x7);
-
- /* GICC_APRn -> s->apr[n][cpu] */
- for (i = 0; i < 4; i++) {
- kvm_gicc_access(s, 0xd0 + i * 4, cpu, &reg, false);
- s->apr[i][cpu] = reg;
- }
- }
-}
-
-static void kvm_arm_gic_reset(DeviceState *dev)
-{
- GICState *s = ARM_GIC_COMMON(dev);
- KVMARMGICClass *kgc = KVM_ARM_GIC_GET_CLASS(s);
-
- kgc->parent_reset(dev);
-
- if (kvm_arm_gic_can_save_restore(s)) {
- kvm_arm_gic_put(s);
- }
-}
-
-static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
-{
- int i;
- GICState *s = KVM_ARM_GIC(dev);
- KVMARMGICClass *kgc = KVM_ARM_GIC_GET_CLASS(s);
- Error *local_err = NULL;
- int ret;
-
- kgc->parent_realize(dev, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- if (s->security_extn) {
- error_setg(errp, "the in-kernel VGIC does not implement the "
- "security extensions");
- return;
- }
-
- gic_init_irqs_and_mmio(s, kvm_arm_gicv2_set_irq, NULL);
-
- for (i = 0; i < s->num_irq - GIC_INTERNAL; i++) {
- qemu_irq irq = qdev_get_gpio_in(dev, i);
- kvm_irqchip_set_qemuirq_gsi(kvm_state, irq, i);
- }
-
- /* Try to create the device via the device control API */
- s->dev_fd = -1;
- ret = kvm_create_device(kvm_state, KVM_DEV_TYPE_ARM_VGIC_V2, false);
- if (ret >= 0) {
- s->dev_fd = ret;
-
- /* Newstyle API is used, we may have attributes */
- if (kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0)) {
- uint32_t numirqs = s->num_irq;
- kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0,
- &numirqs, true);
- }
- /* Tell the kernel to complete VGIC initialization now */
- if (kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
- KVM_DEV_ARM_VGIC_CTRL_INIT)) {
- kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
- KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true);
- }
- } else if (ret != -ENODEV && ret != -ENOTSUP) {
- error_setg_errno(errp, -ret, "error creating in-kernel VGIC");
- return;
- }
-
- /* Distributor */
- kvm_arm_register_device(&s->iomem,
- (KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT)
- | KVM_VGIC_V2_ADDR_TYPE_DIST,
- KVM_DEV_ARM_VGIC_GRP_ADDR,
- KVM_VGIC_V2_ADDR_TYPE_DIST,
- s->dev_fd);
- /* CPU interface for current core. Unlike arm_gic, we don't
- * provide the "interface for core #N" memory regions, because
- * cores with a VGIC don't have those.
- */
- kvm_arm_register_device(&s->cpuiomem[0],
- (KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT)
- | KVM_VGIC_V2_ADDR_TYPE_CPU,
- KVM_DEV_ARM_VGIC_GRP_ADDR,
- KVM_VGIC_V2_ADDR_TYPE_CPU,
- s->dev_fd);
-
- if (!kvm_arm_gic_can_save_restore(s)) {
- error_setg(&s->migration_blocker, "This operating system kernel does "
- "not support vGICv2 migration");
- migrate_add_blocker(s->migration_blocker);
- }
-}
-
-static void kvm_arm_gic_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- ARMGICCommonClass *agcc = ARM_GIC_COMMON_CLASS(klass);
- KVMARMGICClass *kgc = KVM_ARM_GIC_CLASS(klass);
-
- agcc->pre_save = kvm_arm_gic_get;
- agcc->post_load = kvm_arm_gic_put;
- kgc->parent_realize = dc->realize;
- kgc->parent_reset = dc->reset;
- dc->realize = kvm_arm_gic_realize;
- dc->reset = kvm_arm_gic_reset;
-}
-
-static const TypeInfo kvm_arm_gic_info = {
- .name = TYPE_KVM_ARM_GIC,
- .parent = TYPE_ARM_GIC_COMMON,
- .instance_size = sizeof(GICState),
- .class_init = kvm_arm_gic_class_init,
- .class_size = sizeof(KVMARMGICClass),
-};
-
-static void kvm_arm_gic_register_types(void)
-{
- type_register_static(&kvm_arm_gic_info);
-}
-
-type_init(kvm_arm_gic_register_types)
diff --git a/qemu/hw/intc/arm_gicv2m.c b/qemu/hw/intc/arm_gicv2m.c
deleted file mode 100644
index e8b5177dc..000000000
--- a/qemu/hw/intc/arm_gicv2m.c
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * GICv2m extension for MSI/MSI-x support with a GICv2-based system
- *
- * Copyright (C) 2015 Linaro, All rights reserved.
- *
- * Author: Christoffer Dall <christoffer.dall@linaro.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-/* This file implements an emulated GICv2m widget as described in the ARM
- * Server Base System Architecture (SBSA) specification Version 2.2
- * (ARM-DEN-0029 v2.2) pages 35-39 without any optional implementation defined
- * identification registers and with a single non-secure MSI register frame.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/sysbus.h"
-#include "hw/pci/msi.h"
-
-#define TYPE_ARM_GICV2M "arm-gicv2m"
-#define ARM_GICV2M(obj) OBJECT_CHECK(ARMGICv2mState, (obj), TYPE_ARM_GICV2M)
-
-#define GICV2M_NUM_SPI_MAX 128
-
-#define V2M_MSI_TYPER 0x008
-#define V2M_MSI_SETSPI_NS 0x040
-#define V2M_MSI_IIDR 0xFCC
-#define V2M_IIDR0 0xFD0
-#define V2M_IIDR11 0xFFC
-
-#define PRODUCT_ID_QEMU 0x51 /* ASCII code Q */
-
-typedef struct ARMGICv2mState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- qemu_irq spi[GICV2M_NUM_SPI_MAX];
-
- uint32_t base_spi;
- uint32_t num_spi;
-} ARMGICv2mState;
-
-static void gicv2m_set_irq(void *opaque, int irq)
-{
- ARMGICv2mState *s = (ARMGICv2mState *)opaque;
-
- qemu_irq_pulse(s->spi[irq]);
-}
-
-static uint64_t gicv2m_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- ARMGICv2mState *s = (ARMGICv2mState *)opaque;
- uint32_t val;
-
- if (size != 4) {
- qemu_log_mask(LOG_GUEST_ERROR, "gicv2m_read: bad size %u\n", size);
- return 0;
- }
-
- switch (offset) {
- case V2M_MSI_TYPER:
- val = (s->base_spi + 32) << 16;
- val |= s->num_spi;
- return val;
- case V2M_MSI_IIDR:
- /* We don't have any valid implementor so we leave that field as zero
- * and we return 0 in the arch revision as per the spec.
- */
- return (PRODUCT_ID_QEMU << 20);
- case V2M_IIDR0 ... V2M_IIDR11:
- /* We do not implement any optional identification registers and the
- * mandatory MSI_PIDR2 register reads as 0x0, so we capture all
- * implementation defined registers here.
- */
- return 0;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "gicv2m_read: Bad offset %x\n", (int)offset);
- return 0;
- }
-}
-
-static void gicv2m_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- ARMGICv2mState *s = (ARMGICv2mState *)opaque;
-
- if (size != 2 && size != 4) {
- qemu_log_mask(LOG_GUEST_ERROR, "gicv2m_write: bad size %u\n", size);
- return;
- }
-
- switch (offset) {
- case V2M_MSI_SETSPI_NS: {
- int spi;
-
- spi = (value & 0x3ff) - (s->base_spi + 32);
- if (spi >= 0 && spi < s->num_spi) {
- gicv2m_set_irq(s, spi);
- }
- return;
- }
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "gicv2m_write: Bad offset %x\n", (int)offset);
- }
-}
-
-static const MemoryRegionOps gicv2m_ops = {
- .read = gicv2m_read,
- .write = gicv2m_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void gicv2m_realize(DeviceState *dev, Error **errp)
-{
- ARMGICv2mState *s = ARM_GICV2M(dev);
- int i;
-
- if (s->num_spi > GICV2M_NUM_SPI_MAX) {
- error_setg(errp,
- "requested %u SPIs exceeds GICv2m frame maximum %d",
- s->num_spi, GICV2M_NUM_SPI_MAX);
- return;
- }
-
- if (s->base_spi + 32 > 1020 - s->num_spi) {
- error_setg(errp,
- "requested base SPI %u+%u exceeds max. number 1020",
- s->base_spi + 32, s->num_spi);
- return;
- }
-
- for (i = 0; i < s->num_spi; i++) {
- sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->spi[i]);
- }
-
- msi_nonbroken = true;
- kvm_gsi_direct_mapping = true;
- kvm_msi_via_irqfd_allowed = kvm_irqfds_enabled();
-}
-
-static void gicv2m_init(Object *obj)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- ARMGICv2mState *s = ARM_GICV2M(obj);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &gicv2m_ops, s,
- "gicv2m", 0x1000);
- sysbus_init_mmio(sbd, &s->iomem);
-}
-
-static Property gicv2m_properties[] = {
- DEFINE_PROP_UINT32("base-spi", ARMGICv2mState, base_spi, 0),
- DEFINE_PROP_UINT32("num-spi", ARMGICv2mState, num_spi, 64),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void gicv2m_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->props = gicv2m_properties;
- dc->realize = gicv2m_realize;
-}
-
-static const TypeInfo gicv2m_info = {
- .name = TYPE_ARM_GICV2M,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(ARMGICv2mState),
- .instance_init = gicv2m_init,
- .class_init = gicv2m_class_init,
-};
-
-static void gicv2m_register_types(void)
-{
- type_register_static(&gicv2m_info);
-}
-
-type_init(gicv2m_register_types)
diff --git a/qemu/hw/intc/arm_gicv3_common.c b/qemu/hw/intc/arm_gicv3_common.c
deleted file mode 100644
index b9d3824f2..000000000
--- a/qemu/hw/intc/arm_gicv3_common.c
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * ARM GICv3 support - common bits of emulated and KVM kernel model
- *
- * Copyright (c) 2012 Linaro Limited
- * Copyright (c) 2015 Huawei.
- * Written by Peter Maydell
- * Extended to 64 cores by Shlomo Pongratz
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/intc/arm_gicv3_common.h"
-
-static void gicv3_pre_save(void *opaque)
-{
- GICv3State *s = (GICv3State *)opaque;
- ARMGICv3CommonClass *c = ARM_GICV3_COMMON_GET_CLASS(s);
-
- if (c->pre_save) {
- c->pre_save(s);
- }
-}
-
-static int gicv3_post_load(void *opaque, int version_id)
-{
- GICv3State *s = (GICv3State *)opaque;
- ARMGICv3CommonClass *c = ARM_GICV3_COMMON_GET_CLASS(s);
-
- if (c->post_load) {
- c->post_load(s);
- }
- return 0;
-}
-
-static const VMStateDescription vmstate_gicv3 = {
- .name = "arm_gicv3",
- .unmigratable = 1,
- .pre_save = gicv3_pre_save,
- .post_load = gicv3_post_load,
-};
-
-void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler,
- const MemoryRegionOps *ops)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(s);
- int i;
-
- /* For the GIC, also expose incoming GPIO lines for PPIs for each CPU.
- * GPIO array layout is thus:
- * [0..N-1] spi
- * [N..N+31] PPIs for CPU 0
- * [N+32..N+63] PPIs for CPU 1
- * ...
- */
- i = s->num_irq - GIC_INTERNAL + GIC_INTERNAL * s->num_cpu;
- qdev_init_gpio_in(DEVICE(s), handler, i);
-
- s->parent_irq = g_malloc(s->num_cpu * sizeof(qemu_irq));
- s->parent_fiq = g_malloc(s->num_cpu * sizeof(qemu_irq));
-
- for (i = 0; i < s->num_cpu; i++) {
- sysbus_init_irq(sbd, &s->parent_irq[i]);
- }
- for (i = 0; i < s->num_cpu; i++) {
- sysbus_init_irq(sbd, &s->parent_fiq[i]);
- }
-
- memory_region_init_io(&s->iomem_dist, OBJECT(s), ops, s,
- "gicv3_dist", 0x10000);
- memory_region_init_io(&s->iomem_redist, OBJECT(s), ops ? &ops[1] : NULL, s,
- "gicv3_redist", 0x20000 * s->num_cpu);
-
- sysbus_init_mmio(sbd, &s->iomem_dist);
- sysbus_init_mmio(sbd, &s->iomem_redist);
-}
-
-static void arm_gicv3_common_realize(DeviceState *dev, Error **errp)
-{
- GICv3State *s = ARM_GICV3_COMMON(dev);
-
- /* revision property is actually reserved and currently used only in order
- * to keep the interface compatible with GICv2 code, avoiding extra
- * conditions. However, in future it could be used, for example, if we
- * implement GICv4.
- */
- if (s->revision != 3) {
- error_setg(errp, "unsupported GIC revision %d", s->revision);
- return;
- }
-}
-
-static void arm_gicv3_common_reset(DeviceState *dev)
-{
- /* TODO */
-}
-
-static Property arm_gicv3_common_properties[] = {
- DEFINE_PROP_UINT32("num-cpu", GICv3State, num_cpu, 1),
- DEFINE_PROP_UINT32("num-irq", GICv3State, num_irq, 32),
- DEFINE_PROP_UINT32("revision", GICv3State, revision, 3),
- DEFINE_PROP_BOOL("has-security-extensions", GICv3State, security_extn, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void arm_gicv3_common_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->reset = arm_gicv3_common_reset;
- dc->realize = arm_gicv3_common_realize;
- dc->props = arm_gicv3_common_properties;
- dc->vmsd = &vmstate_gicv3;
-}
-
-static const TypeInfo arm_gicv3_common_type = {
- .name = TYPE_ARM_GICV3_COMMON,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(GICv3State),
- .class_size = sizeof(ARMGICv3CommonClass),
- .class_init = arm_gicv3_common_class_init,
- .abstract = true,
-};
-
-static void register_types(void)
-{
- type_register_static(&arm_gicv3_common_type);
-}
-
-type_init(register_types)
diff --git a/qemu/hw/intc/arm_gicv3_kvm.c b/qemu/hw/intc/arm_gicv3_kvm.c
deleted file mode 100644
index acc173004..000000000
--- a/qemu/hw/intc/arm_gicv3_kvm.c
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * ARM Generic Interrupt Controller using KVM in-kernel support
- *
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
- * Written by Pavel Fedin
- * Based on vGICv2 code by Peter Maydell
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/intc/arm_gicv3_common.h"
-#include "hw/sysbus.h"
-#include "sysemu/kvm.h"
-#include "kvm_arm.h"
-#include "vgic_common.h"
-
-#ifdef DEBUG_GICV3_KVM
-#define DPRINTF(fmt, ...) \
- do { fprintf(stderr, "kvm_gicv3: " fmt, ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) \
- do { } while (0)
-#endif
-
-#define TYPE_KVM_ARM_GICV3 "kvm-arm-gicv3"
-#define KVM_ARM_GICV3(obj) \
- OBJECT_CHECK(GICv3State, (obj), TYPE_KVM_ARM_GICV3)
-#define KVM_ARM_GICV3_CLASS(klass) \
- OBJECT_CLASS_CHECK(KVMARMGICv3Class, (klass), TYPE_KVM_ARM_GICV3)
-#define KVM_ARM_GICV3_GET_CLASS(obj) \
- OBJECT_GET_CLASS(KVMARMGICv3Class, (obj), TYPE_KVM_ARM_GICV3)
-
-typedef struct KVMARMGICv3Class {
- ARMGICv3CommonClass parent_class;
- DeviceRealize parent_realize;
- void (*parent_reset)(DeviceState *dev);
-} KVMARMGICv3Class;
-
-static void kvm_arm_gicv3_set_irq(void *opaque, int irq, int level)
-{
- GICv3State *s = (GICv3State *)opaque;
-
- kvm_arm_gic_set_irq(s->num_irq, irq, level);
-}
-
-static void kvm_arm_gicv3_put(GICv3State *s)
-{
- /* TODO */
- DPRINTF("Cannot put kernel gic state, no kernel interface\n");
-}
-
-static void kvm_arm_gicv3_get(GICv3State *s)
-{
- /* TODO */
- DPRINTF("Cannot get kernel gic state, no kernel interface\n");
-}
-
-static void kvm_arm_gicv3_reset(DeviceState *dev)
-{
- GICv3State *s = ARM_GICV3_COMMON(dev);
- KVMARMGICv3Class *kgc = KVM_ARM_GICV3_GET_CLASS(s);
-
- DPRINTF("Reset\n");
-
- kgc->parent_reset(dev);
- kvm_arm_gicv3_put(s);
-}
-
-static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp)
-{
- GICv3State *s = KVM_ARM_GICV3(dev);
- KVMARMGICv3Class *kgc = KVM_ARM_GICV3_GET_CLASS(s);
- Error *local_err = NULL;
-
- DPRINTF("kvm_arm_gicv3_realize\n");
-
- kgc->parent_realize(dev, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- if (s->security_extn) {
- error_setg(errp, "the in-kernel VGICv3 does not implement the "
- "security extensions");
- return;
- }
-
- gicv3_init_irqs_and_mmio(s, kvm_arm_gicv3_set_irq, NULL);
-
- /* Try to create the device via the device control API */
- s->dev_fd = kvm_create_device(kvm_state, KVM_DEV_TYPE_ARM_VGIC_V3, false);
- if (s->dev_fd < 0) {
- error_setg_errno(errp, -s->dev_fd, "error creating in-kernel VGIC");
- return;
- }
-
- kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_NR_IRQS,
- 0, &s->num_irq, true);
-
- /* Tell the kernel to complete VGIC initialization now */
- kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
- KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true);
-
- kvm_arm_register_device(&s->iomem_dist, -1, KVM_DEV_ARM_VGIC_GRP_ADDR,
- KVM_VGIC_V3_ADDR_TYPE_DIST, s->dev_fd);
- kvm_arm_register_device(&s->iomem_redist, -1, KVM_DEV_ARM_VGIC_GRP_ADDR,
- KVM_VGIC_V3_ADDR_TYPE_REDIST, s->dev_fd);
-}
-
-static void kvm_arm_gicv3_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- ARMGICv3CommonClass *agcc = ARM_GICV3_COMMON_CLASS(klass);
- KVMARMGICv3Class *kgc = KVM_ARM_GICV3_CLASS(klass);
-
- agcc->pre_save = kvm_arm_gicv3_get;
- agcc->post_load = kvm_arm_gicv3_put;
- kgc->parent_realize = dc->realize;
- kgc->parent_reset = dc->reset;
- dc->realize = kvm_arm_gicv3_realize;
- dc->reset = kvm_arm_gicv3_reset;
-}
-
-static const TypeInfo kvm_arm_gicv3_info = {
- .name = TYPE_KVM_ARM_GICV3,
- .parent = TYPE_ARM_GICV3_COMMON,
- .instance_size = sizeof(GICv3State),
- .class_init = kvm_arm_gicv3_class_init,
- .class_size = sizeof(KVMARMGICv3Class),
-};
-
-static void kvm_arm_gicv3_register_types(void)
-{
- type_register_static(&kvm_arm_gicv3_info);
-}
-
-type_init(kvm_arm_gicv3_register_types)
diff --git a/qemu/hw/intc/armv7m_nvic.c b/qemu/hw/intc/armv7m_nvic.c
deleted file mode 100644
index 669e82adf..000000000
--- a/qemu/hw/intc/armv7m_nvic.c
+++ /dev/null
@@ -1,581 +0,0 @@
-/*
- * ARM Nested Vectored Interrupt Controller
- *
- * Copyright (c) 2006-2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- *
- * The ARMv7M System controller is fairly tightly tied in with the
- * NVIC. Much of that is also implemented here.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "hw/sysbus.h"
-#include "qemu/timer.h"
-#include "hw/arm/arm.h"
-#include "exec/address-spaces.h"
-#include "gic_internal.h"
-
-typedef struct {
- GICState gic;
- struct {
- uint32_t control;
- uint32_t reload;
- int64_t tick;
- QEMUTimer *timer;
- } systick;
- MemoryRegion sysregmem;
- MemoryRegion gic_iomem_alias;
- MemoryRegion container;
- uint32_t num_irq;
- qemu_irq sysresetreq;
-} nvic_state;
-
-#define TYPE_NVIC "armv7m_nvic"
-/**
- * NVICClass:
- * @parent_reset: the parent class' reset handler.
- *
- * A model of the v7M NVIC and System Controller
- */
-typedef struct NVICClass {
- /*< private >*/
- ARMGICClass parent_class;
- /*< public >*/
- DeviceRealize parent_realize;
- void (*parent_reset)(DeviceState *dev);
-} NVICClass;
-
-#define NVIC_CLASS(klass) \
- OBJECT_CLASS_CHECK(NVICClass, (klass), TYPE_NVIC)
-#define NVIC_GET_CLASS(obj) \
- OBJECT_GET_CLASS(NVICClass, (obj), TYPE_NVIC)
-#define NVIC(obj) \
- OBJECT_CHECK(nvic_state, (obj), TYPE_NVIC)
-
-static const uint8_t nvic_id[] = {
- 0x00, 0xb0, 0x1b, 0x00, 0x0d, 0xe0, 0x05, 0xb1
-};
-
-/* qemu timers run at 1GHz. We want something closer to 1MHz. */
-#define SYSTICK_SCALE 1000ULL
-
-#define SYSTICK_ENABLE (1 << 0)
-#define SYSTICK_TICKINT (1 << 1)
-#define SYSTICK_CLKSOURCE (1 << 2)
-#define SYSTICK_COUNTFLAG (1 << 16)
-
-int system_clock_scale;
-
-/* Conversion factor from qemu timer to SysTick frequencies. */
-static inline int64_t systick_scale(nvic_state *s)
-{
- if (s->systick.control & SYSTICK_CLKSOURCE)
- return system_clock_scale;
- else
- return 1000;
-}
-
-static void systick_reload(nvic_state *s, int reset)
-{
- /* The Cortex-M3 Devices Generic User Guide says that "When the
- * ENABLE bit is set to 1, the counter loads the RELOAD value from the
- * SYST RVR register and then counts down". So, we need to check the
- * ENABLE bit before reloading the value.
- */
- if ((s->systick.control & SYSTICK_ENABLE) == 0) {
- return;
- }
-
- if (reset)
- s->systick.tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- s->systick.tick += (s->systick.reload + 1) * systick_scale(s);
- timer_mod(s->systick.timer, s->systick.tick);
-}
-
-static void systick_timer_tick(void * opaque)
-{
- nvic_state *s = (nvic_state *)opaque;
- s->systick.control |= SYSTICK_COUNTFLAG;
- if (s->systick.control & SYSTICK_TICKINT) {
- /* Trigger the interrupt. */
- armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK);
- }
- if (s->systick.reload == 0) {
- s->systick.control &= ~SYSTICK_ENABLE;
- } else {
- systick_reload(s, 0);
- }
-}
-
-static void systick_reset(nvic_state *s)
-{
- s->systick.control = 0;
- s->systick.reload = 0;
- s->systick.tick = 0;
- timer_del(s->systick.timer);
-}
-
-/* The external routines use the hardware vector numbering, ie. the first
- IRQ is #16. The internal GIC routines use #32 as the first IRQ. */
-void armv7m_nvic_set_pending(void *opaque, int irq)
-{
- nvic_state *s = (nvic_state *)opaque;
- if (irq >= 16)
- irq += 16;
- gic_set_pending_private(&s->gic, 0, irq);
-}
-
-/* Make pending IRQ active. */
-int armv7m_nvic_acknowledge_irq(void *opaque)
-{
- nvic_state *s = (nvic_state *)opaque;
- uint32_t irq;
-
- irq = gic_acknowledge_irq(&s->gic, 0, MEMTXATTRS_UNSPECIFIED);
- if (irq == 1023)
- hw_error("Interrupt but no vector\n");
- if (irq >= 32)
- irq -= 16;
- return irq;
-}
-
-void armv7m_nvic_complete_irq(void *opaque, int irq)
-{
- nvic_state *s = (nvic_state *)opaque;
- if (irq >= 16)
- irq += 16;
- gic_complete_irq(&s->gic, 0, irq, MEMTXATTRS_UNSPECIFIED);
-}
-
-static uint32_t nvic_readl(nvic_state *s, uint32_t offset)
-{
- ARMCPU *cpu;
- uint32_t val;
- int irq;
-
- switch (offset) {
- case 4: /* Interrupt Control Type. */
- return (s->num_irq / 32) - 1;
- case 0x10: /* SysTick Control and Status. */
- val = s->systick.control;
- s->systick.control &= ~SYSTICK_COUNTFLAG;
- return val;
- case 0x14: /* SysTick Reload Value. */
- return s->systick.reload;
- case 0x18: /* SysTick Current Value. */
- {
- int64_t t;
- if ((s->systick.control & SYSTICK_ENABLE) == 0)
- return 0;
- t = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- if (t >= s->systick.tick)
- return 0;
- val = ((s->systick.tick - (t + 1)) / systick_scale(s)) + 1;
- /* The interrupt in triggered when the timer reaches zero.
- However the counter is not reloaded until the next clock
- tick. This is a hack to return zero during the first tick. */
- if (val > s->systick.reload)
- val = 0;
- return val;
- }
- case 0x1c: /* SysTick Calibration Value. */
- return 10000;
- case 0xd00: /* CPUID Base. */
- cpu = ARM_CPU(current_cpu);
- return cpu->midr;
- case 0xd04: /* Interrupt Control State. */
- /* VECTACTIVE */
- cpu = ARM_CPU(current_cpu);
- val = cpu->env.v7m.exception;
- if (val == 1023) {
- val = 0;
- } else if (val >= 32) {
- val -= 16;
- }
- /* VECTPENDING */
- if (s->gic.current_pending[0] != 1023)
- val |= (s->gic.current_pending[0] << 12);
- /* ISRPENDING and RETTOBASE */
- for (irq = 32; irq < s->num_irq; irq++) {
- if (s->gic.irq_state[irq].pending) {
- val |= (1 << 22);
- break;
- }
- if (irq != cpu->env.v7m.exception && s->gic.irq_state[irq].active) {
- val |= (1 << 11);
- }
- }
- /* PENDSTSET */
- if (s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending)
- val |= (1 << 26);
- /* PENDSVSET */
- if (s->gic.irq_state[ARMV7M_EXCP_PENDSV].pending)
- val |= (1 << 28);
- /* NMIPENDSET */
- if (s->gic.irq_state[ARMV7M_EXCP_NMI].pending)
- val |= (1 << 31);
- return val;
- case 0xd08: /* Vector Table Offset. */
- cpu = ARM_CPU(current_cpu);
- return cpu->env.v7m.vecbase;
- case 0xd0c: /* Application Interrupt/Reset Control. */
- return 0xfa050000;
- case 0xd10: /* System Control. */
- /* TODO: Implement SLEEPONEXIT. */
- return 0;
- case 0xd14: /* Configuration Control. */
- /* TODO: Implement Configuration Control bits. */
- return 0;
- case 0xd24: /* System Handler Status. */
- val = 0;
- if (s->gic.irq_state[ARMV7M_EXCP_MEM].active) val |= (1 << 0);
- if (s->gic.irq_state[ARMV7M_EXCP_BUS].active) val |= (1 << 1);
- if (s->gic.irq_state[ARMV7M_EXCP_USAGE].active) val |= (1 << 3);
- if (s->gic.irq_state[ARMV7M_EXCP_SVC].active) val |= (1 << 7);
- if (s->gic.irq_state[ARMV7M_EXCP_DEBUG].active) val |= (1 << 8);
- if (s->gic.irq_state[ARMV7M_EXCP_PENDSV].active) val |= (1 << 10);
- if (s->gic.irq_state[ARMV7M_EXCP_SYSTICK].active) val |= (1 << 11);
- if (s->gic.irq_state[ARMV7M_EXCP_USAGE].pending) val |= (1 << 12);
- if (s->gic.irq_state[ARMV7M_EXCP_MEM].pending) val |= (1 << 13);
- if (s->gic.irq_state[ARMV7M_EXCP_BUS].pending) val |= (1 << 14);
- if (s->gic.irq_state[ARMV7M_EXCP_SVC].pending) val |= (1 << 15);
- if (s->gic.irq_state[ARMV7M_EXCP_MEM].enabled) val |= (1 << 16);
- if (s->gic.irq_state[ARMV7M_EXCP_BUS].enabled) val |= (1 << 17);
- if (s->gic.irq_state[ARMV7M_EXCP_USAGE].enabled) val |= (1 << 18);
- return val;
- case 0xd28: /* Configurable Fault Status. */
- /* TODO: Implement Fault Status. */
- qemu_log_mask(LOG_UNIMP, "Configurable Fault Status unimplemented\n");
- return 0;
- case 0xd2c: /* Hard Fault Status. */
- case 0xd30: /* Debug Fault Status. */
- case 0xd34: /* Mem Manage Address. */
- case 0xd38: /* Bus Fault Address. */
- case 0xd3c: /* Aux Fault Status. */
- /* TODO: Implement fault status registers. */
- qemu_log_mask(LOG_UNIMP, "Fault status registers unimplemented\n");
- return 0;
- case 0xd40: /* PFR0. */
- return 0x00000030;
- case 0xd44: /* PRF1. */
- return 0x00000200;
- case 0xd48: /* DFR0. */
- return 0x00100000;
- case 0xd4c: /* AFR0. */
- return 0x00000000;
- case 0xd50: /* MMFR0. */
- return 0x00000030;
- case 0xd54: /* MMFR1. */
- return 0x00000000;
- case 0xd58: /* MMFR2. */
- return 0x00000000;
- case 0xd5c: /* MMFR3. */
- return 0x00000000;
- case 0xd60: /* ISAR0. */
- return 0x01141110;
- case 0xd64: /* ISAR1. */
- return 0x02111000;
- case 0xd68: /* ISAR2. */
- return 0x21112231;
- case 0xd6c: /* ISAR3. */
- return 0x01111110;
- case 0xd70: /* ISAR4. */
- return 0x01310102;
- /* TODO: Implement debug registers. */
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "NVIC: Bad read offset 0x%x\n", offset);
- return 0;
- }
-}
-
-static void nvic_writel(nvic_state *s, uint32_t offset, uint32_t value)
-{
- ARMCPU *cpu;
- uint32_t oldval;
- switch (offset) {
- case 0x10: /* SysTick Control and Status. */
- oldval = s->systick.control;
- s->systick.control &= 0xfffffff8;
- s->systick.control |= value & 7;
- if ((oldval ^ value) & SYSTICK_ENABLE) {
- int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- if (value & SYSTICK_ENABLE) {
- if (s->systick.tick) {
- s->systick.tick += now;
- timer_mod(s->systick.timer, s->systick.tick);
- } else {
- systick_reload(s, 1);
- }
- } else {
- timer_del(s->systick.timer);
- s->systick.tick -= now;
- if (s->systick.tick < 0)
- s->systick.tick = 0;
- }
- } else if ((oldval ^ value) & SYSTICK_CLKSOURCE) {
- /* This is a hack. Force the timer to be reloaded
- when the reference clock is changed. */
- systick_reload(s, 1);
- }
- break;
- case 0x14: /* SysTick Reload Value. */
- s->systick.reload = value;
- break;
- case 0x18: /* SysTick Current Value. Writes reload the timer. */
- systick_reload(s, 1);
- s->systick.control &= ~SYSTICK_COUNTFLAG;
- break;
- case 0xd04: /* Interrupt Control State. */
- if (value & (1 << 31)) {
- armv7m_nvic_set_pending(s, ARMV7M_EXCP_NMI);
- }
- if (value & (1 << 28)) {
- armv7m_nvic_set_pending(s, ARMV7M_EXCP_PENDSV);
- } else if (value & (1 << 27)) {
- s->gic.irq_state[ARMV7M_EXCP_PENDSV].pending = 0;
- gic_update(&s->gic);
- }
- if (value & (1 << 26)) {
- armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK);
- } else if (value & (1 << 25)) {
- s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending = 0;
- gic_update(&s->gic);
- }
- break;
- case 0xd08: /* Vector Table Offset. */
- cpu = ARM_CPU(current_cpu);
- cpu->env.v7m.vecbase = value & 0xffffff80;
- break;
- case 0xd0c: /* Application Interrupt/Reset Control. */
- if ((value >> 16) == 0x05fa) {
- if (value & 4) {
- qemu_irq_pulse(s->sysresetreq);
- }
- if (value & 2) {
- qemu_log_mask(LOG_UNIMP, "VECTCLRACTIVE unimplemented\n");
- }
- if (value & 1) {
- qemu_log_mask(LOG_UNIMP, "AIRCR system reset unimplemented\n");
- }
- if (value & 0x700) {
- qemu_log_mask(LOG_UNIMP, "PRIGROUP unimplemented\n");
- }
- }
- break;
- case 0xd10: /* System Control. */
- case 0xd14: /* Configuration Control. */
- /* TODO: Implement control registers. */
- qemu_log_mask(LOG_UNIMP, "NVIC: SCR and CCR unimplemented\n");
- break;
- case 0xd24: /* System Handler Control. */
- /* TODO: Real hardware allows you to set/clear the active bits
- under some circumstances. We don't implement this. */
- s->gic.irq_state[ARMV7M_EXCP_MEM].enabled = (value & (1 << 16)) != 0;
- s->gic.irq_state[ARMV7M_EXCP_BUS].enabled = (value & (1 << 17)) != 0;
- s->gic.irq_state[ARMV7M_EXCP_USAGE].enabled = (value & (1 << 18)) != 0;
- break;
- case 0xd28: /* Configurable Fault Status. */
- case 0xd2c: /* Hard Fault Status. */
- case 0xd30: /* Debug Fault Status. */
- case 0xd34: /* Mem Manage Address. */
- case 0xd38: /* Bus Fault Address. */
- case 0xd3c: /* Aux Fault Status. */
- qemu_log_mask(LOG_UNIMP,
- "NVIC: fault status registers unimplemented\n");
- break;
- case 0xf00: /* Software Triggered Interrupt Register */
- if ((value & 0x1ff) < s->num_irq) {
- gic_set_pending_private(&s->gic, 0, value & 0x1ff);
- }
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "NVIC: Bad write offset 0x%x\n", offset);
- }
-}
-
-static uint64_t nvic_sysreg_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- nvic_state *s = (nvic_state *)opaque;
- uint32_t offset = addr;
- int i;
- uint32_t val;
-
- switch (offset) {
- case 0xd18 ... 0xd23: /* System Handler Priority. */
- val = 0;
- for (i = 0; i < size; i++) {
- val |= s->gic.priority1[(offset - 0xd14) + i][0] << (i * 8);
- }
- return val;
- case 0xfe0 ... 0xfff: /* ID. */
- if (offset & 3) {
- return 0;
- }
- return nvic_id[(offset - 0xfe0) >> 2];
- }
- if (size == 4) {
- return nvic_readl(s, offset);
- }
- qemu_log_mask(LOG_GUEST_ERROR,
- "NVIC: Bad read of size %d at offset 0x%x\n", size, offset);
- return 0;
-}
-
-static void nvic_sysreg_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- nvic_state *s = (nvic_state *)opaque;
- uint32_t offset = addr;
- int i;
-
- switch (offset) {
- case 0xd18 ... 0xd23: /* System Handler Priority. */
- for (i = 0; i < size; i++) {
- s->gic.priority1[(offset - 0xd14) + i][0] =
- (value >> (i * 8)) & 0xff;
- }
- gic_update(&s->gic);
- return;
- }
- if (size == 4) {
- nvic_writel(s, offset, value);
- return;
- }
- qemu_log_mask(LOG_GUEST_ERROR,
- "NVIC: Bad write of size %d at offset 0x%x\n", size, offset);
-}
-
-static const MemoryRegionOps nvic_sysreg_ops = {
- .read = nvic_sysreg_read,
- .write = nvic_sysreg_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_nvic = {
- .name = "armv7m_nvic",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(systick.control, nvic_state),
- VMSTATE_UINT32(systick.reload, nvic_state),
- VMSTATE_INT64(systick.tick, nvic_state),
- VMSTATE_TIMER_PTR(systick.timer, nvic_state),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void armv7m_nvic_reset(DeviceState *dev)
-{
- nvic_state *s = NVIC(dev);
- NVICClass *nc = NVIC_GET_CLASS(s);
- nc->parent_reset(dev);
- /* Common GIC reset resets to disabled; the NVIC doesn't have
- * per-CPU interfaces so mark our non-existent CPU interface
- * as enabled by default, and with a priority mask which allows
- * all interrupts through.
- */
- s->gic.cpu_ctlr[0] = GICC_CTLR_EN_GRP0;
- s->gic.priority_mask[0] = 0x100;
- /* The NVIC as a whole is always enabled. */
- s->gic.ctlr = 1;
- systick_reset(s);
-}
-
-static void armv7m_nvic_realize(DeviceState *dev, Error **errp)
-{
- nvic_state *s = NVIC(dev);
- NVICClass *nc = NVIC_GET_CLASS(s);
- Error *local_err = NULL;
-
- /* The NVIC always has only one CPU */
- s->gic.num_cpu = 1;
- /* Tell the common code we're an NVIC */
- s->gic.revision = 0xffffffff;
- s->num_irq = s->gic.num_irq;
- nc->parent_realize(dev, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
- gic_init_irqs_and_distributor(&s->gic);
- /* The NVIC and system controller register area looks like this:
- * 0..0xff : system control registers, including systick
- * 0x100..0xcff : GIC-like registers
- * 0xd00..0xfff : system control registers
- * We use overlaying to put the GIC like registers
- * over the top of the system control register region.
- */
- memory_region_init(&s->container, OBJECT(s), "nvic", 0x1000);
- /* The system register region goes at the bottom of the priority
- * stack as it covers the whole page.
- */
- memory_region_init_io(&s->sysregmem, OBJECT(s), &nvic_sysreg_ops, s,
- "nvic_sysregs", 0x1000);
- memory_region_add_subregion(&s->container, 0, &s->sysregmem);
- /* Alias the GIC region so we can get only the section of it
- * we need, and layer it on top of the system register region.
- */
- memory_region_init_alias(&s->gic_iomem_alias, OBJECT(s),
- "nvic-gic", &s->gic.iomem,
- 0x100, 0xc00);
- memory_region_add_subregion_overlap(&s->container, 0x100,
- &s->gic_iomem_alias, 1);
- /* Map the whole thing into system memory at the location required
- * by the v7M architecture.
- */
- memory_region_add_subregion(get_system_memory(), 0xe000e000, &s->container);
- s->systick.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, systick_timer_tick, s);
-}
-
-static void armv7m_nvic_instance_init(Object *obj)
-{
- /* We have a different default value for the num-irq property
- * than our superclass. This function runs after qdev init
- * has set the defaults from the Property array and before
- * any user-specified property setting, so just modify the
- * value in the GICState struct.
- */
- GICState *s = ARM_GIC_COMMON(obj);
- DeviceState *dev = DEVICE(obj);
- nvic_state *nvic = NVIC(obj);
- /* The ARM v7m may have anything from 0 to 496 external interrupt
- * IRQ lines. We default to 64. Other boards may differ and should
- * set the num-irq property appropriately.
- */
- s->num_irq = 64;
- qdev_init_gpio_out_named(dev, &nvic->sysresetreq, "SYSRESETREQ", 1);
-}
-
-static void armv7m_nvic_class_init(ObjectClass *klass, void *data)
-{
- NVICClass *nc = NVIC_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- nc->parent_reset = dc->reset;
- nc->parent_realize = dc->realize;
- dc->vmsd = &vmstate_nvic;
- dc->reset = armv7m_nvic_reset;
- dc->realize = armv7m_nvic_realize;
-}
-
-static const TypeInfo armv7m_nvic_info = {
- .name = TYPE_NVIC,
- .parent = TYPE_ARM_GIC_COMMON,
- .instance_init = armv7m_nvic_instance_init,
- .instance_size = sizeof(nvic_state),
- .class_init = armv7m_nvic_class_init,
- .class_size = sizeof(NVICClass),
-};
-
-static void armv7m_nvic_register_types(void)
-{
- type_register_static(&armv7m_nvic_info);
-}
-
-type_init(armv7m_nvic_register_types)
diff --git a/qemu/hw/intc/aspeed_vic.c b/qemu/hw/intc/aspeed_vic.c
deleted file mode 100644
index 19a0ff748..000000000
--- a/qemu/hw/intc/aspeed_vic.c
+++ /dev/null
@@ -1,339 +0,0 @@
-/*
- * ASPEED Interrupt Controller (New)
- *
- * Andrew Jeffery <andrew@aj.id.au>
- *
- * Copyright 2015, 2016 IBM Corp.
- *
- * This code is licensed under the GPL version 2 or later. See
- * the COPYING file in the top-level directory.
- */
-
-/* The hardware exposes two register sets, a legacy set and a 'new' set. The
- * model implements the 'new' register set, and logs warnings on accesses to
- * the legacy IO space.
- *
- * The hardware uses 32bit registers to manage 51 IRQs, with low and high
- * registers for each conceptual register. The device model's implementation
- * uses 64bit data types to store both low and high register values (in the one
- * member), but must cope with access offset values in multiples of 4 passed to
- * the callbacks. As such the read() and write() implementations process the
- * provided offset to understand whether the access is requesting the lower or
- * upper 32 bits of the 64bit member.
- *
- * Additionally, the "Interrupt Enable", "Edge Status" and "Software Interrupt"
- * fields have separate "enable"/"status" and "clear" registers, where set bits
- * are written to one or the other to change state (avoiding a
- * read-modify-write sequence).
- */
-
-#include "qemu/osdep.h"
-#include <inttypes.h>
-#include "hw/intc/aspeed_vic.h"
-#include "qemu/bitops.h"
-#include "trace.h"
-
-#define AVIC_NEW_BASE_OFFSET 0x80
-
-#define AVIC_L_MASK 0xFFFFFFFFU
-#define AVIC_H_MASK 0x0007FFFFU
-#define AVIC_EVENT_W_MASK (0x78000ULL << 32)
-
-static void aspeed_vic_update(AspeedVICState *s)
-{
- uint64_t new = (s->raw & s->enable);
- uint64_t flags;
-
- flags = new & s->select;
- trace_aspeed_vic_update_fiq(!!flags);
- qemu_set_irq(s->fiq, !!flags);
-
- flags = new & ~s->select;
- trace_aspeed_vic_update_irq(!!flags);
- qemu_set_irq(s->irq, !!flags);
-}
-
-static void aspeed_vic_set_irq(void *opaque, int irq, int level)
-{
- uint64_t irq_mask;
- bool raise;
- AspeedVICState *s = (AspeedVICState *)opaque;
-
- if (irq > ASPEED_VIC_NR_IRQS) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n",
- __func__, irq);
- return;
- }
-
- trace_aspeed_vic_set_irq(irq, level);
-
- irq_mask = BIT(irq);
- if (s->sense & irq_mask) {
- /* level-triggered */
- if (s->event & irq_mask) {
- /* high-sensitive */
- raise = level;
- } else {
- /* low-sensitive */
- raise = !level;
- }
- s->raw = deposit64(s->raw, irq, 1, raise);
- } else {
- uint64_t old_level = s->level & irq_mask;
-
- /* edge-triggered */
- if (s->dual_edge & irq_mask) {
- raise = (!!old_level) != (!!level);
- } else {
- if (s->event & irq_mask) {
- /* rising-sensitive */
- raise = !old_level && level;
- } else {
- /* falling-sensitive */
- raise = old_level && !level;
- }
- }
- if (raise) {
- s->raw = deposit64(s->raw, irq, 1, raise);
- }
- }
- s->level = deposit64(s->level, irq, 1, level);
- aspeed_vic_update(s);
-}
-
-static uint64_t aspeed_vic_read(void *opaque, hwaddr offset, unsigned size)
-{
- uint64_t val;
- const bool high = !!(offset & 0x4);
- hwaddr n_offset = (offset & ~0x4);
- AspeedVICState *s = (AspeedVICState *)opaque;
-
- if (offset < AVIC_NEW_BASE_OFFSET) {
- qemu_log_mask(LOG_UNIMP, "%s: Ignoring read from legacy registers "
- "at 0x%" HWADDR_PRIx "[%u]\n", __func__, offset, size);
- return 0;
- }
-
- n_offset -= AVIC_NEW_BASE_OFFSET;
-
- switch (n_offset) {
- case 0x0: /* IRQ Status */
- val = s->raw & ~s->select & s->enable;
- break;
- case 0x08: /* FIQ Status */
- val = s->raw & s->select & s->enable;
- break;
- case 0x10: /* Raw Interrupt Status */
- val = s->raw;
- break;
- case 0x18: /* Interrupt Selection */
- val = s->select;
- break;
- case 0x20: /* Interrupt Enable */
- val = s->enable;
- break;
- case 0x30: /* Software Interrupt */
- val = s->trigger;
- break;
- case 0x40: /* Interrupt Sensitivity */
- val = s->sense;
- break;
- case 0x48: /* Interrupt Both Edge Trigger Control */
- val = s->dual_edge;
- break;
- case 0x50: /* Interrupt Event */
- val = s->event;
- break;
- case 0x60: /* Edge Triggered Interrupt Status */
- val = s->raw & ~s->sense;
- break;
- /* Illegal */
- case 0x28: /* Interrupt Enable Clear */
- case 0x38: /* Software Interrupt Clear */
- case 0x58: /* Edge Triggered Interrupt Clear */
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Read of write-only register with offset 0x%"
- HWADDR_PRIx "\n", __func__, offset);
- val = 0;
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad register at offset 0x%" HWADDR_PRIx "\n",
- __func__, offset);
- val = 0;
- break;
- }
- if (high) {
- val = extract64(val, 32, 19);
- }
- trace_aspeed_vic_read(offset, size, val);
- return val;
-}
-
-static void aspeed_vic_write(void *opaque, hwaddr offset, uint64_t data,
- unsigned size)
-{
- const bool high = !!(offset & 0x4);
- hwaddr n_offset = (offset & ~0x4);
- AspeedVICState *s = (AspeedVICState *)opaque;
-
- if (offset < AVIC_NEW_BASE_OFFSET) {
- qemu_log_mask(LOG_UNIMP,
- "%s: Ignoring write to legacy registers at 0x%"
- HWADDR_PRIx "[%u] <- 0x%" PRIx64 "\n", __func__, offset,
- size, data);
- return;
- }
-
- n_offset -= AVIC_NEW_BASE_OFFSET;
- trace_aspeed_vic_write(offset, size, data);
-
- /* Given we have members using separate enable/clear registers, deposit64()
- * isn't quite the tool for the job. Instead, relocate the incoming bits to
- * the required bit offset based on the provided access address
- */
- if (high) {
- data &= AVIC_H_MASK;
- data <<= 32;
- } else {
- data &= AVIC_L_MASK;
- }
-
- switch (n_offset) {
- case 0x18: /* Interrupt Selection */
- /* Register has deposit64() semantics - overwrite requested 32 bits */
- if (high) {
- s->select &= AVIC_L_MASK;
- } else {
- s->select &= ((uint64_t) AVIC_H_MASK) << 32;
- }
- s->select |= data;
- break;
- case 0x20: /* Interrupt Enable */
- s->enable |= data;
- break;
- case 0x28: /* Interrupt Enable Clear */
- s->enable &= ~data;
- break;
- case 0x30: /* Software Interrupt */
- qemu_log_mask(LOG_UNIMP, "%s: Software interrupts unavailable. "
- "IRQs requested: 0x%016" PRIx64 "\n", __func__, data);
- break;
- case 0x38: /* Software Interrupt Clear */
- qemu_log_mask(LOG_UNIMP, "%s: Software interrupts unavailable. "
- "IRQs to be cleared: 0x%016" PRIx64 "\n", __func__, data);
- break;
- case 0x50: /* Interrupt Event */
- /* Register has deposit64() semantics - overwrite the top four valid
- * IRQ bits, as only the top four IRQs (GPIOs) can change their event
- * type */
- if (high) {
- s->event &= ~AVIC_EVENT_W_MASK;
- s->event |= (data & AVIC_EVENT_W_MASK);
- } else {
- qemu_log_mask(LOG_GUEST_ERROR,
- "Ignoring invalid write to interrupt event register");
- }
- break;
- case 0x58: /* Edge Triggered Interrupt Clear */
- s->raw &= ~(data & ~s->sense);
- break;
- case 0x00: /* IRQ Status */
- case 0x08: /* FIQ Status */
- case 0x10: /* Raw Interrupt Status */
- case 0x40: /* Interrupt Sensitivity */
- case 0x48: /* Interrupt Both Edge Trigger Control */
- case 0x60: /* Edge Triggered Interrupt Status */
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Write of read-only register with offset 0x%"
- HWADDR_PRIx "\n", __func__, offset);
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad register at offset 0x%" HWADDR_PRIx "\n",
- __func__, offset);
- break;
- }
- aspeed_vic_update(s);
-}
-
-static const MemoryRegionOps aspeed_vic_ops = {
- .read = aspeed_vic_read,
- .write = aspeed_vic_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .valid.min_access_size = 4,
- .valid.max_access_size = 4,
- .valid.unaligned = false,
-};
-
-static void aspeed_vic_reset(DeviceState *dev)
-{
- AspeedVICState *s = ASPEED_VIC(dev);
-
- s->level = 0;
- s->raw = 0;
- s->select = 0;
- s->enable = 0;
- s->trigger = 0;
- s->sense = 0x1F07FFF8FFFFULL;
- s->dual_edge = 0xF800070000ULL;
- s->event = 0x5F07FFF8FFFFULL;
-}
-
-#define AVIC_IO_REGION_SIZE 0x20000
-
-static void aspeed_vic_realize(DeviceState *dev, Error **errp)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- AspeedVICState *s = ASPEED_VIC(dev);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_vic_ops, s,
- TYPE_ASPEED_VIC, AVIC_IO_REGION_SIZE);
-
- sysbus_init_mmio(sbd, &s->iomem);
-
- qdev_init_gpio_in(dev, aspeed_vic_set_irq, ASPEED_VIC_NR_IRQS);
- sysbus_init_irq(sbd, &s->irq);
- sysbus_init_irq(sbd, &s->fiq);
-}
-
-static const VMStateDescription vmstate_aspeed_vic = {
- .name = "aspeed.new-vic",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT64(level, AspeedVICState),
- VMSTATE_UINT64(raw, AspeedVICState),
- VMSTATE_UINT64(select, AspeedVICState),
- VMSTATE_UINT64(enable, AspeedVICState),
- VMSTATE_UINT64(trigger, AspeedVICState),
- VMSTATE_UINT64(sense, AspeedVICState),
- VMSTATE_UINT64(dual_edge, AspeedVICState),
- VMSTATE_UINT64(event, AspeedVICState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void aspeed_vic_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- dc->realize = aspeed_vic_realize;
- dc->reset = aspeed_vic_reset;
- dc->desc = "ASPEED Interrupt Controller (New)";
- dc->vmsd = &vmstate_aspeed_vic;
-}
-
-static const TypeInfo aspeed_vic_info = {
- .name = TYPE_ASPEED_VIC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(AspeedVICState),
- .class_init = aspeed_vic_class_init,
-};
-
-static void aspeed_vic_register_types(void)
-{
- type_register_static(&aspeed_vic_info);
-}
-
-type_init(aspeed_vic_register_types);
diff --git a/qemu/hw/intc/bcm2835_ic.c b/qemu/hw/intc/bcm2835_ic.c
deleted file mode 100644
index 80513b28f..000000000
--- a/qemu/hw/intc/bcm2835_ic.c
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * Raspberry Pi emulation (c) 2012 Gregory Estrade
- * Refactoring for Pi2 Copyright (c) 2015, Microsoft. Written by Andrew Baumann.
- * This code is licensed under the GNU GPLv2 and later.
- * Heavily based on pl190.c, copyright terms below:
- *
- * Arm PrimeCell PL190 Vector Interrupt Controller
- *
- * Copyright (c) 2006 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-#include "qemu/osdep.h"
-#include "hw/intc/bcm2835_ic.h"
-
-#define GPU_IRQS 64
-#define ARM_IRQS 8
-
-#define IRQ_PENDING_BASIC 0x00 /* IRQ basic pending */
-#define IRQ_PENDING_1 0x04 /* IRQ pending 1 */
-#define IRQ_PENDING_2 0x08 /* IRQ pending 2 */
-#define FIQ_CONTROL 0x0C /* FIQ register */
-#define IRQ_ENABLE_1 0x10 /* Interrupt enable register 1 */
-#define IRQ_ENABLE_2 0x14 /* Interrupt enable register 2 */
-#define IRQ_ENABLE_BASIC 0x18 /* Base interrupt enable register */
-#define IRQ_DISABLE_1 0x1C /* Interrupt disable register 1 */
-#define IRQ_DISABLE_2 0x20 /* Interrupt disable register 2 */
-#define IRQ_DISABLE_BASIC 0x24 /* Base interrupt disable register */
-
-/* Update interrupts. */
-static void bcm2835_ic_update(BCM2835ICState *s)
-{
- bool set = false;
-
- if (s->fiq_enable) {
- if (s->fiq_select >= GPU_IRQS) {
- /* ARM IRQ */
- set = extract32(s->arm_irq_level, s->fiq_select - GPU_IRQS, 1);
- } else {
- set = extract64(s->gpu_irq_level, s->fiq_select, 1);
- }
- }
- qemu_set_irq(s->fiq, set);
-
- set = (s->gpu_irq_level & s->gpu_irq_enable)
- || (s->arm_irq_level & s->arm_irq_enable);
- qemu_set_irq(s->irq, set);
-
-}
-
-static void bcm2835_ic_set_gpu_irq(void *opaque, int irq, int level)
-{
- BCM2835ICState *s = opaque;
-
- assert(irq >= 0 && irq < 64);
- s->gpu_irq_level = deposit64(s->gpu_irq_level, irq, 1, level != 0);
- bcm2835_ic_update(s);
-}
-
-static void bcm2835_ic_set_arm_irq(void *opaque, int irq, int level)
-{
- BCM2835ICState *s = opaque;
-
- assert(irq >= 0 && irq < 8);
- s->arm_irq_level = deposit32(s->arm_irq_level, irq, 1, level != 0);
- bcm2835_ic_update(s);
-}
-
-static const int irq_dups[] = { 7, 9, 10, 18, 19, 53, 54, 55, 56, 57, 62 };
-
-static uint64_t bcm2835_ic_read(void *opaque, hwaddr offset, unsigned size)
-{
- BCM2835ICState *s = opaque;
- uint32_t res = 0;
- uint64_t gpu_pending = s->gpu_irq_level & s->gpu_irq_enable;
- int i;
-
- switch (offset) {
- case IRQ_PENDING_BASIC:
- /* bits 0-7: ARM irqs */
- res = s->arm_irq_level & s->arm_irq_enable;
-
- /* bits 8 & 9: pending registers 1 & 2 */
- res |= (((uint32_t)gpu_pending) != 0) << 8;
- res |= ((gpu_pending >> 32) != 0) << 9;
-
- /* bits 10-20: selected GPU IRQs */
- for (i = 0; i < ARRAY_SIZE(irq_dups); i++) {
- res |= extract64(gpu_pending, irq_dups[i], 1) << (i + 10);
- }
- break;
- case IRQ_PENDING_1:
- res = gpu_pending;
- break;
- case IRQ_PENDING_2:
- res = gpu_pending >> 32;
- break;
- case FIQ_CONTROL:
- res = (s->fiq_enable << 7) | s->fiq_select;
- break;
- case IRQ_ENABLE_1:
- res = s->gpu_irq_enable;
- break;
- case IRQ_ENABLE_2:
- res = s->gpu_irq_enable >> 32;
- break;
- case IRQ_ENABLE_BASIC:
- res = s->arm_irq_enable;
- break;
- case IRQ_DISABLE_1:
- res = ~s->gpu_irq_enable;
- break;
- case IRQ_DISABLE_2:
- res = ~s->gpu_irq_enable >> 32;
- break;
- case IRQ_DISABLE_BASIC:
- res = ~s->arm_irq_enable;
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
- __func__, offset);
- return 0;
- }
-
- return res;
-}
-
-static void bcm2835_ic_write(void *opaque, hwaddr offset, uint64_t val,
- unsigned size)
-{
- BCM2835ICState *s = opaque;
-
- switch (offset) {
- case FIQ_CONTROL:
- s->fiq_select = extract32(val, 0, 7);
- s->fiq_enable = extract32(val, 7, 1);
- break;
- case IRQ_ENABLE_1:
- s->gpu_irq_enable |= val;
- break;
- case IRQ_ENABLE_2:
- s->gpu_irq_enable |= val << 32;
- break;
- case IRQ_ENABLE_BASIC:
- s->arm_irq_enable |= val & 0xff;
- break;
- case IRQ_DISABLE_1:
- s->gpu_irq_enable &= ~val;
- break;
- case IRQ_DISABLE_2:
- s->gpu_irq_enable &= ~(val << 32);
- break;
- case IRQ_DISABLE_BASIC:
- s->arm_irq_enable &= ~val & 0xff;
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
- __func__, offset);
- return;
- }
- bcm2835_ic_update(s);
-}
-
-static const MemoryRegionOps bcm2835_ic_ops = {
- .read = bcm2835_ic_read,
- .write = bcm2835_ic_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid.min_access_size = 4,
- .valid.max_access_size = 4,
-};
-
-static void bcm2835_ic_reset(DeviceState *d)
-{
- BCM2835ICState *s = BCM2835_IC(d);
-
- s->gpu_irq_enable = 0;
- s->arm_irq_enable = 0;
- s->fiq_enable = false;
- s->fiq_select = 0;
-}
-
-static void bcm2835_ic_init(Object *obj)
-{
- BCM2835ICState *s = BCM2835_IC(obj);
-
- memory_region_init_io(&s->iomem, obj, &bcm2835_ic_ops, s, TYPE_BCM2835_IC,
- 0x200);
- sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
-
- qdev_init_gpio_in_named(DEVICE(s), bcm2835_ic_set_gpu_irq,
- BCM2835_IC_GPU_IRQ, GPU_IRQS);
- qdev_init_gpio_in_named(DEVICE(s), bcm2835_ic_set_arm_irq,
- BCM2835_IC_ARM_IRQ, ARM_IRQS);
-
- sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq);
- sysbus_init_irq(SYS_BUS_DEVICE(s), &s->fiq);
-}
-
-static const VMStateDescription vmstate_bcm2835_ic = {
- .name = TYPE_BCM2835_IC,
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT64(gpu_irq_level, BCM2835ICState),
- VMSTATE_UINT64(gpu_irq_enable, BCM2835ICState),
- VMSTATE_UINT8(arm_irq_level, BCM2835ICState),
- VMSTATE_UINT8(arm_irq_enable, BCM2835ICState),
- VMSTATE_BOOL(fiq_enable, BCM2835ICState),
- VMSTATE_UINT8(fiq_select, BCM2835ICState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void bcm2835_ic_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->reset = bcm2835_ic_reset;
- dc->vmsd = &vmstate_bcm2835_ic;
-}
-
-static TypeInfo bcm2835_ic_info = {
- .name = TYPE_BCM2835_IC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(BCM2835ICState),
- .class_init = bcm2835_ic_class_init,
- .instance_init = bcm2835_ic_init,
-};
-
-static void bcm2835_ic_register_types(void)
-{
- type_register_static(&bcm2835_ic_info);
-}
-
-type_init(bcm2835_ic_register_types)
diff --git a/qemu/hw/intc/bcm2836_control.c b/qemu/hw/intc/bcm2836_control.c
deleted file mode 100644
index d0271810c..000000000
--- a/qemu/hw/intc/bcm2836_control.c
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * Rasperry Pi 2 emulation ARM control logic module.
- * Copyright (c) 2015, Microsoft
- * Written by Andrew Baumann
- *
- * Based on bcm2835_ic.c (Raspberry Pi emulation) (c) 2012 Gregory Estrade
- * This code is licensed under the GNU GPLv2 and later.
- *
- * At present, only implements interrupt routing, and mailboxes (i.e.,
- * not local timer, PMU interrupt, or AXI counters).
- *
- * Ref:
- * https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836/QA7_rev3.4.pdf
- */
-
-#include "qemu/osdep.h"
-#include "hw/intc/bcm2836_control.h"
-
-#define REG_GPU_ROUTE 0x0c
-#define REG_TIMERCONTROL 0x40
-#define REG_MBOXCONTROL 0x50
-#define REG_IRQSRC 0x60
-#define REG_FIQSRC 0x70
-#define REG_MBOX0_WR 0x80
-#define REG_MBOX0_RDCLR 0xc0
-#define REG_LIMIT 0x100
-
-#define IRQ_BIT(cntrl, num) (((cntrl) & (1 << (num))) != 0)
-#define FIQ_BIT(cntrl, num) (((cntrl) & (1 << ((num) + 4))) != 0)
-
-#define IRQ_CNTPSIRQ 0
-#define IRQ_CNTPNSIRQ 1
-#define IRQ_CNTHPIRQ 2
-#define IRQ_CNTVIRQ 3
-#define IRQ_MAILBOX0 4
-#define IRQ_MAILBOX1 5
-#define IRQ_MAILBOX2 6
-#define IRQ_MAILBOX3 7
-#define IRQ_GPU 8
-#define IRQ_PMU 9
-#define IRQ_AXI 10
-#define IRQ_TIMER 11
-#define IRQ_MAX IRQ_TIMER
-
-static void deliver_local(BCM2836ControlState *s, uint8_t core, uint8_t irq,
- uint32_t controlreg, uint8_t controlidx)
-{
- if (FIQ_BIT(controlreg, controlidx)) {
- /* deliver a FIQ */
- s->fiqsrc[core] |= (uint32_t)1 << irq;
- } else if (IRQ_BIT(controlreg, controlidx)) {
- /* deliver an IRQ */
- s->irqsrc[core] |= (uint32_t)1 << irq;
- } else {
- /* the interrupt is masked */
- }
-}
-
-/* Update interrupts. */
-static void bcm2836_control_update(BCM2836ControlState *s)
-{
- int i, j;
-
- /* reset pending IRQs/FIQs */
- for (i = 0; i < BCM2836_NCORES; i++) {
- s->irqsrc[i] = s->fiqsrc[i] = 0;
- }
-
- /* apply routing logic, update status regs */
- if (s->gpu_irq) {
- assert(s->route_gpu_irq < BCM2836_NCORES);
- s->irqsrc[s->route_gpu_irq] |= (uint32_t)1 << IRQ_GPU;
- }
-
- if (s->gpu_fiq) {
- assert(s->route_gpu_fiq < BCM2836_NCORES);
- s->fiqsrc[s->route_gpu_fiq] |= (uint32_t)1 << IRQ_GPU;
- }
-
- for (i = 0; i < BCM2836_NCORES; i++) {
- /* handle local timer interrupts for this core */
- if (s->timerirqs[i]) {
- assert(s->timerirqs[i] < (1 << (IRQ_CNTVIRQ + 1))); /* sane mask? */
- for (j = 0; j <= IRQ_CNTVIRQ; j++) {
- if ((s->timerirqs[i] & (1 << j)) != 0) {
- /* local interrupt j is set */
- deliver_local(s, i, j, s->timercontrol[i], j);
- }
- }
- }
-
- /* handle mailboxes for this core */
- for (j = 0; j < BCM2836_MBPERCORE; j++) {
- if (s->mailboxes[i * BCM2836_MBPERCORE + j] != 0) {
- /* mailbox j is set */
- deliver_local(s, i, j + IRQ_MAILBOX0, s->mailboxcontrol[i], j);
- }
- }
- }
-
- /* call set_irq appropriately for each output */
- for (i = 0; i < BCM2836_NCORES; i++) {
- qemu_set_irq(s->irq[i], s->irqsrc[i] != 0);
- qemu_set_irq(s->fiq[i], s->fiqsrc[i] != 0);
- }
-}
-
-static void bcm2836_control_set_local_irq(void *opaque, int core, int local_irq,
- int level)
-{
- BCM2836ControlState *s = opaque;
-
- assert(core >= 0 && core < BCM2836_NCORES);
- assert(local_irq >= 0 && local_irq <= IRQ_CNTVIRQ);
-
- s->timerirqs[core] = deposit32(s->timerirqs[core], local_irq, 1, !!level);
-
- bcm2836_control_update(s);
-}
-
-/* XXX: the following wrapper functions are a kludgy workaround,
- * needed because I can't seem to pass useful information in the "irq"
- * parameter when using named interrupts. Feel free to clean this up!
- */
-
-static void bcm2836_control_set_local_irq0(void *opaque, int core, int level)
-{
- bcm2836_control_set_local_irq(opaque, core, 0, level);
-}
-
-static void bcm2836_control_set_local_irq1(void *opaque, int core, int level)
-{
- bcm2836_control_set_local_irq(opaque, core, 1, level);
-}
-
-static void bcm2836_control_set_local_irq2(void *opaque, int core, int level)
-{
- bcm2836_control_set_local_irq(opaque, core, 2, level);
-}
-
-static void bcm2836_control_set_local_irq3(void *opaque, int core, int level)
-{
- bcm2836_control_set_local_irq(opaque, core, 3, level);
-}
-
-static void bcm2836_control_set_gpu_irq(void *opaque, int irq, int level)
-{
- BCM2836ControlState *s = opaque;
-
- s->gpu_irq = level;
-
- bcm2836_control_update(s);
-}
-
-static void bcm2836_control_set_gpu_fiq(void *opaque, int irq, int level)
-{
- BCM2836ControlState *s = opaque;
-
- s->gpu_fiq = level;
-
- bcm2836_control_update(s);
-}
-
-static uint64_t bcm2836_control_read(void *opaque, hwaddr offset, unsigned size)
-{
- BCM2836ControlState *s = opaque;
-
- if (offset == REG_GPU_ROUTE) {
- assert(s->route_gpu_fiq < BCM2836_NCORES
- && s->route_gpu_irq < BCM2836_NCORES);
- return ((uint32_t)s->route_gpu_fiq << 2) | s->route_gpu_irq;
- } else if (offset >= REG_TIMERCONTROL && offset < REG_MBOXCONTROL) {
- return s->timercontrol[(offset - REG_TIMERCONTROL) >> 2];
- } else if (offset >= REG_MBOXCONTROL && offset < REG_IRQSRC) {
- return s->mailboxcontrol[(offset - REG_MBOXCONTROL) >> 2];
- } else if (offset >= REG_IRQSRC && offset < REG_FIQSRC) {
- return s->irqsrc[(offset - REG_IRQSRC) >> 2];
- } else if (offset >= REG_FIQSRC && offset < REG_MBOX0_WR) {
- return s->fiqsrc[(offset - REG_FIQSRC) >> 2];
- } else if (offset >= REG_MBOX0_RDCLR && offset < REG_LIMIT) {
- return s->mailboxes[(offset - REG_MBOX0_RDCLR) >> 2];
- } else {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
- __func__, offset);
- return 0;
- }
-}
-
-static void bcm2836_control_write(void *opaque, hwaddr offset,
- uint64_t val, unsigned size)
-{
- BCM2836ControlState *s = opaque;
-
- if (offset == REG_GPU_ROUTE) {
- s->route_gpu_irq = val & 0x3;
- s->route_gpu_fiq = (val >> 2) & 0x3;
- } else if (offset >= REG_TIMERCONTROL && offset < REG_MBOXCONTROL) {
- s->timercontrol[(offset - REG_TIMERCONTROL) >> 2] = val & 0xff;
- } else if (offset >= REG_MBOXCONTROL && offset < REG_IRQSRC) {
- s->mailboxcontrol[(offset - REG_MBOXCONTROL) >> 2] = val & 0xff;
- } else if (offset >= REG_MBOX0_WR && offset < REG_MBOX0_RDCLR) {
- s->mailboxes[(offset - REG_MBOX0_WR) >> 2] |= val;
- } else if (offset >= REG_MBOX0_RDCLR && offset < REG_LIMIT) {
- s->mailboxes[(offset - REG_MBOX0_RDCLR) >> 2] &= ~val;
- } else {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
- __func__, offset);
- return;
- }
-
- bcm2836_control_update(s);
-}
-
-static const MemoryRegionOps bcm2836_control_ops = {
- .read = bcm2836_control_read,
- .write = bcm2836_control_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid.min_access_size = 4,
- .valid.max_access_size = 4,
-};
-
-static void bcm2836_control_reset(DeviceState *d)
-{
- BCM2836ControlState *s = BCM2836_CONTROL(d);
- int i;
-
- s->route_gpu_irq = s->route_gpu_fiq = 0;
-
- for (i = 0; i < BCM2836_NCORES; i++) {
- s->timercontrol[i] = 0;
- s->mailboxcontrol[i] = 0;
- }
-
- for (i = 0; i < BCM2836_NCORES * BCM2836_MBPERCORE; i++) {
- s->mailboxes[i] = 0;
- }
-}
-
-static void bcm2836_control_init(Object *obj)
-{
- BCM2836ControlState *s = BCM2836_CONTROL(obj);
- DeviceState *dev = DEVICE(obj);
-
- memory_region_init_io(&s->iomem, obj, &bcm2836_control_ops, s,
- TYPE_BCM2836_CONTROL, REG_LIMIT);
- sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
-
- /* inputs from each CPU core */
- qdev_init_gpio_in_named(dev, bcm2836_control_set_local_irq0, "cntpsirq",
- BCM2836_NCORES);
- qdev_init_gpio_in_named(dev, bcm2836_control_set_local_irq1, "cntpnsirq",
- BCM2836_NCORES);
- qdev_init_gpio_in_named(dev, bcm2836_control_set_local_irq2, "cnthpirq",
- BCM2836_NCORES);
- qdev_init_gpio_in_named(dev, bcm2836_control_set_local_irq3, "cntvirq",
- BCM2836_NCORES);
-
- /* IRQ and FIQ inputs from upstream bcm2835 controller */
- qdev_init_gpio_in_named(dev, bcm2836_control_set_gpu_irq, "gpu-irq", 1);
- qdev_init_gpio_in_named(dev, bcm2836_control_set_gpu_fiq, "gpu-fiq", 1);
-
- /* outputs to CPU cores */
- qdev_init_gpio_out_named(dev, s->irq, "irq", BCM2836_NCORES);
- qdev_init_gpio_out_named(dev, s->fiq, "fiq", BCM2836_NCORES);
-}
-
-static const VMStateDescription vmstate_bcm2836_control = {
- .name = TYPE_BCM2836_CONTROL,
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(mailboxes, BCM2836ControlState,
- BCM2836_NCORES * BCM2836_MBPERCORE),
- VMSTATE_UINT8(route_gpu_irq, BCM2836ControlState),
- VMSTATE_UINT8(route_gpu_fiq, BCM2836ControlState),
- VMSTATE_UINT32_ARRAY(timercontrol, BCM2836ControlState, BCM2836_NCORES),
- VMSTATE_UINT32_ARRAY(mailboxcontrol, BCM2836ControlState,
- BCM2836_NCORES),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void bcm2836_control_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->reset = bcm2836_control_reset;
- dc->vmsd = &vmstate_bcm2836_control;
-}
-
-static TypeInfo bcm2836_control_info = {
- .name = TYPE_BCM2836_CONTROL,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(BCM2836ControlState),
- .class_init = bcm2836_control_class_init,
- .instance_init = bcm2836_control_init,
-};
-
-static void bcm2836_control_register_types(void)
-{
- type_register_static(&bcm2836_control_info);
-}
-
-type_init(bcm2836_control_register_types)
diff --git a/qemu/hw/intc/etraxfs_pic.c b/qemu/hw/intc/etraxfs_pic.c
deleted file mode 100644
index 48f947706..000000000
--- a/qemu/hw/intc/etraxfs_pic.c
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * QEMU ETRAX Interrupt Controller.
- *
- * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "hw/hw.h"
-//#include "pc.h"
-//#include "etraxfs.h"
-
-#define D(x)
-
-#define R_RW_MASK 0
-#define R_R_VECT 1
-#define R_R_MASKED_VECT 2
-#define R_R_NMI 3
-#define R_R_GURU 4
-#define R_MAX 5
-
-#define TYPE_ETRAX_FS_PIC "etraxfs,pic"
-#define ETRAX_FS_PIC(obj) \
- OBJECT_CHECK(struct etrax_pic, (obj), TYPE_ETRAX_FS_PIC)
-
-struct etrax_pic
-{
- SysBusDevice parent_obj;
-
- MemoryRegion mmio;
- void *interrupt_vector;
- qemu_irq parent_irq;
- qemu_irq parent_nmi;
- uint32_t regs[R_MAX];
-};
-
-static void pic_update(struct etrax_pic *fs)
-{
- uint32_t vector = 0;
- int i;
-
- fs->regs[R_R_MASKED_VECT] = fs->regs[R_R_VECT] & fs->regs[R_RW_MASK];
-
- /* The ETRAX interrupt controller signals interrupts to the core
- through an interrupt request wire and an irq vector bus. If
- multiple interrupts are simultaneously active it chooses vector
- 0x30 and lets the sw choose the priorities. */
- if (fs->regs[R_R_MASKED_VECT]) {
- uint32_t mv = fs->regs[R_R_MASKED_VECT];
- for (i = 0; i < 31; i++) {
- if (mv & 1) {
- vector = 0x31 + i;
- /* Check for multiple interrupts. */
- if (mv > 1)
- vector = 0x30;
- break;
- }
- mv >>= 1;
- }
- }
-
- if (fs->interrupt_vector) {
- /* hack alert: ptr property */
- *(uint32_t*)(fs->interrupt_vector) = vector;
- }
- qemu_set_irq(fs->parent_irq, !!vector);
-}
-
-static uint64_t
-pic_read(void *opaque, hwaddr addr, unsigned int size)
-{
- struct etrax_pic *fs = opaque;
- uint32_t rval;
-
- rval = fs->regs[addr >> 2];
- D(printf("%s %x=%x\n", __func__, addr, rval));
- return rval;
-}
-
-static void pic_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned int size)
-{
- struct etrax_pic *fs = opaque;
- D(printf("%s addr=%x val=%x\n", __func__, addr, value));
-
- if (addr == R_RW_MASK) {
- fs->regs[R_RW_MASK] = value;
- pic_update(fs);
- }
-}
-
-static const MemoryRegionOps pic_ops = {
- .read = pic_read,
- .write = pic_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4
- }
-};
-
-static void nmi_handler(void *opaque, int irq, int level)
-{
- struct etrax_pic *fs = (void *)opaque;
- uint32_t mask;
-
- mask = 1 << irq;
- if (level)
- fs->regs[R_R_NMI] |= mask;
- else
- fs->regs[R_R_NMI] &= ~mask;
-
- qemu_set_irq(fs->parent_nmi, !!fs->regs[R_R_NMI]);
-}
-
-static void irq_handler(void *opaque, int irq, int level)
-{
- struct etrax_pic *fs = (void *)opaque;
-
- if (irq >= 30) {
- nmi_handler(opaque, irq, level);
- return;
- }
-
- irq -= 1;
- fs->regs[R_R_VECT] &= ~(1 << irq);
- fs->regs[R_R_VECT] |= (!!level << irq);
- pic_update(fs);
-}
-
-static int etraxfs_pic_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- struct etrax_pic *s = ETRAX_FS_PIC(dev);
-
- qdev_init_gpio_in(dev, irq_handler, 32);
- sysbus_init_irq(sbd, &s->parent_irq);
- sysbus_init_irq(sbd, &s->parent_nmi);
-
- memory_region_init_io(&s->mmio, OBJECT(s), &pic_ops, s,
- "etraxfs-pic", R_MAX * 4);
- sysbus_init_mmio(sbd, &s->mmio);
- return 0;
-}
-
-static Property etraxfs_pic_properties[] = {
- DEFINE_PROP_PTR("interrupt_vector", struct etrax_pic, interrupt_vector),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void etraxfs_pic_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = etraxfs_pic_init;
- dc->props = etraxfs_pic_properties;
- /*
- * Note: pointer property "interrupt_vector" may remain null, thus
- * no need for dc->cannot_instantiate_with_device_add_yet = true;
- */
-}
-
-static const TypeInfo etraxfs_pic_info = {
- .name = TYPE_ETRAX_FS_PIC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(struct etrax_pic),
- .class_init = etraxfs_pic_class_init,
-};
-
-static void etraxfs_pic_register_types(void)
-{
- type_register_static(&etraxfs_pic_info);
-}
-
-type_init(etraxfs_pic_register_types)
diff --git a/qemu/hw/intc/exynos4210_combiner.c b/qemu/hw/intc/exynos4210_combiner.c
deleted file mode 100644
index dc0c90326..000000000
--- a/qemu/hw/intc/exynos4210_combiner.c
+++ /dev/null
@@ -1,459 +0,0 @@
-/*
- * Samsung exynos4210 Interrupt Combiner
- *
- * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
- * All rights reserved.
- *
- * Evgeny Voevodin <e.voevodin@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * Exynos4210 Combiner represents an OR gate for SOC's IRQ lines. It combines
- * IRQ sources into groups and provides signal output to GIC from each group. It
- * is driven by common mask and enable/disable logic. Take a note that not all
- * IRQs are passed to GIC through Combiner.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-
-#include "hw/arm/exynos4210.h"
-
-//#define DEBUG_COMBINER
-
-#ifdef DEBUG_COMBINER
-#define DPRINTF(fmt, ...) \
- do { fprintf(stdout, "COMBINER: [%s:%d] " fmt, __func__ , __LINE__, \
- ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while (0)
-#endif
-
-#define IIC_NGRP 64 /* Internal Interrupt Combiner
- Groups number */
-#define IIC_NIRQ (IIC_NGRP * 8)/* Internal Interrupt Combiner
- Interrupts number */
-#define IIC_REGION_SIZE 0x108 /* Size of memory mapped region */
-#define IIC_REGSET_SIZE 0x41
-
-/*
- * State for each output signal of internal combiner
- */
-typedef struct CombinerGroupState {
- uint8_t src_mask; /* 1 - source enabled, 0 - disabled */
- uint8_t src_pending; /* Pending source interrupts before masking */
-} CombinerGroupState;
-
-#define TYPE_EXYNOS4210_COMBINER "exynos4210.combiner"
-#define EXYNOS4210_COMBINER(obj) \
- OBJECT_CHECK(Exynos4210CombinerState, (obj), TYPE_EXYNOS4210_COMBINER)
-
-typedef struct Exynos4210CombinerState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
-
- struct CombinerGroupState group[IIC_NGRP];
- uint32_t reg_set[IIC_REGSET_SIZE];
- uint32_t icipsr[2];
- uint32_t external; /* 1 means that this combiner is external */
-
- qemu_irq output_irq[IIC_NGRP];
-} Exynos4210CombinerState;
-
-static const VMStateDescription vmstate_exynos4210_combiner_group_state = {
- .name = "exynos4210.combiner.groupstate",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(src_mask, CombinerGroupState),
- VMSTATE_UINT8(src_pending, CombinerGroupState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_exynos4210_combiner = {
- .name = "exynos4210.combiner",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT_ARRAY(group, Exynos4210CombinerState, IIC_NGRP, 0,
- vmstate_exynos4210_combiner_group_state, CombinerGroupState),
- VMSTATE_UINT32_ARRAY(reg_set, Exynos4210CombinerState,
- IIC_REGSET_SIZE),
- VMSTATE_UINT32_ARRAY(icipsr, Exynos4210CombinerState, 2),
- VMSTATE_UINT32(external, Exynos4210CombinerState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-/*
- * Get Combiner input GPIO into irqs structure
- */
-void exynos4210_combiner_get_gpioin(Exynos4210Irq *irqs, DeviceState *dev,
- int ext)
-{
- int n;
- int bit;
- int max;
- qemu_irq *irq;
-
- max = ext ? EXYNOS4210_MAX_EXT_COMBINER_IN_IRQ :
- EXYNOS4210_MAX_INT_COMBINER_IN_IRQ;
- irq = ext ? irqs->ext_combiner_irq : irqs->int_combiner_irq;
-
- /*
- * Some IRQs of Int/External Combiner are going to two Combiners groups,
- * so let split them.
- */
- for (n = 0; n < max; n++) {
-
- bit = EXYNOS4210_COMBINER_GET_BIT_NUM(n);
-
- switch (n) {
- /* MDNIE_LCD1 INTG1 */
- case EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 0) ...
- EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 3):
- irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n),
- irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(0, bit + 4)]);
- continue;
-
- /* TMU INTG3 */
- case EXYNOS4210_COMBINER_GET_IRQ_NUM(3, 4):
- irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n),
- irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(2, bit)]);
- continue;
-
- /* LCD1 INTG12 */
- case EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 0) ...
- EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 3):
- irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n),
- irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(11, bit + 4)]);
- continue;
-
- /* Multi-Core Timer INTG12 */
- case EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 4) ...
- EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 8):
- irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n),
- irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(1, bit + 4)]);
- continue;
-
- /* Multi-Core Timer INTG35 */
- case EXYNOS4210_COMBINER_GET_IRQ_NUM(35, 4) ...
- EXYNOS4210_COMBINER_GET_IRQ_NUM(35, 8):
- irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n),
- irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(1, bit + 4)]);
- continue;
-
- /* Multi-Core Timer INTG51 */
- case EXYNOS4210_COMBINER_GET_IRQ_NUM(51, 4) ...
- EXYNOS4210_COMBINER_GET_IRQ_NUM(51, 8):
- irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n),
- irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(1, bit + 4)]);
- continue;
-
- /* Multi-Core Timer INTG53 */
- case EXYNOS4210_COMBINER_GET_IRQ_NUM(53, 4) ...
- EXYNOS4210_COMBINER_GET_IRQ_NUM(53, 8):
- irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n),
- irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(1, bit + 4)]);
- continue;
- }
-
- irq[n] = qdev_get_gpio_in(dev, n);
- }
-}
-
-static uint64_t
-exynos4210_combiner_read(void *opaque, hwaddr offset, unsigned size)
-{
- struct Exynos4210CombinerState *s =
- (struct Exynos4210CombinerState *)opaque;
- uint32_t req_quad_base_n; /* Base of registers quad. Multiply it by 4 and
- get a start of corresponding group quad */
- uint32_t grp_quad_base_n; /* Base of group quad */
- uint32_t reg_n; /* Register number inside the quad */
- uint32_t val;
-
- req_quad_base_n = offset >> 4;
- grp_quad_base_n = req_quad_base_n << 2;
- reg_n = (offset - (req_quad_base_n << 4)) >> 2;
-
- if (req_quad_base_n >= IIC_NGRP) {
- /* Read of ICIPSR register */
- return s->icipsr[reg_n];
- }
-
- val = 0;
-
- switch (reg_n) {
- /* IISTR */
- case 2:
- val |= s->group[grp_quad_base_n].src_pending;
- val |= s->group[grp_quad_base_n + 1].src_pending << 8;
- val |= s->group[grp_quad_base_n + 2].src_pending << 16;
- val |= s->group[grp_quad_base_n + 3].src_pending << 24;
- break;
- /* IIMSR */
- case 3:
- val |= s->group[grp_quad_base_n].src_mask &
- s->group[grp_quad_base_n].src_pending;
- val |= (s->group[grp_quad_base_n + 1].src_mask &
- s->group[grp_quad_base_n + 1].src_pending) << 8;
- val |= (s->group[grp_quad_base_n + 2].src_mask &
- s->group[grp_quad_base_n + 2].src_pending) << 16;
- val |= (s->group[grp_quad_base_n + 3].src_mask &
- s->group[grp_quad_base_n + 3].src_pending) << 24;
- break;
- default:
- if (offset >> 2 >= IIC_REGSET_SIZE) {
- hw_error("exynos4210.combiner: overflow of reg_set by 0x"
- TARGET_FMT_plx "offset\n", offset);
- }
- val = s->reg_set[offset >> 2];
- return 0;
- }
- return val;
-}
-
-static void exynos4210_combiner_update(void *opaque, uint8_t group_n)
-{
- struct Exynos4210CombinerState *s =
- (struct Exynos4210CombinerState *)opaque;
-
- /* Send interrupt if needed */
- if (s->group[group_n].src_mask & s->group[group_n].src_pending) {
-#ifdef DEBUG_COMBINER
- if (group_n != 26) {
- /* skip uart */
- DPRINTF("%s raise IRQ[%d]\n", s->external ? "EXT" : "INT", group_n);
- }
-#endif
-
- /* Set Combiner interrupt pending status after masking */
- if (group_n >= 32) {
- s->icipsr[1] |= 1 << (group_n - 32);
- } else {
- s->icipsr[0] |= 1 << group_n;
- }
-
- qemu_irq_raise(s->output_irq[group_n]);
- } else {
-#ifdef DEBUG_COMBINER
- if (group_n != 26) {
- /* skip uart */
- DPRINTF("%s lower IRQ[%d]\n", s->external ? "EXT" : "INT", group_n);
- }
-#endif
-
- /* Set Combiner interrupt pending status after masking */
- if (group_n >= 32) {
- s->icipsr[1] &= ~(1 << (group_n - 32));
- } else {
- s->icipsr[0] &= ~(1 << group_n);
- }
-
- qemu_irq_lower(s->output_irq[group_n]);
- }
-}
-
-static void exynos4210_combiner_write(void *opaque, hwaddr offset,
- uint64_t val, unsigned size)
-{
- struct Exynos4210CombinerState *s =
- (struct Exynos4210CombinerState *)opaque;
- uint32_t req_quad_base_n; /* Base of registers quad. Multiply it by 4 and
- get a start of corresponding group quad */
- uint32_t grp_quad_base_n; /* Base of group quad */
- uint32_t reg_n; /* Register number inside the quad */
-
- req_quad_base_n = offset >> 4;
- grp_quad_base_n = req_quad_base_n << 2;
- reg_n = (offset - (req_quad_base_n << 4)) >> 2;
-
- if (req_quad_base_n >= IIC_NGRP) {
- hw_error("exynos4210.combiner: unallowed write access at offset 0x"
- TARGET_FMT_plx "\n", offset);
- return;
- }
-
- if (reg_n > 1) {
- hw_error("exynos4210.combiner: unallowed write access at offset 0x"
- TARGET_FMT_plx "\n", offset);
- return;
- }
-
- if (offset >> 2 >= IIC_REGSET_SIZE) {
- hw_error("exynos4210.combiner: overflow of reg_set by 0x"
- TARGET_FMT_plx "offset\n", offset);
- }
- s->reg_set[offset >> 2] = val;
-
- switch (reg_n) {
- /* IIESR */
- case 0:
- /* FIXME: what if irq is pending, allowed by mask, and we allow it
- * again. Interrupt will rise again! */
-
- DPRINTF("%s enable IRQ for groups %d, %d, %d, %d\n",
- s->external ? "EXT" : "INT",
- grp_quad_base_n,
- grp_quad_base_n + 1,
- grp_quad_base_n + 2,
- grp_quad_base_n + 3);
-
- /* Enable interrupt sources */
- s->group[grp_quad_base_n].src_mask |= val & 0xFF;
- s->group[grp_quad_base_n + 1].src_mask |= (val & 0xFF00) >> 8;
- s->group[grp_quad_base_n + 2].src_mask |= (val & 0xFF0000) >> 16;
- s->group[grp_quad_base_n + 3].src_mask |= (val & 0xFF000000) >> 24;
-
- exynos4210_combiner_update(s, grp_quad_base_n);
- exynos4210_combiner_update(s, grp_quad_base_n + 1);
- exynos4210_combiner_update(s, grp_quad_base_n + 2);
- exynos4210_combiner_update(s, grp_quad_base_n + 3);
- break;
- /* IIECR */
- case 1:
- DPRINTF("%s disable IRQ for groups %d, %d, %d, %d\n",
- s->external ? "EXT" : "INT",
- grp_quad_base_n,
- grp_quad_base_n + 1,
- grp_quad_base_n + 2,
- grp_quad_base_n + 3);
-
- /* Disable interrupt sources */
- s->group[grp_quad_base_n].src_mask &= ~(val & 0xFF);
- s->group[grp_quad_base_n + 1].src_mask &= ~((val & 0xFF00) >> 8);
- s->group[grp_quad_base_n + 2].src_mask &= ~((val & 0xFF0000) >> 16);
- s->group[grp_quad_base_n + 3].src_mask &= ~((val & 0xFF000000) >> 24);
-
- exynos4210_combiner_update(s, grp_quad_base_n);
- exynos4210_combiner_update(s, grp_quad_base_n + 1);
- exynos4210_combiner_update(s, grp_quad_base_n + 2);
- exynos4210_combiner_update(s, grp_quad_base_n + 3);
- break;
- default:
- hw_error("exynos4210.combiner: unallowed write access at offset 0x"
- TARGET_FMT_plx "\n", offset);
- break;
- }
-}
-
-/* Get combiner group and bit from irq number */
-static uint8_t get_combiner_group_and_bit(int irq, uint8_t *bit)
-{
- *bit = irq - ((irq >> 3) << 3);
- return irq >> 3;
-}
-
-/* Process a change in an external IRQ input. */
-static void exynos4210_combiner_handler(void *opaque, int irq, int level)
-{
- struct Exynos4210CombinerState *s =
- (struct Exynos4210CombinerState *)opaque;
- uint8_t bit_n, group_n;
-
- group_n = get_combiner_group_and_bit(irq, &bit_n);
-
- if (s->external && group_n >= EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ) {
- DPRINTF("%s unallowed IRQ group 0x%x\n", s->external ? "EXT" : "INT"
- , group_n);
- return;
- }
-
- if (level) {
- s->group[group_n].src_pending |= 1 << bit_n;
- } else {
- s->group[group_n].src_pending &= ~(1 << bit_n);
- }
-
- exynos4210_combiner_update(s, group_n);
-}
-
-static void exynos4210_combiner_reset(DeviceState *d)
-{
- struct Exynos4210CombinerState *s = (struct Exynos4210CombinerState *)d;
-
- memset(&s->group, 0, sizeof(s->group));
- memset(&s->reg_set, 0, sizeof(s->reg_set));
-
- s->reg_set[0xC0 >> 2] = 0x01010101;
- s->reg_set[0xC4 >> 2] = 0x01010101;
- s->reg_set[0xD0 >> 2] = 0x01010101;
- s->reg_set[0xD4 >> 2] = 0x01010101;
-}
-
-static const MemoryRegionOps exynos4210_combiner_ops = {
- .read = exynos4210_combiner_read,
- .write = exynos4210_combiner_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-/*
- * Internal Combiner initialization.
- */
-static int exynos4210_combiner_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- Exynos4210CombinerState *s = EXYNOS4210_COMBINER(dev);
- unsigned int i;
-
- /* Allocate general purpose input signals and connect a handler to each of
- * them */
- qdev_init_gpio_in(dev, exynos4210_combiner_handler, IIC_NIRQ);
-
- /* Connect SysBusDev irqs to device specific irqs */
- for (i = 0; i < IIC_NGRP; i++) {
- sysbus_init_irq(sbd, &s->output_irq[i]);
- }
-
- memory_region_init_io(&s->iomem, OBJECT(s), &exynos4210_combiner_ops, s,
- "exynos4210-combiner", IIC_REGION_SIZE);
- sysbus_init_mmio(sbd, &s->iomem);
-
- return 0;
-}
-
-static Property exynos4210_combiner_properties[] = {
- DEFINE_PROP_UINT32("external", Exynos4210CombinerState, external, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void exynos4210_combiner_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = exynos4210_combiner_init;
- dc->reset = exynos4210_combiner_reset;
- dc->props = exynos4210_combiner_properties;
- dc->vmsd = &vmstate_exynos4210_combiner;
-}
-
-static const TypeInfo exynos4210_combiner_info = {
- .name = TYPE_EXYNOS4210_COMBINER,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(Exynos4210CombinerState),
- .class_init = exynos4210_combiner_class_init,
-};
-
-static void exynos4210_combiner_register_types(void)
-{
- type_register_static(&exynos4210_combiner_info);
-}
-
-type_init(exynos4210_combiner_register_types)
diff --git a/qemu/hw/intc/exynos4210_gic.c b/qemu/hw/intc/exynos4210_gic.c
deleted file mode 100644
index 4f7e89f7b..000000000
--- a/qemu/hw/intc/exynos4210_gic.c
+++ /dev/null
@@ -1,472 +0,0 @@
-/*
- * Samsung exynos4210 GIC implementation. Based on hw/arm_gic.c
- *
- * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
- * All rights reserved.
- *
- * Evgeny Voevodin <e.voevodin@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "qemu-common.h"
-#include "hw/irq.h"
-#include "hw/arm/exynos4210.h"
-
-enum ExtGicId {
- EXT_GIC_ID_MDMA_LCD0 = 66,
- EXT_GIC_ID_PDMA0,
- EXT_GIC_ID_PDMA1,
- EXT_GIC_ID_TIMER0,
- EXT_GIC_ID_TIMER1,
- EXT_GIC_ID_TIMER2,
- EXT_GIC_ID_TIMER3,
- EXT_GIC_ID_TIMER4,
- EXT_GIC_ID_MCT_L0,
- EXT_GIC_ID_WDT,
- EXT_GIC_ID_RTC_ALARM,
- EXT_GIC_ID_RTC_TIC,
- EXT_GIC_ID_GPIO_XB,
- EXT_GIC_ID_GPIO_XA,
- EXT_GIC_ID_MCT_L1,
- EXT_GIC_ID_IEM_APC,
- EXT_GIC_ID_IEM_IEC,
- EXT_GIC_ID_NFC,
- EXT_GIC_ID_UART0,
- EXT_GIC_ID_UART1,
- EXT_GIC_ID_UART2,
- EXT_GIC_ID_UART3,
- EXT_GIC_ID_UART4,
- EXT_GIC_ID_MCT_G0,
- EXT_GIC_ID_I2C0,
- EXT_GIC_ID_I2C1,
- EXT_GIC_ID_I2C2,
- EXT_GIC_ID_I2C3,
- EXT_GIC_ID_I2C4,
- EXT_GIC_ID_I2C5,
- EXT_GIC_ID_I2C6,
- EXT_GIC_ID_I2C7,
- EXT_GIC_ID_SPI0,
- EXT_GIC_ID_SPI1,
- EXT_GIC_ID_SPI2,
- EXT_GIC_ID_MCT_G1,
- EXT_GIC_ID_USB_HOST,
- EXT_GIC_ID_USB_DEVICE,
- EXT_GIC_ID_MODEMIF,
- EXT_GIC_ID_HSMMC0,
- EXT_GIC_ID_HSMMC1,
- EXT_GIC_ID_HSMMC2,
- EXT_GIC_ID_HSMMC3,
- EXT_GIC_ID_SDMMC,
- EXT_GIC_ID_MIPI_CSI_4LANE,
- EXT_GIC_ID_MIPI_DSI_4LANE,
- EXT_GIC_ID_MIPI_CSI_2LANE,
- EXT_GIC_ID_MIPI_DSI_2LANE,
- EXT_GIC_ID_ONENAND_AUDI,
- EXT_GIC_ID_ROTATOR,
- EXT_GIC_ID_FIMC0,
- EXT_GIC_ID_FIMC1,
- EXT_GIC_ID_FIMC2,
- EXT_GIC_ID_FIMC3,
- EXT_GIC_ID_JPEG,
- EXT_GIC_ID_2D,
- EXT_GIC_ID_PCIe,
- EXT_GIC_ID_MIXER,
- EXT_GIC_ID_HDMI,
- EXT_GIC_ID_HDMI_I2C,
- EXT_GIC_ID_MFC,
- EXT_GIC_ID_TVENC,
-};
-
-enum ExtInt {
- EXT_GIC_ID_EXTINT0 = 48,
- EXT_GIC_ID_EXTINT1,
- EXT_GIC_ID_EXTINT2,
- EXT_GIC_ID_EXTINT3,
- EXT_GIC_ID_EXTINT4,
- EXT_GIC_ID_EXTINT5,
- EXT_GIC_ID_EXTINT6,
- EXT_GIC_ID_EXTINT7,
- EXT_GIC_ID_EXTINT8,
- EXT_GIC_ID_EXTINT9,
- EXT_GIC_ID_EXTINT10,
- EXT_GIC_ID_EXTINT11,
- EXT_GIC_ID_EXTINT12,
- EXT_GIC_ID_EXTINT13,
- EXT_GIC_ID_EXTINT14,
- EXT_GIC_ID_EXTINT15
-};
-
-/*
- * External GIC sources which are not from External Interrupt Combiner or
- * External Interrupts are starting from EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ,
- * which is INTG16 in Internal Interrupt Combiner.
- */
-
-static uint32_t
-combiner_grp_to_gic_id[64-EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ][8] = {
- /* int combiner groups 16-19 */
- { }, { }, { }, { },
- /* int combiner group 20 */
- { 0, EXT_GIC_ID_MDMA_LCD0 },
- /* int combiner group 21 */
- { EXT_GIC_ID_PDMA0, EXT_GIC_ID_PDMA1 },
- /* int combiner group 22 */
- { EXT_GIC_ID_TIMER0, EXT_GIC_ID_TIMER1, EXT_GIC_ID_TIMER2,
- EXT_GIC_ID_TIMER3, EXT_GIC_ID_TIMER4 },
- /* int combiner group 23 */
- { EXT_GIC_ID_RTC_ALARM, EXT_GIC_ID_RTC_TIC },
- /* int combiner group 24 */
- { EXT_GIC_ID_GPIO_XB, EXT_GIC_ID_GPIO_XA },
- /* int combiner group 25 */
- { EXT_GIC_ID_IEM_APC, EXT_GIC_ID_IEM_IEC },
- /* int combiner group 26 */
- { EXT_GIC_ID_UART0, EXT_GIC_ID_UART1, EXT_GIC_ID_UART2, EXT_GIC_ID_UART3,
- EXT_GIC_ID_UART4 },
- /* int combiner group 27 */
- { EXT_GIC_ID_I2C0, EXT_GIC_ID_I2C1, EXT_GIC_ID_I2C2, EXT_GIC_ID_I2C3,
- EXT_GIC_ID_I2C4, EXT_GIC_ID_I2C5, EXT_GIC_ID_I2C6,
- EXT_GIC_ID_I2C7 },
- /* int combiner group 28 */
- { EXT_GIC_ID_SPI0, EXT_GIC_ID_SPI1, EXT_GIC_ID_SPI2 , EXT_GIC_ID_USB_HOST},
- /* int combiner group 29 */
- { EXT_GIC_ID_HSMMC0, EXT_GIC_ID_HSMMC1, EXT_GIC_ID_HSMMC2,
- EXT_GIC_ID_HSMMC3, EXT_GIC_ID_SDMMC },
- /* int combiner group 30 */
- { EXT_GIC_ID_MIPI_CSI_4LANE, EXT_GIC_ID_MIPI_CSI_2LANE },
- /* int combiner group 31 */
- { EXT_GIC_ID_MIPI_DSI_4LANE, EXT_GIC_ID_MIPI_DSI_2LANE },
- /* int combiner group 32 */
- { EXT_GIC_ID_FIMC0, EXT_GIC_ID_FIMC1 },
- /* int combiner group 33 */
- { EXT_GIC_ID_FIMC2, EXT_GIC_ID_FIMC3 },
- /* int combiner group 34 */
- { EXT_GIC_ID_ONENAND_AUDI, EXT_GIC_ID_NFC },
- /* int combiner group 35 */
- { 0, 0, 0, EXT_GIC_ID_MCT_L1, EXT_GIC_ID_MCT_G0, EXT_GIC_ID_MCT_G1 },
- /* int combiner group 36 */
- { EXT_GIC_ID_MIXER },
- /* int combiner group 37 */
- { EXT_GIC_ID_EXTINT4, EXT_GIC_ID_EXTINT5, EXT_GIC_ID_EXTINT6,
- EXT_GIC_ID_EXTINT7 },
- /* groups 38-50 */
- { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { },
- /* int combiner group 51 */
- { EXT_GIC_ID_MCT_L0, 0, 0, 0, EXT_GIC_ID_MCT_G0, EXT_GIC_ID_MCT_G1 },
- /* group 52 */
- { },
- /* int combiner group 53 */
- { EXT_GIC_ID_WDT, 0, 0, 0, EXT_GIC_ID_MCT_G0, EXT_GIC_ID_MCT_G1 },
- /* groups 54-63 */
- { }, { }, { }, { }, { }, { }, { }, { }, { }, { }
-};
-
-#define EXYNOS4210_GIC_NIRQ 160
-
-#define EXYNOS4210_EXT_GIC_CPU_REGION_SIZE 0x10000
-#define EXYNOS4210_EXT_GIC_DIST_REGION_SIZE 0x10000
-
-#define EXYNOS4210_EXT_GIC_PER_CPU_OFFSET 0x8000
-#define EXYNOS4210_EXT_GIC_CPU_GET_OFFSET(n) \
- ((n) * EXYNOS4210_EXT_GIC_PER_CPU_OFFSET)
-#define EXYNOS4210_EXT_GIC_DIST_GET_OFFSET(n) \
- ((n) * EXYNOS4210_EXT_GIC_PER_CPU_OFFSET)
-
-#define EXYNOS4210_GIC_CPU_REGION_SIZE 0x100
-#define EXYNOS4210_GIC_DIST_REGION_SIZE 0x1000
-
-static void exynos4210_irq_handler(void *opaque, int irq, int level)
-{
- Exynos4210Irq *s = (Exynos4210Irq *)opaque;
-
- /* Bypass */
- qemu_set_irq(s->board_irqs[irq], level);
-}
-
-/*
- * Initialize exynos4210 IRQ subsystem stub.
- */
-qemu_irq *exynos4210_init_irq(Exynos4210Irq *s)
-{
- return qemu_allocate_irqs(exynos4210_irq_handler, s,
- EXYNOS4210_MAX_INT_COMBINER_IN_IRQ);
-}
-
-/*
- * Initialize board IRQs.
- * These IRQs contain splitted Int/External Combiner and External Gic IRQs.
- */
-void exynos4210_init_board_irqs(Exynos4210Irq *s)
-{
- uint32_t grp, bit, irq_id, n;
-
- for (n = 0; n < EXYNOS4210_MAX_EXT_COMBINER_IN_IRQ; n++) {
- irq_id = 0;
- if (n == EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 4) ||
- n == EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 4)) {
- /* MCT_G0 is passed to External GIC */
- irq_id = EXT_GIC_ID_MCT_G0;
- }
- if (n == EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 5) ||
- n == EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 5)) {
- /* MCT_G1 is passed to External and GIC */
- irq_id = EXT_GIC_ID_MCT_G1;
- }
- if (irq_id) {
- s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n],
- s->ext_gic_irq[irq_id-32]);
- } else {
- s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n],
- s->ext_combiner_irq[n]);
- }
- }
- for (; n < EXYNOS4210_MAX_INT_COMBINER_IN_IRQ; n++) {
- /* these IDs are passed to Internal Combiner and External GIC */
- grp = EXYNOS4210_COMBINER_GET_GRP_NUM(n);
- bit = EXYNOS4210_COMBINER_GET_BIT_NUM(n);
- irq_id = combiner_grp_to_gic_id[grp -
- EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ][bit];
-
- if (irq_id) {
- s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n],
- s->ext_gic_irq[irq_id-32]);
- }
- }
-}
-
-/*
- * Get IRQ number from exynos4210 IRQ subsystem stub.
- * To identify IRQ source use internal combiner group and bit number
- * grp - group number
- * bit - bit number inside group
- */
-uint32_t exynos4210_get_irq(uint32_t grp, uint32_t bit)
-{
- return EXYNOS4210_COMBINER_GET_IRQ_NUM(grp, bit);
-}
-
-/********* GIC part *********/
-
-#define TYPE_EXYNOS4210_GIC "exynos4210.gic"
-#define EXYNOS4210_GIC(obj) \
- OBJECT_CHECK(Exynos4210GicState, (obj), TYPE_EXYNOS4210_GIC)
-
-typedef struct {
- SysBusDevice parent_obj;
-
- MemoryRegion cpu_container;
- MemoryRegion dist_container;
- MemoryRegion cpu_alias[EXYNOS4210_NCPUS];
- MemoryRegion dist_alias[EXYNOS4210_NCPUS];
- uint32_t num_cpu;
- DeviceState *gic;
-} Exynos4210GicState;
-
-static void exynos4210_gic_set_irq(void *opaque, int irq, int level)
-{
- Exynos4210GicState *s = (Exynos4210GicState *)opaque;
- qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level);
-}
-
-static int exynos4210_gic_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- Exynos4210GicState *s = EXYNOS4210_GIC(dev);
- uint32_t i;
- const char cpu_prefix[] = "exynos4210-gic-alias_cpu";
- const char dist_prefix[] = "exynos4210-gic-alias_dist";
- char cpu_alias_name[sizeof(cpu_prefix) + 3];
- char dist_alias_name[sizeof(cpu_prefix) + 3];
- SysBusDevice *busdev;
-
- s->gic = qdev_create(NULL, "arm_gic");
- qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu);
- qdev_prop_set_uint32(s->gic, "num-irq", EXYNOS4210_GIC_NIRQ);
- qdev_init_nofail(s->gic);
- busdev = SYS_BUS_DEVICE(s->gic);
-
- /* Pass through outbound IRQ lines from the GIC */
- sysbus_pass_irq(sbd, busdev);
-
- /* Pass through inbound GPIO lines to the GIC */
- qdev_init_gpio_in(dev, exynos4210_gic_set_irq,
- EXYNOS4210_GIC_NIRQ - 32);
-
- memory_region_init(&s->cpu_container, OBJECT(s), "exynos4210-cpu-container",
- EXYNOS4210_EXT_GIC_CPU_REGION_SIZE);
- memory_region_init(&s->dist_container, OBJECT(s), "exynos4210-dist-container",
- EXYNOS4210_EXT_GIC_DIST_REGION_SIZE);
-
- for (i = 0; i < s->num_cpu; i++) {
- /* Map CPU interface per SMP Core */
- sprintf(cpu_alias_name, "%s%x", cpu_prefix, i);
- memory_region_init_alias(&s->cpu_alias[i], OBJECT(s),
- cpu_alias_name,
- sysbus_mmio_get_region(busdev, 1),
- 0,
- EXYNOS4210_GIC_CPU_REGION_SIZE);
- memory_region_add_subregion(&s->cpu_container,
- EXYNOS4210_EXT_GIC_CPU_GET_OFFSET(i), &s->cpu_alias[i]);
-
- /* Map Distributor per SMP Core */
- sprintf(dist_alias_name, "%s%x", dist_prefix, i);
- memory_region_init_alias(&s->dist_alias[i], OBJECT(s),
- dist_alias_name,
- sysbus_mmio_get_region(busdev, 0),
- 0,
- EXYNOS4210_GIC_DIST_REGION_SIZE);
- memory_region_add_subregion(&s->dist_container,
- EXYNOS4210_EXT_GIC_DIST_GET_OFFSET(i), &s->dist_alias[i]);
- }
-
- sysbus_init_mmio(sbd, &s->cpu_container);
- sysbus_init_mmio(sbd, &s->dist_container);
-
- return 0;
-}
-
-static Property exynos4210_gic_properties[] = {
- DEFINE_PROP_UINT32("num-cpu", Exynos4210GicState, num_cpu, 1),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void exynos4210_gic_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = exynos4210_gic_init;
- dc->props = exynos4210_gic_properties;
-}
-
-static const TypeInfo exynos4210_gic_info = {
- .name = TYPE_EXYNOS4210_GIC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(Exynos4210GicState),
- .class_init = exynos4210_gic_class_init,
-};
-
-static void exynos4210_gic_register_types(void)
-{
- type_register_static(&exynos4210_gic_info);
-}
-
-type_init(exynos4210_gic_register_types)
-
-/* IRQ OR Gate struct.
- *
- * This device models an OR gate. There are n_in input qdev gpio lines and one
- * output sysbus IRQ line. The output IRQ level is formed as OR between all
- * gpio inputs.
- */
-
-#define TYPE_EXYNOS4210_IRQ_GATE "exynos4210.irq_gate"
-#define EXYNOS4210_IRQ_GATE(obj) \
- OBJECT_CHECK(Exynos4210IRQGateState, (obj), TYPE_EXYNOS4210_IRQ_GATE)
-
-typedef struct Exynos4210IRQGateState {
- SysBusDevice parent_obj;
-
- uint32_t n_in; /* inputs amount */
- uint32_t *level; /* input levels */
- qemu_irq out; /* output IRQ */
-} Exynos4210IRQGateState;
-
-static Property exynos4210_irq_gate_properties[] = {
- DEFINE_PROP_UINT32("n_in", Exynos4210IRQGateState, n_in, 1),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static const VMStateDescription vmstate_exynos4210_irq_gate = {
- .name = "exynos4210.irq_gate",
- .version_id = 2,
- .minimum_version_id = 2,
- .fields = (VMStateField[]) {
- VMSTATE_VBUFFER_UINT32(level, Exynos4210IRQGateState, 1, NULL, 0, n_in),
- VMSTATE_END_OF_LIST()
- }
-};
-
-/* Process a change in IRQ input. */
-static void exynos4210_irq_gate_handler(void *opaque, int irq, int level)
-{
- Exynos4210IRQGateState *s = (Exynos4210IRQGateState *)opaque;
- uint32_t i;
-
- assert(irq < s->n_in);
-
- s->level[irq] = level;
-
- for (i = 0; i < s->n_in; i++) {
- if (s->level[i] >= 1) {
- qemu_irq_raise(s->out);
- return;
- }
- }
-
- qemu_irq_lower(s->out);
-}
-
-static void exynos4210_irq_gate_reset(DeviceState *d)
-{
- Exynos4210IRQGateState *s = EXYNOS4210_IRQ_GATE(d);
-
- memset(s->level, 0, s->n_in * sizeof(*s->level));
-}
-
-/*
- * IRQ Gate initialization.
- */
-static int exynos4210_irq_gate_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- Exynos4210IRQGateState *s = EXYNOS4210_IRQ_GATE(dev);
-
- /* Allocate general purpose input signals and connect a handler to each of
- * them */
- qdev_init_gpio_in(dev, exynos4210_irq_gate_handler, s->n_in);
-
- s->level = g_malloc0(s->n_in * sizeof(*s->level));
-
- sysbus_init_irq(sbd, &s->out);
-
- return 0;
-}
-
-static void exynos4210_irq_gate_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = exynos4210_irq_gate_init;
- dc->reset = exynos4210_irq_gate_reset;
- dc->vmsd = &vmstate_exynos4210_irq_gate;
- dc->props = exynos4210_irq_gate_properties;
-}
-
-static const TypeInfo exynos4210_irq_gate_info = {
- .name = TYPE_EXYNOS4210_IRQ_GATE,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(Exynos4210IRQGateState),
- .class_init = exynos4210_irq_gate_class_init,
-};
-
-static void exynos4210_irq_gate_register_types(void)
-{
- type_register_static(&exynos4210_irq_gate_info);
-}
-
-type_init(exynos4210_irq_gate_register_types)
diff --git a/qemu/hw/intc/gic_internal.h b/qemu/hw/intc/gic_internal.h
deleted file mode 100644
index 20c1e8a24..000000000
--- a/qemu/hw/intc/gic_internal.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * ARM GIC support - internal interfaces
- *
- * Copyright (c) 2012 Linaro Limited
- * Written by Peter Maydell
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef QEMU_ARM_GIC_INTERNAL_H
-#define QEMU_ARM_GIC_INTERNAL_H
-
-#include "hw/intc/arm_gic.h"
-
-#define ALL_CPU_MASK ((unsigned)(((1 << GIC_NCPU) - 1)))
-
-/* The NVIC has 16 internal vectors. However these are not exposed
- through the normal GIC interface. */
-#define GIC_BASE_IRQ ((s->revision == REV_NVIC) ? 32 : 0)
-
-#define GIC_SET_ENABLED(irq, cm) s->irq_state[irq].enabled |= (cm)
-#define GIC_CLEAR_ENABLED(irq, cm) s->irq_state[irq].enabled &= ~(cm)
-#define GIC_TEST_ENABLED(irq, cm) ((s->irq_state[irq].enabled & (cm)) != 0)
-#define GIC_SET_PENDING(irq, cm) s->irq_state[irq].pending |= (cm)
-#define GIC_CLEAR_PENDING(irq, cm) s->irq_state[irq].pending &= ~(cm)
-#define GIC_SET_ACTIVE(irq, cm) s->irq_state[irq].active |= (cm)
-#define GIC_CLEAR_ACTIVE(irq, cm) s->irq_state[irq].active &= ~(cm)
-#define GIC_TEST_ACTIVE(irq, cm) ((s->irq_state[irq].active & (cm)) != 0)
-#define GIC_SET_MODEL(irq) s->irq_state[irq].model = true
-#define GIC_CLEAR_MODEL(irq) s->irq_state[irq].model = false
-#define GIC_TEST_MODEL(irq) s->irq_state[irq].model
-#define GIC_SET_LEVEL(irq, cm) s->irq_state[irq].level |= (cm)
-#define GIC_CLEAR_LEVEL(irq, cm) s->irq_state[irq].level &= ~(cm)
-#define GIC_TEST_LEVEL(irq, cm) ((s->irq_state[irq].level & (cm)) != 0)
-#define GIC_SET_EDGE_TRIGGER(irq) s->irq_state[irq].edge_trigger = true
-#define GIC_CLEAR_EDGE_TRIGGER(irq) s->irq_state[irq].edge_trigger = false
-#define GIC_TEST_EDGE_TRIGGER(irq) (s->irq_state[irq].edge_trigger)
-#define GIC_GET_PRIORITY(irq, cpu) (((irq) < GIC_INTERNAL) ? \
- s->priority1[irq][cpu] : \
- s->priority2[(irq) - GIC_INTERNAL])
-#define GIC_TARGET(irq) s->irq_target[irq]
-#define GIC_CLEAR_GROUP(irq, cm) (s->irq_state[irq].group &= ~(cm))
-#define GIC_SET_GROUP(irq, cm) (s->irq_state[irq].group |= (cm))
-#define GIC_TEST_GROUP(irq, cm) ((s->irq_state[irq].group & (cm)) != 0)
-
-#define GICD_CTLR_EN_GRP0 (1U << 0)
-#define GICD_CTLR_EN_GRP1 (1U << 1)
-
-#define GICC_CTLR_EN_GRP0 (1U << 0)
-#define GICC_CTLR_EN_GRP1 (1U << 1)
-#define GICC_CTLR_ACK_CTL (1U << 2)
-#define GICC_CTLR_FIQ_EN (1U << 3)
-#define GICC_CTLR_CBPR (1U << 4) /* GICv1: SBPR */
-#define GICC_CTLR_EOIMODE (1U << 9)
-#define GICC_CTLR_EOIMODE_NS (1U << 10)
-
-/* Valid bits for GICC_CTLR for GICv1, v1 with security extensions,
- * GICv2 and GICv2 with security extensions:
- */
-#define GICC_CTLR_V1_MASK 0x1
-#define GICC_CTLR_V1_S_MASK 0x1f
-#define GICC_CTLR_V2_MASK 0x21f
-#define GICC_CTLR_V2_S_MASK 0x61f
-
-/* The special cases for the revision property: */
-#define REV_11MPCORE 0
-#define REV_NVIC 0xffffffff
-
-void gic_set_pending_private(GICState *s, int cpu, int irq);
-uint32_t gic_acknowledge_irq(GICState *s, int cpu, MemTxAttrs attrs);
-void gic_complete_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs);
-void gic_update(GICState *s);
-void gic_init_irqs_and_distributor(GICState *s);
-void gic_set_priority(GICState *s, int cpu, int irq, uint8_t val,
- MemTxAttrs attrs);
-
-static inline bool gic_test_pending(GICState *s, int irq, int cm)
-{
- if (s->revision == REV_NVIC || s->revision == REV_11MPCORE) {
- return s->irq_state[irq].pending & cm;
- } else {
- /* Edge-triggered interrupts are marked pending on a rising edge, but
- * level-triggered interrupts are either considered pending when the
- * level is active or if software has explicitly written to
- * GICD_ISPENDR to set the state pending.
- */
- return (s->irq_state[irq].pending & cm) ||
- (!GIC_TEST_EDGE_TRIGGER(irq) && GIC_TEST_LEVEL(irq, cm));
- }
-}
-
-#endif /* !QEMU_ARM_GIC_INTERNAL_H */
diff --git a/qemu/hw/intc/grlib_irqmp.c b/qemu/hw/intc/grlib_irqmp.c
deleted file mode 100644
index f5ca8f752..000000000
--- a/qemu/hw/intc/grlib_irqmp.c
+++ /dev/null
@@ -1,375 +0,0 @@
-/*
- * QEMU GRLIB IRQMP Emulator
- *
- * (Multiprocessor and extended interrupt not supported)
- *
- * Copyright (c) 2010-2011 AdaCore
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "cpu.h"
-
-#include "hw/sparc/grlib.h"
-
-#include "trace.h"
-
-#define IRQMP_MAX_CPU 16
-#define IRQMP_REG_SIZE 256 /* Size of memory mapped registers */
-
-/* Memory mapped register offsets */
-#define LEVEL_OFFSET 0x00
-#define PENDING_OFFSET 0x04
-#define FORCE0_OFFSET 0x08
-#define CLEAR_OFFSET 0x0C
-#define MP_STATUS_OFFSET 0x10
-#define BROADCAST_OFFSET 0x14
-#define MASK_OFFSET 0x40
-#define FORCE_OFFSET 0x80
-#define EXTENDED_OFFSET 0xC0
-
-#define TYPE_GRLIB_IRQMP "grlib,irqmp"
-#define GRLIB_IRQMP(obj) OBJECT_CHECK(IRQMP, (obj), TYPE_GRLIB_IRQMP)
-
-typedef struct IRQMPState IRQMPState;
-
-typedef struct IRQMP {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
-
- void *set_pil_in;
- void *set_pil_in_opaque;
-
- IRQMPState *state;
-} IRQMP;
-
-struct IRQMPState {
- uint32_t level;
- uint32_t pending;
- uint32_t clear;
- uint32_t broadcast;
-
- uint32_t mask[IRQMP_MAX_CPU];
- uint32_t force[IRQMP_MAX_CPU];
- uint32_t extended[IRQMP_MAX_CPU];
-
- IRQMP *parent;
-};
-
-static void grlib_irqmp_check_irqs(IRQMPState *state)
-{
- uint32_t pend = 0;
- uint32_t level0 = 0;
- uint32_t level1 = 0;
- set_pil_in_fn set_pil_in;
-
- assert(state != NULL);
- assert(state->parent != NULL);
-
- /* IRQ for CPU 0 (no SMP support) */
- pend = (state->pending | state->force[0])
- & state->mask[0];
-
- level0 = pend & ~state->level;
- level1 = pend & state->level;
-
- trace_grlib_irqmp_check_irqs(state->pending, state->force[0],
- state->mask[0], level1, level0);
-
- set_pil_in = (set_pil_in_fn)state->parent->set_pil_in;
-
- /* Trigger level1 interrupt first and level0 if there is no level1 */
- if (level1 != 0) {
- set_pil_in(state->parent->set_pil_in_opaque, level1);
- } else {
- set_pil_in(state->parent->set_pil_in_opaque, level0);
- }
-}
-
-void grlib_irqmp_ack(DeviceState *dev, int intno)
-{
- IRQMP *irqmp = GRLIB_IRQMP(dev);
- IRQMPState *state;
- uint32_t mask;
-
- state = irqmp->state;
- assert(state != NULL);
-
- intno &= 15;
- mask = 1 << intno;
-
- trace_grlib_irqmp_ack(intno);
-
- /* Clear registers */
- state->pending &= ~mask;
- state->force[0] &= ~mask; /* Only CPU 0 (No SMP support) */
-
- grlib_irqmp_check_irqs(state);
-}
-
-void grlib_irqmp_set_irq(void *opaque, int irq, int level)
-{
- IRQMP *irqmp = GRLIB_IRQMP(opaque);
- IRQMPState *s;
- int i = 0;
-
- s = irqmp->state;
- assert(s != NULL);
- assert(s->parent != NULL);
-
-
- if (level) {
- trace_grlib_irqmp_set_irq(irq);
-
- if (s->broadcast & 1 << irq) {
- /* Broadcasted IRQ */
- for (i = 0; i < IRQMP_MAX_CPU; i++) {
- s->force[i] |= 1 << irq;
- }
- } else {
- s->pending |= 1 << irq;
- }
- grlib_irqmp_check_irqs(s);
-
- }
-}
-
-static uint64_t grlib_irqmp_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- IRQMP *irqmp = opaque;
- IRQMPState *state;
-
- assert(irqmp != NULL);
- state = irqmp->state;
- assert(state != NULL);
-
- addr &= 0xff;
-
- /* global registers */
- switch (addr) {
- case LEVEL_OFFSET:
- return state->level;
-
- case PENDING_OFFSET:
- return state->pending;
-
- case FORCE0_OFFSET:
- /* This register is an "alias" for the force register of CPU 0 */
- return state->force[0];
-
- case CLEAR_OFFSET:
- case MP_STATUS_OFFSET:
- /* Always read as 0 */
- return 0;
-
- case BROADCAST_OFFSET:
- return state->broadcast;
-
- default:
- break;
- }
-
- /* mask registers */
- if (addr >= MASK_OFFSET && addr < FORCE_OFFSET) {
- int cpu = (addr - MASK_OFFSET) / 4;
- assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
-
- return state->mask[cpu];
- }
-
- /* force registers */
- if (addr >= FORCE_OFFSET && addr < EXTENDED_OFFSET) {
- int cpu = (addr - FORCE_OFFSET) / 4;
- assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
-
- return state->force[cpu];
- }
-
- /* extended (not supported) */
- if (addr >= EXTENDED_OFFSET && addr < IRQMP_REG_SIZE) {
- int cpu = (addr - EXTENDED_OFFSET) / 4;
- assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
-
- return state->extended[cpu];
- }
-
- trace_grlib_irqmp_readl_unknown(addr);
- return 0;
-}
-
-static void grlib_irqmp_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- IRQMP *irqmp = opaque;
- IRQMPState *state;
-
- assert(irqmp != NULL);
- state = irqmp->state;
- assert(state != NULL);
-
- addr &= 0xff;
-
- /* global registers */
- switch (addr) {
- case LEVEL_OFFSET:
- value &= 0xFFFF << 1; /* clean up the value */
- state->level = value;
- return;
-
- case PENDING_OFFSET:
- /* Read Only */
- return;
-
- case FORCE0_OFFSET:
- /* This register is an "alias" for the force register of CPU 0 */
-
- value &= 0xFFFE; /* clean up the value */
- state->force[0] = value;
- grlib_irqmp_check_irqs(irqmp->state);
- return;
-
- case CLEAR_OFFSET:
- value &= ~1; /* clean up the value */
- state->pending &= ~value;
- return;
-
- case MP_STATUS_OFFSET:
- /* Read Only (no SMP support) */
- return;
-
- case BROADCAST_OFFSET:
- value &= 0xFFFE; /* clean up the value */
- state->broadcast = value;
- return;
-
- default:
- break;
- }
-
- /* mask registers */
- if (addr >= MASK_OFFSET && addr < FORCE_OFFSET) {
- int cpu = (addr - MASK_OFFSET) / 4;
- assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
-
- value &= ~1; /* clean up the value */
- state->mask[cpu] = value;
- grlib_irqmp_check_irqs(irqmp->state);
- return;
- }
-
- /* force registers */
- if (addr >= FORCE_OFFSET && addr < EXTENDED_OFFSET) {
- int cpu = (addr - FORCE_OFFSET) / 4;
- assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
-
- uint32_t force = value & 0xFFFE;
- uint32_t clear = (value >> 16) & 0xFFFE;
- uint32_t old = state->force[cpu];
-
- state->force[cpu] = (old | force) & ~clear;
- grlib_irqmp_check_irqs(irqmp->state);
- return;
- }
-
- /* extended (not supported) */
- if (addr >= EXTENDED_OFFSET && addr < IRQMP_REG_SIZE) {
- int cpu = (addr - EXTENDED_OFFSET) / 4;
- assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
-
- value &= 0xF; /* clean up the value */
- state->extended[cpu] = value;
- return;
- }
-
- trace_grlib_irqmp_writel_unknown(addr, value);
-}
-
-static const MemoryRegionOps grlib_irqmp_ops = {
- .read = grlib_irqmp_read,
- .write = grlib_irqmp_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static void grlib_irqmp_reset(DeviceState *d)
-{
- IRQMP *irqmp = GRLIB_IRQMP(d);
- assert(irqmp->state != NULL);
-
- memset(irqmp->state, 0, sizeof *irqmp->state);
- irqmp->state->parent = irqmp;
-}
-
-static int grlib_irqmp_init(SysBusDevice *dev)
-{
- IRQMP *irqmp = GRLIB_IRQMP(dev);
-
- /* Check parameters */
- if (irqmp->set_pil_in == NULL) {
- return -1;
- }
-
- memory_region_init_io(&irqmp->iomem, OBJECT(dev), &grlib_irqmp_ops, irqmp,
- "irqmp", IRQMP_REG_SIZE);
-
- irqmp->state = g_malloc0(sizeof *irqmp->state);
-
- sysbus_init_mmio(dev, &irqmp->iomem);
-
- return 0;
-}
-
-static Property grlib_irqmp_properties[] = {
- DEFINE_PROP_PTR("set_pil_in", IRQMP, set_pil_in),
- DEFINE_PROP_PTR("set_pil_in_opaque", IRQMP, set_pil_in_opaque),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void grlib_irqmp_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = grlib_irqmp_init;
- dc->reset = grlib_irqmp_reset;
- dc->props = grlib_irqmp_properties;
- /* Reason: pointer properties "set_pil_in", "set_pil_in_opaque" */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo grlib_irqmp_info = {
- .name = TYPE_GRLIB_IRQMP,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(IRQMP),
- .class_init = grlib_irqmp_class_init,
-};
-
-static void grlib_irqmp_register_types(void)
-{
- type_register_static(&grlib_irqmp_info);
-}
-
-type_init(grlib_irqmp_register_types)
diff --git a/qemu/hw/intc/heathrow_pic.c b/qemu/hw/intc/heathrow_pic.c
deleted file mode 100644
index 171f5ed81..000000000
--- a/qemu/hw/intc/heathrow_pic.c
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * Heathrow PIC support (OldWorld PowerMac)
- *
- * Copyright (c) 2005-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.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/ppc/mac.h"
-
-/* debug PIC */
-//#define DEBUG_PIC
-
-#ifdef DEBUG_PIC
-#define PIC_DPRINTF(fmt, ...) \
- do { printf("PIC: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define PIC_DPRINTF(fmt, ...)
-#endif
-
-typedef struct HeathrowPIC {
- uint32_t events;
- uint32_t mask;
- uint32_t levels;
- uint32_t level_triggered;
-} HeathrowPIC;
-
-typedef struct HeathrowPICS {
- MemoryRegion mem;
- HeathrowPIC pics[2];
- qemu_irq *irqs;
-} HeathrowPICS;
-
-static inline int check_irq(HeathrowPIC *pic)
-{
- return (pic->events | (pic->levels & pic->level_triggered)) & pic->mask;
-}
-
-/* update the CPU irq state */
-static void heathrow_pic_update(HeathrowPICS *s)
-{
- if (check_irq(&s->pics[0]) || check_irq(&s->pics[1])) {
- qemu_irq_raise(s->irqs[0]);
- } else {
- qemu_irq_lower(s->irqs[0]);
- }
-}
-
-static void pic_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- HeathrowPICS *s = opaque;
- HeathrowPIC *pic;
- unsigned int n;
-
- n = ((addr & 0xfff) - 0x10) >> 4;
- PIC_DPRINTF("writel: " TARGET_FMT_plx " %u: %08x\n", addr, n, value);
- if (n >= 2)
- return;
- pic = &s->pics[n];
- switch(addr & 0xf) {
- case 0x04:
- pic->mask = value;
- heathrow_pic_update(s);
- break;
- case 0x08:
- /* do not reset level triggered IRQs */
- value &= ~pic->level_triggered;
- pic->events &= ~value;
- heathrow_pic_update(s);
- break;
- default:
- break;
- }
-}
-
-static uint64_t pic_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- HeathrowPICS *s = opaque;
- HeathrowPIC *pic;
- unsigned int n;
- uint32_t value;
-
- n = ((addr & 0xfff) - 0x10) >> 4;
- if (n >= 2) {
- value = 0;
- } else {
- pic = &s->pics[n];
- switch(addr & 0xf) {
- case 0x0:
- value = pic->events;
- break;
- case 0x4:
- value = pic->mask;
- break;
- case 0xc:
- value = pic->levels;
- break;
- default:
- value = 0;
- break;
- }
- }
- PIC_DPRINTF("readl: " TARGET_FMT_plx " %u: %08x\n", addr, n, value);
- return value;
-}
-
-static const MemoryRegionOps heathrow_pic_ops = {
- .read = pic_read,
- .write = pic_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void heathrow_pic_set_irq(void *opaque, int num, int level)
-{
- HeathrowPICS *s = opaque;
- HeathrowPIC *pic;
- unsigned int irq_bit;
-
-#if defined(DEBUG)
- {
- static int last_level[64];
- if (last_level[num] != level) {
- PIC_DPRINTF("set_irq: num=0x%02x level=%d\n", num, level);
- last_level[num] = level;
- }
- }
-#endif
- pic = &s->pics[1 - (num >> 5)];
- irq_bit = 1 << (num & 0x1f);
- if (level) {
- pic->events |= irq_bit & ~pic->level_triggered;
- pic->levels |= irq_bit;
- } else {
- pic->levels &= ~irq_bit;
- }
- heathrow_pic_update(s);
-}
-
-static const VMStateDescription vmstate_heathrow_pic_one = {
- .name = "heathrow_pic_one",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(events, HeathrowPIC),
- VMSTATE_UINT32(mask, HeathrowPIC),
- VMSTATE_UINT32(levels, HeathrowPIC),
- VMSTATE_UINT32(level_triggered, HeathrowPIC),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_heathrow_pic = {
- .name = "heathrow_pic",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT_ARRAY(pics, HeathrowPICS, 2, 1,
- vmstate_heathrow_pic_one, HeathrowPIC),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void heathrow_pic_reset_one(HeathrowPIC *s)
-{
- memset(s, '\0', sizeof(HeathrowPIC));
-}
-
-static void heathrow_pic_reset(void *opaque)
-{
- HeathrowPICS *s = opaque;
-
- heathrow_pic_reset_one(&s->pics[0]);
- heathrow_pic_reset_one(&s->pics[1]);
-
- s->pics[0].level_triggered = 0;
- s->pics[1].level_triggered = 0x1ff00000;
-}
-
-qemu_irq *heathrow_pic_init(MemoryRegion **pmem,
- int nb_cpus, qemu_irq **irqs)
-{
- HeathrowPICS *s;
-
- s = g_malloc0(sizeof(HeathrowPICS));
- /* only 1 CPU */
- s->irqs = irqs[0];
- memory_region_init_io(&s->mem, NULL, &heathrow_pic_ops, s,
- "heathrow-pic", 0x1000);
- *pmem = &s->mem;
-
- vmstate_register(NULL, -1, &vmstate_heathrow_pic, s);
- qemu_register_reset(heathrow_pic_reset, s);
- return qemu_allocate_irqs(heathrow_pic_set_irq, s, 64);
-}
diff --git a/qemu/hw/intc/i8259.c b/qemu/hw/intc/i8259.c
deleted file mode 100644
index bb43669b9..000000000
--- a/qemu/hw/intc/i8259.c
+++ /dev/null
@@ -1,524 +0,0 @@
-/*
- * QEMU 8259 interrupt controller emulation
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/i386/pc.h"
-#include "hw/isa/isa.h"
-#include "monitor/monitor.h"
-#include "qemu/timer.h"
-#include "hw/isa/i8259_internal.h"
-
-/* debug PIC */
-//#define DEBUG_PIC
-
-#ifdef DEBUG_PIC
-#define DPRINTF(fmt, ...) \
- do { printf("pic: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...)
-#endif
-
-//#define DEBUG_IRQ_LATENCY
-//#define DEBUG_IRQ_COUNT
-
-#define TYPE_I8259 "isa-i8259"
-#define PIC_CLASS(class) OBJECT_CLASS_CHECK(PICClass, (class), TYPE_I8259)
-#define PIC_GET_CLASS(obj) OBJECT_GET_CLASS(PICClass, (obj), TYPE_I8259)
-
-/**
- * PICClass:
- * @parent_realize: The parent's realizefn.
- */
-typedef struct PICClass {
- PICCommonClass parent_class;
-
- DeviceRealize parent_realize;
-} PICClass;
-
-#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
-static int irq_level[16];
-#endif
-#ifdef DEBUG_IRQ_COUNT
-static uint64_t irq_count[16];
-#endif
-#ifdef DEBUG_IRQ_LATENCY
-static int64_t irq_time[16];
-#endif
-DeviceState *isa_pic;
-static PICCommonState *slave_pic;
-
-/* return the highest priority found in mask (highest = smallest
- number). Return 8 if no irq */
-static int get_priority(PICCommonState *s, int mask)
-{
- int priority;
-
- if (mask == 0) {
- return 8;
- }
- priority = 0;
- while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0) {
- priority++;
- }
- return priority;
-}
-
-/* return the pic wanted interrupt. return -1 if none */
-static int pic_get_irq(PICCommonState *s)
-{
- int mask, cur_priority, priority;
-
- mask = s->irr & ~s->imr;
- priority = get_priority(s, mask);
- if (priority == 8) {
- return -1;
- }
- /* compute current priority. If special fully nested mode on the
- master, the IRQ coming from the slave is not taken into account
- for the priority computation. */
- mask = s->isr;
- if (s->special_mask) {
- mask &= ~s->imr;
- }
- if (s->special_fully_nested_mode && s->master) {
- mask &= ~(1 << 2);
- }
- cur_priority = get_priority(s, mask);
- if (priority < cur_priority) {
- /* higher priority found: an irq should be generated */
- return (priority + s->priority_add) & 7;
- } else {
- return -1;
- }
-}
-
-/* Update INT output. Must be called every time the output may have changed. */
-static void pic_update_irq(PICCommonState *s)
-{
- int irq;
-
- irq = pic_get_irq(s);
- if (irq >= 0) {
- DPRINTF("pic%d: imr=%x irr=%x padd=%d\n",
- s->master ? 0 : 1, s->imr, s->irr, s->priority_add);
- qemu_irq_raise(s->int_out[0]);
- } else {
- qemu_irq_lower(s->int_out[0]);
- }
-}
-
-/* set irq level. If an edge is detected, then the IRR is set to 1 */
-static void pic_set_irq(void *opaque, int irq, int level)
-{
- PICCommonState *s = opaque;
- int mask = 1 << irq;
-
-#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT) || \
- defined(DEBUG_IRQ_LATENCY)
- int irq_index = s->master ? irq : irq + 8;
-#endif
-#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
- if (level != irq_level[irq_index]) {
- DPRINTF("pic_set_irq: irq=%d level=%d\n", irq_index, level);
- irq_level[irq_index] = level;
-#ifdef DEBUG_IRQ_COUNT
- if (level == 1) {
- irq_count[irq_index]++;
- }
-#endif
- }
-#endif
-#ifdef DEBUG_IRQ_LATENCY
- if (level) {
- irq_time[irq_index] = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- }
-#endif
-
- if (s->elcr & mask) {
- /* level triggered */
- if (level) {
- s->irr |= mask;
- s->last_irr |= mask;
- } else {
- s->irr &= ~mask;
- s->last_irr &= ~mask;
- }
- } else {
- /* edge triggered */
- if (level) {
- if ((s->last_irr & mask) == 0) {
- s->irr |= mask;
- }
- s->last_irr |= mask;
- } else {
- s->last_irr &= ~mask;
- }
- }
- pic_update_irq(s);
-}
-
-/* acknowledge interrupt 'irq' */
-static void pic_intack(PICCommonState *s, int irq)
-{
- if (s->auto_eoi) {
- if (s->rotate_on_auto_eoi) {
- s->priority_add = (irq + 1) & 7;
- }
- } else {
- s->isr |= (1 << irq);
- }
- /* We don't clear a level sensitive interrupt here */
- if (!(s->elcr & (1 << irq))) {
- s->irr &= ~(1 << irq);
- }
- pic_update_irq(s);
-}
-
-int pic_read_irq(DeviceState *d)
-{
- PICCommonState *s = PIC_COMMON(d);
- int irq, irq2, intno;
-
- irq = pic_get_irq(s);
- if (irq >= 0) {
- if (irq == 2) {
- irq2 = pic_get_irq(slave_pic);
- if (irq2 >= 0) {
- pic_intack(slave_pic, irq2);
- } else {
- /* spurious IRQ on slave controller */
- irq2 = 7;
- }
- intno = slave_pic->irq_base + irq2;
- } else {
- intno = s->irq_base + irq;
- }
- pic_intack(s, irq);
- } else {
- /* spurious IRQ on host controller */
- irq = 7;
- intno = s->irq_base + irq;
- }
-
-#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_LATENCY)
- if (irq == 2) {
- irq = irq2 + 8;
- }
-#endif
-#ifdef DEBUG_IRQ_LATENCY
- printf("IRQ%d latency=%0.3fus\n",
- irq,
- (double)(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) -
- irq_time[irq]) * 1000000.0 / NANOSECONDS_PER_SECOND);
-#endif
- DPRINTF("pic_interrupt: irq=%d\n", irq);
- return intno;
-}
-
-static void pic_init_reset(PICCommonState *s)
-{
- pic_reset_common(s);
- pic_update_irq(s);
-}
-
-static void pic_reset(DeviceState *dev)
-{
- PICCommonState *s = PIC_COMMON(dev);
-
- s->elcr = 0;
- pic_init_reset(s);
-}
-
-static void pic_ioport_write(void *opaque, hwaddr addr64,
- uint64_t val64, unsigned size)
-{
- PICCommonState *s = opaque;
- uint32_t addr = addr64;
- uint32_t val = val64;
- int priority, cmd, irq;
-
- DPRINTF("write: addr=0x%02x val=0x%02x\n", addr, val);
- if (addr == 0) {
- if (val & 0x10) {
- pic_init_reset(s);
- s->init_state = 1;
- s->init4 = val & 1;
- s->single_mode = val & 2;
- if (val & 0x08) {
- qemu_log_mask(LOG_UNIMP,
- "i8259: level sensitive irq not supported\n");
- }
- } else if (val & 0x08) {
- if (val & 0x04) {
- s->poll = 1;
- }
- if (val & 0x02) {
- s->read_reg_select = val & 1;
- }
- if (val & 0x40) {
- s->special_mask = (val >> 5) & 1;
- }
- } else {
- cmd = val >> 5;
- switch (cmd) {
- case 0:
- case 4:
- s->rotate_on_auto_eoi = cmd >> 2;
- break;
- case 1: /* end of interrupt */
- case 5:
- priority = get_priority(s, s->isr);
- if (priority != 8) {
- irq = (priority + s->priority_add) & 7;
- s->isr &= ~(1 << irq);
- if (cmd == 5) {
- s->priority_add = (irq + 1) & 7;
- }
- pic_update_irq(s);
- }
- break;
- case 3:
- irq = val & 7;
- s->isr &= ~(1 << irq);
- pic_update_irq(s);
- break;
- case 6:
- s->priority_add = (val + 1) & 7;
- pic_update_irq(s);
- break;
- case 7:
- irq = val & 7;
- s->isr &= ~(1 << irq);
- s->priority_add = (irq + 1) & 7;
- pic_update_irq(s);
- break;
- default:
- /* no operation */
- break;
- }
- }
- } else {
- switch (s->init_state) {
- case 0:
- /* normal mode */
- s->imr = val;
- pic_update_irq(s);
- break;
- case 1:
- s->irq_base = val & 0xf8;
- s->init_state = s->single_mode ? (s->init4 ? 3 : 0) : 2;
- break;
- case 2:
- if (s->init4) {
- s->init_state = 3;
- } else {
- s->init_state = 0;
- }
- break;
- case 3:
- s->special_fully_nested_mode = (val >> 4) & 1;
- s->auto_eoi = (val >> 1) & 1;
- s->init_state = 0;
- break;
- }
- }
-}
-
-static uint64_t pic_ioport_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- PICCommonState *s = opaque;
- int ret;
-
- if (s->poll) {
- ret = pic_get_irq(s);
- if (ret >= 0) {
- pic_intack(s, ret);
- ret |= 0x80;
- } else {
- ret = 0;
- }
- s->poll = 0;
- } else {
- if (addr == 0) {
- if (s->read_reg_select) {
- ret = s->isr;
- } else {
- ret = s->irr;
- }
- } else {
- ret = s->imr;
- }
- }
- DPRINTF("read: addr=0x%02" HWADDR_PRIx " val=0x%02x\n", addr, ret);
- return ret;
-}
-
-int pic_get_output(DeviceState *d)
-{
- PICCommonState *s = PIC_COMMON(d);
-
- return (pic_get_irq(s) >= 0);
-}
-
-static void elcr_ioport_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- PICCommonState *s = opaque;
- s->elcr = val & s->elcr_mask;
-}
-
-static uint64_t elcr_ioport_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- PICCommonState *s = opaque;
- return s->elcr;
-}
-
-static const MemoryRegionOps pic_base_ioport_ops = {
- .read = pic_ioport_read,
- .write = pic_ioport_write,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
-};
-
-static const MemoryRegionOps pic_elcr_ioport_ops = {
- .read = elcr_ioport_read,
- .write = elcr_ioport_write,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
-};
-
-static void pic_realize(DeviceState *dev, Error **errp)
-{
- PICCommonState *s = PIC_COMMON(dev);
- PICClass *pc = PIC_GET_CLASS(dev);
-
- memory_region_init_io(&s->base_io, OBJECT(s), &pic_base_ioport_ops, s,
- "pic", 2);
- memory_region_init_io(&s->elcr_io, OBJECT(s), &pic_elcr_ioport_ops, s,
- "elcr", 1);
-
- qdev_init_gpio_out(dev, s->int_out, ARRAY_SIZE(s->int_out));
- qdev_init_gpio_in(dev, pic_set_irq, 8);
-
- pc->parent_realize(dev, errp);
-}
-
-void hmp_info_pic(Monitor *mon, const QDict *qdict)
-{
- int i;
- PICCommonState *s;
-
- if (!isa_pic) {
- return;
- }
- for (i = 0; i < 2; i++) {
- s = i == 0 ? PIC_COMMON(isa_pic) : slave_pic;
- monitor_printf(mon, "pic%d: irr=%02x imr=%02x isr=%02x hprio=%d "
- "irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n",
- i, s->irr, s->imr, s->isr, s->priority_add,
- s->irq_base, s->read_reg_select, s->elcr,
- s->special_fully_nested_mode);
- }
-}
-
-void hmp_info_irq(Monitor *mon, const QDict *qdict)
-{
-#ifndef DEBUG_IRQ_COUNT
- monitor_printf(mon, "irq statistic code not compiled.\n");
-#else
- int i;
- int64_t count;
-
- monitor_printf(mon, "IRQ statistics:\n");
- for (i = 0; i < 16; i++) {
- count = irq_count[i];
- if (count > 0) {
- monitor_printf(mon, "%2d: %" PRId64 "\n", i, count);
- }
- }
-#endif
-}
-
-qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq)
-{
- qemu_irq *irq_set;
- DeviceState *dev;
- ISADevice *isadev;
- int i;
-
- irq_set = g_new0(qemu_irq, ISA_NUM_IRQS);
-
- isadev = i8259_init_chip(TYPE_I8259, bus, true);
- dev = DEVICE(isadev);
-
- qdev_connect_gpio_out(dev, 0, parent_irq);
- for (i = 0 ; i < 8; i++) {
- irq_set[i] = qdev_get_gpio_in(dev, i);
- }
-
- isa_pic = dev;
-
- isadev = i8259_init_chip(TYPE_I8259, bus, false);
- dev = DEVICE(isadev);
-
- qdev_connect_gpio_out(dev, 0, irq_set[2]);
- for (i = 0 ; i < 8; i++) {
- irq_set[i + 8] = qdev_get_gpio_in(dev, i);
- }
-
- slave_pic = PIC_COMMON(dev);
-
- return irq_set;
-}
-
-static void i8259_class_init(ObjectClass *klass, void *data)
-{
- PICClass *k = PIC_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- k->parent_realize = dc->realize;
- dc->realize = pic_realize;
- dc->reset = pic_reset;
-}
-
-static const TypeInfo i8259_info = {
- .name = TYPE_I8259,
- .instance_size = sizeof(PICCommonState),
- .parent = TYPE_PIC_COMMON,
- .class_init = i8259_class_init,
- .class_size = sizeof(PICClass),
-};
-
-static void pic_register_types(void)
-{
- type_register_static(&i8259_info);
-}
-
-type_init(pic_register_types)
diff --git a/qemu/hw/intc/i8259_common.c b/qemu/hw/intc/i8259_common.c
deleted file mode 100644
index 3a850b0c6..000000000
--- a/qemu/hw/intc/i8259_common.c
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * QEMU 8259 - common bits of emulated and KVM kernel model
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- * Copyright (c) 2011 Jan Kiszka, Siemens AG
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "hw/i386/pc.h"
-#include "hw/isa/i8259_internal.h"
-
-void pic_reset_common(PICCommonState *s)
-{
- s->last_irr = 0;
- s->irr &= s->elcr;
- s->imr = 0;
- s->isr = 0;
- s->priority_add = 0;
- s->irq_base = 0;
- s->read_reg_select = 0;
- s->poll = 0;
- s->special_mask = 0;
- s->init_state = 0;
- s->auto_eoi = 0;
- s->rotate_on_auto_eoi = 0;
- s->special_fully_nested_mode = 0;
- s->init4 = 0;
- s->single_mode = 0;
- /* Note: ELCR is not reset */
-}
-
-static void pic_dispatch_pre_save(void *opaque)
-{
- PICCommonState *s = opaque;
- PICCommonClass *info = PIC_COMMON_GET_CLASS(s);
-
- if (info->pre_save) {
- info->pre_save(s);
- }
-}
-
-static int pic_dispatch_post_load(void *opaque, int version_id)
-{
- PICCommonState *s = opaque;
- PICCommonClass *info = PIC_COMMON_GET_CLASS(s);
-
- if (info->post_load) {
- info->post_load(s);
- }
- return 0;
-}
-
-static void pic_common_realize(DeviceState *dev, Error **errp)
-{
- PICCommonState *s = PIC_COMMON(dev);
-
- isa_register_ioport(NULL, &s->base_io, s->iobase);
- if (s->elcr_addr != -1) {
- isa_register_ioport(NULL, &s->elcr_io, s->elcr_addr);
- }
-
- qdev_set_legacy_instance_id(dev, s->iobase, 1);
-}
-
-ISADevice *i8259_init_chip(const char *name, ISABus *bus, bool master)
-{
- DeviceState *dev;
- ISADevice *isadev;
-
- isadev = isa_create(bus, name);
- dev = DEVICE(isadev);
- qdev_prop_set_uint32(dev, "iobase", master ? 0x20 : 0xa0);
- qdev_prop_set_uint32(dev, "elcr_addr", master ? 0x4d0 : 0x4d1);
- qdev_prop_set_uint8(dev, "elcr_mask", master ? 0xf8 : 0xde);
- qdev_prop_set_bit(dev, "master", master);
- qdev_init_nofail(dev);
-
- return isadev;
-}
-
-static const VMStateDescription vmstate_pic_common = {
- .name = "i8259",
- .version_id = 1,
- .minimum_version_id = 1,
- .pre_save = pic_dispatch_pre_save,
- .post_load = pic_dispatch_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(last_irr, PICCommonState),
- VMSTATE_UINT8(irr, PICCommonState),
- VMSTATE_UINT8(imr, PICCommonState),
- VMSTATE_UINT8(isr, PICCommonState),
- VMSTATE_UINT8(priority_add, PICCommonState),
- VMSTATE_UINT8(irq_base, PICCommonState),
- VMSTATE_UINT8(read_reg_select, PICCommonState),
- VMSTATE_UINT8(poll, PICCommonState),
- VMSTATE_UINT8(special_mask, PICCommonState),
- VMSTATE_UINT8(init_state, PICCommonState),
- VMSTATE_UINT8(auto_eoi, PICCommonState),
- VMSTATE_UINT8(rotate_on_auto_eoi, PICCommonState),
- VMSTATE_UINT8(special_fully_nested_mode, PICCommonState),
- VMSTATE_UINT8(init4, PICCommonState),
- VMSTATE_UINT8(single_mode, PICCommonState),
- VMSTATE_UINT8(elcr, PICCommonState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property pic_properties_common[] = {
- DEFINE_PROP_UINT32("iobase", PICCommonState, iobase, -1),
- DEFINE_PROP_UINT32("elcr_addr", PICCommonState, elcr_addr, -1),
- DEFINE_PROP_UINT8("elcr_mask", PICCommonState, elcr_mask, -1),
- DEFINE_PROP_BIT("master", PICCommonState, master, 0, false),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pic_common_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->vmsd = &vmstate_pic_common;
- dc->props = pic_properties_common;
- dc->realize = pic_common_realize;
- /*
- * Reason: unlike ordinary ISA devices, the PICs need additional
- * wiring: its IRQ input lines are set up by board code, and the
- * wiring of the slave to the master is hard-coded in device model
- * code.
- */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo pic_common_type = {
- .name = TYPE_PIC_COMMON,
- .parent = TYPE_ISA_DEVICE,
- .instance_size = sizeof(PICCommonState),
- .class_size = sizeof(PICCommonClass),
- .class_init = pic_common_class_init,
- .abstract = true,
-};
-
-static void pic_common_register_types(void)
-{
- type_register_static(&pic_common_type);
-}
-
-type_init(pic_common_register_types)
diff --git a/qemu/hw/intc/imx_avic.c b/qemu/hw/intc/imx_avic.c
deleted file mode 100644
index 702765577..000000000
--- a/qemu/hw/intc/imx_avic.c
+++ /dev/null
@@ -1,363 +0,0 @@
-/*
- * i.MX31 Vectored Interrupt Controller
- *
- * Note this is NOT the PL192 provided by ARM, but
- * a custom implementation by Freescale.
- *
- * Copyright (c) 2008 OKL
- * Copyright (c) 2011 NICTA Pty Ltd
- * Originally written by Hans Jiang
- * Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
- *
- * This code is licensed under the GPL version 2 or later. See
- * the COPYING file in the top-level directory.
- *
- * TODO: implement vectors.
- */
-
-#include "qemu/osdep.h"
-#include "hw/intc/imx_avic.h"
-
-#ifndef DEBUG_IMX_AVIC
-#define DEBUG_IMX_AVIC 0
-#endif
-
-#define DPRINTF(fmt, args...) \
- do { \
- if (DEBUG_IMX_AVIC) { \
- fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_AVIC, \
- __func__, ##args); \
- } \
- } while (0)
-
-static const VMStateDescription vmstate_imx_avic = {
- .name = TYPE_IMX_AVIC,
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT64(pending, IMXAVICState),
- VMSTATE_UINT64(enabled, IMXAVICState),
- VMSTATE_UINT64(is_fiq, IMXAVICState),
- VMSTATE_UINT32(intcntl, IMXAVICState),
- VMSTATE_UINT32(intmask, IMXAVICState),
- VMSTATE_UINT32_ARRAY(prio, IMXAVICState, PRIO_WORDS),
- VMSTATE_END_OF_LIST()
- },
-};
-
-static inline int imx_avic_prio(IMXAVICState *s, int irq)
-{
- uint32_t word = irq / PRIO_PER_WORD;
- uint32_t part = 4 * (irq % PRIO_PER_WORD);
- return 0xf & (s->prio[word] >> part);
-}
-
-/* Update interrupts. */
-static void imx_avic_update(IMXAVICState *s)
-{
- int i;
- uint64_t new = s->pending & s->enabled;
- uint64_t flags;
-
- flags = new & s->is_fiq;
- qemu_set_irq(s->fiq, !!flags);
-
- flags = new & ~s->is_fiq;
- if (!flags || (s->intmask == 0x1f)) {
- qemu_set_irq(s->irq, !!flags);
- return;
- }
-
- /*
- * Take interrupt if there's a pending interrupt with
- * priority higher than the value of intmask
- */
- for (i = 0; i < IMX_AVIC_NUM_IRQS; i++) {
- if (flags & (1UL << i)) {
- if (imx_avic_prio(s, i) > s->intmask) {
- qemu_set_irq(s->irq, 1);
- return;
- }
- }
- }
- qemu_set_irq(s->irq, 0);
-}
-
-static void imx_avic_set_irq(void *opaque, int irq, int level)
-{
- IMXAVICState *s = (IMXAVICState *)opaque;
-
- if (level) {
- DPRINTF("Raising IRQ %d, prio %d\n",
- irq, imx_avic_prio(s, irq));
- s->pending |= (1ULL << irq);
- } else {
- DPRINTF("Clearing IRQ %d, prio %d\n",
- irq, imx_avic_prio(s, irq));
- s->pending &= ~(1ULL << irq);
- }
-
- imx_avic_update(s);
-}
-
-
-static uint64_t imx_avic_read(void *opaque,
- hwaddr offset, unsigned size)
-{
- IMXAVICState *s = (IMXAVICState *)opaque;
-
- DPRINTF("read(offset = 0x%" HWADDR_PRIx ")\n", offset);
-
- switch (offset >> 2) {
- case 0: /* INTCNTL */
- return s->intcntl;
-
- case 1: /* Normal Interrupt Mask Register, NIMASK */
- return s->intmask;
-
- case 2: /* Interrupt Enable Number Register, INTENNUM */
- case 3: /* Interrupt Disable Number Register, INTDISNUM */
- return 0;
-
- case 4: /* Interrupt Enabled Number Register High */
- return s->enabled >> 32;
-
- case 5: /* Interrupt Enabled Number Register Low */
- return s->enabled & 0xffffffffULL;
-
- case 6: /* Interrupt Type Register High */
- return s->is_fiq >> 32;
-
- case 7: /* Interrupt Type Register Low */
- return s->is_fiq & 0xffffffffULL;
-
- case 8: /* Normal Interrupt Priority Register 7 */
- case 9: /* Normal Interrupt Priority Register 6 */
- case 10:/* Normal Interrupt Priority Register 5 */
- case 11:/* Normal Interrupt Priority Register 4 */
- case 12:/* Normal Interrupt Priority Register 3 */
- case 13:/* Normal Interrupt Priority Register 2 */
- case 14:/* Normal Interrupt Priority Register 1 */
- case 15:/* Normal Interrupt Priority Register 0 */
- return s->prio[15-(offset>>2)];
-
- case 16: /* Normal interrupt vector and status register */
- {
- /*
- * This returns the highest priority
- * outstanding interrupt. Where there is more than
- * one pending IRQ with the same priority,
- * take the highest numbered one.
- */
- uint64_t flags = s->pending & s->enabled & ~s->is_fiq;
- int i;
- int prio = -1;
- int irq = -1;
- for (i = 63; i >= 0; --i) {
- if (flags & (1ULL<<i)) {
- int irq_prio = imx_avic_prio(s, i);
- if (irq_prio > prio) {
- irq = i;
- prio = irq_prio;
- }
- }
- }
- if (irq >= 0) {
- imx_avic_set_irq(s, irq, 0);
- return irq << 16 | prio;
- }
- return 0xffffffffULL;
- }
- case 17:/* Fast Interrupt vector and status register */
- {
- uint64_t flags = s->pending & s->enabled & s->is_fiq;
- int i = ctz64(flags);
- if (i < 64) {
- imx_avic_set_irq(opaque, i, 0);
- return i;
- }
- return 0xffffffffULL;
- }
- case 18:/* Interrupt source register high */
- return s->pending >> 32;
-
- case 19:/* Interrupt source register low */
- return s->pending & 0xffffffffULL;
-
- case 20:/* Interrupt Force Register high */
- case 21:/* Interrupt Force Register low */
- return 0;
-
- case 22:/* Normal Interrupt Pending Register High */
- return (s->pending & s->enabled & ~s->is_fiq) >> 32;
-
- case 23:/* Normal Interrupt Pending Register Low */
- return (s->pending & s->enabled & ~s->is_fiq) & 0xffffffffULL;
-
- case 24: /* Fast Interrupt Pending Register High */
- return (s->pending & s->enabled & s->is_fiq) >> 32;
-
- case 25: /* Fast Interrupt Pending Register Low */
- return (s->pending & s->enabled & s->is_fiq) & 0xffffffffULL;
-
- case 0x40: /* AVIC vector 0, use for WFI WAR */
- return 0x4;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
- HWADDR_PRIx "\n", TYPE_IMX_AVIC, __func__, offset);
- return 0;
- }
-}
-
-static void imx_avic_write(void *opaque, hwaddr offset,
- uint64_t val, unsigned size)
-{
- IMXAVICState *s = (IMXAVICState *)opaque;
-
- /* Vector Registers not yet supported */
- if (offset >= 0x100 && offset <= 0x2fc) {
- qemu_log_mask(LOG_UNIMP, "[%s]%s: vector %d ignored\n",
- TYPE_IMX_AVIC, __func__, (int)((offset - 0x100) >> 2));
- return;
- }
-
- DPRINTF("(0x%" HWADDR_PRIx ") = 0x%x\n", offset, (unsigned int)val);
-
- switch (offset >> 2) {
- case 0: /* Interrupt Control Register, INTCNTL */
- s->intcntl = val & (ABFEN | NIDIS | FIDIS | NIAD | FIAD | NM);
- if (s->intcntl & ABFEN) {
- s->intcntl &= ~(val & ABFLAG);
- }
- break;
-
- case 1: /* Normal Interrupt Mask Register, NIMASK */
- s->intmask = val & 0x1f;
- break;
-
- case 2: /* Interrupt Enable Number Register, INTENNUM */
- DPRINTF("enable(%d)\n", (int)val);
- val &= 0x3f;
- s->enabled |= (1ULL << val);
- break;
-
- case 3: /* Interrupt Disable Number Register, INTDISNUM */
- DPRINTF("disable(%d)\n", (int)val);
- val &= 0x3f;
- s->enabled &= ~(1ULL << val);
- break;
-
- case 4: /* Interrupt Enable Number Register High */
- s->enabled = (s->enabled & 0xffffffffULL) | (val << 32);
- break;
-
- case 5: /* Interrupt Enable Number Register Low */
- s->enabled = (s->enabled & 0xffffffff00000000ULL) | val;
- break;
-
- case 6: /* Interrupt Type Register High */
- s->is_fiq = (s->is_fiq & 0xffffffffULL) | (val << 32);
- break;
-
- case 7: /* Interrupt Type Register Low */
- s->is_fiq = (s->is_fiq & 0xffffffff00000000ULL) | val;
- break;
-
- case 8: /* Normal Interrupt Priority Register 7 */
- case 9: /* Normal Interrupt Priority Register 6 */
- case 10:/* Normal Interrupt Priority Register 5 */
- case 11:/* Normal Interrupt Priority Register 4 */
- case 12:/* Normal Interrupt Priority Register 3 */
- case 13:/* Normal Interrupt Priority Register 2 */
- case 14:/* Normal Interrupt Priority Register 1 */
- case 15:/* Normal Interrupt Priority Register 0 */
- s->prio[15-(offset>>2)] = val;
- break;
-
- /* Read-only registers, writes ignored */
- case 16:/* Normal Interrupt Vector and Status register */
- case 17:/* Fast Interrupt vector and status register */
- case 18:/* Interrupt source register high */
- case 19:/* Interrupt source register low */
- return;
-
- case 20:/* Interrupt Force Register high */
- s->pending = (s->pending & 0xffffffffULL) | (val << 32);
- break;
-
- case 21:/* Interrupt Force Register low */
- s->pending = (s->pending & 0xffffffff00000000ULL) | val;
- break;
-
- case 22:/* Normal Interrupt Pending Register High */
- case 23:/* Normal Interrupt Pending Register Low */
- case 24: /* Fast Interrupt Pending Register High */
- case 25: /* Fast Interrupt Pending Register Low */
- return;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
- HWADDR_PRIx "\n", TYPE_IMX_AVIC, __func__, offset);
- }
- imx_avic_update(s);
-}
-
-static const MemoryRegionOps imx_avic_ops = {
- .read = imx_avic_read,
- .write = imx_avic_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void imx_avic_reset(DeviceState *dev)
-{
- IMXAVICState *s = IMX_AVIC(dev);
-
- s->pending = 0;
- s->enabled = 0;
- s->is_fiq = 0;
- s->intmask = 0x1f;
- s->intcntl = 0;
- memset(s->prio, 0, sizeof s->prio);
-}
-
-static int imx_avic_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- IMXAVICState *s = IMX_AVIC(dev);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &imx_avic_ops, s,
- TYPE_IMX_AVIC, 0x1000);
- sysbus_init_mmio(sbd, &s->iomem);
-
- qdev_init_gpio_in(dev, imx_avic_set_irq, IMX_AVIC_NUM_IRQS);
- sysbus_init_irq(sbd, &s->irq);
- sysbus_init_irq(sbd, &s->fiq);
-
- return 0;
-}
-
-
-static void imx_avic_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- k->init = imx_avic_init;
- dc->vmsd = &vmstate_imx_avic;
- dc->reset = imx_avic_reset;
- dc->desc = "i.MX Advanced Vector Interrupt Controller";
-}
-
-static const TypeInfo imx_avic_info = {
- .name = TYPE_IMX_AVIC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(IMXAVICState),
- .class_init = imx_avic_class_init,
-};
-
-static void imx_avic_register_types(void)
-{
- type_register_static(&imx_avic_info);
-}
-
-type_init(imx_avic_register_types)
diff --git a/qemu/hw/intc/ioapic.c b/qemu/hw/intc/ioapic.c
deleted file mode 100644
index 378e663f6..000000000
--- a/qemu/hw/intc/ioapic.c
+++ /dev/null
@@ -1,338 +0,0 @@
-/*
- * ioapic.c IOAPIC emulation logic
- *
- * Copyright (c) 2004-2005 Fabrice Bellard
- *
- * Split the ioapic logic from apic.c
- * Xiantao Zhang <xiantao.zhang@intel.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "monitor/monitor.h"
-#include "hw/hw.h"
-#include "hw/i386/pc.h"
-#include "hw/i386/ioapic.h"
-#include "hw/i386/ioapic_internal.h"
-#include "include/hw/pci/msi.h"
-#include "sysemu/kvm.h"
-
-//#define DEBUG_IOAPIC
-
-#ifdef DEBUG_IOAPIC
-#define DPRINTF(fmt, ...) \
- do { printf("ioapic: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...)
-#endif
-
-#define APIC_DELIVERY_MODE_SHIFT 8
-#define APIC_POLARITY_SHIFT 14
-#define APIC_TRIG_MODE_SHIFT 15
-
-static IOAPICCommonState *ioapics[MAX_IOAPICS];
-
-/* global variable from ioapic_common.c */
-extern int ioapic_no;
-
-static void ioapic_service(IOAPICCommonState *s)
-{
- uint8_t i;
- uint8_t trig_mode;
- uint8_t vector;
- uint8_t delivery_mode;
- uint32_t mask;
- uint64_t entry;
- uint8_t dest;
- uint8_t dest_mode;
-
- for (i = 0; i < IOAPIC_NUM_PINS; i++) {
- mask = 1 << i;
- if (s->irr & mask) {
- int coalesce = 0;
-
- entry = s->ioredtbl[i];
- if (!(entry & IOAPIC_LVT_MASKED)) {
- trig_mode = ((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1);
- dest = entry >> IOAPIC_LVT_DEST_SHIFT;
- dest_mode = (entry >> IOAPIC_LVT_DEST_MODE_SHIFT) & 1;
- delivery_mode =
- (entry >> IOAPIC_LVT_DELIV_MODE_SHIFT) & IOAPIC_DM_MASK;
- if (trig_mode == IOAPIC_TRIGGER_EDGE) {
- s->irr &= ~mask;
- } else {
- coalesce = s->ioredtbl[i] & IOAPIC_LVT_REMOTE_IRR;
- s->ioredtbl[i] |= IOAPIC_LVT_REMOTE_IRR;
- }
- if (delivery_mode == IOAPIC_DM_EXTINT) {
- vector = pic_read_irq(isa_pic);
- } else {
- vector = entry & IOAPIC_VECTOR_MASK;
- }
-#ifdef CONFIG_KVM
- if (kvm_irqchip_is_split()) {
- if (trig_mode == IOAPIC_TRIGGER_EDGE) {
- kvm_set_irq(kvm_state, i, 1);
- kvm_set_irq(kvm_state, i, 0);
- } else {
- if (!coalesce) {
- kvm_set_irq(kvm_state, i, 1);
- }
- }
- continue;
- }
-#else
- (void)coalesce;
-#endif
- apic_deliver_irq(dest, dest_mode, delivery_mode, vector,
- trig_mode);
- }
- }
- }
-}
-
-static void ioapic_set_irq(void *opaque, int vector, int level)
-{
- IOAPICCommonState *s = opaque;
-
- /* ISA IRQs map to GSI 1-1 except for IRQ0 which maps
- * to GSI 2. GSI maps to ioapic 1-1. This is not
- * the cleanest way of doing it but it should work. */
-
- DPRINTF("%s: %s vec %x\n", __func__, level ? "raise" : "lower", vector);
- if (vector == 0) {
- vector = 2;
- }
- if (vector >= 0 && vector < IOAPIC_NUM_PINS) {
- uint32_t mask = 1 << vector;
- uint64_t entry = s->ioredtbl[vector];
-
- if (((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1) ==
- IOAPIC_TRIGGER_LEVEL) {
- /* level triggered */
- if (level) {
- s->irr |= mask;
- if (!(entry & IOAPIC_LVT_REMOTE_IRR)) {
- ioapic_service(s);
- }
- } else {
- s->irr &= ~mask;
- }
- } else {
- /* According to the 82093AA manual, we must ignore edge requests
- * if the input pin is masked. */
- if (level && !(entry & IOAPIC_LVT_MASKED)) {
- s->irr |= mask;
- ioapic_service(s);
- }
- }
- }
-}
-
-static void ioapic_update_kvm_routes(IOAPICCommonState *s)
-{
-#ifdef CONFIG_KVM
- int i;
-
- if (kvm_irqchip_is_split()) {
- for (i = 0; i < IOAPIC_NUM_PINS; i++) {
- uint64_t entry = s->ioredtbl[i];
- uint8_t trig_mode;
- uint8_t delivery_mode;
- uint8_t dest;
- uint8_t dest_mode;
- uint64_t pin_polarity;
- MSIMessage msg;
-
- trig_mode = ((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1);
- dest = entry >> IOAPIC_LVT_DEST_SHIFT;
- dest_mode = (entry >> IOAPIC_LVT_DEST_MODE_SHIFT) & 1;
- pin_polarity = (entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1;
- delivery_mode =
- (entry >> IOAPIC_LVT_DELIV_MODE_SHIFT) & IOAPIC_DM_MASK;
-
- msg.address = APIC_DEFAULT_ADDRESS;
- msg.address |= dest_mode << 2;
- msg.address |= dest << 12;
-
- msg.data = entry & IOAPIC_VECTOR_MASK;
- msg.data |= delivery_mode << APIC_DELIVERY_MODE_SHIFT;
- msg.data |= pin_polarity << APIC_POLARITY_SHIFT;
- msg.data |= trig_mode << APIC_TRIG_MODE_SHIFT;
-
- kvm_irqchip_update_msi_route(kvm_state, i, msg, NULL);
- }
- kvm_irqchip_commit_routes(kvm_state);
- }
-#endif
-}
-
-void ioapic_eoi_broadcast(int vector)
-{
- IOAPICCommonState *s;
- uint64_t entry;
- int i, n;
-
- for (i = 0; i < MAX_IOAPICS; i++) {
- s = ioapics[i];
- if (!s) {
- continue;
- }
- for (n = 0; n < IOAPIC_NUM_PINS; n++) {
- entry = s->ioredtbl[n];
- if ((entry & IOAPIC_LVT_REMOTE_IRR)
- && (entry & IOAPIC_VECTOR_MASK) == vector) {
- s->ioredtbl[n] = entry & ~IOAPIC_LVT_REMOTE_IRR;
- if (!(entry & IOAPIC_LVT_MASKED) && (s->irr & (1 << n))) {
- ioapic_service(s);
- }
- }
- }
- }
-}
-
-void ioapic_dump_state(Monitor *mon, const QDict *qdict)
-{
- int i;
-
- for (i = 0; i < MAX_IOAPICS; i++) {
- if (ioapics[i] != 0) {
- ioapic_print_redtbl(mon, ioapics[i]);
- }
- }
-}
-
-static uint64_t
-ioapic_mem_read(void *opaque, hwaddr addr, unsigned int size)
-{
- IOAPICCommonState *s = opaque;
- int index;
- uint32_t val = 0;
-
- switch (addr & 0xff) {
- case IOAPIC_IOREGSEL:
- val = s->ioregsel;
- break;
- case IOAPIC_IOWIN:
- if (size != 4) {
- break;
- }
- switch (s->ioregsel) {
- case IOAPIC_REG_ID:
- case IOAPIC_REG_ARB:
- val = s->id << IOAPIC_ID_SHIFT;
- break;
- case IOAPIC_REG_VER:
- val = IOAPIC_VERSION |
- ((IOAPIC_NUM_PINS - 1) << IOAPIC_VER_ENTRIES_SHIFT);
- break;
- default:
- index = (s->ioregsel - IOAPIC_REG_REDTBL_BASE) >> 1;
- if (index >= 0 && index < IOAPIC_NUM_PINS) {
- if (s->ioregsel & 1) {
- val = s->ioredtbl[index] >> 32;
- } else {
- val = s->ioredtbl[index] & 0xffffffff;
- }
- }
- }
- DPRINTF("read: %08x = %08x\n", s->ioregsel, val);
- break;
- }
- return val;
-}
-
-static void
-ioapic_mem_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned int size)
-{
- IOAPICCommonState *s = opaque;
- int index;
-
- switch (addr & 0xff) {
- case IOAPIC_IOREGSEL:
- s->ioregsel = val;
- break;
- case IOAPIC_IOWIN:
- if (size != 4) {
- break;
- }
- DPRINTF("write: %08x = %08" PRIx64 "\n", s->ioregsel, val);
- switch (s->ioregsel) {
- case IOAPIC_REG_ID:
- s->id = (val >> IOAPIC_ID_SHIFT) & IOAPIC_ID_MASK;
- break;
- case IOAPIC_REG_VER:
- case IOAPIC_REG_ARB:
- break;
- default:
- index = (s->ioregsel - IOAPIC_REG_REDTBL_BASE) >> 1;
- if (index >= 0 && index < IOAPIC_NUM_PINS) {
- if (s->ioregsel & 1) {
- s->ioredtbl[index] &= 0xffffffff;
- s->ioredtbl[index] |= (uint64_t)val << 32;
- } else {
- s->ioredtbl[index] &= ~0xffffffffULL;
- s->ioredtbl[index] |= val;
- }
- ioapic_service(s);
- }
- }
- break;
- }
-
- ioapic_update_kvm_routes(s);
-}
-
-static const MemoryRegionOps ioapic_io_ops = {
- .read = ioapic_mem_read,
- .write = ioapic_mem_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void ioapic_realize(DeviceState *dev, Error **errp)
-{
- IOAPICCommonState *s = IOAPIC_COMMON(dev);
-
- memory_region_init_io(&s->io_memory, OBJECT(s), &ioapic_io_ops, s,
- "ioapic", 0x1000);
-
- qdev_init_gpio_in(dev, ioapic_set_irq, IOAPIC_NUM_PINS);
-
- ioapics[ioapic_no] = s;
-}
-
-static void ioapic_class_init(ObjectClass *klass, void *data)
-{
- IOAPICCommonClass *k = IOAPIC_COMMON_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- k->realize = ioapic_realize;
- dc->reset = ioapic_reset_common;
-}
-
-static const TypeInfo ioapic_info = {
- .name = "ioapic",
- .parent = TYPE_IOAPIC_COMMON,
- .instance_size = sizeof(IOAPICCommonState),
- .class_init = ioapic_class_init,
-};
-
-static void ioapic_register_types(void)
-{
- type_register_static(&ioapic_info);
-}
-
-type_init(ioapic_register_types)
diff --git a/qemu/hw/intc/ioapic_common.c b/qemu/hw/intc/ioapic_common.c
deleted file mode 100644
index 1b7ec5ec2..000000000
--- a/qemu/hw/intc/ioapic_common.c
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * IOAPIC emulation logic - common bits of emulated and KVM kernel model
- *
- * Copyright (c) 2004-2005 Fabrice Bellard
- * Copyright (c) 2009 Xiantao Zhang, Intel
- * Copyright (c) 2011 Jan Kiszka, Siemens AG
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "monitor/monitor.h"
-#include "hw/i386/ioapic.h"
-#include "hw/i386/ioapic_internal.h"
-#include "hw/sysbus.h"
-
-/* ioapic_no count start from 0 to MAX_IOAPICS,
- * remove as static variable from ioapic_common_init.
- * now as a global variable, let child to increase the counter
- * then we can drop the 'instance_no' argument
- * and convert to our QOM's realize function
- */
-int ioapic_no;
-
-static void ioapic_irr_dump(Monitor *mon, const char *name, uint32_t bitmap)
-{
- int i;
-
- monitor_printf(mon, "%-10s ", name);
- if (bitmap == 0) {
- monitor_printf(mon, "(none)\n");
- return;
- }
- for (i = 0; i < IOAPIC_NUM_PINS; i++) {
- if (bitmap & (1 << i)) {
- monitor_printf(mon, "%-2u ", i);
- }
- }
- monitor_printf(mon, "\n");
-}
-
-void ioapic_print_redtbl(Monitor *mon, IOAPICCommonState *s)
-{
- static const char *delm_str[] = {
- "fixed", "lowest", "SMI", "...", "NMI", "INIT", "...", "extINT"};
- uint32_t remote_irr = 0;
- int i;
-
- monitor_printf(mon, "ioapic id=0x%02x sel=0x%02x", s->id, s->ioregsel);
- if (s->ioregsel) {
- monitor_printf(mon, " (redir[%u])\n",
- (s->ioregsel - IOAPIC_REG_REDTBL_BASE) >> 1);
- } else {
- monitor_printf(mon, "\n");
- }
- for (i = 0; i < IOAPIC_NUM_PINS; i++) {
- uint64_t entry = s->ioredtbl[i];
- uint32_t delm = (uint32_t)((entry & IOAPIC_LVT_DELIV_MODE) >>
- IOAPIC_LVT_DELIV_MODE_SHIFT);
- monitor_printf(mon, "pin %-2u 0x%016"PRIx64" dest=%"PRIx64
- " vec=%-3"PRIu64" %s %-5s %-6s %-6s %s\n",
- i, entry,
- (entry >> IOAPIC_LVT_DEST_SHIFT) &
- (entry & IOAPIC_LVT_DEST_MODE ? 0xff : 0xf),
- entry & IOAPIC_VECTOR_MASK,
- entry & IOAPIC_LVT_POLARITY ? "active-lo" : "active-hi",
- entry & IOAPIC_LVT_TRIGGER_MODE ? "level" : "edge",
- entry & IOAPIC_LVT_MASKED ? "masked" : "",
- delm_str[delm],
- entry & IOAPIC_LVT_DEST_MODE ? "logical" : "physical");
-
- remote_irr |= entry & IOAPIC_LVT_TRIGGER_MODE ?
- (entry & IOAPIC_LVT_REMOTE_IRR ? (1 << i) : 0) : 0;
- }
- ioapic_irr_dump(mon, "IRR", s->irr);
- ioapic_irr_dump(mon, "Remote IRR", remote_irr);
-}
-
-void ioapic_reset_common(DeviceState *dev)
-{
- IOAPICCommonState *s = IOAPIC_COMMON(dev);
- int i;
-
- s->id = 0;
- s->ioregsel = 0;
- s->irr = 0;
- for (i = 0; i < IOAPIC_NUM_PINS; i++) {
- s->ioredtbl[i] = 1 << IOAPIC_LVT_MASKED_SHIFT;
- }
-}
-
-static void ioapic_dispatch_pre_save(void *opaque)
-{
- IOAPICCommonState *s = IOAPIC_COMMON(opaque);
- IOAPICCommonClass *info = IOAPIC_COMMON_GET_CLASS(s);
-
- if (info->pre_save) {
- info->pre_save(s);
- }
-}
-
-static int ioapic_dispatch_post_load(void *opaque, int version_id)
-{
- IOAPICCommonState *s = IOAPIC_COMMON(opaque);
- IOAPICCommonClass *info = IOAPIC_COMMON_GET_CLASS(s);
-
- if (info->post_load) {
- info->post_load(s);
- }
- return 0;
-}
-
-static void ioapic_common_realize(DeviceState *dev, Error **errp)
-{
- IOAPICCommonState *s = IOAPIC_COMMON(dev);
- IOAPICCommonClass *info;
-
- if (ioapic_no >= MAX_IOAPICS) {
- error_setg(errp, "Only %d ioapics allowed", MAX_IOAPICS);
- return;
- }
-
- info = IOAPIC_COMMON_GET_CLASS(s);
- info->realize(dev, errp);
-
- sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->io_memory);
- ioapic_no++;
-}
-
-static const VMStateDescription vmstate_ioapic_common = {
- .name = "ioapic",
- .version_id = 3,
- .minimum_version_id = 1,
- .pre_save = ioapic_dispatch_pre_save,
- .post_load = ioapic_dispatch_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(id, IOAPICCommonState),
- VMSTATE_UINT8(ioregsel, IOAPICCommonState),
- VMSTATE_UNUSED_V(2, 8), /* to account for qemu-kvm's v2 format */
- VMSTATE_UINT32_V(irr, IOAPICCommonState, 2),
- VMSTATE_UINT64_ARRAY(ioredtbl, IOAPICCommonState, IOAPIC_NUM_PINS),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void ioapic_common_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = ioapic_common_realize;
- dc->vmsd = &vmstate_ioapic_common;
-}
-
-static const TypeInfo ioapic_common_type = {
- .name = TYPE_IOAPIC_COMMON,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(IOAPICCommonState),
- .class_size = sizeof(IOAPICCommonClass),
- .class_init = ioapic_common_class_init,
- .abstract = true,
-};
-
-static void ioapic_common_register_types(void)
-{
- type_register_static(&ioapic_common_type);
-}
-
-type_init(ioapic_common_register_types)
diff --git a/qemu/hw/intc/lm32_pic.c b/qemu/hw/intc/lm32_pic.c
deleted file mode 100644
index edc08f184..000000000
--- a/qemu/hw/intc/lm32_pic.c
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * LatticeMico32 CPU interrupt controller logic.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-
-#include "hw/hw.h"
-#include "hw/i386/pc.h"
-#include "monitor/monitor.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "hw/lm32/lm32_pic.h"
-
-#define TYPE_LM32_PIC "lm32-pic"
-#define LM32_PIC(obj) OBJECT_CHECK(LM32PicState, (obj), TYPE_LM32_PIC)
-
-struct LM32PicState {
- SysBusDevice parent_obj;
-
- qemu_irq parent_irq;
- uint32_t im; /* interrupt mask */
- uint32_t ip; /* interrupt pending */
- uint32_t irq_state;
-
- /* statistics */
- uint32_t stats_irq_count[32];
-};
-typedef struct LM32PicState LM32PicState;
-
-static LM32PicState *pic;
-void lm32_hmp_info_pic(Monitor *mon, const QDict *qdict)
-{
- if (pic == NULL) {
- return;
- }
-
- monitor_printf(mon, "lm32-pic: im=%08x ip=%08x irq_state=%08x\n",
- pic->im, pic->ip, pic->irq_state);
-}
-
-void lm32_hmp_info_irq(Monitor *mon, const QDict *qdict)
-{
- int i;
- uint32_t count;
-
- if (pic == NULL) {
- return;
- }
-
- monitor_printf(mon, "IRQ statistics:\n");
- for (i = 0; i < 32; i++) {
- count = pic->stats_irq_count[i];
- if (count > 0) {
- monitor_printf(mon, "%2d: %u\n", i, count);
- }
- }
-}
-
-static void update_irq(LM32PicState *s)
-{
- s->ip |= s->irq_state;
-
- if (s->ip & s->im) {
- trace_lm32_pic_raise_irq();
- qemu_irq_raise(s->parent_irq);
- } else {
- trace_lm32_pic_lower_irq();
- qemu_irq_lower(s->parent_irq);
- }
-}
-
-static void irq_handler(void *opaque, int irq, int level)
-{
- LM32PicState *s = opaque;
-
- assert(irq < 32);
- trace_lm32_pic_interrupt(irq, level);
-
- if (level) {
- s->irq_state |= (1 << irq);
- s->stats_irq_count[irq]++;
- } else {
- s->irq_state &= ~(1 << irq);
- }
-
- update_irq(s);
-}
-
-void lm32_pic_set_im(DeviceState *d, uint32_t im)
-{
- LM32PicState *s = LM32_PIC(d);
-
- trace_lm32_pic_set_im(im);
- s->im = im;
-
- update_irq(s);
-}
-
-void lm32_pic_set_ip(DeviceState *d, uint32_t ip)
-{
- LM32PicState *s = LM32_PIC(d);
-
- trace_lm32_pic_set_ip(ip);
-
- /* ack interrupt */
- s->ip &= ~ip;
-
- update_irq(s);
-}
-
-uint32_t lm32_pic_get_im(DeviceState *d)
-{
- LM32PicState *s = LM32_PIC(d);
-
- trace_lm32_pic_get_im(s->im);
- return s->im;
-}
-
-uint32_t lm32_pic_get_ip(DeviceState *d)
-{
- LM32PicState *s = LM32_PIC(d);
-
- trace_lm32_pic_get_ip(s->ip);
- return s->ip;
-}
-
-static void pic_reset(DeviceState *d)
-{
- LM32PicState *s = LM32_PIC(d);
- int i;
-
- s->im = 0;
- s->ip = 0;
- s->irq_state = 0;
- for (i = 0; i < 32; i++) {
- s->stats_irq_count[i] = 0;
- }
-}
-
-static int lm32_pic_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- LM32PicState *s = LM32_PIC(dev);
-
- qdev_init_gpio_in(dev, irq_handler, 32);
- sysbus_init_irq(sbd, &s->parent_irq);
-
- pic = s;
-
- return 0;
-}
-
-static const VMStateDescription vmstate_lm32_pic = {
- .name = "lm32-pic",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(im, LM32PicState),
- VMSTATE_UINT32(ip, LM32PicState),
- VMSTATE_UINT32(irq_state, LM32PicState),
- VMSTATE_UINT32_ARRAY(stats_irq_count, LM32PicState, 32),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void lm32_pic_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = lm32_pic_init;
- dc->reset = pic_reset;
- dc->vmsd = &vmstate_lm32_pic;
-}
-
-static const TypeInfo lm32_pic_info = {
- .name = TYPE_LM32_PIC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(LM32PicState),
- .class_init = lm32_pic_class_init,
-};
-
-static void lm32_pic_register_types(void)
-{
- type_register_static(&lm32_pic_info);
-}
-
-type_init(lm32_pic_register_types)
diff --git a/qemu/hw/intc/omap_intc.c b/qemu/hw/intc/omap_intc.c
deleted file mode 100644
index 336882510..000000000
--- a/qemu/hw/intc/omap_intc.c
+++ /dev/null
@@ -1,672 +0,0 @@
-/*
- * TI OMAP interrupt controller emulation.
- *
- * Copyright (C) 2006-2008 Andrzej Zaborowski <balrog@zabor.org>
- * Copyright (C) 2007-2008 Nokia Corporation
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/arm/omap.h"
-#include "hw/sysbus.h"
-#include "qemu/error-report.h"
-
-/* Interrupt Handlers */
-struct omap_intr_handler_bank_s {
- uint32_t irqs;
- uint32_t inputs;
- uint32_t mask;
- uint32_t fiq;
- uint32_t sens_edge;
- uint32_t swi;
- unsigned char priority[32];
-};
-
-#define TYPE_OMAP_INTC "common-omap-intc"
-#define OMAP_INTC(obj) \
- OBJECT_CHECK(struct omap_intr_handler_s, (obj), TYPE_OMAP_INTC)
-
-struct omap_intr_handler_s {
- SysBusDevice parent_obj;
-
- qemu_irq *pins;
- qemu_irq parent_intr[2];
- MemoryRegion mmio;
- void *iclk;
- void *fclk;
- unsigned char nbanks;
- int level_only;
- uint32_t size;
-
- uint8_t revision;
-
- /* state */
- uint32_t new_agr[2];
- int sir_intr[2];
- int autoidle;
- uint32_t mask;
- struct omap_intr_handler_bank_s bank[3];
-};
-
-static void omap_inth_sir_update(struct omap_intr_handler_s *s, int is_fiq)
-{
- int i, j, sir_intr, p_intr, p;
- uint32_t level;
- sir_intr = 0;
- p_intr = 255;
-
- /* Find the interrupt line with the highest dynamic priority.
- * Note: 0 denotes the hightest priority.
- * If all interrupts have the same priority, the default order is IRQ_N,
- * IRQ_N-1,...,IRQ_0. */
- for (j = 0; j < s->nbanks; ++j) {
- level = s->bank[j].irqs & ~s->bank[j].mask &
- (is_fiq ? s->bank[j].fiq : ~s->bank[j].fiq);
-
- while (level != 0) {
- i = ctz32(level);
- p = s->bank[j].priority[i];
- if (p <= p_intr) {
- p_intr = p;
- sir_intr = 32 * j + i;
- }
- level &= level - 1;
- }
- }
- s->sir_intr[is_fiq] = sir_intr;
-}
-
-static inline void omap_inth_update(struct omap_intr_handler_s *s, int is_fiq)
-{
- int i;
- uint32_t has_intr = 0;
-
- for (i = 0; i < s->nbanks; ++i)
- has_intr |= s->bank[i].irqs & ~s->bank[i].mask &
- (is_fiq ? s->bank[i].fiq : ~s->bank[i].fiq);
-
- if (s->new_agr[is_fiq] & has_intr & s->mask) {
- s->new_agr[is_fiq] = 0;
- omap_inth_sir_update(s, is_fiq);
- qemu_set_irq(s->parent_intr[is_fiq], 1);
- }
-}
-
-#define INT_FALLING_EDGE 0
-#define INT_LOW_LEVEL 1
-
-static void omap_set_intr(void *opaque, int irq, int req)
-{
- struct omap_intr_handler_s *ih = (struct omap_intr_handler_s *) opaque;
- uint32_t rise;
-
- struct omap_intr_handler_bank_s *bank = &ih->bank[irq >> 5];
- int n = irq & 31;
-
- if (req) {
- rise = ~bank->irqs & (1 << n);
- if (~bank->sens_edge & (1 << n))
- rise &= ~bank->inputs;
-
- bank->inputs |= (1 << n);
- if (rise) {
- bank->irqs |= rise;
- omap_inth_update(ih, 0);
- omap_inth_update(ih, 1);
- }
- } else {
- rise = bank->sens_edge & bank->irqs & (1 << n);
- bank->irqs &= ~rise;
- bank->inputs &= ~(1 << n);
- }
-}
-
-/* Simplified version with no edge detection */
-static void omap_set_intr_noedge(void *opaque, int irq, int req)
-{
- struct omap_intr_handler_s *ih = (struct omap_intr_handler_s *) opaque;
- uint32_t rise;
-
- struct omap_intr_handler_bank_s *bank = &ih->bank[irq >> 5];
- int n = irq & 31;
-
- if (req) {
- rise = ~bank->inputs & (1 << n);
- if (rise) {
- bank->irqs |= bank->inputs |= rise;
- omap_inth_update(ih, 0);
- omap_inth_update(ih, 1);
- }
- } else
- bank->irqs = (bank->inputs &= ~(1 << n)) | bank->swi;
-}
-
-static uint64_t omap_inth_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
- int i, offset = addr;
- int bank_no = offset >> 8;
- int line_no;
- struct omap_intr_handler_bank_s *bank = &s->bank[bank_no];
- offset &= 0xff;
-
- switch (offset) {
- case 0x00: /* ITR */
- return bank->irqs;
-
- case 0x04: /* MIR */
- return bank->mask;
-
- case 0x10: /* SIR_IRQ_CODE */
- case 0x14: /* SIR_FIQ_CODE */
- if (bank_no != 0)
- break;
- line_no = s->sir_intr[(offset - 0x10) >> 2];
- bank = &s->bank[line_no >> 5];
- i = line_no & 31;
- if (((bank->sens_edge >> i) & 1) == INT_FALLING_EDGE)
- bank->irqs &= ~(1 << i);
- return line_no;
-
- case 0x18: /* CONTROL_REG */
- if (bank_no != 0)
- break;
- return 0;
-
- case 0x1c: /* ILR0 */
- case 0x20: /* ILR1 */
- case 0x24: /* ILR2 */
- case 0x28: /* ILR3 */
- case 0x2c: /* ILR4 */
- case 0x30: /* ILR5 */
- case 0x34: /* ILR6 */
- case 0x38: /* ILR7 */
- case 0x3c: /* ILR8 */
- case 0x40: /* ILR9 */
- case 0x44: /* ILR10 */
- case 0x48: /* ILR11 */
- case 0x4c: /* ILR12 */
- case 0x50: /* ILR13 */
- case 0x54: /* ILR14 */
- case 0x58: /* ILR15 */
- case 0x5c: /* ILR16 */
- case 0x60: /* ILR17 */
- case 0x64: /* ILR18 */
- case 0x68: /* ILR19 */
- case 0x6c: /* ILR20 */
- case 0x70: /* ILR21 */
- case 0x74: /* ILR22 */
- case 0x78: /* ILR23 */
- case 0x7c: /* ILR24 */
- case 0x80: /* ILR25 */
- case 0x84: /* ILR26 */
- case 0x88: /* ILR27 */
- case 0x8c: /* ILR28 */
- case 0x90: /* ILR29 */
- case 0x94: /* ILR30 */
- case 0x98: /* ILR31 */
- i = (offset - 0x1c) >> 2;
- return (bank->priority[i] << 2) |
- (((bank->sens_edge >> i) & 1) << 1) |
- ((bank->fiq >> i) & 1);
-
- case 0x9c: /* ISR */
- return 0x00000000;
-
- }
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_inth_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
- int i, offset = addr;
- int bank_no = offset >> 8;
- struct omap_intr_handler_bank_s *bank = &s->bank[bank_no];
- offset &= 0xff;
-
- switch (offset) {
- case 0x00: /* ITR */
- /* Important: ignore the clearing if the IRQ is level-triggered and
- the input bit is 1 */
- bank->irqs &= value | (bank->inputs & bank->sens_edge);
- return;
-
- case 0x04: /* MIR */
- bank->mask = value;
- omap_inth_update(s, 0);
- omap_inth_update(s, 1);
- return;
-
- case 0x10: /* SIR_IRQ_CODE */
- case 0x14: /* SIR_FIQ_CODE */
- OMAP_RO_REG(addr);
- break;
-
- case 0x18: /* CONTROL_REG */
- if (bank_no != 0)
- break;
- if (value & 2) {
- qemu_set_irq(s->parent_intr[1], 0);
- s->new_agr[1] = ~0;
- omap_inth_update(s, 1);
- }
- if (value & 1) {
- qemu_set_irq(s->parent_intr[0], 0);
- s->new_agr[0] = ~0;
- omap_inth_update(s, 0);
- }
- return;
-
- case 0x1c: /* ILR0 */
- case 0x20: /* ILR1 */
- case 0x24: /* ILR2 */
- case 0x28: /* ILR3 */
- case 0x2c: /* ILR4 */
- case 0x30: /* ILR5 */
- case 0x34: /* ILR6 */
- case 0x38: /* ILR7 */
- case 0x3c: /* ILR8 */
- case 0x40: /* ILR9 */
- case 0x44: /* ILR10 */
- case 0x48: /* ILR11 */
- case 0x4c: /* ILR12 */
- case 0x50: /* ILR13 */
- case 0x54: /* ILR14 */
- case 0x58: /* ILR15 */
- case 0x5c: /* ILR16 */
- case 0x60: /* ILR17 */
- case 0x64: /* ILR18 */
- case 0x68: /* ILR19 */
- case 0x6c: /* ILR20 */
- case 0x70: /* ILR21 */
- case 0x74: /* ILR22 */
- case 0x78: /* ILR23 */
- case 0x7c: /* ILR24 */
- case 0x80: /* ILR25 */
- case 0x84: /* ILR26 */
- case 0x88: /* ILR27 */
- case 0x8c: /* ILR28 */
- case 0x90: /* ILR29 */
- case 0x94: /* ILR30 */
- case 0x98: /* ILR31 */
- i = (offset - 0x1c) >> 2;
- bank->priority[i] = (value >> 2) & 0x1f;
- bank->sens_edge &= ~(1 << i);
- bank->sens_edge |= ((value >> 1) & 1) << i;
- bank->fiq &= ~(1 << i);
- bank->fiq |= (value & 1) << i;
- return;
-
- case 0x9c: /* ISR */
- for (i = 0; i < 32; i ++)
- if (value & (1 << i)) {
- omap_set_intr(s, 32 * bank_no + i, 1);
- return;
- }
- return;
- }
- OMAP_BAD_REG(addr);
-}
-
-static const MemoryRegionOps omap_inth_mem_ops = {
- .read = omap_inth_read,
- .write = omap_inth_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static void omap_inth_reset(DeviceState *dev)
-{
- struct omap_intr_handler_s *s = OMAP_INTC(dev);
- int i;
-
- for (i = 0; i < s->nbanks; ++i){
- s->bank[i].irqs = 0x00000000;
- s->bank[i].mask = 0xffffffff;
- s->bank[i].sens_edge = 0x00000000;
- s->bank[i].fiq = 0x00000000;
- s->bank[i].inputs = 0x00000000;
- s->bank[i].swi = 0x00000000;
- memset(s->bank[i].priority, 0, sizeof(s->bank[i].priority));
-
- if (s->level_only)
- s->bank[i].sens_edge = 0xffffffff;
- }
-
- s->new_agr[0] = ~0;
- s->new_agr[1] = ~0;
- s->sir_intr[0] = 0;
- s->sir_intr[1] = 0;
- s->autoidle = 0;
- s->mask = ~0;
-
- qemu_set_irq(s->parent_intr[0], 0);
- qemu_set_irq(s->parent_intr[1], 0);
-}
-
-static int omap_intc_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- struct omap_intr_handler_s *s = OMAP_INTC(dev);
-
- if (!s->iclk) {
- error_report("omap-intc: clk not connected");
- return -1;
- }
- s->nbanks = 1;
- sysbus_init_irq(sbd, &s->parent_intr[0]);
- sysbus_init_irq(sbd, &s->parent_intr[1]);
- qdev_init_gpio_in(dev, omap_set_intr, s->nbanks * 32);
- memory_region_init_io(&s->mmio, OBJECT(s), &omap_inth_mem_ops, s,
- "omap-intc", s->size);
- sysbus_init_mmio(sbd, &s->mmio);
- return 0;
-}
-
-static Property omap_intc_properties[] = {
- DEFINE_PROP_UINT32("size", struct omap_intr_handler_s, size, 0x100),
- DEFINE_PROP_PTR("clk", struct omap_intr_handler_s, iclk),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void omap_intc_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = omap_intc_init;
- dc->reset = omap_inth_reset;
- dc->props = omap_intc_properties;
- /* Reason: pointer property "clk" */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo omap_intc_info = {
- .name = "omap-intc",
- .parent = TYPE_OMAP_INTC,
- .class_init = omap_intc_class_init,
-};
-
-static uint64_t omap2_inth_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
- int offset = addr;
- int bank_no, line_no;
- struct omap_intr_handler_bank_s *bank = NULL;
-
- if ((offset & 0xf80) == 0x80) {
- bank_no = (offset & 0x60) >> 5;
- if (bank_no < s->nbanks) {
- offset &= ~0x60;
- bank = &s->bank[bank_no];
- } else {
- OMAP_BAD_REG(addr);
- return 0;
- }
- }
-
- switch (offset) {
- case 0x00: /* INTC_REVISION */
- return s->revision;
-
- case 0x10: /* INTC_SYSCONFIG */
- return (s->autoidle >> 2) & 1;
-
- case 0x14: /* INTC_SYSSTATUS */
- return 1; /* RESETDONE */
-
- case 0x40: /* INTC_SIR_IRQ */
- return s->sir_intr[0];
-
- case 0x44: /* INTC_SIR_FIQ */
- return s->sir_intr[1];
-
- case 0x48: /* INTC_CONTROL */
- return (!s->mask) << 2; /* GLOBALMASK */
-
- case 0x4c: /* INTC_PROTECTION */
- return 0;
-
- case 0x50: /* INTC_IDLE */
- return s->autoidle & 3;
-
- /* Per-bank registers */
- case 0x80: /* INTC_ITR */
- return bank->inputs;
-
- case 0x84: /* INTC_MIR */
- return bank->mask;
-
- case 0x88: /* INTC_MIR_CLEAR */
- case 0x8c: /* INTC_MIR_SET */
- return 0;
-
- case 0x90: /* INTC_ISR_SET */
- return bank->swi;
-
- case 0x94: /* INTC_ISR_CLEAR */
- return 0;
-
- case 0x98: /* INTC_PENDING_IRQ */
- return bank->irqs & ~bank->mask & ~bank->fiq;
-
- case 0x9c: /* INTC_PENDING_FIQ */
- return bank->irqs & ~bank->mask & bank->fiq;
-
- /* Per-line registers */
- case 0x100 ... 0x300: /* INTC_ILR */
- bank_no = (offset - 0x100) >> 7;
- if (bank_no > s->nbanks)
- break;
- bank = &s->bank[bank_no];
- line_no = (offset & 0x7f) >> 2;
- return (bank->priority[line_no] << 2) |
- ((bank->fiq >> line_no) & 1);
- }
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap2_inth_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
- int offset = addr;
- int bank_no, line_no;
- struct omap_intr_handler_bank_s *bank = NULL;
-
- if ((offset & 0xf80) == 0x80) {
- bank_no = (offset & 0x60) >> 5;
- if (bank_no < s->nbanks) {
- offset &= ~0x60;
- bank = &s->bank[bank_no];
- } else {
- OMAP_BAD_REG(addr);
- return;
- }
- }
-
- switch (offset) {
- case 0x10: /* INTC_SYSCONFIG */
- s->autoidle &= 4;
- s->autoidle |= (value & 1) << 2;
- if (value & 2) { /* SOFTRESET */
- omap_inth_reset(DEVICE(s));
- }
- return;
-
- case 0x48: /* INTC_CONTROL */
- s->mask = (value & 4) ? 0 : ~0; /* GLOBALMASK */
- if (value & 2) { /* NEWFIQAGR */
- qemu_set_irq(s->parent_intr[1], 0);
- s->new_agr[1] = ~0;
- omap_inth_update(s, 1);
- }
- if (value & 1) { /* NEWIRQAGR */
- qemu_set_irq(s->parent_intr[0], 0);
- s->new_agr[0] = ~0;
- omap_inth_update(s, 0);
- }
- return;
-
- case 0x4c: /* INTC_PROTECTION */
- /* TODO: Make a bitmap (or sizeof(char)map) of access privileges
- * for every register, see Chapter 3 and 4 for privileged mode. */
- if (value & 1)
- fprintf(stderr, "%s: protection mode enable attempt\n",
- __FUNCTION__);
- return;
-
- case 0x50: /* INTC_IDLE */
- s->autoidle &= ~3;
- s->autoidle |= value & 3;
- return;
-
- /* Per-bank registers */
- case 0x84: /* INTC_MIR */
- bank->mask = value;
- omap_inth_update(s, 0);
- omap_inth_update(s, 1);
- return;
-
- case 0x88: /* INTC_MIR_CLEAR */
- bank->mask &= ~value;
- omap_inth_update(s, 0);
- omap_inth_update(s, 1);
- return;
-
- case 0x8c: /* INTC_MIR_SET */
- bank->mask |= value;
- return;
-
- case 0x90: /* INTC_ISR_SET */
- bank->irqs |= bank->swi |= value;
- omap_inth_update(s, 0);
- omap_inth_update(s, 1);
- return;
-
- case 0x94: /* INTC_ISR_CLEAR */
- bank->swi &= ~value;
- bank->irqs = bank->swi & bank->inputs;
- return;
-
- /* Per-line registers */
- case 0x100 ... 0x300: /* INTC_ILR */
- bank_no = (offset - 0x100) >> 7;
- if (bank_no > s->nbanks)
- break;
- bank = &s->bank[bank_no];
- line_no = (offset & 0x7f) >> 2;
- bank->priority[line_no] = (value >> 2) & 0x3f;
- bank->fiq &= ~(1 << line_no);
- bank->fiq |= (value & 1) << line_no;
- return;
-
- case 0x00: /* INTC_REVISION */
- case 0x14: /* INTC_SYSSTATUS */
- case 0x40: /* INTC_SIR_IRQ */
- case 0x44: /* INTC_SIR_FIQ */
- case 0x80: /* INTC_ITR */
- case 0x98: /* INTC_PENDING_IRQ */
- case 0x9c: /* INTC_PENDING_FIQ */
- OMAP_RO_REG(addr);
- return;
- }
- OMAP_BAD_REG(addr);
-}
-
-static const MemoryRegionOps omap2_inth_mem_ops = {
- .read = omap2_inth_read,
- .write = omap2_inth_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static int omap2_intc_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- struct omap_intr_handler_s *s = OMAP_INTC(dev);
-
- if (!s->iclk) {
- error_report("omap2-intc: iclk not connected");
- return -1;
- }
- if (!s->fclk) {
- error_report("omap2-intc: fclk not connected");
- return -1;
- }
- s->level_only = 1;
- s->nbanks = 3;
- sysbus_init_irq(sbd, &s->parent_intr[0]);
- sysbus_init_irq(sbd, &s->parent_intr[1]);
- qdev_init_gpio_in(dev, omap_set_intr_noedge, s->nbanks * 32);
- memory_region_init_io(&s->mmio, OBJECT(s), &omap2_inth_mem_ops, s,
- "omap2-intc", 0x1000);
- sysbus_init_mmio(sbd, &s->mmio);
- return 0;
-}
-
-static Property omap2_intc_properties[] = {
- DEFINE_PROP_UINT8("revision", struct omap_intr_handler_s,
- revision, 0x21),
- DEFINE_PROP_PTR("iclk", struct omap_intr_handler_s, iclk),
- DEFINE_PROP_PTR("fclk", struct omap_intr_handler_s, fclk),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void omap2_intc_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = omap2_intc_init;
- dc->reset = omap_inth_reset;
- dc->props = omap2_intc_properties;
- /* Reason: pointer property "iclk", "fclk" */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo omap2_intc_info = {
- .name = "omap2-intc",
- .parent = TYPE_OMAP_INTC,
- .class_init = omap2_intc_class_init,
-};
-
-static const TypeInfo omap_intc_type_info = {
- .name = TYPE_OMAP_INTC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(struct omap_intr_handler_s),
- .abstract = true,
-};
-
-static void omap_intc_register_types(void)
-{
- type_register_static(&omap_intc_type_info);
- type_register_static(&omap_intc_info);
- type_register_static(&omap2_intc_info);
-}
-
-type_init(omap_intc_register_types)
diff --git a/qemu/hw/intc/openpic.c b/qemu/hw/intc/openpic.c
deleted file mode 100644
index 2d3769310..000000000
--- a/qemu/hw/intc/openpic.c
+++ /dev/null
@@ -1,1664 +0,0 @@
-/*
- * OpenPIC emulation
- *
- * Copyright (c) 2004 Jocelyn Mayer
- * 2011 Alexander Graf
- *
- * 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.
- */
-/*
- *
- * Based on OpenPic implementations:
- * - Intel GW80314 I/O companion chip developer's manual
- * - Motorola MPC8245 & MPC8540 user manuals.
- * - Motorola MCP750 (aka Raven) programmer manual.
- * - Motorola Harrier programmer manuel
- *
- * Serial interrupts, as implemented in Raven chipset are not supported yet.
- *
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/ppc/mac.h"
-#include "hw/pci/pci.h"
-#include "hw/ppc/openpic.h"
-#include "hw/ppc/ppc_e500.h"
-#include "hw/sysbus.h"
-#include "hw/pci/msi.h"
-#include "qapi/error.h"
-#include "qemu/bitops.h"
-#include "qapi/qmp/qerror.h"
-
-//#define DEBUG_OPENPIC
-
-#ifdef DEBUG_OPENPIC
-static const int debug_openpic = 1;
-#else
-static const int debug_openpic = 0;
-#endif
-
-#define DPRINTF(fmt, ...) do { \
- if (debug_openpic) { \
- printf(fmt , ## __VA_ARGS__); \
- } \
- } while (0)
-
-#define MAX_CPU 32
-#define MAX_MSI 8
-#define VID 0x03 /* MPIC version ID */
-
-/* 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
-#define OPENPIC_GLB_REG_SIZE 0x10F0
-#define OPENPIC_TMR_REG_START 0x10F0
-#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 (OPENPIC_MAX_SRC * 0x20)
-#define OPENPIC_CPU_REG_START 0x20000
-#define OPENPIC_CPU_REG_SIZE 0x100 + ((MAX_CPU - 1) * 0x1000)
-
-/* Raven */
-#define RAVEN_MAX_CPU 2
-#define RAVEN_MAX_EXT 48
-#define RAVEN_MAX_IRQ 64
-#define RAVEN_MAX_TMR OPENPIC_MAX_TMR
-#define RAVEN_MAX_IPI OPENPIC_MAX_IPI
-
-/* Interrupt definitions */
-#define RAVEN_FE_IRQ (RAVEN_MAX_EXT) /* Internal functional IRQ */
-#define RAVEN_ERR_IRQ (RAVEN_MAX_EXT + 1) /* Error IRQ */
-#define RAVEN_TMR_IRQ (RAVEN_MAX_EXT + 2) /* First timer IRQ */
-#define RAVEN_IPI_IRQ (RAVEN_TMR_IRQ + RAVEN_MAX_TMR) /* First IPI IRQ */
-/* First doorbell IRQ */
-#define RAVEN_DBL_IRQ (RAVEN_IPI_IRQ + (RAVEN_MAX_CPU * RAVEN_MAX_IPI))
-
-typedef struct FslMpicInfo {
- int max_ext;
-} FslMpicInfo;
-
-static FslMpicInfo fsl_mpic_20 = {
- .max_ext = 12,
-};
-
-static FslMpicInfo fsl_mpic_42 = {
- .max_ext = 12,
-};
-
-#define FRR_NIRQ_SHIFT 16
-#define FRR_NCPU_SHIFT 8
-#define FRR_VID_SHIFT 0
-
-#define VID_REVISION_1_2 2
-#define VID_REVISION_1_3 3
-
-#define VIR_GENERIC 0x00000000 /* Generic Vendor ID */
-
-#define GCR_RESET 0x80000000
-#define GCR_MODE_PASS 0x00000000
-#define GCR_MODE_MIXED 0x20000000
-#define GCR_MODE_PROXY 0x60000000
-
-#define TBCR_CI 0x80000000 /* count inhibit */
-#define TCCR_TOG 0x80000000 /* toggles when decrement to zero */
-
-#define IDR_EP_SHIFT 31
-#define IDR_EP_MASK (1U << IDR_EP_SHIFT)
-#define IDR_CI0_SHIFT 30
-#define IDR_CI1_SHIFT 29
-#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)
-#define MSIIR_IBS_SHIFT 24
-#define MSIIR_IBS_MASK (0x1f << MSIIR_IBS_SHIFT)
-
-static int get_current_cpu(void)
-{
- if (!current_cpu) {
- return -1;
- }
-
- return current_cpu->cpu_index;
-}
-
-static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr,
- int idx);
-static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
- uint32_t val, int idx);
-static void openpic_reset(DeviceState *d);
-
-typedef enum IRQType {
- IRQ_TYPE_NORMAL = 0,
- IRQ_TYPE_FSLINT, /* FSL internal interrupt -- level only */
- IRQ_TYPE_FSLSPECIAL, /* FSL timer/IPI interrupt, edge, no polarity */
-} IRQType;
-
-/* Round up to the nearest 64 IRQs so that the queue length
- * won't change when moving between 32 and 64 bit hosts.
- */
-#define IRQQUEUE_SIZE_BITS ((OPENPIC_MAX_IRQ + 63) & ~63)
-
-typedef struct IRQQueue {
- unsigned long *queue;
- int32_t queue_size; /* Only used for VMSTATE_BITMAP */
- int next;
- int priority;
-} IRQQueue;
-
-typedef struct IRQSource {
- uint32_t ivpr; /* IRQ vector/priority register */
- uint32_t idr; /* IRQ destination register */
- uint32_t destmask; /* bitmap of CPU destinations */
- int last_cpu;
- int output; /* IRQ level, e.g. OPENPIC_OUTPUT_INT */
- int pending; /* TRUE if IRQ is pending */
- IRQType type;
- bool level:1; /* level-triggered */
- bool nomask:1; /* critical interrupts ignore mask on some FSL MPICs */
-} IRQSource;
-
-#define IVPR_MASK_SHIFT 31
-#define IVPR_MASK_MASK (1U << IVPR_MASK_SHIFT)
-#define IVPR_ACTIVITY_SHIFT 30
-#define IVPR_ACTIVITY_MASK (1U << IVPR_ACTIVITY_SHIFT)
-#define IVPR_MODE_SHIFT 29
-#define IVPR_MODE_MASK (1U << IVPR_MODE_SHIFT)
-#define IVPR_POLARITY_SHIFT 23
-#define IVPR_POLARITY_MASK (1U << IVPR_POLARITY_SHIFT)
-#define IVPR_SENSE_SHIFT 22
-#define IVPR_SENSE_MASK (1U << IVPR_SENSE_SHIFT)
-
-#define IVPR_PRIORITY_MASK (0xFU << 16)
-#define IVPR_PRIORITY(_ivprr_) ((int)(((_ivprr_) & IVPR_PRIORITY_MASK) >> 16))
-#define IVPR_VECTOR(opp, _ivprr_) ((_ivprr_) & (opp)->vector_mask)
-
-/* IDR[EP/CI] are only for FSL MPIC prior to v4.0 */
-#define IDR_EP 0x80000000 /* external pin */
-#define IDR_CI 0x40000000 /* critical interrupt */
-
-typedef struct OpenPICTimer {
- uint32_t tccr; /* Global timer current count register */
- uint32_t tbcr; /* Global timer base count register */
-} OpenPICTimer;
-
-typedef struct OpenPICMSI {
- uint32_t msir; /* Shared Message Signaled Interrupt Register */
-} OpenPICMSI;
-
-typedef struct IRQDest {
- int32_t ctpr; /* CPU current task priority */
- IRQQueue raised;
- IRQQueue servicing;
- qemu_irq *irqs;
-
- /* Count of IRQ sources asserting on non-INT outputs */
- uint32_t outputs_active[OPENPIC_OUTPUT_NB];
-} IRQDest;
-
-#define OPENPIC(obj) OBJECT_CHECK(OpenPICState, (obj), TYPE_OPENPIC)
-
-typedef struct OpenPICState {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- MemoryRegion mem;
-
- /* Behavior control */
- FslMpicInfo *fsl;
- uint32_t model;
- uint32_t flags;
- uint32_t nb_irqs;
- uint32_t vid;
- uint32_t vir; /* Vendor identification register */
- uint32_t vector_mask;
- uint32_t tfrr_reset;
- uint32_t ivpr_reset;
- uint32_t idr_reset;
- uint32_t brr1;
- uint32_t mpic_mode_mask;
-
- /* Sub-regions */
- MemoryRegion sub_io_mem[6];
-
- /* Global registers */
- uint32_t frr; /* Feature reporting register */
- uint32_t gcr; /* Global configuration register */
- uint32_t pir; /* Processor initialization register */
- uint32_t spve; /* Spurious vector register */
- uint32_t tfrr; /* Timer frequency reporting register */
- /* Source registers */
- IRQSource src[OPENPIC_MAX_IRQ];
- /* Local registers per output pin */
- IRQDest dst[MAX_CPU];
- uint32_t nb_cpus;
- /* Timer registers */
- OpenPICTimer timers[OPENPIC_MAX_TMR];
- /* Shared MSI registers */
- OpenPICMSI msi[MAX_MSI];
- uint32_t max_irq;
- uint32_t irq_ipi0;
- uint32_t irq_tim0;
- uint32_t irq_msi;
-} OpenPICState;
-
-static inline void IRQ_setbit(IRQQueue *q, int n_IRQ)
-{
- set_bit(n_IRQ, q->queue);
-}
-
-static inline void IRQ_resetbit(IRQQueue *q, int n_IRQ)
-{
- clear_bit(n_IRQ, q->queue);
-}
-
-static void IRQ_check(OpenPICState *opp, IRQQueue *q)
-{
- int irq = -1;
- int next = -1;
- int priority = -1;
-
- for (;;) {
- irq = find_next_bit(q->queue, opp->max_irq, irq + 1);
- if (irq == opp->max_irq) {
- break;
- }
-
- DPRINTF("IRQ_check: irq %d set ivpr_pr=%d pr=%d\n",
- irq, IVPR_PRIORITY(opp->src[irq].ivpr), priority);
-
- if (IVPR_PRIORITY(opp->src[irq].ivpr) > priority) {
- next = irq;
- priority = IVPR_PRIORITY(opp->src[irq].ivpr);
- }
- }
-
- q->next = next;
- q->priority = priority;
-}
-
-static int IRQ_get_next(OpenPICState *opp, IRQQueue *q)
-{
- /* XXX: optimize */
- IRQ_check(opp, q);
-
- return q->next;
-}
-
-static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ,
- bool active, bool was_active)
-{
- IRQDest *dst;
- IRQSource *src;
- int priority;
-
- dst = &opp->dst[n_CPU];
- src = &opp->src[n_IRQ];
-
- DPRINTF("%s: IRQ %d active %d was %d\n",
- __func__, n_IRQ, active, was_active);
-
- if (src->output != OPENPIC_OUTPUT_INT) {
- DPRINTF("%s: output %d irq %d active %d was %d count %d\n",
- __func__, src->output, n_IRQ, active, was_active,
- dst->outputs_active[src->output]);
-
- /* On Freescale MPIC, critical interrupts ignore priority,
- * IACK, EOI, etc. Before MPIC v4.1 they also ignore
- * masking.
- */
- if (active) {
- if (!was_active && dst->outputs_active[src->output]++ == 0) {
- DPRINTF("%s: Raise OpenPIC output %d cpu %d irq %d\n",
- __func__, src->output, n_CPU, n_IRQ);
- qemu_irq_raise(dst->irqs[src->output]);
- }
- } else {
- if (was_active && --dst->outputs_active[src->output] == 0) {
- DPRINTF("%s: Lower OpenPIC output %d cpu %d irq %d\n",
- __func__, src->output, n_CPU, n_IRQ);
- qemu_irq_lower(dst->irqs[src->output]);
- }
- }
-
- return;
- }
-
- priority = IVPR_PRIORITY(src->ivpr);
-
- /* Even if the interrupt doesn't have enough priority,
- * it is still raised, in case ctpr is lowered later.
- */
- if (active) {
- IRQ_setbit(&dst->raised, n_IRQ);
- } else {
- IRQ_resetbit(&dst->raised, n_IRQ);
- }
-
- IRQ_check(opp, &dst->raised);
-
- if (active && priority <= dst->ctpr) {
- DPRINTF("%s: IRQ %d priority %d too low for ctpr %d on CPU %d\n",
- __func__, n_IRQ, priority, dst->ctpr, n_CPU);
- active = 0;
- }
-
- if (active) {
- if (IRQ_get_next(opp, &dst->servicing) >= 0 &&
- priority <= dst->servicing.priority) {
- DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n",
- __func__, n_IRQ, dst->servicing.next, n_CPU);
- } else {
- DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d/%d\n",
- __func__, n_CPU, n_IRQ, dst->raised.next);
- qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
- }
- } else {
- IRQ_get_next(opp, &dst->servicing);
- if (dst->raised.priority > dst->ctpr &&
- dst->raised.priority > dst->servicing.priority) {
- DPRINTF("%s: IRQ %d inactive, IRQ %d prio %d above %d/%d, CPU %d\n",
- __func__, n_IRQ, dst->raised.next, dst->raised.priority,
- dst->ctpr, dst->servicing.priority, n_CPU);
- /* IRQ line stays asserted */
- } else {
- DPRINTF("%s: IRQ %d inactive, current prio %d/%d, CPU %d\n",
- __func__, n_IRQ, dst->ctpr, dst->servicing.priority, n_CPU);
- qemu_irq_lower(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
- }
- }
-}
-
-/* update pic state because registers for n_IRQ have changed value */
-static void openpic_update_irq(OpenPICState *opp, int n_IRQ)
-{
- IRQSource *src;
- bool active, was_active;
- int i;
-
- src = &opp->src[n_IRQ];
- active = src->pending;
-
- if ((src->ivpr & IVPR_MASK_MASK) && !src->nomask) {
- /* Interrupt source is disabled */
- DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ);
- active = false;
- }
-
- was_active = !!(src->ivpr & IVPR_ACTIVITY_MASK);
-
- /*
- * We don't have a similar check for already-active because
- * ctpr may have changed and we need to withdraw the interrupt.
- */
- if (!active && !was_active) {
- DPRINTF("%s: IRQ %d is already inactive\n", __func__, n_IRQ);
- return;
- }
-
- if (active) {
- src->ivpr |= IVPR_ACTIVITY_MASK;
- } else {
- src->ivpr &= ~IVPR_ACTIVITY_MASK;
- }
-
- if (src->destmask == 0) {
- /* No target */
- DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ);
- return;
- }
-
- 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)) {
- /* Directed delivery mode */
- for (i = 0; i < opp->nb_cpus; i++) {
- if (src->destmask & (1 << i)) {
- IRQ_local_pipe(opp, i, n_IRQ, active, was_active);
- }
- }
- } else {
- /* Distributed delivery mode */
- for (i = src->last_cpu + 1; i != src->last_cpu; i++) {
- if (i == opp->nb_cpus) {
- i = 0;
- }
- if (src->destmask & (1 << i)) {
- IRQ_local_pipe(opp, i, n_IRQ, active, was_active);
- src->last_cpu = i;
- break;
- }
- }
- }
-}
-
-static void openpic_set_irq(void *opaque, int n_IRQ, int level)
-{
- OpenPICState *opp = opaque;
- IRQSource *src;
-
- if (n_IRQ >= OPENPIC_MAX_IRQ) {
- fprintf(stderr, "%s: IRQ %d out of range\n", __func__, n_IRQ);
- abort();
- }
-
- src = &opp->src[n_IRQ];
- DPRINTF("openpic: set irq %d = %d ivpr=0x%08x\n",
- n_IRQ, level, src->ivpr);
- if (src->level) {
- /* level-sensitive irq */
- src->pending = level;
- openpic_update_irq(opp, n_IRQ);
- } else {
- /* edge-sensitive irq */
- if (level) {
- src->pending = 1;
- openpic_update_irq(opp, n_IRQ);
- }
-
- if (src->output != OPENPIC_OUTPUT_INT) {
- /* Edge-triggered interrupts shouldn't be used
- * with non-INT delivery, but just in case,
- * try to make it do something sane rather than
- * cause an interrupt storm. This is close to
- * what you'd probably see happen in real hardware.
- */
- src->pending = 0;
- openpic_update_irq(opp, n_IRQ);
- }
- }
-}
-
-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;
-}
-
-static inline void write_IRQreg_idr(OpenPICState *opp, int n_IRQ, uint32_t val)
-{
- IRQSource *src = &opp->src[n_IRQ];
- uint32_t normal_mask = (1UL << opp->nb_cpus) - 1;
- uint32_t crit_mask = 0;
- uint32_t mask = normal_mask;
- int crit_shift = IDR_EP_SHIFT - opp->nb_cpus;
- int i;
-
- if (opp->flags & OPENPIC_FLAG_IDR_CRIT) {
- crit_mask = mask << crit_shift;
- mask |= crit_mask | IDR_EP;
- }
-
- src->idr = val & mask;
- DPRINTF("Set IDR %d to 0x%08x\n", n_IRQ, src->idr);
-
- if (opp->flags & OPENPIC_FLAG_IDR_CRIT) {
- if (src->idr & crit_mask) {
- if (src->idr & normal_mask) {
- DPRINTF("%s: IRQ configured for multiple output types, using "
- "critical\n", __func__);
- }
-
- src->output = OPENPIC_OUTPUT_CINT;
- src->nomask = true;
- src->destmask = 0;
-
- for (i = 0; i < opp->nb_cpus; i++) {
- int n_ci = IDR_CI0_SHIFT - i;
-
- if (src->idr & (1UL << n_ci)) {
- src->destmask |= 1UL << i;
- }
- }
- } else {
- src->output = OPENPIC_OUTPUT_INT;
- src->nomask = false;
- src->destmask = src->idr & normal_mask;
- }
- } else {
- src->destmask = src->idr;
- }
-}
-
-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;
-
- /* NOTE when implementing newer FSL MPIC models: starting with v4.0,
- * the polarity bit is read-only on internal interrupts.
- */
- mask = IVPR_MASK_MASK | IVPR_PRIORITY_MASK | IVPR_SENSE_MASK |
- IVPR_POLARITY_MASK | opp->vector_mask;
-
- /* ACTIVITY bit is read-only */
- opp->src[n_IRQ].ivpr =
- (opp->src[n_IRQ].ivpr & IVPR_ACTIVITY_MASK) | (val & mask);
-
- /* For FSL internal interrupts, The sense bit is reserved and zero,
- * and the interrupt is always level-triggered. Timers and IPIs
- * have no sense or polarity bits, and are edge-triggered.
- */
- switch (opp->src[n_IRQ].type) {
- case IRQ_TYPE_NORMAL:
- opp->src[n_IRQ].level = !!(opp->src[n_IRQ].ivpr & IVPR_SENSE_MASK);
- break;
-
- case IRQ_TYPE_FSLINT:
- opp->src[n_IRQ].ivpr &= ~IVPR_SENSE_MASK;
- break;
-
- case IRQ_TYPE_FSLSPECIAL:
- opp->src[n_IRQ].ivpr &= ~(IVPR_POLARITY_MASK | IVPR_SENSE_MASK);
- break;
- }
-
- openpic_update_irq(opp, n_IRQ);
- DPRINTF("Set IVPR %d to 0x%08x -> 0x%08x\n", n_IRQ, val,
- opp->src[n_IRQ].ivpr);
-}
-
-static void openpic_gcr_write(OpenPICState *opp, uint64_t val)
-{
- bool mpic_proxy = false;
-
- if (val & GCR_RESET) {
- openpic_reset(DEVICE(opp));
- return;
- }
-
- opp->gcr &= ~opp->mpic_mode_mask;
- opp->gcr |= val & opp->mpic_mode_mask;
-
- /* Set external proxy mode */
- if ((val & opp->mpic_mode_mask) == GCR_MODE_PROXY) {
- mpic_proxy = true;
- }
-
- ppce500_set_mpic_proxy(mpic_proxy);
-}
-
-static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned len)
-{
- OpenPICState *opp = opaque;
- IRQDest *dst;
- int idx;
-
- DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n",
- __func__, addr, val);
- if (addr & 0xF) {
- return;
- }
- switch (addr) {
- case 0x00: /* Block Revision Register1 (BRR1) is Readonly */
- break;
- case 0x40:
- case 0x50:
- case 0x60:
- case 0x70:
- case 0x80:
- case 0x90:
- case 0xA0:
- case 0xB0:
- openpic_cpu_write_internal(opp, addr, val, get_current_cpu());
- break;
- case 0x1000: /* FRR */
- break;
- case 0x1020: /* GCR */
- openpic_gcr_write(opp, val);
- break;
- case 0x1080: /* VIR */
- break;
- case 0x1090: /* PIR */
- for (idx = 0; idx < opp->nb_cpus; idx++) {
- if ((val & (1 << idx)) && !(opp->pir & (1 << idx))) {
- DPRINTF("Raise OpenPIC RESET output for CPU %d\n", idx);
- dst = &opp->dst[idx];
- qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_RESET]);
- } else if (!(val & (1 << idx)) && (opp->pir & (1 << idx))) {
- DPRINTF("Lower OpenPIC RESET output for CPU %d\n", idx);
- dst = &opp->dst[idx];
- qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_RESET]);
- }
- }
- opp->pir = val;
- break;
- case 0x10A0: /* IPI_IVPR */
- case 0x10B0:
- case 0x10C0:
- case 0x10D0:
- {
- int idx;
- idx = (addr - 0x10A0) >> 4;
- write_IRQreg_ivpr(opp, opp->irq_ipi0 + idx, val);
- }
- break;
- case 0x10E0: /* SPVE */
- opp->spve = val & opp->vector_mask;
- break;
- default:
- break;
- }
-}
-
-static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len)
-{
- OpenPICState *opp = opaque;
- uint32_t retval;
-
- DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
- retval = 0xFFFFFFFF;
- if (addr & 0xF) {
- return retval;
- }
- switch (addr) {
- case 0x1000: /* FRR */
- retval = opp->frr;
- break;
- case 0x1020: /* GCR */
- retval = opp->gcr;
- break;
- case 0x1080: /* VIR */
- retval = opp->vir;
- break;
- case 0x1090: /* PIR */
- retval = 0x00000000;
- break;
- case 0x00: /* Block Revision Register1 (BRR1) */
- retval = opp->brr1;
- break;
- case 0x40:
- case 0x50:
- case 0x60:
- case 0x70:
- case 0x80:
- case 0x90:
- case 0xA0:
- case 0xB0:
- retval = openpic_cpu_read_internal(opp, addr, get_current_cpu());
- break;
- case 0x10A0: /* IPI_IVPR */
- case 0x10B0:
- case 0x10C0:
- case 0x10D0:
- {
- int idx;
- idx = (addr - 0x10A0) >> 4;
- retval = read_IRQreg_ivpr(opp, opp->irq_ipi0 + idx);
- }
- break;
- case 0x10E0: /* SPVE */
- retval = opp->spve;
- break;
- default:
- break;
- }
- DPRINTF("%s: => 0x%08x\n", __func__, retval);
-
- return retval;
-}
-
-static void openpic_tmr_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned len)
-{
- OpenPICState *opp = opaque;
- int idx;
-
- addr += 0x10f0;
-
- DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n",
- __func__, addr, val);
- if (addr & 0xF) {
- return;
- }
-
- if (addr == 0x10f0) {
- /* TFRR */
- opp->tfrr = val;
- return;
- }
-
- idx = (addr >> 6) & 0x3;
- addr = addr & 0x30;
-
- switch (addr & 0x30) {
- case 0x00: /* TCCR */
- break;
- case 0x10: /* TBCR */
- if ((opp->timers[idx].tccr & TCCR_TOG) != 0 &&
- (val & TBCR_CI) == 0 &&
- (opp->timers[idx].tbcr & TBCR_CI) != 0) {
- opp->timers[idx].tccr &= ~TCCR_TOG;
- }
- opp->timers[idx].tbcr = val;
- break;
- case 0x20: /* TVPR */
- write_IRQreg_ivpr(opp, opp->irq_tim0 + idx, val);
- break;
- case 0x30: /* TDR */
- write_IRQreg_idr(opp, opp->irq_tim0 + idx, val);
- break;
- }
-}
-
-static uint64_t openpic_tmr_read(void *opaque, hwaddr addr, unsigned len)
-{
- OpenPICState *opp = opaque;
- uint32_t retval = -1;
- int idx;
-
- DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
- if (addr & 0xF) {
- goto out;
- }
- idx = (addr >> 6) & 0x3;
- if (addr == 0x0) {
- /* TFRR */
- retval = opp->tfrr;
- goto out;
- }
- switch (addr & 0x30) {
- case 0x00: /* TCCR */
- retval = opp->timers[idx].tccr;
- break;
- case 0x10: /* TBCR */
- retval = opp->timers[idx].tbcr;
- break;
- case 0x20: /* TIPV */
- retval = read_IRQreg_ivpr(opp, opp->irq_tim0 + idx);
- break;
- case 0x30: /* TIDE (TIDR) */
- retval = read_IRQreg_idr(opp, opp->irq_tim0 + idx);
- break;
- }
-
-out:
- DPRINTF("%s: => 0x%08x\n", __func__, retval);
-
- return retval;
-}
-
-static void openpic_src_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned len)
-{
- OpenPICState *opp = opaque;
- int idx;
-
- DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n",
- __func__, addr, val);
-
- addr = addr & 0xffff;
- idx = addr >> 5;
-
- 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;
- }
-}
-
-static uint64_t openpic_src_read(void *opaque, uint64_t addr, unsigned len)
-{
- OpenPICState *opp = opaque;
- uint32_t retval;
- int idx;
-
- DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
- retval = 0xFFFFFFFF;
-
- addr = addr & 0xffff;
- idx = addr >> 5;
-
- 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);
- return retval;
-}
-
-static void openpic_msi_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned size)
-{
- OpenPICState *opp = opaque;
- int idx = opp->irq_msi;
- int srs, ibs;
-
- DPRINTF("%s: addr %#" HWADDR_PRIx " <= 0x%08" PRIx64 "\n",
- __func__, addr, val);
- if (addr & 0xF) {
- return;
- }
-
- switch (addr) {
- case MSIIR_OFFSET:
- srs = val >> MSIIR_SRS_SHIFT;
- idx += srs;
- ibs = (val & MSIIR_IBS_MASK) >> MSIIR_IBS_SHIFT;
- opp->msi[srs].msir |= 1 << ibs;
- openpic_set_irq(opp, idx, 1);
- break;
- default:
- /* most registers are read-only, thus ignored */
- break;
- }
-}
-
-static uint64_t openpic_msi_read(void *opaque, hwaddr addr, unsigned size)
-{
- OpenPICState *opp = opaque;
- uint64_t r = 0;
- int i, srs;
-
- DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
- if (addr & 0xF) {
- return -1;
- }
-
- srs = addr >> 4;
-
- switch (addr) {
- case 0x00:
- case 0x10:
- case 0x20:
- case 0x30:
- case 0x40:
- case 0x50:
- case 0x60:
- case 0x70: /* MSIRs */
- r = opp->msi[srs].msir;
- /* Clear on read */
- opp->msi[srs].msir = 0;
- openpic_set_irq(opp, opp->irq_msi + srs, 0);
- break;
- case 0x120: /* MSISR */
- for (i = 0; i < MAX_MSI; i++) {
- r |= (opp->msi[i].msir ? 1 : 0) << i;
- }
- break;
- }
-
- 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)
-{
- OpenPICState *opp = opaque;
- IRQSource *src;
- IRQDest *dst;
- int s_IRQ, n_IRQ;
-
- DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx " <= 0x%08x\n", __func__, idx,
- addr, val);
-
- if (idx < 0 || idx >= opp->nb_cpus) {
- return;
- }
-
- if (addr & 0xF) {
- return;
- }
- dst = &opp->dst[idx];
- addr &= 0xFF0;
- switch (addr) {
- case 0x40: /* IPIDR */
- case 0x50:
- case 0x60:
- case 0x70:
- idx = (addr - 0x40) >> 4;
- /* we use IDE as mask which CPUs to deliver the IPI to still. */
- 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;
- case 0x80: /* CTPR */
- dst->ctpr = val & 0x0000000F;
-
- DPRINTF("%s: set CPU %d ctpr to %d, raised %d servicing %d\n",
- __func__, idx, dst->ctpr, dst->raised.priority,
- dst->servicing.priority);
-
- if (dst->raised.priority <= dst->ctpr) {
- DPRINTF("%s: Lower OpenPIC INT output cpu %d due to ctpr\n",
- __func__, idx);
- qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]);
- } else if (dst->raised.priority > dst->servicing.priority) {
- DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d\n",
- __func__, idx, dst->raised.next);
- qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]);
- }
-
- break;
- case 0x90: /* WHOAMI */
- /* Read-only register */
- break;
- case 0xA0: /* IACK */
- /* Read-only register */
- break;
- case 0xB0: /* EOI */
- DPRINTF("EOI\n");
- s_IRQ = IRQ_get_next(opp, &dst->servicing);
-
- if (s_IRQ < 0) {
- DPRINTF("%s: EOI with no interrupt in service\n", __func__);
- break;
- }
-
- IRQ_resetbit(&dst->servicing, s_IRQ);
- /* Set up next servicing IRQ */
- s_IRQ = IRQ_get_next(opp, &dst->servicing);
- /* Check queued interrupts. */
- n_IRQ = IRQ_get_next(opp, &dst->raised);
- src = &opp->src[n_IRQ];
- if (n_IRQ != -1 &&
- (s_IRQ == -1 ||
- IVPR_PRIORITY(src->ivpr) > dst->servicing.priority)) {
- DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n",
- idx, n_IRQ);
- qemu_irq_raise(opp->dst[idx].irqs[OPENPIC_OUTPUT_INT]);
- }
- break;
- default:
- break;
- }
-}
-
-static void openpic_cpu_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned len)
-{
- openpic_cpu_write_internal(opaque, addr, val, (addr & 0x1f000) >> 12);
-}
-
-
-static uint32_t openpic_iack(OpenPICState *opp, IRQDest *dst, int cpu)
-{
- IRQSource *src;
- int retval, irq;
-
- DPRINTF("Lower OpenPIC INT output\n");
- qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]);
-
- irq = IRQ_get_next(opp, &dst->raised);
- DPRINTF("IACK: irq=%d\n", irq);
-
- if (irq == -1) {
- /* No more interrupt pending */
- return opp->spve;
- }
-
- src = &opp->src[irq];
- if (!(src->ivpr & IVPR_ACTIVITY_MASK) ||
- !(IVPR_PRIORITY(src->ivpr) > dst->ctpr)) {
- fprintf(stderr, "%s: bad raised IRQ %d ctpr %d ivpr 0x%08x\n",
- __func__, irq, dst->ctpr, src->ivpr);
- openpic_update_irq(opp, irq);
- retval = opp->spve;
- } else {
- /* IRQ enter servicing state */
- IRQ_setbit(&dst->servicing, irq);
- retval = IVPR_VECTOR(opp, src->ivpr);
- }
-
- if (!src->level) {
- /* edge-sensitive IRQ */
- src->ivpr &= ~IVPR_ACTIVITY_MASK;
- src->pending = 0;
- IRQ_resetbit(&dst->raised, irq);
- }
-
- if ((irq >= opp->irq_ipi0) && (irq < (opp->irq_ipi0 + OPENPIC_MAX_IPI))) {
- 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);
- /* if all CPUs knew about it, set active bit again */
- src->ivpr |= IVPR_ACTIVITY_MASK;
- }
- }
-
- return retval;
-}
-
-static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr,
- int idx)
-{
- OpenPICState *opp = opaque;
- IRQDest *dst;
- uint32_t retval;
-
- DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx "\n", __func__, idx, addr);
- retval = 0xFFFFFFFF;
-
- if (idx < 0 || idx >= opp->nb_cpus) {
- return retval;
- }
-
- if (addr & 0xF) {
- return retval;
- }
- dst = &opp->dst[idx];
- addr &= 0xFF0;
- switch (addr) {
- case 0x80: /* CTPR */
- retval = dst->ctpr;
- break;
- case 0x90: /* WHOAMI */
- retval = idx;
- break;
- case 0xA0: /* IACK */
- retval = openpic_iack(opp, dst, idx);
- break;
- case 0xB0: /* EOI */
- retval = 0;
- break;
- default:
- break;
- }
- DPRINTF("%s: => 0x%08x\n", __func__, retval);
-
- return retval;
-}
-
-static uint64_t openpic_cpu_read(void *opaque, hwaddr addr, unsigned len)
-{
- return openpic_cpu_read_internal(opaque, addr, (addr & 0x1f000) >> 12);
-}
-
-static const MemoryRegionOps openpic_glb_ops_le = {
- .write = openpic_gbl_write,
- .read = openpic_gbl_read,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .impl = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static const MemoryRegionOps openpic_glb_ops_be = {
- .write = openpic_gbl_write,
- .read = openpic_gbl_read,
- .endianness = DEVICE_BIG_ENDIAN,
- .impl = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static const MemoryRegionOps openpic_tmr_ops_le = {
- .write = openpic_tmr_write,
- .read = openpic_tmr_read,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .impl = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static const MemoryRegionOps openpic_tmr_ops_be = {
- .write = openpic_tmr_write,
- .read = openpic_tmr_read,
- .endianness = DEVICE_BIG_ENDIAN,
- .impl = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static const MemoryRegionOps openpic_cpu_ops_le = {
- .write = openpic_cpu_write,
- .read = openpic_cpu_read,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .impl = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static const MemoryRegionOps openpic_cpu_ops_be = {
- .write = openpic_cpu_write,
- .read = openpic_cpu_read,
- .endianness = DEVICE_BIG_ENDIAN,
- .impl = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static const MemoryRegionOps openpic_src_ops_le = {
- .write = openpic_src_write,
- .read = openpic_src_read,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .impl = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static const MemoryRegionOps openpic_src_ops_be = {
- .write = openpic_src_write,
- .read = openpic_src_read,
- .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,
- .endianness = DEVICE_BIG_ENDIAN,
- .impl = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static const MemoryRegionOps openpic_summary_ops_be = {
- .read = openpic_summary_read,
- .write = openpic_summary_write,
- .endianness = DEVICE_BIG_ENDIAN,
- .impl = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static void openpic_reset(DeviceState *d)
-{
- OpenPICState *opp = OPENPIC(d);
- int i;
-
- opp->gcr = GCR_RESET;
- /* Initialise controller registers */
- opp->frr = ((opp->nb_irqs - 1) << FRR_NIRQ_SHIFT) |
- ((opp->nb_cpus - 1) << FRR_NCPU_SHIFT) |
- (opp->vid << FRR_VID_SHIFT);
-
- opp->pir = 0;
- opp->spve = -1 & opp->vector_mask;
- opp->tfrr = opp->tfrr_reset;
- /* Initialise IRQ sources */
- for (i = 0; i < opp->max_irq; i++) {
- opp->src[i].ivpr = opp->ivpr_reset;
- switch (opp->src[i].type) {
- case IRQ_TYPE_NORMAL:
- opp->src[i].level = !!(opp->ivpr_reset & IVPR_SENSE_MASK);
- break;
-
- case IRQ_TYPE_FSLINT:
- opp->src[i].ivpr |= IVPR_POLARITY_MASK;
- break;
-
- case IRQ_TYPE_FSLSPECIAL:
- break;
- }
-
- write_IRQreg_idr(opp, i, opp->idr_reset);
- }
- /* Initialise IRQ destinations */
- for (i = 0; i < opp->nb_cpus; i++) {
- opp->dst[i].ctpr = 15;
- opp->dst[i].raised.next = -1;
- opp->dst[i].raised.priority = 0;
- bitmap_clear(opp->dst[i].raised.queue, 0, IRQQUEUE_SIZE_BITS);
- opp->dst[i].servicing.next = -1;
- opp->dst[i].servicing.priority = 0;
- bitmap_clear(opp->dst[i].servicing.queue, 0, IRQQUEUE_SIZE_BITS);
- }
- /* Initialise timers */
- for (i = 0; i < OPENPIC_MAX_TMR; i++) {
- opp->timers[i].tccr = 0;
- opp->timers[i].tbcr = TBCR_CI;
- }
- /* Go out of RESET state */
- opp->gcr = 0;
-}
-
-typedef struct MemReg {
- const char *name;
- MemoryRegionOps const *ops;
- hwaddr start_addr;
- ram_addr_t size;
-} MemReg;
-
-static void fsl_common_init(OpenPICState *opp)
-{
- int i;
- int virq = OPENPIC_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 = OPENPIC_MAX_IRQ;
-
- opp->irq_ipi0 = virq;
- virq += OPENPIC_MAX_IPI;
- opp->irq_tim0 = virq;
- virq += OPENPIC_MAX_TMR;
-
- assert(virq <= OPENPIC_MAX_IRQ);
-
- opp->irq_msi = 224;
-
- msi_nonbroken = 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 < OPENPIC_MAX_SRC; i++) {
- opp->src[i].type = IRQ_TYPE_FSLINT;
- opp->src[i].level = true;
- }
-
- /* timers and IPIs */
- for (i = OPENPIC_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], OBJECT(opp), list->ops,
- opp, list->name, list->size);
-
- memory_region_add_subregion(&opp->mem, list->start_addr,
- &opp->sub_io_mem[*count]);
-
- (*count)++;
- list++;
- }
-}
-
-static const VMStateDescription vmstate_openpic_irq_queue = {
- .name = "openpic_irq_queue",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_BITMAP(queue, IRQQueue, 0, queue_size),
- VMSTATE_INT32(next, IRQQueue),
- VMSTATE_INT32(priority, IRQQueue),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_openpic_irqdest = {
- .name = "openpic_irqdest",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_INT32(ctpr, IRQDest),
- VMSTATE_STRUCT(raised, IRQDest, 0, vmstate_openpic_irq_queue,
- IRQQueue),
- VMSTATE_STRUCT(servicing, IRQDest, 0, vmstate_openpic_irq_queue,
- IRQQueue),
- VMSTATE_UINT32_ARRAY(outputs_active, IRQDest, OPENPIC_OUTPUT_NB),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_openpic_irqsource = {
- .name = "openpic_irqsource",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(ivpr, IRQSource),
- VMSTATE_UINT32(idr, IRQSource),
- VMSTATE_UINT32(destmask, IRQSource),
- VMSTATE_INT32(last_cpu, IRQSource),
- VMSTATE_INT32(pending, IRQSource),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_openpic_timer = {
- .name = "openpic_timer",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(tccr, OpenPICTimer),
- VMSTATE_UINT32(tbcr, OpenPICTimer),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_openpic_msi = {
- .name = "openpic_msi",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(msir, OpenPICMSI),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static int openpic_post_load(void *opaque, int version_id)
-{
- OpenPICState *opp = (OpenPICState *)opaque;
- int i;
-
- /* Update internal ivpr and idr variables */
- for (i = 0; i < opp->max_irq; i++) {
- write_IRQreg_idr(opp, i, opp->src[i].idr);
- write_IRQreg_ivpr(opp, i, opp->src[i].ivpr);
- }
-
- return 0;
-}
-
-static const VMStateDescription vmstate_openpic = {
- .name = "openpic",
- .version_id = 3,
- .minimum_version_id = 3,
- .post_load = openpic_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(gcr, OpenPICState),
- VMSTATE_UINT32(vir, OpenPICState),
- VMSTATE_UINT32(pir, OpenPICState),
- VMSTATE_UINT32(spve, OpenPICState),
- VMSTATE_UINT32(tfrr, OpenPICState),
- VMSTATE_UINT32(max_irq, OpenPICState),
- VMSTATE_STRUCT_VARRAY_UINT32(src, OpenPICState, max_irq, 0,
- vmstate_openpic_irqsource, IRQSource),
- VMSTATE_UINT32_EQUAL(nb_cpus, OpenPICState),
- VMSTATE_STRUCT_VARRAY_UINT32(dst, OpenPICState, nb_cpus, 0,
- vmstate_openpic_irqdest, IRQDest),
- VMSTATE_STRUCT_ARRAY(timers, OpenPICState, OPENPIC_MAX_TMR, 0,
- vmstate_openpic_timer, OpenPICTimer),
- VMSTATE_STRUCT_ARRAY(msi, OpenPICState, MAX_MSI, 0,
- vmstate_openpic_msi, OpenPICMSI),
- VMSTATE_UINT32(irq_ipi0, OpenPICState),
- VMSTATE_UINT32(irq_tim0, OpenPICState),
- VMSTATE_UINT32(irq_msi, OpenPICState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void openpic_init(Object *obj)
-{
- OpenPICState *opp = OPENPIC(obj);
-
- memory_region_init(&opp->mem, obj, "openpic", 0x40000);
-}
-
-static void openpic_realize(DeviceState *dev, Error **errp)
-{
- SysBusDevice *d = SYS_BUS_DEVICE(dev);
- OpenPICState *opp = OPENPIC(dev);
- int i, j;
- 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,
- OPENPIC_TMR_REG_START, OPENPIC_TMR_REG_SIZE},
- {"src", &openpic_src_ops_le,
- OPENPIC_SRC_REG_START, OPENPIC_SRC_REG_SIZE},
- {"cpu", &openpic_cpu_ops_le,
- OPENPIC_CPU_REG_START, OPENPIC_CPU_REG_SIZE},
- {NULL}
- };
- static const MemReg list_be[] = {
- {"glb", &openpic_glb_ops_be,
- OPENPIC_GLB_REG_START, OPENPIC_GLB_REG_SIZE},
- {"tmr", &openpic_tmr_ops_be,
- OPENPIC_TMR_REG_START, OPENPIC_TMR_REG_SIZE},
- {"src", &openpic_src_ops_be,
- OPENPIC_SRC_REG_START, OPENPIC_SRC_REG_SIZE},
- {"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}
- };
-
- if (opp->nb_cpus > MAX_CPU) {
- error_setg(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE,
- TYPE_OPENPIC, "nb_cpus", (uint64_t)opp->nb_cpus,
- (uint64_t)0, (uint64_t)MAX_CPU);
- return;
- }
-
- 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->mpic_mode_mask = GCR_MODE_MIXED;
-
- fsl_common_init(opp);
- map_list(opp, list_be, &list_count);
- map_list(opp, list_fsl, &list_count);
-
- break;
-
- 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;
-
- fsl_common_init(opp);
- map_list(opp, list_be, &list_count);
- map_list(opp, list_fsl, &list_count);
-
- break;
-
- case OPENPIC_MODEL_RAVEN:
- opp->nb_irqs = RAVEN_MAX_EXT;
- opp->vid = VID_REVISION_1_3;
- opp->vir = VIR_GENERIC;
- opp->vector_mask = 0xFF;
- opp->tfrr_reset = 4160000;
- opp->ivpr_reset = IVPR_MASK_MASK | IVPR_MODE_MASK;
- opp->idr_reset = 0;
- opp->max_irq = RAVEN_MAX_IRQ;
- opp->irq_ipi0 = RAVEN_IPI_IRQ;
- opp->irq_tim0 = RAVEN_TMR_IRQ;
- opp->brr1 = -1;
- opp->mpic_mode_mask = GCR_MODE_MIXED;
-
- if (opp->nb_cpus != 1) {
- error_setg(errp, "Only UP supported today");
- return;
- }
-
- map_list(opp, list_le, &list_count);
- break;
- }
-
- for (i = 0; i < opp->nb_cpus; i++) {
- opp->dst[i].irqs = g_new0(qemu_irq, OPENPIC_OUTPUT_NB);
- for (j = 0; j < OPENPIC_OUTPUT_NB; j++) {
- sysbus_init_irq(d, &opp->dst[i].irqs[j]);
- }
-
- opp->dst[i].raised.queue_size = IRQQUEUE_SIZE_BITS;
- opp->dst[i].raised.queue = bitmap_new(IRQQUEUE_SIZE_BITS);
- opp->dst[i].servicing.queue_size = IRQQUEUE_SIZE_BITS;
- opp->dst[i].servicing.queue = bitmap_new(IRQQUEUE_SIZE_BITS);
- }
-
- sysbus_init_mmio(d, &opp->mem);
- qdev_init_gpio_in(dev, openpic_set_irq, opp->max_irq);
-}
-
-static Property openpic_properties[] = {
- DEFINE_PROP_UINT32("model", OpenPICState, model, OPENPIC_MODEL_FSL_MPIC_20),
- DEFINE_PROP_UINT32("nb_cpus", OpenPICState, nb_cpus, 1),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void openpic_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- dc->realize = openpic_realize;
- dc->props = openpic_properties;
- dc->reset = openpic_reset;
- dc->vmsd = &vmstate_openpic;
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
-}
-
-static const TypeInfo openpic_info = {
- .name = TYPE_OPENPIC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(OpenPICState),
- .instance_init = openpic_init,
- .class_init = openpic_class_init,
-};
-
-static void openpic_register_types(void)
-{
- type_register_static(&openpic_info);
-}
-
-type_init(openpic_register_types)
diff --git a/qemu/hw/intc/openpic_kvm.c b/qemu/hw/intc/openpic_kvm.c
deleted file mode 100644
index e47e94f2c..000000000
--- a/qemu/hw/intc/openpic_kvm.c
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
- * KVM in-kernel OpenPIC
- *
- * Copyright 2013 Freescale Semiconductor, Inc.
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include <sys/ioctl.h>
-#include "exec/address-spaces.h"
-#include "hw/hw.h"
-#include "hw/ppc/openpic.h"
-#include "hw/pci/msi.h"
-#include "hw/sysbus.h"
-#include "sysemu/kvm.h"
-#include "qemu/log.h"
-
-#define GCR_RESET 0x80000000
-
-#define KVM_OPENPIC(obj) \
- OBJECT_CHECK(KVMOpenPICState, (obj), TYPE_KVM_OPENPIC)
-
-typedef struct KVMOpenPICState {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- MemoryRegion mem;
- MemoryListener mem_listener;
- uint32_t fd;
- uint32_t model;
- hwaddr mapped;
-} KVMOpenPICState;
-
-static void kvm_openpic_set_irq(void *opaque, int n_IRQ, int level)
-{
- kvm_set_irq(kvm_state, n_IRQ, level);
-}
-
-static void kvm_openpic_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned size)
-{
- KVMOpenPICState *opp = opaque;
- struct kvm_device_attr attr;
- uint32_t val32 = val;
- int ret;
-
- attr.group = KVM_DEV_MPIC_GRP_REGISTER;
- attr.attr = addr;
- attr.addr = (uint64_t)(unsigned long)&val32;
-
- ret = ioctl(opp->fd, KVM_SET_DEVICE_ATTR, &attr);
- if (ret < 0) {
- qemu_log_mask(LOG_UNIMP, "%s: %s %" PRIx64 "\n", __func__,
- strerror(errno), attr.attr);
- }
-}
-
-static void kvm_openpic_reset(DeviceState *d)
-{
- KVMOpenPICState *opp = KVM_OPENPIC(d);
-
- /* Trigger the GCR.RESET bit to reset the PIC */
- kvm_openpic_write(opp, 0x1020, GCR_RESET, sizeof(uint32_t));
-}
-
-static uint64_t kvm_openpic_read(void *opaque, hwaddr addr, unsigned size)
-{
- KVMOpenPICState *opp = opaque;
- struct kvm_device_attr attr;
- uint32_t val = 0xdeadbeef;
- int ret;
-
- attr.group = KVM_DEV_MPIC_GRP_REGISTER;
- attr.attr = addr;
- attr.addr = (uint64_t)(unsigned long)&val;
-
- ret = ioctl(opp->fd, KVM_GET_DEVICE_ATTR, &attr);
- if (ret < 0) {
- qemu_log_mask(LOG_UNIMP, "%s: %s %" PRIx64 "\n", __func__,
- strerror(errno), attr.attr);
- return 0;
- }
-
- return val;
-}
-
-static const MemoryRegionOps kvm_openpic_mem_ops = {
- .write = kvm_openpic_write,
- .read = kvm_openpic_read,
- .endianness = DEVICE_BIG_ENDIAN,
- .impl = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static void kvm_openpic_region_add(MemoryListener *listener,
- MemoryRegionSection *section)
-{
- KVMOpenPICState *opp = container_of(listener, KVMOpenPICState,
- mem_listener);
- struct kvm_device_attr attr;
- uint64_t reg_base;
- int ret;
-
- if (section->address_space != &address_space_memory) {
- abort();
- }
-
- /* Ignore events on regions that are not us */
- if (section->mr != &opp->mem) {
- return;
- }
-
- if (opp->mapped) {
- /*
- * We can only map the MPIC once. Since we are already mapped,
- * the best we can do is ignore new maps.
- */
- return;
- }
-
- reg_base = section->offset_within_address_space;
- opp->mapped = reg_base;
-
- attr.group = KVM_DEV_MPIC_GRP_MISC;
- attr.attr = KVM_DEV_MPIC_BASE_ADDR;
- attr.addr = (uint64_t)(unsigned long)&reg_base;
-
- ret = ioctl(opp->fd, KVM_SET_DEVICE_ATTR, &attr);
- if (ret < 0) {
- fprintf(stderr, "%s: %s %" PRIx64 "\n", __func__,
- strerror(errno), reg_base);
- }
-}
-
-static void kvm_openpic_region_del(MemoryListener *listener,
- MemoryRegionSection *section)
-{
- KVMOpenPICState *opp = container_of(listener, KVMOpenPICState,
- mem_listener);
- struct kvm_device_attr attr;
- uint64_t reg_base = 0;
- int ret;
-
- /* Ignore events on regions that are not us */
- if (section->mr != &opp->mem) {
- return;
- }
-
- if (section->offset_within_address_space != opp->mapped) {
- /*
- * We can only map the MPIC once. This mapping was a secondary
- * one that we couldn't fulfill. Ignore it.
- */
- return;
- }
- opp->mapped = 0;
-
- attr.group = KVM_DEV_MPIC_GRP_MISC;
- attr.attr = KVM_DEV_MPIC_BASE_ADDR;
- attr.addr = (uint64_t)(unsigned long)&reg_base;
-
- ret = ioctl(opp->fd, KVM_SET_DEVICE_ATTR, &attr);
- if (ret < 0) {
- fprintf(stderr, "%s: %s %" PRIx64 "\n", __func__,
- strerror(errno), reg_base);
- }
-}
-
-static void kvm_openpic_init(Object *obj)
-{
- KVMOpenPICState *opp = KVM_OPENPIC(obj);
-
- memory_region_init_io(&opp->mem, OBJECT(opp), &kvm_openpic_mem_ops, opp,
- "kvm-openpic", 0x40000);
-}
-
-static void kvm_openpic_realize(DeviceState *dev, Error **errp)
-{
- SysBusDevice *d = SYS_BUS_DEVICE(dev);
- KVMOpenPICState *opp = KVM_OPENPIC(dev);
- KVMState *s = kvm_state;
- int kvm_openpic_model;
- struct kvm_create_device cd = {0};
- int ret, i;
-
- if (!kvm_check_extension(s, KVM_CAP_DEVICE_CTRL)) {
- error_setg(errp, "Kernel is lacking Device Control API");
- return;
- }
-
- switch (opp->model) {
- case OPENPIC_MODEL_FSL_MPIC_20:
- kvm_openpic_model = KVM_DEV_TYPE_FSL_MPIC_20;
- break;
-
- case OPENPIC_MODEL_FSL_MPIC_42:
- kvm_openpic_model = KVM_DEV_TYPE_FSL_MPIC_42;
- break;
-
- default:
- error_setg(errp, "Unsupported OpenPIC model %" PRIu32, opp->model);
- return;
- }
-
- cd.type = kvm_openpic_model;
- ret = kvm_vm_ioctl(s, KVM_CREATE_DEVICE, &cd);
- if (ret < 0) {
- error_setg(errp, "Can't create device %d: %s",
- cd.type, strerror(errno));
- return;
- }
- opp->fd = cd.fd;
-
- sysbus_init_mmio(d, &opp->mem);
- qdev_init_gpio_in(dev, kvm_openpic_set_irq, OPENPIC_MAX_IRQ);
-
- opp->mem_listener.region_add = kvm_openpic_region_add;
- opp->mem_listener.region_del = kvm_openpic_region_del;
- memory_listener_register(&opp->mem_listener, &address_space_memory);
-
- /* indicate pic capabilities */
- msi_nonbroken = true;
- kvm_kernel_irqchip = true;
- kvm_async_interrupts_allowed = true;
-
- /* set up irq routing */
- kvm_init_irq_routing(kvm_state);
- for (i = 0; i < 256; ++i) {
- kvm_irqchip_add_irq_route(kvm_state, i, 0, i);
- }
-
- kvm_msi_via_irqfd_allowed = true;
- kvm_gsi_routing_allowed = true;
-
- kvm_irqchip_commit_routes(s);
-}
-
-int kvm_openpic_connect_vcpu(DeviceState *d, CPUState *cs)
-{
- KVMOpenPICState *opp = KVM_OPENPIC(d);
-
- return kvm_vcpu_enable_cap(cs, KVM_CAP_IRQ_MPIC, 0, opp->fd,
- kvm_arch_vcpu_id(cs));
-}
-
-static Property kvm_openpic_properties[] = {
- DEFINE_PROP_UINT32("model", KVMOpenPICState, model,
- OPENPIC_MODEL_FSL_MPIC_20),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void kvm_openpic_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- dc->realize = kvm_openpic_realize;
- dc->props = kvm_openpic_properties;
- dc->reset = kvm_openpic_reset;
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
-}
-
-static const TypeInfo kvm_openpic_info = {
- .name = TYPE_KVM_OPENPIC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(KVMOpenPICState),
- .instance_init = kvm_openpic_init,
- .class_init = kvm_openpic_class_init,
-};
-
-static void kvm_openpic_register_types(void)
-{
- type_register_static(&kvm_openpic_info);
-}
-
-type_init(kvm_openpic_register_types)
diff --git a/qemu/hw/intc/pl190.c b/qemu/hw/intc/pl190.c
deleted file mode 100644
index 5ecbc4a48..000000000
--- a/qemu/hw/intc/pl190.c
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * Arm PrimeCell PL190 Vector Interrupt Controller
- *
- * Copyright (c) 2006 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-
-/* The number of virtual priority levels. 16 user vectors plus the
- unvectored IRQ. Chained interrupts would require an additional level
- if implemented. */
-
-#define PL190_NUM_PRIO 17
-
-#define TYPE_PL190 "pl190"
-#define PL190(obj) OBJECT_CHECK(PL190State, (obj), TYPE_PL190)
-
-typedef struct PL190State {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- uint32_t level;
- uint32_t soft_level;
- uint32_t irq_enable;
- uint32_t fiq_select;
- uint8_t vect_control[16];
- uint32_t vect_addr[PL190_NUM_PRIO];
- /* Mask containing interrupts with higher priority than this one. */
- uint32_t prio_mask[PL190_NUM_PRIO + 1];
- int protected;
- /* Current priority level. */
- int priority;
- int prev_prio[PL190_NUM_PRIO];
- qemu_irq irq;
- qemu_irq fiq;
-} PL190State;
-
-static const unsigned char pl190_id[] =
-{ 0x90, 0x11, 0x04, 0x00, 0x0D, 0xf0, 0x05, 0xb1 };
-
-static inline uint32_t pl190_irq_level(PL190State *s)
-{
- return (s->level | s->soft_level) & s->irq_enable & ~s->fiq_select;
-}
-
-/* Update interrupts. */
-static void pl190_update(PL190State *s)
-{
- uint32_t level = pl190_irq_level(s);
- int set;
-
- set = (level & s->prio_mask[s->priority]) != 0;
- qemu_set_irq(s->irq, set);
- set = ((s->level | s->soft_level) & s->fiq_select) != 0;
- qemu_set_irq(s->fiq, set);
-}
-
-static void pl190_set_irq(void *opaque, int irq, int level)
-{
- PL190State *s = (PL190State *)opaque;
-
- if (level)
- s->level |= 1u << irq;
- else
- s->level &= ~(1u << irq);
- pl190_update(s);
-}
-
-static void pl190_update_vectors(PL190State *s)
-{
- uint32_t mask;
- int i;
- int n;
-
- mask = 0;
- for (i = 0; i < 16; i++)
- {
- s->prio_mask[i] = mask;
- if (s->vect_control[i] & 0x20)
- {
- n = s->vect_control[i] & 0x1f;
- mask |= 1 << n;
- }
- }
- s->prio_mask[16] = mask;
- pl190_update(s);
-}
-
-static uint64_t pl190_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- PL190State *s = (PL190State *)opaque;
- int i;
-
- if (offset >= 0xfe0 && offset < 0x1000) {
- return pl190_id[(offset - 0xfe0) >> 2];
- }
- if (offset >= 0x100 && offset < 0x140) {
- return s->vect_addr[(offset - 0x100) >> 2];
- }
- if (offset >= 0x200 && offset < 0x240) {
- return s->vect_control[(offset - 0x200) >> 2];
- }
- switch (offset >> 2) {
- case 0: /* IRQSTATUS */
- return pl190_irq_level(s);
- case 1: /* FIQSATUS */
- return (s->level | s->soft_level) & s->fiq_select;
- case 2: /* RAWINTR */
- return s->level | s->soft_level;
- case 3: /* INTSELECT */
- return s->fiq_select;
- case 4: /* INTENABLE */
- return s->irq_enable;
- case 6: /* SOFTINT */
- return s->soft_level;
- case 8: /* PROTECTION */
- return s->protected;
- case 12: /* VECTADDR */
- /* Read vector address at the start of an ISR. Increases the
- * current priority level to that of the current interrupt.
- *
- * Since an enabled interrupt X at priority P causes prio_mask[Y]
- * to have bit X set for all Y > P, this loop will stop with
- * i == the priority of the highest priority set interrupt.
- */
- for (i = 0; i < s->priority; i++) {
- if ((s->level | s->soft_level) & s->prio_mask[i + 1]) {
- break;
- }
- }
-
- /* Reading this value with no pending interrupts is undefined.
- We return the default address. */
- if (i == PL190_NUM_PRIO)
- return s->vect_addr[16];
- if (i < s->priority)
- {
- s->prev_prio[i] = s->priority;
- s->priority = i;
- pl190_update(s);
- }
- return s->vect_addr[s->priority];
- case 13: /* DEFVECTADDR */
- return s->vect_addr[16];
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "pl190_read: Bad offset %x\n", (int)offset);
- return 0;
- }
-}
-
-static void pl190_write(void *opaque, hwaddr offset,
- uint64_t val, unsigned size)
-{
- PL190State *s = (PL190State *)opaque;
-
- if (offset >= 0x100 && offset < 0x140) {
- s->vect_addr[(offset - 0x100) >> 2] = val;
- pl190_update_vectors(s);
- return;
- }
- if (offset >= 0x200 && offset < 0x240) {
- s->vect_control[(offset - 0x200) >> 2] = val;
- pl190_update_vectors(s);
- return;
- }
- switch (offset >> 2) {
- case 0: /* SELECT */
- /* This is a readonly register, but linux tries to write to it
- anyway. Ignore the write. */
- break;
- case 3: /* INTSELECT */
- s->fiq_select = val;
- break;
- case 4: /* INTENABLE */
- s->irq_enable |= val;
- break;
- case 5: /* INTENCLEAR */
- s->irq_enable &= ~val;
- break;
- case 6: /* SOFTINT */
- s->soft_level |= val;
- break;
- case 7: /* SOFTINTCLEAR */
- s->soft_level &= ~val;
- break;
- case 8: /* PROTECTION */
- /* TODO: Protection (supervisor only access) is not implemented. */
- s->protected = val & 1;
- break;
- case 12: /* VECTADDR */
- /* Restore the previous priority level. The value written is
- ignored. */
- if (s->priority < PL190_NUM_PRIO)
- s->priority = s->prev_prio[s->priority];
- break;
- case 13: /* DEFVECTADDR */
- s->vect_addr[16] = val;
- break;
- case 0xc0: /* ITCR */
- if (val) {
- qemu_log_mask(LOG_UNIMP, "pl190: Test mode not implemented\n");
- }
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "pl190_write: Bad offset %x\n", (int)offset);
- return;
- }
- pl190_update(s);
-}
-
-static const MemoryRegionOps pl190_ops = {
- .read = pl190_read,
- .write = pl190_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void pl190_reset(DeviceState *d)
-{
- PL190State *s = PL190(d);
- int i;
-
- for (i = 0; i < 16; i++) {
- s->vect_addr[i] = 0;
- s->vect_control[i] = 0;
- }
- s->vect_addr[16] = 0;
- s->prio_mask[17] = 0xffffffff;
- s->priority = PL190_NUM_PRIO;
- pl190_update_vectors(s);
-}
-
-static int pl190_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- PL190State *s = PL190(dev);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &pl190_ops, s, "pl190", 0x1000);
- sysbus_init_mmio(sbd, &s->iomem);
- qdev_init_gpio_in(dev, pl190_set_irq, 32);
- sysbus_init_irq(sbd, &s->irq);
- sysbus_init_irq(sbd, &s->fiq);
- return 0;
-}
-
-static const VMStateDescription vmstate_pl190 = {
- .name = "pl190",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(level, PL190State),
- VMSTATE_UINT32(soft_level, PL190State),
- VMSTATE_UINT32(irq_enable, PL190State),
- VMSTATE_UINT32(fiq_select, PL190State),
- VMSTATE_UINT8_ARRAY(vect_control, PL190State, 16),
- VMSTATE_UINT32_ARRAY(vect_addr, PL190State, PL190_NUM_PRIO),
- VMSTATE_UINT32_ARRAY(prio_mask, PL190State, PL190_NUM_PRIO+1),
- VMSTATE_INT32(protected, PL190State),
- VMSTATE_INT32(priority, PL190State),
- VMSTATE_INT32_ARRAY(prev_prio, PL190State, PL190_NUM_PRIO),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void pl190_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = pl190_init;
- dc->reset = pl190_reset;
- dc->vmsd = &vmstate_pl190;
-}
-
-static const TypeInfo pl190_info = {
- .name = TYPE_PL190,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PL190State),
- .class_init = pl190_class_init,
-};
-
-static void pl190_register_types(void)
-{
- type_register_static(&pl190_info);
-}
-
-type_init(pl190_register_types)
diff --git a/qemu/hw/intc/puv3_intc.c b/qemu/hw/intc/puv3_intc.c
deleted file mode 100644
index ef8488aac..000000000
--- a/qemu/hw/intc/puv3_intc.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * INTC device simulation in PKUnity SoC
- *
- * Copyright (C) 2010-2012 Guan Xuetao
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation, or any later version.
- * See the COPYING file in the top-level directory.
- */
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-
-#undef DEBUG_PUV3
-#include "hw/unicore32/puv3.h"
-
-#define TYPE_PUV3_INTC "puv3_intc"
-#define PUV3_INTC(obj) OBJECT_CHECK(PUV3INTCState, (obj), TYPE_PUV3_INTC)
-
-typedef struct PUV3INTCState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- qemu_irq parent_irq;
-
- uint32_t reg_ICMR;
- uint32_t reg_ICPR;
-} PUV3INTCState;
-
-/* Update interrupt status after enabled or pending bits have been changed. */
-static void puv3_intc_update(PUV3INTCState *s)
-{
- if (s->reg_ICMR & s->reg_ICPR) {
- qemu_irq_raise(s->parent_irq);
- } else {
- qemu_irq_lower(s->parent_irq);
- }
-}
-
-/* Process a change in an external INTC input. */
-static void puv3_intc_handler(void *opaque, int irq, int level)
-{
- PUV3INTCState *s = opaque;
-
- DPRINTF("irq 0x%x, level 0x%x\n", irq, level);
- if (level) {
- s->reg_ICPR |= (1 << irq);
- } else {
- s->reg_ICPR &= ~(1 << irq);
- }
- puv3_intc_update(s);
-}
-
-static uint64_t puv3_intc_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- PUV3INTCState *s = opaque;
- uint32_t ret = 0;
-
- switch (offset) {
- case 0x04: /* INTC_ICMR */
- ret = s->reg_ICMR;
- break;
- case 0x0c: /* INTC_ICIP */
- ret = s->reg_ICPR; /* the same value with ICPR */
- break;
- default:
- DPRINTF("Bad offset %x\n", (int)offset);
- }
- DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
- return ret;
-}
-
-static void puv3_intc_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PUV3INTCState *s = opaque;
-
- DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
- switch (offset) {
- case 0x00: /* INTC_ICLR */
- case 0x14: /* INTC_ICCR */
- break;
- case 0x04: /* INTC_ICMR */
- s->reg_ICMR = value;
- break;
- default:
- DPRINTF("Bad offset 0x%x\n", (int)offset);
- return;
- }
- puv3_intc_update(s);
-}
-
-static const MemoryRegionOps puv3_intc_ops = {
- .read = puv3_intc_read,
- .write = puv3_intc_write,
- .impl = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int puv3_intc_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- PUV3INTCState *s = PUV3_INTC(dev);
-
- qdev_init_gpio_in(dev, puv3_intc_handler, PUV3_IRQS_NR);
- sysbus_init_irq(sbd, &s->parent_irq);
-
- s->reg_ICMR = 0;
- s->reg_ICPR = 0;
-
- memory_region_init_io(&s->iomem, OBJECT(s), &puv3_intc_ops, s, "puv3_intc",
- PUV3_REGS_OFFSET);
- sysbus_init_mmio(sbd, &s->iomem);
-
- return 0;
-}
-
-static void puv3_intc_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
- sdc->init = puv3_intc_init;
-}
-
-static const TypeInfo puv3_intc_info = {
- .name = TYPE_PUV3_INTC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PUV3INTCState),
- .class_init = puv3_intc_class_init,
-};
-
-static void puv3_intc_register_type(void)
-{
- type_register_static(&puv3_intc_info);
-}
-
-type_init(puv3_intc_register_type)
diff --git a/qemu/hw/intc/realview_gic.c b/qemu/hw/intc/realview_gic.c
deleted file mode 100644
index 50bbab66e..000000000
--- a/qemu/hw/intc/realview_gic.c
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * ARM RealView Emulation Baseboard Interrupt Controller
- *
- * Copyright (c) 2006-2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/intc/realview_gic.h"
-
-static void realview_gic_set_irq(void *opaque, int irq, int level)
-{
- RealViewGICState *s = (RealViewGICState *)opaque;
-
- qemu_set_irq(qdev_get_gpio_in(DEVICE(&s->gic), irq), level);
-}
-
-static void realview_gic_realize(DeviceState *dev, Error **errp)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- RealViewGICState *s = REALVIEW_GIC(dev);
- SysBusDevice *busdev;
- Error *err = NULL;
- /* The GICs on the RealView boards have a fixed nonconfigurable
- * number of interrupt lines, so we don't need to expose this as
- * a qdev property.
- */
- int numirq = 96;
-
- qdev_prop_set_uint32(DEVICE(&s->gic), "num-irq", numirq);
- object_property_set_bool(OBJECT(&s->gic), true, "realized", &err);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
- busdev = SYS_BUS_DEVICE(&s->gic);
-
- /* Pass through outbound IRQ lines from the GIC */
- sysbus_pass_irq(sbd, busdev);
-
- /* Pass through inbound GPIO lines to the GIC */
- qdev_init_gpio_in(dev, realview_gic_set_irq, numirq - 32);
-
- memory_region_add_subregion(&s->container, 0,
- sysbus_mmio_get_region(busdev, 1));
- memory_region_add_subregion(&s->container, 0x1000,
- sysbus_mmio_get_region(busdev, 0));
-}
-
-static void realview_gic_init(Object *obj)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- RealViewGICState *s = REALVIEW_GIC(obj);
- DeviceState *gicdev;
-
- memory_region_init(&s->container, OBJECT(s),
- "realview-gic-container", 0x2000);
- sysbus_init_mmio(sbd, &s->container);
-
- object_initialize(&s->gic, sizeof(s->gic), TYPE_ARM_GIC);
- gicdev = DEVICE(&s->gic);
- qdev_set_parent_bus(gicdev, sysbus_get_default());
- qdev_prop_set_uint32(gicdev, "num-cpu", 1);
-}
-
-static void realview_gic_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- dc->realize = realview_gic_realize;
-}
-
-static const TypeInfo realview_gic_info = {
- .name = TYPE_REALVIEW_GIC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(RealViewGICState),
- .instance_init = realview_gic_init,
- .class_init = realview_gic_class_init,
-};
-
-static void realview_gic_register_types(void)
-{
- type_register_static(&realview_gic_info);
-}
-
-type_init(realview_gic_register_types)
diff --git a/qemu/hw/intc/s390_flic.c b/qemu/hw/intc/s390_flic.c
deleted file mode 100644
index bc75fa7d9..000000000
--- a/qemu/hw/intc/s390_flic.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * QEMU S390x floating interrupt controller (flic)
- *
- * Copyright 2014 IBM Corp.
- * Author(s): Jens Freimann <jfrei@linux.vnet.ibm.com>
- * Cornelia Huck <cornelia.huck@de.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or (at
- * your option) any later version. See the COPYING file in the top-level
- * directory.
- */
-
-#include "qemu/osdep.h"
-#include "qemu/error-report.h"
-#include "hw/sysbus.h"
-#include "migration/qemu-file.h"
-#include "hw/s390x/s390_flic.h"
-#include "trace.h"
-
-S390FLICState *s390_get_flic(void)
-{
- S390FLICState *fs;
-
- fs = S390_FLIC_COMMON(object_resolve_path(TYPE_KVM_S390_FLIC, NULL));
- if (!fs) {
- fs = S390_FLIC_COMMON(object_resolve_path(TYPE_QEMU_S390_FLIC, NULL));
- }
- return fs;
-}
-
-void s390_flic_init(void)
-{
- DeviceState *dev;
-
- dev = s390_flic_kvm_create();
- if (!dev) {
- dev = qdev_create(NULL, TYPE_QEMU_S390_FLIC);
- object_property_add_child(qdev_get_machine(), TYPE_QEMU_S390_FLIC,
- OBJECT(dev), NULL);
- }
- qdev_init_nofail(dev);
-}
-
-static int qemu_s390_register_io_adapter(S390FLICState *fs, uint32_t id,
- uint8_t isc, bool swap,
- bool is_maskable)
-{
- /* nothing to do */
- return 0;
-}
-
-static int qemu_s390_io_adapter_map(S390FLICState *fs, uint32_t id,
- uint64_t map_addr, bool do_map)
-{
- /* nothing to do */
- return 0;
-}
-
-static int qemu_s390_add_adapter_routes(S390FLICState *fs,
- AdapterRoutes *routes)
-{
- return -ENOSYS;
-}
-
-static void qemu_s390_release_adapter_routes(S390FLICState *fs,
- AdapterRoutes *routes)
-{
-}
-
-static void qemu_s390_flic_class_init(ObjectClass *oc, void *data)
-{
- S390FLICStateClass *fsc = S390_FLIC_COMMON_CLASS(oc);
-
- fsc->register_io_adapter = qemu_s390_register_io_adapter;
- fsc->io_adapter_map = qemu_s390_io_adapter_map;
- fsc->add_adapter_routes = qemu_s390_add_adapter_routes;
- fsc->release_adapter_routes = qemu_s390_release_adapter_routes;
-}
-
-static const TypeInfo qemu_s390_flic_info = {
- .name = TYPE_QEMU_S390_FLIC,
- .parent = TYPE_S390_FLIC_COMMON,
- .instance_size = sizeof(QEMUS390FLICState),
- .class_init = qemu_s390_flic_class_init,
-};
-
-static const TypeInfo s390_flic_common_info = {
- .name = TYPE_S390_FLIC_COMMON,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(S390FLICState),
- .class_size = sizeof(S390FLICStateClass),
-};
-
-static void qemu_s390_flic_register_types(void)
-{
- type_register_static(&s390_flic_common_info);
- type_register_static(&qemu_s390_flic_info);
-}
-
-type_init(qemu_s390_flic_register_types)
diff --git a/qemu/hw/intc/s390_flic_kvm.c b/qemu/hw/intc/s390_flic_kvm.c
deleted file mode 100644
index 02449b390..000000000
--- a/qemu/hw/intc/s390_flic_kvm.c
+++ /dev/null
@@ -1,435 +0,0 @@
-/*
- * QEMU S390x KVM floating interrupt controller (flic)
- *
- * Copyright 2014 IBM Corp.
- * Author(s): Jens Freimann <jfrei@linux.vnet.ibm.com>
- * Cornelia Huck <cornelia.huck@de.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or (at
- * your option) any later version. See the COPYING file in the top-level
- * directory.
- */
-
-#include "qemu/osdep.h"
-#include <sys/ioctl.h>
-#include "qemu/error-report.h"
-#include "hw/sysbus.h"
-#include "sysemu/kvm.h"
-#include "migration/qemu-file.h"
-#include "hw/s390x/s390_flic.h"
-#include "hw/s390x/adapter.h"
-#include "trace.h"
-
-#define FLIC_SAVE_INITIAL_SIZE getpagesize()
-#define FLIC_FAILED (-1UL)
-#define FLIC_SAVEVM_VERSION 1
-
-typedef struct KVMS390FLICState {
- S390FLICState parent_obj;
-
- uint32_t fd;
-} KVMS390FLICState;
-
-DeviceState *s390_flic_kvm_create(void)
-{
- DeviceState *dev = NULL;
-
- if (kvm_enabled()) {
- dev = qdev_create(NULL, TYPE_KVM_S390_FLIC);
- object_property_add_child(qdev_get_machine(), TYPE_KVM_S390_FLIC,
- OBJECT(dev), NULL);
- }
- return dev;
-}
-
-/**
- * flic_get_all_irqs - store all pending irqs in buffer
- * @buf: pointer to buffer which is passed to kernel
- * @len: length of buffer
- * @flic: pointer to flic device state
- *
- * Returns: -ENOMEM if buffer is too small,
- * -EINVAL if attr.group is invalid,
- * -EFAULT if copying to userspace failed,
- * on success return number of stored interrupts
- */
-static int flic_get_all_irqs(KVMS390FLICState *flic,
- void *buf, int len)
-{
- struct kvm_device_attr attr = {
- .group = KVM_DEV_FLIC_GET_ALL_IRQS,
- .addr = (uint64_t) buf,
- .attr = len,
- };
- int rc;
-
- rc = ioctl(flic->fd, KVM_GET_DEVICE_ATTR, &attr);
-
- return rc == -1 ? -errno : rc;
-}
-
-static void flic_enable_pfault(KVMS390FLICState *flic)
-{
- struct kvm_device_attr attr = {
- .group = KVM_DEV_FLIC_APF_ENABLE,
- };
- int rc;
-
- rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
-
- if (rc) {
- fprintf(stderr, "flic: couldn't enable pfault\n");
- }
-}
-
-static void flic_disable_wait_pfault(KVMS390FLICState *flic)
-{
- struct kvm_device_attr attr = {
- .group = KVM_DEV_FLIC_APF_DISABLE_WAIT,
- };
- int rc;
-
- rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
-
- if (rc) {
- fprintf(stderr, "flic: couldn't disable pfault\n");
- }
-}
-
-/** flic_enqueue_irqs - returns 0 on success
- * @buf: pointer to buffer which is passed to kernel
- * @len: length of buffer
- * @flic: pointer to flic device state
- *
- * Returns: -EINVAL if attr.group is unknown
- */
-static int flic_enqueue_irqs(void *buf, uint64_t len,
- KVMS390FLICState *flic)
-{
- int rc;
- struct kvm_device_attr attr = {
- .group = KVM_DEV_FLIC_ENQUEUE,
- .addr = (uint64_t) buf,
- .attr = len,
- };
-
- rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
-
- return rc ? -errno : 0;
-}
-
-int kvm_s390_inject_flic(struct kvm_s390_irq *irq)
-{
- static KVMS390FLICState *flic;
-
- if (unlikely(!flic)) {
- flic = KVM_S390_FLIC(s390_get_flic());
- }
- return flic_enqueue_irqs(irq, sizeof(*irq), flic);
-}
-
-/**
- * __get_all_irqs - store all pending irqs in buffer
- * @flic: pointer to flic device state
- * @buf: pointer to pointer to a buffer
- * @len: length of buffer
- *
- * Returns: return value of flic_get_all_irqs
- * Note: Retry and increase buffer size until flic_get_all_irqs
- * either returns a value >= 0 or a negative error code.
- * -ENOMEM is an exception, which means the buffer is too small
- * and we should try again. Other negative error codes can be
- * -EFAULT and -EINVAL which we ignore at this point
- */
-static int __get_all_irqs(KVMS390FLICState *flic,
- void **buf, int len)
-{
- int r;
-
- do {
- /* returns -ENOMEM if buffer is too small and number
- * of queued interrupts on success */
- r = flic_get_all_irqs(flic, *buf, len);
- if (r >= 0) {
- break;
- }
- len *= 2;
- *buf = g_try_realloc(*buf, len);
- if (!buf) {
- return -ENOMEM;
- }
- } while (r == -ENOMEM && len <= KVM_S390_FLIC_MAX_BUFFER);
-
- return r;
-}
-
-static int kvm_s390_register_io_adapter(S390FLICState *fs, uint32_t id,
- uint8_t isc, bool swap,
- bool is_maskable)
-{
- struct kvm_s390_io_adapter adapter = {
- .id = id,
- .isc = isc,
- .maskable = is_maskable,
- .swap = swap,
- };
- KVMS390FLICState *flic = KVM_S390_FLIC(fs);
- int r, ret;
- struct kvm_device_attr attr = {
- .group = KVM_DEV_FLIC_ADAPTER_REGISTER,
- .addr = (uint64_t)&adapter,
- };
-
- if (!kvm_check_extension(kvm_state, KVM_CAP_IRQ_ROUTING)) {
- /* nothing to do */
- return 0;
- }
-
- r = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
-
- ret = r ? -errno : 0;
- return ret;
-}
-
-static int kvm_s390_io_adapter_map(S390FLICState *fs, uint32_t id,
- uint64_t map_addr, bool do_map)
-{
- struct kvm_s390_io_adapter_req req = {
- .id = id,
- .type = do_map ? KVM_S390_IO_ADAPTER_MAP : KVM_S390_IO_ADAPTER_UNMAP,
- .addr = map_addr,
- };
- struct kvm_device_attr attr = {
- .group = KVM_DEV_FLIC_ADAPTER_MODIFY,
- .addr = (uint64_t)&req,
- };
- KVMS390FLICState *flic = KVM_S390_FLIC(fs);
- int r;
-
- if (!kvm_check_extension(kvm_state, KVM_CAP_IRQ_ROUTING)) {
- /* nothing to do */
- return 0;
- }
-
- r = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
- return r ? -errno : 0;
-}
-
-static int kvm_s390_add_adapter_routes(S390FLICState *fs,
- AdapterRoutes *routes)
-{
- int ret, i;
- uint64_t ind_offset = routes->adapter.ind_offset;
-
- for (i = 0; i < routes->num_routes; i++) {
- ret = kvm_irqchip_add_adapter_route(kvm_state, &routes->adapter);
- if (ret < 0) {
- goto out_undo;
- }
- routes->gsi[i] = ret;
- routes->adapter.ind_offset++;
- }
- kvm_irqchip_commit_routes(kvm_state);
-
- /* Restore passed-in structure to original state. */
- routes->adapter.ind_offset = ind_offset;
- return 0;
-out_undo:
- while (--i >= 0) {
- kvm_irqchip_release_virq(kvm_state, routes->gsi[i]);
- routes->gsi[i] = -1;
- }
- routes->adapter.ind_offset = ind_offset;
- return ret;
-}
-
-static void kvm_s390_release_adapter_routes(S390FLICState *fs,
- AdapterRoutes *routes)
-{
- int i;
-
- for (i = 0; i < routes->num_routes; i++) {
- if (routes->gsi[i] >= 0) {
- kvm_irqchip_release_virq(kvm_state, routes->gsi[i]);
- routes->gsi[i] = -1;
- }
- }
-}
-
-/**
- * kvm_flic_save - Save pending floating interrupts
- * @f: QEMUFile containing migration state
- * @opaque: pointer to flic device state
- *
- * Note: Pass buf and len to kernel. Start with one page and
- * increase until buffer is sufficient or maxium size is
- * reached
- */
-static void kvm_flic_save(QEMUFile *f, void *opaque)
-{
- KVMS390FLICState *flic = opaque;
- int len = FLIC_SAVE_INITIAL_SIZE;
- void *buf;
- int count;
-
- flic_disable_wait_pfault((struct KVMS390FLICState *) opaque);
-
- buf = g_try_malloc0(len);
- if (!buf) {
- /* Storing FLIC_FAILED into the count field here will cause the
- * target system to fail when attempting to load irqs from the
- * migration state */
- error_report("flic: couldn't allocate memory");
- qemu_put_be64(f, FLIC_FAILED);
- return;
- }
-
- count = __get_all_irqs(flic, &buf, len);
- if (count < 0) {
- error_report("flic: couldn't retrieve irqs from kernel, rc %d",
- count);
- /* Storing FLIC_FAILED into the count field here will cause the
- * target system to fail when attempting to load irqs from the
- * migration state */
- qemu_put_be64(f, FLIC_FAILED);
- } else {
- qemu_put_be64(f, count);
- qemu_put_buffer(f, (uint8_t *) buf,
- count * sizeof(struct kvm_s390_irq));
- }
- g_free(buf);
-}
-
-/**
- * kvm_flic_load - Load pending floating interrupts
- * @f: QEMUFile containing migration state
- * @opaque: pointer to flic device state
- * @version_id: version id for migration
- *
- * Returns: value of flic_enqueue_irqs, -EINVAL on error
- * Note: Do nothing when no interrupts where stored
- * in QEMUFile
- */
-static int kvm_flic_load(QEMUFile *f, void *opaque, int version_id)
-{
- uint64_t len = 0;
- uint64_t count = 0;
- void *buf = NULL;
- int r = 0;
-
- if (version_id != FLIC_SAVEVM_VERSION) {
- r = -EINVAL;
- goto out;
- }
-
- flic_enable_pfault((struct KVMS390FLICState *) opaque);
-
- count = qemu_get_be64(f);
- len = count * sizeof(struct kvm_s390_irq);
- if (count == FLIC_FAILED) {
- r = -EINVAL;
- goto out;
- }
- if (count == 0) {
- r = 0;
- goto out;
- }
- buf = g_try_malloc0(len);
- if (!buf) {
- r = -ENOMEM;
- goto out;
- }
-
- if (qemu_get_buffer(f, (uint8_t *) buf, len) != len) {
- r = -EINVAL;
- goto out_free;
- }
- r = flic_enqueue_irqs(buf, len, (struct KVMS390FLICState *) opaque);
-
-out_free:
- g_free(buf);
-out:
- return r;
-}
-
-static void kvm_s390_flic_realize(DeviceState *dev, Error **errp)
-{
- KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
- struct kvm_create_device cd = {0};
- int ret;
-
- flic_state->fd = -1;
- if (!kvm_check_extension(kvm_state, KVM_CAP_DEVICE_CTRL)) {
- trace_flic_no_device_api(errno);
- return;
- }
-
- cd.type = KVM_DEV_TYPE_FLIC;
- ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd);
- if (ret < 0) {
- trace_flic_create_device(errno);
- return;
- }
- flic_state->fd = cd.fd;
-
- /* Register savevm handler for floating interrupts */
- register_savevm(NULL, "s390-flic", 0, 1, kvm_flic_save,
- kvm_flic_load, (void *) flic_state);
-}
-
-static void kvm_s390_flic_unrealize(DeviceState *dev, Error **errp)
-{
- KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
-
- unregister_savevm(DEVICE(flic_state), "s390-flic", flic_state);
-}
-
-static void kvm_s390_flic_reset(DeviceState *dev)
-{
- KVMS390FLICState *flic = KVM_S390_FLIC(dev);
- struct kvm_device_attr attr = {
- .group = KVM_DEV_FLIC_CLEAR_IRQS,
- };
- int rc = 0;
-
- if (flic->fd == -1) {
- return;
- }
-
- flic_disable_wait_pfault(flic);
-
- rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
- if (rc) {
- trace_flic_reset_failed(errno);
- }
-
- flic_enable_pfault(flic);
-}
-
-static void kvm_s390_flic_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
- S390FLICStateClass *fsc = S390_FLIC_COMMON_CLASS(oc);
-
- dc->realize = kvm_s390_flic_realize;
- dc->unrealize = kvm_s390_flic_unrealize;
- dc->reset = kvm_s390_flic_reset;
- fsc->register_io_adapter = kvm_s390_register_io_adapter;
- fsc->io_adapter_map = kvm_s390_io_adapter_map;
- fsc->add_adapter_routes = kvm_s390_add_adapter_routes;
- fsc->release_adapter_routes = kvm_s390_release_adapter_routes;
-}
-
-static const TypeInfo kvm_s390_flic_info = {
- .name = TYPE_KVM_S390_FLIC,
- .parent = TYPE_S390_FLIC_COMMON,
- .instance_size = sizeof(KVMS390FLICState),
- .class_init = kvm_s390_flic_class_init,
-};
-
-static void kvm_s390_flic_register_types(void)
-{
- type_register_static(&kvm_s390_flic_info);
-}
-
-type_init(kvm_s390_flic_register_types)
diff --git a/qemu/hw/intc/sh_intc.c b/qemu/hw/intc/sh_intc.c
deleted file mode 100644
index 6ce2a8084..000000000
--- a/qemu/hw/intc/sh_intc.c
+++ /dev/null
@@ -1,515 +0,0 @@
-/*
- * SuperH interrupt controller module
- *
- * Copyright (c) 2007 Magnus Damm
- * Based on sh_timer.c and arm_timer.c by Paul Brook
- * Copyright (c) 2005-2006 CodeSourcery.
- *
- * This code is licensed under the GPL.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/sh4/sh_intc.h"
-#include "hw/hw.h"
-#include "hw/sh4/sh.h"
-
-//#define DEBUG_INTC
-//#define DEBUG_INTC_SOURCES
-
-#define INTC_A7(x) ((x) & 0x1fffffff)
-
-void sh_intc_toggle_source(struct intc_source *source,
- int enable_adj, int assert_adj)
-{
- int enable_changed = 0;
- int pending_changed = 0;
- int old_pending;
-
- if ((source->enable_count == source->enable_max) && (enable_adj == -1))
- enable_changed = -1;
-
- source->enable_count += enable_adj;
-
- if (source->enable_count == source->enable_max)
- enable_changed = 1;
-
- source->asserted += assert_adj;
-
- old_pending = source->pending;
- source->pending = source->asserted &&
- (source->enable_count == source->enable_max);
-
- if (old_pending != source->pending)
- pending_changed = 1;
-
- if (pending_changed) {
- if (source->pending) {
- source->parent->pending++;
- if (source->parent->pending == 1) {
- cpu_interrupt(first_cpu, CPU_INTERRUPT_HARD);
- }
- } else {
- source->parent->pending--;
- if (source->parent->pending == 0) {
- cpu_reset_interrupt(first_cpu, CPU_INTERRUPT_HARD);
- }
- }
- }
-
- if (enable_changed || assert_adj || pending_changed) {
-#ifdef DEBUG_INTC_SOURCES
- printf("sh_intc: (%d/%d/%d/%d) interrupt source 0x%x %s%s%s\n",
- source->parent->pending,
- source->asserted,
- source->enable_count,
- source->enable_max,
- source->vect,
- source->asserted ? "asserted " :
- assert_adj ? "deasserted" : "",
- enable_changed == 1 ? "enabled " :
- enable_changed == -1 ? "disabled " : "",
- source->pending ? "pending" : "");
-#endif
- }
-}
-
-static void sh_intc_set_irq (void *opaque, int n, int level)
-{
- struct intc_desc *desc = opaque;
- struct intc_source *source = &(desc->sources[n]);
-
- if (level && !source->asserted)
- sh_intc_toggle_source(source, 0, 1);
- else if (!level && source->asserted)
- sh_intc_toggle_source(source, 0, -1);
-}
-
-int sh_intc_get_pending_vector(struct intc_desc *desc, int imask)
-{
- unsigned int i;
-
- /* slow: use a linked lists of pending sources instead */
- /* wrong: take interrupt priority into account (one list per priority) */
-
- if (imask == 0x0f) {
- return -1; /* FIXME, update code to include priority per source */
- }
-
- for (i = 0; i < desc->nr_sources; i++) {
- struct intc_source *source = desc->sources + i;
-
- if (source->pending) {
-#ifdef DEBUG_INTC_SOURCES
- printf("sh_intc: (%d) returning interrupt source 0x%x\n",
- desc->pending, source->vect);
-#endif
- return source->vect;
- }
- }
-
- abort();
-}
-
-#define INTC_MODE_NONE 0
-#define INTC_MODE_DUAL_SET 1
-#define INTC_MODE_DUAL_CLR 2
-#define INTC_MODE_ENABLE_REG 3
-#define INTC_MODE_MASK_REG 4
-#define INTC_MODE_IS_PRIO 8
-
-static unsigned int sh_intc_mode(unsigned long address,
- unsigned long set_reg, unsigned long clr_reg)
-{
- if ((address != INTC_A7(set_reg)) &&
- (address != INTC_A7(clr_reg)))
- return INTC_MODE_NONE;
-
- if (set_reg && clr_reg) {
- if (address == INTC_A7(set_reg))
- return INTC_MODE_DUAL_SET;
- else
- return INTC_MODE_DUAL_CLR;
- }
-
- if (set_reg)
- return INTC_MODE_ENABLE_REG;
- else
- return INTC_MODE_MASK_REG;
-}
-
-static void sh_intc_locate(struct intc_desc *desc,
- unsigned long address,
- unsigned long **datap,
- intc_enum **enums,
- unsigned int *first,
- unsigned int *width,
- unsigned int *modep)
-{
- unsigned int i, mode;
-
- /* this is slow but works for now */
-
- if (desc->mask_regs) {
- for (i = 0; i < desc->nr_mask_regs; i++) {
- struct intc_mask_reg *mr = desc->mask_regs + i;
-
- mode = sh_intc_mode(address, mr->set_reg, mr->clr_reg);
- if (mode == INTC_MODE_NONE)
- continue;
-
- *modep = mode;
- *datap = &mr->value;
- *enums = mr->enum_ids;
- *first = mr->reg_width - 1;
- *width = 1;
- return;
- }
- }
-
- if (desc->prio_regs) {
- for (i = 0; i < desc->nr_prio_regs; i++) {
- struct intc_prio_reg *pr = desc->prio_regs + i;
-
- mode = sh_intc_mode(address, pr->set_reg, pr->clr_reg);
- if (mode == INTC_MODE_NONE)
- continue;
-
- *modep = mode | INTC_MODE_IS_PRIO;
- *datap = &pr->value;
- *enums = pr->enum_ids;
- *first = (pr->reg_width / pr->field_width) - 1;
- *width = pr->field_width;
- return;
- }
- }
-
- abort();
-}
-
-static void sh_intc_toggle_mask(struct intc_desc *desc, intc_enum id,
- int enable, int is_group)
-{
- struct intc_source *source = desc->sources + id;
-
- if (!id)
- return;
-
- if (!source->next_enum_id && (!source->enable_max || !source->vect)) {
-#ifdef DEBUG_INTC_SOURCES
- printf("sh_intc: reserved interrupt source %d modified\n", id);
-#endif
- return;
- }
-
- if (source->vect)
- sh_intc_toggle_source(source, enable ? 1 : -1, 0);
-
-#ifdef DEBUG_INTC
- else {
- printf("setting interrupt group %d to %d\n", id, !!enable);
- }
-#endif
-
- if ((is_group || !source->vect) && source->next_enum_id) {
- sh_intc_toggle_mask(desc, source->next_enum_id, enable, 1);
- }
-
-#ifdef DEBUG_INTC
- if (!source->vect) {
- printf("setting interrupt group %d to %d - done\n", id, !!enable);
- }
-#endif
-}
-
-static uint64_t sh_intc_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- struct intc_desc *desc = opaque;
- intc_enum *enum_ids = NULL;
- unsigned int first = 0;
- unsigned int width = 0;
- unsigned int mode = 0;
- unsigned long *valuep;
-
-#ifdef DEBUG_INTC
- printf("sh_intc_read 0x%lx\n", (unsigned long) offset);
-#endif
-
- sh_intc_locate(desc, (unsigned long)offset, &valuep,
- &enum_ids, &first, &width, &mode);
- return *valuep;
-}
-
-static void sh_intc_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- struct intc_desc *desc = opaque;
- intc_enum *enum_ids = NULL;
- unsigned int first = 0;
- unsigned int width = 0;
- unsigned int mode = 0;
- unsigned int k;
- unsigned long *valuep;
- unsigned long mask;
-
-#ifdef DEBUG_INTC
- printf("sh_intc_write 0x%lx 0x%08x\n", (unsigned long) offset, value);
-#endif
-
- sh_intc_locate(desc, (unsigned long)offset, &valuep,
- &enum_ids, &first, &width, &mode);
-
- switch (mode) {
- case INTC_MODE_ENABLE_REG | INTC_MODE_IS_PRIO: break;
- case INTC_MODE_DUAL_SET: value |= *valuep; break;
- case INTC_MODE_DUAL_CLR: value = *valuep & ~value; break;
- default: abort();
- }
-
- for (k = 0; k <= first; k++) {
- mask = ((1 << width) - 1) << ((first - k) * width);
-
- if ((*valuep & mask) == (value & mask))
- continue;
-#if 0
- printf("k = %d, first = %d, enum = %d, mask = 0x%08x\n",
- k, first, enum_ids[k], (unsigned int)mask);
-#endif
- sh_intc_toggle_mask(desc, enum_ids[k], value & mask, 0);
- }
-
- *valuep = value;
-
-#ifdef DEBUG_INTC
- printf("sh_intc_write 0x%lx -> 0x%08x\n", (unsigned long) offset, value);
-#endif
-}
-
-static const MemoryRegionOps sh_intc_ops = {
- .read = sh_intc_read,
- .write = sh_intc_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct intc_source *sh_intc_source(struct intc_desc *desc, intc_enum id)
-{
- if (id)
- return desc->sources + id;
-
- return NULL;
-}
-
-static unsigned int sh_intc_register(MemoryRegion *sysmem,
- struct intc_desc *desc,
- const unsigned long address,
- const char *type,
- const char *action,
- const unsigned int index)
-{
- char name[60];
- MemoryRegion *iomem, *iomem_p4, *iomem_a7;
-
- if (!address) {
- return 0;
- }
-
- iomem = &desc->iomem;
- iomem_p4 = desc->iomem_aliases + index;
- iomem_a7 = iomem_p4 + 1;
-
-#define SH_INTC_IOMEM_FORMAT "interrupt-controller-%s-%s-%s"
- snprintf(name, sizeof(name), SH_INTC_IOMEM_FORMAT, type, action, "p4");
- memory_region_init_alias(iomem_p4, NULL, name, iomem, INTC_A7(address), 4);
- memory_region_add_subregion(sysmem, P4ADDR(address), iomem_p4);
-
- snprintf(name, sizeof(name), SH_INTC_IOMEM_FORMAT, type, action, "a7");
- memory_region_init_alias(iomem_a7, NULL, name, iomem, INTC_A7(address), 4);
- memory_region_add_subregion(sysmem, A7ADDR(address), iomem_a7);
-#undef SH_INTC_IOMEM_FORMAT
-
- /* used to increment aliases index */
- return 2;
-}
-
-static void sh_intc_register_source(struct intc_desc *desc,
- intc_enum source,
- struct intc_group *groups,
- int nr_groups)
-{
- unsigned int i, k;
- struct intc_source *s;
-
- if (desc->mask_regs) {
- for (i = 0; i < desc->nr_mask_regs; i++) {
- struct intc_mask_reg *mr = desc->mask_regs + i;
-
- for (k = 0; k < ARRAY_SIZE(mr->enum_ids); k++) {
- if (mr->enum_ids[k] != source)
- continue;
-
- s = sh_intc_source(desc, mr->enum_ids[k]);
- if (s)
- s->enable_max++;
- }
- }
- }
-
- if (desc->prio_regs) {
- for (i = 0; i < desc->nr_prio_regs; i++) {
- struct intc_prio_reg *pr = desc->prio_regs + i;
-
- for (k = 0; k < ARRAY_SIZE(pr->enum_ids); k++) {
- if (pr->enum_ids[k] != source)
- continue;
-
- s = sh_intc_source(desc, pr->enum_ids[k]);
- if (s)
- s->enable_max++;
- }
- }
- }
-
- if (groups) {
- for (i = 0; i < nr_groups; i++) {
- struct intc_group *gr = groups + i;
-
- for (k = 0; k < ARRAY_SIZE(gr->enum_ids); k++) {
- if (gr->enum_ids[k] != source)
- continue;
-
- s = sh_intc_source(desc, gr->enum_ids[k]);
- if (s)
- s->enable_max++;
- }
- }
- }
-
-}
-
-void sh_intc_register_sources(struct intc_desc *desc,
- struct intc_vect *vectors,
- int nr_vectors,
- struct intc_group *groups,
- int nr_groups)
-{
- unsigned int i, k;
- struct intc_source *s;
-
- for (i = 0; i < nr_vectors; i++) {
- struct intc_vect *vect = vectors + i;
-
- sh_intc_register_source(desc, vect->enum_id, groups, nr_groups);
- s = sh_intc_source(desc, vect->enum_id);
- if (s) {
- s->vect = vect->vect;
-
-#ifdef DEBUG_INTC_SOURCES
- printf("sh_intc: registered source %d -> 0x%04x (%d/%d)\n",
- vect->enum_id, s->vect, s->enable_count, s->enable_max);
-#endif
- }
- }
-
- if (groups) {
- for (i = 0; i < nr_groups; i++) {
- struct intc_group *gr = groups + i;
-
- s = sh_intc_source(desc, gr->enum_id);
- s->next_enum_id = gr->enum_ids[0];
-
- for (k = 1; k < ARRAY_SIZE(gr->enum_ids); k++) {
- if (!gr->enum_ids[k])
- continue;
-
- s = sh_intc_source(desc, gr->enum_ids[k - 1]);
- s->next_enum_id = gr->enum_ids[k];
- }
-
-#ifdef DEBUG_INTC_SOURCES
- printf("sh_intc: registered group %d (%d/%d)\n",
- gr->enum_id, s->enable_count, s->enable_max);
-#endif
- }
- }
-}
-
-int sh_intc_init(MemoryRegion *sysmem,
- struct intc_desc *desc,
- int nr_sources,
- struct intc_mask_reg *mask_regs,
- int nr_mask_regs,
- struct intc_prio_reg *prio_regs,
- int nr_prio_regs)
-{
- unsigned int i, j;
-
- desc->pending = 0;
- desc->nr_sources = nr_sources;
- desc->mask_regs = mask_regs;
- desc->nr_mask_regs = nr_mask_regs;
- desc->prio_regs = prio_regs;
- desc->nr_prio_regs = nr_prio_regs;
- /* Allocate 4 MemoryRegions per register (2 actions * 2 aliases).
- **/
- desc->iomem_aliases = g_new0(MemoryRegion,
- (nr_mask_regs + nr_prio_regs) * 4);
-
- j = 0;
- i = sizeof(struct intc_source) * nr_sources;
- desc->sources = g_malloc0(i);
-
- for (i = 0; i < desc->nr_sources; i++) {
- struct intc_source *source = desc->sources + i;
-
- source->parent = desc;
- }
-
- desc->irqs = qemu_allocate_irqs(sh_intc_set_irq, desc, nr_sources);
-
- memory_region_init_io(&desc->iomem, NULL, &sh_intc_ops, desc,
- "interrupt-controller", 0x100000000ULL);
-
-#define INT_REG_PARAMS(reg_struct, type, action, j) \
- reg_struct->action##_reg, #type, #action, j
- if (desc->mask_regs) {
- for (i = 0; i < desc->nr_mask_regs; i++) {
- struct intc_mask_reg *mr = desc->mask_regs + i;
-
- j += sh_intc_register(sysmem, desc,
- INT_REG_PARAMS(mr, mask, set, j));
- j += sh_intc_register(sysmem, desc,
- INT_REG_PARAMS(mr, mask, clr, j));
- }
- }
-
- if (desc->prio_regs) {
- for (i = 0; i < desc->nr_prio_regs; i++) {
- struct intc_prio_reg *pr = desc->prio_regs + i;
-
- j += sh_intc_register(sysmem, desc,
- INT_REG_PARAMS(pr, prio, set, j));
- j += sh_intc_register(sysmem, desc,
- INT_REG_PARAMS(pr, prio, clr, j));
- }
- }
-#undef INT_REG_PARAMS
-
- return 0;
-}
-
-/* Assert level <n> IRL interrupt.
- 0:deassert. 1:lowest priority,... 15:highest priority. */
-void sh_intc_set_irl(void *opaque, int n, int level)
-{
- struct intc_source *s = opaque;
- int i, irl = level ^ 15;
- for (i = 0; (s = sh_intc_source(s->parent, s->next_enum_id)); i++) {
- if (i == irl)
- sh_intc_toggle_source(s, s->enable_count?0:1, s->asserted?0:1);
- else
- if (s->asserted)
- sh_intc_toggle_source(s, 0, -1);
- }
-}
diff --git a/qemu/hw/intc/slavio_intctl.c b/qemu/hw/intc/slavio_intctl.c
deleted file mode 100644
index c9486ed99..000000000
--- a/qemu/hw/intc/slavio_intctl.c
+++ /dev/null
@@ -1,472 +0,0 @@
-/*
- * QEMU Sparc SLAVIO interrupt controller emulation
- *
- * Copyright (c) 2003-2005 Fabrice Bellard
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sparc/sun4m.h"
-#include "monitor/monitor.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-
-//#define DEBUG_IRQ_COUNT
-
-/*
- * Registers of interrupt controller in sun4m.
- *
- * This is the interrupt controller part of chip STP2001 (Slave I/O), also
- * produced as NCR89C105. See
- * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
- *
- * There is a system master controller and one for each cpu.
- *
- */
-
-#define MAX_CPUS 16
-#define MAX_PILS 16
-
-struct SLAVIO_INTCTLState;
-
-typedef struct SLAVIO_CPUINTCTLState {
- MemoryRegion iomem;
- struct SLAVIO_INTCTLState *master;
- uint32_t intreg_pending;
- uint32_t cpu;
- uint32_t irl_out;
-} SLAVIO_CPUINTCTLState;
-
-#define TYPE_SLAVIO_INTCTL "slavio_intctl"
-#define SLAVIO_INTCTL(obj) \
- OBJECT_CHECK(SLAVIO_INTCTLState, (obj), TYPE_SLAVIO_INTCTL)
-
-typedef struct SLAVIO_INTCTLState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
-#ifdef DEBUG_IRQ_COUNT
- uint64_t irq_count[32];
-#endif
- qemu_irq cpu_irqs[MAX_CPUS][MAX_PILS];
- SLAVIO_CPUINTCTLState slaves[MAX_CPUS];
- uint32_t intregm_pending;
- uint32_t intregm_disabled;
- uint32_t target_cpu;
-} SLAVIO_INTCTLState;
-
-#define INTCTL_MAXADDR 0xf
-#define INTCTL_SIZE (INTCTL_MAXADDR + 1)
-#define INTCTLM_SIZE 0x14
-#define MASTER_IRQ_MASK ~0x0fa2007f
-#define MASTER_DISABLE 0x80000000
-#define CPU_SOFTIRQ_MASK 0xfffe0000
-#define CPU_IRQ_INT15_IN (1 << 15)
-#define CPU_IRQ_TIMER_IN (1 << 14)
-
-static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs);
-
-// per-cpu interrupt controller
-static uint64_t slavio_intctl_mem_readl(void *opaque, hwaddr addr,
- unsigned size)
-{
- SLAVIO_CPUINTCTLState *s = opaque;
- uint32_t saddr, ret;
-
- saddr = addr >> 2;
- switch (saddr) {
- case 0:
- ret = s->intreg_pending;
- break;
- default:
- ret = 0;
- break;
- }
- trace_slavio_intctl_mem_readl(s->cpu, addr, ret);
-
- return ret;
-}
-
-static void slavio_intctl_mem_writel(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- SLAVIO_CPUINTCTLState *s = opaque;
- uint32_t saddr;
-
- saddr = addr >> 2;
- trace_slavio_intctl_mem_writel(s->cpu, addr, val);
- switch (saddr) {
- case 1: // clear pending softints
- val &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN;
- s->intreg_pending &= ~val;
- slavio_check_interrupts(s->master, 1);
- trace_slavio_intctl_mem_writel_clear(s->cpu, val, s->intreg_pending);
- break;
- case 2: // set softint
- val &= CPU_SOFTIRQ_MASK;
- s->intreg_pending |= val;
- slavio_check_interrupts(s->master, 1);
- trace_slavio_intctl_mem_writel_set(s->cpu, val, s->intreg_pending);
- break;
- default:
- break;
- }
-}
-
-static const MemoryRegionOps slavio_intctl_mem_ops = {
- .read = slavio_intctl_mem_readl,
- .write = slavio_intctl_mem_writel,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-// master system interrupt controller
-static uint64_t slavio_intctlm_mem_readl(void *opaque, hwaddr addr,
- unsigned size)
-{
- SLAVIO_INTCTLState *s = opaque;
- uint32_t saddr, ret;
-
- saddr = addr >> 2;
- switch (saddr) {
- case 0:
- ret = s->intregm_pending & ~MASTER_DISABLE;
- break;
- case 1:
- ret = s->intregm_disabled & MASTER_IRQ_MASK;
- break;
- case 4:
- ret = s->target_cpu;
- break;
- default:
- ret = 0;
- break;
- }
- trace_slavio_intctlm_mem_readl(addr, ret);
-
- return ret;
-}
-
-static void slavio_intctlm_mem_writel(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- SLAVIO_INTCTLState *s = opaque;
- uint32_t saddr;
-
- saddr = addr >> 2;
- trace_slavio_intctlm_mem_writel(addr, val);
- switch (saddr) {
- case 2: // clear (enable)
- // Force clear unused bits
- val &= MASTER_IRQ_MASK;
- s->intregm_disabled &= ~val;
- trace_slavio_intctlm_mem_writel_enable(val, s->intregm_disabled);
- slavio_check_interrupts(s, 1);
- break;
- case 3: // set (disable; doesn't affect pending)
- // Force clear unused bits
- val &= MASTER_IRQ_MASK;
- s->intregm_disabled |= val;
- slavio_check_interrupts(s, 1);
- trace_slavio_intctlm_mem_writel_disable(val, s->intregm_disabled);
- break;
- case 4:
- s->target_cpu = val & (MAX_CPUS - 1);
- slavio_check_interrupts(s, 1);
- trace_slavio_intctlm_mem_writel_target(s->target_cpu);
- break;
- default:
- break;
- }
-}
-
-static const MemoryRegionOps slavio_intctlm_mem_ops = {
- .read = slavio_intctlm_mem_readl,
- .write = slavio_intctlm_mem_writel,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-void slavio_pic_info(Monitor *mon, DeviceState *dev)
-{
- SLAVIO_INTCTLState *s = SLAVIO_INTCTL(dev);
- int i;
-
- for (i = 0; i < MAX_CPUS; i++) {
- monitor_printf(mon, "per-cpu %d: pending 0x%08x\n", i,
- s->slaves[i].intreg_pending);
- }
- monitor_printf(mon, "master: pending 0x%08x, disabled 0x%08x\n",
- s->intregm_pending, s->intregm_disabled);
-}
-
-void slavio_irq_info(Monitor *mon, DeviceState *dev)
-{
-#ifndef DEBUG_IRQ_COUNT
- monitor_printf(mon, "irq statistic code not compiled.\n");
-#else
- SLAVIO_INTCTLState *s = SLAVIO_INTCTL(dev);
- int i;
- int64_t count;
-
- s = SLAVIO_INTCTL(dev);
- monitor_printf(mon, "IRQ statistics:\n");
- for (i = 0; i < 32; i++) {
- count = s->irq_count[i];
- if (count > 0)
- monitor_printf(mon, "%2d: %" PRId64 "\n", i, count);
- }
-#endif
-}
-
-static const uint32_t intbit_to_level[] = {
- 2, 3, 5, 7, 9, 11, 13, 2, 3, 5, 7, 9, 11, 13, 12, 12,
- 6, 13, 4, 10, 8, 9, 11, 0, 0, 0, 0, 15, 15, 15, 15, 0,
-};
-
-static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs)
-{
- uint32_t pending = s->intregm_pending, pil_pending;
- unsigned int i, j;
-
- pending &= ~s->intregm_disabled;
-
- trace_slavio_check_interrupts(pending, s->intregm_disabled);
- for (i = 0; i < MAX_CPUS; i++) {
- pil_pending = 0;
-
- /* If we are the current interrupt target, get hard interrupts */
- if (pending && !(s->intregm_disabled & MASTER_DISABLE) &&
- (i == s->target_cpu)) {
- for (j = 0; j < 32; j++) {
- if ((pending & (1 << j)) && intbit_to_level[j]) {
- pil_pending |= 1 << intbit_to_level[j];
- }
- }
- }
-
- /* Calculate current pending hard interrupts for display */
- s->slaves[i].intreg_pending &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN |
- CPU_IRQ_TIMER_IN;
- if (i == s->target_cpu) {
- for (j = 0; j < 32; j++) {
- if ((s->intregm_pending & (1U << j)) && intbit_to_level[j]) {
- s->slaves[i].intreg_pending |= 1 << intbit_to_level[j];
- }
- }
- }
-
- /* Level 15 and CPU timer interrupts are only masked when
- the MASTER_DISABLE bit is set */
- if (!(s->intregm_disabled & MASTER_DISABLE)) {
- pil_pending |= s->slaves[i].intreg_pending &
- (CPU_IRQ_INT15_IN | CPU_IRQ_TIMER_IN);
- }
-
- /* Add soft interrupts */
- pil_pending |= (s->slaves[i].intreg_pending & CPU_SOFTIRQ_MASK) >> 16;
-
- if (set_irqs) {
- /* Since there is not really an interrupt 0 (and pil_pending
- * and irl_out bit zero are thus always zero) there is no need
- * to do anything with cpu_irqs[i][0] and it is OK not to do
- * the j=0 iteration of this loop.
- */
- for (j = MAX_PILS-1; j > 0; j--) {
- if (pil_pending & (1 << j)) {
- if (!(s->slaves[i].irl_out & (1 << j))) {
- qemu_irq_raise(s->cpu_irqs[i][j]);
- }
- } else {
- if (s->slaves[i].irl_out & (1 << j)) {
- qemu_irq_lower(s->cpu_irqs[i][j]);
- }
- }
- }
- }
- s->slaves[i].irl_out = pil_pending;
- }
-}
-
-/*
- * "irq" here is the bit number in the system interrupt register to
- * separate serial and keyboard interrupts sharing a level.
- */
-static void slavio_set_irq(void *opaque, int irq, int level)
-{
- SLAVIO_INTCTLState *s = opaque;
- uint32_t mask = 1 << irq;
- uint32_t pil = intbit_to_level[irq];
- unsigned int i;
-
- trace_slavio_set_irq(s->target_cpu, irq, pil, level);
- if (pil > 0) {
- if (level) {
-#ifdef DEBUG_IRQ_COUNT
- s->irq_count[pil]++;
-#endif
- s->intregm_pending |= mask;
- if (pil == 15) {
- for (i = 0; i < MAX_CPUS; i++) {
- s->slaves[i].intreg_pending |= 1 << pil;
- }
- }
- } else {
- s->intregm_pending &= ~mask;
- if (pil == 15) {
- for (i = 0; i < MAX_CPUS; i++) {
- s->slaves[i].intreg_pending &= ~(1 << pil);
- }
- }
- }
- slavio_check_interrupts(s, 1);
- }
-}
-
-static void slavio_set_timer_irq_cpu(void *opaque, int cpu, int level)
-{
- SLAVIO_INTCTLState *s = opaque;
-
- trace_slavio_set_timer_irq_cpu(cpu, level);
-
- if (level) {
- s->slaves[cpu].intreg_pending |= CPU_IRQ_TIMER_IN;
- } else {
- s->slaves[cpu].intreg_pending &= ~CPU_IRQ_TIMER_IN;
- }
-
- slavio_check_interrupts(s, 1);
-}
-
-static void slavio_set_irq_all(void *opaque, int irq, int level)
-{
- if (irq < 32) {
- slavio_set_irq(opaque, irq, level);
- } else {
- slavio_set_timer_irq_cpu(opaque, irq - 32, level);
- }
-}
-
-static int vmstate_intctl_post_load(void *opaque, int version_id)
-{
- SLAVIO_INTCTLState *s = opaque;
-
- slavio_check_interrupts(s, 0);
- return 0;
-}
-
-static const VMStateDescription vmstate_intctl_cpu = {
- .name ="slavio_intctl_cpu",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(intreg_pending, SLAVIO_CPUINTCTLState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_intctl = {
- .name ="slavio_intctl",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = vmstate_intctl_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT_ARRAY(slaves, SLAVIO_INTCTLState, MAX_CPUS, 1,
- vmstate_intctl_cpu, SLAVIO_CPUINTCTLState),
- VMSTATE_UINT32(intregm_pending, SLAVIO_INTCTLState),
- VMSTATE_UINT32(intregm_disabled, SLAVIO_INTCTLState),
- VMSTATE_UINT32(target_cpu, SLAVIO_INTCTLState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void slavio_intctl_reset(DeviceState *d)
-{
- SLAVIO_INTCTLState *s = SLAVIO_INTCTL(d);
- int i;
-
- for (i = 0; i < MAX_CPUS; i++) {
- s->slaves[i].intreg_pending = 0;
- s->slaves[i].irl_out = 0;
- }
- s->intregm_disabled = ~MASTER_IRQ_MASK;
- s->intregm_pending = 0;
- s->target_cpu = 0;
- slavio_check_interrupts(s, 0);
-}
-
-static int slavio_intctl_init1(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- SLAVIO_INTCTLState *s = SLAVIO_INTCTL(dev);
- unsigned int i, j;
- char slave_name[45];
-
- qdev_init_gpio_in(dev, slavio_set_irq_all, 32 + MAX_CPUS);
- memory_region_init_io(&s->iomem, OBJECT(s), &slavio_intctlm_mem_ops, s,
- "master-interrupt-controller", INTCTLM_SIZE);
- sysbus_init_mmio(sbd, &s->iomem);
-
- for (i = 0; i < MAX_CPUS; i++) {
- snprintf(slave_name, sizeof(slave_name),
- "slave-interrupt-controller-%i", i);
- for (j = 0; j < MAX_PILS; j++) {
- sysbus_init_irq(sbd, &s->cpu_irqs[i][j]);
- }
- memory_region_init_io(&s->slaves[i].iomem, OBJECT(s),
- &slavio_intctl_mem_ops,
- &s->slaves[i], slave_name, INTCTL_SIZE);
- sysbus_init_mmio(sbd, &s->slaves[i].iomem);
- s->slaves[i].cpu = i;
- s->slaves[i].master = s;
- }
-
- return 0;
-}
-
-static void slavio_intctl_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = slavio_intctl_init1;
- dc->reset = slavio_intctl_reset;
- dc->vmsd = &vmstate_intctl;
-}
-
-static const TypeInfo slavio_intctl_info = {
- .name = TYPE_SLAVIO_INTCTL,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(SLAVIO_INTCTLState),
- .class_init = slavio_intctl_class_init,
-};
-
-static void slavio_intctl_register_types(void)
-{
- type_register_static(&slavio_intctl_info);
-}
-
-type_init(slavio_intctl_register_types)
diff --git a/qemu/hw/intc/vgic_common.h b/qemu/hw/intc/vgic_common.h
deleted file mode 100644
index 80d919eb9..000000000
--- a/qemu/hw/intc/vgic_common.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * ARM KVM vGIC utility functions
- *
- * Copyright (c) 2015 Samsung Electronics
- * Written by Pavel Fedin
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef QEMU_ARM_VGIC_COMMON_H
-#define QEMU_ARM_VGIC_COMMON_H
-
-/**
- * kvm_arm_gic_set_irq - Send an IRQ to the in-kernel vGIC
- * @num_irq: Total number of IRQs configured for the GIC instance
- * @irq: qemu internal IRQ line number:
- * [0..N-1] : external interrupts
- * [N..N+31] : PPI (internal) interrupts for CPU 0
- * [N+32..N+63] : PPI (internal interrupts for CPU 1
- * @level: level of the IRQ line.
- */
-void kvm_arm_gic_set_irq(uint32_t num_irq, int irq, int level);
-
-#endif
diff --git a/qemu/hw/intc/xics.c b/qemu/hw/intc/xics.c
deleted file mode 100644
index 8659be017..000000000
--- a/qemu/hw/intc/xics.c
+++ /dev/null
@@ -1,1093 +0,0 @@
-/*
- * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
- *
- * PAPR Virtualized Interrupt System, aka ICS/ICP aka xics
- *
- * Copyright (c) 2010,2011 David Gibson, IBM Corporation.
- *
- * 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.
- *
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/hw.h"
-#include "trace.h"
-#include "qemu/timer.h"
-#include "hw/ppc/spapr.h"
-#include "hw/ppc/xics.h"
-#include "qemu/error-report.h"
-#include "qapi/visitor.h"
-
-static int get_cpu_index_by_dt_id(int cpu_dt_id)
-{
- PowerPCCPU *cpu = ppc_get_vcpu_by_dt_id(cpu_dt_id);
-
- if (cpu) {
- return cpu->parent_obj.cpu_index;
- }
-
- return -1;
-}
-
-void xics_cpu_setup(XICSState *icp, PowerPCCPU *cpu)
-{
- CPUState *cs = CPU(cpu);
- CPUPPCState *env = &cpu->env;
- ICPState *ss = &icp->ss[cs->cpu_index];
- XICSStateClass *info = XICS_COMMON_GET_CLASS(icp);
-
- assert(cs->cpu_index < icp->nr_servers);
-
- if (info->cpu_setup) {
- info->cpu_setup(icp, cpu);
- }
-
- switch (PPC_INPUT(env)) {
- case PPC_FLAGS_INPUT_POWER7:
- ss->output = env->irq_inputs[POWER7_INPUT_INT];
- break;
-
- case PPC_FLAGS_INPUT_970:
- ss->output = env->irq_inputs[PPC970_INPUT_INT];
- break;
-
- default:
- error_report("XICS interrupt controller does not support this CPU "
- "bus model");
- abort();
- }
-}
-
-/*
- * XICS Common class - parent for emulated XICS and KVM-XICS
- */
-static void xics_common_reset(DeviceState *d)
-{
- XICSState *icp = XICS_COMMON(d);
- int i;
-
- for (i = 0; i < icp->nr_servers; i++) {
- device_reset(DEVICE(&icp->ss[i]));
- }
-
- device_reset(DEVICE(icp->ics));
-}
-
-static void xics_prop_get_nr_irqs(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- XICSState *icp = XICS_COMMON(obj);
- int64_t value = icp->nr_irqs;
-
- visit_type_int(v, name, &value, errp);
-}
-
-static void xics_prop_set_nr_irqs(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- XICSState *icp = XICS_COMMON(obj);
- XICSStateClass *info = XICS_COMMON_GET_CLASS(icp);
- Error *error = NULL;
- int64_t value;
-
- visit_type_int(v, name, &value, &error);
- if (error) {
- error_propagate(errp, error);
- return;
- }
- if (icp->nr_irqs) {
- error_setg(errp, "Number of interrupts is already set to %u",
- icp->nr_irqs);
- return;
- }
-
- assert(info->set_nr_irqs);
- assert(icp->ics);
- info->set_nr_irqs(icp, value, errp);
-}
-
-static void xics_prop_get_nr_servers(Object *obj, Visitor *v,
- const char *name, void *opaque,
- Error **errp)
-{
- XICSState *icp = XICS_COMMON(obj);
- int64_t value = icp->nr_servers;
-
- visit_type_int(v, name, &value, errp);
-}
-
-static void xics_prop_set_nr_servers(Object *obj, Visitor *v,
- const char *name, void *opaque,
- Error **errp)
-{
- XICSState *icp = XICS_COMMON(obj);
- XICSStateClass *info = XICS_COMMON_GET_CLASS(icp);
- Error *error = NULL;
- int64_t value;
-
- visit_type_int(v, name, &value, &error);
- if (error) {
- error_propagate(errp, error);
- return;
- }
- if (icp->nr_servers) {
- error_setg(errp, "Number of servers is already set to %u",
- icp->nr_servers);
- return;
- }
-
- assert(info->set_nr_servers);
- info->set_nr_servers(icp, value, errp);
-}
-
-static void xics_common_initfn(Object *obj)
-{
- object_property_add(obj, "nr_irqs", "int",
- xics_prop_get_nr_irqs, xics_prop_set_nr_irqs,
- NULL, NULL, NULL);
- object_property_add(obj, "nr_servers", "int",
- xics_prop_get_nr_servers, xics_prop_set_nr_servers,
- NULL, NULL, NULL);
-}
-
-static void xics_common_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- dc->reset = xics_common_reset;
-}
-
-static const TypeInfo xics_common_info = {
- .name = TYPE_XICS_COMMON,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(XICSState),
- .class_size = sizeof(XICSStateClass),
- .instance_init = xics_common_initfn,
- .class_init = xics_common_class_init,
-};
-
-/*
- * ICP: Presentation layer
- */
-
-#define XISR_MASK 0x00ffffff
-#define CPPR_MASK 0xff000000
-
-#define XISR(ss) (((ss)->xirr) & XISR_MASK)
-#define CPPR(ss) (((ss)->xirr) >> 24)
-
-static void ics_reject(ICSState *ics, int nr);
-static void ics_resend(ICSState *ics);
-static void ics_eoi(ICSState *ics, int nr);
-
-static void icp_check_ipi(XICSState *icp, int server)
-{
- ICPState *ss = icp->ss + server;
-
- if (XISR(ss) && (ss->pending_priority <= ss->mfrr)) {
- return;
- }
-
- trace_xics_icp_check_ipi(server, ss->mfrr);
-
- if (XISR(ss)) {
- ics_reject(icp->ics, XISR(ss));
- }
-
- ss->xirr = (ss->xirr & ~XISR_MASK) | XICS_IPI;
- ss->pending_priority = ss->mfrr;
- qemu_irq_raise(ss->output);
-}
-
-static void icp_resend(XICSState *icp, int server)
-{
- ICPState *ss = icp->ss + server;
-
- if (ss->mfrr < CPPR(ss)) {
- icp_check_ipi(icp, server);
- }
- ics_resend(icp->ics);
-}
-
-static void icp_set_cppr(XICSState *icp, int server, uint8_t cppr)
-{
- ICPState *ss = icp->ss + server;
- uint8_t old_cppr;
- uint32_t old_xisr;
-
- old_cppr = CPPR(ss);
- ss->xirr = (ss->xirr & ~CPPR_MASK) | (cppr << 24);
-
- if (cppr < old_cppr) {
- if (XISR(ss) && (cppr <= ss->pending_priority)) {
- old_xisr = XISR(ss);
- ss->xirr &= ~XISR_MASK; /* Clear XISR */
- ss->pending_priority = 0xff;
- qemu_irq_lower(ss->output);
- ics_reject(icp->ics, old_xisr);
- }
- } else {
- if (!XISR(ss)) {
- icp_resend(icp, server);
- }
- }
-}
-
-static void icp_set_mfrr(XICSState *icp, int server, uint8_t mfrr)
-{
- ICPState *ss = icp->ss + server;
-
- ss->mfrr = mfrr;
- if (mfrr < CPPR(ss)) {
- icp_check_ipi(icp, server);
- }
-}
-
-static uint32_t icp_accept(ICPState *ss)
-{
- uint32_t xirr = ss->xirr;
-
- qemu_irq_lower(ss->output);
- ss->xirr = ss->pending_priority << 24;
- ss->pending_priority = 0xff;
-
- trace_xics_icp_accept(xirr, ss->xirr);
-
- return xirr;
-}
-
-static void icp_eoi(XICSState *icp, int server, uint32_t xirr)
-{
- ICPState *ss = icp->ss + server;
-
- /* Send EOI -> ICS */
- ss->xirr = (ss->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK);
- trace_xics_icp_eoi(server, xirr, ss->xirr);
- ics_eoi(icp->ics, xirr & XISR_MASK);
- if (!XISR(ss)) {
- icp_resend(icp, server);
- }
-}
-
-static void icp_irq(XICSState *icp, int server, int nr, uint8_t priority)
-{
- ICPState *ss = icp->ss + server;
-
- trace_xics_icp_irq(server, nr, priority);
-
- if ((priority >= CPPR(ss))
- || (XISR(ss) && (ss->pending_priority <= priority))) {
- ics_reject(icp->ics, nr);
- } else {
- if (XISR(ss)) {
- ics_reject(icp->ics, XISR(ss));
- }
- ss->xirr = (ss->xirr & ~XISR_MASK) | (nr & XISR_MASK);
- ss->pending_priority = priority;
- trace_xics_icp_raise(ss->xirr, ss->pending_priority);
- qemu_irq_raise(ss->output);
- }
-}
-
-static void icp_dispatch_pre_save(void *opaque)
-{
- ICPState *ss = opaque;
- ICPStateClass *info = ICP_GET_CLASS(ss);
-
- if (info->pre_save) {
- info->pre_save(ss);
- }
-}
-
-static int icp_dispatch_post_load(void *opaque, int version_id)
-{
- ICPState *ss = opaque;
- ICPStateClass *info = ICP_GET_CLASS(ss);
-
- if (info->post_load) {
- return info->post_load(ss, version_id);
- }
-
- return 0;
-}
-
-static const VMStateDescription vmstate_icp_server = {
- .name = "icp/server",
- .version_id = 1,
- .minimum_version_id = 1,
- .pre_save = icp_dispatch_pre_save,
- .post_load = icp_dispatch_post_load,
- .fields = (VMStateField[]) {
- /* Sanity check */
- VMSTATE_UINT32(xirr, ICPState),
- VMSTATE_UINT8(pending_priority, ICPState),
- VMSTATE_UINT8(mfrr, ICPState),
- VMSTATE_END_OF_LIST()
- },
-};
-
-static void icp_reset(DeviceState *dev)
-{
- ICPState *icp = ICP(dev);
-
- icp->xirr = 0;
- icp->pending_priority = 0xff;
- icp->mfrr = 0xff;
-
- /* Make all outputs are deasserted */
- qemu_set_irq(icp->output, 0);
-}
-
-static void icp_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->reset = icp_reset;
- dc->vmsd = &vmstate_icp_server;
-}
-
-static const TypeInfo icp_info = {
- .name = TYPE_ICP,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(ICPState),
- .class_init = icp_class_init,
- .class_size = sizeof(ICPStateClass),
-};
-
-/*
- * ICS: Source layer
- */
-static int ics_valid_irq(ICSState *ics, uint32_t nr)
-{
- return (nr >= ics->offset)
- && (nr < (ics->offset + ics->nr_irqs));
-}
-
-static void resend_msi(ICSState *ics, int srcno)
-{
- ICSIRQState *irq = ics->irqs + srcno;
-
- /* FIXME: filter by server#? */
- if (irq->status & XICS_STATUS_REJECTED) {
- irq->status &= ~XICS_STATUS_REJECTED;
- if (irq->priority != 0xff) {
- icp_irq(ics->icp, irq->server, srcno + ics->offset,
- irq->priority);
- }
- }
-}
-
-static void resend_lsi(ICSState *ics, int srcno)
-{
- ICSIRQState *irq = ics->irqs + srcno;
-
- if ((irq->priority != 0xff)
- && (irq->status & XICS_STATUS_ASSERTED)
- && !(irq->status & XICS_STATUS_SENT)) {
- irq->status |= XICS_STATUS_SENT;
- icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority);
- }
-}
-
-static void set_irq_msi(ICSState *ics, int srcno, int val)
-{
- ICSIRQState *irq = ics->irqs + srcno;
-
- trace_xics_set_irq_msi(srcno, srcno + ics->offset);
-
- if (val) {
- if (irq->priority == 0xff) {
- irq->status |= XICS_STATUS_MASKED_PENDING;
- trace_xics_masked_pending();
- } else {
- icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority);
- }
- }
-}
-
-static void set_irq_lsi(ICSState *ics, int srcno, int val)
-{
- ICSIRQState *irq = ics->irqs + srcno;
-
- trace_xics_set_irq_lsi(srcno, srcno + ics->offset);
- if (val) {
- irq->status |= XICS_STATUS_ASSERTED;
- } else {
- irq->status &= ~XICS_STATUS_ASSERTED;
- }
- resend_lsi(ics, srcno);
-}
-
-static void ics_set_irq(void *opaque, int srcno, int val)
-{
- ICSState *ics = (ICSState *)opaque;
-
- if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) {
- set_irq_lsi(ics, srcno, val);
- } else {
- set_irq_msi(ics, srcno, val);
- }
-}
-
-static void write_xive_msi(ICSState *ics, int srcno)
-{
- ICSIRQState *irq = ics->irqs + srcno;
-
- if (!(irq->status & XICS_STATUS_MASKED_PENDING)
- || (irq->priority == 0xff)) {
- return;
- }
-
- irq->status &= ~XICS_STATUS_MASKED_PENDING;
- icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority);
-}
-
-static void write_xive_lsi(ICSState *ics, int srcno)
-{
- resend_lsi(ics, srcno);
-}
-
-static void ics_write_xive(ICSState *ics, int nr, int server,
- uint8_t priority, uint8_t saved_priority)
-{
- int srcno = nr - ics->offset;
- ICSIRQState *irq = ics->irqs + srcno;
-
- irq->server = server;
- irq->priority = priority;
- irq->saved_priority = saved_priority;
-
- trace_xics_ics_write_xive(nr, srcno, server, priority);
-
- if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) {
- write_xive_lsi(ics, srcno);
- } else {
- write_xive_msi(ics, srcno);
- }
-}
-
-static void ics_reject(ICSState *ics, int nr)
-{
- ICSIRQState *irq = ics->irqs + nr - ics->offset;
-
- trace_xics_ics_reject(nr, nr - ics->offset);
- irq->status |= XICS_STATUS_REJECTED; /* Irrelevant but harmless for LSI */
- irq->status &= ~XICS_STATUS_SENT; /* Irrelevant but harmless for MSI */
-}
-
-static void ics_resend(ICSState *ics)
-{
- int i;
-
- for (i = 0; i < ics->nr_irqs; i++) {
- /* FIXME: filter by server#? */
- if (ics->irqs[i].flags & XICS_FLAGS_IRQ_LSI) {
- resend_lsi(ics, i);
- } else {
- resend_msi(ics, i);
- }
- }
-}
-
-static void ics_eoi(ICSState *ics, int nr)
-{
- int srcno = nr - ics->offset;
- ICSIRQState *irq = ics->irqs + srcno;
-
- trace_xics_ics_eoi(nr);
-
- if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) {
- irq->status &= ~XICS_STATUS_SENT;
- }
-}
-
-static void ics_reset(DeviceState *dev)
-{
- ICSState *ics = ICS(dev);
- int i;
- uint8_t flags[ics->nr_irqs];
-
- for (i = 0; i < ics->nr_irqs; i++) {
- flags[i] = ics->irqs[i].flags;
- }
-
- memset(ics->irqs, 0, sizeof(ICSIRQState) * ics->nr_irqs);
-
- for (i = 0; i < ics->nr_irqs; i++) {
- ics->irqs[i].priority = 0xff;
- ics->irqs[i].saved_priority = 0xff;
- ics->irqs[i].flags = flags[i];
- }
-}
-
-static int ics_post_load(ICSState *ics, int version_id)
-{
- int i;
-
- for (i = 0; i < ics->icp->nr_servers; i++) {
- icp_resend(ics->icp, i);
- }
-
- return 0;
-}
-
-static void ics_dispatch_pre_save(void *opaque)
-{
- ICSState *ics = opaque;
- ICSStateClass *info = ICS_GET_CLASS(ics);
-
- if (info->pre_save) {
- info->pre_save(ics);
- }
-}
-
-static int ics_dispatch_post_load(void *opaque, int version_id)
-{
- ICSState *ics = opaque;
- ICSStateClass *info = ICS_GET_CLASS(ics);
-
- if (info->post_load) {
- return info->post_load(ics, version_id);
- }
-
- return 0;
-}
-
-static const VMStateDescription vmstate_ics_irq = {
- .name = "ics/irq",
- .version_id = 2,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(server, ICSIRQState),
- VMSTATE_UINT8(priority, ICSIRQState),
- VMSTATE_UINT8(saved_priority, ICSIRQState),
- VMSTATE_UINT8(status, ICSIRQState),
- VMSTATE_UINT8(flags, ICSIRQState),
- VMSTATE_END_OF_LIST()
- },
-};
-
-static const VMStateDescription vmstate_ics = {
- .name = "ics",
- .version_id = 1,
- .minimum_version_id = 1,
- .pre_save = ics_dispatch_pre_save,
- .post_load = ics_dispatch_post_load,
- .fields = (VMStateField[]) {
- /* Sanity check */
- VMSTATE_UINT32_EQUAL(nr_irqs, ICSState),
-
- VMSTATE_STRUCT_VARRAY_POINTER_UINT32(irqs, ICSState, nr_irqs,
- vmstate_ics_irq, ICSIRQState),
- VMSTATE_END_OF_LIST()
- },
-};
-
-static void ics_initfn(Object *obj)
-{
- ICSState *ics = ICS(obj);
-
- ics->offset = XICS_IRQ_BASE;
-}
-
-static void ics_realize(DeviceState *dev, Error **errp)
-{
- ICSState *ics = ICS(dev);
-
- if (!ics->nr_irqs) {
- error_setg(errp, "Number of interrupts needs to be greater 0");
- return;
- }
- ics->irqs = g_malloc0(ics->nr_irqs * sizeof(ICSIRQState));
- ics->qirqs = qemu_allocate_irqs(ics_set_irq, ics, ics->nr_irqs);
-}
-
-static void ics_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- ICSStateClass *isc = ICS_CLASS(klass);
-
- dc->realize = ics_realize;
- dc->vmsd = &vmstate_ics;
- dc->reset = ics_reset;
- isc->post_load = ics_post_load;
-}
-
-static const TypeInfo ics_info = {
- .name = TYPE_ICS,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(ICSState),
- .class_init = ics_class_init,
- .class_size = sizeof(ICSStateClass),
- .instance_init = ics_initfn,
-};
-
-/*
- * Exported functions
- */
-static int xics_find_source(XICSState *icp, int irq)
-{
- int sources = 1;
- int src;
-
- /* FIXME: implement multiple sources */
- for (src = 0; src < sources; ++src) {
- ICSState *ics = &icp->ics[src];
- if (ics_valid_irq(ics, irq)) {
- return src;
- }
- }
-
- return -1;
-}
-
-qemu_irq xics_get_qirq(XICSState *icp, int irq)
-{
- int src = xics_find_source(icp, irq);
-
- if (src >= 0) {
- ICSState *ics = &icp->ics[src];
- return ics->qirqs[irq - ics->offset];
- }
-
- return NULL;
-}
-
-static void ics_set_irq_type(ICSState *ics, int srcno, bool lsi)
-{
- assert(!(ics->irqs[srcno].flags & XICS_FLAGS_IRQ_MASK));
-
- ics->irqs[srcno].flags |=
- lsi ? XICS_FLAGS_IRQ_LSI : XICS_FLAGS_IRQ_MSI;
-}
-
-void xics_set_irq_type(XICSState *icp, int irq, bool lsi)
-{
- int src = xics_find_source(icp, irq);
- ICSState *ics;
-
- assert(src >= 0);
-
- ics = &icp->ics[src];
- ics_set_irq_type(ics, irq - ics->offset, lsi);
-}
-
-#define ICS_IRQ_FREE(ics, srcno) \
- (!((ics)->irqs[(srcno)].flags & (XICS_FLAGS_IRQ_MASK)))
-
-static int ics_find_free_block(ICSState *ics, int num, int alignnum)
-{
- int first, i;
-
- for (first = 0; first < ics->nr_irqs; first += alignnum) {
- if (num > (ics->nr_irqs - first)) {
- return -1;
- }
- for (i = first; i < first + num; ++i) {
- if (!ICS_IRQ_FREE(ics, i)) {
- break;
- }
- }
- if (i == (first + num)) {
- return first;
- }
- }
-
- return -1;
-}
-
-int xics_alloc(XICSState *icp, int src, int irq_hint, bool lsi, Error **errp)
-{
- ICSState *ics = &icp->ics[src];
- int irq;
-
- if (irq_hint) {
- assert(src == xics_find_source(icp, irq_hint));
- if (!ICS_IRQ_FREE(ics, irq_hint - ics->offset)) {
- error_setg(errp, "can't allocate IRQ %d: already in use", irq_hint);
- return -1;
- }
- irq = irq_hint;
- } else {
- irq = ics_find_free_block(ics, 1, 1);
- if (irq < 0) {
- error_setg(errp, "can't allocate IRQ: no IRQ left");
- return -1;
- }
- irq += ics->offset;
- }
-
- ics_set_irq_type(ics, irq - ics->offset, lsi);
- trace_xics_alloc(src, irq);
-
- return irq;
-}
-
-/*
- * Allocate block of consecutive IRQs, and return the number of the first IRQ in the block.
- * If align==true, aligns the first IRQ number to num.
- */
-int xics_alloc_block(XICSState *icp, int src, int num, bool lsi, bool align,
- Error **errp)
-{
- int i, first = -1;
- ICSState *ics = &icp->ics[src];
-
- assert(src == 0);
- /*
- * MSIMesage::data is used for storing VIRQ so
- * it has to be aligned to num to support multiple
- * MSI vectors. MSI-X is not affected by this.
- * The hint is used for the first IRQ, the rest should
- * be allocated continuously.
- */
- if (align) {
- assert((num == 1) || (num == 2) || (num == 4) ||
- (num == 8) || (num == 16) || (num == 32));
- first = ics_find_free_block(ics, num, num);
- } else {
- first = ics_find_free_block(ics, num, 1);
- }
- if (first < 0) {
- error_setg(errp, "can't find a free %d-IRQ block", num);
- return -1;
- }
-
- if (first >= 0) {
- for (i = first; i < first + num; ++i) {
- ics_set_irq_type(ics, i, lsi);
- }
- }
- first += ics->offset;
-
- trace_xics_alloc_block(src, first, num, lsi, align);
-
- return first;
-}
-
-static void ics_free(ICSState *ics, int srcno, int num)
-{
- int i;
-
- for (i = srcno; i < srcno + num; ++i) {
- if (ICS_IRQ_FREE(ics, i)) {
- trace_xics_ics_free_warn(ics - ics->icp->ics, i + ics->offset);
- }
- memset(&ics->irqs[i], 0, sizeof(ICSIRQState));
- }
-}
-
-void xics_free(XICSState *icp, int irq, int num)
-{
- int src = xics_find_source(icp, irq);
-
- if (src >= 0) {
- ICSState *ics = &icp->ics[src];
-
- /* FIXME: implement multiple sources */
- assert(src == 0);
-
- trace_xics_ics_free(ics - icp->ics, irq, num);
- ics_free(ics, irq - ics->offset, num);
- }
-}
-
-/*
- * Guest interfaces
- */
-
-static target_ulong h_cppr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- CPUState *cs = CPU(cpu);
- target_ulong cppr = args[0];
-
- icp_set_cppr(spapr->icp, cs->cpu_index, cppr);
- return H_SUCCESS;
-}
-
-static target_ulong h_ipi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- target_ulong server = get_cpu_index_by_dt_id(args[0]);
- target_ulong mfrr = args[1];
-
- if (server >= spapr->icp->nr_servers) {
- return H_PARAMETER;
- }
-
- icp_set_mfrr(spapr->icp, server, mfrr);
- return H_SUCCESS;
-}
-
-static target_ulong h_xirr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- CPUState *cs = CPU(cpu);
- uint32_t xirr = icp_accept(spapr->icp->ss + cs->cpu_index);
-
- args[0] = xirr;
- return H_SUCCESS;
-}
-
-static target_ulong h_xirr_x(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- CPUState *cs = CPU(cpu);
- ICPState *ss = &spapr->icp->ss[cs->cpu_index];
- uint32_t xirr = icp_accept(ss);
-
- args[0] = xirr;
- args[1] = cpu_get_host_ticks();
- return H_SUCCESS;
-}
-
-static target_ulong h_eoi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- CPUState *cs = CPU(cpu);
- target_ulong xirr = args[0];
-
- icp_eoi(spapr->icp, cs->cpu_index, xirr);
- return H_SUCCESS;
-}
-
-static target_ulong h_ipoll(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- CPUState *cs = CPU(cpu);
- ICPState *ss = &spapr->icp->ss[cs->cpu_index];
-
- args[0] = ss->xirr;
- args[1] = ss->mfrr;
-
- return H_SUCCESS;
-}
-
-static void rtas_set_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- uint32_t token,
- uint32_t nargs, target_ulong args,
- uint32_t nret, target_ulong rets)
-{
- ICSState *ics = spapr->icp->ics;
- uint32_t nr, server, priority;
-
- if ((nargs != 3) || (nret != 1)) {
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
- return;
- }
-
- nr = rtas_ld(args, 0);
- server = get_cpu_index_by_dt_id(rtas_ld(args, 1));
- priority = rtas_ld(args, 2);
-
- if (!ics_valid_irq(ics, nr) || (server >= ics->icp->nr_servers)
- || (priority > 0xff)) {
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
- return;
- }
-
- ics_write_xive(ics, nr, server, priority, priority);
-
- rtas_st(rets, 0, RTAS_OUT_SUCCESS);
-}
-
-static void rtas_get_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- uint32_t token,
- uint32_t nargs, target_ulong args,
- uint32_t nret, target_ulong rets)
-{
- ICSState *ics = spapr->icp->ics;
- uint32_t nr;
-
- if ((nargs != 1) || (nret != 3)) {
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
- return;
- }
-
- nr = rtas_ld(args, 0);
-
- if (!ics_valid_irq(ics, nr)) {
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
- return;
- }
-
- rtas_st(rets, 0, RTAS_OUT_SUCCESS);
- rtas_st(rets, 1, ics->irqs[nr - ics->offset].server);
- rtas_st(rets, 2, ics->irqs[nr - ics->offset].priority);
-}
-
-static void rtas_int_off(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- uint32_t token,
- uint32_t nargs, target_ulong args,
- uint32_t nret, target_ulong rets)
-{
- ICSState *ics = spapr->icp->ics;
- uint32_t nr;
-
- if ((nargs != 1) || (nret != 1)) {
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
- return;
- }
-
- nr = rtas_ld(args, 0);
-
- if (!ics_valid_irq(ics, nr)) {
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
- return;
- }
-
- ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server, 0xff,
- ics->irqs[nr - ics->offset].priority);
-
- rtas_st(rets, 0, RTAS_OUT_SUCCESS);
-}
-
-static void rtas_int_on(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- uint32_t token,
- uint32_t nargs, target_ulong args,
- uint32_t nret, target_ulong rets)
-{
- ICSState *ics = spapr->icp->ics;
- uint32_t nr;
-
- if ((nargs != 1) || (nret != 1)) {
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
- return;
- }
-
- nr = rtas_ld(args, 0);
-
- if (!ics_valid_irq(ics, nr)) {
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
- return;
- }
-
- ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server,
- ics->irqs[nr - ics->offset].saved_priority,
- ics->irqs[nr - ics->offset].saved_priority);
-
- rtas_st(rets, 0, RTAS_OUT_SUCCESS);
-}
-
-/*
- * XICS
- */
-
-static void xics_set_nr_irqs(XICSState *icp, uint32_t nr_irqs, Error **errp)
-{
- icp->nr_irqs = icp->ics->nr_irqs = nr_irqs;
-}
-
-static void xics_set_nr_servers(XICSState *icp, uint32_t nr_servers,
- Error **errp)
-{
- int i;
-
- icp->nr_servers = nr_servers;
-
- icp->ss = g_malloc0(icp->nr_servers*sizeof(ICPState));
- for (i = 0; i < icp->nr_servers; i++) {
- char buffer[32];
- object_initialize(&icp->ss[i], sizeof(icp->ss[i]), TYPE_ICP);
- snprintf(buffer, sizeof(buffer), "icp[%d]", i);
- object_property_add_child(OBJECT(icp), buffer, OBJECT(&icp->ss[i]),
- errp);
- }
-}
-
-static void xics_realize(DeviceState *dev, Error **errp)
-{
- XICSState *icp = XICS(dev);
- Error *error = NULL;
- int i;
-
- if (!icp->nr_servers) {
- error_setg(errp, "Number of servers needs to be greater 0");
- return;
- }
-
- /* Registration of global state belongs into realize */
- spapr_rtas_register(RTAS_IBM_SET_XIVE, "ibm,set-xive", rtas_set_xive);
- spapr_rtas_register(RTAS_IBM_GET_XIVE, "ibm,get-xive", rtas_get_xive);
- spapr_rtas_register(RTAS_IBM_INT_OFF, "ibm,int-off", rtas_int_off);
- spapr_rtas_register(RTAS_IBM_INT_ON, "ibm,int-on", rtas_int_on);
-
- spapr_register_hypercall(H_CPPR, h_cppr);
- spapr_register_hypercall(H_IPI, h_ipi);
- spapr_register_hypercall(H_XIRR, h_xirr);
- spapr_register_hypercall(H_XIRR_X, h_xirr_x);
- spapr_register_hypercall(H_EOI, h_eoi);
- spapr_register_hypercall(H_IPOLL, h_ipoll);
-
- object_property_set_bool(OBJECT(icp->ics), true, "realized", &error);
- if (error) {
- error_propagate(errp, error);
- return;
- }
-
- for (i = 0; i < icp->nr_servers; i++) {
- object_property_set_bool(OBJECT(&icp->ss[i]), true, "realized", &error);
- if (error) {
- error_propagate(errp, error);
- return;
- }
- }
-}
-
-static void xics_initfn(Object *obj)
-{
- XICSState *xics = XICS(obj);
-
- xics->ics = ICS(object_new(TYPE_ICS));
- object_property_add_child(obj, "ics", OBJECT(xics->ics), NULL);
- xics->ics->icp = xics;
-}
-
-static void xics_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
- XICSStateClass *xsc = XICS_CLASS(oc);
-
- dc->realize = xics_realize;
- xsc->set_nr_irqs = xics_set_nr_irqs;
- xsc->set_nr_servers = xics_set_nr_servers;
-}
-
-static const TypeInfo xics_info = {
- .name = TYPE_XICS,
- .parent = TYPE_XICS_COMMON,
- .instance_size = sizeof(XICSState),
- .class_size = sizeof(XICSStateClass),
- .class_init = xics_class_init,
- .instance_init = xics_initfn,
-};
-
-static void xics_register_types(void)
-{
- type_register_static(&xics_common_info);
- type_register_static(&xics_info);
- type_register_static(&ics_info);
- type_register_static(&icp_info);
-}
-
-type_init(xics_register_types)
diff --git a/qemu/hw/intc/xics_kvm.c b/qemu/hw/intc/xics_kvm.c
deleted file mode 100644
index 9029d9ee0..000000000
--- a/qemu/hw/intc/xics_kvm.c
+++ /dev/null
@@ -1,512 +0,0 @@
-/*
- * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
- *
- * PAPR Virtualized Interrupt System, aka ICS/ICP aka xics, in-kernel emulation
- *
- * Copyright (c) 2013 David Gibson, IBM Corporation.
- *
- * 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.
- *
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/hw.h"
-#include "trace.h"
-#include "hw/ppc/spapr.h"
-#include "hw/ppc/xics.h"
-#include "kvm_ppc.h"
-#include "qemu/config-file.h"
-#include "qemu/error-report.h"
-
-#include <sys/ioctl.h>
-
-typedef struct KVMXICSState {
- XICSState parent_obj;
-
- int kernel_xics_fd;
-} KVMXICSState;
-
-/*
- * ICP-KVM
- */
-static void icp_get_kvm_state(ICPState *ss)
-{
- uint64_t state;
- struct kvm_one_reg reg = {
- .id = KVM_REG_PPC_ICP_STATE,
- .addr = (uintptr_t)&state,
- };
- int ret;
-
- /* ICP for this CPU thread is not in use, exiting */
- if (!ss->cs) {
- return;
- }
-
- ret = kvm_vcpu_ioctl(ss->cs, KVM_GET_ONE_REG, &reg);
- if (ret != 0) {
- error_report("Unable to retrieve KVM interrupt controller state"
- " for CPU %ld: %s", kvm_arch_vcpu_id(ss->cs), strerror(errno));
- exit(1);
- }
-
- ss->xirr = state >> KVM_REG_PPC_ICP_XISR_SHIFT;
- ss->mfrr = (state >> KVM_REG_PPC_ICP_MFRR_SHIFT)
- & KVM_REG_PPC_ICP_MFRR_MASK;
- ss->pending_priority = (state >> KVM_REG_PPC_ICP_PPRI_SHIFT)
- & KVM_REG_PPC_ICP_PPRI_MASK;
-}
-
-static int icp_set_kvm_state(ICPState *ss, int version_id)
-{
- uint64_t state;
- struct kvm_one_reg reg = {
- .id = KVM_REG_PPC_ICP_STATE,
- .addr = (uintptr_t)&state,
- };
- int ret;
-
- /* ICP for this CPU thread is not in use, exiting */
- if (!ss->cs) {
- return 0;
- }
-
- state = ((uint64_t)ss->xirr << KVM_REG_PPC_ICP_XISR_SHIFT)
- | ((uint64_t)ss->mfrr << KVM_REG_PPC_ICP_MFRR_SHIFT)
- | ((uint64_t)ss->pending_priority << KVM_REG_PPC_ICP_PPRI_SHIFT);
-
- ret = kvm_vcpu_ioctl(ss->cs, KVM_SET_ONE_REG, &reg);
- if (ret != 0) {
- error_report("Unable to restore KVM interrupt controller state (0x%"
- PRIx64 ") for CPU %ld: %s", state, kvm_arch_vcpu_id(ss->cs),
- strerror(errno));
- return ret;
- }
-
- return 0;
-}
-
-static void icp_kvm_reset(DeviceState *dev)
-{
- ICPState *icp = ICP(dev);
-
- icp->xirr = 0;
- icp->pending_priority = 0xff;
- icp->mfrr = 0xff;
-
- /* Make all outputs are deasserted */
- qemu_set_irq(icp->output, 0);
-
- icp_set_kvm_state(icp, 1);
-}
-
-static void icp_kvm_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- ICPStateClass *icpc = ICP_CLASS(klass);
-
- dc->reset = icp_kvm_reset;
- icpc->pre_save = icp_get_kvm_state;
- icpc->post_load = icp_set_kvm_state;
-}
-
-static const TypeInfo icp_kvm_info = {
- .name = TYPE_KVM_ICP,
- .parent = TYPE_ICP,
- .instance_size = sizeof(ICPState),
- .class_init = icp_kvm_class_init,
- .class_size = sizeof(ICPStateClass),
-};
-
-/*
- * ICS-KVM
- */
-static void ics_get_kvm_state(ICSState *ics)
-{
- KVMXICSState *icpkvm = KVM_XICS(ics->icp);
- uint64_t state;
- struct kvm_device_attr attr = {
- .flags = 0,
- .group = KVM_DEV_XICS_GRP_SOURCES,
- .addr = (uint64_t)(uintptr_t)&state,
- };
- int i;
-
- for (i = 0; i < ics->nr_irqs; i++) {
- ICSIRQState *irq = &ics->irqs[i];
- int ret;
-
- attr.attr = i + ics->offset;
-
- ret = ioctl(icpkvm->kernel_xics_fd, KVM_GET_DEVICE_ATTR, &attr);
- if (ret != 0) {
- error_report("Unable to retrieve KVM interrupt controller state"
- " for IRQ %d: %s", i + ics->offset, strerror(errno));
- exit(1);
- }
-
- irq->server = state & KVM_XICS_DESTINATION_MASK;
- irq->saved_priority = (state >> KVM_XICS_PRIORITY_SHIFT)
- & KVM_XICS_PRIORITY_MASK;
- /*
- * To be consistent with the software emulation in xics.c, we
- * split out the masked state + priority that we get from the
- * kernel into 'current priority' (0xff if masked) and
- * 'saved priority' (if masked, this is the priority the
- * interrupt had before it was masked). Masking and unmasking
- * are done with the ibm,int-off and ibm,int-on RTAS calls.
- */
- if (state & KVM_XICS_MASKED) {
- irq->priority = 0xff;
- } else {
- irq->priority = irq->saved_priority;
- }
-
- if (state & KVM_XICS_PENDING) {
- if (state & KVM_XICS_LEVEL_SENSITIVE) {
- irq->status |= XICS_STATUS_ASSERTED;
- } else {
- /*
- * A pending edge-triggered interrupt (or MSI)
- * must have been rejected previously when we
- * first detected it and tried to deliver it,
- * so mark it as pending and previously rejected
- * for consistency with how xics.c works.
- */
- irq->status |= XICS_STATUS_MASKED_PENDING
- | XICS_STATUS_REJECTED;
- }
- }
- }
-}
-
-static int ics_set_kvm_state(ICSState *ics, int version_id)
-{
- KVMXICSState *icpkvm = KVM_XICS(ics->icp);
- uint64_t state;
- struct kvm_device_attr attr = {
- .flags = 0,
- .group = KVM_DEV_XICS_GRP_SOURCES,
- .addr = (uint64_t)(uintptr_t)&state,
- };
- int i;
-
- for (i = 0; i < ics->nr_irqs; i++) {
- ICSIRQState *irq = &ics->irqs[i];
- int ret;
-
- attr.attr = i + ics->offset;
-
- state = irq->server;
- state |= (uint64_t)(irq->saved_priority & KVM_XICS_PRIORITY_MASK)
- << KVM_XICS_PRIORITY_SHIFT;
- if (irq->priority != irq->saved_priority) {
- assert(irq->priority == 0xff);
- state |= KVM_XICS_MASKED;
- }
-
- if (ics->irqs[i].flags & XICS_FLAGS_IRQ_LSI) {
- state |= KVM_XICS_LEVEL_SENSITIVE;
- if (irq->status & XICS_STATUS_ASSERTED) {
- state |= KVM_XICS_PENDING;
- }
- } else {
- if (irq->status & XICS_STATUS_MASKED_PENDING) {
- state |= KVM_XICS_PENDING;
- }
- }
-
- ret = ioctl(icpkvm->kernel_xics_fd, KVM_SET_DEVICE_ATTR, &attr);
- if (ret != 0) {
- error_report("Unable to restore KVM interrupt controller state"
- " for IRQs %d: %s", i + ics->offset, strerror(errno));
- return ret;
- }
- }
-
- return 0;
-}
-
-static void ics_kvm_set_irq(void *opaque, int srcno, int val)
-{
- ICSState *ics = opaque;
- struct kvm_irq_level args;
- int rc;
-
- args.irq = srcno + ics->offset;
- if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_MSI) {
- if (!val) {
- return;
- }
- args.level = KVM_INTERRUPT_SET;
- } else {
- args.level = val ? KVM_INTERRUPT_SET_LEVEL : KVM_INTERRUPT_UNSET;
- }
- rc = kvm_vm_ioctl(kvm_state, KVM_IRQ_LINE, &args);
- if (rc < 0) {
- perror("kvm_irq_line");
- }
-}
-
-static void ics_kvm_reset(DeviceState *dev)
-{
- ICSState *ics = ICS(dev);
- int i;
- uint8_t flags[ics->nr_irqs];
-
- for (i = 0; i < ics->nr_irqs; i++) {
- flags[i] = ics->irqs[i].flags;
- }
-
- memset(ics->irqs, 0, sizeof(ICSIRQState) * ics->nr_irqs);
-
- for (i = 0; i < ics->nr_irqs; i++) {
- ics->irqs[i].priority = 0xff;
- ics->irqs[i].saved_priority = 0xff;
- ics->irqs[i].flags = flags[i];
- }
-
- ics_set_kvm_state(ics, 1);
-}
-
-static void ics_kvm_realize(DeviceState *dev, Error **errp)
-{
- ICSState *ics = ICS(dev);
-
- if (!ics->nr_irqs) {
- error_setg(errp, "Number of interrupts needs to be greater 0");
- return;
- }
- ics->irqs = g_malloc0(ics->nr_irqs * sizeof(ICSIRQState));
- ics->qirqs = qemu_allocate_irqs(ics_kvm_set_irq, ics, ics->nr_irqs);
-}
-
-static void ics_kvm_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- ICSStateClass *icsc = ICS_CLASS(klass);
-
- dc->realize = ics_kvm_realize;
- dc->reset = ics_kvm_reset;
- icsc->pre_save = ics_get_kvm_state;
- icsc->post_load = ics_set_kvm_state;
-}
-
-static const TypeInfo ics_kvm_info = {
- .name = TYPE_KVM_ICS,
- .parent = TYPE_ICS,
- .instance_size = sizeof(ICSState),
- .class_init = ics_kvm_class_init,
-};
-
-/*
- * XICS-KVM
- */
-static void xics_kvm_cpu_setup(XICSState *icp, PowerPCCPU *cpu)
-{
- CPUState *cs;
- ICPState *ss;
- KVMXICSState *icpkvm = KVM_XICS(icp);
-
- cs = CPU(cpu);
- ss = &icp->ss[cs->cpu_index];
-
- assert(cs->cpu_index < icp->nr_servers);
- if (icpkvm->kernel_xics_fd == -1) {
- abort();
- }
-
- /*
- * If we are reusing a parked vCPU fd corresponding to the CPU
- * which was hot-removed earlier we don't have to renable
- * KVM_CAP_IRQ_XICS capability again.
- */
- if (ss->cap_irq_xics_enabled) {
- return;
- }
-
- if (icpkvm->kernel_xics_fd != -1) {
- int ret;
-
- ss->cs = cs;
-
- ret = kvm_vcpu_enable_cap(cs, KVM_CAP_IRQ_XICS, 0,
- icpkvm->kernel_xics_fd, kvm_arch_vcpu_id(cs));
- if (ret < 0) {
- error_report("Unable to connect CPU%ld to kernel XICS: %s",
- kvm_arch_vcpu_id(cs), strerror(errno));
- exit(1);
- }
- ss->cap_irq_xics_enabled = true;
- }
-}
-
-static void xics_kvm_set_nr_irqs(XICSState *icp, uint32_t nr_irqs, Error **errp)
-{
- icp->nr_irqs = icp->ics->nr_irqs = nr_irqs;
-}
-
-static void xics_kvm_set_nr_servers(XICSState *icp, uint32_t nr_servers,
- Error **errp)
-{
- int i;
-
- icp->nr_servers = nr_servers;
-
- icp->ss = g_malloc0(icp->nr_servers*sizeof(ICPState));
- for (i = 0; i < icp->nr_servers; i++) {
- char buffer[32];
- object_initialize(&icp->ss[i], sizeof(icp->ss[i]), TYPE_KVM_ICP);
- snprintf(buffer, sizeof(buffer), "icp[%d]", i);
- object_property_add_child(OBJECT(icp), buffer, OBJECT(&icp->ss[i]),
- errp);
- }
-}
-
-static void rtas_dummy(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- uint32_t token,
- uint32_t nargs, target_ulong args,
- uint32_t nret, target_ulong rets)
-{
- error_report("pseries: %s must never be called for in-kernel XICS",
- __func__);
-}
-
-static void xics_kvm_realize(DeviceState *dev, Error **errp)
-{
- KVMXICSState *icpkvm = KVM_XICS(dev);
- XICSState *icp = XICS_COMMON(dev);
- int i, rc;
- Error *error = NULL;
- struct kvm_create_device xics_create_device = {
- .type = KVM_DEV_TYPE_XICS,
- .flags = 0,
- };
-
- if (!kvm_enabled() || !kvm_check_extension(kvm_state, KVM_CAP_IRQ_XICS)) {
- error_setg(errp,
- "KVM and IRQ_XICS capability must be present for in-kernel XICS");
- goto fail;
- }
-
- spapr_rtas_register(RTAS_IBM_SET_XIVE, "ibm,set-xive", rtas_dummy);
- spapr_rtas_register(RTAS_IBM_GET_XIVE, "ibm,get-xive", rtas_dummy);
- spapr_rtas_register(RTAS_IBM_INT_OFF, "ibm,int-off", rtas_dummy);
- spapr_rtas_register(RTAS_IBM_INT_ON, "ibm,int-on", rtas_dummy);
-
- rc = kvmppc_define_rtas_kernel_token(RTAS_IBM_SET_XIVE, "ibm,set-xive");
- if (rc < 0) {
- error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,set-xive");
- goto fail;
- }
-
- rc = kvmppc_define_rtas_kernel_token(RTAS_IBM_GET_XIVE, "ibm,get-xive");
- if (rc < 0) {
- error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,get-xive");
- goto fail;
- }
-
- rc = kvmppc_define_rtas_kernel_token(RTAS_IBM_INT_ON, "ibm,int-on");
- if (rc < 0) {
- error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,int-on");
- goto fail;
- }
-
- rc = kvmppc_define_rtas_kernel_token(RTAS_IBM_INT_OFF, "ibm,int-off");
- if (rc < 0) {
- error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,int-off");
- goto fail;
- }
-
- /* Create the kernel ICP */
- rc = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &xics_create_device);
- if (rc < 0) {
- error_setg_errno(errp, -rc, "Error on KVM_CREATE_DEVICE for XICS");
- goto fail;
- }
-
- icpkvm->kernel_xics_fd = xics_create_device.fd;
-
- object_property_set_bool(OBJECT(icp->ics), true, "realized", &error);
- if (error) {
- error_propagate(errp, error);
- goto fail;
- }
-
- assert(icp->nr_servers);
- for (i = 0; i < icp->nr_servers; i++) {
- object_property_set_bool(OBJECT(&icp->ss[i]), true, "realized", &error);
- if (error) {
- error_propagate(errp, error);
- goto fail;
- }
- }
-
- kvm_kernel_irqchip = true;
- kvm_msi_via_irqfd_allowed = true;
- kvm_gsi_direct_mapping = true;
-
- return;
-
-fail:
- kvmppc_define_rtas_kernel_token(0, "ibm,set-xive");
- kvmppc_define_rtas_kernel_token(0, "ibm,get-xive");
- kvmppc_define_rtas_kernel_token(0, "ibm,int-on");
- kvmppc_define_rtas_kernel_token(0, "ibm,int-off");
-}
-
-static void xics_kvm_initfn(Object *obj)
-{
- XICSState *xics = XICS_COMMON(obj);
-
- xics->ics = ICS(object_new(TYPE_KVM_ICS));
- object_property_add_child(obj, "ics", OBJECT(xics->ics), NULL);
- xics->ics->icp = xics;
-}
-
-static void xics_kvm_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
- XICSStateClass *xsc = XICS_COMMON_CLASS(oc);
-
- dc->realize = xics_kvm_realize;
- xsc->cpu_setup = xics_kvm_cpu_setup;
- xsc->set_nr_irqs = xics_kvm_set_nr_irqs;
- xsc->set_nr_servers = xics_kvm_set_nr_servers;
-}
-
-static const TypeInfo xics_kvm_info = {
- .name = TYPE_KVM_XICS,
- .parent = TYPE_XICS_COMMON,
- .instance_size = sizeof(KVMXICSState),
- .class_init = xics_kvm_class_init,
- .instance_init = xics_kvm_initfn,
-};
-
-static void xics_kvm_register_types(void)
-{
- type_register_static(&xics_kvm_info);
- type_register_static(&ics_kvm_info);
- type_register_static(&icp_kvm_info);
-}
-
-type_init(xics_kvm_register_types)
diff --git a/qemu/hw/intc/xilinx_intc.c b/qemu/hw/intc/xilinx_intc.c
deleted file mode 100644
index 9d8139bc6..000000000
--- a/qemu/hw/intc/xilinx_intc.c
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * QEMU Xilinx OPB Interrupt Controller.
- *
- * Copyright (c) 2009 Edgar E. Iglesias.
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "hw/hw.h"
-
-#define D(x)
-
-#define R_ISR 0
-#define R_IPR 1
-#define R_IER 2
-#define R_IAR 3
-#define R_SIE 4
-#define R_CIE 5
-#define R_IVR 6
-#define R_MER 7
-#define R_MAX 8
-
-#define TYPE_XILINX_INTC "xlnx.xps-intc"
-#define XILINX_INTC(obj) OBJECT_CHECK(struct xlx_pic, (obj), TYPE_XILINX_INTC)
-
-struct xlx_pic
-{
- SysBusDevice parent_obj;
-
- MemoryRegion mmio;
- qemu_irq parent_irq;
-
- /* Configuration reg chosen at synthesis-time. QEMU populates
- the bits at board-setup. */
- uint32_t c_kind_of_intr;
-
- /* Runtime control registers. */
- uint32_t regs[R_MAX];
- /* state of the interrupt input pins */
- uint32_t irq_pin_state;
-};
-
-static void update_irq(struct xlx_pic *p)
-{
- uint32_t i;
-
- /* level triggered interrupt */
- if (p->regs[R_MER] & 2) {
- p->regs[R_ISR] |= p->irq_pin_state & ~p->c_kind_of_intr;
- }
-
- /* Update the pending register. */
- p->regs[R_IPR] = p->regs[R_ISR] & p->regs[R_IER];
-
- /* Update the vector register. */
- for (i = 0; i < 32; i++) {
- if (p->regs[R_IPR] & (1U << i)) {
- break;
- }
- }
- if (i == 32)
- i = ~0;
-
- p->regs[R_IVR] = i;
- qemu_set_irq(p->parent_irq, (p->regs[R_MER] & 1) && p->regs[R_IPR]);
-}
-
-static uint64_t
-pic_read(void *opaque, hwaddr addr, unsigned int size)
-{
- struct xlx_pic *p = opaque;
- uint32_t r = 0;
-
- addr >>= 2;
- switch (addr)
- {
- default:
- if (addr < ARRAY_SIZE(p->regs))
- r = p->regs[addr];
- break;
-
- }
- D(printf("%s %x=%x\n", __func__, addr * 4, r));
- return r;
-}
-
-static void
-pic_write(void *opaque, hwaddr addr,
- uint64_t val64, unsigned int size)
-{
- struct xlx_pic *p = opaque;
- uint32_t value = val64;
-
- addr >>= 2;
- D(qemu_log("%s addr=%x val=%x\n", __func__, addr * 4, value));
- switch (addr)
- {
- case R_IAR:
- p->regs[R_ISR] &= ~value; /* ACK. */
- break;
- case R_SIE:
- p->regs[R_IER] |= value; /* Atomic set ie. */
- break;
- case R_CIE:
- p->regs[R_IER] &= ~value; /* Atomic clear ie. */
- break;
- case R_MER:
- p->regs[R_MER] = value & 0x3;
- break;
- case R_ISR:
- if ((p->regs[R_MER] & 2)) {
- break;
- }
- /* fallthrough */
- default:
- if (addr < ARRAY_SIZE(p->regs))
- p->regs[addr] = value;
- break;
- }
- update_irq(p);
-}
-
-static const MemoryRegionOps pic_ops = {
- .read = pic_read,
- .write = pic_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4
- }
-};
-
-static void irq_handler(void *opaque, int irq, int level)
-{
- struct xlx_pic *p = opaque;
-
- /* edge triggered interrupt */
- if (p->c_kind_of_intr & (1 << irq) && p->regs[R_MER] & 2) {
- p->regs[R_ISR] |= (level << irq);
- }
-
- p->irq_pin_state &= ~(1 << irq);
- p->irq_pin_state |= level << irq;
- update_irq(p);
-}
-
-static void xilinx_intc_init(Object *obj)
-{
- struct xlx_pic *p = XILINX_INTC(obj);
-
- qdev_init_gpio_in(DEVICE(obj), irq_handler, 32);
- sysbus_init_irq(SYS_BUS_DEVICE(obj), &p->parent_irq);
-
- memory_region_init_io(&p->mmio, obj, &pic_ops, p, "xlnx.xps-intc",
- R_MAX * 4);
- sysbus_init_mmio(SYS_BUS_DEVICE(obj), &p->mmio);
-}
-
-static Property xilinx_intc_properties[] = {
- DEFINE_PROP_UINT32("kind-of-intr", struct xlx_pic, c_kind_of_intr, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void xilinx_intc_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->props = xilinx_intc_properties;
-}
-
-static const TypeInfo xilinx_intc_info = {
- .name = TYPE_XILINX_INTC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(struct xlx_pic),
- .instance_init = xilinx_intc_init,
- .class_init = xilinx_intc_class_init,
-};
-
-static void xilinx_intc_register_types(void)
-{
- type_register_static(&xilinx_intc_info);
-}
-
-type_init(xilinx_intc_register_types)
diff --git a/qemu/hw/ipack/Makefile.objs b/qemu/hw/ipack/Makefile.objs
deleted file mode 100644
index 8b9bdcb54..000000000
--- a/qemu/hw/ipack/Makefile.objs
+++ /dev/null
@@ -1,2 +0,0 @@
-common-obj-$(CONFIG_IPACK) += ipack.o
-common-obj-$(CONFIG_IPACK) += tpci200.o
diff --git a/qemu/hw/ipack/ipack.c b/qemu/hw/ipack/ipack.c
deleted file mode 100644
index 5f99ed9a7..000000000
--- a/qemu/hw/ipack/ipack.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * QEMU IndustryPack emulation
- *
- * Copyright (C) 2012 Igalia, S.L.
- * Author: Alberto Garcia <agarcia@igalia.com>
- *
- * This code is licensed under the GNU GPL v2 or (at your option) any
- * later version.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/ipack/ipack.h"
-
-IPackDevice *ipack_device_find(IPackBus *bus, int32_t slot)
-{
- BusChild *kid;
-
- QTAILQ_FOREACH(kid, &BUS(bus)->children, sibling) {
- DeviceState *qdev = kid->child;
- IPackDevice *ip = IPACK_DEVICE(qdev);
- if (ip->slot == slot) {
- return ip;
- }
- }
- return NULL;
-}
-
-void ipack_bus_new_inplace(IPackBus *bus, size_t bus_size,
- DeviceState *parent,
- const char *name, uint8_t n_slots,
- qemu_irq_handler handler)
-{
- qbus_create_inplace(bus, bus_size, TYPE_IPACK_BUS, parent, name);
- bus->n_slots = n_slots;
- bus->set_irq = handler;
-}
-
-static void ipack_device_realize(DeviceState *dev, Error **errp)
-{
- IPackDevice *idev = IPACK_DEVICE(dev);
- IPackBus *bus = IPACK_BUS(qdev_get_parent_bus(dev));
- IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(dev);
-
- if (idev->slot < 0) {
- idev->slot = bus->free_slot;
- }
- if (idev->slot >= bus->n_slots) {
- error_setg(errp, "Only %" PRIu8 " slots available.", bus->n_slots);
- return;
- }
- bus->free_slot = idev->slot + 1;
-
- idev->irq = qemu_allocate_irqs(bus->set_irq, idev, 2);
-
- k->realize(dev, errp);
-}
-
-static void ipack_device_unrealize(DeviceState *dev, Error **errp)
-{
- IPackDevice *idev = IPACK_DEVICE(dev);
- IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(dev);
- Error *err = NULL;
-
- if (k->unrealize) {
- k->unrealize(dev, &err);
- error_propagate(errp, err);
- return;
- }
-
- qemu_free_irqs(idev->irq, 2);
-}
-
-static Property ipack_device_props[] = {
- DEFINE_PROP_INT32("slot", IPackDevice, slot, -1),
- DEFINE_PROP_END_OF_LIST()
-};
-
-static void ipack_device_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *k = DEVICE_CLASS(klass);
-
- set_bit(DEVICE_CATEGORY_INPUT, k->categories);
- k->bus_type = TYPE_IPACK_BUS;
- k->realize = ipack_device_realize;
- k->unrealize = ipack_device_unrealize;
- k->props = ipack_device_props;
-}
-
-const VMStateDescription vmstate_ipack_device = {
- .name = "ipack_device",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_INT32(slot, IPackDevice),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const TypeInfo ipack_device_info = {
- .name = TYPE_IPACK_DEVICE,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(IPackDevice),
- .class_size = sizeof(IPackDeviceClass),
- .class_init = ipack_device_class_init,
- .abstract = true,
-};
-
-static const TypeInfo ipack_bus_info = {
- .name = TYPE_IPACK_BUS,
- .parent = TYPE_BUS,
- .instance_size = sizeof(IPackBus),
-};
-
-static void ipack_register_types(void)
-{
- type_register_static(&ipack_device_info);
- type_register_static(&ipack_bus_info);
-}
-
-type_init(ipack_register_types)
diff --git a/qemu/hw/ipack/tpci200.c b/qemu/hw/ipack/tpci200.c
deleted file mode 100644
index fdda6f414..000000000
--- a/qemu/hw/ipack/tpci200.c
+++ /dev/null
@@ -1,656 +0,0 @@
-/*
- * QEMU TEWS TPCI200 IndustryPack carrier emulation
- *
- * Copyright (C) 2012 Igalia, S.L.
- * Author: Alberto Garcia <agarcia@igalia.com>
- *
- * This code is licensed under the GNU GPL v2 or (at your option) any
- * later version.
- */
-
-#include "qemu/osdep.h"
-#include "hw/ipack/ipack.h"
-#include "hw/pci/pci.h"
-#include "qemu/bitops.h"
-
-/* #define DEBUG_TPCI */
-
-#ifdef DEBUG_TPCI
-#define DPRINTF(fmt, ...) \
- do { fprintf(stderr, "TPCI200: " fmt, ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do { } while (0)
-#endif
-
-#define N_MODULES 4
-
-#define IP_ID_SPACE 2
-#define IP_INT_SPACE 3
-#define IP_IO_SPACE_ADDR_MASK 0x7F
-#define IP_ID_SPACE_ADDR_MASK 0x3F
-#define IP_INT_SPACE_ADDR_MASK 0x3F
-
-#define STATUS_INT(IP, INTNO) BIT((IP) * 2 + (INTNO))
-#define STATUS_TIME(IP) BIT((IP) + 12)
-#define STATUS_ERR_ANY 0xF00
-
-#define CTRL_CLKRATE BIT(0)
-#define CTRL_RECOVER BIT(1)
-#define CTRL_TIME_INT BIT(2)
-#define CTRL_ERR_INT BIT(3)
-#define CTRL_INT_EDGE(INTNO) BIT(4 + (INTNO))
-#define CTRL_INT(INTNO) BIT(6 + (INTNO))
-
-#define REG_REV_ID 0x00
-#define REG_IP_A_CTRL 0x02
-#define REG_IP_B_CTRL 0x04
-#define REG_IP_C_CTRL 0x06
-#define REG_IP_D_CTRL 0x08
-#define REG_RESET 0x0A
-#define REG_STATUS 0x0C
-#define IP_N_FROM_REG(REG) ((REG) / 2 - 1)
-
-typedef struct {
- PCIDevice dev;
- IPackBus bus;
- MemoryRegion mmio;
- MemoryRegion io;
- MemoryRegion las0;
- MemoryRegion las1;
- MemoryRegion las2;
- MemoryRegion las3;
- bool big_endian[3];
- uint8_t ctrl[N_MODULES];
- uint16_t status;
- uint8_t int_set;
-} TPCI200State;
-
-#define TYPE_TPCI200 "tpci200"
-
-#define TPCI200(obj) \
- OBJECT_CHECK(TPCI200State, (obj), TYPE_TPCI200)
-
-static const uint8_t local_config_regs[] = {
- 0x00, 0xFF, 0xFF, 0x0F, 0x00, 0xFC, 0xFF, 0x0F, 0x00, 0x00, 0x00,
- 0x0E, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x00, 0x08, 0x01, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x60, 0x41, 0xD4,
- 0xA2, 0x20, 0x41, 0x14, 0xA2, 0x20, 0x41, 0x14, 0xA2, 0x20, 0x01,
- 0x14, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x08, 0x01, 0x02,
- 0x00, 0x04, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x80, 0x02, 0x41,
- 0x00, 0x00, 0x00, 0x00, 0x40, 0x7A, 0x00, 0x52, 0x92, 0x24, 0x02
-};
-
-static void adjust_addr(bool big_endian, hwaddr *addr, unsigned size)
-{
- /* During 8 bit access in big endian mode,
- odd and even addresses are swapped */
- if (big_endian && size == 1) {
- *addr ^= 1;
- }
-}
-
-static uint64_t adjust_value(bool big_endian, uint64_t *val, unsigned size)
-{
- /* Local spaces only support 8/16 bit access,
- * so there's no need to care for sizes > 2 */
- if (big_endian && size == 2) {
- *val = bswap16(*val);
- }
- return *val;
-}
-
-static void tpci200_set_irq(void *opaque, int intno, int level)
-{
- IPackDevice *ip = opaque;
- IPackBus *bus = IPACK_BUS(qdev_get_parent_bus(DEVICE(ip)));
- PCIDevice *pcidev = PCI_DEVICE(BUS(bus)->parent);
- TPCI200State *dev = TPCI200(pcidev);
- unsigned ip_n = ip->slot;
- uint16_t prev_status = dev->status;
-
- assert(ip->slot >= 0 && ip->slot < N_MODULES);
-
- /* The requested interrupt must be enabled in the IP CONTROL
- * register */
- if (!(dev->ctrl[ip_n] & CTRL_INT(intno))) {
- return;
- }
-
- /* Update the interrupt status in the IP STATUS register */
- if (level) {
- dev->status |= STATUS_INT(ip_n, intno);
- } else {
- dev->status &= ~STATUS_INT(ip_n, intno);
- }
-
- /* Return if there are no changes */
- if (dev->status == prev_status) {
- return;
- }
-
- DPRINTF("IP %u INT%u#: %u\n", ip_n, intno, level);
-
- /* Check if the interrupt is edge sensitive */
- if (dev->ctrl[ip_n] & CTRL_INT_EDGE(intno)) {
- if (level) {
- pci_set_irq(&dev->dev, !dev->int_set);
- pci_set_irq(&dev->dev, dev->int_set);
- }
- } else {
- unsigned i, j;
- uint16_t level_status = dev->status;
-
- /* Check if there are any level sensitive interrupts set by
- removing the ones that are edge sensitive from the status
- register */
- for (i = 0; i < N_MODULES; i++) {
- for (j = 0; j < 2; j++) {
- if (dev->ctrl[i] & CTRL_INT_EDGE(j)) {
- level_status &= ~STATUS_INT(i, j);
- }
- }
- }
-
- if (level_status && !dev->int_set) {
- pci_irq_assert(&dev->dev);
- dev->int_set = 1;
- } else if (!level_status && dev->int_set) {
- pci_irq_deassert(&dev->dev);
- dev->int_set = 0;
- }
- }
-}
-
-static uint64_t tpci200_read_cfg(void *opaque, hwaddr addr, unsigned size)
-{
- TPCI200State *s = opaque;
- uint8_t ret = 0;
- if (addr < ARRAY_SIZE(local_config_regs)) {
- ret = local_config_regs[addr];
- }
- /* Endianness is stored in the first bit of these registers */
- if ((addr == 0x2b && s->big_endian[0]) ||
- (addr == 0x2f && s->big_endian[1]) ||
- (addr == 0x33 && s->big_endian[2])) {
- ret |= 1;
- }
- DPRINTF("Read from LCR 0x%x: 0x%x\n", (unsigned) addr, (unsigned) ret);
- return ret;
-}
-
-static void tpci200_write_cfg(void *opaque, hwaddr addr, uint64_t val,
- unsigned size)
-{
- TPCI200State *s = opaque;
- /* Endianness is stored in the first bit of these registers */
- if (addr == 0x2b || addr == 0x2f || addr == 0x33) {
- unsigned las = (addr - 0x2b) / 4;
- s->big_endian[las] = val & 1;
- DPRINTF("LAS%u big endian mode: %u\n", las, (unsigned) val & 1);
- } else {
- DPRINTF("Write to LCR 0x%x: 0x%x\n", (unsigned) addr, (unsigned) val);
- }
-}
-
-static uint64_t tpci200_read_las0(void *opaque, hwaddr addr, unsigned size)
-{
- TPCI200State *s = opaque;
- uint64_t ret = 0;
-
- switch (addr) {
-
- case REG_REV_ID:
- DPRINTF("Read REVISION ID\n"); /* Current value is 0x00 */
- break;
-
- case REG_IP_A_CTRL:
- case REG_IP_B_CTRL:
- case REG_IP_C_CTRL:
- case REG_IP_D_CTRL:
- {
- unsigned ip_n = IP_N_FROM_REG(addr);
- ret = s->ctrl[ip_n];
- DPRINTF("Read IP %c CONTROL: 0x%x\n", 'A' + ip_n, (unsigned) ret);
- }
- break;
-
- case REG_RESET:
- DPRINTF("Read RESET\n"); /* Not implemented */
- break;
-
- case REG_STATUS:
- ret = s->status;
- DPRINTF("Read STATUS: 0x%x\n", (unsigned) ret);
- break;
-
- /* Reserved */
- default:
- DPRINTF("Unsupported read from LAS0 0x%x\n", (unsigned) addr);
- break;
- }
-
- return adjust_value(s->big_endian[0], &ret, size);
-}
-
-static void tpci200_write_las0(void *opaque, hwaddr addr, uint64_t val,
- unsigned size)
-{
- TPCI200State *s = opaque;
-
- adjust_value(s->big_endian[0], &val, size);
-
- switch (addr) {
-
- case REG_REV_ID:
- DPRINTF("Write Revision ID: 0x%x\n", (unsigned) val); /* No effect */
- break;
-
- case REG_IP_A_CTRL:
- case REG_IP_B_CTRL:
- case REG_IP_C_CTRL:
- case REG_IP_D_CTRL:
- {
- unsigned ip_n = IP_N_FROM_REG(addr);
- s->ctrl[ip_n] = val;
- DPRINTF("Write IP %c CONTROL: 0x%x\n", 'A' + ip_n, (unsigned) val);
- }
- break;
-
- case REG_RESET:
- DPRINTF("Write RESET: 0x%x\n", (unsigned) val); /* Not implemented */
- break;
-
- case REG_STATUS:
- {
- unsigned i;
-
- for (i = 0; i < N_MODULES; i++) {
- IPackDevice *ip = ipack_device_find(&s->bus, i);
-
- if (ip != NULL) {
- if (val & STATUS_INT(i, 0)) {
- DPRINTF("Clear IP %c INT0# status\n", 'A' + i);
- qemu_irq_lower(ip->irq[0]);
- }
- if (val & STATUS_INT(i, 1)) {
- DPRINTF("Clear IP %c INT1# status\n", 'A' + i);
- qemu_irq_lower(ip->irq[1]);
- }
- }
-
- if (val & STATUS_TIME(i)) {
- DPRINTF("Clear IP %c timeout\n", 'A' + i);
- s->status &= ~STATUS_TIME(i);
- }
- }
-
- if (val & STATUS_ERR_ANY) {
- DPRINTF("Unexpected write to STATUS register: 0x%x\n",
- (unsigned) val);
- }
- }
- break;
-
- /* Reserved */
- default:
- DPRINTF("Unsupported write to LAS0 0x%x: 0x%x\n",
- (unsigned) addr, (unsigned) val);
- break;
- }
-}
-
-static uint64_t tpci200_read_las1(void *opaque, hwaddr addr, unsigned size)
-{
- TPCI200State *s = opaque;
- IPackDevice *ip;
- uint64_t ret = 0;
- unsigned ip_n, space;
- uint8_t offset;
-
- adjust_addr(s->big_endian[1], &addr, size);
-
- /*
- * The address is divided into the IP module number (0-4), the IP
- * address space (I/O, ID, INT) and the offset within that space.
- */
- ip_n = addr >> 8;
- space = (addr >> 6) & 3;
- ip = ipack_device_find(&s->bus, ip_n);
-
- if (ip == NULL) {
- DPRINTF("Read LAS1: IP module %u not installed\n", ip_n);
- } else {
- IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(ip);
- switch (space) {
-
- case IP_ID_SPACE:
- offset = addr & IP_ID_SPACE_ADDR_MASK;
- if (k->id_read) {
- ret = k->id_read(ip, offset);
- }
- break;
-
- case IP_INT_SPACE:
- offset = addr & IP_INT_SPACE_ADDR_MASK;
-
- /* Read address 0 to ACK IP INT0# and address 2 to ACK IP INT1# */
- if (offset == 0 || offset == 2) {
- unsigned intno = offset / 2;
- bool int_set = s->status & STATUS_INT(ip_n, intno);
- bool int_edge_sensitive = s->ctrl[ip_n] & CTRL_INT_EDGE(intno);
- if (int_set && !int_edge_sensitive) {
- qemu_irq_lower(ip->irq[intno]);
- }
- }
-
- if (k->int_read) {
- ret = k->int_read(ip, offset);
- }
- break;
-
- default:
- offset = addr & IP_IO_SPACE_ADDR_MASK;
- if (k->io_read) {
- ret = k->io_read(ip, offset);
- }
- break;
- }
- }
-
- return adjust_value(s->big_endian[1], &ret, size);
-}
-
-static void tpci200_write_las1(void *opaque, hwaddr addr, uint64_t val,
- unsigned size)
-{
- TPCI200State *s = opaque;
- IPackDevice *ip;
- unsigned ip_n, space;
- uint8_t offset;
-
- adjust_addr(s->big_endian[1], &addr, size);
- adjust_value(s->big_endian[1], &val, size);
-
- /*
- * The address is divided into the IP module number, the IP
- * address space (I/O, ID, INT) and the offset within that space.
- */
- ip_n = addr >> 8;
- space = (addr >> 6) & 3;
- ip = ipack_device_find(&s->bus, ip_n);
-
- if (ip == NULL) {
- DPRINTF("Write LAS1: IP module %u not installed\n", ip_n);
- } else {
- IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(ip);
- switch (space) {
-
- case IP_ID_SPACE:
- offset = addr & IP_ID_SPACE_ADDR_MASK;
- if (k->id_write) {
- k->id_write(ip, offset, val);
- }
- break;
-
- case IP_INT_SPACE:
- offset = addr & IP_INT_SPACE_ADDR_MASK;
- if (k->int_write) {
- k->int_write(ip, offset, val);
- }
- break;
-
- default:
- offset = addr & IP_IO_SPACE_ADDR_MASK;
- if (k->io_write) {
- k->io_write(ip, offset, val);
- }
- break;
- }
- }
-}
-
-static uint64_t tpci200_read_las2(void *opaque, hwaddr addr, unsigned size)
-{
- TPCI200State *s = opaque;
- IPackDevice *ip;
- uint64_t ret = 0;
- unsigned ip_n;
- uint32_t offset;
-
- adjust_addr(s->big_endian[2], &addr, size);
-
- /*
- * The address is divided into the IP module number and the offset
- * within the IP module MEM space.
- */
- ip_n = addr >> 23;
- offset = addr & 0x7fffff;
- ip = ipack_device_find(&s->bus, ip_n);
-
- if (ip == NULL) {
- DPRINTF("Read LAS2: IP module %u not installed\n", ip_n);
- } else {
- IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(ip);
- if (k->mem_read16) {
- ret = k->mem_read16(ip, offset);
- }
- }
-
- return adjust_value(s->big_endian[2], &ret, size);
-}
-
-static void tpci200_write_las2(void *opaque, hwaddr addr, uint64_t val,
- unsigned size)
-{
- TPCI200State *s = opaque;
- IPackDevice *ip;
- unsigned ip_n;
- uint32_t offset;
-
- adjust_addr(s->big_endian[2], &addr, size);
- adjust_value(s->big_endian[2], &val, size);
-
- /*
- * The address is divided into the IP module number and the offset
- * within the IP module MEM space.
- */
- ip_n = addr >> 23;
- offset = addr & 0x7fffff;
- ip = ipack_device_find(&s->bus, ip_n);
-
- if (ip == NULL) {
- DPRINTF("Write LAS2: IP module %u not installed\n", ip_n);
- } else {
- IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(ip);
- if (k->mem_write16) {
- k->mem_write16(ip, offset, val);
- }
- }
-}
-
-static uint64_t tpci200_read_las3(void *opaque, hwaddr addr, unsigned size)
-{
- TPCI200State *s = opaque;
- IPackDevice *ip;
- uint64_t ret = 0;
- /*
- * The address is divided into the IP module number and the offset
- * within the IP module MEM space.
- */
- unsigned ip_n = addr >> 22;
- uint32_t offset = addr & 0x3fffff;
-
- ip = ipack_device_find(&s->bus, ip_n);
-
- if (ip == NULL) {
- DPRINTF("Read LAS3: IP module %u not installed\n", ip_n);
- } else {
- IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(ip);
- if (k->mem_read8) {
- ret = k->mem_read8(ip, offset);
- }
- }
-
- return ret;
-}
-
-static void tpci200_write_las3(void *opaque, hwaddr addr, uint64_t val,
- unsigned size)
-{
- TPCI200State *s = opaque;
- IPackDevice *ip;
- /*
- * The address is divided into the IP module number and the offset
- * within the IP module MEM space.
- */
- unsigned ip_n = addr >> 22;
- uint32_t offset = addr & 0x3fffff;
-
- ip = ipack_device_find(&s->bus, ip_n);
-
- if (ip == NULL) {
- DPRINTF("Write LAS3: IP module %u not installed\n", ip_n);
- } else {
- IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(ip);
- if (k->mem_write8) {
- k->mem_write8(ip, offset, val);
- }
- }
-}
-
-static const MemoryRegionOps tpci200_cfg_ops = {
- .read = tpci200_read_cfg,
- .write = tpci200_write_cfg,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 1,
- .max_access_size = 4
- },
- .impl = {
- .min_access_size = 1,
- .max_access_size = 1
- }
-};
-
-static const MemoryRegionOps tpci200_las0_ops = {
- .read = tpci200_read_las0,
- .write = tpci200_write_las0,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 2,
- .max_access_size = 2
- }
-};
-
-static const MemoryRegionOps tpci200_las1_ops = {
- .read = tpci200_read_las1,
- .write = tpci200_write_las1,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 1,
- .max_access_size = 2
- }
-};
-
-static const MemoryRegionOps tpci200_las2_ops = {
- .read = tpci200_read_las2,
- .write = tpci200_write_las2,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 1,
- .max_access_size = 2
- }
-};
-
-static const MemoryRegionOps tpci200_las3_ops = {
- .read = tpci200_read_las3,
- .write = tpci200_write_las3,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 1,
- .max_access_size = 1
- }
-};
-
-static void tpci200_realize(PCIDevice *pci_dev, Error **errp)
-{
- TPCI200State *s = TPCI200(pci_dev);
- uint8_t *c = s->dev.config;
-
- pci_set_word(c + PCI_COMMAND, 0x0003);
- pci_set_word(c + PCI_STATUS, 0x0280);
-
- pci_set_byte(c + PCI_INTERRUPT_PIN, 0x01); /* Interrupt pin A */
-
- pci_set_byte(c + PCI_CAPABILITY_LIST, 0x40);
- pci_set_long(c + 0x40, 0x48014801);
- pci_set_long(c + 0x48, 0x00024C06);
- pci_set_long(c + 0x4C, 0x00000003);
-
- memory_region_init_io(&s->mmio, OBJECT(s), &tpci200_cfg_ops,
- s, "tpci200_mmio", 128);
- memory_region_init_io(&s->io, OBJECT(s), &tpci200_cfg_ops,
- s, "tpci200_io", 128);
- memory_region_init_io(&s->las0, OBJECT(s), &tpci200_las0_ops,
- s, "tpci200_las0", 256);
- memory_region_init_io(&s->las1, OBJECT(s), &tpci200_las1_ops,
- s, "tpci200_las1", 1024);
- memory_region_init_io(&s->las2, OBJECT(s), &tpci200_las2_ops,
- s, "tpci200_las2", 1024*1024*32);
- memory_region_init_io(&s->las3, OBJECT(s), &tpci200_las3_ops,
- s, "tpci200_las3", 1024*1024*16);
- pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio);
- pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->io);
- pci_register_bar(&s->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->las0);
- pci_register_bar(&s->dev, 3, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->las1);
- pci_register_bar(&s->dev, 4, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->las2);
- pci_register_bar(&s->dev, 5, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->las3);
-
- ipack_bus_new_inplace(&s->bus, sizeof(s->bus), DEVICE(pci_dev), NULL,
- N_MODULES, tpci200_set_irq);
-}
-
-static const VMStateDescription vmstate_tpci200 = {
- .name = "tpci200",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(dev, TPCI200State),
- VMSTATE_BOOL_ARRAY(big_endian, TPCI200State, 3),
- VMSTATE_UINT8_ARRAY(ctrl, TPCI200State, N_MODULES),
- VMSTATE_UINT16(status, TPCI200State),
- VMSTATE_UINT8(int_set, TPCI200State),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void tpci200_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = tpci200_realize;
- k->vendor_id = PCI_VENDOR_ID_TEWS;
- k->device_id = PCI_DEVICE_ID_TEWS_TPCI200;
- k->class_id = PCI_CLASS_BRIDGE_OTHER;
- k->subsystem_vendor_id = PCI_VENDOR_ID_TEWS;
- k->subsystem_id = 0x300A;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
- dc->desc = "TEWS TPCI200 IndustryPack carrier";
- dc->vmsd = &vmstate_tpci200;
-}
-
-static const TypeInfo tpci200_info = {
- .name = TYPE_TPCI200,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(TPCI200State),
- .class_init = tpci200_class_init,
-};
-
-static void tpci200_register_types(void)
-{
- type_register_static(&tpci200_info);
-}
-
-type_init(tpci200_register_types)
diff --git a/qemu/hw/ipmi/Makefile.objs b/qemu/hw/ipmi/Makefile.objs
deleted file mode 100644
index a90318d5b..000000000
--- a/qemu/hw/ipmi/Makefile.objs
+++ /dev/null
@@ -1,5 +0,0 @@
-common-obj-$(CONFIG_IPMI) += ipmi.o
-common-obj-$(CONFIG_IPMI_LOCAL) += ipmi_bmc_sim.o
-common-obj-$(CONFIG_IPMI_LOCAL) += ipmi_bmc_extern.o
-common-obj-$(CONFIG_ISA_IPMI_KCS) += isa_ipmi_kcs.o
-common-obj-$(CONFIG_ISA_IPMI_BT) += isa_ipmi_bt.o
diff --git a/qemu/hw/ipmi/ipmi.c b/qemu/hw/ipmi/ipmi.c
deleted file mode 100644
index 6adec1e99..000000000
--- a/qemu/hw/ipmi/ipmi.c
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * QEMU IPMI emulation
- *
- * Copyright (c) 2015 Corey Minyard, MontaVista Software, LLC
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/ipmi/ipmi.h"
-#include "sysemu/sysemu.h"
-#include "qmp-commands.h"
-#include "qom/object_interfaces.h"
-#include "qapi/visitor.h"
-
-static int ipmi_do_hw_op(IPMIInterface *s, enum ipmi_op op, int checkonly)
-{
- switch (op) {
- case IPMI_RESET_CHASSIS:
- if (checkonly) {
- return 0;
- }
- qemu_system_reset_request();
- return 0;
-
- case IPMI_POWEROFF_CHASSIS:
- if (checkonly) {
- return 0;
- }
- qemu_system_powerdown_request();
- return 0;
-
- case IPMI_SEND_NMI:
- if (checkonly) {
- return 0;
- }
- qmp_inject_nmi(NULL);
- return 0;
-
- case IPMI_POWERCYCLE_CHASSIS:
- case IPMI_PULSE_DIAG_IRQ:
- case IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP:
- case IPMI_POWERON_CHASSIS:
- default:
- return IPMI_CC_COMMAND_NOT_SUPPORTED;
- }
-}
-
-static void ipmi_interface_class_init(ObjectClass *class, void *data)
-{
- IPMIInterfaceClass *ik = IPMI_INTERFACE_CLASS(class);
-
- ik->do_hw_op = ipmi_do_hw_op;
-}
-
-static TypeInfo ipmi_interface_type_info = {
- .name = TYPE_IPMI_INTERFACE,
- .parent = TYPE_INTERFACE,
- .class_size = sizeof(IPMIInterfaceClass),
- .class_init = ipmi_interface_class_init,
-};
-
-static void isa_ipmi_bmc_check(Object *obj, const char *name,
- Object *val, Error **errp)
-{
- IPMIBmc *bmc = IPMI_BMC(val);
-
- if (bmc->intf)
- error_setg(errp, "BMC object is already in use");
-}
-
-void ipmi_bmc_find_and_link(Object *obj, Object **bmc)
-{
- object_property_add_link(obj, "bmc", TYPE_IPMI_BMC, bmc,
- isa_ipmi_bmc_check,
- OBJ_PROP_LINK_UNREF_ON_RELEASE,
- &error_abort);
-}
-
-static Property ipmi_bmc_properties[] = {
- DEFINE_PROP_UINT8("slave_addr", IPMIBmc, slave_addr, 0x20),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void bmc_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- dc->props = ipmi_bmc_properties;
-}
-
-static TypeInfo ipmi_bmc_type_info = {
- .name = TYPE_IPMI_BMC,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(IPMIBmc),
- .abstract = true,
- .class_size = sizeof(IPMIBmcClass),
- .class_init = bmc_class_init,
-};
-
-static void ipmi_register_types(void)
-{
- type_register_static(&ipmi_interface_type_info);
- type_register_static(&ipmi_bmc_type_info);
-}
-
-type_init(ipmi_register_types)
-
-static IPMIFwInfo *ipmi_fw_info;
-static unsigned int ipmi_fw_info_len;
-
-static uint32_t current_uuid = 1;
-
-void ipmi_add_fwinfo(IPMIFwInfo *info, Error **errp)
-{
- info->uuid = current_uuid++;
- ipmi_fw_info = g_realloc(ipmi_fw_info,
- sizeof(*ipmi_fw_info) * (ipmi_fw_info_len + 1));
- ipmi_fw_info[ipmi_fw_info_len] = *info;
-}
-
-IPMIFwInfo *ipmi_first_fwinfo(void)
-{
- return ipmi_fw_info;
-}
-
-IPMIFwInfo *ipmi_next_fwinfo(IPMIFwInfo *current)
-{
- current++;
- if (current >= &ipmi_fw_info[ipmi_fw_info_len]) {
- return NULL;
- }
- return current;
-}
diff --git a/qemu/hw/ipmi/ipmi_bmc_extern.c b/qemu/hw/ipmi/ipmi_bmc_extern.c
deleted file mode 100644
index fe12112a2..000000000
--- a/qemu/hw/ipmi/ipmi_bmc_extern.c
+++ /dev/null
@@ -1,519 +0,0 @@
-/*
- * IPMI BMC external connection
- *
- * Copyright (c) 2015 Corey Minyard, MontaVista Software, LLC
- *
- * 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.
- */
-
-/*
- * This is designed to connect with OpenIPMI's lanserv serial interface
- * using the "VM" connection type. See that for details.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu/timer.h"
-#include "sysemu/char.h"
-#include "sysemu/sysemu.h"
-#include "hw/ipmi/ipmi.h"
-
-#define VM_MSG_CHAR 0xA0 /* Marks end of message */
-#define VM_CMD_CHAR 0xA1 /* Marks end of a command */
-#define VM_ESCAPE_CHAR 0xAA /* Set bit 4 from the next byte to 0 */
-
-#define VM_PROTOCOL_VERSION 1
-#define VM_CMD_VERSION 0xff /* A version number byte follows */
-#define VM_CMD_NOATTN 0x00
-#define VM_CMD_ATTN 0x01
-#define VM_CMD_ATTN_IRQ 0x02
-#define VM_CMD_POWEROFF 0x03
-#define VM_CMD_RESET 0x04
-#define VM_CMD_ENABLE_IRQ 0x05 /* Enable/disable the messaging irq */
-#define VM_CMD_DISABLE_IRQ 0x06
-#define VM_CMD_SEND_NMI 0x07
-#define VM_CMD_CAPABILITIES 0x08
-#define VM_CAPABILITIES_POWER 0x01
-#define VM_CAPABILITIES_RESET 0x02
-#define VM_CAPABILITIES_IRQ 0x04
-#define VM_CAPABILITIES_NMI 0x08
-#define VM_CAPABILITIES_ATTN 0x10
-#define VM_CMD_FORCEOFF 0x09
-
-#define TYPE_IPMI_BMC_EXTERN "ipmi-bmc-extern"
-#define IPMI_BMC_EXTERN(obj) OBJECT_CHECK(IPMIBmcExtern, (obj), \
- TYPE_IPMI_BMC_EXTERN)
-typedef struct IPMIBmcExtern {
- IPMIBmc parent;
-
- CharDriverState *chr;
-
- bool connected;
-
- unsigned char inbuf[MAX_IPMI_MSG_SIZE + 2];
- unsigned int inpos;
- bool in_escape;
- bool in_too_many;
- bool waiting_rsp;
- bool sending_cmd;
-
- unsigned char outbuf[(MAX_IPMI_MSG_SIZE + 2) * 2 + 1];
- unsigned int outpos;
- unsigned int outlen;
-
- struct QEMUTimer *extern_timer;
-
- /* A reset event is pending to be sent upstream. */
- bool send_reset;
-} IPMIBmcExtern;
-
-static int can_receive(void *opaque);
-static void receive(void *opaque, const uint8_t *buf, int size);
-static void chr_event(void *opaque, int event);
-
-static unsigned char
-ipmb_checksum(const unsigned char *data, int size, unsigned char start)
-{
- unsigned char csum = start;
-
- for (; size > 0; size--, data++) {
- csum += *data;
- }
- return csum;
-}
-
-static void continue_send(IPMIBmcExtern *ibe)
-{
- if (ibe->outlen == 0) {
- goto check_reset;
- }
- send:
- ibe->outpos += qemu_chr_fe_write(ibe->chr, ibe->outbuf + ibe->outpos,
- ibe->outlen - ibe->outpos);
- if (ibe->outpos < ibe->outlen) {
- /* Not fully transmitted, try again in a 10ms */
- timer_mod_ns(ibe->extern_timer,
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 10000000);
- } else {
- /* Sent */
- ibe->outlen = 0;
- ibe->outpos = 0;
- if (!ibe->sending_cmd) {
- ibe->waiting_rsp = true;
- } else {
- ibe->sending_cmd = false;
- }
- check_reset:
- if (ibe->connected && ibe->send_reset) {
- /* Send the reset */
- ibe->outbuf[0] = VM_CMD_RESET;
- ibe->outbuf[1] = VM_CMD_CHAR;
- ibe->outlen = 2;
- ibe->outpos = 0;
- ibe->send_reset = false;
- ibe->sending_cmd = true;
- goto send;
- }
-
- if (ibe->waiting_rsp) {
- /* Make sure we get a response within 4 seconds. */
- timer_mod_ns(ibe->extern_timer,
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 4000000000ULL);
- }
- }
- return;
-}
-
-static void extern_timeout(void *opaque)
-{
- IPMIBmcExtern *ibe = opaque;
- IPMIInterface *s = ibe->parent.intf;
-
- if (ibe->connected) {
- if (ibe->waiting_rsp && (ibe->outlen == 0)) {
- IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
- /* The message response timed out, return an error. */
- ibe->waiting_rsp = false;
- ibe->inbuf[1] = ibe->outbuf[1] | 0x04;
- ibe->inbuf[2] = ibe->outbuf[2];
- ibe->inbuf[3] = IPMI_CC_TIMEOUT;
- k->handle_rsp(s, ibe->outbuf[0], ibe->inbuf + 1, 3);
- } else {
- continue_send(ibe);
- }
- }
-}
-
-static void addchar(IPMIBmcExtern *ibe, unsigned char ch)
-{
- switch (ch) {
- case VM_MSG_CHAR:
- case VM_CMD_CHAR:
- case VM_ESCAPE_CHAR:
- ibe->outbuf[ibe->outlen] = VM_ESCAPE_CHAR;
- ibe->outlen++;
- ch |= 0x10;
- /* No break */
-
- default:
- ibe->outbuf[ibe->outlen] = ch;
- ibe->outlen++;
- }
-}
-
-static void ipmi_bmc_extern_handle_command(IPMIBmc *b,
- uint8_t *cmd, unsigned int cmd_len,
- unsigned int max_cmd_len,
- uint8_t msg_id)
-{
- IPMIBmcExtern *ibe = IPMI_BMC_EXTERN(b);
- IPMIInterface *s = ibe->parent.intf;
- uint8_t err = 0, csum;
- unsigned int i;
-
- if (ibe->outlen) {
- /* We already have a command queued. Shouldn't ever happen. */
- fprintf(stderr, "IPMI KCS: Got command when not finished with the"
- " previous commmand\n");
- abort();
- }
-
- /* If it's too short or it was truncated, return an error. */
- if (cmd_len < 2) {
- err = IPMI_CC_REQUEST_DATA_LENGTH_INVALID;
- } else if ((cmd_len > max_cmd_len) || (cmd_len > MAX_IPMI_MSG_SIZE)) {
- err = IPMI_CC_REQUEST_DATA_TRUNCATED;
- } else if (!ibe->connected) {
- err = IPMI_CC_BMC_INIT_IN_PROGRESS;
- }
- if (err) {
- IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
- unsigned char rsp[3];
- rsp[0] = cmd[0] | 0x04;
- rsp[1] = cmd[1];
- rsp[2] = err;
- ibe->waiting_rsp = false;
- k->handle_rsp(s, msg_id, rsp, 3);
- goto out;
- }
-
- addchar(ibe, msg_id);
- for (i = 0; i < cmd_len; i++) {
- addchar(ibe, cmd[i]);
- }
- csum = ipmb_checksum(&msg_id, 1, 0);
- addchar(ibe, -ipmb_checksum(cmd, cmd_len, csum));
-
- ibe->outbuf[ibe->outlen] = VM_MSG_CHAR;
- ibe->outlen++;
-
- /* Start the transmit */
- continue_send(ibe);
-
- out:
- return;
-}
-
-static void handle_hw_op(IPMIBmcExtern *ibe, unsigned char hw_op)
-{
- IPMIInterface *s = ibe->parent.intf;
- IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
-
- switch (hw_op) {
- case VM_CMD_VERSION:
- /* We only support one version at this time. */
- break;
-
- case VM_CMD_NOATTN:
- k->set_atn(s, 0, 0);
- break;
-
- case VM_CMD_ATTN:
- k->set_atn(s, 1, 0);
- break;
-
- case VM_CMD_ATTN_IRQ:
- k->set_atn(s, 1, 1);
- break;
-
- case VM_CMD_POWEROFF:
- k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0);
- break;
-
- case VM_CMD_RESET:
- k->do_hw_op(s, IPMI_RESET_CHASSIS, 0);
- break;
-
- case VM_CMD_ENABLE_IRQ:
- k->set_irq_enable(s, 1);
- break;
-
- case VM_CMD_DISABLE_IRQ:
- k->set_irq_enable(s, 0);
- break;
-
- case VM_CMD_SEND_NMI:
- k->do_hw_op(s, IPMI_SEND_NMI, 0);
- break;
-
- case VM_CMD_FORCEOFF:
- qemu_system_shutdown_request();
- break;
- }
-}
-
-static void handle_msg(IPMIBmcExtern *ibe)
-{
- IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(ibe->parent.intf);
-
- if (ibe->in_escape) {
- ipmi_debug("msg escape not ended\n");
- return;
- }
- if (ibe->inpos < 5) {
- ipmi_debug("msg too short\n");
- return;
- }
- if (ibe->in_too_many) {
- ibe->inbuf[3] = IPMI_CC_REQUEST_DATA_TRUNCATED;
- ibe->inpos = 4;
- } else if (ipmb_checksum(ibe->inbuf, ibe->inpos, 0) != 0) {
- ipmi_debug("msg checksum failure\n");
- return;
- } else {
- ibe->inpos--; /* Remove checkum */
- }
-
- timer_del(ibe->extern_timer);
- ibe->waiting_rsp = false;
- k->handle_rsp(ibe->parent.intf, ibe->inbuf[0], ibe->inbuf + 1, ibe->inpos - 1);
-}
-
-static int can_receive(void *opaque)
-{
- return 1;
-}
-
-static void receive(void *opaque, const uint8_t *buf, int size)
-{
- IPMIBmcExtern *ibe = opaque;
- int i;
- unsigned char hw_op;
-
- for (i = 0; i < size; i++) {
- unsigned char ch = buf[i];
-
- switch (ch) {
- case VM_MSG_CHAR:
- handle_msg(ibe);
- ibe->in_too_many = false;
- ibe->inpos = 0;
- break;
-
- case VM_CMD_CHAR:
- if (ibe->in_too_many) {
- ipmi_debug("cmd in too many\n");
- ibe->in_too_many = false;
- ibe->inpos = 0;
- break;
- }
- if (ibe->in_escape) {
- ipmi_debug("cmd in escape\n");
- ibe->in_too_many = false;
- ibe->inpos = 0;
- ibe->in_escape = false;
- break;
- }
- ibe->in_too_many = false;
- if (ibe->inpos < 1) {
- break;
- }
- hw_op = ibe->inbuf[0];
- ibe->inpos = 0;
- goto out_hw_op;
- break;
-
- case VM_ESCAPE_CHAR:
- ibe->in_escape = true;
- break;
-
- default:
- if (ibe->in_escape) {
- ch &= ~0x10;
- ibe->in_escape = false;
- }
- if (ibe->in_too_many) {
- break;
- }
- if (ibe->inpos >= sizeof(ibe->inbuf)) {
- ibe->in_too_many = true;
- break;
- }
- ibe->inbuf[ibe->inpos] = ch;
- ibe->inpos++;
- break;
- }
- }
- return;
-
- out_hw_op:
- handle_hw_op(ibe, hw_op);
-}
-
-static void chr_event(void *opaque, int event)
-{
- IPMIBmcExtern *ibe = opaque;
- IPMIInterface *s = ibe->parent.intf;
- IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
- unsigned char v;
-
- switch (event) {
- case CHR_EVENT_OPENED:
- ibe->connected = true;
- ibe->outpos = 0;
- ibe->outlen = 0;
- addchar(ibe, VM_CMD_VERSION);
- addchar(ibe, VM_PROTOCOL_VERSION);
- ibe->outbuf[ibe->outlen] = VM_CMD_CHAR;
- ibe->outlen++;
- addchar(ibe, VM_CMD_CAPABILITIES);
- v = VM_CAPABILITIES_IRQ | VM_CAPABILITIES_ATTN;
- if (k->do_hw_op(ibe->parent.intf, IPMI_POWEROFF_CHASSIS, 1) == 0) {
- v |= VM_CAPABILITIES_POWER;
- }
- if (k->do_hw_op(ibe->parent.intf, IPMI_RESET_CHASSIS, 1) == 0) {
- v |= VM_CAPABILITIES_RESET;
- }
- if (k->do_hw_op(ibe->parent.intf, IPMI_SEND_NMI, 1) == 0) {
- v |= VM_CAPABILITIES_NMI;
- }
- addchar(ibe, v);
- ibe->outbuf[ibe->outlen] = VM_CMD_CHAR;
- ibe->outlen++;
- ibe->sending_cmd = false;
- continue_send(ibe);
- break;
-
- case CHR_EVENT_CLOSED:
- if (!ibe->connected) {
- return;
- }
- ibe->connected = false;
- if (ibe->waiting_rsp) {
- ibe->waiting_rsp = false;
- ibe->inbuf[1] = ibe->outbuf[1] | 0x04;
- ibe->inbuf[2] = ibe->outbuf[2];
- ibe->inbuf[3] = IPMI_CC_BMC_INIT_IN_PROGRESS;
- k->handle_rsp(s, ibe->outbuf[0], ibe->inbuf + 1, 3);
- }
- break;
- }
-}
-
-static void ipmi_bmc_extern_handle_reset(IPMIBmc *b)
-{
- IPMIBmcExtern *ibe = IPMI_BMC_EXTERN(b);
-
- ibe->send_reset = true;
- continue_send(ibe);
-}
-
-static void ipmi_bmc_extern_realize(DeviceState *dev, Error **errp)
-{
- IPMIBmcExtern *ibe = IPMI_BMC_EXTERN(dev);
-
- if (!ibe->chr) {
- error_setg(errp, "IPMI external bmc requires chardev attribute");
- return;
- }
-
- qemu_chr_add_handlers(ibe->chr, can_receive, receive, chr_event, ibe);
-}
-
-static int ipmi_bmc_extern_post_migrate(void *opaque, int version_id)
-{
- IPMIBmcExtern *ibe = opaque;
-
- /*
- * We don't directly restore waiting_rsp, Instead, we return an
- * error on the interface if a response was being waited for.
- */
- if (ibe->waiting_rsp) {
- IPMIInterface *ii = ibe->parent.intf;
- IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
-
- ibe->waiting_rsp = false;
- ibe->inbuf[1] = ibe->outbuf[1] | 0x04;
- ibe->inbuf[2] = ibe->outbuf[2];
- ibe->inbuf[3] = IPMI_CC_BMC_INIT_IN_PROGRESS;
- iic->handle_rsp(ii, ibe->outbuf[0], ibe->inbuf + 1, 3);
- }
- return 0;
-}
-
-static const VMStateDescription vmstate_ipmi_bmc_extern = {
- .name = TYPE_IPMI_BMC_EXTERN,
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = ipmi_bmc_extern_post_migrate,
- .fields = (VMStateField[]) {
- VMSTATE_BOOL(send_reset, IPMIBmcExtern),
- VMSTATE_BOOL(waiting_rsp, IPMIBmcExtern),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void ipmi_bmc_extern_init(Object *obj)
-{
- IPMIBmcExtern *ibe = IPMI_BMC_EXTERN(obj);
-
- ibe->extern_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, extern_timeout, ibe);
- vmstate_register(NULL, 0, &vmstate_ipmi_bmc_extern, ibe);
-}
-
-static Property ipmi_bmc_extern_properties[] = {
- DEFINE_PROP_CHR("chardev", IPMIBmcExtern, chr),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void ipmi_bmc_extern_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
- IPMIBmcClass *bk = IPMI_BMC_CLASS(oc);
-
- bk->handle_command = ipmi_bmc_extern_handle_command;
- bk->handle_reset = ipmi_bmc_extern_handle_reset;
- dc->realize = ipmi_bmc_extern_realize;
- dc->props = ipmi_bmc_extern_properties;
-}
-
-static const TypeInfo ipmi_bmc_extern_type = {
- .name = TYPE_IPMI_BMC_EXTERN,
- .parent = TYPE_IPMI_BMC,
- .instance_size = sizeof(IPMIBmcExtern),
- .instance_init = ipmi_bmc_extern_init,
- .class_init = ipmi_bmc_extern_class_init,
- };
-
-static void ipmi_bmc_extern_register_types(void)
-{
- type_register_static(&ipmi_bmc_extern_type);
-}
-
-type_init(ipmi_bmc_extern_register_types)
diff --git a/qemu/hw/ipmi/ipmi_bmc_sim.c b/qemu/hw/ipmi/ipmi_bmc_sim.c
deleted file mode 100644
index dc9c14cd2..000000000
--- a/qemu/hw/ipmi/ipmi_bmc_sim.c
+++ /dev/null
@@ -1,1810 +0,0 @@
-/*
- * IPMI BMC emulation
- *
- * Copyright (c) 2015 Corey Minyard, MontaVista Software, LLC
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "sysemu/sysemu.h"
-#include "qemu/timer.h"
-#include "hw/ipmi/ipmi.h"
-#include "qemu/error-report.h"
-
-#define IPMI_NETFN_CHASSIS 0x00
-
-#define IPMI_CMD_GET_CHASSIS_CAPABILITIES 0x00
-#define IPMI_CMD_GET_CHASSIS_STATUS 0x01
-#define IPMI_CMD_CHASSIS_CONTROL 0x02
-#define IPMI_CMD_GET_SYS_RESTART_CAUSE 0x09
-
-#define IPMI_NETFN_SENSOR_EVENT 0x04
-
-#define IPMI_CMD_SET_SENSOR_EVT_ENABLE 0x28
-#define IPMI_CMD_GET_SENSOR_EVT_ENABLE 0x29
-#define IPMI_CMD_REARM_SENSOR_EVTS 0x2a
-#define IPMI_CMD_GET_SENSOR_EVT_STATUS 0x2b
-#define IPMI_CMD_GET_SENSOR_READING 0x2d
-#define IPMI_CMD_SET_SENSOR_TYPE 0x2e
-#define IPMI_CMD_GET_SENSOR_TYPE 0x2f
-
-/* #define IPMI_NETFN_APP 0x06 In ipmi.h */
-
-#define IPMI_CMD_GET_DEVICE_ID 0x01
-#define IPMI_CMD_COLD_RESET 0x02
-#define IPMI_CMD_WARM_RESET 0x03
-#define IPMI_CMD_SET_ACPI_POWER_STATE 0x06
-#define IPMI_CMD_GET_ACPI_POWER_STATE 0x07
-#define IPMI_CMD_GET_DEVICE_GUID 0x08
-#define IPMI_CMD_RESET_WATCHDOG_TIMER 0x22
-#define IPMI_CMD_SET_WATCHDOG_TIMER 0x24
-#define IPMI_CMD_GET_WATCHDOG_TIMER 0x25
-#define IPMI_CMD_SET_BMC_GLOBAL_ENABLES 0x2e
-#define IPMI_CMD_GET_BMC_GLOBAL_ENABLES 0x2f
-#define IPMI_CMD_CLR_MSG_FLAGS 0x30
-#define IPMI_CMD_GET_MSG_FLAGS 0x31
-#define IPMI_CMD_GET_MSG 0x33
-#define IPMI_CMD_SEND_MSG 0x34
-#define IPMI_CMD_READ_EVT_MSG_BUF 0x35
-
-#define IPMI_NETFN_STORAGE 0x0a
-
-#define IPMI_CMD_GET_SDR_REP_INFO 0x20
-#define IPMI_CMD_GET_SDR_REP_ALLOC_INFO 0x21
-#define IPMI_CMD_RESERVE_SDR_REP 0x22
-#define IPMI_CMD_GET_SDR 0x23
-#define IPMI_CMD_ADD_SDR 0x24
-#define IPMI_CMD_PARTIAL_ADD_SDR 0x25
-#define IPMI_CMD_DELETE_SDR 0x26
-#define IPMI_CMD_CLEAR_SDR_REP 0x27
-#define IPMI_CMD_GET_SDR_REP_TIME 0x28
-#define IPMI_CMD_SET_SDR_REP_TIME 0x29
-#define IPMI_CMD_ENTER_SDR_REP_UPD_MODE 0x2A
-#define IPMI_CMD_EXIT_SDR_REP_UPD_MODE 0x2B
-#define IPMI_CMD_RUN_INIT_AGENT 0x2C
-#define IPMI_CMD_GET_SEL_INFO 0x40
-#define IPMI_CMD_GET_SEL_ALLOC_INFO 0x41
-#define IPMI_CMD_RESERVE_SEL 0x42
-#define IPMI_CMD_GET_SEL_ENTRY 0x43
-#define IPMI_CMD_ADD_SEL_ENTRY 0x44
-#define IPMI_CMD_PARTIAL_ADD_SEL_ENTRY 0x45
-#define IPMI_CMD_DELETE_SEL_ENTRY 0x46
-#define IPMI_CMD_CLEAR_SEL 0x47
-#define IPMI_CMD_GET_SEL_TIME 0x48
-#define IPMI_CMD_SET_SEL_TIME 0x49
-
-
-/* Same as a timespec struct. */
-struct ipmi_time {
- long tv_sec;
- long tv_nsec;
-};
-
-#define MAX_SEL_SIZE 128
-
-typedef struct IPMISel {
- uint8_t sel[MAX_SEL_SIZE][16];
- unsigned int next_free;
- long time_offset;
- uint16_t reservation;
- uint8_t last_addition[4];
- uint8_t last_clear[4];
- uint8_t overflow;
-} IPMISel;
-
-#define MAX_SDR_SIZE 16384
-
-typedef struct IPMISdr {
- uint8_t sdr[MAX_SDR_SIZE];
- unsigned int next_free;
- uint16_t next_rec_id;
- uint16_t reservation;
- uint8_t last_addition[4];
- uint8_t last_clear[4];
- uint8_t overflow;
-} IPMISdr;
-
-typedef struct IPMISensor {
- uint8_t status;
- uint8_t reading;
- uint16_t states_suppt;
- uint16_t assert_suppt;
- uint16_t deassert_suppt;
- uint16_t states;
- uint16_t assert_states;
- uint16_t deassert_states;
- uint16_t assert_enable;
- uint16_t deassert_enable;
- uint8_t sensor_type;
- uint8_t evt_reading_type_code;
-} IPMISensor;
-#define IPMI_SENSOR_GET_PRESENT(s) ((s)->status & 0x01)
-#define IPMI_SENSOR_SET_PRESENT(s, v) ((s)->status = (s->status & ~0x01) | \
- !!(v))
-#define IPMI_SENSOR_GET_SCAN_ON(s) ((s)->status & 0x40)
-#define IPMI_SENSOR_SET_SCAN_ON(s, v) ((s)->status = (s->status & ~0x40) | \
- ((!!(v)) << 6))
-#define IPMI_SENSOR_GET_EVENTS_ON(s) ((s)->status & 0x80)
-#define IPMI_SENSOR_SET_EVENTS_ON(s, v) ((s)->status = (s->status & ~0x80) | \
- ((!!(v)) << 7))
-#define IPMI_SENSOR_GET_RET_STATUS(s) ((s)->status & 0xc0)
-#define IPMI_SENSOR_SET_RET_STATUS(s, v) ((s)->status = (s->status & ~0xc0) | \
- (v & 0xc0))
-#define IPMI_SENSOR_IS_DISCRETE(s) ((s)->evt_reading_type_code != 1)
-
-#define MAX_SENSORS 20
-#define IPMI_WATCHDOG_SENSOR 0
-
-typedef struct IPMIBmcSim IPMIBmcSim;
-typedef struct RspBuffer RspBuffer;
-
-#define MAX_NETFNS 64
-
-typedef struct IPMICmdHandler {
- void (*cmd_handler)(IPMIBmcSim *s,
- uint8_t *cmd, unsigned int cmd_len,
- RspBuffer *rsp);
- unsigned int cmd_len_min;
-} IPMICmdHandler;
-
-typedef struct IPMINetfn {
- unsigned int cmd_nums;
- const IPMICmdHandler *cmd_handlers;
-} IPMINetfn;
-
-typedef struct IPMIRcvBufEntry {
- QTAILQ_ENTRY(IPMIRcvBufEntry) entry;
- uint8_t len;
- uint8_t buf[MAX_IPMI_MSG_SIZE];
-} IPMIRcvBufEntry;
-
-#define TYPE_IPMI_BMC_SIMULATOR "ipmi-bmc-sim"
-#define IPMI_BMC_SIMULATOR(obj) OBJECT_CHECK(IPMIBmcSim, (obj), \
- TYPE_IPMI_BMC_SIMULATOR)
-struct IPMIBmcSim {
- IPMIBmc parent;
-
- QEMUTimer *timer;
-
- uint8_t bmc_global_enables;
- uint8_t msg_flags;
-
- bool watchdog_initialized;
- uint8_t watchdog_use;
- uint8_t watchdog_action;
- uint8_t watchdog_pretimeout; /* In seconds */
- bool watchdog_expired;
- uint16_t watchdog_timeout; /* in 100's of milliseconds */
-
- bool watchdog_running;
- bool watchdog_preaction_ran;
- int64_t watchdog_expiry;
-
- uint8_t device_id;
- uint8_t ipmi_version;
- uint8_t device_rev;
- uint8_t fwrev1;
- uint8_t fwrev2;
- uint8_t mfg_id[3];
- uint8_t product_id[2];
-
- uint8_t restart_cause;
-
- uint8_t acpi_power_state[2];
- uint8_t uuid[16];
-
- IPMISel sel;
- IPMISdr sdr;
- IPMISensor sensors[MAX_SENSORS];
-
- /* Odd netfns are for responses, so we only need the even ones. */
- const IPMINetfn *netfns[MAX_NETFNS / 2];
-
- QemuMutex lock;
- /* We allow one event in the buffer */
- uint8_t evtbuf[16];
-
- QTAILQ_HEAD(, IPMIRcvBufEntry) rcvbufs;
-};
-
-#define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK (1 << 3)
-#define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL (1 << 1)
-#define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE (1 << 0)
-#define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(s) \
- (IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK & (s)->msg_flags)
-#define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(s) \
- (IPMI_BMC_MSG_FLAG_EVT_BUF_FULL & (s)->msg_flags)
-#define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(s) \
- (IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE & (s)->msg_flags)
-
-#define IPMI_BMC_RCV_MSG_QUEUE_INT_BIT 0
-#define IPMI_BMC_EVBUF_FULL_INT_BIT 1
-#define IPMI_BMC_EVENT_MSG_BUF_BIT 2
-#define IPMI_BMC_EVENT_LOG_BIT 3
-#define IPMI_BMC_MSG_INTS_ON(s) ((s)->bmc_global_enables & \
- (1 << IPMI_BMC_RCV_MSG_QUEUE_INT_BIT))
-#define IPMI_BMC_EVBUF_FULL_INT_ENABLED(s) ((s)->bmc_global_enables & \
- (1 << IPMI_BMC_EVBUF_FULL_INT_BIT))
-#define IPMI_BMC_EVENT_LOG_ENABLED(s) ((s)->bmc_global_enables & \
- (1 << IPMI_BMC_EVENT_LOG_BIT))
-#define IPMI_BMC_EVENT_MSG_BUF_ENABLED(s) ((s)->bmc_global_enables & \
- (1 << IPMI_BMC_EVENT_MSG_BUF_BIT))
-
-#define IPMI_BMC_WATCHDOG_USE_MASK 0xc7
-#define IPMI_BMC_WATCHDOG_ACTION_MASK 0x77
-#define IPMI_BMC_WATCHDOG_GET_USE(s) ((s)->watchdog_use & 0x7)
-#define IPMI_BMC_WATCHDOG_GET_DONT_LOG(s) (((s)->watchdog_use >> 7) & 0x1)
-#define IPMI_BMC_WATCHDOG_GET_DONT_STOP(s) (((s)->watchdog_use >> 6) & 0x1)
-#define IPMI_BMC_WATCHDOG_GET_PRE_ACTION(s) (((s)->watchdog_action >> 4) & 0x7)
-#define IPMI_BMC_WATCHDOG_PRE_NONE 0
-#define IPMI_BMC_WATCHDOG_PRE_SMI 1
-#define IPMI_BMC_WATCHDOG_PRE_NMI 2
-#define IPMI_BMC_WATCHDOG_PRE_MSG_INT 3
-#define IPMI_BMC_WATCHDOG_GET_ACTION(s) ((s)->watchdog_action & 0x7)
-#define IPMI_BMC_WATCHDOG_ACTION_NONE 0
-#define IPMI_BMC_WATCHDOG_ACTION_RESET 1
-#define IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN 2
-#define IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE 3
-
-struct RspBuffer {
- uint8_t buffer[MAX_IPMI_MSG_SIZE];
- unsigned int len;
-};
-
-#define RSP_BUFFER_INITIALIZER { }
-
-static inline void rsp_buffer_set_error(RspBuffer *rsp, uint8_t byte)
-{
- rsp->buffer[2] = byte;
-}
-
-/* Add a byte to the response. */
-static inline void rsp_buffer_push(RspBuffer *rsp, uint8_t byte)
-{
- if (rsp->len >= sizeof(rsp->buffer)) {
- rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
- return;
- }
- rsp->buffer[rsp->len++] = byte;
-}
-
-static inline void rsp_buffer_pushmore(RspBuffer *rsp, uint8_t *bytes,
- unsigned int n)
-{
- if (rsp->len + n >= sizeof(rsp->buffer)) {
- rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
- return;
- }
-
- memcpy(&rsp->buffer[rsp->len], bytes, n);
- rsp->len += n;
-}
-
-static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs);
-
-static void ipmi_gettime(struct ipmi_time *time)
-{
- int64_t stime;
-
- stime = qemu_clock_get_ns(QEMU_CLOCK_HOST);
- time->tv_sec = stime / 1000000000LL;
- time->tv_nsec = stime % 1000000000LL;
-}
-
-static int64_t ipmi_getmonotime(void)
-{
- return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-}
-
-static void ipmi_timeout(void *opaque)
-{
- IPMIBmcSim *ibs = opaque;
-
- ipmi_sim_handle_timeout(ibs);
-}
-
-static void set_timestamp(IPMIBmcSim *ibs, uint8_t *ts)
-{
- unsigned int val;
- struct ipmi_time now;
-
- ipmi_gettime(&now);
- val = now.tv_sec + ibs->sel.time_offset;
- ts[0] = val & 0xff;
- ts[1] = (val >> 8) & 0xff;
- ts[2] = (val >> 16) & 0xff;
- ts[3] = (val >> 24) & 0xff;
-}
-
-static void sdr_inc_reservation(IPMISdr *sdr)
-{
- sdr->reservation++;
- if (sdr->reservation == 0) {
- sdr->reservation = 1;
- }
-}
-
-static int sdr_add_entry(IPMIBmcSim *ibs,
- const struct ipmi_sdr_header *sdrh_entry,
- unsigned int len, uint16_t *recid)
-{
- struct ipmi_sdr_header *sdrh =
- (struct ipmi_sdr_header *) &ibs->sdr.sdr[ibs->sdr.next_free];
-
- if ((len < IPMI_SDR_HEADER_SIZE) || (len > 255)) {
- return 1;
- }
-
- if (ipmi_sdr_length(sdrh_entry) != len) {
- return 1;
- }
-
- if (ibs->sdr.next_free + len > MAX_SDR_SIZE) {
- ibs->sdr.overflow = 1;
- return 1;
- }
-
- memcpy(sdrh, sdrh_entry, len);
- sdrh->rec_id[0] = ibs->sdr.next_rec_id & 0xff;
- sdrh->rec_id[1] = (ibs->sdr.next_rec_id >> 8) & 0xff;
- sdrh->sdr_version = 0x51; /* Conform to IPMI 1.5 spec */
-
- if (recid) {
- *recid = ibs->sdr.next_rec_id;
- }
- ibs->sdr.next_rec_id++;
- set_timestamp(ibs, ibs->sdr.last_addition);
- ibs->sdr.next_free += len;
- sdr_inc_reservation(&ibs->sdr);
- return 0;
-}
-
-static int sdr_find_entry(IPMISdr *sdr, uint16_t recid,
- unsigned int *retpos, uint16_t *nextrec)
-{
- unsigned int pos = *retpos;
-
- while (pos < sdr->next_free) {
- struct ipmi_sdr_header *sdrh =
- (struct ipmi_sdr_header *) &sdr->sdr[pos];
- uint16_t trec = ipmi_sdr_recid(sdrh);
- unsigned int nextpos = pos + ipmi_sdr_length(sdrh);
-
- if (trec == recid) {
- if (nextrec) {
- if (nextpos >= sdr->next_free) {
- *nextrec = 0xffff;
- } else {
- *nextrec = (sdr->sdr[nextpos] |
- (sdr->sdr[nextpos + 1] << 8));
- }
- }
- *retpos = pos;
- return 0;
- }
- pos = nextpos;
- }
- return 1;
-}
-
-static void sel_inc_reservation(IPMISel *sel)
-{
- sel->reservation++;
- if (sel->reservation == 0) {
- sel->reservation = 1;
- }
-}
-
-/* Returns 1 if the SEL is full and can't hold the event. */
-static int sel_add_event(IPMIBmcSim *ibs, uint8_t *event)
-{
- event[0] = 0xff;
- event[1] = 0xff;
- set_timestamp(ibs, event + 3);
- if (ibs->sel.next_free == MAX_SEL_SIZE) {
- ibs->sel.overflow = 1;
- return 1;
- }
- event[0] = ibs->sel.next_free & 0xff;
- event[1] = (ibs->sel.next_free >> 8) & 0xff;
- memcpy(ibs->sel.last_addition, event + 3, 4);
- memcpy(ibs->sel.sel[ibs->sel.next_free], event, 16);
- ibs->sel.next_free++;
- sel_inc_reservation(&ibs->sel);
- return 0;
-}
-
-static int attn_set(IPMIBmcSim *ibs)
-{
- return IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs)
- || IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs)
- || IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs);
-}
-
-static int attn_irq_enabled(IPMIBmcSim *ibs)
-{
- return (IPMI_BMC_MSG_INTS_ON(ibs) && IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs))
- || (IPMI_BMC_EVBUF_FULL_INT_ENABLED(ibs) &&
- IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs));
-}
-
-static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert,
- uint8_t evd1, uint8_t evd2, uint8_t evd3)
-{
- IPMIInterface *s = ibs->parent.intf;
- IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
- uint8_t evt[16];
- IPMISensor *sens = ibs->sensors + sens_num;
-
- if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) {
- return;
- }
- if (!IPMI_SENSOR_GET_EVENTS_ON(sens)) {
- return;
- }
-
- evt[2] = 0x2; /* System event record */
- evt[7] = ibs->parent.slave_addr;
- evt[8] = 0;
- evt[9] = 0x04; /* Format version */
- evt[10] = sens->sensor_type;
- evt[11] = sens_num;
- evt[12] = sens->evt_reading_type_code | (!!deassert << 7);
- evt[13] = evd1;
- evt[14] = evd2;
- evt[15] = evd3;
-
- if (IPMI_BMC_EVENT_LOG_ENABLED(ibs)) {
- sel_add_event(ibs, evt);
- }
-
- if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) {
- return;
- }
-
- memcpy(ibs->evtbuf, evt, 16);
- ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
- k->set_atn(s, 1, attn_irq_enabled(ibs));
-}
-
-static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor,
- unsigned int bit, unsigned int val,
- uint8_t evd1, uint8_t evd2, uint8_t evd3)
-{
- IPMISensor *sens;
- uint16_t mask;
-
- if (sensor >= MAX_SENSORS) {
- return;
- }
- if (bit >= 16) {
- return;
- }
-
- mask = (1 << bit);
- sens = ibs->sensors + sensor;
- if (val) {
- sens->states |= mask & sens->states_suppt;
- if (sens->assert_states & mask) {
- return; /* Already asserted */
- }
- sens->assert_states |= mask & sens->assert_suppt;
- if (sens->assert_enable & mask & sens->assert_states) {
- /* Send an event on assert */
- gen_event(ibs, sensor, 0, evd1, evd2, evd3);
- }
- } else {
- sens->states &= ~(mask & sens->states_suppt);
- if (sens->deassert_states & mask) {
- return; /* Already deasserted */
- }
- sens->deassert_states |= mask & sens->deassert_suppt;
- if (sens->deassert_enable & mask & sens->deassert_states) {
- /* Send an event on deassert */
- gen_event(ibs, sensor, 1, evd1, evd2, evd3);
- }
- }
-}
-
-static void ipmi_init_sensors_from_sdrs(IPMIBmcSim *s)
-{
- unsigned int i, pos;
- IPMISensor *sens;
-
- for (i = 0; i < MAX_SENSORS; i++) {
- memset(s->sensors + i, 0, sizeof(*sens));
- }
-
- pos = 0;
- for (i = 0; !sdr_find_entry(&s->sdr, i, &pos, NULL); i++) {
- struct ipmi_sdr_compact *sdr =
- (struct ipmi_sdr_compact *) &s->sdr.sdr[pos];
- unsigned int len = sdr->header.rec_length;
-
- if (len < 20) {
- continue;
- }
- if (sdr->header.rec_type != IPMI_SDR_COMPACT_TYPE) {
- continue; /* Not a sensor SDR we set from */
- }
-
- if (sdr->sensor_owner_number >= MAX_SENSORS) {
- continue;
- }
- sens = s->sensors + sdr->sensor_owner_number;
-
- IPMI_SENSOR_SET_PRESENT(sens, 1);
- IPMI_SENSOR_SET_SCAN_ON(sens, (sdr->sensor_init >> 6) & 1);
- IPMI_SENSOR_SET_EVENTS_ON(sens, (sdr->sensor_init >> 5) & 1);
- sens->assert_suppt = sdr->assert_mask[0] | (sdr->assert_mask[1] << 8);
- sens->deassert_suppt =
- sdr->deassert_mask[0] | (sdr->deassert_mask[1] << 8);
- sens->states_suppt =
- sdr->discrete_mask[0] | (sdr->discrete_mask[1] << 8);
- sens->sensor_type = sdr->sensor_type;
- sens->evt_reading_type_code = sdr->reading_type & 0x7f;
-
- /* Enable all the events that are supported. */
- sens->assert_enable = sens->assert_suppt;
- sens->deassert_enable = sens->deassert_suppt;
- }
-}
-
-static int ipmi_register_netfn(IPMIBmcSim *s, unsigned int netfn,
- const IPMINetfn *netfnd)
-{
- if ((netfn & 1) || (netfn >= MAX_NETFNS) || (s->netfns[netfn / 2])) {
- return -1;
- }
- s->netfns[netfn / 2] = netfnd;
- return 0;
-}
-
-static const IPMICmdHandler *ipmi_get_handler(IPMIBmcSim *ibs,
- unsigned int netfn,
- unsigned int cmd)
-{
- const IPMICmdHandler *hdl;
-
- if (netfn & 1 || netfn >= MAX_NETFNS || !ibs->netfns[netfn / 2]) {
- return NULL;
- }
-
- if (cmd >= ibs->netfns[netfn / 2]->cmd_nums) {
- return NULL;
- }
-
- hdl = &ibs->netfns[netfn / 2]->cmd_handlers[cmd];
- if (!hdl->cmd_handler) {
- return NULL;
- }
-
- return hdl;
-}
-
-static void next_timeout(IPMIBmcSim *ibs)
-{
- int64_t next;
- if (ibs->watchdog_running) {
- next = ibs->watchdog_expiry;
- } else {
- /* Wait a minute */
- next = ipmi_getmonotime() + 60 * 1000000000LL;
- }
- timer_mod_ns(ibs->timer, next);
-}
-
-static void ipmi_sim_handle_command(IPMIBmc *b,
- uint8_t *cmd, unsigned int cmd_len,
- unsigned int max_cmd_len,
- uint8_t msg_id)
-{
- IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
- IPMIInterface *s = ibs->parent.intf;
- IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
- const IPMICmdHandler *hdl;
- RspBuffer rsp = RSP_BUFFER_INITIALIZER;
-
- /* Set up the response, set the low bit of NETFN. */
- /* Note that max_rsp_len must be at least 3 */
- if (sizeof(rsp.buffer) < 3) {
- rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
- goto out;
- }
-
- rsp_buffer_push(&rsp, cmd[0] | 0x04);
- rsp_buffer_push(&rsp, cmd[1]);
- rsp_buffer_push(&rsp, 0); /* Assume success */
-
- /* If it's too short or it was truncated, return an error. */
- if (cmd_len < 2) {
- rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
- goto out;
- }
- if (cmd_len > max_cmd_len) {
- rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
- goto out;
- }
-
- if ((cmd[0] & 0x03) != 0) {
- /* Only have stuff on LUN 0 */
- rsp_buffer_set_error(&rsp, IPMI_CC_COMMAND_INVALID_FOR_LUN);
- goto out;
- }
-
- hdl = ipmi_get_handler(ibs, cmd[0] >> 2, cmd[1]);
- if (!hdl) {
- rsp_buffer_set_error(&rsp, IPMI_CC_INVALID_CMD);
- goto out;
- }
-
- if (cmd_len < hdl->cmd_len_min) {
- rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
- goto out;
- }
-
- hdl->cmd_handler(ibs, cmd, cmd_len, &rsp);
-
- out:
- k->handle_rsp(s, msg_id, rsp.buffer, rsp.len);
-
- next_timeout(ibs);
-}
-
-static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs)
-{
- IPMIInterface *s = ibs->parent.intf;
- IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
-
- if (!ibs->watchdog_running) {
- goto out;
- }
-
- if (!ibs->watchdog_preaction_ran) {
- switch (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs)) {
- case IPMI_BMC_WATCHDOG_PRE_NMI:
- ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
- k->do_hw_op(s, IPMI_SEND_NMI, 0);
- sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
- 0xc8, (2 << 4) | 0xf, 0xff);
- break;
-
- case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
- ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
- k->set_atn(s, 1, attn_irq_enabled(ibs));
- sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
- 0xc8, (3 << 4) | 0xf, 0xff);
- break;
-
- default:
- goto do_full_expiry;
- }
-
- ibs->watchdog_preaction_ran = 1;
- /* Issued the pretimeout, do the rest of the timeout now. */
- ibs->watchdog_expiry = ipmi_getmonotime();
- ibs->watchdog_expiry += ibs->watchdog_pretimeout * 1000000000LL;
- goto out;
- }
-
- do_full_expiry:
- ibs->watchdog_running = 0; /* Stop the watchdog on a timeout */
- ibs->watchdog_expired |= (1 << IPMI_BMC_WATCHDOG_GET_USE(ibs));
- switch (IPMI_BMC_WATCHDOG_GET_ACTION(ibs)) {
- case IPMI_BMC_WATCHDOG_ACTION_NONE:
- sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 0, 1,
- 0xc0, ibs->watchdog_use & 0xf, 0xff);
- break;
-
- case IPMI_BMC_WATCHDOG_ACTION_RESET:
- sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 1, 1,
- 0xc1, ibs->watchdog_use & 0xf, 0xff);
- k->do_hw_op(s, IPMI_RESET_CHASSIS, 0);
- break;
-
- case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
- sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
- 0xc2, ibs->watchdog_use & 0xf, 0xff);
- k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0);
- break;
-
- case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
- sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
- 0xc3, ibs->watchdog_use & 0xf, 0xff);
- k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0);
- break;
- }
-
- out:
- next_timeout(ibs);
-}
-
-static void chassis_capabilities(IPMIBmcSim *ibs,
- uint8_t *cmd, unsigned int cmd_len,
- RspBuffer *rsp)
-{
- rsp_buffer_push(rsp, 0);
- rsp_buffer_push(rsp, ibs->parent.slave_addr);
- rsp_buffer_push(rsp, ibs->parent.slave_addr);
- rsp_buffer_push(rsp, ibs->parent.slave_addr);
- rsp_buffer_push(rsp, ibs->parent.slave_addr);
-}
-
-static void chassis_status(IPMIBmcSim *ibs,
- uint8_t *cmd, unsigned int cmd_len,
- RspBuffer *rsp)
-{
- rsp_buffer_push(rsp, 0x61); /* Unknown power restore, power is on */
- rsp_buffer_push(rsp, 0);
- rsp_buffer_push(rsp, 0);
- rsp_buffer_push(rsp, 0);
-}
-
-static void chassis_control(IPMIBmcSim *ibs,
- uint8_t *cmd, unsigned int cmd_len,
- RspBuffer *rsp)
-{
- IPMIInterface *s = ibs->parent.intf;
- IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
-
- switch (cmd[2] & 0xf) {
- case 0: /* power down */
- rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0));
- break;
- case 1: /* power up */
- rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERON_CHASSIS, 0));
- break;
- case 2: /* power cycle */
- rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0));
- break;
- case 3: /* hard reset */
- rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 0));
- break;
- case 4: /* pulse diagnostic interrupt */
- rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_PULSE_DIAG_IRQ, 0));
- break;
- case 5: /* soft shutdown via ACPI by overtemp emulation */
- rsp_buffer_set_error(rsp, k->do_hw_op(s,
- IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP, 0));
- break;
- default:
- rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
- return;
- }
-}
-
-static void chassis_get_sys_restart_cause(IPMIBmcSim *ibs,
- uint8_t *cmd, unsigned int cmd_len,
- RspBuffer *rsp)
-
-{
- rsp_buffer_push(rsp, ibs->restart_cause & 0xf); /* Restart Cause */
- rsp_buffer_push(rsp, 0); /* Channel 0 */
-}
-
-static void get_device_id(IPMIBmcSim *ibs,
- uint8_t *cmd, unsigned int cmd_len,
- RspBuffer *rsp)
-{
- rsp_buffer_push(rsp, ibs->device_id);
- rsp_buffer_push(rsp, ibs->device_rev & 0xf);
- rsp_buffer_push(rsp, ibs->fwrev1 & 0x7f);
- rsp_buffer_push(rsp, ibs->fwrev2);
- rsp_buffer_push(rsp, ibs->ipmi_version);
- rsp_buffer_push(rsp, 0x07); /* sensor, SDR, and SEL. */
- rsp_buffer_push(rsp, ibs->mfg_id[0]);
- rsp_buffer_push(rsp, ibs->mfg_id[1]);
- rsp_buffer_push(rsp, ibs->mfg_id[2]);
- rsp_buffer_push(rsp, ibs->product_id[0]);
- rsp_buffer_push(rsp, ibs->product_id[1]);
-}
-
-static void set_global_enables(IPMIBmcSim *ibs, uint8_t val)
-{
- IPMIInterface *s = ibs->parent.intf;
- IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
- bool irqs_on;
-
- ibs->bmc_global_enables = val;
-
- irqs_on = val & (IPMI_BMC_EVBUF_FULL_INT_BIT |
- IPMI_BMC_RCV_MSG_QUEUE_INT_BIT);
-
- k->set_irq_enable(s, irqs_on);
-}
-
-static void cold_reset(IPMIBmcSim *ibs,
- uint8_t *cmd, unsigned int cmd_len,
- RspBuffer *rsp)
-{
- IPMIInterface *s = ibs->parent.intf;
- IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
-
- /* Disable all interrupts */
- set_global_enables(ibs, 1 << IPMI_BMC_EVENT_LOG_BIT);
-
- if (k->reset) {
- k->reset(s, true);
- }
-}
-
-static void warm_reset(IPMIBmcSim *ibs,
- uint8_t *cmd, unsigned int cmd_len,
- RspBuffer *rsp)
-{
- IPMIInterface *s = ibs->parent.intf;
- IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
-
- if (k->reset) {
- k->reset(s, false);
- }
-}
-static void set_acpi_power_state(IPMIBmcSim *ibs,
- uint8_t *cmd, unsigned int cmd_len,
- RspBuffer *rsp)
-{
- ibs->acpi_power_state[0] = cmd[2];
- ibs->acpi_power_state[1] = cmd[3];
-}
-
-static void get_acpi_power_state(IPMIBmcSim *ibs,
- uint8_t *cmd, unsigned int cmd_len,
- RspBuffer *rsp)
-{
- rsp_buffer_push(rsp, ibs->acpi_power_state[0]);
- rsp_buffer_push(rsp, ibs->acpi_power_state[1]);
-}
-
-static void get_device_guid(IPMIBmcSim *ibs,
- uint8_t *cmd, unsigned int cmd_len,
- RspBuffer *rsp)
-{
- unsigned int i;
-
- for (i = 0; i < 16; i++) {
- rsp_buffer_push(rsp, ibs->uuid[i]);
- }
-}
-
-static void set_bmc_global_enables(IPMIBmcSim *ibs,
- uint8_t *cmd, unsigned int cmd_len,
- RspBuffer *rsp)
-{
- set_global_enables(ibs, cmd[2]);
-}
-
-static void get_bmc_global_enables(IPMIBmcSim *ibs,
- uint8_t *cmd, unsigned int cmd_len,
- RspBuffer *rsp)
-{
- rsp_buffer_push(rsp, ibs->bmc_global_enables);
-}
-
-static void clr_msg_flags(IPMIBmcSim *ibs,
- uint8_t *cmd, unsigned int cmd_len,
- RspBuffer *rsp)
-{
- IPMIInterface *s = ibs->parent.intf;
- IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
-
- ibs->msg_flags &= ~cmd[2];
- k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
-}
-
-static void get_msg_flags(IPMIBmcSim *ibs,
- uint8_t *cmd, unsigned int cmd_len,
- RspBuffer *rsp)
-{
- rsp_buffer_push(rsp, ibs->msg_flags);
-}
-
-static void read_evt_msg_buf(IPMIBmcSim *ibs,
- uint8_t *cmd, unsigned int cmd_len,
- RspBuffer *rsp)
-{
- IPMIInterface *s = ibs->parent.intf;
- IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
- unsigned int i;
-
- if (!(ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL)) {
- rsp_buffer_set_error(rsp, 0x80);
- return;
- }
- for (i = 0; i < 16; i++) {
- rsp_buffer_push(rsp, ibs->evtbuf[i]);
- }
- ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
- k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
-}
-
-static void get_msg(IPMIBmcSim *ibs,
- uint8_t *cmd, unsigned int cmd_len,
- RspBuffer *rsp)
-{
- IPMIRcvBufEntry *msg;
-
- qemu_mutex_lock(&ibs->lock);
- if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
- rsp_buffer_set_error(rsp, 0x80); /* Queue empty */
- goto out;
- }
- rsp_buffer_push(rsp, 0); /* Channel 0 */
- msg = QTAILQ_FIRST(&ibs->rcvbufs);
- rsp_buffer_pushmore(rsp, msg->buf, msg->len);
- QTAILQ_REMOVE(&ibs->rcvbufs, msg, entry);
- g_free(msg);
-
- if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
- IPMIInterface *s = ibs->parent.intf;
- IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
-
- ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
- k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
- }
-
-out:
- qemu_mutex_unlock(&ibs->lock);
- return;
-}
-
-static unsigned char
-ipmb_checksum(unsigned char *data, int size, unsigned char csum)
-{
- for (; size > 0; size--, data++) {
- csum += *data;
- }
-
- return -csum;
-}
-
-static void send_msg(IPMIBmcSim *ibs,
- uint8_t *cmd, unsigned int cmd_len,
- RspBuffer *rsp)
-{
- IPMIInterface *s = ibs->parent.intf;
- IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
- IPMIRcvBufEntry *msg;
- uint8_t *buf;
- uint8_t netfn, rqLun, rsLun, rqSeq;
-
- if (cmd[2] != 0) {
- /* We only handle channel 0 with no options */
- rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
- return;
- }
-
- if (cmd_len < 10) {
- rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
- return;
- }
-
- if (cmd[3] != 0x40) {
- /* We only emulate a MC at address 0x40. */
- rsp_buffer_set_error(rsp, 0x83); /* NAK on write */
- return;
- }
-
- cmd += 3; /* Skip the header. */
- cmd_len -= 3;
-
- /*
- * At this point we "send" the message successfully. Any error will
- * be returned in the response.
- */
- if (ipmb_checksum(cmd, cmd_len, 0) != 0 ||
- cmd[3] != 0x20) { /* Improper response address */
- return; /* No response */
- }
-
- netfn = cmd[1] >> 2;
- rqLun = cmd[4] & 0x3;
- rsLun = cmd[1] & 0x3;
- rqSeq = cmd[4] >> 2;
-
- if (rqLun != 2) {
- /* We only support LUN 2 coming back to us. */
- return;
- }
-
- msg = g_malloc(sizeof(*msg));
- msg->buf[0] = ((netfn | 1) << 2) | rqLun; /* NetFN, and make a response */
- msg->buf[1] = ipmb_checksum(msg->buf, 1, 0);
- msg->buf[2] = cmd[0]; /* rsSA */
- msg->buf[3] = (rqSeq << 2) | rsLun;
- msg->buf[4] = cmd[5]; /* Cmd */
- msg->buf[5] = 0; /* Completion Code */
- msg->len = 6;
-
- if ((cmd[1] >> 2) != IPMI_NETFN_APP || cmd[5] != IPMI_CMD_GET_DEVICE_ID) {
- /* Not a command we handle. */
- msg->buf[5] = IPMI_CC_INVALID_CMD;
- goto end_msg;
- }
-
- buf = msg->buf + msg->len; /* After the CC */
- buf[0] = 0;
- buf[1] = 0;
- buf[2] = 0;
- buf[3] = 0;
- buf[4] = 0x51;
- buf[5] = 0;
- buf[6] = 0;
- buf[7] = 0;
- buf[8] = 0;
- buf[9] = 0;
- buf[10] = 0;
- msg->len += 11;
-
- end_msg:
- msg->buf[msg->len] = ipmb_checksum(msg->buf, msg->len, 0);
- msg->len++;
- qemu_mutex_lock(&ibs->lock);
- QTAILQ_INSERT_TAIL(&ibs->rcvbufs, msg, entry);
- ibs->msg_flags |= IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
- k->set_atn(s, 1, attn_irq_enabled(ibs));
- qemu_mutex_unlock(&ibs->lock);
-}
-
-static void do_watchdog_reset(IPMIBmcSim *ibs)
-{
- if (IPMI_BMC_WATCHDOG_GET_ACTION(ibs) ==
- IPMI_BMC_WATCHDOG_ACTION_NONE) {
- ibs->watchdog_running = 0;
- return;
- }
- ibs->watchdog_preaction_ran = 0;
-
-
- /* Timeout is in tenths of a second, offset is in seconds */
- ibs->watchdog_expiry = ipmi_getmonotime();
- ibs->watchdog_expiry += ibs->watchdog_timeout * 100000000LL;
- if (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs) != IPMI_BMC_WATCHDOG_PRE_NONE) {
- ibs->watchdog_expiry -= ibs->watchdog_pretimeout * 1000000000LL;
- }
- ibs->watchdog_running = 1;
-}
-
-static void reset_watchdog_timer(IPMIBmcSim *ibs,
- uint8_t *cmd, unsigned int cmd_len,
- RspBuffer *rsp)
-{
- if (!ibs->watchdog_initialized) {
- rsp_buffer_set_error(rsp, 0x80);
- return;
- }
- do_watchdog_reset(ibs);
-}
-
-static void set_watchdog_timer(IPMIBmcSim *ibs,
- uint8_t *cmd, unsigned int cmd_len,
- RspBuffer *rsp)
-{
- IPMIInterface *s = ibs->parent.intf;
- IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
- unsigned int val;
-
- val = cmd[2] & 0x7; /* Validate use */
- if (val == 0 || val > 5) {
- rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
- return;
- }
- val = cmd[3] & 0x7; /* Validate action */
- switch (val) {
- case IPMI_BMC_WATCHDOG_ACTION_NONE:
- break;
-
- case IPMI_BMC_WATCHDOG_ACTION_RESET:
- rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 1));
- break;
-
- case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
- rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 1));
- break;
-
- case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
- rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 1));
- break;
-
- default:
- rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
- }
- if (rsp->buffer[2]) {
- rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
- return;
- }
-
- val = (cmd[3] >> 4) & 0x7; /* Validate preaction */
- switch (val) {
- case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
- case IPMI_BMC_WATCHDOG_PRE_NONE:
- break;
-
- case IPMI_BMC_WATCHDOG_PRE_NMI:
- if (!k->do_hw_op(s, IPMI_SEND_NMI, 1)) {
- /* NMI not supported. */
- rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
- return;
- }
- break;
-
- default:
- /* We don't support PRE_SMI */
- rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
- return;
- }
-
- ibs->watchdog_initialized = 1;
- ibs->watchdog_use = cmd[2] & IPMI_BMC_WATCHDOG_USE_MASK;
- ibs->watchdog_action = cmd[3] & IPMI_BMC_WATCHDOG_ACTION_MASK;
- ibs->watchdog_pretimeout = cmd[4];
- ibs->watchdog_expired &= ~cmd[5];
- ibs->watchdog_timeout = cmd[6] | (((uint16_t) cmd[7]) << 8);
- if (ibs->watchdog_running & IPMI_BMC_WATCHDOG_GET_DONT_STOP(ibs)) {
- do_watchdog_reset(ibs);
- } else {
- ibs->watchdog_running = 0;
- }
-}
-
-static void get_watchdog_timer(IPMIBmcSim *ibs,
- uint8_t *cmd, unsigned int cmd_len,
- RspBuffer *rsp)
-{
- rsp_buffer_push(rsp, ibs->watchdog_use);
- rsp_buffer_push(rsp, ibs->watchdog_action);
- rsp_buffer_push(rsp, ibs->watchdog_pretimeout);
- rsp_buffer_push(rsp, ibs->watchdog_expired);
- if (ibs->watchdog_running) {
- long timeout;
- timeout = ((ibs->watchdog_expiry - ipmi_getmonotime() + 50000000)
- / 100000000);
- rsp_buffer_push(rsp, timeout & 0xff);
- rsp_buffer_push(rsp, (timeout >> 8) & 0xff);
- } else {
- rsp_buffer_push(rsp, 0);
- rsp_buffer_push(rsp, 0);
- }
-}
-
-static void get_sdr_rep_info(IPMIBmcSim *ibs,
- uint8_t *cmd, unsigned int cmd_len,
- RspBuffer *rsp)
-{
- unsigned int i;
-
- rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 spec */
- rsp_buffer_push(rsp, ibs->sdr.next_rec_id & 0xff);
- rsp_buffer_push(rsp, (ibs->sdr.next_rec_id >> 8) & 0xff);
- rsp_buffer_push(rsp, (MAX_SDR_SIZE - ibs->sdr.next_free) & 0xff);
- rsp_buffer_push(rsp, ((MAX_SDR_SIZE - ibs->sdr.next_free) >> 8) & 0xff);
- for (i = 0; i < 4; i++) {
- rsp_buffer_push(rsp, ibs->sdr.last_addition[i]);
- }
- for (i = 0; i < 4; i++) {
- rsp_buffer_push(rsp, ibs->sdr.last_clear[i]);
- }
- /* Only modal support, reserve supported */
- rsp_buffer_push(rsp, (ibs->sdr.overflow << 7) | 0x22);
-}
-
-static void reserve_sdr_rep(IPMIBmcSim *ibs,
- uint8_t *cmd, unsigned int cmd_len,
- RspBuffer *rsp)
-{
- rsp_buffer_push(rsp, ibs->sdr.reservation & 0xff);
- rsp_buffer_push(rsp, (ibs->sdr.reservation >> 8) & 0xff);
-}
-
-static void get_sdr(IPMIBmcSim *ibs,
- uint8_t *cmd, unsigned int cmd_len,
- RspBuffer *rsp)
-{
- unsigned int pos;
- uint16_t nextrec;
- struct ipmi_sdr_header *sdrh;
-
- if (cmd[6]) {
- if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) {
- rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
- return;
- }
- }
-
- pos = 0;
- if (sdr_find_entry(&ibs->sdr, cmd[4] | (cmd[5] << 8),
- &pos, &nextrec)) {
- rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
- return;
- }
-
- sdrh = (struct ipmi_sdr_header *) &ibs->sdr.sdr[pos];
-
- if (cmd[6] > ipmi_sdr_length(sdrh)) {
- rsp_buffer_set_error(rsp, IPMI_CC_PARM_OUT_OF_RANGE);
- return;
- }
-
- rsp_buffer_push(rsp, nextrec & 0xff);
- rsp_buffer_push(rsp, (nextrec >> 8) & 0xff);
-
- if (cmd[7] == 0xff) {
- cmd[7] = ipmi_sdr_length(sdrh) - cmd[6];
- }
-
- if ((cmd[7] + rsp->len) > sizeof(rsp->buffer)) {
- rsp_buffer_set_error(rsp, IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES);
- return;
- }
-
- rsp_buffer_pushmore(rsp, ibs->sdr.sdr + pos + cmd[6], cmd[7]);
-}
-
-static void add_sdr(IPMIBmcSim *ibs,
- uint8_t *cmd, unsigned int cmd_len,
- RspBuffer *rsp)
-{
- uint16_t recid;
- struct ipmi_sdr_header *sdrh = (struct ipmi_sdr_header *) cmd + 2;
-
- if (sdr_add_entry(ibs, sdrh, cmd_len - 2, &recid)) {
- rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
- return;
- }
- rsp_buffer_push(rsp, recid & 0xff);
- rsp_buffer_push(rsp, (recid >> 8) & 0xff);
-}
-
-static void clear_sdr_rep(IPMIBmcSim *ibs,
- uint8_t *cmd, unsigned int cmd_len,
- RspBuffer *rsp)
-{
- if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) {
- rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
- return;
- }
-
- if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
- rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
- return;
- }
- if (cmd[7] == 0xaa) {
- ibs->sdr.next_free = 0;
- ibs->sdr.overflow = 0;
- set_timestamp(ibs, ibs->sdr.last_clear);
- rsp_buffer_push(rsp, 1); /* Erasure complete */
- sdr_inc_reservation(&ibs->sdr);
- } else if (cmd[7] == 0) {
- rsp_buffer_push(rsp, 1); /* Erasure complete */
- } else {
- rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
- return;
- }
-}
-
-static void get_sel_info(IPMIBmcSim *ibs,
- uint8_t *cmd, unsigned int cmd_len,
- RspBuffer *rsp)
-{
- unsigned int i, val;
-
- rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 */
- rsp_buffer_push(rsp, ibs->sel.next_free & 0xff);
- rsp_buffer_push(rsp, (ibs->sel.next_free >> 8) & 0xff);
- val = (MAX_SEL_SIZE - ibs->sel.next_free) * 16;
- rsp_buffer_push(rsp, val & 0xff);
- rsp_buffer_push(rsp, (val >> 8) & 0xff);
- for (i = 0; i < 4; i++) {
- rsp_buffer_push(rsp, ibs->sel.last_addition[i]);
- }
- for (i = 0; i < 4; i++) {
- rsp_buffer_push(rsp, ibs->sel.last_clear[i]);
- }
- /* Only support Reserve SEL */
- rsp_buffer_push(rsp, (ibs->sel.overflow << 7) | 0x02);
-}
-
-static void reserve_sel(IPMIBmcSim *ibs,
- uint8_t *cmd, unsigned int cmd_len,
- RspBuffer *rsp)
-{
- rsp_buffer_push(rsp, ibs->sel.reservation & 0xff);
- rsp_buffer_push(rsp, (ibs->sel.reservation >> 8) & 0xff);
-}
-
-static void get_sel_entry(IPMIBmcSim *ibs,
- uint8_t *cmd, unsigned int cmd_len,
- RspBuffer *rsp)
-{
- unsigned int val;
-
- if (cmd[6]) {
- if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) {
- rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
- return;
- }
- }
- if (ibs->sel.next_free == 0) {
- rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
- return;
- }
- if (cmd[6] > 15) {
- rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
- return;
- }
- if (cmd[7] == 0xff) {
- cmd[7] = 16;
- } else if ((cmd[7] + cmd[6]) > 16) {
- rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
- return;
- } else {
- cmd[7] += cmd[6];
- }
-
- val = cmd[4] | (cmd[5] << 8);
- if (val == 0xffff) {
- val = ibs->sel.next_free - 1;
- } else if (val >= ibs->sel.next_free) {
- rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
- return;
- }
- if ((val + 1) == ibs->sel.next_free) {
- rsp_buffer_push(rsp, 0xff);
- rsp_buffer_push(rsp, 0xff);
- } else {
- rsp_buffer_push(rsp, (val + 1) & 0xff);
- rsp_buffer_push(rsp, ((val + 1) >> 8) & 0xff);
- }
- for (; cmd[6] < cmd[7]; cmd[6]++) {
- rsp_buffer_push(rsp, ibs->sel.sel[val][cmd[6]]);
- }
-}
-
-static void add_sel_entry(IPMIBmcSim *ibs,
- uint8_t *cmd, unsigned int cmd_len,
- RspBuffer *rsp)
-{
- if (sel_add_event(ibs, cmd + 2)) {
- rsp_buffer_set_error(rsp, IPMI_CC_OUT_OF_SPACE);
- return;
- }
- /* sel_add_event fills in the record number. */
- rsp_buffer_push(rsp, cmd[2]);
- rsp_buffer_push(rsp, cmd[3]);
-}
-
-static void clear_sel(IPMIBmcSim *ibs,
- uint8_t *cmd, unsigned int cmd_len,
- RspBuffer *rsp)
-{
- if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) {
- rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
- return;
- }
-
- if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
- rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
- return;
- }
- if (cmd[7] == 0xaa) {
- ibs->sel.next_free = 0;
- ibs->sel.overflow = 0;
- set_timestamp(ibs, ibs->sdr.last_clear);
- rsp_buffer_push(rsp, 1); /* Erasure complete */
- sel_inc_reservation(&ibs->sel);
- } else if (cmd[7] == 0) {
- rsp_buffer_push(rsp, 1); /* Erasure complete */
- } else {
- rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
- return;
- }
-}
-
-static void get_sel_time(IPMIBmcSim *ibs,
- uint8_t *cmd, unsigned int cmd_len,
- RspBuffer *rsp)
-{
- uint32_t val;
- struct ipmi_time now;
-
- ipmi_gettime(&now);
- val = now.tv_sec + ibs->sel.time_offset;
- rsp_buffer_push(rsp, val & 0xff);
- rsp_buffer_push(rsp, (val >> 8) & 0xff);
- rsp_buffer_push(rsp, (val >> 16) & 0xff);
- rsp_buffer_push(rsp, (val >> 24) & 0xff);
-}
-
-static void set_sel_time(IPMIBmcSim *ibs,
- uint8_t *cmd, unsigned int cmd_len,
- RspBuffer *rsp)
-{
- uint32_t val;
- struct ipmi_time now;
-
- val = cmd[2] | (cmd[3] << 8) | (cmd[4] << 16) | (cmd[5] << 24);
- ipmi_gettime(&now);
- ibs->sel.time_offset = now.tv_sec - ((long) val);
-}
-
-static void set_sensor_evt_enable(IPMIBmcSim *ibs,
- uint8_t *cmd, unsigned int cmd_len,
- RspBuffer *rsp)
-{
- IPMISensor *sens;
-
- if ((cmd[2] >= MAX_SENSORS) ||
- !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
- rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
- return;
- }
- sens = ibs->sensors + cmd[2];
- switch ((cmd[3] >> 4) & 0x3) {
- case 0: /* Do not change */
- break;
- case 1: /* Enable bits */
- if (cmd_len > 4) {
- sens->assert_enable |= cmd[4];
- }
- if (cmd_len > 5) {
- sens->assert_enable |= cmd[5] << 8;
- }
- if (cmd_len > 6) {
- sens->deassert_enable |= cmd[6];
- }
- if (cmd_len > 7) {
- sens->deassert_enable |= cmd[7] << 8;
- }
- break;
- case 2: /* Disable bits */
- if (cmd_len > 4) {
- sens->assert_enable &= ~cmd[4];
- }
- if (cmd_len > 5) {
- sens->assert_enable &= ~(cmd[5] << 8);
- }
- if (cmd_len > 6) {
- sens->deassert_enable &= ~cmd[6];
- }
- if (cmd_len > 7) {
- sens->deassert_enable &= ~(cmd[7] << 8);
- }
- break;
- case 3:
- rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
- return;
- }
- IPMI_SENSOR_SET_RET_STATUS(sens, cmd[3]);
-}
-
-static void get_sensor_evt_enable(IPMIBmcSim *ibs,
- uint8_t *cmd, unsigned int cmd_len,
- RspBuffer *rsp)
-{
- IPMISensor *sens;
-
- if ((cmd[2] >= MAX_SENSORS) ||
- !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
- rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
- return;
- }
- sens = ibs->sensors + cmd[2];
- rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
- rsp_buffer_push(rsp, sens->assert_enable & 0xff);
- rsp_buffer_push(rsp, (sens->assert_enable >> 8) & 0xff);
- rsp_buffer_push(rsp, sens->deassert_enable & 0xff);
- rsp_buffer_push(rsp, (sens->deassert_enable >> 8) & 0xff);
-}
-
-static void rearm_sensor_evts(IPMIBmcSim *ibs,
- uint8_t *cmd, unsigned int cmd_len,
- RspBuffer *rsp)
-{
- IPMISensor *sens;
-
- if ((cmd[2] >= MAX_SENSORS) ||
- !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
- rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
- return;
- }
- sens = ibs->sensors + cmd[2];
-
- if ((cmd[3] & 0x80) == 0) {
- /* Just clear everything */
- sens->states = 0;
- return;
- }
-}
-
-static void get_sensor_evt_status(IPMIBmcSim *ibs,
- uint8_t *cmd, unsigned int cmd_len,
- RspBuffer *rsp)
-{
- IPMISensor *sens;
-
- if ((cmd[2] >= MAX_SENSORS) ||
- !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
- rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
- return;
- }
- sens = ibs->sensors + cmd[2];
- rsp_buffer_push(rsp, sens->reading);
- rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
- rsp_buffer_push(rsp, sens->assert_states & 0xff);
- rsp_buffer_push(rsp, (sens->assert_states >> 8) & 0xff);
- rsp_buffer_push(rsp, sens->deassert_states & 0xff);
- rsp_buffer_push(rsp, (sens->deassert_states >> 8) & 0xff);
-}
-
-static void get_sensor_reading(IPMIBmcSim *ibs,
- uint8_t *cmd, unsigned int cmd_len,
- RspBuffer *rsp)
-{
- IPMISensor *sens;
-
- if ((cmd[2] >= MAX_SENSORS) ||
- !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
- rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
- return;
- }
- sens = ibs->sensors + cmd[2];
- rsp_buffer_push(rsp, sens->reading);
- rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
- rsp_buffer_push(rsp, sens->states & 0xff);
- if (IPMI_SENSOR_IS_DISCRETE(sens)) {
- rsp_buffer_push(rsp, (sens->states >> 8) & 0xff);
- }
-}
-
-static void set_sensor_type(IPMIBmcSim *ibs,
- uint8_t *cmd, unsigned int cmd_len,
- RspBuffer *rsp)
-{
- IPMISensor *sens;
-
-
- if ((cmd[2] >= MAX_SENSORS) ||
- !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
- rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
- return;
- }
- sens = ibs->sensors + cmd[2];
- sens->sensor_type = cmd[3];
- sens->evt_reading_type_code = cmd[4] & 0x7f;
-}
-
-static void get_sensor_type(IPMIBmcSim *ibs,
- uint8_t *cmd, unsigned int cmd_len,
- RspBuffer *rsp)
-{
- IPMISensor *sens;
-
-
- if ((cmd[2] >= MAX_SENSORS) ||
- !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
- rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
- return;
- }
- sens = ibs->sensors + cmd[2];
- rsp_buffer_push(rsp, sens->sensor_type);
- rsp_buffer_push(rsp, sens->evt_reading_type_code);
-}
-
-
-static const IPMICmdHandler chassis_cmds[] = {
- [IPMI_CMD_GET_CHASSIS_CAPABILITIES] = { chassis_capabilities },
- [IPMI_CMD_GET_CHASSIS_STATUS] = { chassis_status },
- [IPMI_CMD_CHASSIS_CONTROL] = { chassis_control, 3 },
- [IPMI_CMD_GET_SYS_RESTART_CAUSE] = { chassis_get_sys_restart_cause }
-};
-static const IPMINetfn chassis_netfn = {
- .cmd_nums = ARRAY_SIZE(chassis_cmds),
- .cmd_handlers = chassis_cmds
-};
-
-static const IPMICmdHandler sensor_event_cmds[] = {
- [IPMI_CMD_SET_SENSOR_EVT_ENABLE] = { set_sensor_evt_enable, 4 },
- [IPMI_CMD_GET_SENSOR_EVT_ENABLE] = { get_sensor_evt_enable, 3 },
- [IPMI_CMD_REARM_SENSOR_EVTS] = { rearm_sensor_evts, 4 },
- [IPMI_CMD_GET_SENSOR_EVT_STATUS] = { get_sensor_evt_status, 3 },
- [IPMI_CMD_GET_SENSOR_READING] = { get_sensor_reading, 3 },
- [IPMI_CMD_SET_SENSOR_TYPE] = { set_sensor_type, 5 },
- [IPMI_CMD_GET_SENSOR_TYPE] = { get_sensor_type, 3 },
-};
-static const IPMINetfn sensor_event_netfn = {
- .cmd_nums = ARRAY_SIZE(sensor_event_cmds),
- .cmd_handlers = sensor_event_cmds
-};
-
-static const IPMICmdHandler app_cmds[] = {
- [IPMI_CMD_GET_DEVICE_ID] = { get_device_id },
- [IPMI_CMD_COLD_RESET] = { cold_reset },
- [IPMI_CMD_WARM_RESET] = { warm_reset },
- [IPMI_CMD_SET_ACPI_POWER_STATE] = { set_acpi_power_state, 4 },
- [IPMI_CMD_GET_ACPI_POWER_STATE] = { get_acpi_power_state },
- [IPMI_CMD_GET_DEVICE_GUID] = { get_device_guid },
- [IPMI_CMD_SET_BMC_GLOBAL_ENABLES] = { set_bmc_global_enables, 3 },
- [IPMI_CMD_GET_BMC_GLOBAL_ENABLES] = { get_bmc_global_enables },
- [IPMI_CMD_CLR_MSG_FLAGS] = { clr_msg_flags, 3 },
- [IPMI_CMD_GET_MSG_FLAGS] = { get_msg_flags },
- [IPMI_CMD_GET_MSG] = { get_msg },
- [IPMI_CMD_SEND_MSG] = { send_msg, 3 },
- [IPMI_CMD_READ_EVT_MSG_BUF] = { read_evt_msg_buf },
- [IPMI_CMD_RESET_WATCHDOG_TIMER] = { reset_watchdog_timer },
- [IPMI_CMD_SET_WATCHDOG_TIMER] = { set_watchdog_timer, 8 },
- [IPMI_CMD_GET_WATCHDOG_TIMER] = { get_watchdog_timer },
-};
-static const IPMINetfn app_netfn = {
- .cmd_nums = ARRAY_SIZE(app_cmds),
- .cmd_handlers = app_cmds
-};
-
-static const IPMICmdHandler storage_cmds[] = {
- [IPMI_CMD_GET_SDR_REP_INFO] = { get_sdr_rep_info },
- [IPMI_CMD_RESERVE_SDR_REP] = { reserve_sdr_rep },
- [IPMI_CMD_GET_SDR] = { get_sdr, 8 },
- [IPMI_CMD_ADD_SDR] = { add_sdr },
- [IPMI_CMD_CLEAR_SDR_REP] = { clear_sdr_rep, 8 },
- [IPMI_CMD_GET_SEL_INFO] = { get_sel_info },
- [IPMI_CMD_RESERVE_SEL] = { reserve_sel },
- [IPMI_CMD_GET_SEL_ENTRY] = { get_sel_entry, 8 },
- [IPMI_CMD_ADD_SEL_ENTRY] = { add_sel_entry, 18 },
- [IPMI_CMD_CLEAR_SEL] = { clear_sel, 8 },
- [IPMI_CMD_GET_SEL_TIME] = { get_sel_time, 6 },
- [IPMI_CMD_SET_SEL_TIME] = { set_sel_time },
-};
-
-static const IPMINetfn storage_netfn = {
- .cmd_nums = ARRAY_SIZE(storage_cmds),
- .cmd_handlers = storage_cmds
-};
-
-static void register_cmds(IPMIBmcSim *s)
-{
- ipmi_register_netfn(s, IPMI_NETFN_CHASSIS, &chassis_netfn);
- ipmi_register_netfn(s, IPMI_NETFN_SENSOR_EVENT, &sensor_event_netfn);
- ipmi_register_netfn(s, IPMI_NETFN_APP, &app_netfn);
- ipmi_register_netfn(s, IPMI_NETFN_STORAGE, &storage_netfn);
-}
-
-static uint8_t init_sdrs[] = {
- /* Watchdog device */
- 0x00, 0x00, 0x51, 0x02, 35, 0x20, 0x00, 0x00,
- 0x23, 0x01, 0x63, 0x00, 0x23, 0x6f, 0x0f, 0x01,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8,
- 'W', 'a', 't', 'c', 'h', 'd', 'o', 'g',
-};
-
-static void ipmi_sdr_init(IPMIBmcSim *ibs)
-{
- unsigned int i;
- int len;
- size_t sdrs_size;
- uint8_t *sdrs;
-
- sdrs_size = sizeof(init_sdrs);
- sdrs = init_sdrs;
-
- for (i = 0; i < sdrs_size; i += len) {
- struct ipmi_sdr_header *sdrh;
-
- if (i + IPMI_SDR_HEADER_SIZE > sdrs_size) {
- error_report("Problem with recid 0x%4.4x", i);
- return;
- }
- sdrh = (struct ipmi_sdr_header *) &sdrs[i];
- len = ipmi_sdr_length(sdrh);
- if (i + len > sdrs_size) {
- error_report("Problem with recid 0x%4.4x", i);
- return;
- }
- sdr_add_entry(ibs, sdrh, len, NULL);
- }
-}
-
-static const VMStateDescription vmstate_ipmi_sim = {
- .name = TYPE_IPMI_BMC_SIMULATOR,
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(bmc_global_enables, IPMIBmcSim),
- VMSTATE_UINT8(msg_flags, IPMIBmcSim),
- VMSTATE_BOOL(watchdog_initialized, IPMIBmcSim),
- VMSTATE_UINT8(watchdog_use, IPMIBmcSim),
- VMSTATE_UINT8(watchdog_action, IPMIBmcSim),
- VMSTATE_UINT8(watchdog_pretimeout, IPMIBmcSim),
- VMSTATE_BOOL(watchdog_expired, IPMIBmcSim),
- VMSTATE_UINT16(watchdog_timeout, IPMIBmcSim),
- VMSTATE_BOOL(watchdog_running, IPMIBmcSim),
- VMSTATE_BOOL(watchdog_preaction_ran, IPMIBmcSim),
- VMSTATE_INT64(watchdog_expiry, IPMIBmcSim),
- VMSTATE_UINT8_ARRAY(evtbuf, IPMIBmcSim, 16),
- VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].status, IPMIBmcSim),
- VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].reading, IPMIBmcSim),
- VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].states, IPMIBmcSim),
- VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_states, IPMIBmcSim),
- VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].deassert_states,
- IPMIBmcSim),
- VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_enable, IPMIBmcSim),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void ipmi_sim_realize(DeviceState *dev, Error **errp)
-{
- IPMIBmc *b = IPMI_BMC(dev);
- unsigned int i;
- IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
-
- qemu_mutex_init(&ibs->lock);
- QTAILQ_INIT(&ibs->rcvbufs);
-
- ibs->bmc_global_enables = (1 << IPMI_BMC_EVENT_LOG_BIT);
- ibs->device_id = 0x20;
- ibs->ipmi_version = 0x02; /* IPMI 2.0 */
- ibs->restart_cause = 0;
- for (i = 0; i < 4; i++) {
- ibs->sel.last_addition[i] = 0xff;
- ibs->sel.last_clear[i] = 0xff;
- ibs->sdr.last_addition[i] = 0xff;
- ibs->sdr.last_clear[i] = 0xff;
- }
-
- ipmi_sdr_init(ibs);
-
- ibs->acpi_power_state[0] = 0;
- ibs->acpi_power_state[1] = 0;
-
- if (qemu_uuid_set) {
- memcpy(&ibs->uuid, qemu_uuid, 16);
- } else {
- memset(&ibs->uuid, 0, 16);
- }
-
- ipmi_init_sensors_from_sdrs(ibs);
- register_cmds(ibs);
-
- ibs->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ipmi_timeout, ibs);
-
- vmstate_register(NULL, 0, &vmstate_ipmi_sim, ibs);
-}
-
-static void ipmi_sim_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
- IPMIBmcClass *bk = IPMI_BMC_CLASS(oc);
-
- dc->realize = ipmi_sim_realize;
- bk->handle_command = ipmi_sim_handle_command;
-}
-
-static const TypeInfo ipmi_sim_type = {
- .name = TYPE_IPMI_BMC_SIMULATOR,
- .parent = TYPE_IPMI_BMC,
- .instance_size = sizeof(IPMIBmcSim),
- .class_init = ipmi_sim_class_init,
-};
-
-static void ipmi_sim_register_types(void)
-{
- type_register_static(&ipmi_sim_type);
-}
-
-type_init(ipmi_sim_register_types)
diff --git a/qemu/hw/ipmi/isa_ipmi_bt.c b/qemu/hw/ipmi/isa_ipmi_bt.c
deleted file mode 100644
index aaea12ecd..000000000
--- a/qemu/hw/ipmi/isa_ipmi_bt.c
+++ /dev/null
@@ -1,530 +0,0 @@
-/*
- * QEMU ISA IPMI BT emulation
- *
- * Copyright (c) 2015 Corey Minyard, MontaVista Software, LLC
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/hw.h"
-#include "hw/ipmi/ipmi.h"
-#include "hw/isa/isa.h"
-#include "hw/i386/pc.h"
-
-/* Control register */
-#define IPMI_BT_CLR_WR_BIT 0
-#define IPMI_BT_CLR_RD_BIT 1
-#define IPMI_BT_H2B_ATN_BIT 2
-#define IPMI_BT_B2H_ATN_BIT 3
-#define IPMI_BT_SMS_ATN_BIT 4
-#define IPMI_BT_HBUSY_BIT 6
-#define IPMI_BT_BBUSY_BIT 7
-
-#define IPMI_BT_CLR_WR_MASK (1 << IPMI_BT_CLR_WR_BIT)
-#define IPMI_BT_GET_CLR_WR(d) (((d) >> IPMI_BT_CLR_WR_BIT) & 0x1)
-#define IPMI_BT_SET_CLR_WR(d, v) (d) = (((d) & ~IPMI_BT_CLR_WR_MASK) | \
- (((v & 1) << IPMI_BT_CLR_WR_BIT)))
-
-#define IPMI_BT_CLR_RD_MASK (1 << IPMI_BT_CLR_RD_BIT)
-#define IPMI_BT_GET_CLR_RD(d) (((d) >> IPMI_BT_CLR_RD_BIT) & 0x1)
-#define IPMI_BT_SET_CLR_RD(d, v) (d) = (((d) & ~IPMI_BT_CLR_RD_MASK) | \
- (((v & 1) << IPMI_BT_CLR_RD_BIT)))
-
-#define IPMI_BT_H2B_ATN_MASK (1 << IPMI_BT_H2B_ATN_BIT)
-#define IPMI_BT_GET_H2B_ATN(d) (((d) >> IPMI_BT_H2B_ATN_BIT) & 0x1)
-#define IPMI_BT_SET_H2B_ATN(d, v) (d) = (((d) & ~IPMI_BT_H2B_ATN_MASK) | \
- (((v & 1) << IPMI_BT_H2B_ATN_BIT)))
-
-#define IPMI_BT_B2H_ATN_MASK (1 << IPMI_BT_B2H_ATN_BIT)
-#define IPMI_BT_GET_B2H_ATN(d) (((d) >> IPMI_BT_B2H_ATN_BIT) & 0x1)
-#define IPMI_BT_SET_B2H_ATN(d, v) (d) = (((d) & ~IPMI_BT_B2H_ATN_MASK) | \
- (((v & 1) << IPMI_BT_B2H_ATN_BIT)))
-
-#define IPMI_BT_SMS_ATN_MASK (1 << IPMI_BT_SMS_ATN_BIT)
-#define IPMI_BT_GET_SMS_ATN(d) (((d) >> IPMI_BT_SMS_ATN_BIT) & 0x1)
-#define IPMI_BT_SET_SMS_ATN(d, v) (d) = (((d) & ~IPMI_BT_SMS_ATN_MASK) | \
- (((v & 1) << IPMI_BT_SMS_ATN_BIT)))
-
-#define IPMI_BT_HBUSY_MASK (1 << IPMI_BT_HBUSY_BIT)
-#define IPMI_BT_GET_HBUSY(d) (((d) >> IPMI_BT_HBUSY_BIT) & 0x1)
-#define IPMI_BT_SET_HBUSY(d, v) (d) = (((d) & ~IPMI_BT_HBUSY_MASK) | \
- (((v & 1) << IPMI_BT_HBUSY_BIT)))
-
-#define IPMI_BT_BBUSY_MASK (1 << IPMI_BT_BBUSY_BIT)
-#define IPMI_BT_GET_BBUSY(d) (((d) >> IPMI_BT_BBUSY_BIT) & 0x1)
-#define IPMI_BT_SET_BBUSY(d, v) (d) = (((d) & ~IPMI_BT_BBUSY_MASK) | \
- (((v & 1) << IPMI_BT_BBUSY_BIT)))
-
-
-/* Mask register */
-#define IPMI_BT_B2H_IRQ_EN_BIT 0
-#define IPMI_BT_B2H_IRQ_BIT 1
-
-#define IPMI_BT_B2H_IRQ_EN_MASK (1 << IPMI_BT_B2H_IRQ_EN_BIT)
-#define IPMI_BT_GET_B2H_IRQ_EN(d) (((d) >> IPMI_BT_B2H_IRQ_EN_BIT) & 0x1)
-#define IPMI_BT_SET_B2H_IRQ_EN(d, v) (d) = (((d) & ~IPMI_BT_B2H_IRQ_EN_MASK) | \
- (((v & 1) << IPMI_BT_B2H_IRQ_EN_BIT)))
-
-#define IPMI_BT_B2H_IRQ_MASK (1 << IPMI_BT_B2H_IRQ_BIT)
-#define IPMI_BT_GET_B2H_IRQ(d) (((d) >> IPMI_BT_B2H_IRQ_BIT) & 0x1)
-#define IPMI_BT_SET_B2H_IRQ(d, v) (d) = (((d) & ~IPMI_BT_B2H_IRQ_MASK) | \
- (((v & 1) << IPMI_BT_B2H_IRQ_BIT)))
-
-typedef struct IPMIBT {
- IPMIBmc *bmc;
-
- bool do_wake;
-
- qemu_irq irq;
-
- uint32_t io_base;
- unsigned long io_length;
- MemoryRegion io;
-
- bool obf_irq_set;
- bool atn_irq_set;
- bool use_irq;
- bool irqs_enabled;
-
- uint8_t outmsg[MAX_IPMI_MSG_SIZE];
- uint32_t outpos;
- uint32_t outlen;
-
- uint8_t inmsg[MAX_IPMI_MSG_SIZE];
- uint32_t inlen;
-
- uint8_t control_reg;
- uint8_t mask_reg;
-
- /*
- * This is a response number that we send with the command to make
- * sure that the response matches the command.
- */
- uint8_t waiting_rsp;
- uint8_t waiting_seq;
-} IPMIBT;
-
-#define IPMI_CMD_GET_BT_INTF_CAP 0x36
-
-static void ipmi_bt_handle_event(IPMIInterface *ii)
-{
- IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
- IPMIBT *ib = iic->get_backend_data(ii);
-
- if (ib->inlen < 4) {
- goto out;
- }
- /* Note that overruns are handled by handle_command */
- if (ib->inmsg[0] != (ib->inlen - 1)) {
- /* Length mismatch, just ignore. */
- IPMI_BT_SET_BBUSY(ib->control_reg, 1);
- ib->inlen = 0;
- goto out;
- }
- if ((ib->inmsg[1] == (IPMI_NETFN_APP << 2)) &&
- (ib->inmsg[3] == IPMI_CMD_GET_BT_INTF_CAP)) {
- /* We handle this one ourselves. */
- ib->outmsg[0] = 9;
- ib->outmsg[1] = ib->inmsg[1] | 0x04;
- ib->outmsg[2] = ib->inmsg[2];
- ib->outmsg[3] = ib->inmsg[3];
- ib->outmsg[4] = 0;
- ib->outmsg[5] = 1; /* Only support 1 outstanding request. */
- if (sizeof(ib->inmsg) > 0xff) { /* Input buffer size */
- ib->outmsg[6] = 0xff;
- } else {
- ib->outmsg[6] = (unsigned char) sizeof(ib->inmsg);
- }
- if (sizeof(ib->outmsg) > 0xff) { /* Output buffer size */
- ib->outmsg[7] = 0xff;
- } else {
- ib->outmsg[7] = (unsigned char) sizeof(ib->outmsg);
- }
- ib->outmsg[8] = 10; /* Max request to response time */
- ib->outmsg[9] = 0; /* Don't recommend retries */
- ib->outlen = 10;
- IPMI_BT_SET_BBUSY(ib->control_reg, 0);
- IPMI_BT_SET_B2H_ATN(ib->control_reg, 1);
- if (ib->use_irq && ib->irqs_enabled &&
- !IPMI_BT_GET_B2H_IRQ(ib->mask_reg) &&
- IPMI_BT_GET_B2H_IRQ_EN(ib->mask_reg)) {
- IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 1);
- qemu_irq_raise(ib->irq);
- }
- goto out;
- }
- ib->waiting_seq = ib->inmsg[2];
- ib->inmsg[2] = ib->inmsg[1];
- {
- IPMIBmcClass *bk = IPMI_BMC_GET_CLASS(ib->bmc);
- bk->handle_command(ib->bmc, ib->inmsg + 2, ib->inlen - 2,
- sizeof(ib->inmsg), ib->waiting_rsp);
- }
- out:
- return;
-}
-
-static void ipmi_bt_handle_rsp(IPMIInterface *ii, uint8_t msg_id,
- unsigned char *rsp, unsigned int rsp_len)
-{
- IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
- IPMIBT *ib = iic->get_backend_data(ii);
-
- if (ib->waiting_rsp == msg_id) {
- ib->waiting_rsp++;
- if (rsp_len > (sizeof(ib->outmsg) - 2)) {
- ib->outmsg[0] = 4;
- ib->outmsg[1] = rsp[0];
- ib->outmsg[2] = ib->waiting_seq;
- ib->outmsg[3] = rsp[1];
- ib->outmsg[4] = IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES;
- ib->outlen = 5;
- } else {
- ib->outmsg[0] = rsp_len + 1;
- ib->outmsg[1] = rsp[0];
- ib->outmsg[2] = ib->waiting_seq;
- memcpy(ib->outmsg + 3, rsp + 1, rsp_len - 1);
- ib->outlen = rsp_len + 2;
- }
- IPMI_BT_SET_BBUSY(ib->control_reg, 0);
- IPMI_BT_SET_B2H_ATN(ib->control_reg, 1);
- if (ib->use_irq && ib->irqs_enabled &&
- !IPMI_BT_GET_B2H_IRQ(ib->mask_reg) &&
- IPMI_BT_GET_B2H_IRQ_EN(ib->mask_reg)) {
- IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 1);
- qemu_irq_raise(ib->irq);
- }
- }
-}
-
-
-static uint64_t ipmi_bt_ioport_read(void *opaque, hwaddr addr, unsigned size)
-{
- IPMIInterface *ii = opaque;
- IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
- IPMIBT *ib = iic->get_backend_data(ii);
- uint32_t ret = 0xff;
-
- switch (addr & 3) {
- case 0:
- ret = ib->control_reg;
- break;
- case 1:
- if (ib->outpos < ib->outlen) {
- ret = ib->outmsg[ib->outpos];
- ib->outpos++;
- if (ib->outpos == ib->outlen) {
- ib->outpos = 0;
- ib->outlen = 0;
- }
- } else {
- ret = 0xff;
- }
- break;
- case 2:
- ret = ib->mask_reg;
- break;
- }
- return ret;
-}
-
-static void ipmi_bt_signal(IPMIBT *ib, IPMIInterface *ii)
-{
- IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
-
- ib->do_wake = 1;
- while (ib->do_wake) {
- ib->do_wake = 0;
- iic->handle_if_event(ii);
- }
-}
-
-static void ipmi_bt_ioport_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned size)
-{
- IPMIInterface *ii = opaque;
- IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
- IPMIBT *ib = iic->get_backend_data(ii);
-
- switch (addr & 3) {
- case 0:
- if (IPMI_BT_GET_CLR_WR(val)) {
- ib->inlen = 0;
- }
- if (IPMI_BT_GET_CLR_RD(val)) {
- ib->outpos = 0;
- }
- if (IPMI_BT_GET_B2H_ATN(val)) {
- IPMI_BT_SET_B2H_ATN(ib->control_reg, 0);
- }
- if (IPMI_BT_GET_SMS_ATN(val)) {
- IPMI_BT_SET_SMS_ATN(ib->control_reg, 0);
- }
- if (IPMI_BT_GET_HBUSY(val)) {
- /* Toggle */
- IPMI_BT_SET_HBUSY(ib->control_reg,
- !IPMI_BT_GET_HBUSY(ib->control_reg));
- }
- if (IPMI_BT_GET_H2B_ATN(val)) {
- IPMI_BT_SET_BBUSY(ib->control_reg, 1);
- ipmi_bt_signal(ib, ii);
- }
- break;
-
- case 1:
- if (ib->inlen < sizeof(ib->inmsg)) {
- ib->inmsg[ib->inlen] = val;
- }
- ib->inlen++;
- break;
-
- case 2:
- if (IPMI_BT_GET_B2H_IRQ_EN(val) !=
- IPMI_BT_GET_B2H_IRQ_EN(ib->mask_reg)) {
- if (IPMI_BT_GET_B2H_IRQ_EN(val)) {
- if (IPMI_BT_GET_B2H_ATN(ib->control_reg) ||
- IPMI_BT_GET_SMS_ATN(ib->control_reg)) {
- IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 1);
- qemu_irq_raise(ib->irq);
- }
- IPMI_BT_SET_B2H_IRQ_EN(ib->mask_reg, 1);
- } else {
- if (IPMI_BT_GET_B2H_IRQ(ib->mask_reg)) {
- IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 0);
- qemu_irq_lower(ib->irq);
- }
- IPMI_BT_SET_B2H_IRQ_EN(ib->mask_reg, 0);
- }
- }
- if (IPMI_BT_GET_B2H_IRQ(val) && IPMI_BT_GET_B2H_IRQ(ib->mask_reg)) {
- IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 0);
- qemu_irq_lower(ib->irq);
- }
- break;
- }
-}
-
-static const MemoryRegionOps ipmi_bt_io_ops = {
- .read = ipmi_bt_ioport_read,
- .write = ipmi_bt_ioport_write,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void ipmi_bt_set_atn(IPMIInterface *ii, int val, int irq)
-{
- IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
- IPMIBT *ib = iic->get_backend_data(ii);
-
- if (!!val == IPMI_BT_GET_SMS_ATN(ib->control_reg)) {
- return;
- }
-
- IPMI_BT_SET_SMS_ATN(ib->control_reg, val);
- if (val) {
- if (irq && ib->use_irq && ib->irqs_enabled &&
- !IPMI_BT_GET_B2H_ATN(ib->control_reg) &&
- IPMI_BT_GET_B2H_IRQ_EN(ib->mask_reg)) {
- IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 1);
- qemu_irq_raise(ib->irq);
- }
- } else {
- if (!IPMI_BT_GET_B2H_ATN(ib->control_reg) &&
- IPMI_BT_GET_B2H_IRQ(ib->mask_reg)) {
- IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 0);
- qemu_irq_lower(ib->irq);
- }
- }
-}
-
-static void ipmi_bt_handle_reset(IPMIInterface *ii, bool is_cold)
-{
- IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
- IPMIBT *ib = iic->get_backend_data(ii);
-
- if (is_cold) {
- /* Disable the BT interrupt on reset */
- if (IPMI_BT_GET_B2H_IRQ(ib->mask_reg)) {
- IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 0);
- qemu_irq_lower(ib->irq);
- }
- IPMI_BT_SET_B2H_IRQ_EN(ib->mask_reg, 0);
- }
-}
-
-static void ipmi_bt_set_irq_enable(IPMIInterface *ii, int val)
-{
- IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
- IPMIBT *ib = iic->get_backend_data(ii);
-
- ib->irqs_enabled = val;
-}
-
-static void ipmi_bt_init(IPMIInterface *ii, Error **errp)
-{
- IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
- IPMIBT *ib = iic->get_backend_data(ii);
-
- ib->io_length = 3;
-
- memory_region_init_io(&ib->io, NULL, &ipmi_bt_io_ops, ii, "ipmi-bt", 3);
-}
-
-static void ipmi_bt_class_init(IPMIInterfaceClass *iic)
-{
- iic->init = ipmi_bt_init;
- iic->set_atn = ipmi_bt_set_atn;
- iic->handle_rsp = ipmi_bt_handle_rsp;
- iic->handle_if_event = ipmi_bt_handle_event;
- iic->set_irq_enable = ipmi_bt_set_irq_enable;
- iic->reset = ipmi_bt_handle_reset;
-}
-
-
-#define TYPE_ISA_IPMI_BT "isa-ipmi-bt"
-#define ISA_IPMI_BT(obj) OBJECT_CHECK(ISAIPMIBTDevice, (obj), \
- TYPE_ISA_IPMI_BT)
-
-typedef struct ISAIPMIBTDevice {
- ISADevice dev;
- int32_t isairq;
- IPMIBT bt;
- IPMIFwInfo fwinfo;
-} ISAIPMIBTDevice;
-
-static void isa_ipmi_bt_realize(DeviceState *dev, Error **errp)
-{
- ISADevice *isadev = ISA_DEVICE(dev);
- ISAIPMIBTDevice *iib = ISA_IPMI_BT(dev);
- IPMIInterface *ii = IPMI_INTERFACE(dev);
- IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
-
- if (!iib->bt.bmc) {
- error_setg(errp, "IPMI device requires a bmc attribute to be set");
- return;
- }
-
- iib->bt.bmc->intf = ii;
-
- iic->init(ii, errp);
- if (*errp)
- return;
-
- if (iib->isairq > 0) {
- isa_init_irq(isadev, &iib->bt.irq, iib->isairq);
- iib->bt.use_irq = 1;
- }
-
- qdev_set_legacy_instance_id(dev, iib->bt.io_base, iib->bt.io_length);
-
- isa_register_ioport(isadev, &iib->bt.io, iib->bt.io_base);
-
- iib->fwinfo.interface_name = "bt";
- iib->fwinfo.interface_type = IPMI_SMBIOS_BT;
- iib->fwinfo.ipmi_spec_major_revision = 2;
- iib->fwinfo.ipmi_spec_minor_revision = 0;
- iib->fwinfo.base_address = iib->bt.io_base;
- iib->fwinfo.register_length = iib->bt.io_length;
- iib->fwinfo.register_spacing = 1;
- iib->fwinfo.memspace = IPMI_MEMSPACE_IO;
- iib->fwinfo.irq_type = IPMI_LEVEL_IRQ;
- iib->fwinfo.interrupt_number = iib->isairq;
- iib->fwinfo.acpi_parent = "\\_SB.PCI0.ISA";
- iib->fwinfo.i2c_slave_address = iib->bt.bmc->slave_addr;
- ipmi_add_fwinfo(&iib->fwinfo, errp);
-}
-
-static const VMStateDescription vmstate_ISAIPMIBTDevice = {
- .name = TYPE_IPMI_INTERFACE,
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_BOOL(bt.obf_irq_set, ISAIPMIBTDevice),
- VMSTATE_BOOL(bt.atn_irq_set, ISAIPMIBTDevice),
- VMSTATE_BOOL(bt.use_irq, ISAIPMIBTDevice),
- VMSTATE_BOOL(bt.irqs_enabled, ISAIPMIBTDevice),
- VMSTATE_UINT32(bt.outpos, ISAIPMIBTDevice),
- VMSTATE_VBUFFER_UINT32(bt.outmsg, ISAIPMIBTDevice, 1, NULL, 0,
- bt.outlen),
- VMSTATE_VBUFFER_UINT32(bt.inmsg, ISAIPMIBTDevice, 1, NULL, 0,
- bt.inlen),
- VMSTATE_UINT8(bt.control_reg, ISAIPMIBTDevice),
- VMSTATE_UINT8(bt.mask_reg, ISAIPMIBTDevice),
- VMSTATE_UINT8(bt.waiting_rsp, ISAIPMIBTDevice),
- VMSTATE_UINT8(bt.waiting_seq, ISAIPMIBTDevice),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void isa_ipmi_bt_init(Object *obj)
-{
- ISAIPMIBTDevice *iib = ISA_IPMI_BT(obj);
-
- ipmi_bmc_find_and_link(obj, (Object **) &iib->bt.bmc);
-
- vmstate_register(NULL, 0, &vmstate_ISAIPMIBTDevice, iib);
-}
-
-static void *isa_ipmi_bt_get_backend_data(IPMIInterface *ii)
-{
- ISAIPMIBTDevice *iib = ISA_IPMI_BT(ii);
-
- return &iib->bt;
-}
-
-static Property ipmi_isa_properties[] = {
- DEFINE_PROP_UINT32("ioport", ISAIPMIBTDevice, bt.io_base, 0xe4),
- DEFINE_PROP_INT32("irq", ISAIPMIBTDevice, isairq, 5),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void isa_ipmi_bt_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
- IPMIInterfaceClass *iic = IPMI_INTERFACE_CLASS(oc);
-
- dc->realize = isa_ipmi_bt_realize;
- dc->props = ipmi_isa_properties;
-
- iic->get_backend_data = isa_ipmi_bt_get_backend_data;
- ipmi_bt_class_init(iic);
-}
-
-static const TypeInfo isa_ipmi_bt_info = {
- .name = TYPE_ISA_IPMI_BT,
- .parent = TYPE_ISA_DEVICE,
- .instance_size = sizeof(ISAIPMIBTDevice),
- .instance_init = isa_ipmi_bt_init,
- .class_init = isa_ipmi_bt_class_init,
- .interfaces = (InterfaceInfo[]) {
- { TYPE_IPMI_INTERFACE },
- { }
- }
-};
-
-static void ipmi_register_types(void)
-{
- type_register_static(&isa_ipmi_bt_info);
-}
-
-type_init(ipmi_register_types)
diff --git a/qemu/hw/ipmi/isa_ipmi_kcs.c b/qemu/hw/ipmi/isa_ipmi_kcs.c
deleted file mode 100644
index 2742ce06c..000000000
--- a/qemu/hw/ipmi/isa_ipmi_kcs.c
+++ /dev/null
@@ -1,495 +0,0 @@
-/*
- * QEMU ISA IPMI KCS emulation
- *
- * Copyright (c) 2015 Corey Minyard, MontaVista Software, LLC
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/hw.h"
-#include "hw/ipmi/ipmi.h"
-#include "hw/isa/isa.h"
-#include "hw/i386/pc.h"
-
-#define IPMI_KCS_OBF_BIT 0
-#define IPMI_KCS_IBF_BIT 1
-#define IPMI_KCS_SMS_ATN_BIT 2
-#define IPMI_KCS_CD_BIT 3
-
-#define IPMI_KCS_OBF_MASK (1 << IPMI_KCS_OBF_BIT)
-#define IPMI_KCS_GET_OBF(d) (((d) >> IPMI_KCS_OBF_BIT) & 0x1)
-#define IPMI_KCS_SET_OBF(d, v) (d) = (((d) & ~IPMI_KCS_OBF_MASK) | \
- (((v) & 1) << IPMI_KCS_OBF_BIT))
-#define IPMI_KCS_IBF_MASK (1 << IPMI_KCS_IBF_BIT)
-#define IPMI_KCS_GET_IBF(d) (((d) >> IPMI_KCS_IBF_BIT) & 0x1)
-#define IPMI_KCS_SET_IBF(d, v) (d) = (((d) & ~IPMI_KCS_IBF_MASK) | \
- (((v) & 1) << IPMI_KCS_IBF_BIT))
-#define IPMI_KCS_SMS_ATN_MASK (1 << IPMI_KCS_SMS_ATN_BIT)
-#define IPMI_KCS_GET_SMS_ATN(d) (((d) >> IPMI_KCS_SMS_ATN_BIT) & 0x1)
-#define IPMI_KCS_SET_SMS_ATN(d, v) (d) = (((d) & ~IPMI_KCS_SMS_ATN_MASK) | \
- (((v) & 1) << IPMI_KCS_SMS_ATN_BIT))
-#define IPMI_KCS_CD_MASK (1 << IPMI_KCS_CD_BIT)
-#define IPMI_KCS_GET_CD(d) (((d) >> IPMI_KCS_CD_BIT) & 0x1)
-#define IPMI_KCS_SET_CD(d, v) (d) = (((d) & ~IPMI_KCS_CD_MASK) | \
- (((v) & 1) << IPMI_KCS_CD_BIT))
-
-#define IPMI_KCS_IDLE_STATE 0
-#define IPMI_KCS_READ_STATE 1
-#define IPMI_KCS_WRITE_STATE 2
-#define IPMI_KCS_ERROR_STATE 3
-
-#define IPMI_KCS_GET_STATE(d) (((d) >> 6) & 0x3)
-#define IPMI_KCS_SET_STATE(d, v) ((d) = ((d) & ~0xc0) | (((v) & 0x3) << 6))
-
-#define IPMI_KCS_ABORT_STATUS_CMD 0x60
-#define IPMI_KCS_WRITE_START_CMD 0x61
-#define IPMI_KCS_WRITE_END_CMD 0x62
-#define IPMI_KCS_READ_CMD 0x68
-
-#define IPMI_KCS_STATUS_NO_ERR 0x00
-#define IPMI_KCS_STATUS_ABORTED_ERR 0x01
-#define IPMI_KCS_STATUS_BAD_CC_ERR 0x02
-#define IPMI_KCS_STATUS_LENGTH_ERR 0x06
-
-typedef struct IPMIKCS {
- IPMIBmc *bmc;
-
- bool do_wake;
-
- qemu_irq irq;
-
- uint32_t io_base;
- unsigned long io_length;
- MemoryRegion io;
-
- bool obf_irq_set;
- bool atn_irq_set;
- bool use_irq;
- bool irqs_enabled;
-
- uint8_t outmsg[MAX_IPMI_MSG_SIZE];
- uint32_t outpos;
- uint32_t outlen;
-
- uint8_t inmsg[MAX_IPMI_MSG_SIZE];
- uint32_t inlen;
- bool write_end;
-
- uint8_t status_reg;
- uint8_t data_out_reg;
-
- int16_t data_in_reg; /* -1 means not written */
- int16_t cmd_reg;
-
- /*
- * This is a response number that we send with the command to make
- * sure that the response matches the command.
- */
- uint8_t waiting_rsp;
-} IPMIKCS;
-
-#define SET_OBF() \
- do { \
- IPMI_KCS_SET_OBF(ik->status_reg, 1); \
- if (ik->use_irq && ik->irqs_enabled && !ik->obf_irq_set) { \
- ik->obf_irq_set = 1; \
- if (!ik->atn_irq_set) { \
- qemu_irq_raise(ik->irq); \
- } \
- } \
- } while (0)
-
-static void ipmi_kcs_signal(IPMIKCS *ik, IPMIInterface *ii)
-{
- IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
-
- ik->do_wake = 1;
- while (ik->do_wake) {
- ik->do_wake = 0;
- iic->handle_if_event(ii);
- }
-}
-
-static void ipmi_kcs_handle_event(IPMIInterface *ii)
-{
- IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
- IPMIKCS *ik = iic->get_backend_data(ii);
-
- if (ik->cmd_reg == IPMI_KCS_ABORT_STATUS_CMD) {
- if (IPMI_KCS_GET_STATE(ik->status_reg) != IPMI_KCS_ERROR_STATE) {
- ik->waiting_rsp++; /* Invalidate the message */
- ik->outmsg[0] = IPMI_KCS_STATUS_ABORTED_ERR;
- ik->outlen = 1;
- ik->outpos = 0;
- IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_ERROR_STATE);
- SET_OBF();
- }
- goto out;
- }
-
- switch (IPMI_KCS_GET_STATE(ik->status_reg)) {
- case IPMI_KCS_IDLE_STATE:
- if (ik->cmd_reg == IPMI_KCS_WRITE_START_CMD) {
- IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_WRITE_STATE);
- ik->cmd_reg = -1;
- ik->write_end = 0;
- ik->inlen = 0;
- SET_OBF();
- }
- break;
-
- case IPMI_KCS_READ_STATE:
- handle_read:
- if (ik->outpos >= ik->outlen) {
- IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_IDLE_STATE);
- SET_OBF();
- } else if (ik->data_in_reg == IPMI_KCS_READ_CMD) {
- ik->data_out_reg = ik->outmsg[ik->outpos];
- ik->outpos++;
- SET_OBF();
- } else {
- ik->outmsg[0] = IPMI_KCS_STATUS_BAD_CC_ERR;
- ik->outlen = 1;
- ik->outpos = 0;
- IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_ERROR_STATE);
- SET_OBF();
- goto out;
- }
- break;
-
- case IPMI_KCS_WRITE_STATE:
- if (ik->data_in_reg != -1) {
- /*
- * Don't worry about input overrun here, that will be
- * handled in the BMC.
- */
- if (ik->inlen < sizeof(ik->inmsg)) {
- ik->inmsg[ik->inlen] = ik->data_in_reg;
- }
- ik->inlen++;
- }
- if (ik->write_end) {
- IPMIBmcClass *bk = IPMI_BMC_GET_CLASS(ik->bmc);
- ik->outlen = 0;
- ik->write_end = 0;
- ik->outpos = 0;
- bk->handle_command(ik->bmc, ik->inmsg, ik->inlen, sizeof(ik->inmsg),
- ik->waiting_rsp);
- goto out_noibf;
- } else if (ik->cmd_reg == IPMI_KCS_WRITE_END_CMD) {
- ik->cmd_reg = -1;
- ik->write_end = 1;
- }
- SET_OBF();
- break;
-
- case IPMI_KCS_ERROR_STATE:
- if (ik->data_in_reg != -1) {
- IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_READ_STATE);
- ik->data_in_reg = IPMI_KCS_READ_CMD;
- goto handle_read;
- }
- break;
- }
-
- if (ik->cmd_reg != -1) {
- /* Got an invalid command */
- ik->outmsg[0] = IPMI_KCS_STATUS_BAD_CC_ERR;
- ik->outlen = 1;
- ik->outpos = 0;
- IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_ERROR_STATE);
- }
-
- out:
- ik->cmd_reg = -1;
- ik->data_in_reg = -1;
- IPMI_KCS_SET_IBF(ik->status_reg, 0);
- out_noibf:
- return;
-}
-
-static void ipmi_kcs_handle_rsp(IPMIInterface *ii, uint8_t msg_id,
- unsigned char *rsp, unsigned int rsp_len)
-{
- IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
- IPMIKCS *ik = iic->get_backend_data(ii);
-
- if (ik->waiting_rsp == msg_id) {
- ik->waiting_rsp++;
- if (rsp_len > sizeof(ik->outmsg)) {
- ik->outmsg[0] = rsp[0];
- ik->outmsg[1] = rsp[1];
- ik->outmsg[2] = IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES;
- ik->outlen = 3;
- } else {
- memcpy(ik->outmsg, rsp, rsp_len);
- ik->outlen = rsp_len;
- }
- IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_READ_STATE);
- ik->data_in_reg = IPMI_KCS_READ_CMD;
- ipmi_kcs_signal(ik, ii);
- }
-}
-
-
-static uint64_t ipmi_kcs_ioport_read(void *opaque, hwaddr addr, unsigned size)
-{
- IPMIInterface *ii = opaque;
- IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
- IPMIKCS *ik = iic->get_backend_data(ii);
- uint32_t ret;
-
- switch (addr & 1) {
- case 0:
- ret = ik->data_out_reg;
- IPMI_KCS_SET_OBF(ik->status_reg, 0);
- if (ik->obf_irq_set) {
- ik->obf_irq_set = 0;
- if (!ik->atn_irq_set) {
- qemu_irq_lower(ik->irq);
- }
- }
- break;
- case 1:
- ret = ik->status_reg;
- if (ik->atn_irq_set) {
- ik->atn_irq_set = 0;
- if (!ik->obf_irq_set) {
- qemu_irq_lower(ik->irq);
- }
- }
- break;
- }
- return ret;
-}
-
-static void ipmi_kcs_ioport_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned size)
-{
- IPMIInterface *ii = opaque;
- IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
- IPMIKCS *ik = iic->get_backend_data(ii);
-
- if (IPMI_KCS_GET_IBF(ik->status_reg)) {
- return;
- }
-
- switch (addr & 1) {
- case 0:
- ik->data_in_reg = val;
- break;
-
- case 1:
- ik->cmd_reg = val;
- break;
- }
- IPMI_KCS_SET_IBF(ik->status_reg, 1);
- ipmi_kcs_signal(ik, ii);
-}
-
-const MemoryRegionOps ipmi_kcs_io_ops = {
- .read = ipmi_kcs_ioport_read,
- .write = ipmi_kcs_ioport_write,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void ipmi_kcs_set_atn(IPMIInterface *ii, int val, int irq)
-{
- IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
- IPMIKCS *ik = iic->get_backend_data(ii);
-
- IPMI_KCS_SET_SMS_ATN(ik->status_reg, val);
- if (val) {
- if (irq && !ik->atn_irq_set && ik->use_irq && ik->irqs_enabled) {
- ik->atn_irq_set = 1;
- if (!ik->obf_irq_set) {
- qemu_irq_raise(ik->irq);
- }
- }
- } else {
- if (ik->atn_irq_set) {
- ik->atn_irq_set = 0;
- if (!ik->obf_irq_set) {
- qemu_irq_lower(ik->irq);
- }
- }
- }
-}
-
-static void ipmi_kcs_set_irq_enable(IPMIInterface *ii, int val)
-{
- IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
- IPMIKCS *ik = iic->get_backend_data(ii);
-
- ik->irqs_enabled = val;
-}
-
-static void ipmi_kcs_init(IPMIInterface *ii, Error **errp)
-{
- IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
- IPMIKCS *ik = iic->get_backend_data(ii);
-
- ik->io_length = 2;
- memory_region_init_io(&ik->io, NULL, &ipmi_kcs_io_ops, ii, "ipmi-kcs", 2);
-}
-
-static void ipmi_kcs_class_init(IPMIInterfaceClass *iic)
-{
- iic->init = ipmi_kcs_init;
- iic->set_atn = ipmi_kcs_set_atn;
- iic->handle_rsp = ipmi_kcs_handle_rsp;
- iic->handle_if_event = ipmi_kcs_handle_event;
- iic->set_irq_enable = ipmi_kcs_set_irq_enable;
-}
-
-
-#define TYPE_ISA_IPMI_KCS "isa-ipmi-kcs"
-#define ISA_IPMI_KCS(obj) OBJECT_CHECK(ISAIPMIKCSDevice, (obj), \
- TYPE_ISA_IPMI_KCS)
-
-typedef struct ISAIPMIKCSDevice {
- ISADevice dev;
- int32_t isairq;
- IPMIKCS kcs;
- IPMIFwInfo fwinfo;
-} ISAIPMIKCSDevice;
-
-static void ipmi_isa_realize(DeviceState *dev, Error **errp)
-{
- ISADevice *isadev = ISA_DEVICE(dev);
- ISAIPMIKCSDevice *iik = ISA_IPMI_KCS(dev);
- IPMIInterface *ii = IPMI_INTERFACE(dev);
- IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
-
- if (!iik->kcs.bmc) {
- error_setg(errp, "IPMI device requires a bmc attribute to be set");
- return;
- }
-
- iik->kcs.bmc->intf = ii;
-
- iic->init(ii, errp);
- if (*errp)
- return;
-
- if (iik->isairq > 0) {
- isa_init_irq(isadev, &iik->kcs.irq, iik->isairq);
- iik->kcs.use_irq = 1;
- }
-
- qdev_set_legacy_instance_id(dev, iik->kcs.io_base, iik->kcs.io_length);
-
- isa_register_ioport(isadev, &iik->kcs.io, iik->kcs.io_base);
-
- iik->fwinfo.interface_name = "kcs";
- iik->fwinfo.interface_type = IPMI_SMBIOS_KCS;
- iik->fwinfo.ipmi_spec_major_revision = 2;
- iik->fwinfo.ipmi_spec_minor_revision = 0;
- iik->fwinfo.base_address = iik->kcs.io_base;
- iik->fwinfo.i2c_slave_address = iik->kcs.bmc->slave_addr;
- iik->fwinfo.register_length = iik->kcs.io_length;
- iik->fwinfo.register_spacing = 1;
- iik->fwinfo.memspace = IPMI_MEMSPACE_IO;
- iik->fwinfo.irq_type = IPMI_LEVEL_IRQ;
- iik->fwinfo.interrupt_number = iik->isairq;
- iik->fwinfo.acpi_parent = "\\_SB.PCI0.ISA";
- ipmi_add_fwinfo(&iik->fwinfo, errp);
-}
-
-const VMStateDescription vmstate_ISAIPMIKCSDevice = {
- .name = TYPE_IPMI_INTERFACE,
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_BOOL(kcs.obf_irq_set, ISAIPMIKCSDevice),
- VMSTATE_BOOL(kcs.atn_irq_set, ISAIPMIKCSDevice),
- VMSTATE_BOOL(kcs.use_irq, ISAIPMIKCSDevice),
- VMSTATE_BOOL(kcs.irqs_enabled, ISAIPMIKCSDevice),
- VMSTATE_UINT32(kcs.outpos, ISAIPMIKCSDevice),
- VMSTATE_VBUFFER_UINT32(kcs.outmsg, ISAIPMIKCSDevice, 1, NULL, 0,
- kcs.outlen),
- VMSTATE_VBUFFER_UINT32(kcs.inmsg, ISAIPMIKCSDevice, 1, NULL, 0,
- kcs.inlen),
- VMSTATE_BOOL(kcs.write_end, ISAIPMIKCSDevice),
- VMSTATE_UINT8(kcs.status_reg, ISAIPMIKCSDevice),
- VMSTATE_UINT8(kcs.data_out_reg, ISAIPMIKCSDevice),
- VMSTATE_INT16(kcs.data_in_reg, ISAIPMIKCSDevice),
- VMSTATE_INT16(kcs.cmd_reg, ISAIPMIKCSDevice),
- VMSTATE_UINT8(kcs.waiting_rsp, ISAIPMIKCSDevice),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void isa_ipmi_kcs_init(Object *obj)
-{
- ISAIPMIKCSDevice *iik = ISA_IPMI_KCS(obj);
-
- ipmi_bmc_find_and_link(obj, (Object **) &iik->kcs.bmc);
-
- vmstate_register(NULL, 0, &vmstate_ISAIPMIKCSDevice, iik);
-}
-
-static void *isa_ipmi_kcs_get_backend_data(IPMIInterface *ii)
-{
- ISAIPMIKCSDevice *iik = ISA_IPMI_KCS(ii);
-
- return &iik->kcs;
-}
-
-static Property ipmi_isa_properties[] = {
- DEFINE_PROP_UINT32("ioport", ISAIPMIKCSDevice, kcs.io_base, 0xca2),
- DEFINE_PROP_INT32("irq", ISAIPMIKCSDevice, isairq, 5),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void isa_ipmi_kcs_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
- IPMIInterfaceClass *iic = IPMI_INTERFACE_CLASS(oc);
-
- dc->realize = ipmi_isa_realize;
- dc->props = ipmi_isa_properties;
-
- iic->get_backend_data = isa_ipmi_kcs_get_backend_data;
- ipmi_kcs_class_init(iic);
-}
-
-static const TypeInfo isa_ipmi_kcs_info = {
- .name = TYPE_ISA_IPMI_KCS,
- .parent = TYPE_ISA_DEVICE,
- .instance_size = sizeof(ISAIPMIKCSDevice),
- .instance_init = isa_ipmi_kcs_init,
- .class_init = isa_ipmi_kcs_class_init,
- .interfaces = (InterfaceInfo[]) {
- { TYPE_IPMI_INTERFACE },
- { }
- }
-};
-
-static void ipmi_register_types(void)
-{
- type_register_static(&isa_ipmi_kcs_info);
-}
-
-type_init(ipmi_register_types)
diff --git a/qemu/hw/isa/Makefile.objs b/qemu/hw/isa/Makefile.objs
deleted file mode 100644
index 9164556a4..000000000
--- a/qemu/hw/isa/Makefile.objs
+++ /dev/null
@@ -1,8 +0,0 @@
-common-obj-y += isa-bus.o
-common-obj-$(CONFIG_APM) += apm.o
-common-obj-$(CONFIG_I82378) += i82378.o
-common-obj-$(CONFIG_PC87312) += pc87312.o
-common-obj-$(CONFIG_PIIX4) += piix4.o
-common-obj-$(CONFIG_VT82C686) += vt82c686.o
-
-obj-$(CONFIG_LPC_ICH9) += lpc_ich9.o
diff --git a/qemu/hw/isa/apm.c b/qemu/hw/isa/apm.c
deleted file mode 100644
index e232b0da0..000000000
--- a/qemu/hw/isa/apm.c
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * QEMU PC APM controller Emulation
- * This is split out from acpi.c
- *
- * Copyright (c) 2006 Fabrice Bellard
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2 as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "hw/isa/apm.h"
-#include "hw/hw.h"
-#include "hw/pci/pci.h"
-
-//#define DEBUG
-
-#ifdef DEBUG
-# define APM_DPRINTF(format, ...) printf(format, ## __VA_ARGS__)
-#else
-# define APM_DPRINTF(format, ...) do { } while (0)
-#endif
-
-/* fixed I/O location */
-#define APM_CNT_IOPORT 0xb2
-#define APM_STS_IOPORT 0xb3
-
-static void apm_ioport_writeb(void *opaque, hwaddr addr, uint64_t val,
- unsigned size)
-{
- APMState *apm = opaque;
- addr &= 1;
- APM_DPRINTF("apm_ioport_writeb addr=0x%" HWADDR_PRIx
- " val=0x%02" PRIx64 "\n", addr, val);
- if (addr == 0) {
- apm->apmc = val;
-
- if (apm->callback) {
- (apm->callback)(val, apm->arg);
- }
- } else {
- apm->apms = val;
- }
-}
-
-static uint64_t apm_ioport_readb(void *opaque, hwaddr addr, unsigned size)
-{
- APMState *apm = opaque;
- uint32_t val;
-
- addr &= 1;
- if (addr == 0) {
- val = apm->apmc;
- } else {
- val = apm->apms;
- }
- APM_DPRINTF("apm_ioport_readb addr=0x%" HWADDR_PRIx " val=0x%02x\n", addr, val);
- return val;
-}
-
-const VMStateDescription vmstate_apm = {
- .name = "APM State",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(apmc, APMState),
- VMSTATE_UINT8(apms, APMState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const MemoryRegionOps apm_ops = {
- .read = apm_ioport_readb,
- .write = apm_ioport_writeb,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
-};
-
-void apm_init(PCIDevice *dev, APMState *apm, apm_ctrl_changed_t callback,
- void *arg)
-{
- apm->callback = callback;
- apm->arg = arg;
-
- /* ioport 0xb2, 0xb3 */
- memory_region_init_io(&apm->io, OBJECT(dev), &apm_ops, apm, "apm-io", 2);
- memory_region_add_subregion(pci_address_space_io(dev), APM_CNT_IOPORT,
- &apm->io);
-}
diff --git a/qemu/hw/isa/i82378.c b/qemu/hw/isa/i82378.c
deleted file mode 100644
index 4d29a9900..000000000
--- a/qemu/hw/isa/i82378.c
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * QEMU Intel i82378 emulation (PCI to ISA bridge)
- *
- * Copyright (c) 2010-2011 Hervé Poussineau
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/pci/pci.h"
-#include "hw/i386/pc.h"
-#include "hw/timer/i8254.h"
-#include "hw/audio/pcspk.h"
-
-#define TYPE_I82378 "i82378"
-#define I82378(obj) \
- OBJECT_CHECK(I82378State, (obj), TYPE_I82378)
-
-typedef struct I82378State {
- PCIDevice parent_obj;
-
- qemu_irq out[2];
- qemu_irq *i8259;
- MemoryRegion io;
-} I82378State;
-
-static const VMStateDescription vmstate_i82378 = {
- .name = "pci-i82378",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(parent_obj, I82378State),
- VMSTATE_END_OF_LIST()
- },
-};
-
-static void i82378_request_out0_irq(void *opaque, int irq, int level)
-{
- I82378State *s = opaque;
- qemu_set_irq(s->out[0], level);
-}
-
-static void i82378_request_pic_irq(void *opaque, int irq, int level)
-{
- DeviceState *dev = opaque;
- I82378State *s = I82378(dev);
-
- qemu_set_irq(s->i8259[irq], level);
-}
-
-static void i82378_realize(PCIDevice *pci, Error **errp)
-{
- DeviceState *dev = DEVICE(pci);
- I82378State *s = I82378(dev);
- uint8_t *pci_conf;
- ISABus *isabus;
- ISADevice *isa;
-
- pci_conf = pci->config;
- pci_set_word(pci_conf + PCI_COMMAND,
- PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
- pci_set_word(pci_conf + PCI_STATUS,
- PCI_STATUS_DEVSEL_MEDIUM);
-
- pci_config_set_interrupt_pin(pci_conf, 1); /* interrupt pin 0 */
-
- isabus = isa_bus_new(dev, get_system_memory(),
- pci_address_space_io(pci), errp);
- if (!isabus) {
- return;
- }
-
- /* This device has:
- 2 82C59 (irq)
- 1 82C54 (pit)
- 2 82C37 (dma)
- NMI
- Utility Bus Support Registers
-
- All devices accept byte access only, except timer
- */
-
- /* 2 82C59 (irq) */
- s->i8259 = i8259_init(isabus,
- qemu_allocate_irq(i82378_request_out0_irq, s, 0));
- isa_bus_irqs(isabus, s->i8259);
-
- /* 1 82C54 (pit) */
- isa = pit_init(isabus, 0x40, 0, NULL);
-
- /* speaker */
- pcspk_init(isabus, isa);
-
- /* 2 82C37 (dma) */
- isa = isa_create_simple(isabus, "i82374");
-
- /* timer */
- isa_create_simple(isabus, "mc146818rtc");
-}
-
-static void i82378_init(Object *obj)
-{
- DeviceState *dev = DEVICE(obj);
- I82378State *s = I82378(obj);
-
- qdev_init_gpio_out(dev, s->out, 1);
- qdev_init_gpio_in(dev, i82378_request_pic_irq, 16);
-}
-
-static void i82378_class_init(ObjectClass *klass, void *data)
-{
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- k->realize = i82378_realize;
- k->vendor_id = PCI_VENDOR_ID_INTEL;
- k->device_id = PCI_DEVICE_ID_INTEL_82378;
- k->revision = 0x03;
- k->class_id = PCI_CLASS_BRIDGE_ISA;
- dc->vmsd = &vmstate_i82378;
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
-}
-
-static const TypeInfo i82378_type_info = {
- .name = TYPE_I82378,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(I82378State),
- .instance_init = i82378_init,
- .class_init = i82378_class_init,
-};
-
-static void i82378_register_types(void)
-{
- type_register_static(&i82378_type_info);
-}
-
-type_init(i82378_register_types)
diff --git a/qemu/hw/isa/isa-bus.c b/qemu/hw/isa/isa-bus.c
deleted file mode 100644
index 7aa115caf..000000000
--- a/qemu/hw/isa/isa-bus.c
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- * isa bus support for qdev.
- *
- * Copyright (c) 2009 Gerd Hoffmann <kraxel@redhat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/hw.h"
-#include "monitor/monitor.h"
-#include "hw/sysbus.h"
-#include "sysemu/sysemu.h"
-#include "hw/isa/isa.h"
-#include "hw/i386/pc.h"
-
-static ISABus *isabus;
-
-static void isabus_dev_print(Monitor *mon, DeviceState *dev, int indent);
-static char *isabus_get_fw_dev_path(DeviceState *dev);
-
-static void isa_bus_class_init(ObjectClass *klass, void *data)
-{
- BusClass *k = BUS_CLASS(klass);
-
- k->print_dev = isabus_dev_print;
- k->get_fw_dev_path = isabus_get_fw_dev_path;
-}
-
-static const TypeInfo isa_dma_info = {
- .name = TYPE_ISADMA,
- .parent = TYPE_INTERFACE,
- .class_size = sizeof(IsaDmaClass),
-};
-
-static const TypeInfo isa_bus_info = {
- .name = TYPE_ISA_BUS,
- .parent = TYPE_BUS,
- .instance_size = sizeof(ISABus),
- .class_init = isa_bus_class_init,
-};
-
-ISABus *isa_bus_new(DeviceState *dev, MemoryRegion* address_space,
- MemoryRegion *address_space_io, Error **errp)
-{
- if (isabus) {
- error_setg(errp, "Can't create a second ISA bus");
- return NULL;
- }
- if (!dev) {
- dev = qdev_create(NULL, "isabus-bridge");
- qdev_init_nofail(dev);
- }
-
- isabus = ISA_BUS(qbus_create(TYPE_ISA_BUS, dev, NULL));
- isabus->address_space = address_space;
- isabus->address_space_io = address_space_io;
- return isabus;
-}
-
-void isa_bus_irqs(ISABus *bus, qemu_irq *irqs)
-{
- bus->irqs = irqs;
-}
-
-/*
- * isa_get_irq() returns the corresponding qemu_irq entry for the i8259.
- *
- * This function is only for special cases such as the 'ferr', and
- * temporary use for normal devices until they are converted to qdev.
- */
-qemu_irq isa_get_irq(ISADevice *dev, int isairq)
-{
- assert(!dev || ISA_BUS(qdev_get_parent_bus(DEVICE(dev))) == isabus);
- if (isairq < 0 || isairq > 15) {
- hw_error("isa irq %d invalid", isairq);
- }
- return isabus->irqs[isairq];
-}
-
-void isa_init_irq(ISADevice *dev, qemu_irq *p, int isairq)
-{
- assert(dev->nirqs < ARRAY_SIZE(dev->isairq));
- dev->isairq[dev->nirqs] = isairq;
- *p = isa_get_irq(dev, isairq);
- dev->nirqs++;
-}
-
-void isa_bus_dma(ISABus *bus, IsaDma *dma8, IsaDma *dma16)
-{
- assert(bus && dma8 && dma16);
- assert(!bus->dma[0] && !bus->dma[1]);
- bus->dma[0] = dma8;
- bus->dma[1] = dma16;
-}
-
-IsaDma *isa_get_dma(ISABus *bus, int nchan)
-{
- assert(bus);
- return bus->dma[nchan > 3 ? 1 : 0];
-}
-
-static inline void isa_init_ioport(ISADevice *dev, uint16_t ioport)
-{
- if (dev && (dev->ioport_id == 0 || ioport < dev->ioport_id)) {
- dev->ioport_id = ioport;
- }
-}
-
-void isa_register_ioport(ISADevice *dev, MemoryRegion *io, uint16_t start)
-{
- memory_region_add_subregion(isabus->address_space_io, start, io);
- isa_init_ioport(dev, start);
-}
-
-void isa_register_portio_list(ISADevice *dev, uint16_t start,
- const MemoryRegionPortio *pio_start,
- void *opaque, const char *name)
-{
- PortioList piolist;
-
- /* START is how we should treat DEV, regardless of the actual
- contents of the portio array. This is how the old code
- actually handled e.g. the FDC device. */
- isa_init_ioport(dev, start);
-
- /* FIXME: the device should store created PortioList in its state. Note
- that DEV can be NULL here and that single device can register several
- portio lists. Current implementation is leaking memory allocated
- in portio_list_init. The leak is not critical because it happens only
- at initialization time. */
- portio_list_init(&piolist, OBJECT(dev), pio_start, opaque, name);
- portio_list_add(&piolist, isabus->address_space_io, start);
-}
-
-static void isa_device_init(Object *obj)
-{
- ISADevice *dev = ISA_DEVICE(obj);
-
- dev->isairq[0] = -1;
- dev->isairq[1] = -1;
-}
-
-ISADevice *isa_create(ISABus *bus, const char *name)
-{
- DeviceState *dev;
-
- dev = qdev_create(BUS(bus), name);
- return ISA_DEVICE(dev);
-}
-
-ISADevice *isa_try_create(ISABus *bus, const char *name)
-{
- DeviceState *dev;
-
- dev = qdev_try_create(BUS(bus), name);
- return ISA_DEVICE(dev);
-}
-
-ISADevice *isa_create_simple(ISABus *bus, const char *name)
-{
- ISADevice *dev;
-
- dev = isa_create(bus, name);
- qdev_init_nofail(DEVICE(dev));
- return dev;
-}
-
-ISADevice *isa_vga_init(ISABus *bus)
-{
- switch (vga_interface_type) {
- case VGA_CIRRUS:
- return isa_create_simple(bus, "isa-cirrus-vga");
- case VGA_QXL:
- fprintf(stderr, "%s: qxl: no PCI bus\n", __func__);
- return NULL;
- case VGA_STD:
- return isa_create_simple(bus, "isa-vga");
- case VGA_VMWARE:
- fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __func__);
- return NULL;
- case VGA_VIRTIO:
- fprintf(stderr, "%s: virtio-vga: no PCI bus\n", __func__);
- return NULL;
- case VGA_NONE:
- default:
- return NULL;
- }
-}
-
-static void isabus_dev_print(Monitor *mon, DeviceState *dev, int indent)
-{
- ISADevice *d = ISA_DEVICE(dev);
-
- if (d->isairq[1] != -1) {
- monitor_printf(mon, "%*sisa irqs %d,%d\n", indent, "",
- d->isairq[0], d->isairq[1]);
- } else if (d->isairq[0] != -1) {
- monitor_printf(mon, "%*sisa irq %d\n", indent, "",
- d->isairq[0]);
- }
-}
-
-static void isabus_bridge_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->fw_name = "isa";
-}
-
-static const TypeInfo isabus_bridge_info = {
- .name = "isabus-bridge",
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(SysBusDevice),
- .class_init = isabus_bridge_class_init,
-};
-
-static void isa_device_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *k = DEVICE_CLASS(klass);
- k->bus_type = TYPE_ISA_BUS;
-}
-
-static const TypeInfo isa_device_type_info = {
- .name = TYPE_ISA_DEVICE,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(ISADevice),
- .instance_init = isa_device_init,
- .abstract = true,
- .class_size = sizeof(ISADeviceClass),
- .class_init = isa_device_class_init,
-};
-
-static void isabus_register_types(void)
-{
- type_register_static(&isa_dma_info);
- type_register_static(&isa_bus_info);
- type_register_static(&isabus_bridge_info);
- type_register_static(&isa_device_type_info);
-}
-
-static char *isabus_get_fw_dev_path(DeviceState *dev)
-{
- ISADevice *d = ISA_DEVICE(dev);
- char path[40];
- int off;
-
- off = snprintf(path, sizeof(path), "%s", qdev_fw_name(dev));
- if (d->ioport_id) {
- snprintf(path + off, sizeof(path) - off, "@%04x", d->ioport_id);
- }
-
- return g_strdup(path);
-}
-
-MemoryRegion *isa_address_space(ISADevice *dev)
-{
- if (dev) {
- return isa_bus_from_device(dev)->address_space;
- }
-
- return isabus->address_space;
-}
-
-MemoryRegion *isa_address_space_io(ISADevice *dev)
-{
- if (dev) {
- return isa_bus_from_device(dev)->address_space_io;
- }
-
- return isabus->address_space_io;
-}
-
-type_init(isabus_register_types)
-
-static void parallel_init(ISABus *bus, int index, CharDriverState *chr)
-{
- DeviceState *dev;
- ISADevice *isadev;
-
- isadev = isa_create(bus, "isa-parallel");
- dev = DEVICE(isadev);
- qdev_prop_set_uint32(dev, "index", index);
- qdev_prop_set_chr(dev, "chardev", chr);
- qdev_init_nofail(dev);
-}
-
-void parallel_hds_isa_init(ISABus *bus, int n)
-{
- int i;
-
- assert(n <= MAX_PARALLEL_PORTS);
-
- for (i = 0; i < n; i++) {
- if (parallel_hds[i]) {
- parallel_init(bus, i, parallel_hds[i]);
- }
- }
-}
diff --git a/qemu/hw/isa/lpc_ich9.c b/qemu/hw/isa/lpc_ich9.c
deleted file mode 100644
index 99cd3ba9e..000000000
--- a/qemu/hw/isa/lpc_ich9.c
+++ /dev/null
@@ -1,752 +0,0 @@
-/*
- * QEMU ICH9 Emulation
- *
- * Copyright (c) 2006 Fabrice Bellard
- * Copyright (c) 2009, 2010, 2011
- * Isaku Yamahata <yamahata at valinux co jp>
- * VA Linux Systems Japan K.K.
- * Copyright (C) 2012 Jason Baron <jbaron@redhat.com>
- *
- * This is based on piix.c, but heavily modified.
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/hw.h"
-#include "qapi/visitor.h"
-#include "qemu/range.h"
-#include "hw/isa/isa.h"
-#include "hw/sysbus.h"
-#include "hw/i386/pc.h"
-#include "hw/isa/apm.h"
-#include "hw/i386/ioapic.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/pcie_host.h"
-#include "hw/pci/pci_bridge.h"
-#include "hw/i386/ich9.h"
-#include "hw/acpi/acpi.h"
-#include "hw/acpi/ich9.h"
-#include "hw/pci/pci_bus.h"
-#include "exec/address-spaces.h"
-#include "sysemu/sysemu.h"
-
-static int ich9_lpc_sci_irq(ICH9LPCState *lpc);
-
-/*****************************************************************************/
-/* ICH9 LPC PCI to ISA bridge */
-
-static void ich9_lpc_reset(DeviceState *qdev);
-
-/* chipset configuration register
- * to access chipset configuration registers, pci_[sg]et_{byte, word, long}
- * are used.
- * Although it's not pci configuration space, it's little endian as Intel.
- */
-
-static void ich9_cc_update_ir(uint8_t irr[PCI_NUM_PINS], uint16_t ir)
-{
- int intx;
- for (intx = 0; intx < PCI_NUM_PINS; intx++) {
- irr[intx] = (ir >> (intx * ICH9_CC_DIR_SHIFT)) & ICH9_CC_DIR_MASK;
- }
-}
-
-static void ich9_cc_update(ICH9LPCState *lpc)
-{
- int slot;
- int pci_intx;
-
- const int reg_offsets[] = {
- ICH9_CC_D25IR,
- ICH9_CC_D26IR,
- ICH9_CC_D27IR,
- ICH9_CC_D28IR,
- ICH9_CC_D29IR,
- ICH9_CC_D30IR,
- ICH9_CC_D31IR,
- };
- const int *offset;
-
- /* D{25 - 31}IR, but D30IR is read only to 0. */
- for (slot = 25, offset = reg_offsets; slot < 32; slot++, offset++) {
- if (slot == 30) {
- continue;
- }
- ich9_cc_update_ir(lpc->irr[slot],
- pci_get_word(lpc->chip_config + *offset));
- }
-
- /*
- * D30: DMI2PCI bridge
- * It is arbitrarily decided how INTx lines of PCI devicesbehind the bridge
- * are connected to pirq lines. Our choice is PIRQ[E-H].
- * INT[A-D] are connected to PIRQ[E-H]
- */
- for (pci_intx = 0; pci_intx < PCI_NUM_PINS; pci_intx++) {
- lpc->irr[30][pci_intx] = pci_intx + 4;
- }
-}
-
-static void ich9_cc_init(ICH9LPCState *lpc)
-{
- int slot;
- int intx;
-
- /* the default irq routing is arbitrary as long as it matches with
- * acpi irq routing table.
- * The one that is incompatible with piix_pci(= bochs) one is
- * intentionally chosen to let the users know that the different
- * board is used.
- *
- * int[A-D] -> pirq[E-F]
- * avoid pirq A-D because they are used for pci express port
- */
- for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
- for (intx = 0; intx < PCI_NUM_PINS; intx++) {
- lpc->irr[slot][intx] = (slot + intx) % 4 + 4;
- }
- }
- ich9_cc_update(lpc);
-}
-
-static void ich9_cc_reset(ICH9LPCState *lpc)
-{
- uint8_t *c = lpc->chip_config;
-
- memset(lpc->chip_config, 0, sizeof(lpc->chip_config));
-
- pci_set_long(c + ICH9_CC_D31IR, ICH9_CC_DIR_DEFAULT);
- pci_set_long(c + ICH9_CC_D30IR, ICH9_CC_D30IR_DEFAULT);
- pci_set_long(c + ICH9_CC_D29IR, ICH9_CC_DIR_DEFAULT);
- pci_set_long(c + ICH9_CC_D28IR, ICH9_CC_DIR_DEFAULT);
- pci_set_long(c + ICH9_CC_D27IR, ICH9_CC_DIR_DEFAULT);
- pci_set_long(c + ICH9_CC_D26IR, ICH9_CC_DIR_DEFAULT);
- pci_set_long(c + ICH9_CC_D25IR, ICH9_CC_DIR_DEFAULT);
- pci_set_long(c + ICH9_CC_GCS, ICH9_CC_GCS_DEFAULT);
-
- ich9_cc_update(lpc);
-}
-
-static void ich9_cc_addr_len(uint64_t *addr, unsigned *len)
-{
- *addr &= ICH9_CC_ADDR_MASK;
- if (*addr + *len >= ICH9_CC_SIZE) {
- *len = ICH9_CC_SIZE - *addr;
- }
-}
-
-/* val: little endian */
-static void ich9_cc_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned len)
-{
- ICH9LPCState *lpc = (ICH9LPCState *)opaque;
-
- ich9_cc_addr_len(&addr, &len);
- memcpy(lpc->chip_config + addr, &val, len);
- pci_bus_fire_intx_routing_notifier(lpc->d.bus);
- ich9_cc_update(lpc);
-}
-
-/* return value: little endian */
-static uint64_t ich9_cc_read(void *opaque, hwaddr addr,
- unsigned len)
-{
- ICH9LPCState *lpc = (ICH9LPCState *)opaque;
-
- uint32_t val = 0;
- ich9_cc_addr_len(&addr, &len);
- memcpy(&val, lpc->chip_config + addr, len);
- return val;
-}
-
-/* IRQ routing */
-/* */
-static void ich9_lpc_rout(uint8_t pirq_rout, int *pic_irq, int *pic_dis)
-{
- *pic_irq = pirq_rout & ICH9_LPC_PIRQ_ROUT_MASK;
- *pic_dis = pirq_rout & ICH9_LPC_PIRQ_ROUT_IRQEN;
-}
-
-static void ich9_lpc_pic_irq(ICH9LPCState *lpc, int pirq_num,
- int *pic_irq, int *pic_dis)
-{
- switch (pirq_num) {
- case 0 ... 3: /* A-D */
- ich9_lpc_rout(lpc->d.config[ICH9_LPC_PIRQA_ROUT + pirq_num],
- pic_irq, pic_dis);
- return;
- case 4 ... 7: /* E-H */
- ich9_lpc_rout(lpc->d.config[ICH9_LPC_PIRQE_ROUT + (pirq_num - 4)],
- pic_irq, pic_dis);
- return;
- default:
- break;
- }
- abort();
-}
-
-/* pic_irq: i8254 irq 0-15 */
-static void ich9_lpc_update_pic(ICH9LPCState *lpc, int pic_irq)
-{
- int i, pic_level;
-
- /* The pic level is the logical OR of all the PCI irqs mapped to it */
- pic_level = 0;
- for (i = 0; i < ICH9_LPC_NB_PIRQS; i++) {
- int tmp_irq;
- int tmp_dis;
- ich9_lpc_pic_irq(lpc, i, &tmp_irq, &tmp_dis);
- if (!tmp_dis && pic_irq == tmp_irq) {
- pic_level |= pci_bus_get_irq_level(lpc->d.bus, i);
- }
- }
- if (pic_irq == ich9_lpc_sci_irq(lpc)) {
- pic_level |= lpc->sci_level;
- }
-
- qemu_set_irq(lpc->pic[pic_irq], pic_level);
-}
-
-/* pirq: pirq[A-H] 0-7*/
-static void ich9_lpc_update_by_pirq(ICH9LPCState *lpc, int pirq)
-{
- int pic_irq;
- int pic_dis;
-
- ich9_lpc_pic_irq(lpc, pirq, &pic_irq, &pic_dis);
- assert(pic_irq < ICH9_LPC_PIC_NUM_PINS);
- if (pic_dis) {
- return;
- }
-
- ich9_lpc_update_pic(lpc, pic_irq);
-}
-
-/* APIC mode: GSIx: PIRQ[A-H] -> GSI 16, ... no pirq shares same APIC pins. */
-static int ich9_pirq_to_gsi(int pirq)
-{
- return pirq + ICH9_LPC_PIC_NUM_PINS;
-}
-
-static int ich9_gsi_to_pirq(int gsi)
-{
- return gsi - ICH9_LPC_PIC_NUM_PINS;
-}
-
-static void ich9_lpc_update_apic(ICH9LPCState *lpc, int gsi)
-{
- int level = 0;
-
- if (gsi >= ICH9_LPC_PIC_NUM_PINS) {
- level |= pci_bus_get_irq_level(lpc->d.bus, ich9_gsi_to_pirq(gsi));
- }
- if (gsi == ich9_lpc_sci_irq(lpc)) {
- level |= lpc->sci_level;
- }
-
- qemu_set_irq(lpc->ioapic[gsi], level);
-}
-
-void ich9_lpc_set_irq(void *opaque, int pirq, int level)
-{
- ICH9LPCState *lpc = opaque;
-
- assert(0 <= pirq);
- assert(pirq < ICH9_LPC_NB_PIRQS);
-
- ich9_lpc_update_apic(lpc, ich9_pirq_to_gsi(pirq));
- ich9_lpc_update_by_pirq(lpc, pirq);
-}
-
-/* return the pirq number (PIRQ[A-H]:0-7) corresponding to
- * a given device irq pin.
- */
-int ich9_lpc_map_irq(PCIDevice *pci_dev, int intx)
-{
- BusState *bus = qdev_get_parent_bus(&pci_dev->qdev);
- PCIBus *pci_bus = PCI_BUS(bus);
- PCIDevice *lpc_pdev =
- pci_bus->devices[PCI_DEVFN(ICH9_LPC_DEV, ICH9_LPC_FUNC)];
- ICH9LPCState *lpc = ICH9_LPC_DEVICE(lpc_pdev);
-
- return lpc->irr[PCI_SLOT(pci_dev->devfn)][intx];
-}
-
-PCIINTxRoute ich9_route_intx_pin_to_irq(void *opaque, int pirq_pin)
-{
- ICH9LPCState *lpc = opaque;
- PCIINTxRoute route;
- int pic_irq;
- int pic_dis;
-
- assert(0 <= pirq_pin);
- assert(pirq_pin < ICH9_LPC_NB_PIRQS);
-
- route.mode = PCI_INTX_ENABLED;
- ich9_lpc_pic_irq(lpc, pirq_pin, &pic_irq, &pic_dis);
- if (!pic_dis) {
- if (pic_irq < ICH9_LPC_PIC_NUM_PINS) {
- route.irq = pic_irq;
- } else {
- route.mode = PCI_INTX_DISABLED;
- route.irq = -1;
- }
- } else {
- route.irq = ich9_pirq_to_gsi(pirq_pin);
- }
-
- return route;
-}
-
-void ich9_generate_smi(void)
-{
- cpu_interrupt(first_cpu, CPU_INTERRUPT_SMI);
-}
-
-void ich9_generate_nmi(void)
-{
- cpu_interrupt(first_cpu, CPU_INTERRUPT_NMI);
-}
-
-static int ich9_lpc_sci_irq(ICH9LPCState *lpc)
-{
- switch (lpc->d.config[ICH9_LPC_ACPI_CTRL] &
- ICH9_LPC_ACPI_CTRL_SCI_IRQ_SEL_MASK) {
- case ICH9_LPC_ACPI_CTRL_9:
- return 9;
- case ICH9_LPC_ACPI_CTRL_10:
- return 10;
- case ICH9_LPC_ACPI_CTRL_11:
- return 11;
- case ICH9_LPC_ACPI_CTRL_20:
- return 20;
- case ICH9_LPC_ACPI_CTRL_21:
- return 21;
- default:
- /* reserved */
- break;
- }
- return -1;
-}
-
-static void ich9_set_sci(void *opaque, int irq_num, int level)
-{
- ICH9LPCState *lpc = opaque;
- int irq;
-
- assert(irq_num == 0);
- level = !!level;
- if (level == lpc->sci_level) {
- return;
- }
- lpc->sci_level = level;
-
- irq = ich9_lpc_sci_irq(lpc);
- if (irq < 0) {
- return;
- }
-
- ich9_lpc_update_apic(lpc, irq);
- if (irq < ICH9_LPC_PIC_NUM_PINS) {
- ich9_lpc_update_pic(lpc, irq);
- }
-}
-
-void ich9_lpc_pm_init(PCIDevice *lpc_pci, bool smm_enabled)
-{
- ICH9LPCState *lpc = ICH9_LPC_DEVICE(lpc_pci);
- qemu_irq sci_irq;
-
- sci_irq = qemu_allocate_irq(ich9_set_sci, lpc, 0);
- ich9_pm_init(lpc_pci, &lpc->pm, smm_enabled, sci_irq);
- ich9_lpc_reset(&lpc->d.qdev);
-}
-
-/* APM */
-
-static void ich9_apm_ctrl_changed(uint32_t val, void *arg)
-{
- ICH9LPCState *lpc = arg;
-
- /* ACPI specs 3.0, 4.7.2.5 */
- acpi_pm1_cnt_update(&lpc->pm.acpi_regs,
- val == ICH9_APM_ACPI_ENABLE,
- val == ICH9_APM_ACPI_DISABLE);
- if (val == ICH9_APM_ACPI_ENABLE || val == ICH9_APM_ACPI_DISABLE) {
- return;
- }
-
- /* SMI_EN = PMBASE + 30. SMI control and enable register */
- if (lpc->pm.smi_en & ICH9_PMIO_SMI_EN_APMC_EN) {
- cpu_interrupt(current_cpu, CPU_INTERRUPT_SMI);
- }
-}
-
-/* config:PMBASE */
-static void
-ich9_lpc_pmbase_update(ICH9LPCState *lpc)
-{
- uint32_t pm_io_base = pci_get_long(lpc->d.config + ICH9_LPC_PMBASE);
- pm_io_base &= ICH9_LPC_PMBASE_BASE_ADDRESS_MASK;
-
- ich9_pm_iospace_update(&lpc->pm, pm_io_base);
-}
-
-/* config:RCBA */
-static void ich9_lpc_rcba_update(ICH9LPCState *lpc, uint32_t rcba_old)
-{
- uint32_t rcba = pci_get_long(lpc->d.config + ICH9_LPC_RCBA);
-
- if (rcba_old & ICH9_LPC_RCBA_EN) {
- memory_region_del_subregion(get_system_memory(), &lpc->rcrb_mem);
- }
- if (rcba & ICH9_LPC_RCBA_EN) {
- memory_region_add_subregion_overlap(get_system_memory(),
- rcba & ICH9_LPC_RCBA_BA_MASK,
- &lpc->rcrb_mem, 1);
- }
-}
-
-/* config:GEN_PMCON* */
-static void
-ich9_lpc_pmcon_update(ICH9LPCState *lpc)
-{
- uint16_t gen_pmcon_1 = pci_get_word(lpc->d.config + ICH9_LPC_GEN_PMCON_1);
- uint16_t wmask;
-
- if (gen_pmcon_1 & ICH9_LPC_GEN_PMCON_1_SMI_LOCK) {
- wmask = pci_get_word(lpc->d.wmask + ICH9_LPC_GEN_PMCON_1);
- wmask &= ~ICH9_LPC_GEN_PMCON_1_SMI_LOCK;
- pci_set_word(lpc->d.wmask + ICH9_LPC_GEN_PMCON_1, wmask);
- lpc->pm.smi_en_wmask &= ~1;
- }
-}
-
-static int ich9_lpc_post_load(void *opaque, int version_id)
-{
- ICH9LPCState *lpc = opaque;
-
- ich9_lpc_pmbase_update(lpc);
- ich9_lpc_rcba_update(lpc, 0 /* disabled ICH9_LPC_RCBA_EN */);
- ich9_lpc_pmcon_update(lpc);
- return 0;
-}
-
-static void ich9_lpc_config_write(PCIDevice *d,
- uint32_t addr, uint32_t val, int len)
-{
- ICH9LPCState *lpc = ICH9_LPC_DEVICE(d);
- uint32_t rcba_old = pci_get_long(d->config + ICH9_LPC_RCBA);
-
- pci_default_write_config(d, addr, val, len);
- if (ranges_overlap(addr, len, ICH9_LPC_PMBASE, 4)) {
- ich9_lpc_pmbase_update(lpc);
- }
- if (ranges_overlap(addr, len, ICH9_LPC_RCBA, 4)) {
- ich9_lpc_rcba_update(lpc, rcba_old);
- }
- if (ranges_overlap(addr, len, ICH9_LPC_PIRQA_ROUT, 4)) {
- pci_bus_fire_intx_routing_notifier(lpc->d.bus);
- }
- if (ranges_overlap(addr, len, ICH9_LPC_PIRQE_ROUT, 4)) {
- pci_bus_fire_intx_routing_notifier(lpc->d.bus);
- }
- if (ranges_overlap(addr, len, ICH9_LPC_GEN_PMCON_1, 8)) {
- ich9_lpc_pmcon_update(lpc);
- }
-}
-
-static void ich9_lpc_reset(DeviceState *qdev)
-{
- PCIDevice *d = PCI_DEVICE(qdev);
- ICH9LPCState *lpc = ICH9_LPC_DEVICE(d);
- uint32_t rcba_old = pci_get_long(d->config + ICH9_LPC_RCBA);
- int i;
-
- for (i = 0; i < 4; i++) {
- pci_set_byte(d->config + ICH9_LPC_PIRQA_ROUT + i,
- ICH9_LPC_PIRQ_ROUT_DEFAULT);
- }
- for (i = 0; i < 4; i++) {
- pci_set_byte(d->config + ICH9_LPC_PIRQE_ROUT + i,
- ICH9_LPC_PIRQ_ROUT_DEFAULT);
- }
- pci_set_byte(d->config + ICH9_LPC_ACPI_CTRL, ICH9_LPC_ACPI_CTRL_DEFAULT);
-
- pci_set_long(d->config + ICH9_LPC_PMBASE, ICH9_LPC_PMBASE_DEFAULT);
- pci_set_long(d->config + ICH9_LPC_RCBA, ICH9_LPC_RCBA_DEFAULT);
-
- ich9_cc_reset(lpc);
-
- ich9_lpc_pmbase_update(lpc);
- ich9_lpc_rcba_update(lpc, rcba_old);
-
- lpc->sci_level = 0;
- lpc->rst_cnt = 0;
-}
-
-/* root complex register block is mapped into memory space */
-static const MemoryRegionOps rcrb_mmio_ops = {
- .read = ich9_cc_read,
- .write = ich9_cc_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void ich9_lpc_machine_ready(Notifier *n, void *opaque)
-{
- ICH9LPCState *s = container_of(n, ICH9LPCState, machine_ready);
- MemoryRegion *io_as = pci_address_space_io(&s->d);
- uint8_t *pci_conf;
-
- pci_conf = s->d.config;
- if (memory_region_present(io_as, 0x3f8)) {
- /* com1 */
- pci_conf[0x82] |= 0x01;
- }
- if (memory_region_present(io_as, 0x2f8)) {
- /* com2 */
- pci_conf[0x82] |= 0x02;
- }
- if (memory_region_present(io_as, 0x378)) {
- /* lpt */
- pci_conf[0x82] |= 0x04;
- }
- if (memory_region_present(io_as, 0x3f2)) {
- /* floppy */
- pci_conf[0x82] |= 0x08;
- }
-}
-
-/* reset control */
-static void ich9_rst_cnt_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned len)
-{
- ICH9LPCState *lpc = opaque;
-
- if (val & 4) {
- qemu_system_reset_request();
- return;
- }
- lpc->rst_cnt = val & 0xA; /* keep FULL_RST (bit 3) and SYS_RST (bit 1) */
-}
-
-static uint64_t ich9_rst_cnt_read(void *opaque, hwaddr addr, unsigned len)
-{
- ICH9LPCState *lpc = opaque;
-
- return lpc->rst_cnt;
-}
-
-static const MemoryRegionOps ich9_rst_cnt_ops = {
- .read = ich9_rst_cnt_read,
- .write = ich9_rst_cnt_write,
- .endianness = DEVICE_LITTLE_ENDIAN
-};
-
-Object *ich9_lpc_find(void)
-{
- bool ambig;
- Object *o = object_resolve_path_type("", TYPE_ICH9_LPC_DEVICE, &ambig);
-
- if (ambig) {
- return NULL;
- }
- return o;
-}
-
-static void ich9_lpc_get_sci_int(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- ICH9LPCState *lpc = ICH9_LPC_DEVICE(obj);
- uint32_t value = ich9_lpc_sci_irq(lpc);
-
- visit_type_uint32(v, name, &value, errp);
-}
-
-static void ich9_lpc_add_properties(ICH9LPCState *lpc)
-{
- static const uint8_t acpi_enable_cmd = ICH9_APM_ACPI_ENABLE;
- static const uint8_t acpi_disable_cmd = ICH9_APM_ACPI_DISABLE;
-
- object_property_add(OBJECT(lpc), ACPI_PM_PROP_SCI_INT, "uint32",
- ich9_lpc_get_sci_int,
- NULL, NULL, NULL, NULL);
- object_property_add_uint8_ptr(OBJECT(lpc), ACPI_PM_PROP_ACPI_ENABLE_CMD,
- &acpi_enable_cmd, NULL);
- object_property_add_uint8_ptr(OBJECT(lpc), ACPI_PM_PROP_ACPI_DISABLE_CMD,
- &acpi_disable_cmd, NULL);
-
- ich9_pm_add_properties(OBJECT(lpc), &lpc->pm, NULL);
-}
-
-static void ich9_lpc_initfn(Object *obj)
-{
- ICH9LPCState *lpc = ICH9_LPC_DEVICE(obj);
-
- ich9_lpc_add_properties(lpc);
-}
-
-static void ich9_lpc_realize(PCIDevice *d, Error **errp)
-{
- ICH9LPCState *lpc = ICH9_LPC_DEVICE(d);
- ISABus *isa_bus;
-
- isa_bus = isa_bus_new(DEVICE(d), get_system_memory(), get_system_io(),
- errp);
- if (!isa_bus) {
- return;
- }
-
- pci_set_long(d->wmask + ICH9_LPC_PMBASE,
- ICH9_LPC_PMBASE_BASE_ADDRESS_MASK);
-
- memory_region_init_io(&lpc->rcrb_mem, OBJECT(d), &rcrb_mmio_ops, lpc,
- "lpc-rcrb-mmio", ICH9_CC_SIZE);
-
- lpc->isa_bus = isa_bus;
-
- ich9_cc_init(lpc);
- apm_init(d, &lpc->apm, ich9_apm_ctrl_changed, lpc);
-
- lpc->machine_ready.notify = ich9_lpc_machine_ready;
- qemu_add_machine_init_done_notifier(&lpc->machine_ready);
-
- memory_region_init_io(&lpc->rst_cnt_mem, OBJECT(d), &ich9_rst_cnt_ops, lpc,
- "lpc-reset-control", 1);
- memory_region_add_subregion_overlap(pci_address_space_io(d),
- ICH9_RST_CNT_IOPORT, &lpc->rst_cnt_mem,
- 1);
-}
-
-static void ich9_device_plug_cb(HotplugHandler *hotplug_dev,
- DeviceState *dev, Error **errp)
-{
- ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev);
-
- ich9_pm_device_plug_cb(&lpc->pm, dev, errp);
-}
-
-static void ich9_device_unplug_request_cb(HotplugHandler *hotplug_dev,
- DeviceState *dev, Error **errp)
-{
- ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev);
-
- ich9_pm_device_unplug_request_cb(&lpc->pm, dev, errp);
-}
-
-static void ich9_device_unplug_cb(HotplugHandler *hotplug_dev,
- DeviceState *dev, Error **errp)
-{
- ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev);
-
- ich9_pm_device_unplug_cb(&lpc->pm, dev, errp);
-}
-
-static bool ich9_rst_cnt_needed(void *opaque)
-{
- ICH9LPCState *lpc = opaque;
-
- return (lpc->rst_cnt != 0);
-}
-
-static const VMStateDescription vmstate_ich9_rst_cnt = {
- .name = "ICH9LPC/rst_cnt",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = ich9_rst_cnt_needed,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(rst_cnt, ICH9LPCState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_ich9_lpc = {
- .name = "ICH9LPC",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = ich9_lpc_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(d, ICH9LPCState),
- VMSTATE_STRUCT(apm, ICH9LPCState, 0, vmstate_apm, APMState),
- VMSTATE_STRUCT(pm, ICH9LPCState, 0, vmstate_ich9_pm, ICH9LPCPMRegs),
- VMSTATE_UINT8_ARRAY(chip_config, ICH9LPCState, ICH9_CC_SIZE),
- VMSTATE_UINT32(sci_level, ICH9LPCState),
- VMSTATE_END_OF_LIST()
- },
- .subsections = (const VMStateDescription*[]) {
- &vmstate_ich9_rst_cnt,
- NULL
- }
-};
-
-static Property ich9_lpc_properties[] = {
- DEFINE_PROP_BOOL("noreboot", ICH9LPCState, pin_strap.spkr_hi, true),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void ich9_lpc_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
- AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_CLASS(klass);
-
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
- dc->reset = ich9_lpc_reset;
- k->realize = ich9_lpc_realize;
- dc->vmsd = &vmstate_ich9_lpc;
- dc->props = ich9_lpc_properties;
- k->config_write = ich9_lpc_config_write;
- dc->desc = "ICH9 LPC bridge";
- k->vendor_id = PCI_VENDOR_ID_INTEL;
- k->device_id = PCI_DEVICE_ID_INTEL_ICH9_8;
- k->revision = ICH9_A2_LPC_REVISION;
- k->class_id = PCI_CLASS_BRIDGE_ISA;
- /*
- * Reason: part of ICH9 southbridge, needs to be wired up by
- * pc_q35_init()
- */
- dc->cannot_instantiate_with_device_add_yet = true;
- hc->plug = ich9_device_plug_cb;
- hc->unplug_request = ich9_device_unplug_request_cb;
- hc->unplug = ich9_device_unplug_cb;
- adevc->ospm_status = ich9_pm_ospm_status;
-}
-
-static const TypeInfo ich9_lpc_info = {
- .name = TYPE_ICH9_LPC_DEVICE,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(struct ICH9LPCState),
- .instance_init = ich9_lpc_initfn,
- .class_init = ich9_lpc_class_init,
- .interfaces = (InterfaceInfo[]) {
- { TYPE_HOTPLUG_HANDLER },
- { TYPE_ACPI_DEVICE_IF },
- { }
- }
-};
-
-static void ich9_lpc_register(void)
-{
- type_register_static(&ich9_lpc_info);
-}
-
-type_init(ich9_lpc_register);
diff --git a/qemu/hw/isa/pc87312.c b/qemu/hw/isa/pc87312.c
deleted file mode 100644
index c3ebf3e7a..000000000
--- a/qemu/hw/isa/pc87312.c
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- * QEMU National Semiconductor PC87312 (Super I/O)
- *
- * Copyright (c) 2010-2012 Herve Poussineau
- * Copyright (c) 2011-2012 Andreas Färber
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/isa/pc87312.h"
-#include "qapi/error.h"
-#include "qemu/error-report.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/char.h"
-#include "trace.h"
-
-
-#define REG_FER 0
-#define REG_FAR 1
-#define REG_PTR 2
-
-#define FER_PARALLEL_EN 0x01
-#define FER_UART1_EN 0x02
-#define FER_UART2_EN 0x04
-#define FER_FDC_EN 0x08
-#define FER_FDC_4 0x10
-#define FER_FDC_ADDR 0x20
-#define FER_IDE_EN 0x40
-#define FER_IDE_ADDR 0x80
-
-#define FAR_PARALLEL_ADDR 0x03
-#define FAR_UART1_ADDR 0x0C
-#define FAR_UART2_ADDR 0x30
-#define FAR_UART_3_4 0xC0
-
-#define PTR_POWER_DOWN 0x01
-#define PTR_CLOCK_DOWN 0x02
-#define PTR_PWDN 0x04
-#define PTR_IRQ_5_7 0x08
-#define PTR_UART1_TEST 0x10
-#define PTR_UART2_TEST 0x20
-#define PTR_LOCK_CONF 0x40
-#define PTR_EPP_MODE 0x80
-
-
-/* Parallel port */
-
-static inline bool is_parallel_enabled(PC87312State *s)
-{
- return s->regs[REG_FER] & FER_PARALLEL_EN;
-}
-
-static const uint32_t parallel_base[] = { 0x378, 0x3bc, 0x278, 0x00 };
-
-static inline uint32_t get_parallel_iobase(PC87312State *s)
-{
- return parallel_base[s->regs[REG_FAR] & FAR_PARALLEL_ADDR];
-}
-
-static const uint32_t parallel_irq[] = { 5, 7, 5, 0 };
-
-static inline uint32_t get_parallel_irq(PC87312State *s)
-{
- int idx;
- idx = (s->regs[REG_FAR] & FAR_PARALLEL_ADDR);
- if (idx == 0) {
- return (s->regs[REG_PTR] & PTR_IRQ_5_7) ? 7 : 5;
- } else {
- return parallel_irq[idx];
- }
-}
-
-
-/* UARTs */
-
-static const uint32_t uart_base[2][4] = {
- { 0x3e8, 0x338, 0x2e8, 0x220 },
- { 0x2e8, 0x238, 0x2e0, 0x228 }
-};
-
-static inline uint32_t get_uart_iobase(PC87312State *s, int i)
-{
- int idx;
- idx = (s->regs[REG_FAR] >> (2 * i + 2)) & 0x3;
- if (idx == 0) {
- return 0x3f8;
- } else if (idx == 1) {
- return 0x2f8;
- } else {
- return uart_base[idx & 1][(s->regs[REG_FAR] & FAR_UART_3_4) >> 6];
- }
-}
-
-static inline uint32_t get_uart_irq(PC87312State *s, int i)
-{
- int idx;
- idx = (s->regs[REG_FAR] >> (2 * i + 2)) & 0x3;
- return (idx & 1) ? 3 : 4;
-}
-
-static inline bool is_uart_enabled(PC87312State *s, int i)
-{
- return s->regs[REG_FER] & (FER_UART1_EN << i);
-}
-
-
-/* Floppy controller */
-
-static inline bool is_fdc_enabled(PC87312State *s)
-{
- return s->regs[REG_FER] & FER_FDC_EN;
-}
-
-static inline uint32_t get_fdc_iobase(PC87312State *s)
-{
- return (s->regs[REG_FER] & FER_FDC_ADDR) ? 0x370 : 0x3f0;
-}
-
-
-/* IDE controller */
-
-static inline bool is_ide_enabled(PC87312State *s)
-{
- return s->regs[REG_FER] & FER_IDE_EN;
-}
-
-static inline uint32_t get_ide_iobase(PC87312State *s)
-{
- return (s->regs[REG_FER] & FER_IDE_ADDR) ? 0x170 : 0x1f0;
-}
-
-
-static void reconfigure_devices(PC87312State *s)
-{
- error_report("pc87312: unsupported device reconfiguration (%02x %02x %02x)",
- s->regs[REG_FER], s->regs[REG_FAR], s->regs[REG_PTR]);
-}
-
-static void pc87312_soft_reset(PC87312State *s)
-{
- static const uint8_t fer_init[] = {
- 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4b, 0x4b,
- 0x4b, 0x4b, 0x4b, 0x4b, 0x0f, 0x0f, 0x0f, 0x0f,
- 0x49, 0x49, 0x49, 0x49, 0x07, 0x07, 0x07, 0x07,
- 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x08, 0x00,
- };
- static const uint8_t far_init[] = {
- 0x10, 0x11, 0x11, 0x39, 0x24, 0x38, 0x00, 0x01,
- 0x01, 0x09, 0x08, 0x08, 0x10, 0x11, 0x39, 0x24,
- 0x00, 0x01, 0x01, 0x00, 0x10, 0x11, 0x39, 0x24,
- 0x10, 0x11, 0x11, 0x39, 0x24, 0x38, 0x10, 0x10,
- };
- static const uint8_t ptr_init[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
- };
-
- s->read_id_step = 0;
- s->selected_index = REG_FER;
-
- s->regs[REG_FER] = fer_init[s->config & 0x1f];
- s->regs[REG_FAR] = far_init[s->config & 0x1f];
- s->regs[REG_PTR] = ptr_init[s->config & 0x1f];
-}
-
-static void pc87312_hard_reset(PC87312State *s)
-{
- pc87312_soft_reset(s);
-}
-
-static void pc87312_io_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned int size)
-{
- PC87312State *s = opaque;
-
- trace_pc87312_io_write(addr, val);
-
- if ((addr & 1) == 0) {
- /* Index register */
- s->read_id_step = 2;
- s->selected_index = val;
- } else {
- /* Data register */
- if (s->selected_index < 3) {
- s->regs[s->selected_index] = val;
- reconfigure_devices(s);
- }
- }
-}
-
-static uint64_t pc87312_io_read(void *opaque, hwaddr addr, unsigned int size)
-{
- PC87312State *s = opaque;
- uint32_t val;
-
- if ((addr & 1) == 0) {
- /* Index register */
- if (s->read_id_step++ == 0) {
- val = 0x88;
- } else if (s->read_id_step++ == 1) {
- val = 0;
- } else {
- val = s->selected_index;
- }
- } else {
- /* Data register */
- if (s->selected_index < 3) {
- val = s->regs[s->selected_index];
- } else {
- /* Invalid selected index */
- val = 0;
- }
- }
-
- trace_pc87312_io_read(addr, val);
- return val;
-}
-
-static const MemoryRegionOps pc87312_io_ops = {
- .read = pc87312_io_read,
- .write = pc87312_io_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .valid = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
-};
-
-static int pc87312_post_load(void *opaque, int version_id)
-{
- PC87312State *s = opaque;
-
- reconfigure_devices(s);
- return 0;
-}
-
-static void pc87312_reset(DeviceState *d)
-{
- PC87312State *s = PC87312(d);
-
- pc87312_soft_reset(s);
-}
-
-static void pc87312_realize(DeviceState *dev, Error **errp)
-{
- PC87312State *s;
- DeviceState *d;
- ISADevice *isa;
- ISABus *bus;
- CharDriverState *chr;
- DriveInfo *drive;
- char name[5];
- int i;
-
- s = PC87312(dev);
- isa = ISA_DEVICE(dev);
- bus = isa_bus_from_device(isa);
- isa_register_ioport(isa, &s->io, s->iobase);
- pc87312_hard_reset(s);
-
- if (is_parallel_enabled(s)) {
- /* FIXME use a qdev chardev prop instead of parallel_hds[] */
- chr = parallel_hds[0];
- if (chr == NULL) {
- chr = qemu_chr_new("par0", "null", NULL);
- }
- isa = isa_create(bus, "isa-parallel");
- d = DEVICE(isa);
- qdev_prop_set_uint32(d, "index", 0);
- qdev_prop_set_uint32(d, "iobase", get_parallel_iobase(s));
- qdev_prop_set_uint32(d, "irq", get_parallel_irq(s));
- qdev_prop_set_chr(d, "chardev", chr);
- qdev_init_nofail(d);
- s->parallel.dev = isa;
- trace_pc87312_info_parallel(get_parallel_iobase(s),
- get_parallel_irq(s));
- }
-
- for (i = 0; i < 2; i++) {
- if (is_uart_enabled(s, i)) {
- /* FIXME use a qdev chardev prop instead of serial_hds[] */
- chr = serial_hds[i];
- if (chr == NULL) {
- snprintf(name, sizeof(name), "ser%d", i);
- chr = qemu_chr_new(name, "null", NULL);
- }
- isa = isa_create(bus, "isa-serial");
- d = DEVICE(isa);
- qdev_prop_set_uint32(d, "index", i);
- qdev_prop_set_uint32(d, "iobase", get_uart_iobase(s, i));
- qdev_prop_set_uint32(d, "irq", get_uart_irq(s, i));
- qdev_prop_set_chr(d, "chardev", chr);
- qdev_init_nofail(d);
- s->uart[i].dev = isa;
- trace_pc87312_info_serial(i, get_uart_iobase(s, i),
- get_uart_irq(s, i));
- }
- }
-
- if (is_fdc_enabled(s)) {
- isa = isa_create(bus, "isa-fdc");
- d = DEVICE(isa);
- qdev_prop_set_uint32(d, "iobase", get_fdc_iobase(s));
- qdev_prop_set_uint32(d, "irq", 6);
- /* FIXME use a qdev drive property instead of drive_get() */
- drive = drive_get(IF_FLOPPY, 0, 0);
- if (drive != NULL) {
- qdev_prop_set_drive(d, "driveA", blk_by_legacy_dinfo(drive),
- &error_fatal);
- }
- /* FIXME use a qdev drive property instead of drive_get() */
- drive = drive_get(IF_FLOPPY, 0, 1);
- if (drive != NULL) {
- qdev_prop_set_drive(d, "driveB", blk_by_legacy_dinfo(drive),
- &error_fatal);
- }
- qdev_init_nofail(d);
- s->fdc.dev = isa;
- trace_pc87312_info_floppy(get_fdc_iobase(s));
- }
-
- if (is_ide_enabled(s)) {
- isa = isa_create(bus, "isa-ide");
- d = DEVICE(isa);
- qdev_prop_set_uint32(d, "iobase", get_ide_iobase(s));
- qdev_prop_set_uint32(d, "iobase2", get_ide_iobase(s) + 0x206);
- qdev_prop_set_uint32(d, "irq", 14);
- qdev_init_nofail(d);
- s->ide.dev = isa;
- trace_pc87312_info_ide(get_ide_iobase(s));
- }
-}
-
-static void pc87312_initfn(Object *obj)
-{
- PC87312State *s = PC87312(obj);
-
- memory_region_init_io(&s->io, obj, &pc87312_io_ops, s, "pc87312", 2);
-}
-
-static const VMStateDescription vmstate_pc87312 = {
- .name = "pc87312",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = pc87312_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(read_id_step, PC87312State),
- VMSTATE_UINT8(selected_index, PC87312State),
- VMSTATE_UINT8_ARRAY(regs, PC87312State, 3),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property pc87312_properties[] = {
- DEFINE_PROP_UINT32("iobase", PC87312State, iobase, 0x398),
- DEFINE_PROP_UINT8("config", PC87312State, config, 1),
- DEFINE_PROP_END_OF_LIST()
-};
-
-static void pc87312_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = pc87312_realize;
- dc->reset = pc87312_reset;
- dc->vmsd = &vmstate_pc87312;
- dc->props = pc87312_properties;
-}
-
-static const TypeInfo pc87312_type_info = {
- .name = TYPE_PC87312,
- .parent = TYPE_ISA_DEVICE,
- .instance_size = sizeof(PC87312State),
- .instance_init = pc87312_initfn,
- .class_init = pc87312_class_init,
-};
-
-static void pc87312_register_types(void)
-{
- type_register_static(&pc87312_type_info);
-}
-
-type_init(pc87312_register_types)
diff --git a/qemu/hw/isa/piix4.c b/qemu/hw/isa/piix4.c
deleted file mode 100644
index 5500fcc4d..000000000
--- a/qemu/hw/isa/piix4.c
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * QEMU PIIX4 PCI Bridge Emulation
- *
- * Copyright (c) 2006 Fabrice Bellard
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/i386/pc.h"
-#include "hw/pci/pci.h"
-#include "hw/isa/isa.h"
-#include "hw/sysbus.h"
-
-PCIDevice *piix4_dev;
-
-typedef struct PIIX4State {
- PCIDevice dev;
-} PIIX4State;
-
-#define TYPE_PIIX4_PCI_DEVICE "PIIX4"
-#define PIIX4_PCI_DEVICE(obj) \
- OBJECT_CHECK(PIIX4State, (obj), TYPE_PIIX4_PCI_DEVICE)
-
-static void piix4_reset(void *opaque)
-{
- PIIX4State *d = opaque;
- uint8_t *pci_conf = d->dev.config;
-
- pci_conf[0x04] = 0x07; // master, memory and I/O
- pci_conf[0x05] = 0x00;
- pci_conf[0x06] = 0x00;
- pci_conf[0x07] = 0x02; // PCI_status_devsel_medium
- pci_conf[0x4c] = 0x4d;
- pci_conf[0x4e] = 0x03;
- pci_conf[0x4f] = 0x00;
- pci_conf[0x60] = 0x0a; // PCI A -> IRQ 10
- pci_conf[0x61] = 0x0a; // PCI B -> IRQ 10
- pci_conf[0x62] = 0x0b; // PCI C -> IRQ 11
- pci_conf[0x63] = 0x0b; // PCI D -> IRQ 11
- pci_conf[0x69] = 0x02;
- pci_conf[0x70] = 0x80;
- pci_conf[0x76] = 0x0c;
- pci_conf[0x77] = 0x0c;
- pci_conf[0x78] = 0x02;
- pci_conf[0x79] = 0x00;
- pci_conf[0x80] = 0x00;
- pci_conf[0x82] = 0x00;
- pci_conf[0xa0] = 0x08;
- pci_conf[0xa2] = 0x00;
- pci_conf[0xa3] = 0x00;
- pci_conf[0xa4] = 0x00;
- pci_conf[0xa5] = 0x00;
- pci_conf[0xa6] = 0x00;
- pci_conf[0xa7] = 0x00;
- pci_conf[0xa8] = 0x0f;
- pci_conf[0xaa] = 0x00;
- pci_conf[0xab] = 0x00;
- pci_conf[0xac] = 0x00;
- pci_conf[0xae] = 0x00;
-}
-
-static const VMStateDescription vmstate_piix4 = {
- .name = "PIIX4",
- .version_id = 2,
- .minimum_version_id = 2,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(dev, PIIX4State),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void piix4_realize(PCIDevice *dev, Error **errp)
-{
- PIIX4State *d = PIIX4_PCI_DEVICE(dev);
-
- if (!isa_bus_new(DEVICE(d), pci_address_space(dev),
- pci_address_space_io(dev), errp)) {
- return;
- }
- piix4_dev = &d->dev;
- qemu_register_reset(piix4_reset, d);
-}
-
-int piix4_init(PCIBus *bus, ISABus **isa_bus, int devfn)
-{
- PCIDevice *d;
-
- d = pci_create_simple_multifunction(bus, devfn, true, "PIIX4");
- *isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(d), "isa.0"));
- return d->devfn;
-}
-
-static void piix4_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = piix4_realize;
- k->vendor_id = PCI_VENDOR_ID_INTEL;
- k->device_id = PCI_DEVICE_ID_INTEL_82371AB_0;
- k->class_id = PCI_CLASS_BRIDGE_ISA;
- dc->desc = "ISA bridge";
- dc->vmsd = &vmstate_piix4;
- /*
- * Reason: part of PIIX4 southbridge, needs to be wired up,
- * e.g. by mips_malta_init()
- */
- dc->cannot_instantiate_with_device_add_yet = true;
- dc->hotpluggable = false;
-}
-
-static const TypeInfo piix4_info = {
- .name = TYPE_PIIX4_PCI_DEVICE,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(PIIX4State),
- .class_init = piix4_class_init,
-};
-
-static void piix4_register_types(void)
-{
- type_register_static(&piix4_info);
-}
-
-type_init(piix4_register_types)
diff --git a/qemu/hw/isa/vt82c686.c b/qemu/hw/isa/vt82c686.c
deleted file mode 100644
index 41d5254f8..000000000
--- a/qemu/hw/isa/vt82c686.c
+++ /dev/null
@@ -1,515 +0,0 @@
-/*
- * VT82C686B south bridge support
- *
- * Copyright (c) 2008 yajin (yajin@vm-kernel.org)
- * Copyright (c) 2009 chenming (chenming@rdc.faw.com.cn)
- * Copyright (c) 2010 Huacai Chen (zltjiangshi@gmail.com)
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/i386/pc.h"
-#include "hw/isa/vt82c686.h"
-#include "hw/i2c/i2c.h"
-#include "hw/i2c/smbus.h"
-#include "hw/pci/pci.h"
-#include "hw/isa/isa.h"
-#include "hw/sysbus.h"
-#include "hw/mips/mips.h"
-#include "hw/isa/apm.h"
-#include "hw/acpi/acpi.h"
-#include "hw/i2c/pm_smbus.h"
-#include "sysemu/sysemu.h"
-#include "qemu/timer.h"
-#include "exec/address-spaces.h"
-
-//#define DEBUG_VT82C686B
-
-#ifdef DEBUG_VT82C686B
-#define DPRINTF(fmt, ...) fprintf(stderr, "%s: " fmt, __FUNCTION__, ##__VA_ARGS__)
-#else
-#define DPRINTF(fmt, ...)
-#endif
-
-typedef struct SuperIOConfig
-{
- uint8_t config[0x100];
- uint8_t index;
- uint8_t data;
-} SuperIOConfig;
-
-typedef struct VT82C686BState {
- PCIDevice dev;
- MemoryRegion superio;
- SuperIOConfig superio_conf;
-} VT82C686BState;
-
-#define TYPE_VT82C686B_DEVICE "VT82C686B"
-#define VT82C686B_DEVICE(obj) \
- OBJECT_CHECK(VT82C686BState, (obj), TYPE_VT82C686B_DEVICE)
-
-static void superio_ioport_writeb(void *opaque, hwaddr addr, uint64_t data,
- unsigned size)
-{
- SuperIOConfig *superio_conf = opaque;
-
- DPRINTF("superio_ioport_writeb address 0x%x val 0x%x\n", addr, data);
- if (addr == 0x3f0) {
- superio_conf->index = data & 0xff;
- } else {
- bool can_write = true;
- /* 0x3f1 */
- switch (superio_conf->index) {
- case 0x00 ... 0xdf:
- case 0xe4:
- case 0xe5:
- case 0xe9 ... 0xed:
- case 0xf3:
- case 0xf5:
- case 0xf7:
- case 0xf9 ... 0xfb:
- case 0xfd ... 0xff:
- can_write = false;
- break;
- case 0xe7:
- if ((data & 0xff) != 0xfe) {
- DPRINTF("change uart 1 base. unsupported yet\n");
- can_write = false;
- }
- break;
- case 0xe8:
- if ((data & 0xff) != 0xbe) {
- DPRINTF("change uart 2 base. unsupported yet\n");
- can_write = false;
- }
- break;
- default:
- break;
-
- }
- if (can_write) {
- superio_conf->config[superio_conf->index] = data & 0xff;
- }
- }
-}
-
-static uint64_t superio_ioport_readb(void *opaque, hwaddr addr, unsigned size)
-{
- SuperIOConfig *superio_conf = opaque;
-
- DPRINTF("superio_ioport_readb address 0x%x\n", addr);
- return (superio_conf->config[superio_conf->index]);
-}
-
-static const MemoryRegionOps superio_ops = {
- .read = superio_ioport_readb,
- .write = superio_ioport_writeb,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
-};
-
-static void vt82c686b_reset(void * opaque)
-{
- PCIDevice *d = opaque;
- uint8_t *pci_conf = d->config;
- VT82C686BState *vt82c = VT82C686B_DEVICE(d);
-
- pci_set_long(pci_conf + PCI_CAPABILITY_LIST, 0x000000c0);
- pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
- PCI_COMMAND_MASTER | PCI_COMMAND_SPECIAL);
- pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM);
-
- pci_conf[0x48] = 0x01; /* Miscellaneous Control 3 */
- pci_conf[0x4a] = 0x04; /* IDE interrupt Routing */
- pci_conf[0x4f] = 0x03; /* DMA/Master Mem Access Control 3 */
- pci_conf[0x50] = 0x2d; /* PnP DMA Request Control */
- pci_conf[0x59] = 0x04;
- pci_conf[0x5a] = 0x04; /* KBC/RTC Control*/
- pci_conf[0x5f] = 0x04;
- pci_conf[0x77] = 0x10; /* GPIO Control 1/2/3/4 */
-
- vt82c->superio_conf.config[0xe0] = 0x3c;
- vt82c->superio_conf.config[0xe2] = 0x03;
- vt82c->superio_conf.config[0xe3] = 0xfc;
- vt82c->superio_conf.config[0xe6] = 0xde;
- vt82c->superio_conf.config[0xe7] = 0xfe;
- vt82c->superio_conf.config[0xe8] = 0xbe;
-}
-
-/* write config pci function0 registers. PCI-ISA bridge */
-static void vt82c686b_write_config(PCIDevice * d, uint32_t address,
- uint32_t val, int len)
-{
- VT82C686BState *vt686 = VT82C686B_DEVICE(d);
-
- DPRINTF("vt82c686b_write_config address 0x%x val 0x%x len 0x%x\n",
- address, val, len);
-
- pci_default_write_config(d, address, val, len);
- if (address == 0x85) { /* enable or disable super IO configure */
- memory_region_set_enabled(&vt686->superio, val & 0x2);
- }
-}
-
-#define ACPI_DBG_IO_ADDR 0xb044
-
-typedef struct VT686PMState {
- PCIDevice dev;
- MemoryRegion io;
- ACPIREGS ar;
- APMState apm;
- PMSMBus smb;
- uint32_t smb_io_base;
-} VT686PMState;
-
-typedef struct VT686AC97State {
- PCIDevice dev;
-} VT686AC97State;
-
-typedef struct VT686MC97State {
- PCIDevice dev;
-} VT686MC97State;
-
-#define TYPE_VT82C686B_PM_DEVICE "VT82C686B_PM"
-#define VT82C686B_PM_DEVICE(obj) \
- OBJECT_CHECK(VT686PMState, (obj), TYPE_VT82C686B_PM_DEVICE)
-
-#define TYPE_VT82C686B_MC97_DEVICE "VT82C686B_MC97"
-#define VT82C686B_MC97_DEVICE(obj) \
- OBJECT_CHECK(VT686MC97State, (obj), TYPE_VT82C686B_MC97_DEVICE)
-
-#define TYPE_VT82C686B_AC97_DEVICE "VT82C686B_AC97"
-#define VT82C686B_AC97_DEVICE(obj) \
- OBJECT_CHECK(VT686AC97State, (obj), TYPE_VT82C686B_AC97_DEVICE)
-
-static void pm_update_sci(VT686PMState *s)
-{
- int sci_level, pmsts;
-
- pmsts = acpi_pm1_evt_get_sts(&s->ar);
- sci_level = (((pmsts & s->ar.pm1.evt.en) &
- (ACPI_BITMASK_RT_CLOCK_ENABLE |
- ACPI_BITMASK_POWER_BUTTON_ENABLE |
- ACPI_BITMASK_GLOBAL_LOCK_ENABLE |
- ACPI_BITMASK_TIMER_ENABLE)) != 0);
- pci_set_irq(&s->dev, sci_level);
- /* schedule a timer interruption if needed */
- acpi_pm_tmr_update(&s->ar, (s->ar.pm1.evt.en & ACPI_BITMASK_TIMER_ENABLE) &&
- !(pmsts & ACPI_BITMASK_TIMER_STATUS));
-}
-
-static void pm_tmr_timer(ACPIREGS *ar)
-{
- VT686PMState *s = container_of(ar, VT686PMState, ar);
- pm_update_sci(s);
-}
-
-static void pm_io_space_update(VT686PMState *s)
-{
- uint32_t pm_io_base;
-
- pm_io_base = pci_get_long(s->dev.config + 0x40);
- pm_io_base &= 0xffc0;
-
- memory_region_transaction_begin();
- memory_region_set_enabled(&s->io, s->dev.config[0x80] & 1);
- memory_region_set_address(&s->io, pm_io_base);
- memory_region_transaction_commit();
-}
-
-static void pm_write_config(PCIDevice *d,
- uint32_t address, uint32_t val, int len)
-{
- DPRINTF("pm_write_config address 0x%x val 0x%x len 0x%x\n",
- address, val, len);
- pci_default_write_config(d, address, val, len);
-}
-
-static int vmstate_acpi_post_load(void *opaque, int version_id)
-{
- VT686PMState *s = opaque;
-
- pm_io_space_update(s);
- return 0;
-}
-
-static const VMStateDescription vmstate_acpi = {
- .name = "vt82c686b_pm",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = vmstate_acpi_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(dev, VT686PMState),
- VMSTATE_UINT16(ar.pm1.evt.sts, VT686PMState),
- VMSTATE_UINT16(ar.pm1.evt.en, VT686PMState),
- VMSTATE_UINT16(ar.pm1.cnt.cnt, VT686PMState),
- VMSTATE_STRUCT(apm, VT686PMState, 0, vmstate_apm, APMState),
- VMSTATE_TIMER_PTR(ar.tmr.timer, VT686PMState),
- VMSTATE_INT64(ar.tmr.overflow_time, VT686PMState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-/*
- * TODO: vt82c686b_ac97_init() and vt82c686b_mc97_init()
- * just register a PCI device now, functionalities will be implemented later.
- */
-
-static void vt82c686b_ac97_realize(PCIDevice *dev, Error **errp)
-{
- VT686AC97State *s = VT82C686B_AC97_DEVICE(dev);
- uint8_t *pci_conf = s->dev.config;
-
- pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_INVALIDATE |
- PCI_COMMAND_PARITY);
- pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_CAP_LIST |
- PCI_STATUS_DEVSEL_MEDIUM);
- pci_set_long(pci_conf + PCI_INTERRUPT_PIN, 0x03);
-}
-
-void vt82c686b_ac97_init(PCIBus *bus, int devfn)
-{
- PCIDevice *dev;
-
- dev = pci_create(bus, devfn, TYPE_VT82C686B_AC97_DEVICE);
- qdev_init_nofail(&dev->qdev);
-}
-
-static void via_ac97_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = vt82c686b_ac97_realize;
- k->vendor_id = PCI_VENDOR_ID_VIA;
- k->device_id = PCI_DEVICE_ID_VIA_AC97;
- k->revision = 0x50;
- k->class_id = PCI_CLASS_MULTIMEDIA_AUDIO;
- set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
- dc->desc = "AC97";
-}
-
-static const TypeInfo via_ac97_info = {
- .name = TYPE_VT82C686B_AC97_DEVICE,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(VT686AC97State),
- .class_init = via_ac97_class_init,
-};
-
-static void vt82c686b_mc97_realize(PCIDevice *dev, Error **errp)
-{
- VT686MC97State *s = VT82C686B_MC97_DEVICE(dev);
- uint8_t *pci_conf = s->dev.config;
-
- pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_INVALIDATE |
- PCI_COMMAND_VGA_PALETTE);
- pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM);
- pci_set_long(pci_conf + PCI_INTERRUPT_PIN, 0x03);
-}
-
-void vt82c686b_mc97_init(PCIBus *bus, int devfn)
-{
- PCIDevice *dev;
-
- dev = pci_create(bus, devfn, TYPE_VT82C686B_MC97_DEVICE);
- qdev_init_nofail(&dev->qdev);
-}
-
-static void via_mc97_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = vt82c686b_mc97_realize;
- k->vendor_id = PCI_VENDOR_ID_VIA;
- k->device_id = PCI_DEVICE_ID_VIA_MC97;
- k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
- k->revision = 0x30;
- set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
- dc->desc = "MC97";
-}
-
-static const TypeInfo via_mc97_info = {
- .name = TYPE_VT82C686B_MC97_DEVICE,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(VT686MC97State),
- .class_init = via_mc97_class_init,
-};
-
-/* vt82c686 pm init */
-static void vt82c686b_pm_realize(PCIDevice *dev, Error **errp)
-{
- VT686PMState *s = VT82C686B_PM_DEVICE(dev);
- uint8_t *pci_conf;
-
- pci_conf = s->dev.config;
- pci_set_word(pci_conf + PCI_COMMAND, 0);
- pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_FAST_BACK |
- PCI_STATUS_DEVSEL_MEDIUM);
-
- /* 0x48-0x4B is Power Management I/O Base */
- pci_set_long(pci_conf + 0x48, 0x00000001);
-
- /* SMB ports:0xeee0~0xeeef */
- s->smb_io_base =((s->smb_io_base & 0xfff0) + 0x0);
- pci_conf[0x90] = s->smb_io_base | 1;
- pci_conf[0x91] = s->smb_io_base >> 8;
- pci_conf[0xd2] = 0x90;
- pm_smbus_init(&s->dev.qdev, &s->smb);
- memory_region_add_subregion(get_system_io(), s->smb_io_base, &s->smb.io);
-
- apm_init(dev, &s->apm, NULL, s);
-
- memory_region_init(&s->io, OBJECT(dev), "vt82c686-pm", 64);
- memory_region_set_enabled(&s->io, false);
- memory_region_add_subregion(get_system_io(), 0, &s->io);
-
- acpi_pm_tmr_init(&s->ar, pm_tmr_timer, &s->io);
- acpi_pm1_evt_init(&s->ar, pm_tmr_timer, &s->io);
- acpi_pm1_cnt_init(&s->ar, &s->io, false, false, 2);
-}
-
-I2CBus *vt82c686b_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
- qemu_irq sci_irq)
-{
- PCIDevice *dev;
- VT686PMState *s;
-
- dev = pci_create(bus, devfn, TYPE_VT82C686B_PM_DEVICE);
- qdev_prop_set_uint32(&dev->qdev, "smb_io_base", smb_io_base);
-
- s = VT82C686B_PM_DEVICE(dev);
-
- qdev_init_nofail(&dev->qdev);
-
- return s->smb.smbus;
-}
-
-static Property via_pm_properties[] = {
- DEFINE_PROP_UINT32("smb_io_base", VT686PMState, smb_io_base, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void via_pm_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = vt82c686b_pm_realize;
- k->config_write = pm_write_config;
- k->vendor_id = PCI_VENDOR_ID_VIA;
- k->device_id = PCI_DEVICE_ID_VIA_ACPI;
- k->class_id = PCI_CLASS_BRIDGE_OTHER;
- k->revision = 0x40;
- dc->desc = "PM";
- dc->vmsd = &vmstate_acpi;
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
- dc->props = via_pm_properties;
-}
-
-static const TypeInfo via_pm_info = {
- .name = TYPE_VT82C686B_PM_DEVICE,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(VT686PMState),
- .class_init = via_pm_class_init,
-};
-
-static const VMStateDescription vmstate_via = {
- .name = "vt82c686b",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(dev, VT82C686BState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-/* init the PCI-to-ISA bridge */
-static void vt82c686b_realize(PCIDevice *d, Error **errp)
-{
- VT82C686BState *vt82c = VT82C686B_DEVICE(d);
- uint8_t *pci_conf;
- ISABus *isa_bus;
- uint8_t *wmask;
- int i;
-
- isa_bus = isa_bus_new(DEVICE(d), get_system_memory(),
- pci_address_space_io(d), errp);
- if (!isa_bus) {
- return;
- }
-
- pci_conf = d->config;
- pci_config_set_prog_interface(pci_conf, 0x0);
-
- wmask = d->wmask;
- for (i = 0x00; i < 0xff; i++) {
- if (i<=0x03 || (i>=0x08 && i<=0x3f)) {
- wmask[i] = 0x00;
- }
- }
-
- memory_region_init_io(&vt82c->superio, OBJECT(d), &superio_ops,
- &vt82c->superio_conf, "superio", 2);
- memory_region_set_enabled(&vt82c->superio, false);
- /* The floppy also uses 0x3f0 and 0x3f1.
- * But we do not emulate a floppy, so just set it here. */
- memory_region_add_subregion(isa_bus->address_space_io, 0x3f0,
- &vt82c->superio);
-
- qemu_register_reset(vt82c686b_reset, d);
-}
-
-ISABus *vt82c686b_init(PCIBus *bus, int devfn)
-{
- PCIDevice *d;
-
- d = pci_create_simple_multifunction(bus, devfn, true,
- TYPE_VT82C686B_DEVICE);
-
- return ISA_BUS(qdev_get_child_bus(DEVICE(d), "isa.0"));
-}
-
-static void via_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = vt82c686b_realize;
- k->config_write = vt82c686b_write_config;
- k->vendor_id = PCI_VENDOR_ID_VIA;
- k->device_id = PCI_DEVICE_ID_VIA_ISA_BRIDGE;
- k->class_id = PCI_CLASS_BRIDGE_ISA;
- k->revision = 0x40;
- dc->desc = "ISA bridge";
- dc->vmsd = &vmstate_via;
- /*
- * Reason: part of VIA VT82C686 southbridge, needs to be wired up,
- * e.g. by mips_fulong2e_init()
- */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo via_info = {
- .name = TYPE_VT82C686B_DEVICE,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(VT82C686BState),
- .class_init = via_class_init,
-};
-
-static void vt82c686b_register_types(void)
-{
- type_register_static(&via_ac97_info);
- type_register_static(&via_mc97_info);
- type_register_static(&via_pm_info);
- type_register_static(&via_info);
-}
-
-type_init(vt82c686b_register_types)
diff --git a/qemu/hw/lm32/Makefile.objs b/qemu/hw/lm32/Makefile.objs
deleted file mode 100644
index ea6418ae5..000000000
--- a/qemu/hw/lm32/Makefile.objs
+++ /dev/null
@@ -1,3 +0,0 @@
-# LM32 boards
-obj-y += lm32_boards.o
-obj-y += milkymist.o
diff --git a/qemu/hw/lm32/lm32.h b/qemu/hw/lm32/lm32.h
deleted file mode 100644
index 18aa6fdc1..000000000
--- a/qemu/hw/lm32/lm32.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef HW_LM32_H
-#define HW_LM32_H 1
-
-#include "hw/char/lm32_juart.h"
-
-static inline DeviceState *lm32_pic_init(qemu_irq cpu_irq)
-{
- DeviceState *dev;
- SysBusDevice *d;
-
- dev = qdev_create(NULL, "lm32-pic");
- qdev_init_nofail(dev);
- d = SYS_BUS_DEVICE(dev);
- sysbus_connect_irq(d, 0, cpu_irq);
-
- return dev;
-}
-
-static inline DeviceState *lm32_juart_init(void)
-{
- DeviceState *dev;
-
- dev = qdev_create(NULL, TYPE_LM32_JUART);
- qdev_init_nofail(dev);
-
- return dev;
-}
-
-#endif
diff --git a/qemu/hw/lm32/lm32_boards.c b/qemu/hw/lm32/lm32_boards.c
deleted file mode 100644
index c0290560f..000000000
--- a/qemu/hw/lm32/lm32_boards.c
+++ /dev/null
@@ -1,334 +0,0 @@
-/*
- * QEMU models for LatticeMico32 uclinux and evr32 boards.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/sysbus.h"
-#include "hw/hw.h"
-#include "hw/block/flash.h"
-#include "hw/devices.h"
-#include "hw/boards.h"
-#include "hw/loader.h"
-#include "sysemu/block-backend.h"
-#include "elf.h"
-#include "lm32_hwsetup.h"
-#include "lm32.h"
-#include "exec/address-spaces.h"
-
-typedef struct {
- LM32CPU *cpu;
- hwaddr bootstrap_pc;
- hwaddr flash_base;
- hwaddr hwsetup_base;
- hwaddr initrd_base;
- size_t initrd_size;
- hwaddr cmdline_base;
-} ResetInfo;
-
-static void cpu_irq_handler(void *opaque, int irq, int level)
-{
- LM32CPU *cpu = opaque;
- CPUState *cs = CPU(cpu);
-
- if (level) {
- cpu_interrupt(cs, CPU_INTERRUPT_HARD);
- } else {
- cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
- }
-}
-
-static void main_cpu_reset(void *opaque)
-{
- ResetInfo *reset_info = opaque;
- CPULM32State *env = &reset_info->cpu->env;
-
- cpu_reset(CPU(reset_info->cpu));
-
- /* init defaults */
- env->pc = (uint32_t)reset_info->bootstrap_pc;
- env->regs[R_R1] = (uint32_t)reset_info->hwsetup_base;
- env->regs[R_R2] = (uint32_t)reset_info->cmdline_base;
- env->regs[R_R3] = (uint32_t)reset_info->initrd_base;
- env->regs[R_R4] = (uint32_t)(reset_info->initrd_base +
- reset_info->initrd_size);
- env->eba = reset_info->flash_base;
- env->deba = reset_info->flash_base;
-}
-
-static void lm32_evr_init(MachineState *machine)
-{
- const char *cpu_model = machine->cpu_model;
- const char *kernel_filename = machine->kernel_filename;
- LM32CPU *cpu;
- CPULM32State *env;
- DriveInfo *dinfo;
- MemoryRegion *address_space_mem = get_system_memory();
- MemoryRegion *phys_ram = g_new(MemoryRegion, 1);
- qemu_irq irq[32];
- ResetInfo *reset_info;
- int i;
-
- /* memory map */
- hwaddr flash_base = 0x04000000;
- size_t flash_sector_size = 256 * 1024;
- size_t flash_size = 32 * 1024 * 1024;
- hwaddr ram_base = 0x08000000;
- size_t ram_size = 64 * 1024 * 1024;
- hwaddr timer0_base = 0x80002000;
- hwaddr uart0_base = 0x80006000;
- hwaddr timer1_base = 0x8000a000;
- int uart0_irq = 0;
- int timer0_irq = 1;
- int timer1_irq = 3;
-
- reset_info = g_malloc0(sizeof(ResetInfo));
-
- if (cpu_model == NULL) {
- cpu_model = "lm32-full";
- }
- cpu = cpu_lm32_init(cpu_model);
- if (cpu == NULL) {
- fprintf(stderr, "qemu: unable to find CPU '%s'\n", cpu_model);
- exit(1);
- }
-
- env = &cpu->env;
- reset_info->cpu = cpu;
-
- reset_info->flash_base = flash_base;
-
- memory_region_allocate_system_memory(phys_ram, NULL, "lm32_evr.sdram",
- ram_size);
- memory_region_add_subregion(address_space_mem, ram_base, phys_ram);
-
- dinfo = drive_get(IF_PFLASH, 0, 0);
- /* Spansion S29NS128P */
- pflash_cfi02_register(flash_base, NULL, "lm32_evr.flash", flash_size,
- dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- flash_sector_size, flash_size / flash_sector_size,
- 1, 2, 0x01, 0x7e, 0x43, 0x00, 0x555, 0x2aa, 1);
-
- /* create irq lines */
- env->pic_state = lm32_pic_init(qemu_allocate_irq(cpu_irq_handler, cpu, 0));
- for (i = 0; i < 32; i++) {
- irq[i] = qdev_get_gpio_in(env->pic_state, i);
- }
-
- sysbus_create_simple("lm32-uart", uart0_base, irq[uart0_irq]);
- sysbus_create_simple("lm32-timer", timer0_base, irq[timer0_irq]);
- sysbus_create_simple("lm32-timer", timer1_base, irq[timer1_irq]);
-
- /* make sure juart isn't the first chardev */
- env->juart_state = lm32_juart_init();
-
- reset_info->bootstrap_pc = flash_base;
-
- if (kernel_filename) {
- uint64_t entry;
- int kernel_size;
-
- kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL,
- 1, EM_LATTICEMICO32, 0, 0);
- reset_info->bootstrap_pc = entry;
-
- if (kernel_size < 0) {
- kernel_size = load_image_targphys(kernel_filename, ram_base,
- ram_size);
- reset_info->bootstrap_pc = ram_base;
- }
-
- if (kernel_size < 0) {
- fprintf(stderr, "qemu: could not load kernel '%s'\n",
- kernel_filename);
- exit(1);
- }
- }
-
- qemu_register_reset(main_cpu_reset, reset_info);
-}
-
-static void lm32_uclinux_init(MachineState *machine)
-{
- const char *cpu_model = machine->cpu_model;
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- const char *initrd_filename = machine->initrd_filename;
- LM32CPU *cpu;
- CPULM32State *env;
- DriveInfo *dinfo;
- MemoryRegion *address_space_mem = get_system_memory();
- MemoryRegion *phys_ram = g_new(MemoryRegion, 1);
- qemu_irq irq[32];
- HWSetup *hw;
- ResetInfo *reset_info;
- int i;
-
- /* memory map */
- hwaddr flash_base = 0x04000000;
- size_t flash_sector_size = 256 * 1024;
- size_t flash_size = 32 * 1024 * 1024;
- hwaddr ram_base = 0x08000000;
- size_t ram_size = 64 * 1024 * 1024;
- hwaddr uart0_base = 0x80000000;
- hwaddr timer0_base = 0x80002000;
- hwaddr timer1_base = 0x80010000;
- hwaddr timer2_base = 0x80012000;
- int uart0_irq = 0;
- int timer0_irq = 1;
- int timer1_irq = 20;
- int timer2_irq = 21;
- hwaddr hwsetup_base = 0x0bffe000;
- hwaddr cmdline_base = 0x0bfff000;
- hwaddr initrd_base = 0x08400000;
- size_t initrd_max = 0x01000000;
-
- reset_info = g_malloc0(sizeof(ResetInfo));
-
- if (cpu_model == NULL) {
- cpu_model = "lm32-full";
- }
- cpu = cpu_lm32_init(cpu_model);
- if (cpu == NULL) {
- fprintf(stderr, "qemu: unable to find CPU '%s'\n", cpu_model);
- exit(1);
- }
-
- env = &cpu->env;
- reset_info->cpu = cpu;
-
- reset_info->flash_base = flash_base;
-
- memory_region_allocate_system_memory(phys_ram, NULL,
- "lm32_uclinux.sdram", ram_size);
- memory_region_add_subregion(address_space_mem, ram_base, phys_ram);
-
- dinfo = drive_get(IF_PFLASH, 0, 0);
- /* Spansion S29NS128P */
- pflash_cfi02_register(flash_base, NULL, "lm32_uclinux.flash", flash_size,
- dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- flash_sector_size, flash_size / flash_sector_size,
- 1, 2, 0x01, 0x7e, 0x43, 0x00, 0x555, 0x2aa, 1);
-
- /* create irq lines */
- env->pic_state = lm32_pic_init(qemu_allocate_irq(cpu_irq_handler, env, 0));
- for (i = 0; i < 32; i++) {
- irq[i] = qdev_get_gpio_in(env->pic_state, i);
- }
-
- sysbus_create_simple("lm32-uart", uart0_base, irq[uart0_irq]);
- sysbus_create_simple("lm32-timer", timer0_base, irq[timer0_irq]);
- sysbus_create_simple("lm32-timer", timer1_base, irq[timer1_irq]);
- sysbus_create_simple("lm32-timer", timer2_base, irq[timer2_irq]);
-
- /* make sure juart isn't the first chardev */
- env->juart_state = lm32_juart_init();
-
- reset_info->bootstrap_pc = flash_base;
-
- if (kernel_filename) {
- uint64_t entry;
- int kernel_size;
-
- kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL,
- 1, EM_LATTICEMICO32, 0, 0);
- reset_info->bootstrap_pc = entry;
-
- if (kernel_size < 0) {
- kernel_size = load_image_targphys(kernel_filename, ram_base,
- ram_size);
- reset_info->bootstrap_pc = ram_base;
- }
-
- if (kernel_size < 0) {
- fprintf(stderr, "qemu: could not load kernel '%s'\n",
- kernel_filename);
- exit(1);
- }
- }
-
- /* generate a rom with the hardware description */
- hw = hwsetup_init();
- hwsetup_add_cpu(hw, "LM32", 75000000);
- hwsetup_add_flash(hw, "flash", flash_base, flash_size);
- hwsetup_add_ddr_sdram(hw, "ddr_sdram", ram_base, ram_size);
- hwsetup_add_timer(hw, "timer0", timer0_base, timer0_irq);
- hwsetup_add_timer(hw, "timer1_dev_only", timer1_base, timer1_irq);
- hwsetup_add_timer(hw, "timer2_dev_only", timer2_base, timer2_irq);
- hwsetup_add_uart(hw, "uart", uart0_base, uart0_irq);
- hwsetup_add_trailer(hw);
- hwsetup_create_rom(hw, hwsetup_base);
- hwsetup_free(hw);
-
- reset_info->hwsetup_base = hwsetup_base;
-
- if (kernel_cmdline && strlen(kernel_cmdline)) {
- pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE,
- kernel_cmdline);
- reset_info->cmdline_base = cmdline_base;
- }
-
- if (initrd_filename) {
- size_t initrd_size;
- initrd_size = load_image_targphys(initrd_filename, initrd_base,
- initrd_max);
- reset_info->initrd_base = initrd_base;
- reset_info->initrd_size = initrd_size;
- }
-
- qemu_register_reset(main_cpu_reset, reset_info);
-}
-
-static void lm32_evr_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "LatticeMico32 EVR32 eval system";
- mc->init = lm32_evr_init;
- mc->is_default = 1;
-}
-
-static const TypeInfo lm32_evr_type = {
- .name = MACHINE_TYPE_NAME("lm32-evr"),
- .parent = TYPE_MACHINE,
- .class_init = lm32_evr_class_init,
-};
-
-static void lm32_uclinux_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "lm32 platform for uClinux and u-boot by Theobroma Systems";
- mc->init = lm32_uclinux_init;
- mc->is_default = 0;
-}
-
-static const TypeInfo lm32_uclinux_type = {
- .name = MACHINE_TYPE_NAME("lm32-uclinux"),
- .parent = TYPE_MACHINE,
- .class_init = lm32_uclinux_class_init,
-};
-
-static void lm32_machine_init(void)
-{
- type_register_static(&lm32_evr_type);
- type_register_static(&lm32_uclinux_type);
-}
-
-type_init(lm32_machine_init)
diff --git a/qemu/hw/lm32/lm32_hwsetup.h b/qemu/hw/lm32/lm32_hwsetup.h
deleted file mode 100644
index b71e6eafb..000000000
--- a/qemu/hw/lm32/lm32_hwsetup.h
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * LatticeMico32 hwsetup helper functions.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * These are helper functions for creating the hardware description blob used
- * in the Theobroma's uClinux port.
- */
-
-#ifndef QEMU_HW_LM32_HWSETUP_H
-#define QEMU_HW_LM32_HWSETUP_H
-
-#include "qemu-common.h"
-#include "qemu/cutils.h"
-#include "hw/loader.h"
-
-typedef struct {
- void *data;
- void *ptr;
-} HWSetup;
-
-enum hwsetup_tag {
- HWSETUP_TAG_EOL = 0,
- HWSETUP_TAG_CPU = 1,
- HWSETUP_TAG_ASRAM = 2,
- HWSETUP_TAG_FLASH = 3,
- HWSETUP_TAG_SDRAM = 4,
- HWSETUP_TAG_OCM = 5,
- HWSETUP_TAG_DDR_SDRAM = 6,
- HWSETUP_TAG_DDR2_SDRAM = 7,
- HWSETUP_TAG_TIMER = 8,
- HWSETUP_TAG_UART = 9,
- HWSETUP_TAG_GPIO = 10,
- HWSETUP_TAG_TRISPEEDMAC = 11,
- HWSETUP_TAG_I2CM = 12,
- HWSETUP_TAG_LEDS = 13,
- HWSETUP_TAG_7SEG = 14,
- HWSETUP_TAG_SPI_S = 15,
- HWSETUP_TAG_SPI_M = 16,
-};
-
-static inline HWSetup *hwsetup_init(void)
-{
- HWSetup *hw;
-
- hw = g_malloc(sizeof(HWSetup));
- hw->data = g_malloc0(TARGET_PAGE_SIZE);
- hw->ptr = hw->data;
-
- return hw;
-}
-
-static inline void hwsetup_free(HWSetup *hw)
-{
- g_free(hw->data);
- g_free(hw);
-}
-
-static inline void hwsetup_create_rom(HWSetup *hw,
- hwaddr base)
-{
- rom_add_blob("hwsetup", hw->data, TARGET_PAGE_SIZE,
- TARGET_PAGE_SIZE, base, NULL, NULL, NULL);
-}
-
-static inline void hwsetup_add_u8(HWSetup *hw, uint8_t u)
-{
- stb_p(hw->ptr, u);
- hw->ptr += 1;
-}
-
-static inline void hwsetup_add_u32(HWSetup *hw, uint32_t u)
-{
- stl_p(hw->ptr, u);
- hw->ptr += 4;
-}
-
-static inline void hwsetup_add_tag(HWSetup *hw, enum hwsetup_tag t)
-{
- stl_p(hw->ptr, t);
- hw->ptr += 4;
-}
-
-static inline void hwsetup_add_str(HWSetup *hw, const char *str)
-{
- pstrcpy(hw->ptr, 32, str);
- hw->ptr += 32;
-}
-
-static inline void hwsetup_add_trailer(HWSetup *hw)
-{
- hwsetup_add_u32(hw, 8); /* size */
- hwsetup_add_tag(hw, HWSETUP_TAG_EOL);
-}
-
-static inline void hwsetup_add_cpu(HWSetup *hw,
- const char *name, uint32_t frequency)
-{
- hwsetup_add_u32(hw, 44); /* size */
- hwsetup_add_tag(hw, HWSETUP_TAG_CPU);
- hwsetup_add_str(hw, name);
- hwsetup_add_u32(hw, frequency);
-}
-
-static inline void hwsetup_add_flash(HWSetup *hw,
- const char *name, uint32_t base, uint32_t size)
-{
- hwsetup_add_u32(hw, 52); /* size */
- hwsetup_add_tag(hw, HWSETUP_TAG_FLASH);
- hwsetup_add_str(hw, name);
- hwsetup_add_u32(hw, base);
- hwsetup_add_u32(hw, size);
- hwsetup_add_u8(hw, 8); /* read latency */
- hwsetup_add_u8(hw, 8); /* write latency */
- hwsetup_add_u8(hw, 25); /* address width */
- hwsetup_add_u8(hw, 32); /* data width */
-}
-
-static inline void hwsetup_add_ddr_sdram(HWSetup *hw,
- const char *name, uint32_t base, uint32_t size)
-{
- hwsetup_add_u32(hw, 48); /* size */
- hwsetup_add_tag(hw, HWSETUP_TAG_DDR_SDRAM);
- hwsetup_add_str(hw, name);
- hwsetup_add_u32(hw, base);
- hwsetup_add_u32(hw, size);
-}
-
-static inline void hwsetup_add_timer(HWSetup *hw,
- const char *name, uint32_t base, uint32_t irq)
-{
- hwsetup_add_u32(hw, 56); /* size */
- hwsetup_add_tag(hw, HWSETUP_TAG_TIMER);
- hwsetup_add_str(hw, name);
- hwsetup_add_u32(hw, base);
- hwsetup_add_u8(hw, 1); /* wr_tickcount */
- hwsetup_add_u8(hw, 1); /* rd_tickcount */
- hwsetup_add_u8(hw, 1); /* start_stop_control */
- hwsetup_add_u8(hw, 32); /* counter_width */
- hwsetup_add_u32(hw, 20); /* reload_ticks */
- hwsetup_add_u8(hw, irq);
- hwsetup_add_u8(hw, 0); /* padding */
- hwsetup_add_u8(hw, 0); /* padding */
- hwsetup_add_u8(hw, 0); /* padding */
-}
-
-static inline void hwsetup_add_uart(HWSetup *hw,
- const char *name, uint32_t base, uint32_t irq)
-{
- hwsetup_add_u32(hw, 56); /* size */
- hwsetup_add_tag(hw, HWSETUP_TAG_UART);
- hwsetup_add_str(hw, name);
- hwsetup_add_u32(hw, base);
- hwsetup_add_u32(hw, 115200); /* baudrate */
- hwsetup_add_u8(hw, 8); /* databits */
- hwsetup_add_u8(hw, 1); /* stopbits */
- hwsetup_add_u8(hw, 1); /* use_interrupt */
- hwsetup_add_u8(hw, 1); /* block_on_transmit */
- hwsetup_add_u8(hw, 1); /* block_on_receive */
- hwsetup_add_u8(hw, 4); /* rx_buffer_size */
- hwsetup_add_u8(hw, 4); /* tx_buffer_size */
- hwsetup_add_u8(hw, irq);
-}
-
-#endif /* QEMU_HW_LM32_HWSETUP_H */
diff --git a/qemu/hw/lm32/milkymist-hw.h b/qemu/hw/lm32/milkymist-hw.h
deleted file mode 100644
index c8dfb4d2d..000000000
--- a/qemu/hw/lm32/milkymist-hw.h
+++ /dev/null
@@ -1,208 +0,0 @@
-#ifndef QEMU_HW_MILKYMIST_H
-#define QEMU_HW_MILKYMIST_H
-
-#include "hw/qdev.h"
-#include "net/net.h"
-
-static inline DeviceState *milkymist_uart_create(hwaddr base,
- qemu_irq irq)
-{
- DeviceState *dev;
-
- dev = qdev_create(NULL, "milkymist-uart");
- qdev_init_nofail(dev);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
-
- return dev;
-}
-
-static inline DeviceState *milkymist_hpdmc_create(hwaddr base)
-{
- DeviceState *dev;
-
- dev = qdev_create(NULL, "milkymist-hpdmc");
- qdev_init_nofail(dev);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
-
- return dev;
-}
-
-static inline DeviceState *milkymist_memcard_create(hwaddr base)
-{
- DeviceState *dev;
-
- dev = qdev_create(NULL, "milkymist-memcard");
- qdev_init_nofail(dev);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
-
- return dev;
-}
-
-static inline DeviceState *milkymist_vgafb_create(hwaddr base,
- uint32_t fb_offset, uint32_t fb_mask)
-{
- DeviceState *dev;
-
- dev = qdev_create(NULL, "milkymist-vgafb");
- qdev_prop_set_uint32(dev, "fb_offset", fb_offset);
- qdev_prop_set_uint32(dev, "fb_mask", fb_mask);
- qdev_init_nofail(dev);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
-
- return dev;
-}
-
-static inline DeviceState *milkymist_sysctl_create(hwaddr base,
- qemu_irq gpio_irq, qemu_irq timer0_irq, qemu_irq timer1_irq,
- uint32_t freq_hz, uint32_t system_id, uint32_t capabilities,
- uint32_t gpio_strappings)
-{
- DeviceState *dev;
-
- dev = qdev_create(NULL, "milkymist-sysctl");
- qdev_prop_set_uint32(dev, "frequency", freq_hz);
- qdev_prop_set_uint32(dev, "systemid", system_id);
- qdev_prop_set_uint32(dev, "capabilities", capabilities);
- qdev_prop_set_uint32(dev, "gpio_strappings", gpio_strappings);
- qdev_init_nofail(dev);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, gpio_irq);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, timer0_irq);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, timer1_irq);
-
- return dev;
-}
-
-static inline DeviceState *milkymist_pfpu_create(hwaddr base,
- qemu_irq irq)
-{
- DeviceState *dev;
-
- dev = qdev_create(NULL, "milkymist-pfpu");
- qdev_init_nofail(dev);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
- return dev;
-}
-
-#ifdef CONFIG_OPENGL
-#include <X11/Xlib.h>
-#include <epoxy/gl.h>
-#include <epoxy/glx.h>
-static const int glx_fbconfig_attr[] = {
- GLX_GREEN_SIZE, 5,
- GLX_GREEN_SIZE, 6,
- GLX_BLUE_SIZE, 5,
- None
-};
-#endif
-
-static inline DeviceState *milkymist_tmu2_create(hwaddr base,
- qemu_irq irq)
-{
-#ifdef CONFIG_OPENGL
- DeviceState *dev;
- Display *d;
- GLXFBConfig *configs;
- int nelements;
- int ver_major, ver_minor;
-
- if (display_type == DT_NOGRAPHIC) {
- return NULL;
- }
-
- /* check that GLX will work */
- d = XOpenDisplay(NULL);
- if (d == NULL) {
- return NULL;
- }
-
- if (!glXQueryVersion(d, &ver_major, &ver_minor)) {
- /* Yeah, sometimes getting the GLX version can fail.
- * Isn't X beautiful? */
- XCloseDisplay(d);
- return NULL;
- }
-
- if ((ver_major < 1) || ((ver_major == 1) && (ver_minor < 3))) {
- printf("Your GLX version is %d.%d,"
- "but TMU emulation needs at least 1.3. TMU disabled.\n",
- ver_major, ver_minor);
- XCloseDisplay(d);
- return NULL;
- }
-
- configs = glXChooseFBConfig(d, 0, glx_fbconfig_attr, &nelements);
- if (configs == NULL) {
- XCloseDisplay(d);
- return NULL;
- }
-
- XFree(configs);
- XCloseDisplay(d);
-
- dev = qdev_create(NULL, "milkymist-tmu2");
- qdev_init_nofail(dev);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
-
- return dev;
-#else
- return NULL;
-#endif
-}
-
-static inline DeviceState *milkymist_ac97_create(hwaddr base,
- qemu_irq crrequest_irq, qemu_irq crreply_irq, qemu_irq dmar_irq,
- qemu_irq dmaw_irq)
-{
- DeviceState *dev;
-
- dev = qdev_create(NULL, "milkymist-ac97");
- qdev_init_nofail(dev);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, crrequest_irq);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, crreply_irq);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, dmar_irq);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 3, dmaw_irq);
-
- return dev;
-}
-
-static inline DeviceState *milkymist_minimac2_create(hwaddr base,
- hwaddr buffers_base, qemu_irq rx_irq, qemu_irq tx_irq)
-{
- DeviceState *dev;
-
- qemu_check_nic_model(&nd_table[0], "minimac2");
- dev = qdev_create(NULL, "milkymist-minimac2");
- qdev_set_nic_properties(dev, &nd_table[0]);
- qdev_init_nofail(dev);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, buffers_base);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, rx_irq);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, tx_irq);
-
- return dev;
-}
-
-static inline DeviceState *milkymist_softusb_create(hwaddr base,
- qemu_irq irq, uint32_t pmem_base, uint32_t pmem_size,
- uint32_t dmem_base, uint32_t dmem_size)
-{
- DeviceState *dev;
-
- dev = qdev_create(NULL, "milkymist-softusb");
- qdev_prop_set_uint32(dev, "pmem_size", pmem_size);
- qdev_prop_set_uint32(dev, "dmem_size", dmem_size);
- qdev_init_nofail(dev);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, pmem_base);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, dmem_base);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
-
- return dev;
-}
-
-#endif /* QEMU_HW_MILKYMIST_H */
diff --git a/qemu/hw/lm32/milkymist.c b/qemu/hw/lm32/milkymist.c
deleted file mode 100644
index 96e6f4dc2..000000000
--- a/qemu/hw/lm32/milkymist.c
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * QEMU model for the Milkymist board.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/sysbus.h"
-#include "hw/hw.h"
-#include "hw/block/flash.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/qtest.h"
-#include "hw/devices.h"
-#include "hw/boards.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "sysemu/block-backend.h"
-#include "milkymist-hw.h"
-#include "lm32.h"
-#include "exec/address-spaces.h"
-#include "qemu/cutils.h"
-
-#define BIOS_FILENAME "mmone-bios.bin"
-#define BIOS_OFFSET 0x00860000
-#define BIOS_SIZE (512*1024)
-#define KERNEL_LOAD_ADDR 0x40000000
-
-typedef struct {
- LM32CPU *cpu;
- hwaddr bootstrap_pc;
- hwaddr flash_base;
- hwaddr initrd_base;
- size_t initrd_size;
- hwaddr cmdline_base;
-} ResetInfo;
-
-static void cpu_irq_handler(void *opaque, int irq, int level)
-{
- LM32CPU *cpu = opaque;
- CPUState *cs = CPU(cpu);
-
- if (level) {
- cpu_interrupt(cs, CPU_INTERRUPT_HARD);
- } else {
- cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
- }
-}
-
-static void main_cpu_reset(void *opaque)
-{
- ResetInfo *reset_info = opaque;
- CPULM32State *env = &reset_info->cpu->env;
-
- cpu_reset(CPU(reset_info->cpu));
-
- /* init defaults */
- env->pc = reset_info->bootstrap_pc;
- env->regs[R_R1] = reset_info->cmdline_base;
- env->regs[R_R2] = reset_info->initrd_base;
- env->regs[R_R3] = reset_info->initrd_base + reset_info->initrd_size;
- env->eba = reset_info->flash_base;
- env->deba = reset_info->flash_base;
-}
-
-static void
-milkymist_init(MachineState *machine)
-{
- const char *cpu_model = machine->cpu_model;
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- const char *initrd_filename = machine->initrd_filename;
- LM32CPU *cpu;
- CPULM32State *env;
- int kernel_size;
- DriveInfo *dinfo;
- MemoryRegion *address_space_mem = get_system_memory();
- MemoryRegion *phys_sdram = g_new(MemoryRegion, 1);
- qemu_irq irq[32];
- int i;
- char *bios_filename;
- ResetInfo *reset_info;
-
- /* memory map */
- hwaddr flash_base = 0x00000000;
- size_t flash_sector_size = 128 * 1024;
- size_t flash_size = 32 * 1024 * 1024;
- hwaddr sdram_base = 0x40000000;
- size_t sdram_size = 128 * 1024 * 1024;
-
- hwaddr initrd_base = sdram_base + 0x1002000;
- hwaddr cmdline_base = sdram_base + 0x1000000;
- size_t initrd_max = sdram_size - 0x1002000;
-
- reset_info = g_malloc0(sizeof(ResetInfo));
-
- if (cpu_model == NULL) {
- cpu_model = "lm32-full";
- }
- cpu = cpu_lm32_init(cpu_model);
- if (cpu == NULL) {
- fprintf(stderr, "qemu: unable to find CPU '%s'\n", cpu_model);
- exit(1);
- }
-
- env = &cpu->env;
- reset_info->cpu = cpu;
-
- cpu_lm32_set_phys_msb_ignore(env, 1);
-
- memory_region_allocate_system_memory(phys_sdram, NULL, "milkymist.sdram",
- sdram_size);
- memory_region_add_subregion(address_space_mem, sdram_base, phys_sdram);
-
- dinfo = drive_get(IF_PFLASH, 0, 0);
- /* Numonyx JS28F256J3F105 */
- pflash_cfi01_register(flash_base, NULL, "milkymist.flash", flash_size,
- dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- flash_sector_size, flash_size / flash_sector_size,
- 2, 0x00, 0x89, 0x00, 0x1d, 1);
-
- /* create irq lines */
- env->pic_state = lm32_pic_init(qemu_allocate_irq(cpu_irq_handler, cpu, 0));
- for (i = 0; i < 32; i++) {
- irq[i] = qdev_get_gpio_in(env->pic_state, i);
- }
-
- /* load bios rom */
- if (bios_name == NULL) {
- bios_name = BIOS_FILENAME;
- }
- bios_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
-
- if (bios_filename) {
- load_image_targphys(bios_filename, BIOS_OFFSET, BIOS_SIZE);
- }
-
- reset_info->bootstrap_pc = BIOS_OFFSET;
-
- /* if no kernel is given no valid bios rom is a fatal error */
- if (!kernel_filename && !dinfo && !bios_filename && !qtest_enabled()) {
- fprintf(stderr, "qemu: could not load Milkymist One bios '%s'\n",
- bios_name);
- exit(1);
- }
- g_free(bios_filename);
-
- milkymist_uart_create(0x60000000, irq[0]);
- milkymist_sysctl_create(0x60001000, irq[1], irq[2], irq[3],
- 80000000, 0x10014d31, 0x0000041f, 0x00000001);
- milkymist_hpdmc_create(0x60002000);
- milkymist_vgafb_create(0x60003000, 0x40000000, 0x0fffffff);
- milkymist_memcard_create(0x60004000);
- milkymist_ac97_create(0x60005000, irq[4], irq[5], irq[6], irq[7]);
- milkymist_pfpu_create(0x60006000, irq[8]);
- milkymist_tmu2_create(0x60007000, irq[9]);
- milkymist_minimac2_create(0x60008000, 0x30000000, irq[10], irq[11]);
- milkymist_softusb_create(0x6000f000, irq[15],
- 0x20000000, 0x1000, 0x20020000, 0x2000);
-
- /* make sure juart isn't the first chardev */
- env->juart_state = lm32_juart_init();
-
- if (kernel_filename) {
- uint64_t entry;
-
- /* Boots a kernel elf binary. */
- kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL,
- 1, EM_LATTICEMICO32, 0, 0);
- reset_info->bootstrap_pc = entry;
-
- if (kernel_size < 0) {
- kernel_size = load_image_targphys(kernel_filename, sdram_base,
- sdram_size);
- reset_info->bootstrap_pc = sdram_base;
- }
-
- if (kernel_size < 0) {
- fprintf(stderr, "qemu: could not load kernel '%s'\n",
- kernel_filename);
- exit(1);
- }
- }
-
- if (kernel_cmdline && strlen(kernel_cmdline)) {
- pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE,
- kernel_cmdline);
- reset_info->cmdline_base = (uint32_t)cmdline_base;
- }
-
- if (initrd_filename) {
- size_t initrd_size;
- initrd_size = load_image_targphys(initrd_filename, initrd_base,
- initrd_max);
- reset_info->initrd_base = (uint32_t)initrd_base;
- reset_info->initrd_size = (uint32_t)initrd_size;
- }
-
- qemu_register_reset(main_cpu_reset, reset_info);
-}
-
-static void milkymist_machine_init(MachineClass *mc)
-{
- mc->desc = "Milkymist One";
- mc->init = milkymist_init;
- mc->is_default = 0;
-}
-
-DEFINE_MACHINE("milkymist", milkymist_machine_init)
diff --git a/qemu/hw/m68k/Makefile.objs b/qemu/hw/m68k/Makefile.objs
deleted file mode 100644
index c4352e783..000000000
--- a/qemu/hw/m68k/Makefile.objs
+++ /dev/null
@@ -1,4 +0,0 @@
-obj-y += an5206.o mcf5208.o
-obj-y += dummy_m68k.o
-
-obj-y += mcf5206.o mcf_intc.o
diff --git a/qemu/hw/m68k/an5206.c b/qemu/hw/m68k/an5206.c
deleted file mode 100644
index 142bab98c..000000000
--- a/qemu/hw/m68k/an5206.c
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Arnewsh 5206 ColdFire system emulation.
- *
- * Copyright (c) 2007 CodeSourcery.
- *
- * This code is licensed under the GPL
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/hw.h"
-#include "hw/m68k/mcf.h"
-#include "hw/boards.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "exec/address-spaces.h"
-#include "qemu/error-report.h"
-#include "sysemu/qtest.h"
-
-#define KERNEL_LOAD_ADDR 0x10000
-#define AN5206_MBAR_ADDR 0x10000000
-#define AN5206_RAMBAR_ADDR 0x20000000
-
-/* Board init. */
-
-static void an5206_init(MachineState *machine)
-{
- ram_addr_t ram_size = machine->ram_size;
- const char *cpu_model = machine->cpu_model;
- const char *kernel_filename = machine->kernel_filename;
- M68kCPU *cpu;
- CPUM68KState *env;
- int kernel_size;
- uint64_t elf_entry;
- hwaddr entry;
- MemoryRegion *address_space_mem = get_system_memory();
- MemoryRegion *ram = g_new(MemoryRegion, 1);
- MemoryRegion *sram = g_new(MemoryRegion, 1);
-
- if (!cpu_model) {
- cpu_model = "m5206";
- }
- cpu = cpu_m68k_init(cpu_model);
- if (!cpu) {
- error_report("Unable to find m68k CPU definition");
- exit(1);
- }
- env = &cpu->env;
-
- /* Initialize CPU registers. */
- env->vbr = 0;
- /* TODO: allow changing MBAR and RAMBAR. */
- env->mbar = AN5206_MBAR_ADDR | 1;
- env->rambar0 = AN5206_RAMBAR_ADDR | 1;
-
- /* DRAM at address zero */
- memory_region_allocate_system_memory(ram, NULL, "an5206.ram", ram_size);
- memory_region_add_subregion(address_space_mem, 0, ram);
-
- /* Internal SRAM. */
- memory_region_init_ram(sram, NULL, "an5206.sram", 512, &error_fatal);
- vmstate_register_ram_global(sram);
- memory_region_add_subregion(address_space_mem, AN5206_RAMBAR_ADDR, sram);
-
- mcf5206_init(address_space_mem, AN5206_MBAR_ADDR, cpu);
-
- /* Load kernel. */
- if (!kernel_filename) {
- if (qtest_enabled()) {
- return;
- }
- fprintf(stderr, "Kernel image must be specified\n");
- exit(1);
- }
-
- kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry,
- NULL, NULL, 1, EM_68K, 0, 0);
- entry = elf_entry;
- if (kernel_size < 0) {
- kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL,
- NULL, NULL);
- }
- if (kernel_size < 0) {
- kernel_size = load_image_targphys(kernel_filename, KERNEL_LOAD_ADDR,
- ram_size - KERNEL_LOAD_ADDR);
- entry = KERNEL_LOAD_ADDR;
- }
- if (kernel_size < 0) {
- fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename);
- exit(1);
- }
-
- env->pc = entry;
-}
-
-static void an5206_machine_init(MachineClass *mc)
-{
- mc->desc = "Arnewsh 5206";
- mc->init = an5206_init;
-}
-
-DEFINE_MACHINE("an5206", an5206_machine_init)
diff --git a/qemu/hw/m68k/dummy_m68k.c b/qemu/hw/m68k/dummy_m68k.c
deleted file mode 100644
index 0b11d2074..000000000
--- a/qemu/hw/m68k/dummy_m68k.c
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Dummy board with just RAM and CPU for use as an ISS.
- *
- * Copyright (c) 2007 CodeSourcery.
- *
- * This code is licensed under the GPL
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/hw.h"
-#include "hw/boards.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "exec/address-spaces.h"
-
-#define KERNEL_LOAD_ADDR 0x10000
-
-/* Board init. */
-
-static void dummy_m68k_init(MachineState *machine)
-{
- ram_addr_t ram_size = machine->ram_size;
- const char *cpu_model = machine->cpu_model;
- const char *kernel_filename = machine->kernel_filename;
- M68kCPU *cpu;
- CPUM68KState *env;
- MemoryRegion *address_space_mem = get_system_memory();
- MemoryRegion *ram = g_new(MemoryRegion, 1);
- int kernel_size;
- uint64_t elf_entry;
- hwaddr entry;
-
- if (!cpu_model)
- cpu_model = "cfv4e";
- cpu = cpu_m68k_init(cpu_model);
- if (!cpu) {
- fprintf(stderr, "Unable to find m68k CPU definition\n");
- exit(1);
- }
- env = &cpu->env;
-
- /* Initialize CPU registers. */
- env->vbr = 0;
-
- /* RAM at address zero */
- memory_region_allocate_system_memory(ram, NULL, "dummy_m68k.ram",
- ram_size);
- memory_region_add_subregion(address_space_mem, 0, ram);
-
- /* Load kernel. */
- if (kernel_filename) {
- kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry,
- NULL, NULL, 1, EM_68K, 0, 0);
- entry = elf_entry;
- if (kernel_size < 0) {
- kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL,
- NULL, NULL);
- }
- if (kernel_size < 0) {
- kernel_size = load_image_targphys(kernel_filename,
- KERNEL_LOAD_ADDR,
- ram_size - KERNEL_LOAD_ADDR);
- entry = KERNEL_LOAD_ADDR;
- }
- if (kernel_size < 0) {
- fprintf(stderr, "qemu: could not load kernel '%s'\n",
- kernel_filename);
- exit(1);
- }
- } else {
- entry = 0;
- }
- env->pc = entry;
-}
-
-static void dummy_m68k_machine_init(MachineClass *mc)
-{
- mc->desc = "Dummy board";
- mc->init = dummy_m68k_init;
-}
-
-DEFINE_MACHINE("dummy", dummy_m68k_machine_init)
diff --git a/qemu/hw/m68k/mcf5206.c b/qemu/hw/m68k/mcf5206.c
deleted file mode 100644
index e14896e52..000000000
--- a/qemu/hw/m68k/mcf5206.c
+++ /dev/null
@@ -1,551 +0,0 @@
-/*
- * Motorola ColdFire MCF5206 SoC embedded peripheral emulation.
- *
- * Copyright (c) 2007 CodeSourcery.
- *
- * This code is licensed under the GPL
- */
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/hw.h"
-#include "hw/m68k/mcf.h"
-#include "qemu/timer.h"
-#include "hw/ptimer.h"
-#include "sysemu/sysemu.h"
-#include "exec/address-spaces.h"
-
-/* General purpose timer module. */
-typedef struct {
- uint16_t tmr;
- uint16_t trr;
- uint16_t tcr;
- uint16_t ter;
- ptimer_state *timer;
- qemu_irq irq;
- int irq_state;
-} m5206_timer_state;
-
-#define TMR_RST 0x01
-#define TMR_CLK 0x06
-#define TMR_FRR 0x08
-#define TMR_ORI 0x10
-#define TMR_OM 0x20
-#define TMR_CE 0xc0
-
-#define TER_CAP 0x01
-#define TER_REF 0x02
-
-static void m5206_timer_update(m5206_timer_state *s)
-{
- if ((s->tmr & TMR_ORI) != 0 && (s->ter & TER_REF))
- qemu_irq_raise(s->irq);
- else
- qemu_irq_lower(s->irq);
-}
-
-static void m5206_timer_reset(m5206_timer_state *s)
-{
- s->tmr = 0;
- s->trr = 0;
-}
-
-static void m5206_timer_recalibrate(m5206_timer_state *s)
-{
- int prescale;
- int mode;
-
- ptimer_stop(s->timer);
-
- if ((s->tmr & TMR_RST) == 0)
- return;
-
- prescale = (s->tmr >> 8) + 1;
- mode = (s->tmr >> 1) & 3;
- if (mode == 2)
- prescale *= 16;
-
- if (mode == 3 || mode == 0)
- hw_error("m5206_timer: mode %d not implemented\n", mode);
- if ((s->tmr & TMR_FRR) == 0)
- hw_error("m5206_timer: free running mode not implemented\n");
-
- /* Assume 66MHz system clock. */
- ptimer_set_freq(s->timer, 66000000 / prescale);
-
- ptimer_set_limit(s->timer, s->trr, 0);
-
- ptimer_run(s->timer, 0);
-}
-
-static void m5206_timer_trigger(void *opaque)
-{
- m5206_timer_state *s = (m5206_timer_state *)opaque;
- s->ter |= TER_REF;
- m5206_timer_update(s);
-}
-
-static uint32_t m5206_timer_read(m5206_timer_state *s, uint32_t addr)
-{
- switch (addr) {
- case 0:
- return s->tmr;
- case 4:
- return s->trr;
- case 8:
- return s->tcr;
- case 0xc:
- return s->trr - ptimer_get_count(s->timer);
- case 0x11:
- return s->ter;
- default:
- return 0;
- }
-}
-
-static void m5206_timer_write(m5206_timer_state *s, uint32_t addr, uint32_t val)
-{
- switch (addr) {
- case 0:
- if ((s->tmr & TMR_RST) != 0 && (val & TMR_RST) == 0) {
- m5206_timer_reset(s);
- }
- s->tmr = val;
- m5206_timer_recalibrate(s);
- break;
- case 4:
- s->trr = val;
- m5206_timer_recalibrate(s);
- break;
- case 8:
- s->tcr = val;
- break;
- case 0xc:
- ptimer_set_count(s->timer, val);
- break;
- case 0x11:
- s->ter &= ~val;
- break;
- default:
- break;
- }
- m5206_timer_update(s);
-}
-
-static m5206_timer_state *m5206_timer_init(qemu_irq irq)
-{
- m5206_timer_state *s;
- QEMUBH *bh;
-
- s = (m5206_timer_state *)g_malloc0(sizeof(m5206_timer_state));
- bh = qemu_bh_new(m5206_timer_trigger, s);
- s->timer = ptimer_init(bh);
- s->irq = irq;
- m5206_timer_reset(s);
- return s;
-}
-
-/* System Integration Module. */
-
-typedef struct {
- M68kCPU *cpu;
- MemoryRegion iomem;
- m5206_timer_state *timer[2];
- void *uart[2];
- uint8_t scr;
- uint8_t icr[14];
- uint16_t imr; /* 1 == interrupt is masked. */
- uint16_t ipr;
- uint8_t rsr;
- uint8_t swivr;
- uint8_t par;
- /* Include the UART vector registers here. */
- uint8_t uivr[2];
-} m5206_mbar_state;
-
-/* Interrupt controller. */
-
-static int m5206_find_pending_irq(m5206_mbar_state *s)
-{
- int level;
- int vector;
- uint16_t active;
- int i;
-
- level = 0;
- vector = 0;
- active = s->ipr & ~s->imr;
- if (!active)
- return 0;
-
- for (i = 1; i < 14; i++) {
- if (active & (1 << i)) {
- if ((s->icr[i] & 0x1f) > level) {
- level = s->icr[i] & 0x1f;
- vector = i;
- }
- }
- }
-
- if (level < 4)
- vector = 0;
-
- return vector;
-}
-
-static void m5206_mbar_update(m5206_mbar_state *s)
-{
- int irq;
- int vector;
- int level;
-
- irq = m5206_find_pending_irq(s);
- if (irq) {
- int tmp;
- tmp = s->icr[irq];
- level = (tmp >> 2) & 7;
- if (tmp & 0x80) {
- /* Autovector. */
- vector = 24 + level;
- } else {
- switch (irq) {
- case 8: /* SWT */
- vector = s->swivr;
- break;
- case 12: /* UART1 */
- vector = s->uivr[0];
- break;
- case 13: /* UART2 */
- vector = s->uivr[1];
- break;
- default:
- /* Unknown vector. */
- fprintf(stderr, "Unhandled vector for IRQ %d\n", irq);
- vector = 0xf;
- break;
- }
- }
- } else {
- level = 0;
- vector = 0;
- }
- m68k_set_irq_level(s->cpu, level, vector);
-}
-
-static void m5206_mbar_set_irq(void *opaque, int irq, int level)
-{
- m5206_mbar_state *s = (m5206_mbar_state *)opaque;
- if (level) {
- s->ipr |= 1 << irq;
- } else {
- s->ipr &= ~(1 << irq);
- }
- m5206_mbar_update(s);
-}
-
-/* System Integration Module. */
-
-static void m5206_mbar_reset(m5206_mbar_state *s)
-{
- s->scr = 0xc0;
- s->icr[1] = 0x04;
- s->icr[2] = 0x08;
- s->icr[3] = 0x0c;
- s->icr[4] = 0x10;
- s->icr[5] = 0x14;
- s->icr[6] = 0x18;
- s->icr[7] = 0x1c;
- s->icr[8] = 0x1c;
- s->icr[9] = 0x80;
- s->icr[10] = 0x80;
- s->icr[11] = 0x80;
- s->icr[12] = 0x00;
- s->icr[13] = 0x00;
- s->imr = 0x3ffe;
- s->rsr = 0x80;
- s->swivr = 0x0f;
- s->par = 0;
-}
-
-static uint64_t m5206_mbar_read(m5206_mbar_state *s,
- uint64_t offset, unsigned size)
-{
- if (offset >= 0x100 && offset < 0x120) {
- return m5206_timer_read(s->timer[0], offset - 0x100);
- } else if (offset >= 0x120 && offset < 0x140) {
- return m5206_timer_read(s->timer[1], offset - 0x120);
- } else if (offset >= 0x140 && offset < 0x160) {
- return mcf_uart_read(s->uart[0], offset - 0x140, size);
- } else if (offset >= 0x180 && offset < 0x1a0) {
- return mcf_uart_read(s->uart[1], offset - 0x180, size);
- }
- switch (offset) {
- case 0x03: return s->scr;
- case 0x14 ... 0x20: return s->icr[offset - 0x13];
- case 0x36: return s->imr;
- case 0x3a: return s->ipr;
- case 0x40: return s->rsr;
- case 0x41: return 0;
- case 0x42: return s->swivr;
- case 0x50:
- /* DRAM mask register. */
- /* FIXME: currently hardcoded to 128Mb. */
- {
- uint32_t mask = ~0;
- while (mask > ram_size)
- mask >>= 1;
- return mask & 0x0ffe0000;
- }
- case 0x5c: return 1; /* DRAM bank 1 empty. */
- case 0xcb: return s->par;
- case 0x170: return s->uivr[0];
- case 0x1b0: return s->uivr[1];
- }
- hw_error("Bad MBAR read offset 0x%x", (int)offset);
- return 0;
-}
-
-static void m5206_mbar_write(m5206_mbar_state *s, uint32_t offset,
- uint64_t value, unsigned size)
-{
- if (offset >= 0x100 && offset < 0x120) {
- m5206_timer_write(s->timer[0], offset - 0x100, value);
- return;
- } else if (offset >= 0x120 && offset < 0x140) {
- m5206_timer_write(s->timer[1], offset - 0x120, value);
- return;
- } else if (offset >= 0x140 && offset < 0x160) {
- mcf_uart_write(s->uart[0], offset - 0x140, value, size);
- return;
- } else if (offset >= 0x180 && offset < 0x1a0) {
- mcf_uart_write(s->uart[1], offset - 0x180, value, size);
- return;
- }
- switch (offset) {
- case 0x03:
- s->scr = value;
- break;
- case 0x14 ... 0x20:
- s->icr[offset - 0x13] = value;
- m5206_mbar_update(s);
- break;
- case 0x36:
- s->imr = value;
- m5206_mbar_update(s);
- break;
- case 0x40:
- s->rsr &= ~value;
- break;
- case 0x41:
- /* TODO: implement watchdog. */
- break;
- case 0x42:
- s->swivr = value;
- break;
- case 0xcb:
- s->par = value;
- break;
- case 0x170:
- s->uivr[0] = value;
- break;
- case 0x178: case 0x17c: case 0x1c8: case 0x1bc:
- /* Not implemented: UART Output port bits. */
- break;
- case 0x1b0:
- s->uivr[1] = value;
- break;
- default:
- hw_error("Bad MBAR write offset 0x%x", (int)offset);
- break;
- }
-}
-
-/* Internal peripherals use a variety of register widths.
- This lookup table allows a single routine to handle all of them. */
-static const uint8_t m5206_mbar_width[] =
-{
- /* 000-040 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
- /* 040-080 */ 1, 2, 2, 2, 4, 1, 2, 4, 1, 2, 4, 2, 2, 4, 2, 2,
- /* 080-0c0 */ 4, 2, 2, 4, 2, 2, 4, 2, 2, 4, 2, 2, 4, 2, 2, 4,
- /* 0c0-100 */ 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 100-140 */ 2, 2, 2, 2, 1, 0, 0, 0, 2, 2, 2, 2, 1, 0, 0, 0,
- /* 140-180 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- /* 180-1c0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- /* 1c0-200 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-};
-
-static uint32_t m5206_mbar_readw(void *opaque, hwaddr offset);
-static uint32_t m5206_mbar_readl(void *opaque, hwaddr offset);
-
-static uint32_t m5206_mbar_readb(void *opaque, hwaddr offset)
-{
- m5206_mbar_state *s = (m5206_mbar_state *)opaque;
- offset &= 0x3ff;
- if (offset >= 0x200) {
- hw_error("Bad MBAR read offset 0x%x", (int)offset);
- }
- if (m5206_mbar_width[offset >> 2] > 1) {
- uint16_t val;
- val = m5206_mbar_readw(opaque, offset & ~1);
- if ((offset & 1) == 0) {
- val >>= 8;
- }
- return val & 0xff;
- }
- return m5206_mbar_read(s, offset, 1);
-}
-
-static uint32_t m5206_mbar_readw(void *opaque, hwaddr offset)
-{
- m5206_mbar_state *s = (m5206_mbar_state *)opaque;
- int width;
- offset &= 0x3ff;
- if (offset >= 0x200) {
- hw_error("Bad MBAR read offset 0x%x", (int)offset);
- }
- width = m5206_mbar_width[offset >> 2];
- if (width > 2) {
- uint32_t val;
- val = m5206_mbar_readl(opaque, offset & ~3);
- if ((offset & 3) == 0)
- val >>= 16;
- return val & 0xffff;
- } else if (width < 2) {
- uint16_t val;
- val = m5206_mbar_readb(opaque, offset) << 8;
- val |= m5206_mbar_readb(opaque, offset + 1);
- return val;
- }
- return m5206_mbar_read(s, offset, 2);
-}
-
-static uint32_t m5206_mbar_readl(void *opaque, hwaddr offset)
-{
- m5206_mbar_state *s = (m5206_mbar_state *)opaque;
- int width;
- offset &= 0x3ff;
- if (offset >= 0x200) {
- hw_error("Bad MBAR read offset 0x%x", (int)offset);
- }
- width = m5206_mbar_width[offset >> 2];
- if (width < 4) {
- uint32_t val;
- val = m5206_mbar_readw(opaque, offset) << 16;
- val |= m5206_mbar_readw(opaque, offset + 2);
- return val;
- }
- return m5206_mbar_read(s, offset, 4);
-}
-
-static void m5206_mbar_writew(void *opaque, hwaddr offset,
- uint32_t value);
-static void m5206_mbar_writel(void *opaque, hwaddr offset,
- uint32_t value);
-
-static void m5206_mbar_writeb(void *opaque, hwaddr offset,
- uint32_t value)
-{
- m5206_mbar_state *s = (m5206_mbar_state *)opaque;
- int width;
- offset &= 0x3ff;
- if (offset >= 0x200) {
- hw_error("Bad MBAR write offset 0x%x", (int)offset);
- }
- width = m5206_mbar_width[offset >> 2];
- if (width > 1) {
- uint32_t tmp;
- tmp = m5206_mbar_readw(opaque, offset & ~1);
- if (offset & 1) {
- tmp = (tmp & 0xff00) | value;
- } else {
- tmp = (tmp & 0x00ff) | (value << 8);
- }
- m5206_mbar_writew(opaque, offset & ~1, tmp);
- return;
- }
- m5206_mbar_write(s, offset, value, 1);
-}
-
-static void m5206_mbar_writew(void *opaque, hwaddr offset,
- uint32_t value)
-{
- m5206_mbar_state *s = (m5206_mbar_state *)opaque;
- int width;
- offset &= 0x3ff;
- if (offset >= 0x200) {
- hw_error("Bad MBAR write offset 0x%x", (int)offset);
- }
- width = m5206_mbar_width[offset >> 2];
- if (width > 2) {
- uint32_t tmp;
- tmp = m5206_mbar_readl(opaque, offset & ~3);
- if (offset & 3) {
- tmp = (tmp & 0xffff0000) | value;
- } else {
- tmp = (tmp & 0x0000ffff) | (value << 16);
- }
- m5206_mbar_writel(opaque, offset & ~3, tmp);
- return;
- } else if (width < 2) {
- m5206_mbar_writeb(opaque, offset, value >> 8);
- m5206_mbar_writeb(opaque, offset + 1, value & 0xff);
- return;
- }
- m5206_mbar_write(s, offset, value, 2);
-}
-
-static void m5206_mbar_writel(void *opaque, hwaddr offset,
- uint32_t value)
-{
- m5206_mbar_state *s = (m5206_mbar_state *)opaque;
- int width;
- offset &= 0x3ff;
- if (offset >= 0x200) {
- hw_error("Bad MBAR write offset 0x%x", (int)offset);
- }
- width = m5206_mbar_width[offset >> 2];
- if (width < 4) {
- m5206_mbar_writew(opaque, offset, value >> 16);
- m5206_mbar_writew(opaque, offset + 2, value & 0xffff);
- return;
- }
- m5206_mbar_write(s, offset, value, 4);
-}
-
-static const MemoryRegionOps m5206_mbar_ops = {
- .old_mmio = {
- .read = {
- m5206_mbar_readb,
- m5206_mbar_readw,
- m5206_mbar_readl,
- },
- .write = {
- m5206_mbar_writeb,
- m5206_mbar_writew,
- m5206_mbar_writel,
- },
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-qemu_irq *mcf5206_init(MemoryRegion *sysmem, uint32_t base, M68kCPU *cpu)
-{
- m5206_mbar_state *s;
- qemu_irq *pic;
-
- s = (m5206_mbar_state *)g_malloc0(sizeof(m5206_mbar_state));
-
- memory_region_init_io(&s->iomem, NULL, &m5206_mbar_ops, s,
- "mbar", 0x00001000);
- memory_region_add_subregion(sysmem, base, &s->iomem);
-
- pic = qemu_allocate_irqs(m5206_mbar_set_irq, s, 14);
- s->timer[0] = m5206_timer_init(pic[9]);
- s->timer[1] = m5206_timer_init(pic[10]);
- s->uart[0] = mcf_uart_init(pic[12], serial_hds[0]);
- s->uart[1] = mcf_uart_init(pic[13], serial_hds[1]);
- s->cpu = cpu;
-
- m5206_mbar_reset(s);
- return pic;
-}
diff --git a/qemu/hw/m68k/mcf5208.c b/qemu/hw/m68k/mcf5208.c
deleted file mode 100644
index 24155574f..000000000
--- a/qemu/hw/m68k/mcf5208.c
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * Motorola ColdFire MCF5208 SoC emulation.
- *
- * Copyright (c) 2007 CodeSourcery.
- *
- * This code is licensed under the GPL
- */
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/hw.h"
-#include "hw/m68k/mcf.h"
-#include "qemu/timer.h"
-#include "hw/ptimer.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/qtest.h"
-#include "net/net.h"
-#include "hw/boards.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "exec/address-spaces.h"
-
-#define SYS_FREQ 66000000
-
-#define PCSR_EN 0x0001
-#define PCSR_RLD 0x0002
-#define PCSR_PIF 0x0004
-#define PCSR_PIE 0x0008
-#define PCSR_OVW 0x0010
-#define PCSR_DBG 0x0020
-#define PCSR_DOZE 0x0040
-#define PCSR_PRE_SHIFT 8
-#define PCSR_PRE_MASK 0x0f00
-
-typedef struct {
- MemoryRegion iomem;
- qemu_irq irq;
- ptimer_state *timer;
- uint16_t pcsr;
- uint16_t pmr;
- uint16_t pcntr;
-} m5208_timer_state;
-
-static void m5208_timer_update(m5208_timer_state *s)
-{
- if ((s->pcsr & (PCSR_PIE | PCSR_PIF)) == (PCSR_PIE | PCSR_PIF))
- qemu_irq_raise(s->irq);
- else
- qemu_irq_lower(s->irq);
-}
-
-static void m5208_timer_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- m5208_timer_state *s = (m5208_timer_state *)opaque;
- int prescale;
- int limit;
- switch (offset) {
- case 0:
- /* The PIF bit is set-to-clear. */
- if (value & PCSR_PIF) {
- s->pcsr &= ~PCSR_PIF;
- value &= ~PCSR_PIF;
- }
- /* Avoid frobbing the timer if we're just twiddling IRQ bits. */
- if (((s->pcsr ^ value) & ~PCSR_PIE) == 0) {
- s->pcsr = value;
- m5208_timer_update(s);
- return;
- }
-
- if (s->pcsr & PCSR_EN)
- ptimer_stop(s->timer);
-
- s->pcsr = value;
-
- prescale = 1 << ((s->pcsr & PCSR_PRE_MASK) >> PCSR_PRE_SHIFT);
- ptimer_set_freq(s->timer, (SYS_FREQ / 2) / prescale);
- if (s->pcsr & PCSR_RLD)
- limit = s->pmr;
- else
- limit = 0xffff;
- ptimer_set_limit(s->timer, limit, 0);
-
- if (s->pcsr & PCSR_EN)
- ptimer_run(s->timer, 0);
- break;
- case 2:
- s->pmr = value;
- s->pcsr &= ~PCSR_PIF;
- if ((s->pcsr & PCSR_RLD) == 0) {
- if (s->pcsr & PCSR_OVW)
- ptimer_set_count(s->timer, value);
- } else {
- ptimer_set_limit(s->timer, value, s->pcsr & PCSR_OVW);
- }
- break;
- case 4:
- break;
- default:
- hw_error("m5208_timer_write: Bad offset 0x%x\n", (int)offset);
- break;
- }
- m5208_timer_update(s);
-}
-
-static void m5208_timer_trigger(void *opaque)
-{
- m5208_timer_state *s = (m5208_timer_state *)opaque;
- s->pcsr |= PCSR_PIF;
- m5208_timer_update(s);
-}
-
-static uint64_t m5208_timer_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- m5208_timer_state *s = (m5208_timer_state *)opaque;
- switch (addr) {
- case 0:
- return s->pcsr;
- case 2:
- return s->pmr;
- case 4:
- return ptimer_get_count(s->timer);
- default:
- hw_error("m5208_timer_read: Bad offset 0x%x\n", (int)addr);
- return 0;
- }
-}
-
-static const MemoryRegionOps m5208_timer_ops = {
- .read = m5208_timer_read,
- .write = m5208_timer_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static uint64_t m5208_sys_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- switch (addr) {
- case 0x110: /* SDCS0 */
- {
- int n;
- for (n = 0; n < 32; n++) {
- if (ram_size < (2u << n))
- break;
- }
- return (n - 1) | 0x40000000;
- }
- case 0x114: /* SDCS1 */
- return 0;
-
- default:
- hw_error("m5208_sys_read: Bad offset 0x%x\n", (int)addr);
- return 0;
- }
-}
-
-static void m5208_sys_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- hw_error("m5208_sys_write: Bad offset 0x%x\n", (int)addr);
-}
-
-static const MemoryRegionOps m5208_sys_ops = {
- .read = m5208_sys_read,
- .write = m5208_sys_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void mcf5208_sys_init(MemoryRegion *address_space, qemu_irq *pic)
-{
- MemoryRegion *iomem = g_new(MemoryRegion, 1);
- m5208_timer_state *s;
- QEMUBH *bh;
- int i;
-
- /* SDRAMC. */
- memory_region_init_io(iomem, NULL, &m5208_sys_ops, NULL, "m5208-sys", 0x00004000);
- memory_region_add_subregion(address_space, 0xfc0a8000, iomem);
- /* Timers. */
- for (i = 0; i < 2; i++) {
- s = (m5208_timer_state *)g_malloc0(sizeof(m5208_timer_state));
- bh = qemu_bh_new(m5208_timer_trigger, s);
- s->timer = ptimer_init(bh);
- memory_region_init_io(&s->iomem, NULL, &m5208_timer_ops, s,
- "m5208-timer", 0x00004000);
- memory_region_add_subregion(address_space, 0xfc080000 + 0x4000 * i,
- &s->iomem);
- s->irq = pic[4 + i];
- }
-}
-
-static void mcf5208evb_init(MachineState *machine)
-{
- ram_addr_t ram_size = machine->ram_size;
- const char *cpu_model = machine->cpu_model;
- const char *kernel_filename = machine->kernel_filename;
- M68kCPU *cpu;
- CPUM68KState *env;
- int kernel_size;
- uint64_t elf_entry;
- hwaddr entry;
- qemu_irq *pic;
- MemoryRegion *address_space_mem = get_system_memory();
- MemoryRegion *ram = g_new(MemoryRegion, 1);
- MemoryRegion *sram = g_new(MemoryRegion, 1);
-
- if (!cpu_model) {
- cpu_model = "m5208";
- }
- cpu = cpu_m68k_init(cpu_model);
- if (!cpu) {
- fprintf(stderr, "Unable to find m68k CPU definition\n");
- exit(1);
- }
- env = &cpu->env;
-
- /* Initialize CPU registers. */
- env->vbr = 0;
- /* TODO: Configure BARs. */
-
- /* DRAM at 0x40000000 */
- memory_region_allocate_system_memory(ram, NULL, "mcf5208.ram", ram_size);
- memory_region_add_subregion(address_space_mem, 0x40000000, ram);
-
- /* Internal SRAM. */
- memory_region_init_ram(sram, NULL, "mcf5208.sram", 16384, &error_fatal);
- vmstate_register_ram_global(sram);
- memory_region_add_subregion(address_space_mem, 0x80000000, sram);
-
- /* Internal peripherals. */
- pic = mcf_intc_init(address_space_mem, 0xfc048000, cpu);
-
- mcf_uart_mm_init(address_space_mem, 0xfc060000, pic[26], serial_hds[0]);
- mcf_uart_mm_init(address_space_mem, 0xfc064000, pic[27], serial_hds[1]);
- mcf_uart_mm_init(address_space_mem, 0xfc068000, pic[28], serial_hds[2]);
-
- mcf5208_sys_init(address_space_mem, pic);
-
- if (nb_nics > 1) {
- fprintf(stderr, "Too many NICs\n");
- exit(1);
- }
- if (nd_table[0].used)
- mcf_fec_init(address_space_mem, &nd_table[0],
- 0xfc030000, pic + 36);
-
- /* 0xfc000000 SCM. */
- /* 0xfc004000 XBS. */
- /* 0xfc008000 FlexBus CS. */
- /* 0xfc030000 FEC. */
- /* 0xfc040000 SCM + Power management. */
- /* 0xfc044000 eDMA. */
- /* 0xfc048000 INTC. */
- /* 0xfc058000 I2C. */
- /* 0xfc05c000 QSPI. */
- /* 0xfc060000 UART0. */
- /* 0xfc064000 UART0. */
- /* 0xfc068000 UART0. */
- /* 0xfc070000 DMA timers. */
- /* 0xfc080000 PIT0. */
- /* 0xfc084000 PIT1. */
- /* 0xfc088000 EPORT. */
- /* 0xfc08c000 Watchdog. */
- /* 0xfc090000 clock module. */
- /* 0xfc0a0000 CCM + reset. */
- /* 0xfc0a4000 GPIO. */
- /* 0xfc0a8000 SDRAM controller. */
-
- /* Load kernel. */
- if (!kernel_filename) {
- if (qtest_enabled()) {
- return;
- }
- fprintf(stderr, "Kernel image must be specified\n");
- exit(1);
- }
-
- kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry,
- NULL, NULL, 1, EM_68K, 0, 0);
- entry = elf_entry;
- if (kernel_size < 0) {
- kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL,
- NULL, NULL);
- }
- if (kernel_size < 0) {
- kernel_size = load_image_targphys(kernel_filename, 0x40000000,
- ram_size);
- entry = 0x40000000;
- }
- if (kernel_size < 0) {
- fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename);
- exit(1);
- }
-
- env->pc = entry;
-}
-
-static void mcf5208evb_machine_init(MachineClass *mc)
-{
- mc->desc = "MCF5206EVB";
- mc->init = mcf5208evb_init;
- mc->is_default = 1;
-}
-
-DEFINE_MACHINE("mcf5208evb", mcf5208evb_machine_init)
diff --git a/qemu/hw/m68k/mcf_intc.c b/qemu/hw/m68k/mcf_intc.c
deleted file mode 100644
index cf581324e..000000000
--- a/qemu/hw/m68k/mcf_intc.c
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * ColdFire Interrupt Controller emulation.
- *
- * Copyright (c) 2007 CodeSourcery.
- *
- * This code is licensed under the GPL
- */
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/hw.h"
-#include "hw/m68k/mcf.h"
-#include "exec/address-spaces.h"
-
-typedef struct {
- MemoryRegion iomem;
- uint64_t ipr;
- uint64_t imr;
- uint64_t ifr;
- uint64_t enabled;
- uint8_t icr[64];
- M68kCPU *cpu;
- int active_vector;
-} mcf_intc_state;
-
-static void mcf_intc_update(mcf_intc_state *s)
-{
- uint64_t active;
- int i;
- int best;
- int best_level;
-
- active = (s->ipr | s->ifr) & s->enabled & ~s->imr;
- best_level = 0;
- best = 64;
- if (active) {
- for (i = 0; i < 64; i++) {
- if ((active & 1) != 0 && s->icr[i] >= best_level) {
- best_level = s->icr[i];
- best = i;
- }
- active >>= 1;
- }
- }
- s->active_vector = ((best == 64) ? 24 : (best + 64));
- m68k_set_irq_level(s->cpu, best_level, s->active_vector);
-}
-
-static uint64_t mcf_intc_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- int offset;
- mcf_intc_state *s = (mcf_intc_state *)opaque;
- offset = addr & 0xff;
- if (offset >= 0x40 && offset < 0x80) {
- return s->icr[offset - 0x40];
- }
- switch (offset) {
- case 0x00:
- return (uint32_t)(s->ipr >> 32);
- case 0x04:
- return (uint32_t)s->ipr;
- case 0x08:
- return (uint32_t)(s->imr >> 32);
- case 0x0c:
- return (uint32_t)s->imr;
- case 0x10:
- return (uint32_t)(s->ifr >> 32);
- case 0x14:
- return (uint32_t)s->ifr;
- case 0xe0: /* SWIACK. */
- return s->active_vector;
- case 0xe1: case 0xe2: case 0xe3: case 0xe4:
- case 0xe5: case 0xe6: case 0xe7:
- /* LnIACK */
- hw_error("mcf_intc_read: LnIACK not implemented\n");
- default:
- return 0;
- }
-}
-
-static void mcf_intc_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- int offset;
- mcf_intc_state *s = (mcf_intc_state *)opaque;
- offset = addr & 0xff;
- if (offset >= 0x40 && offset < 0x80) {
- int n = offset - 0x40;
- s->icr[n] = val;
- if (val == 0)
- s->enabled &= ~(1ull << n);
- else
- s->enabled |= (1ull << n);
- mcf_intc_update(s);
- return;
- }
- switch (offset) {
- case 0x00: case 0x04:
- /* Ignore IPR writes. */
- return;
- case 0x08:
- s->imr = (s->imr & 0xffffffff) | ((uint64_t)val << 32);
- break;
- case 0x0c:
- s->imr = (s->imr & 0xffffffff00000000ull) | (uint32_t)val;
- break;
- case 0x1c:
- if (val & 0x40) {
- s->imr = ~0ull;
- } else {
- s->imr |= (0x1ull << (val & 0x3f));
- }
- break;
- case 0x1d:
- if (val & 0x40) {
- s->imr = 0ull;
- } else {
- s->imr &= ~(0x1ull << (val & 0x3f));
- }
- break;
- default:
- hw_error("mcf_intc_write: Bad write offset %d\n", offset);
- break;
- }
- mcf_intc_update(s);
-}
-
-static void mcf_intc_set_irq(void *opaque, int irq, int level)
-{
- mcf_intc_state *s = (mcf_intc_state *)opaque;
- if (irq >= 64)
- return;
- if (level)
- s->ipr |= 1ull << irq;
- else
- s->ipr &= ~(1ull << irq);
- mcf_intc_update(s);
-}
-
-static void mcf_intc_reset(mcf_intc_state *s)
-{
- s->imr = ~0ull;
- s->ipr = 0;
- s->ifr = 0;
- s->enabled = 0;
- memset(s->icr, 0, 64);
- s->active_vector = 24;
-}
-
-static const MemoryRegionOps mcf_intc_ops = {
- .read = mcf_intc_read,
- .write = mcf_intc_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-qemu_irq *mcf_intc_init(MemoryRegion *sysmem,
- hwaddr base,
- M68kCPU *cpu)
-{
- mcf_intc_state *s;
-
- s = g_malloc0(sizeof(mcf_intc_state));
- s->cpu = cpu;
- mcf_intc_reset(s);
-
- memory_region_init_io(&s->iomem, NULL, &mcf_intc_ops, s, "mcf", 0x100);
- memory_region_add_subregion(sysmem, base, &s->iomem);
-
- return qemu_allocate_irqs(mcf_intc_set_irq, s, 64);
-}
diff --git a/qemu/hw/mem/Makefile.objs b/qemu/hw/mem/Makefile.objs
deleted file mode 100644
index f12f8b97a..000000000
--- a/qemu/hw/mem/Makefile.objs
+++ /dev/null
@@ -1,2 +0,0 @@
-common-obj-$(CONFIG_MEM_HOTPLUG) += pc-dimm.o
-common-obj-$(CONFIG_NVDIMM) += nvdimm.o
diff --git a/qemu/hw/mem/nvdimm.c b/qemu/hw/mem/nvdimm.c
deleted file mode 100644
index 0a602f28b..000000000
--- a/qemu/hw/mem/nvdimm.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Non-Volatile Dual In-line Memory Module Virtualization Implementation
- *
- * Copyright(C) 2015 Intel Corporation.
- *
- * Author:
- * Xiao Guangrong <guangrong.xiao@linux.intel.com>
- *
- * Currently, it only supports PMEM Virtualization.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>
- */
-
-#include "qemu/osdep.h"
-#include "hw/mem/nvdimm.h"
-
-static void nvdimm_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- /* nvdimm hotplug has not been supported yet. */
- dc->hotpluggable = false;
-}
-
-static TypeInfo nvdimm_info = {
- .name = TYPE_NVDIMM,
- .parent = TYPE_PC_DIMM,
- .class_init = nvdimm_class_init,
-};
-
-static void nvdimm_register_types(void)
-{
- type_register_static(&nvdimm_info);
-}
-
-type_init(nvdimm_register_types)
diff --git a/qemu/hw/mem/pc-dimm.c b/qemu/hw/mem/pc-dimm.c
deleted file mode 100644
index 9e7de5682..000000000
--- a/qemu/hw/mem/pc-dimm.c
+++ /dev/null
@@ -1,447 +0,0 @@
-/*
- * Dimm device for Memory Hotplug
- *
- * Copyright ProfitBricks GmbH 2012
- * Copyright (C) 2014 Red Hat Inc
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>
- */
-
-#include "qemu/osdep.h"
-#include "hw/mem/pc-dimm.h"
-#include "qapi/error.h"
-#include "qemu/config-file.h"
-#include "qapi/visitor.h"
-#include "qemu/range.h"
-#include "sysemu/numa.h"
-#include "sysemu/kvm.h"
-#include "trace.h"
-#include "hw/virtio/vhost.h"
-
-typedef struct pc_dimms_capacity {
- uint64_t size;
- Error **errp;
-} pc_dimms_capacity;
-
-void pc_dimm_memory_plug(DeviceState *dev, MemoryHotplugState *hpms,
- MemoryRegion *mr, uint64_t align, Error **errp)
-{
- int slot;
- MachineState *machine = MACHINE(qdev_get_machine());
- PCDIMMDevice *dimm = PC_DIMM(dev);
- Error *local_err = NULL;
- uint64_t existing_dimms_capacity = 0;
- uint64_t addr;
-
- addr = object_property_get_int(OBJECT(dimm), PC_DIMM_ADDR_PROP, &local_err);
- if (local_err) {
- goto out;
- }
-
- addr = pc_dimm_get_free_addr(hpms->base,
- memory_region_size(&hpms->mr),
- !addr ? NULL : &addr, align,
- memory_region_size(mr), &local_err);
- if (local_err) {
- goto out;
- }
-
- existing_dimms_capacity = pc_existing_dimms_capacity(&local_err);
- if (local_err) {
- goto out;
- }
-
- if (existing_dimms_capacity + memory_region_size(mr) >
- machine->maxram_size - machine->ram_size) {
- error_setg(&local_err, "not enough space, currently 0x%" PRIx64
- " in use of total hot pluggable 0x" RAM_ADDR_FMT,
- existing_dimms_capacity,
- machine->maxram_size - machine->ram_size);
- goto out;
- }
-
- object_property_set_int(OBJECT(dev), addr, PC_DIMM_ADDR_PROP, &local_err);
- if (local_err) {
- goto out;
- }
- trace_mhp_pc_dimm_assigned_address(addr);
-
- slot = object_property_get_int(OBJECT(dev), PC_DIMM_SLOT_PROP, &local_err);
- if (local_err) {
- goto out;
- }
-
- slot = pc_dimm_get_free_slot(slot == PC_DIMM_UNASSIGNED_SLOT ? NULL : &slot,
- machine->ram_slots, &local_err);
- if (local_err) {
- goto out;
- }
- object_property_set_int(OBJECT(dev), slot, PC_DIMM_SLOT_PROP, &local_err);
- if (local_err) {
- goto out;
- }
- trace_mhp_pc_dimm_assigned_slot(slot);
-
- if (kvm_enabled() && !kvm_has_free_slot(machine)) {
- error_setg(&local_err, "hypervisor has no free memory slots left");
- goto out;
- }
-
- if (!vhost_has_free_slot()) {
- error_setg(&local_err, "a used vhost backend has no free"
- " memory slots left");
- goto out;
- }
-
- memory_region_add_subregion(&hpms->mr, addr - hpms->base, mr);
- vmstate_register_ram(mr, dev);
- numa_set_mem_node_id(addr, memory_region_size(mr), dimm->node);
-
-out:
- error_propagate(errp, local_err);
-}
-
-void pc_dimm_memory_unplug(DeviceState *dev, MemoryHotplugState *hpms,
- MemoryRegion *mr)
-{
- PCDIMMDevice *dimm = PC_DIMM(dev);
-
- numa_unset_mem_node_id(dimm->addr, memory_region_size(mr), dimm->node);
- memory_region_del_subregion(&hpms->mr, mr);
- vmstate_unregister_ram(mr, dev);
-}
-
-static int pc_existing_dimms_capacity_internal(Object *obj, void *opaque)
-{
- pc_dimms_capacity *cap = opaque;
- uint64_t *size = &cap->size;
-
- if (object_dynamic_cast(obj, TYPE_PC_DIMM)) {
- DeviceState *dev = DEVICE(obj);
-
- if (dev->realized) {
- (*size) += object_property_get_int(obj, PC_DIMM_SIZE_PROP,
- cap->errp);
- }
-
- if (cap->errp && *cap->errp) {
- return 1;
- }
- }
- object_child_foreach(obj, pc_existing_dimms_capacity_internal, opaque);
- return 0;
-}
-
-uint64_t pc_existing_dimms_capacity(Error **errp)
-{
- pc_dimms_capacity cap;
-
- cap.size = 0;
- cap.errp = errp;
-
- pc_existing_dimms_capacity_internal(qdev_get_machine(), &cap);
- return cap.size;
-}
-
-int qmp_pc_dimm_device_list(Object *obj, void *opaque)
-{
- MemoryDeviceInfoList ***prev = opaque;
-
- if (object_dynamic_cast(obj, TYPE_PC_DIMM)) {
- DeviceState *dev = DEVICE(obj);
-
- if (dev->realized) {
- MemoryDeviceInfoList *elem = g_new0(MemoryDeviceInfoList, 1);
- MemoryDeviceInfo *info = g_new0(MemoryDeviceInfo, 1);
- PCDIMMDeviceInfo *di = g_new0(PCDIMMDeviceInfo, 1);
- DeviceClass *dc = DEVICE_GET_CLASS(obj);
- PCDIMMDevice *dimm = PC_DIMM(obj);
-
- if (dev->id) {
- di->has_id = true;
- di->id = g_strdup(dev->id);
- }
- di->hotplugged = dev->hotplugged;
- di->hotpluggable = dc->hotpluggable;
- di->addr = dimm->addr;
- di->slot = dimm->slot;
- di->node = dimm->node;
- di->size = object_property_get_int(OBJECT(dimm), PC_DIMM_SIZE_PROP,
- NULL);
- di->memdev = object_get_canonical_path(OBJECT(dimm->hostmem));
-
- info->u.dimm.data = di;
- elem->value = info;
- elem->next = NULL;
- **prev = elem;
- *prev = &elem->next;
- }
- }
-
- object_child_foreach(obj, qmp_pc_dimm_device_list, opaque);
- return 0;
-}
-
-static int pc_dimm_slot2bitmap(Object *obj, void *opaque)
-{
- unsigned long *bitmap = opaque;
-
- if (object_dynamic_cast(obj, TYPE_PC_DIMM)) {
- DeviceState *dev = DEVICE(obj);
- if (dev->realized) { /* count only realized DIMMs */
- PCDIMMDevice *d = PC_DIMM(obj);
- set_bit(d->slot, bitmap);
- }
- }
-
- object_child_foreach(obj, pc_dimm_slot2bitmap, opaque);
- return 0;
-}
-
-int pc_dimm_get_free_slot(const int *hint, int max_slots, Error **errp)
-{
- unsigned long *bitmap = bitmap_new(max_slots);
- int slot = 0;
-
- object_child_foreach(qdev_get_machine(), pc_dimm_slot2bitmap, bitmap);
-
- /* check if requested slot is not occupied */
- if (hint) {
- if (*hint >= max_slots) {
- error_setg(errp, "invalid slot# %d, should be less than %d",
- *hint, max_slots);
- } else if (!test_bit(*hint, bitmap)) {
- slot = *hint;
- } else {
- error_setg(errp, "slot %d is busy", *hint);
- }
- goto out;
- }
-
- /* search for free slot */
- slot = find_first_zero_bit(bitmap, max_slots);
- if (slot == max_slots) {
- error_setg(errp, "no free slots available");
- }
-out:
- g_free(bitmap);
- return slot;
-}
-
-static gint pc_dimm_addr_sort(gconstpointer a, gconstpointer b)
-{
- PCDIMMDevice *x = PC_DIMM(a);
- PCDIMMDevice *y = PC_DIMM(b);
- Int128 diff = int128_sub(int128_make64(x->addr), int128_make64(y->addr));
-
- if (int128_lt(diff, int128_zero())) {
- return -1;
- } else if (int128_gt(diff, int128_zero())) {
- return 1;
- }
- return 0;
-}
-
-static int pc_dimm_built_list(Object *obj, void *opaque)
-{
- GSList **list = opaque;
-
- if (object_dynamic_cast(obj, TYPE_PC_DIMM)) {
- DeviceState *dev = DEVICE(obj);
- if (dev->realized) { /* only realized DIMMs matter */
- *list = g_slist_insert_sorted(*list, dev, pc_dimm_addr_sort);
- }
- }
-
- object_child_foreach(obj, pc_dimm_built_list, opaque);
- return 0;
-}
-
-uint64_t pc_dimm_get_free_addr(uint64_t address_space_start,
- uint64_t address_space_size,
- uint64_t *hint, uint64_t align, uint64_t size,
- Error **errp)
-{
- GSList *list = NULL, *item;
- uint64_t new_addr, ret = 0;
- uint64_t address_space_end = address_space_start + address_space_size;
-
- g_assert(QEMU_ALIGN_UP(address_space_start, align) == address_space_start);
-
- if (!address_space_size) {
- error_setg(errp, "memory hotplug is not enabled, "
- "please add maxmem option");
- goto out;
- }
-
- if (hint && QEMU_ALIGN_UP(*hint, align) != *hint) {
- error_setg(errp, "address must be aligned to 0x%" PRIx64 " bytes",
- align);
- goto out;
- }
-
- if (QEMU_ALIGN_UP(size, align) != size) {
- error_setg(errp, "backend memory size must be multiple of 0x%"
- PRIx64, align);
- goto out;
- }
-
- assert(address_space_end > address_space_start);
- object_child_foreach(qdev_get_machine(), pc_dimm_built_list, &list);
-
- if (hint) {
- new_addr = *hint;
- } else {
- new_addr = address_space_start;
- }
-
- /* find address range that will fit new DIMM */
- for (item = list; item; item = g_slist_next(item)) {
- PCDIMMDevice *dimm = item->data;
- uint64_t dimm_size = object_property_get_int(OBJECT(dimm),
- PC_DIMM_SIZE_PROP,
- errp);
- if (errp && *errp) {
- goto out;
- }
-
- if (ranges_overlap(dimm->addr, dimm_size, new_addr, size)) {
- if (hint) {
- DeviceState *d = DEVICE(dimm);
- error_setg(errp, "address range conflicts with '%s'", d->id);
- goto out;
- }
- new_addr = QEMU_ALIGN_UP(dimm->addr + dimm_size, align);
- }
- }
- ret = new_addr;
-
- if (new_addr < address_space_start) {
- error_setg(errp, "can't add memory [0x%" PRIx64 ":0x%" PRIx64
- "] at 0x%" PRIx64, new_addr, size, address_space_start);
- } else if ((new_addr + size) > address_space_end) {
- error_setg(errp, "can't add memory [0x%" PRIx64 ":0x%" PRIx64
- "] beyond 0x%" PRIx64, new_addr, size, address_space_end);
- }
-
-out:
- g_slist_free(list);
- return ret;
-}
-
-static Property pc_dimm_properties[] = {
- DEFINE_PROP_UINT64(PC_DIMM_ADDR_PROP, PCDIMMDevice, addr, 0),
- DEFINE_PROP_UINT32(PC_DIMM_NODE_PROP, PCDIMMDevice, node, 0),
- DEFINE_PROP_INT32(PC_DIMM_SLOT_PROP, PCDIMMDevice, slot,
- PC_DIMM_UNASSIGNED_SLOT),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pc_dimm_get_size(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- int64_t value;
- MemoryRegion *mr;
- PCDIMMDevice *dimm = PC_DIMM(obj);
-
- mr = host_memory_backend_get_memory(dimm->hostmem, errp);
- value = memory_region_size(mr);
-
- visit_type_int(v, name, &value, errp);
-}
-
-static void pc_dimm_check_memdev_is_busy(Object *obj, const char *name,
- Object *val, Error **errp)
-{
- MemoryRegion *mr;
- Error *local_err = NULL;
-
- mr = host_memory_backend_get_memory(MEMORY_BACKEND(val), &local_err);
- if (local_err) {
- goto out;
- }
- if (memory_region_is_mapped(mr)) {
- char *path = object_get_canonical_path_component(val);
- error_setg(&local_err, "can't use already busy memdev: %s", path);
- g_free(path);
- } else {
- qdev_prop_allow_set_link_before_realize(obj, name, val, &local_err);
- }
-
-out:
- error_propagate(errp, local_err);
-}
-
-static void pc_dimm_init(Object *obj)
-{
- PCDIMMDevice *dimm = PC_DIMM(obj);
-
- object_property_add(obj, PC_DIMM_SIZE_PROP, "int", pc_dimm_get_size,
- NULL, NULL, NULL, &error_abort);
- object_property_add_link(obj, PC_DIMM_MEMDEV_PROP, TYPE_MEMORY_BACKEND,
- (Object **)&dimm->hostmem,
- pc_dimm_check_memdev_is_busy,
- OBJ_PROP_LINK_UNREF_ON_RELEASE,
- &error_abort);
-}
-
-static void pc_dimm_realize(DeviceState *dev, Error **errp)
-{
- PCDIMMDevice *dimm = PC_DIMM(dev);
-
- if (!dimm->hostmem) {
- error_setg(errp, "'" PC_DIMM_MEMDEV_PROP "' property is not set");
- return;
- }
- if (((nb_numa_nodes > 0) && (dimm->node >= nb_numa_nodes)) ||
- (!nb_numa_nodes && dimm->node)) {
- error_setg(errp, "'DIMM property " PC_DIMM_NODE_PROP " has value %"
- PRIu32 "' which exceeds the number of numa nodes: %d",
- dimm->node, nb_numa_nodes ? nb_numa_nodes : 1);
- return;
- }
-}
-
-static MemoryRegion *pc_dimm_get_memory_region(PCDIMMDevice *dimm)
-{
- return host_memory_backend_get_memory(dimm->hostmem, &error_abort);
-}
-
-static void pc_dimm_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
- PCDIMMDeviceClass *ddc = PC_DIMM_CLASS(oc);
-
- dc->realize = pc_dimm_realize;
- dc->props = pc_dimm_properties;
- dc->desc = "DIMM memory module";
-
- ddc->get_memory_region = pc_dimm_get_memory_region;
-}
-
-static TypeInfo pc_dimm_info = {
- .name = TYPE_PC_DIMM,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(PCDIMMDevice),
- .instance_init = pc_dimm_init,
- .class_init = pc_dimm_class_init,
- .class_size = sizeof(PCDIMMDeviceClass),
-};
-
-static void pc_dimm_register_types(void)
-{
- type_register_static(&pc_dimm_info);
-}
-
-type_init(pc_dimm_register_types)
diff --git a/qemu/hw/microblaze/Makefile.objs b/qemu/hw/microblaze/Makefile.objs
deleted file mode 100644
index b2517d87f..000000000
--- a/qemu/hw/microblaze/Makefile.objs
+++ /dev/null
@@ -1,3 +0,0 @@
-obj-y += petalogix_s3adsp1800_mmu.o
-obj-y += petalogix_ml605_mmu.o
-obj-y += boot.o
diff --git a/qemu/hw/microblaze/boot.c b/qemu/hw/microblaze/boot.c
deleted file mode 100644
index 9eebb1a52..000000000
--- a/qemu/hw/microblaze/boot.c
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Microblaze kernel loader
- *
- * Copyright (c) 2012 Peter Crosthwaite <peter.crosthwaite@petalogix.com>
- * Copyright (c) 2012 PetaLogix
- * Copyright (c) 2009 Edgar E. Iglesias.
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "qemu/option.h"
-#include "qemu/config-file.h"
-#include "qemu/error-report.h"
-#include "qemu-common.h"
-#include "sysemu/device_tree.h"
-#include "sysemu/sysemu.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "qemu/cutils.h"
-
-#include "boot.h"
-
-static struct
-{
- void (*machine_cpu_reset)(MicroBlazeCPU *);
- uint32_t bootstrap_pc;
- uint32_t cmdline;
- uint32_t initrd_start;
- uint32_t initrd_end;
- uint32_t fdt;
-} boot_info;
-
-static void main_cpu_reset(void *opaque)
-{
- MicroBlazeCPU *cpu = opaque;
- CPUState *cs = CPU(cpu);
- CPUMBState *env = &cpu->env;
-
- cpu_reset(cs);
- env->regs[5] = boot_info.cmdline;
- env->regs[6] = boot_info.initrd_start;
- env->regs[7] = boot_info.fdt;
- cpu_set_pc(cs, boot_info.bootstrap_pc);
- if (boot_info.machine_cpu_reset) {
- boot_info.machine_cpu_reset(cpu);
- }
-}
-
-static int microblaze_load_dtb(hwaddr addr,
- uint32_t ramsize,
- uint32_t initrd_start,
- uint32_t initrd_end,
- const char *kernel_cmdline,
- const char *dtb_filename)
-{
- int fdt_size;
- void *fdt = NULL;
- int r;
-
- if (dtb_filename) {
- fdt = load_device_tree(dtb_filename, &fdt_size);
- }
- if (!fdt) {
- return 0;
- }
-
- if (kernel_cmdline) {
- r = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
- kernel_cmdline);
- if (r < 0) {
- fprintf(stderr, "couldn't set /chosen/bootargs\n");
- }
- }
-
- if (initrd_start) {
- qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start",
- initrd_start);
-
- qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
- initrd_end);
- }
-
- cpu_physical_memory_write(addr, fdt, fdt_size);
- return fdt_size;
-}
-
-static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
-{
- return addr - 0x30000000LL;
-}
-
-void microblaze_load_kernel(MicroBlazeCPU *cpu, hwaddr ddr_base,
- uint32_t ramsize,
- const char *initrd_filename,
- const char *dtb_filename,
- void (*machine_cpu_reset)(MicroBlazeCPU *))
-{
- QemuOpts *machine_opts;
- const char *kernel_filename;
- const char *kernel_cmdline;
- const char *dtb_arg;
- char *filename = NULL;
-
- machine_opts = qemu_get_machine_opts();
- kernel_filename = qemu_opt_get(machine_opts, "kernel");
- kernel_cmdline = qemu_opt_get(machine_opts, "append");
- dtb_arg = qemu_opt_get(machine_opts, "dtb");
- /* default to pcbios dtb as passed by machine_init */
- if (!dtb_arg) {
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_filename);
- }
-
- boot_info.machine_cpu_reset = machine_cpu_reset;
- qemu_register_reset(main_cpu_reset, cpu);
-
- if (kernel_filename) {
- int kernel_size;
- uint64_t entry, low, high;
- uint32_t base32;
- int big_endian = 0;
-
-#ifdef TARGET_WORDS_BIGENDIAN
- big_endian = 1;
-#endif
-
- /* Boots a kernel elf binary. */
- kernel_size = load_elf(kernel_filename, NULL, NULL,
- &entry, &low, &high,
- big_endian, EM_MICROBLAZE, 0, 0);
- base32 = entry;
- if (base32 == 0xc0000000) {
- kernel_size = load_elf(kernel_filename, translate_kernel_address,
- NULL, &entry, NULL, NULL,
- big_endian, EM_MICROBLAZE, 0, 0);
- }
- /* Always boot into physical ram. */
- boot_info.bootstrap_pc = (uint32_t)entry;
-
- /* If it wasn't an ELF image, try an u-boot image. */
- if (kernel_size < 0) {
- hwaddr uentry, loadaddr;
-
- kernel_size = load_uimage(kernel_filename, &uentry, &loadaddr, 0,
- NULL, NULL);
- boot_info.bootstrap_pc = uentry;
- high = (loadaddr + kernel_size + 3) & ~3;
- }
-
- /* Not an ELF image nor an u-boot image, try a RAW image. */
- if (kernel_size < 0) {
- kernel_size = load_image_targphys(kernel_filename, ddr_base,
- ram_size);
- boot_info.bootstrap_pc = ddr_base;
- high = (ddr_base + kernel_size + 3) & ~3;
- }
-
- if (initrd_filename) {
- int initrd_size;
- uint32_t initrd_offset;
-
- high = ROUND_UP(high + kernel_size, 4);
- boot_info.initrd_start = high;
- initrd_offset = boot_info.initrd_start - ddr_base;
-
- initrd_size = load_ramdisk(initrd_filename,
- boot_info.initrd_start,
- ram_size - initrd_offset);
- if (initrd_size < 0) {
- initrd_size = load_image_targphys(initrd_filename,
- boot_info.initrd_start,
- ram_size - initrd_offset);
- }
- if (initrd_size < 0) {
- error_report("qemu: could not load initrd '%s'",
- initrd_filename);
- exit(EXIT_FAILURE);
- }
- boot_info.initrd_end = boot_info.initrd_start + initrd_size;
- high = ROUND_UP(high + initrd_size, 4);
- }
-
- boot_info.cmdline = high + 4096;
- if (kernel_cmdline && strlen(kernel_cmdline)) {
- pstrcpy_targphys("cmdline", boot_info.cmdline, 256, kernel_cmdline);
- }
- /* Provide a device-tree. */
- boot_info.fdt = boot_info.cmdline + 4096;
- microblaze_load_dtb(boot_info.fdt, ram_size,
- boot_info.initrd_start,
- boot_info.initrd_end,
- kernel_cmdline,
- /* Preference a -dtb argument */
- dtb_arg ? dtb_arg : filename);
- }
- g_free(filename);
-}
diff --git a/qemu/hw/microblaze/boot.h b/qemu/hw/microblaze/boot.h
deleted file mode 100644
index 0eb7f8e4f..000000000
--- a/qemu/hw/microblaze/boot.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef __MICROBLAZE_BOOT__
-#define __MICROBLAZE_BOOT__
-
-#include "hw/hw.h"
-
-void microblaze_load_kernel(MicroBlazeCPU *cpu, hwaddr ddr_base,
- uint32_t ramsize,
- const char *initrd_filename,
- const char *dtb_filename,
- void (*machine_cpu_reset)(MicroBlazeCPU *));
-
-#endif /* __MICROBLAZE_BOOT __ */
diff --git a/qemu/hw/microblaze/petalogix_ml605_mmu.c b/qemu/hw/microblaze/petalogix_ml605_mmu.c
deleted file mode 100644
index 07527b677..000000000
--- a/qemu/hw/microblaze/petalogix_ml605_mmu.c
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * Model of Petalogix linux reference design targeting Xilinx Spartan ml605
- * board.
- *
- * Copyright (c) 2011 Michal Simek <monstr@monstr.eu>
- * Copyright (c) 2011 PetaLogix
- * Copyright (c) 2009 Edgar E. Iglesias.
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/sysbus.h"
-#include "hw/hw.h"
-#include "net/net.h"
-#include "hw/block/flash.h"
-#include "sysemu/sysemu.h"
-#include "hw/devices.h"
-#include "hw/boards.h"
-#include "sysemu/block-backend.h"
-#include "hw/char/serial.h"
-#include "exec/address-spaces.h"
-#include "hw/ssi/ssi.h"
-
-#include "boot.h"
-
-#include "hw/stream.h"
-
-#define LMB_BRAM_SIZE (128 * 1024)
-#define FLASH_SIZE (32 * 1024 * 1024)
-
-#define BINARY_DEVICE_TREE_FILE "petalogix-ml605.dtb"
-
-#define NUM_SPI_FLASHES 4
-
-#define SPI_BASEADDR 0x40a00000
-#define MEMORY_BASEADDR 0x50000000
-#define FLASH_BASEADDR 0x86000000
-#define INTC_BASEADDR 0x81800000
-#define TIMER_BASEADDR 0x83c00000
-#define UART16550_BASEADDR 0x83e00000
-#define AXIENET_BASEADDR 0x82780000
-#define AXIDMA_BASEADDR 0x84600000
-
-#define AXIDMA_IRQ1 0
-#define AXIDMA_IRQ0 1
-#define TIMER_IRQ 2
-#define AXIENET_IRQ 3
-#define SPI_IRQ 4
-#define UART16550_IRQ 5
-
-static void
-petalogix_ml605_init(MachineState *machine)
-{
- ram_addr_t ram_size = machine->ram_size;
- MemoryRegion *address_space_mem = get_system_memory();
- DeviceState *dev, *dma, *eth0;
- Object *ds, *cs;
- MicroBlazeCPU *cpu;
- SysBusDevice *busdev;
- DriveInfo *dinfo;
- int i;
- MemoryRegion *phys_lmb_bram = g_new(MemoryRegion, 1);
- MemoryRegion *phys_ram = g_new(MemoryRegion, 1);
- qemu_irq irq[32];
-
- /* init CPUs */
- cpu = MICROBLAZE_CPU(object_new(TYPE_MICROBLAZE_CPU));
- object_property_set_str(OBJECT(cpu), "8.10.a", "version", &error_abort);
- /* Use FPU but don't use floating point conversion and square
- * root instructions
- */
- object_property_set_int(OBJECT(cpu), 1, "use-fpu", &error_abort);
- object_property_set_bool(OBJECT(cpu), true, "dcache-writeback",
- &error_abort);
- object_property_set_bool(OBJECT(cpu), true, "endianness", &error_abort);
- object_property_set_bool(OBJECT(cpu), true, "realized", &error_abort);
-
- /* Attach emulated BRAM through the LMB. */
- memory_region_init_ram(phys_lmb_bram, NULL, "petalogix_ml605.lmb_bram",
- LMB_BRAM_SIZE, &error_fatal);
- vmstate_register_ram_global(phys_lmb_bram);
- memory_region_add_subregion(address_space_mem, 0x00000000, phys_lmb_bram);
-
- memory_region_init_ram(phys_ram, NULL, "petalogix_ml605.ram", ram_size,
- &error_fatal);
- vmstate_register_ram_global(phys_ram);
- memory_region_add_subregion(address_space_mem, MEMORY_BASEADDR, phys_ram);
-
- dinfo = drive_get(IF_PFLASH, 0, 0);
- /* 5th parameter 2 means bank-width
- * 10th paremeter 0 means little-endian */
- pflash_cfi01_register(FLASH_BASEADDR,
- NULL, "petalogix_ml605.flash", FLASH_SIZE,
- dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- (64 * 1024), FLASH_SIZE >> 16,
- 2, 0x89, 0x18, 0x0000, 0x0, 0);
-
-
- dev = qdev_create(NULL, "xlnx.xps-intc");
- qdev_prop_set_uint32(dev, "kind-of-intr", 1 << TIMER_IRQ);
- qdev_init_nofail(dev);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, INTC_BASEADDR);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0,
- qdev_get_gpio_in(DEVICE(cpu), MB_CPU_IRQ));
- for (i = 0; i < 32; i++) {
- irq[i] = qdev_get_gpio_in(dev, i);
- }
-
- serial_mm_init(address_space_mem, UART16550_BASEADDR + 0x1000, 2,
- irq[UART16550_IRQ], 115200, serial_hds[0],
- DEVICE_LITTLE_ENDIAN);
-
- /* 2 timers at irq 2 @ 100 Mhz. */
- dev = qdev_create(NULL, "xlnx.xps-timer");
- qdev_prop_set_uint32(dev, "one-timer-only", 0);
- qdev_prop_set_uint32(dev, "clock-frequency", 100 * 1000000);
- qdev_init_nofail(dev);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, TIMER_BASEADDR);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[TIMER_IRQ]);
-
- /* axi ethernet and dma initialization. */
- qemu_check_nic_model(&nd_table[0], "xlnx.axi-ethernet");
- eth0 = qdev_create(NULL, "xlnx.axi-ethernet");
- dma = qdev_create(NULL, "xlnx.axi-dma");
-
- /* FIXME: attach to the sysbus instead */
- object_property_add_child(qdev_get_machine(), "xilinx-eth", OBJECT(eth0),
- NULL);
- object_property_add_child(qdev_get_machine(), "xilinx-dma", OBJECT(dma),
- NULL);
-
- ds = object_property_get_link(OBJECT(dma),
- "axistream-connected-target", NULL);
- cs = object_property_get_link(OBJECT(dma),
- "axistream-control-connected-target", NULL);
- qdev_set_nic_properties(eth0, &nd_table[0]);
- qdev_prop_set_uint32(eth0, "rxmem", 0x1000);
- qdev_prop_set_uint32(eth0, "txmem", 0x1000);
- object_property_set_link(OBJECT(eth0), OBJECT(ds),
- "axistream-connected", &error_abort);
- object_property_set_link(OBJECT(eth0), OBJECT(cs),
- "axistream-control-connected", &error_abort);
- qdev_init_nofail(eth0);
- sysbus_mmio_map(SYS_BUS_DEVICE(eth0), 0, AXIENET_BASEADDR);
- sysbus_connect_irq(SYS_BUS_DEVICE(eth0), 0, irq[AXIENET_IRQ]);
-
- ds = object_property_get_link(OBJECT(eth0),
- "axistream-connected-target", NULL);
- cs = object_property_get_link(OBJECT(eth0),
- "axistream-control-connected-target", NULL);
- qdev_prop_set_uint32(dma, "freqhz", 100 * 1000000);
- object_property_set_link(OBJECT(dma), OBJECT(ds),
- "axistream-connected", &error_abort);
- object_property_set_link(OBJECT(dma), OBJECT(cs),
- "axistream-control-connected", &error_abort);
- qdev_init_nofail(dma);
- sysbus_mmio_map(SYS_BUS_DEVICE(dma), 0, AXIDMA_BASEADDR);
- sysbus_connect_irq(SYS_BUS_DEVICE(dma), 0, irq[AXIDMA_IRQ0]);
- sysbus_connect_irq(SYS_BUS_DEVICE(dma), 1, irq[AXIDMA_IRQ1]);
-
- {
- SSIBus *spi;
-
- dev = qdev_create(NULL, "xlnx.xps-spi");
- qdev_prop_set_uint8(dev, "num-ss-bits", NUM_SPI_FLASHES);
- qdev_init_nofail(dev);
- busdev = SYS_BUS_DEVICE(dev);
- sysbus_mmio_map(busdev, 0, SPI_BASEADDR);
- sysbus_connect_irq(busdev, 0, irq[SPI_IRQ]);
-
- spi = (SSIBus *)qdev_get_child_bus(dev, "spi");
-
- for (i = 0; i < NUM_SPI_FLASHES; i++) {
- qemu_irq cs_line;
-
- dev = ssi_create_slave(spi, "n25q128");
- cs_line = qdev_get_gpio_in_named(dev, SSI_GPIO_CS, 0);
- sysbus_connect_irq(busdev, i+1, cs_line);
- }
- }
-
- /* setup PVR to match kernel settings */
- cpu->env.pvr.regs[4] = 0xc56b8000;
- cpu->env.pvr.regs[5] = 0xc56be000;
- cpu->env.pvr.regs[10] = 0x0e000000; /* virtex 6 */
-
- microblaze_load_kernel(cpu, MEMORY_BASEADDR, ram_size,
- machine->initrd_filename,
- BINARY_DEVICE_TREE_FILE,
- NULL);
-
-}
-
-static void petalogix_ml605_machine_init(MachineClass *mc)
-{
- mc->desc = "PetaLogix linux refdesign for xilinx ml605 little endian";
- mc->init = petalogix_ml605_init;
- mc->is_default = 0;
-}
-
-DEFINE_MACHINE("petalogix-ml605", petalogix_ml605_machine_init)
diff --git a/qemu/hw/microblaze/petalogix_s3adsp1800_mmu.c b/qemu/hw/microblaze/petalogix_s3adsp1800_mmu.c
deleted file mode 100644
index f821e1cfe..000000000
--- a/qemu/hw/microblaze/petalogix_s3adsp1800_mmu.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Model of Petalogix linux reference design targeting Xilinx Spartan 3ADSP-1800
- * boards.
- *
- * Copyright (c) 2009 Edgar E. Iglesias.
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/sysbus.h"
-#include "hw/hw.h"
-#include "net/net.h"
-#include "hw/block/flash.h"
-#include "sysemu/sysemu.h"
-#include "hw/devices.h"
-#include "hw/boards.h"
-#include "sysemu/block-backend.h"
-#include "exec/address-spaces.h"
-
-#include "boot.h"
-
-#define LMB_BRAM_SIZE (128 * 1024)
-#define FLASH_SIZE (16 * 1024 * 1024)
-
-#define BINARY_DEVICE_TREE_FILE "petalogix-s3adsp1800.dtb"
-
-#define MEMORY_BASEADDR 0x90000000
-#define FLASH_BASEADDR 0xa0000000
-#define INTC_BASEADDR 0x81800000
-#define TIMER_BASEADDR 0x83c00000
-#define UARTLITE_BASEADDR 0x84000000
-#define ETHLITE_BASEADDR 0x81000000
-
-#define TIMER_IRQ 0
-#define ETHLITE_IRQ 1
-#define UARTLITE_IRQ 3
-
-static void
-petalogix_s3adsp1800_init(MachineState *machine)
-{
- ram_addr_t ram_size = machine->ram_size;
- DeviceState *dev;
- MicroBlazeCPU *cpu;
- DriveInfo *dinfo;
- int i;
- hwaddr ddr_base = MEMORY_BASEADDR;
- MemoryRegion *phys_lmb_bram = g_new(MemoryRegion, 1);
- MemoryRegion *phys_ram = g_new(MemoryRegion, 1);
- qemu_irq irq[32];
- MemoryRegion *sysmem = get_system_memory();
-
- cpu = MICROBLAZE_CPU(object_new(TYPE_MICROBLAZE_CPU));
- object_property_set_str(OBJECT(cpu), "7.10.d", "version", &error_abort);
- object_property_set_bool(OBJECT(cpu), true, "realized", &error_abort);
-
- /* Attach emulated BRAM through the LMB. */
- memory_region_init_ram(phys_lmb_bram, NULL,
- "petalogix_s3adsp1800.lmb_bram", LMB_BRAM_SIZE,
- &error_fatal);
- vmstate_register_ram_global(phys_lmb_bram);
- memory_region_add_subregion(sysmem, 0x00000000, phys_lmb_bram);
-
- memory_region_init_ram(phys_ram, NULL, "petalogix_s3adsp1800.ram",
- ram_size, &error_fatal);
- vmstate_register_ram_global(phys_ram);
- memory_region_add_subregion(sysmem, ddr_base, phys_ram);
-
- dinfo = drive_get(IF_PFLASH, 0, 0);
- pflash_cfi01_register(FLASH_BASEADDR,
- NULL, "petalogix_s3adsp1800.flash", FLASH_SIZE,
- dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- (64 * 1024), FLASH_SIZE >> 16,
- 1, 0x89, 0x18, 0x0000, 0x0, 1);
-
- dev = qdev_create(NULL, "xlnx.xps-intc");
- qdev_prop_set_uint32(dev, "kind-of-intr",
- 1 << ETHLITE_IRQ | 1 << UARTLITE_IRQ);
- qdev_init_nofail(dev);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, INTC_BASEADDR);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0,
- qdev_get_gpio_in(DEVICE(cpu), MB_CPU_IRQ));
- for (i = 0; i < 32; i++) {
- irq[i] = qdev_get_gpio_in(dev, i);
- }
-
- sysbus_create_simple("xlnx.xps-uartlite", UARTLITE_BASEADDR,
- irq[UARTLITE_IRQ]);
-
- /* 2 timers at irq 2 @ 62 Mhz. */
- dev = qdev_create(NULL, "xlnx.xps-timer");
- qdev_prop_set_uint32(dev, "one-timer-only", 0);
- qdev_prop_set_uint32(dev, "clock-frequency", 62 * 1000000);
- qdev_init_nofail(dev);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, TIMER_BASEADDR);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[TIMER_IRQ]);
-
- qemu_check_nic_model(&nd_table[0], "xlnx.xps-ethernetlite");
- dev = qdev_create(NULL, "xlnx.xps-ethernetlite");
- qdev_set_nic_properties(dev, &nd_table[0]);
- qdev_prop_set_uint32(dev, "tx-ping-pong", 0);
- qdev_prop_set_uint32(dev, "rx-ping-pong", 0);
- qdev_init_nofail(dev);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, ETHLITE_BASEADDR);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[ETHLITE_IRQ]);
-
- microblaze_load_kernel(cpu, ddr_base, ram_size,
- machine->initrd_filename,
- BINARY_DEVICE_TREE_FILE,
- NULL);
-}
-
-static void petalogix_s3adsp1800_machine_init(MachineClass *mc)
-{
- mc->desc = "PetaLogix linux refdesign for xilinx Spartan 3ADSP1800";
- mc->init = petalogix_s3adsp1800_init;
- mc->is_default = 1;
-}
-
-DEFINE_MACHINE("petalogix-s3adsp1800", petalogix_s3adsp1800_machine_init)
diff --git a/qemu/hw/mips/Makefile.objs b/qemu/hw/mips/Makefile.objs
deleted file mode 100644
index 9352a1c06..000000000
--- a/qemu/hw/mips/Makefile.objs
+++ /dev/null
@@ -1,6 +0,0 @@
-obj-y += mips_r4k.o mips_malta.o mips_mipssim.o
-obj-y += addr.o cputimer.o mips_int.o
-obj-$(CONFIG_JAZZ) += mips_jazz.o
-obj-$(CONFIG_FULONG) += mips_fulong2e.o
-obj-y += gt64xxx_pci.o
-obj-$(CONFIG_MIPS_CPS) += cps.o
diff --git a/qemu/hw/mips/addr.c b/qemu/hw/mips/addr.c
deleted file mode 100644
index e4e86b4a7..000000000
--- a/qemu/hw/mips/addr.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * QEMU MIPS address translation support
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/mips/cpudevs.h"
-
-uint64_t cpu_mips_kseg0_to_phys(void *opaque, uint64_t addr)
-{
- return addr & 0x1fffffffll;
-}
-
-uint64_t cpu_mips_phys_to_kseg0(void *opaque, uint64_t addr)
-{
- return addr | ~0x7fffffffll;
-}
-
-uint64_t cpu_mips_kvm_um_phys_to_kseg0(void *opaque, uint64_t addr)
-{
- return addr | 0x40000000ll;
-}
diff --git a/qemu/hw/mips/cps.c b/qemu/hw/mips/cps.c
deleted file mode 100644
index 1bafbbb27..000000000
--- a/qemu/hw/mips/cps.c
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Coherent Processing System emulation.
- *
- * Copyright (c) 2016 Imagination Technologies
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/mips/cps.h"
-#include "hw/mips/mips.h"
-#include "hw/mips/cpudevs.h"
-#include "sysemu/kvm.h"
-
-qemu_irq get_cps_irq(MIPSCPSState *s, int pin_number)
-{
- MIPSCPU *cpu = MIPS_CPU(first_cpu);
- CPUMIPSState *env = &cpu->env;
-
- assert(pin_number < s->num_irq);
-
- /* TODO: return GIC pins once implemented */
- return env->irq[pin_number];
-}
-
-static void mips_cps_init(Object *obj)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- MIPSCPSState *s = MIPS_CPS(obj);
-
- /* Cover entire address space as there do not seem to be any
- * constraints for the base address of CPC and GIC. */
- memory_region_init(&s->container, obj, "mips-cps-container", UINT64_MAX);
- sysbus_init_mmio(sbd, &s->container);
-}
-
-static void main_cpu_reset(void *opaque)
-{
- MIPSCPU *cpu = opaque;
- CPUState *cs = CPU(cpu);
-
- cpu_reset(cs);
-
- /* All VPs are halted on reset. Leave powering up to CPC. */
- cs->halted = 1;
-}
-
-static bool cpu_mips_itu_supported(CPUMIPSState *env)
-{
- bool is_mt = (env->CP0_Config5 & (1 << CP0C5_VP)) ||
- (env->CP0_Config3 & (1 << CP0C3_MT));
-
- return is_mt && !kvm_enabled();
-}
-
-static void mips_cps_realize(DeviceState *dev, Error **errp)
-{
- MIPSCPSState *s = MIPS_CPS(dev);
- CPUMIPSState *env;
- MIPSCPU *cpu;
- int i;
- Error *err = NULL;
- target_ulong gcr_base;
- bool itu_present = false;
-
- for (i = 0; i < s->num_vp; i++) {
- cpu = cpu_mips_init(s->cpu_model);
- if (cpu == NULL) {
- error_setg(errp, "%s: CPU initialization failed\n", __func__);
- return;
- }
- env = &cpu->env;
-
- /* Init internal devices */
- cpu_mips_irq_init_cpu(env);
- cpu_mips_clock_init(env);
- if (cpu_mips_itu_supported(env)) {
- itu_present = true;
- /* Attach ITC Tag to the VP */
- env->itc_tag = mips_itu_get_tag_region(&s->itu);
- }
- qemu_register_reset(main_cpu_reset, cpu);
- }
-
- cpu = MIPS_CPU(first_cpu);
- env = &cpu->env;
-
- /* Inter-Thread Communication Unit */
- if (itu_present) {
- object_initialize(&s->itu, sizeof(s->itu), TYPE_MIPS_ITU);
- qdev_set_parent_bus(DEVICE(&s->itu), sysbus_get_default());
-
- object_property_set_int(OBJECT(&s->itu), 16, "num-fifo", &err);
- object_property_set_int(OBJECT(&s->itu), 16, "num-semaphores", &err);
- object_property_set_bool(OBJECT(&s->itu), true, "realized", &err);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
-
- memory_region_add_subregion(&s->container, 0,
- sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->itu), 0));
- }
-
- /* Cluster Power Controller */
- object_initialize(&s->cpc, sizeof(s->cpc), TYPE_MIPS_CPC);
- qdev_set_parent_bus(DEVICE(&s->cpc), sysbus_get_default());
-
- object_property_set_int(OBJECT(&s->cpc), s->num_vp, "num-vp", &err);
- object_property_set_int(OBJECT(&s->cpc), 1, "vp-start-running", &err);
- object_property_set_bool(OBJECT(&s->cpc), true, "realized", &err);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
-
- memory_region_add_subregion(&s->container, 0,
- sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->cpc), 0));
-
- /* Global Configuration Registers */
- gcr_base = env->CP0_CMGCRBase << 4;
-
- object_initialize(&s->gcr, sizeof(s->gcr), TYPE_MIPS_GCR);
- qdev_set_parent_bus(DEVICE(&s->gcr), sysbus_get_default());
-
- object_property_set_int(OBJECT(&s->gcr), s->num_vp, "num-vp", &err);
- object_property_set_int(OBJECT(&s->gcr), 0x800, "gcr-rev", &err);
- object_property_set_int(OBJECT(&s->gcr), gcr_base, "gcr-base", &err);
- object_property_set_link(OBJECT(&s->gcr), OBJECT(&s->cpc.mr), "cpc", &err);
- object_property_set_bool(OBJECT(&s->gcr), true, "realized", &err);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
-
- memory_region_add_subregion(&s->container, gcr_base,
- sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->gcr), 0));
-}
-
-static Property mips_cps_properties[] = {
- DEFINE_PROP_UINT32("num-vp", MIPSCPSState, num_vp, 1),
- DEFINE_PROP_UINT32("num-irq", MIPSCPSState, num_irq, 8),
- DEFINE_PROP_STRING("cpu-model", MIPSCPSState, cpu_model),
- DEFINE_PROP_END_OF_LIST()
-};
-
-static void mips_cps_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = mips_cps_realize;
- dc->props = mips_cps_properties;
-}
-
-static const TypeInfo mips_cps_info = {
- .name = TYPE_MIPS_CPS,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(MIPSCPSState),
- .instance_init = mips_cps_init,
- .class_init = mips_cps_class_init,
-};
-
-static void mips_cps_register_types(void)
-{
- type_register_static(&mips_cps_info);
-}
-
-type_init(mips_cps_register_types)
diff --git a/qemu/hw/mips/cputimer.c b/qemu/hw/mips/cputimer.c
deleted file mode 100644
index efb227d06..000000000
--- a/qemu/hw/mips/cputimer.c
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * QEMU MIPS timer support
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/mips/cpudevs.h"
-#include "qemu/timer.h"
-#include "sysemu/kvm.h"
-
-#define TIMER_PERIOD 10 /* 10 ns period for 100 Mhz frequency */
-
-/* XXX: do not use a global */
-uint32_t cpu_mips_get_random (CPUMIPSState *env)
-{
- static uint32_t seed = 1;
- static uint32_t prev_idx = 0;
- uint32_t idx;
- uint32_t nb_rand_tlb = env->tlb->nb_tlb - env->CP0_Wired;
-
- if (nb_rand_tlb == 1) {
- return env->tlb->nb_tlb - 1;
- }
-
- /* Don't return same value twice, so get another value */
- do {
- /* Use a simple algorithm of Linear Congruential Generator
- * from ISO/IEC 9899 standard. */
- seed = 1103515245 * seed + 12345;
- idx = (seed >> 16) % nb_rand_tlb + env->CP0_Wired;
- } while (idx == prev_idx);
- prev_idx = idx;
- return idx;
-}
-
-/* MIPS R4K timer */
-static void cpu_mips_timer_update(CPUMIPSState *env)
-{
- uint64_t now, next;
- uint32_t wait;
-
- now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- wait = env->CP0_Compare - env->CP0_Count - (uint32_t)(now / TIMER_PERIOD);
- next = now + (uint64_t)wait * TIMER_PERIOD;
- timer_mod(env->timer, next);
-}
-
-/* Expire the timer. */
-static void cpu_mips_timer_expire(CPUMIPSState *env)
-{
- cpu_mips_timer_update(env);
- if (env->insn_flags & ISA_MIPS32R2) {
- env->CP0_Cause |= 1 << CP0Ca_TI;
- }
- qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
-}
-
-uint32_t cpu_mips_get_count (CPUMIPSState *env)
-{
- if (env->CP0_Cause & (1 << CP0Ca_DC)) {
- return env->CP0_Count;
- } else {
- uint64_t now;
-
- now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- if (timer_pending(env->timer)
- && timer_expired(env->timer, now)) {
- /* The timer has already expired. */
- cpu_mips_timer_expire(env);
- }
-
- return env->CP0_Count + (uint32_t)(now / TIMER_PERIOD);
- }
-}
-
-void cpu_mips_store_count (CPUMIPSState *env, uint32_t count)
-{
- /*
- * This gets called from cpu_state_reset(), potentially before timer init.
- * So env->timer may be NULL, which is also the case with KVM enabled so
- * treat timer as disabled in that case.
- */
- if (env->CP0_Cause & (1 << CP0Ca_DC) || !env->timer)
- env->CP0_Count = count;
- else {
- /* Store new count register */
- env->CP0_Count = count -
- (uint32_t)(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / TIMER_PERIOD);
- /* Update timer timer */
- cpu_mips_timer_update(env);
- }
-}
-
-void cpu_mips_store_compare (CPUMIPSState *env, uint32_t value)
-{
- env->CP0_Compare = value;
- if (!(env->CP0_Cause & (1 << CP0Ca_DC)))
- cpu_mips_timer_update(env);
- if (env->insn_flags & ISA_MIPS32R2)
- env->CP0_Cause &= ~(1 << CP0Ca_TI);
- qemu_irq_lower(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
-}
-
-void cpu_mips_start_count(CPUMIPSState *env)
-{
- cpu_mips_store_count(env, env->CP0_Count);
-}
-
-void cpu_mips_stop_count(CPUMIPSState *env)
-{
- /* Store the current value */
- env->CP0_Count += (uint32_t)(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) /
- TIMER_PERIOD);
-}
-
-static void mips_timer_cb (void *opaque)
-{
- CPUMIPSState *env;
-
- env = opaque;
-#if 0
- qemu_log("%s\n", __func__);
-#endif
-
- if (env->CP0_Cause & (1 << CP0Ca_DC))
- return;
-
- /* ??? This callback should occur when the counter is exactly equal to
- the comparator value. Offset the count by one to avoid immediately
- retriggering the callback before any virtual time has passed. */
- env->CP0_Count++;
- cpu_mips_timer_expire(env);
- env->CP0_Count--;
-}
-
-void cpu_mips_clock_init (CPUMIPSState *env)
-{
- /*
- * If we're in KVM mode, don't create the periodic timer, that is handled in
- * kernel.
- */
- if (!kvm_enabled()) {
- env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &mips_timer_cb, env);
- }
-}
diff --git a/qemu/hw/mips/gt64xxx_pci.c b/qemu/hw/mips/gt64xxx_pci.c
deleted file mode 100644
index 3f4523df2..000000000
--- a/qemu/hw/mips/gt64xxx_pci.c
+++ /dev/null
@@ -1,1259 +0,0 @@
-/*
- * QEMU GT64120 PCI host
- *
- * Copyright (c) 2006,2007 Aurelien Jarno
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/mips/mips.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/pci_host.h"
-#include "hw/i386/pc.h"
-#include "exec/address-spaces.h"
-
-//#define DEBUG
-
-#ifdef DEBUG
-#define DPRINTF(fmt, ...) fprintf(stderr, "%s: " fmt, __FUNCTION__, ##__VA_ARGS__)
-#else
-#define DPRINTF(fmt, ...)
-#endif
-
-#define GT_REGS (0x1000 >> 2)
-
-/* CPU Configuration */
-#define GT_CPU (0x000 >> 2)
-#define GT_MULTI (0x120 >> 2)
-
-/* CPU Address Decode */
-#define GT_SCS10LD (0x008 >> 2)
-#define GT_SCS10HD (0x010 >> 2)
-#define GT_SCS32LD (0x018 >> 2)
-#define GT_SCS32HD (0x020 >> 2)
-#define GT_CS20LD (0x028 >> 2)
-#define GT_CS20HD (0x030 >> 2)
-#define GT_CS3BOOTLD (0x038 >> 2)
-#define GT_CS3BOOTHD (0x040 >> 2)
-#define GT_PCI0IOLD (0x048 >> 2)
-#define GT_PCI0IOHD (0x050 >> 2)
-#define GT_PCI0M0LD (0x058 >> 2)
-#define GT_PCI0M0HD (0x060 >> 2)
-#define GT_PCI0M1LD (0x080 >> 2)
-#define GT_PCI0M1HD (0x088 >> 2)
-#define GT_PCI1IOLD (0x090 >> 2)
-#define GT_PCI1IOHD (0x098 >> 2)
-#define GT_PCI1M0LD (0x0a0 >> 2)
-#define GT_PCI1M0HD (0x0a8 >> 2)
-#define GT_PCI1M1LD (0x0b0 >> 2)
-#define GT_PCI1M1HD (0x0b8 >> 2)
-#define GT_ISD (0x068 >> 2)
-
-#define GT_SCS10AR (0x0d0 >> 2)
-#define GT_SCS32AR (0x0d8 >> 2)
-#define GT_CS20R (0x0e0 >> 2)
-#define GT_CS3BOOTR (0x0e8 >> 2)
-
-#define GT_PCI0IOREMAP (0x0f0 >> 2)
-#define GT_PCI0M0REMAP (0x0f8 >> 2)
-#define GT_PCI0M1REMAP (0x100 >> 2)
-#define GT_PCI1IOREMAP (0x108 >> 2)
-#define GT_PCI1M0REMAP (0x110 >> 2)
-#define GT_PCI1M1REMAP (0x118 >> 2)
-
-/* CPU Error Report */
-#define GT_CPUERR_ADDRLO (0x070 >> 2)
-#define GT_CPUERR_ADDRHI (0x078 >> 2)
-#define GT_CPUERR_DATALO (0x128 >> 2) /* GT-64120A only */
-#define GT_CPUERR_DATAHI (0x130 >> 2) /* GT-64120A only */
-#define GT_CPUERR_PARITY (0x138 >> 2) /* GT-64120A only */
-
-/* CPU Sync Barrier */
-#define GT_PCI0SYNC (0x0c0 >> 2)
-#define GT_PCI1SYNC (0x0c8 >> 2)
-
-/* SDRAM and Device Address Decode */
-#define GT_SCS0LD (0x400 >> 2)
-#define GT_SCS0HD (0x404 >> 2)
-#define GT_SCS1LD (0x408 >> 2)
-#define GT_SCS1HD (0x40c >> 2)
-#define GT_SCS2LD (0x410 >> 2)
-#define GT_SCS2HD (0x414 >> 2)
-#define GT_SCS3LD (0x418 >> 2)
-#define GT_SCS3HD (0x41c >> 2)
-#define GT_CS0LD (0x420 >> 2)
-#define GT_CS0HD (0x424 >> 2)
-#define GT_CS1LD (0x428 >> 2)
-#define GT_CS1HD (0x42c >> 2)
-#define GT_CS2LD (0x430 >> 2)
-#define GT_CS2HD (0x434 >> 2)
-#define GT_CS3LD (0x438 >> 2)
-#define GT_CS3HD (0x43c >> 2)
-#define GT_BOOTLD (0x440 >> 2)
-#define GT_BOOTHD (0x444 >> 2)
-#define GT_ADERR (0x470 >> 2)
-
-/* SDRAM Configuration */
-#define GT_SDRAM_CFG (0x448 >> 2)
-#define GT_SDRAM_OPMODE (0x474 >> 2)
-#define GT_SDRAM_BM (0x478 >> 2)
-#define GT_SDRAM_ADDRDECODE (0x47c >> 2)
-
-/* SDRAM Parameters */
-#define GT_SDRAM_B0 (0x44c >> 2)
-#define GT_SDRAM_B1 (0x450 >> 2)
-#define GT_SDRAM_B2 (0x454 >> 2)
-#define GT_SDRAM_B3 (0x458 >> 2)
-
-/* Device Parameters */
-#define GT_DEV_B0 (0x45c >> 2)
-#define GT_DEV_B1 (0x460 >> 2)
-#define GT_DEV_B2 (0x464 >> 2)
-#define GT_DEV_B3 (0x468 >> 2)
-#define GT_DEV_BOOT (0x46c >> 2)
-
-/* ECC */
-#define GT_ECC_ERRDATALO (0x480 >> 2) /* GT-64120A only */
-#define GT_ECC_ERRDATAHI (0x484 >> 2) /* GT-64120A only */
-#define GT_ECC_MEM (0x488 >> 2) /* GT-64120A only */
-#define GT_ECC_CALC (0x48c >> 2) /* GT-64120A only */
-#define GT_ECC_ERRADDR (0x490 >> 2) /* GT-64120A only */
-
-/* DMA Record */
-#define GT_DMA0_CNT (0x800 >> 2)
-#define GT_DMA1_CNT (0x804 >> 2)
-#define GT_DMA2_CNT (0x808 >> 2)
-#define GT_DMA3_CNT (0x80c >> 2)
-#define GT_DMA0_SA (0x810 >> 2)
-#define GT_DMA1_SA (0x814 >> 2)
-#define GT_DMA2_SA (0x818 >> 2)
-#define GT_DMA3_SA (0x81c >> 2)
-#define GT_DMA0_DA (0x820 >> 2)
-#define GT_DMA1_DA (0x824 >> 2)
-#define GT_DMA2_DA (0x828 >> 2)
-#define GT_DMA3_DA (0x82c >> 2)
-#define GT_DMA0_NEXT (0x830 >> 2)
-#define GT_DMA1_NEXT (0x834 >> 2)
-#define GT_DMA2_NEXT (0x838 >> 2)
-#define GT_DMA3_NEXT (0x83c >> 2)
-#define GT_DMA0_CUR (0x870 >> 2)
-#define GT_DMA1_CUR (0x874 >> 2)
-#define GT_DMA2_CUR (0x878 >> 2)
-#define GT_DMA3_CUR (0x87c >> 2)
-
-/* DMA Channel Control */
-#define GT_DMA0_CTRL (0x840 >> 2)
-#define GT_DMA1_CTRL (0x844 >> 2)
-#define GT_DMA2_CTRL (0x848 >> 2)
-#define GT_DMA3_CTRL (0x84c >> 2)
-
-/* DMA Arbiter */
-#define GT_DMA_ARB (0x860 >> 2)
-
-/* Timer/Counter */
-#define GT_TC0 (0x850 >> 2)
-#define GT_TC1 (0x854 >> 2)
-#define GT_TC2 (0x858 >> 2)
-#define GT_TC3 (0x85c >> 2)
-#define GT_TC_CONTROL (0x864 >> 2)
-
-/* PCI Internal */
-#define GT_PCI0_CMD (0xc00 >> 2)
-#define GT_PCI0_TOR (0xc04 >> 2)
-#define GT_PCI0_BS_SCS10 (0xc08 >> 2)
-#define GT_PCI0_BS_SCS32 (0xc0c >> 2)
-#define GT_PCI0_BS_CS20 (0xc10 >> 2)
-#define GT_PCI0_BS_CS3BT (0xc14 >> 2)
-#define GT_PCI1_IACK (0xc30 >> 2)
-#define GT_PCI0_IACK (0xc34 >> 2)
-#define GT_PCI0_BARE (0xc3c >> 2)
-#define GT_PCI0_PREFMBR (0xc40 >> 2)
-#define GT_PCI0_SCS10_BAR (0xc48 >> 2)
-#define GT_PCI0_SCS32_BAR (0xc4c >> 2)
-#define GT_PCI0_CS20_BAR (0xc50 >> 2)
-#define GT_PCI0_CS3BT_BAR (0xc54 >> 2)
-#define GT_PCI0_SSCS10_BAR (0xc58 >> 2)
-#define GT_PCI0_SSCS32_BAR (0xc5c >> 2)
-#define GT_PCI0_SCS3BT_BAR (0xc64 >> 2)
-#define GT_PCI1_CMD (0xc80 >> 2)
-#define GT_PCI1_TOR (0xc84 >> 2)
-#define GT_PCI1_BS_SCS10 (0xc88 >> 2)
-#define GT_PCI1_BS_SCS32 (0xc8c >> 2)
-#define GT_PCI1_BS_CS20 (0xc90 >> 2)
-#define GT_PCI1_BS_CS3BT (0xc94 >> 2)
-#define GT_PCI1_BARE (0xcbc >> 2)
-#define GT_PCI1_PREFMBR (0xcc0 >> 2)
-#define GT_PCI1_SCS10_BAR (0xcc8 >> 2)
-#define GT_PCI1_SCS32_BAR (0xccc >> 2)
-#define GT_PCI1_CS20_BAR (0xcd0 >> 2)
-#define GT_PCI1_CS3BT_BAR (0xcd4 >> 2)
-#define GT_PCI1_SSCS10_BAR (0xcd8 >> 2)
-#define GT_PCI1_SSCS32_BAR (0xcdc >> 2)
-#define GT_PCI1_SCS3BT_BAR (0xce4 >> 2)
-#define GT_PCI1_CFGADDR (0xcf0 >> 2)
-#define GT_PCI1_CFGDATA (0xcf4 >> 2)
-#define GT_PCI0_CFGADDR (0xcf8 >> 2)
-#define GT_PCI0_CFGDATA (0xcfc >> 2)
-
-/* Interrupts */
-#define GT_INTRCAUSE (0xc18 >> 2)
-#define GT_INTRMASK (0xc1c >> 2)
-#define GT_PCI0_ICMASK (0xc24 >> 2)
-#define GT_PCI0_SERR0MASK (0xc28 >> 2)
-#define GT_CPU_INTSEL (0xc70 >> 2)
-#define GT_PCI0_INTSEL (0xc74 >> 2)
-#define GT_HINTRCAUSE (0xc98 >> 2)
-#define GT_HINTRMASK (0xc9c >> 2)
-#define GT_PCI0_HICMASK (0xca4 >> 2)
-#define GT_PCI1_SERR1MASK (0xca8 >> 2)
-
-#define PCI_MAPPING_ENTRY(regname) \
- hwaddr regname ##_start; \
- hwaddr regname ##_length; \
- MemoryRegion regname ##_mem
-
-#define TYPE_GT64120_PCI_HOST_BRIDGE "gt64120"
-
-#define GT64120_PCI_HOST_BRIDGE(obj) \
- OBJECT_CHECK(GT64120State, (obj), TYPE_GT64120_PCI_HOST_BRIDGE)
-
-typedef struct GT64120State {
- PCIHostState parent_obj;
-
- uint32_t regs[GT_REGS];
- PCI_MAPPING_ENTRY(PCI0IO);
- PCI_MAPPING_ENTRY(PCI0M0);
- PCI_MAPPING_ENTRY(PCI0M1);
- PCI_MAPPING_ENTRY(ISD);
- MemoryRegion pci0_mem;
- AddressSpace pci0_mem_as;
-} GT64120State;
-
-/* Adjust range to avoid touching space which isn't mappable via PCI */
-/* XXX: Hardcoded values for Malta: 0x1e000000 - 0x1f100000
- 0x1fc00000 - 0x1fd00000 */
-static void check_reserved_space (hwaddr *start,
- hwaddr *length)
-{
- hwaddr begin = *start;
- hwaddr end = *start + *length;
-
- if (end >= 0x1e000000LL && end < 0x1f100000LL)
- end = 0x1e000000LL;
- if (begin >= 0x1e000000LL && begin < 0x1f100000LL)
- begin = 0x1f100000LL;
- if (end >= 0x1fc00000LL && end < 0x1fd00000LL)
- end = 0x1fc00000LL;
- if (begin >= 0x1fc00000LL && begin < 0x1fd00000LL)
- begin = 0x1fd00000LL;
- /* XXX: This is broken when a reserved range splits the requested range */
- if (end >= 0x1f100000LL && begin < 0x1e000000LL)
- end = 0x1e000000LL;
- if (end >= 0x1fd00000LL && begin < 0x1fc00000LL)
- end = 0x1fc00000LL;
-
- *start = begin;
- *length = end - begin;
-}
-
-static void gt64120_isd_mapping(GT64120State *s)
-{
- /* Bits 14:0 of ISD map to bits 35:21 of the start address. */
- hwaddr start = ((hwaddr)s->regs[GT_ISD] << 21) & 0xFFFE00000ull;
- hwaddr length = 0x1000;
-
- if (s->ISD_length) {
- memory_region_del_subregion(get_system_memory(), &s->ISD_mem);
- }
- check_reserved_space(&start, &length);
- length = 0x1000;
- /* Map new address */
- DPRINTF("ISD: "TARGET_FMT_plx"@"TARGET_FMT_plx
- " -> "TARGET_FMT_plx"@"TARGET_FMT_plx"\n",
- s->ISD_length, s->ISD_start, length, start);
- s->ISD_start = start;
- s->ISD_length = length;
- memory_region_add_subregion(get_system_memory(), s->ISD_start, &s->ISD_mem);
-}
-
-static void gt64120_pci_mapping(GT64120State *s)
-{
- /* Update PCI0IO mapping */
- if ((s->regs[GT_PCI0IOLD] & 0x7f) <= s->regs[GT_PCI0IOHD]) {
- /* Unmap old IO address */
- if (s->PCI0IO_length) {
- memory_region_del_subregion(get_system_memory(), &s->PCI0IO_mem);
- object_unparent(OBJECT(&s->PCI0IO_mem));
- }
- /* Map new IO address */
- s->PCI0IO_start = s->regs[GT_PCI0IOLD] << 21;
- s->PCI0IO_length = ((s->regs[GT_PCI0IOHD] + 1) -
- (s->regs[GT_PCI0IOLD] & 0x7f)) << 21;
- if (s->PCI0IO_length) {
- memory_region_init_alias(&s->PCI0IO_mem, OBJECT(s), "pci0-io",
- get_system_io(), 0, s->PCI0IO_length);
- memory_region_add_subregion(get_system_memory(), s->PCI0IO_start,
- &s->PCI0IO_mem);
- }
- }
-
- /* Update PCI0M0 mapping */
- if ((s->regs[GT_PCI0M0LD] & 0x7f) <= s->regs[GT_PCI0M0HD]) {
- /* Unmap old MEM address */
- if (s->PCI0M0_length) {
- memory_region_del_subregion(get_system_memory(), &s->PCI0M0_mem);
- object_unparent(OBJECT(&s->PCI0M0_mem));
- }
- /* Map new mem address */
- s->PCI0M0_start = s->regs[GT_PCI0M0LD] << 21;
- s->PCI0M0_length = ((s->regs[GT_PCI0M0HD] + 1) -
- (s->regs[GT_PCI0M0LD] & 0x7f)) << 21;
- if (s->PCI0M0_length) {
- memory_region_init_alias(&s->PCI0M0_mem, OBJECT(s), "pci0-mem0",
- &s->pci0_mem, s->PCI0M0_start,
- s->PCI0M0_length);
- memory_region_add_subregion(get_system_memory(), s->PCI0M0_start,
- &s->PCI0M0_mem);
- }
- }
-
- /* Update PCI0M1 mapping */
- if ((s->regs[GT_PCI0M1LD] & 0x7f) <= s->regs[GT_PCI0M1HD]) {
- /* Unmap old MEM address */
- if (s->PCI0M1_length) {
- memory_region_del_subregion(get_system_memory(), &s->PCI0M1_mem);
- object_unparent(OBJECT(&s->PCI0M1_mem));
- }
- /* Map new mem address */
- s->PCI0M1_start = s->regs[GT_PCI0M1LD] << 21;
- s->PCI0M1_length = ((s->regs[GT_PCI0M1HD] + 1) -
- (s->regs[GT_PCI0M1LD] & 0x7f)) << 21;
- if (s->PCI0M1_length) {
- memory_region_init_alias(&s->PCI0M1_mem, OBJECT(s), "pci0-mem1",
- &s->pci0_mem, s->PCI0M1_start,
- s->PCI0M1_length);
- memory_region_add_subregion(get_system_memory(), s->PCI0M1_start,
- &s->PCI0M1_mem);
- }
- }
-}
-
-static int gt64120_post_load(void *opaque, int version_id)
-{
- GT64120State *s = opaque;
-
- gt64120_isd_mapping(s);
- gt64120_pci_mapping(s);
-
- return 0;
-}
-
-static const VMStateDescription vmstate_gt64120 = {
- .name = "gt64120",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = gt64120_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, GT64120State, GT_REGS),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void gt64120_writel (void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- GT64120State *s = opaque;
- PCIHostState *phb = PCI_HOST_BRIDGE(s);
- uint32_t saddr;
-
- if (!(s->regs[GT_CPU] & 0x00001000))
- val = bswap32(val);
-
- saddr = (addr & 0xfff) >> 2;
- switch (saddr) {
-
- /* CPU Configuration */
- case GT_CPU:
- s->regs[GT_CPU] = val;
- break;
- case GT_MULTI:
- /* Read-only register as only one GT64xxx is present on the CPU bus */
- break;
-
- /* CPU Address Decode */
- case GT_PCI0IOLD:
- s->regs[GT_PCI0IOLD] = val & 0x00007fff;
- s->regs[GT_PCI0IOREMAP] = val & 0x000007ff;
- gt64120_pci_mapping(s);
- break;
- case GT_PCI0M0LD:
- s->regs[GT_PCI0M0LD] = val & 0x00007fff;
- s->regs[GT_PCI0M0REMAP] = val & 0x000007ff;
- gt64120_pci_mapping(s);
- break;
- case GT_PCI0M1LD:
- s->regs[GT_PCI0M1LD] = val & 0x00007fff;
- s->regs[GT_PCI0M1REMAP] = val & 0x000007ff;
- gt64120_pci_mapping(s);
- break;
- case GT_PCI1IOLD:
- s->regs[GT_PCI1IOLD] = val & 0x00007fff;
- s->regs[GT_PCI1IOREMAP] = val & 0x000007ff;
- break;
- case GT_PCI1M0LD:
- s->regs[GT_PCI1M0LD] = val & 0x00007fff;
- s->regs[GT_PCI1M0REMAP] = val & 0x000007ff;
- break;
- case GT_PCI1M1LD:
- s->regs[GT_PCI1M1LD] = val & 0x00007fff;
- s->regs[GT_PCI1M1REMAP] = val & 0x000007ff;
- break;
- case GT_PCI0M0HD:
- case GT_PCI0M1HD:
- case GT_PCI0IOHD:
- s->regs[saddr] = val & 0x0000007f;
- gt64120_pci_mapping(s);
- break;
- case GT_PCI1IOHD:
- case GT_PCI1M0HD:
- case GT_PCI1M1HD:
- s->regs[saddr] = val & 0x0000007f;
- break;
- case GT_ISD:
- s->regs[saddr] = val & 0x00007fff;
- gt64120_isd_mapping(s);
- break;
-
- case GT_PCI0IOREMAP:
- case GT_PCI0M0REMAP:
- case GT_PCI0M1REMAP:
- case GT_PCI1IOREMAP:
- case GT_PCI1M0REMAP:
- case GT_PCI1M1REMAP:
- s->regs[saddr] = val & 0x000007ff;
- break;
-
- /* CPU Error Report */
- case GT_CPUERR_ADDRLO:
- case GT_CPUERR_ADDRHI:
- case GT_CPUERR_DATALO:
- case GT_CPUERR_DATAHI:
- case GT_CPUERR_PARITY:
- /* Read-only registers, do nothing */
- break;
-
- /* CPU Sync Barrier */
- case GT_PCI0SYNC:
- case GT_PCI1SYNC:
- /* Read-only registers, do nothing */
- break;
-
- /* SDRAM and Device Address Decode */
- case GT_SCS0LD:
- case GT_SCS0HD:
- case GT_SCS1LD:
- case GT_SCS1HD:
- case GT_SCS2LD:
- case GT_SCS2HD:
- case GT_SCS3LD:
- case GT_SCS3HD:
- case GT_CS0LD:
- case GT_CS0HD:
- case GT_CS1LD:
- case GT_CS1HD:
- case GT_CS2LD:
- case GT_CS2HD:
- case GT_CS3LD:
- case GT_CS3HD:
- case GT_BOOTLD:
- case GT_BOOTHD:
- case GT_ADERR:
- /* SDRAM Configuration */
- case GT_SDRAM_CFG:
- case GT_SDRAM_OPMODE:
- case GT_SDRAM_BM:
- case GT_SDRAM_ADDRDECODE:
- /* Accept and ignore SDRAM interleave configuration */
- s->regs[saddr] = val;
- break;
-
- /* Device Parameters */
- case GT_DEV_B0:
- case GT_DEV_B1:
- case GT_DEV_B2:
- case GT_DEV_B3:
- case GT_DEV_BOOT:
- /* Not implemented */
- DPRINTF ("Unimplemented device register offset 0x%x\n", saddr << 2);
- break;
-
- /* ECC */
- case GT_ECC_ERRDATALO:
- case GT_ECC_ERRDATAHI:
- case GT_ECC_MEM:
- case GT_ECC_CALC:
- case GT_ECC_ERRADDR:
- /* Read-only registers, do nothing */
- break;
-
- /* DMA Record */
- case GT_DMA0_CNT:
- case GT_DMA1_CNT:
- case GT_DMA2_CNT:
- case GT_DMA3_CNT:
- case GT_DMA0_SA:
- case GT_DMA1_SA:
- case GT_DMA2_SA:
- case GT_DMA3_SA:
- case GT_DMA0_DA:
- case GT_DMA1_DA:
- case GT_DMA2_DA:
- case GT_DMA3_DA:
- case GT_DMA0_NEXT:
- case GT_DMA1_NEXT:
- case GT_DMA2_NEXT:
- case GT_DMA3_NEXT:
- case GT_DMA0_CUR:
- case GT_DMA1_CUR:
- case GT_DMA2_CUR:
- case GT_DMA3_CUR:
- /* Not implemented */
- DPRINTF ("Unimplemented DMA register offset 0x%x\n", saddr << 2);
- break;
-
- /* DMA Channel Control */
- case GT_DMA0_CTRL:
- case GT_DMA1_CTRL:
- case GT_DMA2_CTRL:
- case GT_DMA3_CTRL:
- /* Not implemented */
- DPRINTF ("Unimplemented DMA register offset 0x%x\n", saddr << 2);
- break;
-
- /* DMA Arbiter */
- case GT_DMA_ARB:
- /* Not implemented */
- DPRINTF ("Unimplemented DMA register offset 0x%x\n", saddr << 2);
- break;
-
- /* Timer/Counter */
- case GT_TC0:
- case GT_TC1:
- case GT_TC2:
- case GT_TC3:
- case GT_TC_CONTROL:
- /* Not implemented */
- DPRINTF ("Unimplemented timer register offset 0x%x\n", saddr << 2);
- break;
-
- /* PCI Internal */
- case GT_PCI0_CMD:
- case GT_PCI1_CMD:
- s->regs[saddr] = val & 0x0401fc0f;
- break;
- case GT_PCI0_TOR:
- case GT_PCI0_BS_SCS10:
- case GT_PCI0_BS_SCS32:
- case GT_PCI0_BS_CS20:
- case GT_PCI0_BS_CS3BT:
- case GT_PCI1_IACK:
- case GT_PCI0_IACK:
- case GT_PCI0_BARE:
- case GT_PCI0_PREFMBR:
- case GT_PCI0_SCS10_BAR:
- case GT_PCI0_SCS32_BAR:
- case GT_PCI0_CS20_BAR:
- case GT_PCI0_CS3BT_BAR:
- case GT_PCI0_SSCS10_BAR:
- case GT_PCI0_SSCS32_BAR:
- case GT_PCI0_SCS3BT_BAR:
- case GT_PCI1_TOR:
- case GT_PCI1_BS_SCS10:
- case GT_PCI1_BS_SCS32:
- case GT_PCI1_BS_CS20:
- case GT_PCI1_BS_CS3BT:
- case GT_PCI1_BARE:
- case GT_PCI1_PREFMBR:
- case GT_PCI1_SCS10_BAR:
- case GT_PCI1_SCS32_BAR:
- case GT_PCI1_CS20_BAR:
- case GT_PCI1_CS3BT_BAR:
- case GT_PCI1_SSCS10_BAR:
- case GT_PCI1_SSCS32_BAR:
- case GT_PCI1_SCS3BT_BAR:
- case GT_PCI1_CFGADDR:
- case GT_PCI1_CFGDATA:
- /* not implemented */
- break;
- case GT_PCI0_CFGADDR:
- phb->config_reg = val & 0x80fffffc;
- break;
- case GT_PCI0_CFGDATA:
- if (!(s->regs[GT_PCI0_CMD] & 1) && (phb->config_reg & 0x00fff800)) {
- val = bswap32(val);
- }
- if (phb->config_reg & (1u << 31)) {
- pci_data_write(phb->bus, phb->config_reg, val, 4);
- }
- break;
-
- /* Interrupts */
- case GT_INTRCAUSE:
- /* not really implemented */
- s->regs[saddr] = ~(~(s->regs[saddr]) | ~(val & 0xfffffffe));
- s->regs[saddr] |= !!(s->regs[saddr] & 0xfffffffe);
- DPRINTF("INTRCAUSE %" PRIx64 "\n", val);
- break;
- case GT_INTRMASK:
- s->regs[saddr] = val & 0x3c3ffffe;
- DPRINTF("INTRMASK %" PRIx64 "\n", val);
- break;
- case GT_PCI0_ICMASK:
- s->regs[saddr] = val & 0x03fffffe;
- DPRINTF("ICMASK %" PRIx64 "\n", val);
- break;
- case GT_PCI0_SERR0MASK:
- s->regs[saddr] = val & 0x0000003f;
- DPRINTF("SERR0MASK %" PRIx64 "\n", val);
- break;
-
- /* Reserved when only PCI_0 is configured. */
- case GT_HINTRCAUSE:
- case GT_CPU_INTSEL:
- case GT_PCI0_INTSEL:
- case GT_HINTRMASK:
- case GT_PCI0_HICMASK:
- case GT_PCI1_SERR1MASK:
- /* not implemented */
- break;
-
- /* SDRAM Parameters */
- case GT_SDRAM_B0:
- case GT_SDRAM_B1:
- case GT_SDRAM_B2:
- case GT_SDRAM_B3:
- /* We don't simulate electrical parameters of the SDRAM.
- Accept, but ignore the values. */
- s->regs[saddr] = val;
- break;
-
- default:
- DPRINTF ("Bad register offset 0x%x\n", (int)addr);
- break;
- }
-}
-
-static uint64_t gt64120_readl (void *opaque,
- hwaddr addr, unsigned size)
-{
- GT64120State *s = opaque;
- PCIHostState *phb = PCI_HOST_BRIDGE(s);
- uint32_t val;
- uint32_t saddr;
-
- saddr = (addr & 0xfff) >> 2;
- switch (saddr) {
-
- /* CPU Configuration */
- case GT_MULTI:
- /* Only one GT64xxx is present on the CPU bus, return
- the initial value */
- val = s->regs[saddr];
- break;
-
- /* CPU Error Report */
- case GT_CPUERR_ADDRLO:
- case GT_CPUERR_ADDRHI:
- case GT_CPUERR_DATALO:
- case GT_CPUERR_DATAHI:
- case GT_CPUERR_PARITY:
- /* Emulated memory has no error, always return the initial
- values */
- val = s->regs[saddr];
- break;
-
- /* CPU Sync Barrier */
- case GT_PCI0SYNC:
- case GT_PCI1SYNC:
- /* Reading those register should empty all FIFO on the PCI
- bus, which are not emulated. The return value should be
- a random value that should be ignored. */
- val = 0xc000ffee;
- break;
-
- /* ECC */
- case GT_ECC_ERRDATALO:
- case GT_ECC_ERRDATAHI:
- case GT_ECC_MEM:
- case GT_ECC_CALC:
- case GT_ECC_ERRADDR:
- /* Emulated memory has no error, always return the initial
- values */
- val = s->regs[saddr];
- break;
-
- case GT_CPU:
- case GT_SCS10LD:
- case GT_SCS10HD:
- case GT_SCS32LD:
- case GT_SCS32HD:
- case GT_CS20LD:
- case GT_CS20HD:
- case GT_CS3BOOTLD:
- case GT_CS3BOOTHD:
- case GT_SCS10AR:
- case GT_SCS32AR:
- case GT_CS20R:
- case GT_CS3BOOTR:
- case GT_PCI0IOLD:
- case GT_PCI0M0LD:
- case GT_PCI0M1LD:
- case GT_PCI1IOLD:
- case GT_PCI1M0LD:
- case GT_PCI1M1LD:
- case GT_PCI0IOHD:
- case GT_PCI0M0HD:
- case GT_PCI0M1HD:
- case GT_PCI1IOHD:
- case GT_PCI1M0HD:
- case GT_PCI1M1HD:
- case GT_PCI0IOREMAP:
- case GT_PCI0M0REMAP:
- case GT_PCI0M1REMAP:
- case GT_PCI1IOREMAP:
- case GT_PCI1M0REMAP:
- case GT_PCI1M1REMAP:
- case GT_ISD:
- val = s->regs[saddr];
- break;
- case GT_PCI0_IACK:
- /* Read the IRQ number */
- val = pic_read_irq(isa_pic);
- break;
-
- /* SDRAM and Device Address Decode */
- case GT_SCS0LD:
- case GT_SCS0HD:
- case GT_SCS1LD:
- case GT_SCS1HD:
- case GT_SCS2LD:
- case GT_SCS2HD:
- case GT_SCS3LD:
- case GT_SCS3HD:
- case GT_CS0LD:
- case GT_CS0HD:
- case GT_CS1LD:
- case GT_CS1HD:
- case GT_CS2LD:
- case GT_CS2HD:
- case GT_CS3LD:
- case GT_CS3HD:
- case GT_BOOTLD:
- case GT_BOOTHD:
- case GT_ADERR:
- val = s->regs[saddr];
- break;
-
- /* SDRAM Configuration */
- case GT_SDRAM_CFG:
- case GT_SDRAM_OPMODE:
- case GT_SDRAM_BM:
- case GT_SDRAM_ADDRDECODE:
- val = s->regs[saddr];
- break;
-
- /* SDRAM Parameters */
- case GT_SDRAM_B0:
- case GT_SDRAM_B1:
- case GT_SDRAM_B2:
- case GT_SDRAM_B3:
- /* We don't simulate electrical parameters of the SDRAM.
- Just return the last written value. */
- val = s->regs[saddr];
- break;
-
- /* Device Parameters */
- case GT_DEV_B0:
- case GT_DEV_B1:
- case GT_DEV_B2:
- case GT_DEV_B3:
- case GT_DEV_BOOT:
- val = s->regs[saddr];
- break;
-
- /* DMA Record */
- case GT_DMA0_CNT:
- case GT_DMA1_CNT:
- case GT_DMA2_CNT:
- case GT_DMA3_CNT:
- case GT_DMA0_SA:
- case GT_DMA1_SA:
- case GT_DMA2_SA:
- case GT_DMA3_SA:
- case GT_DMA0_DA:
- case GT_DMA1_DA:
- case GT_DMA2_DA:
- case GT_DMA3_DA:
- case GT_DMA0_NEXT:
- case GT_DMA1_NEXT:
- case GT_DMA2_NEXT:
- case GT_DMA3_NEXT:
- case GT_DMA0_CUR:
- case GT_DMA1_CUR:
- case GT_DMA2_CUR:
- case GT_DMA3_CUR:
- val = s->regs[saddr];
- break;
-
- /* DMA Channel Control */
- case GT_DMA0_CTRL:
- case GT_DMA1_CTRL:
- case GT_DMA2_CTRL:
- case GT_DMA3_CTRL:
- val = s->regs[saddr];
- break;
-
- /* DMA Arbiter */
- case GT_DMA_ARB:
- val = s->regs[saddr];
- break;
-
- /* Timer/Counter */
- case GT_TC0:
- case GT_TC1:
- case GT_TC2:
- case GT_TC3:
- case GT_TC_CONTROL:
- val = s->regs[saddr];
- break;
-
- /* PCI Internal */
- case GT_PCI0_CFGADDR:
- val = phb->config_reg;
- break;
- case GT_PCI0_CFGDATA:
- if (!(phb->config_reg & (1 << 31))) {
- val = 0xffffffff;
- } else {
- val = pci_data_read(phb->bus, phb->config_reg, 4);
- }
- if (!(s->regs[GT_PCI0_CMD] & 1) && (phb->config_reg & 0x00fff800)) {
- val = bswap32(val);
- }
- break;
-
- case GT_PCI0_CMD:
- case GT_PCI0_TOR:
- case GT_PCI0_BS_SCS10:
- case GT_PCI0_BS_SCS32:
- case GT_PCI0_BS_CS20:
- case GT_PCI0_BS_CS3BT:
- case GT_PCI1_IACK:
- case GT_PCI0_BARE:
- case GT_PCI0_PREFMBR:
- case GT_PCI0_SCS10_BAR:
- case GT_PCI0_SCS32_BAR:
- case GT_PCI0_CS20_BAR:
- case GT_PCI0_CS3BT_BAR:
- case GT_PCI0_SSCS10_BAR:
- case GT_PCI0_SSCS32_BAR:
- case GT_PCI0_SCS3BT_BAR:
- case GT_PCI1_CMD:
- case GT_PCI1_TOR:
- case GT_PCI1_BS_SCS10:
- case GT_PCI1_BS_SCS32:
- case GT_PCI1_BS_CS20:
- case GT_PCI1_BS_CS3BT:
- case GT_PCI1_BARE:
- case GT_PCI1_PREFMBR:
- case GT_PCI1_SCS10_BAR:
- case GT_PCI1_SCS32_BAR:
- case GT_PCI1_CS20_BAR:
- case GT_PCI1_CS3BT_BAR:
- case GT_PCI1_SSCS10_BAR:
- case GT_PCI1_SSCS32_BAR:
- case GT_PCI1_SCS3BT_BAR:
- case GT_PCI1_CFGADDR:
- case GT_PCI1_CFGDATA:
- val = s->regs[saddr];
- break;
-
- /* Interrupts */
- case GT_INTRCAUSE:
- val = s->regs[saddr];
- DPRINTF("INTRCAUSE %x\n", val);
- break;
- case GT_INTRMASK:
- val = s->regs[saddr];
- DPRINTF("INTRMASK %x\n", val);
- break;
- case GT_PCI0_ICMASK:
- val = s->regs[saddr];
- DPRINTF("ICMASK %x\n", val);
- break;
- case GT_PCI0_SERR0MASK:
- val = s->regs[saddr];
- DPRINTF("SERR0MASK %x\n", val);
- break;
-
- /* Reserved when only PCI_0 is configured. */
- case GT_HINTRCAUSE:
- case GT_CPU_INTSEL:
- case GT_PCI0_INTSEL:
- case GT_HINTRMASK:
- case GT_PCI0_HICMASK:
- case GT_PCI1_SERR1MASK:
- val = s->regs[saddr];
- break;
-
- default:
- val = s->regs[saddr];
- DPRINTF ("Bad register offset 0x%x\n", (int)addr);
- break;
- }
-
- if (!(s->regs[GT_CPU] & 0x00001000))
- val = bswap32(val);
-
- return val;
-}
-
-static const MemoryRegionOps isd_mem_ops = {
- .read = gt64120_readl,
- .write = gt64120_writel,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int gt64120_pci_map_irq(PCIDevice *pci_dev, int irq_num)
-{
- int slot;
-
- slot = (pci_dev->devfn >> 3);
-
- switch (slot) {
- /* PIIX4 USB */
- case 10:
- return 3;
- /* AMD 79C973 Ethernet */
- case 11:
- return 1;
- /* Crystal 4281 Sound */
- case 12:
- return 2;
- /* PCI slot 1 to 4 */
- case 18 ... 21:
- return ((slot - 18) + irq_num) & 0x03;
- /* Unknown device, don't do any translation */
- default:
- return irq_num;
- }
-}
-
-static int pci_irq_levels[4];
-
-static void gt64120_pci_set_irq(void *opaque, int irq_num, int level)
-{
- int i, pic_irq, pic_level;
- qemu_irq *pic = opaque;
-
- pci_irq_levels[irq_num] = level;
-
- /* now we change the pic irq level according to the piix irq mappings */
- /* XXX: optimize */
- pic_irq = piix4_dev->config[0x60 + irq_num];
- if (pic_irq < 16) {
- /* The pic level is the logical OR of all the PCI irqs mapped
- to it */
- pic_level = 0;
- for (i = 0; i < 4; i++) {
- if (pic_irq == piix4_dev->config[0x60 + i])
- pic_level |= pci_irq_levels[i];
- }
- qemu_set_irq(pic[pic_irq], pic_level);
- }
-}
-
-
-static void gt64120_reset(void *opaque)
-{
- GT64120State *s = opaque;
-
- /* FIXME: Malta specific hw assumptions ahead */
-
- /* CPU Configuration */
-#ifdef TARGET_WORDS_BIGENDIAN
- s->regs[GT_CPU] = 0x00000000;
-#else
- s->regs[GT_CPU] = 0x00001000;
-#endif
- s->regs[GT_MULTI] = 0x00000003;
-
- /* CPU Address decode */
- s->regs[GT_SCS10LD] = 0x00000000;
- s->regs[GT_SCS10HD] = 0x00000007;
- s->regs[GT_SCS32LD] = 0x00000008;
- s->regs[GT_SCS32HD] = 0x0000000f;
- s->regs[GT_CS20LD] = 0x000000e0;
- s->regs[GT_CS20HD] = 0x00000070;
- s->regs[GT_CS3BOOTLD] = 0x000000f8;
- s->regs[GT_CS3BOOTHD] = 0x0000007f;
-
- s->regs[GT_PCI0IOLD] = 0x00000080;
- s->regs[GT_PCI0IOHD] = 0x0000000f;
- s->regs[GT_PCI0M0LD] = 0x00000090;
- s->regs[GT_PCI0M0HD] = 0x0000001f;
- s->regs[GT_ISD] = 0x000000a0;
- s->regs[GT_PCI0M1LD] = 0x00000790;
- s->regs[GT_PCI0M1HD] = 0x0000001f;
- s->regs[GT_PCI1IOLD] = 0x00000100;
- s->regs[GT_PCI1IOHD] = 0x0000000f;
- s->regs[GT_PCI1M0LD] = 0x00000110;
- s->regs[GT_PCI1M0HD] = 0x0000001f;
- s->regs[GT_PCI1M1LD] = 0x00000120;
- s->regs[GT_PCI1M1HD] = 0x0000002f;
-
- s->regs[GT_SCS10AR] = 0x00000000;
- s->regs[GT_SCS32AR] = 0x00000008;
- s->regs[GT_CS20R] = 0x000000e0;
- s->regs[GT_CS3BOOTR] = 0x000000f8;
-
- s->regs[GT_PCI0IOREMAP] = 0x00000080;
- s->regs[GT_PCI0M0REMAP] = 0x00000090;
- s->regs[GT_PCI0M1REMAP] = 0x00000790;
- s->regs[GT_PCI1IOREMAP] = 0x00000100;
- s->regs[GT_PCI1M0REMAP] = 0x00000110;
- s->regs[GT_PCI1M1REMAP] = 0x00000120;
-
- /* CPU Error Report */
- s->regs[GT_CPUERR_ADDRLO] = 0x00000000;
- s->regs[GT_CPUERR_ADDRHI] = 0x00000000;
- s->regs[GT_CPUERR_DATALO] = 0xffffffff;
- s->regs[GT_CPUERR_DATAHI] = 0xffffffff;
- s->regs[GT_CPUERR_PARITY] = 0x000000ff;
-
- /* CPU Sync Barrier */
- s->regs[GT_PCI0SYNC] = 0x00000000;
- s->regs[GT_PCI1SYNC] = 0x00000000;
-
- /* SDRAM and Device Address Decode */
- s->regs[GT_SCS0LD] = 0x00000000;
- s->regs[GT_SCS0HD] = 0x00000007;
- s->regs[GT_SCS1LD] = 0x00000008;
- s->regs[GT_SCS1HD] = 0x0000000f;
- s->regs[GT_SCS2LD] = 0x00000010;
- s->regs[GT_SCS2HD] = 0x00000017;
- s->regs[GT_SCS3LD] = 0x00000018;
- s->regs[GT_SCS3HD] = 0x0000001f;
- s->regs[GT_CS0LD] = 0x000000c0;
- s->regs[GT_CS0HD] = 0x000000c7;
- s->regs[GT_CS1LD] = 0x000000c8;
- s->regs[GT_CS1HD] = 0x000000cf;
- s->regs[GT_CS2LD] = 0x000000d0;
- s->regs[GT_CS2HD] = 0x000000df;
- s->regs[GT_CS3LD] = 0x000000f0;
- s->regs[GT_CS3HD] = 0x000000fb;
- s->regs[GT_BOOTLD] = 0x000000fc;
- s->regs[GT_BOOTHD] = 0x000000ff;
- s->regs[GT_ADERR] = 0xffffffff;
-
- /* SDRAM Configuration */
- s->regs[GT_SDRAM_CFG] = 0x00000200;
- s->regs[GT_SDRAM_OPMODE] = 0x00000000;
- s->regs[GT_SDRAM_BM] = 0x00000007;
- s->regs[GT_SDRAM_ADDRDECODE] = 0x00000002;
-
- /* SDRAM Parameters */
- s->regs[GT_SDRAM_B0] = 0x00000005;
- s->regs[GT_SDRAM_B1] = 0x00000005;
- s->regs[GT_SDRAM_B2] = 0x00000005;
- s->regs[GT_SDRAM_B3] = 0x00000005;
-
- /* ECC */
- s->regs[GT_ECC_ERRDATALO] = 0x00000000;
- s->regs[GT_ECC_ERRDATAHI] = 0x00000000;
- s->regs[GT_ECC_MEM] = 0x00000000;
- s->regs[GT_ECC_CALC] = 0x00000000;
- s->regs[GT_ECC_ERRADDR] = 0x00000000;
-
- /* Device Parameters */
- s->regs[GT_DEV_B0] = 0x386fffff;
- s->regs[GT_DEV_B1] = 0x386fffff;
- s->regs[GT_DEV_B2] = 0x386fffff;
- s->regs[GT_DEV_B3] = 0x386fffff;
- s->regs[GT_DEV_BOOT] = 0x146fffff;
-
- /* DMA registers are all zeroed at reset */
-
- /* Timer/Counter */
- s->regs[GT_TC0] = 0xffffffff;
- s->regs[GT_TC1] = 0x00ffffff;
- s->regs[GT_TC2] = 0x00ffffff;
- s->regs[GT_TC3] = 0x00ffffff;
- s->regs[GT_TC_CONTROL] = 0x00000000;
-
- /* PCI Internal */
-#ifdef TARGET_WORDS_BIGENDIAN
- s->regs[GT_PCI0_CMD] = 0x00000000;
-#else
- s->regs[GT_PCI0_CMD] = 0x00010001;
-#endif
- s->regs[GT_PCI0_TOR] = 0x0000070f;
- s->regs[GT_PCI0_BS_SCS10] = 0x00fff000;
- s->regs[GT_PCI0_BS_SCS32] = 0x00fff000;
- s->regs[GT_PCI0_BS_CS20] = 0x01fff000;
- s->regs[GT_PCI0_BS_CS3BT] = 0x00fff000;
- s->regs[GT_PCI1_IACK] = 0x00000000;
- s->regs[GT_PCI0_IACK] = 0x00000000;
- s->regs[GT_PCI0_BARE] = 0x0000000f;
- s->regs[GT_PCI0_PREFMBR] = 0x00000040;
- s->regs[GT_PCI0_SCS10_BAR] = 0x00000000;
- s->regs[GT_PCI0_SCS32_BAR] = 0x01000000;
- s->regs[GT_PCI0_CS20_BAR] = 0x1c000000;
- s->regs[GT_PCI0_CS3BT_BAR] = 0x1f000000;
- s->regs[GT_PCI0_SSCS10_BAR] = 0x00000000;
- s->regs[GT_PCI0_SSCS32_BAR] = 0x01000000;
- s->regs[GT_PCI0_SCS3BT_BAR] = 0x1f000000;
-#ifdef TARGET_WORDS_BIGENDIAN
- s->regs[GT_PCI1_CMD] = 0x00000000;
-#else
- s->regs[GT_PCI1_CMD] = 0x00010001;
-#endif
- s->regs[GT_PCI1_TOR] = 0x0000070f;
- s->regs[GT_PCI1_BS_SCS10] = 0x00fff000;
- s->regs[GT_PCI1_BS_SCS32] = 0x00fff000;
- s->regs[GT_PCI1_BS_CS20] = 0x01fff000;
- s->regs[GT_PCI1_BS_CS3BT] = 0x00fff000;
- s->regs[GT_PCI1_BARE] = 0x0000000f;
- s->regs[GT_PCI1_PREFMBR] = 0x00000040;
- s->regs[GT_PCI1_SCS10_BAR] = 0x00000000;
- s->regs[GT_PCI1_SCS32_BAR] = 0x01000000;
- s->regs[GT_PCI1_CS20_BAR] = 0x1c000000;
- s->regs[GT_PCI1_CS3BT_BAR] = 0x1f000000;
- s->regs[GT_PCI1_SSCS10_BAR] = 0x00000000;
- s->regs[GT_PCI1_SSCS32_BAR] = 0x01000000;
- s->regs[GT_PCI1_SCS3BT_BAR] = 0x1f000000;
- s->regs[GT_PCI1_CFGADDR] = 0x00000000;
- s->regs[GT_PCI1_CFGDATA] = 0x00000000;
- s->regs[GT_PCI0_CFGADDR] = 0x00000000;
-
- /* Interrupt registers are all zeroed at reset */
-
- gt64120_isd_mapping(s);
- gt64120_pci_mapping(s);
-}
-
-PCIBus *gt64120_register(qemu_irq *pic)
-{
- GT64120State *d;
- PCIHostState *phb;
- DeviceState *dev;
-
- dev = qdev_create(NULL, TYPE_GT64120_PCI_HOST_BRIDGE);
- qdev_init_nofail(dev);
- d = GT64120_PCI_HOST_BRIDGE(dev);
- phb = PCI_HOST_BRIDGE(dev);
- memory_region_init(&d->pci0_mem, OBJECT(dev), "pci0-mem", UINT32_MAX);
- address_space_init(&d->pci0_mem_as, &d->pci0_mem, "pci0-mem");
- phb->bus = pci_register_bus(dev, "pci",
- gt64120_pci_set_irq, gt64120_pci_map_irq,
- pic,
- &d->pci0_mem,
- get_system_io(),
- PCI_DEVFN(18, 0), 4, TYPE_PCI_BUS);
- memory_region_init_io(&d->ISD_mem, OBJECT(dev), &isd_mem_ops, d, "isd-mem", 0x1000);
-
- pci_create_simple(phb->bus, PCI_DEVFN(0, 0), "gt64120_pci");
- return phb->bus;
-}
-
-static int gt64120_init(SysBusDevice *dev)
-{
- GT64120State *s;
-
- s = GT64120_PCI_HOST_BRIDGE(dev);
-
- qemu_register_reset(gt64120_reset, s);
- return 0;
-}
-
-static void gt64120_pci_realize(PCIDevice *d, Error **errp)
-{
- /* FIXME: Malta specific hw assumptions ahead */
- pci_set_word(d->config + PCI_COMMAND, 0);
- pci_set_word(d->config + PCI_STATUS,
- PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM);
- pci_config_set_prog_interface(d->config, 0);
- pci_set_long(d->config + PCI_BASE_ADDRESS_0, 0x00000008);
- pci_set_long(d->config + PCI_BASE_ADDRESS_1, 0x01000008);
- pci_set_long(d->config + PCI_BASE_ADDRESS_2, 0x1c000000);
- pci_set_long(d->config + PCI_BASE_ADDRESS_3, 0x1f000000);
- pci_set_long(d->config + PCI_BASE_ADDRESS_4, 0x14000000);
- pci_set_long(d->config + PCI_BASE_ADDRESS_5, 0x14000001);
- pci_set_byte(d->config + 0x3d, 0x01);
-}
-
-static void gt64120_pci_class_init(ObjectClass *klass, void *data)
-{
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- k->realize = gt64120_pci_realize;
- k->vendor_id = PCI_VENDOR_ID_MARVELL;
- k->device_id = PCI_DEVICE_ID_MARVELL_GT6412X;
- k->revision = 0x10;
- k->class_id = PCI_CLASS_BRIDGE_HOST;
- /*
- * PCI-facing part of the host bridge, not usable without the
- * host-facing part, which can't be device_add'ed, yet.
- */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo gt64120_pci_info = {
- .name = "gt64120_pci",
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(PCIDevice),
- .class_init = gt64120_pci_class_init,
-};
-
-static void gt64120_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
- sdc->init = gt64120_init;
- dc->vmsd = &vmstate_gt64120;
-}
-
-static const TypeInfo gt64120_info = {
- .name = TYPE_GT64120_PCI_HOST_BRIDGE,
- .parent = TYPE_PCI_HOST_BRIDGE,
- .instance_size = sizeof(GT64120State),
- .class_init = gt64120_class_init,
-};
-
-static void gt64120_pci_register_types(void)
-{
- type_register_static(&gt64120_info);
- type_register_static(&gt64120_pci_info);
-}
-
-type_init(gt64120_pci_register_types)
diff --git a/qemu/hw/mips/mips_fulong2e.c b/qemu/hw/mips/mips_fulong2e.c
deleted file mode 100644
index bdb716e72..000000000
--- a/qemu/hw/mips/mips_fulong2e.c
+++ /dev/null
@@ -1,392 +0,0 @@
-/*
- * QEMU fulong 2e mini pc support
- *
- * Copyright (c) 2008 yajin (yajin@vm-kernel.org)
- * Copyright (c) 2009 chenming (chenming@rdc.faw.com.cn)
- * Copyright (c) 2010 Huacai Chen (zltjiangshi@gmail.com)
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-/*
- * Fulong 2e mini pc is based on ICT/ST Loongson 2e CPU (MIPS III like, 800MHz)
- * http://www.linux-mips.org/wiki/Fulong
- *
- * Loongson 2e user manual:
- * http://www.loongsondeveloper.com/doc/Loongson2EUserGuide.pdf
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/hw.h"
-#include "hw/i386/pc.h"
-#include "hw/char/serial.h"
-#include "hw/block/fdc.h"
-#include "net/net.h"
-#include "hw/boards.h"
-#include "hw/i2c/smbus.h"
-#include "sysemu/block-backend.h"
-#include "hw/block/flash.h"
-#include "hw/mips/mips.h"
-#include "hw/mips/cpudevs.h"
-#include "hw/pci/pci.h"
-#include "sysemu/char.h"
-#include "sysemu/sysemu.h"
-#include "audio/audio.h"
-#include "qemu/log.h"
-#include "hw/loader.h"
-#include "hw/mips/bios.h"
-#include "hw/ide.h"
-#include "elf.h"
-#include "hw/isa/vt82c686.h"
-#include "hw/timer/mc146818rtc.h"
-#include "hw/timer/i8254.h"
-#include "sysemu/blockdev.h"
-#include "exec/address-spaces.h"
-#include "sysemu/qtest.h"
-#include "qemu/error-report.h"
-
-#define DEBUG_FULONG2E_INIT
-
-#define ENVP_ADDR 0x80002000l
-#define ENVP_NB_ENTRIES 16
-#define ENVP_ENTRY_SIZE 256
-
-#define MAX_IDE_BUS 2
-
-/*
- * PMON is not part of qemu and released with BSD license, anyone
- * who want to build a pmon binary please first git-clone the source
- * from the git repository at:
- * http://www.loongson.cn/support/git/pmon
- * Then follow the "Compile Guide" available at:
- * http://dev.lemote.com/code/pmon
- *
- * Notes:
- * 1, don't use the source at http://dev.lemote.com/http_git/pmon.git
- * 2, use "Bonito2edev" to replace "dir_corresponding_to_your_target_hardware"
- * in the "Compile Guide".
- */
-#define FULONG_BIOSNAME "pmon_fulong2e.bin"
-
-/* PCI SLOT in fulong 2e */
-#define FULONG2E_VIA_SLOT 5
-#define FULONG2E_ATI_SLOT 6
-#define FULONG2E_RTL8139_SLOT 7
-
-static ISADevice *pit;
-
-static struct _loaderparams {
- int ram_size;
- const char *kernel_filename;
- const char *kernel_cmdline;
- const char *initrd_filename;
-} loaderparams;
-
-static void GCC_FMT_ATTR(3, 4) prom_set(uint32_t* prom_buf, int index,
- const char *string, ...)
-{
- va_list ap;
- int32_t table_addr;
-
- if (index >= ENVP_NB_ENTRIES)
- return;
-
- if (string == NULL) {
- prom_buf[index] = 0;
- return;
- }
-
- table_addr = sizeof(int32_t) * ENVP_NB_ENTRIES + index * ENVP_ENTRY_SIZE;
- prom_buf[index] = tswap32(ENVP_ADDR + table_addr);
-
- va_start(ap, string);
- vsnprintf((char *)prom_buf + table_addr, ENVP_ENTRY_SIZE, string, ap);
- va_end(ap);
-}
-
-static int64_t load_kernel (CPUMIPSState *env)
-{
- int64_t kernel_entry, kernel_low, kernel_high;
- int index = 0;
- long initrd_size;
- ram_addr_t initrd_offset;
- uint32_t *prom_buf;
- long prom_size;
-
- if (load_elf(loaderparams.kernel_filename, cpu_mips_kseg0_to_phys, NULL,
- (uint64_t *)&kernel_entry, (uint64_t *)&kernel_low,
- (uint64_t *)&kernel_high, 0, EM_MIPS, 1, 0) < 0) {
- fprintf(stderr, "qemu: could not load kernel '%s'\n",
- loaderparams.kernel_filename);
- exit(1);
- }
-
- /* load initrd */
- initrd_size = 0;
- initrd_offset = 0;
- if (loaderparams.initrd_filename) {
- initrd_size = get_image_size (loaderparams.initrd_filename);
- if (initrd_size > 0) {
- initrd_offset = (kernel_high + ~INITRD_PAGE_MASK) & INITRD_PAGE_MASK;
- if (initrd_offset + initrd_size > ram_size) {
- fprintf(stderr,
- "qemu: memory too small for initial ram disk '%s'\n",
- loaderparams.initrd_filename);
- exit(1);
- }
- initrd_size = load_image_targphys(loaderparams.initrd_filename,
- initrd_offset, ram_size - initrd_offset);
- }
- if (initrd_size == (target_ulong) -1) {
- fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
- loaderparams.initrd_filename);
- exit(1);
- }
- }
-
- /* Setup prom parameters. */
- prom_size = ENVP_NB_ENTRIES * (sizeof(int32_t) + ENVP_ENTRY_SIZE);
- prom_buf = g_malloc(prom_size);
-
- prom_set(prom_buf, index++, "%s", loaderparams.kernel_filename);
- if (initrd_size > 0) {
- prom_set(prom_buf, index++, "rd_start=0x%" PRIx64 " rd_size=%li %s",
- cpu_mips_phys_to_kseg0(NULL, initrd_offset), initrd_size,
- loaderparams.kernel_cmdline);
- } else {
- prom_set(prom_buf, index++, "%s", loaderparams.kernel_cmdline);
- }
-
- /* Setup minimum environment variables */
- prom_set(prom_buf, index++, "busclock=33000000");
- prom_set(prom_buf, index++, "cpuclock=100000000");
- prom_set(prom_buf, index++, "memsize=%i", loaderparams.ram_size/1024/1024);
- prom_set(prom_buf, index++, "modetty0=38400n8r");
- prom_set(prom_buf, index++, NULL);
-
- rom_add_blob_fixed("prom", prom_buf, prom_size,
- cpu_mips_kseg0_to_phys(NULL, ENVP_ADDR));
-
- g_free(prom_buf);
- return kernel_entry;
-}
-
-static void write_bootloader (CPUMIPSState *env, uint8_t *base, int64_t kernel_addr)
-{
- uint32_t *p;
-
- /* Small bootloader */
- p = (uint32_t *) base;
-
- stl_p(p++, 0x0bf00010); /* j 0x1fc00040 */
- stl_p(p++, 0x00000000); /* nop */
-
- /* Second part of the bootloader */
- p = (uint32_t *) (base + 0x040);
-
- stl_p(p++, 0x3c040000); /* lui a0, 0 */
- stl_p(p++, 0x34840002); /* ori a0, a0, 2 */
- stl_p(p++, 0x3c050000 | ((ENVP_ADDR >> 16) & 0xffff)); /* lui a1, high(ENVP_ADDR) */
- stl_p(p++, 0x34a50000 | (ENVP_ADDR & 0xffff)); /* ori a1, a0, low(ENVP_ADDR) */
- stl_p(p++, 0x3c060000 | (((ENVP_ADDR + 8) >> 16) & 0xffff)); /* lui a2, high(ENVP_ADDR + 8) */
- stl_p(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff)); /* ori a2, a2, low(ENVP_ADDR + 8) */
- stl_p(p++, 0x3c070000 | (loaderparams.ram_size >> 16)); /* lui a3, high(env->ram_size) */
- stl_p(p++, 0x34e70000 | (loaderparams.ram_size & 0xffff)); /* ori a3, a3, low(env->ram_size) */
- stl_p(p++, 0x3c1f0000 | ((kernel_addr >> 16) & 0xffff)); /* lui ra, high(kernel_addr) */;
- stl_p(p++, 0x37ff0000 | (kernel_addr & 0xffff)); /* ori ra, ra, low(kernel_addr) */
- stl_p(p++, 0x03e00008); /* jr ra */
- stl_p(p++, 0x00000000); /* nop */
-}
-
-
-static void main_cpu_reset(void *opaque)
-{
- MIPSCPU *cpu = opaque;
- CPUMIPSState *env = &cpu->env;
-
- cpu_reset(CPU(cpu));
- /* TODO: 2E reset stuff */
- if (loaderparams.kernel_filename) {
- env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL));
- }
-}
-
-static const uint8_t eeprom_spd[0x80] = {
- 0x80,0x08,0x07,0x0d,0x09,0x02,0x40,0x00,0x04,0x70,
- 0x70,0x00,0x82,0x10,0x00,0x01,0x0e,0x04,0x0c,0x01,
- 0x02,0x20,0x80,0x75,0x70,0x00,0x00,0x50,0x3c,0x50,
- 0x2d,0x20,0xb0,0xb0,0x50,0x50,0x00,0x00,0x00,0x00,
- 0x00,0x41,0x48,0x3c,0x32,0x75,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x9c,0x7b,0x07,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x48,0x42,0x35,0x34,0x41,0x32,
- 0x35,0x36,0x38,0x4b,0x4e,0x2d,0x41,0x37,0x35,0x42,
- 0x20,0x30,0x20
-};
-
-/* Audio support */
-static void audio_init (PCIBus *pci_bus)
-{
- vt82c686b_ac97_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 5));
- vt82c686b_mc97_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 6));
-}
-
-/* Network support */
-static void network_init (PCIBus *pci_bus)
-{
- int i;
-
- for(i = 0; i < nb_nics; i++) {
- NICInfo *nd = &nd_table[i];
- const char *default_devaddr = NULL;
-
- if (i == 0 && (!nd->model || strcmp(nd->model, "rtl8139") == 0)) {
- /* The fulong board has a RTL8139 card using PCI SLOT 7 */
- default_devaddr = "07";
- }
-
- pci_nic_init_nofail(nd, pci_bus, "rtl8139", default_devaddr);
- }
-}
-
-static void mips_fulong2e_init(MachineState *machine)
-{
- ram_addr_t ram_size = machine->ram_size;
- const char *cpu_model = machine->cpu_model;
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- const char *initrd_filename = machine->initrd_filename;
- char *filename;
- MemoryRegion *address_space_mem = get_system_memory();
- MemoryRegion *ram = g_new(MemoryRegion, 1);
- MemoryRegion *bios = g_new(MemoryRegion, 1);
- long bios_size;
- int64_t kernel_entry;
- qemu_irq *i8259;
- PCIBus *pci_bus;
- ISABus *isa_bus;
- I2CBus *smbus;
- DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
- MIPSCPU *cpu;
- CPUMIPSState *env;
-
- /* init CPUs */
- if (cpu_model == NULL) {
- cpu_model = "Loongson-2E";
- }
- cpu = cpu_mips_init(cpu_model);
- if (cpu == NULL) {
- fprintf(stderr, "Unable to find CPU definition\n");
- exit(1);
- }
- env = &cpu->env;
-
- qemu_register_reset(main_cpu_reset, cpu);
-
- /* fulong 2e has 256M ram. */
- ram_size = 256 * 1024 * 1024;
-
- /* fulong 2e has a 1M flash.Winbond W39L040AP70Z */
- bios_size = 1024 * 1024;
-
- /* allocate RAM */
- memory_region_allocate_system_memory(ram, NULL, "fulong2e.ram", ram_size);
- memory_region_init_ram(bios, NULL, "fulong2e.bios", bios_size,
- &error_fatal);
- vmstate_register_ram_global(bios);
- memory_region_set_readonly(bios, true);
-
- memory_region_add_subregion(address_space_mem, 0, ram);
- memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios);
-
- /* We do not support flash operation, just loading pmon.bin as raw BIOS.
- * Please use -L to set the BIOS path and -bios to set bios name. */
-
- if (kernel_filename) {
- loaderparams.ram_size = ram_size;
- loaderparams.kernel_filename = kernel_filename;
- loaderparams.kernel_cmdline = kernel_cmdline;
- loaderparams.initrd_filename = initrd_filename;
- kernel_entry = load_kernel (env);
- write_bootloader(env, memory_region_get_ram_ptr(bios), kernel_entry);
- } else {
- if (bios_name == NULL) {
- bios_name = FULONG_BIOSNAME;
- }
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
- if (filename) {
- bios_size = load_image_targphys(filename, 0x1fc00000LL,
- BIOS_SIZE);
- g_free(filename);
- } else {
- bios_size = -1;
- }
-
- if ((bios_size < 0 || bios_size > BIOS_SIZE) &&
- !kernel_filename && !qtest_enabled()) {
- error_report("Could not load MIPS bios '%s'", bios_name);
- exit(1);
- }
- }
-
- /* Init internal devices */
- cpu_mips_irq_init_cpu(env);
- cpu_mips_clock_init(env);
-
- /* North bridge, Bonito --> IP2 */
- pci_bus = bonito_init((qemu_irq *)&(env->irq[2]));
-
- /* South bridge */
- ide_drive_get(hd, ARRAY_SIZE(hd));
-
- isa_bus = vt82c686b_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 0));
- if (!isa_bus) {
- fprintf(stderr, "vt82c686b_init error\n");
- exit(1);
- }
-
- /* Interrupt controller */
- /* The 8259 -> IP5 */
- i8259 = i8259_init(isa_bus, env->irq[5]);
- isa_bus_irqs(isa_bus, i8259);
-
- vt82c686b_ide_init(pci_bus, hd, PCI_DEVFN(FULONG2E_VIA_SLOT, 1));
- pci_create_simple(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 2),
- "vt82c686b-usb-uhci");
- pci_create_simple(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 3),
- "vt82c686b-usb-uhci");
-
- smbus = vt82c686b_pm_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 4),
- 0xeee1, NULL);
- /* TODO: Populate SPD eeprom data. */
- smbus_eeprom_init(smbus, 1, eeprom_spd, sizeof(eeprom_spd));
-
- /* init other devices */
- pit = pit_init(isa_bus, 0x40, 0, NULL);
- DMA_init(isa_bus, 0);
-
- /* Super I/O */
- isa_create_simple(isa_bus, "i8042");
-
- rtc_init(isa_bus, 2000, NULL);
-
- serial_hds_isa_init(isa_bus, MAX_SERIAL_PORTS);
- parallel_hds_isa_init(isa_bus, 1);
-
- /* Sound card */
- audio_init(pci_bus);
- /* Network card */
- network_init(pci_bus);
-}
-
-static void mips_fulong2e_machine_init(MachineClass *mc)
-{
- mc->desc = "Fulong 2e mini pc";
- mc->init = mips_fulong2e_init;
-}
-
-DEFINE_MACHINE("fulong2e", mips_fulong2e_machine_init)
diff --git a/qemu/hw/mips/mips_int.c b/qemu/hw/mips/mips_int.c
deleted file mode 100644
index 59081f9d1..000000000
--- a/qemu/hw/mips/mips_int.c
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * QEMU MIPS interrupt support
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/mips/cpudevs.h"
-#include "cpu.h"
-#include "sysemu/kvm.h"
-#include "kvm_mips.h"
-
-static void cpu_mips_irq_request(void *opaque, int irq, int level)
-{
- MIPSCPU *cpu = opaque;
- CPUMIPSState *env = &cpu->env;
- CPUState *cs = CPU(cpu);
-
- if (irq < 0 || irq > 7)
- return;
-
- if (level) {
- env->CP0_Cause |= 1 << (irq + CP0Ca_IP);
-
- if (kvm_enabled() && irq == 2) {
- kvm_mips_set_interrupt(cpu, irq, level);
- }
-
- } else {
- env->CP0_Cause &= ~(1 << (irq + CP0Ca_IP));
-
- if (kvm_enabled() && irq == 2) {
- kvm_mips_set_interrupt(cpu, irq, level);
- }
- }
-
- if (env->CP0_Cause & CP0Ca_IP_mask) {
- cpu_interrupt(cs, CPU_INTERRUPT_HARD);
- } else {
- cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
- }
-}
-
-void cpu_mips_irq_init_cpu(CPUMIPSState *env)
-{
- qemu_irq *qi;
- int i;
-
- qi = qemu_allocate_irqs(cpu_mips_irq_request, mips_env_get_cpu(env), 8);
- for (i = 0; i < 8; i++) {
- env->irq[i] = qi[i];
- }
-}
-
-void cpu_mips_soft_irq(CPUMIPSState *env, int irq, int level)
-{
- if (irq < 0 || irq > 2) {
- return;
- }
-
- qemu_set_irq(env->irq[irq], level);
-}
diff --git a/qemu/hw/mips/mips_jazz.c b/qemu/hw/mips/mips_jazz.c
deleted file mode 100644
index ac7c64125..000000000
--- a/qemu/hw/mips/mips_jazz.c
+++ /dev/null
@@ -1,391 +0,0 @@
-/*
- * QEMU MIPS Jazz support
- *
- * Copyright (c) 2007-2008 Hervé Poussineau
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/mips/mips.h"
-#include "hw/mips/cpudevs.h"
-#include "hw/i386/pc.h"
-#include "hw/char/serial.h"
-#include "hw/isa/isa.h"
-#include "hw/block/fdc.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/arch_init.h"
-#include "hw/boards.h"
-#include "net/net.h"
-#include "hw/scsi/esp.h"
-#include "hw/mips/bios.h"
-#include "hw/loader.h"
-#include "hw/timer/mc146818rtc.h"
-#include "hw/timer/i8254.h"
-#include "hw/audio/pcspk.h"
-#include "sysemu/block-backend.h"
-#include "hw/sysbus.h"
-#include "exec/address-spaces.h"
-#include "sysemu/qtest.h"
-#include "qemu/error-report.h"
-#include "qemu/help_option.h"
-
-enum jazz_model_e
-{
- JAZZ_MAGNUM,
- JAZZ_PICA61,
-};
-
-static void main_cpu_reset(void *opaque)
-{
- MIPSCPU *cpu = opaque;
-
- cpu_reset(CPU(cpu));
-}
-
-static uint64_t rtc_read(void *opaque, hwaddr addr, unsigned size)
-{
- uint8_t val;
- address_space_read(&address_space_memory, 0x90000071,
- MEMTXATTRS_UNSPECIFIED, &val, 1);
- return val;
-}
-
-static void rtc_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- uint8_t buf = val & 0xff;
- address_space_write(&address_space_memory, 0x90000071,
- MEMTXATTRS_UNSPECIFIED, &buf, 1);
-}
-
-static const MemoryRegionOps rtc_ops = {
- .read = rtc_read,
- .write = rtc_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static uint64_t dma_dummy_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- /* Nothing to do. That is only to ensure that
- * the current DMA acknowledge cycle is completed. */
- return 0xff;
-}
-
-static void dma_dummy_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- /* Nothing to do. That is only to ensure that
- * the current DMA acknowledge cycle is completed. */
-}
-
-static const MemoryRegionOps dma_dummy_ops = {
- .read = dma_dummy_read,
- .write = dma_dummy_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-#define MAGNUM_BIOS_SIZE_MAX 0x7e000
-#define MAGNUM_BIOS_SIZE (BIOS_SIZE < MAGNUM_BIOS_SIZE_MAX ? BIOS_SIZE : MAGNUM_BIOS_SIZE_MAX)
-
-static CPUUnassignedAccess real_do_unassigned_access;
-static void mips_jazz_do_unassigned_access(CPUState *cpu, hwaddr addr,
- bool is_write, bool is_exec,
- int opaque, unsigned size)
-{
- if (!is_exec) {
- /* ignore invalid access (ie do not raise exception) */
- return;
- }
- (*real_do_unassigned_access)(cpu, addr, is_write, is_exec, opaque, size);
-}
-
-static void mips_jazz_init(MachineState *machine,
- enum jazz_model_e jazz_model)
-{
- MemoryRegion *address_space = get_system_memory();
- const char *cpu_model = machine->cpu_model;
- char *filename;
- int bios_size, n;
- MIPSCPU *cpu;
- CPUClass *cc;
- CPUMIPSState *env;
- qemu_irq *i8259;
- rc4030_dma *dmas;
- MemoryRegion *rc4030_dma_mr;
- MemoryRegion *isa_mem = g_new(MemoryRegion, 1);
- MemoryRegion *isa_io = g_new(MemoryRegion, 1);
- MemoryRegion *rtc = g_new(MemoryRegion, 1);
- MemoryRegion *i8042 = g_new(MemoryRegion, 1);
- MemoryRegion *dma_dummy = g_new(MemoryRegion, 1);
- NICInfo *nd;
- DeviceState *dev, *rc4030;
- SysBusDevice *sysbus;
- ISABus *isa_bus;
- ISADevice *pit;
- DriveInfo *fds[MAX_FD];
- qemu_irq esp_reset, dma_enable;
- MemoryRegion *ram = g_new(MemoryRegion, 1);
- MemoryRegion *bios = g_new(MemoryRegion, 1);
- MemoryRegion *bios2 = g_new(MemoryRegion, 1);
-
- /* init CPUs */
- if (cpu_model == NULL) {
- cpu_model = "R4000";
- }
- cpu = cpu_mips_init(cpu_model);
- if (cpu == NULL) {
- fprintf(stderr, "Unable to find CPU definition\n");
- exit(1);
- }
- env = &cpu->env;
- qemu_register_reset(main_cpu_reset, cpu);
-
- /* Chipset returns 0 in invalid reads and do not raise data exceptions.
- * However, we can't simply add a global memory region to catch
- * everything, as memory core directly call unassigned_mem_read/write
- * on some invalid accesses, which call do_unassigned_access on the
- * CPU, which raise an exception.
- * Handle that case by hijacking the do_unassigned_access method on
- * the CPU, and do not raise exceptions for data access. */
- cc = CPU_GET_CLASS(cpu);
- real_do_unassigned_access = cc->do_unassigned_access;
- cc->do_unassigned_access = mips_jazz_do_unassigned_access;
-
- /* allocate RAM */
- memory_region_allocate_system_memory(ram, NULL, "mips_jazz.ram",
- machine->ram_size);
- memory_region_add_subregion(address_space, 0, ram);
-
- memory_region_init_ram(bios, NULL, "mips_jazz.bios", MAGNUM_BIOS_SIZE,
- &error_fatal);
- vmstate_register_ram_global(bios);
- memory_region_set_readonly(bios, true);
- memory_region_init_alias(bios2, NULL, "mips_jazz.bios", bios,
- 0, MAGNUM_BIOS_SIZE);
- memory_region_add_subregion(address_space, 0x1fc00000LL, bios);
- memory_region_add_subregion(address_space, 0xfff00000LL, bios2);
-
- /* load the BIOS image. */
- if (bios_name == NULL)
- bios_name = BIOS_FILENAME;
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
- if (filename) {
- bios_size = load_image_targphys(filename, 0xfff00000LL,
- MAGNUM_BIOS_SIZE);
- g_free(filename);
- } else {
- bios_size = -1;
- }
- if ((bios_size < 0 || bios_size > MAGNUM_BIOS_SIZE) && !qtest_enabled()) {
- error_report("Could not load MIPS bios '%s'", bios_name);
- exit(1);
- }
-
- /* Init CPU internal devices */
- cpu_mips_irq_init_cpu(env);
- cpu_mips_clock_init(env);
-
- /* Chipset */
- rc4030 = rc4030_init(&dmas, &rc4030_dma_mr);
- sysbus = SYS_BUS_DEVICE(rc4030);
- sysbus_connect_irq(sysbus, 0, env->irq[6]);
- sysbus_connect_irq(sysbus, 1, env->irq[3]);
- memory_region_add_subregion(address_space, 0x80000000,
- sysbus_mmio_get_region(sysbus, 0));
- memory_region_add_subregion(address_space, 0xf0000000,
- sysbus_mmio_get_region(sysbus, 1));
- memory_region_init_io(dma_dummy, NULL, &dma_dummy_ops, NULL, "dummy_dma", 0x1000);
- memory_region_add_subregion(address_space, 0x8000d000, dma_dummy);
-
- /* ISA bus: IO space at 0x90000000, mem space at 0x91000000 */
- memory_region_init(isa_io, NULL, "isa-io", 0x00010000);
- memory_region_init(isa_mem, NULL, "isa-mem", 0x01000000);
- memory_region_add_subregion(address_space, 0x90000000, isa_io);
- memory_region_add_subregion(address_space, 0x91000000, isa_mem);
- isa_bus = isa_bus_new(NULL, isa_mem, isa_io, &error_abort);
-
- /* ISA devices */
- i8259 = i8259_init(isa_bus, env->irq[4]);
- isa_bus_irqs(isa_bus, i8259);
- DMA_init(isa_bus, 0);
- pit = pit_init(isa_bus, 0x40, 0, NULL);
- pcspk_init(isa_bus, pit);
-
- /* Video card */
- switch (jazz_model) {
- case JAZZ_MAGNUM:
- dev = qdev_create(NULL, "sysbus-g364");
- qdev_init_nofail(dev);
- sysbus = SYS_BUS_DEVICE(dev);
- sysbus_mmio_map(sysbus, 0, 0x60080000);
- sysbus_mmio_map(sysbus, 1, 0x40000000);
- sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(rc4030, 3));
- {
- /* Simple ROM, so user doesn't have to provide one */
- MemoryRegion *rom_mr = g_new(MemoryRegion, 1);
- memory_region_init_ram(rom_mr, NULL, "g364fb.rom", 0x80000,
- &error_fatal);
- vmstate_register_ram_global(rom_mr);
- memory_region_set_readonly(rom_mr, true);
- uint8_t *rom = memory_region_get_ram_ptr(rom_mr);
- memory_region_add_subregion(address_space, 0x60000000, rom_mr);
- rom[0] = 0x10; /* Mips G364 */
- }
- break;
- case JAZZ_PICA61:
- isa_vga_mm_init(0x40000000, 0x60000000, 0, get_system_memory());
- break;
- default:
- break;
- }
-
- /* Network controller */
- for (n = 0; n < nb_nics; n++) {
- nd = &nd_table[n];
- if (!nd->model)
- nd->model = g_strdup("dp83932");
- if (strcmp(nd->model, "dp83932") == 0) {
- qemu_check_nic_model(nd, "dp83932");
-
- dev = qdev_create(NULL, "dp8393x");
- qdev_set_nic_properties(dev, nd);
- qdev_prop_set_uint8(dev, "it_shift", 2);
- qdev_prop_set_ptr(dev, "dma_mr", rc4030_dma_mr);
- qdev_init_nofail(dev);
- sysbus = SYS_BUS_DEVICE(dev);
- sysbus_mmio_map(sysbus, 0, 0x80001000);
- sysbus_mmio_map(sysbus, 1, 0x8000b000);
- sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(rc4030, 4));
- break;
- } else if (is_help_option(nd->model)) {
- fprintf(stderr, "qemu: Supported NICs: dp83932\n");
- exit(1);
- } else {
- fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model);
- exit(1);
- }
- }
-
- /* SCSI adapter */
- esp_init(0x80002000, 0,
- rc4030_dma_read, rc4030_dma_write, dmas[0],
- qdev_get_gpio_in(rc4030, 5), &esp_reset, &dma_enable);
-
- /* Floppy */
- if (drive_get_max_bus(IF_FLOPPY) >= MAX_FD) {
- fprintf(stderr, "qemu: too many floppy drives\n");
- exit(1);
- }
- for (n = 0; n < MAX_FD; n++) {
- fds[n] = drive_get(IF_FLOPPY, 0, n);
- }
- /* FIXME: we should enable DMA with a custom IsaDma device */
- fdctrl_init_sysbus(qdev_get_gpio_in(rc4030, 1), -1, 0x80003000, fds);
-
- /* Real time clock */
- rtc_init(isa_bus, 1980, NULL);
- memory_region_init_io(rtc, NULL, &rtc_ops, NULL, "rtc", 0x1000);
- memory_region_add_subregion(address_space, 0x80004000, rtc);
-
- /* Keyboard (i8042) */
- i8042_mm_init(qdev_get_gpio_in(rc4030, 6), qdev_get_gpio_in(rc4030, 7),
- i8042, 0x1000, 0x1);
- memory_region_add_subregion(address_space, 0x80005000, i8042);
-
- /* Serial ports */
- if (serial_hds[0]) {
- serial_mm_init(address_space, 0x80006000, 0,
- qdev_get_gpio_in(rc4030, 8), 8000000/16,
- serial_hds[0], DEVICE_NATIVE_ENDIAN);
- }
- if (serial_hds[1]) {
- serial_mm_init(address_space, 0x80007000, 0,
- qdev_get_gpio_in(rc4030, 9), 8000000/16,
- serial_hds[1], DEVICE_NATIVE_ENDIAN);
- }
-
- /* Parallel port */
- if (parallel_hds[0])
- parallel_mm_init(address_space, 0x80008000, 0,
- qdev_get_gpio_in(rc4030, 0), parallel_hds[0]);
-
- /* FIXME: missing Jazz sound at 0x8000c000, rc4030[2] */
-
- /* NVRAM */
- dev = qdev_create(NULL, "ds1225y");
- qdev_init_nofail(dev);
- sysbus = SYS_BUS_DEVICE(dev);
- sysbus_mmio_map(sysbus, 0, 0x80009000);
-
- /* LED indicator */
- sysbus_create_simple("jazz-led", 0x8000f000, NULL);
-}
-
-static
-void mips_magnum_init(MachineState *machine)
-{
- mips_jazz_init(machine, JAZZ_MAGNUM);
-}
-
-static
-void mips_pica61_init(MachineState *machine)
-{
- mips_jazz_init(machine, JAZZ_PICA61);
-}
-
-static void mips_magnum_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "MIPS Magnum";
- mc->init = mips_magnum_init;
- mc->block_default_type = IF_SCSI;
-}
-
-static const TypeInfo mips_magnum_type = {
- .name = MACHINE_TYPE_NAME("magnum"),
- .parent = TYPE_MACHINE,
- .class_init = mips_magnum_class_init,
-};
-
-static void mips_pica61_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "Acer Pica 61";
- mc->init = mips_pica61_init;
- mc->block_default_type = IF_SCSI;
-}
-
-static const TypeInfo mips_pica61_type = {
- .name = MACHINE_TYPE_NAME("pica61"),
- .parent = TYPE_MACHINE,
- .class_init = mips_pica61_class_init,
-};
-
-static void mips_jazz_machine_init(void)
-{
- type_register_static(&mips_magnum_type);
- type_register_static(&mips_pica61_type);
-}
-
-type_init(mips_jazz_machine_init)
diff --git a/qemu/hw/mips/mips_malta.c b/qemu/hw/mips/mips_malta.c
deleted file mode 100644
index fa769e5c0..000000000
--- a/qemu/hw/mips/mips_malta.c
+++ /dev/null
@@ -1,1270 +0,0 @@
-/*
- * QEMU Malta board support
- *
- * Copyright (c) 2006 Aurelien Jarno
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/hw.h"
-#include "hw/i386/pc.h"
-#include "hw/char/serial.h"
-#include "hw/block/fdc.h"
-#include "net/net.h"
-#include "hw/boards.h"
-#include "hw/i2c/smbus.h"
-#include "sysemu/block-backend.h"
-#include "hw/block/flash.h"
-#include "hw/mips/mips.h"
-#include "hw/mips/cpudevs.h"
-#include "hw/pci/pci.h"
-#include "sysemu/char.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/arch_init.h"
-#include "qemu/log.h"
-#include "hw/mips/bios.h"
-#include "hw/ide.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "hw/timer/mc146818rtc.h"
-#include "hw/timer/i8254.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
-#include "exec/address-spaces.h"
-#include "hw/sysbus.h" /* SysBusDevice */
-#include "qemu/host-utils.h"
-#include "sysemu/qtest.h"
-#include "qemu/error-report.h"
-#include "hw/empty_slot.h"
-#include "sysemu/kvm.h"
-#include "exec/semihost.h"
-#include "hw/mips/cps.h"
-
-//#define DEBUG_BOARD_INIT
-
-#define ENVP_ADDR 0x80002000l
-#define ENVP_NB_ENTRIES 16
-#define ENVP_ENTRY_SIZE 256
-
-/* Hardware addresses */
-#define FLASH_ADDRESS 0x1e000000ULL
-#define FPGA_ADDRESS 0x1f000000ULL
-#define RESET_ADDRESS 0x1fc00000ULL
-
-#define FLASH_SIZE 0x400000
-
-#define MAX_IDE_BUS 2
-
-typedef struct {
- MemoryRegion iomem;
- MemoryRegion iomem_lo; /* 0 - 0x900 */
- MemoryRegion iomem_hi; /* 0xa00 - 0x100000 */
- uint32_t leds;
- uint32_t brk;
- uint32_t gpout;
- uint32_t i2cin;
- uint32_t i2coe;
- uint32_t i2cout;
- uint32_t i2csel;
- CharDriverState *display;
- char display_text[9];
- SerialState *uart;
-} MaltaFPGAState;
-
-#define TYPE_MIPS_MALTA "mips-malta"
-#define MIPS_MALTA(obj) OBJECT_CHECK(MaltaState, (obj), TYPE_MIPS_MALTA)
-
-typedef struct {
- SysBusDevice parent_obj;
-
- MIPSCPSState *cps;
- qemu_irq *i8259;
-} MaltaState;
-
-static ISADevice *pit;
-
-static struct _loaderparams {
- int ram_size, ram_low_size;
- const char *kernel_filename;
- const char *kernel_cmdline;
- const char *initrd_filename;
-} loaderparams;
-
-/* Malta FPGA */
-static void malta_fpga_update_display(void *opaque)
-{
- char leds_text[9];
- int i;
- MaltaFPGAState *s = opaque;
-
- for (i = 7 ; i >= 0 ; i--) {
- if (s->leds & (1 << i))
- leds_text[i] = '#';
- else
- leds_text[i] = ' ';
- }
- leds_text[8] = '\0';
-
- qemu_chr_fe_printf(s->display, "\e[H\n\n|\e[32m%-8.8s\e[00m|\r\n", leds_text);
- qemu_chr_fe_printf(s->display, "\n\n\n\n|\e[31m%-8.8s\e[00m|", s->display_text);
-}
-
-/*
- * EEPROM 24C01 / 24C02 emulation.
- *
- * Emulation for serial EEPROMs:
- * 24C01 - 1024 bit (128 x 8)
- * 24C02 - 2048 bit (256 x 8)
- *
- * Typical device names include Microchip 24C02SC or SGS Thomson ST24C02.
- */
-
-//~ #define DEBUG
-
-#if defined(DEBUG)
-# define logout(fmt, ...) fprintf(stderr, "MALTA\t%-24s" fmt, __func__, ## __VA_ARGS__)
-#else
-# define logout(fmt, ...) ((void)0)
-#endif
-
-struct _eeprom24c0x_t {
- uint8_t tick;
- uint8_t address;
- uint8_t command;
- uint8_t ack;
- uint8_t scl;
- uint8_t sda;
- uint8_t data;
- //~ uint16_t size;
- uint8_t contents[256];
-};
-
-typedef struct _eeprom24c0x_t eeprom24c0x_t;
-
-static eeprom24c0x_t spd_eeprom = {
- .contents = {
- /* 00000000: */ 0x80,0x08,0xFF,0x0D,0x0A,0xFF,0x40,0x00,
- /* 00000008: */ 0x01,0x75,0x54,0x00,0x82,0x08,0x00,0x01,
- /* 00000010: */ 0x8F,0x04,0x02,0x01,0x01,0x00,0x00,0x00,
- /* 00000018: */ 0x00,0x00,0x00,0x14,0x0F,0x14,0x2D,0xFF,
- /* 00000020: */ 0x15,0x08,0x15,0x08,0x00,0x00,0x00,0x00,
- /* 00000028: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- /* 00000030: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- /* 00000038: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x12,0xD0,
- /* 00000040: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- /* 00000048: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- /* 00000050: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- /* 00000058: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- /* 00000060: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- /* 00000068: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- /* 00000070: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- /* 00000078: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x64,0xF4,
- },
-};
-
-static void generate_eeprom_spd(uint8_t *eeprom, ram_addr_t ram_size)
-{
- enum { SDR = 0x4, DDR2 = 0x8 } type;
- uint8_t *spd = spd_eeprom.contents;
- uint8_t nbanks = 0;
- uint16_t density = 0;
- int i;
-
- /* work in terms of MB */
- ram_size >>= 20;
-
- while ((ram_size >= 4) && (nbanks <= 2)) {
- int sz_log2 = MIN(31 - clz32(ram_size), 14);
- nbanks++;
- density |= 1 << (sz_log2 - 2);
- ram_size -= 1 << sz_log2;
- }
-
- /* split to 2 banks if possible */
- if ((nbanks == 1) && (density > 1)) {
- nbanks++;
- density >>= 1;
- }
-
- if (density & 0xff00) {
- density = (density & 0xe0) | ((density >> 8) & 0x1f);
- type = DDR2;
- } else if (!(density & 0x1f)) {
- type = DDR2;
- } else {
- type = SDR;
- }
-
- if (ram_size) {
- fprintf(stderr, "Warning: SPD cannot represent final %dMB"
- " of SDRAM\n", (int)ram_size);
- }
-
- /* fill in SPD memory information */
- spd[2] = type;
- spd[5] = nbanks;
- spd[31] = density;
-
- /* checksum */
- spd[63] = 0;
- for (i = 0; i < 63; i++) {
- spd[63] += spd[i];
- }
-
- /* copy for SMBUS */
- memcpy(eeprom, spd, sizeof(spd_eeprom.contents));
-}
-
-static void generate_eeprom_serial(uint8_t *eeprom)
-{
- int i, pos = 0;
- uint8_t mac[6] = { 0x00 };
- uint8_t sn[5] = { 0x01, 0x23, 0x45, 0x67, 0x89 };
-
- /* version */
- eeprom[pos++] = 0x01;
-
- /* count */
- eeprom[pos++] = 0x02;
-
- /* MAC address */
- eeprom[pos++] = 0x01; /* MAC */
- eeprom[pos++] = 0x06; /* length */
- memcpy(&eeprom[pos], mac, sizeof(mac));
- pos += sizeof(mac);
-
- /* serial number */
- eeprom[pos++] = 0x02; /* serial */
- eeprom[pos++] = 0x05; /* length */
- memcpy(&eeprom[pos], sn, sizeof(sn));
- pos += sizeof(sn);
-
- /* checksum */
- eeprom[pos] = 0;
- for (i = 0; i < pos; i++) {
- eeprom[pos] += eeprom[i];
- }
-}
-
-static uint8_t eeprom24c0x_read(eeprom24c0x_t *eeprom)
-{
- logout("%u: scl = %u, sda = %u, data = 0x%02x\n",
- eeprom->tick, eeprom->scl, eeprom->sda, eeprom->data);
- return eeprom->sda;
-}
-
-static void eeprom24c0x_write(eeprom24c0x_t *eeprom, int scl, int sda)
-{
- if (eeprom->scl && scl && (eeprom->sda != sda)) {
- logout("%u: scl = %u->%u, sda = %u->%u i2c %s\n",
- eeprom->tick, eeprom->scl, scl, eeprom->sda, sda,
- sda ? "stop" : "start");
- if (!sda) {
- eeprom->tick = 1;
- eeprom->command = 0;
- }
- } else if (eeprom->tick == 0 && !eeprom->ack) {
- /* Waiting for start. */
- logout("%u: scl = %u->%u, sda = %u->%u wait for i2c start\n",
- eeprom->tick, eeprom->scl, scl, eeprom->sda, sda);
- } else if (!eeprom->scl && scl) {
- logout("%u: scl = %u->%u, sda = %u->%u trigger bit\n",
- eeprom->tick, eeprom->scl, scl, eeprom->sda, sda);
- if (eeprom->ack) {
- logout("\ti2c ack bit = 0\n");
- sda = 0;
- eeprom->ack = 0;
- } else if (eeprom->sda == sda) {
- uint8_t bit = (sda != 0);
- logout("\ti2c bit = %d\n", bit);
- if (eeprom->tick < 9) {
- eeprom->command <<= 1;
- eeprom->command += bit;
- eeprom->tick++;
- if (eeprom->tick == 9) {
- logout("\tcommand 0x%04x, %s\n", eeprom->command,
- bit ? "read" : "write");
- eeprom->ack = 1;
- }
- } else if (eeprom->tick < 17) {
- if (eeprom->command & 1) {
- sda = ((eeprom->data & 0x80) != 0);
- }
- eeprom->address <<= 1;
- eeprom->address += bit;
- eeprom->tick++;
- eeprom->data <<= 1;
- if (eeprom->tick == 17) {
- eeprom->data = eeprom->contents[eeprom->address];
- logout("\taddress 0x%04x, data 0x%02x\n",
- eeprom->address, eeprom->data);
- eeprom->ack = 1;
- eeprom->tick = 0;
- }
- } else if (eeprom->tick >= 17) {
- sda = 0;
- }
- } else {
- logout("\tsda changed with raising scl\n");
- }
- } else {
- logout("%u: scl = %u->%u, sda = %u->%u\n", eeprom->tick, eeprom->scl,
- scl, eeprom->sda, sda);
- }
- eeprom->scl = scl;
- eeprom->sda = sda;
-}
-
-static uint64_t malta_fpga_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- MaltaFPGAState *s = opaque;
- uint32_t val = 0;
- uint32_t saddr;
-
- saddr = (addr & 0xfffff);
-
- switch (saddr) {
-
- /* SWITCH Register */
- case 0x00200:
- val = 0x00000000; /* All switches closed */
- break;
-
- /* STATUS Register */
- case 0x00208:
-#ifdef TARGET_WORDS_BIGENDIAN
- val = 0x00000012;
-#else
- val = 0x00000010;
-#endif
- break;
-
- /* JMPRS Register */
- case 0x00210:
- val = 0x00;
- break;
-
- /* LEDBAR Register */
- case 0x00408:
- val = s->leds;
- break;
-
- /* BRKRES Register */
- case 0x00508:
- val = s->brk;
- break;
-
- /* UART Registers are handled directly by the serial device */
-
- /* GPOUT Register */
- case 0x00a00:
- val = s->gpout;
- break;
-
- /* XXX: implement a real I2C controller */
-
- /* GPINP Register */
- case 0x00a08:
- /* IN = OUT until a real I2C control is implemented */
- if (s->i2csel)
- val = s->i2cout;
- else
- val = 0x00;
- break;
-
- /* I2CINP Register */
- case 0x00b00:
- val = ((s->i2cin & ~1) | eeprom24c0x_read(&spd_eeprom));
- break;
-
- /* I2COE Register */
- case 0x00b08:
- val = s->i2coe;
- break;
-
- /* I2COUT Register */
- case 0x00b10:
- val = s->i2cout;
- break;
-
- /* I2CSEL Register */
- case 0x00b18:
- val = s->i2csel;
- break;
-
- default:
-#if 0
- printf ("malta_fpga_read: Bad register offset 0x" TARGET_FMT_lx "\n",
- addr);
-#endif
- break;
- }
- return val;
-}
-
-static void malta_fpga_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- MaltaFPGAState *s = opaque;
- uint32_t saddr;
-
- saddr = (addr & 0xfffff);
-
- switch (saddr) {
-
- /* SWITCH Register */
- case 0x00200:
- break;
-
- /* JMPRS Register */
- case 0x00210:
- break;
-
- /* LEDBAR Register */
- case 0x00408:
- s->leds = val & 0xff;
- malta_fpga_update_display(s);
- break;
-
- /* ASCIIWORD Register */
- case 0x00410:
- snprintf(s->display_text, 9, "%08X", (uint32_t)val);
- malta_fpga_update_display(s);
- break;
-
- /* ASCIIPOS0 to ASCIIPOS7 Registers */
- case 0x00418:
- case 0x00420:
- case 0x00428:
- case 0x00430:
- case 0x00438:
- case 0x00440:
- case 0x00448:
- case 0x00450:
- s->display_text[(saddr - 0x00418) >> 3] = (char) val;
- malta_fpga_update_display(s);
- break;
-
- /* SOFTRES Register */
- case 0x00500:
- if (val == 0x42)
- qemu_system_reset_request ();
- break;
-
- /* BRKRES Register */
- case 0x00508:
- s->brk = val & 0xff;
- break;
-
- /* UART Registers are handled directly by the serial device */
-
- /* GPOUT Register */
- case 0x00a00:
- s->gpout = val & 0xff;
- break;
-
- /* I2COE Register */
- case 0x00b08:
- s->i2coe = val & 0x03;
- break;
-
- /* I2COUT Register */
- case 0x00b10:
- eeprom24c0x_write(&spd_eeprom, val & 0x02, val & 0x01);
- s->i2cout = val;
- break;
-
- /* I2CSEL Register */
- case 0x00b18:
- s->i2csel = val & 0x01;
- break;
-
- default:
-#if 0
- printf ("malta_fpga_write: Bad register offset 0x" TARGET_FMT_lx "\n",
- addr);
-#endif
- break;
- }
-}
-
-static const MemoryRegionOps malta_fpga_ops = {
- .read = malta_fpga_read,
- .write = malta_fpga_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void malta_fpga_reset(void *opaque)
-{
- MaltaFPGAState *s = opaque;
-
- s->leds = 0x00;
- s->brk = 0x0a;
- s->gpout = 0x00;
- s->i2cin = 0x3;
- s->i2coe = 0x0;
- s->i2cout = 0x3;
- s->i2csel = 0x1;
-
- s->display_text[8] = '\0';
- snprintf(s->display_text, 9, " ");
-}
-
-static void malta_fpga_led_init(CharDriverState *chr)
-{
- qemu_chr_fe_printf(chr, "\e[HMalta LEDBAR\r\n");
- qemu_chr_fe_printf(chr, "+--------+\r\n");
- qemu_chr_fe_printf(chr, "+ +\r\n");
- qemu_chr_fe_printf(chr, "+--------+\r\n");
- qemu_chr_fe_printf(chr, "\n");
- qemu_chr_fe_printf(chr, "Malta ASCII\r\n");
- qemu_chr_fe_printf(chr, "+--------+\r\n");
- qemu_chr_fe_printf(chr, "+ +\r\n");
- qemu_chr_fe_printf(chr, "+--------+\r\n");
-}
-
-static MaltaFPGAState *malta_fpga_init(MemoryRegion *address_space,
- hwaddr base, qemu_irq uart_irq, CharDriverState *uart_chr)
-{
- MaltaFPGAState *s;
-
- s = (MaltaFPGAState *)g_malloc0(sizeof(MaltaFPGAState));
-
- memory_region_init_io(&s->iomem, NULL, &malta_fpga_ops, s,
- "malta-fpga", 0x100000);
- memory_region_init_alias(&s->iomem_lo, NULL, "malta-fpga",
- &s->iomem, 0, 0x900);
- memory_region_init_alias(&s->iomem_hi, NULL, "malta-fpga",
- &s->iomem, 0xa00, 0x10000-0xa00);
-
- memory_region_add_subregion(address_space, base, &s->iomem_lo);
- memory_region_add_subregion(address_space, base + 0xa00, &s->iomem_hi);
-
- s->display = qemu_chr_new("fpga", "vc:320x200", malta_fpga_led_init);
-
- s->uart = serial_mm_init(address_space, base + 0x900, 3, uart_irq,
- 230400, uart_chr, DEVICE_NATIVE_ENDIAN);
-
- malta_fpga_reset(s);
- qemu_register_reset(malta_fpga_reset, s);
-
- return s;
-}
-
-/* Network support */
-static void network_init(PCIBus *pci_bus)
-{
- int i;
-
- for(i = 0; i < nb_nics; i++) {
- NICInfo *nd = &nd_table[i];
- const char *default_devaddr = NULL;
-
- if (i == 0 && (!nd->model || strcmp(nd->model, "pcnet") == 0))
- /* The malta board has a PCNet card using PCI SLOT 11 */
- default_devaddr = "0b";
-
- pci_nic_init_nofail(nd, pci_bus, "pcnet", default_devaddr);
- }
-}
-
-/* ROM and pseudo bootloader
-
- The following code implements a very very simple bootloader. It first
- loads the registers a0 to a3 to the values expected by the OS, and
- then jump at the kernel address.
-
- The bootloader should pass the locations of the kernel arguments and
- environment variables tables. Those tables contain the 32-bit address
- of NULL terminated strings. The environment variables table should be
- terminated by a NULL address.
-
- For a simpler implementation, the number of kernel arguments is fixed
- to two (the name of the kernel and the command line), and the two
- tables are actually the same one.
-
- The registers a0 to a3 should contain the following values:
- a0 - number of kernel arguments
- a1 - 32-bit address of the kernel arguments table
- a2 - 32-bit address of the environment variables table
- a3 - RAM size in bytes
-*/
-
-static void write_bootloader(uint8_t *base, int64_t run_addr,
- int64_t kernel_entry)
-{
- uint32_t *p;
-
- /* Small bootloader */
- p = (uint32_t *)base;
-
- stl_p(p++, 0x08000000 | /* j 0x1fc00580 */
- ((run_addr + 0x580) & 0x0fffffff) >> 2);
- stl_p(p++, 0x00000000); /* nop */
-
- /* YAMON service vector */
- stl_p(base + 0x500, run_addr + 0x0580); /* start: */
- stl_p(base + 0x504, run_addr + 0x083c); /* print_count: */
- stl_p(base + 0x520, run_addr + 0x0580); /* start: */
- stl_p(base + 0x52c, run_addr + 0x0800); /* flush_cache: */
- stl_p(base + 0x534, run_addr + 0x0808); /* print: */
- stl_p(base + 0x538, run_addr + 0x0800); /* reg_cpu_isr: */
- stl_p(base + 0x53c, run_addr + 0x0800); /* unred_cpu_isr: */
- stl_p(base + 0x540, run_addr + 0x0800); /* reg_ic_isr: */
- stl_p(base + 0x544, run_addr + 0x0800); /* unred_ic_isr: */
- stl_p(base + 0x548, run_addr + 0x0800); /* reg_esr: */
- stl_p(base + 0x54c, run_addr + 0x0800); /* unreg_esr: */
- stl_p(base + 0x550, run_addr + 0x0800); /* getchar: */
- stl_p(base + 0x554, run_addr + 0x0800); /* syscon_read: */
-
-
- /* Second part of the bootloader */
- p = (uint32_t *) (base + 0x580);
-
- if (semihosting_get_argc()) {
- /* Preserve a0 content as arguments have been passed */
- stl_p(p++, 0x00000000); /* nop */
- } else {
- stl_p(p++, 0x24040002); /* addiu a0, zero, 2 */
- }
- stl_p(p++, 0x3c1d0000 | (((ENVP_ADDR - 64) >> 16) & 0xffff)); /* lui sp, high(ENVP_ADDR) */
- stl_p(p++, 0x37bd0000 | ((ENVP_ADDR - 64) & 0xffff)); /* ori sp, sp, low(ENVP_ADDR) */
- stl_p(p++, 0x3c050000 | ((ENVP_ADDR >> 16) & 0xffff)); /* lui a1, high(ENVP_ADDR) */
- stl_p(p++, 0x34a50000 | (ENVP_ADDR & 0xffff)); /* ori a1, a1, low(ENVP_ADDR) */
- stl_p(p++, 0x3c060000 | (((ENVP_ADDR + 8) >> 16) & 0xffff)); /* lui a2, high(ENVP_ADDR + 8) */
- stl_p(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff)); /* ori a2, a2, low(ENVP_ADDR + 8) */
- stl_p(p++, 0x3c070000 | (loaderparams.ram_low_size >> 16)); /* lui a3, high(ram_low_size) */
- stl_p(p++, 0x34e70000 | (loaderparams.ram_low_size & 0xffff)); /* ori a3, a3, low(ram_low_size) */
-
- /* Load BAR registers as done by YAMON */
- stl_p(p++, 0x3c09b400); /* lui t1, 0xb400 */
-
-#ifdef TARGET_WORDS_BIGENDIAN
- stl_p(p++, 0x3c08df00); /* lui t0, 0xdf00 */
-#else
- stl_p(p++, 0x340800df); /* ori t0, r0, 0x00df */
-#endif
- stl_p(p++, 0xad280068); /* sw t0, 0x0068(t1) */
-
- stl_p(p++, 0x3c09bbe0); /* lui t1, 0xbbe0 */
-
-#ifdef TARGET_WORDS_BIGENDIAN
- stl_p(p++, 0x3c08c000); /* lui t0, 0xc000 */
-#else
- stl_p(p++, 0x340800c0); /* ori t0, r0, 0x00c0 */
-#endif
- stl_p(p++, 0xad280048); /* sw t0, 0x0048(t1) */
-#ifdef TARGET_WORDS_BIGENDIAN
- stl_p(p++, 0x3c084000); /* lui t0, 0x4000 */
-#else
- stl_p(p++, 0x34080040); /* ori t0, r0, 0x0040 */
-#endif
- stl_p(p++, 0xad280050); /* sw t0, 0x0050(t1) */
-
-#ifdef TARGET_WORDS_BIGENDIAN
- stl_p(p++, 0x3c088000); /* lui t0, 0x8000 */
-#else
- stl_p(p++, 0x34080080); /* ori t0, r0, 0x0080 */
-#endif
- stl_p(p++, 0xad280058); /* sw t0, 0x0058(t1) */
-#ifdef TARGET_WORDS_BIGENDIAN
- stl_p(p++, 0x3c083f00); /* lui t0, 0x3f00 */
-#else
- stl_p(p++, 0x3408003f); /* ori t0, r0, 0x003f */
-#endif
- stl_p(p++, 0xad280060); /* sw t0, 0x0060(t1) */
-
-#ifdef TARGET_WORDS_BIGENDIAN
- stl_p(p++, 0x3c08c100); /* lui t0, 0xc100 */
-#else
- stl_p(p++, 0x340800c1); /* ori t0, r0, 0x00c1 */
-#endif
- stl_p(p++, 0xad280080); /* sw t0, 0x0080(t1) */
-#ifdef TARGET_WORDS_BIGENDIAN
- stl_p(p++, 0x3c085e00); /* lui t0, 0x5e00 */
-#else
- stl_p(p++, 0x3408005e); /* ori t0, r0, 0x005e */
-#endif
- stl_p(p++, 0xad280088); /* sw t0, 0x0088(t1) */
-
- /* Jump to kernel code */
- stl_p(p++, 0x3c1f0000 | ((kernel_entry >> 16) & 0xffff)); /* lui ra, high(kernel_entry) */
- stl_p(p++, 0x37ff0000 | (kernel_entry & 0xffff)); /* ori ra, ra, low(kernel_entry) */
- stl_p(p++, 0x03e00009); /* jalr ra */
- stl_p(p++, 0x00000000); /* nop */
-
- /* YAMON subroutines */
- p = (uint32_t *) (base + 0x800);
- stl_p(p++, 0x03e00009); /* jalr ra */
- stl_p(p++, 0x24020000); /* li v0,0 */
- /* 808 YAMON print */
- stl_p(p++, 0x03e06821); /* move t5,ra */
- stl_p(p++, 0x00805821); /* move t3,a0 */
- stl_p(p++, 0x00a05021); /* move t2,a1 */
- stl_p(p++, 0x91440000); /* lbu a0,0(t2) */
- stl_p(p++, 0x254a0001); /* addiu t2,t2,1 */
- stl_p(p++, 0x10800005); /* beqz a0,834 */
- stl_p(p++, 0x00000000); /* nop */
- stl_p(p++, 0x0ff0021c); /* jal 870 */
- stl_p(p++, 0x00000000); /* nop */
- stl_p(p++, 0x08000205); /* j 814 */
- stl_p(p++, 0x00000000); /* nop */
- stl_p(p++, 0x01a00009); /* jalr t5 */
- stl_p(p++, 0x01602021); /* move a0,t3 */
- /* 0x83c YAMON print_count */
- stl_p(p++, 0x03e06821); /* move t5,ra */
- stl_p(p++, 0x00805821); /* move t3,a0 */
- stl_p(p++, 0x00a05021); /* move t2,a1 */
- stl_p(p++, 0x00c06021); /* move t4,a2 */
- stl_p(p++, 0x91440000); /* lbu a0,0(t2) */
- stl_p(p++, 0x0ff0021c); /* jal 870 */
- stl_p(p++, 0x00000000); /* nop */
- stl_p(p++, 0x254a0001); /* addiu t2,t2,1 */
- stl_p(p++, 0x258cffff); /* addiu t4,t4,-1 */
- stl_p(p++, 0x1580fffa); /* bnez t4,84c */
- stl_p(p++, 0x00000000); /* nop */
- stl_p(p++, 0x01a00009); /* jalr t5 */
- stl_p(p++, 0x01602021); /* move a0,t3 */
- /* 0x870 */
- stl_p(p++, 0x3c08b800); /* lui t0,0xb400 */
- stl_p(p++, 0x350803f8); /* ori t0,t0,0x3f8 */
- stl_p(p++, 0x91090005); /* lbu t1,5(t0) */
- stl_p(p++, 0x00000000); /* nop */
- stl_p(p++, 0x31290040); /* andi t1,t1,0x40 */
- stl_p(p++, 0x1120fffc); /* beqz t1,878 <outch+0x8> */
- stl_p(p++, 0x00000000); /* nop */
- stl_p(p++, 0x03e00009); /* jalr ra */
- stl_p(p++, 0xa1040000); /* sb a0,0(t0) */
-
-}
-
-static void GCC_FMT_ATTR(3, 4) prom_set(uint32_t* prom_buf, int index,
- const char *string, ...)
-{
- va_list ap;
- int32_t table_addr;
-
- if (index >= ENVP_NB_ENTRIES)
- return;
-
- if (string == NULL) {
- prom_buf[index] = 0;
- return;
- }
-
- table_addr = sizeof(int32_t) * ENVP_NB_ENTRIES + index * ENVP_ENTRY_SIZE;
- prom_buf[index] = tswap32(ENVP_ADDR + table_addr);
-
- va_start(ap, string);
- vsnprintf((char *)prom_buf + table_addr, ENVP_ENTRY_SIZE, string, ap);
- va_end(ap);
-}
-
-/* Kernel */
-static int64_t load_kernel (void)
-{
- int64_t kernel_entry, kernel_high;
- long initrd_size;
- ram_addr_t initrd_offset;
- int big_endian;
- uint32_t *prom_buf;
- long prom_size;
- int prom_index = 0;
- uint64_t (*xlate_to_kseg0) (void *opaque, uint64_t addr);
-
-#ifdef TARGET_WORDS_BIGENDIAN
- big_endian = 1;
-#else
- big_endian = 0;
-#endif
-
- if (load_elf(loaderparams.kernel_filename, cpu_mips_kseg0_to_phys, NULL,
- (uint64_t *)&kernel_entry, NULL, (uint64_t *)&kernel_high,
- big_endian, EM_MIPS, 1, 0) < 0) {
- fprintf(stderr, "qemu: could not load kernel '%s'\n",
- loaderparams.kernel_filename);
- exit(1);
- }
-
- /* Sanity check where the kernel has been linked */
- if (kvm_enabled()) {
- if (kernel_entry & 0x80000000ll) {
- error_report("KVM guest kernels must be linked in useg. "
- "Did you forget to enable CONFIG_KVM_GUEST?");
- exit(1);
- }
-
- xlate_to_kseg0 = cpu_mips_kvm_um_phys_to_kseg0;
- } else {
- if (!(kernel_entry & 0x80000000ll)) {
- error_report("KVM guest kernels aren't supported with TCG. "
- "Did you unintentionally enable CONFIG_KVM_GUEST?");
- exit(1);
- }
-
- xlate_to_kseg0 = cpu_mips_phys_to_kseg0;
- }
-
- /* load initrd */
- initrd_size = 0;
- initrd_offset = 0;
- if (loaderparams.initrd_filename) {
- initrd_size = get_image_size (loaderparams.initrd_filename);
- if (initrd_size > 0) {
- initrd_offset = (kernel_high + ~INITRD_PAGE_MASK) & INITRD_PAGE_MASK;
- if (initrd_offset + initrd_size > ram_size) {
- fprintf(stderr,
- "qemu: memory too small for initial ram disk '%s'\n",
- loaderparams.initrd_filename);
- exit(1);
- }
- initrd_size = load_image_targphys(loaderparams.initrd_filename,
- initrd_offset,
- ram_size - initrd_offset);
- }
- if (initrd_size == (target_ulong) -1) {
- fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
- loaderparams.initrd_filename);
- exit(1);
- }
- }
-
- /* Setup prom parameters. */
- prom_size = ENVP_NB_ENTRIES * (sizeof(int32_t) + ENVP_ENTRY_SIZE);
- prom_buf = g_malloc(prom_size);
-
- prom_set(prom_buf, prom_index++, "%s", loaderparams.kernel_filename);
- if (initrd_size > 0) {
- prom_set(prom_buf, prom_index++, "rd_start=0x%" PRIx64 " rd_size=%li %s",
- xlate_to_kseg0(NULL, initrd_offset), initrd_size,
- loaderparams.kernel_cmdline);
- } else {
- prom_set(prom_buf, prom_index++, "%s", loaderparams.kernel_cmdline);
- }
-
- prom_set(prom_buf, prom_index++, "memsize");
- prom_set(prom_buf, prom_index++, "%u", loaderparams.ram_low_size);
-
- prom_set(prom_buf, prom_index++, "ememsize");
- prom_set(prom_buf, prom_index++, "%u", loaderparams.ram_size);
-
- prom_set(prom_buf, prom_index++, "modetty0");
- prom_set(prom_buf, prom_index++, "38400n8r");
- prom_set(prom_buf, prom_index++, NULL);
-
- rom_add_blob_fixed("prom", prom_buf, prom_size,
- cpu_mips_kseg0_to_phys(NULL, ENVP_ADDR));
-
- g_free(prom_buf);
- return kernel_entry;
-}
-
-static void malta_mips_config(MIPSCPU *cpu)
-{
- CPUMIPSState *env = &cpu->env;
- CPUState *cs = CPU(cpu);
-
- env->mvp->CP0_MVPConf0 |= ((smp_cpus - 1) << CP0MVPC0_PVPE) |
- ((smp_cpus * cs->nr_threads - 1) << CP0MVPC0_PTC);
-}
-
-static void main_cpu_reset(void *opaque)
-{
- MIPSCPU *cpu = opaque;
- CPUMIPSState *env = &cpu->env;
-
- cpu_reset(CPU(cpu));
-
- /* The bootloader does not need to be rewritten as it is located in a
- read only location. The kernel location and the arguments table
- location does not change. */
- if (loaderparams.kernel_filename) {
- env->CP0_Status &= ~(1 << CP0St_ERL);
- }
-
- malta_mips_config(cpu);
-
- if (kvm_enabled()) {
- /* Start running from the bootloader we wrote to end of RAM */
- env->active_tc.PC = 0x40000000 + loaderparams.ram_low_size;
- }
-}
-
-static void create_cpu_without_cps(const char *cpu_model,
- qemu_irq *cbus_irq, qemu_irq *i8259_irq)
-{
- CPUMIPSState *env;
- MIPSCPU *cpu;
- int i;
-
- for (i = 0; i < smp_cpus; i++) {
- cpu = cpu_mips_init(cpu_model);
- if (cpu == NULL) {
- fprintf(stderr, "Unable to find CPU definition\n");
- exit(1);
- }
- env = &cpu->env;
-
- /* Init internal devices */
- cpu_mips_irq_init_cpu(env);
- cpu_mips_clock_init(env);
- qemu_register_reset(main_cpu_reset, cpu);
- }
-
- cpu = MIPS_CPU(first_cpu);
- env = &cpu->env;
- *i8259_irq = env->irq[2];
- *cbus_irq = env->irq[4];
-}
-
-static void create_cps(MaltaState *s, const char *cpu_model,
- qemu_irq *cbus_irq, qemu_irq *i8259_irq)
-{
- Error *err = NULL;
- s->cps = g_new0(MIPSCPSState, 1);
-
- object_initialize(s->cps, sizeof(MIPSCPSState), TYPE_MIPS_CPS);
- qdev_set_parent_bus(DEVICE(s->cps), sysbus_get_default());
-
- object_property_set_str(OBJECT(s->cps), cpu_model, "cpu-model", &err);
- object_property_set_int(OBJECT(s->cps), smp_cpus, "num-vp", &err);
- object_property_set_bool(OBJECT(s->cps), true, "realized", &err);
- if (err != NULL) {
- error_report("%s", error_get_pretty(err));
- exit(1);
- }
-
- sysbus_mmio_map_overlap(SYS_BUS_DEVICE(s->cps), 0, 0, 1);
-
- /* FIXME: When GIC is present then we should use GIC's IRQ 3.
- Until then CPS exposes CPU's IRQs thus use the default IRQ 2. */
- *i8259_irq = get_cps_irq(s->cps, 2);
- *cbus_irq = NULL;
-}
-
-static void create_cpu(MaltaState *s, const char *cpu_model,
- qemu_irq *cbus_irq, qemu_irq *i8259_irq)
-{
- if (cpu_model == NULL) {
-#ifdef TARGET_MIPS64
- cpu_model = "20Kc";
-#else
- cpu_model = "24Kf";
-#endif
- }
-
- if ((smp_cpus > 1) && cpu_supports_cps_smp(cpu_model)) {
- create_cps(s, cpu_model, cbus_irq, i8259_irq);
- } else {
- create_cpu_without_cps(cpu_model, cbus_irq, i8259_irq);
- }
-}
-
-static
-void mips_malta_init(MachineState *machine)
-{
- ram_addr_t ram_size = machine->ram_size;
- ram_addr_t ram_low_size;
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- const char *initrd_filename = machine->initrd_filename;
- char *filename;
- pflash_t *fl;
- MemoryRegion *system_memory = get_system_memory();
- MemoryRegion *ram_high = g_new(MemoryRegion, 1);
- MemoryRegion *ram_low_preio = g_new(MemoryRegion, 1);
- MemoryRegion *ram_low_postio;
- MemoryRegion *bios, *bios_copy = g_new(MemoryRegion, 1);
- target_long bios_size = FLASH_SIZE;
- const size_t smbus_eeprom_size = 8 * 256;
- uint8_t *smbus_eeprom_buf = g_malloc0(smbus_eeprom_size);
- int64_t kernel_entry, bootloader_run_addr;
- PCIBus *pci_bus;
- ISABus *isa_bus;
- qemu_irq *isa_irq;
- qemu_irq cbus_irq, i8259_irq;
- int piix4_devfn;
- I2CBus *smbus;
- int i;
- DriveInfo *dinfo;
- DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
- DriveInfo *fd[MAX_FD];
- int fl_idx = 0;
- int fl_sectors = bios_size >> 16;
- int be;
-
- DeviceState *dev = qdev_create(NULL, TYPE_MIPS_MALTA);
- MaltaState *s = MIPS_MALTA(dev);
-
- /* The whole address space decoded by the GT-64120A doesn't generate
- exception when accessing invalid memory. Create an empty slot to
- emulate this feature. */
- empty_slot_init(0, 0x20000000);
-
- qdev_init_nofail(dev);
-
- /* Make sure the first 3 serial ports are associated with a device. */
- for(i = 0; i < 3; i++) {
- if (!serial_hds[i]) {
- char label[32];
- snprintf(label, sizeof(label), "serial%d", i);
- serial_hds[i] = qemu_chr_new(label, "null", NULL);
- }
- }
-
- /* create CPU */
- create_cpu(s, machine->cpu_model, &cbus_irq, &i8259_irq);
-
- /* allocate RAM */
- if (ram_size > (2048u << 20)) {
- fprintf(stderr,
- "qemu: Too much memory for this machine: %d MB, maximum 2048 MB\n",
- ((unsigned int)ram_size / (1 << 20)));
- exit(1);
- }
-
- /* register RAM at high address where it is undisturbed by IO */
- memory_region_allocate_system_memory(ram_high, NULL, "mips_malta.ram",
- ram_size);
- memory_region_add_subregion(system_memory, 0x80000000, ram_high);
-
- /* alias for pre IO hole access */
- memory_region_init_alias(ram_low_preio, NULL, "mips_malta_low_preio.ram",
- ram_high, 0, MIN(ram_size, (256 << 20)));
- memory_region_add_subregion(system_memory, 0, ram_low_preio);
-
- /* alias for post IO hole access, if there is enough RAM */
- if (ram_size > (512 << 20)) {
- ram_low_postio = g_new(MemoryRegion, 1);
- memory_region_init_alias(ram_low_postio, NULL,
- "mips_malta_low_postio.ram",
- ram_high, 512 << 20,
- ram_size - (512 << 20));
- memory_region_add_subregion(system_memory, 512 << 20, ram_low_postio);
- }
-
- /* generate SPD EEPROM data */
- generate_eeprom_spd(&smbus_eeprom_buf[0 * 256], ram_size);
- generate_eeprom_serial(&smbus_eeprom_buf[6 * 256]);
-
-#ifdef TARGET_WORDS_BIGENDIAN
- be = 1;
-#else
- be = 0;
-#endif
- /* FPGA */
- /* The CBUS UART is attached to the MIPS CPU INT2 pin, ie interrupt 4 */
- malta_fpga_init(system_memory, FPGA_ADDRESS, cbus_irq, serial_hds[2]);
-
- /* Load firmware in flash / BIOS. */
- dinfo = drive_get(IF_PFLASH, 0, fl_idx);
-#ifdef DEBUG_BOARD_INIT
- if (dinfo) {
- printf("Register parallel flash %d size " TARGET_FMT_lx " at "
- "addr %08llx '%s' %x\n",
- fl_idx, bios_size, FLASH_ADDRESS,
- blk_name(dinfo->bdrv), fl_sectors);
- }
-#endif
- fl = pflash_cfi01_register(FLASH_ADDRESS, NULL, "mips_malta.bios",
- BIOS_SIZE,
- dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- 65536, fl_sectors,
- 4, 0x0000, 0x0000, 0x0000, 0x0000, be);
- bios = pflash_cfi01_get_memory(fl);
- fl_idx++;
- if (kernel_filename) {
- ram_low_size = MIN(ram_size, 256 << 20);
- /* For KVM we reserve 1MB of RAM for running bootloader */
- if (kvm_enabled()) {
- ram_low_size -= 0x100000;
- bootloader_run_addr = 0x40000000 + ram_low_size;
- } else {
- bootloader_run_addr = 0xbfc00000;
- }
-
- /* Write a small bootloader to the flash location. */
- loaderparams.ram_size = ram_size;
- loaderparams.ram_low_size = ram_low_size;
- loaderparams.kernel_filename = kernel_filename;
- loaderparams.kernel_cmdline = kernel_cmdline;
- loaderparams.initrd_filename = initrd_filename;
- kernel_entry = load_kernel();
-
- write_bootloader(memory_region_get_ram_ptr(bios),
- bootloader_run_addr, kernel_entry);
- if (kvm_enabled()) {
- /* Write the bootloader code @ the end of RAM, 1MB reserved */
- write_bootloader(memory_region_get_ram_ptr(ram_low_preio) +
- ram_low_size,
- bootloader_run_addr, kernel_entry);
- }
- } else {
- /* The flash region isn't executable from a KVM guest */
- if (kvm_enabled()) {
- error_report("KVM enabled but no -kernel argument was specified. "
- "Booting from flash is not supported with KVM.");
- exit(1);
- }
- /* Load firmware from flash. */
- if (!dinfo) {
- /* Load a BIOS image. */
- if (bios_name == NULL) {
- bios_name = BIOS_FILENAME;
- }
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
- if (filename) {
- bios_size = load_image_targphys(filename, FLASH_ADDRESS,
- BIOS_SIZE);
- g_free(filename);
- } else {
- bios_size = -1;
- }
- if ((bios_size < 0 || bios_size > BIOS_SIZE) &&
- !kernel_filename && !qtest_enabled()) {
- error_report("Could not load MIPS bios '%s', and no "
- "-kernel argument was specified", bios_name);
- exit(1);
- }
- }
- /* In little endian mode the 32bit words in the bios are swapped,
- a neat trick which allows bi-endian firmware. */
-#ifndef TARGET_WORDS_BIGENDIAN
- {
- uint32_t *end, *addr = rom_ptr(FLASH_ADDRESS);
- if (!addr) {
- addr = memory_region_get_ram_ptr(bios);
- }
- end = (void *)addr + MIN(bios_size, 0x3e0000);
- while (addr < end) {
- bswap32s(addr);
- addr++;
- }
- }
-#endif
- }
-
- /*
- * Map the BIOS at a 2nd physical location, as on the real board.
- * Copy it so that we can patch in the MIPS revision, which cannot be
- * handled by an overlapping region as the resulting ROM code subpage
- * regions are not executable.
- */
- memory_region_init_ram(bios_copy, NULL, "bios.1fc", BIOS_SIZE,
- &error_fatal);
- if (!rom_copy(memory_region_get_ram_ptr(bios_copy),
- FLASH_ADDRESS, BIOS_SIZE)) {
- memcpy(memory_region_get_ram_ptr(bios_copy),
- memory_region_get_ram_ptr(bios), BIOS_SIZE);
- }
- memory_region_set_readonly(bios_copy, true);
- memory_region_add_subregion(system_memory, RESET_ADDRESS, bios_copy);
-
- /* Board ID = 0x420 (Malta Board with CoreLV) */
- stl_p(memory_region_get_ram_ptr(bios_copy) + 0x10, 0x00000420);
-
- /*
- * We have a circular dependency problem: pci_bus depends on isa_irq,
- * isa_irq is provided by i8259, i8259 depends on ISA, ISA depends
- * on piix4, and piix4 depends on pci_bus. To stop the cycle we have
- * qemu_irq_proxy() adds an extra bit of indirection, allowing us
- * to resolve the isa_irq -> i8259 dependency after i8259 is initialized.
- */
- isa_irq = qemu_irq_proxy(&s->i8259, 16);
-
- /* Northbridge */
- pci_bus = gt64120_register(isa_irq);
-
- /* Southbridge */
- ide_drive_get(hd, ARRAY_SIZE(hd));
-
- piix4_devfn = piix4_init(pci_bus, &isa_bus, 80);
-
- /* Interrupt controller */
- /* The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2 */
- s->i8259 = i8259_init(isa_bus, i8259_irq);
-
- isa_bus_irqs(isa_bus, s->i8259);
- pci_piix4_ide_init(pci_bus, hd, piix4_devfn + 1);
- pci_create_simple(pci_bus, piix4_devfn + 2, "piix4-usb-uhci");
- smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100,
- isa_get_irq(NULL, 9), NULL, 0, NULL);
- smbus_eeprom_init(smbus, 8, smbus_eeprom_buf, smbus_eeprom_size);
- g_free(smbus_eeprom_buf);
- pit = pit_init(isa_bus, 0x40, 0, NULL);
- DMA_init(isa_bus, 0);
-
- /* Super I/O */
- isa_create_simple(isa_bus, "i8042");
-
- rtc_init(isa_bus, 2000, NULL);
- serial_hds_isa_init(isa_bus, 2);
- parallel_hds_isa_init(isa_bus, 1);
-
- for(i = 0; i < MAX_FD; i++) {
- fd[i] = drive_get(IF_FLOPPY, 0, i);
- }
- fdctrl_init_isa(isa_bus, fd);
-
- /* Network card */
- network_init(pci_bus);
-
- /* Optional PCI video card */
- pci_vga_init(pci_bus);
-}
-
-static int mips_malta_sysbus_device_init(SysBusDevice *sysbusdev)
-{
- return 0;
-}
-
-static void mips_malta_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = mips_malta_sysbus_device_init;
-}
-
-static const TypeInfo mips_malta_device = {
- .name = TYPE_MIPS_MALTA,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(MaltaState),
- .class_init = mips_malta_class_init,
-};
-
-static void mips_malta_machine_init(MachineClass *mc)
-{
- mc->desc = "MIPS Malta Core LV";
- mc->init = mips_malta_init;
- mc->max_cpus = 16;
- mc->is_default = 1;
-}
-
-DEFINE_MACHINE("malta", mips_malta_machine_init)
-
-static void mips_malta_register_types(void)
-{
- type_register_static(&mips_malta_device);
-}
-
-type_init(mips_malta_register_types)
diff --git a/qemu/hw/mips/mips_mipssim.c b/qemu/hw/mips/mips_mipssim.c
deleted file mode 100644
index a2c2a1646..000000000
--- a/qemu/hw/mips/mips_mipssim.c
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * QEMU/mipssim emulation
- *
- * Emulates a very simple machine model similar to the one used by the
- * proprietary MIPS emulator.
- *
- * Copyright (c) 2007 Thiemo Seufer
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/hw.h"
-#include "hw/mips/mips.h"
-#include "hw/mips/cpudevs.h"
-#include "hw/char/serial.h"
-#include "hw/isa/isa.h"
-#include "net/net.h"
-#include "sysemu/sysemu.h"
-#include "hw/boards.h"
-#include "hw/mips/bios.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "hw/sysbus.h"
-#include "exec/address-spaces.h"
-#include "qemu/error-report.h"
-#include "sysemu/qtest.h"
-
-static struct _loaderparams {
- int ram_size;
- const char *kernel_filename;
- const char *kernel_cmdline;
- const char *initrd_filename;
-} loaderparams;
-
-typedef struct ResetData {
- MIPSCPU *cpu;
- uint64_t vector;
-} ResetData;
-
-static int64_t load_kernel(void)
-{
- int64_t entry, kernel_high;
- long kernel_size;
- long initrd_size;
- ram_addr_t initrd_offset;
- int big_endian;
-
-#ifdef TARGET_WORDS_BIGENDIAN
- big_endian = 1;
-#else
- big_endian = 0;
-#endif
-
- kernel_size = load_elf(loaderparams.kernel_filename, cpu_mips_kseg0_to_phys,
- NULL, (uint64_t *)&entry, NULL,
- (uint64_t *)&kernel_high, big_endian,
- EM_MIPS, 1, 0);
- if (kernel_size >= 0) {
- if ((entry & ~0x7fffffffULL) == 0x80000000)
- entry = (int32_t)entry;
- } else {
- fprintf(stderr, "qemu: could not load kernel '%s'\n",
- loaderparams.kernel_filename);
- exit(1);
- }
-
- /* load initrd */
- initrd_size = 0;
- initrd_offset = 0;
- if (loaderparams.initrd_filename) {
- initrd_size = get_image_size (loaderparams.initrd_filename);
- if (initrd_size > 0) {
- initrd_offset = (kernel_high + ~INITRD_PAGE_MASK) & INITRD_PAGE_MASK;
- if (initrd_offset + initrd_size > loaderparams.ram_size) {
- fprintf(stderr,
- "qemu: memory too small for initial ram disk '%s'\n",
- loaderparams.initrd_filename);
- exit(1);
- }
- initrd_size = load_image_targphys(loaderparams.initrd_filename,
- initrd_offset, loaderparams.ram_size - initrd_offset);
- }
- if (initrd_size == (target_ulong) -1) {
- fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
- loaderparams.initrd_filename);
- exit(1);
- }
- }
- return entry;
-}
-
-static void main_cpu_reset(void *opaque)
-{
- ResetData *s = (ResetData *)opaque;
- CPUMIPSState *env = &s->cpu->env;
-
- cpu_reset(CPU(s->cpu));
- env->active_tc.PC = s->vector & ~(target_ulong)1;
- if (s->vector & 1) {
- env->hflags |= MIPS_HFLAG_M16;
- }
-}
-
-static void mipsnet_init(int base, qemu_irq irq, NICInfo *nd)
-{
- DeviceState *dev;
- SysBusDevice *s;
-
- dev = qdev_create(NULL, "mipsnet");
- qdev_set_nic_properties(dev, nd);
- qdev_init_nofail(dev);
-
- s = SYS_BUS_DEVICE(dev);
- sysbus_connect_irq(s, 0, irq);
- memory_region_add_subregion(get_system_io(),
- base,
- sysbus_mmio_get_region(s, 0));
-}
-
-static void
-mips_mipssim_init(MachineState *machine)
-{
- ram_addr_t ram_size = machine->ram_size;
- const char *cpu_model = machine->cpu_model;
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- const char *initrd_filename = machine->initrd_filename;
- char *filename;
- MemoryRegion *address_space_mem = get_system_memory();
- MemoryRegion *isa = g_new(MemoryRegion, 1);
- MemoryRegion *ram = g_new(MemoryRegion, 1);
- MemoryRegion *bios = g_new(MemoryRegion, 1);
- MIPSCPU *cpu;
- CPUMIPSState *env;
- ResetData *reset_info;
- int bios_size;
-
- /* Init CPUs. */
- if (cpu_model == NULL) {
-#ifdef TARGET_MIPS64
- cpu_model = "5Kf";
-#else
- cpu_model = "24Kf";
-#endif
- }
- cpu = cpu_mips_init(cpu_model);
- if (cpu == NULL) {
- fprintf(stderr, "Unable to find CPU definition\n");
- exit(1);
- }
- env = &cpu->env;
-
- reset_info = g_malloc0(sizeof(ResetData));
- reset_info->cpu = cpu;
- reset_info->vector = env->active_tc.PC;
- qemu_register_reset(main_cpu_reset, reset_info);
-
- /* Allocate RAM. */
- memory_region_allocate_system_memory(ram, NULL, "mips_mipssim.ram",
- ram_size);
- memory_region_init_ram(bios, NULL, "mips_mipssim.bios", BIOS_SIZE,
- &error_fatal);
- vmstate_register_ram_global(bios);
- memory_region_set_readonly(bios, true);
-
- memory_region_add_subregion(address_space_mem, 0, ram);
-
- /* Map the BIOS / boot exception handler. */
- memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios);
- /* Load a BIOS / boot exception handler image. */
- if (bios_name == NULL)
- bios_name = BIOS_FILENAME;
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
- if (filename) {
- bios_size = load_image_targphys(filename, 0x1fc00000LL, BIOS_SIZE);
- g_free(filename);
- } else {
- bios_size = -1;
- }
- if ((bios_size < 0 || bios_size > BIOS_SIZE) &&
- !kernel_filename && !qtest_enabled()) {
- /* Bail out if we have neither a kernel image nor boot vector code. */
- error_report("Could not load MIPS bios '%s', and no "
- "-kernel argument was specified", bios_name);
- exit(1);
- } else {
- /* We have a boot vector start address. */
- env->active_tc.PC = (target_long)(int32_t)0xbfc00000;
- }
-
- if (kernel_filename) {
- loaderparams.ram_size = ram_size;
- loaderparams.kernel_filename = kernel_filename;
- loaderparams.kernel_cmdline = kernel_cmdline;
- loaderparams.initrd_filename = initrd_filename;
- reset_info->vector = load_kernel();
- }
-
- /* Init CPU internal devices. */
- cpu_mips_irq_init_cpu(env);
- cpu_mips_clock_init(env);
-
- /* Register 64 KB of ISA IO space at 0x1fd00000. */
- memory_region_init_alias(isa, NULL, "isa_mmio",
- get_system_io(), 0, 0x00010000);
- memory_region_add_subregion(get_system_memory(), 0x1fd00000, isa);
-
- /* A single 16450 sits at offset 0x3f8. It is attached to
- MIPS CPU INT2, which is interrupt 4. */
- if (serial_hds[0])
- serial_init(0x3f8, env->irq[4], 115200, serial_hds[0],
- get_system_io());
-
- if (nd_table[0].used)
- /* MIPSnet uses the MIPS CPU INT0, which is interrupt 2. */
- mipsnet_init(0x4200, env->irq[2], &nd_table[0]);
-}
-
-static void mips_mipssim_machine_init(MachineClass *mc)
-{
- mc->desc = "MIPS MIPSsim platform";
- mc->init = mips_mipssim_init;
-}
-
-DEFINE_MACHINE("mipssim", mips_mipssim_machine_init)
diff --git a/qemu/hw/mips/mips_r4k.c b/qemu/hw/mips/mips_r4k.c
deleted file mode 100644
index 21aca981c..000000000
--- a/qemu/hw/mips/mips_r4k.c
+++ /dev/null
@@ -1,311 +0,0 @@
-/*
- * QEMU/MIPS pseudo-board
- *
- * emulates a simple machine with ISA-like bus.
- * ISA IO space mapped to the 0x14000000 (PHYS) and
- * ISA memory at the 0x10000000 (PHYS, 16Mb in size).
- * All peripherial devices are attached to this "bus" with
- * the standard PC ISA addresses.
-*/
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/hw.h"
-#include "hw/mips/mips.h"
-#include "hw/mips/cpudevs.h"
-#include "hw/i386/pc.h"
-#include "hw/char/serial.h"
-#include "hw/isa/isa.h"
-#include "net/net.h"
-#include "sysemu/sysemu.h"
-#include "hw/boards.h"
-#include "hw/block/flash.h"
-#include "qemu/log.h"
-#include "hw/mips/bios.h"
-#include "hw/ide.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "hw/timer/mc146818rtc.h"
-#include "hw/timer/i8254.h"
-#include "sysemu/block-backend.h"
-#include "exec/address-spaces.h"
-#include "sysemu/qtest.h"
-
-#define MAX_IDE_BUS 2
-
-static const int ide_iobase[2] = { 0x1f0, 0x170 };
-static const int ide_iobase2[2] = { 0x3f6, 0x376 };
-static const int ide_irq[2] = { 14, 15 };
-
-static ISADevice *pit; /* PIT i8254 */
-
-/* i8254 PIT is attached to the IRQ0 at PIC i8259 */
-
-static struct _loaderparams {
- int ram_size;
- const char *kernel_filename;
- const char *kernel_cmdline;
- const char *initrd_filename;
-} loaderparams;
-
-static void mips_qemu_write (void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- if ((addr & 0xffff) == 0 && val == 42)
- qemu_system_reset_request ();
- else if ((addr & 0xffff) == 4 && val == 42)
- qemu_system_shutdown_request ();
-}
-
-static uint64_t mips_qemu_read (void *opaque, hwaddr addr,
- unsigned size)
-{
- return 0;
-}
-
-static const MemoryRegionOps mips_qemu_ops = {
- .read = mips_qemu_read,
- .write = mips_qemu_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-typedef struct ResetData {
- MIPSCPU *cpu;
- uint64_t vector;
-} ResetData;
-
-static int64_t load_kernel(void)
-{
- int64_t entry, kernel_high;
- long kernel_size, initrd_size, params_size;
- ram_addr_t initrd_offset;
- uint32_t *params_buf;
- int big_endian;
-
-#ifdef TARGET_WORDS_BIGENDIAN
- big_endian = 1;
-#else
- big_endian = 0;
-#endif
- kernel_size = load_elf(loaderparams.kernel_filename, cpu_mips_kseg0_to_phys,
- NULL, (uint64_t *)&entry, NULL,
- (uint64_t *)&kernel_high, big_endian,
- EM_MIPS, 1, 0);
- if (kernel_size >= 0) {
- if ((entry & ~0x7fffffffULL) == 0x80000000)
- entry = (int32_t)entry;
- } else {
- fprintf(stderr, "qemu: could not load kernel '%s'\n",
- loaderparams.kernel_filename);
- exit(1);
- }
-
- /* load initrd */
- initrd_size = 0;
- initrd_offset = 0;
- if (loaderparams.initrd_filename) {
- initrd_size = get_image_size (loaderparams.initrd_filename);
- if (initrd_size > 0) {
- initrd_offset = (kernel_high + ~INITRD_PAGE_MASK) & INITRD_PAGE_MASK;
- if (initrd_offset + initrd_size > ram_size) {
- fprintf(stderr,
- "qemu: memory too small for initial ram disk '%s'\n",
- loaderparams.initrd_filename);
- exit(1);
- }
- initrd_size = load_image_targphys(loaderparams.initrd_filename,
- initrd_offset,
- ram_size - initrd_offset);
- }
- if (initrd_size == (target_ulong) -1) {
- fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
- loaderparams.initrd_filename);
- exit(1);
- }
- }
-
- /* Store command line. */
- params_size = 264;
- params_buf = g_malloc(params_size);
-
- params_buf[0] = tswap32(ram_size);
- params_buf[1] = tswap32(0x12345678);
-
- if (initrd_size > 0) {
- snprintf((char *)params_buf + 8, 256, "rd_start=0x%" PRIx64 " rd_size=%li %s",
- cpu_mips_phys_to_kseg0(NULL, initrd_offset),
- initrd_size, loaderparams.kernel_cmdline);
- } else {
- snprintf((char *)params_buf + 8, 256, "%s", loaderparams.kernel_cmdline);
- }
-
- rom_add_blob_fixed("params", params_buf, params_size,
- (16 << 20) - 264);
-
- g_free(params_buf);
- return entry;
-}
-
-static void main_cpu_reset(void *opaque)
-{
- ResetData *s = (ResetData *)opaque;
- CPUMIPSState *env = &s->cpu->env;
-
- cpu_reset(CPU(s->cpu));
- env->active_tc.PC = s->vector;
-}
-
-static const int sector_len = 32 * 1024;
-static
-void mips_r4k_init(MachineState *machine)
-{
- ram_addr_t ram_size = machine->ram_size;
- const char *cpu_model = machine->cpu_model;
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- const char *initrd_filename = machine->initrd_filename;
- char *filename;
- MemoryRegion *address_space_mem = get_system_memory();
- MemoryRegion *ram = g_new(MemoryRegion, 1);
- MemoryRegion *bios;
- MemoryRegion *iomem = g_new(MemoryRegion, 1);
- MemoryRegion *isa_io = g_new(MemoryRegion, 1);
- MemoryRegion *isa_mem = g_new(MemoryRegion, 1);
- int bios_size;
- MIPSCPU *cpu;
- CPUMIPSState *env;
- ResetData *reset_info;
- int i;
- qemu_irq *i8259;
- ISABus *isa_bus;
- DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
- DriveInfo *dinfo;
- int be;
-
- /* init CPUs */
- if (cpu_model == NULL) {
-#ifdef TARGET_MIPS64
- cpu_model = "R4000";
-#else
- cpu_model = "24Kf";
-#endif
- }
- cpu = cpu_mips_init(cpu_model);
- if (cpu == NULL) {
- fprintf(stderr, "Unable to find CPU definition\n");
- exit(1);
- }
- env = &cpu->env;
-
- reset_info = g_malloc0(sizeof(ResetData));
- reset_info->cpu = cpu;
- reset_info->vector = env->active_tc.PC;
- qemu_register_reset(main_cpu_reset, reset_info);
-
- /* allocate RAM */
- if (ram_size > (256 << 20)) {
- fprintf(stderr,
- "qemu: Too much memory for this machine: %d MB, maximum 256 MB\n",
- ((unsigned int)ram_size / (1 << 20)));
- exit(1);
- }
- memory_region_allocate_system_memory(ram, NULL, "mips_r4k.ram", ram_size);
-
- memory_region_add_subregion(address_space_mem, 0, ram);
-
- memory_region_init_io(iomem, NULL, &mips_qemu_ops, NULL, "mips-qemu", 0x10000);
- memory_region_add_subregion(address_space_mem, 0x1fbf0000, iomem);
-
- /* Try to load a BIOS image. If this fails, we continue regardless,
- but initialize the hardware ourselves. When a kernel gets
- preloaded we also initialize the hardware, since the BIOS wasn't
- run. */
- if (bios_name == NULL)
- bios_name = BIOS_FILENAME;
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
- if (filename) {
- bios_size = get_image_size(filename);
- } else {
- bios_size = -1;
- }
-#ifdef TARGET_WORDS_BIGENDIAN
- be = 1;
-#else
- be = 0;
-#endif
- if ((bios_size > 0) && (bios_size <= BIOS_SIZE)) {
- bios = g_new(MemoryRegion, 1);
- memory_region_init_ram(bios, NULL, "mips_r4k.bios", BIOS_SIZE,
- &error_fatal);
- vmstate_register_ram_global(bios);
- memory_region_set_readonly(bios, true);
- memory_region_add_subregion(get_system_memory(), 0x1fc00000, bios);
-
- load_image_targphys(filename, 0x1fc00000, BIOS_SIZE);
- } else if ((dinfo = drive_get(IF_PFLASH, 0, 0)) != NULL) {
- uint32_t mips_rom = 0x00400000;
- if (!pflash_cfi01_register(0x1fc00000, NULL, "mips_r4k.bios", mips_rom,
- blk_by_legacy_dinfo(dinfo),
- sector_len, mips_rom / sector_len,
- 4, 0, 0, 0, 0, be)) {
- fprintf(stderr, "qemu: Error registering flash memory.\n");
- }
- } else if (!qtest_enabled()) {
- /* not fatal */
- fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n",
- bios_name);
- }
- g_free(filename);
-
- if (kernel_filename) {
- loaderparams.ram_size = ram_size;
- loaderparams.kernel_filename = kernel_filename;
- loaderparams.kernel_cmdline = kernel_cmdline;
- loaderparams.initrd_filename = initrd_filename;
- reset_info->vector = load_kernel();
- }
-
- /* Init CPU internal devices */
- cpu_mips_irq_init_cpu(env);
- cpu_mips_clock_init(env);
-
- /* ISA bus: IO space at 0x14000000, mem space at 0x10000000 */
- memory_region_init_alias(isa_io, NULL, "isa-io",
- get_system_io(), 0, 0x00010000);
- memory_region_init(isa_mem, NULL, "isa-mem", 0x01000000);
- memory_region_add_subregion(get_system_memory(), 0x14000000, isa_io);
- memory_region_add_subregion(get_system_memory(), 0x10000000, isa_mem);
- isa_bus = isa_bus_new(NULL, isa_mem, get_system_io(), &error_abort);
-
- /* The PIC is attached to the MIPS CPU INT0 pin */
- i8259 = i8259_init(isa_bus, env->irq[2]);
- isa_bus_irqs(isa_bus, i8259);
-
- rtc_init(isa_bus, 2000, NULL);
-
- pit = pit_init(isa_bus, 0x40, 0, NULL);
-
- serial_hds_isa_init(isa_bus, MAX_SERIAL_PORTS);
-
- isa_vga_init(isa_bus);
-
- if (nd_table[0].used)
- isa_ne2000_init(isa_bus, 0x300, 9, &nd_table[0]);
-
- ide_drive_get(hd, ARRAY_SIZE(hd));
- for(i = 0; i < MAX_IDE_BUS; i++)
- isa_ide_init(isa_bus, ide_iobase[i], ide_iobase2[i], ide_irq[i],
- hd[MAX_IDE_DEVS * i],
- hd[MAX_IDE_DEVS * i + 1]);
-
- isa_create_simple(isa_bus, "i8042");
-}
-
-static void mips_machine_init(MachineClass *mc)
-{
- mc->desc = "mips r4k platform";
- mc->init = mips_r4k_init;
-}
-
-DEFINE_MACHINE("mips", mips_machine_init)
diff --git a/qemu/hw/misc/Makefile.objs b/qemu/hw/misc/Makefile.objs
deleted file mode 100644
index 93f952880..000000000
--- a/qemu/hw/misc/Makefile.objs
+++ /dev/null
@@ -1,52 +0,0 @@
-common-obj-$(CONFIG_APPLESMC) += applesmc.o
-common-obj-$(CONFIG_MAX111X) += max111x.o
-common-obj-$(CONFIG_TMP105) += tmp105.o
-common-obj-$(CONFIG_ISA_DEBUG) += debugexit.o
-common-obj-$(CONFIG_SGA) += sga.o
-common-obj-$(CONFIG_ISA_TESTDEV) += pc-testdev.o
-common-obj-$(CONFIG_PCI_TESTDEV) += pci-testdev.o
-
-obj-$(CONFIG_VMPORT) += vmport.o
-
-# ARM devices
-common-obj-$(CONFIG_PL310) += arm_l2x0.o
-common-obj-$(CONFIG_INTEGRATOR_DEBUG) += arm_integrator_debug.o
-common-obj-$(CONFIG_A9SCU) += a9scu.o
-common-obj-$(CONFIG_ARM11SCU) += arm11scu.o
-
-# PKUnity SoC devices
-common-obj-$(CONFIG_PUV3) += puv3_pm.o
-
-common-obj-$(CONFIG_MACIO) += macio/
-
-obj-$(CONFIG_IVSHMEM) += ivshmem.o
-
-obj-$(CONFIG_REALVIEW) += arm_sysctl.o
-obj-$(CONFIG_NSERIES) += cbus.o
-obj-$(CONFIG_ECCMEMCTL) += eccmemctl.o
-obj-$(CONFIG_EXYNOS4) += exynos4210_pmu.o
-obj-$(CONFIG_IMX) += imx_ccm.o
-obj-$(CONFIG_IMX) += imx31_ccm.o
-obj-$(CONFIG_IMX) += imx25_ccm.o
-obj-$(CONFIG_IMX) += imx6_ccm.o
-obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o
-obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o
-obj-$(CONFIG_MAINSTONE) += mst_fpga.o
-obj-$(CONFIG_OMAP) += omap_clk.o
-obj-$(CONFIG_OMAP) += omap_gpmc.o
-obj-$(CONFIG_OMAP) += omap_l4.o
-obj-$(CONFIG_OMAP) += omap_sdrc.o
-obj-$(CONFIG_OMAP) += omap_tap.o
-obj-$(CONFIG_RASPI) += bcm2835_mbox.o
-obj-$(CONFIG_RASPI) += bcm2835_property.o
-obj-$(CONFIG_SLAVIO) += slavio_misc.o
-obj-$(CONFIG_ZYNQ) += zynq_slcr.o
-obj-$(CONFIG_ZYNQ) += zynq-xadc.o
-obj-$(CONFIG_STM32F2XX_SYSCFG) += stm32f2xx_syscfg.o
-obj-$(CONFIG_MIPS_CPS) += mips_cmgcr.o
-obj-$(CONFIG_MIPS_CPS) += mips_cpc.o
-obj-$(CONFIG_MIPS_ITU) += mips_itu.o
-
-obj-$(CONFIG_PVPANIC) += pvpanic.o
-obj-$(CONFIG_EDU) += edu.o
-obj-$(CONFIG_HYPERV_TESTDEV) += hyperv_testdev.o
diff --git a/qemu/hw/misc/a9scu.c b/qemu/hw/misc/a9scu.c
deleted file mode 100644
index 3e8ad8cd7..000000000
--- a/qemu/hw/misc/a9scu.c
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Cortex-A9MPCore Snoop Control Unit (SCU) emulation.
- *
- * Copyright (c) 2009 CodeSourcery.
- * Copyright (c) 2011 Linaro Limited.
- * Written by Paul Brook, Peter Maydell.
- *
- * This code is licensed under the GPL.
- */
-
-#include "qemu/osdep.h"
-#include "hw/misc/a9scu.h"
-
-static uint64_t a9_scu_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- A9SCUState *s = (A9SCUState *)opaque;
- switch (offset) {
- case 0x00: /* Control */
- return s->control;
- case 0x04: /* Configuration */
- return (((1 << s->num_cpu) - 1) << 4) | (s->num_cpu - 1);
- case 0x08: /* CPU Power Status */
- return s->status;
- case 0x09: /* CPU status. */
- return s->status >> 8;
- case 0x0a: /* CPU status. */
- return s->status >> 16;
- case 0x0b: /* CPU status. */
- return s->status >> 24;
- case 0x0c: /* Invalidate All Registers In Secure State */
- return 0;
- case 0x40: /* Filtering Start Address Register */
- case 0x44: /* Filtering End Address Register */
- /* RAZ/WI, like an implementation with only one AXI master */
- return 0;
- case 0x50: /* SCU Access Control Register */
- case 0x54: /* SCU Non-secure Access Control Register */
- /* unimplemented, fall through */
- default:
- return 0;
- }
-}
-
-static void a9_scu_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- A9SCUState *s = (A9SCUState *)opaque;
- uint32_t mask;
- uint32_t shift;
- switch (size) {
- case 1:
- mask = 0xff;
- break;
- case 2:
- mask = 0xffff;
- break;
- case 4:
- mask = 0xffffffff;
- break;
- default:
- fprintf(stderr, "Invalid size %u in write to a9 scu register %x\n",
- size, (unsigned)offset);
- return;
- }
-
- switch (offset) {
- case 0x00: /* Control */
- s->control = value & 1;
- break;
- case 0x4: /* Configuration: RO */
- break;
- case 0x08: case 0x09: case 0x0A: case 0x0B: /* Power Control */
- shift = (offset - 0x8) * 8;
- s->status &= ~(mask << shift);
- s->status |= ((value & mask) << shift);
- break;
- case 0x0c: /* Invalidate All Registers In Secure State */
- /* no-op as we do not implement caches */
- break;
- case 0x40: /* Filtering Start Address Register */
- case 0x44: /* Filtering End Address Register */
- /* RAZ/WI, like an implementation with only one AXI master */
- break;
- case 0x50: /* SCU Access Control Register */
- case 0x54: /* SCU Non-secure Access Control Register */
- /* unimplemented, fall through */
- default:
- break;
- }
-}
-
-static const MemoryRegionOps a9_scu_ops = {
- .read = a9_scu_read,
- .write = a9_scu_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void a9_scu_reset(DeviceState *dev)
-{
- A9SCUState *s = A9_SCU(dev);
- s->control = 0;
-}
-
-static void a9_scu_init(Object *obj)
-{
- A9SCUState *s = A9_SCU(obj);
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
-
- memory_region_init_io(&s->iomem, obj, &a9_scu_ops, s,
- "a9-scu", 0x100);
- sysbus_init_mmio(sbd, &s->iomem);
-}
-
-static const VMStateDescription vmstate_a9_scu = {
- .name = "a9-scu",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(control, A9SCUState),
- VMSTATE_UINT32(status, A9SCUState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property a9_scu_properties[] = {
- DEFINE_PROP_UINT32("num-cpu", A9SCUState, num_cpu, 1),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void a9_scu_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->props = a9_scu_properties;
- dc->vmsd = &vmstate_a9_scu;
- dc->reset = a9_scu_reset;
-}
-
-static const TypeInfo a9_scu_info = {
- .name = TYPE_A9_SCU,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(A9SCUState),
- .instance_init = a9_scu_init,
- .class_init = a9_scu_class_init,
-};
-
-static void a9mp_register_types(void)
-{
- type_register_static(&a9_scu_info);
-}
-
-type_init(a9mp_register_types)
diff --git a/qemu/hw/misc/applesmc.c b/qemu/hw/misc/applesmc.c
deleted file mode 100644
index 77fab5b9d..000000000
--- a/qemu/hw/misc/applesmc.c
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * Apple SMC controller
- *
- * Copyright (c) 2007 Alexander Graf
- *
- * Authors: Alexander Graf <agraf@suse.de>
- * Susanne Graf <suse@csgraf.de>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- * *****************************************************************
- *
- * In all Intel-based Apple hardware there is an SMC chip to control the
- * backlight, fans and several other generic device parameters. It also
- * contains the magic keys used to dongle Mac OS X to the device.
- *
- * This driver was mostly created by looking at the Linux AppleSMC driver
- * implementation and does not support IRQ.
- *
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/isa/isa.h"
-#include "ui/console.h"
-#include "qemu/timer.h"
-
-/* #define DEBUG_SMC */
-
-#define APPLESMC_DEFAULT_IOBASE 0x300
-/* data port used by Apple SMC */
-#define APPLESMC_DATA_PORT 0x0
-/* command/status port used by Apple SMC */
-#define APPLESMC_CMD_PORT 0x4
-#define APPLESMC_NR_PORTS 32
-
-#define APPLESMC_READ_CMD 0x10
-#define APPLESMC_WRITE_CMD 0x11
-#define APPLESMC_GET_KEY_BY_INDEX_CMD 0x12
-#define APPLESMC_GET_KEY_TYPE_CMD 0x13
-
-#ifdef DEBUG_SMC
-#define smc_debug(...) fprintf(stderr, "AppleSMC: " __VA_ARGS__)
-#else
-#define smc_debug(...) do { } while(0)
-#endif
-
-static char default_osk[64] = "This is a dummy key. Enter the real key "
- "using the -osk parameter";
-
-struct AppleSMCData {
- uint8_t len;
- const char *key;
- const char *data;
- QLIST_ENTRY(AppleSMCData) node;
-};
-
-#define APPLE_SMC(obj) OBJECT_CHECK(AppleSMCState, (obj), TYPE_APPLE_SMC)
-
-typedef struct AppleSMCState AppleSMCState;
-struct AppleSMCState {
- ISADevice parent_obj;
-
- MemoryRegion io_data;
- MemoryRegion io_cmd;
- uint32_t iobase;
- uint8_t cmd;
- uint8_t status;
- uint8_t key[4];
- uint8_t read_pos;
- uint8_t data_len;
- uint8_t data_pos;
- uint8_t data[255];
- uint8_t charactic[4];
- char *osk;
- QLIST_HEAD(, AppleSMCData) data_def;
-};
-
-static void applesmc_io_cmd_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned size)
-{
- AppleSMCState *s = opaque;
-
- smc_debug("CMD Write B: %#x = %#x\n", addr, val);
- switch(val) {
- case APPLESMC_READ_CMD:
- s->status = 0x0c;
- break;
- }
- s->cmd = val;
- s->read_pos = 0;
- s->data_pos = 0;
-}
-
-static void applesmc_fill_data(AppleSMCState *s)
-{
- struct AppleSMCData *d;
-
- QLIST_FOREACH(d, &s->data_def, node) {
- if (!memcmp(d->key, s->key, 4)) {
- smc_debug("Key matched (%s Len=%d Data=%s)\n", d->key,
- d->len, d->data);
- memcpy(s->data, d->data, d->len);
- return;
- }
- }
-}
-
-static void applesmc_io_data_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned size)
-{
- AppleSMCState *s = opaque;
-
- smc_debug("DATA Write B: %#x = %#x\n", addr, val);
- switch(s->cmd) {
- case APPLESMC_READ_CMD:
- if(s->read_pos < 4) {
- s->key[s->read_pos] = val;
- s->status = 0x04;
- } else if(s->read_pos == 4) {
- s->data_len = val;
- s->status = 0x05;
- s->data_pos = 0;
- smc_debug("Key = %c%c%c%c Len = %d\n", s->key[0],
- s->key[1], s->key[2], s->key[3], val);
- applesmc_fill_data(s);
- }
- s->read_pos++;
- break;
- }
-}
-
-static uint64_t applesmc_io_data_read(void *opaque, hwaddr addr1,
- unsigned size)
-{
- AppleSMCState *s = opaque;
- uint8_t retval = 0;
-
- switch(s->cmd) {
- case APPLESMC_READ_CMD:
- if(s->data_pos < s->data_len) {
- retval = s->data[s->data_pos];
- smc_debug("READ_DATA[%d] = %#hhx\n", s->data_pos,
- retval);
- s->data_pos++;
- if(s->data_pos == s->data_len) {
- s->status = 0x00;
- smc_debug("EOF\n");
- } else
- s->status = 0x05;
- }
- }
- smc_debug("DATA Read b: %#x = %#x\n", addr1, retval);
-
- return retval;
-}
-
-static uint64_t applesmc_io_cmd_read(void *opaque, hwaddr addr1, unsigned size)
-{
- AppleSMCState *s = opaque;
-
- smc_debug("CMD Read B: %#x\n", addr1);
- return s->status;
-}
-
-static void applesmc_add_key(AppleSMCState *s, const char *key,
- int len, const char *data)
-{
- struct AppleSMCData *def;
-
- def = g_malloc0(sizeof(struct AppleSMCData));
- def->key = key;
- def->len = len;
- def->data = data;
-
- QLIST_INSERT_HEAD(&s->data_def, def, node);
-}
-
-static void qdev_applesmc_isa_reset(DeviceState *dev)
-{
- AppleSMCState *s = APPLE_SMC(dev);
- struct AppleSMCData *d, *next;
-
- /* Remove existing entries */
- QLIST_FOREACH_SAFE(d, &s->data_def, node, next) {
- QLIST_REMOVE(d, node);
- }
-
- applesmc_add_key(s, "REV ", 6, "\x01\x13\x0f\x00\x00\x03");
- applesmc_add_key(s, "OSK0", 32, s->osk);
- applesmc_add_key(s, "OSK1", 32, s->osk + 32);
- applesmc_add_key(s, "NATJ", 1, "\0");
- applesmc_add_key(s, "MSSP", 1, "\0");
- applesmc_add_key(s, "MSSD", 1, "\0x3");
-}
-
-static const MemoryRegionOps applesmc_data_io_ops = {
- .write = applesmc_io_data_write,
- .read = applesmc_io_data_read,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
-};
-
-static const MemoryRegionOps applesmc_cmd_io_ops = {
- .write = applesmc_io_cmd_write,
- .read = applesmc_io_cmd_read,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
-};
-
-static void applesmc_isa_realize(DeviceState *dev, Error **errp)
-{
- AppleSMCState *s = APPLE_SMC(dev);
-
- memory_region_init_io(&s->io_data, OBJECT(s), &applesmc_data_io_ops, s,
- "applesmc-data", 4);
- isa_register_ioport(&s->parent_obj, &s->io_data,
- s->iobase + APPLESMC_DATA_PORT);
-
- memory_region_init_io(&s->io_cmd, OBJECT(s), &applesmc_cmd_io_ops, s,
- "applesmc-cmd", 4);
- isa_register_ioport(&s->parent_obj, &s->io_cmd,
- s->iobase + APPLESMC_CMD_PORT);
-
- if (!s->osk || (strlen(s->osk) != 64)) {
- fprintf(stderr, "WARNING: Using AppleSMC with invalid key\n");
- s->osk = default_osk;
- }
-
- QLIST_INIT(&s->data_def);
- qdev_applesmc_isa_reset(dev);
-}
-
-static Property applesmc_isa_properties[] = {
- DEFINE_PROP_UINT32(APPLESMC_PROP_IO_BASE, AppleSMCState, iobase,
- APPLESMC_DEFAULT_IOBASE),
- DEFINE_PROP_STRING("osk", AppleSMCState, osk),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void qdev_applesmc_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = applesmc_isa_realize;
- dc->reset = qdev_applesmc_isa_reset;
- dc->props = applesmc_isa_properties;
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
-}
-
-static const TypeInfo applesmc_isa_info = {
- .name = TYPE_APPLE_SMC,
- .parent = TYPE_ISA_DEVICE,
- .instance_size = sizeof(AppleSMCState),
- .class_init = qdev_applesmc_class_init,
-};
-
-static void applesmc_register_types(void)
-{
- type_register_static(&applesmc_isa_info);
-}
-
-type_init(applesmc_register_types)
diff --git a/qemu/hw/misc/arm11scu.c b/qemu/hw/misc/arm11scu.c
deleted file mode 100644
index 5e54b494b..000000000
--- a/qemu/hw/misc/arm11scu.c
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * ARM11MPCore Snoop Control Unit (SCU) emulation
- *
- * Copyright (c) 2006-2007 CodeSourcery.
- * Copyright (c) 2013 SUSE LINUX Products GmbH
- * Written by Paul Brook and Andreas Färber
- *
- * This code is licensed under the GPL.
- */
-
-#include "qemu/osdep.h"
-#include "hw/misc/arm11scu.h"
-
-static uint64_t mpcore_scu_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- ARM11SCUState *s = (ARM11SCUState *)opaque;
- int id;
- /* SCU */
- switch (offset) {
- case 0x00: /* Control. */
- return s->control;
- case 0x04: /* Configuration. */
- id = ((1 << s->num_cpu) - 1) << 4;
- return id | (s->num_cpu - 1);
- case 0x08: /* CPU status. */
- return 0;
- case 0x0c: /* Invalidate all. */
- return 0;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "mpcore_priv_read: Bad offset %x\n", (int)offset);
- return 0;
- }
-}
-
-static void mpcore_scu_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- ARM11SCUState *s = (ARM11SCUState *)opaque;
- /* SCU */
- switch (offset) {
- case 0: /* Control register. */
- s->control = value & 1;
- break;
- case 0x0c: /* Invalidate all. */
- /* This is a no-op as cache is not emulated. */
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "mpcore_priv_read: Bad offset %x\n", (int)offset);
- }
-}
-
-static const MemoryRegionOps mpcore_scu_ops = {
- .read = mpcore_scu_read,
- .write = mpcore_scu_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void arm11_scu_realize(DeviceState *dev, Error **errp)
-{
-}
-
-static void arm11_scu_init(Object *obj)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- ARM11SCUState *s = ARM11_SCU(obj);
-
- memory_region_init_io(&s->iomem, OBJECT(s),
- &mpcore_scu_ops, s, "mpcore-scu", 0x100);
- sysbus_init_mmio(sbd, &s->iomem);
-}
-
-static Property arm11_scu_properties[] = {
- DEFINE_PROP_UINT32("num-cpu", ARM11SCUState, num_cpu, 1),
- DEFINE_PROP_END_OF_LIST()
-};
-
-static void arm11_scu_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- dc->realize = arm11_scu_realize;
- dc->props = arm11_scu_properties;
-}
-
-static const TypeInfo arm11_scu_type_info = {
- .name = TYPE_ARM11_SCU,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(ARM11SCUState),
- .instance_init = arm11_scu_init,
- .class_init = arm11_scu_class_init,
-};
-
-static void arm11_scu_register_types(void)
-{
- type_register_static(&arm11_scu_type_info);
-}
-
-type_init(arm11_scu_register_types)
diff --git a/qemu/hw/misc/arm_integrator_debug.c b/qemu/hw/misc/arm_integrator_debug.c
deleted file mode 100644
index 902605fef..000000000
--- a/qemu/hw/misc/arm_integrator_debug.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * LED, Switch and Debug control registers for ARM Integrator Boards
- *
- * This is currently a stub for this functionality but at least
- * ensures something other than unassigned_mem_read() handles access
- * to this area.
- *
- * The real h/w is described at:
- * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0159b/Babbfijf.html
- *
- * Copyright (c) 2013 Alex Bennée <alex@bennee.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "exec/address-spaces.h"
-#include "hw/misc/arm_integrator_debug.h"
-
-#define INTEGRATOR_DEBUG(obj) \
- OBJECT_CHECK(IntegratorDebugState, (obj), TYPE_INTEGRATOR_DEBUG)
-
-typedef struct {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
-} IntegratorDebugState;
-
-static uint64_t intdbg_control_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- switch (offset >> 2) {
- case 0: /* ALPHA */
- case 1: /* LEDS */
- case 2: /* SWITCHES */
- qemu_log_mask(LOG_UNIMP,
- "%s: returning zero from %" HWADDR_PRIx ":%u\n",
- __func__, offset, size);
- return 0;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad offset %" HWADDR_PRIx,
- __func__, offset);
- return 0;
- }
-}
-
-static void intdbg_control_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- switch (offset >> 2) {
- case 1: /* ALPHA */
- case 2: /* LEDS */
- case 3: /* SWITCHES */
- /* Nothing interesting implemented yet. */
- qemu_log_mask(LOG_UNIMP,
- "%s: ignoring write of %" PRIu64
- " to %" HWADDR_PRIx ":%u\n",
- __func__, value, offset, size);
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: write of %" PRIu64
- " to bad offset %" HWADDR_PRIx "\n",
- __func__, value, offset);
- }
-}
-
-static const MemoryRegionOps intdbg_control_ops = {
- .read = intdbg_control_read,
- .write = intdbg_control_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void intdbg_control_init(Object *obj)
-{
- SysBusDevice *sd = SYS_BUS_DEVICE(obj);
- IntegratorDebugState *s = INTEGRATOR_DEBUG(obj);
-
- memory_region_init_io(&s->iomem, obj, &intdbg_control_ops,
- NULL, "dbg-leds", 0x1000000);
- sysbus_init_mmio(sd, &s->iomem);
-}
-
-static const TypeInfo intdbg_info = {
- .name = TYPE_INTEGRATOR_DEBUG,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(IntegratorDebugState),
- .instance_init = intdbg_control_init,
-};
-
-static void intdbg_register_types(void)
-{
- type_register_static(&intdbg_info);
-}
-
-type_init(intdbg_register_types)
diff --git a/qemu/hw/misc/arm_l2x0.c b/qemu/hw/misc/arm_l2x0.c
deleted file mode 100644
index 7e179f1a4..000000000
--- a/qemu/hw/misc/arm_l2x0.c
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * ARM dummy L210, L220, PL310 cache controller.
- *
- * Copyright (c) 2010-2012 Calxeda
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2 or any later version, as published by the Free Software
- * Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-
-/* L2C-310 r3p2 */
-#define CACHE_ID 0x410000c8
-
-#define TYPE_ARM_L2X0 "l2x0"
-#define ARM_L2X0(obj) OBJECT_CHECK(L2x0State, (obj), TYPE_ARM_L2X0)
-
-typedef struct L2x0State {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- uint32_t cache_type;
- uint32_t ctrl;
- uint32_t aux_ctrl;
- uint32_t data_ctrl;
- uint32_t tag_ctrl;
- uint32_t filter_start;
- uint32_t filter_end;
-} L2x0State;
-
-static const VMStateDescription vmstate_l2x0 = {
- .name = "l2x0",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(ctrl, L2x0State),
- VMSTATE_UINT32(aux_ctrl, L2x0State),
- VMSTATE_UINT32(data_ctrl, L2x0State),
- VMSTATE_UINT32(tag_ctrl, L2x0State),
- VMSTATE_UINT32(filter_start, L2x0State),
- VMSTATE_UINT32(filter_end, L2x0State),
- VMSTATE_END_OF_LIST()
- }
-};
-
-
-static uint64_t l2x0_priv_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- uint32_t cache_data;
- L2x0State *s = (L2x0State *)opaque;
- offset &= 0xfff;
- if (offset >= 0x730 && offset < 0x800) {
- return 0; /* cache ops complete */
- }
- switch (offset) {
- case 0:
- return CACHE_ID;
- case 0x4:
- /* aux_ctrl values affect cache_type values */
- cache_data = (s->aux_ctrl & (7 << 17)) >> 15;
- cache_data |= (s->aux_ctrl & (1 << 16)) >> 16;
- return s->cache_type |= (cache_data << 18) | (cache_data << 6);
- case 0x100:
- return s->ctrl;
- case 0x104:
- return s->aux_ctrl;
- case 0x108:
- return s->tag_ctrl;
- case 0x10C:
- return s->data_ctrl;
- case 0xC00:
- return s->filter_start;
- case 0xC04:
- return s->filter_end;
- case 0xF40:
- return 0;
- case 0xF60:
- return 0;
- case 0xF80:
- return 0;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "l2x0_priv_read: Bad offset %x\n", (int)offset);
- break;
- }
- return 0;
-}
-
-static void l2x0_priv_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- L2x0State *s = (L2x0State *)opaque;
- offset &= 0xfff;
- if (offset >= 0x730 && offset < 0x800) {
- /* ignore */
- return;
- }
- switch (offset) {
- case 0x100:
- s->ctrl = value & 1;
- break;
- case 0x104:
- s->aux_ctrl = value;
- break;
- case 0x108:
- s->tag_ctrl = value;
- break;
- case 0x10C:
- s->data_ctrl = value;
- break;
- case 0xC00:
- s->filter_start = value;
- break;
- case 0xC04:
- s->filter_end = value;
- break;
- case 0xF40:
- return;
- case 0xF60:
- return;
- case 0xF80:
- return;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "l2x0_priv_write: Bad offset %x\n", (int)offset);
- break;
- }
-}
-
-static void l2x0_priv_reset(DeviceState *dev)
-{
- L2x0State *s = ARM_L2X0(dev);
-
- s->ctrl = 0;
- s->aux_ctrl = 0x02020000;
- s->tag_ctrl = 0;
- s->data_ctrl = 0;
- s->filter_start = 0;
- s->filter_end = 0;
-}
-
-static const MemoryRegionOps l2x0_mem_ops = {
- .read = l2x0_priv_read,
- .write = l2x0_priv_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- };
-
-static int l2x0_priv_init(SysBusDevice *dev)
-{
- L2x0State *s = ARM_L2X0(dev);
-
- memory_region_init_io(&s->iomem, OBJECT(dev), &l2x0_mem_ops, s,
- "l2x0_cc", 0x1000);
- sysbus_init_mmio(dev, &s->iomem);
- return 0;
-}
-
-static Property l2x0_properties[] = {
- DEFINE_PROP_UINT32("cache-type", L2x0State, cache_type, 0x1c100100),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void l2x0_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- k->init = l2x0_priv_init;
- dc->vmsd = &vmstate_l2x0;
- dc->props = l2x0_properties;
- dc->reset = l2x0_priv_reset;
-}
-
-static const TypeInfo l2x0_info = {
- .name = TYPE_ARM_L2X0,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(L2x0State),
- .class_init = l2x0_class_init,
-};
-
-static void l2x0_register_types(void)
-{
- type_register_static(&l2x0_info);
-}
-
-type_init(l2x0_register_types)
diff --git a/qemu/hw/misc/arm_sysctl.c b/qemu/hw/misc/arm_sysctl.c
deleted file mode 100644
index 34d90d523..000000000
--- a/qemu/hw/misc/arm_sysctl.c
+++ /dev/null
@@ -1,658 +0,0 @@
-/*
- * Status and system control registers for ARM RealView/Versatile boards.
- *
- * Copyright (c) 2006-2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "qemu/timer.h"
-#include "qemu/bitops.h"
-#include "hw/sysbus.h"
-#include "hw/arm/primecell.h"
-#include "sysemu/sysemu.h"
-
-#define LOCK_VALUE 0xa05f
-
-#define TYPE_ARM_SYSCTL "realview_sysctl"
-#define ARM_SYSCTL(obj) \
- OBJECT_CHECK(arm_sysctl_state, (obj), TYPE_ARM_SYSCTL)
-
-typedef struct {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- qemu_irq pl110_mux_ctrl;
-
- uint32_t sys_id;
- uint32_t leds;
- uint16_t lockval;
- uint32_t cfgdata1;
- uint32_t cfgdata2;
- uint32_t flags;
- uint32_t nvflags;
- uint32_t resetlevel;
- uint32_t proc_id;
- uint32_t sys_mci;
- uint32_t sys_cfgdata;
- uint32_t sys_cfgctrl;
- uint32_t sys_cfgstat;
- uint32_t sys_clcd;
- uint32_t mb_clock[6];
- uint32_t *db_clock;
- uint32_t db_num_vsensors;
- uint32_t *db_voltage;
- uint32_t db_num_clocks;
- uint32_t *db_clock_reset;
-} arm_sysctl_state;
-
-static const VMStateDescription vmstate_arm_sysctl = {
- .name = "realview_sysctl",
- .version_id = 4,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(leds, arm_sysctl_state),
- VMSTATE_UINT16(lockval, arm_sysctl_state),
- VMSTATE_UINT32(cfgdata1, arm_sysctl_state),
- VMSTATE_UINT32(cfgdata2, arm_sysctl_state),
- VMSTATE_UINT32(flags, arm_sysctl_state),
- VMSTATE_UINT32(nvflags, arm_sysctl_state),
- VMSTATE_UINT32(resetlevel, arm_sysctl_state),
- VMSTATE_UINT32_V(sys_mci, arm_sysctl_state, 2),
- VMSTATE_UINT32_V(sys_cfgdata, arm_sysctl_state, 2),
- VMSTATE_UINT32_V(sys_cfgctrl, arm_sysctl_state, 2),
- VMSTATE_UINT32_V(sys_cfgstat, arm_sysctl_state, 2),
- VMSTATE_UINT32_V(sys_clcd, arm_sysctl_state, 3),
- VMSTATE_UINT32_ARRAY_V(mb_clock, arm_sysctl_state, 6, 4),
- VMSTATE_VARRAY_UINT32(db_clock, arm_sysctl_state, db_num_clocks,
- 4, vmstate_info_uint32, uint32_t),
- VMSTATE_END_OF_LIST()
- }
-};
-
-/* The PB926 actually uses a different format for
- * its SYS_ID register. Fortunately the bits which are
- * board type on later boards are distinct.
- */
-#define BOARD_ID_PB926 0x100
-#define BOARD_ID_EB 0x140
-#define BOARD_ID_PBA8 0x178
-#define BOARD_ID_PBX 0x182
-#define BOARD_ID_VEXPRESS 0x190
-
-static int board_id(arm_sysctl_state *s)
-{
- /* Extract the board ID field from the SYS_ID register value */
- return (s->sys_id >> 16) & 0xfff;
-}
-
-static void arm_sysctl_reset(DeviceState *d)
-{
- arm_sysctl_state *s = ARM_SYSCTL(d);
- int i;
-
- s->leds = 0;
- s->lockval = 0;
- s->cfgdata1 = 0;
- s->cfgdata2 = 0;
- s->flags = 0;
- s->resetlevel = 0;
- /* Motherboard oscillators (in Hz) */
- s->mb_clock[0] = 50000000; /* Static memory clock: 50MHz */
- s->mb_clock[1] = 23750000; /* motherboard CLCD clock: 23.75MHz */
- s->mb_clock[2] = 24000000; /* IO FPGA peripheral clock: 24MHz */
- s->mb_clock[3] = 24000000; /* IO FPGA reserved clock: 24MHz */
- s->mb_clock[4] = 24000000; /* System bus global clock: 24MHz */
- s->mb_clock[5] = 24000000; /* IO FPGA reserved clock: 24MHz */
- /* Daughterboard oscillators: reset from property values */
- for (i = 0; i < s->db_num_clocks; i++) {
- s->db_clock[i] = s->db_clock_reset[i];
- }
- if (board_id(s) == BOARD_ID_VEXPRESS) {
- /* On VExpress this register will RAZ/WI */
- s->sys_clcd = 0;
- } else {
- /* All others: CLCDID 0x1f, indicating VGA */
- s->sys_clcd = 0x1f00;
- }
-}
-
-static uint64_t arm_sysctl_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- arm_sysctl_state *s = (arm_sysctl_state *)opaque;
-
- switch (offset) {
- case 0x00: /* ID */
- return s->sys_id;
- case 0x04: /* SW */
- /* General purpose hardware switches.
- We don't have a useful way of exposing these to the user. */
- return 0;
- case 0x08: /* LED */
- return s->leds;
- case 0x20: /* LOCK */
- return s->lockval;
- case 0x0c: /* OSC0 */
- case 0x10: /* OSC1 */
- case 0x14: /* OSC2 */
- case 0x18: /* OSC3 */
- case 0x1c: /* OSC4 */
- case 0x24: /* 100HZ */
- /* ??? Implement these. */
- return 0;
- case 0x28: /* CFGDATA1 */
- return s->cfgdata1;
- case 0x2c: /* CFGDATA2 */
- return s->cfgdata2;
- case 0x30: /* FLAGS */
- return s->flags;
- case 0x38: /* NVFLAGS */
- return s->nvflags;
- case 0x40: /* RESETCTL */
- if (board_id(s) == BOARD_ID_VEXPRESS) {
- /* reserved: RAZ/WI */
- return 0;
- }
- return s->resetlevel;
- case 0x44: /* PCICTL */
- return 1;
- case 0x48: /* MCI */
- return s->sys_mci;
- case 0x4c: /* FLASH */
- return 0;
- case 0x50: /* CLCD */
- return s->sys_clcd;
- case 0x54: /* CLCDSER */
- return 0;
- case 0x58: /* BOOTCS */
- return 0;
- case 0x5c: /* 24MHz */
- return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24000000,
- NANOSECONDS_PER_SECOND);
- case 0x60: /* MISC */
- return 0;
- case 0x84: /* PROCID0 */
- return s->proc_id;
- case 0x88: /* PROCID1 */
- return 0xff000000;
- case 0x64: /* DMAPSR0 */
- case 0x68: /* DMAPSR1 */
- case 0x6c: /* DMAPSR2 */
- case 0x70: /* IOSEL */
- case 0x74: /* PLDCTL */
- case 0x80: /* BUSID */
- case 0x8c: /* OSCRESET0 */
- case 0x90: /* OSCRESET1 */
- case 0x94: /* OSCRESET2 */
- case 0x98: /* OSCRESET3 */
- case 0x9c: /* OSCRESET4 */
- case 0xc0: /* SYS_TEST_OSC0 */
- case 0xc4: /* SYS_TEST_OSC1 */
- case 0xc8: /* SYS_TEST_OSC2 */
- case 0xcc: /* SYS_TEST_OSC3 */
- case 0xd0: /* SYS_TEST_OSC4 */
- return 0;
- case 0xa0: /* SYS_CFGDATA */
- if (board_id(s) != BOARD_ID_VEXPRESS) {
- goto bad_reg;
- }
- return s->sys_cfgdata;
- case 0xa4: /* SYS_CFGCTRL */
- if (board_id(s) != BOARD_ID_VEXPRESS) {
- goto bad_reg;
- }
- return s->sys_cfgctrl;
- case 0xa8: /* SYS_CFGSTAT */
- if (board_id(s) != BOARD_ID_VEXPRESS) {
- goto bad_reg;
- }
- return s->sys_cfgstat;
- default:
- bad_reg:
- qemu_log_mask(LOG_GUEST_ERROR,
- "arm_sysctl_read: Bad register offset 0x%x\n",
- (int)offset);
- return 0;
- }
-}
-
-/* SYS_CFGCTRL functions */
-#define SYS_CFG_OSC 1
-#define SYS_CFG_VOLT 2
-#define SYS_CFG_AMP 3
-#define SYS_CFG_TEMP 4
-#define SYS_CFG_RESET 5
-#define SYS_CFG_SCC 6
-#define SYS_CFG_MUXFPGA 7
-#define SYS_CFG_SHUTDOWN 8
-#define SYS_CFG_REBOOT 9
-#define SYS_CFG_DVIMODE 11
-#define SYS_CFG_POWER 12
-#define SYS_CFG_ENERGY 13
-
-/* SYS_CFGCTRL site field values */
-#define SYS_CFG_SITE_MB 0
-#define SYS_CFG_SITE_DB1 1
-#define SYS_CFG_SITE_DB2 2
-
-/**
- * vexpress_cfgctrl_read:
- * @s: arm_sysctl_state pointer
- * @dcc, @function, @site, @position, @device: split out values from
- * SYS_CFGCTRL register
- * @val: pointer to where to put the read data on success
- *
- * Handle a VExpress SYS_CFGCTRL register read. On success, return true and
- * write the read value to *val. On failure, return false (and val may
- * or may not be written to).
- */
-static bool vexpress_cfgctrl_read(arm_sysctl_state *s, unsigned int dcc,
- unsigned int function, unsigned int site,
- unsigned int position, unsigned int device,
- uint32_t *val)
-{
- /* We don't support anything other than DCC 0, board stack position 0
- * or sites other than motherboard/daughterboard:
- */
- if (dcc != 0 || position != 0 ||
- (site != SYS_CFG_SITE_MB && site != SYS_CFG_SITE_DB1)) {
- goto cfgctrl_unimp;
- }
-
- switch (function) {
- case SYS_CFG_VOLT:
- if (site == SYS_CFG_SITE_DB1 && device < s->db_num_vsensors) {
- *val = s->db_voltage[device];
- return true;
- }
- if (site == SYS_CFG_SITE_MB && device == 0) {
- /* There is only one motherboard voltage sensor:
- * VIO : 3.3V : bus voltage between mother and daughterboard
- */
- *val = 3300000;
- return true;
- }
- break;
- case SYS_CFG_OSC:
- if (site == SYS_CFG_SITE_MB && device < ARRAY_SIZE(s->mb_clock)) {
- /* motherboard clock */
- *val = s->mb_clock[device];
- return true;
- }
- if (site == SYS_CFG_SITE_DB1 && device < s->db_num_clocks) {
- /* daughterboard clock */
- *val = s->db_clock[device];
- return true;
- }
- break;
- default:
- break;
- }
-
-cfgctrl_unimp:
- qemu_log_mask(LOG_UNIMP,
- "arm_sysctl: Unimplemented SYS_CFGCTRL read of function "
- "0x%x DCC 0x%x site 0x%x position 0x%x device 0x%x\n",
- function, dcc, site, position, device);
- return false;
-}
-
-/**
- * vexpress_cfgctrl_write:
- * @s: arm_sysctl_state pointer
- * @dcc, @function, @site, @position, @device: split out values from
- * SYS_CFGCTRL register
- * @val: data to write
- *
- * Handle a VExpress SYS_CFGCTRL register write. On success, return true.
- * On failure, return false.
- */
-static bool vexpress_cfgctrl_write(arm_sysctl_state *s, unsigned int dcc,
- unsigned int function, unsigned int site,
- unsigned int position, unsigned int device,
- uint32_t val)
-{
- /* We don't support anything other than DCC 0, board stack position 0
- * or sites other than motherboard/daughterboard:
- */
- if (dcc != 0 || position != 0 ||
- (site != SYS_CFG_SITE_MB && site != SYS_CFG_SITE_DB1)) {
- goto cfgctrl_unimp;
- }
-
- switch (function) {
- case SYS_CFG_OSC:
- if (site == SYS_CFG_SITE_MB && device < ARRAY_SIZE(s->mb_clock)) {
- /* motherboard clock */
- s->mb_clock[device] = val;
- return true;
- }
- if (site == SYS_CFG_SITE_DB1 && device < s->db_num_clocks) {
- /* daughterboard clock */
- s->db_clock[device] = val;
- return true;
- }
- break;
- case SYS_CFG_MUXFPGA:
- if (site == SYS_CFG_SITE_MB && device == 0) {
- /* Select whether video output comes from motherboard
- * or daughterboard: log and ignore as QEMU doesn't
- * support this.
- */
- qemu_log_mask(LOG_UNIMP, "arm_sysctl: selection of video output "
- "not supported, ignoring\n");
- return true;
- }
- break;
- case SYS_CFG_SHUTDOWN:
- if (site == SYS_CFG_SITE_MB && device == 0) {
- qemu_system_shutdown_request();
- return true;
- }
- break;
- case SYS_CFG_REBOOT:
- if (site == SYS_CFG_SITE_MB && device == 0) {
- qemu_system_reset_request();
- return true;
- }
- break;
- case SYS_CFG_DVIMODE:
- if (site == SYS_CFG_SITE_MB && device == 0) {
- /* Selecting DVI mode is meaningless for QEMU: we will
- * always display the output correctly according to the
- * pixel height/width programmed into the CLCD controller.
- */
- return true;
- }
- default:
- break;
- }
-
-cfgctrl_unimp:
- qemu_log_mask(LOG_UNIMP,
- "arm_sysctl: Unimplemented SYS_CFGCTRL write of function "
- "0x%x DCC 0x%x site 0x%x position 0x%x device 0x%x\n",
- function, dcc, site, position, device);
- return false;
-}
-
-static void arm_sysctl_write(void *opaque, hwaddr offset,
- uint64_t val, unsigned size)
-{
- arm_sysctl_state *s = (arm_sysctl_state *)opaque;
-
- switch (offset) {
- case 0x08: /* LED */
- s->leds = val;
- break;
- case 0x0c: /* OSC0 */
- case 0x10: /* OSC1 */
- case 0x14: /* OSC2 */
- case 0x18: /* OSC3 */
- case 0x1c: /* OSC4 */
- /* ??? */
- break;
- case 0x20: /* LOCK */
- if (val == LOCK_VALUE)
- s->lockval = val;
- else
- s->lockval = val & 0x7fff;
- break;
- case 0x28: /* CFGDATA1 */
- /* ??? Need to implement this. */
- s->cfgdata1 = val;
- break;
- case 0x2c: /* CFGDATA2 */
- /* ??? Need to implement this. */
- s->cfgdata2 = val;
- break;
- case 0x30: /* FLAGSSET */
- s->flags |= val;
- break;
- case 0x34: /* FLAGSCLR */
- s->flags &= ~val;
- break;
- case 0x38: /* NVFLAGSSET */
- s->nvflags |= val;
- break;
- case 0x3c: /* NVFLAGSCLR */
- s->nvflags &= ~val;
- break;
- case 0x40: /* RESETCTL */
- switch (board_id(s)) {
- case BOARD_ID_PB926:
- if (s->lockval == LOCK_VALUE) {
- s->resetlevel = val;
- if (val & 0x100) {
- qemu_system_reset_request();
- }
- }
- break;
- case BOARD_ID_PBX:
- case BOARD_ID_PBA8:
- if (s->lockval == LOCK_VALUE) {
- s->resetlevel = val;
- if (val & 0x04) {
- qemu_system_reset_request();
- }
- }
- break;
- case BOARD_ID_VEXPRESS:
- case BOARD_ID_EB:
- default:
- /* reserved: RAZ/WI */
- break;
- }
- break;
- case 0x44: /* PCICTL */
- /* nothing to do. */
- break;
- case 0x4c: /* FLASH */
- break;
- case 0x50: /* CLCD */
- switch (board_id(s)) {
- case BOARD_ID_PB926:
- /* On 926 bits 13:8 are R/O, bits 1:0 control
- * the mux that defines how to interpret the PL110
- * graphics format, and other bits are r/w but we
- * don't implement them to do anything.
- */
- s->sys_clcd &= 0x3f00;
- s->sys_clcd |= val & ~0x3f00;
- qemu_set_irq(s->pl110_mux_ctrl, val & 3);
- break;
- case BOARD_ID_EB:
- /* The EB is the same except that there is no mux since
- * the EB has a PL111.
- */
- s->sys_clcd &= 0x3f00;
- s->sys_clcd |= val & ~0x3f00;
- break;
- case BOARD_ID_PBA8:
- case BOARD_ID_PBX:
- /* On PBA8 and PBX bit 7 is r/w and all other bits
- * are either r/o or RAZ/WI.
- */
- s->sys_clcd &= (1 << 7);
- s->sys_clcd |= val & ~(1 << 7);
- break;
- case BOARD_ID_VEXPRESS:
- default:
- /* On VExpress this register is unimplemented and will RAZ/WI */
- break;
- }
- break;
- case 0x54: /* CLCDSER */
- case 0x64: /* DMAPSR0 */
- case 0x68: /* DMAPSR1 */
- case 0x6c: /* DMAPSR2 */
- case 0x70: /* IOSEL */
- case 0x74: /* PLDCTL */
- case 0x80: /* BUSID */
- case 0x84: /* PROCID0 */
- case 0x88: /* PROCID1 */
- case 0x8c: /* OSCRESET0 */
- case 0x90: /* OSCRESET1 */
- case 0x94: /* OSCRESET2 */
- case 0x98: /* OSCRESET3 */
- case 0x9c: /* OSCRESET4 */
- break;
- case 0xa0: /* SYS_CFGDATA */
- if (board_id(s) != BOARD_ID_VEXPRESS) {
- goto bad_reg;
- }
- s->sys_cfgdata = val;
- return;
- case 0xa4: /* SYS_CFGCTRL */
- if (board_id(s) != BOARD_ID_VEXPRESS) {
- goto bad_reg;
- }
- /* Undefined bits [19:18] are RAZ/WI, and writing to
- * the start bit just triggers the action; it always reads
- * as zero.
- */
- s->sys_cfgctrl = val & ~((3 << 18) | (1 << 31));
- if (val & (1 << 31)) {
- /* Start bit set -- actually do something */
- unsigned int dcc = extract32(s->sys_cfgctrl, 26, 4);
- unsigned int function = extract32(s->sys_cfgctrl, 20, 6);
- unsigned int site = extract32(s->sys_cfgctrl, 16, 2);
- unsigned int position = extract32(s->sys_cfgctrl, 12, 4);
- unsigned int device = extract32(s->sys_cfgctrl, 0, 12);
- s->sys_cfgstat = 1; /* complete */
- if (s->sys_cfgctrl & (1 << 30)) {
- if (!vexpress_cfgctrl_write(s, dcc, function, site, position,
- device, s->sys_cfgdata)) {
- s->sys_cfgstat |= 2; /* error */
- }
- } else {
- uint32_t val;
- if (!vexpress_cfgctrl_read(s, dcc, function, site, position,
- device, &val)) {
- s->sys_cfgstat |= 2; /* error */
- } else {
- s->sys_cfgdata = val;
- }
- }
- }
- s->sys_cfgctrl &= ~(1 << 31);
- return;
- case 0xa8: /* SYS_CFGSTAT */
- if (board_id(s) != BOARD_ID_VEXPRESS) {
- goto bad_reg;
- }
- s->sys_cfgstat = val & 3;
- return;
- default:
- bad_reg:
- qemu_log_mask(LOG_GUEST_ERROR,
- "arm_sysctl_write: Bad register offset 0x%x\n",
- (int)offset);
- return;
- }
-}
-
-static const MemoryRegionOps arm_sysctl_ops = {
- .read = arm_sysctl_read,
- .write = arm_sysctl_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void arm_sysctl_gpio_set(void *opaque, int line, int level)
-{
- arm_sysctl_state *s = (arm_sysctl_state *)opaque;
- switch (line) {
- case ARM_SYSCTL_GPIO_MMC_WPROT:
- {
- /* For PB926 and EB write-protect is bit 2 of SYS_MCI;
- * for all later boards it is bit 1.
- */
- int bit = 2;
- if ((board_id(s) == BOARD_ID_PB926) || (board_id(s) == BOARD_ID_EB)) {
- bit = 4;
- }
- s->sys_mci &= ~bit;
- if (level) {
- s->sys_mci |= bit;
- }
- break;
- }
- case ARM_SYSCTL_GPIO_MMC_CARDIN:
- s->sys_mci &= ~1;
- if (level) {
- s->sys_mci |= 1;
- }
- break;
- }
-}
-
-static void arm_sysctl_init(Object *obj)
-{
- DeviceState *dev = DEVICE(obj);
- SysBusDevice *sd = SYS_BUS_DEVICE(obj);
- arm_sysctl_state *s = ARM_SYSCTL(obj);
-
- memory_region_init_io(&s->iomem, OBJECT(dev), &arm_sysctl_ops, s,
- "arm-sysctl", 0x1000);
- sysbus_init_mmio(sd, &s->iomem);
- qdev_init_gpio_in(dev, arm_sysctl_gpio_set, 2);
- qdev_init_gpio_out(dev, &s->pl110_mux_ctrl, 1);
-}
-
-static void arm_sysctl_realize(DeviceState *d, Error **errp)
-{
- arm_sysctl_state *s = ARM_SYSCTL(d);
-
- s->db_clock = g_new0(uint32_t, s->db_num_clocks);
-}
-
-static void arm_sysctl_finalize(Object *obj)
-{
- arm_sysctl_state *s = ARM_SYSCTL(obj);
-
- g_free(s->db_voltage);
- g_free(s->db_clock);
- g_free(s->db_clock_reset);
-}
-
-static Property arm_sysctl_properties[] = {
- DEFINE_PROP_UINT32("sys_id", arm_sysctl_state, sys_id, 0),
- DEFINE_PROP_UINT32("proc_id", arm_sysctl_state, proc_id, 0),
- /* Daughterboard power supply voltages (as reported via SYS_CFG) */
- DEFINE_PROP_ARRAY("db-voltage", arm_sysctl_state, db_num_vsensors,
- db_voltage, qdev_prop_uint32, uint32_t),
- /* Daughterboard clock reset values (as reported via SYS_CFG) */
- DEFINE_PROP_ARRAY("db-clock", arm_sysctl_state, db_num_clocks,
- db_clock_reset, qdev_prop_uint32, uint32_t),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void arm_sysctl_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = arm_sysctl_realize;
- dc->reset = arm_sysctl_reset;
- dc->vmsd = &vmstate_arm_sysctl;
- dc->props = arm_sysctl_properties;
-}
-
-static const TypeInfo arm_sysctl_info = {
- .name = TYPE_ARM_SYSCTL,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(arm_sysctl_state),
- .instance_init = arm_sysctl_init,
- .instance_finalize = arm_sysctl_finalize,
- .class_init = arm_sysctl_class_init,
-};
-
-static void arm_sysctl_register_types(void)
-{
- type_register_static(&arm_sysctl_info);
-}
-
-type_init(arm_sysctl_register_types)
diff --git a/qemu/hw/misc/bcm2835_mbox.c b/qemu/hw/misc/bcm2835_mbox.c
deleted file mode 100644
index 263280fd4..000000000
--- a/qemu/hw/misc/bcm2835_mbox.c
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * Raspberry Pi emulation (c) 2012 Gregory Estrade
- * This code is licensed under the GNU GPLv2 and later.
- *
- * This file models the system mailboxes, which are used for
- * communication with low-bandwidth GPU peripherals. Refs:
- * https://github.com/raspberrypi/firmware/wiki/Mailboxes
- * https://github.com/raspberrypi/firmware/wiki/Accessing-mailboxes
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/misc/bcm2835_mbox.h"
-
-#define MAIL0_PEEK 0x90
-#define MAIL0_SENDER 0x94
-#define MAIL1_STATUS 0xb8
-
-/* Mailbox status register */
-#define MAIL0_STATUS 0x98
-#define ARM_MS_FULL 0x80000000
-#define ARM_MS_EMPTY 0x40000000
-#define ARM_MS_LEVEL 0x400000FF /* Max. value depends on mailbox depth */
-
-/* MAILBOX config/status register */
-#define MAIL0_CONFIG 0x9c
-/* ANY write to this register clears the error bits! */
-#define ARM_MC_IHAVEDATAIRQEN 0x00000001 /* mbox irq enable: has data */
-#define ARM_MC_IHAVESPACEIRQEN 0x00000002 /* mbox irq enable: has space */
-#define ARM_MC_OPPISEMPTYIRQEN 0x00000004 /* mbox irq enable: Opp is empty */
-#define ARM_MC_MAIL_CLEAR 0x00000008 /* mbox clear write 1, then 0 */
-#define ARM_MC_IHAVEDATAIRQPEND 0x00000010 /* mbox irq pending: has space */
-#define ARM_MC_IHAVESPACEIRQPEND 0x00000020 /* mbox irq pending: Opp is empty */
-#define ARM_MC_OPPISEMPTYIRQPEND 0x00000040 /* mbox irq pending */
-/* Bit 7 is unused */
-#define ARM_MC_ERRNOOWN 0x00000100 /* error : none owner read from mailbox */
-#define ARM_MC_ERROVERFLW 0x00000200 /* error : write to fill mailbox */
-#define ARM_MC_ERRUNDRFLW 0x00000400 /* error : read from empty mailbox */
-
-static void mbox_update_status(BCM2835Mbox *mb)
-{
- mb->status &= ~(ARM_MS_EMPTY | ARM_MS_FULL);
- if (mb->count == 0) {
- mb->status |= ARM_MS_EMPTY;
- } else if (mb->count == MBOX_SIZE) {
- mb->status |= ARM_MS_FULL;
- }
-}
-
-static void mbox_reset(BCM2835Mbox *mb)
-{
- int n;
-
- mb->count = 0;
- mb->config = 0;
- for (n = 0; n < MBOX_SIZE; n++) {
- mb->reg[n] = MBOX_INVALID_DATA;
- }
- mbox_update_status(mb);
-}
-
-static uint32_t mbox_pull(BCM2835Mbox *mb, int index)
-{
- int n;
- uint32_t val;
-
- assert(mb->count > 0);
- assert(index < mb->count);
-
- val = mb->reg[index];
- for (n = index + 1; n < mb->count; n++) {
- mb->reg[n - 1] = mb->reg[n];
- }
- mb->count--;
- mb->reg[mb->count] = MBOX_INVALID_DATA;
-
- mbox_update_status(mb);
-
- return val;
-}
-
-static void mbox_push(BCM2835Mbox *mb, uint32_t val)
-{
- assert(mb->count < MBOX_SIZE);
- mb->reg[mb->count++] = val;
- mbox_update_status(mb);
-}
-
-static void bcm2835_mbox_update(BCM2835MboxState *s)
-{
- uint32_t value;
- bool set;
- int n;
-
- s->mbox_irq_disabled = true;
-
- /* Get pending responses and put them in the vc->arm mbox,
- * as long as it's not full
- */
- for (n = 0; n < MBOX_CHAN_COUNT; n++) {
- while (s->available[n] && !(s->mbox[0].status & ARM_MS_FULL)) {
- value = ldl_le_phys(&s->mbox_as, n << MBOX_AS_CHAN_SHIFT);
- assert(value != MBOX_INVALID_DATA); /* Pending interrupt but no data */
- mbox_push(&s->mbox[0], value);
- }
- }
-
- /* TODO (?): Try to push pending requests from the arm->vc mbox */
-
- /* Re-enable calls from the IRQ routine */
- s->mbox_irq_disabled = false;
-
- /* Update ARM IRQ status */
- set = false;
- s->mbox[0].config &= ~ARM_MC_IHAVEDATAIRQPEND;
- if (!(s->mbox[0].status & ARM_MS_EMPTY)) {
- s->mbox[0].config |= ARM_MC_IHAVEDATAIRQPEND;
- if (s->mbox[0].config & ARM_MC_IHAVEDATAIRQEN) {
- set = true;
- }
- }
- qemu_set_irq(s->arm_irq, set);
-}
-
-static void bcm2835_mbox_set_irq(void *opaque, int irq, int level)
-{
- BCM2835MboxState *s = opaque;
-
- s->available[irq] = level;
-
- /* avoid recursively calling bcm2835_mbox_update when the interrupt
- * status changes due to the ldl_phys call within that function
- */
- if (!s->mbox_irq_disabled) {
- bcm2835_mbox_update(s);
- }
-}
-
-static uint64_t bcm2835_mbox_read(void *opaque, hwaddr offset, unsigned size)
-{
- BCM2835MboxState *s = opaque;
- uint32_t res = 0;
-
- offset &= 0xff;
-
- switch (offset) {
- case 0x80 ... 0x8c: /* MAIL0_READ */
- if (s->mbox[0].status & ARM_MS_EMPTY) {
- res = MBOX_INVALID_DATA;
- } else {
- res = mbox_pull(&s->mbox[0], 0);
- }
- break;
-
- case MAIL0_PEEK:
- res = s->mbox[0].reg[0];
- break;
-
- case MAIL0_SENDER:
- break;
-
- case MAIL0_STATUS:
- res = s->mbox[0].status;
- break;
-
- case MAIL0_CONFIG:
- res = s->mbox[0].config;
- break;
-
- case MAIL1_STATUS:
- res = s->mbox[1].status;
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
- __func__, offset);
- return 0;
- }
-
- bcm2835_mbox_update(s);
-
- return res;
-}
-
-static void bcm2835_mbox_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- BCM2835MboxState *s = opaque;
- hwaddr childaddr;
- uint8_t ch;
-
- offset &= 0xff;
-
- switch (offset) {
- case MAIL0_SENDER:
- break;
-
- case MAIL0_CONFIG:
- s->mbox[0].config &= ~ARM_MC_IHAVEDATAIRQEN;
- s->mbox[0].config |= value & ARM_MC_IHAVEDATAIRQEN;
- break;
-
- case 0xa0 ... 0xac: /* MAIL1_WRITE */
- if (s->mbox[1].status & ARM_MS_FULL) {
- /* Mailbox full */
- qemu_log_mask(LOG_GUEST_ERROR, "%s: mailbox full\n", __func__);
- } else {
- ch = value & 0xf;
- if (ch < MBOX_CHAN_COUNT) {
- childaddr = ch << MBOX_AS_CHAN_SHIFT;
- if (ldl_le_phys(&s->mbox_as, childaddr + MBOX_AS_PENDING)) {
- /* Child busy, push delayed. Push it in the arm->vc mbox */
- mbox_push(&s->mbox[1], value);
- } else {
- /* Push it directly to the child device */
- stl_le_phys(&s->mbox_as, childaddr, value);
- }
- } else {
- /* Invalid channel number */
- qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid channel %u\n",
- __func__, ch);
- }
- }
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
- __func__, offset);
- return;
- }
-
- bcm2835_mbox_update(s);
-}
-
-static const MemoryRegionOps bcm2835_mbox_ops = {
- .read = bcm2835_mbox_read,
- .write = bcm2835_mbox_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid.min_access_size = 4,
- .valid.max_access_size = 4,
-};
-
-/* vmstate of a single mailbox */
-static const VMStateDescription vmstate_bcm2835_mbox_box = {
- .name = TYPE_BCM2835_MBOX "_box",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(reg, BCM2835Mbox, MBOX_SIZE),
- VMSTATE_UINT32(count, BCM2835Mbox),
- VMSTATE_UINT32(status, BCM2835Mbox),
- VMSTATE_UINT32(config, BCM2835Mbox),
- VMSTATE_END_OF_LIST()
- }
-};
-
-/* vmstate of the entire device */
-static const VMStateDescription vmstate_bcm2835_mbox = {
- .name = TYPE_BCM2835_MBOX,
- .version_id = 1,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .fields = (VMStateField[]) {
- VMSTATE_BOOL_ARRAY(available, BCM2835MboxState, MBOX_CHAN_COUNT),
- VMSTATE_STRUCT_ARRAY(mbox, BCM2835MboxState, 2, 1,
- vmstate_bcm2835_mbox_box, BCM2835Mbox),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void bcm2835_mbox_init(Object *obj)
-{
- BCM2835MboxState *s = BCM2835_MBOX(obj);
-
- memory_region_init_io(&s->iomem, obj, &bcm2835_mbox_ops, s,
- TYPE_BCM2835_MBOX, 0x400);
- sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
- sysbus_init_irq(SYS_BUS_DEVICE(s), &s->arm_irq);
- qdev_init_gpio_in(DEVICE(s), bcm2835_mbox_set_irq, MBOX_CHAN_COUNT);
-}
-
-static void bcm2835_mbox_reset(DeviceState *dev)
-{
- BCM2835MboxState *s = BCM2835_MBOX(dev);
- int n;
-
- mbox_reset(&s->mbox[0]);
- mbox_reset(&s->mbox[1]);
- s->mbox_irq_disabled = false;
- for (n = 0; n < MBOX_CHAN_COUNT; n++) {
- s->available[n] = false;
- }
-}
-
-static void bcm2835_mbox_realize(DeviceState *dev, Error **errp)
-{
- BCM2835MboxState *s = BCM2835_MBOX(dev);
- Object *obj;
- Error *err = NULL;
-
- obj = object_property_get_link(OBJECT(dev), "mbox-mr", &err);
- if (obj == NULL) {
- error_setg(errp, "%s: required mbox-mr link not found: %s",
- __func__, error_get_pretty(err));
- return;
- }
-
- s->mbox_mr = MEMORY_REGION(obj);
- address_space_init(&s->mbox_as, s->mbox_mr, NULL);
- bcm2835_mbox_reset(dev);
-}
-
-static void bcm2835_mbox_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = bcm2835_mbox_realize;
- dc->reset = bcm2835_mbox_reset;
- dc->vmsd = &vmstate_bcm2835_mbox;
-}
-
-static TypeInfo bcm2835_mbox_info = {
- .name = TYPE_BCM2835_MBOX,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(BCM2835MboxState),
- .class_init = bcm2835_mbox_class_init,
- .instance_init = bcm2835_mbox_init,
-};
-
-static void bcm2835_mbox_register_types(void)
-{
- type_register_static(&bcm2835_mbox_info);
-}
-
-type_init(bcm2835_mbox_register_types)
diff --git a/qemu/hw/misc/bcm2835_property.c b/qemu/hw/misc/bcm2835_property.c
deleted file mode 100644
index 530411f84..000000000
--- a/qemu/hw/misc/bcm2835_property.c
+++ /dev/null
@@ -1,424 +0,0 @@
-/*
- * Raspberry Pi emulation (c) 2012 Gregory Estrade
- * This code is licensed under the GNU GPLv2 and later.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/misc/bcm2835_property.h"
-#include "hw/misc/bcm2835_mbox_defs.h"
-#include "sysemu/dma.h"
-
-/* https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface */
-
-static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
-{
- uint32_t tag;
- uint32_t bufsize;
- uint32_t tot_len;
- size_t resplen;
- uint32_t tmp;
- int n;
- uint32_t offset, length, color;
- uint32_t xres, yres, xoffset, yoffset, bpp, pixo, alpha;
- uint32_t *newxres = NULL, *newyres = NULL, *newxoffset = NULL,
- *newyoffset = NULL, *newbpp = NULL, *newpixo = NULL, *newalpha = NULL;
-
- value &= ~0xf;
-
- s->addr = value;
-
- tot_len = ldl_le_phys(&s->dma_as, value);
-
- /* @(addr + 4) : Buffer response code */
- value = s->addr + 8;
- while (value + 8 <= s->addr + tot_len) {
- tag = ldl_le_phys(&s->dma_as, value);
- bufsize = ldl_le_phys(&s->dma_as, value + 4);
- /* @(value + 8) : Request/response indicator */
- resplen = 0;
- switch (tag) {
- case 0x00000000: /* End tag */
- break;
- case 0x00000001: /* Get firmware revision */
- stl_le_phys(&s->dma_as, value + 12, 346337);
- resplen = 4;
- break;
- case 0x00010001: /* Get board model */
- qemu_log_mask(LOG_UNIMP,
- "bcm2835_property: %x get board model NYI\n", tag);
- resplen = 4;
- break;
- case 0x00010002: /* Get board revision */
- stl_le_phys(&s->dma_as, value + 12, s->board_rev);
- resplen = 4;
- break;
- case 0x00010003: /* Get board MAC address */
- resplen = sizeof(s->macaddr.a);
- dma_memory_write(&s->dma_as, value + 12, s->macaddr.a, resplen);
- break;
- case 0x00010004: /* Get board serial */
- qemu_log_mask(LOG_UNIMP,
- "bcm2835_property: %x get board serial NYI\n", tag);
- resplen = 8;
- break;
- case 0x00010005: /* Get ARM memory */
- /* base */
- stl_le_phys(&s->dma_as, value + 12, 0);
- /* size */
- stl_le_phys(&s->dma_as, value + 16, s->fbdev->vcram_base);
- resplen = 8;
- break;
- case 0x00010006: /* Get VC memory */
- /* base */
- stl_le_phys(&s->dma_as, value + 12, s->fbdev->vcram_base);
- /* size */
- stl_le_phys(&s->dma_as, value + 16, s->fbdev->vcram_size);
- resplen = 8;
- break;
- case 0x00028001: /* Set power state */
- /* Assume that whatever device they asked for exists,
- * and we'll just claim we set it to the desired state
- */
- tmp = ldl_le_phys(&s->dma_as, value + 16);
- stl_le_phys(&s->dma_as, value + 16, (tmp & 1));
- resplen = 8;
- break;
-
- /* Clocks */
-
- case 0x00030001: /* Get clock state */
- stl_le_phys(&s->dma_as, value + 16, 0x1);
- resplen = 8;
- break;
-
- case 0x00038001: /* Set clock state */
- qemu_log_mask(LOG_UNIMP,
- "bcm2835_property: %x set clock state NYI\n", tag);
- resplen = 8;
- break;
-
- case 0x00030002: /* Get clock rate */
- case 0x00030004: /* Get max clock rate */
- case 0x00030007: /* Get min clock rate */
- switch (ldl_le_phys(&s->dma_as, value + 12)) {
- case 1: /* EMMC */
- stl_le_phys(&s->dma_as, value + 16, 50000000);
- break;
- case 2: /* UART */
- stl_le_phys(&s->dma_as, value + 16, 3000000);
- break;
- default:
- stl_le_phys(&s->dma_as, value + 16, 700000000);
- break;
- }
- resplen = 8;
- break;
-
- case 0x00038002: /* Set clock rate */
- case 0x00038004: /* Set max clock rate */
- case 0x00038007: /* Set min clock rate */
- qemu_log_mask(LOG_UNIMP,
- "bcm2835_property: %x set clock rates NYI\n", tag);
- resplen = 8;
- break;
-
- /* Temperature */
-
- case 0x00030006: /* Get temperature */
- stl_le_phys(&s->dma_as, value + 16, 25000);
- resplen = 8;
- break;
-
- case 0x0003000A: /* Get max temperature */
- stl_le_phys(&s->dma_as, value + 16, 99000);
- resplen = 8;
- break;
-
- /* Frame buffer */
-
- case 0x00040001: /* Allocate buffer */
- stl_le_phys(&s->dma_as, value + 12, s->fbdev->base);
- stl_le_phys(&s->dma_as, value + 16, s->fbdev->size);
- resplen = 8;
- break;
- case 0x00048001: /* Release buffer */
- resplen = 0;
- break;
- case 0x00040002: /* Blank screen */
- resplen = 4;
- break;
- case 0x00040003: /* Get display width/height */
- case 0x00040004:
- stl_le_phys(&s->dma_as, value + 12, s->fbdev->xres);
- stl_le_phys(&s->dma_as, value + 16, s->fbdev->yres);
- resplen = 8;
- break;
- case 0x00044003: /* Test display width/height */
- case 0x00044004:
- resplen = 8;
- break;
- case 0x00048003: /* Set display width/height */
- case 0x00048004:
- xres = ldl_le_phys(&s->dma_as, value + 12);
- newxres = &xres;
- yres = ldl_le_phys(&s->dma_as, value + 16);
- newyres = &yres;
- resplen = 8;
- break;
- case 0x00040005: /* Get depth */
- stl_le_phys(&s->dma_as, value + 12, s->fbdev->bpp);
- resplen = 4;
- break;
- case 0x00044005: /* Test depth */
- resplen = 4;
- break;
- case 0x00048005: /* Set depth */
- bpp = ldl_le_phys(&s->dma_as, value + 12);
- newbpp = &bpp;
- resplen = 4;
- break;
- case 0x00040006: /* Get pixel order */
- stl_le_phys(&s->dma_as, value + 12, s->fbdev->pixo);
- resplen = 4;
- break;
- case 0x00044006: /* Test pixel order */
- resplen = 4;
- break;
- case 0x00048006: /* Set pixel order */
- pixo = ldl_le_phys(&s->dma_as, value + 12);
- newpixo = &pixo;
- resplen = 4;
- break;
- case 0x00040007: /* Get alpha */
- stl_le_phys(&s->dma_as, value + 12, s->fbdev->alpha);
- resplen = 4;
- break;
- case 0x00044007: /* Test pixel alpha */
- resplen = 4;
- break;
- case 0x00048007: /* Set alpha */
- alpha = ldl_le_phys(&s->dma_as, value + 12);
- newalpha = &alpha;
- resplen = 4;
- break;
- case 0x00040008: /* Get pitch */
- stl_le_phys(&s->dma_as, value + 12, s->fbdev->pitch);
- resplen = 4;
- break;
- case 0x00040009: /* Get virtual offset */
- stl_le_phys(&s->dma_as, value + 12, s->fbdev->xoffset);
- stl_le_phys(&s->dma_as, value + 16, s->fbdev->yoffset);
- resplen = 8;
- break;
- case 0x00044009: /* Test virtual offset */
- resplen = 8;
- break;
- case 0x00048009: /* Set virtual offset */
- xoffset = ldl_le_phys(&s->dma_as, value + 12);
- newxoffset = &xoffset;
- yoffset = ldl_le_phys(&s->dma_as, value + 16);
- newyoffset = &yoffset;
- resplen = 8;
- break;
- case 0x0004000a: /* Get/Test/Set overscan */
- case 0x0004400a:
- case 0x0004800a:
- stl_le_phys(&s->dma_as, value + 12, 0);
- stl_le_phys(&s->dma_as, value + 16, 0);
- stl_le_phys(&s->dma_as, value + 20, 0);
- stl_le_phys(&s->dma_as, value + 24, 0);
- resplen = 16;
- break;
- case 0x0004800b: /* Set palette */
- offset = ldl_le_phys(&s->dma_as, value + 12);
- length = ldl_le_phys(&s->dma_as, value + 16);
- n = 0;
- while (n < length - offset) {
- color = ldl_le_phys(&s->dma_as, value + 20 + (n << 2));
- stl_le_phys(&s->dma_as,
- s->fbdev->vcram_base + ((offset + n) << 2), color);
- n++;
- }
- stl_le_phys(&s->dma_as, value + 12, 0);
- resplen = 4;
- break;
-
- case 0x00060001: /* Get DMA channels */
- /* channels 2-5 */
- stl_le_phys(&s->dma_as, value + 12, 0x003C);
- resplen = 4;
- break;
-
- case 0x00050001: /* Get command line */
- resplen = 0;
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "bcm2835_property: unhandled tag %08x\n", tag);
- break;
- }
-
- if (tag == 0) {
- break;
- }
-
- stl_le_phys(&s->dma_as, value + 8, (1 << 31) | resplen);
- value += bufsize + 12;
- }
-
- /* Reconfigure framebuffer if required */
- if (newxres || newyres || newxoffset || newyoffset || newbpp || newpixo
- || newalpha) {
- bcm2835_fb_reconfigure(s->fbdev, newxres, newyres, newxoffset,
- newyoffset, newbpp, newpixo, newalpha);
- }
-
- /* Buffer response code */
- stl_le_phys(&s->dma_as, s->addr + 4, (1 << 31));
-}
-
-static uint64_t bcm2835_property_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- BCM2835PropertyState *s = opaque;
- uint32_t res = 0;
-
- switch (offset) {
- case MBOX_AS_DATA:
- res = MBOX_CHAN_PROPERTY | s->addr;
- s->pending = false;
- qemu_set_irq(s->mbox_irq, 0);
- break;
-
- case MBOX_AS_PENDING:
- res = s->pending;
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
- __func__, offset);
- return 0;
- }
-
- return res;
-}
-
-static void bcm2835_property_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- BCM2835PropertyState *s = opaque;
-
- switch (offset) {
- case MBOX_AS_DATA:
- /* bcm2835_mbox should check our pending status before pushing */
- assert(!s->pending);
- s->pending = true;
- bcm2835_property_mbox_push(s, value);
- qemu_set_irq(s->mbox_irq, 1);
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
- __func__, offset);
- return;
- }
-}
-
-static const MemoryRegionOps bcm2835_property_ops = {
- .read = bcm2835_property_read,
- .write = bcm2835_property_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid.min_access_size = 4,
- .valid.max_access_size = 4,
-};
-
-static const VMStateDescription vmstate_bcm2835_property = {
- .name = TYPE_BCM2835_PROPERTY,
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_MACADDR(macaddr, BCM2835PropertyState),
- VMSTATE_UINT32(addr, BCM2835PropertyState),
- VMSTATE_BOOL(pending, BCM2835PropertyState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void bcm2835_property_init(Object *obj)
-{
- BCM2835PropertyState *s = BCM2835_PROPERTY(obj);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_property_ops, s,
- TYPE_BCM2835_PROPERTY, 0x10);
- sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
- sysbus_init_irq(SYS_BUS_DEVICE(s), &s->mbox_irq);
-}
-
-static void bcm2835_property_reset(DeviceState *dev)
-{
- BCM2835PropertyState *s = BCM2835_PROPERTY(dev);
-
- s->pending = false;
-}
-
-static void bcm2835_property_realize(DeviceState *dev, Error **errp)
-{
- BCM2835PropertyState *s = BCM2835_PROPERTY(dev);
- Object *obj;
- Error *err = NULL;
-
- obj = object_property_get_link(OBJECT(dev), "fb", &err);
- if (obj == NULL) {
- error_setg(errp, "%s: required fb link not found: %s",
- __func__, error_get_pretty(err));
- return;
- }
-
- s->fbdev = BCM2835_FB(obj);
-
- obj = object_property_get_link(OBJECT(dev), "dma-mr", &err);
- if (obj == NULL) {
- error_setg(errp, "%s: required dma-mr link not found: %s",
- __func__, error_get_pretty(err));
- return;
- }
-
- s->dma_mr = MEMORY_REGION(obj);
- address_space_init(&s->dma_as, s->dma_mr, NULL);
-
- /* TODO: connect to MAC address of USB NIC device, once we emulate it */
- qemu_macaddr_default_if_unset(&s->macaddr);
-
- bcm2835_property_reset(dev);
-}
-
-static Property bcm2835_property_props[] = {
- DEFINE_PROP_UINT32("board-rev", BCM2835PropertyState, board_rev, 0),
- DEFINE_PROP_END_OF_LIST()
-};
-
-static void bcm2835_property_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->props = bcm2835_property_props;
- dc->realize = bcm2835_property_realize;
- dc->vmsd = &vmstate_bcm2835_property;
-}
-
-static TypeInfo bcm2835_property_info = {
- .name = TYPE_BCM2835_PROPERTY,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(BCM2835PropertyState),
- .class_init = bcm2835_property_class_init,
- .instance_init = bcm2835_property_init,
-};
-
-static void bcm2835_property_register_types(void)
-{
- type_register_static(&bcm2835_property_info);
-}
-
-type_init(bcm2835_property_register_types)
diff --git a/qemu/hw/misc/cbus.c b/qemu/hw/misc/cbus.c
deleted file mode 100644
index 0c207e310..000000000
--- a/qemu/hw/misc/cbus.c
+++ /dev/null
@@ -1,619 +0,0 @@
-/*
- * CBUS three-pin bus and the Retu / Betty / Tahvo / Vilma / Avilma /
- * Hinku / Vinku / Ahne / Pihi chips used in various Nokia platforms.
- * Based on reverse-engineering of a linux driver.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/irq.h"
-#include "hw/devices.h"
-#include "sysemu/sysemu.h"
-
-//#define DEBUG
-
-typedef struct {
- void *opaque;
- void (*io)(void *opaque, int rw, int reg, uint16_t *val);
- int addr;
-} CBusSlave;
-
-typedef struct {
- CBus cbus;
-
- int sel;
- int dat;
- int clk;
- int bit;
- int dir;
- uint16_t val;
- qemu_irq dat_out;
-
- int addr;
- int reg;
- int rw;
- enum {
- cbus_address,
- cbus_value,
- } cycle;
-
- CBusSlave *slave[8];
-} CBusPriv;
-
-static void cbus_io(CBusPriv *s)
-{
- if (s->slave[s->addr])
- s->slave[s->addr]->io(s->slave[s->addr]->opaque,
- s->rw, s->reg, &s->val);
- else
- hw_error("%s: bad slave address %i\n", __FUNCTION__, s->addr);
-}
-
-static void cbus_cycle(CBusPriv *s)
-{
- switch (s->cycle) {
- case cbus_address:
- s->addr = (s->val >> 6) & 7;
- s->rw = (s->val >> 5) & 1;
- s->reg = (s->val >> 0) & 0x1f;
-
- s->cycle = cbus_value;
- s->bit = 15;
- s->dir = !s->rw;
- s->val = 0;
-
- if (s->rw)
- cbus_io(s);
- break;
-
- case cbus_value:
- if (!s->rw)
- cbus_io(s);
-
- s->cycle = cbus_address;
- s->bit = 8;
- s->dir = 1;
- s->val = 0;
- break;
- }
-}
-
-static void cbus_clk(void *opaque, int line, int level)
-{
- CBusPriv *s = (CBusPriv *) opaque;
-
- if (!s->sel && level && !s->clk) {
- if (s->dir)
- s->val |= s->dat << (s->bit --);
- else
- qemu_set_irq(s->dat_out, (s->val >> (s->bit --)) & 1);
-
- if (s->bit < 0)
- cbus_cycle(s);
- }
-
- s->clk = level;
-}
-
-static void cbus_dat(void *opaque, int line, int level)
-{
- CBusPriv *s = (CBusPriv *) opaque;
-
- s->dat = level;
-}
-
-static void cbus_sel(void *opaque, int line, int level)
-{
- CBusPriv *s = (CBusPriv *) opaque;
-
- if (!level) {
- s->dir = 1;
- s->bit = 8;
- s->val = 0;
- }
-
- s->sel = level;
-}
-
-CBus *cbus_init(qemu_irq dat)
-{
- CBusPriv *s = (CBusPriv *) g_malloc0(sizeof(*s));
-
- s->dat_out = dat;
- s->cbus.clk = qemu_allocate_irq(cbus_clk, s, 0);
- s->cbus.dat = qemu_allocate_irq(cbus_dat, s, 0);
- s->cbus.sel = qemu_allocate_irq(cbus_sel, s, 0);
-
- s->sel = 1;
- s->clk = 0;
- s->dat = 0;
-
- return &s->cbus;
-}
-
-void cbus_attach(CBus *bus, void *slave_opaque)
-{
- CBusSlave *slave = (CBusSlave *) slave_opaque;
- CBusPriv *s = (CBusPriv *) bus;
-
- s->slave[slave->addr] = slave;
-}
-
-/* Retu/Vilma */
-typedef struct {
- uint16_t irqst;
- uint16_t irqen;
- uint16_t cc[2];
- int channel;
- uint16_t result[16];
- uint16_t sample;
- uint16_t status;
-
- struct {
- uint16_t cal;
- } rtc;
-
- int is_vilma;
- qemu_irq irq;
- CBusSlave cbus;
-} CBusRetu;
-
-static void retu_interrupt_update(CBusRetu *s)
-{
- qemu_set_irq(s->irq, s->irqst & ~s->irqen);
-}
-
-#define RETU_REG_ASICR 0x00 /* (RO) ASIC ID & revision */
-#define RETU_REG_IDR 0x01 /* (T) Interrupt ID */
-#define RETU_REG_IMR 0x02 /* (RW) Interrupt mask */
-#define RETU_REG_RTCDSR 0x03 /* (RW) RTC seconds register */
-#define RETU_REG_RTCHMR 0x04 /* (RO) RTC hours and minutes reg */
-#define RETU_REG_RTCHMAR 0x05 /* (RW) RTC hours and minutes set reg */
-#define RETU_REG_RTCCALR 0x06 /* (RW) RTC calibration register */
-#define RETU_REG_ADCR 0x08 /* (RW) ADC result register */
-#define RETU_REG_ADCSCR 0x09 /* (RW) ADC sample control register */
-#define RETU_REG_AFCR 0x0a /* (RW) AFC register */
-#define RETU_REG_ANTIFR 0x0b /* (RW) AntiF register */
-#define RETU_REG_CALIBR 0x0c /* (RW) CalibR register*/
-#define RETU_REG_CCR1 0x0d /* (RW) Common control register 1 */
-#define RETU_REG_CCR2 0x0e /* (RW) Common control register 2 */
-#define RETU_REG_RCTRL_CLR 0x0f /* (T) Regulator clear register */
-#define RETU_REG_RCTRL_SET 0x10 /* (T) Regulator set register */
-#define RETU_REG_TXCR 0x11 /* (RW) TxC register */
-#define RETU_REG_STATUS 0x16 /* (RO) Status register */
-#define RETU_REG_WATCHDOG 0x17 /* (RW) Watchdog register */
-#define RETU_REG_AUDTXR 0x18 /* (RW) Audio Codec Tx register */
-#define RETU_REG_AUDPAR 0x19 /* (RW) AudioPA register */
-#define RETU_REG_AUDRXR1 0x1a /* (RW) Audio receive register 1 */
-#define RETU_REG_AUDRXR2 0x1b /* (RW) Audio receive register 2 */
-#define RETU_REG_SGR1 0x1c /* (RW) */
-#define RETU_REG_SCR1 0x1d /* (RW) */
-#define RETU_REG_SGR2 0x1e /* (RW) */
-#define RETU_REG_SCR2 0x1f /* (RW) */
-
-/* Retu Interrupt sources */
-enum {
- retu_int_pwr = 0, /* Power button */
- retu_int_char = 1, /* Charger */
- retu_int_rtcs = 2, /* Seconds */
- retu_int_rtcm = 3, /* Minutes */
- retu_int_rtcd = 4, /* Days */
- retu_int_rtca = 5, /* Alarm */
- retu_int_hook = 6, /* Hook */
- retu_int_head = 7, /* Headset */
- retu_int_adcs = 8, /* ADC sample */
-};
-
-/* Retu ADC channel wiring */
-enum {
- retu_adc_bsi = 1, /* BSI */
- retu_adc_batt_temp = 2, /* Battery temperature */
- retu_adc_chg_volt = 3, /* Charger voltage */
- retu_adc_head_det = 4, /* Headset detection */
- retu_adc_hook_det = 5, /* Hook detection */
- retu_adc_rf_gp = 6, /* RF GP */
- retu_adc_tx_det = 7, /* Wideband Tx detection */
- retu_adc_batt_volt = 8, /* Battery voltage */
- retu_adc_sens = 10, /* Light sensor */
- retu_adc_sens_temp = 11, /* Light sensor temperature */
- retu_adc_bbatt_volt = 12, /* Backup battery voltage */
- retu_adc_self_temp = 13, /* RETU temperature */
-};
-
-static inline uint16_t retu_read(CBusRetu *s, int reg)
-{
-#ifdef DEBUG
- printf("RETU read at %02x\n", reg);
-#endif
-
- switch (reg) {
- case RETU_REG_ASICR:
- return 0x0215 | (s->is_vilma << 7);
-
- case RETU_REG_IDR: /* TODO: Or is this ffs(s->irqst)? */
- return s->irqst;
-
- case RETU_REG_IMR:
- return s->irqen;
-
- case RETU_REG_RTCDSR:
- case RETU_REG_RTCHMR:
- case RETU_REG_RTCHMAR:
- /* TODO */
- return 0x0000;
-
- case RETU_REG_RTCCALR:
- return s->rtc.cal;
-
- case RETU_REG_ADCR:
- return (s->channel << 10) | s->result[s->channel];
- case RETU_REG_ADCSCR:
- return s->sample;
-
- case RETU_REG_AFCR:
- case RETU_REG_ANTIFR:
- case RETU_REG_CALIBR:
- /* TODO */
- return 0x0000;
-
- case RETU_REG_CCR1:
- return s->cc[0];
- case RETU_REG_CCR2:
- return s->cc[1];
-
- case RETU_REG_RCTRL_CLR:
- case RETU_REG_RCTRL_SET:
- case RETU_REG_TXCR:
- /* TODO */
- return 0x0000;
-
- case RETU_REG_STATUS:
- return s->status;
-
- case RETU_REG_WATCHDOG:
- case RETU_REG_AUDTXR:
- case RETU_REG_AUDPAR:
- case RETU_REG_AUDRXR1:
- case RETU_REG_AUDRXR2:
- case RETU_REG_SGR1:
- case RETU_REG_SCR1:
- case RETU_REG_SGR2:
- case RETU_REG_SCR2:
- /* TODO */
- return 0x0000;
-
- default:
- hw_error("%s: bad register %02x\n", __FUNCTION__, reg);
- }
-}
-
-static inline void retu_write(CBusRetu *s, int reg, uint16_t val)
-{
-#ifdef DEBUG
- printf("RETU write of %04x at %02x\n", val, reg);
-#endif
-
- switch (reg) {
- case RETU_REG_IDR:
- s->irqst ^= val;
- retu_interrupt_update(s);
- break;
-
- case RETU_REG_IMR:
- s->irqen = val;
- retu_interrupt_update(s);
- break;
-
- case RETU_REG_RTCDSR:
- case RETU_REG_RTCHMAR:
- /* TODO */
- break;
-
- case RETU_REG_RTCCALR:
- s->rtc.cal = val;
- break;
-
- case RETU_REG_ADCR:
- s->channel = (val >> 10) & 0xf;
- s->irqst |= 1 << retu_int_adcs;
- retu_interrupt_update(s);
- break;
- case RETU_REG_ADCSCR:
- s->sample &= ~val;
- break;
-
- case RETU_REG_AFCR:
- case RETU_REG_ANTIFR:
- case RETU_REG_CALIBR:
-
- case RETU_REG_CCR1:
- s->cc[0] = val;
- break;
- case RETU_REG_CCR2:
- s->cc[1] = val;
- break;
-
- case RETU_REG_RCTRL_CLR:
- case RETU_REG_RCTRL_SET:
- /* TODO */
- break;
-
- case RETU_REG_WATCHDOG:
- if (val == 0 && (s->cc[0] & 2))
- qemu_system_shutdown_request();
- break;
-
- case RETU_REG_TXCR:
- case RETU_REG_AUDTXR:
- case RETU_REG_AUDPAR:
- case RETU_REG_AUDRXR1:
- case RETU_REG_AUDRXR2:
- case RETU_REG_SGR1:
- case RETU_REG_SCR1:
- case RETU_REG_SGR2:
- case RETU_REG_SCR2:
- /* TODO */
- break;
-
- default:
- hw_error("%s: bad register %02x\n", __FUNCTION__, reg);
- }
-}
-
-static void retu_io(void *opaque, int rw, int reg, uint16_t *val)
-{
- CBusRetu *s = (CBusRetu *) opaque;
-
- if (rw)
- *val = retu_read(s, reg);
- else
- retu_write(s, reg, *val);
-}
-
-void *retu_init(qemu_irq irq, int vilma)
-{
- CBusRetu *s = (CBusRetu *) g_malloc0(sizeof(*s));
-
- s->irq = irq;
- s->irqen = 0xffff;
- s->irqst = 0x0000;
- s->status = 0x0020;
- s->is_vilma = !!vilma;
- s->rtc.cal = 0x01;
- s->result[retu_adc_bsi] = 0x3c2;
- s->result[retu_adc_batt_temp] = 0x0fc;
- s->result[retu_adc_chg_volt] = 0x165;
- s->result[retu_adc_head_det] = 123;
- s->result[retu_adc_hook_det] = 1023;
- s->result[retu_adc_rf_gp] = 0x11;
- s->result[retu_adc_tx_det] = 0x11;
- s->result[retu_adc_batt_volt] = 0x250;
- s->result[retu_adc_sens] = 2;
- s->result[retu_adc_sens_temp] = 0x11;
- s->result[retu_adc_bbatt_volt] = 0x3d0;
- s->result[retu_adc_self_temp] = 0x330;
-
- s->cbus.opaque = s;
- s->cbus.io = retu_io;
- s->cbus.addr = 1;
-
- return &s->cbus;
-}
-
-void retu_key_event(void *retu, int state)
-{
- CBusSlave *slave = (CBusSlave *) retu;
- CBusRetu *s = (CBusRetu *) slave->opaque;
-
- s->irqst |= 1 << retu_int_pwr;
- retu_interrupt_update(s);
-
- if (state)
- s->status &= ~(1 << 5);
- else
- s->status |= 1 << 5;
-}
-
-#if 0
-static void retu_head_event(void *retu, int state)
-{
- CBusSlave *slave = (CBusSlave *) retu;
- CBusRetu *s = (CBusRetu *) slave->opaque;
-
- if ((s->cc[0] & 0x500) == 0x500) { /* TODO: Which bits? */
- /* TODO: reissue the interrupt every 100ms or so. */
- s->irqst |= 1 << retu_int_head;
- retu_interrupt_update(s);
- }
-
- if (state)
- s->result[retu_adc_head_det] = 50;
- else
- s->result[retu_adc_head_det] = 123;
-}
-
-static void retu_hook_event(void *retu, int state)
-{
- CBusSlave *slave = (CBusSlave *) retu;
- CBusRetu *s = (CBusRetu *) slave->opaque;
-
- if ((s->cc[0] & 0x500) == 0x500) {
- /* TODO: reissue the interrupt every 100ms or so. */
- s->irqst |= 1 << retu_int_hook;
- retu_interrupt_update(s);
- }
-
- if (state)
- s->result[retu_adc_hook_det] = 50;
- else
- s->result[retu_adc_hook_det] = 123;
-}
-#endif
-
-/* Tahvo/Betty */
-typedef struct {
- uint16_t irqst;
- uint16_t irqen;
- uint8_t charger;
- uint8_t backlight;
- uint16_t usbr;
- uint16_t power;
-
- int is_betty;
- qemu_irq irq;
- CBusSlave cbus;
-} CBusTahvo;
-
-static void tahvo_interrupt_update(CBusTahvo *s)
-{
- qemu_set_irq(s->irq, s->irqst & ~s->irqen);
-}
-
-#define TAHVO_REG_ASICR 0x00 /* (RO) ASIC ID & revision */
-#define TAHVO_REG_IDR 0x01 /* (T) Interrupt ID */
-#define TAHVO_REG_IDSR 0x02 /* (RO) Interrupt status */
-#define TAHVO_REG_IMR 0x03 /* (RW) Interrupt mask */
-#define TAHVO_REG_CHAPWMR 0x04 /* (RW) Charger PWM */
-#define TAHVO_REG_LEDPWMR 0x05 /* (RW) LED PWM */
-#define TAHVO_REG_USBR 0x06 /* (RW) USB control */
-#define TAHVO_REG_RCR 0x07 /* (RW) Some kind of power management */
-#define TAHVO_REG_CCR1 0x08 /* (RW) Common control register 1 */
-#define TAHVO_REG_CCR2 0x09 /* (RW) Common control register 2 */
-#define TAHVO_REG_TESTR1 0x0a /* (RW) Test register 1 */
-#define TAHVO_REG_TESTR2 0x0b /* (RW) Test register 2 */
-#define TAHVO_REG_NOPR 0x0c /* (RW) Number of periods */
-#define TAHVO_REG_FRR 0x0d /* (RO) FR */
-
-static inline uint16_t tahvo_read(CBusTahvo *s, int reg)
-{
-#ifdef DEBUG
- printf("TAHVO read at %02x\n", reg);
-#endif
-
- switch (reg) {
- case TAHVO_REG_ASICR:
- return 0x0021 | (s->is_betty ? 0x0b00 : 0x0300); /* 22 in N810 */
-
- case TAHVO_REG_IDR:
- case TAHVO_REG_IDSR: /* XXX: what does this do? */
- return s->irqst;
-
- case TAHVO_REG_IMR:
- return s->irqen;
-
- case TAHVO_REG_CHAPWMR:
- return s->charger;
-
- case TAHVO_REG_LEDPWMR:
- return s->backlight;
-
- case TAHVO_REG_USBR:
- return s->usbr;
-
- case TAHVO_REG_RCR:
- return s->power;
-
- case TAHVO_REG_CCR1:
- case TAHVO_REG_CCR2:
- case TAHVO_REG_TESTR1:
- case TAHVO_REG_TESTR2:
- case TAHVO_REG_NOPR:
- case TAHVO_REG_FRR:
- return 0x0000;
-
- default:
- hw_error("%s: bad register %02x\n", __FUNCTION__, reg);
- }
-}
-
-static inline void tahvo_write(CBusTahvo *s, int reg, uint16_t val)
-{
-#ifdef DEBUG
- printf("TAHVO write of %04x at %02x\n", val, reg);
-#endif
-
- switch (reg) {
- case TAHVO_REG_IDR:
- s->irqst ^= val;
- tahvo_interrupt_update(s);
- break;
-
- case TAHVO_REG_IMR:
- s->irqen = val;
- tahvo_interrupt_update(s);
- break;
-
- case TAHVO_REG_CHAPWMR:
- s->charger = val;
- break;
-
- case TAHVO_REG_LEDPWMR:
- if (s->backlight != (val & 0x7f)) {
- s->backlight = val & 0x7f;
- printf("%s: LCD backlight now at %i / 127\n",
- __FUNCTION__, s->backlight);
- }
- break;
-
- case TAHVO_REG_USBR:
- s->usbr = val;
- break;
-
- case TAHVO_REG_RCR:
- s->power = val;
- break;
-
- case TAHVO_REG_CCR1:
- case TAHVO_REG_CCR2:
- case TAHVO_REG_TESTR1:
- case TAHVO_REG_TESTR2:
- case TAHVO_REG_NOPR:
- case TAHVO_REG_FRR:
- break;
-
- default:
- hw_error("%s: bad register %02x\n", __FUNCTION__, reg);
- }
-}
-
-static void tahvo_io(void *opaque, int rw, int reg, uint16_t *val)
-{
- CBusTahvo *s = (CBusTahvo *) opaque;
-
- if (rw)
- *val = tahvo_read(s, reg);
- else
- tahvo_write(s, reg, *val);
-}
-
-void *tahvo_init(qemu_irq irq, int betty)
-{
- CBusTahvo *s = (CBusTahvo *) g_malloc0(sizeof(*s));
-
- s->irq = irq;
- s->irqen = 0xffff;
- s->irqst = 0x0000;
- s->is_betty = !!betty;
-
- s->cbus.opaque = s;
- s->cbus.io = tahvo_io;
- s->cbus.addr = 2;
-
- return &s->cbus;
-}
diff --git a/qemu/hw/misc/debugexit.c b/qemu/hw/misc/debugexit.c
deleted file mode 100644
index 84fa1a5b9..000000000
--- a/qemu/hw/misc/debugexit.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * debug exit port emulation
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/isa/isa.h"
-
-#define TYPE_ISA_DEBUG_EXIT_DEVICE "isa-debug-exit"
-#define ISA_DEBUG_EXIT_DEVICE(obj) \
- OBJECT_CHECK(ISADebugExitState, (obj), TYPE_ISA_DEBUG_EXIT_DEVICE)
-
-typedef struct ISADebugExitState {
- ISADevice parent_obj;
-
- uint32_t iobase;
- uint32_t iosize;
- MemoryRegion io;
-} ISADebugExitState;
-
-static void debug_exit_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned width)
-{
- exit((val << 1) | 1);
-}
-
-static const MemoryRegionOps debug_exit_ops = {
- .write = debug_exit_write,
- .valid.min_access_size = 1,
- .valid.max_access_size = 4,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void debug_exit_realizefn(DeviceState *d, Error **errp)
-{
- ISADevice *dev = ISA_DEVICE(d);
- ISADebugExitState *isa = ISA_DEBUG_EXIT_DEVICE(d);
-
- memory_region_init_io(&isa->io, OBJECT(dev), &debug_exit_ops, isa,
- TYPE_ISA_DEBUG_EXIT_DEVICE, isa->iosize);
- memory_region_add_subregion(isa_address_space_io(dev),
- isa->iobase, &isa->io);
-}
-
-static Property debug_exit_properties[] = {
- DEFINE_PROP_UINT32("iobase", ISADebugExitState, iobase, 0x501),
- DEFINE_PROP_UINT32("iosize", ISADebugExitState, iosize, 0x02),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void debug_exit_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = debug_exit_realizefn;
- dc->props = debug_exit_properties;
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
-}
-
-static const TypeInfo debug_exit_info = {
- .name = TYPE_ISA_DEBUG_EXIT_DEVICE,
- .parent = TYPE_ISA_DEVICE,
- .instance_size = sizeof(ISADebugExitState),
- .class_init = debug_exit_class_initfn,
-};
-
-static void debug_exit_register_types(void)
-{
- type_register_static(&debug_exit_info);
-}
-
-type_init(debug_exit_register_types)
diff --git a/qemu/hw/misc/eccmemctl.c b/qemu/hw/misc/eccmemctl.c
deleted file mode 100644
index a0071f3ea..000000000
--- a/qemu/hw/misc/eccmemctl.c
+++ /dev/null
@@ -1,345 +0,0 @@
-/*
- * QEMU Sparc Sun4m ECC memory controller emulation
- *
- * Copyright (c) 2007 Robert Reif
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-
-/* There are 3 versions of this chip used in SMP sun4m systems:
- * MCC (version 0, implementation 0) SS-600MP
- * EMC (version 0, implementation 1) SS-10
- * SMC (version 0, implementation 2) SS-10SX and SS-20
- *
- * Chipset docs:
- * "Sun-4M System Architecture (revision 2.0) by Chuck Narad", 950-1373-01,
- * http://mediacast.sun.com/users/Barton808/media/Sun4M_SystemArchitecture_edited2.pdf
- */
-
-#define ECC_MCC 0x00000000
-#define ECC_EMC 0x10000000
-#define ECC_SMC 0x20000000
-
-/* Register indexes */
-#define ECC_MER 0 /* Memory Enable Register */
-#define ECC_MDR 1 /* Memory Delay Register */
-#define ECC_MFSR 2 /* Memory Fault Status Register */
-#define ECC_VCR 3 /* Video Configuration Register */
-#define ECC_MFAR0 4 /* Memory Fault Address Register 0 */
-#define ECC_MFAR1 5 /* Memory Fault Address Register 1 */
-#define ECC_DR 6 /* Diagnostic Register */
-#define ECC_ECR0 7 /* Event Count Register 0 */
-#define ECC_ECR1 8 /* Event Count Register 1 */
-
-/* ECC fault control register */
-#define ECC_MER_EE 0x00000001 /* Enable ECC checking */
-#define ECC_MER_EI 0x00000002 /* Enable Interrupts on
- correctable errors */
-#define ECC_MER_MRR0 0x00000004 /* SIMM 0 */
-#define ECC_MER_MRR1 0x00000008 /* SIMM 1 */
-#define ECC_MER_MRR2 0x00000010 /* SIMM 2 */
-#define ECC_MER_MRR3 0x00000020 /* SIMM 3 */
-#define ECC_MER_MRR4 0x00000040 /* SIMM 4 */
-#define ECC_MER_MRR5 0x00000080 /* SIMM 5 */
-#define ECC_MER_MRR6 0x00000100 /* SIMM 6 */
-#define ECC_MER_MRR7 0x00000200 /* SIMM 7 */
-#define ECC_MER_REU 0x00000100 /* Memory Refresh Enable (600MP) */
-#define ECC_MER_MRR 0x000003fc /* MRR mask */
-#define ECC_MER_A 0x00000400 /* Memory controller addr map select */
-#define ECC_MER_DCI 0x00000800 /* Disables Coherent Invalidate ACK */
-#define ECC_MER_VER 0x0f000000 /* Version */
-#define ECC_MER_IMPL 0xf0000000 /* Implementation */
-#define ECC_MER_MASK_0 0x00000103 /* Version 0 (MCC) mask */
-#define ECC_MER_MASK_1 0x00000bff /* Version 1 (EMC) mask */
-#define ECC_MER_MASK_2 0x00000bff /* Version 2 (SMC) mask */
-
-/* ECC memory delay register */
-#define ECC_MDR_RRI 0x000003ff /* Refresh Request Interval */
-#define ECC_MDR_MI 0x00001c00 /* MIH Delay */
-#define ECC_MDR_CI 0x0000e000 /* Coherent Invalidate Delay */
-#define ECC_MDR_MDL 0x001f0000 /* MBus Master arbitration delay */
-#define ECC_MDR_MDH 0x03e00000 /* MBus Master arbitration delay */
-#define ECC_MDR_GAD 0x7c000000 /* Graphics Arbitration Delay */
-#define ECC_MDR_RSC 0x80000000 /* Refresh load control */
-#define ECC_MDR_MASK 0x7fffffff
-
-/* ECC fault status register */
-#define ECC_MFSR_CE 0x00000001 /* Correctable error */
-#define ECC_MFSR_BS 0x00000002 /* C2 graphics bad slot access */
-#define ECC_MFSR_TO 0x00000004 /* Timeout on write */
-#define ECC_MFSR_UE 0x00000008 /* Uncorrectable error */
-#define ECC_MFSR_DW 0x000000f0 /* Index of double word in block */
-#define ECC_MFSR_SYND 0x0000ff00 /* Syndrome for correctable error */
-#define ECC_MFSR_ME 0x00010000 /* Multiple errors */
-#define ECC_MFSR_C2ERR 0x00020000 /* C2 graphics error */
-
-/* ECC fault address register 0 */
-#define ECC_MFAR0_PADDR 0x0000000f /* PA[32-35] */
-#define ECC_MFAR0_TYPE 0x000000f0 /* Transaction type */
-#define ECC_MFAR0_SIZE 0x00000700 /* Transaction size */
-#define ECC_MFAR0_CACHE 0x00000800 /* Mapped cacheable */
-#define ECC_MFAR0_LOCK 0x00001000 /* Error occurred in atomic cycle */
-#define ECC_MFAR0_BMODE 0x00002000 /* Boot mode */
-#define ECC_MFAR0_VADDR 0x003fc000 /* VA[12-19] (superset bits) */
-#define ECC_MFAR0_S 0x08000000 /* Supervisor mode */
-#define ECC_MFARO_MID 0xf0000000 /* Module ID */
-
-/* ECC diagnostic register */
-#define ECC_DR_CBX 0x00000001
-#define ECC_DR_CB0 0x00000002
-#define ECC_DR_CB1 0x00000004
-#define ECC_DR_CB2 0x00000008
-#define ECC_DR_CB4 0x00000010
-#define ECC_DR_CB8 0x00000020
-#define ECC_DR_CB16 0x00000040
-#define ECC_DR_CB32 0x00000080
-#define ECC_DR_DMODE 0x00000c00
-
-#define ECC_NREGS 9
-#define ECC_SIZE (ECC_NREGS * sizeof(uint32_t))
-
-#define ECC_DIAG_SIZE 4
-#define ECC_DIAG_MASK (ECC_DIAG_SIZE - 1)
-
-#define TYPE_ECC_MEMCTL "eccmemctl"
-#define ECC_MEMCTL(obj) OBJECT_CHECK(ECCState, (obj), TYPE_ECC_MEMCTL)
-
-typedef struct ECCState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem, iomem_diag;
- qemu_irq irq;
- uint32_t regs[ECC_NREGS];
- uint8_t diag[ECC_DIAG_SIZE];
- uint32_t version;
-} ECCState;
-
-static void ecc_mem_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned size)
-{
- ECCState *s = opaque;
-
- switch (addr >> 2) {
- case ECC_MER:
- if (s->version == ECC_MCC)
- s->regs[ECC_MER] = (val & ECC_MER_MASK_0);
- else if (s->version == ECC_EMC)
- s->regs[ECC_MER] = s->version | (val & ECC_MER_MASK_1);
- else if (s->version == ECC_SMC)
- s->regs[ECC_MER] = s->version | (val & ECC_MER_MASK_2);
- trace_ecc_mem_writel_mer(val);
- break;
- case ECC_MDR:
- s->regs[ECC_MDR] = val & ECC_MDR_MASK;
- trace_ecc_mem_writel_mdr(val);
- break;
- case ECC_MFSR:
- s->regs[ECC_MFSR] = val;
- qemu_irq_lower(s->irq);
- trace_ecc_mem_writel_mfsr(val);
- break;
- case ECC_VCR:
- s->regs[ECC_VCR] = val;
- trace_ecc_mem_writel_vcr(val);
- break;
- case ECC_DR:
- s->regs[ECC_DR] = val;
- trace_ecc_mem_writel_dr(val);
- break;
- case ECC_ECR0:
- s->regs[ECC_ECR0] = val;
- trace_ecc_mem_writel_ecr0(val);
- break;
- case ECC_ECR1:
- s->regs[ECC_ECR0] = val;
- trace_ecc_mem_writel_ecr1(val);
- break;
- }
-}
-
-static uint64_t ecc_mem_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- ECCState *s = opaque;
- uint32_t ret = 0;
-
- switch (addr >> 2) {
- case ECC_MER:
- ret = s->regs[ECC_MER];
- trace_ecc_mem_readl_mer(ret);
- break;
- case ECC_MDR:
- ret = s->regs[ECC_MDR];
- trace_ecc_mem_readl_mdr(ret);
- break;
- case ECC_MFSR:
- ret = s->regs[ECC_MFSR];
- trace_ecc_mem_readl_mfsr(ret);
- break;
- case ECC_VCR:
- ret = s->regs[ECC_VCR];
- trace_ecc_mem_readl_vcr(ret);
- break;
- case ECC_MFAR0:
- ret = s->regs[ECC_MFAR0];
- trace_ecc_mem_readl_mfar0(ret);
- break;
- case ECC_MFAR1:
- ret = s->regs[ECC_MFAR1];
- trace_ecc_mem_readl_mfar1(ret);
- break;
- case ECC_DR:
- ret = s->regs[ECC_DR];
- trace_ecc_mem_readl_dr(ret);
- break;
- case ECC_ECR0:
- ret = s->regs[ECC_ECR0];
- trace_ecc_mem_readl_ecr0(ret);
- break;
- case ECC_ECR1:
- ret = s->regs[ECC_ECR0];
- trace_ecc_mem_readl_ecr1(ret);
- break;
- }
- return ret;
-}
-
-static const MemoryRegionOps ecc_mem_ops = {
- .read = ecc_mem_read,
- .write = ecc_mem_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static void ecc_diag_mem_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- ECCState *s = opaque;
-
- trace_ecc_diag_mem_writeb(addr, val);
- s->diag[addr & ECC_DIAG_MASK] = val;
-}
-
-static uint64_t ecc_diag_mem_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- ECCState *s = opaque;
- uint32_t ret = s->diag[(int)addr];
-
- trace_ecc_diag_mem_readb(addr, ret);
- return ret;
-}
-
-static const MemoryRegionOps ecc_diag_mem_ops = {
- .read = ecc_diag_mem_read,
- .write = ecc_diag_mem_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
-};
-
-static const VMStateDescription vmstate_ecc = {
- .name ="ECC",
- .version_id = 3,
- .minimum_version_id = 3,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, ECCState, ECC_NREGS),
- VMSTATE_BUFFER(diag, ECCState),
- VMSTATE_UINT32(version, ECCState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void ecc_reset(DeviceState *d)
-{
- ECCState *s = ECC_MEMCTL(d);
-
- if (s->version == ECC_MCC) {
- s->regs[ECC_MER] &= ECC_MER_REU;
- } else {
- s->regs[ECC_MER] &= (ECC_MER_VER | ECC_MER_IMPL | ECC_MER_MRR |
- ECC_MER_DCI);
- }
- s->regs[ECC_MDR] = 0x20;
- s->regs[ECC_MFSR] = 0;
- s->regs[ECC_VCR] = 0;
- s->regs[ECC_MFAR0] = 0x07c00000;
- s->regs[ECC_MFAR1] = 0;
- s->regs[ECC_DR] = 0;
- s->regs[ECC_ECR0] = 0;
- s->regs[ECC_ECR1] = 0;
-}
-
-static int ecc_init1(SysBusDevice *dev)
-{
- ECCState *s = ECC_MEMCTL(dev);
-
- sysbus_init_irq(dev, &s->irq);
- s->regs[0] = s->version;
- memory_region_init_io(&s->iomem, OBJECT(dev), &ecc_mem_ops, s, "ecc", ECC_SIZE);
- sysbus_init_mmio(dev, &s->iomem);
-
- if (s->version == ECC_MCC) { // SS-600MP only
- memory_region_init_io(&s->iomem_diag, OBJECT(dev), &ecc_diag_mem_ops, s,
- "ecc.diag", ECC_DIAG_SIZE);
- sysbus_init_mmio(dev, &s->iomem_diag);
- }
-
- return 0;
-}
-
-static Property ecc_properties[] = {
- DEFINE_PROP_UINT32("version", ECCState, version, -1),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void ecc_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = ecc_init1;
- dc->reset = ecc_reset;
- dc->vmsd = &vmstate_ecc;
- dc->props = ecc_properties;
-}
-
-static const TypeInfo ecc_info = {
- .name = TYPE_ECC_MEMCTL,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(ECCState),
- .class_init = ecc_class_init,
-};
-
-
-static void ecc_register_types(void)
-{
- type_register_static(&ecc_info);
-}
-
-type_init(ecc_register_types)
diff --git a/qemu/hw/misc/edu.c b/qemu/hw/misc/edu.c
deleted file mode 100644
index 888ba49a0..000000000
--- a/qemu/hw/misc/edu.c
+++ /dev/null
@@ -1,407 +0,0 @@
-/*
- * QEMU educational PCI device
- *
- * Copyright (c) 2012-2015 Jiri Slaby
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/pci/pci.h"
-#include "qemu/timer.h"
-#include "qemu/main-loop.h" /* iothread mutex */
-#include "qapi/visitor.h"
-
-#define EDU(obj) OBJECT_CHECK(EduState, obj, "edu")
-
-#define FACT_IRQ 0x00000001
-#define DMA_IRQ 0x00000100
-
-#define DMA_START 0x40000
-#define DMA_SIZE 4096
-
-typedef struct {
- PCIDevice pdev;
- MemoryRegion mmio;
-
- QemuThread thread;
- QemuMutex thr_mutex;
- QemuCond thr_cond;
- bool stopping;
-
- uint32_t addr4;
- uint32_t fact;
-#define EDU_STATUS_COMPUTING 0x01
-#define EDU_STATUS_IRQFACT 0x80
- uint32_t status;
-
- uint32_t irq_status;
-
-#define EDU_DMA_RUN 0x1
-#define EDU_DMA_DIR(cmd) (((cmd) & 0x2) >> 1)
-# define EDU_DMA_FROM_PCI 0
-# define EDU_DMA_TO_PCI 1
-#define EDU_DMA_IRQ 0x4
- struct dma_state {
- dma_addr_t src;
- dma_addr_t dst;
- dma_addr_t cnt;
- dma_addr_t cmd;
- } dma;
- QEMUTimer dma_timer;
- char dma_buf[DMA_SIZE];
- uint64_t dma_mask;
-} EduState;
-
-static void edu_raise_irq(EduState *edu, uint32_t val)
-{
- edu->irq_status |= val;
- if (edu->irq_status) {
- pci_set_irq(&edu->pdev, 1);
- }
-}
-
-static void edu_lower_irq(EduState *edu, uint32_t val)
-{
- edu->irq_status &= ~val;
-
- if (!edu->irq_status) {
- pci_set_irq(&edu->pdev, 0);
- }
-}
-
-static bool within(uint32_t addr, uint32_t start, uint32_t end)
-{
- return start <= addr && addr < end;
-}
-
-static void edu_check_range(uint32_t addr, uint32_t size1, uint32_t start,
- uint32_t size2)
-{
- uint32_t end1 = addr + size1;
- uint32_t end2 = start + size2;
-
- if (within(addr, start, end2) &&
- end1 > addr && within(end1, start, end2)) {
- return;
- }
-
- hw_error("EDU: DMA range 0x%.8x-0x%.8x out of bounds (0x%.8x-0x%.8x)!",
- addr, end1 - 1, start, end2 - 1);
-}
-
-static dma_addr_t edu_clamp_addr(const EduState *edu, dma_addr_t addr)
-{
- dma_addr_t res = addr & edu->dma_mask;
-
- if (addr != res) {
- printf("EDU: clamping DMA %#.16"PRIx64" to %#.16"PRIx64"!\n", addr, res);
- }
-
- return res;
-}
-
-static void edu_dma_timer(void *opaque)
-{
- EduState *edu = opaque;
- bool raise_irq = false;
-
- if (!(edu->dma.cmd & EDU_DMA_RUN)) {
- return;
- }
-
- if (EDU_DMA_DIR(edu->dma.cmd) == EDU_DMA_FROM_PCI) {
- uint32_t dst = edu->dma.dst;
- edu_check_range(dst, edu->dma.cnt, DMA_START, DMA_SIZE);
- dst -= DMA_START;
- pci_dma_read(&edu->pdev, edu_clamp_addr(edu, edu->dma.src),
- edu->dma_buf + dst, edu->dma.cnt);
- } else {
- uint32_t src = edu->dma.src;
- edu_check_range(src, edu->dma.cnt, DMA_START, DMA_SIZE);
- src -= DMA_START;
- pci_dma_write(&edu->pdev, edu_clamp_addr(edu, edu->dma.dst),
- edu->dma_buf + src, edu->dma.cnt);
- }
-
- edu->dma.cmd &= ~EDU_DMA_RUN;
- if (edu->dma.cmd & EDU_DMA_IRQ) {
- raise_irq = true;
- }
-
- if (raise_irq) {
- edu_raise_irq(edu, DMA_IRQ);
- }
-}
-
-static void dma_rw(EduState *edu, bool write, dma_addr_t *val, dma_addr_t *dma,
- bool timer)
-{
- if (write && (edu->dma.cmd & EDU_DMA_RUN)) {
- return;
- }
-
- if (write) {
- *dma = *val;
- } else {
- *val = *dma;
- }
-
- if (timer) {
- timer_mod(&edu->dma_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 100);
- }
-}
-
-static uint64_t edu_mmio_read(void *opaque, hwaddr addr, unsigned size)
-{
- EduState *edu = opaque;
- uint64_t val = ~0ULL;
-
- if (size != 4) {
- return val;
- }
-
- switch (addr) {
- case 0x00:
- val = 0x010000edu;
- break;
- case 0x04:
- val = edu->addr4;
- break;
- case 0x08:
- qemu_mutex_lock(&edu->thr_mutex);
- val = edu->fact;
- qemu_mutex_unlock(&edu->thr_mutex);
- break;
- case 0x20:
- val = atomic_read(&edu->status);
- break;
- case 0x24:
- val = edu->irq_status;
- break;
- case 0x80:
- dma_rw(edu, false, &val, &edu->dma.src, false);
- break;
- case 0x88:
- dma_rw(edu, false, &val, &edu->dma.dst, false);
- break;
- case 0x90:
- dma_rw(edu, false, &val, &edu->dma.cnt, false);
- break;
- case 0x98:
- dma_rw(edu, false, &val, &edu->dma.cmd, false);
- break;
- }
-
- return val;
-}
-
-static void edu_mmio_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned size)
-{
- EduState *edu = opaque;
-
- if (addr < 0x80 && size != 4) {
- return;
- }
-
- if (addr >= 0x80 && size != 4 && size != 8) {
- return;
- }
-
- switch (addr) {
- case 0x04:
- edu->addr4 = ~val;
- break;
- case 0x08:
- if (atomic_read(&edu->status) & EDU_STATUS_COMPUTING) {
- break;
- }
- /* EDU_STATUS_COMPUTING cannot go 0->1 concurrently, because it is only
- * set in this function and it is under the iothread mutex.
- */
- qemu_mutex_lock(&edu->thr_mutex);
- edu->fact = val;
- atomic_or(&edu->status, EDU_STATUS_COMPUTING);
- qemu_cond_signal(&edu->thr_cond);
- qemu_mutex_unlock(&edu->thr_mutex);
- break;
- case 0x20:
- if (val & EDU_STATUS_IRQFACT) {
- atomic_or(&edu->status, EDU_STATUS_IRQFACT);
- } else {
- atomic_and(&edu->status, ~EDU_STATUS_IRQFACT);
- }
- break;
- case 0x60:
- edu_raise_irq(edu, val);
- break;
- case 0x64:
- edu_lower_irq(edu, val);
- break;
- case 0x80:
- dma_rw(edu, true, &val, &edu->dma.src, false);
- break;
- case 0x88:
- dma_rw(edu, true, &val, &edu->dma.dst, false);
- break;
- case 0x90:
- dma_rw(edu, true, &val, &edu->dma.cnt, false);
- break;
- case 0x98:
- if (!(val & EDU_DMA_RUN)) {
- break;
- }
- dma_rw(edu, true, &val, &edu->dma.cmd, true);
- break;
- }
-}
-
-static const MemoryRegionOps edu_mmio_ops = {
- .read = edu_mmio_read,
- .write = edu_mmio_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-/*
- * We purposely use a thread, so that users are forced to wait for the status
- * register.
- */
-static void *edu_fact_thread(void *opaque)
-{
- EduState *edu = opaque;
-
- while (1) {
- uint32_t val, ret = 1;
-
- qemu_mutex_lock(&edu->thr_mutex);
- while ((atomic_read(&edu->status) & EDU_STATUS_COMPUTING) == 0 &&
- !edu->stopping) {
- qemu_cond_wait(&edu->thr_cond, &edu->thr_mutex);
- }
-
- if (edu->stopping) {
- qemu_mutex_unlock(&edu->thr_mutex);
- break;
- }
-
- val = edu->fact;
- qemu_mutex_unlock(&edu->thr_mutex);
-
- while (val > 0) {
- ret *= val--;
- }
-
- /*
- * We should sleep for a random period here, so that students are
- * forced to check the status properly.
- */
-
- qemu_mutex_lock(&edu->thr_mutex);
- edu->fact = ret;
- qemu_mutex_unlock(&edu->thr_mutex);
- atomic_and(&edu->status, ~EDU_STATUS_COMPUTING);
-
- if (atomic_read(&edu->status) & EDU_STATUS_IRQFACT) {
- qemu_mutex_lock_iothread();
- edu_raise_irq(edu, FACT_IRQ);
- qemu_mutex_unlock_iothread();
- }
- }
-
- return NULL;
-}
-
-static void pci_edu_realize(PCIDevice *pdev, Error **errp)
-{
- EduState *edu = DO_UPCAST(EduState, pdev, pdev);
- uint8_t *pci_conf = pdev->config;
-
- timer_init_ms(&edu->dma_timer, QEMU_CLOCK_VIRTUAL, edu_dma_timer, edu);
-
- qemu_mutex_init(&edu->thr_mutex);
- qemu_cond_init(&edu->thr_cond);
- qemu_thread_create(&edu->thread, "edu", edu_fact_thread,
- edu, QEMU_THREAD_JOINABLE);
-
- pci_config_set_interrupt_pin(pci_conf, 1);
-
- memory_region_init_io(&edu->mmio, OBJECT(edu), &edu_mmio_ops, edu,
- "edu-mmio", 1 << 20);
- pci_register_bar(pdev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &edu->mmio);
-}
-
-static void pci_edu_uninit(PCIDevice *pdev)
-{
- EduState *edu = DO_UPCAST(EduState, pdev, pdev);
-
- qemu_mutex_lock(&edu->thr_mutex);
- edu->stopping = true;
- qemu_mutex_unlock(&edu->thr_mutex);
- qemu_cond_signal(&edu->thr_cond);
- qemu_thread_join(&edu->thread);
-
- qemu_cond_destroy(&edu->thr_cond);
- qemu_mutex_destroy(&edu->thr_mutex);
-
- timer_del(&edu->dma_timer);
-}
-
-static void edu_obj_uint64(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- uint64_t *val = opaque;
-
- visit_type_uint64(v, name, val, errp);
-}
-
-static void edu_instance_init(Object *obj)
-{
- EduState *edu = EDU(obj);
-
- edu->dma_mask = (1UL << 28) - 1;
- object_property_add(obj, "dma_mask", "uint64", edu_obj_uint64,
- edu_obj_uint64, NULL, &edu->dma_mask, NULL);
-}
-
-static void edu_class_init(ObjectClass *class, void *data)
-{
- PCIDeviceClass *k = PCI_DEVICE_CLASS(class);
-
- k->realize = pci_edu_realize;
- k->exit = pci_edu_uninit;
- k->vendor_id = PCI_VENDOR_ID_QEMU;
- k->device_id = 0x11e8;
- k->revision = 0x10;
- k->class_id = PCI_CLASS_OTHERS;
-}
-
-static void pci_edu_register_types(void)
-{
- static const TypeInfo edu_info = {
- .name = "edu",
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(EduState),
- .instance_init = edu_instance_init,
- .class_init = edu_class_init,
- };
-
- type_register_static(&edu_info);
-}
-type_init(pci_edu_register_types)
diff --git a/qemu/hw/misc/exynos4210_pmu.c b/qemu/hw/misc/exynos4210_pmu.c
deleted file mode 100644
index 889abadfe..000000000
--- a/qemu/hw/misc/exynos4210_pmu.c
+++ /dev/null
@@ -1,503 +0,0 @@
-/*
- * Exynos4210 Power Management Unit (PMU) Emulation
- *
- * Copyright (C) 2011 Samsung Electronics Co Ltd.
- * Maksim Kozlov <m.kozlov@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * This model implements PMU registers just as a bulk of memory. Currently,
- * the only reason this device exists is that secondary CPU boot loader
- * uses PMU INFORM5 register as a holding pen.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-
-#ifndef DEBUG_PMU
-#define DEBUG_PMU 0
-#endif
-
-#ifndef DEBUG_PMU_EXTEND
-#define DEBUG_PMU_EXTEND 0
-#endif
-
-#if DEBUG_PMU
-#define PRINT_DEBUG(fmt, args...) \
- do { \
- fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \
- } while (0)
-
-#if DEBUG_PMU_EXTEND
-#define PRINT_DEBUG_EXTEND(fmt, args...) \
- do { \
- fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \
- } while (0)
-#else
-#define PRINT_DEBUG_EXTEND(fmt, args...) do {} while (0)
-#endif /* EXTEND */
-
-#else
-#define PRINT_DEBUG(fmt, args...) do {} while (0)
-#define PRINT_DEBUG_EXTEND(fmt, args...) do {} while (0)
-#endif
-
-/*
- * Offsets for PMU registers
- */
-#define OM_STAT 0x0000 /* OM status register */
-#define RTC_CLKO_SEL 0x000C /* Controls RTCCLKOUT */
-#define GNSS_RTC_OUT_CTRL 0x0010 /* Controls GNSS_RTC_OUT */
-/* Decides whether system-level low-power mode is used. */
-#define SYSTEM_POWER_DOWN_CTRL 0x0200
-/* Sets control options for CENTRAL_SEQ */
-#define SYSTEM_POWER_DOWN_OPTION 0x0208
-#define SWRESET 0x0400 /* Generate software reset */
-#define RST_STAT 0x0404 /* Reset status register */
-#define WAKEUP_STAT 0x0600 /* Wakeup status register */
-#define EINT_WAKEUP_MASK 0x0604 /* Configure External INTerrupt mask */
-#define WAKEUP_MASK 0x0608 /* Configure wakeup source mask */
-#define HDMI_PHY_CONTROL 0x0700 /* HDMI PHY control register */
-#define USBDEVICE_PHY_CONTROL 0x0704 /* USB Device PHY control register */
-#define USBHOST_PHY_CONTROL 0x0708 /* USB HOST PHY control register */
-#define DAC_PHY_CONTROL 0x070C /* DAC control register */
-#define MIPI_PHY0_CONTROL 0x0710 /* MIPI PHY control register */
-#define MIPI_PHY1_CONTROL 0x0714 /* MIPI PHY control register */
-#define ADC_PHY_CONTROL 0x0718 /* TS-ADC control register */
-#define PCIe_PHY_CONTROL 0x071C /* TS-PCIe control register */
-#define SATA_PHY_CONTROL 0x0720 /* TS-SATA control register */
-#define INFORM0 0x0800 /* Information register 0 */
-#define INFORM1 0x0804 /* Information register 1 */
-#define INFORM2 0x0808 /* Information register 2 */
-#define INFORM3 0x080C /* Information register 3 */
-#define INFORM4 0x0810 /* Information register 4 */
-#define INFORM5 0x0814 /* Information register 5 */
-#define INFORM6 0x0818 /* Information register 6 */
-#define INFORM7 0x081C /* Information register 7 */
-#define PMU_DEBUG 0x0A00 /* PMU debug register */
-/* Registers to set system-level low-power option */
-#define ARM_CORE0_SYS_PWR_REG 0x1000
-#define ARM_CORE1_SYS_PWR_REG 0x1010
-#define ARM_COMMON_SYS_PWR_REG 0x1080
-#define ARM_CPU_L2_0_SYS_PWR_REG 0x10C0
-#define ARM_CPU_L2_1_SYS_PWR_REG 0x10C4
-#define CMU_ACLKSTOP_SYS_PWR_REG 0x1100
-#define CMU_SCLKSTOP_SYS_PWR_REG 0x1104
-#define CMU_RESET_SYS_PWR_REG 0x110C
-#define APLL_SYSCLK_SYS_PWR_REG 0x1120
-#define MPLL_SYSCLK_SYS_PWR_REG 0x1124
-#define VPLL_SYSCLK_SYS_PWR_REG 0x1128
-#define EPLL_SYSCLK_SYS_PWR_REG 0x112C
-#define CMU_CLKSTOP_GPS_ALIVE_SYS_PWR_REG 0x1138
-#define CMU_RESET_GPS_ALIVE_SYS_PWR_REG 0x113C
-#define CMU_CLKSTOP_CAM_SYS_PWR_REG 0x1140
-#define CMU_CLKSTOP_TV_SYS_PWR_REG 0x1144
-#define CMU_CLKSTOP_MFC_SYS_PWR_REG 0x1148
-#define CMU_CLKSTOP_G3D_SYS_PWR_REG 0x114C
-#define CMU_CLKSTOP_LCD0_SYS_PWR_REG 0x1150
-#define CMU_CLKSTOP_LCD1_SYS_PWR_REG 0x1154
-#define CMU_CLKSTOP_MAUDIO_SYS_PWR_REG 0x1158
-#define CMU_CLKSTOP_GPS_SYS_PWR_REG 0x115C
-#define CMU_RESET_CAM_SYS_PWR_REG 0x1160
-#define CMU_RESET_TV_SYS_PWR_REG 0x1164
-#define CMU_RESET_MFC_SYS_PWR_REG 0x1168
-#define CMU_RESET_G3D_SYS_PWR_REG 0x116C
-#define CMU_RESET_LCD0_SYS_PWR_REG 0x1170
-#define CMU_RESET_LCD1_SYS_PWR_REG 0x1174
-#define CMU_RESET_MAUDIO_SYS_PWR_REG 0x1178
-#define CMU_RESET_GPS_SYS_PWR_REG 0x117C
-#define TOP_BUS_SYS_PWR_REG 0x1180
-#define TOP_RETENTION_SYS_PWR_REG 0x1184
-#define TOP_PWR_SYS_PWR_REG 0x1188
-#define LOGIC_RESET_SYS_PWR_REG 0x11A0
-#define OneNANDXL_MEM_SYS_PWR_REG 0x11C0
-#define MODEMIF_MEM_SYS_PWR_REG 0x11C4
-#define USBDEVICE_MEM_SYS_PWR_REG 0x11CC
-#define SDMMC_MEM_SYS_PWR_REG 0x11D0
-#define CSSYS_MEM_SYS_PWR_REG 0x11D4
-#define SECSS_MEM_SYS_PWR_REG 0x11D8
-#define PCIe_MEM_SYS_PWR_REG 0x11E0
-#define SATA_MEM_SYS_PWR_REG 0x11E4
-#define PAD_RETENTION_DRAM_SYS_PWR_REG 0x1200
-#define PAD_RETENTION_MAUDIO_SYS_PWR_REG 0x1204
-#define PAD_RETENTION_GPIO_SYS_PWR_REG 0x1220
-#define PAD_RETENTION_UART_SYS_PWR_REG 0x1224
-#define PAD_RETENTION_MMCA_SYS_PWR_REG 0x1228
-#define PAD_RETENTION_MMCB_SYS_PWR_REG 0x122C
-#define PAD_RETENTION_EBIA_SYS_PWR_REG 0x1230
-#define PAD_RETENTION_EBIB_SYS_PWR_REG 0x1234
-#define PAD_ISOLATION_SYS_PWR_REG 0x1240
-#define PAD_ALV_SEL_SYS_PWR_REG 0x1260
-#define XUSBXTI_SYS_PWR_REG 0x1280
-#define XXTI_SYS_PWR_REG 0x1284
-#define EXT_REGULATOR_SYS_PWR_REG 0x12C0
-#define GPIO_MODE_SYS_PWR_REG 0x1300
-#define GPIO_MODE_MAUDIO_SYS_PWR_REG 0x1340
-#define CAM_SYS_PWR_REG 0x1380
-#define TV_SYS_PWR_REG 0x1384
-#define MFC_SYS_PWR_REG 0x1388
-#define G3D_SYS_PWR_REG 0x138C
-#define LCD0_SYS_PWR_REG 0x1390
-#define LCD1_SYS_PWR_REG 0x1394
-#define MAUDIO_SYS_PWR_REG 0x1398
-#define GPS_SYS_PWR_REG 0x139C
-#define GPS_ALIVE_SYS_PWR_REG 0x13A0
-#define ARM_CORE0_CONFIGURATION 0x2000 /* Configure power mode of ARM_CORE0 */
-#define ARM_CORE0_STATUS 0x2004 /* Check power mode of ARM_CORE0 */
-#define ARM_CORE0_OPTION 0x2008 /* Sets control options for ARM_CORE0 */
-#define ARM_CORE1_CONFIGURATION 0x2080 /* Configure power mode of ARM_CORE1 */
-#define ARM_CORE1_STATUS 0x2084 /* Check power mode of ARM_CORE1 */
-#define ARM_CORE1_OPTION 0x2088 /* Sets control options for ARM_CORE0 */
-#define ARM_COMMON_OPTION 0x2408 /* Sets control options for ARM_COMMON */
-/* Configure power mode of ARM_CPU_L2_0 */
-#define ARM_CPU_L2_0_CONFIGURATION 0x2600
-#define ARM_CPU_L2_0_STATUS 0x2604 /* Check power mode of ARM_CPU_L2_0 */
-/* Configure power mode of ARM_CPU_L2_1 */
-#define ARM_CPU_L2_1_CONFIGURATION 0x2620
-#define ARM_CPU_L2_1_STATUS 0x2624 /* Check power mode of ARM_CPU_L2_1 */
-/* Sets control options for PAD_RETENTION_MAUDIO */
-#define PAD_RETENTION_MAUDIO_OPTION 0x3028
-/* Sets control options for PAD_RETENTION_GPIO */
-#define PAD_RETENTION_GPIO_OPTION 0x3108
-/* Sets control options for PAD_RETENTION_UART */
-#define PAD_RETENTION_UART_OPTION 0x3128
-/* Sets control options for PAD_RETENTION_MMCA */
-#define PAD_RETENTION_MMCA_OPTION 0x3148
-/* Sets control options for PAD_RETENTION_MMCB */
-#define PAD_RETENTION_MMCB_OPTION 0x3168
-/* Sets control options for PAD_RETENTION_EBIA */
-#define PAD_RETENTION_EBIA_OPTION 0x3188
-/* Sets control options for PAD_RETENTION_EBIB */
-#define PAD_RETENTION_EBIB_OPTION 0x31A8
-#define PS_HOLD_CONTROL 0x330C /* PS_HOLD control register */
-#define XUSBXTI_CONFIGURATION 0x3400 /* Configure the pad of XUSBXTI */
-#define XUSBXTI_STATUS 0x3404 /* Check the pad of XUSBXTI */
-/* Sets time required for XUSBXTI to be stabilized */
-#define XUSBXTI_DURATION 0x341C
-#define XXTI_CONFIGURATION 0x3420 /* Configure the pad of XXTI */
-#define XXTI_STATUS 0x3424 /* Check the pad of XXTI */
-/* Sets time required for XXTI to be stabilized */
-#define XXTI_DURATION 0x343C
-/* Sets time required for EXT_REGULATOR to be stabilized */
-#define EXT_REGULATOR_DURATION 0x361C
-#define CAM_CONFIGURATION 0x3C00 /* Configure power mode of CAM */
-#define CAM_STATUS 0x3C04 /* Check power mode of CAM */
-#define CAM_OPTION 0x3C08 /* Sets control options for CAM */
-#define TV_CONFIGURATION 0x3C20 /* Configure power mode of TV */
-#define TV_STATUS 0x3C24 /* Check power mode of TV */
-#define TV_OPTION 0x3C28 /* Sets control options for TV */
-#define MFC_CONFIGURATION 0x3C40 /* Configure power mode of MFC */
-#define MFC_STATUS 0x3C44 /* Check power mode of MFC */
-#define MFC_OPTION 0x3C48 /* Sets control options for MFC */
-#define G3D_CONFIGURATION 0x3C60 /* Configure power mode of G3D */
-#define G3D_STATUS 0x3C64 /* Check power mode of G3D */
-#define G3D_OPTION 0x3C68 /* Sets control options for G3D */
-#define LCD0_CONFIGURATION 0x3C80 /* Configure power mode of LCD0 */
-#define LCD0_STATUS 0x3C84 /* Check power mode of LCD0 */
-#define LCD0_OPTION 0x3C88 /* Sets control options for LCD0 */
-#define LCD1_CONFIGURATION 0x3CA0 /* Configure power mode of LCD1 */
-#define LCD1_STATUS 0x3CA4 /* Check power mode of LCD1 */
-#define LCD1_OPTION 0x3CA8 /* Sets control options for LCD1 */
-#define GPS_CONFIGURATION 0x3CE0 /* Configure power mode of GPS */
-#define GPS_STATUS 0x3CE4 /* Check power mode of GPS */
-#define GPS_OPTION 0x3CE8 /* Sets control options for GPS */
-#define GPS_ALIVE_CONFIGURATION 0x3D00 /* Configure power mode of GPS */
-#define GPS_ALIVE_STATUS 0x3D04 /* Check power mode of GPS */
-#define GPS_ALIVE_OPTION 0x3D08 /* Sets control options for GPS */
-
-#define EXYNOS4210_PMU_REGS_MEM_SIZE 0x3d0c
-
-typedef struct Exynos4210PmuReg {
- const char *name; /* for debug only */
- uint32_t offset;
- uint32_t reset_value;
-} Exynos4210PmuReg;
-
-static const Exynos4210PmuReg exynos4210_pmu_regs[] = {
- {"OM_STAT", OM_STAT, 0x00000000},
- {"RTC_CLKO_SEL", RTC_CLKO_SEL, 0x00000000},
- {"GNSS_RTC_OUT_CTRL", GNSS_RTC_OUT_CTRL, 0x00000001},
- {"SYSTEM_POWER_DOWN_CTRL", SYSTEM_POWER_DOWN_CTRL, 0x00010000},
- {"SYSTEM_POWER_DOWN_OPTION", SYSTEM_POWER_DOWN_OPTION, 0x03030000},
- {"SWRESET", SWRESET, 0x00000000},
- {"RST_STAT", RST_STAT, 0x00000000},
- {"WAKEUP_STAT", WAKEUP_STAT, 0x00000000},
- {"EINT_WAKEUP_MASK", EINT_WAKEUP_MASK, 0x00000000},
- {"WAKEUP_MASK", WAKEUP_MASK, 0x00000000},
- {"HDMI_PHY_CONTROL", HDMI_PHY_CONTROL, 0x00960000},
- {"USBDEVICE_PHY_CONTROL", USBDEVICE_PHY_CONTROL, 0x00000000},
- {"USBHOST_PHY_CONTROL", USBHOST_PHY_CONTROL, 0x00000000},
- {"DAC_PHY_CONTROL", DAC_PHY_CONTROL, 0x00000000},
- {"MIPI_PHY0_CONTROL", MIPI_PHY0_CONTROL, 0x00000000},
- {"MIPI_PHY1_CONTROL", MIPI_PHY1_CONTROL, 0x00000000},
- {"ADC_PHY_CONTROL", ADC_PHY_CONTROL, 0x00000001},
- {"PCIe_PHY_CONTROL", PCIe_PHY_CONTROL, 0x00000000},
- {"SATA_PHY_CONTROL", SATA_PHY_CONTROL, 0x00000000},
- {"INFORM0", INFORM0, 0x00000000},
- {"INFORM1", INFORM1, 0x00000000},
- {"INFORM2", INFORM2, 0x00000000},
- {"INFORM3", INFORM3, 0x00000000},
- {"INFORM4", INFORM4, 0x00000000},
- {"INFORM5", INFORM5, 0x00000000},
- {"INFORM6", INFORM6, 0x00000000},
- {"INFORM7", INFORM7, 0x00000000},
- {"PMU_DEBUG", PMU_DEBUG, 0x00000000},
- {"ARM_CORE0_SYS_PWR_REG", ARM_CORE0_SYS_PWR_REG, 0xFFFFFFFF},
- {"ARM_CORE1_SYS_PWR_REG", ARM_CORE1_SYS_PWR_REG, 0xFFFFFFFF},
- {"ARM_COMMON_SYS_PWR_REG", ARM_COMMON_SYS_PWR_REG, 0xFFFFFFFF},
- {"ARM_CPU_L2_0_SYS_PWR_REG", ARM_CPU_L2_0_SYS_PWR_REG, 0xFFFFFFFF},
- {"ARM_CPU_L2_1_SYS_PWR_REG", ARM_CPU_L2_1_SYS_PWR_REG, 0xFFFFFFFF},
- {"CMU_ACLKSTOP_SYS_PWR_REG", CMU_ACLKSTOP_SYS_PWR_REG, 0xFFFFFFFF},
- {"CMU_SCLKSTOP_SYS_PWR_REG", CMU_SCLKSTOP_SYS_PWR_REG, 0xFFFFFFFF},
- {"CMU_RESET_SYS_PWR_REG", CMU_RESET_SYS_PWR_REG, 0xFFFFFFFF},
- {"APLL_SYSCLK_SYS_PWR_REG", APLL_SYSCLK_SYS_PWR_REG, 0xFFFFFFFF},
- {"MPLL_SYSCLK_SYS_PWR_REG", MPLL_SYSCLK_SYS_PWR_REG, 0xFFFFFFFF},
- {"VPLL_SYSCLK_SYS_PWR_REG", VPLL_SYSCLK_SYS_PWR_REG, 0xFFFFFFFF},
- {"EPLL_SYSCLK_SYS_PWR_REG", EPLL_SYSCLK_SYS_PWR_REG, 0xFFFFFFFF},
- {"CMU_CLKSTOP_GPS_ALIVE_SYS_PWR_REG", CMU_CLKSTOP_GPS_ALIVE_SYS_PWR_REG,
- 0xFFFFFFFF},
- {"CMU_RESET_GPS_ALIVE_SYS_PWR_REG", CMU_RESET_GPS_ALIVE_SYS_PWR_REG,
- 0xFFFFFFFF},
- {"CMU_CLKSTOP_CAM_SYS_PWR_REG", CMU_CLKSTOP_CAM_SYS_PWR_REG, 0xFFFFFFFF},
- {"CMU_CLKSTOP_TV_SYS_PWR_REG", CMU_CLKSTOP_TV_SYS_PWR_REG, 0xFFFFFFFF},
- {"CMU_CLKSTOP_MFC_SYS_PWR_REG", CMU_CLKSTOP_MFC_SYS_PWR_REG, 0xFFFFFFFF},
- {"CMU_CLKSTOP_G3D_SYS_PWR_REG", CMU_CLKSTOP_G3D_SYS_PWR_REG, 0xFFFFFFFF},
- {"CMU_CLKSTOP_LCD0_SYS_PWR_REG", CMU_CLKSTOP_LCD0_SYS_PWR_REG, 0xFFFFFFFF},
- {"CMU_CLKSTOP_LCD1_SYS_PWR_REG", CMU_CLKSTOP_LCD1_SYS_PWR_REG, 0xFFFFFFFF},
- {"CMU_CLKSTOP_MAUDIO_SYS_PWR_REG", CMU_CLKSTOP_MAUDIO_SYS_PWR_REG,
- 0xFFFFFFFF},
- {"CMU_CLKSTOP_GPS_SYS_PWR_REG", CMU_CLKSTOP_GPS_SYS_PWR_REG, 0xFFFFFFFF},
- {"CMU_RESET_CAM_SYS_PWR_REG", CMU_RESET_CAM_SYS_PWR_REG, 0xFFFFFFFF},
- {"CMU_RESET_TV_SYS_PWR_REG", CMU_RESET_TV_SYS_PWR_REG, 0xFFFFFFFF},
- {"CMU_RESET_MFC_SYS_PWR_REG", CMU_RESET_MFC_SYS_PWR_REG, 0xFFFFFFFF},
- {"CMU_RESET_G3D_SYS_PWR_REG", CMU_RESET_G3D_SYS_PWR_REG, 0xFFFFFFFF},
- {"CMU_RESET_LCD0_SYS_PWR_REG", CMU_RESET_LCD0_SYS_PWR_REG, 0xFFFFFFFF},
- {"CMU_RESET_LCD1_SYS_PWR_REG", CMU_RESET_LCD1_SYS_PWR_REG, 0xFFFFFFFF},
- {"CMU_RESET_MAUDIO_SYS_PWR_REG", CMU_RESET_MAUDIO_SYS_PWR_REG, 0xFFFFFFFF},
- {"CMU_RESET_GPS_SYS_PWR_REG", CMU_RESET_GPS_SYS_PWR_REG, 0xFFFFFFFF},
- {"TOP_BUS_SYS_PWR_REG", TOP_BUS_SYS_PWR_REG, 0xFFFFFFFF},
- {"TOP_RETENTION_SYS_PWR_REG", TOP_RETENTION_SYS_PWR_REG, 0xFFFFFFFF},
- {"TOP_PWR_SYS_PWR_REG", TOP_PWR_SYS_PWR_REG, 0xFFFFFFFF},
- {"LOGIC_RESET_SYS_PWR_REG", LOGIC_RESET_SYS_PWR_REG, 0xFFFFFFFF},
- {"OneNANDXL_MEM_SYS_PWR_REG", OneNANDXL_MEM_SYS_PWR_REG, 0xFFFFFFFF},
- {"MODEMIF_MEM_SYS_PWR_REG", MODEMIF_MEM_SYS_PWR_REG, 0xFFFFFFFF},
- {"USBDEVICE_MEM_SYS_PWR_REG", USBDEVICE_MEM_SYS_PWR_REG, 0xFFFFFFFF},
- {"SDMMC_MEM_SYS_PWR_REG", SDMMC_MEM_SYS_PWR_REG, 0xFFFFFFFF},
- {"CSSYS_MEM_SYS_PWR_REG", CSSYS_MEM_SYS_PWR_REG, 0xFFFFFFFF},
- {"SECSS_MEM_SYS_PWR_REG", SECSS_MEM_SYS_PWR_REG, 0xFFFFFFFF},
- {"PCIe_MEM_SYS_PWR_REG", PCIe_MEM_SYS_PWR_REG, 0xFFFFFFFF},
- {"SATA_MEM_SYS_PWR_REG", SATA_MEM_SYS_PWR_REG, 0xFFFFFFFF},
- {"PAD_RETENTION_DRAM_SYS_PWR_REG", PAD_RETENTION_DRAM_SYS_PWR_REG,
- 0xFFFFFFFF},
- {"PAD_RETENTION_MAUDIO_SYS_PWR_REG", PAD_RETENTION_MAUDIO_SYS_PWR_REG,
- 0xFFFFFFFF},
- {"PAD_RETENTION_GPIO_SYS_PWR_REG", PAD_RETENTION_GPIO_SYS_PWR_REG,
- 0xFFFFFFFF},
- {"PAD_RETENTION_UART_SYS_PWR_REG", PAD_RETENTION_UART_SYS_PWR_REG,
- 0xFFFFFFFF},
- {"PAD_RETENTION_MMCA_SYS_PWR_REG", PAD_RETENTION_MMCA_SYS_PWR_REG,
- 0xFFFFFFFF},
- {"PAD_RETENTION_MMCB_SYS_PWR_REG", PAD_RETENTION_MMCB_SYS_PWR_REG,
- 0xFFFFFFFF},
- {"PAD_RETENTION_EBIA_SYS_PWR_REG", PAD_RETENTION_EBIA_SYS_PWR_REG,
- 0xFFFFFFFF},
- {"PAD_RETENTION_EBIB_SYS_PWR_REG", PAD_RETENTION_EBIB_SYS_PWR_REG,
- 0xFFFFFFFF},
- {"PAD_ISOLATION_SYS_PWR_REG", PAD_ISOLATION_SYS_PWR_REG, 0xFFFFFFFF},
- {"PAD_ALV_SEL_SYS_PWR_REG", PAD_ALV_SEL_SYS_PWR_REG, 0xFFFFFFFF},
- {"XUSBXTI_SYS_PWR_REG", XUSBXTI_SYS_PWR_REG, 0xFFFFFFFF},
- {"XXTI_SYS_PWR_REG", XXTI_SYS_PWR_REG, 0xFFFFFFFF},
- {"EXT_REGULATOR_SYS_PWR_REG", EXT_REGULATOR_SYS_PWR_REG, 0xFFFFFFFF},
- {"GPIO_MODE_SYS_PWR_REG", GPIO_MODE_SYS_PWR_REG, 0xFFFFFFFF},
- {"GPIO_MODE_MAUDIO_SYS_PWR_REG", GPIO_MODE_MAUDIO_SYS_PWR_REG, 0xFFFFFFFF},
- {"CAM_SYS_PWR_REG", CAM_SYS_PWR_REG, 0xFFFFFFFF},
- {"TV_SYS_PWR_REG", TV_SYS_PWR_REG, 0xFFFFFFFF},
- {"MFC_SYS_PWR_REG", MFC_SYS_PWR_REG, 0xFFFFFFFF},
- {"G3D_SYS_PWR_REG", G3D_SYS_PWR_REG, 0xFFFFFFFF},
- {"LCD0_SYS_PWR_REG", LCD0_SYS_PWR_REG, 0xFFFFFFFF},
- {"LCD1_SYS_PWR_REG", LCD1_SYS_PWR_REG, 0xFFFFFFFF},
- {"MAUDIO_SYS_PWR_REG", MAUDIO_SYS_PWR_REG, 0xFFFFFFFF},
- {"GPS_SYS_PWR_REG", GPS_SYS_PWR_REG, 0xFFFFFFFF},
- {"GPS_ALIVE_SYS_PWR_REG", GPS_ALIVE_SYS_PWR_REG, 0xFFFFFFFF},
- {"ARM_CORE0_CONFIGURATION", ARM_CORE0_CONFIGURATION, 0x00000003},
- {"ARM_CORE0_STATUS", ARM_CORE0_STATUS, 0x00030003},
- {"ARM_CORE0_OPTION", ARM_CORE0_OPTION, 0x01010001},
- {"ARM_CORE1_CONFIGURATION", ARM_CORE1_CONFIGURATION, 0x00000003},
- {"ARM_CORE1_STATUS", ARM_CORE1_STATUS, 0x00030003},
- {"ARM_CORE1_OPTION", ARM_CORE1_OPTION, 0x01010001},
- {"ARM_COMMON_OPTION", ARM_COMMON_OPTION, 0x00000001},
- {"ARM_CPU_L2_0_CONFIGURATION", ARM_CPU_L2_0_CONFIGURATION, 0x00000003},
- {"ARM_CPU_L2_0_STATUS", ARM_CPU_L2_0_STATUS, 0x00000003},
- {"ARM_CPU_L2_1_CONFIGURATION", ARM_CPU_L2_1_CONFIGURATION, 0x00000003},
- {"ARM_CPU_L2_1_STATUS", ARM_CPU_L2_1_STATUS, 0x00000003},
- {"PAD_RETENTION_MAUDIO_OPTION", PAD_RETENTION_MAUDIO_OPTION, 0x00000000},
- {"PAD_RETENTION_GPIO_OPTION", PAD_RETENTION_GPIO_OPTION, 0x00000000},
- {"PAD_RETENTION_UART_OPTION", PAD_RETENTION_UART_OPTION, 0x00000000},
- {"PAD_RETENTION_MMCA_OPTION", PAD_RETENTION_MMCA_OPTION, 0x00000000},
- {"PAD_RETENTION_MMCB_OPTION", PAD_RETENTION_MMCB_OPTION, 0x00000000},
- {"PAD_RETENTION_EBIA_OPTION", PAD_RETENTION_EBIA_OPTION, 0x00000000},
- {"PAD_RETENTION_EBIB_OPTION", PAD_RETENTION_EBIB_OPTION, 0x00000000},
- {"PS_HOLD_CONTROL", PS_HOLD_CONTROL, 0x00005200},
- {"XUSBXTI_CONFIGURATION", XUSBXTI_CONFIGURATION, 0x00000001},
- {"XUSBXTI_STATUS", XUSBXTI_STATUS, 0x00000001},
- {"XUSBXTI_DURATION", XUSBXTI_DURATION, 0xFFF00000},
- {"XXTI_CONFIGURATION", XXTI_CONFIGURATION, 0x00000001},
- {"XXTI_STATUS", XXTI_STATUS, 0x00000001},
- {"XXTI_DURATION", XXTI_DURATION, 0xFFF00000},
- {"EXT_REGULATOR_DURATION", EXT_REGULATOR_DURATION, 0xFFF03FFF},
- {"CAM_CONFIGURATION", CAM_CONFIGURATION, 0x00000007},
- {"CAM_STATUS", CAM_STATUS, 0x00060007},
- {"CAM_OPTION", CAM_OPTION, 0x00000001},
- {"TV_CONFIGURATION", TV_CONFIGURATION, 0x00000007},
- {"TV_STATUS", TV_STATUS, 0x00060007},
- {"TV_OPTION", TV_OPTION, 0x00000001},
- {"MFC_CONFIGURATION", MFC_CONFIGURATION, 0x00000007},
- {"MFC_STATUS", MFC_STATUS, 0x00060007},
- {"MFC_OPTION", MFC_OPTION, 0x00000001},
- {"G3D_CONFIGURATION", G3D_CONFIGURATION, 0x00000007},
- {"G3D_STATUS", G3D_STATUS, 0x00060007},
- {"G3D_OPTION", G3D_OPTION, 0x00000001},
- {"LCD0_CONFIGURATION", LCD0_CONFIGURATION, 0x00000007},
- {"LCD0_STATUS", LCD0_STATUS, 0x00060007},
- {"LCD0_OPTION", LCD0_OPTION, 0x00000001},
- {"LCD1_CONFIGURATION", LCD1_CONFIGURATION, 0x00000007},
- {"LCD1_STATUS", LCD1_STATUS, 0x00060007},
- {"LCD1_OPTION", LCD1_OPTION, 0x00000001},
- {"GPS_CONFIGURATION", GPS_CONFIGURATION, 0x00000007},
- {"GPS_STATUS", GPS_STATUS, 0x00060007},
- {"GPS_OPTION", GPS_OPTION, 0x00000001},
- {"GPS_ALIVE_CONFIGURATION", GPS_ALIVE_CONFIGURATION, 0x00000007},
- {"GPS_ALIVE_STATUS", GPS_ALIVE_STATUS, 0x00060007},
- {"GPS_ALIVE_OPTION", GPS_ALIVE_OPTION, 0x00000001},
-};
-
-#define PMU_NUM_OF_REGISTERS ARRAY_SIZE(exynos4210_pmu_regs)
-
-#define TYPE_EXYNOS4210_PMU "exynos4210.pmu"
-#define EXYNOS4210_PMU(obj) \
- OBJECT_CHECK(Exynos4210PmuState, (obj), TYPE_EXYNOS4210_PMU)
-
-typedef struct Exynos4210PmuState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- uint32_t reg[PMU_NUM_OF_REGISTERS];
-} Exynos4210PmuState;
-
-static uint64_t exynos4210_pmu_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- Exynos4210PmuState *s = (Exynos4210PmuState *)opaque;
- unsigned i;
- const Exynos4210PmuReg *reg_p = exynos4210_pmu_regs;
-
- for (i = 0; i < PMU_NUM_OF_REGISTERS; i++) {
- if (reg_p->offset == offset) {
- PRINT_DEBUG_EXTEND("%s [0x%04x] -> 0x%04x\n", reg_p->name,
- (uint32_t)offset, s->reg[i]);
- return s->reg[i];
- }
- reg_p++;
- }
- PRINT_DEBUG("QEMU PMU ERROR: bad read offset 0x%04x\n", (uint32_t)offset);
- return 0;
-}
-
-static void exynos4210_pmu_write(void *opaque, hwaddr offset,
- uint64_t val, unsigned size)
-{
- Exynos4210PmuState *s = (Exynos4210PmuState *)opaque;
- unsigned i;
- const Exynos4210PmuReg *reg_p = exynos4210_pmu_regs;
-
- for (i = 0; i < PMU_NUM_OF_REGISTERS; i++) {
- if (reg_p->offset == offset) {
- PRINT_DEBUG_EXTEND("%s <0x%04x> <- 0x%04x\n", reg_p->name,
- (uint32_t)offset, (uint32_t)val);
- s->reg[i] = val;
- return;
- }
- reg_p++;
- }
- PRINT_DEBUG("QEMU PMU ERROR: bad write offset 0x%04x\n", (uint32_t)offset);
-}
-
-static const MemoryRegionOps exynos4210_pmu_ops = {
- .read = exynos4210_pmu_read,
- .write = exynos4210_pmu_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- .unaligned = false
- }
-};
-
-static void exynos4210_pmu_reset(DeviceState *dev)
-{
- Exynos4210PmuState *s = EXYNOS4210_PMU(dev);
- unsigned i;
-
- /* Set default values for registers */
- for (i = 0; i < PMU_NUM_OF_REGISTERS; i++) {
- s->reg[i] = exynos4210_pmu_regs[i].reset_value;
- }
-}
-
-static int exynos4210_pmu_init(SysBusDevice *dev)
-{
- Exynos4210PmuState *s = EXYNOS4210_PMU(dev);
-
- /* memory mapping */
- memory_region_init_io(&s->iomem, OBJECT(dev), &exynos4210_pmu_ops, s,
- "exynos4210.pmu", EXYNOS4210_PMU_REGS_MEM_SIZE);
- sysbus_init_mmio(dev, &s->iomem);
- return 0;
-}
-
-static const VMStateDescription exynos4210_pmu_vmstate = {
- .name = "exynos4210.pmu",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(reg, Exynos4210PmuState, PMU_NUM_OF_REGISTERS),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void exynos4210_pmu_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = exynos4210_pmu_init;
- dc->reset = exynos4210_pmu_reset;
- dc->vmsd = &exynos4210_pmu_vmstate;
-}
-
-static const TypeInfo exynos4210_pmu_info = {
- .name = TYPE_EXYNOS4210_PMU,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(Exynos4210PmuState),
- .class_init = exynos4210_pmu_class_init,
-};
-
-static void exynos4210_pmu_register(void)
-{
- type_register_static(&exynos4210_pmu_info);
-}
-
-type_init(exynos4210_pmu_register)
diff --git a/qemu/hw/misc/hyperv_testdev.c b/qemu/hw/misc/hyperv_testdev.c
deleted file mode 100644
index 1883fd7f2..000000000
--- a/qemu/hw/misc/hyperv_testdev.c
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * QEMU KVM Hyper-V test device to support Hyper-V kvm-unit-tests
- *
- * Copyright (C) 2015 Andrey Smetanin <asmetanin@virtuozzo.com>
- *
- * Authors:
- * Andrey Smetanin <asmetanin@virtuozzo.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/qdev.h"
-#include "hw/isa/isa.h"
-#include "sysemu/kvm.h"
-#include "linux/kvm.h"
-#include "target-i386/hyperv.h"
-#include "kvm_i386.h"
-
-#define HV_TEST_DEV_MAX_SINT_ROUTES 64
-
-struct HypervTestDev {
- ISADevice parent_obj;
- MemoryRegion sint_control;
- HvSintRoute *sint_route[HV_TEST_DEV_MAX_SINT_ROUTES];
-};
-typedef struct HypervTestDev HypervTestDev;
-
-#define TYPE_HYPERV_TEST_DEV "hyperv-testdev"
-#define HYPERV_TEST_DEV(obj) \
- OBJECT_CHECK(HypervTestDev, (obj), TYPE_HYPERV_TEST_DEV)
-
-enum {
- HV_TEST_DEV_SINT_ROUTE_CREATE = 1,
- HV_TEST_DEV_SINT_ROUTE_DESTROY,
- HV_TEST_DEV_SINT_ROUTE_SET_SINT
-};
-
-static int alloc_sint_route_index(HypervTestDev *dev)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(dev->sint_route); i++) {
- if (dev->sint_route[i] == NULL) {
- return i;
- }
- }
- return -1;
-}
-
-static void free_sint_route_index(HypervTestDev *dev, int i)
-{
- assert(i >= 0 && i < ARRAY_SIZE(dev->sint_route));
- dev->sint_route[i] = NULL;
-}
-
-static int find_sint_route_index(HypervTestDev *dev, uint32_t vcpu_id,
- uint32_t sint)
-{
- HvSintRoute *sint_route;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(dev->sint_route); i++) {
- sint_route = dev->sint_route[i];
- if (sint_route && sint_route->vcpu_id == vcpu_id &&
- sint_route->sint == sint) {
- return i;
- }
- }
- return -1;
-}
-
-static void hv_synic_test_dev_control(HypervTestDev *dev, uint32_t ctl,
- uint32_t vcpu_id, uint32_t sint)
-{
- int i;
- HvSintRoute *sint_route;
-
- switch (ctl) {
- case HV_TEST_DEV_SINT_ROUTE_CREATE:
- i = alloc_sint_route_index(dev);
- assert(i >= 0);
- sint_route = kvm_hv_sint_route_create(vcpu_id, sint, NULL);
- assert(sint_route);
- dev->sint_route[i] = sint_route;
- break;
- case HV_TEST_DEV_SINT_ROUTE_DESTROY:
- i = find_sint_route_index(dev, vcpu_id, sint);
- assert(i >= 0);
- sint_route = dev->sint_route[i];
- kvm_hv_sint_route_destroy(sint_route);
- free_sint_route_index(dev, i);
- break;
- case HV_TEST_DEV_SINT_ROUTE_SET_SINT:
- i = find_sint_route_index(dev, vcpu_id, sint);
- assert(i >= 0);
- sint_route = dev->sint_route[i];
- kvm_hv_sint_route_set_sint(sint_route);
- break;
- default:
- break;
- }
-}
-
-static void hv_test_dev_control(void *opaque, hwaddr addr, uint64_t data,
- uint32_t len)
-{
- HypervTestDev *dev = HYPERV_TEST_DEV(opaque);
- uint8_t ctl;
-
- ctl = (data >> 16ULL) & 0xFF;
- switch (ctl) {
- case HV_TEST_DEV_SINT_ROUTE_CREATE:
- case HV_TEST_DEV_SINT_ROUTE_DESTROY:
- case HV_TEST_DEV_SINT_ROUTE_SET_SINT: {
- uint8_t sint = data & 0xFF;
- uint8_t vcpu_id = (data >> 8ULL) & 0xFF;
- hv_synic_test_dev_control(dev, ctl, vcpu_id, sint);
- break;
- }
- default:
- break;
- }
-}
-
-static const MemoryRegionOps synic_test_sint_ops = {
- .write = hv_test_dev_control,
- .valid.min_access_size = 4,
- .valid.max_access_size = 4,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void hv_test_dev_realizefn(DeviceState *d, Error **errp)
-{
- ISADevice *isa = ISA_DEVICE(d);
- HypervTestDev *dev = HYPERV_TEST_DEV(d);
- MemoryRegion *io = isa_address_space_io(isa);
-
- memset(dev->sint_route, 0, sizeof(dev->sint_route));
- memory_region_init_io(&dev->sint_control, OBJECT(dev),
- &synic_test_sint_ops, dev,
- "hyperv-testdev-ctl", 4);
- memory_region_add_subregion(io, 0x3000, &dev->sint_control);
-}
-
-static void hv_test_dev_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- dc->realize = hv_test_dev_realizefn;
-}
-
-static const TypeInfo hv_test_dev_info = {
- .name = TYPE_HYPERV_TEST_DEV,
- .parent = TYPE_ISA_DEVICE,
- .instance_size = sizeof(HypervTestDev),
- .class_init = hv_test_dev_class_init,
-};
-
-static void hv_test_dev_register_types(void)
-{
- type_register_static(&hv_test_dev_info);
-}
-type_init(hv_test_dev_register_types);
diff --git a/qemu/hw/misc/imx25_ccm.c b/qemu/hw/misc/imx25_ccm.c
deleted file mode 100644
index 225604d82..000000000
--- a/qemu/hw/misc/imx25_ccm.c
+++ /dev/null
@@ -1,317 +0,0 @@
-/*
- * IMX25 Clock Control Module
- *
- * Copyright (C) 2012 NICTA
- * Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- * To get the timer frequencies right, we need to emulate at least part of
- * the CCM.
- */
-
-#include "qemu/osdep.h"
-#include "hw/misc/imx25_ccm.h"
-
-#ifndef DEBUG_IMX25_CCM
-#define DEBUG_IMX25_CCM 0
-#endif
-
-#define DPRINTF(fmt, args...) \
- do { \
- if (DEBUG_IMX25_CCM) { \
- fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX25_CCM, \
- __func__, ##args); \
- } \
- } while (0)
-
-static char const *imx25_ccm_reg_name(uint32_t reg)
-{
- static char unknown[20];
-
- switch (reg) {
- case IMX25_CCM_MPCTL_REG:
- return "mpctl";
- case IMX25_CCM_UPCTL_REG:
- return "upctl";
- case IMX25_CCM_CCTL_REG:
- return "cctl";
- case IMX25_CCM_CGCR0_REG:
- return "cgcr0";
- case IMX25_CCM_CGCR1_REG:
- return "cgcr1";
- case IMX25_CCM_CGCR2_REG:
- return "cgcr2";
- case IMX25_CCM_PCDR0_REG:
- return "pcdr0";
- case IMX25_CCM_PCDR1_REG:
- return "pcdr1";
- case IMX25_CCM_PCDR2_REG:
- return "pcdr2";
- case IMX25_CCM_PCDR3_REG:
- return "pcdr3";
- case IMX25_CCM_RCSR_REG:
- return "rcsr";
- case IMX25_CCM_CRDR_REG:
- return "crdr";
- case IMX25_CCM_DCVR0_REG:
- return "dcvr0";
- case IMX25_CCM_DCVR1_REG:
- return "dcvr1";
- case IMX25_CCM_DCVR2_REG:
- return "dcvr2";
- case IMX25_CCM_DCVR3_REG:
- return "dcvr3";
- case IMX25_CCM_LTR0_REG:
- return "ltr0";
- case IMX25_CCM_LTR1_REG:
- return "ltr1";
- case IMX25_CCM_LTR2_REG:
- return "ltr2";
- case IMX25_CCM_LTR3_REG:
- return "ltr3";
- case IMX25_CCM_LTBR0_REG:
- return "ltbr0";
- case IMX25_CCM_LTBR1_REG:
- return "ltbr1";
- case IMX25_CCM_PMCR0_REG:
- return "pmcr0";
- case IMX25_CCM_PMCR1_REG:
- return "pmcr1";
- case IMX25_CCM_PMCR2_REG:
- return "pmcr2";
- case IMX25_CCM_MCR_REG:
- return "mcr";
- case IMX25_CCM_LPIMR0_REG:
- return "lpimr0";
- case IMX25_CCM_LPIMR1_REG:
- return "lpimr1";
- default:
- sprintf(unknown, "[%d ?]", reg);
- return unknown;
- }
-}
-#define CKIH_FREQ 24000000 /* 24MHz crystal input */
-
-static const VMStateDescription vmstate_imx25_ccm = {
- .name = TYPE_IMX25_CCM,
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(reg, IMX25CCMState, IMX25_CCM_MAX_REG),
- VMSTATE_END_OF_LIST()
- },
-};
-
-static uint32_t imx25_ccm_get_mpll_clk(IMXCCMState *dev)
-{
- uint32_t freq;
- IMX25CCMState *s = IMX25_CCM(dev);
-
- if (EXTRACT(s->reg[IMX25_CCM_CCTL_REG], MPLL_BYPASS)) {
- freq = CKIH_FREQ;
- } else {
- freq = imx_ccm_calc_pll(s->reg[IMX25_CCM_MPCTL_REG], CKIH_FREQ);
- }
-
- DPRINTF("freq = %d\n", freq);
-
- return freq;
-}
-
-static uint32_t imx25_ccm_get_mcu_clk(IMXCCMState *dev)
-{
- uint32_t freq;
- IMX25CCMState *s = IMX25_CCM(dev);
-
- freq = imx25_ccm_get_mpll_clk(dev);
-
- if (EXTRACT(s->reg[IMX25_CCM_CCTL_REG], ARM_SRC)) {
- freq = (freq * 3 / 4);
- }
-
- freq = freq / (1 + EXTRACT(s->reg[IMX25_CCM_CCTL_REG], ARM_CLK_DIV));
-
- DPRINTF("freq = %d\n", freq);
-
- return freq;
-}
-
-static uint32_t imx25_ccm_get_ahb_clk(IMXCCMState *dev)
-{
- uint32_t freq;
- IMX25CCMState *s = IMX25_CCM(dev);
-
- freq = imx25_ccm_get_mcu_clk(dev)
- / (1 + EXTRACT(s->reg[IMX25_CCM_CCTL_REG], AHB_CLK_DIV));
-
- DPRINTF("freq = %d\n", freq);
-
- return freq;
-}
-
-static uint32_t imx25_ccm_get_ipg_clk(IMXCCMState *dev)
-{
- uint32_t freq;
-
- freq = imx25_ccm_get_ahb_clk(dev) / 2;
-
- DPRINTF("freq = %d\n", freq);
-
- return freq;
-}
-
-static uint32_t imx25_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock)
-{
- uint32_t freq = 0;
- DPRINTF("Clock = %d)\n", clock);
-
- switch (clock) {
- case CLK_NONE:
- break;
- case CLK_IPG:
- case CLK_IPG_HIGH:
- freq = imx25_ccm_get_ipg_clk(dev);
- break;
- case CLK_32k:
- freq = CKIL_FREQ;
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: unsupported clock %d\n",
- TYPE_IMX25_CCM, __func__, clock);
- break;
- }
-
- DPRINTF("Clock = %d) = %d\n", clock, freq);
-
- return freq;
-}
-
-static void imx25_ccm_reset(DeviceState *dev)
-{
- IMX25CCMState *s = IMX25_CCM(dev);
-
- DPRINTF("\n");
-
- memset(s->reg, 0, IMX25_CCM_MAX_REG * sizeof(uint32_t));
- s->reg[IMX25_CCM_MPCTL_REG] = 0x800b2c01;
- s->reg[IMX25_CCM_UPCTL_REG] = 0x84042800;
- /*
- * The value below gives:
- * CPU = 133 MHz, AHB = 66,5 MHz, IPG = 33 MHz.
- */
- s->reg[IMX25_CCM_CCTL_REG] = 0xd0030000;
- s->reg[IMX25_CCM_CGCR0_REG] = 0x028A0100;
- s->reg[IMX25_CCM_CGCR1_REG] = 0x04008100;
- s->reg[IMX25_CCM_CGCR2_REG] = 0x00000438;
- s->reg[IMX25_CCM_PCDR0_REG] = 0x01010101;
- s->reg[IMX25_CCM_PCDR1_REG] = 0x01010101;
- s->reg[IMX25_CCM_PCDR2_REG] = 0x01010101;
- s->reg[IMX25_CCM_PCDR3_REG] = 0x01010101;
- s->reg[IMX25_CCM_PMCR0_REG] = 0x00A00000;
- s->reg[IMX25_CCM_PMCR1_REG] = 0x0000A030;
- s->reg[IMX25_CCM_PMCR2_REG] = 0x0000A030;
- s->reg[IMX25_CCM_MCR_REG] = 0x43000000;
-
- /*
- * default boot will change the reset values to allow:
- * CPU = 399 MHz, AHB = 133 MHz, IPG = 66,5 MHz.
- * For some reason, this doesn't work. With the value below, linux
- * detects a 88 MHz IPG CLK instead of 66,5 MHz.
- s->reg[IMX25_CCM_CCTL_REG] = 0x20032000;
- */
-}
-
-static uint64_t imx25_ccm_read(void *opaque, hwaddr offset, unsigned size)
-{
- uint32_t value = 0;
- IMX25CCMState *s = (IMX25CCMState *)opaque;
-
- if (offset < 0x70) {
- value = s->reg[offset >> 2];
- } else {
- qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
- HWADDR_PRIx "\n", TYPE_IMX25_CCM, __func__, offset);
- }
-
- DPRINTF("reg[%s] => 0x%" PRIx32 "\n", imx25_ccm_reg_name(offset >> 2),
- value);
-
- return value;
-}
-
-static void imx25_ccm_write(void *opaque, hwaddr offset, uint64_t value,
- unsigned size)
-{
- IMX25CCMState *s = (IMX25CCMState *)opaque;
-
- DPRINTF("reg[%s] <= 0x%" PRIx32 "\n", imx25_ccm_reg_name(offset >> 2),
- (uint32_t)value);
-
- if (offset < 0x70) {
- /*
- * We will do a better implementation later. In particular some bits
- * cannot be written to.
- */
- s->reg[offset >> 2] = value;
- } else {
- qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
- HWADDR_PRIx "\n", TYPE_IMX25_CCM, __func__, offset);
- }
-}
-
-static const struct MemoryRegionOps imx25_ccm_ops = {
- .read = imx25_ccm_read,
- .write = imx25_ccm_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- /*
- * Our device would not work correctly if the guest was doing
- * unaligned access. This might not be a limitation on the real
- * device but in practice there is no reason for a guest to access
- * this device unaligned.
- */
- .min_access_size = 4,
- .max_access_size = 4,
- .unaligned = false,
- },
-};
-
-static void imx25_ccm_init(Object *obj)
-{
- DeviceState *dev = DEVICE(obj);
- SysBusDevice *sd = SYS_BUS_DEVICE(obj);
- IMX25CCMState *s = IMX25_CCM(obj);
-
- memory_region_init_io(&s->iomem, OBJECT(dev), &imx25_ccm_ops, s,
- TYPE_IMX25_CCM, 0x1000);
- sysbus_init_mmio(sd, &s->iomem);
-}
-
-static void imx25_ccm_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- IMXCCMClass *ccm = IMX_CCM_CLASS(klass);
-
- dc->reset = imx25_ccm_reset;
- dc->vmsd = &vmstate_imx25_ccm;
- dc->desc = "i.MX25 Clock Control Module";
-
- ccm->get_clock_frequency = imx25_ccm_get_clock_frequency;
-}
-
-static const TypeInfo imx25_ccm_info = {
- .name = TYPE_IMX25_CCM,
- .parent = TYPE_IMX_CCM,
- .instance_size = sizeof(IMX25CCMState),
- .instance_init = imx25_ccm_init,
- .class_init = imx25_ccm_class_init,
-};
-
-static void imx25_ccm_register_types(void)
-{
- type_register_static(&imx25_ccm_info);
-}
-
-type_init(imx25_ccm_register_types)
diff --git a/qemu/hw/misc/imx31_ccm.c b/qemu/hw/misc/imx31_ccm.c
deleted file mode 100644
index 80c164716..000000000
--- a/qemu/hw/misc/imx31_ccm.c
+++ /dev/null
@@ -1,344 +0,0 @@
-/*
- * IMX31 Clock Control Module
- *
- * Copyright (C) 2012 NICTA
- * Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- * To get the timer frequencies right, we need to emulate at least part of
- * the i.MX31 CCM.
- */
-
-#include "qemu/osdep.h"
-#include "hw/misc/imx31_ccm.h"
-
-#define CKIH_FREQ 26000000 /* 26MHz crystal input */
-
-#ifndef DEBUG_IMX31_CCM
-#define DEBUG_IMX31_CCM 0
-#endif
-
-#define DPRINTF(fmt, args...) \
- do { \
- if (DEBUG_IMX31_CCM) { \
- fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX31_CCM, \
- __func__, ##args); \
- } \
- } while (0)
-
-static char const *imx31_ccm_reg_name(uint32_t reg)
-{
- static char unknown[20];
-
- switch (reg) {
- case IMX31_CCM_CCMR_REG:
- return "CCMR";
- case IMX31_CCM_PDR0_REG:
- return "PDR0";
- case IMX31_CCM_PDR1_REG:
- return "PDR1";
- case IMX31_CCM_RCSR_REG:
- return "RCSR";
- case IMX31_CCM_MPCTL_REG:
- return "MPCTL";
- case IMX31_CCM_UPCTL_REG:
- return "UPCTL";
- case IMX31_CCM_SPCTL_REG:
- return "SPCTL";
- case IMX31_CCM_COSR_REG:
- return "COSR";
- case IMX31_CCM_CGR0_REG:
- return "CGR0";
- case IMX31_CCM_CGR1_REG:
- return "CGR1";
- case IMX31_CCM_CGR2_REG:
- return "CGR2";
- case IMX31_CCM_WIMR_REG:
- return "WIMR";
- case IMX31_CCM_LDC_REG:
- return "LDC";
- case IMX31_CCM_DCVR0_REG:
- return "DCVR0";
- case IMX31_CCM_DCVR1_REG:
- return "DCVR1";
- case IMX31_CCM_DCVR2_REG:
- return "DCVR2";
- case IMX31_CCM_DCVR3_REG:
- return "DCVR3";
- case IMX31_CCM_LTR0_REG:
- return "LTR0";
- case IMX31_CCM_LTR1_REG:
- return "LTR1";
- case IMX31_CCM_LTR2_REG:
- return "LTR2";
- case IMX31_CCM_LTR3_REG:
- return "LTR3";
- case IMX31_CCM_LTBR0_REG:
- return "LTBR0";
- case IMX31_CCM_LTBR1_REG:
- return "LTBR1";
- case IMX31_CCM_PMCR0_REG:
- return "PMCR0";
- case IMX31_CCM_PMCR1_REG:
- return "PMCR1";
- case IMX31_CCM_PDR2_REG:
- return "PDR2";
- default:
- sprintf(unknown, "[%d ?]", reg);
- return unknown;
- }
-}
-
-static const VMStateDescription vmstate_imx31_ccm = {
- .name = TYPE_IMX31_CCM,
- .version_id = 2,
- .minimum_version_id = 2,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(reg, IMX31CCMState, IMX31_CCM_MAX_REG),
- VMSTATE_END_OF_LIST()
- },
-};
-
-static uint32_t imx31_ccm_get_pll_ref_clk(IMXCCMState *dev)
-{
- uint32_t freq = 0;
- IMX31CCMState *s = IMX31_CCM(dev);
-
- if ((s->reg[IMX31_CCM_CCMR_REG] & CCMR_PRCS) == 2) {
- if (s->reg[IMX31_CCM_CCMR_REG] & CCMR_FPME) {
- freq = CKIL_FREQ;
- if (s->reg[IMX31_CCM_CCMR_REG] & CCMR_FPMF) {
- freq *= 1024;
- }
- }
- } else {
- freq = CKIH_FREQ;
- }
-
- DPRINTF("freq = %d\n", freq);
-
- return freq;
-}
-
-static uint32_t imx31_ccm_get_mpll_clk(IMXCCMState *dev)
-{
- uint32_t freq;
- IMX31CCMState *s = IMX31_CCM(dev);
-
- freq = imx_ccm_calc_pll(s->reg[IMX31_CCM_MPCTL_REG],
- imx31_ccm_get_pll_ref_clk(dev));
-
- DPRINTF("freq = %d\n", freq);
-
- return freq;
-}
-
-static uint32_t imx31_ccm_get_mcu_main_clk(IMXCCMState *dev)
-{
- uint32_t freq;
- IMX31CCMState *s = IMX31_CCM(dev);
-
- if ((s->reg[IMX31_CCM_CCMR_REG] & CCMR_MDS) ||
- !(s->reg[IMX31_CCM_CCMR_REG] & CCMR_MPE)) {
- freq = imx31_ccm_get_pll_ref_clk(dev);
- } else {
- freq = imx31_ccm_get_mpll_clk(dev);
- }
-
- DPRINTF("freq = %d\n", freq);
-
- return freq;
-}
-
-static uint32_t imx31_ccm_get_hclk_clk(IMXCCMState *dev)
-{
- uint32_t freq;
- IMX31CCMState *s = IMX31_CCM(dev);
-
- freq = imx31_ccm_get_mcu_main_clk(dev)
- / (1 + EXTRACT(s->reg[IMX31_CCM_PDR0_REG], MAX));
-
- DPRINTF("freq = %d\n", freq);
-
- return freq;
-}
-
-static uint32_t imx31_ccm_get_ipg_clk(IMXCCMState *dev)
-{
- uint32_t freq;
- IMX31CCMState *s = IMX31_CCM(dev);
-
- freq = imx31_ccm_get_hclk_clk(dev)
- / (1 + EXTRACT(s->reg[IMX31_CCM_PDR0_REG], IPG));
-
- DPRINTF("freq = %d\n", freq);
-
- return freq;
-}
-
-static uint32_t imx31_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock)
-{
- uint32_t freq = 0;
-
- switch (clock) {
- case CLK_NONE:
- break;
- case CLK_IPG:
- case CLK_IPG_HIGH:
- freq = imx31_ccm_get_ipg_clk(dev);
- break;
- case CLK_32k:
- freq = CKIL_FREQ;
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: unsupported clock %d\n",
- TYPE_IMX31_CCM, __func__, clock);
- break;
- }
-
- DPRINTF("Clock = %d) = %d\n", clock, freq);
-
- return freq;
-}
-
-static void imx31_ccm_reset(DeviceState *dev)
-{
- IMX31CCMState *s = IMX31_CCM(dev);
-
- DPRINTF("()\n");
-
- memset(s->reg, 0, sizeof(uint32_t) * IMX31_CCM_MAX_REG);
-
- s->reg[IMX31_CCM_CCMR_REG] = 0x074b0b7d;
- s->reg[IMX31_CCM_PDR0_REG] = 0xff870b48;
- s->reg[IMX31_CCM_PDR1_REG] = 0x49fcfe7f;
- s->reg[IMX31_CCM_RCSR_REG] = 0x007f0000;
- s->reg[IMX31_CCM_MPCTL_REG] = 0x04001800;
- s->reg[IMX31_CCM_UPCTL_REG] = 0x04051c03;
- s->reg[IMX31_CCM_SPCTL_REG] = 0x04043001;
- s->reg[IMX31_CCM_COSR_REG] = 0x00000280;
- s->reg[IMX31_CCM_CGR0_REG] = 0xffffffff;
- s->reg[IMX31_CCM_CGR1_REG] = 0xffffffff;
- s->reg[IMX31_CCM_CGR2_REG] = 0xffffffff;
- s->reg[IMX31_CCM_WIMR_REG] = 0xffffffff;
- s->reg[IMX31_CCM_LTR1_REG] = 0x00004040;
- s->reg[IMX31_CCM_PMCR0_REG] = 0x80209828;
- s->reg[IMX31_CCM_PMCR1_REG] = 0x00aa0000;
- s->reg[IMX31_CCM_PDR2_REG] = 0x00000285;
-}
-
-static uint64_t imx31_ccm_read(void *opaque, hwaddr offset, unsigned size)
-{
- uint32_t value = 0;
- IMX31CCMState *s = (IMX31CCMState *)opaque;
-
- if ((offset >> 2) < IMX31_CCM_MAX_REG) {
- value = s->reg[offset >> 2];
- } else {
- qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
- HWADDR_PRIx "\n", TYPE_IMX31_CCM, __func__, offset);
- }
-
- DPRINTF("reg[%s] => 0x%" PRIx32 "\n", imx31_ccm_reg_name(offset >> 2),
- value);
-
- return (uint64_t)value;
-}
-
-static void imx31_ccm_write(void *opaque, hwaddr offset, uint64_t value,
- unsigned size)
-{
- IMX31CCMState *s = (IMX31CCMState *)opaque;
-
- DPRINTF("reg[%s] <= 0x%" PRIx32 "\n", imx31_ccm_reg_name(offset >> 2),
- (uint32_t)value);
-
- switch (offset >> 2) {
- case IMX31_CCM_CCMR_REG:
- s->reg[IMX31_CCM_CCMR_REG] = CCMR_FPMF | (value & 0x3b6fdfff);
- break;
- case IMX31_CCM_PDR0_REG:
- s->reg[IMX31_CCM_PDR0_REG] = value & 0xff9f3fff;
- break;
- case IMX31_CCM_PDR1_REG:
- s->reg[IMX31_CCM_PDR1_REG] = value;
- break;
- case IMX31_CCM_MPCTL_REG:
- s->reg[IMX31_CCM_MPCTL_REG] = value & 0xbfff3fff;
- break;
- case IMX31_CCM_SPCTL_REG:
- s->reg[IMX31_CCM_SPCTL_REG] = value & 0xbfff3fff;
- break;
- case IMX31_CCM_CGR0_REG:
- s->reg[IMX31_CCM_CGR0_REG] = value;
- break;
- case IMX31_CCM_CGR1_REG:
- s->reg[IMX31_CCM_CGR1_REG] = value;
- break;
- case IMX31_CCM_CGR2_REG:
- s->reg[IMX31_CCM_CGR2_REG] = value;
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
- HWADDR_PRIx "\n", TYPE_IMX31_CCM, __func__, offset);
- break;
- }
-}
-
-static const struct MemoryRegionOps imx31_ccm_ops = {
- .read = imx31_ccm_read,
- .write = imx31_ccm_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- /*
- * Our device would not work correctly if the guest was doing
- * unaligned access. This might not be a limitation on the real
- * device but in practice there is no reason for a guest to access
- * this device unaligned.
- */
- .min_access_size = 4,
- .max_access_size = 4,
- .unaligned = false,
- },
-
-};
-
-static void imx31_ccm_init(Object *obj)
-{
- DeviceState *dev = DEVICE(obj);
- SysBusDevice *sd = SYS_BUS_DEVICE(obj);
- IMX31CCMState *s = IMX31_CCM(obj);
-
- memory_region_init_io(&s->iomem, OBJECT(dev), &imx31_ccm_ops, s,
- TYPE_IMX31_CCM, 0x1000);
- sysbus_init_mmio(sd, &s->iomem);
-}
-
-static void imx31_ccm_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- IMXCCMClass *ccm = IMX_CCM_CLASS(klass);
-
- dc->reset = imx31_ccm_reset;
- dc->vmsd = &vmstate_imx31_ccm;
- dc->desc = "i.MX31 Clock Control Module";
-
- ccm->get_clock_frequency = imx31_ccm_get_clock_frequency;
-}
-
-static const TypeInfo imx31_ccm_info = {
- .name = TYPE_IMX31_CCM,
- .parent = TYPE_IMX_CCM,
- .instance_size = sizeof(IMX31CCMState),
- .instance_init = imx31_ccm_init,
- .class_init = imx31_ccm_class_init,
-};
-
-static void imx31_ccm_register_types(void)
-{
- type_register_static(&imx31_ccm_info);
-}
-
-type_init(imx31_ccm_register_types)
diff --git a/qemu/hw/misc/imx6_ccm.c b/qemu/hw/misc/imx6_ccm.c
deleted file mode 100644
index 4e1d49da6..000000000
--- a/qemu/hw/misc/imx6_ccm.c
+++ /dev/null
@@ -1,774 +0,0 @@
-/*
- * IMX6 Clock Control Module
- *
- * Copyright (c) 2015 Jean-Christophe Dubois <jcd@tribudubois.net>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- * To get the timer frequencies right, we need to emulate at least part of
- * the CCM.
- */
-
-#include "qemu/osdep.h"
-#include "hw/misc/imx6_ccm.h"
-
-#ifndef DEBUG_IMX6_CCM
-#define DEBUG_IMX6_CCM 0
-#endif
-
-#define DPRINTF(fmt, args...) \
- do { \
- if (DEBUG_IMX6_CCM) { \
- fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX6_CCM, \
- __func__, ##args); \
- } \
- } while (0)
-
-static char const *imx6_ccm_reg_name(uint32_t reg)
-{
- static char unknown[20];
-
- switch (reg) {
- case CCM_CCR:
- return "CCR";
- case CCM_CCDR:
- return "CCDR";
- case CCM_CSR:
- return "CSR";
- case CCM_CCSR:
- return "CCSR";
- case CCM_CACRR:
- return "CACRR";
- case CCM_CBCDR:
- return "CBCDR";
- case CCM_CBCMR:
- return "CBCMR";
- case CCM_CSCMR1:
- return "CSCMR1";
- case CCM_CSCMR2:
- return "CSCMR2";
- case CCM_CSCDR1:
- return "CSCDR1";
- case CCM_CS1CDR:
- return "CS1CDR";
- case CCM_CS2CDR:
- return "CS2CDR";
- case CCM_CDCDR:
- return "CDCDR";
- case CCM_CHSCCDR:
- return "CHSCCDR";
- case CCM_CSCDR2:
- return "CSCDR2";
- case CCM_CSCDR3:
- return "CSCDR3";
- case CCM_CDHIPR:
- return "CDHIPR";
- case CCM_CTOR:
- return "CTOR";
- case CCM_CLPCR:
- return "CLPCR";
- case CCM_CISR:
- return "CISR";
- case CCM_CIMR:
- return "CIMR";
- case CCM_CCOSR:
- return "CCOSR";
- case CCM_CGPR:
- return "CGPR";
- case CCM_CCGR0:
- return "CCGR0";
- case CCM_CCGR1:
- return "CCGR1";
- case CCM_CCGR2:
- return "CCGR2";
- case CCM_CCGR3:
- return "CCGR3";
- case CCM_CCGR4:
- return "CCGR4";
- case CCM_CCGR5:
- return "CCGR5";
- case CCM_CCGR6:
- return "CCGR6";
- case CCM_CMEOR:
- return "CMEOR";
- default:
- sprintf(unknown, "%d ?", reg);
- return unknown;
- }
-}
-
-static char const *imx6_analog_reg_name(uint32_t reg)
-{
- static char unknown[20];
-
- switch (reg) {
- case CCM_ANALOG_PLL_ARM:
- return "PLL_ARM";
- case CCM_ANALOG_PLL_ARM_SET:
- return "PLL_ARM_SET";
- case CCM_ANALOG_PLL_ARM_CLR:
- return "PLL_ARM_CLR";
- case CCM_ANALOG_PLL_ARM_TOG:
- return "PLL_ARM_TOG";
- case CCM_ANALOG_PLL_USB1:
- return "PLL_USB1";
- case CCM_ANALOG_PLL_USB1_SET:
- return "PLL_USB1_SET";
- case CCM_ANALOG_PLL_USB1_CLR:
- return "PLL_USB1_CLR";
- case CCM_ANALOG_PLL_USB1_TOG:
- return "PLL_USB1_TOG";
- case CCM_ANALOG_PLL_USB2:
- return "PLL_USB2";
- case CCM_ANALOG_PLL_USB2_SET:
- return "PLL_USB2_SET";
- case CCM_ANALOG_PLL_USB2_CLR:
- return "PLL_USB2_CLR";
- case CCM_ANALOG_PLL_USB2_TOG:
- return "PLL_USB2_TOG";
- case CCM_ANALOG_PLL_SYS:
- return "PLL_SYS";
- case CCM_ANALOG_PLL_SYS_SET:
- return "PLL_SYS_SET";
- case CCM_ANALOG_PLL_SYS_CLR:
- return "PLL_SYS_CLR";
- case CCM_ANALOG_PLL_SYS_TOG:
- return "PLL_SYS_TOG";
- case CCM_ANALOG_PLL_SYS_SS:
- return "PLL_SYS_SS";
- case CCM_ANALOG_PLL_SYS_NUM:
- return "PLL_SYS_NUM";
- case CCM_ANALOG_PLL_SYS_DENOM:
- return "PLL_SYS_DENOM";
- case CCM_ANALOG_PLL_AUDIO:
- return "PLL_AUDIO";
- case CCM_ANALOG_PLL_AUDIO_SET:
- return "PLL_AUDIO_SET";
- case CCM_ANALOG_PLL_AUDIO_CLR:
- return "PLL_AUDIO_CLR";
- case CCM_ANALOG_PLL_AUDIO_TOG:
- return "PLL_AUDIO_TOG";
- case CCM_ANALOG_PLL_AUDIO_NUM:
- return "PLL_AUDIO_NUM";
- case CCM_ANALOG_PLL_AUDIO_DENOM:
- return "PLL_AUDIO_DENOM";
- case CCM_ANALOG_PLL_VIDEO:
- return "PLL_VIDEO";
- case CCM_ANALOG_PLL_VIDEO_SET:
- return "PLL_VIDEO_SET";
- case CCM_ANALOG_PLL_VIDEO_CLR:
- return "PLL_VIDEO_CLR";
- case CCM_ANALOG_PLL_VIDEO_TOG:
- return "PLL_VIDEO_TOG";
- case CCM_ANALOG_PLL_VIDEO_NUM:
- return "PLL_VIDEO_NUM";
- case CCM_ANALOG_PLL_VIDEO_DENOM:
- return "PLL_VIDEO_DENOM";
- case CCM_ANALOG_PLL_MLB:
- return "PLL_MLB";
- case CCM_ANALOG_PLL_MLB_SET:
- return "PLL_MLB_SET";
- case CCM_ANALOG_PLL_MLB_CLR:
- return "PLL_MLB_CLR";
- case CCM_ANALOG_PLL_MLB_TOG:
- return "PLL_MLB_TOG";
- case CCM_ANALOG_PLL_ENET:
- return "PLL_ENET";
- case CCM_ANALOG_PLL_ENET_SET:
- return "PLL_ENET_SET";
- case CCM_ANALOG_PLL_ENET_CLR:
- return "PLL_ENET_CLR";
- case CCM_ANALOG_PLL_ENET_TOG:
- return "PLL_ENET_TOG";
- case CCM_ANALOG_PFD_480:
- return "PFD_480";
- case CCM_ANALOG_PFD_480_SET:
- return "PFD_480_SET";
- case CCM_ANALOG_PFD_480_CLR:
- return "PFD_480_CLR";
- case CCM_ANALOG_PFD_480_TOG:
- return "PFD_480_TOG";
- case CCM_ANALOG_PFD_528:
- return "PFD_528";
- case CCM_ANALOG_PFD_528_SET:
- return "PFD_528_SET";
- case CCM_ANALOG_PFD_528_CLR:
- return "PFD_528_CLR";
- case CCM_ANALOG_PFD_528_TOG:
- return "PFD_528_TOG";
- case CCM_ANALOG_MISC0:
- return "MISC0";
- case CCM_ANALOG_MISC0_SET:
- return "MISC0_SET";
- case CCM_ANALOG_MISC0_CLR:
- return "MISC0_CLR";
- case CCM_ANALOG_MISC0_TOG:
- return "MISC0_TOG";
- case CCM_ANALOG_MISC2:
- return "MISC2";
- case CCM_ANALOG_MISC2_SET:
- return "MISC2_SET";
- case CCM_ANALOG_MISC2_CLR:
- return "MISC2_CLR";
- case CCM_ANALOG_MISC2_TOG:
- return "MISC2_TOG";
- case PMU_REG_1P1:
- return "PMU_REG_1P1";
- case PMU_REG_3P0:
- return "PMU_REG_3P0";
- case PMU_REG_2P5:
- return "PMU_REG_2P5";
- case PMU_REG_CORE:
- return "PMU_REG_CORE";
- case PMU_MISC1:
- return "PMU_MISC1";
- case PMU_MISC1_SET:
- return "PMU_MISC1_SET";
- case PMU_MISC1_CLR:
- return "PMU_MISC1_CLR";
- case PMU_MISC1_TOG:
- return "PMU_MISC1_TOG";
- case USB_ANALOG_DIGPROG:
- return "USB_ANALOG_DIGPROG";
- default:
- sprintf(unknown, "%d ?", reg);
- return unknown;
- }
-}
-
-#define CKIH_FREQ 24000000 /* 24MHz crystal input */
-
-static const VMStateDescription vmstate_imx6_ccm = {
- .name = TYPE_IMX6_CCM,
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(ccm, IMX6CCMState, CCM_MAX),
- VMSTATE_UINT32_ARRAY(analog, IMX6CCMState, CCM_ANALOG_MAX),
- VMSTATE_END_OF_LIST()
- },
-};
-
-static uint64_t imx6_analog_get_pll2_clk(IMX6CCMState *dev)
-{
- uint64_t freq = 24000000;
-
- if (EXTRACT(dev->analog[CCM_ANALOG_PLL_SYS], DIV_SELECT)) {
- freq *= 22;
- } else {
- freq *= 20;
- }
-
- DPRINTF("freq = %d\n", (uint32_t)freq);
-
- return freq;
-}
-
-static uint64_t imx6_analog_get_pll2_pfd0_clk(IMX6CCMState *dev)
-{
- uint64_t freq = 0;
-
- freq = imx6_analog_get_pll2_clk(dev) * 18
- / EXTRACT(dev->analog[CCM_ANALOG_PFD_528], PFD0_FRAC);
-
- DPRINTF("freq = %d\n", (uint32_t)freq);
-
- return freq;
-}
-
-static uint64_t imx6_analog_get_pll2_pfd2_clk(IMX6CCMState *dev)
-{
- uint64_t freq = 0;
-
- freq = imx6_analog_get_pll2_clk(dev) * 18
- / EXTRACT(dev->analog[CCM_ANALOG_PFD_528], PFD2_FRAC);
-
- DPRINTF("freq = %d\n", (uint32_t)freq);
-
- return freq;
-}
-
-static uint64_t imx6_analog_get_periph_clk(IMX6CCMState *dev)
-{
- uint64_t freq = 0;
-
- switch (EXTRACT(dev->ccm[CCM_CBCMR], PRE_PERIPH_CLK_SEL)) {
- case 0:
- freq = imx6_analog_get_pll2_clk(dev);
- break;
- case 1:
- freq = imx6_analog_get_pll2_pfd2_clk(dev);
- break;
- case 2:
- freq = imx6_analog_get_pll2_pfd0_clk(dev);
- break;
- case 3:
- freq = imx6_analog_get_pll2_pfd2_clk(dev) / 2;
- break;
- default:
- /* We should never get there */
- g_assert_not_reached();
- break;
- }
-
- DPRINTF("freq = %d\n", (uint32_t)freq);
-
- return freq;
-}
-
-static uint64_t imx6_ccm_get_ahb_clk(IMX6CCMState *dev)
-{
- uint64_t freq = 0;
-
- freq = imx6_analog_get_periph_clk(dev)
- / (1 + EXTRACT(dev->ccm[CCM_CBCDR], AHB_PODF));
-
- DPRINTF("freq = %d\n", (uint32_t)freq);
-
- return freq;
-}
-
-static uint64_t imx6_ccm_get_ipg_clk(IMX6CCMState *dev)
-{
- uint64_t freq = 0;
-
- freq = imx6_ccm_get_ahb_clk(dev)
- / (1 + EXTRACT(dev->ccm[CCM_CBCDR], IPG_PODF));;
-
- DPRINTF("freq = %d\n", (uint32_t)freq);
-
- return freq;
-}
-
-static uint64_t imx6_ccm_get_per_clk(IMX6CCMState *dev)
-{
- uint64_t freq = 0;
-
- freq = imx6_ccm_get_ipg_clk(dev)
- / (1 + EXTRACT(dev->ccm[CCM_CSCMR1], PERCLK_PODF));
-
- DPRINTF("freq = %d\n", (uint32_t)freq);
-
- return freq;
-}
-
-static uint32_t imx6_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock)
-{
- uint32_t freq = 0;
- IMX6CCMState *s = IMX6_CCM(dev);
-
- switch (clock) {
- case CLK_NONE:
- break;
- case CLK_IPG:
- freq = imx6_ccm_get_ipg_clk(s);
- break;
- case CLK_IPG_HIGH:
- freq = imx6_ccm_get_per_clk(s);
- break;
- case CLK_32k:
- freq = CKIL_FREQ;
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: unsupported clock %d\n",
- TYPE_IMX6_CCM, __func__, clock);
- break;
- }
-
- DPRINTF("Clock = %d) = %d\n", clock, freq);
-
- return freq;
-}
-
-static void imx6_ccm_reset(DeviceState *dev)
-{
- IMX6CCMState *s = IMX6_CCM(dev);
-
- DPRINTF("\n");
-
- s->ccm[CCM_CCR] = 0x040116FF;
- s->ccm[CCM_CCDR] = 0x00000000;
- s->ccm[CCM_CSR] = 0x00000010;
- s->ccm[CCM_CCSR] = 0x00000100;
- s->ccm[CCM_CACRR] = 0x00000000;
- s->ccm[CCM_CBCDR] = 0x00018D40;
- s->ccm[CCM_CBCMR] = 0x00022324;
- s->ccm[CCM_CSCMR1] = 0x00F00000;
- s->ccm[CCM_CSCMR2] = 0x02B92F06;
- s->ccm[CCM_CSCDR1] = 0x00490B00;
- s->ccm[CCM_CS1CDR] = 0x0EC102C1;
- s->ccm[CCM_CS2CDR] = 0x000736C1;
- s->ccm[CCM_CDCDR] = 0x33F71F92;
- s->ccm[CCM_CHSCCDR] = 0x0002A150;
- s->ccm[CCM_CSCDR2] = 0x0002A150;
- s->ccm[CCM_CSCDR3] = 0x00014841;
- s->ccm[CCM_CDHIPR] = 0x00000000;
- s->ccm[CCM_CTOR] = 0x00000000;
- s->ccm[CCM_CLPCR] = 0x00000079;
- s->ccm[CCM_CISR] = 0x00000000;
- s->ccm[CCM_CIMR] = 0xFFFFFFFF;
- s->ccm[CCM_CCOSR] = 0x000A0001;
- s->ccm[CCM_CGPR] = 0x0000FE62;
- s->ccm[CCM_CCGR0] = 0xFFFFFFFF;
- s->ccm[CCM_CCGR1] = 0xFFFFFFFF;
- s->ccm[CCM_CCGR2] = 0xFC3FFFFF;
- s->ccm[CCM_CCGR3] = 0xFFFFFFFF;
- s->ccm[CCM_CCGR4] = 0xFFFFFFFF;
- s->ccm[CCM_CCGR5] = 0xFFFFFFFF;
- s->ccm[CCM_CCGR6] = 0xFFFFFFFF;
- s->ccm[CCM_CMEOR] = 0xFFFFFFFF;
-
- s->analog[CCM_ANALOG_PLL_ARM] = 0x00013042;
- s->analog[CCM_ANALOG_PLL_USB1] = 0x00012000;
- s->analog[CCM_ANALOG_PLL_USB2] = 0x00012000;
- s->analog[CCM_ANALOG_PLL_SYS] = 0x00013001;
- s->analog[CCM_ANALOG_PLL_SYS_SS] = 0x00000000;
- s->analog[CCM_ANALOG_PLL_SYS_NUM] = 0x00000000;
- s->analog[CCM_ANALOG_PLL_SYS_DENOM] = 0x00000012;
- s->analog[CCM_ANALOG_PLL_AUDIO] = 0x00011006;
- s->analog[CCM_ANALOG_PLL_AUDIO_NUM] = 0x05F5E100;
- s->analog[CCM_ANALOG_PLL_AUDIO_DENOM] = 0x2964619C;
- s->analog[CCM_ANALOG_PLL_VIDEO] = 0x0001100C;
- s->analog[CCM_ANALOG_PLL_VIDEO_NUM] = 0x05F5E100;
- s->analog[CCM_ANALOG_PLL_VIDEO_DENOM] = 0x10A24447;
- s->analog[CCM_ANALOG_PLL_MLB] = 0x00010000;
- s->analog[CCM_ANALOG_PLL_ENET] = 0x00011001;
- s->analog[CCM_ANALOG_PFD_480] = 0x1311100C;
- s->analog[CCM_ANALOG_PFD_528] = 0x1018101B;
-
- s->analog[PMU_REG_1P1] = 0x00001073;
- s->analog[PMU_REG_3P0] = 0x00000F74;
- s->analog[PMU_REG_2P5] = 0x00005071;
- s->analog[PMU_REG_CORE] = 0x00402010;
- s->analog[PMU_MISC0] = 0x04000000;
- s->analog[PMU_MISC1] = 0x00000000;
- s->analog[PMU_MISC2] = 0x00272727;
-
- s->analog[USB_ANALOG_USB1_VBUS_DETECT] = 0x00000004;
- s->analog[USB_ANALOG_USB1_CHRG_DETECT] = 0x00000000;
- s->analog[USB_ANALOG_USB1_VBUS_DETECT_STAT] = 0x00000000;
- s->analog[USB_ANALOG_USB1_CHRG_DETECT_STAT] = 0x00000000;
- s->analog[USB_ANALOG_USB1_MISC] = 0x00000002;
- s->analog[USB_ANALOG_USB2_VBUS_DETECT] = 0x00000004;
- s->analog[USB_ANALOG_USB2_CHRG_DETECT] = 0x00000000;
- s->analog[USB_ANALOG_USB2_MISC] = 0x00000002;
- s->analog[USB_ANALOG_DIGPROG] = 0x00000000;
-
- /* all PLLs need to be locked */
- s->analog[CCM_ANALOG_PLL_ARM] |= CCM_ANALOG_PLL_LOCK;
- s->analog[CCM_ANALOG_PLL_USB1] |= CCM_ANALOG_PLL_LOCK;
- s->analog[CCM_ANALOG_PLL_USB2] |= CCM_ANALOG_PLL_LOCK;
- s->analog[CCM_ANALOG_PLL_SYS] |= CCM_ANALOG_PLL_LOCK;
- s->analog[CCM_ANALOG_PLL_AUDIO] |= CCM_ANALOG_PLL_LOCK;
- s->analog[CCM_ANALOG_PLL_VIDEO] |= CCM_ANALOG_PLL_LOCK;
- s->analog[CCM_ANALOG_PLL_MLB] |= CCM_ANALOG_PLL_LOCK;
- s->analog[CCM_ANALOG_PLL_ENET] |= CCM_ANALOG_PLL_LOCK;
-}
-
-static uint64_t imx6_ccm_read(void *opaque, hwaddr offset, unsigned size)
-{
- uint32_t value = 0;
- uint32_t index = offset >> 2;
- IMX6CCMState *s = (IMX6CCMState *)opaque;
-
- value = s->ccm[index];
-
- DPRINTF("reg[%s] => 0x%" PRIx32 "\n", imx6_ccm_reg_name(index), value);
-
- return (uint64_t)value;
-}
-
-static void imx6_ccm_write(void *opaque, hwaddr offset, uint64_t value,
- unsigned size)
-{
- uint32_t index = offset >> 2;
- IMX6CCMState *s = (IMX6CCMState *)opaque;
-
- DPRINTF("reg[%s] <= 0x%" PRIx32 "\n", imx6_ccm_reg_name(index),
- (uint32_t)value);
-
- /*
- * We will do a better implementation later. In particular some bits
- * cannot be written to.
- */
- s->ccm[index] = (uint32_t)value;
-}
-
-static uint64_t imx6_analog_read(void *opaque, hwaddr offset, unsigned size)
-{
- uint32_t value;
- uint32_t index = offset >> 2;
- IMX6CCMState *s = (IMX6CCMState *)opaque;
-
- switch (index) {
- case CCM_ANALOG_PLL_ARM_SET:
- case CCM_ANALOG_PLL_USB1_SET:
- case CCM_ANALOG_PLL_USB2_SET:
- case CCM_ANALOG_PLL_SYS_SET:
- case CCM_ANALOG_PLL_AUDIO_SET:
- case CCM_ANALOG_PLL_VIDEO_SET:
- case CCM_ANALOG_PLL_MLB_SET:
- case CCM_ANALOG_PLL_ENET_SET:
- case CCM_ANALOG_PFD_480_SET:
- case CCM_ANALOG_PFD_528_SET:
- case CCM_ANALOG_MISC0_SET:
- case PMU_MISC1_SET:
- case CCM_ANALOG_MISC2_SET:
- case USB_ANALOG_USB1_VBUS_DETECT_SET:
- case USB_ANALOG_USB1_CHRG_DETECT_SET:
- case USB_ANALOG_USB1_MISC_SET:
- case USB_ANALOG_USB2_VBUS_DETECT_SET:
- case USB_ANALOG_USB2_CHRG_DETECT_SET:
- case USB_ANALOG_USB2_MISC_SET:
- /*
- * All REG_NAME_SET register access are in fact targeting the
- * the REG_NAME register.
- */
- value = s->analog[index - 1];
- break;
- case CCM_ANALOG_PLL_ARM_CLR:
- case CCM_ANALOG_PLL_USB1_CLR:
- case CCM_ANALOG_PLL_USB2_CLR:
- case CCM_ANALOG_PLL_SYS_CLR:
- case CCM_ANALOG_PLL_AUDIO_CLR:
- case CCM_ANALOG_PLL_VIDEO_CLR:
- case CCM_ANALOG_PLL_MLB_CLR:
- case CCM_ANALOG_PLL_ENET_CLR:
- case CCM_ANALOG_PFD_480_CLR:
- case CCM_ANALOG_PFD_528_CLR:
- case CCM_ANALOG_MISC0_CLR:
- case PMU_MISC1_CLR:
- case CCM_ANALOG_MISC2_CLR:
- case USB_ANALOG_USB1_VBUS_DETECT_CLR:
- case USB_ANALOG_USB1_CHRG_DETECT_CLR:
- case USB_ANALOG_USB1_MISC_CLR:
- case USB_ANALOG_USB2_VBUS_DETECT_CLR:
- case USB_ANALOG_USB2_CHRG_DETECT_CLR:
- case USB_ANALOG_USB2_MISC_CLR:
- /*
- * All REG_NAME_CLR register access are in fact targeting the
- * the REG_NAME register.
- */
- value = s->analog[index - 2];
- break;
- case CCM_ANALOG_PLL_ARM_TOG:
- case CCM_ANALOG_PLL_USB1_TOG:
- case CCM_ANALOG_PLL_USB2_TOG:
- case CCM_ANALOG_PLL_SYS_TOG:
- case CCM_ANALOG_PLL_AUDIO_TOG:
- case CCM_ANALOG_PLL_VIDEO_TOG:
- case CCM_ANALOG_PLL_MLB_TOG:
- case CCM_ANALOG_PLL_ENET_TOG:
- case CCM_ANALOG_PFD_480_TOG:
- case CCM_ANALOG_PFD_528_TOG:
- case CCM_ANALOG_MISC0_TOG:
- case PMU_MISC1_TOG:
- case CCM_ANALOG_MISC2_TOG:
- case USB_ANALOG_USB1_VBUS_DETECT_TOG:
- case USB_ANALOG_USB1_CHRG_DETECT_TOG:
- case USB_ANALOG_USB1_MISC_TOG:
- case USB_ANALOG_USB2_VBUS_DETECT_TOG:
- case USB_ANALOG_USB2_CHRG_DETECT_TOG:
- case USB_ANALOG_USB2_MISC_TOG:
- /*
- * All REG_NAME_TOG register access are in fact targeting the
- * the REG_NAME register.
- */
- value = s->analog[index - 3];
- break;
- default:
- value = s->analog[index];
- break;
- }
-
- DPRINTF("reg[%s] => 0x%" PRIx32 "\n", imx6_analog_reg_name(index), value);
-
- return (uint64_t)value;
-}
-
-static void imx6_analog_write(void *opaque, hwaddr offset, uint64_t value,
- unsigned size)
-{
- uint32_t index = offset >> 2;
- IMX6CCMState *s = (IMX6CCMState *)opaque;
-
- DPRINTF("reg[%s] <= 0x%" PRIx32 "\n", imx6_analog_reg_name(index),
- (uint32_t)value);
-
- switch (index) {
- case CCM_ANALOG_PLL_ARM_SET:
- case CCM_ANALOG_PLL_USB1_SET:
- case CCM_ANALOG_PLL_USB2_SET:
- case CCM_ANALOG_PLL_SYS_SET:
- case CCM_ANALOG_PLL_AUDIO_SET:
- case CCM_ANALOG_PLL_VIDEO_SET:
- case CCM_ANALOG_PLL_MLB_SET:
- case CCM_ANALOG_PLL_ENET_SET:
- case CCM_ANALOG_PFD_480_SET:
- case CCM_ANALOG_PFD_528_SET:
- case CCM_ANALOG_MISC0_SET:
- case PMU_MISC1_SET:
- case CCM_ANALOG_MISC2_SET:
- case USB_ANALOG_USB1_VBUS_DETECT_SET:
- case USB_ANALOG_USB1_CHRG_DETECT_SET:
- case USB_ANALOG_USB1_MISC_SET:
- case USB_ANALOG_USB2_VBUS_DETECT_SET:
- case USB_ANALOG_USB2_CHRG_DETECT_SET:
- case USB_ANALOG_USB2_MISC_SET:
- /*
- * All REG_NAME_SET register access are in fact targeting the
- * the REG_NAME register. So we change the value of the
- * REG_NAME register, setting bits passed in the value.
- */
- s->analog[index - 1] |= value;
- break;
- case CCM_ANALOG_PLL_ARM_CLR:
- case CCM_ANALOG_PLL_USB1_CLR:
- case CCM_ANALOG_PLL_USB2_CLR:
- case CCM_ANALOG_PLL_SYS_CLR:
- case CCM_ANALOG_PLL_AUDIO_CLR:
- case CCM_ANALOG_PLL_VIDEO_CLR:
- case CCM_ANALOG_PLL_MLB_CLR:
- case CCM_ANALOG_PLL_ENET_CLR:
- case CCM_ANALOG_PFD_480_CLR:
- case CCM_ANALOG_PFD_528_CLR:
- case CCM_ANALOG_MISC0_CLR:
- case PMU_MISC1_CLR:
- case CCM_ANALOG_MISC2_CLR:
- case USB_ANALOG_USB1_VBUS_DETECT_CLR:
- case USB_ANALOG_USB1_CHRG_DETECT_CLR:
- case USB_ANALOG_USB1_MISC_CLR:
- case USB_ANALOG_USB2_VBUS_DETECT_CLR:
- case USB_ANALOG_USB2_CHRG_DETECT_CLR:
- case USB_ANALOG_USB2_MISC_CLR:
- /*
- * All REG_NAME_CLR register access are in fact targeting the
- * the REG_NAME register. So we change the value of the
- * REG_NAME register, unsetting bits passed in the value.
- */
- s->analog[index - 2] &= ~value;
- break;
- case CCM_ANALOG_PLL_ARM_TOG:
- case CCM_ANALOG_PLL_USB1_TOG:
- case CCM_ANALOG_PLL_USB2_TOG:
- case CCM_ANALOG_PLL_SYS_TOG:
- case CCM_ANALOG_PLL_AUDIO_TOG:
- case CCM_ANALOG_PLL_VIDEO_TOG:
- case CCM_ANALOG_PLL_MLB_TOG:
- case CCM_ANALOG_PLL_ENET_TOG:
- case CCM_ANALOG_PFD_480_TOG:
- case CCM_ANALOG_PFD_528_TOG:
- case CCM_ANALOG_MISC0_TOG:
- case PMU_MISC1_TOG:
- case CCM_ANALOG_MISC2_TOG:
- case USB_ANALOG_USB1_VBUS_DETECT_TOG:
- case USB_ANALOG_USB1_CHRG_DETECT_TOG:
- case USB_ANALOG_USB1_MISC_TOG:
- case USB_ANALOG_USB2_VBUS_DETECT_TOG:
- case USB_ANALOG_USB2_CHRG_DETECT_TOG:
- case USB_ANALOG_USB2_MISC_TOG:
- /*
- * All REG_NAME_TOG register access are in fact targeting the
- * the REG_NAME register. So we change the value of the
- * REG_NAME register, toggling bits passed in the value.
- */
- s->analog[index - 3] ^= value;
- break;
- default:
- /*
- * We will do a better implementation later. In particular some bits
- * cannot be written to.
- */
- s->analog[index] = value;
- break;
- }
-}
-
-static const struct MemoryRegionOps imx6_ccm_ops = {
- .read = imx6_ccm_read,
- .write = imx6_ccm_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- /*
- * Our device would not work correctly if the guest was doing
- * unaligned access. This might not be a limitation on the real
- * device but in practice there is no reason for a guest to access
- * this device unaligned.
- */
- .min_access_size = 4,
- .max_access_size = 4,
- .unaligned = false,
- },
-};
-
-static const struct MemoryRegionOps imx6_analog_ops = {
- .read = imx6_analog_read,
- .write = imx6_analog_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- /*
- * Our device would not work correctly if the guest was doing
- * unaligned access. This might not be a limitation on the real
- * device but in practice there is no reason for a guest to access
- * this device unaligned.
- */
- .min_access_size = 4,
- .max_access_size = 4,
- .unaligned = false,
- },
-};
-
-static void imx6_ccm_init(Object *obj)
-{
- DeviceState *dev = DEVICE(obj);
- SysBusDevice *sd = SYS_BUS_DEVICE(obj);
- IMX6CCMState *s = IMX6_CCM(obj);
-
- /* initialize a container for the all memory range */
- memory_region_init(&s->container, OBJECT(dev), TYPE_IMX6_CCM, 0x5000);
-
- /* We initialize an IO memory region for the CCM part */
- memory_region_init_io(&s->ioccm, OBJECT(dev), &imx6_ccm_ops, s,
- TYPE_IMX6_CCM ".ccm", CCM_MAX * sizeof(uint32_t));
-
- /* Add the CCM as a subregion at offset 0 */
- memory_region_add_subregion(&s->container, 0, &s->ioccm);
-
- /* We initialize an IO memory region for the ANALOG part */
- memory_region_init_io(&s->ioanalog, OBJECT(dev), &imx6_analog_ops, s,
- TYPE_IMX6_CCM ".analog",
- CCM_ANALOG_MAX * sizeof(uint32_t));
-
- /* Add the ANALOG as a subregion at offset 0x4000 */
- memory_region_add_subregion(&s->container, 0x4000, &s->ioanalog);
-
- sysbus_init_mmio(sd, &s->container);
-}
-
-static void imx6_ccm_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- IMXCCMClass *ccm = IMX_CCM_CLASS(klass);
-
- dc->reset = imx6_ccm_reset;
- dc->vmsd = &vmstate_imx6_ccm;
- dc->desc = "i.MX6 Clock Control Module";
-
- ccm->get_clock_frequency = imx6_ccm_get_clock_frequency;
-}
-
-static const TypeInfo imx6_ccm_info = {
- .name = TYPE_IMX6_CCM,
- .parent = TYPE_IMX_CCM,
- .instance_size = sizeof(IMX6CCMState),
- .instance_init = imx6_ccm_init,
- .class_init = imx6_ccm_class_init,
-};
-
-static void imx6_ccm_register_types(void)
-{
- type_register_static(&imx6_ccm_info);
-}
-
-type_init(imx6_ccm_register_types)
diff --git a/qemu/hw/misc/imx_ccm.c b/qemu/hw/misc/imx_ccm.c
deleted file mode 100644
index 986d890ca..000000000
--- a/qemu/hw/misc/imx_ccm.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * IMX31 Clock Control Module
- *
- * Copyright (C) 2012 NICTA
- * Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- * This is an abstract base class used to get a common interface to
- * retrieve the CCM frequencies from the various i.MX SOC.
- */
-
-#include "qemu/osdep.h"
-#include "hw/misc/imx_ccm.h"
-
-#ifndef DEBUG_IMX_CCM
-#define DEBUG_IMX_CCM 0
-#endif
-
-#define DPRINTF(fmt, args...) \
- do { \
- if (DEBUG_IMX_CCM) { \
- fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_CCM, \
- __func__, ##args); \
- } \
- } while (0)
-
-
-uint32_t imx_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock)
-{
- uint32_t freq = 0;
- IMXCCMClass *klass = IMX_GET_CLASS(dev);
-
- if (klass->get_clock_frequency) {
- freq = klass->get_clock_frequency(dev, clock);
- }
-
- DPRINTF("(clock = %d) = %d\n", clock, freq);
-
- return freq;
-}
-
-/*
- * Calculate PLL output frequency
- */
-uint32_t imx_ccm_calc_pll(uint32_t pllreg, uint32_t base_freq)
-{
- int32_t freq;
- int32_t mfn = MFN(pllreg); /* Numerator */
- uint32_t mfi = MFI(pllreg); /* Integer part */
- uint32_t mfd = 1 + MFD(pllreg); /* Denominator */
- uint32_t pd = 1 + PD(pllreg); /* Pre-divider */
-
- if (mfi < 5) {
- mfi = 5;
- }
-
- /* mfn is 10-bit signed twos-complement */
- mfn <<= 32 - 10;
- mfn >>= 32 - 10;
-
- freq = ((2 * (base_freq >> 10) * (mfi * mfd + mfn)) /
- (mfd * pd)) << 10;
-
- DPRINTF("(pllreg = 0x%08x, base_freq = %d) = %d\n", pllreg, base_freq,
- freq);
-
- return freq;
-}
-
-static const TypeInfo imx_ccm_info = {
- .name = TYPE_IMX_CCM,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(IMXCCMState),
- .class_size = sizeof(IMXCCMClass),
- .abstract = true,
-};
-
-static void imx_ccm_register_types(void)
-{
- type_register_static(&imx_ccm_info);
-}
-
-type_init(imx_ccm_register_types)
diff --git a/qemu/hw/misc/ivshmem.c b/qemu/hw/misc/ivshmem.c
deleted file mode 100644
index e40f23bfc..000000000
--- a/qemu/hw/misc/ivshmem.c
+++ /dev/null
@@ -1,1323 +0,0 @@
-/*
- * Inter-VM Shared Memory PCI device.
- *
- * Author:
- * Cam Macdonell <cam@cs.ualberta.ca>
- *
- * Based On: cirrus_vga.c
- * Copyright (c) 2004 Fabrice Bellard
- * Copyright (c) 2004 Makoto Suzuki (suzu)
- *
- * and rtl8139.c
- * Copyright (c) 2006 Igor Kovalenko
- *
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu/cutils.h"
-#include "hw/hw.h"
-#include "hw/i386/pc.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/msi.h"
-#include "hw/pci/msix.h"
-#include "sysemu/kvm.h"
-#include "migration/migration.h"
-#include "qemu/error-report.h"
-#include "qemu/event_notifier.h"
-#include "qom/object_interfaces.h"
-#include "sysemu/char.h"
-#include "sysemu/hostmem.h"
-#include "sysemu/qtest.h"
-#include "qapi/visitor.h"
-#include "exec/ram_addr.h"
-
-#include "hw/misc/ivshmem.h"
-
-#include <sys/mman.h>
-
-#define PCI_VENDOR_ID_IVSHMEM PCI_VENDOR_ID_REDHAT_QUMRANET
-#define PCI_DEVICE_ID_IVSHMEM 0x1110
-
-#define IVSHMEM_MAX_PEERS UINT16_MAX
-#define IVSHMEM_IOEVENTFD 0
-#define IVSHMEM_MSI 1
-
-#define IVSHMEM_REG_BAR_SIZE 0x100
-
-#define IVSHMEM_DEBUG 0
-#define IVSHMEM_DPRINTF(fmt, ...) \
- do { \
- if (IVSHMEM_DEBUG) { \
- printf("IVSHMEM: " fmt, ## __VA_ARGS__); \
- } \
- } while (0)
-
-#define TYPE_IVSHMEM_COMMON "ivshmem-common"
-#define IVSHMEM_COMMON(obj) \
- OBJECT_CHECK(IVShmemState, (obj), TYPE_IVSHMEM_COMMON)
-
-#define TYPE_IVSHMEM_PLAIN "ivshmem-plain"
-#define IVSHMEM_PLAIN(obj) \
- OBJECT_CHECK(IVShmemState, (obj), TYPE_IVSHMEM_PLAIN)
-
-#define TYPE_IVSHMEM_DOORBELL "ivshmem-doorbell"
-#define IVSHMEM_DOORBELL(obj) \
- OBJECT_CHECK(IVShmemState, (obj), TYPE_IVSHMEM_DOORBELL)
-
-#define TYPE_IVSHMEM "ivshmem"
-#define IVSHMEM(obj) \
- OBJECT_CHECK(IVShmemState, (obj), TYPE_IVSHMEM)
-
-typedef struct Peer {
- int nb_eventfds;
- EventNotifier *eventfds;
-} Peer;
-
-typedef struct MSIVector {
- PCIDevice *pdev;
- int virq;
-} MSIVector;
-
-typedef struct IVShmemState {
- /*< private >*/
- PCIDevice parent_obj;
- /*< public >*/
-
- uint32_t features;
-
- /* exactly one of these two may be set */
- HostMemoryBackend *hostmem; /* with interrupts */
- CharDriverState *server_chr; /* without interrupts */
-
- /* registers */
- uint32_t intrmask;
- uint32_t intrstatus;
- int vm_id;
-
- /* BARs */
- MemoryRegion ivshmem_mmio; /* BAR 0 (registers) */
- MemoryRegion *ivshmem_bar2; /* BAR 2 (shared memory) */
- MemoryRegion server_bar2; /* used with server_chr */
-
- /* interrupt support */
- Peer *peers;
- int nb_peers; /* space in @peers[] */
- uint32_t vectors;
- MSIVector *msi_vectors;
- uint64_t msg_buf; /* buffer for receiving server messages */
- int msg_buffered_bytes; /* #bytes in @msg_buf */
-
- /* migration stuff */
- OnOffAuto master;
- Error *migration_blocker;
-
- /* legacy cruft */
- char *role;
- char *shmobj;
- char *sizearg;
- size_t legacy_size;
- uint32_t not_legacy_32bit;
-} IVShmemState;
-
-/* registers for the Inter-VM shared memory device */
-enum ivshmem_registers {
- INTRMASK = 0,
- INTRSTATUS = 4,
- IVPOSITION = 8,
- DOORBELL = 12,
-};
-
-static inline uint32_t ivshmem_has_feature(IVShmemState *ivs,
- unsigned int feature) {
- return (ivs->features & (1 << feature));
-}
-
-static inline bool ivshmem_is_master(IVShmemState *s)
-{
- assert(s->master != ON_OFF_AUTO_AUTO);
- return s->master == ON_OFF_AUTO_ON;
-}
-
-static void ivshmem_update_irq(IVShmemState *s)
-{
- PCIDevice *d = PCI_DEVICE(s);
- uint32_t isr = s->intrstatus & s->intrmask;
-
- /*
- * Do nothing unless the device actually uses INTx. Here's how
- * the device variants signal interrupts, what they put in PCI
- * config space:
- * Device variant Interrupt Interrupt Pin MSI-X cap.
- * ivshmem-plain none 0 no
- * ivshmem-doorbell MSI-X 1 yes(1)
- * ivshmem,msi=off INTx 1 no
- * ivshmem,msi=on MSI-X 1(2) yes(1)
- * (1) if guest enabled MSI-X
- * (2) the device lies
- * Leads to the condition for doing nothing:
- */
- if (ivshmem_has_feature(s, IVSHMEM_MSI)
- || !d->config[PCI_INTERRUPT_PIN]) {
- return;
- }
-
- /* don't print ISR resets */
- if (isr) {
- IVSHMEM_DPRINTF("Set IRQ to %d (%04x %04x)\n",
- isr ? 1 : 0, s->intrstatus, s->intrmask);
- }
-
- pci_set_irq(d, isr != 0);
-}
-
-static void ivshmem_IntrMask_write(IVShmemState *s, uint32_t val)
-{
- IVSHMEM_DPRINTF("IntrMask write(w) val = 0x%04x\n", val);
-
- s->intrmask = val;
- ivshmem_update_irq(s);
-}
-
-static uint32_t ivshmem_IntrMask_read(IVShmemState *s)
-{
- uint32_t ret = s->intrmask;
-
- IVSHMEM_DPRINTF("intrmask read(w) val = 0x%04x\n", ret);
- return ret;
-}
-
-static void ivshmem_IntrStatus_write(IVShmemState *s, uint32_t val)
-{
- IVSHMEM_DPRINTF("IntrStatus write(w) val = 0x%04x\n", val);
-
- s->intrstatus = val;
- ivshmem_update_irq(s);
-}
-
-static uint32_t ivshmem_IntrStatus_read(IVShmemState *s)
-{
- uint32_t ret = s->intrstatus;
-
- /* reading ISR clears all interrupts */
- s->intrstatus = 0;
- ivshmem_update_irq(s);
- return ret;
-}
-
-static void ivshmem_io_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- IVShmemState *s = opaque;
-
- uint16_t dest = val >> 16;
- uint16_t vector = val & 0xff;
-
- addr &= 0xfc;
-
- IVSHMEM_DPRINTF("writing to addr " TARGET_FMT_plx "\n", addr);
- switch (addr)
- {
- case INTRMASK:
- ivshmem_IntrMask_write(s, val);
- break;
-
- case INTRSTATUS:
- ivshmem_IntrStatus_write(s, val);
- break;
-
- case DOORBELL:
- /* check that dest VM ID is reasonable */
- if (dest >= s->nb_peers) {
- IVSHMEM_DPRINTF("Invalid destination VM ID (%d)\n", dest);
- break;
- }
-
- /* check doorbell range */
- if (vector < s->peers[dest].nb_eventfds) {
- IVSHMEM_DPRINTF("Notifying VM %d on vector %d\n", dest, vector);
- event_notifier_set(&s->peers[dest].eventfds[vector]);
- } else {
- IVSHMEM_DPRINTF("Invalid destination vector %d on VM %d\n",
- vector, dest);
- }
- break;
- default:
- IVSHMEM_DPRINTF("Unhandled write " TARGET_FMT_plx "\n", addr);
- }
-}
-
-static uint64_t ivshmem_io_read(void *opaque, hwaddr addr,
- unsigned size)
-{
-
- IVShmemState *s = opaque;
- uint32_t ret;
-
- switch (addr)
- {
- case INTRMASK:
- ret = ivshmem_IntrMask_read(s);
- break;
-
- case INTRSTATUS:
- ret = ivshmem_IntrStatus_read(s);
- break;
-
- case IVPOSITION:
- ret = s->vm_id;
- break;
-
- default:
- IVSHMEM_DPRINTF("why are we reading " TARGET_FMT_plx "\n", addr);
- ret = 0;
- }
-
- return ret;
-}
-
-static const MemoryRegionOps ivshmem_mmio_ops = {
- .read = ivshmem_io_read,
- .write = ivshmem_io_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .impl = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static void ivshmem_vector_notify(void *opaque)
-{
- MSIVector *entry = opaque;
- PCIDevice *pdev = entry->pdev;
- IVShmemState *s = IVSHMEM_COMMON(pdev);
- int vector = entry - s->msi_vectors;
- EventNotifier *n = &s->peers[s->vm_id].eventfds[vector];
-
- if (!event_notifier_test_and_clear(n)) {
- return;
- }
-
- IVSHMEM_DPRINTF("interrupt on vector %p %d\n", pdev, vector);
- if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
- if (msix_enabled(pdev)) {
- msix_notify(pdev, vector);
- }
- } else {
- ivshmem_IntrStatus_write(s, 1);
- }
-}
-
-static int ivshmem_vector_unmask(PCIDevice *dev, unsigned vector,
- MSIMessage msg)
-{
- IVShmemState *s = IVSHMEM_COMMON(dev);
- EventNotifier *n = &s->peers[s->vm_id].eventfds[vector];
- MSIVector *v = &s->msi_vectors[vector];
- int ret;
-
- IVSHMEM_DPRINTF("vector unmask %p %d\n", dev, vector);
-
- ret = kvm_irqchip_update_msi_route(kvm_state, v->virq, msg, dev);
- if (ret < 0) {
- return ret;
- }
-
- return kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, n, NULL, v->virq);
-}
-
-static void ivshmem_vector_mask(PCIDevice *dev, unsigned vector)
-{
- IVShmemState *s = IVSHMEM_COMMON(dev);
- EventNotifier *n = &s->peers[s->vm_id].eventfds[vector];
- int ret;
-
- IVSHMEM_DPRINTF("vector mask %p %d\n", dev, vector);
-
- ret = kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, n,
- s->msi_vectors[vector].virq);
- if (ret != 0) {
- error_report("remove_irqfd_notifier_gsi failed");
- }
-}
-
-static void ivshmem_vector_poll(PCIDevice *dev,
- unsigned int vector_start,
- unsigned int vector_end)
-{
- IVShmemState *s = IVSHMEM_COMMON(dev);
- unsigned int vector;
-
- IVSHMEM_DPRINTF("vector poll %p %d-%d\n", dev, vector_start, vector_end);
-
- vector_end = MIN(vector_end, s->vectors);
-
- for (vector = vector_start; vector < vector_end; vector++) {
- EventNotifier *notifier = &s->peers[s->vm_id].eventfds[vector];
-
- if (!msix_is_masked(dev, vector)) {
- continue;
- }
-
- if (event_notifier_test_and_clear(notifier)) {
- msix_set_pending(dev, vector);
- }
- }
-}
-
-static void watch_vector_notifier(IVShmemState *s, EventNotifier *n,
- int vector)
-{
- int eventfd = event_notifier_get_fd(n);
-
- assert(!s->msi_vectors[vector].pdev);
- s->msi_vectors[vector].pdev = PCI_DEVICE(s);
-
- qemu_set_fd_handler(eventfd, ivshmem_vector_notify,
- NULL, &s->msi_vectors[vector]);
-}
-
-static void ivshmem_add_eventfd(IVShmemState *s, int posn, int i)
-{
- memory_region_add_eventfd(&s->ivshmem_mmio,
- DOORBELL,
- 4,
- true,
- (posn << 16) | i,
- &s->peers[posn].eventfds[i]);
-}
-
-static void ivshmem_del_eventfd(IVShmemState *s, int posn, int i)
-{
- memory_region_del_eventfd(&s->ivshmem_mmio,
- DOORBELL,
- 4,
- true,
- (posn << 16) | i,
- &s->peers[posn].eventfds[i]);
-}
-
-static void close_peer_eventfds(IVShmemState *s, int posn)
-{
- int i, n;
-
- assert(posn >= 0 && posn < s->nb_peers);
- n = s->peers[posn].nb_eventfds;
-
- if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
- memory_region_transaction_begin();
- for (i = 0; i < n; i++) {
- ivshmem_del_eventfd(s, posn, i);
- }
- memory_region_transaction_commit();
- }
-
- for (i = 0; i < n; i++) {
- event_notifier_cleanup(&s->peers[posn].eventfds[i]);
- }
-
- g_free(s->peers[posn].eventfds);
- s->peers[posn].nb_eventfds = 0;
-}
-
-static void resize_peers(IVShmemState *s, int nb_peers)
-{
- int old_nb_peers = s->nb_peers;
- int i;
-
- assert(nb_peers > old_nb_peers);
- IVSHMEM_DPRINTF("bumping storage to %d peers\n", nb_peers);
-
- s->peers = g_realloc(s->peers, nb_peers * sizeof(Peer));
- s->nb_peers = nb_peers;
-
- for (i = old_nb_peers; i < nb_peers; i++) {
- s->peers[i].eventfds = g_new0(EventNotifier, s->vectors);
- s->peers[i].nb_eventfds = 0;
- }
-}
-
-static void ivshmem_add_kvm_msi_virq(IVShmemState *s, int vector,
- Error **errp)
-{
- PCIDevice *pdev = PCI_DEVICE(s);
- MSIMessage msg = msix_get_message(pdev, vector);
- int ret;
-
- IVSHMEM_DPRINTF("ivshmem_add_kvm_msi_virq vector:%d\n", vector);
- assert(!s->msi_vectors[vector].pdev);
-
- ret = kvm_irqchip_add_msi_route(kvm_state, msg, pdev);
- if (ret < 0) {
- error_setg(errp, "kvm_irqchip_add_msi_route failed");
- return;
- }
-
- s->msi_vectors[vector].virq = ret;
- s->msi_vectors[vector].pdev = pdev;
-}
-
-static void setup_interrupt(IVShmemState *s, int vector, Error **errp)
-{
- EventNotifier *n = &s->peers[s->vm_id].eventfds[vector];
- bool with_irqfd = kvm_msi_via_irqfd_enabled() &&
- ivshmem_has_feature(s, IVSHMEM_MSI);
- PCIDevice *pdev = PCI_DEVICE(s);
- Error *err = NULL;
-
- IVSHMEM_DPRINTF("setting up interrupt for vector: %d\n", vector);
-
- if (!with_irqfd) {
- IVSHMEM_DPRINTF("with eventfd\n");
- watch_vector_notifier(s, n, vector);
- } else if (msix_enabled(pdev)) {
- IVSHMEM_DPRINTF("with irqfd\n");
- ivshmem_add_kvm_msi_virq(s, vector, &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- if (!msix_is_masked(pdev, vector)) {
- kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, n, NULL,
- s->msi_vectors[vector].virq);
- /* TODO handle error */
- }
- } else {
- /* it will be delayed until msix is enabled, in write_config */
- IVSHMEM_DPRINTF("with irqfd, delayed until msix enabled\n");
- }
-}
-
-static void process_msg_shmem(IVShmemState *s, int fd, Error **errp)
-{
- struct stat buf;
- size_t size;
- void *ptr;
-
- if (s->ivshmem_bar2) {
- error_setg(errp, "server sent unexpected shared memory message");
- close(fd);
- return;
- }
-
- if (fstat(fd, &buf) < 0) {
- error_setg_errno(errp, errno,
- "can't determine size of shared memory sent by server");
- close(fd);
- return;
- }
-
- size = buf.st_size;
-
- /* Legacy cruft */
- if (s->legacy_size != SIZE_MAX) {
- if (size < s->legacy_size) {
- error_setg(errp, "server sent only %zd bytes of shared memory",
- (size_t)buf.st_size);
- close(fd);
- return;
- }
- size = s->legacy_size;
- }
-
- /* mmap the region and map into the BAR2 */
- ptr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
- if (ptr == MAP_FAILED) {
- error_setg_errno(errp, errno, "Failed to mmap shared memory");
- close(fd);
- return;
- }
- memory_region_init_ram_ptr(&s->server_bar2, OBJECT(s),
- "ivshmem.bar2", size, ptr);
- qemu_set_ram_fd(memory_region_get_ram_addr(&s->server_bar2), fd);
- s->ivshmem_bar2 = &s->server_bar2;
-}
-
-static void process_msg_disconnect(IVShmemState *s, uint16_t posn,
- Error **errp)
-{
- IVSHMEM_DPRINTF("posn %d has gone away\n", posn);
- if (posn >= s->nb_peers || posn == s->vm_id) {
- error_setg(errp, "invalid peer %d", posn);
- return;
- }
- close_peer_eventfds(s, posn);
-}
-
-static void process_msg_connect(IVShmemState *s, uint16_t posn, int fd,
- Error **errp)
-{
- Peer *peer = &s->peers[posn];
- int vector;
-
- /*
- * The N-th connect message for this peer comes with the file
- * descriptor for vector N-1. Count messages to find the vector.
- */
- if (peer->nb_eventfds >= s->vectors) {
- error_setg(errp, "Too many eventfd received, device has %d vectors",
- s->vectors);
- close(fd);
- return;
- }
- vector = peer->nb_eventfds++;
-
- IVSHMEM_DPRINTF("eventfds[%d][%d] = %d\n", posn, vector, fd);
- event_notifier_init_fd(&peer->eventfds[vector], fd);
- fcntl_setfl(fd, O_NONBLOCK); /* msix/irqfd poll non block */
-
- if (posn == s->vm_id) {
- setup_interrupt(s, vector, errp);
- /* TODO do we need to handle the error? */
- }
-
- if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
- ivshmem_add_eventfd(s, posn, vector);
- }
-}
-
-static void process_msg(IVShmemState *s, int64_t msg, int fd, Error **errp)
-{
- IVSHMEM_DPRINTF("posn is %" PRId64 ", fd is %d\n", msg, fd);
-
- if (msg < -1 || msg > IVSHMEM_MAX_PEERS) {
- error_setg(errp, "server sent invalid message %" PRId64, msg);
- close(fd);
- return;
- }
-
- if (msg == -1) {
- process_msg_shmem(s, fd, errp);
- return;
- }
-
- if (msg >= s->nb_peers) {
- resize_peers(s, msg + 1);
- }
-
- if (fd >= 0) {
- process_msg_connect(s, msg, fd, errp);
- } else {
- process_msg_disconnect(s, msg, errp);
- }
-}
-
-static int ivshmem_can_receive(void *opaque)
-{
- IVShmemState *s = opaque;
-
- assert(s->msg_buffered_bytes < sizeof(s->msg_buf));
- return sizeof(s->msg_buf) - s->msg_buffered_bytes;
-}
-
-static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
-{
- IVShmemState *s = opaque;
- Error *err = NULL;
- int fd;
- int64_t msg;
-
- assert(size >= 0 && s->msg_buffered_bytes + size <= sizeof(s->msg_buf));
- memcpy((unsigned char *)&s->msg_buf + s->msg_buffered_bytes, buf, size);
- s->msg_buffered_bytes += size;
- if (s->msg_buffered_bytes < sizeof(s->msg_buf)) {
- return;
- }
- msg = le64_to_cpu(s->msg_buf);
- s->msg_buffered_bytes = 0;
-
- fd = qemu_chr_fe_get_msgfd(s->server_chr);
- IVSHMEM_DPRINTF("posn is %" PRId64 ", fd is %d\n", msg, fd);
-
- process_msg(s, msg, fd, &err);
- if (err) {
- error_report_err(err);
- }
-}
-
-static int64_t ivshmem_recv_msg(IVShmemState *s, int *pfd, Error **errp)
-{
- int64_t msg;
- int n, ret;
-
- n = 0;
- do {
- ret = qemu_chr_fe_read_all(s->server_chr, (uint8_t *)&msg + n,
- sizeof(msg) - n);
- if (ret < 0 && ret != -EINTR) {
- error_setg_errno(errp, -ret, "read from server failed");
- return INT64_MIN;
- }
- n += ret;
- } while (n < sizeof(msg));
-
- *pfd = qemu_chr_fe_get_msgfd(s->server_chr);
- return msg;
-}
-
-static void ivshmem_recv_setup(IVShmemState *s, Error **errp)
-{
- Error *err = NULL;
- int64_t msg;
- int fd;
-
- msg = ivshmem_recv_msg(s, &fd, &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- if (msg != IVSHMEM_PROTOCOL_VERSION) {
- error_setg(errp, "server sent version %" PRId64 ", expecting %d",
- msg, IVSHMEM_PROTOCOL_VERSION);
- return;
- }
- if (fd != -1) {
- error_setg(errp, "server sent invalid version message");
- return;
- }
-
- /*
- * ivshmem-server sends the remaining initial messages in a fixed
- * order, but the device has always accepted them in any order.
- * Stay as compatible as practical, just in case people use
- * servers that behave differently.
- */
-
- /*
- * ivshmem_device_spec.txt has always required the ID message
- * right here, and ivshmem-server has always complied. However,
- * older versions of the device accepted it out of order, but
- * broke when an interrupt setup message arrived before it.
- */
- msg = ivshmem_recv_msg(s, &fd, &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- if (fd != -1 || msg < 0 || msg > IVSHMEM_MAX_PEERS) {
- error_setg(errp, "server sent invalid ID message");
- return;
- }
- s->vm_id = msg;
-
- /*
- * Receive more messages until we got shared memory.
- */
- do {
- msg = ivshmem_recv_msg(s, &fd, &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- process_msg(s, msg, fd, &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- } while (msg != -1);
-
- /*
- * This function must either map the shared memory or fail. The
- * loop above ensures that: it terminates normally only after it
- * successfully processed the server's shared memory message.
- * Assert that actually mapped the shared memory:
- */
- assert(s->ivshmem_bar2);
-}
-
-/* Select the MSI-X vectors used by device.
- * ivshmem maps events to vectors statically, so
- * we just enable all vectors on init and after reset. */
-static void ivshmem_msix_vector_use(IVShmemState *s)
-{
- PCIDevice *d = PCI_DEVICE(s);
- int i;
-
- for (i = 0; i < s->vectors; i++) {
- msix_vector_use(d, i);
- }
-}
-
-static void ivshmem_reset(DeviceState *d)
-{
- IVShmemState *s = IVSHMEM_COMMON(d);
-
- s->intrstatus = 0;
- s->intrmask = 0;
- if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
- ivshmem_msix_vector_use(s);
- }
-}
-
-static int ivshmem_setup_interrupts(IVShmemState *s)
-{
- /* allocate QEMU callback data for receiving interrupts */
- s->msi_vectors = g_malloc0(s->vectors * sizeof(MSIVector));
-
- if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
- if (msix_init_exclusive_bar(PCI_DEVICE(s), s->vectors, 1)) {
- return -1;
- }
-
- IVSHMEM_DPRINTF("msix initialized (%d vectors)\n", s->vectors);
- ivshmem_msix_vector_use(s);
- }
-
- return 0;
-}
-
-static void ivshmem_enable_irqfd(IVShmemState *s)
-{
- PCIDevice *pdev = PCI_DEVICE(s);
- int i;
-
- for (i = 0; i < s->peers[s->vm_id].nb_eventfds; i++) {
- Error *err = NULL;
-
- ivshmem_add_kvm_msi_virq(s, i, &err);
- if (err) {
- error_report_err(err);
- /* TODO do we need to handle the error? */
- }
- }
-
- if (msix_set_vector_notifiers(pdev,
- ivshmem_vector_unmask,
- ivshmem_vector_mask,
- ivshmem_vector_poll)) {
- error_report("ivshmem: msix_set_vector_notifiers failed");
- }
-}
-
-static void ivshmem_remove_kvm_msi_virq(IVShmemState *s, int vector)
-{
- IVSHMEM_DPRINTF("ivshmem_remove_kvm_msi_virq vector:%d\n", vector);
-
- if (s->msi_vectors[vector].pdev == NULL) {
- return;
- }
-
- /* it was cleaned when masked in the frontend. */
- kvm_irqchip_release_virq(kvm_state, s->msi_vectors[vector].virq);
-
- s->msi_vectors[vector].pdev = NULL;
-}
-
-static void ivshmem_disable_irqfd(IVShmemState *s)
-{
- PCIDevice *pdev = PCI_DEVICE(s);
- int i;
-
- for (i = 0; i < s->peers[s->vm_id].nb_eventfds; i++) {
- ivshmem_remove_kvm_msi_virq(s, i);
- }
-
- msix_unset_vector_notifiers(pdev);
-}
-
-static void ivshmem_write_config(PCIDevice *pdev, uint32_t address,
- uint32_t val, int len)
-{
- IVShmemState *s = IVSHMEM_COMMON(pdev);
- int is_enabled, was_enabled = msix_enabled(pdev);
-
- pci_default_write_config(pdev, address, val, len);
- is_enabled = msix_enabled(pdev);
-
- if (kvm_msi_via_irqfd_enabled()) {
- if (!was_enabled && is_enabled) {
- ivshmem_enable_irqfd(s);
- } else if (was_enabled && !is_enabled) {
- ivshmem_disable_irqfd(s);
- }
- }
-}
-
-static void ivshmem_common_realize(PCIDevice *dev, Error **errp)
-{
- IVShmemState *s = IVSHMEM_COMMON(dev);
- Error *err = NULL;
- uint8_t *pci_conf;
- uint8_t attr = PCI_BASE_ADDRESS_SPACE_MEMORY |
- PCI_BASE_ADDRESS_MEM_PREFETCH;
-
- /* IRQFD requires MSI */
- if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD) &&
- !ivshmem_has_feature(s, IVSHMEM_MSI)) {
- error_setg(errp, "ioeventfd/irqfd requires MSI");
- return;
- }
-
- pci_conf = dev->config;
- pci_conf[PCI_COMMAND] = PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
-
- memory_region_init_io(&s->ivshmem_mmio, OBJECT(s), &ivshmem_mmio_ops, s,
- "ivshmem-mmio", IVSHMEM_REG_BAR_SIZE);
-
- /* region for registers*/
- pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY,
- &s->ivshmem_mmio);
-
- if (!s->not_legacy_32bit) {
- attr |= PCI_BASE_ADDRESS_MEM_TYPE_64;
- }
-
- if (s->hostmem != NULL) {
- IVSHMEM_DPRINTF("using hostmem\n");
-
- s->ivshmem_bar2 = host_memory_backend_get_memory(s->hostmem,
- &error_abort);
- } else {
- assert(s->server_chr);
-
- IVSHMEM_DPRINTF("using shared memory server (socket = %s)\n",
- s->server_chr->filename);
-
- /* we allocate enough space for 16 peers and grow as needed */
- resize_peers(s, 16);
-
- /*
- * Receive setup messages from server synchronously.
- * Older versions did it asynchronously, but that creates a
- * number of entertaining race conditions.
- */
- ivshmem_recv_setup(s, &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- if (s->master == ON_OFF_AUTO_ON && s->vm_id != 0) {
- error_setg(errp,
- "master must connect to the server before any peers");
- return;
- }
-
- qemu_chr_add_handlers(s->server_chr, ivshmem_can_receive,
- ivshmem_read, NULL, s);
-
- if (ivshmem_setup_interrupts(s) < 0) {
- error_setg(errp, "failed to initialize interrupts");
- return;
- }
- }
-
- vmstate_register_ram(s->ivshmem_bar2, DEVICE(s));
- pci_register_bar(PCI_DEVICE(s), 2, attr, s->ivshmem_bar2);
-
- if (s->master == ON_OFF_AUTO_AUTO) {
- s->master = s->vm_id == 0 ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
- }
-
- if (!ivshmem_is_master(s)) {
- error_setg(&s->migration_blocker,
- "Migration is disabled when using feature 'peer mode' in device 'ivshmem'");
- migrate_add_blocker(s->migration_blocker);
- }
-}
-
-static void ivshmem_exit(PCIDevice *dev)
-{
- IVShmemState *s = IVSHMEM_COMMON(dev);
- int i;
-
- if (s->migration_blocker) {
- migrate_del_blocker(s->migration_blocker);
- error_free(s->migration_blocker);
- }
-
- if (memory_region_is_mapped(s->ivshmem_bar2)) {
- if (!s->hostmem) {
- void *addr = memory_region_get_ram_ptr(s->ivshmem_bar2);
- int fd;
-
- if (munmap(addr, memory_region_size(s->ivshmem_bar2) == -1)) {
- error_report("Failed to munmap shared memory %s",
- strerror(errno));
- }
-
- fd = qemu_get_ram_fd(memory_region_get_ram_addr(s->ivshmem_bar2));
- close(fd);
- }
-
- vmstate_unregister_ram(s->ivshmem_bar2, DEVICE(dev));
- }
-
- if (s->peers) {
- for (i = 0; i < s->nb_peers; i++) {
- close_peer_eventfds(s, i);
- }
- g_free(s->peers);
- }
-
- if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
- msix_uninit_exclusive_bar(dev);
- }
-
- g_free(s->msi_vectors);
-}
-
-static int ivshmem_pre_load(void *opaque)
-{
- IVShmemState *s = opaque;
-
- if (!ivshmem_is_master(s)) {
- error_report("'peer' devices are not migratable");
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int ivshmem_post_load(void *opaque, int version_id)
-{
- IVShmemState *s = opaque;
-
- if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
- ivshmem_msix_vector_use(s);
- }
- return 0;
-}
-
-static void ivshmem_common_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = ivshmem_common_realize;
- k->exit = ivshmem_exit;
- k->config_write = ivshmem_write_config;
- k->vendor_id = PCI_VENDOR_ID_IVSHMEM;
- k->device_id = PCI_DEVICE_ID_IVSHMEM;
- k->class_id = PCI_CLASS_MEMORY_RAM;
- k->revision = 1;
- dc->reset = ivshmem_reset;
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- dc->desc = "Inter-VM shared memory";
-}
-
-static const TypeInfo ivshmem_common_info = {
- .name = TYPE_IVSHMEM_COMMON,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(IVShmemState),
- .abstract = true,
- .class_init = ivshmem_common_class_init,
-};
-
-static void ivshmem_check_memdev_is_busy(Object *obj, const char *name,
- Object *val, Error **errp)
-{
- MemoryRegion *mr;
-
- mr = host_memory_backend_get_memory(MEMORY_BACKEND(val), &error_abort);
- if (memory_region_is_mapped(mr)) {
- char *path = object_get_canonical_path_component(val);
- error_setg(errp, "can't use already busy memdev: %s", path);
- g_free(path);
- } else {
- qdev_prop_allow_set_link_before_realize(obj, name, val, errp);
- }
-}
-
-static const VMStateDescription ivshmem_plain_vmsd = {
- .name = TYPE_IVSHMEM_PLAIN,
- .version_id = 0,
- .minimum_version_id = 0,
- .pre_load = ivshmem_pre_load,
- .post_load = ivshmem_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(parent_obj, IVShmemState),
- VMSTATE_UINT32(intrstatus, IVShmemState),
- VMSTATE_UINT32(intrmask, IVShmemState),
- VMSTATE_END_OF_LIST()
- },
-};
-
-static Property ivshmem_plain_properties[] = {
- DEFINE_PROP_ON_OFF_AUTO("master", IVShmemState, master, ON_OFF_AUTO_OFF),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void ivshmem_plain_init(Object *obj)
-{
- IVShmemState *s = IVSHMEM_PLAIN(obj);
-
- object_property_add_link(obj, "memdev", TYPE_MEMORY_BACKEND,
- (Object **)&s->hostmem,
- ivshmem_check_memdev_is_busy,
- OBJ_PROP_LINK_UNREF_ON_RELEASE,
- &error_abort);
-}
-
-static void ivshmem_plain_realize(PCIDevice *dev, Error **errp)
-{
- IVShmemState *s = IVSHMEM_COMMON(dev);
-
- if (!s->hostmem) {
- error_setg(errp, "You must specify a 'memdev'");
- return;
- }
-
- ivshmem_common_realize(dev, errp);
-}
-
-static void ivshmem_plain_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = ivshmem_plain_realize;
- dc->props = ivshmem_plain_properties;
- dc->vmsd = &ivshmem_plain_vmsd;
-}
-
-static const TypeInfo ivshmem_plain_info = {
- .name = TYPE_IVSHMEM_PLAIN,
- .parent = TYPE_IVSHMEM_COMMON,
- .instance_size = sizeof(IVShmemState),
- .instance_init = ivshmem_plain_init,
- .class_init = ivshmem_plain_class_init,
-};
-
-static const VMStateDescription ivshmem_doorbell_vmsd = {
- .name = TYPE_IVSHMEM_DOORBELL,
- .version_id = 0,
- .minimum_version_id = 0,
- .pre_load = ivshmem_pre_load,
- .post_load = ivshmem_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(parent_obj, IVShmemState),
- VMSTATE_MSIX(parent_obj, IVShmemState),
- VMSTATE_UINT32(intrstatus, IVShmemState),
- VMSTATE_UINT32(intrmask, IVShmemState),
- VMSTATE_END_OF_LIST()
- },
-};
-
-static Property ivshmem_doorbell_properties[] = {
- DEFINE_PROP_CHR("chardev", IVShmemState, server_chr),
- DEFINE_PROP_UINT32("vectors", IVShmemState, vectors, 1),
- DEFINE_PROP_BIT("ioeventfd", IVShmemState, features, IVSHMEM_IOEVENTFD,
- true),
- DEFINE_PROP_ON_OFF_AUTO("master", IVShmemState, master, ON_OFF_AUTO_OFF),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void ivshmem_doorbell_init(Object *obj)
-{
- IVShmemState *s = IVSHMEM_DOORBELL(obj);
-
- s->features |= (1 << IVSHMEM_MSI);
- s->legacy_size = SIZE_MAX; /* whatever the server sends */
-}
-
-static void ivshmem_doorbell_realize(PCIDevice *dev, Error **errp)
-{
- IVShmemState *s = IVSHMEM_COMMON(dev);
-
- if (!s->server_chr) {
- error_setg(errp, "You must specify a 'chardev'");
- return;
- }
-
- ivshmem_common_realize(dev, errp);
-}
-
-static void ivshmem_doorbell_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = ivshmem_doorbell_realize;
- dc->props = ivshmem_doorbell_properties;
- dc->vmsd = &ivshmem_doorbell_vmsd;
-}
-
-static const TypeInfo ivshmem_doorbell_info = {
- .name = TYPE_IVSHMEM_DOORBELL,
- .parent = TYPE_IVSHMEM_COMMON,
- .instance_size = sizeof(IVShmemState),
- .instance_init = ivshmem_doorbell_init,
- .class_init = ivshmem_doorbell_class_init,
-};
-
-static int ivshmem_load_old(QEMUFile *f, void *opaque, int version_id)
-{
- IVShmemState *s = opaque;
- PCIDevice *pdev = PCI_DEVICE(s);
- int ret;
-
- IVSHMEM_DPRINTF("ivshmem_load_old\n");
-
- if (version_id != 0) {
- return -EINVAL;
- }
-
- ret = ivshmem_pre_load(s);
- if (ret) {
- return ret;
- }
-
- ret = pci_device_load(pdev, f);
- if (ret) {
- return ret;
- }
-
- if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
- msix_load(pdev, f);
- ivshmem_msix_vector_use(s);
- } else {
- s->intrstatus = qemu_get_be32(f);
- s->intrmask = qemu_get_be32(f);
- }
-
- return 0;
-}
-
-static bool test_msix(void *opaque, int version_id)
-{
- IVShmemState *s = opaque;
-
- return ivshmem_has_feature(s, IVSHMEM_MSI);
-}
-
-static bool test_no_msix(void *opaque, int version_id)
-{
- return !test_msix(opaque, version_id);
-}
-
-static const VMStateDescription ivshmem_vmsd = {
- .name = "ivshmem",
- .version_id = 1,
- .minimum_version_id = 1,
- .pre_load = ivshmem_pre_load,
- .post_load = ivshmem_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(parent_obj, IVShmemState),
-
- VMSTATE_MSIX_TEST(parent_obj, IVShmemState, test_msix),
- VMSTATE_UINT32_TEST(intrstatus, IVShmemState, test_no_msix),
- VMSTATE_UINT32_TEST(intrmask, IVShmemState, test_no_msix),
-
- VMSTATE_END_OF_LIST()
- },
- .load_state_old = ivshmem_load_old,
- .minimum_version_id_old = 0
-};
-
-static Property ivshmem_properties[] = {
- DEFINE_PROP_CHR("chardev", IVShmemState, server_chr),
- DEFINE_PROP_STRING("size", IVShmemState, sizearg),
- DEFINE_PROP_UINT32("vectors", IVShmemState, vectors, 1),
- DEFINE_PROP_BIT("ioeventfd", IVShmemState, features, IVSHMEM_IOEVENTFD,
- false),
- DEFINE_PROP_BIT("msi", IVShmemState, features, IVSHMEM_MSI, true),
- DEFINE_PROP_STRING("shm", IVShmemState, shmobj),
- DEFINE_PROP_STRING("role", IVShmemState, role),
- DEFINE_PROP_UINT32("use64", IVShmemState, not_legacy_32bit, 1),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void desugar_shm(IVShmemState *s)
-{
- Object *obj;
- char *path;
-
- obj = object_new("memory-backend-file");
- path = g_strdup_printf("/dev/shm/%s", s->shmobj);
- object_property_set_str(obj, path, "mem-path", &error_abort);
- g_free(path);
- object_property_set_int(obj, s->legacy_size, "size", &error_abort);
- object_property_set_bool(obj, true, "share", &error_abort);
- object_property_add_child(OBJECT(s), "internal-shm-backend", obj,
- &error_abort);
- user_creatable_complete(obj, &error_abort);
- s->hostmem = MEMORY_BACKEND(obj);
-}
-
-static void ivshmem_realize(PCIDevice *dev, Error **errp)
-{
- IVShmemState *s = IVSHMEM_COMMON(dev);
-
- if (!qtest_enabled()) {
- error_report("ivshmem is deprecated, please use ivshmem-plain"
- " or ivshmem-doorbell instead");
- }
-
- if (!!s->server_chr + !!s->shmobj != 1) {
- error_setg(errp, "You must specify either 'shm' or 'chardev'");
- return;
- }
-
- if (s->sizearg == NULL) {
- s->legacy_size = 4 << 20; /* 4 MB default */
- } else {
- char *end;
- int64_t size = qemu_strtosz(s->sizearg, &end);
- if (size < 0 || (size_t)size != size || *end != '\0'
- || !is_power_of_2(size)) {
- error_setg(errp, "Invalid size %s", s->sizearg);
- return;
- }
- s->legacy_size = size;
- }
-
- /* check that role is reasonable */
- if (s->role) {
- if (strncmp(s->role, "peer", 5) == 0) {
- s->master = ON_OFF_AUTO_OFF;
- } else if (strncmp(s->role, "master", 7) == 0) {
- s->master = ON_OFF_AUTO_ON;
- } else {
- error_setg(errp, "'role' must be 'peer' or 'master'");
- return;
- }
- } else {
- s->master = ON_OFF_AUTO_AUTO;
- }
-
- if (s->shmobj) {
- desugar_shm(s);
- }
-
- /*
- * Note: we don't use INTx with IVSHMEM_MSI at all, so this is a
- * bald-faced lie then. But it's a backwards compatible lie.
- */
- pci_config_set_interrupt_pin(dev->config, 1);
-
- ivshmem_common_realize(dev, errp);
-}
-
-static void ivshmem_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = ivshmem_realize;
- k->revision = 0;
- dc->desc = "Inter-VM shared memory (legacy)";
- dc->props = ivshmem_properties;
- dc->vmsd = &ivshmem_vmsd;
-}
-
-static const TypeInfo ivshmem_info = {
- .name = TYPE_IVSHMEM,
- .parent = TYPE_IVSHMEM_COMMON,
- .instance_size = sizeof(IVShmemState),
- .class_init = ivshmem_class_init,
-};
-
-static void ivshmem_register_types(void)
-{
- type_register_static(&ivshmem_common_info);
- type_register_static(&ivshmem_plain_info);
- type_register_static(&ivshmem_doorbell_info);
- type_register_static(&ivshmem_info);
-}
-
-type_init(ivshmem_register_types)
diff --git a/qemu/hw/misc/macio/Makefile.objs b/qemu/hw/misc/macio/Makefile.objs
deleted file mode 100644
index ef7ac249e..000000000
--- a/qemu/hw/misc/macio/Makefile.objs
+++ /dev/null
@@ -1,3 +0,0 @@
-common-obj-y += macio.o
-common-obj-$(CONFIG_CUDA) += cuda.o
-common-obj-$(CONFIG_MAC_DBDMA) += mac_dbdma.o
diff --git a/qemu/hw/misc/macio/cuda.c b/qemu/hw/misc/macio/cuda.c
deleted file mode 100644
index f15f30110..000000000
--- a/qemu/hw/misc/macio/cuda.c
+++ /dev/null
@@ -1,964 +0,0 @@
-/*
- * QEMU PowerMac CUDA device support
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/ppc/mac.h"
-#include "hw/input/adb.h"
-#include "qemu/timer.h"
-#include "sysemu/sysemu.h"
-#include "qemu/cutils.h"
-
-/* XXX: implement all timer modes */
-
-/* debug CUDA */
-//#define DEBUG_CUDA
-
-/* debug CUDA packets */
-//#define DEBUG_CUDA_PACKET
-
-#ifdef DEBUG_CUDA
-#define CUDA_DPRINTF(fmt, ...) \
- do { printf("CUDA: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define CUDA_DPRINTF(fmt, ...)
-#endif
-
-/* Bits in B data register: all active low */
-#define TREQ 0x08 /* Transfer request (input) */
-#define TACK 0x10 /* Transfer acknowledge (output) */
-#define TIP 0x20 /* Transfer in progress (output) */
-
-/* Bits in ACR */
-#define SR_CTRL 0x1c /* Shift register control bits */
-#define SR_EXT 0x0c /* Shift on external clock */
-#define SR_OUT 0x10 /* Shift out if 1 */
-
-/* Bits in IFR and IER */
-#define IER_SET 0x80 /* set bits in IER */
-#define IER_CLR 0 /* clear bits in IER */
-#define SR_INT 0x04 /* Shift register full/empty */
-#define SR_DATA_INT 0x08
-#define SR_CLOCK_INT 0x10
-#define T1_INT 0x40 /* Timer 1 interrupt */
-#define T2_INT 0x20 /* Timer 2 interrupt */
-
-/* Bits in ACR */
-#define T1MODE 0xc0 /* Timer 1 mode */
-#define T1MODE_CONT 0x40 /* continuous interrupts */
-
-/* commands (1st byte) */
-#define ADB_PACKET 0
-#define CUDA_PACKET 1
-#define ERROR_PACKET 2
-#define TIMER_PACKET 3
-#define POWER_PACKET 4
-#define MACIIC_PACKET 5
-#define PMU_PACKET 6
-
-
-/* CUDA commands (2nd byte) */
-#define CUDA_WARM_START 0x0
-#define CUDA_AUTOPOLL 0x1
-#define CUDA_GET_6805_ADDR 0x2
-#define CUDA_GET_TIME 0x3
-#define CUDA_GET_PRAM 0x7
-#define CUDA_SET_6805_ADDR 0x8
-#define CUDA_SET_TIME 0x9
-#define CUDA_POWERDOWN 0xa
-#define CUDA_POWERUP_TIME 0xb
-#define CUDA_SET_PRAM 0xc
-#define CUDA_MS_RESET 0xd
-#define CUDA_SEND_DFAC 0xe
-#define CUDA_BATTERY_SWAP_SENSE 0x10
-#define CUDA_RESET_SYSTEM 0x11
-#define CUDA_SET_IPL 0x12
-#define CUDA_FILE_SERVER_FLAG 0x13
-#define CUDA_SET_AUTO_RATE 0x14
-#define CUDA_GET_AUTO_RATE 0x16
-#define CUDA_SET_DEVICE_LIST 0x19
-#define CUDA_GET_DEVICE_LIST 0x1a
-#define CUDA_SET_ONE_SECOND_MODE 0x1b
-#define CUDA_SET_POWER_MESSAGES 0x21
-#define CUDA_GET_SET_IIC 0x22
-#define CUDA_WAKEUP 0x23
-#define CUDA_TIMER_TICKLE 0x24
-#define CUDA_COMBINED_FORMAT_IIC 0x25
-
-#define CUDA_TIMER_FREQ (4700000 / 6)
-
-/* CUDA returns time_t's offset from Jan 1, 1904, not 1970 */
-#define RTC_OFFSET 2082844800
-
-/* CUDA registers */
-#define CUDA_REG_B 0x00
-#define CUDA_REG_A 0x01
-#define CUDA_REG_DIRB 0x02
-#define CUDA_REG_DIRA 0x03
-#define CUDA_REG_T1CL 0x04
-#define CUDA_REG_T1CH 0x05
-#define CUDA_REG_T1LL 0x06
-#define CUDA_REG_T1LH 0x07
-#define CUDA_REG_T2CL 0x08
-#define CUDA_REG_T2CH 0x09
-#define CUDA_REG_SR 0x0a
-#define CUDA_REG_ACR 0x0b
-#define CUDA_REG_PCR 0x0c
-#define CUDA_REG_IFR 0x0d
-#define CUDA_REG_IER 0x0e
-#define CUDA_REG_ANH 0x0f
-
-static void cuda_update(CUDAState *s);
-static void cuda_receive_packet_from_host(CUDAState *s,
- const uint8_t *data, int len);
-static void cuda_timer_update(CUDAState *s, CUDATimer *ti,
- int64_t current_time);
-
-static void cuda_update_irq(CUDAState *s)
-{
- if (s->ifr & s->ier & (SR_INT | T1_INT | T2_INT)) {
- qemu_irq_raise(s->irq);
- } else {
- qemu_irq_lower(s->irq);
- }
-}
-
-static uint64_t get_tb(uint64_t time, uint64_t freq)
-{
- return muldiv64(time, freq, NANOSECONDS_PER_SECOND);
-}
-
-static unsigned int get_counter(CUDATimer *ti)
-{
- int64_t d;
- unsigned int counter;
- uint64_t tb_diff;
- uint64_t current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-
- /* Reverse of the tb calculation algorithm that Mac OS X uses on bootup. */
- tb_diff = get_tb(current_time, ti->frequency) - ti->load_time;
- d = (tb_diff * 0xBF401675E5DULL) / (ti->frequency << 24);
-
- if (ti->index == 0) {
- /* the timer goes down from latch to -1 (period of latch + 2) */
- if (d <= (ti->counter_value + 1)) {
- counter = (ti->counter_value - d) & 0xffff;
- } else {
- counter = (d - (ti->counter_value + 1)) % (ti->latch + 2);
- counter = (ti->latch - counter) & 0xffff;
- }
- } else {
- counter = (ti->counter_value - d) & 0xffff;
- }
- return counter;
-}
-
-static void set_counter(CUDAState *s, CUDATimer *ti, unsigned int val)
-{
- CUDA_DPRINTF("T%d.counter=%d\n", 1 + ti->index, val);
- ti->load_time = get_tb(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
- s->frequency);
- ti->counter_value = val;
- cuda_timer_update(s, ti, ti->load_time);
-}
-
-static int64_t get_next_irq_time(CUDATimer *s, int64_t current_time)
-{
- int64_t d, next_time;
- unsigned int counter;
-
- /* current counter value */
- d = muldiv64(current_time - s->load_time,
- CUDA_TIMER_FREQ, NANOSECONDS_PER_SECOND);
- /* the timer goes down from latch to -1 (period of latch + 2) */
- if (d <= (s->counter_value + 1)) {
- counter = (s->counter_value - d) & 0xffff;
- } else {
- counter = (d - (s->counter_value + 1)) % (s->latch + 2);
- counter = (s->latch - counter) & 0xffff;
- }
-
- /* Note: we consider the irq is raised on 0 */
- if (counter == 0xffff) {
- next_time = d + s->latch + 1;
- } else if (counter == 0) {
- next_time = d + s->latch + 2;
- } else {
- next_time = d + counter;
- }
- CUDA_DPRINTF("latch=%d counter=%" PRId64 " delta_next=%" PRId64 "\n",
- s->latch, d, next_time - d);
- next_time = muldiv64(next_time, NANOSECONDS_PER_SECOND, CUDA_TIMER_FREQ) +
- s->load_time;
- if (next_time <= current_time)
- next_time = current_time + 1;
- return next_time;
-}
-
-static void cuda_timer_update(CUDAState *s, CUDATimer *ti,
- int64_t current_time)
-{
- if (!ti->timer)
- return;
- if (ti->index == 0 && (s->acr & T1MODE) != T1MODE_CONT) {
- timer_del(ti->timer);
- } else {
- ti->next_irq_time = get_next_irq_time(ti, current_time);
- timer_mod(ti->timer, ti->next_irq_time);
- }
-}
-
-static void cuda_timer1(void *opaque)
-{
- CUDAState *s = opaque;
- CUDATimer *ti = &s->timers[0];
-
- cuda_timer_update(s, ti, ti->next_irq_time);
- s->ifr |= T1_INT;
- cuda_update_irq(s);
-}
-
-static void cuda_timer2(void *opaque)
-{
- CUDAState *s = opaque;
- CUDATimer *ti = &s->timers[1];
-
- cuda_timer_update(s, ti, ti->next_irq_time);
- s->ifr |= T2_INT;
- cuda_update_irq(s);
-}
-
-static void cuda_set_sr_int(void *opaque)
-{
- CUDAState *s = opaque;
-
- CUDA_DPRINTF("CUDA: %s:%d\n", __func__, __LINE__);
- s->ifr |= SR_INT;
- cuda_update_irq(s);
-}
-
-static void cuda_delay_set_sr_int(CUDAState *s)
-{
- int64_t expire;
-
- if (s->dirb == 0xff) {
- /* Not in Mac OS, fire the IRQ directly */
- cuda_set_sr_int(s);
- return;
- }
-
- CUDA_DPRINTF("CUDA: %s:%d\n", __func__, __LINE__);
-
- expire = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 300 * SCALE_US;
- timer_mod(s->sr_delay_timer, expire);
-}
-
-static uint32_t cuda_readb(void *opaque, hwaddr addr)
-{
- CUDAState *s = opaque;
- uint32_t val;
-
- addr = (addr >> 9) & 0xf;
- switch(addr) {
- case CUDA_REG_B:
- val = s->b;
- break;
- case CUDA_REG_A:
- val = s->a;
- break;
- case CUDA_REG_DIRB:
- val = s->dirb;
- break;
- case CUDA_REG_DIRA:
- val = s->dira;
- break;
- case CUDA_REG_T1CL:
- val = get_counter(&s->timers[0]) & 0xff;
- s->ifr &= ~T1_INT;
- cuda_update_irq(s);
- break;
- case CUDA_REG_T1CH:
- val = get_counter(&s->timers[0]) >> 8;
- cuda_update_irq(s);
- break;
- case CUDA_REG_T1LL:
- val = s->timers[0].latch & 0xff;
- break;
- case CUDA_REG_T1LH:
- /* XXX: check this */
- val = (s->timers[0].latch >> 8) & 0xff;
- break;
- case CUDA_REG_T2CL:
- val = get_counter(&s->timers[1]) & 0xff;
- s->ifr &= ~T2_INT;
- cuda_update_irq(s);
- break;
- case CUDA_REG_T2CH:
- val = get_counter(&s->timers[1]) >> 8;
- break;
- case CUDA_REG_SR:
- val = s->sr;
- s->ifr &= ~(SR_INT | SR_CLOCK_INT | SR_DATA_INT);
- cuda_update_irq(s);
- break;
- case CUDA_REG_ACR:
- val = s->acr;
- break;
- case CUDA_REG_PCR:
- val = s->pcr;
- break;
- case CUDA_REG_IFR:
- val = s->ifr;
- if (s->ifr & s->ier) {
- val |= 0x80;
- }
- break;
- case CUDA_REG_IER:
- val = s->ier | 0x80;
- break;
- default:
- case CUDA_REG_ANH:
- val = s->anh;
- break;
- }
- if (addr != CUDA_REG_IFR || val != 0) {
- CUDA_DPRINTF("read: reg=0x%x val=%02x\n", (int)addr, val);
- }
-
- return val;
-}
-
-static void cuda_writeb(void *opaque, hwaddr addr, uint32_t val)
-{
- CUDAState *s = opaque;
-
- addr = (addr >> 9) & 0xf;
- CUDA_DPRINTF("write: reg=0x%x val=%02x\n", (int)addr, val);
-
- switch(addr) {
- case CUDA_REG_B:
- s->b = val;
- cuda_update(s);
- break;
- case CUDA_REG_A:
- s->a = val;
- break;
- case CUDA_REG_DIRB:
- s->dirb = val;
- break;
- case CUDA_REG_DIRA:
- s->dira = val;
- break;
- case CUDA_REG_T1CL:
- s->timers[0].latch = (s->timers[0].latch & 0xff00) | val;
- cuda_timer_update(s, &s->timers[0], qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
- break;
- case CUDA_REG_T1CH:
- s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8);
- s->ifr &= ~T1_INT;
- set_counter(s, &s->timers[0], s->timers[0].latch);
- break;
- case CUDA_REG_T1LL:
- s->timers[0].latch = (s->timers[0].latch & 0xff00) | val;
- cuda_timer_update(s, &s->timers[0], qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
- break;
- case CUDA_REG_T1LH:
- s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8);
- s->ifr &= ~T1_INT;
- cuda_timer_update(s, &s->timers[0], qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
- break;
- case CUDA_REG_T2CL:
- s->timers[1].latch = (s->timers[1].latch & 0xff00) | val;
- break;
- case CUDA_REG_T2CH:
- /* To ensure T2 generates an interrupt on zero crossing with the
- common timer code, write the value directly from the latch to
- the counter */
- s->timers[1].latch = (s->timers[1].latch & 0xff) | (val << 8);
- s->ifr &= ~T2_INT;
- set_counter(s, &s->timers[1], s->timers[1].latch);
- break;
- case CUDA_REG_SR:
- s->sr = val;
- break;
- case CUDA_REG_ACR:
- s->acr = val;
- cuda_timer_update(s, &s->timers[0], qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
- cuda_update(s);
- break;
- case CUDA_REG_PCR:
- s->pcr = val;
- break;
- case CUDA_REG_IFR:
- /* reset bits */
- s->ifr &= ~val;
- cuda_update_irq(s);
- break;
- case CUDA_REG_IER:
- if (val & IER_SET) {
- /* set bits */
- s->ier |= val & 0x7f;
- } else {
- /* reset bits */
- s->ier &= ~val;
- }
- cuda_update_irq(s);
- break;
- default:
- case CUDA_REG_ANH:
- s->anh = val;
- break;
- }
-}
-
-/* NOTE: TIP and TREQ are negated */
-static void cuda_update(CUDAState *s)
-{
- int packet_received, len;
-
- packet_received = 0;
- if (!(s->b & TIP)) {
- /* transfer requested from host */
-
- if (s->acr & SR_OUT) {
- /* data output */
- if ((s->b & (TACK | TIP)) != (s->last_b & (TACK | TIP))) {
- if (s->data_out_index < sizeof(s->data_out)) {
- CUDA_DPRINTF("send: %02x\n", s->sr);
- s->data_out[s->data_out_index++] = s->sr;
- cuda_delay_set_sr_int(s);
- }
- }
- } else {
- if (s->data_in_index < s->data_in_size) {
- /* data input */
- if ((s->b & (TACK | TIP)) != (s->last_b & (TACK | TIP))) {
- s->sr = s->data_in[s->data_in_index++];
- CUDA_DPRINTF("recv: %02x\n", s->sr);
- /* indicate end of transfer */
- if (s->data_in_index >= s->data_in_size) {
- s->b = (s->b | TREQ);
- }
- cuda_delay_set_sr_int(s);
- }
- }
- }
- } else {
- /* no transfer requested: handle sync case */
- if ((s->last_b & TIP) && (s->b & TACK) != (s->last_b & TACK)) {
- /* update TREQ state each time TACK change state */
- if (s->b & TACK)
- s->b = (s->b | TREQ);
- else
- s->b = (s->b & ~TREQ);
- cuda_delay_set_sr_int(s);
- } else {
- if (!(s->last_b & TIP)) {
- /* handle end of host to cuda transfer */
- packet_received = (s->data_out_index > 0);
- /* always an IRQ at the end of transfer */
- cuda_delay_set_sr_int(s);
- }
- /* signal if there is data to read */
- if (s->data_in_index < s->data_in_size) {
- s->b = (s->b & ~TREQ);
- }
- }
- }
-
- s->last_acr = s->acr;
- s->last_b = s->b;
-
- /* NOTE: cuda_receive_packet_from_host() can call cuda_update()
- recursively */
- if (packet_received) {
- len = s->data_out_index;
- s->data_out_index = 0;
- cuda_receive_packet_from_host(s, s->data_out, len);
- }
-}
-
-static void cuda_send_packet_to_host(CUDAState *s,
- const uint8_t *data, int len)
-{
-#ifdef DEBUG_CUDA_PACKET
- {
- int i;
- printf("cuda_send_packet_to_host:\n");
- for(i = 0; i < len; i++)
- printf(" %02x", data[i]);
- printf("\n");
- }
-#endif
- memcpy(s->data_in, data, len);
- s->data_in_size = len;
- s->data_in_index = 0;
- cuda_update(s);
- cuda_delay_set_sr_int(s);
-}
-
-static void cuda_adb_poll(void *opaque)
-{
- CUDAState *s = opaque;
- uint8_t obuf[ADB_MAX_OUT_LEN + 2];
- int olen;
-
- olen = adb_poll(&s->adb_bus, obuf + 2, s->adb_poll_mask);
- if (olen > 0) {
- obuf[0] = ADB_PACKET;
- obuf[1] = 0x40; /* polled data */
- cuda_send_packet_to_host(s, obuf, olen + 2);
- }
- timer_mod(s->adb_poll_timer,
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- (NANOSECONDS_PER_SECOND / (1000 / s->autopoll_rate_ms)));
-}
-
-/* description of commands */
-typedef struct CudaCommand {
- uint8_t command;
- const char *name;
- bool (*handler)(CUDAState *s,
- const uint8_t *in_args, int in_len,
- uint8_t *out_args, int *out_len);
-} CudaCommand;
-
-static bool cuda_cmd_autopoll(CUDAState *s,
- const uint8_t *in_data, int in_len,
- uint8_t *out_data, int *out_len)
-{
- int autopoll;
-
- if (in_len != 1) {
- return false;
- }
-
- autopoll = (in_data[0] != 0);
- if (autopoll != s->autopoll) {
- s->autopoll = autopoll;
- if (autopoll) {
- timer_mod(s->adb_poll_timer,
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- (NANOSECONDS_PER_SECOND / (1000 / s->autopoll_rate_ms)));
- } else {
- timer_del(s->adb_poll_timer);
- }
- }
- return true;
-}
-
-static bool cuda_cmd_set_autorate(CUDAState *s,
- const uint8_t *in_data, int in_len,
- uint8_t *out_data, int *out_len)
-{
- if (in_len != 1) {
- return false;
- }
-
- /* we don't want a period of 0 ms */
- /* FIXME: check what real hardware does */
- if (in_data[0] == 0) {
- return false;
- }
-
- s->autopoll_rate_ms = in_data[0];
- if (s->autopoll) {
- timer_mod(s->adb_poll_timer,
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- (NANOSECONDS_PER_SECOND / (1000 / s->autopoll_rate_ms)));
- }
- return true;
-}
-
-static bool cuda_cmd_set_device_list(CUDAState *s,
- const uint8_t *in_data, int in_len,
- uint8_t *out_data, int *out_len)
-{
- if (in_len != 2) {
- return false;
- }
-
- s->adb_poll_mask = (((uint16_t)in_data[0]) << 8) | in_data[1];
- return true;
-}
-
-static bool cuda_cmd_powerdown(CUDAState *s,
- const uint8_t *in_data, int in_len,
- uint8_t *out_data, int *out_len)
-{
- if (in_len != 0) {
- return false;
- }
-
- qemu_system_shutdown_request();
- return true;
-}
-
-static bool cuda_cmd_reset_system(CUDAState *s,
- const uint8_t *in_data, int in_len,
- uint8_t *out_data, int *out_len)
-{
- if (in_len != 0) {
- return false;
- }
-
- qemu_system_reset_request();
- return true;
-}
-
-static bool cuda_cmd_set_file_server_flag(CUDAState *s,
- const uint8_t *in_data, int in_len,
- uint8_t *out_data, int *out_len)
-{
- if (in_len != 1) {
- return false;
- }
-
- qemu_log_mask(LOG_UNIMP,
- "CUDA: unimplemented command FILE_SERVER_FLAG %d\n",
- in_data[0]);
- return true;
-}
-
-static bool cuda_cmd_set_power_message(CUDAState *s,
- const uint8_t *in_data, int in_len,
- uint8_t *out_data, int *out_len)
-{
- if (in_len != 1) {
- return false;
- }
-
- qemu_log_mask(LOG_UNIMP,
- "CUDA: unimplemented command SET_POWER_MESSAGE %d\n",
- in_data[0]);
- return true;
-}
-
-static bool cuda_cmd_get_time(CUDAState *s,
- const uint8_t *in_data, int in_len,
- uint8_t *out_data, int *out_len)
-{
- uint32_t ti;
-
- if (in_len != 0) {
- return false;
- }
-
- ti = s->tick_offset + (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)
- / NANOSECONDS_PER_SECOND);
- out_data[0] = ti >> 24;
- out_data[1] = ti >> 16;
- out_data[2] = ti >> 8;
- out_data[3] = ti;
- *out_len = 4;
- return true;
-}
-
-static bool cuda_cmd_set_time(CUDAState *s,
- const uint8_t *in_data, int in_len,
- uint8_t *out_data, int *out_len)
-{
- uint32_t ti;
-
- if (in_len != 4) {
- return false;
- }
-
- ti = (((uint32_t)in_data[0]) << 24) + (((uint32_t)in_data[1]) << 16)
- + (((uint32_t)in_data[2]) << 8) + in_data[3];
- s->tick_offset = ti - (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)
- / NANOSECONDS_PER_SECOND);
- return true;
-}
-
-static const CudaCommand handlers[] = {
- { CUDA_AUTOPOLL, "AUTOPOLL", cuda_cmd_autopoll },
- { CUDA_SET_AUTO_RATE, "SET_AUTO_RATE", cuda_cmd_set_autorate },
- { CUDA_SET_DEVICE_LIST, "SET_DEVICE_LIST", cuda_cmd_set_device_list },
- { CUDA_POWERDOWN, "POWERDOWN", cuda_cmd_powerdown },
- { CUDA_RESET_SYSTEM, "RESET_SYSTEM", cuda_cmd_reset_system },
- { CUDA_FILE_SERVER_FLAG, "FILE_SERVER_FLAG",
- cuda_cmd_set_file_server_flag },
- { CUDA_SET_POWER_MESSAGES, "SET_POWER_MESSAGES",
- cuda_cmd_set_power_message },
- { CUDA_GET_TIME, "GET_TIME", cuda_cmd_get_time },
- { CUDA_SET_TIME, "SET_TIME", cuda_cmd_set_time },
-};
-
-static void cuda_receive_packet(CUDAState *s,
- const uint8_t *data, int len)
-{
- uint8_t obuf[16] = { CUDA_PACKET, 0, data[0] };
- int i, out_len = 0;
-
- for (i = 0; i < ARRAY_SIZE(handlers); i++) {
- const CudaCommand *desc = &handlers[i];
- if (desc->command == data[0]) {
- CUDA_DPRINTF("handling command %s\n", desc->name);
- out_len = 0;
- if (desc->handler(s, data + 1, len - 1, obuf + 3, &out_len)) {
- cuda_send_packet_to_host(s, obuf, 3 + out_len);
- } else {
- qemu_log_mask(LOG_GUEST_ERROR,
- "CUDA: %s: wrong parameters %d\n",
- desc->name, len);
- obuf[0] = ERROR_PACKET;
- obuf[1] = 0x5; /* bad parameters */
- obuf[2] = CUDA_PACKET;
- obuf[3] = data[0];
- cuda_send_packet_to_host(s, obuf, 4);
- }
- return;
- }
- }
-
- qemu_log_mask(LOG_GUEST_ERROR, "CUDA: unknown command 0x%02x\n", data[0]);
- obuf[0] = ERROR_PACKET;
- obuf[1] = 0x2; /* unknown command */
- obuf[2] = CUDA_PACKET;
- obuf[3] = data[0];
- cuda_send_packet_to_host(s, obuf, 4);
-}
-
-static void cuda_receive_packet_from_host(CUDAState *s,
- const uint8_t *data, int len)
-{
-#ifdef DEBUG_CUDA_PACKET
- {
- int i;
- printf("cuda_receive_packet_from_host:\n");
- for(i = 0; i < len; i++)
- printf(" %02x", data[i]);
- printf("\n");
- }
-#endif
- switch(data[0]) {
- case ADB_PACKET:
- {
- uint8_t obuf[ADB_MAX_OUT_LEN + 3];
- int olen;
- olen = adb_request(&s->adb_bus, obuf + 2, data + 1, len - 1);
- if (olen > 0) {
- obuf[0] = ADB_PACKET;
- obuf[1] = 0x00;
- cuda_send_packet_to_host(s, obuf, olen + 2);
- } else {
- /* error */
- obuf[0] = ADB_PACKET;
- obuf[1] = -olen;
- obuf[2] = data[1];
- olen = 0;
- cuda_send_packet_to_host(s, obuf, olen + 3);
- }
- }
- break;
- case CUDA_PACKET:
- cuda_receive_packet(s, data + 1, len - 1);
- break;
- }
-}
-
-static void cuda_writew (void *opaque, hwaddr addr, uint32_t value)
-{
-}
-
-static void cuda_writel (void *opaque, hwaddr addr, uint32_t value)
-{
-}
-
-static uint32_t cuda_readw (void *opaque, hwaddr addr)
-{
- return 0;
-}
-
-static uint32_t cuda_readl (void *opaque, hwaddr addr)
-{
- return 0;
-}
-
-static const MemoryRegionOps cuda_ops = {
- .old_mmio = {
- .write = {
- cuda_writeb,
- cuda_writew,
- cuda_writel,
- },
- .read = {
- cuda_readb,
- cuda_readw,
- cuda_readl,
- },
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static bool cuda_timer_exist(void *opaque, int version_id)
-{
- CUDATimer *s = opaque;
-
- return s->timer != NULL;
-}
-
-static const VMStateDescription vmstate_cuda_timer = {
- .name = "cuda_timer",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_UINT16(latch, CUDATimer),
- VMSTATE_UINT16(counter_value, CUDATimer),
- VMSTATE_INT64(load_time, CUDATimer),
- VMSTATE_INT64(next_irq_time, CUDATimer),
- VMSTATE_TIMER_PTR_TEST(timer, CUDATimer, cuda_timer_exist),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_cuda = {
- .name = "cuda",
- .version_id = 4,
- .minimum_version_id = 4,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(a, CUDAState),
- VMSTATE_UINT8(b, CUDAState),
- VMSTATE_UINT8(last_b, CUDAState),
- VMSTATE_UINT8(dira, CUDAState),
- VMSTATE_UINT8(dirb, CUDAState),
- VMSTATE_UINT8(sr, CUDAState),
- VMSTATE_UINT8(acr, CUDAState),
- VMSTATE_UINT8(last_acr, CUDAState),
- VMSTATE_UINT8(pcr, CUDAState),
- VMSTATE_UINT8(ifr, CUDAState),
- VMSTATE_UINT8(ier, CUDAState),
- VMSTATE_UINT8(anh, CUDAState),
- VMSTATE_INT32(data_in_size, CUDAState),
- VMSTATE_INT32(data_in_index, CUDAState),
- VMSTATE_INT32(data_out_index, CUDAState),
- VMSTATE_UINT8(autopoll, CUDAState),
- VMSTATE_UINT8(autopoll_rate_ms, CUDAState),
- VMSTATE_UINT16(adb_poll_mask, CUDAState),
- VMSTATE_BUFFER(data_in, CUDAState),
- VMSTATE_BUFFER(data_out, CUDAState),
- VMSTATE_UINT32(tick_offset, CUDAState),
- VMSTATE_STRUCT_ARRAY(timers, CUDAState, 2, 1,
- vmstate_cuda_timer, CUDATimer),
- VMSTATE_TIMER_PTR(adb_poll_timer, CUDAState),
- VMSTATE_TIMER_PTR(sr_delay_timer, CUDAState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void cuda_reset(DeviceState *dev)
-{
- CUDAState *s = CUDA(dev);
-
- s->b = 0;
- s->a = 0;
- s->dirb = 0xff;
- s->dira = 0;
- s->sr = 0;
- s->acr = 0;
- s->pcr = 0;
- s->ifr = 0;
- s->ier = 0;
- // s->ier = T1_INT | SR_INT;
- s->anh = 0;
- s->data_in_size = 0;
- s->data_in_index = 0;
- s->data_out_index = 0;
- s->autopoll = 0;
-
- s->timers[0].latch = 0xffff;
- set_counter(s, &s->timers[0], 0xffff);
-
- s->timers[1].latch = 0xffff;
-
- s->sr_delay_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cuda_set_sr_int, s);
-}
-
-static void cuda_realizefn(DeviceState *dev, Error **errp)
-{
- CUDAState *s = CUDA(dev);
- struct tm tm;
-
- s->timers[0].timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cuda_timer1, s);
- s->timers[0].frequency = s->frequency;
- s->timers[1].timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cuda_timer2, s);
- s->timers[1].frequency = (SCALE_US * 6000) / 4700;
-
- qemu_get_timedate(&tm, 0);
- s->tick_offset = (uint32_t)mktimegm(&tm) + RTC_OFFSET;
-
- s->adb_poll_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cuda_adb_poll, s);
- s->autopoll_rate_ms = 20;
- s->adb_poll_mask = 0xffff;
-}
-
-static void cuda_initfn(Object *obj)
-{
- SysBusDevice *d = SYS_BUS_DEVICE(obj);
- CUDAState *s = CUDA(obj);
- int i;
-
- memory_region_init_io(&s->mem, obj, &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;
- }
-
- qbus_create_inplace(&s->adb_bus, sizeof(s->adb_bus), TYPE_ADB_BUS,
- DEVICE(obj), "adb.0");
-}
-
-static Property cuda_properties[] = {
- DEFINE_PROP_UINT64("frequency", CUDAState, frequency, 0),
- DEFINE_PROP_END_OF_LIST()
-};
-
-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;
- dc->props = cuda_properties;
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
-}
-
-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/qemu/hw/misc/macio/mac_dbdma.c b/qemu/hw/misc/macio/mac_dbdma.c
deleted file mode 100644
index 6051f17db..000000000
--- a/qemu/hw/misc/macio/mac_dbdma.c
+++ /dev/null
@@ -1,820 +0,0 @@
-/*
- * PowerMac descriptor-based DMA emulation
- *
- * Copyright (c) 2005-2007 Fabrice Bellard
- * Copyright (c) 2007 Jocelyn Mayer
- * Copyright (c) 2009 Laurent Vivier
- *
- * some parts from linux-2.6.28, arch/powerpc/include/asm/dbdma.h
- *
- * Definitions for using the Apple Descriptor-Based DMA controller
- * in Power Macintosh computers.
- *
- * Copyright (C) 1996 Paul Mackerras.
- *
- * some parts from mol 0.9.71
- *
- * Descriptor based DMA emulation
- *
- * Copyright (C) 1998-2004 Samuel Rydh (samuel@ibrium.se)
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/isa/isa.h"
-#include "hw/ppc/mac_dbdma.h"
-#include "qemu/main-loop.h"
-
-/* debug DBDMA */
-//#define DEBUG_DBDMA
-
-#ifdef DEBUG_DBDMA
-#define DBDMA_DPRINTF(fmt, ...) \
- do { printf("DBDMA: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DBDMA_DPRINTF(fmt, ...)
-#endif
-
-/*
- */
-
-static DBDMAState *dbdma_from_ch(DBDMA_channel *ch)
-{
- return container_of(ch, DBDMAState, channels[ch->channel]);
-}
-
-#ifdef DEBUG_DBDMA
-static void dump_dbdma_cmd(dbdma_cmd *cmd)
-{
- printf("dbdma_cmd %p\n", cmd);
- printf(" req_count 0x%04x\n", le16_to_cpu(cmd->req_count));
- printf(" command 0x%04x\n", le16_to_cpu(cmd->command));
- printf(" phy_addr 0x%08x\n", le32_to_cpu(cmd->phy_addr));
- printf(" cmd_dep 0x%08x\n", le32_to_cpu(cmd->cmd_dep));
- printf(" res_count 0x%04x\n", le16_to_cpu(cmd->res_count));
- printf(" xfer_status 0x%04x\n", le16_to_cpu(cmd->xfer_status));
-}
-#else
-static void dump_dbdma_cmd(dbdma_cmd *cmd)
-{
-}
-#endif
-static void dbdma_cmdptr_load(DBDMA_channel *ch)
-{
- DBDMA_DPRINTF("dbdma_cmdptr_load 0x%08x\n",
- ch->regs[DBDMA_CMDPTR_LO]);
- cpu_physical_memory_read(ch->regs[DBDMA_CMDPTR_LO],
- &ch->current, sizeof(dbdma_cmd));
-}
-
-static void dbdma_cmdptr_save(DBDMA_channel *ch)
-{
- DBDMA_DPRINTF("dbdma_cmdptr_save 0x%08x\n",
- ch->regs[DBDMA_CMDPTR_LO]);
- DBDMA_DPRINTF("xfer_status 0x%08x res_count 0x%04x\n",
- le16_to_cpu(ch->current.xfer_status),
- le16_to_cpu(ch->current.res_count));
- cpu_physical_memory_write(ch->regs[DBDMA_CMDPTR_LO],
- &ch->current, sizeof(dbdma_cmd));
-}
-
-static void kill_channel(DBDMA_channel *ch)
-{
- DBDMA_DPRINTF("kill_channel\n");
-
- ch->regs[DBDMA_STATUS] |= DEAD;
- ch->regs[DBDMA_STATUS] &= ~ACTIVE;
-
- qemu_irq_raise(ch->irq);
-}
-
-static void conditional_interrupt(DBDMA_channel *ch)
-{
- dbdma_cmd *current = &ch->current;
- uint16_t intr;
- uint16_t sel_mask, sel_value;
- uint32_t status;
- int cond;
-
- DBDMA_DPRINTF("%s\n", __func__);
-
- intr = le16_to_cpu(current->command) & INTR_MASK;
-
- switch(intr) {
- case INTR_NEVER: /* don't interrupt */
- return;
- case INTR_ALWAYS: /* always interrupt */
- qemu_irq_raise(ch->irq);
- DBDMA_DPRINTF("%s: raise\n", __func__);
- return;
- }
-
- status = ch->regs[DBDMA_STATUS] & DEVSTAT;
-
- sel_mask = (ch->regs[DBDMA_INTR_SEL] >> 16) & 0x0f;
- sel_value = ch->regs[DBDMA_INTR_SEL] & 0x0f;
-
- cond = (status & sel_mask) == (sel_value & sel_mask);
-
- switch(intr) {
- case INTR_IFSET: /* intr if condition bit is 1 */
- if (cond) {
- qemu_irq_raise(ch->irq);
- DBDMA_DPRINTF("%s: raise\n", __func__);
- }
- return;
- case INTR_IFCLR: /* intr if condition bit is 0 */
- if (!cond) {
- qemu_irq_raise(ch->irq);
- DBDMA_DPRINTF("%s: raise\n", __func__);
- }
- return;
- }
-}
-
-static int conditional_wait(DBDMA_channel *ch)
-{
- dbdma_cmd *current = &ch->current;
- uint16_t wait;
- uint16_t sel_mask, sel_value;
- uint32_t status;
- int cond;
-
- DBDMA_DPRINTF("conditional_wait\n");
-
- wait = le16_to_cpu(current->command) & WAIT_MASK;
-
- switch(wait) {
- case WAIT_NEVER: /* don't wait */
- return 0;
- case WAIT_ALWAYS: /* always wait */
- return 1;
- }
-
- status = ch->regs[DBDMA_STATUS] & DEVSTAT;
-
- sel_mask = (ch->regs[DBDMA_WAIT_SEL] >> 16) & 0x0f;
- sel_value = ch->regs[DBDMA_WAIT_SEL] & 0x0f;
-
- cond = (status & sel_mask) == (sel_value & sel_mask);
-
- switch(wait) {
- case WAIT_IFSET: /* wait if condition bit is 1 */
- if (cond)
- return 1;
- return 0;
- case WAIT_IFCLR: /* wait if condition bit is 0 */
- if (!cond)
- return 1;
- return 0;
- }
- return 0;
-}
-
-static void next(DBDMA_channel *ch)
-{
- uint32_t cp;
-
- ch->regs[DBDMA_STATUS] &= ~BT;
-
- cp = ch->regs[DBDMA_CMDPTR_LO];
- ch->regs[DBDMA_CMDPTR_LO] = cp + sizeof(dbdma_cmd);
- dbdma_cmdptr_load(ch);
-}
-
-static void branch(DBDMA_channel *ch)
-{
- dbdma_cmd *current = &ch->current;
-
- ch->regs[DBDMA_CMDPTR_LO] = current->cmd_dep;
- ch->regs[DBDMA_STATUS] |= BT;
- dbdma_cmdptr_load(ch);
-}
-
-static void conditional_branch(DBDMA_channel *ch)
-{
- dbdma_cmd *current = &ch->current;
- uint16_t br;
- uint16_t sel_mask, sel_value;
- uint32_t status;
- int cond;
-
- DBDMA_DPRINTF("conditional_branch\n");
-
- /* check if we must branch */
-
- br = le16_to_cpu(current->command) & BR_MASK;
-
- switch(br) {
- case BR_NEVER: /* don't branch */
- next(ch);
- return;
- case BR_ALWAYS: /* always branch */
- branch(ch);
- return;
- }
-
- status = ch->regs[DBDMA_STATUS] & DEVSTAT;
-
- sel_mask = (ch->regs[DBDMA_BRANCH_SEL] >> 16) & 0x0f;
- sel_value = ch->regs[DBDMA_BRANCH_SEL] & 0x0f;
-
- cond = (status & sel_mask) == (sel_value & sel_mask);
-
- switch(br) {
- case BR_IFSET: /* branch if condition bit is 1 */
- if (cond)
- branch(ch);
- else
- next(ch);
- return;
- case BR_IFCLR: /* branch if condition bit is 0 */
- if (!cond)
- branch(ch);
- else
- next(ch);
- return;
- }
-}
-
-static void channel_run(DBDMA_channel *ch);
-
-static void dbdma_end(DBDMA_io *io)
-{
- DBDMA_channel *ch = io->channel;
- dbdma_cmd *current = &ch->current;
-
- DBDMA_DPRINTF("%s\n", __func__);
-
- if (conditional_wait(ch))
- goto wait;
-
- current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]);
- current->res_count = cpu_to_le16(io->len);
- dbdma_cmdptr_save(ch);
- if (io->is_last)
- ch->regs[DBDMA_STATUS] &= ~FLUSH;
-
- conditional_interrupt(ch);
- conditional_branch(ch);
-
-wait:
- /* Indicate that we're ready for a new DMA round */
- ch->io.processing = false;
-
- if ((ch->regs[DBDMA_STATUS] & RUN) &&
- (ch->regs[DBDMA_STATUS] & ACTIVE))
- channel_run(ch);
-}
-
-static void start_output(DBDMA_channel *ch, int key, uint32_t addr,
- uint16_t req_count, int is_last)
-{
- DBDMA_DPRINTF("start_output\n");
-
- /* KEY_REGS, KEY_DEVICE and KEY_STREAM
- * are not implemented in the mac-io chip
- */
-
- DBDMA_DPRINTF("addr 0x%x key 0x%x\n", addr, key);
- if (!addr || key > KEY_STREAM3) {
- kill_channel(ch);
- return;
- }
-
- ch->io.addr = addr;
- ch->io.len = req_count;
- ch->io.is_last = is_last;
- ch->io.dma_end = dbdma_end;
- ch->io.is_dma_out = 1;
- ch->io.processing = true;
- if (ch->rw) {
- ch->rw(&ch->io);
- }
-}
-
-static void start_input(DBDMA_channel *ch, int key, uint32_t addr,
- uint16_t req_count, int is_last)
-{
- DBDMA_DPRINTF("start_input\n");
-
- /* KEY_REGS, KEY_DEVICE and KEY_STREAM
- * are not implemented in the mac-io chip
- */
-
- DBDMA_DPRINTF("addr 0x%x key 0x%x\n", addr, key);
- if (!addr || key > KEY_STREAM3) {
- kill_channel(ch);
- return;
- }
-
- ch->io.addr = addr;
- ch->io.len = req_count;
- ch->io.is_last = is_last;
- ch->io.dma_end = dbdma_end;
- ch->io.is_dma_out = 0;
- ch->io.processing = true;
- if (ch->rw) {
- ch->rw(&ch->io);
- }
-}
-
-static void load_word(DBDMA_channel *ch, int key, uint32_t addr,
- uint16_t len)
-{
- dbdma_cmd *current = &ch->current;
- uint32_t val;
-
- DBDMA_DPRINTF("load_word\n");
-
- /* only implements KEY_SYSTEM */
-
- if (key != KEY_SYSTEM) {
- printf("DBDMA: LOAD_WORD, unimplemented key %x\n", key);
- kill_channel(ch);
- return;
- }
-
- cpu_physical_memory_read(addr, &val, len);
-
- if (len == 2)
- val = (val << 16) | (current->cmd_dep & 0x0000ffff);
- else if (len == 1)
- val = (val << 24) | (current->cmd_dep & 0x00ffffff);
-
- current->cmd_dep = val;
-
- if (conditional_wait(ch))
- goto wait;
-
- current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]);
- dbdma_cmdptr_save(ch);
- ch->regs[DBDMA_STATUS] &= ~FLUSH;
-
- conditional_interrupt(ch);
- next(ch);
-
-wait:
- DBDMA_kick(dbdma_from_ch(ch));
-}
-
-static void store_word(DBDMA_channel *ch, int key, uint32_t addr,
- uint16_t len)
-{
- dbdma_cmd *current = &ch->current;
- uint32_t val;
-
- DBDMA_DPRINTF("store_word\n");
-
- /* only implements KEY_SYSTEM */
-
- if (key != KEY_SYSTEM) {
- printf("DBDMA: STORE_WORD, unimplemented key %x\n", key);
- kill_channel(ch);
- return;
- }
-
- val = current->cmd_dep;
- if (len == 2)
- val >>= 16;
- else if (len == 1)
- val >>= 24;
-
- cpu_physical_memory_write(addr, &val, len);
-
- if (conditional_wait(ch))
- goto wait;
-
- current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]);
- dbdma_cmdptr_save(ch);
- ch->regs[DBDMA_STATUS] &= ~FLUSH;
-
- conditional_interrupt(ch);
- next(ch);
-
-wait:
- DBDMA_kick(dbdma_from_ch(ch));
-}
-
-static void nop(DBDMA_channel *ch)
-{
- dbdma_cmd *current = &ch->current;
-
- if (conditional_wait(ch))
- goto wait;
-
- current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]);
- dbdma_cmdptr_save(ch);
-
- conditional_interrupt(ch);
- conditional_branch(ch);
-
-wait:
- DBDMA_kick(dbdma_from_ch(ch));
-}
-
-static void stop(DBDMA_channel *ch)
-{
- ch->regs[DBDMA_STATUS] &= ~(ACTIVE|DEAD|FLUSH);
-
- /* the stop command does not increment command pointer */
-}
-
-static void channel_run(DBDMA_channel *ch)
-{
- dbdma_cmd *current = &ch->current;
- uint16_t cmd, key;
- uint16_t req_count;
- uint32_t phy_addr;
-
- DBDMA_DPRINTF("channel_run\n");
- dump_dbdma_cmd(current);
-
- /* clear WAKE flag at command fetch */
-
- ch->regs[DBDMA_STATUS] &= ~WAKE;
-
- cmd = le16_to_cpu(current->command) & COMMAND_MASK;
-
- switch (cmd) {
- case DBDMA_NOP:
- nop(ch);
- return;
-
- case DBDMA_STOP:
- stop(ch);
- return;
- }
-
- key = le16_to_cpu(current->command) & 0x0700;
- req_count = le16_to_cpu(current->req_count);
- phy_addr = le32_to_cpu(current->phy_addr);
-
- if (key == KEY_STREAM4) {
- printf("command %x, invalid key 4\n", cmd);
- kill_channel(ch);
- return;
- }
-
- switch (cmd) {
- case OUTPUT_MORE:
- start_output(ch, key, phy_addr, req_count, 0);
- return;
-
- case OUTPUT_LAST:
- start_output(ch, key, phy_addr, req_count, 1);
- return;
-
- case INPUT_MORE:
- start_input(ch, key, phy_addr, req_count, 0);
- return;
-
- case INPUT_LAST:
- start_input(ch, key, phy_addr, req_count, 1);
- return;
- }
-
- if (key < KEY_REGS) {
- printf("command %x, invalid key %x\n", cmd, key);
- key = KEY_SYSTEM;
- }
-
- /* for LOAD_WORD and STORE_WORD, req_count is on 3 bits
- * and BRANCH is invalid
- */
-
- req_count = req_count & 0x0007;
- if (req_count & 0x4) {
- req_count = 4;
- phy_addr &= ~3;
- } else if (req_count & 0x2) {
- req_count = 2;
- phy_addr &= ~1;
- } else
- req_count = 1;
-
- switch (cmd) {
- case LOAD_WORD:
- load_word(ch, key, phy_addr, req_count);
- return;
-
- case STORE_WORD:
- store_word(ch, key, phy_addr, req_count);
- return;
- }
-}
-
-static void DBDMA_run(DBDMAState *s)
-{
- int channel;
-
- for (channel = 0; channel < DBDMA_CHANNELS; channel++) {
- DBDMA_channel *ch = &s->channels[channel];
- uint32_t status = ch->regs[DBDMA_STATUS];
- if (!ch->io.processing && (status & RUN) && (status & ACTIVE)) {
- channel_run(ch);
- }
- }
-}
-
-static void DBDMA_run_bh(void *opaque)
-{
- DBDMAState *s = opaque;
-
- DBDMA_DPRINTF("DBDMA_run_bh\n");
-
- DBDMA_run(s);
-}
-
-void DBDMA_kick(DBDMAState *dbdma)
-{
- qemu_bh_schedule(dbdma->bh);
-}
-
-void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq,
- DBDMA_rw rw, DBDMA_flush flush,
- void *opaque)
-{
- DBDMAState *s = dbdma;
- DBDMA_channel *ch = &s->channels[nchan];
-
- DBDMA_DPRINTF("DBDMA_register_channel 0x%x\n", nchan);
-
- assert(rw);
- assert(flush);
-
- ch->irq = irq;
- ch->rw = rw;
- ch->flush = flush;
- ch->io.opaque = opaque;
-}
-
-static void
-dbdma_control_write(DBDMA_channel *ch)
-{
- uint16_t mask, value;
- uint32_t status;
-
- mask = (ch->regs[DBDMA_CONTROL] >> 16) & 0xffff;
- value = ch->regs[DBDMA_CONTROL] & 0xffff;
-
- value &= (RUN | PAUSE | FLUSH | WAKE | DEVSTAT);
-
- status = ch->regs[DBDMA_STATUS];
-
- status = (value & mask) | (status & ~mask);
-
- if (status & WAKE)
- status |= ACTIVE;
- if (status & RUN) {
- status |= ACTIVE;
- status &= ~DEAD;
- }
- if (status & PAUSE)
- status &= ~ACTIVE;
- if ((ch->regs[DBDMA_STATUS] & RUN) && !(status & RUN)) {
- /* RUN is cleared */
- status &= ~(ACTIVE|DEAD);
- }
-
- if ((status & FLUSH) && ch->flush) {
- ch->flush(&ch->io);
- status &= ~FLUSH;
- }
-
- DBDMA_DPRINTF(" status 0x%08x\n", status);
-
- ch->regs[DBDMA_STATUS] = status;
-
- if (status & ACTIVE) {
- DBDMA_kick(dbdma_from_ch(ch));
- }
-}
-
-static void dbdma_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- int channel = addr >> DBDMA_CHANNEL_SHIFT;
- DBDMAState *s = opaque;
- DBDMA_channel *ch = &s->channels[channel];
- int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2;
-
- DBDMA_DPRINTF("writel 0x" TARGET_FMT_plx " <= 0x%08"PRIx64"\n",
- addr, value);
- DBDMA_DPRINTF("channel 0x%x reg 0x%x\n",
- (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg);
-
- /* cmdptr cannot be modified if channel is ACTIVE */
-
- if (reg == DBDMA_CMDPTR_LO && (ch->regs[DBDMA_STATUS] & ACTIVE)) {
- return;
- }
-
- ch->regs[reg] = value;
-
- switch(reg) {
- case DBDMA_CONTROL:
- dbdma_control_write(ch);
- break;
- case DBDMA_CMDPTR_LO:
- /* 16-byte aligned */
- ch->regs[DBDMA_CMDPTR_LO] &= ~0xf;
- dbdma_cmdptr_load(ch);
- break;
- case DBDMA_STATUS:
- case DBDMA_INTR_SEL:
- case DBDMA_BRANCH_SEL:
- case DBDMA_WAIT_SEL:
- /* nothing to do */
- break;
- case DBDMA_XFER_MODE:
- case DBDMA_CMDPTR_HI:
- case DBDMA_DATA2PTR_HI:
- case DBDMA_DATA2PTR_LO:
- case DBDMA_ADDRESS_HI:
- case DBDMA_BRANCH_ADDR_HI:
- case DBDMA_RES1:
- case DBDMA_RES2:
- case DBDMA_RES3:
- case DBDMA_RES4:
- /* unused */
- break;
- }
-}
-
-static uint64_t dbdma_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- uint32_t value;
- int channel = addr >> DBDMA_CHANNEL_SHIFT;
- DBDMAState *s = opaque;
- DBDMA_channel *ch = &s->channels[channel];
- int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2;
-
- value = ch->regs[reg];
-
- DBDMA_DPRINTF("readl 0x" TARGET_FMT_plx " => 0x%08x\n", addr, value);
- DBDMA_DPRINTF("channel 0x%x reg 0x%x\n",
- (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg);
-
- switch(reg) {
- case DBDMA_CONTROL:
- value = 0;
- break;
- case DBDMA_STATUS:
- case DBDMA_CMDPTR_LO:
- case DBDMA_INTR_SEL:
- case DBDMA_BRANCH_SEL:
- case DBDMA_WAIT_SEL:
- /* nothing to do */
- break;
- case DBDMA_XFER_MODE:
- case DBDMA_CMDPTR_HI:
- case DBDMA_DATA2PTR_HI:
- case DBDMA_DATA2PTR_LO:
- case DBDMA_ADDRESS_HI:
- case DBDMA_BRANCH_ADDR_HI:
- /* unused */
- value = 0;
- break;
- case DBDMA_RES1:
- case DBDMA_RES2:
- case DBDMA_RES3:
- case DBDMA_RES4:
- /* reserved */
- break;
- }
-
- return value;
-}
-
-static const MemoryRegionOps dbdma_ops = {
- .read = dbdma_read,
- .write = dbdma_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static const VMStateDescription vmstate_dbdma_io = {
- .name = "dbdma_io",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_UINT64(addr, struct DBDMA_io),
- VMSTATE_INT32(len, struct DBDMA_io),
- VMSTATE_INT32(is_last, struct DBDMA_io),
- VMSTATE_INT32(is_dma_out, struct DBDMA_io),
- VMSTATE_BOOL(processing, struct DBDMA_io),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_dbdma_cmd = {
- .name = "dbdma_cmd",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_UINT16(req_count, dbdma_cmd),
- VMSTATE_UINT16(command, dbdma_cmd),
- VMSTATE_UINT32(phy_addr, dbdma_cmd),
- VMSTATE_UINT32(cmd_dep, dbdma_cmd),
- VMSTATE_UINT16(res_count, dbdma_cmd),
- VMSTATE_UINT16(xfer_status, dbdma_cmd),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_dbdma_channel = {
- .name = "dbdma_channel",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, struct DBDMA_channel, DBDMA_REGS),
- VMSTATE_STRUCT(io, struct DBDMA_channel, 0, vmstate_dbdma_io, DBDMA_io),
- VMSTATE_STRUCT(current, struct DBDMA_channel, 0, vmstate_dbdma_cmd,
- dbdma_cmd),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_dbdma = {
- .name = "dbdma",
- .version_id = 3,
- .minimum_version_id = 3,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT_ARRAY(channels, DBDMAState, DBDMA_CHANNELS, 1,
- vmstate_dbdma_channel, DBDMA_channel),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void dbdma_reset(void *opaque)
-{
- DBDMAState *s = opaque;
- int i;
-
- for (i = 0; i < DBDMA_CHANNELS; i++)
- memset(s->channels[i].regs, 0, DBDMA_SIZE);
-}
-
-static void dbdma_unassigned_rw(DBDMA_io *io)
-{
- DBDMA_channel *ch = io->channel;
- qemu_log_mask(LOG_GUEST_ERROR, "%s: use of unassigned channel %d\n",
- __func__, ch->channel);
-}
-
-static void dbdma_unassigned_flush(DBDMA_io *io)
-{
- DBDMA_channel *ch = io->channel;
- qemu_log_mask(LOG_GUEST_ERROR, "%s: use of unassigned channel %d\n",
- __func__, ch->channel);
-}
-
-void* DBDMA_init (MemoryRegion **dbdma_mem)
-{
- DBDMAState *s;
- int i;
-
- s = g_malloc0(sizeof(DBDMAState));
-
- for (i = 0; i < DBDMA_CHANNELS; i++) {
- DBDMA_io *io = &s->channels[i].io;
- DBDMA_channel *ch = &s->channels[i];
- qemu_iovec_init(&io->iov, 1);
-
- ch->rw = dbdma_unassigned_rw;
- ch->flush = dbdma_unassigned_flush;
- ch->channel = i;
- ch->io.channel = ch;
- }
-
- memory_region_init_io(&s->mem, NULL, &dbdma_ops, s, "dbdma", 0x1000);
- *dbdma_mem = &s->mem;
- vmstate_register(NULL, -1, &vmstate_dbdma, s);
- qemu_register_reset(dbdma_reset, s);
-
- s->bh = qemu_bh_new(DBDMA_run_bh, s);
-
- return s;
-}
diff --git a/qemu/hw/misc/macio/macio.c b/qemu/hw/misc/macio/macio.c
deleted file mode 100644
index be03926b9..000000000
--- a/qemu/hw/misc/macio/macio.c
+++ /dev/null
@@ -1,449 +0,0 @@
-/*
- * PowerMac MacIO device emulation
- *
- * Copyright (c) 2005-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.
- */
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/hw.h"
-#include "hw/ppc/mac.h"
-#include "hw/pci/pci.h"
-#include "hw/ppc/mac_dbdma.h"
-#include "hw/char/escc.h"
-
-#define TYPE_MACIO "macio"
-#define MACIO(obj) OBJECT_CHECK(MacIOState, (obj), TYPE_MACIO)
-
-typedef struct MacIOState
-{
- /*< private >*/
- PCIDevice parent;
- /*< public >*/
-
- MemoryRegion bar;
- CUDAState cuda;
- void *dbdma;
- MemoryRegion *pic_mem;
- MemoryRegion *escc_mem;
- uint64_t frequency;
-} MacIOState;
-
-#define OLDWORLD_MACIO(obj) \
- OBJECT_CHECK(OldWorldMacIOState, (obj), TYPE_OLDWORLD_MACIO)
-
-typedef struct OldWorldMacIOState {
- /*< private >*/
- MacIOState parent_obj;
- /*< public >*/
-
- qemu_irq irqs[5];
-
- MacIONVRAMState nvram;
- MACIOIDEState ide[2];
-} 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;
-
-/*
- * The mac-io has two interfaces to the ESCC. One is called "escc-legacy",
- * while the other one is the normal, current ESCC interface.
- *
- * The magic below creates memory aliases to spawn the escc-legacy device
- * purely by rerouting the respective registers to our escc region. This
- * works because the only difference between the two memory regions is the
- * register layout, not their semantics.
- *
- * Reference: ftp://ftp.software.ibm.com/rs6000/technology/spec/chrp/inwork/CHRP_IORef_1.0.pdf
- */
-static void macio_escc_legacy_setup(MacIOState *macio_state)
-{
- MemoryRegion *escc_legacy = g_new(MemoryRegion, 1);
- MemoryRegion *bar = &macio_state->bar;
- int i;
- static const int maps[] = {
- 0x00, 0x00,
- 0x02, 0x20,
- 0x04, 0x10,
- 0x06, 0x30,
- 0x08, 0x40,
- 0x0A, 0x50,
- 0x60, 0x60,
- 0x70, 0x70,
- 0x80, 0x70,
- 0x90, 0x80,
- 0xA0, 0x90,
- 0xB0, 0xA0,
- 0xC0, 0xB0,
- 0xD0, 0xC0,
- 0xE0, 0xD0,
- 0xF0, 0xE0,
- };
-
- memory_region_init(escc_legacy, OBJECT(macio_state), "escc-legacy", 256);
- for (i = 0; i < ARRAY_SIZE(maps); i += 2) {
- MemoryRegion *port = g_new(MemoryRegion, 1);
- memory_region_init_alias(port, OBJECT(macio_state), "escc-legacy-port",
- macio_state->escc_mem, maps[i+1], 0x2);
- memory_region_add_subregion(escc_legacy, maps[i], port);
- }
-
- memory_region_add_subregion(bar, 0x12000, escc_legacy);
-}
-
-static void macio_bar_setup(MacIOState *macio_state)
-{
- MemoryRegion *bar = &macio_state->bar;
-
- if (macio_state->escc_mem) {
- memory_region_add_subregion(bar, 0x13000, macio_state->escc_mem);
- macio_escc_legacy_setup(macio_state);
- }
-}
-
-static void macio_common_realize(PCIDevice *d, Error **errp)
-{
- MacIOState *s = MACIO(d);
- SysBusDevice *sysbus_dev;
- Error *err = NULL;
- MemoryRegion *dbdma_mem;
-
- s->dbdma = DBDMA_init(&dbdma_mem);
- memory_region_add_subregion(&s->bar, 0x08000, dbdma_mem);
-
- object_property_set_bool(OBJECT(&s->cuda), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- 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);
-}
-
-static void macio_realize_ide(MacIOState *s, MACIOIDEState *ide,
- qemu_irq irq0, qemu_irq irq1, int dmaid,
- Error **errp)
-{
- SysBusDevice *sysbus_dev;
-
- sysbus_dev = SYS_BUS_DEVICE(ide);
- sysbus_connect_irq(sysbus_dev, 0, irq0);
- sysbus_connect_irq(sysbus_dev, 1, irq1);
- macio_ide_register_dma(ide, s->dbdma, dmaid);
- object_property_set_bool(OBJECT(ide), true, "realized", errp);
-}
-
-static void macio_oldworld_realize(PCIDevice *d, Error **errp)
-{
- MacIOState *s = MACIO(d);
- OldWorldMacIOState *os = OLDWORLD_MACIO(d);
- Error *err = NULL;
- SysBusDevice *sysbus_dev;
- int i;
- int cur_irq = 0;
-
- macio_common_realize(d, &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
- sysbus_connect_irq(sysbus_dev, 0, os->irqs[cur_irq++]);
-
- object_property_set_bool(OBJECT(&os->nvram), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- 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);
- }
-
- /* IDE buses */
- for (i = 0; i < ARRAY_SIZE(os->ide); i++) {
- qemu_irq irq0 = os->irqs[cur_irq++];
- qemu_irq irq1 = os->irqs[cur_irq++];
-
- macio_realize_ide(s, &os->ide[i], irq0, irq1, 0x16 + (i * 4), &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- }
-}
-
-static void macio_init_ide(MacIOState *s, MACIOIDEState *ide, size_t ide_size,
- int index)
-{
- gchar *name;
-
- object_initialize(ide, ide_size, TYPE_MACIO_IDE);
- qdev_set_parent_bus(DEVICE(ide), sysbus_get_default());
- memory_region_add_subregion(&s->bar, 0x1f000 + ((index + 1) * 0x1000),
- &ide->mem);
- name = g_strdup_printf("ide[%i]", index);
- object_property_add_child(OBJECT(s), name, OBJECT(ide), NULL);
- g_free(name);
-}
-
-static void macio_oldworld_init(Object *obj)
-{
- MacIOState *s = MACIO(obj);
- OldWorldMacIOState *os = OLDWORLD_MACIO(obj);
- DeviceState *dev;
- int i;
-
- qdev_init_gpio_out(DEVICE(obj), os->irqs, ARRAY_SIZE(os->irqs));
-
- object_initialize(&os->nvram, sizeof(os->nvram), TYPE_MACIO_NVRAM);
- dev = DEVICE(&os->nvram);
- qdev_prop_set_uint32(dev, "size", 0x2000);
- qdev_prop_set_uint32(dev, "it_shift", 4);
-
- for (i = 0; i < 2; i++) {
- macio_init_ide(s, &os->ide[i], sizeof(os->ide[i]), i);
- }
-}
-
-static void timer_write(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
-}
-
-static uint64_t timer_read(void *opaque, hwaddr addr, unsigned size)
-{
- uint32_t value = 0;
- uint64_t systime = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- uint64_t kltime;
-
- kltime = muldiv64(systime, 4194300, NANOSECONDS_PER_SECOND * 4);
- kltime = muldiv64(kltime, 18432000, 1048575);
-
- switch (addr) {
- case 0x38:
- value = kltime;
- break;
- case 0x3c:
- value = kltime >> 32;
- break;
- }
-
- return value;
-}
-
-static const MemoryRegionOps timer_ops = {
- .read = timer_read,
- .write = timer_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void macio_newworld_realize(PCIDevice *d, Error **errp)
-{
- MacIOState *s = MACIO(d);
- NewWorldMacIOState *ns = NEWWORLD_MACIO(d);
- Error *err = NULL;
- SysBusDevice *sysbus_dev;
- MemoryRegion *timer_memory = NULL;
- int i;
- int cur_irq = 0;
-
- macio_common_realize(d, &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
- sysbus_connect_irq(sysbus_dev, 0, ns->irqs[cur_irq++]);
-
- if (s->pic_mem) {
- /* OpenPIC */
- memory_region_add_subregion(&s->bar, 0x40000, s->pic_mem);
- }
-
- /* IDE buses */
- for (i = 0; i < ARRAY_SIZE(ns->ide); i++) {
- qemu_irq irq0 = ns->irqs[cur_irq++];
- qemu_irq irq1 = ns->irqs[cur_irq++];
-
- macio_realize_ide(s, &ns->ide[i], irq0, irq1, 0x16 + (i * 4), &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- }
-
- /* Timer */
- timer_memory = g_new(MemoryRegion, 1);
- memory_region_init_io(timer_memory, OBJECT(s), &timer_ops, NULL, "timer",
- 0x1000);
- memory_region_add_subregion(&s->bar, 0x15000, timer_memory);
-}
-
-static void macio_newworld_init(Object *obj)
-{
- MacIOState *s = MACIO(obj);
- NewWorldMacIOState *ns = NEWWORLD_MACIO(obj);
- int i;
-
- qdev_init_gpio_out(DEVICE(obj), ns->irqs, ARRAY_SIZE(ns->irqs));
-
- for (i = 0; i < 2; i++) {
- macio_init_ide(s, &ns->ide[i], sizeof(ns->ide[i]), i);
- }
-}
-
-static void macio_instance_init(Object *obj)
-{
- MacIOState *s = MACIO(obj);
-
- memory_region_init(&s->bar, obj, "macio", 0x80000);
-
- object_initialize(&s->cuda, sizeof(s->cuda), TYPE_CUDA);
- qdev_set_parent_bus(DEVICE(&s->cuda), sysbus_get_default());
- object_property_add_child(obj, "cuda", OBJECT(&s->cuda), NULL);
-}
-
-static const VMStateDescription vmstate_macio_oldworld = {
- .name = "macio-oldworld",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(parent_obj.parent, OldWorldMacIOState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void macio_oldworld_class_init(ObjectClass *oc, void *data)
-{
- PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc);
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- pdc->realize = macio_oldworld_realize;
- pdc->device_id = PCI_DEVICE_ID_APPLE_343S1201;
- dc->vmsd = &vmstate_macio_oldworld;
-}
-
-static const VMStateDescription vmstate_macio_newworld = {
- .name = "macio-newworld",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(parent_obj.parent, NewWorldMacIOState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void macio_newworld_class_init(ObjectClass *oc, void *data)
-{
- PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc);
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- pdc->realize = macio_newworld_realize;
- pdc->device_id = PCI_DEVICE_ID_APPLE_UNI_N_KEYL;
- dc->vmsd = &vmstate_macio_newworld;
-}
-
-static Property macio_properties[] = {
- DEFINE_PROP_UINT64("frequency", MacIOState, frequency, 0),
- DEFINE_PROP_END_OF_LIST()
-};
-
-static void macio_class_init(ObjectClass *klass, void *data)
-{
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- k->vendor_id = PCI_VENDOR_ID_APPLE;
- k->class_id = PCI_CLASS_OTHERS << 8;
- dc->props = macio_properties;
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
-}
-
-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_type_info);
- type_register_static(&macio_oldworld_type_info);
- type_register_static(&macio_newworld_type_info);
-}
-
-type_init(macio_register_types)
-
-void macio_init(PCIDevice *d,
- MemoryRegion *pic_mem,
- MemoryRegion *escc_mem)
-{
- MacIOState *macio_state = MACIO(d);
-
- macio_state->pic_mem = pic_mem;
- macio_state->escc_mem = escc_mem;
- /* Note: this code is strongly inspirated from the corresponding code
- in PearPC */
- qdev_prop_set_uint64(DEVICE(&macio_state->cuda), "frequency",
- macio_state->frequency);
-
- qdev_init_nofail(DEVICE(d));
-}
diff --git a/qemu/hw/misc/max111x.c b/qemu/hw/misc/max111x.c
deleted file mode 100644
index 9014f0f70..000000000
--- a/qemu/hw/misc/max111x.c
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Maxim MAX1110/1111 ADC chip emulation.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GNU GPLv2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "hw/ssi/ssi.h"
-
-typedef struct {
- SSISlave parent_obj;
-
- qemu_irq interrupt;
- uint8_t tb1, rb2, rb3;
- int cycle;
-
- uint8_t input[8];
- int inputs, com;
-} MAX111xState;
-
-#define TYPE_MAX_111X "max111x"
-
-#define MAX_111X(obj) \
- OBJECT_CHECK(MAX111xState, (obj), TYPE_MAX_111X)
-
-#define TYPE_MAX_1110 "max1110"
-#define TYPE_MAX_1111 "max1111"
-
-/* Control-byte bitfields */
-#define CB_PD0 (1 << 0)
-#define CB_PD1 (1 << 1)
-#define CB_SGL (1 << 2)
-#define CB_UNI (1 << 3)
-#define CB_SEL0 (1 << 4)
-#define CB_SEL1 (1 << 5)
-#define CB_SEL2 (1 << 6)
-#define CB_START (1 << 7)
-
-#define CHANNEL_NUM(v, b0, b1, b2) \
- ((((v) >> (2 + (b0))) & 4) | \
- (((v) >> (3 + (b1))) & 2) | \
- (((v) >> (4 + (b2))) & 1))
-
-static uint32_t max111x_read(MAX111xState *s)
-{
- if (!s->tb1)
- return 0;
-
- switch (s->cycle ++) {
- case 1:
- return s->rb2;
- case 2:
- return s->rb3;
- }
-
- return 0;
-}
-
-/* Interpret a control-byte */
-static void max111x_write(MAX111xState *s, uint32_t value)
-{
- int measure, chan;
-
- /* Ignore the value if START bit is zero */
- if (!(value & CB_START))
- return;
-
- s->cycle = 0;
-
- if (!(value & CB_PD1)) {
- s->tb1 = 0;
- return;
- }
-
- s->tb1 = value;
-
- if (s->inputs == 8)
- chan = CHANNEL_NUM(value, 1, 0, 2);
- else
- chan = CHANNEL_NUM(value & ~CB_SEL0, 0, 1, 2);
-
- if (value & CB_SGL)
- measure = s->input[chan] - s->com;
- else
- measure = s->input[chan] - s->input[chan ^ 1];
-
- if (!(value & CB_UNI))
- measure ^= 0x80;
-
- s->rb2 = (measure >> 2) & 0x3f;
- s->rb3 = (measure << 6) & 0xc0;
-
- /* FIXME: When should the IRQ be lowered? */
- qemu_irq_raise(s->interrupt);
-}
-
-static uint32_t max111x_transfer(SSISlave *dev, uint32_t value)
-{
- MAX111xState *s = MAX_111X(dev);
- max111x_write(s, value);
- return max111x_read(s);
-}
-
-static const VMStateDescription vmstate_max111x = {
- .name = "max111x",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_SSI_SLAVE(parent_obj, MAX111xState),
- VMSTATE_UINT8(tb1, MAX111xState),
- VMSTATE_UINT8(rb2, MAX111xState),
- VMSTATE_UINT8(rb3, MAX111xState),
- VMSTATE_INT32_EQUAL(inputs, MAX111xState),
- VMSTATE_INT32(com, MAX111xState),
- VMSTATE_ARRAY_INT32_UNSAFE(input, MAX111xState, inputs,
- vmstate_info_uint8, uint8_t),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static int max111x_init(SSISlave *d, int inputs)
-{
- DeviceState *dev = DEVICE(d);
- MAX111xState *s = MAX_111X(dev);
-
- qdev_init_gpio_out(dev, &s->interrupt, 1);
-
- s->inputs = inputs;
- /* TODO: add a user interface for setting these */
- s->input[0] = 0xf0;
- s->input[1] = 0xe0;
- s->input[2] = 0xd0;
- s->input[3] = 0xc0;
- s->input[4] = 0xb0;
- s->input[5] = 0xa0;
- s->input[6] = 0x90;
- s->input[7] = 0x80;
- s->com = 0;
-
- vmstate_register(dev, -1, &vmstate_max111x, s);
- return 0;
-}
-
-static int max1110_init(SSISlave *dev)
-{
- return max111x_init(dev, 8);
-}
-
-static int max1111_init(SSISlave *dev)
-{
- return max111x_init(dev, 4);
-}
-
-void max111x_set_input(DeviceState *dev, int line, uint8_t value)
-{
- MAX111xState *s = MAX_111X(dev);
- assert(line >= 0 && line < s->inputs);
- s->input[line] = value;
-}
-
-static void max111x_class_init(ObjectClass *klass, void *data)
-{
- SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
-
- k->transfer = max111x_transfer;
-}
-
-static const TypeInfo max111x_info = {
- .name = TYPE_MAX_111X,
- .parent = TYPE_SSI_SLAVE,
- .instance_size = sizeof(MAX111xState),
- .class_init = max111x_class_init,
- .abstract = true,
-};
-
-static void max1110_class_init(ObjectClass *klass, void *data)
-{
- SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
-
- k->init = max1110_init;
-}
-
-static const TypeInfo max1110_info = {
- .name = TYPE_MAX_1110,
- .parent = TYPE_MAX_111X,
- .class_init = max1110_class_init,
-};
-
-static void max1111_class_init(ObjectClass *klass, void *data)
-{
- SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
-
- k->init = max1111_init;
-}
-
-static const TypeInfo max1111_info = {
- .name = TYPE_MAX_1111,
- .parent = TYPE_MAX_111X,
- .class_init = max1111_class_init,
-};
-
-static void max111x_register_types(void)
-{
- type_register_static(&max111x_info);
- type_register_static(&max1110_info);
- type_register_static(&max1111_info);
-}
-
-type_init(max111x_register_types)
diff --git a/qemu/hw/misc/milkymist-hpdmc.c b/qemu/hw/misc/milkymist-hpdmc.c
deleted file mode 100644
index b97000fc4..000000000
--- a/qemu/hw/misc/milkymist-hpdmc.c
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * QEMU model of the Milkymist High Performance Dynamic Memory Controller.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * Specification available at:
- * http://www.milkymist.org/socdoc/hpdmc.pdf
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "qemu/error-report.h"
-
-enum {
- R_SYSTEM = 0,
- R_BYPASS,
- R_TIMING,
- R_IODELAY,
- R_MAX
-};
-
-enum {
- IODELAY_DQSDELAY_RDY = (1<<5),
- IODELAY_PLL1_LOCKED = (1<<6),
- IODELAY_PLL2_LOCKED = (1<<7),
-};
-
-#define TYPE_MILKYMIST_HPDMC "milkymist-hpdmc"
-#define MILKYMIST_HPDMC(obj) \
- OBJECT_CHECK(MilkymistHpdmcState, (obj), TYPE_MILKYMIST_HPDMC)
-
-struct MilkymistHpdmcState {
- SysBusDevice parent_obj;
-
- MemoryRegion regs_region;
-
- uint32_t regs[R_MAX];
-};
-typedef struct MilkymistHpdmcState MilkymistHpdmcState;
-
-static uint64_t hpdmc_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- MilkymistHpdmcState *s = opaque;
- uint32_t r = 0;
-
- addr >>= 2;
- switch (addr) {
- case R_SYSTEM:
- case R_BYPASS:
- case R_TIMING:
- case R_IODELAY:
- r = s->regs[addr];
- break;
-
- default:
- error_report("milkymist_hpdmc: read access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-
- trace_milkymist_hpdmc_memory_read(addr << 2, r);
-
- return r;
-}
-
-static void hpdmc_write(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
- MilkymistHpdmcState *s = opaque;
-
- trace_milkymist_hpdmc_memory_write(addr, value);
-
- addr >>= 2;
- switch (addr) {
- case R_SYSTEM:
- case R_BYPASS:
- case R_TIMING:
- s->regs[addr] = value;
- break;
- case R_IODELAY:
- /* ignore writes */
- break;
-
- default:
- error_report("milkymist_hpdmc: write access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-}
-
-static const MemoryRegionOps hpdmc_mmio_ops = {
- .read = hpdmc_read,
- .write = hpdmc_write,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void milkymist_hpdmc_reset(DeviceState *d)
-{
- MilkymistHpdmcState *s = MILKYMIST_HPDMC(d);
- int i;
-
- for (i = 0; i < R_MAX; i++) {
- s->regs[i] = 0;
- }
-
- /* defaults */
- s->regs[R_IODELAY] = IODELAY_DQSDELAY_RDY | IODELAY_PLL1_LOCKED
- | IODELAY_PLL2_LOCKED;
-}
-
-static int milkymist_hpdmc_init(SysBusDevice *dev)
-{
- MilkymistHpdmcState *s = MILKYMIST_HPDMC(dev);
-
- memory_region_init_io(&s->regs_region, OBJECT(dev), &hpdmc_mmio_ops, s,
- "milkymist-hpdmc", R_MAX * 4);
- sysbus_init_mmio(dev, &s->regs_region);
-
- return 0;
-}
-
-static const VMStateDescription vmstate_milkymist_hpdmc = {
- .name = "milkymist-hpdmc",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, MilkymistHpdmcState, R_MAX),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void milkymist_hpdmc_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = milkymist_hpdmc_init;
- dc->reset = milkymist_hpdmc_reset;
- dc->vmsd = &vmstate_milkymist_hpdmc;
-}
-
-static const TypeInfo milkymist_hpdmc_info = {
- .name = TYPE_MILKYMIST_HPDMC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(MilkymistHpdmcState),
- .class_init = milkymist_hpdmc_class_init,
-};
-
-static void milkymist_hpdmc_register_types(void)
-{
- type_register_static(&milkymist_hpdmc_info);
-}
-
-type_init(milkymist_hpdmc_register_types)
diff --git a/qemu/hw/misc/milkymist-pfpu.c b/qemu/hw/misc/milkymist-pfpu.c
deleted file mode 100644
index 57acd7b36..000000000
--- a/qemu/hw/misc/milkymist-pfpu.c
+++ /dev/null
@@ -1,549 +0,0 @@
-/*
- * QEMU model of the Milkymist programmable FPU.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * Specification available at:
- * http://www.milkymist.org/socdoc/pfpu.pdf
- *
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "qemu/log.h"
-#include "qemu/error-report.h"
-#include <math.h>
-
-/* #define TRACE_EXEC */
-
-#ifdef TRACE_EXEC
-# define D_EXEC(x) x
-#else
-# define D_EXEC(x)
-#endif
-
-enum {
- R_CTL = 0,
- R_MESHBASE,
- R_HMESHLAST,
- R_VMESHLAST,
- R_CODEPAGE,
- R_VERTICES,
- R_COLLISIONS,
- R_STRAYWRITES,
- R_LASTDMA,
- R_PC,
- R_DREGBASE,
- R_CODEBASE,
- R_MAX
-};
-
-enum {
- CTL_START_BUSY = (1<<0),
-};
-
-enum {
- OP_NOP = 0,
- OP_FADD,
- OP_FSUB,
- OP_FMUL,
- OP_FABS,
- OP_F2I,
- OP_I2F,
- OP_VECTOUT,
- OP_SIN,
- OP_COS,
- OP_ABOVE,
- OP_EQUAL,
- OP_COPY,
- OP_IF,
- OP_TSIGN,
- OP_QUAKE,
-};
-
-enum {
- GPR_X = 0,
- GPR_Y = 1,
- GPR_FLAGS = 2,
-};
-
-enum {
- LATENCY_FADD = 5,
- LATENCY_FSUB = 5,
- LATENCY_FMUL = 7,
- LATENCY_FABS = 2,
- LATENCY_F2I = 2,
- LATENCY_I2F = 3,
- LATENCY_VECTOUT = 0,
- LATENCY_SIN = 4,
- LATENCY_COS = 4,
- LATENCY_ABOVE = 2,
- LATENCY_EQUAL = 2,
- LATENCY_COPY = 2,
- LATENCY_IF = 2,
- LATENCY_TSIGN = 2,
- LATENCY_QUAKE = 2,
- MAX_LATENCY = 7
-};
-
-#define GPR_BEGIN 0x100
-#define GPR_END 0x17f
-#define MICROCODE_BEGIN 0x200
-#define MICROCODE_END 0x3ff
-#define MICROCODE_WORDS 2048
-
-#define REINTERPRET_CAST(type, val) (*((type *)&(val)))
-
-#ifdef TRACE_EXEC
-static const char *opcode_to_str[] = {
- "NOP", "FADD", "FSUB", "FMUL", "FABS", "F2I", "I2F", "VECTOUT",
- "SIN", "COS", "ABOVE", "EQUAL", "COPY", "IF", "TSIGN", "QUAKE",
-};
-#endif
-
-#define TYPE_MILKYMIST_PFPU "milkymist-pfpu"
-#define MILKYMIST_PFPU(obj) \
- OBJECT_CHECK(MilkymistPFPUState, (obj), TYPE_MILKYMIST_PFPU)
-
-struct MilkymistPFPUState {
- SysBusDevice parent_obj;
-
- MemoryRegion regs_region;
- CharDriverState *chr;
- qemu_irq irq;
-
- uint32_t regs[R_MAX];
- uint32_t gp_regs[128];
- uint32_t microcode[MICROCODE_WORDS];
-
- int output_queue_pos;
- uint32_t output_queue[MAX_LATENCY];
-};
-typedef struct MilkymistPFPUState MilkymistPFPUState;
-
-static inline hwaddr
-get_dma_address(uint32_t base, uint32_t x, uint32_t y)
-{
- return base + 8 * (128 * y + x);
-}
-
-static inline void
-output_queue_insert(MilkymistPFPUState *s, uint32_t val, int pos)
-{
- s->output_queue[(s->output_queue_pos + pos) % MAX_LATENCY] = val;
-}
-
-static inline uint32_t
-output_queue_remove(MilkymistPFPUState *s)
-{
- return s->output_queue[s->output_queue_pos];
-}
-
-static inline void
-output_queue_advance(MilkymistPFPUState *s)
-{
- s->output_queue[s->output_queue_pos] = 0;
- s->output_queue_pos = (s->output_queue_pos + 1) % MAX_LATENCY;
-}
-
-static int pfpu_decode_insn(MilkymistPFPUState *s)
-{
- uint32_t pc = s->regs[R_PC];
- uint32_t insn = s->microcode[pc];
- uint32_t reg_a = (insn >> 18) & 0x7f;
- uint32_t reg_b = (insn >> 11) & 0x7f;
- uint32_t op = (insn >> 7) & 0xf;
- uint32_t reg_d = insn & 0x7f;
- uint32_t r = 0;
- int latency = 0;
-
- switch (op) {
- case OP_NOP:
- break;
- case OP_FADD:
- {
- float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
- float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
- float t = a + b;
- r = REINTERPRET_CAST(uint32_t, t);
- latency = LATENCY_FADD;
- D_EXEC(qemu_log("ADD a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
- } break;
- case OP_FSUB:
- {
- float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
- float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
- float t = a - b;
- r = REINTERPRET_CAST(uint32_t, t);
- latency = LATENCY_FSUB;
- D_EXEC(qemu_log("SUB a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
- } break;
- case OP_FMUL:
- {
- float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
- float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
- float t = a * b;
- r = REINTERPRET_CAST(uint32_t, t);
- latency = LATENCY_FMUL;
- D_EXEC(qemu_log("MUL a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
- } break;
- case OP_FABS:
- {
- float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
- float t = fabsf(a);
- r = REINTERPRET_CAST(uint32_t, t);
- latency = LATENCY_FABS;
- D_EXEC(qemu_log("ABS a=%f t=%f, r=%08x\n", a, t, r));
- } break;
- case OP_F2I:
- {
- float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
- int32_t t = a;
- r = REINTERPRET_CAST(uint32_t, t);
- latency = LATENCY_F2I;
- D_EXEC(qemu_log("F2I a=%f t=%d, r=%08x\n", a, t, r));
- } break;
- case OP_I2F:
- {
- int32_t a = REINTERPRET_CAST(int32_t, s->gp_regs[reg_a]);
- float t = a;
- r = REINTERPRET_CAST(uint32_t, t);
- latency = LATENCY_I2F;
- D_EXEC(qemu_log("I2F a=%08x t=%f, r=%08x\n", a, t, r));
- } break;
- case OP_VECTOUT:
- {
- uint32_t a = cpu_to_be32(s->gp_regs[reg_a]);
- uint32_t b = cpu_to_be32(s->gp_regs[reg_b]);
- hwaddr dma_ptr =
- get_dma_address(s->regs[R_MESHBASE],
- s->gp_regs[GPR_X], s->gp_regs[GPR_Y]);
- cpu_physical_memory_write(dma_ptr, &a, 4);
- cpu_physical_memory_write(dma_ptr + 4, &b, 4);
- s->regs[R_LASTDMA] = dma_ptr + 4;
- D_EXEC(qemu_log("VECTOUT a=%08x b=%08x dma=%08x\n", a, b, dma_ptr));
- trace_milkymist_pfpu_vectout(a, b, dma_ptr);
- } break;
- case OP_SIN:
- {
- int32_t a = REINTERPRET_CAST(int32_t, s->gp_regs[reg_a]);
- float t = sinf(a * (1.0f / (M_PI * 4096.0f)));
- r = REINTERPRET_CAST(uint32_t, t);
- latency = LATENCY_SIN;
- D_EXEC(qemu_log("SIN a=%d t=%f, r=%08x\n", a, t, r));
- } break;
- case OP_COS:
- {
- int32_t a = REINTERPRET_CAST(int32_t, s->gp_regs[reg_a]);
- float t = cosf(a * (1.0f / (M_PI * 4096.0f)));
- r = REINTERPRET_CAST(uint32_t, t);
- latency = LATENCY_COS;
- D_EXEC(qemu_log("COS a=%d t=%f, r=%08x\n", a, t, r));
- } break;
- case OP_ABOVE:
- {
- float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
- float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
- float t = (a > b) ? 1.0f : 0.0f;
- r = REINTERPRET_CAST(uint32_t, t);
- latency = LATENCY_ABOVE;
- D_EXEC(qemu_log("ABOVE a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
- } break;
- case OP_EQUAL:
- {
- float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
- float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
- float t = (a == b) ? 1.0f : 0.0f;
- r = REINTERPRET_CAST(uint32_t, t);
- latency = LATENCY_EQUAL;
- D_EXEC(qemu_log("EQUAL a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
- } break;
- case OP_COPY:
- {
- r = s->gp_regs[reg_a];
- latency = LATENCY_COPY;
- D_EXEC(qemu_log("COPY"));
- } break;
- case OP_IF:
- {
- float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
- float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
- uint32_t f = s->gp_regs[GPR_FLAGS];
- float t = (f != 0) ? a : b;
- r = REINTERPRET_CAST(uint32_t, t);
- latency = LATENCY_IF;
- D_EXEC(qemu_log("IF f=%u a=%f b=%f t=%f, r=%08x\n", f, a, b, t, r));
- } break;
- case OP_TSIGN:
- {
- float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
- float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
- float t = (b < 0) ? -a : a;
- r = REINTERPRET_CAST(uint32_t, t);
- latency = LATENCY_TSIGN;
- D_EXEC(qemu_log("TSIGN a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
- } break;
- case OP_QUAKE:
- {
- uint32_t a = s->gp_regs[reg_a];
- r = 0x5f3759df - (a >> 1);
- latency = LATENCY_QUAKE;
- D_EXEC(qemu_log("QUAKE a=%d r=%08x\n", a, r));
- } break;
-
- default:
- error_report("milkymist_pfpu: unknown opcode %d", op);
- break;
- }
-
- if (!reg_d) {
- D_EXEC(qemu_log("%04d %8s R%03d, R%03d <L=%d, E=%04d>\n",
- s->regs[R_PC], opcode_to_str[op], reg_a, reg_b, latency,
- s->regs[R_PC] + latency));
- } else {
- D_EXEC(qemu_log("%04d %8s R%03d, R%03d <L=%d, E=%04d> -> R%03d\n",
- s->regs[R_PC], opcode_to_str[op], reg_a, reg_b, latency,
- s->regs[R_PC] + latency, reg_d));
- }
-
- if (op == OP_VECTOUT) {
- return 0;
- }
-
- /* store output for this cycle */
- if (reg_d) {
- uint32_t val = output_queue_remove(s);
- D_EXEC(qemu_log("R%03d <- 0x%08x\n", reg_d, val));
- s->gp_regs[reg_d] = val;
- }
-
- output_queue_advance(s);
-
- /* store op output */
- if (op != OP_NOP) {
- output_queue_insert(s, r, latency-1);
- }
-
- /* advance PC */
- s->regs[R_PC]++;
-
- return 1;
-};
-
-static void pfpu_start(MilkymistPFPUState *s)
-{
- int x, y;
- int i;
-
- for (y = 0; y <= s->regs[R_VMESHLAST]; y++) {
- for (x = 0; x <= s->regs[R_HMESHLAST]; x++) {
- D_EXEC(qemu_log("\nprocessing x=%d y=%d\n", x, y));
-
- /* set current position */
- s->gp_regs[GPR_X] = x;
- s->gp_regs[GPR_Y] = y;
-
- /* run microcode on this position */
- i = 0;
- while (pfpu_decode_insn(s)) {
- /* decode at most MICROCODE_WORDS instructions */
- if (++i >= MICROCODE_WORDS) {
- error_report("milkymist_pfpu: too many instructions "
- "executed in microcode. No VECTOUT?");
- break;
- }
- }
-
- /* reset pc for next run */
- s->regs[R_PC] = 0;
- }
- }
-
- s->regs[R_VERTICES] = x * y;
-
- trace_milkymist_pfpu_pulse_irq();
- qemu_irq_pulse(s->irq);
-}
-
-static inline int get_microcode_address(MilkymistPFPUState *s, uint32_t addr)
-{
- return (512 * s->regs[R_CODEPAGE]) + addr - MICROCODE_BEGIN;
-}
-
-static uint64_t pfpu_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- MilkymistPFPUState *s = opaque;
- uint32_t r = 0;
-
- addr >>= 2;
- switch (addr) {
- case R_CTL:
- case R_MESHBASE:
- case R_HMESHLAST:
- case R_VMESHLAST:
- case R_CODEPAGE:
- case R_VERTICES:
- case R_COLLISIONS:
- case R_STRAYWRITES:
- case R_LASTDMA:
- case R_PC:
- case R_DREGBASE:
- case R_CODEBASE:
- r = s->regs[addr];
- break;
- case GPR_BEGIN ... GPR_END:
- r = s->gp_regs[addr - GPR_BEGIN];
- break;
- case MICROCODE_BEGIN ... MICROCODE_END:
- r = s->microcode[get_microcode_address(s, addr)];
- break;
-
- default:
- error_report("milkymist_pfpu: read access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-
- trace_milkymist_pfpu_memory_read(addr << 2, r);
-
- return r;
-}
-
-static void pfpu_write(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
- MilkymistPFPUState *s = opaque;
-
- trace_milkymist_pfpu_memory_write(addr, value);
-
- addr >>= 2;
- switch (addr) {
- case R_CTL:
- if (value & CTL_START_BUSY) {
- pfpu_start(s);
- }
- break;
- case R_MESHBASE:
- case R_HMESHLAST:
- case R_VMESHLAST:
- case R_CODEPAGE:
- case R_VERTICES:
- case R_COLLISIONS:
- case R_STRAYWRITES:
- case R_LASTDMA:
- case R_PC:
- case R_DREGBASE:
- case R_CODEBASE:
- s->regs[addr] = value;
- break;
- case GPR_BEGIN ... GPR_END:
- s->gp_regs[addr - GPR_BEGIN] = value;
- break;
- case MICROCODE_BEGIN ... MICROCODE_END:
- s->microcode[get_microcode_address(s, addr)] = value;
- break;
-
- default:
- error_report("milkymist_pfpu: write access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-}
-
-static const MemoryRegionOps pfpu_mmio_ops = {
- .read = pfpu_read,
- .write = pfpu_write,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void milkymist_pfpu_reset(DeviceState *d)
-{
- MilkymistPFPUState *s = MILKYMIST_PFPU(d);
- int i;
-
- for (i = 0; i < R_MAX; i++) {
- s->regs[i] = 0;
- }
- for (i = 0; i < 128; i++) {
- s->gp_regs[i] = 0;
- }
- for (i = 0; i < MICROCODE_WORDS; i++) {
- s->microcode[i] = 0;
- }
- s->output_queue_pos = 0;
- for (i = 0; i < MAX_LATENCY; i++) {
- s->output_queue[i] = 0;
- }
-}
-
-static int milkymist_pfpu_init(SysBusDevice *dev)
-{
- MilkymistPFPUState *s = MILKYMIST_PFPU(dev);
-
- sysbus_init_irq(dev, &s->irq);
-
- memory_region_init_io(&s->regs_region, OBJECT(dev), &pfpu_mmio_ops, s,
- "milkymist-pfpu", MICROCODE_END * 4);
- sysbus_init_mmio(dev, &s->regs_region);
-
- return 0;
-}
-
-static const VMStateDescription vmstate_milkymist_pfpu = {
- .name = "milkymist-pfpu",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, MilkymistPFPUState, R_MAX),
- VMSTATE_UINT32_ARRAY(gp_regs, MilkymistPFPUState, 128),
- VMSTATE_UINT32_ARRAY(microcode, MilkymistPFPUState, MICROCODE_WORDS),
- VMSTATE_INT32(output_queue_pos, MilkymistPFPUState),
- VMSTATE_UINT32_ARRAY(output_queue, MilkymistPFPUState, MAX_LATENCY),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void milkymist_pfpu_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = milkymist_pfpu_init;
- dc->reset = milkymist_pfpu_reset;
- dc->vmsd = &vmstate_milkymist_pfpu;
-}
-
-static const TypeInfo milkymist_pfpu_info = {
- .name = TYPE_MILKYMIST_PFPU,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(MilkymistPFPUState),
- .class_init = milkymist_pfpu_class_init,
-};
-
-static void milkymist_pfpu_register_types(void)
-{
- type_register_static(&milkymist_pfpu_info);
-}
-
-type_init(milkymist_pfpu_register_types)
diff --git a/qemu/hw/misc/mips_cmgcr.c b/qemu/hw/misc/mips_cmgcr.c
deleted file mode 100644
index 37be23995..000000000
--- a/qemu/hw/misc/mips_cmgcr.c
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved.
- * Authors: Sanjay Lal <sanjayl@kymasys.com>
- *
- * Copyright (C) 2015 Imagination Technologies
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "sysemu/sysemu.h"
-#include "hw/misc/mips_cmgcr.h"
-#include "hw/misc/mips_cpc.h"
-
-static inline bool is_cpc_connected(MIPSGCRState *s)
-{
- return s->cpc_mr != NULL;
-}
-
-static inline void update_cpc_base(MIPSGCRState *gcr, uint64_t val)
-{
- if (is_cpc_connected(gcr)) {
- gcr->cpc_base = val & GCR_CPC_BASE_MSK;
- memory_region_transaction_begin();
- memory_region_set_address(gcr->cpc_mr,
- gcr->cpc_base & GCR_CPC_BASE_CPCBASE_MSK);
- memory_region_set_enabled(gcr->cpc_mr,
- gcr->cpc_base & GCR_CPC_BASE_CPCEN_MSK);
- memory_region_transaction_commit();
- }
-}
-
-/* Read GCR registers */
-static uint64_t gcr_read(void *opaque, hwaddr addr, unsigned size)
-{
- MIPSGCRState *gcr = (MIPSGCRState *) opaque;
-
- switch (addr) {
- /* Global Control Block Register */
- case GCR_CONFIG_OFS:
- /* Set PCORES to 0 */
- return 0;
- case GCR_BASE_OFS:
- return gcr->gcr_base;
- case GCR_REV_OFS:
- return gcr->gcr_rev;
- case GCR_CPC_BASE_OFS:
- return gcr->cpc_base;
- case GCR_CPC_STATUS_OFS:
- return is_cpc_connected(gcr);
- case GCR_L2_CONFIG_OFS:
- /* L2 BYPASS */
- return GCR_L2_CONFIG_BYPASS_MSK;
- /* Core-Local and Core-Other Control Blocks */
- case MIPS_CLCB_OFS + GCR_CL_CONFIG_OFS:
- case MIPS_COCB_OFS + GCR_CL_CONFIG_OFS:
- /* Set PVP to # of VPs - 1 */
- return gcr->num_vps - 1;
- case MIPS_CLCB_OFS + GCR_CL_OTHER_OFS:
- return 0;
- default:
- qemu_log_mask(LOG_UNIMP, "Read %d bytes at GCR offset 0x%" HWADDR_PRIx
- "\n", size, addr);
- return 0;
- }
- return 0;
-}
-
-/* Write GCR registers */
-static void gcr_write(void *opaque, hwaddr addr, uint64_t data, unsigned size)
-{
- MIPSGCRState *gcr = (MIPSGCRState *)opaque;
-
- switch (addr) {
- case GCR_CPC_BASE_OFS:
- update_cpc_base(gcr, data);
- break;
- default:
- qemu_log_mask(LOG_UNIMP, "Write %d bytes at GCR offset 0x%" HWADDR_PRIx
- " 0x%" PRIx64 "\n", size, addr, data);
- break;
- }
-}
-
-static const MemoryRegionOps gcr_ops = {
- .read = gcr_read,
- .write = gcr_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .impl = {
- .max_access_size = 8,
- },
-};
-
-static void mips_gcr_init(Object *obj)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- MIPSGCRState *s = MIPS_GCR(obj);
-
- object_property_add_link(obj, "cpc", TYPE_MEMORY_REGION,
- (Object **)&s->cpc_mr,
- qdev_prop_allow_set_link_before_realize,
- OBJ_PROP_LINK_UNREF_ON_RELEASE,
- &error_abort);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &gcr_ops, s,
- "mips-gcr", GCR_ADDRSPACE_SZ);
- sysbus_init_mmio(sbd, &s->iomem);
-}
-
-static void mips_gcr_reset(DeviceState *dev)
-{
- MIPSGCRState *s = MIPS_GCR(dev);
-
- update_cpc_base(s, 0);
-}
-
-static const VMStateDescription vmstate_mips_gcr = {
- .name = "mips-gcr",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_UINT64(cpc_base, MIPSGCRState),
- VMSTATE_END_OF_LIST()
- },
-};
-
-static Property mips_gcr_properties[] = {
- DEFINE_PROP_INT32("num-vp", MIPSGCRState, num_vps, 1),
- DEFINE_PROP_INT32("gcr-rev", MIPSGCRState, gcr_rev, 0x800),
- DEFINE_PROP_UINT64("gcr-base", MIPSGCRState, gcr_base, GCR_BASE_ADDR),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void mips_gcr_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- dc->props = mips_gcr_properties;
- dc->vmsd = &vmstate_mips_gcr;
- dc->reset = mips_gcr_reset;
-}
-
-static const TypeInfo mips_gcr_info = {
- .name = TYPE_MIPS_GCR,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(MIPSGCRState),
- .instance_init = mips_gcr_init,
- .class_init = mips_gcr_class_init,
-};
-
-static void mips_gcr_register_types(void)
-{
- type_register_static(&mips_gcr_info);
-}
-
-type_init(mips_gcr_register_types)
diff --git a/qemu/hw/misc/mips_cpc.c b/qemu/hw/misc/mips_cpc.c
deleted file mode 100644
index d2b8e42da..000000000
--- a/qemu/hw/misc/mips_cpc.c
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Cluster Power Controller emulation
- *
- * Copyright (c) 2016 Imagination Technologies
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/sysbus.h"
-
-#include "hw/misc/mips_cpc.h"
-
-static inline uint64_t cpc_vp_run_mask(MIPSCPCState *cpc)
-{
- return (1ULL << cpc->num_vp) - 1;
-}
-
-static void cpc_run_vp(MIPSCPCState *cpc, uint64_t vp_run)
-{
- CPUState *cs = first_cpu;
-
- CPU_FOREACH(cs) {
- uint64_t i = 1ULL << cs->cpu_index;
- if (i & vp_run & ~cpc->vp_running) {
- cpu_interrupt(cs, CPU_INTERRUPT_WAKE);
- cpc->vp_running |= i;
- }
- }
-}
-
-static void cpc_stop_vp(MIPSCPCState *cpc, uint64_t vp_stop)
-{
- CPUState *cs = first_cpu;
-
- CPU_FOREACH(cs) {
- uint64_t i = 1ULL << cs->cpu_index;
- if (i & vp_stop & cpc->vp_running) {
- cs->halted = 1;
- cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE);
- cpc->vp_running &= ~i;
- }
- }
-}
-
-static void cpc_write(void *opaque, hwaddr offset, uint64_t data,
- unsigned size)
-{
- MIPSCPCState *s = opaque;
-
- switch (offset) {
- case CPC_CL_BASE_OFS + CPC_VP_RUN_OFS:
- case CPC_CO_BASE_OFS + CPC_VP_RUN_OFS:
- cpc_run_vp(s, data & cpc_vp_run_mask(s));
- break;
- case CPC_CL_BASE_OFS + CPC_VP_STOP_OFS:
- case CPC_CO_BASE_OFS + CPC_VP_STOP_OFS:
- cpc_stop_vp(s, data & cpc_vp_run_mask(s));
- break;
- default:
- qemu_log_mask(LOG_UNIMP,
- "%s: Bad offset 0x%x\n", __func__, (int)offset);
- break;
- }
-
- return;
-}
-
-static uint64_t cpc_read(void *opaque, hwaddr offset, unsigned size)
-{
- MIPSCPCState *s = opaque;
-
- switch (offset) {
- case CPC_CL_BASE_OFS + CPC_VP_RUNNING_OFS:
- case CPC_CO_BASE_OFS + CPC_VP_RUNNING_OFS:
- return s->vp_running;
- default:
- qemu_log_mask(LOG_UNIMP,
- "%s: Bad offset 0x%x\n", __func__, (int)offset);
- return 0;
- }
-}
-
-static const MemoryRegionOps cpc_ops = {
- .read = cpc_read,
- .write = cpc_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .impl = {
- .max_access_size = 8,
- },
-};
-
-static void mips_cpc_init(Object *obj)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- MIPSCPCState *s = MIPS_CPC(obj);
-
- memory_region_init_io(&s->mr, OBJECT(s), &cpc_ops, s, "mips-cpc",
- CPC_ADDRSPACE_SZ);
- sysbus_init_mmio(sbd, &s->mr);
-}
-
-static void mips_cpc_realize(DeviceState *dev, Error **errp)
-{
- MIPSCPCState *s = MIPS_CPC(dev);
-
- if (s->vp_start_running > cpc_vp_run_mask(s)) {
- error_setg(errp,
- "incorrect vp_start_running 0x%" PRIx64 " for num_vp = %d",
- s->vp_running, s->num_vp);
- return;
- }
-}
-
-static void mips_cpc_reset(DeviceState *dev)
-{
- MIPSCPCState *s = MIPS_CPC(dev);
-
- /* Reflect the fact that all VPs are halted on reset */
- s->vp_running = 0;
-
- /* Put selected VPs into run state */
- cpc_run_vp(s, s->vp_start_running);
-}
-
-static const VMStateDescription vmstate_mips_cpc = {
- .name = "mips-cpc",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_UINT64(vp_running, MIPSCPCState),
- VMSTATE_END_OF_LIST()
- },
-};
-
-static Property mips_cpc_properties[] = {
- DEFINE_PROP_UINT32("num-vp", MIPSCPCState, num_vp, 0x1),
- DEFINE_PROP_UINT64("vp-start-running", MIPSCPCState, vp_start_running, 0x1),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void mips_cpc_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = mips_cpc_realize;
- dc->reset = mips_cpc_reset;
- dc->vmsd = &vmstate_mips_cpc;
- dc->props = mips_cpc_properties;
-}
-
-static const TypeInfo mips_cpc_info = {
- .name = TYPE_MIPS_CPC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(MIPSCPCState),
- .instance_init = mips_cpc_init,
- .class_init = mips_cpc_class_init,
-};
-
-static void mips_cpc_register_types(void)
-{
- type_register_static(&mips_cpc_info);
-}
-
-type_init(mips_cpc_register_types)
diff --git a/qemu/hw/misc/mips_itu.c b/qemu/hw/misc/mips_itu.c
deleted file mode 100644
index da5455062..000000000
--- a/qemu/hw/misc/mips_itu.c
+++ /dev/null
@@ -1,521 +0,0 @@
-/*
- * Inter-Thread Communication Unit emulation.
- *
- * Copyright (c) 2016 Imagination Technologies
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "sysemu/sysemu.h"
-#include "hw/misc/mips_itu.h"
-
-#define ITC_TAG_ADDRSPACE_SZ (ITC_ADDRESSMAP_NUM * 8)
-/* Initialize as 4kB area to fit all 32 cells with default 128B grain.
- Storage may be resized by the software. */
-#define ITC_STORAGE_ADDRSPACE_SZ 0x1000
-
-#define ITC_FIFO_NUM_MAX 16
-#define ITC_SEMAPH_NUM_MAX 16
-#define ITC_AM1_NUMENTRIES_OFS 20
-
-#define ITC_CELL_PV_MAX_VAL 0xFFFF
-
-#define ITC_CELL_TAG_FIFO_DEPTH 28
-#define ITC_CELL_TAG_FIFO_PTR 18
-#define ITC_CELL_TAG_FIFO 17
-#define ITC_CELL_TAG_T 16
-#define ITC_CELL_TAG_F 1
-#define ITC_CELL_TAG_E 0
-
-#define ITC_AM0_BASE_ADDRESS_MASK 0xFFFFFC00ULL
-#define ITC_AM0_EN_MASK 0x1
-
-#define ITC_AM1_ADDR_MASK_MASK 0x1FC00
-#define ITC_AM1_ENTRY_GRAIN_MASK 0x7
-
-typedef enum ITCView {
- ITCVIEW_BYPASS = 0,
- ITCVIEW_CONTROL = 1,
- ITCVIEW_EF_SYNC = 2,
- ITCVIEW_EF_TRY = 3,
- ITCVIEW_PV_SYNC = 4,
- ITCVIEW_PV_TRY = 5
-} ITCView;
-
-MemoryRegion *mips_itu_get_tag_region(MIPSITUState *itu)
-{
- return &itu->tag_io;
-}
-
-static uint64_t itc_tag_read(void *opaque, hwaddr addr, unsigned size)
-{
- MIPSITUState *tag = (MIPSITUState *)opaque;
- uint64_t index = addr >> 3;
-
- if (index >= ITC_ADDRESSMAP_NUM) {
- qemu_log_mask(LOG_GUEST_ERROR, "Read 0x%" PRIx64 "\n", addr);
- return 0;
- }
-
- return tag->ITCAddressMap[index];
-}
-
-static void itc_reconfigure(MIPSITUState *tag)
-{
- uint64_t *am = &tag->ITCAddressMap[0];
- MemoryRegion *mr = &tag->storage_io;
- hwaddr address = am[0] & ITC_AM0_BASE_ADDRESS_MASK;
- uint64_t size = (1 << 10) + (am[1] & ITC_AM1_ADDR_MASK_MASK);
- bool is_enabled = (am[0] & ITC_AM0_EN_MASK) != 0;
-
- memory_region_transaction_begin();
- if (!(size & (size - 1))) {
- memory_region_set_size(mr, size);
- }
- memory_region_set_address(mr, address);
- memory_region_set_enabled(mr, is_enabled);
- memory_region_transaction_commit();
-}
-
-static void itc_tag_write(void *opaque, hwaddr addr,
- uint64_t data, unsigned size)
-{
- MIPSITUState *tag = (MIPSITUState *)opaque;
- uint64_t *am = &tag->ITCAddressMap[0];
- uint64_t am_old, mask;
- uint64_t index = addr >> 3;
-
- switch (index) {
- case 0:
- mask = ITC_AM0_BASE_ADDRESS_MASK | ITC_AM0_EN_MASK;
- break;
- case 1:
- mask = ITC_AM1_ADDR_MASK_MASK | ITC_AM1_ENTRY_GRAIN_MASK;
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "Bad write 0x%" PRIx64 "\n", addr);
- return;
- }
-
- am_old = am[index];
- am[index] = (data & mask) | (am_old & ~mask);
- if (am_old != am[index]) {
- itc_reconfigure(tag);
- }
-}
-
-static const MemoryRegionOps itc_tag_ops = {
- .read = itc_tag_read,
- .write = itc_tag_write,
- .impl = {
- .max_access_size = 8,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static inline uint32_t get_num_cells(MIPSITUState *s)
-{
- return s->num_fifo + s->num_semaphores;
-}
-
-static inline ITCView get_itc_view(hwaddr addr)
-{
- return (addr >> 3) & 0xf;
-}
-
-static inline int get_cell_stride_shift(const MIPSITUState *s)
-{
- /* Minimum interval (for EntryGain = 0) is 128 B */
- return 7 + (s->ITCAddressMap[1] & ITC_AM1_ENTRY_GRAIN_MASK);
-}
-
-static inline ITCStorageCell *get_cell(MIPSITUState *s,
- hwaddr addr)
-{
- uint32_t cell_idx = addr >> get_cell_stride_shift(s);
- uint32_t num_cells = get_num_cells(s);
-
- if (cell_idx >= num_cells) {
- cell_idx = num_cells - 1;
- }
-
- return &s->cell[cell_idx];
-}
-
-static void wake_blocked_threads(ITCStorageCell *c)
-{
- CPUState *cs;
- CPU_FOREACH(cs) {
- if (cs->halted && (c->blocked_threads & (1ULL << cs->cpu_index))) {
- cpu_interrupt(cs, CPU_INTERRUPT_WAKE);
- }
- }
- c->blocked_threads = 0;
-}
-
-static void QEMU_NORETURN block_thread_and_exit(ITCStorageCell *c)
-{
- c->blocked_threads |= 1ULL << current_cpu->cpu_index;
- cpu_restore_state(current_cpu, current_cpu->mem_io_pc);
- current_cpu->halted = 1;
- current_cpu->exception_index = EXCP_HLT;
- cpu_loop_exit(current_cpu);
-}
-
-/* ITC Bypass View */
-
-static inline uint64_t view_bypass_read(ITCStorageCell *c)
-{
- if (c->tag.FIFO) {
- return c->data[c->fifo_out];
- } else {
- return c->data[0];
- }
-}
-
-static inline void view_bypass_write(ITCStorageCell *c, uint64_t val)
-{
- if (c->tag.FIFO && (c->tag.FIFOPtr > 0)) {
- int idx = (c->fifo_out + c->tag.FIFOPtr - 1) % ITC_CELL_DEPTH;
- c->data[idx] = val;
- }
-
- /* ignore a write to the semaphore cell */
-}
-
-/* ITC Control View */
-
-static inline uint64_t view_control_read(ITCStorageCell *c)
-{
- return ((uint64_t)c->tag.FIFODepth << ITC_CELL_TAG_FIFO_DEPTH) |
- (c->tag.FIFOPtr << ITC_CELL_TAG_FIFO_PTR) |
- (c->tag.FIFO << ITC_CELL_TAG_FIFO) |
- (c->tag.T << ITC_CELL_TAG_T) |
- (c->tag.E << ITC_CELL_TAG_E) |
- (c->tag.F << ITC_CELL_TAG_F);
-}
-
-static inline void view_control_write(ITCStorageCell *c, uint64_t val)
-{
- c->tag.T = (val >> ITC_CELL_TAG_T) & 1;
- c->tag.E = (val >> ITC_CELL_TAG_E) & 1;
- c->tag.F = (val >> ITC_CELL_TAG_F) & 1;
-
- if (c->tag.E) {
- c->tag.FIFOPtr = 0;
- }
-}
-
-/* ITC Empty/Full View */
-
-static uint64_t view_ef_common_read(ITCStorageCell *c, bool blocking)
-{
- uint64_t ret = 0;
-
- if (!c->tag.FIFO) {
- return 0;
- }
-
- c->tag.F = 0;
-
- if (blocking && c->tag.E) {
- block_thread_and_exit(c);
- }
-
- if (c->blocked_threads) {
- wake_blocked_threads(c);
- }
-
- if (c->tag.FIFOPtr > 0) {
- ret = c->data[c->fifo_out];
- c->fifo_out = (c->fifo_out + 1) % ITC_CELL_DEPTH;
- c->tag.FIFOPtr--;
- }
-
- if (c->tag.FIFOPtr == 0) {
- c->tag.E = 1;
- }
-
- return ret;
-}
-
-static uint64_t view_ef_sync_read(ITCStorageCell *c)
-{
- return view_ef_common_read(c, true);
-}
-
-static uint64_t view_ef_try_read(ITCStorageCell *c)
-{
- return view_ef_common_read(c, false);
-}
-
-static inline void view_ef_common_write(ITCStorageCell *c, uint64_t val,
- bool blocking)
-{
- if (!c->tag.FIFO) {
- return;
- }
-
- c->tag.E = 0;
-
- if (blocking && c->tag.F) {
- block_thread_and_exit(c);
- }
-
- if (c->blocked_threads) {
- wake_blocked_threads(c);
- }
-
- if (c->tag.FIFOPtr < ITC_CELL_DEPTH) {
- int idx = (c->fifo_out + c->tag.FIFOPtr) % ITC_CELL_DEPTH;
- c->data[idx] = val;
- c->tag.FIFOPtr++;
- }
-
- if (c->tag.FIFOPtr == ITC_CELL_DEPTH) {
- c->tag.F = 1;
- }
-}
-
-static void view_ef_sync_write(ITCStorageCell *c, uint64_t val)
-{
- view_ef_common_write(c, val, true);
-}
-
-static void view_ef_try_write(ITCStorageCell *c, uint64_t val)
-{
- view_ef_common_write(c, val, false);
-}
-
-/* ITC P/V View */
-
-static uint64_t view_pv_common_read(ITCStorageCell *c, bool blocking)
-{
- uint64_t ret = c->data[0];
-
- if (c->tag.FIFO) {
- return 0;
- }
-
- if (c->data[0] > 0) {
- c->data[0]--;
- } else if (blocking) {
- block_thread_and_exit(c);
- }
-
- return ret;
-}
-
-static uint64_t view_pv_sync_read(ITCStorageCell *c)
-{
- return view_pv_common_read(c, true);
-}
-
-static uint64_t view_pv_try_read(ITCStorageCell *c)
-{
- return view_pv_common_read(c, false);
-}
-
-static inline void view_pv_common_write(ITCStorageCell *c)
-{
- if (c->tag.FIFO) {
- return;
- }
-
- if (c->data[0] < ITC_CELL_PV_MAX_VAL) {
- c->data[0]++;
- }
-
- if (c->blocked_threads) {
- wake_blocked_threads(c);
- }
-}
-
-static void view_pv_sync_write(ITCStorageCell *c)
-{
- view_pv_common_write(c);
-}
-
-static void view_pv_try_write(ITCStorageCell *c)
-{
- view_pv_common_write(c);
-}
-
-static uint64_t itc_storage_read(void *opaque, hwaddr addr, unsigned size)
-{
- MIPSITUState *s = (MIPSITUState *)opaque;
- ITCStorageCell *cell = get_cell(s, addr);
- ITCView view = get_itc_view(addr);
- uint64_t ret = -1;
-
- switch (view) {
- case ITCVIEW_BYPASS:
- ret = view_bypass_read(cell);
- break;
- case ITCVIEW_CONTROL:
- ret = view_control_read(cell);
- break;
- case ITCVIEW_EF_SYNC:
- ret = view_ef_sync_read(cell);
- break;
- case ITCVIEW_EF_TRY:
- ret = view_ef_try_read(cell);
- break;
- case ITCVIEW_PV_SYNC:
- ret = view_pv_sync_read(cell);
- break;
- case ITCVIEW_PV_TRY:
- ret = view_pv_try_read(cell);
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "itc_storage_read: Bad ITC View %d\n", (int)view);
- break;
- }
-
- return ret;
-}
-
-static void itc_storage_write(void *opaque, hwaddr addr, uint64_t data,
- unsigned size)
-{
- MIPSITUState *s = (MIPSITUState *)opaque;
- ITCStorageCell *cell = get_cell(s, addr);
- ITCView view = get_itc_view(addr);
-
- switch (view) {
- case ITCVIEW_BYPASS:
- view_bypass_write(cell, data);
- break;
- case ITCVIEW_CONTROL:
- view_control_write(cell, data);
- break;
- case ITCVIEW_EF_SYNC:
- view_ef_sync_write(cell, data);
- break;
- case ITCVIEW_EF_TRY:
- view_ef_try_write(cell, data);
- break;
- case ITCVIEW_PV_SYNC:
- view_pv_sync_write(cell);
- break;
- case ITCVIEW_PV_TRY:
- view_pv_try_write(cell);
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "itc_storage_write: Bad ITC View %d\n", (int)view);
- break;
- }
-
-}
-
-static const MemoryRegionOps itc_storage_ops = {
- .read = itc_storage_read,
- .write = itc_storage_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void itc_reset_cells(MIPSITUState *s)
-{
- int i;
-
- memset(s->cell, 0, get_num_cells(s) * sizeof(s->cell[0]));
-
- for (i = 0; i < s->num_fifo; i++) {
- s->cell[i].tag.E = 1;
- s->cell[i].tag.FIFO = 1;
- s->cell[i].tag.FIFODepth = ITC_CELL_DEPTH_SHIFT;
- }
-}
-
-static void mips_itu_init(Object *obj)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- MIPSITUState *s = MIPS_ITU(obj);
-
- memory_region_init_io(&s->storage_io, OBJECT(s), &itc_storage_ops, s,
- "mips-itc-storage", ITC_STORAGE_ADDRSPACE_SZ);
- sysbus_init_mmio(sbd, &s->storage_io);
-
- memory_region_init_io(&s->tag_io, OBJECT(s), &itc_tag_ops, s,
- "mips-itc-tag", ITC_TAG_ADDRSPACE_SZ);
-}
-
-static void mips_itu_realize(DeviceState *dev, Error **errp)
-{
- MIPSITUState *s = MIPS_ITU(dev);
-
- if (s->num_fifo > ITC_FIFO_NUM_MAX) {
- error_setg(errp, "Exceed maximum number of FIFO cells: %d",
- s->num_fifo);
- return;
- }
- if (s->num_semaphores > ITC_SEMAPH_NUM_MAX) {
- error_setg(errp, "Exceed maximum number of Semaphore cells: %d",
- s->num_semaphores);
- return;
- }
-
- s->cell = g_new(ITCStorageCell, get_num_cells(s));
-}
-
-static void mips_itu_reset(DeviceState *dev)
-{
- MIPSITUState *s = MIPS_ITU(dev);
-
- s->ITCAddressMap[0] = 0;
- s->ITCAddressMap[1] =
- ((ITC_STORAGE_ADDRSPACE_SZ - 1) & ITC_AM1_ADDR_MASK_MASK) |
- (get_num_cells(s) << ITC_AM1_NUMENTRIES_OFS);
- itc_reconfigure(s);
-
- itc_reset_cells(s);
-}
-
-static Property mips_itu_properties[] = {
- DEFINE_PROP_INT32("num-fifo", MIPSITUState, num_fifo,
- ITC_FIFO_NUM_MAX),
- DEFINE_PROP_INT32("num-semaphores", MIPSITUState, num_semaphores,
- ITC_SEMAPH_NUM_MAX),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void mips_itu_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->props = mips_itu_properties;
- dc->realize = mips_itu_realize;
- dc->reset = mips_itu_reset;
-}
-
-static const TypeInfo mips_itu_info = {
- .name = TYPE_MIPS_ITU,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(MIPSITUState),
- .instance_init = mips_itu_init,
- .class_init = mips_itu_class_init,
-};
-
-static void mips_itu_register_types(void)
-{
- type_register_static(&mips_itu_info);
-}
-
-type_init(mips_itu_register_types)
diff --git a/qemu/hw/misc/mst_fpga.c b/qemu/hw/misc/mst_fpga.c
deleted file mode 100644
index 48d7dfb2d..000000000
--- a/qemu/hw/misc/mst_fpga.c
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * PXA270-based Intel Mainstone platforms.
- * FPGA driver
- *
- * Copyright (c) 2007 by Armin Kuster <akuster@kama-aina.net> or
- * <akuster@mvista.com>
- *
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-
-/* Mainstone FPGA for extern irqs */
-#define FPGA_GPIO_PIN 0
-#define MST_NUM_IRQS 16
-#define MST_LEDDAT1 0x10
-#define MST_LEDDAT2 0x14
-#define MST_LEDCTRL 0x40
-#define MST_GPSWR 0x60
-#define MST_MSCWR1 0x80
-#define MST_MSCWR2 0x84
-#define MST_MSCWR3 0x88
-#define MST_MSCRD 0x90
-#define MST_INTMSKENA 0xc0
-#define MST_INTSETCLR 0xd0
-#define MST_PCMCIA0 0xe0
-#define MST_PCMCIA1 0xe4
-
-#define MST_PCMCIAx_READY (1 << 10)
-#define MST_PCMCIAx_nCD (1 << 5)
-
-#define MST_PCMCIA_CD0_IRQ 9
-#define MST_PCMCIA_CD1_IRQ 13
-
-#define TYPE_MAINSTONE_FPGA "mainstone-fpga"
-#define MAINSTONE_FPGA(obj) \
- OBJECT_CHECK(mst_irq_state, (obj), TYPE_MAINSTONE_FPGA)
-
-typedef struct mst_irq_state{
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
-
- qemu_irq parent;
-
- uint32_t prev_level;
- uint32_t leddat1;
- uint32_t leddat2;
- uint32_t ledctrl;
- uint32_t gpswr;
- uint32_t mscwr1;
- uint32_t mscwr2;
- uint32_t mscwr3;
- uint32_t mscrd;
- uint32_t intmskena;
- uint32_t intsetclr;
- uint32_t pcmcia0;
- uint32_t pcmcia1;
-}mst_irq_state;
-
-static void
-mst_fpga_set_irq(void *opaque, int irq, int level)
-{
- mst_irq_state *s = (mst_irq_state *)opaque;
- uint32_t oldint = s->intsetclr & s->intmskena;
-
- if (level)
- s->prev_level |= 1u << irq;
- else
- s->prev_level &= ~(1u << irq);
-
- switch(irq) {
- case MST_PCMCIA_CD0_IRQ:
- if (level)
- s->pcmcia0 &= ~MST_PCMCIAx_nCD;
- else
- s->pcmcia0 |= MST_PCMCIAx_nCD;
- break;
- case MST_PCMCIA_CD1_IRQ:
- if (level)
- s->pcmcia1 &= ~MST_PCMCIAx_nCD;
- else
- s->pcmcia1 |= MST_PCMCIAx_nCD;
- break;
- }
-
- if ((s->intmskena & (1u << irq)) && level)
- s->intsetclr |= 1u << irq;
-
- if (oldint != (s->intsetclr & s->intmskena))
- qemu_set_irq(s->parent, s->intsetclr & s->intmskena);
-}
-
-
-static uint64_t
-mst_fpga_readb(void *opaque, hwaddr addr, unsigned size)
-{
- mst_irq_state *s = (mst_irq_state *) opaque;
-
- switch (addr) {
- case MST_LEDDAT1:
- return s->leddat1;
- case MST_LEDDAT2:
- return s->leddat2;
- case MST_LEDCTRL:
- return s->ledctrl;
- case MST_GPSWR:
- return s->gpswr;
- case MST_MSCWR1:
- return s->mscwr1;
- case MST_MSCWR2:
- return s->mscwr2;
- case MST_MSCWR3:
- return s->mscwr3;
- case MST_MSCRD:
- return s->mscrd;
- case MST_INTMSKENA:
- return s->intmskena;
- case MST_INTSETCLR:
- return s->intsetclr;
- case MST_PCMCIA0:
- return s->pcmcia0;
- case MST_PCMCIA1:
- return s->pcmcia1;
- default:
- printf("Mainstone - mst_fpga_readb: Bad register offset "
- "0x" TARGET_FMT_plx "\n", addr);
- }
- return 0;
-}
-
-static void
-mst_fpga_writeb(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
- mst_irq_state *s = (mst_irq_state *) opaque;
- value &= 0xffffffff;
-
- switch (addr) {
- case MST_LEDDAT1:
- s->leddat1 = value;
- break;
- case MST_LEDDAT2:
- s->leddat2 = value;
- break;
- case MST_LEDCTRL:
- s->ledctrl = value;
- break;
- case MST_GPSWR:
- s->gpswr = value;
- break;
- case MST_MSCWR1:
- s->mscwr1 = value;
- break;
- case MST_MSCWR2:
- s->mscwr2 = value;
- break;
- case MST_MSCWR3:
- s->mscwr3 = value;
- break;
- case MST_MSCRD:
- s->mscrd = value;
- break;
- case MST_INTMSKENA: /* Mask interrupt */
- s->intmskena = (value & 0xFEEFF);
- qemu_set_irq(s->parent, s->intsetclr & s->intmskena);
- break;
- case MST_INTSETCLR: /* clear or set interrupt */
- s->intsetclr = (value & 0xFEEFF);
- qemu_set_irq(s->parent, s->intsetclr & s->intmskena);
- break;
- /* For PCMCIAx allow the to change only power and reset */
- case MST_PCMCIA0:
- s->pcmcia0 = (value & 0x1f) | (s->pcmcia0 & ~0x1f);
- break;
- case MST_PCMCIA1:
- s->pcmcia1 = (value & 0x1f) | (s->pcmcia1 & ~0x1f);
- break;
- default:
- printf("Mainstone - mst_fpga_writeb: Bad register offset "
- "0x" TARGET_FMT_plx "\n", addr);
- }
-}
-
-static const MemoryRegionOps mst_fpga_ops = {
- .read = mst_fpga_readb,
- .write = mst_fpga_writeb,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int mst_fpga_post_load(void *opaque, int version_id)
-{
- mst_irq_state *s = (mst_irq_state *) opaque;
-
- qemu_set_irq(s->parent, s->intsetclr & s->intmskena);
- return 0;
-}
-
-static int mst_fpga_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- mst_irq_state *s = MAINSTONE_FPGA(dev);
-
- s->pcmcia0 = MST_PCMCIAx_READY | MST_PCMCIAx_nCD;
- s->pcmcia1 = MST_PCMCIAx_READY | MST_PCMCIAx_nCD;
-
- sysbus_init_irq(sbd, &s->parent);
-
- /* alloc the external 16 irqs */
- qdev_init_gpio_in(dev, mst_fpga_set_irq, MST_NUM_IRQS);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &mst_fpga_ops, s,
- "fpga", 0x00100000);
- sysbus_init_mmio(sbd, &s->iomem);
- return 0;
-}
-
-static VMStateDescription vmstate_mst_fpga_regs = {
- .name = "mainstone_fpga",
- .version_id = 0,
- .minimum_version_id = 0,
- .post_load = mst_fpga_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(prev_level, mst_irq_state),
- VMSTATE_UINT32(leddat1, mst_irq_state),
- VMSTATE_UINT32(leddat2, mst_irq_state),
- VMSTATE_UINT32(ledctrl, mst_irq_state),
- VMSTATE_UINT32(gpswr, mst_irq_state),
- VMSTATE_UINT32(mscwr1, mst_irq_state),
- VMSTATE_UINT32(mscwr2, mst_irq_state),
- VMSTATE_UINT32(mscwr3, mst_irq_state),
- VMSTATE_UINT32(mscrd, mst_irq_state),
- VMSTATE_UINT32(intmskena, mst_irq_state),
- VMSTATE_UINT32(intsetclr, mst_irq_state),
- VMSTATE_UINT32(pcmcia0, mst_irq_state),
- VMSTATE_UINT32(pcmcia1, mst_irq_state),
- VMSTATE_END_OF_LIST(),
- },
-};
-
-static void mst_fpga_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = mst_fpga_init;
- dc->desc = "Mainstone II FPGA";
- dc->vmsd = &vmstate_mst_fpga_regs;
-}
-
-static const TypeInfo mst_fpga_info = {
- .name = TYPE_MAINSTONE_FPGA,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(mst_irq_state),
- .class_init = mst_fpga_class_init,
-};
-
-static void mst_fpga_register_types(void)
-{
- type_register_static(&mst_fpga_info);
-}
-
-type_init(mst_fpga_register_types)
diff --git a/qemu/hw/misc/omap_clk.c b/qemu/hw/misc/omap_clk.c
deleted file mode 100644
index 19151d07d..000000000
--- a/qemu/hw/misc/omap_clk.c
+++ /dev/null
@@ -1,1265 +0,0 @@
-/*
- * OMAP clocks.
- *
- * Copyright (C) 2006-2008 Andrzej Zaborowski <balrog@zabor.org>
- *
- * Clocks data comes in part from arch/arm/mach-omap1/clock.h in Linux.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/arm/omap.h"
-
-struct clk {
- const char *name;
- const char *alias;
- struct clk *parent;
- struct clk *child1;
- struct clk *sibling;
-#define ALWAYS_ENABLED (1 << 0)
-#define CLOCK_IN_OMAP310 (1 << 10)
-#define CLOCK_IN_OMAP730 (1 << 11)
-#define CLOCK_IN_OMAP1510 (1 << 12)
-#define CLOCK_IN_OMAP16XX (1 << 13)
-#define CLOCK_IN_OMAP242X (1 << 14)
-#define CLOCK_IN_OMAP243X (1 << 15)
-#define CLOCK_IN_OMAP343X (1 << 16)
- uint32_t flags;
- int id;
-
- int running; /* Is currently ticking */
- int enabled; /* Is enabled, regardless of its input clk */
- unsigned long rate; /* Current rate (if .running) */
- unsigned int divisor; /* Rate relative to input (if .enabled) */
- unsigned int multiplier; /* Rate relative to input (if .enabled) */
- qemu_irq users[16]; /* Who to notify on change */
- int usecount; /* Automatically idle when unused */
-};
-
-static struct clk xtal_osc12m = {
- .name = "xtal_osc_12m",
- .rate = 12000000,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
-};
-
-static struct clk xtal_osc32k = {
- .name = "xtal_osc_32k",
- .rate = 32768,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
- CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-};
-
-static struct clk ck_ref = {
- .name = "ck_ref",
- .alias = "clkin",
- .parent = &xtal_osc12m,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
- ALWAYS_ENABLED,
-};
-
-/* If a dpll is disabled it becomes a bypass, child clocks don't stop */
-static struct clk dpll1 = {
- .name = "dpll1",
- .parent = &ck_ref,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
- ALWAYS_ENABLED,
-};
-
-static struct clk dpll2 = {
- .name = "dpll2",
- .parent = &ck_ref,
- .flags = CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
-};
-
-static struct clk dpll3 = {
- .name = "dpll3",
- .parent = &ck_ref,
- .flags = CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
-};
-
-static struct clk dpll4 = {
- .name = "dpll4",
- .parent = &ck_ref,
- .multiplier = 4,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
-};
-
-static struct clk apll = {
- .name = "apll",
- .parent = &ck_ref,
- .multiplier = 48,
- .divisor = 12,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
-};
-
-static struct clk ck_48m = {
- .name = "ck_48m",
- .parent = &dpll4, /* either dpll4 or apll */
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
-};
-
-static struct clk ck_dpll1out = {
- .name = "ck_dpll1out",
- .parent = &dpll1,
- .flags = CLOCK_IN_OMAP16XX,
-};
-
-static struct clk sossi_ck = {
- .name = "ck_sossi",
- .parent = &ck_dpll1out,
- .flags = CLOCK_IN_OMAP16XX,
-};
-
-static struct clk clkm1 = {
- .name = "clkm1",
- .alias = "ck_gen1",
- .parent = &dpll1,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
- ALWAYS_ENABLED,
-};
-
-static struct clk clkm2 = {
- .name = "clkm2",
- .alias = "ck_gen2",
- .parent = &dpll1,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
- ALWAYS_ENABLED,
-};
-
-static struct clk clkm3 = {
- .name = "clkm3",
- .alias = "ck_gen3",
- .parent = &dpll1, /* either dpll1 or ck_ref */
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
- ALWAYS_ENABLED,
-};
-
-static struct clk arm_ck = {
- .name = "arm_ck",
- .alias = "mpu_ck",
- .parent = &clkm1,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
- ALWAYS_ENABLED,
-};
-
-static struct clk armper_ck = {
- .name = "armper_ck",
- .alias = "mpuper_ck",
- .parent = &clkm1,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
-};
-
-static struct clk arm_gpio_ck = {
- .name = "arm_gpio_ck",
- .alias = "mpu_gpio_ck",
- .parent = &clkm1,
- .divisor = 1,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
-};
-
-static struct clk armxor_ck = {
- .name = "armxor_ck",
- .alias = "mpuxor_ck",
- .parent = &ck_ref,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
-};
-
-static struct clk armtim_ck = {
- .name = "armtim_ck",
- .alias = "mputim_ck",
- .parent = &ck_ref, /* either CLKIN or DPLL1 */
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
-};
-
-static struct clk armwdt_ck = {
- .name = "armwdt_ck",
- .alias = "mpuwd_ck",
- .parent = &clkm1,
- .divisor = 14,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
- ALWAYS_ENABLED,
-};
-
-static struct clk arminth_ck16xx = {
- .name = "arminth_ck",
- .parent = &arm_ck,
- .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
- /* Note: On 16xx the frequency can be divided by 2 by programming
- * ARM_CKCTL:ARM_INTHCK_SEL(14) to 1
- *
- * 1510 version is in TC clocks.
- */
-};
-
-static struct clk dsp_ck = {
- .name = "dsp_ck",
- .parent = &clkm2,
- .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
-};
-
-static struct clk dspmmu_ck = {
- .name = "dspmmu_ck",
- .parent = &clkm2,
- .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- ALWAYS_ENABLED,
-};
-
-static struct clk dspper_ck = {
- .name = "dspper_ck",
- .parent = &clkm2,
- .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
-};
-
-static struct clk dspxor_ck = {
- .name = "dspxor_ck",
- .parent = &ck_ref,
- .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
-};
-
-static struct clk dsptim_ck = {
- .name = "dsptim_ck",
- .parent = &ck_ref,
- .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
-};
-
-static struct clk tc_ck = {
- .name = "tc_ck",
- .parent = &clkm3,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- CLOCK_IN_OMAP730 | CLOCK_IN_OMAP310 |
- ALWAYS_ENABLED,
-};
-
-static struct clk arminth_ck15xx = {
- .name = "arminth_ck",
- .parent = &tc_ck,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
- /* Note: On 1510 the frequency follows TC_CK
- *
- * 16xx version is in MPU clocks.
- */
-};
-
-static struct clk tipb_ck = {
- /* No-idle controlled by "tc_ck" */
- .name = "tipb_ck",
- .parent = &tc_ck,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
-};
-
-static struct clk l3_ocpi_ck = {
- /* No-idle controlled by "tc_ck" */
- .name = "l3_ocpi_ck",
- .parent = &tc_ck,
- .flags = CLOCK_IN_OMAP16XX,
-};
-
-static struct clk tc1_ck = {
- .name = "tc1_ck",
- .parent = &tc_ck,
- .flags = CLOCK_IN_OMAP16XX,
-};
-
-static struct clk tc2_ck = {
- .name = "tc2_ck",
- .parent = &tc_ck,
- .flags = CLOCK_IN_OMAP16XX,
-};
-
-static struct clk dma_ck = {
- /* No-idle controlled by "tc_ck" */
- .name = "dma_ck",
- .parent = &tc_ck,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
- ALWAYS_ENABLED,
-};
-
-static struct clk dma_lcdfree_ck = {
- .name = "dma_lcdfree_ck",
- .parent = &tc_ck,
- .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
-};
-
-static struct clk api_ck = {
- .name = "api_ck",
- .alias = "mpui_ck",
- .parent = &tc_ck,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
-};
-
-static struct clk lb_ck = {
- .name = "lb_ck",
- .parent = &tc_ck,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
-};
-
-static struct clk lbfree_ck = {
- .name = "lbfree_ck",
- .parent = &tc_ck,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
-};
-
-static struct clk hsab_ck = {
- .name = "hsab_ck",
- .parent = &tc_ck,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
-};
-
-static struct clk rhea1_ck = {
- .name = "rhea1_ck",
- .parent = &tc_ck,
- .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
-};
-
-static struct clk rhea2_ck = {
- .name = "rhea2_ck",
- .parent = &tc_ck,
- .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
-};
-
-static struct clk lcd_ck_16xx = {
- .name = "lcd_ck",
- .parent = &clkm3,
- .flags = CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP730,
-};
-
-static struct clk lcd_ck_1510 = {
- .name = "lcd_ck",
- .parent = &clkm3,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
-};
-
-static struct clk uart1_1510 = {
- .name = "uart1_ck",
- /* Direct from ULPD, no real parent */
- .parent = &armper_ck, /* either armper_ck or dpll4 */
- .rate = 12000000,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
-};
-
-static struct clk uart1_16xx = {
- .name = "uart1_ck",
- /* Direct from ULPD, no real parent */
- .parent = &armper_ck,
- .rate = 48000000,
- .flags = CLOCK_IN_OMAP16XX,
-};
-
-static struct clk uart2_ck = {
- .name = "uart2_ck",
- /* Direct from ULPD, no real parent */
- .parent = &armper_ck, /* either armper_ck or dpll4 */
- .rate = 12000000,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
- ALWAYS_ENABLED,
-};
-
-static struct clk uart3_1510 = {
- .name = "uart3_ck",
- /* Direct from ULPD, no real parent */
- .parent = &armper_ck, /* either armper_ck or dpll4 */
- .rate = 12000000,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
-};
-
-static struct clk uart3_16xx = {
- .name = "uart3_ck",
- /* Direct from ULPD, no real parent */
- .parent = &armper_ck,
- .rate = 48000000,
- .flags = CLOCK_IN_OMAP16XX,
-};
-
-static struct clk usb_clk0 = { /* 6 MHz output on W4_USB_CLK0 */
- .name = "usb_clk0",
- .alias = "usb.clko",
- /* Direct from ULPD, no parent */
- .rate = 6000000,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
-};
-
-static struct clk usb_hhc_ck1510 = {
- .name = "usb_hhc_ck",
- /* Direct from ULPD, no parent */
- .rate = 48000000, /* Actually 2 clocks, 12MHz and 48MHz */
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
-};
-
-static struct clk usb_hhc_ck16xx = {
- .name = "usb_hhc_ck",
- /* Direct from ULPD, no parent */
- .rate = 48000000,
- /* OTG_SYSCON_2.OTG_PADEN == 0 (not 1510-compatible) */
- .flags = CLOCK_IN_OMAP16XX,
-};
-
-static struct clk usb_w2fc_mclk = {
- .name = "usb_w2fc_mclk",
- .alias = "usb_w2fc_ck",
- .parent = &ck_48m,
- .rate = 48000000,
- .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
-};
-
-static struct clk mclk_1510 = {
- .name = "mclk",
- /* Direct from ULPD, no parent. May be enabled by ext hardware. */
- .rate = 12000000,
- .flags = CLOCK_IN_OMAP1510,
-};
-
-static struct clk bclk_310 = {
- .name = "bt_mclk_out", /* Alias midi_mclk_out? */
- .parent = &armper_ck,
- .flags = CLOCK_IN_OMAP310,
-};
-
-static struct clk mclk_310 = {
- .name = "com_mclk_out",
- .parent = &armper_ck,
- .flags = CLOCK_IN_OMAP310,
-};
-
-static struct clk mclk_16xx = {
- .name = "mclk",
- /* Direct from ULPD, no parent. May be enabled by ext hardware. */
- .flags = CLOCK_IN_OMAP16XX,
-};
-
-static struct clk bclk_1510 = {
- .name = "bclk",
- /* Direct from ULPD, no parent. May be enabled by ext hardware. */
- .rate = 12000000,
- .flags = CLOCK_IN_OMAP1510,
-};
-
-static struct clk bclk_16xx = {
- .name = "bclk",
- /* Direct from ULPD, no parent. May be enabled by ext hardware. */
- .flags = CLOCK_IN_OMAP16XX,
-};
-
-static struct clk mmc1_ck = {
- .name = "mmc_ck",
- .id = 1,
- /* Functional clock is direct from ULPD, interface clock is ARMPER */
- .parent = &armper_ck, /* either armper_ck or dpll4 */
- .rate = 48000000,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
-};
-
-static struct clk mmc2_ck = {
- .name = "mmc_ck",
- .id = 2,
- /* Functional clock is direct from ULPD, interface clock is ARMPER */
- .parent = &armper_ck,
- .rate = 48000000,
- .flags = CLOCK_IN_OMAP16XX,
-};
-
-static struct clk cam_mclk = {
- .name = "cam.mclk",
- .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
- .rate = 12000000,
-};
-
-static struct clk cam_exclk = {
- .name = "cam.exclk",
- .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
- /* Either 12M from cam.mclk or 48M from dpll4 */
- .parent = &cam_mclk,
-};
-
-static struct clk cam_lclk = {
- .name = "cam.lclk",
- .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
-};
-
-static struct clk i2c_fck = {
- .name = "i2c_fck",
- .id = 1,
- .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- ALWAYS_ENABLED,
- .parent = &armxor_ck,
-};
-
-static struct clk i2c_ick = {
- .name = "i2c_ick",
- .id = 1,
- .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
- .parent = &armper_ck,
-};
-
-static struct clk clk32k = {
- .name = "clk32-kHz",
- .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
- .parent = &xtal_osc32k,
-};
-
-static struct clk ref_clk = {
- .name = "ref_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
- .rate = 12000000, /* 12 MHz or 13 MHz or 19.2 MHz */
- /*.parent = sys.xtalin */
-};
-
-static struct clk apll_96m = {
- .name = "apll_96m",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
- .rate = 96000000,
- /*.parent = ref_clk */
-};
-
-static struct clk apll_54m = {
- .name = "apll_54m",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
- .rate = 54000000,
- /*.parent = ref_clk */
-};
-
-static struct clk sys_clk = {
- .name = "sys_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
- .rate = 32768,
- /*.parent = sys.xtalin */
-};
-
-static struct clk sleep_clk = {
- .name = "sleep_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
- .rate = 32768,
- /*.parent = sys.xtalin */
-};
-
-static struct clk dpll_ck = {
- .name = "dpll",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
- .parent = &ref_clk,
-};
-
-static struct clk dpll_x2_ck = {
- .name = "dpll_x2",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
- .parent = &ref_clk,
-};
-
-static struct clk wdt1_sys_clk = {
- .name = "wdt1_sys_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
- .rate = 32768,
- /*.parent = sys.xtalin */
-};
-
-static struct clk func_96m_clk = {
- .name = "func_96m_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .divisor = 1,
- .parent = &apll_96m,
-};
-
-static struct clk func_48m_clk = {
- .name = "func_48m_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .divisor = 2,
- .parent = &apll_96m,
-};
-
-static struct clk func_12m_clk = {
- .name = "func_12m_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .divisor = 8,
- .parent = &apll_96m,
-};
-
-static struct clk func_54m_clk = {
- .name = "func_54m_clk",
- .flags = CLOCK_IN_OMAP242X,
- .divisor = 1,
- .parent = &apll_54m,
-};
-
-static struct clk sys_clkout = {
- .name = "clkout",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk sys_clkout2 = {
- .name = "clkout2",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk core_clk = {
- .name = "core_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &dpll_x2_ck, /* Switchable between dpll_ck and clk32k */
-};
-
-static struct clk l3_clk = {
- .name = "l3_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_clk,
-};
-
-static struct clk core_l4_iclk = {
- .name = "core_l4_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &l3_clk,
-};
-
-static struct clk wu_l4_iclk = {
- .name = "wu_l4_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &l3_clk,
-};
-
-static struct clk core_l3_iclk = {
- .name = "core_l3_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_clk,
-};
-
-static struct clk core_l4_usb_clk = {
- .name = "core_l4_usb_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &l3_clk,
-};
-
-static struct clk wu_gpt1_clk = {
- .name = "wu_gpt1_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk wu_32k_clk = {
- .name = "wu_32k_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk uart1_fclk = {
- .name = "uart1_fclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &func_48m_clk,
-};
-
-static struct clk uart1_iclk = {
- .name = "uart1_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_l4_iclk,
-};
-
-static struct clk uart2_fclk = {
- .name = "uart2_fclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &func_48m_clk,
-};
-
-static struct clk uart2_iclk = {
- .name = "uart2_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_l4_iclk,
-};
-
-static struct clk uart3_fclk = {
- .name = "uart3_fclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &func_48m_clk,
-};
-
-static struct clk uart3_iclk = {
- .name = "uart3_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_l4_iclk,
-};
-
-static struct clk mpu_fclk = {
- .name = "mpu_fclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_clk,
-};
-
-static struct clk mpu_iclk = {
- .name = "mpu_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_clk,
-};
-
-static struct clk int_m_fclk = {
- .name = "int_m_fclk",
- .alias = "mpu_intc_fclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_clk,
-};
-
-static struct clk int_m_iclk = {
- .name = "int_m_iclk",
- .alias = "mpu_intc_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_clk,
-};
-
-static struct clk core_gpt2_clk = {
- .name = "core_gpt2_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk core_gpt3_clk = {
- .name = "core_gpt3_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk core_gpt4_clk = {
- .name = "core_gpt4_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk core_gpt5_clk = {
- .name = "core_gpt5_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk core_gpt6_clk = {
- .name = "core_gpt6_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk core_gpt7_clk = {
- .name = "core_gpt7_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk core_gpt8_clk = {
- .name = "core_gpt8_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk core_gpt9_clk = {
- .name = "core_gpt9_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk core_gpt10_clk = {
- .name = "core_gpt10_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk core_gpt11_clk = {
- .name = "core_gpt11_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk core_gpt12_clk = {
- .name = "core_gpt12_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk mcbsp1_clk = {
- .name = "mcbsp1_cg",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .divisor = 2,
- .parent = &func_96m_clk,
-};
-
-static struct clk mcbsp2_clk = {
- .name = "mcbsp2_cg",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .divisor = 2,
- .parent = &func_96m_clk,
-};
-
-static struct clk emul_clk = {
- .name = "emul_ck",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &func_54m_clk,
-};
-
-static struct clk sdma_fclk = {
- .name = "sdma_fclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &l3_clk,
-};
-
-static struct clk sdma_iclk = {
- .name = "sdma_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_l3_iclk, /* core_l4_iclk for the configuration port */
-};
-
-static struct clk i2c1_fclk = {
- .name = "i2c1.fclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &func_12m_clk,
- .divisor = 1,
-};
-
-static struct clk i2c1_iclk = {
- .name = "i2c1.iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_l4_iclk,
-};
-
-static struct clk i2c2_fclk = {
- .name = "i2c2.fclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &func_12m_clk,
- .divisor = 1,
-};
-
-static struct clk i2c2_iclk = {
- .name = "i2c2.iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_l4_iclk,
-};
-
-static struct clk gpio_dbclk[5] = {
- {
- .name = "gpio1_dbclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &wu_32k_clk,
- }, {
- .name = "gpio2_dbclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &wu_32k_clk,
- }, {
- .name = "gpio3_dbclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &wu_32k_clk,
- }, {
- .name = "gpio4_dbclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &wu_32k_clk,
- }, {
- .name = "gpio5_dbclk",
- .flags = CLOCK_IN_OMAP243X,
- .parent = &wu_32k_clk,
- },
-};
-
-static struct clk gpio_iclk = {
- .name = "gpio_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &wu_l4_iclk,
-};
-
-static struct clk mmc_fck = {
- .name = "mmc_fclk",
- .flags = CLOCK_IN_OMAP242X,
- .parent = &func_96m_clk,
-};
-
-static struct clk mmc_ick = {
- .name = "mmc_iclk",
- .flags = CLOCK_IN_OMAP242X,
- .parent = &core_l4_iclk,
-};
-
-static struct clk spi_fclk[3] = {
- {
- .name = "spi1_fclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &func_48m_clk,
- }, {
- .name = "spi2_fclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &func_48m_clk,
- }, {
- .name = "spi3_fclk",
- .flags = CLOCK_IN_OMAP243X,
- .parent = &func_48m_clk,
- },
-};
-
-static struct clk dss_clk[2] = {
- {
- .name = "dss_clk1",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_clk,
- }, {
- .name = "dss_clk2",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
- },
-};
-
-static struct clk dss_54m_clk = {
- .name = "dss_54m_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &func_54m_clk,
-};
-
-static struct clk dss_l3_iclk = {
- .name = "dss_l3_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_l3_iclk,
-};
-
-static struct clk dss_l4_iclk = {
- .name = "dss_l4_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_l4_iclk,
-};
-
-static struct clk spi_iclk[3] = {
- {
- .name = "spi1_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_l4_iclk,
- }, {
- .name = "spi2_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_l4_iclk,
- }, {
- .name = "spi3_iclk",
- .flags = CLOCK_IN_OMAP243X,
- .parent = &core_l4_iclk,
- },
-};
-
-static struct clk omapctrl_clk = {
- .name = "omapctrl_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- /* XXX Should be in WKUP domain */
- .parent = &core_l4_iclk,
-};
-
-static struct clk *onchip_clks[] = {
- /* OMAP 1 */
-
- /* non-ULPD clocks */
- &xtal_osc12m,
- &xtal_osc32k,
- &ck_ref,
- &dpll1,
- &dpll2,
- &dpll3,
- &dpll4,
- &apll,
- &ck_48m,
- /* CK_GEN1 clocks */
- &clkm1,
- &ck_dpll1out,
- &sossi_ck,
- &arm_ck,
- &armper_ck,
- &arm_gpio_ck,
- &armxor_ck,
- &armtim_ck,
- &armwdt_ck,
- &arminth_ck15xx, &arminth_ck16xx,
- /* CK_GEN2 clocks */
- &clkm2,
- &dsp_ck,
- &dspmmu_ck,
- &dspper_ck,
- &dspxor_ck,
- &dsptim_ck,
- /* CK_GEN3 clocks */
- &clkm3,
- &tc_ck,
- &tipb_ck,
- &l3_ocpi_ck,
- &tc1_ck,
- &tc2_ck,
- &dma_ck,
- &dma_lcdfree_ck,
- &api_ck,
- &lb_ck,
- &lbfree_ck,
- &hsab_ck,
- &rhea1_ck,
- &rhea2_ck,
- &lcd_ck_16xx,
- &lcd_ck_1510,
- /* ULPD clocks */
- &uart1_1510,
- &uart1_16xx,
- &uart2_ck,
- &uart3_1510,
- &uart3_16xx,
- &usb_clk0,
- &usb_hhc_ck1510, &usb_hhc_ck16xx,
- &mclk_1510, &mclk_16xx, &mclk_310,
- &bclk_1510, &bclk_16xx, &bclk_310,
- &mmc1_ck,
- &mmc2_ck,
- &cam_mclk,
- &cam_exclk,
- &cam_lclk,
- &clk32k,
- &usb_w2fc_mclk,
- /* Virtual clocks */
- &i2c_fck,
- &i2c_ick,
-
- /* OMAP 2 */
-
- &ref_clk,
- &apll_96m,
- &apll_54m,
- &sys_clk,
- &sleep_clk,
- &dpll_ck,
- &dpll_x2_ck,
- &wdt1_sys_clk,
- &func_96m_clk,
- &func_48m_clk,
- &func_12m_clk,
- &func_54m_clk,
- &sys_clkout,
- &sys_clkout2,
- &core_clk,
- &l3_clk,
- &core_l4_iclk,
- &wu_l4_iclk,
- &core_l3_iclk,
- &core_l4_usb_clk,
- &wu_gpt1_clk,
- &wu_32k_clk,
- &uart1_fclk,
- &uart1_iclk,
- &uart2_fclk,
- &uart2_iclk,
- &uart3_fclk,
- &uart3_iclk,
- &mpu_fclk,
- &mpu_iclk,
- &int_m_fclk,
- &int_m_iclk,
- &core_gpt2_clk,
- &core_gpt3_clk,
- &core_gpt4_clk,
- &core_gpt5_clk,
- &core_gpt6_clk,
- &core_gpt7_clk,
- &core_gpt8_clk,
- &core_gpt9_clk,
- &core_gpt10_clk,
- &core_gpt11_clk,
- &core_gpt12_clk,
- &mcbsp1_clk,
- &mcbsp2_clk,
- &emul_clk,
- &sdma_fclk,
- &sdma_iclk,
- &i2c1_fclk,
- &i2c1_iclk,
- &i2c2_fclk,
- &i2c2_iclk,
- &gpio_dbclk[0],
- &gpio_dbclk[1],
- &gpio_dbclk[2],
- &gpio_dbclk[3],
- &gpio_iclk,
- &mmc_fck,
- &mmc_ick,
- &spi_fclk[0],
- &spi_iclk[0],
- &spi_fclk[1],
- &spi_iclk[1],
- &spi_fclk[2],
- &spi_iclk[2],
- &dss_clk[0],
- &dss_clk[1],
- &dss_54m_clk,
- &dss_l3_iclk,
- &dss_l4_iclk,
- &omapctrl_clk,
-
- NULL
-};
-
-void omap_clk_adduser(struct clk *clk, qemu_irq user)
-{
- qemu_irq *i;
-
- for (i = clk->users; *i; i ++);
- *i = user;
-}
-
-struct clk *omap_findclk(struct omap_mpu_state_s *mpu, const char *name)
-{
- struct clk *i;
-
- for (i = mpu->clks; i->name; i ++)
- if (!strcmp(i->name, name) || (i->alias && !strcmp(i->alias, name)))
- return i;
- hw_error("%s: %s not found\n", __FUNCTION__, name);
-}
-
-void omap_clk_get(struct clk *clk)
-{
- clk->usecount ++;
-}
-
-void omap_clk_put(struct clk *clk)
-{
- if (!(clk->usecount --))
- hw_error("%s: %s is not in use\n", __FUNCTION__, clk->name);
-}
-
-static void omap_clk_update(struct clk *clk)
-{
- int parent, running;
- qemu_irq *user;
- struct clk *i;
-
- if (clk->parent)
- parent = clk->parent->running;
- else
- parent = 1;
-
- running = parent && (clk->enabled ||
- ((clk->flags & ALWAYS_ENABLED) && clk->usecount));
- if (clk->running != running) {
- clk->running = running;
- for (user = clk->users; *user; user ++)
- qemu_set_irq(*user, running);
- for (i = clk->child1; i; i = i->sibling)
- omap_clk_update(i);
- }
-}
-
-static void omap_clk_rate_update_full(struct clk *clk, unsigned long int rate,
- unsigned long int div, unsigned long int mult)
-{
- struct clk *i;
- qemu_irq *user;
-
- clk->rate = muldiv64(rate, mult, div);
- if (clk->running)
- for (user = clk->users; *user; user ++)
- qemu_irq_raise(*user);
- for (i = clk->child1; i; i = i->sibling)
- omap_clk_rate_update_full(i, rate,
- div * i->divisor, mult * i->multiplier);
-}
-
-static void omap_clk_rate_update(struct clk *clk)
-{
- struct clk *i;
- unsigned long int div, mult = div = 1;
-
- for (i = clk; i->parent; i = i->parent) {
- div *= i->divisor;
- mult *= i->multiplier;
- }
-
- omap_clk_rate_update_full(clk, i->rate, div, mult);
-}
-
-void omap_clk_reparent(struct clk *clk, struct clk *parent)
-{
- struct clk **p;
-
- if (clk->parent) {
- for (p = &clk->parent->child1; *p != clk; p = &(*p)->sibling);
- *p = clk->sibling;
- }
-
- clk->parent = parent;
- if (parent) {
- clk->sibling = parent->child1;
- parent->child1 = clk;
- omap_clk_update(clk);
- omap_clk_rate_update(clk);
- } else
- clk->sibling = NULL;
-}
-
-void omap_clk_onoff(struct clk *clk, int on)
-{
- clk->enabled = on;
- omap_clk_update(clk);
-}
-
-void omap_clk_canidle(struct clk *clk, int can)
-{
- if (can)
- omap_clk_put(clk);
- else
- omap_clk_get(clk);
-}
-
-void omap_clk_setrate(struct clk *clk, int divide, int multiply)
-{
- clk->divisor = divide;
- clk->multiplier = multiply;
- omap_clk_rate_update(clk);
-}
-
-int64_t omap_clk_getrate(omap_clk clk)
-{
- return clk->rate;
-}
-
-void omap_clk_init(struct omap_mpu_state_s *mpu)
-{
- struct clk **i, *j, *k;
- int count;
- int flag;
-
- if (cpu_is_omap310(mpu))
- flag = CLOCK_IN_OMAP310;
- else if (cpu_is_omap1510(mpu))
- flag = CLOCK_IN_OMAP1510;
- else if (cpu_is_omap2410(mpu) || cpu_is_omap2420(mpu))
- flag = CLOCK_IN_OMAP242X;
- else if (cpu_is_omap2430(mpu))
- flag = CLOCK_IN_OMAP243X;
- else if (cpu_is_omap3430(mpu))
- flag = CLOCK_IN_OMAP243X;
- else
- return;
-
- for (i = onchip_clks, count = 0; *i; i ++)
- if ((*i)->flags & flag)
- count ++;
- mpu->clks = g_new0(struct clk, count + 1);
- for (i = onchip_clks, j = mpu->clks; *i; i ++)
- if ((*i)->flags & flag) {
- memcpy(j, *i, sizeof(struct clk));
- for (k = mpu->clks; k < j; k ++)
- if (j->parent && !strcmp(j->parent->name, k->name)) {
- j->parent = k;
- j->sibling = k->child1;
- k->child1 = j;
- } else if (k->parent && !strcmp(k->parent->name, j->name)) {
- k->parent = j;
- k->sibling = j->child1;
- j->child1 = k;
- }
- j->divisor = j->divisor ?: 1;
- j->multiplier = j->multiplier ?: 1;
- j ++;
- }
- for (j = mpu->clks; count --; j ++) {
- omap_clk_update(j);
- omap_clk_rate_update(j);
- }
-}
diff --git a/qemu/hw/misc/omap_gpmc.c b/qemu/hw/misc/omap_gpmc.c
deleted file mode 100644
index 67d8e2f02..000000000
--- a/qemu/hw/misc/omap_gpmc.c
+++ /dev/null
@@ -1,897 +0,0 @@
-/*
- * TI OMAP general purpose memory controller emulation.
- *
- * Copyright (C) 2007-2009 Nokia Corporation
- * Original code written by Andrzej Zaborowski <andrew@openedhand.com>
- * Enhancements for OMAP3 and NAND support written by Juha Riihimäki
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) any later version of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/block/flash.h"
-#include "hw/arm/omap.h"
-#include "exec/memory.h"
-#include "exec/address-spaces.h"
-
-/* General-Purpose Memory Controller */
-struct omap_gpmc_s {
- qemu_irq irq;
- qemu_irq drq;
- MemoryRegion iomem;
- int accept_256;
-
- uint8_t revision;
- uint8_t sysconfig;
- uint16_t irqst;
- uint16_t irqen;
- uint16_t lastirq;
- uint16_t timeout;
- uint16_t config;
- struct omap_gpmc_cs_file_s {
- uint32_t config[7];
- MemoryRegion *iomem;
- MemoryRegion container;
- MemoryRegion nandiomem;
- DeviceState *dev;
- } cs_file[8];
- int ecc_cs;
- int ecc_ptr;
- uint32_t ecc_cfg;
- ECCState ecc[9];
- struct prefetch {
- uint32_t config1; /* GPMC_PREFETCH_CONFIG1 */
- uint32_t transfercount; /* GPMC_PREFETCH_CONFIG2:TRANSFERCOUNT */
- int startengine; /* GPMC_PREFETCH_CONTROL:STARTENGINE */
- int fifopointer; /* GPMC_PREFETCH_STATUS:FIFOPOINTER */
- int count; /* GPMC_PREFETCH_STATUS:COUNTVALUE */
- MemoryRegion iomem;
- uint8_t fifo[64];
- } prefetch;
-};
-
-#define OMAP_GPMC_8BIT 0
-#define OMAP_GPMC_16BIT 1
-#define OMAP_GPMC_NOR 0
-#define OMAP_GPMC_NAND 2
-
-static int omap_gpmc_devtype(struct omap_gpmc_cs_file_s *f)
-{
- return (f->config[0] >> 10) & 3;
-}
-
-static int omap_gpmc_devsize(struct omap_gpmc_cs_file_s *f)
-{
- /* devsize field is really 2 bits but we ignore the high
- * bit to ensure consistent behaviour if the guest sets
- * it (values 2 and 3 are reserved in the TRM)
- */
- return (f->config[0] >> 12) & 1;
-}
-
-/* Extract the chip-select value from the prefetch config1 register */
-static int prefetch_cs(uint32_t config1)
-{
- return (config1 >> 24) & 7;
-}
-
-static int prefetch_threshold(uint32_t config1)
-{
- return (config1 >> 8) & 0x7f;
-}
-
-static void omap_gpmc_int_update(struct omap_gpmc_s *s)
-{
- /* The TRM is a bit unclear, but it seems to say that
- * the TERMINALCOUNTSTATUS bit is set only on the
- * transition when the prefetch engine goes from
- * active to inactive, whereas the FIFOEVENTSTATUS
- * bit is held high as long as the fifo has at
- * least THRESHOLD bytes available.
- * So we do the latter here, but TERMINALCOUNTSTATUS
- * is set elsewhere.
- */
- if (s->prefetch.fifopointer >= prefetch_threshold(s->prefetch.config1)) {
- s->irqst |= 1;
- }
- if ((s->irqen & s->irqst) != s->lastirq) {
- s->lastirq = s->irqen & s->irqst;
- qemu_set_irq(s->irq, s->lastirq);
- }
-}
-
-static void omap_gpmc_dma_update(struct omap_gpmc_s *s, int value)
-{
- if (s->prefetch.config1 & 4) {
- qemu_set_irq(s->drq, value);
- }
-}
-
-/* Access functions for when a NAND-like device is mapped into memory:
- * all addresses in the region behave like accesses to the relevant
- * GPMC_NAND_DATA_i register (which is actually implemented to call these)
- */
-static uint64_t omap_nand_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_gpmc_cs_file_s *f = (struct omap_gpmc_cs_file_s *)opaque;
- uint64_t v;
- nand_setpins(f->dev, 0, 0, 0, 1, 0);
- switch (omap_gpmc_devsize(f)) {
- case OMAP_GPMC_8BIT:
- v = nand_getio(f->dev);
- if (size == 1) {
- return v;
- }
- v |= (nand_getio(f->dev) << 8);
- if (size == 2) {
- return v;
- }
- v |= (nand_getio(f->dev) << 16);
- v |= (nand_getio(f->dev) << 24);
- return v;
- case OMAP_GPMC_16BIT:
- v = nand_getio(f->dev);
- if (size == 1) {
- /* 8 bit read from 16 bit device : probably a guest bug */
- return v & 0xff;
- }
- if (size == 2) {
- return v;
- }
- v |= (nand_getio(f->dev) << 16);
- return v;
- default:
- abort();
- }
-}
-
-static void omap_nand_setio(DeviceState *dev, uint64_t value,
- int nandsize, int size)
-{
- /* Write the specified value to the NAND device, respecting
- * both size of the NAND device and size of the write access.
- */
- switch (nandsize) {
- case OMAP_GPMC_8BIT:
- switch (size) {
- case 1:
- nand_setio(dev, value & 0xff);
- break;
- case 2:
- nand_setio(dev, value & 0xff);
- nand_setio(dev, (value >> 8) & 0xff);
- break;
- case 4:
- default:
- nand_setio(dev, value & 0xff);
- nand_setio(dev, (value >> 8) & 0xff);
- nand_setio(dev, (value >> 16) & 0xff);
- nand_setio(dev, (value >> 24) & 0xff);
- break;
- }
- break;
- case OMAP_GPMC_16BIT:
- switch (size) {
- case 1:
- /* writing to a 16bit device with 8bit access is probably a guest
- * bug; pass the value through anyway.
- */
- case 2:
- nand_setio(dev, value & 0xffff);
- break;
- case 4:
- default:
- nand_setio(dev, value & 0xffff);
- nand_setio(dev, (value >> 16) & 0xffff);
- break;
- }
- break;
- }
-}
-
-static void omap_nand_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_gpmc_cs_file_s *f = (struct omap_gpmc_cs_file_s *)opaque;
- nand_setpins(f->dev, 0, 0, 0, 1, 0);
- omap_nand_setio(f->dev, value, omap_gpmc_devsize(f), size);
-}
-
-static const MemoryRegionOps omap_nand_ops = {
- .read = omap_nand_read,
- .write = omap_nand_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void fill_prefetch_fifo(struct omap_gpmc_s *s)
-{
- /* Fill the prefetch FIFO by reading data from NAND.
- * We do this synchronously, unlike the hardware which
- * will do this asynchronously. We refill when the
- * FIFO has THRESHOLD bytes free, and we always refill
- * as much data as possible starting at the top end
- * of the FIFO.
- * (We have to refill at THRESHOLD rather than waiting
- * for the FIFO to empty to allow for the case where
- * the FIFO size isn't an exact multiple of THRESHOLD
- * and we're doing DMA transfers.)
- * This means we never need to handle wrap-around in
- * the fifo-reading code, and the next byte of data
- * to read is always fifo[63 - fifopointer].
- */
- int fptr;
- int cs = prefetch_cs(s->prefetch.config1);
- int is16bit = (((s->cs_file[cs].config[0] >> 12) & 3) != 0);
- int bytes;
- /* Don't believe the bit of the OMAP TRM that says that COUNTVALUE
- * and TRANSFERCOUNT are in units of 16 bit words for 16 bit NAND.
- * Instead believe the bit that says it is always a byte count.
- */
- bytes = 64 - s->prefetch.fifopointer;
- if (bytes > s->prefetch.count) {
- bytes = s->prefetch.count;
- }
- if (is16bit) {
- bytes &= ~1;
- }
-
- s->prefetch.count -= bytes;
- s->prefetch.fifopointer += bytes;
- fptr = 64 - s->prefetch.fifopointer;
- /* Move the existing data in the FIFO so it sits just
- * before what we're about to read in
- */
- while (fptr < (64 - bytes)) {
- s->prefetch.fifo[fptr] = s->prefetch.fifo[fptr + bytes];
- fptr++;
- }
- while (fptr < 64) {
- if (is16bit) {
- uint32_t v = omap_nand_read(&s->cs_file[cs], 0, 2);
- s->prefetch.fifo[fptr++] = v & 0xff;
- s->prefetch.fifo[fptr++] = (v >> 8) & 0xff;
- } else {
- s->prefetch.fifo[fptr++] = omap_nand_read(&s->cs_file[cs], 0, 1);
- }
- }
- if (s->prefetch.startengine && (s->prefetch.count == 0)) {
- /* This was the final transfer: raise TERMINALCOUNTSTATUS */
- s->irqst |= 2;
- s->prefetch.startengine = 0;
- }
- /* If there are any bytes in the FIFO at this point then
- * we must raise a DMA request (either this is a final part
- * transfer, or we filled the FIFO in which case we certainly
- * have THRESHOLD bytes available)
- */
- if (s->prefetch.fifopointer != 0) {
- omap_gpmc_dma_update(s, 1);
- }
- omap_gpmc_int_update(s);
-}
-
-/* Access functions for a NAND-like device when the prefetch/postwrite
- * engine is enabled -- all addresses in the region behave alike:
- * data is read or written to the FIFO.
- */
-static uint64_t omap_gpmc_prefetch_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque;
- uint32_t data;
- if (s->prefetch.config1 & 1) {
- /* The TRM doesn't define the behaviour if you read from the
- * FIFO when the prefetch engine is in write mode. We choose
- * to always return zero.
- */
- return 0;
- }
- /* Note that trying to read an empty fifo repeats the last byte */
- if (s->prefetch.fifopointer) {
- s->prefetch.fifopointer--;
- }
- data = s->prefetch.fifo[63 - s->prefetch.fifopointer];
- if (s->prefetch.fifopointer ==
- (64 - prefetch_threshold(s->prefetch.config1))) {
- /* We've drained THRESHOLD bytes now. So deassert the
- * DMA request, then refill the FIFO (which will probably
- * assert it again.)
- */
- omap_gpmc_dma_update(s, 0);
- fill_prefetch_fifo(s);
- }
- omap_gpmc_int_update(s);
- return data;
-}
-
-static void omap_gpmc_prefetch_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque;
- int cs = prefetch_cs(s->prefetch.config1);
- if ((s->prefetch.config1 & 1) == 0) {
- /* The TRM doesn't define the behaviour of writing to the
- * FIFO when the prefetch engine is in read mode. We
- * choose to ignore the write.
- */
- return;
- }
- if (s->prefetch.count == 0) {
- /* The TRM doesn't define the behaviour of writing to the
- * FIFO if the transfer is complete. We choose to ignore.
- */
- return;
- }
- /* The only reason we do any data buffering in postwrite
- * mode is if we are talking to a 16 bit NAND device, in
- * which case we need to buffer the first byte of the
- * 16 bit word until the other byte arrives.
- */
- int is16bit = (((s->cs_file[cs].config[0] >> 12) & 3) != 0);
- if (is16bit) {
- /* fifopointer alternates between 64 (waiting for first
- * byte of word) and 63 (waiting for second byte)
- */
- if (s->prefetch.fifopointer == 64) {
- s->prefetch.fifo[0] = value;
- s->prefetch.fifopointer--;
- } else {
- value = (value << 8) | s->prefetch.fifo[0];
- omap_nand_write(&s->cs_file[cs], 0, value, 2);
- s->prefetch.count--;
- s->prefetch.fifopointer = 64;
- }
- } else {
- /* Just write the byte : fifopointer remains 64 at all times */
- omap_nand_write(&s->cs_file[cs], 0, value, 1);
- s->prefetch.count--;
- }
- if (s->prefetch.count == 0) {
- /* Final transfer: raise TERMINALCOUNTSTATUS */
- s->irqst |= 2;
- s->prefetch.startengine = 0;
- }
- omap_gpmc_int_update(s);
-}
-
-static const MemoryRegionOps omap_prefetch_ops = {
- .read = omap_gpmc_prefetch_read,
- .write = omap_gpmc_prefetch_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .impl.min_access_size = 1,
- .impl.max_access_size = 1,
-};
-
-static MemoryRegion *omap_gpmc_cs_memregion(struct omap_gpmc_s *s, int cs)
-{
- /* Return the MemoryRegion* to map/unmap for this chipselect */
- struct omap_gpmc_cs_file_s *f = &s->cs_file[cs];
- if (omap_gpmc_devtype(f) == OMAP_GPMC_NOR) {
- return f->iomem;
- }
- if ((s->prefetch.config1 & 0x80) &&
- (prefetch_cs(s->prefetch.config1) == cs)) {
- /* The prefetch engine is enabled for this CS: map the FIFO */
- return &s->prefetch.iomem;
- }
- return &f->nandiomem;
-}
-
-static void omap_gpmc_cs_map(struct omap_gpmc_s *s, int cs)
-{
- struct omap_gpmc_cs_file_s *f = &s->cs_file[cs];
- uint32_t mask = (f->config[6] >> 8) & 0xf;
- uint32_t base = f->config[6] & 0x3f;
- uint32_t size;
-
- if (!f->iomem && !f->dev) {
- return;
- }
-
- if (!(f->config[6] & (1 << 6))) {
- /* Do nothing unless CSVALID */
- return;
- }
-
- /* TODO: check for overlapping regions and report access errors */
- if (mask != 0x8 && mask != 0xc && mask != 0xe && mask != 0xf
- && !(s->accept_256 && !mask)) {
- fprintf(stderr, "%s: invalid chip-select mask address (0x%x)\n",
- __func__, mask);
- }
-
- base <<= 24;
- size = (0x0fffffff & ~(mask << 24)) + 1;
- /* TODO: rather than setting the size of the mapping (which should be
- * constant), the mask should cause wrapping of the address space, so
- * that the same memory becomes accessible at every <i>size</i> bytes
- * starting from <i>base</i>. */
- memory_region_init(&f->container, NULL, "omap-gpmc-file", size);
- memory_region_add_subregion(&f->container, 0,
- omap_gpmc_cs_memregion(s, cs));
- memory_region_add_subregion(get_system_memory(), base,
- &f->container);
-}
-
-static void omap_gpmc_cs_unmap(struct omap_gpmc_s *s, int cs)
-{
- struct omap_gpmc_cs_file_s *f = &s->cs_file[cs];
- if (!(f->config[6] & (1 << 6))) {
- /* Do nothing unless CSVALID */
- return;
- }
- if (!f->iomem && !f->dev) {
- return;
- }
- memory_region_del_subregion(get_system_memory(), &f->container);
- memory_region_del_subregion(&f->container, omap_gpmc_cs_memregion(s, cs));
- object_unparent(OBJECT(&f->container));
-}
-
-void omap_gpmc_reset(struct omap_gpmc_s *s)
-{
- int i;
-
- s->sysconfig = 0;
- s->irqst = 0;
- s->irqen = 0;
- omap_gpmc_int_update(s);
- for (i = 0; i < 8; i++) {
- /* This has to happen before we change any of the config
- * used to determine which memory regions are mapped or unmapped.
- */
- omap_gpmc_cs_unmap(s, i);
- }
- s->timeout = 0;
- s->config = 0xa00;
- s->prefetch.config1 = 0x00004000;
- s->prefetch.transfercount = 0x00000000;
- s->prefetch.startengine = 0;
- s->prefetch.fifopointer = 0;
- s->prefetch.count = 0;
- for (i = 0; i < 8; i ++) {
- s->cs_file[i].config[1] = 0x101001;
- s->cs_file[i].config[2] = 0x020201;
- s->cs_file[i].config[3] = 0x10031003;
- s->cs_file[i].config[4] = 0x10f1111;
- s->cs_file[i].config[5] = 0;
- s->cs_file[i].config[6] = 0xf00;
- /* In theory we could probe attached devices for some CFG1
- * bits here, but we just retain them across resets as they
- * were set initially by omap_gpmc_attach().
- */
- if (i == 0) {
- s->cs_file[i].config[0] &= 0x00433e00;
- s->cs_file[i].config[6] |= 1 << 6; /* CSVALID */
- omap_gpmc_cs_map(s, i);
- } else {
- s->cs_file[i].config[0] &= 0x00403c00;
- }
- }
- s->ecc_cs = 0;
- s->ecc_ptr = 0;
- s->ecc_cfg = 0x3fcff000;
- for (i = 0; i < 9; i ++)
- ecc_reset(&s->ecc[i]);
-}
-
-static int gpmc_wordaccess_only(hwaddr addr)
-{
- /* Return true if the register offset is to a register that
- * only permits word width accesses.
- * Non-word accesses are only OK for GPMC_NAND_DATA/ADDRESS/COMMAND
- * for any chipselect.
- */
- if (addr >= 0x60 && addr <= 0x1d4) {
- int cs = (addr - 0x60) / 0x30;
- addr -= cs * 0x30;
- if (addr >= 0x7c && addr < 0x88) {
- /* GPMC_NAND_COMMAND, GPMC_NAND_ADDRESS, GPMC_NAND_DATA */
- return 0;
- }
- }
- return 1;
-}
-
-static uint64_t omap_gpmc_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque;
- int cs;
- struct omap_gpmc_cs_file_s *f;
-
- if (size != 4 && gpmc_wordaccess_only(addr)) {
- return omap_badwidth_read32(opaque, addr);
- }
-
- switch (addr) {
- case 0x000: /* GPMC_REVISION */
- return s->revision;
-
- case 0x010: /* GPMC_SYSCONFIG */
- return s->sysconfig;
-
- case 0x014: /* GPMC_SYSSTATUS */
- return 1; /* RESETDONE */
-
- case 0x018: /* GPMC_IRQSTATUS */
- return s->irqst;
-
- case 0x01c: /* GPMC_IRQENABLE */
- return s->irqen;
-
- case 0x040: /* GPMC_TIMEOUT_CONTROL */
- return s->timeout;
-
- case 0x044: /* GPMC_ERR_ADDRESS */
- case 0x048: /* GPMC_ERR_TYPE */
- return 0;
-
- case 0x050: /* GPMC_CONFIG */
- return s->config;
-
- case 0x054: /* GPMC_STATUS */
- return 0x001;
-
- case 0x060 ... 0x1d4:
- cs = (addr - 0x060) / 0x30;
- addr -= cs * 0x30;
- f = s->cs_file + cs;
- switch (addr) {
- case 0x60: /* GPMC_CONFIG1 */
- return f->config[0];
- case 0x64: /* GPMC_CONFIG2 */
- return f->config[1];
- case 0x68: /* GPMC_CONFIG3 */
- return f->config[2];
- case 0x6c: /* GPMC_CONFIG4 */
- return f->config[3];
- case 0x70: /* GPMC_CONFIG5 */
- return f->config[4];
- case 0x74: /* GPMC_CONFIG6 */
- return f->config[5];
- case 0x78: /* GPMC_CONFIG7 */
- return f->config[6];
- case 0x84 ... 0x87: /* GPMC_NAND_DATA */
- if (omap_gpmc_devtype(f) == OMAP_GPMC_NAND) {
- return omap_nand_read(f, 0, size);
- }
- return 0;
- }
- break;
-
- case 0x1e0: /* GPMC_PREFETCH_CONFIG1 */
- return s->prefetch.config1;
- case 0x1e4: /* GPMC_PREFETCH_CONFIG2 */
- return s->prefetch.transfercount;
- case 0x1ec: /* GPMC_PREFETCH_CONTROL */
- return s->prefetch.startengine;
- case 0x1f0: /* GPMC_PREFETCH_STATUS */
- /* NB: The OMAP3 TRM is inconsistent about whether the GPMC
- * FIFOTHRESHOLDSTATUS bit should be set when
- * FIFOPOINTER > FIFOTHRESHOLD or when it is >= FIFOTHRESHOLD.
- * Apparently the underlying functional spec from which the TRM was
- * created states that the behaviour is ">=", and this also
- * makes more conceptual sense.
- */
- return (s->prefetch.fifopointer << 24) |
- ((s->prefetch.fifopointer >=
- ((s->prefetch.config1 >> 8) & 0x7f) ? 1 : 0) << 16) |
- s->prefetch.count;
-
- case 0x1f4: /* GPMC_ECC_CONFIG */
- return s->ecc_cs;
- case 0x1f8: /* GPMC_ECC_CONTROL */
- return s->ecc_ptr;
- case 0x1fc: /* GPMC_ECC_SIZE_CONFIG */
- return s->ecc_cfg;
- case 0x200 ... 0x220: /* GPMC_ECC_RESULT */
- cs = (addr & 0x1f) >> 2;
- /* TODO: check correctness */
- return
- ((s->ecc[cs].cp & 0x07) << 0) |
- ((s->ecc[cs].cp & 0x38) << 13) |
- ((s->ecc[cs].lp[0] & 0x1ff) << 3) |
- ((s->ecc[cs].lp[1] & 0x1ff) << 19);
-
- case 0x230: /* GPMC_TESTMODE_CTRL */
- return 0;
- case 0x234: /* GPMC_PSA_LSB */
- case 0x238: /* GPMC_PSA_MSB */
- return 0x00000000;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_gpmc_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque;
- int cs;
- struct omap_gpmc_cs_file_s *f;
-
- if (size != 4 && gpmc_wordaccess_only(addr)) {
- omap_badwidth_write32(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x000: /* GPMC_REVISION */
- case 0x014: /* GPMC_SYSSTATUS */
- case 0x054: /* GPMC_STATUS */
- case 0x1f0: /* GPMC_PREFETCH_STATUS */
- case 0x200 ... 0x220: /* GPMC_ECC_RESULT */
- case 0x234: /* GPMC_PSA_LSB */
- case 0x238: /* GPMC_PSA_MSB */
- OMAP_RO_REG(addr);
- break;
-
- case 0x010: /* GPMC_SYSCONFIG */
- if ((value >> 3) == 0x3)
- fprintf(stderr, "%s: bad SDRAM idle mode %"PRIi64"\n",
- __FUNCTION__, value >> 3);
- if (value & 2)
- omap_gpmc_reset(s);
- s->sysconfig = value & 0x19;
- break;
-
- case 0x018: /* GPMC_IRQSTATUS */
- s->irqst &= ~value;
- omap_gpmc_int_update(s);
- break;
-
- case 0x01c: /* GPMC_IRQENABLE */
- s->irqen = value & 0xf03;
- omap_gpmc_int_update(s);
- break;
-
- case 0x040: /* GPMC_TIMEOUT_CONTROL */
- s->timeout = value & 0x1ff1;
- break;
-
- case 0x044: /* GPMC_ERR_ADDRESS */
- case 0x048: /* GPMC_ERR_TYPE */
- break;
-
- case 0x050: /* GPMC_CONFIG */
- s->config = value & 0xf13;
- break;
-
- case 0x060 ... 0x1d4:
- cs = (addr - 0x060) / 0x30;
- addr -= cs * 0x30;
- f = s->cs_file + cs;
- switch (addr) {
- case 0x60: /* GPMC_CONFIG1 */
- f->config[0] = value & 0xffef3e13;
- break;
- case 0x64: /* GPMC_CONFIG2 */
- f->config[1] = value & 0x001f1f8f;
- break;
- case 0x68: /* GPMC_CONFIG3 */
- f->config[2] = value & 0x001f1f8f;
- break;
- case 0x6c: /* GPMC_CONFIG4 */
- f->config[3] = value & 0x1f8f1f8f;
- break;
- case 0x70: /* GPMC_CONFIG5 */
- f->config[4] = value & 0x0f1f1f1f;
- break;
- case 0x74: /* GPMC_CONFIG6 */
- f->config[5] = value & 0x00000fcf;
- break;
- case 0x78: /* GPMC_CONFIG7 */
- if ((f->config[6] ^ value) & 0xf7f) {
- omap_gpmc_cs_unmap(s, cs);
- f->config[6] = value & 0x00000f7f;
- omap_gpmc_cs_map(s, cs);
- }
- break;
- case 0x7c ... 0x7f: /* GPMC_NAND_COMMAND */
- if (omap_gpmc_devtype(f) == OMAP_GPMC_NAND) {
- nand_setpins(f->dev, 1, 0, 0, 1, 0); /* CLE */
- omap_nand_setio(f->dev, value, omap_gpmc_devsize(f), size);
- }
- break;
- case 0x80 ... 0x83: /* GPMC_NAND_ADDRESS */
- if (omap_gpmc_devtype(f) == OMAP_GPMC_NAND) {
- nand_setpins(f->dev, 0, 1, 0, 1, 0); /* ALE */
- omap_nand_setio(f->dev, value, omap_gpmc_devsize(f), size);
- }
- break;
- case 0x84 ... 0x87: /* GPMC_NAND_DATA */
- if (omap_gpmc_devtype(f) == OMAP_GPMC_NAND) {
- omap_nand_write(f, 0, value, size);
- }
- break;
- default:
- goto bad_reg;
- }
- break;
-
- case 0x1e0: /* GPMC_PREFETCH_CONFIG1 */
- if (!s->prefetch.startengine) {
- uint32_t newconfig1 = value & 0x7f8f7fbf;
- uint32_t changed;
- changed = newconfig1 ^ s->prefetch.config1;
- if (changed & (0x80 | 0x7000000)) {
- /* Turning the engine on or off, or mapping it somewhere else.
- * cs_map() and cs_unmap() check the prefetch config and
- * overall CSVALID bits, so it is sufficient to unmap-and-map
- * both the old cs and the new one. Note that we adhere to
- * the "unmap/change config/map" order (and not unmap twice
- * if newcs == oldcs), otherwise we'll try to delete the wrong
- * memory region.
- */
- int oldcs = prefetch_cs(s->prefetch.config1);
- int newcs = prefetch_cs(newconfig1);
- omap_gpmc_cs_unmap(s, oldcs);
- if (oldcs != newcs) {
- omap_gpmc_cs_unmap(s, newcs);
- }
- s->prefetch.config1 = newconfig1;
- omap_gpmc_cs_map(s, oldcs);
- if (oldcs != newcs) {
- omap_gpmc_cs_map(s, newcs);
- }
- } else {
- s->prefetch.config1 = newconfig1;
- }
- }
- break;
-
- case 0x1e4: /* GPMC_PREFETCH_CONFIG2 */
- if (!s->prefetch.startengine) {
- s->prefetch.transfercount = value & 0x3fff;
- }
- break;
-
- case 0x1ec: /* GPMC_PREFETCH_CONTROL */
- if (s->prefetch.startengine != (value & 1)) {
- s->prefetch.startengine = value & 1;
- if (s->prefetch.startengine) {
- /* Prefetch engine start */
- s->prefetch.count = s->prefetch.transfercount;
- if (s->prefetch.config1 & 1) {
- /* Write */
- s->prefetch.fifopointer = 64;
- } else {
- /* Read */
- s->prefetch.fifopointer = 0;
- fill_prefetch_fifo(s);
- }
- } else {
- /* Prefetch engine forcibly stopped. The TRM
- * doesn't define the behaviour if you do this.
- * We clear the prefetch count, which means that
- * we permit no more writes, and don't read any
- * more data from NAND. The CPU can still drain
- * the FIFO of unread data.
- */
- s->prefetch.count = 0;
- }
- omap_gpmc_int_update(s);
- }
- break;
-
- case 0x1f4: /* GPMC_ECC_CONFIG */
- s->ecc_cs = 0x8f;
- break;
- case 0x1f8: /* GPMC_ECC_CONTROL */
- if (value & (1 << 8))
- for (cs = 0; cs < 9; cs ++)
- ecc_reset(&s->ecc[cs]);
- s->ecc_ptr = value & 0xf;
- if (s->ecc_ptr == 0 || s->ecc_ptr > 9) {
- s->ecc_ptr = 0;
- s->ecc_cs &= ~1;
- }
- break;
- case 0x1fc: /* GPMC_ECC_SIZE_CONFIG */
- s->ecc_cfg = value & 0x3fcff1ff;
- break;
- case 0x230: /* GPMC_TESTMODE_CTRL */
- if (value & 7)
- fprintf(stderr, "%s: test mode enable attempt\n", __FUNCTION__);
- break;
-
- default:
- bad_reg:
- OMAP_BAD_REG(addr);
- return;
- }
-}
-
-static const MemoryRegionOps omap_gpmc_ops = {
- .read = omap_gpmc_read,
- .write = omap_gpmc_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct omap_gpmc_s *omap_gpmc_init(struct omap_mpu_state_s *mpu,
- hwaddr base,
- qemu_irq irq, qemu_irq drq)
-{
- int cs;
- struct omap_gpmc_s *s = g_new0(struct omap_gpmc_s, 1);
-
- memory_region_init_io(&s->iomem, NULL, &omap_gpmc_ops, s, "omap-gpmc", 0x1000);
- memory_region_add_subregion(get_system_memory(), base, &s->iomem);
-
- s->irq = irq;
- s->drq = drq;
- s->accept_256 = cpu_is_omap3630(mpu);
- s->revision = cpu_class_omap3(mpu) ? 0x50 : 0x20;
- s->lastirq = 0;
- omap_gpmc_reset(s);
-
- /* We have to register a different IO memory handler for each
- * chip select region in case a NAND device is mapped there. We
- * make the region the worst-case size of 256MB and rely on the
- * container memory region in cs_map to chop it down to the actual
- * guest-requested size.
- */
- for (cs = 0; cs < 8; cs++) {
- memory_region_init_io(&s->cs_file[cs].nandiomem, NULL,
- &omap_nand_ops,
- &s->cs_file[cs],
- "omap-nand",
- 256 * 1024 * 1024);
- }
-
- memory_region_init_io(&s->prefetch.iomem, NULL, &omap_prefetch_ops, s,
- "omap-gpmc-prefetch", 256 * 1024 * 1024);
- return s;
-}
-
-void omap_gpmc_attach(struct omap_gpmc_s *s, int cs, MemoryRegion *iomem)
-{
- struct omap_gpmc_cs_file_s *f;
- assert(iomem);
-
- if (cs < 0 || cs >= 8) {
- fprintf(stderr, "%s: bad chip-select %i\n", __FUNCTION__, cs);
- exit(-1);
- }
- f = &s->cs_file[cs];
-
- omap_gpmc_cs_unmap(s, cs);
- f->config[0] &= ~(0xf << 10);
- f->iomem = iomem;
- omap_gpmc_cs_map(s, cs);
-}
-
-void omap_gpmc_attach_nand(struct omap_gpmc_s *s, int cs, DeviceState *nand)
-{
- struct omap_gpmc_cs_file_s *f;
- assert(nand);
-
- if (cs < 0 || cs >= 8) {
- fprintf(stderr, "%s: bad chip-select %i\n", __func__, cs);
- exit(-1);
- }
- f = &s->cs_file[cs];
-
- omap_gpmc_cs_unmap(s, cs);
- f->config[0] &= ~(0xf << 10);
- f->config[0] |= (OMAP_GPMC_NAND << 10);
- f->dev = nand;
- if (nand_getbuswidth(f->dev) == 16) {
- f->config[0] |= OMAP_GPMC_16BIT << 12;
- }
- omap_gpmc_cs_map(s, cs);
-}
diff --git a/qemu/hw/misc/omap_l4.c b/qemu/hw/misc/omap_l4.c
deleted file mode 100644
index 88c533a0f..000000000
--- a/qemu/hw/misc/omap_l4.c
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * TI OMAP L4 interconnect emulation.
- *
- * Copyright (C) 2007-2009 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) any later version of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/arm/omap.h"
-
-struct omap_l4_s {
- MemoryRegion *address_space;
- hwaddr base;
- int ta_num;
- struct omap_target_agent_s ta[0];
-};
-
-struct omap_l4_s *omap_l4_init(MemoryRegion *address_space,
- hwaddr base, int ta_num)
-{
- struct omap_l4_s *bus = g_malloc0(
- sizeof(*bus) + ta_num * sizeof(*bus->ta));
-
- bus->address_space = address_space;
- bus->ta_num = ta_num;
- bus->base = base;
-
- return bus;
-}
-
-hwaddr omap_l4_region_base(struct omap_target_agent_s *ta,
- int region)
-{
- return ta->bus->base + ta->start[region].offset;
-}
-
-hwaddr omap_l4_region_size(struct omap_target_agent_s *ta,
- int region)
-{
- return ta->start[region].size;
-}
-
-static uint64_t omap_l4ta_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_target_agent_s *s = (struct omap_target_agent_s *) opaque;
-
- if (size != 2) {
- return omap_badwidth_read16(opaque, addr);
- }
-
- switch (addr) {
- case 0x00: /* COMPONENT */
- return s->component;
-
- case 0x20: /* AGENT_CONTROL */
- return s->control;
-
- case 0x28: /* AGENT_STATUS */
- return s->status;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_l4ta_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_target_agent_s *s = (struct omap_target_agent_s *) opaque;
-
- if (size != 4) {
- omap_badwidth_write32(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x00: /* COMPONENT */
- case 0x28: /* AGENT_STATUS */
- OMAP_RO_REG(addr);
- break;
-
- case 0x20: /* AGENT_CONTROL */
- s->control = value & 0x01000700;
- if (value & 1) /* OCP_RESET */
- s->status &= ~1; /* REQ_TIMEOUT */
- break;
-
- default:
- OMAP_BAD_REG(addr);
- }
-}
-
-static const MemoryRegionOps omap_l4ta_ops = {
- .read = omap_l4ta_read,
- .write = omap_l4ta_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct omap_target_agent_s *omap_l4ta_get(struct omap_l4_s *bus,
- const struct omap_l4_region_s *regions,
- const struct omap_l4_agent_info_s *agents,
- int cs)
-{
- int i;
- struct omap_target_agent_s *ta = NULL;
- const struct omap_l4_agent_info_s *info = NULL;
-
- for (i = 0; i < bus->ta_num; i ++)
- if (agents[i].ta == cs) {
- ta = &bus->ta[i];
- info = &agents[i];
- break;
- }
- if (!ta) {
- fprintf(stderr, "%s: bad target agent (%i)\n", __FUNCTION__, cs);
- exit(-1);
- }
-
- ta->bus = bus;
- ta->start = &regions[info->region];
- ta->regions = info->regions;
-
- ta->component = ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0);
- ta->status = 0x00000000;
- ta->control = 0x00000200; /* XXX 01000200 for L4TAO */
-
- memory_region_init_io(&ta->iomem, NULL, &omap_l4ta_ops, ta, "omap.l4ta",
- omap_l4_region_size(ta, info->ta_region));
- omap_l4_attach(ta, info->ta_region, &ta->iomem);
-
- return ta;
-}
-
-hwaddr omap_l4_attach(struct omap_target_agent_s *ta,
- int region, MemoryRegion *mr)
-{
- hwaddr base;
-
- if (region < 0 || region >= ta->regions) {
- fprintf(stderr, "%s: bad io region (%i)\n", __FUNCTION__, region);
- exit(-1);
- }
-
- base = ta->bus->base + ta->start[region].offset;
- if (mr) {
- memory_region_add_subregion(ta->bus->address_space, base, mr);
- }
-
- return base;
-}
diff --git a/qemu/hw/misc/omap_sdrc.c b/qemu/hw/misc/omap_sdrc.c
deleted file mode 100644
index dff37ecaf..000000000
--- a/qemu/hw/misc/omap_sdrc.c
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * TI OMAP SDRAM controller emulation.
- *
- * Copyright (C) 2007-2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) any later version of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/arm/omap.h"
-
-/* SDRAM Controller Subsystem */
-struct omap_sdrc_s {
- MemoryRegion iomem;
- uint8_t config;
-};
-
-void omap_sdrc_reset(struct omap_sdrc_s *s)
-{
- s->config = 0x10;
-}
-
-static uint64_t omap_sdrc_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_sdrc_s *s = (struct omap_sdrc_s *) opaque;
-
- if (size != 4) {
- return omap_badwidth_read32(opaque, addr);
- }
-
- switch (addr) {
- case 0x00: /* SDRC_REVISION */
- return 0x20;
-
- case 0x10: /* SDRC_SYSCONFIG */
- return s->config;
-
- case 0x14: /* SDRC_SYSSTATUS */
- return 1; /* RESETDONE */
-
- case 0x40: /* SDRC_CS_CFG */
- case 0x44: /* SDRC_SHARING */
- case 0x48: /* SDRC_ERR_ADDR */
- case 0x4c: /* SDRC_ERR_TYPE */
- case 0x60: /* SDRC_DLLA_SCTRL */
- case 0x64: /* SDRC_DLLA_STATUS */
- case 0x68: /* SDRC_DLLB_CTRL */
- case 0x6c: /* SDRC_DLLB_STATUS */
- case 0x70: /* SDRC_POWER */
- case 0x80: /* SDRC_MCFG_0 */
- case 0x84: /* SDRC_MR_0 */
- case 0x88: /* SDRC_EMR1_0 */
- case 0x8c: /* SDRC_EMR2_0 */
- case 0x90: /* SDRC_EMR3_0 */
- case 0x94: /* SDRC_DCDL1_CTRL */
- case 0x98: /* SDRC_DCDL2_CTRL */
- case 0x9c: /* SDRC_ACTIM_CTRLA_0 */
- case 0xa0: /* SDRC_ACTIM_CTRLB_0 */
- case 0xa4: /* SDRC_RFR_CTRL_0 */
- case 0xa8: /* SDRC_MANUAL_0 */
- case 0xb0: /* SDRC_MCFG_1 */
- case 0xb4: /* SDRC_MR_1 */
- case 0xb8: /* SDRC_EMR1_1 */
- case 0xbc: /* SDRC_EMR2_1 */
- case 0xc0: /* SDRC_EMR3_1 */
- case 0xc4: /* SDRC_ACTIM_CTRLA_1 */
- case 0xc8: /* SDRC_ACTIM_CTRLB_1 */
- case 0xd4: /* SDRC_RFR_CTRL_1 */
- case 0xd8: /* SDRC_MANUAL_1 */
- return 0x00;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_sdrc_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_sdrc_s *s = (struct omap_sdrc_s *) opaque;
-
- if (size != 4) {
- omap_badwidth_write32(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x00: /* SDRC_REVISION */
- case 0x14: /* SDRC_SYSSTATUS */
- case 0x48: /* SDRC_ERR_ADDR */
- case 0x64: /* SDRC_DLLA_STATUS */
- case 0x6c: /* SDRC_DLLB_STATUS */
- OMAP_RO_REG(addr);
- return;
-
- case 0x10: /* SDRC_SYSCONFIG */
- if ((value >> 3) != 0x2)
- fprintf(stderr, "%s: bad SDRAM idle mode %i\n",
- __FUNCTION__, (unsigned)value >> 3);
- if (value & 2)
- omap_sdrc_reset(s);
- s->config = value & 0x18;
- break;
-
- case 0x40: /* SDRC_CS_CFG */
- case 0x44: /* SDRC_SHARING */
- case 0x4c: /* SDRC_ERR_TYPE */
- case 0x60: /* SDRC_DLLA_SCTRL */
- case 0x68: /* SDRC_DLLB_CTRL */
- case 0x70: /* SDRC_POWER */
- case 0x80: /* SDRC_MCFG_0 */
- case 0x84: /* SDRC_MR_0 */
- case 0x88: /* SDRC_EMR1_0 */
- case 0x8c: /* SDRC_EMR2_0 */
- case 0x90: /* SDRC_EMR3_0 */
- case 0x94: /* SDRC_DCDL1_CTRL */
- case 0x98: /* SDRC_DCDL2_CTRL */
- case 0x9c: /* SDRC_ACTIM_CTRLA_0 */
- case 0xa0: /* SDRC_ACTIM_CTRLB_0 */
- case 0xa4: /* SDRC_RFR_CTRL_0 */
- case 0xa8: /* SDRC_MANUAL_0 */
- case 0xb0: /* SDRC_MCFG_1 */
- case 0xb4: /* SDRC_MR_1 */
- case 0xb8: /* SDRC_EMR1_1 */
- case 0xbc: /* SDRC_EMR2_1 */
- case 0xc0: /* SDRC_EMR3_1 */
- case 0xc4: /* SDRC_ACTIM_CTRLA_1 */
- case 0xc8: /* SDRC_ACTIM_CTRLB_1 */
- case 0xd4: /* SDRC_RFR_CTRL_1 */
- case 0xd8: /* SDRC_MANUAL_1 */
- break;
-
- default:
- OMAP_BAD_REG(addr);
- return;
- }
-}
-
-static const MemoryRegionOps omap_sdrc_ops = {
- .read = omap_sdrc_read,
- .write = omap_sdrc_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct omap_sdrc_s *omap_sdrc_init(MemoryRegion *sysmem,
- hwaddr base)
-{
- struct omap_sdrc_s *s = g_new0(struct omap_sdrc_s, 1);
-
- omap_sdrc_reset(s);
-
- memory_region_init_io(&s->iomem, NULL, &omap_sdrc_ops, s, "omap.sdrc", 0x1000);
- memory_region_add_subregion(sysmem, base, &s->iomem);
-
- return s;
-}
diff --git a/qemu/hw/misc/omap_tap.c b/qemu/hw/misc/omap_tap.c
deleted file mode 100644
index e6ea8ee23..000000000
--- a/qemu/hw/misc/omap_tap.c
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * TI OMAP TEST-Chip-level TAP emulation.
- *
- * Copyright (C) 2007-2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) any later version of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/arm/omap.h"
-
-/* TEST-Chip-level TAP */
-static uint64_t omap_tap_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
-
- if (size != 4) {
- return omap_badwidth_read32(opaque, addr);
- }
-
- switch (addr) {
- case 0x204: /* IDCODE_reg */
- switch (s->mpu_model) {
- case omap2420:
- case omap2422:
- case omap2423:
- return 0x5b5d902f; /* ES 2.2 */
- case omap2430:
- return 0x5b68a02f; /* ES 2.2 */
- case omap3430:
- return 0x1b7ae02f; /* ES 2 */
- default:
- hw_error("%s: Bad mpu model\n", __FUNCTION__);
- }
-
- case 0x208: /* PRODUCTION_ID_reg for OMAP2 */
- case 0x210: /* PRODUCTION_ID_reg for OMAP3 */
- switch (s->mpu_model) {
- case omap2420:
- return 0x000254f0; /* POP ESHS2.1.1 in N91/93/95, ES2 in N800 */
- case omap2422:
- return 0x000400f0;
- case omap2423:
- return 0x000800f0;
- case omap2430:
- return 0x000000f0;
- case omap3430:
- return 0x000000f0;
- default:
- hw_error("%s: Bad mpu model\n", __FUNCTION__);
- }
-
- case 0x20c:
- switch (s->mpu_model) {
- case omap2420:
- case omap2422:
- case omap2423:
- return 0xcafeb5d9; /* ES 2.2 */
- case omap2430:
- return 0xcafeb68a; /* ES 2.2 */
- case omap3430:
- return 0xcafeb7ae; /* ES 2 */
- default:
- hw_error("%s: Bad mpu model\n", __FUNCTION__);
- }
-
- case 0x218: /* DIE_ID_reg */
- return ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0);
- case 0x21c: /* DIE_ID_reg */
- return 0x54 << 24;
- case 0x220: /* DIE_ID_reg */
- return ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0);
- case 0x224: /* DIE_ID_reg */
- return ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0);
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_tap_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- if (size != 4) {
- omap_badwidth_write32(opaque, addr, value);
- return;
- }
-
- OMAP_BAD_REG(addr);
-}
-
-static const MemoryRegionOps omap_tap_ops = {
- .read = omap_tap_read,
- .write = omap_tap_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-void omap_tap_init(struct omap_target_agent_s *ta,
- struct omap_mpu_state_s *mpu)
-{
- memory_region_init_io(&mpu->tap_iomem, NULL, &omap_tap_ops, mpu, "omap.tap",
- omap_l4_region_size(ta, 0));
- omap_l4_attach(ta, 0, &mpu->tap_iomem);
-}
diff --git a/qemu/hw/misc/pc-testdev.c b/qemu/hw/misc/pc-testdev.c
deleted file mode 100644
index 086893dcc..000000000
--- a/qemu/hw/misc/pc-testdev.c
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * QEMU x86 ISA testdev
- *
- * Copyright (c) 2012 Avi Kivity, Gerd Hoffmann, Marcelo Tosatti
- *
- * 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.
- */
-
-/*
- * This device is used to test KVM features specific to the x86 port, such
- * as emulation, power management, interrupt routing, among others. It's meant
- * to be used like:
- *
- * qemu-system-x86_64 -device pc-testdev -serial stdio \
- * -device isa-debug-exit,iobase=0xf4,iosize=0x4 \
- * -kernel /home/lmr/Code/virt-test.git/kvm/unittests/msr.flat
- *
- * Where msr.flat is one of the KVM unittests, present on a separate repo,
- * git://git.kernel.org/pub/scm/virt/kvm/kvm-unit-tests.git
-*/
-
-#include "qemu/osdep.h"
-#if defined(CONFIG_POSIX)
-#include <sys/mman.h>
-#endif
-#include "hw/hw.h"
-#include "hw/qdev.h"
-#include "hw/isa/isa.h"
-
-#define IOMEM_LEN 0x10000
-
-typedef struct PCTestdev {
- ISADevice parent_obj;
-
- MemoryRegion ioport;
- MemoryRegion ioport_byte;
- MemoryRegion flush;
- MemoryRegion irq;
- MemoryRegion iomem;
- uint32_t ioport_data;
- char iomem_buf[IOMEM_LEN];
-} PCTestdev;
-
-#define TYPE_TESTDEV "pc-testdev"
-#define TESTDEV(obj) \
- OBJECT_CHECK(PCTestdev, (obj), TYPE_TESTDEV)
-
-static void test_irq_line(void *opaque, hwaddr addr, uint64_t data,
- unsigned len)
-{
- PCTestdev *dev = opaque;
- ISADevice *isa = ISA_DEVICE(dev);
-
- qemu_set_irq(isa_get_irq(isa, addr), !!data);
-}
-
-static const MemoryRegionOps test_irq_ops = {
- .write = test_irq_line,
- .valid.min_access_size = 1,
- .valid.max_access_size = 1,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void test_ioport_write(void *opaque, hwaddr addr, uint64_t data,
- unsigned len)
-{
- PCTestdev *dev = opaque;
- int bits = len * 8;
- int start_bit = (addr & 3) * 8;
- uint32_t mask = ((uint32_t)-1 >> (32 - bits)) << start_bit;
- dev->ioport_data &= ~mask;
- dev->ioport_data |= data << start_bit;
-}
-
-static uint64_t test_ioport_read(void *opaque, hwaddr addr, unsigned len)
-{
- PCTestdev *dev = opaque;
- int bits = len * 8;
- int start_bit = (addr & 3) * 8;
- uint32_t mask = ((uint32_t)-1 >> (32 - bits)) << start_bit;
- return (dev->ioport_data & mask) >> start_bit;
-}
-
-static const MemoryRegionOps test_ioport_ops = {
- .read = test_ioport_read,
- .write = test_ioport_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static const MemoryRegionOps test_ioport_byte_ops = {
- .read = test_ioport_read,
- .write = test_ioport_write,
- .valid.min_access_size = 1,
- .valid.max_access_size = 4,
- .impl.min_access_size = 1,
- .impl.max_access_size = 1,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void test_flush_page(void *opaque, hwaddr addr, uint64_t data,
- unsigned len)
-{
- hwaddr page = 4096;
- void *a = cpu_physical_memory_map(data & ~0xffful, &page, 0);
-
- /* We might not be able to get the full page, only mprotect what we actually
- have mapped */
-#if defined(CONFIG_POSIX)
- mprotect(a, page, PROT_NONE);
- mprotect(a, page, PROT_READ|PROT_WRITE);
-#endif
- cpu_physical_memory_unmap(a, page, 0, 0);
-}
-
-static const MemoryRegionOps test_flush_ops = {
- .write = test_flush_page,
- .valid.min_access_size = 4,
- .valid.max_access_size = 4,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static uint64_t test_iomem_read(void *opaque, hwaddr addr, unsigned len)
-{
- PCTestdev *dev = opaque;
- uint64_t ret = 0;
- memcpy(&ret, &dev->iomem_buf[addr], len);
-
- return ret;
-}
-
-static void test_iomem_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned len)
-{
- PCTestdev *dev = opaque;
- memcpy(&dev->iomem_buf[addr], &val, len);
- dev->iomem_buf[addr] = val;
-}
-
-static const MemoryRegionOps test_iomem_ops = {
- .read = test_iomem_read,
- .write = test_iomem_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void testdev_realizefn(DeviceState *d, Error **errp)
-{
- ISADevice *isa = ISA_DEVICE(d);
- PCTestdev *dev = TESTDEV(d);
- MemoryRegion *mem = isa_address_space(isa);
- MemoryRegion *io = isa_address_space_io(isa);
-
- memory_region_init_io(&dev->ioport, OBJECT(dev), &test_ioport_ops, dev,
- "pc-testdev-ioport", 4);
- memory_region_init_io(&dev->ioport_byte, OBJECT(dev),
- &test_ioport_byte_ops, dev,
- "pc-testdev-ioport-byte", 4);
- memory_region_init_io(&dev->flush, OBJECT(dev), &test_flush_ops, dev,
- "pc-testdev-flush-page", 4);
- memory_region_init_io(&dev->irq, OBJECT(dev), &test_irq_ops, dev,
- "pc-testdev-irq-line", 24);
- memory_region_init_io(&dev->iomem, OBJECT(dev), &test_iomem_ops, dev,
- "pc-testdev-iomem", IOMEM_LEN);
-
- memory_region_add_subregion(io, 0xe0, &dev->ioport);
- memory_region_add_subregion(io, 0xe4, &dev->flush);
- memory_region_add_subregion(io, 0xe8, &dev->ioport_byte);
- memory_region_add_subregion(io, 0x2000, &dev->irq);
- memory_region_add_subregion(mem, 0xff000000, &dev->iomem);
-}
-
-static void testdev_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- dc->realize = testdev_realizefn;
-}
-
-static const TypeInfo testdev_info = {
- .name = TYPE_TESTDEV,
- .parent = TYPE_ISA_DEVICE,
- .instance_size = sizeof(PCTestdev),
- .class_init = testdev_class_init,
-};
-
-static void testdev_register_types(void)
-{
- type_register_static(&testdev_info);
-}
-
-type_init(testdev_register_types)
diff --git a/qemu/hw/misc/pci-testdev.c b/qemu/hw/misc/pci-testdev.c
deleted file mode 100644
index 2f2e98977..000000000
--- a/qemu/hw/misc/pci-testdev.c
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * QEMU PCI test device
- *
- * Copyright (c) 2012 Red Hat Inc.
- * Author: Michael S. Tsirkin <mst@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/pci/pci.h"
-#include "qemu/event_notifier.h"
-
-typedef struct PCITestDevHdr {
- uint8_t test;
- uint8_t width;
- uint8_t pad0[2];
- uint32_t offset;
- uint8_t data;
- uint8_t pad1[3];
- uint32_t count;
- uint8_t name[];
-} PCITestDevHdr;
-
-typedef struct IOTest {
- MemoryRegion *mr;
- EventNotifier notifier;
- bool hasnotifier;
- unsigned size;
- bool match_data;
- PCITestDevHdr *hdr;
- unsigned bufsize;
-} IOTest;
-
-#define IOTEST_DATAMATCH 0xFA
-#define IOTEST_NOMATCH 0xCE
-
-#define IOTEST_IOSIZE 128
-#define IOTEST_MEMSIZE 2048
-
-static const char *iotest_test[] = {
- "no-eventfd",
- "wildcard-eventfd",
- "datamatch-eventfd"
-};
-
-static const char *iotest_type[] = {
- "mmio",
- "portio"
-};
-
-#define IOTEST_TEST(i) (iotest_test[((i) % ARRAY_SIZE(iotest_test))])
-#define IOTEST_TYPE(i) (iotest_type[((i) / ARRAY_SIZE(iotest_test))])
-#define IOTEST_MAX_TEST (ARRAY_SIZE(iotest_test))
-#define IOTEST_MAX_TYPE (ARRAY_SIZE(iotest_type))
-#define IOTEST_MAX (IOTEST_MAX_TEST * IOTEST_MAX_TYPE)
-
-enum {
- IOTEST_ACCESS_NAME,
- IOTEST_ACCESS_DATA,
- IOTEST_ACCESS_MAX,
-};
-
-#define IOTEST_ACCESS_TYPE uint8_t
-#define IOTEST_ACCESS_WIDTH (sizeof(uint8_t))
-
-typedef struct PCITestDevState {
- /*< private >*/
- PCIDevice parent_obj;
- /*< public >*/
-
- MemoryRegion mmio;
- MemoryRegion portio;
- IOTest *tests;
- int current;
-} PCITestDevState;
-
-#define TYPE_PCI_TEST_DEV "pci-testdev"
-
-#define PCI_TEST_DEV(obj) \
- OBJECT_CHECK(PCITestDevState, (obj), TYPE_PCI_TEST_DEV)
-
-#define IOTEST_IS_MEM(i) (strcmp(IOTEST_TYPE(i), "portio"))
-#define IOTEST_REGION(d, i) (IOTEST_IS_MEM(i) ? &(d)->mmio : &(d)->portio)
-#define IOTEST_SIZE(i) (IOTEST_IS_MEM(i) ? IOTEST_MEMSIZE : IOTEST_IOSIZE)
-#define IOTEST_PCI_BAR(i) (IOTEST_IS_MEM(i) ? PCI_BASE_ADDRESS_SPACE_MEMORY : \
- PCI_BASE_ADDRESS_SPACE_IO)
-
-static int pci_testdev_start(IOTest *test)
-{
- test->hdr->count = 0;
- if (!test->hasnotifier) {
- return 0;
- }
- event_notifier_test_and_clear(&test->notifier);
- memory_region_add_eventfd(test->mr,
- le32_to_cpu(test->hdr->offset),
- test->size,
- test->match_data,
- test->hdr->data,
- &test->notifier);
- return 0;
-}
-
-static void pci_testdev_stop(IOTest *test)
-{
- if (!test->hasnotifier) {
- return;
- }
- memory_region_del_eventfd(test->mr,
- le32_to_cpu(test->hdr->offset),
- test->size,
- test->match_data,
- test->hdr->data,
- &test->notifier);
-}
-
-static void
-pci_testdev_reset(PCITestDevState *d)
-{
- if (d->current == -1) {
- return;
- }
- pci_testdev_stop(&d->tests[d->current]);
- d->current = -1;
-}
-
-static void pci_testdev_inc(IOTest *test, unsigned inc)
-{
- uint32_t c = le32_to_cpu(test->hdr->count);
- test->hdr->count = cpu_to_le32(c + inc);
-}
-
-static void
-pci_testdev_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned size, int type)
-{
- PCITestDevState *d = opaque;
- IOTest *test;
- int t, r;
-
- if (addr == offsetof(PCITestDevHdr, test)) {
- pci_testdev_reset(d);
- if (val >= IOTEST_MAX_TEST) {
- return;
- }
- t = type * IOTEST_MAX_TEST + val;
- r = pci_testdev_start(&d->tests[t]);
- if (r < 0) {
- return;
- }
- d->current = t;
- return;
- }
- if (d->current < 0) {
- return;
- }
- test = &d->tests[d->current];
- if (addr != le32_to_cpu(test->hdr->offset)) {
- return;
- }
- if (test->match_data && test->size != size) {
- return;
- }
- if (test->match_data && val != test->hdr->data) {
- return;
- }
- pci_testdev_inc(test, 1);
-}
-
-static uint64_t
-pci_testdev_read(void *opaque, hwaddr addr, unsigned size)
-{
- PCITestDevState *d = opaque;
- const char *buf;
- IOTest *test;
- if (d->current < 0) {
- return 0;
- }
- test = &d->tests[d->current];
- buf = (const char *)test->hdr;
- if (addr + size >= test->bufsize) {
- return 0;
- }
- if (test->hasnotifier) {
- event_notifier_test_and_clear(&test->notifier);
- }
- return buf[addr];
-}
-
-static void
-pci_testdev_mmio_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned size)
-{
- pci_testdev_write(opaque, addr, val, size, 0);
-}
-
-static void
-pci_testdev_pio_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned size)
-{
- pci_testdev_write(opaque, addr, val, size, 1);
-}
-
-static const MemoryRegionOps pci_testdev_mmio_ops = {
- .read = pci_testdev_read,
- .write = pci_testdev_mmio_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
-};
-
-static const MemoryRegionOps pci_testdev_pio_ops = {
- .read = pci_testdev_read,
- .write = pci_testdev_pio_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
-};
-
-static void pci_testdev_realize(PCIDevice *pci_dev, Error **errp)
-{
- PCITestDevState *d = PCI_TEST_DEV(pci_dev);
- uint8_t *pci_conf;
- char *name;
- int r, i;
- bool fastmmio = kvm_ioeventfd_any_length_enabled();
-
- pci_conf = pci_dev->config;
-
- pci_conf[PCI_INTERRUPT_PIN] = 0; /* no interrupt pin */
-
- memory_region_init_io(&d->mmio, OBJECT(d), &pci_testdev_mmio_ops, d,
- "pci-testdev-mmio", IOTEST_MEMSIZE * 2);
- memory_region_init_io(&d->portio, OBJECT(d), &pci_testdev_pio_ops, d,
- "pci-testdev-portio", IOTEST_IOSIZE * 2);
- pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio);
- pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &d->portio);
-
- d->current = -1;
- d->tests = g_malloc0(IOTEST_MAX * sizeof *d->tests);
- for (i = 0; i < IOTEST_MAX; ++i) {
- IOTest *test = &d->tests[i];
- name = g_strdup_printf("%s-%s", IOTEST_TYPE(i), IOTEST_TEST(i));
- test->bufsize = sizeof(PCITestDevHdr) + strlen(name) + 1;
- test->hdr = g_malloc0(test->bufsize);
- memcpy(test->hdr->name, name, strlen(name) + 1);
- g_free(name);
- test->hdr->offset = cpu_to_le32(IOTEST_SIZE(i) + i * IOTEST_ACCESS_WIDTH);
- test->match_data = strcmp(IOTEST_TEST(i), "wildcard-eventfd");
- if (fastmmio && IOTEST_IS_MEM(i) && !test->match_data) {
- test->size = 0;
- } else {
- test->size = IOTEST_ACCESS_WIDTH;
- }
- test->hdr->test = i;
- test->hdr->data = test->match_data ? IOTEST_DATAMATCH : IOTEST_NOMATCH;
- test->hdr->width = IOTEST_ACCESS_WIDTH;
- test->mr = IOTEST_REGION(d, i);
- if (!strcmp(IOTEST_TEST(i), "no-eventfd")) {
- test->hasnotifier = false;
- continue;
- }
- r = event_notifier_init(&test->notifier, 0);
- assert(r >= 0);
- test->hasnotifier = true;
- }
-}
-
-static void
-pci_testdev_uninit(PCIDevice *dev)
-{
- PCITestDevState *d = PCI_TEST_DEV(dev);
- int i;
-
- pci_testdev_reset(d);
- for (i = 0; i < IOTEST_MAX; ++i) {
- if (d->tests[i].hasnotifier) {
- event_notifier_cleanup(&d->tests[i].notifier);
- }
- g_free(d->tests[i].hdr);
- }
- g_free(d->tests);
-}
-
-static void qdev_pci_testdev_reset(DeviceState *dev)
-{
- PCITestDevState *d = PCI_TEST_DEV(dev);
- pci_testdev_reset(d);
-}
-
-static void pci_testdev_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = pci_testdev_realize;
- k->exit = pci_testdev_uninit;
- k->vendor_id = PCI_VENDOR_ID_REDHAT;
- k->device_id = PCI_DEVICE_ID_REDHAT_TEST;
- k->revision = 0x00;
- k->class_id = PCI_CLASS_OTHERS;
- dc->desc = "PCI Test Device";
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- dc->reset = qdev_pci_testdev_reset;
-}
-
-static const TypeInfo pci_testdev_info = {
- .name = TYPE_PCI_TEST_DEV,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(PCITestDevState),
- .class_init = pci_testdev_class_init,
-};
-
-static void pci_testdev_register_types(void)
-{
- type_register_static(&pci_testdev_info);
-}
-
-type_init(pci_testdev_register_types)
diff --git a/qemu/hw/misc/puv3_pm.c b/qemu/hw/misc/puv3_pm.c
deleted file mode 100644
index 577cebaac..000000000
--- a/qemu/hw/misc/puv3_pm.c
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Power Management device simulation in PKUnity SoC
- *
- * Copyright (C) 2010-2012 Guan Xuetao
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation, or any later version.
- * See the COPYING file in the top-level directory.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-
-#undef DEBUG_PUV3
-#include "hw/unicore32/puv3.h"
-
-#define TYPE_PUV3_PM "puv3_pm"
-#define PUV3_PM(obj) OBJECT_CHECK(PUV3PMState, (obj), TYPE_PUV3_PM)
-
-typedef struct PUV3PMState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
-
- uint32_t reg_PMCR;
- uint32_t reg_PCGR;
- uint32_t reg_PLL_SYS_CFG;
- uint32_t reg_PLL_DDR_CFG;
- uint32_t reg_PLL_VGA_CFG;
- uint32_t reg_DIVCFG;
-} PUV3PMState;
-
-static uint64_t puv3_pm_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- PUV3PMState *s = opaque;
- uint32_t ret = 0;
-
- switch (offset) {
- case 0x14:
- ret = s->reg_PCGR;
- break;
- case 0x18:
- ret = s->reg_PLL_SYS_CFG;
- break;
- case 0x1c:
- ret = s->reg_PLL_DDR_CFG;
- break;
- case 0x20:
- ret = s->reg_PLL_VGA_CFG;
- break;
- case 0x24:
- ret = s->reg_DIVCFG;
- break;
- case 0x28: /* PLL SYS STATUS */
- ret = 0x00002401;
- break;
- case 0x2c: /* PLL DDR STATUS */
- ret = 0x00100c00;
- break;
- case 0x30: /* PLL VGA STATUS */
- ret = 0x00003801;
- break;
- case 0x34: /* DIV STATUS */
- ret = 0x22f52015;
- break;
- case 0x38: /* SW RESET */
- ret = 0x0;
- break;
- case 0x44: /* PLL DFC DONE */
- ret = 0x7;
- break;
- default:
- DPRINTF("Bad offset 0x%x\n", offset);
- }
- DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
-
- return ret;
-}
-
-static void puv3_pm_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PUV3PMState *s = opaque;
-
- switch (offset) {
- case 0x0:
- s->reg_PMCR = value;
- break;
- case 0x14:
- s->reg_PCGR = value;
- break;
- case 0x18:
- s->reg_PLL_SYS_CFG = value;
- break;
- case 0x1c:
- s->reg_PLL_DDR_CFG = value;
- break;
- case 0x20:
- s->reg_PLL_VGA_CFG = value;
- break;
- case 0x24:
- case 0x38:
- break;
- default:
- DPRINTF("Bad offset 0x%x\n", offset);
- }
- DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
-}
-
-static const MemoryRegionOps puv3_pm_ops = {
- .read = puv3_pm_read,
- .write = puv3_pm_write,
- .impl = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int puv3_pm_init(SysBusDevice *dev)
-{
- PUV3PMState *s = PUV3_PM(dev);
-
- s->reg_PCGR = 0x0;
-
- memory_region_init_io(&s->iomem, OBJECT(s), &puv3_pm_ops, s, "puv3_pm",
- PUV3_REGS_OFFSET);
- sysbus_init_mmio(dev, &s->iomem);
-
- return 0;
-}
-
-static void puv3_pm_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
- sdc->init = puv3_pm_init;
-}
-
-static const TypeInfo puv3_pm_info = {
- .name = TYPE_PUV3_PM,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PUV3PMState),
- .class_init = puv3_pm_class_init,
-};
-
-static void puv3_pm_register_type(void)
-{
- type_register_static(&puv3_pm_info);
-}
-
-type_init(puv3_pm_register_type)
diff --git a/qemu/hw/misc/pvpanic.c b/qemu/hw/misc/pvpanic.c
deleted file mode 100644
index 0ac1e6ac9..000000000
--- a/qemu/hw/misc/pvpanic.c
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * QEMU simulated pvpanic device.
- *
- * Copyright Fujitsu, Corp. 2013
- *
- * Authors:
- * Wen Congyang <wency@cn.fujitsu.com>
- * Hu Tao <hutao@cn.fujitsu.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "qapi/qmp/qobject.h"
-#include "qapi/qmp/qjson.h"
-#include "sysemu/sysemu.h"
-#include "qemu/log.h"
-
-#include "hw/nvram/fw_cfg.h"
-#include "hw/i386/pc.h"
-#include "qapi-event.h"
-
-/* The bit of supported pv event */
-#define PVPANIC_F_PANICKED 0
-
-/* The pv event value */
-#define PVPANIC_PANICKED (1 << PVPANIC_F_PANICKED)
-
-#define TYPE_ISA_PVPANIC_DEVICE "pvpanic"
-#define ISA_PVPANIC_DEVICE(obj) \
- OBJECT_CHECK(PVPanicState, (obj), TYPE_ISA_PVPANIC_DEVICE)
-
-static void handle_event(int event)
-{
- static bool logged;
-
- if (event & ~PVPANIC_PANICKED && !logged) {
- qemu_log_mask(LOG_GUEST_ERROR, "pvpanic: unknown event %#x.\n", event);
- logged = true;
- }
-
- if (event & PVPANIC_PANICKED) {
- qemu_system_guest_panicked();
- return;
- }
-}
-
-#include "hw/isa/isa.h"
-
-typedef struct PVPanicState {
- ISADevice parent_obj;
-
- MemoryRegion io;
- uint16_t ioport;
-} PVPanicState;
-
-/* return supported events on read */
-static uint64_t pvpanic_ioport_read(void *opaque, hwaddr addr, unsigned size)
-{
- return PVPANIC_PANICKED;
-}
-
-static void pvpanic_ioport_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned size)
-{
- handle_event(val);
-}
-
-static const MemoryRegionOps pvpanic_ops = {
- .read = pvpanic_ioport_read,
- .write = pvpanic_ioport_write,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
-};
-
-static void pvpanic_isa_initfn(Object *obj)
-{
- PVPanicState *s = ISA_PVPANIC_DEVICE(obj);
-
- memory_region_init_io(&s->io, OBJECT(s), &pvpanic_ops, s, "pvpanic", 1);
-}
-
-static void pvpanic_isa_realizefn(DeviceState *dev, Error **errp)
-{
- ISADevice *d = ISA_DEVICE(dev);
- PVPanicState *s = ISA_PVPANIC_DEVICE(dev);
- FWCfgState *fw_cfg = fw_cfg_find();
- uint16_t *pvpanic_port;
-
- if (!fw_cfg) {
- return;
- }
-
- pvpanic_port = g_malloc(sizeof(*pvpanic_port));
- *pvpanic_port = cpu_to_le16(s->ioport);
- fw_cfg_add_file(fw_cfg, "etc/pvpanic-port", pvpanic_port,
- sizeof(*pvpanic_port));
-
- isa_register_ioport(d, &s->io, s->ioport);
-}
-
-#define PVPANIC_IOPORT_PROP "ioport"
-
-uint16_t pvpanic_port(void)
-{
- Object *o = object_resolve_path_type("", TYPE_ISA_PVPANIC_DEVICE, NULL);
- if (!o) {
- return 0;
- }
- return object_property_get_int(o, PVPANIC_IOPORT_PROP, NULL);
-}
-
-static Property pvpanic_isa_properties[] = {
- DEFINE_PROP_UINT16(PVPANIC_IOPORT_PROP, PVPanicState, ioport, 0x505),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pvpanic_isa_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = pvpanic_isa_realizefn;
- dc->props = pvpanic_isa_properties;
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
-}
-
-static TypeInfo pvpanic_isa_info = {
- .name = TYPE_ISA_PVPANIC_DEVICE,
- .parent = TYPE_ISA_DEVICE,
- .instance_size = sizeof(PVPanicState),
- .instance_init = pvpanic_isa_initfn,
- .class_init = pvpanic_isa_class_init,
-};
-
-static void pvpanic_register_types(void)
-{
- type_register_static(&pvpanic_isa_info);
-}
-
-type_init(pvpanic_register_types)
diff --git a/qemu/hw/misc/sga.c b/qemu/hw/misc/sga.c
deleted file mode 100644
index 03b006d6f..000000000
--- a/qemu/hw/misc/sga.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * QEMU dummy ISA device for loading sgabios option rom.
- *
- * Copyright (c) 2011 Glauber Costa, Red Hat Inc.
- *
- * 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.
- *
- * sgabios code originally available at code.google.com/p/sgabios
- *
- */
-#include "qemu/osdep.h"
-#include "hw/pci/pci.h"
-#include "hw/i386/pc.h"
-#include "hw/loader.h"
-#include "sysemu/sysemu.h"
-
-#define SGABIOS_FILENAME "sgabios.bin"
-
-#define TYPE_SGA "sga"
-#define SGA(obj) OBJECT_CHECK(ISASGAState, (obj), TYPE_SGA)
-
-typedef struct ISASGAState {
- ISADevice parent_obj;
-} ISASGAState;
-
-static void sga_realizefn(DeviceState *dev, Error **errp)
-{
- rom_add_vga(SGABIOS_FILENAME);
-}
-
-static void sga_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
- dc->realize = sga_realizefn;
- dc->desc = "Serial Graphics Adapter";
-}
-
-static const TypeInfo sga_info = {
- .name = TYPE_SGA,
- .parent = TYPE_ISA_DEVICE,
- .instance_size = sizeof(ISASGAState),
- .class_init = sga_class_initfn,
-};
-
-static void sga_register_types(void)
-{
- type_register_static(&sga_info);
-}
-
-type_init(sga_register_types)
diff --git a/qemu/hw/misc/slavio_misc.c b/qemu/hw/misc/slavio_misc.c
deleted file mode 100644
index edd5de070..000000000
--- a/qemu/hw/misc/slavio_misc.c
+++ /dev/null
@@ -1,518 +0,0 @@
-/*
- * QEMU Sparc SLAVIO aux io port emulation
- *
- * Copyright (c) 2005 Fabrice Bellard
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "sysemu/sysemu.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-
-/*
- * This is the auxio port, chip control and system control part of
- * chip STP2001 (Slave I/O), also produced as NCR89C105. See
- * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
- *
- * This also includes the PMC CPU idle controller.
- */
-
-#define TYPE_SLAVIO_MISC "slavio_misc"
-#define SLAVIO_MISC(obj) OBJECT_CHECK(MiscState, (obj), TYPE_SLAVIO_MISC)
-
-typedef struct MiscState {
- SysBusDevice parent_obj;
-
- MemoryRegion cfg_iomem;
- MemoryRegion diag_iomem;
- MemoryRegion mdm_iomem;
- MemoryRegion led_iomem;
- MemoryRegion sysctrl_iomem;
- MemoryRegion aux1_iomem;
- MemoryRegion aux2_iomem;
- qemu_irq irq;
- qemu_irq fdc_tc;
- uint32_t dummy;
- uint8_t config;
- uint8_t aux1, aux2;
- uint8_t diag, mctrl;
- uint8_t sysctrl;
- uint16_t leds;
-} MiscState;
-
-#define TYPE_APC "apc"
-#define APC(obj) OBJECT_CHECK(APCState, (obj), TYPE_APC)
-
-typedef struct APCState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- qemu_irq cpu_halt;
-} APCState;
-
-#define MISC_SIZE 1
-#define LED_SIZE 2
-#define SYSCTRL_SIZE 4
-
-#define AUX1_TC 0x02
-
-#define AUX2_PWROFF 0x01
-#define AUX2_PWRINTCLR 0x02
-#define AUX2_PWRFAIL 0x20
-
-#define CFG_PWRINTEN 0x08
-
-#define SYS_RESET 0x01
-#define SYS_RESETSTAT 0x02
-
-static void slavio_misc_update_irq(void *opaque)
-{
- MiscState *s = opaque;
-
- if ((s->aux2 & AUX2_PWRFAIL) && (s->config & CFG_PWRINTEN)) {
- trace_slavio_misc_update_irq_raise();
- qemu_irq_raise(s->irq);
- } else {
- trace_slavio_misc_update_irq_lower();
- qemu_irq_lower(s->irq);
- }
-}
-
-static void slavio_misc_reset(DeviceState *d)
-{
- MiscState *s = SLAVIO_MISC(d);
-
- // Diagnostic and system control registers not cleared in reset
- s->config = s->aux1 = s->aux2 = s->mctrl = 0;
-}
-
-static void slavio_set_power_fail(void *opaque, int irq, int power_failing)
-{
- MiscState *s = opaque;
-
- trace_slavio_set_power_fail(power_failing, s->config);
- if (power_failing && (s->config & CFG_PWRINTEN)) {
- s->aux2 |= AUX2_PWRFAIL;
- } else {
- s->aux2 &= ~AUX2_PWRFAIL;
- }
- slavio_misc_update_irq(s);
-}
-
-static void slavio_cfg_mem_writeb(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- MiscState *s = opaque;
-
- trace_slavio_cfg_mem_writeb(val & 0xff);
- s->config = val & 0xff;
- slavio_misc_update_irq(s);
-}
-
-static uint64_t slavio_cfg_mem_readb(void *opaque, hwaddr addr,
- unsigned size)
-{
- MiscState *s = opaque;
- uint32_t ret = 0;
-
- ret = s->config;
- trace_slavio_cfg_mem_readb(ret);
- return ret;
-}
-
-static const MemoryRegionOps slavio_cfg_mem_ops = {
- .read = slavio_cfg_mem_readb,
- .write = slavio_cfg_mem_writeb,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
-};
-
-static void slavio_diag_mem_writeb(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- MiscState *s = opaque;
-
- trace_slavio_diag_mem_writeb(val & 0xff);
- s->diag = val & 0xff;
-}
-
-static uint64_t slavio_diag_mem_readb(void *opaque, hwaddr addr,
- unsigned size)
-{
- MiscState *s = opaque;
- uint32_t ret = 0;
-
- ret = s->diag;
- trace_slavio_diag_mem_readb(ret);
- return ret;
-}
-
-static const MemoryRegionOps slavio_diag_mem_ops = {
- .read = slavio_diag_mem_readb,
- .write = slavio_diag_mem_writeb,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
-};
-
-static void slavio_mdm_mem_writeb(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- MiscState *s = opaque;
-
- trace_slavio_mdm_mem_writeb(val & 0xff);
- s->mctrl = val & 0xff;
-}
-
-static uint64_t slavio_mdm_mem_readb(void *opaque, hwaddr addr,
- unsigned size)
-{
- MiscState *s = opaque;
- uint32_t ret = 0;
-
- ret = s->mctrl;
- trace_slavio_mdm_mem_readb(ret);
- return ret;
-}
-
-static const MemoryRegionOps slavio_mdm_mem_ops = {
- .read = slavio_mdm_mem_readb,
- .write = slavio_mdm_mem_writeb,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
-};
-
-static void slavio_aux1_mem_writeb(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- MiscState *s = opaque;
-
- trace_slavio_aux1_mem_writeb(val & 0xff);
- if (val & AUX1_TC) {
- // Send a pulse to floppy terminal count line
- if (s->fdc_tc) {
- qemu_irq_raise(s->fdc_tc);
- qemu_irq_lower(s->fdc_tc);
- }
- val &= ~AUX1_TC;
- }
- s->aux1 = val & 0xff;
-}
-
-static uint64_t slavio_aux1_mem_readb(void *opaque, hwaddr addr,
- unsigned size)
-{
- MiscState *s = opaque;
- uint32_t ret = 0;
-
- ret = s->aux1;
- trace_slavio_aux1_mem_readb(ret);
- return ret;
-}
-
-static const MemoryRegionOps slavio_aux1_mem_ops = {
- .read = slavio_aux1_mem_readb,
- .write = slavio_aux1_mem_writeb,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
-};
-
-static void slavio_aux2_mem_writeb(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- MiscState *s = opaque;
-
- val &= AUX2_PWRINTCLR | AUX2_PWROFF;
- trace_slavio_aux2_mem_writeb(val & 0xff);
- val |= s->aux2 & AUX2_PWRFAIL;
- if (val & AUX2_PWRINTCLR) // Clear Power Fail int
- val &= AUX2_PWROFF;
- s->aux2 = val;
- if (val & AUX2_PWROFF)
- qemu_system_shutdown_request();
- slavio_misc_update_irq(s);
-}
-
-static uint64_t slavio_aux2_mem_readb(void *opaque, hwaddr addr,
- unsigned size)
-{
- MiscState *s = opaque;
- uint32_t ret = 0;
-
- ret = s->aux2;
- trace_slavio_aux2_mem_readb(ret);
- return ret;
-}
-
-static const MemoryRegionOps slavio_aux2_mem_ops = {
- .read = slavio_aux2_mem_readb,
- .write = slavio_aux2_mem_writeb,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
-};
-
-static void apc_mem_writeb(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- APCState *s = opaque;
-
- trace_apc_mem_writeb(val & 0xff);
- qemu_irq_raise(s->cpu_halt);
-}
-
-static uint64_t apc_mem_readb(void *opaque, hwaddr addr,
- unsigned size)
-{
- uint32_t ret = 0;
-
- trace_apc_mem_readb(ret);
- return ret;
-}
-
-static const MemoryRegionOps apc_mem_ops = {
- .read = apc_mem_readb,
- .write = apc_mem_writeb,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 1,
- .max_access_size = 1,
- }
-};
-
-static uint64_t slavio_sysctrl_mem_readl(void *opaque, hwaddr addr,
- unsigned size)
-{
- MiscState *s = opaque;
- uint32_t ret = 0;
-
- switch (addr) {
- case 0:
- ret = s->sysctrl;
- break;
- default:
- break;
- }
- trace_slavio_sysctrl_mem_readl(ret);
- return ret;
-}
-
-static void slavio_sysctrl_mem_writel(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- MiscState *s = opaque;
-
- trace_slavio_sysctrl_mem_writel(val);
- switch (addr) {
- case 0:
- if (val & SYS_RESET) {
- s->sysctrl = SYS_RESETSTAT;
- qemu_system_reset_request();
- }
- break;
- default:
- break;
- }
-}
-
-static const MemoryRegionOps slavio_sysctrl_mem_ops = {
- .read = slavio_sysctrl_mem_readl,
- .write = slavio_sysctrl_mem_writel,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static uint64_t slavio_led_mem_readw(void *opaque, hwaddr addr,
- unsigned size)
-{
- MiscState *s = opaque;
- uint32_t ret = 0;
-
- switch (addr) {
- case 0:
- ret = s->leds;
- break;
- default:
- break;
- }
- trace_slavio_led_mem_readw(ret);
- return ret;
-}
-
-static void slavio_led_mem_writew(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- MiscState *s = opaque;
-
- trace_slavio_led_mem_writew(val & 0xffff);
- switch (addr) {
- case 0:
- s->leds = val;
- break;
- default:
- break;
- }
-}
-
-static const MemoryRegionOps slavio_led_mem_ops = {
- .read = slavio_led_mem_readw,
- .write = slavio_led_mem_writew,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 2,
- .max_access_size = 2,
- },
-};
-
-static const VMStateDescription vmstate_misc = {
- .name ="slavio_misc",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(dummy, MiscState),
- VMSTATE_UINT8(config, MiscState),
- VMSTATE_UINT8(aux1, MiscState),
- VMSTATE_UINT8(aux2, MiscState),
- VMSTATE_UINT8(diag, MiscState),
- VMSTATE_UINT8(mctrl, MiscState),
- VMSTATE_UINT8(sysctrl, MiscState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static int apc_init1(SysBusDevice *dev)
-{
- APCState *s = APC(dev);
-
- sysbus_init_irq(dev, &s->cpu_halt);
-
- /* Power management (APC) XXX: not a Slavio device */
- memory_region_init_io(&s->iomem, OBJECT(s), &apc_mem_ops, s,
- "apc", MISC_SIZE);
- sysbus_init_mmio(dev, &s->iomem);
- return 0;
-}
-
-static int slavio_misc_init1(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- MiscState *s = SLAVIO_MISC(dev);
-
- sysbus_init_irq(sbd, &s->irq);
- sysbus_init_irq(sbd, &s->fdc_tc);
-
- /* 8 bit registers */
- /* Slavio control */
- memory_region_init_io(&s->cfg_iomem, OBJECT(s), &slavio_cfg_mem_ops, s,
- "configuration", MISC_SIZE);
- sysbus_init_mmio(sbd, &s->cfg_iomem);
-
- /* Diagnostics */
- memory_region_init_io(&s->diag_iomem, OBJECT(s), &slavio_diag_mem_ops, s,
- "diagnostic", MISC_SIZE);
- sysbus_init_mmio(sbd, &s->diag_iomem);
-
- /* Modem control */
- memory_region_init_io(&s->mdm_iomem, OBJECT(s), &slavio_mdm_mem_ops, s,
- "modem", MISC_SIZE);
- sysbus_init_mmio(sbd, &s->mdm_iomem);
-
- /* 16 bit registers */
- /* ss600mp diag LEDs */
- memory_region_init_io(&s->led_iomem, OBJECT(s), &slavio_led_mem_ops, s,
- "leds", LED_SIZE);
- sysbus_init_mmio(sbd, &s->led_iomem);
-
- /* 32 bit registers */
- /* System control */
- memory_region_init_io(&s->sysctrl_iomem, OBJECT(s), &slavio_sysctrl_mem_ops, s,
- "system-control", SYSCTRL_SIZE);
- sysbus_init_mmio(sbd, &s->sysctrl_iomem);
-
- /* AUX 1 (Misc System Functions) */
- memory_region_init_io(&s->aux1_iomem, OBJECT(s), &slavio_aux1_mem_ops, s,
- "misc-system-functions", MISC_SIZE);
- sysbus_init_mmio(sbd, &s->aux1_iomem);
-
- /* AUX 2 (Software Powerdown Control) */
- memory_region_init_io(&s->aux2_iomem, OBJECT(s), &slavio_aux2_mem_ops, s,
- "software-powerdown-control", MISC_SIZE);
- sysbus_init_mmio(sbd, &s->aux2_iomem);
-
- qdev_init_gpio_in(dev, slavio_set_power_fail, 1);
-
- return 0;
-}
-
-static void slavio_misc_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = slavio_misc_init1;
- dc->reset = slavio_misc_reset;
- dc->vmsd = &vmstate_misc;
-}
-
-static const TypeInfo slavio_misc_info = {
- .name = TYPE_SLAVIO_MISC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(MiscState),
- .class_init = slavio_misc_class_init,
-};
-
-static void apc_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = apc_init1;
-}
-
-static const TypeInfo apc_info = {
- .name = TYPE_APC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(MiscState),
- .class_init = apc_class_init,
-};
-
-static void slavio_misc_register_types(void)
-{
- type_register_static(&slavio_misc_info);
- type_register_static(&apc_info);
-}
-
-type_init(slavio_misc_register_types)
diff --git a/qemu/hw/misc/stm32f2xx_syscfg.c b/qemu/hw/misc/stm32f2xx_syscfg.c
deleted file mode 100644
index d0d7076ef..000000000
--- a/qemu/hw/misc/stm32f2xx_syscfg.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * STM32F2XX SYSCFG
- *
- * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/misc/stm32f2xx_syscfg.h"
-
-#ifndef STM_SYSCFG_ERR_DEBUG
-#define STM_SYSCFG_ERR_DEBUG 0
-#endif
-
-#define DB_PRINT_L(lvl, fmt, args...) do { \
- if (STM_SYSCFG_ERR_DEBUG >= lvl) { \
- qemu_log("%s: " fmt, __func__, ## args); \
- } \
-} while (0);
-
-#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args)
-
-static void stm32f2xx_syscfg_reset(DeviceState *dev)
-{
- STM32F2XXSyscfgState *s = STM32F2XX_SYSCFG(dev);
-
- s->syscfg_memrmp = 0x00000000;
- s->syscfg_pmc = 0x00000000;
- s->syscfg_exticr1 = 0x00000000;
- s->syscfg_exticr2 = 0x00000000;
- s->syscfg_exticr3 = 0x00000000;
- s->syscfg_exticr4 = 0x00000000;
- s->syscfg_cmpcr = 0x00000000;
-}
-
-static uint64_t stm32f2xx_syscfg_read(void *opaque, hwaddr addr,
- unsigned int size)
-{
- STM32F2XXSyscfgState *s = opaque;
-
- DB_PRINT("0x%"HWADDR_PRIx"\n", addr);
-
- switch (addr) {
- case SYSCFG_MEMRMP:
- return s->syscfg_memrmp;
- case SYSCFG_PMC:
- return s->syscfg_pmc;
- case SYSCFG_EXTICR1:
- return s->syscfg_exticr1;
- case SYSCFG_EXTICR2:
- return s->syscfg_exticr2;
- case SYSCFG_EXTICR3:
- return s->syscfg_exticr3;
- case SYSCFG_EXTICR4:
- return s->syscfg_exticr4;
- case SYSCFG_CMPCR:
- return s->syscfg_cmpcr;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
- return 0;
- }
-
- return 0;
-}
-
-static void stm32f2xx_syscfg_write(void *opaque, hwaddr addr,
- uint64_t val64, unsigned int size)
-{
- STM32F2XXSyscfgState *s = opaque;
- uint32_t value = val64;
-
- DB_PRINT("0x%x, 0x%"HWADDR_PRIx"\n", value, addr);
-
- switch (addr) {
- case SYSCFG_MEMRMP:
- qemu_log_mask(LOG_UNIMP,
- "%s: Changeing the memory mapping isn't supported " \
- "in QEMU\n", __func__);
- return;
- case SYSCFG_PMC:
- qemu_log_mask(LOG_UNIMP,
- "%s: Changeing the memory mapping isn't supported " \
- "in QEMU\n", __func__);
- return;
- case SYSCFG_EXTICR1:
- s->syscfg_exticr1 = (value & 0xFFFF);
- return;
- case SYSCFG_EXTICR2:
- s->syscfg_exticr2 = (value & 0xFFFF);
- return;
- case SYSCFG_EXTICR3:
- s->syscfg_exticr3 = (value & 0xFFFF);
- return;
- case SYSCFG_EXTICR4:
- s->syscfg_exticr4 = (value & 0xFFFF);
- return;
- case SYSCFG_CMPCR:
- s->syscfg_cmpcr = value;
- return;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
- }
-}
-
-static const MemoryRegionOps stm32f2xx_syscfg_ops = {
- .read = stm32f2xx_syscfg_read,
- .write = stm32f2xx_syscfg_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void stm32f2xx_syscfg_init(Object *obj)
-{
- STM32F2XXSyscfgState *s = STM32F2XX_SYSCFG(obj);
-
- sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
-
- memory_region_init_io(&s->mmio, obj, &stm32f2xx_syscfg_ops, s,
- TYPE_STM32F2XX_SYSCFG, 0x400);
- sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
-}
-
-static void stm32f2xx_syscfg_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->reset = stm32f2xx_syscfg_reset;
-}
-
-static const TypeInfo stm32f2xx_syscfg_info = {
- .name = TYPE_STM32F2XX_SYSCFG,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(STM32F2XXSyscfgState),
- .instance_init = stm32f2xx_syscfg_init,
- .class_init = stm32f2xx_syscfg_class_init,
-};
-
-static void stm32f2xx_syscfg_register_types(void)
-{
- type_register_static(&stm32f2xx_syscfg_info);
-}
-
-type_init(stm32f2xx_syscfg_register_types)
diff --git a/qemu/hw/misc/tmp105.c b/qemu/hw/misc/tmp105.c
deleted file mode 100644
index f5c2472b5..000000000
--- a/qemu/hw/misc/tmp105.c
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * Texas Instruments TMP105 temperature sensor.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/i2c/i2c.h"
-#include "tmp105.h"
-#include "qapi/error.h"
-#include "qapi/visitor.h"
-
-static void tmp105_interrupt_update(TMP105State *s)
-{
- qemu_set_irq(s->pin, s->alarm ^ ((~s->config >> 2) & 1)); /* POL */
-}
-
-static void tmp105_alarm_update(TMP105State *s)
-{
- if ((s->config >> 0) & 1) { /* SD */
- if ((s->config >> 7) & 1) /* OS */
- s->config &= ~(1 << 7); /* OS */
- else
- return;
- }
-
- if ((s->config >> 1) & 1) { /* TM */
- if (s->temperature >= s->limit[1])
- s->alarm = 1;
- else if (s->temperature < s->limit[0])
- s->alarm = 1;
- } else {
- if (s->temperature >= s->limit[1])
- s->alarm = 1;
- else if (s->temperature < s->limit[0])
- s->alarm = 0;
- }
-
- tmp105_interrupt_update(s);
-}
-
-static void tmp105_get_temperature(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- TMP105State *s = TMP105(obj);
- int64_t value = s->temperature * 1000 / 256;
-
- visit_type_int(v, name, &value, errp);
-}
-
-/* Units are 0.001 centigrades relative to 0 C. s->temperature is 8.8
- * fixed point, so units are 1/256 centigrades. A simple ratio will do.
- */
-static void tmp105_set_temperature(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- TMP105State *s = TMP105(obj);
- Error *local_err = NULL;
- int64_t temp;
-
- visit_type_int(v, name, &temp, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
- if (temp >= 128000 || temp < -128000) {
- error_setg(errp, "value %" PRId64 ".%03" PRIu64 " °C is out of range",
- temp / 1000, temp % 1000);
- return;
- }
-
- s->temperature = (int16_t) (temp * 256 / 1000);
-
- tmp105_alarm_update(s);
-}
-
-static const int tmp105_faultq[4] = { 1, 2, 4, 6 };
-
-static void tmp105_read(TMP105State *s)
-{
- s->len = 0;
-
- if ((s->config >> 1) & 1) { /* TM */
- s->alarm = 0;
- tmp105_interrupt_update(s);
- }
-
- switch (s->pointer & 3) {
- case TMP105_REG_TEMPERATURE:
- s->buf[s->len ++] = (((uint16_t) s->temperature) >> 8);
- s->buf[s->len ++] = (((uint16_t) s->temperature) >> 0) &
- (0xf0 << ((~s->config >> 5) & 3)); /* R */
- break;
-
- case TMP105_REG_CONFIG:
- s->buf[s->len ++] = s->config;
- break;
-
- case TMP105_REG_T_LOW:
- s->buf[s->len ++] = ((uint16_t) s->limit[0]) >> 8;
- s->buf[s->len ++] = ((uint16_t) s->limit[0]) >> 0;
- break;
-
- case TMP105_REG_T_HIGH:
- s->buf[s->len ++] = ((uint16_t) s->limit[1]) >> 8;
- s->buf[s->len ++] = ((uint16_t) s->limit[1]) >> 0;
- break;
- }
-}
-
-static void tmp105_write(TMP105State *s)
-{
- switch (s->pointer & 3) {
- case TMP105_REG_TEMPERATURE:
- break;
-
- case TMP105_REG_CONFIG:
- if (s->buf[0] & ~s->config & (1 << 0)) /* SD */
- printf("%s: TMP105 shutdown\n", __FUNCTION__);
- s->config = s->buf[0];
- s->faults = tmp105_faultq[(s->config >> 3) & 3]; /* F */
- tmp105_alarm_update(s);
- break;
-
- case TMP105_REG_T_LOW:
- case TMP105_REG_T_HIGH:
- if (s->len >= 3)
- s->limit[s->pointer & 1] = (int16_t)
- ((((uint16_t) s->buf[0]) << 8) | s->buf[1]);
- tmp105_alarm_update(s);
- break;
- }
-}
-
-static int tmp105_rx(I2CSlave *i2c)
-{
- TMP105State *s = TMP105(i2c);
-
- if (s->len < 2) {
- return s->buf[s->len ++];
- } else {
- return 0xff;
- }
-}
-
-static int tmp105_tx(I2CSlave *i2c, uint8_t data)
-{
- TMP105State *s = TMP105(i2c);
-
- if (s->len == 0) {
- s->pointer = data;
- s->len++;
- } else {
- if (s->len <= 2) {
- s->buf[s->len - 1] = data;
- }
- s->len++;
- tmp105_write(s);
- }
-
- return 0;
-}
-
-static void tmp105_event(I2CSlave *i2c, enum i2c_event event)
-{
- TMP105State *s = TMP105(i2c);
-
- if (event == I2C_START_RECV) {
- tmp105_read(s);
- }
-
- s->len = 0;
-}
-
-static int tmp105_post_load(void *opaque, int version_id)
-{
- TMP105State *s = opaque;
-
- s->faults = tmp105_faultq[(s->config >> 3) & 3]; /* F */
-
- tmp105_interrupt_update(s);
- return 0;
-}
-
-static const VMStateDescription vmstate_tmp105 = {
- .name = "TMP105",
- .version_id = 0,
- .minimum_version_id = 0,
- .post_load = tmp105_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(len, TMP105State),
- VMSTATE_UINT8_ARRAY(buf, TMP105State, 2),
- VMSTATE_UINT8(pointer, TMP105State),
- VMSTATE_UINT8(config, TMP105State),
- VMSTATE_INT16(temperature, TMP105State),
- VMSTATE_INT16_ARRAY(limit, TMP105State, 2),
- VMSTATE_UINT8(alarm, TMP105State),
- VMSTATE_I2C_SLAVE(i2c, TMP105State),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void tmp105_reset(I2CSlave *i2c)
-{
- TMP105State *s = TMP105(i2c);
-
- s->temperature = 0;
- s->pointer = 0;
- s->config = 0;
- s->faults = tmp105_faultq[(s->config >> 3) & 3];
- s->alarm = 0;
-
- tmp105_interrupt_update(s);
-}
-
-static int tmp105_init(I2CSlave *i2c)
-{
- TMP105State *s = TMP105(i2c);
-
- qdev_init_gpio_out(&i2c->qdev, &s->pin, 1);
-
- tmp105_reset(&s->i2c);
-
- return 0;
-}
-
-static void tmp105_initfn(Object *obj)
-{
- object_property_add(obj, "temperature", "int",
- tmp105_get_temperature,
- tmp105_set_temperature, NULL, NULL, NULL);
-}
-
-static void tmp105_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
-
- k->init = tmp105_init;
- k->event = tmp105_event;
- k->recv = tmp105_rx;
- k->send = tmp105_tx;
- dc->vmsd = &vmstate_tmp105;
-}
-
-static const TypeInfo tmp105_info = {
- .name = TYPE_TMP105,
- .parent = TYPE_I2C_SLAVE,
- .instance_size = sizeof(TMP105State),
- .instance_init = tmp105_initfn,
- .class_init = tmp105_class_init,
-};
-
-static void tmp105_register_types(void)
-{
- type_register_static(&tmp105_info);
-}
-
-type_init(tmp105_register_types)
diff --git a/qemu/hw/misc/tmp105.h b/qemu/hw/misc/tmp105.h
deleted file mode 100644
index 9ba05ecc9..000000000
--- a/qemu/hw/misc/tmp105.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Texas Instruments TMP105 Temperature Sensor
- *
- * Browse the data sheet:
- *
- * http://www.ti.com/lit/gpn/tmp105
- *
- * Copyright (C) 2012 Alex Horn <alex.horn@cs.ox.ac.uk>
- * Copyright (C) 2008-2012 Andrzej Zaborowski <balrogg@gmail.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or
- * later. See the COPYING file in the top-level directory.
- */
-#ifndef QEMU_TMP105_H
-#define QEMU_TMP105_H
-
-#include "hw/i2c/i2c.h"
-#include "hw/misc/tmp105_regs.h"
-
-#define TYPE_TMP105 "tmp105"
-#define TMP105(obj) OBJECT_CHECK(TMP105State, (obj), TYPE_TMP105)
-
-/**
- * TMP105State:
- * @config: Bits 5 and 6 (value 32 and 64) determine the precision of the
- * temperature. See Table 8 in the data sheet.
- *
- * @see_also: http://www.ti.com/lit/gpn/tmp105
- */
-typedef struct TMP105State {
- /*< private >*/
- I2CSlave i2c;
- /*< public >*/
-
- uint8_t len;
- uint8_t buf[2];
- qemu_irq pin;
-
- uint8_t pointer;
- uint8_t config;
- int16_t temperature;
- int16_t limit[2];
- int faults;
- uint8_t alarm;
-} TMP105State;
-
-#endif
diff --git a/qemu/hw/misc/vmport.c b/qemu/hw/misc/vmport.c
deleted file mode 100644
index 689678980..000000000
--- a/qemu/hw/misc/vmport.c
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * QEMU VMPort emulation
- *
- * Copyright (C) 2007 Hervé Poussineau
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/isa/isa.h"
-#include "hw/i386/pc.h"
-#include "sysemu/kvm.h"
-#include "hw/qdev.h"
-
-//#define VMPORT_DEBUG
-
-#define VMPORT_CMD_GETVERSION 0x0a
-#define VMPORT_CMD_GETRAMSIZE 0x14
-
-#define VMPORT_ENTRIES 0x2c
-#define VMPORT_MAGIC 0x564D5868
-
-#define TYPE_VMPORT "vmport"
-#define VMPORT(obj) OBJECT_CHECK(VMPortState, (obj), TYPE_VMPORT)
-
-typedef struct VMPortState
-{
- ISADevice parent_obj;
-
- MemoryRegion io;
- VMPortReadFunc *func[VMPORT_ENTRIES];
- void *opaque[VMPORT_ENTRIES];
-} VMPortState;
-
-static VMPortState *port_state;
-
-void vmport_register(unsigned char command, VMPortReadFunc *func, void *opaque)
-{
- if (command >= VMPORT_ENTRIES)
- return;
-
- port_state->func[command] = func;
- port_state->opaque[command] = opaque;
-}
-
-static uint64_t vmport_ioport_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- VMPortState *s = opaque;
- CPUState *cs = current_cpu;
- X86CPU *cpu = X86_CPU(cs);
- CPUX86State *env = &cpu->env;
- unsigned char command;
- uint32_t eax;
-
- cpu_synchronize_state(cs);
-
- eax = env->regs[R_EAX];
- if (eax != VMPORT_MAGIC)
- return eax;
-
- command = env->regs[R_ECX];
- if (command >= VMPORT_ENTRIES)
- return eax;
- if (!s->func[command])
- {
-#ifdef VMPORT_DEBUG
- fprintf(stderr, "vmport: unknown command %x\n", command);
-#endif
- return eax;
- }
-
- return s->func[command](s->opaque[command], addr);
-}
-
-static void vmport_ioport_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- X86CPU *cpu = X86_CPU(current_cpu);
-
- cpu->env.regs[R_EAX] = vmport_ioport_read(opaque, addr, 4);
-}
-
-static uint32_t vmport_cmd_get_version(void *opaque, uint32_t addr)
-{
- X86CPU *cpu = X86_CPU(current_cpu);
-
- cpu->env.regs[R_EBX] = VMPORT_MAGIC;
- return 6;
-}
-
-static uint32_t vmport_cmd_ram_size(void *opaque, uint32_t addr)
-{
- X86CPU *cpu = X86_CPU(current_cpu);
-
- cpu->env.regs[R_EBX] = 0x1177;
- return ram_size;
-}
-
-/* vmmouse helpers */
-void vmmouse_get_data(uint32_t *data)
-{
- X86CPU *cpu = X86_CPU(current_cpu);
- CPUX86State *env = &cpu->env;
-
- data[0] = env->regs[R_EAX]; data[1] = env->regs[R_EBX];
- data[2] = env->regs[R_ECX]; data[3] = env->regs[R_EDX];
- data[4] = env->regs[R_ESI]; data[5] = env->regs[R_EDI];
-}
-
-void vmmouse_set_data(const uint32_t *data)
-{
- X86CPU *cpu = X86_CPU(current_cpu);
- CPUX86State *env = &cpu->env;
-
- env->regs[R_EAX] = data[0]; env->regs[R_EBX] = data[1];
- env->regs[R_ECX] = data[2]; env->regs[R_EDX] = data[3];
- env->regs[R_ESI] = data[4]; env->regs[R_EDI] = data[5];
-}
-
-static const MemoryRegionOps vmport_ops = {
- .read = vmport_ioport_read,
- .write = vmport_ioport_write,
- .impl = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void vmport_realizefn(DeviceState *dev, Error **errp)
-{
- ISADevice *isadev = ISA_DEVICE(dev);
- VMPortState *s = VMPORT(dev);
-
- memory_region_init_io(&s->io, OBJECT(s), &vmport_ops, s, "vmport", 1);
- isa_register_ioport(isadev, &s->io, 0x5658);
-
- port_state = s;
- /* Register some generic port commands */
- vmport_register(VMPORT_CMD_GETVERSION, vmport_cmd_get_version, NULL);
- vmport_register(VMPORT_CMD_GETRAMSIZE, vmport_cmd_ram_size, NULL);
-}
-
-static void vmport_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = vmport_realizefn;
- /* Reason: realize sets global port_state */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo vmport_info = {
- .name = TYPE_VMPORT,
- .parent = TYPE_ISA_DEVICE,
- .instance_size = sizeof(VMPortState),
- .class_init = vmport_class_initfn,
-};
-
-static void vmport_register_types(void)
-{
- type_register_static(&vmport_info);
-}
-
-type_init(vmport_register_types)
diff --git a/qemu/hw/misc/zynq-xadc.c b/qemu/hw/misc/zynq-xadc.c
deleted file mode 100644
index 71fbccd79..000000000
--- a/qemu/hw/misc/zynq-xadc.c
+++ /dev/null
@@ -1,303 +0,0 @@
-/*
- * ADC registers for Xilinx Zynq Platform
- *
- * Copyright (c) 2015 Guenter Roeck
- * Based on hw/misc/zynq_slcr.c, written by Michal Simek
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/misc/zynq-xadc.h"
-#include "qemu/timer.h"
-#include "sysemu/sysemu.h"
-
-enum {
- CFG = 0x000 / 4,
- INT_STS,
- INT_MASK,
- MSTS,
- CMDFIFO,
- RDFIFO,
- MCTL,
-};
-
-#define CFG_ENABLE BIT(31)
-#define CFG_CFIFOTH_SHIFT 20
-#define CFG_CFIFOTH_LENGTH 4
-#define CFG_DFIFOTH_SHIFT 16
-#define CFG_DFIFOTH_LENGTH 4
-#define CFG_WEDGE BIT(13)
-#define CFG_REDGE BIT(12)
-#define CFG_TCKRATE_SHIFT 8
-#define CFG_TCKRATE_LENGTH 2
-
-#define CFG_TCKRATE_DIV(x) (0x1 << (x - 1))
-
-#define CFG_IGAP_SHIFT 0
-#define CFG_IGAP_LENGTH 5
-
-#define INT_CFIFO_LTH BIT(9)
-#define INT_DFIFO_GTH BIT(8)
-#define INT_OT BIT(7)
-#define INT_ALM_SHIFT 0
-#define INT_ALM_LENGTH 7
-#define INT_ALM_MASK (((1 << INT_ALM_LENGTH) - 1) << INT_ALM_SHIFT)
-
-#define INT_ALL (INT_CFIFO_LTH | INT_DFIFO_GTH | INT_OT | INT_ALM_MASK)
-
-#define MSTS_CFIFO_LVL_SHIFT 16
-#define MSTS_CFIFO_LVL_LENGTH 4
-#define MSTS_DFIFO_LVL_SHIFT 12
-#define MSTS_DFIFO_LVL_LENGTH 4
-#define MSTS_CFIFOF BIT(11)
-#define MSTS_CFIFOE BIT(10)
-#define MSTS_DFIFOF BIT(9)
-#define MSTS_DFIFOE BIT(8)
-#define MSTS_OT BIT(7)
-#define MSTS_ALM_SHIFT 0
-#define MSTS_ALM_LENGTH 7
-
-#define MCTL_RESET BIT(4)
-
-#define CMD_NOP 0x00
-#define CMD_READ 0x01
-#define CMD_WRITE 0x02
-
-static void zynq_xadc_update_ints(ZynqXADCState *s)
-{
-
- /* We are fast, commands are actioned instantly so the CFIFO is always
- * empty (and below threshold).
- */
- s->regs[INT_STS] |= INT_CFIFO_LTH;
-
- if (s->xadc_dfifo_entries >
- extract32(s->regs[CFG], CFG_DFIFOTH_SHIFT, CFG_DFIFOTH_LENGTH)) {
- s->regs[INT_STS] |= INT_DFIFO_GTH;
- }
-
- qemu_set_irq(s->qemu_irq, !!(s->regs[INT_STS] & ~s->regs[INT_MASK]));
-}
-
-static void zynq_xadc_reset(DeviceState *d)
-{
- ZynqXADCState *s = ZYNQ_XADC(d);
-
- s->regs[CFG] = 0x14 << CFG_IGAP_SHIFT |
- CFG_TCKRATE_DIV(4) << CFG_TCKRATE_SHIFT | CFG_REDGE;
- s->regs[INT_STS] = INT_CFIFO_LTH;
- s->regs[INT_MASK] = 0xffffffff;
- s->regs[CMDFIFO] = 0;
- s->regs[RDFIFO] = 0;
- s->regs[MCTL] = MCTL_RESET;
-
- memset(s->xadc_regs, 0, sizeof(s->xadc_regs));
- memset(s->xadc_dfifo, 0, sizeof(s->xadc_dfifo));
- s->xadc_dfifo_entries = 0;
-
- zynq_xadc_update_ints(s);
-}
-
-static uint16_t xadc_pop_dfifo(ZynqXADCState *s)
-{
- uint16_t rv = s->xadc_dfifo[0];
- int i;
-
- if (s->xadc_dfifo_entries > 0) {
- s->xadc_dfifo_entries--;
- }
- for (i = 0; i < s->xadc_dfifo_entries; i++) {
- s->xadc_dfifo[i] = s->xadc_dfifo[i + 1];
- }
- s->xadc_dfifo[s->xadc_dfifo_entries] = 0;
- zynq_xadc_update_ints(s);
- return rv;
-}
-
-static void xadc_push_dfifo(ZynqXADCState *s, uint16_t regval)
-{
- if (s->xadc_dfifo_entries < ZYNQ_XADC_FIFO_DEPTH) {
- s->xadc_dfifo[s->xadc_dfifo_entries++] = s->xadc_read_reg_previous;
- }
- s->xadc_read_reg_previous = regval;
- zynq_xadc_update_ints(s);
-}
-
-static bool zynq_xadc_check_offset(hwaddr offset, bool rnw)
-{
- switch (offset) {
- case CFG:
- case INT_MASK:
- case INT_STS:
- case MCTL:
- return true;
- case RDFIFO:
- case MSTS:
- return rnw; /* read only */
- case CMDFIFO:
- return !rnw; /* write only */
- default:
- return false;
- }
-}
-
-static uint64_t zynq_xadc_read(void *opaque, hwaddr offset, unsigned size)
-{
- ZynqXADCState *s = opaque;
- int reg = offset / 4;
- uint32_t rv = 0;
-
- if (!zynq_xadc_check_offset(reg, true)) {
- qemu_log_mask(LOG_GUEST_ERROR, "zynq_xadc: Invalid read access to "
- "addr %" HWADDR_PRIx "\n", offset);
- return 0;
- }
-
- switch (reg) {
- case CFG:
- case INT_MASK:
- case INT_STS:
- case MCTL:
- rv = s->regs[reg];
- break;
- case MSTS:
- rv = MSTS_CFIFOE;
- rv |= s->xadc_dfifo_entries << MSTS_DFIFO_LVL_SHIFT;
- if (!s->xadc_dfifo_entries) {
- rv |= MSTS_DFIFOE;
- } else if (s->xadc_dfifo_entries == ZYNQ_XADC_FIFO_DEPTH) {
- rv |= MSTS_DFIFOF;
- }
- break;
- case RDFIFO:
- rv = xadc_pop_dfifo(s);
- break;
- }
- return rv;
-}
-
-static void zynq_xadc_write(void *opaque, hwaddr offset, uint64_t val,
- unsigned size)
-{
- ZynqXADCState *s = (ZynqXADCState *)opaque;
- int reg = offset / 4;
- int xadc_reg;
- int xadc_cmd;
- int xadc_data;
-
- if (!zynq_xadc_check_offset(reg, false)) {
- qemu_log_mask(LOG_GUEST_ERROR, "zynq_xadc: Invalid write access "
- "to addr %" HWADDR_PRIx "\n", offset);
- return;
- }
-
- switch (reg) {
- case CFG:
- s->regs[CFG] = val;
- break;
- case INT_STS:
- s->regs[INT_STS] &= ~val;
- break;
- case INT_MASK:
- s->regs[INT_MASK] = val & INT_ALL;
- break;
- case CMDFIFO:
- xadc_cmd = extract32(val, 26, 4);
- xadc_reg = extract32(val, 16, 10);
- xadc_data = extract32(val, 0, 16);
-
- if (s->regs[MCTL] & MCTL_RESET) {
- qemu_log_mask(LOG_GUEST_ERROR, "zynq_xadc: Sending command "
- "while comm channel held in reset: %" PRIx32 "\n",
- (uint32_t) val);
- break;
- }
-
- if (xadc_reg >= ZYNQ_XADC_NUM_ADC_REGS && xadc_cmd != CMD_NOP) {
- qemu_log_mask(LOG_GUEST_ERROR, "read/write op to invalid xadc "
- "reg 0x%x\n", xadc_reg);
- break;
- }
-
- switch (xadc_cmd) {
- case CMD_READ:
- xadc_push_dfifo(s, s->xadc_regs[xadc_reg]);
- break;
- case CMD_WRITE:
- s->xadc_regs[xadc_reg] = xadc_data;
- /* fallthrough */
- case CMD_NOP:
- xadc_push_dfifo(s, 0);
- break;
- }
- break;
- case MCTL:
- s->regs[MCTL] = val & 0x00fffeff;
- break;
- }
- zynq_xadc_update_ints(s);
-}
-
-static const MemoryRegionOps xadc_ops = {
- .read = zynq_xadc_read,
- .write = zynq_xadc_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void zynq_xadc_init(Object *obj)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- ZynqXADCState *s = ZYNQ_XADC(obj);
-
- memory_region_init_io(&s->iomem, obj, &xadc_ops, s, "zynq-xadc",
- ZYNQ_XADC_MMIO_SIZE);
- sysbus_init_mmio(sbd, &s->iomem);
- sysbus_init_irq(sbd, &s->qemu_irq);
-}
-
-static const VMStateDescription vmstate_zynq_xadc = {
- .name = "zynq-xadc",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, ZynqXADCState, ZYNQ_XADC_NUM_IO_REGS),
- VMSTATE_UINT16_ARRAY(xadc_regs, ZynqXADCState,
- ZYNQ_XADC_NUM_ADC_REGS),
- VMSTATE_UINT16_ARRAY(xadc_dfifo, ZynqXADCState,
- ZYNQ_XADC_FIFO_DEPTH),
- VMSTATE_UINT16(xadc_read_reg_previous, ZynqXADCState),
- VMSTATE_UINT16(xadc_dfifo_entries, ZynqXADCState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void zynq_xadc_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->vmsd = &vmstate_zynq_xadc;
- dc->reset = zynq_xadc_reset;
-}
-
-static const TypeInfo zynq_xadc_info = {
- .class_init = zynq_xadc_class_init,
- .name = TYPE_ZYNQ_XADC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(ZynqXADCState),
- .instance_init = zynq_xadc_init,
-};
-
-static void zynq_xadc_register_types(void)
-{
- type_register_static(&zynq_xadc_info);
-}
-
-type_init(zynq_xadc_register_types)
diff --git a/qemu/hw/misc/zynq_slcr.c b/qemu/hw/misc/zynq_slcr.c
deleted file mode 100644
index b1b7591ef..000000000
--- a/qemu/hw/misc/zynq_slcr.c
+++ /dev/null
@@ -1,459 +0,0 @@
-/*
- * Status and system control registers for Xilinx Zynq Platform
- *
- * Copyright (c) 2011 Michal Simek <monstr@monstr.eu>
- * Copyright (c) 2012 PetaLogix Pty Ltd.
- * Based on hw/arm_sysctl.c, written by Paul Brook
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "qemu/timer.h"
-#include "hw/sysbus.h"
-#include "sysemu/sysemu.h"
-
-#ifndef ZYNQ_SLCR_ERR_DEBUG
-#define ZYNQ_SLCR_ERR_DEBUG 0
-#endif
-
-#define DB_PRINT(...) do { \
- if (ZYNQ_SLCR_ERR_DEBUG) { \
- fprintf(stderr, ": %s: ", __func__); \
- fprintf(stderr, ## __VA_ARGS__); \
- } \
- } while (0);
-
-#define XILINX_LOCK_KEY 0x767b
-#define XILINX_UNLOCK_KEY 0xdf0d
-
-#define R_PSS_RST_CTRL_SOFT_RST 0x1
-
-enum {
- SCL = 0x000 / 4,
- LOCK,
- UNLOCK,
- LOCKSTA,
-
- ARM_PLL_CTRL = 0x100 / 4,
- DDR_PLL_CTRL,
- IO_PLL_CTRL,
- PLL_STATUS,
- ARM_PLL_CFG,
- DDR_PLL_CFG,
- IO_PLL_CFG,
-
- ARM_CLK_CTRL = 0x120 / 4,
- DDR_CLK_CTRL,
- DCI_CLK_CTRL,
- APER_CLK_CTRL,
- USB0_CLK_CTRL,
- USB1_CLK_CTRL,
- GEM0_RCLK_CTRL,
- GEM1_RCLK_CTRL,
- GEM0_CLK_CTRL,
- GEM1_CLK_CTRL,
- SMC_CLK_CTRL,
- LQSPI_CLK_CTRL,
- SDIO_CLK_CTRL,
- UART_CLK_CTRL,
- SPI_CLK_CTRL,
- CAN_CLK_CTRL,
- CAN_MIOCLK_CTRL,
- DBG_CLK_CTRL,
- PCAP_CLK_CTRL,
- TOPSW_CLK_CTRL,
-
-#define FPGA_CTRL_REGS(n, start) \
- FPGA ## n ## _CLK_CTRL = (start) / 4, \
- FPGA ## n ## _THR_CTRL, \
- FPGA ## n ## _THR_CNT, \
- FPGA ## n ## _THR_STA,
- FPGA_CTRL_REGS(0, 0x170)
- FPGA_CTRL_REGS(1, 0x180)
- FPGA_CTRL_REGS(2, 0x190)
- FPGA_CTRL_REGS(3, 0x1a0)
-
- BANDGAP_TRIP = 0x1b8 / 4,
- PLL_PREDIVISOR = 0x1c0 / 4,
- CLK_621_TRUE,
-
- PSS_RST_CTRL = 0x200 / 4,
- DDR_RST_CTRL,
- TOPSW_RESET_CTRL,
- DMAC_RST_CTRL,
- USB_RST_CTRL,
- GEM_RST_CTRL,
- SDIO_RST_CTRL,
- SPI_RST_CTRL,
- CAN_RST_CTRL,
- I2C_RST_CTRL,
- UART_RST_CTRL,
- GPIO_RST_CTRL,
- LQSPI_RST_CTRL,
- SMC_RST_CTRL,
- OCM_RST_CTRL,
- FPGA_RST_CTRL = 0x240 / 4,
- A9_CPU_RST_CTRL,
-
- RS_AWDT_CTRL = 0x24c / 4,
- RST_REASON,
-
- REBOOT_STATUS = 0x258 / 4,
- BOOT_MODE,
-
- APU_CTRL = 0x300 / 4,
- WDT_CLK_SEL,
-
- TZ_DMA_NS = 0x440 / 4,
- TZ_DMA_IRQ_NS,
- TZ_DMA_PERIPH_NS,
-
- PSS_IDCODE = 0x530 / 4,
-
- DDR_URGENT = 0x600 / 4,
- DDR_CAL_START = 0x60c / 4,
- DDR_REF_START = 0x614 / 4,
- DDR_CMD_STA,
- DDR_URGENT_SEL,
- DDR_DFI_STATUS,
-
- MIO = 0x700 / 4,
-#define MIO_LENGTH 54
-
- MIO_LOOPBACK = 0x804 / 4,
- MIO_MST_TRI0,
- MIO_MST_TRI1,
-
- SD0_WP_CD_SEL = 0x830 / 4,
- SD1_WP_CD_SEL,
-
- LVL_SHFTR_EN = 0x900 / 4,
- OCM_CFG = 0x910 / 4,
-
- CPU_RAM = 0xa00 / 4,
-
- IOU = 0xa30 / 4,
-
- DMAC_RAM = 0xa50 / 4,
-
- AFI0 = 0xa60 / 4,
- AFI1 = AFI0 + 3,
- AFI2 = AFI1 + 3,
- AFI3 = AFI2 + 3,
-#define AFI_LENGTH 3
-
- OCM = 0xa90 / 4,
-
- DEVCI_RAM = 0xaa0 / 4,
-
- CSG_RAM = 0xab0 / 4,
-
- GPIOB_CTRL = 0xb00 / 4,
- GPIOB_CFG_CMOS18,
- GPIOB_CFG_CMOS25,
- GPIOB_CFG_CMOS33,
- GPIOB_CFG_HSTL = 0xb14 / 4,
- GPIOB_DRVR_BIAS_CTRL,
-
- DDRIOB = 0xb40 / 4,
-#define DDRIOB_LENGTH 14
-};
-
-#define ZYNQ_SLCR_MMIO_SIZE 0x1000
-#define ZYNQ_SLCR_NUM_REGS (ZYNQ_SLCR_MMIO_SIZE / 4)
-
-#define TYPE_ZYNQ_SLCR "xilinx,zynq_slcr"
-#define ZYNQ_SLCR(obj) OBJECT_CHECK(ZynqSLCRState, (obj), TYPE_ZYNQ_SLCR)
-
-typedef struct ZynqSLCRState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
-
- uint32_t regs[ZYNQ_SLCR_NUM_REGS];
-} ZynqSLCRState;
-
-static void zynq_slcr_reset(DeviceState *d)
-{
- ZynqSLCRState *s = ZYNQ_SLCR(d);
- int i;
-
- DB_PRINT("RESET\n");
-
- s->regs[LOCKSTA] = 1;
- /* 0x100 - 0x11C */
- s->regs[ARM_PLL_CTRL] = 0x0001A008;
- s->regs[DDR_PLL_CTRL] = 0x0001A008;
- s->regs[IO_PLL_CTRL] = 0x0001A008;
- s->regs[PLL_STATUS] = 0x0000003F;
- s->regs[ARM_PLL_CFG] = 0x00014000;
- s->regs[DDR_PLL_CFG] = 0x00014000;
- s->regs[IO_PLL_CFG] = 0x00014000;
-
- /* 0x120 - 0x16C */
- s->regs[ARM_CLK_CTRL] = 0x1F000400;
- s->regs[DDR_CLK_CTRL] = 0x18400003;
- s->regs[DCI_CLK_CTRL] = 0x01E03201;
- s->regs[APER_CLK_CTRL] = 0x01FFCCCD;
- s->regs[USB0_CLK_CTRL] = s->regs[USB1_CLK_CTRL] = 0x00101941;
- s->regs[GEM0_RCLK_CTRL] = s->regs[GEM1_RCLK_CTRL] = 0x00000001;
- s->regs[GEM0_CLK_CTRL] = s->regs[GEM1_CLK_CTRL] = 0x00003C01;
- s->regs[SMC_CLK_CTRL] = 0x00003C01;
- s->regs[LQSPI_CLK_CTRL] = 0x00002821;
- s->regs[SDIO_CLK_CTRL] = 0x00001E03;
- s->regs[UART_CLK_CTRL] = 0x00003F03;
- s->regs[SPI_CLK_CTRL] = 0x00003F03;
- s->regs[CAN_CLK_CTRL] = 0x00501903;
- s->regs[DBG_CLK_CTRL] = 0x00000F03;
- s->regs[PCAP_CLK_CTRL] = 0x00000F01;
-
- /* 0x170 - 0x1AC */
- s->regs[FPGA0_CLK_CTRL] = s->regs[FPGA1_CLK_CTRL] = s->regs[FPGA2_CLK_CTRL]
- = s->regs[FPGA3_CLK_CTRL] = 0x00101800;
- s->regs[FPGA0_THR_STA] = s->regs[FPGA1_THR_STA] = s->regs[FPGA2_THR_STA]
- = s->regs[FPGA3_THR_STA] = 0x00010000;
-
- /* 0x1B0 - 0x1D8 */
- s->regs[BANDGAP_TRIP] = 0x0000001F;
- s->regs[PLL_PREDIVISOR] = 0x00000001;
- s->regs[CLK_621_TRUE] = 0x00000001;
-
- /* 0x200 - 0x25C */
- s->regs[FPGA_RST_CTRL] = 0x01F33F0F;
- s->regs[RST_REASON] = 0x00000040;
-
- s->regs[BOOT_MODE] = 0x00000001;
-
- /* 0x700 - 0x7D4 */
- for (i = 0; i < 54; i++) {
- s->regs[MIO + i] = 0x00001601;
- }
- for (i = 2; i <= 8; i++) {
- s->regs[MIO + i] = 0x00000601;
- }
-
- s->regs[MIO_MST_TRI0] = s->regs[MIO_MST_TRI1] = 0xFFFFFFFF;
-
- s->regs[CPU_RAM + 0] = s->regs[CPU_RAM + 1] = s->regs[CPU_RAM + 3]
- = s->regs[CPU_RAM + 4] = s->regs[CPU_RAM + 7]
- = 0x00010101;
- s->regs[CPU_RAM + 2] = s->regs[CPU_RAM + 5] = 0x01010101;
- s->regs[CPU_RAM + 6] = 0x00000001;
-
- s->regs[IOU + 0] = s->regs[IOU + 1] = s->regs[IOU + 2] = s->regs[IOU + 3]
- = 0x09090909;
- s->regs[IOU + 4] = s->regs[IOU + 5] = 0x00090909;
- s->regs[IOU + 6] = 0x00000909;
-
- s->regs[DMAC_RAM] = 0x00000009;
-
- s->regs[AFI0 + 0] = s->regs[AFI0 + 1] = 0x09090909;
- s->regs[AFI1 + 0] = s->regs[AFI1 + 1] = 0x09090909;
- s->regs[AFI2 + 0] = s->regs[AFI2 + 1] = 0x09090909;
- s->regs[AFI3 + 0] = s->regs[AFI3 + 1] = 0x09090909;
- s->regs[AFI0 + 2] = s->regs[AFI1 + 2] = s->regs[AFI2 + 2]
- = s->regs[AFI3 + 2] = 0x00000909;
-
- s->regs[OCM + 0] = 0x01010101;
- s->regs[OCM + 1] = s->regs[OCM + 2] = 0x09090909;
-
- s->regs[DEVCI_RAM] = 0x00000909;
- s->regs[CSG_RAM] = 0x00000001;
-
- s->regs[DDRIOB + 0] = s->regs[DDRIOB + 1] = s->regs[DDRIOB + 2]
- = s->regs[DDRIOB + 3] = 0x00000e00;
- s->regs[DDRIOB + 4] = s->regs[DDRIOB + 5] = s->regs[DDRIOB + 6]
- = 0x00000e00;
- s->regs[DDRIOB + 12] = 0x00000021;
-}
-
-
-static bool zynq_slcr_check_offset(hwaddr offset, bool rnw)
-{
- switch (offset) {
- case LOCK:
- case UNLOCK:
- case DDR_CAL_START:
- case DDR_REF_START:
- return !rnw; /* Write only */
- case LOCKSTA:
- case FPGA0_THR_STA:
- case FPGA1_THR_STA:
- case FPGA2_THR_STA:
- case FPGA3_THR_STA:
- case BOOT_MODE:
- case PSS_IDCODE:
- case DDR_CMD_STA:
- case DDR_DFI_STATUS:
- case PLL_STATUS:
- return rnw;/* read only */
- case SCL:
- case ARM_PLL_CTRL ... IO_PLL_CTRL:
- case ARM_PLL_CFG ... IO_PLL_CFG:
- case ARM_CLK_CTRL ... TOPSW_CLK_CTRL:
- case FPGA0_CLK_CTRL ... FPGA0_THR_CNT:
- case FPGA1_CLK_CTRL ... FPGA1_THR_CNT:
- case FPGA2_CLK_CTRL ... FPGA2_THR_CNT:
- case FPGA3_CLK_CTRL ... FPGA3_THR_CNT:
- case BANDGAP_TRIP:
- case PLL_PREDIVISOR:
- case CLK_621_TRUE:
- case PSS_RST_CTRL ... A9_CPU_RST_CTRL:
- case RS_AWDT_CTRL:
- case RST_REASON:
- case REBOOT_STATUS:
- case APU_CTRL:
- case WDT_CLK_SEL:
- case TZ_DMA_NS ... TZ_DMA_PERIPH_NS:
- case DDR_URGENT:
- case DDR_URGENT_SEL:
- case MIO ... MIO + MIO_LENGTH - 1:
- case MIO_LOOPBACK ... MIO_MST_TRI1:
- case SD0_WP_CD_SEL:
- case SD1_WP_CD_SEL:
- case LVL_SHFTR_EN:
- case OCM_CFG:
- case CPU_RAM:
- case IOU:
- case DMAC_RAM:
- case AFI0 ... AFI3 + AFI_LENGTH - 1:
- case OCM:
- case DEVCI_RAM:
- case CSG_RAM:
- case GPIOB_CTRL ... GPIOB_CFG_CMOS33:
- case GPIOB_CFG_HSTL:
- case GPIOB_DRVR_BIAS_CTRL:
- case DDRIOB ... DDRIOB + DDRIOB_LENGTH - 1:
- return true;
- default:
- return false;
- }
-}
-
-static uint64_t zynq_slcr_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- ZynqSLCRState *s = opaque;
- offset /= 4;
- uint32_t ret = s->regs[offset];
-
- if (!zynq_slcr_check_offset(offset, true)) {
- qemu_log_mask(LOG_GUEST_ERROR, "zynq_slcr: Invalid read access to "
- " addr %" HWADDR_PRIx "\n", offset * 4);
- }
-
- DB_PRINT("addr: %08" HWADDR_PRIx " data: %08" PRIx32 "\n", offset * 4, ret);
- return ret;
-}
-
-static void zynq_slcr_write(void *opaque, hwaddr offset,
- uint64_t val, unsigned size)
-{
- ZynqSLCRState *s = (ZynqSLCRState *)opaque;
- offset /= 4;
-
- DB_PRINT("addr: %08" HWADDR_PRIx " data: %08" PRIx64 "\n", offset * 4, val);
-
- if (!zynq_slcr_check_offset(offset, false)) {
- qemu_log_mask(LOG_GUEST_ERROR, "zynq_slcr: Invalid write access to "
- "addr %" HWADDR_PRIx "\n", offset * 4);
- return;
- }
-
- switch (offset) {
- case SCL:
- s->regs[SCL] = val & 0x1;
- return;
- case LOCK:
- if ((val & 0xFFFF) == XILINX_LOCK_KEY) {
- DB_PRINT("XILINX LOCK 0xF8000000 + 0x%x <= 0x%x\n", (int)offset,
- (unsigned)val & 0xFFFF);
- s->regs[LOCKSTA] = 1;
- } else {
- DB_PRINT("WRONG XILINX LOCK KEY 0xF8000000 + 0x%x <= 0x%x\n",
- (int)offset, (unsigned)val & 0xFFFF);
- }
- return;
- case UNLOCK:
- if ((val & 0xFFFF) == XILINX_UNLOCK_KEY) {
- DB_PRINT("XILINX UNLOCK 0xF8000000 + 0x%x <= 0x%x\n", (int)offset,
- (unsigned)val & 0xFFFF);
- s->regs[LOCKSTA] = 0;
- } else {
- DB_PRINT("WRONG XILINX UNLOCK KEY 0xF8000000 + 0x%x <= 0x%x\n",
- (int)offset, (unsigned)val & 0xFFFF);
- }
- return;
- }
-
- if (s->regs[LOCKSTA]) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "SCLR registers are locked. Unlock them first\n");
- return;
- }
- s->regs[offset] = val;
-
- switch (offset) {
- case PSS_RST_CTRL:
- if (val & R_PSS_RST_CTRL_SOFT_RST) {
- qemu_system_reset_request();
- }
- break;
- }
-}
-
-static const MemoryRegionOps slcr_ops = {
- .read = zynq_slcr_read,
- .write = zynq_slcr_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void zynq_slcr_init(Object *obj)
-{
- ZynqSLCRState *s = ZYNQ_SLCR(obj);
-
- memory_region_init_io(&s->iomem, obj, &slcr_ops, s, "slcr",
- ZYNQ_SLCR_MMIO_SIZE);
- sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
-}
-
-static const VMStateDescription vmstate_zynq_slcr = {
- .name = "zynq_slcr",
- .version_id = 2,
- .minimum_version_id = 2,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, ZynqSLCRState, ZYNQ_SLCR_NUM_REGS),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void zynq_slcr_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->vmsd = &vmstate_zynq_slcr;
- dc->reset = zynq_slcr_reset;
-}
-
-static const TypeInfo zynq_slcr_info = {
- .class_init = zynq_slcr_class_init,
- .name = TYPE_ZYNQ_SLCR,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(ZynqSLCRState),
- .instance_init = zynq_slcr_init,
-};
-
-static void zynq_slcr_register_types(void)
-{
- type_register_static(&zynq_slcr_info);
-}
-
-type_init(zynq_slcr_register_types)
diff --git a/qemu/hw/moxie/Makefile.objs b/qemu/hw/moxie/Makefile.objs
deleted file mode 100644
index bfc90012f..000000000
--- a/qemu/hw/moxie/Makefile.objs
+++ /dev/null
@@ -1,2 +0,0 @@
-# moxie boards
-obj-y += moxiesim.o
diff --git a/qemu/hw/moxie/moxiesim.c b/qemu/hw/moxie/moxiesim.c
deleted file mode 100644
index 3069834cf..000000000
--- a/qemu/hw/moxie/moxiesim.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * QEMU/moxiesim emulation
- *
- * Emulates a very simple machine model similar to the one used by the
- * GDB moxie simulator.
- *
- * Copyright (c) 2008, 2009, 2010, 2013 Anthony Green
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/sysbus.h"
-#include "hw/hw.h"
-#include "hw/i386/pc.h"
-#include "hw/isa/isa.h"
-#include "net/net.h"
-#include "sysemu/sysemu.h"
-#include "hw/boards.h"
-#include "hw/loader.h"
-#include "hw/char/serial.h"
-#include "exec/address-spaces.h"
-#include "elf.h"
-
-#define PHYS_MEM_BASE 0x80000000
-
-typedef struct {
- uint64_t ram_size;
- const char *kernel_filename;
- const char *kernel_cmdline;
- const char *initrd_filename;
-} LoaderParams;
-
-static void load_kernel(MoxieCPU *cpu, LoaderParams *loader_params)
-{
- uint64_t entry, kernel_low, kernel_high;
- long kernel_size;
- long initrd_size;
- ram_addr_t initrd_offset;
-
- kernel_size = load_elf(loader_params->kernel_filename, NULL, NULL,
- &entry, &kernel_low, &kernel_high, 1, EM_MOXIE,
- 0, 0);
-
- if (kernel_size <= 0) {
- fprintf(stderr, "qemu: could not load kernel '%s'\n",
- loader_params->kernel_filename);
- exit(1);
- }
-
- /* load initrd */
- initrd_size = 0;
- initrd_offset = 0;
- if (loader_params->initrd_filename) {
- initrd_size = get_image_size(loader_params->initrd_filename);
- if (initrd_size > 0) {
- initrd_offset = (kernel_high + ~TARGET_PAGE_MASK)
- & TARGET_PAGE_MASK;
- if (initrd_offset + initrd_size > loader_params->ram_size) {
- fprintf(stderr,
- "qemu: memory too small for initial ram disk '%s'\n",
- loader_params->initrd_filename);
- exit(1);
- }
- initrd_size = load_image_targphys(loader_params->initrd_filename,
- initrd_offset,
- ram_size);
- }
- if (initrd_size == (target_ulong)-1) {
- fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
- loader_params->initrd_filename);
- exit(1);
- }
- }
-}
-
-static void main_cpu_reset(void *opaque)
-{
- MoxieCPU *cpu = opaque;
-
- cpu_reset(CPU(cpu));
-}
-
-static void moxiesim_init(MachineState *machine)
-{
- MoxieCPU *cpu = NULL;
- ram_addr_t ram_size = machine->ram_size;
- const char *cpu_model = machine->cpu_model;
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- const char *initrd_filename = machine->initrd_filename;
- CPUMoxieState *env;
- MemoryRegion *address_space_mem = get_system_memory();
- MemoryRegion *ram = g_new(MemoryRegion, 1);
- MemoryRegion *rom = g_new(MemoryRegion, 1);
- hwaddr ram_base = 0x200000;
- LoaderParams loader_params;
-
- /* Init CPUs. */
- if (cpu_model == NULL) {
- cpu_model = "MoxieLite-moxie-cpu";
- }
- cpu = cpu_moxie_init(cpu_model);
- if (!cpu) {
- fprintf(stderr, "Unable to find CPU definition\n");
- exit(1);
- }
- env = &cpu->env;
-
- qemu_register_reset(main_cpu_reset, cpu);
-
- /* Allocate RAM. */
- memory_region_init_ram(ram, NULL, "moxiesim.ram", ram_size, &error_fatal);
- vmstate_register_ram_global(ram);
- memory_region_add_subregion(address_space_mem, ram_base, ram);
-
- memory_region_init_ram(rom, NULL, "moxie.rom", 128*0x1000, &error_fatal);
- vmstate_register_ram_global(rom);
- memory_region_add_subregion(get_system_memory(), 0x1000, rom);
-
- if (kernel_filename) {
- loader_params.ram_size = ram_size;
- loader_params.kernel_filename = kernel_filename;
- loader_params.kernel_cmdline = kernel_cmdline;
- loader_params.initrd_filename = initrd_filename;
- load_kernel(cpu, &loader_params);
- }
-
- /* A single 16450 sits at offset 0x3f8. */
- if (serial_hds[0]) {
- serial_mm_init(address_space_mem, 0x3f8, 0, env->irq[4],
- 8000000/16, serial_hds[0], DEVICE_LITTLE_ENDIAN);
- }
-}
-
-static void moxiesim_machine_init(MachineClass *mc)
-{
- mc->desc = "Moxie simulator platform";
- mc->init = moxiesim_init;
- mc->is_default = 1;
-}
-
-DEFINE_MACHINE("moxiesim", moxiesim_machine_init)
diff --git a/qemu/hw/net/Makefile.objs b/qemu/hw/net/Makefile.objs
deleted file mode 100644
index 64d044923..000000000
--- a/qemu/hw/net/Makefile.objs
+++ /dev/null
@@ -1,43 +0,0 @@
-common-obj-$(CONFIG_DP8393X) += dp8393x.o
-common-obj-$(CONFIG_XEN_BACKEND) += xen_nic.o
-
-# PCI network cards
-common-obj-$(CONFIG_NE2000_PCI) += ne2000.o
-common-obj-$(CONFIG_EEPRO100_PCI) += eepro100.o
-common-obj-$(CONFIG_PCNET_PCI) += pcnet-pci.o
-common-obj-$(CONFIG_PCNET_COMMON) += pcnet.o
-common-obj-$(CONFIG_E1000_PCI) += e1000.o
-common-obj-$(CONFIG_RTL8139_PCI) += rtl8139.o
-common-obj-$(CONFIG_VMXNET3_PCI) += vmxnet_tx_pkt.o vmxnet_rx_pkt.o
-common-obj-$(CONFIG_VMXNET3_PCI) += vmxnet3.o
-
-common-obj-$(CONFIG_SMC91C111) += smc91c111.o
-common-obj-$(CONFIG_LAN9118) += lan9118.o
-common-obj-$(CONFIG_NE2000_ISA) += ne2000-isa.o
-common-obj-$(CONFIG_OPENCORES_ETH) += opencores_eth.o
-common-obj-$(CONFIG_XGMAC) += xgmac.o
-common-obj-$(CONFIG_MIPSNET) += mipsnet.o
-common-obj-$(CONFIG_XILINX_AXI) += xilinx_axienet.o
-common-obj-$(CONFIG_ALLWINNER_EMAC) += allwinner_emac.o
-common-obj-$(CONFIG_IMX_FEC) += imx_fec.o
-
-common-obj-$(CONFIG_CADENCE) += cadence_gem.o
-common-obj-$(CONFIG_STELLARIS_ENET) += stellaris_enet.o
-common-obj-$(CONFIG_LANCE) += lance.o
-
-obj-$(CONFIG_ETRAXFS) += etraxfs_eth.o
-obj-$(CONFIG_COLDFIRE) += mcf_fec.o
-obj-$(CONFIG_MILKYMIST) += milkymist-minimac2.o
-obj-$(CONFIG_PSERIES) += spapr_llan.o
-obj-$(CONFIG_XILINX_ETHLITE) += xilinx_ethlite.o
-
-obj-$(CONFIG_VIRTIO) += virtio-net.o
-obj-y += vhost_net.o
-
-obj-$(CONFIG_ETSEC) += fsl_etsec/etsec.o fsl_etsec/registers.o \
- fsl_etsec/rings.o fsl_etsec/miim.o
-
-common-obj-$(CONFIG_ROCKER) += rocker/rocker.o rocker/rocker_fp.o \
- rocker/rocker_desc.o rocker/rocker_world.o \
- rocker/rocker_of_dpa.o
-obj-$(call lnot,$(CONFIG_ROCKER)) += rocker/qmp-norocker.o
diff --git a/qemu/hw/net/allwinner_emac.c b/qemu/hw/net/allwinner_emac.c
deleted file mode 100644
index 16d4b63ba..000000000
--- a/qemu/hw/net/allwinner_emac.c
+++ /dev/null
@@ -1,534 +0,0 @@
-/*
- * Emulation of Allwinner EMAC Fast Ethernet controller and
- * Realtek RTL8201CP PHY
- *
- * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
- *
- * This model is based on reverse-engineering of Linux kernel driver.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "net/net.h"
-#include "qemu/fifo8.h"
-#include "hw/net/allwinner_emac.h"
-#include <zlib.h>
-
-static uint8_t padding[60];
-
-static void mii_set_link(RTL8201CPState *mii, bool link_ok)
-{
- if (link_ok) {
- mii->bmsr |= MII_BMSR_LINK_ST | MII_BMSR_AN_COMP;
- mii->anlpar |= MII_ANAR_TXFD | MII_ANAR_10FD | MII_ANAR_10 |
- MII_ANAR_CSMACD;
- } else {
- mii->bmsr &= ~(MII_BMSR_LINK_ST | MII_BMSR_AN_COMP);
- mii->anlpar = MII_ANAR_TX;
- }
-}
-
-static void mii_reset(RTL8201CPState *mii, bool link_ok)
-{
- mii->bmcr = MII_BMCR_FD | MII_BMCR_AUTOEN | MII_BMCR_SPEED;
- mii->bmsr = MII_BMSR_100TX_FD | MII_BMSR_100TX_HD | MII_BMSR_10T_FD |
- MII_BMSR_10T_HD | MII_BMSR_MFPS | MII_BMSR_AUTONEG;
- mii->anar = MII_ANAR_TXFD | MII_ANAR_TX | MII_ANAR_10FD | MII_ANAR_10 |
- MII_ANAR_CSMACD;
- mii->anlpar = MII_ANAR_TX;
-
- mii_set_link(mii, link_ok);
-}
-
-static uint16_t RTL8201CP_mdio_read(AwEmacState *s, uint8_t addr, uint8_t reg)
-{
- RTL8201CPState *mii = &s->mii;
- uint16_t ret = 0xffff;
-
- if (addr == s->phy_addr) {
- switch (reg) {
- case MII_BMCR:
- return mii->bmcr;
- case MII_BMSR:
- return mii->bmsr;
- case MII_PHYID1:
- return RTL8201CP_PHYID1;
- case MII_PHYID2:
- return RTL8201CP_PHYID2;
- case MII_ANAR:
- return mii->anar;
- case MII_ANLPAR:
- return mii->anlpar;
- case MII_ANER:
- case MII_NSR:
- case MII_LBREMR:
- case MII_REC:
- case MII_SNRDR:
- case MII_TEST:
- qemu_log_mask(LOG_UNIMP,
- "allwinner_emac: read from unimpl. mii reg 0x%x\n",
- reg);
- return 0;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "allwinner_emac: read from invalid mii reg 0x%x\n",
- reg);
- return 0;
- }
- }
- return ret;
-}
-
-static void RTL8201CP_mdio_write(AwEmacState *s, uint8_t addr, uint8_t reg,
- uint16_t value)
-{
- RTL8201CPState *mii = &s->mii;
- NetClientState *nc;
-
- if (addr == s->phy_addr) {
- switch (reg) {
- case MII_BMCR:
- if (value & MII_BMCR_RESET) {
- nc = qemu_get_queue(s->nic);
- mii_reset(mii, !nc->link_down);
- } else {
- mii->bmcr = value;
- }
- break;
- case MII_ANAR:
- mii->anar = value;
- break;
- case MII_BMSR:
- case MII_PHYID1:
- case MII_PHYID2:
- case MII_ANLPAR:
- case MII_ANER:
- qemu_log_mask(LOG_GUEST_ERROR,
- "allwinner_emac: write to read-only mii reg 0x%x\n",
- reg);
- break;
- case MII_NSR:
- case MII_LBREMR:
- case MII_REC:
- case MII_SNRDR:
- case MII_TEST:
- qemu_log_mask(LOG_UNIMP,
- "allwinner_emac: write to unimpl. mii reg 0x%x\n",
- reg);
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "allwinner_emac: write to invalid mii reg 0x%x\n",
- reg);
- }
- }
-}
-
-static void aw_emac_update_irq(AwEmacState *s)
-{
- qemu_set_irq(s->irq, (s->int_sta & s->int_ctl) != 0);
-}
-
-static void aw_emac_tx_reset(AwEmacState *s, int chan)
-{
- fifo8_reset(&s->tx_fifo[chan]);
- s->tx_length[chan] = 0;
-}
-
-static void aw_emac_rx_reset(AwEmacState *s)
-{
- fifo8_reset(&s->rx_fifo);
- s->rx_num_packets = 0;
- s->rx_packet_size = 0;
- s->rx_packet_pos = 0;
-}
-
-static void fifo8_push_word(Fifo8 *fifo, uint32_t val)
-{
- fifo8_push(fifo, val);
- fifo8_push(fifo, val >> 8);
- fifo8_push(fifo, val >> 16);
- fifo8_push(fifo, val >> 24);
-}
-
-static uint32_t fifo8_pop_word(Fifo8 *fifo)
-{
- uint32_t ret;
-
- ret = fifo8_pop(fifo);
- ret |= fifo8_pop(fifo) << 8;
- ret |= fifo8_pop(fifo) << 16;
- ret |= fifo8_pop(fifo) << 24;
-
- return ret;
-}
-
-static int aw_emac_can_receive(NetClientState *nc)
-{
- AwEmacState *s = qemu_get_nic_opaque(nc);
-
- /*
- * To avoid packet drops, allow reception only when there is space
- * for a full frame: 1522 + 8 (rx headers) + 2 (padding).
- */
- return (s->ctl & EMAC_CTL_RX_EN) && (fifo8_num_free(&s->rx_fifo) >= 1532);
-}
-
-static ssize_t aw_emac_receive(NetClientState *nc, const uint8_t *buf,
- size_t size)
-{
- AwEmacState *s = qemu_get_nic_opaque(nc);
- Fifo8 *fifo = &s->rx_fifo;
- size_t padded_size, total_size;
- uint32_t crc;
-
- padded_size = size > 60 ? size : 60;
- total_size = QEMU_ALIGN_UP(RX_HDR_SIZE + padded_size + CRC_SIZE, 4);
-
- if (!(s->ctl & EMAC_CTL_RX_EN) || (fifo8_num_free(fifo) < total_size)) {
- return -1;
- }
-
- fifo8_push_word(fifo, EMAC_UNDOCUMENTED_MAGIC);
- fifo8_push_word(fifo, EMAC_RX_HEADER(padded_size + CRC_SIZE,
- EMAC_RX_IO_DATA_STATUS_OK));
- fifo8_push_all(fifo, buf, size);
- crc = crc32(~0, buf, size);
-
- if (padded_size != size) {
- fifo8_push_all(fifo, padding, padded_size - size);
- crc = crc32(crc, padding, padded_size - size);
- }
-
- fifo8_push_word(fifo, crc);
- fifo8_push_all(fifo, padding, QEMU_ALIGN_UP(padded_size, 4) - padded_size);
- s->rx_num_packets++;
-
- s->int_sta |= EMAC_INT_RX;
- aw_emac_update_irq(s);
-
- return size;
-}
-
-static void aw_emac_reset(DeviceState *dev)
-{
- AwEmacState *s = AW_EMAC(dev);
- NetClientState *nc = qemu_get_queue(s->nic);
-
- s->ctl = 0;
- s->tx_mode = 0;
- s->int_ctl = 0;
- s->int_sta = 0;
- s->tx_channel = 0;
- s->phy_target = 0;
-
- aw_emac_tx_reset(s, 0);
- aw_emac_tx_reset(s, 1);
- aw_emac_rx_reset(s);
-
- mii_reset(&s->mii, !nc->link_down);
-}
-
-static uint64_t aw_emac_read(void *opaque, hwaddr offset, unsigned size)
-{
- AwEmacState *s = opaque;
- Fifo8 *fifo = &s->rx_fifo;
- NetClientState *nc;
- uint64_t ret;
-
- switch (offset) {
- case EMAC_CTL_REG:
- return s->ctl;
- case EMAC_TX_MODE_REG:
- return s->tx_mode;
- case EMAC_TX_INS_REG:
- return s->tx_channel;
- case EMAC_RX_CTL_REG:
- return s->rx_ctl;
- case EMAC_RX_IO_DATA_REG:
- if (!s->rx_num_packets) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "Read IO data register when no packet available");
- return 0;
- }
-
- ret = fifo8_pop_word(fifo);
-
- switch (s->rx_packet_pos) {
- case 0: /* Word is magic header */
- s->rx_packet_pos += 4;
- break;
- case 4: /* Word is rx info header */
- s->rx_packet_pos += 4;
- s->rx_packet_size = QEMU_ALIGN_UP(extract32(ret, 0, 16), 4);
- break;
- default: /* Word is packet data */
- s->rx_packet_pos += 4;
- s->rx_packet_size -= 4;
-
- if (!s->rx_packet_size) {
- s->rx_packet_pos = 0;
- s->rx_num_packets--;
- nc = qemu_get_queue(s->nic);
- if (aw_emac_can_receive(nc)) {
- qemu_flush_queued_packets(nc);
- }
- }
- }
- return ret;
- case EMAC_RX_FBC_REG:
- return s->rx_num_packets;
- case EMAC_INT_CTL_REG:
- return s->int_ctl;
- case EMAC_INT_STA_REG:
- return s->int_sta;
- case EMAC_MAC_MRDD_REG:
- return RTL8201CP_mdio_read(s,
- extract32(s->phy_target, PHY_ADDR_SHIFT, 8),
- extract32(s->phy_target, PHY_REG_SHIFT, 8));
- default:
- qemu_log_mask(LOG_UNIMP,
- "allwinner_emac: read access to unknown register 0x"
- TARGET_FMT_plx "\n", offset);
- ret = 0;
- }
-
- return ret;
-}
-
-static void aw_emac_write(void *opaque, hwaddr offset, uint64_t value,
- unsigned size)
-{
- AwEmacState *s = opaque;
- Fifo8 *fifo;
- NetClientState *nc = qemu_get_queue(s->nic);
- int chan;
-
- switch (offset) {
- case EMAC_CTL_REG:
- if (value & EMAC_CTL_RESET) {
- aw_emac_reset(DEVICE(s));
- value &= ~EMAC_CTL_RESET;
- }
- s->ctl = value;
- if (aw_emac_can_receive(nc)) {
- qemu_flush_queued_packets(nc);
- }
- break;
- case EMAC_TX_MODE_REG:
- s->tx_mode = value;
- break;
- case EMAC_TX_CTL0_REG:
- case EMAC_TX_CTL1_REG:
- chan = (offset == EMAC_TX_CTL0_REG ? 0 : 1);
- if ((value & 1) && (s->ctl & EMAC_CTL_TX_EN)) {
- uint32_t len, ret;
- const uint8_t *data;
-
- fifo = &s->tx_fifo[chan];
- len = s->tx_length[chan];
-
- if (len > fifo8_num_used(fifo)) {
- len = fifo8_num_used(fifo);
- qemu_log_mask(LOG_GUEST_ERROR,
- "allwinner_emac: TX length > fifo data length\n");
- }
- if (len > 0) {
- data = fifo8_pop_buf(fifo, len, &ret);
- qemu_send_packet(nc, data, ret);
- aw_emac_tx_reset(s, chan);
- /* Raise TX interrupt */
- s->int_sta |= EMAC_INT_TX_CHAN(chan);
- aw_emac_update_irq(s);
- }
- }
- break;
- case EMAC_TX_INS_REG:
- s->tx_channel = value < NUM_TX_FIFOS ? value : 0;
- break;
- case EMAC_TX_PL0_REG:
- case EMAC_TX_PL1_REG:
- chan = (offset == EMAC_TX_PL0_REG ? 0 : 1);
- if (value > TX_FIFO_SIZE) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "allwinner_emac: invalid TX frame length %d\n",
- (int)value);
- value = TX_FIFO_SIZE;
- }
- s->tx_length[chan] = value;
- break;
- case EMAC_TX_IO_DATA_REG:
- fifo = &s->tx_fifo[s->tx_channel];
- if (fifo8_num_free(fifo) < 4) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "allwinner_emac: TX data overruns fifo\n");
- break;
- }
- fifo8_push_word(fifo, value);
- break;
- case EMAC_RX_CTL_REG:
- s->rx_ctl = value;
- break;
- case EMAC_RX_FBC_REG:
- if (value == 0) {
- aw_emac_rx_reset(s);
- }
- break;
- case EMAC_INT_CTL_REG:
- s->int_ctl = value;
- aw_emac_update_irq(s);
- break;
- case EMAC_INT_STA_REG:
- s->int_sta &= ~value;
- aw_emac_update_irq(s);
- break;
- case EMAC_MAC_MADR_REG:
- s->phy_target = value;
- break;
- case EMAC_MAC_MWTD_REG:
- RTL8201CP_mdio_write(s, extract32(s->phy_target, PHY_ADDR_SHIFT, 8),
- extract32(s->phy_target, PHY_REG_SHIFT, 8), value);
- break;
- default:
- qemu_log_mask(LOG_UNIMP,
- "allwinner_emac: write access to unknown register 0x"
- TARGET_FMT_plx "\n", offset);
- }
-}
-
-static void aw_emac_set_link(NetClientState *nc)
-{
- AwEmacState *s = qemu_get_nic_opaque(nc);
-
- mii_set_link(&s->mii, !nc->link_down);
-}
-
-static const MemoryRegionOps aw_emac_mem_ops = {
- .read = aw_emac_read,
- .write = aw_emac_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static NetClientInfo net_aw_emac_info = {
- .type = NET_CLIENT_OPTIONS_KIND_NIC,
- .size = sizeof(NICState),
- .can_receive = aw_emac_can_receive,
- .receive = aw_emac_receive,
- .link_status_changed = aw_emac_set_link,
-};
-
-static void aw_emac_init(Object *obj)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- AwEmacState *s = AW_EMAC(obj);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &aw_emac_mem_ops, s,
- "aw_emac", 0x1000);
- sysbus_init_mmio(sbd, &s->iomem);
- sysbus_init_irq(sbd, &s->irq);
-}
-
-static void aw_emac_realize(DeviceState *dev, Error **errp)
-{
- AwEmacState *s = AW_EMAC(dev);
-
- qemu_macaddr_default_if_unset(&s->conf.macaddr);
- s->nic = qemu_new_nic(&net_aw_emac_info, &s->conf,
- object_get_typename(OBJECT(dev)), dev->id, s);
- qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-
- fifo8_create(&s->rx_fifo, RX_FIFO_SIZE);
- fifo8_create(&s->tx_fifo[0], TX_FIFO_SIZE);
- fifo8_create(&s->tx_fifo[1], TX_FIFO_SIZE);
-}
-
-static Property aw_emac_properties[] = {
- DEFINE_NIC_PROPERTIES(AwEmacState, conf),
- DEFINE_PROP_UINT8("phy-addr", AwEmacState, phy_addr, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static const VMStateDescription vmstate_mii = {
- .name = "rtl8201cp",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT16(bmcr, RTL8201CPState),
- VMSTATE_UINT16(bmsr, RTL8201CPState),
- VMSTATE_UINT16(anar, RTL8201CPState),
- VMSTATE_UINT16(anlpar, RTL8201CPState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static int aw_emac_post_load(void *opaque, int version_id)
-{
- AwEmacState *s = opaque;
-
- aw_emac_set_link(qemu_get_queue(s->nic));
-
- return 0;
-}
-
-static const VMStateDescription vmstate_aw_emac = {
- .name = "allwinner_emac",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = aw_emac_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT(mii, AwEmacState, 1, vmstate_mii, RTL8201CPState),
- VMSTATE_UINT32(ctl, AwEmacState),
- VMSTATE_UINT32(tx_mode, AwEmacState),
- VMSTATE_UINT32(rx_ctl, AwEmacState),
- VMSTATE_UINT32(int_ctl, AwEmacState),
- VMSTATE_UINT32(int_sta, AwEmacState),
- VMSTATE_UINT32(phy_target, AwEmacState),
- VMSTATE_FIFO8(rx_fifo, AwEmacState),
- VMSTATE_UINT32(rx_num_packets, AwEmacState),
- VMSTATE_UINT32(rx_packet_size, AwEmacState),
- VMSTATE_UINT32(rx_packet_pos, AwEmacState),
- VMSTATE_STRUCT_ARRAY(tx_fifo, AwEmacState, NUM_TX_FIFOS, 1,
- vmstate_fifo8, Fifo8),
- VMSTATE_UINT32_ARRAY(tx_length, AwEmacState, NUM_TX_FIFOS),
- VMSTATE_UINT32(tx_channel, AwEmacState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void aw_emac_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = aw_emac_realize;
- dc->props = aw_emac_properties;
- dc->reset = aw_emac_reset;
- dc->vmsd = &vmstate_aw_emac;
-}
-
-static const TypeInfo aw_emac_info = {
- .name = TYPE_AW_EMAC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(AwEmacState),
- .instance_init = aw_emac_init,
- .class_init = aw_emac_class_init,
-};
-
-static void aw_emac_register_types(void)
-{
- type_register_static(&aw_emac_info);
-}
-
-type_init(aw_emac_register_types)
diff --git a/qemu/hw/net/cadence_gem.c b/qemu/hw/net/cadence_gem.c
deleted file mode 100644
index 0346f3e33..000000000
--- a/qemu/hw/net/cadence_gem.c
+++ /dev/null
@@ -1,1267 +0,0 @@
-/*
- * QEMU Cadence GEM emulation
- *
- * Copyright (c) 2011 Xilinx, Inc.
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include <zlib.h> /* For crc32 */
-
-#include "hw/net/cadence_gem.h"
-#include "net/checksum.h"
-
-#ifdef CADENCE_GEM_ERR_DEBUG
-#define DB_PRINT(...) do { \
- fprintf(stderr, ": %s: ", __func__); \
- fprintf(stderr, ## __VA_ARGS__); \
- } while (0);
-#else
- #define DB_PRINT(...)
-#endif
-
-#define GEM_NWCTRL (0x00000000/4) /* Network Control reg */
-#define GEM_NWCFG (0x00000004/4) /* Network Config reg */
-#define GEM_NWSTATUS (0x00000008/4) /* Network Status reg */
-#define GEM_USERIO (0x0000000C/4) /* User IO reg */
-#define GEM_DMACFG (0x00000010/4) /* DMA Control reg */
-#define GEM_TXSTATUS (0x00000014/4) /* TX Status reg */
-#define GEM_RXQBASE (0x00000018/4) /* RX Q Base address reg */
-#define GEM_TXQBASE (0x0000001C/4) /* TX Q Base address reg */
-#define GEM_RXSTATUS (0x00000020/4) /* RX Status reg */
-#define GEM_ISR (0x00000024/4) /* Interrupt Status reg */
-#define GEM_IER (0x00000028/4) /* Interrupt Enable reg */
-#define GEM_IDR (0x0000002C/4) /* Interrupt Disable reg */
-#define GEM_IMR (0x00000030/4) /* Interrupt Mask reg */
-#define GEM_PHYMNTNC (0x00000034/4) /* Phy Maintenance reg */
-#define GEM_RXPAUSE (0x00000038/4) /* RX Pause Time reg */
-#define GEM_TXPAUSE (0x0000003C/4) /* TX Pause Time reg */
-#define GEM_TXPARTIALSF (0x00000040/4) /* TX Partial Store and Forward */
-#define GEM_RXPARTIALSF (0x00000044/4) /* RX Partial Store and Forward */
-#define GEM_HASHLO (0x00000080/4) /* Hash Low address reg */
-#define GEM_HASHHI (0x00000084/4) /* Hash High address reg */
-#define GEM_SPADDR1LO (0x00000088/4) /* Specific addr 1 low reg */
-#define GEM_SPADDR1HI (0x0000008C/4) /* Specific addr 1 high reg */
-#define GEM_SPADDR2LO (0x00000090/4) /* Specific addr 2 low reg */
-#define GEM_SPADDR2HI (0x00000094/4) /* Specific addr 2 high reg */
-#define GEM_SPADDR3LO (0x00000098/4) /* Specific addr 3 low reg */
-#define GEM_SPADDR3HI (0x0000009C/4) /* Specific addr 3 high reg */
-#define GEM_SPADDR4LO (0x000000A0/4) /* Specific addr 4 low reg */
-#define GEM_SPADDR4HI (0x000000A4/4) /* Specific addr 4 high reg */
-#define GEM_TIDMATCH1 (0x000000A8/4) /* Type ID1 Match reg */
-#define GEM_TIDMATCH2 (0x000000AC/4) /* Type ID2 Match reg */
-#define GEM_TIDMATCH3 (0x000000B0/4) /* Type ID3 Match reg */
-#define GEM_TIDMATCH4 (0x000000B4/4) /* Type ID4 Match reg */
-#define GEM_WOLAN (0x000000B8/4) /* Wake on LAN reg */
-#define GEM_IPGSTRETCH (0x000000BC/4) /* IPG Stretch reg */
-#define GEM_SVLAN (0x000000C0/4) /* Stacked VLAN reg */
-#define GEM_MODID (0x000000FC/4) /* Module ID reg */
-#define GEM_OCTTXLO (0x00000100/4) /* Octects transmitted Low reg */
-#define GEM_OCTTXHI (0x00000104/4) /* Octects transmitted High reg */
-#define GEM_TXCNT (0x00000108/4) /* Error-free Frames transmitted */
-#define GEM_TXBCNT (0x0000010C/4) /* Error-free Broadcast Frames */
-#define GEM_TXMCNT (0x00000110/4) /* Error-free Multicast Frame */
-#define GEM_TXPAUSECNT (0x00000114/4) /* Pause Frames Transmitted */
-#define GEM_TX64CNT (0x00000118/4) /* Error-free 64 TX */
-#define GEM_TX65CNT (0x0000011C/4) /* Error-free 65-127 TX */
-#define GEM_TX128CNT (0x00000120/4) /* Error-free 128-255 TX */
-#define GEM_TX256CNT (0x00000124/4) /* Error-free 256-511 */
-#define GEM_TX512CNT (0x00000128/4) /* Error-free 512-1023 TX */
-#define GEM_TX1024CNT (0x0000012C/4) /* Error-free 1024-1518 TX */
-#define GEM_TX1519CNT (0x00000130/4) /* Error-free larger than 1519 TX */
-#define GEM_TXURUNCNT (0x00000134/4) /* TX under run error counter */
-#define GEM_SINGLECOLLCNT (0x00000138/4) /* Single Collision Frames */
-#define GEM_MULTCOLLCNT (0x0000013C/4) /* Multiple Collision Frames */
-#define GEM_EXCESSCOLLCNT (0x00000140/4) /* Excessive Collision Frames */
-#define GEM_LATECOLLCNT (0x00000144/4) /* Late Collision Frames */
-#define GEM_DEFERTXCNT (0x00000148/4) /* Deferred Transmission Frames */
-#define GEM_CSENSECNT (0x0000014C/4) /* Carrier Sense Error Counter */
-#define GEM_OCTRXLO (0x00000150/4) /* Octects Received register Low */
-#define GEM_OCTRXHI (0x00000154/4) /* Octects Received register High */
-#define GEM_RXCNT (0x00000158/4) /* Error-free Frames Received */
-#define GEM_RXBROADCNT (0x0000015C/4) /* Error-free Broadcast Frames RX */
-#define GEM_RXMULTICNT (0x00000160/4) /* Error-free Multicast Frames RX */
-#define GEM_RXPAUSECNT (0x00000164/4) /* Pause Frames Received Counter */
-#define GEM_RX64CNT (0x00000168/4) /* Error-free 64 byte Frames RX */
-#define GEM_RX65CNT (0x0000016C/4) /* Error-free 65-127B Frames RX */
-#define GEM_RX128CNT (0x00000170/4) /* Error-free 128-255B Frames RX */
-#define GEM_RX256CNT (0x00000174/4) /* Error-free 256-512B Frames RX */
-#define GEM_RX512CNT (0x00000178/4) /* Error-free 512-1023B Frames RX */
-#define GEM_RX1024CNT (0x0000017C/4) /* Error-free 1024-1518B Frames RX */
-#define GEM_RX1519CNT (0x00000180/4) /* Error-free 1519-max Frames RX */
-#define GEM_RXUNDERCNT (0x00000184/4) /* Undersize Frames Received */
-#define GEM_RXOVERCNT (0x00000188/4) /* Oversize Frames Received */
-#define GEM_RXJABCNT (0x0000018C/4) /* Jabbers Received Counter */
-#define GEM_RXFCSCNT (0x00000190/4) /* Frame Check seq. Error Counter */
-#define GEM_RXLENERRCNT (0x00000194/4) /* Length Field Error Counter */
-#define GEM_RXSYMERRCNT (0x00000198/4) /* Symbol Error Counter */
-#define GEM_RXALIGNERRCNT (0x0000019C/4) /* Alignment Error Counter */
-#define GEM_RXRSCERRCNT (0x000001A0/4) /* Receive Resource Error Counter */
-#define GEM_RXORUNCNT (0x000001A4/4) /* Receive Overrun Counter */
-#define GEM_RXIPCSERRCNT (0x000001A8/4) /* IP header Checksum Error Counter */
-#define GEM_RXTCPCCNT (0x000001AC/4) /* TCP Checksum Error Counter */
-#define GEM_RXUDPCCNT (0x000001B0/4) /* UDP Checksum Error Counter */
-
-#define GEM_1588S (0x000001D0/4) /* 1588 Timer Seconds */
-#define GEM_1588NS (0x000001D4/4) /* 1588 Timer Nanoseconds */
-#define GEM_1588ADJ (0x000001D8/4) /* 1588 Timer Adjust */
-#define GEM_1588INC (0x000001DC/4) /* 1588 Timer Increment */
-#define GEM_PTPETXS (0x000001E0/4) /* PTP Event Frame Transmitted (s) */
-#define GEM_PTPETXNS (0x000001E4/4) /* PTP Event Frame Transmitted (ns) */
-#define GEM_PTPERXS (0x000001E8/4) /* PTP Event Frame Received (s) */
-#define GEM_PTPERXNS (0x000001EC/4) /* PTP Event Frame Received (ns) */
-#define GEM_PTPPTXS (0x000001E0/4) /* PTP Peer Frame Transmitted (s) */
-#define GEM_PTPPTXNS (0x000001E4/4) /* PTP Peer Frame Transmitted (ns) */
-#define GEM_PTPPRXS (0x000001E8/4) /* PTP Peer Frame Received (s) */
-#define GEM_PTPPRXNS (0x000001EC/4) /* PTP Peer Frame Received (ns) */
-
-/* Design Configuration Registers */
-#define GEM_DESCONF (0x00000280/4)
-#define GEM_DESCONF2 (0x00000284/4)
-#define GEM_DESCONF3 (0x00000288/4)
-#define GEM_DESCONF4 (0x0000028C/4)
-#define GEM_DESCONF5 (0x00000290/4)
-#define GEM_DESCONF6 (0x00000294/4)
-#define GEM_DESCONF7 (0x00000298/4)
-
-/*****************************************/
-#define GEM_NWCTRL_TXSTART 0x00000200 /* Transmit Enable */
-#define GEM_NWCTRL_TXENA 0x00000008 /* Transmit Enable */
-#define GEM_NWCTRL_RXENA 0x00000004 /* Receive Enable */
-#define GEM_NWCTRL_LOCALLOOP 0x00000002 /* Local Loopback */
-
-#define GEM_NWCFG_STRIP_FCS 0x00020000 /* Strip FCS field */
-#define GEM_NWCFG_LERR_DISC 0x00010000 /* Discard RX frames with len err */
-#define GEM_NWCFG_BUFF_OFST_M 0x0000C000 /* Receive buffer offset mask */
-#define GEM_NWCFG_BUFF_OFST_S 14 /* Receive buffer offset shift */
-#define GEM_NWCFG_UCAST_HASH 0x00000080 /* accept unicast if hash match */
-#define GEM_NWCFG_MCAST_HASH 0x00000040 /* accept multicast if hash match */
-#define GEM_NWCFG_BCAST_REJ 0x00000020 /* Reject broadcast packets */
-#define GEM_NWCFG_PROMISC 0x00000010 /* Accept all packets */
-
-#define GEM_DMACFG_RBUFSZ_M 0x00FF0000 /* DMA RX Buffer Size mask */
-#define GEM_DMACFG_RBUFSZ_S 16 /* DMA RX Buffer Size shift */
-#define GEM_DMACFG_RBUFSZ_MUL 64 /* DMA RX Buffer Size multiplier */
-#define GEM_DMACFG_TXCSUM_OFFL 0x00000800 /* Transmit checksum offload */
-
-#define GEM_TXSTATUS_TXCMPL 0x00000020 /* Transmit Complete */
-#define GEM_TXSTATUS_USED 0x00000001 /* sw owned descriptor encountered */
-
-#define GEM_RXSTATUS_FRMRCVD 0x00000002 /* Frame received */
-#define GEM_RXSTATUS_NOBUF 0x00000001 /* Buffer unavailable */
-
-/* GEM_ISR GEM_IER GEM_IDR GEM_IMR */
-#define GEM_INT_TXCMPL 0x00000080 /* Transmit Complete */
-#define GEM_INT_TXUSED 0x00000008
-#define GEM_INT_RXUSED 0x00000004
-#define GEM_INT_RXCMPL 0x00000002
-
-#define GEM_PHYMNTNC_OP_R 0x20000000 /* read operation */
-#define GEM_PHYMNTNC_OP_W 0x10000000 /* write operation */
-#define GEM_PHYMNTNC_ADDR 0x0F800000 /* Address bits */
-#define GEM_PHYMNTNC_ADDR_SHFT 23
-#define GEM_PHYMNTNC_REG 0x007C0000 /* register bits */
-#define GEM_PHYMNTNC_REG_SHIFT 18
-
-/* Marvell PHY definitions */
-#define BOARD_PHY_ADDRESS 23 /* PHY address we will emulate a device at */
-
-#define PHY_REG_CONTROL 0
-#define PHY_REG_STATUS 1
-#define PHY_REG_PHYID1 2
-#define PHY_REG_PHYID2 3
-#define PHY_REG_ANEGADV 4
-#define PHY_REG_LINKPABIL 5
-#define PHY_REG_ANEGEXP 6
-#define PHY_REG_NEXTP 7
-#define PHY_REG_LINKPNEXTP 8
-#define PHY_REG_100BTCTRL 9
-#define PHY_REG_1000BTSTAT 10
-#define PHY_REG_EXTSTAT 15
-#define PHY_REG_PHYSPCFC_CTL 16
-#define PHY_REG_PHYSPCFC_ST 17
-#define PHY_REG_INT_EN 18
-#define PHY_REG_INT_ST 19
-#define PHY_REG_EXT_PHYSPCFC_CTL 20
-#define PHY_REG_RXERR 21
-#define PHY_REG_EACD 22
-#define PHY_REG_LED 24
-#define PHY_REG_LED_OVRD 25
-#define PHY_REG_EXT_PHYSPCFC_CTL2 26
-#define PHY_REG_EXT_PHYSPCFC_ST 27
-#define PHY_REG_CABLE_DIAG 28
-
-#define PHY_REG_CONTROL_RST 0x8000
-#define PHY_REG_CONTROL_LOOP 0x4000
-#define PHY_REG_CONTROL_ANEG 0x1000
-
-#define PHY_REG_STATUS_LINK 0x0004
-#define PHY_REG_STATUS_ANEGCMPL 0x0020
-
-#define PHY_REG_INT_ST_ANEGCMPL 0x0800
-#define PHY_REG_INT_ST_LINKC 0x0400
-#define PHY_REG_INT_ST_ENERGY 0x0010
-
-/***********************************************************************/
-#define GEM_RX_REJECT (-1)
-#define GEM_RX_PROMISCUOUS_ACCEPT (-2)
-#define GEM_RX_BROADCAST_ACCEPT (-3)
-#define GEM_RX_MULTICAST_HASH_ACCEPT (-4)
-#define GEM_RX_UNICAST_HASH_ACCEPT (-5)
-
-#define GEM_RX_SAR_ACCEPT 0
-
-/***********************************************************************/
-
-#define DESC_1_USED 0x80000000
-#define DESC_1_LENGTH 0x00001FFF
-
-#define DESC_1_TX_WRAP 0x40000000
-#define DESC_1_TX_LAST 0x00008000
-
-#define DESC_0_RX_WRAP 0x00000002
-#define DESC_0_RX_OWNERSHIP 0x00000001
-
-#define R_DESC_1_RX_SAR_SHIFT 25
-#define R_DESC_1_RX_SAR_LENGTH 2
-#define R_DESC_1_RX_SAR_MATCH (1 << 27)
-#define R_DESC_1_RX_UNICAST_HASH (1 << 29)
-#define R_DESC_1_RX_MULTICAST_HASH (1 << 30)
-#define R_DESC_1_RX_BROADCAST (1 << 31)
-
-#define DESC_1_RX_SOF 0x00004000
-#define DESC_1_RX_EOF 0x00008000
-
-static inline unsigned tx_desc_get_buffer(unsigned *desc)
-{
- return desc[0];
-}
-
-static inline unsigned tx_desc_get_used(unsigned *desc)
-{
- return (desc[1] & DESC_1_USED) ? 1 : 0;
-}
-
-static inline void tx_desc_set_used(unsigned *desc)
-{
- desc[1] |= DESC_1_USED;
-}
-
-static inline unsigned tx_desc_get_wrap(unsigned *desc)
-{
- return (desc[1] & DESC_1_TX_WRAP) ? 1 : 0;
-}
-
-static inline unsigned tx_desc_get_last(unsigned *desc)
-{
- return (desc[1] & DESC_1_TX_LAST) ? 1 : 0;
-}
-
-static inline unsigned tx_desc_get_length(unsigned *desc)
-{
- return desc[1] & DESC_1_LENGTH;
-}
-
-static inline void print_gem_tx_desc(unsigned *desc)
-{
- DB_PRINT("TXDESC:\n");
- DB_PRINT("bufaddr: 0x%08x\n", *desc);
- DB_PRINT("used_hw: %d\n", tx_desc_get_used(desc));
- DB_PRINT("wrap: %d\n", tx_desc_get_wrap(desc));
- DB_PRINT("last: %d\n", tx_desc_get_last(desc));
- DB_PRINT("length: %d\n", tx_desc_get_length(desc));
-}
-
-static inline unsigned rx_desc_get_buffer(unsigned *desc)
-{
- return desc[0] & ~0x3UL;
-}
-
-static inline unsigned rx_desc_get_wrap(unsigned *desc)
-{
- return desc[0] & DESC_0_RX_WRAP ? 1 : 0;
-}
-
-static inline unsigned rx_desc_get_ownership(unsigned *desc)
-{
- return desc[0] & DESC_0_RX_OWNERSHIP ? 1 : 0;
-}
-
-static inline void rx_desc_set_ownership(unsigned *desc)
-{
- desc[0] |= DESC_0_RX_OWNERSHIP;
-}
-
-static inline void rx_desc_set_sof(unsigned *desc)
-{
- desc[1] |= DESC_1_RX_SOF;
-}
-
-static inline void rx_desc_set_eof(unsigned *desc)
-{
- desc[1] |= DESC_1_RX_EOF;
-}
-
-static inline void rx_desc_set_length(unsigned *desc, unsigned len)
-{
- desc[1] &= ~DESC_1_LENGTH;
- desc[1] |= len;
-}
-
-static inline void rx_desc_set_broadcast(unsigned *desc)
-{
- desc[1] |= R_DESC_1_RX_BROADCAST;
-}
-
-static inline void rx_desc_set_unicast_hash(unsigned *desc)
-{
- desc[1] |= R_DESC_1_RX_UNICAST_HASH;
-}
-
-static inline void rx_desc_set_multicast_hash(unsigned *desc)
-{
- desc[1] |= R_DESC_1_RX_MULTICAST_HASH;
-}
-
-static inline void rx_desc_set_sar(unsigned *desc, int sar_idx)
-{
- desc[1] = deposit32(desc[1], R_DESC_1_RX_SAR_SHIFT, R_DESC_1_RX_SAR_LENGTH,
- sar_idx);
- desc[1] |= R_DESC_1_RX_SAR_MATCH;
-}
-
-/* The broadcast MAC address: 0xFFFFFFFFFFFF */
-static const uint8_t broadcast_addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
-
-/*
- * gem_init_register_masks:
- * One time initialization.
- * Set masks to identify which register bits have magical clear properties
- */
-static void gem_init_register_masks(CadenceGEMState *s)
-{
- /* Mask of register bits which are read only */
- memset(&s->regs_ro[0], 0, sizeof(s->regs_ro));
- s->regs_ro[GEM_NWCTRL] = 0xFFF80000;
- s->regs_ro[GEM_NWSTATUS] = 0xFFFFFFFF;
- s->regs_ro[GEM_DMACFG] = 0xFE00F000;
- s->regs_ro[GEM_TXSTATUS] = 0xFFFFFE08;
- s->regs_ro[GEM_RXQBASE] = 0x00000003;
- s->regs_ro[GEM_TXQBASE] = 0x00000003;
- s->regs_ro[GEM_RXSTATUS] = 0xFFFFFFF0;
- s->regs_ro[GEM_ISR] = 0xFFFFFFFF;
- s->regs_ro[GEM_IMR] = 0xFFFFFFFF;
- s->regs_ro[GEM_MODID] = 0xFFFFFFFF;
-
- /* Mask of register bits which are clear on read */
- memset(&s->regs_rtc[0], 0, sizeof(s->regs_rtc));
- s->regs_rtc[GEM_ISR] = 0xFFFFFFFF;
-
- /* Mask of register bits which are write 1 to clear */
- memset(&s->regs_w1c[0], 0, sizeof(s->regs_w1c));
- s->regs_w1c[GEM_TXSTATUS] = 0x000001F7;
- s->regs_w1c[GEM_RXSTATUS] = 0x0000000F;
-
- /* Mask of register bits which are write only */
- memset(&s->regs_wo[0], 0, sizeof(s->regs_wo));
- s->regs_wo[GEM_NWCTRL] = 0x00073E60;
- s->regs_wo[GEM_IER] = 0x07FFFFFF;
- s->regs_wo[GEM_IDR] = 0x07FFFFFF;
-}
-
-/*
- * phy_update_link:
- * Make the emulated PHY link state match the QEMU "interface" state.
- */
-static void phy_update_link(CadenceGEMState *s)
-{
- DB_PRINT("down %d\n", qemu_get_queue(s->nic)->link_down);
-
- /* Autonegotiation status mirrors link status. */
- if (qemu_get_queue(s->nic)->link_down) {
- s->phy_regs[PHY_REG_STATUS] &= ~(PHY_REG_STATUS_ANEGCMPL |
- PHY_REG_STATUS_LINK);
- s->phy_regs[PHY_REG_INT_ST] |= PHY_REG_INT_ST_LINKC;
- } else {
- s->phy_regs[PHY_REG_STATUS] |= (PHY_REG_STATUS_ANEGCMPL |
- PHY_REG_STATUS_LINK);
- s->phy_regs[PHY_REG_INT_ST] |= (PHY_REG_INT_ST_LINKC |
- PHY_REG_INT_ST_ANEGCMPL |
- PHY_REG_INT_ST_ENERGY);
- }
-}
-
-static int gem_can_receive(NetClientState *nc)
-{
- CadenceGEMState *s;
-
- s = qemu_get_nic_opaque(nc);
-
- /* Do nothing if receive is not enabled. */
- if (!(s->regs[GEM_NWCTRL] & GEM_NWCTRL_RXENA)) {
- if (s->can_rx_state != 1) {
- s->can_rx_state = 1;
- DB_PRINT("can't receive - no enable\n");
- }
- return 0;
- }
-
- if (rx_desc_get_ownership(s->rx_desc) == 1) {
- if (s->can_rx_state != 2) {
- s->can_rx_state = 2;
- DB_PRINT("can't receive - busy buffer descriptor 0x%x\n",
- s->rx_desc_addr);
- }
- return 0;
- }
-
- if (s->can_rx_state != 0) {
- s->can_rx_state = 0;
- DB_PRINT("can receive 0x%x\n", s->rx_desc_addr);
- }
- return 1;
-}
-
-/*
- * gem_update_int_status:
- * Raise or lower interrupt based on current status.
- */
-static void gem_update_int_status(CadenceGEMState *s)
-{
- if (s->regs[GEM_ISR]) {
- DB_PRINT("asserting int. (0x%08x)\n", s->regs[GEM_ISR]);
- qemu_set_irq(s->irq, 1);
- }
-}
-
-/*
- * gem_receive_updatestats:
- * Increment receive statistics.
- */
-static void gem_receive_updatestats(CadenceGEMState *s, const uint8_t *packet,
- unsigned bytes)
-{
- uint64_t octets;
-
- /* Total octets (bytes) received */
- octets = ((uint64_t)(s->regs[GEM_OCTRXLO]) << 32) |
- s->regs[GEM_OCTRXHI];
- octets += bytes;
- s->regs[GEM_OCTRXLO] = octets >> 32;
- s->regs[GEM_OCTRXHI] = octets;
-
- /* Error-free Frames received */
- s->regs[GEM_RXCNT]++;
-
- /* Error-free Broadcast Frames counter */
- if (!memcmp(packet, broadcast_addr, 6)) {
- s->regs[GEM_RXBROADCNT]++;
- }
-
- /* Error-free Multicast Frames counter */
- if (packet[0] == 0x01) {
- s->regs[GEM_RXMULTICNT]++;
- }
-
- if (bytes <= 64) {
- s->regs[GEM_RX64CNT]++;
- } else if (bytes <= 127) {
- s->regs[GEM_RX65CNT]++;
- } else if (bytes <= 255) {
- s->regs[GEM_RX128CNT]++;
- } else if (bytes <= 511) {
- s->regs[GEM_RX256CNT]++;
- } else if (bytes <= 1023) {
- s->regs[GEM_RX512CNT]++;
- } else if (bytes <= 1518) {
- s->regs[GEM_RX1024CNT]++;
- } else {
- s->regs[GEM_RX1519CNT]++;
- }
-}
-
-/*
- * Get the MAC Address bit from the specified position
- */
-static unsigned get_bit(const uint8_t *mac, unsigned bit)
-{
- unsigned byte;
-
- byte = mac[bit / 8];
- byte >>= (bit & 0x7);
- byte &= 1;
-
- return byte;
-}
-
-/*
- * Calculate a GEM MAC Address hash index
- */
-static unsigned calc_mac_hash(const uint8_t *mac)
-{
- int index_bit, mac_bit;
- unsigned hash_index;
-
- hash_index = 0;
- mac_bit = 5;
- for (index_bit = 5; index_bit >= 0; index_bit--) {
- hash_index |= (get_bit(mac, mac_bit) ^
- get_bit(mac, mac_bit + 6) ^
- get_bit(mac, mac_bit + 12) ^
- get_bit(mac, mac_bit + 18) ^
- get_bit(mac, mac_bit + 24) ^
- get_bit(mac, mac_bit + 30) ^
- get_bit(mac, mac_bit + 36) ^
- get_bit(mac, mac_bit + 42)) << index_bit;
- mac_bit--;
- }
-
- return hash_index;
-}
-
-/*
- * gem_mac_address_filter:
- * Accept or reject this destination address?
- * Returns:
- * GEM_RX_REJECT: reject
- * >= 0: Specific address accept (which matched SAR is returned)
- * others for various other modes of accept:
- * GEM_RM_PROMISCUOUS_ACCEPT, GEM_RX_BROADCAST_ACCEPT,
- * GEM_RX_MULTICAST_HASH_ACCEPT or GEM_RX_UNICAST_HASH_ACCEPT
- */
-static int gem_mac_address_filter(CadenceGEMState *s, const uint8_t *packet)
-{
- uint8_t *gem_spaddr;
- int i;
-
- /* Promiscuous mode? */
- if (s->regs[GEM_NWCFG] & GEM_NWCFG_PROMISC) {
- return GEM_RX_PROMISCUOUS_ACCEPT;
- }
-
- if (!memcmp(packet, broadcast_addr, 6)) {
- /* Reject broadcast packets? */
- if (s->regs[GEM_NWCFG] & GEM_NWCFG_BCAST_REJ) {
- return GEM_RX_REJECT;
- }
- return GEM_RX_BROADCAST_ACCEPT;
- }
-
- /* Accept packets -w- hash match? */
- if ((packet[0] == 0x01 && (s->regs[GEM_NWCFG] & GEM_NWCFG_MCAST_HASH)) ||
- (packet[0] != 0x01 && (s->regs[GEM_NWCFG] & GEM_NWCFG_UCAST_HASH))) {
- unsigned hash_index;
-
- hash_index = calc_mac_hash(packet);
- if (hash_index < 32) {
- if (s->regs[GEM_HASHLO] & (1<<hash_index)) {
- return packet[0] == 0x01 ? GEM_RX_MULTICAST_HASH_ACCEPT :
- GEM_RX_UNICAST_HASH_ACCEPT;
- }
- } else {
- hash_index -= 32;
- if (s->regs[GEM_HASHHI] & (1<<hash_index)) {
- return packet[0] == 0x01 ? GEM_RX_MULTICAST_HASH_ACCEPT :
- GEM_RX_UNICAST_HASH_ACCEPT;
- }
- }
- }
-
- /* Check all 4 specific addresses */
- gem_spaddr = (uint8_t *)&(s->regs[GEM_SPADDR1LO]);
- for (i = 3; i >= 0; i--) {
- if (s->sar_active[i] && !memcmp(packet, gem_spaddr + 8 * i, 6)) {
- return GEM_RX_SAR_ACCEPT + i;
- }
- }
-
- /* No address match; reject the packet */
- return GEM_RX_REJECT;
-}
-
-static void gem_get_rx_desc(CadenceGEMState *s)
-{
- DB_PRINT("read descriptor 0x%x\n", (unsigned)s->rx_desc_addr);
- /* read current descriptor */
- cpu_physical_memory_read(s->rx_desc_addr,
- (uint8_t *)s->rx_desc, sizeof(s->rx_desc));
-
- /* Descriptor owned by software ? */
- if (rx_desc_get_ownership(s->rx_desc) == 1) {
- DB_PRINT("descriptor 0x%x owned by sw.\n",
- (unsigned)s->rx_desc_addr);
- s->regs[GEM_RXSTATUS] |= GEM_RXSTATUS_NOBUF;
- s->regs[GEM_ISR] |= GEM_INT_RXUSED & ~(s->regs[GEM_IMR]);
- /* Handle interrupt consequences */
- gem_update_int_status(s);
- }
-}
-
-/*
- * gem_receive:
- * Fit a packet handed to us by QEMU into the receive descriptor ring.
- */
-static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
-{
- CadenceGEMState *s;
- unsigned rxbufsize, bytes_to_copy;
- unsigned rxbuf_offset;
- uint8_t rxbuf[2048];
- uint8_t *rxbuf_ptr;
- bool first_desc = true;
- int maf;
-
- s = qemu_get_nic_opaque(nc);
-
- /* Is this destination MAC address "for us" ? */
- maf = gem_mac_address_filter(s, buf);
- if (maf == GEM_RX_REJECT) {
- return -1;
- }
-
- /* Discard packets with receive length error enabled ? */
- if (s->regs[GEM_NWCFG] & GEM_NWCFG_LERR_DISC) {
- unsigned type_len;
-
- /* Fish the ethertype / length field out of the RX packet */
- type_len = buf[12] << 8 | buf[13];
- /* It is a length field, not an ethertype */
- if (type_len < 0x600) {
- if (size < type_len) {
- /* discard */
- return -1;
- }
- }
- }
-
- /*
- * Determine configured receive buffer offset (probably 0)
- */
- rxbuf_offset = (s->regs[GEM_NWCFG] & GEM_NWCFG_BUFF_OFST_M) >>
- GEM_NWCFG_BUFF_OFST_S;
-
- /* The configure size of each receive buffer. Determines how many
- * buffers needed to hold this packet.
- */
- rxbufsize = ((s->regs[GEM_DMACFG] & GEM_DMACFG_RBUFSZ_M) >>
- GEM_DMACFG_RBUFSZ_S) * GEM_DMACFG_RBUFSZ_MUL;
- bytes_to_copy = size;
-
- /* Pad to minimum length. Assume FCS field is stripped, logic
- * below will increment it to the real minimum of 64 when
- * not FCS stripping
- */
- if (size < 60) {
- size = 60;
- }
-
- /* Strip of FCS field ? (usually yes) */
- if (s->regs[GEM_NWCFG] & GEM_NWCFG_STRIP_FCS) {
- rxbuf_ptr = (void *)buf;
- } else {
- unsigned crc_val;
-
- if (size > sizeof(rxbuf) - sizeof(crc_val)) {
- size = sizeof(rxbuf) - sizeof(crc_val);
- }
- bytes_to_copy = size;
- /* The application wants the FCS field, which QEMU does not provide.
- * We must try and calculate one.
- */
-
- memcpy(rxbuf, buf, size);
- memset(rxbuf + size, 0, sizeof(rxbuf) - size);
- rxbuf_ptr = rxbuf;
- crc_val = cpu_to_le32(crc32(0, rxbuf, MAX(size, 60)));
- memcpy(rxbuf + size, &crc_val, sizeof(crc_val));
-
- bytes_to_copy += 4;
- size += 4;
- }
-
- DB_PRINT("config bufsize: %d packet size: %ld\n", rxbufsize, size);
-
- while (bytes_to_copy) {
- /* Do nothing if receive is not enabled. */
- if (!gem_can_receive(nc)) {
- assert(!first_desc);
- return -1;
- }
-
- DB_PRINT("copy %d bytes to 0x%x\n", MIN(bytes_to_copy, rxbufsize),
- rx_desc_get_buffer(s->rx_desc));
-
- /* Copy packet data to emulated DMA buffer */
- cpu_physical_memory_write(rx_desc_get_buffer(s->rx_desc) + rxbuf_offset,
- rxbuf_ptr, MIN(bytes_to_copy, rxbufsize));
- rxbuf_ptr += MIN(bytes_to_copy, rxbufsize);
- bytes_to_copy -= MIN(bytes_to_copy, rxbufsize);
-
- /* Update the descriptor. */
- if (first_desc) {
- rx_desc_set_sof(s->rx_desc);
- first_desc = false;
- }
- if (bytes_to_copy == 0) {
- rx_desc_set_eof(s->rx_desc);
- rx_desc_set_length(s->rx_desc, size);
- }
- rx_desc_set_ownership(s->rx_desc);
-
- switch (maf) {
- case GEM_RX_PROMISCUOUS_ACCEPT:
- break;
- case GEM_RX_BROADCAST_ACCEPT:
- rx_desc_set_broadcast(s->rx_desc);
- break;
- case GEM_RX_UNICAST_HASH_ACCEPT:
- rx_desc_set_unicast_hash(s->rx_desc);
- break;
- case GEM_RX_MULTICAST_HASH_ACCEPT:
- rx_desc_set_multicast_hash(s->rx_desc);
- break;
- case GEM_RX_REJECT:
- abort();
- default: /* SAR */
- rx_desc_set_sar(s->rx_desc, maf);
- }
-
- /* Descriptor write-back. */
- cpu_physical_memory_write(s->rx_desc_addr,
- (uint8_t *)s->rx_desc, sizeof(s->rx_desc));
-
- /* Next descriptor */
- if (rx_desc_get_wrap(s->rx_desc)) {
- DB_PRINT("wrapping RX descriptor list\n");
- s->rx_desc_addr = s->regs[GEM_RXQBASE];
- } else {
- DB_PRINT("incrementing RX descriptor list\n");
- s->rx_desc_addr += 8;
- }
- gem_get_rx_desc(s);
- }
-
- /* Count it */
- gem_receive_updatestats(s, buf, size);
-
- s->regs[GEM_RXSTATUS] |= GEM_RXSTATUS_FRMRCVD;
- s->regs[GEM_ISR] |= GEM_INT_RXCMPL & ~(s->regs[GEM_IMR]);
-
- /* Handle interrupt consequences */
- gem_update_int_status(s);
-
- return size;
-}
-
-/*
- * gem_transmit_updatestats:
- * Increment transmit statistics.
- */
-static void gem_transmit_updatestats(CadenceGEMState *s, const uint8_t *packet,
- unsigned bytes)
-{
- uint64_t octets;
-
- /* Total octets (bytes) transmitted */
- octets = ((uint64_t)(s->regs[GEM_OCTTXLO]) << 32) |
- s->regs[GEM_OCTTXHI];
- octets += bytes;
- s->regs[GEM_OCTTXLO] = octets >> 32;
- s->regs[GEM_OCTTXHI] = octets;
-
- /* Error-free Frames transmitted */
- s->regs[GEM_TXCNT]++;
-
- /* Error-free Broadcast Frames counter */
- if (!memcmp(packet, broadcast_addr, 6)) {
- s->regs[GEM_TXBCNT]++;
- }
-
- /* Error-free Multicast Frames counter */
- if (packet[0] == 0x01) {
- s->regs[GEM_TXMCNT]++;
- }
-
- if (bytes <= 64) {
- s->regs[GEM_TX64CNT]++;
- } else if (bytes <= 127) {
- s->regs[GEM_TX65CNT]++;
- } else if (bytes <= 255) {
- s->regs[GEM_TX128CNT]++;
- } else if (bytes <= 511) {
- s->regs[GEM_TX256CNT]++;
- } else if (bytes <= 1023) {
- s->regs[GEM_TX512CNT]++;
- } else if (bytes <= 1518) {
- s->regs[GEM_TX1024CNT]++;
- } else {
- s->regs[GEM_TX1519CNT]++;
- }
-}
-
-/*
- * gem_transmit:
- * Fish packets out of the descriptor ring and feed them to QEMU
- */
-static void gem_transmit(CadenceGEMState *s)
-{
- unsigned desc[2];
- hwaddr packet_desc_addr;
- uint8_t tx_packet[2048];
- uint8_t *p;
- unsigned total_bytes;
-
- /* Do nothing if transmit is not enabled. */
- if (!(s->regs[GEM_NWCTRL] & GEM_NWCTRL_TXENA)) {
- return;
- }
-
- DB_PRINT("\n");
-
- /* The packet we will hand off to QEMU.
- * Packets scattered across multiple descriptors are gathered to this
- * one contiguous buffer first.
- */
- p = tx_packet;
- total_bytes = 0;
-
- /* read current descriptor */
- packet_desc_addr = s->tx_desc_addr;
-
- DB_PRINT("read descriptor 0x%" HWADDR_PRIx "\n", packet_desc_addr);
- cpu_physical_memory_read(packet_desc_addr,
- (uint8_t *)desc, sizeof(desc));
- /* Handle all descriptors owned by hardware */
- while (tx_desc_get_used(desc) == 0) {
-
- /* Do nothing if transmit is not enabled. */
- if (!(s->regs[GEM_NWCTRL] & GEM_NWCTRL_TXENA)) {
- return;
- }
- print_gem_tx_desc(desc);
-
- /* The real hardware would eat this (and possibly crash).
- * For QEMU let's lend a helping hand.
- */
- if ((tx_desc_get_buffer(desc) == 0) ||
- (tx_desc_get_length(desc) == 0)) {
- DB_PRINT("Invalid TX descriptor @ 0x%x\n",
- (unsigned)packet_desc_addr);
- break;
- }
-
- if (tx_desc_get_length(desc) > sizeof(tx_packet) - (p - tx_packet)) {
- DB_PRINT("TX descriptor @ 0x%x too large: size 0x%x space 0x%x\n",
- (unsigned)packet_desc_addr,
- (unsigned)tx_desc_get_length(desc),
- sizeof(tx_packet) - (p - tx_packet));
- break;
- }
-
- /* Gather this fragment of the packet from "dma memory" to our contig.
- * buffer.
- */
- cpu_physical_memory_read(tx_desc_get_buffer(desc), p,
- tx_desc_get_length(desc));
- p += tx_desc_get_length(desc);
- total_bytes += tx_desc_get_length(desc);
-
- /* Last descriptor for this packet; hand the whole thing off */
- if (tx_desc_get_last(desc)) {
- unsigned desc_first[2];
-
- /* Modify the 1st descriptor of this packet to be owned by
- * the processor.
- */
- cpu_physical_memory_read(s->tx_desc_addr, (uint8_t *)desc_first,
- sizeof(desc_first));
- tx_desc_set_used(desc_first);
- cpu_physical_memory_write(s->tx_desc_addr, (uint8_t *)desc_first,
- sizeof(desc_first));
- /* Advance the hardware current descriptor past this packet */
- if (tx_desc_get_wrap(desc)) {
- s->tx_desc_addr = s->regs[GEM_TXQBASE];
- } else {
- s->tx_desc_addr = packet_desc_addr + 8;
- }
- DB_PRINT("TX descriptor next: 0x%08x\n", s->tx_desc_addr);
-
- s->regs[GEM_TXSTATUS] |= GEM_TXSTATUS_TXCMPL;
- s->regs[GEM_ISR] |= GEM_INT_TXCMPL & ~(s->regs[GEM_IMR]);
-
- /* Handle interrupt consequences */
- gem_update_int_status(s);
-
- /* Is checksum offload enabled? */
- if (s->regs[GEM_DMACFG] & GEM_DMACFG_TXCSUM_OFFL) {
- net_checksum_calculate(tx_packet, total_bytes);
- }
-
- /* Update MAC statistics */
- gem_transmit_updatestats(s, tx_packet, total_bytes);
-
- /* Send the packet somewhere */
- if (s->phy_loop || (s->regs[GEM_NWCTRL] & GEM_NWCTRL_LOCALLOOP)) {
- gem_receive(qemu_get_queue(s->nic), tx_packet, total_bytes);
- } else {
- qemu_send_packet(qemu_get_queue(s->nic), tx_packet,
- total_bytes);
- }
-
- /* Prepare for next packet */
- p = tx_packet;
- total_bytes = 0;
- }
-
- /* read next descriptor */
- if (tx_desc_get_wrap(desc)) {
- packet_desc_addr = s->regs[GEM_TXQBASE];
- } else {
- packet_desc_addr += 8;
- }
- DB_PRINT("read descriptor 0x%" HWADDR_PRIx "\n", packet_desc_addr);
- cpu_physical_memory_read(packet_desc_addr,
- (uint8_t *)desc, sizeof(desc));
- }
-
- if (tx_desc_get_used(desc)) {
- s->regs[GEM_TXSTATUS] |= GEM_TXSTATUS_USED;
- s->regs[GEM_ISR] |= GEM_INT_TXUSED & ~(s->regs[GEM_IMR]);
- gem_update_int_status(s);
- }
-}
-
-static void gem_phy_reset(CadenceGEMState *s)
-{
- memset(&s->phy_regs[0], 0, sizeof(s->phy_regs));
- s->phy_regs[PHY_REG_CONTROL] = 0x1140;
- s->phy_regs[PHY_REG_STATUS] = 0x7969;
- s->phy_regs[PHY_REG_PHYID1] = 0x0141;
- s->phy_regs[PHY_REG_PHYID2] = 0x0CC2;
- s->phy_regs[PHY_REG_ANEGADV] = 0x01E1;
- s->phy_regs[PHY_REG_LINKPABIL] = 0xCDE1;
- s->phy_regs[PHY_REG_ANEGEXP] = 0x000F;
- s->phy_regs[PHY_REG_NEXTP] = 0x2001;
- s->phy_regs[PHY_REG_LINKPNEXTP] = 0x40E6;
- s->phy_regs[PHY_REG_100BTCTRL] = 0x0300;
- s->phy_regs[PHY_REG_1000BTSTAT] = 0x7C00;
- s->phy_regs[PHY_REG_EXTSTAT] = 0x3000;
- s->phy_regs[PHY_REG_PHYSPCFC_CTL] = 0x0078;
- s->phy_regs[PHY_REG_PHYSPCFC_ST] = 0x7C00;
- s->phy_regs[PHY_REG_EXT_PHYSPCFC_CTL] = 0x0C60;
- s->phy_regs[PHY_REG_LED] = 0x4100;
- s->phy_regs[PHY_REG_EXT_PHYSPCFC_CTL2] = 0x000A;
- s->phy_regs[PHY_REG_EXT_PHYSPCFC_ST] = 0x848B;
-
- phy_update_link(s);
-}
-
-static void gem_reset(DeviceState *d)
-{
- int i;
- CadenceGEMState *s = CADENCE_GEM(d);
- const uint8_t *a;
-
- DB_PRINT("\n");
-
- /* Set post reset register values */
- memset(&s->regs[0], 0, sizeof(s->regs));
- s->regs[GEM_NWCFG] = 0x00080000;
- s->regs[GEM_NWSTATUS] = 0x00000006;
- s->regs[GEM_DMACFG] = 0x00020784;
- s->regs[GEM_IMR] = 0x07ffffff;
- s->regs[GEM_TXPAUSE] = 0x0000ffff;
- s->regs[GEM_TXPARTIALSF] = 0x000003ff;
- s->regs[GEM_RXPARTIALSF] = 0x000003ff;
- s->regs[GEM_MODID] = 0x00020118;
- s->regs[GEM_DESCONF] = 0x02500111;
- s->regs[GEM_DESCONF2] = 0x2ab13fff;
- s->regs[GEM_DESCONF5] = 0x002f2145;
- s->regs[GEM_DESCONF6] = 0x00000200;
-
- /* Set MAC address */
- a = &s->conf.macaddr.a[0];
- s->regs[GEM_SPADDR1LO] = a[0] | (a[1] << 8) | (a[2] << 16) | (a[3] << 24);
- s->regs[GEM_SPADDR1HI] = a[4] | (a[5] << 8);
-
- for (i = 0; i < 4; i++) {
- s->sar_active[i] = false;
- }
-
- gem_phy_reset(s);
-
- gem_update_int_status(s);
-}
-
-static uint16_t gem_phy_read(CadenceGEMState *s, unsigned reg_num)
-{
- DB_PRINT("reg: %d value: 0x%04x\n", reg_num, s->phy_regs[reg_num]);
- return s->phy_regs[reg_num];
-}
-
-static void gem_phy_write(CadenceGEMState *s, unsigned reg_num, uint16_t val)
-{
- DB_PRINT("reg: %d value: 0x%04x\n", reg_num, val);
-
- switch (reg_num) {
- case PHY_REG_CONTROL:
- if (val & PHY_REG_CONTROL_RST) {
- /* Phy reset */
- gem_phy_reset(s);
- val &= ~(PHY_REG_CONTROL_RST | PHY_REG_CONTROL_LOOP);
- s->phy_loop = 0;
- }
- if (val & PHY_REG_CONTROL_ANEG) {
- /* Complete autonegotiation immediately */
- val &= ~PHY_REG_CONTROL_ANEG;
- s->phy_regs[PHY_REG_STATUS] |= PHY_REG_STATUS_ANEGCMPL;
- }
- if (val & PHY_REG_CONTROL_LOOP) {
- DB_PRINT("PHY placed in loopback\n");
- s->phy_loop = 1;
- } else {
- s->phy_loop = 0;
- }
- break;
- }
- s->phy_regs[reg_num] = val;
-}
-
-/*
- * gem_read32:
- * Read a GEM register.
- */
-static uint64_t gem_read(void *opaque, hwaddr offset, unsigned size)
-{
- CadenceGEMState *s;
- uint32_t retval;
-
- s = (CadenceGEMState *)opaque;
-
- offset >>= 2;
- retval = s->regs[offset];
-
- DB_PRINT("offset: 0x%04x read: 0x%08x\n", (unsigned)offset*4, retval);
-
- switch (offset) {
- case GEM_ISR:
- DB_PRINT("lowering irq on ISR read\n");
- qemu_set_irq(s->irq, 0);
- break;
- case GEM_PHYMNTNC:
- if (retval & GEM_PHYMNTNC_OP_R) {
- uint32_t phy_addr, reg_num;
-
- phy_addr = (retval & GEM_PHYMNTNC_ADDR) >> GEM_PHYMNTNC_ADDR_SHFT;
- if (phy_addr == BOARD_PHY_ADDRESS || phy_addr == 0) {
- reg_num = (retval & GEM_PHYMNTNC_REG) >> GEM_PHYMNTNC_REG_SHIFT;
- retval &= 0xFFFF0000;
- retval |= gem_phy_read(s, reg_num);
- } else {
- retval |= 0xFFFF; /* No device at this address */
- }
- }
- break;
- }
-
- /* Squash read to clear bits */
- s->regs[offset] &= ~(s->regs_rtc[offset]);
-
- /* Do not provide write only bits */
- retval &= ~(s->regs_wo[offset]);
-
- DB_PRINT("0x%08x\n", retval);
- return retval;
-}
-
-/*
- * gem_write32:
- * Write a GEM register.
- */
-static void gem_write(void *opaque, hwaddr offset, uint64_t val,
- unsigned size)
-{
- CadenceGEMState *s = (CadenceGEMState *)opaque;
- uint32_t readonly;
-
- DB_PRINT("offset: 0x%04x write: 0x%08x ", (unsigned)offset, (unsigned)val);
- offset >>= 2;
-
- /* Squash bits which are read only in write value */
- val &= ~(s->regs_ro[offset]);
- /* Preserve (only) bits which are read only and wtc in register */
- readonly = s->regs[offset] & (s->regs_ro[offset] | s->regs_w1c[offset]);
-
- /* Copy register write to backing store */
- s->regs[offset] = (val & ~s->regs_w1c[offset]) | readonly;
-
- /* do w1c */
- s->regs[offset] &= ~(s->regs_w1c[offset] & val);
-
- /* Handle register write side effects */
- switch (offset) {
- case GEM_NWCTRL:
- if (val & GEM_NWCTRL_RXENA) {
- gem_get_rx_desc(s);
- }
- if (val & GEM_NWCTRL_TXSTART) {
- gem_transmit(s);
- }
- if (!(val & GEM_NWCTRL_TXENA)) {
- /* Reset to start of Q when transmit disabled. */
- s->tx_desc_addr = s->regs[GEM_TXQBASE];
- }
- if (gem_can_receive(qemu_get_queue(s->nic))) {
- qemu_flush_queued_packets(qemu_get_queue(s->nic));
- }
- break;
-
- case GEM_TXSTATUS:
- gem_update_int_status(s);
- break;
- case GEM_RXQBASE:
- s->rx_desc_addr = val;
- break;
- case GEM_TXQBASE:
- s->tx_desc_addr = val;
- break;
- case GEM_RXSTATUS:
- gem_update_int_status(s);
- break;
- case GEM_IER:
- s->regs[GEM_IMR] &= ~val;
- gem_update_int_status(s);
- break;
- case GEM_IDR:
- s->regs[GEM_IMR] |= val;
- gem_update_int_status(s);
- break;
- case GEM_SPADDR1LO:
- case GEM_SPADDR2LO:
- case GEM_SPADDR3LO:
- case GEM_SPADDR4LO:
- s->sar_active[(offset - GEM_SPADDR1LO) / 2] = false;
- break;
- case GEM_SPADDR1HI:
- case GEM_SPADDR2HI:
- case GEM_SPADDR3HI:
- case GEM_SPADDR4HI:
- s->sar_active[(offset - GEM_SPADDR1HI) / 2] = true;
- break;
- case GEM_PHYMNTNC:
- if (val & GEM_PHYMNTNC_OP_W) {
- uint32_t phy_addr, reg_num;
-
- phy_addr = (val & GEM_PHYMNTNC_ADDR) >> GEM_PHYMNTNC_ADDR_SHFT;
- if (phy_addr == BOARD_PHY_ADDRESS || phy_addr == 0) {
- reg_num = (val & GEM_PHYMNTNC_REG) >> GEM_PHYMNTNC_REG_SHIFT;
- gem_phy_write(s, reg_num, val);
- }
- }
- break;
- }
-
- DB_PRINT("newval: 0x%08x\n", s->regs[offset]);
-}
-
-static const MemoryRegionOps gem_ops = {
- .read = gem_read,
- .write = gem_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void gem_set_link(NetClientState *nc)
-{
- DB_PRINT("\n");
- phy_update_link(qemu_get_nic_opaque(nc));
-}
-
-static NetClientInfo net_gem_info = {
- .type = NET_CLIENT_OPTIONS_KIND_NIC,
- .size = sizeof(NICState),
- .can_receive = gem_can_receive,
- .receive = gem_receive,
- .link_status_changed = gem_set_link,
-};
-
-static int gem_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- CadenceGEMState *s = CADENCE_GEM(dev);
-
- DB_PRINT("\n");
-
- gem_init_register_masks(s);
- memory_region_init_io(&s->iomem, OBJECT(s), &gem_ops, s,
- "enet", sizeof(s->regs));
- sysbus_init_mmio(sbd, &s->iomem);
- sysbus_init_irq(sbd, &s->irq);
- qemu_macaddr_default_if_unset(&s->conf.macaddr);
-
- s->nic = qemu_new_nic(&net_gem_info, &s->conf,
- object_get_typename(OBJECT(dev)), dev->id, s);
-
- return 0;
-}
-
-static const VMStateDescription vmstate_cadence_gem = {
- .name = "cadence_gem",
- .version_id = 2,
- .minimum_version_id = 2,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, CadenceGEMState, CADENCE_GEM_MAXREG),
- VMSTATE_UINT16_ARRAY(phy_regs, CadenceGEMState, 32),
- VMSTATE_UINT8(phy_loop, CadenceGEMState),
- VMSTATE_UINT32(rx_desc_addr, CadenceGEMState),
- VMSTATE_UINT32(tx_desc_addr, CadenceGEMState),
- VMSTATE_BOOL_ARRAY(sar_active, CadenceGEMState, 4),
- VMSTATE_END_OF_LIST(),
- }
-};
-
-static Property gem_properties[] = {
- DEFINE_NIC_PROPERTIES(CadenceGEMState, conf),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void gem_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
- sdc->init = gem_init;
- dc->props = gem_properties;
- dc->vmsd = &vmstate_cadence_gem;
- dc->reset = gem_reset;
-}
-
-static const TypeInfo gem_info = {
- .name = TYPE_CADENCE_GEM,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(CadenceGEMState),
- .class_init = gem_class_init,
-};
-
-static void gem_register_types(void)
-{
- type_register_static(&gem_info);
-}
-
-type_init(gem_register_types)
diff --git a/qemu/hw/net/dp8393x.c b/qemu/hw/net/dp8393x.c
deleted file mode 100644
index 0fa652c39..000000000
--- a/qemu/hw/net/dp8393x.c
+++ /dev/null
@@ -1,912 +0,0 @@
-/*
- * QEMU NS SONIC DP8393x netcard
- *
- * Copyright (c) 2008-2009 Herve Poussineau
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "hw/devices.h"
-#include "net/net.h"
-#include "qapi/error.h"
-#include "qemu/timer.h"
-#include <zlib.h>
-
-//#define DEBUG_SONIC
-
-#define SONIC_PROM_SIZE 0x1000
-
-#ifdef DEBUG_SONIC
-#define DPRINTF(fmt, ...) \
-do { printf("sonic: " fmt , ## __VA_ARGS__); } while (0)
-static const char* reg_names[] = {
- "CR", "DCR", "RCR", "TCR", "IMR", "ISR", "UTDA", "CTDA",
- "TPS", "TFC", "TSA0", "TSA1", "TFS", "URDA", "CRDA", "CRBA0",
- "CRBA1", "RBWC0", "RBWC1", "EOBC", "URRA", "RSA", "REA", "RRP",
- "RWP", "TRBA0", "TRBA1", "0x1b", "0x1c", "0x1d", "0x1e", "LLFA",
- "TTDA", "CEP", "CAP2", "CAP1", "CAP0", "CE", "CDP", "CDC",
- "SR", "WT0", "WT1", "RSC", "CRCT", "FAET", "MPT", "MDT",
- "0x30", "0x31", "0x32", "0x33", "0x34", "0x35", "0x36", "0x37",
- "0x38", "0x39", "0x3a", "0x3b", "0x3c", "0x3d", "0x3e", "DCR2" };
-#else
-#define DPRINTF(fmt, ...) do {} while (0)
-#endif
-
-#define SONIC_ERROR(fmt, ...) \
-do { printf("sonic ERROR: %s: " fmt, __func__ , ## __VA_ARGS__); } while (0)
-
-#define SONIC_CR 0x00
-#define SONIC_DCR 0x01
-#define SONIC_RCR 0x02
-#define SONIC_TCR 0x03
-#define SONIC_IMR 0x04
-#define SONIC_ISR 0x05
-#define SONIC_UTDA 0x06
-#define SONIC_CTDA 0x07
-#define SONIC_TPS 0x08
-#define SONIC_TFC 0x09
-#define SONIC_TSA0 0x0a
-#define SONIC_TSA1 0x0b
-#define SONIC_TFS 0x0c
-#define SONIC_URDA 0x0d
-#define SONIC_CRDA 0x0e
-#define SONIC_CRBA0 0x0f
-#define SONIC_CRBA1 0x10
-#define SONIC_RBWC0 0x11
-#define SONIC_RBWC1 0x12
-#define SONIC_EOBC 0x13
-#define SONIC_URRA 0x14
-#define SONIC_RSA 0x15
-#define SONIC_REA 0x16
-#define SONIC_RRP 0x17
-#define SONIC_RWP 0x18
-#define SONIC_TRBA0 0x19
-#define SONIC_TRBA1 0x1a
-#define SONIC_LLFA 0x1f
-#define SONIC_TTDA 0x20
-#define SONIC_CEP 0x21
-#define SONIC_CAP2 0x22
-#define SONIC_CAP1 0x23
-#define SONIC_CAP0 0x24
-#define SONIC_CE 0x25
-#define SONIC_CDP 0x26
-#define SONIC_CDC 0x27
-#define SONIC_SR 0x28
-#define SONIC_WT0 0x29
-#define SONIC_WT1 0x2a
-#define SONIC_RSC 0x2b
-#define SONIC_CRCT 0x2c
-#define SONIC_FAET 0x2d
-#define SONIC_MPT 0x2e
-#define SONIC_MDT 0x2f
-#define SONIC_DCR2 0x3f
-
-#define SONIC_CR_HTX 0x0001
-#define SONIC_CR_TXP 0x0002
-#define SONIC_CR_RXDIS 0x0004
-#define SONIC_CR_RXEN 0x0008
-#define SONIC_CR_STP 0x0010
-#define SONIC_CR_ST 0x0020
-#define SONIC_CR_RST 0x0080
-#define SONIC_CR_RRRA 0x0100
-#define SONIC_CR_LCAM 0x0200
-#define SONIC_CR_MASK 0x03bf
-
-#define SONIC_DCR_DW 0x0020
-#define SONIC_DCR_LBR 0x2000
-#define SONIC_DCR_EXBUS 0x8000
-
-#define SONIC_RCR_PRX 0x0001
-#define SONIC_RCR_LBK 0x0002
-#define SONIC_RCR_FAER 0x0004
-#define SONIC_RCR_CRCR 0x0008
-#define SONIC_RCR_CRS 0x0020
-#define SONIC_RCR_LPKT 0x0040
-#define SONIC_RCR_BC 0x0080
-#define SONIC_RCR_MC 0x0100
-#define SONIC_RCR_LB0 0x0200
-#define SONIC_RCR_LB1 0x0400
-#define SONIC_RCR_AMC 0x0800
-#define SONIC_RCR_PRO 0x1000
-#define SONIC_RCR_BRD 0x2000
-#define SONIC_RCR_RNT 0x4000
-
-#define SONIC_TCR_PTX 0x0001
-#define SONIC_TCR_BCM 0x0002
-#define SONIC_TCR_FU 0x0004
-#define SONIC_TCR_EXC 0x0040
-#define SONIC_TCR_CRSL 0x0080
-#define SONIC_TCR_NCRS 0x0100
-#define SONIC_TCR_EXD 0x0400
-#define SONIC_TCR_CRCI 0x2000
-#define SONIC_TCR_PINT 0x8000
-
-#define SONIC_ISR_RBE 0x0020
-#define SONIC_ISR_RDE 0x0040
-#define SONIC_ISR_TC 0x0080
-#define SONIC_ISR_TXDN 0x0200
-#define SONIC_ISR_PKTRX 0x0400
-#define SONIC_ISR_PINT 0x0800
-#define SONIC_ISR_LCD 0x1000
-
-#define TYPE_DP8393X "dp8393x"
-#define DP8393X(obj) OBJECT_CHECK(dp8393xState, (obj), TYPE_DP8393X)
-
-typedef struct dp8393xState {
- SysBusDevice parent_obj;
-
- /* Hardware */
- uint8_t it_shift;
- qemu_irq irq;
-#ifdef DEBUG_SONIC
- int irq_level;
-#endif
- QEMUTimer *watchdog;
- int64_t wt_last_update;
- NICConf conf;
- NICState *nic;
- MemoryRegion mmio;
- MemoryRegion prom;
-
- /* Registers */
- uint8_t cam[16][6];
- uint16_t regs[0x40];
-
- /* Temporaries */
- uint8_t tx_buffer[0x10000];
- int loopback_packet;
-
- /* Memory access */
- void *dma_mr;
- AddressSpace as;
-} dp8393xState;
-
-static void dp8393x_update_irq(dp8393xState *s)
-{
- int level = (s->regs[SONIC_IMR] & s->regs[SONIC_ISR]) ? 1 : 0;
-
-#ifdef DEBUG_SONIC
- if (level != s->irq_level) {
- s->irq_level = level;
- if (level) {
- DPRINTF("raise irq, isr is 0x%04x\n", s->regs[SONIC_ISR]);
- } else {
- DPRINTF("lower irq\n");
- }
- }
-#endif
-
- qemu_set_irq(s->irq, level);
-}
-
-static void dp8393x_do_load_cam(dp8393xState *s)
-{
- uint16_t data[8];
- int width, size;
- uint16_t index = 0;
-
- width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
- size = sizeof(uint16_t) * 4 * width;
-
- while (s->regs[SONIC_CDC] & 0x1f) {
- /* Fill current entry */
- address_space_rw(&s->as,
- (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP],
- MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
- s->cam[index][0] = data[1 * width] & 0xff;
- s->cam[index][1] = data[1 * width] >> 8;
- s->cam[index][2] = data[2 * width] & 0xff;
- s->cam[index][3] = data[2 * width] >> 8;
- s->cam[index][4] = data[3 * width] & 0xff;
- s->cam[index][5] = data[3 * width] >> 8;
- DPRINTF("load cam[%d] with %02x%02x%02x%02x%02x%02x\n", index,
- s->cam[index][0], s->cam[index][1], s->cam[index][2],
- s->cam[index][3], s->cam[index][4], s->cam[index][5]);
- /* Move to next entry */
- s->regs[SONIC_CDC]--;
- s->regs[SONIC_CDP] += size;
- index++;
- }
-
- /* Read CAM enable */
- address_space_rw(&s->as,
- (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP],
- MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
- s->regs[SONIC_CE] = data[0 * width];
- DPRINTF("load cam done. cam enable mask 0x%04x\n", s->regs[SONIC_CE]);
-
- /* Done */
- s->regs[SONIC_CR] &= ~SONIC_CR_LCAM;
- s->regs[SONIC_ISR] |= SONIC_ISR_LCD;
- dp8393x_update_irq(s);
-}
-
-static void dp8393x_do_read_rra(dp8393xState *s)
-{
- uint16_t data[8];
- int width, size;
-
- /* Read memory */
- width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
- size = sizeof(uint16_t) * 4 * width;
- address_space_rw(&s->as,
- (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_RRP],
- MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
-
- /* Update SONIC registers */
- s->regs[SONIC_CRBA0] = data[0 * width];
- s->regs[SONIC_CRBA1] = data[1 * width];
- s->regs[SONIC_RBWC0] = data[2 * width];
- s->regs[SONIC_RBWC1] = data[3 * width];
- DPRINTF("CRBA0/1: 0x%04x/0x%04x, RBWC0/1: 0x%04x/0x%04x\n",
- s->regs[SONIC_CRBA0], s->regs[SONIC_CRBA1],
- s->regs[SONIC_RBWC0], s->regs[SONIC_RBWC1]);
-
- /* Go to next entry */
- s->regs[SONIC_RRP] += size;
-
- /* Handle wrap */
- if (s->regs[SONIC_RRP] == s->regs[SONIC_REA]) {
- s->regs[SONIC_RRP] = s->regs[SONIC_RSA];
- }
-
- /* Check resource exhaustion */
- if (s->regs[SONIC_RRP] == s->regs[SONIC_RWP])
- {
- s->regs[SONIC_ISR] |= SONIC_ISR_RBE;
- dp8393x_update_irq(s);
- }
-
- /* Done */
- s->regs[SONIC_CR] &= ~SONIC_CR_RRRA;
-}
-
-static void dp8393x_do_software_reset(dp8393xState *s)
-{
- timer_del(s->watchdog);
-
- s->regs[SONIC_CR] &= ~(SONIC_CR_LCAM | SONIC_CR_RRRA | SONIC_CR_TXP | SONIC_CR_HTX);
- s->regs[SONIC_CR] |= SONIC_CR_RST | SONIC_CR_RXDIS;
-}
-
-static void dp8393x_set_next_tick(dp8393xState *s)
-{
- uint32_t ticks;
- int64_t delay;
-
- if (s->regs[SONIC_CR] & SONIC_CR_STP) {
- timer_del(s->watchdog);
- return;
- }
-
- ticks = s->regs[SONIC_WT1] << 16 | s->regs[SONIC_WT0];
- s->wt_last_update = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- delay = NANOSECONDS_PER_SECOND * ticks / 5000000;
- timer_mod(s->watchdog, s->wt_last_update + delay);
-}
-
-static void dp8393x_update_wt_regs(dp8393xState *s)
-{
- int64_t elapsed;
- uint32_t val;
-
- if (s->regs[SONIC_CR] & SONIC_CR_STP) {
- timer_del(s->watchdog);
- return;
- }
-
- elapsed = s->wt_last_update - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- val = s->regs[SONIC_WT1] << 16 | s->regs[SONIC_WT0];
- val -= elapsed / 5000000;
- s->regs[SONIC_WT1] = (val >> 16) & 0xffff;
- s->regs[SONIC_WT0] = (val >> 0) & 0xffff;
- dp8393x_set_next_tick(s);
-
-}
-
-static void dp8393x_do_start_timer(dp8393xState *s)
-{
- s->regs[SONIC_CR] &= ~SONIC_CR_STP;
- dp8393x_set_next_tick(s);
-}
-
-static void dp8393x_do_stop_timer(dp8393xState *s)
-{
- s->regs[SONIC_CR] &= ~SONIC_CR_ST;
- dp8393x_update_wt_regs(s);
-}
-
-static int dp8393x_can_receive(NetClientState *nc);
-
-static void dp8393x_do_receiver_enable(dp8393xState *s)
-{
- s->regs[SONIC_CR] &= ~SONIC_CR_RXDIS;
- if (dp8393x_can_receive(s->nic->ncs)) {
- qemu_flush_queued_packets(qemu_get_queue(s->nic));
- }
-}
-
-static void dp8393x_do_receiver_disable(dp8393xState *s)
-{
- s->regs[SONIC_CR] &= ~SONIC_CR_RXEN;
-}
-
-static void dp8393x_do_transmit_packets(dp8393xState *s)
-{
- NetClientState *nc = qemu_get_queue(s->nic);
- uint16_t data[12];
- int width, size;
- int tx_len, len;
- uint16_t i;
-
- width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
-
- while (1) {
- /* Read memory */
- DPRINTF("Transmit packet at %08x\n",
- (s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_CTDA]);
- size = sizeof(uint16_t) * 6 * width;
- s->regs[SONIC_TTDA] = s->regs[SONIC_CTDA];
- address_space_rw(&s->as,
- ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * width,
- MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
- tx_len = 0;
-
- /* Update registers */
- s->regs[SONIC_TCR] = data[0 * width] & 0xf000;
- s->regs[SONIC_TPS] = data[1 * width];
- s->regs[SONIC_TFC] = data[2 * width];
- s->regs[SONIC_TSA0] = data[3 * width];
- s->regs[SONIC_TSA1] = data[4 * width];
- s->regs[SONIC_TFS] = data[5 * width];
-
- /* Handle programmable interrupt */
- if (s->regs[SONIC_TCR] & SONIC_TCR_PINT) {
- s->regs[SONIC_ISR] |= SONIC_ISR_PINT;
- } else {
- s->regs[SONIC_ISR] &= ~SONIC_ISR_PINT;
- }
-
- for (i = 0; i < s->regs[SONIC_TFC]; ) {
- /* Append fragment */
- len = s->regs[SONIC_TFS];
- if (tx_len + len > sizeof(s->tx_buffer)) {
- len = sizeof(s->tx_buffer) - tx_len;
- }
- address_space_rw(&s->as,
- (s->regs[SONIC_TSA1] << 16) | s->regs[SONIC_TSA0],
- MEMTXATTRS_UNSPECIFIED, &s->tx_buffer[tx_len], len, 0);
- tx_len += len;
-
- i++;
- if (i != s->regs[SONIC_TFC]) {
- /* Read next fragment details */
- size = sizeof(uint16_t) * 3 * width;
- address_space_rw(&s->as,
- ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * (4 + 3 * i) * width,
- MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
- s->regs[SONIC_TSA0] = data[0 * width];
- s->regs[SONIC_TSA1] = data[1 * width];
- s->regs[SONIC_TFS] = data[2 * width];
- }
- }
-
- /* Handle Ethernet checksum */
- if (!(s->regs[SONIC_TCR] & SONIC_TCR_CRCI)) {
- /* Don't append FCS there, to look like slirp packets
- * which don't have one */
- } else {
- /* Remove existing FCS */
- tx_len -= 4;
- }
-
- if (s->regs[SONIC_RCR] & (SONIC_RCR_LB1 | SONIC_RCR_LB0)) {
- /* Loopback */
- s->regs[SONIC_TCR] |= SONIC_TCR_CRSL;
- if (nc->info->can_receive(nc)) {
- s->loopback_packet = 1;
- nc->info->receive(nc, s->tx_buffer, tx_len);
- }
- } else {
- /* Transmit packet */
- qemu_send_packet(nc, s->tx_buffer, tx_len);
- }
- s->regs[SONIC_TCR] |= SONIC_TCR_PTX;
-
- /* Write status */
- data[0 * width] = s->regs[SONIC_TCR] & 0x0fff; /* status */
- size = sizeof(uint16_t) * width;
- address_space_rw(&s->as,
- (s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA],
- MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 1);
-
- if (!(s->regs[SONIC_CR] & SONIC_CR_HTX)) {
- /* Read footer of packet */
- size = sizeof(uint16_t) * width;
- address_space_rw(&s->as,
- ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * (4 + 3 * s->regs[SONIC_TFC]) * width,
- MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
- s->regs[SONIC_CTDA] = data[0 * width] & ~0x1;
- if (data[0 * width] & 0x1) {
- /* EOL detected */
- break;
- }
- }
- }
-
- /* Done */
- s->regs[SONIC_CR] &= ~SONIC_CR_TXP;
- s->regs[SONIC_ISR] |= SONIC_ISR_TXDN;
- dp8393x_update_irq(s);
-}
-
-static void dp8393x_do_halt_transmission(dp8393xState *s)
-{
- /* Nothing to do */
-}
-
-static void dp8393x_do_command(dp8393xState *s, uint16_t command)
-{
- if ((s->regs[SONIC_CR] & SONIC_CR_RST) && !(command & SONIC_CR_RST)) {
- s->regs[SONIC_CR] &= ~SONIC_CR_RST;
- return;
- }
-
- s->regs[SONIC_CR] |= (command & SONIC_CR_MASK);
-
- if (command & SONIC_CR_HTX)
- dp8393x_do_halt_transmission(s);
- if (command & SONIC_CR_TXP)
- dp8393x_do_transmit_packets(s);
- if (command & SONIC_CR_RXDIS)
- dp8393x_do_receiver_disable(s);
- if (command & SONIC_CR_RXEN)
- dp8393x_do_receiver_enable(s);
- if (command & SONIC_CR_STP)
- dp8393x_do_stop_timer(s);
- if (command & SONIC_CR_ST)
- dp8393x_do_start_timer(s);
- if (command & SONIC_CR_RST)
- dp8393x_do_software_reset(s);
- if (command & SONIC_CR_RRRA)
- dp8393x_do_read_rra(s);
- if (command & SONIC_CR_LCAM)
- dp8393x_do_load_cam(s);
-}
-
-static uint64_t dp8393x_read(void *opaque, hwaddr addr, unsigned int size)
-{
- dp8393xState *s = opaque;
- int reg = addr >> s->it_shift;
- uint16_t val = 0;
-
- switch (reg) {
- /* Update data before reading it */
- case SONIC_WT0:
- case SONIC_WT1:
- dp8393x_update_wt_regs(s);
- val = s->regs[reg];
- break;
- /* Accept read to some registers only when in reset mode */
- case SONIC_CAP2:
- case SONIC_CAP1:
- case SONIC_CAP0:
- if (s->regs[SONIC_CR] & SONIC_CR_RST) {
- val = s->cam[s->regs[SONIC_CEP] & 0xf][2* (SONIC_CAP0 - reg) + 1] << 8;
- val |= s->cam[s->regs[SONIC_CEP] & 0xf][2* (SONIC_CAP0 - reg)];
- }
- break;
- /* All other registers have no special contrainst */
- default:
- val = s->regs[reg];
- }
-
- DPRINTF("read 0x%04x from reg %s\n", val, reg_names[reg]);
-
- return val;
-}
-
-static void dp8393x_write(void *opaque, hwaddr addr, uint64_t data,
- unsigned int size)
-{
- dp8393xState *s = opaque;
- int reg = addr >> s->it_shift;
-
- DPRINTF("write 0x%04x to reg %s\n", (uint16_t)data, reg_names[reg]);
-
- switch (reg) {
- /* Command register */
- case SONIC_CR:
- dp8393x_do_command(s, data);
- break;
- /* Prevent write to read-only registers */
- case SONIC_CAP2:
- case SONIC_CAP1:
- case SONIC_CAP0:
- case SONIC_SR:
- case SONIC_MDT:
- DPRINTF("writing to reg %d invalid\n", reg);
- break;
- /* Accept write to some registers only when in reset mode */
- case SONIC_DCR:
- if (s->regs[SONIC_CR] & SONIC_CR_RST) {
- s->regs[reg] = data & 0xbfff;
- } else {
- DPRINTF("writing to DCR invalid\n");
- }
- break;
- case SONIC_DCR2:
- if (s->regs[SONIC_CR] & SONIC_CR_RST) {
- s->regs[reg] = data & 0xf017;
- } else {
- DPRINTF("writing to DCR2 invalid\n");
- }
- break;
- /* 12 lower bytes are Read Only */
- case SONIC_TCR:
- s->regs[reg] = data & 0xf000;
- break;
- /* 9 lower bytes are Read Only */
- case SONIC_RCR:
- s->regs[reg] = data & 0xffe0;
- break;
- /* Ignore most significant bit */
- case SONIC_IMR:
- s->regs[reg] = data & 0x7fff;
- dp8393x_update_irq(s);
- break;
- /* Clear bits by writing 1 to them */
- case SONIC_ISR:
- data &= s->regs[reg];
- s->regs[reg] &= ~data;
- if (data & SONIC_ISR_RBE) {
- dp8393x_do_read_rra(s);
- }
- dp8393x_update_irq(s);
- if (dp8393x_can_receive(s->nic->ncs)) {
- qemu_flush_queued_packets(qemu_get_queue(s->nic));
- }
- break;
- /* Ignore least significant bit */
- case SONIC_RSA:
- case SONIC_REA:
- case SONIC_RRP:
- case SONIC_RWP:
- s->regs[reg] = data & 0xfffe;
- break;
- /* Invert written value for some registers */
- case SONIC_CRCT:
- case SONIC_FAET:
- case SONIC_MPT:
- s->regs[reg] = data ^ 0xffff;
- break;
- /* All other registers have no special contrainst */
- default:
- s->regs[reg] = data;
- }
-
- if (reg == SONIC_WT0 || reg == SONIC_WT1) {
- dp8393x_set_next_tick(s);
- }
-}
-
-static const MemoryRegionOps dp8393x_ops = {
- .read = dp8393x_read,
- .write = dp8393x_write,
- .impl.min_access_size = 2,
- .impl.max_access_size = 2,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void dp8393x_watchdog(void *opaque)
-{
- dp8393xState *s = opaque;
-
- if (s->regs[SONIC_CR] & SONIC_CR_STP) {
- return;
- }
-
- s->regs[SONIC_WT1] = 0xffff;
- s->regs[SONIC_WT0] = 0xffff;
- dp8393x_set_next_tick(s);
-
- /* Signal underflow */
- s->regs[SONIC_ISR] |= SONIC_ISR_TC;
- dp8393x_update_irq(s);
-}
-
-static int dp8393x_can_receive(NetClientState *nc)
-{
- dp8393xState *s = qemu_get_nic_opaque(nc);
-
- if (!(s->regs[SONIC_CR] & SONIC_CR_RXEN))
- return 0;
- if (s->regs[SONIC_ISR] & SONIC_ISR_RBE)
- return 0;
- return 1;
-}
-
-static int dp8393x_receive_filter(dp8393xState *s, const uint8_t * buf,
- int size)
-{
- static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
- int i;
-
- /* Check promiscuous mode */
- if ((s->regs[SONIC_RCR] & SONIC_RCR_PRO) && (buf[0] & 1) == 0) {
- return 0;
- }
-
- /* Check multicast packets */
- if ((s->regs[SONIC_RCR] & SONIC_RCR_AMC) && (buf[0] & 1) == 1) {
- return SONIC_RCR_MC;
- }
-
- /* Check broadcast */
- if ((s->regs[SONIC_RCR] & SONIC_RCR_BRD) && !memcmp(buf, bcast, sizeof(bcast))) {
- return SONIC_RCR_BC;
- }
-
- /* Check CAM */
- for (i = 0; i < 16; i++) {
- if (s->regs[SONIC_CE] & (1 << i)) {
- /* Entry enabled */
- if (!memcmp(buf, s->cam[i], sizeof(s->cam[i]))) {
- return 0;
- }
- }
- }
-
- return -1;
-}
-
-static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf,
- size_t size)
-{
- dp8393xState *s = qemu_get_nic_opaque(nc);
- uint16_t data[10];
- int packet_type;
- uint32_t available, address;
- int width, rx_len = size;
- uint32_t checksum;
-
- width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
-
- s->regs[SONIC_RCR] &= ~(SONIC_RCR_PRX | SONIC_RCR_LBK | SONIC_RCR_FAER |
- SONIC_RCR_CRCR | SONIC_RCR_LPKT | SONIC_RCR_BC | SONIC_RCR_MC);
-
- packet_type = dp8393x_receive_filter(s, buf, size);
- if (packet_type < 0) {
- DPRINTF("packet not for netcard\n");
- return -1;
- }
-
- /* XXX: Check byte ordering */
-
- /* Check for EOL */
- if (s->regs[SONIC_LLFA] & 0x1) {
- /* Are we still in resource exhaustion? */
- size = sizeof(uint16_t) * 1 * width;
- address = ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 5 * width;
- address_space_rw(&s->as, address, MEMTXATTRS_UNSPECIFIED,
- (uint8_t *)data, size, 0);
- if (data[0 * width] & 0x1) {
- /* Still EOL ; stop reception */
- return -1;
- } else {
- s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA];
- }
- }
-
- /* Save current position */
- s->regs[SONIC_TRBA1] = s->regs[SONIC_CRBA1];
- s->regs[SONIC_TRBA0] = s->regs[SONIC_CRBA0];
-
- /* Calculate the ethernet checksum */
- checksum = cpu_to_le32(crc32(0, buf, rx_len));
-
- /* Put packet into RBA */
- DPRINTF("Receive packet at %08x\n", (s->regs[SONIC_CRBA1] << 16) | s->regs[SONIC_CRBA0]);
- address = (s->regs[SONIC_CRBA1] << 16) | s->regs[SONIC_CRBA0];
- address_space_rw(&s->as, address,
- MEMTXATTRS_UNSPECIFIED, (uint8_t *)buf, rx_len, 1);
- address += rx_len;
- address_space_rw(&s->as, address,
- MEMTXATTRS_UNSPECIFIED, (uint8_t *)&checksum, 4, 1);
- rx_len += 4;
- s->regs[SONIC_CRBA1] = address >> 16;
- s->regs[SONIC_CRBA0] = address & 0xffff;
- available = (s->regs[SONIC_RBWC1] << 16) | s->regs[SONIC_RBWC0];
- available -= rx_len / 2;
- s->regs[SONIC_RBWC1] = available >> 16;
- s->regs[SONIC_RBWC0] = available & 0xffff;
-
- /* Update status */
- if (((s->regs[SONIC_RBWC1] << 16) | s->regs[SONIC_RBWC0]) < s->regs[SONIC_EOBC]) {
- s->regs[SONIC_RCR] |= SONIC_RCR_LPKT;
- }
- s->regs[SONIC_RCR] |= packet_type;
- s->regs[SONIC_RCR] |= SONIC_RCR_PRX;
- if (s->loopback_packet) {
- s->regs[SONIC_RCR] |= SONIC_RCR_LBK;
- s->loopback_packet = 0;
- }
-
- /* Write status to memory */
- DPRINTF("Write status at %08x\n", (s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]);
- data[0 * width] = s->regs[SONIC_RCR]; /* status */
- data[1 * width] = rx_len; /* byte count */
- data[2 * width] = s->regs[SONIC_TRBA0]; /* pkt_ptr0 */
- data[3 * width] = s->regs[SONIC_TRBA1]; /* pkt_ptr1 */
- data[4 * width] = s->regs[SONIC_RSC]; /* seq_no */
- size = sizeof(uint16_t) * 5 * width;
- address_space_rw(&s->as, (s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA],
- MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 1);
-
- /* Move to next descriptor */
- size = sizeof(uint16_t) * width;
- address_space_rw(&s->as,
- ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 5 * width,
- MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
- s->regs[SONIC_LLFA] = data[0 * width];
- if (s->regs[SONIC_LLFA] & 0x1) {
- /* EOL detected */
- s->regs[SONIC_ISR] |= SONIC_ISR_RDE;
- } else {
- data[0 * width] = 0; /* in_use */
- address_space_rw(&s->as,
- ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 6 * width,
- MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, sizeof(uint16_t), 1);
- s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA];
- s->regs[SONIC_ISR] |= SONIC_ISR_PKTRX;
- s->regs[SONIC_RSC] = (s->regs[SONIC_RSC] & 0xff00) | (((s->regs[SONIC_RSC] & 0x00ff) + 1) & 0x00ff);
-
- if (s->regs[SONIC_RCR] & SONIC_RCR_LPKT) {
- /* Read next RRA */
- dp8393x_do_read_rra(s);
- }
- }
-
- /* Done */
- dp8393x_update_irq(s);
-
- return size;
-}
-
-static void dp8393x_reset(DeviceState *dev)
-{
- dp8393xState *s = DP8393X(dev);
- timer_del(s->watchdog);
-
- memset(s->regs, 0, sizeof(s->regs));
- s->regs[SONIC_CR] = SONIC_CR_RST | SONIC_CR_STP | SONIC_CR_RXDIS;
- s->regs[SONIC_DCR] &= ~(SONIC_DCR_EXBUS | SONIC_DCR_LBR);
- s->regs[SONIC_RCR] &= ~(SONIC_RCR_LB0 | SONIC_RCR_LB1 | SONIC_RCR_BRD | SONIC_RCR_RNT);
- s->regs[SONIC_TCR] |= SONIC_TCR_NCRS | SONIC_TCR_PTX;
- s->regs[SONIC_TCR] &= ~SONIC_TCR_BCM;
- s->regs[SONIC_IMR] = 0;
- s->regs[SONIC_ISR] = 0;
- s->regs[SONIC_DCR2] = 0;
- s->regs[SONIC_EOBC] = 0x02F8;
- s->regs[SONIC_RSC] = 0;
- s->regs[SONIC_CE] = 0;
- s->regs[SONIC_RSC] = 0;
-
- /* Network cable is connected */
- s->regs[SONIC_RCR] |= SONIC_RCR_CRS;
-
- dp8393x_update_irq(s);
-}
-
-static NetClientInfo net_dp83932_info = {
- .type = NET_CLIENT_OPTIONS_KIND_NIC,
- .size = sizeof(NICState),
- .can_receive = dp8393x_can_receive,
- .receive = dp8393x_receive,
-};
-
-static void dp8393x_instance_init(Object *obj)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- dp8393xState *s = DP8393X(obj);
-
- sysbus_init_mmio(sbd, &s->mmio);
- sysbus_init_mmio(sbd, &s->prom);
- sysbus_init_irq(sbd, &s->irq);
-}
-
-static void dp8393x_realize(DeviceState *dev, Error **errp)
-{
- dp8393xState *s = DP8393X(dev);
- int i, checksum;
- uint8_t *prom;
- Error *local_err = NULL;
-
- address_space_init(&s->as, s->dma_mr, "dp8393x");
- memory_region_init_io(&s->mmio, OBJECT(dev), &dp8393x_ops, s,
- "dp8393x-regs", 0x40 << s->it_shift);
-
- s->nic = qemu_new_nic(&net_dp83932_info, &s->conf,
- object_get_typename(OBJECT(dev)), dev->id, s);
- qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-
- s->watchdog = timer_new_ns(QEMU_CLOCK_VIRTUAL, dp8393x_watchdog, s);
- s->regs[SONIC_SR] = 0x0004; /* only revision recognized by Linux */
-
- memory_region_init_ram(&s->prom, OBJECT(dev),
- "dp8393x-prom", SONIC_PROM_SIZE, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
- memory_region_set_readonly(&s->prom, true);
- prom = memory_region_get_ram_ptr(&s->prom);
- checksum = 0;
- for (i = 0; i < 6; i++) {
- prom[i] = s->conf.macaddr.a[i];
- checksum += prom[i];
- if (checksum > 0xff) {
- checksum = (checksum + 1) & 0xff;
- }
- }
- prom[7] = 0xff - checksum;
-}
-
-static const VMStateDescription vmstate_dp8393x = {
- .name = "dp8393x",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField []) {
- VMSTATE_BUFFER_UNSAFE(cam, dp8393xState, 0, 16 * 6),
- VMSTATE_UINT16_ARRAY(regs, dp8393xState, 0x40),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property dp8393x_properties[] = {
- DEFINE_NIC_PROPERTIES(dp8393xState, conf),
- DEFINE_PROP_PTR("dma_mr", dp8393xState, dma_mr),
- DEFINE_PROP_UINT8("it_shift", dp8393xState, it_shift, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void dp8393x_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
- dc->realize = dp8393x_realize;
- dc->reset = dp8393x_reset;
- dc->vmsd = &vmstate_dp8393x;
- dc->props = dp8393x_properties;
- /* Reason: dma_mr property can't be set */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo dp8393x_info = {
- .name = TYPE_DP8393X,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(dp8393xState),
- .instance_init = dp8393x_instance_init,
- .class_init = dp8393x_class_init,
-};
-
-static void dp8393x_register_types(void)
-{
- type_register_static(&dp8393x_info);
-}
-
-type_init(dp8393x_register_types)
diff --git a/qemu/hw/net/e1000.c b/qemu/hw/net/e1000.c
deleted file mode 100644
index 8e79b550e..000000000
--- a/qemu/hw/net/e1000.c
+++ /dev/null
@@ -1,1959 +0,0 @@
-/*
- * QEMU e1000 emulation
- *
- * Software developer's manual:
- * http://download.intel.com/design/network/manuals/8254x_GBe_SDM.pdf
- *
- * Nir Peleg, Tutis Systems Ltd. for Qumranet Inc.
- * Copyright (c) 2008 Qumranet
- * Based on work done by:
- * Copyright (c) 2007 Dan Aloni
- * Copyright (c) 2004 Antony T Curtis
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/pci/pci.h"
-#include "net/net.h"
-#include "net/checksum.h"
-#include "hw/loader.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/dma.h"
-#include "qemu/iov.h"
-#include "qemu/range.h"
-
-#include "e1000_regs.h"
-
-static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-
-#define E1000_DEBUG
-
-#ifdef E1000_DEBUG
-enum {
- DEBUG_GENERAL, DEBUG_IO, DEBUG_MMIO, DEBUG_INTERRUPT,
- DEBUG_RX, DEBUG_TX, DEBUG_MDIC, DEBUG_EEPROM,
- DEBUG_UNKNOWN, DEBUG_TXSUM, DEBUG_TXERR, DEBUG_RXERR,
- DEBUG_RXFILTER, DEBUG_PHY, DEBUG_NOTYET,
-};
-#define DBGBIT(x) (1<<DEBUG_##x)
-static int debugflags = DBGBIT(TXERR) | DBGBIT(GENERAL);
-
-#define DBGOUT(what, fmt, ...) do { \
- if (debugflags & DBGBIT(what)) \
- fprintf(stderr, "e1000: " fmt, ## __VA_ARGS__); \
- } while (0)
-#else
-#define DBGOUT(what, fmt, ...) do {} while (0)
-#endif
-
-#define IOPORT_SIZE 0x40
-#define PNPMMIO_SIZE 0x20000
-#define MIN_BUF_SIZE 60 /* Min. octets in an ethernet frame sans FCS */
-
-/* this is the size past which hardware will drop packets when setting LPE=0 */
-#define MAXIMUM_ETHERNET_VLAN_SIZE 1522
-/* this is the size past which hardware will drop packets when setting LPE=1 */
-#define MAXIMUM_ETHERNET_LPE_SIZE 16384
-
-#define MAXIMUM_ETHERNET_HDR_LEN (14+4)
-
-/*
- * HW models:
- * E1000_DEV_ID_82540EM works with Windows, Linux, and OS X <= 10.8
- * E1000_DEV_ID_82544GC_COPPER appears to work; not well tested
- * E1000_DEV_ID_82545EM_COPPER works with Linux and OS X >= 10.6
- * Others never tested
- */
-
-typedef struct E1000State_st {
- /*< private >*/
- PCIDevice parent_obj;
- /*< public >*/
-
- NICState *nic;
- NICConf conf;
- MemoryRegion mmio;
- MemoryRegion io;
-
- uint32_t mac_reg[0x8000];
- uint16_t phy_reg[0x20];
- uint16_t eeprom_data[64];
-
- uint32_t rxbuf_size;
- uint32_t rxbuf_min_shift;
- struct e1000_tx {
- unsigned char header[256];
- unsigned char vlan_header[4];
- /* Fields vlan and data must not be reordered or separated. */
- unsigned char vlan[4];
- unsigned char data[0x10000];
- uint16_t size;
- unsigned char sum_needed;
- unsigned char vlan_needed;
- uint8_t ipcss;
- uint8_t ipcso;
- uint16_t ipcse;
- uint8_t tucss;
- uint8_t tucso;
- uint16_t tucse;
- uint8_t hdr_len;
- uint16_t mss;
- uint32_t paylen;
- uint16_t tso_frames;
- char tse;
- int8_t ip;
- int8_t tcp;
- char cptse; // current packet tse bit
- } tx;
-
- struct {
- uint32_t val_in; /* shifted in from guest driver */
- uint16_t bitnum_in;
- uint16_t bitnum_out;
- uint16_t reading;
- uint32_t old_eecd;
- } eecd_state;
-
- QEMUTimer *autoneg_timer;
-
- QEMUTimer *mit_timer; /* Mitigation timer. */
- bool mit_timer_on; /* Mitigation timer is running. */
- bool mit_irq_level; /* Tracks interrupt pin level. */
- uint32_t mit_ide; /* Tracks E1000_TXD_CMD_IDE bit. */
-
-/* Compatibility flags for migration to/from qemu 1.3.0 and older */
-#define E1000_FLAG_AUTONEG_BIT 0
-#define E1000_FLAG_MIT_BIT 1
-#define E1000_FLAG_MAC_BIT 2
-#define E1000_FLAG_AUTONEG (1 << E1000_FLAG_AUTONEG_BIT)
-#define E1000_FLAG_MIT (1 << E1000_FLAG_MIT_BIT)
-#define E1000_FLAG_MAC (1 << E1000_FLAG_MAC_BIT)
- uint32_t compat_flags;
-} E1000State;
-
-#define chkflag(x) (s->compat_flags & E1000_FLAG_##x)
-
-typedef struct E1000BaseClass {
- PCIDeviceClass parent_class;
- uint16_t phy_id2;
-} E1000BaseClass;
-
-#define TYPE_E1000_BASE "e1000-base"
-
-#define E1000(obj) \
- OBJECT_CHECK(E1000State, (obj), TYPE_E1000_BASE)
-
-#define E1000_DEVICE_CLASS(klass) \
- OBJECT_CLASS_CHECK(E1000BaseClass, (klass), TYPE_E1000_BASE)
-#define E1000_DEVICE_GET_CLASS(obj) \
- OBJECT_GET_CLASS(E1000BaseClass, (obj), TYPE_E1000_BASE)
-
-#define defreg(x) x = (E1000_##x>>2)
-enum {
- defreg(CTRL), defreg(EECD), defreg(EERD), defreg(GPRC),
- defreg(GPTC), defreg(ICR), defreg(ICS), defreg(IMC),
- defreg(IMS), defreg(LEDCTL), defreg(MANC), defreg(MDIC),
- defreg(MPC), defreg(PBA), defreg(RCTL), defreg(RDBAH),
- defreg(RDBAL), defreg(RDH), defreg(RDLEN), defreg(RDT),
- defreg(STATUS), defreg(SWSM), defreg(TCTL), defreg(TDBAH),
- defreg(TDBAL), defreg(TDH), defreg(TDLEN), defreg(TDT),
- defreg(TORH), defreg(TORL), defreg(TOTH), defreg(TOTL),
- defreg(TPR), defreg(TPT), defreg(TXDCTL), defreg(WUFC),
- defreg(RA), defreg(MTA), defreg(CRCERRS), defreg(VFTA),
- defreg(VET), defreg(RDTR), defreg(RADV), defreg(TADV),
- defreg(ITR), defreg(FCRUC), defreg(TDFH), defreg(TDFT),
- defreg(TDFHS), defreg(TDFTS), defreg(TDFPC), defreg(RDFH),
- defreg(RDFT), defreg(RDFHS), defreg(RDFTS), defreg(RDFPC),
- defreg(IPAV), defreg(WUC), defreg(WUS), defreg(AIT),
- defreg(IP6AT), defreg(IP4AT), defreg(FFLT), defreg(FFMT),
- defreg(FFVT), defreg(WUPM), defreg(PBM), defreg(SCC),
- defreg(ECOL), defreg(MCC), defreg(LATECOL), defreg(COLC),
- defreg(DC), defreg(TNCRS), defreg(SEC), defreg(CEXTERR),
- defreg(RLEC), defreg(XONRXC), defreg(XONTXC), defreg(XOFFRXC),
- defreg(XOFFTXC), defreg(RFC), defreg(RJC), defreg(RNBC),
- defreg(TSCTFC), defreg(MGTPRC), defreg(MGTPDC), defreg(MGTPTC),
- defreg(RUC), defreg(ROC), defreg(GORCL), defreg(GORCH),
- defreg(GOTCL), defreg(GOTCH), defreg(BPRC), defreg(MPRC),
- defreg(TSCTC), defreg(PRC64), defreg(PRC127), defreg(PRC255),
- defreg(PRC511), defreg(PRC1023), defreg(PRC1522), defreg(PTC64),
- defreg(PTC127), defreg(PTC255), defreg(PTC511), defreg(PTC1023),
- defreg(PTC1522), defreg(MPTC), defreg(BPTC)
-};
-
-static void
-e1000_link_down(E1000State *s)
-{
- s->mac_reg[STATUS] &= ~E1000_STATUS_LU;
- s->phy_reg[PHY_STATUS] &= ~MII_SR_LINK_STATUS;
- s->phy_reg[PHY_STATUS] &= ~MII_SR_AUTONEG_COMPLETE;
- s->phy_reg[PHY_LP_ABILITY] &= ~MII_LPAR_LPACK;
-}
-
-static void
-e1000_link_up(E1000State *s)
-{
- s->mac_reg[STATUS] |= E1000_STATUS_LU;
- s->phy_reg[PHY_STATUS] |= MII_SR_LINK_STATUS;
-
- /* E1000_STATUS_LU is tested by e1000_can_receive() */
- qemu_flush_queued_packets(qemu_get_queue(s->nic));
-}
-
-static bool
-have_autoneg(E1000State *s)
-{
- return chkflag(AUTONEG) && (s->phy_reg[PHY_CTRL] & MII_CR_AUTO_NEG_EN);
-}
-
-static void
-set_phy_ctrl(E1000State *s, int index, uint16_t val)
-{
- /* bits 0-5 reserved; MII_CR_[RESTART_AUTO_NEG,RESET] are self clearing */
- s->phy_reg[PHY_CTRL] = val & ~(0x3f |
- MII_CR_RESET |
- MII_CR_RESTART_AUTO_NEG);
-
- /*
- * QEMU 1.3 does not support link auto-negotiation emulation, so if we
- * migrate during auto negotiation, after migration the link will be
- * down.
- */
- if (have_autoneg(s) && (val & MII_CR_RESTART_AUTO_NEG)) {
- e1000_link_down(s);
- DBGOUT(PHY, "Start link auto negotiation\n");
- timer_mod(s->autoneg_timer,
- qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 500);
- }
-}
-
-static void (*phyreg_writeops[])(E1000State *, int, uint16_t) = {
- [PHY_CTRL] = set_phy_ctrl,
-};
-
-enum { NPHYWRITEOPS = ARRAY_SIZE(phyreg_writeops) };
-
-enum { PHY_R = 1, PHY_W = 2, PHY_RW = PHY_R | PHY_W };
-static const char phy_regcap[0x20] = {
- [PHY_STATUS] = PHY_R, [M88E1000_EXT_PHY_SPEC_CTRL] = PHY_RW,
- [PHY_ID1] = PHY_R, [M88E1000_PHY_SPEC_CTRL] = PHY_RW,
- [PHY_CTRL] = PHY_RW, [PHY_1000T_CTRL] = PHY_RW,
- [PHY_LP_ABILITY] = PHY_R, [PHY_1000T_STATUS] = PHY_R,
- [PHY_AUTONEG_ADV] = PHY_RW, [M88E1000_RX_ERR_CNTR] = PHY_R,
- [PHY_ID2] = PHY_R, [M88E1000_PHY_SPEC_STATUS] = PHY_R,
- [PHY_AUTONEG_EXP] = PHY_R,
-};
-
-/* PHY_ID2 documented in 8254x_GBe_SDM.pdf, pp. 250 */
-static const uint16_t phy_reg_init[] = {
- [PHY_CTRL] = MII_CR_SPEED_SELECT_MSB |
- MII_CR_FULL_DUPLEX |
- MII_CR_AUTO_NEG_EN,
-
- [PHY_STATUS] = MII_SR_EXTENDED_CAPS |
- MII_SR_LINK_STATUS | /* link initially up */
- MII_SR_AUTONEG_CAPS |
- /* MII_SR_AUTONEG_COMPLETE: initially NOT completed */
- MII_SR_PREAMBLE_SUPPRESS |
- MII_SR_EXTENDED_STATUS |
- MII_SR_10T_HD_CAPS |
- MII_SR_10T_FD_CAPS |
- MII_SR_100X_HD_CAPS |
- MII_SR_100X_FD_CAPS,
-
- [PHY_ID1] = 0x141,
- /* [PHY_ID2] configured per DevId, from e1000_reset() */
- [PHY_AUTONEG_ADV] = 0xde1,
- [PHY_LP_ABILITY] = 0x1e0,
- [PHY_1000T_CTRL] = 0x0e00,
- [PHY_1000T_STATUS] = 0x3c00,
- [M88E1000_PHY_SPEC_CTRL] = 0x360,
- [M88E1000_PHY_SPEC_STATUS] = 0xac00,
- [M88E1000_EXT_PHY_SPEC_CTRL] = 0x0d60,
-};
-
-static const uint32_t mac_reg_init[] = {
- [PBA] = 0x00100030,
- [LEDCTL] = 0x602,
- [CTRL] = E1000_CTRL_SWDPIN2 | E1000_CTRL_SWDPIN0 |
- E1000_CTRL_SPD_1000 | E1000_CTRL_SLU,
- [STATUS] = 0x80000000 | E1000_STATUS_GIO_MASTER_ENABLE |
- E1000_STATUS_ASDV | E1000_STATUS_MTXCKOK |
- E1000_STATUS_SPEED_1000 | E1000_STATUS_FD |
- E1000_STATUS_LU,
- [MANC] = E1000_MANC_EN_MNG2HOST | E1000_MANC_RCV_TCO_EN |
- E1000_MANC_ARP_EN | E1000_MANC_0298_EN |
- E1000_MANC_RMCP_EN,
-};
-
-/* Helper function, *curr == 0 means the value is not set */
-static inline void
-mit_update_delay(uint32_t *curr, uint32_t value)
-{
- if (value && (*curr == 0 || value < *curr)) {
- *curr = value;
- }
-}
-
-static void
-set_interrupt_cause(E1000State *s, int index, uint32_t val)
-{
- PCIDevice *d = PCI_DEVICE(s);
- uint32_t pending_ints;
- uint32_t mit_delay;
-
- s->mac_reg[ICR] = val;
-
- /*
- * Make sure ICR and ICS registers have the same value.
- * The spec says that the ICS register is write-only. However in practice,
- * on real hardware ICS is readable, and for reads it has the same value as
- * ICR (except that ICS does not have the clear on read behaviour of ICR).
- *
- * The VxWorks PRO/1000 driver uses this behaviour.
- */
- s->mac_reg[ICS] = val;
-
- pending_ints = (s->mac_reg[IMS] & s->mac_reg[ICR]);
- if (!s->mit_irq_level && pending_ints) {
- /*
- * Here we detect a potential raising edge. We postpone raising the
- * interrupt line if we are inside the mitigation delay window
- * (s->mit_timer_on == 1).
- * We provide a partial implementation of interrupt mitigation,
- * emulating only RADV, TADV and ITR (lower 16 bits, 1024ns units for
- * RADV and TADV, 256ns units for ITR). RDTR is only used to enable
- * RADV; relative timers based on TIDV and RDTR are not implemented.
- */
- if (s->mit_timer_on) {
- return;
- }
- if (chkflag(MIT)) {
- /* Compute the next mitigation delay according to pending
- * interrupts and the current values of RADV (provided
- * RDTR!=0), TADV and ITR.
- * Then rearm the timer.
- */
- mit_delay = 0;
- if (s->mit_ide &&
- (pending_ints & (E1000_ICR_TXQE | E1000_ICR_TXDW))) {
- mit_update_delay(&mit_delay, s->mac_reg[TADV] * 4);
- }
- if (s->mac_reg[RDTR] && (pending_ints & E1000_ICS_RXT0)) {
- mit_update_delay(&mit_delay, s->mac_reg[RADV] * 4);
- }
- mit_update_delay(&mit_delay, s->mac_reg[ITR]);
-
- /*
- * According to e1000 SPEC, the Ethernet controller guarantees
- * a maximum observable interrupt rate of 7813 interrupts/sec.
- * Thus if mit_delay < 500 then the delay should be set to the
- * minimum delay possible which is 500.
- */
- mit_delay = (mit_delay < 500) ? 500 : mit_delay;
-
- if (mit_delay) {
- s->mit_timer_on = 1;
- timer_mod(s->mit_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- mit_delay * 256);
- }
- s->mit_ide = 0;
- }
- }
-
- s->mit_irq_level = (pending_ints != 0);
- pci_set_irq(d, s->mit_irq_level);
-}
-
-static void
-e1000_mit_timer(void *opaque)
-{
- E1000State *s = opaque;
-
- s->mit_timer_on = 0;
- /* Call set_interrupt_cause to update the irq level (if necessary). */
- set_interrupt_cause(s, 0, s->mac_reg[ICR]);
-}
-
-static void
-set_ics(E1000State *s, int index, uint32_t val)
-{
- DBGOUT(INTERRUPT, "set_ics %x, ICR %x, IMR %x\n", val, s->mac_reg[ICR],
- s->mac_reg[IMS]);
- set_interrupt_cause(s, 0, val | s->mac_reg[ICR]);
-}
-
-static void
-e1000_autoneg_timer(void *opaque)
-{
- E1000State *s = opaque;
- if (!qemu_get_queue(s->nic)->link_down) {
- e1000_link_up(s);
- s->phy_reg[PHY_LP_ABILITY] |= MII_LPAR_LPACK;
- s->phy_reg[PHY_STATUS] |= MII_SR_AUTONEG_COMPLETE;
- DBGOUT(PHY, "Auto negotiation is completed\n");
- set_ics(s, 0, E1000_ICS_LSC); /* signal link status change to guest */
- }
-}
-
-static int
-rxbufsize(uint32_t v)
-{
- v &= E1000_RCTL_BSEX | E1000_RCTL_SZ_16384 | E1000_RCTL_SZ_8192 |
- E1000_RCTL_SZ_4096 | E1000_RCTL_SZ_2048 | E1000_RCTL_SZ_1024 |
- E1000_RCTL_SZ_512 | E1000_RCTL_SZ_256;
- switch (v) {
- case E1000_RCTL_BSEX | E1000_RCTL_SZ_16384:
- return 16384;
- case E1000_RCTL_BSEX | E1000_RCTL_SZ_8192:
- return 8192;
- case E1000_RCTL_BSEX | E1000_RCTL_SZ_4096:
- return 4096;
- case E1000_RCTL_SZ_1024:
- return 1024;
- case E1000_RCTL_SZ_512:
- return 512;
- case E1000_RCTL_SZ_256:
- return 256;
- }
- return 2048;
-}
-
-static void e1000_reset(void *opaque)
-{
- E1000State *d = opaque;
- E1000BaseClass *edc = E1000_DEVICE_GET_CLASS(d);
- uint8_t *macaddr = d->conf.macaddr.a;
- int i;
-
- timer_del(d->autoneg_timer);
- timer_del(d->mit_timer);
- d->mit_timer_on = 0;
- d->mit_irq_level = 0;
- d->mit_ide = 0;
- memset(d->phy_reg, 0, sizeof d->phy_reg);
- memmove(d->phy_reg, phy_reg_init, sizeof phy_reg_init);
- d->phy_reg[PHY_ID2] = edc->phy_id2;
- memset(d->mac_reg, 0, sizeof d->mac_reg);
- memmove(d->mac_reg, mac_reg_init, sizeof mac_reg_init);
- d->rxbuf_min_shift = 1;
- memset(&d->tx, 0, sizeof d->tx);
-
- if (qemu_get_queue(d->nic)->link_down) {
- e1000_link_down(d);
- }
-
- /* Some guests expect pre-initialized RAH/RAL (AddrValid flag + MACaddr) */
- d->mac_reg[RA] = 0;
- d->mac_reg[RA + 1] = E1000_RAH_AV;
- for (i = 0; i < 4; i++) {
- d->mac_reg[RA] |= macaddr[i] << (8 * i);
- d->mac_reg[RA + 1] |= (i < 2) ? macaddr[i + 4] << (8 * i) : 0;
- }
- qemu_format_nic_info_str(qemu_get_queue(d->nic), macaddr);
-}
-
-static void
-set_ctrl(E1000State *s, int index, uint32_t val)
-{
- /* RST is self clearing */
- s->mac_reg[CTRL] = val & ~E1000_CTRL_RST;
-}
-
-static void
-set_rx_control(E1000State *s, int index, uint32_t val)
-{
- s->mac_reg[RCTL] = val;
- s->rxbuf_size = rxbufsize(val);
- s->rxbuf_min_shift = ((val / E1000_RCTL_RDMTS_QUAT) & 3) + 1;
- DBGOUT(RX, "RCTL: %d, mac_reg[RCTL] = 0x%x\n", s->mac_reg[RDT],
- s->mac_reg[RCTL]);
- qemu_flush_queued_packets(qemu_get_queue(s->nic));
-}
-
-static void
-set_mdic(E1000State *s, int index, uint32_t val)
-{
- uint32_t data = val & E1000_MDIC_DATA_MASK;
- uint32_t addr = ((val & E1000_MDIC_REG_MASK) >> E1000_MDIC_REG_SHIFT);
-
- if ((val & E1000_MDIC_PHY_MASK) >> E1000_MDIC_PHY_SHIFT != 1) // phy #
- val = s->mac_reg[MDIC] | E1000_MDIC_ERROR;
- else if (val & E1000_MDIC_OP_READ) {
- DBGOUT(MDIC, "MDIC read reg 0x%x\n", addr);
- if (!(phy_regcap[addr] & PHY_R)) {
- DBGOUT(MDIC, "MDIC read reg %x unhandled\n", addr);
- val |= E1000_MDIC_ERROR;
- } else
- val = (val ^ data) | s->phy_reg[addr];
- } else if (val & E1000_MDIC_OP_WRITE) {
- DBGOUT(MDIC, "MDIC write reg 0x%x, value 0x%x\n", addr, data);
- if (!(phy_regcap[addr] & PHY_W)) {
- DBGOUT(MDIC, "MDIC write reg %x unhandled\n", addr);
- val |= E1000_MDIC_ERROR;
- } else {
- if (addr < NPHYWRITEOPS && phyreg_writeops[addr]) {
- phyreg_writeops[addr](s, index, data);
- } else {
- s->phy_reg[addr] = data;
- }
- }
- }
- s->mac_reg[MDIC] = val | E1000_MDIC_READY;
-
- if (val & E1000_MDIC_INT_EN) {
- set_ics(s, 0, E1000_ICR_MDAC);
- }
-}
-
-static uint32_t
-get_eecd(E1000State *s, int index)
-{
- uint32_t ret = E1000_EECD_PRES|E1000_EECD_GNT | s->eecd_state.old_eecd;
-
- DBGOUT(EEPROM, "reading eeprom bit %d (reading %d)\n",
- s->eecd_state.bitnum_out, s->eecd_state.reading);
- if (!s->eecd_state.reading ||
- ((s->eeprom_data[(s->eecd_state.bitnum_out >> 4) & 0x3f] >>
- ((s->eecd_state.bitnum_out & 0xf) ^ 0xf))) & 1)
- ret |= E1000_EECD_DO;
- return ret;
-}
-
-static void
-set_eecd(E1000State *s, int index, uint32_t val)
-{
- uint32_t oldval = s->eecd_state.old_eecd;
-
- s->eecd_state.old_eecd = val & (E1000_EECD_SK | E1000_EECD_CS |
- E1000_EECD_DI|E1000_EECD_FWE_MASK|E1000_EECD_REQ);
- if (!(E1000_EECD_CS & val)) { /* CS inactive; nothing to do */
- return;
- }
- if (E1000_EECD_CS & (val ^ oldval)) { /* CS rise edge; reset state */
- s->eecd_state.val_in = 0;
- s->eecd_state.bitnum_in = 0;
- s->eecd_state.bitnum_out = 0;
- s->eecd_state.reading = 0;
- }
- if (!(E1000_EECD_SK & (val ^ oldval))) { /* no clock edge */
- return;
- }
- if (!(E1000_EECD_SK & val)) { /* falling edge */
- s->eecd_state.bitnum_out++;
- return;
- }
- s->eecd_state.val_in <<= 1;
- if (val & E1000_EECD_DI)
- s->eecd_state.val_in |= 1;
- if (++s->eecd_state.bitnum_in == 9 && !s->eecd_state.reading) {
- s->eecd_state.bitnum_out = ((s->eecd_state.val_in & 0x3f)<<4)-1;
- s->eecd_state.reading = (((s->eecd_state.val_in >> 6) & 7) ==
- EEPROM_READ_OPCODE_MICROWIRE);
- }
- DBGOUT(EEPROM, "eeprom bitnum in %d out %d, reading %d\n",
- s->eecd_state.bitnum_in, s->eecd_state.bitnum_out,
- s->eecd_state.reading);
-}
-
-static uint32_t
-flash_eerd_read(E1000State *s, int x)
-{
- unsigned int index, r = s->mac_reg[EERD] & ~E1000_EEPROM_RW_REG_START;
-
- if ((s->mac_reg[EERD] & E1000_EEPROM_RW_REG_START) == 0)
- return (s->mac_reg[EERD]);
-
- if ((index = r >> E1000_EEPROM_RW_ADDR_SHIFT) > EEPROM_CHECKSUM_REG)
- return (E1000_EEPROM_RW_REG_DONE | r);
-
- return ((s->eeprom_data[index] << E1000_EEPROM_RW_REG_DATA) |
- E1000_EEPROM_RW_REG_DONE | r);
-}
-
-static void
-putsum(uint8_t *data, uint32_t n, uint32_t sloc, uint32_t css, uint32_t cse)
-{
- uint32_t sum;
-
- if (cse && cse < n)
- n = cse + 1;
- if (sloc < n-1) {
- sum = net_checksum_add(n-css, data+css);
- stw_be_p(data + sloc, net_checksum_finish(sum));
- }
-}
-
-static inline void
-inc_reg_if_not_full(E1000State *s, int index)
-{
- if (s->mac_reg[index] != 0xffffffff) {
- s->mac_reg[index]++;
- }
-}
-
-static inline void
-inc_tx_bcast_or_mcast_count(E1000State *s, const unsigned char *arr)
-{
- if (!memcmp(arr, bcast, sizeof bcast)) {
- inc_reg_if_not_full(s, BPTC);
- } else if (arr[0] & 1) {
- inc_reg_if_not_full(s, MPTC);
- }
-}
-
-static void
-grow_8reg_if_not_full(E1000State *s, int index, int size)
-{
- uint64_t sum = s->mac_reg[index] | (uint64_t)s->mac_reg[index+1] << 32;
-
- if (sum + size < sum) {
- sum = ~0ULL;
- } else {
- sum += size;
- }
- s->mac_reg[index] = sum;
- s->mac_reg[index+1] = sum >> 32;
-}
-
-static void
-increase_size_stats(E1000State *s, const int *size_regs, int size)
-{
- if (size > 1023) {
- inc_reg_if_not_full(s, size_regs[5]);
- } else if (size > 511) {
- inc_reg_if_not_full(s, size_regs[4]);
- } else if (size > 255) {
- inc_reg_if_not_full(s, size_regs[3]);
- } else if (size > 127) {
- inc_reg_if_not_full(s, size_regs[2]);
- } else if (size > 64) {
- inc_reg_if_not_full(s, size_regs[1]);
- } else if (size == 64) {
- inc_reg_if_not_full(s, size_regs[0]);
- }
-}
-
-static inline int
-vlan_enabled(E1000State *s)
-{
- return ((s->mac_reg[CTRL] & E1000_CTRL_VME) != 0);
-}
-
-static inline int
-vlan_rx_filter_enabled(E1000State *s)
-{
- return ((s->mac_reg[RCTL] & E1000_RCTL_VFE) != 0);
-}
-
-static inline int
-is_vlan_packet(E1000State *s, const uint8_t *buf)
-{
- return (be16_to_cpup((uint16_t *)(buf + 12)) ==
- le16_to_cpu(s->mac_reg[VET]));
-}
-
-static inline int
-is_vlan_txd(uint32_t txd_lower)
-{
- return ((txd_lower & E1000_TXD_CMD_VLE) != 0);
-}
-
-/* FCS aka Ethernet CRC-32. We don't get it from backends and can't
- * fill it in, just pad descriptor length by 4 bytes unless guest
- * told us to strip it off the packet. */
-static inline int
-fcs_len(E1000State *s)
-{
- return (s->mac_reg[RCTL] & E1000_RCTL_SECRC) ? 0 : 4;
-}
-
-static void
-e1000_send_packet(E1000State *s, const uint8_t *buf, int size)
-{
- static const int PTCregs[6] = { PTC64, PTC127, PTC255, PTC511,
- PTC1023, PTC1522 };
-
- NetClientState *nc = qemu_get_queue(s->nic);
- if (s->phy_reg[PHY_CTRL] & MII_CR_LOOPBACK) {
- nc->info->receive(nc, buf, size);
- } else {
- qemu_send_packet(nc, buf, size);
- }
- inc_tx_bcast_or_mcast_count(s, buf);
- increase_size_stats(s, PTCregs, size);
-}
-
-static void
-xmit_seg(E1000State *s)
-{
- uint16_t len, *sp;
- unsigned int frames = s->tx.tso_frames, css, sofar;
- struct e1000_tx *tp = &s->tx;
-
- if (tp->tse && tp->cptse) {
- css = tp->ipcss;
- DBGOUT(TXSUM, "frames %d size %d ipcss %d\n",
- frames, tp->size, css);
- if (tp->ip) { /* IPv4 */
- stw_be_p(tp->data+css+2, tp->size - css);
- stw_be_p(tp->data+css+4,
- be16_to_cpup((uint16_t *)(tp->data+css+4))+frames);
- } else { /* IPv6 */
- stw_be_p(tp->data+css+4, tp->size - css);
- }
- css = tp->tucss;
- len = tp->size - css;
- DBGOUT(TXSUM, "tcp %d tucss %d len %d\n", tp->tcp, css, len);
- if (tp->tcp) {
- sofar = frames * tp->mss;
- stl_be_p(tp->data+css+4, ldl_be_p(tp->data+css+4)+sofar); /* seq */
- if (tp->paylen - sofar > tp->mss) {
- tp->data[css + 13] &= ~9; /* PSH, FIN */
- } else if (frames) {
- inc_reg_if_not_full(s, TSCTC);
- }
- } else /* UDP */
- stw_be_p(tp->data+css+4, len);
- if (tp->sum_needed & E1000_TXD_POPTS_TXSM) {
- unsigned int phsum;
- // add pseudo-header length before checksum calculation
- sp = (uint16_t *)(tp->data + tp->tucso);
- phsum = be16_to_cpup(sp) + len;
- phsum = (phsum >> 16) + (phsum & 0xffff);
- stw_be_p(sp, phsum);
- }
- tp->tso_frames++;
- }
-
- if (tp->sum_needed & E1000_TXD_POPTS_TXSM)
- putsum(tp->data, tp->size, tp->tucso, tp->tucss, tp->tucse);
- if (tp->sum_needed & E1000_TXD_POPTS_IXSM)
- putsum(tp->data, tp->size, tp->ipcso, tp->ipcss, tp->ipcse);
- if (tp->vlan_needed) {
- memmove(tp->vlan, tp->data, 4);
- memmove(tp->data, tp->data + 4, 8);
- memcpy(tp->data + 8, tp->vlan_header, 4);
- e1000_send_packet(s, tp->vlan, tp->size + 4);
- } else {
- e1000_send_packet(s, tp->data, tp->size);
- }
-
- inc_reg_if_not_full(s, TPT);
- grow_8reg_if_not_full(s, TOTL, s->tx.size);
- s->mac_reg[GPTC] = s->mac_reg[TPT];
- s->mac_reg[GOTCL] = s->mac_reg[TOTL];
- s->mac_reg[GOTCH] = s->mac_reg[TOTH];
-}
-
-static void
-process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
-{
- PCIDevice *d = PCI_DEVICE(s);
- uint32_t txd_lower = le32_to_cpu(dp->lower.data);
- uint32_t dtype = txd_lower & (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D);
- unsigned int split_size = txd_lower & 0xffff, bytes, sz, op;
- unsigned int msh = 0xfffff;
- uint64_t addr;
- struct e1000_context_desc *xp = (struct e1000_context_desc *)dp;
- struct e1000_tx *tp = &s->tx;
-
- s->mit_ide |= (txd_lower & E1000_TXD_CMD_IDE);
- if (dtype == E1000_TXD_CMD_DEXT) { /* context descriptor */
- op = le32_to_cpu(xp->cmd_and_length);
- tp->ipcss = xp->lower_setup.ip_fields.ipcss;
- tp->ipcso = xp->lower_setup.ip_fields.ipcso;
- tp->ipcse = le16_to_cpu(xp->lower_setup.ip_fields.ipcse);
- tp->tucss = xp->upper_setup.tcp_fields.tucss;
- tp->tucso = xp->upper_setup.tcp_fields.tucso;
- tp->tucse = le16_to_cpu(xp->upper_setup.tcp_fields.tucse);
- tp->paylen = op & 0xfffff;
- tp->hdr_len = xp->tcp_seg_setup.fields.hdr_len;
- tp->mss = le16_to_cpu(xp->tcp_seg_setup.fields.mss);
- tp->ip = (op & E1000_TXD_CMD_IP) ? 1 : 0;
- tp->tcp = (op & E1000_TXD_CMD_TCP) ? 1 : 0;
- tp->tse = (op & E1000_TXD_CMD_TSE) ? 1 : 0;
- tp->tso_frames = 0;
- if (tp->tucso == 0) { /* this is probably wrong */
- DBGOUT(TXSUM, "TCP/UDP: cso 0!\n");
- tp->tucso = tp->tucss + (tp->tcp ? 16 : 6);
- }
- return;
- } else if (dtype == (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)) {
- // data descriptor
- if (tp->size == 0) {
- tp->sum_needed = le32_to_cpu(dp->upper.data) >> 8;
- }
- tp->cptse = ( txd_lower & E1000_TXD_CMD_TSE ) ? 1 : 0;
- } else {
- // legacy descriptor
- tp->cptse = 0;
- }
-
- if (vlan_enabled(s) && is_vlan_txd(txd_lower) &&
- (tp->cptse || txd_lower & E1000_TXD_CMD_EOP)) {
- tp->vlan_needed = 1;
- stw_be_p(tp->vlan_header,
- le16_to_cpu(s->mac_reg[VET]));
- stw_be_p(tp->vlan_header + 2,
- le16_to_cpu(dp->upper.fields.special));
- }
-
- addr = le64_to_cpu(dp->buffer_addr);
- if (tp->tse && tp->cptse) {
- msh = tp->hdr_len + tp->mss;
- do {
- bytes = split_size;
- if (tp->size + bytes > msh)
- bytes = msh - tp->size;
-
- bytes = MIN(sizeof(tp->data) - tp->size, bytes);
- pci_dma_read(d, addr, tp->data + tp->size, bytes);
- sz = tp->size + bytes;
- if (sz >= tp->hdr_len && tp->size < tp->hdr_len) {
- memmove(tp->header, tp->data, tp->hdr_len);
- }
- tp->size = sz;
- addr += bytes;
- if (sz == msh) {
- xmit_seg(s);
- memmove(tp->data, tp->header, tp->hdr_len);
- tp->size = tp->hdr_len;
- }
- split_size -= bytes;
- } while (bytes && split_size);
- } else if (!tp->tse && tp->cptse) {
- // context descriptor TSE is not set, while data descriptor TSE is set
- DBGOUT(TXERR, "TCP segmentation error\n");
- } else {
- split_size = MIN(sizeof(tp->data) - tp->size, split_size);
- pci_dma_read(d, addr, tp->data + tp->size, split_size);
- tp->size += split_size;
- }
-
- if (!(txd_lower & E1000_TXD_CMD_EOP))
- return;
- if (!(tp->tse && tp->cptse && tp->size < tp->hdr_len)) {
- xmit_seg(s);
- }
- tp->tso_frames = 0;
- tp->sum_needed = 0;
- tp->vlan_needed = 0;
- tp->size = 0;
- tp->cptse = 0;
-}
-
-static uint32_t
-txdesc_writeback(E1000State *s, dma_addr_t base, struct e1000_tx_desc *dp)
-{
- PCIDevice *d = PCI_DEVICE(s);
- uint32_t txd_upper, txd_lower = le32_to_cpu(dp->lower.data);
-
- if (!(txd_lower & (E1000_TXD_CMD_RS|E1000_TXD_CMD_RPS)))
- return 0;
- txd_upper = (le32_to_cpu(dp->upper.data) | E1000_TXD_STAT_DD) &
- ~(E1000_TXD_STAT_EC | E1000_TXD_STAT_LC | E1000_TXD_STAT_TU);
- dp->upper.data = cpu_to_le32(txd_upper);
- pci_dma_write(d, base + ((char *)&dp->upper - (char *)dp),
- &dp->upper, sizeof(dp->upper));
- return E1000_ICR_TXDW;
-}
-
-static uint64_t tx_desc_base(E1000State *s)
-{
- uint64_t bah = s->mac_reg[TDBAH];
- uint64_t bal = s->mac_reg[TDBAL] & ~0xf;
-
- return (bah << 32) + bal;
-}
-
-static void
-start_xmit(E1000State *s)
-{
- PCIDevice *d = PCI_DEVICE(s);
- dma_addr_t base;
- struct e1000_tx_desc desc;
- uint32_t tdh_start = s->mac_reg[TDH], cause = E1000_ICS_TXQE;
-
- if (!(s->mac_reg[TCTL] & E1000_TCTL_EN)) {
- DBGOUT(TX, "tx disabled\n");
- return;
- }
-
- while (s->mac_reg[TDH] != s->mac_reg[TDT]) {
- base = tx_desc_base(s) +
- sizeof(struct e1000_tx_desc) * s->mac_reg[TDH];
- pci_dma_read(d, base, &desc, sizeof(desc));
-
- DBGOUT(TX, "index %d: %p : %x %x\n", s->mac_reg[TDH],
- (void *)(intptr_t)desc.buffer_addr, desc.lower.data,
- desc.upper.data);
-
- process_tx_desc(s, &desc);
- cause |= txdesc_writeback(s, base, &desc);
-
- if (++s->mac_reg[TDH] * sizeof(desc) >= s->mac_reg[TDLEN])
- s->mac_reg[TDH] = 0;
- /*
- * the following could happen only if guest sw assigns
- * bogus values to TDT/TDLEN.
- * there's nothing too intelligent we could do about this.
- */
- if (s->mac_reg[TDH] == tdh_start ||
- tdh_start >= s->mac_reg[TDLEN] / sizeof(desc)) {
- DBGOUT(TXERR, "TDH wraparound @%x, TDT %x, TDLEN %x\n",
- tdh_start, s->mac_reg[TDT], s->mac_reg[TDLEN]);
- break;
- }
- }
- set_ics(s, 0, cause);
-}
-
-static int
-receive_filter(E1000State *s, const uint8_t *buf, int size)
-{
- static const int mta_shift[] = {4, 3, 2, 0};
- uint32_t f, rctl = s->mac_reg[RCTL], ra[2], *rp;
- int isbcast = !memcmp(buf, bcast, sizeof bcast), ismcast = (buf[0] & 1);
-
- if (is_vlan_packet(s, buf) && vlan_rx_filter_enabled(s)) {
- uint16_t vid = be16_to_cpup((uint16_t *)(buf + 14));
- uint32_t vfta = le32_to_cpup((uint32_t *)(s->mac_reg + VFTA) +
- ((vid >> 5) & 0x7f));
- if ((vfta & (1 << (vid & 0x1f))) == 0)
- return 0;
- }
-
- if (!isbcast && !ismcast && (rctl & E1000_RCTL_UPE)) { /* promiscuous ucast */
- return 1;
- }
-
- if (ismcast && (rctl & E1000_RCTL_MPE)) { /* promiscuous mcast */
- inc_reg_if_not_full(s, MPRC);
- return 1;
- }
-
- if (isbcast && (rctl & E1000_RCTL_BAM)) { /* broadcast enabled */
- inc_reg_if_not_full(s, BPRC);
- return 1;
- }
-
- for (rp = s->mac_reg + RA; rp < s->mac_reg + RA + 32; rp += 2) {
- if (!(rp[1] & E1000_RAH_AV))
- continue;
- ra[0] = cpu_to_le32(rp[0]);
- ra[1] = cpu_to_le32(rp[1]);
- if (!memcmp(buf, (uint8_t *)ra, 6)) {
- DBGOUT(RXFILTER,
- "unicast match[%d]: %02x:%02x:%02x:%02x:%02x:%02x\n",
- (int)(rp - s->mac_reg - RA)/2,
- buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
- return 1;
- }
- }
- DBGOUT(RXFILTER, "unicast mismatch: %02x:%02x:%02x:%02x:%02x:%02x\n",
- buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
-
- f = mta_shift[(rctl >> E1000_RCTL_MO_SHIFT) & 3];
- f = (((buf[5] << 8) | buf[4]) >> f) & 0xfff;
- if (s->mac_reg[MTA + (f >> 5)] & (1 << (f & 0x1f))) {
- inc_reg_if_not_full(s, MPRC);
- return 1;
- }
- DBGOUT(RXFILTER,
- "dropping, inexact filter mismatch: %02x:%02x:%02x:%02x:%02x:%02x MO %d MTA[%d] %x\n",
- buf[0], buf[1], buf[2], buf[3], buf[4], buf[5],
- (rctl >> E1000_RCTL_MO_SHIFT) & 3, f >> 5,
- s->mac_reg[MTA + (f >> 5)]);
-
- return 0;
-}
-
-static void
-e1000_set_link_status(NetClientState *nc)
-{
- E1000State *s = qemu_get_nic_opaque(nc);
- uint32_t old_status = s->mac_reg[STATUS];
-
- if (nc->link_down) {
- e1000_link_down(s);
- } else {
- if (have_autoneg(s) &&
- !(s->phy_reg[PHY_STATUS] & MII_SR_AUTONEG_COMPLETE)) {
- /* emulate auto-negotiation if supported */
- timer_mod(s->autoneg_timer,
- qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 500);
- } else {
- e1000_link_up(s);
- }
- }
-
- if (s->mac_reg[STATUS] != old_status)
- set_ics(s, 0, E1000_ICR_LSC);
-}
-
-static bool e1000_has_rxbufs(E1000State *s, size_t total_size)
-{
- int bufs;
- /* Fast-path short packets */
- if (total_size <= s->rxbuf_size) {
- return s->mac_reg[RDH] != s->mac_reg[RDT];
- }
- if (s->mac_reg[RDH] < s->mac_reg[RDT]) {
- bufs = s->mac_reg[RDT] - s->mac_reg[RDH];
- } else if (s->mac_reg[RDH] > s->mac_reg[RDT]) {
- bufs = s->mac_reg[RDLEN] / sizeof(struct e1000_rx_desc) +
- s->mac_reg[RDT] - s->mac_reg[RDH];
- } else {
- return false;
- }
- return total_size <= bufs * s->rxbuf_size;
-}
-
-static int
-e1000_can_receive(NetClientState *nc)
-{
- E1000State *s = qemu_get_nic_opaque(nc);
-
- return (s->mac_reg[STATUS] & E1000_STATUS_LU) &&
- (s->mac_reg[RCTL] & E1000_RCTL_EN) &&
- (s->parent_obj.config[PCI_COMMAND] & PCI_COMMAND_MASTER) &&
- e1000_has_rxbufs(s, 1);
-}
-
-static uint64_t rx_desc_base(E1000State *s)
-{
- uint64_t bah = s->mac_reg[RDBAH];
- uint64_t bal = s->mac_reg[RDBAL] & ~0xf;
-
- return (bah << 32) + bal;
-}
-
-static ssize_t
-e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
-{
- E1000State *s = qemu_get_nic_opaque(nc);
- PCIDevice *d = PCI_DEVICE(s);
- struct e1000_rx_desc desc;
- dma_addr_t base;
- unsigned int n, rdt;
- uint32_t rdh_start;
- uint16_t vlan_special = 0;
- uint8_t vlan_status = 0;
- uint8_t min_buf[MIN_BUF_SIZE];
- struct iovec min_iov;
- uint8_t *filter_buf = iov->iov_base;
- size_t size = iov_size(iov, iovcnt);
- size_t iov_ofs = 0;
- size_t desc_offset;
- size_t desc_size;
- size_t total_size;
- static const int PRCregs[6] = { PRC64, PRC127, PRC255, PRC511,
- PRC1023, PRC1522 };
-
- if (!(s->mac_reg[STATUS] & E1000_STATUS_LU)) {
- return -1;
- }
-
- if (!(s->mac_reg[RCTL] & E1000_RCTL_EN)) {
- return -1;
- }
-
- /* Pad to minimum Ethernet frame length */
- if (size < sizeof(min_buf)) {
- iov_to_buf(iov, iovcnt, 0, min_buf, size);
- memset(&min_buf[size], 0, sizeof(min_buf) - size);
- inc_reg_if_not_full(s, RUC);
- min_iov.iov_base = filter_buf = min_buf;
- min_iov.iov_len = size = sizeof(min_buf);
- iovcnt = 1;
- iov = &min_iov;
- } else if (iov->iov_len < MAXIMUM_ETHERNET_HDR_LEN) {
- /* This is very unlikely, but may happen. */
- iov_to_buf(iov, iovcnt, 0, min_buf, MAXIMUM_ETHERNET_HDR_LEN);
- filter_buf = min_buf;
- }
-
- /* Discard oversized packets if !LPE and !SBP. */
- if ((size > MAXIMUM_ETHERNET_LPE_SIZE ||
- (size > MAXIMUM_ETHERNET_VLAN_SIZE
- && !(s->mac_reg[RCTL] & E1000_RCTL_LPE)))
- && !(s->mac_reg[RCTL] & E1000_RCTL_SBP)) {
- inc_reg_if_not_full(s, ROC);
- return size;
- }
-
- if (!receive_filter(s, filter_buf, size)) {
- return size;
- }
-
- if (vlan_enabled(s) && is_vlan_packet(s, filter_buf)) {
- vlan_special = cpu_to_le16(be16_to_cpup((uint16_t *)(filter_buf
- + 14)));
- iov_ofs = 4;
- if (filter_buf == iov->iov_base) {
- memmove(filter_buf + 4, filter_buf, 12);
- } else {
- iov_from_buf(iov, iovcnt, 4, filter_buf, 12);
- while (iov->iov_len <= iov_ofs) {
- iov_ofs -= iov->iov_len;
- iov++;
- }
- }
- vlan_status = E1000_RXD_STAT_VP;
- size -= 4;
- }
-
- rdh_start = s->mac_reg[RDH];
- desc_offset = 0;
- total_size = size + fcs_len(s);
- if (!e1000_has_rxbufs(s, total_size)) {
- set_ics(s, 0, E1000_ICS_RXO);
- return -1;
- }
- do {
- desc_size = total_size - desc_offset;
- if (desc_size > s->rxbuf_size) {
- desc_size = s->rxbuf_size;
- }
- base = rx_desc_base(s) + sizeof(desc) * s->mac_reg[RDH];
- pci_dma_read(d, base, &desc, sizeof(desc));
- desc.special = vlan_special;
- desc.status |= (vlan_status | E1000_RXD_STAT_DD);
- if (desc.buffer_addr) {
- if (desc_offset < size) {
- size_t iov_copy;
- hwaddr ba = le64_to_cpu(desc.buffer_addr);
- size_t copy_size = size - desc_offset;
- if (copy_size > s->rxbuf_size) {
- copy_size = s->rxbuf_size;
- }
- do {
- iov_copy = MIN(copy_size, iov->iov_len - iov_ofs);
- pci_dma_write(d, ba, iov->iov_base + iov_ofs, iov_copy);
- copy_size -= iov_copy;
- ba += iov_copy;
- iov_ofs += iov_copy;
- if (iov_ofs == iov->iov_len) {
- iov++;
- iov_ofs = 0;
- }
- } while (copy_size);
- }
- desc_offset += desc_size;
- desc.length = cpu_to_le16(desc_size);
- if (desc_offset >= total_size) {
- desc.status |= E1000_RXD_STAT_EOP | E1000_RXD_STAT_IXSM;
- } else {
- /* Guest zeroing out status is not a hardware requirement.
- Clear EOP in case guest didn't do it. */
- desc.status &= ~E1000_RXD_STAT_EOP;
- }
- } else { // as per intel docs; skip descriptors with null buf addr
- DBGOUT(RX, "Null RX descriptor!!\n");
- }
- pci_dma_write(d, base, &desc, sizeof(desc));
-
- if (++s->mac_reg[RDH] * sizeof(desc) >= s->mac_reg[RDLEN])
- s->mac_reg[RDH] = 0;
- /* see comment in start_xmit; same here */
- if (s->mac_reg[RDH] == rdh_start ||
- rdh_start >= s->mac_reg[RDLEN] / sizeof(desc)) {
- DBGOUT(RXERR, "RDH wraparound @%x, RDT %x, RDLEN %x\n",
- rdh_start, s->mac_reg[RDT], s->mac_reg[RDLEN]);
- set_ics(s, 0, E1000_ICS_RXO);
- return -1;
- }
- } while (desc_offset < total_size);
-
- increase_size_stats(s, PRCregs, total_size);
- inc_reg_if_not_full(s, TPR);
- s->mac_reg[GPRC] = s->mac_reg[TPR];
- /* TOR - Total Octets Received:
- * This register includes bytes received in a packet from the <Destination
- * Address> field through the <CRC> field, inclusively.
- * Always include FCS length (4) in size.
- */
- grow_8reg_if_not_full(s, TORL, size+4);
- s->mac_reg[GORCL] = s->mac_reg[TORL];
- s->mac_reg[GORCH] = s->mac_reg[TORH];
-
- n = E1000_ICS_RXT0;
- if ((rdt = s->mac_reg[RDT]) < s->mac_reg[RDH])
- rdt += s->mac_reg[RDLEN] / sizeof(desc);
- if (((rdt - s->mac_reg[RDH]) * sizeof(desc)) <= s->mac_reg[RDLEN] >>
- s->rxbuf_min_shift)
- n |= E1000_ICS_RXDMT0;
-
- set_ics(s, 0, n);
-
- return size;
-}
-
-static ssize_t
-e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size)
-{
- const struct iovec iov = {
- .iov_base = (uint8_t *)buf,
- .iov_len = size
- };
-
- return e1000_receive_iov(nc, &iov, 1);
-}
-
-static uint32_t
-mac_readreg(E1000State *s, int index)
-{
- return s->mac_reg[index];
-}
-
-static uint32_t
-mac_low4_read(E1000State *s, int index)
-{
- return s->mac_reg[index] & 0xf;
-}
-
-static uint32_t
-mac_low11_read(E1000State *s, int index)
-{
- return s->mac_reg[index] & 0x7ff;
-}
-
-static uint32_t
-mac_low13_read(E1000State *s, int index)
-{
- return s->mac_reg[index] & 0x1fff;
-}
-
-static uint32_t
-mac_low16_read(E1000State *s, int index)
-{
- return s->mac_reg[index] & 0xffff;
-}
-
-static uint32_t
-mac_icr_read(E1000State *s, int index)
-{
- uint32_t ret = s->mac_reg[ICR];
-
- DBGOUT(INTERRUPT, "ICR read: %x\n", ret);
- set_interrupt_cause(s, 0, 0);
- return ret;
-}
-
-static uint32_t
-mac_read_clr4(E1000State *s, int index)
-{
- uint32_t ret = s->mac_reg[index];
-
- s->mac_reg[index] = 0;
- return ret;
-}
-
-static uint32_t
-mac_read_clr8(E1000State *s, int index)
-{
- uint32_t ret = s->mac_reg[index];
-
- s->mac_reg[index] = 0;
- s->mac_reg[index-1] = 0;
- return ret;
-}
-
-static void
-mac_writereg(E1000State *s, int index, uint32_t val)
-{
- uint32_t macaddr[2];
-
- s->mac_reg[index] = val;
-
- if (index == RA + 1) {
- macaddr[0] = cpu_to_le32(s->mac_reg[RA]);
- macaddr[1] = cpu_to_le32(s->mac_reg[RA + 1]);
- qemu_format_nic_info_str(qemu_get_queue(s->nic), (uint8_t *)macaddr);
- }
-}
-
-static void
-set_rdt(E1000State *s, int index, uint32_t val)
-{
- s->mac_reg[index] = val & 0xffff;
- if (e1000_has_rxbufs(s, 1)) {
- qemu_flush_queued_packets(qemu_get_queue(s->nic));
- }
-}
-
-static void
-set_16bit(E1000State *s, int index, uint32_t val)
-{
- s->mac_reg[index] = val & 0xffff;
-}
-
-static void
-set_dlen(E1000State *s, int index, uint32_t val)
-{
- s->mac_reg[index] = val & 0xfff80;
-}
-
-static void
-set_tctl(E1000State *s, int index, uint32_t val)
-{
- s->mac_reg[index] = val;
- s->mac_reg[TDT] &= 0xffff;
- start_xmit(s);
-}
-
-static void
-set_icr(E1000State *s, int index, uint32_t val)
-{
- DBGOUT(INTERRUPT, "set_icr %x\n", val);
- set_interrupt_cause(s, 0, s->mac_reg[ICR] & ~val);
-}
-
-static void
-set_imc(E1000State *s, int index, uint32_t val)
-{
- s->mac_reg[IMS] &= ~val;
- set_ics(s, 0, 0);
-}
-
-static void
-set_ims(E1000State *s, int index, uint32_t val)
-{
- s->mac_reg[IMS] |= val;
- set_ics(s, 0, 0);
-}
-
-#define getreg(x) [x] = mac_readreg
-static uint32_t (*macreg_readops[])(E1000State *, int) = {
- getreg(PBA), getreg(RCTL), getreg(TDH), getreg(TXDCTL),
- getreg(WUFC), getreg(TDT), getreg(CTRL), getreg(LEDCTL),
- getreg(MANC), getreg(MDIC), getreg(SWSM), getreg(STATUS),
- getreg(TORL), getreg(TOTL), getreg(IMS), getreg(TCTL),
- getreg(RDH), getreg(RDT), getreg(VET), getreg(ICS),
- getreg(TDBAL), getreg(TDBAH), getreg(RDBAH), getreg(RDBAL),
- getreg(TDLEN), getreg(RDLEN), getreg(RDTR), getreg(RADV),
- getreg(TADV), getreg(ITR), getreg(FCRUC), getreg(IPAV),
- getreg(WUC), getreg(WUS), getreg(SCC), getreg(ECOL),
- getreg(MCC), getreg(LATECOL), getreg(COLC), getreg(DC),
- getreg(TNCRS), getreg(SEC), getreg(CEXTERR), getreg(RLEC),
- getreg(XONRXC), getreg(XONTXC), getreg(XOFFRXC), getreg(XOFFTXC),
- getreg(RFC), getreg(RJC), getreg(RNBC), getreg(TSCTFC),
- getreg(MGTPRC), getreg(MGTPDC), getreg(MGTPTC), getreg(GORCL),
- getreg(GOTCL),
-
- [TOTH] = mac_read_clr8, [TORH] = mac_read_clr8,
- [GOTCH] = mac_read_clr8, [GORCH] = mac_read_clr8,
- [PRC64] = mac_read_clr4, [PRC127] = mac_read_clr4,
- [PRC255] = mac_read_clr4, [PRC511] = mac_read_clr4,
- [PRC1023] = mac_read_clr4, [PRC1522] = mac_read_clr4,
- [PTC64] = mac_read_clr4, [PTC127] = mac_read_clr4,
- [PTC255] = mac_read_clr4, [PTC511] = mac_read_clr4,
- [PTC1023] = mac_read_clr4, [PTC1522] = mac_read_clr4,
- [GPRC] = mac_read_clr4, [GPTC] = mac_read_clr4,
- [TPT] = mac_read_clr4, [TPR] = mac_read_clr4,
- [RUC] = mac_read_clr4, [ROC] = mac_read_clr4,
- [BPRC] = mac_read_clr4, [MPRC] = mac_read_clr4,
- [TSCTC] = mac_read_clr4, [BPTC] = mac_read_clr4,
- [MPTC] = mac_read_clr4,
- [ICR] = mac_icr_read, [EECD] = get_eecd,
- [EERD] = flash_eerd_read,
- [RDFH] = mac_low13_read, [RDFT] = mac_low13_read,
- [RDFHS] = mac_low13_read, [RDFTS] = mac_low13_read,
- [RDFPC] = mac_low13_read,
- [TDFH] = mac_low11_read, [TDFT] = mac_low11_read,
- [TDFHS] = mac_low13_read, [TDFTS] = mac_low13_read,
- [TDFPC] = mac_low13_read,
- [AIT] = mac_low16_read,
-
- [CRCERRS ... MPC] = &mac_readreg,
- [IP6AT ... IP6AT+3] = &mac_readreg, [IP4AT ... IP4AT+6] = &mac_readreg,
- [FFLT ... FFLT+6] = &mac_low11_read,
- [RA ... RA+31] = &mac_readreg,
- [WUPM ... WUPM+31] = &mac_readreg,
- [MTA ... MTA+127] = &mac_readreg,
- [VFTA ... VFTA+127] = &mac_readreg,
- [FFMT ... FFMT+254] = &mac_low4_read,
- [FFVT ... FFVT+254] = &mac_readreg,
- [PBM ... PBM+16383] = &mac_readreg,
-};
-enum { NREADOPS = ARRAY_SIZE(macreg_readops) };
-
-#define putreg(x) [x] = mac_writereg
-static void (*macreg_writeops[])(E1000State *, int, uint32_t) = {
- putreg(PBA), putreg(EERD), putreg(SWSM), putreg(WUFC),
- putreg(TDBAL), putreg(TDBAH), putreg(TXDCTL), putreg(RDBAH),
- putreg(RDBAL), putreg(LEDCTL), putreg(VET), putreg(FCRUC),
- putreg(TDFH), putreg(TDFT), putreg(TDFHS), putreg(TDFTS),
- putreg(TDFPC), putreg(RDFH), putreg(RDFT), putreg(RDFHS),
- putreg(RDFTS), putreg(RDFPC), putreg(IPAV), putreg(WUC),
- putreg(WUS), putreg(AIT),
-
- [TDLEN] = set_dlen, [RDLEN] = set_dlen, [TCTL] = set_tctl,
- [TDT] = set_tctl, [MDIC] = set_mdic, [ICS] = set_ics,
- [TDH] = set_16bit, [RDH] = set_16bit, [RDT] = set_rdt,
- [IMC] = set_imc, [IMS] = set_ims, [ICR] = set_icr,
- [EECD] = set_eecd, [RCTL] = set_rx_control, [CTRL] = set_ctrl,
- [RDTR] = set_16bit, [RADV] = set_16bit, [TADV] = set_16bit,
- [ITR] = set_16bit,
-
- [IP6AT ... IP6AT+3] = &mac_writereg, [IP4AT ... IP4AT+6] = &mac_writereg,
- [FFLT ... FFLT+6] = &mac_writereg,
- [RA ... RA+31] = &mac_writereg,
- [WUPM ... WUPM+31] = &mac_writereg,
- [MTA ... MTA+127] = &mac_writereg,
- [VFTA ... VFTA+127] = &mac_writereg,
- [FFMT ... FFMT+254] = &mac_writereg, [FFVT ... FFVT+254] = &mac_writereg,
- [PBM ... PBM+16383] = &mac_writereg,
-};
-
-enum { NWRITEOPS = ARRAY_SIZE(macreg_writeops) };
-
-enum { MAC_ACCESS_PARTIAL = 1, MAC_ACCESS_FLAG_NEEDED = 2 };
-
-#define markflag(x) ((E1000_FLAG_##x << 2) | MAC_ACCESS_FLAG_NEEDED)
-/* In the array below the meaning of the bits is: [f|f|f|f|f|f|n|p]
- * f - flag bits (up to 6 possible flags)
- * n - flag needed
- * p - partially implenented */
-static const uint8_t mac_reg_access[0x8000] = {
- [RDTR] = markflag(MIT), [TADV] = markflag(MIT),
- [RADV] = markflag(MIT), [ITR] = markflag(MIT),
-
- [IPAV] = markflag(MAC), [WUC] = markflag(MAC),
- [IP6AT] = markflag(MAC), [IP4AT] = markflag(MAC),
- [FFVT] = markflag(MAC), [WUPM] = markflag(MAC),
- [ECOL] = markflag(MAC), [MCC] = markflag(MAC),
- [DC] = markflag(MAC), [TNCRS] = markflag(MAC),
- [RLEC] = markflag(MAC), [XONRXC] = markflag(MAC),
- [XOFFTXC] = markflag(MAC), [RFC] = markflag(MAC),
- [TSCTFC] = markflag(MAC), [MGTPRC] = markflag(MAC),
- [WUS] = markflag(MAC), [AIT] = markflag(MAC),
- [FFLT] = markflag(MAC), [FFMT] = markflag(MAC),
- [SCC] = markflag(MAC), [FCRUC] = markflag(MAC),
- [LATECOL] = markflag(MAC), [COLC] = markflag(MAC),
- [SEC] = markflag(MAC), [CEXTERR] = markflag(MAC),
- [XONTXC] = markflag(MAC), [XOFFRXC] = markflag(MAC),
- [RJC] = markflag(MAC), [RNBC] = markflag(MAC),
- [MGTPDC] = markflag(MAC), [MGTPTC] = markflag(MAC),
- [RUC] = markflag(MAC), [ROC] = markflag(MAC),
- [GORCL] = markflag(MAC), [GORCH] = markflag(MAC),
- [GOTCL] = markflag(MAC), [GOTCH] = markflag(MAC),
- [BPRC] = markflag(MAC), [MPRC] = markflag(MAC),
- [TSCTC] = markflag(MAC), [PRC64] = markflag(MAC),
- [PRC127] = markflag(MAC), [PRC255] = markflag(MAC),
- [PRC511] = markflag(MAC), [PRC1023] = markflag(MAC),
- [PRC1522] = markflag(MAC), [PTC64] = markflag(MAC),
- [PTC127] = markflag(MAC), [PTC255] = markflag(MAC),
- [PTC511] = markflag(MAC), [PTC1023] = markflag(MAC),
- [PTC1522] = markflag(MAC), [MPTC] = markflag(MAC),
- [BPTC] = markflag(MAC),
-
- [TDFH] = markflag(MAC) | MAC_ACCESS_PARTIAL,
- [TDFT] = markflag(MAC) | MAC_ACCESS_PARTIAL,
- [TDFHS] = markflag(MAC) | MAC_ACCESS_PARTIAL,
- [TDFTS] = markflag(MAC) | MAC_ACCESS_PARTIAL,
- [TDFPC] = markflag(MAC) | MAC_ACCESS_PARTIAL,
- [RDFH] = markflag(MAC) | MAC_ACCESS_PARTIAL,
- [RDFT] = markflag(MAC) | MAC_ACCESS_PARTIAL,
- [RDFHS] = markflag(MAC) | MAC_ACCESS_PARTIAL,
- [RDFTS] = markflag(MAC) | MAC_ACCESS_PARTIAL,
- [RDFPC] = markflag(MAC) | MAC_ACCESS_PARTIAL,
- [PBM] = markflag(MAC) | MAC_ACCESS_PARTIAL,
-};
-
-static void
-e1000_mmio_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned size)
-{
- E1000State *s = opaque;
- unsigned int index = (addr & 0x1ffff) >> 2;
-
- if (index < NWRITEOPS && macreg_writeops[index]) {
- if (!(mac_reg_access[index] & MAC_ACCESS_FLAG_NEEDED)
- || (s->compat_flags & (mac_reg_access[index] >> 2))) {
- if (mac_reg_access[index] & MAC_ACCESS_PARTIAL) {
- DBGOUT(GENERAL, "Writing to register at offset: 0x%08x. "
- "It is not fully implemented.\n", index<<2);
- }
- macreg_writeops[index](s, index, val);
- } else { /* "flag needed" bit is set, but the flag is not active */
- DBGOUT(MMIO, "MMIO write attempt to disabled reg. addr=0x%08x\n",
- index<<2);
- }
- } else if (index < NREADOPS && macreg_readops[index]) {
- DBGOUT(MMIO, "e1000_mmio_writel RO %x: 0x%04"PRIx64"\n",
- index<<2, val);
- } else {
- DBGOUT(UNKNOWN, "MMIO unknown write addr=0x%08x,val=0x%08"PRIx64"\n",
- index<<2, val);
- }
-}
-
-static uint64_t
-e1000_mmio_read(void *opaque, hwaddr addr, unsigned size)
-{
- E1000State *s = opaque;
- unsigned int index = (addr & 0x1ffff) >> 2;
-
- if (index < NREADOPS && macreg_readops[index]) {
- if (!(mac_reg_access[index] & MAC_ACCESS_FLAG_NEEDED)
- || (s->compat_flags & (mac_reg_access[index] >> 2))) {
- if (mac_reg_access[index] & MAC_ACCESS_PARTIAL) {
- DBGOUT(GENERAL, "Reading register at offset: 0x%08x. "
- "It is not fully implemented.\n", index<<2);
- }
- return macreg_readops[index](s, index);
- } else { /* "flag needed" bit is set, but the flag is not active */
- DBGOUT(MMIO, "MMIO read attempt of disabled reg. addr=0x%08x\n",
- index<<2);
- }
- } else {
- DBGOUT(UNKNOWN, "MMIO unknown read addr=0x%08x\n", index<<2);
- }
- return 0;
-}
-
-static const MemoryRegionOps e1000_mmio_ops = {
- .read = e1000_mmio_read,
- .write = e1000_mmio_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .impl = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static uint64_t e1000_io_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- E1000State *s = opaque;
-
- (void)s;
- return 0;
-}
-
-static void e1000_io_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- E1000State *s = opaque;
-
- (void)s;
-}
-
-static const MemoryRegionOps e1000_io_ops = {
- .read = e1000_io_read,
- .write = e1000_io_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static bool is_version_1(void *opaque, int version_id)
-{
- return version_id == 1;
-}
-
-static void e1000_pre_save(void *opaque)
-{
- E1000State *s = opaque;
- NetClientState *nc = qemu_get_queue(s->nic);
-
- /* If the mitigation timer is active, emulate a timeout now. */
- if (s->mit_timer_on) {
- e1000_mit_timer(s);
- }
-
- /*
- * If link is down and auto-negotiation is supported and ongoing,
- * complete auto-negotiation immediately. This allows us to look
- * at MII_SR_AUTONEG_COMPLETE to infer link status on load.
- */
- if (nc->link_down && have_autoneg(s)) {
- s->phy_reg[PHY_STATUS] |= MII_SR_AUTONEG_COMPLETE;
- }
-}
-
-static int e1000_post_load(void *opaque, int version_id)
-{
- E1000State *s = opaque;
- NetClientState *nc = qemu_get_queue(s->nic);
-
- if (!chkflag(MIT)) {
- s->mac_reg[ITR] = s->mac_reg[RDTR] = s->mac_reg[RADV] =
- s->mac_reg[TADV] = 0;
- s->mit_irq_level = false;
- }
- s->mit_ide = 0;
- s->mit_timer_on = false;
-
- /* nc.link_down can't be migrated, so infer link_down according
- * to link status bit in mac_reg[STATUS].
- * Alternatively, restart link negotiation if it was in progress. */
- nc->link_down = (s->mac_reg[STATUS] & E1000_STATUS_LU) == 0;
-
- if (have_autoneg(s) &&
- !(s->phy_reg[PHY_STATUS] & MII_SR_AUTONEG_COMPLETE)) {
- nc->link_down = false;
- timer_mod(s->autoneg_timer,
- qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 500);
- }
-
- return 0;
-}
-
-static bool e1000_mit_state_needed(void *opaque)
-{
- E1000State *s = opaque;
-
- return chkflag(MIT);
-}
-
-static bool e1000_full_mac_needed(void *opaque)
-{
- E1000State *s = opaque;
-
- return chkflag(MAC);
-}
-
-static const VMStateDescription vmstate_e1000_mit_state = {
- .name = "e1000/mit_state",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = e1000_mit_state_needed,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(mac_reg[RDTR], E1000State),
- VMSTATE_UINT32(mac_reg[RADV], E1000State),
- VMSTATE_UINT32(mac_reg[TADV], E1000State),
- VMSTATE_UINT32(mac_reg[ITR], E1000State),
- VMSTATE_BOOL(mit_irq_level, E1000State),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_e1000_full_mac_state = {
- .name = "e1000/full_mac_state",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = e1000_full_mac_needed,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(mac_reg, E1000State, 0x8000),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_e1000 = {
- .name = "e1000",
- .version_id = 2,
- .minimum_version_id = 1,
- .pre_save = e1000_pre_save,
- .post_load = e1000_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(parent_obj, E1000State),
- VMSTATE_UNUSED_TEST(is_version_1, 4), /* was instance id */
- VMSTATE_UNUSED(4), /* Was mmio_base. */
- VMSTATE_UINT32(rxbuf_size, E1000State),
- VMSTATE_UINT32(rxbuf_min_shift, E1000State),
- VMSTATE_UINT32(eecd_state.val_in, E1000State),
- VMSTATE_UINT16(eecd_state.bitnum_in, E1000State),
- VMSTATE_UINT16(eecd_state.bitnum_out, E1000State),
- VMSTATE_UINT16(eecd_state.reading, E1000State),
- VMSTATE_UINT32(eecd_state.old_eecd, E1000State),
- VMSTATE_UINT8(tx.ipcss, E1000State),
- VMSTATE_UINT8(tx.ipcso, E1000State),
- VMSTATE_UINT16(tx.ipcse, E1000State),
- VMSTATE_UINT8(tx.tucss, E1000State),
- VMSTATE_UINT8(tx.tucso, E1000State),
- VMSTATE_UINT16(tx.tucse, E1000State),
- VMSTATE_UINT32(tx.paylen, E1000State),
- VMSTATE_UINT8(tx.hdr_len, E1000State),
- VMSTATE_UINT16(tx.mss, E1000State),
- VMSTATE_UINT16(tx.size, E1000State),
- VMSTATE_UINT16(tx.tso_frames, E1000State),
- VMSTATE_UINT8(tx.sum_needed, E1000State),
- VMSTATE_INT8(tx.ip, E1000State),
- VMSTATE_INT8(tx.tcp, E1000State),
- VMSTATE_BUFFER(tx.header, E1000State),
- VMSTATE_BUFFER(tx.data, E1000State),
- VMSTATE_UINT16_ARRAY(eeprom_data, E1000State, 64),
- VMSTATE_UINT16_ARRAY(phy_reg, E1000State, 0x20),
- VMSTATE_UINT32(mac_reg[CTRL], E1000State),
- VMSTATE_UINT32(mac_reg[EECD], E1000State),
- VMSTATE_UINT32(mac_reg[EERD], E1000State),
- VMSTATE_UINT32(mac_reg[GPRC], E1000State),
- VMSTATE_UINT32(mac_reg[GPTC], E1000State),
- VMSTATE_UINT32(mac_reg[ICR], E1000State),
- VMSTATE_UINT32(mac_reg[ICS], E1000State),
- VMSTATE_UINT32(mac_reg[IMC], E1000State),
- VMSTATE_UINT32(mac_reg[IMS], E1000State),
- VMSTATE_UINT32(mac_reg[LEDCTL], E1000State),
- VMSTATE_UINT32(mac_reg[MANC], E1000State),
- VMSTATE_UINT32(mac_reg[MDIC], E1000State),
- VMSTATE_UINT32(mac_reg[MPC], E1000State),
- VMSTATE_UINT32(mac_reg[PBA], E1000State),
- VMSTATE_UINT32(mac_reg[RCTL], E1000State),
- VMSTATE_UINT32(mac_reg[RDBAH], E1000State),
- VMSTATE_UINT32(mac_reg[RDBAL], E1000State),
- VMSTATE_UINT32(mac_reg[RDH], E1000State),
- VMSTATE_UINT32(mac_reg[RDLEN], E1000State),
- VMSTATE_UINT32(mac_reg[RDT], E1000State),
- VMSTATE_UINT32(mac_reg[STATUS], E1000State),
- VMSTATE_UINT32(mac_reg[SWSM], E1000State),
- VMSTATE_UINT32(mac_reg[TCTL], E1000State),
- VMSTATE_UINT32(mac_reg[TDBAH], E1000State),
- VMSTATE_UINT32(mac_reg[TDBAL], E1000State),
- VMSTATE_UINT32(mac_reg[TDH], E1000State),
- VMSTATE_UINT32(mac_reg[TDLEN], E1000State),
- VMSTATE_UINT32(mac_reg[TDT], E1000State),
- VMSTATE_UINT32(mac_reg[TORH], E1000State),
- VMSTATE_UINT32(mac_reg[TORL], E1000State),
- VMSTATE_UINT32(mac_reg[TOTH], E1000State),
- VMSTATE_UINT32(mac_reg[TOTL], E1000State),
- VMSTATE_UINT32(mac_reg[TPR], E1000State),
- VMSTATE_UINT32(mac_reg[TPT], E1000State),
- VMSTATE_UINT32(mac_reg[TXDCTL], E1000State),
- VMSTATE_UINT32(mac_reg[WUFC], E1000State),
- VMSTATE_UINT32(mac_reg[VET], E1000State),
- VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, RA, 32),
- VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, MTA, 128),
- VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, VFTA, 128),
- VMSTATE_END_OF_LIST()
- },
- .subsections = (const VMStateDescription*[]) {
- &vmstate_e1000_mit_state,
- &vmstate_e1000_full_mac_state,
- NULL
- }
-};
-
-/*
- * EEPROM contents documented in Tables 5-2 and 5-3, pp. 98-102.
- * Note: A valid DevId will be inserted during pci_e1000_init().
- */
-static const uint16_t e1000_eeprom_template[64] = {
- 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000,
- 0x3000, 0x1000, 0x6403, 0 /*DevId*/, 0x8086, 0 /*DevId*/, 0x8086, 0x3040,
- 0x0008, 0x2000, 0x7e14, 0x0048, 0x1000, 0x00d8, 0x0000, 0x2700,
- 0x6cc9, 0x3150, 0x0722, 0x040b, 0x0984, 0x0000, 0xc000, 0x0706,
- 0x1008, 0x0000, 0x0f04, 0x7fff, 0x4d01, 0xffff, 0xffff, 0xffff,
- 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
- 0x0100, 0x4000, 0x121c, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
- 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x0000,
-};
-
-/* PCI interface */
-
-static void
-e1000_mmio_setup(E1000State *d)
-{
- int i;
- const uint32_t excluded_regs[] = {
- E1000_MDIC, E1000_ICR, E1000_ICS, E1000_IMS,
- E1000_IMC, E1000_TCTL, E1000_TDT, PNPMMIO_SIZE
- };
-
- memory_region_init_io(&d->mmio, OBJECT(d), &e1000_mmio_ops, d,
- "e1000-mmio", PNPMMIO_SIZE);
- memory_region_add_coalescing(&d->mmio, 0, excluded_regs[0]);
- for (i = 0; excluded_regs[i] != PNPMMIO_SIZE; i++)
- memory_region_add_coalescing(&d->mmio, excluded_regs[i] + 4,
- excluded_regs[i+1] - excluded_regs[i] - 4);
- memory_region_init_io(&d->io, OBJECT(d), &e1000_io_ops, d, "e1000-io", IOPORT_SIZE);
-}
-
-static void
-pci_e1000_uninit(PCIDevice *dev)
-{
- E1000State *d = E1000(dev);
-
- timer_del(d->autoneg_timer);
- timer_free(d->autoneg_timer);
- timer_del(d->mit_timer);
- timer_free(d->mit_timer);
- qemu_del_nic(d->nic);
-}
-
-static NetClientInfo net_e1000_info = {
- .type = NET_CLIENT_OPTIONS_KIND_NIC,
- .size = sizeof(NICState),
- .can_receive = e1000_can_receive,
- .receive = e1000_receive,
- .receive_iov = e1000_receive_iov,
- .link_status_changed = e1000_set_link_status,
-};
-
-static void e1000_write_config(PCIDevice *pci_dev, uint32_t address,
- uint32_t val, int len)
-{
- E1000State *s = E1000(pci_dev);
-
- pci_default_write_config(pci_dev, address, val, len);
-
- if (range_covers_byte(address, len, PCI_COMMAND) &&
- (pci_dev->config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
- qemu_flush_queued_packets(qemu_get_queue(s->nic));
- }
-}
-
-
-static void pci_e1000_realize(PCIDevice *pci_dev, Error **errp)
-{
- DeviceState *dev = DEVICE(pci_dev);
- E1000State *d = E1000(pci_dev);
- PCIDeviceClass *pdc = PCI_DEVICE_GET_CLASS(pci_dev);
- uint8_t *pci_conf;
- uint16_t checksum = 0;
- int i;
- uint8_t *macaddr;
-
- pci_dev->config_write = e1000_write_config;
-
- pci_conf = pci_dev->config;
-
- /* TODO: RST# value should be 0, PCI spec 6.2.4 */
- pci_conf[PCI_CACHE_LINE_SIZE] = 0x10;
-
- pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */
-
- e1000_mmio_setup(d);
-
- pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio);
-
- pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &d->io);
-
- memmove(d->eeprom_data, e1000_eeprom_template,
- sizeof e1000_eeprom_template);
- qemu_macaddr_default_if_unset(&d->conf.macaddr);
- macaddr = d->conf.macaddr.a;
- for (i = 0; i < 3; i++)
- d->eeprom_data[i] = (macaddr[2*i+1]<<8) | macaddr[2*i];
- d->eeprom_data[11] = d->eeprom_data[13] = pdc->device_id;
- for (i = 0; i < EEPROM_CHECKSUM_REG; i++)
- checksum += d->eeprom_data[i];
- checksum = (uint16_t) EEPROM_SUM - checksum;
- d->eeprom_data[EEPROM_CHECKSUM_REG] = checksum;
-
- d->nic = qemu_new_nic(&net_e1000_info, &d->conf,
- object_get_typename(OBJECT(d)), dev->id, d);
-
- qemu_format_nic_info_str(qemu_get_queue(d->nic), macaddr);
-
- d->autoneg_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, e1000_autoneg_timer, d);
- d->mit_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, e1000_mit_timer, d);
-}
-
-static void qdev_e1000_reset(DeviceState *dev)
-{
- E1000State *d = E1000(dev);
- e1000_reset(d);
-}
-
-static Property e1000_properties[] = {
- DEFINE_NIC_PROPERTIES(E1000State, conf),
- DEFINE_PROP_BIT("autonegotiation", E1000State,
- compat_flags, E1000_FLAG_AUTONEG_BIT, true),
- DEFINE_PROP_BIT("mitigation", E1000State,
- compat_flags, E1000_FLAG_MIT_BIT, true),
- DEFINE_PROP_BIT("extra_mac_registers", E1000State,
- compat_flags, E1000_FLAG_MAC_BIT, true),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-typedef struct E1000Info {
- const char *name;
- uint16_t device_id;
- uint8_t revision;
- uint16_t phy_id2;
-} E1000Info;
-
-static void e1000_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- E1000BaseClass *e = E1000_DEVICE_CLASS(klass);
- const E1000Info *info = data;
-
- k->realize = pci_e1000_realize;
- k->exit = pci_e1000_uninit;
- k->romfile = "efi-e1000.rom";
- k->vendor_id = PCI_VENDOR_ID_INTEL;
- k->device_id = info->device_id;
- k->revision = info->revision;
- e->phy_id2 = info->phy_id2;
- k->class_id = PCI_CLASS_NETWORK_ETHERNET;
- set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
- dc->desc = "Intel Gigabit Ethernet";
- dc->reset = qdev_e1000_reset;
- dc->vmsd = &vmstate_e1000;
- dc->props = e1000_properties;
-}
-
-static void e1000_instance_init(Object *obj)
-{
- E1000State *n = E1000(obj);
- device_add_bootindex_property(obj, &n->conf.bootindex,
- "bootindex", "/ethernet-phy@0",
- DEVICE(n), NULL);
-}
-
-static const TypeInfo e1000_base_info = {
- .name = TYPE_E1000_BASE,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(E1000State),
- .instance_init = e1000_instance_init,
- .class_size = sizeof(E1000BaseClass),
- .abstract = true,
-};
-
-static const E1000Info e1000_devices[] = {
- {
- .name = "e1000",
- .device_id = E1000_DEV_ID_82540EM,
- .revision = 0x03,
- .phy_id2 = E1000_PHY_ID2_8254xx_DEFAULT,
- },
- {
- .name = "e1000-82544gc",
- .device_id = E1000_DEV_ID_82544GC_COPPER,
- .revision = 0x03,
- .phy_id2 = E1000_PHY_ID2_82544x,
- },
- {
- .name = "e1000-82545em",
- .device_id = E1000_DEV_ID_82545EM_COPPER,
- .revision = 0x03,
- .phy_id2 = E1000_PHY_ID2_8254xx_DEFAULT,
- },
-};
-
-static void e1000_register_types(void)
-{
- int i;
-
- type_register_static(&e1000_base_info);
- for (i = 0; i < ARRAY_SIZE(e1000_devices); i++) {
- const E1000Info *info = &e1000_devices[i];
- TypeInfo type_info = {};
-
- type_info.name = info->name;
- type_info.parent = TYPE_E1000_BASE;
- type_info.class_data = (void *)info;
- type_info.class_init = e1000_class_init;
- type_info.instance_init = e1000_instance_init;
-
- type_register(&type_info);
- }
-}
-
-type_init(e1000_register_types)
diff --git a/qemu/hw/net/e1000_regs.h b/qemu/hw/net/e1000_regs.h
deleted file mode 100644
index 1c40244ab..000000000
--- a/qemu/hw/net/e1000_regs.h
+++ /dev/null
@@ -1,908 +0,0 @@
-/*******************************************************************************
-
- Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2006 Intel Corporation.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms and conditions of the GNU General Public License,
- version 2, as published by the Free Software Foundation.
-
- This program is distributed in the hope it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, see <http://www.gnu.org/licenses/>.
-
- The full GNU General Public License is included in this distribution in
- the file called "COPYING".
-
- Contact Information:
- Linux NICS <linux.nics@intel.com>
- e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-/* e1000_hw.h
- * Structures, enums, and macros for the MAC
- */
-
-#ifndef _E1000_HW_H_
-#define _E1000_HW_H_
-
-
-/* PCI Device IDs */
-#define E1000_DEV_ID_82542 0x1000
-#define E1000_DEV_ID_82543GC_FIBER 0x1001
-#define E1000_DEV_ID_82543GC_COPPER 0x1004
-#define E1000_DEV_ID_82544EI_COPPER 0x1008
-#define E1000_DEV_ID_82544EI_FIBER 0x1009
-#define E1000_DEV_ID_82544GC_COPPER 0x100C
-#define E1000_DEV_ID_82544GC_LOM 0x100D
-#define E1000_DEV_ID_82540EM 0x100E
-#define E1000_DEV_ID_82540EM_LOM 0x1015
-#define E1000_DEV_ID_82540EP_LOM 0x1016
-#define E1000_DEV_ID_82540EP 0x1017
-#define E1000_DEV_ID_82540EP_LP 0x101E
-#define E1000_DEV_ID_82545EM_COPPER 0x100F
-#define E1000_DEV_ID_82545EM_FIBER 0x1011
-#define E1000_DEV_ID_82545GM_COPPER 0x1026
-#define E1000_DEV_ID_82545GM_FIBER 0x1027
-#define E1000_DEV_ID_82545GM_SERDES 0x1028
-#define E1000_DEV_ID_82546EB_COPPER 0x1010
-#define E1000_DEV_ID_82546EB_FIBER 0x1012
-#define E1000_DEV_ID_82546EB_QUAD_COPPER 0x101D
-#define E1000_DEV_ID_82541EI 0x1013
-#define E1000_DEV_ID_82541EI_MOBILE 0x1018
-#define E1000_DEV_ID_82541ER_LOM 0x1014
-#define E1000_DEV_ID_82541ER 0x1078
-#define E1000_DEV_ID_82547GI 0x1075
-#define E1000_DEV_ID_82541GI 0x1076
-#define E1000_DEV_ID_82541GI_MOBILE 0x1077
-#define E1000_DEV_ID_82541GI_LF 0x107C
-#define E1000_DEV_ID_82546GB_COPPER 0x1079
-#define E1000_DEV_ID_82546GB_FIBER 0x107A
-#define E1000_DEV_ID_82546GB_SERDES 0x107B
-#define E1000_DEV_ID_82546GB_PCIE 0x108A
-#define E1000_DEV_ID_82546GB_QUAD_COPPER 0x1099
-#define E1000_DEV_ID_82547EI 0x1019
-#define E1000_DEV_ID_82547EI_MOBILE 0x101A
-#define E1000_DEV_ID_82571EB_COPPER 0x105E
-#define E1000_DEV_ID_82571EB_FIBER 0x105F
-#define E1000_DEV_ID_82571EB_SERDES 0x1060
-#define E1000_DEV_ID_82571EB_QUAD_COPPER 0x10A4
-#define E1000_DEV_ID_82571PT_QUAD_COPPER 0x10D5
-#define E1000_DEV_ID_82571EB_QUAD_FIBER 0x10A5
-#define E1000_DEV_ID_82571EB_QUAD_COPPER_LOWPROFILE 0x10BC
-#define E1000_DEV_ID_82571EB_SERDES_DUAL 0x10D9
-#define E1000_DEV_ID_82571EB_SERDES_QUAD 0x10DA
-#define E1000_DEV_ID_82572EI_COPPER 0x107D
-#define E1000_DEV_ID_82572EI_FIBER 0x107E
-#define E1000_DEV_ID_82572EI_SERDES 0x107F
-#define E1000_DEV_ID_82572EI 0x10B9
-#define E1000_DEV_ID_82573E 0x108B
-#define E1000_DEV_ID_82573E_IAMT 0x108C
-#define E1000_DEV_ID_82573L 0x109A
-#define E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3 0x10B5
-#define E1000_DEV_ID_80003ES2LAN_COPPER_DPT 0x1096
-#define E1000_DEV_ID_80003ES2LAN_SERDES_DPT 0x1098
-#define E1000_DEV_ID_80003ES2LAN_COPPER_SPT 0x10BA
-#define E1000_DEV_ID_80003ES2LAN_SERDES_SPT 0x10BB
-
-#define E1000_DEV_ID_ICH8_IGP_M_AMT 0x1049
-#define E1000_DEV_ID_ICH8_IGP_AMT 0x104A
-#define E1000_DEV_ID_ICH8_IGP_C 0x104B
-#define E1000_DEV_ID_ICH8_IFE 0x104C
-#define E1000_DEV_ID_ICH8_IFE_GT 0x10C4
-#define E1000_DEV_ID_ICH8_IFE_G 0x10C5
-#define E1000_DEV_ID_ICH8_IGP_M 0x104D
-
-/* Device Specific Register Defaults */
-#define E1000_PHY_ID2_82541x 0x380
-#define E1000_PHY_ID2_82544x 0xC30
-#define E1000_PHY_ID2_8254xx_DEFAULT 0xC20 /* 82540x, 82545x, and 82546x */
-#define E1000_PHY_ID2_82573x 0xCC0
-
-/* Register Set. (82543, 82544)
- *
- * Registers are defined to be 32 bits and should be accessed as 32 bit values.
- * These registers are physically located on the NIC, but are mapped into the
- * host memory address space.
- *
- * RW - register is both readable and writable
- * RO - register is read only
- * WO - register is write only
- * R/clr - register is read only and is cleared when read
- * A - register array
- */
-#define E1000_CTRL 0x00000 /* Device Control - RW */
-#define E1000_CTRL_DUP 0x00004 /* Device Control Duplicate (Shadow) - RW */
-#define E1000_STATUS 0x00008 /* Device Status - RO */
-#define E1000_EECD 0x00010 /* EEPROM/Flash Control - RW */
-#define E1000_EERD 0x00014 /* EEPROM Read - RW */
-#define E1000_CTRL_EXT 0x00018 /* Extended Device Control - RW */
-#define E1000_FLA 0x0001C /* Flash Access - RW */
-#define E1000_MDIC 0x00020 /* MDI Control - RW */
-#define E1000_SCTL 0x00024 /* SerDes Control - RW */
-#define E1000_FEXTNVM 0x00028 /* Future Extended NVM register */
-#define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */
-#define E1000_FCAH 0x0002C /* Flow Control Address High -RW */
-#define E1000_FCT 0x00030 /* Flow Control Type - RW */
-#define E1000_VET 0x00038 /* VLAN Ether Type - RW */
-#define E1000_ICR 0x000C0 /* Interrupt Cause Read - R/clr */
-#define E1000_ITR 0x000C4 /* Interrupt Throttling Rate - RW */
-#define E1000_ICS 0x000C8 /* Interrupt Cause Set - WO */
-#define E1000_IMS 0x000D0 /* Interrupt Mask Set - RW */
-#define E1000_IMC 0x000D8 /* Interrupt Mask Clear - WO */
-#define E1000_IAM 0x000E0 /* Interrupt Acknowledge Auto Mask */
-#define E1000_RCTL 0x00100 /* RX Control - RW */
-#define E1000_RDTR1 0x02820 /* RX Delay Timer (1) - RW */
-#define E1000_RDBAL1 0x02900 /* RX Descriptor Base Address Low (1) - RW */
-#define E1000_RDBAH1 0x02904 /* RX Descriptor Base Address High (1) - RW */
-#define E1000_RDLEN1 0x02908 /* RX Descriptor Length (1) - RW */
-#define E1000_RDH1 0x02910 /* RX Descriptor Head (1) - RW */
-#define E1000_RDT1 0x02918 /* RX Descriptor Tail (1) - RW */
-#define E1000_FCTTV 0x00170 /* Flow Control Transmit Timer Value - RW */
-#define E1000_TXCW 0x00178 /* TX Configuration Word - RW */
-#define E1000_RXCW 0x00180 /* RX Configuration Word - RO */
-#define E1000_TCTL 0x00400 /* TX Control - RW */
-#define E1000_TCTL_EXT 0x00404 /* Extended TX Control - RW */
-#define E1000_TIPG 0x00410 /* TX Inter-packet gap -RW */
-#define E1000_TBT 0x00448 /* TX Burst Timer - RW */
-#define E1000_AIT 0x00458 /* Adaptive Interframe Spacing Throttle - RW */
-#define E1000_LEDCTL 0x00E00 /* LED Control - RW */
-#define E1000_EXTCNF_CTRL 0x00F00 /* Extended Configuration Control */
-#define E1000_EXTCNF_SIZE 0x00F08 /* Extended Configuration Size */
-#define E1000_PHY_CTRL 0x00F10 /* PHY Control Register in CSR */
-#define FEXTNVM_SW_CONFIG 0x0001
-#define E1000_PBA 0x01000 /* Packet Buffer Allocation - RW */
-#define E1000_PBM 0x10000 /* Packet Buffer Memory - RW */
-#define E1000_PBS 0x01008 /* Packet Buffer Size - RW */
-#define E1000_EEMNGCTL 0x01010 /* MNG EEprom Control */
-#define E1000_FLASH_UPDATES 1000
-#define E1000_EEARBC 0x01024 /* EEPROM Auto Read Bus Control */
-#define E1000_FLASHT 0x01028 /* FLASH Timer Register */
-#define E1000_EEWR 0x0102C /* EEPROM Write Register - RW */
-#define E1000_FLSWCTL 0x01030 /* FLASH control register */
-#define E1000_FLSWDATA 0x01034 /* FLASH data register */
-#define E1000_FLSWCNT 0x01038 /* FLASH Access Counter */
-#define E1000_FLOP 0x0103C /* FLASH Opcode Register */
-#define E1000_ERT 0x02008 /* Early Rx Threshold - RW */
-#define E1000_FCRTL 0x02160 /* Flow Control Receive Threshold Low - RW */
-#define E1000_FCRTH 0x02168 /* Flow Control Receive Threshold High - RW */
-#define E1000_PSRCTL 0x02170 /* Packet Split Receive Control - RW */
-#define E1000_RDBAL 0x02800 /* RX Descriptor Base Address Low - RW */
-#define E1000_RDBAH 0x02804 /* RX Descriptor Base Address High - RW */
-#define E1000_RDLEN 0x02808 /* RX Descriptor Length - RW */
-#define E1000_RDH 0x02810 /* RX Descriptor Head - RW */
-#define E1000_RDT 0x02818 /* RX Descriptor Tail - RW */
-#define E1000_RDTR 0x02820 /* RX Delay Timer - RW */
-#define E1000_RDBAL0 E1000_RDBAL /* RX Desc Base Address Low (0) - RW */
-#define E1000_RDBAH0 E1000_RDBAH /* RX Desc Base Address High (0) - RW */
-#define E1000_RDLEN0 E1000_RDLEN /* RX Desc Length (0) - RW */
-#define E1000_RDH0 E1000_RDH /* RX Desc Head (0) - RW */
-#define E1000_RDT0 E1000_RDT /* RX Desc Tail (0) - RW */
-#define E1000_RDTR0 E1000_RDTR /* RX Delay Timer (0) - RW */
-#define E1000_RXDCTL 0x02828 /* RX Descriptor Control queue 0 - RW */
-#define E1000_RXDCTL1 0x02928 /* RX Descriptor Control queue 1 - RW */
-#define E1000_RADV 0x0282C /* RX Interrupt Absolute Delay Timer - RW */
-#define E1000_RSRPD 0x02C00 /* RX Small Packet Detect - RW */
-#define E1000_RAID 0x02C08 /* Receive Ack Interrupt Delay - RW */
-#define E1000_TXDMAC 0x03000 /* TX DMA Control - RW */
-#define E1000_KABGTXD 0x03004 /* AFE Band Gap Transmit Ref Data */
-#define E1000_RDFH 0x02410 /* Receive Data FIFO Head Register - RW */
-#define E1000_RDFT 0x02418 /* Receive Data FIFO Tail Register - RW */
-#define E1000_RDFHS 0x02420 /* Receive Data FIFO Head Saved Register - RW */
-#define E1000_RDFTS 0x02428 /* Receive Data FIFO Tail Saved Register - RW */
-#define E1000_RDFPC 0x02430 /* Receive Data FIFO Packet Count - RW */
-#define E1000_TDFH 0x03410 /* TX Data FIFO Head - RW */
-#define E1000_TDFT 0x03418 /* TX Data FIFO Tail - RW */
-#define E1000_TDFHS 0x03420 /* TX Data FIFO Head Saved - RW */
-#define E1000_TDFTS 0x03428 /* TX Data FIFO Tail Saved - RW */
-#define E1000_TDFPC 0x03430 /* TX Data FIFO Packet Count - RW */
-#define E1000_TDBAL 0x03800 /* TX Descriptor Base Address Low - RW */
-#define E1000_TDBAH 0x03804 /* TX Descriptor Base Address High - RW */
-#define E1000_TDLEN 0x03808 /* TX Descriptor Length - RW */
-#define E1000_TDH 0x03810 /* TX Descriptor Head - RW */
-#define E1000_TDT 0x03818 /* TX Descripotr Tail - RW */
-#define E1000_TIDV 0x03820 /* TX Interrupt Delay Value - RW */
-#define E1000_TXDCTL 0x03828 /* TX Descriptor Control - RW */
-#define E1000_TADV 0x0382C /* TX Interrupt Absolute Delay Val - RW */
-#define E1000_TSPMT 0x03830 /* TCP Segmentation PAD & Min Threshold - RW */
-#define E1000_TARC0 0x03840 /* TX Arbitration Count (0) */
-#define E1000_TDBAL1 0x03900 /* TX Desc Base Address Low (1) - RW */
-#define E1000_TDBAH1 0x03904 /* TX Desc Base Address High (1) - RW */
-#define E1000_TDLEN1 0x03908 /* TX Desc Length (1) - RW */
-#define E1000_TDH1 0x03910 /* TX Desc Head (1) - RW */
-#define E1000_TDT1 0x03918 /* TX Desc Tail (1) - RW */
-#define E1000_TXDCTL1 0x03928 /* TX Descriptor Control (1) - RW */
-#define E1000_TARC1 0x03940 /* TX Arbitration Count (1) */
-#define E1000_CRCERRS 0x04000 /* CRC Error Count - R/clr */
-#define E1000_ALGNERRC 0x04004 /* Alignment Error Count - R/clr */
-#define E1000_SYMERRS 0x04008 /* Symbol Error Count - R/clr */
-#define E1000_RXERRC 0x0400C /* Receive Error Count - R/clr */
-#define E1000_MPC 0x04010 /* Missed Packet Count - R/clr */
-#define E1000_SCC 0x04014 /* Single Collision Count - R/clr */
-#define E1000_ECOL 0x04018 /* Excessive Collision Count - R/clr */
-#define E1000_MCC 0x0401C /* Multiple Collision Count - R/clr */
-#define E1000_LATECOL 0x04020 /* Late Collision Count - R/clr */
-#define E1000_COLC 0x04028 /* Collision Count - R/clr */
-#define E1000_DC 0x04030 /* Defer Count - R/clr */
-#define E1000_TNCRS 0x04034 /* TX-No CRS - R/clr */
-#define E1000_SEC 0x04038 /* Sequence Error Count - R/clr */
-#define E1000_CEXTERR 0x0403C /* Carrier Extension Error Count - R/clr */
-#define E1000_RLEC 0x04040 /* Receive Length Error Count - R/clr */
-#define E1000_XONRXC 0x04048 /* XON RX Count - R/clr */
-#define E1000_XONTXC 0x0404C /* XON TX Count - R/clr */
-#define E1000_XOFFRXC 0x04050 /* XOFF RX Count - R/clr */
-#define E1000_XOFFTXC 0x04054 /* XOFF TX Count - R/clr */
-#define E1000_FCRUC 0x04058 /* Flow Control RX Unsupported Count- R/clr */
-#define E1000_PRC64 0x0405C /* Packets RX (64 bytes) - R/clr */
-#define E1000_PRC127 0x04060 /* Packets RX (65-127 bytes) - R/clr */
-#define E1000_PRC255 0x04064 /* Packets RX (128-255 bytes) - R/clr */
-#define E1000_PRC511 0x04068 /* Packets RX (255-511 bytes) - R/clr */
-#define E1000_PRC1023 0x0406C /* Packets RX (512-1023 bytes) - R/clr */
-#define E1000_PRC1522 0x04070 /* Packets RX (1024-1522 bytes) - R/clr */
-#define E1000_GPRC 0x04074 /* Good Packets RX Count - R/clr */
-#define E1000_BPRC 0x04078 /* Broadcast Packets RX Count - R/clr */
-#define E1000_MPRC 0x0407C /* Multicast Packets RX Count - R/clr */
-#define E1000_GPTC 0x04080 /* Good Packets TX Count - R/clr */
-#define E1000_GORCL 0x04088 /* Good Octets RX Count Low - R/clr */
-#define E1000_GORCH 0x0408C /* Good Octets RX Count High - R/clr */
-#define E1000_GOTCL 0x04090 /* Good Octets TX Count Low - R/clr */
-#define E1000_GOTCH 0x04094 /* Good Octets TX Count High - R/clr */
-#define E1000_RNBC 0x040A0 /* RX No Buffers Count - R/clr */
-#define E1000_RUC 0x040A4 /* RX Undersize Count - R/clr */
-#define E1000_RFC 0x040A8 /* RX Fragment Count - R/clr */
-#define E1000_ROC 0x040AC /* RX Oversize Count - R/clr */
-#define E1000_RJC 0x040B0 /* RX Jabber Count - R/clr */
-#define E1000_MGTPRC 0x040B4 /* Management Packets RX Count - R/clr */
-#define E1000_MGTPDC 0x040B8 /* Management Packets Dropped Count - R/clr */
-#define E1000_MGTPTC 0x040BC /* Management Packets TX Count - R/clr */
-#define E1000_TORL 0x040C0 /* Total Octets RX Low - R/clr */
-#define E1000_TORH 0x040C4 /* Total Octets RX High - R/clr */
-#define E1000_TOTL 0x040C8 /* Total Octets TX Low - R/clr */
-#define E1000_TOTH 0x040CC /* Total Octets TX High - R/clr */
-#define E1000_TPR 0x040D0 /* Total Packets RX - R/clr */
-#define E1000_TPT 0x040D4 /* Total Packets TX - R/clr */
-#define E1000_PTC64 0x040D8 /* Packets TX (64 bytes) - R/clr */
-#define E1000_PTC127 0x040DC /* Packets TX (65-127 bytes) - R/clr */
-#define E1000_PTC255 0x040E0 /* Packets TX (128-255 bytes) - R/clr */
-#define E1000_PTC511 0x040E4 /* Packets TX (256-511 bytes) - R/clr */
-#define E1000_PTC1023 0x040E8 /* Packets TX (512-1023 bytes) - R/clr */
-#define E1000_PTC1522 0x040EC /* Packets TX (1024-1522 Bytes) - R/clr */
-#define E1000_MPTC 0x040F0 /* Multicast Packets TX Count - R/clr */
-#define E1000_BPTC 0x040F4 /* Broadcast Packets TX Count - R/clr */
-#define E1000_TSCTC 0x040F8 /* TCP Segmentation Context TX - R/clr */
-#define E1000_TSCTFC 0x040FC /* TCP Segmentation Context TX Fail - R/clr */
-#define E1000_IAC 0x04100 /* Interrupt Assertion Count */
-#define E1000_ICRXPTC 0x04104 /* Interrupt Cause Rx Packet Timer Expire Count */
-#define E1000_ICRXATC 0x04108 /* Interrupt Cause Rx Absolute Timer Expire Count */
-#define E1000_ICTXPTC 0x0410C /* Interrupt Cause Tx Packet Timer Expire Count */
-#define E1000_ICTXATC 0x04110 /* Interrupt Cause Tx Absolute Timer Expire Count */
-#define E1000_ICTXQEC 0x04118 /* Interrupt Cause Tx Queue Empty Count */
-#define E1000_ICTXQMTC 0x0411C /* Interrupt Cause Tx Queue Minimum Threshold Count */
-#define E1000_ICRXDMTC 0x04120 /* Interrupt Cause Rx Descriptor Minimum Threshold Count */
-#define E1000_ICRXOC 0x04124 /* Interrupt Cause Receiver Overrun Count */
-#define E1000_RXCSUM 0x05000 /* RX Checksum Control - RW */
-#define E1000_RFCTL 0x05008 /* Receive Filter Control*/
-#define E1000_MTA 0x05200 /* Multicast Table Array - RW Array */
-#define E1000_RA 0x05400 /* Receive Address - RW Array */
-#define E1000_VFTA 0x05600 /* VLAN Filter Table Array - RW Array */
-#define E1000_WUC 0x05800 /* Wakeup Control - RW */
-#define E1000_WUFC 0x05808 /* Wakeup Filter Control - RW */
-#define E1000_WUS 0x05810 /* Wakeup Status - RO */
-#define E1000_MANC 0x05820 /* Management Control - RW */
-#define E1000_IPAV 0x05838 /* IP Address Valid - RW */
-#define E1000_IP4AT 0x05840 /* IPv4 Address Table - RW Array */
-#define E1000_IP6AT 0x05880 /* IPv6 Address Table - RW Array */
-#define E1000_WUPL 0x05900 /* Wakeup Packet Length - RW */
-#define E1000_WUPM 0x05A00 /* Wakeup Packet Memory - RO A */
-#define E1000_FFLT 0x05F00 /* Flexible Filter Length Table - RW Array */
-#define E1000_HOST_IF 0x08800 /* Host Interface */
-#define E1000_FFMT 0x09000 /* Flexible Filter Mask Table - RW Array */
-#define E1000_FFVT 0x09800 /* Flexible Filter Value Table - RW Array */
-
-#define E1000_KUMCTRLSTA 0x00034 /* MAC-PHY interface - RW */
-#define E1000_MDPHYA 0x0003C /* PHY address - RW */
-#define E1000_MANC2H 0x05860 /* Management Control To Host - RW */
-#define E1000_SW_FW_SYNC 0x05B5C /* Software-Firmware Synchronization - RW */
-
-#define E1000_GCR 0x05B00 /* PCI-Ex Control */
-#define E1000_GSCL_1 0x05B10 /* PCI-Ex Statistic Control #1 */
-#define E1000_GSCL_2 0x05B14 /* PCI-Ex Statistic Control #2 */
-#define E1000_GSCL_3 0x05B18 /* PCI-Ex Statistic Control #3 */
-#define E1000_GSCL_4 0x05B1C /* PCI-Ex Statistic Control #4 */
-#define E1000_FACTPS 0x05B30 /* Function Active and Power State to MNG */
-#define E1000_SWSM 0x05B50 /* SW Semaphore */
-#define E1000_FWSM 0x05B54 /* FW Semaphore */
-#define E1000_FFLT_DBG 0x05F04 /* Debug Register */
-#define E1000_HICR 0x08F00 /* Host Inteface Control */
-
-/* RSS registers */
-#define E1000_CPUVEC 0x02C10 /* CPU Vector Register - RW */
-#define E1000_MRQC 0x05818 /* Multiple Receive Control - RW */
-#define E1000_RETA 0x05C00 /* Redirection Table - RW Array */
-#define E1000_RSSRK 0x05C80 /* RSS Random Key - RW Array */
-#define E1000_RSSIM 0x05864 /* RSS Interrupt Mask */
-#define E1000_RSSIR 0x05868 /* RSS Interrupt Request */
-
-/* PHY 1000 MII Register/Bit Definitions */
-/* PHY Registers defined by IEEE */
-#define PHY_CTRL 0x00 /* Control Register */
-#define PHY_STATUS 0x01 /* Status Regiser */
-#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */
-#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */
-#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */
-#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */
-#define PHY_AUTONEG_EXP 0x06 /* Autoneg Expansion Reg */
-#define PHY_NEXT_PAGE_TX 0x07 /* Next Page TX */
-#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */
-#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */
-#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
-#define PHY_EXT_STATUS 0x0F /* Extended Status Reg */
-
-#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */
-#define MAX_PHY_MULTI_PAGE_REG 0xF /* Registers equal on all pages */
-
-/* M88E1000 Specific Registers */
-#define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */
-#define M88E1000_PHY_SPEC_STATUS 0x11 /* PHY Specific Status Register */
-#define M88E1000_INT_ENABLE 0x12 /* Interrupt Enable Register */
-#define M88E1000_INT_STATUS 0x13 /* Interrupt Status Register */
-#define M88E1000_EXT_PHY_SPEC_CTRL 0x14 /* Extended PHY Specific Control */
-#define M88E1000_RX_ERR_CNTR 0x15 /* Receive Error Counter */
-
-#define M88E1000_PHY_EXT_CTRL 0x1A /* PHY extend control register */
-#define M88E1000_PHY_PAGE_SELECT 0x1D /* Reg 29 for page number setting */
-#define M88E1000_PHY_GEN_CONTROL 0x1E /* Its meaning depends on reg 29 */
-#define M88E1000_PHY_VCO_REG_BIT8 0x100 /* Bits 8 & 11 are adjusted for */
-#define M88E1000_PHY_VCO_REG_BIT11 0x800 /* improved BER performance */
-
-/* PHY Control Register */
-#define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */
-#define MII_CR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */
-#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */
-#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */
-#define MII_CR_ISOLATE 0x0400 /* Isolate PHY from MII */
-#define MII_CR_POWER_DOWN 0x0800 /* Power down */
-#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */
-#define MII_CR_SPEED_SELECT_LSB 0x2000 /* bits 6,13: 10=1000, 01=100, 00=10 */
-#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */
-#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */
-
-/* PHY Status Register */
-#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */
-#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */
-#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */
-#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */
-#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */
-#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */
-#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */
-#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */
-#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */
-#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */
-#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */
-#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */
-#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */
-#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */
-#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */
-
-/* PHY Link Partner Ability Register */
-#define MII_LPAR_LPACK 0x4000 /* Acked by link partner */
-
-/* Interrupt Cause Read */
-#define E1000_ICR_TXDW 0x00000001 /* Transmit desc written back */
-#define E1000_ICR_TXQE 0x00000002 /* Transmit Queue empty */
-#define E1000_ICR_LSC 0x00000004 /* Link Status Change */
-#define E1000_ICR_RXSEQ 0x00000008 /* rx sequence error */
-#define E1000_ICR_RXDMT0 0x00000010 /* rx desc min. threshold (0) */
-#define E1000_ICR_RXO 0x00000040 /* rx overrun */
-#define E1000_ICR_RXT0 0x00000080 /* rx timer intr (ring 0) */
-#define E1000_ICR_MDAC 0x00000200 /* MDIO access complete */
-#define E1000_ICR_RXCFG 0x00000400 /* RX /c/ ordered set */
-#define E1000_ICR_GPI_EN0 0x00000800 /* GP Int 0 */
-#define E1000_ICR_GPI_EN1 0x00001000 /* GP Int 1 */
-#define E1000_ICR_GPI_EN2 0x00002000 /* GP Int 2 */
-#define E1000_ICR_GPI_EN3 0x00004000 /* GP Int 3 */
-#define E1000_ICR_TXD_LOW 0x00008000
-#define E1000_ICR_SRPD 0x00010000
-#define E1000_ICR_ACK 0x00020000 /* Receive Ack frame */
-#define E1000_ICR_MNG 0x00040000 /* Manageability event */
-#define E1000_ICR_DOCK 0x00080000 /* Dock/Undock */
-#define E1000_ICR_INT_ASSERTED 0x80000000 /* If this bit asserted, the driver should claim the interrupt */
-#define E1000_ICR_RXD_FIFO_PAR0 0x00100000 /* queue 0 Rx descriptor FIFO parity error */
-#define E1000_ICR_TXD_FIFO_PAR0 0x00200000 /* queue 0 Tx descriptor FIFO parity error */
-#define E1000_ICR_HOST_ARB_PAR 0x00400000 /* host arb read buffer parity error */
-#define E1000_ICR_PB_PAR 0x00800000 /* packet buffer parity error */
-#define E1000_ICR_RXD_FIFO_PAR1 0x01000000 /* queue 1 Rx descriptor FIFO parity error */
-#define E1000_ICR_TXD_FIFO_PAR1 0x02000000 /* queue 1 Tx descriptor FIFO parity error */
-#define E1000_ICR_ALL_PARITY 0x03F00000 /* all parity error bits */
-#define E1000_ICR_DSW 0x00000020 /* FW changed the status of DISSW bit in the FWSM */
-#define E1000_ICR_PHYINT 0x00001000 /* LAN connected device generates an interrupt */
-#define E1000_ICR_EPRST 0x00100000 /* ME handware reset occurs */
-
-/* Interrupt Cause Set */
-#define E1000_ICS_TXDW E1000_ICR_TXDW /* Transmit desc written back */
-#define E1000_ICS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */
-#define E1000_ICS_LSC E1000_ICR_LSC /* Link Status Change */
-#define E1000_ICS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */
-#define E1000_ICS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */
-#define E1000_ICS_RXO E1000_ICR_RXO /* rx overrun */
-#define E1000_ICS_RXT0 E1000_ICR_RXT0 /* rx timer intr */
-#define E1000_ICS_MDAC E1000_ICR_MDAC /* MDIO access complete */
-#define E1000_ICS_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */
-#define E1000_ICS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */
-#define E1000_ICS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */
-#define E1000_ICS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */
-#define E1000_ICS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */
-#define E1000_ICS_TXD_LOW E1000_ICR_TXD_LOW
-#define E1000_ICS_SRPD E1000_ICR_SRPD
-#define E1000_ICS_ACK E1000_ICR_ACK /* Receive Ack frame */
-#define E1000_ICS_MNG E1000_ICR_MNG /* Manageability event */
-#define E1000_ICS_DOCK E1000_ICR_DOCK /* Dock/Undock */
-#define E1000_ICS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */
-#define E1000_ICS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */
-#define E1000_ICS_HOST_ARB_PAR E1000_ICR_HOST_ARB_PAR /* host arb read buffer parity error */
-#define E1000_ICS_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity error */
-#define E1000_ICS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */
-#define E1000_ICS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */
-#define E1000_ICS_DSW E1000_ICR_DSW
-#define E1000_ICS_PHYINT E1000_ICR_PHYINT
-#define E1000_ICS_EPRST E1000_ICR_EPRST
-
-/* Interrupt Mask Set */
-#define E1000_IMS_TXDW E1000_ICR_TXDW /* Transmit desc written back */
-#define E1000_IMS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */
-#define E1000_IMS_LSC E1000_ICR_LSC /* Link Status Change */
-#define E1000_IMS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */
-#define E1000_IMS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */
-#define E1000_IMS_RXO E1000_ICR_RXO /* rx overrun */
-#define E1000_IMS_RXT0 E1000_ICR_RXT0 /* rx timer intr */
-#define E1000_IMS_MDAC E1000_ICR_MDAC /* MDIO access complete */
-#define E1000_IMS_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */
-#define E1000_IMS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */
-#define E1000_IMS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */
-#define E1000_IMS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */
-#define E1000_IMS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */
-#define E1000_IMS_TXD_LOW E1000_ICR_TXD_LOW
-#define E1000_IMS_SRPD E1000_ICR_SRPD
-#define E1000_IMS_ACK E1000_ICR_ACK /* Receive Ack frame */
-#define E1000_IMS_MNG E1000_ICR_MNG /* Manageability event */
-#define E1000_IMS_DOCK E1000_ICR_DOCK /* Dock/Undock */
-#define E1000_IMS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */
-#define E1000_IMS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */
-#define E1000_IMS_HOST_ARB_PAR E1000_ICR_HOST_ARB_PAR /* host arb read buffer parity error */
-#define E1000_IMS_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity error */
-#define E1000_IMS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */
-#define E1000_IMS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */
-#define E1000_IMS_DSW E1000_ICR_DSW
-#define E1000_IMS_PHYINT E1000_ICR_PHYINT
-#define E1000_IMS_EPRST E1000_ICR_EPRST
-
-/* Interrupt Mask Clear */
-#define E1000_IMC_TXDW E1000_ICR_TXDW /* Transmit desc written back */
-#define E1000_IMC_TXQE E1000_ICR_TXQE /* Transmit Queue empty */
-#define E1000_IMC_LSC E1000_ICR_LSC /* Link Status Change */
-#define E1000_IMC_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */
-#define E1000_IMC_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */
-#define E1000_IMC_RXO E1000_ICR_RXO /* rx overrun */
-#define E1000_IMC_RXT0 E1000_ICR_RXT0 /* rx timer intr */
-#define E1000_IMC_MDAC E1000_ICR_MDAC /* MDIO access complete */
-#define E1000_IMC_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */
-#define E1000_IMC_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */
-#define E1000_IMC_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */
-#define E1000_IMC_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */
-#define E1000_IMC_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */
-#define E1000_IMC_TXD_LOW E1000_ICR_TXD_LOW
-#define E1000_IMC_SRPD E1000_ICR_SRPD
-#define E1000_IMC_ACK E1000_ICR_ACK /* Receive Ack frame */
-#define E1000_IMC_MNG E1000_ICR_MNG /* Manageability event */
-#define E1000_IMC_DOCK E1000_ICR_DOCK /* Dock/Undock */
-#define E1000_IMC_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */
-#define E1000_IMC_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */
-#define E1000_IMC_HOST_ARB_PAR E1000_ICR_HOST_ARB_PAR /* host arb read buffer parity error */
-#define E1000_IMC_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity error */
-#define E1000_IMC_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */
-#define E1000_IMC_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */
-#define E1000_IMC_DSW E1000_ICR_DSW
-#define E1000_IMC_PHYINT E1000_ICR_PHYINT
-#define E1000_IMC_EPRST E1000_ICR_EPRST
-
-/* Receive Control */
-#define E1000_RCTL_RST 0x00000001 /* Software reset */
-#define E1000_RCTL_EN 0x00000002 /* enable */
-#define E1000_RCTL_SBP 0x00000004 /* store bad packet */
-#define E1000_RCTL_UPE 0x00000008 /* unicast promiscuous enable */
-#define E1000_RCTL_MPE 0x00000010 /* multicast promiscuous enab */
-#define E1000_RCTL_LPE 0x00000020 /* long packet enable */
-#define E1000_RCTL_LBM_NO 0x00000000 /* no loopback mode */
-#define E1000_RCTL_LBM_MAC 0x00000040 /* MAC loopback mode */
-#define E1000_RCTL_LBM_SLP 0x00000080 /* serial link loopback mode */
-#define E1000_RCTL_LBM_TCVR 0x000000C0 /* tcvr loopback mode */
-#define E1000_RCTL_DTYP_MASK 0x00000C00 /* Descriptor type mask */
-#define E1000_RCTL_DTYP_PS 0x00000400 /* Packet Split descriptor */
-#define E1000_RCTL_RDMTS_HALF 0x00000000 /* rx desc min threshold size */
-#define E1000_RCTL_RDMTS_QUAT 0x00000100 /* rx desc min threshold size */
-#define E1000_RCTL_RDMTS_EIGTH 0x00000200 /* rx desc min threshold size */
-#define E1000_RCTL_MO_SHIFT 12 /* multicast offset shift */
-#define E1000_RCTL_MO_0 0x00000000 /* multicast offset 11:0 */
-#define E1000_RCTL_MO_1 0x00001000 /* multicast offset 12:1 */
-#define E1000_RCTL_MO_2 0x00002000 /* multicast offset 13:2 */
-#define E1000_RCTL_MO_3 0x00003000 /* multicast offset 15:4 */
-#define E1000_RCTL_MDR 0x00004000 /* multicast desc ring 0 */
-#define E1000_RCTL_BAM 0x00008000 /* broadcast enable */
-/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */
-#define E1000_RCTL_SZ_2048 0x00000000 /* rx buffer size 2048 */
-#define E1000_RCTL_SZ_1024 0x00010000 /* rx buffer size 1024 */
-#define E1000_RCTL_SZ_512 0x00020000 /* rx buffer size 512 */
-#define E1000_RCTL_SZ_256 0x00030000 /* rx buffer size 256 */
-/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */
-#define E1000_RCTL_SZ_16384 0x00010000 /* rx buffer size 16384 */
-#define E1000_RCTL_SZ_8192 0x00020000 /* rx buffer size 8192 */
-#define E1000_RCTL_SZ_4096 0x00030000 /* rx buffer size 4096 */
-#define E1000_RCTL_VFE 0x00040000 /* vlan filter enable */
-#define E1000_RCTL_CFIEN 0x00080000 /* canonical form enable */
-#define E1000_RCTL_CFI 0x00100000 /* canonical form indicator */
-#define E1000_RCTL_DPF 0x00400000 /* discard pause frames */
-#define E1000_RCTL_PMCF 0x00800000 /* pass MAC control frames */
-#define E1000_RCTL_BSEX 0x02000000 /* Buffer size extension */
-#define E1000_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */
-#define E1000_RCTL_FLXBUF_MASK 0x78000000 /* Flexible buffer size */
-#define E1000_RCTL_FLXBUF_SHIFT 27 /* Flexible buffer shift */
-
-
-#define E1000_EEPROM_SWDPIN0 0x0001 /* SWDPIN 0 EEPROM Value */
-#define E1000_EEPROM_LED_LOGIC 0x0020 /* Led Logic Word */
-#define E1000_EEPROM_RW_REG_DATA 16 /* Offset to data in EEPROM read/write registers */
-#define E1000_EEPROM_RW_REG_DONE 0x10 /* Offset to READ/WRITE done bit */
-#define E1000_EEPROM_RW_REG_START 1 /* First bit for telling part to start operation */
-#define E1000_EEPROM_RW_ADDR_SHIFT 8 /* Shift to the address bits */
-#define E1000_EEPROM_POLL_WRITE 1 /* Flag for polling for write complete */
-#define E1000_EEPROM_POLL_READ 0 /* Flag for polling for read complete */
-/* Register Bit Masks */
-/* Device Control */
-#define E1000_CTRL_FD 0x00000001 /* Full duplex.0=half; 1=full */
-#define E1000_CTRL_BEM 0x00000002 /* Endian Mode.0=little,1=big */
-#define E1000_CTRL_PRIOR 0x00000004 /* Priority on PCI. 0=rx,1=fair */
-#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master requests */
-#define E1000_CTRL_LRST 0x00000008 /* Link reset. 0=normal,1=reset */
-#define E1000_CTRL_TME 0x00000010 /* Test mode. 0=normal,1=test */
-#define E1000_CTRL_SLE 0x00000020 /* Serial Link on 0=dis,1=en */
-#define E1000_CTRL_ASDE 0x00000020 /* Auto-speed detect enable */
-#define E1000_CTRL_SLU 0x00000040 /* Set link up (Force Link) */
-#define E1000_CTRL_ILOS 0x00000080 /* Invert Loss-Of Signal */
-#define E1000_CTRL_SPD_SEL 0x00000300 /* Speed Select Mask */
-#define E1000_CTRL_SPD_10 0x00000000 /* Force 10Mb */
-#define E1000_CTRL_SPD_100 0x00000100 /* Force 100Mb */
-#define E1000_CTRL_SPD_1000 0x00000200 /* Force 1Gb */
-#define E1000_CTRL_BEM32 0x00000400 /* Big Endian 32 mode */
-#define E1000_CTRL_FRCSPD 0x00000800 /* Force Speed */
-#define E1000_CTRL_FRCDPX 0x00001000 /* Force Duplex */
-#define E1000_CTRL_D_UD_EN 0x00002000 /* Dock/Undock enable */
-#define E1000_CTRL_D_UD_POLARITY 0x00004000 /* Defined polarity of Dock/Undock indication in SDP[0] */
-#define E1000_CTRL_FORCE_PHY_RESET 0x00008000 /* Reset both PHY ports, through PHYRST_N pin */
-#define E1000_CTRL_EXT_LINK_EN 0x00010000 /* enable link status from external LINK_0 and LINK_1 pins */
-#define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */
-#define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */
-#define E1000_CTRL_SWDPIN2 0x00100000 /* SWDPIN 2 value */
-#define E1000_CTRL_SWDPIN3 0x00200000 /* SWDPIN 3 value */
-#define E1000_CTRL_SWDPIO0 0x00400000 /* SWDPIN 0 Input or output */
-#define E1000_CTRL_SWDPIO1 0x00800000 /* SWDPIN 1 input or output */
-#define E1000_CTRL_SWDPIO2 0x01000000 /* SWDPIN 2 input or output */
-#define E1000_CTRL_SWDPIO3 0x02000000 /* SWDPIN 3 input or output */
-#define E1000_CTRL_RST 0x04000000 /* Global reset */
-#define E1000_CTRL_RFCE 0x08000000 /* Receive Flow Control enable */
-#define E1000_CTRL_TFCE 0x10000000 /* Transmit flow control enable */
-#define E1000_CTRL_RTE 0x20000000 /* Routing tag enable */
-#define E1000_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */
-#define E1000_CTRL_PHY_RST 0x80000000 /* PHY Reset */
-#define E1000_CTRL_SW2FW_INT 0x02000000 /* Initiate an interrupt to manageability engine */
-
-/* Device Status */
-#define E1000_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */
-#define E1000_STATUS_LU 0x00000002 /* Link up.0=no,1=link */
-#define E1000_STATUS_FUNC_MASK 0x0000000C /* PCI Function Mask */
-#define E1000_STATUS_FUNC_SHIFT 2
-#define E1000_STATUS_FUNC_0 0x00000000 /* Function 0 */
-#define E1000_STATUS_FUNC_1 0x00000004 /* Function 1 */
-#define E1000_STATUS_TXOFF 0x00000010 /* transmission paused */
-#define E1000_STATUS_TBIMODE 0x00000020 /* TBI mode */
-#define E1000_STATUS_SPEED_MASK 0x000000C0
-#define E1000_STATUS_SPEED_10 0x00000000 /* Speed 10Mb/s */
-#define E1000_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */
-#define E1000_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */
-#define E1000_STATUS_LAN_INIT_DONE 0x00000200 /* Lan Init Completion
- by EEPROM/Flash */
-#define E1000_STATUS_ASDV 0x00000300 /* Auto speed detect value */
-#define E1000_STATUS_DOCK_CI 0x00000800 /* Change in Dock/Undock state. Clear on write '0'. */
-#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Status of Master requests. */
-#define E1000_STATUS_MTXCKOK 0x00000400 /* MTX clock running OK */
-#define E1000_STATUS_PCI66 0x00000800 /* In 66Mhz slot */
-#define E1000_STATUS_BUS64 0x00001000 /* In 64 bit slot */
-#define E1000_STATUS_PCIX_MODE 0x00002000 /* PCI-X mode */
-#define E1000_STATUS_PCIX_SPEED 0x0000C000 /* PCI-X bus speed */
-#define E1000_STATUS_BMC_SKU_0 0x00100000 /* BMC USB redirect disabled */
-#define E1000_STATUS_BMC_SKU_1 0x00200000 /* BMC SRAM disabled */
-#define E1000_STATUS_BMC_SKU_2 0x00400000 /* BMC SDRAM disabled */
-#define E1000_STATUS_BMC_CRYPTO 0x00800000 /* BMC crypto disabled */
-#define E1000_STATUS_BMC_LITE 0x01000000 /* BMC external code execution disabled */
-#define E1000_STATUS_RGMII_ENABLE 0x02000000 /* RGMII disabled */
-#define E1000_STATUS_FUSE_8 0x04000000
-#define E1000_STATUS_FUSE_9 0x08000000
-#define E1000_STATUS_SERDES0_DIS 0x10000000 /* SERDES disabled on port 0 */
-#define E1000_STATUS_SERDES1_DIS 0x20000000 /* SERDES disabled on port 1 */
-
-/* EEPROM/Flash Control */
-#define E1000_EECD_SK 0x00000001 /* EEPROM Clock */
-#define E1000_EECD_CS 0x00000002 /* EEPROM Chip Select */
-#define E1000_EECD_DI 0x00000004 /* EEPROM Data In */
-#define E1000_EECD_DO 0x00000008 /* EEPROM Data Out */
-#define E1000_EECD_FWE_MASK 0x00000030
-#define E1000_EECD_FWE_DIS 0x00000010 /* Disable FLASH writes */
-#define E1000_EECD_FWE_EN 0x00000020 /* Enable FLASH writes */
-#define E1000_EECD_FWE_SHIFT 4
-#define E1000_EECD_REQ 0x00000040 /* EEPROM Access Request */
-#define E1000_EECD_GNT 0x00000080 /* EEPROM Access Grant */
-#define E1000_EECD_PRES 0x00000100 /* EEPROM Present */
-#define E1000_EECD_SIZE 0x00000200 /* EEPROM Size (0=64 word 1=256 word) */
-#define E1000_EECD_ADDR_BITS 0x00000400 /* EEPROM Addressing bits based on type
- * (0-small, 1-large) */
-#define E1000_EECD_TYPE 0x00002000 /* EEPROM Type (1-SPI, 0-Microwire) */
-#ifndef E1000_EEPROM_GRANT_ATTEMPTS
-#define E1000_EEPROM_GRANT_ATTEMPTS 1000 /* EEPROM # attempts to gain grant */
-#endif
-#define E1000_EECD_AUTO_RD 0x00000200 /* EEPROM Auto Read done */
-#define E1000_EECD_SIZE_EX_MASK 0x00007800 /* EEprom Size */
-#define E1000_EECD_SIZE_EX_SHIFT 11
-#define E1000_EECD_NVADDS 0x00018000 /* NVM Address Size */
-#define E1000_EECD_SELSHAD 0x00020000 /* Select Shadow RAM */
-#define E1000_EECD_INITSRAM 0x00040000 /* Initialize Shadow RAM */
-#define E1000_EECD_FLUPD 0x00080000 /* Update FLASH */
-#define E1000_EECD_AUPDEN 0x00100000 /* Enable Autonomous FLASH update */
-#define E1000_EECD_SHADV 0x00200000 /* Shadow RAM Data Valid */
-#define E1000_EECD_SEC1VAL 0x00400000 /* Sector One Valid */
-#define E1000_EECD_SECVAL_SHIFT 22
-#define E1000_STM_OPCODE 0xDB00
-#define E1000_HICR_FW_RESET 0xC0
-
-#define E1000_SHADOW_RAM_WORDS 2048
-#define E1000_ICH_NVM_SIG_WORD 0x13
-#define E1000_ICH_NVM_SIG_MASK 0xC0
-
-/* MDI Control */
-#define E1000_MDIC_DATA_MASK 0x0000FFFF
-#define E1000_MDIC_REG_MASK 0x001F0000
-#define E1000_MDIC_REG_SHIFT 16
-#define E1000_MDIC_PHY_MASK 0x03E00000
-#define E1000_MDIC_PHY_SHIFT 21
-#define E1000_MDIC_OP_WRITE 0x04000000
-#define E1000_MDIC_OP_READ 0x08000000
-#define E1000_MDIC_READY 0x10000000
-#define E1000_MDIC_INT_EN 0x20000000
-#define E1000_MDIC_ERROR 0x40000000
-
-/* EEPROM Commands - Microwire */
-#define EEPROM_READ_OPCODE_MICROWIRE 0x6 /* EEPROM read opcode */
-#define EEPROM_WRITE_OPCODE_MICROWIRE 0x5 /* EEPROM write opcode */
-#define EEPROM_ERASE_OPCODE_MICROWIRE 0x7 /* EEPROM erase opcode */
-#define EEPROM_EWEN_OPCODE_MICROWIRE 0x13 /* EEPROM erase/write enable */
-#define EEPROM_EWDS_OPCODE_MICROWIRE 0x10 /* EEPROM erast/write disable */
-
-/* EEPROM Word Offsets */
-#define EEPROM_COMPAT 0x0003
-#define EEPROM_ID_LED_SETTINGS 0x0004
-#define EEPROM_VERSION 0x0005
-#define EEPROM_SERDES_AMPLITUDE 0x0006 /* For SERDES output amplitude adjustment. */
-#define EEPROM_PHY_CLASS_WORD 0x0007
-#define EEPROM_INIT_CONTROL1_REG 0x000A
-#define EEPROM_INIT_CONTROL2_REG 0x000F
-#define EEPROM_SWDEF_PINS_CTRL_PORT_1 0x0010
-#define EEPROM_INIT_CONTROL3_PORT_B 0x0014
-#define EEPROM_INIT_3GIO_3 0x001A
-#define EEPROM_SWDEF_PINS_CTRL_PORT_0 0x0020
-#define EEPROM_INIT_CONTROL3_PORT_A 0x0024
-#define EEPROM_CFG 0x0012
-#define EEPROM_FLASH_VERSION 0x0032
-#define EEPROM_CHECKSUM_REG 0x003F
-
-#define E1000_EEPROM_CFG_DONE 0x00040000 /* MNG config cycle done */
-#define E1000_EEPROM_CFG_DONE_PORT_1 0x00080000 /* ...for second port */
-
-/* Transmit Descriptor */
-struct e1000_tx_desc {
- uint64_t buffer_addr; /* Address of the descriptor's data buffer */
- union {
- uint32_t data;
- struct {
- uint16_t length; /* Data buffer length */
- uint8_t cso; /* Checksum offset */
- uint8_t cmd; /* Descriptor control */
- } flags;
- } lower;
- union {
- uint32_t data;
- struct {
- uint8_t status; /* Descriptor status */
- uint8_t css; /* Checksum start */
- uint16_t special;
- } fields;
- } upper;
-};
-
-/* Transmit Descriptor bit definitions */
-#define E1000_TXD_DTYP_D 0x00100000 /* Data Descriptor */
-#define E1000_TXD_DTYP_C 0x00000000 /* Context Descriptor */
-#define E1000_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */
-#define E1000_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */
-#define E1000_TXD_CMD_EOP 0x01000000 /* End of Packet */
-#define E1000_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */
-#define E1000_TXD_CMD_IC 0x04000000 /* Insert Checksum */
-#define E1000_TXD_CMD_RS 0x08000000 /* Report Status */
-#define E1000_TXD_CMD_RPS 0x10000000 /* Report Packet Sent */
-#define E1000_TXD_CMD_DEXT 0x20000000 /* Descriptor extension (0 = legacy) */
-#define E1000_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */
-#define E1000_TXD_CMD_IDE 0x80000000 /* Enable Tidv register */
-#define E1000_TXD_STAT_DD 0x00000001 /* Descriptor Done */
-#define E1000_TXD_STAT_EC 0x00000002 /* Excess Collisions */
-#define E1000_TXD_STAT_LC 0x00000004 /* Late Collisions */
-#define E1000_TXD_STAT_TU 0x00000008 /* Transmit underrun */
-#define E1000_TXD_CMD_TCP 0x01000000 /* TCP packet */
-#define E1000_TXD_CMD_IP 0x02000000 /* IP packet */
-#define E1000_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */
-#define E1000_TXD_STAT_TC 0x00000004 /* Tx Underrun */
-
-/* Transmit Control */
-#define E1000_TCTL_RST 0x00000001 /* software reset */
-#define E1000_TCTL_EN 0x00000002 /* enable tx */
-#define E1000_TCTL_BCE 0x00000004 /* busy check enable */
-#define E1000_TCTL_PSP 0x00000008 /* pad short packets */
-#define E1000_TCTL_CT 0x00000ff0 /* collision threshold */
-#define E1000_TCTL_COLD 0x003ff000 /* collision distance */
-#define E1000_TCTL_SWXOFF 0x00400000 /* SW Xoff transmission */
-#define E1000_TCTL_PBE 0x00800000 /* Packet Burst Enable */
-#define E1000_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */
-#define E1000_TCTL_NRTU 0x02000000 /* No Re-transmit on underrun */
-#define E1000_TCTL_MULR 0x10000000 /* Multiple request support */
-
-/* Receive Descriptor */
-struct e1000_rx_desc {
- uint64_t buffer_addr; /* Address of the descriptor's data buffer */
- uint16_t length; /* Length of data DMAed into data buffer */
- uint16_t csum; /* Packet checksum */
- uint8_t status; /* Descriptor status */
- uint8_t errors; /* Descriptor Errors */
- uint16_t special;
-};
-
-/* Receive Descriptor bit definitions */
-#define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */
-#define E1000_RXD_STAT_EOP 0x02 /* End of Packet */
-#define E1000_RXD_STAT_IXSM 0x04 /* Ignore checksum */
-#define E1000_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */
-#define E1000_RXD_STAT_UDPCS 0x10 /* UDP xsum caculated */
-#define E1000_RXD_STAT_TCPCS 0x20 /* TCP xsum calculated */
-#define E1000_RXD_STAT_IPCS 0x40 /* IP xsum calculated */
-#define E1000_RXD_STAT_PIF 0x80 /* passed in-exact filter */
-#define E1000_RXD_STAT_IPIDV 0x200 /* IP identification valid */
-#define E1000_RXD_STAT_UDPV 0x400 /* Valid UDP checksum */
-#define E1000_RXD_STAT_ACK 0x8000 /* ACK Packet indication */
-#define E1000_RXD_ERR_CE 0x01 /* CRC Error */
-#define E1000_RXD_ERR_SE 0x02 /* Symbol Error */
-#define E1000_RXD_ERR_SEQ 0x04 /* Sequence Error */
-#define E1000_RXD_ERR_CXE 0x10 /* Carrier Extension Error */
-#define E1000_RXD_ERR_TCPE 0x20 /* TCP/UDP Checksum Error */
-#define E1000_RXD_ERR_IPE 0x40 /* IP Checksum Error */
-#define E1000_RXD_ERR_RXE 0x80 /* Rx Data Error */
-#define E1000_RXD_SPC_VLAN_MASK 0x0FFF /* VLAN ID is in lower 12 bits */
-#define E1000_RXD_SPC_PRI_MASK 0xE000 /* Priority is in upper 3 bits */
-#define E1000_RXD_SPC_PRI_SHIFT 13
-#define E1000_RXD_SPC_CFI_MASK 0x1000 /* CFI is bit 12 */
-#define E1000_RXD_SPC_CFI_SHIFT 12
-
-#define E1000_RXDEXT_STATERR_CE 0x01000000
-#define E1000_RXDEXT_STATERR_SE 0x02000000
-#define E1000_RXDEXT_STATERR_SEQ 0x04000000
-#define E1000_RXDEXT_STATERR_CXE 0x10000000
-#define E1000_RXDEXT_STATERR_TCPE 0x20000000
-#define E1000_RXDEXT_STATERR_IPE 0x40000000
-#define E1000_RXDEXT_STATERR_RXE 0x80000000
-
-#define E1000_RXDPS_HDRSTAT_HDRSP 0x00008000
-#define E1000_RXDPS_HDRSTAT_HDRLEN_MASK 0x000003FF
-
-/* Receive Address */
-#define E1000_RAH_AV 0x80000000 /* Receive descriptor valid */
-
-/* Offload Context Descriptor */
-struct e1000_context_desc {
- union {
- uint32_t ip_config;
- struct {
- uint8_t ipcss; /* IP checksum start */
- uint8_t ipcso; /* IP checksum offset */
- uint16_t ipcse; /* IP checksum end */
- } ip_fields;
- } lower_setup;
- union {
- uint32_t tcp_config;
- struct {
- uint8_t tucss; /* TCP checksum start */
- uint8_t tucso; /* TCP checksum offset */
- uint16_t tucse; /* TCP checksum end */
- } tcp_fields;
- } upper_setup;
- uint32_t cmd_and_length; /* */
- union {
- uint32_t data;
- struct {
- uint8_t status; /* Descriptor status */
- uint8_t hdr_len; /* Header length */
- uint16_t mss; /* Maximum segment size */
- } fields;
- } tcp_seg_setup;
-};
-
-/* Offload data descriptor */
-struct e1000_data_desc {
- uint64_t buffer_addr; /* Address of the descriptor's buffer address */
- union {
- uint32_t data;
- struct {
- uint16_t length; /* Data buffer length */
- uint8_t typ_len_ext; /* */
- uint8_t cmd; /* */
- } flags;
- } lower;
- union {
- uint32_t data;
- struct {
- uint8_t status; /* Descriptor status */
- uint8_t popts; /* Packet Options */
- uint16_t special; /* */
- } fields;
- } upper;
-};
-
-/* Management Control */
-#define E1000_MANC_SMBUS_EN 0x00000001 /* SMBus Enabled - RO */
-#define E1000_MANC_ASF_EN 0x00000002 /* ASF Enabled - RO */
-#define E1000_MANC_R_ON_FORCE 0x00000004 /* Reset on Force TCO - RO */
-#define E1000_MANC_RMCP_EN 0x00000100 /* Enable RCMP 026Fh Filtering */
-#define E1000_MANC_0298_EN 0x00000200 /* Enable RCMP 0298h Filtering */
-#define E1000_MANC_IPV4_EN 0x00000400 /* Enable IPv4 */
-#define E1000_MANC_IPV6_EN 0x00000800 /* Enable IPv6 */
-#define E1000_MANC_SNAP_EN 0x00001000 /* Accept LLC/SNAP */
-#define E1000_MANC_ARP_EN 0x00002000 /* Enable ARP Request Filtering */
-#define E1000_MANC_NEIGHBOR_EN 0x00004000 /* Enable Neighbor Discovery
- * Filtering */
-#define E1000_MANC_ARP_RES_EN 0x00008000 /* Enable ARP response Filtering */
-#define E1000_MANC_TCO_RESET 0x00010000 /* TCO Reset Occurred */
-#define E1000_MANC_RCV_TCO_EN 0x00020000 /* Receive TCO Packets Enabled */
-#define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */
-#define E1000_MANC_RCV_ALL 0x00080000 /* Receive All Enabled */
-#define E1000_MANC_BLK_PHY_RST_ON_IDE 0x00040000 /* Block phy resets */
-#define E1000_MANC_EN_MAC_ADDR_FILTER 0x00100000 /* Enable MAC address
- * filtering */
-#define E1000_MANC_EN_MNG2HOST 0x00200000 /* Enable MNG packets to host
- * memory */
-#define E1000_MANC_EN_IP_ADDR_FILTER 0x00400000 /* Enable IP address
- * filtering */
-#define E1000_MANC_EN_XSUM_FILTER 0x00800000 /* Enable checksum filtering */
-#define E1000_MANC_BR_EN 0x01000000 /* Enable broadcast filtering */
-#define E1000_MANC_SMB_REQ 0x01000000 /* SMBus Request */
-#define E1000_MANC_SMB_GNT 0x02000000 /* SMBus Grant */
-#define E1000_MANC_SMB_CLK_IN 0x04000000 /* SMBus Clock In */
-#define E1000_MANC_SMB_DATA_IN 0x08000000 /* SMBus Data In */
-#define E1000_MANC_SMB_DATA_OUT 0x10000000 /* SMBus Data Out */
-#define E1000_MANC_SMB_CLK_OUT 0x20000000 /* SMBus Clock Out */
-
-#define E1000_MANC_SMB_DATA_OUT_SHIFT 28 /* SMBus Data Out Shift */
-#define E1000_MANC_SMB_CLK_OUT_SHIFT 29 /* SMBus Clock Out Shift */
-
-/* For checksumming, the sum of all words in the EEPROM should equal 0xBABA. */
-#define EEPROM_SUM 0xBABA
-
-#endif /* _E1000_HW_H_ */
diff --git a/qemu/hw/net/eepro100.c b/qemu/hw/net/eepro100.c
deleted file mode 100644
index 9b4b9b59d..000000000
--- a/qemu/hw/net/eepro100.c
+++ /dev/null
@@ -1,2114 +0,0 @@
-/*
- * QEMU i8255x (PRO100) emulation
- *
- * Copyright (C) 2006-2011 Stefan Weil
- *
- * Portions of the code are copies from grub / etherboot eepro100.c
- * and linux e100.c.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) version 3 or any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * Tested features (i82559):
- * PXE boot (i386 guest, i386 / mips / mipsel / ppc host) ok
- * Linux networking (i386) ok
- *
- * Untested:
- * Windows networking
- *
- * References:
- *
- * Intel 8255x 10/100 Mbps Ethernet Controller Family
- * Open Source Software Developer Manual
- *
- * TODO:
- * * PHY emulation should be separated from nic emulation.
- * Most nic emulations could share the same phy code.
- * * i82550 is untested. It is programmed like the i82559.
- * * i82562 is untested. It is programmed like the i82559.
- * * Power management (i82558 and later) is not implemented.
- * * Wake-on-LAN is not implemented.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/pci/pci.h"
-#include "net/net.h"
-#include "hw/nvram/eeprom93xx.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/dma.h"
-#include "qemu/bitops.h"
-
-/* QEMU sends frames smaller than 60 bytes to ethernet nics.
- * Such frames are rejected by real nics and their emulations.
- * To avoid this behaviour, other nic emulations pad received
- * frames. The following definition enables this padding for
- * eepro100, too. We keep the define around in case it might
- * become useful the future if the core networking is ever
- * changed to pad short packets itself. */
-#define CONFIG_PAD_RECEIVED_FRAMES
-
-#define KiB 1024
-
-/* Debug EEPRO100 card. */
-#if 0
-# define DEBUG_EEPRO100
-#endif
-
-#ifdef DEBUG_EEPRO100
-#define logout(fmt, ...) fprintf(stderr, "EE100\t%-24s" fmt, __func__, ## __VA_ARGS__)
-#else
-#define logout(fmt, ...) ((void)0)
-#endif
-
-/* Set flags to 0 to disable debug output. */
-#define INT 1 /* interrupt related actions */
-#define MDI 1 /* mdi related actions */
-#define OTHER 1
-#define RXTX 1
-#define EEPROM 1 /* eeprom related actions */
-
-#define TRACE(flag, command) ((flag) ? (command) : (void)0)
-
-#define missing(text) fprintf(stderr, "eepro100: feature is missing in this emulation: " text "\n")
-
-#define MAX_ETH_FRAME_SIZE 1514
-
-/* This driver supports several different devices which are declared here. */
-#define i82550 0x82550
-#define i82551 0x82551
-#define i82557A 0x82557a
-#define i82557B 0x82557b
-#define i82557C 0x82557c
-#define i82558A 0x82558a
-#define i82558B 0x82558b
-#define i82559A 0x82559a
-#define i82559B 0x82559b
-#define i82559C 0x82559c
-#define i82559ER 0x82559e
-#define i82562 0x82562
-#define i82801 0x82801
-
-/* Use 64 word EEPROM. TODO: could be a runtime option. */
-#define EEPROM_SIZE 64
-
-#define PCI_MEM_SIZE (4 * KiB)
-#define PCI_IO_SIZE 64
-#define PCI_FLASH_SIZE (128 * KiB)
-
-#define BITS(n, m) (((0xffffffffU << (31 - n)) >> (31 - n + m)) << m)
-
-/* The SCB accepts the following controls for the Tx and Rx units: */
-#define CU_NOP 0x0000 /* No operation. */
-#define CU_START 0x0010 /* CU start. */
-#define CU_RESUME 0x0020 /* CU resume. */
-#define CU_STATSADDR 0x0040 /* Load dump counters address. */
-#define CU_SHOWSTATS 0x0050 /* Dump statistical counters. */
-#define CU_CMD_BASE 0x0060 /* Load CU base address. */
-#define CU_DUMPSTATS 0x0070 /* Dump and reset statistical counters. */
-#define CU_SRESUME 0x00a0 /* CU static resume. */
-
-#define RU_NOP 0x0000
-#define RX_START 0x0001
-#define RX_RESUME 0x0002
-#define RU_ABORT 0x0004
-#define RX_ADDR_LOAD 0x0006
-#define RX_RESUMENR 0x0007
-#define INT_MASK 0x0100
-#define DRVR_INT 0x0200 /* Driver generated interrupt. */
-
-typedef struct {
- const char *name;
- const char *desc;
- uint16_t device_id;
- uint8_t revision;
- uint16_t subsystem_vendor_id;
- uint16_t subsystem_id;
-
- uint32_t device;
- uint8_t stats_size;
- bool has_extended_tcb_support;
- bool power_management;
-} E100PCIDeviceInfo;
-
-/* Offsets to the various registers.
- All accesses need not be longword aligned. */
-typedef enum {
- SCBStatus = 0, /* Status Word. */
- SCBAck = 1,
- SCBCmd = 2, /* Rx/Command Unit command and status. */
- SCBIntmask = 3,
- SCBPointer = 4, /* General purpose pointer. */
- SCBPort = 8, /* Misc. commands and operands. */
- SCBflash = 12, /* Flash memory control. */
- SCBeeprom = 14, /* EEPROM control. */
- SCBCtrlMDI = 16, /* MDI interface control. */
- SCBEarlyRx = 20, /* Early receive byte count. */
- SCBFlow = 24, /* Flow Control. */
- SCBpmdr = 27, /* Power Management Driver. */
- SCBgctrl = 28, /* General Control. */
- SCBgstat = 29, /* General Status. */
-} E100RegisterOffset;
-
-/* A speedo3 transmit buffer descriptor with two buffers... */
-typedef struct {
- uint16_t status;
- uint16_t command;
- uint32_t link; /* void * */
- uint32_t tbd_array_addr; /* transmit buffer descriptor array address. */
- uint16_t tcb_bytes; /* transmit command block byte count (in lower 14 bits */
- uint8_t tx_threshold; /* transmit threshold */
- uint8_t tbd_count; /* TBD number */
-#if 0
- /* This constitutes two "TBD" entries: hdr and data */
- uint32_t tx_buf_addr0; /* void *, header of frame to be transmitted. */
- int32_t tx_buf_size0; /* Length of Tx hdr. */
- uint32_t tx_buf_addr1; /* void *, data to be transmitted. */
- int32_t tx_buf_size1; /* Length of Tx data. */
-#endif
-} eepro100_tx_t;
-
-/* Receive frame descriptor. */
-typedef struct {
- int16_t status;
- uint16_t command;
- uint32_t link; /* struct RxFD * */
- uint32_t rx_buf_addr; /* void * */
- uint16_t count;
- uint16_t size;
- /* Ethernet frame data follows. */
-} eepro100_rx_t;
-
-typedef enum {
- COMMAND_EL = BIT(15),
- COMMAND_S = BIT(14),
- COMMAND_I = BIT(13),
- COMMAND_NC = BIT(4),
- COMMAND_SF = BIT(3),
- COMMAND_CMD = BITS(2, 0),
-} scb_command_bit;
-
-typedef enum {
- STATUS_C = BIT(15),
- STATUS_OK = BIT(13),
-} scb_status_bit;
-
-typedef struct {
- uint32_t tx_good_frames, tx_max_collisions, tx_late_collisions,
- tx_underruns, tx_lost_crs, tx_deferred, tx_single_collisions,
- tx_multiple_collisions, tx_total_collisions;
- uint32_t rx_good_frames, rx_crc_errors, rx_alignment_errors,
- rx_resource_errors, rx_overrun_errors, rx_cdt_errors,
- rx_short_frame_errors;
- uint32_t fc_xmt_pause, fc_rcv_pause, fc_rcv_unsupported;
- uint16_t xmt_tco_frames, rcv_tco_frames;
- /* TODO: i82559 has six reserved statistics but a total of 24 dwords. */
- uint32_t reserved[4];
-} eepro100_stats_t;
-
-typedef enum {
- cu_idle = 0,
- cu_suspended = 1,
- cu_active = 2,
- cu_lpq_active = 2,
- cu_hqp_active = 3
-} cu_state_t;
-
-typedef enum {
- ru_idle = 0,
- ru_suspended = 1,
- ru_no_resources = 2,
- ru_ready = 4
-} ru_state_t;
-
-typedef struct {
- PCIDevice dev;
- /* Hash register (multicast mask array, multiple individual addresses). */
- uint8_t mult[8];
- MemoryRegion mmio_bar;
- MemoryRegion io_bar;
- MemoryRegion flash_bar;
- NICState *nic;
- NICConf conf;
- uint8_t scb_stat; /* SCB stat/ack byte */
- uint8_t int_stat; /* PCI interrupt status */
- /* region must not be saved by nic_save. */
- uint16_t mdimem[32];
- eeprom_t *eeprom;
- uint32_t device; /* device variant */
- /* (cu_base + cu_offset) address the next command block in the command block list. */
- uint32_t cu_base; /* CU base address */
- uint32_t cu_offset; /* CU address offset */
- /* (ru_base + ru_offset) address the RFD in the Receive Frame Area. */
- uint32_t ru_base; /* RU base address */
- uint32_t ru_offset; /* RU address offset */
- uint32_t statsaddr; /* pointer to eepro100_stats_t */
-
- /* Temporary status information (no need to save these values),
- * used while processing CU commands. */
- eepro100_tx_t tx; /* transmit buffer descriptor */
- uint32_t cb_address; /* = cu_base + cu_offset */
-
- /* Statistical counters. Also used for wake-up packet (i82559). */
- eepro100_stats_t statistics;
-
- /* Data in mem is always in the byte order of the controller (le).
- * It must be dword aligned to allow direct access to 32 bit values. */
- uint8_t mem[PCI_MEM_SIZE] __attribute__((aligned(8)));
-
- /* Configuration bytes. */
- uint8_t configuration[22];
-
- /* vmstate for each particular nic */
- VMStateDescription *vmstate;
-
- /* Quasi static device properties (no need to save them). */
- uint16_t stats_size;
- bool has_extended_tcb_support;
-} EEPRO100State;
-
-/* Word indices in EEPROM. */
-typedef enum {
- EEPROM_CNFG_MDIX = 0x03,
- EEPROM_ID = 0x05,
- EEPROM_PHY_ID = 0x06,
- EEPROM_VENDOR_ID = 0x0c,
- EEPROM_CONFIG_ASF = 0x0d,
- EEPROM_DEVICE_ID = 0x23,
- EEPROM_SMBUS_ADDR = 0x90,
-} EEPROMOffset;
-
-/* Bit values for EEPROM ID word. */
-typedef enum {
- EEPROM_ID_MDM = BIT(0), /* Modem */
- EEPROM_ID_STB = BIT(1), /* Standby Enable */
- EEPROM_ID_WMR = BIT(2), /* ??? */
- EEPROM_ID_WOL = BIT(5), /* Wake on LAN */
- EEPROM_ID_DPD = BIT(6), /* Deep Power Down */
- EEPROM_ID_ALT = BIT(7), /* */
- /* BITS(10, 8) device revision */
- EEPROM_ID_BD = BIT(11), /* boot disable */
- EEPROM_ID_ID = BIT(13), /* id bit */
- /* BITS(15, 14) signature */
- EEPROM_ID_VALID = BIT(14), /* signature for valid eeprom */
-} eeprom_id_bit;
-
-/* Default values for MDI (PHY) registers */
-static const uint16_t eepro100_mdi_default[] = {
- /* MDI Registers 0 - 6, 7 */
- 0x3000, 0x780d, 0x02a8, 0x0154, 0x05e1, 0x0000, 0x0000, 0x0000,
- /* MDI Registers 8 - 15 */
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- /* MDI Registers 16 - 31 */
- 0x0003, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-};
-
-/* Readonly mask for MDI (PHY) registers */
-static const uint16_t eepro100_mdi_mask[] = {
- 0x0000, 0xffff, 0xffff, 0xffff, 0xc01f, 0xffff, 0xffff, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0fff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
- 0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-};
-
-#define POLYNOMIAL 0x04c11db6
-
-static E100PCIDeviceInfo *eepro100_get_class(EEPRO100State *s);
-
-/* From FreeBSD (locally modified). */
-static unsigned e100_compute_mcast_idx(const uint8_t *ep)
-{
- uint32_t crc;
- int carry, i, j;
- uint8_t b;
-
- crc = 0xffffffff;
- for (i = 0; i < 6; i++) {
- b = *ep++;
- for (j = 0; j < 8; j++) {
- carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
- crc <<= 1;
- b >>= 1;
- if (carry) {
- crc = ((crc ^ POLYNOMIAL) | carry);
- }
- }
- }
- return (crc & BITS(7, 2)) >> 2;
-}
-
-/* Read a 16 bit control/status (CSR) register. */
-static uint16_t e100_read_reg2(EEPRO100State *s, E100RegisterOffset addr)
-{
- assert(!((uintptr_t)&s->mem[addr] & 1));
- return le16_to_cpup((uint16_t *)&s->mem[addr]);
-}
-
-/* Read a 32 bit control/status (CSR) register. */
-static uint32_t e100_read_reg4(EEPRO100State *s, E100RegisterOffset addr)
-{
- assert(!((uintptr_t)&s->mem[addr] & 3));
- return le32_to_cpup((uint32_t *)&s->mem[addr]);
-}
-
-/* Write a 16 bit control/status (CSR) register. */
-static void e100_write_reg2(EEPRO100State *s, E100RegisterOffset addr,
- uint16_t val)
-{
- assert(!((uintptr_t)&s->mem[addr] & 1));
- cpu_to_le16w((uint16_t *)&s->mem[addr], val);
-}
-
-/* Read a 32 bit control/status (CSR) register. */
-static void e100_write_reg4(EEPRO100State *s, E100RegisterOffset addr,
- uint32_t val)
-{
- assert(!((uintptr_t)&s->mem[addr] & 3));
- cpu_to_le32w((uint32_t *)&s->mem[addr], val);
-}
-
-#if defined(DEBUG_EEPRO100)
-static const char *nic_dump(const uint8_t * buf, unsigned size)
-{
- static char dump[3 * 16 + 1];
- char *p = &dump[0];
- if (size > 16) {
- size = 16;
- }
- while (size-- > 0) {
- p += sprintf(p, " %02x", *buf++);
- }
- return dump;
-}
-#endif /* DEBUG_EEPRO100 */
-
-enum scb_stat_ack {
- stat_ack_not_ours = 0x00,
- stat_ack_sw_gen = 0x04,
- stat_ack_rnr = 0x10,
- stat_ack_cu_idle = 0x20,
- stat_ack_frame_rx = 0x40,
- stat_ack_cu_cmd_done = 0x80,
- stat_ack_not_present = 0xFF,
- stat_ack_rx = (stat_ack_sw_gen | stat_ack_rnr | stat_ack_frame_rx),
- stat_ack_tx = (stat_ack_cu_idle | stat_ack_cu_cmd_done),
-};
-
-static void disable_interrupt(EEPRO100State * s)
-{
- if (s->int_stat) {
- TRACE(INT, logout("interrupt disabled\n"));
- pci_irq_deassert(&s->dev);
- s->int_stat = 0;
- }
-}
-
-static void enable_interrupt(EEPRO100State * s)
-{
- if (!s->int_stat) {
- TRACE(INT, logout("interrupt enabled\n"));
- pci_irq_assert(&s->dev);
- s->int_stat = 1;
- }
-}
-
-static void eepro100_acknowledge(EEPRO100State * s)
-{
- s->scb_stat &= ~s->mem[SCBAck];
- s->mem[SCBAck] = s->scb_stat;
- if (s->scb_stat == 0) {
- disable_interrupt(s);
- }
-}
-
-static void eepro100_interrupt(EEPRO100State * s, uint8_t status)
-{
- uint8_t mask = ~s->mem[SCBIntmask];
- s->mem[SCBAck] |= status;
- status = s->scb_stat = s->mem[SCBAck];
- status &= (mask | 0x0f);
-#if 0
- status &= (~s->mem[SCBIntmask] | 0x0xf);
-#endif
- if (status && (mask & 0x01)) {
- /* SCB mask and SCB Bit M do not disable interrupt. */
- enable_interrupt(s);
- } else if (s->int_stat) {
- disable_interrupt(s);
- }
-}
-
-static void eepro100_cx_interrupt(EEPRO100State * s)
-{
- /* CU completed action command. */
- /* Transmit not ok (82557 only, not in emulation). */
- eepro100_interrupt(s, 0x80);
-}
-
-static void eepro100_cna_interrupt(EEPRO100State * s)
-{
- /* CU left the active state. */
- eepro100_interrupt(s, 0x20);
-}
-
-static void eepro100_fr_interrupt(EEPRO100State * s)
-{
- /* RU received a complete frame. */
- eepro100_interrupt(s, 0x40);
-}
-
-static void eepro100_rnr_interrupt(EEPRO100State * s)
-{
- /* RU is not ready. */
- eepro100_interrupt(s, 0x10);
-}
-
-static void eepro100_mdi_interrupt(EEPRO100State * s)
-{
- /* MDI completed read or write cycle. */
- eepro100_interrupt(s, 0x08);
-}
-
-static void eepro100_swi_interrupt(EEPRO100State * s)
-{
- /* Software has requested an interrupt. */
- eepro100_interrupt(s, 0x04);
-}
-
-#if 0
-static void eepro100_fcp_interrupt(EEPRO100State * s)
-{
- /* Flow control pause interrupt (82558 and later). */
- eepro100_interrupt(s, 0x01);
-}
-#endif
-
-static void e100_pci_reset(EEPRO100State * s)
-{
- E100PCIDeviceInfo *info = eepro100_get_class(s);
- uint32_t device = s->device;
- uint8_t *pci_conf = s->dev.config;
-
- TRACE(OTHER, logout("%p\n", s));
-
- /* PCI Status */
- pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM |
- PCI_STATUS_FAST_BACK);
- /* PCI Latency Timer */
- pci_set_byte(pci_conf + PCI_LATENCY_TIMER, 0x20); /* latency timer = 32 clocks */
- /* Capability Pointer is set by PCI framework. */
- /* Interrupt Line */
- /* Interrupt Pin */
- pci_set_byte(pci_conf + PCI_INTERRUPT_PIN, 1); /* interrupt pin A */
- /* Minimum Grant */
- pci_set_byte(pci_conf + PCI_MIN_GNT, 0x08);
- /* Maximum Latency */
- pci_set_byte(pci_conf + PCI_MAX_LAT, 0x18);
-
- s->stats_size = info->stats_size;
- s->has_extended_tcb_support = info->has_extended_tcb_support;
-
- switch (device) {
- case i82550:
- case i82551:
- case i82557A:
- case i82557B:
- case i82557C:
- case i82558A:
- case i82558B:
- case i82559A:
- case i82559B:
- case i82559ER:
- case i82562:
- case i82801:
- case i82559C:
- break;
- default:
- logout("Device %X is undefined!\n", device);
- }
-
- /* Standard TxCB. */
- s->configuration[6] |= BIT(4);
-
- /* Standard statistical counters. */
- s->configuration[6] |= BIT(5);
-
- if (s->stats_size == 80) {
- /* TODO: check TCO Statistical Counters bit. Documentation not clear. */
- if (s->configuration[6] & BIT(2)) {
- /* TCO statistical counters. */
- assert(s->configuration[6] & BIT(5));
- } else {
- if (s->configuration[6] & BIT(5)) {
- /* No extended statistical counters, i82557 compatible. */
- s->stats_size = 64;
- } else {
- /* i82558 compatible. */
- s->stats_size = 76;
- }
- }
- } else {
- if (s->configuration[6] & BIT(5)) {
- /* No extended statistical counters. */
- s->stats_size = 64;
- }
- }
- assert(s->stats_size > 0 && s->stats_size <= sizeof(s->statistics));
-
- if (info->power_management) {
- /* Power Management Capabilities */
- int cfg_offset = 0xdc;
- int r = pci_add_capability(&s->dev, PCI_CAP_ID_PM,
- cfg_offset, PCI_PM_SIZEOF);
- assert(r >= 0);
- pci_set_word(pci_conf + cfg_offset + PCI_PM_PMC, 0x7e21);
-#if 0 /* TODO: replace dummy code for power management emulation. */
- /* TODO: Power Management Control / Status. */
- pci_set_word(pci_conf + cfg_offset + PCI_PM_CTRL, 0x0000);
- /* TODO: Ethernet Power Consumption Registers (i82559 and later). */
- pci_set_byte(pci_conf + cfg_offset + PCI_PM_PPB_EXTENSIONS, 0x0000);
-#endif
- }
-
-#if EEPROM_SIZE > 0
- if (device == i82557C || device == i82558B || device == i82559C) {
- /*
- TODO: get vendor id from EEPROM for i82557C or later.
- TODO: get device id from EEPROM for i82557C or later.
- TODO: status bit 4 can be disabled by EEPROM for i82558, i82559.
- TODO: header type is determined by EEPROM for i82559.
- TODO: get subsystem id from EEPROM for i82557C or later.
- TODO: get subsystem vendor id from EEPROM for i82557C or later.
- TODO: exp. rom baddr depends on a bit in EEPROM for i82558 or later.
- TODO: capability pointer depends on EEPROM for i82558.
- */
- logout("Get device id and revision from EEPROM!!!\n");
- }
-#endif /* EEPROM_SIZE > 0 */
-}
-
-static void nic_selective_reset(EEPRO100State * s)
-{
- size_t i;
- uint16_t *eeprom_contents = eeprom93xx_data(s->eeprom);
-#if 0
- eeprom93xx_reset(s->eeprom);
-#endif
- memcpy(eeprom_contents, s->conf.macaddr.a, 6);
- eeprom_contents[EEPROM_ID] = EEPROM_ID_VALID;
- if (s->device == i82557B || s->device == i82557C)
- eeprom_contents[5] = 0x0100;
- eeprom_contents[EEPROM_PHY_ID] = 1;
- uint16_t sum = 0;
- for (i = 0; i < EEPROM_SIZE - 1; i++) {
- sum += eeprom_contents[i];
- }
- eeprom_contents[EEPROM_SIZE - 1] = 0xbaba - sum;
- TRACE(EEPROM, logout("checksum=0x%04x\n", eeprom_contents[EEPROM_SIZE - 1]));
-
- memset(s->mem, 0, sizeof(s->mem));
- e100_write_reg4(s, SCBCtrlMDI, BIT(21));
-
- assert(sizeof(s->mdimem) == sizeof(eepro100_mdi_default));
- memcpy(&s->mdimem[0], &eepro100_mdi_default[0], sizeof(s->mdimem));
-}
-
-static void nic_reset(void *opaque)
-{
- EEPRO100State *s = opaque;
- TRACE(OTHER, logout("%p\n", s));
- /* TODO: Clearing of hash register for selective reset, too? */
- memset(&s->mult[0], 0, sizeof(s->mult));
- nic_selective_reset(s);
-}
-
-#if defined(DEBUG_EEPRO100)
-static const char * const e100_reg[PCI_IO_SIZE / 4] = {
- "Command/Status",
- "General Pointer",
- "Port",
- "EEPROM/Flash Control",
- "MDI Control",
- "Receive DMA Byte Count",
- "Flow Control",
- "General Status/Control"
-};
-
-static char *regname(uint32_t addr)
-{
- static char buf[32];
- if (addr < PCI_IO_SIZE) {
- const char *r = e100_reg[addr / 4];
- if (r != 0) {
- snprintf(buf, sizeof(buf), "%s+%u", r, addr % 4);
- } else {
- snprintf(buf, sizeof(buf), "0x%02x", addr);
- }
- } else {
- snprintf(buf, sizeof(buf), "??? 0x%08x", addr);
- }
- return buf;
-}
-#endif /* DEBUG_EEPRO100 */
-
-/*****************************************************************************
- *
- * Command emulation.
- *
- ****************************************************************************/
-
-#if 0
-static uint16_t eepro100_read_command(EEPRO100State * s)
-{
- uint16_t val = 0xffff;
- TRACE(OTHER, logout("val=0x%04x\n", val));
- return val;
-}
-#endif
-
-/* Commands that can be put in a command list entry. */
-enum commands {
- CmdNOp = 0,
- CmdIASetup = 1,
- CmdConfigure = 2,
- CmdMulticastList = 3,
- CmdTx = 4,
- CmdTDR = 5, /* load microcode */
- CmdDump = 6,
- CmdDiagnose = 7,
-
- /* And some extra flags: */
- CmdSuspend = 0x4000, /* Suspend after completion. */
- CmdIntr = 0x2000, /* Interrupt after completion. */
- CmdTxFlex = 0x0008, /* Use "Flexible mode" for CmdTx command. */
-};
-
-static cu_state_t get_cu_state(EEPRO100State * s)
-{
- return ((s->mem[SCBStatus] & BITS(7, 6)) >> 6);
-}
-
-static void set_cu_state(EEPRO100State * s, cu_state_t state)
-{
- s->mem[SCBStatus] = (s->mem[SCBStatus] & ~BITS(7, 6)) + (state << 6);
-}
-
-static ru_state_t get_ru_state(EEPRO100State * s)
-{
- return ((s->mem[SCBStatus] & BITS(5, 2)) >> 2);
-}
-
-static void set_ru_state(EEPRO100State * s, ru_state_t state)
-{
- s->mem[SCBStatus] = (s->mem[SCBStatus] & ~BITS(5, 2)) + (state << 2);
-}
-
-static void dump_statistics(EEPRO100State * s)
-{
- /* Dump statistical data. Most data is never changed by the emulation
- * and always 0, so we first just copy the whole block and then those
- * values which really matter.
- * Number of data should check configuration!!!
- */
- pci_dma_write(&s->dev, s->statsaddr, &s->statistics, s->stats_size);
- stl_le_pci_dma(&s->dev, s->statsaddr + 0,
- s->statistics.tx_good_frames);
- stl_le_pci_dma(&s->dev, s->statsaddr + 36,
- s->statistics.rx_good_frames);
- stl_le_pci_dma(&s->dev, s->statsaddr + 48,
- s->statistics.rx_resource_errors);
- stl_le_pci_dma(&s->dev, s->statsaddr + 60,
- s->statistics.rx_short_frame_errors);
-#if 0
- stw_le_pci_dma(&s->dev, s->statsaddr + 76, s->statistics.xmt_tco_frames);
- stw_le_pci_dma(&s->dev, s->statsaddr + 78, s->statistics.rcv_tco_frames);
- missing("CU dump statistical counters");
-#endif
-}
-
-static void read_cb(EEPRO100State *s)
-{
- pci_dma_read(&s->dev, s->cb_address, &s->tx, sizeof(s->tx));
- s->tx.status = le16_to_cpu(s->tx.status);
- s->tx.command = le16_to_cpu(s->tx.command);
- s->tx.link = le32_to_cpu(s->tx.link);
- s->tx.tbd_array_addr = le32_to_cpu(s->tx.tbd_array_addr);
- s->tx.tcb_bytes = le16_to_cpu(s->tx.tcb_bytes);
-}
-
-static void tx_command(EEPRO100State *s)
-{
- uint32_t tbd_array = le32_to_cpu(s->tx.tbd_array_addr);
- uint16_t tcb_bytes = (le16_to_cpu(s->tx.tcb_bytes) & 0x3fff);
- /* Sends larger than MAX_ETH_FRAME_SIZE are allowed, up to 2600 bytes. */
- uint8_t buf[2600];
- uint16_t size = 0;
- uint32_t tbd_address = s->cb_address + 0x10;
- TRACE(RXTX, logout
- ("transmit, TBD array address 0x%08x, TCB byte count 0x%04x, TBD count %u\n",
- tbd_array, tcb_bytes, s->tx.tbd_count));
-
- if (tcb_bytes > 2600) {
- logout("TCB byte count too large, using 2600\n");
- tcb_bytes = 2600;
- }
- if (!((tcb_bytes > 0) || (tbd_array != 0xffffffff))) {
- logout
- ("illegal values of TBD array address and TCB byte count!\n");
- }
- assert(tcb_bytes <= sizeof(buf));
- while (size < tcb_bytes) {
- uint32_t tx_buffer_address = ldl_le_pci_dma(&s->dev, tbd_address);
- uint16_t tx_buffer_size = lduw_le_pci_dma(&s->dev, tbd_address + 4);
-#if 0
- uint16_t tx_buffer_el = lduw_le_pci_dma(&s->dev, tbd_address + 6);
-#endif
- if (tx_buffer_size == 0) {
- /* Prevent an endless loop. */
- logout("loop in %s:%u\n", __FILE__, __LINE__);
- break;
- }
- tbd_address += 8;
- TRACE(RXTX, logout
- ("TBD (simplified mode): buffer address 0x%08x, size 0x%04x\n",
- tx_buffer_address, tx_buffer_size));
- tx_buffer_size = MIN(tx_buffer_size, sizeof(buf) - size);
- pci_dma_read(&s->dev, tx_buffer_address, &buf[size], tx_buffer_size);
- size += tx_buffer_size;
- }
- if (tbd_array == 0xffffffff) {
- /* Simplified mode. Was already handled by code above. */
- } else {
- /* Flexible mode. */
- uint8_t tbd_count = 0;
- if (s->has_extended_tcb_support && !(s->configuration[6] & BIT(4))) {
- /* Extended Flexible TCB. */
- for (; tbd_count < 2; tbd_count++) {
- uint32_t tx_buffer_address = ldl_le_pci_dma(&s->dev,
- tbd_address);
- uint16_t tx_buffer_size = lduw_le_pci_dma(&s->dev,
- tbd_address + 4);
- uint16_t tx_buffer_el = lduw_le_pci_dma(&s->dev,
- tbd_address + 6);
- tbd_address += 8;
- TRACE(RXTX, logout
- ("TBD (extended flexible mode): buffer address 0x%08x, size 0x%04x\n",
- tx_buffer_address, tx_buffer_size));
- tx_buffer_size = MIN(tx_buffer_size, sizeof(buf) - size);
- pci_dma_read(&s->dev, tx_buffer_address,
- &buf[size], tx_buffer_size);
- size += tx_buffer_size;
- if (tx_buffer_el & 1) {
- break;
- }
- }
- }
- tbd_address = tbd_array;
- for (; tbd_count < s->tx.tbd_count; tbd_count++) {
- uint32_t tx_buffer_address = ldl_le_pci_dma(&s->dev, tbd_address);
- uint16_t tx_buffer_size = lduw_le_pci_dma(&s->dev, tbd_address + 4);
- uint16_t tx_buffer_el = lduw_le_pci_dma(&s->dev, tbd_address + 6);
- tbd_address += 8;
- TRACE(RXTX, logout
- ("TBD (flexible mode): buffer address 0x%08x, size 0x%04x\n",
- tx_buffer_address, tx_buffer_size));
- tx_buffer_size = MIN(tx_buffer_size, sizeof(buf) - size);
- pci_dma_read(&s->dev, tx_buffer_address,
- &buf[size], tx_buffer_size);
- size += tx_buffer_size;
- if (tx_buffer_el & 1) {
- break;
- }
- }
- }
- TRACE(RXTX, logout("%p sending frame, len=%d,%s\n", s, size, nic_dump(buf, size)));
- qemu_send_packet(qemu_get_queue(s->nic), buf, size);
- s->statistics.tx_good_frames++;
- /* Transmit with bad status would raise an CX/TNO interrupt.
- * (82557 only). Emulation never has bad status. */
-#if 0
- eepro100_cx_interrupt(s);
-#endif
-}
-
-static void set_multicast_list(EEPRO100State *s)
-{
- uint16_t multicast_count = s->tx.tbd_array_addr & BITS(13, 0);
- uint16_t i;
- memset(&s->mult[0], 0, sizeof(s->mult));
- TRACE(OTHER, logout("multicast list, multicast count = %u\n", multicast_count));
- for (i = 0; i < multicast_count; i += 6) {
- uint8_t multicast_addr[6];
- pci_dma_read(&s->dev, s->cb_address + 10 + i, multicast_addr, 6);
- TRACE(OTHER, logout("multicast entry %s\n", nic_dump(multicast_addr, 6)));
- unsigned mcast_idx = e100_compute_mcast_idx(multicast_addr);
- assert(mcast_idx < 64);
- s->mult[mcast_idx >> 3] |= (1 << (mcast_idx & 7));
- }
-}
-
-static void action_command(EEPRO100State *s)
-{
- /* The loop below won't stop if it gets special handcrafted data.
- Therefore we limit the number of iterations. */
- unsigned max_loop_count = 16;
-
- for (;;) {
- bool bit_el;
- bool bit_s;
- bool bit_i;
- bool bit_nc;
- uint16_t ok_status = STATUS_OK;
- s->cb_address = s->cu_base + s->cu_offset;
- read_cb(s);
- bit_el = ((s->tx.command & COMMAND_EL) != 0);
- bit_s = ((s->tx.command & COMMAND_S) != 0);
- bit_i = ((s->tx.command & COMMAND_I) != 0);
- bit_nc = ((s->tx.command & COMMAND_NC) != 0);
-#if 0
- bool bit_sf = ((s->tx.command & COMMAND_SF) != 0);
-#endif
-
- if (max_loop_count-- == 0) {
- /* Prevent an endless loop. */
- logout("loop in %s:%u\n", __FILE__, __LINE__);
- break;
- }
-
- s->cu_offset = s->tx.link;
- TRACE(OTHER,
- logout("val=(cu start), status=0x%04x, command=0x%04x, link=0x%08x\n",
- s->tx.status, s->tx.command, s->tx.link));
- switch (s->tx.command & COMMAND_CMD) {
- case CmdNOp:
- /* Do nothing. */
- break;
- case CmdIASetup:
- pci_dma_read(&s->dev, s->cb_address + 8, &s->conf.macaddr.a[0], 6);
- TRACE(OTHER, logout("macaddr: %s\n", nic_dump(&s->conf.macaddr.a[0], 6)));
- break;
- case CmdConfigure:
- pci_dma_read(&s->dev, s->cb_address + 8,
- &s->configuration[0], sizeof(s->configuration));
- TRACE(OTHER, logout("configuration: %s\n",
- nic_dump(&s->configuration[0], 16)));
- TRACE(OTHER, logout("configuration: %s\n",
- nic_dump(&s->configuration[16],
- ARRAY_SIZE(s->configuration) - 16)));
- if (s->configuration[20] & BIT(6)) {
- TRACE(OTHER, logout("Multiple IA bit\n"));
- }
- break;
- case CmdMulticastList:
- set_multicast_list(s);
- break;
- case CmdTx:
- if (bit_nc) {
- missing("CmdTx: NC = 0");
- ok_status = 0;
- break;
- }
- tx_command(s);
- break;
- case CmdTDR:
- TRACE(OTHER, logout("load microcode\n"));
- /* Starting with offset 8, the command contains
- * 64 dwords microcode which we just ignore here. */
- break;
- case CmdDiagnose:
- TRACE(OTHER, logout("diagnose\n"));
- /* Make sure error flag is not set. */
- s->tx.status = 0;
- break;
- default:
- missing("undefined command");
- ok_status = 0;
- break;
- }
- /* Write new status. */
- stw_le_pci_dma(&s->dev, s->cb_address,
- s->tx.status | ok_status | STATUS_C);
- if (bit_i) {
- /* CU completed action. */
- eepro100_cx_interrupt(s);
- }
- if (bit_el) {
- /* CU becomes idle. Terminate command loop. */
- set_cu_state(s, cu_idle);
- eepro100_cna_interrupt(s);
- break;
- } else if (bit_s) {
- /* CU becomes suspended. Terminate command loop. */
- set_cu_state(s, cu_suspended);
- eepro100_cna_interrupt(s);
- break;
- } else {
- /* More entries in list. */
- TRACE(OTHER, logout("CU list with at least one more entry\n"));
- }
- }
- TRACE(OTHER, logout("CU list empty\n"));
- /* List is empty. Now CU is idle or suspended. */
-}
-
-static void eepro100_cu_command(EEPRO100State * s, uint8_t val)
-{
- cu_state_t cu_state;
- switch (val) {
- case CU_NOP:
- /* No operation. */
- break;
- case CU_START:
- cu_state = get_cu_state(s);
- if (cu_state != cu_idle && cu_state != cu_suspended) {
- /* Intel documentation says that CU must be idle or suspended
- * for the CU start command. */
- logout("unexpected CU state is %u\n", cu_state);
- }
- set_cu_state(s, cu_active);
- s->cu_offset = e100_read_reg4(s, SCBPointer);
- action_command(s);
- break;
- case CU_RESUME:
- if (get_cu_state(s) != cu_suspended) {
- logout("bad CU resume from CU state %u\n", get_cu_state(s));
- /* Workaround for bad Linux eepro100 driver which resumes
- * from idle state. */
-#if 0
- missing("cu resume");
-#endif
- set_cu_state(s, cu_suspended);
- }
- if (get_cu_state(s) == cu_suspended) {
- TRACE(OTHER, logout("CU resuming\n"));
- set_cu_state(s, cu_active);
- action_command(s);
- }
- break;
- case CU_STATSADDR:
- /* Load dump counters address. */
- s->statsaddr = e100_read_reg4(s, SCBPointer);
- TRACE(OTHER, logout("val=0x%02x (dump counters address)\n", val));
- if (s->statsaddr & 3) {
- /* Memory must be Dword aligned. */
- logout("unaligned dump counters address\n");
- /* Handling of misaligned addresses is undefined.
- * Here we align the address by ignoring the lower bits. */
- /* TODO: Test unaligned dump counter address on real hardware. */
- s->statsaddr &= ~3;
- }
- break;
- case CU_SHOWSTATS:
- /* Dump statistical counters. */
- TRACE(OTHER, logout("val=0x%02x (dump stats)\n", val));
- dump_statistics(s);
- stl_le_pci_dma(&s->dev, s->statsaddr + s->stats_size, 0xa005);
- break;
- case CU_CMD_BASE:
- /* Load CU base. */
- TRACE(OTHER, logout("val=0x%02x (CU base address)\n", val));
- s->cu_base = e100_read_reg4(s, SCBPointer);
- break;
- case CU_DUMPSTATS:
- /* Dump and reset statistical counters. */
- TRACE(OTHER, logout("val=0x%02x (dump stats and reset)\n", val));
- dump_statistics(s);
- stl_le_pci_dma(&s->dev, s->statsaddr + s->stats_size, 0xa007);
- memset(&s->statistics, 0, sizeof(s->statistics));
- break;
- case CU_SRESUME:
- /* CU static resume. */
- missing("CU static resume");
- break;
- default:
- missing("Undefined CU command");
- }
-}
-
-static void eepro100_ru_command(EEPRO100State * s, uint8_t val)
-{
- switch (val) {
- case RU_NOP:
- /* No operation. */
- break;
- case RX_START:
- /* RU start. */
- if (get_ru_state(s) != ru_idle) {
- logout("RU state is %u, should be %u\n", get_ru_state(s), ru_idle);
-#if 0
- assert(!"wrong RU state");
-#endif
- }
- set_ru_state(s, ru_ready);
- s->ru_offset = e100_read_reg4(s, SCBPointer);
- qemu_flush_queued_packets(qemu_get_queue(s->nic));
- TRACE(OTHER, logout("val=0x%02x (rx start)\n", val));
- break;
- case RX_RESUME:
- /* Restart RU. */
- if (get_ru_state(s) != ru_suspended) {
- logout("RU state is %u, should be %u\n", get_ru_state(s),
- ru_suspended);
-#if 0
- assert(!"wrong RU state");
-#endif
- }
- set_ru_state(s, ru_ready);
- break;
- case RU_ABORT:
- /* RU abort. */
- if (get_ru_state(s) == ru_ready) {
- eepro100_rnr_interrupt(s);
- }
- set_ru_state(s, ru_idle);
- break;
- case RX_ADDR_LOAD:
- /* Load RU base. */
- TRACE(OTHER, logout("val=0x%02x (RU base address)\n", val));
- s->ru_base = e100_read_reg4(s, SCBPointer);
- break;
- default:
- logout("val=0x%02x (undefined RU command)\n", val);
- missing("Undefined SU command");
- }
-}
-
-static void eepro100_write_command(EEPRO100State * s, uint8_t val)
-{
- eepro100_ru_command(s, val & 0x0f);
- eepro100_cu_command(s, val & 0xf0);
- if ((val) == 0) {
- TRACE(OTHER, logout("val=0x%02x\n", val));
- }
- /* Clear command byte after command was accepted. */
- s->mem[SCBCmd] = 0;
-}
-
-/*****************************************************************************
- *
- * EEPROM emulation.
- *
- ****************************************************************************/
-
-#define EEPROM_CS 0x02
-#define EEPROM_SK 0x01
-#define EEPROM_DI 0x04
-#define EEPROM_DO 0x08
-
-static uint16_t eepro100_read_eeprom(EEPRO100State * s)
-{
- uint16_t val = e100_read_reg2(s, SCBeeprom);
- if (eeprom93xx_read(s->eeprom)) {
- val |= EEPROM_DO;
- } else {
- val &= ~EEPROM_DO;
- }
- TRACE(EEPROM, logout("val=0x%04x\n", val));
- return val;
-}
-
-static void eepro100_write_eeprom(eeprom_t * eeprom, uint8_t val)
-{
- TRACE(EEPROM, logout("val=0x%02x\n", val));
-
- /* mask unwritable bits */
-#if 0
- val = SET_MASKED(val, 0x31, eeprom->value);
-#endif
-
- int eecs = ((val & EEPROM_CS) != 0);
- int eesk = ((val & EEPROM_SK) != 0);
- int eedi = ((val & EEPROM_DI) != 0);
- eeprom93xx_write(eeprom, eecs, eesk, eedi);
-}
-
-/*****************************************************************************
- *
- * MDI emulation.
- *
- ****************************************************************************/
-
-#if defined(DEBUG_EEPRO100)
-static const char * const mdi_op_name[] = {
- "opcode 0",
- "write",
- "read",
- "opcode 3"
-};
-
-static const char * const mdi_reg_name[] = {
- "Control",
- "Status",
- "PHY Identification (Word 1)",
- "PHY Identification (Word 2)",
- "Auto-Negotiation Advertisement",
- "Auto-Negotiation Link Partner Ability",
- "Auto-Negotiation Expansion"
-};
-
-static const char *reg2name(uint8_t reg)
-{
- static char buffer[10];
- const char *p = buffer;
- if (reg < ARRAY_SIZE(mdi_reg_name)) {
- p = mdi_reg_name[reg];
- } else {
- snprintf(buffer, sizeof(buffer), "reg=0x%02x", reg);
- }
- return p;
-}
-#endif /* DEBUG_EEPRO100 */
-
-static uint32_t eepro100_read_mdi(EEPRO100State * s)
-{
- uint32_t val = e100_read_reg4(s, SCBCtrlMDI);
-
-#ifdef DEBUG_EEPRO100
- uint8_t raiseint = (val & BIT(29)) >> 29;
- uint8_t opcode = (val & BITS(27, 26)) >> 26;
- uint8_t phy = (val & BITS(25, 21)) >> 21;
- uint8_t reg = (val & BITS(20, 16)) >> 16;
- uint16_t data = (val & BITS(15, 0));
-#endif
- /* Emulation takes no time to finish MDI transaction. */
- val |= BIT(28);
- TRACE(MDI, logout("val=0x%08x (int=%u, %s, phy=%u, %s, data=0x%04x\n",
- val, raiseint, mdi_op_name[opcode], phy,
- reg2name(reg), data));
- return val;
-}
-
-static void eepro100_write_mdi(EEPRO100State *s)
-{
- uint32_t val = e100_read_reg4(s, SCBCtrlMDI);
- uint8_t raiseint = (val & BIT(29)) >> 29;
- uint8_t opcode = (val & BITS(27, 26)) >> 26;
- uint8_t phy = (val & BITS(25, 21)) >> 21;
- uint8_t reg = (val & BITS(20, 16)) >> 16;
- uint16_t data = (val & BITS(15, 0));
- TRACE(MDI, logout("val=0x%08x (int=%u, %s, phy=%u, %s, data=0x%04x\n",
- val, raiseint, mdi_op_name[opcode], phy, reg2name(reg), data));
- if (phy != 1) {
- /* Unsupported PHY address. */
-#if 0
- logout("phy must be 1 but is %u\n", phy);
-#endif
- data = 0;
- } else if (opcode != 1 && opcode != 2) {
- /* Unsupported opcode. */
- logout("opcode must be 1 or 2 but is %u\n", opcode);
- data = 0;
- } else if (reg > 6) {
- /* Unsupported register. */
- logout("register must be 0...6 but is %u\n", reg);
- data = 0;
- } else {
- TRACE(MDI, logout("val=0x%08x (int=%u, %s, phy=%u, %s, data=0x%04x\n",
- val, raiseint, mdi_op_name[opcode], phy,
- reg2name(reg), data));
- if (opcode == 1) {
- /* MDI write */
- switch (reg) {
- case 0: /* Control Register */
- if (data & 0x8000) {
- /* Reset status and control registers to default. */
- s->mdimem[0] = eepro100_mdi_default[0];
- s->mdimem[1] = eepro100_mdi_default[1];
- data = s->mdimem[reg];
- } else {
- /* Restart Auto Configuration = Normal Operation */
- data &= ~0x0200;
- }
- break;
- case 1: /* Status Register */
- missing("not writable");
- break;
- case 2: /* PHY Identification Register (Word 1) */
- case 3: /* PHY Identification Register (Word 2) */
- missing("not implemented");
- break;
- case 4: /* Auto-Negotiation Advertisement Register */
- case 5: /* Auto-Negotiation Link Partner Ability Register */
- break;
- case 6: /* Auto-Negotiation Expansion Register */
- default:
- missing("not implemented");
- }
- s->mdimem[reg] &= eepro100_mdi_mask[reg];
- s->mdimem[reg] |= data & ~eepro100_mdi_mask[reg];
- } else if (opcode == 2) {
- /* MDI read */
- switch (reg) {
- case 0: /* Control Register */
- if (data & 0x8000) {
- /* Reset status and control registers to default. */
- s->mdimem[0] = eepro100_mdi_default[0];
- s->mdimem[1] = eepro100_mdi_default[1];
- }
- break;
- case 1: /* Status Register */
- s->mdimem[reg] |= 0x0020;
- break;
- case 2: /* PHY Identification Register (Word 1) */
- case 3: /* PHY Identification Register (Word 2) */
- case 4: /* Auto-Negotiation Advertisement Register */
- break;
- case 5: /* Auto-Negotiation Link Partner Ability Register */
- s->mdimem[reg] = 0x41fe;
- break;
- case 6: /* Auto-Negotiation Expansion Register */
- s->mdimem[reg] = 0x0001;
- break;
- }
- data = s->mdimem[reg];
- }
- /* Emulation takes no time to finish MDI transaction.
- * Set MDI bit in SCB status register. */
- s->mem[SCBAck] |= 0x08;
- val |= BIT(28);
- if (raiseint) {
- eepro100_mdi_interrupt(s);
- }
- }
- val = (val & 0xffff0000) + data;
- e100_write_reg4(s, SCBCtrlMDI, val);
-}
-
-/*****************************************************************************
- *
- * Port emulation.
- *
- ****************************************************************************/
-
-#define PORT_SOFTWARE_RESET 0
-#define PORT_SELFTEST 1
-#define PORT_SELECTIVE_RESET 2
-#define PORT_DUMP 3
-#define PORT_SELECTION_MASK 3
-
-typedef struct {
- uint32_t st_sign; /* Self Test Signature */
- uint32_t st_result; /* Self Test Results */
-} eepro100_selftest_t;
-
-static uint32_t eepro100_read_port(EEPRO100State * s)
-{
- return 0;
-}
-
-static void eepro100_write_port(EEPRO100State *s)
-{
- uint32_t val = e100_read_reg4(s, SCBPort);
- uint32_t address = (val & ~PORT_SELECTION_MASK);
- uint8_t selection = (val & PORT_SELECTION_MASK);
- switch (selection) {
- case PORT_SOFTWARE_RESET:
- nic_reset(s);
- break;
- case PORT_SELFTEST:
- TRACE(OTHER, logout("selftest address=0x%08x\n", address));
- eepro100_selftest_t data;
- pci_dma_read(&s->dev, address, (uint8_t *) &data, sizeof(data));
- data.st_sign = 0xffffffff;
- data.st_result = 0;
- pci_dma_write(&s->dev, address, (uint8_t *) &data, sizeof(data));
- break;
- case PORT_SELECTIVE_RESET:
- TRACE(OTHER, logout("selective reset, selftest address=0x%08x\n", address));
- nic_selective_reset(s);
- break;
- default:
- logout("val=0x%08x\n", val);
- missing("unknown port selection");
- }
-}
-
-/*****************************************************************************
- *
- * General hardware emulation.
- *
- ****************************************************************************/
-
-static uint8_t eepro100_read1(EEPRO100State * s, uint32_t addr)
-{
- uint8_t val = 0;
- if (addr <= sizeof(s->mem) - sizeof(val)) {
- val = s->mem[addr];
- }
-
- switch (addr) {
- case SCBStatus:
- case SCBAck:
- TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
- break;
- case SCBCmd:
- TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
-#if 0
- val = eepro100_read_command(s);
-#endif
- break;
- case SCBIntmask:
- TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
- break;
- case SCBPort + 3:
- TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
- break;
- case SCBeeprom:
- val = eepro100_read_eeprom(s);
- break;
- case SCBCtrlMDI:
- case SCBCtrlMDI + 1:
- case SCBCtrlMDI + 2:
- case SCBCtrlMDI + 3:
- val = (uint8_t)(eepro100_read_mdi(s) >> (8 * (addr & 3)));
- TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
- break;
- case SCBpmdr: /* Power Management Driver Register */
- val = 0;
- TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
- break;
- case SCBgctrl: /* General Control Register */
- TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
- break;
- case SCBgstat: /* General Status Register */
- /* 100 Mbps full duplex, valid link */
- val = 0x07;
- TRACE(OTHER, logout("addr=General Status val=%02x\n", val));
- break;
- default:
- logout("addr=%s val=0x%02x\n", regname(addr), val);
- missing("unknown byte read");
- }
- return val;
-}
-
-static uint16_t eepro100_read2(EEPRO100State * s, uint32_t addr)
-{
- uint16_t val = 0;
- if (addr <= sizeof(s->mem) - sizeof(val)) {
- val = e100_read_reg2(s, addr);
- }
-
- switch (addr) {
- case SCBStatus:
- case SCBCmd:
- TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
- break;
- case SCBeeprom:
- val = eepro100_read_eeprom(s);
- TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
- break;
- case SCBCtrlMDI:
- case SCBCtrlMDI + 2:
- val = (uint16_t)(eepro100_read_mdi(s) >> (8 * (addr & 3)));
- TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
- break;
- default:
- logout("addr=%s val=0x%04x\n", regname(addr), val);
- missing("unknown word read");
- }
- return val;
-}
-
-static uint32_t eepro100_read4(EEPRO100State * s, uint32_t addr)
-{
- uint32_t val = 0;
- if (addr <= sizeof(s->mem) - sizeof(val)) {
- val = e100_read_reg4(s, addr);
- }
-
- switch (addr) {
- case SCBStatus:
- TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
- break;
- case SCBPointer:
- TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
- break;
- case SCBPort:
- val = eepro100_read_port(s);
- TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
- break;
- case SCBflash:
- val = eepro100_read_eeprom(s);
- TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
- break;
- case SCBCtrlMDI:
- val = eepro100_read_mdi(s);
- break;
- default:
- logout("addr=%s val=0x%08x\n", regname(addr), val);
- missing("unknown longword read");
- }
- return val;
-}
-
-static void eepro100_write1(EEPRO100State * s, uint32_t addr, uint8_t val)
-{
- /* SCBStatus is readonly. */
- if (addr > SCBStatus && addr <= sizeof(s->mem) - sizeof(val)) {
- s->mem[addr] = val;
- }
-
- switch (addr) {
- case SCBStatus:
- TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
- break;
- case SCBAck:
- TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
- eepro100_acknowledge(s);
- break;
- case SCBCmd:
- TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
- eepro100_write_command(s, val);
- break;
- case SCBIntmask:
- TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
- if (val & BIT(1)) {
- eepro100_swi_interrupt(s);
- }
- eepro100_interrupt(s, 0);
- break;
- case SCBPointer:
- case SCBPointer + 1:
- case SCBPointer + 2:
- case SCBPointer + 3:
- TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
- break;
- case SCBPort:
- case SCBPort + 1:
- case SCBPort + 2:
- TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
- break;
- case SCBPort + 3:
- TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
- eepro100_write_port(s);
- break;
- case SCBFlow: /* does not exist on 82557 */
- case SCBFlow + 1:
- case SCBFlow + 2:
- case SCBpmdr: /* does not exist on 82557 */
- TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
- break;
- case SCBeeprom:
- TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
- eepro100_write_eeprom(s->eeprom, val);
- break;
- case SCBCtrlMDI:
- case SCBCtrlMDI + 1:
- case SCBCtrlMDI + 2:
- TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
- break;
- case SCBCtrlMDI + 3:
- TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
- eepro100_write_mdi(s);
- break;
- default:
- logout("addr=%s val=0x%02x\n", regname(addr), val);
- missing("unknown byte write");
- }
-}
-
-static void eepro100_write2(EEPRO100State * s, uint32_t addr, uint16_t val)
-{
- /* SCBStatus is readonly. */
- if (addr > SCBStatus && addr <= sizeof(s->mem) - sizeof(val)) {
- e100_write_reg2(s, addr, val);
- }
-
- switch (addr) {
- case SCBStatus:
- TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
- s->mem[SCBAck] = (val >> 8);
- eepro100_acknowledge(s);
- break;
- case SCBCmd:
- TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
- eepro100_write_command(s, val);
- eepro100_write1(s, SCBIntmask, val >> 8);
- break;
- case SCBPointer:
- case SCBPointer + 2:
- TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
- break;
- case SCBPort:
- TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
- break;
- case SCBPort + 2:
- TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
- eepro100_write_port(s);
- break;
- case SCBeeprom:
- TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
- eepro100_write_eeprom(s->eeprom, val);
- break;
- case SCBCtrlMDI:
- TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
- break;
- case SCBCtrlMDI + 2:
- TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
- eepro100_write_mdi(s);
- break;
- default:
- logout("addr=%s val=0x%04x\n", regname(addr), val);
- missing("unknown word write");
- }
-}
-
-static void eepro100_write4(EEPRO100State * s, uint32_t addr, uint32_t val)
-{
- if (addr <= sizeof(s->mem) - sizeof(val)) {
- e100_write_reg4(s, addr, val);
- }
-
- switch (addr) {
- case SCBPointer:
- TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
- break;
- case SCBPort:
- TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
- eepro100_write_port(s);
- break;
- case SCBflash:
- TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
- val = val >> 16;
- eepro100_write_eeprom(s->eeprom, val);
- break;
- case SCBCtrlMDI:
- TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
- eepro100_write_mdi(s);
- break;
- default:
- logout("addr=%s val=0x%08x\n", regname(addr), val);
- missing("unknown longword write");
- }
-}
-
-static uint64_t eepro100_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- EEPRO100State *s = opaque;
-
- switch (size) {
- case 1: return eepro100_read1(s, addr);
- case 2: return eepro100_read2(s, addr);
- case 4: return eepro100_read4(s, addr);
- default: abort();
- }
-}
-
-static void eepro100_write(void *opaque, hwaddr addr,
- uint64_t data, unsigned size)
-{
- EEPRO100State *s = opaque;
-
- switch (size) {
- case 1:
- eepro100_write1(s, addr, data);
- break;
- case 2:
- eepro100_write2(s, addr, data);
- break;
- case 4:
- eepro100_write4(s, addr, data);
- break;
- default:
- abort();
- }
-}
-
-static const MemoryRegionOps eepro100_ops = {
- .read = eepro100_read,
- .write = eepro100_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size)
-{
- /* TODO:
- * - Magic packets should set bit 30 in power management driver register.
- * - Interesting packets should set bit 29 in power management driver register.
- */
- EEPRO100State *s = qemu_get_nic_opaque(nc);
- uint16_t rfd_status = 0xa000;
-#if defined(CONFIG_PAD_RECEIVED_FRAMES)
- uint8_t min_buf[60];
-#endif
- static const uint8_t broadcast_macaddr[6] =
- { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-
-#if defined(CONFIG_PAD_RECEIVED_FRAMES)
- /* Pad to minimum Ethernet frame length */
- if (size < sizeof(min_buf)) {
- memcpy(min_buf, buf, size);
- memset(&min_buf[size], 0, sizeof(min_buf) - size);
- buf = min_buf;
- size = sizeof(min_buf);
- }
-#endif
-
- if (s->configuration[8] & 0x80) {
- /* CSMA is disabled. */
- logout("%p received while CSMA is disabled\n", s);
- return -1;
-#if !defined(CONFIG_PAD_RECEIVED_FRAMES)
- } else if (size < 64 && (s->configuration[7] & BIT(0))) {
- /* Short frame and configuration byte 7/0 (discard short receive) set:
- * Short frame is discarded */
- logout("%p received short frame (%zu byte)\n", s, size);
- s->statistics.rx_short_frame_errors++;
- return -1;
-#endif
- } else if ((size > MAX_ETH_FRAME_SIZE + 4) && !(s->configuration[18] & BIT(3))) {
- /* Long frame and configuration byte 18/3 (long receive ok) not set:
- * Long frames are discarded. */
- logout("%p received long frame (%zu byte), ignored\n", s, size);
- return -1;
- } else if (memcmp(buf, s->conf.macaddr.a, 6) == 0) { /* !!! */
- /* Frame matches individual address. */
- /* TODO: check configuration byte 15/4 (ignore U/L). */
- TRACE(RXTX, logout("%p received frame for me, len=%zu\n", s, size));
- } else if (memcmp(buf, broadcast_macaddr, 6) == 0) {
- /* Broadcast frame. */
- TRACE(RXTX, logout("%p received broadcast, len=%zu\n", s, size));
- rfd_status |= 0x0002;
- } else if (buf[0] & 0x01) {
- /* Multicast frame. */
- TRACE(RXTX, logout("%p received multicast, len=%zu,%s\n", s, size, nic_dump(buf, size)));
- if (s->configuration[21] & BIT(3)) {
- /* Multicast all bit is set, receive all multicast frames. */
- } else {
- unsigned mcast_idx = e100_compute_mcast_idx(buf);
- assert(mcast_idx < 64);
- if (s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))) {
- /* Multicast frame is allowed in hash table. */
- } else if (s->configuration[15] & BIT(0)) {
- /* Promiscuous: receive all. */
- rfd_status |= 0x0004;
- } else {
- TRACE(RXTX, logout("%p multicast ignored\n", s));
- return -1;
- }
- }
- /* TODO: Next not for promiscuous mode? */
- rfd_status |= 0x0002;
- } else if (s->configuration[15] & BIT(0)) {
- /* Promiscuous: receive all. */
- TRACE(RXTX, logout("%p received frame in promiscuous mode, len=%zu\n", s, size));
- rfd_status |= 0x0004;
- } else if (s->configuration[20] & BIT(6)) {
- /* Multiple IA bit set. */
- unsigned mcast_idx = compute_mcast_idx(buf);
- assert(mcast_idx < 64);
- if (s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))) {
- TRACE(RXTX, logout("%p accepted, multiple IA bit set\n", s));
- } else {
- TRACE(RXTX, logout("%p frame ignored, multiple IA bit set\n", s));
- return -1;
- }
- } else {
- TRACE(RXTX, logout("%p received frame, ignored, len=%zu,%s\n", s, size,
- nic_dump(buf, size)));
- return size;
- }
-
- if (get_ru_state(s) != ru_ready) {
- /* No resources available. */
- logout("no resources, state=%u\n", get_ru_state(s));
- /* TODO: RNR interrupt only at first failed frame? */
- eepro100_rnr_interrupt(s);
- s->statistics.rx_resource_errors++;
-#if 0
- assert(!"no resources");
-#endif
- return -1;
- }
- /* !!! */
- eepro100_rx_t rx;
- pci_dma_read(&s->dev, s->ru_base + s->ru_offset,
- &rx, sizeof(eepro100_rx_t));
- uint16_t rfd_command = le16_to_cpu(rx.command);
- uint16_t rfd_size = le16_to_cpu(rx.size);
-
- if (size > rfd_size) {
- logout("Receive buffer (%" PRId16 " bytes) too small for data "
- "(%zu bytes); data truncated\n", rfd_size, size);
- size = rfd_size;
- }
-#if !defined(CONFIG_PAD_RECEIVED_FRAMES)
- if (size < 64) {
- rfd_status |= 0x0080;
- }
-#endif
- TRACE(OTHER, logout("command 0x%04x, link 0x%08x, addr 0x%08x, size %u\n",
- rfd_command, rx.link, rx.rx_buf_addr, rfd_size));
- stw_le_pci_dma(&s->dev, s->ru_base + s->ru_offset +
- offsetof(eepro100_rx_t, status), rfd_status);
- stw_le_pci_dma(&s->dev, s->ru_base + s->ru_offset +
- offsetof(eepro100_rx_t, count), size);
- /* Early receive interrupt not supported. */
-#if 0
- eepro100_er_interrupt(s);
-#endif
- /* Receive CRC Transfer not supported. */
- if (s->configuration[18] & BIT(2)) {
- missing("Receive CRC Transfer");
- return -1;
- }
- /* TODO: check stripping enable bit. */
-#if 0
- assert(!(s->configuration[17] & BIT(0)));
-#endif
- pci_dma_write(&s->dev, s->ru_base + s->ru_offset +
- sizeof(eepro100_rx_t), buf, size);
- s->statistics.rx_good_frames++;
- eepro100_fr_interrupt(s);
- s->ru_offset = le32_to_cpu(rx.link);
- if (rfd_command & COMMAND_EL) {
- /* EL bit is set, so this was the last frame. */
- logout("receive: Running out of frames\n");
- set_ru_state(s, ru_no_resources);
- eepro100_rnr_interrupt(s);
- }
- if (rfd_command & COMMAND_S) {
- /* S bit is set. */
- set_ru_state(s, ru_suspended);
- }
- return size;
-}
-
-static const VMStateDescription vmstate_eepro100 = {
- .version_id = 3,
- .minimum_version_id = 2,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(dev, EEPRO100State),
- VMSTATE_UNUSED(32),
- VMSTATE_BUFFER(mult, EEPRO100State),
- VMSTATE_BUFFER(mem, EEPRO100State),
- /* Save all members of struct between scb_stat and mem. */
- VMSTATE_UINT8(scb_stat, EEPRO100State),
- VMSTATE_UINT8(int_stat, EEPRO100State),
- VMSTATE_UNUSED(3*4),
- VMSTATE_MACADDR(conf.macaddr, EEPRO100State),
- VMSTATE_UNUSED(19*4),
- VMSTATE_UINT16_ARRAY(mdimem, EEPRO100State, 32),
- /* The eeprom should be saved and restored by its own routines. */
- VMSTATE_UINT32(device, EEPRO100State),
- /* TODO check device. */
- VMSTATE_UINT32(cu_base, EEPRO100State),
- VMSTATE_UINT32(cu_offset, EEPRO100State),
- VMSTATE_UINT32(ru_base, EEPRO100State),
- VMSTATE_UINT32(ru_offset, EEPRO100State),
- VMSTATE_UINT32(statsaddr, EEPRO100State),
- /* Save eepro100_stats_t statistics. */
- VMSTATE_UINT32(statistics.tx_good_frames, EEPRO100State),
- VMSTATE_UINT32(statistics.tx_max_collisions, EEPRO100State),
- VMSTATE_UINT32(statistics.tx_late_collisions, EEPRO100State),
- VMSTATE_UINT32(statistics.tx_underruns, EEPRO100State),
- VMSTATE_UINT32(statistics.tx_lost_crs, EEPRO100State),
- VMSTATE_UINT32(statistics.tx_deferred, EEPRO100State),
- VMSTATE_UINT32(statistics.tx_single_collisions, EEPRO100State),
- VMSTATE_UINT32(statistics.tx_multiple_collisions, EEPRO100State),
- VMSTATE_UINT32(statistics.tx_total_collisions, EEPRO100State),
- VMSTATE_UINT32(statistics.rx_good_frames, EEPRO100State),
- VMSTATE_UINT32(statistics.rx_crc_errors, EEPRO100State),
- VMSTATE_UINT32(statistics.rx_alignment_errors, EEPRO100State),
- VMSTATE_UINT32(statistics.rx_resource_errors, EEPRO100State),
- VMSTATE_UINT32(statistics.rx_overrun_errors, EEPRO100State),
- VMSTATE_UINT32(statistics.rx_cdt_errors, EEPRO100State),
- VMSTATE_UINT32(statistics.rx_short_frame_errors, EEPRO100State),
- VMSTATE_UINT32(statistics.fc_xmt_pause, EEPRO100State),
- VMSTATE_UINT32(statistics.fc_rcv_pause, EEPRO100State),
- VMSTATE_UINT32(statistics.fc_rcv_unsupported, EEPRO100State),
- VMSTATE_UINT16(statistics.xmt_tco_frames, EEPRO100State),
- VMSTATE_UINT16(statistics.rcv_tco_frames, EEPRO100State),
- /* Configuration bytes. */
- VMSTATE_BUFFER(configuration, EEPRO100State),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void pci_nic_uninit(PCIDevice *pci_dev)
-{
- EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
-
- vmstate_unregister(&pci_dev->qdev, s->vmstate, s);
- eeprom93xx_free(&pci_dev->qdev, s->eeprom);
- qemu_del_nic(s->nic);
-}
-
-static NetClientInfo net_eepro100_info = {
- .type = NET_CLIENT_OPTIONS_KIND_NIC,
- .size = sizeof(NICState),
- .receive = nic_receive,
-};
-
-static void e100_nic_realize(PCIDevice *pci_dev, Error **errp)
-{
- EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
- E100PCIDeviceInfo *info = eepro100_get_class(s);
-
- TRACE(OTHER, logout("\n"));
-
- s->device = info->device;
-
- e100_pci_reset(s);
-
- /* Add 64 * 2 EEPROM. i82557 and i82558 support a 64 word EEPROM,
- * i82559 and later support 64 or 256 word EEPROM. */
- s->eeprom = eeprom93xx_new(&pci_dev->qdev, EEPROM_SIZE);
-
- /* Handler for memory-mapped I/O */
- memory_region_init_io(&s->mmio_bar, OBJECT(s), &eepro100_ops, s,
- "eepro100-mmio", PCI_MEM_SIZE);
- pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->mmio_bar);
- memory_region_init_io(&s->io_bar, OBJECT(s), &eepro100_ops, s,
- "eepro100-io", PCI_IO_SIZE);
- pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->io_bar);
- /* FIXME: flash aliases to mmio?! */
- memory_region_init_io(&s->flash_bar, OBJECT(s), &eepro100_ops, s,
- "eepro100-flash", PCI_FLASH_SIZE);
- pci_register_bar(&s->dev, 2, 0, &s->flash_bar);
-
- qemu_macaddr_default_if_unset(&s->conf.macaddr);
- logout("macaddr: %s\n", nic_dump(&s->conf.macaddr.a[0], 6));
-
- nic_reset(s);
-
- s->nic = qemu_new_nic(&net_eepro100_info, &s->conf,
- object_get_typename(OBJECT(pci_dev)), pci_dev->qdev.id, s);
-
- qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
- TRACE(OTHER, logout("%s\n", qemu_get_queue(s->nic)->info_str));
-
- qemu_register_reset(nic_reset, s);
-
- s->vmstate = g_malloc(sizeof(vmstate_eepro100));
- memcpy(s->vmstate, &vmstate_eepro100, sizeof(vmstate_eepro100));
- s->vmstate->name = qemu_get_queue(s->nic)->model;
- vmstate_register(&pci_dev->qdev, -1, s->vmstate, s);
-}
-
-static void eepro100_instance_init(Object *obj)
-{
- EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, PCI_DEVICE(obj));
- device_add_bootindex_property(obj, &s->conf.bootindex,
- "bootindex", "/ethernet-phy@0",
- DEVICE(s), NULL);
-}
-
-static E100PCIDeviceInfo e100_devices[] = {
- {
- .name = "i82550",
- .desc = "Intel i82550 Ethernet",
- .device = i82550,
- /* TODO: check device id. */
- .device_id = PCI_DEVICE_ID_INTEL_82551IT,
- /* Revision ID: 0x0c, 0x0d, 0x0e. */
- .revision = 0x0e,
- /* TODO: check size of statistical counters. */
- .stats_size = 80,
- /* TODO: check extended tcb support. */
- .has_extended_tcb_support = true,
- .power_management = true,
- },{
- .name = "i82551",
- .desc = "Intel i82551 Ethernet",
- .device = i82551,
- .device_id = PCI_DEVICE_ID_INTEL_82551IT,
- /* Revision ID: 0x0f, 0x10. */
- .revision = 0x0f,
- /* TODO: check size of statistical counters. */
- .stats_size = 80,
- .has_extended_tcb_support = true,
- .power_management = true,
- },{
- .name = "i82557a",
- .desc = "Intel i82557A Ethernet",
- .device = i82557A,
- .device_id = PCI_DEVICE_ID_INTEL_82557,
- .revision = 0x01,
- .power_management = false,
- },{
- .name = "i82557b",
- .desc = "Intel i82557B Ethernet",
- .device = i82557B,
- .device_id = PCI_DEVICE_ID_INTEL_82557,
- .revision = 0x02,
- .power_management = false,
- },{
- .name = "i82557c",
- .desc = "Intel i82557C Ethernet",
- .device = i82557C,
- .device_id = PCI_DEVICE_ID_INTEL_82557,
- .revision = 0x03,
- .power_management = false,
- },{
- .name = "i82558a",
- .desc = "Intel i82558A Ethernet",
- .device = i82558A,
- .device_id = PCI_DEVICE_ID_INTEL_82557,
- .revision = 0x04,
- .stats_size = 76,
- .has_extended_tcb_support = true,
- .power_management = true,
- },{
- .name = "i82558b",
- .desc = "Intel i82558B Ethernet",
- .device = i82558B,
- .device_id = PCI_DEVICE_ID_INTEL_82557,
- .revision = 0x05,
- .stats_size = 76,
- .has_extended_tcb_support = true,
- .power_management = true,
- },{
- .name = "i82559a",
- .desc = "Intel i82559A Ethernet",
- .device = i82559A,
- .device_id = PCI_DEVICE_ID_INTEL_82557,
- .revision = 0x06,
- .stats_size = 80,
- .has_extended_tcb_support = true,
- .power_management = true,
- },{
- .name = "i82559b",
- .desc = "Intel i82559B Ethernet",
- .device = i82559B,
- .device_id = PCI_DEVICE_ID_INTEL_82557,
- .revision = 0x07,
- .stats_size = 80,
- .has_extended_tcb_support = true,
- .power_management = true,
- },{
- .name = "i82559c",
- .desc = "Intel i82559C Ethernet",
- .device = i82559C,
- .device_id = PCI_DEVICE_ID_INTEL_82557,
-#if 0
- .revision = 0x08,
-#endif
- /* TODO: Windows wants revision id 0x0c. */
- .revision = 0x0c,
-#if EEPROM_SIZE > 0
- .subsystem_vendor_id = PCI_VENDOR_ID_INTEL,
- .subsystem_id = 0x0040,
-#endif
- .stats_size = 80,
- .has_extended_tcb_support = true,
- .power_management = true,
- },{
- .name = "i82559er",
- .desc = "Intel i82559ER Ethernet",
- .device = i82559ER,
- .device_id = PCI_DEVICE_ID_INTEL_82551IT,
- .revision = 0x09,
- .stats_size = 80,
- .has_extended_tcb_support = true,
- .power_management = true,
- },{
- .name = "i82562",
- .desc = "Intel i82562 Ethernet",
- .device = i82562,
- /* TODO: check device id. */
- .device_id = PCI_DEVICE_ID_INTEL_82551IT,
- /* TODO: wrong revision id. */
- .revision = 0x0e,
- .stats_size = 80,
- .has_extended_tcb_support = true,
- .power_management = true,
- },{
- /* Toshiba Tecra 8200. */
- .name = "i82801",
- .desc = "Intel i82801 Ethernet",
- .device = i82801,
- .device_id = 0x2449,
- .revision = 0x03,
- .stats_size = 80,
- .has_extended_tcb_support = true,
- .power_management = true,
- }
-};
-
-static E100PCIDeviceInfo *eepro100_get_class_by_name(const char *typename)
-{
- E100PCIDeviceInfo *info = NULL;
- int i;
-
- /* This is admittedly awkward but also temporary. QOM allows for
- * parameterized typing and for subclassing both of which would suitable
- * handle what's going on here. But class_data is already being used as
- * a stop-gap hack to allow incremental qdev conversion so we cannot use it
- * right now. Once we merge the final QOM series, we can come back here and
- * do this in a much more elegant fashion.
- */
- for (i = 0; i < ARRAY_SIZE(e100_devices); i++) {
- if (strcmp(e100_devices[i].name, typename) == 0) {
- info = &e100_devices[i];
- break;
- }
- }
- assert(info != NULL);
-
- return info;
-}
-
-static E100PCIDeviceInfo *eepro100_get_class(EEPRO100State *s)
-{
- return eepro100_get_class_by_name(object_get_typename(OBJECT(s)));
-}
-
-static Property e100_properties[] = {
- DEFINE_NIC_PROPERTIES(EEPRO100State, conf),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void eepro100_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- E100PCIDeviceInfo *info;
-
- info = eepro100_get_class_by_name(object_class_get_name(klass));
-
- set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
- dc->props = e100_properties;
- dc->desc = info->desc;
- k->vendor_id = PCI_VENDOR_ID_INTEL;
- k->class_id = PCI_CLASS_NETWORK_ETHERNET;
- k->romfile = "pxe-eepro100.rom";
- k->realize = e100_nic_realize;
- k->exit = pci_nic_uninit;
- k->device_id = info->device_id;
- k->revision = info->revision;
- k->subsystem_vendor_id = info->subsystem_vendor_id;
- k->subsystem_id = info->subsystem_id;
-}
-
-static void eepro100_register_types(void)
-{
- size_t i;
- for (i = 0; i < ARRAY_SIZE(e100_devices); i++) {
- TypeInfo type_info = {};
- E100PCIDeviceInfo *info = &e100_devices[i];
-
- type_info.name = info->name;
- type_info.parent = TYPE_PCI_DEVICE;
- type_info.class_init = eepro100_class_init;
- type_info.instance_size = sizeof(EEPRO100State);
- type_info.instance_init = eepro100_instance_init;
-
- type_register(&type_info);
- }
-}
-
-type_init(eepro100_register_types)
diff --git a/qemu/hw/net/etraxfs_eth.c b/qemu/hw/net/etraxfs_eth.c
deleted file mode 100644
index 05495ec40..000000000
--- a/qemu/hw/net/etraxfs_eth.c
+++ /dev/null
@@ -1,648 +0,0 @@
-/*
- * QEMU ETRAX Ethernet Controller.
- *
- * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "net/net.h"
-#include "hw/cris/etraxfs.h"
-#include "qemu/error-report.h"
-
-#define D(x)
-
-/* Advertisement control register. */
-#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */
-#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */
-#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
- * linux driver (PHYID and Diagnostics reg).
- * TODO: Add friendly names for the register nums.
- */
-struct qemu_phy
-{
- uint32_t regs[32];
-
- int link;
-
- 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;
-}
-
-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;
- }
-}
-
-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;
-}
-
-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];
-};
-
-static void
-mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
-{
- bus->devs[addr & 0x1f] = phy;
-}
-
-#ifdef USE_THIS_DEAD_CODE
-static void
-mdio_detach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
-{
- 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;
- }
-}
-
-static void mdio_write_req(struct qemu_mdio *bus)
-{
- struct qemu_phy *phy;
-
- 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++;
-
- 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);
- }
-#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;
- }
-}
-
-/* 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 TYPE_ETRAX_FS_ETH "etraxfs-eth"
-#define ETRAX_FS_ETH(obj) \
- OBJECT_CHECK(ETRAXFSEthState, (obj), TYPE_ETRAX_FS_ETH)
-
-typedef struct ETRAXFSEthState
-{
- SysBusDevice parent_obj;
-
- 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;
-} ETRAXFSEthState;
-
-static void eth_validate_duplex(ETRAXFSEthState *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;
- }
-}
-
-static uint64_t
-eth_read(void *opaque, hwaddr addr, unsigned int size)
-{
- ETRAXFSEthState *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(ETRAXFSEthState *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]));
-}
-
-static void
-eth_write(void *opaque, hwaddr addr,
- uint64_t val64, unsigned int size)
-{
- ETRAXFSEthState *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(&eth->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. */
-static int eth_match_groupaddr(ETRAXFSEthState *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;
-}
-
-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 };
- ETRAXFSEthState *eth = qemu_get_nic_opaque(nc);
- 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)
-{
- ETRAXFSEthState *eth = opaque;
-
- D(printf("%s buf=%p len=%d\n", __func__, buf, len));
- qemu_send_packet(qemu_get_queue(eth->nic), buf, len);
- return len;
-}
-
-static void eth_set_link(NetClientState *nc)
-{
- ETRAXFSEthState *eth = qemu_get_nic_opaque(nc);
- 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
- }
-};
-
-static NetClientInfo net_etraxfs_info = {
- .type = NET_CLIENT_OPTIONS_KIND_NIC,
- .size = sizeof(NICState),
- .receive = eth_receive,
- .link_status_changed = eth_set_link,
-};
-
-static int fs_eth_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- ETRAXFSEthState *s = ETRAX_FS_ETH(dev);
-
- if (!s->dma_out || !s->dma_in) {
- error_report("Unconnected ETRAX-FS Ethernet MAC");
- return -1;
- }
-
- 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, OBJECT(dev), &eth_ops, s,
- "etraxfs-eth", 0x5c);
- sysbus_init_mmio(sbd, &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->id, s);
- qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-
-
- tdk_init(&s->phy);
- mdio_attach(&s->mdio_bus, &s->phy, s->phyaddr);
- return 0;
-}
-
-static Property etraxfs_eth_properties[] = {
- DEFINE_PROP_UINT32("phyaddr", ETRAXFSEthState, phyaddr, 1),
- DEFINE_PROP_PTR("dma_out", ETRAXFSEthState, vdma_out),
- DEFINE_PROP_PTR("dma_in", ETRAXFSEthState, vdma_in),
- DEFINE_NIC_PROPERTIES(ETRAXFSEthState, conf),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void etraxfs_eth_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = fs_eth_init;
- dc->props = etraxfs_eth_properties;
- /* Reason: pointer properties "dma_out", "dma_in" */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo etraxfs_eth_info = {
- .name = TYPE_ETRAX_FS_ETH,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(ETRAXFSEthState),
- .class_init = etraxfs_eth_class_init,
-};
-
-static void etraxfs_eth_register_types(void)
-{
- type_register_static(&etraxfs_eth_info);
-}
-
-type_init(etraxfs_eth_register_types)
diff --git a/qemu/hw/net/fsl_etsec/etsec.c b/qemu/hw/net/fsl_etsec/etsec.c
deleted file mode 100644
index 1e35f7f8c..000000000
--- a/qemu/hw/net/fsl_etsec/etsec.c
+++ /dev/null
@@ -1,457 +0,0 @@
-/*
- * QEMU Freescale eTSEC Emulator
- *
- * Copyright (c) 2011-2013 AdaCore
- *
- * 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.
- */
-
-/*
- * This implementation doesn't include ring priority, TCP/IP Off-Load, QoS.
- */
-
-#include "qemu/osdep.h"
-#include "sysemu/sysemu.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "hw/ptimer.h"
-#include "etsec.h"
-#include "registers.h"
-
-/* #define HEX_DUMP */
-/* #define DEBUG_REGISTER */
-
-#ifdef DEBUG_REGISTER
-static const int debug_etsec = 1;
-#else
-static const int debug_etsec;
-#endif
-
-#define DPRINTF(fmt, ...) do { \
- if (debug_etsec) { \
- qemu_log(fmt , ## __VA_ARGS__); \
- } \
- } while (0)
-
-static uint64_t etsec_read(void *opaque, hwaddr addr, unsigned size)
-{
- eTSEC *etsec = opaque;
- uint32_t reg_index = addr / 4;
- eTSEC_Register *reg = NULL;
- uint32_t ret = 0x0;
-
- assert(reg_index < ETSEC_REG_NUMBER);
-
- reg = &etsec->regs[reg_index];
-
-
- switch (reg->access) {
- case ACC_WO:
- ret = 0x00000000;
- break;
-
- case ACC_RW:
- case ACC_W1C:
- case ACC_RO:
- default:
- ret = reg->value;
- break;
- }
-
- DPRINTF("Read 0x%08x @ 0x" TARGET_FMT_plx
- " : %s (%s)\n",
- ret, addr, reg->name, reg->desc);
-
- return ret;
-}
-
-static void write_tstat(eTSEC *etsec,
- eTSEC_Register *reg,
- uint32_t reg_index,
- uint32_t value)
-{
- int i = 0;
-
- for (i = 0; i < 8; i++) {
- /* Check THLTi flag in TSTAT */
- if (value & (1 << (31 - i))) {
- etsec_walk_tx_ring(etsec, i);
- }
- }
-
- /* Write 1 to clear */
- reg->value &= ~value;
-}
-
-static void write_rstat(eTSEC *etsec,
- eTSEC_Register *reg,
- uint32_t reg_index,
- uint32_t value)
-{
- int i = 0;
-
- for (i = 0; i < 8; i++) {
- /* Check QHLTi flag in RSTAT */
- if (value & (1 << (23 - i)) && !(reg->value & (1 << (23 - i)))) {
- etsec_walk_rx_ring(etsec, i);
- }
- }
-
- /* Write 1 to clear */
- reg->value &= ~value;
-}
-
-static void write_tbasex(eTSEC *etsec,
- eTSEC_Register *reg,
- uint32_t reg_index,
- uint32_t value)
-{
- reg->value = value & ~0x7;
-
- /* Copy this value in the ring's TxBD pointer */
- etsec->regs[TBPTR0 + (reg_index - TBASE0)].value = value & ~0x7;
-}
-
-static void write_rbasex(eTSEC *etsec,
- eTSEC_Register *reg,
- uint32_t reg_index,
- uint32_t value)
-{
- reg->value = value & ~0x7;
-
- /* Copy this value in the ring's RxBD pointer */
- etsec->regs[RBPTR0 + (reg_index - RBASE0)].value = value & ~0x7;
-}
-
-static void write_ievent(eTSEC *etsec,
- eTSEC_Register *reg,
- uint32_t reg_index,
- uint32_t value)
-{
- /* Write 1 to clear */
- reg->value &= ~value;
-
- if (!(reg->value & (IEVENT_TXF | IEVENT_TXF))) {
- qemu_irq_lower(etsec->tx_irq);
- }
- if (!(reg->value & (IEVENT_RXF | IEVENT_RXF))) {
- qemu_irq_lower(etsec->rx_irq);
- }
-
- if (!(reg->value & (IEVENT_MAG | IEVENT_GTSC | IEVENT_GRSC | IEVENT_TXC |
- IEVENT_RXC | IEVENT_BABR | IEVENT_BABT | IEVENT_LC |
- IEVENT_CRL | IEVENT_FGPI | IEVENT_FIR | IEVENT_FIQ |
- IEVENT_DPE | IEVENT_PERR | IEVENT_EBERR | IEVENT_TXE |
- IEVENT_XFUN | IEVENT_BSY | IEVENT_MSRO | IEVENT_MMRD |
- IEVENT_MMRW))) {
- qemu_irq_lower(etsec->err_irq);
- }
-}
-
-static void write_dmactrl(eTSEC *etsec,
- eTSEC_Register *reg,
- uint32_t reg_index,
- uint32_t value)
-{
- reg->value = value;
-
- if (value & DMACTRL_GRS) {
-
- if (etsec->rx_buffer_len != 0) {
- /* Graceful receive stop delayed until end of frame */
- } else {
- /* Graceful receive stop now */
- etsec->regs[IEVENT].value |= IEVENT_GRSC;
- if (etsec->regs[IMASK].value & IMASK_GRSCEN) {
- qemu_irq_raise(etsec->err_irq);
- }
- }
- }
-
- if (value & DMACTRL_GTS) {
-
- if (etsec->tx_buffer_len != 0) {
- /* Graceful transmit stop delayed until end of frame */
- } else {
- /* Graceful transmit stop now */
- etsec->regs[IEVENT].value |= IEVENT_GTSC;
- if (etsec->regs[IMASK].value & IMASK_GTSCEN) {
- qemu_irq_raise(etsec->err_irq);
- }
- }
- }
-
- if (!(value & DMACTRL_WOP)) {
- /* Start polling */
- ptimer_stop(etsec->ptimer);
- ptimer_set_count(etsec->ptimer, 1);
- ptimer_run(etsec->ptimer, 1);
- }
-}
-
-static void etsec_write(void *opaque,
- hwaddr addr,
- uint64_t value,
- unsigned size)
-{
- eTSEC *etsec = opaque;
- uint32_t reg_index = addr / 4;
- eTSEC_Register *reg = NULL;
- uint32_t before = 0x0;
-
- assert(reg_index < ETSEC_REG_NUMBER);
-
- reg = &etsec->regs[reg_index];
- before = reg->value;
-
- switch (reg_index) {
- case IEVENT:
- write_ievent(etsec, reg, reg_index, value);
- break;
-
- case DMACTRL:
- write_dmactrl(etsec, reg, reg_index, value);
- break;
-
- case TSTAT:
- write_tstat(etsec, reg, reg_index, value);
- break;
-
- case RSTAT:
- write_rstat(etsec, reg, reg_index, value);
- break;
-
- case TBASE0 ... TBASE7:
- write_tbasex(etsec, reg, reg_index, value);
- break;
-
- case RBASE0 ... RBASE7:
- write_rbasex(etsec, reg, reg_index, value);
- break;
-
- case MIIMCFG ... MIIMIND:
- etsec_write_miim(etsec, reg, reg_index, value);
- break;
-
- default:
- /* Default handling */
- switch (reg->access) {
-
- case ACC_RW:
- case ACC_WO:
- reg->value = value;
- break;
-
- case ACC_W1C:
- reg->value &= ~value;
- break;
-
- case ACC_RO:
- default:
- /* Read Only or Unknown register */
- break;
- }
- }
-
- DPRINTF("Write 0x%08x @ 0x" TARGET_FMT_plx
- " val:0x%08x->0x%08x : %s (%s)\n",
- (unsigned int)value, addr, before, reg->value,
- reg->name, reg->desc);
-}
-
-static const MemoryRegionOps etsec_ops = {
- .read = etsec_read,
- .write = etsec_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .impl = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static void etsec_timer_hit(void *opaque)
-{
- eTSEC *etsec = opaque;
-
- ptimer_stop(etsec->ptimer);
-
- if (!(etsec->regs[DMACTRL].value & DMACTRL_WOP)) {
-
- if (!(etsec->regs[DMACTRL].value & DMACTRL_GTS)) {
- etsec_walk_tx_ring(etsec, 0);
- }
- ptimer_set_count(etsec->ptimer, 1);
- ptimer_run(etsec->ptimer, 1);
- }
-}
-
-static void etsec_reset(DeviceState *d)
-{
- eTSEC *etsec = ETSEC_COMMON(d);
- int i = 0;
- int reg_index = 0;
-
- /* Default value for all registers */
- for (i = 0; i < ETSEC_REG_NUMBER; i++) {
- etsec->regs[i].name = "Reserved";
- etsec->regs[i].desc = "";
- etsec->regs[i].access = ACC_UNKNOWN;
- etsec->regs[i].value = 0x00000000;
- }
-
- /* Set-up known registers */
- for (i = 0; eTSEC_registers_def[i].name != NULL; i++) {
-
- reg_index = eTSEC_registers_def[i].offset / 4;
-
- etsec->regs[reg_index].name = eTSEC_registers_def[i].name;
- etsec->regs[reg_index].desc = eTSEC_registers_def[i].desc;
- etsec->regs[reg_index].access = eTSEC_registers_def[i].access;
- etsec->regs[reg_index].value = eTSEC_registers_def[i].reset;
- }
-
- etsec->tx_buffer = NULL;
- etsec->tx_buffer_len = 0;
- etsec->rx_buffer = NULL;
- etsec->rx_buffer_len = 0;
-
- etsec->phy_status =
- MII_SR_EXTENDED_CAPS | MII_SR_LINK_STATUS | MII_SR_AUTONEG_CAPS |
- MII_SR_AUTONEG_COMPLETE | MII_SR_PREAMBLE_SUPPRESS |
- MII_SR_EXTENDED_STATUS | MII_SR_100T2_HD_CAPS | MII_SR_100T2_FD_CAPS |
- MII_SR_10T_HD_CAPS | MII_SR_10T_FD_CAPS | MII_SR_100X_HD_CAPS |
- MII_SR_100X_FD_CAPS | MII_SR_100T4_CAPS;
-}
-
-static ssize_t etsec_receive(NetClientState *nc,
- const uint8_t *buf,
- size_t size)
-{
- ssize_t ret;
- eTSEC *etsec = qemu_get_nic_opaque(nc);
-
-#if defined(HEX_DUMP)
- fprintf(stderr, "%s receive size:%d\n", etsec->nic->nc.name, size);
- qemu_hexdump(buf, stderr, "", size);
-#endif
- /* Flush is unnecessary as are already in receiving path */
- etsec->need_flush = false;
- ret = etsec_rx_ring_write(etsec, buf, size);
- if (ret == 0) {
- /* The packet will be queued, let's flush it when buffer is available
- * again. */
- etsec->need_flush = true;
- }
- return ret;
-}
-
-
-static void etsec_set_link_status(NetClientState *nc)
-{
- eTSEC *etsec = qemu_get_nic_opaque(nc);
-
- etsec_miim_link_status(etsec, nc);
-}
-
-static NetClientInfo net_etsec_info = {
- .type = NET_CLIENT_OPTIONS_KIND_NIC,
- .size = sizeof(NICState),
- .receive = etsec_receive,
- .link_status_changed = etsec_set_link_status,
-};
-
-static void etsec_realize(DeviceState *dev, Error **errp)
-{
- eTSEC *etsec = ETSEC_COMMON(dev);
-
- etsec->nic = qemu_new_nic(&net_etsec_info, &etsec->conf,
- object_get_typename(OBJECT(dev)), dev->id, etsec);
- qemu_format_nic_info_str(qemu_get_queue(etsec->nic), etsec->conf.macaddr.a);
-
-
- etsec->bh = qemu_bh_new(etsec_timer_hit, etsec);
- etsec->ptimer = ptimer_init(etsec->bh);
- ptimer_set_freq(etsec->ptimer, 100);
-}
-
-static void etsec_instance_init(Object *obj)
-{
- eTSEC *etsec = ETSEC_COMMON(obj);
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
-
- memory_region_init_io(&etsec->io_area, OBJECT(etsec), &etsec_ops, etsec,
- "eTSEC", 0x1000);
- sysbus_init_mmio(sbd, &etsec->io_area);
-
- sysbus_init_irq(sbd, &etsec->tx_irq);
- sysbus_init_irq(sbd, &etsec->rx_irq);
- sysbus_init_irq(sbd, &etsec->err_irq);
-}
-
-static Property etsec_properties[] = {
- DEFINE_NIC_PROPERTIES(eTSEC, conf),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void etsec_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = etsec_realize;
- dc->reset = etsec_reset;
- dc->props = etsec_properties;
-}
-
-static TypeInfo etsec_info = {
- .name = "eTSEC",
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(eTSEC),
- .class_init = etsec_class_init,
- .instance_init = etsec_instance_init,
-};
-
-static void etsec_register_types(void)
-{
- type_register_static(&etsec_info);
-}
-
-type_init(etsec_register_types)
-
-DeviceState *etsec_create(hwaddr base,
- MemoryRegion * mr,
- NICInfo * nd,
- qemu_irq tx_irq,
- qemu_irq rx_irq,
- qemu_irq err_irq)
-{
- DeviceState *dev;
-
- dev = qdev_create(NULL, "eTSEC");
- qdev_set_nic_properties(dev, nd);
- qdev_init_nofail(dev);
-
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, tx_irq);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, rx_irq);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, err_irq);
-
- memory_region_add_subregion(mr, base,
- SYS_BUS_DEVICE(dev)->mmio[0].memory);
-
- return dev;
-}
diff --git a/qemu/hw/net/fsl_etsec/etsec.h b/qemu/hw/net/fsl_etsec/etsec.h
deleted file mode 100644
index e7dc0a4b9..000000000
--- a/qemu/hw/net/fsl_etsec/etsec.h
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * QEMU Freescale eTSEC Emulator
- *
- * Copyright (c) 2011-2013 AdaCore
- *
- * 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.
- */
-#ifndef _ETSEC_H_
-#define _ETSEC_H_
-
-#include "hw/qdev.h"
-#include "hw/sysbus.h"
-#include "net/net.h"
-#include "hw/ptimer.h"
-
-/* Buffer Descriptors */
-
-typedef struct eTSEC_rxtx_bd {
- uint16_t flags;
- uint16_t length;
- uint32_t bufptr;
-} eTSEC_rxtx_bd;
-
-#define BD_WRAP (1 << 13)
-#define BD_INTERRUPT (1 << 12)
-#define BD_LAST (1 << 11)
-
-#define BD_TX_READY (1 << 15)
-#define BD_TX_PADCRC (1 << 14)
-#define BD_TX_TC (1 << 10)
-#define BD_TX_PREDEF (1 << 9)
-#define BD_TX_HFELC (1 << 7)
-#define BD_TX_CFRL (1 << 6)
-#define BD_TX_RC_MASK 0xF
-#define BD_TX_RC_OFFSET 0x2
-#define BD_TX_TOEUN (1 << 1)
-#define BD_TX_TR (1 << 0)
-
-#define BD_RX_EMPTY (1 << 15)
-#define BD_RX_RO1 (1 << 14)
-#define BD_RX_FIRST (1 << 10)
-#define BD_RX_MISS (1 << 8)
-#define BD_RX_BROADCAST (1 << 7)
-#define BD_RX_MULTICAST (1 << 6)
-#define BD_RX_LG (1 << 5)
-#define BD_RX_NO (1 << 4)
-#define BD_RX_SH (1 << 3)
-#define BD_RX_CR (1 << 2)
-#define BD_RX_OV (1 << 1)
-#define BD_RX_TR (1 << 0)
-
-/* Tx FCB flags */
-#define FCB_TX_VLN (1 << 7)
-#define FCB_TX_IP (1 << 6)
-#define FCB_TX_IP6 (1 << 5)
-#define FCB_TX_TUP (1 << 4)
-#define FCB_TX_UDP (1 << 3)
-#define FCB_TX_CIP (1 << 2)
-#define FCB_TX_CTU (1 << 1)
-#define FCB_TX_NPH (1 << 0)
-
-/* PHY Status Register */
-#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */
-#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */
-#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */
-#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */
-#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */
-#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */
-#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */
-#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */
-#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */
-#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */
-#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */
-#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */
-#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */
-#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */
-#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */
-
-/* eTSEC */
-
-/* Number of register in the device */
-#define ETSEC_REG_NUMBER 1024
-
-typedef struct eTSEC_Register {
- const char *name;
- const char *desc;
- uint32_t access;
- uint32_t value;
-} eTSEC_Register;
-
-typedef struct eTSEC {
- SysBusDevice busdev;
-
- MemoryRegion io_area;
-
- eTSEC_Register regs[ETSEC_REG_NUMBER];
-
- NICState *nic;
- NICConf conf;
-
- /* Tx */
-
- uint8_t *tx_buffer;
- uint32_t tx_buffer_len;
- eTSEC_rxtx_bd first_bd;
-
- /* Rx */
-
- uint8_t *rx_buffer;
- uint32_t rx_buffer_len;
- uint32_t rx_remaining_data;
- uint8_t rx_first_in_frame;
- uint8_t rx_fcb_size;
- eTSEC_rxtx_bd rx_first_bd;
- uint8_t rx_fcb[10];
- uint32_t rx_padding;
-
- /* IRQs */
- qemu_irq tx_irq;
- qemu_irq rx_irq;
- qemu_irq err_irq;
-
-
- uint16_t phy_status;
- uint16_t phy_control;
-
- /* Polling */
- QEMUBH *bh;
- struct ptimer_state *ptimer;
-
- /* Whether we should flush the rx queue when buffer becomes available. */
- bool need_flush;
-} eTSEC;
-
-#define TYPE_ETSEC_COMMON "eTSEC"
-#define ETSEC_COMMON(obj) \
- OBJECT_CHECK(eTSEC, (obj), TYPE_ETSEC_COMMON)
-
-#define eTSEC_TRANSMIT 1
-#define eTSEC_RECEIVE 2
-
-DeviceState *etsec_create(hwaddr base,
- MemoryRegion *mr,
- NICInfo *nd,
- qemu_irq tx_irq,
- qemu_irq rx_irq,
- qemu_irq err_irq);
-
-void etsec_walk_tx_ring(eTSEC *etsec, int ring_nbr);
-void etsec_walk_rx_ring(eTSEC *etsec, int ring_nbr);
-ssize_t etsec_rx_ring_write(eTSEC *etsec, const uint8_t *buf, size_t size);
-
-void etsec_write_miim(eTSEC *etsec,
- eTSEC_Register *reg,
- uint32_t reg_index,
- uint32_t value);
-
-void etsec_miim_link_status(eTSEC *etsec, NetClientState *nc);
-
-#endif /* ! _ETSEC_H_ */
diff --git a/qemu/hw/net/fsl_etsec/miim.c b/qemu/hw/net/fsl_etsec/miim.c
deleted file mode 100644
index 6bba01c82..000000000
--- a/qemu/hw/net/fsl_etsec/miim.c
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * QEMU Freescale eTSEC Emulator
- *
- * Copyright (c) 2011-2013 AdaCore
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "etsec.h"
-#include "registers.h"
-
-/* #define DEBUG_MIIM */
-
-#define MIIM_CONTROL 0
-#define MIIM_STATUS 1
-#define MIIM_PHY_ID_1 2
-#define MIIM_PHY_ID_2 3
-#define MIIM_T2_STATUS 10
-#define MIIM_EXT_STATUS 15
-
-static void miim_read_cycle(eTSEC *etsec)
-{
- uint8_t phy;
- uint8_t addr;
- uint16_t value;
-
- phy = (etsec->regs[MIIMADD].value >> 8) & 0x1F;
- (void)phy; /* Unreferenced */
- addr = etsec->regs[MIIMADD].value & 0x1F;
-
- switch (addr) {
- case MIIM_CONTROL:
- value = etsec->phy_control;
- break;
- case MIIM_STATUS:
- value = etsec->phy_status;
- break;
- case MIIM_T2_STATUS:
- value = 0x1800; /* Local and remote receivers OK */
- break;
- default:
- value = 0x0;
- break;
- };
-
-#ifdef DEBUG_MIIM
- qemu_log("%s phy:%d addr:0x%x value:0x%x\n", __func__, phy, addr, value);
-#endif
-
- etsec->regs[MIIMSTAT].value = value;
-}
-
-static void miim_write_cycle(eTSEC *etsec)
-{
- uint8_t phy;
- uint8_t addr;
- uint16_t value;
-
- phy = (etsec->regs[MIIMADD].value >> 8) & 0x1F;
- (void)phy; /* Unreferenced */
- addr = etsec->regs[MIIMADD].value & 0x1F;
- value = etsec->regs[MIIMCON].value & 0xffff;
-
-#ifdef DEBUG_MIIM
- qemu_log("%s phy:%d addr:0x%x value:0x%x\n", __func__, phy, addr, value);
-#endif
-
- switch (addr) {
- case MIIM_CONTROL:
- etsec->phy_control = value & ~(0x8100);
- break;
- default:
- break;
- };
-}
-
-void etsec_write_miim(eTSEC *etsec,
- eTSEC_Register *reg,
- uint32_t reg_index,
- uint32_t value)
-{
-
- switch (reg_index) {
-
- case MIIMCOM:
- /* Read and scan cycle */
-
- if ((!(reg->value & MIIMCOM_READ)) && (value & MIIMCOM_READ)) {
- /* Read */
- miim_read_cycle(etsec);
- }
- reg->value = value;
- break;
-
- case MIIMCON:
- reg->value = value & 0xffff;
- miim_write_cycle(etsec);
- break;
-
- default:
- /* Default handling */
- switch (reg->access) {
-
- case ACC_RW:
- case ACC_WO:
- reg->value = value;
- break;
-
- case ACC_W1C:
- reg->value &= ~value;
- break;
-
- case ACC_RO:
- default:
- /* Read Only or Unknown register */
- break;
- }
- }
-
-}
-
-void etsec_miim_link_status(eTSEC *etsec, NetClientState *nc)
-{
- /* Set link status */
- if (nc->link_down) {
- etsec->phy_status &= ~MII_SR_LINK_STATUS;
- } else {
- etsec->phy_status |= MII_SR_LINK_STATUS;
- }
-}
diff --git a/qemu/hw/net/fsl_etsec/registers.c b/qemu/hw/net/fsl_etsec/registers.c
deleted file mode 100644
index 46ce7a84b..000000000
--- a/qemu/hw/net/fsl_etsec/registers.c
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
- * QEMU Freescale eTSEC Emulator
- *
- * Copyright (c) 2011-2013 AdaCore
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "registers.h"
-
-const eTSEC_Register_Definition eTSEC_registers_def[] = {
-{0x000, "TSEC_ID", "Controller ID register", ACC_RO, 0x01240000},
-{0x004, "TSEC_ID2", "Controller ID register 2", ACC_RO, 0x003000F0},
-{0x010, "IEVENT", "Interrupt event register", ACC_W1C, 0x00000000},
-{0x014, "IMASK", "Interrupt mask register", ACC_RW, 0x00000000},
-{0x018, "EDIS", "Error disabled register", ACC_RW, 0x00000000},
-{0x020, "ECNTRL", "Ethernet control register", ACC_RW, 0x00000040},
-{0x028, "PTV", "Pause time value register", ACC_RW, 0x00000000},
-{0x02C, "DMACTRL", "DMA control register", ACC_RW, 0x00000000},
-{0x030, "TBIPA", "TBI PHY address register", ACC_RW, 0x00000000},
-
-/* eTSEC FIFO Control and Status Registers */
-
-{0x058, "FIFO_RX_ALARM", "FIFO receive alarm start threshold register", ACC_RW, 0x00000040},
-{0x05C, "FIFO_RX_ALARM_SHUTOFF", "FIFO receive alarm shut-off threshold register", ACC_RW, 0x00000080},
-{0x08C, "FIFO_TX_THR", "FIFO transmit threshold register", ACC_RW, 0x00000080},
-{0x098, "FIFO_TX_STARVE", "FIFO transmit starve register", ACC_RW, 0x00000040},
-{0x09C, "FIFO_TX_STARVE_SHUTOFF", "FIFO transmit starve shut-off register", ACC_RW, 0x00000080},
-
-/* eTSEC Transmit Control and Status Registers */
-
-{0x100, "TCTRL", "Transmit control register", ACC_RW, 0x00000000},
-{0x104, "TSTAT", "Transmit status register", ACC_W1C, 0x00000000},
-{0x108, "DFVLAN", "Default VLAN control word", ACC_RW, 0x81000000},
-{0x110, "TXIC", "Transmit interrupt coalescing register", ACC_RW, 0x00000000},
-{0x114, "TQUEUE", "Transmit queue control register", ACC_RW, 0x00008000},
-{0x140, "TR03WT", "TxBD Rings 0-3 round-robin weightings", ACC_RW, 0x00000000},
-{0x144, "TR47WT", "TxBD Rings 4-7 round-robin weightings", ACC_RW, 0x00000000},
-{0x180, "TBDBPH", "Tx data buffer pointer high bits", ACC_RW, 0x00000000},
-{0x184, "TBPTR0", "TxBD pointer for ring 0", ACC_RW, 0x00000000},
-{0x18C, "TBPTR1", "TxBD pointer for ring 1", ACC_RW, 0x00000000},
-{0x194, "TBPTR2", "TxBD pointer for ring 2", ACC_RW, 0x00000000},
-{0x19C, "TBPTR3", "TxBD pointer for ring 3", ACC_RW, 0x00000000},
-{0x1A4, "TBPTR4", "TxBD pointer for ring 4", ACC_RW, 0x00000000},
-{0x1AC, "TBPTR5", "TxBD pointer for ring 5", ACC_RW, 0x00000000},
-{0x1B4, "TBPTR6", "TxBD pointer for ring 6", ACC_RW, 0x00000000},
-{0x1BC, "TBPTR7", "TxBD pointer for ring 7", ACC_RW, 0x00000000},
-{0x200, "TBASEH", "TxBD base address high bits", ACC_RW, 0x00000000},
-{0x204, "TBASE0", "TxBD base address of ring 0", ACC_RW, 0x00000000},
-{0x20C, "TBASE1", "TxBD base address of ring 1", ACC_RW, 0x00000000},
-{0x214, "TBASE2", "TxBD base address of ring 2", ACC_RW, 0x00000000},
-{0x21C, "TBASE3", "TxBD base address of ring 3", ACC_RW, 0x00000000},
-{0x224, "TBASE4", "TxBD base address of ring 4", ACC_RW, 0x00000000},
-{0x22C, "TBASE5", "TxBD base address of ring 5", ACC_RW, 0x00000000},
-{0x234, "TBASE6", "TxBD base address of ring 6", ACC_RW, 0x00000000},
-{0x23C, "TBASE7", "TxBD base address of ring 7", ACC_RW, 0x00000000},
-{0x280, "TMR_TXTS1_ID", "Tx time stamp identification tag (set 1)", ACC_RO, 0x00000000},
-{0x284, "TMR_TXTS2_ID", "Tx time stamp identification tag (set 2)", ACC_RO, 0x00000000},
-{0x2C0, "TMR_TXTS1_H", "Tx time stamp high (set 1)", ACC_RO, 0x00000000},
-{0x2C4, "TMR_TXTS1_L", "Tx time stamp high (set 1)", ACC_RO, 0x00000000},
-{0x2C8, "TMR_TXTS2_H", "Tx time stamp high (set 2)", ACC_RO, 0x00000000},
-{0x2CC, "TMR_TXTS2_L", "Tx time stamp high (set 2)", ACC_RO, 0x00000000},
-
-/* eTSEC Receive Control and Status Registers */
-
-{0x300, "RCTRL", "Receive control register", ACC_RW, 0x00000000},
-{0x304, "RSTAT", "Receive status register", ACC_W1C, 0x00000000},
-{0x310, "RXIC", "Receive interrupt coalescing register", ACC_RW, 0x00000000},
-{0x314, "RQUEUE", "Receive queue control register.", ACC_RW, 0x00800080},
-{0x330, "RBIFX", "Receive bit field extract control register", ACC_RW, 0x00000000},
-{0x334, "RQFAR", "Receive queue filing table address register", ACC_RW, 0x00000000},
-{0x338, "RQFCR", "Receive queue filing table control register", ACC_RW, 0x00000000},
-{0x33C, "RQFPR", "Receive queue filing table property register", ACC_RW, 0x00000000},
-{0x340, "MRBLR", "Maximum receive buffer length register", ACC_RW, 0x00000000},
-{0x380, "RBDBPH", "Rx data buffer pointer high bits", ACC_RW, 0x00000000},
-{0x384, "RBPTR0", "RxBD pointer for ring 0", ACC_RW, 0x00000000},
-{0x38C, "RBPTR1", "RxBD pointer for ring 1", ACC_RW, 0x00000000},
-{0x394, "RBPTR2", "RxBD pointer for ring 2", ACC_RW, 0x00000000},
-{0x39C, "RBPTR3", "RxBD pointer for ring 3", ACC_RW, 0x00000000},
-{0x3A4, "RBPTR4", "RxBD pointer for ring 4", ACC_RW, 0x00000000},
-{0x3AC, "RBPTR5", "RxBD pointer for ring 5", ACC_RW, 0x00000000},
-{0x3B4, "RBPTR6", "RxBD pointer for ring 6", ACC_RW, 0x00000000},
-{0x3BC, "RBPTR7", "RxBD pointer for ring 7", ACC_RW, 0x00000000},
-{0x400, "RBASEH", "RxBD base address high bits", ACC_RW, 0x00000000},
-{0x404, "RBASE0", "RxBD base address of ring 0", ACC_RW, 0x00000000},
-{0x40C, "RBASE1", "RxBD base address of ring 1", ACC_RW, 0x00000000},
-{0x414, "RBASE2", "RxBD base address of ring 2", ACC_RW, 0x00000000},
-{0x41C, "RBASE3", "RxBD base address of ring 3", ACC_RW, 0x00000000},
-{0x424, "RBASE4", "RxBD base address of ring 4", ACC_RW, 0x00000000},
-{0x42C, "RBASE5", "RxBD base address of ring 5", ACC_RW, 0x00000000},
-{0x434, "RBASE6", "RxBD base address of ring 6", ACC_RW, 0x00000000},
-{0x43C, "RBASE7", "RxBD base address of ring 7", ACC_RW, 0x00000000},
-{0x4C0, "TMR_RXTS_H", "Rx timer time stamp register high", ACC_RW, 0x00000000},
-{0x4C4, "TMR_RXTS_L", "Rx timer time stamp register low", ACC_RW, 0x00000000},
-
-/* eTSEC MAC Registers */
-
-{0x500, "MACCFG1", "MAC configuration register 1", ACC_RW, 0x00000000},
-{0x504, "MACCFG2", "MAC configuration register 2", ACC_RW, 0x00007000},
-{0x508, "IPGIFG", "Inter-packet/inter-frame gap register", ACC_RW, 0x40605060},
-{0x50C, "HAFDUP", "Half-duplex control", ACC_RW, 0x00A1F037},
-{0x510, "MAXFRM", "Maximum frame length", ACC_RW, 0x00000600},
-{0x520, "MIIMCFG", "MII management configuration", ACC_RW, 0x00000007},
-{0x524, "MIIMCOM", "MII management command", ACC_RW, 0x00000000},
-{0x528, "MIIMADD", "MII management address", ACC_RW, 0x00000000},
-{0x52C, "MIIMCON", "MII management control", ACC_WO, 0x00000000},
-{0x530, "MIIMSTAT", "MII management status", ACC_RO, 0x00000000},
-{0x534, "MIIMIND", "MII management indicator", ACC_RO, 0x00000000},
-{0x53C, "IFSTAT", "Interface status", ACC_RO, 0x00000000},
-{0x540, "MACSTNADDR1", "MAC station address register 1", ACC_RW, 0x00000000},
-{0x544, "MACSTNADDR2", "MAC station address register 2", ACC_RW, 0x00000000},
-{0x548, "MAC01ADDR1", "MAC exact match address 1, part 1", ACC_RW, 0x00000000},
-{0x54C, "MAC01ADDR2", "MAC exact match address 1, part 2", ACC_RW, 0x00000000},
-{0x550, "MAC02ADDR1", "MAC exact match address 2, part 1", ACC_RW, 0x00000000},
-{0x554, "MAC02ADDR2", "MAC exact match address 2, part 2", ACC_RW, 0x00000000},
-{0x558, "MAC03ADDR1", "MAC exact match address 3, part 1", ACC_RW, 0x00000000},
-{0x55C, "MAC03ADDR2", "MAC exact match address 3, part 2", ACC_RW, 0x00000000},
-{0x560, "MAC04ADDR1", "MAC exact match address 4, part 1", ACC_RW, 0x00000000},
-{0x564, "MAC04ADDR2", "MAC exact match address 4, part 2", ACC_RW, 0x00000000},
-{0x568, "MAC05ADDR1", "MAC exact match address 5, part 1", ACC_RW, 0x00000000},
-{0x56C, "MAC05ADDR2", "MAC exact match address 5, part 2", ACC_RW, 0x00000000},
-{0x570, "MAC06ADDR1", "MAC exact match address 6, part 1", ACC_RW, 0x00000000},
-{0x574, "MAC06ADDR2", "MAC exact match address 6, part 2", ACC_RW, 0x00000000},
-{0x578, "MAC07ADDR1", "MAC exact match address 7, part 1", ACC_RW, 0x00000000},
-{0x57C, "MAC07ADDR2", "MAC exact match address 7, part 2", ACC_RW, 0x00000000},
-{0x580, "MAC08ADDR1", "MAC exact match address 8, part 1", ACC_RW, 0x00000000},
-{0x584, "MAC08ADDR2", "MAC exact match address 8, part 2", ACC_RW, 0x00000000},
-{0x588, "MAC09ADDR1", "MAC exact match address 9, part 1", ACC_RW, 0x00000000},
-{0x58C, "MAC09ADDR2", "MAC exact match address 9, part 2", ACC_RW, 0x00000000},
-{0x590, "MAC10ADDR1", "MAC exact match address 10, part 1", ACC_RW, 0x00000000},
-{0x594, "MAC10ADDR2", "MAC exact match address 10, part 2", ACC_RW, 0x00000000},
-{0x598, "MAC11ADDR1", "MAC exact match address 11, part 1", ACC_RW, 0x00000000},
-{0x59C, "MAC11ADDR2", "MAC exact match address 11, part 2", ACC_RW, 0x00000000},
-{0x5A0, "MAC12ADDR1", "MAC exact match address 12, part 1", ACC_RW, 0x00000000},
-{0x5A4, "MAC12ADDR2", "MAC exact match address 12, part 2", ACC_RW, 0x00000000},
-{0x5A8, "MAC13ADDR1", "MAC exact match address 13, part 1", ACC_RW, 0x00000000},
-{0x5AC, "MAC13ADDR2", "MAC exact match address 13, part 2", ACC_RW, 0x00000000},
-{0x5B0, "MAC14ADDR1", "MAC exact match address 14, part 1", ACC_RW, 0x00000000},
-{0x5B4, "MAC14ADDR2", "MAC exact match address 14, part 2", ACC_RW, 0x00000000},
-{0x5B8, "MAC15ADDR1", "MAC exact match address 15, part 1", ACC_RW, 0x00000000},
-{0x5BC, "MAC15ADDR2", "MAC exact match address 15, part 2", ACC_RW, 0x00000000},
-
-/* eTSEC, "Transmit", "and", Receive, Counters */
-
-{0x680, "TR64", "Transmit and receive 64-byte frame counter ", ACC_RW, 0x00000000},
-{0x684, "TR127", "Transmit and receive 65- to 127-byte frame counter", ACC_RW, 0x00000000},
-{0x688, "TR255", "Transmit and receive 128- to 255-byte frame counter", ACC_RW, 0x00000000},
-{0x68C, "TR511", "Transmit and receive 256- to 511-byte frame counter", ACC_RW, 0x00000000},
-{0x690, "TR1K", "Transmit and receive 512- to 1023-byte frame counter", ACC_RW, 0x00000000},
-{0x694, "TRMAX", "Transmit and receive 1024- to 1518-byte frame counter", ACC_RW, 0x00000000},
-{0x698, "TRMGV", "Transmit and receive 1519- to 1522-byte good VLAN frame count", ACC_RW, 0x00000000},
-
-/* eTSEC Receive Counters */
-
-{0x69C, "RBYT", "Receive byte counter", ACC_RW, 0x00000000},
-{0x6A0, "RPKT", "Receive packet counter", ACC_RW, 0x00000000},
-{0x6A4, "RFCS", "Receive FCS error counter", ACC_RW, 0x00000000},
-{0x6A8, "RMCA", "Receive multicast packet counter", ACC_RW, 0x00000000},
-{0x6AC, "RBCA", "Receive broadcast packet counter", ACC_RW, 0x00000000},
-{0x6B0, "RXCF", "Receive control frame packet counter ", ACC_RW, 0x00000000},
-{0x6B4, "RXPF", "Receive PAUSE frame packet counter", ACC_RW, 0x00000000},
-{0x6B8, "RXUO", "Receive unknown OP code counter ", ACC_RW, 0x00000000},
-{0x6BC, "RALN", "Receive alignment error counter ", ACC_RW, 0x00000000},
-{0x6C0, "RFLR", "Receive frame length error counter ", ACC_RW, 0x00000000},
-{0x6C4, "RCDE", "Receive code error counter ", ACC_RW, 0x00000000},
-{0x6C8, "RCSE", "Receive carrier sense error counter", ACC_RW, 0x00000000},
-{0x6CC, "RUND", "Receive undersize packet counter", ACC_RW, 0x00000000},
-{0x6D0, "ROVR", "Receive oversize packet counter ", ACC_RW, 0x00000000},
-{0x6D4, "RFRG", "Receive fragments counter", ACC_RW, 0x00000000},
-{0x6D8, "RJBR", "Receive jabber counter ", ACC_RW, 0x00000000},
-{0x6DC, "RDRP", "Receive drop counter", ACC_RW, 0x00000000},
-
-/* eTSEC Transmit Counters */
-
-{0x6E0, "TBYT", "Transmit byte counter", ACC_RW, 0x00000000},
-{0x6E4, "TPKT", "Transmit packet counter", ACC_RW, 0x00000000},
-{0x6E8, "TMCA", "Transmit multicast packet counter ", ACC_RW, 0x00000000},
-{0x6EC, "TBCA", "Transmit broadcast packet counter ", ACC_RW, 0x00000000},
-{0x6F0, "TXPF", "Transmit PAUSE control frame counter ", ACC_RW, 0x00000000},
-{0x6F4, "TDFR", "Transmit deferral packet counter ", ACC_RW, 0x00000000},
-{0x6F8, "TEDF", "Transmit excessive deferral packet counter ", ACC_RW, 0x00000000},
-{0x6FC, "TSCL", "Transmit single collision packet counter", ACC_RW, 0x00000000},
-{0x700, "TMCL", "Transmit multiple collision packet counter", ACC_RW, 0x00000000},
-{0x704, "TLCL", "Transmit late collision packet counter", ACC_RW, 0x00000000},
-{0x708, "TXCL", "Transmit excessive collision packet counter", ACC_RW, 0x00000000},
-{0x70C, "TNCL", "Transmit total collision counter ", ACC_RW, 0x00000000},
-{0x714, "TDRP", "Transmit drop frame counter", ACC_RW, 0x00000000},
-{0x718, "TJBR", "Transmit jabber frame counter ", ACC_RW, 0x00000000},
-{0x71C, "TFCS", "Transmit FCS error counter", ACC_RW, 0x00000000},
-{0x720, "TXCF", "Transmit control frame counter ", ACC_RW, 0x00000000},
-{0x724, "TOVR", "Transmit oversize frame counter", ACC_RW, 0x00000000},
-{0x728, "TUND", "Transmit undersize frame counter ", ACC_RW, 0x00000000},
-{0x72C, "TFRG", "Transmit fragments frame counter ", ACC_RW, 0x00000000},
-
-/* eTSEC Counter Control and TOE Statistics Registers */
-
-{0x730, "CAR1", "Carry register one register", ACC_W1C, 0x00000000},
-{0x734, "CAR2", "Carry register two register ", ACC_W1C, 0x00000000},
-{0x738, "CAM1", "Carry register one mask register ", ACC_RW, 0xFE03FFFF},
-{0x73C, "CAM2", "Carry register two mask register ", ACC_RW, 0x000FFFFD},
-{0x740, "RREJ", "Receive filer rejected packet counter", ACC_RW, 0x00000000},
-
-/* Hash Function Registers */
-
-{0x800, "IGADDR0", "Individual/group address register 0", ACC_RW, 0x00000000},
-{0x804, "IGADDR1", "Individual/group address register 1", ACC_RW, 0x00000000},
-{0x808, "IGADDR2", "Individual/group address register 2", ACC_RW, 0x00000000},
-{0x80C, "IGADDR3", "Individual/group address register 3", ACC_RW, 0x00000000},
-{0x810, "IGADDR4", "Individual/group address register 4", ACC_RW, 0x00000000},
-{0x814, "IGADDR5", "Individual/group address register 5", ACC_RW, 0x00000000},
-{0x818, "IGADDR6", "Individual/group address register 6", ACC_RW, 0x00000000},
-{0x81C, "IGADDR7", "Individual/group address register 7", ACC_RW, 0x00000000},
-{0x880, "GADDR0", "Group address register 0", ACC_RW, 0x00000000},
-{0x884, "GADDR1", "Group address register 1", ACC_RW, 0x00000000},
-{0x888, "GADDR2", "Group address register 2", ACC_RW, 0x00000000},
-{0x88C, "GADDR3", "Group address register 3", ACC_RW, 0x00000000},
-{0x890, "GADDR4", "Group address register 4", ACC_RW, 0x00000000},
-{0x894, "GADDR5", "Group address register 5", ACC_RW, 0x00000000},
-{0x898, "GADDR6", "Group address register 6", ACC_RW, 0x00000000},
-{0x89C, "GADDR7", "Group address register 7", ACC_RW, 0x00000000},
-
-/* eTSEC DMA Attribute Registers */
-
-{0xBF8, "ATTR", "Attribute register", ACC_RW, 0x00000000},
-{0xBFC, "ATTRELI", "Attribute extract length and extract index register", ACC_RW, 0x00000000},
-
-
-/* eTSEC Lossless Flow Control Registers */
-
-{0xC00, "RQPRM0", "Receive Queue Parameters register 0 ", ACC_RW, 0x00000000},
-{0xC04, "RQPRM1", "Receive Queue Parameters register 1 ", ACC_RW, 0x00000000},
-{0xC08, "RQPRM2", "Receive Queue Parameters register 2 ", ACC_RW, 0x00000000},
-{0xC0C, "RQPRM3", "Receive Queue Parameters register 3 ", ACC_RW, 0x00000000},
-{0xC10, "RQPRM4", "Receive Queue Parameters register 4 ", ACC_RW, 0x00000000},
-{0xC14, "RQPRM5", "Receive Queue Parameters register 5 ", ACC_RW, 0x00000000},
-{0xC18, "RQPRM6", "Receive Queue Parameters register 6 ", ACC_RW, 0x00000000},
-{0xC1C, "RQPRM7", "Receive Queue Parameters register 7 ", ACC_RW, 0x00000000},
-{0xC44, "RFBPTR0", "Last Free RxBD pointer for ring 0", ACC_RW, 0x00000000},
-{0xC4C, "RFBPTR1", "Last Free RxBD pointer for ring 1", ACC_RW, 0x00000000},
-{0xC54, "RFBPTR2", "Last Free RxBD pointer for ring 2", ACC_RW, 0x00000000},
-{0xC5C, "RFBPTR3", "Last Free RxBD pointer for ring 3", ACC_RW, 0x00000000},
-{0xC64, "RFBPTR4", "Last Free RxBD pointer for ring 4", ACC_RW, 0x00000000},
-{0xC6C, "RFBPTR5", "Last Free RxBD pointer for ring 5", ACC_RW, 0x00000000},
-{0xC74, "RFBPTR6", "Last Free RxBD pointer for ring 6", ACC_RW, 0x00000000},
-{0xC7C, "RFBPTR7", "Last Free RxBD pointer for ring 7", ACC_RW, 0x00000000},
-
-/* eTSEC Future Expansion Space */
-
-/* Reserved*/
-
-/* eTSEC IEEE 1588 Registers */
-
-{0xE00, "TMR_CTRL", "Timer control register", ACC_RW, 0x00010001},
-{0xE04, "TMR_TEVENT", "time stamp event register", ACC_W1C, 0x00000000},
-{0xE08, "TMR_TEMASK", "Timer event mask register", ACC_RW, 0x00000000},
-{0xE0C, "TMR_PEVENT", "time stamp event register", ACC_RW, 0x00000000},
-{0xE10, "TMR_PEMASK", "Timer event mask register", ACC_RW, 0x00000000},
-{0xE14, "TMR_STAT", "time stamp status register", ACC_RW, 0x00000000},
-{0xE18, "TMR_CNT_H", "timer counter high register", ACC_RW, 0x00000000},
-{0xE1C, "TMR_CNT_L", "timer counter low register", ACC_RW, 0x00000000},
-{0xE20, "TMR_ADD", "Timer drift compensation addend register", ACC_RW, 0x00000000},
-{0xE24, "TMR_ACC", "Timer accumulator register", ACC_RW, 0x00000000},
-{0xE28, "TMR_PRSC", "Timer prescale", ACC_RW, 0x00000002},
-{0xE30, "TMROFF_H", "Timer offset high", ACC_RW, 0x00000000},
-{0xE34, "TMROFF_L", "Timer offset low", ACC_RW, 0x00000000},
-{0xE40, "TMR_ALARM1_H", "Timer alarm 1 high register", ACC_RW, 0xFFFFFFFF},
-{0xE44, "TMR_ALARM1_L", "Timer alarm 1 high register", ACC_RW, 0xFFFFFFFF},
-{0xE48, "TMR_ALARM2_H", "Timer alarm 2 high register", ACC_RW, 0xFFFFFFFF},
-{0xE4C, "TMR_ALARM2_L", "Timer alarm 2 high register", ACC_RW, 0xFFFFFFFF},
-{0xE80, "TMR_FIPER1", "Timer fixed period interval", ACC_RW, 0xFFFFFFFF},
-{0xE84, "TMR_FIPER2", "Timer fixed period interval", ACC_RW, 0xFFFFFFFF},
-{0xE88, "TMR_FIPER3", "Timer fixed period interval", ACC_RW, 0xFFFFFFFF},
-{0xEA0, "TMR_ETTS1_H", "Time stamp of general purpose external trigger ", ACC_RW, 0x00000000},
-{0xEA4, "TMR_ETTS1_L", "Time stamp of general purpose external trigger", ACC_RW, 0x00000000},
-{0xEA8, "TMR_ETTS2_H", "Time stamp of general purpose external trigger ", ACC_RW, 0x00000000},
-{0xEAC, "TMR_ETTS2_L", "Time stamp of general purpose external trigger", ACC_RW, 0x00000000},
-
-/* End Of Table */
-{0x0, 0x0, 0x0, 0x0, 0x0}
-};
diff --git a/qemu/hw/net/fsl_etsec/registers.h b/qemu/hw/net/fsl_etsec/registers.h
deleted file mode 100644
index 6fb96842b..000000000
--- a/qemu/hw/net/fsl_etsec/registers.h
+++ /dev/null
@@ -1,319 +0,0 @@
-/*
- * QEMU Freescale eTSEC Emulator
- *
- * Copyright (c) 2011-2013 AdaCore
- *
- * 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.
- */
-#ifndef _ETSEC_REGISTERS_H_
-#define _ETSEC_REGISTERS_H_
-
-
-enum eTSEC_Register_Access_Type {
- ACC_RW = 1, /* Read/Write */
- ACC_RO = 2, /* Read Only */
- ACC_WO = 3, /* Write Only */
- ACC_W1C = 4, /* Write 1 to clear */
- ACC_UNKNOWN = 5 /* Unknown register*/
-};
-
-typedef struct eTSEC_Register_Definition {
- uint32_t offset;
- const char *name;
- const char *desc;
- enum eTSEC_Register_Access_Type access;
- uint32_t reset;
-} eTSEC_Register_Definition;
-
-extern const eTSEC_Register_Definition eTSEC_registers_def[];
-
-#define DMACTRL_LE (1 << 15)
-#define DMACTRL_GRS (1 << 4)
-#define DMACTRL_GTS (1 << 3)
-#define DMACTRL_WOP (1 << 0)
-
-#define IEVENT_PERR (1 << 0)
-#define IEVENT_DPE (1 << 1)
-#define IEVENT_FIQ (1 << 2)
-#define IEVENT_FIR (1 << 3)
-#define IEVENT_FGPI (1 << 4)
-#define IEVENT_RXF (1 << 7)
-#define IEVENT_GRSC (1 << 8)
-#define IEVENT_MMRW (1 << 9)
-#define IEVENT_MMRD (1 << 10)
-#define IEVENT_MAG (1 << 11)
-#define IEVENT_RXB (1 << 15)
-#define IEVENT_XFUN (1 << 16)
-#define IEVENT_CRL (1 << 17)
-#define IEVENT_LC (1 << 18)
-#define IEVENT_TXF (1 << 20)
-#define IEVENT_TXB (1 << 21)
-#define IEVENT_TXE (1 << 22)
-#define IEVENT_TXC (1 << 23)
-#define IEVENT_BABT (1 << 24)
-#define IEVENT_GTSC (1 << 25)
-#define IEVENT_MSRO (1 << 26)
-#define IEVENT_EBERR (1 << 28)
-#define IEVENT_BSY (1 << 29)
-#define IEVENT_RXC (1 << 30)
-#define IEVENT_BABR (1 << 31)
-
-#define IMASK_RXFEN (1 << 7)
-#define IMASK_GRSCEN (1 << 8)
-#define IMASK_RXBEN (1 << 15)
-#define IMASK_TXFEN (1 << 20)
-#define IMASK_TXBEN (1 << 21)
-#define IMASK_GTSCEN (1 << 25)
-
-#define MACCFG1_TX_EN (1 << 0)
-#define MACCFG1_RX_EN (1 << 2)
-
-#define MACCFG2_CRC_EN (1 << 1)
-#define MACCFG2_PADCRC (1 << 2)
-
-#define MIIMCOM_READ (1 << 0)
-#define MIIMCOM_SCAN (1 << 1)
-
-#define RCTRL_PRSDEP_MASK (0x3)
-#define RCTRL_PRSDEP_OFFSET (6)
-#define RCTRL_RSF (1 << 2)
-
-/* Index of each register */
-
-#define TSEC_ID (0x000 / 4)
-#define TSEC_ID2 (0x004 / 4)
-#define IEVENT (0x010 / 4)
-#define IMASK (0x014 / 4)
-#define EDIS (0x018 / 4)
-#define ECNTRL (0x020 / 4)
-#define PTV (0x028 / 4)
-#define DMACTRL (0x02C / 4)
-#define TBIPA (0x030 / 4)
-#define TCTRL (0x100 / 4)
-#define TSTAT (0x104 / 4)
-#define DFVLAN (0x108 / 4)
-#define TXIC (0x110 / 4)
-#define TQUEUE (0x114 / 4)
-#define TR03WT (0x140 / 4)
-#define TR47WT (0x144 / 4)
-#define TBDBPH (0x180 / 4)
-#define TBPTR0 (0x184 / 4)
-#define TBPTR1 (0x18C / 4)
-#define TBPTR2 (0x194 / 4)
-#define TBPTR3 (0x19C / 4)
-#define TBPTR4 (0x1A4 / 4)
-#define TBPTR5 (0x1AC / 4)
-#define TBPTR6 (0x1B4 / 4)
-#define TBPTR7 (0x1BC / 4)
-#define TBASEH (0x200 / 4)
-#define TBASE0 (0x204 / 4)
-#define TBASE1 (0x20C / 4)
-#define TBASE2 (0x214 / 4)
-#define TBASE3 (0x21C / 4)
-#define TBASE4 (0x224 / 4)
-#define TBASE5 (0x22C / 4)
-#define TBASE6 (0x234 / 4)
-#define TBASE7 (0x23C / 4)
-#define TMR_TXTS1_ID (0x280 / 4)
-#define TMR_TXTS2_ID (0x284 / 4)
-#define TMR_TXTS1_H (0x2C0 / 4)
-#define TMR_TXTS1_L (0x2C4 / 4)
-#define TMR_TXTS2_H (0x2C8 / 4)
-#define TMR_TXTS2_L (0x2CC / 4)
-#define RCTRL (0x300 / 4)
-#define RSTAT (0x304 / 4)
-#define RXIC (0x310 / 4)
-#define RQUEUE (0x314 / 4)
-#define RBIFX (0x330 / 4)
-#define RQFAR (0x334 / 4)
-#define RQFCR (0x338 / 4)
-#define RQFPR (0x33C / 4)
-#define MRBLR (0x340 / 4)
-#define RBDBPH (0x380 / 4)
-#define RBPTR0 (0x384 / 4)
-#define RBPTR1 (0x38C / 4)
-#define RBPTR2 (0x394 / 4)
-#define RBPTR3 (0x39C / 4)
-#define RBPTR4 (0x3A4 / 4)
-#define RBPTR5 (0x3AC / 4)
-#define RBPTR6 (0x3B4 / 4)
-#define RBPTR7 (0x3BC / 4)
-#define RBASEH (0x400 / 4)
-#define RBASE0 (0x404 / 4)
-#define RBASE1 (0x40C / 4)
-#define RBASE2 (0x414 / 4)
-#define RBASE3 (0x41C / 4)
-#define RBASE4 (0x424 / 4)
-#define RBASE5 (0x42C / 4)
-#define RBASE6 (0x434 / 4)
-#define RBASE7 (0x43C / 4)
-#define TMR_RXTS_H (0x4C0 / 4)
-#define TMR_RXTS_L (0x4C4 / 4)
-#define MACCFG1 (0x500 / 4)
-#define MACCFG2 (0x504 / 4)
-#define IPGIFG (0x508 / 4)
-#define HAFDUP (0x50C / 4)
-#define MAXFRM (0x510 / 4)
-#define MIIMCFG (0x520 / 4)
-#define MIIMCOM (0x524 / 4)
-#define MIIMADD (0x528 / 4)
-#define MIIMCON (0x52C / 4)
-#define MIIMSTAT (0x530 / 4)
-#define MIIMIND (0x534 / 4)
-#define IFSTAT (0x53C / 4)
-#define MACSTNADDR1 (0x540 / 4)
-#define MACSTNADDR2 (0x544 / 4)
-#define MAC01ADDR1 (0x548 / 4)
-#define MAC01ADDR2 (0x54C / 4)
-#define MAC02ADDR1 (0x550 / 4)
-#define MAC02ADDR2 (0x554 / 4)
-#define MAC03ADDR1 (0x558 / 4)
-#define MAC03ADDR2 (0x55C / 4)
-#define MAC04ADDR1 (0x560 / 4)
-#define MAC04ADDR2 (0x564 / 4)
-#define MAC05ADDR1 (0x568 / 4)
-#define MAC05ADDR2 (0x56C / 4)
-#define MAC06ADDR1 (0x570 / 4)
-#define MAC06ADDR2 (0x574 / 4)
-#define MAC07ADDR1 (0x578 / 4)
-#define MAC07ADDR2 (0x57C / 4)
-#define MAC08ADDR1 (0x580 / 4)
-#define MAC08ADDR2 (0x584 / 4)
-#define MAC09ADDR1 (0x588 / 4)
-#define MAC09ADDR2 (0x58C / 4)
-#define MAC10ADDR1 (0x590 / 4)
-#define MAC10ADDR2 (0x594 / 4)
-#define MAC11ADDR1 (0x598 / 4)
-#define MAC11ADDR2 (0x59C / 4)
-#define MAC12ADDR1 (0x5A0 / 4)
-#define MAC12ADDR2 (0x5A4 / 4)
-#define MAC13ADDR1 (0x5A8 / 4)
-#define MAC13ADDR2 (0x5AC / 4)
-#define MAC14ADDR1 (0x5B0 / 4)
-#define MAC14ADDR2 (0x5B4 / 4)
-#define MAC15ADDR1 (0x5B8 / 4)
-#define MAC15ADDR2 (0x5BC / 4)
-#define TR64 (0x680 / 4)
-#define TR127 (0x684 / 4)
-#define TR255 (0x688 / 4)
-#define TR511 (0x68C / 4)
-#define TR1K (0x690 / 4)
-#define TRMAX (0x694 / 4)
-#define TRMGV (0x698 / 4)
-#define RBYT (0x69C / 4)
-#define RPKT (0x6A0 / 4)
-#define RFCS (0x6A4 / 4)
-#define RMCA (0x6A8 / 4)
-#define RBCA (0x6AC / 4)
-#define RXCF (0x6B0 / 4)
-#define RXPF (0x6B4 / 4)
-#define RXUO (0x6B8 / 4)
-#define RALN (0x6BC / 4)
-#define RFLR (0x6C0 / 4)
-#define RCDE (0x6C4 / 4)
-#define RCSE (0x6C8 / 4)
-#define RUND (0x6CC / 4)
-#define ROVR (0x6D0 / 4)
-#define RFRG (0x6D4 / 4)
-#define RJBR (0x6D8 / 4)
-#define RDRP (0x6DC / 4)
-#define TBYT (0x6E0 / 4)
-#define TPKT (0x6E4 / 4)
-#define TMCA (0x6E8 / 4)
-#define TBCA (0x6EC / 4)
-#define TXPF (0x6F0 / 4)
-#define TDFR (0x6F4 / 4)
-#define TEDF (0x6F8 / 4)
-#define TSCL (0x6FC / 4)
-#define TMCL (0x700 / 4)
-#define TLCL (0x704 / 4)
-#define TXCL (0x708 / 4)
-#define TNCL (0x70C / 4)
-#define TDRP (0x714 / 4)
-#define TJBR (0x718 / 4)
-#define TFCS (0x71C / 4)
-#define TXCF (0x720 / 4)
-#define TOVR (0x724 / 4)
-#define TUND (0x728 / 4)
-#define TFRG (0x72C / 4)
-#define CAR1 (0x730 / 4)
-#define CAR2 (0x734 / 4)
-#define CAM1 (0x738 / 4)
-#define CAM2 (0x73C / 4)
-#define RREJ (0x740 / 4)
-#define IGADDR0 (0x800 / 4)
-#define IGADDR1 (0x804 / 4)
-#define IGADDR2 (0x808 / 4)
-#define IGADDR3 (0x80C / 4)
-#define IGADDR4 (0x810 / 4)
-#define IGADDR5 (0x814 / 4)
-#define IGADDR6 (0x818 / 4)
-#define IGADDR7 (0x81C / 4)
-#define GADDR0 (0x880 / 4)
-#define GADDR1 (0x884 / 4)
-#define GADDR2 (0x888 / 4)
-#define GADDR3 (0x88C / 4)
-#define GADDR4 (0x890 / 4)
-#define GADDR5 (0x894 / 4)
-#define GADDR6 (0x898 / 4)
-#define GADDR7 (0x89C / 4)
-#define ATTR (0xBF8 / 4)
-#define ATTRELI (0xBFC / 4)
-#define RQPRM0 (0xC00 / 4)
-#define RQPRM1 (0xC04 / 4)
-#define RQPRM2 (0xC08 / 4)
-#define RQPRM3 (0xC0C / 4)
-#define RQPRM4 (0xC10 / 4)
-#define RQPRM5 (0xC14 / 4)
-#define RQPRM6 (0xC18 / 4)
-#define RQPRM7 (0xC1C / 4)
-#define RFBPTR0 (0xC44 / 4)
-#define RFBPTR1 (0xC4C / 4)
-#define RFBPTR2 (0xC54 / 4)
-#define RFBPTR3 (0xC5C / 4)
-#define RFBPTR4 (0xC64 / 4)
-#define RFBPTR5 (0xC6C / 4)
-#define RFBPTR6 (0xC74 / 4)
-#define RFBPTR7 (0xC7C / 4)
-#define TMR_CTRL (0xE00 / 4)
-#define TMR_TEVENT (0xE04 / 4)
-#define TMR_TEMASK (0xE08 / 4)
-#define TMR_PEVENT (0xE0C / 4)
-#define TMR_PEMASK (0xE10 / 4)
-#define TMR_STAT (0xE14 / 4)
-#define TMR_CNT_H (0xE18 / 4)
-#define TMR_CNT_L (0xE1C / 4)
-#define TMR_ADD (0xE20 / 4)
-#define TMR_ACC (0xE24 / 4)
-#define TMR_PRSC (0xE28 / 4)
-#define TMROFF_H (0xE30 / 4)
-#define TMROFF_L (0xE34 / 4)
-#define TMR_ALARM1_H (0xE40 / 4)
-#define TMR_ALARM1_L (0xE44 / 4)
-#define TMR_ALARM2_H (0xE48 / 4)
-#define TMR_ALARM2_L (0xE4C / 4)
-#define TMR_FIPER1 (0xE80 / 4)
-#define TMR_FIPER2 (0xE84 / 4)
-#define TMR_FIPER3 (0xE88 / 4)
-#define TMR_ETTS1_H (0xEA0 / 4)
-#define TMR_ETTS1_L (0xEA4 / 4)
-#define TMR_ETTS2_H (0xEA8 / 4)
-#define TMR_ETTS2_L (0xEAC / 4)
-
-#endif /* ! _ETSEC_REGISTERS_H_ */
diff --git a/qemu/hw/net/fsl_etsec/rings.c b/qemu/hw/net/fsl_etsec/rings.c
deleted file mode 100644
index ed1de7da9..000000000
--- a/qemu/hw/net/fsl_etsec/rings.c
+++ /dev/null
@@ -1,654 +0,0 @@
-/*
- * QEMU Freescale eTSEC Emulator
- *
- * Copyright (c) 2011-2013 AdaCore
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "net/checksum.h"
-
-#include "etsec.h"
-#include "registers.h"
-
-/* #define ETSEC_RING_DEBUG */
-/* #define HEX_DUMP */
-/* #define DEBUG_BD */
-
-#ifdef ETSEC_RING_DEBUG
-static const int debug_etsec = 1;
-#else
-static const int debug_etsec;
-#endif
-
-#define RING_DEBUG(fmt, ...) do { \
- if (debug_etsec) { \
- qemu_log(fmt , ## __VA_ARGS__); \
- } \
- } while (0)
-
-#ifdef DEBUG_BD
-
-static void print_tx_bd_flags(uint16_t flags)
-{
- qemu_log(" Ready: %d\n", !!(flags & BD_TX_READY));
- qemu_log(" PAD/CRC: %d\n", !!(flags & BD_TX_PADCRC));
- qemu_log(" Wrap: %d\n", !!(flags & BD_WRAP));
- qemu_log(" Interrupt: %d\n", !!(flags & BD_INTERRUPT));
- qemu_log(" Last in frame: %d\n", !!(flags & BD_LAST));
- qemu_log(" Tx CRC: %d\n", !!(flags & BD_TX_TC));
- qemu_log(" User-defined preamble / defer: %d\n",
- !!(flags & BD_TX_PREDEF));
- qemu_log(" Huge frame enable / Late collision: %d\n",
- !!(flags & BD_TX_HFELC));
- qemu_log(" Control frame / Retransmission Limit: %d\n",
- !!(flags & BD_TX_CFRL));
- qemu_log(" Retry count: %d\n",
- (flags >> BD_TX_RC_OFFSET) & BD_TX_RC_MASK);
- qemu_log(" Underrun / TCP/IP off-load enable: %d\n",
- !!(flags & BD_TX_TOEUN));
- qemu_log(" Truncation: %d\n", !!(flags & BD_TX_TR));
-}
-
-static void print_rx_bd_flags(uint16_t flags)
-{
- qemu_log(" Empty: %d\n", !!(flags & BD_RX_EMPTY));
- qemu_log(" Receive software ownership: %d\n", !!(flags & BD_RX_RO1));
- qemu_log(" Wrap: %d\n", !!(flags & BD_WRAP));
- qemu_log(" Interrupt: %d\n", !!(flags & BD_INTERRUPT));
- qemu_log(" Last in frame: %d\n", !!(flags & BD_LAST));
- qemu_log(" First in frame: %d\n", !!(flags & BD_RX_FIRST));
- qemu_log(" Miss: %d\n", !!(flags & BD_RX_MISS));
- qemu_log(" Broadcast: %d\n", !!(flags & BD_RX_BROADCAST));
- qemu_log(" Multicast: %d\n", !!(flags & BD_RX_MULTICAST));
- qemu_log(" Rx frame length violation: %d\n", !!(flags & BD_RX_LG));
- qemu_log(" Rx non-octet aligned frame: %d\n", !!(flags & BD_RX_NO));
- qemu_log(" Short frame: %d\n", !!(flags & BD_RX_SH));
- qemu_log(" Rx CRC Error: %d\n", !!(flags & BD_RX_CR));
- qemu_log(" Overrun: %d\n", !!(flags & BD_RX_OV));
- qemu_log(" Truncation: %d\n", !!(flags & BD_RX_TR));
-}
-
-
-static void print_bd(eTSEC_rxtx_bd bd, int mode, uint32_t index)
-{
- qemu_log("eTSEC %s Data Buffer Descriptor (%u)\n",
- mode == eTSEC_TRANSMIT ? "Transmit" : "Receive",
- index);
- qemu_log(" Flags : 0x%04x\n", bd.flags);
- if (mode == eTSEC_TRANSMIT) {
- print_tx_bd_flags(bd.flags);
- } else {
- print_rx_bd_flags(bd.flags);
- }
- qemu_log(" Length : 0x%04x\n", bd.length);
- qemu_log(" Pointer : 0x%08x\n", bd.bufptr);
-}
-
-#endif /* DEBUG_BD */
-
-static void read_buffer_descriptor(eTSEC *etsec,
- hwaddr addr,
- eTSEC_rxtx_bd *bd)
-{
- assert(bd != NULL);
-
- RING_DEBUG("READ Buffer Descriptor @ 0x" TARGET_FMT_plx"\n", addr);
- cpu_physical_memory_read(addr,
- bd,
- sizeof(eTSEC_rxtx_bd));
-
- if (etsec->regs[DMACTRL].value & DMACTRL_LE) {
- bd->flags = lduw_le_p(&bd->flags);
- bd->length = lduw_le_p(&bd->length);
- bd->bufptr = ldl_le_p(&bd->bufptr);
- } else {
- bd->flags = lduw_be_p(&bd->flags);
- bd->length = lduw_be_p(&bd->length);
- bd->bufptr = ldl_be_p(&bd->bufptr);
- }
-}
-
-static void write_buffer_descriptor(eTSEC *etsec,
- hwaddr addr,
- eTSEC_rxtx_bd *bd)
-{
- assert(bd != NULL);
-
- if (etsec->regs[DMACTRL].value & DMACTRL_LE) {
- stw_le_p(&bd->flags, bd->flags);
- stw_le_p(&bd->length, bd->length);
- stl_le_p(&bd->bufptr, bd->bufptr);
- } else {
- stw_be_p(&bd->flags, bd->flags);
- stw_be_p(&bd->length, bd->length);
- stl_be_p(&bd->bufptr, bd->bufptr);
- }
-
- RING_DEBUG("Write Buffer Descriptor @ 0x" TARGET_FMT_plx"\n", addr);
- cpu_physical_memory_write(addr,
- bd,
- sizeof(eTSEC_rxtx_bd));
-}
-
-static void ievent_set(eTSEC *etsec,
- uint32_t flags)
-{
- etsec->regs[IEVENT].value |= flags;
-
- if ((flags & IEVENT_TXB && etsec->regs[IMASK].value & IMASK_TXBEN)
- || (flags & IEVENT_TXF && etsec->regs[IMASK].value & IMASK_TXFEN)) {
- qemu_irq_raise(etsec->tx_irq);
- RING_DEBUG("%s Raise Tx IRQ\n", __func__);
- }
-
- if ((flags & IEVENT_RXB && etsec->regs[IMASK].value & IMASK_RXBEN)
- || (flags & IEVENT_RXF && etsec->regs[IMASK].value & IMASK_RXFEN)) {
- qemu_irq_raise(etsec->rx_irq);
- RING_DEBUG("%s Raise Rx IRQ\n", __func__);
- }
-}
-
-static void tx_padding_and_crc(eTSEC *etsec, uint32_t min_frame_len)
-{
- int add = min_frame_len - etsec->tx_buffer_len;
-
- /* Padding */
- if (add > 0) {
- RING_DEBUG("pad:%u\n", add);
- etsec->tx_buffer = g_realloc(etsec->tx_buffer,
- etsec->tx_buffer_len + add);
-
- memset(etsec->tx_buffer + etsec->tx_buffer_len, 0x0, add);
- etsec->tx_buffer_len += add;
- }
-
- /* Never add CRC in QEMU */
-}
-
-static void process_tx_fcb(eTSEC *etsec)
-{
- uint8_t flags = (uint8_t)(*etsec->tx_buffer);
- /* L3 header offset from start of frame */
- uint8_t l3_header_offset = (uint8_t)*(etsec->tx_buffer + 3);
- /* L4 header offset from start of L3 header */
- uint8_t l4_header_offset = (uint8_t)*(etsec->tx_buffer + 2);
- /* L3 header */
- uint8_t *l3_header = etsec->tx_buffer + 8 + l3_header_offset;
- /* L4 header */
- uint8_t *l4_header = l3_header + l4_header_offset;
-
- /* if packet is IP4 and IP checksum is requested */
- if (flags & FCB_TX_IP && flags & FCB_TX_CIP) {
- /* do IP4 checksum (TODO This function does TCP/UDP checksum
- * but not sure if it also does IP4 checksum.) */
- net_checksum_calculate(etsec->tx_buffer + 8,
- etsec->tx_buffer_len - 8);
- }
- /* TODO Check the correct usage of the PHCS field of the FCB in case the NPH
- * flag is on */
-
- /* if packet is IP4 and TCP or UDP */
- if (flags & FCB_TX_IP && flags & FCB_TX_TUP) {
- /* if UDP */
- if (flags & FCB_TX_UDP) {
- /* if checksum is requested */
- if (flags & FCB_TX_CTU) {
- /* do UDP checksum */
-
- net_checksum_calculate(etsec->tx_buffer + 8,
- etsec->tx_buffer_len - 8);
- } else {
- /* set checksum field to 0 */
- l4_header[6] = 0;
- l4_header[7] = 0;
- }
- } else if (flags & FCB_TX_CTU) { /* if TCP and checksum is requested */
- /* do TCP checksum */
- net_checksum_calculate(etsec->tx_buffer + 8,
- etsec->tx_buffer_len - 8);
- }
- }
-}
-
-static void process_tx_bd(eTSEC *etsec,
- eTSEC_rxtx_bd *bd)
-{
- uint8_t *tmp_buff = NULL;
- hwaddr tbdbth = (hwaddr)(etsec->regs[TBDBPH].value & 0xF) << 32;
-
- if (bd->length == 0) {
- /* ERROR */
- return;
- }
-
- if (etsec->tx_buffer_len == 0) {
- /* It's the first BD */
- etsec->first_bd = *bd;
- }
-
- /* TODO: if TxBD[TOE/UN] skip the Tx Frame Control Block*/
-
- /* Load this Data Buffer */
- etsec->tx_buffer = g_realloc(etsec->tx_buffer,
- etsec->tx_buffer_len + bd->length);
- tmp_buff = etsec->tx_buffer + etsec->tx_buffer_len;
- cpu_physical_memory_read(bd->bufptr + tbdbth, tmp_buff, bd->length);
-
- /* Update buffer length */
- etsec->tx_buffer_len += bd->length;
-
-
- if (etsec->tx_buffer_len != 0 && (bd->flags & BD_LAST)) {
- if (etsec->regs[MACCFG1].value & MACCFG1_TX_EN) {
- /* MAC Transmit enabled */
-
- /* Process offload Tx FCB */
- if (etsec->first_bd.flags & BD_TX_TOEUN) {
- process_tx_fcb(etsec);
- }
-
- if (etsec->first_bd.flags & BD_TX_PADCRC
- || etsec->regs[MACCFG2].value & MACCFG2_PADCRC) {
-
- /* Padding and CRC (Padding implies CRC) */
- tx_padding_and_crc(etsec, 64);
-
- } else if (etsec->first_bd.flags & BD_TX_TC
- || etsec->regs[MACCFG2].value & MACCFG2_CRC_EN) {
-
- /* Only CRC */
- /* Never add CRC in QEMU */
- }
-
-#if defined(HEX_DUMP)
- qemu_log("eTSEC Send packet size:%d\n", etsec->tx_buffer_len);
- qemu_hexdump(etsec->tx_buffer, stderr, "", etsec->tx_buffer_len);
-#endif /* ETSEC_RING_DEBUG */
-
- if (etsec->first_bd.flags & BD_TX_TOEUN) {
- qemu_send_packet(qemu_get_queue(etsec->nic),
- etsec->tx_buffer + 8,
- etsec->tx_buffer_len - 8);
- } else {
- qemu_send_packet(qemu_get_queue(etsec->nic),
- etsec->tx_buffer,
- etsec->tx_buffer_len);
- }
-
- }
-
- etsec->tx_buffer_len = 0;
-
- if (bd->flags & BD_INTERRUPT) {
- ievent_set(etsec, IEVENT_TXF);
- }
- } else {
- if (bd->flags & BD_INTERRUPT) {
- ievent_set(etsec, IEVENT_TXB);
- }
- }
-
- /* Update DB flags */
-
- /* Clear Ready */
- bd->flags &= ~BD_TX_READY;
-
- /* Clear Defer */
- bd->flags &= ~BD_TX_PREDEF;
-
- /* Clear Late Collision */
- bd->flags &= ~BD_TX_HFELC;
-
- /* Clear Retransmission Limit */
- bd->flags &= ~BD_TX_CFRL;
-
- /* Clear Retry Count */
- bd->flags &= ~(BD_TX_RC_MASK << BD_TX_RC_OFFSET);
-
- /* Clear Underrun */
- bd->flags &= ~BD_TX_TOEUN;
-
- /* Clear Truncation */
- bd->flags &= ~BD_TX_TR;
-}
-
-void etsec_walk_tx_ring(eTSEC *etsec, int ring_nbr)
-{
- hwaddr ring_base = 0;
- hwaddr bd_addr = 0;
- eTSEC_rxtx_bd bd;
- uint16_t bd_flags;
-
- if (!(etsec->regs[MACCFG1].value & MACCFG1_TX_EN)) {
- RING_DEBUG("%s: MAC Transmit not enabled\n", __func__);
- return;
- }
-
- ring_base = (hwaddr)(etsec->regs[TBASEH].value & 0xF) << 32;
- ring_base += etsec->regs[TBASE0 + ring_nbr].value & ~0x7;
- bd_addr = etsec->regs[TBPTR0 + ring_nbr].value & ~0x7;
-
- do {
- read_buffer_descriptor(etsec, bd_addr, &bd);
-
-#ifdef DEBUG_BD
- print_bd(bd,
- eTSEC_TRANSMIT,
- (bd_addr - ring_base) / sizeof(eTSEC_rxtx_bd));
-
-#endif /* DEBUG_BD */
-
- /* Save flags before BD update */
- bd_flags = bd.flags;
-
- if (bd_flags & BD_TX_READY) {
- process_tx_bd(etsec, &bd);
-
- /* Write back BD after update */
- write_buffer_descriptor(etsec, bd_addr, &bd);
- }
-
- /* Wrap or next BD */
- if (bd_flags & BD_WRAP) {
- bd_addr = ring_base;
- } else {
- bd_addr += sizeof(eTSEC_rxtx_bd);
- }
-
- } while (bd_addr != ring_base);
-
- bd_addr = ring_base;
-
- /* Save the Buffer Descriptor Pointers to current bd */
- etsec->regs[TBPTR0 + ring_nbr].value = bd_addr;
-
- /* Set transmit halt THLTx */
- etsec->regs[TSTAT].value |= 1 << (31 - ring_nbr);
-}
-
-static void fill_rx_bd(eTSEC *etsec,
- eTSEC_rxtx_bd *bd,
- const uint8_t **buf,
- size_t *size)
-{
- uint16_t to_write;
- hwaddr bufptr = bd->bufptr +
- ((hwaddr)(etsec->regs[TBDBPH].value & 0xF) << 32);
- uint8_t padd[etsec->rx_padding];
- uint8_t rem;
-
- RING_DEBUG("eTSEC fill Rx buffer @ 0x%016" HWADDR_PRIx
- " size:%zu(padding + crc:%u) + fcb:%u\n",
- bufptr, *size, etsec->rx_padding, etsec->rx_fcb_size);
-
- bd->length = 0;
-
- /* This operation will only write FCB */
- if (etsec->rx_fcb_size != 0) {
-
- cpu_physical_memory_write(bufptr, etsec->rx_fcb, etsec->rx_fcb_size);
-
- bufptr += etsec->rx_fcb_size;
- bd->length += etsec->rx_fcb_size;
- etsec->rx_fcb_size = 0;
-
- }
-
- /* We remove padding from the computation of to_write because it is not
- * allocated in the buffer.
- */
- to_write = MIN(*size - etsec->rx_padding,
- etsec->regs[MRBLR].value - etsec->rx_fcb_size);
-
- /* This operation can only write packet data and no padding */
- if (to_write > 0) {
- cpu_physical_memory_write(bufptr, *buf, to_write);
-
- *buf += to_write;
- bufptr += to_write;
- *size -= to_write;
-
- bd->flags &= ~BD_RX_EMPTY;
- bd->length += to_write;
- }
-
- if (*size == etsec->rx_padding) {
- /* The remaining bytes are only for padding which is not actually
- * allocated in the data buffer.
- */
-
- rem = MIN(etsec->regs[MRBLR].value - bd->length, etsec->rx_padding);
-
- if (rem > 0) {
- memset(padd, 0x0, sizeof(padd));
- etsec->rx_padding -= rem;
- *size -= rem;
- bd->length += rem;
- cpu_physical_memory_write(bufptr, padd, rem);
- }
- }
-}
-
-static void rx_init_frame(eTSEC *etsec, const uint8_t *buf, size_t size)
-{
- uint32_t fcb_size = 0;
- uint8_t prsdep = (etsec->regs[RCTRL].value >> RCTRL_PRSDEP_OFFSET)
- & RCTRL_PRSDEP_MASK;
-
- if (prsdep != 0) {
- /* Prepend FCB (FCB size + RCTRL[PAL]) */
- fcb_size = 8 + ((etsec->regs[RCTRL].value >> 16) & 0x1F);
-
- etsec->rx_fcb_size = fcb_size;
-
- /* TODO: fill_FCB(etsec); */
- memset(etsec->rx_fcb, 0x0, sizeof(etsec->rx_fcb));
-
- } else {
- etsec->rx_fcb_size = 0;
- }
-
- g_free(etsec->rx_buffer);
-
- /* Do not copy the frame for now */
- etsec->rx_buffer = (uint8_t *)buf;
- etsec->rx_buffer_len = size;
-
- /* CRC padding (We don't have to compute the CRC) */
- etsec->rx_padding = 4;
-
- etsec->rx_first_in_frame = 1;
- etsec->rx_remaining_data = etsec->rx_buffer_len;
- RING_DEBUG("%s: rx_buffer_len:%u rx_padding+crc:%u\n", __func__,
- etsec->rx_buffer_len, etsec->rx_padding);
-}
-
-ssize_t etsec_rx_ring_write(eTSEC *etsec, const uint8_t *buf, size_t size)
-{
- int ring_nbr = 0; /* Always use ring0 (no filer) */
-
- if (etsec->rx_buffer_len != 0) {
- RING_DEBUG("%s: We can't receive now,"
- " a buffer is already in the pipe\n", __func__);
- return 0;
- }
-
- if (etsec->regs[RSTAT].value & 1 << (23 - ring_nbr)) {
- RING_DEBUG("%s: The ring is halted\n", __func__);
- return -1;
- }
-
- if (etsec->regs[DMACTRL].value & DMACTRL_GRS) {
- RING_DEBUG("%s: Graceful receive stop\n", __func__);
- return -1;
- }
-
- if (!(etsec->regs[MACCFG1].value & MACCFG1_RX_EN)) {
- RING_DEBUG("%s: MAC Receive not enabled\n", __func__);
- return -1;
- }
-
- if ((etsec->regs[RCTRL].value & RCTRL_RSF) && (size < 60)) {
- /* CRC is not in the packet yet, so short frame is below 60 bytes */
- RING_DEBUG("%s: Drop short frame\n", __func__);
- return -1;
- }
-
- rx_init_frame(etsec, buf, size);
-
- etsec_walk_rx_ring(etsec, ring_nbr);
-
- return size;
-}
-
-void etsec_walk_rx_ring(eTSEC *etsec, int ring_nbr)
-{
- hwaddr ring_base = 0;
- hwaddr bd_addr = 0;
- hwaddr start_bd_addr = 0;
- eTSEC_rxtx_bd bd;
- uint16_t bd_flags;
- size_t remaining_data;
- const uint8_t *buf;
- uint8_t *tmp_buf;
- size_t size;
-
- if (etsec->rx_buffer_len == 0) {
- /* No frame to send */
- RING_DEBUG("No frame to send\n");
- return;
- }
-
- remaining_data = etsec->rx_remaining_data + etsec->rx_padding;
- buf = etsec->rx_buffer
- + (etsec->rx_buffer_len - etsec->rx_remaining_data);
- size = etsec->rx_buffer_len + etsec->rx_padding;
-
- ring_base = (hwaddr)(etsec->regs[RBASEH].value & 0xF) << 32;
- ring_base += etsec->regs[RBASE0 + ring_nbr].value & ~0x7;
- start_bd_addr = bd_addr = etsec->regs[RBPTR0 + ring_nbr].value & ~0x7;
-
- do {
- read_buffer_descriptor(etsec, bd_addr, &bd);
-
-#ifdef DEBUG_BD
- print_bd(bd,
- eTSEC_RECEIVE,
- (bd_addr - ring_base) / sizeof(eTSEC_rxtx_bd));
-
-#endif /* DEBUG_BD */
-
- /* Save flags before BD update */
- bd_flags = bd.flags;
-
- if (bd_flags & BD_RX_EMPTY) {
- fill_rx_bd(etsec, &bd, &buf, &remaining_data);
-
- if (etsec->rx_first_in_frame) {
- bd.flags |= BD_RX_FIRST;
- etsec->rx_first_in_frame = 0;
- etsec->rx_first_bd = bd;
- }
-
- /* Last in frame */
- if (remaining_data == 0) {
-
- /* Clear flags */
-
- bd.flags &= ~0x7ff;
-
- bd.flags |= BD_LAST;
-
- /* NOTE: non-octet aligned frame is impossible in qemu */
-
- if (size >= etsec->regs[MAXFRM].value) {
- /* frame length violation */
- qemu_log("%s frame length violation: size:%zu MAXFRM:%d\n",
- __func__, size, etsec->regs[MAXFRM].value);
-
- bd.flags |= BD_RX_LG;
- }
-
- if (size < 64) {
- /* Short frame */
- bd.flags |= BD_RX_SH;
- }
-
- /* TODO: Broadcast and Multicast */
-
- if (bd.flags & BD_INTERRUPT) {
- /* Set RXFx */
- etsec->regs[RSTAT].value |= 1 << (7 - ring_nbr);
-
- /* Set IEVENT */
- ievent_set(etsec, IEVENT_RXF);
- }
-
- } else {
- if (bd.flags & BD_INTERRUPT) {
- /* Set IEVENT */
- ievent_set(etsec, IEVENT_RXB);
- }
- }
-
- /* Write back BD after update */
- write_buffer_descriptor(etsec, bd_addr, &bd);
- }
-
- /* Wrap or next BD */
- if (bd_flags & BD_WRAP) {
- bd_addr = ring_base;
- } else {
- bd_addr += sizeof(eTSEC_rxtx_bd);
- }
- } while (remaining_data != 0
- && (bd_flags & BD_RX_EMPTY)
- && bd_addr != start_bd_addr);
-
- /* Reset ring ptr */
- etsec->regs[RBPTR0 + ring_nbr].value = bd_addr;
-
- /* The frame is too large to fit in the Rx ring */
- if (remaining_data > 0) {
-
- /* Set RSTAT[QHLTx] */
- etsec->regs[RSTAT].value |= 1 << (23 - ring_nbr);
-
- /* Save remaining data to send the end of the frame when the ring will
- * be restarted
- */
- etsec->rx_remaining_data = remaining_data;
-
- /* Copy the frame */
- tmp_buf = g_malloc(size);
- memcpy(tmp_buf, etsec->rx_buffer, size);
- etsec->rx_buffer = tmp_buf;
-
- RING_DEBUG("no empty RxBD available any more\n");
- } else {
- etsec->rx_buffer_len = 0;
- etsec->rx_buffer = NULL;
- if (etsec->need_flush) {
- qemu_flush_queued_packets(qemu_get_queue(etsec->nic));
- }
- }
-
- RING_DEBUG("eTSEC End of ring_write: remaining_data:%zu\n", remaining_data);
-}
diff --git a/qemu/hw/net/imx_fec.c b/qemu/hw/net/imx_fec.c
deleted file mode 100644
index e60e3380e..000000000
--- a/qemu/hw/net/imx_fec.c
+++ /dev/null
@@ -1,711 +0,0 @@
-/*
- * i.MX Fast Ethernet Controller emulation.
- *
- * Copyright (c) 2013 Jean-Christophe Dubois. <jcd@tribudubois.net>
- *
- * Based on Coldfire Fast Ethernet Controller emulation.
- *
- * Copyright (c) 2007 CodeSourcery.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/net/imx_fec.h"
-#include "sysemu/dma.h"
-
-/* For crc32 */
-#include <zlib.h>
-
-#ifndef DEBUG_IMX_FEC
-#define DEBUG_IMX_FEC 0
-#endif
-
-#define FEC_PRINTF(fmt, args...) \
- do { \
- if (DEBUG_IMX_FEC) { \
- fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_FEC, \
- __func__, ##args); \
- } \
- } while (0)
-
-#ifndef DEBUG_IMX_PHY
-#define DEBUG_IMX_PHY 0
-#endif
-
-#define PHY_PRINTF(fmt, args...) \
- do { \
- if (DEBUG_IMX_PHY) { \
- fprintf(stderr, "[%s.phy]%s: " fmt , TYPE_IMX_FEC, \
- __func__, ##args); \
- } \
- } while (0)
-
-static const VMStateDescription vmstate_imx_fec = {
- .name = TYPE_IMX_FEC,
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(irq_state, IMXFECState),
- VMSTATE_UINT32(eir, IMXFECState),
- VMSTATE_UINT32(eimr, IMXFECState),
- VMSTATE_UINT32(rx_enabled, IMXFECState),
- VMSTATE_UINT32(rx_descriptor, IMXFECState),
- VMSTATE_UINT32(tx_descriptor, IMXFECState),
- VMSTATE_UINT32(ecr, IMXFECState),
- VMSTATE_UINT32(mmfr, IMXFECState),
- VMSTATE_UINT32(mscr, IMXFECState),
- VMSTATE_UINT32(mibc, IMXFECState),
- VMSTATE_UINT32(rcr, IMXFECState),
- VMSTATE_UINT32(tcr, IMXFECState),
- VMSTATE_UINT32(tfwr, IMXFECState),
- VMSTATE_UINT32(frsr, IMXFECState),
- VMSTATE_UINT32(erdsr, IMXFECState),
- VMSTATE_UINT32(etdsr, IMXFECState),
- VMSTATE_UINT32(emrbr, IMXFECState),
- VMSTATE_UINT32(miigsk_cfgr, IMXFECState),
- VMSTATE_UINT32(miigsk_enr, IMXFECState),
-
- VMSTATE_UINT32(phy_status, IMXFECState),
- VMSTATE_UINT32(phy_control, IMXFECState),
- VMSTATE_UINT32(phy_advertise, IMXFECState),
- VMSTATE_UINT32(phy_int, IMXFECState),
- VMSTATE_UINT32(phy_int_mask, IMXFECState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-#define PHY_INT_ENERGYON (1 << 7)
-#define PHY_INT_AUTONEG_COMPLETE (1 << 6)
-#define PHY_INT_FAULT (1 << 5)
-#define PHY_INT_DOWN (1 << 4)
-#define PHY_INT_AUTONEG_LP (1 << 3)
-#define PHY_INT_PARFAULT (1 << 2)
-#define PHY_INT_AUTONEG_PAGE (1 << 1)
-
-static void imx_fec_update(IMXFECState *s);
-
-/*
- * The MII phy could raise a GPIO to the processor which in turn
- * could be handled as an interrpt by the OS.
- * For now we don't handle any GPIO/interrupt line, so the OS will
- * have to poll for the PHY status.
- */
-static void phy_update_irq(IMXFECState *s)
-{
- imx_fec_update(s);
-}
-
-static void phy_update_link(IMXFECState *s)
-{
- /* Autonegotiation status mirrors link status. */
- if (qemu_get_queue(s->nic)->link_down) {
- PHY_PRINTF("link is down\n");
- s->phy_status &= ~0x0024;
- s->phy_int |= PHY_INT_DOWN;
- } else {
- PHY_PRINTF("link is up\n");
- s->phy_status |= 0x0024;
- s->phy_int |= PHY_INT_ENERGYON;
- s->phy_int |= PHY_INT_AUTONEG_COMPLETE;
- }
- phy_update_irq(s);
-}
-
-static void imx_fec_set_link(NetClientState *nc)
-{
- phy_update_link(IMX_FEC(qemu_get_nic_opaque(nc)));
-}
-
-static void phy_reset(IMXFECState *s)
-{
- s->phy_status = 0x7809;
- s->phy_control = 0x3000;
- s->phy_advertise = 0x01e1;
- s->phy_int_mask = 0;
- s->phy_int = 0;
- phy_update_link(s);
-}
-
-static uint32_t do_phy_read(IMXFECState *s, int reg)
-{
- uint32_t val;
-
- if (reg > 31) {
- /* we only advertise one phy */
- return 0;
- }
-
- switch (reg) {
- case 0: /* Basic Control */
- val = s->phy_control;
- break;
- case 1: /* Basic Status */
- val = s->phy_status;
- break;
- case 2: /* ID1 */
- val = 0x0007;
- break;
- case 3: /* ID2 */
- val = 0xc0d1;
- break;
- case 4: /* Auto-neg advertisement */
- val = s->phy_advertise;
- break;
- case 5: /* Auto-neg Link Partner Ability */
- val = 0x0f71;
- break;
- case 6: /* Auto-neg Expansion */
- val = 1;
- break;
- case 29: /* Interrupt source. */
- val = s->phy_int;
- s->phy_int = 0;
- phy_update_irq(s);
- break;
- case 30: /* Interrupt mask */
- val = s->phy_int_mask;
- break;
- case 17:
- case 18:
- case 27:
- case 31:
- qemu_log_mask(LOG_UNIMP, "[%s.phy]%s: reg %d not implemented\n",
- TYPE_IMX_FEC, __func__, reg);
- val = 0;
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "[%s.phy]%s: Bad address at offset %d\n",
- TYPE_IMX_FEC, __func__, reg);
- val = 0;
- break;
- }
-
- PHY_PRINTF("read 0x%04x @ %d\n", val, reg);
-
- return val;
-}
-
-static void do_phy_write(IMXFECState *s, int reg, uint32_t val)
-{
- PHY_PRINTF("write 0x%04x @ %d\n", val, reg);
-
- if (reg > 31) {
- /* we only advertise one phy */
- return;
- }
-
- switch (reg) {
- case 0: /* Basic Control */
- if (val & 0x8000) {
- phy_reset(s);
- } else {
- s->phy_control = val & 0x7980;
- /* Complete autonegotiation immediately. */
- if (val & 0x1000) {
- s->phy_status |= 0x0020;
- }
- }
- break;
- case 4: /* Auto-neg advertisement */
- s->phy_advertise = (val & 0x2d7f) | 0x80;
- break;
- case 30: /* Interrupt mask */
- s->phy_int_mask = val & 0xff;
- phy_update_irq(s);
- break;
- case 17:
- case 18:
- case 27:
- case 31:
- qemu_log_mask(LOG_UNIMP, "[%s.phy)%s: reg %d not implemented\n",
- TYPE_IMX_FEC, __func__, reg);
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "[%s.phy]%s: Bad address at offset %d\n",
- TYPE_IMX_FEC, __func__, reg);
- break;
- }
-}
-
-static void imx_fec_read_bd(IMXFECBufDesc *bd, dma_addr_t addr)
-{
- dma_memory_read(&address_space_memory, addr, bd, sizeof(*bd));
-}
-
-static void imx_fec_write_bd(IMXFECBufDesc *bd, dma_addr_t addr)
-{
- dma_memory_write(&address_space_memory, addr, bd, sizeof(*bd));
-}
-
-static void imx_fec_update(IMXFECState *s)
-{
- uint32_t active;
- uint32_t changed;
-
- active = s->eir & s->eimr;
- changed = active ^ s->irq_state;
- if (changed) {
- qemu_set_irq(s->irq, active);
- }
- s->irq_state = active;
-}
-
-static void imx_fec_do_tx(IMXFECState *s)
-{
- int frame_size = 0;
- uint8_t frame[FEC_MAX_FRAME_SIZE];
- uint8_t *ptr = frame;
- uint32_t addr = s->tx_descriptor;
-
- while (1) {
- IMXFECBufDesc bd;
- int len;
-
- imx_fec_read_bd(&bd, addr);
- FEC_PRINTF("tx_bd %x flags %04x len %d data %08x\n",
- addr, bd.flags, bd.length, bd.data);
- if ((bd.flags & FEC_BD_R) == 0) {
- /* Run out of descriptors to transmit. */
- break;
- }
- len = bd.length;
- if (frame_size + len > FEC_MAX_FRAME_SIZE) {
- len = FEC_MAX_FRAME_SIZE - frame_size;
- s->eir |= FEC_INT_BABT;
- }
- dma_memory_read(&address_space_memory, bd.data, ptr, len);
- ptr += len;
- frame_size += len;
- if (bd.flags & FEC_BD_L) {
- /* Last buffer in frame. */
- qemu_send_packet(qemu_get_queue(s->nic), frame, len);
- ptr = frame;
- frame_size = 0;
- s->eir |= FEC_INT_TXF;
- }
- s->eir |= FEC_INT_TXB;
- bd.flags &= ~FEC_BD_R;
- /* Write back the modified descriptor. */
- imx_fec_write_bd(&bd, addr);
- /* Advance to the next descriptor. */
- if ((bd.flags & FEC_BD_W) != 0) {
- addr = s->etdsr;
- } else {
- addr += 8;
- }
- }
-
- s->tx_descriptor = addr;
-
- imx_fec_update(s);
-}
-
-static void imx_fec_enable_rx(IMXFECState *s)
-{
- IMXFECBufDesc bd;
- uint32_t tmp;
-
- imx_fec_read_bd(&bd, s->rx_descriptor);
-
- tmp = ((bd.flags & FEC_BD_E) != 0);
-
- if (!tmp) {
- FEC_PRINTF("RX buffer full\n");
- } else if (!s->rx_enabled) {
- qemu_flush_queued_packets(qemu_get_queue(s->nic));
- }
-
- s->rx_enabled = tmp;
-}
-
-static void imx_fec_reset(DeviceState *d)
-{
- IMXFECState *s = IMX_FEC(d);
-
- /* Reset the FEC */
- s->eir = 0;
- s->eimr = 0;
- s->rx_enabled = 0;
- s->ecr = 0;
- s->mscr = 0;
- s->mibc = 0xc0000000;
- s->rcr = 0x05ee0001;
- s->tcr = 0;
- s->tfwr = 0;
- s->frsr = 0x500;
- s->miigsk_cfgr = 0;
- s->miigsk_enr = 0x6;
-
- /* We also reset the PHY */
- phy_reset(s);
-}
-
-static uint64_t imx_fec_read(void *opaque, hwaddr addr, unsigned size)
-{
- IMXFECState *s = IMX_FEC(opaque);
-
- FEC_PRINTF("reading from @ 0x%" HWADDR_PRIx "\n", addr);
-
- switch (addr & 0x3ff) {
- case 0x004:
- return s->eir;
- case 0x008:
- return s->eimr;
- case 0x010:
- return s->rx_enabled ? (1 << 24) : 0; /* RDAR */
- case 0x014:
- return 0; /* TDAR */
- case 0x024:
- return s->ecr;
- case 0x040:
- return s->mmfr;
- case 0x044:
- return s->mscr;
- case 0x064:
- return s->mibc; /* MIBC */
- case 0x084:
- return s->rcr;
- case 0x0c4:
- return s->tcr;
- case 0x0e4: /* PALR */
- return (s->conf.macaddr.a[0] << 24)
- | (s->conf.macaddr.a[1] << 16)
- | (s->conf.macaddr.a[2] << 8)
- | s->conf.macaddr.a[3];
- break;
- case 0x0e8: /* PAUR */
- return (s->conf.macaddr.a[4] << 24)
- | (s->conf.macaddr.a[5] << 16)
- | 0x8808;
- case 0x0ec:
- return 0x10000; /* OPD */
- case 0x118:
- return 0;
- case 0x11c:
- return 0;
- case 0x120:
- return 0;
- case 0x124:
- return 0;
- case 0x144:
- return s->tfwr;
- case 0x14c:
- return 0x600;
- case 0x150:
- return s->frsr;
- case 0x180:
- return s->erdsr;
- case 0x184:
- return s->etdsr;
- case 0x188:
- return s->emrbr;
- case 0x300:
- return s->miigsk_cfgr;
- case 0x308:
- return s->miigsk_enr;
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad address at offset 0x%"
- HWADDR_PRIx "\n", TYPE_IMX_FEC, __func__, addr);
- return 0;
- }
-}
-
-static void imx_fec_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- IMXFECState *s = IMX_FEC(opaque);
-
- FEC_PRINTF("writing 0x%08x @ 0x%" HWADDR_PRIx "\n", (int)value, addr);
-
- switch (addr & 0x3ff) {
- case 0x004: /* EIR */
- s->eir &= ~value;
- break;
- case 0x008: /* EIMR */
- s->eimr = value;
- break;
- case 0x010: /* RDAR */
- if ((s->ecr & FEC_EN) && !s->rx_enabled) {
- imx_fec_enable_rx(s);
- }
- break;
- case 0x014: /* TDAR */
- if (s->ecr & FEC_EN) {
- imx_fec_do_tx(s);
- }
- break;
- case 0x024: /* ECR */
- s->ecr = value;
- if (value & FEC_RESET) {
- imx_fec_reset(DEVICE(s));
- }
- if ((s->ecr & FEC_EN) == 0) {
- s->rx_enabled = 0;
- }
- break;
- case 0x040: /* MMFR */
- /* store the value */
- s->mmfr = value;
- if (extract32(value, 28, 1)) {
- do_phy_write(s, extract32(value, 18, 9), extract32(value, 0, 16));
- } else {
- s->mmfr = do_phy_read(s, extract32(value, 18, 9));
- }
- /* raise the interrupt as the PHY operation is done */
- s->eir |= FEC_INT_MII;
- break;
- case 0x044: /* MSCR */
- s->mscr = value & 0xfe;
- break;
- case 0x064: /* MIBC */
- /* TODO: Implement MIB. */
- s->mibc = (value & 0x80000000) ? 0xc0000000 : 0;
- break;
- case 0x084: /* RCR */
- s->rcr = value & 0x07ff003f;
- /* TODO: Implement LOOP mode. */
- break;
- case 0x0c4: /* TCR */
- /* We transmit immediately, so raise GRA immediately. */
- s->tcr = value;
- if (value & 1) {
- s->eir |= FEC_INT_GRA;
- }
- break;
- case 0x0e4: /* PALR */
- s->conf.macaddr.a[0] = value >> 24;
- s->conf.macaddr.a[1] = value >> 16;
- s->conf.macaddr.a[2] = value >> 8;
- s->conf.macaddr.a[3] = value;
- break;
- case 0x0e8: /* PAUR */
- s->conf.macaddr.a[4] = value >> 24;
- s->conf.macaddr.a[5] = value >> 16;
- break;
- case 0x0ec: /* OPDR */
- break;
- case 0x118: /* IAUR */
- case 0x11c: /* IALR */
- case 0x120: /* GAUR */
- case 0x124: /* GALR */
- /* TODO: implement MAC hash filtering. */
- break;
- case 0x144: /* TFWR */
- s->tfwr = value & 3;
- break;
- case 0x14c: /* FRBR */
- /* FRBR writes ignored. */
- break;
- case 0x150: /* FRSR */
- s->frsr = (value & 0x3fc) | 0x400;
- break;
- case 0x180: /* ERDSR */
- s->erdsr = value & ~3;
- s->rx_descriptor = s->erdsr;
- break;
- case 0x184: /* ETDSR */
- s->etdsr = value & ~3;
- s->tx_descriptor = s->etdsr;
- break;
- case 0x188: /* EMRBR */
- s->emrbr = value & 0x7f0;
- break;
- case 0x300: /* MIIGSK_CFGR */
- s->miigsk_cfgr = value & 0x53;
- break;
- case 0x308: /* MIIGSK_ENR */
- s->miigsk_enr = (value & 0x2) ? 0x6 : 0;
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad address at offset 0x%"
- HWADDR_PRIx "\n", TYPE_IMX_FEC, __func__, addr);
- break;
- }
-
- imx_fec_update(s);
-}
-
-static int imx_fec_can_receive(NetClientState *nc)
-{
- IMXFECState *s = IMX_FEC(qemu_get_nic_opaque(nc));
-
- return s->rx_enabled;
-}
-
-static ssize_t imx_fec_receive(NetClientState *nc, const uint8_t *buf,
- size_t len)
-{
- IMXFECState *s = IMX_FEC(qemu_get_nic_opaque(nc));
- IMXFECBufDesc bd;
- uint32_t flags = 0;
- uint32_t addr;
- uint32_t crc;
- uint32_t buf_addr;
- uint8_t *crc_ptr;
- unsigned int buf_len;
- size_t size = len;
-
- FEC_PRINTF("len %d\n", (int)size);
-
- if (!s->rx_enabled) {
- qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Unexpected packet\n",
- TYPE_IMX_FEC, __func__);
- return 0;
- }
-
- /* 4 bytes for the CRC. */
- size += 4;
- crc = cpu_to_be32(crc32(~0, buf, size));
- crc_ptr = (uint8_t *) &crc;
-
- /* Huge frames are truncted. */
- if (size > FEC_MAX_FRAME_SIZE) {
- size = FEC_MAX_FRAME_SIZE;
- flags |= FEC_BD_TR | FEC_BD_LG;
- }
-
- /* Frames larger than the user limit just set error flags. */
- if (size > (s->rcr >> 16)) {
- flags |= FEC_BD_LG;
- }
-
- addr = s->rx_descriptor;
- while (size > 0) {
- imx_fec_read_bd(&bd, addr);
- if ((bd.flags & FEC_BD_E) == 0) {
- /* No descriptors available. Bail out. */
- /*
- * FIXME: This is wrong. We should probably either
- * save the remainder for when more RX buffers are
- * available, or flag an error.
- */
- qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Lost end of frame\n",
- TYPE_IMX_FEC, __func__);
- break;
- }
- buf_len = (size <= s->emrbr) ? size : s->emrbr;
- bd.length = buf_len;
- size -= buf_len;
-
- FEC_PRINTF("rx_bd 0x%x length %d\n", addr, bd.length);
-
- /* The last 4 bytes are the CRC. */
- if (size < 4) {
- buf_len += size - 4;
- }
- buf_addr = bd.data;
- dma_memory_write(&address_space_memory, buf_addr, buf, buf_len);
- buf += buf_len;
- if (size < 4) {
- dma_memory_write(&address_space_memory, buf_addr + buf_len,
- crc_ptr, 4 - size);
- crc_ptr += 4 - size;
- }
- bd.flags &= ~FEC_BD_E;
- if (size == 0) {
- /* Last buffer in frame. */
- bd.flags |= flags | FEC_BD_L;
- FEC_PRINTF("rx frame flags %04x\n", bd.flags);
- s->eir |= FEC_INT_RXF;
- } else {
- s->eir |= FEC_INT_RXB;
- }
- imx_fec_write_bd(&bd, addr);
- /* Advance to the next descriptor. */
- if ((bd.flags & FEC_BD_W) != 0) {
- addr = s->erdsr;
- } else {
- addr += 8;
- }
- }
- s->rx_descriptor = addr;
- imx_fec_enable_rx(s);
- imx_fec_update(s);
- return len;
-}
-
-static const MemoryRegionOps imx_fec_ops = {
- .read = imx_fec_read,
- .write = imx_fec_write,
- .valid.min_access_size = 4,
- .valid.max_access_size = 4,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void imx_fec_cleanup(NetClientState *nc)
-{
- IMXFECState *s = IMX_FEC(qemu_get_nic_opaque(nc));
-
- s->nic = NULL;
-}
-
-static NetClientInfo net_imx_fec_info = {
- .type = NET_CLIENT_OPTIONS_KIND_NIC,
- .size = sizeof(NICState),
- .can_receive = imx_fec_can_receive,
- .receive = imx_fec_receive,
- .cleanup = imx_fec_cleanup,
- .link_status_changed = imx_fec_set_link,
-};
-
-
-static void imx_fec_realize(DeviceState *dev, Error **errp)
-{
- IMXFECState *s = IMX_FEC(dev);
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
-
- memory_region_init_io(&s->iomem, OBJECT(dev), &imx_fec_ops, s,
- TYPE_IMX_FEC, 0x400);
- sysbus_init_mmio(sbd, &s->iomem);
- sysbus_init_irq(sbd, &s->irq);
- qemu_macaddr_default_if_unset(&s->conf.macaddr);
-
- s->conf.peers.ncs[0] = nd_table[0].netdev;
-
- s->nic = qemu_new_nic(&net_imx_fec_info, &s->conf,
- object_get_typename(OBJECT(dev)), DEVICE(dev)->id,
- s);
- qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-}
-
-static Property imx_fec_properties[] = {
- DEFINE_NIC_PROPERTIES(IMXFECState, conf),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void imx_fec_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->vmsd = &vmstate_imx_fec;
- dc->reset = imx_fec_reset;
- dc->props = imx_fec_properties;
- dc->realize = imx_fec_realize;
- dc->desc = "i.MX FEC Ethernet Controller";
-}
-
-static const TypeInfo imx_fec_info = {
- .name = TYPE_IMX_FEC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(IMXFECState),
- .class_init = imx_fec_class_init,
-};
-
-static void imx_fec_register_types(void)
-{
- type_register_static(&imx_fec_info);
-}
-
-type_init(imx_fec_register_types)
diff --git a/qemu/hw/net/lan9118.c b/qemu/hw/net/lan9118.c
deleted file mode 100644
index 08dc474d6..000000000
--- a/qemu/hw/net/lan9118.c
+++ /dev/null
@@ -1,1399 +0,0 @@
-/*
- * SMSC LAN9118 Ethernet interface emulation
- *
- * Copyright (c) 2009 CodeSourcery, LLC.
- * Written by Paul Brook
- *
- * This code is licensed under the GNU GPL v2
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "net/net.h"
-#include "hw/devices.h"
-#include "sysemu/sysemu.h"
-#include "hw/ptimer.h"
-/* For crc32 */
-#include <zlib.h>
-
-//#define DEBUG_LAN9118
-
-#ifdef DEBUG_LAN9118
-#define DPRINTF(fmt, ...) \
-do { printf("lan9118: " fmt , ## __VA_ARGS__); } while (0)
-#define BADF(fmt, ...) \
-do { hw_error("lan9118: error: " fmt , ## __VA_ARGS__);} while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "lan9118: error: " fmt , ## __VA_ARGS__);} while (0)
-#endif
-
-#define CSR_ID_REV 0x50
-#define CSR_IRQ_CFG 0x54
-#define CSR_INT_STS 0x58
-#define CSR_INT_EN 0x5c
-#define CSR_BYTE_TEST 0x64
-#define CSR_FIFO_INT 0x68
-#define CSR_RX_CFG 0x6c
-#define CSR_TX_CFG 0x70
-#define CSR_HW_CFG 0x74
-#define CSR_RX_DP_CTRL 0x78
-#define CSR_RX_FIFO_INF 0x7c
-#define CSR_TX_FIFO_INF 0x80
-#define CSR_PMT_CTRL 0x84
-#define CSR_GPIO_CFG 0x88
-#define CSR_GPT_CFG 0x8c
-#define CSR_GPT_CNT 0x90
-#define CSR_WORD_SWAP 0x98
-#define CSR_FREE_RUN 0x9c
-#define CSR_RX_DROP 0xa0
-#define CSR_MAC_CSR_CMD 0xa4
-#define CSR_MAC_CSR_DATA 0xa8
-#define CSR_AFC_CFG 0xac
-#define CSR_E2P_CMD 0xb0
-#define CSR_E2P_DATA 0xb4
-
-#define E2P_CMD_MAC_ADDR_LOADED 0x100
-
-/* IRQ_CFG */
-#define IRQ_INT 0x00001000
-#define IRQ_EN 0x00000100
-#define IRQ_POL 0x00000010
-#define IRQ_TYPE 0x00000001
-
-/* INT_STS/INT_EN */
-#define SW_INT 0x80000000
-#define TXSTOP_INT 0x02000000
-#define RXSTOP_INT 0x01000000
-#define RXDFH_INT 0x00800000
-#define TX_IOC_INT 0x00200000
-#define RXD_INT 0x00100000
-#define GPT_INT 0x00080000
-#define PHY_INT 0x00040000
-#define PME_INT 0x00020000
-#define TXSO_INT 0x00010000
-#define RWT_INT 0x00008000
-#define RXE_INT 0x00004000
-#define TXE_INT 0x00002000
-#define TDFU_INT 0x00000800
-#define TDFO_INT 0x00000400
-#define TDFA_INT 0x00000200
-#define TSFF_INT 0x00000100
-#define TSFL_INT 0x00000080
-#define RXDF_INT 0x00000040
-#define RDFL_INT 0x00000020
-#define RSFF_INT 0x00000010
-#define RSFL_INT 0x00000008
-#define GPIO2_INT 0x00000004
-#define GPIO1_INT 0x00000002
-#define GPIO0_INT 0x00000001
-#define RESERVED_INT 0x7c001000
-
-#define MAC_CR 1
-#define MAC_ADDRH 2
-#define MAC_ADDRL 3
-#define MAC_HASHH 4
-#define MAC_HASHL 5
-#define MAC_MII_ACC 6
-#define MAC_MII_DATA 7
-#define MAC_FLOW 8
-#define MAC_VLAN1 9 /* TODO */
-#define MAC_VLAN2 10 /* TODO */
-#define MAC_WUFF 11 /* TODO */
-#define MAC_WUCSR 12 /* TODO */
-
-#define MAC_CR_RXALL 0x80000000
-#define MAC_CR_RCVOWN 0x00800000
-#define MAC_CR_LOOPBK 0x00200000
-#define MAC_CR_FDPX 0x00100000
-#define MAC_CR_MCPAS 0x00080000
-#define MAC_CR_PRMS 0x00040000
-#define MAC_CR_INVFILT 0x00020000
-#define MAC_CR_PASSBAD 0x00010000
-#define MAC_CR_HO 0x00008000
-#define MAC_CR_HPFILT 0x00002000
-#define MAC_CR_LCOLL 0x00001000
-#define MAC_CR_BCAST 0x00000800
-#define MAC_CR_DISRTY 0x00000400
-#define MAC_CR_PADSTR 0x00000100
-#define MAC_CR_BOLMT 0x000000c0
-#define MAC_CR_DFCHK 0x00000020
-#define MAC_CR_TXEN 0x00000008
-#define MAC_CR_RXEN 0x00000004
-#define MAC_CR_RESERVED 0x7f404213
-
-#define PHY_INT_ENERGYON 0x80
-#define PHY_INT_AUTONEG_COMPLETE 0x40
-#define PHY_INT_FAULT 0x20
-#define PHY_INT_DOWN 0x10
-#define PHY_INT_AUTONEG_LP 0x08
-#define PHY_INT_PARFAULT 0x04
-#define PHY_INT_AUTONEG_PAGE 0x02
-
-#define GPT_TIMER_EN 0x20000000
-
-enum tx_state {
- TX_IDLE,
- TX_B,
- TX_DATA
-};
-
-typedef struct {
- /* state is a tx_state but we can't put enums in VMStateDescriptions. */
- uint32_t state;
- uint32_t cmd_a;
- uint32_t cmd_b;
- int32_t buffer_size;
- int32_t offset;
- int32_t pad;
- int32_t fifo_used;
- int32_t len;
- uint8_t data[2048];
-} LAN9118Packet;
-
-static const VMStateDescription vmstate_lan9118_packet = {
- .name = "lan9118_packet",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(state, LAN9118Packet),
- VMSTATE_UINT32(cmd_a, LAN9118Packet),
- VMSTATE_UINT32(cmd_b, LAN9118Packet),
- VMSTATE_INT32(buffer_size, LAN9118Packet),
- VMSTATE_INT32(offset, LAN9118Packet),
- VMSTATE_INT32(pad, LAN9118Packet),
- VMSTATE_INT32(fifo_used, LAN9118Packet),
- VMSTATE_INT32(len, LAN9118Packet),
- VMSTATE_UINT8_ARRAY(data, LAN9118Packet, 2048),
- VMSTATE_END_OF_LIST()
- }
-};
-
-#define TYPE_LAN9118 "lan9118"
-#define LAN9118(obj) OBJECT_CHECK(lan9118_state, (obj), TYPE_LAN9118)
-
-typedef struct {
- SysBusDevice parent_obj;
-
- NICState *nic;
- NICConf conf;
- qemu_irq irq;
- MemoryRegion mmio;
- ptimer_state *timer;
-
- uint32_t irq_cfg;
- uint32_t int_sts;
- uint32_t int_en;
- uint32_t fifo_int;
- uint32_t rx_cfg;
- uint32_t tx_cfg;
- uint32_t hw_cfg;
- uint32_t pmt_ctrl;
- uint32_t gpio_cfg;
- uint32_t gpt_cfg;
- uint32_t word_swap;
- uint32_t free_timer_start;
- uint32_t mac_cmd;
- uint32_t mac_data;
- uint32_t afc_cfg;
- uint32_t e2p_cmd;
- uint32_t e2p_data;
-
- uint32_t mac_cr;
- uint32_t mac_hashh;
- uint32_t mac_hashl;
- uint32_t mac_mii_acc;
- uint32_t mac_mii_data;
- uint32_t mac_flow;
-
- uint32_t phy_status;
- uint32_t phy_control;
- uint32_t phy_advertise;
- uint32_t phy_int;
- uint32_t phy_int_mask;
-
- int32_t eeprom_writable;
- uint8_t eeprom[128];
-
- int32_t tx_fifo_size;
- LAN9118Packet *txp;
- LAN9118Packet tx_packet;
-
- int32_t tx_status_fifo_used;
- int32_t tx_status_fifo_head;
- uint32_t tx_status_fifo[512];
-
- int32_t rx_status_fifo_size;
- int32_t rx_status_fifo_used;
- int32_t rx_status_fifo_head;
- uint32_t rx_status_fifo[896];
- int32_t rx_fifo_size;
- int32_t rx_fifo_used;
- int32_t rx_fifo_head;
- uint32_t rx_fifo[3360];
- int32_t rx_packet_size_head;
- int32_t rx_packet_size_tail;
- int32_t rx_packet_size[1024];
-
- int32_t rxp_offset;
- int32_t rxp_size;
- int32_t rxp_pad;
-
- uint32_t write_word_prev_offset;
- uint32_t write_word_n;
- uint16_t write_word_l;
- uint16_t write_word_h;
- uint32_t read_word_prev_offset;
- uint32_t read_word_n;
- uint32_t read_long;
-
- uint32_t mode_16bit;
-} lan9118_state;
-
-static const VMStateDescription vmstate_lan9118 = {
- .name = "lan9118",
- .version_id = 2,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_PTIMER(timer, lan9118_state),
- VMSTATE_UINT32(irq_cfg, lan9118_state),
- VMSTATE_UINT32(int_sts, lan9118_state),
- VMSTATE_UINT32(int_en, lan9118_state),
- VMSTATE_UINT32(fifo_int, lan9118_state),
- VMSTATE_UINT32(rx_cfg, lan9118_state),
- VMSTATE_UINT32(tx_cfg, lan9118_state),
- VMSTATE_UINT32(hw_cfg, lan9118_state),
- VMSTATE_UINT32(pmt_ctrl, lan9118_state),
- VMSTATE_UINT32(gpio_cfg, lan9118_state),
- VMSTATE_UINT32(gpt_cfg, lan9118_state),
- VMSTATE_UINT32(word_swap, lan9118_state),
- VMSTATE_UINT32(free_timer_start, lan9118_state),
- VMSTATE_UINT32(mac_cmd, lan9118_state),
- VMSTATE_UINT32(mac_data, lan9118_state),
- VMSTATE_UINT32(afc_cfg, lan9118_state),
- VMSTATE_UINT32(e2p_cmd, lan9118_state),
- VMSTATE_UINT32(e2p_data, lan9118_state),
- VMSTATE_UINT32(mac_cr, lan9118_state),
- VMSTATE_UINT32(mac_hashh, lan9118_state),
- VMSTATE_UINT32(mac_hashl, lan9118_state),
- VMSTATE_UINT32(mac_mii_acc, lan9118_state),
- VMSTATE_UINT32(mac_mii_data, lan9118_state),
- VMSTATE_UINT32(mac_flow, lan9118_state),
- VMSTATE_UINT32(phy_status, lan9118_state),
- VMSTATE_UINT32(phy_control, lan9118_state),
- VMSTATE_UINT32(phy_advertise, lan9118_state),
- VMSTATE_UINT32(phy_int, lan9118_state),
- VMSTATE_UINT32(phy_int_mask, lan9118_state),
- VMSTATE_INT32(eeprom_writable, lan9118_state),
- VMSTATE_UINT8_ARRAY(eeprom, lan9118_state, 128),
- VMSTATE_INT32(tx_fifo_size, lan9118_state),
- /* txp always points at tx_packet so need not be saved */
- VMSTATE_STRUCT(tx_packet, lan9118_state, 0,
- vmstate_lan9118_packet, LAN9118Packet),
- VMSTATE_INT32(tx_status_fifo_used, lan9118_state),
- VMSTATE_INT32(tx_status_fifo_head, lan9118_state),
- VMSTATE_UINT32_ARRAY(tx_status_fifo, lan9118_state, 512),
- VMSTATE_INT32(rx_status_fifo_size, lan9118_state),
- VMSTATE_INT32(rx_status_fifo_used, lan9118_state),
- VMSTATE_INT32(rx_status_fifo_head, lan9118_state),
- VMSTATE_UINT32_ARRAY(rx_status_fifo, lan9118_state, 896),
- VMSTATE_INT32(rx_fifo_size, lan9118_state),
- VMSTATE_INT32(rx_fifo_used, lan9118_state),
- VMSTATE_INT32(rx_fifo_head, lan9118_state),
- VMSTATE_UINT32_ARRAY(rx_fifo, lan9118_state, 3360),
- VMSTATE_INT32(rx_packet_size_head, lan9118_state),
- VMSTATE_INT32(rx_packet_size_tail, lan9118_state),
- VMSTATE_INT32_ARRAY(rx_packet_size, lan9118_state, 1024),
- VMSTATE_INT32(rxp_offset, lan9118_state),
- VMSTATE_INT32(rxp_size, lan9118_state),
- VMSTATE_INT32(rxp_pad, lan9118_state),
- VMSTATE_UINT32_V(write_word_prev_offset, lan9118_state, 2),
- VMSTATE_UINT32_V(write_word_n, lan9118_state, 2),
- VMSTATE_UINT16_V(write_word_l, lan9118_state, 2),
- VMSTATE_UINT16_V(write_word_h, lan9118_state, 2),
- VMSTATE_UINT32_V(read_word_prev_offset, lan9118_state, 2),
- VMSTATE_UINT32_V(read_word_n, lan9118_state, 2),
- VMSTATE_UINT32_V(read_long, lan9118_state, 2),
- VMSTATE_UINT32_V(mode_16bit, lan9118_state, 2),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void lan9118_update(lan9118_state *s)
-{
- int level;
-
- /* TODO: Implement FIFO level IRQs. */
- level = (s->int_sts & s->int_en) != 0;
- if (level) {
- s->irq_cfg |= IRQ_INT;
- } else {
- s->irq_cfg &= ~IRQ_INT;
- }
- if ((s->irq_cfg & IRQ_EN) == 0) {
- level = 0;
- }
- if ((s->irq_cfg & (IRQ_TYPE | IRQ_POL)) != (IRQ_TYPE | IRQ_POL)) {
- /* Interrupt is active low unless we're configured as
- * active-high polarity, push-pull type.
- */
- level = !level;
- }
- qemu_set_irq(s->irq, level);
-}
-
-static void lan9118_mac_changed(lan9118_state *s)
-{
- qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-}
-
-static void lan9118_reload_eeprom(lan9118_state *s)
-{
- int i;
- if (s->eeprom[0] != 0xa5) {
- s->e2p_cmd &= ~E2P_CMD_MAC_ADDR_LOADED;
- DPRINTF("MACADDR load failed\n");
- return;
- }
- for (i = 0; i < 6; i++) {
- s->conf.macaddr.a[i] = s->eeprom[i + 1];
- }
- s->e2p_cmd |= E2P_CMD_MAC_ADDR_LOADED;
- DPRINTF("MACADDR loaded from eeprom\n");
- lan9118_mac_changed(s);
-}
-
-static void phy_update_irq(lan9118_state *s)
-{
- if (s->phy_int & s->phy_int_mask) {
- s->int_sts |= PHY_INT;
- } else {
- s->int_sts &= ~PHY_INT;
- }
- lan9118_update(s);
-}
-
-static void phy_update_link(lan9118_state *s)
-{
- /* Autonegotiation status mirrors link status. */
- if (qemu_get_queue(s->nic)->link_down) {
- s->phy_status &= ~0x0024;
- s->phy_int |= PHY_INT_DOWN;
- } else {
- s->phy_status |= 0x0024;
- s->phy_int |= PHY_INT_ENERGYON;
- s->phy_int |= PHY_INT_AUTONEG_COMPLETE;
- }
- phy_update_irq(s);
-}
-
-static void lan9118_set_link(NetClientState *nc)
-{
- phy_update_link(qemu_get_nic_opaque(nc));
-}
-
-static void phy_reset(lan9118_state *s)
-{
- s->phy_status = 0x7809;
- s->phy_control = 0x3000;
- s->phy_advertise = 0x01e1;
- s->phy_int_mask = 0;
- s->phy_int = 0;
- phy_update_link(s);
-}
-
-static void lan9118_reset(DeviceState *d)
-{
- lan9118_state *s = LAN9118(d);
-
- s->irq_cfg &= (IRQ_TYPE | IRQ_POL);
- s->int_sts = 0;
- s->int_en = 0;
- s->fifo_int = 0x48000000;
- s->rx_cfg = 0;
- s->tx_cfg = 0;
- s->hw_cfg = s->mode_16bit ? 0x00050000 : 0x00050004;
- s->pmt_ctrl &= 0x45;
- s->gpio_cfg = 0;
- s->txp->fifo_used = 0;
- s->txp->state = TX_IDLE;
- s->txp->cmd_a = 0xffffffffu;
- s->txp->cmd_b = 0xffffffffu;
- s->txp->len = 0;
- s->txp->fifo_used = 0;
- s->tx_fifo_size = 4608;
- s->tx_status_fifo_used = 0;
- s->rx_status_fifo_size = 704;
- s->rx_fifo_size = 2640;
- s->rx_fifo_used = 0;
- s->rx_status_fifo_size = 176;
- s->rx_status_fifo_used = 0;
- s->rxp_offset = 0;
- s->rxp_size = 0;
- s->rxp_pad = 0;
- s->rx_packet_size_tail = s->rx_packet_size_head;
- s->rx_packet_size[s->rx_packet_size_head] = 0;
- s->mac_cmd = 0;
- s->mac_data = 0;
- s->afc_cfg = 0;
- s->e2p_cmd = 0;
- s->e2p_data = 0;
- s->free_timer_start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / 40;
-
- ptimer_stop(s->timer);
- ptimer_set_count(s->timer, 0xffff);
- s->gpt_cfg = 0xffff;
-
- s->mac_cr = MAC_CR_PRMS;
- s->mac_hashh = 0;
- s->mac_hashl = 0;
- s->mac_mii_acc = 0;
- s->mac_mii_data = 0;
- s->mac_flow = 0;
-
- s->read_word_n = 0;
- s->write_word_n = 0;
-
- phy_reset(s);
-
- s->eeprom_writable = 0;
- lan9118_reload_eeprom(s);
-}
-
-static void rx_fifo_push(lan9118_state *s, uint32_t val)
-{
- int fifo_pos;
- fifo_pos = s->rx_fifo_head + s->rx_fifo_used;
- if (fifo_pos >= s->rx_fifo_size)
- fifo_pos -= s->rx_fifo_size;
- s->rx_fifo[fifo_pos] = val;
- s->rx_fifo_used++;
-}
-
-/* Return nonzero if the packet is accepted by the filter. */
-static int lan9118_filter(lan9118_state *s, const uint8_t *addr)
-{
- int multicast;
- uint32_t hash;
-
- if (s->mac_cr & MAC_CR_PRMS) {
- return 1;
- }
- if (addr[0] == 0xff && addr[1] == 0xff && addr[2] == 0xff &&
- addr[3] == 0xff && addr[4] == 0xff && addr[5] == 0xff) {
- return (s->mac_cr & MAC_CR_BCAST) == 0;
- }
-
- multicast = addr[0] & 1;
- if (multicast &&s->mac_cr & MAC_CR_MCPAS) {
- return 1;
- }
- if (multicast ? (s->mac_cr & MAC_CR_HPFILT) == 0
- : (s->mac_cr & MAC_CR_HO) == 0) {
- /* Exact matching. */
- hash = memcmp(addr, s->conf.macaddr.a, 6);
- if (s->mac_cr & MAC_CR_INVFILT) {
- return hash != 0;
- } else {
- return hash == 0;
- }
- } else {
- /* Hash matching */
- hash = compute_mcast_idx(addr);
- if (hash & 0x20) {
- return (s->mac_hashh >> (hash & 0x1f)) & 1;
- } else {
- return (s->mac_hashl >> (hash & 0x1f)) & 1;
- }
- }
-}
-
-static ssize_t lan9118_receive(NetClientState *nc, const uint8_t *buf,
- size_t size)
-{
- lan9118_state *s = qemu_get_nic_opaque(nc);
- int fifo_len;
- int offset;
- int src_pos;
- int n;
- int filter;
- uint32_t val;
- uint32_t crc;
- uint32_t status;
-
- if ((s->mac_cr & MAC_CR_RXEN) == 0) {
- return -1;
- }
-
- if (size >= 2048 || size < 14) {
- return -1;
- }
-
- /* TODO: Implement FIFO overflow notification. */
- if (s->rx_status_fifo_used == s->rx_status_fifo_size) {
- return -1;
- }
-
- filter = lan9118_filter(s, buf);
- if (!filter && (s->mac_cr & MAC_CR_RXALL) == 0) {
- return size;
- }
-
- offset = (s->rx_cfg >> 8) & 0x1f;
- n = offset & 3;
- fifo_len = (size + n + 3) >> 2;
- /* Add a word for the CRC. */
- fifo_len++;
- if (s->rx_fifo_size - s->rx_fifo_used < fifo_len) {
- return -1;
- }
-
- DPRINTF("Got packet len:%d fifo:%d filter:%s\n",
- (int)size, fifo_len, filter ? "pass" : "fail");
- val = 0;
- crc = bswap32(crc32(~0, buf, size));
- for (src_pos = 0; src_pos < size; src_pos++) {
- val = (val >> 8) | ((uint32_t)buf[src_pos] << 24);
- n++;
- if (n == 4) {
- n = 0;
- rx_fifo_push(s, val);
- val = 0;
- }
- }
- if (n) {
- val >>= ((4 - n) * 8);
- val |= crc << (n * 8);
- rx_fifo_push(s, val);
- val = crc >> ((4 - n) * 8);
- rx_fifo_push(s, val);
- } else {
- rx_fifo_push(s, crc);
- }
- n = s->rx_status_fifo_head + s->rx_status_fifo_used;
- if (n >= s->rx_status_fifo_size) {
- n -= s->rx_status_fifo_size;
- }
- s->rx_packet_size[s->rx_packet_size_tail] = fifo_len;
- s->rx_packet_size_tail = (s->rx_packet_size_tail + 1023) & 1023;
- s->rx_status_fifo_used++;
-
- status = (size + 4) << 16;
- if (buf[0] == 0xff && buf[1] == 0xff && buf[2] == 0xff &&
- buf[3] == 0xff && buf[4] == 0xff && buf[5] == 0xff) {
- status |= 0x00002000;
- } else if (buf[0] & 1) {
- status |= 0x00000400;
- }
- if (!filter) {
- status |= 0x40000000;
- }
- s->rx_status_fifo[n] = status;
-
- if (s->rx_status_fifo_used > (s->fifo_int & 0xff)) {
- s->int_sts |= RSFL_INT;
- }
- lan9118_update(s);
-
- return size;
-}
-
-static uint32_t rx_fifo_pop(lan9118_state *s)
-{
- int n;
- uint32_t val;
-
- if (s->rxp_size == 0 && s->rxp_pad == 0) {
- s->rxp_size = s->rx_packet_size[s->rx_packet_size_head];
- s->rx_packet_size[s->rx_packet_size_head] = 0;
- if (s->rxp_size != 0) {
- s->rx_packet_size_head = (s->rx_packet_size_head + 1023) & 1023;
- s->rxp_offset = (s->rx_cfg >> 10) & 7;
- n = s->rxp_offset + s->rxp_size;
- switch (s->rx_cfg >> 30) {
- case 1:
- n = (-n) & 3;
- break;
- case 2:
- n = (-n) & 7;
- break;
- default:
- n = 0;
- break;
- }
- s->rxp_pad = n;
- DPRINTF("Pop packet size:%d offset:%d pad: %d\n",
- s->rxp_size, s->rxp_offset, s->rxp_pad);
- }
- }
- if (s->rxp_offset > 0) {
- s->rxp_offset--;
- val = 0;
- } else if (s->rxp_size > 0) {
- s->rxp_size--;
- val = s->rx_fifo[s->rx_fifo_head++];
- if (s->rx_fifo_head >= s->rx_fifo_size) {
- s->rx_fifo_head -= s->rx_fifo_size;
- }
- s->rx_fifo_used--;
- } else if (s->rxp_pad > 0) {
- s->rxp_pad--;
- val = 0;
- } else {
- DPRINTF("RX underflow\n");
- s->int_sts |= RXE_INT;
- val = 0;
- }
- lan9118_update(s);
- return val;
-}
-
-static void do_tx_packet(lan9118_state *s)
-{
- int n;
- uint32_t status;
-
- /* FIXME: Honor TX disable, and allow queueing of packets. */
- if (s->phy_control & 0x4000) {
- /* This assumes the receive routine doesn't touch the VLANClient. */
- lan9118_receive(qemu_get_queue(s->nic), s->txp->data, s->txp->len);
- } else {
- qemu_send_packet(qemu_get_queue(s->nic), s->txp->data, s->txp->len);
- }
- s->txp->fifo_used = 0;
-
- if (s->tx_status_fifo_used == 512) {
- /* Status FIFO full */
- return;
- }
- /* Add entry to status FIFO. */
- status = s->txp->cmd_b & 0xffff0000u;
- DPRINTF("Sent packet tag:%04x len %d\n", status >> 16, s->txp->len);
- n = (s->tx_status_fifo_head + s->tx_status_fifo_used) & 511;
- s->tx_status_fifo[n] = status;
- s->tx_status_fifo_used++;
- if (s->tx_status_fifo_used == 512) {
- s->int_sts |= TSFF_INT;
- /* TODO: Stop transmission. */
- }
-}
-
-static uint32_t rx_status_fifo_pop(lan9118_state *s)
-{
- uint32_t val;
-
- val = s->rx_status_fifo[s->rx_status_fifo_head];
- if (s->rx_status_fifo_used != 0) {
- s->rx_status_fifo_used--;
- s->rx_status_fifo_head++;
- if (s->rx_status_fifo_head >= s->rx_status_fifo_size) {
- s->rx_status_fifo_head -= s->rx_status_fifo_size;
- }
- /* ??? What value should be returned when the FIFO is empty? */
- DPRINTF("RX status pop 0x%08x\n", val);
- }
- return val;
-}
-
-static uint32_t tx_status_fifo_pop(lan9118_state *s)
-{
- uint32_t val;
-
- val = s->tx_status_fifo[s->tx_status_fifo_head];
- if (s->tx_status_fifo_used != 0) {
- s->tx_status_fifo_used--;
- s->tx_status_fifo_head = (s->tx_status_fifo_head + 1) & 511;
- /* ??? What value should be returned when the FIFO is empty? */
- }
- return val;
-}
-
-static void tx_fifo_push(lan9118_state *s, uint32_t val)
-{
- int n;
-
- if (s->txp->fifo_used == s->tx_fifo_size) {
- s->int_sts |= TDFO_INT;
- return;
- }
- switch (s->txp->state) {
- case TX_IDLE:
- s->txp->cmd_a = val & 0x831f37ff;
- s->txp->fifo_used++;
- s->txp->state = TX_B;
- s->txp->buffer_size = extract32(s->txp->cmd_a, 0, 11);
- s->txp->offset = extract32(s->txp->cmd_a, 16, 5);
- break;
- case TX_B:
- if (s->txp->cmd_a & 0x2000) {
- /* First segment */
- s->txp->cmd_b = val;
- s->txp->fifo_used++;
- /* End alignment does not include command words. */
- n = (s->txp->buffer_size + s->txp->offset + 3) >> 2;
- switch ((n >> 24) & 3) {
- case 1:
- n = (-n) & 3;
- break;
- case 2:
- n = (-n) & 7;
- break;
- default:
- n = 0;
- }
- s->txp->pad = n;
- s->txp->len = 0;
- }
- DPRINTF("Block len:%d offset:%d pad:%d cmd %08x\n",
- s->txp->buffer_size, s->txp->offset, s->txp->pad,
- s->txp->cmd_a);
- s->txp->state = TX_DATA;
- break;
- case TX_DATA:
- if (s->txp->offset >= 4) {
- s->txp->offset -= 4;
- break;
- }
- if (s->txp->buffer_size <= 0 && s->txp->pad != 0) {
- s->txp->pad--;
- } else {
- n = MIN(4, s->txp->buffer_size + s->txp->offset);
- while (s->txp->offset) {
- val >>= 8;
- n--;
- s->txp->offset--;
- }
- /* Documentation is somewhat unclear on the ordering of bytes
- in FIFO words. Empirical results show it to be little-endian.
- */
- /* TODO: FIFO overflow checking. */
- while (n--) {
- s->txp->data[s->txp->len] = val & 0xff;
- s->txp->len++;
- val >>= 8;
- s->txp->buffer_size--;
- }
- s->txp->fifo_used++;
- }
- if (s->txp->buffer_size <= 0 && s->txp->pad == 0) {
- if (s->txp->cmd_a & 0x1000) {
- do_tx_packet(s);
- }
- if (s->txp->cmd_a & 0x80000000) {
- s->int_sts |= TX_IOC_INT;
- }
- s->txp->state = TX_IDLE;
- }
- break;
- }
-}
-
-static uint32_t do_phy_read(lan9118_state *s, int reg)
-{
- uint32_t val;
-
- switch (reg) {
- case 0: /* Basic Control */
- return s->phy_control;
- case 1: /* Basic Status */
- return s->phy_status;
- case 2: /* ID1 */
- return 0x0007;
- case 3: /* ID2 */
- return 0xc0d1;
- case 4: /* Auto-neg advertisement */
- return s->phy_advertise;
- case 5: /* Auto-neg Link Partner Ability */
- return 0x0f71;
- case 6: /* Auto-neg Expansion */
- return 1;
- /* TODO 17, 18, 27, 29, 30, 31 */
- case 29: /* Interrupt source. */
- val = s->phy_int;
- s->phy_int = 0;
- phy_update_irq(s);
- return val;
- case 30: /* Interrupt mask */
- return s->phy_int_mask;
- default:
- BADF("PHY read reg %d\n", reg);
- return 0;
- }
-}
-
-static void do_phy_write(lan9118_state *s, int reg, uint32_t val)
-{
- switch (reg) {
- case 0: /* Basic Control */
- if (val & 0x8000) {
- phy_reset(s);
- break;
- }
- s->phy_control = val & 0x7980;
- /* Complete autonegotiation immediately. */
- if (val & 0x1000) {
- s->phy_status |= 0x0020;
- }
- break;
- case 4: /* Auto-neg advertisement */
- s->phy_advertise = (val & 0x2d7f) | 0x80;
- break;
- /* TODO 17, 18, 27, 31 */
- case 30: /* Interrupt mask */
- s->phy_int_mask = val & 0xff;
- phy_update_irq(s);
- break;
- default:
- BADF("PHY write reg %d = 0x%04x\n", reg, val);
- }
-}
-
-static void do_mac_write(lan9118_state *s, int reg, uint32_t val)
-{
- switch (reg) {
- case MAC_CR:
- if ((s->mac_cr & MAC_CR_RXEN) != 0 && (val & MAC_CR_RXEN) == 0) {
- s->int_sts |= RXSTOP_INT;
- }
- s->mac_cr = val & ~MAC_CR_RESERVED;
- DPRINTF("MAC_CR: %08x\n", val);
- break;
- case MAC_ADDRH:
- s->conf.macaddr.a[4] = val & 0xff;
- s->conf.macaddr.a[5] = (val >> 8) & 0xff;
- lan9118_mac_changed(s);
- break;
- case MAC_ADDRL:
- s->conf.macaddr.a[0] = val & 0xff;
- s->conf.macaddr.a[1] = (val >> 8) & 0xff;
- s->conf.macaddr.a[2] = (val >> 16) & 0xff;
- s->conf.macaddr.a[3] = (val >> 24) & 0xff;
- lan9118_mac_changed(s);
- break;
- case MAC_HASHH:
- s->mac_hashh = val;
- break;
- case MAC_HASHL:
- s->mac_hashl = val;
- break;
- case MAC_MII_ACC:
- s->mac_mii_acc = val & 0xffc2;
- if (val & 2) {
- DPRINTF("PHY write %d = 0x%04x\n",
- (val >> 6) & 0x1f, s->mac_mii_data);
- do_phy_write(s, (val >> 6) & 0x1f, s->mac_mii_data);
- } else {
- s->mac_mii_data = do_phy_read(s, (val >> 6) & 0x1f);
- DPRINTF("PHY read %d = 0x%04x\n",
- (val >> 6) & 0x1f, s->mac_mii_data);
- }
- break;
- case MAC_MII_DATA:
- s->mac_mii_data = val & 0xffff;
- break;
- case MAC_FLOW:
- s->mac_flow = val & 0xffff0000;
- break;
- case MAC_VLAN1:
- /* Writing to this register changes a condition for
- * FrameTooLong bit in rx_status. Since we do not set
- * FrameTooLong anyway, just ignore write to this.
- */
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "lan9118: Unimplemented MAC register write: %d = 0x%x\n",
- s->mac_cmd & 0xf, val);
- }
-}
-
-static uint32_t do_mac_read(lan9118_state *s, int reg)
-{
- switch (reg) {
- case MAC_CR:
- return s->mac_cr;
- case MAC_ADDRH:
- return s->conf.macaddr.a[4] | (s->conf.macaddr.a[5] << 8);
- case MAC_ADDRL:
- return s->conf.macaddr.a[0] | (s->conf.macaddr.a[1] << 8)
- | (s->conf.macaddr.a[2] << 16) | (s->conf.macaddr.a[3] << 24);
- case MAC_HASHH:
- return s->mac_hashh;
- break;
- case MAC_HASHL:
- return s->mac_hashl;
- break;
- case MAC_MII_ACC:
- return s->mac_mii_acc;
- case MAC_MII_DATA:
- return s->mac_mii_data;
- case MAC_FLOW:
- return s->mac_flow;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "lan9118: Unimplemented MAC register read: %d\n",
- s->mac_cmd & 0xf);
- return 0;
- }
-}
-
-static void lan9118_eeprom_cmd(lan9118_state *s, int cmd, int addr)
-{
- s->e2p_cmd = (s->e2p_cmd & E2P_CMD_MAC_ADDR_LOADED) | (cmd << 28) | addr;
- switch (cmd) {
- case 0:
- s->e2p_data = s->eeprom[addr];
- DPRINTF("EEPROM Read %d = 0x%02x\n", addr, s->e2p_data);
- break;
- case 1:
- s->eeprom_writable = 0;
- DPRINTF("EEPROM Write Disable\n");
- break;
- case 2: /* EWEN */
- s->eeprom_writable = 1;
- DPRINTF("EEPROM Write Enable\n");
- break;
- case 3: /* WRITE */
- if (s->eeprom_writable) {
- s->eeprom[addr] &= s->e2p_data;
- DPRINTF("EEPROM Write %d = 0x%02x\n", addr, s->e2p_data);
- } else {
- DPRINTF("EEPROM Write %d (ignored)\n", addr);
- }
- break;
- case 4: /* WRAL */
- if (s->eeprom_writable) {
- for (addr = 0; addr < 128; addr++) {
- s->eeprom[addr] &= s->e2p_data;
- }
- DPRINTF("EEPROM Write All 0x%02x\n", s->e2p_data);
- } else {
- DPRINTF("EEPROM Write All (ignored)\n");
- }
- break;
- case 5: /* ERASE */
- if (s->eeprom_writable) {
- s->eeprom[addr] = 0xff;
- DPRINTF("EEPROM Erase %d\n", addr);
- } else {
- DPRINTF("EEPROM Erase %d (ignored)\n", addr);
- }
- break;
- case 6: /* ERAL */
- if (s->eeprom_writable) {
- memset(s->eeprom, 0xff, 128);
- DPRINTF("EEPROM Erase All\n");
- } else {
- DPRINTF("EEPROM Erase All (ignored)\n");
- }
- break;
- case 7: /* RELOAD */
- lan9118_reload_eeprom(s);
- break;
- }
-}
-
-static void lan9118_tick(void *opaque)
-{
- lan9118_state *s = (lan9118_state *)opaque;
- if (s->int_en & GPT_INT) {
- s->int_sts |= GPT_INT;
- }
- lan9118_update(s);
-}
-
-static void lan9118_writel(void *opaque, hwaddr offset,
- uint64_t val, unsigned size)
-{
- lan9118_state *s = (lan9118_state *)opaque;
- offset &= 0xff;
-
- //DPRINTF("Write reg 0x%02x = 0x%08x\n", (int)offset, val);
- if (offset >= 0x20 && offset < 0x40) {
- /* TX FIFO */
- tx_fifo_push(s, val);
- return;
- }
- switch (offset) {
- case CSR_IRQ_CFG:
- /* TODO: Implement interrupt deassertion intervals. */
- val &= (IRQ_EN | IRQ_POL | IRQ_TYPE);
- s->irq_cfg = (s->irq_cfg & IRQ_INT) | val;
- break;
- case CSR_INT_STS:
- s->int_sts &= ~val;
- break;
- case CSR_INT_EN:
- s->int_en = val & ~RESERVED_INT;
- s->int_sts |= val & SW_INT;
- break;
- case CSR_FIFO_INT:
- DPRINTF("FIFO INT levels %08x\n", val);
- s->fifo_int = val;
- break;
- case CSR_RX_CFG:
- if (val & 0x8000) {
- /* RX_DUMP */
- s->rx_fifo_used = 0;
- s->rx_status_fifo_used = 0;
- s->rx_packet_size_tail = s->rx_packet_size_head;
- s->rx_packet_size[s->rx_packet_size_head] = 0;
- }
- s->rx_cfg = val & 0xcfff1ff0;
- break;
- case CSR_TX_CFG:
- if (val & 0x8000) {
- s->tx_status_fifo_used = 0;
- }
- if (val & 0x4000) {
- s->txp->state = TX_IDLE;
- s->txp->fifo_used = 0;
- s->txp->cmd_a = 0xffffffff;
- }
- s->tx_cfg = val & 6;
- break;
- case CSR_HW_CFG:
- if (val & 1) {
- /* SRST */
- lan9118_reset(DEVICE(s));
- } else {
- s->hw_cfg = (val & 0x003f300) | (s->hw_cfg & 0x4);
- }
- break;
- case CSR_RX_DP_CTRL:
- if (val & 0x80000000) {
- /* Skip forward to next packet. */
- s->rxp_pad = 0;
- s->rxp_offset = 0;
- if (s->rxp_size == 0) {
- /* Pop a word to start the next packet. */
- rx_fifo_pop(s);
- s->rxp_pad = 0;
- s->rxp_offset = 0;
- }
- s->rx_fifo_head += s->rxp_size;
- if (s->rx_fifo_head >= s->rx_fifo_size) {
- s->rx_fifo_head -= s->rx_fifo_size;
- }
- }
- break;
- case CSR_PMT_CTRL:
- if (val & 0x400) {
- phy_reset(s);
- }
- s->pmt_ctrl &= ~0x34e;
- s->pmt_ctrl |= (val & 0x34e);
- break;
- case CSR_GPIO_CFG:
- /* Probably just enabling LEDs. */
- s->gpio_cfg = val & 0x7777071f;
- break;
- case CSR_GPT_CFG:
- if ((s->gpt_cfg ^ val) & GPT_TIMER_EN) {
- if (val & GPT_TIMER_EN) {
- ptimer_set_count(s->timer, val & 0xffff);
- ptimer_run(s->timer, 0);
- } else {
- ptimer_stop(s->timer);
- ptimer_set_count(s->timer, 0xffff);
- }
- }
- s->gpt_cfg = val & (GPT_TIMER_EN | 0xffff);
- break;
- case CSR_WORD_SWAP:
- /* Ignored because we're in 32-bit mode. */
- s->word_swap = val;
- break;
- case CSR_MAC_CSR_CMD:
- s->mac_cmd = val & 0x4000000f;
- if (val & 0x80000000) {
- if (val & 0x40000000) {
- s->mac_data = do_mac_read(s, val & 0xf);
- DPRINTF("MAC read %d = 0x%08x\n", val & 0xf, s->mac_data);
- } else {
- DPRINTF("MAC write %d = 0x%08x\n", val & 0xf, s->mac_data);
- do_mac_write(s, val & 0xf, s->mac_data);
- }
- }
- break;
- case CSR_MAC_CSR_DATA:
- s->mac_data = val;
- break;
- case CSR_AFC_CFG:
- s->afc_cfg = val & 0x00ffffff;
- break;
- case CSR_E2P_CMD:
- lan9118_eeprom_cmd(s, (val >> 28) & 7, val & 0x7f);
- break;
- case CSR_E2P_DATA:
- s->e2p_data = val & 0xff;
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "lan9118_write: Bad reg 0x%x = %x\n",
- (int)offset, (int)val);
- break;
- }
- lan9118_update(s);
-}
-
-static void lan9118_writew(void *opaque, hwaddr offset,
- uint32_t val)
-{
- lan9118_state *s = (lan9118_state *)opaque;
- offset &= 0xff;
-
- if (s->write_word_prev_offset != (offset & ~0x3)) {
- /* New offset, reset word counter */
- s->write_word_n = 0;
- s->write_word_prev_offset = offset & ~0x3;
- }
-
- if (offset & 0x2) {
- s->write_word_h = val;
- } else {
- s->write_word_l = val;
- }
-
- //DPRINTF("Writew reg 0x%02x = 0x%08x\n", (int)offset, val);
- s->write_word_n++;
- if (s->write_word_n == 2) {
- s->write_word_n = 0;
- lan9118_writel(s, offset & ~3, s->write_word_l +
- (s->write_word_h << 16), 4);
- }
-}
-
-static void lan9118_16bit_mode_write(void *opaque, hwaddr offset,
- uint64_t val, unsigned size)
-{
- switch (size) {
- case 2:
- lan9118_writew(opaque, offset, (uint32_t)val);
- return;
- case 4:
- lan9118_writel(opaque, offset, val, size);
- return;
- }
-
- hw_error("lan9118_write: Bad size 0x%x\n", size);
-}
-
-static uint64_t lan9118_readl(void *opaque, hwaddr offset,
- unsigned size)
-{
- lan9118_state *s = (lan9118_state *)opaque;
-
- //DPRINTF("Read reg 0x%02x\n", (int)offset);
- if (offset < 0x20) {
- /* RX FIFO */
- return rx_fifo_pop(s);
- }
- switch (offset) {
- case 0x40:
- return rx_status_fifo_pop(s);
- case 0x44:
- return s->rx_status_fifo[s->tx_status_fifo_head];
- case 0x48:
- return tx_status_fifo_pop(s);
- case 0x4c:
- return s->tx_status_fifo[s->tx_status_fifo_head];
- case CSR_ID_REV:
- return 0x01180001;
- case CSR_IRQ_CFG:
- return s->irq_cfg;
- case CSR_INT_STS:
- return s->int_sts;
- case CSR_INT_EN:
- return s->int_en;
- case CSR_BYTE_TEST:
- return 0x87654321;
- case CSR_FIFO_INT:
- return s->fifo_int;
- case CSR_RX_CFG:
- return s->rx_cfg;
- case CSR_TX_CFG:
- return s->tx_cfg;
- case CSR_HW_CFG:
- return s->hw_cfg;
- case CSR_RX_DP_CTRL:
- return 0;
- case CSR_RX_FIFO_INF:
- return (s->rx_status_fifo_used << 16) | (s->rx_fifo_used << 2);
- case CSR_TX_FIFO_INF:
- return (s->tx_status_fifo_used << 16)
- | (s->tx_fifo_size - s->txp->fifo_used);
- case CSR_PMT_CTRL:
- return s->pmt_ctrl;
- case CSR_GPIO_CFG:
- return s->gpio_cfg;
- case CSR_GPT_CFG:
- return s->gpt_cfg;
- case CSR_GPT_CNT:
- return ptimer_get_count(s->timer);
- case CSR_WORD_SWAP:
- return s->word_swap;
- case CSR_FREE_RUN:
- return (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / 40) - s->free_timer_start;
- case CSR_RX_DROP:
- /* TODO: Implement dropped frames counter. */
- return 0;
- case CSR_MAC_CSR_CMD:
- return s->mac_cmd;
- case CSR_MAC_CSR_DATA:
- return s->mac_data;
- case CSR_AFC_CFG:
- return s->afc_cfg;
- case CSR_E2P_CMD:
- return s->e2p_cmd;
- case CSR_E2P_DATA:
- return s->e2p_data;
- }
- qemu_log_mask(LOG_GUEST_ERROR, "lan9118_read: Bad reg 0x%x\n", (int)offset);
- return 0;
-}
-
-static uint32_t lan9118_readw(void *opaque, hwaddr offset)
-{
- lan9118_state *s = (lan9118_state *)opaque;
- uint32_t val;
-
- if (s->read_word_prev_offset != (offset & ~0x3)) {
- /* New offset, reset word counter */
- s->read_word_n = 0;
- s->read_word_prev_offset = offset & ~0x3;
- }
-
- s->read_word_n++;
- if (s->read_word_n == 1) {
- s->read_long = lan9118_readl(s, offset & ~3, 4);
- } else {
- s->read_word_n = 0;
- }
-
- if (offset & 2) {
- val = s->read_long >> 16;
- } else {
- val = s->read_long & 0xFFFF;
- }
-
- //DPRINTF("Readw reg 0x%02x, val 0x%x\n", (int)offset, val);
- return val;
-}
-
-static uint64_t lan9118_16bit_mode_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- switch (size) {
- case 2:
- return lan9118_readw(opaque, offset);
- case 4:
- return lan9118_readl(opaque, offset, size);
- }
-
- hw_error("lan9118_read: Bad size 0x%x\n", size);
- return 0;
-}
-
-static const MemoryRegionOps lan9118_mem_ops = {
- .read = lan9118_readl,
- .write = lan9118_writel,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const MemoryRegionOps lan9118_16bit_mem_ops = {
- .read = lan9118_16bit_mode_read,
- .write = lan9118_16bit_mode_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static NetClientInfo net_lan9118_info = {
- .type = NET_CLIENT_OPTIONS_KIND_NIC,
- .size = sizeof(NICState),
- .receive = lan9118_receive,
- .link_status_changed = lan9118_set_link,
-};
-
-static int lan9118_init1(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- lan9118_state *s = LAN9118(dev);
- QEMUBH *bh;
- int i;
- const MemoryRegionOps *mem_ops =
- s->mode_16bit ? &lan9118_16bit_mem_ops : &lan9118_mem_ops;
-
- memory_region_init_io(&s->mmio, OBJECT(dev), mem_ops, s,
- "lan9118-mmio", 0x100);
- sysbus_init_mmio(sbd, &s->mmio);
- sysbus_init_irq(sbd, &s->irq);
- qemu_macaddr_default_if_unset(&s->conf.macaddr);
-
- s->nic = qemu_new_nic(&net_lan9118_info, &s->conf,
- object_get_typename(OBJECT(dev)), dev->id, s);
- qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
- s->eeprom[0] = 0xa5;
- for (i = 0; i < 6; i++) {
- s->eeprom[i + 1] = s->conf.macaddr.a[i];
- }
- s->pmt_ctrl = 1;
- s->txp = &s->tx_packet;
-
- bh = qemu_bh_new(lan9118_tick, s);
- s->timer = ptimer_init(bh);
- ptimer_set_freq(s->timer, 10000);
- ptimer_set_limit(s->timer, 0xffff, 1);
-
- return 0;
-}
-
-static Property lan9118_properties[] = {
- DEFINE_NIC_PROPERTIES(lan9118_state, conf),
- DEFINE_PROP_UINT32("mode_16bit", lan9118_state, mode_16bit, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void lan9118_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = lan9118_init1;
- dc->reset = lan9118_reset;
- dc->props = lan9118_properties;
- dc->vmsd = &vmstate_lan9118;
-}
-
-static const TypeInfo lan9118_info = {
- .name = TYPE_LAN9118,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(lan9118_state),
- .class_init = lan9118_class_init,
-};
-
-static void lan9118_register_types(void)
-{
- type_register_static(&lan9118_info);
-}
-
-/* Legacy helper function. Should go away when machine config files are
- implemented. */
-void lan9118_init(NICInfo *nd, uint32_t base, qemu_irq irq)
-{
- DeviceState *dev;
- SysBusDevice *s;
-
- qemu_check_nic_model(nd, "lan9118");
- dev = qdev_create(NULL, TYPE_LAN9118);
- qdev_set_nic_properties(dev, nd);
- qdev_init_nofail(dev);
- s = SYS_BUS_DEVICE(dev);
- sysbus_mmio_map(s, 0, base);
- sysbus_connect_irq(s, 0, irq);
-}
-
-type_init(lan9118_register_types)
diff --git a/qemu/hw/net/lance.c b/qemu/hw/net/lance.c
deleted file mode 100644
index 6253d2103..000000000
--- a/qemu/hw/net/lance.c
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * QEMU AMD PC-Net II (Am79C970A) emulation
- *
- * Copyright (c) 2004 Antony T Curtis
- *
- * 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.
- */
-
-/* This software was written to be compatible with the specification:
- * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet
- * AMD Publication# 19436 Rev:E Amendment/0 Issue Date: June 2000
- */
-
-/*
- * On Sparc32, this is the Lance (Am7990) part of chip STP2000 (Master I/O), also
- * produced as NCR89C100. See
- * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt
- * and
- * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "net/net.h"
-#include "qemu/timer.h"
-#include "qemu/sockets.h"
-#include "hw/sparc/sun4m.h"
-#include "pcnet.h"
-#include "trace.h"
-#include "sysemu/sysemu.h"
-
-#define TYPE_LANCE "lance"
-#define SYSBUS_PCNET(obj) \
- OBJECT_CHECK(SysBusPCNetState, (obj), TYPE_LANCE)
-
-typedef struct {
- SysBusDevice parent_obj;
-
- PCNetState state;
-} SysBusPCNetState;
-
-static void parent_lance_reset(void *opaque, int irq, int level)
-{
- SysBusPCNetState *d = opaque;
- if (level)
- pcnet_h_reset(&d->state);
-}
-
-static void lance_mem_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- SysBusPCNetState *d = opaque;
-
- trace_lance_mem_writew(addr, val & 0xffff);
- pcnet_ioport_writew(&d->state, addr, val & 0xffff);
-}
-
-static uint64_t lance_mem_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- SysBusPCNetState *d = opaque;
- uint32_t val;
-
- val = pcnet_ioport_readw(&d->state, addr);
- trace_lance_mem_readw(addr, val & 0xffff);
- return val & 0xffff;
-}
-
-static const MemoryRegionOps lance_mem_ops = {
- .read = lance_mem_read,
- .write = lance_mem_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 2,
- .max_access_size = 2,
- },
-};
-
-static NetClientInfo net_lance_info = {
- .type = NET_CLIENT_OPTIONS_KIND_NIC,
- .size = sizeof(NICState),
- .receive = pcnet_receive,
- .link_status_changed = pcnet_set_link_status,
-};
-
-static const VMStateDescription vmstate_lance = {
- .name = "pcnet",
- .version_id = 3,
- .minimum_version_id = 2,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT(state, SysBusPCNetState, 0, vmstate_pcnet, PCNetState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static int lance_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- SysBusPCNetState *d = SYSBUS_PCNET(dev);
- PCNetState *s = &d->state;
-
- memory_region_init_io(&s->mmio, OBJECT(d), &lance_mem_ops, d,
- "lance-mmio", 4);
-
- qdev_init_gpio_in(dev, parent_lance_reset, 1);
-
- sysbus_init_mmio(sbd, &s->mmio);
-
- sysbus_init_irq(sbd, &s->irq);
-
- s->phys_mem_read = ledma_memory_read;
- s->phys_mem_write = ledma_memory_write;
- pcnet_common_init(dev, s, &net_lance_info);
- return 0;
-}
-
-static void lance_reset(DeviceState *dev)
-{
- SysBusPCNetState *d = SYSBUS_PCNET(dev);
-
- pcnet_h_reset(&d->state);
-}
-
-static void lance_instance_init(Object *obj)
-{
- SysBusPCNetState *d = SYSBUS_PCNET(obj);
- PCNetState *s = &d->state;
-
- device_add_bootindex_property(obj, &s->conf.bootindex,
- "bootindex", "/ethernet-phy@0",
- DEVICE(obj), NULL);
-}
-
-static Property lance_properties[] = {
- DEFINE_PROP_PTR("dma", SysBusPCNetState, state.dma_opaque),
- DEFINE_NIC_PROPERTIES(SysBusPCNetState, state.conf),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void lance_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = lance_init;
- set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
- dc->fw_name = "ethernet";
- dc->reset = lance_reset;
- dc->vmsd = &vmstate_lance;
- dc->props = lance_properties;
- /* Reason: pointer property "dma" */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo lance_info = {
- .name = TYPE_LANCE,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(SysBusPCNetState),
- .class_init = lance_class_init,
- .instance_init = lance_instance_init,
-};
-
-static void lance_register_types(void)
-{
- type_register_static(&lance_info);
-}
-
-type_init(lance_register_types)
diff --git a/qemu/hw/net/mcf_fec.c b/qemu/hw/net/mcf_fec.c
deleted file mode 100644
index 7c0398ed9..000000000
--- a/qemu/hw/net/mcf_fec.c
+++ /dev/null
@@ -1,535 +0,0 @@
-/*
- * ColdFire Fast Ethernet Controller emulation.
- *
- * Copyright (c) 2007 CodeSourcery.
- *
- * This code is licensed under the GPL
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "net/net.h"
-#include "hw/m68k/mcf.h"
-#include "hw/net/mii.h"
-/* For crc32 */
-#include <zlib.h>
-#include "exec/address-spaces.h"
-
-//#define DEBUG_FEC 1
-
-#ifdef DEBUG_FEC
-#define DPRINTF(fmt, ...) \
-do { printf("mcf_fec: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#endif
-
-#define FEC_MAX_FRAME_SIZE 2032
-
-typedef struct {
- MemoryRegion *sysmem;
- MemoryRegion iomem;
- qemu_irq *irq;
- NICState *nic;
- NICConf conf;
- uint32_t irq_state;
- uint32_t eir;
- uint32_t eimr;
- int rx_enabled;
- uint32_t rx_descriptor;
- uint32_t tx_descriptor;
- uint32_t ecr;
- uint32_t mmfr;
- uint32_t mscr;
- uint32_t rcr;
- uint32_t tcr;
- uint32_t tfwr;
- uint32_t rfsr;
- uint32_t erdsr;
- uint32_t etdsr;
- uint32_t emrbr;
-} mcf_fec_state;
-
-#define FEC_INT_HB 0x80000000
-#define FEC_INT_BABR 0x40000000
-#define FEC_INT_BABT 0x20000000
-#define FEC_INT_GRA 0x10000000
-#define FEC_INT_TXF 0x08000000
-#define FEC_INT_TXB 0x04000000
-#define FEC_INT_RXF 0x02000000
-#define FEC_INT_RXB 0x01000000
-#define FEC_INT_MII 0x00800000
-#define FEC_INT_EB 0x00400000
-#define FEC_INT_LC 0x00200000
-#define FEC_INT_RL 0x00100000
-#define FEC_INT_UN 0x00080000
-
-#define FEC_EN 2
-#define FEC_RESET 1
-
-/* Map interrupt flags onto IRQ lines. */
-#define FEC_NUM_IRQ 13
-static const uint32_t mcf_fec_irq_map[FEC_NUM_IRQ] = {
- FEC_INT_TXF,
- FEC_INT_TXB,
- FEC_INT_UN,
- FEC_INT_RL,
- FEC_INT_RXF,
- FEC_INT_RXB,
- FEC_INT_MII,
- FEC_INT_LC,
- FEC_INT_HB,
- FEC_INT_GRA,
- FEC_INT_EB,
- FEC_INT_BABT,
- FEC_INT_BABR
-};
-
-/* Buffer Descriptor. */
-typedef struct {
- uint16_t flags;
- uint16_t length;
- uint32_t data;
-} mcf_fec_bd;
-
-#define FEC_BD_R 0x8000
-#define FEC_BD_E 0x8000
-#define FEC_BD_O1 0x4000
-#define FEC_BD_W 0x2000
-#define FEC_BD_O2 0x1000
-#define FEC_BD_L 0x0800
-#define FEC_BD_TC 0x0400
-#define FEC_BD_ABC 0x0200
-#define FEC_BD_M 0x0100
-#define FEC_BD_BC 0x0080
-#define FEC_BD_MC 0x0040
-#define FEC_BD_LG 0x0020
-#define FEC_BD_NO 0x0010
-#define FEC_BD_CR 0x0004
-#define FEC_BD_OV 0x0002
-#define FEC_BD_TR 0x0001
-
-static void mcf_fec_read_bd(mcf_fec_bd *bd, uint32_t addr)
-{
- cpu_physical_memory_read(addr, bd, sizeof(*bd));
- be16_to_cpus(&bd->flags);
- be16_to_cpus(&bd->length);
- be32_to_cpus(&bd->data);
-}
-
-static void mcf_fec_write_bd(mcf_fec_bd *bd, uint32_t addr)
-{
- mcf_fec_bd tmp;
- tmp.flags = cpu_to_be16(bd->flags);
- tmp.length = cpu_to_be16(bd->length);
- tmp.data = cpu_to_be32(bd->data);
- cpu_physical_memory_write(addr, &tmp, sizeof(tmp));
-}
-
-static void mcf_fec_update(mcf_fec_state *s)
-{
- uint32_t active;
- uint32_t changed;
- uint32_t mask;
- int i;
-
- active = s->eir & s->eimr;
- changed = active ^s->irq_state;
- for (i = 0; i < FEC_NUM_IRQ; i++) {
- mask = mcf_fec_irq_map[i];
- if (changed & mask) {
- DPRINTF("IRQ %d = %d\n", i, (active & mask) != 0);
- qemu_set_irq(s->irq[i], (active & mask) != 0);
- }
- }
- s->irq_state = active;
-}
-
-static void mcf_fec_do_tx(mcf_fec_state *s)
-{
- uint32_t addr;
- mcf_fec_bd bd;
- int frame_size;
- int len;
- uint8_t frame[FEC_MAX_FRAME_SIZE];
- uint8_t *ptr;
-
- DPRINTF("do_tx\n");
- ptr = frame;
- frame_size = 0;
- addr = s->tx_descriptor;
- while (1) {
- mcf_fec_read_bd(&bd, addr);
- DPRINTF("tx_bd %x flags %04x len %d data %08x\n",
- addr, bd.flags, bd.length, bd.data);
- if ((bd.flags & FEC_BD_R) == 0) {
- /* Run out of descriptors to transmit. */
- break;
- }
- len = bd.length;
- if (frame_size + len > FEC_MAX_FRAME_SIZE) {
- len = FEC_MAX_FRAME_SIZE - frame_size;
- s->eir |= FEC_INT_BABT;
- }
- cpu_physical_memory_read(bd.data, ptr, len);
- ptr += len;
- frame_size += len;
- if (bd.flags & FEC_BD_L) {
- /* Last buffer in frame. */
- DPRINTF("Sending packet\n");
- qemu_send_packet(qemu_get_queue(s->nic), frame, len);
- ptr = frame;
- frame_size = 0;
- s->eir |= FEC_INT_TXF;
- }
- s->eir |= FEC_INT_TXB;
- bd.flags &= ~FEC_BD_R;
- /* Write back the modified descriptor. */
- mcf_fec_write_bd(&bd, addr);
- /* Advance to the next descriptor. */
- if ((bd.flags & FEC_BD_W) != 0) {
- addr = s->etdsr;
- } else {
- addr += 8;
- }
- }
- s->tx_descriptor = addr;
-}
-
-static void mcf_fec_enable_rx(mcf_fec_state *s)
-{
- NetClientState *nc = qemu_get_queue(s->nic);
- mcf_fec_bd bd;
-
- mcf_fec_read_bd(&bd, s->rx_descriptor);
- s->rx_enabled = ((bd.flags & FEC_BD_E) != 0);
- if (s->rx_enabled) {
- qemu_flush_queued_packets(nc);
- }
-}
-
-static void mcf_fec_reset(mcf_fec_state *s)
-{
- s->eir = 0;
- s->eimr = 0;
- s->rx_enabled = 0;
- s->ecr = 0;
- s->mscr = 0;
- s->rcr = 0x05ee0001;
- s->tcr = 0;
- s->tfwr = 0;
- s->rfsr = 0x500;
-}
-
-#define MMFR_WRITE_OP (1 << 28)
-#define MMFR_READ_OP (2 << 28)
-#define MMFR_PHYADDR(v) (((v) >> 23) & 0x1f)
-#define MMFR_REGNUM(v) (((v) >> 18) & 0x1f)
-
-static uint64_t mcf_fec_read_mdio(mcf_fec_state *s)
-{
- uint64_t v;
-
- if (s->mmfr & MMFR_WRITE_OP)
- return s->mmfr;
- if (MMFR_PHYADDR(s->mmfr) != 1)
- return s->mmfr |= 0xffff;
-
- switch (MMFR_REGNUM(s->mmfr)) {
- case MII_BMCR:
- v = MII_BMCR_SPEED | MII_BMCR_AUTOEN | MII_BMCR_FD;
- break;
- case MII_BMSR:
- v = MII_BMSR_100TX_FD | MII_BMSR_100TX_HD | MII_BMSR_10T_FD |
- MII_BMSR_10T_HD | MII_BMSR_MFPS | MII_BMSR_AN_COMP |
- MII_BMSR_AUTONEG | MII_BMSR_LINK_ST;
- break;
- case MII_PHYID1:
- v = DP83848_PHYID1;
- break;
- case MII_PHYID2:
- v = DP83848_PHYID2;
- break;
- case MII_ANAR:
- v = MII_ANAR_TXFD | MII_ANAR_TX | MII_ANAR_10FD |
- MII_ANAR_10 | MII_ANAR_CSMACD;
- break;
- case MII_ANLPAR:
- v = MII_ANLPAR_ACK | MII_ANLPAR_TXFD | MII_ANLPAR_TX |
- MII_ANLPAR_10FD | MII_ANLPAR_10 | MII_ANLPAR_CSMACD;
- break;
- default:
- v = 0xffff;
- break;
- }
- s->mmfr = (s->mmfr & ~0xffff) | v;
- return s->mmfr;
-}
-
-static uint64_t mcf_fec_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- mcf_fec_state *s = (mcf_fec_state *)opaque;
- switch (addr & 0x3ff) {
- case 0x004: return s->eir;
- case 0x008: return s->eimr;
- case 0x010: return s->rx_enabled ? (1 << 24) : 0; /* RDAR */
- case 0x014: return 0; /* TDAR */
- case 0x024: return s->ecr;
- case 0x040: return mcf_fec_read_mdio(s);
- case 0x044: return s->mscr;
- case 0x064: return 0; /* MIBC */
- case 0x084: return s->rcr;
- case 0x0c4: return s->tcr;
- case 0x0e4: /* PALR */
- return (s->conf.macaddr.a[0] << 24) | (s->conf.macaddr.a[1] << 16)
- | (s->conf.macaddr.a[2] << 8) | s->conf.macaddr.a[3];
- break;
- case 0x0e8: /* PAUR */
- return (s->conf.macaddr.a[4] << 24) | (s->conf.macaddr.a[5] << 16) | 0x8808;
- case 0x0ec: return 0x10000; /* OPD */
- case 0x118: return 0;
- case 0x11c: return 0;
- case 0x120: return 0;
- case 0x124: return 0;
- case 0x144: return s->tfwr;
- case 0x14c: return 0x600;
- case 0x150: return s->rfsr;
- case 0x180: return s->erdsr;
- case 0x184: return s->etdsr;
- case 0x188: return s->emrbr;
- default:
- hw_error("mcf_fec_read: Bad address 0x%x\n", (int)addr);
- return 0;
- }
-}
-
-static void mcf_fec_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- mcf_fec_state *s = (mcf_fec_state *)opaque;
- switch (addr & 0x3ff) {
- case 0x004:
- s->eir &= ~value;
- break;
- case 0x008:
- s->eimr = value;
- break;
- case 0x010: /* RDAR */
- if ((s->ecr & FEC_EN) && !s->rx_enabled) {
- DPRINTF("RX enable\n");
- mcf_fec_enable_rx(s);
- }
- break;
- case 0x014: /* TDAR */
- if (s->ecr & FEC_EN) {
- mcf_fec_do_tx(s);
- }
- break;
- case 0x024:
- s->ecr = value;
- if (value & FEC_RESET) {
- DPRINTF("Reset\n");
- mcf_fec_reset(s);
- }
- if ((s->ecr & FEC_EN) == 0) {
- s->rx_enabled = 0;
- }
- break;
- case 0x040:
- s->mmfr = value;
- s->eir |= FEC_INT_MII;
- break;
- case 0x044:
- s->mscr = value & 0xfe;
- break;
- case 0x064:
- /* TODO: Implement MIB. */
- break;
- case 0x084:
- s->rcr = value & 0x07ff003f;
- /* TODO: Implement LOOP mode. */
- break;
- case 0x0c4: /* TCR */
- /* We transmit immediately, so raise GRA immediately. */
- s->tcr = value;
- if (value & 1)
- s->eir |= FEC_INT_GRA;
- break;
- case 0x0e4: /* PALR */
- s->conf.macaddr.a[0] = value >> 24;
- s->conf.macaddr.a[1] = value >> 16;
- s->conf.macaddr.a[2] = value >> 8;
- s->conf.macaddr.a[3] = value;
- break;
- case 0x0e8: /* PAUR */
- s->conf.macaddr.a[4] = value >> 24;
- s->conf.macaddr.a[5] = value >> 16;
- break;
- case 0x0ec:
- /* OPD */
- break;
- case 0x118:
- case 0x11c:
- case 0x120:
- case 0x124:
- /* TODO: implement MAC hash filtering. */
- break;
- case 0x144:
- s->tfwr = value & 3;
- break;
- case 0x14c:
- /* FRBR writes ignored. */
- break;
- case 0x150:
- s->rfsr = (value & 0x3fc) | 0x400;
- break;
- case 0x180:
- s->erdsr = value & ~3;
- s->rx_descriptor = s->erdsr;
- break;
- case 0x184:
- s->etdsr = value & ~3;
- s->tx_descriptor = s->etdsr;
- break;
- case 0x188:
- s->emrbr = value & 0x7f0;
- break;
- default:
- hw_error("mcf_fec_write Bad address 0x%x\n", (int)addr);
- }
- mcf_fec_update(s);
-}
-
-static int mcf_fec_have_receive_space(mcf_fec_state *s, size_t want)
-{
- mcf_fec_bd bd;
- uint32_t addr;
-
- /* Walk descriptor list to determine if we have enough buffer */
- addr = s->rx_descriptor;
- while (want > 0) {
- mcf_fec_read_bd(&bd, addr);
- if ((bd.flags & FEC_BD_E) == 0) {
- return 0;
- }
- if (want < s->emrbr) {
- return 1;
- }
- want -= s->emrbr;
- /* Advance to the next descriptor. */
- if ((bd.flags & FEC_BD_W) != 0) {
- addr = s->erdsr;
- } else {
- addr += 8;
- }
- }
- return 0;
-}
-
-static ssize_t mcf_fec_receive(NetClientState *nc, const uint8_t *buf, size_t size)
-{
- mcf_fec_state *s = qemu_get_nic_opaque(nc);
- mcf_fec_bd bd;
- uint32_t flags = 0;
- uint32_t addr;
- uint32_t crc;
- uint32_t buf_addr;
- uint8_t *crc_ptr;
- unsigned int buf_len;
- size_t retsize;
-
- DPRINTF("do_rx len %d\n", size);
- if (!s->rx_enabled) {
- return -1;
- }
- /* 4 bytes for the CRC. */
- size += 4;
- crc = cpu_to_be32(crc32(~0, buf, size));
- crc_ptr = (uint8_t *)&crc;
- /* Huge frames are truncted. */
- if (size > FEC_MAX_FRAME_SIZE) {
- size = FEC_MAX_FRAME_SIZE;
- flags |= FEC_BD_TR | FEC_BD_LG;
- }
- /* Frames larger than the user limit just set error flags. */
- if (size > (s->rcr >> 16)) {
- flags |= FEC_BD_LG;
- }
- /* Check if we have enough space in current descriptors */
- if (!mcf_fec_have_receive_space(s, size)) {
- return 0;
- }
- addr = s->rx_descriptor;
- retsize = size;
- while (size > 0) {
- mcf_fec_read_bd(&bd, addr);
- buf_len = (size <= s->emrbr) ? size: s->emrbr;
- bd.length = buf_len;
- size -= buf_len;
- DPRINTF("rx_bd %x length %d\n", addr, bd.length);
- /* The last 4 bytes are the CRC. */
- if (size < 4)
- buf_len += size - 4;
- buf_addr = bd.data;
- cpu_physical_memory_write(buf_addr, buf, buf_len);
- buf += buf_len;
- if (size < 4) {
- cpu_physical_memory_write(buf_addr + buf_len, crc_ptr, 4 - size);
- crc_ptr += 4 - size;
- }
- bd.flags &= ~FEC_BD_E;
- if (size == 0) {
- /* Last buffer in frame. */
- bd.flags |= flags | FEC_BD_L;
- DPRINTF("rx frame flags %04x\n", bd.flags);
- s->eir |= FEC_INT_RXF;
- } else {
- s->eir |= FEC_INT_RXB;
- }
- mcf_fec_write_bd(&bd, addr);
- /* Advance to the next descriptor. */
- if ((bd.flags & FEC_BD_W) != 0) {
- addr = s->erdsr;
- } else {
- addr += 8;
- }
- }
- s->rx_descriptor = addr;
- mcf_fec_enable_rx(s);
- mcf_fec_update(s);
- return retsize;
-}
-
-static const MemoryRegionOps mcf_fec_ops = {
- .read = mcf_fec_read,
- .write = mcf_fec_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static NetClientInfo net_mcf_fec_info = {
- .type = NET_CLIENT_OPTIONS_KIND_NIC,
- .size = sizeof(NICState),
- .receive = mcf_fec_receive,
-};
-
-void mcf_fec_init(MemoryRegion *sysmem, NICInfo *nd,
- hwaddr base, qemu_irq *irq)
-{
- mcf_fec_state *s;
-
- qemu_check_nic_model(nd, "mcf_fec");
-
- s = (mcf_fec_state *)g_malloc0(sizeof(mcf_fec_state));
- s->sysmem = sysmem;
- s->irq = irq;
-
- memory_region_init_io(&s->iomem, NULL, &mcf_fec_ops, s, "fec", 0x400);
- memory_region_add_subregion(sysmem, base, &s->iomem);
-
- s->conf.macaddr = nd->macaddr;
- s->conf.peers.ncs[0] = nd->netdev;
-
- s->nic = qemu_new_nic(&net_mcf_fec_info, &s->conf, nd->model, nd->name, s);
-
- qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-}
diff --git a/qemu/hw/net/milkymist-minimac2.c b/qemu/hw/net/milkymist-minimac2.c
deleted file mode 100644
index 1e147c33c..000000000
--- a/qemu/hw/net/milkymist-minimac2.c
+++ /dev/null
@@ -1,544 +0,0 @@
-/*
- * QEMU model of the Milkymist minimac2 block.
- *
- * Copyright (c) 2011 Michael Walle <michael@walle.cc>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * Specification available at:
- * not available yet
- *
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h" /* FIXME: why does this use TARGET_PAGE_ALIGN? */
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "net/net.h"
-#include "qemu/error-report.h"
-
-#include <zlib.h>
-
-enum {
- R_SETUP = 0,
- R_MDIO,
- R_STATE0,
- R_COUNT0,
- R_STATE1,
- R_COUNT1,
- R_TXCOUNT,
- R_MAX
-};
-
-enum {
- SETUP_PHY_RST = (1<<0),
-};
-
-enum {
- MDIO_DO = (1<<0),
- MDIO_DI = (1<<1),
- MDIO_OE = (1<<2),
- MDIO_CLK = (1<<3),
-};
-
-enum {
- STATE_EMPTY = 0,
- STATE_LOADED = 1,
- STATE_PENDING = 2,
-};
-
-enum {
- MDIO_OP_WRITE = 1,
- MDIO_OP_READ = 2,
-};
-
-enum mdio_state {
- MDIO_STATE_IDLE,
- MDIO_STATE_READING,
- MDIO_STATE_WRITING,
-};
-
-enum {
- R_PHY_ID1 = 2,
- R_PHY_ID2 = 3,
- R_PHY_MAX = 32
-};
-
-#define MINIMAC2_MTU 1530
-#define MINIMAC2_BUFFER_SIZE 2048
-
-struct MilkymistMinimac2MdioState {
- int last_clk;
- int count;
- uint32_t data;
- uint16_t data_out;
- int state;
-
- uint8_t phy_addr;
- uint8_t reg_addr;
-};
-typedef struct MilkymistMinimac2MdioState MilkymistMinimac2MdioState;
-
-#define TYPE_MILKYMIST_MINIMAC2 "milkymist-minimac2"
-#define MILKYMIST_MINIMAC2(obj) \
- OBJECT_CHECK(MilkymistMinimac2State, (obj), TYPE_MILKYMIST_MINIMAC2)
-
-struct MilkymistMinimac2State {
- SysBusDevice parent_obj;
-
- NICState *nic;
- NICConf conf;
- char *phy_model;
- MemoryRegion buffers;
- MemoryRegion regs_region;
-
- qemu_irq rx_irq;
- qemu_irq tx_irq;
-
- uint32_t regs[R_MAX];
-
- MilkymistMinimac2MdioState mdio;
-
- uint16_t phy_regs[R_PHY_MAX];
-
- uint8_t *rx0_buf;
- uint8_t *rx1_buf;
- uint8_t *tx_buf;
-};
-typedef struct MilkymistMinimac2State MilkymistMinimac2State;
-
-static const uint8_t preamble_sfd[] = {
- 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5
-};
-
-static void minimac2_mdio_write_reg(MilkymistMinimac2State *s,
- uint8_t phy_addr, uint8_t reg_addr, uint16_t value)
-{
- trace_milkymist_minimac2_mdio_write(phy_addr, reg_addr, value);
-
- /* nop */
-}
-
-static uint16_t minimac2_mdio_read_reg(MilkymistMinimac2State *s,
- uint8_t phy_addr, uint8_t reg_addr)
-{
- uint16_t r = s->phy_regs[reg_addr];
-
- trace_milkymist_minimac2_mdio_read(phy_addr, reg_addr, r);
-
- return r;
-}
-
-static void minimac2_update_mdio(MilkymistMinimac2State *s)
-{
- MilkymistMinimac2MdioState *m = &s->mdio;
-
- /* detect rising clk edge */
- if (m->last_clk == 0 && (s->regs[R_MDIO] & MDIO_CLK)) {
- /* shift data in */
- int bit = ((s->regs[R_MDIO] & MDIO_DO)
- && (s->regs[R_MDIO] & MDIO_OE)) ? 1 : 0;
- m->data = (m->data << 1) | bit;
-
- /* check for sync */
- if (m->data == 0xffffffff) {
- m->count = 32;
- }
-
- if (m->count == 16) {
- uint8_t start = (m->data >> 14) & 0x3;
- uint8_t op = (m->data >> 12) & 0x3;
- uint8_t ta = (m->data) & 0x3;
-
- if (start == 1 && op == MDIO_OP_WRITE && ta == 2) {
- m->state = MDIO_STATE_WRITING;
- } else if (start == 1 && op == MDIO_OP_READ && (ta & 1) == 0) {
- m->state = MDIO_STATE_READING;
- } else {
- m->state = MDIO_STATE_IDLE;
- }
-
- if (m->state != MDIO_STATE_IDLE) {
- m->phy_addr = (m->data >> 7) & 0x1f;
- m->reg_addr = (m->data >> 2) & 0x1f;
- }
-
- if (m->state == MDIO_STATE_READING) {
- m->data_out = minimac2_mdio_read_reg(s, m->phy_addr,
- m->reg_addr);
- }
- }
-
- if (m->count < 16 && m->state == MDIO_STATE_READING) {
- int bit = (m->data_out & 0x8000) ? 1 : 0;
- m->data_out <<= 1;
-
- if (bit) {
- s->regs[R_MDIO] |= MDIO_DI;
- } else {
- s->regs[R_MDIO] &= ~MDIO_DI;
- }
- }
-
- if (m->count == 0 && m->state) {
- if (m->state == MDIO_STATE_WRITING) {
- uint16_t data = m->data & 0xffff;
- minimac2_mdio_write_reg(s, m->phy_addr, m->reg_addr, data);
- }
- m->state = MDIO_STATE_IDLE;
- }
- m->count--;
- }
-
- m->last_clk = (s->regs[R_MDIO] & MDIO_CLK) ? 1 : 0;
-}
-
-static size_t assemble_frame(uint8_t *buf, size_t size,
- const uint8_t *payload, size_t payload_size)
-{
- uint32_t crc;
-
- if (size < payload_size + 12) {
- error_report("milkymist_minimac2: received too big ethernet frame");
- return 0;
- }
-
- /* prepend preamble and sfd */
- memcpy(buf, preamble_sfd, 8);
-
- /* now copy the payload */
- memcpy(buf + 8, payload, payload_size);
-
- /* pad frame if needed */
- if (payload_size < 60) {
- memset(buf + payload_size + 8, 0, 60 - payload_size);
- payload_size = 60;
- }
-
- /* append fcs */
- crc = cpu_to_le32(crc32(0, buf + 8, payload_size));
- memcpy(buf + payload_size + 8, &crc, 4);
-
- return payload_size + 12;
-}
-
-static void minimac2_tx(MilkymistMinimac2State *s)
-{
- uint32_t txcount = s->regs[R_TXCOUNT];
- uint8_t *buf = s->tx_buf;
-
- if (txcount < 64) {
- error_report("milkymist_minimac2: ethernet frame too small (%u < %u)",
- txcount, 64);
- goto err;
- }
-
- if (txcount > MINIMAC2_MTU) {
- error_report("milkymist_minimac2: MTU exceeded (%u > %u)",
- txcount, MINIMAC2_MTU);
- goto err;
- }
-
- if (memcmp(buf, preamble_sfd, 8) != 0) {
- error_report("milkymist_minimac2: frame doesn't contain the preamble "
- "and/or the SFD (%02x %02x %02x %02x %02x %02x %02x %02x)",
- buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
- goto err;
- }
-
- trace_milkymist_minimac2_tx_frame(txcount - 12);
-
- /* send packet, skipping preamble and sfd */
- qemu_send_packet_raw(qemu_get_queue(s->nic), buf + 8, txcount - 12);
-
- s->regs[R_TXCOUNT] = 0;
-
-err:
- trace_milkymist_minimac2_pulse_irq_tx();
- qemu_irq_pulse(s->tx_irq);
-}
-
-static void update_rx_interrupt(MilkymistMinimac2State *s)
-{
- if (s->regs[R_STATE0] == STATE_PENDING
- || s->regs[R_STATE1] == STATE_PENDING) {
- trace_milkymist_minimac2_raise_irq_rx();
- qemu_irq_raise(s->rx_irq);
- } else {
- trace_milkymist_minimac2_lower_irq_rx();
- qemu_irq_lower(s->rx_irq);
- }
-}
-
-static ssize_t minimac2_rx(NetClientState *nc, const uint8_t *buf, size_t size)
-{
- MilkymistMinimac2State *s = qemu_get_nic_opaque(nc);
-
- uint32_t r_count;
- uint32_t r_state;
- uint8_t *rx_buf;
-
- size_t frame_size;
-
- trace_milkymist_minimac2_rx_frame(buf, size);
-
- /* choose appropriate slot */
- if (s->regs[R_STATE0] == STATE_LOADED) {
- r_count = R_COUNT0;
- r_state = R_STATE0;
- rx_buf = s->rx0_buf;
- } else if (s->regs[R_STATE1] == STATE_LOADED) {
- r_count = R_COUNT1;
- r_state = R_STATE1;
- rx_buf = s->rx1_buf;
- } else {
- return 0;
- }
-
- /* assemble frame */
- frame_size = assemble_frame(rx_buf, MINIMAC2_BUFFER_SIZE, buf, size);
-
- if (frame_size == 0) {
- return size;
- }
-
- trace_milkymist_minimac2_rx_transfer(rx_buf, frame_size);
-
- /* update slot */
- s->regs[r_count] = frame_size;
- s->regs[r_state] = STATE_PENDING;
-
- update_rx_interrupt(s);
-
- return size;
-}
-
-static uint64_t
-minimac2_read(void *opaque, hwaddr addr, unsigned size)
-{
- MilkymistMinimac2State *s = opaque;
- uint32_t r = 0;
-
- addr >>= 2;
- switch (addr) {
- case R_SETUP:
- case R_MDIO:
- case R_STATE0:
- case R_COUNT0:
- case R_STATE1:
- case R_COUNT1:
- case R_TXCOUNT:
- r = s->regs[addr];
- break;
-
- default:
- error_report("milkymist_minimac2: read access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-
- trace_milkymist_minimac2_memory_read(addr << 2, r);
-
- return r;
-}
-
-static int minimac2_can_rx(MilkymistMinimac2State *s)
-{
- if (s->regs[R_STATE0] == STATE_LOADED) {
- return 1;
- }
- if (s->regs[R_STATE1] == STATE_LOADED) {
- return 1;
- }
-
- return 0;
-}
-
-static void
-minimac2_write(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
- MilkymistMinimac2State *s = opaque;
-
- trace_milkymist_minimac2_memory_write(addr, value);
-
- addr >>= 2;
- switch (addr) {
- case R_MDIO:
- {
- /* MDIO_DI is read only */
- int mdio_di = (s->regs[R_MDIO] & MDIO_DI);
- s->regs[R_MDIO] = value;
- if (mdio_di) {
- s->regs[R_MDIO] |= mdio_di;
- } else {
- s->regs[R_MDIO] &= ~mdio_di;
- }
-
- minimac2_update_mdio(s);
- } break;
- case R_TXCOUNT:
- s->regs[addr] = value;
- if (value > 0) {
- minimac2_tx(s);
- }
- break;
- case R_STATE0:
- case R_STATE1:
- s->regs[addr] = value;
- update_rx_interrupt(s);
- if (minimac2_can_rx(s)) {
- qemu_flush_queued_packets(qemu_get_queue(s->nic));
- }
- break;
- case R_SETUP:
- case R_COUNT0:
- case R_COUNT1:
- s->regs[addr] = value;
- break;
-
- default:
- error_report("milkymist_minimac2: write access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-}
-
-static const MemoryRegionOps minimac2_ops = {
- .read = minimac2_read,
- .write = minimac2_write,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void milkymist_minimac2_reset(DeviceState *d)
-{
- MilkymistMinimac2State *s = MILKYMIST_MINIMAC2(d);
- int i;
-
- for (i = 0; i < R_MAX; i++) {
- s->regs[i] = 0;
- }
- for (i = 0; i < R_PHY_MAX; i++) {
- s->phy_regs[i] = 0;
- }
-
- /* defaults */
- s->phy_regs[R_PHY_ID1] = 0x0022; /* Micrel KSZ8001L */
- s->phy_regs[R_PHY_ID2] = 0x161a;
-}
-
-static NetClientInfo net_milkymist_minimac2_info = {
- .type = NET_CLIENT_OPTIONS_KIND_NIC,
- .size = sizeof(NICState),
- .receive = minimac2_rx,
-};
-
-static int milkymist_minimac2_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- MilkymistMinimac2State *s = MILKYMIST_MINIMAC2(dev);
- size_t buffers_size = TARGET_PAGE_ALIGN(3 * MINIMAC2_BUFFER_SIZE);
-
- sysbus_init_irq(sbd, &s->rx_irq);
- sysbus_init_irq(sbd, &s->tx_irq);
-
- memory_region_init_io(&s->regs_region, OBJECT(dev), &minimac2_ops, s,
- "milkymist-minimac2", R_MAX * 4);
- sysbus_init_mmio(sbd, &s->regs_region);
-
- /* register buffers memory */
- memory_region_init_ram(&s->buffers, OBJECT(dev), "milkymist-minimac2.buffers",
- buffers_size, &error_fatal);
- vmstate_register_ram_global(&s->buffers);
- s->rx0_buf = memory_region_get_ram_ptr(&s->buffers);
- s->rx1_buf = s->rx0_buf + MINIMAC2_BUFFER_SIZE;
- s->tx_buf = s->rx1_buf + MINIMAC2_BUFFER_SIZE;
-
- sysbus_init_mmio(sbd, &s->buffers);
-
- qemu_macaddr_default_if_unset(&s->conf.macaddr);
- s->nic = qemu_new_nic(&net_milkymist_minimac2_info, &s->conf,
- object_get_typename(OBJECT(dev)), dev->id, s);
- qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-
- return 0;
-}
-
-static const VMStateDescription vmstate_milkymist_minimac2_mdio = {
- .name = "milkymist-minimac2-mdio",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_INT32(last_clk, MilkymistMinimac2MdioState),
- VMSTATE_INT32(count, MilkymistMinimac2MdioState),
- VMSTATE_UINT32(data, MilkymistMinimac2MdioState),
- VMSTATE_UINT16(data_out, MilkymistMinimac2MdioState),
- VMSTATE_INT32(state, MilkymistMinimac2MdioState),
- VMSTATE_UINT8(phy_addr, MilkymistMinimac2MdioState),
- VMSTATE_UINT8(reg_addr, MilkymistMinimac2MdioState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_milkymist_minimac2 = {
- .name = "milkymist-minimac2",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, MilkymistMinimac2State, R_MAX),
- VMSTATE_UINT16_ARRAY(phy_regs, MilkymistMinimac2State, R_PHY_MAX),
- VMSTATE_STRUCT(mdio, MilkymistMinimac2State, 0,
- vmstate_milkymist_minimac2_mdio, MilkymistMinimac2MdioState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property milkymist_minimac2_properties[] = {
- DEFINE_NIC_PROPERTIES(MilkymistMinimac2State, conf),
- DEFINE_PROP_STRING("phy_model", MilkymistMinimac2State, phy_model),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void milkymist_minimac2_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = milkymist_minimac2_init;
- dc->reset = milkymist_minimac2_reset;
- dc->vmsd = &vmstate_milkymist_minimac2;
- dc->props = milkymist_minimac2_properties;
-}
-
-static const TypeInfo milkymist_minimac2_info = {
- .name = TYPE_MILKYMIST_MINIMAC2,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(MilkymistMinimac2State),
- .class_init = milkymist_minimac2_class_init,
-};
-
-static void milkymist_minimac2_register_types(void)
-{
- type_register_static(&milkymist_minimac2_info);
-}
-
-type_init(milkymist_minimac2_register_types)
diff --git a/qemu/hw/net/mipsnet.c b/qemu/hw/net/mipsnet.c
deleted file mode 100644
index 740cd98ff..000000000
--- a/qemu/hw/net/mipsnet.c
+++ /dev/null
@@ -1,287 +0,0 @@
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "net/net.h"
-#include "trace.h"
-#include "hw/sysbus.h"
-
-/* MIPSnet register offsets */
-
-#define MIPSNET_DEV_ID 0x00
-#define MIPSNET_BUSY 0x08
-#define MIPSNET_RX_DATA_COUNT 0x0c
-#define MIPSNET_TX_DATA_COUNT 0x10
-#define MIPSNET_INT_CTL 0x14
-# define MIPSNET_INTCTL_TXDONE 0x00000001
-# define MIPSNET_INTCTL_RXDONE 0x00000002
-# define MIPSNET_INTCTL_TESTBIT 0x80000000
-#define MIPSNET_INTERRUPT_INFO 0x18
-#define MIPSNET_RX_DATA_BUFFER 0x1c
-#define MIPSNET_TX_DATA_BUFFER 0x20
-
-#define MAX_ETH_FRAME_SIZE 1514
-
-#define TYPE_MIPS_NET "mipsnet"
-#define MIPS_NET(obj) OBJECT_CHECK(MIPSnetState, (obj), TYPE_MIPS_NET)
-
-typedef struct MIPSnetState {
- SysBusDevice parent_obj;
-
- uint32_t busy;
- uint32_t rx_count;
- uint32_t rx_read;
- uint32_t tx_count;
- uint32_t tx_written;
- uint32_t intctl;
- uint8_t rx_buffer[MAX_ETH_FRAME_SIZE];
- uint8_t tx_buffer[MAX_ETH_FRAME_SIZE];
- MemoryRegion io;
- qemu_irq irq;
- NICState *nic;
- NICConf conf;
-} MIPSnetState;
-
-static void mipsnet_reset(MIPSnetState *s)
-{
- s->busy = 1;
- s->rx_count = 0;
- s->rx_read = 0;
- s->tx_count = 0;
- s->tx_written = 0;
- s->intctl = 0;
- memset(s->rx_buffer, 0, MAX_ETH_FRAME_SIZE);
- memset(s->tx_buffer, 0, MAX_ETH_FRAME_SIZE);
-}
-
-static void mipsnet_update_irq(MIPSnetState *s)
-{
- int isr = !!s->intctl;
- trace_mipsnet_irq(isr, s->intctl);
- qemu_set_irq(s->irq, isr);
-}
-
-static int mipsnet_buffer_full(MIPSnetState *s)
-{
- if (s->rx_count >= MAX_ETH_FRAME_SIZE)
- return 1;
- return 0;
-}
-
-static int mipsnet_can_receive(NetClientState *nc)
-{
- MIPSnetState *s = qemu_get_nic_opaque(nc);
-
- if (s->busy)
- return 0;
- return !mipsnet_buffer_full(s);
-}
-
-static ssize_t mipsnet_receive(NetClientState *nc, const uint8_t *buf, size_t size)
-{
- MIPSnetState *s = qemu_get_nic_opaque(nc);
-
- trace_mipsnet_receive(size);
- if (!mipsnet_can_receive(nc))
- return 0;
-
- s->busy = 1;
-
- /* Just accept everything. */
-
- /* Write packet data. */
- memcpy(s->rx_buffer, buf, size);
-
- s->rx_count = size;
- s->rx_read = 0;
-
- /* Now we can signal we have received something. */
- s->intctl |= MIPSNET_INTCTL_RXDONE;
- mipsnet_update_irq(s);
-
- return size;
-}
-
-static uint64_t mipsnet_ioport_read(void *opaque, hwaddr addr,
- unsigned int size)
-{
- MIPSnetState *s = opaque;
- int ret = 0;
-
- addr &= 0x3f;
- switch (addr) {
- case MIPSNET_DEV_ID:
- ret = be32_to_cpu(0x4d495053); /* MIPS */
- break;
- case MIPSNET_DEV_ID + 4:
- ret = be32_to_cpu(0x4e455430); /* NET0 */
- break;
- case MIPSNET_BUSY:
- ret = s->busy;
- break;
- case MIPSNET_RX_DATA_COUNT:
- ret = s->rx_count;
- break;
- case MIPSNET_TX_DATA_COUNT:
- ret = s->tx_count;
- break;
- case MIPSNET_INT_CTL:
- ret = s->intctl;
- s->intctl &= ~MIPSNET_INTCTL_TESTBIT;
- break;
- case MIPSNET_INTERRUPT_INFO:
- /* XXX: This seems to be a per-VPE interrupt number. */
- ret = 0;
- break;
- case MIPSNET_RX_DATA_BUFFER:
- if (s->rx_count) {
- s->rx_count--;
- ret = s->rx_buffer[s->rx_read++];
- if (mipsnet_can_receive(s->nic->ncs)) {
- qemu_flush_queued_packets(qemu_get_queue(s->nic));
- }
- }
- break;
- /* Reads as zero. */
- case MIPSNET_TX_DATA_BUFFER:
- default:
- break;
- }
- trace_mipsnet_read(addr, ret);
- return ret;
-}
-
-static void mipsnet_ioport_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned int size)
-{
- MIPSnetState *s = opaque;
-
- addr &= 0x3f;
- trace_mipsnet_write(addr, val);
- switch (addr) {
- case MIPSNET_TX_DATA_COUNT:
- s->tx_count = (val <= MAX_ETH_FRAME_SIZE) ? val : 0;
- s->tx_written = 0;
- break;
- case MIPSNET_INT_CTL:
- if (val & MIPSNET_INTCTL_TXDONE) {
- s->intctl &= ~MIPSNET_INTCTL_TXDONE;
- } else if (val & MIPSNET_INTCTL_RXDONE) {
- s->intctl &= ~MIPSNET_INTCTL_RXDONE;
- } else if (val & MIPSNET_INTCTL_TESTBIT) {
- mipsnet_reset(s);
- s->intctl |= MIPSNET_INTCTL_TESTBIT;
- } else if (!val) {
- /* ACK testbit interrupt, flag was cleared on read. */
- }
- s->busy = !!s->intctl;
- mipsnet_update_irq(s);
- if (mipsnet_can_receive(s->nic->ncs)) {
- qemu_flush_queued_packets(qemu_get_queue(s->nic));
- }
- break;
- case MIPSNET_TX_DATA_BUFFER:
- s->tx_buffer[s->tx_written++] = val;
- if (s->tx_written == s->tx_count) {
- /* Send buffer. */
- trace_mipsnet_send(s->tx_count);
- qemu_send_packet(qemu_get_queue(s->nic), s->tx_buffer, s->tx_count);
- s->tx_count = s->tx_written = 0;
- s->intctl |= MIPSNET_INTCTL_TXDONE;
- s->busy = 1;
- mipsnet_update_irq(s);
- }
- break;
- /* Read-only registers */
- case MIPSNET_DEV_ID:
- case MIPSNET_BUSY:
- case MIPSNET_RX_DATA_COUNT:
- case MIPSNET_INTERRUPT_INFO:
- case MIPSNET_RX_DATA_BUFFER:
- default:
- break;
- }
-}
-
-static const VMStateDescription vmstate_mipsnet = {
- .name = "mipsnet",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(busy, MIPSnetState),
- VMSTATE_UINT32(rx_count, MIPSnetState),
- VMSTATE_UINT32(rx_read, MIPSnetState),
- VMSTATE_UINT32(tx_count, MIPSnetState),
- VMSTATE_UINT32(tx_written, MIPSnetState),
- VMSTATE_UINT32(intctl, MIPSnetState),
- VMSTATE_BUFFER(rx_buffer, MIPSnetState),
- VMSTATE_BUFFER(tx_buffer, MIPSnetState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static NetClientInfo net_mipsnet_info = {
- .type = NET_CLIENT_OPTIONS_KIND_NIC,
- .size = sizeof(NICState),
- .receive = mipsnet_receive,
-};
-
-static const MemoryRegionOps mipsnet_ioport_ops = {
- .read = mipsnet_ioport_read,
- .write = mipsnet_ioport_write,
- .impl.min_access_size = 1,
- .impl.max_access_size = 4,
-};
-
-static int mipsnet_sysbus_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- MIPSnetState *s = MIPS_NET(dev);
-
- memory_region_init_io(&s->io, OBJECT(dev), &mipsnet_ioport_ops, s,
- "mipsnet-io", 36);
- sysbus_init_mmio(sbd, &s->io);
- sysbus_init_irq(sbd, &s->irq);
-
- s->nic = qemu_new_nic(&net_mipsnet_info, &s->conf,
- object_get_typename(OBJECT(dev)), dev->id, s);
- qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-
- return 0;
-}
-
-static void mipsnet_sysbus_reset(DeviceState *dev)
-{
- MIPSnetState *s = MIPS_NET(dev);
- mipsnet_reset(s);
-}
-
-static Property mipsnet_properties[] = {
- DEFINE_NIC_PROPERTIES(MIPSnetState, conf),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void mipsnet_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = mipsnet_sysbus_init;
- set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
- dc->desc = "MIPS Simulator network device";
- dc->reset = mipsnet_sysbus_reset;
- dc->vmsd = &vmstate_mipsnet;
- dc->props = mipsnet_properties;
-}
-
-static const TypeInfo mipsnet_info = {
- .name = TYPE_MIPS_NET,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(MIPSnetState),
- .class_init = mipsnet_class_init,
-};
-
-static void mipsnet_register_types(void)
-{
- type_register_static(&mipsnet_info);
-}
-
-type_init(mipsnet_register_types)
diff --git a/qemu/hw/net/ne2000-isa.c b/qemu/hw/net/ne2000-isa.c
deleted file mode 100644
index a7f5a9464..000000000
--- a/qemu/hw/net/ne2000-isa.c
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * QEMU NE2000 emulation -- isa bus windup
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/i386/pc.h"
-#include "hw/isa/isa.h"
-#include "hw/qdev.h"
-#include "net/net.h"
-#include "ne2000.h"
-#include "exec/address-spaces.h"
-#include "qapi/error.h"
-#include "qapi/visitor.h"
-
-#define TYPE_ISA_NE2000 "ne2k_isa"
-#define ISA_NE2000(obj) OBJECT_CHECK(ISANE2000State, (obj), TYPE_ISA_NE2000)
-
-typedef struct ISANE2000State {
- ISADevice parent_obj;
-
- uint32_t iobase;
- uint32_t isairq;
- NE2000State ne2000;
-} ISANE2000State;
-
-static NetClientInfo net_ne2000_isa_info = {
- .type = NET_CLIENT_OPTIONS_KIND_NIC,
- .size = sizeof(NICState),
- .receive = ne2000_receive,
-};
-
-static const VMStateDescription vmstate_isa_ne2000 = {
- .name = "ne2000",
- .version_id = 2,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT(ne2000, ISANE2000State, 0, vmstate_ne2000, NE2000State),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void isa_ne2000_realizefn(DeviceState *dev, Error **errp)
-{
- ISADevice *isadev = ISA_DEVICE(dev);
- ISANE2000State *isa = ISA_NE2000(dev);
- NE2000State *s = &isa->ne2000;
-
- ne2000_setup_io(s, DEVICE(isadev), 0x20);
- isa_register_ioport(isadev, &s->io, isa->iobase);
-
- isa_init_irq(isadev, &s->irq, isa->isairq);
-
- qemu_macaddr_default_if_unset(&s->c.macaddr);
- ne2000_reset(s);
-
- s->nic = qemu_new_nic(&net_ne2000_isa_info, &s->c,
- object_get_typename(OBJECT(dev)), dev->id, s);
- qemu_format_nic_info_str(qemu_get_queue(s->nic), s->c.macaddr.a);
-}
-
-static Property ne2000_isa_properties[] = {
- DEFINE_PROP_UINT32("iobase", ISANE2000State, iobase, 0x300),
- DEFINE_PROP_UINT32("irq", ISANE2000State, isairq, 9),
- DEFINE_NIC_PROPERTIES(ISANE2000State, ne2000.c),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void isa_ne2000_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = isa_ne2000_realizefn;
- dc->props = ne2000_isa_properties;
- dc->vmsd = &vmstate_isa_ne2000;
- set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
-}
-
-static void isa_ne2000_get_bootindex(Object *obj, Visitor *v,
- const char *name, void *opaque,
- Error **errp)
-{
- ISANE2000State *isa = ISA_NE2000(obj);
- NE2000State *s = &isa->ne2000;
-
- visit_type_int32(v, name, &s->c.bootindex, errp);
-}
-
-static void isa_ne2000_set_bootindex(Object *obj, Visitor *v,
- const char *name, void *opaque,
- Error **errp)
-{
- ISANE2000State *isa = ISA_NE2000(obj);
- NE2000State *s = &isa->ne2000;
- int32_t boot_index;
- Error *local_err = NULL;
-
- visit_type_int32(v, name, &boot_index, &local_err);
- if (local_err) {
- goto out;
- }
- /* check whether bootindex is present in fw_boot_order list */
- check_boot_index(boot_index, &local_err);
- if (local_err) {
- goto out;
- }
- /* change bootindex to a new one */
- s->c.bootindex = boot_index;
-
-out:
- if (local_err) {
- error_propagate(errp, local_err);
- }
-}
-
-static void isa_ne2000_instance_init(Object *obj)
-{
- object_property_add(obj, "bootindex", "int32",
- isa_ne2000_get_bootindex,
- isa_ne2000_set_bootindex, NULL, NULL, NULL);
- object_property_set_int(obj, -1, "bootindex", NULL);
-}
-static const TypeInfo ne2000_isa_info = {
- .name = TYPE_ISA_NE2000,
- .parent = TYPE_ISA_DEVICE,
- .instance_size = sizeof(ISANE2000State),
- .class_init = isa_ne2000_class_initfn,
- .instance_init = isa_ne2000_instance_init,
-};
-
-static void ne2000_isa_register_types(void)
-{
- type_register_static(&ne2000_isa_info);
-}
-
-type_init(ne2000_isa_register_types)
diff --git a/qemu/hw/net/ne2000.c b/qemu/hw/net/ne2000.c
deleted file mode 100644
index f0feaf96b..000000000
--- a/qemu/hw/net/ne2000.c
+++ /dev/null
@@ -1,796 +0,0 @@
-/*
- * QEMU NE2000 emulation
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/pci/pci.h"
-#include "net/net.h"
-#include "ne2000.h"
-#include "hw/loader.h"
-#include "sysemu/sysemu.h"
-
-/* debug NE2000 card */
-//#define DEBUG_NE2000
-
-#define MAX_ETH_FRAME_SIZE 1514
-
-#define E8390_CMD 0x00 /* The command register (for all pages) */
-/* Page 0 register offsets. */
-#define EN0_CLDALO 0x01 /* Low byte of current local dma addr RD */
-#define EN0_STARTPG 0x01 /* Starting page of ring bfr WR */
-#define EN0_CLDAHI 0x02 /* High byte of current local dma addr RD */
-#define EN0_STOPPG 0x02 /* Ending page +1 of ring bfr WR */
-#define EN0_BOUNDARY 0x03 /* Boundary page of ring bfr RD WR */
-#define EN0_TSR 0x04 /* Transmit status reg RD */
-#define EN0_TPSR 0x04 /* Transmit starting page WR */
-#define EN0_NCR 0x05 /* Number of collision reg RD */
-#define EN0_TCNTLO 0x05 /* Low byte of tx byte count WR */
-#define EN0_FIFO 0x06 /* FIFO RD */
-#define EN0_TCNTHI 0x06 /* High byte of tx byte count WR */
-#define EN0_ISR 0x07 /* Interrupt status reg RD WR */
-#define EN0_CRDALO 0x08 /* low byte of current remote dma address RD */
-#define EN0_RSARLO 0x08 /* Remote start address reg 0 */
-#define EN0_CRDAHI 0x09 /* high byte, current remote dma address RD */
-#define EN0_RSARHI 0x09 /* Remote start address reg 1 */
-#define EN0_RCNTLO 0x0a /* Remote byte count reg WR */
-#define EN0_RTL8029ID0 0x0a /* Realtek ID byte #1 RD */
-#define EN0_RCNTHI 0x0b /* Remote byte count reg WR */
-#define EN0_RTL8029ID1 0x0b /* Realtek ID byte #2 RD */
-#define EN0_RSR 0x0c /* rx status reg RD */
-#define EN0_RXCR 0x0c /* RX configuration reg WR */
-#define EN0_TXCR 0x0d /* TX configuration reg WR */
-#define EN0_COUNTER0 0x0d /* Rcv alignment error counter RD */
-#define EN0_DCFG 0x0e /* Data configuration reg WR */
-#define EN0_COUNTER1 0x0e /* Rcv CRC error counter RD */
-#define EN0_IMR 0x0f /* Interrupt mask reg WR */
-#define EN0_COUNTER2 0x0f /* Rcv missed frame error counter RD */
-
-#define EN1_PHYS 0x11
-#define EN1_CURPAG 0x17
-#define EN1_MULT 0x18
-
-#define EN2_STARTPG 0x21 /* Starting page of ring bfr RD */
-#define EN2_STOPPG 0x22 /* Ending page +1 of ring bfr RD */
-
-#define EN3_CONFIG0 0x33
-#define EN3_CONFIG1 0x34
-#define EN3_CONFIG2 0x35
-#define EN3_CONFIG3 0x36
-
-/* Register accessed at EN_CMD, the 8390 base addr. */
-#define E8390_STOP 0x01 /* Stop and reset the chip */
-#define E8390_START 0x02 /* Start the chip, clear reset */
-#define E8390_TRANS 0x04 /* Transmit a frame */
-#define E8390_RREAD 0x08 /* Remote read */
-#define E8390_RWRITE 0x10 /* Remote write */
-#define E8390_NODMA 0x20 /* Remote DMA */
-#define E8390_PAGE0 0x00 /* Select page chip registers */
-#define E8390_PAGE1 0x40 /* using the two high-order bits */
-#define E8390_PAGE2 0x80 /* Page 3 is invalid. */
-
-/* Bits in EN0_ISR - Interrupt status register */
-#define ENISR_RX 0x01 /* Receiver, no error */
-#define ENISR_TX 0x02 /* Transmitter, no error */
-#define ENISR_RX_ERR 0x04 /* Receiver, with error */
-#define ENISR_TX_ERR 0x08 /* Transmitter, with error */
-#define ENISR_OVER 0x10 /* Receiver overwrote the ring */
-#define ENISR_COUNTERS 0x20 /* Counters need emptying */
-#define ENISR_RDC 0x40 /* remote dma complete */
-#define ENISR_RESET 0x80 /* Reset completed */
-#define ENISR_ALL 0x3f /* Interrupts we will enable */
-
-/* Bits in received packet status byte and EN0_RSR*/
-#define ENRSR_RXOK 0x01 /* Received a good packet */
-#define ENRSR_CRC 0x02 /* CRC error */
-#define ENRSR_FAE 0x04 /* frame alignment error */
-#define ENRSR_FO 0x08 /* FIFO overrun */
-#define ENRSR_MPA 0x10 /* missed pkt */
-#define ENRSR_PHY 0x20 /* physical/multicast address */
-#define ENRSR_DIS 0x40 /* receiver disable. set in monitor mode */
-#define ENRSR_DEF 0x80 /* deferring */
-
-/* Transmitted packet status, EN0_TSR. */
-#define ENTSR_PTX 0x01 /* Packet transmitted without error */
-#define ENTSR_ND 0x02 /* The transmit wasn't deferred. */
-#define ENTSR_COL 0x04 /* The transmit collided at least once. */
-#define ENTSR_ABT 0x08 /* The transmit collided 16 times, and was deferred. */
-#define ENTSR_CRS 0x10 /* The carrier sense was lost. */
-#define ENTSR_FU 0x20 /* A "FIFO underrun" occurred during transmit. */
-#define ENTSR_CDH 0x40 /* The collision detect "heartbeat" signal was lost. */
-#define ENTSR_OWC 0x80 /* There was an out-of-window collision. */
-
-typedef struct PCINE2000State {
- PCIDevice dev;
- NE2000State ne2000;
-} PCINE2000State;
-
-void ne2000_reset(NE2000State *s)
-{
- int i;
-
- s->isr = ENISR_RESET;
- memcpy(s->mem, &s->c.macaddr, 6);
- s->mem[14] = 0x57;
- s->mem[15] = 0x57;
-
- /* duplicate prom data */
- for(i = 15;i >= 0; i--) {
- s->mem[2 * i] = s->mem[i];
- s->mem[2 * i + 1] = s->mem[i];
- }
-}
-
-static void ne2000_update_irq(NE2000State *s)
-{
- int isr;
- isr = (s->isr & s->imr) & 0x7f;
-#if defined(DEBUG_NE2000)
- printf("NE2000: Set IRQ to %d (%02x %02x)\n",
- isr ? 1 : 0, s->isr, s->imr);
-#endif
- qemu_set_irq(s->irq, (isr != 0));
-}
-
-static int ne2000_buffer_full(NE2000State *s)
-{
- int avail, index, boundary;
-
- if (s->stop <= s->start) {
- return 1;
- }
-
- index = s->curpag << 8;
- boundary = s->boundary << 8;
- if (index < boundary)
- avail = boundary - index;
- else
- avail = (s->stop - s->start) - (index - boundary);
- if (avail < (MAX_ETH_FRAME_SIZE + 4))
- return 1;
- return 0;
-}
-
-#define MIN_BUF_SIZE 60
-
-ssize_t ne2000_receive(NetClientState *nc, const uint8_t *buf, size_t size_)
-{
- NE2000State *s = qemu_get_nic_opaque(nc);
- int size = size_;
- uint8_t *p;
- unsigned int total_len, next, avail, len, index, mcast_idx;
- uint8_t buf1[60];
- static const uint8_t broadcast_macaddr[6] =
- { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-
-#if defined(DEBUG_NE2000)
- printf("NE2000: received len=%d\n", size);
-#endif
-
- if (s->cmd & E8390_STOP || ne2000_buffer_full(s))
- return -1;
-
- /* XXX: check this */
- if (s->rxcr & 0x10) {
- /* promiscuous: receive all */
- } else {
- if (!memcmp(buf, broadcast_macaddr, 6)) {
- /* broadcast address */
- if (!(s->rxcr & 0x04))
- return size;
- } else if (buf[0] & 0x01) {
- /* multicast */
- if (!(s->rxcr & 0x08))
- return size;
- mcast_idx = compute_mcast_idx(buf);
- if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))))
- return size;
- } else if (s->mem[0] == buf[0] &&
- s->mem[2] == buf[1] &&
- s->mem[4] == buf[2] &&
- s->mem[6] == buf[3] &&
- s->mem[8] == buf[4] &&
- s->mem[10] == buf[5]) {
- /* match */
- } else {
- return size;
- }
- }
-
-
- /* if too small buffer, then expand it */
- if (size < MIN_BUF_SIZE) {
- memcpy(buf1, buf, size);
- memset(buf1 + size, 0, MIN_BUF_SIZE - size);
- buf = buf1;
- size = MIN_BUF_SIZE;
- }
-
- index = s->curpag << 8;
- if (index >= NE2000_PMEM_END) {
- index = s->start;
- }
- /* 4 bytes for header */
- total_len = size + 4;
- /* address for next packet (4 bytes for CRC) */
- next = index + ((total_len + 4 + 255) & ~0xff);
- if (next >= s->stop)
- next -= (s->stop - s->start);
- /* prepare packet header */
- p = s->mem + index;
- s->rsr = ENRSR_RXOK; /* receive status */
- /* XXX: check this */
- if (buf[0] & 0x01)
- s->rsr |= ENRSR_PHY;
- p[0] = s->rsr;
- p[1] = next >> 8;
- p[2] = total_len;
- p[3] = total_len >> 8;
- index += 4;
-
- /* write packet data */
- while (size > 0) {
- if (index <= s->stop)
- avail = s->stop - index;
- else
- break;
- len = size;
- if (len > avail)
- len = avail;
- memcpy(s->mem + index, buf, len);
- buf += len;
- index += len;
- if (index == s->stop)
- index = s->start;
- size -= len;
- }
- s->curpag = next >> 8;
-
- /* now we can signal we have received something */
- s->isr |= ENISR_RX;
- ne2000_update_irq(s);
-
- return size_;
-}
-
-static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val)
-{
- NE2000State *s = opaque;
- int offset, page, index;
-
- addr &= 0xf;
-#ifdef DEBUG_NE2000
- printf("NE2000: write addr=0x%x val=0x%02x\n", addr, val);
-#endif
- if (addr == E8390_CMD) {
- /* control register */
- s->cmd = val;
- if (!(val & E8390_STOP)) { /* START bit makes no sense on RTL8029... */
- s->isr &= ~ENISR_RESET;
- /* test specific case: zero length transfer */
- if ((val & (E8390_RREAD | E8390_RWRITE)) &&
- s->rcnt == 0) {
- s->isr |= ENISR_RDC;
- ne2000_update_irq(s);
- }
- if (val & E8390_TRANS) {
- index = (s->tpsr << 8);
- /* XXX: next 2 lines are a hack to make netware 3.11 work */
- if (index >= NE2000_PMEM_END)
- index -= NE2000_PMEM_SIZE;
- /* fail safe: check range on the transmitted length */
- if (index + s->tcnt <= NE2000_PMEM_END) {
- qemu_send_packet(qemu_get_queue(s->nic), s->mem + index,
- s->tcnt);
- }
- /* signal end of transfer */
- s->tsr = ENTSR_PTX;
- s->isr |= ENISR_TX;
- s->cmd &= ~E8390_TRANS;
- ne2000_update_irq(s);
- }
- }
- } else {
- page = s->cmd >> 6;
- offset = addr | (page << 4);
- switch(offset) {
- case EN0_STARTPG:
- if (val << 8 <= NE2000_PMEM_END) {
- s->start = val << 8;
- }
- break;
- case EN0_STOPPG:
- if (val << 8 <= NE2000_PMEM_END) {
- s->stop = val << 8;
- }
- break;
- case EN0_BOUNDARY:
- if (val << 8 < NE2000_PMEM_END) {
- s->boundary = val;
- }
- break;
- case EN0_IMR:
- s->imr = val;
- ne2000_update_irq(s);
- break;
- case EN0_TPSR:
- s->tpsr = val;
- break;
- case EN0_TCNTLO:
- s->tcnt = (s->tcnt & 0xff00) | val;
- break;
- case EN0_TCNTHI:
- s->tcnt = (s->tcnt & 0x00ff) | (val << 8);
- break;
- case EN0_RSARLO:
- s->rsar = (s->rsar & 0xff00) | val;
- break;
- case EN0_RSARHI:
- s->rsar = (s->rsar & 0x00ff) | (val << 8);
- break;
- case EN0_RCNTLO:
- s->rcnt = (s->rcnt & 0xff00) | val;
- break;
- case EN0_RCNTHI:
- s->rcnt = (s->rcnt & 0x00ff) | (val << 8);
- break;
- case EN0_RXCR:
- s->rxcr = val;
- break;
- case EN0_DCFG:
- s->dcfg = val;
- break;
- case EN0_ISR:
- s->isr &= ~(val & 0x7f);
- ne2000_update_irq(s);
- break;
- case EN1_PHYS ... EN1_PHYS + 5:
- s->phys[offset - EN1_PHYS] = val;
- break;
- case EN1_CURPAG:
- if (val << 8 < NE2000_PMEM_END) {
- s->curpag = val;
- }
- break;
- case EN1_MULT ... EN1_MULT + 7:
- s->mult[offset - EN1_MULT] = val;
- break;
- }
- }
-}
-
-static uint32_t ne2000_ioport_read(void *opaque, uint32_t addr)
-{
- NE2000State *s = opaque;
- int offset, page, ret;
-
- addr &= 0xf;
- if (addr == E8390_CMD) {
- ret = s->cmd;
- } else {
- page = s->cmd >> 6;
- offset = addr | (page << 4);
- switch(offset) {
- case EN0_TSR:
- ret = s->tsr;
- break;
- case EN0_BOUNDARY:
- ret = s->boundary;
- break;
- case EN0_ISR:
- ret = s->isr;
- break;
- case EN0_RSARLO:
- ret = s->rsar & 0x00ff;
- break;
- case EN0_RSARHI:
- ret = s->rsar >> 8;
- break;
- case EN1_PHYS ... EN1_PHYS + 5:
- ret = s->phys[offset - EN1_PHYS];
- break;
- case EN1_CURPAG:
- ret = s->curpag;
- break;
- case EN1_MULT ... EN1_MULT + 7:
- ret = s->mult[offset - EN1_MULT];
- break;
- case EN0_RSR:
- ret = s->rsr;
- break;
- case EN2_STARTPG:
- ret = s->start >> 8;
- break;
- case EN2_STOPPG:
- ret = s->stop >> 8;
- break;
- case EN0_RTL8029ID0:
- ret = 0x50;
- break;
- case EN0_RTL8029ID1:
- ret = 0x43;
- break;
- case EN3_CONFIG0:
- ret = 0; /* 10baseT media */
- break;
- case EN3_CONFIG2:
- ret = 0x40; /* 10baseT active */
- break;
- case EN3_CONFIG3:
- ret = 0x40; /* Full duplex */
- break;
- default:
- ret = 0x00;
- break;
- }
- }
-#ifdef DEBUG_NE2000
- printf("NE2000: read addr=0x%x val=%02x\n", addr, ret);
-#endif
- return ret;
-}
-
-static inline void ne2000_mem_writeb(NE2000State *s, uint32_t addr,
- uint32_t val)
-{
- if (addr < 32 ||
- (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
- s->mem[addr] = val;
- }
-}
-
-static inline void ne2000_mem_writew(NE2000State *s, uint32_t addr,
- uint32_t val)
-{
- addr &= ~1; /* XXX: check exact behaviour if not even */
- if (addr < 32 ||
- (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
- *(uint16_t *)(s->mem + addr) = cpu_to_le16(val);
- }
-}
-
-static inline void ne2000_mem_writel(NE2000State *s, uint32_t addr,
- uint32_t val)
-{
- addr &= ~1; /* XXX: check exact behaviour if not even */
- if (addr < 32
- || (addr >= NE2000_PMEM_START
- && addr + sizeof(uint32_t) <= NE2000_MEM_SIZE)) {
- stl_le_p(s->mem + addr, val);
- }
-}
-
-static inline uint32_t ne2000_mem_readb(NE2000State *s, uint32_t addr)
-{
- if (addr < 32 ||
- (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
- return s->mem[addr];
- } else {
- return 0xff;
- }
-}
-
-static inline uint32_t ne2000_mem_readw(NE2000State *s, uint32_t addr)
-{
- addr &= ~1; /* XXX: check exact behaviour if not even */
- if (addr < 32 ||
- (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
- return le16_to_cpu(*(uint16_t *)(s->mem + addr));
- } else {
- return 0xffff;
- }
-}
-
-static inline uint32_t ne2000_mem_readl(NE2000State *s, uint32_t addr)
-{
- addr &= ~1; /* XXX: check exact behaviour if not even */
- if (addr < 32
- || (addr >= NE2000_PMEM_START
- && addr + sizeof(uint32_t) <= NE2000_MEM_SIZE)) {
- return ldl_le_p(s->mem + addr);
- } else {
- return 0xffffffff;
- }
-}
-
-static inline void ne2000_dma_update(NE2000State *s, int len)
-{
- s->rsar += len;
- /* wrap */
- /* XXX: check what to do if rsar > stop */
- if (s->rsar == s->stop)
- s->rsar = s->start;
-
- if (s->rcnt <= len) {
- s->rcnt = 0;
- /* signal end of transfer */
- s->isr |= ENISR_RDC;
- ne2000_update_irq(s);
- } else {
- s->rcnt -= len;
- }
-}
-
-static void ne2000_asic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
-{
- NE2000State *s = opaque;
-
-#ifdef DEBUG_NE2000
- printf("NE2000: asic write val=0x%04x\n", val);
-#endif
- if (s->rcnt == 0)
- return;
- if (s->dcfg & 0x01) {
- /* 16 bit access */
- ne2000_mem_writew(s, s->rsar, val);
- ne2000_dma_update(s, 2);
- } else {
- /* 8 bit access */
- ne2000_mem_writeb(s, s->rsar, val);
- ne2000_dma_update(s, 1);
- }
-}
-
-static uint32_t ne2000_asic_ioport_read(void *opaque, uint32_t addr)
-{
- NE2000State *s = opaque;
- int ret;
-
- if (s->dcfg & 0x01) {
- /* 16 bit access */
- ret = ne2000_mem_readw(s, s->rsar);
- ne2000_dma_update(s, 2);
- } else {
- /* 8 bit access */
- ret = ne2000_mem_readb(s, s->rsar);
- ne2000_dma_update(s, 1);
- }
-#ifdef DEBUG_NE2000
- printf("NE2000: asic read val=0x%04x\n", ret);
-#endif
- return ret;
-}
-
-static void ne2000_asic_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
-{
- NE2000State *s = opaque;
-
-#ifdef DEBUG_NE2000
- printf("NE2000: asic writel val=0x%04x\n", val);
-#endif
- if (s->rcnt == 0)
- return;
- /* 32 bit access */
- ne2000_mem_writel(s, s->rsar, val);
- ne2000_dma_update(s, 4);
-}
-
-static uint32_t ne2000_asic_ioport_readl(void *opaque, uint32_t addr)
-{
- NE2000State *s = opaque;
- int ret;
-
- /* 32 bit access */
- ret = ne2000_mem_readl(s, s->rsar);
- ne2000_dma_update(s, 4);
-#ifdef DEBUG_NE2000
- printf("NE2000: asic readl val=0x%04x\n", ret);
-#endif
- return ret;
-}
-
-static void ne2000_reset_ioport_write(void *opaque, uint32_t addr, uint32_t val)
-{
- /* nothing to do (end of reset pulse) */
-}
-
-static uint32_t ne2000_reset_ioport_read(void *opaque, uint32_t addr)
-{
- NE2000State *s = opaque;
- ne2000_reset(s);
- return 0;
-}
-
-static int ne2000_post_load(void* opaque, int version_id)
-{
- NE2000State* s = opaque;
-
- if (version_id < 2) {
- s->rxcr = 0x0c;
- }
- return 0;
-}
-
-const VMStateDescription vmstate_ne2000 = {
- .name = "ne2000",
- .version_id = 2,
- .minimum_version_id = 0,
- .post_load = ne2000_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8_V(rxcr, NE2000State, 2),
- VMSTATE_UINT8(cmd, NE2000State),
- VMSTATE_UINT32(start, NE2000State),
- VMSTATE_UINT32(stop, NE2000State),
- VMSTATE_UINT8(boundary, NE2000State),
- VMSTATE_UINT8(tsr, NE2000State),
- VMSTATE_UINT8(tpsr, NE2000State),
- VMSTATE_UINT16(tcnt, NE2000State),
- VMSTATE_UINT16(rcnt, NE2000State),
- VMSTATE_UINT32(rsar, NE2000State),
- VMSTATE_UINT8(rsr, NE2000State),
- VMSTATE_UINT8(isr, NE2000State),
- VMSTATE_UINT8(dcfg, NE2000State),
- VMSTATE_UINT8(imr, NE2000State),
- VMSTATE_BUFFER(phys, NE2000State),
- VMSTATE_UINT8(curpag, NE2000State),
- VMSTATE_BUFFER(mult, NE2000State),
- VMSTATE_UNUSED(4), /* was irq */
- VMSTATE_BUFFER(mem, NE2000State),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_pci_ne2000 = {
- .name = "ne2000",
- .version_id = 3,
- .minimum_version_id = 3,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(dev, PCINE2000State),
- VMSTATE_STRUCT(ne2000, PCINE2000State, 0, vmstate_ne2000, NE2000State),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static uint64_t ne2000_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- NE2000State *s = opaque;
-
- if (addr < 0x10 && size == 1) {
- return ne2000_ioport_read(s, addr);
- } else if (addr == 0x10) {
- if (size <= 2) {
- return ne2000_asic_ioport_read(s, addr);
- } else {
- return ne2000_asic_ioport_readl(s, addr);
- }
- } else if (addr == 0x1f && size == 1) {
- return ne2000_reset_ioport_read(s, addr);
- }
- return ((uint64_t)1 << (size * 8)) - 1;
-}
-
-static void ne2000_write(void *opaque, hwaddr addr,
- uint64_t data, unsigned size)
-{
- NE2000State *s = opaque;
-
- if (addr < 0x10 && size == 1) {
- ne2000_ioport_write(s, addr, data);
- } else if (addr == 0x10) {
- if (size <= 2) {
- ne2000_asic_ioport_write(s, addr, data);
- } else {
- ne2000_asic_ioport_writel(s, addr, data);
- }
- } else if (addr == 0x1f && size == 1) {
- ne2000_reset_ioport_write(s, addr, data);
- }
-}
-
-static const MemoryRegionOps ne2000_ops = {
- .read = ne2000_read,
- .write = ne2000_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-/***********************************************************/
-/* PCI NE2000 definitions */
-
-void ne2000_setup_io(NE2000State *s, DeviceState *dev, unsigned size)
-{
- memory_region_init_io(&s->io, OBJECT(dev), &ne2000_ops, s, "ne2000", size);
-}
-
-static NetClientInfo net_ne2000_info = {
- .type = NET_CLIENT_OPTIONS_KIND_NIC,
- .size = sizeof(NICState),
- .receive = ne2000_receive,
-};
-
-static void pci_ne2000_realize(PCIDevice *pci_dev, Error **errp)
-{
- PCINE2000State *d = DO_UPCAST(PCINE2000State, dev, pci_dev);
- NE2000State *s;
- uint8_t *pci_conf;
-
- pci_conf = d->dev.config;
- pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */
-
- s = &d->ne2000;
- ne2000_setup_io(s, DEVICE(pci_dev), 0x100);
- pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io);
- s->irq = pci_allocate_irq(&d->dev);
-
- qemu_macaddr_default_if_unset(&s->c.macaddr);
- ne2000_reset(s);
-
- s->nic = qemu_new_nic(&net_ne2000_info, &s->c,
- object_get_typename(OBJECT(pci_dev)), pci_dev->qdev.id, s);
- qemu_format_nic_info_str(qemu_get_queue(s->nic), s->c.macaddr.a);
-}
-
-static void pci_ne2000_exit(PCIDevice *pci_dev)
-{
- PCINE2000State *d = DO_UPCAST(PCINE2000State, dev, pci_dev);
- NE2000State *s = &d->ne2000;
-
- qemu_del_nic(s->nic);
- qemu_free_irq(s->irq);
-}
-
-static void ne2000_instance_init(Object *obj)
-{
- PCIDevice *pci_dev = PCI_DEVICE(obj);
- PCINE2000State *d = DO_UPCAST(PCINE2000State, dev, pci_dev);
- NE2000State *s = &d->ne2000;
-
- device_add_bootindex_property(obj, &s->c.bootindex,
- "bootindex", "/ethernet-phy@0",
- &pci_dev->qdev, NULL);
-}
-
-static Property ne2000_properties[] = {
- DEFINE_NIC_PROPERTIES(PCINE2000State, ne2000.c),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void ne2000_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = pci_ne2000_realize;
- k->exit = pci_ne2000_exit;
- k->romfile = "efi-ne2k_pci.rom",
- k->vendor_id = PCI_VENDOR_ID_REALTEK;
- k->device_id = PCI_DEVICE_ID_REALTEK_8029;
- k->class_id = PCI_CLASS_NETWORK_ETHERNET;
- dc->vmsd = &vmstate_pci_ne2000;
- dc->props = ne2000_properties;
- set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
-}
-
-static const TypeInfo ne2000_info = {
- .name = "ne2k_pci",
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(PCINE2000State),
- .class_init = ne2000_class_init,
- .instance_init = ne2000_instance_init,
-};
-
-static void ne2000_register_types(void)
-{
- type_register_static(&ne2000_info);
-}
-
-type_init(ne2000_register_types)
diff --git a/qemu/hw/net/ne2000.h b/qemu/hw/net/ne2000.h
deleted file mode 100644
index d022b28fc..000000000
--- a/qemu/hw/net/ne2000.h
+++ /dev/null
@@ -1,39 +0,0 @@
-#ifndef HW_NE2000_H
-#define HW_NE2000_H 1
-
-#define NE2000_PMEM_SIZE (32*1024)
-#define NE2000_PMEM_START (16*1024)
-#define NE2000_PMEM_END (NE2000_PMEM_SIZE+NE2000_PMEM_START)
-#define NE2000_MEM_SIZE NE2000_PMEM_END
-
-typedef struct NE2000State {
- MemoryRegion io;
- uint8_t cmd;
- uint32_t start;
- uint32_t stop;
- uint8_t boundary;
- uint8_t tsr;
- uint8_t tpsr;
- uint16_t tcnt;
- uint16_t rcnt;
- uint32_t rsar;
- uint8_t rsr;
- uint8_t rxcr;
- uint8_t isr;
- uint8_t dcfg;
- uint8_t imr;
- uint8_t phys[6]; /* mac address */
- uint8_t curpag;
- uint8_t mult[8]; /* multicast mask array */
- qemu_irq irq;
- NICState *nic;
- NICConf c;
- uint8_t mem[NE2000_MEM_SIZE];
-} NE2000State;
-
-void ne2000_setup_io(NE2000State *s, DeviceState *dev, unsigned size);
-extern const VMStateDescription vmstate_ne2000;
-void ne2000_reset(NE2000State *s);
-ssize_t ne2000_receive(NetClientState *nc, const uint8_t *buf, size_t size_);
-
-#endif
diff --git a/qemu/hw/net/opencores_eth.c b/qemu/hw/net/opencores_eth.c
deleted file mode 100644
index c6094fbb5..000000000
--- a/qemu/hw/net/opencores_eth.c
+++ /dev/null
@@ -1,765 +0,0 @@
-/*
- * OpenCores Ethernet MAC 10/100 + subset of
- * National Semiconductors DP83848C 10/100 PHY
- *
- * http://opencores.org/svnget,ethmac?file=%2Ftrunk%2F%2Fdoc%2Feth_speci.pdf
- * http://cache.national.com/ds/DP/DP83848C.pdf
- *
- * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of the Open Source and Linux Lab nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "net/net.h"
-#include "sysemu/sysemu.h"
-#include "trace.h"
-
-/* RECSMALL is not used because it breaks tap networking in linux:
- * incoming ARP responses are too short
- */
-#undef USE_RECSMALL
-
-#define GET_FIELD(v, field) (((v) & (field)) >> (field ## _LBN))
-#define GET_REGBIT(s, reg, field) ((s)->regs[reg] & (reg ## _ ## field))
-#define GET_REGFIELD(s, reg, field) \
- GET_FIELD((s)->regs[reg], reg ## _ ## field)
-
-#define SET_FIELD(v, field, data) \
- ((v) = (((v) & ~(field)) | (((data) << (field ## _LBN)) & (field))))
-#define SET_REGFIELD(s, reg, field, data) \
- SET_FIELD((s)->regs[reg], reg ## _ ## field, data)
-
-/* PHY MII registers */
-enum {
- MII_BMCR,
- MII_BMSR,
- MII_PHYIDR1,
- MII_PHYIDR2,
- MII_ANAR,
- MII_ANLPAR,
- MII_REG_MAX = 16,
-};
-
-typedef struct Mii {
- uint16_t regs[MII_REG_MAX];
- bool link_ok;
-} Mii;
-
-static void mii_set_link(Mii *s, bool link_ok)
-{
- if (link_ok) {
- s->regs[MII_BMSR] |= 0x4;
- s->regs[MII_ANLPAR] |= 0x01e1;
- } else {
- s->regs[MII_BMSR] &= ~0x4;
- s->regs[MII_ANLPAR] &= 0x01ff;
- }
- s->link_ok = link_ok;
-}
-
-static void mii_reset(Mii *s)
-{
- memset(s->regs, 0, sizeof(s->regs));
- s->regs[MII_BMCR] = 0x1000;
- s->regs[MII_BMSR] = 0x7868; /* no ext regs */
- s->regs[MII_PHYIDR1] = 0x2000;
- s->regs[MII_PHYIDR2] = 0x5c90;
- s->regs[MII_ANAR] = 0x01e1;
- mii_set_link(s, s->link_ok);
-}
-
-static void mii_ro(Mii *s, uint16_t v)
-{
-}
-
-static void mii_write_bmcr(Mii *s, uint16_t v)
-{
- if (v & 0x8000) {
- mii_reset(s);
- } else {
- s->regs[MII_BMCR] = v;
- }
-}
-
-static void mii_write_host(Mii *s, unsigned idx, uint16_t v)
-{
- static void (*reg_write[MII_REG_MAX])(Mii *s, uint16_t v) = {
- [MII_BMCR] = mii_write_bmcr,
- [MII_BMSR] = mii_ro,
- [MII_PHYIDR1] = mii_ro,
- [MII_PHYIDR2] = mii_ro,
- };
-
- if (idx < MII_REG_MAX) {
- trace_open_eth_mii_write(idx, v);
- if (reg_write[idx]) {
- reg_write[idx](s, v);
- } else {
- s->regs[idx] = v;
- }
- }
-}
-
-static uint16_t mii_read_host(Mii *s, unsigned idx)
-{
- trace_open_eth_mii_read(idx, s->regs[idx]);
- return s->regs[idx];
-}
-
-/* OpenCores Ethernet registers */
-enum {
- MODER,
- INT_SOURCE,
- INT_MASK,
- IPGT,
- IPGR1,
- IPGR2,
- PACKETLEN,
- COLLCONF,
- TX_BD_NUM,
- CTRLMODER,
- MIIMODER,
- MIICOMMAND,
- MIIADDRESS,
- MIITX_DATA,
- MIIRX_DATA,
- MIISTATUS,
- MAC_ADDR0,
- MAC_ADDR1,
- HASH0,
- HASH1,
- TXCTRL,
- REG_MAX,
-};
-
-enum {
- MODER_RECSMALL = 0x10000,
- MODER_PAD = 0x8000,
- MODER_HUGEN = 0x4000,
- MODER_RST = 0x800,
- MODER_LOOPBCK = 0x80,
- MODER_PRO = 0x20,
- MODER_IAM = 0x10,
- MODER_BRO = 0x8,
- MODER_TXEN = 0x2,
- MODER_RXEN = 0x1,
-};
-
-enum {
- INT_SOURCE_BUSY = 0x10,
- INT_SOURCE_RXB = 0x4,
- INT_SOURCE_TXB = 0x1,
-};
-
-enum {
- PACKETLEN_MINFL = 0xffff0000,
- PACKETLEN_MINFL_LBN = 16,
- PACKETLEN_MAXFL = 0xffff,
- PACKETLEN_MAXFL_LBN = 0,
-};
-
-enum {
- MIICOMMAND_WCTRLDATA = 0x4,
- MIICOMMAND_RSTAT = 0x2,
- MIICOMMAND_SCANSTAT = 0x1,
-};
-
-enum {
- MIIADDRESS_RGAD = 0x1f00,
- MIIADDRESS_RGAD_LBN = 8,
- MIIADDRESS_FIAD = 0x1f,
- MIIADDRESS_FIAD_LBN = 0,
-};
-
-enum {
- MIITX_DATA_CTRLDATA = 0xffff,
- MIITX_DATA_CTRLDATA_LBN = 0,
-};
-
-enum {
- MIIRX_DATA_PRSD = 0xffff,
- MIIRX_DATA_PRSD_LBN = 0,
-};
-
-enum {
- MIISTATUS_LINKFAIL = 0x1,
- MIISTATUS_LINKFAIL_LBN = 0,
-};
-
-enum {
- MAC_ADDR0_BYTE2 = 0xff000000,
- MAC_ADDR0_BYTE2_LBN = 24,
- MAC_ADDR0_BYTE3 = 0xff0000,
- MAC_ADDR0_BYTE3_LBN = 16,
- MAC_ADDR0_BYTE4 = 0xff00,
- MAC_ADDR0_BYTE4_LBN = 8,
- MAC_ADDR0_BYTE5 = 0xff,
- MAC_ADDR0_BYTE5_LBN = 0,
-};
-
-enum {
- MAC_ADDR1_BYTE0 = 0xff00,
- MAC_ADDR1_BYTE0_LBN = 8,
- MAC_ADDR1_BYTE1 = 0xff,
- MAC_ADDR1_BYTE1_LBN = 0,
-};
-
-enum {
- TXD_LEN = 0xffff0000,
- TXD_LEN_LBN = 16,
- TXD_RD = 0x8000,
- TXD_IRQ = 0x4000,
- TXD_WR = 0x2000,
- TXD_PAD = 0x1000,
- TXD_CRC = 0x800,
- TXD_UR = 0x100,
- TXD_RTRY = 0xf0,
- TXD_RTRY_LBN = 4,
- TXD_RL = 0x8,
- TXD_LC = 0x4,
- TXD_DF = 0x2,
- TXD_CS = 0x1,
-};
-
-enum {
- RXD_LEN = 0xffff0000,
- RXD_LEN_LBN = 16,
- RXD_E = 0x8000,
- RXD_IRQ = 0x4000,
- RXD_WRAP = 0x2000,
- RXD_CF = 0x100,
- RXD_M = 0x80,
- RXD_OR = 0x40,
- RXD_IS = 0x20,
- RXD_DN = 0x10,
- RXD_TL = 0x8,
- RXD_SF = 0x4,
- RXD_CRC = 0x2,
- RXD_LC = 0x1,
-};
-
-typedef struct desc {
- uint32_t len_flags;
- uint32_t buf_ptr;
-} desc;
-
-#define DEFAULT_PHY 1
-
-#define TYPE_OPEN_ETH "open_eth"
-#define OPEN_ETH(obj) OBJECT_CHECK(OpenEthState, (obj), TYPE_OPEN_ETH)
-
-typedef struct OpenEthState {
- SysBusDevice parent_obj;
-
- NICState *nic;
- NICConf conf;
- MemoryRegion reg_io;
- MemoryRegion desc_io;
- qemu_irq irq;
-
- Mii mii;
- uint32_t regs[REG_MAX];
- unsigned tx_desc;
- unsigned rx_desc;
- desc desc[128];
-} OpenEthState;
-
-static desc *rx_desc(OpenEthState *s)
-{
- return s->desc + s->rx_desc;
-}
-
-static desc *tx_desc(OpenEthState *s)
-{
- return s->desc + s->tx_desc;
-}
-
-static void open_eth_update_irq(OpenEthState *s,
- uint32_t old, uint32_t new)
-{
- if (!old != !new) {
- trace_open_eth_update_irq(new);
- qemu_set_irq(s->irq, new);
- }
-}
-
-static void open_eth_int_source_write(OpenEthState *s,
- uint32_t val)
-{
- uint32_t old_val = s->regs[INT_SOURCE];
-
- s->regs[INT_SOURCE] = val;
- open_eth_update_irq(s, old_val & s->regs[INT_MASK],
- s->regs[INT_SOURCE] & s->regs[INT_MASK]);
-}
-
-static void open_eth_set_link_status(NetClientState *nc)
-{
- OpenEthState *s = qemu_get_nic_opaque(nc);
-
- if (GET_REGBIT(s, MIICOMMAND, SCANSTAT)) {
- SET_REGFIELD(s, MIISTATUS, LINKFAIL, nc->link_down);
- }
- mii_set_link(&s->mii, !nc->link_down);
-}
-
-static void open_eth_reset(void *opaque)
-{
- OpenEthState *s = opaque;
-
- memset(s->regs, 0, sizeof(s->regs));
- s->regs[MODER] = 0xa000;
- s->regs[IPGT] = 0x12;
- s->regs[IPGR1] = 0xc;
- s->regs[IPGR2] = 0x12;
- s->regs[PACKETLEN] = 0x400600;
- s->regs[COLLCONF] = 0xf003f;
- s->regs[TX_BD_NUM] = 0x40;
- s->regs[MIIMODER] = 0x64;
-
- s->tx_desc = 0;
- s->rx_desc = 0x40;
-
- mii_reset(&s->mii);
- open_eth_set_link_status(qemu_get_queue(s->nic));
-}
-
-static int open_eth_can_receive(NetClientState *nc)
-{
- OpenEthState *s = qemu_get_nic_opaque(nc);
-
- return GET_REGBIT(s, MODER, RXEN) &&
- (s->regs[TX_BD_NUM] < 0x80);
-}
-
-static ssize_t open_eth_receive(NetClientState *nc,
- const uint8_t *buf, size_t size)
-{
- OpenEthState *s = qemu_get_nic_opaque(nc);
- size_t maxfl = GET_REGFIELD(s, PACKETLEN, MAXFL);
- size_t minfl = GET_REGFIELD(s, PACKETLEN, MINFL);
- size_t fcsl = 4;
- bool miss = true;
-
- trace_open_eth_receive((unsigned)size);
-
- if (size >= 6) {
- static const uint8_t bcast_addr[] = {
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
- };
- if (memcmp(buf, bcast_addr, sizeof(bcast_addr)) == 0) {
- miss = GET_REGBIT(s, MODER, BRO);
- } else if ((buf[0] & 0x1) || GET_REGBIT(s, MODER, IAM)) {
- unsigned mcast_idx = compute_mcast_idx(buf);
- miss = !(s->regs[HASH0 + mcast_idx / 32] &
- (1 << (mcast_idx % 32)));
- trace_open_eth_receive_mcast(
- mcast_idx, s->regs[HASH0], s->regs[HASH1]);
- } else {
- miss = GET_REGFIELD(s, MAC_ADDR1, BYTE0) != buf[0] ||
- GET_REGFIELD(s, MAC_ADDR1, BYTE1) != buf[1] ||
- GET_REGFIELD(s, MAC_ADDR0, BYTE2) != buf[2] ||
- GET_REGFIELD(s, MAC_ADDR0, BYTE3) != buf[3] ||
- GET_REGFIELD(s, MAC_ADDR0, BYTE4) != buf[4] ||
- GET_REGFIELD(s, MAC_ADDR0, BYTE5) != buf[5];
- }
- }
-
- if (miss && !GET_REGBIT(s, MODER, PRO)) {
- trace_open_eth_receive_reject();
- return size;
- }
-
-#ifdef USE_RECSMALL
- if (GET_REGBIT(s, MODER, RECSMALL) || size >= minfl) {
-#else
- {
-#endif
- static const uint8_t zero[64] = {0};
- desc *desc = rx_desc(s);
- size_t copy_size = GET_REGBIT(s, MODER, HUGEN) ? 65536 : maxfl;
-
- if (!(desc->len_flags & RXD_E)) {
- open_eth_int_source_write(s,
- s->regs[INT_SOURCE] | INT_SOURCE_BUSY);
- return size;
- }
-
- desc->len_flags &= ~(RXD_CF | RXD_M | RXD_OR |
- RXD_IS | RXD_DN | RXD_TL | RXD_SF | RXD_CRC | RXD_LC);
-
- if (copy_size > size) {
- copy_size = size;
- } else {
- fcsl = 0;
- }
- if (miss) {
- desc->len_flags |= RXD_M;
- }
- if (GET_REGBIT(s, MODER, HUGEN) && size > maxfl) {
- desc->len_flags |= RXD_TL;
- }
-#ifdef USE_RECSMALL
- if (size < minfl) {
- desc->len_flags |= RXD_SF;
- }
-#endif
-
- cpu_physical_memory_write(desc->buf_ptr, buf, copy_size);
-
- if (GET_REGBIT(s, MODER, PAD) && copy_size < minfl) {
- if (minfl - copy_size > fcsl) {
- fcsl = 0;
- } else {
- fcsl -= minfl - copy_size;
- }
- while (copy_size < minfl) {
- size_t zero_sz = minfl - copy_size < sizeof(zero) ?
- minfl - copy_size : sizeof(zero);
-
- cpu_physical_memory_write(desc->buf_ptr + copy_size,
- zero, zero_sz);
- copy_size += zero_sz;
- }
- }
-
- /* There's no FCS in the frames handed to us by the QEMU, zero fill it.
- * Don't do it if the frame is cut at the MAXFL or padded with 4 or
- * more bytes to the MINFL.
- */
- cpu_physical_memory_write(desc->buf_ptr + copy_size, zero, fcsl);
- copy_size += fcsl;
-
- SET_FIELD(desc->len_flags, RXD_LEN, copy_size);
-
- if ((desc->len_flags & RXD_WRAP) || s->rx_desc == 0x7f) {
- s->rx_desc = s->regs[TX_BD_NUM];
- } else {
- ++s->rx_desc;
- }
- desc->len_flags &= ~RXD_E;
-
- trace_open_eth_receive_desc(desc->buf_ptr, desc->len_flags);
-
- if (desc->len_flags & RXD_IRQ) {
- open_eth_int_source_write(s,
- s->regs[INT_SOURCE] | INT_SOURCE_RXB);
- }
- }
- return size;
-}
-
-static NetClientInfo net_open_eth_info = {
- .type = NET_CLIENT_OPTIONS_KIND_NIC,
- .size = sizeof(NICState),
- .can_receive = open_eth_can_receive,
- .receive = open_eth_receive,
- .link_status_changed = open_eth_set_link_status,
-};
-
-static void open_eth_start_xmit(OpenEthState *s, desc *tx)
-{
- uint8_t buf[65536];
- unsigned len = GET_FIELD(tx->len_flags, TXD_LEN);
- unsigned tx_len = len;
-
- if ((tx->len_flags & TXD_PAD) &&
- tx_len < GET_REGFIELD(s, PACKETLEN, MINFL)) {
- tx_len = GET_REGFIELD(s, PACKETLEN, MINFL);
- }
- if (!GET_REGBIT(s, MODER, HUGEN) &&
- tx_len > GET_REGFIELD(s, PACKETLEN, MAXFL)) {
- tx_len = GET_REGFIELD(s, PACKETLEN, MAXFL);
- }
-
- trace_open_eth_start_xmit(tx->buf_ptr, len, tx_len);
-
- if (len > tx_len) {
- len = tx_len;
- }
- cpu_physical_memory_read(tx->buf_ptr, buf, len);
- if (tx_len > len) {
- memset(buf + len, 0, tx_len - len);
- }
- qemu_send_packet(qemu_get_queue(s->nic), buf, tx_len);
-
- if (tx->len_flags & TXD_WR) {
- s->tx_desc = 0;
- } else {
- ++s->tx_desc;
- if (s->tx_desc >= s->regs[TX_BD_NUM]) {
- s->tx_desc = 0;
- }
- }
- tx->len_flags &= ~(TXD_RD | TXD_UR |
- TXD_RTRY | TXD_RL | TXD_LC | TXD_DF | TXD_CS);
- if (tx->len_flags & TXD_IRQ) {
- open_eth_int_source_write(s, s->regs[INT_SOURCE] | INT_SOURCE_TXB);
- }
-
-}
-
-static void open_eth_check_start_xmit(OpenEthState *s)
-{
- desc *tx = tx_desc(s);
- if (GET_REGBIT(s, MODER, TXEN) && s->regs[TX_BD_NUM] > 0 &&
- (tx->len_flags & TXD_RD) &&
- GET_FIELD(tx->len_flags, TXD_LEN) > 4) {
- open_eth_start_xmit(s, tx);
- }
-}
-
-static uint64_t open_eth_reg_read(void *opaque,
- hwaddr addr, unsigned int size)
-{
- static uint32_t (*reg_read[REG_MAX])(OpenEthState *s) = {
- };
- OpenEthState *s = opaque;
- unsigned idx = addr / 4;
- uint64_t v = 0;
-
- if (idx < REG_MAX) {
- if (reg_read[idx]) {
- v = reg_read[idx](s);
- } else {
- v = s->regs[idx];
- }
- }
- trace_open_eth_reg_read((uint32_t)addr, (uint32_t)v);
- return v;
-}
-
-static void open_eth_notify_can_receive(OpenEthState *s)
-{
- NetClientState *nc = qemu_get_queue(s->nic);
-
- if (open_eth_can_receive(nc)) {
- qemu_flush_queued_packets(nc);
- }
-}
-
-static void open_eth_ro(OpenEthState *s, uint32_t val)
-{
-}
-
-static void open_eth_moder_host_write(OpenEthState *s, uint32_t val)
-{
- uint32_t set = val & ~s->regs[MODER];
-
- if (set & MODER_RST) {
- open_eth_reset(s);
- }
-
- s->regs[MODER] = val;
-
- if (set & MODER_RXEN) {
- s->rx_desc = s->regs[TX_BD_NUM];
- open_eth_notify_can_receive(s);
- }
- if (set & MODER_TXEN) {
- s->tx_desc = 0;
- open_eth_check_start_xmit(s);
- }
-}
-
-static void open_eth_int_source_host_write(OpenEthState *s, uint32_t val)
-{
- uint32_t old = s->regs[INT_SOURCE];
-
- s->regs[INT_SOURCE] &= ~val;
- open_eth_update_irq(s, old & s->regs[INT_MASK],
- s->regs[INT_SOURCE] & s->regs[INT_MASK]);
-}
-
-static void open_eth_int_mask_host_write(OpenEthState *s, uint32_t val)
-{
- uint32_t old = s->regs[INT_MASK];
-
- s->regs[INT_MASK] = val;
- open_eth_update_irq(s, s->regs[INT_SOURCE] & old,
- s->regs[INT_SOURCE] & s->regs[INT_MASK]);
-}
-
-static void open_eth_tx_bd_num_host_write(OpenEthState *s, uint32_t val)
-{
- if (val < 0x80) {
- bool enable = s->regs[TX_BD_NUM] == 0x80;
-
- s->regs[TX_BD_NUM] = val;
- if (enable) {
- open_eth_notify_can_receive(s);
- }
- }
-}
-
-static void open_eth_mii_command_host_write(OpenEthState *s, uint32_t val)
-{
- unsigned fiad = GET_REGFIELD(s, MIIADDRESS, FIAD);
- unsigned rgad = GET_REGFIELD(s, MIIADDRESS, RGAD);
-
- if (val & MIICOMMAND_WCTRLDATA) {
- if (fiad == DEFAULT_PHY) {
- mii_write_host(&s->mii, rgad,
- GET_REGFIELD(s, MIITX_DATA, CTRLDATA));
- }
- }
- if (val & MIICOMMAND_RSTAT) {
- if (fiad == DEFAULT_PHY) {
- SET_REGFIELD(s, MIIRX_DATA, PRSD,
- mii_read_host(&s->mii, rgad));
- } else {
- s->regs[MIIRX_DATA] = 0xffff;
- }
- SET_REGFIELD(s, MIISTATUS, LINKFAIL, qemu_get_queue(s->nic)->link_down);
- }
-}
-
-static void open_eth_mii_tx_host_write(OpenEthState *s, uint32_t val)
-{
- SET_REGFIELD(s, MIITX_DATA, CTRLDATA, val);
- if (GET_REGFIELD(s, MIIADDRESS, FIAD) == DEFAULT_PHY) {
- mii_write_host(&s->mii, GET_REGFIELD(s, MIIADDRESS, RGAD),
- GET_REGFIELD(s, MIITX_DATA, CTRLDATA));
- }
-}
-
-static void open_eth_reg_write(void *opaque,
- hwaddr addr, uint64_t val, unsigned int size)
-{
- static void (*reg_write[REG_MAX])(OpenEthState *s, uint32_t val) = {
- [MODER] = open_eth_moder_host_write,
- [INT_SOURCE] = open_eth_int_source_host_write,
- [INT_MASK] = open_eth_int_mask_host_write,
- [TX_BD_NUM] = open_eth_tx_bd_num_host_write,
- [MIICOMMAND] = open_eth_mii_command_host_write,
- [MIITX_DATA] = open_eth_mii_tx_host_write,
- [MIISTATUS] = open_eth_ro,
- };
- OpenEthState *s = opaque;
- unsigned idx = addr / 4;
-
- if (idx < REG_MAX) {
- trace_open_eth_reg_write((uint32_t)addr, (uint32_t)val);
- if (reg_write[idx]) {
- reg_write[idx](s, val);
- } else {
- s->regs[idx] = val;
- }
- }
-}
-
-static uint64_t open_eth_desc_read(void *opaque,
- hwaddr addr, unsigned int size)
-{
- OpenEthState *s = opaque;
- uint64_t v = 0;
-
- addr &= 0x3ff;
- memcpy(&v, (uint8_t *)s->desc + addr, size);
- trace_open_eth_desc_read((uint32_t)addr, (uint32_t)v);
- return v;
-}
-
-static void open_eth_desc_write(void *opaque,
- hwaddr addr, uint64_t val, unsigned int size)
-{
- OpenEthState *s = opaque;
-
- addr &= 0x3ff;
- trace_open_eth_desc_write((uint32_t)addr, (uint32_t)val);
- memcpy((uint8_t *)s->desc + addr, &val, size);
- open_eth_check_start_xmit(s);
-}
-
-
-static const MemoryRegionOps open_eth_reg_ops = {
- .read = open_eth_reg_read,
- .write = open_eth_reg_write,
-};
-
-static const MemoryRegionOps open_eth_desc_ops = {
- .read = open_eth_desc_read,
- .write = open_eth_desc_write,
-};
-
-static int sysbus_open_eth_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- OpenEthState *s = OPEN_ETH(dev);
-
- memory_region_init_io(&s->reg_io, OBJECT(dev), &open_eth_reg_ops, s,
- "open_eth.regs", 0x54);
- sysbus_init_mmio(sbd, &s->reg_io);
-
- memory_region_init_io(&s->desc_io, OBJECT(dev), &open_eth_desc_ops, s,
- "open_eth.desc", 0x400);
- sysbus_init_mmio(sbd, &s->desc_io);
-
- sysbus_init_irq(sbd, &s->irq);
-
- s->nic = qemu_new_nic(&net_open_eth_info, &s->conf,
- object_get_typename(OBJECT(s)), dev->id, s);
- return 0;
-}
-
-static void qdev_open_eth_reset(DeviceState *dev)
-{
- OpenEthState *d = OPEN_ETH(dev);
-
- open_eth_reset(d);
-}
-
-static Property open_eth_properties[] = {
- DEFINE_NIC_PROPERTIES(OpenEthState, conf),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void open_eth_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = sysbus_open_eth_init;
- set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
- dc->desc = "Opencores 10/100 Mbit Ethernet";
- dc->reset = qdev_open_eth_reset;
- dc->props = open_eth_properties;
-}
-
-static const TypeInfo open_eth_info = {
- .name = TYPE_OPEN_ETH,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(OpenEthState),
- .class_init = open_eth_class_init,
-};
-
-static void open_eth_register_types(void)
-{
- type_register_static(&open_eth_info);
-}
-
-type_init(open_eth_register_types)
diff --git a/qemu/hw/net/pcnet-pci.c b/qemu/hw/net/pcnet-pci.c
deleted file mode 100644
index 595439a65..000000000
--- a/qemu/hw/net/pcnet-pci.c
+++ /dev/null
@@ -1,375 +0,0 @@
-/*
- * QEMU AMD PC-Net II (Am79C970A) PCI emulation
- *
- * Copyright (c) 2004 Antony T Curtis
- *
- * 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.
- */
-
-/* This software was written to be compatible with the specification:
- * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet
- * AMD Publication# 19436 Rev:E Amendment/0 Issue Date: June 2000
- */
-
-#include "qemu/osdep.h"
-#include "hw/pci/pci.h"
-#include "net/net.h"
-#include "hw/loader.h"
-#include "qemu/timer.h"
-#include "sysemu/dma.h"
-#include "sysemu/sysemu.h"
-#include "trace.h"
-
-#include "pcnet.h"
-
-//#define PCNET_DEBUG
-//#define PCNET_DEBUG_IO
-//#define PCNET_DEBUG_BCR
-//#define PCNET_DEBUG_CSR
-//#define PCNET_DEBUG_RMD
-//#define PCNET_DEBUG_TMD
-//#define PCNET_DEBUG_MATCH
-
-#define TYPE_PCI_PCNET "pcnet"
-
-#define PCI_PCNET(obj) \
- OBJECT_CHECK(PCIPCNetState, (obj), TYPE_PCI_PCNET)
-
-typedef struct {
- /*< private >*/
- PCIDevice parent_obj;
- /*< public >*/
-
- PCNetState state;
- MemoryRegion io_bar;
-} PCIPCNetState;
-
-static void pcnet_aprom_writeb(void *opaque, uint32_t addr, uint32_t val)
-{
- PCNetState *s = opaque;
-
- trace_pcnet_aprom_writeb(opaque, addr, val);
- if (BCR_APROMWE(s)) {
- s->prom[addr & 15] = val;
- }
-}
-
-static uint32_t pcnet_aprom_readb(void *opaque, uint32_t addr)
-{
- PCNetState *s = opaque;
- uint32_t val = s->prom[addr & 15];
-
- trace_pcnet_aprom_readb(opaque, addr, val);
- return val;
-}
-
-static uint64_t pcnet_ioport_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- PCNetState *d = opaque;
-
- trace_pcnet_ioport_read(opaque, addr, size);
- if (addr < 0x10) {
- if (!BCR_DWIO(d) && size == 1) {
- return pcnet_aprom_readb(d, addr);
- } else if (!BCR_DWIO(d) && (addr & 1) == 0 && size == 2) {
- return pcnet_aprom_readb(d, addr) |
- (pcnet_aprom_readb(d, addr + 1) << 8);
- } else if (BCR_DWIO(d) && (addr & 3) == 0 && size == 4) {
- return pcnet_aprom_readb(d, addr) |
- (pcnet_aprom_readb(d, addr + 1) << 8) |
- (pcnet_aprom_readb(d, addr + 2) << 16) |
- (pcnet_aprom_readb(d, addr + 3) << 24);
- }
- } else {
- if (size == 2) {
- return pcnet_ioport_readw(d, addr);
- } else if (size == 4) {
- return pcnet_ioport_readl(d, addr);
- }
- }
- return ((uint64_t)1 << (size * 8)) - 1;
-}
-
-static void pcnet_ioport_write(void *opaque, hwaddr addr,
- uint64_t data, unsigned size)
-{
- PCNetState *d = opaque;
-
- trace_pcnet_ioport_write(opaque, addr, data, size);
- if (addr < 0x10) {
- if (!BCR_DWIO(d) && size == 1) {
- pcnet_aprom_writeb(d, addr, data);
- } else if (!BCR_DWIO(d) && (addr & 1) == 0 && size == 2) {
- pcnet_aprom_writeb(d, addr, data & 0xff);
- pcnet_aprom_writeb(d, addr + 1, data >> 8);
- } else if (BCR_DWIO(d) && (addr & 3) == 0 && size == 4) {
- pcnet_aprom_writeb(d, addr, data & 0xff);
- pcnet_aprom_writeb(d, addr + 1, (data >> 8) & 0xff);
- pcnet_aprom_writeb(d, addr + 2, (data >> 16) & 0xff);
- pcnet_aprom_writeb(d, addr + 3, data >> 24);
- }
- } else {
- if (size == 2) {
- pcnet_ioport_writew(d, addr, data);
- } else if (size == 4) {
- pcnet_ioport_writel(d, addr, data);
- }
- }
-}
-
-static const MemoryRegionOps pcnet_io_ops = {
- .read = pcnet_ioport_read,
- .write = pcnet_ioport_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void pcnet_mmio_writeb(void *opaque, hwaddr addr, uint32_t val)
-{
- PCNetState *d = opaque;
-
- trace_pcnet_mmio_writeb(opaque, addr, val);
- if (!(addr & 0x10))
- pcnet_aprom_writeb(d, addr & 0x0f, val);
-}
-
-static uint32_t pcnet_mmio_readb(void *opaque, hwaddr addr)
-{
- PCNetState *d = opaque;
- uint32_t val = -1;
-
- if (!(addr & 0x10))
- val = pcnet_aprom_readb(d, addr & 0x0f);
- trace_pcnet_mmio_readb(opaque, addr, val);
- return val;
-}
-
-static void pcnet_mmio_writew(void *opaque, hwaddr addr, uint32_t val)
-{
- PCNetState *d = opaque;
-
- trace_pcnet_mmio_writew(opaque, addr, val);
- if (addr & 0x10)
- pcnet_ioport_writew(d, addr & 0x0f, val);
- else {
- addr &= 0x0f;
- pcnet_aprom_writeb(d, addr, val & 0xff);
- pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8);
- }
-}
-
-static uint32_t pcnet_mmio_readw(void *opaque, hwaddr addr)
-{
- PCNetState *d = opaque;
- uint32_t val = -1;
-
- if (addr & 0x10)
- val = pcnet_ioport_readw(d, addr & 0x0f);
- else {
- addr &= 0x0f;
- val = pcnet_aprom_readb(d, addr+1);
- val <<= 8;
- val |= pcnet_aprom_readb(d, addr);
- }
- trace_pcnet_mmio_readw(opaque, addr, val);
- return val;
-}
-
-static void pcnet_mmio_writel(void *opaque, hwaddr addr, uint32_t val)
-{
- PCNetState *d = opaque;
-
- trace_pcnet_mmio_writel(opaque, addr, val);
- if (addr & 0x10)
- pcnet_ioport_writel(d, addr & 0x0f, val);
- else {
- addr &= 0x0f;
- pcnet_aprom_writeb(d, addr, val & 0xff);
- pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8);
- pcnet_aprom_writeb(d, addr+2, (val & 0xff0000) >> 16);
- pcnet_aprom_writeb(d, addr+3, (val & 0xff000000) >> 24);
- }
-}
-
-static uint32_t pcnet_mmio_readl(void *opaque, hwaddr addr)
-{
- PCNetState *d = opaque;
- uint32_t val;
-
- if (addr & 0x10)
- val = pcnet_ioport_readl(d, addr & 0x0f);
- else {
- addr &= 0x0f;
- val = pcnet_aprom_readb(d, addr+3);
- val <<= 8;
- val |= pcnet_aprom_readb(d, addr+2);
- val <<= 8;
- val |= pcnet_aprom_readb(d, addr+1);
- val <<= 8;
- val |= pcnet_aprom_readb(d, addr);
- }
- trace_pcnet_mmio_readl(opaque, addr, val);
- return val;
-}
-
-static const VMStateDescription vmstate_pci_pcnet = {
- .name = "pcnet",
- .version_id = 3,
- .minimum_version_id = 2,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(parent_obj, PCIPCNetState),
- VMSTATE_STRUCT(state, PCIPCNetState, 0, vmstate_pcnet, PCNetState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-/* PCI interface */
-
-static const MemoryRegionOps pcnet_mmio_ops = {
- .old_mmio = {
- .read = { pcnet_mmio_readb, pcnet_mmio_readw, pcnet_mmio_readl },
- .write = { pcnet_mmio_writeb, pcnet_mmio_writew, pcnet_mmio_writel },
- },
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void pci_physical_memory_write(void *dma_opaque, hwaddr addr,
- uint8_t *buf, int len, int do_bswap)
-{
- pci_dma_write(dma_opaque, addr, buf, len);
-}
-
-static void pci_physical_memory_read(void *dma_opaque, hwaddr addr,
- uint8_t *buf, int len, int do_bswap)
-{
- pci_dma_read(dma_opaque, addr, buf, len);
-}
-
-static void pci_pcnet_uninit(PCIDevice *dev)
-{
- PCIPCNetState *d = PCI_PCNET(dev);
-
- qemu_free_irq(d->state.irq);
- timer_del(d->state.poll_timer);
- timer_free(d->state.poll_timer);
- qemu_del_nic(d->state.nic);
-}
-
-static NetClientInfo net_pci_pcnet_info = {
- .type = NET_CLIENT_OPTIONS_KIND_NIC,
- .size = sizeof(NICState),
- .receive = pcnet_receive,
- .link_status_changed = pcnet_set_link_status,
-};
-
-static void pci_pcnet_realize(PCIDevice *pci_dev, Error **errp)
-{
- PCIPCNetState *d = PCI_PCNET(pci_dev);
- PCNetState *s = &d->state;
- uint8_t *pci_conf;
-
-#if 0
- printf("sizeof(RMD)=%d, sizeof(TMD)=%d\n",
- sizeof(struct pcnet_RMD), sizeof(struct pcnet_TMD));
-#endif
-
- pci_conf = pci_dev->config;
-
- pci_set_word(pci_conf + PCI_STATUS,
- PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM);
-
- pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, 0x0);
- pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, 0x0);
-
- pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */
- pci_conf[PCI_MIN_GNT] = 0x06;
- pci_conf[PCI_MAX_LAT] = 0xff;
-
- /* Handler for memory-mapped I/O */
- memory_region_init_io(&d->state.mmio, OBJECT(d), &pcnet_mmio_ops, s,
- "pcnet-mmio", PCNET_PNPMMIO_SIZE);
-
- memory_region_init_io(&d->io_bar, OBJECT(d), &pcnet_io_ops, s, "pcnet-io",
- PCNET_IOPORT_SIZE);
- pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &d->io_bar);
-
- pci_register_bar(pci_dev, 1, 0, &s->mmio);
-
- s->irq = pci_allocate_irq(pci_dev);
- s->phys_mem_read = pci_physical_memory_read;
- s->phys_mem_write = pci_physical_memory_write;
- s->dma_opaque = pci_dev;
-
- pcnet_common_init(DEVICE(pci_dev), s, &net_pci_pcnet_info);
-}
-
-static void pci_reset(DeviceState *dev)
-{
- PCIPCNetState *d = PCI_PCNET(dev);
-
- pcnet_h_reset(&d->state);
-}
-
-static void pcnet_instance_init(Object *obj)
-{
- PCIPCNetState *d = PCI_PCNET(obj);
- PCNetState *s = &d->state;
-
- device_add_bootindex_property(obj, &s->conf.bootindex,
- "bootindex", "/ethernet-phy@0",
- DEVICE(obj), NULL);
-}
-
-static Property pcnet_properties[] = {
- DEFINE_NIC_PROPERTIES(PCIPCNetState, state.conf),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pcnet_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = pci_pcnet_realize;
- k->exit = pci_pcnet_uninit;
- k->romfile = "efi-pcnet.rom",
- k->vendor_id = PCI_VENDOR_ID_AMD;
- k->device_id = PCI_DEVICE_ID_AMD_LANCE;
- k->revision = 0x10;
- k->class_id = PCI_CLASS_NETWORK_ETHERNET;
- dc->reset = pci_reset;
- dc->vmsd = &vmstate_pci_pcnet;
- dc->props = pcnet_properties;
- set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
-}
-
-static const TypeInfo pcnet_info = {
- .name = TYPE_PCI_PCNET,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(PCIPCNetState),
- .class_init = pcnet_class_init,
- .instance_init = pcnet_instance_init,
-};
-
-static void pci_pcnet_register_types(void)
-{
- type_register_static(&pcnet_info);
-}
-
-type_init(pci_pcnet_register_types)
diff --git a/qemu/hw/net/pcnet.c b/qemu/hw/net/pcnet.c
deleted file mode 100644
index 198a01f92..000000000
--- a/qemu/hw/net/pcnet.c
+++ /dev/null
@@ -1,1761 +0,0 @@
-/*
- * QEMU AMD PC-Net II (Am79C970A) emulation
- *
- * Copyright (c) 2004 Antony T Curtis
- *
- * 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.
- */
-
-/* This software was written to be compatible with the specification:
- * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet
- * AMD Publication# 19436 Rev:E Amendment/0 Issue Date: June 2000
- */
-
-/*
- * On Sparc32, this is the Lance (Am7990) part of chip STP2000 (Master I/O), also
- * produced as NCR89C100. See
- * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt
- * and
- * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt
- */
-
-#include "qemu/osdep.h"
-#include "hw/qdev.h"
-#include "net/net.h"
-#include "qemu/timer.h"
-#include "qemu/sockets.h"
-#include "sysemu/sysemu.h"
-#include "trace.h"
-
-#include "pcnet.h"
-
-//#define PCNET_DEBUG
-//#define PCNET_DEBUG_IO
-//#define PCNET_DEBUG_BCR
-//#define PCNET_DEBUG_CSR
-//#define PCNET_DEBUG_RMD
-//#define PCNET_DEBUG_TMD
-//#define PCNET_DEBUG_MATCH
-
-
-struct qemu_ether_header {
- uint8_t ether_dhost[6];
- uint8_t ether_shost[6];
- uint16_t ether_type;
-};
-
-#define CSR_INIT(S) !!(((S)->csr[0])&0x0001)
-#define CSR_STRT(S) !!(((S)->csr[0])&0x0002)
-#define CSR_STOP(S) !!(((S)->csr[0])&0x0004)
-#define CSR_TDMD(S) !!(((S)->csr[0])&0x0008)
-#define CSR_TXON(S) !!(((S)->csr[0])&0x0010)
-#define CSR_RXON(S) !!(((S)->csr[0])&0x0020)
-#define CSR_INEA(S) !!(((S)->csr[0])&0x0040)
-#define CSR_BSWP(S) !!(((S)->csr[3])&0x0004)
-#define CSR_LAPPEN(S) !!(((S)->csr[3])&0x0020)
-#define CSR_DXSUFLO(S) !!(((S)->csr[3])&0x0040)
-#define CSR_ASTRP_RCV(S) !!(((S)->csr[4])&0x0800)
-#define CSR_DPOLL(S) !!(((S)->csr[4])&0x1000)
-#define CSR_SPND(S) !!(((S)->csr[5])&0x0001)
-#define CSR_LTINTEN(S) !!(((S)->csr[5])&0x4000)
-#define CSR_TOKINTD(S) !!(((S)->csr[5])&0x8000)
-#define CSR_DRX(S) !!(((S)->csr[15])&0x0001)
-#define CSR_DTX(S) !!(((S)->csr[15])&0x0002)
-#define CSR_LOOP(S) !!(((S)->csr[15])&0x0004)
-#define CSR_DXMTFCS(S) !!(((S)->csr[15])&0x0008)
-#define CSR_INTL(S) !!(((S)->csr[15])&0x0040)
-#define CSR_DRCVPA(S) !!(((S)->csr[15])&0x2000)
-#define CSR_DRCVBC(S) !!(((S)->csr[15])&0x4000)
-#define CSR_PROM(S) !!(((S)->csr[15])&0x8000)
-
-#define CSR_CRBC(S) ((S)->csr[40])
-#define CSR_CRST(S) ((S)->csr[41])
-#define CSR_CXBC(S) ((S)->csr[42])
-#define CSR_CXST(S) ((S)->csr[43])
-#define CSR_NRBC(S) ((S)->csr[44])
-#define CSR_NRST(S) ((S)->csr[45])
-#define CSR_POLL(S) ((S)->csr[46])
-#define CSR_PINT(S) ((S)->csr[47])
-#define CSR_RCVRC(S) ((S)->csr[72])
-#define CSR_XMTRC(S) ((S)->csr[74])
-#define CSR_RCVRL(S) ((S)->csr[76])
-#define CSR_XMTRL(S) ((S)->csr[78])
-#define CSR_MISSC(S) ((S)->csr[112])
-
-#define CSR_IADR(S) ((S)->csr[ 1] | ((uint32_t)(S)->csr[ 2] << 16))
-#define CSR_CRBA(S) ((S)->csr[18] | ((uint32_t)(S)->csr[19] << 16))
-#define CSR_CXBA(S) ((S)->csr[20] | ((uint32_t)(S)->csr[21] << 16))
-#define CSR_NRBA(S) ((S)->csr[22] | ((uint32_t)(S)->csr[23] << 16))
-#define CSR_BADR(S) ((S)->csr[24] | ((uint32_t)(S)->csr[25] << 16))
-#define CSR_NRDA(S) ((S)->csr[26] | ((uint32_t)(S)->csr[27] << 16))
-#define CSR_CRDA(S) ((S)->csr[28] | ((uint32_t)(S)->csr[29] << 16))
-#define CSR_BADX(S) ((S)->csr[30] | ((uint32_t)(S)->csr[31] << 16))
-#define CSR_NXDA(S) ((S)->csr[32] | ((uint32_t)(S)->csr[33] << 16))
-#define CSR_CXDA(S) ((S)->csr[34] | ((uint32_t)(S)->csr[35] << 16))
-#define CSR_NNRD(S) ((S)->csr[36] | ((uint32_t)(S)->csr[37] << 16))
-#define CSR_NNXD(S) ((S)->csr[38] | ((uint32_t)(S)->csr[39] << 16))
-#define CSR_PXDA(S) ((S)->csr[60] | ((uint32_t)(S)->csr[61] << 16))
-#define CSR_NXBA(S) ((S)->csr[64] | ((uint32_t)(S)->csr[65] << 16))
-
-#define PHYSADDR(S,A) \
- (BCR_SSIZE32(S) ? (A) : (A) | ((0xff00 & (uint32_t)(S)->csr[2])<<16))
-
-struct pcnet_initblk16 {
- uint16_t mode;
- uint16_t padr[3];
- uint16_t ladrf[4];
- uint32_t rdra;
- uint32_t tdra;
-};
-
-struct pcnet_initblk32 {
- uint16_t mode;
- uint8_t rlen;
- uint8_t tlen;
- uint16_t padr[3];
- uint16_t _res;
- uint16_t ladrf[4];
- uint32_t rdra;
- uint32_t tdra;
-};
-
-struct pcnet_TMD {
- uint32_t tbadr;
- int16_t length;
- int16_t status;
- uint32_t misc;
- uint32_t res;
-};
-
-#define TMDL_BCNT_MASK 0x0fff
-#define TMDL_BCNT_SH 0
-#define TMDL_ONES_MASK 0xf000
-#define TMDL_ONES_SH 12
-
-#define TMDS_BPE_MASK 0x0080
-#define TMDS_BPE_SH 7
-#define TMDS_ENP_MASK 0x0100
-#define TMDS_ENP_SH 8
-#define TMDS_STP_MASK 0x0200
-#define TMDS_STP_SH 9
-#define TMDS_DEF_MASK 0x0400
-#define TMDS_DEF_SH 10
-#define TMDS_ONE_MASK 0x0800
-#define TMDS_ONE_SH 11
-#define TMDS_LTINT_MASK 0x1000
-#define TMDS_LTINT_SH 12
-#define TMDS_NOFCS_MASK 0x2000
-#define TMDS_NOFCS_SH 13
-#define TMDS_ADDFCS_MASK TMDS_NOFCS_MASK
-#define TMDS_ADDFCS_SH TMDS_NOFCS_SH
-#define TMDS_ERR_MASK 0x4000
-#define TMDS_ERR_SH 14
-#define TMDS_OWN_MASK 0x8000
-#define TMDS_OWN_SH 15
-
-#define TMDM_TRC_MASK 0x0000000f
-#define TMDM_TRC_SH 0
-#define TMDM_TDR_MASK 0x03ff0000
-#define TMDM_TDR_SH 16
-#define TMDM_RTRY_MASK 0x04000000
-#define TMDM_RTRY_SH 26
-#define TMDM_LCAR_MASK 0x08000000
-#define TMDM_LCAR_SH 27
-#define TMDM_LCOL_MASK 0x10000000
-#define TMDM_LCOL_SH 28
-#define TMDM_EXDEF_MASK 0x20000000
-#define TMDM_EXDEF_SH 29
-#define TMDM_UFLO_MASK 0x40000000
-#define TMDM_UFLO_SH 30
-#define TMDM_BUFF_MASK 0x80000000
-#define TMDM_BUFF_SH 31
-
-struct pcnet_RMD {
- uint32_t rbadr;
- int16_t buf_length;
- int16_t status;
- uint32_t msg_length;
- uint32_t res;
-};
-
-#define RMDL_BCNT_MASK 0x0fff
-#define RMDL_BCNT_SH 0
-#define RMDL_ONES_MASK 0xf000
-#define RMDL_ONES_SH 12
-
-#define RMDS_BAM_MASK 0x0010
-#define RMDS_BAM_SH 4
-#define RMDS_LFAM_MASK 0x0020
-#define RMDS_LFAM_SH 5
-#define RMDS_PAM_MASK 0x0040
-#define RMDS_PAM_SH 6
-#define RMDS_BPE_MASK 0x0080
-#define RMDS_BPE_SH 7
-#define RMDS_ENP_MASK 0x0100
-#define RMDS_ENP_SH 8
-#define RMDS_STP_MASK 0x0200
-#define RMDS_STP_SH 9
-#define RMDS_BUFF_MASK 0x0400
-#define RMDS_BUFF_SH 10
-#define RMDS_CRC_MASK 0x0800
-#define RMDS_CRC_SH 11
-#define RMDS_OFLO_MASK 0x1000
-#define RMDS_OFLO_SH 12
-#define RMDS_FRAM_MASK 0x2000
-#define RMDS_FRAM_SH 13
-#define RMDS_ERR_MASK 0x4000
-#define RMDS_ERR_SH 14
-#define RMDS_OWN_MASK 0x8000
-#define RMDS_OWN_SH 15
-
-#define RMDM_MCNT_MASK 0x00000fff
-#define RMDM_MCNT_SH 0
-#define RMDM_ZEROS_MASK 0x0000f000
-#define RMDM_ZEROS_SH 12
-#define RMDM_RPC_MASK 0x00ff0000
-#define RMDM_RPC_SH 16
-#define RMDM_RCC_MASK 0xff000000
-#define RMDM_RCC_SH 24
-
-#define SET_FIELD(regp, name, field, value) \
- (*(regp) = (*(regp) & ~(name ## _ ## field ## _MASK)) \
- | ((value) << name ## _ ## field ## _SH))
-
-#define GET_FIELD(reg, name, field) \
- (((reg) & name ## _ ## field ## _MASK) >> name ## _ ## field ## _SH)
-
-#define PRINT_TMD(T) printf( \
- "TMD0 : TBADR=0x%08x\n" \
- "TMD1 : OWN=%d, ERR=%d, FCS=%d, LTI=%d, " \
- "ONE=%d, DEF=%d, STP=%d, ENP=%d,\n" \
- " BPE=%d, BCNT=%d\n" \
- "TMD2 : BUF=%d, UFL=%d, EXD=%d, LCO=%d, " \
- "LCA=%d, RTR=%d,\n" \
- " TDR=%d, TRC=%d\n", \
- (T)->tbadr, \
- GET_FIELD((T)->status, TMDS, OWN), \
- GET_FIELD((T)->status, TMDS, ERR), \
- GET_FIELD((T)->status, TMDS, NOFCS), \
- GET_FIELD((T)->status, TMDS, LTINT), \
- GET_FIELD((T)->status, TMDS, ONE), \
- GET_FIELD((T)->status, TMDS, DEF), \
- GET_FIELD((T)->status, TMDS, STP), \
- GET_FIELD((T)->status, TMDS, ENP), \
- GET_FIELD((T)->status, TMDS, BPE), \
- 4096-GET_FIELD((T)->length, TMDL, BCNT), \
- GET_FIELD((T)->misc, TMDM, BUFF), \
- GET_FIELD((T)->misc, TMDM, UFLO), \
- GET_FIELD((T)->misc, TMDM, EXDEF), \
- GET_FIELD((T)->misc, TMDM, LCOL), \
- GET_FIELD((T)->misc, TMDM, LCAR), \
- GET_FIELD((T)->misc, TMDM, RTRY), \
- GET_FIELD((T)->misc, TMDM, TDR), \
- GET_FIELD((T)->misc, TMDM, TRC))
-
-#define PRINT_RMD(R) printf( \
- "RMD0 : RBADR=0x%08x\n" \
- "RMD1 : OWN=%d, ERR=%d, FRAM=%d, OFLO=%d, " \
- "CRC=%d, BUFF=%d, STP=%d, ENP=%d,\n " \
- "BPE=%d, PAM=%d, LAFM=%d, BAM=%d, ONES=%d, BCNT=%d\n" \
- "RMD2 : RCC=%d, RPC=%d, MCNT=%d, ZEROS=%d\n", \
- (R)->rbadr, \
- GET_FIELD((R)->status, RMDS, OWN), \
- GET_FIELD((R)->status, RMDS, ERR), \
- GET_FIELD((R)->status, RMDS, FRAM), \
- GET_FIELD((R)->status, RMDS, OFLO), \
- GET_FIELD((R)->status, RMDS, CRC), \
- GET_FIELD((R)->status, RMDS, BUFF), \
- GET_FIELD((R)->status, RMDS, STP), \
- GET_FIELD((R)->status, RMDS, ENP), \
- GET_FIELD((R)->status, RMDS, BPE), \
- GET_FIELD((R)->status, RMDS, PAM), \
- GET_FIELD((R)->status, RMDS, LFAM), \
- GET_FIELD((R)->status, RMDS, BAM), \
- GET_FIELD((R)->buf_length, RMDL, ONES), \
- 4096-GET_FIELD((R)->buf_length, RMDL, BCNT), \
- GET_FIELD((R)->msg_length, RMDM, RCC), \
- GET_FIELD((R)->msg_length, RMDM, RPC), \
- GET_FIELD((R)->msg_length, RMDM, MCNT), \
- GET_FIELD((R)->msg_length, RMDM, ZEROS))
-
-static inline void pcnet_tmd_load(PCNetState *s, struct pcnet_TMD *tmd,
- hwaddr addr)
-{
- if (!BCR_SSIZE32(s)) {
- struct {
- uint32_t tbadr;
- int16_t length;
- int16_t status;
- } xda;
- s->phys_mem_read(s->dma_opaque, addr, (void *)&xda, sizeof(xda), 0);
- tmd->tbadr = le32_to_cpu(xda.tbadr) & 0xffffff;
- tmd->length = le16_to_cpu(xda.length);
- tmd->status = (le32_to_cpu(xda.tbadr) >> 16) & 0xff00;
- tmd->misc = le16_to_cpu(xda.status) << 16;
- tmd->res = 0;
- } else {
- s->phys_mem_read(s->dma_opaque, addr, (void *)tmd, sizeof(*tmd), 0);
- le32_to_cpus(&tmd->tbadr);
- le16_to_cpus((uint16_t *)&tmd->length);
- le16_to_cpus((uint16_t *)&tmd->status);
- le32_to_cpus(&tmd->misc);
- le32_to_cpus(&tmd->res);
- if (BCR_SWSTYLE(s) == 3) {
- uint32_t tmp = tmd->tbadr;
- tmd->tbadr = tmd->misc;
- tmd->misc = tmp;
- }
- }
-}
-
-static inline void pcnet_tmd_store(PCNetState *s, const struct pcnet_TMD *tmd,
- hwaddr addr)
-{
- if (!BCR_SSIZE32(s)) {
- struct {
- uint32_t tbadr;
- int16_t length;
- int16_t status;
- } xda;
- xda.tbadr = cpu_to_le32((tmd->tbadr & 0xffffff) |
- ((tmd->status & 0xff00) << 16));
- xda.length = cpu_to_le16(tmd->length);
- xda.status = cpu_to_le16(tmd->misc >> 16);
- s->phys_mem_write(s->dma_opaque, addr, (void *)&xda, sizeof(xda), 0);
- } else {
- struct {
- uint32_t tbadr;
- int16_t length;
- int16_t status;
- uint32_t misc;
- uint32_t res;
- } xda;
- xda.tbadr = cpu_to_le32(tmd->tbadr);
- xda.length = cpu_to_le16(tmd->length);
- xda.status = cpu_to_le16(tmd->status);
- xda.misc = cpu_to_le32(tmd->misc);
- xda.res = cpu_to_le32(tmd->res);
- if (BCR_SWSTYLE(s) == 3) {
- uint32_t tmp = xda.tbadr;
- xda.tbadr = xda.misc;
- xda.misc = tmp;
- }
- s->phys_mem_write(s->dma_opaque, addr, (void *)&xda, sizeof(xda), 0);
- }
-}
-
-static inline void pcnet_rmd_load(PCNetState *s, struct pcnet_RMD *rmd,
- hwaddr addr)
-{
- if (!BCR_SSIZE32(s)) {
- struct {
- uint32_t rbadr;
- int16_t buf_length;
- int16_t msg_length;
- } rda;
- s->phys_mem_read(s->dma_opaque, addr, (void *)&rda, sizeof(rda), 0);
- rmd->rbadr = le32_to_cpu(rda.rbadr) & 0xffffff;
- rmd->buf_length = le16_to_cpu(rda.buf_length);
- rmd->status = (le32_to_cpu(rda.rbadr) >> 16) & 0xff00;
- rmd->msg_length = le16_to_cpu(rda.msg_length);
- rmd->res = 0;
- } else {
- s->phys_mem_read(s->dma_opaque, addr, (void *)rmd, sizeof(*rmd), 0);
- le32_to_cpus(&rmd->rbadr);
- le16_to_cpus((uint16_t *)&rmd->buf_length);
- le16_to_cpus((uint16_t *)&rmd->status);
- le32_to_cpus(&rmd->msg_length);
- le32_to_cpus(&rmd->res);
- if (BCR_SWSTYLE(s) == 3) {
- uint32_t tmp = rmd->rbadr;
- rmd->rbadr = rmd->msg_length;
- rmd->msg_length = tmp;
- }
- }
-}
-
-static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd,
- hwaddr addr)
-{
- if (!BCR_SSIZE32(s)) {
- struct {
- uint32_t rbadr;
- int16_t buf_length;
- int16_t msg_length;
- } rda;
- rda.rbadr = cpu_to_le32((rmd->rbadr & 0xffffff) |
- ((rmd->status & 0xff00) << 16));
- rda.buf_length = cpu_to_le16(rmd->buf_length);
- rda.msg_length = cpu_to_le16(rmd->msg_length);
- s->phys_mem_write(s->dma_opaque, addr, (void *)&rda, sizeof(rda), 0);
- } else {
- struct {
- uint32_t rbadr;
- int16_t buf_length;
- int16_t status;
- uint32_t msg_length;
- uint32_t res;
- } rda;
- rda.rbadr = cpu_to_le32(rmd->rbadr);
- rda.buf_length = cpu_to_le16(rmd->buf_length);
- rda.status = cpu_to_le16(rmd->status);
- rda.msg_length = cpu_to_le32(rmd->msg_length);
- rda.res = cpu_to_le32(rmd->res);
- if (BCR_SWSTYLE(s) == 3) {
- uint32_t tmp = rda.rbadr;
- rda.rbadr = rda.msg_length;
- rda.msg_length = tmp;
- }
- s->phys_mem_write(s->dma_opaque, addr, (void *)&rda, sizeof(rda), 0);
- }
-}
-
-
-#define TMDLOAD(TMD,ADDR) pcnet_tmd_load(s,TMD,ADDR)
-
-#define TMDSTORE(TMD,ADDR) pcnet_tmd_store(s,TMD,ADDR)
-
-#define RMDLOAD(RMD,ADDR) pcnet_rmd_load(s,RMD,ADDR)
-
-#define RMDSTORE(RMD,ADDR) pcnet_rmd_store(s,RMD,ADDR)
-
-#if 1
-
-#define CHECK_RMD(ADDR,RES) do { \
- struct pcnet_RMD rmd; \
- RMDLOAD(&rmd,(ADDR)); \
- (RES) |= (GET_FIELD(rmd.buf_length, RMDL, ONES) != 15) \
- || (GET_FIELD(rmd.msg_length, RMDM, ZEROS) != 0); \
-} while (0)
-
-#define CHECK_TMD(ADDR,RES) do { \
- struct pcnet_TMD tmd; \
- TMDLOAD(&tmd,(ADDR)); \
- (RES) |= (GET_FIELD(tmd.length, TMDL, ONES) != 15); \
-} while (0)
-
-#else
-
-#define CHECK_RMD(ADDR,RES) do { \
- switch (BCR_SWSTYLE(s)) { \
- case 0x00: \
- do { \
- uint16_t rda[4]; \
- s->phys_mem_read(s->dma_opaque, (ADDR), \
- (void *)&rda[0], sizeof(rda), 0); \
- (RES) |= (rda[2] & 0xf000)!=0xf000; \
- (RES) |= (rda[3] & 0xf000)!=0x0000; \
- } while (0); \
- break; \
- case 0x01: \
- case 0x02: \
- do { \
- uint32_t rda[4]; \
- s->phys_mem_read(s->dma_opaque, (ADDR), \
- (void *)&rda[0], sizeof(rda), 0); \
- (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \
- (RES) |= (rda[2] & 0x0000f000L)!=0x00000000L; \
- } while (0); \
- break; \
- case 0x03: \
- do { \
- uint32_t rda[4]; \
- s->phys_mem_read(s->dma_opaque, (ADDR), \
- (void *)&rda[0], sizeof(rda), 0); \
- (RES) |= (rda[0] & 0x0000f000L)!=0x00000000L; \
- (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \
- } while (0); \
- break; \
- } \
-} while (0)
-
-#define CHECK_TMD(ADDR,RES) do { \
- switch (BCR_SWSTYLE(s)) { \
- case 0x00: \
- do { \
- uint16_t xda[4]; \
- s->phys_mem_read(s->dma_opaque, (ADDR), \
- (void *)&xda[0], sizeof(xda), 0); \
- (RES) |= (xda[2] & 0xf000)!=0xf000; \
- } while (0); \
- break; \
- case 0x01: \
- case 0x02: \
- case 0x03: \
- do { \
- uint32_t xda[4]; \
- s->phys_mem_read(s->dma_opaque, (ADDR), \
- (void *)&xda[0], sizeof(xda), 0); \
- (RES) |= (xda[1] & 0x0000f000L)!=0x0000f000L; \
- } while (0); \
- break; \
- } \
-} while (0)
-
-#endif
-
-#define PRINT_PKTHDR(BUF) do { \
- struct qemu_ether_header *hdr = (void *)(BUF); \
- printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, " \
- "shost=%02x:%02x:%02x:%02x:%02x:%02x, " \
- "type=0x%04x\n", \
- hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2], \
- hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5], \
- hdr->ether_shost[0],hdr->ether_shost[1],hdr->ether_shost[2], \
- hdr->ether_shost[3],hdr->ether_shost[4],hdr->ether_shost[5], \
- be16_to_cpu(hdr->ether_type)); \
-} while (0)
-
-#define MULTICAST_FILTER_LEN 8
-
-static inline uint32_t lnc_mchash(const uint8_t *ether_addr)
-{
-#define LNC_POLYNOMIAL 0xEDB88320UL
- uint32_t crc = 0xFFFFFFFF;
- int idx, bit;
- uint8_t data;
-
- for (idx = 0; idx < 6; idx++) {
- for (data = *ether_addr++, bit = 0; bit < MULTICAST_FILTER_LEN; bit++) {
- crc = (crc >> 1) ^ (((crc ^ data) & 1) ? LNC_POLYNOMIAL : 0);
- data >>= 1;
- }
- }
- return crc;
-#undef LNC_POLYNOMIAL
-}
-
-#define CRC(crc, ch) (crc = (crc >> 8) ^ crctab[(crc ^ (ch)) & 0xff])
-
-/* generated using the AUTODIN II polynomial
- * x^32 + x^26 + x^23 + x^22 + x^16 +
- * x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
- */
-static const uint32_t crctab[256] = {
- 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
- 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
- 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
- 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
- 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
- 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
- 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
- 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
- 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
- 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
- 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
- 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
- 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
- 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
- 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
- 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
- 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
- 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
- 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
- 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
- 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
- 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
- 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
- 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
- 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
- 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
- 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
- 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
- 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
- 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
- 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
- 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
- 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
- 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
- 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
- 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
- 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
- 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
- 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
- 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
- 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
- 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
- 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
- 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
- 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
- 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
- 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
- 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
- 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
- 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
- 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
- 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
- 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
- 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
- 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
- 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
- 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
- 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
- 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
- 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
- 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
- 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
- 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
- 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
-};
-
-static inline int padr_match(PCNetState *s, const uint8_t *buf, int size)
-{
- struct qemu_ether_header *hdr = (void *)buf;
- uint8_t padr[6] = {
- s->csr[12] & 0xff, s->csr[12] >> 8,
- s->csr[13] & 0xff, s->csr[13] >> 8,
- s->csr[14] & 0xff, s->csr[14] >> 8
- };
- int result = (!CSR_DRCVPA(s)) && !memcmp(hdr->ether_dhost, padr, 6);
-#ifdef PCNET_DEBUG_MATCH
- printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, "
- "padr=%02x:%02x:%02x:%02x:%02x:%02x\n",
- hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2],
- hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5],
- padr[0],padr[1],padr[2],padr[3],padr[4],padr[5]);
- printf("padr_match result=%d\n", result);
-#endif
- return result;
-}
-
-static inline int padr_bcast(PCNetState *s, const uint8_t *buf, int size)
-{
- static const uint8_t BCAST[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
- struct qemu_ether_header *hdr = (void *)buf;
- int result = !CSR_DRCVBC(s) && !memcmp(hdr->ether_dhost, BCAST, 6);
-#ifdef PCNET_DEBUG_MATCH
- printf("padr_bcast result=%d\n", result);
-#endif
- return result;
-}
-
-static inline int ladr_match(PCNetState *s, const uint8_t *buf, int size)
-{
- struct qemu_ether_header *hdr = (void *)buf;
- if ((*(hdr->ether_dhost)&0x01) &&
- ((uint64_t *)&s->csr[8])[0] != 0LL) {
- uint8_t ladr[8] = {
- s->csr[8] & 0xff, s->csr[8] >> 8,
- s->csr[9] & 0xff, s->csr[9] >> 8,
- s->csr[10] & 0xff, s->csr[10] >> 8,
- s->csr[11] & 0xff, s->csr[11] >> 8
- };
- int index = lnc_mchash(hdr->ether_dhost) >> 26;
- return !!(ladr[index >> 3] & (1 << (index & 7)));
- }
- return 0;
-}
-
-static inline hwaddr pcnet_rdra_addr(PCNetState *s, int idx)
-{
- while (idx < 1) idx += CSR_RCVRL(s);
- return s->rdra + ((CSR_RCVRL(s) - idx) * (BCR_SWSTYLE(s) ? 16 : 8));
-}
-
-static inline int64_t pcnet_get_next_poll_time(PCNetState *s, int64_t current_time)
-{
- int64_t next_time = current_time +
- (65536 - (CSR_SPND(s) ? 0 : CSR_POLL(s))) * 30;
- if (next_time <= current_time)
- next_time = current_time + 1;
- return next_time;
-}
-
-static void pcnet_poll(PCNetState *s);
-static void pcnet_poll_timer(void *opaque);
-
-static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap);
-static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value);
-static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val);
-
-static void pcnet_s_reset(PCNetState *s)
-{
- trace_pcnet_s_reset(s);
-
- s->rdra = 0;
- s->tdra = 0;
- s->rap = 0;
-
- s->bcr[BCR_BSBC] &= ~0x0080;
-
- s->csr[0] = 0x0004;
- s->csr[3] = 0x0000;
- s->csr[4] = 0x0115;
- s->csr[5] = 0x0000;
- s->csr[6] = 0x0000;
- s->csr[8] = 0;
- s->csr[9] = 0;
- s->csr[10] = 0;
- s->csr[11] = 0;
- s->csr[12] = le16_to_cpu(((uint16_t *)&s->prom[0])[0]);
- s->csr[13] = le16_to_cpu(((uint16_t *)&s->prom[0])[1]);
- s->csr[14] = le16_to_cpu(((uint16_t *)&s->prom[0])[2]);
- s->csr[15] &= 0x21c4;
- s->csr[72] = 1;
- s->csr[74] = 1;
- s->csr[76] = 1;
- s->csr[78] = 1;
- s->csr[80] = 0x1410;
- s->csr[88] = 0x1003;
- s->csr[89] = 0x0262;
- s->csr[94] = 0x0000;
- s->csr[100] = 0x0200;
- s->csr[103] = 0x0105;
- s->csr[112] = 0x0000;
- s->csr[114] = 0x0000;
- s->csr[122] = 0x0000;
- s->csr[124] = 0x0000;
-
- s->tx_busy = 0;
-}
-
-static void pcnet_update_irq(PCNetState *s)
-{
- int isr = 0;
- s->csr[0] &= ~0x0080;
-
-#if 1
- if (((s->csr[0] & ~s->csr[3]) & 0x5f00) ||
- (((s->csr[4]>>1) & ~s->csr[4]) & 0x0115) ||
- (((s->csr[5]>>1) & s->csr[5]) & 0x0048))
-#else
- if ((!(s->csr[3] & 0x4000) && !!(s->csr[0] & 0x4000)) /* BABL */ ||
- (!(s->csr[3] & 0x1000) && !!(s->csr[0] & 0x1000)) /* MISS */ ||
- (!(s->csr[3] & 0x0100) && !!(s->csr[0] & 0x0100)) /* IDON */ ||
- (!(s->csr[3] & 0x0200) && !!(s->csr[0] & 0x0200)) /* TINT */ ||
- (!(s->csr[3] & 0x0400) && !!(s->csr[0] & 0x0400)) /* RINT */ ||
- (!(s->csr[3] & 0x0800) && !!(s->csr[0] & 0x0800)) /* MERR */ ||
- (!(s->csr[4] & 0x0001) && !!(s->csr[4] & 0x0002)) /* JAB */ ||
- (!(s->csr[4] & 0x0004) && !!(s->csr[4] & 0x0008)) /* TXSTRT */ ||
- (!(s->csr[4] & 0x0010) && !!(s->csr[4] & 0x0020)) /* RCVO */ ||
- (!(s->csr[4] & 0x0100) && !!(s->csr[4] & 0x0200)) /* MFCO */ ||
- (!!(s->csr[5] & 0x0040) && !!(s->csr[5] & 0x0080)) /* EXDINT */ ||
- (!!(s->csr[5] & 0x0008) && !!(s->csr[5] & 0x0010)) /* MPINT */)
-#endif
- {
-
- isr = CSR_INEA(s);
- s->csr[0] |= 0x0080;
- }
-
- if (!!(s->csr[4] & 0x0080) && CSR_INEA(s)) { /* UINT */
- s->csr[4] &= ~0x0080;
- s->csr[4] |= 0x0040;
- s->csr[0] |= 0x0080;
- isr = 1;
- trace_pcnet_user_int(s);
- }
-
-#if 1
- if (((s->csr[5]>>1) & s->csr[5]) & 0x0500)
-#else
- if ((!!(s->csr[5] & 0x0400) && !!(s->csr[5] & 0x0800)) /* SINT */ ||
- (!!(s->csr[5] & 0x0100) && !!(s->csr[5] & 0x0200)) /* SLPINT */ )
-#endif
- {
- isr = 1;
- s->csr[0] |= 0x0080;
- }
-
- if (isr != s->isr) {
- trace_pcnet_isr_change(s, isr, s->isr);
- }
- qemu_set_irq(s->irq, isr);
- s->isr = isr;
-}
-
-static void pcnet_init(PCNetState *s)
-{
- int rlen, tlen;
- uint16_t padr[3], ladrf[4], mode;
- uint32_t rdra, tdra;
-
- trace_pcnet_init(s, PHYSADDR(s, CSR_IADR(s)));
-
- if (BCR_SSIZE32(s)) {
- struct pcnet_initblk32 initblk;
- s->phys_mem_read(s->dma_opaque, PHYSADDR(s,CSR_IADR(s)),
- (uint8_t *)&initblk, sizeof(initblk), 0);
- mode = le16_to_cpu(initblk.mode);
- rlen = initblk.rlen >> 4;
- tlen = initblk.tlen >> 4;
- ladrf[0] = le16_to_cpu(initblk.ladrf[0]);
- ladrf[1] = le16_to_cpu(initblk.ladrf[1]);
- ladrf[2] = le16_to_cpu(initblk.ladrf[2]);
- ladrf[3] = le16_to_cpu(initblk.ladrf[3]);
- padr[0] = le16_to_cpu(initblk.padr[0]);
- padr[1] = le16_to_cpu(initblk.padr[1]);
- padr[2] = le16_to_cpu(initblk.padr[2]);
- rdra = le32_to_cpu(initblk.rdra);
- tdra = le32_to_cpu(initblk.tdra);
- } else {
- struct pcnet_initblk16 initblk;
- s->phys_mem_read(s->dma_opaque, PHYSADDR(s,CSR_IADR(s)),
- (uint8_t *)&initblk, sizeof(initblk), 0);
- mode = le16_to_cpu(initblk.mode);
- ladrf[0] = le16_to_cpu(initblk.ladrf[0]);
- ladrf[1] = le16_to_cpu(initblk.ladrf[1]);
- ladrf[2] = le16_to_cpu(initblk.ladrf[2]);
- ladrf[3] = le16_to_cpu(initblk.ladrf[3]);
- padr[0] = le16_to_cpu(initblk.padr[0]);
- padr[1] = le16_to_cpu(initblk.padr[1]);
- padr[2] = le16_to_cpu(initblk.padr[2]);
- rdra = le32_to_cpu(initblk.rdra);
- tdra = le32_to_cpu(initblk.tdra);
- rlen = rdra >> 29;
- tlen = tdra >> 29;
- rdra &= 0x00ffffff;
- tdra &= 0x00ffffff;
- }
-
- trace_pcnet_rlen_tlen(s, rlen, tlen);
-
- CSR_RCVRL(s) = (rlen < 9) ? (1 << rlen) : 512;
- CSR_XMTRL(s) = (tlen < 9) ? (1 << tlen) : 512;
- s->csr[ 6] = (tlen << 12) | (rlen << 8);
- s->csr[15] = mode;
- s->csr[ 8] = ladrf[0];
- s->csr[ 9] = ladrf[1];
- s->csr[10] = ladrf[2];
- s->csr[11] = ladrf[3];
- s->csr[12] = padr[0];
- s->csr[13] = padr[1];
- s->csr[14] = padr[2];
- s->rdra = PHYSADDR(s, rdra);
- s->tdra = PHYSADDR(s, tdra);
-
- CSR_RCVRC(s) = CSR_RCVRL(s);
- CSR_XMTRC(s) = CSR_XMTRL(s);
-
- trace_pcnet_ss32_rdra_tdra(s, BCR_SSIZE32(s),
- s->rdra, CSR_RCVRL(s), s->tdra, CSR_XMTRL(s));
-
- s->csr[0] |= 0x0101;
- s->csr[0] &= ~0x0004; /* clear STOP bit */
-
- qemu_flush_queued_packets(qemu_get_queue(s->nic));
-}
-
-static void pcnet_start(PCNetState *s)
-{
-#ifdef PCNET_DEBUG
- printf("pcnet_start\n");
-#endif
-
- if (!CSR_DTX(s))
- s->csr[0] |= 0x0010; /* set TXON */
-
- if (!CSR_DRX(s))
- s->csr[0] |= 0x0020; /* set RXON */
-
- s->csr[0] &= ~0x0004; /* clear STOP bit */
- s->csr[0] |= 0x0002;
- pcnet_poll_timer(s);
-
- qemu_flush_queued_packets(qemu_get_queue(s->nic));
-}
-
-static void pcnet_stop(PCNetState *s)
-{
-#ifdef PCNET_DEBUG
- printf("pcnet_stop\n");
-#endif
- s->csr[0] &= ~0xffeb;
- s->csr[0] |= 0x0014;
- s->csr[4] &= ~0x02c2;
- s->csr[5] &= ~0x0011;
- pcnet_poll_timer(s);
-}
-
-static void pcnet_rdte_poll(PCNetState *s)
-{
- s->csr[28] = s->csr[29] = 0;
- if (s->rdra) {
- int bad = 0;
-#if 1
- hwaddr crda = pcnet_rdra_addr(s, CSR_RCVRC(s));
- hwaddr nrda = pcnet_rdra_addr(s, -1 + CSR_RCVRC(s));
- hwaddr nnrd = pcnet_rdra_addr(s, -2 + CSR_RCVRC(s));
-#else
- hwaddr crda = s->rdra +
- (CSR_RCVRL(s) - CSR_RCVRC(s)) *
- (BCR_SWSTYLE(s) ? 16 : 8 );
- int nrdc = CSR_RCVRC(s)<=1 ? CSR_RCVRL(s) : CSR_RCVRC(s)-1;
- hwaddr nrda = s->rdra +
- (CSR_RCVRL(s) - nrdc) *
- (BCR_SWSTYLE(s) ? 16 : 8 );
- int nnrc = nrdc<=1 ? CSR_RCVRL(s) : nrdc-1;
- hwaddr nnrd = s->rdra +
- (CSR_RCVRL(s) - nnrc) *
- (BCR_SWSTYLE(s) ? 16 : 8 );
-#endif
-
- CHECK_RMD(crda, bad);
- if (!bad) {
- CHECK_RMD(nrda, bad);
- if (bad || (nrda == crda)) nrda = 0;
- CHECK_RMD(nnrd, bad);
- if (bad || (nnrd == crda)) nnrd = 0;
-
- s->csr[28] = crda & 0xffff;
- s->csr[29] = crda >> 16;
- s->csr[26] = nrda & 0xffff;
- s->csr[27] = nrda >> 16;
- s->csr[36] = nnrd & 0xffff;
- s->csr[37] = nnrd >> 16;
-#ifdef PCNET_DEBUG
- if (bad) {
- printf("pcnet: BAD RMD RECORDS AFTER 0x" TARGET_FMT_plx "\n",
- crda);
- }
- } else {
- printf("pcnet: BAD RMD RDA=0x" TARGET_FMT_plx "\n",
- crda);
-#endif
- }
- }
-
- if (CSR_CRDA(s)) {
- struct pcnet_RMD rmd;
- RMDLOAD(&rmd, PHYSADDR(s,CSR_CRDA(s)));
- CSR_CRBC(s) = GET_FIELD(rmd.buf_length, RMDL, BCNT);
- CSR_CRST(s) = rmd.status;
-#ifdef PCNET_DEBUG_RMD_X
- printf("CRDA=0x%08x CRST=0x%04x RCVRC=%d RMDL=0x%04x RMDS=0x%04x RMDM=0x%08x\n",
- PHYSADDR(s,CSR_CRDA(s)), CSR_CRST(s), CSR_RCVRC(s),
- rmd.buf_length, rmd.status, rmd.msg_length);
- PRINT_RMD(&rmd);
-#endif
- } else {
- CSR_CRBC(s) = CSR_CRST(s) = 0;
- }
-
- if (CSR_NRDA(s)) {
- struct pcnet_RMD rmd;
- RMDLOAD(&rmd, PHYSADDR(s,CSR_NRDA(s)));
- CSR_NRBC(s) = GET_FIELD(rmd.buf_length, RMDL, BCNT);
- CSR_NRST(s) = rmd.status;
- } else {
- CSR_NRBC(s) = CSR_NRST(s) = 0;
- }
-
-}
-
-static int pcnet_tdte_poll(PCNetState *s)
-{
- s->csr[34] = s->csr[35] = 0;
- if (s->tdra) {
- hwaddr cxda = s->tdra +
- (CSR_XMTRL(s) - CSR_XMTRC(s)) *
- (BCR_SWSTYLE(s) ? 16 : 8);
- int bad = 0;
- CHECK_TMD(cxda, bad);
- if (!bad) {
- if (CSR_CXDA(s) != cxda) {
- s->csr[60] = s->csr[34];
- s->csr[61] = s->csr[35];
- s->csr[62] = CSR_CXBC(s);
- s->csr[63] = CSR_CXST(s);
- }
- s->csr[34] = cxda & 0xffff;
- s->csr[35] = cxda >> 16;
-#ifdef PCNET_DEBUG_X
- printf("pcnet: BAD TMD XDA=0x%08x\n", cxda);
-#endif
- }
- }
-
- if (CSR_CXDA(s)) {
- struct pcnet_TMD tmd;
-
- TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s)));
-
- CSR_CXBC(s) = GET_FIELD(tmd.length, TMDL, BCNT);
- CSR_CXST(s) = tmd.status;
- } else {
- CSR_CXBC(s) = CSR_CXST(s) = 0;
- }
-
- return !!(CSR_CXST(s) & 0x8000);
-}
-
-#define MIN_BUF_SIZE 60
-
-ssize_t pcnet_receive(NetClientState *nc, const uint8_t *buf, size_t size_)
-{
- PCNetState *s = qemu_get_nic_opaque(nc);
- int is_padr = 0, is_bcast = 0, is_ladr = 0;
- uint8_t buf1[60];
- int remaining;
- int crc_err = 0;
- int size = size_;
-
- if (CSR_DRX(s) || CSR_STOP(s) || CSR_SPND(s) || !size ||
- (CSR_LOOP(s) && !s->looptest)) {
- return -1;
- }
-#ifdef PCNET_DEBUG
- printf("pcnet_receive size=%d\n", size);
-#endif
-
- /* if too small buffer, then expand it */
- if (size < MIN_BUF_SIZE) {
- memcpy(buf1, buf, size);
- memset(buf1 + size, 0, MIN_BUF_SIZE - size);
- buf = buf1;
- size = MIN_BUF_SIZE;
- }
-
- if (CSR_PROM(s)
- || (is_padr=padr_match(s, buf, size))
- || (is_bcast=padr_bcast(s, buf, size))
- || (is_ladr=ladr_match(s, buf, size))) {
-
- pcnet_rdte_poll(s);
-
- if (!(CSR_CRST(s) & 0x8000) && s->rdra) {
- struct pcnet_RMD rmd;
- int rcvrc = CSR_RCVRC(s)-1,i;
- hwaddr nrda;
- for (i = CSR_RCVRL(s)-1; i > 0; i--, rcvrc--) {
- if (rcvrc <= 1)
- rcvrc = CSR_RCVRL(s);
- nrda = s->rdra +
- (CSR_RCVRL(s) - rcvrc) *
- (BCR_SWSTYLE(s) ? 16 : 8 );
- RMDLOAD(&rmd, nrda);
- if (GET_FIELD(rmd.status, RMDS, OWN)) {
-#ifdef PCNET_DEBUG_RMD
- printf("pcnet - scan buffer: RCVRC=%d PREV_RCVRC=%d\n",
- rcvrc, CSR_RCVRC(s));
-#endif
- CSR_RCVRC(s) = rcvrc;
- pcnet_rdte_poll(s);
- break;
- }
- }
- }
-
- if (!(CSR_CRST(s) & 0x8000)) {
-#ifdef PCNET_DEBUG_RMD
- printf("pcnet - no buffer: RCVRC=%d\n", CSR_RCVRC(s));
-#endif
- s->csr[0] |= 0x1000; /* Set MISS flag */
- CSR_MISSC(s)++;
- } else {
- uint8_t *src = s->buffer;
- hwaddr crda = CSR_CRDA(s);
- struct pcnet_RMD rmd;
- int pktcount = 0;
-
- if (!s->looptest) {
- if (size > 4092) {
-#ifdef PCNET_DEBUG_RMD
- fprintf(stderr, "pcnet: truncates rx packet.\n");
-#endif
- size = 4092;
- }
- memcpy(src, buf, size);
- /* no need to compute the CRC */
- src[size] = 0;
- src[size + 1] = 0;
- src[size + 2] = 0;
- src[size + 3] = 0;
- size += 4;
- } else if (s->looptest == PCNET_LOOPTEST_CRC ||
- !CSR_DXMTFCS(s) || size < MIN_BUF_SIZE+4) {
- uint32_t fcs = ~0;
- uint8_t *p = src;
-
- while (p != &src[size])
- CRC(fcs, *p++);
- *(uint32_t *)p = htonl(fcs);
- size += 4;
- } else {
- uint32_t fcs = ~0;
- uint8_t *p = src;
-
- while (p != &src[size])
- CRC(fcs, *p++);
- crc_err = (*(uint32_t *)p != htonl(fcs));
- }
-
-#ifdef PCNET_DEBUG_MATCH
- PRINT_PKTHDR(buf);
-#endif
-
- RMDLOAD(&rmd, PHYSADDR(s,crda));
- /*if (!CSR_LAPPEN(s))*/
- SET_FIELD(&rmd.status, RMDS, STP, 1);
-
-#define PCNET_RECV_STORE() do { \
- int count = MIN(4096 - GET_FIELD(rmd.buf_length, RMDL, BCNT),remaining); \
- hwaddr rbadr = PHYSADDR(s, rmd.rbadr); \
- s->phys_mem_write(s->dma_opaque, rbadr, src, count, CSR_BSWP(s)); \
- src += count; remaining -= count; \
- SET_FIELD(&rmd.status, RMDS, OWN, 0); \
- RMDSTORE(&rmd, PHYSADDR(s,crda)); \
- pktcount++; \
-} while (0)
-
- remaining = size;
- PCNET_RECV_STORE();
- if ((remaining > 0) && CSR_NRDA(s)) {
- hwaddr nrda = CSR_NRDA(s);
-#ifdef PCNET_DEBUG_RMD
- PRINT_RMD(&rmd);
-#endif
- RMDLOAD(&rmd, PHYSADDR(s,nrda));
- if (GET_FIELD(rmd.status, RMDS, OWN)) {
- crda = nrda;
- PCNET_RECV_STORE();
-#ifdef PCNET_DEBUG_RMD
- PRINT_RMD(&rmd);
-#endif
- if ((remaining > 0) && (nrda=CSR_NNRD(s))) {
- RMDLOAD(&rmd, PHYSADDR(s,nrda));
- if (GET_FIELD(rmd.status, RMDS, OWN)) {
- crda = nrda;
- PCNET_RECV_STORE();
- }
- }
- }
- }
-
-#undef PCNET_RECV_STORE
-
- RMDLOAD(&rmd, PHYSADDR(s,crda));
- if (remaining == 0) {
- SET_FIELD(&rmd.msg_length, RMDM, MCNT, size);
- SET_FIELD(&rmd.status, RMDS, ENP, 1);
- SET_FIELD(&rmd.status, RMDS, PAM, !CSR_PROM(s) && is_padr);
- SET_FIELD(&rmd.status, RMDS, LFAM, !CSR_PROM(s) && is_ladr);
- SET_FIELD(&rmd.status, RMDS, BAM, !CSR_PROM(s) && is_bcast);
- if (crc_err) {
- SET_FIELD(&rmd.status, RMDS, CRC, 1);
- SET_FIELD(&rmd.status, RMDS, ERR, 1);
- }
- } else {
- SET_FIELD(&rmd.status, RMDS, OFLO, 1);
- SET_FIELD(&rmd.status, RMDS, BUFF, 1);
- SET_FIELD(&rmd.status, RMDS, ERR, 1);
- }
- RMDSTORE(&rmd, PHYSADDR(s,crda));
- s->csr[0] |= 0x0400;
-
-#ifdef PCNET_DEBUG
- printf("RCVRC=%d CRDA=0x%08x BLKS=%d\n",
- CSR_RCVRC(s), PHYSADDR(s,CSR_CRDA(s)), pktcount);
-#endif
-#ifdef PCNET_DEBUG_RMD
- PRINT_RMD(&rmd);
-#endif
-
- while (pktcount--) {
- if (CSR_RCVRC(s) <= 1)
- CSR_RCVRC(s) = CSR_RCVRL(s);
- else
- CSR_RCVRC(s)--;
- }
-
- pcnet_rdte_poll(s);
-
- }
- }
-
- pcnet_poll(s);
- pcnet_update_irq(s);
-
- return size_;
-}
-
-void pcnet_set_link_status(NetClientState *nc)
-{
- PCNetState *d = qemu_get_nic_opaque(nc);
-
- d->lnkst = nc->link_down ? 0 : 0x40;
-}
-
-static void pcnet_transmit(PCNetState *s)
-{
- hwaddr xmit_cxda = 0;
- int count = CSR_XMTRL(s)-1;
- int add_crc = 0;
- int bcnt;
- s->xmit_pos = -1;
-
- if (!CSR_TXON(s)) {
- s->csr[0] &= ~0x0008;
- return;
- }
-
- s->tx_busy = 1;
-
- txagain:
- if (pcnet_tdte_poll(s)) {
- struct pcnet_TMD tmd;
-
- TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s)));
-
-#ifdef PCNET_DEBUG_TMD
- printf(" TMDLOAD 0x%08x\n", PHYSADDR(s,CSR_CXDA(s)));
- PRINT_TMD(&tmd);
-#endif
- if (GET_FIELD(tmd.status, TMDS, STP)) {
- s->xmit_pos = 0;
- xmit_cxda = PHYSADDR(s,CSR_CXDA(s));
- if (BCR_SWSTYLE(s) != 1)
- add_crc = GET_FIELD(tmd.status, TMDS, ADDFCS);
- }
- if (s->lnkst == 0 &&
- (!CSR_LOOP(s) || (!CSR_INTL(s) && !BCR_TMAULOOP(s)))) {
- SET_FIELD(&tmd.misc, TMDM, LCAR, 1);
- SET_FIELD(&tmd.status, TMDS, ERR, 1);
- SET_FIELD(&tmd.status, TMDS, OWN, 0);
- s->csr[0] |= 0xa000; /* ERR | CERR */
- s->xmit_pos = -1;
- goto txdone;
- }
-
- if (s->xmit_pos < 0) {
- goto txdone;
- }
-
- bcnt = 4096 - GET_FIELD(tmd.length, TMDL, BCNT);
-
- /* if multi-tmd packet outsizes s->buffer then skip it silently.
- * Note: this is not what real hw does.
- * Last four bytes of s->buffer are used to store CRC FCS code.
- */
- if (s->xmit_pos + bcnt > sizeof(s->buffer) - 4) {
- s->xmit_pos = -1;
- goto txdone;
- }
-
- s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tbadr),
- s->buffer + s->xmit_pos, bcnt, CSR_BSWP(s));
- s->xmit_pos += bcnt;
-
- if (!GET_FIELD(tmd.status, TMDS, ENP)) {
- goto txdone;
- }
-
-#ifdef PCNET_DEBUG
- printf("pcnet_transmit size=%d\n", s->xmit_pos);
-#endif
- if (CSR_LOOP(s)) {
- if (BCR_SWSTYLE(s) == 1)
- add_crc = !GET_FIELD(tmd.status, TMDS, NOFCS);
- s->looptest = add_crc ? PCNET_LOOPTEST_CRC : PCNET_LOOPTEST_NOCRC;
- pcnet_receive(qemu_get_queue(s->nic), s->buffer, s->xmit_pos);
- s->looptest = 0;
- } else {
- if (s->nic) {
- qemu_send_packet(qemu_get_queue(s->nic), s->buffer,
- s->xmit_pos);
- }
- }
-
- s->csr[0] &= ~0x0008; /* clear TDMD */
- s->csr[4] |= 0x0004; /* set TXSTRT */
- s->xmit_pos = -1;
-
- txdone:
- SET_FIELD(&tmd.status, TMDS, OWN, 0);
- TMDSTORE(&tmd, PHYSADDR(s,CSR_CXDA(s)));
- if (!CSR_TOKINTD(s) || (CSR_LTINTEN(s) && GET_FIELD(tmd.status, TMDS, LTINT)))
- s->csr[0] |= 0x0200; /* set TINT */
-
- if (CSR_XMTRC(s)<=1)
- CSR_XMTRC(s) = CSR_XMTRL(s);
- else
- CSR_XMTRC(s)--;
- if (count--)
- goto txagain;
-
- } else
- if (s->xmit_pos >= 0) {
- struct pcnet_TMD tmd;
- TMDLOAD(&tmd, xmit_cxda);
- SET_FIELD(&tmd.misc, TMDM, BUFF, 1);
- SET_FIELD(&tmd.misc, TMDM, UFLO, 1);
- SET_FIELD(&tmd.status, TMDS, ERR, 1);
- SET_FIELD(&tmd.status, TMDS, OWN, 0);
- TMDSTORE(&tmd, xmit_cxda);
- s->csr[0] |= 0x0200; /* set TINT */
- if (!CSR_DXSUFLO(s)) {
- s->csr[0] &= ~0x0010;
- } else
- if (count--)
- goto txagain;
- }
-
- s->tx_busy = 0;
-}
-
-static void pcnet_poll(PCNetState *s)
-{
- if (CSR_RXON(s)) {
- pcnet_rdte_poll(s);
- }
-
- if (CSR_TDMD(s) ||
- (CSR_TXON(s) && !CSR_DPOLL(s) && pcnet_tdte_poll(s)))
- {
- /* prevent recursion */
- if (s->tx_busy)
- return;
-
- pcnet_transmit(s);
- }
-}
-
-static void pcnet_poll_timer(void *opaque)
-{
- PCNetState *s = opaque;
-
- timer_del(s->poll_timer);
-
- if (CSR_TDMD(s)) {
- pcnet_transmit(s);
- }
-
- pcnet_update_irq(s);
-
- if (!CSR_STOP(s) && !CSR_SPND(s) && !CSR_DPOLL(s)) {
- uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) * 33;
- if (!s->timer || !now)
- s->timer = now;
- else {
- uint64_t t = now - s->timer + CSR_POLL(s);
- if (t > 0xffffLL) {
- pcnet_poll(s);
- CSR_POLL(s) = CSR_PINT(s);
- } else
- CSR_POLL(s) = t;
- }
- timer_mod(s->poll_timer,
- pcnet_get_next_poll_time(s,qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)));
- }
-}
-
-
-static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value)
-{
- uint16_t val = new_value;
-#ifdef PCNET_DEBUG_CSR
- printf("pcnet_csr_writew rap=%d val=0x%04x\n", rap, val);
-#endif
- switch (rap) {
- case 0:
- s->csr[0] &= ~(val & 0x7f00); /* Clear any interrupt flags */
-
- s->csr[0] = (s->csr[0] & ~0x0040) | (val & 0x0048);
-
- val = (val & 0x007f) | (s->csr[0] & 0x7f00);
-
- /* IFF STOP, STRT and INIT are set, clear STRT and INIT */
- if ((val&7) == 7)
- val &= ~3;
-
- if (!CSR_STOP(s) && (val & 4))
- pcnet_stop(s);
-
- if (!CSR_INIT(s) && (val & 1))
- pcnet_init(s);
-
- if (!CSR_STRT(s) && (val & 2))
- pcnet_start(s);
-
- if (CSR_TDMD(s))
- pcnet_transmit(s);
-
- return;
- case 1:
- case 2:
- case 8:
- case 9:
- case 10:
- case 11:
- case 12:
- case 13:
- case 14:
- case 15:
- case 18: /* CRBAL */
- case 19: /* CRBAU */
- case 20: /* CXBAL */
- case 21: /* CXBAU */
- case 22: /* NRBAU */
- case 23: /* NRBAU */
- case 24:
- case 25:
- case 26:
- case 27:
- case 28:
- case 29:
- case 30:
- case 31:
- case 32:
- case 33:
- case 34:
- case 35:
- case 36:
- case 37:
- case 38:
- case 39:
- case 40: /* CRBC */
- case 41:
- case 42: /* CXBC */
- case 43:
- case 44:
- case 45:
- case 46: /* POLL */
- case 47: /* POLLINT */
- case 72:
- case 74:
- case 76: /* RCVRL */
- case 78: /* XMTRL */
- case 112:
- if (CSR_STOP(s) || CSR_SPND(s))
- break;
- return;
- case 3:
- break;
- case 4:
- s->csr[4] &= ~(val & 0x026a);
- val &= ~0x026a; val |= s->csr[4] & 0x026a;
- break;
- case 5:
- s->csr[5] &= ~(val & 0x0a90);
- val &= ~0x0a90; val |= s->csr[5] & 0x0a90;
- break;
- case 16:
- pcnet_csr_writew(s,1,val);
- return;
- case 17:
- pcnet_csr_writew(s,2,val);
- return;
- case 58:
- pcnet_bcr_writew(s,BCR_SWS,val);
- break;
- default:
- return;
- }
- s->csr[rap] = val;
-}
-
-static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap)
-{
- uint32_t val;
- switch (rap) {
- case 0:
- pcnet_update_irq(s);
- val = s->csr[0];
- val |= (val & 0x7800) ? 0x8000 : 0;
- break;
- case 16:
- return pcnet_csr_readw(s,1);
- case 17:
- return pcnet_csr_readw(s,2);
- case 58:
- return pcnet_bcr_readw(s,BCR_SWS);
- case 88:
- val = s->csr[89];
- val <<= 16;
- val |= s->csr[88];
- break;
- default:
- val = s->csr[rap];
- }
-#ifdef PCNET_DEBUG_CSR
- printf("pcnet_csr_readw rap=%d val=0x%04x\n", rap, val);
-#endif
- return val;
-}
-
-static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val)
-{
- rap &= 127;
-#ifdef PCNET_DEBUG_BCR
- printf("pcnet_bcr_writew rap=%d val=0x%04x\n", rap, val);
-#endif
- switch (rap) {
- case BCR_SWS:
- if (!(CSR_STOP(s) || CSR_SPND(s)))
- return;
- val &= ~0x0300;
- switch (val & 0x00ff) {
- case 0:
- val |= 0x0200;
- break;
- case 1:
- val |= 0x0100;
- break;
- case 2:
- case 3:
- val |= 0x0300;
- break;
- default:
- printf("Bad SWSTYLE=0x%02x\n", val & 0xff);
- val = 0x0200;
- break;
- }
-#ifdef PCNET_DEBUG
- printf("BCR_SWS=0x%04x\n", val);
-#endif
- /* fall through */
- case BCR_LNKST:
- case BCR_LED1:
- case BCR_LED2:
- case BCR_LED3:
- case BCR_MC:
- case BCR_FDC:
- case BCR_BSBC:
- case BCR_EECAS:
- case BCR_PLAT:
- s->bcr[rap] = val;
- break;
- default:
- break;
- }
-}
-
-uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap)
-{
- uint32_t val;
- rap &= 127;
- switch (rap) {
- case BCR_LNKST:
- case BCR_LED1:
- case BCR_LED2:
- case BCR_LED3:
- val = s->bcr[rap] & ~0x8000;
- val |= (val & 0x017f & s->lnkst) ? 0x8000 : 0;
- break;
- default:
- val = rap < 32 ? s->bcr[rap] : 0;
- break;
- }
-#ifdef PCNET_DEBUG_BCR
- printf("pcnet_bcr_readw rap=%d val=0x%04x\n", rap, val);
-#endif
- return val;
-}
-
-void pcnet_h_reset(void *opaque)
-{
- PCNetState *s = opaque;
-
- s->bcr[BCR_MSRDA] = 0x0005;
- s->bcr[BCR_MSWRA] = 0x0005;
- s->bcr[BCR_MC ] = 0x0002;
- s->bcr[BCR_LNKST] = 0x00c0;
- s->bcr[BCR_LED1 ] = 0x0084;
- s->bcr[BCR_LED2 ] = 0x0088;
- s->bcr[BCR_LED3 ] = 0x0090;
- s->bcr[BCR_FDC ] = 0x0000;
- s->bcr[BCR_BSBC ] = 0x9001;
- s->bcr[BCR_EECAS] = 0x0002;
- s->bcr[BCR_SWS ] = 0x0200;
- s->bcr[BCR_PLAT ] = 0xff06;
-
- pcnet_s_reset(s);
- pcnet_update_irq(s);
- pcnet_poll_timer(s);
-}
-
-void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
-{
- PCNetState *s = opaque;
- pcnet_poll_timer(s);
-#ifdef PCNET_DEBUG_IO
- printf("pcnet_ioport_writew addr=0x%08x val=0x%04x\n", addr, val);
-#endif
- if (!BCR_DWIO(s)) {
- switch (addr & 0x0f) {
- case 0x00: /* RDP */
- pcnet_csr_writew(s, s->rap, val);
- break;
- case 0x02:
- s->rap = val & 0x7f;
- break;
- case 0x06:
- pcnet_bcr_writew(s, s->rap, val);
- break;
- }
- }
- pcnet_update_irq(s);
-}
-
-uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr)
-{
- PCNetState *s = opaque;
- uint32_t val = -1;
- pcnet_poll_timer(s);
- if (!BCR_DWIO(s)) {
- switch (addr & 0x0f) {
- case 0x00: /* RDP */
- val = pcnet_csr_readw(s, s->rap);
- break;
- case 0x02:
- val = s->rap;
- break;
- case 0x04:
- pcnet_s_reset(s);
- val = 0;
- break;
- case 0x06:
- val = pcnet_bcr_readw(s, s->rap);
- break;
- }
- }
- pcnet_update_irq(s);
-#ifdef PCNET_DEBUG_IO
- printf("pcnet_ioport_readw addr=0x%08x val=0x%04x\n", addr, val & 0xffff);
-#endif
- return val;
-}
-
-void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
-{
- PCNetState *s = opaque;
- pcnet_poll_timer(s);
-#ifdef PCNET_DEBUG_IO
- printf("pcnet_ioport_writel addr=0x%08x val=0x%08x\n", addr, val);
-#endif
- if (BCR_DWIO(s)) {
- switch (addr & 0x0f) {
- case 0x00: /* RDP */
- pcnet_csr_writew(s, s->rap, val & 0xffff);
- break;
- case 0x04:
- s->rap = val & 0x7f;
- break;
- case 0x0c:
- pcnet_bcr_writew(s, s->rap, val & 0xffff);
- break;
- }
- } else
- if ((addr & 0x0f) == 0) {
- /* switch device to dword i/o mode */
- pcnet_bcr_writew(s, BCR_BSBC, pcnet_bcr_readw(s, BCR_BSBC) | 0x0080);
-#ifdef PCNET_DEBUG_IO
- printf("device switched into dword i/o mode\n");
-#endif
- }
- pcnet_update_irq(s);
-}
-
-uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr)
-{
- PCNetState *s = opaque;
- uint32_t val = -1;
- pcnet_poll_timer(s);
- if (BCR_DWIO(s)) {
- switch (addr & 0x0f) {
- case 0x00: /* RDP */
- val = pcnet_csr_readw(s, s->rap);
- break;
- case 0x04:
- val = s->rap;
- break;
- case 0x08:
- pcnet_s_reset(s);
- val = 0;
- break;
- case 0x0c:
- val = pcnet_bcr_readw(s, s->rap);
- break;
- }
- }
- pcnet_update_irq(s);
-#ifdef PCNET_DEBUG_IO
- printf("pcnet_ioport_readl addr=0x%08x val=0x%08x\n", addr, val);
-#endif
- return val;
-}
-
-static bool is_version_2(void *opaque, int version_id)
-{
- return version_id == 2;
-}
-
-const VMStateDescription vmstate_pcnet = {
- .name = "pcnet",
- .version_id = 3,
- .minimum_version_id = 2,
- .fields = (VMStateField[]) {
- VMSTATE_INT32(rap, PCNetState),
- VMSTATE_INT32(isr, PCNetState),
- VMSTATE_INT32(lnkst, PCNetState),
- VMSTATE_UINT32(rdra, PCNetState),
- VMSTATE_UINT32(tdra, PCNetState),
- VMSTATE_BUFFER(prom, PCNetState),
- VMSTATE_UINT16_ARRAY(csr, PCNetState, 128),
- VMSTATE_UINT16_ARRAY(bcr, PCNetState, 32),
- VMSTATE_UINT64(timer, PCNetState),
- VMSTATE_INT32(xmit_pos, PCNetState),
- VMSTATE_BUFFER(buffer, PCNetState),
- VMSTATE_UNUSED_TEST(is_version_2, 4),
- VMSTATE_INT32(tx_busy, PCNetState),
- VMSTATE_TIMER_PTR(poll_timer, PCNetState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-void pcnet_common_init(DeviceState *dev, PCNetState *s, NetClientInfo *info)
-{
- int i;
- uint16_t checksum;
-
- s->poll_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, pcnet_poll_timer, s);
-
- qemu_macaddr_default_if_unset(&s->conf.macaddr);
- s->nic = qemu_new_nic(info, &s->conf, object_get_typename(OBJECT(dev)), dev->id, s);
- qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-
- /* Initialize the PROM */
-
- /*
- Datasheet: http://pdfdata.datasheetsite.com/web/24528/AM79C970A.pdf
- page 95
- */
- memcpy(s->prom, s->conf.macaddr.a, 6);
- /* Reserved Location: must be 00h */
- s->prom[6] = s->prom[7] = 0x00;
- /* Reserved Location: must be 00h */
- s->prom[8] = 0x00;
- /* Hardware ID: must be 11h if compatibility to AMD drivers is desired */
- s->prom[9] = 0x11;
- /* User programmable space, init with 0 */
- s->prom[10] = s->prom[11] = 0x00;
- /* LSByte of two-byte checksum, which is the sum of bytes 00h-0Bh
- and bytes 0Eh and 0Fh, must therefore be initialized with 0! */
- s->prom[12] = s->prom[13] = 0x00;
- /* Must be ASCII W (57h) if compatibility to AMD
- driver software is desired */
- s->prom[14] = s->prom[15] = 0x57;
-
- for (i = 0, checksum = 0; i < 16; i++) {
- checksum += s->prom[i];
- }
- *(uint16_t *)&s->prom[12] = cpu_to_le16(checksum);
-
- s->lnkst = 0x40; /* initial link state: up */
-}
diff --git a/qemu/hw/net/pcnet.h b/qemu/hw/net/pcnet.h
deleted file mode 100644
index dec8de834..000000000
--- a/qemu/hw/net/pcnet.h
+++ /dev/null
@@ -1,67 +0,0 @@
-#ifndef HW_PCNET_H
-#define HW_PCNET_H 1
-
-#define PCNET_IOPORT_SIZE 0x20
-#define PCNET_PNPMMIO_SIZE 0x20
-
-#define PCNET_LOOPTEST_CRC 1
-#define PCNET_LOOPTEST_NOCRC 2
-
-#include "exec/memory.h"
-
-/* BUS CONFIGURATION REGISTERS */
-#define BCR_MSRDA 0
-#define BCR_MSWRA 1
-#define BCR_MC 2
-#define BCR_LNKST 4
-#define BCR_LED1 5
-#define BCR_LED2 6
-#define BCR_LED3 7
-#define BCR_FDC 9
-#define BCR_BSBC 18
-#define BCR_EECAS 19
-#define BCR_SWS 20
-#define BCR_PLAT 22
-
-#define BCR_TMAULOOP(S) !!((S)->bcr[BCR_MC ] & 0x4000)
-#define BCR_APROMWE(S) !!((S)->bcr[BCR_MC ] & 0x0100)
-#define BCR_DWIO(S) !!((S)->bcr[BCR_BSBC] & 0x0080)
-#define BCR_SSIZE32(S) !!((S)->bcr[BCR_SWS ] & 0x0100)
-#define BCR_SWSTYLE(S) ((S)->bcr[BCR_SWS ] & 0x00FF)
-
-typedef struct PCNetState_st PCNetState;
-
-struct PCNetState_st {
- NICState *nic;
- NICConf conf;
- QEMUTimer *poll_timer;
- int rap, isr, lnkst;
- uint32_t rdra, tdra;
- uint8_t prom[16];
- uint16_t csr[128];
- uint16_t bcr[32];
- int xmit_pos;
- uint64_t timer;
- MemoryRegion mmio;
- uint8_t buffer[4096];
- qemu_irq irq;
- void (*phys_mem_read)(void *dma_opaque, hwaddr addr,
- uint8_t *buf, int len, int do_bswap);
- void (*phys_mem_write)(void *dma_opaque, hwaddr addr,
- uint8_t *buf, int len, int do_bswap);
- void *dma_opaque;
- int tx_busy;
- int looptest;
-};
-
-void pcnet_h_reset(void *opaque);
-void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val);
-uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr);
-void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val);
-uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr);
-uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap);
-ssize_t pcnet_receive(NetClientState *nc, const uint8_t *buf, size_t size_);
-void pcnet_set_link_status(NetClientState *nc);
-void pcnet_common_init(DeviceState *dev, PCNetState *s, NetClientInfo *info);
-extern const VMStateDescription vmstate_pcnet;
-#endif
diff --git a/qemu/hw/net/rocker/qmp-norocker.c b/qemu/hw/net/rocker/qmp-norocker.c
deleted file mode 100644
index 6acbcdb02..000000000
--- a/qemu/hw/net/rocker/qmp-norocker.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * QMP Target options - Commands handled based on a target config
- * versus a host config
- *
- * Copyright (c) 2015 David Ahern <dsahern@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "qmp-commands.h"
-#include "qapi/qmp/qerror.h"
-
-RockerSwitch *qmp_query_rocker(const char *name, Error **errp)
-{
- error_setg(errp, QERR_FEATURE_DISABLED, "rocker");
- return NULL;
-};
-
-RockerPortList *qmp_query_rocker_ports(const char *name, Error **errp)
-{
- error_setg(errp, QERR_FEATURE_DISABLED, "rocker");
- return NULL;
-};
-
-RockerOfDpaFlowList *qmp_query_rocker_of_dpa_flows(const char *name,
- bool has_tbl_id,
- uint32_t tbl_id,
- Error **errp)
-{
- error_setg(errp, QERR_FEATURE_DISABLED, "rocker");
- return NULL;
-};
-
-RockerOfDpaGroupList *qmp_query_rocker_of_dpa_groups(const char *name,
- bool has_type,
- uint8_t type,
- Error **errp)
-{
- error_setg(errp, QERR_FEATURE_DISABLED, "rocker");
- return NULL;
-};
diff --git a/qemu/hw/net/rocker/rocker.c b/qemu/hw/net/rocker/rocker.c
deleted file mode 100644
index 30f2ce417..000000000
--- a/qemu/hw/net/rocker/rocker.c
+++ /dev/null
@@ -1,1584 +0,0 @@
-/*
- * QEMU rocker switch emulation - PCI device
- *
- * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com>
- * Copyright (c) 2014 Jiri Pirko <jiri@resnulli.us>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/msix.h"
-#include "net/net.h"
-#include "net/eth.h"
-#include "qemu/iov.h"
-#include "qemu/bitops.h"
-#include "qmp-commands.h"
-
-#include "rocker.h"
-#include "rocker_hw.h"
-#include "rocker_fp.h"
-#include "rocker_desc.h"
-#include "rocker_tlv.h"
-#include "rocker_world.h"
-#include "rocker_of_dpa.h"
-
-struct rocker {
- /* private */
- PCIDevice parent_obj;
- /* public */
-
- MemoryRegion mmio;
- MemoryRegion msix_bar;
-
- /* switch configuration */
- char *name; /* switch name */
- char *world_name; /* world name */
- uint32_t fp_ports; /* front-panel port count */
- NICPeers *fp_ports_peers;
- MACAddr fp_start_macaddr; /* front-panel port 0 mac addr */
- uint64_t switch_id; /* switch id */
-
- /* front-panel ports */
- FpPort *fp_port[ROCKER_FP_PORTS_MAX];
-
- /* register backings */
- uint32_t test_reg;
- uint64_t test_reg64;
- dma_addr_t test_dma_addr;
- uint32_t test_dma_size;
- uint64_t lower32; /* lower 32-bit val in 2-part 64-bit access */
-
- /* desc rings */
- DescRing **rings;
-
- /* switch worlds */
- World *worlds[ROCKER_WORLD_TYPE_MAX];
- World *world_dflt;
-
- QLIST_ENTRY(rocker) next;
-};
-
-#define ROCKER "rocker"
-
-#define to_rocker(obj) \
- OBJECT_CHECK(Rocker, (obj), ROCKER)
-
-static QLIST_HEAD(, rocker) rockers;
-
-Rocker *rocker_find(const char *name)
-{
- Rocker *r;
-
- QLIST_FOREACH(r, &rockers, next)
- if (strcmp(r->name, name) == 0) {
- return r;
- }
-
- return NULL;
-}
-
-World *rocker_get_world(Rocker *r, enum rocker_world_type type)
-{
- if (type < ROCKER_WORLD_TYPE_MAX) {
- return r->worlds[type];
- }
- return NULL;
-}
-
-RockerSwitch *qmp_query_rocker(const char *name, Error **errp)
-{
- RockerSwitch *rocker;
- Rocker *r;
-
- r = rocker_find(name);
- if (!r) {
- error_setg(errp, "rocker %s not found", name);
- return NULL;
- }
-
- rocker = g_new0(RockerSwitch, 1);
- rocker->name = g_strdup(r->name);
- rocker->id = r->switch_id;
- rocker->ports = r->fp_ports;
-
- return rocker;
-}
-
-RockerPortList *qmp_query_rocker_ports(const char *name, Error **errp)
-{
- RockerPortList *list = NULL;
- Rocker *r;
- int i;
-
- r = rocker_find(name);
- if (!r) {
- error_setg(errp, "rocker %s not found", name);
- return NULL;
- }
-
- for (i = r->fp_ports - 1; i >= 0; i--) {
- RockerPortList *info = g_malloc0(sizeof(*info));
- info->value = g_malloc0(sizeof(*info->value));
- struct fp_port *port = r->fp_port[i];
-
- fp_port_get_info(port, info);
- info->next = list;
- list = info;
- }
-
- return list;
-}
-
-uint32_t rocker_fp_ports(Rocker *r)
-{
- return r->fp_ports;
-}
-
-static uint32_t rocker_get_pport_by_tx_ring(Rocker *r,
- DescRing *ring)
-{
- return (desc_ring_index(ring) - 2) / 2 + 1;
-}
-
-static int tx_consume(Rocker *r, DescInfo *info)
-{
- PCIDevice *dev = PCI_DEVICE(r);
- char *buf = desc_get_buf(info, true);
- RockerTlv *tlv_frag;
- RockerTlv *tlvs[ROCKER_TLV_TX_MAX + 1];
- struct iovec iov[ROCKER_TX_FRAGS_MAX] = { { 0, }, };
- uint32_t pport;
- uint32_t port;
- uint16_t tx_offload = ROCKER_TX_OFFLOAD_NONE;
- uint16_t tx_l3_csum_off = 0;
- uint16_t tx_tso_mss = 0;
- uint16_t tx_tso_hdr_len = 0;
- int iovcnt = 0;
- int err = ROCKER_OK;
- int rem;
- int i;
-
- if (!buf) {
- return -ROCKER_ENXIO;
- }
-
- rocker_tlv_parse(tlvs, ROCKER_TLV_TX_MAX, buf, desc_tlv_size(info));
-
- if (!tlvs[ROCKER_TLV_TX_FRAGS]) {
- return -ROCKER_EINVAL;
- }
-
- pport = rocker_get_pport_by_tx_ring(r, desc_get_ring(info));
- if (!fp_port_from_pport(pport, &port)) {
- return -ROCKER_EINVAL;
- }
-
- if (tlvs[ROCKER_TLV_TX_OFFLOAD]) {
- tx_offload = rocker_tlv_get_u8(tlvs[ROCKER_TLV_TX_OFFLOAD]);
- }
-
- switch (tx_offload) {
- case ROCKER_TX_OFFLOAD_L3_CSUM:
- if (!tlvs[ROCKER_TLV_TX_L3_CSUM_OFF]) {
- return -ROCKER_EINVAL;
- }
- break;
- case ROCKER_TX_OFFLOAD_TSO:
- if (!tlvs[ROCKER_TLV_TX_TSO_MSS] ||
- !tlvs[ROCKER_TLV_TX_TSO_HDR_LEN]) {
- return -ROCKER_EINVAL;
- }
- break;
- }
-
- if (tlvs[ROCKER_TLV_TX_L3_CSUM_OFF]) {
- tx_l3_csum_off = rocker_tlv_get_le16(tlvs[ROCKER_TLV_TX_L3_CSUM_OFF]);
- }
-
- if (tlvs[ROCKER_TLV_TX_TSO_MSS]) {
- tx_tso_mss = rocker_tlv_get_le16(tlvs[ROCKER_TLV_TX_TSO_MSS]);
- }
-
- if (tlvs[ROCKER_TLV_TX_TSO_HDR_LEN]) {
- tx_tso_hdr_len = rocker_tlv_get_le16(tlvs[ROCKER_TLV_TX_TSO_HDR_LEN]);
- }
-
- rocker_tlv_for_each_nested(tlv_frag, tlvs[ROCKER_TLV_TX_FRAGS], rem) {
- hwaddr frag_addr;
- uint16_t frag_len;
-
- if (rocker_tlv_type(tlv_frag) != ROCKER_TLV_TX_FRAG) {
- err = -ROCKER_EINVAL;
- goto err_bad_attr;
- }
-
- rocker_tlv_parse_nested(tlvs, ROCKER_TLV_TX_FRAG_ATTR_MAX, tlv_frag);
-
- if (!tlvs[ROCKER_TLV_TX_FRAG_ATTR_ADDR] ||
- !tlvs[ROCKER_TLV_TX_FRAG_ATTR_LEN]) {
- err = -ROCKER_EINVAL;
- goto err_bad_attr;
- }
-
- frag_addr = rocker_tlv_get_le64(tlvs[ROCKER_TLV_TX_FRAG_ATTR_ADDR]);
- frag_len = rocker_tlv_get_le16(tlvs[ROCKER_TLV_TX_FRAG_ATTR_LEN]);
-
- if (iovcnt >= ROCKER_TX_FRAGS_MAX) {
- goto err_too_many_frags;
- }
- iov[iovcnt].iov_len = frag_len;
- iov[iovcnt].iov_base = g_malloc(frag_len);
- if (!iov[iovcnt].iov_base) {
- err = -ROCKER_ENOMEM;
- goto err_no_mem;
- }
-
- if (pci_dma_read(dev, frag_addr, iov[iovcnt].iov_base,
- iov[iovcnt].iov_len)) {
- err = -ROCKER_ENXIO;
- goto err_bad_io;
- }
- iovcnt++;
- }
-
- if (iovcnt) {
- /* XXX perform Tx offloads */
- /* XXX silence compiler for now */
- tx_l3_csum_off += tx_tso_mss = tx_tso_hdr_len = 0;
- }
-
- err = fp_port_eg(r->fp_port[port], iov, iovcnt);
-
-err_too_many_frags:
-err_bad_io:
-err_no_mem:
-err_bad_attr:
- for (i = 0; i < ROCKER_TX_FRAGS_MAX; i++) {
- g_free(iov[i].iov_base);
- }
-
- return err;
-}
-
-static int cmd_get_port_settings(Rocker *r,
- DescInfo *info, char *buf,
- RockerTlv *cmd_info_tlv)
-{
- RockerTlv *tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MAX + 1];
- RockerTlv *nest;
- FpPort *fp_port;
- uint32_t pport;
- uint32_t port;
- uint32_t speed;
- uint8_t duplex;
- uint8_t autoneg;
- uint8_t learning;
- char *phys_name;
- MACAddr macaddr;
- enum rocker_world_type mode;
- size_t tlv_size;
- int pos;
- int err;
-
- rocker_tlv_parse_nested(tlvs, ROCKER_TLV_CMD_PORT_SETTINGS_MAX,
- cmd_info_tlv);
-
- if (!tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_PPORT]) {
- return -ROCKER_EINVAL;
- }
-
- pport = rocker_tlv_get_le32(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_PPORT]);
- if (!fp_port_from_pport(pport, &port)) {
- return -ROCKER_EINVAL;
- }
- fp_port = r->fp_port[port];
-
- err = fp_port_get_settings(fp_port, &speed, &duplex, &autoneg);
- if (err) {
- return err;
- }
-
- fp_port_get_macaddr(fp_port, &macaddr);
- mode = world_type(fp_port_get_world(fp_port));
- learning = fp_port_get_learning(fp_port);
- phys_name = fp_port_get_name(fp_port);
-
- tlv_size = rocker_tlv_total_size(0) + /* nest */
- rocker_tlv_total_size(sizeof(uint32_t)) + /* pport */
- rocker_tlv_total_size(sizeof(uint32_t)) + /* speed */
- rocker_tlv_total_size(sizeof(uint8_t)) + /* duplex */
- rocker_tlv_total_size(sizeof(uint8_t)) + /* autoneg */
- rocker_tlv_total_size(sizeof(macaddr.a)) + /* macaddr */
- rocker_tlv_total_size(sizeof(uint8_t)) + /* mode */
- rocker_tlv_total_size(sizeof(uint8_t)) + /* learning */
- rocker_tlv_total_size(strlen(phys_name));
-
- if (tlv_size > desc_buf_size(info)) {
- return -ROCKER_EMSGSIZE;
- }
-
- pos = 0;
- nest = rocker_tlv_nest_start(buf, &pos, ROCKER_TLV_CMD_INFO);
- rocker_tlv_put_le32(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_PPORT, pport);
- rocker_tlv_put_le32(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_SPEED, speed);
- rocker_tlv_put_u8(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_DUPLEX, duplex);
- rocker_tlv_put_u8(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_AUTONEG, autoneg);
- rocker_tlv_put(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR,
- sizeof(macaddr.a), macaddr.a);
- rocker_tlv_put_u8(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_MODE, mode);
- rocker_tlv_put_u8(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING,
- learning);
- rocker_tlv_put(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_PHYS_NAME,
- strlen(phys_name), phys_name);
- rocker_tlv_nest_end(buf, &pos, nest);
-
- return desc_set_buf(info, tlv_size);
-}
-
-static int cmd_set_port_settings(Rocker *r,
- RockerTlv *cmd_info_tlv)
-{
- RockerTlv *tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MAX + 1];
- FpPort *fp_port;
- uint32_t pport;
- uint32_t port;
- uint32_t speed;
- uint8_t duplex;
- uint8_t autoneg;
- uint8_t learning;
- MACAddr macaddr;
- enum rocker_world_type mode;
- int err;
-
- rocker_tlv_parse_nested(tlvs, ROCKER_TLV_CMD_PORT_SETTINGS_MAX,
- cmd_info_tlv);
-
- if (!tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_PPORT]) {
- return -ROCKER_EINVAL;
- }
-
- pport = rocker_tlv_get_le32(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_PPORT]);
- if (!fp_port_from_pport(pport, &port)) {
- return -ROCKER_EINVAL;
- }
- fp_port = r->fp_port[port];
-
- if (tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_SPEED] &&
- tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_DUPLEX] &&
- tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_AUTONEG]) {
-
- speed = rocker_tlv_get_le32(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_SPEED]);
- duplex = rocker_tlv_get_u8(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_DUPLEX]);
- autoneg = rocker_tlv_get_u8(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_AUTONEG]);
-
- err = fp_port_set_settings(fp_port, speed, duplex, autoneg);
- if (err) {
- return err;
- }
- }
-
- if (tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR]) {
- if (rocker_tlv_len(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR]) !=
- sizeof(macaddr.a)) {
- return -ROCKER_EINVAL;
- }
- memcpy(macaddr.a,
- rocker_tlv_data(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR]),
- sizeof(macaddr.a));
- fp_port_set_macaddr(fp_port, &macaddr);
- }
-
- if (tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MODE]) {
- mode = rocker_tlv_get_u8(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MODE]);
- if (mode >= ROCKER_WORLD_TYPE_MAX) {
- return -ROCKER_EINVAL;
- }
- /* We don't support world change. */
- if (!fp_port_check_world(fp_port, r->worlds[mode])) {
- return -ROCKER_EINVAL;
- }
- }
-
- if (tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING]) {
- learning =
- rocker_tlv_get_u8(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING]);
- fp_port_set_learning(fp_port, learning);
- }
-
- return ROCKER_OK;
-}
-
-static int cmd_consume(Rocker *r, DescInfo *info)
-{
- char *buf = desc_get_buf(info, false);
- RockerTlv *tlvs[ROCKER_TLV_CMD_MAX + 1];
- RockerTlv *info_tlv;
- World *world;
- uint16_t cmd;
- int err;
-
- if (!buf) {
- return -ROCKER_ENXIO;
- }
-
- rocker_tlv_parse(tlvs, ROCKER_TLV_CMD_MAX, buf, desc_tlv_size(info));
-
- if (!tlvs[ROCKER_TLV_CMD_TYPE] || !tlvs[ROCKER_TLV_CMD_INFO]) {
- return -ROCKER_EINVAL;
- }
-
- cmd = rocker_tlv_get_le16(tlvs[ROCKER_TLV_CMD_TYPE]);
- info_tlv = tlvs[ROCKER_TLV_CMD_INFO];
-
- /* This might be reworked to something like this:
- * Every world will have an array of command handlers from
- * ROCKER_TLV_CMD_TYPE_UNSPEC to ROCKER_TLV_CMD_TYPE_MAX. There is
- * up to each world to implement whatever command it want.
- * It can reference "generic" commands as cmd_set_port_settings or
- * cmd_get_port_settings
- */
-
- switch (cmd) {
- case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_ADD:
- case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_MOD:
- case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_DEL:
- case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_GET_STATS:
- case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_ADD:
- case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_MOD:
- case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_DEL:
- case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_GET_STATS:
- world = r->worlds[ROCKER_WORLD_TYPE_OF_DPA];
- err = world_do_cmd(world, info, buf, cmd, info_tlv);
- break;
- case ROCKER_TLV_CMD_TYPE_GET_PORT_SETTINGS:
- err = cmd_get_port_settings(r, info, buf, info_tlv);
- break;
- case ROCKER_TLV_CMD_TYPE_SET_PORT_SETTINGS:
- err = cmd_set_port_settings(r, info_tlv);
- break;
- default:
- err = -ROCKER_EINVAL;
- break;
- }
-
- return err;
-}
-
-static void rocker_msix_irq(Rocker *r, unsigned vector)
-{
- PCIDevice *dev = PCI_DEVICE(r);
-
- DPRINTF("MSI-X notify request for vector %d\n", vector);
- if (vector >= ROCKER_MSIX_VEC_COUNT(r->fp_ports)) {
- DPRINTF("incorrect vector %d\n", vector);
- return;
- }
- msix_notify(dev, vector);
-}
-
-int rocker_event_link_changed(Rocker *r, uint32_t pport, bool link_up)
-{
- DescRing *ring = r->rings[ROCKER_RING_EVENT];
- DescInfo *info = desc_ring_fetch_desc(ring);
- RockerTlv *nest;
- char *buf;
- size_t tlv_size;
- int pos;
- int err;
-
- if (!info) {
- return -ROCKER_ENOBUFS;
- }
-
- tlv_size = rocker_tlv_total_size(sizeof(uint16_t)) + /* event type */
- rocker_tlv_total_size(0) + /* nest */
- rocker_tlv_total_size(sizeof(uint32_t)) + /* pport */
- rocker_tlv_total_size(sizeof(uint8_t)); /* link up */
-
- if (tlv_size > desc_buf_size(info)) {
- err = -ROCKER_EMSGSIZE;
- goto err_too_big;
- }
-
- buf = desc_get_buf(info, false);
- if (!buf) {
- err = -ROCKER_ENOMEM;
- goto err_no_mem;
- }
-
- pos = 0;
- rocker_tlv_put_le32(buf, &pos, ROCKER_TLV_EVENT_TYPE,
- ROCKER_TLV_EVENT_TYPE_LINK_CHANGED);
- nest = rocker_tlv_nest_start(buf, &pos, ROCKER_TLV_EVENT_INFO);
- rocker_tlv_put_le32(buf, &pos, ROCKER_TLV_EVENT_LINK_CHANGED_PPORT, pport);
- rocker_tlv_put_u8(buf, &pos, ROCKER_TLV_EVENT_LINK_CHANGED_LINKUP,
- link_up ? 1 : 0);
- rocker_tlv_nest_end(buf, &pos, nest);
-
- err = desc_set_buf(info, tlv_size);
-
-err_too_big:
-err_no_mem:
- if (desc_ring_post_desc(ring, err)) {
- rocker_msix_irq(r, ROCKER_MSIX_VEC_EVENT);
- }
-
- return err;
-}
-
-int rocker_event_mac_vlan_seen(Rocker *r, uint32_t pport, uint8_t *addr,
- uint16_t vlan_id)
-{
- DescRing *ring = r->rings[ROCKER_RING_EVENT];
- DescInfo *info;
- FpPort *fp_port;
- uint32_t port;
- RockerTlv *nest;
- char *buf;
- size_t tlv_size;
- int pos;
- int err;
-
- if (!fp_port_from_pport(pport, &port)) {
- return -ROCKER_EINVAL;
- }
- fp_port = r->fp_port[port];
- if (!fp_port_get_learning(fp_port)) {
- return ROCKER_OK;
- }
-
- info = desc_ring_fetch_desc(ring);
- if (!info) {
- return -ROCKER_ENOBUFS;
- }
-
- tlv_size = rocker_tlv_total_size(sizeof(uint16_t)) + /* event type */
- rocker_tlv_total_size(0) + /* nest */
- rocker_tlv_total_size(sizeof(uint32_t)) + /* pport */
- rocker_tlv_total_size(ETH_ALEN) + /* mac addr */
- rocker_tlv_total_size(sizeof(uint16_t)); /* vlan_id */
-
- if (tlv_size > desc_buf_size(info)) {
- err = -ROCKER_EMSGSIZE;
- goto err_too_big;
- }
-
- buf = desc_get_buf(info, false);
- if (!buf) {
- err = -ROCKER_ENOMEM;
- goto err_no_mem;
- }
-
- pos = 0;
- rocker_tlv_put_le32(buf, &pos, ROCKER_TLV_EVENT_TYPE,
- ROCKER_TLV_EVENT_TYPE_MAC_VLAN_SEEN);
- nest = rocker_tlv_nest_start(buf, &pos, ROCKER_TLV_EVENT_INFO);
- rocker_tlv_put_le32(buf, &pos, ROCKER_TLV_EVENT_MAC_VLAN_PPORT, pport);
- rocker_tlv_put(buf, &pos, ROCKER_TLV_EVENT_MAC_VLAN_MAC, ETH_ALEN, addr);
- rocker_tlv_put_u16(buf, &pos, ROCKER_TLV_EVENT_MAC_VLAN_VLAN_ID, vlan_id);
- rocker_tlv_nest_end(buf, &pos, nest);
-
- err = desc_set_buf(info, tlv_size);
-
-err_too_big:
-err_no_mem:
- if (desc_ring_post_desc(ring, err)) {
- rocker_msix_irq(r, ROCKER_MSIX_VEC_EVENT);
- }
-
- return err;
-}
-
-static DescRing *rocker_get_rx_ring_by_pport(Rocker *r,
- uint32_t pport)
-{
- return r->rings[(pport - 1) * 2 + 3];
-}
-
-int rx_produce(World *world, uint32_t pport,
- const struct iovec *iov, int iovcnt, uint8_t copy_to_cpu)
-{
- Rocker *r = world_rocker(world);
- PCIDevice *dev = (PCIDevice *)r;
- DescRing *ring = rocker_get_rx_ring_by_pport(r, pport);
- DescInfo *info = desc_ring_fetch_desc(ring);
- char *data;
- size_t data_size = iov_size(iov, iovcnt);
- char *buf;
- uint16_t rx_flags = 0;
- uint16_t rx_csum = 0;
- size_t tlv_size;
- RockerTlv *tlvs[ROCKER_TLV_RX_MAX + 1];
- hwaddr frag_addr;
- uint16_t frag_max_len;
- int pos;
- int err;
-
- if (!info) {
- return -ROCKER_ENOBUFS;
- }
-
- buf = desc_get_buf(info, false);
- if (!buf) {
- err = -ROCKER_ENXIO;
- goto out;
- }
- rocker_tlv_parse(tlvs, ROCKER_TLV_RX_MAX, buf, desc_tlv_size(info));
-
- if (!tlvs[ROCKER_TLV_RX_FRAG_ADDR] ||
- !tlvs[ROCKER_TLV_RX_FRAG_MAX_LEN]) {
- err = -ROCKER_EINVAL;
- goto out;
- }
-
- frag_addr = rocker_tlv_get_le64(tlvs[ROCKER_TLV_RX_FRAG_ADDR]);
- frag_max_len = rocker_tlv_get_le16(tlvs[ROCKER_TLV_RX_FRAG_MAX_LEN]);
-
- if (data_size > frag_max_len) {
- err = -ROCKER_EMSGSIZE;
- goto out;
- }
-
- if (copy_to_cpu) {
- rx_flags |= ROCKER_RX_FLAGS_FWD_OFFLOAD;
- }
-
- /* XXX calc rx flags/csum */
-
- tlv_size = rocker_tlv_total_size(sizeof(uint16_t)) + /* flags */
- rocker_tlv_total_size(sizeof(uint16_t)) + /* scum */
- rocker_tlv_total_size(sizeof(uint64_t)) + /* frag addr */
- rocker_tlv_total_size(sizeof(uint16_t)) + /* frag max len */
- rocker_tlv_total_size(sizeof(uint16_t)); /* frag len */
-
- if (tlv_size > desc_buf_size(info)) {
- err = -ROCKER_EMSGSIZE;
- goto out;
- }
-
- /* TODO:
- * iov dma write can be optimized in similar way e1000 does it in
- * e1000_receive_iov. But maybe if would make sense to introduce
- * generic helper iov_dma_write.
- */
-
- data = g_malloc(data_size);
- if (!data) {
- err = -ROCKER_ENOMEM;
- goto out;
- }
- iov_to_buf(iov, iovcnt, 0, data, data_size);
- pci_dma_write(dev, frag_addr, data, data_size);
- g_free(data);
-
- pos = 0;
- rocker_tlv_put_le16(buf, &pos, ROCKER_TLV_RX_FLAGS, rx_flags);
- rocker_tlv_put_le16(buf, &pos, ROCKER_TLV_RX_CSUM, rx_csum);
- rocker_tlv_put_le64(buf, &pos, ROCKER_TLV_RX_FRAG_ADDR, frag_addr);
- rocker_tlv_put_le16(buf, &pos, ROCKER_TLV_RX_FRAG_MAX_LEN, frag_max_len);
- rocker_tlv_put_le16(buf, &pos, ROCKER_TLV_RX_FRAG_LEN, data_size);
-
- err = desc_set_buf(info, tlv_size);
-
-out:
- if (desc_ring_post_desc(ring, err)) {
- rocker_msix_irq(r, ROCKER_MSIX_VEC_RX(pport - 1));
- }
-
- return err;
-}
-
-int rocker_port_eg(Rocker *r, uint32_t pport,
- const struct iovec *iov, int iovcnt)
-{
- FpPort *fp_port;
- uint32_t port;
-
- if (!fp_port_from_pport(pport, &port)) {
- return -ROCKER_EINVAL;
- }
-
- fp_port = r->fp_port[port];
-
- return fp_port_eg(fp_port, iov, iovcnt);
-}
-
-static void rocker_test_dma_ctrl(Rocker *r, uint32_t val)
-{
- PCIDevice *dev = PCI_DEVICE(r);
- char *buf;
- int i;
-
- buf = g_malloc(r->test_dma_size);
-
- if (!buf) {
- DPRINTF("test dma buffer alloc failed");
- return;
- }
-
- switch (val) {
- case ROCKER_TEST_DMA_CTRL_CLEAR:
- memset(buf, 0, r->test_dma_size);
- break;
- case ROCKER_TEST_DMA_CTRL_FILL:
- memset(buf, 0x96, r->test_dma_size);
- break;
- case ROCKER_TEST_DMA_CTRL_INVERT:
- pci_dma_read(dev, r->test_dma_addr, buf, r->test_dma_size);
- for (i = 0; i < r->test_dma_size; i++) {
- buf[i] = ~buf[i];
- }
- break;
- default:
- DPRINTF("not test dma control val=0x%08x\n", val);
- goto err_out;
- }
- pci_dma_write(dev, r->test_dma_addr, buf, r->test_dma_size);
-
- rocker_msix_irq(r, ROCKER_MSIX_VEC_TEST);
-
-err_out:
- g_free(buf);
-}
-
-static void rocker_reset(DeviceState *dev);
-
-static void rocker_control(Rocker *r, uint32_t val)
-{
- if (val & ROCKER_CONTROL_RESET) {
- rocker_reset(DEVICE(r));
- }
-}
-
-static int rocker_pci_ring_count(Rocker *r)
-{
- /* There are:
- * - command ring
- * - event ring
- * - tx and rx ring per each port
- */
- return 2 + (2 * r->fp_ports);
-}
-
-static bool rocker_addr_is_desc_reg(Rocker *r, hwaddr addr)
-{
- hwaddr start = ROCKER_DMA_DESC_BASE;
- hwaddr end = start + (ROCKER_DMA_DESC_SIZE * rocker_pci_ring_count(r));
-
- return addr >= start && addr < end;
-}
-
-static void rocker_port_phys_enable_write(Rocker *r, uint64_t new)
-{
- int i;
- bool old_enabled;
- bool new_enabled;
- FpPort *fp_port;
-
- for (i = 0; i < r->fp_ports; i++) {
- fp_port = r->fp_port[i];
- old_enabled = fp_port_enabled(fp_port);
- new_enabled = (new >> (i + 1)) & 0x1;
- if (new_enabled == old_enabled) {
- continue;
- }
- if (new_enabled) {
- fp_port_enable(r->fp_port[i]);
- } else {
- fp_port_disable(r->fp_port[i]);
- }
- }
-}
-
-static void rocker_io_writel(void *opaque, hwaddr addr, uint32_t val)
-{
- Rocker *r = opaque;
-
- if (rocker_addr_is_desc_reg(r, addr)) {
- unsigned index = ROCKER_RING_INDEX(addr);
- unsigned offset = addr & ROCKER_DMA_DESC_MASK;
-
- switch (offset) {
- case ROCKER_DMA_DESC_ADDR_OFFSET:
- r->lower32 = (uint64_t)val;
- break;
- case ROCKER_DMA_DESC_ADDR_OFFSET + 4:
- desc_ring_set_base_addr(r->rings[index],
- ((uint64_t)val) << 32 | r->lower32);
- r->lower32 = 0;
- break;
- case ROCKER_DMA_DESC_SIZE_OFFSET:
- desc_ring_set_size(r->rings[index], val);
- break;
- case ROCKER_DMA_DESC_HEAD_OFFSET:
- if (desc_ring_set_head(r->rings[index], val)) {
- rocker_msix_irq(r, desc_ring_get_msix_vector(r->rings[index]));
- }
- break;
- case ROCKER_DMA_DESC_CTRL_OFFSET:
- desc_ring_set_ctrl(r->rings[index], val);
- break;
- case ROCKER_DMA_DESC_CREDITS_OFFSET:
- if (desc_ring_ret_credits(r->rings[index], val)) {
- rocker_msix_irq(r, desc_ring_get_msix_vector(r->rings[index]));
- }
- break;
- default:
- DPRINTF("not implemented dma reg write(l) addr=0x" TARGET_FMT_plx
- " val=0x%08x (ring %d, addr=0x%02x)\n",
- addr, val, index, offset);
- break;
- }
- return;
- }
-
- switch (addr) {
- case ROCKER_TEST_REG:
- r->test_reg = val;
- break;
- case ROCKER_TEST_REG64:
- case ROCKER_TEST_DMA_ADDR:
- case ROCKER_PORT_PHYS_ENABLE:
- r->lower32 = (uint64_t)val;
- break;
- case ROCKER_TEST_REG64 + 4:
- r->test_reg64 = ((uint64_t)val) << 32 | r->lower32;
- r->lower32 = 0;
- break;
- case ROCKER_TEST_IRQ:
- rocker_msix_irq(r, val);
- break;
- case ROCKER_TEST_DMA_SIZE:
- r->test_dma_size = val;
- break;
- case ROCKER_TEST_DMA_ADDR + 4:
- r->test_dma_addr = ((uint64_t)val) << 32 | r->lower32;
- r->lower32 = 0;
- break;
- case ROCKER_TEST_DMA_CTRL:
- rocker_test_dma_ctrl(r, val);
- break;
- case ROCKER_CONTROL:
- rocker_control(r, val);
- break;
- case ROCKER_PORT_PHYS_ENABLE + 4:
- rocker_port_phys_enable_write(r, ((uint64_t)val) << 32 | r->lower32);
- r->lower32 = 0;
- break;
- default:
- DPRINTF("not implemented write(l) addr=0x" TARGET_FMT_plx
- " val=0x%08x\n", addr, val);
- break;
- }
-}
-
-static void rocker_io_writeq(void *opaque, hwaddr addr, uint64_t val)
-{
- Rocker *r = opaque;
-
- if (rocker_addr_is_desc_reg(r, addr)) {
- unsigned index = ROCKER_RING_INDEX(addr);
- unsigned offset = addr & ROCKER_DMA_DESC_MASK;
-
- switch (offset) {
- case ROCKER_DMA_DESC_ADDR_OFFSET:
- desc_ring_set_base_addr(r->rings[index], val);
- break;
- default:
- DPRINTF("not implemented dma reg write(q) addr=0x" TARGET_FMT_plx
- " val=0x" TARGET_FMT_plx " (ring %d, offset=0x%02x)\n",
- addr, val, index, offset);
- break;
- }
- return;
- }
-
- switch (addr) {
- case ROCKER_TEST_REG64:
- r->test_reg64 = val;
- break;
- case ROCKER_TEST_DMA_ADDR:
- r->test_dma_addr = val;
- break;
- case ROCKER_PORT_PHYS_ENABLE:
- rocker_port_phys_enable_write(r, val);
- break;
- default:
- DPRINTF("not implemented write(q) addr=0x" TARGET_FMT_plx
- " val=0x" TARGET_FMT_plx "\n", addr, val);
- break;
- }
-}
-
-#ifdef DEBUG_ROCKER
-#define regname(reg) case (reg): return #reg
-static const char *rocker_reg_name(void *opaque, hwaddr addr)
-{
- Rocker *r = opaque;
-
- if (rocker_addr_is_desc_reg(r, addr)) {
- unsigned index = ROCKER_RING_INDEX(addr);
- unsigned offset = addr & ROCKER_DMA_DESC_MASK;
- static char buf[100];
- char ring_name[10];
-
- switch (index) {
- case 0:
- sprintf(ring_name, "cmd");
- break;
- case 1:
- sprintf(ring_name, "event");
- break;
- default:
- sprintf(ring_name, "%s-%d", index % 2 ? "rx" : "tx",
- (index - 2) / 2);
- }
-
- switch (offset) {
- case ROCKER_DMA_DESC_ADDR_OFFSET:
- sprintf(buf, "Ring[%s] ADDR", ring_name);
- return buf;
- case ROCKER_DMA_DESC_ADDR_OFFSET+4:
- sprintf(buf, "Ring[%s] ADDR+4", ring_name);
- return buf;
- case ROCKER_DMA_DESC_SIZE_OFFSET:
- sprintf(buf, "Ring[%s] SIZE", ring_name);
- return buf;
- case ROCKER_DMA_DESC_HEAD_OFFSET:
- sprintf(buf, "Ring[%s] HEAD", ring_name);
- return buf;
- case ROCKER_DMA_DESC_TAIL_OFFSET:
- sprintf(buf, "Ring[%s] TAIL", ring_name);
- return buf;
- case ROCKER_DMA_DESC_CTRL_OFFSET:
- sprintf(buf, "Ring[%s] CTRL", ring_name);
- return buf;
- case ROCKER_DMA_DESC_CREDITS_OFFSET:
- sprintf(buf, "Ring[%s] CREDITS", ring_name);
- return buf;
- default:
- sprintf(buf, "Ring[%s] ???", ring_name);
- return buf;
- }
- } else {
- switch (addr) {
- regname(ROCKER_BOGUS_REG0);
- regname(ROCKER_BOGUS_REG1);
- regname(ROCKER_BOGUS_REG2);
- regname(ROCKER_BOGUS_REG3);
- regname(ROCKER_TEST_REG);
- regname(ROCKER_TEST_REG64);
- regname(ROCKER_TEST_REG64+4);
- regname(ROCKER_TEST_IRQ);
- regname(ROCKER_TEST_DMA_ADDR);
- regname(ROCKER_TEST_DMA_ADDR+4);
- regname(ROCKER_TEST_DMA_SIZE);
- regname(ROCKER_TEST_DMA_CTRL);
- regname(ROCKER_CONTROL);
- regname(ROCKER_PORT_PHYS_COUNT);
- regname(ROCKER_PORT_PHYS_LINK_STATUS);
- regname(ROCKER_PORT_PHYS_LINK_STATUS+4);
- regname(ROCKER_PORT_PHYS_ENABLE);
- regname(ROCKER_PORT_PHYS_ENABLE+4);
- regname(ROCKER_SWITCH_ID);
- regname(ROCKER_SWITCH_ID+4);
- }
- }
- return "???";
-}
-#else
-static const char *rocker_reg_name(void *opaque, hwaddr addr)
-{
- return NULL;
-}
-#endif
-
-static void rocker_mmio_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned size)
-{
- DPRINTF("Write %s addr " TARGET_FMT_plx
- ", size %u, val " TARGET_FMT_plx "\n",
- rocker_reg_name(opaque, addr), addr, size, val);
-
- switch (size) {
- case 4:
- rocker_io_writel(opaque, addr, val);
- break;
- case 8:
- rocker_io_writeq(opaque, addr, val);
- break;
- }
-}
-
-static uint64_t rocker_port_phys_link_status(Rocker *r)
-{
- int i;
- uint64_t status = 0;
-
- for (i = 0; i < r->fp_ports; i++) {
- FpPort *port = r->fp_port[i];
-
- if (fp_port_get_link_up(port)) {
- status |= 1 << (i + 1);
- }
- }
- return status;
-}
-
-static uint64_t rocker_port_phys_enable_read(Rocker *r)
-{
- int i;
- uint64_t ret = 0;
-
- for (i = 0; i < r->fp_ports; i++) {
- FpPort *port = r->fp_port[i];
-
- if (fp_port_enabled(port)) {
- ret |= 1 << (i + 1);
- }
- }
- return ret;
-}
-
-static uint32_t rocker_io_readl(void *opaque, hwaddr addr)
-{
- Rocker *r = opaque;
- uint32_t ret;
-
- if (rocker_addr_is_desc_reg(r, addr)) {
- unsigned index = ROCKER_RING_INDEX(addr);
- unsigned offset = addr & ROCKER_DMA_DESC_MASK;
-
- switch (offset) {
- case ROCKER_DMA_DESC_ADDR_OFFSET:
- ret = (uint32_t)desc_ring_get_base_addr(r->rings[index]);
- break;
- case ROCKER_DMA_DESC_ADDR_OFFSET + 4:
- ret = (uint32_t)(desc_ring_get_base_addr(r->rings[index]) >> 32);
- break;
- case ROCKER_DMA_DESC_SIZE_OFFSET:
- ret = desc_ring_get_size(r->rings[index]);
- break;
- case ROCKER_DMA_DESC_HEAD_OFFSET:
- ret = desc_ring_get_head(r->rings[index]);
- break;
- case ROCKER_DMA_DESC_TAIL_OFFSET:
- ret = desc_ring_get_tail(r->rings[index]);
- break;
- case ROCKER_DMA_DESC_CREDITS_OFFSET:
- ret = desc_ring_get_credits(r->rings[index]);
- break;
- default:
- DPRINTF("not implemented dma reg read(l) addr=0x" TARGET_FMT_plx
- " (ring %d, addr=0x%02x)\n", addr, index, offset);
- ret = 0;
- break;
- }
- return ret;
- }
-
- switch (addr) {
- case ROCKER_BOGUS_REG0:
- case ROCKER_BOGUS_REG1:
- case ROCKER_BOGUS_REG2:
- case ROCKER_BOGUS_REG3:
- ret = 0xDEADBABE;
- break;
- case ROCKER_TEST_REG:
- ret = r->test_reg * 2;
- break;
- case ROCKER_TEST_REG64:
- ret = (uint32_t)(r->test_reg64 * 2);
- break;
- case ROCKER_TEST_REG64 + 4:
- ret = (uint32_t)((r->test_reg64 * 2) >> 32);
- break;
- case ROCKER_TEST_DMA_SIZE:
- ret = r->test_dma_size;
- break;
- case ROCKER_TEST_DMA_ADDR:
- ret = (uint32_t)r->test_dma_addr;
- break;
- case ROCKER_TEST_DMA_ADDR + 4:
- ret = (uint32_t)(r->test_dma_addr >> 32);
- break;
- case ROCKER_PORT_PHYS_COUNT:
- ret = r->fp_ports;
- break;
- case ROCKER_PORT_PHYS_LINK_STATUS:
- ret = (uint32_t)rocker_port_phys_link_status(r);
- break;
- case ROCKER_PORT_PHYS_LINK_STATUS + 4:
- ret = (uint32_t)(rocker_port_phys_link_status(r) >> 32);
- break;
- case ROCKER_PORT_PHYS_ENABLE:
- ret = (uint32_t)rocker_port_phys_enable_read(r);
- break;
- case ROCKER_PORT_PHYS_ENABLE + 4:
- ret = (uint32_t)(rocker_port_phys_enable_read(r) >> 32);
- break;
- case ROCKER_SWITCH_ID:
- ret = (uint32_t)r->switch_id;
- break;
- case ROCKER_SWITCH_ID + 4:
- ret = (uint32_t)(r->switch_id >> 32);
- break;
- default:
- DPRINTF("not implemented read(l) addr=0x" TARGET_FMT_plx "\n", addr);
- ret = 0;
- break;
- }
- return ret;
-}
-
-static uint64_t rocker_io_readq(void *opaque, hwaddr addr)
-{
- Rocker *r = opaque;
- uint64_t ret;
-
- if (rocker_addr_is_desc_reg(r, addr)) {
- unsigned index = ROCKER_RING_INDEX(addr);
- unsigned offset = addr & ROCKER_DMA_DESC_MASK;
-
- switch (addr & ROCKER_DMA_DESC_MASK) {
- case ROCKER_DMA_DESC_ADDR_OFFSET:
- ret = desc_ring_get_base_addr(r->rings[index]);
- break;
- default:
- DPRINTF("not implemented dma reg read(q) addr=0x" TARGET_FMT_plx
- " (ring %d, addr=0x%02x)\n", addr, index, offset);
- ret = 0;
- break;
- }
- return ret;
- }
-
- switch (addr) {
- case ROCKER_BOGUS_REG0:
- case ROCKER_BOGUS_REG2:
- ret = 0xDEADBABEDEADBABEULL;
- break;
- case ROCKER_TEST_REG64:
- ret = r->test_reg64 * 2;
- break;
- case ROCKER_TEST_DMA_ADDR:
- ret = r->test_dma_addr;
- break;
- case ROCKER_PORT_PHYS_LINK_STATUS:
- ret = rocker_port_phys_link_status(r);
- break;
- case ROCKER_PORT_PHYS_ENABLE:
- ret = rocker_port_phys_enable_read(r);
- break;
- case ROCKER_SWITCH_ID:
- ret = r->switch_id;
- break;
- default:
- DPRINTF("not implemented read(q) addr=0x" TARGET_FMT_plx "\n", addr);
- ret = 0;
- break;
- }
- return ret;
-}
-
-static uint64_t rocker_mmio_read(void *opaque, hwaddr addr, unsigned size)
-{
- DPRINTF("Read %s addr " TARGET_FMT_plx ", size %u\n",
- rocker_reg_name(opaque, addr), addr, size);
-
- switch (size) {
- case 4:
- return rocker_io_readl(opaque, addr);
- case 8:
- return rocker_io_readq(opaque, addr);
- }
-
- return -1;
-}
-
-static const MemoryRegionOps rocker_mmio_ops = {
- .read = rocker_mmio_read,
- .write = rocker_mmio_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 8,
- },
- .impl = {
- .min_access_size = 4,
- .max_access_size = 8,
- },
-};
-
-static void rocker_msix_vectors_unuse(Rocker *r,
- unsigned int num_vectors)
-{
- PCIDevice *dev = PCI_DEVICE(r);
- int i;
-
- for (i = 0; i < num_vectors; i++) {
- msix_vector_unuse(dev, i);
- }
-}
-
-static int rocker_msix_vectors_use(Rocker *r,
- unsigned int num_vectors)
-{
- PCIDevice *dev = PCI_DEVICE(r);
- int err;
- int i;
-
- for (i = 0; i < num_vectors; i++) {
- err = msix_vector_use(dev, i);
- if (err) {
- goto rollback;
- }
- }
- return 0;
-
-rollback:
- rocker_msix_vectors_unuse(r, i);
- return err;
-}
-
-static int rocker_msix_init(Rocker *r)
-{
- PCIDevice *dev = PCI_DEVICE(r);
- int err;
-
- err = msix_init(dev, ROCKER_MSIX_VEC_COUNT(r->fp_ports),
- &r->msix_bar,
- ROCKER_PCI_MSIX_BAR_IDX, ROCKER_PCI_MSIX_TABLE_OFFSET,
- &r->msix_bar,
- ROCKER_PCI_MSIX_BAR_IDX, ROCKER_PCI_MSIX_PBA_OFFSET,
- 0);
- if (err) {
- return err;
- }
-
- err = rocker_msix_vectors_use(r, ROCKER_MSIX_VEC_COUNT(r->fp_ports));
- if (err) {
- goto err_msix_vectors_use;
- }
-
- return 0;
-
-err_msix_vectors_use:
- msix_uninit(dev, &r->msix_bar, &r->msix_bar);
- return err;
-}
-
-static void rocker_msix_uninit(Rocker *r)
-{
- PCIDevice *dev = PCI_DEVICE(r);
-
- msix_uninit(dev, &r->msix_bar, &r->msix_bar);
- rocker_msix_vectors_unuse(r, ROCKER_MSIX_VEC_COUNT(r->fp_ports));
-}
-
-static World *rocker_world_type_by_name(Rocker *r, const char *name)
-{
- int i;
-
- for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) {
- if (strcmp(name, world_name(r->worlds[i])) == 0) {
- return r->worlds[i];
- }
- }
- return NULL;
-}
-
-static int pci_rocker_init(PCIDevice *dev)
-{
- Rocker *r = to_rocker(dev);
- const MACAddr zero = { .a = { 0, 0, 0, 0, 0, 0 } };
- const MACAddr dflt = { .a = { 0x52, 0x54, 0x00, 0x12, 0x35, 0x01 } };
- static int sw_index;
- int i, err = 0;
-
- /* allocate worlds */
-
- r->worlds[ROCKER_WORLD_TYPE_OF_DPA] = of_dpa_world_alloc(r);
-
- for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) {
- if (!r->worlds[i]) {
- err = -ENOMEM;
- goto err_world_alloc;
- }
- }
-
- if (!r->world_name) {
- r->world_name = g_strdup(world_name(r->worlds[ROCKER_WORLD_TYPE_OF_DPA]));
- }
-
- r->world_dflt = rocker_world_type_by_name(r, r->world_name);
- if (!r->world_dflt) {
- fprintf(stderr,
- "rocker: requested world \"%s\" does not exist\n",
- r->world_name);
- err = -EINVAL;
- goto err_world_type_by_name;
- }
-
- /* set up memory-mapped region at BAR0 */
-
- memory_region_init_io(&r->mmio, OBJECT(r), &rocker_mmio_ops, r,
- "rocker-mmio", ROCKER_PCI_BAR0_SIZE);
- pci_register_bar(dev, ROCKER_PCI_BAR0_IDX,
- PCI_BASE_ADDRESS_SPACE_MEMORY, &r->mmio);
-
- /* set up memory-mapped region for MSI-X */
-
- memory_region_init(&r->msix_bar, OBJECT(r), "rocker-msix-bar",
- ROCKER_PCI_MSIX_BAR_SIZE);
- pci_register_bar(dev, ROCKER_PCI_MSIX_BAR_IDX,
- PCI_BASE_ADDRESS_SPACE_MEMORY, &r->msix_bar);
-
- /* MSI-X init */
-
- err = rocker_msix_init(r);
- if (err) {
- goto err_msix_init;
- }
-
- /* validate switch properties */
-
- if (!r->name) {
- r->name = g_strdup(ROCKER);
- }
-
- if (rocker_find(r->name)) {
- err = -EEXIST;
- goto err_duplicate;
- }
-
- /* Rocker name is passed in port name requests to OS with the intention
- * that the name is used in interface names. Limit the length of the
- * rocker name to avoid naming problems in the OS. Also, adding the
- * port number as p# and unganged breakout b#, where # is at most 2
- * digits, so leave room for it too (-1 for string terminator, -3 for
- * p# and -3 for b#)
- */
-#define ROCKER_IFNAMSIZ 16
-#define MAX_ROCKER_NAME_LEN (ROCKER_IFNAMSIZ - 1 - 3 - 3)
- if (strlen(r->name) > MAX_ROCKER_NAME_LEN) {
- fprintf(stderr,
- "rocker: name too long; please shorten to at most %d chars\n",
- MAX_ROCKER_NAME_LEN);
- return -EINVAL;
- }
-
- if (memcmp(&r->fp_start_macaddr, &zero, sizeof(zero)) == 0) {
- memcpy(&r->fp_start_macaddr, &dflt, sizeof(dflt));
- r->fp_start_macaddr.a[4] += (sw_index++);
- }
-
- if (!r->switch_id) {
- memcpy(&r->switch_id, &r->fp_start_macaddr,
- sizeof(r->fp_start_macaddr));
- }
-
- if (r->fp_ports > ROCKER_FP_PORTS_MAX) {
- r->fp_ports = ROCKER_FP_PORTS_MAX;
- }
-
- r->rings = g_new(DescRing *, rocker_pci_ring_count(r));
- if (!r->rings) {
- goto err_rings_alloc;
- }
-
- /* Rings are ordered like this:
- * - command ring
- * - event ring
- * - port0 tx ring
- * - port0 rx ring
- * - port1 tx ring
- * - port1 rx ring
- * .....
- */
-
- err = -ENOMEM;
- for (i = 0; i < rocker_pci_ring_count(r); i++) {
- DescRing *ring = desc_ring_alloc(r, i);
-
- if (!ring) {
- goto err_ring_alloc;
- }
-
- if (i == ROCKER_RING_CMD) {
- desc_ring_set_consume(ring, cmd_consume, ROCKER_MSIX_VEC_CMD);
- } else if (i == ROCKER_RING_EVENT) {
- desc_ring_set_consume(ring, NULL, ROCKER_MSIX_VEC_EVENT);
- } else if (i % 2 == 0) {
- desc_ring_set_consume(ring, tx_consume,
- ROCKER_MSIX_VEC_TX((i - 2) / 2));
- } else if (i % 2 == 1) {
- desc_ring_set_consume(ring, NULL, ROCKER_MSIX_VEC_RX((i - 3) / 2));
- }
-
- r->rings[i] = ring;
- }
-
- for (i = 0; i < r->fp_ports; i++) {
- FpPort *port =
- fp_port_alloc(r, r->name, &r->fp_start_macaddr,
- i, &r->fp_ports_peers[i]);
-
- if (!port) {
- goto err_port_alloc;
- }
-
- r->fp_port[i] = port;
- fp_port_set_world(port, r->world_dflt);
- }
-
- QLIST_INSERT_HEAD(&rockers, r, next);
-
- return 0;
-
-err_port_alloc:
- for (--i; i >= 0; i--) {
- FpPort *port = r->fp_port[i];
- fp_port_free(port);
- }
- i = rocker_pci_ring_count(r);
-err_ring_alloc:
- for (--i; i >= 0; i--) {
- desc_ring_free(r->rings[i]);
- }
- g_free(r->rings);
-err_rings_alloc:
-err_duplicate:
- rocker_msix_uninit(r);
-err_msix_init:
- object_unparent(OBJECT(&r->msix_bar));
- object_unparent(OBJECT(&r->mmio));
-err_world_type_by_name:
-err_world_alloc:
- for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) {
- if (r->worlds[i]) {
- world_free(r->worlds[i]);
- }
- }
- return err;
-}
-
-static void pci_rocker_uninit(PCIDevice *dev)
-{
- Rocker *r = to_rocker(dev);
- int i;
-
- QLIST_REMOVE(r, next);
-
- for (i = 0; i < r->fp_ports; i++) {
- FpPort *port = r->fp_port[i];
-
- fp_port_free(port);
- r->fp_port[i] = NULL;
- }
-
- for (i = 0; i < rocker_pci_ring_count(r); i++) {
- if (r->rings[i]) {
- desc_ring_free(r->rings[i]);
- }
- }
- g_free(r->rings);
-
- rocker_msix_uninit(r);
- object_unparent(OBJECT(&r->msix_bar));
- object_unparent(OBJECT(&r->mmio));
-
- for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) {
- if (r->worlds[i]) {
- world_free(r->worlds[i]);
- }
- }
- g_free(r->fp_ports_peers);
-}
-
-static void rocker_reset(DeviceState *dev)
-{
- Rocker *r = to_rocker(dev);
- int i;
-
- for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) {
- if (r->worlds[i]) {
- world_reset(r->worlds[i]);
- }
- }
- for (i = 0; i < r->fp_ports; i++) {
- fp_port_reset(r->fp_port[i]);
- fp_port_set_world(r->fp_port[i], r->world_dflt);
- }
-
- r->test_reg = 0;
- r->test_reg64 = 0;
- r->test_dma_addr = 0;
- r->test_dma_size = 0;
-
- for (i = 0; i < rocker_pci_ring_count(r); i++) {
- desc_ring_reset(r->rings[i]);
- }
-
- DPRINTF("Reset done\n");
-}
-
-static Property rocker_properties[] = {
- DEFINE_PROP_STRING("name", Rocker, name),
- DEFINE_PROP_STRING("world", Rocker, world_name),
- DEFINE_PROP_MACADDR("fp_start_macaddr", Rocker,
- fp_start_macaddr),
- DEFINE_PROP_UINT64("switch_id", Rocker,
- switch_id, 0),
- DEFINE_PROP_ARRAY("ports", Rocker, fp_ports,
- fp_ports_peers, qdev_prop_netdev, NICPeers),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static const VMStateDescription rocker_vmsd = {
- .name = ROCKER,
- .unmigratable = 1,
-};
-
-static void rocker_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->init = pci_rocker_init;
- k->exit = pci_rocker_uninit;
- k->vendor_id = PCI_VENDOR_ID_REDHAT;
- k->device_id = PCI_DEVICE_ID_REDHAT_ROCKER;
- k->revision = ROCKER_PCI_REVISION;
- k->class_id = PCI_CLASS_NETWORK_OTHER;
- set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
- dc->desc = "Rocker Switch";
- dc->reset = rocker_reset;
- dc->props = rocker_properties;
- dc->vmsd = &rocker_vmsd;
-}
-
-static const TypeInfo rocker_info = {
- .name = ROCKER,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(Rocker),
- .class_init = rocker_class_init,
-};
-
-static void rocker_register_types(void)
-{
- type_register_static(&rocker_info);
-}
-
-type_init(rocker_register_types)
diff --git a/qemu/hw/net/rocker/rocker.h b/qemu/hw/net/rocker/rocker.h
deleted file mode 100644
index f9c80f801..000000000
--- a/qemu/hw/net/rocker/rocker.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * QEMU rocker switch emulation
- *
- * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com>
- * Copyright (c) 2014 Jiri Pirko <jiri@resnulli.us>
- * Copyright (c) 2014 Neil Horman <nhorman@tuxdriver.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#ifndef _ROCKER_H_
-#define _ROCKER_H_
-
-#include "qemu/sockets.h"
-
-#if defined(DEBUG_ROCKER)
-# define DPRINTF(fmt, ...) \
- do { \
- struct timeval tv; \
- char timestr[64]; \
- time_t now; \
- gettimeofday(&tv, NULL); \
- now = tv.tv_sec; \
- strftime(timestr, sizeof(timestr), "%T", localtime(&now)); \
- fprintf(stderr, "%s.%06ld ", timestr, tv.tv_usec); \
- fprintf(stderr, "ROCKER: " fmt, ## __VA_ARGS__); \
- } while (0)
-#else
-static inline GCC_FMT_ATTR(1, 2) int DPRINTF(const char *fmt, ...)
-{
- return 0;
-}
-#endif
-
-#define __le16 uint16_t
-#define __le32 uint32_t
-#define __le64 uint64_t
-
-#define __be16 uint16_t
-#define __be32 uint32_t
-#define __be64 uint64_t
-
-static inline bool ipv4_addr_is_multicast(__be32 addr)
-{
- return (addr & htonl(0xf0000000)) == htonl(0xe0000000);
-}
-
-typedef struct ipv6_addr {
- union {
- uint8_t addr8[16];
- __be16 addr16[8];
- __be32 addr32[4];
- };
-} Ipv6Addr;
-
-static inline bool ipv6_addr_is_multicast(const Ipv6Addr *addr)
-{
- return (addr->addr32[0] & htonl(0xFF000000)) == htonl(0xFF000000);
-}
-
-typedef struct rocker Rocker;
-typedef struct world World;
-typedef struct desc_info DescInfo;
-typedef struct desc_ring DescRing;
-
-Rocker *rocker_find(const char *name);
-uint32_t rocker_fp_ports(Rocker *r);
-int rocker_event_link_changed(Rocker *r, uint32_t pport, bool link_up);
-int rocker_event_mac_vlan_seen(Rocker *r, uint32_t pport, uint8_t *addr,
- uint16_t vlan_id);
-int rx_produce(World *world, uint32_t pport,
- const struct iovec *iov, int iovcnt, uint8_t copy_to_cpu);
-int rocker_port_eg(Rocker *r, uint32_t pport,
- const struct iovec *iov, int iovcnt);
-
-#endif /* _ROCKER_H_ */
diff --git a/qemu/hw/net/rocker/rocker_desc.c b/qemu/hw/net/rocker/rocker_desc.c
deleted file mode 100644
index ac02797b7..000000000
--- a/qemu/hw/net/rocker/rocker_desc.c
+++ /dev/null
@@ -1,374 +0,0 @@
-/*
- * QEMU rocker switch emulation - Descriptor ring support
- *
- * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include "qemu/osdep.h"
-#include "net/net.h"
-#include "hw/hw.h"
-#include "hw/pci/pci.h"
-
-#include "rocker.h"
-#include "rocker_hw.h"
-#include "rocker_desc.h"
-
-struct desc_ring {
- hwaddr base_addr;
- uint32_t size;
- uint32_t head;
- uint32_t tail;
- uint32_t ctrl;
- uint32_t credits;
- Rocker *r;
- DescInfo *info;
- int index;
- desc_ring_consume *consume;
- unsigned msix_vector;
-};
-
-struct desc_info {
- DescRing *ring;
- RockerDesc desc;
- char *buf;
- size_t buf_size;
-};
-
-uint16_t desc_buf_size(DescInfo *info)
-{
- return le16_to_cpu(info->desc.buf_size);
-}
-
-uint16_t desc_tlv_size(DescInfo *info)
-{
- return le16_to_cpu(info->desc.tlv_size);
-}
-
-char *desc_get_buf(DescInfo *info, bool read_only)
-{
- PCIDevice *dev = PCI_DEVICE(info->ring->r);
- size_t size = read_only ? le16_to_cpu(info->desc.tlv_size) :
- le16_to_cpu(info->desc.buf_size);
-
- if (size > info->buf_size) {
- info->buf = g_realloc(info->buf, size);
- info->buf_size = size;
- }
-
- if (!info->buf) {
- return NULL;
- }
-
- if (pci_dma_read(dev, le64_to_cpu(info->desc.buf_addr), info->buf, size)) {
- return NULL;
- }
-
- return info->buf;
-}
-
-int desc_set_buf(DescInfo *info, size_t tlv_size)
-{
- PCIDevice *dev = PCI_DEVICE(info->ring->r);
-
- if (tlv_size > info->buf_size) {
- DPRINTF("ERROR: trying to write more to desc buf than it "
- "can hold buf_size %zu tlv_size %zu\n",
- info->buf_size, tlv_size);
- return -ROCKER_EMSGSIZE;
- }
-
- info->desc.tlv_size = cpu_to_le16(tlv_size);
- pci_dma_write(dev, le64_to_cpu(info->desc.buf_addr), info->buf, tlv_size);
-
- return ROCKER_OK;
-}
-
-DescRing *desc_get_ring(DescInfo *info)
-{
- return info->ring;
-}
-
-int desc_ring_index(DescRing *ring)
-{
- return ring->index;
-}
-
-static bool desc_ring_empty(DescRing *ring)
-{
- return ring->head == ring->tail;
-}
-
-bool desc_ring_set_base_addr(DescRing *ring, uint64_t base_addr)
-{
- if (base_addr & 0x7) {
- DPRINTF("ERROR: ring[%d] desc base addr (0x" TARGET_FMT_plx
- ") not 8-byte aligned\n", ring->index, base_addr);
- return false;
- }
-
- ring->base_addr = base_addr;
-
- return true;
-}
-
-uint64_t desc_ring_get_base_addr(DescRing *ring)
-{
- return ring->base_addr;
-}
-
-bool desc_ring_set_size(DescRing *ring, uint32_t size)
-{
- int i;
-
- if (size < 2 || size > 0x10000 || (size & (size - 1))) {
- DPRINTF("ERROR: ring[%d] size (%d) not a power of 2 "
- "or in range [2, 64K]\n", ring->index, size);
- return false;
- }
-
- for (i = 0; i < ring->size; i++) {
- g_free(ring->info[i].buf);
- }
-
- ring->size = size;
- ring->head = ring->tail = 0;
-
- ring->info = g_renew(DescInfo, ring->info, size);
- if (!ring->info) {
- return false;
- }
-
- memset(ring->info, 0, size * sizeof(DescInfo));
-
- for (i = 0; i < size; i++) {
- ring->info[i].ring = ring;
- }
-
- return true;
-}
-
-uint32_t desc_ring_get_size(DescRing *ring)
-{
- return ring->size;
-}
-
-static DescInfo *desc_read(DescRing *ring, uint32_t index)
-{
- PCIDevice *dev = PCI_DEVICE(ring->r);
- DescInfo *info = &ring->info[index];
- hwaddr addr = ring->base_addr + (sizeof(RockerDesc) * index);
-
- pci_dma_read(dev, addr, &info->desc, sizeof(info->desc));
-
- return info;
-}
-
-static void desc_write(DescRing *ring, uint32_t index)
-{
- PCIDevice *dev = PCI_DEVICE(ring->r);
- DescInfo *info = &ring->info[index];
- hwaddr addr = ring->base_addr + (sizeof(RockerDesc) * index);
-
- pci_dma_write(dev, addr, &info->desc, sizeof(info->desc));
-}
-
-static bool desc_ring_base_addr_check(DescRing *ring)
-{
- if (!ring->base_addr) {
- DPRINTF("ERROR: ring[%d] not-initialized desc base address!\n",
- ring->index);
- return false;
- }
- return true;
-}
-
-static DescInfo *__desc_ring_fetch_desc(DescRing *ring)
-{
- return desc_read(ring, ring->tail);
-}
-
-DescInfo *desc_ring_fetch_desc(DescRing *ring)
-{
- if (desc_ring_empty(ring) || !desc_ring_base_addr_check(ring)) {
- return NULL;
- }
-
- return desc_read(ring, ring->tail);
-}
-
-static bool __desc_ring_post_desc(DescRing *ring, int err)
-{
- uint16_t comp_err = 0x8000 | (uint16_t)-err;
- DescInfo *info = &ring->info[ring->tail];
-
- info->desc.comp_err = cpu_to_le16(comp_err);
- desc_write(ring, ring->tail);
- ring->tail = (ring->tail + 1) % ring->size;
-
- /* return true if starting credit count */
-
- return ring->credits++ == 0;
-}
-
-bool desc_ring_post_desc(DescRing *ring, int err)
-{
- if (desc_ring_empty(ring)) {
- DPRINTF("ERROR: ring[%d] trying to post desc to empty ring\n",
- ring->index);
- return false;
- }
-
- if (!desc_ring_base_addr_check(ring)) {
- return false;
- }
-
- return __desc_ring_post_desc(ring, err);
-}
-
-static bool ring_pump(DescRing *ring)
-{
- DescInfo *info;
- bool primed = false;
- int err;
-
- /* If the ring has a consumer, call consumer for each
- * desc starting at tail and stopping when tail reaches
- * head (the empty ring condition).
- */
-
- if (ring->consume) {
- while (ring->head != ring->tail) {
- info = __desc_ring_fetch_desc(ring);
- err = ring->consume(ring->r, info);
- if (__desc_ring_post_desc(ring, err)) {
- primed = true;
- }
- }
- }
-
- return primed;
-}
-
-bool desc_ring_set_head(DescRing *ring, uint32_t new)
-{
- uint32_t tail = ring->tail;
- uint32_t head = ring->head;
-
- if (!desc_ring_base_addr_check(ring)) {
- return false;
- }
-
- if (new >= ring->size) {
- DPRINTF("ERROR: trying to set head (%d) past ring[%d] size (%d)\n",
- new, ring->index, ring->size);
- return false;
- }
-
- if (((head < tail) && ((new >= tail) || (new < head))) ||
- ((head > tail) && ((new >= tail) && (new < head)))) {
- DPRINTF("ERROR: trying to wrap ring[%d] "
- "(head %d, tail %d, new head %d)\n",
- ring->index, head, tail, new);
- return false;
- }
-
- if (new == ring->head) {
- DPRINTF("WARNING: setting head (%d) to current head position\n", new);
- }
-
- ring->head = new;
-
- return ring_pump(ring);
-}
-
-uint32_t desc_ring_get_head(DescRing *ring)
-{
- return ring->head;
-}
-
-uint32_t desc_ring_get_tail(DescRing *ring)
-{
- return ring->tail;
-}
-
-void desc_ring_set_ctrl(DescRing *ring, uint32_t val)
-{
- if (val & ROCKER_DMA_DESC_CTRL_RESET) {
- DPRINTF("ring[%d] resetting\n", ring->index);
- desc_ring_reset(ring);
- }
-}
-
-bool desc_ring_ret_credits(DescRing *ring, uint32_t credits)
-{
- if (credits > ring->credits) {
- DPRINTF("ERROR: trying to return more credits (%d) "
- "than are outstanding (%d)\n", credits, ring->credits);
- ring->credits = 0;
- return false;
- }
-
- ring->credits -= credits;
-
- /* return true if credits are still outstanding */
-
- return ring->credits > 0;
-}
-
-uint32_t desc_ring_get_credits(DescRing *ring)
-{
- return ring->credits;
-}
-
-void desc_ring_set_consume(DescRing *ring, desc_ring_consume *consume,
- unsigned vector)
-{
- ring->consume = consume;
- ring->msix_vector = vector;
-}
-
-unsigned desc_ring_get_msix_vector(DescRing *ring)
-{
- return ring->msix_vector;
-}
-
-DescRing *desc_ring_alloc(Rocker *r, int index)
-{
- DescRing *ring;
-
- ring = g_new0(DescRing, 1);
- if (!ring) {
- return NULL;
- }
-
- ring->r = r;
- ring->index = index;
-
- return ring;
-}
-
-void desc_ring_free(DescRing *ring)
-{
- g_free(ring->info);
- g_free(ring);
-}
-
-void desc_ring_reset(DescRing *ring)
-{
- ring->base_addr = 0;
- ring->size = 0;
- ring->head = 0;
- ring->tail = 0;
- ring->ctrl = 0;
- ring->credits = 0;
-}
diff --git a/qemu/hw/net/rocker/rocker_desc.h b/qemu/hw/net/rocker/rocker_desc.h
deleted file mode 100644
index d4041f5c4..000000000
--- a/qemu/hw/net/rocker/rocker_desc.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * QEMU rocker switch emulation - Descriptor ring support
- *
- * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-
-#ifndef _ROCKER_DESC_H_
-#define _ROCKER_DESC_H_
-
-#include "rocker_hw.h"
-
-typedef int (desc_ring_consume)(Rocker *r, DescInfo *info);
-
-uint16_t desc_buf_size(DescInfo *info);
-uint16_t desc_tlv_size(DescInfo *info);
-char *desc_get_buf(DescInfo *info, bool read_only);
-int desc_set_buf(DescInfo *info, size_t tlv_size);
-DescRing *desc_get_ring(DescInfo *info);
-
-int desc_ring_index(DescRing *ring);
-bool desc_ring_set_base_addr(DescRing *ring, uint64_t base_addr);
-uint64_t desc_ring_get_base_addr(DescRing *ring);
-bool desc_ring_set_size(DescRing *ring, uint32_t size);
-uint32_t desc_ring_get_size(DescRing *ring);
-bool desc_ring_set_head(DescRing *ring, uint32_t new);
-uint32_t desc_ring_get_head(DescRing *ring);
-uint32_t desc_ring_get_tail(DescRing *ring);
-void desc_ring_set_ctrl(DescRing *ring, uint32_t val);
-bool desc_ring_ret_credits(DescRing *ring, uint32_t credits);
-uint32_t desc_ring_get_credits(DescRing *ring);
-
-DescInfo *desc_ring_fetch_desc(DescRing *ring);
-bool desc_ring_post_desc(DescRing *ring, int status);
-
-void desc_ring_set_consume(DescRing *ring, desc_ring_consume *consume,
- unsigned vector);
-unsigned desc_ring_get_msix_vector(DescRing *ring);
-DescRing *desc_ring_alloc(Rocker *r, int index);
-void desc_ring_free(DescRing *ring);
-void desc_ring_reset(DescRing *ring);
-
-#endif
diff --git a/qemu/hw/net/rocker/rocker_fp.c b/qemu/hw/net/rocker/rocker_fp.c
deleted file mode 100644
index 0149899c6..000000000
--- a/qemu/hw/net/rocker/rocker_fp.c
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * QEMU rocker switch emulation - front-panel ports
- *
- * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include "qemu/osdep.h"
-#include "net/clients.h"
-
-#include "rocker.h"
-#include "rocker_hw.h"
-#include "rocker_fp.h"
-#include "rocker_world.h"
-
-enum duplex {
- DUPLEX_HALF = 0,
- DUPLEX_FULL
-};
-
-struct fp_port {
- Rocker *r;
- World *world;
- unsigned int index;
- char *name;
- uint32_t pport;
- bool enabled;
- uint32_t speed;
- uint8_t duplex;
- uint8_t autoneg;
- uint8_t learning;
- NICState *nic;
- NICConf conf;
-};
-
-char *fp_port_get_name(FpPort *port)
-{
- return port->name;
-}
-
-bool fp_port_get_link_up(FpPort *port)
-{
- return !qemu_get_queue(port->nic)->link_down;
-}
-
-void fp_port_get_info(FpPort *port, RockerPortList *info)
-{
- info->value->name = g_strdup(port->name);
- info->value->enabled = port->enabled;
- info->value->link_up = fp_port_get_link_up(port);
- info->value->speed = port->speed;
- info->value->duplex = port->duplex;
- info->value->autoneg = port->autoneg;
-}
-
-void fp_port_get_macaddr(FpPort *port, MACAddr *macaddr)
-{
- memcpy(macaddr->a, port->conf.macaddr.a, sizeof(macaddr->a));
-}
-
-void fp_port_set_macaddr(FpPort *port, MACAddr *macaddr)
-{
-/* XXX TODO implement and test setting mac addr
- * XXX memcpy(port->conf.macaddr.a, macaddr.a, sizeof(port->conf.macaddr.a));
- */
-}
-
-uint8_t fp_port_get_learning(FpPort *port)
-{
- return port->learning;
-}
-
-void fp_port_set_learning(FpPort *port, uint8_t learning)
-{
- port->learning = learning;
-}
-
-int fp_port_get_settings(FpPort *port, uint32_t *speed,
- uint8_t *duplex, uint8_t *autoneg)
-{
- *speed = port->speed;
- *duplex = port->duplex;
- *autoneg = port->autoneg;
-
- return ROCKER_OK;
-}
-
-int fp_port_set_settings(FpPort *port, uint32_t speed,
- uint8_t duplex, uint8_t autoneg)
-{
- /* XXX validate inputs */
-
- port->speed = speed;
- port->duplex = duplex;
- port->autoneg = autoneg;
-
- return ROCKER_OK;
-}
-
-bool fp_port_from_pport(uint32_t pport, uint32_t *port)
-{
- if (pport < 1 || pport > ROCKER_FP_PORTS_MAX) {
- return false;
- }
- *port = pport - 1;
- return true;
-}
-
-int fp_port_eg(FpPort *port, const struct iovec *iov, int iovcnt)
-{
- NetClientState *nc = qemu_get_queue(port->nic);
-
- if (port->enabled) {
- qemu_sendv_packet(nc, iov, iovcnt);
- }
-
- return ROCKER_OK;
-}
-
-static ssize_t fp_port_receive_iov(NetClientState *nc, const struct iovec *iov,
- int iovcnt)
-{
- FpPort *port = qemu_get_nic_opaque(nc);
-
- /* If the port is disabled, we want to drop this pkt
- * now rather than queing it for later. We don't want
- * any stale pkts getting into the device when the port
- * transitions to enabled.
- */
-
- if (!port->enabled) {
- return -1;
- }
-
- return world_ingress(port->world, port->pport, iov, iovcnt);
-}
-
-static ssize_t fp_port_receive(NetClientState *nc, const uint8_t *buf,
- size_t size)
-{
- const struct iovec iov = {
- .iov_base = (uint8_t *)buf,
- .iov_len = size
- };
-
- return fp_port_receive_iov(nc, &iov, 1);
-}
-
-static void fp_port_cleanup(NetClientState *nc)
-{
-}
-
-static void fp_port_set_link_status(NetClientState *nc)
-{
- FpPort *port = qemu_get_nic_opaque(nc);
-
- rocker_event_link_changed(port->r, port->pport, !nc->link_down);
-}
-
-static NetClientInfo fp_port_info = {
- .type = NET_CLIENT_OPTIONS_KIND_NIC,
- .size = sizeof(NICState),
- .receive = fp_port_receive,
- .receive_iov = fp_port_receive_iov,
- .cleanup = fp_port_cleanup,
- .link_status_changed = fp_port_set_link_status,
-};
-
-World *fp_port_get_world(FpPort *port)
-{
- return port->world;
-}
-
-void fp_port_set_world(FpPort *port, World *world)
-{
- DPRINTF("port %d setting world \"%s\"\n", port->index, world_name(world));
- port->world = world;
-}
-
-bool fp_port_check_world(FpPort *port, World *world)
-{
- return port->world == world;
-}
-
-bool fp_port_enabled(FpPort *port)
-{
- return port->enabled;
-}
-
-static void fp_port_set_link(FpPort *port, bool up)
-{
- NetClientState *nc = qemu_get_queue(port->nic);
-
- if (up == nc->link_down) {
- nc->link_down = !up;
- nc->info->link_status_changed(nc);
- }
-}
-
-void fp_port_enable(FpPort *port)
-{
- fp_port_set_link(port, true);
- port->enabled = true;
- DPRINTF("port %d enabled\n", port->index);
-}
-
-void fp_port_disable(FpPort *port)
-{
- port->enabled = false;
- fp_port_set_link(port, false);
- DPRINTF("port %d disabled\n", port->index);
-}
-
-FpPort *fp_port_alloc(Rocker *r, char *sw_name,
- MACAddr *start_mac, unsigned int index,
- NICPeers *peers)
-{
- FpPort *port = g_new0(FpPort, 1);
-
- if (!port) {
- return NULL;
- }
-
- port->r = r;
- port->index = index;
- port->pport = index + 1;
-
- /* front-panel switch port names are 1-based */
-
- port->name = g_strdup_printf("%sp%d", sw_name, port->pport);
-
- memcpy(port->conf.macaddr.a, start_mac, sizeof(port->conf.macaddr.a));
- port->conf.macaddr.a[5] += index;
- port->conf.bootindex = -1;
- port->conf.peers = *peers;
-
- port->nic = qemu_new_nic(&fp_port_info, &port->conf,
- sw_name, NULL, port);
- qemu_format_nic_info_str(qemu_get_queue(port->nic),
- port->conf.macaddr.a);
-
- fp_port_reset(port);
-
- return port;
-}
-
-void fp_port_free(FpPort *port)
-{
- qemu_del_nic(port->nic);
- g_free(port->name);
- g_free(port);
-}
-
-void fp_port_reset(FpPort *port)
-{
- fp_port_disable(port);
- port->speed = 10000; /* 10Gbps */
- port->duplex = DUPLEX_FULL;
- port->autoneg = 0;
-}
diff --git a/qemu/hw/net/rocker/rocker_fp.h b/qemu/hw/net/rocker/rocker_fp.h
deleted file mode 100644
index 04592bbfd..000000000
--- a/qemu/hw/net/rocker/rocker_fp.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * QEMU rocker switch emulation - front-panel ports
- *
- * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#ifndef _ROCKER_FP_H_
-#define _ROCKER_FP_H_
-
-#include "net/net.h"
-#include "qemu/iov.h"
-
-#define ROCKER_FP_PORTS_MAX 62
-
-typedef struct fp_port FpPort;
-
-int fp_port_eg(FpPort *port, const struct iovec *iov, int iovcnt);
-
-char *fp_port_get_name(FpPort *port);
-bool fp_port_get_link_up(FpPort *port);
-void fp_port_get_info(FpPort *port, RockerPortList *info);
-void fp_port_get_macaddr(FpPort *port, MACAddr *macaddr);
-void fp_port_set_macaddr(FpPort *port, MACAddr *macaddr);
-uint8_t fp_port_get_learning(FpPort *port);
-void fp_port_set_learning(FpPort *port, uint8_t learning);
-int fp_port_get_settings(FpPort *port, uint32_t *speed,
- uint8_t *duplex, uint8_t *autoneg);
-int fp_port_set_settings(FpPort *port, uint32_t speed,
- uint8_t duplex, uint8_t autoneg);
-bool fp_port_from_pport(uint32_t pport, uint32_t *port);
-World *fp_port_get_world(FpPort *port);
-void fp_port_set_world(FpPort *port, World *world);
-bool fp_port_check_world(FpPort *port, World *world);
-bool fp_port_enabled(FpPort *port);
-void fp_port_enable(FpPort *port);
-void fp_port_disable(FpPort *port);
-
-FpPort *fp_port_alloc(Rocker *r, char *sw_name,
- MACAddr *start_mac, unsigned int index,
- NICPeers *peers);
-void fp_port_free(FpPort *port);
-void fp_port_reset(FpPort *port);
-
-#endif /* _ROCKER_FP_H_ */
diff --git a/qemu/hw/net/rocker/rocker_hw.h b/qemu/hw/net/rocker/rocker_hw.h
deleted file mode 100644
index 8c5083032..000000000
--- a/qemu/hw/net/rocker/rocker_hw.h
+++ /dev/null
@@ -1,493 +0,0 @@
-/*
- * Rocker switch hardware register and descriptor definitions.
- *
- * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com>
- * Copyright (c) 2014 Jiri Pirko <jiri@resnulli.us>
- *
- */
-
-#ifndef _ROCKER_HW_
-#define _ROCKER_HW_
-
-#define __le16 uint16_t
-#define __le32 uint32_t
-#define __le64 uint64_t
-
-/*
- * Return codes
- */
-
-enum {
- ROCKER_OK = 0,
- ROCKER_ENOENT = 2,
- ROCKER_ENXIO = 6,
- ROCKER_ENOMEM = 12,
- ROCKER_EEXIST = 17,
- ROCKER_EINVAL = 22,
- ROCKER_EMSGSIZE = 90,
- ROCKER_ENOTSUP = 95,
- ROCKER_ENOBUFS = 105,
-};
-
-/*
- * PCI configuration space
- */
-
-#define ROCKER_PCI_REVISION 0x1
-#define ROCKER_PCI_BAR0_IDX 0
-#define ROCKER_PCI_BAR0_SIZE 0x2000
-#define ROCKER_PCI_MSIX_BAR_IDX 1
-#define ROCKER_PCI_MSIX_BAR_SIZE 0x2000
-#define ROCKER_PCI_MSIX_TABLE_OFFSET 0x0000
-#define ROCKER_PCI_MSIX_PBA_OFFSET 0x1000
-
-/*
- * MSI-X vectors
- */
-
-enum {
- ROCKER_MSIX_VEC_CMD,
- ROCKER_MSIX_VEC_EVENT,
- ROCKER_MSIX_VEC_TEST,
- ROCKER_MSIX_VEC_RESERVED0,
- __ROCKER_MSIX_VEC_TX,
- __ROCKER_MSIX_VEC_RX,
-#define ROCKER_MSIX_VEC_TX(port) \
- (__ROCKER_MSIX_VEC_TX + ((port) * 2))
-#define ROCKER_MSIX_VEC_RX(port) \
- (__ROCKER_MSIX_VEC_RX + ((port) * 2))
-#define ROCKER_MSIX_VEC_COUNT(portcnt) \
- (ROCKER_MSIX_VEC_RX((portcnt) - 1) + 1)
-};
-
-/*
- * Rocker bogus registers
- */
-#define ROCKER_BOGUS_REG0 0x0000
-#define ROCKER_BOGUS_REG1 0x0004
-#define ROCKER_BOGUS_REG2 0x0008
-#define ROCKER_BOGUS_REG3 0x000c
-
-/*
- * Rocker test registers
- */
-#define ROCKER_TEST_REG 0x0010
-#define ROCKER_TEST_REG64 0x0018 /* 8-byte */
-#define ROCKER_TEST_IRQ 0x0020
-#define ROCKER_TEST_DMA_ADDR 0x0028 /* 8-byte */
-#define ROCKER_TEST_DMA_SIZE 0x0030
-#define ROCKER_TEST_DMA_CTRL 0x0034
-
-/*
- * Rocker test register ctrl
- */
-#define ROCKER_TEST_DMA_CTRL_CLEAR (1 << 0)
-#define ROCKER_TEST_DMA_CTRL_FILL (1 << 1)
-#define ROCKER_TEST_DMA_CTRL_INVERT (1 << 2)
-
-/*
- * Rocker DMA ring register offsets
- */
-#define ROCKER_DMA_DESC_BASE 0x1000
-#define ROCKER_DMA_DESC_SIZE 32
-#define ROCKER_DMA_DESC_MASK 0x1F
-#define ROCKER_DMA_DESC_TOTAL_SIZE \
- (ROCKER_DMA_DESC_SIZE * 64) /* 62 ports + event + cmd */
-#define ROCKER_DMA_DESC_ADDR_OFFSET 0x00 /* 8-byte */
-#define ROCKER_DMA_DESC_SIZE_OFFSET 0x08
-#define ROCKER_DMA_DESC_HEAD_OFFSET 0x0c
-#define ROCKER_DMA_DESC_TAIL_OFFSET 0x10
-#define ROCKER_DMA_DESC_CTRL_OFFSET 0x14
-#define ROCKER_DMA_DESC_CREDITS_OFFSET 0x18
-#define ROCKER_DMA_DESC_RSVD_OFFSET 0x1c
-
-/*
- * Rocker dma ctrl register bits
- */
-#define ROCKER_DMA_DESC_CTRL_RESET (1 << 0)
-
-/*
- * Rocker ring indices
- */
-#define ROCKER_RING_CMD 0
-#define ROCKER_RING_EVENT 1
-
-/*
- * Helper macro to do convert a dma ring register
- * to its index. Based on the fact that the register
- * group stride is 32 bytes.
- */
-#define ROCKER_RING_INDEX(reg) ((reg >> 5) & 0x7F)
-
-/*
- * Rocker DMA Descriptor
- */
-
-typedef struct rocker_desc {
- __le64 buf_addr;
- uint64_t cookie;
- __le16 buf_size;
- __le16 tlv_size;
- __le16 rsvd[5]; /* pad to 32 bytes */
- __le16 comp_err;
-} __attribute__((packed, aligned(8))) RockerDesc;
-
-/*
- * Rocker TLV type fields
- */
-
-typedef struct rocker_tlv {
- __le32 type;
- __le16 len;
- __le16 rsvd;
-} __attribute__((packed, aligned(8))) RockerTlv;
-
-/* cmd msg */
-enum {
- ROCKER_TLV_CMD_UNSPEC,
- ROCKER_TLV_CMD_TYPE, /* u16 */
- ROCKER_TLV_CMD_INFO, /* nest */
-
- __ROCKER_TLV_CMD_MAX,
- ROCKER_TLV_CMD_MAX = __ROCKER_TLV_CMD_MAX - 1,
-};
-
-enum {
- ROCKER_TLV_CMD_TYPE_UNSPEC,
- ROCKER_TLV_CMD_TYPE_GET_PORT_SETTINGS,
- ROCKER_TLV_CMD_TYPE_SET_PORT_SETTINGS,
- ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_ADD,
- ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_MOD,
- ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_DEL,
- ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_GET_STATS,
- ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_ADD,
- ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_MOD,
- ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_DEL,
- ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_GET_STATS,
-
- __ROCKER_TLV_CMD_TYPE_MAX,
- ROCKER_TLV_CMD_TYPE_MAX = __ROCKER_TLV_CMD_TYPE_MAX - 1,
-};
-
-/* cmd info nested for set/get port settings */
-enum {
- ROCKER_TLV_CMD_PORT_SETTINGS_UNSPEC,
- ROCKER_TLV_CMD_PORT_SETTINGS_PPORT, /* u32 */
- ROCKER_TLV_CMD_PORT_SETTINGS_SPEED, /* u32 */
- ROCKER_TLV_CMD_PORT_SETTINGS_DUPLEX, /* u8 */
- ROCKER_TLV_CMD_PORT_SETTINGS_AUTONEG, /* u8 */
- ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR, /* binary */
- ROCKER_TLV_CMD_PORT_SETTINGS_MODE, /* u8 */
- ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING, /* u8 */
- ROCKER_TLV_CMD_PORT_SETTINGS_PHYS_NAME, /* binary */
-
- __ROCKER_TLV_CMD_PORT_SETTINGS_MAX,
- ROCKER_TLV_CMD_PORT_SETTINGS_MAX = __ROCKER_TLV_CMD_PORT_SETTINGS_MAX - 1,
-};
-
-enum {
- ROCKER_PORT_MODE_OF_DPA,
-};
-
-/* event msg */
-enum {
- ROCKER_TLV_EVENT_UNSPEC,
- ROCKER_TLV_EVENT_TYPE, /* u16 */
- ROCKER_TLV_EVENT_INFO, /* nest */
-
- __ROCKER_TLV_EVENT_MAX,
- ROCKER_TLV_EVENT_MAX = __ROCKER_TLV_EVENT_MAX - 1,
-};
-
-enum {
- ROCKER_TLV_EVENT_TYPE_UNSPEC,
- ROCKER_TLV_EVENT_TYPE_LINK_CHANGED,
- ROCKER_TLV_EVENT_TYPE_MAC_VLAN_SEEN,
-
- __ROCKER_TLV_EVENT_TYPE_MAX,
- ROCKER_TLV_EVENT_TYPE_MAX = __ROCKER_TLV_EVENT_TYPE_MAX - 1,
-};
-
-/* event info nested for link changed */
-enum {
- ROCKER_TLV_EVENT_LINK_CHANGED_UNSPEC,
- ROCKER_TLV_EVENT_LINK_CHANGED_PPORT, /* u32 */
- ROCKER_TLV_EVENT_LINK_CHANGED_LINKUP, /* u8 */
-
- __ROCKER_TLV_EVENT_LINK_CHANGED_MAX,
- ROCKER_TLV_EVENT_LINK_CHANGED_MAX = __ROCKER_TLV_EVENT_LINK_CHANGED_MAX - 1,
-};
-
-/* event info nested for MAC/VLAN */
-enum {
- ROCKER_TLV_EVENT_MAC_VLAN_UNSPEC,
- ROCKER_TLV_EVENT_MAC_VLAN_PPORT, /* u32 */
- ROCKER_TLV_EVENT_MAC_VLAN_MAC, /* binary */
- ROCKER_TLV_EVENT_MAC_VLAN_VLAN_ID, /* __be16 */
-
- __ROCKER_TLV_EVENT_MAC_VLAN_MAX,
- ROCKER_TLV_EVENT_MAC_VLAN_MAX = __ROCKER_TLV_EVENT_MAC_VLAN_MAX - 1,
-};
-
-/* Rx msg */
-enum {
- ROCKER_TLV_RX_UNSPEC,
- ROCKER_TLV_RX_FLAGS, /* u16, see RX_FLAGS_ */
- ROCKER_TLV_RX_CSUM, /* u16 */
- ROCKER_TLV_RX_FRAG_ADDR, /* u64 */
- ROCKER_TLV_RX_FRAG_MAX_LEN, /* u16 */
- ROCKER_TLV_RX_FRAG_LEN, /* u16 */
-
- __ROCKER_TLV_RX_MAX,
- ROCKER_TLV_RX_MAX = __ROCKER_TLV_RX_MAX - 1,
-};
-
-#define ROCKER_RX_FLAGS_IPV4 (1 << 0)
-#define ROCKER_RX_FLAGS_IPV6 (1 << 1)
-#define ROCKER_RX_FLAGS_CSUM_CALC (1 << 2)
-#define ROCKER_RX_FLAGS_IPV4_CSUM_GOOD (1 << 3)
-#define ROCKER_RX_FLAGS_IP_FRAG (1 << 4)
-#define ROCKER_RX_FLAGS_TCP (1 << 5)
-#define ROCKER_RX_FLAGS_UDP (1 << 6)
-#define ROCKER_RX_FLAGS_TCP_UDP_CSUM_GOOD (1 << 7)
-#define ROCKER_RX_FLAGS_FWD_OFFLOAD (1 << 8)
-
-/* Tx msg */
-enum {
- ROCKER_TLV_TX_UNSPEC,
- ROCKER_TLV_TX_OFFLOAD, /* u8, see TX_OFFLOAD_ */
- ROCKER_TLV_TX_L3_CSUM_OFF, /* u16 */
- ROCKER_TLV_TX_TSO_MSS, /* u16 */
- ROCKER_TLV_TX_TSO_HDR_LEN, /* u16 */
- ROCKER_TLV_TX_FRAGS, /* array */
-
- __ROCKER_TLV_TX_MAX,
- ROCKER_TLV_TX_MAX = __ROCKER_TLV_TX_MAX - 1,
-};
-
-#define ROCKER_TX_OFFLOAD_NONE 0
-#define ROCKER_TX_OFFLOAD_IP_CSUM 1
-#define ROCKER_TX_OFFLOAD_TCP_UDP_CSUM 2
-#define ROCKER_TX_OFFLOAD_L3_CSUM 3
-#define ROCKER_TX_OFFLOAD_TSO 4
-
-#define ROCKER_TX_FRAGS_MAX 16
-
-enum {
- ROCKER_TLV_TX_FRAG_UNSPEC,
- ROCKER_TLV_TX_FRAG, /* nest */
-
- __ROCKER_TLV_TX_FRAG_MAX,
- ROCKER_TLV_TX_FRAG_MAX = __ROCKER_TLV_TX_FRAG_MAX - 1,
-};
-
-enum {
- ROCKER_TLV_TX_FRAG_ATTR_UNSPEC,
- ROCKER_TLV_TX_FRAG_ATTR_ADDR, /* u64 */
- ROCKER_TLV_TX_FRAG_ATTR_LEN, /* u16 */
-
- __ROCKER_TLV_TX_FRAG_ATTR_MAX,
- ROCKER_TLV_TX_FRAG_ATTR_MAX = __ROCKER_TLV_TX_FRAG_ATTR_MAX - 1,
-};
-
-/*
- * cmd info nested for OF-DPA msgs
- */
-
-enum {
- ROCKER_TLV_OF_DPA_UNSPEC,
- ROCKER_TLV_OF_DPA_TABLE_ID, /* u16 */
- ROCKER_TLV_OF_DPA_PRIORITY, /* u32 */
- ROCKER_TLV_OF_DPA_HARDTIME, /* u32 */
- ROCKER_TLV_OF_DPA_IDLETIME, /* u32 */
- ROCKER_TLV_OF_DPA_COOKIE, /* u64 */
- ROCKER_TLV_OF_DPA_IN_PPORT, /* u32 */
- ROCKER_TLV_OF_DPA_IN_PPORT_MASK, /* u32 */
- ROCKER_TLV_OF_DPA_OUT_PPORT, /* u32 */
- ROCKER_TLV_OF_DPA_GOTO_TABLE_ID, /* u16 */
- ROCKER_TLV_OF_DPA_GROUP_ID, /* u32 */
- ROCKER_TLV_OF_DPA_GROUP_ID_LOWER, /* u32 */
- ROCKER_TLV_OF_DPA_GROUP_COUNT, /* u16 */
- ROCKER_TLV_OF_DPA_GROUP_IDS, /* u32 array */
- ROCKER_TLV_OF_DPA_VLAN_ID, /* __be16 */
- ROCKER_TLV_OF_DPA_VLAN_ID_MASK, /* __be16 */
- ROCKER_TLV_OF_DPA_VLAN_PCP, /* __be16 */
- ROCKER_TLV_OF_DPA_VLAN_PCP_MASK, /* __be16 */
- ROCKER_TLV_OF_DPA_VLAN_PCP_ACTION, /* u8 */
- ROCKER_TLV_OF_DPA_NEW_VLAN_ID, /* __be16 */
- ROCKER_TLV_OF_DPA_NEW_VLAN_PCP, /* u8 */
- ROCKER_TLV_OF_DPA_TUNNEL_ID, /* u32 */
- ROCKER_TLV_OF_DPA_TUNNEL_LPORT, /* u32 */
- ROCKER_TLV_OF_DPA_ETHERTYPE, /* __be16 */
- ROCKER_TLV_OF_DPA_DST_MAC, /* binary */
- ROCKER_TLV_OF_DPA_DST_MAC_MASK, /* binary */
- ROCKER_TLV_OF_DPA_SRC_MAC, /* binary */
- ROCKER_TLV_OF_DPA_SRC_MAC_MASK, /* binary */
- ROCKER_TLV_OF_DPA_IP_PROTO, /* u8 */
- ROCKER_TLV_OF_DPA_IP_PROTO_MASK, /* u8 */
- ROCKER_TLV_OF_DPA_IP_DSCP, /* u8 */
- ROCKER_TLV_OF_DPA_IP_DSCP_MASK, /* u8 */
- ROCKER_TLV_OF_DPA_IP_DSCP_ACTION, /* u8 */
- ROCKER_TLV_OF_DPA_NEW_IP_DSCP, /* u8 */
- ROCKER_TLV_OF_DPA_IP_ECN, /* u8 */
- ROCKER_TLV_OF_DPA_IP_ECN_MASK, /* u8 */
- ROCKER_TLV_OF_DPA_DST_IP, /* __be32 */
- ROCKER_TLV_OF_DPA_DST_IP_MASK, /* __be32 */
- ROCKER_TLV_OF_DPA_SRC_IP, /* __be32 */
- ROCKER_TLV_OF_DPA_SRC_IP_MASK, /* __be32 */
- ROCKER_TLV_OF_DPA_DST_IPV6, /* binary */
- ROCKER_TLV_OF_DPA_DST_IPV6_MASK, /* binary */
- ROCKER_TLV_OF_DPA_SRC_IPV6, /* binary */
- ROCKER_TLV_OF_DPA_SRC_IPV6_MASK, /* binary */
- ROCKER_TLV_OF_DPA_SRC_ARP_IP, /* __be32 */
- ROCKER_TLV_OF_DPA_SRC_ARP_IP_MASK, /* __be32 */
- ROCKER_TLV_OF_DPA_L4_DST_PORT, /* __be16 */
- ROCKER_TLV_OF_DPA_L4_DST_PORT_MASK, /* __be16 */
- ROCKER_TLV_OF_DPA_L4_SRC_PORT, /* __be16 */
- ROCKER_TLV_OF_DPA_L4_SRC_PORT_MASK, /* __be16 */
- ROCKER_TLV_OF_DPA_ICMP_TYPE, /* u8 */
- ROCKER_TLV_OF_DPA_ICMP_TYPE_MASK, /* u8 */
- ROCKER_TLV_OF_DPA_ICMP_CODE, /* u8 */
- ROCKER_TLV_OF_DPA_ICMP_CODE_MASK, /* u8 */
- ROCKER_TLV_OF_DPA_IPV6_LABEL, /* __be32 */
- ROCKER_TLV_OF_DPA_IPV6_LABEL_MASK, /* __be32 */
- ROCKER_TLV_OF_DPA_QUEUE_ID_ACTION, /* u8 */
- ROCKER_TLV_OF_DPA_NEW_QUEUE_ID, /* u8 */
- ROCKER_TLV_OF_DPA_CLEAR_ACTIONS, /* u32 */
- ROCKER_TLV_OF_DPA_POP_VLAN, /* u8 */
- ROCKER_TLV_OF_DPA_TTL_CHECK, /* u8 */
- ROCKER_TLV_OF_DPA_COPY_CPU_ACTION, /* u8 */
-
- __ROCKER_TLV_OF_DPA_MAX,
- ROCKER_TLV_OF_DPA_MAX = __ROCKER_TLV_OF_DPA_MAX - 1,
-};
-
-/*
- * OF-DPA table IDs
- */
-
-enum rocker_of_dpa_table_id {
- ROCKER_OF_DPA_TABLE_ID_INGRESS_PORT = 0,
- ROCKER_OF_DPA_TABLE_ID_VLAN = 10,
- ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC = 20,
- ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING = 30,
- ROCKER_OF_DPA_TABLE_ID_MULTICAST_ROUTING = 40,
- ROCKER_OF_DPA_TABLE_ID_BRIDGING = 50,
- ROCKER_OF_DPA_TABLE_ID_ACL_POLICY = 60,
-};
-
-/*
- * OF-DPA flow stats
- */
-
-enum {
- ROCKER_TLV_OF_DPA_FLOW_STAT_UNSPEC,
- ROCKER_TLV_OF_DPA_FLOW_STAT_DURATION, /* u32 */
- ROCKER_TLV_OF_DPA_FLOW_STAT_RX_PKTS, /* u64 */
- ROCKER_TLV_OF_DPA_FLOW_STAT_TX_PKTS, /* u64 */
-
- __ROCKER_TLV_OF_DPA_FLOW_STAT_MAX,
- ROCKER_TLV_OF_DPA_FLOW_STAT_MAX = __ROCKER_TLV_OF_DPA_FLOW_STAT_MAX - 1,
-};
-
-/*
- * OF-DPA group types
- */
-
-enum rocker_of_dpa_group_type {
- ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE = 0,
- ROCKER_OF_DPA_GROUP_TYPE_L2_REWRITE,
- ROCKER_OF_DPA_GROUP_TYPE_L3_UCAST,
- ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST,
- ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD,
- ROCKER_OF_DPA_GROUP_TYPE_L3_INTERFACE,
- ROCKER_OF_DPA_GROUP_TYPE_L3_MCAST,
- ROCKER_OF_DPA_GROUP_TYPE_L3_ECMP,
- ROCKER_OF_DPA_GROUP_TYPE_L2_OVERLAY,
-};
-
-/*
- * OF-DPA group L2 overlay types
- */
-
-enum rocker_of_dpa_overlay_type {
- ROCKER_OF_DPA_OVERLAY_TYPE_FLOOD_UCAST = 0,
- ROCKER_OF_DPA_OVERLAY_TYPE_FLOOD_MCAST,
- ROCKER_OF_DPA_OVERLAY_TYPE_MCAST_UCAST,
- ROCKER_OF_DPA_OVERLAY_TYPE_MCAST_MCAST,
-};
-
-/*
- * OF-DPA group ID encoding
- */
-
-#define ROCKER_GROUP_TYPE_SHIFT 28
-#define ROCKER_GROUP_TYPE_MASK 0xf0000000
-#define ROCKER_GROUP_VLAN_ID_SHIFT 16
-#define ROCKER_GROUP_VLAN_ID_MASK 0x0fff0000
-#define ROCKER_GROUP_PORT_SHIFT 0
-#define ROCKER_GROUP_PORT_MASK 0x0000ffff
-#define ROCKER_GROUP_TUNNEL_ID_SHIFT 12
-#define ROCKER_GROUP_TUNNEL_ID_MASK 0x0ffff000
-#define ROCKER_GROUP_SUBTYPE_SHIFT 10
-#define ROCKER_GROUP_SUBTYPE_MASK 0x00000c00
-#define ROCKER_GROUP_INDEX_SHIFT 0
-#define ROCKER_GROUP_INDEX_MASK 0x0000ffff
-#define ROCKER_GROUP_INDEX_LONG_SHIFT 0
-#define ROCKER_GROUP_INDEX_LONG_MASK 0x0fffffff
-
-#define ROCKER_GROUP_TYPE_GET(group_id) \
- (((group_id) & ROCKER_GROUP_TYPE_MASK) >> ROCKER_GROUP_TYPE_SHIFT)
-#define ROCKER_GROUP_TYPE_SET(type) \
- (((type) << ROCKER_GROUP_TYPE_SHIFT) & ROCKER_GROUP_TYPE_MASK)
-#define ROCKER_GROUP_VLAN_GET(group_id) \
- (((group_id) & ROCKER_GROUP_VLAN_ID_MASK) >> ROCKER_GROUP_VLAN_ID_SHIFT)
-#define ROCKER_GROUP_VLAN_SET(vlan_id) \
- (((vlan_id) << ROCKER_GROUP_VLAN_ID_SHIFT) & ROCKER_GROUP_VLAN_ID_MASK)
-#define ROCKER_GROUP_PORT_GET(group_id) \
- (((group_id) & ROCKER_GROUP_PORT_MASK) >> ROCKER_GROUP_PORT_SHIFT)
-#define ROCKER_GROUP_PORT_SET(port) \
- (((port) << ROCKER_GROUP_PORT_SHIFT) & ROCKER_GROUP_PORT_MASK)
-#define ROCKER_GROUP_INDEX_GET(group_id) \
- (((group_id) & ROCKER_GROUP_INDEX_MASK) >> ROCKER_GROUP_INDEX_SHIFT)
-#define ROCKER_GROUP_INDEX_SET(index) \
- (((index) << ROCKER_GROUP_INDEX_SHIFT) & ROCKER_GROUP_INDEX_MASK)
-#define ROCKER_GROUP_INDEX_LONG_GET(group_id) \
- (((group_id) & ROCKER_GROUP_INDEX_LONG_MASK) >> \
- ROCKER_GROUP_INDEX_LONG_SHIFT)
-#define ROCKER_GROUP_INDEX_LONG_SET(index) \
- (((index) << ROCKER_GROUP_INDEX_LONG_SHIFT) & \
- ROCKER_GROUP_INDEX_LONG_MASK)
-
-#define ROCKER_GROUP_NONE 0
-#define ROCKER_GROUP_L2_INTERFACE(vlan_id, port) \
- (ROCKER_GROUP_TYPE_SET(ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE) |\
- ROCKER_GROUP_VLAN_SET(ntohs(vlan_id)) | ROCKER_GROUP_PORT_SET(port))
-#define ROCKER_GROUP_L2_REWRITE(index) \
- (ROCKER_GROUP_TYPE_SET(ROCKER_OF_DPA_GROUP_TYPE_L2_REWRITE) |\
- ROCKER_GROUP_INDEX_LONG_SET(index))
-#define ROCKER_GROUP_L2_MCAST(vlan_id, index) \
- (ROCKER_GROUP_TYPE_SET(ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST) |\
- ROCKER_GROUP_VLAN_SET(ntohs(vlan_id)) | ROCKER_GROUP_INDEX_SET(index))
-#define ROCKER_GROUP_L2_FLOOD(vlan_id, index) \
- (ROCKER_GROUP_TYPE_SET(ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD) |\
- ROCKER_GROUP_VLAN_SET(ntohs(vlan_id)) | ROCKER_GROUP_INDEX_SET(index))
-#define ROCKER_GROUP_L3_UNICAST(index) \
- (ROCKER_GROUP_TYPE_SET(ROCKER_OF_DPA_GROUP_TYPE_L3_UCAST) |\
- ROCKER_GROUP_INDEX_LONG_SET(index))
-
-/*
- * Rocker general purpose registers
- */
-#define ROCKER_CONTROL 0x0300
-#define ROCKER_PORT_PHYS_COUNT 0x0304
-#define ROCKER_PORT_PHYS_LINK_STATUS 0x0310 /* 8-byte */
-#define ROCKER_PORT_PHYS_ENABLE 0x0318 /* 8-byte */
-#define ROCKER_SWITCH_ID 0x0320 /* 8-byte */
-
-/*
- * Rocker control bits
- */
-#define ROCKER_CONTROL_RESET (1 << 0)
-
-#endif /* _ROCKER_HW_ */
diff --git a/qemu/hw/net/rocker/rocker_of_dpa.c b/qemu/hw/net/rocker/rocker_of_dpa.c
deleted file mode 100644
index 0a134ebca..000000000
--- a/qemu/hw/net/rocker/rocker_of_dpa.c
+++ /dev/null
@@ -1,2627 +0,0 @@
-/*
- * QEMU rocker switch emulation - OF-DPA flow processing support
- *
- * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include "qemu/osdep.h"
-#include "net/eth.h"
-#include "qemu/iov.h"
-#include "qemu/timer.h"
-#include "qmp-commands.h"
-
-#include "rocker.h"
-#include "rocker_hw.h"
-#include "rocker_fp.h"
-#include "rocker_tlv.h"
-#include "rocker_world.h"
-#include "rocker_desc.h"
-#include "rocker_of_dpa.h"
-
-static const MACAddr zero_mac = { .a = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
-static const MACAddr ff_mac = { .a = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
-
-typedef struct of_dpa {
- World *world;
- GHashTable *flow_tbl;
- GHashTable *group_tbl;
- unsigned int flow_tbl_max_size;
- unsigned int group_tbl_max_size;
-} OfDpa;
-
-/* flow_key stolen mostly from OVS
- *
- * Note: fields that compare with network packet header fields
- * are stored in network order (BE) to avoid per-packet field
- * byte-swaps.
- */
-
-typedef struct of_dpa_flow_key {
- uint32_t in_pport; /* ingress port */
- uint32_t tunnel_id; /* overlay tunnel id */
- uint32_t tbl_id; /* table id */
- struct {
- __be16 vlan_id; /* 0 if no VLAN */
- MACAddr src; /* ethernet source address */
- MACAddr dst; /* ethernet destination address */
- __be16 type; /* ethernet frame type */
- } eth;
- struct {
- uint8_t proto; /* IP protocol or ARP opcode */
- uint8_t tos; /* IP ToS */
- uint8_t ttl; /* IP TTL/hop limit */
- uint8_t frag; /* one of FRAG_TYPE_* */
- } ip;
- union {
- struct {
- struct {
- __be32 src; /* IP source address */
- __be32 dst; /* IP destination address */
- } addr;
- union {
- struct {
- __be16 src; /* TCP/UDP/SCTP source port */
- __be16 dst; /* TCP/UDP/SCTP destination port */
- __be16 flags; /* TCP flags */
- } tp;
- struct {
- MACAddr sha; /* ARP source hardware address */
- MACAddr tha; /* ARP target hardware address */
- } arp;
- };
- } ipv4;
- struct {
- struct {
- Ipv6Addr src; /* IPv6 source address */
- Ipv6Addr dst; /* IPv6 destination address */
- } addr;
- __be32 label; /* IPv6 flow label */
- struct {
- __be16 src; /* TCP/UDP/SCTP source port */
- __be16 dst; /* TCP/UDP/SCTP destination port */
- __be16 flags; /* TCP flags */
- } tp;
- struct {
- Ipv6Addr target; /* ND target address */
- MACAddr sll; /* ND source link layer address */
- MACAddr tll; /* ND target link layer address */
- } nd;
- } ipv6;
- };
- int width; /* how many uint64_t's in key? */
-} OfDpaFlowKey;
-
-/* Width of key which includes field 'f' in u64s, rounded up */
-#define FLOW_KEY_WIDTH(f) \
- ((offsetof(OfDpaFlowKey, f) + \
- sizeof(((OfDpaFlowKey *)0)->f) + \
- sizeof(uint64_t) - 1) / sizeof(uint64_t))
-
-typedef struct of_dpa_flow_action {
- uint32_t goto_tbl;
- struct {
- uint32_t group_id;
- uint32_t tun_log_lport;
- __be16 vlan_id;
- } write;
- struct {
- __be16 new_vlan_id;
- uint32_t out_pport;
- uint8_t copy_to_cpu;
- __be16 vlan_id;
- } apply;
-} OfDpaFlowAction;
-
-typedef struct of_dpa_flow {
- uint32_t lpm;
- uint32_t priority;
- uint32_t hardtime;
- uint32_t idletime;
- uint64_t cookie;
- OfDpaFlowKey key;
- OfDpaFlowKey mask;
- OfDpaFlowAction action;
- struct {
- uint64_t hits;
- int64_t install_time;
- int64_t refresh_time;
- uint64_t rx_pkts;
- uint64_t tx_pkts;
- } stats;
-} OfDpaFlow;
-
-typedef struct of_dpa_flow_pkt_fields {
- uint32_t tunnel_id;
- struct eth_header *ethhdr;
- __be16 *h_proto;
- struct vlan_header *vlanhdr;
- struct ip_header *ipv4hdr;
- struct ip6_header *ipv6hdr;
- Ipv6Addr *ipv6_src_addr;
- Ipv6Addr *ipv6_dst_addr;
-} OfDpaFlowPktFields;
-
-typedef struct of_dpa_flow_context {
- uint32_t in_pport;
- uint32_t tunnel_id;
- struct iovec *iov;
- int iovcnt;
- struct eth_header ethhdr_rewrite;
- struct vlan_header vlanhdr_rewrite;
- struct vlan_header vlanhdr;
- OfDpa *of_dpa;
- OfDpaFlowPktFields fields;
- OfDpaFlowAction action_set;
-} OfDpaFlowContext;
-
-typedef struct of_dpa_flow_match {
- OfDpaFlowKey value;
- OfDpaFlow *best;
-} OfDpaFlowMatch;
-
-typedef struct of_dpa_group {
- uint32_t id;
- union {
- struct {
- uint32_t out_pport;
- uint8_t pop_vlan;
- } l2_interface;
- struct {
- uint32_t group_id;
- MACAddr src_mac;
- MACAddr dst_mac;
- __be16 vlan_id;
- } l2_rewrite;
- struct {
- uint16_t group_count;
- uint32_t *group_ids;
- } l2_flood;
- struct {
- uint32_t group_id;
- MACAddr src_mac;
- MACAddr dst_mac;
- __be16 vlan_id;
- uint8_t ttl_check;
- } l3_unicast;
- };
-} OfDpaGroup;
-
-static int of_dpa_mask2prefix(__be32 mask)
-{
- int i;
- int count = 32;
-
- for (i = 0; i < 32; i++) {
- if (!(ntohl(mask) & ((2 << i) - 1))) {
- count--;
- }
- }
-
- return count;
-}
-
-#if defined(DEBUG_ROCKER)
-static void of_dpa_flow_key_dump(OfDpaFlowKey *key, OfDpaFlowKey *mask)
-{
- char buf[512], *b = buf, *mac;
-
- b += sprintf(b, " tbl %2d", key->tbl_id);
-
- if (key->in_pport || (mask && mask->in_pport)) {
- b += sprintf(b, " in_pport %2d", key->in_pport);
- if (mask && mask->in_pport != 0xffffffff) {
- b += sprintf(b, "/0x%08x", key->in_pport);
- }
- }
-
- if (key->tunnel_id || (mask && mask->tunnel_id)) {
- b += sprintf(b, " tun %8d", key->tunnel_id);
- if (mask && mask->tunnel_id != 0xffffffff) {
- b += sprintf(b, "/0x%08x", key->tunnel_id);
- }
- }
-
- if (key->eth.vlan_id || (mask && mask->eth.vlan_id)) {
- b += sprintf(b, " vlan %4d", ntohs(key->eth.vlan_id));
- if (mask && mask->eth.vlan_id != 0xffff) {
- b += sprintf(b, "/0x%04x", ntohs(key->eth.vlan_id));
- }
- }
-
- if (memcmp(key->eth.src.a, zero_mac.a, ETH_ALEN) ||
- (mask && memcmp(mask->eth.src.a, zero_mac.a, ETH_ALEN))) {
- mac = qemu_mac_strdup_printf(key->eth.src.a);
- b += sprintf(b, " src %s", mac);
- g_free(mac);
- if (mask && memcmp(mask->eth.src.a, ff_mac.a, ETH_ALEN)) {
- mac = qemu_mac_strdup_printf(mask->eth.src.a);
- b += sprintf(b, "/%s", mac);
- g_free(mac);
- }
- }
-
- if (memcmp(key->eth.dst.a, zero_mac.a, ETH_ALEN) ||
- (mask && memcmp(mask->eth.dst.a, zero_mac.a, ETH_ALEN))) {
- mac = qemu_mac_strdup_printf(key->eth.dst.a);
- b += sprintf(b, " dst %s", mac);
- g_free(mac);
- if (mask && memcmp(mask->eth.dst.a, ff_mac.a, ETH_ALEN)) {
- mac = qemu_mac_strdup_printf(mask->eth.dst.a);
- b += sprintf(b, "/%s", mac);
- g_free(mac);
- }
- }
-
- if (key->eth.type || (mask && mask->eth.type)) {
- b += sprintf(b, " type 0x%04x", ntohs(key->eth.type));
- if (mask && mask->eth.type != 0xffff) {
- b += sprintf(b, "/0x%04x", ntohs(mask->eth.type));
- }
- switch (ntohs(key->eth.type)) {
- case 0x0800:
- case 0x86dd:
- if (key->ip.proto || (mask && mask->ip.proto)) {
- b += sprintf(b, " ip proto %2d", key->ip.proto);
- if (mask && mask->ip.proto != 0xff) {
- b += sprintf(b, "/0x%02x", mask->ip.proto);
- }
- }
- if (key->ip.tos || (mask && mask->ip.tos)) {
- b += sprintf(b, " ip tos %2d", key->ip.tos);
- if (mask && mask->ip.tos != 0xff) {
- b += sprintf(b, "/0x%02x", mask->ip.tos);
- }
- }
- break;
- }
- switch (ntohs(key->eth.type)) {
- case 0x0800:
- if (key->ipv4.addr.dst || (mask && mask->ipv4.addr.dst)) {
- b += sprintf(b, " dst %s",
- inet_ntoa(*(struct in_addr *)&key->ipv4.addr.dst));
- if (mask) {
- b += sprintf(b, "/%d",
- of_dpa_mask2prefix(mask->ipv4.addr.dst));
- }
- }
- break;
- }
- }
-
- DPRINTF("%s\n", buf);
-}
-#else
-#define of_dpa_flow_key_dump(k, m)
-#endif
-
-static void _of_dpa_flow_match(void *key, void *value, void *user_data)
-{
- OfDpaFlow *flow = value;
- OfDpaFlowMatch *match = user_data;
- uint64_t *k = (uint64_t *)&flow->key;
- uint64_t *m = (uint64_t *)&flow->mask;
- uint64_t *v = (uint64_t *)&match->value;
- int i;
-
- if (flow->key.tbl_id == match->value.tbl_id) {
- of_dpa_flow_key_dump(&flow->key, &flow->mask);
- }
-
- if (flow->key.width > match->value.width) {
- return;
- }
-
- for (i = 0; i < flow->key.width; i++, k++, m++, v++) {
- if ((~*k & *m & *v) | (*k & *m & ~*v)) {
- return;
- }
- }
-
- DPRINTF("match\n");
-
- if (!match->best ||
- flow->priority > match->best->priority ||
- flow->lpm > match->best->lpm) {
- match->best = flow;
- }
-}
-
-static OfDpaFlow *of_dpa_flow_match(OfDpa *of_dpa, OfDpaFlowMatch *match)
-{
- DPRINTF("\nnew search\n");
- of_dpa_flow_key_dump(&match->value, NULL);
-
- g_hash_table_foreach(of_dpa->flow_tbl, _of_dpa_flow_match, match);
-
- return match->best;
-}
-
-static OfDpaFlow *of_dpa_flow_find(OfDpa *of_dpa, uint64_t cookie)
-{
- return g_hash_table_lookup(of_dpa->flow_tbl, &cookie);
-}
-
-static int of_dpa_flow_add(OfDpa *of_dpa, OfDpaFlow *flow)
-{
- g_hash_table_insert(of_dpa->flow_tbl, &flow->cookie, flow);
-
- return ROCKER_OK;
-}
-
-static void of_dpa_flow_del(OfDpa *of_dpa, OfDpaFlow *flow)
-{
- g_hash_table_remove(of_dpa->flow_tbl, &flow->cookie);
-}
-
-static OfDpaFlow *of_dpa_flow_alloc(uint64_t cookie)
-{
- OfDpaFlow *flow;
- int64_t now = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) / 1000;
-
- flow = g_new0(OfDpaFlow, 1);
- if (!flow) {
- return NULL;
- }
-
- flow->cookie = cookie;
- flow->mask.tbl_id = 0xffffffff;
-
- flow->stats.install_time = flow->stats.refresh_time = now;
-
- return flow;
-}
-
-static void of_dpa_flow_pkt_hdr_reset(OfDpaFlowContext *fc)
-{
- OfDpaFlowPktFields *fields = &fc->fields;
-
- fc->iov[0].iov_base = fields->ethhdr;
- fc->iov[0].iov_len = sizeof(struct eth_header);
- fc->iov[1].iov_base = fields->vlanhdr;
- fc->iov[1].iov_len = fields->vlanhdr ? sizeof(struct vlan_header) : 0;
-}
-
-static void of_dpa_flow_pkt_parse(OfDpaFlowContext *fc,
- const struct iovec *iov, int iovcnt)
-{
- OfDpaFlowPktFields *fields = &fc->fields;
- size_t sofar = 0;
- int i;
-
- sofar += sizeof(struct eth_header);
- if (iov->iov_len < sofar) {
- DPRINTF("flow_pkt_parse underrun on eth_header\n");
- return;
- }
-
- fields->ethhdr = iov->iov_base;
- fields->h_proto = &fields->ethhdr->h_proto;
-
- if (ntohs(*fields->h_proto) == ETH_P_VLAN) {
- sofar += sizeof(struct vlan_header);
- if (iov->iov_len < sofar) {
- DPRINTF("flow_pkt_parse underrun on vlan_header\n");
- return;
- }
- fields->vlanhdr = (struct vlan_header *)(fields->ethhdr + 1);
- fields->h_proto = &fields->vlanhdr->h_proto;
- }
-
- switch (ntohs(*fields->h_proto)) {
- case ETH_P_IP:
- sofar += sizeof(struct ip_header);
- if (iov->iov_len < sofar) {
- DPRINTF("flow_pkt_parse underrun on ip_header\n");
- return;
- }
- fields->ipv4hdr = (struct ip_header *)(fields->h_proto + 1);
- break;
- case ETH_P_IPV6:
- sofar += sizeof(struct ip6_header);
- if (iov->iov_len < sofar) {
- DPRINTF("flow_pkt_parse underrun on ip6_header\n");
- return;
- }
- fields->ipv6hdr = (struct ip6_header *)(fields->h_proto + 1);
- break;
- }
-
- /* To facilitate (potential) VLAN tag insertion, Make a
- * copy of the iov and insert two new vectors at the
- * beginning for eth hdr and vlan hdr. No data is copied,
- * just the vectors.
- */
-
- of_dpa_flow_pkt_hdr_reset(fc);
-
- fc->iov[2].iov_base = fields->h_proto + 1;
- fc->iov[2].iov_len = iov->iov_len - fc->iov[0].iov_len - fc->iov[1].iov_len;
-
- for (i = 1; i < iovcnt; i++) {
- fc->iov[i+2] = iov[i];
- }
-
- fc->iovcnt = iovcnt + 2;
-}
-
-static void of_dpa_flow_pkt_insert_vlan(OfDpaFlowContext *fc, __be16 vlan_id)
-{
- OfDpaFlowPktFields *fields = &fc->fields;
- uint16_t h_proto = fields->ethhdr->h_proto;
-
- if (fields->vlanhdr) {
- DPRINTF("flow_pkt_insert_vlan packet already has vlan\n");
- return;
- }
-
- fields->ethhdr->h_proto = htons(ETH_P_VLAN);
- fields->vlanhdr = &fc->vlanhdr;
- fields->vlanhdr->h_tci = vlan_id;
- fields->vlanhdr->h_proto = h_proto;
- fields->h_proto = &fields->vlanhdr->h_proto;
-
- fc->iov[1].iov_base = fields->vlanhdr;
- fc->iov[1].iov_len = sizeof(struct vlan_header);
-}
-
-static void of_dpa_flow_pkt_strip_vlan(OfDpaFlowContext *fc)
-{
- OfDpaFlowPktFields *fields = &fc->fields;
-
- if (!fields->vlanhdr) {
- return;
- }
-
- fc->iov[0].iov_len -= sizeof(fields->ethhdr->h_proto);
- fc->iov[1].iov_base = fields->h_proto;
- fc->iov[1].iov_len = sizeof(fields->ethhdr->h_proto);
-}
-
-static void of_dpa_flow_pkt_hdr_rewrite(OfDpaFlowContext *fc,
- uint8_t *src_mac, uint8_t *dst_mac,
- __be16 vlan_id)
-{
- OfDpaFlowPktFields *fields = &fc->fields;
-
- if (src_mac || dst_mac) {
- memcpy(&fc->ethhdr_rewrite, fields->ethhdr, sizeof(struct eth_header));
- if (src_mac && memcmp(src_mac, zero_mac.a, ETH_ALEN)) {
- memcpy(fc->ethhdr_rewrite.h_source, src_mac, ETH_ALEN);
- }
- if (dst_mac && memcmp(dst_mac, zero_mac.a, ETH_ALEN)) {
- memcpy(fc->ethhdr_rewrite.h_dest, dst_mac, ETH_ALEN);
- }
- fc->iov[0].iov_base = &fc->ethhdr_rewrite;
- }
-
- if (vlan_id && fields->vlanhdr) {
- fc->vlanhdr_rewrite = fc->vlanhdr;
- fc->vlanhdr_rewrite.h_tci = vlan_id;
- fc->iov[1].iov_base = &fc->vlanhdr_rewrite;
- }
-}
-
-static void of_dpa_flow_ig_tbl(OfDpaFlowContext *fc, uint32_t tbl_id);
-
-static void of_dpa_ig_port_build_match(OfDpaFlowContext *fc,
- OfDpaFlowMatch *match)
-{
- match->value.tbl_id = ROCKER_OF_DPA_TABLE_ID_INGRESS_PORT;
- match->value.in_pport = fc->in_pport;
- match->value.width = FLOW_KEY_WIDTH(tbl_id);
-}
-
-static void of_dpa_ig_port_miss(OfDpaFlowContext *fc)
-{
- uint32_t port;
-
- /* The default on miss is for packets from physical ports
- * to go to the VLAN Flow Table. There is no default rule
- * for packets from logical ports, which are dropped on miss.
- */
-
- if (fp_port_from_pport(fc->in_pport, &port)) {
- of_dpa_flow_ig_tbl(fc, ROCKER_OF_DPA_TABLE_ID_VLAN);
- }
-}
-
-static void of_dpa_vlan_build_match(OfDpaFlowContext *fc,
- OfDpaFlowMatch *match)
-{
- match->value.tbl_id = ROCKER_OF_DPA_TABLE_ID_VLAN;
- match->value.in_pport = fc->in_pport;
- if (fc->fields.vlanhdr) {
- match->value.eth.vlan_id = fc->fields.vlanhdr->h_tci;
- }
- match->value.width = FLOW_KEY_WIDTH(eth.vlan_id);
-}
-
-static void of_dpa_vlan_insert(OfDpaFlowContext *fc,
- OfDpaFlow *flow)
-{
- if (flow->action.apply.new_vlan_id) {
- of_dpa_flow_pkt_insert_vlan(fc, flow->action.apply.new_vlan_id);
- }
-}
-
-static void of_dpa_term_mac_build_match(OfDpaFlowContext *fc,
- OfDpaFlowMatch *match)
-{
- match->value.tbl_id = ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC;
- match->value.in_pport = fc->in_pport;
- match->value.eth.type = *fc->fields.h_proto;
- match->value.eth.vlan_id = fc->fields.vlanhdr->h_tci;
- memcpy(match->value.eth.dst.a, fc->fields.ethhdr->h_dest,
- sizeof(match->value.eth.dst.a));
- match->value.width = FLOW_KEY_WIDTH(eth.type);
-}
-
-static void of_dpa_term_mac_miss(OfDpaFlowContext *fc)
-{
- of_dpa_flow_ig_tbl(fc, ROCKER_OF_DPA_TABLE_ID_BRIDGING);
-}
-
-static void of_dpa_apply_actions(OfDpaFlowContext *fc,
- OfDpaFlow *flow)
-{
- fc->action_set.apply.copy_to_cpu = flow->action.apply.copy_to_cpu;
- fc->action_set.apply.vlan_id = flow->key.eth.vlan_id;
-}
-
-static void of_dpa_bridging_build_match(OfDpaFlowContext *fc,
- OfDpaFlowMatch *match)
-{
- match->value.tbl_id = ROCKER_OF_DPA_TABLE_ID_BRIDGING;
- if (fc->fields.vlanhdr) {
- match->value.eth.vlan_id = fc->fields.vlanhdr->h_tci;
- } else if (fc->tunnel_id) {
- match->value.tunnel_id = fc->tunnel_id;
- }
- memcpy(match->value.eth.dst.a, fc->fields.ethhdr->h_dest,
- sizeof(match->value.eth.dst.a));
- match->value.width = FLOW_KEY_WIDTH(eth.dst);
-}
-
-static void of_dpa_bridging_learn(OfDpaFlowContext *fc,
- OfDpaFlow *dst_flow)
-{
- OfDpaFlowMatch match = { { 0, }, };
- OfDpaFlow *flow;
- uint8_t *addr;
- uint16_t vlan_id;
- int64_t now = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) / 1000;
- int64_t refresh_delay = 1;
-
- /* Do a lookup in bridge table by src_mac/vlan */
-
- addr = fc->fields.ethhdr->h_source;
- vlan_id = fc->fields.vlanhdr->h_tci;
-
- match.value.tbl_id = ROCKER_OF_DPA_TABLE_ID_BRIDGING;
- match.value.eth.vlan_id = vlan_id;
- memcpy(match.value.eth.dst.a, addr, sizeof(match.value.eth.dst.a));
- match.value.width = FLOW_KEY_WIDTH(eth.dst);
-
- flow = of_dpa_flow_match(fc->of_dpa, &match);
- if (flow) {
- if (!memcmp(flow->mask.eth.dst.a, ff_mac.a,
- sizeof(flow->mask.eth.dst.a))) {
- /* src_mac/vlan already learned; if in_port and out_port
- * don't match, the end station has moved and the port
- * needs updating */
- /* XXX implement the in_port/out_port check */
- if (now - flow->stats.refresh_time < refresh_delay) {
- return;
- }
- flow->stats.refresh_time = now;
- }
- }
-
- /* Let driver know about mac/vlan. This may be a new mac/vlan
- * or a refresh of existing mac/vlan that's been hit after the
- * refresh_delay.
- */
-
- rocker_event_mac_vlan_seen(world_rocker(fc->of_dpa->world),
- fc->in_pport, addr, vlan_id);
-}
-
-static void of_dpa_bridging_miss(OfDpaFlowContext *fc)
-{
- of_dpa_bridging_learn(fc, NULL);
- of_dpa_flow_ig_tbl(fc, ROCKER_OF_DPA_TABLE_ID_ACL_POLICY);
-}
-
-static void of_dpa_bridging_action_write(OfDpaFlowContext *fc,
- OfDpaFlow *flow)
-{
- if (flow->action.write.group_id != ROCKER_GROUP_NONE) {
- fc->action_set.write.group_id = flow->action.write.group_id;
- }
- fc->action_set.write.tun_log_lport = flow->action.write.tun_log_lport;
-}
-
-static void of_dpa_unicast_routing_build_match(OfDpaFlowContext *fc,
- OfDpaFlowMatch *match)
-{
- match->value.tbl_id = ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING;
- match->value.eth.type = *fc->fields.h_proto;
- if (fc->fields.ipv4hdr) {
- match->value.ipv4.addr.dst = fc->fields.ipv4hdr->ip_dst;
- }
- if (fc->fields.ipv6_dst_addr) {
- memcpy(&match->value.ipv6.addr.dst, fc->fields.ipv6_dst_addr,
- sizeof(match->value.ipv6.addr.dst));
- }
- match->value.width = FLOW_KEY_WIDTH(ipv6.addr.dst);
-}
-
-static void of_dpa_unicast_routing_miss(OfDpaFlowContext *fc)
-{
- of_dpa_flow_ig_tbl(fc, ROCKER_OF_DPA_TABLE_ID_ACL_POLICY);
-}
-
-static void of_dpa_unicast_routing_action_write(OfDpaFlowContext *fc,
- OfDpaFlow *flow)
-{
- if (flow->action.write.group_id != ROCKER_GROUP_NONE) {
- fc->action_set.write.group_id = flow->action.write.group_id;
- }
-}
-
-static void
-of_dpa_multicast_routing_build_match(OfDpaFlowContext *fc,
- OfDpaFlowMatch *match)
-{
- match->value.tbl_id = ROCKER_OF_DPA_TABLE_ID_MULTICAST_ROUTING;
- match->value.eth.type = *fc->fields.h_proto;
- match->value.eth.vlan_id = fc->fields.vlanhdr->h_tci;
- if (fc->fields.ipv4hdr) {
- match->value.ipv4.addr.src = fc->fields.ipv4hdr->ip_src;
- match->value.ipv4.addr.dst = fc->fields.ipv4hdr->ip_dst;
- }
- if (fc->fields.ipv6_src_addr) {
- memcpy(&match->value.ipv6.addr.src, fc->fields.ipv6_src_addr,
- sizeof(match->value.ipv6.addr.src));
- }
- if (fc->fields.ipv6_dst_addr) {
- memcpy(&match->value.ipv6.addr.dst, fc->fields.ipv6_dst_addr,
- sizeof(match->value.ipv6.addr.dst));
- }
- match->value.width = FLOW_KEY_WIDTH(ipv6.addr.dst);
-}
-
-static void of_dpa_multicast_routing_miss(OfDpaFlowContext *fc)
-{
- of_dpa_flow_ig_tbl(fc, ROCKER_OF_DPA_TABLE_ID_ACL_POLICY);
-}
-
-static void
-of_dpa_multicast_routing_action_write(OfDpaFlowContext *fc,
- OfDpaFlow *flow)
-{
- if (flow->action.write.group_id != ROCKER_GROUP_NONE) {
- fc->action_set.write.group_id = flow->action.write.group_id;
- }
- fc->action_set.write.vlan_id = flow->action.write.vlan_id;
-}
-
-static void of_dpa_acl_build_match(OfDpaFlowContext *fc,
- OfDpaFlowMatch *match)
-{
- match->value.tbl_id = ROCKER_OF_DPA_TABLE_ID_ACL_POLICY;
- match->value.in_pport = fc->in_pport;
- memcpy(match->value.eth.src.a, fc->fields.ethhdr->h_source,
- sizeof(match->value.eth.src.a));
- memcpy(match->value.eth.dst.a, fc->fields.ethhdr->h_dest,
- sizeof(match->value.eth.dst.a));
- match->value.eth.type = *fc->fields.h_proto;
- match->value.eth.vlan_id = fc->fields.vlanhdr->h_tci;
- match->value.width = FLOW_KEY_WIDTH(eth.type);
- if (fc->fields.ipv4hdr) {
- match->value.ip.proto = fc->fields.ipv4hdr->ip_p;
- match->value.ip.tos = fc->fields.ipv4hdr->ip_tos;
- match->value.width = FLOW_KEY_WIDTH(ip.tos);
- } else if (fc->fields.ipv6hdr) {
- match->value.ip.proto =
- fc->fields.ipv6hdr->ip6_ctlun.ip6_un1.ip6_un1_nxt;
- match->value.ip.tos = 0; /* XXX what goes here? */
- match->value.width = FLOW_KEY_WIDTH(ip.tos);
- }
-}
-
-static void of_dpa_eg(OfDpaFlowContext *fc);
-static void of_dpa_acl_hit(OfDpaFlowContext *fc,
- OfDpaFlow *dst_flow)
-{
- of_dpa_eg(fc);
-}
-
-static void of_dpa_acl_action_write(OfDpaFlowContext *fc,
- OfDpaFlow *flow)
-{
- if (flow->action.write.group_id != ROCKER_GROUP_NONE) {
- fc->action_set.write.group_id = flow->action.write.group_id;
- }
-}
-
-static void of_dpa_drop(OfDpaFlowContext *fc)
-{
- /* drop packet */
-}
-
-static OfDpaGroup *of_dpa_group_find(OfDpa *of_dpa,
- uint32_t group_id)
-{
- return g_hash_table_lookup(of_dpa->group_tbl, &group_id);
-}
-
-static int of_dpa_group_add(OfDpa *of_dpa, OfDpaGroup *group)
-{
- g_hash_table_insert(of_dpa->group_tbl, &group->id, group);
-
- return 0;
-}
-
-#if 0
-static int of_dpa_group_mod(OfDpa *of_dpa, OfDpaGroup *group)
-{
- OfDpaGroup *old_group = of_dpa_group_find(of_dpa, group->id);
-
- if (!old_group) {
- return -ENOENT;
- }
-
- /* XXX */
-
- return 0;
-}
-#endif
-
-static int of_dpa_group_del(OfDpa *of_dpa, OfDpaGroup *group)
-{
- g_hash_table_remove(of_dpa->group_tbl, &group->id);
-
- return 0;
-}
-
-#if 0
-static int of_dpa_group_get_stats(OfDpa *of_dpa, uint32_t id)
-{
- OfDpaGroup *group = of_dpa_group_find(of_dpa, id);
-
- if (!group) {
- return -ENOENT;
- }
-
- /* XXX get/return stats */
-
- return 0;
-}
-#endif
-
-static OfDpaGroup *of_dpa_group_alloc(uint32_t id)
-{
- OfDpaGroup *group = g_new0(OfDpaGroup, 1);
-
- if (!group) {
- return NULL;
- }
-
- group->id = id;
-
- return group;
-}
-
-static void of_dpa_output_l2_interface(OfDpaFlowContext *fc,
- OfDpaGroup *group)
-{
- uint8_t copy_to_cpu = fc->action_set.apply.copy_to_cpu;
-
- if (group->l2_interface.pop_vlan) {
- of_dpa_flow_pkt_strip_vlan(fc);
- }
-
- /* Note: By default, and as per the OpenFlow 1.3.1
- * specification, a packet cannot be forwarded back
- * to the IN_PORT from which it came in. An action
- * bucket that specifies the particular packet's
- * egress port is not evaluated.
- */
-
- if (group->l2_interface.out_pport == 0) {
- rx_produce(fc->of_dpa->world, fc->in_pport, fc->iov, fc->iovcnt,
- copy_to_cpu);
- } else if (group->l2_interface.out_pport != fc->in_pport) {
- rocker_port_eg(world_rocker(fc->of_dpa->world),
- group->l2_interface.out_pport,
- fc->iov, fc->iovcnt);
- }
-}
-
-static void of_dpa_output_l2_rewrite(OfDpaFlowContext *fc,
- OfDpaGroup *group)
-{
- OfDpaGroup *l2_group =
- of_dpa_group_find(fc->of_dpa, group->l2_rewrite.group_id);
-
- if (!l2_group) {
- return;
- }
-
- of_dpa_flow_pkt_hdr_rewrite(fc, group->l2_rewrite.src_mac.a,
- group->l2_rewrite.dst_mac.a,
- group->l2_rewrite.vlan_id);
- of_dpa_output_l2_interface(fc, l2_group);
-}
-
-static void of_dpa_output_l2_flood(OfDpaFlowContext *fc,
- OfDpaGroup *group)
-{
- OfDpaGroup *l2_group;
- int i;
-
- for (i = 0; i < group->l2_flood.group_count; i++) {
- of_dpa_flow_pkt_hdr_reset(fc);
- l2_group = of_dpa_group_find(fc->of_dpa, group->l2_flood.group_ids[i]);
- if (!l2_group) {
- continue;
- }
- switch (ROCKER_GROUP_TYPE_GET(l2_group->id)) {
- case ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE:
- of_dpa_output_l2_interface(fc, l2_group);
- break;
- case ROCKER_OF_DPA_GROUP_TYPE_L2_REWRITE:
- of_dpa_output_l2_rewrite(fc, l2_group);
- break;
- }
- }
-}
-
-static void of_dpa_output_l3_unicast(OfDpaFlowContext *fc, OfDpaGroup *group)
-{
- OfDpaGroup *l2_group =
- of_dpa_group_find(fc->of_dpa, group->l3_unicast.group_id);
-
- if (!l2_group) {
- return;
- }
-
- of_dpa_flow_pkt_hdr_rewrite(fc, group->l3_unicast.src_mac.a,
- group->l3_unicast.dst_mac.a,
- group->l3_unicast.vlan_id);
- /* XXX need ttl_check */
- of_dpa_output_l2_interface(fc, l2_group);
-}
-
-static void of_dpa_eg(OfDpaFlowContext *fc)
-{
- OfDpaFlowAction *set = &fc->action_set;
- OfDpaGroup *group;
- uint32_t group_id;
-
- /* send a copy of pkt to CPU (controller)? */
-
- if (set->apply.copy_to_cpu) {
- group_id = ROCKER_GROUP_L2_INTERFACE(set->apply.vlan_id, 0);
- group = of_dpa_group_find(fc->of_dpa, group_id);
- if (group) {
- of_dpa_output_l2_interface(fc, group);
- of_dpa_flow_pkt_hdr_reset(fc);
- }
- }
-
- /* process group write actions */
-
- if (!set->write.group_id) {
- return;
- }
-
- group = of_dpa_group_find(fc->of_dpa, set->write.group_id);
- if (!group) {
- return;
- }
-
- switch (ROCKER_GROUP_TYPE_GET(group->id)) {
- case ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE:
- of_dpa_output_l2_interface(fc, group);
- break;
- case ROCKER_OF_DPA_GROUP_TYPE_L2_REWRITE:
- of_dpa_output_l2_rewrite(fc, group);
- break;
- case ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD:
- case ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST:
- of_dpa_output_l2_flood(fc, group);
- break;
- case ROCKER_OF_DPA_GROUP_TYPE_L3_UCAST:
- of_dpa_output_l3_unicast(fc, group);
- break;
- }
-}
-
-typedef struct of_dpa_flow_tbl_ops {
- void (*build_match)(OfDpaFlowContext *fc, OfDpaFlowMatch *match);
- void (*hit)(OfDpaFlowContext *fc, OfDpaFlow *flow);
- void (*miss)(OfDpaFlowContext *fc);
- void (*hit_no_goto)(OfDpaFlowContext *fc);
- void (*action_apply)(OfDpaFlowContext *fc, OfDpaFlow *flow);
- void (*action_write)(OfDpaFlowContext *fc, OfDpaFlow *flow);
-} OfDpaFlowTblOps;
-
-static OfDpaFlowTblOps of_dpa_tbl_ops[] = {
- [ROCKER_OF_DPA_TABLE_ID_INGRESS_PORT] = {
- .build_match = of_dpa_ig_port_build_match,
- .miss = of_dpa_ig_port_miss,
- .hit_no_goto = of_dpa_drop,
- },
- [ROCKER_OF_DPA_TABLE_ID_VLAN] = {
- .build_match = of_dpa_vlan_build_match,
- .hit_no_goto = of_dpa_drop,
- .action_apply = of_dpa_vlan_insert,
- },
- [ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC] = {
- .build_match = of_dpa_term_mac_build_match,
- .miss = of_dpa_term_mac_miss,
- .hit_no_goto = of_dpa_drop,
- .action_apply = of_dpa_apply_actions,
- },
- [ROCKER_OF_DPA_TABLE_ID_BRIDGING] = {
- .build_match = of_dpa_bridging_build_match,
- .hit = of_dpa_bridging_learn,
- .miss = of_dpa_bridging_miss,
- .hit_no_goto = of_dpa_drop,
- .action_apply = of_dpa_apply_actions,
- .action_write = of_dpa_bridging_action_write,
- },
- [ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING] = {
- .build_match = of_dpa_unicast_routing_build_match,
- .miss = of_dpa_unicast_routing_miss,
- .hit_no_goto = of_dpa_drop,
- .action_write = of_dpa_unicast_routing_action_write,
- },
- [ROCKER_OF_DPA_TABLE_ID_MULTICAST_ROUTING] = {
- .build_match = of_dpa_multicast_routing_build_match,
- .miss = of_dpa_multicast_routing_miss,
- .hit_no_goto = of_dpa_drop,
- .action_write = of_dpa_multicast_routing_action_write,
- },
- [ROCKER_OF_DPA_TABLE_ID_ACL_POLICY] = {
- .build_match = of_dpa_acl_build_match,
- .hit = of_dpa_acl_hit,
- .miss = of_dpa_eg,
- .action_apply = of_dpa_apply_actions,
- .action_write = of_dpa_acl_action_write,
- },
-};
-
-static void of_dpa_flow_ig_tbl(OfDpaFlowContext *fc, uint32_t tbl_id)
-{
- OfDpaFlowTblOps *ops = &of_dpa_tbl_ops[tbl_id];
- OfDpaFlowMatch match = { { 0, }, };
- OfDpaFlow *flow;
-
- if (ops->build_match) {
- ops->build_match(fc, &match);
- } else {
- return;
- }
-
- flow = of_dpa_flow_match(fc->of_dpa, &match);
- if (!flow) {
- if (ops->miss) {
- ops->miss(fc);
- }
- return;
- }
-
- flow->stats.hits++;
-
- if (ops->action_apply) {
- ops->action_apply(fc, flow);
- }
-
- if (ops->action_write) {
- ops->action_write(fc, flow);
- }
-
- if (ops->hit) {
- ops->hit(fc, flow);
- }
-
- if (flow->action.goto_tbl) {
- of_dpa_flow_ig_tbl(fc, flow->action.goto_tbl);
- } else if (ops->hit_no_goto) {
- ops->hit_no_goto(fc);
- }
-
- /* drop packet */
-}
-
-static ssize_t of_dpa_ig(World *world, uint32_t pport,
- const struct iovec *iov, int iovcnt)
-{
- struct iovec iov_copy[iovcnt + 2];
- OfDpaFlowContext fc = {
- .of_dpa = world_private(world),
- .in_pport = pport,
- .iov = iov_copy,
- .iovcnt = iovcnt + 2,
- };
-
- of_dpa_flow_pkt_parse(&fc, iov, iovcnt);
- of_dpa_flow_ig_tbl(&fc, ROCKER_OF_DPA_TABLE_ID_INGRESS_PORT);
-
- return iov_size(iov, iovcnt);
-}
-
-#define ROCKER_TUNNEL_LPORT 0x00010000
-
-static int of_dpa_cmd_add_ig_port(OfDpaFlow *flow, RockerTlv **flow_tlvs)
-{
- OfDpaFlowKey *key = &flow->key;
- OfDpaFlowKey *mask = &flow->mask;
- OfDpaFlowAction *action = &flow->action;
- bool overlay_tunnel;
-
- if (!flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT] ||
- !flow_tlvs[ROCKER_TLV_OF_DPA_GOTO_TABLE_ID]) {
- return -ROCKER_EINVAL;
- }
-
- key->tbl_id = ROCKER_OF_DPA_TABLE_ID_INGRESS_PORT;
- key->width = FLOW_KEY_WIDTH(tbl_id);
-
- key->in_pport = rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT]);
- if (flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT_MASK]) {
- mask->in_pport =
- rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT_MASK]);
- }
-
- overlay_tunnel = !!(key->in_pport & ROCKER_TUNNEL_LPORT);
-
- action->goto_tbl =
- rocker_tlv_get_le16(flow_tlvs[ROCKER_TLV_OF_DPA_GOTO_TABLE_ID]);
-
- if (!overlay_tunnel && action->goto_tbl != ROCKER_OF_DPA_TABLE_ID_VLAN) {
- return -ROCKER_EINVAL;
- }
-
- if (overlay_tunnel && action->goto_tbl != ROCKER_OF_DPA_TABLE_ID_BRIDGING) {
- return -ROCKER_EINVAL;
- }
-
- return ROCKER_OK;
-}
-
-static int of_dpa_cmd_add_vlan(OfDpaFlow *flow, RockerTlv **flow_tlvs)
-{
- OfDpaFlowKey *key = &flow->key;
- OfDpaFlowKey *mask = &flow->mask;
- OfDpaFlowAction *action = &flow->action;
- uint32_t port;
- bool untagged;
-
- if (!flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT] ||
- !flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID]) {
- DPRINTF("Must give in_pport and vlan_id to install VLAN tbl entry\n");
- return -ROCKER_EINVAL;
- }
-
- key->tbl_id = ROCKER_OF_DPA_TABLE_ID_VLAN;
- key->width = FLOW_KEY_WIDTH(eth.vlan_id);
-
- key->in_pport = rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT]);
- if (!fp_port_from_pport(key->in_pport, &port)) {
- DPRINTF("in_pport (%d) not a front-panel port\n", key->in_pport);
- return -ROCKER_EINVAL;
- }
- mask->in_pport = 0xffffffff;
-
- key->eth.vlan_id = rocker_tlv_get_u16(flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID]);
-
- if (flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID_MASK]) {
- mask->eth.vlan_id =
- rocker_tlv_get_u16(flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID_MASK]);
- }
-
- if (key->eth.vlan_id) {
- untagged = false; /* filtering */
- } else {
- untagged = true;
- }
-
- if (flow_tlvs[ROCKER_TLV_OF_DPA_GOTO_TABLE_ID]) {
- action->goto_tbl =
- rocker_tlv_get_le16(flow_tlvs[ROCKER_TLV_OF_DPA_GOTO_TABLE_ID]);
- if (action->goto_tbl != ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC) {
- DPRINTF("Goto tbl (%d) must be TERM_MAC\n", action->goto_tbl);
- return -ROCKER_EINVAL;
- }
- }
-
- if (untagged) {
- if (!flow_tlvs[ROCKER_TLV_OF_DPA_NEW_VLAN_ID]) {
- DPRINTF("Must specify new vlan_id if untagged\n");
- return -ROCKER_EINVAL;
- }
- action->apply.new_vlan_id =
- rocker_tlv_get_u16(flow_tlvs[ROCKER_TLV_OF_DPA_NEW_VLAN_ID]);
- if (1 > ntohs(action->apply.new_vlan_id) ||
- ntohs(action->apply.new_vlan_id) > 4095) {
- DPRINTF("New vlan_id (%d) must be between 1 and 4095\n",
- ntohs(action->apply.new_vlan_id));
- return -ROCKER_EINVAL;
- }
- }
-
- return ROCKER_OK;
-}
-
-static int of_dpa_cmd_add_term_mac(OfDpaFlow *flow, RockerTlv **flow_tlvs)
-{
- OfDpaFlowKey *key = &flow->key;
- OfDpaFlowKey *mask = &flow->mask;
- OfDpaFlowAction *action = &flow->action;
- const MACAddr ipv4_mcast = { .a = { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 } };
- const MACAddr ipv4_mask = { .a = { 0xff, 0xff, 0xff, 0x80, 0x00, 0x00 } };
- const MACAddr ipv6_mcast = { .a = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x00 } };
- const MACAddr ipv6_mask = { .a = { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } };
- uint32_t port;
- bool unicast = false;
- bool multicast = false;
-
- if (!flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT] ||
- !flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT_MASK] ||
- !flow_tlvs[ROCKER_TLV_OF_DPA_ETHERTYPE] ||
- !flow_tlvs[ROCKER_TLV_OF_DPA_DST_MAC] ||
- !flow_tlvs[ROCKER_TLV_OF_DPA_DST_MAC_MASK] ||
- !flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID] ||
- !flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID_MASK]) {
- return -ROCKER_EINVAL;
- }
-
- key->tbl_id = ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC;
- key->width = FLOW_KEY_WIDTH(eth.type);
-
- key->in_pport = rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT]);
- if (!fp_port_from_pport(key->in_pport, &port)) {
- return -ROCKER_EINVAL;
- }
- mask->in_pport =
- rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT_MASK]);
-
- key->eth.type = rocker_tlv_get_u16(flow_tlvs[ROCKER_TLV_OF_DPA_ETHERTYPE]);
- if (key->eth.type != htons(0x0800) && key->eth.type != htons(0x86dd)) {
- return -ROCKER_EINVAL;
- }
- mask->eth.type = htons(0xffff);
-
- memcpy(key->eth.dst.a,
- rocker_tlv_data(flow_tlvs[ROCKER_TLV_OF_DPA_DST_MAC]),
- sizeof(key->eth.dst.a));
- memcpy(mask->eth.dst.a,
- rocker_tlv_data(flow_tlvs[ROCKER_TLV_OF_DPA_DST_MAC_MASK]),
- sizeof(mask->eth.dst.a));
-
- if ((key->eth.dst.a[0] & 0x01) == 0x00) {
- unicast = true;
- }
-
- /* only two wildcard rules are acceptable for IPv4 and IPv6 multicast */
- if (memcmp(key->eth.dst.a, ipv4_mcast.a, sizeof(key->eth.dst.a)) == 0 &&
- memcmp(mask->eth.dst.a, ipv4_mask.a, sizeof(mask->eth.dst.a)) == 0) {
- multicast = true;
- }
- if (memcmp(key->eth.dst.a, ipv6_mcast.a, sizeof(key->eth.dst.a)) == 0 &&
- memcmp(mask->eth.dst.a, ipv6_mask.a, sizeof(mask->eth.dst.a)) == 0) {
- multicast = true;
- }
-
- if (!unicast && !multicast) {
- return -ROCKER_EINVAL;
- }
-
- key->eth.vlan_id = rocker_tlv_get_u16(flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID]);
- mask->eth.vlan_id =
- rocker_tlv_get_u16(flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID_MASK]);
-
- if (flow_tlvs[ROCKER_TLV_OF_DPA_GOTO_TABLE_ID]) {
- action->goto_tbl =
- rocker_tlv_get_le16(flow_tlvs[ROCKER_TLV_OF_DPA_GOTO_TABLE_ID]);
-
- if (action->goto_tbl != ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING &&
- action->goto_tbl != ROCKER_OF_DPA_TABLE_ID_MULTICAST_ROUTING) {
- return -ROCKER_EINVAL;
- }
-
- if (unicast &&
- action->goto_tbl != ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING) {
- return -ROCKER_EINVAL;
- }
-
- if (multicast &&
- action->goto_tbl != ROCKER_OF_DPA_TABLE_ID_MULTICAST_ROUTING) {
- return -ROCKER_EINVAL;
- }
- }
-
- if (flow_tlvs[ROCKER_TLV_OF_DPA_COPY_CPU_ACTION]) {
- action->apply.copy_to_cpu =
- rocker_tlv_get_u8(flow_tlvs[ROCKER_TLV_OF_DPA_COPY_CPU_ACTION]);
- }
-
- return ROCKER_OK;
-}
-
-static int of_dpa_cmd_add_bridging(OfDpaFlow *flow, RockerTlv **flow_tlvs)
-{
- OfDpaFlowKey *key = &flow->key;
- OfDpaFlowKey *mask = &flow->mask;
- OfDpaFlowAction *action = &flow->action;
- bool unicast = false;
- bool dst_mac = false;
- bool dst_mac_mask = false;
- enum {
- BRIDGING_MODE_UNKNOWN,
- BRIDGING_MODE_VLAN_UCAST,
- BRIDGING_MODE_VLAN_MCAST,
- BRIDGING_MODE_VLAN_DFLT,
- BRIDGING_MODE_TUNNEL_UCAST,
- BRIDGING_MODE_TUNNEL_MCAST,
- BRIDGING_MODE_TUNNEL_DFLT,
- } mode = BRIDGING_MODE_UNKNOWN;
-
- key->tbl_id = ROCKER_OF_DPA_TABLE_ID_BRIDGING;
-
- if (flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID]) {
- key->eth.vlan_id =
- rocker_tlv_get_u16(flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID]);
- mask->eth.vlan_id = 0xffff;
- key->width = FLOW_KEY_WIDTH(eth.vlan_id);
- }
-
- if (flow_tlvs[ROCKER_TLV_OF_DPA_TUNNEL_ID]) {
- key->tunnel_id =
- rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_TUNNEL_ID]);
- mask->tunnel_id = 0xffffffff;
- key->width = FLOW_KEY_WIDTH(tunnel_id);
- }
-
- /* can't do VLAN bridging and tunnel bridging at same time */
- if (key->eth.vlan_id && key->tunnel_id) {
- DPRINTF("can't do VLAN bridging and tunnel bridging at same time\n");
- return -ROCKER_EINVAL;
- }
-
- if (flow_tlvs[ROCKER_TLV_OF_DPA_DST_MAC]) {
- memcpy(key->eth.dst.a,
- rocker_tlv_data(flow_tlvs[ROCKER_TLV_OF_DPA_DST_MAC]),
- sizeof(key->eth.dst.a));
- key->width = FLOW_KEY_WIDTH(eth.dst);
- dst_mac = true;
- unicast = (key->eth.dst.a[0] & 0x01) == 0x00;
- }
-
- if (flow_tlvs[ROCKER_TLV_OF_DPA_DST_MAC_MASK]) {
- memcpy(mask->eth.dst.a,
- rocker_tlv_data(flow_tlvs[ROCKER_TLV_OF_DPA_DST_MAC_MASK]),
- sizeof(mask->eth.dst.a));
- key->width = FLOW_KEY_WIDTH(eth.dst);
- dst_mac_mask = true;
- } else if (flow_tlvs[ROCKER_TLV_OF_DPA_DST_MAC]) {
- memcpy(mask->eth.dst.a, ff_mac.a, sizeof(mask->eth.dst.a));
- }
-
- if (key->eth.vlan_id) {
- if (dst_mac && !dst_mac_mask) {
- mode = unicast ? BRIDGING_MODE_VLAN_UCAST :
- BRIDGING_MODE_VLAN_MCAST;
- } else if ((dst_mac && dst_mac_mask) || !dst_mac) {
- mode = BRIDGING_MODE_VLAN_DFLT;
- }
- } else if (key->tunnel_id) {
- if (dst_mac && !dst_mac_mask) {
- mode = unicast ? BRIDGING_MODE_TUNNEL_UCAST :
- BRIDGING_MODE_TUNNEL_MCAST;
- } else if ((dst_mac && dst_mac_mask) || !dst_mac) {
- mode = BRIDGING_MODE_TUNNEL_DFLT;
- }
- }
-
- if (mode == BRIDGING_MODE_UNKNOWN) {
- DPRINTF("Unknown bridging mode\n");
- return -ROCKER_EINVAL;
- }
-
- if (flow_tlvs[ROCKER_TLV_OF_DPA_GOTO_TABLE_ID]) {
- action->goto_tbl =
- rocker_tlv_get_le16(flow_tlvs[ROCKER_TLV_OF_DPA_GOTO_TABLE_ID]);
- if (action->goto_tbl != ROCKER_OF_DPA_TABLE_ID_ACL_POLICY) {
- DPRINTF("Briding goto tbl must be ACL policy\n");
- return -ROCKER_EINVAL;
- }
- }
-
- if (flow_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID]) {
- action->write.group_id =
- rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID]);
- switch (mode) {
- case BRIDGING_MODE_VLAN_UCAST:
- if (ROCKER_GROUP_TYPE_GET(action->write.group_id) !=
- ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE) {
- DPRINTF("Bridging mode vlan ucast needs L2 "
- "interface group (0x%08x)\n",
- action->write.group_id);
- return -ROCKER_EINVAL;
- }
- break;
- case BRIDGING_MODE_VLAN_MCAST:
- if (ROCKER_GROUP_TYPE_GET(action->write.group_id) !=
- ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST) {
- DPRINTF("Bridging mode vlan mcast needs L2 "
- "mcast group (0x%08x)\n",
- action->write.group_id);
- return -ROCKER_EINVAL;
- }
- break;
- case BRIDGING_MODE_VLAN_DFLT:
- if (ROCKER_GROUP_TYPE_GET(action->write.group_id) !=
- ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD) {
- DPRINTF("Bridging mode vlan dflt needs L2 "
- "flood group (0x%08x)\n",
- action->write.group_id);
- return -ROCKER_EINVAL;
- }
- break;
- case BRIDGING_MODE_TUNNEL_MCAST:
- if (ROCKER_GROUP_TYPE_GET(action->write.group_id) !=
- ROCKER_OF_DPA_GROUP_TYPE_L2_OVERLAY) {
- DPRINTF("Bridging mode tunnel mcast needs L2 "
- "overlay group (0x%08x)\n",
- action->write.group_id);
- return -ROCKER_EINVAL;
- }
- break;
- case BRIDGING_MODE_TUNNEL_DFLT:
- if (ROCKER_GROUP_TYPE_GET(action->write.group_id) !=
- ROCKER_OF_DPA_GROUP_TYPE_L2_OVERLAY) {
- DPRINTF("Bridging mode tunnel dflt needs L2 "
- "overlay group (0x%08x)\n",
- action->write.group_id);
- return -ROCKER_EINVAL;
- }
- break;
- default:
- return -ROCKER_EINVAL;
- }
- }
-
- if (flow_tlvs[ROCKER_TLV_OF_DPA_TUNNEL_LPORT]) {
- action->write.tun_log_lport =
- rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_TUNNEL_LPORT]);
- if (mode != BRIDGING_MODE_TUNNEL_UCAST) {
- DPRINTF("Have tunnel logical port but not "
- "in bridging tunnel mode\n");
- return -ROCKER_EINVAL;
- }
- }
-
- if (flow_tlvs[ROCKER_TLV_OF_DPA_COPY_CPU_ACTION]) {
- action->apply.copy_to_cpu =
- rocker_tlv_get_u8(flow_tlvs[ROCKER_TLV_OF_DPA_COPY_CPU_ACTION]);
- }
-
- return ROCKER_OK;
-}
-
-static int of_dpa_cmd_add_unicast_routing(OfDpaFlow *flow,
- RockerTlv **flow_tlvs)
-{
- OfDpaFlowKey *key = &flow->key;
- OfDpaFlowKey *mask = &flow->mask;
- OfDpaFlowAction *action = &flow->action;
- enum {
- UNICAST_ROUTING_MODE_UNKNOWN,
- UNICAST_ROUTING_MODE_IPV4,
- UNICAST_ROUTING_MODE_IPV6,
- } mode = UNICAST_ROUTING_MODE_UNKNOWN;
- uint8_t type;
-
- if (!flow_tlvs[ROCKER_TLV_OF_DPA_ETHERTYPE]) {
- return -ROCKER_EINVAL;
- }
-
- key->tbl_id = ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING;
- key->width = FLOW_KEY_WIDTH(ipv6.addr.dst);
-
- key->eth.type = rocker_tlv_get_u16(flow_tlvs[ROCKER_TLV_OF_DPA_ETHERTYPE]);
- switch (ntohs(key->eth.type)) {
- case 0x0800:
- mode = UNICAST_ROUTING_MODE_IPV4;
- break;
- case 0x86dd:
- mode = UNICAST_ROUTING_MODE_IPV6;
- break;
- default:
- return -ROCKER_EINVAL;
- }
- mask->eth.type = htons(0xffff);
-
- switch (mode) {
- case UNICAST_ROUTING_MODE_IPV4:
- if (!flow_tlvs[ROCKER_TLV_OF_DPA_DST_IP]) {
- return -ROCKER_EINVAL;
- }
- key->ipv4.addr.dst =
- rocker_tlv_get_u32(flow_tlvs[ROCKER_TLV_OF_DPA_DST_IP]);
- if (ipv4_addr_is_multicast(key->ipv4.addr.dst)) {
- return -ROCKER_EINVAL;
- }
- flow->lpm = of_dpa_mask2prefix(htonl(0xffffffff));
- if (flow_tlvs[ROCKER_TLV_OF_DPA_DST_IP_MASK]) {
- mask->ipv4.addr.dst =
- rocker_tlv_get_u32(flow_tlvs[ROCKER_TLV_OF_DPA_DST_IP_MASK]);
- flow->lpm = of_dpa_mask2prefix(mask->ipv4.addr.dst);
- }
- break;
- case UNICAST_ROUTING_MODE_IPV6:
- if (!flow_tlvs[ROCKER_TLV_OF_DPA_DST_IPV6]) {
- return -ROCKER_EINVAL;
- }
- memcpy(&key->ipv6.addr.dst,
- rocker_tlv_data(flow_tlvs[ROCKER_TLV_OF_DPA_DST_IPV6]),
- sizeof(key->ipv6.addr.dst));
- if (ipv6_addr_is_multicast(&key->ipv6.addr.dst)) {
- return -ROCKER_EINVAL;
- }
- if (flow_tlvs[ROCKER_TLV_OF_DPA_DST_IPV6_MASK]) {
- memcpy(&mask->ipv6.addr.dst,
- rocker_tlv_data(flow_tlvs[ROCKER_TLV_OF_DPA_DST_IPV6_MASK]),
- sizeof(mask->ipv6.addr.dst));
- }
- break;
- default:
- return -ROCKER_EINVAL;
- }
-
- if (flow_tlvs[ROCKER_TLV_OF_DPA_GOTO_TABLE_ID]) {
- action->goto_tbl =
- rocker_tlv_get_le16(flow_tlvs[ROCKER_TLV_OF_DPA_GOTO_TABLE_ID]);
- if (action->goto_tbl != ROCKER_OF_DPA_TABLE_ID_ACL_POLICY) {
- return -ROCKER_EINVAL;
- }
- }
-
- if (flow_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID]) {
- action->write.group_id =
- rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID]);
- type = ROCKER_GROUP_TYPE_GET(action->write.group_id);
- if (type != ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE &&
- type != ROCKER_OF_DPA_GROUP_TYPE_L3_UCAST &&
- type != ROCKER_OF_DPA_GROUP_TYPE_L3_ECMP) {
- return -ROCKER_EINVAL;
- }
- }
-
- return ROCKER_OK;
-}
-
-static int of_dpa_cmd_add_multicast_routing(OfDpaFlow *flow,
- RockerTlv **flow_tlvs)
-{
- OfDpaFlowKey *key = &flow->key;
- OfDpaFlowKey *mask = &flow->mask;
- OfDpaFlowAction *action = &flow->action;
- enum {
- MULTICAST_ROUTING_MODE_UNKNOWN,
- MULTICAST_ROUTING_MODE_IPV4,
- MULTICAST_ROUTING_MODE_IPV6,
- } mode = MULTICAST_ROUTING_MODE_UNKNOWN;
-
- if (!flow_tlvs[ROCKER_TLV_OF_DPA_ETHERTYPE] ||
- !flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID]) {
- return -ROCKER_EINVAL;
- }
-
- key->tbl_id = ROCKER_OF_DPA_TABLE_ID_MULTICAST_ROUTING;
- key->width = FLOW_KEY_WIDTH(ipv6.addr.dst);
-
- key->eth.type = rocker_tlv_get_u16(flow_tlvs[ROCKER_TLV_OF_DPA_ETHERTYPE]);
- switch (ntohs(key->eth.type)) {
- case 0x0800:
- mode = MULTICAST_ROUTING_MODE_IPV4;
- break;
- case 0x86dd:
- mode = MULTICAST_ROUTING_MODE_IPV6;
- break;
- default:
- return -ROCKER_EINVAL;
- }
-
- key->eth.vlan_id = rocker_tlv_get_u16(flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID]);
-
- switch (mode) {
- case MULTICAST_ROUTING_MODE_IPV4:
-
- if (flow_tlvs[ROCKER_TLV_OF_DPA_SRC_IP]) {
- key->ipv4.addr.src =
- rocker_tlv_get_u32(flow_tlvs[ROCKER_TLV_OF_DPA_SRC_IP]);
- }
-
- if (flow_tlvs[ROCKER_TLV_OF_DPA_SRC_IP_MASK]) {
- mask->ipv4.addr.src =
- rocker_tlv_get_u32(flow_tlvs[ROCKER_TLV_OF_DPA_SRC_IP_MASK]);
- }
-
- if (!flow_tlvs[ROCKER_TLV_OF_DPA_SRC_IP]) {
- if (mask->ipv4.addr.src != 0) {
- return -ROCKER_EINVAL;
- }
- }
-
- if (!flow_tlvs[ROCKER_TLV_OF_DPA_DST_IP]) {
- return -ROCKER_EINVAL;
- }
-
- key->ipv4.addr.dst =
- rocker_tlv_get_u32(flow_tlvs[ROCKER_TLV_OF_DPA_DST_IP]);
- if (!ipv4_addr_is_multicast(key->ipv4.addr.dst)) {
- return -ROCKER_EINVAL;
- }
-
- break;
-
- case MULTICAST_ROUTING_MODE_IPV6:
-
- if (flow_tlvs[ROCKER_TLV_OF_DPA_SRC_IPV6]) {
- memcpy(&key->ipv6.addr.src,
- rocker_tlv_data(flow_tlvs[ROCKER_TLV_OF_DPA_SRC_IPV6]),
- sizeof(key->ipv6.addr.src));
- }
-
- if (flow_tlvs[ROCKER_TLV_OF_DPA_SRC_IPV6_MASK]) {
- memcpy(&mask->ipv6.addr.src,
- rocker_tlv_data(flow_tlvs[ROCKER_TLV_OF_DPA_SRC_IPV6_MASK]),
- sizeof(mask->ipv6.addr.src));
- }
-
- if (!flow_tlvs[ROCKER_TLV_OF_DPA_SRC_IPV6]) {
- if (mask->ipv6.addr.src.addr32[0] != 0 &&
- mask->ipv6.addr.src.addr32[1] != 0 &&
- mask->ipv6.addr.src.addr32[2] != 0 &&
- mask->ipv6.addr.src.addr32[3] != 0) {
- return -ROCKER_EINVAL;
- }
- }
-
- if (!flow_tlvs[ROCKER_TLV_OF_DPA_DST_IPV6]) {
- return -ROCKER_EINVAL;
- }
-
- memcpy(&key->ipv6.addr.dst,
- rocker_tlv_data(flow_tlvs[ROCKER_TLV_OF_DPA_DST_IPV6]),
- sizeof(key->ipv6.addr.dst));
- if (!ipv6_addr_is_multicast(&key->ipv6.addr.dst)) {
- return -ROCKER_EINVAL;
- }
-
- break;
-
- default:
- return -ROCKER_EINVAL;
- }
-
- if (flow_tlvs[ROCKER_TLV_OF_DPA_GOTO_TABLE_ID]) {
- action->goto_tbl =
- rocker_tlv_get_le16(flow_tlvs[ROCKER_TLV_OF_DPA_GOTO_TABLE_ID]);
- if (action->goto_tbl != ROCKER_OF_DPA_TABLE_ID_ACL_POLICY) {
- return -ROCKER_EINVAL;
- }
- }
-
- if (flow_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID]) {
- action->write.group_id =
- rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID]);
- if (ROCKER_GROUP_TYPE_GET(action->write.group_id) !=
- ROCKER_OF_DPA_GROUP_TYPE_L3_MCAST) {
- return -ROCKER_EINVAL;
- }
- action->write.vlan_id = key->eth.vlan_id;
- }
-
- return ROCKER_OK;
-}
-
-static int of_dpa_cmd_add_acl_ip(OfDpaFlowKey *key, OfDpaFlowKey *mask,
- RockerTlv **flow_tlvs)
-{
- key->width = FLOW_KEY_WIDTH(ip.tos);
-
- key->ip.proto = 0;
- key->ip.tos = 0;
- mask->ip.proto = 0;
- mask->ip.tos = 0;
-
- if (flow_tlvs[ROCKER_TLV_OF_DPA_IP_PROTO]) {
- key->ip.proto =
- rocker_tlv_get_u8(flow_tlvs[ROCKER_TLV_OF_DPA_IP_PROTO]);
- }
- if (flow_tlvs[ROCKER_TLV_OF_DPA_IP_PROTO_MASK]) {
- mask->ip.proto =
- rocker_tlv_get_u8(flow_tlvs[ROCKER_TLV_OF_DPA_IP_PROTO_MASK]);
- }
- if (flow_tlvs[ROCKER_TLV_OF_DPA_IP_DSCP]) {
- key->ip.tos =
- rocker_tlv_get_u8(flow_tlvs[ROCKER_TLV_OF_DPA_IP_DSCP]);
- }
- if (flow_tlvs[ROCKER_TLV_OF_DPA_IP_DSCP_MASK]) {
- mask->ip.tos =
- rocker_tlv_get_u8(flow_tlvs[ROCKER_TLV_OF_DPA_IP_DSCP_MASK]);
- }
- if (flow_tlvs[ROCKER_TLV_OF_DPA_IP_ECN]) {
- key->ip.tos |=
- rocker_tlv_get_u8(flow_tlvs[ROCKER_TLV_OF_DPA_IP_ECN]) << 6;
- }
- if (flow_tlvs[ROCKER_TLV_OF_DPA_IP_ECN_MASK]) {
- mask->ip.tos |=
- rocker_tlv_get_u8(flow_tlvs[ROCKER_TLV_OF_DPA_IP_ECN_MASK]) << 6;
- }
-
- return ROCKER_OK;
-}
-
-static int of_dpa_cmd_add_acl(OfDpaFlow *flow, RockerTlv **flow_tlvs)
-{
- OfDpaFlowKey *key = &flow->key;
- OfDpaFlowKey *mask = &flow->mask;
- OfDpaFlowAction *action = &flow->action;
- enum {
- ACL_MODE_UNKNOWN,
- ACL_MODE_IPV4_VLAN,
- ACL_MODE_IPV6_VLAN,
- ACL_MODE_IPV4_TENANT,
- ACL_MODE_IPV6_TENANT,
- ACL_MODE_NON_IP_VLAN,
- ACL_MODE_NON_IP_TENANT,
- ACL_MODE_ANY_VLAN,
- ACL_MODE_ANY_TENANT,
- } mode = ACL_MODE_UNKNOWN;
- int err = ROCKER_OK;
-
- if (!flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT] ||
- !flow_tlvs[ROCKER_TLV_OF_DPA_ETHERTYPE]) {
- return -ROCKER_EINVAL;
- }
-
- if (flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID] &&
- flow_tlvs[ROCKER_TLV_OF_DPA_TUNNEL_ID]) {
- return -ROCKER_EINVAL;
- }
-
- key->tbl_id = ROCKER_OF_DPA_TABLE_ID_ACL_POLICY;
- key->width = FLOW_KEY_WIDTH(eth.type);
-
- key->in_pport = rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT]);
- if (flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT_MASK]) {
- mask->in_pport =
- rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT_MASK]);
- }
-
- if (flow_tlvs[ROCKER_TLV_OF_DPA_SRC_MAC]) {
- memcpy(key->eth.src.a,
- rocker_tlv_data(flow_tlvs[ROCKER_TLV_OF_DPA_SRC_MAC]),
- sizeof(key->eth.src.a));
- }
-
- if (flow_tlvs[ROCKER_TLV_OF_DPA_SRC_MAC_MASK]) {
- memcpy(mask->eth.src.a,
- rocker_tlv_data(flow_tlvs[ROCKER_TLV_OF_DPA_SRC_MAC_MASK]),
- sizeof(mask->eth.src.a));
- }
-
- if (flow_tlvs[ROCKER_TLV_OF_DPA_DST_MAC]) {
- memcpy(key->eth.dst.a,
- rocker_tlv_data(flow_tlvs[ROCKER_TLV_OF_DPA_DST_MAC]),
- sizeof(key->eth.dst.a));
- }
-
- if (flow_tlvs[ROCKER_TLV_OF_DPA_DST_MAC_MASK]) {
- memcpy(mask->eth.dst.a,
- rocker_tlv_data(flow_tlvs[ROCKER_TLV_OF_DPA_DST_MAC_MASK]),
- sizeof(mask->eth.dst.a));
- }
-
- key->eth.type = rocker_tlv_get_u16(flow_tlvs[ROCKER_TLV_OF_DPA_ETHERTYPE]);
- if (key->eth.type) {
- mask->eth.type = 0xffff;
- }
-
- if (flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID]) {
- key->eth.vlan_id =
- rocker_tlv_get_u16(flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID]);
- }
-
- if (flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID_MASK]) {
- mask->eth.vlan_id =
- rocker_tlv_get_u16(flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID_MASK]);
- }
-
- switch (ntohs(key->eth.type)) {
- case 0x0000:
- mode = (key->eth.vlan_id) ? ACL_MODE_ANY_VLAN : ACL_MODE_ANY_TENANT;
- break;
- case 0x0800:
- mode = (key->eth.vlan_id) ? ACL_MODE_IPV4_VLAN : ACL_MODE_IPV4_TENANT;
- break;
- case 0x86dd:
- mode = (key->eth.vlan_id) ? ACL_MODE_IPV6_VLAN : ACL_MODE_IPV6_TENANT;
- break;
- default:
- mode = (key->eth.vlan_id) ? ACL_MODE_NON_IP_VLAN :
- ACL_MODE_NON_IP_TENANT;
- break;
- }
-
- /* XXX only supporting VLAN modes for now */
- if (mode != ACL_MODE_IPV4_VLAN &&
- mode != ACL_MODE_IPV6_VLAN &&
- mode != ACL_MODE_NON_IP_VLAN &&
- mode != ACL_MODE_ANY_VLAN) {
- return -ROCKER_EINVAL;
- }
-
- switch (ntohs(key->eth.type)) {
- case 0x0800:
- case 0x86dd:
- err = of_dpa_cmd_add_acl_ip(key, mask, flow_tlvs);
- break;
- }
-
- if (err) {
- return err;
- }
-
- if (flow_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID]) {
- action->write.group_id =
- rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID]);
- }
-
- if (flow_tlvs[ROCKER_TLV_OF_DPA_COPY_CPU_ACTION]) {
- action->apply.copy_to_cpu =
- rocker_tlv_get_u8(flow_tlvs[ROCKER_TLV_OF_DPA_COPY_CPU_ACTION]);
- }
-
- return ROCKER_OK;
-}
-
-static int of_dpa_cmd_flow_add_mod(OfDpa *of_dpa, OfDpaFlow *flow,
- RockerTlv **flow_tlvs)
-{
- enum rocker_of_dpa_table_id tbl;
- int err = ROCKER_OK;
-
- if (!flow_tlvs[ROCKER_TLV_OF_DPA_TABLE_ID] ||
- !flow_tlvs[ROCKER_TLV_OF_DPA_PRIORITY] ||
- !flow_tlvs[ROCKER_TLV_OF_DPA_HARDTIME]) {
- return -ROCKER_EINVAL;
- }
-
- tbl = rocker_tlv_get_le16(flow_tlvs[ROCKER_TLV_OF_DPA_TABLE_ID]);
- flow->priority = rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_PRIORITY]);
- flow->hardtime = rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_HARDTIME]);
-
- if (flow_tlvs[ROCKER_TLV_OF_DPA_IDLETIME]) {
- if (tbl == ROCKER_OF_DPA_TABLE_ID_INGRESS_PORT ||
- tbl == ROCKER_OF_DPA_TABLE_ID_VLAN ||
- tbl == ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC) {
- return -ROCKER_EINVAL;
- }
- flow->idletime =
- rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_IDLETIME]);
- }
-
- switch (tbl) {
- case ROCKER_OF_DPA_TABLE_ID_INGRESS_PORT:
- err = of_dpa_cmd_add_ig_port(flow, flow_tlvs);
- break;
- case ROCKER_OF_DPA_TABLE_ID_VLAN:
- err = of_dpa_cmd_add_vlan(flow, flow_tlvs);
- break;
- case ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC:
- err = of_dpa_cmd_add_term_mac(flow, flow_tlvs);
- break;
- case ROCKER_OF_DPA_TABLE_ID_BRIDGING:
- err = of_dpa_cmd_add_bridging(flow, flow_tlvs);
- break;
- case ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING:
- err = of_dpa_cmd_add_unicast_routing(flow, flow_tlvs);
- break;
- case ROCKER_OF_DPA_TABLE_ID_MULTICAST_ROUTING:
- err = of_dpa_cmd_add_multicast_routing(flow, flow_tlvs);
- break;
- case ROCKER_OF_DPA_TABLE_ID_ACL_POLICY:
- err = of_dpa_cmd_add_acl(flow, flow_tlvs);
- break;
- }
-
- return err;
-}
-
-static int of_dpa_cmd_flow_add(OfDpa *of_dpa, uint64_t cookie,
- RockerTlv **flow_tlvs)
-{
- OfDpaFlow *flow = of_dpa_flow_find(of_dpa, cookie);
- int err = ROCKER_OK;
-
- if (flow) {
- return -ROCKER_EEXIST;
- }
-
- flow = of_dpa_flow_alloc(cookie);
- if (!flow) {
- return -ROCKER_ENOMEM;
- }
-
- err = of_dpa_cmd_flow_add_mod(of_dpa, flow, flow_tlvs);
- if (err) {
- g_free(flow);
- return err;
- }
-
- return of_dpa_flow_add(of_dpa, flow);
-}
-
-static int of_dpa_cmd_flow_mod(OfDpa *of_dpa, uint64_t cookie,
- RockerTlv **flow_tlvs)
-{
- OfDpaFlow *flow = of_dpa_flow_find(of_dpa, cookie);
-
- if (!flow) {
- return -ROCKER_ENOENT;
- }
-
- return of_dpa_cmd_flow_add_mod(of_dpa, flow, flow_tlvs);
-}
-
-static int of_dpa_cmd_flow_del(OfDpa *of_dpa, uint64_t cookie)
-{
- OfDpaFlow *flow = of_dpa_flow_find(of_dpa, cookie);
-
- if (!flow) {
- return -ROCKER_ENOENT;
- }
-
- of_dpa_flow_del(of_dpa, flow);
-
- return ROCKER_OK;
-}
-
-static int of_dpa_cmd_flow_get_stats(OfDpa *of_dpa, uint64_t cookie,
- struct desc_info *info, char *buf)
-{
- OfDpaFlow *flow = of_dpa_flow_find(of_dpa, cookie);
- size_t tlv_size;
- int64_t now = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) / 1000;
- int pos;
-
- if (!flow) {
- return -ROCKER_ENOENT;
- }
-
- tlv_size = rocker_tlv_total_size(sizeof(uint32_t)) + /* duration */
- rocker_tlv_total_size(sizeof(uint64_t)) + /* rx_pkts */
- rocker_tlv_total_size(sizeof(uint64_t)); /* tx_ptks */
-
- if (tlv_size > desc_buf_size(info)) {
- return -ROCKER_EMSGSIZE;
- }
-
- pos = 0;
- rocker_tlv_put_le32(buf, &pos, ROCKER_TLV_OF_DPA_FLOW_STAT_DURATION,
- (int32_t)(now - flow->stats.install_time));
- rocker_tlv_put_le64(buf, &pos, ROCKER_TLV_OF_DPA_FLOW_STAT_RX_PKTS,
- flow->stats.rx_pkts);
- rocker_tlv_put_le64(buf, &pos, ROCKER_TLV_OF_DPA_FLOW_STAT_TX_PKTS,
- flow->stats.tx_pkts);
-
- return desc_set_buf(info, tlv_size);
-}
-
-static int of_dpa_flow_cmd(OfDpa *of_dpa, struct desc_info *info,
- char *buf, uint16_t cmd,
- RockerTlv **flow_tlvs)
-{
- uint64_t cookie;
-
- if (!flow_tlvs[ROCKER_TLV_OF_DPA_COOKIE]) {
- return -ROCKER_EINVAL;
- }
-
- cookie = rocker_tlv_get_le64(flow_tlvs[ROCKER_TLV_OF_DPA_COOKIE]);
-
- switch (cmd) {
- case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_ADD:
- return of_dpa_cmd_flow_add(of_dpa, cookie, flow_tlvs);
- case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_MOD:
- return of_dpa_cmd_flow_mod(of_dpa, cookie, flow_tlvs);
- case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_DEL:
- return of_dpa_cmd_flow_del(of_dpa, cookie);
- case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_GET_STATS:
- return of_dpa_cmd_flow_get_stats(of_dpa, cookie, info, buf);
- }
-
- return -ROCKER_ENOTSUP;
-}
-
-static int of_dpa_cmd_add_l2_interface(OfDpaGroup *group,
- RockerTlv **group_tlvs)
-{
- if (!group_tlvs[ROCKER_TLV_OF_DPA_OUT_PPORT] ||
- !group_tlvs[ROCKER_TLV_OF_DPA_POP_VLAN]) {
- return -ROCKER_EINVAL;
- }
-
- group->l2_interface.out_pport =
- rocker_tlv_get_le32(group_tlvs[ROCKER_TLV_OF_DPA_OUT_PPORT]);
- group->l2_interface.pop_vlan =
- rocker_tlv_get_u8(group_tlvs[ROCKER_TLV_OF_DPA_POP_VLAN]);
-
- return ROCKER_OK;
-}
-
-static int of_dpa_cmd_add_l2_rewrite(OfDpa *of_dpa, OfDpaGroup *group,
- RockerTlv **group_tlvs)
-{
- OfDpaGroup *l2_interface_group;
-
- if (!group_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID_LOWER]) {
- return -ROCKER_EINVAL;
- }
-
- group->l2_rewrite.group_id =
- rocker_tlv_get_le32(group_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID_LOWER]);
-
- l2_interface_group = of_dpa_group_find(of_dpa, group->l2_rewrite.group_id);
- if (!l2_interface_group ||
- ROCKER_GROUP_TYPE_GET(l2_interface_group->id) !=
- ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE) {
- DPRINTF("l2 rewrite group needs a valid l2 interface group\n");
- return -ROCKER_EINVAL;
- }
-
- if (group_tlvs[ROCKER_TLV_OF_DPA_SRC_MAC]) {
- memcpy(group->l2_rewrite.src_mac.a,
- rocker_tlv_data(group_tlvs[ROCKER_TLV_OF_DPA_SRC_MAC]),
- sizeof(group->l2_rewrite.src_mac.a));
- }
-
- if (group_tlvs[ROCKER_TLV_OF_DPA_DST_MAC]) {
- memcpy(group->l2_rewrite.dst_mac.a,
- rocker_tlv_data(group_tlvs[ROCKER_TLV_OF_DPA_DST_MAC]),
- sizeof(group->l2_rewrite.dst_mac.a));
- }
-
- if (group_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID]) {
- group->l2_rewrite.vlan_id =
- rocker_tlv_get_u16(group_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID]);
- if (ROCKER_GROUP_VLAN_GET(l2_interface_group->id) !=
- (ntohs(group->l2_rewrite.vlan_id) & VLAN_VID_MASK)) {
- DPRINTF("Set VLAN ID must be same as L2 interface group\n");
- return -ROCKER_EINVAL;
- }
- }
-
- return ROCKER_OK;
-}
-
-static int of_dpa_cmd_add_l2_flood(OfDpa *of_dpa, OfDpaGroup *group,
- RockerTlv **group_tlvs)
-{
- OfDpaGroup *l2_group;
- RockerTlv **tlvs;
- int err;
- int i;
-
- if (!group_tlvs[ROCKER_TLV_OF_DPA_GROUP_COUNT] ||
- !group_tlvs[ROCKER_TLV_OF_DPA_GROUP_IDS]) {
- return -ROCKER_EINVAL;
- }
-
- group->l2_flood.group_count =
- rocker_tlv_get_le16(group_tlvs[ROCKER_TLV_OF_DPA_GROUP_COUNT]);
-
- tlvs = g_new0(RockerTlv *, group->l2_flood.group_count + 1);
- if (!tlvs) {
- return -ROCKER_ENOMEM;
- }
-
- g_free(group->l2_flood.group_ids);
- group->l2_flood.group_ids =
- g_new0(uint32_t, group->l2_flood.group_count);
- if (!group->l2_flood.group_ids) {
- err = -ROCKER_ENOMEM;
- goto err_out;
- }
-
- rocker_tlv_parse_nested(tlvs, group->l2_flood.group_count,
- group_tlvs[ROCKER_TLV_OF_DPA_GROUP_IDS]);
-
- for (i = 0; i < group->l2_flood.group_count; i++) {
- group->l2_flood.group_ids[i] = rocker_tlv_get_le32(tlvs[i + 1]);
- }
-
- /* All of the L2 interface groups referenced by the L2 flood
- * must have same VLAN
- */
-
- for (i = 0; i < group->l2_flood.group_count; i++) {
- l2_group = of_dpa_group_find(of_dpa, group->l2_flood.group_ids[i]);
- if (!l2_group) {
- continue;
- }
- if ((ROCKER_GROUP_TYPE_GET(l2_group->id) ==
- ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE) &&
- (ROCKER_GROUP_VLAN_GET(l2_group->id) !=
- ROCKER_GROUP_VLAN_GET(group->id))) {
- DPRINTF("l2 interface group 0x%08x VLAN doesn't match l2 "
- "flood group 0x%08x\n",
- group->l2_flood.group_ids[i], group->id);
- err = -ROCKER_EINVAL;
- goto err_out;
- }
- }
-
- g_free(tlvs);
- return ROCKER_OK;
-
-err_out:
- group->l2_flood.group_count = 0;
- g_free(group->l2_flood.group_ids);
- g_free(tlvs);
-
- return err;
-}
-
-static int of_dpa_cmd_add_l3_unicast(OfDpaGroup *group, RockerTlv **group_tlvs)
-{
- if (!group_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID_LOWER]) {
- return -ROCKER_EINVAL;
- }
-
- group->l3_unicast.group_id =
- rocker_tlv_get_le32(group_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID_LOWER]);
-
- if (group_tlvs[ROCKER_TLV_OF_DPA_SRC_MAC]) {
- memcpy(group->l3_unicast.src_mac.a,
- rocker_tlv_data(group_tlvs[ROCKER_TLV_OF_DPA_SRC_MAC]),
- sizeof(group->l3_unicast.src_mac.a));
- }
-
- if (group_tlvs[ROCKER_TLV_OF_DPA_DST_MAC]) {
- memcpy(group->l3_unicast.dst_mac.a,
- rocker_tlv_data(group_tlvs[ROCKER_TLV_OF_DPA_DST_MAC]),
- sizeof(group->l3_unicast.dst_mac.a));
- }
-
- if (group_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID]) {
- group->l3_unicast.vlan_id =
- rocker_tlv_get_u16(group_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID]);
- }
-
- if (group_tlvs[ROCKER_TLV_OF_DPA_TTL_CHECK]) {
- group->l3_unicast.ttl_check =
- rocker_tlv_get_u8(group_tlvs[ROCKER_TLV_OF_DPA_TTL_CHECK]);
- }
-
- return ROCKER_OK;
-}
-
-static int of_dpa_cmd_group_do(OfDpa *of_dpa, uint32_t group_id,
- OfDpaGroup *group, RockerTlv **group_tlvs)
-{
- uint8_t type = ROCKER_GROUP_TYPE_GET(group_id);
-
- switch (type) {
- case ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE:
- return of_dpa_cmd_add_l2_interface(group, group_tlvs);
- case ROCKER_OF_DPA_GROUP_TYPE_L2_REWRITE:
- return of_dpa_cmd_add_l2_rewrite(of_dpa, group, group_tlvs);
- case ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD:
- /* Treat L2 multicast group same as a L2 flood group */
- case ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST:
- return of_dpa_cmd_add_l2_flood(of_dpa, group, group_tlvs);
- case ROCKER_OF_DPA_GROUP_TYPE_L3_UCAST:
- return of_dpa_cmd_add_l3_unicast(group, group_tlvs);
- }
-
- return -ROCKER_ENOTSUP;
-}
-
-static int of_dpa_cmd_group_add(OfDpa *of_dpa, uint32_t group_id,
- RockerTlv **group_tlvs)
-{
- OfDpaGroup *group = of_dpa_group_find(of_dpa, group_id);
- int err;
-
- if (group) {
- return -ROCKER_EEXIST;
- }
-
- group = of_dpa_group_alloc(group_id);
- if (!group) {
- return -ROCKER_ENOMEM;
- }
-
- err = of_dpa_cmd_group_do(of_dpa, group_id, group, group_tlvs);
- if (err) {
- goto err_cmd_add;
- }
-
- err = of_dpa_group_add(of_dpa, group);
- if (err) {
- goto err_cmd_add;
- }
-
- return ROCKER_OK;
-
-err_cmd_add:
- g_free(group);
- return err;
-}
-
-static int of_dpa_cmd_group_mod(OfDpa *of_dpa, uint32_t group_id,
- RockerTlv **group_tlvs)
-{
- OfDpaGroup *group = of_dpa_group_find(of_dpa, group_id);
-
- if (!group) {
- return -ROCKER_ENOENT;
- }
-
- return of_dpa_cmd_group_do(of_dpa, group_id, group, group_tlvs);
-}
-
-static int of_dpa_cmd_group_del(OfDpa *of_dpa, uint32_t group_id)
-{
- OfDpaGroup *group = of_dpa_group_find(of_dpa, group_id);
-
- if (!group) {
- return -ROCKER_ENOENT;
- }
-
- return of_dpa_group_del(of_dpa, group);
-}
-
-static int of_dpa_cmd_group_get_stats(OfDpa *of_dpa, uint32_t group_id,
- struct desc_info *info, char *buf)
-{
- return -ROCKER_ENOTSUP;
-}
-
-static int of_dpa_group_cmd(OfDpa *of_dpa, struct desc_info *info,
- char *buf, uint16_t cmd, RockerTlv **group_tlvs)
-{
- uint32_t group_id;
-
- if (!group_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID]) {
- return -ROCKER_EINVAL;
- }
-
- group_id = rocker_tlv_get_le32(group_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID]);
-
- switch (cmd) {
- case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_ADD:
- return of_dpa_cmd_group_add(of_dpa, group_id, group_tlvs);
- case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_MOD:
- return of_dpa_cmd_group_mod(of_dpa, group_id, group_tlvs);
- case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_DEL:
- return of_dpa_cmd_group_del(of_dpa, group_id);
- case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_GET_STATS:
- return of_dpa_cmd_group_get_stats(of_dpa, group_id, info, buf);
- }
-
- return -ROCKER_ENOTSUP;
-}
-
-static int of_dpa_cmd(World *world, struct desc_info *info,
- char *buf, uint16_t cmd, RockerTlv *cmd_info_tlv)
-{
- OfDpa *of_dpa = world_private(world);
- RockerTlv *tlvs[ROCKER_TLV_OF_DPA_MAX + 1];
-
- rocker_tlv_parse_nested(tlvs, ROCKER_TLV_OF_DPA_MAX, cmd_info_tlv);
-
- switch (cmd) {
- case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_ADD:
- case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_MOD:
- case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_DEL:
- case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_GET_STATS:
- return of_dpa_flow_cmd(of_dpa, info, buf, cmd, tlvs);
- case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_ADD:
- case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_MOD:
- case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_DEL:
- case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_GET_STATS:
- return of_dpa_group_cmd(of_dpa, info, buf, cmd, tlvs);
- }
-
- return -ROCKER_ENOTSUP;
-}
-
-static gboolean rocker_int64_equal(gconstpointer v1, gconstpointer v2)
-{
- return *((const uint64_t *)v1) == *((const uint64_t *)v2);
-}
-
-static guint rocker_int64_hash(gconstpointer v)
-{
- return (guint)*(const uint64_t *)v;
-}
-
-static int of_dpa_init(World *world)
-{
- OfDpa *of_dpa = world_private(world);
-
- of_dpa->world = world;
-
- of_dpa->flow_tbl = g_hash_table_new_full(rocker_int64_hash,
- rocker_int64_equal,
- NULL, g_free);
- if (!of_dpa->flow_tbl) {
- return -ENOMEM;
- }
-
- of_dpa->group_tbl = g_hash_table_new_full(g_int_hash, g_int_equal,
- NULL, g_free);
- if (!of_dpa->group_tbl) {
- goto err_group_tbl;
- }
-
- /* XXX hardcode some artificial table max values */
- of_dpa->flow_tbl_max_size = 100;
- of_dpa->group_tbl_max_size = 100;
-
- return 0;
-
-err_group_tbl:
- g_hash_table_destroy(of_dpa->flow_tbl);
- return -ENOMEM;
-}
-
-static void of_dpa_uninit(World *world)
-{
- OfDpa *of_dpa = world_private(world);
-
- g_hash_table_destroy(of_dpa->group_tbl);
- g_hash_table_destroy(of_dpa->flow_tbl);
-}
-
-struct of_dpa_flow_fill_context {
- RockerOfDpaFlowList *list;
- uint32_t tbl_id;
-};
-
-static void of_dpa_flow_fill(void *cookie, void *value, void *user_data)
-{
- struct of_dpa_flow *flow = value;
- struct of_dpa_flow_key *key = &flow->key;
- struct of_dpa_flow_key *mask = &flow->mask;
- struct of_dpa_flow_fill_context *flow_context = user_data;
- RockerOfDpaFlowList *new;
- RockerOfDpaFlow *nflow;
- RockerOfDpaFlowKey *nkey;
- RockerOfDpaFlowMask *nmask;
- RockerOfDpaFlowAction *naction;
-
- if (flow_context->tbl_id != -1 &&
- flow_context->tbl_id != key->tbl_id) {
- return;
- }
-
- new = g_malloc0(sizeof(*new));
- nflow = new->value = g_malloc0(sizeof(*nflow));
- nkey = nflow->key = g_malloc0(sizeof(*nkey));
- nmask = nflow->mask = g_malloc0(sizeof(*nmask));
- naction = nflow->action = g_malloc0(sizeof(*naction));
-
- nflow->cookie = flow->cookie;
- nflow->hits = flow->stats.hits;
- nkey->priority = flow->priority;
- nkey->tbl_id = key->tbl_id;
-
- if (key->in_pport || mask->in_pport) {
- nkey->has_in_pport = true;
- nkey->in_pport = key->in_pport;
- }
-
- if (nkey->has_in_pport && mask->in_pport != 0xffffffff) {
- nmask->has_in_pport = true;
- nmask->in_pport = mask->in_pport;
- }
-
- if (key->eth.vlan_id || mask->eth.vlan_id) {
- nkey->has_vlan_id = true;
- nkey->vlan_id = ntohs(key->eth.vlan_id);
- }
-
- if (nkey->has_vlan_id && mask->eth.vlan_id != 0xffff) {
- nmask->has_vlan_id = true;
- nmask->vlan_id = ntohs(mask->eth.vlan_id);
- }
-
- if (key->tunnel_id || mask->tunnel_id) {
- nkey->has_tunnel_id = true;
- nkey->tunnel_id = key->tunnel_id;
- }
-
- if (nkey->has_tunnel_id && mask->tunnel_id != 0xffffffff) {
- nmask->has_tunnel_id = true;
- nmask->tunnel_id = mask->tunnel_id;
- }
-
- if (memcmp(key->eth.src.a, zero_mac.a, ETH_ALEN) ||
- memcmp(mask->eth.src.a, zero_mac.a, ETH_ALEN)) {
- nkey->has_eth_src = true;
- nkey->eth_src = qemu_mac_strdup_printf(key->eth.src.a);
- }
-
- if (nkey->has_eth_src && memcmp(mask->eth.src.a, ff_mac.a, ETH_ALEN)) {
- nmask->has_eth_src = true;
- nmask->eth_src = qemu_mac_strdup_printf(mask->eth.src.a);
- }
-
- if (memcmp(key->eth.dst.a, zero_mac.a, ETH_ALEN) ||
- memcmp(mask->eth.dst.a, zero_mac.a, ETH_ALEN)) {
- nkey->has_eth_dst = true;
- nkey->eth_dst = qemu_mac_strdup_printf(key->eth.dst.a);
- }
-
- if (nkey->has_eth_dst && memcmp(mask->eth.dst.a, ff_mac.a, ETH_ALEN)) {
- nmask->has_eth_dst = true;
- nmask->eth_dst = qemu_mac_strdup_printf(mask->eth.dst.a);
- }
-
- if (key->eth.type) {
-
- nkey->has_eth_type = true;
- nkey->eth_type = ntohs(key->eth.type);
-
- switch (ntohs(key->eth.type)) {
- case 0x0800:
- case 0x86dd:
- if (key->ip.proto || mask->ip.proto) {
- nkey->has_ip_proto = true;
- nkey->ip_proto = key->ip.proto;
- }
- if (nkey->has_ip_proto && mask->ip.proto != 0xff) {
- nmask->has_ip_proto = true;
- nmask->ip_proto = mask->ip.proto;
- }
- if (key->ip.tos || mask->ip.tos) {
- nkey->has_ip_tos = true;
- nkey->ip_tos = key->ip.tos;
- }
- if (nkey->has_ip_tos && mask->ip.tos != 0xff) {
- nmask->has_ip_tos = true;
- nmask->ip_tos = mask->ip.tos;
- }
- break;
- }
-
- switch (ntohs(key->eth.type)) {
- case 0x0800:
- if (key->ipv4.addr.dst || mask->ipv4.addr.dst) {
- char *dst = inet_ntoa(*(struct in_addr *)&key->ipv4.addr.dst);
- int dst_len = of_dpa_mask2prefix(mask->ipv4.addr.dst);
- nkey->has_ip_dst = true;
- nkey->ip_dst = g_strdup_printf("%s/%d", dst, dst_len);
- }
- break;
- }
- }
-
- if (flow->action.goto_tbl) {
- naction->has_goto_tbl = true;
- naction->goto_tbl = flow->action.goto_tbl;
- }
-
- if (flow->action.write.group_id) {
- naction->has_group_id = true;
- naction->group_id = flow->action.write.group_id;
- }
-
- if (flow->action.apply.new_vlan_id) {
- naction->has_new_vlan_id = true;
- naction->new_vlan_id = flow->action.apply.new_vlan_id;
- }
-
- new->next = flow_context->list;
- flow_context->list = new;
-}
-
-RockerOfDpaFlowList *qmp_query_rocker_of_dpa_flows(const char *name,
- bool has_tbl_id,
- uint32_t tbl_id,
- Error **errp)
-{
- struct rocker *r;
- struct world *w;
- struct of_dpa *of_dpa;
- struct of_dpa_flow_fill_context fill_context = {
- .list = NULL,
- .tbl_id = tbl_id,
- };
-
- r = rocker_find(name);
- if (!r) {
- error_setg(errp, "rocker %s not found", name);
- return NULL;
- }
-
- w = rocker_get_world(r, ROCKER_WORLD_TYPE_OF_DPA);
- if (!w) {
- error_setg(errp, "rocker %s doesn't have OF-DPA world", name);
- return NULL;
- }
-
- of_dpa = world_private(w);
-
- g_hash_table_foreach(of_dpa->flow_tbl, of_dpa_flow_fill, &fill_context);
-
- return fill_context.list;
-}
-
-struct of_dpa_group_fill_context {
- RockerOfDpaGroupList *list;
- uint8_t type;
-};
-
-static void of_dpa_group_fill(void *key, void *value, void *user_data)
-{
- struct of_dpa_group *group = value;
- struct of_dpa_group_fill_context *flow_context = user_data;
- RockerOfDpaGroupList *new;
- RockerOfDpaGroup *ngroup;
- struct uint32List *id;
- int i;
-
- if (flow_context->type != 9 &&
- flow_context->type != ROCKER_GROUP_TYPE_GET(group->id)) {
- return;
- }
-
- new = g_malloc0(sizeof(*new));
- ngroup = new->value = g_malloc0(sizeof(*ngroup));
-
- ngroup->id = group->id;
-
- ngroup->type = ROCKER_GROUP_TYPE_GET(group->id);
-
- switch (ngroup->type) {
- case ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE:
- ngroup->has_vlan_id = true;
- ngroup->vlan_id = ROCKER_GROUP_VLAN_GET(group->id);
- ngroup->has_pport = true;
- ngroup->pport = ROCKER_GROUP_PORT_GET(group->id);
- ngroup->has_out_pport = true;
- ngroup->out_pport = group->l2_interface.out_pport;
- ngroup->has_pop_vlan = true;
- ngroup->pop_vlan = group->l2_interface.pop_vlan;
- break;
- case ROCKER_OF_DPA_GROUP_TYPE_L2_REWRITE:
- ngroup->has_index = true;
- ngroup->index = ROCKER_GROUP_INDEX_LONG_GET(group->id);
- ngroup->has_group_id = true;
- ngroup->group_id = group->l2_rewrite.group_id;
- if (group->l2_rewrite.vlan_id) {
- ngroup->has_set_vlan_id = true;
- ngroup->set_vlan_id = ntohs(group->l2_rewrite.vlan_id);
- }
- if (memcmp(group->l2_rewrite.src_mac.a, zero_mac.a, ETH_ALEN)) {
- ngroup->has_set_eth_src = true;
- ngroup->set_eth_src =
- qemu_mac_strdup_printf(group->l2_rewrite.src_mac.a);
- }
- if (memcmp(group->l2_rewrite.dst_mac.a, zero_mac.a, ETH_ALEN)) {
- ngroup->has_set_eth_dst = true;
- ngroup->set_eth_dst =
- qemu_mac_strdup_printf(group->l2_rewrite.dst_mac.a);
- }
- break;
- case ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD:
- case ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST:
- ngroup->has_vlan_id = true;
- ngroup->vlan_id = ROCKER_GROUP_VLAN_GET(group->id);
- ngroup->has_index = true;
- ngroup->index = ROCKER_GROUP_INDEX_GET(group->id);
- for (i = 0; i < group->l2_flood.group_count; i++) {
- ngroup->has_group_ids = true;
- id = g_malloc0(sizeof(*id));
- id->value = group->l2_flood.group_ids[i];
- id->next = ngroup->group_ids;
- ngroup->group_ids = id;
- }
- break;
- case ROCKER_OF_DPA_GROUP_TYPE_L3_UCAST:
- ngroup->has_index = true;
- ngroup->index = ROCKER_GROUP_INDEX_LONG_GET(group->id);
- ngroup->has_group_id = true;
- ngroup->group_id = group->l3_unicast.group_id;
- if (group->l3_unicast.vlan_id) {
- ngroup->has_set_vlan_id = true;
- ngroup->set_vlan_id = ntohs(group->l3_unicast.vlan_id);
- }
- if (memcmp(group->l3_unicast.src_mac.a, zero_mac.a, ETH_ALEN)) {
- ngroup->has_set_eth_src = true;
- ngroup->set_eth_src =
- qemu_mac_strdup_printf(group->l3_unicast.src_mac.a);
- }
- if (memcmp(group->l3_unicast.dst_mac.a, zero_mac.a, ETH_ALEN)) {
- ngroup->has_set_eth_dst = true;
- ngroup->set_eth_dst =
- qemu_mac_strdup_printf(group->l3_unicast.dst_mac.a);
- }
- if (group->l3_unicast.ttl_check) {
- ngroup->has_ttl_check = true;
- ngroup->ttl_check = group->l3_unicast.ttl_check;
- }
- break;
- }
-
- new->next = flow_context->list;
- flow_context->list = new;
-}
-
-RockerOfDpaGroupList *qmp_query_rocker_of_dpa_groups(const char *name,
- bool has_type,
- uint8_t type,
- Error **errp)
-{
- struct rocker *r;
- struct world *w;
- struct of_dpa *of_dpa;
- struct of_dpa_group_fill_context fill_context = {
- .list = NULL,
- .type = type,
- };
-
- r = rocker_find(name);
- if (!r) {
- error_setg(errp, "rocker %s not found", name);
- return NULL;
- }
-
- w = rocker_get_world(r, ROCKER_WORLD_TYPE_OF_DPA);
- if (!w) {
- error_setg(errp, "rocker %s doesn't have OF-DPA world", name);
- return NULL;
- }
-
- of_dpa = world_private(w);
-
- g_hash_table_foreach(of_dpa->group_tbl, of_dpa_group_fill, &fill_context);
-
- return fill_context.list;
-}
-
-static WorldOps of_dpa_ops = {
- .name = "ofdpa",
- .init = of_dpa_init,
- .uninit = of_dpa_uninit,
- .ig = of_dpa_ig,
- .cmd = of_dpa_cmd,
-};
-
-World *of_dpa_world_alloc(Rocker *r)
-{
- return world_alloc(r, sizeof(OfDpa), ROCKER_WORLD_TYPE_OF_DPA, &of_dpa_ops);
-}
diff --git a/qemu/hw/net/rocker/rocker_of_dpa.h b/qemu/hw/net/rocker/rocker_of_dpa.h
deleted file mode 100644
index f3f6d7780..000000000
--- a/qemu/hw/net/rocker/rocker_of_dpa.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * QEMU rocker switch emulation - OF-DPA flow processing support
- *
- * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#ifndef _ROCKER_OF_DPA_H_
-#define _ROCKER_OF_DPA_H_
-
-World *of_dpa_world_alloc(Rocker *r);
-
-#endif /* _ROCKER_OF_DPA_H_ */
diff --git a/qemu/hw/net/rocker/rocker_tlv.h b/qemu/hw/net/rocker/rocker_tlv.h
deleted file mode 100644
index e3c4ab679..000000000
--- a/qemu/hw/net/rocker/rocker_tlv.h
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * QEMU rocker switch emulation - TLV parsing and composing
- *
- * Copyright (c) 2014 Jiri Pirko <jiri@resnulli.us>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#ifndef _ROCKER_TLV_H_
-#define _ROCKER_TLV_H_
-
-#define ROCKER_TLV_ALIGNTO 8U
-#define ROCKER_TLV_ALIGN(len) \
- (((len) + ROCKER_TLV_ALIGNTO - 1) & ~(ROCKER_TLV_ALIGNTO - 1))
-#define ROCKER_TLV_HDRLEN ROCKER_TLV_ALIGN(sizeof(RockerTlv))
-
-/*
- * <------- ROCKER_TLV_HDRLEN -------> <--- ROCKER_TLV_ALIGN(payload) --->
- * +-----------------------------+- - -+- - - - - - - - - - - - - - -+- - -+
- * | Header | Pad | Payload | Pad |
- * | (RockerTlv) | ing | | ing |
- * +-----------------------------+- - -+- - - - - - - - - - - - - - -+- - -+
- * <--------------------------- tlv->len -------------------------->
- */
-
-static inline RockerTlv *rocker_tlv_next(const RockerTlv *tlv, int *remaining)
-{
- int totlen = ROCKER_TLV_ALIGN(le16_to_cpu(tlv->len));
-
- *remaining -= totlen;
- return (RockerTlv *) ((char *) tlv + totlen);
-}
-
-static inline int rocker_tlv_ok(const RockerTlv *tlv, int remaining)
-{
- return remaining >= (int) ROCKER_TLV_HDRLEN &&
- le16_to_cpu(tlv->len) >= ROCKER_TLV_HDRLEN &&
- le16_to_cpu(tlv->len) <= remaining;
-}
-
-#define rocker_tlv_for_each(pos, head, len, rem) \
- for (pos = head, rem = len; \
- rocker_tlv_ok(pos, rem); \
- pos = rocker_tlv_next(pos, &(rem)))
-
-#define rocker_tlv_for_each_nested(pos, tlv, rem) \
- rocker_tlv_for_each(pos, rocker_tlv_data(tlv), rocker_tlv_len(tlv), rem)
-
-static inline int rocker_tlv_size(int payload)
-{
- return ROCKER_TLV_HDRLEN + payload;
-}
-
-static inline int rocker_tlv_total_size(int payload)
-{
- return ROCKER_TLV_ALIGN(rocker_tlv_size(payload));
-}
-
-static inline int rocker_tlv_padlen(int payload)
-{
- return rocker_tlv_total_size(payload) - rocker_tlv_size(payload);
-}
-
-static inline int rocker_tlv_type(const RockerTlv *tlv)
-{
- return le32_to_cpu(tlv->type);
-}
-
-static inline void *rocker_tlv_data(const RockerTlv *tlv)
-{
- return (char *) tlv + ROCKER_TLV_HDRLEN;
-}
-
-static inline int rocker_tlv_len(const RockerTlv *tlv)
-{
- return le16_to_cpu(tlv->len) - ROCKER_TLV_HDRLEN;
-}
-
-static inline uint8_t rocker_tlv_get_u8(const RockerTlv *tlv)
-{
- return *(uint8_t *) rocker_tlv_data(tlv);
-}
-
-static inline uint16_t rocker_tlv_get_u16(const RockerTlv *tlv)
-{
- return *(uint16_t *) rocker_tlv_data(tlv);
-}
-
-static inline uint32_t rocker_tlv_get_u32(const RockerTlv *tlv)
-{
- return *(uint32_t *) rocker_tlv_data(tlv);
-}
-
-static inline uint64_t rocker_tlv_get_u64(const RockerTlv *tlv)
-{
- return *(uint64_t *) rocker_tlv_data(tlv);
-}
-
-static inline uint16_t rocker_tlv_get_le16(const RockerTlv *tlv)
-{
- return le16_to_cpup((uint16_t *) rocker_tlv_data(tlv));
-}
-
-static inline uint32_t rocker_tlv_get_le32(const RockerTlv *tlv)
-{
- return le32_to_cpup((uint32_t *) rocker_tlv_data(tlv));
-}
-
-static inline uint64_t rocker_tlv_get_le64(const RockerTlv *tlv)
-{
- return le64_to_cpup((uint64_t *) rocker_tlv_data(tlv));
-}
-
-static inline void rocker_tlv_parse(RockerTlv **tb, int maxtype,
- const char *buf, int buf_len)
-{
- const RockerTlv *tlv;
- const RockerTlv *head = (const RockerTlv *) buf;
- int rem;
-
- memset(tb, 0, sizeof(RockerTlv *) * (maxtype + 1));
-
- rocker_tlv_for_each(tlv, head, buf_len, rem) {
- uint32_t type = rocker_tlv_type(tlv);
-
- if (type > 0 && type <= maxtype) {
- tb[type] = (RockerTlv *) tlv;
- }
- }
-}
-
-static inline void rocker_tlv_parse_nested(RockerTlv **tb, int maxtype,
- const RockerTlv *tlv)
-{
- rocker_tlv_parse(tb, maxtype, rocker_tlv_data(tlv), rocker_tlv_len(tlv));
-}
-
-static inline RockerTlv *rocker_tlv_start(char *buf, int buf_pos)
-{
- return (RockerTlv *) (buf + buf_pos);
-}
-
-static inline void rocker_tlv_put_iov(char *buf, int *buf_pos,
- int type, const struct iovec *iov,
- const unsigned int iovcnt)
-{
- size_t len = iov_size(iov, iovcnt);
- int total_size = rocker_tlv_total_size(len);
- RockerTlv *tlv;
-
- tlv = rocker_tlv_start(buf, *buf_pos);
- *buf_pos += total_size;
- tlv->type = cpu_to_le32(type);
- tlv->len = cpu_to_le16(rocker_tlv_size(len));
- iov_to_buf(iov, iovcnt, 0, rocker_tlv_data(tlv), len);
- memset((char *) tlv + le16_to_cpu(tlv->len), 0, rocker_tlv_padlen(len));
-}
-
-static inline void rocker_tlv_put(char *buf, int *buf_pos,
- int type, int len, void *data)
-{
- struct iovec iov = {
- .iov_base = data,
- .iov_len = len,
- };
-
- rocker_tlv_put_iov(buf, buf_pos, type, &iov, 1);
-}
-
-static inline void rocker_tlv_put_u8(char *buf, int *buf_pos,
- int type, uint8_t value)
-{
- rocker_tlv_put(buf, buf_pos, type, sizeof(uint8_t), &value);
-}
-
-static inline void rocker_tlv_put_u16(char *buf, int *buf_pos,
- int type, uint16_t value)
-{
- rocker_tlv_put(buf, buf_pos, type, sizeof(uint16_t), &value);
-}
-
-static inline void rocker_tlv_put_u32(char *buf, int *buf_pos,
- int type, uint32_t value)
-{
- rocker_tlv_put(buf, buf_pos, type, sizeof(uint32_t), &value);
-}
-
-static inline void rocker_tlv_put_u64(char *buf, int *buf_pos,
- int type, uint64_t value)
-{
- rocker_tlv_put(buf, buf_pos, type, sizeof(uint64_t), &value);
-}
-
-static inline void rocker_tlv_put_le16(char *buf, int *buf_pos,
- int type, uint16_t value)
-{
- value = cpu_to_le16(value);
- rocker_tlv_put(buf, buf_pos, type, sizeof(uint16_t), &value);
-}
-
-static inline void rocker_tlv_put_le32(char *buf, int *buf_pos,
- int type, uint32_t value)
-{
- value = cpu_to_le32(value);
- rocker_tlv_put(buf, buf_pos, type, sizeof(uint32_t), &value);
-}
-
-static inline void rocker_tlv_put_le64(char *buf, int *buf_pos,
- int type, uint64_t value)
-{
- value = cpu_to_le64(value);
- rocker_tlv_put(buf, buf_pos, type, sizeof(uint64_t), &value);
-}
-
-static inline RockerTlv *rocker_tlv_nest_start(char *buf, int *buf_pos,
- int type)
-{
- RockerTlv *start = rocker_tlv_start(buf, *buf_pos);
-
- rocker_tlv_put(buf, buf_pos, type, 0, NULL);
- return start;
-}
-
-static inline void rocker_tlv_nest_end(char *buf, int *buf_pos,
- RockerTlv *start)
-{
- start->len = (char *) rocker_tlv_start(buf, *buf_pos) - (char *) start;
-}
-
-static inline void rocker_tlv_nest_cancel(char *buf, int *buf_pos,
- RockerTlv *start)
-{
- *buf_pos = (char *) start - buf;
-}
-
-#endif
diff --git a/qemu/hw/net/rocker/rocker_world.c b/qemu/hw/net/rocker/rocker_world.c
deleted file mode 100644
index 89777e968..000000000
--- a/qemu/hw/net/rocker/rocker_world.c
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * QEMU rocker switch emulation - switch worlds
- *
- * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include "qemu/osdep.h"
-#include "qemu/iov.h"
-
-#include "rocker.h"
-#include "rocker_world.h"
-
-struct world {
- Rocker *r;
- enum rocker_world_type type;
- WorldOps *ops;
-};
-
-ssize_t world_ingress(World *world, uint32_t pport,
- const struct iovec *iov, int iovcnt)
-{
- if (world->ops->ig) {
- return world->ops->ig(world, pport, iov, iovcnt);
- }
-
- return -1;
-}
-
-int world_do_cmd(World *world, DescInfo *info,
- char *buf, uint16_t cmd, RockerTlv *cmd_info_tlv)
-{
- if (world->ops->cmd) {
- return world->ops->cmd(world, info, buf, cmd, cmd_info_tlv);
- }
-
- return -ROCKER_ENOTSUP;
-}
-
-World *world_alloc(Rocker *r, size_t sizeof_private,
- enum rocker_world_type type, WorldOps *ops)
-{
- World *w = g_malloc0(sizeof(World) + sizeof_private);
-
- if (w) {
- w->r = r;
- w->type = type;
- w->ops = ops;
- if (w->ops->init) {
- w->ops->init(w);
- }
- }
-
- return w;
-}
-
-void world_free(World *world)
-{
- if (world->ops->uninit) {
- world->ops->uninit(world);
- }
- g_free(world);
-}
-
-void world_reset(World *world)
-{
- if (world->ops->uninit) {
- world->ops->uninit(world);
- }
- if (world->ops->init) {
- world->ops->init(world);
- }
-}
-
-void *world_private(World *world)
-{
- return world + 1;
-}
-
-Rocker *world_rocker(World *world)
-{
- return world->r;
-}
-
-enum rocker_world_type world_type(World *world)
-{
- return world->type;
-}
-
-const char *world_name(World *world)
-{
- return world->ops->name;
-}
diff --git a/qemu/hw/net/rocker/rocker_world.h b/qemu/hw/net/rocker/rocker_world.h
deleted file mode 100644
index 58ade4733..000000000
--- a/qemu/hw/net/rocker/rocker_world.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * QEMU rocker switch emulation - switch worlds
- *
- * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#ifndef _ROCKER_WORLD_H_
-#define _ROCKER_WORLD_H_
-
-#include "rocker_hw.h"
-
-enum rocker_world_type {
- ROCKER_WORLD_TYPE_OF_DPA = ROCKER_PORT_MODE_OF_DPA,
- ROCKER_WORLD_TYPE_MAX,
-};
-
-typedef int (world_init)(World *world);
-typedef void (world_uninit)(World *world);
-typedef ssize_t (world_ig)(World *world, uint32_t pport,
- const struct iovec *iov, int iovcnt);
-typedef int (world_cmd)(World *world, DescInfo *info,
- char *buf, uint16_t cmd,
- RockerTlv *cmd_info_tlv);
-
-typedef struct world_ops {
- const char *name;
- world_init *init;
- world_uninit *uninit;
- world_ig *ig;
- world_cmd *cmd;
-} WorldOps;
-
-ssize_t world_ingress(World *world, uint32_t pport,
- const struct iovec *iov, int iovcnt);
-int world_do_cmd(World *world, DescInfo *info,
- char *buf, uint16_t cmd, RockerTlv *cmd_info_tlv);
-
-World *world_alloc(Rocker *r, size_t sizeof_private,
- enum rocker_world_type type, WorldOps *ops);
-void world_free(World *world);
-void world_reset(World *world);
-
-void *world_private(World *world);
-Rocker *world_rocker(World *world);
-
-enum rocker_world_type world_type(World *world);
-const char *world_name(World *world);
-
-World *rocker_get_world(Rocker *r, enum rocker_world_type type);
-
-#endif /* _ROCKER_WORLD_H_ */
diff --git a/qemu/hw/net/rtl8139.c b/qemu/hw/net/rtl8139.c
deleted file mode 100644
index 1e5ec149f..000000000
--- a/qemu/hw/net/rtl8139.c
+++ /dev/null
@@ -1,3509 +0,0 @@
-/**
- * QEMU RTL8139 emulation
- *
- * Copyright (c) 2006 Igor Kovalenko
- *
- * 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.
-
- * Modifications:
- * 2006-Jan-28 Mark Malakanov : TSAD and CSCR implementation (for Windows driver)
- *
- * 2006-Apr-28 Juergen Lock : EEPROM emulation changes for FreeBSD driver
- * HW revision ID changes for FreeBSD driver
- *
- * 2006-Jul-01 Igor Kovalenko : Implemented loopback mode for FreeBSD driver
- * Corrected packet transfer reassembly routine for 8139C+ mode
- * Rearranged debugging print statements
- * Implemented PCI timer interrupt (disabled by default)
- * Implemented Tally Counters, increased VM load/save version
- * Implemented IP/TCP/UDP checksum task offloading
- *
- * 2006-Jul-04 Igor Kovalenko : Implemented TCP segmentation offloading
- * Fixed MTU=1500 for produced ethernet frames
- *
- * 2006-Jul-09 Igor Kovalenko : Fixed TCP header length calculation while processing
- * segmentation offloading
- * Removed slirp.h dependency
- * Added rx/tx buffer reset when enabling rx/tx operation
- *
- * 2010-Feb-04 Frediano Ziglio: Rewrote timer support using QEMU timer only
- * when strictly needed (required for
- * Darwin)
- * 2011-Mar-22 Benjamin Poirier: Implemented VLAN offloading
- */
-
-/* For crc32 */
-#include "qemu/osdep.h"
-#include <zlib.h>
-
-#include "hw/hw.h"
-#include "hw/pci/pci.h"
-#include "sysemu/dma.h"
-#include "qemu/timer.h"
-#include "net/net.h"
-#include "net/eth.h"
-#include "hw/loader.h"
-#include "sysemu/sysemu.h"
-#include "qemu/iov.h"
-
-/* debug RTL8139 card */
-//#define DEBUG_RTL8139 1
-
-#define PCI_PERIOD 30 /* 30 ns period = 33.333333 Mhz frequency */
-
-#define SET_MASKED(input, mask, curr) \
- ( ( (input) & ~(mask) ) | ( (curr) & (mask) ) )
-
-/* arg % size for size which is a power of 2 */
-#define MOD2(input, size) \
- ( ( input ) & ( size - 1 ) )
-
-#define ETHER_TYPE_LEN 2
-#define ETH_MTU 1500
-
-#define VLAN_TCI_LEN 2
-#define VLAN_HLEN (ETHER_TYPE_LEN + VLAN_TCI_LEN)
-
-#if defined (DEBUG_RTL8139)
-# define DPRINTF(fmt, ...) \
- do { fprintf(stderr, "RTL8139: " fmt, ## __VA_ARGS__); } while (0)
-#else
-static inline GCC_FMT_ATTR(1, 2) int DPRINTF(const char *fmt, ...)
-{
- return 0;
-}
-#endif
-
-#define TYPE_RTL8139 "rtl8139"
-
-#define RTL8139(obj) \
- OBJECT_CHECK(RTL8139State, (obj), TYPE_RTL8139)
-
-/* Symbolic offsets to registers. */
-enum RTL8139_registers {
- MAC0 = 0, /* Ethernet hardware address. */
- MAR0 = 8, /* Multicast filter. */
- TxStatus0 = 0x10,/* Transmit status (Four 32bit registers). C mode only */
- /* Dump Tally Conter control register(64bit). C+ mode only */
- TxAddr0 = 0x20, /* Tx descriptors (also four 32bit). */
- RxBuf = 0x30,
- ChipCmd = 0x37,
- RxBufPtr = 0x38,
- RxBufAddr = 0x3A,
- IntrMask = 0x3C,
- IntrStatus = 0x3E,
- TxConfig = 0x40,
- RxConfig = 0x44,
- Timer = 0x48, /* A general-purpose counter. */
- RxMissed = 0x4C, /* 24 bits valid, write clears. */
- Cfg9346 = 0x50,
- Config0 = 0x51,
- Config1 = 0x52,
- FlashReg = 0x54,
- MediaStatus = 0x58,
- Config3 = 0x59,
- Config4 = 0x5A, /* absent on RTL-8139A */
- HltClk = 0x5B,
- MultiIntr = 0x5C,
- PCIRevisionID = 0x5E,
- TxSummary = 0x60, /* TSAD register. Transmit Status of All Descriptors*/
- BasicModeCtrl = 0x62,
- BasicModeStatus = 0x64,
- NWayAdvert = 0x66,
- NWayLPAR = 0x68,
- NWayExpansion = 0x6A,
- /* Undocumented registers, but required for proper operation. */
- FIFOTMS = 0x70, /* FIFO Control and test. */
- CSCR = 0x74, /* Chip Status and Configuration Register. */
- PARA78 = 0x78,
- PARA7c = 0x7c, /* Magic transceiver parameter register. */
- Config5 = 0xD8, /* absent on RTL-8139A */
- /* C+ mode */
- TxPoll = 0xD9, /* Tell chip to check Tx descriptors for work */
- RxMaxSize = 0xDA, /* Max size of an Rx packet (8169 only) */
- CpCmd = 0xE0, /* C+ Command register (C+ mode only) */
- IntrMitigate = 0xE2, /* rx/tx interrupt mitigation control */
- RxRingAddrLO = 0xE4, /* 64-bit start addr of Rx ring */
- RxRingAddrHI = 0xE8, /* 64-bit start addr of Rx ring */
- TxThresh = 0xEC, /* Early Tx threshold */
-};
-
-enum ClearBitMasks {
- MultiIntrClear = 0xF000,
- ChipCmdClear = 0xE2,
- Config1Clear = (1<<7)|(1<<6)|(1<<3)|(1<<2)|(1<<1),
-};
-
-enum ChipCmdBits {
- CmdReset = 0x10,
- CmdRxEnb = 0x08,
- CmdTxEnb = 0x04,
- RxBufEmpty = 0x01,
-};
-
-/* C+ mode */
-enum CplusCmdBits {
- CPlusRxVLAN = 0x0040, /* enable receive VLAN detagging */
- CPlusRxChkSum = 0x0020, /* enable receive checksum offloading */
- CPlusRxEnb = 0x0002,
- CPlusTxEnb = 0x0001,
-};
-
-/* Interrupt register bits, using my own meaningful names. */
-enum IntrStatusBits {
- PCIErr = 0x8000,
- PCSTimeout = 0x4000,
- RxFIFOOver = 0x40,
- RxUnderrun = 0x20, /* Packet Underrun / Link Change */
- RxOverflow = 0x10,
- TxErr = 0x08,
- TxOK = 0x04,
- RxErr = 0x02,
- RxOK = 0x01,
-
- RxAckBits = RxFIFOOver | RxOverflow | RxOK,
-};
-
-enum TxStatusBits {
- TxHostOwns = 0x2000,
- TxUnderrun = 0x4000,
- TxStatOK = 0x8000,
- TxOutOfWindow = 0x20000000,
- TxAborted = 0x40000000,
- TxCarrierLost = 0x80000000,
-};
-enum RxStatusBits {
- RxMulticast = 0x8000,
- RxPhysical = 0x4000,
- RxBroadcast = 0x2000,
- RxBadSymbol = 0x0020,
- RxRunt = 0x0010,
- RxTooLong = 0x0008,
- RxCRCErr = 0x0004,
- RxBadAlign = 0x0002,
- RxStatusOK = 0x0001,
-};
-
-/* Bits in RxConfig. */
-enum rx_mode_bits {
- AcceptErr = 0x20,
- AcceptRunt = 0x10,
- AcceptBroadcast = 0x08,
- AcceptMulticast = 0x04,
- AcceptMyPhys = 0x02,
- AcceptAllPhys = 0x01,
-};
-
-/* Bits in TxConfig. */
-enum tx_config_bits {
-
- /* Interframe Gap Time. Only TxIFG96 doesn't violate IEEE 802.3 */
- TxIFGShift = 24,
- TxIFG84 = (0 << TxIFGShift), /* 8.4us / 840ns (10 / 100Mbps) */
- TxIFG88 = (1 << TxIFGShift), /* 8.8us / 880ns (10 / 100Mbps) */
- TxIFG92 = (2 << TxIFGShift), /* 9.2us / 920ns (10 / 100Mbps) */
- TxIFG96 = (3 << TxIFGShift), /* 9.6us / 960ns (10 / 100Mbps) */
-
- TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */
- TxCRC = (1 << 16), /* DISABLE appending CRC to end of Tx packets */
- TxClearAbt = (1 << 0), /* Clear abort (WO) */
- TxDMAShift = 8, /* DMA burst value (0-7) is shifted this many bits */
- TxRetryShift = 4, /* TXRR value (0-15) is shifted this many bits */
-
- TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */
-};
-
-
-/* Transmit Status of All Descriptors (TSAD) Register */
-enum TSAD_bits {
- TSAD_TOK3 = 1<<15, // TOK bit of Descriptor 3
- TSAD_TOK2 = 1<<14, // TOK bit of Descriptor 2
- TSAD_TOK1 = 1<<13, // TOK bit of Descriptor 1
- TSAD_TOK0 = 1<<12, // TOK bit of Descriptor 0
- TSAD_TUN3 = 1<<11, // TUN bit of Descriptor 3
- TSAD_TUN2 = 1<<10, // TUN bit of Descriptor 2
- TSAD_TUN1 = 1<<9, // TUN bit of Descriptor 1
- TSAD_TUN0 = 1<<8, // TUN bit of Descriptor 0
- TSAD_TABT3 = 1<<07, // TABT bit of Descriptor 3
- TSAD_TABT2 = 1<<06, // TABT bit of Descriptor 2
- TSAD_TABT1 = 1<<05, // TABT bit of Descriptor 1
- TSAD_TABT0 = 1<<04, // TABT bit of Descriptor 0
- TSAD_OWN3 = 1<<03, // OWN bit of Descriptor 3
- TSAD_OWN2 = 1<<02, // OWN bit of Descriptor 2
- TSAD_OWN1 = 1<<01, // OWN bit of Descriptor 1
- TSAD_OWN0 = 1<<00, // OWN bit of Descriptor 0
-};
-
-
-/* Bits in Config1 */
-enum Config1Bits {
- Cfg1_PM_Enable = 0x01,
- Cfg1_VPD_Enable = 0x02,
- Cfg1_PIO = 0x04,
- Cfg1_MMIO = 0x08,
- LWAKE = 0x10, /* not on 8139, 8139A */
- Cfg1_Driver_Load = 0x20,
- Cfg1_LED0 = 0x40,
- Cfg1_LED1 = 0x80,
- SLEEP = (1 << 1), /* only on 8139, 8139A */
- PWRDN = (1 << 0), /* only on 8139, 8139A */
-};
-
-/* Bits in Config3 */
-enum Config3Bits {
- Cfg3_FBtBEn = (1 << 0), /* 1 = Fast Back to Back */
- Cfg3_FuncRegEn = (1 << 1), /* 1 = enable CardBus Function registers */
- Cfg3_CLKRUN_En = (1 << 2), /* 1 = enable CLKRUN */
- Cfg3_CardB_En = (1 << 3), /* 1 = enable CardBus registers */
- Cfg3_LinkUp = (1 << 4), /* 1 = wake up on link up */
- Cfg3_Magic = (1 << 5), /* 1 = wake up on Magic Packet (tm) */
- Cfg3_PARM_En = (1 << 6), /* 0 = software can set twister parameters */
- Cfg3_GNTSel = (1 << 7), /* 1 = delay 1 clock from PCI GNT signal */
-};
-
-/* Bits in Config4 */
-enum Config4Bits {
- LWPTN = (1 << 2), /* not on 8139, 8139A */
-};
-
-/* Bits in Config5 */
-enum Config5Bits {
- Cfg5_PME_STS = (1 << 0), /* 1 = PCI reset resets PME_Status */
- Cfg5_LANWake = (1 << 1), /* 1 = enable LANWake signal */
- Cfg5_LDPS = (1 << 2), /* 0 = save power when link is down */
- Cfg5_FIFOAddrPtr = (1 << 3), /* Realtek internal SRAM testing */
- Cfg5_UWF = (1 << 4), /* 1 = accept unicast wakeup frame */
- Cfg5_MWF = (1 << 5), /* 1 = accept multicast wakeup frame */
- Cfg5_BWF = (1 << 6), /* 1 = accept broadcast wakeup frame */
-};
-
-enum RxConfigBits {
- /* rx fifo threshold */
- RxCfgFIFOShift = 13,
- RxCfgFIFONone = (7 << RxCfgFIFOShift),
-
- /* Max DMA burst */
- RxCfgDMAShift = 8,
- RxCfgDMAUnlimited = (7 << RxCfgDMAShift),
-
- /* rx ring buffer length */
- RxCfgRcv8K = 0,
- RxCfgRcv16K = (1 << 11),
- RxCfgRcv32K = (1 << 12),
- RxCfgRcv64K = (1 << 11) | (1 << 12),
-
- /* Disable packet wrap at end of Rx buffer. (not possible with 64k) */
- RxNoWrap = (1 << 7),
-};
-
-/* Twister tuning parameters from RealTek.
- Completely undocumented, but required to tune bad links on some boards. */
-/*
-enum CSCRBits {
- CSCR_LinkOKBit = 0x0400,
- CSCR_LinkChangeBit = 0x0800,
- CSCR_LinkStatusBits = 0x0f000,
- CSCR_LinkDownOffCmd = 0x003c0,
- CSCR_LinkDownCmd = 0x0f3c0,
-*/
-enum CSCRBits {
- CSCR_Testfun = 1<<15, /* 1 = Auto-neg speeds up internal timer, WO, def 0 */
- CSCR_LD = 1<<9, /* Active low TPI link disable signal. When low, TPI still transmits link pulses and TPI stays in good link state. def 1*/
- CSCR_HEART_BIT = 1<<8, /* 1 = HEART BEAT enable, 0 = HEART BEAT disable. HEART BEAT function is only valid in 10Mbps mode. def 1*/
- CSCR_JBEN = 1<<7, /* 1 = enable jabber function. 0 = disable jabber function, def 1*/
- CSCR_F_LINK_100 = 1<<6, /* Used to login force good link in 100Mbps for diagnostic purposes. 1 = DISABLE, 0 = ENABLE. def 1*/
- CSCR_F_Connect = 1<<5, /* Assertion of this bit forces the disconnect function to be bypassed. def 0*/
- CSCR_Con_status = 1<<3, /* This bit indicates the status of the connection. 1 = valid connected link detected; 0 = disconnected link detected. RO def 0*/
- CSCR_Con_status_En = 1<<2, /* Assertion of this bit configures LED1 pin to indicate connection status. def 0*/
- CSCR_PASS_SCR = 1<<0, /* Bypass Scramble, def 0*/
-};
-
-enum Cfg9346Bits {
- Cfg9346_Normal = 0x00,
- Cfg9346_Autoload = 0x40,
- Cfg9346_Programming = 0x80,
- Cfg9346_ConfigWrite = 0xC0,
-};
-
-typedef enum {
- CH_8139 = 0,
- CH_8139_K,
- CH_8139A,
- CH_8139A_G,
- CH_8139B,
- CH_8130,
- CH_8139C,
- CH_8100,
- CH_8100B_8139D,
- CH_8101,
-} chip_t;
-
-enum chip_flags {
- HasHltClk = (1 << 0),
- HasLWake = (1 << 1),
-};
-
-#define HW_REVID(b30, b29, b28, b27, b26, b23, b22) \
- (b30<<30 | b29<<29 | b28<<28 | b27<<27 | b26<<26 | b23<<23 | b22<<22)
-#define HW_REVID_MASK HW_REVID(1, 1, 1, 1, 1, 1, 1)
-
-#define RTL8139_PCI_REVID_8139 0x10
-#define RTL8139_PCI_REVID_8139CPLUS 0x20
-
-#define RTL8139_PCI_REVID RTL8139_PCI_REVID_8139CPLUS
-
-/* Size is 64 * 16bit words */
-#define EEPROM_9346_ADDR_BITS 6
-#define EEPROM_9346_SIZE (1 << EEPROM_9346_ADDR_BITS)
-#define EEPROM_9346_ADDR_MASK (EEPROM_9346_SIZE - 1)
-
-enum Chip9346Operation
-{
- Chip9346_op_mask = 0xc0, /* 10 zzzzzz */
- Chip9346_op_read = 0x80, /* 10 AAAAAA */
- Chip9346_op_write = 0x40, /* 01 AAAAAA D(15)..D(0) */
- Chip9346_op_ext_mask = 0xf0, /* 11 zzzzzz */
- Chip9346_op_write_enable = 0x30, /* 00 11zzzz */
- Chip9346_op_write_all = 0x10, /* 00 01zzzz */
- Chip9346_op_write_disable = 0x00, /* 00 00zzzz */
-};
-
-enum Chip9346Mode
-{
- Chip9346_none = 0,
- Chip9346_enter_command_mode,
- Chip9346_read_command,
- Chip9346_data_read, /* from output register */
- Chip9346_data_write, /* to input register, then to contents at specified address */
- Chip9346_data_write_all, /* to input register, then filling contents */
-};
-
-typedef struct EEprom9346
-{
- uint16_t contents[EEPROM_9346_SIZE];
- int mode;
- uint32_t tick;
- uint8_t address;
- uint16_t input;
- uint16_t output;
-
- uint8_t eecs;
- uint8_t eesk;
- uint8_t eedi;
- uint8_t eedo;
-} EEprom9346;
-
-typedef struct RTL8139TallyCounters
-{
- /* Tally counters */
- uint64_t TxOk;
- uint64_t RxOk;
- uint64_t TxERR;
- uint32_t RxERR;
- uint16_t MissPkt;
- uint16_t FAE;
- uint32_t Tx1Col;
- uint32_t TxMCol;
- uint64_t RxOkPhy;
- uint64_t RxOkBrd;
- uint32_t RxOkMul;
- uint16_t TxAbt;
- uint16_t TxUndrn;
-} RTL8139TallyCounters;
-
-/* Clears all tally counters */
-static void RTL8139TallyCounters_clear(RTL8139TallyCounters* counters);
-
-typedef struct RTL8139State {
- /*< private >*/
- PCIDevice parent_obj;
- /*< public >*/
-
- uint8_t phys[8]; /* mac address */
- uint8_t mult[8]; /* multicast mask array */
-
- uint32_t TxStatus[4]; /* TxStatus0 in C mode*/ /* also DTCCR[0] and DTCCR[1] in C+ mode */
- uint32_t TxAddr[4]; /* TxAddr0 */
- uint32_t RxBuf; /* Receive buffer */
- uint32_t RxBufferSize;/* internal variable, receive ring buffer size in C mode */
- uint32_t RxBufPtr;
- uint32_t RxBufAddr;
-
- uint16_t IntrStatus;
- uint16_t IntrMask;
-
- uint32_t TxConfig;
- uint32_t RxConfig;
- uint32_t RxMissed;
-
- uint16_t CSCR;
-
- uint8_t Cfg9346;
- uint8_t Config0;
- uint8_t Config1;
- uint8_t Config3;
- uint8_t Config4;
- uint8_t Config5;
-
- uint8_t clock_enabled;
- uint8_t bChipCmdState;
-
- uint16_t MultiIntr;
-
- uint16_t BasicModeCtrl;
- uint16_t BasicModeStatus;
- uint16_t NWayAdvert;
- uint16_t NWayLPAR;
- uint16_t NWayExpansion;
-
- uint16_t CpCmd;
- uint8_t TxThresh;
-
- NICState *nic;
- NICConf conf;
-
- /* C ring mode */
- uint32_t currTxDesc;
-
- /* C+ mode */
- uint32_t cplus_enabled;
-
- uint32_t currCPlusRxDesc;
- uint32_t currCPlusTxDesc;
-
- uint32_t RxRingAddrLO;
- uint32_t RxRingAddrHI;
-
- EEprom9346 eeprom;
-
- uint32_t TCTR;
- uint32_t TimerInt;
- int64_t TCTR_base;
-
- /* Tally counters */
- RTL8139TallyCounters tally_counters;
-
- /* Non-persistent data */
- uint8_t *cplus_txbuffer;
- int cplus_txbuffer_len;
- int cplus_txbuffer_offset;
-
- /* PCI interrupt timer */
- QEMUTimer *timer;
-
- MemoryRegion bar_io;
- MemoryRegion bar_mem;
-
- /* Support migration to/from old versions */
- int rtl8139_mmio_io_addr_dummy;
-} RTL8139State;
-
-/* Writes tally counters to memory via DMA */
-static void RTL8139TallyCounters_dma_write(RTL8139State *s, dma_addr_t tc_addr);
-
-static void rtl8139_set_next_tctr_time(RTL8139State *s);
-
-static void prom9346_decode_command(EEprom9346 *eeprom, uint8_t command)
-{
- DPRINTF("eeprom command 0x%02x\n", command);
-
- switch (command & Chip9346_op_mask)
- {
- case Chip9346_op_read:
- {
- eeprom->address = command & EEPROM_9346_ADDR_MASK;
- eeprom->output = eeprom->contents[eeprom->address];
- eeprom->eedo = 0;
- eeprom->tick = 0;
- eeprom->mode = Chip9346_data_read;
- DPRINTF("eeprom read from address 0x%02x data=0x%04x\n",
- eeprom->address, eeprom->output);
- }
- break;
-
- case Chip9346_op_write:
- {
- eeprom->address = command & EEPROM_9346_ADDR_MASK;
- eeprom->input = 0;
- eeprom->tick = 0;
- eeprom->mode = Chip9346_none; /* Chip9346_data_write */
- DPRINTF("eeprom begin write to address 0x%02x\n",
- eeprom->address);
- }
- break;
- default:
- eeprom->mode = Chip9346_none;
- switch (command & Chip9346_op_ext_mask)
- {
- case Chip9346_op_write_enable:
- DPRINTF("eeprom write enabled\n");
- break;
- case Chip9346_op_write_all:
- DPRINTF("eeprom begin write all\n");
- break;
- case Chip9346_op_write_disable:
- DPRINTF("eeprom write disabled\n");
- break;
- }
- break;
- }
-}
-
-static void prom9346_shift_clock(EEprom9346 *eeprom)
-{
- int bit = eeprom->eedi?1:0;
-
- ++ eeprom->tick;
-
- DPRINTF("eeprom: tick %d eedi=%d eedo=%d\n", eeprom->tick, eeprom->eedi,
- eeprom->eedo);
-
- switch (eeprom->mode)
- {
- case Chip9346_enter_command_mode:
- if (bit)
- {
- eeprom->mode = Chip9346_read_command;
- eeprom->tick = 0;
- eeprom->input = 0;
- DPRINTF("eeprom: +++ synchronized, begin command read\n");
- }
- break;
-
- case Chip9346_read_command:
- eeprom->input = (eeprom->input << 1) | (bit & 1);
- if (eeprom->tick == 8)
- {
- prom9346_decode_command(eeprom, eeprom->input & 0xff);
- }
- break;
-
- case Chip9346_data_read:
- eeprom->eedo = (eeprom->output & 0x8000)?1:0;
- eeprom->output <<= 1;
- if (eeprom->tick == 16)
- {
-#if 1
- // the FreeBSD drivers (rl and re) don't explicitly toggle
- // CS between reads (or does setting Cfg9346 to 0 count too?),
- // so we need to enter wait-for-command state here
- eeprom->mode = Chip9346_enter_command_mode;
- eeprom->input = 0;
- eeprom->tick = 0;
-
- DPRINTF("eeprom: +++ end of read, awaiting next command\n");
-#else
- // original behaviour
- ++eeprom->address;
- eeprom->address &= EEPROM_9346_ADDR_MASK;
- eeprom->output = eeprom->contents[eeprom->address];
- eeprom->tick = 0;
-
- DPRINTF("eeprom: +++ read next address 0x%02x data=0x%04x\n",
- eeprom->address, eeprom->output);
-#endif
- }
- break;
-
- case Chip9346_data_write:
- eeprom->input = (eeprom->input << 1) | (bit & 1);
- if (eeprom->tick == 16)
- {
- DPRINTF("eeprom write to address 0x%02x data=0x%04x\n",
- eeprom->address, eeprom->input);
-
- eeprom->contents[eeprom->address] = eeprom->input;
- eeprom->mode = Chip9346_none; /* waiting for next command after CS cycle */
- eeprom->tick = 0;
- eeprom->input = 0;
- }
- break;
-
- case Chip9346_data_write_all:
- eeprom->input = (eeprom->input << 1) | (bit & 1);
- if (eeprom->tick == 16)
- {
- int i;
- for (i = 0; i < EEPROM_9346_SIZE; i++)
- {
- eeprom->contents[i] = eeprom->input;
- }
- DPRINTF("eeprom filled with data=0x%04x\n", eeprom->input);
-
- eeprom->mode = Chip9346_enter_command_mode;
- eeprom->tick = 0;
- eeprom->input = 0;
- }
- break;
-
- default:
- break;
- }
-}
-
-static int prom9346_get_wire(RTL8139State *s)
-{
- EEprom9346 *eeprom = &s->eeprom;
- if (!eeprom->eecs)
- return 0;
-
- return eeprom->eedo;
-}
-
-/* FIXME: This should be merged into/replaced by eeprom93xx.c. */
-static void prom9346_set_wire(RTL8139State *s, int eecs, int eesk, int eedi)
-{
- EEprom9346 *eeprom = &s->eeprom;
- uint8_t old_eecs = eeprom->eecs;
- uint8_t old_eesk = eeprom->eesk;
-
- eeprom->eecs = eecs;
- eeprom->eesk = eesk;
- eeprom->eedi = eedi;
-
- DPRINTF("eeprom: +++ wires CS=%d SK=%d DI=%d DO=%d\n", eeprom->eecs,
- eeprom->eesk, eeprom->eedi, eeprom->eedo);
-
- if (!old_eecs && eecs)
- {
- /* Synchronize start */
- eeprom->tick = 0;
- eeprom->input = 0;
- eeprom->output = 0;
- eeprom->mode = Chip9346_enter_command_mode;
-
- DPRINTF("=== eeprom: begin access, enter command mode\n");
- }
-
- if (!eecs)
- {
- DPRINTF("=== eeprom: end access\n");
- return;
- }
-
- if (!old_eesk && eesk)
- {
- /* SK front rules */
- prom9346_shift_clock(eeprom);
- }
-}
-
-static void rtl8139_update_irq(RTL8139State *s)
-{
- PCIDevice *d = PCI_DEVICE(s);
- int isr;
- isr = (s->IntrStatus & s->IntrMask) & 0xffff;
-
- DPRINTF("Set IRQ to %d (%04x %04x)\n", isr ? 1 : 0, s->IntrStatus,
- s->IntrMask);
-
- pci_set_irq(d, (isr != 0));
-}
-
-static int rtl8139_RxWrap(RTL8139State *s)
-{
- /* wrapping enabled; assume 1.5k more buffer space if size < 65536 */
- return (s->RxConfig & (1 << 7));
-}
-
-static int rtl8139_receiver_enabled(RTL8139State *s)
-{
- return s->bChipCmdState & CmdRxEnb;
-}
-
-static int rtl8139_transmitter_enabled(RTL8139State *s)
-{
- return s->bChipCmdState & CmdTxEnb;
-}
-
-static int rtl8139_cp_receiver_enabled(RTL8139State *s)
-{
- return s->CpCmd & CPlusRxEnb;
-}
-
-static int rtl8139_cp_transmitter_enabled(RTL8139State *s)
-{
- return s->CpCmd & CPlusTxEnb;
-}
-
-static void rtl8139_write_buffer(RTL8139State *s, const void *buf, int size)
-{
- PCIDevice *d = PCI_DEVICE(s);
-
- if (s->RxBufAddr + size > s->RxBufferSize)
- {
- int wrapped = MOD2(s->RxBufAddr + size, s->RxBufferSize);
-
- /* write packet data */
- if (wrapped && !(s->RxBufferSize < 65536 && rtl8139_RxWrap(s)))
- {
- DPRINTF(">>> rx packet wrapped in buffer at %d\n", size - wrapped);
-
- if (size > wrapped)
- {
- pci_dma_write(d, s->RxBuf + s->RxBufAddr,
- buf, size-wrapped);
- }
-
- /* reset buffer pointer */
- s->RxBufAddr = 0;
-
- pci_dma_write(d, s->RxBuf + s->RxBufAddr,
- buf + (size-wrapped), wrapped);
-
- s->RxBufAddr = wrapped;
-
- return;
- }
- }
-
- /* non-wrapping path or overwrapping enabled */
- pci_dma_write(d, s->RxBuf + s->RxBufAddr, buf, size);
-
- s->RxBufAddr += size;
-}
-
-#define MIN_BUF_SIZE 60
-static inline dma_addr_t rtl8139_addr64(uint32_t low, uint32_t high)
-{
- return low | ((uint64_t)high << 32);
-}
-
-/* Workaround for buggy guest driver such as linux who allocates rx
- * rings after the receiver were enabled. */
-static bool rtl8139_cp_rx_valid(RTL8139State *s)
-{
- return !(s->RxRingAddrLO == 0 && s->RxRingAddrHI == 0);
-}
-
-static int rtl8139_can_receive(NetClientState *nc)
-{
- RTL8139State *s = qemu_get_nic_opaque(nc);
- int avail;
-
- /* Receive (drop) packets if card is disabled. */
- if (!s->clock_enabled)
- return 1;
- if (!rtl8139_receiver_enabled(s))
- return 1;
-
- if (rtl8139_cp_receiver_enabled(s) && rtl8139_cp_rx_valid(s)) {
- /* ??? Flow control not implemented in c+ mode.
- This is a hack to work around slirp deficiencies anyway. */
- return 1;
- } else {
- avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr,
- s->RxBufferSize);
- return (avail == 0 || avail >= 1514 || (s->IntrMask & RxOverflow));
- }
-}
-
-static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t size_, int do_interrupt)
-{
- RTL8139State *s = qemu_get_nic_opaque(nc);
- PCIDevice *d = PCI_DEVICE(s);
- /* size is the length of the buffer passed to the driver */
- int size = size_;
- const uint8_t *dot1q_buf = NULL;
-
- uint32_t packet_header = 0;
-
- uint8_t buf1[MIN_BUF_SIZE + VLAN_HLEN];
- static const uint8_t broadcast_macaddr[6] =
- { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-
- DPRINTF(">>> received len=%d\n", size);
-
- /* test if board clock is stopped */
- if (!s->clock_enabled)
- {
- DPRINTF("stopped ==========================\n");
- return -1;
- }
-
- /* first check if receiver is enabled */
-
- if (!rtl8139_receiver_enabled(s))
- {
- DPRINTF("receiver disabled ================\n");
- return -1;
- }
-
- /* XXX: check this */
- if (s->RxConfig & AcceptAllPhys) {
- /* promiscuous: receive all */
- DPRINTF(">>> packet received in promiscuous mode\n");
-
- } else {
- if (!memcmp(buf, broadcast_macaddr, 6)) {
- /* broadcast address */
- if (!(s->RxConfig & AcceptBroadcast))
- {
- DPRINTF(">>> broadcast packet rejected\n");
-
- /* update tally counter */
- ++s->tally_counters.RxERR;
-
- return size;
- }
-
- packet_header |= RxBroadcast;
-
- DPRINTF(">>> broadcast packet received\n");
-
- /* update tally counter */
- ++s->tally_counters.RxOkBrd;
-
- } else if (buf[0] & 0x01) {
- /* multicast */
- if (!(s->RxConfig & AcceptMulticast))
- {
- DPRINTF(">>> multicast packet rejected\n");
-
- /* update tally counter */
- ++s->tally_counters.RxERR;
-
- return size;
- }
-
- int mcast_idx = compute_mcast_idx(buf);
-
- if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))))
- {
- DPRINTF(">>> multicast address mismatch\n");
-
- /* update tally counter */
- ++s->tally_counters.RxERR;
-
- return size;
- }
-
- packet_header |= RxMulticast;
-
- DPRINTF(">>> multicast packet received\n");
-
- /* update tally counter */
- ++s->tally_counters.RxOkMul;
-
- } else if (s->phys[0] == buf[0] &&
- s->phys[1] == buf[1] &&
- s->phys[2] == buf[2] &&
- s->phys[3] == buf[3] &&
- s->phys[4] == buf[4] &&
- s->phys[5] == buf[5]) {
- /* match */
- if (!(s->RxConfig & AcceptMyPhys))
- {
- DPRINTF(">>> rejecting physical address matching packet\n");
-
- /* update tally counter */
- ++s->tally_counters.RxERR;
-
- return size;
- }
-
- packet_header |= RxPhysical;
-
- DPRINTF(">>> physical address matching packet received\n");
-
- /* update tally counter */
- ++s->tally_counters.RxOkPhy;
-
- } else {
-
- DPRINTF(">>> unknown packet\n");
-
- /* update tally counter */
- ++s->tally_counters.RxERR;
-
- return size;
- }
- }
-
- /* if too small buffer, then expand it
- * Include some tailroom in case a vlan tag is later removed. */
- if (size < MIN_BUF_SIZE + VLAN_HLEN) {
- memcpy(buf1, buf, size);
- memset(buf1 + size, 0, MIN_BUF_SIZE + VLAN_HLEN - size);
- buf = buf1;
- if (size < MIN_BUF_SIZE) {
- size = MIN_BUF_SIZE;
- }
- }
-
- if (rtl8139_cp_receiver_enabled(s))
- {
- if (!rtl8139_cp_rx_valid(s)) {
- return size;
- }
-
- DPRINTF("in C+ Rx mode ================\n");
-
- /* begin C+ receiver mode */
-
-/* w0 ownership flag */
-#define CP_RX_OWN (1<<31)
-/* w0 end of ring flag */
-#define CP_RX_EOR (1<<30)
-/* w0 bits 0...12 : buffer size */
-#define CP_RX_BUFFER_SIZE_MASK ((1<<13) - 1)
-/* w1 tag available flag */
-#define CP_RX_TAVA (1<<16)
-/* w1 bits 0...15 : VLAN tag */
-#define CP_RX_VLAN_TAG_MASK ((1<<16) - 1)
-/* w2 low 32bit of Rx buffer ptr */
-/* w3 high 32bit of Rx buffer ptr */
-
- int descriptor = s->currCPlusRxDesc;
- dma_addr_t cplus_rx_ring_desc;
-
- cplus_rx_ring_desc = rtl8139_addr64(s->RxRingAddrLO, s->RxRingAddrHI);
- cplus_rx_ring_desc += 16 * descriptor;
-
- DPRINTF("+++ C+ mode reading RX descriptor %d from host memory at "
- "%08x %08x = "DMA_ADDR_FMT"\n", descriptor, s->RxRingAddrHI,
- s->RxRingAddrLO, cplus_rx_ring_desc);
-
- uint32_t val, rxdw0,rxdw1,rxbufLO,rxbufHI;
-
- pci_dma_read(d, cplus_rx_ring_desc, &val, 4);
- rxdw0 = le32_to_cpu(val);
- pci_dma_read(d, cplus_rx_ring_desc+4, &val, 4);
- rxdw1 = le32_to_cpu(val);
- pci_dma_read(d, cplus_rx_ring_desc+8, &val, 4);
- rxbufLO = le32_to_cpu(val);
- pci_dma_read(d, cplus_rx_ring_desc+12, &val, 4);
- rxbufHI = le32_to_cpu(val);
-
- DPRINTF("+++ C+ mode RX descriptor %d %08x %08x %08x %08x\n",
- descriptor, rxdw0, rxdw1, rxbufLO, rxbufHI);
-
- if (!(rxdw0 & CP_RX_OWN))
- {
- DPRINTF("C+ Rx mode : descriptor %d is owned by host\n",
- descriptor);
-
- s->IntrStatus |= RxOverflow;
- ++s->RxMissed;
-
- /* update tally counter */
- ++s->tally_counters.RxERR;
- ++s->tally_counters.MissPkt;
-
- rtl8139_update_irq(s);
- return size_;
- }
-
- uint32_t rx_space = rxdw0 & CP_RX_BUFFER_SIZE_MASK;
-
- /* write VLAN info to descriptor variables. */
- if (s->CpCmd & CPlusRxVLAN && be16_to_cpup((uint16_t *)
- &buf[ETH_ALEN * 2]) == ETH_P_VLAN) {
- dot1q_buf = &buf[ETH_ALEN * 2];
- size -= VLAN_HLEN;
- /* if too small buffer, use the tailroom added duing expansion */
- if (size < MIN_BUF_SIZE) {
- size = MIN_BUF_SIZE;
- }
-
- rxdw1 &= ~CP_RX_VLAN_TAG_MASK;
- /* BE + ~le_to_cpu()~ + cpu_to_le() = BE */
- rxdw1 |= CP_RX_TAVA | le16_to_cpup((uint16_t *)
- &dot1q_buf[ETHER_TYPE_LEN]);
-
- DPRINTF("C+ Rx mode : extracted vlan tag with tci: ""%u\n",
- be16_to_cpup((uint16_t *)&dot1q_buf[ETHER_TYPE_LEN]));
- } else {
- /* reset VLAN tag flag */
- rxdw1 &= ~CP_RX_TAVA;
- }
-
- /* TODO: scatter the packet over available receive ring descriptors space */
-
- if (size+4 > rx_space)
- {
- DPRINTF("C+ Rx mode : descriptor %d size %d received %d + 4\n",
- descriptor, rx_space, size);
-
- s->IntrStatus |= RxOverflow;
- ++s->RxMissed;
-
- /* update tally counter */
- ++s->tally_counters.RxERR;
- ++s->tally_counters.MissPkt;
-
- rtl8139_update_irq(s);
- return size_;
- }
-
- dma_addr_t rx_addr = rtl8139_addr64(rxbufLO, rxbufHI);
-
- /* receive/copy to target memory */
- if (dot1q_buf) {
- pci_dma_write(d, rx_addr, buf, 2 * ETH_ALEN);
- pci_dma_write(d, rx_addr + 2 * ETH_ALEN,
- buf + 2 * ETH_ALEN + VLAN_HLEN,
- size - 2 * ETH_ALEN);
- } else {
- pci_dma_write(d, rx_addr, buf, size);
- }
-
- if (s->CpCmd & CPlusRxChkSum)
- {
- /* do some packet checksumming */
- }
-
- /* write checksum */
- val = cpu_to_le32(crc32(0, buf, size_));
- pci_dma_write(d, rx_addr+size, (uint8_t *)&val, 4);
-
-/* first segment of received packet flag */
-#define CP_RX_STATUS_FS (1<<29)
-/* last segment of received packet flag */
-#define CP_RX_STATUS_LS (1<<28)
-/* multicast packet flag */
-#define CP_RX_STATUS_MAR (1<<26)
-/* physical-matching packet flag */
-#define CP_RX_STATUS_PAM (1<<25)
-/* broadcast packet flag */
-#define CP_RX_STATUS_BAR (1<<24)
-/* runt packet flag */
-#define CP_RX_STATUS_RUNT (1<<19)
-/* crc error flag */
-#define CP_RX_STATUS_CRC (1<<18)
-/* IP checksum error flag */
-#define CP_RX_STATUS_IPF (1<<15)
-/* UDP checksum error flag */
-#define CP_RX_STATUS_UDPF (1<<14)
-/* TCP checksum error flag */
-#define CP_RX_STATUS_TCPF (1<<13)
-
- /* transfer ownership to target */
- rxdw0 &= ~CP_RX_OWN;
-
- /* set first segment bit */
- rxdw0 |= CP_RX_STATUS_FS;
-
- /* set last segment bit */
- rxdw0 |= CP_RX_STATUS_LS;
-
- /* set received packet type flags */
- if (packet_header & RxBroadcast)
- rxdw0 |= CP_RX_STATUS_BAR;
- if (packet_header & RxMulticast)
- rxdw0 |= CP_RX_STATUS_MAR;
- if (packet_header & RxPhysical)
- rxdw0 |= CP_RX_STATUS_PAM;
-
- /* set received size */
- rxdw0 &= ~CP_RX_BUFFER_SIZE_MASK;
- rxdw0 |= (size+4);
-
- /* update ring data */
- val = cpu_to_le32(rxdw0);
- pci_dma_write(d, cplus_rx_ring_desc, (uint8_t *)&val, 4);
- val = cpu_to_le32(rxdw1);
- pci_dma_write(d, cplus_rx_ring_desc+4, (uint8_t *)&val, 4);
-
- /* update tally counter */
- ++s->tally_counters.RxOk;
-
- /* seek to next Rx descriptor */
- if (rxdw0 & CP_RX_EOR)
- {
- s->currCPlusRxDesc = 0;
- }
- else
- {
- ++s->currCPlusRxDesc;
- }
-
- DPRINTF("done C+ Rx mode ----------------\n");
-
- }
- else
- {
- DPRINTF("in ring Rx mode ================\n");
-
- /* begin ring receiver mode */
- int avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr, s->RxBufferSize);
-
- /* if receiver buffer is empty then avail == 0 */
-
-#define RX_ALIGN(x) (((x) + 3) & ~0x3)
-
- if (avail != 0 && RX_ALIGN(size + 8) >= avail)
- {
- DPRINTF("rx overflow: rx buffer length %d head 0x%04x "
- "read 0x%04x === available 0x%04x need 0x%04x\n",
- s->RxBufferSize, s->RxBufAddr, s->RxBufPtr, avail, size + 8);
-
- s->IntrStatus |= RxOverflow;
- ++s->RxMissed;
- rtl8139_update_irq(s);
- return 0;
- }
-
- packet_header |= RxStatusOK;
-
- packet_header |= (((size+4) << 16) & 0xffff0000);
-
- /* write header */
- uint32_t val = cpu_to_le32(packet_header);
-
- rtl8139_write_buffer(s, (uint8_t *)&val, 4);
-
- rtl8139_write_buffer(s, buf, size);
-
- /* write checksum */
- val = cpu_to_le32(crc32(0, buf, size));
- rtl8139_write_buffer(s, (uint8_t *)&val, 4);
-
- /* correct buffer write pointer */
- s->RxBufAddr = MOD2(RX_ALIGN(s->RxBufAddr), s->RxBufferSize);
-
- /* now we can signal we have received something */
-
- DPRINTF("received: rx buffer length %d head 0x%04x read 0x%04x\n",
- s->RxBufferSize, s->RxBufAddr, s->RxBufPtr);
- }
-
- s->IntrStatus |= RxOK;
-
- if (do_interrupt)
- {
- rtl8139_update_irq(s);
- }
-
- return size_;
-}
-
-static ssize_t rtl8139_receive(NetClientState *nc, const uint8_t *buf, size_t size)
-{
- return rtl8139_do_receive(nc, buf, size, 1);
-}
-
-static void rtl8139_reset_rxring(RTL8139State *s, uint32_t bufferSize)
-{
- s->RxBufferSize = bufferSize;
- s->RxBufPtr = 0;
- s->RxBufAddr = 0;
-}
-
-static void rtl8139_reset(DeviceState *d)
-{
- RTL8139State *s = RTL8139(d);
- int i;
-
- /* restore MAC address */
- memcpy(s->phys, s->conf.macaddr.a, 6);
- qemu_format_nic_info_str(qemu_get_queue(s->nic), s->phys);
-
- /* reset interrupt mask */
- s->IntrStatus = 0;
- s->IntrMask = 0;
-
- rtl8139_update_irq(s);
-
- /* mark all status registers as owned by host */
- for (i = 0; i < 4; ++i)
- {
- s->TxStatus[i] = TxHostOwns;
- }
-
- s->currTxDesc = 0;
- s->currCPlusRxDesc = 0;
- s->currCPlusTxDesc = 0;
-
- s->RxRingAddrLO = 0;
- s->RxRingAddrHI = 0;
-
- s->RxBuf = 0;
-
- rtl8139_reset_rxring(s, 8192);
-
- /* ACK the reset */
- s->TxConfig = 0;
-
-#if 0
-// s->TxConfig |= HW_REVID(1, 0, 0, 0, 0, 0, 0); // RTL-8139 HasHltClk
- s->clock_enabled = 0;
-#else
- s->TxConfig |= HW_REVID(1, 1, 1, 0, 1, 1, 0); // RTL-8139C+ HasLWake
- s->clock_enabled = 1;
-#endif
-
- s->bChipCmdState = CmdReset; /* RxBufEmpty bit is calculated on read from ChipCmd */;
-
- /* set initial state data */
- s->Config0 = 0x0; /* No boot ROM */
- s->Config1 = 0xC; /* IO mapped and MEM mapped registers available */
- s->Config3 = 0x1; /* fast back-to-back compatible */
- s->Config5 = 0x0;
-
- s->CSCR = CSCR_F_LINK_100 | CSCR_HEART_BIT | CSCR_LD;
-
- s->CpCmd = 0x0; /* reset C+ mode */
- s->cplus_enabled = 0;
-
-
-// s->BasicModeCtrl = 0x3100; // 100Mbps, full duplex, autonegotiation
-// s->BasicModeCtrl = 0x2100; // 100Mbps, full duplex
- s->BasicModeCtrl = 0x1000; // autonegotiation
-
- s->BasicModeStatus = 0x7809;
- //s->BasicModeStatus |= 0x0040; /* UTP medium */
- s->BasicModeStatus |= 0x0020; /* autonegotiation completed */
- /* preserve link state */
- s->BasicModeStatus |= qemu_get_queue(s->nic)->link_down ? 0 : 0x04;
-
- s->NWayAdvert = 0x05e1; /* all modes, full duplex */
- s->NWayLPAR = 0x05e1; /* all modes, full duplex */
- s->NWayExpansion = 0x0001; /* autonegotiation supported */
-
- /* also reset timer and disable timer interrupt */
- s->TCTR = 0;
- s->TimerInt = 0;
- s->TCTR_base = 0;
- rtl8139_set_next_tctr_time(s);
-
- /* reset tally counters */
- RTL8139TallyCounters_clear(&s->tally_counters);
-}
-
-static void RTL8139TallyCounters_clear(RTL8139TallyCounters* counters)
-{
- counters->TxOk = 0;
- counters->RxOk = 0;
- counters->TxERR = 0;
- counters->RxERR = 0;
- counters->MissPkt = 0;
- counters->FAE = 0;
- counters->Tx1Col = 0;
- counters->TxMCol = 0;
- counters->RxOkPhy = 0;
- counters->RxOkBrd = 0;
- counters->RxOkMul = 0;
- counters->TxAbt = 0;
- counters->TxUndrn = 0;
-}
-
-static void RTL8139TallyCounters_dma_write(RTL8139State *s, dma_addr_t tc_addr)
-{
- PCIDevice *d = PCI_DEVICE(s);
- RTL8139TallyCounters *tally_counters = &s->tally_counters;
- uint16_t val16;
- uint32_t val32;
- uint64_t val64;
-
- val64 = cpu_to_le64(tally_counters->TxOk);
- pci_dma_write(d, tc_addr + 0, (uint8_t *)&val64, 8);
-
- val64 = cpu_to_le64(tally_counters->RxOk);
- pci_dma_write(d, tc_addr + 8, (uint8_t *)&val64, 8);
-
- val64 = cpu_to_le64(tally_counters->TxERR);
- pci_dma_write(d, tc_addr + 16, (uint8_t *)&val64, 8);
-
- val32 = cpu_to_le32(tally_counters->RxERR);
- pci_dma_write(d, tc_addr + 24, (uint8_t *)&val32, 4);
-
- val16 = cpu_to_le16(tally_counters->MissPkt);
- pci_dma_write(d, tc_addr + 28, (uint8_t *)&val16, 2);
-
- val16 = cpu_to_le16(tally_counters->FAE);
- pci_dma_write(d, tc_addr + 30, (uint8_t *)&val16, 2);
-
- val32 = cpu_to_le32(tally_counters->Tx1Col);
- pci_dma_write(d, tc_addr + 32, (uint8_t *)&val32, 4);
-
- val32 = cpu_to_le32(tally_counters->TxMCol);
- pci_dma_write(d, tc_addr + 36, (uint8_t *)&val32, 4);
-
- val64 = cpu_to_le64(tally_counters->RxOkPhy);
- pci_dma_write(d, tc_addr + 40, (uint8_t *)&val64, 8);
-
- val64 = cpu_to_le64(tally_counters->RxOkBrd);
- pci_dma_write(d, tc_addr + 48, (uint8_t *)&val64, 8);
-
- val32 = cpu_to_le32(tally_counters->RxOkMul);
- pci_dma_write(d, tc_addr + 56, (uint8_t *)&val32, 4);
-
- val16 = cpu_to_le16(tally_counters->TxAbt);
- pci_dma_write(d, tc_addr + 60, (uint8_t *)&val16, 2);
-
- val16 = cpu_to_le16(tally_counters->TxUndrn);
- pci_dma_write(d, tc_addr + 62, (uint8_t *)&val16, 2);
-}
-
-/* Loads values of tally counters from VM state file */
-
-static const VMStateDescription vmstate_tally_counters = {
- .name = "tally_counters",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT64(TxOk, RTL8139TallyCounters),
- VMSTATE_UINT64(RxOk, RTL8139TallyCounters),
- VMSTATE_UINT64(TxERR, RTL8139TallyCounters),
- VMSTATE_UINT32(RxERR, RTL8139TallyCounters),
- VMSTATE_UINT16(MissPkt, RTL8139TallyCounters),
- VMSTATE_UINT16(FAE, RTL8139TallyCounters),
- VMSTATE_UINT32(Tx1Col, RTL8139TallyCounters),
- VMSTATE_UINT32(TxMCol, RTL8139TallyCounters),
- VMSTATE_UINT64(RxOkPhy, RTL8139TallyCounters),
- VMSTATE_UINT64(RxOkBrd, RTL8139TallyCounters),
- VMSTATE_UINT16(TxAbt, RTL8139TallyCounters),
- VMSTATE_UINT16(TxUndrn, RTL8139TallyCounters),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void rtl8139_ChipCmd_write(RTL8139State *s, uint32_t val)
-{
- DeviceState *d = DEVICE(s);
-
- val &= 0xff;
-
- DPRINTF("ChipCmd write val=0x%08x\n", val);
-
- if (val & CmdReset)
- {
- DPRINTF("ChipCmd reset\n");
- rtl8139_reset(d);
- }
- if (val & CmdRxEnb)
- {
- DPRINTF("ChipCmd enable receiver\n");
-
- s->currCPlusRxDesc = 0;
- }
- if (val & CmdTxEnb)
- {
- DPRINTF("ChipCmd enable transmitter\n");
-
- s->currCPlusTxDesc = 0;
- }
-
- /* mask unwritable bits */
- val = SET_MASKED(val, 0xe3, s->bChipCmdState);
-
- /* Deassert reset pin before next read */
- val &= ~CmdReset;
-
- s->bChipCmdState = val;
-}
-
-static int rtl8139_RxBufferEmpty(RTL8139State *s)
-{
- int unread = MOD2(s->RxBufferSize + s->RxBufAddr - s->RxBufPtr, s->RxBufferSize);
-
- if (unread != 0)
- {
- DPRINTF("receiver buffer data available 0x%04x\n", unread);
- return 0;
- }
-
- DPRINTF("receiver buffer is empty\n");
-
- return 1;
-}
-
-static uint32_t rtl8139_ChipCmd_read(RTL8139State *s)
-{
- uint32_t ret = s->bChipCmdState;
-
- if (rtl8139_RxBufferEmpty(s))
- ret |= RxBufEmpty;
-
- DPRINTF("ChipCmd read val=0x%04x\n", ret);
-
- return ret;
-}
-
-static void rtl8139_CpCmd_write(RTL8139State *s, uint32_t val)
-{
- val &= 0xffff;
-
- DPRINTF("C+ command register write(w) val=0x%04x\n", val);
-
- s->cplus_enabled = 1;
-
- /* mask unwritable bits */
- val = SET_MASKED(val, 0xff84, s->CpCmd);
-
- s->CpCmd = val;
-}
-
-static uint32_t rtl8139_CpCmd_read(RTL8139State *s)
-{
- uint32_t ret = s->CpCmd;
-
- DPRINTF("C+ command register read(w) val=0x%04x\n", ret);
-
- return ret;
-}
-
-static void rtl8139_IntrMitigate_write(RTL8139State *s, uint32_t val)
-{
- DPRINTF("C+ IntrMitigate register write(w) val=0x%04x\n", val);
-}
-
-static uint32_t rtl8139_IntrMitigate_read(RTL8139State *s)
-{
- uint32_t ret = 0;
-
- DPRINTF("C+ IntrMitigate register read(w) val=0x%04x\n", ret);
-
- return ret;
-}
-
-static int rtl8139_config_writable(RTL8139State *s)
-{
- if ((s->Cfg9346 & Chip9346_op_mask) == Cfg9346_ConfigWrite)
- {
- return 1;
- }
-
- DPRINTF("Configuration registers are write-protected\n");
-
- return 0;
-}
-
-static void rtl8139_BasicModeCtrl_write(RTL8139State *s, uint32_t val)
-{
- val &= 0xffff;
-
- DPRINTF("BasicModeCtrl register write(w) val=0x%04x\n", val);
-
- /* mask unwritable bits */
- uint32_t mask = 0x4cff;
-
- if (1 || !rtl8139_config_writable(s))
- {
- /* Speed setting and autonegotiation enable bits are read-only */
- mask |= 0x3000;
- /* Duplex mode setting is read-only */
- mask |= 0x0100;
- }
-
- val = SET_MASKED(val, mask, s->BasicModeCtrl);
-
- s->BasicModeCtrl = val;
-}
-
-static uint32_t rtl8139_BasicModeCtrl_read(RTL8139State *s)
-{
- uint32_t ret = s->BasicModeCtrl;
-
- DPRINTF("BasicModeCtrl register read(w) val=0x%04x\n", ret);
-
- return ret;
-}
-
-static void rtl8139_BasicModeStatus_write(RTL8139State *s, uint32_t val)
-{
- val &= 0xffff;
-
- DPRINTF("BasicModeStatus register write(w) val=0x%04x\n", val);
-
- /* mask unwritable bits */
- val = SET_MASKED(val, 0xff3f, s->BasicModeStatus);
-
- s->BasicModeStatus = val;
-}
-
-static uint32_t rtl8139_BasicModeStatus_read(RTL8139State *s)
-{
- uint32_t ret = s->BasicModeStatus;
-
- DPRINTF("BasicModeStatus register read(w) val=0x%04x\n", ret);
-
- return ret;
-}
-
-static void rtl8139_Cfg9346_write(RTL8139State *s, uint32_t val)
-{
- DeviceState *d = DEVICE(s);
-
- val &= 0xff;
-
- DPRINTF("Cfg9346 write val=0x%02x\n", val);
-
- /* mask unwritable bits */
- val = SET_MASKED(val, 0x31, s->Cfg9346);
-
- uint32_t opmode = val & 0xc0;
- uint32_t eeprom_val = val & 0xf;
-
- if (opmode == 0x80) {
- /* eeprom access */
- int eecs = (eeprom_val & 0x08)?1:0;
- int eesk = (eeprom_val & 0x04)?1:0;
- int eedi = (eeprom_val & 0x02)?1:0;
- prom9346_set_wire(s, eecs, eesk, eedi);
- } else if (opmode == 0x40) {
- /* Reset. */
- val = 0;
- rtl8139_reset(d);
- }
-
- s->Cfg9346 = val;
-}
-
-static uint32_t rtl8139_Cfg9346_read(RTL8139State *s)
-{
- uint32_t ret = s->Cfg9346;
-
- uint32_t opmode = ret & 0xc0;
-
- if (opmode == 0x80)
- {
- /* eeprom access */
- int eedo = prom9346_get_wire(s);
- if (eedo)
- {
- ret |= 0x01;
- }
- else
- {
- ret &= ~0x01;
- }
- }
-
- DPRINTF("Cfg9346 read val=0x%02x\n", ret);
-
- return ret;
-}
-
-static void rtl8139_Config0_write(RTL8139State *s, uint32_t val)
-{
- val &= 0xff;
-
- DPRINTF("Config0 write val=0x%02x\n", val);
-
- if (!rtl8139_config_writable(s)) {
- return;
- }
-
- /* mask unwritable bits */
- val = SET_MASKED(val, 0xf8, s->Config0);
-
- s->Config0 = val;
-}
-
-static uint32_t rtl8139_Config0_read(RTL8139State *s)
-{
- uint32_t ret = s->Config0;
-
- DPRINTF("Config0 read val=0x%02x\n", ret);
-
- return ret;
-}
-
-static void rtl8139_Config1_write(RTL8139State *s, uint32_t val)
-{
- val &= 0xff;
-
- DPRINTF("Config1 write val=0x%02x\n", val);
-
- if (!rtl8139_config_writable(s)) {
- return;
- }
-
- /* mask unwritable bits */
- val = SET_MASKED(val, 0xC, s->Config1);
-
- s->Config1 = val;
-}
-
-static uint32_t rtl8139_Config1_read(RTL8139State *s)
-{
- uint32_t ret = s->Config1;
-
- DPRINTF("Config1 read val=0x%02x\n", ret);
-
- return ret;
-}
-
-static void rtl8139_Config3_write(RTL8139State *s, uint32_t val)
-{
- val &= 0xff;
-
- DPRINTF("Config3 write val=0x%02x\n", val);
-
- if (!rtl8139_config_writable(s)) {
- return;
- }
-
- /* mask unwritable bits */
- val = SET_MASKED(val, 0x8F, s->Config3);
-
- s->Config3 = val;
-}
-
-static uint32_t rtl8139_Config3_read(RTL8139State *s)
-{
- uint32_t ret = s->Config3;
-
- DPRINTF("Config3 read val=0x%02x\n", ret);
-
- return ret;
-}
-
-static void rtl8139_Config4_write(RTL8139State *s, uint32_t val)
-{
- val &= 0xff;
-
- DPRINTF("Config4 write val=0x%02x\n", val);
-
- if (!rtl8139_config_writable(s)) {
- return;
- }
-
- /* mask unwritable bits */
- val = SET_MASKED(val, 0x0a, s->Config4);
-
- s->Config4 = val;
-}
-
-static uint32_t rtl8139_Config4_read(RTL8139State *s)
-{
- uint32_t ret = s->Config4;
-
- DPRINTF("Config4 read val=0x%02x\n", ret);
-
- return ret;
-}
-
-static void rtl8139_Config5_write(RTL8139State *s, uint32_t val)
-{
- val &= 0xff;
-
- DPRINTF("Config5 write val=0x%02x\n", val);
-
- /* mask unwritable bits */
- val = SET_MASKED(val, 0x80, s->Config5);
-
- s->Config5 = val;
-}
-
-static uint32_t rtl8139_Config5_read(RTL8139State *s)
-{
- uint32_t ret = s->Config5;
-
- DPRINTF("Config5 read val=0x%02x\n", ret);
-
- return ret;
-}
-
-static void rtl8139_TxConfig_write(RTL8139State *s, uint32_t val)
-{
- if (!rtl8139_transmitter_enabled(s))
- {
- DPRINTF("transmitter disabled; no TxConfig write val=0x%08x\n", val);
- return;
- }
-
- DPRINTF("TxConfig write val=0x%08x\n", val);
-
- val = SET_MASKED(val, TxVersionMask | 0x8070f80f, s->TxConfig);
-
- s->TxConfig = val;
-}
-
-static void rtl8139_TxConfig_writeb(RTL8139State *s, uint32_t val)
-{
- DPRINTF("RTL8139C TxConfig via write(b) val=0x%02x\n", val);
-
- uint32_t tc = s->TxConfig;
- tc &= 0xFFFFFF00;
- tc |= (val & 0x000000FF);
- rtl8139_TxConfig_write(s, tc);
-}
-
-static uint32_t rtl8139_TxConfig_read(RTL8139State *s)
-{
- uint32_t ret = s->TxConfig;
-
- DPRINTF("TxConfig read val=0x%04x\n", ret);
-
- return ret;
-}
-
-static void rtl8139_RxConfig_write(RTL8139State *s, uint32_t val)
-{
- DPRINTF("RxConfig write val=0x%08x\n", val);
-
- /* mask unwritable bits */
- val = SET_MASKED(val, 0xf0fc0040, s->RxConfig);
-
- s->RxConfig = val;
-
- /* reset buffer size and read/write pointers */
- rtl8139_reset_rxring(s, 8192 << ((s->RxConfig >> 11) & 0x3));
-
- DPRINTF("RxConfig write reset buffer size to %d\n", s->RxBufferSize);
-}
-
-static uint32_t rtl8139_RxConfig_read(RTL8139State *s)
-{
- uint32_t ret = s->RxConfig;
-
- DPRINTF("RxConfig read val=0x%08x\n", ret);
-
- return ret;
-}
-
-static void rtl8139_transfer_frame(RTL8139State *s, uint8_t *buf, int size,
- int do_interrupt, const uint8_t *dot1q_buf)
-{
- struct iovec *iov = NULL;
- struct iovec vlan_iov[3];
-
- if (!size)
- {
- DPRINTF("+++ empty ethernet frame\n");
- return;
- }
-
- if (dot1q_buf && size >= ETH_ALEN * 2) {
- iov = (struct iovec[3]) {
- { .iov_base = buf, .iov_len = ETH_ALEN * 2 },
- { .iov_base = (void *) dot1q_buf, .iov_len = VLAN_HLEN },
- { .iov_base = buf + ETH_ALEN * 2,
- .iov_len = size - ETH_ALEN * 2 },
- };
-
- memcpy(vlan_iov, iov, sizeof(vlan_iov));
- iov = vlan_iov;
- }
-
- if (TxLoopBack == (s->TxConfig & TxLoopBack))
- {
- size_t buf2_size;
- uint8_t *buf2;
-
- if (iov) {
- buf2_size = iov_size(iov, 3);
- buf2 = g_malloc(buf2_size);
- iov_to_buf(iov, 3, 0, buf2, buf2_size);
- buf = buf2;
- }
-
- DPRINTF("+++ transmit loopback mode\n");
- rtl8139_do_receive(qemu_get_queue(s->nic), buf, size, do_interrupt);
-
- if (iov) {
- g_free(buf2);
- }
- }
- else
- {
- if (iov) {
- qemu_sendv_packet(qemu_get_queue(s->nic), iov, 3);
- } else {
- qemu_send_packet(qemu_get_queue(s->nic), buf, size);
- }
- }
-}
-
-static int rtl8139_transmit_one(RTL8139State *s, int descriptor)
-{
- if (!rtl8139_transmitter_enabled(s))
- {
- DPRINTF("+++ cannot transmit from descriptor %d: transmitter "
- "disabled\n", descriptor);
- return 0;
- }
-
- if (s->TxStatus[descriptor] & TxHostOwns)
- {
- DPRINTF("+++ cannot transmit from descriptor %d: owned by host "
- "(%08x)\n", descriptor, s->TxStatus[descriptor]);
- return 0;
- }
-
- DPRINTF("+++ transmitting from descriptor %d\n", descriptor);
-
- PCIDevice *d = PCI_DEVICE(s);
- int txsize = s->TxStatus[descriptor] & 0x1fff;
- uint8_t txbuffer[0x2000];
-
- DPRINTF("+++ transmit reading %d bytes from host memory at 0x%08x\n",
- txsize, s->TxAddr[descriptor]);
-
- pci_dma_read(d, s->TxAddr[descriptor], txbuffer, txsize);
-
- /* Mark descriptor as transferred */
- s->TxStatus[descriptor] |= TxHostOwns;
- s->TxStatus[descriptor] |= TxStatOK;
-
- rtl8139_transfer_frame(s, txbuffer, txsize, 0, NULL);
-
- DPRINTF("+++ transmitted %d bytes from descriptor %d\n", txsize,
- descriptor);
-
- /* update interrupt */
- s->IntrStatus |= TxOK;
- rtl8139_update_irq(s);
-
- return 1;
-}
-
-/* structures and macros for task offloading */
-#define TCP_HEADER_DATA_OFFSET(tcp) (((be16_to_cpu(tcp->th_offset_flags) >> 12)&0xf) << 2)
-#define TCP_FLAGS_ONLY(flags) ((flags)&0x3f)
-#define TCP_HEADER_FLAGS(tcp) TCP_FLAGS_ONLY(be16_to_cpu(tcp->th_offset_flags))
-
-#define TCP_HEADER_CLEAR_FLAGS(tcp, off) ((tcp)->th_offset_flags &= cpu_to_be16(~TCP_FLAGS_ONLY(off)))
-
-/* produces ones' complement sum of data */
-static uint16_t ones_complement_sum(uint8_t *data, size_t len)
-{
- uint32_t result = 0;
-
- for (; len > 1; data+=2, len-=2)
- {
- result += *(uint16_t*)data;
- }
-
- /* add the remainder byte */
- if (len)
- {
- uint8_t odd[2] = {*data, 0};
- result += *(uint16_t*)odd;
- }
-
- while (result>>16)
- result = (result & 0xffff) + (result >> 16);
-
- return result;
-}
-
-static uint16_t ip_checksum(void *data, size_t len)
-{
- return ~ones_complement_sum((uint8_t*)data, len);
-}
-
-static int rtl8139_cplus_transmit_one(RTL8139State *s)
-{
- if (!rtl8139_transmitter_enabled(s))
- {
- DPRINTF("+++ C+ mode: transmitter disabled\n");
- return 0;
- }
-
- if (!rtl8139_cp_transmitter_enabled(s))
- {
- DPRINTF("+++ C+ mode: C+ transmitter disabled\n");
- return 0 ;
- }
-
- PCIDevice *d = PCI_DEVICE(s);
- int descriptor = s->currCPlusTxDesc;
-
- dma_addr_t cplus_tx_ring_desc = rtl8139_addr64(s->TxAddr[0], s->TxAddr[1]);
-
- /* Normal priority ring */
- cplus_tx_ring_desc += 16 * descriptor;
-
- DPRINTF("+++ C+ mode reading TX descriptor %d from host memory at "
- "%08x %08x = 0x"DMA_ADDR_FMT"\n", descriptor, s->TxAddr[1],
- s->TxAddr[0], cplus_tx_ring_desc);
-
- uint32_t val, txdw0,txdw1,txbufLO,txbufHI;
-
- pci_dma_read(d, cplus_tx_ring_desc, (uint8_t *)&val, 4);
- txdw0 = le32_to_cpu(val);
- pci_dma_read(d, cplus_tx_ring_desc+4, (uint8_t *)&val, 4);
- txdw1 = le32_to_cpu(val);
- pci_dma_read(d, cplus_tx_ring_desc+8, (uint8_t *)&val, 4);
- txbufLO = le32_to_cpu(val);
- pci_dma_read(d, cplus_tx_ring_desc+12, (uint8_t *)&val, 4);
- txbufHI = le32_to_cpu(val);
-
- DPRINTF("+++ C+ mode TX descriptor %d %08x %08x %08x %08x\n", descriptor,
- txdw0, txdw1, txbufLO, txbufHI);
-
-/* w0 ownership flag */
-#define CP_TX_OWN (1<<31)
-/* w0 end of ring flag */
-#define CP_TX_EOR (1<<30)
-/* first segment of received packet flag */
-#define CP_TX_FS (1<<29)
-/* last segment of received packet flag */
-#define CP_TX_LS (1<<28)
-/* large send packet flag */
-#define CP_TX_LGSEN (1<<27)
-/* large send MSS mask, bits 16...25 */
-#define CP_TC_LGSEN_MSS_MASK ((1 << 12) - 1)
-
-/* IP checksum offload flag */
-#define CP_TX_IPCS (1<<18)
-/* UDP checksum offload flag */
-#define CP_TX_UDPCS (1<<17)
-/* TCP checksum offload flag */
-#define CP_TX_TCPCS (1<<16)
-
-/* w0 bits 0...15 : buffer size */
-#define CP_TX_BUFFER_SIZE (1<<16)
-#define CP_TX_BUFFER_SIZE_MASK (CP_TX_BUFFER_SIZE - 1)
-/* w1 add tag flag */
-#define CP_TX_TAGC (1<<17)
-/* w1 bits 0...15 : VLAN tag (big endian) */
-#define CP_TX_VLAN_TAG_MASK ((1<<16) - 1)
-/* w2 low 32bit of Rx buffer ptr */
-/* w3 high 32bit of Rx buffer ptr */
-
-/* set after transmission */
-/* FIFO underrun flag */
-#define CP_TX_STATUS_UNF (1<<25)
-/* transmit error summary flag, valid if set any of three below */
-#define CP_TX_STATUS_TES (1<<23)
-/* out-of-window collision flag */
-#define CP_TX_STATUS_OWC (1<<22)
-/* link failure flag */
-#define CP_TX_STATUS_LNKF (1<<21)
-/* excessive collisions flag */
-#define CP_TX_STATUS_EXC (1<<20)
-
- if (!(txdw0 & CP_TX_OWN))
- {
- DPRINTF("C+ Tx mode : descriptor %d is owned by host\n", descriptor);
- return 0 ;
- }
-
- DPRINTF("+++ C+ Tx mode : transmitting from descriptor %d\n", descriptor);
-
- if (txdw0 & CP_TX_FS)
- {
- DPRINTF("+++ C+ Tx mode : descriptor %d is first segment "
- "descriptor\n", descriptor);
-
- /* reset internal buffer offset */
- s->cplus_txbuffer_offset = 0;
- }
-
- int txsize = txdw0 & CP_TX_BUFFER_SIZE_MASK;
- dma_addr_t tx_addr = rtl8139_addr64(txbufLO, txbufHI);
-
- /* make sure we have enough space to assemble the packet */
- if (!s->cplus_txbuffer)
- {
- s->cplus_txbuffer_len = CP_TX_BUFFER_SIZE;
- s->cplus_txbuffer = g_malloc(s->cplus_txbuffer_len);
- s->cplus_txbuffer_offset = 0;
-
- DPRINTF("+++ C+ mode transmission buffer allocated space %d\n",
- s->cplus_txbuffer_len);
- }
-
- if (s->cplus_txbuffer_offset + txsize >= s->cplus_txbuffer_len)
- {
- /* The spec didn't tell the maximum size, stick to CP_TX_BUFFER_SIZE */
- txsize = s->cplus_txbuffer_len - s->cplus_txbuffer_offset;
- DPRINTF("+++ C+ mode transmission buffer overrun, truncated descriptor"
- "length to %d\n", txsize);
- }
-
- /* append more data to the packet */
-
- DPRINTF("+++ C+ mode transmit reading %d bytes from host memory at "
- DMA_ADDR_FMT" to offset %d\n", txsize, tx_addr,
- s->cplus_txbuffer_offset);
-
- pci_dma_read(d, tx_addr,
- s->cplus_txbuffer + s->cplus_txbuffer_offset, txsize);
- s->cplus_txbuffer_offset += txsize;
-
- /* seek to next Rx descriptor */
- if (txdw0 & CP_TX_EOR)
- {
- s->currCPlusTxDesc = 0;
- }
- else
- {
- ++s->currCPlusTxDesc;
- if (s->currCPlusTxDesc >= 64)
- s->currCPlusTxDesc = 0;
- }
-
- /* transfer ownership to target */
- txdw0 &= ~CP_TX_OWN;
-
- /* reset error indicator bits */
- txdw0 &= ~CP_TX_STATUS_UNF;
- txdw0 &= ~CP_TX_STATUS_TES;
- txdw0 &= ~CP_TX_STATUS_OWC;
- txdw0 &= ~CP_TX_STATUS_LNKF;
- txdw0 &= ~CP_TX_STATUS_EXC;
-
- /* update ring data */
- val = cpu_to_le32(txdw0);
- pci_dma_write(d, cplus_tx_ring_desc, (uint8_t *)&val, 4);
-
- /* Now decide if descriptor being processed is holding the last segment of packet */
- if (txdw0 & CP_TX_LS)
- {
- uint8_t dot1q_buffer_space[VLAN_HLEN];
- uint16_t *dot1q_buffer;
-
- DPRINTF("+++ C+ Tx mode : descriptor %d is last segment descriptor\n",
- descriptor);
-
- /* can transfer fully assembled packet */
-
- uint8_t *saved_buffer = s->cplus_txbuffer;
- int saved_size = s->cplus_txbuffer_offset;
- int saved_buffer_len = s->cplus_txbuffer_len;
-
- /* create vlan tag */
- if (txdw1 & CP_TX_TAGC) {
- /* the vlan tag is in BE byte order in the descriptor
- * BE + le_to_cpu() + ~swap()~ = cpu */
- DPRINTF("+++ C+ Tx mode : inserting vlan tag with ""tci: %u\n",
- bswap16(txdw1 & CP_TX_VLAN_TAG_MASK));
-
- dot1q_buffer = (uint16_t *) dot1q_buffer_space;
- dot1q_buffer[0] = cpu_to_be16(ETH_P_VLAN);
- /* BE + le_to_cpu() + ~cpu_to_le()~ = BE */
- dot1q_buffer[1] = cpu_to_le16(txdw1 & CP_TX_VLAN_TAG_MASK);
- } else {
- dot1q_buffer = NULL;
- }
-
- /* reset the card space to protect from recursive call */
- s->cplus_txbuffer = NULL;
- s->cplus_txbuffer_offset = 0;
- s->cplus_txbuffer_len = 0;
-
- if (txdw0 & (CP_TX_IPCS | CP_TX_UDPCS | CP_TX_TCPCS | CP_TX_LGSEN))
- {
- DPRINTF("+++ C+ mode offloaded task checksum\n");
-
- /* Large enough for Ethernet and IP headers? */
- if (saved_size < ETH_HLEN + sizeof(struct ip_header)) {
- goto skip_offload;
- }
-
- /* ip packet header */
- struct ip_header *ip = NULL;
- int hlen = 0;
- uint8_t ip_protocol = 0;
- uint16_t ip_data_len = 0;
-
- uint8_t *eth_payload_data = NULL;
- size_t eth_payload_len = 0;
-
- int proto = be16_to_cpu(*(uint16_t *)(saved_buffer + 12));
- if (proto != ETH_P_IP)
- {
- goto skip_offload;
- }
-
- DPRINTF("+++ C+ mode has IP packet\n");
-
- /* Note on memory alignment: eth_payload_data is 16-bit aligned
- * since saved_buffer is allocated with g_malloc() and ETH_HLEN is
- * even. 32-bit accesses must use ldl/stl wrappers to avoid
- * unaligned accesses.
- */
- eth_payload_data = saved_buffer + ETH_HLEN;
- eth_payload_len = saved_size - ETH_HLEN;
-
- ip = (struct ip_header*)eth_payload_data;
-
- if (IP_HEADER_VERSION(ip) != IP_HEADER_VERSION_4) {
- DPRINTF("+++ C+ mode packet has bad IP version %d "
- "expected %d\n", IP_HEADER_VERSION(ip),
- IP_HEADER_VERSION_4);
- goto skip_offload;
- }
-
- hlen = IP_HDR_GET_LEN(ip);
- if (hlen < sizeof(struct ip_header) || hlen > eth_payload_len) {
- goto skip_offload;
- }
-
- ip_protocol = ip->ip_p;
-
- ip_data_len = be16_to_cpu(ip->ip_len);
- if (ip_data_len < hlen || ip_data_len > eth_payload_len) {
- goto skip_offload;
- }
- ip_data_len -= hlen;
-
- if (txdw0 & CP_TX_IPCS)
- {
- DPRINTF("+++ C+ mode need IP checksum\n");
-
- ip->ip_sum = 0;
- ip->ip_sum = ip_checksum(ip, hlen);
- DPRINTF("+++ C+ mode IP header len=%d checksum=%04x\n",
- hlen, ip->ip_sum);
- }
-
- if ((txdw0 & CP_TX_LGSEN) && ip_protocol == IP_PROTO_TCP)
- {
- /* Large enough for the TCP header? */
- if (ip_data_len < sizeof(tcp_header)) {
- goto skip_offload;
- }
-
- int large_send_mss = (txdw0 >> 16) & CP_TC_LGSEN_MSS_MASK;
-
- DPRINTF("+++ C+ mode offloaded task TSO MTU=%d IP data %d "
- "frame data %d specified MSS=%d\n", ETH_MTU,
- ip_data_len, saved_size - ETH_HLEN, large_send_mss);
-
- int tcp_send_offset = 0;
- int send_count = 0;
-
- /* maximum IP header length is 60 bytes */
- uint8_t saved_ip_header[60];
-
- /* save IP header template; data area is used in tcp checksum calculation */
- memcpy(saved_ip_header, eth_payload_data, hlen);
-
- /* a placeholder for checksum calculation routine in tcp case */
- uint8_t *data_to_checksum = eth_payload_data + hlen - 12;
- // size_t data_to_checksum_len = eth_payload_len - hlen + 12;
-
- /* pointer to TCP header */
- tcp_header *p_tcp_hdr = (tcp_header*)(eth_payload_data + hlen);
-
- int tcp_hlen = TCP_HEADER_DATA_OFFSET(p_tcp_hdr);
-
- /* Invalid TCP data offset? */
- if (tcp_hlen < sizeof(tcp_header) || tcp_hlen > ip_data_len) {
- goto skip_offload;
- }
-
- /* ETH_MTU = ip header len + tcp header len + payload */
- int tcp_data_len = ip_data_len - tcp_hlen;
- int tcp_chunk_size = ETH_MTU - hlen - tcp_hlen;
-
- DPRINTF("+++ C+ mode TSO IP data len %d TCP hlen %d TCP "
- "data len %d TCP chunk size %d\n", ip_data_len,
- tcp_hlen, tcp_data_len, tcp_chunk_size);
-
- /* note the cycle below overwrites IP header data,
- but restores it from saved_ip_header before sending packet */
-
- int is_last_frame = 0;
-
- for (tcp_send_offset = 0; tcp_send_offset < tcp_data_len; tcp_send_offset += tcp_chunk_size)
- {
- uint16_t chunk_size = tcp_chunk_size;
-
- /* check if this is the last frame */
- if (tcp_send_offset + tcp_chunk_size >= tcp_data_len)
- {
- is_last_frame = 1;
- chunk_size = tcp_data_len - tcp_send_offset;
- }
-
- DPRINTF("+++ C+ mode TSO TCP seqno %08x\n",
- ldl_be_p(&p_tcp_hdr->th_seq));
-
- /* add 4 TCP pseudoheader fields */
- /* copy IP source and destination fields */
- memcpy(data_to_checksum, saved_ip_header + 12, 8);
-
- DPRINTF("+++ C+ mode TSO calculating TCP checksum for "
- "packet with %d bytes data\n", tcp_hlen +
- chunk_size);
-
- if (tcp_send_offset)
- {
- memcpy((uint8_t*)p_tcp_hdr + tcp_hlen, (uint8_t*)p_tcp_hdr + tcp_hlen + tcp_send_offset, chunk_size);
- }
-
- /* keep PUSH and FIN flags only for the last frame */
- if (!is_last_frame)
- {
- TCP_HEADER_CLEAR_FLAGS(p_tcp_hdr, TH_PUSH | TH_FIN);
- }
-
- /* recalculate TCP checksum */
- ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum;
- p_tcpip_hdr->zeros = 0;
- p_tcpip_hdr->ip_proto = IP_PROTO_TCP;
- p_tcpip_hdr->ip_payload = cpu_to_be16(tcp_hlen + chunk_size);
-
- p_tcp_hdr->th_sum = 0;
-
- int tcp_checksum = ip_checksum(data_to_checksum, tcp_hlen + chunk_size + 12);
- DPRINTF("+++ C+ mode TSO TCP checksum %04x\n",
- tcp_checksum);
-
- p_tcp_hdr->th_sum = tcp_checksum;
-
- /* restore IP header */
- memcpy(eth_payload_data, saved_ip_header, hlen);
-
- /* set IP data length and recalculate IP checksum */
- ip->ip_len = cpu_to_be16(hlen + tcp_hlen + chunk_size);
-
- /* increment IP id for subsequent frames */
- ip->ip_id = cpu_to_be16(tcp_send_offset/tcp_chunk_size + be16_to_cpu(ip->ip_id));
-
- ip->ip_sum = 0;
- ip->ip_sum = ip_checksum(eth_payload_data, hlen);
- DPRINTF("+++ C+ mode TSO IP header len=%d "
- "checksum=%04x\n", hlen, ip->ip_sum);
-
- int tso_send_size = ETH_HLEN + hlen + tcp_hlen + chunk_size;
- DPRINTF("+++ C+ mode TSO transferring packet size "
- "%d\n", tso_send_size);
- rtl8139_transfer_frame(s, saved_buffer, tso_send_size,
- 0, (uint8_t *) dot1q_buffer);
-
- /* add transferred count to TCP sequence number */
- stl_be_p(&p_tcp_hdr->th_seq,
- chunk_size + ldl_be_p(&p_tcp_hdr->th_seq));
- ++send_count;
- }
-
- /* Stop sending this frame */
- saved_size = 0;
- }
- else if (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS))
- {
- DPRINTF("+++ C+ mode need TCP or UDP checksum\n");
-
- /* maximum IP header length is 60 bytes */
- uint8_t saved_ip_header[60];
- memcpy(saved_ip_header, eth_payload_data, hlen);
-
- uint8_t *data_to_checksum = eth_payload_data + hlen - 12;
- // size_t data_to_checksum_len = eth_payload_len - hlen + 12;
-
- /* add 4 TCP pseudoheader fields */
- /* copy IP source and destination fields */
- memcpy(data_to_checksum, saved_ip_header + 12, 8);
-
- if ((txdw0 & CP_TX_TCPCS) && ip_protocol == IP_PROTO_TCP)
- {
- DPRINTF("+++ C+ mode calculating TCP checksum for "
- "packet with %d bytes data\n", ip_data_len);
-
- ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum;
- p_tcpip_hdr->zeros = 0;
- p_tcpip_hdr->ip_proto = IP_PROTO_TCP;
- p_tcpip_hdr->ip_payload = cpu_to_be16(ip_data_len);
-
- tcp_header* p_tcp_hdr = (tcp_header *) (data_to_checksum+12);
-
- p_tcp_hdr->th_sum = 0;
-
- int tcp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12);
- DPRINTF("+++ C+ mode TCP checksum %04x\n",
- tcp_checksum);
-
- p_tcp_hdr->th_sum = tcp_checksum;
- }
- else if ((txdw0 & CP_TX_UDPCS) && ip_protocol == IP_PROTO_UDP)
- {
- DPRINTF("+++ C+ mode calculating UDP checksum for "
- "packet with %d bytes data\n", ip_data_len);
-
- ip_pseudo_header *p_udpip_hdr = (ip_pseudo_header *)data_to_checksum;
- p_udpip_hdr->zeros = 0;
- p_udpip_hdr->ip_proto = IP_PROTO_UDP;
- p_udpip_hdr->ip_payload = cpu_to_be16(ip_data_len);
-
- udp_header *p_udp_hdr = (udp_header *) (data_to_checksum+12);
-
- p_udp_hdr->uh_sum = 0;
-
- int udp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12);
- DPRINTF("+++ C+ mode UDP checksum %04x\n",
- udp_checksum);
-
- p_udp_hdr->uh_sum = udp_checksum;
- }
-
- /* restore IP header */
- memcpy(eth_payload_data, saved_ip_header, hlen);
- }
- }
-
-skip_offload:
- /* update tally counter */
- ++s->tally_counters.TxOk;
-
- DPRINTF("+++ C+ mode transmitting %d bytes packet\n", saved_size);
-
- rtl8139_transfer_frame(s, saved_buffer, saved_size, 1,
- (uint8_t *) dot1q_buffer);
-
- /* restore card space if there was no recursion and reset offset */
- if (!s->cplus_txbuffer)
- {
- s->cplus_txbuffer = saved_buffer;
- s->cplus_txbuffer_len = saved_buffer_len;
- s->cplus_txbuffer_offset = 0;
- }
- else
- {
- g_free(saved_buffer);
- }
- }
- else
- {
- DPRINTF("+++ C+ mode transmission continue to next descriptor\n");
- }
-
- return 1;
-}
-
-static void rtl8139_cplus_transmit(RTL8139State *s)
-{
- int txcount = 0;
-
- while (rtl8139_cplus_transmit_one(s))
- {
- ++txcount;
- }
-
- /* Mark transfer completed */
- if (!txcount)
- {
- DPRINTF("C+ mode : transmitter queue stalled, current TxDesc = %d\n",
- s->currCPlusTxDesc);
- }
- else
- {
- /* update interrupt status */
- s->IntrStatus |= TxOK;
- rtl8139_update_irq(s);
- }
-}
-
-static void rtl8139_transmit(RTL8139State *s)
-{
- int descriptor = s->currTxDesc, txcount = 0;
-
- /*while*/
- if (rtl8139_transmit_one(s, descriptor))
- {
- ++s->currTxDesc;
- s->currTxDesc %= 4;
- ++txcount;
- }
-
- /* Mark transfer completed */
- if (!txcount)
- {
- DPRINTF("transmitter queue stalled, current TxDesc = %d\n",
- s->currTxDesc);
- }
-}
-
-static void rtl8139_TxStatus_write(RTL8139State *s, uint32_t txRegOffset, uint32_t val)
-{
-
- int descriptor = txRegOffset/4;
-
- /* handle C+ transmit mode register configuration */
-
- if (s->cplus_enabled)
- {
- DPRINTF("RTL8139C+ DTCCR write offset=0x%x val=0x%08x "
- "descriptor=%d\n", txRegOffset, val, descriptor);
-
- /* handle Dump Tally Counters command */
- s->TxStatus[descriptor] = val;
-
- if (descriptor == 0 && (val & 0x8))
- {
- hwaddr tc_addr = rtl8139_addr64(s->TxStatus[0] & ~0x3f, s->TxStatus[1]);
-
- /* dump tally counters to specified memory location */
- RTL8139TallyCounters_dma_write(s, tc_addr);
-
- /* mark dump completed */
- s->TxStatus[0] &= ~0x8;
- }
-
- return;
- }
-
- DPRINTF("TxStatus write offset=0x%x val=0x%08x descriptor=%d\n",
- txRegOffset, val, descriptor);
-
- /* mask only reserved bits */
- val &= ~0xff00c000; /* these bits are reset on write */
- val = SET_MASKED(val, 0x00c00000, s->TxStatus[descriptor]);
-
- s->TxStatus[descriptor] = val;
-
- /* attempt to start transmission */
- rtl8139_transmit(s);
-}
-
-static uint32_t rtl8139_TxStatus_TxAddr_read(RTL8139State *s, uint32_t regs[],
- uint32_t base, uint8_t addr,
- int size)
-{
- uint32_t reg = (addr - base) / 4;
- uint32_t offset = addr & 0x3;
- uint32_t ret = 0;
-
- if (addr & (size - 1)) {
- DPRINTF("not implemented read for TxStatus/TxAddr "
- "addr=0x%x size=0x%x\n", addr, size);
- return ret;
- }
-
- switch (size) {
- case 1: /* fall through */
- case 2: /* fall through */
- case 4:
- ret = (regs[reg] >> offset * 8) & (((uint64_t)1 << (size * 8)) - 1);
- DPRINTF("TxStatus/TxAddr[%d] read addr=0x%x size=0x%x val=0x%08x\n",
- reg, addr, size, ret);
- break;
- default:
- DPRINTF("unsupported size 0x%x of TxStatus/TxAddr reading\n", size);
- break;
- }
-
- return ret;
-}
-
-static uint16_t rtl8139_TSAD_read(RTL8139State *s)
-{
- uint16_t ret = 0;
-
- /* Simulate TSAD, it is read only anyway */
-
- ret = ((s->TxStatus[3] & TxStatOK )?TSAD_TOK3:0)
- |((s->TxStatus[2] & TxStatOK )?TSAD_TOK2:0)
- |((s->TxStatus[1] & TxStatOK )?TSAD_TOK1:0)
- |((s->TxStatus[0] & TxStatOK )?TSAD_TOK0:0)
-
- |((s->TxStatus[3] & TxUnderrun)?TSAD_TUN3:0)
- |((s->TxStatus[2] & TxUnderrun)?TSAD_TUN2:0)
- |((s->TxStatus[1] & TxUnderrun)?TSAD_TUN1:0)
- |((s->TxStatus[0] & TxUnderrun)?TSAD_TUN0:0)
-
- |((s->TxStatus[3] & TxAborted )?TSAD_TABT3:0)
- |((s->TxStatus[2] & TxAborted )?TSAD_TABT2:0)
- |((s->TxStatus[1] & TxAborted )?TSAD_TABT1:0)
- |((s->TxStatus[0] & TxAborted )?TSAD_TABT0:0)
-
- |((s->TxStatus[3] & TxHostOwns )?TSAD_OWN3:0)
- |((s->TxStatus[2] & TxHostOwns )?TSAD_OWN2:0)
- |((s->TxStatus[1] & TxHostOwns )?TSAD_OWN1:0)
- |((s->TxStatus[0] & TxHostOwns )?TSAD_OWN0:0) ;
-
-
- DPRINTF("TSAD read val=0x%04x\n", ret);
-
- return ret;
-}
-
-static uint16_t rtl8139_CSCR_read(RTL8139State *s)
-{
- uint16_t ret = s->CSCR;
-
- DPRINTF("CSCR read val=0x%04x\n", ret);
-
- return ret;
-}
-
-static void rtl8139_TxAddr_write(RTL8139State *s, uint32_t txAddrOffset, uint32_t val)
-{
- DPRINTF("TxAddr write offset=0x%x val=0x%08x\n", txAddrOffset, val);
-
- s->TxAddr[txAddrOffset/4] = val;
-}
-
-static uint32_t rtl8139_TxAddr_read(RTL8139State *s, uint32_t txAddrOffset)
-{
- uint32_t ret = s->TxAddr[txAddrOffset/4];
-
- DPRINTF("TxAddr read offset=0x%x val=0x%08x\n", txAddrOffset, ret);
-
- return ret;
-}
-
-static void rtl8139_RxBufPtr_write(RTL8139State *s, uint32_t val)
-{
- DPRINTF("RxBufPtr write val=0x%04x\n", val);
-
- /* this value is off by 16 */
- s->RxBufPtr = MOD2(val + 0x10, s->RxBufferSize);
-
- /* more buffer space may be available so try to receive */
- qemu_flush_queued_packets(qemu_get_queue(s->nic));
-
- DPRINTF(" CAPR write: rx buffer length %d head 0x%04x read 0x%04x\n",
- s->RxBufferSize, s->RxBufAddr, s->RxBufPtr);
-}
-
-static uint32_t rtl8139_RxBufPtr_read(RTL8139State *s)
-{
- /* this value is off by 16 */
- uint32_t ret = s->RxBufPtr - 0x10;
-
- DPRINTF("RxBufPtr read val=0x%04x\n", ret);
-
- return ret;
-}
-
-static uint32_t rtl8139_RxBufAddr_read(RTL8139State *s)
-{
- /* this value is NOT off by 16 */
- uint32_t ret = s->RxBufAddr;
-
- DPRINTF("RxBufAddr read val=0x%04x\n", ret);
-
- return ret;
-}
-
-static void rtl8139_RxBuf_write(RTL8139State *s, uint32_t val)
-{
- DPRINTF("RxBuf write val=0x%08x\n", val);
-
- s->RxBuf = val;
-
- /* may need to reset rxring here */
-}
-
-static uint32_t rtl8139_RxBuf_read(RTL8139State *s)
-{
- uint32_t ret = s->RxBuf;
-
- DPRINTF("RxBuf read val=0x%08x\n", ret);
-
- return ret;
-}
-
-static void rtl8139_IntrMask_write(RTL8139State *s, uint32_t val)
-{
- DPRINTF("IntrMask write(w) val=0x%04x\n", val);
-
- /* mask unwritable bits */
- val = SET_MASKED(val, 0x1e00, s->IntrMask);
-
- s->IntrMask = val;
-
- rtl8139_update_irq(s);
-
-}
-
-static uint32_t rtl8139_IntrMask_read(RTL8139State *s)
-{
- uint32_t ret = s->IntrMask;
-
- DPRINTF("IntrMask read(w) val=0x%04x\n", ret);
-
- return ret;
-}
-
-static void rtl8139_IntrStatus_write(RTL8139State *s, uint32_t val)
-{
- DPRINTF("IntrStatus write(w) val=0x%04x\n", val);
-
-#if 0
-
- /* writing to ISR has no effect */
-
- return;
-
-#else
- uint16_t newStatus = s->IntrStatus & ~val;
-
- /* mask unwritable bits */
- newStatus = SET_MASKED(newStatus, 0x1e00, s->IntrStatus);
-
- /* writing 1 to interrupt status register bit clears it */
- s->IntrStatus = 0;
- rtl8139_update_irq(s);
-
- s->IntrStatus = newStatus;
- rtl8139_set_next_tctr_time(s);
- rtl8139_update_irq(s);
-
-#endif
-}
-
-static uint32_t rtl8139_IntrStatus_read(RTL8139State *s)
-{
- uint32_t ret = s->IntrStatus;
-
- DPRINTF("IntrStatus read(w) val=0x%04x\n", ret);
-
-#if 0
-
- /* reading ISR clears all interrupts */
- s->IntrStatus = 0;
-
- rtl8139_update_irq(s);
-
-#endif
-
- return ret;
-}
-
-static void rtl8139_MultiIntr_write(RTL8139State *s, uint32_t val)
-{
- DPRINTF("MultiIntr write(w) val=0x%04x\n", val);
-
- /* mask unwritable bits */
- val = SET_MASKED(val, 0xf000, s->MultiIntr);
-
- s->MultiIntr = val;
-}
-
-static uint32_t rtl8139_MultiIntr_read(RTL8139State *s)
-{
- uint32_t ret = s->MultiIntr;
-
- DPRINTF("MultiIntr read(w) val=0x%04x\n", ret);
-
- return ret;
-}
-
-static void rtl8139_io_writeb(void *opaque, uint8_t addr, uint32_t val)
-{
- RTL8139State *s = opaque;
-
- switch (addr)
- {
- case MAC0 ... MAC0+4:
- s->phys[addr - MAC0] = val;
- break;
- case MAC0+5:
- s->phys[addr - MAC0] = val;
- qemu_format_nic_info_str(qemu_get_queue(s->nic), s->phys);
- break;
- case MAC0+6 ... MAC0+7:
- /* reserved */
- break;
- case MAR0 ... MAR0+7:
- s->mult[addr - MAR0] = val;
- break;
- case ChipCmd:
- rtl8139_ChipCmd_write(s, val);
- break;
- case Cfg9346:
- rtl8139_Cfg9346_write(s, val);
- break;
- case TxConfig: /* windows driver sometimes writes using byte-lenth call */
- rtl8139_TxConfig_writeb(s, val);
- break;
- case Config0:
- rtl8139_Config0_write(s, val);
- break;
- case Config1:
- rtl8139_Config1_write(s, val);
- break;
- case Config3:
- rtl8139_Config3_write(s, val);
- break;
- case Config4:
- rtl8139_Config4_write(s, val);
- break;
- case Config5:
- rtl8139_Config5_write(s, val);
- break;
- case MediaStatus:
- /* ignore */
- DPRINTF("not implemented write(b) to MediaStatus val=0x%02x\n",
- val);
- break;
-
- case HltClk:
- DPRINTF("HltClk write val=0x%08x\n", val);
- if (val == 'R')
- {
- s->clock_enabled = 1;
- }
- else if (val == 'H')
- {
- s->clock_enabled = 0;
- }
- break;
-
- case TxThresh:
- DPRINTF("C+ TxThresh write(b) val=0x%02x\n", val);
- s->TxThresh = val;
- break;
-
- case TxPoll:
- DPRINTF("C+ TxPoll write(b) val=0x%02x\n", val);
- if (val & (1 << 7))
- {
- DPRINTF("C+ TxPoll high priority transmission (not "
- "implemented)\n");
- //rtl8139_cplus_transmit(s);
- }
- if (val & (1 << 6))
- {
- DPRINTF("C+ TxPoll normal priority transmission\n");
- rtl8139_cplus_transmit(s);
- }
-
- break;
-
- default:
- DPRINTF("not implemented write(b) addr=0x%x val=0x%02x\n", addr,
- val);
- break;
- }
-}
-
-static void rtl8139_io_writew(void *opaque, uint8_t addr, uint32_t val)
-{
- RTL8139State *s = opaque;
-
- switch (addr)
- {
- case IntrMask:
- rtl8139_IntrMask_write(s, val);
- break;
-
- case IntrStatus:
- rtl8139_IntrStatus_write(s, val);
- break;
-
- case MultiIntr:
- rtl8139_MultiIntr_write(s, val);
- break;
-
- case RxBufPtr:
- rtl8139_RxBufPtr_write(s, val);
- break;
-
- case BasicModeCtrl:
- rtl8139_BasicModeCtrl_write(s, val);
- break;
- case BasicModeStatus:
- rtl8139_BasicModeStatus_write(s, val);
- break;
- case NWayAdvert:
- DPRINTF("NWayAdvert write(w) val=0x%04x\n", val);
- s->NWayAdvert = val;
- break;
- case NWayLPAR:
- DPRINTF("forbidden NWayLPAR write(w) val=0x%04x\n", val);
- break;
- case NWayExpansion:
- DPRINTF("NWayExpansion write(w) val=0x%04x\n", val);
- s->NWayExpansion = val;
- break;
-
- case CpCmd:
- rtl8139_CpCmd_write(s, val);
- break;
-
- case IntrMitigate:
- rtl8139_IntrMitigate_write(s, val);
- break;
-
- default:
- DPRINTF("ioport write(w) addr=0x%x val=0x%04x via write(b)\n",
- addr, val);
-
- rtl8139_io_writeb(opaque, addr, val & 0xff);
- rtl8139_io_writeb(opaque, addr + 1, (val >> 8) & 0xff);
- break;
- }
-}
-
-static void rtl8139_set_next_tctr_time(RTL8139State *s)
-{
- const uint64_t ns_per_period = (uint64_t)PCI_PERIOD << 32;
-
- DPRINTF("entered rtl8139_set_next_tctr_time\n");
-
- /* This function is called at least once per period, so it is a good
- * place to update the timer base.
- *
- * After one iteration of this loop the value in the Timer register does
- * not change, but the device model is counting up by 2^32 ticks (approx.
- * 130 seconds).
- */
- while (s->TCTR_base + ns_per_period <= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)) {
- s->TCTR_base += ns_per_period;
- }
-
- if (!s->TimerInt) {
- timer_del(s->timer);
- } else {
- uint64_t delta = (uint64_t)s->TimerInt * PCI_PERIOD;
- if (s->TCTR_base + delta <= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)) {
- delta += ns_per_period;
- }
- timer_mod(s->timer, s->TCTR_base + delta);
- }
-}
-
-static void rtl8139_io_writel(void *opaque, uint8_t addr, uint32_t val)
-{
- RTL8139State *s = opaque;
-
- switch (addr)
- {
- case RxMissed:
- DPRINTF("RxMissed clearing on write\n");
- s->RxMissed = 0;
- break;
-
- case TxConfig:
- rtl8139_TxConfig_write(s, val);
- break;
-
- case RxConfig:
- rtl8139_RxConfig_write(s, val);
- break;
-
- case TxStatus0 ... TxStatus0+4*4-1:
- rtl8139_TxStatus_write(s, addr-TxStatus0, val);
- break;
-
- case TxAddr0 ... TxAddr0+4*4-1:
- rtl8139_TxAddr_write(s, addr-TxAddr0, val);
- break;
-
- case RxBuf:
- rtl8139_RxBuf_write(s, val);
- break;
-
- case RxRingAddrLO:
- DPRINTF("C+ RxRing low bits write val=0x%08x\n", val);
- s->RxRingAddrLO = val;
- break;
-
- case RxRingAddrHI:
- DPRINTF("C+ RxRing high bits write val=0x%08x\n", val);
- s->RxRingAddrHI = val;
- break;
-
- case Timer:
- DPRINTF("TCTR Timer reset on write\n");
- s->TCTR_base = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- rtl8139_set_next_tctr_time(s);
- break;
-
- case FlashReg:
- DPRINTF("FlashReg TimerInt write val=0x%08x\n", val);
- if (s->TimerInt != val) {
- s->TimerInt = val;
- rtl8139_set_next_tctr_time(s);
- }
- break;
-
- default:
- DPRINTF("ioport write(l) addr=0x%x val=0x%08x via write(b)\n",
- addr, val);
- rtl8139_io_writeb(opaque, addr, val & 0xff);
- rtl8139_io_writeb(opaque, addr + 1, (val >> 8) & 0xff);
- rtl8139_io_writeb(opaque, addr + 2, (val >> 16) & 0xff);
- rtl8139_io_writeb(opaque, addr + 3, (val >> 24) & 0xff);
- break;
- }
-}
-
-static uint32_t rtl8139_io_readb(void *opaque, uint8_t addr)
-{
- RTL8139State *s = opaque;
- int ret;
-
- switch (addr)
- {
- case MAC0 ... MAC0+5:
- ret = s->phys[addr - MAC0];
- break;
- case MAC0+6 ... MAC0+7:
- ret = 0;
- break;
- case MAR0 ... MAR0+7:
- ret = s->mult[addr - MAR0];
- break;
- case TxStatus0 ... TxStatus0+4*4-1:
- ret = rtl8139_TxStatus_TxAddr_read(s, s->TxStatus, TxStatus0,
- addr, 1);
- break;
- case ChipCmd:
- ret = rtl8139_ChipCmd_read(s);
- break;
- case Cfg9346:
- ret = rtl8139_Cfg9346_read(s);
- break;
- case Config0:
- ret = rtl8139_Config0_read(s);
- break;
- case Config1:
- ret = rtl8139_Config1_read(s);
- break;
- case Config3:
- ret = rtl8139_Config3_read(s);
- break;
- case Config4:
- ret = rtl8139_Config4_read(s);
- break;
- case Config5:
- ret = rtl8139_Config5_read(s);
- break;
-
- case MediaStatus:
- /* The LinkDown bit of MediaStatus is inverse with link status */
- ret = 0xd0 | (~s->BasicModeStatus & 0x04);
- DPRINTF("MediaStatus read 0x%x\n", ret);
- break;
-
- case HltClk:
- ret = s->clock_enabled;
- DPRINTF("HltClk read 0x%x\n", ret);
- break;
-
- case PCIRevisionID:
- ret = RTL8139_PCI_REVID;
- DPRINTF("PCI Revision ID read 0x%x\n", ret);
- break;
-
- case TxThresh:
- ret = s->TxThresh;
- DPRINTF("C+ TxThresh read(b) val=0x%02x\n", ret);
- break;
-
- case 0x43: /* Part of TxConfig register. Windows driver tries to read it */
- ret = s->TxConfig >> 24;
- DPRINTF("RTL8139C TxConfig at 0x43 read(b) val=0x%02x\n", ret);
- break;
-
- default:
- DPRINTF("not implemented read(b) addr=0x%x\n", addr);
- ret = 0;
- break;
- }
-
- return ret;
-}
-
-static uint32_t rtl8139_io_readw(void *opaque, uint8_t addr)
-{
- RTL8139State *s = opaque;
- uint32_t ret;
-
- switch (addr)
- {
- case TxAddr0 ... TxAddr0+4*4-1:
- ret = rtl8139_TxStatus_TxAddr_read(s, s->TxAddr, TxAddr0, addr, 2);
- break;
- case IntrMask:
- ret = rtl8139_IntrMask_read(s);
- break;
-
- case IntrStatus:
- ret = rtl8139_IntrStatus_read(s);
- break;
-
- case MultiIntr:
- ret = rtl8139_MultiIntr_read(s);
- break;
-
- case RxBufPtr:
- ret = rtl8139_RxBufPtr_read(s);
- break;
-
- case RxBufAddr:
- ret = rtl8139_RxBufAddr_read(s);
- break;
-
- case BasicModeCtrl:
- ret = rtl8139_BasicModeCtrl_read(s);
- break;
- case BasicModeStatus:
- ret = rtl8139_BasicModeStatus_read(s);
- break;
- case NWayAdvert:
- ret = s->NWayAdvert;
- DPRINTF("NWayAdvert read(w) val=0x%04x\n", ret);
- break;
- case NWayLPAR:
- ret = s->NWayLPAR;
- DPRINTF("NWayLPAR read(w) val=0x%04x\n", ret);
- break;
- case NWayExpansion:
- ret = s->NWayExpansion;
- DPRINTF("NWayExpansion read(w) val=0x%04x\n", ret);
- break;
-
- case CpCmd:
- ret = rtl8139_CpCmd_read(s);
- break;
-
- case IntrMitigate:
- ret = rtl8139_IntrMitigate_read(s);
- break;
-
- case TxSummary:
- ret = rtl8139_TSAD_read(s);
- break;
-
- case CSCR:
- ret = rtl8139_CSCR_read(s);
- break;
-
- default:
- DPRINTF("ioport read(w) addr=0x%x via read(b)\n", addr);
-
- ret = rtl8139_io_readb(opaque, addr);
- ret |= rtl8139_io_readb(opaque, addr + 1) << 8;
-
- DPRINTF("ioport read(w) addr=0x%x val=0x%04x\n", addr, ret);
- break;
- }
-
- return ret;
-}
-
-static uint32_t rtl8139_io_readl(void *opaque, uint8_t addr)
-{
- RTL8139State *s = opaque;
- uint32_t ret;
-
- switch (addr)
- {
- case RxMissed:
- ret = s->RxMissed;
-
- DPRINTF("RxMissed read val=0x%08x\n", ret);
- break;
-
- case TxConfig:
- ret = rtl8139_TxConfig_read(s);
- break;
-
- case RxConfig:
- ret = rtl8139_RxConfig_read(s);
- break;
-
- case TxStatus0 ... TxStatus0+4*4-1:
- ret = rtl8139_TxStatus_TxAddr_read(s, s->TxStatus, TxStatus0,
- addr, 4);
- break;
-
- case TxAddr0 ... TxAddr0+4*4-1:
- ret = rtl8139_TxAddr_read(s, addr-TxAddr0);
- break;
-
- case RxBuf:
- ret = rtl8139_RxBuf_read(s);
- break;
-
- case RxRingAddrLO:
- ret = s->RxRingAddrLO;
- DPRINTF("C+ RxRing low bits read val=0x%08x\n", ret);
- break;
-
- case RxRingAddrHI:
- ret = s->RxRingAddrHI;
- DPRINTF("C+ RxRing high bits read val=0x%08x\n", ret);
- break;
-
- case Timer:
- ret = (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - s->TCTR_base) /
- PCI_PERIOD;
- DPRINTF("TCTR Timer read val=0x%08x\n", ret);
- break;
-
- case FlashReg:
- ret = s->TimerInt;
- DPRINTF("FlashReg TimerInt read val=0x%08x\n", ret);
- break;
-
- default:
- DPRINTF("ioport read(l) addr=0x%x via read(b)\n", addr);
-
- ret = rtl8139_io_readb(opaque, addr);
- ret |= rtl8139_io_readb(opaque, addr + 1) << 8;
- ret |= rtl8139_io_readb(opaque, addr + 2) << 16;
- ret |= rtl8139_io_readb(opaque, addr + 3) << 24;
-
- DPRINTF("read(l) addr=0x%x val=%08x\n", addr, ret);
- break;
- }
-
- return ret;
-}
-
-/* */
-
-static void rtl8139_mmio_writeb(void *opaque, hwaddr addr, uint32_t val)
-{
- rtl8139_io_writeb(opaque, addr & 0xFF, val);
-}
-
-static void rtl8139_mmio_writew(void *opaque, hwaddr addr, uint32_t val)
-{
- rtl8139_io_writew(opaque, addr & 0xFF, val);
-}
-
-static void rtl8139_mmio_writel(void *opaque, hwaddr addr, uint32_t val)
-{
- rtl8139_io_writel(opaque, addr & 0xFF, val);
-}
-
-static uint32_t rtl8139_mmio_readb(void *opaque, hwaddr addr)
-{
- return rtl8139_io_readb(opaque, addr & 0xFF);
-}
-
-static uint32_t rtl8139_mmio_readw(void *opaque, hwaddr addr)
-{
- uint32_t val = rtl8139_io_readw(opaque, addr & 0xFF);
- return val;
-}
-
-static uint32_t rtl8139_mmio_readl(void *opaque, hwaddr addr)
-{
- uint32_t val = rtl8139_io_readl(opaque, addr & 0xFF);
- return val;
-}
-
-static int rtl8139_post_load(void *opaque, int version_id)
-{
- RTL8139State* s = opaque;
- rtl8139_set_next_tctr_time(s);
- if (version_id < 4) {
- s->cplus_enabled = s->CpCmd != 0;
- }
-
- /* nc.link_down can't be migrated, so infer link_down according
- * to link status bit in BasicModeStatus */
- qemu_get_queue(s->nic)->link_down = (s->BasicModeStatus & 0x04) == 0;
-
- return 0;
-}
-
-static bool rtl8139_hotplug_ready_needed(void *opaque)
-{
- return qdev_machine_modified();
-}
-
-static const VMStateDescription vmstate_rtl8139_hotplug_ready ={
- .name = "rtl8139/hotplug_ready",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = rtl8139_hotplug_ready_needed,
- .fields = (VMStateField[]) {
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void rtl8139_pre_save(void *opaque)
-{
- RTL8139State* s = opaque;
- int64_t current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-
- /* for migration to older versions */
- s->TCTR = (current_time - s->TCTR_base) / PCI_PERIOD;
- s->rtl8139_mmio_io_addr_dummy = 0;
-}
-
-static const VMStateDescription vmstate_rtl8139 = {
- .name = "rtl8139",
- .version_id = 4,
- .minimum_version_id = 3,
- .post_load = rtl8139_post_load,
- .pre_save = rtl8139_pre_save,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(parent_obj, RTL8139State),
- VMSTATE_PARTIAL_BUFFER(phys, RTL8139State, 6),
- VMSTATE_BUFFER(mult, RTL8139State),
- VMSTATE_UINT32_ARRAY(TxStatus, RTL8139State, 4),
- VMSTATE_UINT32_ARRAY(TxAddr, RTL8139State, 4),
-
- VMSTATE_UINT32(RxBuf, RTL8139State),
- VMSTATE_UINT32(RxBufferSize, RTL8139State),
- VMSTATE_UINT32(RxBufPtr, RTL8139State),
- VMSTATE_UINT32(RxBufAddr, RTL8139State),
-
- VMSTATE_UINT16(IntrStatus, RTL8139State),
- VMSTATE_UINT16(IntrMask, RTL8139State),
-
- VMSTATE_UINT32(TxConfig, RTL8139State),
- VMSTATE_UINT32(RxConfig, RTL8139State),
- VMSTATE_UINT32(RxMissed, RTL8139State),
- VMSTATE_UINT16(CSCR, RTL8139State),
-
- VMSTATE_UINT8(Cfg9346, RTL8139State),
- VMSTATE_UINT8(Config0, RTL8139State),
- VMSTATE_UINT8(Config1, RTL8139State),
- VMSTATE_UINT8(Config3, RTL8139State),
- VMSTATE_UINT8(Config4, RTL8139State),
- VMSTATE_UINT8(Config5, RTL8139State),
-
- VMSTATE_UINT8(clock_enabled, RTL8139State),
- VMSTATE_UINT8(bChipCmdState, RTL8139State),
-
- VMSTATE_UINT16(MultiIntr, RTL8139State),
-
- VMSTATE_UINT16(BasicModeCtrl, RTL8139State),
- VMSTATE_UINT16(BasicModeStatus, RTL8139State),
- VMSTATE_UINT16(NWayAdvert, RTL8139State),
- VMSTATE_UINT16(NWayLPAR, RTL8139State),
- VMSTATE_UINT16(NWayExpansion, RTL8139State),
-
- VMSTATE_UINT16(CpCmd, RTL8139State),
- VMSTATE_UINT8(TxThresh, RTL8139State),
-
- VMSTATE_UNUSED(4),
- VMSTATE_MACADDR(conf.macaddr, RTL8139State),
- VMSTATE_INT32(rtl8139_mmio_io_addr_dummy, RTL8139State),
-
- VMSTATE_UINT32(currTxDesc, RTL8139State),
- VMSTATE_UINT32(currCPlusRxDesc, RTL8139State),
- VMSTATE_UINT32(currCPlusTxDesc, RTL8139State),
- VMSTATE_UINT32(RxRingAddrLO, RTL8139State),
- VMSTATE_UINT32(RxRingAddrHI, RTL8139State),
-
- VMSTATE_UINT16_ARRAY(eeprom.contents, RTL8139State, EEPROM_9346_SIZE),
- VMSTATE_INT32(eeprom.mode, RTL8139State),
- VMSTATE_UINT32(eeprom.tick, RTL8139State),
- VMSTATE_UINT8(eeprom.address, RTL8139State),
- VMSTATE_UINT16(eeprom.input, RTL8139State),
- VMSTATE_UINT16(eeprom.output, RTL8139State),
-
- VMSTATE_UINT8(eeprom.eecs, RTL8139State),
- VMSTATE_UINT8(eeprom.eesk, RTL8139State),
- VMSTATE_UINT8(eeprom.eedi, RTL8139State),
- VMSTATE_UINT8(eeprom.eedo, RTL8139State),
-
- VMSTATE_UINT32(TCTR, RTL8139State),
- VMSTATE_UINT32(TimerInt, RTL8139State),
- VMSTATE_INT64(TCTR_base, RTL8139State),
-
- VMSTATE_STRUCT(tally_counters, RTL8139State, 0,
- vmstate_tally_counters, RTL8139TallyCounters),
-
- VMSTATE_UINT32_V(cplus_enabled, RTL8139State, 4),
- VMSTATE_END_OF_LIST()
- },
- .subsections = (const VMStateDescription*[]) {
- &vmstate_rtl8139_hotplug_ready,
- NULL
- }
-};
-
-/***********************************************************/
-/* PCI RTL8139 definitions */
-
-static void rtl8139_ioport_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- switch (size) {
- case 1:
- rtl8139_io_writeb(opaque, addr, val);
- break;
- case 2:
- rtl8139_io_writew(opaque, addr, val);
- break;
- case 4:
- rtl8139_io_writel(opaque, addr, val);
- break;
- }
-}
-
-static uint64_t rtl8139_ioport_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- switch (size) {
- case 1:
- return rtl8139_io_readb(opaque, addr);
- case 2:
- return rtl8139_io_readw(opaque, addr);
- case 4:
- return rtl8139_io_readl(opaque, addr);
- }
-
- return -1;
-}
-
-static const MemoryRegionOps rtl8139_io_ops = {
- .read = rtl8139_ioport_read,
- .write = rtl8139_ioport_write,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 4,
- },
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static const MemoryRegionOps rtl8139_mmio_ops = {
- .old_mmio = {
- .read = {
- rtl8139_mmio_readb,
- rtl8139_mmio_readw,
- rtl8139_mmio_readl,
- },
- .write = {
- rtl8139_mmio_writeb,
- rtl8139_mmio_writew,
- rtl8139_mmio_writel,
- },
- },
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void rtl8139_timer(void *opaque)
-{
- RTL8139State *s = opaque;
-
- if (!s->clock_enabled)
- {
- DPRINTF(">>> timer: clock is not running\n");
- return;
- }
-
- s->IntrStatus |= PCSTimeout;
- rtl8139_update_irq(s);
- rtl8139_set_next_tctr_time(s);
-}
-
-static void pci_rtl8139_uninit(PCIDevice *dev)
-{
- RTL8139State *s = RTL8139(dev);
-
- g_free(s->cplus_txbuffer);
- s->cplus_txbuffer = NULL;
- timer_del(s->timer);
- timer_free(s->timer);
- qemu_del_nic(s->nic);
-}
-
-static void rtl8139_set_link_status(NetClientState *nc)
-{
- RTL8139State *s = qemu_get_nic_opaque(nc);
-
- if (nc->link_down) {
- s->BasicModeStatus &= ~0x04;
- } else {
- s->BasicModeStatus |= 0x04;
- }
-
- s->IntrStatus |= RxUnderrun;
- rtl8139_update_irq(s);
-}
-
-static NetClientInfo net_rtl8139_info = {
- .type = NET_CLIENT_OPTIONS_KIND_NIC,
- .size = sizeof(NICState),
- .can_receive = rtl8139_can_receive,
- .receive = rtl8139_receive,
- .link_status_changed = rtl8139_set_link_status,
-};
-
-static void pci_rtl8139_realize(PCIDevice *dev, Error **errp)
-{
- RTL8139State *s = RTL8139(dev);
- DeviceState *d = DEVICE(dev);
- uint8_t *pci_conf;
-
- pci_conf = dev->config;
- pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */
- /* TODO: start of capability list, but no capability
- * list bit in status register, and offset 0xdc seems unused. */
- pci_conf[PCI_CAPABILITY_LIST] = 0xdc;
-
- memory_region_init_io(&s->bar_io, OBJECT(s), &rtl8139_io_ops, s,
- "rtl8139", 0x100);
- memory_region_init_io(&s->bar_mem, OBJECT(s), &rtl8139_mmio_ops, s,
- "rtl8139", 0x100);
- pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->bar_io);
- pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar_mem);
-
- qemu_macaddr_default_if_unset(&s->conf.macaddr);
-
- /* prepare eeprom */
- s->eeprom.contents[0] = 0x8129;
-#if 1
- /* PCI vendor and device ID should be mirrored here */
- s->eeprom.contents[1] = PCI_VENDOR_ID_REALTEK;
- s->eeprom.contents[2] = PCI_DEVICE_ID_REALTEK_8139;
-#endif
- s->eeprom.contents[7] = s->conf.macaddr.a[0] | s->conf.macaddr.a[1] << 8;
- s->eeprom.contents[8] = s->conf.macaddr.a[2] | s->conf.macaddr.a[3] << 8;
- s->eeprom.contents[9] = s->conf.macaddr.a[4] | s->conf.macaddr.a[5] << 8;
-
- s->nic = qemu_new_nic(&net_rtl8139_info, &s->conf,
- object_get_typename(OBJECT(dev)), d->id, s);
- qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-
- s->cplus_txbuffer = NULL;
- s->cplus_txbuffer_len = 0;
- s->cplus_txbuffer_offset = 0;
-
- s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, rtl8139_timer, s);
-}
-
-static void rtl8139_instance_init(Object *obj)
-{
- RTL8139State *s = RTL8139(obj);
-
- device_add_bootindex_property(obj, &s->conf.bootindex,
- "bootindex", "/ethernet-phy@0",
- DEVICE(obj), NULL);
-}
-
-static Property rtl8139_properties[] = {
- DEFINE_NIC_PROPERTIES(RTL8139State, conf),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void rtl8139_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = pci_rtl8139_realize;
- k->exit = pci_rtl8139_uninit;
- k->romfile = "efi-rtl8139.rom";
- k->vendor_id = PCI_VENDOR_ID_REALTEK;
- k->device_id = PCI_DEVICE_ID_REALTEK_8139;
- k->revision = RTL8139_PCI_REVID; /* >=0x20 is for 8139C+ */
- k->class_id = PCI_CLASS_NETWORK_ETHERNET;
- dc->reset = rtl8139_reset;
- dc->vmsd = &vmstate_rtl8139;
- dc->props = rtl8139_properties;
- set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
-}
-
-static const TypeInfo rtl8139_info = {
- .name = TYPE_RTL8139,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(RTL8139State),
- .class_init = rtl8139_class_init,
- .instance_init = rtl8139_instance_init,
-};
-
-static void rtl8139_register_types(void)
-{
- type_register_static(&rtl8139_info);
-}
-
-type_init(rtl8139_register_types)
diff --git a/qemu/hw/net/smc91c111.c b/qemu/hw/net/smc91c111.c
deleted file mode 100644
index 21c1b8f54..000000000
--- a/qemu/hw/net/smc91c111.c
+++ /dev/null
@@ -1,825 +0,0 @@
-/*
- * SMSC 91C111 Ethernet interface emulation
- *
- * Copyright (c) 2005 CodeSourcery, LLC.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "net/net.h"
-#include "hw/devices.h"
-/* For crc32 */
-#include <zlib.h>
-
-/* Number of 2k memory pages available. */
-#define NUM_PACKETS 4
-
-#define TYPE_SMC91C111 "smc91c111"
-#define SMC91C111(obj) OBJECT_CHECK(smc91c111_state, (obj), TYPE_SMC91C111)
-
-typedef struct {
- SysBusDevice parent_obj;
-
- NICState *nic;
- NICConf conf;
- uint16_t tcr;
- uint16_t rcr;
- uint16_t cr;
- uint16_t ctr;
- uint16_t gpr;
- uint16_t ptr;
- uint16_t ercv;
- qemu_irq irq;
- int bank;
- int packet_num;
- int tx_alloc;
- /* Bitmask of allocated packets. */
- int allocated;
- int tx_fifo_len;
- int tx_fifo[NUM_PACKETS];
- int rx_fifo_len;
- int rx_fifo[NUM_PACKETS];
- int tx_fifo_done_len;
- int tx_fifo_done[NUM_PACKETS];
- /* Packet buffer memory. */
- uint8_t data[NUM_PACKETS][2048];
- uint8_t int_level;
- uint8_t int_mask;
- MemoryRegion mmio;
-} smc91c111_state;
-
-static const VMStateDescription vmstate_smc91c111 = {
- .name = "smc91c111",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT16(tcr, smc91c111_state),
- VMSTATE_UINT16(rcr, smc91c111_state),
- VMSTATE_UINT16(cr, smc91c111_state),
- VMSTATE_UINT16(ctr, smc91c111_state),
- VMSTATE_UINT16(gpr, smc91c111_state),
- VMSTATE_UINT16(ptr, smc91c111_state),
- VMSTATE_UINT16(ercv, smc91c111_state),
- VMSTATE_INT32(bank, smc91c111_state),
- VMSTATE_INT32(packet_num, smc91c111_state),
- VMSTATE_INT32(tx_alloc, smc91c111_state),
- VMSTATE_INT32(allocated, smc91c111_state),
- VMSTATE_INT32(tx_fifo_len, smc91c111_state),
- VMSTATE_INT32_ARRAY(tx_fifo, smc91c111_state, NUM_PACKETS),
- VMSTATE_INT32(rx_fifo_len, smc91c111_state),
- VMSTATE_INT32_ARRAY(rx_fifo, smc91c111_state, NUM_PACKETS),
- VMSTATE_INT32(tx_fifo_done_len, smc91c111_state),
- VMSTATE_INT32_ARRAY(tx_fifo_done, smc91c111_state, NUM_PACKETS),
- VMSTATE_BUFFER_UNSAFE(data, smc91c111_state, 0, NUM_PACKETS * 2048),
- VMSTATE_UINT8(int_level, smc91c111_state),
- VMSTATE_UINT8(int_mask, smc91c111_state),
- VMSTATE_END_OF_LIST()
- }
-};
-
-#define RCR_SOFT_RST 0x8000
-#define RCR_STRIP_CRC 0x0200
-#define RCR_RXEN 0x0100
-
-#define TCR_EPH_LOOP 0x2000
-#define TCR_NOCRC 0x0100
-#define TCR_PAD_EN 0x0080
-#define TCR_FORCOL 0x0004
-#define TCR_LOOP 0x0002
-#define TCR_TXEN 0x0001
-
-#define INT_MD 0x80
-#define INT_ERCV 0x40
-#define INT_EPH 0x20
-#define INT_RX_OVRN 0x10
-#define INT_ALLOC 0x08
-#define INT_TX_EMPTY 0x04
-#define INT_TX 0x02
-#define INT_RCV 0x01
-
-#define CTR_AUTO_RELEASE 0x0800
-#define CTR_RELOAD 0x0002
-#define CTR_STORE 0x0001
-
-#define RS_ALGNERR 0x8000
-#define RS_BRODCAST 0x4000
-#define RS_BADCRC 0x2000
-#define RS_ODDFRAME 0x1000
-#define RS_TOOLONG 0x0800
-#define RS_TOOSHORT 0x0400
-#define RS_MULTICAST 0x0001
-
-/* Update interrupt status. */
-static void smc91c111_update(smc91c111_state *s)
-{
- int level;
-
- if (s->tx_fifo_len == 0)
- s->int_level |= INT_TX_EMPTY;
- if (s->tx_fifo_done_len != 0)
- s->int_level |= INT_TX;
- level = (s->int_level & s->int_mask) != 0;
- qemu_set_irq(s->irq, level);
-}
-
-static int smc91c111_can_receive(smc91c111_state *s)
-{
- if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST)) {
- return 1;
- }
- if (s->allocated == (1 << NUM_PACKETS) - 1 ||
- s->rx_fifo_len == NUM_PACKETS) {
- return 0;
- }
- return 1;
-}
-
-static inline void smc91c111_flush_queued_packets(smc91c111_state *s)
-{
- if (smc91c111_can_receive(s)) {
- qemu_flush_queued_packets(qemu_get_queue(s->nic));
- }
-}
-
-/* Try to allocate a packet. Returns 0x80 on failure. */
-static int smc91c111_allocate_packet(smc91c111_state *s)
-{
- int i;
- if (s->allocated == (1 << NUM_PACKETS) - 1) {
- return 0x80;
- }
-
- for (i = 0; i < NUM_PACKETS; i++) {
- if ((s->allocated & (1 << i)) == 0)
- break;
- }
- s->allocated |= 1 << i;
- return i;
-}
-
-
-/* Process a pending TX allocate. */
-static void smc91c111_tx_alloc(smc91c111_state *s)
-{
- s->tx_alloc = smc91c111_allocate_packet(s);
- if (s->tx_alloc == 0x80)
- return;
- s->int_level |= INT_ALLOC;
- smc91c111_update(s);
-}
-
-/* Remove and item from the RX FIFO. */
-static void smc91c111_pop_rx_fifo(smc91c111_state *s)
-{
- int i;
-
- s->rx_fifo_len--;
- if (s->rx_fifo_len) {
- for (i = 0; i < s->rx_fifo_len; i++)
- s->rx_fifo[i] = s->rx_fifo[i + 1];
- s->int_level |= INT_RCV;
- } else {
- s->int_level &= ~INT_RCV;
- }
- smc91c111_flush_queued_packets(s);
- smc91c111_update(s);
-}
-
-/* Remove an item from the TX completion FIFO. */
-static void smc91c111_pop_tx_fifo_done(smc91c111_state *s)
-{
- int i;
-
- if (s->tx_fifo_done_len == 0)
- return;
- s->tx_fifo_done_len--;
- for (i = 0; i < s->tx_fifo_done_len; i++)
- s->tx_fifo_done[i] = s->tx_fifo_done[i + 1];
-}
-
-/* Release the memory allocated to a packet. */
-static void smc91c111_release_packet(smc91c111_state *s, int packet)
-{
- s->allocated &= ~(1 << packet);
- if (s->tx_alloc == 0x80)
- smc91c111_tx_alloc(s);
- smc91c111_flush_queued_packets(s);
-}
-
-/* Flush the TX FIFO. */
-static void smc91c111_do_tx(smc91c111_state *s)
-{
- int i;
- int len;
- int control;
- int packetnum;
- uint8_t *p;
-
- if ((s->tcr & TCR_TXEN) == 0)
- return;
- if (s->tx_fifo_len == 0)
- return;
- for (i = 0; i < s->tx_fifo_len; i++) {
- packetnum = s->tx_fifo[i];
- p = &s->data[packetnum][0];
- /* Set status word. */
- *(p++) = 0x01;
- *(p++) = 0x40;
- len = *(p++);
- len |= ((int)*(p++)) << 8;
- len -= 6;
- control = p[len + 1];
- if (control & 0x20)
- len++;
- /* ??? This overwrites the data following the buffer.
- Don't know what real hardware does. */
- if (len < 64 && (s->tcr & TCR_PAD_EN)) {
- memset(p + len, 0, 64 - len);
- len = 64;
- }
-#if 0
- {
- int add_crc;
-
- /* The card is supposed to append the CRC to the frame.
- However none of the other network traffic has the CRC
- appended. Suspect this is low level ethernet detail we
- don't need to worry about. */
- add_crc = (control & 0x10) || (s->tcr & TCR_NOCRC) == 0;
- if (add_crc) {
- uint32_t crc;
-
- crc = crc32(~0, p, len);
- memcpy(p + len, &crc, 4);
- len += 4;
- }
- }
-#endif
- if (s->ctr & CTR_AUTO_RELEASE)
- /* Race? */
- smc91c111_release_packet(s, packetnum);
- else if (s->tx_fifo_done_len < NUM_PACKETS)
- s->tx_fifo_done[s->tx_fifo_done_len++] = packetnum;
- qemu_send_packet(qemu_get_queue(s->nic), p, len);
- }
- s->tx_fifo_len = 0;
- smc91c111_update(s);
-}
-
-/* Add a packet to the TX FIFO. */
-static void smc91c111_queue_tx(smc91c111_state *s, int packet)
-{
- if (s->tx_fifo_len == NUM_PACKETS)
- return;
- s->tx_fifo[s->tx_fifo_len++] = packet;
- smc91c111_do_tx(s);
-}
-
-static void smc91c111_reset(DeviceState *dev)
-{
- smc91c111_state *s = SMC91C111(dev);
-
- s->bank = 0;
- s->tx_fifo_len = 0;
- s->tx_fifo_done_len = 0;
- s->rx_fifo_len = 0;
- s->allocated = 0;
- s->packet_num = 0;
- s->tx_alloc = 0;
- s->tcr = 0;
- s->rcr = 0;
- s->cr = 0xa0b1;
- s->ctr = 0x1210;
- s->ptr = 0;
- s->ercv = 0x1f;
- s->int_level = INT_TX_EMPTY;
- s->int_mask = 0;
- smc91c111_update(s);
-}
-
-#define SET_LOW(name, val) s->name = (s->name & 0xff00) | val
-#define SET_HIGH(name, val) s->name = (s->name & 0xff) | (val << 8)
-
-static void smc91c111_writeb(void *opaque, hwaddr offset,
- uint32_t value)
-{
- smc91c111_state *s = (smc91c111_state *)opaque;
-
- offset = offset & 0xf;
- if (offset == 14) {
- s->bank = value;
- return;
- }
- if (offset == 15)
- return;
- switch (s->bank) {
- case 0:
- switch (offset) {
- case 0: /* TCR */
- SET_LOW(tcr, value);
- return;
- case 1:
- SET_HIGH(tcr, value);
- return;
- case 4: /* RCR */
- SET_LOW(rcr, value);
- return;
- case 5:
- SET_HIGH(rcr, value);
- if (s->rcr & RCR_SOFT_RST) {
- smc91c111_reset(DEVICE(s));
- }
- smc91c111_flush_queued_packets(s);
- return;
- case 10: case 11: /* RPCR */
- /* Ignored */
- return;
- case 12: case 13: /* Reserved */
- return;
- }
- break;
-
- case 1:
- switch (offset) {
- case 0: /* CONFIG */
- SET_LOW(cr, value);
- return;
- case 1:
- SET_HIGH(cr,value);
- return;
- case 2: case 3: /* BASE */
- case 4: case 5: case 6: case 7: case 8: case 9: /* IA */
- /* Not implemented. */
- return;
- case 10: /* Genral Purpose */
- SET_LOW(gpr, value);
- return;
- case 11:
- SET_HIGH(gpr, value);
- return;
- case 12: /* Control */
- if (value & 1)
- fprintf(stderr, "smc91c111:EEPROM store not implemented\n");
- if (value & 2)
- fprintf(stderr, "smc91c111:EEPROM reload not implemented\n");
- value &= ~3;
- SET_LOW(ctr, value);
- return;
- case 13:
- SET_HIGH(ctr, value);
- return;
- }
- break;
-
- case 2:
- switch (offset) {
- case 0: /* MMU Command */
- switch (value >> 5) {
- case 0: /* no-op */
- break;
- case 1: /* Allocate for TX. */
- s->tx_alloc = 0x80;
- s->int_level &= ~INT_ALLOC;
- smc91c111_update(s);
- smc91c111_tx_alloc(s);
- break;
- case 2: /* Reset MMU. */
- s->allocated = 0;
- s->tx_fifo_len = 0;
- s->tx_fifo_done_len = 0;
- s->rx_fifo_len = 0;
- s->tx_alloc = 0;
- break;
- case 3: /* Remove from RX FIFO. */
- smc91c111_pop_rx_fifo(s);
- break;
- case 4: /* Remove from RX FIFO and release. */
- if (s->rx_fifo_len > 0) {
- smc91c111_release_packet(s, s->rx_fifo[0]);
- }
- smc91c111_pop_rx_fifo(s);
- break;
- case 5: /* Release. */
- smc91c111_release_packet(s, s->packet_num);
- break;
- case 6: /* Add to TX FIFO. */
- smc91c111_queue_tx(s, s->packet_num);
- break;
- case 7: /* Reset TX FIFO. */
- s->tx_fifo_len = 0;
- s->tx_fifo_done_len = 0;
- break;
- }
- return;
- case 1:
- /* Ignore. */
- return;
- case 2: /* Packet Number Register */
- s->packet_num = value;
- return;
- case 3: case 4: case 5:
- /* Should be readonly, but linux writes to them anyway. Ignore. */
- return;
- case 6: /* Pointer */
- SET_LOW(ptr, value);
- return;
- case 7:
- SET_HIGH(ptr, value);
- return;
- case 8: case 9: case 10: case 11: /* Data */
- {
- int p;
- int n;
-
- if (s->ptr & 0x8000)
- n = s->rx_fifo[0];
- else
- n = s->packet_num;
- p = s->ptr & 0x07ff;
- if (s->ptr & 0x4000) {
- s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x7ff);
- } else {
- p += (offset & 3);
- }
- s->data[n][p] = value;
- }
- return;
- case 12: /* Interrupt ACK. */
- s->int_level &= ~(value & 0xd6);
- if (value & INT_TX)
- smc91c111_pop_tx_fifo_done(s);
- smc91c111_update(s);
- return;
- case 13: /* Interrupt mask. */
- s->int_mask = value;
- smc91c111_update(s);
- return;
- }
- break;
-
- case 3:
- switch (offset) {
- case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
- /* Multicast table. */
- /* Not implemented. */
- return;
- case 8: case 9: /* Management Interface. */
- /* Not implemented. */
- return;
- case 12: /* Early receive. */
- s->ercv = value & 0x1f;
- return;
- case 13:
- /* Ignore. */
- return;
- }
- break;
- }
- hw_error("smc91c111_write: Bad reg %d:%x\n", s->bank, (int)offset);
-}
-
-static uint32_t smc91c111_readb(void *opaque, hwaddr offset)
-{
- smc91c111_state *s = (smc91c111_state *)opaque;
-
- offset = offset & 0xf;
- if (offset == 14) {
- return s->bank;
- }
- if (offset == 15)
- return 0x33;
- switch (s->bank) {
- case 0:
- switch (offset) {
- case 0: /* TCR */
- return s->tcr & 0xff;
- case 1:
- return s->tcr >> 8;
- case 2: /* EPH Status */
- return 0;
- case 3:
- return 0x40;
- case 4: /* RCR */
- return s->rcr & 0xff;
- case 5:
- return s->rcr >> 8;
- case 6: /* Counter */
- case 7:
- /* Not implemented. */
- return 0;
- case 8: /* Memory size. */
- return NUM_PACKETS;
- case 9: /* Free memory available. */
- {
- int i;
- int n;
- n = 0;
- for (i = 0; i < NUM_PACKETS; i++) {
- if (s->allocated & (1 << i))
- n++;
- }
- return n;
- }
- case 10: case 11: /* RPCR */
- /* Not implemented. */
- return 0;
- case 12: case 13: /* Reserved */
- return 0;
- }
- break;
-
- case 1:
- switch (offset) {
- case 0: /* CONFIG */
- return s->cr & 0xff;
- case 1:
- return s->cr >> 8;
- case 2: case 3: /* BASE */
- /* Not implemented. */
- return 0;
- case 4: case 5: case 6: case 7: case 8: case 9: /* IA */
- return s->conf.macaddr.a[offset - 4];
- case 10: /* General Purpose */
- return s->gpr & 0xff;
- case 11:
- return s->gpr >> 8;
- case 12: /* Control */
- return s->ctr & 0xff;
- case 13:
- return s->ctr >> 8;
- }
- break;
-
- case 2:
- switch (offset) {
- case 0: case 1: /* MMUCR Busy bit. */
- return 0;
- case 2: /* Packet Number. */
- return s->packet_num;
- case 3: /* Allocation Result. */
- return s->tx_alloc;
- case 4: /* TX FIFO */
- if (s->tx_fifo_done_len == 0)
- return 0x80;
- else
- return s->tx_fifo_done[0];
- case 5: /* RX FIFO */
- if (s->rx_fifo_len == 0)
- return 0x80;
- else
- return s->rx_fifo[0];
- case 6: /* Pointer */
- return s->ptr & 0xff;
- case 7:
- return (s->ptr >> 8) & 0xf7;
- case 8: case 9: case 10: case 11: /* Data */
- {
- int p;
- int n;
-
- if (s->ptr & 0x8000)
- n = s->rx_fifo[0];
- else
- n = s->packet_num;
- p = s->ptr & 0x07ff;
- if (s->ptr & 0x4000) {
- s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x07ff);
- } else {
- p += (offset & 3);
- }
- return s->data[n][p];
- }
- case 12: /* Interrupt status. */
- return s->int_level;
- case 13: /* Interrupt mask. */
- return s->int_mask;
- }
- break;
-
- case 3:
- switch (offset) {
- case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
- /* Multicast table. */
- /* Not implemented. */
- return 0;
- case 8: /* Management Interface. */
- /* Not implemented. */
- return 0x30;
- case 9:
- return 0x33;
- case 10: /* Revision. */
- return 0x91;
- case 11:
- return 0x33;
- case 12:
- return s->ercv;
- case 13:
- return 0;
- }
- break;
- }
- hw_error("smc91c111_read: Bad reg %d:%x\n", s->bank, (int)offset);
- return 0;
-}
-
-static void smc91c111_writew(void *opaque, hwaddr offset,
- uint32_t value)
-{
- smc91c111_writeb(opaque, offset, value & 0xff);
- smc91c111_writeb(opaque, offset + 1, value >> 8);
-}
-
-static void smc91c111_writel(void *opaque, hwaddr offset,
- uint32_t value)
-{
- /* 32-bit writes to offset 0xc only actually write to the bank select
- register (offset 0xe) */
- if (offset != 0xc)
- smc91c111_writew(opaque, offset, value & 0xffff);
- smc91c111_writew(opaque, offset + 2, value >> 16);
-}
-
-static uint32_t smc91c111_readw(void *opaque, hwaddr offset)
-{
- uint32_t val;
- val = smc91c111_readb(opaque, offset);
- val |= smc91c111_readb(opaque, offset + 1) << 8;
- return val;
-}
-
-static uint32_t smc91c111_readl(void *opaque, hwaddr offset)
-{
- uint32_t val;
- val = smc91c111_readw(opaque, offset);
- val |= smc91c111_readw(opaque, offset + 2) << 16;
- return val;
-}
-
-static int smc91c111_can_receive_nc(NetClientState *nc)
-{
- smc91c111_state *s = qemu_get_nic_opaque(nc);
-
- return smc91c111_can_receive(s);
-}
-
-static ssize_t smc91c111_receive(NetClientState *nc, const uint8_t *buf, size_t size)
-{
- smc91c111_state *s = qemu_get_nic_opaque(nc);
- int status;
- int packetsize;
- uint32_t crc;
- int packetnum;
- uint8_t *p;
-
- if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST))
- return -1;
- /* Short packets are padded with zeros. Receiving a packet
- < 64 bytes long is considered an error condition. */
- if (size < 64)
- packetsize = 64;
- else
- packetsize = (size & ~1);
- packetsize += 6;
- crc = (s->rcr & RCR_STRIP_CRC) == 0;
- if (crc)
- packetsize += 4;
- /* TODO: Flag overrun and receive errors. */
- if (packetsize > 2048)
- return -1;
- packetnum = smc91c111_allocate_packet(s);
- if (packetnum == 0x80)
- return -1;
- s->rx_fifo[s->rx_fifo_len++] = packetnum;
-
- p = &s->data[packetnum][0];
- /* ??? Multicast packets? */
- status = 0;
- if (size > 1518)
- status |= RS_TOOLONG;
- if (size & 1)
- status |= RS_ODDFRAME;
- *(p++) = status & 0xff;
- *(p++) = status >> 8;
- *(p++) = packetsize & 0xff;
- *(p++) = packetsize >> 8;
- memcpy(p, buf, size & ~1);
- p += (size & ~1);
- /* Pad short packets. */
- if (size < 64) {
- int pad;
-
- if (size & 1)
- *(p++) = buf[size - 1];
- pad = 64 - size;
- memset(p, 0, pad);
- p += pad;
- size = 64;
- }
- /* It's not clear if the CRC should go before or after the last byte in
- odd sized packets. Linux disables the CRC, so that's no help.
- The pictures in the documentation show the CRC aligned on a 16-bit
- boundary before the last odd byte, so that's what we do. */
- if (crc) {
- crc = crc32(~0, buf, size);
- *(p++) = crc & 0xff; crc >>= 8;
- *(p++) = crc & 0xff; crc >>= 8;
- *(p++) = crc & 0xff; crc >>= 8;
- *(p++) = crc & 0xff;
- }
- if (size & 1) {
- *(p++) = buf[size - 1];
- *p = 0x60;
- } else {
- *(p++) = 0;
- *p = 0x40;
- }
- /* TODO: Raise early RX interrupt? */
- s->int_level |= INT_RCV;
- smc91c111_update(s);
-
- return size;
-}
-
-static const MemoryRegionOps smc91c111_mem_ops = {
- /* The special case for 32 bit writes to 0xc means we can't just
- * set .impl.min/max_access_size to 1, unfortunately
- */
- .old_mmio = {
- .read = { smc91c111_readb, smc91c111_readw, smc91c111_readl, },
- .write = { smc91c111_writeb, smc91c111_writew, smc91c111_writel, },
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static NetClientInfo net_smc91c111_info = {
- .type = NET_CLIENT_OPTIONS_KIND_NIC,
- .size = sizeof(NICState),
- .can_receive = smc91c111_can_receive_nc,
- .receive = smc91c111_receive,
-};
-
-static int smc91c111_init1(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- smc91c111_state *s = SMC91C111(dev);
-
- memory_region_init_io(&s->mmio, OBJECT(s), &smc91c111_mem_ops, s,
- "smc91c111-mmio", 16);
- sysbus_init_mmio(sbd, &s->mmio);
- sysbus_init_irq(sbd, &s->irq);
- qemu_macaddr_default_if_unset(&s->conf.macaddr);
- s->nic = qemu_new_nic(&net_smc91c111_info, &s->conf,
- object_get_typename(OBJECT(dev)), dev->id, s);
- qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
- /* ??? Save/restore. */
- return 0;
-}
-
-static Property smc91c111_properties[] = {
- DEFINE_NIC_PROPERTIES(smc91c111_state, conf),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void smc91c111_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = smc91c111_init1;
- dc->reset = smc91c111_reset;
- dc->vmsd = &vmstate_smc91c111;
- dc->props = smc91c111_properties;
-}
-
-static const TypeInfo smc91c111_info = {
- .name = TYPE_SMC91C111,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(smc91c111_state),
- .class_init = smc91c111_class_init,
-};
-
-static void smc91c111_register_types(void)
-{
- type_register_static(&smc91c111_info);
-}
-
-/* Legacy helper function. Should go away when machine config files are
- implemented. */
-void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq)
-{
- DeviceState *dev;
- SysBusDevice *s;
-
- qemu_check_nic_model(nd, "smc91c111");
- dev = qdev_create(NULL, TYPE_SMC91C111);
- qdev_set_nic_properties(dev, nd);
- qdev_init_nofail(dev);
- s = SYS_BUS_DEVICE(dev);
- sysbus_mmio_map(s, 0, base);
- sysbus_connect_irq(s, 0, irq);
-}
-
-type_init(smc91c111_register_types)
diff --git a/qemu/hw/net/spapr_llan.c b/qemu/hw/net/spapr_llan.c
deleted file mode 100644
index a647f25d9..000000000
--- a/qemu/hw/net/spapr_llan.c
+++ /dev/null
@@ -1,820 +0,0 @@
-/*
- * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
- *
- * PAPR Inter-VM Logical Lan, aka ibmveth
- *
- * Copyright (c) 2010,2011 David Gibson, IBM Corporation.
- *
- * 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.
- *
- */
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/hw.h"
-#include "net/net.h"
-#include "hw/qdev.h"
-#include "hw/ppc/spapr.h"
-#include "hw/ppc/spapr_vio.h"
-#include "sysemu/sysemu.h"
-
-#include <libfdt.h>
-
-#define ETH_ALEN 6
-#define MAX_PACKET_SIZE 65536
-
-/*#define DEBUG*/
-
-#ifdef DEBUG
-#define DPRINTF(fmt...) do { fprintf(stderr, fmt); } while (0)
-#else
-#define DPRINTF(fmt...)
-#endif
-
-/* Compatibility flags for migration */
-#define SPAPRVLAN_FLAG_RX_BUF_POOLS_BIT 0
-#define SPAPRVLAN_FLAG_RX_BUF_POOLS (1 << SPAPRVLAN_FLAG_RX_BUF_POOLS_BIT)
-
-/*
- * Virtual LAN device
- */
-
-typedef uint64_t vlan_bd_t;
-
-#define VLAN_BD_VALID 0x8000000000000000ULL
-#define VLAN_BD_TOGGLE 0x4000000000000000ULL
-#define VLAN_BD_NO_CSUM 0x0200000000000000ULL
-#define VLAN_BD_CSUM_GOOD 0x0100000000000000ULL
-#define VLAN_BD_LEN_MASK 0x00ffffff00000000ULL
-#define VLAN_BD_LEN(bd) (((bd) & VLAN_BD_LEN_MASK) >> 32)
-#define VLAN_BD_ADDR_MASK 0x00000000ffffffffULL
-#define VLAN_BD_ADDR(bd) ((bd) & VLAN_BD_ADDR_MASK)
-
-#define VLAN_VALID_BD(addr, len) (VLAN_BD_VALID | \
- (((len) << 32) & VLAN_BD_LEN_MASK) | \
- (addr & VLAN_BD_ADDR_MASK))
-
-#define VLAN_RXQC_TOGGLE 0x80
-#define VLAN_RXQC_VALID 0x40
-#define VLAN_RXQC_NO_CSUM 0x02
-#define VLAN_RXQC_CSUM_GOOD 0x01
-
-#define VLAN_RQ_ALIGNMENT 16
-#define VLAN_RXQ_BD_OFF 0
-#define VLAN_FILTER_BD_OFF 8
-#define VLAN_RX_BDS_OFF 16
-/*
- * The final 8 bytes of the buffer list is a counter of frames dropped
- * because there was not a buffer in the buffer list capable of holding
- * the frame. We must avoid it, or the operating system will report garbage
- * for this statistic.
- */
-#define VLAN_RX_BDS_LEN (SPAPR_TCE_PAGE_SIZE - VLAN_RX_BDS_OFF - 8)
-#define VLAN_MAX_BUFS (VLAN_RX_BDS_LEN / 8)
-
-#define TYPE_VIO_SPAPR_VLAN_DEVICE "spapr-vlan"
-#define VIO_SPAPR_VLAN_DEVICE(obj) \
- OBJECT_CHECK(VIOsPAPRVLANDevice, (obj), TYPE_VIO_SPAPR_VLAN_DEVICE)
-
-#define RX_POOL_MAX_BDS 4096
-#define RX_MAX_POOLS 5
-
-typedef struct {
- int32_t bufsize;
- int32_t count;
- vlan_bd_t bds[RX_POOL_MAX_BDS];
-} RxBufPool;
-
-typedef struct VIOsPAPRVLANDevice {
- VIOsPAPRDevice sdev;
- NICConf nicconf;
- NICState *nic;
- bool isopen;
- target_ulong buf_list;
- uint32_t add_buf_ptr, use_buf_ptr, rx_bufs;
- target_ulong rxq_ptr;
- uint32_t compat_flags; /* Compatability flags for migration */
- RxBufPool *rx_pool[RX_MAX_POOLS]; /* Receive buffer descriptor pools */
-} VIOsPAPRVLANDevice;
-
-static int spapr_vlan_can_receive(NetClientState *nc)
-{
- VIOsPAPRVLANDevice *dev = qemu_get_nic_opaque(nc);
-
- return (dev->isopen && dev->rx_bufs > 0);
-}
-
-/**
- * Get buffer descriptor from one of our receive buffer pools
- */
-static vlan_bd_t spapr_vlan_get_rx_bd_from_pool(VIOsPAPRVLANDevice *dev,
- size_t size)
-{
- vlan_bd_t bd;
- int pool;
-
- for (pool = 0; pool < RX_MAX_POOLS; pool++) {
- if (dev->rx_pool[pool]->count > 0 &&
- dev->rx_pool[pool]->bufsize >= size + 8) {
- break;
- }
- }
- if (pool == RX_MAX_POOLS) {
- /* Failed to find a suitable buffer */
- return 0;
- }
-
- DPRINTF("Found buffer: pool=%d count=%d rxbufs=%d\n", pool,
- dev->rx_pool[pool]->count, dev->rx_bufs);
-
- /* Remove the buffer from the pool */
- dev->rx_pool[pool]->count--;
- bd = dev->rx_pool[pool]->bds[dev->rx_pool[pool]->count];
- dev->rx_pool[pool]->bds[dev->rx_pool[pool]->count] = 0;
-
- return bd;
-}
-
-/**
- * Get buffer descriptor from the receive buffer list page that has been
- * supplied by the guest with the H_REGISTER_LOGICAL_LAN call
- */
-static vlan_bd_t spapr_vlan_get_rx_bd_from_page(VIOsPAPRVLANDevice *dev,
- size_t size)
-{
- int buf_ptr = dev->use_buf_ptr;
- vlan_bd_t bd;
-
- do {
- buf_ptr += 8;
- if (buf_ptr >= VLAN_RX_BDS_LEN + VLAN_RX_BDS_OFF) {
- buf_ptr = VLAN_RX_BDS_OFF;
- }
-
- bd = vio_ldq(&dev->sdev, dev->buf_list + buf_ptr);
- DPRINTF("use_buf_ptr=%d bd=0x%016llx\n",
- buf_ptr, (unsigned long long)bd);
- } while ((!(bd & VLAN_BD_VALID) || VLAN_BD_LEN(bd) < size + 8)
- && buf_ptr != dev->use_buf_ptr);
-
- if (!(bd & VLAN_BD_VALID) || VLAN_BD_LEN(bd) < size + 8) {
- /* Failed to find a suitable buffer */
- return 0;
- }
-
- /* Remove the buffer from the pool */
- dev->use_buf_ptr = buf_ptr;
- vio_stq(&dev->sdev, dev->buf_list + dev->use_buf_ptr, 0);
-
- DPRINTF("Found buffer: ptr=%d rxbufs=%d\n", dev->use_buf_ptr, dev->rx_bufs);
-
- return bd;
-}
-
-static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf,
- size_t size)
-{
- VIOsPAPRVLANDevice *dev = qemu_get_nic_opaque(nc);
- VIOsPAPRDevice *sdev = VIO_SPAPR_DEVICE(dev);
- vlan_bd_t rxq_bd = vio_ldq(sdev, dev->buf_list + VLAN_RXQ_BD_OFF);
- vlan_bd_t bd;
- uint64_t handle;
- uint8_t control;
-
- DPRINTF("spapr_vlan_receive() [%s] rx_bufs=%d\n", sdev->qdev.id,
- dev->rx_bufs);
-
- if (!dev->isopen) {
- return -1;
- }
-
- if (!dev->rx_bufs) {
- return -1;
- }
-
- if (dev->compat_flags & SPAPRVLAN_FLAG_RX_BUF_POOLS) {
- bd = spapr_vlan_get_rx_bd_from_pool(dev, size);
- } else {
- bd = spapr_vlan_get_rx_bd_from_page(dev, size);
- }
- if (!bd) {
- return -1;
- }
-
- dev->rx_bufs--;
-
- /* Transfer the packet data */
- if (spapr_vio_dma_write(sdev, VLAN_BD_ADDR(bd) + 8, buf, size) < 0) {
- return -1;
- }
-
- DPRINTF("spapr_vlan_receive: DMA write completed\n");
-
- /* Update the receive queue */
- control = VLAN_RXQC_TOGGLE | VLAN_RXQC_VALID;
- if (rxq_bd & VLAN_BD_TOGGLE) {
- control ^= VLAN_RXQC_TOGGLE;
- }
-
- handle = vio_ldq(sdev, VLAN_BD_ADDR(bd));
- vio_stq(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr + 8, handle);
- vio_stl(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr + 4, size);
- vio_sth(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr + 2, 8);
- vio_stb(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr, control);
-
- DPRINTF("wrote rxq entry (ptr=0x%llx): 0x%016llx 0x%016llx\n",
- (unsigned long long)dev->rxq_ptr,
- (unsigned long long)vio_ldq(sdev, VLAN_BD_ADDR(rxq_bd) +
- dev->rxq_ptr),
- (unsigned long long)vio_ldq(sdev, VLAN_BD_ADDR(rxq_bd) +
- dev->rxq_ptr + 8));
-
- dev->rxq_ptr += 16;
- if (dev->rxq_ptr >= VLAN_BD_LEN(rxq_bd)) {
- dev->rxq_ptr = 0;
- vio_stq(sdev, dev->buf_list + VLAN_RXQ_BD_OFF, rxq_bd ^ VLAN_BD_TOGGLE);
- }
-
- if (sdev->signal_state & 1) {
- qemu_irq_pulse(spapr_vio_qirq(sdev));
- }
-
- return size;
-}
-
-static NetClientInfo net_spapr_vlan_info = {
- .type = NET_CLIENT_OPTIONS_KIND_NIC,
- .size = sizeof(NICState),
- .can_receive = spapr_vlan_can_receive,
- .receive = spapr_vlan_receive,
-};
-
-static void spapr_vlan_reset_rx_pool(RxBufPool *rxp)
-{
- /*
- * Use INT_MAX as bufsize so that unused buffers are moved to the end
- * of the list during the qsort in spapr_vlan_add_rxbuf_to_pool() later.
- */
- rxp->bufsize = INT_MAX;
- rxp->count = 0;
- memset(rxp->bds, 0, sizeof(rxp->bds));
-}
-
-static void spapr_vlan_reset(VIOsPAPRDevice *sdev)
-{
- VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
- int i;
-
- dev->buf_list = 0;
- dev->rx_bufs = 0;
- dev->isopen = 0;
-
- if (dev->compat_flags & SPAPRVLAN_FLAG_RX_BUF_POOLS) {
- for (i = 0; i < RX_MAX_POOLS; i++) {
- spapr_vlan_reset_rx_pool(dev->rx_pool[i]);
- }
- }
-}
-
-static void spapr_vlan_realize(VIOsPAPRDevice *sdev, Error **errp)
-{
- VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
-
- qemu_macaddr_default_if_unset(&dev->nicconf.macaddr);
-
- dev->nic = qemu_new_nic(&net_spapr_vlan_info, &dev->nicconf,
- object_get_typename(OBJECT(sdev)), sdev->qdev.id, dev);
- qemu_format_nic_info_str(qemu_get_queue(dev->nic), dev->nicconf.macaddr.a);
-}
-
-static void spapr_vlan_instance_init(Object *obj)
-{
- VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(obj);
- int i;
-
- device_add_bootindex_property(obj, &dev->nicconf.bootindex,
- "bootindex", "",
- DEVICE(dev), NULL);
-
- if (dev->compat_flags & SPAPRVLAN_FLAG_RX_BUF_POOLS) {
- for (i = 0; i < RX_MAX_POOLS; i++) {
- dev->rx_pool[i] = g_new(RxBufPool, 1);
- spapr_vlan_reset_rx_pool(dev->rx_pool[i]);
- }
- }
-}
-
-static void spapr_vlan_instance_finalize(Object *obj)
-{
- VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(obj);
- int i;
-
- if (dev->compat_flags & SPAPRVLAN_FLAG_RX_BUF_POOLS) {
- for (i = 0; i < RX_MAX_POOLS; i++) {
- g_free(dev->rx_pool[i]);
- dev->rx_pool[i] = NULL;
- }
- }
-}
-
-void spapr_vlan_create(VIOsPAPRBus *bus, NICInfo *nd)
-{
- DeviceState *dev;
-
- dev = qdev_create(&bus->bus, "spapr-vlan");
-
- qdev_set_nic_properties(dev, nd);
-
- qdev_init_nofail(dev);
-}
-
-static int spapr_vlan_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off)
-{
- VIOsPAPRVLANDevice *vdev = VIO_SPAPR_VLAN_DEVICE(dev);
- uint8_t padded_mac[8] = {0, 0};
- int ret;
-
- /* Some old phyp versions give the mac address in an 8-byte
- * property. The kernel driver has an insane workaround for this;
- * rather than doing the obvious thing and checking the property
- * length, it checks whether the first byte has 0b10 in the low
- * bits. If a correct 6-byte property has a different first byte
- * the kernel will get the wrong mac address, overrunning its
- * buffer in the process (read only, thank goodness).
- *
- * Here we workaround the kernel workaround by always supplying an
- * 8-byte property, with the mac address in the last six bytes */
- memcpy(&padded_mac[2], &vdev->nicconf.macaddr, ETH_ALEN);
- ret = fdt_setprop(fdt, node_off, "local-mac-address",
- padded_mac, sizeof(padded_mac));
- if (ret < 0) {
- return ret;
- }
-
- ret = fdt_setprop_cell(fdt, node_off, "ibm,mac-address-filters", 0);
- if (ret < 0) {
- return ret;
- }
-
- return 0;
-}
-
-static int check_bd(VIOsPAPRVLANDevice *dev, vlan_bd_t bd,
- target_ulong alignment)
-{
- if ((VLAN_BD_ADDR(bd) % alignment)
- || (VLAN_BD_LEN(bd) % alignment)) {
- return -1;
- }
-
- if (!spapr_vio_dma_valid(&dev->sdev, VLAN_BD_ADDR(bd),
- VLAN_BD_LEN(bd), DMA_DIRECTION_FROM_DEVICE)
- || !spapr_vio_dma_valid(&dev->sdev, VLAN_BD_ADDR(bd),
- VLAN_BD_LEN(bd), DMA_DIRECTION_TO_DEVICE)) {
- return -1;
- }
-
- return 0;
-}
-
-static target_ulong h_register_logical_lan(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
- target_ulong opcode,
- target_ulong *args)
-{
- target_ulong reg = args[0];
- target_ulong buf_list = args[1];
- target_ulong rec_queue = args[2];
- target_ulong filter_list = args[3];
- VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
- VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
- vlan_bd_t filter_list_bd;
-
- if (!dev) {
- return H_PARAMETER;
- }
-
- if (dev->isopen) {
- hcall_dprintf("H_REGISTER_LOGICAL_LAN called twice without "
- "H_FREE_LOGICAL_LAN\n");
- return H_RESOURCE;
- }
-
- if (check_bd(dev, VLAN_VALID_BD(buf_list, SPAPR_TCE_PAGE_SIZE),
- SPAPR_TCE_PAGE_SIZE) < 0) {
- hcall_dprintf("Bad buf_list 0x" TARGET_FMT_lx "\n", buf_list);
- return H_PARAMETER;
- }
-
- filter_list_bd = VLAN_VALID_BD(filter_list, SPAPR_TCE_PAGE_SIZE);
- if (check_bd(dev, filter_list_bd, SPAPR_TCE_PAGE_SIZE) < 0) {
- hcall_dprintf("Bad filter_list 0x" TARGET_FMT_lx "\n", filter_list);
- return H_PARAMETER;
- }
-
- if (!(rec_queue & VLAN_BD_VALID)
- || (check_bd(dev, rec_queue, VLAN_RQ_ALIGNMENT) < 0)) {
- hcall_dprintf("Bad receive queue\n");
- return H_PARAMETER;
- }
-
- dev->buf_list = buf_list;
- sdev->signal_state = 0;
-
- rec_queue &= ~VLAN_BD_TOGGLE;
-
- /* Initialize the buffer list */
- vio_stq(sdev, buf_list, rec_queue);
- vio_stq(sdev, buf_list + 8, filter_list_bd);
- spapr_vio_dma_set(sdev, buf_list + VLAN_RX_BDS_OFF, 0,
- SPAPR_TCE_PAGE_SIZE - VLAN_RX_BDS_OFF);
- dev->add_buf_ptr = VLAN_RX_BDS_OFF - 8;
- dev->use_buf_ptr = VLAN_RX_BDS_OFF - 8;
- dev->rx_bufs = 0;
- dev->rxq_ptr = 0;
-
- /* Initialize the receive queue */
- spapr_vio_dma_set(sdev, VLAN_BD_ADDR(rec_queue), 0, VLAN_BD_LEN(rec_queue));
-
- dev->isopen = 1;
- qemu_flush_queued_packets(qemu_get_queue(dev->nic));
-
- return H_SUCCESS;
-}
-
-
-static target_ulong h_free_logical_lan(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- target_ulong reg = args[0];
- VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
- VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
-
- if (!dev) {
- return H_PARAMETER;
- }
-
- if (!dev->isopen) {
- hcall_dprintf("H_FREE_LOGICAL_LAN called without "
- "H_REGISTER_LOGICAL_LAN\n");
- return H_RESOURCE;
- }
-
- spapr_vlan_reset(sdev);
- return H_SUCCESS;
-}
-
-/**
- * Used for qsort, this function compares two RxBufPools by size.
- */
-static int rx_pool_size_compare(const void *p1, const void *p2)
-{
- const RxBufPool *pool1 = *(RxBufPool **)p1;
- const RxBufPool *pool2 = *(RxBufPool **)p2;
-
- if (pool1->bufsize < pool2->bufsize) {
- return -1;
- }
- return pool1->bufsize > pool2->bufsize;
-}
-
-/**
- * Search for a matching buffer pool with exact matching size,
- * or return -1 if no matching pool has been found.
- */
-static int spapr_vlan_get_rx_pool_id(VIOsPAPRVLANDevice *dev, int size)
-{
- int pool;
-
- for (pool = 0; pool < RX_MAX_POOLS; pool++) {
- if (dev->rx_pool[pool]->bufsize == size) {
- return pool;
- }
- }
-
- return -1;
-}
-
-/**
- * Enqueuing receive buffer by adding it to one of our receive buffer pools
- */
-static target_long spapr_vlan_add_rxbuf_to_pool(VIOsPAPRVLANDevice *dev,
- target_ulong buf)
-{
- int size = VLAN_BD_LEN(buf);
- int pool;
-
- pool = spapr_vlan_get_rx_pool_id(dev, size);
- if (pool < 0) {
- /*
- * No matching pool found? Try to use a new one. If the guest used all
- * pools before, but changed the size of one pool inbetween, we might
- * need to recycle that pool here (if it's empty already). Thus scan
- * all buffer pools now, starting with the last (likely empty) one.
- */
- for (pool = RX_MAX_POOLS - 1; pool >= 0 ; pool--) {
- if (dev->rx_pool[pool]->count == 0) {
- dev->rx_pool[pool]->bufsize = size;
- /*
- * Sort pools by size so that spapr_vlan_receive()
- * can later find the smallest buffer pool easily.
- */
- qsort(dev->rx_pool, RX_MAX_POOLS, sizeof(dev->rx_pool[0]),
- rx_pool_size_compare);
- pool = spapr_vlan_get_rx_pool_id(dev, size);
- DPRINTF("created RX pool %d for size %lld\n", pool,
- VLAN_BD_LEN(buf));
- break;
- }
- }
- }
- /* Still no usable pool? Give up */
- if (pool < 0 || dev->rx_pool[pool]->count >= RX_POOL_MAX_BDS) {
- return H_RESOURCE;
- }
-
- DPRINTF("h_add_llan_buf(): Add buf using pool %i (size %lli, count=%i)\n",
- pool, VLAN_BD_LEN(buf), dev->rx_pool[pool]->count);
-
- dev->rx_pool[pool]->bds[dev->rx_pool[pool]->count++] = buf;
-
- return 0;
-}
-
-/**
- * This is the old way of enqueuing receive buffers: Add it to the rx queue
- * page that has been supplied by the guest (which is quite limited in size).
- */
-static target_long spapr_vlan_add_rxbuf_to_page(VIOsPAPRVLANDevice *dev,
- target_ulong buf)
-{
- vlan_bd_t bd;
-
- if (dev->rx_bufs >= VLAN_MAX_BUFS) {
- return H_RESOURCE;
- }
-
- do {
- dev->add_buf_ptr += 8;
- if (dev->add_buf_ptr >= VLAN_RX_BDS_LEN + VLAN_RX_BDS_OFF) {
- dev->add_buf_ptr = VLAN_RX_BDS_OFF;
- }
-
- bd = vio_ldq(&dev->sdev, dev->buf_list + dev->add_buf_ptr);
- } while (bd & VLAN_BD_VALID);
-
- vio_stq(&dev->sdev, dev->buf_list + dev->add_buf_ptr, buf);
-
- DPRINTF("h_add_llan_buf(): Added buf ptr=%d rx_bufs=%d bd=0x%016llx\n",
- dev->add_buf_ptr, dev->rx_bufs, (unsigned long long)buf);
-
- return 0;
-}
-
-static target_ulong h_add_logical_lan_buffer(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
- target_ulong opcode,
- target_ulong *args)
-{
- target_ulong reg = args[0];
- target_ulong buf = args[1];
- VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
- VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
- target_long ret;
-
- DPRINTF("H_ADD_LOGICAL_LAN_BUFFER(0x" TARGET_FMT_lx
- ", 0x" TARGET_FMT_lx ")\n", reg, buf);
-
- if (!sdev) {
- hcall_dprintf("Bad device\n");
- return H_PARAMETER;
- }
-
- if ((check_bd(dev, buf, 4) < 0)
- || (VLAN_BD_LEN(buf) < 16)) {
- hcall_dprintf("Bad buffer enqueued\n");
- return H_PARAMETER;
- }
-
- if (!dev->isopen) {
- return H_RESOURCE;
- }
-
- if (dev->compat_flags & SPAPRVLAN_FLAG_RX_BUF_POOLS) {
- ret = spapr_vlan_add_rxbuf_to_pool(dev, buf);
- } else {
- ret = spapr_vlan_add_rxbuf_to_page(dev, buf);
- }
- if (ret) {
- return ret;
- }
-
- dev->rx_bufs++;
-
- qemu_flush_queued_packets(qemu_get_queue(dev->nic));
-
- return H_SUCCESS;
-}
-
-static target_ulong h_send_logical_lan(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- target_ulong reg = args[0];
- target_ulong *bufs = args + 1;
- target_ulong continue_token = args[7];
- VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
- VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
- unsigned total_len;
- uint8_t *lbuf, *p;
- int i, nbufs;
- int ret;
-
- DPRINTF("H_SEND_LOGICAL_LAN(0x" TARGET_FMT_lx ", <bufs>, 0x"
- TARGET_FMT_lx ")\n", reg, continue_token);
-
- if (!sdev) {
- return H_PARAMETER;
- }
-
- DPRINTF("rxbufs = %d\n", dev->rx_bufs);
-
- if (!dev->isopen) {
- return H_DROPPED;
- }
-
- if (continue_token) {
- return H_HARDWARE; /* FIXME actually handle this */
- }
-
- total_len = 0;
- for (i = 0; i < 6; i++) {
- DPRINTF(" buf desc: 0x" TARGET_FMT_lx "\n", bufs[i]);
- if (!(bufs[i] & VLAN_BD_VALID)) {
- break;
- }
- total_len += VLAN_BD_LEN(bufs[i]);
- }
-
- nbufs = i;
- DPRINTF("h_send_logical_lan() %d buffers, total length 0x%x\n",
- nbufs, total_len);
-
- if (total_len == 0) {
- return H_SUCCESS;
- }
-
- if (total_len > MAX_PACKET_SIZE) {
- /* Don't let the guest force too large an allocation */
- return H_RESOURCE;
- }
-
- lbuf = alloca(total_len);
- p = lbuf;
- for (i = 0; i < nbufs; i++) {
- ret = spapr_vio_dma_read(sdev, VLAN_BD_ADDR(bufs[i]),
- p, VLAN_BD_LEN(bufs[i]));
- if (ret < 0) {
- return ret;
- }
-
- p += VLAN_BD_LEN(bufs[i]);
- }
-
- qemu_send_packet(qemu_get_queue(dev->nic), lbuf, total_len);
-
- return H_SUCCESS;
-}
-
-static target_ulong h_multicast_ctrl(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- target_ulong reg = args[0];
- VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
-
- if (!dev) {
- return H_PARAMETER;
- }
-
- return H_SUCCESS;
-}
-
-static Property spapr_vlan_properties[] = {
- DEFINE_SPAPR_PROPERTIES(VIOsPAPRVLANDevice, sdev),
- DEFINE_NIC_PROPERTIES(VIOsPAPRVLANDevice, nicconf),
- DEFINE_PROP_BIT("use-rx-buffer-pools", VIOsPAPRVLANDevice,
- compat_flags, SPAPRVLAN_FLAG_RX_BUF_POOLS_BIT, true),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static bool spapr_vlan_rx_buffer_pools_needed(void *opaque)
-{
- VIOsPAPRVLANDevice *dev = opaque;
-
- return (dev->compat_flags & SPAPRVLAN_FLAG_RX_BUF_POOLS) != 0;
-}
-
-static const VMStateDescription vmstate_rx_buffer_pool = {
- .name = "spapr_llan/rx_buffer_pool",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = spapr_vlan_rx_buffer_pools_needed,
- .fields = (VMStateField[]) {
- VMSTATE_INT32(bufsize, RxBufPool),
- VMSTATE_INT32(count, RxBufPool),
- VMSTATE_UINT64_ARRAY(bds, RxBufPool, RX_POOL_MAX_BDS),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_rx_pools = {
- .name = "spapr_llan/rx_pools",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = spapr_vlan_rx_buffer_pools_needed,
- .fields = (VMStateField[]) {
- VMSTATE_ARRAY_OF_POINTER_TO_STRUCT(rx_pool, VIOsPAPRVLANDevice,
- RX_MAX_POOLS, 1,
- vmstate_rx_buffer_pool, RxBufPool),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_spapr_llan = {
- .name = "spapr_llan",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_SPAPR_VIO(sdev, VIOsPAPRVLANDevice),
- /* LLAN state */
- VMSTATE_BOOL(isopen, VIOsPAPRVLANDevice),
- VMSTATE_UINTTL(buf_list, VIOsPAPRVLANDevice),
- VMSTATE_UINT32(add_buf_ptr, VIOsPAPRVLANDevice),
- VMSTATE_UINT32(use_buf_ptr, VIOsPAPRVLANDevice),
- VMSTATE_UINT32(rx_bufs, VIOsPAPRVLANDevice),
- VMSTATE_UINTTL(rxq_ptr, VIOsPAPRVLANDevice),
-
- VMSTATE_END_OF_LIST()
- },
- .subsections = (const VMStateDescription * []) {
- &vmstate_rx_pools,
- NULL
- }
-};
-
-static void spapr_vlan_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
-
- k->realize = spapr_vlan_realize;
- k->reset = spapr_vlan_reset;
- k->devnode = spapr_vlan_devnode;
- k->dt_name = "l-lan";
- k->dt_type = "network";
- k->dt_compatible = "IBM,l-lan";
- k->signal_mask = 0x1;
- set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
- dc->props = spapr_vlan_properties;
- k->rtce_window_size = 0x10000000;
- dc->vmsd = &vmstate_spapr_llan;
-}
-
-static const TypeInfo spapr_vlan_info = {
- .name = TYPE_VIO_SPAPR_VLAN_DEVICE,
- .parent = TYPE_VIO_SPAPR_DEVICE,
- .instance_size = sizeof(VIOsPAPRVLANDevice),
- .class_init = spapr_vlan_class_init,
- .instance_init = spapr_vlan_instance_init,
- .instance_finalize = spapr_vlan_instance_finalize,
-};
-
-static void spapr_vlan_register_types(void)
-{
- spapr_register_hypercall(H_REGISTER_LOGICAL_LAN, h_register_logical_lan);
- spapr_register_hypercall(H_FREE_LOGICAL_LAN, h_free_logical_lan);
- spapr_register_hypercall(H_SEND_LOGICAL_LAN, h_send_logical_lan);
- spapr_register_hypercall(H_ADD_LOGICAL_LAN_BUFFER,
- h_add_logical_lan_buffer);
- spapr_register_hypercall(H_MULTICAST_CTRL, h_multicast_ctrl);
- type_register_static(&spapr_vlan_info);
-}
-
-type_init(spapr_vlan_register_types)
diff --git a/qemu/hw/net/stellaris_enet.c b/qemu/hw/net/stellaris_enet.c
deleted file mode 100644
index 688089494..000000000
--- a/qemu/hw/net/stellaris_enet.c
+++ /dev/null
@@ -1,514 +0,0 @@
-/*
- * Luminary Micro Stellaris Ethernet Controller
- *
- * Copyright (c) 2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "net/net.h"
-#include <zlib.h>
-
-//#define DEBUG_STELLARIS_ENET 1
-
-#ifdef DEBUG_STELLARIS_ENET
-#define DPRINTF(fmt, ...) \
-do { printf("stellaris_enet: " fmt , ## __VA_ARGS__); } while (0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "stellaris_enet: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "stellaris_enet: error: " fmt , ## __VA_ARGS__);} while (0)
-#endif
-
-#define SE_INT_RX 0x01
-#define SE_INT_TXER 0x02
-#define SE_INT_TXEMP 0x04
-#define SE_INT_FOV 0x08
-#define SE_INT_RXER 0x10
-#define SE_INT_MD 0x20
-#define SE_INT_PHY 0x40
-
-#define SE_RCTL_RXEN 0x01
-#define SE_RCTL_AMUL 0x02
-#define SE_RCTL_PRMS 0x04
-#define SE_RCTL_BADCRC 0x08
-#define SE_RCTL_RSTFIFO 0x10
-
-#define SE_TCTL_TXEN 0x01
-#define SE_TCTL_PADEN 0x02
-#define SE_TCTL_CRC 0x04
-#define SE_TCTL_DUPLEX 0x08
-
-#define TYPE_STELLARIS_ENET "stellaris_enet"
-#define STELLARIS_ENET(obj) \
- OBJECT_CHECK(stellaris_enet_state, (obj), TYPE_STELLARIS_ENET)
-
-typedef struct {
- uint8_t data[2048];
- uint32_t len;
-} StellarisEnetRxFrame;
-
-typedef struct {
- SysBusDevice parent_obj;
-
- uint32_t ris;
- uint32_t im;
- uint32_t rctl;
- uint32_t tctl;
- uint32_t thr;
- uint32_t mctl;
- uint32_t mdv;
- uint32_t mtxd;
- uint32_t mrxd;
- uint32_t np;
- uint32_t tx_fifo_len;
- uint8_t tx_fifo[2048];
- /* Real hardware has a 2k fifo, which works out to be at most 31 packets.
- We implement a full 31 packet fifo. */
- StellarisEnetRxFrame rx[31];
- uint32_t rx_fifo_offset;
- uint32_t next_packet;
- NICState *nic;
- NICConf conf;
- qemu_irq irq;
- MemoryRegion mmio;
-} stellaris_enet_state;
-
-static const VMStateDescription vmstate_rx_frame = {
- .name = "stellaris_enet/rx_frame",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8_ARRAY(data, StellarisEnetRxFrame, 2048),
- VMSTATE_UINT32(len, StellarisEnetRxFrame),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static int stellaris_enet_post_load(void *opaque, int version_id)
-{
- stellaris_enet_state *s = opaque;
- int i;
-
- /* Sanitize inbound state. Note that next_packet is an index but
- * np is a size; hence their valid upper bounds differ.
- */
- if (s->next_packet >= ARRAY_SIZE(s->rx)) {
- return -1;
- }
-
- if (s->np > ARRAY_SIZE(s->rx)) {
- return -1;
- }
-
- for (i = 0; i < ARRAY_SIZE(s->rx); i++) {
- if (s->rx[i].len > ARRAY_SIZE(s->rx[i].data)) {
- return -1;
- }
- }
-
- if (s->rx_fifo_offset > ARRAY_SIZE(s->rx[0].data) - 4) {
- return -1;
- }
-
- if (s->tx_fifo_len > ARRAY_SIZE(s->tx_fifo)) {
- return -1;
- }
-
- return 0;
-}
-
-static const VMStateDescription vmstate_stellaris_enet = {
- .name = "stellaris_enet",
- .version_id = 2,
- .minimum_version_id = 2,
- .post_load = stellaris_enet_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(ris, stellaris_enet_state),
- VMSTATE_UINT32(im, stellaris_enet_state),
- VMSTATE_UINT32(rctl, stellaris_enet_state),
- VMSTATE_UINT32(tctl, stellaris_enet_state),
- VMSTATE_UINT32(thr, stellaris_enet_state),
- VMSTATE_UINT32(mctl, stellaris_enet_state),
- VMSTATE_UINT32(mdv, stellaris_enet_state),
- VMSTATE_UINT32(mtxd, stellaris_enet_state),
- VMSTATE_UINT32(mrxd, stellaris_enet_state),
- VMSTATE_UINT32(np, stellaris_enet_state),
- VMSTATE_UINT32(tx_fifo_len, stellaris_enet_state),
- VMSTATE_UINT8_ARRAY(tx_fifo, stellaris_enet_state, 2048),
- VMSTATE_STRUCT_ARRAY(rx, stellaris_enet_state, 31, 1,
- vmstate_rx_frame, StellarisEnetRxFrame),
- VMSTATE_UINT32(rx_fifo_offset, stellaris_enet_state),
- VMSTATE_UINT32(next_packet, stellaris_enet_state),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void stellaris_enet_update(stellaris_enet_state *s)
-{
- qemu_set_irq(s->irq, (s->ris & s->im) != 0);
-}
-
-/* Return the data length of the packet currently being assembled
- * in the TX fifo.
- */
-static inline int stellaris_txpacket_datalen(stellaris_enet_state *s)
-{
- return s->tx_fifo[0] | (s->tx_fifo[1] << 8);
-}
-
-/* Return true if the packet currently in the TX FIFO is complete,
-* ie the FIFO holds enough bytes for the data length, ethernet header,
-* payload and optionally CRC.
-*/
-static inline bool stellaris_txpacket_complete(stellaris_enet_state *s)
-{
- int framelen = stellaris_txpacket_datalen(s);
- framelen += 16;
- if (!(s->tctl & SE_TCTL_CRC)) {
- framelen += 4;
- }
- /* Cover the corner case of a 2032 byte payload with auto-CRC disabled:
- * this requires more bytes than will fit in the FIFO. It's not totally
- * clear how the h/w handles this, but if using threshold-based TX
- * it will definitely try to transmit something.
- */
- framelen = MIN(framelen, ARRAY_SIZE(s->tx_fifo));
- return s->tx_fifo_len >= framelen;
-}
-
-/* Return true if the TX FIFO threshold is enabled and the FIFO
- * has filled enough to reach it.
- */
-static inline bool stellaris_tx_thr_reached(stellaris_enet_state *s)
-{
- return (s->thr < 0x3f &&
- (s->tx_fifo_len >= 4 * (s->thr * 8 + 1)));
-}
-
-/* Send the packet currently in the TX FIFO */
-static void stellaris_enet_send(stellaris_enet_state *s)
-{
- int framelen = stellaris_txpacket_datalen(s);
-
- /* Ethernet header is in the FIFO but not in the datacount.
- * We don't implement explicit CRC, so just ignore any
- * CRC value in the FIFO.
- */
- framelen += 14;
- if ((s->tctl & SE_TCTL_PADEN) && framelen < 60) {
- memset(&s->tx_fifo[framelen + 2], 0, 60 - framelen);
- framelen = 60;
- }
- /* This MIN will have no effect unless the FIFO data is corrupt
- * (eg bad data from an incoming migration); otherwise the check
- * on the datalen at the start of writing the data into the FIFO
- * will have caught this. Silently write a corrupt half-packet,
- * which is what the hardware does in FIFO underrun situations.
- */
- framelen = MIN(framelen, ARRAY_SIZE(s->tx_fifo) - 2);
- qemu_send_packet(qemu_get_queue(s->nic), s->tx_fifo + 2, framelen);
- s->tx_fifo_len = 0;
- s->ris |= SE_INT_TXEMP;
- stellaris_enet_update(s);
- DPRINTF("Done TX\n");
-}
-
-/* TODO: Implement MAC address filtering. */
-static ssize_t stellaris_enet_receive(NetClientState *nc, const uint8_t *buf, size_t size)
-{
- stellaris_enet_state *s = qemu_get_nic_opaque(nc);
- int n;
- uint8_t *p;
- uint32_t crc;
-
- if ((s->rctl & SE_RCTL_RXEN) == 0)
- return -1;
- if (s->np >= 31) {
- return 0;
- }
-
- DPRINTF("Received packet len=%zu\n", size);
- n = s->next_packet + s->np;
- if (n >= 31)
- n -= 31;
-
- if (size >= sizeof(s->rx[n].data) - 6) {
- /* If the packet won't fit into the
- * emulated 2K RAM, this is reported
- * as a FIFO overrun error.
- */
- s->ris |= SE_INT_FOV;
- stellaris_enet_update(s);
- return -1;
- }
-
- s->np++;
- s->rx[n].len = size + 6;
- p = s->rx[n].data;
- *(p++) = (size + 6);
- *(p++) = (size + 6) >> 8;
- memcpy (p, buf, size);
- p += size;
- crc = crc32(~0, buf, size);
- *(p++) = crc;
- *(p++) = crc >> 8;
- *(p++) = crc >> 16;
- *(p++) = crc >> 24;
- /* Clear the remaining bytes in the last word. */
- if ((size & 3) != 2) {
- memset(p, 0, (6 - size) & 3);
- }
-
- s->ris |= SE_INT_RX;
- stellaris_enet_update(s);
-
- return size;
-}
-
-static int stellaris_enet_can_receive(stellaris_enet_state *s)
-{
- return (s->np < 31);
-}
-
-static uint64_t stellaris_enet_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- stellaris_enet_state *s = (stellaris_enet_state *)opaque;
- uint32_t val;
-
- switch (offset) {
- case 0x00: /* RIS */
- DPRINTF("IRQ status %02x\n", s->ris);
- return s->ris;
- case 0x04: /* IM */
- return s->im;
- case 0x08: /* RCTL */
- return s->rctl;
- case 0x0c: /* TCTL */
- return s->tctl;
- case 0x10: /* DATA */
- {
- uint8_t *rx_fifo;
-
- if (s->np == 0) {
- BADF("RX underflow\n");
- return 0;
- }
-
- rx_fifo = s->rx[s->next_packet].data + s->rx_fifo_offset;
-
- val = rx_fifo[0] | (rx_fifo[1] << 8) | (rx_fifo[2] << 16)
- | (rx_fifo[3] << 24);
- s->rx_fifo_offset += 4;
- if (s->rx_fifo_offset >= s->rx[s->next_packet].len) {
- s->rx_fifo_offset = 0;
- s->next_packet++;
- if (s->next_packet >= 31)
- s->next_packet = 0;
- s->np--;
- DPRINTF("RX done np=%d\n", s->np);
- if (!s->np && stellaris_enet_can_receive(s)) {
- qemu_flush_queued_packets(qemu_get_queue(s->nic));
- }
- }
- return val;
- }
- case 0x14: /* IA0 */
- return s->conf.macaddr.a[0] | (s->conf.macaddr.a[1] << 8)
- | (s->conf.macaddr.a[2] << 16)
- | ((uint32_t)s->conf.macaddr.a[3] << 24);
- case 0x18: /* IA1 */
- return s->conf.macaddr.a[4] | (s->conf.macaddr.a[5] << 8);
- case 0x1c: /* THR */
- return s->thr;
- case 0x20: /* MCTL */
- return s->mctl;
- case 0x24: /* MDV */
- return s->mdv;
- case 0x28: /* MADD */
- return 0;
- case 0x2c: /* MTXD */
- return s->mtxd;
- case 0x30: /* MRXD */
- return s->mrxd;
- case 0x34: /* NP */
- return s->np;
- case 0x38: /* TR */
- return 0;
- case 0x3c: /* Undocuented: Timestamp? */
- return 0;
- default:
- hw_error("stellaris_enet_read: Bad offset %x\n", (int)offset);
- return 0;
- }
-}
-
-static void stellaris_enet_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- stellaris_enet_state *s = (stellaris_enet_state *)opaque;
-
- switch (offset) {
- case 0x00: /* IACK */
- s->ris &= ~value;
- DPRINTF("IRQ ack %02" PRIx64 "/%02x\n", value, s->ris);
- stellaris_enet_update(s);
- /* Clearing TXER also resets the TX fifo. */
- if (value & SE_INT_TXER) {
- s->tx_fifo_len = 0;
- }
- break;
- case 0x04: /* IM */
- DPRINTF("IRQ mask %02" PRIx64 "/%02x\n", value, s->ris);
- s->im = value;
- stellaris_enet_update(s);
- break;
- case 0x08: /* RCTL */
- s->rctl = value;
- if (value & SE_RCTL_RSTFIFO) {
- s->np = 0;
- s->rx_fifo_offset = 0;
- stellaris_enet_update(s);
- }
- break;
- case 0x0c: /* TCTL */
- s->tctl = value;
- break;
- case 0x10: /* DATA */
- if (s->tx_fifo_len == 0) {
- /* The first word is special, it contains the data length */
- int framelen = value & 0xffff;
- if (framelen > 2032) {
- DPRINTF("TX frame too long (%d)\n", framelen);
- s->ris |= SE_INT_TXER;
- stellaris_enet_update(s);
- break;
- }
- }
-
- if (s->tx_fifo_len + 4 <= ARRAY_SIZE(s->tx_fifo)) {
- s->tx_fifo[s->tx_fifo_len++] = value;
- s->tx_fifo[s->tx_fifo_len++] = value >> 8;
- s->tx_fifo[s->tx_fifo_len++] = value >> 16;
- s->tx_fifo[s->tx_fifo_len++] = value >> 24;
- }
-
- if (stellaris_tx_thr_reached(s) && stellaris_txpacket_complete(s)) {
- stellaris_enet_send(s);
- }
- break;
- case 0x14: /* IA0 */
- s->conf.macaddr.a[0] = value;
- s->conf.macaddr.a[1] = value >> 8;
- s->conf.macaddr.a[2] = value >> 16;
- s->conf.macaddr.a[3] = value >> 24;
- break;
- case 0x18: /* IA1 */
- s->conf.macaddr.a[4] = value;
- s->conf.macaddr.a[5] = value >> 8;
- break;
- case 0x1c: /* THR */
- s->thr = value;
- break;
- case 0x20: /* MCTL */
- s->mctl = value;
- break;
- case 0x24: /* MDV */
- s->mdv = value;
- break;
- case 0x28: /* MADD */
- /* ignored. */
- break;
- case 0x2c: /* MTXD */
- s->mtxd = value & 0xff;
- break;
- case 0x38: /* TR */
- if (value & 1) {
- stellaris_enet_send(s);
- }
- break;
- case 0x30: /* MRXD */
- case 0x34: /* NP */
- /* Ignored. */
- case 0x3c: /* Undocuented: Timestamp? */
- /* Ignored. */
- break;
- default:
- hw_error("stellaris_enet_write: Bad offset %x\n", (int)offset);
- }
-}
-
-static const MemoryRegionOps stellaris_enet_ops = {
- .read = stellaris_enet_read,
- .write = stellaris_enet_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void stellaris_enet_reset(stellaris_enet_state *s)
-{
- s->mdv = 0x80;
- s->rctl = SE_RCTL_BADCRC;
- s->im = SE_INT_PHY | SE_INT_MD | SE_INT_RXER | SE_INT_FOV | SE_INT_TXEMP
- | SE_INT_TXER | SE_INT_RX;
- s->thr = 0x3f;
- s->tx_fifo_len = 0;
-}
-
-static NetClientInfo net_stellaris_enet_info = {
- .type = NET_CLIENT_OPTIONS_KIND_NIC,
- .size = sizeof(NICState),
- .receive = stellaris_enet_receive,
-};
-
-static int stellaris_enet_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- stellaris_enet_state *s = STELLARIS_ENET(dev);
-
- memory_region_init_io(&s->mmio, OBJECT(s), &stellaris_enet_ops, s,
- "stellaris_enet", 0x1000);
- sysbus_init_mmio(sbd, &s->mmio);
- sysbus_init_irq(sbd, &s->irq);
- qemu_macaddr_default_if_unset(&s->conf.macaddr);
-
- s->nic = qemu_new_nic(&net_stellaris_enet_info, &s->conf,
- object_get_typename(OBJECT(dev)), dev->id, s);
- qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-
- stellaris_enet_reset(s);
- return 0;
-}
-
-static Property stellaris_enet_properties[] = {
- DEFINE_NIC_PROPERTIES(stellaris_enet_state, conf),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void stellaris_enet_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = stellaris_enet_init;
- dc->props = stellaris_enet_properties;
- dc->vmsd = &vmstate_stellaris_enet;
-}
-
-static const TypeInfo stellaris_enet_info = {
- .name = TYPE_STELLARIS_ENET,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(stellaris_enet_state),
- .class_init = stellaris_enet_class_init,
-};
-
-static void stellaris_enet_register_types(void)
-{
- type_register_static(&stellaris_enet_info);
-}
-
-type_init(stellaris_enet_register_types)
diff --git a/qemu/hw/net/vhost_net.c b/qemu/hw/net/vhost_net.c
deleted file mode 100644
index 6e1032fc1..000000000
--- a/qemu/hw/net/vhost_net.c
+++ /dev/null
@@ -1,473 +0,0 @@
-/*
- * vhost-net support
- *
- * Copyright Red Hat, Inc. 2010
- *
- * Authors:
- * Michael S. Tsirkin <mst@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "net/net.h"
-#include "net/tap.h"
-#include "net/vhost-user.h"
-
-#include "hw/virtio/virtio-net.h"
-#include "net/vhost_net.h"
-#include "qemu/error-report.h"
-
-
-#ifdef CONFIG_VHOST_NET
-#include <linux/vhost.h>
-#include <sys/socket.h>
-#include <linux/kvm.h>
-#include <netpacket/packet.h>
-#include <net/ethernet.h>
-#include <net/if.h>
-#include <netinet/in.h>
-
-
-#include "standard-headers/linux/virtio_ring.h"
-#include "hw/virtio/vhost.h"
-#include "hw/virtio/virtio-bus.h"
-
-struct vhost_net {
- struct vhost_dev dev;
- struct vhost_virtqueue vqs[2];
- int backend;
- NetClientState *nc;
-};
-
-/* Features supported by host kernel. */
-static const int kernel_feature_bits[] = {
- VIRTIO_F_NOTIFY_ON_EMPTY,
- VIRTIO_RING_F_INDIRECT_DESC,
- VIRTIO_RING_F_EVENT_IDX,
- VIRTIO_NET_F_MRG_RXBUF,
- VIRTIO_F_VERSION_1,
- VHOST_INVALID_FEATURE_BIT
-};
-
-/* Features supported by others. */
-static const int user_feature_bits[] = {
- VIRTIO_F_NOTIFY_ON_EMPTY,
- VIRTIO_RING_F_INDIRECT_DESC,
- VIRTIO_RING_F_EVENT_IDX,
-
- VIRTIO_F_ANY_LAYOUT,
- VIRTIO_F_VERSION_1,
- VIRTIO_NET_F_CSUM,
- VIRTIO_NET_F_GUEST_CSUM,
- VIRTIO_NET_F_GSO,
- VIRTIO_NET_F_GUEST_TSO4,
- VIRTIO_NET_F_GUEST_TSO6,
- VIRTIO_NET_F_GUEST_ECN,
- VIRTIO_NET_F_GUEST_UFO,
- VIRTIO_NET_F_HOST_TSO4,
- VIRTIO_NET_F_HOST_TSO6,
- VIRTIO_NET_F_HOST_ECN,
- VIRTIO_NET_F_HOST_UFO,
- VIRTIO_NET_F_MRG_RXBUF,
-
- /* This bit implies RARP isn't sent by QEMU out of band */
- VIRTIO_NET_F_GUEST_ANNOUNCE,
-
- VIRTIO_NET_F_MQ,
-
- VHOST_INVALID_FEATURE_BIT
-};
-
-static const int *vhost_net_get_feature_bits(struct vhost_net *net)
-{
- const int *feature_bits = 0;
-
- switch (net->nc->info->type) {
- case NET_CLIENT_OPTIONS_KIND_TAP:
- feature_bits = kernel_feature_bits;
- break;
- case NET_CLIENT_OPTIONS_KIND_VHOST_USER:
- feature_bits = user_feature_bits;
- break;
- default:
- error_report("Feature bits not defined for this type: %d",
- net->nc->info->type);
- break;
- }
-
- return feature_bits;
-}
-
-uint64_t vhost_net_get_features(struct vhost_net *net, uint64_t features)
-{
- return vhost_get_features(&net->dev, vhost_net_get_feature_bits(net),
- features);
-}
-
-void vhost_net_ack_features(struct vhost_net *net, uint64_t features)
-{
- net->dev.acked_features = net->dev.backend_features;
- vhost_ack_features(&net->dev, vhost_net_get_feature_bits(net), features);
-}
-
-uint64_t vhost_net_get_max_queues(VHostNetState *net)
-{
- return net->dev.max_queues;
-}
-
-static int vhost_net_get_fd(NetClientState *backend)
-{
- switch (backend->info->type) {
- case NET_CLIENT_OPTIONS_KIND_TAP:
- return tap_get_fd(backend);
- default:
- fprintf(stderr, "vhost-net requires tap backend\n");
- return -EBADFD;
- }
-}
-
-struct vhost_net *vhost_net_init(VhostNetOptions *options)
-{
- int r;
- bool backend_kernel = options->backend_type == VHOST_BACKEND_TYPE_KERNEL;
- struct vhost_net *net = g_malloc(sizeof *net);
-
- if (!options->net_backend) {
- fprintf(stderr, "vhost-net requires net backend to be setup\n");
- goto fail;
- }
- net->nc = options->net_backend;
-
- net->dev.max_queues = 1;
- net->dev.nvqs = 2;
- net->dev.vqs = net->vqs;
-
- if (backend_kernel) {
- r = vhost_net_get_fd(options->net_backend);
- if (r < 0) {
- goto fail;
- }
- net->dev.backend_features = qemu_has_vnet_hdr(options->net_backend)
- ? 0 : (1ULL << VHOST_NET_F_VIRTIO_NET_HDR);
- net->backend = r;
- net->dev.protocol_features = 0;
- } else {
- net->dev.backend_features = 0;
- net->dev.protocol_features = 0;
- net->backend = -1;
-
- /* vhost-user needs vq_index to initiate a specific queue pair */
- net->dev.vq_index = net->nc->queue_index * net->dev.nvqs;
- }
-
- r = vhost_dev_init(&net->dev, options->opaque,
- options->backend_type);
- if (r < 0) {
- goto fail;
- }
- if (backend_kernel) {
- if (!qemu_has_vnet_hdr_len(options->net_backend,
- sizeof(struct virtio_net_hdr_mrg_rxbuf))) {
- net->dev.features &= ~(1ULL << VIRTIO_NET_F_MRG_RXBUF);
- }
- if (~net->dev.features & net->dev.backend_features) {
- fprintf(stderr, "vhost lacks feature mask %" PRIu64
- " for backend\n",
- (uint64_t)(~net->dev.features & net->dev.backend_features));
- vhost_dev_cleanup(&net->dev);
- goto fail;
- }
- }
- /* Set sane init value. Override when guest acks. */
- vhost_net_ack_features(net, 0);
- return net;
-fail:
- g_free(net);
- return NULL;
-}
-
-static void vhost_net_set_vq_index(struct vhost_net *net, int vq_index)
-{
- net->dev.vq_index = vq_index;
-}
-
-static int vhost_net_start_one(struct vhost_net *net,
- VirtIODevice *dev)
-{
- struct vhost_vring_file file = { };
- int r;
-
- net->dev.nvqs = 2;
- net->dev.vqs = net->vqs;
-
- r = vhost_dev_enable_notifiers(&net->dev, dev);
- if (r < 0) {
- goto fail_notifiers;
- }
-
- r = vhost_dev_start(&net->dev, dev);
- if (r < 0) {
- goto fail_start;
- }
-
- if (net->nc->info->poll) {
- net->nc->info->poll(net->nc, false);
- }
-
- if (net->nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP) {
- qemu_set_fd_handler(net->backend, NULL, NULL, NULL);
- file.fd = net->backend;
- for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
- const VhostOps *vhost_ops = net->dev.vhost_ops;
- r = vhost_ops->vhost_net_set_backend(&net->dev, &file);
- if (r < 0) {
- r = -errno;
- goto fail;
- }
- }
- }
- return 0;
-fail:
- file.fd = -1;
- if (net->nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP) {
- while (file.index-- > 0) {
- const VhostOps *vhost_ops = net->dev.vhost_ops;
- int r = vhost_ops->vhost_net_set_backend(&net->dev, &file);
- assert(r >= 0);
- }
- }
- if (net->nc->info->poll) {
- net->nc->info->poll(net->nc, true);
- }
- vhost_dev_stop(&net->dev, dev);
-fail_start:
- vhost_dev_disable_notifiers(&net->dev, dev);
-fail_notifiers:
- return r;
-}
-
-static void vhost_net_stop_one(struct vhost_net *net,
- VirtIODevice *dev)
-{
- struct vhost_vring_file file = { .fd = -1 };
-
- if (net->nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP) {
- for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
- const VhostOps *vhost_ops = net->dev.vhost_ops;
- int r = vhost_ops->vhost_net_set_backend(&net->dev, &file);
- assert(r >= 0);
- }
- }
- if (net->nc->info->poll) {
- net->nc->info->poll(net->nc, true);
- }
- vhost_dev_stop(&net->dev, dev);
- vhost_dev_disable_notifiers(&net->dev, dev);
-}
-
-int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
- int total_queues)
-{
- BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev)));
- VirtioBusState *vbus = VIRTIO_BUS(qbus);
- VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
- int r, e, i;
-
- if (!k->set_guest_notifiers) {
- error_report("binding does not support guest notifiers");
- return -ENOSYS;
- }
-
- for (i = 0; i < total_queues; i++) {
- struct vhost_net *net;
-
- net = get_vhost_net(ncs[i].peer);
- vhost_net_set_vq_index(net, i * 2);
-
- /* Suppress the masking guest notifiers on vhost user
- * because vhost user doesn't interrupt masking/unmasking
- * properly.
- */
- if (net->nc->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER) {
- dev->use_guest_notifier_mask = false;
- }
- }
-
- r = k->set_guest_notifiers(qbus->parent, total_queues * 2, true);
- if (r < 0) {
- error_report("Error binding guest notifier: %d", -r);
- goto err;
- }
-
- for (i = 0; i < total_queues; i++) {
- r = vhost_net_start_one(get_vhost_net(ncs[i].peer), dev);
-
- if (r < 0) {
- goto err_start;
- }
- }
-
- return 0;
-
-err_start:
- while (--i >= 0) {
- vhost_net_stop_one(get_vhost_net(ncs[i].peer), dev);
- }
- e = k->set_guest_notifiers(qbus->parent, total_queues * 2, false);
- if (e < 0) {
- fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", e);
- fflush(stderr);
- }
-err:
- return r;
-}
-
-void vhost_net_stop(VirtIODevice *dev, NetClientState *ncs,
- int total_queues)
-{
- BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev)));
- VirtioBusState *vbus = VIRTIO_BUS(qbus);
- VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
- int i, r;
-
- for (i = 0; i < total_queues; i++) {
- vhost_net_stop_one(get_vhost_net(ncs[i].peer), dev);
- }
-
- r = k->set_guest_notifiers(qbus->parent, total_queues * 2, false);
- if (r < 0) {
- fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", r);
- fflush(stderr);
- }
- assert(r >= 0);
-}
-
-void vhost_net_cleanup(struct vhost_net *net)
-{
- vhost_dev_cleanup(&net->dev);
- g_free(net);
-}
-
-int vhost_net_notify_migration_done(struct vhost_net *net, char* mac_addr)
-{
- const VhostOps *vhost_ops = net->dev.vhost_ops;
- int r = -1;
-
- if (vhost_ops->vhost_migration_done) {
- r = vhost_ops->vhost_migration_done(&net->dev, mac_addr);
- }
-
- return r;
-}
-
-bool vhost_net_virtqueue_pending(VHostNetState *net, int idx)
-{
- return vhost_virtqueue_pending(&net->dev, idx);
-}
-
-void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev,
- int idx, bool mask)
-{
- vhost_virtqueue_mask(&net->dev, dev, idx, mask);
-}
-
-VHostNetState *get_vhost_net(NetClientState *nc)
-{
- VHostNetState *vhost_net = 0;
-
- if (!nc) {
- return 0;
- }
-
- switch (nc->info->type) {
- case NET_CLIENT_OPTIONS_KIND_TAP:
- vhost_net = tap_get_vhost_net(nc);
- break;
- case NET_CLIENT_OPTIONS_KIND_VHOST_USER:
- vhost_net = vhost_user_get_vhost_net(nc);
- break;
- default:
- break;
- }
-
- return vhost_net;
-}
-
-int vhost_set_vring_enable(NetClientState *nc, int enable)
-{
- VHostNetState *net = get_vhost_net(nc);
- const VhostOps *vhost_ops = net->dev.vhost_ops;
-
- if (vhost_ops->vhost_set_vring_enable) {
- return vhost_ops->vhost_set_vring_enable(&net->dev, enable);
- }
-
- return 0;
-}
-
-#else
-uint64_t vhost_net_get_max_queues(VHostNetState *net)
-{
- return 1;
-}
-
-struct vhost_net *vhost_net_init(VhostNetOptions *options)
-{
- error_report("vhost-net support is not compiled in");
- return NULL;
-}
-
-int vhost_net_start(VirtIODevice *dev,
- NetClientState *ncs,
- int total_queues)
-{
- return -ENOSYS;
-}
-void vhost_net_stop(VirtIODevice *dev,
- NetClientState *ncs,
- int total_queues)
-{
-}
-
-void vhost_net_cleanup(struct vhost_net *net)
-{
-}
-
-uint64_t vhost_net_get_features(struct vhost_net *net, uint64_t features)
-{
- return features;
-}
-void vhost_net_ack_features(struct vhost_net *net, uint64_t features)
-{
-}
-
-bool vhost_net_virtqueue_pending(VHostNetState *net, int idx)
-{
- return false;
-}
-
-void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev,
- int idx, bool mask)
-{
-}
-
-int vhost_net_notify_migration_done(struct vhost_net *net, char* mac_addr)
-{
- return -1;
-}
-
-VHostNetState *get_vhost_net(NetClientState *nc)
-{
- return 0;
-}
-
-int vhost_set_vring_enable(NetClientState *nc, int enable)
-{
- return 0;
-}
-#endif
diff --git a/qemu/hw/net/virtio-net.c b/qemu/hw/net/virtio-net.c
deleted file mode 100644
index 5798f87d8..000000000
--- a/qemu/hw/net/virtio-net.c
+++ /dev/null
@@ -1,1950 +0,0 @@
-/*
- * Virtio Network Device
- *
- * Copyright IBM, Corp. 2007
- *
- * Authors:
- * Anthony Liguori <aliguori@us.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "qemu/iov.h"
-#include "hw/virtio/virtio.h"
-#include "net/net.h"
-#include "net/checksum.h"
-#include "net/tap.h"
-#include "qemu/error-report.h"
-#include "qemu/timer.h"
-#include "hw/virtio/virtio-net.h"
-#include "net/vhost_net.h"
-#include "hw/virtio/virtio-bus.h"
-#include "qapi/qmp/qjson.h"
-#include "qapi-event.h"
-#include "hw/virtio/virtio-access.h"
-
-#define VIRTIO_NET_VM_VERSION 11
-
-#define MAC_TABLE_ENTRIES 64
-#define MAX_VLAN (1 << 12) /* Per 802.1Q definition */
-
-/*
- * Calculate the number of bytes up to and including the given 'field' of
- * 'container'.
- */
-#define endof(container, field) \
- (offsetof(container, field) + sizeof(((container *)0)->field))
-
-typedef struct VirtIOFeature {
- uint32_t flags;
- size_t end;
-} VirtIOFeature;
-
-static VirtIOFeature feature_sizes[] = {
- {.flags = 1 << VIRTIO_NET_F_MAC,
- .end = endof(struct virtio_net_config, mac)},
- {.flags = 1 << VIRTIO_NET_F_STATUS,
- .end = endof(struct virtio_net_config, status)},
- {.flags = 1 << VIRTIO_NET_F_MQ,
- .end = endof(struct virtio_net_config, max_virtqueue_pairs)},
- {}
-};
-
-static VirtIONetQueue *virtio_net_get_subqueue(NetClientState *nc)
-{
- VirtIONet *n = qemu_get_nic_opaque(nc);
-
- return &n->vqs[nc->queue_index];
-}
-
-static int vq2q(int queue_index)
-{
- return queue_index / 2;
-}
-
-/* TODO
- * - we could suppress RX interrupt if we were so inclined.
- */
-
-static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config)
-{
- VirtIONet *n = VIRTIO_NET(vdev);
- struct virtio_net_config netcfg;
-
- virtio_stw_p(vdev, &netcfg.status, n->status);
- virtio_stw_p(vdev, &netcfg.max_virtqueue_pairs, n->max_queues);
- memcpy(netcfg.mac, n->mac, ETH_ALEN);
- memcpy(config, &netcfg, n->config_size);
-}
-
-static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config)
-{
- VirtIONet *n = VIRTIO_NET(vdev);
- struct virtio_net_config netcfg = {};
-
- memcpy(&netcfg, config, n->config_size);
-
- if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_MAC_ADDR) &&
- !virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1) &&
- memcmp(netcfg.mac, n->mac, ETH_ALEN)) {
- memcpy(n->mac, netcfg.mac, ETH_ALEN);
- qemu_format_nic_info_str(qemu_get_queue(n->nic), n->mac);
- }
-}
-
-static bool virtio_net_started(VirtIONet *n, uint8_t status)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(n);
- return (status & VIRTIO_CONFIG_S_DRIVER_OK) &&
- (n->status & VIRTIO_NET_S_LINK_UP) && vdev->vm_running;
-}
-
-static void virtio_net_announce_timer(void *opaque)
-{
- VirtIONet *n = opaque;
- VirtIODevice *vdev = VIRTIO_DEVICE(n);
-
- n->announce_counter--;
- n->status |= VIRTIO_NET_S_ANNOUNCE;
- virtio_notify_config(vdev);
-}
-
-static void virtio_net_vhost_status(VirtIONet *n, uint8_t status)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(n);
- NetClientState *nc = qemu_get_queue(n->nic);
- int queues = n->multiqueue ? n->max_queues : 1;
-
- if (!get_vhost_net(nc->peer)) {
- return;
- }
-
- if ((virtio_net_started(n, status) && !nc->peer->link_down) ==
- !!n->vhost_started) {
- return;
- }
- if (!n->vhost_started) {
- int r, i;
-
- if (n->needs_vnet_hdr_swap) {
- error_report("backend does not support %s vnet headers; "
- "falling back on userspace virtio",
- virtio_is_big_endian(vdev) ? "BE" : "LE");
- return;
- }
-
- /* Any packets outstanding? Purge them to avoid touching rings
- * when vhost is running.
- */
- for (i = 0; i < queues; i++) {
- NetClientState *qnc = qemu_get_subqueue(n->nic, i);
-
- /* Purge both directions: TX and RX. */
- qemu_net_queue_purge(qnc->peer->incoming_queue, qnc);
- qemu_net_queue_purge(qnc->incoming_queue, qnc->peer);
- }
-
- n->vhost_started = 1;
- r = vhost_net_start(vdev, n->nic->ncs, queues);
- if (r < 0) {
- error_report("unable to start vhost net: %d: "
- "falling back on userspace virtio", -r);
- n->vhost_started = 0;
- }
- } else {
- vhost_net_stop(vdev, n->nic->ncs, queues);
- n->vhost_started = 0;
- }
-}
-
-static int virtio_net_set_vnet_endian_one(VirtIODevice *vdev,
- NetClientState *peer,
- bool enable)
-{
- if (virtio_is_big_endian(vdev)) {
- return qemu_set_vnet_be(peer, enable);
- } else {
- return qemu_set_vnet_le(peer, enable);
- }
-}
-
-static bool virtio_net_set_vnet_endian(VirtIODevice *vdev, NetClientState *ncs,
- int queues, bool enable)
-{
- int i;
-
- for (i = 0; i < queues; i++) {
- if (virtio_net_set_vnet_endian_one(vdev, ncs[i].peer, enable) < 0 &&
- enable) {
- while (--i >= 0) {
- virtio_net_set_vnet_endian_one(vdev, ncs[i].peer, false);
- }
-
- return true;
- }
- }
-
- return false;
-}
-
-static void virtio_net_vnet_endian_status(VirtIONet *n, uint8_t status)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(n);
- int queues = n->multiqueue ? n->max_queues : 1;
-
- if (virtio_net_started(n, status)) {
- /* Before using the device, we tell the network backend about the
- * endianness to use when parsing vnet headers. If the backend
- * can't do it, we fallback onto fixing the headers in the core
- * virtio-net code.
- */
- n->needs_vnet_hdr_swap = virtio_net_set_vnet_endian(vdev, n->nic->ncs,
- queues, true);
- } else if (virtio_net_started(n, vdev->status)) {
- /* After using the device, we need to reset the network backend to
- * the default (guest native endianness), otherwise the guest may
- * lose network connectivity if it is rebooted into a different
- * endianness.
- */
- virtio_net_set_vnet_endian(vdev, n->nic->ncs, queues, false);
- }
-}
-
-static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
-{
- VirtIONet *n = VIRTIO_NET(vdev);
- VirtIONetQueue *q;
- int i;
- uint8_t queue_status;
-
- virtio_net_vnet_endian_status(n, status);
- virtio_net_vhost_status(n, status);
-
- for (i = 0; i < n->max_queues; i++) {
- NetClientState *ncs = qemu_get_subqueue(n->nic, i);
- bool queue_started;
- q = &n->vqs[i];
-
- if ((!n->multiqueue && i != 0) || i >= n->curr_queues) {
- queue_status = 0;
- } else {
- queue_status = status;
- }
- queue_started =
- virtio_net_started(n, queue_status) && !n->vhost_started;
-
- if (queue_started) {
- qemu_flush_queued_packets(ncs);
- }
-
- if (!q->tx_waiting) {
- continue;
- }
-
- if (queue_started) {
- if (q->tx_timer) {
- timer_mod(q->tx_timer,
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + n->tx_timeout);
- } else {
- qemu_bh_schedule(q->tx_bh);
- }
- } else {
- if (q->tx_timer) {
- timer_del(q->tx_timer);
- } else {
- qemu_bh_cancel(q->tx_bh);
- }
- }
- }
-}
-
-static void virtio_net_set_link_status(NetClientState *nc)
-{
- VirtIONet *n = qemu_get_nic_opaque(nc);
- VirtIODevice *vdev = VIRTIO_DEVICE(n);
- uint16_t old_status = n->status;
-
- if (nc->link_down)
- n->status &= ~VIRTIO_NET_S_LINK_UP;
- else
- n->status |= VIRTIO_NET_S_LINK_UP;
-
- if (n->status != old_status)
- virtio_notify_config(vdev);
-
- virtio_net_set_status(vdev, vdev->status);
-}
-
-static void rxfilter_notify(NetClientState *nc)
-{
- VirtIONet *n = qemu_get_nic_opaque(nc);
-
- if (nc->rxfilter_notify_enabled) {
- gchar *path = object_get_canonical_path(OBJECT(n->qdev));
- qapi_event_send_nic_rx_filter_changed(!!n->netclient_name,
- n->netclient_name, path, &error_abort);
- g_free(path);
-
- /* disable event notification to avoid events flooding */
- nc->rxfilter_notify_enabled = 0;
- }
-}
-
-static intList *get_vlan_table(VirtIONet *n)
-{
- intList *list, *entry;
- int i, j;
-
- list = NULL;
- for (i = 0; i < MAX_VLAN >> 5; i++) {
- for (j = 0; n->vlans[i] && j <= 0x1f; j++) {
- if (n->vlans[i] & (1U << j)) {
- entry = g_malloc0(sizeof(*entry));
- entry->value = (i << 5) + j;
- entry->next = list;
- list = entry;
- }
- }
- }
-
- return list;
-}
-
-static RxFilterInfo *virtio_net_query_rxfilter(NetClientState *nc)
-{
- VirtIONet *n = qemu_get_nic_opaque(nc);
- VirtIODevice *vdev = VIRTIO_DEVICE(n);
- RxFilterInfo *info;
- strList *str_list, *entry;
- int i;
-
- info = g_malloc0(sizeof(*info));
- info->name = g_strdup(nc->name);
- info->promiscuous = n->promisc;
-
- if (n->nouni) {
- info->unicast = RX_STATE_NONE;
- } else if (n->alluni) {
- info->unicast = RX_STATE_ALL;
- } else {
- info->unicast = RX_STATE_NORMAL;
- }
-
- if (n->nomulti) {
- info->multicast = RX_STATE_NONE;
- } else if (n->allmulti) {
- info->multicast = RX_STATE_ALL;
- } else {
- info->multicast = RX_STATE_NORMAL;
- }
-
- info->broadcast_allowed = n->nobcast;
- info->multicast_overflow = n->mac_table.multi_overflow;
- info->unicast_overflow = n->mac_table.uni_overflow;
-
- info->main_mac = qemu_mac_strdup_printf(n->mac);
-
- str_list = NULL;
- for (i = 0; i < n->mac_table.first_multi; i++) {
- entry = g_malloc0(sizeof(*entry));
- entry->value = qemu_mac_strdup_printf(n->mac_table.macs + i * ETH_ALEN);
- entry->next = str_list;
- str_list = entry;
- }
- info->unicast_table = str_list;
-
- str_list = NULL;
- for (i = n->mac_table.first_multi; i < n->mac_table.in_use; i++) {
- entry = g_malloc0(sizeof(*entry));
- entry->value = qemu_mac_strdup_printf(n->mac_table.macs + i * ETH_ALEN);
- entry->next = str_list;
- str_list = entry;
- }
- info->multicast_table = str_list;
- info->vlan_table = get_vlan_table(n);
-
- if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_VLAN)) {
- info->vlan = RX_STATE_ALL;
- } else if (!info->vlan_table) {
- info->vlan = RX_STATE_NONE;
- } else {
- info->vlan = RX_STATE_NORMAL;
- }
-
- /* enable event notification after query */
- nc->rxfilter_notify_enabled = 1;
-
- return info;
-}
-
-static void virtio_net_reset(VirtIODevice *vdev)
-{
- VirtIONet *n = VIRTIO_NET(vdev);
-
- /* Reset back to compatibility mode */
- n->promisc = 1;
- n->allmulti = 0;
- n->alluni = 0;
- n->nomulti = 0;
- n->nouni = 0;
- n->nobcast = 0;
- /* multiqueue is disabled by default */
- n->curr_queues = 1;
- timer_del(n->announce_timer);
- n->announce_counter = 0;
- n->status &= ~VIRTIO_NET_S_ANNOUNCE;
-
- /* Flush any MAC and VLAN filter table state */
- n->mac_table.in_use = 0;
- n->mac_table.first_multi = 0;
- n->mac_table.multi_overflow = 0;
- n->mac_table.uni_overflow = 0;
- memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN);
- memcpy(&n->mac[0], &n->nic->conf->macaddr, sizeof(n->mac));
- qemu_format_nic_info_str(qemu_get_queue(n->nic), n->mac);
- memset(n->vlans, 0, MAX_VLAN >> 3);
-}
-
-static void peer_test_vnet_hdr(VirtIONet *n)
-{
- NetClientState *nc = qemu_get_queue(n->nic);
- if (!nc->peer) {
- return;
- }
-
- n->has_vnet_hdr = qemu_has_vnet_hdr(nc->peer);
-}
-
-static int peer_has_vnet_hdr(VirtIONet *n)
-{
- return n->has_vnet_hdr;
-}
-
-static int peer_has_ufo(VirtIONet *n)
-{
- if (!peer_has_vnet_hdr(n))
- return 0;
-
- n->has_ufo = qemu_has_ufo(qemu_get_queue(n->nic)->peer);
-
- return n->has_ufo;
-}
-
-static void virtio_net_set_mrg_rx_bufs(VirtIONet *n, int mergeable_rx_bufs,
- int version_1)
-{
- int i;
- NetClientState *nc;
-
- n->mergeable_rx_bufs = mergeable_rx_bufs;
-
- if (version_1) {
- n->guest_hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
- } else {
- n->guest_hdr_len = n->mergeable_rx_bufs ?
- sizeof(struct virtio_net_hdr_mrg_rxbuf) :
- sizeof(struct virtio_net_hdr);
- }
-
- for (i = 0; i < n->max_queues; i++) {
- nc = qemu_get_subqueue(n->nic, i);
-
- if (peer_has_vnet_hdr(n) &&
- qemu_has_vnet_hdr_len(nc->peer, n->guest_hdr_len)) {
- qemu_set_vnet_hdr_len(nc->peer, n->guest_hdr_len);
- n->host_hdr_len = n->guest_hdr_len;
- }
- }
-}
-
-static int peer_attach(VirtIONet *n, int index)
-{
- NetClientState *nc = qemu_get_subqueue(n->nic, index);
-
- if (!nc->peer) {
- return 0;
- }
-
- if (nc->peer->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER) {
- vhost_set_vring_enable(nc->peer, 1);
- }
-
- if (nc->peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) {
- return 0;
- }
-
- return tap_enable(nc->peer);
-}
-
-static int peer_detach(VirtIONet *n, int index)
-{
- NetClientState *nc = qemu_get_subqueue(n->nic, index);
-
- if (!nc->peer) {
- return 0;
- }
-
- if (nc->peer->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER) {
- vhost_set_vring_enable(nc->peer, 0);
- }
-
- if (nc->peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) {
- return 0;
- }
-
- return tap_disable(nc->peer);
-}
-
-static void virtio_net_set_queues(VirtIONet *n)
-{
- int i;
- int r;
-
- for (i = 0; i < n->max_queues; i++) {
- if (i < n->curr_queues) {
- r = peer_attach(n, i);
- assert(!r);
- } else {
- r = peer_detach(n, i);
- assert(!r);
- }
- }
-}
-
-static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue);
-
-static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features,
- Error **errp)
-{
- VirtIONet *n = VIRTIO_NET(vdev);
- NetClientState *nc = qemu_get_queue(n->nic);
-
- /* Firstly sync all virtio-net possible supported features */
- features |= n->host_features;
-
- virtio_add_feature(&features, VIRTIO_NET_F_MAC);
-
- if (!peer_has_vnet_hdr(n)) {
- virtio_clear_feature(&features, VIRTIO_NET_F_CSUM);
- virtio_clear_feature(&features, VIRTIO_NET_F_HOST_TSO4);
- virtio_clear_feature(&features, VIRTIO_NET_F_HOST_TSO6);
- virtio_clear_feature(&features, VIRTIO_NET_F_HOST_ECN);
-
- virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_CSUM);
- virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_TSO4);
- virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_TSO6);
- virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_ECN);
- }
-
- if (!peer_has_vnet_hdr(n) || !peer_has_ufo(n)) {
- virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_UFO);
- virtio_clear_feature(&features, VIRTIO_NET_F_HOST_UFO);
- }
-
- if (!get_vhost_net(nc->peer)) {
- return features;
- }
- return vhost_net_get_features(get_vhost_net(nc->peer), features);
-}
-
-static uint64_t virtio_net_bad_features(VirtIODevice *vdev)
-{
- uint64_t features = 0;
-
- /* Linux kernel 2.6.25. It understood MAC (as everyone must),
- * but also these: */
- virtio_add_feature(&features, VIRTIO_NET_F_MAC);
- virtio_add_feature(&features, VIRTIO_NET_F_CSUM);
- virtio_add_feature(&features, VIRTIO_NET_F_HOST_TSO4);
- virtio_add_feature(&features, VIRTIO_NET_F_HOST_TSO6);
- virtio_add_feature(&features, VIRTIO_NET_F_HOST_ECN);
-
- return features;
-}
-
-static void virtio_net_apply_guest_offloads(VirtIONet *n)
-{
- qemu_set_offload(qemu_get_queue(n->nic)->peer,
- !!(n->curr_guest_offloads & (1ULL << VIRTIO_NET_F_GUEST_CSUM)),
- !!(n->curr_guest_offloads & (1ULL << VIRTIO_NET_F_GUEST_TSO4)),
- !!(n->curr_guest_offloads & (1ULL << VIRTIO_NET_F_GUEST_TSO6)),
- !!(n->curr_guest_offloads & (1ULL << VIRTIO_NET_F_GUEST_ECN)),
- !!(n->curr_guest_offloads & (1ULL << VIRTIO_NET_F_GUEST_UFO)));
-}
-
-static uint64_t virtio_net_guest_offloads_by_features(uint32_t features)
-{
- static const uint64_t guest_offloads_mask =
- (1ULL << VIRTIO_NET_F_GUEST_CSUM) |
- (1ULL << VIRTIO_NET_F_GUEST_TSO4) |
- (1ULL << VIRTIO_NET_F_GUEST_TSO6) |
- (1ULL << VIRTIO_NET_F_GUEST_ECN) |
- (1ULL << VIRTIO_NET_F_GUEST_UFO);
-
- return guest_offloads_mask & features;
-}
-
-static inline uint64_t virtio_net_supported_guest_offloads(VirtIONet *n)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(n);
- return virtio_net_guest_offloads_by_features(vdev->guest_features);
-}
-
-static void virtio_net_set_features(VirtIODevice *vdev, uint64_t features)
-{
- VirtIONet *n = VIRTIO_NET(vdev);
- int i;
-
- virtio_net_set_multiqueue(n,
- virtio_has_feature(features, VIRTIO_NET_F_MQ));
-
- virtio_net_set_mrg_rx_bufs(n,
- virtio_has_feature(features,
- VIRTIO_NET_F_MRG_RXBUF),
- virtio_has_feature(features,
- VIRTIO_F_VERSION_1));
-
- if (n->has_vnet_hdr) {
- n->curr_guest_offloads =
- virtio_net_guest_offloads_by_features(features);
- virtio_net_apply_guest_offloads(n);
- }
-
- for (i = 0; i < n->max_queues; i++) {
- NetClientState *nc = qemu_get_subqueue(n->nic, i);
-
- if (!get_vhost_net(nc->peer)) {
- continue;
- }
- vhost_net_ack_features(get_vhost_net(nc->peer), features);
- }
-
- if (virtio_has_feature(features, VIRTIO_NET_F_CTRL_VLAN)) {
- memset(n->vlans, 0, MAX_VLAN >> 3);
- } else {
- memset(n->vlans, 0xff, MAX_VLAN >> 3);
- }
-}
-
-static int virtio_net_handle_rx_mode(VirtIONet *n, uint8_t cmd,
- struct iovec *iov, unsigned int iov_cnt)
-{
- uint8_t on;
- size_t s;
- NetClientState *nc = qemu_get_queue(n->nic);
-
- s = iov_to_buf(iov, iov_cnt, 0, &on, sizeof(on));
- if (s != sizeof(on)) {
- return VIRTIO_NET_ERR;
- }
-
- if (cmd == VIRTIO_NET_CTRL_RX_PROMISC) {
- n->promisc = on;
- } else if (cmd == VIRTIO_NET_CTRL_RX_ALLMULTI) {
- n->allmulti = on;
- } else if (cmd == VIRTIO_NET_CTRL_RX_ALLUNI) {
- n->alluni = on;
- } else if (cmd == VIRTIO_NET_CTRL_RX_NOMULTI) {
- n->nomulti = on;
- } else if (cmd == VIRTIO_NET_CTRL_RX_NOUNI) {
- n->nouni = on;
- } else if (cmd == VIRTIO_NET_CTRL_RX_NOBCAST) {
- n->nobcast = on;
- } else {
- return VIRTIO_NET_ERR;
- }
-
- rxfilter_notify(nc);
-
- return VIRTIO_NET_OK;
-}
-
-static int virtio_net_handle_offloads(VirtIONet *n, uint8_t cmd,
- struct iovec *iov, unsigned int iov_cnt)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(n);
- uint64_t offloads;
- size_t s;
-
- if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) {
- return VIRTIO_NET_ERR;
- }
-
- s = iov_to_buf(iov, iov_cnt, 0, &offloads, sizeof(offloads));
- if (s != sizeof(offloads)) {
- return VIRTIO_NET_ERR;
- }
-
- if (cmd == VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET) {
- uint64_t supported_offloads;
-
- if (!n->has_vnet_hdr) {
- return VIRTIO_NET_ERR;
- }
-
- supported_offloads = virtio_net_supported_guest_offloads(n);
- if (offloads & ~supported_offloads) {
- return VIRTIO_NET_ERR;
- }
-
- n->curr_guest_offloads = offloads;
- virtio_net_apply_guest_offloads(n);
-
- return VIRTIO_NET_OK;
- } else {
- return VIRTIO_NET_ERR;
- }
-}
-
-static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
- struct iovec *iov, unsigned int iov_cnt)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(n);
- struct virtio_net_ctrl_mac mac_data;
- size_t s;
- NetClientState *nc = qemu_get_queue(n->nic);
-
- if (cmd == VIRTIO_NET_CTRL_MAC_ADDR_SET) {
- if (iov_size(iov, iov_cnt) != sizeof(n->mac)) {
- return VIRTIO_NET_ERR;
- }
- s = iov_to_buf(iov, iov_cnt, 0, &n->mac, sizeof(n->mac));
- assert(s == sizeof(n->mac));
- qemu_format_nic_info_str(qemu_get_queue(n->nic), n->mac);
- rxfilter_notify(nc);
-
- return VIRTIO_NET_OK;
- }
-
- if (cmd != VIRTIO_NET_CTRL_MAC_TABLE_SET) {
- return VIRTIO_NET_ERR;
- }
-
- int in_use = 0;
- int first_multi = 0;
- uint8_t uni_overflow = 0;
- uint8_t multi_overflow = 0;
- uint8_t *macs = g_malloc0(MAC_TABLE_ENTRIES * ETH_ALEN);
-
- s = iov_to_buf(iov, iov_cnt, 0, &mac_data.entries,
- sizeof(mac_data.entries));
- mac_data.entries = virtio_ldl_p(vdev, &mac_data.entries);
- if (s != sizeof(mac_data.entries)) {
- goto error;
- }
- iov_discard_front(&iov, &iov_cnt, s);
-
- if (mac_data.entries * ETH_ALEN > iov_size(iov, iov_cnt)) {
- goto error;
- }
-
- if (mac_data.entries <= MAC_TABLE_ENTRIES) {
- s = iov_to_buf(iov, iov_cnt, 0, macs,
- mac_data.entries * ETH_ALEN);
- if (s != mac_data.entries * ETH_ALEN) {
- goto error;
- }
- in_use += mac_data.entries;
- } else {
- uni_overflow = 1;
- }
-
- iov_discard_front(&iov, &iov_cnt, mac_data.entries * ETH_ALEN);
-
- first_multi = in_use;
-
- s = iov_to_buf(iov, iov_cnt, 0, &mac_data.entries,
- sizeof(mac_data.entries));
- mac_data.entries = virtio_ldl_p(vdev, &mac_data.entries);
- if (s != sizeof(mac_data.entries)) {
- goto error;
- }
-
- iov_discard_front(&iov, &iov_cnt, s);
-
- if (mac_data.entries * ETH_ALEN != iov_size(iov, iov_cnt)) {
- goto error;
- }
-
- if (mac_data.entries <= MAC_TABLE_ENTRIES - in_use) {
- s = iov_to_buf(iov, iov_cnt, 0, &macs[in_use * ETH_ALEN],
- mac_data.entries * ETH_ALEN);
- if (s != mac_data.entries * ETH_ALEN) {
- goto error;
- }
- in_use += mac_data.entries;
- } else {
- multi_overflow = 1;
- }
-
- n->mac_table.in_use = in_use;
- n->mac_table.first_multi = first_multi;
- n->mac_table.uni_overflow = uni_overflow;
- n->mac_table.multi_overflow = multi_overflow;
- memcpy(n->mac_table.macs, macs, MAC_TABLE_ENTRIES * ETH_ALEN);
- g_free(macs);
- rxfilter_notify(nc);
-
- return VIRTIO_NET_OK;
-
-error:
- g_free(macs);
- return VIRTIO_NET_ERR;
-}
-
-static int virtio_net_handle_vlan_table(VirtIONet *n, uint8_t cmd,
- struct iovec *iov, unsigned int iov_cnt)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(n);
- uint16_t vid;
- size_t s;
- NetClientState *nc = qemu_get_queue(n->nic);
-
- s = iov_to_buf(iov, iov_cnt, 0, &vid, sizeof(vid));
- vid = virtio_lduw_p(vdev, &vid);
- if (s != sizeof(vid)) {
- return VIRTIO_NET_ERR;
- }
-
- if (vid >= MAX_VLAN)
- return VIRTIO_NET_ERR;
-
- if (cmd == VIRTIO_NET_CTRL_VLAN_ADD)
- n->vlans[vid >> 5] |= (1U << (vid & 0x1f));
- else if (cmd == VIRTIO_NET_CTRL_VLAN_DEL)
- n->vlans[vid >> 5] &= ~(1U << (vid & 0x1f));
- else
- return VIRTIO_NET_ERR;
-
- rxfilter_notify(nc);
-
- return VIRTIO_NET_OK;
-}
-
-static int virtio_net_handle_announce(VirtIONet *n, uint8_t cmd,
- struct iovec *iov, unsigned int iov_cnt)
-{
- if (cmd == VIRTIO_NET_CTRL_ANNOUNCE_ACK &&
- n->status & VIRTIO_NET_S_ANNOUNCE) {
- n->status &= ~VIRTIO_NET_S_ANNOUNCE;
- if (n->announce_counter) {
- timer_mod(n->announce_timer,
- qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
- self_announce_delay(n->announce_counter));
- }
- return VIRTIO_NET_OK;
- } else {
- return VIRTIO_NET_ERR;
- }
-}
-
-static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd,
- struct iovec *iov, unsigned int iov_cnt)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(n);
- struct virtio_net_ctrl_mq mq;
- size_t s;
- uint16_t queues;
-
- s = iov_to_buf(iov, iov_cnt, 0, &mq, sizeof(mq));
- if (s != sizeof(mq)) {
- return VIRTIO_NET_ERR;
- }
-
- if (cmd != VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET) {
- return VIRTIO_NET_ERR;
- }
-
- queues = virtio_lduw_p(vdev, &mq.virtqueue_pairs);
-
- if (queues < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN ||
- queues > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX ||
- queues > n->max_queues ||
- !n->multiqueue) {
- return VIRTIO_NET_ERR;
- }
-
- n->curr_queues = queues;
- /* stop the backend before changing the number of queues to avoid handling a
- * disabled queue */
- virtio_net_set_status(vdev, vdev->status);
- virtio_net_set_queues(n);
-
- return VIRTIO_NET_OK;
-}
-static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
-{
- VirtIONet *n = VIRTIO_NET(vdev);
- struct virtio_net_ctrl_hdr ctrl;
- virtio_net_ctrl_ack status = VIRTIO_NET_ERR;
- VirtQueueElement *elem;
- size_t s;
- struct iovec *iov, *iov2;
- unsigned int iov_cnt;
-
- for (;;) {
- elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
- if (!elem) {
- break;
- }
- if (iov_size(elem->in_sg, elem->in_num) < sizeof(status) ||
- iov_size(elem->out_sg, elem->out_num) < sizeof(ctrl)) {
- error_report("virtio-net ctrl missing headers");
- exit(1);
- }
-
- iov_cnt = elem->out_num;
- iov2 = iov = g_memdup(elem->out_sg, sizeof(struct iovec) * elem->out_num);
- s = iov_to_buf(iov, iov_cnt, 0, &ctrl, sizeof(ctrl));
- iov_discard_front(&iov, &iov_cnt, sizeof(ctrl));
- if (s != sizeof(ctrl)) {
- status = VIRTIO_NET_ERR;
- } else if (ctrl.class == VIRTIO_NET_CTRL_RX) {
- status = virtio_net_handle_rx_mode(n, ctrl.cmd, iov, iov_cnt);
- } else if (ctrl.class == VIRTIO_NET_CTRL_MAC) {
- status = virtio_net_handle_mac(n, ctrl.cmd, iov, iov_cnt);
- } else if (ctrl.class == VIRTIO_NET_CTRL_VLAN) {
- status = virtio_net_handle_vlan_table(n, ctrl.cmd, iov, iov_cnt);
- } else if (ctrl.class == VIRTIO_NET_CTRL_ANNOUNCE) {
- status = virtio_net_handle_announce(n, ctrl.cmd, iov, iov_cnt);
- } else if (ctrl.class == VIRTIO_NET_CTRL_MQ) {
- status = virtio_net_handle_mq(n, ctrl.cmd, iov, iov_cnt);
- } else if (ctrl.class == VIRTIO_NET_CTRL_GUEST_OFFLOADS) {
- status = virtio_net_handle_offloads(n, ctrl.cmd, iov, iov_cnt);
- }
-
- s = iov_from_buf(elem->in_sg, elem->in_num, 0, &status, sizeof(status));
- assert(s == sizeof(status));
-
- virtqueue_push(vq, elem, sizeof(status));
- virtio_notify(vdev, vq);
- g_free(iov2);
- g_free(elem);
- }
-}
-
-/* RX */
-
-static void virtio_net_handle_rx(VirtIODevice *vdev, VirtQueue *vq)
-{
- VirtIONet *n = VIRTIO_NET(vdev);
- int queue_index = vq2q(virtio_get_queue_index(vq));
-
- qemu_flush_queued_packets(qemu_get_subqueue(n->nic, queue_index));
-}
-
-static int virtio_net_can_receive(NetClientState *nc)
-{
- VirtIONet *n = qemu_get_nic_opaque(nc);
- VirtIODevice *vdev = VIRTIO_DEVICE(n);
- VirtIONetQueue *q = virtio_net_get_subqueue(nc);
-
- if (!vdev->vm_running) {
- return 0;
- }
-
- if (nc->queue_index >= n->curr_queues) {
- return 0;
- }
-
- if (!virtio_queue_ready(q->rx_vq) ||
- !(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) {
- return 0;
- }
-
- return 1;
-}
-
-static int virtio_net_has_buffers(VirtIONetQueue *q, int bufsize)
-{
- VirtIONet *n = q->n;
- if (virtio_queue_empty(q->rx_vq) ||
- (n->mergeable_rx_bufs &&
- !virtqueue_avail_bytes(q->rx_vq, bufsize, 0))) {
- virtio_queue_set_notification(q->rx_vq, 1);
-
- /* To avoid a race condition where the guest has made some buffers
- * available after the above check but before notification was
- * enabled, check for available buffers again.
- */
- if (virtio_queue_empty(q->rx_vq) ||
- (n->mergeable_rx_bufs &&
- !virtqueue_avail_bytes(q->rx_vq, bufsize, 0))) {
- return 0;
- }
- }
-
- virtio_queue_set_notification(q->rx_vq, 0);
- return 1;
-}
-
-static void virtio_net_hdr_swap(VirtIODevice *vdev, struct virtio_net_hdr *hdr)
-{
- virtio_tswap16s(vdev, &hdr->hdr_len);
- virtio_tswap16s(vdev, &hdr->gso_size);
- virtio_tswap16s(vdev, &hdr->csum_start);
- virtio_tswap16s(vdev, &hdr->csum_offset);
-}
-
-/* dhclient uses AF_PACKET but doesn't pass auxdata to the kernel so
- * it never finds out that the packets don't have valid checksums. This
- * causes dhclient to get upset. Fedora's carried a patch for ages to
- * fix this with Xen but it hasn't appeared in an upstream release of
- * dhclient yet.
- *
- * To avoid breaking existing guests, we catch udp packets and add
- * checksums. This is terrible but it's better than hacking the guest
- * kernels.
- *
- * N.B. if we introduce a zero-copy API, this operation is no longer free so
- * we should provide a mechanism to disable it to avoid polluting the host
- * cache.
- */
-static void work_around_broken_dhclient(struct virtio_net_hdr *hdr,
- uint8_t *buf, size_t size)
-{
- if ((hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) && /* missing csum */
- (size > 27 && size < 1500) && /* normal sized MTU */
- (buf[12] == 0x08 && buf[13] == 0x00) && /* ethertype == IPv4 */
- (buf[23] == 17) && /* ip.protocol == UDP */
- (buf[34] == 0 && buf[35] == 67)) { /* udp.srcport == bootps */
- net_checksum_calculate(buf, size);
- hdr->flags &= ~VIRTIO_NET_HDR_F_NEEDS_CSUM;
- }
-}
-
-static void receive_header(VirtIONet *n, const struct iovec *iov, int iov_cnt,
- const void *buf, size_t size)
-{
- if (n->has_vnet_hdr) {
- /* FIXME this cast is evil */
- void *wbuf = (void *)buf;
- work_around_broken_dhclient(wbuf, wbuf + n->host_hdr_len,
- size - n->host_hdr_len);
-
- if (n->needs_vnet_hdr_swap) {
- virtio_net_hdr_swap(VIRTIO_DEVICE(n), wbuf);
- }
- iov_from_buf(iov, iov_cnt, 0, buf, sizeof(struct virtio_net_hdr));
- } else {
- struct virtio_net_hdr hdr = {
- .flags = 0,
- .gso_type = VIRTIO_NET_HDR_GSO_NONE
- };
- iov_from_buf(iov, iov_cnt, 0, &hdr, sizeof hdr);
- }
-}
-
-static int receive_filter(VirtIONet *n, const uint8_t *buf, int size)
-{
- static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
- static const uint8_t vlan[] = {0x81, 0x00};
- uint8_t *ptr = (uint8_t *)buf;
- int i;
-
- if (n->promisc)
- return 1;
-
- ptr += n->host_hdr_len;
-
- if (!memcmp(&ptr[12], vlan, sizeof(vlan))) {
- int vid = be16_to_cpup((uint16_t *)(ptr + 14)) & 0xfff;
- if (!(n->vlans[vid >> 5] & (1U << (vid & 0x1f))))
- return 0;
- }
-
- if (ptr[0] & 1) { // multicast
- if (!memcmp(ptr, bcast, sizeof(bcast))) {
- return !n->nobcast;
- } else if (n->nomulti) {
- return 0;
- } else if (n->allmulti || n->mac_table.multi_overflow) {
- return 1;
- }
-
- for (i = n->mac_table.first_multi; i < n->mac_table.in_use; i++) {
- if (!memcmp(ptr, &n->mac_table.macs[i * ETH_ALEN], ETH_ALEN)) {
- return 1;
- }
- }
- } else { // unicast
- if (n->nouni) {
- return 0;
- } else if (n->alluni || n->mac_table.uni_overflow) {
- return 1;
- } else if (!memcmp(ptr, n->mac, ETH_ALEN)) {
- return 1;
- }
-
- for (i = 0; i < n->mac_table.first_multi; i++) {
- if (!memcmp(ptr, &n->mac_table.macs[i * ETH_ALEN], ETH_ALEN)) {
- return 1;
- }
- }
- }
-
- return 0;
-}
-
-static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t size)
-{
- VirtIONet *n = qemu_get_nic_opaque(nc);
- VirtIONetQueue *q = virtio_net_get_subqueue(nc);
- VirtIODevice *vdev = VIRTIO_DEVICE(n);
- struct iovec mhdr_sg[VIRTQUEUE_MAX_SIZE];
- struct virtio_net_hdr_mrg_rxbuf mhdr;
- unsigned mhdr_cnt = 0;
- size_t offset, i, guest_offset;
-
- if (!virtio_net_can_receive(nc)) {
- return -1;
- }
-
- /* hdr_len refers to the header we supply to the guest */
- if (!virtio_net_has_buffers(q, size + n->guest_hdr_len - n->host_hdr_len)) {
- return 0;
- }
-
- if (!receive_filter(n, buf, size))
- return size;
-
- offset = i = 0;
-
- while (offset < size) {
- VirtQueueElement *elem;
- int len, total;
- const struct iovec *sg;
-
- total = 0;
-
- elem = virtqueue_pop(q->rx_vq, sizeof(VirtQueueElement));
- if (!elem) {
- if (i == 0)
- return -1;
- error_report("virtio-net unexpected empty queue: "
- "i %zd mergeable %d offset %zd, size %zd, "
- "guest hdr len %zd, host hdr len %zd "
- "guest features 0x%" PRIx64,
- i, n->mergeable_rx_bufs, offset, size,
- n->guest_hdr_len, n->host_hdr_len,
- vdev->guest_features);
- exit(1);
- }
-
- if (elem->in_num < 1) {
- error_report("virtio-net receive queue contains no in buffers");
- exit(1);
- }
-
- sg = elem->in_sg;
- if (i == 0) {
- assert(offset == 0);
- if (n->mergeable_rx_bufs) {
- mhdr_cnt = iov_copy(mhdr_sg, ARRAY_SIZE(mhdr_sg),
- sg, elem->in_num,
- offsetof(typeof(mhdr), num_buffers),
- sizeof(mhdr.num_buffers));
- }
-
- receive_header(n, sg, elem->in_num, buf, size);
- offset = n->host_hdr_len;
- total += n->guest_hdr_len;
- guest_offset = n->guest_hdr_len;
- } else {
- guest_offset = 0;
- }
-
- /* copy in packet. ugh */
- len = iov_from_buf(sg, elem->in_num, guest_offset,
- buf + offset, size - offset);
- total += len;
- offset += len;
- /* If buffers can't be merged, at this point we
- * must have consumed the complete packet.
- * Otherwise, drop it. */
- if (!n->mergeable_rx_bufs && offset < size) {
- virtqueue_discard(q->rx_vq, elem, total);
- g_free(elem);
- return size;
- }
-
- /* signal other side */
- virtqueue_fill(q->rx_vq, elem, total, i++);
- g_free(elem);
- }
-
- if (mhdr_cnt) {
- virtio_stw_p(vdev, &mhdr.num_buffers, i);
- iov_from_buf(mhdr_sg, mhdr_cnt,
- 0,
- &mhdr.num_buffers, sizeof mhdr.num_buffers);
- }
-
- virtqueue_flush(q->rx_vq, i);
- virtio_notify(vdev, q->rx_vq);
-
- return size;
-}
-
-static int32_t virtio_net_flush_tx(VirtIONetQueue *q);
-
-static void virtio_net_tx_complete(NetClientState *nc, ssize_t len)
-{
- VirtIONet *n = qemu_get_nic_opaque(nc);
- VirtIONetQueue *q = virtio_net_get_subqueue(nc);
- VirtIODevice *vdev = VIRTIO_DEVICE(n);
-
- virtqueue_push(q->tx_vq, q->async_tx.elem, 0);
- virtio_notify(vdev, q->tx_vq);
-
- g_free(q->async_tx.elem);
- q->async_tx.elem = NULL;
-
- virtio_queue_set_notification(q->tx_vq, 1);
- virtio_net_flush_tx(q);
-}
-
-/* TX */
-static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
-{
- VirtIONet *n = q->n;
- VirtIODevice *vdev = VIRTIO_DEVICE(n);
- VirtQueueElement *elem;
- int32_t num_packets = 0;
- int queue_index = vq2q(virtio_get_queue_index(q->tx_vq));
- if (!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) {
- return num_packets;
- }
-
- if (q->async_tx.elem) {
- virtio_queue_set_notification(q->tx_vq, 0);
- return num_packets;
- }
-
- for (;;) {
- ssize_t ret;
- unsigned int out_num;
- struct iovec sg[VIRTQUEUE_MAX_SIZE], sg2[VIRTQUEUE_MAX_SIZE + 1], *out_sg;
- struct virtio_net_hdr_mrg_rxbuf mhdr;
-
- elem = virtqueue_pop(q->tx_vq, sizeof(VirtQueueElement));
- if (!elem) {
- break;
- }
-
- out_num = elem->out_num;
- out_sg = elem->out_sg;
- if (out_num < 1) {
- error_report("virtio-net header not in first element");
- exit(1);
- }
-
- if (n->has_vnet_hdr) {
- if (iov_to_buf(out_sg, out_num, 0, &mhdr, n->guest_hdr_len) <
- n->guest_hdr_len) {
- error_report("virtio-net header incorrect");
- exit(1);
- }
- if (n->needs_vnet_hdr_swap) {
- virtio_net_hdr_swap(vdev, (void *) &mhdr);
- sg2[0].iov_base = &mhdr;
- sg2[0].iov_len = n->guest_hdr_len;
- out_num = iov_copy(&sg2[1], ARRAY_SIZE(sg2) - 1,
- out_sg, out_num,
- n->guest_hdr_len, -1);
- if (out_num == VIRTQUEUE_MAX_SIZE) {
- goto drop;
- }
- out_num += 1;
- out_sg = sg2;
- }
- }
- /*
- * If host wants to see the guest header as is, we can
- * pass it on unchanged. Otherwise, copy just the parts
- * that host is interested in.
- */
- assert(n->host_hdr_len <= n->guest_hdr_len);
- if (n->host_hdr_len != n->guest_hdr_len) {
- unsigned sg_num = iov_copy(sg, ARRAY_SIZE(sg),
- out_sg, out_num,
- 0, n->host_hdr_len);
- sg_num += iov_copy(sg + sg_num, ARRAY_SIZE(sg) - sg_num,
- out_sg, out_num,
- n->guest_hdr_len, -1);
- out_num = sg_num;
- out_sg = sg;
- }
-
- ret = qemu_sendv_packet_async(qemu_get_subqueue(n->nic, queue_index),
- out_sg, out_num, virtio_net_tx_complete);
- if (ret == 0) {
- virtio_queue_set_notification(q->tx_vq, 0);
- q->async_tx.elem = elem;
- return -EBUSY;
- }
-
-drop:
- virtqueue_push(q->tx_vq, elem, 0);
- virtio_notify(vdev, q->tx_vq);
- g_free(elem);
-
- if (++num_packets >= n->tx_burst) {
- break;
- }
- }
- return num_packets;
-}
-
-static void virtio_net_handle_tx_timer(VirtIODevice *vdev, VirtQueue *vq)
-{
- VirtIONet *n = VIRTIO_NET(vdev);
- VirtIONetQueue *q = &n->vqs[vq2q(virtio_get_queue_index(vq))];
-
- /* This happens when device was stopped but VCPU wasn't. */
- if (!vdev->vm_running) {
- q->tx_waiting = 1;
- return;
- }
-
- if (q->tx_waiting) {
- virtio_queue_set_notification(vq, 1);
- timer_del(q->tx_timer);
- q->tx_waiting = 0;
- virtio_net_flush_tx(q);
- } else {
- timer_mod(q->tx_timer,
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + n->tx_timeout);
- q->tx_waiting = 1;
- virtio_queue_set_notification(vq, 0);
- }
-}
-
-static void virtio_net_handle_tx_bh(VirtIODevice *vdev, VirtQueue *vq)
-{
- VirtIONet *n = VIRTIO_NET(vdev);
- VirtIONetQueue *q = &n->vqs[vq2q(virtio_get_queue_index(vq))];
-
- if (unlikely(q->tx_waiting)) {
- return;
- }
- q->tx_waiting = 1;
- /* This happens when device was stopped but VCPU wasn't. */
- if (!vdev->vm_running) {
- return;
- }
- virtio_queue_set_notification(vq, 0);
- qemu_bh_schedule(q->tx_bh);
-}
-
-static void virtio_net_tx_timer(void *opaque)
-{
- VirtIONetQueue *q = opaque;
- VirtIONet *n = q->n;
- VirtIODevice *vdev = VIRTIO_DEVICE(n);
- /* This happens when device was stopped but BH wasn't. */
- if (!vdev->vm_running) {
- /* Make sure tx waiting is set, so we'll run when restarted. */
- assert(q->tx_waiting);
- return;
- }
-
- q->tx_waiting = 0;
-
- /* Just in case the driver is not ready on more */
- if (!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) {
- return;
- }
-
- virtio_queue_set_notification(q->tx_vq, 1);
- virtio_net_flush_tx(q);
-}
-
-static void virtio_net_tx_bh(void *opaque)
-{
- VirtIONetQueue *q = opaque;
- VirtIONet *n = q->n;
- VirtIODevice *vdev = VIRTIO_DEVICE(n);
- int32_t ret;
-
- /* This happens when device was stopped but BH wasn't. */
- if (!vdev->vm_running) {
- /* Make sure tx waiting is set, so we'll run when restarted. */
- assert(q->tx_waiting);
- return;
- }
-
- q->tx_waiting = 0;
-
- /* Just in case the driver is not ready on more */
- if (unlikely(!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK))) {
- return;
- }
-
- ret = virtio_net_flush_tx(q);
- if (ret == -EBUSY) {
- return; /* Notification re-enable handled by tx_complete */
- }
-
- /* If we flush a full burst of packets, assume there are
- * more coming and immediately reschedule */
- if (ret >= n->tx_burst) {
- qemu_bh_schedule(q->tx_bh);
- q->tx_waiting = 1;
- return;
- }
-
- /* If less than a full burst, re-enable notification and flush
- * anything that may have come in while we weren't looking. If
- * we find something, assume the guest is still active and reschedule */
- virtio_queue_set_notification(q->tx_vq, 1);
- if (virtio_net_flush_tx(q) > 0) {
- virtio_queue_set_notification(q->tx_vq, 0);
- qemu_bh_schedule(q->tx_bh);
- q->tx_waiting = 1;
- }
-}
-
-static void virtio_net_add_queue(VirtIONet *n, int index)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(n);
-
- n->vqs[index].rx_vq = virtio_add_queue(vdev, 256, virtio_net_handle_rx);
- if (n->net_conf.tx && !strcmp(n->net_conf.tx, "timer")) {
- n->vqs[index].tx_vq =
- virtio_add_queue(vdev, 256, virtio_net_handle_tx_timer);
- n->vqs[index].tx_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
- virtio_net_tx_timer,
- &n->vqs[index]);
- } else {
- n->vqs[index].tx_vq =
- virtio_add_queue(vdev, 256, virtio_net_handle_tx_bh);
- n->vqs[index].tx_bh = qemu_bh_new(virtio_net_tx_bh, &n->vqs[index]);
- }
-
- n->vqs[index].tx_waiting = 0;
- n->vqs[index].n = n;
-}
-
-static void virtio_net_del_queue(VirtIONet *n, int index)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(n);
- VirtIONetQueue *q = &n->vqs[index];
- NetClientState *nc = qemu_get_subqueue(n->nic, index);
-
- qemu_purge_queued_packets(nc);
-
- virtio_del_queue(vdev, index * 2);
- if (q->tx_timer) {
- timer_del(q->tx_timer);
- timer_free(q->tx_timer);
- } else {
- qemu_bh_delete(q->tx_bh);
- }
- virtio_del_queue(vdev, index * 2 + 1);
-}
-
-static void virtio_net_change_num_queues(VirtIONet *n, int new_max_queues)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(n);
- int old_num_queues = virtio_get_num_queues(vdev);
- int new_num_queues = new_max_queues * 2 + 1;
- int i;
-
- assert(old_num_queues >= 3);
- assert(old_num_queues % 2 == 1);
-
- if (old_num_queues == new_num_queues) {
- return;
- }
-
- /*
- * We always need to remove and add ctrl vq if
- * old_num_queues != new_num_queues. Remove ctrl_vq first,
- * and then we only enter one of the following too loops.
- */
- virtio_del_queue(vdev, old_num_queues - 1);
-
- for (i = new_num_queues - 1; i < old_num_queues - 1; i += 2) {
- /* new_num_queues < old_num_queues */
- virtio_net_del_queue(n, i / 2);
- }
-
- for (i = old_num_queues - 1; i < new_num_queues - 1; i += 2) {
- /* new_num_queues > old_num_queues */
- virtio_net_add_queue(n, i / 2);
- }
-
- /* add ctrl_vq last */
- n->ctrl_vq = virtio_add_queue(vdev, 64, virtio_net_handle_ctrl);
-}
-
-static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue)
-{
- int max = multiqueue ? n->max_queues : 1;
-
- n->multiqueue = multiqueue;
- virtio_net_change_num_queues(n, max);
-
- virtio_net_set_queues(n);
-}
-
-static void virtio_net_save(QEMUFile *f, void *opaque)
-{
- VirtIONet *n = opaque;
- VirtIODevice *vdev = VIRTIO_DEVICE(n);
-
- /* At this point, backend must be stopped, otherwise
- * it might keep writing to memory. */
- assert(!n->vhost_started);
- virtio_save(vdev, f);
-}
-
-static void virtio_net_save_device(VirtIODevice *vdev, QEMUFile *f)
-{
- VirtIONet *n = VIRTIO_NET(vdev);
- int i;
-
- qemu_put_buffer(f, n->mac, ETH_ALEN);
- qemu_put_be32(f, n->vqs[0].tx_waiting);
- qemu_put_be32(f, n->mergeable_rx_bufs);
- qemu_put_be16(f, n->status);
- qemu_put_byte(f, n->promisc);
- qemu_put_byte(f, n->allmulti);
- qemu_put_be32(f, n->mac_table.in_use);
- qemu_put_buffer(f, n->mac_table.macs, n->mac_table.in_use * ETH_ALEN);
- qemu_put_buffer(f, (uint8_t *)n->vlans, MAX_VLAN >> 3);
- qemu_put_be32(f, n->has_vnet_hdr);
- qemu_put_byte(f, n->mac_table.multi_overflow);
- qemu_put_byte(f, n->mac_table.uni_overflow);
- qemu_put_byte(f, n->alluni);
- qemu_put_byte(f, n->nomulti);
- qemu_put_byte(f, n->nouni);
- qemu_put_byte(f, n->nobcast);
- qemu_put_byte(f, n->has_ufo);
- if (n->max_queues > 1) {
- qemu_put_be16(f, n->max_queues);
- qemu_put_be16(f, n->curr_queues);
- for (i = 1; i < n->curr_queues; i++) {
- qemu_put_be32(f, n->vqs[i].tx_waiting);
- }
- }
-
- if (virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) {
- qemu_put_be64(f, n->curr_guest_offloads);
- }
-}
-
-static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
-{
- VirtIONet *n = opaque;
- VirtIODevice *vdev = VIRTIO_DEVICE(n);
- int ret;
-
- if (version_id < 2 || version_id > VIRTIO_NET_VM_VERSION)
- return -EINVAL;
-
- ret = virtio_load(vdev, f, version_id);
- if (ret) {
- return ret;
- }
-
- if (virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) {
- n->curr_guest_offloads = qemu_get_be64(f);
- } else {
- n->curr_guest_offloads = virtio_net_supported_guest_offloads(n);
- }
-
- if (peer_has_vnet_hdr(n)) {
- virtio_net_apply_guest_offloads(n);
- }
-
- if (virtio_vdev_has_feature(vdev, VIRTIO_NET_F_GUEST_ANNOUNCE) &&
- virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ)) {
- n->announce_counter = SELF_ANNOUNCE_ROUNDS;
- timer_mod(n->announce_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL));
- }
-
- return 0;
-}
-
-static int virtio_net_load_device(VirtIODevice *vdev, QEMUFile *f,
- int version_id)
-{
- VirtIONet *n = VIRTIO_NET(vdev);
- int i, link_down;
-
- qemu_get_buffer(f, n->mac, ETH_ALEN);
- n->vqs[0].tx_waiting = qemu_get_be32(f);
-
- virtio_net_set_mrg_rx_bufs(n, qemu_get_be32(f),
- virtio_vdev_has_feature(vdev,
- VIRTIO_F_VERSION_1));
-
- if (version_id >= 3)
- n->status = qemu_get_be16(f);
-
- if (version_id >= 4) {
- if (version_id < 8) {
- n->promisc = qemu_get_be32(f);
- n->allmulti = qemu_get_be32(f);
- } else {
- n->promisc = qemu_get_byte(f);
- n->allmulti = qemu_get_byte(f);
- }
- }
-
- if (version_id >= 5) {
- n->mac_table.in_use = qemu_get_be32(f);
- /* MAC_TABLE_ENTRIES may be different from the saved image */
- if (n->mac_table.in_use <= MAC_TABLE_ENTRIES) {
- qemu_get_buffer(f, n->mac_table.macs,
- n->mac_table.in_use * ETH_ALEN);
- } else {
- int64_t i;
-
- /* Overflow detected - can happen if source has a larger MAC table.
- * We simply set overflow flag so there's no need to maintain the
- * table of addresses, discard them all.
- * Note: 64 bit math to avoid integer overflow.
- */
- for (i = 0; i < (int64_t)n->mac_table.in_use * ETH_ALEN; ++i) {
- qemu_get_byte(f);
- }
- n->mac_table.multi_overflow = n->mac_table.uni_overflow = 1;
- n->mac_table.in_use = 0;
- }
- }
-
- if (version_id >= 6)
- qemu_get_buffer(f, (uint8_t *)n->vlans, MAX_VLAN >> 3);
-
- if (version_id >= 7) {
- if (qemu_get_be32(f) && !peer_has_vnet_hdr(n)) {
- error_report("virtio-net: saved image requires vnet_hdr=on");
- return -1;
- }
- }
-
- if (version_id >= 9) {
- n->mac_table.multi_overflow = qemu_get_byte(f);
- n->mac_table.uni_overflow = qemu_get_byte(f);
- }
-
- if (version_id >= 10) {
- n->alluni = qemu_get_byte(f);
- n->nomulti = qemu_get_byte(f);
- n->nouni = qemu_get_byte(f);
- n->nobcast = qemu_get_byte(f);
- }
-
- if (version_id >= 11) {
- if (qemu_get_byte(f) && !peer_has_ufo(n)) {
- error_report("virtio-net: saved image requires TUN_F_UFO support");
- return -1;
- }
- }
-
- if (n->max_queues > 1) {
- if (n->max_queues != qemu_get_be16(f)) {
- error_report("virtio-net: different max_queues ");
- return -1;
- }
-
- n->curr_queues = qemu_get_be16(f);
- if (n->curr_queues > n->max_queues) {
- error_report("virtio-net: curr_queues %x > max_queues %x",
- n->curr_queues, n->max_queues);
- return -1;
- }
- for (i = 1; i < n->curr_queues; i++) {
- n->vqs[i].tx_waiting = qemu_get_be32(f);
- }
- }
-
- virtio_net_set_queues(n);
-
- /* Find the first multicast entry in the saved MAC filter */
- for (i = 0; i < n->mac_table.in_use; i++) {
- if (n->mac_table.macs[i * ETH_ALEN] & 1) {
- break;
- }
- }
- n->mac_table.first_multi = i;
-
- /* nc.link_down can't be migrated, so infer link_down according
- * to link status bit in n->status */
- link_down = (n->status & VIRTIO_NET_S_LINK_UP) == 0;
- for (i = 0; i < n->max_queues; i++) {
- qemu_get_subqueue(n->nic, i)->link_down = link_down;
- }
-
- return 0;
-}
-
-static NetClientInfo net_virtio_info = {
- .type = NET_CLIENT_OPTIONS_KIND_NIC,
- .size = sizeof(NICState),
- .can_receive = virtio_net_can_receive,
- .receive = virtio_net_receive,
- .link_status_changed = virtio_net_set_link_status,
- .query_rx_filter = virtio_net_query_rxfilter,
-};
-
-static bool virtio_net_guest_notifier_pending(VirtIODevice *vdev, int idx)
-{
- VirtIONet *n = VIRTIO_NET(vdev);
- NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(idx));
- assert(n->vhost_started);
- return vhost_net_virtqueue_pending(get_vhost_net(nc->peer), idx);
-}
-
-static void virtio_net_guest_notifier_mask(VirtIODevice *vdev, int idx,
- bool mask)
-{
- VirtIONet *n = VIRTIO_NET(vdev);
- NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(idx));
- assert(n->vhost_started);
- vhost_net_virtqueue_mask(get_vhost_net(nc->peer),
- vdev, idx, mask);
-}
-
-static void virtio_net_set_config_size(VirtIONet *n, uint64_t host_features)
-{
- int i, config_size = 0;
- virtio_add_feature(&host_features, VIRTIO_NET_F_MAC);
- for (i = 0; feature_sizes[i].flags != 0; i++) {
- if (host_features & feature_sizes[i].flags) {
- config_size = MAX(feature_sizes[i].end, config_size);
- }
- }
- n->config_size = config_size;
-}
-
-void virtio_net_set_netclient_name(VirtIONet *n, const char *name,
- const char *type)
-{
- /*
- * The name can be NULL, the netclient name will be type.x.
- */
- assert(type != NULL);
-
- g_free(n->netclient_name);
- g_free(n->netclient_type);
- n->netclient_name = g_strdup(name);
- n->netclient_type = g_strdup(type);
-}
-
-static void virtio_net_device_realize(DeviceState *dev, Error **errp)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
- VirtIONet *n = VIRTIO_NET(dev);
- NetClientState *nc;
- int i;
-
- virtio_net_set_config_size(n, n->host_features);
- virtio_init(vdev, "virtio-net", VIRTIO_ID_NET, n->config_size);
-
- n->max_queues = MAX(n->nic_conf.peers.queues, 1);
- if (n->max_queues * 2 + 1 > VIRTIO_QUEUE_MAX) {
- error_setg(errp, "Invalid number of queues (= %" PRIu32 "), "
- "must be a positive integer less than %d.",
- n->max_queues, (VIRTIO_QUEUE_MAX - 1) / 2);
- virtio_cleanup(vdev);
- return;
- }
- n->vqs = g_malloc0(sizeof(VirtIONetQueue) * n->max_queues);
- n->curr_queues = 1;
- n->tx_timeout = n->net_conf.txtimer;
-
- if (n->net_conf.tx && strcmp(n->net_conf.tx, "timer")
- && strcmp(n->net_conf.tx, "bh")) {
- error_report("virtio-net: "
- "Unknown option tx=%s, valid options: \"timer\" \"bh\"",
- n->net_conf.tx);
- error_report("Defaulting to \"bh\"");
- }
-
- for (i = 0; i < n->max_queues; i++) {
- virtio_net_add_queue(n, i);
- }
-
- n->ctrl_vq = virtio_add_queue(vdev, 64, virtio_net_handle_ctrl);
- qemu_macaddr_default_if_unset(&n->nic_conf.macaddr);
- memcpy(&n->mac[0], &n->nic_conf.macaddr, sizeof(n->mac));
- n->status = VIRTIO_NET_S_LINK_UP;
- n->announce_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL,
- virtio_net_announce_timer, n);
-
- if (n->netclient_type) {
- /*
- * Happen when virtio_net_set_netclient_name has been called.
- */
- n->nic = qemu_new_nic(&net_virtio_info, &n->nic_conf,
- n->netclient_type, n->netclient_name, n);
- } else {
- n->nic = qemu_new_nic(&net_virtio_info, &n->nic_conf,
- object_get_typename(OBJECT(dev)), dev->id, n);
- }
-
- peer_test_vnet_hdr(n);
- if (peer_has_vnet_hdr(n)) {
- for (i = 0; i < n->max_queues; i++) {
- qemu_using_vnet_hdr(qemu_get_subqueue(n->nic, i)->peer, true);
- }
- n->host_hdr_len = sizeof(struct virtio_net_hdr);
- } else {
- n->host_hdr_len = 0;
- }
-
- qemu_format_nic_info_str(qemu_get_queue(n->nic), n->nic_conf.macaddr.a);
-
- n->vqs[0].tx_waiting = 0;
- n->tx_burst = n->net_conf.txburst;
- virtio_net_set_mrg_rx_bufs(n, 0, 0);
- n->promisc = 1; /* for compatibility */
-
- n->mac_table.macs = g_malloc0(MAC_TABLE_ENTRIES * ETH_ALEN);
-
- n->vlans = g_malloc0(MAX_VLAN >> 3);
-
- nc = qemu_get_queue(n->nic);
- nc->rxfilter_notify_enabled = 1;
-
- n->qdev = dev;
- register_savevm(dev, "virtio-net", -1, VIRTIO_NET_VM_VERSION,
- virtio_net_save, virtio_net_load, n);
-}
-
-static void virtio_net_device_unrealize(DeviceState *dev, Error **errp)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
- VirtIONet *n = VIRTIO_NET(dev);
- int i, max_queues;
-
- /* This will stop vhost backend if appropriate. */
- virtio_net_set_status(vdev, 0);
-
- unregister_savevm(dev, "virtio-net", n);
-
- g_free(n->netclient_name);
- n->netclient_name = NULL;
- g_free(n->netclient_type);
- n->netclient_type = NULL;
-
- g_free(n->mac_table.macs);
- g_free(n->vlans);
-
- max_queues = n->multiqueue ? n->max_queues : 1;
- for (i = 0; i < max_queues; i++) {
- virtio_net_del_queue(n, i);
- }
-
- timer_del(n->announce_timer);
- timer_free(n->announce_timer);
- g_free(n->vqs);
- qemu_del_nic(n->nic);
- virtio_cleanup(vdev);
-}
-
-static void virtio_net_instance_init(Object *obj)
-{
- VirtIONet *n = VIRTIO_NET(obj);
-
- /*
- * The default config_size is sizeof(struct virtio_net_config).
- * Can be overriden with virtio_net_set_config_size.
- */
- n->config_size = sizeof(struct virtio_net_config);
- device_add_bootindex_property(obj, &n->nic_conf.bootindex,
- "bootindex", "/ethernet-phy@0",
- DEVICE(n), NULL);
-}
-
-static Property virtio_net_properties[] = {
- DEFINE_PROP_BIT("csum", VirtIONet, host_features, VIRTIO_NET_F_CSUM, true),
- DEFINE_PROP_BIT("guest_csum", VirtIONet, host_features,
- VIRTIO_NET_F_GUEST_CSUM, true),
- DEFINE_PROP_BIT("gso", VirtIONet, host_features, VIRTIO_NET_F_GSO, true),
- DEFINE_PROP_BIT("guest_tso4", VirtIONet, host_features,
- VIRTIO_NET_F_GUEST_TSO4, true),
- DEFINE_PROP_BIT("guest_tso6", VirtIONet, host_features,
- VIRTIO_NET_F_GUEST_TSO6, true),
- DEFINE_PROP_BIT("guest_ecn", VirtIONet, host_features,
- VIRTIO_NET_F_GUEST_ECN, true),
- DEFINE_PROP_BIT("guest_ufo", VirtIONet, host_features,
- VIRTIO_NET_F_GUEST_UFO, true),
- DEFINE_PROP_BIT("guest_announce", VirtIONet, host_features,
- VIRTIO_NET_F_GUEST_ANNOUNCE, true),
- DEFINE_PROP_BIT("host_tso4", VirtIONet, host_features,
- VIRTIO_NET_F_HOST_TSO4, true),
- DEFINE_PROP_BIT("host_tso6", VirtIONet, host_features,
- VIRTIO_NET_F_HOST_TSO6, true),
- DEFINE_PROP_BIT("host_ecn", VirtIONet, host_features,
- VIRTIO_NET_F_HOST_ECN, true),
- DEFINE_PROP_BIT("host_ufo", VirtIONet, host_features,
- VIRTIO_NET_F_HOST_UFO, true),
- DEFINE_PROP_BIT("mrg_rxbuf", VirtIONet, host_features,
- VIRTIO_NET_F_MRG_RXBUF, true),
- DEFINE_PROP_BIT("status", VirtIONet, host_features,
- VIRTIO_NET_F_STATUS, true),
- DEFINE_PROP_BIT("ctrl_vq", VirtIONet, host_features,
- VIRTIO_NET_F_CTRL_VQ, true),
- DEFINE_PROP_BIT("ctrl_rx", VirtIONet, host_features,
- VIRTIO_NET_F_CTRL_RX, true),
- DEFINE_PROP_BIT("ctrl_vlan", VirtIONet, host_features,
- VIRTIO_NET_F_CTRL_VLAN, true),
- DEFINE_PROP_BIT("ctrl_rx_extra", VirtIONet, host_features,
- VIRTIO_NET_F_CTRL_RX_EXTRA, true),
- DEFINE_PROP_BIT("ctrl_mac_addr", VirtIONet, host_features,
- VIRTIO_NET_F_CTRL_MAC_ADDR, true),
- DEFINE_PROP_BIT("ctrl_guest_offloads", VirtIONet, host_features,
- VIRTIO_NET_F_CTRL_GUEST_OFFLOADS, true),
- DEFINE_PROP_BIT("mq", VirtIONet, host_features, VIRTIO_NET_F_MQ, false),
- DEFINE_NIC_PROPERTIES(VirtIONet, nic_conf),
- DEFINE_PROP_UINT32("x-txtimer", VirtIONet, net_conf.txtimer,
- TX_TIMER_INTERVAL),
- DEFINE_PROP_INT32("x-txburst", VirtIONet, net_conf.txburst, TX_BURST),
- DEFINE_PROP_STRING("tx", VirtIONet, net_conf.tx),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_net_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
-
- dc->props = virtio_net_properties;
- set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
- vdc->realize = virtio_net_device_realize;
- vdc->unrealize = virtio_net_device_unrealize;
- vdc->get_config = virtio_net_get_config;
- vdc->set_config = virtio_net_set_config;
- vdc->get_features = virtio_net_get_features;
- vdc->set_features = virtio_net_set_features;
- vdc->bad_features = virtio_net_bad_features;
- vdc->reset = virtio_net_reset;
- vdc->set_status = virtio_net_set_status;
- vdc->guest_notifier_mask = virtio_net_guest_notifier_mask;
- vdc->guest_notifier_pending = virtio_net_guest_notifier_pending;
- vdc->load = virtio_net_load_device;
- vdc->save = virtio_net_save_device;
-}
-
-static const TypeInfo virtio_net_info = {
- .name = TYPE_VIRTIO_NET,
- .parent = TYPE_VIRTIO_DEVICE,
- .instance_size = sizeof(VirtIONet),
- .instance_init = virtio_net_instance_init,
- .class_init = virtio_net_class_init,
-};
-
-static void virtio_register_types(void)
-{
- type_register_static(&virtio_net_info);
-}
-
-type_init(virtio_register_types)
diff --git a/qemu/hw/net/vmware_utils.h b/qemu/hw/net/vmware_utils.h
deleted file mode 100644
index c0dbb2ff4..000000000
--- a/qemu/hw/net/vmware_utils.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * QEMU VMWARE paravirtual devices - auxiliary code
- *
- * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com)
- *
- * Developed by Daynix Computing LTD (http://www.daynix.com)
- *
- * Authors:
- * Dmitry Fleytman <dmitry@daynix.com>
- * Yan Vugenfirer <yan@daynix.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#ifndef VMWARE_UTILS_H
-#define VMWARE_UTILS_H
-
-#include "qemu/range.h"
-#include "vmxnet_debug.h"
-
-/*
- * Shared memory access functions with byte swap support
- * Each function contains printout for reverse-engineering needs
- *
- */
-static inline void
-vmw_shmem_read(hwaddr addr, void *buf, int len)
-{
- VMW_SHPRN("SHMEM r: %" PRIx64 ", len: %d to %p", addr, len, buf);
- cpu_physical_memory_read(addr, buf, len);
-}
-
-static inline void
-vmw_shmem_write(hwaddr addr, void *buf, int len)
-{
- VMW_SHPRN("SHMEM w: %" PRIx64 ", len: %d to %p", addr, len, buf);
- cpu_physical_memory_write(addr, buf, len);
-}
-
-static inline void
-vmw_shmem_rw(hwaddr addr, void *buf, int len, int is_write)
-{
- VMW_SHPRN("SHMEM r/w: %" PRIx64 ", len: %d (to %p), is write: %d",
- addr, len, buf, is_write);
-
- cpu_physical_memory_rw(addr, buf, len, is_write);
-}
-
-static inline void
-vmw_shmem_set(hwaddr addr, uint8_t val, int len)
-{
- int i;
- VMW_SHPRN("SHMEM set: %" PRIx64 ", len: %d (value 0x%X)", addr, len, val);
-
- for (i = 0; i < len; i++) {
- cpu_physical_memory_write(addr + i, &val, 1);
- }
-}
-
-static inline uint32_t
-vmw_shmem_ld8(hwaddr addr)
-{
- uint8_t res = ldub_phys(&address_space_memory, addr);
- VMW_SHPRN("SHMEM load8: %" PRIx64 " (value 0x%X)", addr, res);
- return res;
-}
-
-static inline void
-vmw_shmem_st8(hwaddr addr, uint8_t value)
-{
- VMW_SHPRN("SHMEM store8: %" PRIx64 " (value 0x%X)", addr, value);
- stb_phys(&address_space_memory, addr, value);
-}
-
-static inline uint32_t
-vmw_shmem_ld16(hwaddr addr)
-{
- uint16_t res = lduw_le_phys(&address_space_memory, addr);
- VMW_SHPRN("SHMEM load16: %" PRIx64 " (value 0x%X)", addr, res);
- return res;
-}
-
-static inline void
-vmw_shmem_st16(hwaddr addr, uint16_t value)
-{
- VMW_SHPRN("SHMEM store16: %" PRIx64 " (value 0x%X)", addr, value);
- stw_le_phys(&address_space_memory, addr, value);
-}
-
-static inline uint32_t
-vmw_shmem_ld32(hwaddr addr)
-{
- uint32_t res = ldl_le_phys(&address_space_memory, addr);
- VMW_SHPRN("SHMEM load32: %" PRIx64 " (value 0x%X)", addr, res);
- return res;
-}
-
-static inline void
-vmw_shmem_st32(hwaddr addr, uint32_t value)
-{
- VMW_SHPRN("SHMEM store32: %" PRIx64 " (value 0x%X)", addr, value);
- stl_le_phys(&address_space_memory, addr, value);
-}
-
-static inline uint64_t
-vmw_shmem_ld64(hwaddr addr)
-{
- uint64_t res = ldq_le_phys(&address_space_memory, addr);
- VMW_SHPRN("SHMEM load64: %" PRIx64 " (value %" PRIx64 ")", addr, res);
- return res;
-}
-
-static inline void
-vmw_shmem_st64(hwaddr addr, uint64_t value)
-{
- VMW_SHPRN("SHMEM store64: %" PRIx64 " (value %" PRIx64 ")", addr, value);
- stq_le_phys(&address_space_memory, addr, value);
-}
-
-/* Macros for simplification of operations on array-style registers */
-
-/*
- * Whether <addr> lies inside of array-style register defined by <base>,
- * number of elements (<cnt>) and element size (<regsize>)
- *
-*/
-#define VMW_IS_MULTIREG_ADDR(addr, base, cnt, regsize) \
- range_covers_byte(base, cnt * regsize, addr)
-
-/*
- * Returns index of given register (<addr>) in array-style register defined by
- * <base> and element size (<regsize>)
- *
-*/
-#define VMW_MULTIREG_IDX_BY_ADDR(addr, base, regsize) \
- (((addr) - (base)) / (regsize))
-
-#endif
diff --git a/qemu/hw/net/vmxnet3.c b/qemu/hw/net/vmxnet3.c
deleted file mode 100644
index 093a71e12..000000000
--- a/qemu/hw/net/vmxnet3.c
+++ /dev/null
@@ -1,2723 +0,0 @@
-/*
- * QEMU VMWARE VMXNET3 paravirtual NIC
- *
- * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com)
- *
- * Developed by Daynix Computing LTD (http://www.daynix.com)
- *
- * Authors:
- * Dmitry Fleytman <dmitry@daynix.com>
- * Tamir Shomer <tamirs@daynix.com>
- * Yan Vugenfirer <yan@daynix.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/pci/pci.h"
-#include "net/net.h"
-#include "net/tap.h"
-#include "net/checksum.h"
-#include "sysemu/sysemu.h"
-#include "qemu-common.h"
-#include "qemu/bswap.h"
-#include "hw/pci/msix.h"
-#include "hw/pci/msi.h"
-
-#include "vmxnet3.h"
-#include "vmxnet_debug.h"
-#include "vmware_utils.h"
-#include "vmxnet_tx_pkt.h"
-#include "vmxnet_rx_pkt.h"
-
-#define PCI_DEVICE_ID_VMWARE_VMXNET3_REVISION 0x1
-#define VMXNET3_MSIX_BAR_SIZE 0x2000
-#define MIN_BUF_SIZE 60
-
-/* Compatability flags for migration */
-#define VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS_BIT 0
-#define VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS \
- (1 << VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS_BIT)
-#define VMXNET3_COMPAT_FLAG_DISABLE_PCIE_BIT 1
-#define VMXNET3_COMPAT_FLAG_DISABLE_PCIE \
- (1 << VMXNET3_COMPAT_FLAG_DISABLE_PCIE_BIT)
-
-#define VMXNET3_EXP_EP_OFFSET (0x48)
-#define VMXNET3_MSI_OFFSET(s) \
- ((s)->compat_flags & VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS ? 0x50 : 0x84)
-#define VMXNET3_MSIX_OFFSET(s) \
- ((s)->compat_flags & VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS ? 0 : 0x9c)
-#define VMXNET3_DSN_OFFSET (0x100)
-
-#define VMXNET3_BAR0_IDX (0)
-#define VMXNET3_BAR1_IDX (1)
-#define VMXNET3_MSIX_BAR_IDX (2)
-
-#define VMXNET3_OFF_MSIX_TABLE (0x000)
-#define VMXNET3_OFF_MSIX_PBA(s) \
- ((s)->compat_flags & VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS ? 0x800 : 0x1000)
-
-/* Link speed in Mbps should be shifted by 16 */
-#define VMXNET3_LINK_SPEED (1000 << 16)
-
-/* Link status: 1 - up, 0 - down. */
-#define VMXNET3_LINK_STATUS_UP 0x1
-
-/* Least significant bit should be set for revision and version */
-#define VMXNET3_UPT_REVISION 0x1
-#define VMXNET3_DEVICE_REVISION 0x1
-
-/* Number of interrupt vectors for non-MSIx modes */
-#define VMXNET3_MAX_NMSIX_INTRS (1)
-
-/* Macros for rings descriptors access */
-#define VMXNET3_READ_TX_QUEUE_DESCR8(dpa, field) \
- (vmw_shmem_ld8(dpa + offsetof(struct Vmxnet3_TxQueueDesc, field)))
-
-#define VMXNET3_WRITE_TX_QUEUE_DESCR8(dpa, field, value) \
- (vmw_shmem_st8(dpa + offsetof(struct Vmxnet3_TxQueueDesc, field, value)))
-
-#define VMXNET3_READ_TX_QUEUE_DESCR32(dpa, field) \
- (vmw_shmem_ld32(dpa + offsetof(struct Vmxnet3_TxQueueDesc, field)))
-
-#define VMXNET3_WRITE_TX_QUEUE_DESCR32(dpa, field, value) \
- (vmw_shmem_st32(dpa + offsetof(struct Vmxnet3_TxQueueDesc, field), value))
-
-#define VMXNET3_READ_TX_QUEUE_DESCR64(dpa, field) \
- (vmw_shmem_ld64(dpa + offsetof(struct Vmxnet3_TxQueueDesc, field)))
-
-#define VMXNET3_WRITE_TX_QUEUE_DESCR64(dpa, field, value) \
- (vmw_shmem_st64(dpa + offsetof(struct Vmxnet3_TxQueueDesc, field), value))
-
-#define VMXNET3_READ_RX_QUEUE_DESCR64(dpa, field) \
- (vmw_shmem_ld64(dpa + offsetof(struct Vmxnet3_RxQueueDesc, field)))
-
-#define VMXNET3_READ_RX_QUEUE_DESCR32(dpa, field) \
- (vmw_shmem_ld32(dpa + offsetof(struct Vmxnet3_RxQueueDesc, field)))
-
-#define VMXNET3_WRITE_RX_QUEUE_DESCR64(dpa, field, value) \
- (vmw_shmem_st64(dpa + offsetof(struct Vmxnet3_RxQueueDesc, field), value))
-
-#define VMXNET3_WRITE_RX_QUEUE_DESCR8(dpa, field, value) \
- (vmw_shmem_st8(dpa + offsetof(struct Vmxnet3_RxQueueDesc, field), value))
-
-/* Macros for guest driver shared area access */
-#define VMXNET3_READ_DRV_SHARED64(shpa, field) \
- (vmw_shmem_ld64(shpa + offsetof(struct Vmxnet3_DriverShared, field)))
-
-#define VMXNET3_READ_DRV_SHARED32(shpa, field) \
- (vmw_shmem_ld32(shpa + offsetof(struct Vmxnet3_DriverShared, field)))
-
-#define VMXNET3_WRITE_DRV_SHARED32(shpa, field, val) \
- (vmw_shmem_st32(shpa + offsetof(struct Vmxnet3_DriverShared, field), val))
-
-#define VMXNET3_READ_DRV_SHARED16(shpa, field) \
- (vmw_shmem_ld16(shpa + offsetof(struct Vmxnet3_DriverShared, field)))
-
-#define VMXNET3_READ_DRV_SHARED8(shpa, field) \
- (vmw_shmem_ld8(shpa + offsetof(struct Vmxnet3_DriverShared, field)))
-
-#define VMXNET3_READ_DRV_SHARED(shpa, field, b, l) \
- (vmw_shmem_read(shpa + offsetof(struct Vmxnet3_DriverShared, field), b, l))
-
-#define VMXNET_FLAG_IS_SET(field, flag) (((field) & (flag)) == (flag))
-
-typedef struct VMXNET3Class {
- PCIDeviceClass parent_class;
- DeviceRealize parent_dc_realize;
-} VMXNET3Class;
-
-#define TYPE_VMXNET3 "vmxnet3"
-#define VMXNET3(obj) OBJECT_CHECK(VMXNET3State, (obj), TYPE_VMXNET3)
-
-#define VMXNET3_DEVICE_CLASS(klass) \
- OBJECT_CLASS_CHECK(VMXNET3Class, (klass), TYPE_VMXNET3)
-#define VMXNET3_DEVICE_GET_CLASS(obj) \
- OBJECT_GET_CLASS(VMXNET3Class, (obj), TYPE_VMXNET3)
-
-/* Cyclic ring abstraction */
-typedef struct {
- hwaddr pa;
- size_t size;
- size_t cell_size;
- size_t next;
- uint8_t gen;
-} Vmxnet3Ring;
-
-static inline void vmxnet3_ring_init(Vmxnet3Ring *ring,
- hwaddr pa,
- size_t size,
- size_t cell_size,
- bool zero_region)
-{
- ring->pa = pa;
- ring->size = size;
- ring->cell_size = cell_size;
- ring->gen = VMXNET3_INIT_GEN;
- ring->next = 0;
-
- if (zero_region) {
- vmw_shmem_set(pa, 0, size * cell_size);
- }
-}
-
-#define VMXNET3_RING_DUMP(macro, ring_name, ridx, r) \
- macro("%s#%d: base %" PRIx64 " size %zu cell_size %zu gen %d next %zu", \
- (ring_name), (ridx), \
- (r)->pa, (r)->size, (r)->cell_size, (r)->gen, (r)->next)
-
-static inline void vmxnet3_ring_inc(Vmxnet3Ring *ring)
-{
- if (++ring->next >= ring->size) {
- ring->next = 0;
- ring->gen ^= 1;
- }
-}
-
-static inline void vmxnet3_ring_dec(Vmxnet3Ring *ring)
-{
- if (ring->next-- == 0) {
- ring->next = ring->size - 1;
- ring->gen ^= 1;
- }
-}
-
-static inline hwaddr vmxnet3_ring_curr_cell_pa(Vmxnet3Ring *ring)
-{
- return ring->pa + ring->next * ring->cell_size;
-}
-
-static inline void vmxnet3_ring_read_curr_cell(Vmxnet3Ring *ring, void *buff)
-{
- vmw_shmem_read(vmxnet3_ring_curr_cell_pa(ring), buff, ring->cell_size);
-}
-
-static inline void vmxnet3_ring_write_curr_cell(Vmxnet3Ring *ring, void *buff)
-{
- vmw_shmem_write(vmxnet3_ring_curr_cell_pa(ring), buff, ring->cell_size);
-}
-
-static inline size_t vmxnet3_ring_curr_cell_idx(Vmxnet3Ring *ring)
-{
- return ring->next;
-}
-
-static inline uint8_t vmxnet3_ring_curr_gen(Vmxnet3Ring *ring)
-{
- return ring->gen;
-}
-
-/* Debug trace-related functions */
-static inline void
-vmxnet3_dump_tx_descr(struct Vmxnet3_TxDesc *descr)
-{
- VMW_PKPRN("TX DESCR: "
- "addr %" PRIx64 ", len: %d, gen: %d, rsvd: %d, "
- "dtype: %d, ext1: %d, msscof: %d, hlen: %d, om: %d, "
- "eop: %d, cq: %d, ext2: %d, ti: %d, tci: %d",
- le64_to_cpu(descr->addr), descr->len, descr->gen, descr->rsvd,
- descr->dtype, descr->ext1, descr->msscof, descr->hlen, descr->om,
- descr->eop, descr->cq, descr->ext2, descr->ti, descr->tci);
-}
-
-static inline void
-vmxnet3_dump_virt_hdr(struct virtio_net_hdr *vhdr)
-{
- VMW_PKPRN("VHDR: flags 0x%x, gso_type: 0x%x, hdr_len: %d, gso_size: %d, "
- "csum_start: %d, csum_offset: %d",
- vhdr->flags, vhdr->gso_type, vhdr->hdr_len, vhdr->gso_size,
- vhdr->csum_start, vhdr->csum_offset);
-}
-
-static inline void
-vmxnet3_dump_rx_descr(struct Vmxnet3_RxDesc *descr)
-{
- VMW_PKPRN("RX DESCR: addr %" PRIx64 ", len: %d, gen: %d, rsvd: %d, "
- "dtype: %d, ext1: %d, btype: %d",
- le64_to_cpu(descr->addr), descr->len, descr->gen,
- descr->rsvd, descr->dtype, descr->ext1, descr->btype);
-}
-
-/* Device state and helper functions */
-#define VMXNET3_RX_RINGS_PER_QUEUE (2)
-
-typedef struct {
- Vmxnet3Ring tx_ring;
- Vmxnet3Ring comp_ring;
-
- uint8_t intr_idx;
- hwaddr tx_stats_pa;
- struct UPT1_TxStats txq_stats;
-} Vmxnet3TxqDescr;
-
-typedef struct {
- Vmxnet3Ring rx_ring[VMXNET3_RX_RINGS_PER_QUEUE];
- Vmxnet3Ring comp_ring;
- uint8_t intr_idx;
- hwaddr rx_stats_pa;
- struct UPT1_RxStats rxq_stats;
-} Vmxnet3RxqDescr;
-
-typedef struct {
- bool is_masked;
- bool is_pending;
- bool is_asserted;
-} Vmxnet3IntState;
-
-typedef struct {
- PCIDevice parent_obj;
- NICState *nic;
- NICConf conf;
- MemoryRegion bar0;
- MemoryRegion bar1;
- MemoryRegion msix_bar;
-
- Vmxnet3RxqDescr rxq_descr[VMXNET3_DEVICE_MAX_RX_QUEUES];
- Vmxnet3TxqDescr txq_descr[VMXNET3_DEVICE_MAX_TX_QUEUES];
-
- /* Whether MSI-X support was installed successfully */
- bool msix_used;
- /* Whether MSI support was installed successfully */
- bool msi_used;
- hwaddr drv_shmem;
- hwaddr temp_shared_guest_driver_memory;
-
- uint8_t txq_num;
-
- /* This boolean tells whether RX packet being indicated has to */
- /* be split into head and body chunks from different RX rings */
- bool rx_packets_compound;
-
- bool rx_vlan_stripping;
- bool lro_supported;
-
- uint8_t rxq_num;
-
- /* Network MTU */
- uint32_t mtu;
-
- /* Maximum number of fragments for indicated TX packets */
- uint32_t max_tx_frags;
-
- /* Maximum number of fragments for indicated RX packets */
- uint16_t max_rx_frags;
-
- /* Index for events interrupt */
- uint8_t event_int_idx;
-
- /* Whether automatic interrupts masking enabled */
- bool auto_int_masking;
-
- bool peer_has_vhdr;
-
- /* TX packets to QEMU interface */
- struct VmxnetTxPkt *tx_pkt;
- uint32_t offload_mode;
- uint32_t cso_or_gso_size;
- uint16_t tci;
- bool needs_vlan;
-
- struct VmxnetRxPkt *rx_pkt;
-
- bool tx_sop;
- bool skip_current_tx_pkt;
-
- uint32_t device_active;
- uint32_t last_command;
-
- uint32_t link_status_and_speed;
-
- Vmxnet3IntState interrupt_states[VMXNET3_MAX_INTRS];
-
- uint32_t temp_mac; /* To store the low part first */
-
- MACAddr perm_mac;
- uint32_t vlan_table[VMXNET3_VFT_SIZE];
- uint32_t rx_mode;
- MACAddr *mcast_list;
- uint32_t mcast_list_len;
- uint32_t mcast_list_buff_size; /* needed for live migration. */
-
- /* Compatability flags for migration */
- uint32_t compat_flags;
-} VMXNET3State;
-
-/* Interrupt management */
-
-/*
- *This function returns sign whether interrupt line is in asserted state
- * This depends on the type of interrupt used. For INTX interrupt line will
- * be asserted until explicit deassertion, for MSI(X) interrupt line will
- * be deasserted automatically due to notification semantics of the MSI(X)
- * interrupts
- */
-static bool _vmxnet3_assert_interrupt_line(VMXNET3State *s, uint32_t int_idx)
-{
- PCIDevice *d = PCI_DEVICE(s);
-
- if (s->msix_used && msix_enabled(d)) {
- VMW_IRPRN("Sending MSI-X notification for vector %u", int_idx);
- msix_notify(d, int_idx);
- return false;
- }
- if (s->msi_used && msi_enabled(d)) {
- VMW_IRPRN("Sending MSI notification for vector %u", int_idx);
- msi_notify(d, int_idx);
- return false;
- }
-
- VMW_IRPRN("Asserting line for interrupt %u", int_idx);
- pci_irq_assert(d);
- return true;
-}
-
-static void _vmxnet3_deassert_interrupt_line(VMXNET3State *s, int lidx)
-{
- PCIDevice *d = PCI_DEVICE(s);
-
- /*
- * This function should never be called for MSI(X) interrupts
- * because deassertion never required for message interrupts
- */
- assert(!s->msix_used || !msix_enabled(d));
- /*
- * This function should never be called for MSI(X) interrupts
- * because deassertion never required for message interrupts
- */
- assert(!s->msi_used || !msi_enabled(d));
-
- VMW_IRPRN("Deasserting line for interrupt %u", lidx);
- pci_irq_deassert(d);
-}
-
-static void vmxnet3_update_interrupt_line_state(VMXNET3State *s, int lidx)
-{
- if (!s->interrupt_states[lidx].is_pending &&
- s->interrupt_states[lidx].is_asserted) {
- VMW_IRPRN("New interrupt line state for index %d is DOWN", lidx);
- _vmxnet3_deassert_interrupt_line(s, lidx);
- s->interrupt_states[lidx].is_asserted = false;
- return;
- }
-
- if (s->interrupt_states[lidx].is_pending &&
- !s->interrupt_states[lidx].is_masked &&
- !s->interrupt_states[lidx].is_asserted) {
- VMW_IRPRN("New interrupt line state for index %d is UP", lidx);
- s->interrupt_states[lidx].is_asserted =
- _vmxnet3_assert_interrupt_line(s, lidx);
- s->interrupt_states[lidx].is_pending = false;
- return;
- }
-}
-
-static void vmxnet3_trigger_interrupt(VMXNET3State *s, int lidx)
-{
- PCIDevice *d = PCI_DEVICE(s);
- s->interrupt_states[lidx].is_pending = true;
- vmxnet3_update_interrupt_line_state(s, lidx);
-
- if (s->msix_used && msix_enabled(d) && s->auto_int_masking) {
- goto do_automask;
- }
-
- if (s->msi_used && msi_enabled(d) && s->auto_int_masking) {
- goto do_automask;
- }
-
- return;
-
-do_automask:
- s->interrupt_states[lidx].is_masked = true;
- vmxnet3_update_interrupt_line_state(s, lidx);
-}
-
-static bool vmxnet3_interrupt_asserted(VMXNET3State *s, int lidx)
-{
- return s->interrupt_states[lidx].is_asserted;
-}
-
-static void vmxnet3_clear_interrupt(VMXNET3State *s, int int_idx)
-{
- s->interrupt_states[int_idx].is_pending = false;
- if (s->auto_int_masking) {
- s->interrupt_states[int_idx].is_masked = true;
- }
- vmxnet3_update_interrupt_line_state(s, int_idx);
-}
-
-static void
-vmxnet3_on_interrupt_mask_changed(VMXNET3State *s, int lidx, bool is_masked)
-{
- s->interrupt_states[lidx].is_masked = is_masked;
- vmxnet3_update_interrupt_line_state(s, lidx);
-}
-
-static bool vmxnet3_verify_driver_magic(hwaddr dshmem)
-{
- return (VMXNET3_READ_DRV_SHARED32(dshmem, magic) == VMXNET3_REV1_MAGIC);
-}
-
-#define VMXNET3_GET_BYTE(x, byte_num) (((x) >> (byte_num)*8) & 0xFF)
-#define VMXNET3_MAKE_BYTE(byte_num, val) \
- (((uint32_t)((val) & 0xFF)) << (byte_num)*8)
-
-static void vmxnet3_set_variable_mac(VMXNET3State *s, uint32_t h, uint32_t l)
-{
- s->conf.macaddr.a[0] = VMXNET3_GET_BYTE(l, 0);
- s->conf.macaddr.a[1] = VMXNET3_GET_BYTE(l, 1);
- s->conf.macaddr.a[2] = VMXNET3_GET_BYTE(l, 2);
- s->conf.macaddr.a[3] = VMXNET3_GET_BYTE(l, 3);
- s->conf.macaddr.a[4] = VMXNET3_GET_BYTE(h, 0);
- s->conf.macaddr.a[5] = VMXNET3_GET_BYTE(h, 1);
-
- VMW_CFPRN("Variable MAC: " VMXNET_MF, VMXNET_MA(s->conf.macaddr.a));
-
- qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-}
-
-static uint64_t vmxnet3_get_mac_low(MACAddr *addr)
-{
- return VMXNET3_MAKE_BYTE(0, addr->a[0]) |
- VMXNET3_MAKE_BYTE(1, addr->a[1]) |
- VMXNET3_MAKE_BYTE(2, addr->a[2]) |
- VMXNET3_MAKE_BYTE(3, addr->a[3]);
-}
-
-static uint64_t vmxnet3_get_mac_high(MACAddr *addr)
-{
- return VMXNET3_MAKE_BYTE(0, addr->a[4]) |
- VMXNET3_MAKE_BYTE(1, addr->a[5]);
-}
-
-static void
-vmxnet3_inc_tx_consumption_counter(VMXNET3State *s, int qidx)
-{
- vmxnet3_ring_inc(&s->txq_descr[qidx].tx_ring);
-}
-
-static inline void
-vmxnet3_inc_rx_consumption_counter(VMXNET3State *s, int qidx, int ridx)
-{
- vmxnet3_ring_inc(&s->rxq_descr[qidx].rx_ring[ridx]);
-}
-
-static inline void
-vmxnet3_inc_tx_completion_counter(VMXNET3State *s, int qidx)
-{
- vmxnet3_ring_inc(&s->txq_descr[qidx].comp_ring);
-}
-
-static void
-vmxnet3_inc_rx_completion_counter(VMXNET3State *s, int qidx)
-{
- vmxnet3_ring_inc(&s->rxq_descr[qidx].comp_ring);
-}
-
-static void
-vmxnet3_dec_rx_completion_counter(VMXNET3State *s, int qidx)
-{
- vmxnet3_ring_dec(&s->rxq_descr[qidx].comp_ring);
-}
-
-static void vmxnet3_complete_packet(VMXNET3State *s, int qidx, uint32_t tx_ridx)
-{
- struct Vmxnet3_TxCompDesc txcq_descr;
-
- VMXNET3_RING_DUMP(VMW_RIPRN, "TXC", qidx, &s->txq_descr[qidx].comp_ring);
-
- txcq_descr.txdIdx = tx_ridx;
- txcq_descr.gen = vmxnet3_ring_curr_gen(&s->txq_descr[qidx].comp_ring);
-
- vmxnet3_ring_write_curr_cell(&s->txq_descr[qidx].comp_ring, &txcq_descr);
-
- /* Flush changes in TX descriptor before changing the counter value */
- smp_wmb();
-
- vmxnet3_inc_tx_completion_counter(s, qidx);
- vmxnet3_trigger_interrupt(s, s->txq_descr[qidx].intr_idx);
-}
-
-static bool
-vmxnet3_setup_tx_offloads(VMXNET3State *s)
-{
- switch (s->offload_mode) {
- case VMXNET3_OM_NONE:
- vmxnet_tx_pkt_build_vheader(s->tx_pkt, false, false, 0);
- break;
-
- case VMXNET3_OM_CSUM:
- vmxnet_tx_pkt_build_vheader(s->tx_pkt, false, true, 0);
- VMW_PKPRN("L4 CSO requested\n");
- break;
-
- case VMXNET3_OM_TSO:
- vmxnet_tx_pkt_build_vheader(s->tx_pkt, true, true,
- s->cso_or_gso_size);
- vmxnet_tx_pkt_update_ip_checksums(s->tx_pkt);
- VMW_PKPRN("GSO offload requested.");
- break;
-
- default:
- g_assert_not_reached();
- return false;
- }
-
- return true;
-}
-
-static void
-vmxnet3_tx_retrieve_metadata(VMXNET3State *s,
- const struct Vmxnet3_TxDesc *txd)
-{
- s->offload_mode = txd->om;
- s->cso_or_gso_size = txd->msscof;
- s->tci = txd->tci;
- s->needs_vlan = txd->ti;
-}
-
-typedef enum {
- VMXNET3_PKT_STATUS_OK,
- VMXNET3_PKT_STATUS_ERROR,
- VMXNET3_PKT_STATUS_DISCARD,/* only for tx */
- VMXNET3_PKT_STATUS_OUT_OF_BUF /* only for rx */
-} Vmxnet3PktStatus;
-
-static void
-vmxnet3_on_tx_done_update_stats(VMXNET3State *s, int qidx,
- Vmxnet3PktStatus status)
-{
- size_t tot_len = vmxnet_tx_pkt_get_total_len(s->tx_pkt);
- struct UPT1_TxStats *stats = &s->txq_descr[qidx].txq_stats;
-
- switch (status) {
- case VMXNET3_PKT_STATUS_OK:
- switch (vmxnet_tx_pkt_get_packet_type(s->tx_pkt)) {
- case ETH_PKT_BCAST:
- stats->bcastPktsTxOK++;
- stats->bcastBytesTxOK += tot_len;
- break;
- case ETH_PKT_MCAST:
- stats->mcastPktsTxOK++;
- stats->mcastBytesTxOK += tot_len;
- break;
- case ETH_PKT_UCAST:
- stats->ucastPktsTxOK++;
- stats->ucastBytesTxOK += tot_len;
- break;
- default:
- g_assert_not_reached();
- }
-
- if (s->offload_mode == VMXNET3_OM_TSO) {
- /*
- * According to VMWARE headers this statistic is a number
- * of packets after segmentation but since we don't have
- * this information in QEMU model, the best we can do is to
- * provide number of non-segmented packets
- */
- stats->TSOPktsTxOK++;
- stats->TSOBytesTxOK += tot_len;
- }
- break;
-
- case VMXNET3_PKT_STATUS_DISCARD:
- stats->pktsTxDiscard++;
- break;
-
- case VMXNET3_PKT_STATUS_ERROR:
- stats->pktsTxError++;
- break;
-
- default:
- g_assert_not_reached();
- }
-}
-
-static void
-vmxnet3_on_rx_done_update_stats(VMXNET3State *s,
- int qidx,
- Vmxnet3PktStatus status)
-{
- struct UPT1_RxStats *stats = &s->rxq_descr[qidx].rxq_stats;
- size_t tot_len = vmxnet_rx_pkt_get_total_len(s->rx_pkt);
-
- switch (status) {
- case VMXNET3_PKT_STATUS_OUT_OF_BUF:
- stats->pktsRxOutOfBuf++;
- break;
-
- case VMXNET3_PKT_STATUS_ERROR:
- stats->pktsRxError++;
- break;
- case VMXNET3_PKT_STATUS_OK:
- switch (vmxnet_rx_pkt_get_packet_type(s->rx_pkt)) {
- case ETH_PKT_BCAST:
- stats->bcastPktsRxOK++;
- stats->bcastBytesRxOK += tot_len;
- break;
- case ETH_PKT_MCAST:
- stats->mcastPktsRxOK++;
- stats->mcastBytesRxOK += tot_len;
- break;
- case ETH_PKT_UCAST:
- stats->ucastPktsRxOK++;
- stats->ucastBytesRxOK += tot_len;
- break;
- default:
- g_assert_not_reached();
- }
-
- if (tot_len > s->mtu) {
- stats->LROPktsRxOK++;
- stats->LROBytesRxOK += tot_len;
- }
- break;
- default:
- g_assert_not_reached();
- }
-}
-
-static inline bool
-vmxnet3_pop_next_tx_descr(VMXNET3State *s,
- int qidx,
- struct Vmxnet3_TxDesc *txd,
- uint32_t *descr_idx)
-{
- Vmxnet3Ring *ring = &s->txq_descr[qidx].tx_ring;
-
- vmxnet3_ring_read_curr_cell(ring, txd);
- if (txd->gen == vmxnet3_ring_curr_gen(ring)) {
- /* Only read after generation field verification */
- smp_rmb();
- /* Re-read to be sure we got the latest version */
- vmxnet3_ring_read_curr_cell(ring, txd);
- VMXNET3_RING_DUMP(VMW_RIPRN, "TX", qidx, ring);
- *descr_idx = vmxnet3_ring_curr_cell_idx(ring);
- vmxnet3_inc_tx_consumption_counter(s, qidx);
- return true;
- }
-
- return false;
-}
-
-static bool
-vmxnet3_send_packet(VMXNET3State *s, uint32_t qidx)
-{
- Vmxnet3PktStatus status = VMXNET3_PKT_STATUS_OK;
-
- if (!vmxnet3_setup_tx_offloads(s)) {
- status = VMXNET3_PKT_STATUS_ERROR;
- goto func_exit;
- }
-
- /* debug prints */
- vmxnet3_dump_virt_hdr(vmxnet_tx_pkt_get_vhdr(s->tx_pkt));
- vmxnet_tx_pkt_dump(s->tx_pkt);
-
- if (!vmxnet_tx_pkt_send(s->tx_pkt, qemu_get_queue(s->nic))) {
- status = VMXNET3_PKT_STATUS_DISCARD;
- goto func_exit;
- }
-
-func_exit:
- vmxnet3_on_tx_done_update_stats(s, qidx, status);
- return (status == VMXNET3_PKT_STATUS_OK);
-}
-
-static void vmxnet3_process_tx_queue(VMXNET3State *s, int qidx)
-{
- struct Vmxnet3_TxDesc txd;
- uint32_t txd_idx;
- uint32_t data_len;
- hwaddr data_pa;
-
- for (;;) {
- if (!vmxnet3_pop_next_tx_descr(s, qidx, &txd, &txd_idx)) {
- break;
- }
-
- vmxnet3_dump_tx_descr(&txd);
-
- if (!s->skip_current_tx_pkt) {
- data_len = (txd.len > 0) ? txd.len : VMXNET3_MAX_TX_BUF_SIZE;
- data_pa = le64_to_cpu(txd.addr);
-
- if (!vmxnet_tx_pkt_add_raw_fragment(s->tx_pkt,
- data_pa,
- data_len)) {
- s->skip_current_tx_pkt = true;
- }
- }
-
- if (s->tx_sop) {
- vmxnet3_tx_retrieve_metadata(s, &txd);
- s->tx_sop = false;
- }
-
- if (txd.eop) {
- if (!s->skip_current_tx_pkt && vmxnet_tx_pkt_parse(s->tx_pkt)) {
- if (s->needs_vlan) {
- vmxnet_tx_pkt_setup_vlan_header(s->tx_pkt, s->tci);
- }
-
- vmxnet3_send_packet(s, qidx);
- } else {
- vmxnet3_on_tx_done_update_stats(s, qidx,
- VMXNET3_PKT_STATUS_ERROR);
- }
-
- vmxnet3_complete_packet(s, qidx, txd_idx);
- s->tx_sop = true;
- s->skip_current_tx_pkt = false;
- vmxnet_tx_pkt_reset(s->tx_pkt);
- }
- }
-}
-
-static inline void
-vmxnet3_read_next_rx_descr(VMXNET3State *s, int qidx, int ridx,
- struct Vmxnet3_RxDesc *dbuf, uint32_t *didx)
-{
- Vmxnet3Ring *ring = &s->rxq_descr[qidx].rx_ring[ridx];
- *didx = vmxnet3_ring_curr_cell_idx(ring);
- vmxnet3_ring_read_curr_cell(ring, dbuf);
-}
-
-static inline uint8_t
-vmxnet3_get_rx_ring_gen(VMXNET3State *s, int qidx, int ridx)
-{
- return s->rxq_descr[qidx].rx_ring[ridx].gen;
-}
-
-static inline hwaddr
-vmxnet3_pop_rxc_descr(VMXNET3State *s, int qidx, uint32_t *descr_gen)
-{
- uint8_t ring_gen;
- struct Vmxnet3_RxCompDesc rxcd;
-
- hwaddr daddr =
- vmxnet3_ring_curr_cell_pa(&s->rxq_descr[qidx].comp_ring);
-
- cpu_physical_memory_read(daddr, &rxcd, sizeof(struct Vmxnet3_RxCompDesc));
- ring_gen = vmxnet3_ring_curr_gen(&s->rxq_descr[qidx].comp_ring);
-
- if (rxcd.gen != ring_gen) {
- *descr_gen = ring_gen;
- vmxnet3_inc_rx_completion_counter(s, qidx);
- return daddr;
- }
-
- return 0;
-}
-
-static inline void
-vmxnet3_revert_rxc_descr(VMXNET3State *s, int qidx)
-{
- vmxnet3_dec_rx_completion_counter(s, qidx);
-}
-
-#define RXQ_IDX (0)
-#define RX_HEAD_BODY_RING (0)
-#define RX_BODY_ONLY_RING (1)
-
-static bool
-vmxnet3_get_next_head_rx_descr(VMXNET3State *s,
- struct Vmxnet3_RxDesc *descr_buf,
- uint32_t *descr_idx,
- uint32_t *ridx)
-{
- for (;;) {
- uint32_t ring_gen;
- vmxnet3_read_next_rx_descr(s, RXQ_IDX, RX_HEAD_BODY_RING,
- descr_buf, descr_idx);
-
- /* If no more free descriptors - return */
- ring_gen = vmxnet3_get_rx_ring_gen(s, RXQ_IDX, RX_HEAD_BODY_RING);
- if (descr_buf->gen != ring_gen) {
- return false;
- }
-
- /* Only read after generation field verification */
- smp_rmb();
- /* Re-read to be sure we got the latest version */
- vmxnet3_read_next_rx_descr(s, RXQ_IDX, RX_HEAD_BODY_RING,
- descr_buf, descr_idx);
-
- /* Mark current descriptor as used/skipped */
- vmxnet3_inc_rx_consumption_counter(s, RXQ_IDX, RX_HEAD_BODY_RING);
-
- /* If this is what we are looking for - return */
- if (descr_buf->btype == VMXNET3_RXD_BTYPE_HEAD) {
- *ridx = RX_HEAD_BODY_RING;
- return true;
- }
- }
-}
-
-static bool
-vmxnet3_get_next_body_rx_descr(VMXNET3State *s,
- struct Vmxnet3_RxDesc *d,
- uint32_t *didx,
- uint32_t *ridx)
-{
- vmxnet3_read_next_rx_descr(s, RXQ_IDX, RX_HEAD_BODY_RING, d, didx);
-
- /* Try to find corresponding descriptor in head/body ring */
- if (d->gen == vmxnet3_get_rx_ring_gen(s, RXQ_IDX, RX_HEAD_BODY_RING)) {
- /* Only read after generation field verification */
- smp_rmb();
- /* Re-read to be sure we got the latest version */
- vmxnet3_read_next_rx_descr(s, RXQ_IDX, RX_HEAD_BODY_RING, d, didx);
- if (d->btype == VMXNET3_RXD_BTYPE_BODY) {
- vmxnet3_inc_rx_consumption_counter(s, RXQ_IDX, RX_HEAD_BODY_RING);
- *ridx = RX_HEAD_BODY_RING;
- return true;
- }
- }
-
- /*
- * If there is no free descriptors on head/body ring or next free
- * descriptor is a head descriptor switch to body only ring
- */
- vmxnet3_read_next_rx_descr(s, RXQ_IDX, RX_BODY_ONLY_RING, d, didx);
-
- /* If no more free descriptors - return */
- if (d->gen == vmxnet3_get_rx_ring_gen(s, RXQ_IDX, RX_BODY_ONLY_RING)) {
- /* Only read after generation field verification */
- smp_rmb();
- /* Re-read to be sure we got the latest version */
- vmxnet3_read_next_rx_descr(s, RXQ_IDX, RX_BODY_ONLY_RING, d, didx);
- assert(d->btype == VMXNET3_RXD_BTYPE_BODY);
- *ridx = RX_BODY_ONLY_RING;
- vmxnet3_inc_rx_consumption_counter(s, RXQ_IDX, RX_BODY_ONLY_RING);
- return true;
- }
-
- return false;
-}
-
-static inline bool
-vmxnet3_get_next_rx_descr(VMXNET3State *s, bool is_head,
- struct Vmxnet3_RxDesc *descr_buf,
- uint32_t *descr_idx,
- uint32_t *ridx)
-{
- if (is_head || !s->rx_packets_compound) {
- return vmxnet3_get_next_head_rx_descr(s, descr_buf, descr_idx, ridx);
- } else {
- return vmxnet3_get_next_body_rx_descr(s, descr_buf, descr_idx, ridx);
- }
-}
-
-/* In case packet was csum offloaded (either NEEDS_CSUM or DATA_VALID),
- * the implementation always passes an RxCompDesc with a "Checksum
- * calculated and found correct" to the OS (cnc=0 and tuc=1, see
- * vmxnet3_rx_update_descr). This emulates the observed ESXi behavior.
- *
- * Therefore, if packet has the NEEDS_CSUM set, we must calculate
- * and place a fully computed checksum into the tcp/udp header.
- * Otherwise, the OS driver will receive a checksum-correct indication
- * (CHECKSUM_UNNECESSARY), but with the actual tcp/udp checksum field
- * having just the pseudo header csum value.
- *
- * While this is not a problem if packet is destined for local delivery,
- * in the case the host OS performs forwarding, it will forward an
- * incorrectly checksummed packet.
- */
-static void vmxnet3_rx_need_csum_calculate(struct VmxnetRxPkt *pkt,
- const void *pkt_data,
- size_t pkt_len)
-{
- struct virtio_net_hdr *vhdr;
- bool isip4, isip6, istcp, isudp;
- uint8_t *data;
- int len;
-
- if (!vmxnet_rx_pkt_has_virt_hdr(pkt)) {
- return;
- }
-
- vhdr = vmxnet_rx_pkt_get_vhdr(pkt);
- if (!VMXNET_FLAG_IS_SET(vhdr->flags, VIRTIO_NET_HDR_F_NEEDS_CSUM)) {
- return;
- }
-
- vmxnet_rx_pkt_get_protocols(pkt, &isip4, &isip6, &isudp, &istcp);
- if (!(isip4 || isip6) || !(istcp || isudp)) {
- return;
- }
-
- vmxnet3_dump_virt_hdr(vhdr);
-
- /* Validate packet len: csum_start + scum_offset + length of csum field */
- if (pkt_len < (vhdr->csum_start + vhdr->csum_offset + 2)) {
- VMW_PKPRN("packet len:%zu < csum_start(%d) + csum_offset(%d) + 2, "
- "cannot calculate checksum",
- pkt_len, vhdr->csum_start, vhdr->csum_offset);
- return;
- }
-
- data = (uint8_t *)pkt_data + vhdr->csum_start;
- len = pkt_len - vhdr->csum_start;
- /* Put the checksum obtained into the packet */
- stw_be_p(data + vhdr->csum_offset, net_raw_checksum(data, len));
-
- vhdr->flags &= ~VIRTIO_NET_HDR_F_NEEDS_CSUM;
- vhdr->flags |= VIRTIO_NET_HDR_F_DATA_VALID;
-}
-
-static void vmxnet3_rx_update_descr(struct VmxnetRxPkt *pkt,
- struct Vmxnet3_RxCompDesc *rxcd)
-{
- int csum_ok, is_gso;
- bool isip4, isip6, istcp, isudp;
- struct virtio_net_hdr *vhdr;
- uint8_t offload_type;
-
- if (vmxnet_rx_pkt_is_vlan_stripped(pkt)) {
- rxcd->ts = 1;
- rxcd->tci = vmxnet_rx_pkt_get_vlan_tag(pkt);
- }
-
- if (!vmxnet_rx_pkt_has_virt_hdr(pkt)) {
- goto nocsum;
- }
-
- vhdr = vmxnet_rx_pkt_get_vhdr(pkt);
- /*
- * Checksum is valid when lower level tell so or when lower level
- * requires checksum offload telling that packet produced/bridged
- * locally and did travel over network after last checksum calculation
- * or production
- */
- csum_ok = VMXNET_FLAG_IS_SET(vhdr->flags, VIRTIO_NET_HDR_F_DATA_VALID) ||
- VMXNET_FLAG_IS_SET(vhdr->flags, VIRTIO_NET_HDR_F_NEEDS_CSUM);
-
- offload_type = vhdr->gso_type & ~VIRTIO_NET_HDR_GSO_ECN;
- is_gso = (offload_type != VIRTIO_NET_HDR_GSO_NONE) ? 1 : 0;
-
- if (!csum_ok && !is_gso) {
- goto nocsum;
- }
-
- vmxnet_rx_pkt_get_protocols(pkt, &isip4, &isip6, &isudp, &istcp);
- if ((!istcp && !isudp) || (!isip4 && !isip6)) {
- goto nocsum;
- }
-
- rxcd->cnc = 0;
- rxcd->v4 = isip4 ? 1 : 0;
- rxcd->v6 = isip6 ? 1 : 0;
- rxcd->tcp = istcp ? 1 : 0;
- rxcd->udp = isudp ? 1 : 0;
- rxcd->fcs = rxcd->tuc = rxcd->ipc = 1;
- return;
-
-nocsum:
- rxcd->cnc = 1;
- return;
-}
-
-static void
-vmxnet3_physical_memory_writev(const struct iovec *iov,
- size_t start_iov_off,
- hwaddr target_addr,
- size_t bytes_to_copy)
-{
- size_t curr_off = 0;
- size_t copied = 0;
-
- while (bytes_to_copy) {
- if (start_iov_off < (curr_off + iov->iov_len)) {
- size_t chunk_len =
- MIN((curr_off + iov->iov_len) - start_iov_off, bytes_to_copy);
-
- cpu_physical_memory_write(target_addr + copied,
- iov->iov_base + start_iov_off - curr_off,
- chunk_len);
-
- copied += chunk_len;
- start_iov_off += chunk_len;
- curr_off = start_iov_off;
- bytes_to_copy -= chunk_len;
- } else {
- curr_off += iov->iov_len;
- }
- iov++;
- }
-}
-
-static bool
-vmxnet3_indicate_packet(VMXNET3State *s)
-{
- struct Vmxnet3_RxDesc rxd;
- bool is_head = true;
- uint32_t rxd_idx;
- uint32_t rx_ridx = 0;
-
- struct Vmxnet3_RxCompDesc rxcd;
- uint32_t new_rxcd_gen = VMXNET3_INIT_GEN;
- hwaddr new_rxcd_pa = 0;
- hwaddr ready_rxcd_pa = 0;
- struct iovec *data = vmxnet_rx_pkt_get_iovec(s->rx_pkt);
- size_t bytes_copied = 0;
- size_t bytes_left = vmxnet_rx_pkt_get_total_len(s->rx_pkt);
- uint16_t num_frags = 0;
- size_t chunk_size;
-
- vmxnet_rx_pkt_dump(s->rx_pkt);
-
- while (bytes_left > 0) {
-
- /* cannot add more frags to packet */
- if (num_frags == s->max_rx_frags) {
- break;
- }
-
- new_rxcd_pa = vmxnet3_pop_rxc_descr(s, RXQ_IDX, &new_rxcd_gen);
- if (!new_rxcd_pa) {
- break;
- }
-
- if (!vmxnet3_get_next_rx_descr(s, is_head, &rxd, &rxd_idx, &rx_ridx)) {
- break;
- }
-
- chunk_size = MIN(bytes_left, rxd.len);
- vmxnet3_physical_memory_writev(data, bytes_copied,
- le64_to_cpu(rxd.addr), chunk_size);
- bytes_copied += chunk_size;
- bytes_left -= chunk_size;
-
- vmxnet3_dump_rx_descr(&rxd);
-
- if (ready_rxcd_pa != 0) {
- cpu_physical_memory_write(ready_rxcd_pa, &rxcd, sizeof(rxcd));
- }
-
- memset(&rxcd, 0, sizeof(struct Vmxnet3_RxCompDesc));
- rxcd.rxdIdx = rxd_idx;
- rxcd.len = chunk_size;
- rxcd.sop = is_head;
- rxcd.gen = new_rxcd_gen;
- rxcd.rqID = RXQ_IDX + rx_ridx * s->rxq_num;
-
- if (bytes_left == 0) {
- vmxnet3_rx_update_descr(s->rx_pkt, &rxcd);
- }
-
- VMW_RIPRN("RX Completion descriptor: rxRing: %lu rxIdx %lu len %lu "
- "sop %d csum_correct %lu",
- (unsigned long) rx_ridx,
- (unsigned long) rxcd.rxdIdx,
- (unsigned long) rxcd.len,
- (int) rxcd.sop,
- (unsigned long) rxcd.tuc);
-
- is_head = false;
- ready_rxcd_pa = new_rxcd_pa;
- new_rxcd_pa = 0;
- num_frags++;
- }
-
- if (ready_rxcd_pa != 0) {
- rxcd.eop = 1;
- rxcd.err = (bytes_left != 0);
- cpu_physical_memory_write(ready_rxcd_pa, &rxcd, sizeof(rxcd));
-
- /* Flush RX descriptor changes */
- smp_wmb();
- }
-
- if (new_rxcd_pa != 0) {
- vmxnet3_revert_rxc_descr(s, RXQ_IDX);
- }
-
- vmxnet3_trigger_interrupt(s, s->rxq_descr[RXQ_IDX].intr_idx);
-
- if (bytes_left == 0) {
- vmxnet3_on_rx_done_update_stats(s, RXQ_IDX, VMXNET3_PKT_STATUS_OK);
- return true;
- } else if (num_frags == s->max_rx_frags) {
- vmxnet3_on_rx_done_update_stats(s, RXQ_IDX, VMXNET3_PKT_STATUS_ERROR);
- return false;
- } else {
- vmxnet3_on_rx_done_update_stats(s, RXQ_IDX,
- VMXNET3_PKT_STATUS_OUT_OF_BUF);
- return false;
- }
-}
-
-static void
-vmxnet3_io_bar0_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- VMXNET3State *s = opaque;
-
- if (VMW_IS_MULTIREG_ADDR(addr, VMXNET3_REG_TXPROD,
- VMXNET3_DEVICE_MAX_TX_QUEUES, VMXNET3_REG_ALIGN)) {
- int tx_queue_idx =
- VMW_MULTIREG_IDX_BY_ADDR(addr, VMXNET3_REG_TXPROD,
- VMXNET3_REG_ALIGN);
- assert(tx_queue_idx <= s->txq_num);
- vmxnet3_process_tx_queue(s, tx_queue_idx);
- return;
- }
-
- if (VMW_IS_MULTIREG_ADDR(addr, VMXNET3_REG_IMR,
- VMXNET3_MAX_INTRS, VMXNET3_REG_ALIGN)) {
- int l = VMW_MULTIREG_IDX_BY_ADDR(addr, VMXNET3_REG_IMR,
- VMXNET3_REG_ALIGN);
-
- VMW_CBPRN("Interrupt mask for line %d written: 0x%" PRIx64, l, val);
-
- vmxnet3_on_interrupt_mask_changed(s, l, val);
- return;
- }
-
- if (VMW_IS_MULTIREG_ADDR(addr, VMXNET3_REG_RXPROD,
- VMXNET3_DEVICE_MAX_RX_QUEUES, VMXNET3_REG_ALIGN) ||
- VMW_IS_MULTIREG_ADDR(addr, VMXNET3_REG_RXPROD2,
- VMXNET3_DEVICE_MAX_RX_QUEUES, VMXNET3_REG_ALIGN)) {
- return;
- }
-
- VMW_WRPRN("BAR0 unknown write [%" PRIx64 "] = %" PRIx64 ", size %d",
- (uint64_t) addr, val, size);
-}
-
-static uint64_t
-vmxnet3_io_bar0_read(void *opaque, hwaddr addr, unsigned size)
-{
- VMXNET3State *s = opaque;
-
- if (VMW_IS_MULTIREG_ADDR(addr, VMXNET3_REG_IMR,
- VMXNET3_MAX_INTRS, VMXNET3_REG_ALIGN)) {
- int l = VMW_MULTIREG_IDX_BY_ADDR(addr, VMXNET3_REG_IMR,
- VMXNET3_REG_ALIGN);
- return s->interrupt_states[l].is_masked;
- }
-
- VMW_CBPRN("BAR0 unknown read [%" PRIx64 "], size %d", addr, size);
- return 0;
-}
-
-static void vmxnet3_reset_interrupt_states(VMXNET3State *s)
-{
- int i;
- for (i = 0; i < ARRAY_SIZE(s->interrupt_states); i++) {
- s->interrupt_states[i].is_asserted = false;
- s->interrupt_states[i].is_pending = false;
- s->interrupt_states[i].is_masked = true;
- }
-}
-
-static void vmxnet3_reset_mac(VMXNET3State *s)
-{
- memcpy(&s->conf.macaddr.a, &s->perm_mac.a, sizeof(s->perm_mac.a));
- VMW_CFPRN("MAC address set to: " VMXNET_MF, VMXNET_MA(s->conf.macaddr.a));
-}
-
-static void vmxnet3_deactivate_device(VMXNET3State *s)
-{
- if (s->device_active) {
- VMW_CBPRN("Deactivating vmxnet3...");
- vmxnet_tx_pkt_reset(s->tx_pkt);
- vmxnet_tx_pkt_uninit(s->tx_pkt);
- vmxnet_rx_pkt_uninit(s->rx_pkt);
- s->device_active = false;
- }
-}
-
-static void vmxnet3_reset(VMXNET3State *s)
-{
- VMW_CBPRN("Resetting vmxnet3...");
-
- vmxnet3_deactivate_device(s);
- vmxnet3_reset_interrupt_states(s);
- s->drv_shmem = 0;
- s->tx_sop = true;
- s->skip_current_tx_pkt = false;
-}
-
-static void vmxnet3_update_rx_mode(VMXNET3State *s)
-{
- s->rx_mode = VMXNET3_READ_DRV_SHARED32(s->drv_shmem,
- devRead.rxFilterConf.rxMode);
- VMW_CFPRN("RX mode: 0x%08X", s->rx_mode);
-}
-
-static void vmxnet3_update_vlan_filters(VMXNET3State *s)
-{
- int i;
-
- /* Copy configuration from shared memory */
- VMXNET3_READ_DRV_SHARED(s->drv_shmem,
- devRead.rxFilterConf.vfTable,
- s->vlan_table,
- sizeof(s->vlan_table));
-
- /* Invert byte order when needed */
- for (i = 0; i < ARRAY_SIZE(s->vlan_table); i++) {
- s->vlan_table[i] = le32_to_cpu(s->vlan_table[i]);
- }
-
- /* Dump configuration for debugging purposes */
- VMW_CFPRN("Configured VLANs:");
- for (i = 0; i < sizeof(s->vlan_table) * 8; i++) {
- if (VMXNET3_VFTABLE_ENTRY_IS_SET(s->vlan_table, i)) {
- VMW_CFPRN("\tVLAN %d is present", i);
- }
- }
-}
-
-static void vmxnet3_update_mcast_filters(VMXNET3State *s)
-{
- uint16_t list_bytes =
- VMXNET3_READ_DRV_SHARED16(s->drv_shmem,
- devRead.rxFilterConf.mfTableLen);
-
- s->mcast_list_len = list_bytes / sizeof(s->mcast_list[0]);
-
- s->mcast_list = g_realloc(s->mcast_list, list_bytes);
- if (!s->mcast_list) {
- if (s->mcast_list_len == 0) {
- VMW_CFPRN("Current multicast list is empty");
- } else {
- VMW_ERPRN("Failed to allocate multicast list of %d elements",
- s->mcast_list_len);
- }
- s->mcast_list_len = 0;
- } else {
- int i;
- hwaddr mcast_list_pa =
- VMXNET3_READ_DRV_SHARED64(s->drv_shmem,
- devRead.rxFilterConf.mfTablePA);
-
- cpu_physical_memory_read(mcast_list_pa, s->mcast_list, list_bytes);
- VMW_CFPRN("Current multicast list len is %d:", s->mcast_list_len);
- for (i = 0; i < s->mcast_list_len; i++) {
- VMW_CFPRN("\t" VMXNET_MF, VMXNET_MA(s->mcast_list[i].a));
- }
- }
-}
-
-static void vmxnet3_setup_rx_filtering(VMXNET3State *s)
-{
- vmxnet3_update_rx_mode(s);
- vmxnet3_update_vlan_filters(s);
- vmxnet3_update_mcast_filters(s);
-}
-
-static uint32_t vmxnet3_get_interrupt_config(VMXNET3State *s)
-{
- uint32_t interrupt_mode = VMXNET3_IT_AUTO | (VMXNET3_IMM_AUTO << 2);
- VMW_CFPRN("Interrupt config is 0x%X", interrupt_mode);
- return interrupt_mode;
-}
-
-static void vmxnet3_fill_stats(VMXNET3State *s)
-{
- int i;
-
- if (!s->device_active)
- return;
-
- for (i = 0; i < s->txq_num; i++) {
- cpu_physical_memory_write(s->txq_descr[i].tx_stats_pa,
- &s->txq_descr[i].txq_stats,
- sizeof(s->txq_descr[i].txq_stats));
- }
-
- for (i = 0; i < s->rxq_num; i++) {
- cpu_physical_memory_write(s->rxq_descr[i].rx_stats_pa,
- &s->rxq_descr[i].rxq_stats,
- sizeof(s->rxq_descr[i].rxq_stats));
- }
-}
-
-static void vmxnet3_adjust_by_guest_type(VMXNET3State *s)
-{
- struct Vmxnet3_GOSInfo gos;
-
- VMXNET3_READ_DRV_SHARED(s->drv_shmem, devRead.misc.driverInfo.gos,
- &gos, sizeof(gos));
- s->rx_packets_compound =
- (gos.gosType == VMXNET3_GOS_TYPE_WIN) ? false : true;
-
- VMW_CFPRN("Guest type specifics: RXCOMPOUND: %d", s->rx_packets_compound);
-}
-
-static void
-vmxnet3_dump_conf_descr(const char *name,
- struct Vmxnet3_VariableLenConfDesc *pm_descr)
-{
- VMW_CFPRN("%s descriptor dump: Version %u, Length %u",
- name, pm_descr->confVer, pm_descr->confLen);
-
-};
-
-static void vmxnet3_update_pm_state(VMXNET3State *s)
-{
- struct Vmxnet3_VariableLenConfDesc pm_descr;
-
- pm_descr.confLen =
- VMXNET3_READ_DRV_SHARED32(s->drv_shmem, devRead.pmConfDesc.confLen);
- pm_descr.confVer =
- VMXNET3_READ_DRV_SHARED32(s->drv_shmem, devRead.pmConfDesc.confVer);
- pm_descr.confPA =
- VMXNET3_READ_DRV_SHARED64(s->drv_shmem, devRead.pmConfDesc.confPA);
-
- vmxnet3_dump_conf_descr("PM State", &pm_descr);
-}
-
-static void vmxnet3_update_features(VMXNET3State *s)
-{
- uint32_t guest_features;
- int rxcso_supported;
-
- guest_features = VMXNET3_READ_DRV_SHARED32(s->drv_shmem,
- devRead.misc.uptFeatures);
-
- rxcso_supported = VMXNET_FLAG_IS_SET(guest_features, UPT1_F_RXCSUM);
- s->rx_vlan_stripping = VMXNET_FLAG_IS_SET(guest_features, UPT1_F_RXVLAN);
- s->lro_supported = VMXNET_FLAG_IS_SET(guest_features, UPT1_F_LRO);
-
- VMW_CFPRN("Features configuration: LRO: %d, RXCSUM: %d, VLANSTRIP: %d",
- s->lro_supported, rxcso_supported,
- s->rx_vlan_stripping);
- if (s->peer_has_vhdr) {
- qemu_set_offload(qemu_get_queue(s->nic)->peer,
- rxcso_supported,
- s->lro_supported,
- s->lro_supported,
- 0,
- 0);
- }
-}
-
-static bool vmxnet3_verify_intx(VMXNET3State *s, int intx)
-{
- return s->msix_used || s->msi_used || (intx ==
- (pci_get_byte(s->parent_obj.config + PCI_INTERRUPT_PIN) - 1));
-}
-
-static void vmxnet3_validate_interrupt_idx(bool is_msix, int idx)
-{
- int max_ints = is_msix ? VMXNET3_MAX_INTRS : VMXNET3_MAX_NMSIX_INTRS;
- if (idx >= max_ints) {
- hw_error("Bad interrupt index: %d\n", idx);
- }
-}
-
-static void vmxnet3_validate_interrupts(VMXNET3State *s)
-{
- int i;
-
- VMW_CFPRN("Verifying event interrupt index (%d)", s->event_int_idx);
- vmxnet3_validate_interrupt_idx(s->msix_used, s->event_int_idx);
-
- for (i = 0; i < s->txq_num; i++) {
- int idx = s->txq_descr[i].intr_idx;
- VMW_CFPRN("Verifying TX queue %d interrupt index (%d)", i, idx);
- vmxnet3_validate_interrupt_idx(s->msix_used, idx);
- }
-
- for (i = 0; i < s->rxq_num; i++) {
- int idx = s->rxq_descr[i].intr_idx;
- VMW_CFPRN("Verifying RX queue %d interrupt index (%d)", i, idx);
- vmxnet3_validate_interrupt_idx(s->msix_used, idx);
- }
-}
-
-static void vmxnet3_validate_queues(VMXNET3State *s)
-{
- /*
- * txq_num and rxq_num are total number of queues
- * configured by guest. These numbers must not
- * exceed corresponding maximal values.
- */
-
- if (s->txq_num > VMXNET3_DEVICE_MAX_TX_QUEUES) {
- hw_error("Bad TX queues number: %d\n", s->txq_num);
- }
-
- if (s->rxq_num > VMXNET3_DEVICE_MAX_RX_QUEUES) {
- hw_error("Bad RX queues number: %d\n", s->rxq_num);
- }
-}
-
-static void vmxnet3_activate_device(VMXNET3State *s)
-{
- int i;
- static const uint32_t VMXNET3_DEF_TX_THRESHOLD = 1;
- hwaddr qdescr_table_pa;
- uint64_t pa;
- uint32_t size;
-
- /* Verify configuration consistency */
- if (!vmxnet3_verify_driver_magic(s->drv_shmem)) {
- VMW_ERPRN("Device configuration received from driver is invalid");
- return;
- }
-
- /* Verify if device is active */
- if (s->device_active) {
- VMW_CFPRN("Vmxnet3 device is active");
- return;
- }
-
- vmxnet3_adjust_by_guest_type(s);
- vmxnet3_update_features(s);
- vmxnet3_update_pm_state(s);
- vmxnet3_setup_rx_filtering(s);
- /* Cache fields from shared memory */
- s->mtu = VMXNET3_READ_DRV_SHARED32(s->drv_shmem, devRead.misc.mtu);
- VMW_CFPRN("MTU is %u", s->mtu);
-
- s->max_rx_frags =
- VMXNET3_READ_DRV_SHARED16(s->drv_shmem, devRead.misc.maxNumRxSG);
-
- if (s->max_rx_frags == 0) {
- s->max_rx_frags = 1;
- }
-
- VMW_CFPRN("Max RX fragments is %u", s->max_rx_frags);
-
- s->event_int_idx =
- VMXNET3_READ_DRV_SHARED8(s->drv_shmem, devRead.intrConf.eventIntrIdx);
- assert(vmxnet3_verify_intx(s, s->event_int_idx));
- VMW_CFPRN("Events interrupt line is %u", s->event_int_idx);
-
- s->auto_int_masking =
- VMXNET3_READ_DRV_SHARED8(s->drv_shmem, devRead.intrConf.autoMask);
- VMW_CFPRN("Automatic interrupt masking is %d", (int)s->auto_int_masking);
-
- s->txq_num =
- VMXNET3_READ_DRV_SHARED8(s->drv_shmem, devRead.misc.numTxQueues);
- s->rxq_num =
- VMXNET3_READ_DRV_SHARED8(s->drv_shmem, devRead.misc.numRxQueues);
-
- VMW_CFPRN("Number of TX/RX queues %u/%u", s->txq_num, s->rxq_num);
- vmxnet3_validate_queues(s);
-
- qdescr_table_pa =
- VMXNET3_READ_DRV_SHARED64(s->drv_shmem, devRead.misc.queueDescPA);
- VMW_CFPRN("TX queues descriptors table is at 0x%" PRIx64, qdescr_table_pa);
-
- /*
- * Worst-case scenario is a packet that holds all TX rings space so
- * we calculate total size of all TX rings for max TX fragments number
- */
- s->max_tx_frags = 0;
-
- /* TX queues */
- for (i = 0; i < s->txq_num; i++) {
- hwaddr qdescr_pa =
- qdescr_table_pa + i * sizeof(struct Vmxnet3_TxQueueDesc);
-
- /* Read interrupt number for this TX queue */
- s->txq_descr[i].intr_idx =
- VMXNET3_READ_TX_QUEUE_DESCR8(qdescr_pa, conf.intrIdx);
- assert(vmxnet3_verify_intx(s, s->txq_descr[i].intr_idx));
-
- VMW_CFPRN("TX Queue %d interrupt: %d", i, s->txq_descr[i].intr_idx);
-
- /* Read rings memory locations for TX queues */
- pa = VMXNET3_READ_TX_QUEUE_DESCR64(qdescr_pa, conf.txRingBasePA);
- size = VMXNET3_READ_TX_QUEUE_DESCR32(qdescr_pa, conf.txRingSize);
-
- vmxnet3_ring_init(&s->txq_descr[i].tx_ring, pa, size,
- sizeof(struct Vmxnet3_TxDesc), false);
- VMXNET3_RING_DUMP(VMW_CFPRN, "TX", i, &s->txq_descr[i].tx_ring);
-
- s->max_tx_frags += size;
-
- /* TXC ring */
- pa = VMXNET3_READ_TX_QUEUE_DESCR64(qdescr_pa, conf.compRingBasePA);
- size = VMXNET3_READ_TX_QUEUE_DESCR32(qdescr_pa, conf.compRingSize);
- vmxnet3_ring_init(&s->txq_descr[i].comp_ring, pa, size,
- sizeof(struct Vmxnet3_TxCompDesc), true);
- VMXNET3_RING_DUMP(VMW_CFPRN, "TXC", i, &s->txq_descr[i].comp_ring);
-
- s->txq_descr[i].tx_stats_pa =
- qdescr_pa + offsetof(struct Vmxnet3_TxQueueDesc, stats);
-
- memset(&s->txq_descr[i].txq_stats, 0,
- sizeof(s->txq_descr[i].txq_stats));
-
- /* Fill device-managed parameters for queues */
- VMXNET3_WRITE_TX_QUEUE_DESCR32(qdescr_pa,
- ctrl.txThreshold,
- VMXNET3_DEF_TX_THRESHOLD);
- }
-
- /* Preallocate TX packet wrapper */
- VMW_CFPRN("Max TX fragments is %u", s->max_tx_frags);
- vmxnet_tx_pkt_init(&s->tx_pkt, s->max_tx_frags, s->peer_has_vhdr);
- vmxnet_rx_pkt_init(&s->rx_pkt, s->peer_has_vhdr);
-
- /* Read rings memory locations for RX queues */
- for (i = 0; i < s->rxq_num; i++) {
- int j;
- hwaddr qd_pa =
- qdescr_table_pa + s->txq_num * sizeof(struct Vmxnet3_TxQueueDesc) +
- i * sizeof(struct Vmxnet3_RxQueueDesc);
-
- /* Read interrupt number for this RX queue */
- s->rxq_descr[i].intr_idx =
- VMXNET3_READ_TX_QUEUE_DESCR8(qd_pa, conf.intrIdx);
- assert(vmxnet3_verify_intx(s, s->rxq_descr[i].intr_idx));
-
- VMW_CFPRN("RX Queue %d interrupt: %d", i, s->rxq_descr[i].intr_idx);
-
- /* Read rings memory locations */
- for (j = 0; j < VMXNET3_RX_RINGS_PER_QUEUE; j++) {
- /* RX rings */
- pa = VMXNET3_READ_RX_QUEUE_DESCR64(qd_pa, conf.rxRingBasePA[j]);
- size = VMXNET3_READ_RX_QUEUE_DESCR32(qd_pa, conf.rxRingSize[j]);
- vmxnet3_ring_init(&s->rxq_descr[i].rx_ring[j], pa, size,
- sizeof(struct Vmxnet3_RxDesc), false);
- VMW_CFPRN("RX queue %d:%d: Base: %" PRIx64 ", Size: %d",
- i, j, pa, size);
- }
-
- /* RXC ring */
- pa = VMXNET3_READ_RX_QUEUE_DESCR64(qd_pa, conf.compRingBasePA);
- size = VMXNET3_READ_RX_QUEUE_DESCR32(qd_pa, conf.compRingSize);
- vmxnet3_ring_init(&s->rxq_descr[i].comp_ring, pa, size,
- sizeof(struct Vmxnet3_RxCompDesc), true);
- VMW_CFPRN("RXC queue %d: Base: %" PRIx64 ", Size: %d", i, pa, size);
-
- s->rxq_descr[i].rx_stats_pa =
- qd_pa + offsetof(struct Vmxnet3_RxQueueDesc, stats);
- memset(&s->rxq_descr[i].rxq_stats, 0,
- sizeof(s->rxq_descr[i].rxq_stats));
- }
-
- vmxnet3_validate_interrupts(s);
-
- /* Make sure everything is in place before device activation */
- smp_wmb();
-
- vmxnet3_reset_mac(s);
-
- s->device_active = true;
-}
-
-static void vmxnet3_handle_command(VMXNET3State *s, uint64_t cmd)
-{
- s->last_command = cmd;
-
- switch (cmd) {
- case VMXNET3_CMD_GET_PERM_MAC_HI:
- VMW_CBPRN("Set: Get upper part of permanent MAC");
- break;
-
- case VMXNET3_CMD_GET_PERM_MAC_LO:
- VMW_CBPRN("Set: Get lower part of permanent MAC");
- break;
-
- case VMXNET3_CMD_GET_STATS:
- VMW_CBPRN("Set: Get device statistics");
- vmxnet3_fill_stats(s);
- break;
-
- case VMXNET3_CMD_ACTIVATE_DEV:
- VMW_CBPRN("Set: Activating vmxnet3 device");
- vmxnet3_activate_device(s);
- break;
-
- case VMXNET3_CMD_UPDATE_RX_MODE:
- VMW_CBPRN("Set: Update rx mode");
- vmxnet3_update_rx_mode(s);
- break;
-
- case VMXNET3_CMD_UPDATE_VLAN_FILTERS:
- VMW_CBPRN("Set: Update VLAN filters");
- vmxnet3_update_vlan_filters(s);
- break;
-
- case VMXNET3_CMD_UPDATE_MAC_FILTERS:
- VMW_CBPRN("Set: Update MAC filters");
- vmxnet3_update_mcast_filters(s);
- break;
-
- case VMXNET3_CMD_UPDATE_FEATURE:
- VMW_CBPRN("Set: Update features");
- vmxnet3_update_features(s);
- break;
-
- case VMXNET3_CMD_UPDATE_PMCFG:
- VMW_CBPRN("Set: Update power management config");
- vmxnet3_update_pm_state(s);
- break;
-
- case VMXNET3_CMD_GET_LINK:
- VMW_CBPRN("Set: Get link");
- break;
-
- case VMXNET3_CMD_RESET_DEV:
- VMW_CBPRN("Set: Reset device");
- vmxnet3_reset(s);
- break;
-
- case VMXNET3_CMD_QUIESCE_DEV:
- VMW_CBPRN("Set: VMXNET3_CMD_QUIESCE_DEV - deactivate the device");
- vmxnet3_deactivate_device(s);
- break;
-
- case VMXNET3_CMD_GET_CONF_INTR:
- VMW_CBPRN("Set: VMXNET3_CMD_GET_CONF_INTR - interrupt configuration");
- break;
-
- case VMXNET3_CMD_GET_ADAPTIVE_RING_INFO:
- VMW_CBPRN("Set: VMXNET3_CMD_GET_ADAPTIVE_RING_INFO - "
- "adaptive ring info flags");
- break;
-
- case VMXNET3_CMD_GET_DID_LO:
- VMW_CBPRN("Set: Get lower part of device ID");
- break;
-
- case VMXNET3_CMD_GET_DID_HI:
- VMW_CBPRN("Set: Get upper part of device ID");
- break;
-
- case VMXNET3_CMD_GET_DEV_EXTRA_INFO:
- VMW_CBPRN("Set: Get device extra info");
- break;
-
- default:
- VMW_CBPRN("Received unknown command: %" PRIx64, cmd);
- break;
- }
-}
-
-static uint64_t vmxnet3_get_command_status(VMXNET3State *s)
-{
- uint64_t ret;
-
- switch (s->last_command) {
- case VMXNET3_CMD_ACTIVATE_DEV:
- ret = (s->device_active) ? 0 : 1;
- VMW_CFPRN("Device active: %" PRIx64, ret);
- break;
-
- case VMXNET3_CMD_RESET_DEV:
- case VMXNET3_CMD_QUIESCE_DEV:
- case VMXNET3_CMD_GET_QUEUE_STATUS:
- case VMXNET3_CMD_GET_DEV_EXTRA_INFO:
- ret = 0;
- break;
-
- case VMXNET3_CMD_GET_LINK:
- ret = s->link_status_and_speed;
- VMW_CFPRN("Link and speed: %" PRIx64, ret);
- break;
-
- case VMXNET3_CMD_GET_PERM_MAC_LO:
- ret = vmxnet3_get_mac_low(&s->perm_mac);
- break;
-
- case VMXNET3_CMD_GET_PERM_MAC_HI:
- ret = vmxnet3_get_mac_high(&s->perm_mac);
- break;
-
- case VMXNET3_CMD_GET_CONF_INTR:
- ret = vmxnet3_get_interrupt_config(s);
- break;
-
- case VMXNET3_CMD_GET_ADAPTIVE_RING_INFO:
- ret = VMXNET3_DISABLE_ADAPTIVE_RING;
- break;
-
- case VMXNET3_CMD_GET_DID_LO:
- ret = PCI_DEVICE_ID_VMWARE_VMXNET3;
- break;
-
- case VMXNET3_CMD_GET_DID_HI:
- ret = VMXNET3_DEVICE_REVISION;
- break;
-
- default:
- VMW_WRPRN("Received request for unknown command: %x", s->last_command);
- ret = 0;
- break;
- }
-
- return ret;
-}
-
-static void vmxnet3_set_events(VMXNET3State *s, uint32_t val)
-{
- uint32_t events;
-
- VMW_CBPRN("Setting events: 0x%x", val);
- events = VMXNET3_READ_DRV_SHARED32(s->drv_shmem, ecr) | val;
- VMXNET3_WRITE_DRV_SHARED32(s->drv_shmem, ecr, events);
-}
-
-static void vmxnet3_ack_events(VMXNET3State *s, uint32_t val)
-{
- uint32_t events;
-
- VMW_CBPRN("Clearing events: 0x%x", val);
- events = VMXNET3_READ_DRV_SHARED32(s->drv_shmem, ecr) & ~val;
- VMXNET3_WRITE_DRV_SHARED32(s->drv_shmem, ecr, events);
-}
-
-static void
-vmxnet3_io_bar1_write(void *opaque,
- hwaddr addr,
- uint64_t val,
- unsigned size)
-{
- VMXNET3State *s = opaque;
-
- switch (addr) {
- /* Vmxnet3 Revision Report Selection */
- case VMXNET3_REG_VRRS:
- VMW_CBPRN("Write BAR1 [VMXNET3_REG_VRRS] = %" PRIx64 ", size %d",
- val, size);
- break;
-
- /* UPT Version Report Selection */
- case VMXNET3_REG_UVRS:
- VMW_CBPRN("Write BAR1 [VMXNET3_REG_UVRS] = %" PRIx64 ", size %d",
- val, size);
- break;
-
- /* Driver Shared Address Low */
- case VMXNET3_REG_DSAL:
- VMW_CBPRN("Write BAR1 [VMXNET3_REG_DSAL] = %" PRIx64 ", size %d",
- val, size);
- /*
- * Guest driver will first write the low part of the shared
- * memory address. We save it to temp variable and set the
- * shared address only after we get the high part
- */
- if (val == 0) {
- vmxnet3_deactivate_device(s);
- }
- s->temp_shared_guest_driver_memory = val;
- s->drv_shmem = 0;
- break;
-
- /* Driver Shared Address High */
- case VMXNET3_REG_DSAH:
- VMW_CBPRN("Write BAR1 [VMXNET3_REG_DSAH] = %" PRIx64 ", size %d",
- val, size);
- /*
- * Set the shared memory between guest driver and device.
- * We already should have low address part.
- */
- s->drv_shmem = s->temp_shared_guest_driver_memory | (val << 32);
- break;
-
- /* Command */
- case VMXNET3_REG_CMD:
- VMW_CBPRN("Write BAR1 [VMXNET3_REG_CMD] = %" PRIx64 ", size %d",
- val, size);
- vmxnet3_handle_command(s, val);
- break;
-
- /* MAC Address Low */
- case VMXNET3_REG_MACL:
- VMW_CBPRN("Write BAR1 [VMXNET3_REG_MACL] = %" PRIx64 ", size %d",
- val, size);
- s->temp_mac = val;
- break;
-
- /* MAC Address High */
- case VMXNET3_REG_MACH:
- VMW_CBPRN("Write BAR1 [VMXNET3_REG_MACH] = %" PRIx64 ", size %d",
- val, size);
- vmxnet3_set_variable_mac(s, val, s->temp_mac);
- break;
-
- /* Interrupt Cause Register */
- case VMXNET3_REG_ICR:
- VMW_CBPRN("Write BAR1 [VMXNET3_REG_ICR] = %" PRIx64 ", size %d",
- val, size);
- g_assert_not_reached();
- break;
-
- /* Event Cause Register */
- case VMXNET3_REG_ECR:
- VMW_CBPRN("Write BAR1 [VMXNET3_REG_ECR] = %" PRIx64 ", size %d",
- val, size);
- vmxnet3_ack_events(s, val);
- break;
-
- default:
- VMW_CBPRN("Unknown Write to BAR1 [%" PRIx64 "] = %" PRIx64 ", size %d",
- addr, val, size);
- break;
- }
-}
-
-static uint64_t
-vmxnet3_io_bar1_read(void *opaque, hwaddr addr, unsigned size)
-{
- VMXNET3State *s = opaque;
- uint64_t ret = 0;
-
- switch (addr) {
- /* Vmxnet3 Revision Report Selection */
- case VMXNET3_REG_VRRS:
- VMW_CBPRN("Read BAR1 [VMXNET3_REG_VRRS], size %d", size);
- ret = VMXNET3_DEVICE_REVISION;
- break;
-
- /* UPT Version Report Selection */
- case VMXNET3_REG_UVRS:
- VMW_CBPRN("Read BAR1 [VMXNET3_REG_UVRS], size %d", size);
- ret = VMXNET3_UPT_REVISION;
- break;
-
- /* Command */
- case VMXNET3_REG_CMD:
- VMW_CBPRN("Read BAR1 [VMXNET3_REG_CMD], size %d", size);
- ret = vmxnet3_get_command_status(s);
- break;
-
- /* MAC Address Low */
- case VMXNET3_REG_MACL:
- VMW_CBPRN("Read BAR1 [VMXNET3_REG_MACL], size %d", size);
- ret = vmxnet3_get_mac_low(&s->conf.macaddr);
- break;
-
- /* MAC Address High */
- case VMXNET3_REG_MACH:
- VMW_CBPRN("Read BAR1 [VMXNET3_REG_MACH], size %d", size);
- ret = vmxnet3_get_mac_high(&s->conf.macaddr);
- break;
-
- /*
- * Interrupt Cause Register
- * Used for legacy interrupts only so interrupt index always 0
- */
- case VMXNET3_REG_ICR:
- VMW_CBPRN("Read BAR1 [VMXNET3_REG_ICR], size %d", size);
- if (vmxnet3_interrupt_asserted(s, 0)) {
- vmxnet3_clear_interrupt(s, 0);
- ret = true;
- } else {
- ret = false;
- }
- break;
-
- default:
- VMW_CBPRN("Unknow read BAR1[%" PRIx64 "], %d bytes", addr, size);
- break;
- }
-
- return ret;
-}
-
-static int
-vmxnet3_can_receive(NetClientState *nc)
-{
- VMXNET3State *s = qemu_get_nic_opaque(nc);
- return s->device_active &&
- VMXNET_FLAG_IS_SET(s->link_status_and_speed, VMXNET3_LINK_STATUS_UP);
-}
-
-static inline bool
-vmxnet3_is_registered_vlan(VMXNET3State *s, const void *data)
-{
- uint16_t vlan_tag = eth_get_pkt_tci(data) & VLAN_VID_MASK;
- if (IS_SPECIAL_VLAN_ID(vlan_tag)) {
- return true;
- }
-
- return VMXNET3_VFTABLE_ENTRY_IS_SET(s->vlan_table, vlan_tag);
-}
-
-static bool
-vmxnet3_is_allowed_mcast_group(VMXNET3State *s, const uint8_t *group_mac)
-{
- int i;
- for (i = 0; i < s->mcast_list_len; i++) {
- if (!memcmp(group_mac, s->mcast_list[i].a, sizeof(s->mcast_list[i]))) {
- return true;
- }
- }
- return false;
-}
-
-static bool
-vmxnet3_rx_filter_may_indicate(VMXNET3State *s, const void *data,
- size_t size)
-{
- struct eth_header *ehdr = PKT_GET_ETH_HDR(data);
-
- if (VMXNET_FLAG_IS_SET(s->rx_mode, VMXNET3_RXM_PROMISC)) {
- return true;
- }
-
- if (!vmxnet3_is_registered_vlan(s, data)) {
- return false;
- }
-
- switch (vmxnet_rx_pkt_get_packet_type(s->rx_pkt)) {
- case ETH_PKT_UCAST:
- if (!VMXNET_FLAG_IS_SET(s->rx_mode, VMXNET3_RXM_UCAST)) {
- return false;
- }
- if (memcmp(s->conf.macaddr.a, ehdr->h_dest, ETH_ALEN)) {
- return false;
- }
- break;
-
- case ETH_PKT_BCAST:
- if (!VMXNET_FLAG_IS_SET(s->rx_mode, VMXNET3_RXM_BCAST)) {
- return false;
- }
- break;
-
- case ETH_PKT_MCAST:
- if (VMXNET_FLAG_IS_SET(s->rx_mode, VMXNET3_RXM_ALL_MULTI)) {
- return true;
- }
- if (!VMXNET_FLAG_IS_SET(s->rx_mode, VMXNET3_RXM_MCAST)) {
- return false;
- }
- if (!vmxnet3_is_allowed_mcast_group(s, ehdr->h_dest)) {
- return false;
- }
- break;
-
- default:
- g_assert_not_reached();
- }
-
- return true;
-}
-
-static ssize_t
-vmxnet3_receive(NetClientState *nc, const uint8_t *buf, size_t size)
-{
- VMXNET3State *s = qemu_get_nic_opaque(nc);
- size_t bytes_indicated;
- uint8_t min_buf[MIN_BUF_SIZE];
-
- if (!vmxnet3_can_receive(nc)) {
- VMW_PKPRN("Cannot receive now");
- return -1;
- }
-
- if (s->peer_has_vhdr) {
- vmxnet_rx_pkt_set_vhdr(s->rx_pkt, (struct virtio_net_hdr *)buf);
- buf += sizeof(struct virtio_net_hdr);
- size -= sizeof(struct virtio_net_hdr);
- }
-
- /* Pad to minimum Ethernet frame length */
- if (size < sizeof(min_buf)) {
- memcpy(min_buf, buf, size);
- memset(&min_buf[size], 0, sizeof(min_buf) - size);
- buf = min_buf;
- size = sizeof(min_buf);
- }
-
- vmxnet_rx_pkt_set_packet_type(s->rx_pkt,
- get_eth_packet_type(PKT_GET_ETH_HDR(buf)));
-
- if (vmxnet3_rx_filter_may_indicate(s, buf, size)) {
- vmxnet_rx_pkt_set_protocols(s->rx_pkt, buf, size);
- vmxnet3_rx_need_csum_calculate(s->rx_pkt, buf, size);
- vmxnet_rx_pkt_attach_data(s->rx_pkt, buf, size, s->rx_vlan_stripping);
- bytes_indicated = vmxnet3_indicate_packet(s) ? size : -1;
- if (bytes_indicated < size) {
- VMW_PKPRN("RX: %zu of %zu bytes indicated", bytes_indicated, size);
- }
- } else {
- VMW_PKPRN("Packet dropped by RX filter");
- bytes_indicated = size;
- }
-
- assert(size > 0);
- assert(bytes_indicated != 0);
- return bytes_indicated;
-}
-
-static void vmxnet3_set_link_status(NetClientState *nc)
-{
- VMXNET3State *s = qemu_get_nic_opaque(nc);
-
- if (nc->link_down) {
- s->link_status_and_speed &= ~VMXNET3_LINK_STATUS_UP;
- } else {
- s->link_status_and_speed |= VMXNET3_LINK_STATUS_UP;
- }
-
- vmxnet3_set_events(s, VMXNET3_ECR_LINK);
- vmxnet3_trigger_interrupt(s, s->event_int_idx);
-}
-
-static NetClientInfo net_vmxnet3_info = {
- .type = NET_CLIENT_OPTIONS_KIND_NIC,
- .size = sizeof(NICState),
- .receive = vmxnet3_receive,
- .link_status_changed = vmxnet3_set_link_status,
-};
-
-static bool vmxnet3_peer_has_vnet_hdr(VMXNET3State *s)
-{
- NetClientState *nc = qemu_get_queue(s->nic);
-
- if (qemu_has_vnet_hdr(nc->peer)) {
- return true;
- }
-
- return false;
-}
-
-static void vmxnet3_net_uninit(VMXNET3State *s)
-{
- g_free(s->mcast_list);
- vmxnet3_deactivate_device(s);
- qemu_del_nic(s->nic);
-}
-
-static void vmxnet3_net_init(VMXNET3State *s)
-{
- DeviceState *d = DEVICE(s);
-
- VMW_CBPRN("vmxnet3_net_init called...");
-
- qemu_macaddr_default_if_unset(&s->conf.macaddr);
-
- /* Windows guest will query the address that was set on init */
- memcpy(&s->perm_mac.a, &s->conf.macaddr.a, sizeof(s->perm_mac.a));
-
- s->mcast_list = NULL;
- s->mcast_list_len = 0;
-
- s->link_status_and_speed = VMXNET3_LINK_SPEED | VMXNET3_LINK_STATUS_UP;
-
- VMW_CFPRN("Permanent MAC: " VMXNET_MF, VMXNET_MA(s->perm_mac.a));
-
- s->nic = qemu_new_nic(&net_vmxnet3_info, &s->conf,
- object_get_typename(OBJECT(s)),
- d->id, s);
-
- s->peer_has_vhdr = vmxnet3_peer_has_vnet_hdr(s);
- s->tx_sop = true;
- s->skip_current_tx_pkt = false;
- s->tx_pkt = NULL;
- s->rx_pkt = NULL;
- s->rx_vlan_stripping = false;
- s->lro_supported = false;
-
- if (s->peer_has_vhdr) {
- qemu_set_vnet_hdr_len(qemu_get_queue(s->nic)->peer,
- sizeof(struct virtio_net_hdr));
-
- qemu_using_vnet_hdr(qemu_get_queue(s->nic)->peer, 1);
- }
-
- qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-}
-
-static void
-vmxnet3_unuse_msix_vectors(VMXNET3State *s, int num_vectors)
-{
- PCIDevice *d = PCI_DEVICE(s);
- int i;
- for (i = 0; i < num_vectors; i++) {
- msix_vector_unuse(d, i);
- }
-}
-
-static bool
-vmxnet3_use_msix_vectors(VMXNET3State *s, int num_vectors)
-{
- PCIDevice *d = PCI_DEVICE(s);
- int i;
- for (i = 0; i < num_vectors; i++) {
- int res = msix_vector_use(d, i);
- if (0 > res) {
- VMW_WRPRN("Failed to use MSI-X vector %d, error %d", i, res);
- vmxnet3_unuse_msix_vectors(s, i);
- return false;
- }
- }
- return true;
-}
-
-static bool
-vmxnet3_init_msix(VMXNET3State *s)
-{
- PCIDevice *d = PCI_DEVICE(s);
- int res = msix_init(d, VMXNET3_MAX_INTRS,
- &s->msix_bar,
- VMXNET3_MSIX_BAR_IDX, VMXNET3_OFF_MSIX_TABLE,
- &s->msix_bar,
- VMXNET3_MSIX_BAR_IDX, VMXNET3_OFF_MSIX_PBA(s),
- VMXNET3_MSIX_OFFSET(s));
-
- if (0 > res) {
- VMW_WRPRN("Failed to initialize MSI-X, error %d", res);
- s->msix_used = false;
- } else {
- if (!vmxnet3_use_msix_vectors(s, VMXNET3_MAX_INTRS)) {
- VMW_WRPRN("Failed to use MSI-X vectors, error %d", res);
- msix_uninit(d, &s->msix_bar, &s->msix_bar);
- s->msix_used = false;
- } else {
- s->msix_used = true;
- }
- }
- return s->msix_used;
-}
-
-static void
-vmxnet3_cleanup_msix(VMXNET3State *s)
-{
- PCIDevice *d = PCI_DEVICE(s);
-
- if (s->msix_used) {
- vmxnet3_unuse_msix_vectors(s, VMXNET3_MAX_INTRS);
- msix_uninit(d, &s->msix_bar, &s->msix_bar);
- }
-}
-
-#define VMXNET3_USE_64BIT (true)
-#define VMXNET3_PER_VECTOR_MASK (false)
-
-static bool
-vmxnet3_init_msi(VMXNET3State *s)
-{
- PCIDevice *d = PCI_DEVICE(s);
- int res;
-
- res = msi_init(d, VMXNET3_MSI_OFFSET(s), VMXNET3_MAX_NMSIX_INTRS,
- VMXNET3_USE_64BIT, VMXNET3_PER_VECTOR_MASK);
- if (0 > res) {
- VMW_WRPRN("Failed to initialize MSI, error %d", res);
- s->msi_used = false;
- } else {
- s->msi_used = true;
- }
-
- return s->msi_used;
-}
-
-static void
-vmxnet3_cleanup_msi(VMXNET3State *s)
-{
- PCIDevice *d = PCI_DEVICE(s);
-
- if (s->msi_used) {
- msi_uninit(d);
- }
-}
-
-static void
-vmxnet3_msix_save(QEMUFile *f, void *opaque)
-{
- PCIDevice *d = PCI_DEVICE(opaque);
- msix_save(d, f);
-}
-
-static int
-vmxnet3_msix_load(QEMUFile *f, void *opaque, int version_id)
-{
- PCIDevice *d = PCI_DEVICE(opaque);
- msix_load(d, f);
- return 0;
-}
-
-static const MemoryRegionOps b0_ops = {
- .read = vmxnet3_io_bar0_read,
- .write = vmxnet3_io_bar0_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .impl = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static const MemoryRegionOps b1_ops = {
- .read = vmxnet3_io_bar1_read,
- .write = vmxnet3_io_bar1_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .impl = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static uint8_t *vmxnet3_device_serial_num(VMXNET3State *s)
-{
- static uint64_t dsn_payload;
- uint8_t *dsnp = (uint8_t *)&dsn_payload;
-
- dsnp[0] = 0xfe;
- dsnp[1] = s->conf.macaddr.a[3];
- dsnp[2] = s->conf.macaddr.a[4];
- dsnp[3] = s->conf.macaddr.a[5];
- dsnp[4] = s->conf.macaddr.a[0];
- dsnp[5] = s->conf.macaddr.a[1];
- dsnp[6] = s->conf.macaddr.a[2];
- dsnp[7] = 0xff;
- return dsnp;
-}
-
-static void vmxnet3_pci_realize(PCIDevice *pci_dev, Error **errp)
-{
- DeviceState *dev = DEVICE(pci_dev);
- VMXNET3State *s = VMXNET3(pci_dev);
-
- VMW_CBPRN("Starting init...");
-
- memory_region_init_io(&s->bar0, OBJECT(s), &b0_ops, s,
- "vmxnet3-b0", VMXNET3_PT_REG_SIZE);
- pci_register_bar(pci_dev, VMXNET3_BAR0_IDX,
- PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar0);
-
- memory_region_init_io(&s->bar1, OBJECT(s), &b1_ops, s,
- "vmxnet3-b1", VMXNET3_VD_REG_SIZE);
- pci_register_bar(pci_dev, VMXNET3_BAR1_IDX,
- PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar1);
-
- memory_region_init(&s->msix_bar, OBJECT(s), "vmxnet3-msix-bar",
- VMXNET3_MSIX_BAR_SIZE);
- pci_register_bar(pci_dev, VMXNET3_MSIX_BAR_IDX,
- PCI_BASE_ADDRESS_SPACE_MEMORY, &s->msix_bar);
-
- vmxnet3_reset_interrupt_states(s);
-
- /* Interrupt pin A */
- pci_dev->config[PCI_INTERRUPT_PIN] = 0x01;
-
- if (!vmxnet3_init_msix(s)) {
- VMW_WRPRN("Failed to initialize MSI-X, configuration is inconsistent.");
- }
-
- if (!vmxnet3_init_msi(s)) {
- VMW_WRPRN("Failed to initialize MSI, configuration is inconsistent.");
- }
-
- vmxnet3_net_init(s);
-
- if (pci_is_express(pci_dev)) {
- if (pci_bus_is_express(pci_dev->bus)) {
- pcie_endpoint_cap_init(pci_dev, VMXNET3_EXP_EP_OFFSET);
- }
-
- pcie_add_capability(pci_dev, PCI_EXT_CAP_ID_DSN, 0x1,
- VMXNET3_DSN_OFFSET, PCI_EXT_CAP_DSN_SIZEOF);
- memcpy(pci_dev->config + VMXNET3_DSN_OFFSET + 4,
- vmxnet3_device_serial_num(s), sizeof(uint64_t));
- }
-
- register_savevm(dev, "vmxnet3-msix", -1, 1,
- vmxnet3_msix_save, vmxnet3_msix_load, s);
-}
-
-static void vmxnet3_instance_init(Object *obj)
-{
- VMXNET3State *s = VMXNET3(obj);
- device_add_bootindex_property(obj, &s->conf.bootindex,
- "bootindex", "/ethernet-phy@0",
- DEVICE(obj), NULL);
-}
-
-static void vmxnet3_pci_uninit(PCIDevice *pci_dev)
-{
- DeviceState *dev = DEVICE(pci_dev);
- VMXNET3State *s = VMXNET3(pci_dev);
-
- VMW_CBPRN("Starting uninit...");
-
- unregister_savevm(dev, "vmxnet3-msix", s);
-
- vmxnet3_net_uninit(s);
-
- vmxnet3_cleanup_msix(s);
-
- vmxnet3_cleanup_msi(s);
-}
-
-static void vmxnet3_qdev_reset(DeviceState *dev)
-{
- PCIDevice *d = PCI_DEVICE(dev);
- VMXNET3State *s = VMXNET3(d);
-
- VMW_CBPRN("Starting QDEV reset...");
- vmxnet3_reset(s);
-}
-
-static bool vmxnet3_mc_list_needed(void *opaque)
-{
- return true;
-}
-
-static int vmxnet3_mcast_list_pre_load(void *opaque)
-{
- VMXNET3State *s = opaque;
-
- s->mcast_list = g_malloc(s->mcast_list_buff_size);
-
- return 0;
-}
-
-
-static void vmxnet3_pre_save(void *opaque)
-{
- VMXNET3State *s = opaque;
-
- s->mcast_list_buff_size = s->mcast_list_len * sizeof(MACAddr);
-}
-
-static const VMStateDescription vmxstate_vmxnet3_mcast_list = {
- .name = "vmxnet3/mcast_list",
- .version_id = 1,
- .minimum_version_id = 1,
- .pre_load = vmxnet3_mcast_list_pre_load,
- .needed = vmxnet3_mc_list_needed,
- .fields = (VMStateField[]) {
- VMSTATE_VBUFFER_UINT32(mcast_list, VMXNET3State, 0, NULL, 0,
- mcast_list_buff_size),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void vmxnet3_get_ring_from_file(QEMUFile *f, Vmxnet3Ring *r)
-{
- r->pa = qemu_get_be64(f);
- r->size = qemu_get_be32(f);
- r->cell_size = qemu_get_be32(f);
- r->next = qemu_get_be32(f);
- r->gen = qemu_get_byte(f);
-}
-
-static void vmxnet3_put_ring_to_file(QEMUFile *f, Vmxnet3Ring *r)
-{
- qemu_put_be64(f, r->pa);
- qemu_put_be32(f, r->size);
- qemu_put_be32(f, r->cell_size);
- qemu_put_be32(f, r->next);
- qemu_put_byte(f, r->gen);
-}
-
-static void vmxnet3_get_tx_stats_from_file(QEMUFile *f,
- struct UPT1_TxStats *tx_stat)
-{
- tx_stat->TSOPktsTxOK = qemu_get_be64(f);
- tx_stat->TSOBytesTxOK = qemu_get_be64(f);
- tx_stat->ucastPktsTxOK = qemu_get_be64(f);
- tx_stat->ucastBytesTxOK = qemu_get_be64(f);
- tx_stat->mcastPktsTxOK = qemu_get_be64(f);
- tx_stat->mcastBytesTxOK = qemu_get_be64(f);
- tx_stat->bcastPktsTxOK = qemu_get_be64(f);
- tx_stat->bcastBytesTxOK = qemu_get_be64(f);
- tx_stat->pktsTxError = qemu_get_be64(f);
- tx_stat->pktsTxDiscard = qemu_get_be64(f);
-}
-
-static void vmxnet3_put_tx_stats_to_file(QEMUFile *f,
- struct UPT1_TxStats *tx_stat)
-{
- qemu_put_be64(f, tx_stat->TSOPktsTxOK);
- qemu_put_be64(f, tx_stat->TSOBytesTxOK);
- qemu_put_be64(f, tx_stat->ucastPktsTxOK);
- qemu_put_be64(f, tx_stat->ucastBytesTxOK);
- qemu_put_be64(f, tx_stat->mcastPktsTxOK);
- qemu_put_be64(f, tx_stat->mcastBytesTxOK);
- qemu_put_be64(f, tx_stat->bcastPktsTxOK);
- qemu_put_be64(f, tx_stat->bcastBytesTxOK);
- qemu_put_be64(f, tx_stat->pktsTxError);
- qemu_put_be64(f, tx_stat->pktsTxDiscard);
-}
-
-static int vmxnet3_get_txq_descr(QEMUFile *f, void *pv, size_t size)
-{
- Vmxnet3TxqDescr *r = pv;
-
- vmxnet3_get_ring_from_file(f, &r->tx_ring);
- vmxnet3_get_ring_from_file(f, &r->comp_ring);
- r->intr_idx = qemu_get_byte(f);
- r->tx_stats_pa = qemu_get_be64(f);
-
- vmxnet3_get_tx_stats_from_file(f, &r->txq_stats);
-
- return 0;
-}
-
-static void vmxnet3_put_txq_descr(QEMUFile *f, void *pv, size_t size)
-{
- Vmxnet3TxqDescr *r = pv;
-
- vmxnet3_put_ring_to_file(f, &r->tx_ring);
- vmxnet3_put_ring_to_file(f, &r->comp_ring);
- qemu_put_byte(f, r->intr_idx);
- qemu_put_be64(f, r->tx_stats_pa);
- vmxnet3_put_tx_stats_to_file(f, &r->txq_stats);
-}
-
-static const VMStateInfo txq_descr_info = {
- .name = "txq_descr",
- .get = vmxnet3_get_txq_descr,
- .put = vmxnet3_put_txq_descr
-};
-
-static void vmxnet3_get_rx_stats_from_file(QEMUFile *f,
- struct UPT1_RxStats *rx_stat)
-{
- rx_stat->LROPktsRxOK = qemu_get_be64(f);
- rx_stat->LROBytesRxOK = qemu_get_be64(f);
- rx_stat->ucastPktsRxOK = qemu_get_be64(f);
- rx_stat->ucastBytesRxOK = qemu_get_be64(f);
- rx_stat->mcastPktsRxOK = qemu_get_be64(f);
- rx_stat->mcastBytesRxOK = qemu_get_be64(f);
- rx_stat->bcastPktsRxOK = qemu_get_be64(f);
- rx_stat->bcastBytesRxOK = qemu_get_be64(f);
- rx_stat->pktsRxOutOfBuf = qemu_get_be64(f);
- rx_stat->pktsRxError = qemu_get_be64(f);
-}
-
-static void vmxnet3_put_rx_stats_to_file(QEMUFile *f,
- struct UPT1_RxStats *rx_stat)
-{
- qemu_put_be64(f, rx_stat->LROPktsRxOK);
- qemu_put_be64(f, rx_stat->LROBytesRxOK);
- qemu_put_be64(f, rx_stat->ucastPktsRxOK);
- qemu_put_be64(f, rx_stat->ucastBytesRxOK);
- qemu_put_be64(f, rx_stat->mcastPktsRxOK);
- qemu_put_be64(f, rx_stat->mcastBytesRxOK);
- qemu_put_be64(f, rx_stat->bcastPktsRxOK);
- qemu_put_be64(f, rx_stat->bcastBytesRxOK);
- qemu_put_be64(f, rx_stat->pktsRxOutOfBuf);
- qemu_put_be64(f, rx_stat->pktsRxError);
-}
-
-static int vmxnet3_get_rxq_descr(QEMUFile *f, void *pv, size_t size)
-{
- Vmxnet3RxqDescr *r = pv;
- int i;
-
- for (i = 0; i < VMXNET3_RX_RINGS_PER_QUEUE; i++) {
- vmxnet3_get_ring_from_file(f, &r->rx_ring[i]);
- }
-
- vmxnet3_get_ring_from_file(f, &r->comp_ring);
- r->intr_idx = qemu_get_byte(f);
- r->rx_stats_pa = qemu_get_be64(f);
-
- vmxnet3_get_rx_stats_from_file(f, &r->rxq_stats);
-
- return 0;
-}
-
-static void vmxnet3_put_rxq_descr(QEMUFile *f, void *pv, size_t size)
-{
- Vmxnet3RxqDescr *r = pv;
- int i;
-
- for (i = 0; i < VMXNET3_RX_RINGS_PER_QUEUE; i++) {
- vmxnet3_put_ring_to_file(f, &r->rx_ring[i]);
- }
-
- vmxnet3_put_ring_to_file(f, &r->comp_ring);
- qemu_put_byte(f, r->intr_idx);
- qemu_put_be64(f, r->rx_stats_pa);
- vmxnet3_put_rx_stats_to_file(f, &r->rxq_stats);
-}
-
-static int vmxnet3_post_load(void *opaque, int version_id)
-{
- VMXNET3State *s = opaque;
- PCIDevice *d = PCI_DEVICE(s);
-
- vmxnet_tx_pkt_init(&s->tx_pkt, s->max_tx_frags, s->peer_has_vhdr);
- vmxnet_rx_pkt_init(&s->rx_pkt, s->peer_has_vhdr);
-
- if (s->msix_used) {
- if (!vmxnet3_use_msix_vectors(s, VMXNET3_MAX_INTRS)) {
- VMW_WRPRN("Failed to re-use MSI-X vectors");
- msix_uninit(d, &s->msix_bar, &s->msix_bar);
- s->msix_used = false;
- return -1;
- }
- }
-
- vmxnet3_validate_queues(s);
- vmxnet3_validate_interrupts(s);
-
- return 0;
-}
-
-static const VMStateInfo rxq_descr_info = {
- .name = "rxq_descr",
- .get = vmxnet3_get_rxq_descr,
- .put = vmxnet3_put_rxq_descr
-};
-
-static int vmxnet3_get_int_state(QEMUFile *f, void *pv, size_t size)
-{
- Vmxnet3IntState *r = pv;
-
- r->is_masked = qemu_get_byte(f);
- r->is_pending = qemu_get_byte(f);
- r->is_asserted = qemu_get_byte(f);
-
- return 0;
-}
-
-static void vmxnet3_put_int_state(QEMUFile *f, void *pv, size_t size)
-{
- Vmxnet3IntState *r = pv;
-
- qemu_put_byte(f, r->is_masked);
- qemu_put_byte(f, r->is_pending);
- qemu_put_byte(f, r->is_asserted);
-}
-
-static const VMStateInfo int_state_info = {
- .name = "int_state",
- .get = vmxnet3_get_int_state,
- .put = vmxnet3_put_int_state
-};
-
-static bool vmxnet3_vmstate_need_pcie_device(void *opaque)
-{
- VMXNET3State *s = VMXNET3(opaque);
-
- return !(s->compat_flags & VMXNET3_COMPAT_FLAG_DISABLE_PCIE);
-}
-
-static bool vmxnet3_vmstate_test_pci_device(void *opaque, int version_id)
-{
- return !vmxnet3_vmstate_need_pcie_device(opaque);
-}
-
-static const VMStateDescription vmstate_vmxnet3_pcie_device = {
- .name = "vmxnet3/pcie",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = vmxnet3_vmstate_need_pcie_device,
- .fields = (VMStateField[]) {
- VMSTATE_PCIE_DEVICE(parent_obj, VMXNET3State),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_vmxnet3 = {
- .name = "vmxnet3",
- .version_id = 1,
- .minimum_version_id = 1,
- .pre_save = vmxnet3_pre_save,
- .post_load = vmxnet3_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT_TEST(parent_obj, VMXNET3State,
- vmxnet3_vmstate_test_pci_device, 0,
- vmstate_pci_device, PCIDevice),
- VMSTATE_BOOL(rx_packets_compound, VMXNET3State),
- VMSTATE_BOOL(rx_vlan_stripping, VMXNET3State),
- VMSTATE_BOOL(lro_supported, VMXNET3State),
- VMSTATE_UINT32(rx_mode, VMXNET3State),
- VMSTATE_UINT32(mcast_list_len, VMXNET3State),
- VMSTATE_UINT32(mcast_list_buff_size, VMXNET3State),
- VMSTATE_UINT32_ARRAY(vlan_table, VMXNET3State, VMXNET3_VFT_SIZE),
- VMSTATE_UINT32(mtu, VMXNET3State),
- VMSTATE_UINT16(max_rx_frags, VMXNET3State),
- VMSTATE_UINT32(max_tx_frags, VMXNET3State),
- VMSTATE_UINT8(event_int_idx, VMXNET3State),
- VMSTATE_BOOL(auto_int_masking, VMXNET3State),
- VMSTATE_UINT8(txq_num, VMXNET3State),
- VMSTATE_UINT8(rxq_num, VMXNET3State),
- VMSTATE_UINT32(device_active, VMXNET3State),
- VMSTATE_UINT32(last_command, VMXNET3State),
- VMSTATE_UINT32(link_status_and_speed, VMXNET3State),
- VMSTATE_UINT32(temp_mac, VMXNET3State),
- VMSTATE_UINT64(drv_shmem, VMXNET3State),
- VMSTATE_UINT64(temp_shared_guest_driver_memory, VMXNET3State),
-
- VMSTATE_ARRAY(txq_descr, VMXNET3State,
- VMXNET3_DEVICE_MAX_TX_QUEUES, 0, txq_descr_info,
- Vmxnet3TxqDescr),
- VMSTATE_ARRAY(rxq_descr, VMXNET3State,
- VMXNET3_DEVICE_MAX_RX_QUEUES, 0, rxq_descr_info,
- Vmxnet3RxqDescr),
- VMSTATE_ARRAY(interrupt_states, VMXNET3State, VMXNET3_MAX_INTRS,
- 0, int_state_info, Vmxnet3IntState),
-
- VMSTATE_END_OF_LIST()
- },
- .subsections = (const VMStateDescription*[]) {
- &vmxstate_vmxnet3_mcast_list,
- &vmstate_vmxnet3_pcie_device,
- NULL
- }
-};
-
-static Property vmxnet3_properties[] = {
- DEFINE_NIC_PROPERTIES(VMXNET3State, conf),
- DEFINE_PROP_BIT("x-old-msi-offsets", VMXNET3State, compat_flags,
- VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS_BIT, false),
- DEFINE_PROP_BIT("x-disable-pcie", VMXNET3State, compat_flags,
- VMXNET3_COMPAT_FLAG_DISABLE_PCIE_BIT, false),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void vmxnet3_realize(DeviceState *qdev, Error **errp)
-{
- VMXNET3Class *vc = VMXNET3_DEVICE_GET_CLASS(qdev);
- PCIDevice *pci_dev = PCI_DEVICE(qdev);
- VMXNET3State *s = VMXNET3(qdev);
-
- if (!(s->compat_flags & VMXNET3_COMPAT_FLAG_DISABLE_PCIE)) {
- pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS;
- }
-
- vc->parent_dc_realize(qdev, errp);
-}
-
-static void vmxnet3_class_init(ObjectClass *class, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(class);
- PCIDeviceClass *c = PCI_DEVICE_CLASS(class);
- VMXNET3Class *vc = VMXNET3_DEVICE_CLASS(class);
-
- c->realize = vmxnet3_pci_realize;
- c->exit = vmxnet3_pci_uninit;
- c->vendor_id = PCI_VENDOR_ID_VMWARE;
- c->device_id = PCI_DEVICE_ID_VMWARE_VMXNET3;
- c->revision = PCI_DEVICE_ID_VMWARE_VMXNET3_REVISION;
- c->class_id = PCI_CLASS_NETWORK_ETHERNET;
- c->subsystem_vendor_id = PCI_VENDOR_ID_VMWARE;
- c->subsystem_id = PCI_DEVICE_ID_VMWARE_VMXNET3;
- vc->parent_dc_realize = dc->realize;
- dc->realize = vmxnet3_realize;
- dc->desc = "VMWare Paravirtualized Ethernet v3";
- dc->reset = vmxnet3_qdev_reset;
- dc->vmsd = &vmstate_vmxnet3;
- dc->props = vmxnet3_properties;
- set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
-}
-
-static const TypeInfo vmxnet3_info = {
- .name = TYPE_VMXNET3,
- .parent = TYPE_PCI_DEVICE,
- .class_size = sizeof(VMXNET3Class),
- .instance_size = sizeof(VMXNET3State),
- .class_init = vmxnet3_class_init,
- .instance_init = vmxnet3_instance_init,
-};
-
-static void vmxnet3_register_types(void)
-{
- VMW_CBPRN("vmxnet3_register_types called...");
- type_register_static(&vmxnet3_info);
-}
-
-type_init(vmxnet3_register_types)
diff --git a/qemu/hw/net/vmxnet3.h b/qemu/hw/net/vmxnet3.h
deleted file mode 100644
index f7006afe9..000000000
--- a/qemu/hw/net/vmxnet3.h
+++ /dev/null
@@ -1,759 +0,0 @@
-/*
- * QEMU VMWARE VMXNET3 paravirtual NIC interface definitions
- *
- * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com)
- *
- * Developed by Daynix Computing LTD (http://www.daynix.com)
- *
- * Authors:
- * Dmitry Fleytman <dmitry@daynix.com>
- * Tamir Shomer <tamirs@daynix.com>
- * Yan Vugenfirer <yan@daynix.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#ifndef _QEMU_VMXNET3_H
-#define _QEMU_VMXNET3_H
-
-#define VMXNET3_DEVICE_MAX_TX_QUEUES 8
-#define VMXNET3_DEVICE_MAX_RX_QUEUES 8 /* Keep this value as a power of 2 */
-
-/*
- * VMWARE headers we got from Linux kernel do not fully comply QEMU coding
- * standards in sense of types and defines used.
- * Since we didn't want to change VMWARE code, following set of typedefs
- * and defines needed to compile these headers with QEMU introduced.
- */
-#define u64 uint64_t
-#define u32 uint32_t
-#define u16 uint16_t
-#define u8 uint8_t
-#define __le16 uint16_t
-#define __le32 uint32_t
-#define __le64 uint64_t
-
-#if defined(HOST_WORDS_BIGENDIAN)
-#define __BIG_ENDIAN_BITFIELD
-#else
-#endif
-
-/*
- * Following is an interface definition for
- * VMXNET3 device as provided by VMWARE
- * See original copyright from Linux kernel v3.2.8
- * header file drivers/net/vmxnet3/vmxnet3_defs.h below.
- */
-
-/*
- * Linux driver for VMware's vmxnet3 ethernet NIC.
- *
- * Copyright (C) 2008-2009, VMware, Inc. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; version 2 of the License and no later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Maintained by: Shreyas Bhatewara <pv-drivers@vmware.com>
- *
- */
-
-struct UPT1_TxStats {
- u64 TSOPktsTxOK; /* TSO pkts post-segmentation */
- u64 TSOBytesTxOK;
- u64 ucastPktsTxOK;
- u64 ucastBytesTxOK;
- u64 mcastPktsTxOK;
- u64 mcastBytesTxOK;
- u64 bcastPktsTxOK;
- u64 bcastBytesTxOK;
- u64 pktsTxError;
- u64 pktsTxDiscard;
-};
-
-struct UPT1_RxStats {
- u64 LROPktsRxOK; /* LRO pkts */
- u64 LROBytesRxOK; /* bytes from LRO pkts */
- /* the following counters are for pkts from the wire, i.e., pre-LRO */
- u64 ucastPktsRxOK;
- u64 ucastBytesRxOK;
- u64 mcastPktsRxOK;
- u64 mcastBytesRxOK;
- u64 bcastPktsRxOK;
- u64 bcastBytesRxOK;
- u64 pktsRxOutOfBuf;
- u64 pktsRxError;
-};
-
-/* interrupt moderation level */
-enum {
- UPT1_IML_NONE = 0, /* no interrupt moderation */
- UPT1_IML_HIGHEST = 7, /* least intr generated */
- UPT1_IML_ADAPTIVE = 8, /* adpative intr moderation */
-};
-/* values for UPT1_RSSConf.hashFunc */
-enum {
- UPT1_RSS_HASH_TYPE_NONE = 0x0,
- UPT1_RSS_HASH_TYPE_IPV4 = 0x01,
- UPT1_RSS_HASH_TYPE_TCP_IPV4 = 0x02,
- UPT1_RSS_HASH_TYPE_IPV6 = 0x04,
- UPT1_RSS_HASH_TYPE_TCP_IPV6 = 0x08,
-};
-
-enum {
- UPT1_RSS_HASH_FUNC_NONE = 0x0,
- UPT1_RSS_HASH_FUNC_TOEPLITZ = 0x01,
-};
-
-#define UPT1_RSS_MAX_KEY_SIZE 40
-#define UPT1_RSS_MAX_IND_TABLE_SIZE 128
-
-struct UPT1_RSSConf {
- u16 hashType;
- u16 hashFunc;
- u16 hashKeySize;
- u16 indTableSize;
- u8 hashKey[UPT1_RSS_MAX_KEY_SIZE];
- u8 indTable[UPT1_RSS_MAX_IND_TABLE_SIZE];
-};
-
-/* features */
-enum {
- UPT1_F_RXCSUM = 0x0001, /* rx csum verification */
- UPT1_F_RSS = 0x0002,
- UPT1_F_RXVLAN = 0x0004, /* VLAN tag stripping */
- UPT1_F_LRO = 0x0008,
-};
-
-/* all registers are 32 bit wide */
-/* BAR 1 */
-enum {
- VMXNET3_REG_VRRS = 0x0, /* Vmxnet3 Revision Report Selection */
- VMXNET3_REG_UVRS = 0x8, /* UPT Version Report Selection */
- VMXNET3_REG_DSAL = 0x10, /* Driver Shared Address Low */
- VMXNET3_REG_DSAH = 0x18, /* Driver Shared Address High */
- VMXNET3_REG_CMD = 0x20, /* Command */
- VMXNET3_REG_MACL = 0x28, /* MAC Address Low */
- VMXNET3_REG_MACH = 0x30, /* MAC Address High */
- VMXNET3_REG_ICR = 0x38, /* Interrupt Cause Register */
- VMXNET3_REG_ECR = 0x40 /* Event Cause Register */
-};
-
-/* BAR 0 */
-enum {
- VMXNET3_REG_IMR = 0x0, /* Interrupt Mask Register */
- VMXNET3_REG_TXPROD = 0x600, /* Tx Producer Index */
- VMXNET3_REG_RXPROD = 0x800, /* Rx Producer Index for ring 1 */
- VMXNET3_REG_RXPROD2 = 0xA00 /* Rx Producer Index for ring 2 */
-};
-
-#define VMXNET3_PT_REG_SIZE 4096 /* BAR 0 */
-#define VMXNET3_VD_REG_SIZE 4096 /* BAR 1 */
-
-#define VMXNET3_REG_ALIGN 8 /* All registers are 8-byte aligned. */
-#define VMXNET3_REG_ALIGN_MASK 0x7
-
-/* I/O Mapped access to registers */
-#define VMXNET3_IO_TYPE_PT 0
-#define VMXNET3_IO_TYPE_VD 1
-#define VMXNET3_IO_ADDR(type, reg) (((type) << 24) | ((reg) & 0xFFFFFF))
-#define VMXNET3_IO_TYPE(addr) ((addr) >> 24)
-#define VMXNET3_IO_REG(addr) ((addr) & 0xFFFFFF)
-
-enum {
- VMXNET3_CMD_FIRST_SET = 0xCAFE0000,
- VMXNET3_CMD_ACTIVATE_DEV = VMXNET3_CMD_FIRST_SET, /* 0xCAFE0000 */
- VMXNET3_CMD_QUIESCE_DEV, /* 0xCAFE0001 */
- VMXNET3_CMD_RESET_DEV, /* 0xCAFE0002 */
- VMXNET3_CMD_UPDATE_RX_MODE, /* 0xCAFE0003 */
- VMXNET3_CMD_UPDATE_MAC_FILTERS, /* 0xCAFE0004 */
- VMXNET3_CMD_UPDATE_VLAN_FILTERS, /* 0xCAFE0005 */
- VMXNET3_CMD_UPDATE_RSSIDT, /* 0xCAFE0006 */
- VMXNET3_CMD_UPDATE_IML, /* 0xCAFE0007 */
- VMXNET3_CMD_UPDATE_PMCFG, /* 0xCAFE0008 */
- VMXNET3_CMD_UPDATE_FEATURE, /* 0xCAFE0009 */
- VMXNET3_CMD_LOAD_PLUGIN, /* 0xCAFE000A */
-
- VMXNET3_CMD_FIRST_GET = 0xF00D0000,
- VMXNET3_CMD_GET_QUEUE_STATUS = VMXNET3_CMD_FIRST_GET, /* 0xF00D0000 */
- VMXNET3_CMD_GET_STATS, /* 0xF00D0001 */
- VMXNET3_CMD_GET_LINK, /* 0xF00D0002 */
- VMXNET3_CMD_GET_PERM_MAC_LO, /* 0xF00D0003 */
- VMXNET3_CMD_GET_PERM_MAC_HI, /* 0xF00D0004 */
- VMXNET3_CMD_GET_DID_LO, /* 0xF00D0005 */
- VMXNET3_CMD_GET_DID_HI, /* 0xF00D0006 */
- VMXNET3_CMD_GET_DEV_EXTRA_INFO, /* 0xF00D0007 */
- VMXNET3_CMD_GET_CONF_INTR, /* 0xF00D0008 */
- VMXNET3_CMD_GET_ADAPTIVE_RING_INFO /* 0xF00D0009 */
-};
-
-/* Adaptive Ring Info Flags */
-#define VMXNET3_DISABLE_ADAPTIVE_RING 1
-
-/*
- * Little Endian layout of bitfields -
- * Byte 0 : 7.....len.....0
- * Byte 1 : rsvd gen 13.len.8
- * Byte 2 : 5.msscof.0 ext1 dtype
- * Byte 3 : 13...msscof...6
- *
- * Big Endian layout of bitfields -
- * Byte 0: 13...msscof...6
- * Byte 1 : 5.msscof.0 ext1 dtype
- * Byte 2 : rsvd gen 13.len.8
- * Byte 3 : 7.....len.....0
- *
- * Thus, le32_to_cpu on the dword will allow the big endian driver to read
- * the bit fields correctly. And cpu_to_le32 will convert bitfields
- * bit fields written by big endian driver to format required by device.
- */
-
-struct Vmxnet3_TxDesc {
- __le64 addr;
-
-#ifdef __BIG_ENDIAN_BITFIELD
- u32 msscof:14; /* MSS, checksum offset, flags */
- u32 ext1:1;
- u32 dtype:1; /* descriptor type */
- u32 rsvd:1;
- u32 gen:1; /* generation bit */
- u32 len:14;
-#else
- u32 len:14;
- u32 gen:1; /* generation bit */
- u32 rsvd:1;
- u32 dtype:1; /* descriptor type */
- u32 ext1:1;
- u32 msscof:14; /* MSS, checksum offset, flags */
-#endif /* __BIG_ENDIAN_BITFIELD */
-
-#ifdef __BIG_ENDIAN_BITFIELD
- u32 tci:16; /* Tag to Insert */
- u32 ti:1; /* VLAN Tag Insertion */
- u32 ext2:1;
- u32 cq:1; /* completion request */
- u32 eop:1; /* End Of Packet */
- u32 om:2; /* offload mode */
- u32 hlen:10; /* header len */
-#else
- u32 hlen:10; /* header len */
- u32 om:2; /* offload mode */
- u32 eop:1; /* End Of Packet */
- u32 cq:1; /* completion request */
- u32 ext2:1;
- u32 ti:1; /* VLAN Tag Insertion */
- u32 tci:16; /* Tag to Insert */
-#endif /* __BIG_ENDIAN_BITFIELD */
-};
-
-/* TxDesc.OM values */
-#define VMXNET3_OM_NONE 0
-#define VMXNET3_OM_CSUM 2
-#define VMXNET3_OM_TSO 3
-
-/* fields in TxDesc we access w/o using bit fields */
-#define VMXNET3_TXD_EOP_SHIFT 12
-#define VMXNET3_TXD_CQ_SHIFT 13
-#define VMXNET3_TXD_GEN_SHIFT 14
-#define VMXNET3_TXD_EOP_DWORD_SHIFT 3
-#define VMXNET3_TXD_GEN_DWORD_SHIFT 2
-
-#define VMXNET3_TXD_CQ (1 << VMXNET3_TXD_CQ_SHIFT)
-#define VMXNET3_TXD_EOP (1 << VMXNET3_TXD_EOP_SHIFT)
-#define VMXNET3_TXD_GEN (1 << VMXNET3_TXD_GEN_SHIFT)
-
-#define VMXNET3_HDR_COPY_SIZE 128
-
-
-struct Vmxnet3_TxDataDesc {
- u8 data[VMXNET3_HDR_COPY_SIZE];
-};
-
-#define VMXNET3_TCD_GEN_SHIFT 31
-#define VMXNET3_TCD_GEN_SIZE 1
-#define VMXNET3_TCD_TXIDX_SHIFT 0
-#define VMXNET3_TCD_TXIDX_SIZE 12
-#define VMXNET3_TCD_GEN_DWORD_SHIFT 3
-
-struct Vmxnet3_TxCompDesc {
- u32 txdIdx:12; /* Index of the EOP TxDesc */
- u32 ext1:20;
-
- __le32 ext2;
- __le32 ext3;
-
- u32 rsvd:24;
- u32 type:7; /* completion type */
- u32 gen:1; /* generation bit */
-};
-
-struct Vmxnet3_RxDesc {
- __le64 addr;
-
-#ifdef __BIG_ENDIAN_BITFIELD
- u32 gen:1; /* Generation bit */
- u32 rsvd:15;
- u32 dtype:1; /* Descriptor type */
- u32 btype:1; /* Buffer Type */
- u32 len:14;
-#else
- u32 len:14;
- u32 btype:1; /* Buffer Type */
- u32 dtype:1; /* Descriptor type */
- u32 rsvd:15;
- u32 gen:1; /* Generation bit */
-#endif
- u32 ext1;
-};
-
-/* values of RXD.BTYPE */
-#define VMXNET3_RXD_BTYPE_HEAD 0 /* head only */
-#define VMXNET3_RXD_BTYPE_BODY 1 /* body only */
-
-/* fields in RxDesc we access w/o using bit fields */
-#define VMXNET3_RXD_BTYPE_SHIFT 14
-#define VMXNET3_RXD_GEN_SHIFT 31
-
-struct Vmxnet3_RxCompDesc {
-#ifdef __BIG_ENDIAN_BITFIELD
- u32 ext2:1;
- u32 cnc:1; /* Checksum Not Calculated */
- u32 rssType:4; /* RSS hash type used */
- u32 rqID:10; /* rx queue/ring ID */
- u32 sop:1; /* Start of Packet */
- u32 eop:1; /* End of Packet */
- u32 ext1:2;
- u32 rxdIdx:12; /* Index of the RxDesc */
-#else
- u32 rxdIdx:12; /* Index of the RxDesc */
- u32 ext1:2;
- u32 eop:1; /* End of Packet */
- u32 sop:1; /* Start of Packet */
- u32 rqID:10; /* rx queue/ring ID */
- u32 rssType:4; /* RSS hash type used */
- u32 cnc:1; /* Checksum Not Calculated */
- u32 ext2:1;
-#endif /* __BIG_ENDIAN_BITFIELD */
-
- __le32 rssHash; /* RSS hash value */
-
-#ifdef __BIG_ENDIAN_BITFIELD
- u32 tci:16; /* Tag stripped */
- u32 ts:1; /* Tag is stripped */
- u32 err:1; /* Error */
- u32 len:14; /* data length */
-#else
- u32 len:14; /* data length */
- u32 err:1; /* Error */
- u32 ts:1; /* Tag is stripped */
- u32 tci:16; /* Tag stripped */
-#endif /* __BIG_ENDIAN_BITFIELD */
-
-
-#ifdef __BIG_ENDIAN_BITFIELD
- u32 gen:1; /* generation bit */
- u32 type:7; /* completion type */
- u32 fcs:1; /* Frame CRC correct */
- u32 frg:1; /* IP Fragment */
- u32 v4:1; /* IPv4 */
- u32 v6:1; /* IPv6 */
- u32 ipc:1; /* IP Checksum Correct */
- u32 tcp:1; /* TCP packet */
- u32 udp:1; /* UDP packet */
- u32 tuc:1; /* TCP/UDP Checksum Correct */
- u32 csum:16;
-#else
- u32 csum:16;
- u32 tuc:1; /* TCP/UDP Checksum Correct */
- u32 udp:1; /* UDP packet */
- u32 tcp:1; /* TCP packet */
- u32 ipc:1; /* IP Checksum Correct */
- u32 v6:1; /* IPv6 */
- u32 v4:1; /* IPv4 */
- u32 frg:1; /* IP Fragment */
- u32 fcs:1; /* Frame CRC correct */
- u32 type:7; /* completion type */
- u32 gen:1; /* generation bit */
-#endif /* __BIG_ENDIAN_BITFIELD */
-};
-
-/* fields in RxCompDesc we access via Vmxnet3_GenericDesc.dword[3] */
-#define VMXNET3_RCD_TUC_SHIFT 16
-#define VMXNET3_RCD_IPC_SHIFT 19
-
-/* fields in RxCompDesc we access via Vmxnet3_GenericDesc.qword[1] */
-#define VMXNET3_RCD_TYPE_SHIFT 56
-#define VMXNET3_RCD_GEN_SHIFT 63
-
-/* csum OK for TCP/UDP pkts over IP */
-#define VMXNET3_RCD_CSUM_OK (1 << VMXNET3_RCD_TUC_SHIFT | \
- 1 << VMXNET3_RCD_IPC_SHIFT)
-#define VMXNET3_TXD_GEN_SIZE 1
-#define VMXNET3_TXD_EOP_SIZE 1
-
-/* value of RxCompDesc.rssType */
-enum {
- VMXNET3_RCD_RSS_TYPE_NONE = 0,
- VMXNET3_RCD_RSS_TYPE_IPV4 = 1,
- VMXNET3_RCD_RSS_TYPE_TCPIPV4 = 2,
- VMXNET3_RCD_RSS_TYPE_IPV6 = 3,
- VMXNET3_RCD_RSS_TYPE_TCPIPV6 = 4,
-};
-
-
-/* a union for accessing all cmd/completion descriptors */
-union Vmxnet3_GenericDesc {
- __le64 qword[2];
- __le32 dword[4];
- __le16 word[8];
- struct Vmxnet3_TxDesc txd;
- struct Vmxnet3_RxDesc rxd;
- struct Vmxnet3_TxCompDesc tcd;
- struct Vmxnet3_RxCompDesc rcd;
-};
-
-#define VMXNET3_INIT_GEN 1
-
-/* Max size of a single tx buffer */
-#define VMXNET3_MAX_TX_BUF_SIZE (1 << 14)
-
-/* # of tx desc needed for a tx buffer size */
-#define VMXNET3_TXD_NEEDED(size) (((size) + VMXNET3_MAX_TX_BUF_SIZE - 1) / \
- VMXNET3_MAX_TX_BUF_SIZE)
-
-/* max # of tx descs for a non-tso pkt */
-#define VMXNET3_MAX_TXD_PER_PKT 16
-
-/* Max size of a single rx buffer */
-#define VMXNET3_MAX_RX_BUF_SIZE ((1 << 14) - 1)
-/* Minimum size of a type 0 buffer */
-#define VMXNET3_MIN_T0_BUF_SIZE 128
-#define VMXNET3_MAX_CSUM_OFFSET 1024
-
-/* Ring base address alignment */
-#define VMXNET3_RING_BA_ALIGN 512
-#define VMXNET3_RING_BA_MASK (VMXNET3_RING_BA_ALIGN - 1)
-
-/* Ring size must be a multiple of 32 */
-#define VMXNET3_RING_SIZE_ALIGN 32
-#define VMXNET3_RING_SIZE_MASK (VMXNET3_RING_SIZE_ALIGN - 1)
-
-/* Max ring size */
-#define VMXNET3_TX_RING_MAX_SIZE 4096
-#define VMXNET3_TC_RING_MAX_SIZE 4096
-#define VMXNET3_RX_RING_MAX_SIZE 4096
-#define VMXNET3_RC_RING_MAX_SIZE 8192
-
-/* a list of reasons for queue stop */
-
-enum {
- VMXNET3_ERR_NOEOP = 0x80000000, /* cannot find the EOP desc of a pkt */
- VMXNET3_ERR_TXD_REUSE = 0x80000001, /* reuse TxDesc before tx completion */
- VMXNET3_ERR_BIG_PKT = 0x80000002, /* too many TxDesc for a pkt */
- VMXNET3_ERR_DESC_NOT_SPT = 0x80000003, /* descriptor type not supported */
- VMXNET3_ERR_SMALL_BUF = 0x80000004, /* type 0 buffer too small */
- VMXNET3_ERR_STRESS = 0x80000005, /* stress option firing in vmkernel */
- VMXNET3_ERR_SWITCH = 0x80000006, /* mode switch failure */
- VMXNET3_ERR_TXD_INVALID = 0x80000007, /* invalid TxDesc */
-};
-
-/* completion descriptor types */
-#define VMXNET3_CDTYPE_TXCOMP 0 /* Tx Completion Descriptor */
-#define VMXNET3_CDTYPE_RXCOMP 3 /* Rx Completion Descriptor */
-
-enum {
- VMXNET3_GOS_BITS_UNK = 0, /* unknown */
- VMXNET3_GOS_BITS_32 = 1,
- VMXNET3_GOS_BITS_64 = 2,
-};
-
-#define VMXNET3_GOS_TYPE_UNK 0 /* unknown */
-#define VMXNET3_GOS_TYPE_LINUX 1
-#define VMXNET3_GOS_TYPE_WIN 2
-#define VMXNET3_GOS_TYPE_SOLARIS 3
-#define VMXNET3_GOS_TYPE_FREEBSD 4
-#define VMXNET3_GOS_TYPE_PXE 5
-
-struct Vmxnet3_GOSInfo {
-#ifdef __BIG_ENDIAN_BITFIELD
- u32 gosMisc:10; /* other info about gos */
- u32 gosVer:16; /* gos version */
- u32 gosType:4; /* which guest */
- u32 gosBits:2; /* 32-bit or 64-bit? */
-#else
- u32 gosBits:2; /* 32-bit or 64-bit? */
- u32 gosType:4; /* which guest */
- u32 gosVer:16; /* gos version */
- u32 gosMisc:10; /* other info about gos */
-#endif /* __BIG_ENDIAN_BITFIELD */
-};
-
-struct Vmxnet3_DriverInfo {
- __le32 version;
- struct Vmxnet3_GOSInfo gos;
- __le32 vmxnet3RevSpt;
- __le32 uptVerSpt;
-};
-
-
-#define VMXNET3_REV1_MAGIC 0xbabefee1
-
-/*
- * QueueDescPA must be 128 bytes aligned. It points to an array of
- * Vmxnet3_TxQueueDesc followed by an array of Vmxnet3_RxQueueDesc.
- * The number of Vmxnet3_TxQueueDesc/Vmxnet3_RxQueueDesc are specified by
- * Vmxnet3_MiscConf.numTxQueues/numRxQueues, respectively.
- */
-#define VMXNET3_QUEUE_DESC_ALIGN 128
-
-
-struct Vmxnet3_MiscConf {
- struct Vmxnet3_DriverInfo driverInfo;
- __le64 uptFeatures;
- __le64 ddPA; /* driver data PA */
- __le64 queueDescPA; /* queue descriptor table PA */
- __le32 ddLen; /* driver data len */
- __le32 queueDescLen; /* queue desc. table len in bytes */
- __le32 mtu;
- __le16 maxNumRxSG;
- u8 numTxQueues;
- u8 numRxQueues;
- __le32 reserved[4];
-};
-
-
-struct Vmxnet3_TxQueueConf {
- __le64 txRingBasePA;
- __le64 dataRingBasePA;
- __le64 compRingBasePA;
- __le64 ddPA; /* driver data */
- __le64 reserved;
- __le32 txRingSize; /* # of tx desc */
- __le32 dataRingSize; /* # of data desc */
- __le32 compRingSize; /* # of comp desc */
- __le32 ddLen; /* size of driver data */
- u8 intrIdx;
- u8 _pad[7];
-};
-
-
-struct Vmxnet3_RxQueueConf {
- __le64 rxRingBasePA[2];
- __le64 compRingBasePA;
- __le64 ddPA; /* driver data */
- __le64 reserved;
- __le32 rxRingSize[2]; /* # of rx desc */
- __le32 compRingSize; /* # of rx comp desc */
- __le32 ddLen; /* size of driver data */
- u8 intrIdx;
- u8 _pad[7];
-};
-
-
-enum vmxnet3_intr_mask_mode {
- VMXNET3_IMM_AUTO = 0,
- VMXNET3_IMM_ACTIVE = 1,
- VMXNET3_IMM_LAZY = 2
-};
-
-enum vmxnet3_intr_type {
- VMXNET3_IT_AUTO = 0,
- VMXNET3_IT_INTX = 1,
- VMXNET3_IT_MSI = 2,
- VMXNET3_IT_MSIX = 3
-};
-
-#define VMXNET3_MAX_TX_QUEUES 8
-#define VMXNET3_MAX_RX_QUEUES 16
-/* addition 1 for events */
-#define VMXNET3_MAX_INTRS 25
-
-/* value of intrCtrl */
-#define VMXNET3_IC_DISABLE_ALL 0x1 /* bit 0 */
-
-
-struct Vmxnet3_IntrConf {
- bool autoMask;
- u8 numIntrs; /* # of interrupts */
- u8 eventIntrIdx;
- u8 modLevels[VMXNET3_MAX_INTRS]; /* moderation level for
- * each intr */
- __le32 intrCtrl;
- __le32 reserved[2];
-};
-
-/* one bit per VLAN ID, the size is in the units of u32 */
-#define VMXNET3_VFT_SIZE (4096/(sizeof(uint32_t)*8))
-
-
-struct Vmxnet3_QueueStatus {
- bool stopped;
- u8 _pad[3];
- __le32 error;
-};
-
-
-struct Vmxnet3_TxQueueCtrl {
- __le32 txNumDeferred;
- __le32 txThreshold;
- __le64 reserved;
-};
-
-
-struct Vmxnet3_RxQueueCtrl {
- bool updateRxProd;
- u8 _pad[7];
- __le64 reserved;
-};
-
-enum {
- VMXNET3_RXM_UCAST = 0x01, /* unicast only */
- VMXNET3_RXM_MCAST = 0x02, /* multicast passing the filters */
- VMXNET3_RXM_BCAST = 0x04, /* broadcast only */
- VMXNET3_RXM_ALL_MULTI = 0x08, /* all multicast */
- VMXNET3_RXM_PROMISC = 0x10 /* promiscuous */
-};
-
-struct Vmxnet3_RxFilterConf {
- __le32 rxMode; /* VMXNET3_RXM_xxx */
- __le16 mfTableLen; /* size of the multicast filter table */
- __le16 _pad1;
- __le64 mfTablePA; /* PA of the multicast filters table */
- __le32 vfTable[VMXNET3_VFT_SIZE]; /* vlan filter */
-};
-
-
-#define VMXNET3_PM_MAX_FILTERS 6
-#define VMXNET3_PM_MAX_PATTERN_SIZE 128
-#define VMXNET3_PM_MAX_MASK_SIZE (VMXNET3_PM_MAX_PATTERN_SIZE / 8)
-
-#define VMXNET3_PM_WAKEUP_MAGIC cpu_to_le16(0x01) /* wake up on magic pkts */
-#define VMXNET3_PM_WAKEUP_FILTER cpu_to_le16(0x02) /* wake up on pkts matching
- * filters */
-
-
-struct Vmxnet3_PM_PktFilter {
- u8 maskSize;
- u8 patternSize;
- u8 mask[VMXNET3_PM_MAX_MASK_SIZE];
- u8 pattern[VMXNET3_PM_MAX_PATTERN_SIZE];
- u8 pad[6];
-};
-
-
-struct Vmxnet3_PMConf {
- __le16 wakeUpEvents; /* VMXNET3_PM_WAKEUP_xxx */
- u8 numFilters;
- u8 pad[5];
- struct Vmxnet3_PM_PktFilter filters[VMXNET3_PM_MAX_FILTERS];
-};
-
-
-struct Vmxnet3_VariableLenConfDesc {
- __le32 confVer;
- __le32 confLen;
- __le64 confPA;
-};
-
-
-struct Vmxnet3_TxQueueDesc {
- struct Vmxnet3_TxQueueCtrl ctrl;
- struct Vmxnet3_TxQueueConf conf;
-
- /* Driver read after a GET command */
- struct Vmxnet3_QueueStatus status;
- struct UPT1_TxStats stats;
- u8 _pad[88]; /* 128 aligned */
-};
-
-
-struct Vmxnet3_RxQueueDesc {
- struct Vmxnet3_RxQueueCtrl ctrl;
- struct Vmxnet3_RxQueueConf conf;
- /* Driver read after a GET commad */
- struct Vmxnet3_QueueStatus status;
- struct UPT1_RxStats stats;
- u8 __pad[88]; /* 128 aligned */
-};
-
-
-struct Vmxnet3_DSDevRead {
- /* read-only region for device, read by dev in response to a SET cmd */
- struct Vmxnet3_MiscConf misc;
- struct Vmxnet3_IntrConf intrConf;
- struct Vmxnet3_RxFilterConf rxFilterConf;
- struct Vmxnet3_VariableLenConfDesc rssConfDesc;
- struct Vmxnet3_VariableLenConfDesc pmConfDesc;
- struct Vmxnet3_VariableLenConfDesc pluginConfDesc;
-};
-
-/* All structures in DriverShared are padded to multiples of 8 bytes */
-struct Vmxnet3_DriverShared {
- __le32 magic;
- /* make devRead start at 64bit boundaries */
- __le32 pad;
- struct Vmxnet3_DSDevRead devRead;
- __le32 ecr;
- __le32 reserved[5];
-};
-
-
-#define VMXNET3_ECR_RQERR (1 << 0)
-#define VMXNET3_ECR_TQERR (1 << 1)
-#define VMXNET3_ECR_LINK (1 << 2)
-#define VMXNET3_ECR_DIC (1 << 3)
-#define VMXNET3_ECR_DEBUG (1 << 4)
-
-/* flip the gen bit of a ring */
-#define VMXNET3_FLIP_RING_GEN(gen) ((gen) = (gen) ^ 0x1)
-
-/* only use this if moving the idx won't affect the gen bit */
-#define VMXNET3_INC_RING_IDX_ONLY(idx, ring_size) \
- do {\
- (idx)++;\
- if (unlikely((idx) == (ring_size))) {\
- (idx) = 0;\
- } \
- } while (0)
-
-#define VMXNET3_SET_VFTABLE_ENTRY(vfTable, vid) \
- (vfTable[vid >> 5] |= (1 << (vid & 31)))
-#define VMXNET3_CLEAR_VFTABLE_ENTRY(vfTable, vid) \
- (vfTable[vid >> 5] &= ~(1 << (vid & 31)))
-
-#define VMXNET3_VFTABLE_ENTRY_IS_SET(vfTable, vid) \
- ((vfTable[vid >> 5] & (1 << (vid & 31))) != 0)
-
-#define VMXNET3_MAX_MTU 9000
-#define VMXNET3_MIN_MTU 60
-
-#define VMXNET3_LINK_UP (10000 << 16 | 1) /* 10 Gbps, up */
-#define VMXNET3_LINK_DOWN 0
-
-#undef u64
-#undef u32
-#undef u16
-#undef u8
-#undef __le16
-#undef __le32
-#undef __le64
-#if defined(HOST_WORDS_BIGENDIAN)
-#undef __BIG_ENDIAN_BITFIELD
-#endif
-
-#endif
diff --git a/qemu/hw/net/vmxnet_debug.h b/qemu/hw/net/vmxnet_debug.h
deleted file mode 100644
index 96495dbb1..000000000
--- a/qemu/hw/net/vmxnet_debug.h
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * QEMU VMWARE VMXNET* paravirtual NICs - debugging facilities
- *
- * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com)
- *
- * Developed by Daynix Computing LTD (http://www.daynix.com)
- *
- * Authors:
- * Dmitry Fleytman <dmitry@daynix.com>
- * Tamir Shomer <tamirs@daynix.com>
- * Yan Vugenfirer <yan@daynix.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#ifndef _QEMU_VMXNET_DEBUG_H
-#define _QEMU_VMXNET_DEBUG_H
-
-#define VMXNET_DEVICE_NAME "vmxnet3"
-
-#define VMXNET_DEBUG_WARNINGS
-#define VMXNET_DEBUG_ERRORS
-
-#undef VMXNET_DEBUG_CB
-#undef VMXNET_DEBUG_INTERRUPTS
-#undef VMXNET_DEBUG_CONFIG
-#undef VMXNET_DEBUG_RINGS
-#undef VMXNET_DEBUG_PACKETS
-#undef VMXNET_DEBUG_SHMEM_ACCESS
-
-#ifdef VMXNET_DEBUG_CB
-# define VMXNET_DEBUG_CB_ENABLED 1
-#else
-# define VMXNET_DEBUG_CB_ENABLED 0
-#endif
-
-#ifdef VMXNET_DEBUG_WARNINGS
-# define VMXNET_DEBUG_WARNINGS_ENABLED 1
-#else
-# define VMXNET_DEBUG_WARNINGS_ENABLED 0
-#endif
-
-#ifdef VMXNET_DEBUG_ERRORS
-# define VMXNET_DEBUG_ERRORS_ENABLED 1
-#else
-# define VMXNET_DEBUG_ERRORS_ENABLED 0
-#endif
-
-#ifdef VMXNET_DEBUG_CONFIG
-# define VMXNET_DEBUG_CONFIG_ENABLED 1
-#else
-# define VMXNET_DEBUG_CONFIG_ENABLED 0
-#endif
-
-#ifdef VMXNET_DEBUG_RINGS
-# define VMXNET_DEBUG_RINGS_ENABLED 1
-#else
-# define VMXNET_DEBUG_RINGS_ENABLED 0
-#endif
-
-#ifdef VMXNET_DEBUG_PACKETS
-# define VMXNET_DEBUG_PACKETS_ENABLED 1
-#else
-# define VMXNET_DEBUG_PACKETS_ENABLED 0
-#endif
-
-#ifdef VMXNET_DEBUG_INTERRUPTS
-# define VMXNET_DEBUG_INTERRUPTS_ENABLED 1
-#else
-# define VMXNET_DEBUG_INTERRUPTS_ENABLED 0
-#endif
-
-#ifdef VMXNET_DEBUG_SHMEM_ACCESS
-# define VMXNET_DEBUG_SHMEM_ACCESS_ENABLED 1
-#else
-# define VMXNET_DEBUG_SHMEM_ACCESS_ENABLED 0
-#endif
-
-#define VMW_SHPRN(fmt, ...) \
- do { \
- if (VMXNET_DEBUG_SHMEM_ACCESS_ENABLED) { \
- printf("[%s][SH][%s]: " fmt "\n", VMXNET_DEVICE_NAME, __func__, \
- ## __VA_ARGS__); \
- } \
- } while (0)
-
-#define VMW_CBPRN(fmt, ...) \
- do { \
- if (VMXNET_DEBUG_CB_ENABLED) { \
- printf("[%s][CB][%s]: " fmt "\n", VMXNET_DEVICE_NAME, __func__, \
- ## __VA_ARGS__); \
- } \
- } while (0)
-
-#define VMW_PKPRN(fmt, ...) \
- do { \
- if (VMXNET_DEBUG_PACKETS_ENABLED) { \
- printf("[%s][PK][%s]: " fmt "\n", VMXNET_DEVICE_NAME, __func__, \
- ## __VA_ARGS__); \
- } \
- } while (0)
-
-#define VMW_WRPRN(fmt, ...) \
- do { \
- if (VMXNET_DEBUG_WARNINGS_ENABLED) { \
- printf("[%s][WR][%s]: " fmt "\n", VMXNET_DEVICE_NAME, __func__, \
- ## __VA_ARGS__); \
- } \
- } while (0)
-
-#define VMW_ERPRN(fmt, ...) \
- do { \
- if (VMXNET_DEBUG_ERRORS_ENABLED) { \
- printf("[%s][ER][%s]: " fmt "\n", VMXNET_DEVICE_NAME, __func__, \
- ## __VA_ARGS__); \
- } \
- } while (0)
-
-#define VMW_IRPRN(fmt, ...) \
- do { \
- if (VMXNET_DEBUG_INTERRUPTS_ENABLED) { \
- printf("[%s][IR][%s]: " fmt "\n", VMXNET_DEVICE_NAME, __func__, \
- ## __VA_ARGS__); \
- } \
- } while (0)
-
-#define VMW_CFPRN(fmt, ...) \
- do { \
- if (VMXNET_DEBUG_CONFIG_ENABLED) { \
- printf("[%s][CF][%s]: " fmt "\n", VMXNET_DEVICE_NAME, __func__, \
- ## __VA_ARGS__); \
- } \
- } while (0)
-
-#define VMW_RIPRN(fmt, ...) \
- do { \
- if (VMXNET_DEBUG_RINGS_ENABLED) { \
- printf("[%s][RI][%s]: " fmt "\n", VMXNET_DEVICE_NAME, __func__, \
- ## __VA_ARGS__); \
- } \
- } while (0)
-
-#define VMXNET_MF "%02X:%02X:%02X:%02X:%02X:%02X"
-#define VMXNET_MA(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
-
-#endif /* _QEMU_VMXNET3_DEBUG_H */
diff --git a/qemu/hw/net/vmxnet_rx_pkt.c b/qemu/hw/net/vmxnet_rx_pkt.c
deleted file mode 100644
index 21bb46e68..000000000
--- a/qemu/hw/net/vmxnet_rx_pkt.c
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * QEMU VMWARE VMXNET* paravirtual NICs - RX packets abstractions
- *
- * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com)
- *
- * Developed by Daynix Computing LTD (http://www.daynix.com)
- *
- * Authors:
- * Dmitry Fleytman <dmitry@daynix.com>
- * Tamir Shomer <tamirs@daynix.com>
- * Yan Vugenfirer <yan@daynix.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "vmxnet_rx_pkt.h"
-#include "net/eth.h"
-#include "qemu-common.h"
-#include "qemu/iov.h"
-#include "net/checksum.h"
-#include "net/tap.h"
-
-/*
- * RX packet may contain up to 2 fragments - rebuilt eth header
- * in case of VLAN tag stripping
- * and payload received from QEMU - in any case
- */
-#define VMXNET_MAX_RX_PACKET_FRAGMENTS (2)
-
-struct VmxnetRxPkt {
- struct virtio_net_hdr virt_hdr;
- uint8_t ehdr_buf[ETH_MAX_L2_HDR_LEN];
- struct iovec vec[VMXNET_MAX_RX_PACKET_FRAGMENTS];
- uint16_t vec_len;
- uint32_t tot_len;
- uint16_t tci;
- bool vlan_stripped;
- bool has_virt_hdr;
- eth_pkt_types_e packet_type;
-
- /* Analysis results */
- bool isip4;
- bool isip6;
- bool isudp;
- bool istcp;
-};
-
-void vmxnet_rx_pkt_init(struct VmxnetRxPkt **pkt, bool has_virt_hdr)
-{
- struct VmxnetRxPkt *p = g_malloc0(sizeof *p);
- p->has_virt_hdr = has_virt_hdr;
- *pkt = p;
-}
-
-void vmxnet_rx_pkt_uninit(struct VmxnetRxPkt *pkt)
-{
- g_free(pkt);
-}
-
-struct virtio_net_hdr *vmxnet_rx_pkt_get_vhdr(struct VmxnetRxPkt *pkt)
-{
- assert(pkt);
- return &pkt->virt_hdr;
-}
-
-void vmxnet_rx_pkt_attach_data(struct VmxnetRxPkt *pkt, const void *data,
- size_t len, bool strip_vlan)
-{
- uint16_t tci = 0;
- uint16_t ploff;
- assert(pkt);
- pkt->vlan_stripped = false;
-
- if (strip_vlan) {
- pkt->vlan_stripped = eth_strip_vlan(data, pkt->ehdr_buf, &ploff, &tci);
- }
-
- if (pkt->vlan_stripped) {
- pkt->vec[0].iov_base = pkt->ehdr_buf;
- pkt->vec[0].iov_len = ploff - sizeof(struct vlan_header);
- pkt->vec[1].iov_base = (uint8_t *) data + ploff;
- pkt->vec[1].iov_len = len - ploff;
- pkt->vec_len = 2;
- pkt->tot_len = len - ploff + sizeof(struct eth_header);
- } else {
- pkt->vec[0].iov_base = (void *)data;
- pkt->vec[0].iov_len = len;
- pkt->vec_len = 1;
- pkt->tot_len = len;
- }
-
- pkt->tci = tci;
-}
-
-void vmxnet_rx_pkt_dump(struct VmxnetRxPkt *pkt)
-{
-#ifdef VMXNET_RX_PKT_DEBUG
- VmxnetRxPkt *pkt = (VmxnetRxPkt *)pkt;
- assert(pkt);
-
- printf("RX PKT: tot_len: %d, vlan_stripped: %d, vlan_tag: %d\n",
- pkt->tot_len, pkt->vlan_stripped, pkt->tci);
-#endif
-}
-
-void vmxnet_rx_pkt_set_packet_type(struct VmxnetRxPkt *pkt,
- eth_pkt_types_e packet_type)
-{
- assert(pkt);
-
- pkt->packet_type = packet_type;
-
-}
-
-eth_pkt_types_e vmxnet_rx_pkt_get_packet_type(struct VmxnetRxPkt *pkt)
-{
- assert(pkt);
-
- return pkt->packet_type;
-}
-
-size_t vmxnet_rx_pkt_get_total_len(struct VmxnetRxPkt *pkt)
-{
- assert(pkt);
-
- return pkt->tot_len;
-}
-
-void vmxnet_rx_pkt_set_protocols(struct VmxnetRxPkt *pkt, const void *data,
- size_t len)
-{
- assert(pkt);
-
- eth_get_protocols(data, len, &pkt->isip4, &pkt->isip6,
- &pkt->isudp, &pkt->istcp);
-}
-
-void vmxnet_rx_pkt_get_protocols(struct VmxnetRxPkt *pkt,
- bool *isip4, bool *isip6,
- bool *isudp, bool *istcp)
-{
- assert(pkt);
-
- *isip4 = pkt->isip4;
- *isip6 = pkt->isip6;
- *isudp = pkt->isudp;
- *istcp = pkt->istcp;
-}
-
-struct iovec *vmxnet_rx_pkt_get_iovec(struct VmxnetRxPkt *pkt)
-{
- assert(pkt);
-
- return pkt->vec;
-}
-
-void vmxnet_rx_pkt_set_vhdr(struct VmxnetRxPkt *pkt,
- struct virtio_net_hdr *vhdr)
-{
- assert(pkt);
-
- memcpy(&pkt->virt_hdr, vhdr, sizeof pkt->virt_hdr);
-}
-
-bool vmxnet_rx_pkt_is_vlan_stripped(struct VmxnetRxPkt *pkt)
-{
- assert(pkt);
-
- return pkt->vlan_stripped;
-}
-
-bool vmxnet_rx_pkt_has_virt_hdr(struct VmxnetRxPkt *pkt)
-{
- assert(pkt);
-
- return pkt->has_virt_hdr;
-}
-
-uint16_t vmxnet_rx_pkt_get_vlan_tag(struct VmxnetRxPkt *pkt)
-{
- assert(pkt);
-
- return pkt->tci;
-}
diff --git a/qemu/hw/net/vmxnet_rx_pkt.h b/qemu/hw/net/vmxnet_rx_pkt.h
deleted file mode 100644
index 0a45c1ba0..000000000
--- a/qemu/hw/net/vmxnet_rx_pkt.h
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * QEMU VMWARE VMXNET* paravirtual NICs - RX packets abstraction
- *
- * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com)
- *
- * Developed by Daynix Computing LTD (http://www.daynix.com)
- *
- * Authors:
- * Dmitry Fleytman <dmitry@daynix.com>
- * Tamir Shomer <tamirs@daynix.com>
- * Yan Vugenfirer <yan@daynix.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#ifndef VMXNET_RX_PKT_H
-#define VMXNET_RX_PKT_H
-
-#include "net/eth.h"
-
-/* defines to enable packet dump functions */
-/*#define VMXNET_RX_PKT_DEBUG*/
-
-struct VmxnetRxPkt;
-
-/**
- * Clean all rx packet resources
- *
- * @pkt: packet
- *
- */
-void vmxnet_rx_pkt_uninit(struct VmxnetRxPkt *pkt);
-
-/**
- * Init function for rx packet functionality
- *
- * @pkt: packet pointer
- * @has_virt_hdr: device uses virtio header
- *
- */
-void vmxnet_rx_pkt_init(struct VmxnetRxPkt **pkt, bool has_virt_hdr);
-
-/**
- * returns total length of data attached to rx context
- *
- * @pkt: packet
- *
- * Return: nothing
- *
- */
-size_t vmxnet_rx_pkt_get_total_len(struct VmxnetRxPkt *pkt);
-
-/**
- * parse and set packet analysis results
- *
- * @pkt: packet
- * @data: pointer to the data buffer to be parsed
- * @len: data length
- *
- */
-void vmxnet_rx_pkt_set_protocols(struct VmxnetRxPkt *pkt, const void *data,
- size_t len);
-
-/**
- * fetches packet analysis results
- *
- * @pkt: packet
- * @isip4: whether the packet given is IPv4
- * @isip6: whether the packet given is IPv6
- * @isudp: whether the packet given is UDP
- * @istcp: whether the packet given is TCP
- *
- */
-void vmxnet_rx_pkt_get_protocols(struct VmxnetRxPkt *pkt,
- bool *isip4, bool *isip6,
- bool *isudp, bool *istcp);
-
-/**
- * returns virtio header stored in rx context
- *
- * @pkt: packet
- * @ret: virtio header
- *
- */
-struct virtio_net_hdr *vmxnet_rx_pkt_get_vhdr(struct VmxnetRxPkt *pkt);
-
-/**
- * returns packet type
- *
- * @pkt: packet
- * @ret: packet type
- *
- */
-eth_pkt_types_e vmxnet_rx_pkt_get_packet_type(struct VmxnetRxPkt *pkt);
-
-/**
- * returns vlan tag
- *
- * @pkt: packet
- * @ret: VLAN tag
- *
- */
-uint16_t vmxnet_rx_pkt_get_vlan_tag(struct VmxnetRxPkt *pkt);
-
-/**
- * tells whether vlan was stripped from the packet
- *
- * @pkt: packet
- * @ret: VLAN stripped sign
- *
- */
-bool vmxnet_rx_pkt_is_vlan_stripped(struct VmxnetRxPkt *pkt);
-
-/**
- * notifies caller if the packet has virtio header
- *
- * @pkt: packet
- * @ret: true if packet has virtio header, false otherwize
- *
- */
-bool vmxnet_rx_pkt_has_virt_hdr(struct VmxnetRxPkt *pkt);
-
-/**
- * attach data to rx packet
- *
- * @pkt: packet
- * @data: pointer to the data buffer
- * @len: data length
- * @strip_vlan: should the module strip vlan from data
- *
- */
-void vmxnet_rx_pkt_attach_data(struct VmxnetRxPkt *pkt, const void *data,
- size_t len, bool strip_vlan);
-
-/**
- * returns io vector that holds the attached data
- *
- * @pkt: packet
- * @ret: pointer to IOVec
- *
- */
-struct iovec *vmxnet_rx_pkt_get_iovec(struct VmxnetRxPkt *pkt);
-
-/**
- * prints rx packet data if debug is enabled
- *
- * @pkt: packet
- *
- */
-void vmxnet_rx_pkt_dump(struct VmxnetRxPkt *pkt);
-
-/**
- * copy passed vhdr data to packet context
- *
- * @pkt: packet
- * @vhdr: VHDR buffer
- *
- */
-void vmxnet_rx_pkt_set_vhdr(struct VmxnetRxPkt *pkt,
- struct virtio_net_hdr *vhdr);
-
-/**
- * save packet type in packet context
- *
- * @pkt: packet
- * @packet_type: the packet type
- *
- */
-void vmxnet_rx_pkt_set_packet_type(struct VmxnetRxPkt *pkt,
- eth_pkt_types_e packet_type);
-
-#endif
diff --git a/qemu/hw/net/vmxnet_tx_pkt.c b/qemu/hw/net/vmxnet_tx_pkt.c
deleted file mode 100644
index 91e1e08fd..000000000
--- a/qemu/hw/net/vmxnet_tx_pkt.c
+++ /dev/null
@@ -1,581 +0,0 @@
-/*
- * QEMU VMWARE VMXNET* paravirtual NICs - TX packets abstractions
- *
- * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com)
- *
- * Developed by Daynix Computing LTD (http://www.daynix.com)
- *
- * Authors:
- * Dmitry Fleytman <dmitry@daynix.com>
- * Tamir Shomer <tamirs@daynix.com>
- * Yan Vugenfirer <yan@daynix.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "vmxnet_tx_pkt.h"
-#include "net/eth.h"
-#include "qemu-common.h"
-#include "qemu/iov.h"
-#include "net/checksum.h"
-#include "net/tap.h"
-#include "net/net.h"
-
-enum {
- VMXNET_TX_PKT_VHDR_FRAG = 0,
- VMXNET_TX_PKT_L2HDR_FRAG,
- VMXNET_TX_PKT_L3HDR_FRAG,
- VMXNET_TX_PKT_PL_START_FRAG
-};
-
-/* TX packet private context */
-struct VmxnetTxPkt {
- struct virtio_net_hdr virt_hdr;
- bool has_virt_hdr;
-
- struct iovec *raw;
- uint32_t raw_frags;
- uint32_t max_raw_frags;
-
- struct iovec *vec;
-
- uint8_t l2_hdr[ETH_MAX_L2_HDR_LEN];
-
- uint32_t payload_len;
-
- uint32_t payload_frags;
- uint32_t max_payload_frags;
-
- uint16_t hdr_len;
- eth_pkt_types_e packet_type;
- uint8_t l4proto;
-};
-
-void vmxnet_tx_pkt_init(struct VmxnetTxPkt **pkt, uint32_t max_frags,
- bool has_virt_hdr)
-{
- struct VmxnetTxPkt *p = g_malloc0(sizeof *p);
-
- p->vec = g_malloc((sizeof *p->vec) *
- (max_frags + VMXNET_TX_PKT_PL_START_FRAG));
-
- p->raw = g_malloc((sizeof *p->raw) * max_frags);
-
- p->max_payload_frags = max_frags;
- p->max_raw_frags = max_frags;
- p->has_virt_hdr = has_virt_hdr;
- p->vec[VMXNET_TX_PKT_VHDR_FRAG].iov_base = &p->virt_hdr;
- p->vec[VMXNET_TX_PKT_VHDR_FRAG].iov_len =
- p->has_virt_hdr ? sizeof p->virt_hdr : 0;
- p->vec[VMXNET_TX_PKT_L2HDR_FRAG].iov_base = &p->l2_hdr;
- p->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_base = NULL;
- p->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_len = 0;
-
- *pkt = p;
-}
-
-void vmxnet_tx_pkt_uninit(struct VmxnetTxPkt *pkt)
-{
- if (pkt) {
- g_free(pkt->vec);
- g_free(pkt->raw);
- g_free(pkt);
- }
-}
-
-void vmxnet_tx_pkt_update_ip_checksums(struct VmxnetTxPkt *pkt)
-{
- uint16_t csum;
- uint32_t ph_raw_csum;
- assert(pkt);
- uint8_t gso_type = pkt->virt_hdr.gso_type & ~VIRTIO_NET_HDR_GSO_ECN;
- struct ip_header *ip_hdr;
-
- if (VIRTIO_NET_HDR_GSO_TCPV4 != gso_type &&
- VIRTIO_NET_HDR_GSO_UDP != gso_type) {
- return;
- }
-
- ip_hdr = pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_base;
-
- if (pkt->payload_len + pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_len >
- ETH_MAX_IP_DGRAM_LEN) {
- return;
- }
-
- ip_hdr->ip_len = cpu_to_be16(pkt->payload_len +
- pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_len);
-
- /* Calculate IP header checksum */
- ip_hdr->ip_sum = 0;
- csum = net_raw_checksum((uint8_t *)ip_hdr,
- pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_len);
- ip_hdr->ip_sum = cpu_to_be16(csum);
-
- /* Calculate IP pseudo header checksum */
- ph_raw_csum = eth_calc_pseudo_hdr_csum(ip_hdr, pkt->payload_len);
- csum = cpu_to_be16(~net_checksum_finish(ph_raw_csum));
- iov_from_buf(&pkt->vec[VMXNET_TX_PKT_PL_START_FRAG], pkt->payload_frags,
- pkt->virt_hdr.csum_offset, &csum, sizeof(csum));
-}
-
-static void vmxnet_tx_pkt_calculate_hdr_len(struct VmxnetTxPkt *pkt)
-{
- pkt->hdr_len = pkt->vec[VMXNET_TX_PKT_L2HDR_FRAG].iov_len +
- pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_len;
-}
-
-static bool vmxnet_tx_pkt_parse_headers(struct VmxnetTxPkt *pkt)
-{
- struct iovec *l2_hdr, *l3_hdr;
- size_t bytes_read;
- size_t full_ip6hdr_len;
- uint16_t l3_proto;
-
- assert(pkt);
-
- l2_hdr = &pkt->vec[VMXNET_TX_PKT_L2HDR_FRAG];
- l3_hdr = &pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG];
-
- bytes_read = iov_to_buf(pkt->raw, pkt->raw_frags, 0, l2_hdr->iov_base,
- ETH_MAX_L2_HDR_LEN);
- if (bytes_read < sizeof(struct eth_header)) {
- l2_hdr->iov_len = 0;
- return false;
- }
-
- l2_hdr->iov_len = sizeof(struct eth_header);
- switch (be16_to_cpu(PKT_GET_ETH_HDR(l2_hdr->iov_base)->h_proto)) {
- case ETH_P_VLAN:
- l2_hdr->iov_len += sizeof(struct vlan_header);
- break;
- case ETH_P_DVLAN:
- l2_hdr->iov_len += 2 * sizeof(struct vlan_header);
- break;
- }
-
- if (bytes_read < l2_hdr->iov_len) {
- l2_hdr->iov_len = 0;
- return false;
- }
-
- l3_proto = eth_get_l3_proto(l2_hdr->iov_base, l2_hdr->iov_len);
-
- switch (l3_proto) {
- case ETH_P_IP:
- l3_hdr->iov_base = g_malloc(ETH_MAX_IP4_HDR_LEN);
-
- bytes_read = iov_to_buf(pkt->raw, pkt->raw_frags, l2_hdr->iov_len,
- l3_hdr->iov_base, sizeof(struct ip_header));
-
- if (bytes_read < sizeof(struct ip_header)) {
- l3_hdr->iov_len = 0;
- return false;
- }
-
- l3_hdr->iov_len = IP_HDR_GET_LEN(l3_hdr->iov_base);
- pkt->l4proto = ((struct ip_header *) l3_hdr->iov_base)->ip_p;
-
- /* copy optional IPv4 header data */
- bytes_read = iov_to_buf(pkt->raw, pkt->raw_frags,
- l2_hdr->iov_len + sizeof(struct ip_header),
- l3_hdr->iov_base + sizeof(struct ip_header),
- l3_hdr->iov_len - sizeof(struct ip_header));
- if (bytes_read < l3_hdr->iov_len - sizeof(struct ip_header)) {
- l3_hdr->iov_len = 0;
- return false;
- }
- break;
-
- case ETH_P_IPV6:
- if (!eth_parse_ipv6_hdr(pkt->raw, pkt->raw_frags, l2_hdr->iov_len,
- &pkt->l4proto, &full_ip6hdr_len)) {
- l3_hdr->iov_len = 0;
- return false;
- }
-
- l3_hdr->iov_base = g_malloc(full_ip6hdr_len);
-
- bytes_read = iov_to_buf(pkt->raw, pkt->raw_frags, l2_hdr->iov_len,
- l3_hdr->iov_base, full_ip6hdr_len);
-
- if (bytes_read < full_ip6hdr_len) {
- l3_hdr->iov_len = 0;
- return false;
- } else {
- l3_hdr->iov_len = full_ip6hdr_len;
- }
- break;
-
- default:
- l3_hdr->iov_len = 0;
- break;
- }
-
- vmxnet_tx_pkt_calculate_hdr_len(pkt);
- pkt->packet_type = get_eth_packet_type(l2_hdr->iov_base);
- return true;
-}
-
-static bool vmxnet_tx_pkt_rebuild_payload(struct VmxnetTxPkt *pkt)
-{
- size_t payload_len = iov_size(pkt->raw, pkt->raw_frags) - pkt->hdr_len;
-
- pkt->payload_frags = iov_copy(&pkt->vec[VMXNET_TX_PKT_PL_START_FRAG],
- pkt->max_payload_frags,
- pkt->raw, pkt->raw_frags,
- pkt->hdr_len, payload_len);
-
- if (pkt->payload_frags != (uint32_t) -1) {
- pkt->payload_len = payload_len;
- return true;
- } else {
- return false;
- }
-}
-
-bool vmxnet_tx_pkt_parse(struct VmxnetTxPkt *pkt)
-{
- return vmxnet_tx_pkt_parse_headers(pkt) &&
- vmxnet_tx_pkt_rebuild_payload(pkt);
-}
-
-struct virtio_net_hdr *vmxnet_tx_pkt_get_vhdr(struct VmxnetTxPkt *pkt)
-{
- assert(pkt);
- return &pkt->virt_hdr;
-}
-
-static uint8_t vmxnet_tx_pkt_get_gso_type(struct VmxnetTxPkt *pkt,
- bool tso_enable)
-{
- uint8_t rc = VIRTIO_NET_HDR_GSO_NONE;
- uint16_t l3_proto;
-
- l3_proto = eth_get_l3_proto(pkt->vec[VMXNET_TX_PKT_L2HDR_FRAG].iov_base,
- pkt->vec[VMXNET_TX_PKT_L2HDR_FRAG].iov_len);
-
- if (!tso_enable) {
- goto func_exit;
- }
-
- rc = eth_get_gso_type(l3_proto, pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_base,
- pkt->l4proto);
-
-func_exit:
- return rc;
-}
-
-void vmxnet_tx_pkt_build_vheader(struct VmxnetTxPkt *pkt, bool tso_enable,
- bool csum_enable, uint32_t gso_size)
-{
- struct tcp_hdr l4hdr;
- assert(pkt);
-
- /* csum has to be enabled if tso is. */
- assert(csum_enable || !tso_enable);
-
- pkt->virt_hdr.gso_type = vmxnet_tx_pkt_get_gso_type(pkt, tso_enable);
-
- switch (pkt->virt_hdr.gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {
- case VIRTIO_NET_HDR_GSO_NONE:
- pkt->virt_hdr.hdr_len = 0;
- pkt->virt_hdr.gso_size = 0;
- break;
-
- case VIRTIO_NET_HDR_GSO_UDP:
- pkt->virt_hdr.gso_size = IP_FRAG_ALIGN_SIZE(gso_size);
- pkt->virt_hdr.hdr_len = pkt->hdr_len + sizeof(struct udp_header);
- break;
-
- case VIRTIO_NET_HDR_GSO_TCPV4:
- case VIRTIO_NET_HDR_GSO_TCPV6:
- iov_to_buf(&pkt->vec[VMXNET_TX_PKT_PL_START_FRAG], pkt->payload_frags,
- 0, &l4hdr, sizeof(l4hdr));
- pkt->virt_hdr.hdr_len = pkt->hdr_len + l4hdr.th_off * sizeof(uint32_t);
- pkt->virt_hdr.gso_size = IP_FRAG_ALIGN_SIZE(gso_size);
- break;
-
- default:
- g_assert_not_reached();
- }
-
- if (csum_enable) {
- switch (pkt->l4proto) {
- case IP_PROTO_TCP:
- pkt->virt_hdr.flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
- pkt->virt_hdr.csum_start = pkt->hdr_len;
- pkt->virt_hdr.csum_offset = offsetof(struct tcp_hdr, th_sum);
- break;
- case IP_PROTO_UDP:
- pkt->virt_hdr.flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
- pkt->virt_hdr.csum_start = pkt->hdr_len;
- pkt->virt_hdr.csum_offset = offsetof(struct udp_hdr, uh_sum);
- break;
- default:
- break;
- }
- }
-}
-
-void vmxnet_tx_pkt_setup_vlan_header(struct VmxnetTxPkt *pkt, uint16_t vlan)
-{
- bool is_new;
- assert(pkt);
-
- eth_setup_vlan_headers(pkt->vec[VMXNET_TX_PKT_L2HDR_FRAG].iov_base,
- vlan, &is_new);
-
- /* update l2hdrlen */
- if (is_new) {
- pkt->hdr_len += sizeof(struct vlan_header);
- pkt->vec[VMXNET_TX_PKT_L2HDR_FRAG].iov_len +=
- sizeof(struct vlan_header);
- }
-}
-
-bool vmxnet_tx_pkt_add_raw_fragment(struct VmxnetTxPkt *pkt, hwaddr pa,
- size_t len)
-{
- hwaddr mapped_len = 0;
- struct iovec *ventry;
- assert(pkt);
- assert(pkt->max_raw_frags > pkt->raw_frags);
-
- if (!len) {
- return true;
- }
-
- ventry = &pkt->raw[pkt->raw_frags];
- mapped_len = len;
-
- ventry->iov_base = cpu_physical_memory_map(pa, &mapped_len, false);
- ventry->iov_len = mapped_len;
- pkt->raw_frags += !!ventry->iov_base;
-
- if ((ventry->iov_base == NULL) || (len != mapped_len)) {
- return false;
- }
-
- return true;
-}
-
-eth_pkt_types_e vmxnet_tx_pkt_get_packet_type(struct VmxnetTxPkt *pkt)
-{
- assert(pkt);
-
- return pkt->packet_type;
-}
-
-size_t vmxnet_tx_pkt_get_total_len(struct VmxnetTxPkt *pkt)
-{
- assert(pkt);
-
- return pkt->hdr_len + pkt->payload_len;
-}
-
-void vmxnet_tx_pkt_dump(struct VmxnetTxPkt *pkt)
-{
-#ifdef VMXNET_TX_PKT_DEBUG
- assert(pkt);
-
- printf("TX PKT: hdr_len: %d, pkt_type: 0x%X, l2hdr_len: %lu, "
- "l3hdr_len: %lu, payload_len: %u\n", pkt->hdr_len, pkt->packet_type,
- pkt->vec[VMXNET_TX_PKT_L2HDR_FRAG].iov_len,
- pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_len, pkt->payload_len);
-#endif
-}
-
-void vmxnet_tx_pkt_reset(struct VmxnetTxPkt *pkt)
-{
- int i;
-
- /* no assert, as reset can be called before tx_pkt_init */
- if (!pkt) {
- return;
- }
-
- memset(&pkt->virt_hdr, 0, sizeof(pkt->virt_hdr));
-
- g_free(pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_base);
- pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_base = NULL;
-
- assert(pkt->vec);
- for (i = VMXNET_TX_PKT_L2HDR_FRAG;
- i < pkt->payload_frags + VMXNET_TX_PKT_PL_START_FRAG; i++) {
- pkt->vec[i].iov_len = 0;
- }
- pkt->payload_len = 0;
- pkt->payload_frags = 0;
-
- assert(pkt->raw);
- for (i = 0; i < pkt->raw_frags; i++) {
- assert(pkt->raw[i].iov_base);
- cpu_physical_memory_unmap(pkt->raw[i].iov_base, pkt->raw[i].iov_len,
- false, pkt->raw[i].iov_len);
- pkt->raw[i].iov_len = 0;
- }
- pkt->raw_frags = 0;
-
- pkt->hdr_len = 0;
- pkt->packet_type = 0;
- pkt->l4proto = 0;
-}
-
-static void vmxnet_tx_pkt_do_sw_csum(struct VmxnetTxPkt *pkt)
-{
- struct iovec *iov = &pkt->vec[VMXNET_TX_PKT_L2HDR_FRAG];
- uint32_t csum_cntr;
- uint16_t csum = 0;
- /* num of iovec without vhdr */
- uint32_t iov_len = pkt->payload_frags + VMXNET_TX_PKT_PL_START_FRAG - 1;
- uint16_t csl;
- struct ip_header *iphdr;
- size_t csum_offset = pkt->virt_hdr.csum_start + pkt->virt_hdr.csum_offset;
-
- /* Put zero to checksum field */
- iov_from_buf(iov, iov_len, csum_offset, &csum, sizeof csum);
-
- /* Calculate L4 TCP/UDP checksum */
- csl = pkt->payload_len;
-
- /* data checksum */
- csum_cntr =
- net_checksum_add_iov(iov, iov_len, pkt->virt_hdr.csum_start, csl);
- /* add pseudo header to csum */
- iphdr = pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_base;
- csum_cntr += eth_calc_pseudo_hdr_csum(iphdr, csl);
-
- /* Put the checksum obtained into the packet */
- csum = cpu_to_be16(net_checksum_finish(csum_cntr));
- iov_from_buf(iov, iov_len, csum_offset, &csum, sizeof csum);
-}
-
-enum {
- VMXNET_TX_PKT_FRAGMENT_L2_HDR_POS = 0,
- VMXNET_TX_PKT_FRAGMENT_L3_HDR_POS,
- VMXNET_TX_PKT_FRAGMENT_HEADER_NUM
-};
-
-#define VMXNET_MAX_FRAG_SG_LIST (64)
-
-static size_t vmxnet_tx_pkt_fetch_fragment(struct VmxnetTxPkt *pkt,
- int *src_idx, size_t *src_offset, struct iovec *dst, int *dst_idx)
-{
- size_t fetched = 0;
- struct iovec *src = pkt->vec;
-
- *dst_idx = VMXNET_TX_PKT_FRAGMENT_HEADER_NUM;
-
- while (fetched < pkt->virt_hdr.gso_size) {
-
- /* no more place in fragment iov */
- if (*dst_idx == VMXNET_MAX_FRAG_SG_LIST) {
- break;
- }
-
- /* no more data in iovec */
- if (*src_idx == (pkt->payload_frags + VMXNET_TX_PKT_PL_START_FRAG)) {
- break;
- }
-
-
- dst[*dst_idx].iov_base = src[*src_idx].iov_base + *src_offset;
- dst[*dst_idx].iov_len = MIN(src[*src_idx].iov_len - *src_offset,
- pkt->virt_hdr.gso_size - fetched);
-
- *src_offset += dst[*dst_idx].iov_len;
- fetched += dst[*dst_idx].iov_len;
-
- if (*src_offset == src[*src_idx].iov_len) {
- *src_offset = 0;
- (*src_idx)++;
- }
-
- (*dst_idx)++;
- }
-
- return fetched;
-}
-
-static bool vmxnet_tx_pkt_do_sw_fragmentation(struct VmxnetTxPkt *pkt,
- NetClientState *nc)
-{
- struct iovec fragment[VMXNET_MAX_FRAG_SG_LIST];
- size_t fragment_len = 0;
- bool more_frags = false;
-
- /* some pointers for shorter code */
- void *l2_iov_base, *l3_iov_base;
- size_t l2_iov_len, l3_iov_len;
- int src_idx = VMXNET_TX_PKT_PL_START_FRAG, dst_idx;
- size_t src_offset = 0;
- size_t fragment_offset = 0;
-
- l2_iov_base = pkt->vec[VMXNET_TX_PKT_L2HDR_FRAG].iov_base;
- l2_iov_len = pkt->vec[VMXNET_TX_PKT_L2HDR_FRAG].iov_len;
- l3_iov_base = pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_base;
- l3_iov_len = pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_len;
-
- /* Copy headers */
- fragment[VMXNET_TX_PKT_FRAGMENT_L2_HDR_POS].iov_base = l2_iov_base;
- fragment[VMXNET_TX_PKT_FRAGMENT_L2_HDR_POS].iov_len = l2_iov_len;
- fragment[VMXNET_TX_PKT_FRAGMENT_L3_HDR_POS].iov_base = l3_iov_base;
- fragment[VMXNET_TX_PKT_FRAGMENT_L3_HDR_POS].iov_len = l3_iov_len;
-
-
- /* Put as much data as possible and send */
- do {
- fragment_len = vmxnet_tx_pkt_fetch_fragment(pkt, &src_idx, &src_offset,
- fragment, &dst_idx);
-
- more_frags = (fragment_offset + fragment_len < pkt->payload_len);
-
- eth_setup_ip4_fragmentation(l2_iov_base, l2_iov_len, l3_iov_base,
- l3_iov_len, fragment_len, fragment_offset, more_frags);
-
- eth_fix_ip4_checksum(l3_iov_base, l3_iov_len);
-
- qemu_sendv_packet(nc, fragment, dst_idx);
-
- fragment_offset += fragment_len;
-
- } while (more_frags);
-
- return true;
-}
-
-bool vmxnet_tx_pkt_send(struct VmxnetTxPkt *pkt, NetClientState *nc)
-{
- assert(pkt);
-
- if (!pkt->has_virt_hdr &&
- pkt->virt_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
- vmxnet_tx_pkt_do_sw_csum(pkt);
- }
-
- /*
- * Since underlying infrastructure does not support IP datagrams longer
- * than 64K we should drop such packets and don't even try to send
- */
- if (VIRTIO_NET_HDR_GSO_NONE != pkt->virt_hdr.gso_type) {
- if (pkt->payload_len >
- ETH_MAX_IP_DGRAM_LEN -
- pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_len) {
- return false;
- }
- }
-
- if (pkt->has_virt_hdr ||
- pkt->virt_hdr.gso_type == VIRTIO_NET_HDR_GSO_NONE) {
- qemu_sendv_packet(nc, pkt->vec,
- pkt->payload_frags + VMXNET_TX_PKT_PL_START_FRAG);
- return true;
- }
-
- return vmxnet_tx_pkt_do_sw_fragmentation(pkt, nc);
-}
diff --git a/qemu/hw/net/vmxnet_tx_pkt.h b/qemu/hw/net/vmxnet_tx_pkt.h
deleted file mode 100644
index f51e98ad9..000000000
--- a/qemu/hw/net/vmxnet_tx_pkt.h
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * QEMU VMWARE VMXNET* paravirtual NICs - TX packets abstraction
- *
- * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com)
- *
- * Developed by Daynix Computing LTD (http://www.daynix.com)
- *
- * Authors:
- * Dmitry Fleytman <dmitry@daynix.com>
- * Tamir Shomer <tamirs@daynix.com>
- * Yan Vugenfirer <yan@daynix.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#ifndef VMXNET_TX_PKT_H
-#define VMXNET_TX_PKT_H
-
-#include "net/eth.h"
-#include "exec/hwaddr.h"
-
-/* define to enable packet dump functions */
-/*#define VMXNET_TX_PKT_DEBUG*/
-
-struct VmxnetTxPkt;
-
-/**
- * Init function for tx packet functionality
- *
- * @pkt: packet pointer
- * @max_frags: max tx ip fragments
- * @has_virt_hdr: device uses virtio header.
- */
-void vmxnet_tx_pkt_init(struct VmxnetTxPkt **pkt, uint32_t max_frags,
- bool has_virt_hdr);
-
-/**
- * Clean all tx packet resources.
- *
- * @pkt: packet.
- */
-void vmxnet_tx_pkt_uninit(struct VmxnetTxPkt *pkt);
-
-/**
- * get virtio header
- *
- * @pkt: packet
- * @ret: virtio header
- */
-struct virtio_net_hdr *vmxnet_tx_pkt_get_vhdr(struct VmxnetTxPkt *pkt);
-
-/**
- * build virtio header (will be stored in module context)
- *
- * @pkt: packet
- * @tso_enable: TSO enabled
- * @csum_enable: CSO enabled
- * @gso_size: MSS size for TSO
- *
- */
-void vmxnet_tx_pkt_build_vheader(struct VmxnetTxPkt *pkt, bool tso_enable,
- bool csum_enable, uint32_t gso_size);
-
-/**
- * updates vlan tag, and adds vlan header in case it is missing
- *
- * @pkt: packet
- * @vlan: VLAN tag
- *
- */
-void vmxnet_tx_pkt_setup_vlan_header(struct VmxnetTxPkt *pkt, uint16_t vlan);
-
-/**
- * populate data fragment into pkt context.
- *
- * @pkt: packet
- * @pa: physical address of fragment
- * @len: length of fragment
- *
- */
-bool vmxnet_tx_pkt_add_raw_fragment(struct VmxnetTxPkt *pkt, hwaddr pa,
- size_t len);
-
-/**
- * fix ip header fields and calculate checksums needed.
- *
- * @pkt: packet
- *
- */
-void vmxnet_tx_pkt_update_ip_checksums(struct VmxnetTxPkt *pkt);
-
-/**
- * get length of all populated data.
- *
- * @pkt: packet
- * @ret: total data length
- *
- */
-size_t vmxnet_tx_pkt_get_total_len(struct VmxnetTxPkt *pkt);
-
-/**
- * get packet type
- *
- * @pkt: packet
- * @ret: packet type
- *
- */
-eth_pkt_types_e vmxnet_tx_pkt_get_packet_type(struct VmxnetTxPkt *pkt);
-
-/**
- * prints packet data if debug is enabled
- *
- * @pkt: packet
- *
- */
-void vmxnet_tx_pkt_dump(struct VmxnetTxPkt *pkt);
-
-/**
- * reset tx packet private context (needed to be called between packets)
- *
- * @pkt: packet
- *
- */
-void vmxnet_tx_pkt_reset(struct VmxnetTxPkt *pkt);
-
-/**
- * Send packet to qemu. handles sw offloads if vhdr is not supported.
- *
- * @pkt: packet
- * @nc: NetClientState
- * @ret: operation result
- *
- */
-bool vmxnet_tx_pkt_send(struct VmxnetTxPkt *pkt, NetClientState *nc);
-
-/**
- * parse raw packet data and analyze offload requirements.
- *
- * @pkt: packet
- *
- */
-bool vmxnet_tx_pkt_parse(struct VmxnetTxPkt *pkt);
-
-#endif
diff --git a/qemu/hw/net/xen_nic.c b/qemu/hw/net/xen_nic.c
deleted file mode 100644
index 7281730d9..000000000
--- a/qemu/hw/net/xen_nic.c
+++ /dev/null
@@ -1,412 +0,0 @@
-/*
- * xen paravirt network card backend
- *
- * (c) Gerd Hoffmann <kraxel@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; under version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <sys/wait.h>
-
-#include "hw/hw.h"
-#include "net/net.h"
-#include "net/checksum.h"
-#include "net/util.h"
-#include "hw/xen/xen_backend.h"
-
-#include <xen/io/netif.h>
-
-/* ------------------------------------------------------------- */
-
-struct XenNetDev {
- struct XenDevice xendev; /* must be first */
- char *mac;
- int tx_work;
- int tx_ring_ref;
- int rx_ring_ref;
- struct netif_tx_sring *txs;
- struct netif_rx_sring *rxs;
- netif_tx_back_ring_t tx_ring;
- netif_rx_back_ring_t rx_ring;
- NICConf conf;
- NICState *nic;
-};
-
-/* ------------------------------------------------------------- */
-
-static void net_tx_response(struct XenNetDev *netdev, netif_tx_request_t *txp, int8_t st)
-{
- RING_IDX i = netdev->tx_ring.rsp_prod_pvt;
- netif_tx_response_t *resp;
- int notify;
-
- resp = RING_GET_RESPONSE(&netdev->tx_ring, i);
- resp->id = txp->id;
- resp->status = st;
-
-#if 0
- if (txp->flags & NETTXF_extra_info) {
- RING_GET_RESPONSE(&netdev->tx_ring, ++i)->status = NETIF_RSP_NULL;
- }
-#endif
-
- netdev->tx_ring.rsp_prod_pvt = ++i;
- RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netdev->tx_ring, notify);
- if (notify) {
- xen_be_send_notify(&netdev->xendev);
- }
-
- if (i == netdev->tx_ring.req_cons) {
- int more_to_do;
- RING_FINAL_CHECK_FOR_REQUESTS(&netdev->tx_ring, more_to_do);
- if (more_to_do) {
- netdev->tx_work++;
- }
- }
-}
-
-static void net_tx_error(struct XenNetDev *netdev, netif_tx_request_t *txp, RING_IDX end)
-{
-#if 0
- /*
- * Hmm, why netback fails everything in the ring?
- * Should we do that even when not supporting SG and TSO?
- */
- RING_IDX cons = netdev->tx_ring.req_cons;
-
- do {
- make_tx_response(netif, txp, NETIF_RSP_ERROR);
- if (cons >= end) {
- break;
- }
- txp = RING_GET_REQUEST(&netdev->tx_ring, cons++);
- } while (1);
- netdev->tx_ring.req_cons = cons;
- netif_schedule_work(netif);
- netif_put(netif);
-#else
- net_tx_response(netdev, txp, NETIF_RSP_ERROR);
-#endif
-}
-
-static void net_tx_packets(struct XenNetDev *netdev)
-{
- netif_tx_request_t txreq;
- RING_IDX rc, rp;
- void *page;
- void *tmpbuf = NULL;
-
- for (;;) {
- rc = netdev->tx_ring.req_cons;
- rp = netdev->tx_ring.sring->req_prod;
- xen_rmb(); /* Ensure we see queued requests up to 'rp'. */
-
- while ((rc != rp)) {
- if (RING_REQUEST_CONS_OVERFLOW(&netdev->tx_ring, rc)) {
- break;
- }
- memcpy(&txreq, RING_GET_REQUEST(&netdev->tx_ring, rc), sizeof(txreq));
- netdev->tx_ring.req_cons = ++rc;
-
-#if 1
- /* should not happen in theory, we don't announce the *
- * feature-{sg,gso,whatelse} flags in xenstore (yet?) */
- if (txreq.flags & NETTXF_extra_info) {
- xen_be_printf(&netdev->xendev, 0, "FIXME: extra info flag\n");
- net_tx_error(netdev, &txreq, rc);
- continue;
- }
- if (txreq.flags & NETTXF_more_data) {
- xen_be_printf(&netdev->xendev, 0, "FIXME: more data flag\n");
- net_tx_error(netdev, &txreq, rc);
- continue;
- }
-#endif
-
- if (txreq.size < 14) {
- xen_be_printf(&netdev->xendev, 0, "bad packet size: %d\n", txreq.size);
- net_tx_error(netdev, &txreq, rc);
- continue;
- }
-
- if ((txreq.offset + txreq.size) > XC_PAGE_SIZE) {
- xen_be_printf(&netdev->xendev, 0, "error: page crossing\n");
- net_tx_error(netdev, &txreq, rc);
- continue;
- }
-
- xen_be_printf(&netdev->xendev, 3, "tx packet ref %d, off %d, len %d, flags 0x%x%s%s%s%s\n",
- txreq.gref, txreq.offset, txreq.size, txreq.flags,
- (txreq.flags & NETTXF_csum_blank) ? " csum_blank" : "",
- (txreq.flags & NETTXF_data_validated) ? " data_validated" : "",
- (txreq.flags & NETTXF_more_data) ? " more_data" : "",
- (txreq.flags & NETTXF_extra_info) ? " extra_info" : "");
-
- page = xengnttab_map_grant_ref(netdev->xendev.gnttabdev,
- netdev->xendev.dom,
- txreq.gref, PROT_READ);
- if (page == NULL) {
- xen_be_printf(&netdev->xendev, 0, "error: tx gref dereference failed (%d)\n",
- txreq.gref);
- net_tx_error(netdev, &txreq, rc);
- continue;
- }
- if (txreq.flags & NETTXF_csum_blank) {
- /* have read-only mapping -> can't fill checksum in-place */
- if (!tmpbuf) {
- tmpbuf = g_malloc(XC_PAGE_SIZE);
- }
- memcpy(tmpbuf, page + txreq.offset, txreq.size);
- net_checksum_calculate(tmpbuf, txreq.size);
- qemu_send_packet(qemu_get_queue(netdev->nic), tmpbuf,
- txreq.size);
- } else {
- qemu_send_packet(qemu_get_queue(netdev->nic),
- page + txreq.offset, txreq.size);
- }
- xengnttab_unmap(netdev->xendev.gnttabdev, page, 1);
- net_tx_response(netdev, &txreq, NETIF_RSP_OKAY);
- }
- if (!netdev->tx_work) {
- break;
- }
- netdev->tx_work = 0;
- }
- g_free(tmpbuf);
-}
-
-/* ------------------------------------------------------------- */
-
-static void net_rx_response(struct XenNetDev *netdev,
- netif_rx_request_t *req, int8_t st,
- uint16_t offset, uint16_t size,
- uint16_t flags)
-{
- RING_IDX i = netdev->rx_ring.rsp_prod_pvt;
- netif_rx_response_t *resp;
- int notify;
-
- resp = RING_GET_RESPONSE(&netdev->rx_ring, i);
- resp->offset = offset;
- resp->flags = flags;
- resp->id = req->id;
- resp->status = (int16_t)size;
- if (st < 0) {
- resp->status = (int16_t)st;
- }
-
- xen_be_printf(&netdev->xendev, 3, "rx response: idx %d, status %d, flags 0x%x\n",
- i, resp->status, resp->flags);
-
- netdev->rx_ring.rsp_prod_pvt = ++i;
- RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netdev->rx_ring, notify);
- if (notify) {
- xen_be_send_notify(&netdev->xendev);
- }
-}
-
-#define NET_IP_ALIGN 2
-
-static ssize_t net_rx_packet(NetClientState *nc, const uint8_t *buf, size_t size)
-{
- struct XenNetDev *netdev = qemu_get_nic_opaque(nc);
- netif_rx_request_t rxreq;
- RING_IDX rc, rp;
- void *page;
-
- if (netdev->xendev.be_state != XenbusStateConnected) {
- return -1;
- }
-
- rc = netdev->rx_ring.req_cons;
- rp = netdev->rx_ring.sring->req_prod;
- xen_rmb(); /* Ensure we see queued requests up to 'rp'. */
-
- if (rc == rp || RING_REQUEST_CONS_OVERFLOW(&netdev->rx_ring, rc)) {
- return 0;
- }
- if (size > XC_PAGE_SIZE - NET_IP_ALIGN) {
- xen_be_printf(&netdev->xendev, 0, "packet too big (%lu > %ld)",
- (unsigned long)size, XC_PAGE_SIZE - NET_IP_ALIGN);
- return -1;
- }
-
- memcpy(&rxreq, RING_GET_REQUEST(&netdev->rx_ring, rc), sizeof(rxreq));
- netdev->rx_ring.req_cons = ++rc;
-
- page = xengnttab_map_grant_ref(netdev->xendev.gnttabdev,
- netdev->xendev.dom,
- rxreq.gref, PROT_WRITE);
- if (page == NULL) {
- xen_be_printf(&netdev->xendev, 0, "error: rx gref dereference failed (%d)\n",
- rxreq.gref);
- net_rx_response(netdev, &rxreq, NETIF_RSP_ERROR, 0, 0, 0);
- return -1;
- }
- memcpy(page + NET_IP_ALIGN, buf, size);
- xengnttab_unmap(netdev->xendev.gnttabdev, page, 1);
- net_rx_response(netdev, &rxreq, NETIF_RSP_OKAY, NET_IP_ALIGN, size, 0);
-
- return size;
-}
-
-/* ------------------------------------------------------------- */
-
-static NetClientInfo net_xen_info = {
- .type = NET_CLIENT_OPTIONS_KIND_NIC,
- .size = sizeof(NICState),
- .receive = net_rx_packet,
-};
-
-static int net_init(struct XenDevice *xendev)
-{
- struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
-
- /* read xenstore entries */
- if (netdev->mac == NULL) {
- netdev->mac = xenstore_read_be_str(&netdev->xendev, "mac");
- }
-
- /* do we have all we need? */
- if (netdev->mac == NULL) {
- return -1;
- }
-
- if (net_parse_macaddr(netdev->conf.macaddr.a, netdev->mac) < 0) {
- return -1;
- }
-
- netdev->nic = qemu_new_nic(&net_xen_info, &netdev->conf,
- "xen", NULL, netdev);
-
- snprintf(qemu_get_queue(netdev->nic)->info_str,
- sizeof(qemu_get_queue(netdev->nic)->info_str),
- "nic: xenbus vif macaddr=%s", netdev->mac);
-
- /* fill info */
- xenstore_write_be_int(&netdev->xendev, "feature-rx-copy", 1);
- xenstore_write_be_int(&netdev->xendev, "feature-rx-flip", 0);
-
- return 0;
-}
-
-static int net_connect(struct XenDevice *xendev)
-{
- struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
- int rx_copy;
-
- if (xenstore_read_fe_int(&netdev->xendev, "tx-ring-ref",
- &netdev->tx_ring_ref) == -1) {
- return -1;
- }
- if (xenstore_read_fe_int(&netdev->xendev, "rx-ring-ref",
- &netdev->rx_ring_ref) == -1) {
- return 1;
- }
- if (xenstore_read_fe_int(&netdev->xendev, "event-channel",
- &netdev->xendev.remote_port) == -1) {
- return -1;
- }
-
- if (xenstore_read_fe_int(&netdev->xendev, "request-rx-copy", &rx_copy) == -1) {
- rx_copy = 0;
- }
- if (rx_copy == 0) {
- xen_be_printf(&netdev->xendev, 0, "frontend doesn't support rx-copy.\n");
- return -1;
- }
-
- netdev->txs = xengnttab_map_grant_ref(netdev->xendev.gnttabdev,
- netdev->xendev.dom,
- netdev->tx_ring_ref,
- PROT_READ | PROT_WRITE);
- if (!netdev->txs) {
- return -1;
- }
- netdev->rxs = xengnttab_map_grant_ref(netdev->xendev.gnttabdev,
- netdev->xendev.dom,
- netdev->rx_ring_ref,
- PROT_READ | PROT_WRITE);
- if (!netdev->rxs) {
- xengnttab_unmap(netdev->xendev.gnttabdev, netdev->txs, 1);
- netdev->txs = NULL;
- return -1;
- }
- BACK_RING_INIT(&netdev->tx_ring, netdev->txs, XC_PAGE_SIZE);
- BACK_RING_INIT(&netdev->rx_ring, netdev->rxs, XC_PAGE_SIZE);
-
- xen_be_bind_evtchn(&netdev->xendev);
-
- xen_be_printf(&netdev->xendev, 1, "ok: tx-ring-ref %d, rx-ring-ref %d, "
- "remote port %d, local port %d\n",
- netdev->tx_ring_ref, netdev->rx_ring_ref,
- netdev->xendev.remote_port, netdev->xendev.local_port);
-
- net_tx_packets(netdev);
- return 0;
-}
-
-static void net_disconnect(struct XenDevice *xendev)
-{
- struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
-
- xen_be_unbind_evtchn(&netdev->xendev);
-
- if (netdev->txs) {
- xengnttab_unmap(netdev->xendev.gnttabdev, netdev->txs, 1);
- netdev->txs = NULL;
- }
- if (netdev->rxs) {
- xengnttab_unmap(netdev->xendev.gnttabdev, netdev->rxs, 1);
- netdev->rxs = NULL;
- }
-}
-
-static void net_event(struct XenDevice *xendev)
-{
- struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
- net_tx_packets(netdev);
- qemu_flush_queued_packets(qemu_get_queue(netdev->nic));
-}
-
-static int net_free(struct XenDevice *xendev)
-{
- struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
-
- if (netdev->nic) {
- qemu_del_nic(netdev->nic);
- netdev->nic = NULL;
- }
- g_free(netdev->mac);
- netdev->mac = NULL;
- return 0;
-}
-
-/* ------------------------------------------------------------- */
-
-struct XenDevOps xen_netdev_ops = {
- .size = sizeof(struct XenNetDev),
- .flags = DEVOPS_FLAG_NEED_GNTDEV,
- .init = net_init,
- .initialise = net_connect,
- .event = net_event,
- .disconnect = net_disconnect,
- .free = net_free,
-};
diff --git a/qemu/hw/net/xgmac.c b/qemu/hw/net/xgmac.c
deleted file mode 100644
index 0c5f793bd..000000000
--- a/qemu/hw/net/xgmac.c
+++ /dev/null
@@ -1,433 +0,0 @@
-/*
- * QEMU model of XGMAC Ethernet.
- *
- * derived from the Xilinx AXI-Ethernet by Edgar E. Iglesias.
- *
- * Copyright (c) 2011 Calxeda, Inc.
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "sysemu/char.h"
-#include "qemu/log.h"
-#include "net/net.h"
-#include "net/checksum.h"
-
-#ifdef DEBUG_XGMAC
-#define DEBUGF_BRK(message, args...) do { \
- fprintf(stderr, (message), ## args); \
- } while (0)
-#else
-#define DEBUGF_BRK(message, args...) do { } while (0)
-#endif
-
-#define XGMAC_CONTROL 0x00000000 /* MAC Configuration */
-#define XGMAC_FRAME_FILTER 0x00000001 /* MAC Frame Filter */
-#define XGMAC_FLOW_CTRL 0x00000006 /* MAC Flow Control */
-#define XGMAC_VLAN_TAG 0x00000007 /* VLAN Tags */
-#define XGMAC_VERSION 0x00000008 /* Version */
-/* VLAN tag for insertion or replacement into tx frames */
-#define XGMAC_VLAN_INCL 0x00000009
-#define XGMAC_LPI_CTRL 0x0000000a /* LPI Control and Status */
-#define XGMAC_LPI_TIMER 0x0000000b /* LPI Timers Control */
-#define XGMAC_TX_PACE 0x0000000c /* Transmit Pace and Stretch */
-#define XGMAC_VLAN_HASH 0x0000000d /* VLAN Hash Table */
-#define XGMAC_DEBUG 0x0000000e /* Debug */
-#define XGMAC_INT_STATUS 0x0000000f /* Interrupt and Control */
-/* HASH table registers */
-#define XGMAC_HASH(n) ((0x00000300/4) + (n))
-#define XGMAC_NUM_HASH 16
-/* Operation Mode */
-#define XGMAC_OPMODE (0x00000400/4)
-/* Remote Wake-Up Frame Filter */
-#define XGMAC_REMOTE_WAKE (0x00000700/4)
-/* PMT Control and Status */
-#define XGMAC_PMT (0x00000704/4)
-
-#define XGMAC_ADDR_HIGH(reg) (0x00000010+((reg) * 2))
-#define XGMAC_ADDR_LOW(reg) (0x00000011+((reg) * 2))
-
-#define DMA_BUS_MODE 0x000003c0 /* Bus Mode */
-#define DMA_XMT_POLL_DEMAND 0x000003c1 /* Transmit Poll Demand */
-#define DMA_RCV_POLL_DEMAND 0x000003c2 /* Received Poll Demand */
-#define DMA_RCV_BASE_ADDR 0x000003c3 /* Receive List Base */
-#define DMA_TX_BASE_ADDR 0x000003c4 /* Transmit List Base */
-#define DMA_STATUS 0x000003c5 /* Status Register */
-#define DMA_CONTROL 0x000003c6 /* Ctrl (Operational Mode) */
-#define DMA_INTR_ENA 0x000003c7 /* Interrupt Enable */
-#define DMA_MISSED_FRAME_CTR 0x000003c8 /* Missed Frame Counter */
-/* Receive Interrupt Watchdog Timer */
-#define DMA_RI_WATCHDOG_TIMER 0x000003c9
-#define DMA_AXI_BUS 0x000003ca /* AXI Bus Mode */
-#define DMA_AXI_STATUS 0x000003cb /* AXI Status */
-#define DMA_CUR_TX_DESC_ADDR 0x000003d2 /* Current Host Tx Descriptor */
-#define DMA_CUR_RX_DESC_ADDR 0x000003d3 /* Current Host Rx Descriptor */
-#define DMA_CUR_TX_BUF_ADDR 0x000003d4 /* Current Host Tx Buffer */
-#define DMA_CUR_RX_BUF_ADDR 0x000003d5 /* Current Host Rx Buffer */
-#define DMA_HW_FEATURE 0x000003d6 /* Enabled Hardware Features */
-
-/* DMA Status register defines */
-#define DMA_STATUS_GMI 0x08000000 /* MMC interrupt */
-#define DMA_STATUS_GLI 0x04000000 /* GMAC Line interface int */
-#define DMA_STATUS_EB_MASK 0x00380000 /* Error Bits Mask */
-#define DMA_STATUS_EB_TX_ABORT 0x00080000 /* Error Bits - TX Abort */
-#define DMA_STATUS_EB_RX_ABORT 0x00100000 /* Error Bits - RX Abort */
-#define DMA_STATUS_TS_MASK 0x00700000 /* Transmit Process State */
-#define DMA_STATUS_TS_SHIFT 20
-#define DMA_STATUS_RS_MASK 0x000e0000 /* Receive Process State */
-#define DMA_STATUS_RS_SHIFT 17
-#define DMA_STATUS_NIS 0x00010000 /* Normal Interrupt Summary */
-#define DMA_STATUS_AIS 0x00008000 /* Abnormal Interrupt Summary */
-#define DMA_STATUS_ERI 0x00004000 /* Early Receive Interrupt */
-#define DMA_STATUS_FBI 0x00002000 /* Fatal Bus Error Interrupt */
-#define DMA_STATUS_ETI 0x00000400 /* Early Transmit Interrupt */
-#define DMA_STATUS_RWT 0x00000200 /* Receive Watchdog Timeout */
-#define DMA_STATUS_RPS 0x00000100 /* Receive Process Stopped */
-#define DMA_STATUS_RU 0x00000080 /* Receive Buffer Unavailable */
-#define DMA_STATUS_RI 0x00000040 /* Receive Interrupt */
-#define DMA_STATUS_UNF 0x00000020 /* Transmit Underflow */
-#define DMA_STATUS_OVF 0x00000010 /* Receive Overflow */
-#define DMA_STATUS_TJT 0x00000008 /* Transmit Jabber Timeout */
-#define DMA_STATUS_TU 0x00000004 /* Transmit Buffer Unavailable */
-#define DMA_STATUS_TPS 0x00000002 /* Transmit Process Stopped */
-#define DMA_STATUS_TI 0x00000001 /* Transmit Interrupt */
-
-/* DMA Control register defines */
-#define DMA_CONTROL_ST 0x00002000 /* Start/Stop Transmission */
-#define DMA_CONTROL_SR 0x00000002 /* Start/Stop Receive */
-#define DMA_CONTROL_DFF 0x01000000 /* Disable flush of rx frames */
-
-struct desc {
- uint32_t ctl_stat;
- uint16_t buffer1_size;
- uint16_t buffer2_size;
- uint32_t buffer1_addr;
- uint32_t buffer2_addr;
- uint32_t ext_stat;
- uint32_t res[3];
-};
-
-#define R_MAX 0x400
-
-typedef struct RxTxStats {
- uint64_t rx_bytes;
- uint64_t tx_bytes;
-
- uint64_t rx;
- uint64_t rx_bcast;
- uint64_t rx_mcast;
-} RxTxStats;
-
-#define TYPE_XGMAC "xgmac"
-#define XGMAC(obj) OBJECT_CHECK(XgmacState, (obj), TYPE_XGMAC)
-
-typedef struct XgmacState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- qemu_irq sbd_irq;
- qemu_irq pmt_irq;
- qemu_irq mci_irq;
- NICState *nic;
- NICConf conf;
-
- struct RxTxStats stats;
- uint32_t regs[R_MAX];
-} XgmacState;
-
-static const VMStateDescription vmstate_rxtx_stats = {
- .name = "xgmac_stats",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT64(rx_bytes, RxTxStats),
- VMSTATE_UINT64(tx_bytes, RxTxStats),
- VMSTATE_UINT64(rx, RxTxStats),
- VMSTATE_UINT64(rx_bcast, RxTxStats),
- VMSTATE_UINT64(rx_mcast, RxTxStats),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_xgmac = {
- .name = "xgmac",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT(stats, XgmacState, 0, vmstate_rxtx_stats, RxTxStats),
- VMSTATE_UINT32_ARRAY(regs, XgmacState, R_MAX),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void xgmac_read_desc(XgmacState *s, struct desc *d, int rx)
-{
- uint32_t addr = rx ? s->regs[DMA_CUR_RX_DESC_ADDR] :
- s->regs[DMA_CUR_TX_DESC_ADDR];
- cpu_physical_memory_read(addr, d, sizeof(*d));
-}
-
-static void xgmac_write_desc(XgmacState *s, struct desc *d, int rx)
-{
- int reg = rx ? DMA_CUR_RX_DESC_ADDR : DMA_CUR_TX_DESC_ADDR;
- uint32_t addr = s->regs[reg];
-
- if (!rx && (d->ctl_stat & 0x00200000)) {
- s->regs[reg] = s->regs[DMA_TX_BASE_ADDR];
- } else if (rx && (d->buffer1_size & 0x8000)) {
- s->regs[reg] = s->regs[DMA_RCV_BASE_ADDR];
- } else {
- s->regs[reg] += sizeof(*d);
- }
- cpu_physical_memory_write(addr, d, sizeof(*d));
-}
-
-static void xgmac_enet_send(XgmacState *s)
-{
- struct desc bd;
- int frame_size;
- int len;
- uint8_t frame[8192];
- uint8_t *ptr;
-
- ptr = frame;
- frame_size = 0;
- while (1) {
- xgmac_read_desc(s, &bd, 0);
- if ((bd.ctl_stat & 0x80000000) == 0) {
- /* Run out of descriptors to transmit. */
- break;
- }
- len = (bd.buffer1_size & 0xfff) + (bd.buffer2_size & 0xfff);
-
- if ((bd.buffer1_size & 0xfff) > 2048) {
- DEBUGF_BRK("qemu:%s:ERROR...ERROR...ERROR... -- "
- "xgmac buffer 1 len on send > 2048 (0x%x)\n",
- __func__, bd.buffer1_size & 0xfff);
- }
- if ((bd.buffer2_size & 0xfff) != 0) {
- DEBUGF_BRK("qemu:%s:ERROR...ERROR...ERROR... -- "
- "xgmac buffer 2 len on send != 0 (0x%x)\n",
- __func__, bd.buffer2_size & 0xfff);
- }
- if (len >= sizeof(frame)) {
- DEBUGF_BRK("qemu:%s: buffer overflow %d read into %zu "
- "buffer\n" , __func__, len, sizeof(frame));
- DEBUGF_BRK("qemu:%s: buffer1.size=%d; buffer2.size=%d\n",
- __func__, bd.buffer1_size, bd.buffer2_size);
- }
-
- cpu_physical_memory_read(bd.buffer1_addr, ptr, len);
- ptr += len;
- frame_size += len;
- if (bd.ctl_stat & 0x20000000) {
- /* Last buffer in frame. */
- qemu_send_packet(qemu_get_queue(s->nic), frame, len);
- ptr = frame;
- frame_size = 0;
- s->regs[DMA_STATUS] |= DMA_STATUS_TI | DMA_STATUS_NIS;
- }
- bd.ctl_stat &= ~0x80000000;
- /* Write back the modified descriptor. */
- xgmac_write_desc(s, &bd, 0);
- }
-}
-
-static void enet_update_irq(XgmacState *s)
-{
- int stat = s->regs[DMA_STATUS] & s->regs[DMA_INTR_ENA];
- qemu_set_irq(s->sbd_irq, !!stat);
-}
-
-static uint64_t enet_read(void *opaque, hwaddr addr, unsigned size)
-{
- XgmacState *s = opaque;
- uint64_t r = 0;
- addr >>= 2;
-
- switch (addr) {
- case XGMAC_VERSION:
- r = 0x1012;
- break;
- default:
- if (addr < ARRAY_SIZE(s->regs)) {
- r = s->regs[addr];
- }
- break;
- }
- return r;
-}
-
-static void enet_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- XgmacState *s = opaque;
-
- addr >>= 2;
- switch (addr) {
- case DMA_BUS_MODE:
- s->regs[DMA_BUS_MODE] = value & ~0x1;
- break;
- case DMA_XMT_POLL_DEMAND:
- xgmac_enet_send(s);
- break;
- case DMA_STATUS:
- s->regs[DMA_STATUS] = s->regs[DMA_STATUS] & ~value;
- break;
- case DMA_RCV_BASE_ADDR:
- s->regs[DMA_RCV_BASE_ADDR] = s->regs[DMA_CUR_RX_DESC_ADDR] = value;
- break;
- case DMA_TX_BASE_ADDR:
- s->regs[DMA_TX_BASE_ADDR] = s->regs[DMA_CUR_TX_DESC_ADDR] = value;
- break;
- default:
- if (addr < ARRAY_SIZE(s->regs)) {
- s->regs[addr] = value;
- }
- break;
- }
- enet_update_irq(s);
-}
-
-static const MemoryRegionOps enet_mem_ops = {
- .read = enet_read,
- .write = enet_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static int eth_can_rx(XgmacState *s)
-{
- /* RX enabled? */
- return s->regs[DMA_CONTROL] & DMA_CONTROL_SR;
-}
-
-static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size)
-{
- XgmacState *s = qemu_get_nic_opaque(nc);
- static const unsigned char sa_bcast[6] = {0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff};
- int unicast, broadcast, multicast;
- struct desc bd;
- ssize_t ret;
-
- if (!eth_can_rx(s)) {
- return -1;
- }
- unicast = ~buf[0] & 0x1;
- broadcast = memcmp(buf, sa_bcast, 6) == 0;
- multicast = !unicast && !broadcast;
- if (size < 12) {
- s->regs[DMA_STATUS] |= DMA_STATUS_RI | DMA_STATUS_NIS;
- ret = -1;
- goto out;
- }
-
- xgmac_read_desc(s, &bd, 1);
- if ((bd.ctl_stat & 0x80000000) == 0) {
- s->regs[DMA_STATUS] |= DMA_STATUS_RU | DMA_STATUS_AIS;
- ret = size;
- goto out;
- }
-
- cpu_physical_memory_write(bd.buffer1_addr, buf, size);
-
- /* Add in the 4 bytes for crc (the real hw returns length incl crc) */
- size += 4;
- bd.ctl_stat = (size << 16) | 0x300;
- xgmac_write_desc(s, &bd, 1);
-
- s->stats.rx_bytes += size;
- s->stats.rx++;
- if (multicast) {
- s->stats.rx_mcast++;
- } else if (broadcast) {
- s->stats.rx_bcast++;
- }
-
- s->regs[DMA_STATUS] |= DMA_STATUS_RI | DMA_STATUS_NIS;
- ret = size;
-
-out:
- enet_update_irq(s);
- return ret;
-}
-
-static NetClientInfo net_xgmac_enet_info = {
- .type = NET_CLIENT_OPTIONS_KIND_NIC,
- .size = sizeof(NICState),
- .receive = eth_rx,
-};
-
-static int xgmac_enet_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- XgmacState *s = XGMAC(dev);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &enet_mem_ops, s,
- "xgmac", 0x1000);
- sysbus_init_mmio(sbd, &s->iomem);
- sysbus_init_irq(sbd, &s->sbd_irq);
- sysbus_init_irq(sbd, &s->pmt_irq);
- sysbus_init_irq(sbd, &s->mci_irq);
-
- qemu_macaddr_default_if_unset(&s->conf.macaddr);
- s->nic = qemu_new_nic(&net_xgmac_enet_info, &s->conf,
- object_get_typename(OBJECT(dev)), dev->id, s);
- qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-
- s->regs[XGMAC_ADDR_HIGH(0)] = (s->conf.macaddr.a[5] << 8) |
- s->conf.macaddr.a[4];
- s->regs[XGMAC_ADDR_LOW(0)] = (s->conf.macaddr.a[3] << 24) |
- (s->conf.macaddr.a[2] << 16) |
- (s->conf.macaddr.a[1] << 8) |
- s->conf.macaddr.a[0];
-
- return 0;
-}
-
-static Property xgmac_properties[] = {
- DEFINE_NIC_PROPERTIES(XgmacState, conf),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void xgmac_enet_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- sbc->init = xgmac_enet_init;
- dc->vmsd = &vmstate_xgmac;
- dc->props = xgmac_properties;
-}
-
-static const TypeInfo xgmac_enet_info = {
- .name = TYPE_XGMAC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(XgmacState),
- .class_init = xgmac_enet_class_init,
-};
-
-static void xgmac_enet_register_types(void)
-{
- type_register_static(&xgmac_enet_info);
-}
-
-type_init(xgmac_enet_register_types)
diff --git a/qemu/hw/net/xilinx_axienet.c b/qemu/hw/net/xilinx_axienet.c
deleted file mode 100644
index de23ab5dc..000000000
--- a/qemu/hw/net/xilinx_axienet.c
+++ /dev/null
@@ -1,1084 +0,0 @@
-/*
- * QEMU model of Xilinx AXI-Ethernet.
- *
- * Copyright (c) 2011 Edgar E. Iglesias.
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "qapi/error.h"
-#include "qemu/log.h"
-#include "net/net.h"
-#include "net/checksum.h"
-
-#include "hw/stream.h"
-
-#define DPHY(x)
-
-#define TYPE_XILINX_AXI_ENET "xlnx.axi-ethernet"
-#define TYPE_XILINX_AXI_ENET_DATA_STREAM "xilinx-axienet-data-stream"
-#define TYPE_XILINX_AXI_ENET_CONTROL_STREAM "xilinx-axienet-control-stream"
-
-#define XILINX_AXI_ENET(obj) \
- OBJECT_CHECK(XilinxAXIEnet, (obj), TYPE_XILINX_AXI_ENET)
-
-#define XILINX_AXI_ENET_DATA_STREAM(obj) \
- OBJECT_CHECK(XilinxAXIEnetStreamSlave, (obj),\
- TYPE_XILINX_AXI_ENET_DATA_STREAM)
-
-#define XILINX_AXI_ENET_CONTROL_STREAM(obj) \
- OBJECT_CHECK(XilinxAXIEnetStreamSlave, (obj),\
- TYPE_XILINX_AXI_ENET_CONTROL_STREAM)
-
-/* Advertisement control register. */
-#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */
-#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */
-#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */
-#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */
-
-#define CONTROL_PAYLOAD_WORDS 5
-#define CONTROL_PAYLOAD_SIZE (CONTROL_PAYLOAD_WORDS * (sizeof(uint32_t)))
-
-struct PHY {
- uint32_t regs[32];
-
- int link;
-
- unsigned int (*read)(struct PHY *phy, unsigned int req);
- void (*write)(struct PHY *phy, unsigned int req,
- unsigned int data);
-};
-
-static unsigned int tdk_read(struct 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. */
- r |= (1 << 1); /* 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 17:
- /* Marvell PHY on many xilinx boards. */
- r = 0x8000; /* 1000Mb */
- 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;
- }
- DPHY(qemu_log("\n%s %x = reg[%d]\n", __func__, r, regnum));
- return r;
-}
-
-static void
-tdk_write(struct PHY *phy, unsigned int req, unsigned int data)
-{
- int regnum;
-
- regnum = req & 0x1f;
- DPHY(qemu_log("%s reg[%d] = %x\n", __func__, regnum, data));
- switch (regnum) {
- default:
- phy->regs[regnum] = data;
- break;
- }
-
- /* Unconditionally clear regs[BMCR][BMCR_RESET] */
- phy->regs[0] &= ~0x8000;
-}
-
-static void
-tdk_init(struct 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;
-}
-
-struct MDIOBus {
- /* 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 PHY *devs[32];
-};
-
-static void
-mdio_attach(struct MDIOBus *bus, struct PHY *phy, unsigned int addr)
-{
- bus->devs[addr & 0x1f] = phy;
-}
-
-#ifdef USE_THIS_DEAD_CODE
-static void
-mdio_detach(struct MDIOBus *bus, struct PHY *phy, unsigned int addr)
-{
- bus->devs[addr & 0x1f] = NULL;
-}
-#endif
-
-static uint16_t mdio_read_req(struct MDIOBus *bus, unsigned int addr,
- unsigned int reg)
-{
- struct PHY *phy;
- uint16_t data;
-
- phy = bus->devs[addr];
- if (phy && phy->read) {
- data = phy->read(phy, reg);
- } else {
- data = 0xffff;
- }
- DPHY(qemu_log("%s addr=%d reg=%d data=%x\n", __func__, addr, reg, data));
- return data;
-}
-
-static void mdio_write_req(struct MDIOBus *bus, unsigned int addr,
- unsigned int reg, uint16_t data)
-{
- struct PHY *phy;
-
- DPHY(qemu_log("%s addr=%d reg=%d data=%x\n", __func__, addr, reg, data));
- phy = bus->devs[addr];
- if (phy && phy->write) {
- phy->write(phy, reg, data);
- }
-}
-
-#define DENET(x)
-
-#define R_RAF (0x000 / 4)
-enum {
- RAF_MCAST_REJ = (1 << 1),
- RAF_BCAST_REJ = (1 << 2),
- RAF_EMCF_EN = (1 << 12),
- RAF_NEWFUNC_EN = (1 << 11)
-};
-
-#define R_IS (0x00C / 4)
-enum {
- IS_HARD_ACCESS_COMPLETE = 1,
- IS_AUTONEG = (1 << 1),
- IS_RX_COMPLETE = (1 << 2),
- IS_RX_REJECT = (1 << 3),
- IS_TX_COMPLETE = (1 << 5),
- IS_RX_DCM_LOCK = (1 << 6),
- IS_MGM_RDY = (1 << 7),
- IS_PHY_RST_DONE = (1 << 8),
-};
-
-#define R_IP (0x010 / 4)
-#define R_IE (0x014 / 4)
-#define R_UAWL (0x020 / 4)
-#define R_UAWU (0x024 / 4)
-#define R_PPST (0x030 / 4)
-enum {
- PPST_LINKSTATUS = (1 << 0),
- PPST_PHY_LINKSTATUS = (1 << 7),
-};
-
-#define R_STATS_RX_BYTESL (0x200 / 4)
-#define R_STATS_RX_BYTESH (0x204 / 4)
-#define R_STATS_TX_BYTESL (0x208 / 4)
-#define R_STATS_TX_BYTESH (0x20C / 4)
-#define R_STATS_RXL (0x290 / 4)
-#define R_STATS_RXH (0x294 / 4)
-#define R_STATS_RX_BCASTL (0x2a0 / 4)
-#define R_STATS_RX_BCASTH (0x2a4 / 4)
-#define R_STATS_RX_MCASTL (0x2a8 / 4)
-#define R_STATS_RX_MCASTH (0x2ac / 4)
-
-#define R_RCW0 (0x400 / 4)
-#define R_RCW1 (0x404 / 4)
-enum {
- RCW1_VLAN = (1 << 27),
- RCW1_RX = (1 << 28),
- RCW1_FCS = (1 << 29),
- RCW1_JUM = (1 << 30),
- RCW1_RST = (1 << 31),
-};
-
-#define R_TC (0x408 / 4)
-enum {
- TC_VLAN = (1 << 27),
- TC_TX = (1 << 28),
- TC_FCS = (1 << 29),
- TC_JUM = (1 << 30),
- TC_RST = (1 << 31),
-};
-
-#define R_EMMC (0x410 / 4)
-enum {
- EMMC_LINKSPEED_10MB = (0 << 30),
- EMMC_LINKSPEED_100MB = (1 << 30),
- EMMC_LINKSPEED_1000MB = (2 << 30),
-};
-
-#define R_PHYC (0x414 / 4)
-
-#define R_MC (0x500 / 4)
-#define MC_EN (1 << 6)
-
-#define R_MCR (0x504 / 4)
-#define R_MWD (0x508 / 4)
-#define R_MRD (0x50c / 4)
-#define R_MIS (0x600 / 4)
-#define R_MIP (0x620 / 4)
-#define R_MIE (0x640 / 4)
-#define R_MIC (0x640 / 4)
-
-#define R_UAW0 (0x700 / 4)
-#define R_UAW1 (0x704 / 4)
-#define R_FMI (0x708 / 4)
-#define R_AF0 (0x710 / 4)
-#define R_AF1 (0x714 / 4)
-#define R_MAX (0x34 / 4)
-
-/* Indirect registers. */
-struct TEMAC {
- struct MDIOBus mdio_bus;
- struct PHY phy;
-
- void *parent;
-};
-
-typedef struct XilinxAXIEnetStreamSlave XilinxAXIEnetStreamSlave;
-typedef struct XilinxAXIEnet XilinxAXIEnet;
-
-struct XilinxAXIEnetStreamSlave {
- Object parent;
-
- struct XilinxAXIEnet *enet;
-} ;
-
-struct XilinxAXIEnet {
- SysBusDevice busdev;
- MemoryRegion iomem;
- qemu_irq irq;
- StreamSlave *tx_data_dev;
- StreamSlave *tx_control_dev;
- XilinxAXIEnetStreamSlave rx_data_dev;
- XilinxAXIEnetStreamSlave rx_control_dev;
- NICState *nic;
- NICConf conf;
-
-
- uint32_t c_rxmem;
- uint32_t c_txmem;
- uint32_t c_phyaddr;
-
- struct TEMAC TEMAC;
-
- /* MII regs. */
- union {
- uint32_t regs[4];
- struct {
- uint32_t mc;
- uint32_t mcr;
- uint32_t mwd;
- uint32_t mrd;
- };
- } mii;
-
- struct {
- uint64_t rx_bytes;
- uint64_t tx_bytes;
-
- uint64_t rx;
- uint64_t rx_bcast;
- uint64_t rx_mcast;
- } stats;
-
- /* Receive configuration words. */
- uint32_t rcw[2];
- /* Transmit config. */
- uint32_t tc;
- uint32_t emmc;
- uint32_t phyc;
-
- /* Unicast Address Word. */
- uint32_t uaw[2];
- /* Unicast address filter used with extended mcast. */
- uint32_t ext_uaw[2];
- uint32_t fmi;
-
- uint32_t regs[R_MAX];
-
- /* Multicast filter addrs. */
- uint32_t maddr[4][2];
- /* 32K x 1 lookup filter. */
- uint32_t ext_mtable[1024];
-
- uint32_t hdr[CONTROL_PAYLOAD_WORDS];
-
- uint8_t *rxmem;
- uint32_t rxsize;
- uint32_t rxpos;
-
- uint8_t rxapp[CONTROL_PAYLOAD_SIZE];
- uint32_t rxappsize;
-
- /* Whether axienet_eth_rx_notify should flush incoming queue. */
- bool need_flush;
-};
-
-static void axienet_rx_reset(XilinxAXIEnet *s)
-{
- s->rcw[1] = RCW1_JUM | RCW1_FCS | RCW1_RX | RCW1_VLAN;
-}
-
-static void axienet_tx_reset(XilinxAXIEnet *s)
-{
- s->tc = TC_JUM | TC_TX | TC_VLAN;
-}
-
-static inline int axienet_rx_resetting(XilinxAXIEnet *s)
-{
- return s->rcw[1] & RCW1_RST;
-}
-
-static inline int axienet_rx_enabled(XilinxAXIEnet *s)
-{
- return s->rcw[1] & RCW1_RX;
-}
-
-static inline int axienet_extmcf_enabled(XilinxAXIEnet *s)
-{
- return !!(s->regs[R_RAF] & RAF_EMCF_EN);
-}
-
-static inline int axienet_newfunc_enabled(XilinxAXIEnet *s)
-{
- return !!(s->regs[R_RAF] & RAF_NEWFUNC_EN);
-}
-
-static void xilinx_axienet_reset(DeviceState *d)
-{
- XilinxAXIEnet *s = XILINX_AXI_ENET(d);
-
- axienet_rx_reset(s);
- axienet_tx_reset(s);
-
- s->regs[R_PPST] = PPST_LINKSTATUS | PPST_PHY_LINKSTATUS;
- s->regs[R_IS] = IS_AUTONEG | IS_RX_DCM_LOCK | IS_MGM_RDY | IS_PHY_RST_DONE;
-
- s->emmc = EMMC_LINKSPEED_100MB;
-}
-
-static void enet_update_irq(XilinxAXIEnet *s)
-{
- s->regs[R_IP] = s->regs[R_IS] & s->regs[R_IE];
- qemu_set_irq(s->irq, !!s->regs[R_IP]);
-}
-
-static uint64_t enet_read(void *opaque, hwaddr addr, unsigned size)
-{
- XilinxAXIEnet *s = opaque;
- uint32_t r = 0;
- addr >>= 2;
-
- switch (addr) {
- case R_RCW0:
- case R_RCW1:
- r = s->rcw[addr & 1];
- break;
-
- case R_TC:
- r = s->tc;
- break;
-
- case R_EMMC:
- r = s->emmc;
- break;
-
- case R_PHYC:
- r = s->phyc;
- break;
-
- case R_MCR:
- r = s->mii.regs[addr & 3] | (1 << 7); /* Always ready. */
- break;
-
- case R_STATS_RX_BYTESL:
- case R_STATS_RX_BYTESH:
- r = s->stats.rx_bytes >> (32 * (addr & 1));
- break;
-
- case R_STATS_TX_BYTESL:
- case R_STATS_TX_BYTESH:
- r = s->stats.tx_bytes >> (32 * (addr & 1));
- break;
-
- case R_STATS_RXL:
- case R_STATS_RXH:
- r = s->stats.rx >> (32 * (addr & 1));
- break;
- case R_STATS_RX_BCASTL:
- case R_STATS_RX_BCASTH:
- r = s->stats.rx_bcast >> (32 * (addr & 1));
- break;
- case R_STATS_RX_MCASTL:
- case R_STATS_RX_MCASTH:
- r = s->stats.rx_mcast >> (32 * (addr & 1));
- break;
-
- case R_MC:
- case R_MWD:
- case R_MRD:
- r = s->mii.regs[addr & 3];
- break;
-
- case R_UAW0:
- case R_UAW1:
- r = s->uaw[addr & 1];
- break;
-
- case R_UAWU:
- case R_UAWL:
- r = s->ext_uaw[addr & 1];
- break;
-
- case R_FMI:
- r = s->fmi;
- break;
-
- case R_AF0:
- case R_AF1:
- r = s->maddr[s->fmi & 3][addr & 1];
- break;
-
- case 0x8000 ... 0x83ff:
- r = s->ext_mtable[addr - 0x8000];
- break;
-
- default:
- if (addr < ARRAY_SIZE(s->regs)) {
- r = s->regs[addr];
- }
- DENET(qemu_log("%s addr=" TARGET_FMT_plx " v=%x\n",
- __func__, addr * 4, r));
- break;
- }
- return r;
-}
-
-static void enet_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- XilinxAXIEnet *s = opaque;
- struct TEMAC *t = &s->TEMAC;
-
- addr >>= 2;
- switch (addr) {
- case R_RCW0:
- case R_RCW1:
- s->rcw[addr & 1] = value;
- if ((addr & 1) && value & RCW1_RST) {
- axienet_rx_reset(s);
- } else {
- qemu_flush_queued_packets(qemu_get_queue(s->nic));
- }
- break;
-
- case R_TC:
- s->tc = value;
- if (value & TC_RST) {
- axienet_tx_reset(s);
- }
- break;
-
- case R_EMMC:
- s->emmc = value;
- break;
-
- case R_PHYC:
- s->phyc = value;
- break;
-
- case R_MC:
- value &= ((1 << 7) - 1);
-
- /* Enable the MII. */
- if (value & MC_EN) {
- unsigned int miiclkdiv = value & ((1 << 6) - 1);
- if (!miiclkdiv) {
- qemu_log("AXIENET: MDIO enabled but MDIOCLK is zero!\n");
- }
- }
- s->mii.mc = value;
- break;
-
- case R_MCR: {
- unsigned int phyaddr = (value >> 24) & 0x1f;
- unsigned int regaddr = (value >> 16) & 0x1f;
- unsigned int op = (value >> 14) & 3;
- unsigned int initiate = (value >> 11) & 1;
-
- if (initiate) {
- if (op == 1) {
- mdio_write_req(&t->mdio_bus, phyaddr, regaddr, s->mii.mwd);
- } else if (op == 2) {
- s->mii.mrd = mdio_read_req(&t->mdio_bus, phyaddr, regaddr);
- } else {
- qemu_log("AXIENET: invalid MDIOBus OP=%d\n", op);
- }
- }
- s->mii.mcr = value;
- break;
- }
-
- case R_MWD:
- case R_MRD:
- s->mii.regs[addr & 3] = value;
- break;
-
-
- case R_UAW0:
- case R_UAW1:
- s->uaw[addr & 1] = value;
- break;
-
- case R_UAWL:
- case R_UAWU:
- s->ext_uaw[addr & 1] = value;
- break;
-
- case R_FMI:
- s->fmi = value;
- break;
-
- case R_AF0:
- case R_AF1:
- s->maddr[s->fmi & 3][addr & 1] = value;
- break;
-
- case R_IS:
- s->regs[addr] &= ~value;
- break;
-
- case 0x8000 ... 0x83ff:
- s->ext_mtable[addr - 0x8000] = value;
- break;
-
- default:
- DENET(qemu_log("%s addr=" TARGET_FMT_plx " v=%x\n",
- __func__, addr * 4, (unsigned)value));
- if (addr < ARRAY_SIZE(s->regs)) {
- s->regs[addr] = value;
- }
- break;
- }
- enet_update_irq(s);
-}
-
-static const MemoryRegionOps enet_ops = {
- .read = enet_read,
- .write = enet_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static int eth_can_rx(XilinxAXIEnet *s)
-{
- /* RX enabled? */
- return !s->rxsize && !axienet_rx_resetting(s) && axienet_rx_enabled(s);
-}
-
-static int enet_match_addr(const uint8_t *buf, uint32_t f0, uint32_t f1)
-{
- int match = 1;
-
- if (memcmp(buf, &f0, 4)) {
- match = 0;
- }
-
- if (buf[4] != (f1 & 0xff) || buf[5] != ((f1 >> 8) & 0xff)) {
- match = 0;
- }
-
- return match;
-}
-
-static void axienet_eth_rx_notify(void *opaque)
-{
- XilinxAXIEnet *s = XILINX_AXI_ENET(opaque);
-
- while (s->rxappsize && stream_can_push(s->tx_control_dev,
- axienet_eth_rx_notify, s)) {
- size_t ret = stream_push(s->tx_control_dev,
- (void *)s->rxapp + CONTROL_PAYLOAD_SIZE
- - s->rxappsize, s->rxappsize);
- s->rxappsize -= ret;
- }
-
- while (s->rxsize && stream_can_push(s->tx_data_dev,
- axienet_eth_rx_notify, s)) {
- size_t ret = stream_push(s->tx_data_dev, (void *)s->rxmem + s->rxpos,
- s->rxsize);
- s->rxsize -= ret;
- s->rxpos += ret;
- if (!s->rxsize) {
- s->regs[R_IS] |= IS_RX_COMPLETE;
- if (s->need_flush) {
- s->need_flush = false;
- qemu_flush_queued_packets(qemu_get_queue(s->nic));
- }
- }
- }
- enet_update_irq(s);
-}
-
-static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size)
-{
- XilinxAXIEnet *s = qemu_get_nic_opaque(nc);
- static const unsigned char sa_bcast[6] = {0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff};
- static const unsigned char sa_ipmcast[3] = {0x01, 0x00, 0x52};
- uint32_t app[CONTROL_PAYLOAD_WORDS] = {0};
- int promisc = s->fmi & (1 << 31);
- int unicast, broadcast, multicast, ip_multicast = 0;
- uint32_t csum32;
- uint16_t csum16;
- int i;
-
- DENET(qemu_log("%s: %zd bytes\n", __func__, size));
-
- if (!eth_can_rx(s)) {
- s->need_flush = true;
- return 0;
- }
-
- unicast = ~buf[0] & 0x1;
- broadcast = memcmp(buf, sa_bcast, 6) == 0;
- multicast = !unicast && !broadcast;
- if (multicast && (memcmp(sa_ipmcast, buf, sizeof sa_ipmcast) == 0)) {
- ip_multicast = 1;
- }
-
- /* Jumbo or vlan sizes ? */
- if (!(s->rcw[1] & RCW1_JUM)) {
- if (size > 1518 && size <= 1522 && !(s->rcw[1] & RCW1_VLAN)) {
- return size;
- }
- }
-
- /* Basic Address filters. If you want to use the extended filters
- you'll generally have to place the ethernet mac into promiscuous mode
- to avoid the basic filtering from dropping most frames. */
- if (!promisc) {
- if (unicast) {
- if (!enet_match_addr(buf, s->uaw[0], s->uaw[1])) {
- return size;
- }
- } else {
- if (broadcast) {
- /* Broadcast. */
- if (s->regs[R_RAF] & RAF_BCAST_REJ) {
- return size;
- }
- } else {
- int drop = 1;
-
- /* Multicast. */
- if (s->regs[R_RAF] & RAF_MCAST_REJ) {
- return size;
- }
-
- for (i = 0; i < 4; i++) {
- if (enet_match_addr(buf, s->maddr[i][0], s->maddr[i][1])) {
- drop = 0;
- break;
- }
- }
-
- if (drop) {
- return size;
- }
- }
- }
- }
-
- /* Extended mcast filtering enabled? */
- if (axienet_newfunc_enabled(s) && axienet_extmcf_enabled(s)) {
- if (unicast) {
- if (!enet_match_addr(buf, s->ext_uaw[0], s->ext_uaw[1])) {
- return size;
- }
- } else {
- if (broadcast) {
- /* Broadcast. ??? */
- if (s->regs[R_RAF] & RAF_BCAST_REJ) {
- return size;
- }
- } else {
- int idx, bit;
-
- /* Multicast. */
- if (!memcmp(buf, sa_ipmcast, 3)) {
- return size;
- }
-
- idx = (buf[4] & 0x7f) << 8;
- idx |= buf[5];
-
- bit = 1 << (idx & 0x1f);
- idx >>= 5;
-
- if (!(s->ext_mtable[idx] & bit)) {
- return size;
- }
- }
- }
- }
-
- if (size < 12) {
- s->regs[R_IS] |= IS_RX_REJECT;
- enet_update_irq(s);
- return -1;
- }
-
- if (size > (s->c_rxmem - 4)) {
- size = s->c_rxmem - 4;
- }
-
- memcpy(s->rxmem, buf, size);
- memset(s->rxmem + size, 0, 4); /* Clear the FCS. */
-
- if (s->rcw[1] & RCW1_FCS) {
- size += 4; /* fcs is inband. */
- }
-
- app[0] = 5 << 28;
- csum32 = net_checksum_add(size - 14, (uint8_t *)s->rxmem + 14);
- /* Fold it once. */
- csum32 = (csum32 & 0xffff) + (csum32 >> 16);
- /* And twice to get rid of possible carries. */
- csum16 = (csum32 & 0xffff) + (csum32 >> 16);
- app[3] = csum16;
- app[4] = size & 0xffff;
-
- s->stats.rx_bytes += size;
- s->stats.rx++;
- if (multicast) {
- s->stats.rx_mcast++;
- app[2] |= 1 | (ip_multicast << 1);
- } else if (broadcast) {
- s->stats.rx_bcast++;
- app[2] |= 1 << 3;
- }
-
- /* Good frame. */
- app[2] |= 1 << 6;
-
- s->rxsize = size;
- s->rxpos = 0;
- for (i = 0; i < ARRAY_SIZE(app); ++i) {
- app[i] = cpu_to_le32(app[i]);
- }
- s->rxappsize = CONTROL_PAYLOAD_SIZE;
- memcpy(s->rxapp, app, s->rxappsize);
- axienet_eth_rx_notify(s);
-
- enet_update_irq(s);
- return size;
-}
-
-static size_t
-xilinx_axienet_control_stream_push(StreamSlave *obj, uint8_t *buf, size_t len)
-{
- int i;
- XilinxAXIEnetStreamSlave *cs = XILINX_AXI_ENET_CONTROL_STREAM(obj);
- XilinxAXIEnet *s = cs->enet;
-
- if (len != CONTROL_PAYLOAD_SIZE) {
- hw_error("AXI Enet requires %d byte control stream payload\n",
- (int)CONTROL_PAYLOAD_SIZE);
- }
-
- memcpy(s->hdr, buf, len);
-
- for (i = 0; i < ARRAY_SIZE(s->hdr); ++i) {
- s->hdr[i] = le32_to_cpu(s->hdr[i]);
- }
- return len;
-}
-
-static size_t
-xilinx_axienet_data_stream_push(StreamSlave *obj, uint8_t *buf, size_t size)
-{
- XilinxAXIEnetStreamSlave *ds = XILINX_AXI_ENET_DATA_STREAM(obj);
- XilinxAXIEnet *s = ds->enet;
-
- /* TX enable ? */
- if (!(s->tc & TC_TX)) {
- return size;
- }
-
- /* Jumbo or vlan sizes ? */
- if (!(s->tc & TC_JUM)) {
- if (size > 1518 && size <= 1522 && !(s->tc & TC_VLAN)) {
- return size;
- }
- }
-
- if (s->hdr[0] & 1) {
- unsigned int start_off = s->hdr[1] >> 16;
- unsigned int write_off = s->hdr[1] & 0xffff;
- uint32_t tmp_csum;
- uint16_t csum;
-
- tmp_csum = net_checksum_add(size - start_off,
- (uint8_t *)buf + start_off);
- /* Accumulate the seed. */
- tmp_csum += s->hdr[2] & 0xffff;
-
- /* Fold the 32bit partial checksum. */
- csum = net_checksum_finish(tmp_csum);
-
- /* Writeback. */
- buf[write_off] = csum >> 8;
- buf[write_off + 1] = csum & 0xff;
- }
-
- qemu_send_packet(qemu_get_queue(s->nic), buf, size);
-
- s->stats.tx_bytes += size;
- s->regs[R_IS] |= IS_TX_COMPLETE;
- enet_update_irq(s);
-
- return size;
-}
-
-static NetClientInfo net_xilinx_enet_info = {
- .type = NET_CLIENT_OPTIONS_KIND_NIC,
- .size = sizeof(NICState),
- .receive = eth_rx,
-};
-
-static void xilinx_enet_realize(DeviceState *dev, Error **errp)
-{
- XilinxAXIEnet *s = XILINX_AXI_ENET(dev);
- XilinxAXIEnetStreamSlave *ds = XILINX_AXI_ENET_DATA_STREAM(&s->rx_data_dev);
- XilinxAXIEnetStreamSlave *cs = XILINX_AXI_ENET_CONTROL_STREAM(
- &s->rx_control_dev);
- Error *local_err = NULL;
-
- object_property_add_link(OBJECT(ds), "enet", "xlnx.axi-ethernet",
- (Object **) &ds->enet,
- object_property_allow_set_link,
- OBJ_PROP_LINK_UNREF_ON_RELEASE,
- &local_err);
- object_property_add_link(OBJECT(cs), "enet", "xlnx.axi-ethernet",
- (Object **) &cs->enet,
- object_property_allow_set_link,
- OBJ_PROP_LINK_UNREF_ON_RELEASE,
- &local_err);
- if (local_err) {
- goto xilinx_enet_realize_fail;
- }
- object_property_set_link(OBJECT(ds), OBJECT(s), "enet", &local_err);
- object_property_set_link(OBJECT(cs), OBJECT(s), "enet", &local_err);
- if (local_err) {
- goto xilinx_enet_realize_fail;
- }
-
- qemu_macaddr_default_if_unset(&s->conf.macaddr);
- s->nic = qemu_new_nic(&net_xilinx_enet_info, &s->conf,
- object_get_typename(OBJECT(dev)), dev->id, s);
- qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-
- tdk_init(&s->TEMAC.phy);
- mdio_attach(&s->TEMAC.mdio_bus, &s->TEMAC.phy, s->c_phyaddr);
-
- s->TEMAC.parent = s;
-
- s->rxmem = g_malloc(s->c_rxmem);
- return;
-
-xilinx_enet_realize_fail:
- if (!*errp) {
- *errp = local_err;
- }
-}
-
-static void xilinx_enet_init(Object *obj)
-{
- XilinxAXIEnet *s = XILINX_AXI_ENET(obj);
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
-
- object_property_add_link(obj, "axistream-connected", TYPE_STREAM_SLAVE,
- (Object **) &s->tx_data_dev,
- qdev_prop_allow_set_link_before_realize,
- OBJ_PROP_LINK_UNREF_ON_RELEASE,
- &error_abort);
- object_property_add_link(obj, "axistream-control-connected",
- TYPE_STREAM_SLAVE,
- (Object **) &s->tx_control_dev,
- qdev_prop_allow_set_link_before_realize,
- OBJ_PROP_LINK_UNREF_ON_RELEASE,
- &error_abort);
-
- object_initialize(&s->rx_data_dev, sizeof(s->rx_data_dev),
- TYPE_XILINX_AXI_ENET_DATA_STREAM);
- object_initialize(&s->rx_control_dev, sizeof(s->rx_control_dev),
- TYPE_XILINX_AXI_ENET_CONTROL_STREAM);
- object_property_add_child(OBJECT(s), "axistream-connected-target",
- (Object *)&s->rx_data_dev, &error_abort);
- object_property_add_child(OBJECT(s), "axistream-control-connected-target",
- (Object *)&s->rx_control_dev, &error_abort);
-
- sysbus_init_irq(sbd, &s->irq);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &enet_ops, s, "enet", 0x40000);
- sysbus_init_mmio(sbd, &s->iomem);
-}
-
-static Property xilinx_enet_properties[] = {
- DEFINE_PROP_UINT32("phyaddr", XilinxAXIEnet, c_phyaddr, 7),
- DEFINE_PROP_UINT32("rxmem", XilinxAXIEnet, c_rxmem, 0x1000),
- DEFINE_PROP_UINT32("txmem", XilinxAXIEnet, c_txmem, 0x1000),
- DEFINE_NIC_PROPERTIES(XilinxAXIEnet, conf),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void xilinx_enet_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = xilinx_enet_realize;
- dc->props = xilinx_enet_properties;
- dc->reset = xilinx_axienet_reset;
-}
-
-static void xilinx_enet_stream_class_init(ObjectClass *klass, void *data)
-{
- StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(klass);
-
- ssc->push = data;
-}
-
-static const TypeInfo xilinx_enet_info = {
- .name = TYPE_XILINX_AXI_ENET,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(XilinxAXIEnet),
- .class_init = xilinx_enet_class_init,
- .instance_init = xilinx_enet_init,
-};
-
-static const TypeInfo xilinx_enet_data_stream_info = {
- .name = TYPE_XILINX_AXI_ENET_DATA_STREAM,
- .parent = TYPE_OBJECT,
- .instance_size = sizeof(struct XilinxAXIEnetStreamSlave),
- .class_init = xilinx_enet_stream_class_init,
- .class_data = xilinx_axienet_data_stream_push,
- .interfaces = (InterfaceInfo[]) {
- { TYPE_STREAM_SLAVE },
- { }
- }
-};
-
-static const TypeInfo xilinx_enet_control_stream_info = {
- .name = TYPE_XILINX_AXI_ENET_CONTROL_STREAM,
- .parent = TYPE_OBJECT,
- .instance_size = sizeof(struct XilinxAXIEnetStreamSlave),
- .class_init = xilinx_enet_stream_class_init,
- .class_data = xilinx_axienet_control_stream_push,
- .interfaces = (InterfaceInfo[]) {
- { TYPE_STREAM_SLAVE },
- { }
- }
-};
-
-static void xilinx_enet_register_types(void)
-{
- type_register_static(&xilinx_enet_info);
- type_register_static(&xilinx_enet_data_stream_info);
- type_register_static(&xilinx_enet_control_stream_info);
-}
-
-type_init(xilinx_enet_register_types)
diff --git a/qemu/hw/net/xilinx_ethlite.c b/qemu/hw/net/xilinx_ethlite.c
deleted file mode 100644
index bc846e709..000000000
--- a/qemu/hw/net/xilinx_ethlite.c
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * QEMU model of the Xilinx Ethernet Lite MAC.
- *
- * Copyright (c) 2009 Edgar E. Iglesias.
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "cpu.h" /* FIXME should not use tswap* */
-#include "hw/sysbus.h"
-#include "hw/hw.h"
-#include "net/net.h"
-
-#define D(x)
-#define R_TX_BUF0 0
-#define R_TX_LEN0 (0x07f4 / 4)
-#define R_TX_GIE0 (0x07f8 / 4)
-#define R_TX_CTRL0 (0x07fc / 4)
-#define R_TX_BUF1 (0x0800 / 4)
-#define R_TX_LEN1 (0x0ff4 / 4)
-#define R_TX_CTRL1 (0x0ffc / 4)
-
-#define R_RX_BUF0 (0x1000 / 4)
-#define R_RX_CTRL0 (0x17fc / 4)
-#define R_RX_BUF1 (0x1800 / 4)
-#define R_RX_CTRL1 (0x1ffc / 4)
-#define R_MAX (0x2000 / 4)
-
-#define GIE_GIE 0x80000000
-
-#define CTRL_I 0x8
-#define CTRL_P 0x2
-#define CTRL_S 0x1
-
-#define TYPE_XILINX_ETHLITE "xlnx.xps-ethernetlite"
-#define XILINX_ETHLITE(obj) \
- OBJECT_CHECK(struct xlx_ethlite, (obj), TYPE_XILINX_ETHLITE)
-
-struct xlx_ethlite
-{
- SysBusDevice parent_obj;
-
- MemoryRegion mmio;
- qemu_irq irq;
- NICState *nic;
- NICConf conf;
-
- uint32_t c_tx_pingpong;
- uint32_t c_rx_pingpong;
- unsigned int txbuf;
- unsigned int rxbuf;
-
- uint32_t regs[R_MAX];
-};
-
-static inline void eth_pulse_irq(struct xlx_ethlite *s)
-{
- /* Only the first gie reg is active. */
- if (s->regs[R_TX_GIE0] & GIE_GIE) {
- qemu_irq_pulse(s->irq);
- }
-}
-
-static uint64_t
-eth_read(void *opaque, hwaddr addr, unsigned int size)
-{
- struct xlx_ethlite *s = opaque;
- uint32_t r = 0;
-
- addr >>= 2;
-
- switch (addr)
- {
- case R_TX_GIE0:
- case R_TX_LEN0:
- case R_TX_LEN1:
- case R_TX_CTRL1:
- case R_TX_CTRL0:
- case R_RX_CTRL1:
- case R_RX_CTRL0:
- r = s->regs[addr];
- D(qemu_log("%s " TARGET_FMT_plx "=%x\n", __func__, addr * 4, r));
- break;
-
- default:
- r = tswap32(s->regs[addr]);
- break;
- }
- return r;
-}
-
-static void
-eth_write(void *opaque, hwaddr addr,
- uint64_t val64, unsigned int size)
-{
- struct xlx_ethlite *s = opaque;
- unsigned int base = 0;
- uint32_t value = val64;
-
- addr >>= 2;
- switch (addr)
- {
- case R_TX_CTRL0:
- case R_TX_CTRL1:
- if (addr == R_TX_CTRL1)
- base = 0x800 / 4;
-
- 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(qemu_get_queue(s->nic),
- (void *) &s->regs[base],
- s->regs[base + R_TX_LEN0]);
- D(qemu_log("eth_tx %d\n", s->regs[base + R_TX_LEN0]));
- if (s->regs[base + R_TX_CTRL0] & CTRL_I)
- eth_pulse_irq(s);
- } else if ((value & (CTRL_P | CTRL_S)) == (CTRL_P | CTRL_S)) {
- memcpy(&s->conf.macaddr.a[0], &s->regs[base], 6);
- if (s->regs[base + R_TX_CTRL0] & CTRL_I)
- eth_pulse_irq(s);
- }
-
- /* We are fast and get ready pretty much immediately so
- we actually never flip the S nor P bits to one. */
- s->regs[addr] = value & ~(CTRL_P | CTRL_S);
- break;
-
- /* Keep these native. */
- case R_RX_CTRL0:
- case R_RX_CTRL1:
- if (!(value & CTRL_S)) {
- qemu_flush_queued_packets(qemu_get_queue(s->nic));
- }
- /* fall through */
- case R_TX_LEN0:
- case R_TX_LEN1:
- case R_TX_GIE0:
- D(qemu_log("%s addr=" TARGET_FMT_plx " val=%x\n",
- __func__, addr * 4, value));
- s->regs[addr] = value;
- break;
-
- default:
- s->regs[addr] = tswap32(value);
- break;
- }
-}
-
-static const MemoryRegionOps eth_ops = {
- .read = eth_read,
- .write = eth_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4
- }
-};
-
-static int eth_can_rx(NetClientState *nc)
-{
- struct xlx_ethlite *s = qemu_get_nic_opaque(nc);
- 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)
-{
- struct xlx_ethlite *s = qemu_get_nic_opaque(nc);
- unsigned int rxbase = s->rxbuf * (0x800 / 4);
-
- /* DA filter. */
- if (!(buf[0] & 0x80) && memcmp(&s->conf.macaddr.a[0], buf, 6))
- return size;
-
- if (s->regs[rxbase + R_RX_CTRL0] & CTRL_S) {
- D(qemu_log("ethlite lost packet %x\n", s->regs[R_RX_CTRL0]));
- return -1;
- }
-
- 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;
- if (s->regs[R_RX_CTRL0] & CTRL_I) {
- eth_pulse_irq(s);
- }
-
- /* If c_rx_pingpong was set flip buffers. */
- s->rxbuf ^= s->c_rx_pingpong;
- return size;
-}
-
-static void xilinx_ethlite_reset(DeviceState *dev)
-{
- struct xlx_ethlite *s = XILINX_ETHLITE(dev);
-
- s->rxbuf = 0;
-}
-
-static NetClientInfo net_xilinx_ethlite_info = {
- .type = NET_CLIENT_OPTIONS_KIND_NIC,
- .size = sizeof(NICState),
- .can_receive = eth_can_rx,
- .receive = eth_rx,
-};
-
-static void xilinx_ethlite_realize(DeviceState *dev, Error **errp)
-{
- struct xlx_ethlite *s = XILINX_ETHLITE(dev);
-
- qemu_macaddr_default_if_unset(&s->conf.macaddr);
- s->nic = qemu_new_nic(&net_xilinx_ethlite_info, &s->conf,
- object_get_typename(OBJECT(dev)), dev->id, s);
- qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-}
-
-static void xilinx_ethlite_init(Object *obj)
-{
- struct xlx_ethlite *s = XILINX_ETHLITE(obj);
-
- sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
-
- memory_region_init_io(&s->mmio, obj, &eth_ops, s,
- "xlnx.xps-ethernetlite", R_MAX * 4);
- sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
-}
-
-static Property xilinx_ethlite_properties[] = {
- DEFINE_PROP_UINT32("tx-ping-pong", struct xlx_ethlite, c_tx_pingpong, 1),
- DEFINE_PROP_UINT32("rx-ping-pong", struct xlx_ethlite, c_rx_pingpong, 1),
- DEFINE_NIC_PROPERTIES(struct xlx_ethlite, conf),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void xilinx_ethlite_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = xilinx_ethlite_realize;
- dc->reset = xilinx_ethlite_reset;
- dc->props = xilinx_ethlite_properties;
-}
-
-static const TypeInfo xilinx_ethlite_info = {
- .name = TYPE_XILINX_ETHLITE,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(struct xlx_ethlite),
- .instance_init = xilinx_ethlite_init,
- .class_init = xilinx_ethlite_class_init,
-};
-
-static void xilinx_ethlite_register_types(void)
-{
- type_register_static(&xilinx_ethlite_info);
-}
-
-type_init(xilinx_ethlite_register_types)
diff --git a/qemu/hw/nvram/Makefile.objs b/qemu/hw/nvram/Makefile.objs
deleted file mode 100644
index e9a66940e..000000000
--- a/qemu/hw/nvram/Makefile.objs
+++ /dev/null
@@ -1,5 +0,0 @@
-common-obj-$(CONFIG_DS1225Y) += ds1225y.o
-common-obj-y += eeprom93xx.o
-common-obj-y += fw_cfg.o
-common-obj-$(CONFIG_MAC_NVRAM) += mac_nvram.o
-obj-$(CONFIG_PSERIES) += spapr_nvram.o
diff --git a/qemu/hw/nvram/ds1225y.c b/qemu/hw/nvram/ds1225y.c
deleted file mode 100644
index 57d5ab215..000000000
--- a/qemu/hw/nvram/ds1225y.c
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * QEMU NVRAM emulation for DS1225Y chip
- *
- * Copyright (c) 2007-2008 Hervé Poussineau
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-
-typedef struct {
- MemoryRegion iomem;
- uint32_t chip_size;
- char *filename;
- FILE *file;
- uint8_t *contents;
-} NvRamState;
-
-static uint64_t nvram_read(void *opaque, hwaddr addr, unsigned size)
-{
- NvRamState *s = opaque;
- uint32_t val;
-
- val = s->contents[addr];
- trace_nvram_read(addr, val);
- return val;
-}
-
-static void nvram_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned size)
-{
- NvRamState *s = opaque;
-
- val &= 0xff;
- trace_nvram_write(addr, s->contents[addr], val);
-
- s->contents[addr] = val;
- if (s->file) {
- fseek(s->file, addr, SEEK_SET);
- fputc(val, s->file);
- fflush(s->file);
- }
-}
-
-static const MemoryRegionOps nvram_ops = {
- .read = nvram_read,
- .write = nvram_write,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static int nvram_post_load(void *opaque, int version_id)
-{
- NvRamState *s = opaque;
-
- /* Close file, as filename may has changed in load/store process */
- if (s->file) {
- fclose(s->file);
- }
-
- /* Write back nvram contents */
- s->file = fopen(s->filename, "wb");
- if (s->file) {
- /* Write back contents, as 'wb' mode cleaned the file */
- if (fwrite(s->contents, s->chip_size, 1, s->file) != 1) {
- printf("nvram_post_load: short write\n");
- }
- fflush(s->file);
- }
-
- return 0;
-}
-
-static const VMStateDescription vmstate_nvram = {
- .name = "nvram",
- .version_id = 0,
- .minimum_version_id = 0,
- .post_load = nvram_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_VARRAY_UINT32(contents, NvRamState, chip_size, 0,
- vmstate_info_uint8, uint8_t),
- VMSTATE_END_OF_LIST()
- }
-};
-
-#define TYPE_DS1225Y "ds1225y"
-#define DS1225Y(obj) OBJECT_CHECK(SysBusNvRamState, (obj), TYPE_DS1225Y)
-
-typedef struct {
- SysBusDevice parent_obj;
-
- NvRamState nvram;
-} SysBusNvRamState;
-
-static int nvram_sysbus_initfn(SysBusDevice *dev)
-{
- SysBusNvRamState *sys = DS1225Y(dev);
- NvRamState *s = &sys->nvram;
- FILE *file;
-
- s->contents = g_malloc0(s->chip_size);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &nvram_ops, s,
- "nvram", s->chip_size);
- sysbus_init_mmio(dev, &s->iomem);
-
- /* Read current file */
- file = fopen(s->filename, "rb");
- if (file) {
- /* Read nvram contents */
- if (fread(s->contents, s->chip_size, 1, file) != 1) {
- printf("nvram_sysbus_initfn: short read\n");
- }
- fclose(file);
- }
- nvram_post_load(s, 0);
-
- return 0;
-}
-
-static Property nvram_sysbus_properties[] = {
- DEFINE_PROP_UINT32("size", SysBusNvRamState, nvram.chip_size, 0x2000),
- DEFINE_PROP_STRING("filename", SysBusNvRamState, nvram.filename),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void nvram_sysbus_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = nvram_sysbus_initfn;
- dc->vmsd = &vmstate_nvram;
- dc->props = nvram_sysbus_properties;
-}
-
-static const TypeInfo nvram_sysbus_info = {
- .name = TYPE_DS1225Y,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(SysBusNvRamState),
- .class_init = nvram_sysbus_class_init,
-};
-
-static void nvram_register_types(void)
-{
- type_register_static(&nvram_sysbus_info);
-}
-
-type_init(nvram_register_types)
diff --git a/qemu/hw/nvram/eeprom93xx.c b/qemu/hw/nvram/eeprom93xx.c
deleted file mode 100644
index 2c16fc23d..000000000
--- a/qemu/hw/nvram/eeprom93xx.c
+++ /dev/null
@@ -1,337 +0,0 @@
-/*
- * QEMU EEPROM 93xx emulation
- *
- * Copyright (c) 2006-2007 Stefan Weil
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-/* Emulation for serial EEPROMs:
- * NMC93C06 256-Bit (16 x 16)
- * NMC93C46 1024-Bit (64 x 16)
- * NMC93C56 2028 Bit (128 x 16)
- * NMC93C66 4096 Bit (256 x 16)
- * Compatible devices include FM93C46 and others.
- *
- * Other drivers use these interface functions:
- * eeprom93xx_new - add a new EEPROM (with 16, 64 or 256 words)
- * eeprom93xx_free - destroy EEPROM
- * eeprom93xx_read - read data from the EEPROM
- * eeprom93xx_write - write data to the EEPROM
- * eeprom93xx_data - get EEPROM data array for external manipulation
- *
- * Todo list:
- * - No emulation of EEPROM timings.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/nvram/eeprom93xx.h"
-
-/* Debug EEPROM emulation. */
-//~ #define DEBUG_EEPROM
-
-#ifdef DEBUG_EEPROM
-#define logout(fmt, ...) fprintf(stderr, "EEPROM\t%-24s" fmt, __func__, ## __VA_ARGS__)
-#else
-#define logout(fmt, ...) ((void)0)
-#endif
-
-#define EEPROM_INSTANCE 0
-#define OLD_EEPROM_VERSION 20061112
-#define EEPROM_VERSION (OLD_EEPROM_VERSION + 1)
-
-#if 0
-typedef enum {
- eeprom_read = 0x80, /* read register xx */
- eeprom_write = 0x40, /* write register xx */
- eeprom_erase = 0xc0, /* erase register xx */
- eeprom_ewen = 0x30, /* erase / write enable */
- eeprom_ewds = 0x00, /* erase / write disable */
- eeprom_eral = 0x20, /* erase all registers */
- eeprom_wral = 0x10, /* write all registers */
- eeprom_amask = 0x0f,
- eeprom_imask = 0xf0
-} eeprom_instruction_t;
-#endif
-
-#ifdef DEBUG_EEPROM
-static const char *opstring[] = {
- "extended", "write", "read", "erase"
-};
-#endif
-
-struct _eeprom_t {
- uint8_t tick;
- uint8_t address;
- uint8_t command;
- uint8_t writable;
-
- uint8_t eecs;
- uint8_t eesk;
- uint8_t eedo;
-
- uint8_t addrbits;
- uint16_t size;
- uint16_t data;
- uint16_t contents[0];
-};
-
-/* Code for saving and restoring of EEPROM state. */
-
-/* Restore an uint16_t from an uint8_t
- This is a Big hack, but it is how the old state did it.
- */
-
-static int get_uint16_from_uint8(QEMUFile *f, void *pv, size_t size)
-{
- uint16_t *v = pv;
- *v = qemu_get_ubyte(f);
- return 0;
-}
-
-static void put_unused(QEMUFile *f, void *pv, size_t size)
-{
- fprintf(stderr, "uint16_from_uint8 is used only for backwards compatibility.\n");
- fprintf(stderr, "Never should be used to write a new state.\n");
- exit(0);
-}
-
-static const VMStateInfo vmstate_hack_uint16_from_uint8 = {
- .name = "uint16_from_uint8",
- .get = get_uint16_from_uint8,
- .put = put_unused,
-};
-
-#define VMSTATE_UINT16_HACK_TEST(_f, _s, _t) \
- VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_hack_uint16_from_uint8, uint16_t)
-
-static bool is_old_eeprom_version(void *opaque, int version_id)
-{
- return version_id == OLD_EEPROM_VERSION;
-}
-
-static const VMStateDescription vmstate_eeprom = {
- .name = "eeprom",
- .version_id = EEPROM_VERSION,
- .minimum_version_id = OLD_EEPROM_VERSION,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(tick, eeprom_t),
- VMSTATE_UINT8(address, eeprom_t),
- VMSTATE_UINT8(command, eeprom_t),
- VMSTATE_UINT8(writable, eeprom_t),
-
- VMSTATE_UINT8(eecs, eeprom_t),
- VMSTATE_UINT8(eesk, eeprom_t),
- VMSTATE_UINT8(eedo, eeprom_t),
-
- VMSTATE_UINT8(addrbits, eeprom_t),
- VMSTATE_UINT16_HACK_TEST(size, eeprom_t, is_old_eeprom_version),
- VMSTATE_UNUSED_TEST(is_old_eeprom_version, 1),
- VMSTATE_UINT16_EQUAL_V(size, eeprom_t, EEPROM_VERSION),
- VMSTATE_UINT16(data, eeprom_t),
- VMSTATE_VARRAY_UINT16_UNSAFE(contents, eeprom_t, size, 0,
- vmstate_info_uint16, uint16_t),
- VMSTATE_END_OF_LIST()
- }
-};
-
-void eeprom93xx_write(eeprom_t *eeprom, int eecs, int eesk, int eedi)
-{
- uint8_t tick = eeprom->tick;
- uint8_t eedo = eeprom->eedo;
- uint16_t address = eeprom->address;
- uint8_t command = eeprom->command;
-
- logout("CS=%u SK=%u DI=%u DO=%u, tick = %u\n",
- eecs, eesk, eedi, eedo, tick);
-
- if (!eeprom->eecs && eecs) {
- /* Start chip select cycle. */
- logout("Cycle start, waiting for 1st start bit (0)\n");
- tick = 0;
- command = 0x0;
- address = 0x0;
- } else if (eeprom->eecs && !eecs) {
- /* End chip select cycle. This triggers write / erase. */
- if (eeprom->writable) {
- uint8_t subcommand = address >> (eeprom->addrbits - 2);
- if (command == 0 && subcommand == 2) {
- /* Erase all. */
- for (address = 0; address < eeprom->size; address++) {
- eeprom->contents[address] = 0xffff;
- }
- } else if (command == 3) {
- /* Erase word. */
- eeprom->contents[address] = 0xffff;
- } else if (tick >= 2 + 2 + eeprom->addrbits + 16) {
- if (command == 1) {
- /* Write word. */
- eeprom->contents[address] &= eeprom->data;
- } else if (command == 0 && subcommand == 1) {
- /* Write all. */
- for (address = 0; address < eeprom->size; address++) {
- eeprom->contents[address] &= eeprom->data;
- }
- }
- }
- }
- /* Output DO is tristate, read results in 1. */
- eedo = 1;
- } else if (eecs && !eeprom->eesk && eesk) {
- /* Raising edge of clock shifts data in. */
- if (tick == 0) {
- /* Wait for 1st start bit. */
- if (eedi == 0) {
- logout("Got correct 1st start bit, waiting for 2nd start bit (1)\n");
- tick++;
- } else {
- logout("wrong 1st start bit (is 1, should be 0)\n");
- tick = 2;
- //~ assert(!"wrong start bit");
- }
- } else if (tick == 1) {
- /* Wait for 2nd start bit. */
- if (eedi != 0) {
- logout("Got correct 2nd start bit, getting command + address\n");
- tick++;
- } else {
- logout("1st start bit is longer than needed\n");
- }
- } else if (tick < 2 + 2) {
- /* Got 2 start bits, transfer 2 opcode bits. */
- tick++;
- command <<= 1;
- if (eedi) {
- command += 1;
- }
- } else if (tick < 2 + 2 + eeprom->addrbits) {
- /* Got 2 start bits and 2 opcode bits, transfer all address bits. */
- tick++;
- address = ((address << 1) | eedi);
- if (tick == 2 + 2 + eeprom->addrbits) {
- logout("%s command, address = 0x%02x (value 0x%04x)\n",
- opstring[command], address, eeprom->contents[address]);
- if (command == 2) {
- eedo = 0;
- }
- address = address % eeprom->size;
- if (command == 0) {
- /* Command code in upper 2 bits of address. */
- switch (address >> (eeprom->addrbits - 2)) {
- case 0:
- logout("write disable command\n");
- eeprom->writable = 0;
- break;
- case 1:
- logout("write all command\n");
- break;
- case 2:
- logout("erase all command\n");
- break;
- case 3:
- logout("write enable command\n");
- eeprom->writable = 1;
- break;
- }
- } else {
- /* Read, write or erase word. */
- eeprom->data = eeprom->contents[address];
- }
- }
- } else if (tick < 2 + 2 + eeprom->addrbits + 16) {
- /* Transfer 16 data bits. */
- tick++;
- if (command == 2) {
- /* Read word. */
- eedo = ((eeprom->data & 0x8000) != 0);
- }
- eeprom->data <<= 1;
- eeprom->data += eedi;
- } else {
- logout("additional unneeded tick, not processed\n");
- }
- }
- /* Save status of EEPROM. */
- eeprom->tick = tick;
- eeprom->eecs = eecs;
- eeprom->eesk = eesk;
- eeprom->eedo = eedo;
- eeprom->address = address;
- eeprom->command = command;
-}
-
-uint16_t eeprom93xx_read(eeprom_t *eeprom)
-{
- /* Return status of pin DO (0 or 1). */
- logout("CS=%u DO=%u\n", eeprom->eecs, eeprom->eedo);
- return eeprom->eedo;
-}
-
-#if 0
-void eeprom93xx_reset(eeprom_t *eeprom)
-{
- /* prepare eeprom */
- logout("eeprom = 0x%p\n", eeprom);
- eeprom->tick = 0;
- eeprom->command = 0;
-}
-#endif
-
-eeprom_t *eeprom93xx_new(DeviceState *dev, uint16_t nwords)
-{
- /* Add a new EEPROM (with 16, 64 or 256 words). */
- eeprom_t *eeprom;
- uint8_t addrbits;
-
- switch (nwords) {
- case 16:
- case 64:
- addrbits = 6;
- break;
- case 128:
- case 256:
- addrbits = 8;
- break;
- default:
- assert(!"Unsupported EEPROM size, fallback to 64 words!");
- nwords = 64;
- addrbits = 6;
- }
-
- eeprom = (eeprom_t *)g_malloc0(sizeof(*eeprom) + nwords * 2);
- eeprom->size = nwords;
- eeprom->addrbits = addrbits;
- /* Output DO is tristate, read results in 1. */
- eeprom->eedo = 1;
- logout("eeprom = 0x%p, nwords = %u\n", eeprom, nwords);
- vmstate_register(dev, 0, &vmstate_eeprom, eeprom);
- return eeprom;
-}
-
-void eeprom93xx_free(DeviceState *dev, eeprom_t *eeprom)
-{
- /* Destroy EEPROM. */
- logout("eeprom = 0x%p\n", eeprom);
- vmstate_unregister(dev, &vmstate_eeprom, eeprom);
- g_free(eeprom);
-}
-
-uint16_t *eeprom93xx_data(eeprom_t *eeprom)
-{
- /* Get EEPROM data array. */
- return &eeprom->contents[0];
-}
-
-/* eof */
diff --git a/qemu/hw/nvram/fw_cfg.c b/qemu/hw/nvram/fw_cfg.c
deleted file mode 100644
index 999f48028..000000000
--- a/qemu/hw/nvram/fw_cfg.c
+++ /dev/null
@@ -1,1099 +0,0 @@
-/*
- * QEMU Firmware configuration device emulation
- *
- * Copyright (c) 2008 Gleb Natapov
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/dma.h"
-#include "hw/isa/isa.h"
-#include "hw/nvram/fw_cfg.h"
-#include "hw/sysbus.h"
-#include "hw/boards.h"
-#include "trace.h"
-#include "qemu/error-report.h"
-#include "qemu/config-file.h"
-#include "qemu/cutils.h"
-
-#define FW_CFG_NAME "fw_cfg"
-#define FW_CFG_PATH "/machine/" FW_CFG_NAME
-
-#define TYPE_FW_CFG "fw_cfg"
-#define TYPE_FW_CFG_IO "fw_cfg_io"
-#define TYPE_FW_CFG_MEM "fw_cfg_mem"
-
-#define FW_CFG(obj) OBJECT_CHECK(FWCfgState, (obj), TYPE_FW_CFG)
-#define FW_CFG_IO(obj) OBJECT_CHECK(FWCfgIoState, (obj), TYPE_FW_CFG_IO)
-#define FW_CFG_MEM(obj) OBJECT_CHECK(FWCfgMemState, (obj), TYPE_FW_CFG_MEM)
-
-/* FW_CFG_VERSION bits */
-#define FW_CFG_VERSION 0x01
-#define FW_CFG_VERSION_DMA 0x02
-
-/* FW_CFG_DMA_CONTROL bits */
-#define FW_CFG_DMA_CTL_ERROR 0x01
-#define FW_CFG_DMA_CTL_READ 0x02
-#define FW_CFG_DMA_CTL_SKIP 0x04
-#define FW_CFG_DMA_CTL_SELECT 0x08
-
-#define FW_CFG_DMA_SIGNATURE 0x51454d5520434647ULL /* "QEMU CFG" */
-
-typedef struct FWCfgEntry {
- uint32_t len;
- uint8_t *data;
- void *callback_opaque;
- FWCfgReadCallback read_callback;
-} FWCfgEntry;
-
-struct FWCfgState {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- FWCfgEntry entries[2][FW_CFG_MAX_ENTRY];
- int entry_order[FW_CFG_MAX_ENTRY];
- FWCfgFiles *files;
- uint16_t cur_entry;
- uint32_t cur_offset;
- Notifier machine_ready;
-
- int fw_cfg_order_override;
-
- bool dma_enabled;
- dma_addr_t dma_addr;
- AddressSpace *dma_as;
- MemoryRegion dma_iomem;
-};
-
-struct FWCfgIoState {
- /*< private >*/
- FWCfgState parent_obj;
- /*< public >*/
-
- MemoryRegion comb_iomem;
- uint32_t iobase, dma_iobase;
-};
-
-struct FWCfgMemState {
- /*< private >*/
- FWCfgState parent_obj;
- /*< public >*/
-
- MemoryRegion ctl_iomem, data_iomem;
- uint32_t data_width;
- MemoryRegionOps wide_data_ops;
-};
-
-#define JPG_FILE 0
-#define BMP_FILE 1
-
-static char *read_splashfile(char *filename, gsize *file_sizep,
- int *file_typep)
-{
- GError *err = NULL;
- gboolean res;
- gchar *content;
- int file_type;
- unsigned int filehead;
- int bmp_bpp;
-
- 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);
- return NULL;
- }
-
- /* check file size */
- if (*file_sizep < 30) {
- goto error;
- }
-
- /* check magic ID */
- filehead = ((content[0] & 0xff) + (content[1] << 8)) & 0xffff;
- if (filehead == 0xd8ff) {
- file_type = JPG_FILE;
- } else if (filehead == 0x4d42) {
- file_type = BMP_FILE;
- } else {
- goto error;
- }
-
- /* check BMP bpp */
- if (file_type == BMP_FILE) {
- bmp_bpp = (content[28] + (content[29] << 8)) & 0xffff;
- if (bmp_bpp != 24) {
- goto error;
- }
- }
-
- /* return values */
- *file_typep = file_type;
-
- return content;
-
-error:
- error_report("splash file '%s' format not recognized; must be JPEG "
- "or 24 bit BMP", filename);
- g_free(content);
- return NULL;
-}
-
-static void fw_cfg_bootsplash(FWCfgState *s)
-{
- int boot_splash_time = -1;
- const char *boot_splash_filename = NULL;
- char *p;
- char *filename, *file_data;
- gsize file_size;
- int file_type;
- const char *temp;
-
- /* get user configuration */
- QemuOptsList *plist = qemu_find_opts("boot-opts");
- QemuOpts *opts = QTAILQ_FIRST(&plist->head);
- if (opts != NULL) {
- temp = qemu_opt_get(opts, "splash");
- if (temp != NULL) {
- boot_splash_filename = temp;
- }
- temp = qemu_opt_get(opts, "splash-time");
- if (temp != NULL) {
- p = (char *)temp;
- boot_splash_time = strtol(p, (char **)&p, 10);
- }
- }
-
- /* insert splash time if user configurated */
- if (boot_splash_time >= 0) {
- /* validate the input */
- if (boot_splash_time > 0xffff) {
- error_report("splash time is big than 65535, force it to 65535.");
- boot_splash_time = 0xffff;
- }
- /* use little endian format */
- qemu_extra_params_fw[0] = (uint8_t)(boot_splash_time & 0xff);
- qemu_extra_params_fw[1] = (uint8_t)((boot_splash_time >> 8) & 0xff);
- fw_cfg_add_file(s, "etc/boot-menu-wait", qemu_extra_params_fw, 2);
- }
-
- /* insert splash file if user configurated */
- if (boot_splash_filename != NULL) {
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, boot_splash_filename);
- if (filename == NULL) {
- error_report("failed to find file '%s'.", boot_splash_filename);
- return;
- }
-
- /* loading file data */
- file_data = read_splashfile(filename, &file_size, &file_type);
- if (file_data == NULL) {
- g_free(filename);
- return;
- }
- g_free(boot_splash_filedata);
- boot_splash_filedata = (uint8_t *)file_data;
- boot_splash_filedata_size = file_size;
-
- /* insert data */
- if (file_type == JPG_FILE) {
- fw_cfg_add_file(s, "bootsplash.jpg",
- boot_splash_filedata, boot_splash_filedata_size);
- } else {
- fw_cfg_add_file(s, "bootsplash.bmp",
- boot_splash_filedata, boot_splash_filedata_size);
- }
- g_free(filename);
- }
-}
-
-static void fw_cfg_reboot(FWCfgState *s)
-{
- int reboot_timeout = -1;
- char *p;
- const char *temp;
-
- /* get user configuration */
- QemuOptsList *plist = qemu_find_opts("boot-opts");
- QemuOpts *opts = QTAILQ_FIRST(&plist->head);
- if (opts != NULL) {
- temp = qemu_opt_get(opts, "reboot-timeout");
- if (temp != NULL) {
- p = (char *)temp;
- reboot_timeout = strtol(p, (char **)&p, 10);
- }
- }
- /* validate the input */
- if (reboot_timeout > 0xffff) {
- error_report("reboot timeout is larger than 65535, force it to 65535.");
- reboot_timeout = 0xffff;
- }
- fw_cfg_add_file(s, "etc/boot-fail-wait", g_memdup(&reboot_timeout, 4), 4);
-}
-
-static void fw_cfg_write(FWCfgState *s, uint8_t value)
-{
- /* nothing, write support removed in QEMU v2.4+ */
-}
-
-static int fw_cfg_select(FWCfgState *s, uint16_t key)
-{
- int arch, ret;
- FWCfgEntry *e;
-
- s->cur_offset = 0;
- if ((key & FW_CFG_ENTRY_MASK) >= FW_CFG_MAX_ENTRY) {
- s->cur_entry = FW_CFG_INVALID;
- ret = 0;
- } else {
- s->cur_entry = key;
- ret = 1;
- /* entry successfully selected, now run callback if present */
- arch = !!(key & FW_CFG_ARCH_LOCAL);
- e = &s->entries[arch][key & FW_CFG_ENTRY_MASK];
- if (e->read_callback) {
- e->read_callback(e->callback_opaque);
- }
- }
-
- trace_fw_cfg_select(s, key, ret);
- return ret;
-}
-
-static uint64_t fw_cfg_data_read(void *opaque, hwaddr addr, unsigned size)
-{
- FWCfgState *s = opaque;
- int arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL);
- FWCfgEntry *e = (s->cur_entry == FW_CFG_INVALID) ? NULL :
- &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];
- uint64_t value = 0;
-
- assert(size > 0 && size <= sizeof(value));
- if (s->cur_entry != FW_CFG_INVALID && e->data && s->cur_offset < e->len) {
- /* The least significant 'size' bytes of the return value are
- * expected to contain a string preserving portion of the item
- * data, padded with zeros on the right in case we run out early.
- * In technical terms, we're composing the host-endian representation
- * of the big endian interpretation of the fw_cfg string.
- */
- do {
- value = (value << 8) | e->data[s->cur_offset++];
- } while (--size && s->cur_offset < e->len);
- /* If size is still not zero, we *did* run out early, so continue
- * left-shifting, to add the appropriate number of padding zeros
- * on the right.
- */
- value <<= 8 * size;
- }
-
- trace_fw_cfg_read(s, value);
- return value;
-}
-
-static void fw_cfg_data_mem_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- FWCfgState *s = opaque;
- unsigned i = size;
-
- do {
- fw_cfg_write(s, value >> (8 * --i));
- } while (i);
-}
-
-static void fw_cfg_dma_transfer(FWCfgState *s)
-{
- dma_addr_t len;
- FWCfgDmaAccess dma;
- int arch;
- FWCfgEntry *e;
- int read;
- dma_addr_t dma_addr;
-
- /* Reset the address before the next access */
- dma_addr = s->dma_addr;
- s->dma_addr = 0;
-
- if (dma_memory_read(s->dma_as, dma_addr, &dma, sizeof(dma))) {
- stl_be_dma(s->dma_as, dma_addr + offsetof(FWCfgDmaAccess, control),
- FW_CFG_DMA_CTL_ERROR);
- return;
- }
-
- dma.address = be64_to_cpu(dma.address);
- dma.length = be32_to_cpu(dma.length);
- dma.control = be32_to_cpu(dma.control);
-
- if (dma.control & FW_CFG_DMA_CTL_SELECT) {
- fw_cfg_select(s, dma.control >> 16);
- }
-
- arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL);
- e = (s->cur_entry == FW_CFG_INVALID) ? NULL :
- &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];
-
- if (dma.control & FW_CFG_DMA_CTL_READ) {
- read = 1;
- } else if (dma.control & FW_CFG_DMA_CTL_SKIP) {
- read = 0;
- } else {
- dma.length = 0;
- }
-
- dma.control = 0;
-
- while (dma.length > 0 && !(dma.control & FW_CFG_DMA_CTL_ERROR)) {
- if (s->cur_entry == FW_CFG_INVALID || !e->data ||
- s->cur_offset >= e->len) {
- len = dma.length;
-
- /* If the access is not a read access, it will be a skip access,
- * tested before.
- */
- if (read) {
- if (dma_memory_set(s->dma_as, dma.address, 0, len)) {
- dma.control |= FW_CFG_DMA_CTL_ERROR;
- }
- }
-
- } else {
- if (dma.length <= (e->len - s->cur_offset)) {
- len = dma.length;
- } else {
- len = (e->len - s->cur_offset);
- }
-
- /* If the access is not a read access, it will be a skip access,
- * tested before.
- */
- if (read) {
- if (dma_memory_write(s->dma_as, dma.address,
- &e->data[s->cur_offset], len)) {
- dma.control |= FW_CFG_DMA_CTL_ERROR;
- }
- }
-
- s->cur_offset += len;
- }
-
- dma.address += len;
- dma.length -= len;
-
- }
-
- stl_be_dma(s->dma_as, dma_addr + offsetof(FWCfgDmaAccess, control),
- dma.control);
-
- trace_fw_cfg_read(s, 0);
-}
-
-static uint64_t fw_cfg_dma_mem_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- /* Return a signature value (and handle various read sizes) */
- return extract64(FW_CFG_DMA_SIGNATURE, (8 - addr - size) * 8, size * 8);
-}
-
-static void fw_cfg_dma_mem_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- FWCfgState *s = opaque;
-
- if (size == 4) {
- if (addr == 0) {
- /* FWCfgDmaAccess high address */
- s->dma_addr = value << 32;
- } else if (addr == 4) {
- /* FWCfgDmaAccess low address */
- s->dma_addr |= value;
- fw_cfg_dma_transfer(s);
- }
- } else if (size == 8 && addr == 0) {
- s->dma_addr = value;
- fw_cfg_dma_transfer(s);
- }
-}
-
-static bool fw_cfg_dma_mem_valid(void *opaque, hwaddr addr,
- unsigned size, bool is_write)
-{
- return !is_write || ((size == 4 && (addr == 0 || addr == 4)) ||
- (size == 8 && addr == 0));
-}
-
-static bool fw_cfg_data_mem_valid(void *opaque, hwaddr addr,
- unsigned size, bool is_write)
-{
- return addr == 0;
-}
-
-static void fw_cfg_ctl_mem_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- fw_cfg_select(opaque, (uint16_t)value);
-}
-
-static bool fw_cfg_ctl_mem_valid(void *opaque, hwaddr addr,
- unsigned size, bool is_write)
-{
- return is_write && size == 2;
-}
-
-static void fw_cfg_comb_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- switch (size) {
- case 1:
- fw_cfg_write(opaque, (uint8_t)value);
- break;
- case 2:
- fw_cfg_select(opaque, (uint16_t)value);
- break;
- }
-}
-
-static bool fw_cfg_comb_valid(void *opaque, hwaddr addr,
- unsigned size, bool is_write)
-{
- return (size == 1) || (is_write && size == 2);
-}
-
-static const MemoryRegionOps fw_cfg_ctl_mem_ops = {
- .write = fw_cfg_ctl_mem_write,
- .endianness = DEVICE_BIG_ENDIAN,
- .valid.accepts = fw_cfg_ctl_mem_valid,
-};
-
-static const MemoryRegionOps fw_cfg_data_mem_ops = {
- .read = fw_cfg_data_read,
- .write = fw_cfg_data_mem_write,
- .endianness = DEVICE_BIG_ENDIAN,
- .valid = {
- .min_access_size = 1,
- .max_access_size = 1,
- .accepts = fw_cfg_data_mem_valid,
- },
-};
-
-static const MemoryRegionOps fw_cfg_comb_mem_ops = {
- .read = fw_cfg_data_read,
- .write = fw_cfg_comb_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .valid.accepts = fw_cfg_comb_valid,
-};
-
-static const MemoryRegionOps fw_cfg_dma_mem_ops = {
- .read = fw_cfg_dma_mem_read,
- .write = fw_cfg_dma_mem_write,
- .endianness = DEVICE_BIG_ENDIAN,
- .valid.accepts = fw_cfg_dma_mem_valid,
- .valid.max_access_size = 8,
- .impl.max_access_size = 8,
-};
-
-static void fw_cfg_reset(DeviceState *d)
-{
- FWCfgState *s = FW_CFG(d);
-
- /* we never register a read callback for FW_CFG_SIGNATURE */
- fw_cfg_select(s, FW_CFG_SIGNATURE);
-}
-
-/* Save restore 32 bit int as uint16_t
- This is a Big hack, but it is how the old state did it.
- Or we broke compatibility in the state, or we can't use struct tm
- */
-
-static int get_uint32_as_uint16(QEMUFile *f, void *pv, size_t size)
-{
- uint32_t *v = pv;
- *v = qemu_get_be16(f);
- return 0;
-}
-
-static void put_unused(QEMUFile *f, void *pv, size_t size)
-{
- fprintf(stderr, "uint32_as_uint16 is only used for backward compatibility.\n");
- fprintf(stderr, "This functions shouldn't be called.\n");
-}
-
-static const VMStateInfo vmstate_hack_uint32_as_uint16 = {
- .name = "int32_as_uint16",
- .get = get_uint32_as_uint16,
- .put = put_unused,
-};
-
-#define VMSTATE_UINT16_HACK(_f, _s, _t) \
- VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_hack_uint32_as_uint16, uint32_t)
-
-
-static bool is_version_1(void *opaque, int version_id)
-{
- return version_id == 1;
-}
-
-static bool fw_cfg_dma_enabled(void *opaque)
-{
- FWCfgState *s = opaque;
-
- return s->dma_enabled;
-}
-
-static const VMStateDescription vmstate_fw_cfg_dma = {
- .name = "fw_cfg/dma",
- .needed = fw_cfg_dma_enabled,
- .fields = (VMStateField[]) {
- VMSTATE_UINT64(dma_addr, FWCfgState),
- VMSTATE_END_OF_LIST()
- },
-};
-
-static const VMStateDescription vmstate_fw_cfg = {
- .name = "fw_cfg",
- .version_id = 2,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT16(cur_entry, FWCfgState),
- VMSTATE_UINT16_HACK(cur_offset, FWCfgState, is_version_1),
- VMSTATE_UINT32_V(cur_offset, FWCfgState, 2),
- VMSTATE_END_OF_LIST()
- },
- .subsections = (const VMStateDescription*[]) {
- &vmstate_fw_cfg_dma,
- NULL,
- }
-};
-
-static void fw_cfg_add_bytes_read_callback(FWCfgState *s, uint16_t key,
- FWCfgReadCallback callback,
- void *callback_opaque,
- void *data, size_t len)
-{
- int arch = !!(key & FW_CFG_ARCH_LOCAL);
-
- key &= FW_CFG_ENTRY_MASK;
-
- assert(key < FW_CFG_MAX_ENTRY && len < UINT32_MAX);
- assert(s->entries[arch][key].data == NULL); /* avoid key conflict */
-
- s->entries[arch][key].data = data;
- s->entries[arch][key].len = (uint32_t)len;
- s->entries[arch][key].read_callback = callback;
- s->entries[arch][key].callback_opaque = callback_opaque;
-}
-
-static void *fw_cfg_modify_bytes_read(FWCfgState *s, uint16_t key,
- void *data, size_t len)
-{
- void *ptr;
- int arch = !!(key & FW_CFG_ARCH_LOCAL);
-
- key &= FW_CFG_ENTRY_MASK;
-
- assert(key < FW_CFG_MAX_ENTRY && len < UINT32_MAX);
-
- /* return the old data to the function caller, avoid memory leak */
- ptr = s->entries[arch][key].data;
- s->entries[arch][key].data = data;
- s->entries[arch][key].len = len;
- s->entries[arch][key].callback_opaque = NULL;
-
- return ptr;
-}
-
-void fw_cfg_add_bytes(FWCfgState *s, uint16_t key, void *data, size_t len)
-{
- fw_cfg_add_bytes_read_callback(s, key, NULL, NULL, data, len);
-}
-
-void fw_cfg_add_string(FWCfgState *s, uint16_t key, const char *value)
-{
- size_t sz = strlen(value) + 1;
-
- fw_cfg_add_bytes(s, key, g_memdup(value, sz), sz);
-}
-
-void fw_cfg_add_i16(FWCfgState *s, uint16_t key, uint16_t value)
-{
- uint16_t *copy;
-
- copy = g_malloc(sizeof(value));
- *copy = cpu_to_le16(value);
- fw_cfg_add_bytes(s, key, copy, sizeof(value));
-}
-
-void fw_cfg_modify_i16(FWCfgState *s, uint16_t key, uint16_t value)
-{
- uint16_t *copy, *old;
-
- copy = g_malloc(sizeof(value));
- *copy = cpu_to_le16(value);
- old = fw_cfg_modify_bytes_read(s, key, copy, sizeof(value));
- g_free(old);
-}
-
-void fw_cfg_add_i32(FWCfgState *s, uint16_t key, uint32_t value)
-{
- uint32_t *copy;
-
- copy = g_malloc(sizeof(value));
- *copy = cpu_to_le32(value);
- fw_cfg_add_bytes(s, key, copy, sizeof(value));
-}
-
-void fw_cfg_add_i64(FWCfgState *s, uint16_t key, uint64_t value)
-{
- uint64_t *copy;
-
- copy = g_malloc(sizeof(value));
- *copy = cpu_to_le64(value);
- fw_cfg_add_bytes(s, key, copy, sizeof(value));
-}
-
-void fw_cfg_set_order_override(FWCfgState *s, int order)
-{
- assert(s->fw_cfg_order_override == 0);
- s->fw_cfg_order_override = order;
-}
-
-void fw_cfg_reset_order_override(FWCfgState *s)
-{
- assert(s->fw_cfg_order_override != 0);
- s->fw_cfg_order_override = 0;
-}
-
-/*
- * This is the legacy order list. For legacy systems, files are in
- * the fw_cfg in the order defined below, by the "order" value. Note
- * that some entries (VGA ROMs, NIC option ROMS, etc.) go into a
- * specific area, but there may be more than one and they occur in the
- * order that the user specifies them on the command line. Those are
- * handled in a special manner, using the order override above.
- *
- * For non-legacy, the files are sorted by filename to avoid this kind
- * of complexity in the future.
- *
- * This is only for x86, other arches don't implement versioning so
- * they won't set legacy mode.
- */
-static struct {
- const char *name;
- int order;
-} fw_cfg_order[] = {
- { "etc/boot-menu-wait", 10 },
- { "bootsplash.jpg", 11 },
- { "bootsplash.bmp", 12 },
- { "etc/boot-fail-wait", 15 },
- { "etc/smbios/smbios-tables", 20 },
- { "etc/smbios/smbios-anchor", 30 },
- { "etc/e820", 40 },
- { "etc/reserved-memory-end", 50 },
- { "genroms/kvmvapic.bin", 55 },
- { "genroms/linuxboot.bin", 60 },
- { }, /* VGA ROMs from pc_vga_init come here, 70. */
- { }, /* NIC option ROMs from pc_nic_init come here, 80. */
- { "etc/system-states", 90 },
- { }, /* User ROMs come here, 100. */
- { }, /* Device FW comes here, 110. */
- { "etc/extra-pci-roots", 120 },
- { "etc/acpi/tables", 130 },
- { "etc/table-loader", 140 },
- { "etc/tpm/log", 150 },
- { "etc/acpi/rsdp", 160 },
- { "bootorder", 170 },
-
-#define FW_CFG_ORDER_OVERRIDE_LAST 200
-};
-
-static int get_fw_cfg_order(FWCfgState *s, const char *name)
-{
- int i;
-
- if (s->fw_cfg_order_override > 0)
- return s->fw_cfg_order_override;
-
- for (i = 0; i < ARRAY_SIZE(fw_cfg_order); i++) {
- if (fw_cfg_order[i].name == NULL)
- continue;
- if (strcmp(name, fw_cfg_order[i].name) == 0)
- return fw_cfg_order[i].order;
- }
- /* Stick unknown stuff at the end. */
- error_report("warning: Unknown firmware file in legacy mode: %s\n", name);
- return FW_CFG_ORDER_OVERRIDE_LAST;
-}
-
-void fw_cfg_add_file_callback(FWCfgState *s, const char *filename,
- FWCfgReadCallback callback, void *callback_opaque,
- void *data, size_t len)
-{
- int i, index, count;
- size_t dsize;
- MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
- int order = 0;
-
- if (!s->files) {
- dsize = sizeof(uint32_t) + sizeof(FWCfgFile) * FW_CFG_FILE_SLOTS;
- s->files = g_malloc0(dsize);
- fw_cfg_add_bytes(s, FW_CFG_FILE_DIR, s->files, dsize);
- }
-
- count = be32_to_cpu(s->files->count);
- assert(count < FW_CFG_FILE_SLOTS);
-
- /* Find the insertion point. */
- if (mc->legacy_fw_cfg_order) {
- /*
- * Sort by order. For files with the same order, we keep them
- * in the sequence in which they were added.
- */
- order = get_fw_cfg_order(s, filename);
- for (index = count;
- index > 0 && order < s->entry_order[index - 1];
- index--);
- } else {
- /* Sort by file name. */
- for (index = count;
- index > 0 && strcmp(filename, s->files->f[index - 1].name) < 0;
- index--);
- }
-
- /*
- * Move all the entries from the index point and after down one
- * to create a slot for the new entry. Because calculations are
- * being done with the index, make it so that "i" is the current
- * index and "i - 1" is the one being copied from, thus the
- * unusual start and end in the for statement.
- */
- for (i = count + 1; i > index; i--) {
- s->files->f[i] = s->files->f[i - 1];
- s->files->f[i].select = cpu_to_be16(FW_CFG_FILE_FIRST + i);
- s->entries[0][FW_CFG_FILE_FIRST + i] =
- s->entries[0][FW_CFG_FILE_FIRST + i - 1];
- s->entry_order[i] = s->entry_order[i - 1];
- }
-
- memset(&s->files->f[index], 0, sizeof(FWCfgFile));
- memset(&s->entries[0][FW_CFG_FILE_FIRST + index], 0, sizeof(FWCfgEntry));
-
- pstrcpy(s->files->f[index].name, sizeof(s->files->f[index].name), filename);
- for (i = 0; i <= count; i++) {
- if (i != index &&
- strcmp(s->files->f[index].name, s->files->f[i].name) == 0) {
- error_report("duplicate fw_cfg file name: %s",
- s->files->f[index].name);
- exit(1);
- }
- }
-
- fw_cfg_add_bytes_read_callback(s, FW_CFG_FILE_FIRST + index,
- callback, callback_opaque, data, len);
-
- s->files->f[index].size = cpu_to_be32(len);
- s->files->f[index].select = cpu_to_be16(FW_CFG_FILE_FIRST + index);
- s->entry_order[index] = order;
- trace_fw_cfg_add_file(s, index, s->files->f[index].name, len);
-
- s->files->count = cpu_to_be32(count+1);
-}
-
-void fw_cfg_add_file(FWCfgState *s, const char *filename,
- void *data, size_t len)
-{
- fw_cfg_add_file_callback(s, filename, NULL, NULL, data, len);
-}
-
-void *fw_cfg_modify_file(FWCfgState *s, const char *filename,
- void *data, size_t len)
-{
- int i, index;
- void *ptr = NULL;
-
- assert(s->files);
-
- index = be32_to_cpu(s->files->count);
- assert(index < FW_CFG_FILE_SLOTS);
-
- for (i = 0; i < index; i++) {
- if (strcmp(filename, s->files->f[i].name) == 0) {
- ptr = fw_cfg_modify_bytes_read(s, FW_CFG_FILE_FIRST + i,
- data, len);
- s->files->f[i].size = cpu_to_be32(len);
- return ptr;
- }
- }
- /* add new one */
- fw_cfg_add_file_callback(s, filename, NULL, NULL, data, len);
- return NULL;
-}
-
-static void fw_cfg_machine_reset(void *opaque)
-{
- void *ptr;
- size_t len;
- FWCfgState *s = opaque;
- char *bootindex = get_boot_devices_list(&len, false);
-
- ptr = fw_cfg_modify_file(s, "bootorder", (uint8_t *)bootindex, len);
- g_free(ptr);
-}
-
-static void fw_cfg_machine_ready(struct Notifier *n, void *data)
-{
- FWCfgState *s = container_of(n, FWCfgState, machine_ready);
- qemu_register_reset(fw_cfg_machine_reset, s);
-}
-
-
-
-static void fw_cfg_init1(DeviceState *dev)
-{
- FWCfgState *s = FW_CFG(dev);
-
- assert(!object_resolve_path(FW_CFG_PATH, NULL));
-
- object_property_add_child(qdev_get_machine(), FW_CFG_NAME, OBJECT(s), NULL);
-
- qdev_init_nofail(dev);
-
- fw_cfg_add_bytes(s, FW_CFG_SIGNATURE, (char *)"QEMU", 4);
- 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_BOOT_MENU, (uint16_t)boot_menu);
- fw_cfg_bootsplash(s);
- fw_cfg_reboot(s);
-
- s->machine_ready.notify = fw_cfg_machine_ready;
- qemu_add_machine_init_done_notifier(&s->machine_ready);
-}
-
-FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
- AddressSpace *dma_as)
-{
- DeviceState *dev;
- FWCfgState *s;
- uint32_t version = FW_CFG_VERSION;
- bool dma_requested = dma_iobase && dma_as;
-
- dev = qdev_create(NULL, TYPE_FW_CFG_IO);
- qdev_prop_set_uint32(dev, "iobase", iobase);
- qdev_prop_set_uint32(dev, "dma_iobase", dma_iobase);
- if (!dma_requested) {
- qdev_prop_set_bit(dev, "dma_enabled", false);
- }
-
- fw_cfg_init1(dev);
- s = FW_CFG(dev);
-
- if (s->dma_enabled) {
- /* 64 bits for the address field */
- s->dma_as = dma_as;
- s->dma_addr = 0;
-
- version |= FW_CFG_VERSION_DMA;
- }
-
- fw_cfg_add_i32(s, FW_CFG_ID, version);
-
- return s;
-}
-
-FWCfgState *fw_cfg_init_io(uint32_t iobase)
-{
- return fw_cfg_init_io_dma(iobase, 0, NULL);
-}
-
-FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr,
- hwaddr data_addr, uint32_t data_width,
- hwaddr dma_addr, AddressSpace *dma_as)
-{
- DeviceState *dev;
- SysBusDevice *sbd;
- FWCfgState *s;
- uint32_t version = FW_CFG_VERSION;
- bool dma_requested = dma_addr && dma_as;
-
- dev = qdev_create(NULL, TYPE_FW_CFG_MEM);
- qdev_prop_set_uint32(dev, "data_width", data_width);
- if (!dma_requested) {
- qdev_prop_set_bit(dev, "dma_enabled", false);
- }
-
- fw_cfg_init1(dev);
-
- sbd = SYS_BUS_DEVICE(dev);
- sysbus_mmio_map(sbd, 0, ctl_addr);
- sysbus_mmio_map(sbd, 1, data_addr);
-
- s = FW_CFG(dev);
-
- if (s->dma_enabled) {
- s->dma_as = dma_as;
- s->dma_addr = 0;
- sysbus_mmio_map(sbd, 2, dma_addr);
- version |= FW_CFG_VERSION_DMA;
- }
-
- fw_cfg_add_i32(s, FW_CFG_ID, version);
-
- return s;
-}
-
-FWCfgState *fw_cfg_init_mem(hwaddr ctl_addr, hwaddr data_addr)
-{
- return fw_cfg_init_mem_wide(ctl_addr, data_addr,
- fw_cfg_data_mem_ops.valid.max_access_size,
- 0, NULL);
-}
-
-
-FWCfgState *fw_cfg_find(void)
-{
- return FW_CFG(object_resolve_path(FW_CFG_PATH, NULL));
-}
-
-static void fw_cfg_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->reset = fw_cfg_reset;
- dc->vmsd = &vmstate_fw_cfg;
-}
-
-static const TypeInfo fw_cfg_info = {
- .name = TYPE_FW_CFG,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(FWCfgState),
- .class_init = fw_cfg_class_init,
-};
-
-
-static Property fw_cfg_io_properties[] = {
- DEFINE_PROP_UINT32("iobase", FWCfgIoState, iobase, -1),
- DEFINE_PROP_UINT32("dma_iobase", FWCfgIoState, dma_iobase, -1),
- DEFINE_PROP_BOOL("dma_enabled", FWCfgIoState, parent_obj.dma_enabled,
- true),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void fw_cfg_io_realize(DeviceState *dev, Error **errp)
-{
- FWCfgIoState *s = FW_CFG_IO(dev);
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
-
- /* when using port i/o, the 8-bit data register ALWAYS overlaps
- * with half of the 16-bit control register. Hence, the total size
- * of the i/o region used is FW_CFG_CTL_SIZE */
- memory_region_init_io(&s->comb_iomem, OBJECT(s), &fw_cfg_comb_mem_ops,
- FW_CFG(s), "fwcfg", FW_CFG_CTL_SIZE);
- sysbus_add_io(sbd, s->iobase, &s->comb_iomem);
-
- if (FW_CFG(s)->dma_enabled) {
- memory_region_init_io(&FW_CFG(s)->dma_iomem, OBJECT(s),
- &fw_cfg_dma_mem_ops, FW_CFG(s), "fwcfg.dma",
- sizeof(dma_addr_t));
- sysbus_add_io(sbd, s->dma_iobase, &FW_CFG(s)->dma_iomem);
- }
-}
-
-static void fw_cfg_io_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = fw_cfg_io_realize;
- dc->props = fw_cfg_io_properties;
-}
-
-static const TypeInfo fw_cfg_io_info = {
- .name = TYPE_FW_CFG_IO,
- .parent = TYPE_FW_CFG,
- .instance_size = sizeof(FWCfgIoState),
- .class_init = fw_cfg_io_class_init,
-};
-
-
-static Property fw_cfg_mem_properties[] = {
- DEFINE_PROP_UINT32("data_width", FWCfgMemState, data_width, -1),
- DEFINE_PROP_BOOL("dma_enabled", FWCfgMemState, parent_obj.dma_enabled,
- true),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void fw_cfg_mem_realize(DeviceState *dev, Error **errp)
-{
- FWCfgMemState *s = FW_CFG_MEM(dev);
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- const MemoryRegionOps *data_ops = &fw_cfg_data_mem_ops;
-
- memory_region_init_io(&s->ctl_iomem, OBJECT(s), &fw_cfg_ctl_mem_ops,
- FW_CFG(s), "fwcfg.ctl", FW_CFG_CTL_SIZE);
- sysbus_init_mmio(sbd, &s->ctl_iomem);
-
- if (s->data_width > data_ops->valid.max_access_size) {
- /* memberwise copy because the "old_mmio" member is const */
- s->wide_data_ops.read = data_ops->read;
- s->wide_data_ops.write = data_ops->write;
- s->wide_data_ops.endianness = data_ops->endianness;
- s->wide_data_ops.valid = data_ops->valid;
- s->wide_data_ops.impl = data_ops->impl;
-
- s->wide_data_ops.valid.max_access_size = s->data_width;
- s->wide_data_ops.impl.max_access_size = s->data_width;
- data_ops = &s->wide_data_ops;
- }
- memory_region_init_io(&s->data_iomem, OBJECT(s), data_ops, FW_CFG(s),
- "fwcfg.data", data_ops->valid.max_access_size);
- sysbus_init_mmio(sbd, &s->data_iomem);
-
- if (FW_CFG(s)->dma_enabled) {
- memory_region_init_io(&FW_CFG(s)->dma_iomem, OBJECT(s),
- &fw_cfg_dma_mem_ops, FW_CFG(s), "fwcfg.dma",
- sizeof(dma_addr_t));
- sysbus_init_mmio(sbd, &FW_CFG(s)->dma_iomem);
- }
-}
-
-static void fw_cfg_mem_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = fw_cfg_mem_realize;
- dc->props = fw_cfg_mem_properties;
-}
-
-static const TypeInfo fw_cfg_mem_info = {
- .name = TYPE_FW_CFG_MEM,
- .parent = TYPE_FW_CFG,
- .instance_size = sizeof(FWCfgMemState),
- .class_init = fw_cfg_mem_class_init,
-};
-
-
-static void fw_cfg_register_types(void)
-{
- type_register_static(&fw_cfg_info);
- type_register_static(&fw_cfg_io_info);
- type_register_static(&fw_cfg_mem_info);
-}
-
-type_init(fw_cfg_register_types)
diff --git a/qemu/hw/nvram/mac_nvram.c b/qemu/hw/nvram/mac_nvram.c
deleted file mode 100644
index 24f61212b..000000000
--- a/qemu/hw/nvram/mac_nvram.c
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * PowerMac NVRAM emulation
- *
- * Copyright (c) 2005-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.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/nvram/openbios_firmware_abi.h"
-#include "sysemu/sysemu.h"
-#include "hw/ppc/mac.h"
-#include "qemu/cutils.h"
-#include <zlib.h>
-
-/* debug NVR */
-//#define DEBUG_NVR
-
-#ifdef DEBUG_NVR
-#define NVR_DPRINTF(fmt, ...) \
- do { printf("NVR: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define NVR_DPRINTF(fmt, ...)
-#endif
-
-#define DEF_SYSTEM_SIZE 0xc10
-
-/* macio style NVRAM device */
-static void macio_nvram_writeb(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- MacIONVRAMState *s = opaque;
-
- addr = (addr >> s->it_shift) & (s->size - 1);
- s->data[addr] = value;
- NVR_DPRINTF("writeb addr %04" HWADDR_PRIx " val %" PRIx64 "\n",
- addr, value);
-}
-
-static uint64_t macio_nvram_readb(void *opaque, hwaddr addr,
- unsigned size)
-{
- MacIONVRAMState *s = opaque;
- uint32_t value;
-
- addr = (addr >> s->it_shift) & (s->size - 1);
- value = s->data[addr];
- NVR_DPRINTF("readb addr %04" HWADDR_PRIx " val %" PRIx32 "\n",
- addr, value);
-
- return value;
-}
-
-static const MemoryRegionOps macio_nvram_ops = {
- .read = macio_nvram_readb,
- .write = macio_nvram_writeb,
- .valid.min_access_size = 1,
- .valid.max_access_size = 4,
- .impl.min_access_size = 1,
- .impl.max_access_size = 1,
- .endianness = DEVICE_BIG_ENDIAN,
-};
-
-static const VMStateDescription vmstate_macio_nvram = {
- .name = "macio_nvram",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_VBUFFER_UINT32(data, MacIONVRAMState, 0, NULL, 0, size),
- VMSTATE_END_OF_LIST()
- }
-};
-
-
-static void macio_nvram_reset(DeviceState *dev)
-{
-}
-
-static void macio_nvram_realizefn(DeviceState *dev, Error **errp)
-{
- SysBusDevice *d = SYS_BUS_DEVICE(dev);
- MacIONVRAMState *s = MACIO_NVRAM(dev);
-
- s->data = g_malloc0(s->size);
-
- memory_region_init_io(&s->mem, OBJECT(s), &macio_nvram_ops, s,
- "macio-nvram", 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);
-
- g_free(s->data);
-}
-
-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)
-{
- 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;
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
-}
-
-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 */
-static void pmac_format_nvram_partition_of(MacIONVRAMState *nvr, int off,
- int len)
-{
- unsigned int i;
- uint32_t start = off, end;
- struct OpenBIOS_nvpart_v1 *part_header;
-
- // OpenBIOS nvram variables
- // Variable partition
- part_header = (struct OpenBIOS_nvpart_v1 *)&nvr->data[start];
- part_header->signature = OPENBIOS_PART_SYSTEM;
- pstrcpy(part_header->name, sizeof(part_header->name), "system");
-
- end = start + sizeof(struct OpenBIOS_nvpart_v1);
- for (i = 0; i < nb_prom_envs; i++)
- end = OpenBIOS_set_var(nvr->data, end, prom_envs[i]);
-
- // End marker
- nvr->data[end++] = '\0';
-
- end = start + ((end - start + 15) & ~15);
- /* XXX: OpenBIOS is not able to grow up a partition. Leave some space for
- new variables. */
- if (end < DEF_SYSTEM_SIZE)
- end = DEF_SYSTEM_SIZE;
- OpenBIOS_finish_partition(part_header, end - start);
-
- // free partition
- start = end;
- part_header = (struct OpenBIOS_nvpart_v1 *)&nvr->data[start];
- part_header->signature = OPENBIOS_PART_FREE;
- pstrcpy(part_header->name, sizeof(part_header->name), "free");
-
- end = len;
- OpenBIOS_finish_partition(part_header, end - start);
-}
-
-#define OSX_NVRAM_SIGNATURE (0x5A)
-
-/* Set up a Mac OS X NVRAM partition */
-static void pmac_format_nvram_partition_osx(MacIONVRAMState *nvr, int off,
- int len)
-{
- uint32_t start = off;
- struct OpenBIOS_nvpart_v1 *part_header;
- unsigned char *data = &nvr->data[start];
-
- /* empty partition */
- part_header = (struct OpenBIOS_nvpart_v1 *)data;
- part_header->signature = OSX_NVRAM_SIGNATURE;
- pstrcpy(part_header->name, sizeof(part_header->name), "wwwwwwwwwwww");
-
- OpenBIOS_finish_partition(part_header, len);
-
- /* Generation */
- stl_be_p(&data[20], 2);
-
- /* Adler32 checksum */
- stl_be_p(&data[16], adler32(0, &data[20], len - 20));
-}
-
-/* Set up NVRAM with OF and OSX partitions */
-void pmac_format_nvram_partition(MacIONVRAMState *nvr, int len)
-{
- /*
- * Mac OS X expects side "B" of the flash at the second half of NVRAM,
- * so we use half of the chip for OF and the other half for a free OSX
- * partition.
- */
- pmac_format_nvram_partition_of(nvr, 0, len / 2);
- pmac_format_nvram_partition_osx(nvr, len / 2, len / 2);
-}
-type_init(macio_nvram_register_types)
diff --git a/qemu/hw/nvram/spapr_nvram.c b/qemu/hw/nvram/spapr_nvram.c
deleted file mode 100644
index 802636ef3..000000000
--- a/qemu/hw/nvram/spapr_nvram.c
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * QEMU sPAPR NVRAM emulation
- *
- * Copyright (C) 2012 David Gibson, IBM Corporation.
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include <libfdt.h>
-
-#include "sysemu/block-backend.h"
-#include "sysemu/device_tree.h"
-#include "hw/sysbus.h"
-#include "hw/ppc/spapr.h"
-#include "hw/ppc/spapr_vio.h"
-
-typedef struct sPAPRNVRAM {
- VIOsPAPRDevice sdev;
- uint32_t size;
- uint8_t *buf;
- BlockBackend *blk;
-} sPAPRNVRAM;
-
-#define TYPE_VIO_SPAPR_NVRAM "spapr-nvram"
-#define VIO_SPAPR_NVRAM(obj) \
- OBJECT_CHECK(sPAPRNVRAM, (obj), TYPE_VIO_SPAPR_NVRAM)
-
-#define MIN_NVRAM_SIZE 8192
-#define DEFAULT_NVRAM_SIZE 65536
-#define MAX_NVRAM_SIZE 1048576
-
-static void rtas_nvram_fetch(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- uint32_t token, uint32_t nargs,
- target_ulong args,
- uint32_t nret, target_ulong rets)
-{
- sPAPRNVRAM *nvram = spapr->nvram;
- hwaddr offset, buffer, len;
- void *membuf;
-
- if ((nargs != 3) || (nret != 2)) {
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
- return;
- }
-
- if (!nvram) {
- rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
- rtas_st(rets, 1, 0);
- return;
- }
-
- offset = rtas_ld(args, 0);
- buffer = rtas_ld(args, 1);
- len = rtas_ld(args, 2);
-
- if (((offset + len) < offset)
- || ((offset + len) > nvram->size)) {
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
- rtas_st(rets, 1, 0);
- return;
- }
-
- assert(nvram->buf);
-
- membuf = cpu_physical_memory_map(buffer, &len, 1);
- memcpy(membuf, nvram->buf + offset, len);
- cpu_physical_memory_unmap(membuf, len, 1, len);
-
- rtas_st(rets, 0, RTAS_OUT_SUCCESS);
- rtas_st(rets, 1, len);
-}
-
-static void rtas_nvram_store(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- uint32_t token, uint32_t nargs,
- target_ulong args,
- uint32_t nret, target_ulong rets)
-{
- sPAPRNVRAM *nvram = spapr->nvram;
- hwaddr offset, buffer, len;
- int alen;
- void *membuf;
-
- if ((nargs != 3) || (nret != 2)) {
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
- return;
- }
-
- if (!nvram) {
- rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
- return;
- }
-
- offset = rtas_ld(args, 0);
- buffer = rtas_ld(args, 1);
- len = rtas_ld(args, 2);
-
- if (((offset + len) < offset)
- || ((offset + len) > nvram->size)) {
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
- return;
- }
-
- membuf = cpu_physical_memory_map(buffer, &len, 0);
-
- alen = len;
- if (nvram->blk) {
- alen = blk_pwrite(nvram->blk, offset, membuf, len);
- }
-
- assert(nvram->buf);
- memcpy(nvram->buf + offset, membuf, len);
-
- cpu_physical_memory_unmap(membuf, len, 0, len);
-
- rtas_st(rets, 0, (alen < len) ? RTAS_OUT_HW_ERROR : RTAS_OUT_SUCCESS);
- rtas_st(rets, 1, (alen < 0) ? 0 : alen);
-}
-
-static void spapr_nvram_realize(VIOsPAPRDevice *dev, Error **errp)
-{
- sPAPRNVRAM *nvram = VIO_SPAPR_NVRAM(dev);
-
- if (nvram->blk) {
- nvram->size = blk_getlength(nvram->blk);
- } else {
- nvram->size = DEFAULT_NVRAM_SIZE;
- }
-
- nvram->buf = g_malloc0(nvram->size);
-
- if ((nvram->size < MIN_NVRAM_SIZE) || (nvram->size > MAX_NVRAM_SIZE)) {
- error_setg(errp, "spapr-nvram must be between %d and %d bytes in size",
- MIN_NVRAM_SIZE, MAX_NVRAM_SIZE);
- return;
- }
-
- if (nvram->blk) {
- int alen = blk_pread(nvram->blk, 0, nvram->buf, nvram->size);
-
- if (alen != nvram->size) {
- error_setg(errp, "can't read spapr-nvram contents");
- return;
- }
- }
-
- spapr_rtas_register(RTAS_NVRAM_FETCH, "nvram-fetch", rtas_nvram_fetch);
- spapr_rtas_register(RTAS_NVRAM_STORE, "nvram-store", rtas_nvram_store);
-}
-
-static int spapr_nvram_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off)
-{
- sPAPRNVRAM *nvram = VIO_SPAPR_NVRAM(dev);
-
- return fdt_setprop_cell(fdt, node_off, "#bytes", nvram->size);
-}
-
-static int spapr_nvram_pre_load(void *opaque)
-{
- sPAPRNVRAM *nvram = VIO_SPAPR_NVRAM(opaque);
-
- g_free(nvram->buf);
- nvram->buf = NULL;
- nvram->size = 0;
-
- return 0;
-}
-
-static int spapr_nvram_post_load(void *opaque, int version_id)
-{
- sPAPRNVRAM *nvram = VIO_SPAPR_NVRAM(opaque);
-
- if (nvram->blk) {
- int alen = blk_pwrite(nvram->blk, 0, nvram->buf, nvram->size);
-
- if (alen < 0) {
- return alen;
- }
- if (alen != nvram->size) {
- return -1;
- }
- }
-
- return 0;
-}
-
-static const VMStateDescription vmstate_spapr_nvram = {
- .name = "spapr_nvram",
- .version_id = 1,
- .minimum_version_id = 1,
- .pre_load = spapr_nvram_pre_load,
- .post_load = spapr_nvram_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(size, sPAPRNVRAM),
- VMSTATE_VBUFFER_ALLOC_UINT32(buf, sPAPRNVRAM, 1, NULL, 0, size),
- VMSTATE_END_OF_LIST()
- },
-};
-
-static Property spapr_nvram_properties[] = {
- DEFINE_SPAPR_PROPERTIES(sPAPRNVRAM, sdev),
- DEFINE_PROP_DRIVE("drive", sPAPRNVRAM, blk),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void spapr_nvram_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
-
- k->realize = spapr_nvram_realize;
- k->devnode = spapr_nvram_devnode;
- k->dt_name = "nvram";
- k->dt_type = "nvram";
- k->dt_compatible = "qemu,spapr-nvram";
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- dc->props = spapr_nvram_properties;
- dc->vmsd = &vmstate_spapr_nvram;
-}
-
-static const TypeInfo spapr_nvram_type_info = {
- .name = TYPE_VIO_SPAPR_NVRAM,
- .parent = TYPE_VIO_SPAPR_DEVICE,
- .instance_size = sizeof(sPAPRNVRAM),
- .class_init = spapr_nvram_class_init,
-};
-
-static void spapr_nvram_register_types(void)
-{
- type_register_static(&spapr_nvram_type_info);
-}
-
-type_init(spapr_nvram_register_types)
diff --git a/qemu/hw/openrisc/Makefile.objs b/qemu/hw/openrisc/Makefile.objs
deleted file mode 100644
index 61246b149..000000000
--- a/qemu/hw/openrisc/Makefile.objs
+++ /dev/null
@@ -1,2 +0,0 @@
-obj-y = pic_cpu.o cputimer.o
-obj-y += openrisc_sim.o
diff --git a/qemu/hw/openrisc/cputimer.c b/qemu/hw/openrisc/cputimer.c
deleted file mode 100644
index a98c799de..000000000
--- a/qemu/hw/openrisc/cputimer.c
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * QEMU OpenRISC timer support
- *
- * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
- * Zhizhou Zhang <etouzh@gmail.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "cpu.h"
-#include "hw/hw.h"
-#include "qemu/timer.h"
-
-#define TIMER_PERIOD 50 /* 50 ns period for 20 MHz timer */
-
-/* The time when TTCR changes */
-static uint64_t last_clk;
-static int is_counting;
-
-void cpu_openrisc_count_update(OpenRISCCPU *cpu)
-{
- uint64_t now;
-
- if (!is_counting) {
- return;
- }
- now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- cpu->env.ttcr += (uint32_t)((now - last_clk) / TIMER_PERIOD);
- last_clk = now;
-}
-
-void cpu_openrisc_timer_update(OpenRISCCPU *cpu)
-{
- uint32_t wait;
- uint64_t now, next;
-
- if (!is_counting) {
- return;
- }
-
- cpu_openrisc_count_update(cpu);
- now = last_clk;
-
- if ((cpu->env.ttmr & TTMR_TP) <= (cpu->env.ttcr & TTMR_TP)) {
- wait = TTMR_TP - (cpu->env.ttcr & TTMR_TP) + 1;
- wait += cpu->env.ttmr & TTMR_TP;
- } else {
- wait = (cpu->env.ttmr & TTMR_TP) - (cpu->env.ttcr & TTMR_TP);
- }
- next = now + (uint64_t)wait * TIMER_PERIOD;
- timer_mod(cpu->env.timer, next);
-}
-
-void cpu_openrisc_count_start(OpenRISCCPU *cpu)
-{
- is_counting = 1;
- cpu_openrisc_count_update(cpu);
-}
-
-void cpu_openrisc_count_stop(OpenRISCCPU *cpu)
-{
- timer_del(cpu->env.timer);
- cpu_openrisc_count_update(cpu);
- is_counting = 0;
-}
-
-static void openrisc_timer_cb(void *opaque)
-{
- OpenRISCCPU *cpu = opaque;
-
- if ((cpu->env.ttmr & TTMR_IE) &&
- timer_expired(cpu->env.timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL))) {
- CPUState *cs = CPU(cpu);
-
- cpu->env.ttmr |= TTMR_IP;
- cs->interrupt_request |= CPU_INTERRUPT_TIMER;
- }
-
- switch (cpu->env.ttmr & TTMR_M) {
- case TIMER_NONE:
- break;
- case TIMER_INTR:
- cpu->env.ttcr = 0;
- break;
- case TIMER_SHOT:
- cpu_openrisc_count_stop(cpu);
- break;
- case TIMER_CONT:
- break;
- }
-
- cpu_openrisc_timer_update(cpu);
-}
-
-void cpu_openrisc_clock_init(OpenRISCCPU *cpu)
-{
- cpu->env.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &openrisc_timer_cb, cpu);
- cpu->env.ttmr = 0x00000000;
- cpu->env.ttcr = 0x00000000;
-}
diff --git a/qemu/hw/openrisc/openrisc_sim.c b/qemu/hw/openrisc/openrisc_sim.c
deleted file mode 100644
index 6d06d5be0..000000000
--- a/qemu/hw/openrisc/openrisc_sim.c
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * OpenRISC simulator for use as an IIS.
- *
- * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
- * Feng Gao <gf91597@gmail.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/hw.h"
-#include "hw/boards.h"
-#include "elf.h"
-#include "hw/char/serial.h"
-#include "net/net.h"
-#include "hw/loader.h"
-#include "exec/address-spaces.h"
-#include "sysemu/sysemu.h"
-#include "hw/sysbus.h"
-#include "sysemu/qtest.h"
-
-#define KERNEL_LOAD_ADDR 0x100
-
-static void main_cpu_reset(void *opaque)
-{
- OpenRISCCPU *cpu = opaque;
-
- cpu_reset(CPU(cpu));
-}
-
-static void openrisc_sim_net_init(MemoryRegion *address_space,
- hwaddr base,
- hwaddr descriptors,
- qemu_irq irq, NICInfo *nd)
-{
- DeviceState *dev;
- SysBusDevice *s;
-
- dev = qdev_create(NULL, "open_eth");
- qdev_set_nic_properties(dev, nd);
- qdev_init_nofail(dev);
-
- s = SYS_BUS_DEVICE(dev);
- sysbus_connect_irq(s, 0, irq);
- memory_region_add_subregion(address_space, base,
- sysbus_mmio_get_region(s, 0));
- memory_region_add_subregion(address_space, descriptors,
- sysbus_mmio_get_region(s, 1));
-}
-
-static void cpu_openrisc_load_kernel(ram_addr_t ram_size,
- const char *kernel_filename,
- OpenRISCCPU *cpu)
-{
- long kernel_size;
- uint64_t elf_entry;
- hwaddr entry;
-
- if (kernel_filename && !qtest_enabled()) {
- kernel_size = load_elf(kernel_filename, NULL, NULL,
- &elf_entry, NULL, NULL, 1, EM_OPENRISC,
- 1, 0);
- entry = elf_entry;
- if (kernel_size < 0) {
- kernel_size = load_uimage(kernel_filename,
- &entry, NULL, NULL, NULL, NULL);
- }
- if (kernel_size < 0) {
- kernel_size = load_image_targphys(kernel_filename,
- KERNEL_LOAD_ADDR,
- ram_size - KERNEL_LOAD_ADDR);
- entry = KERNEL_LOAD_ADDR;
- }
-
- if (kernel_size < 0) {
- fprintf(stderr, "QEMU: couldn't load the kernel '%s'\n",
- kernel_filename);
- exit(1);
- }
- cpu->env.pc = entry;
- }
-}
-
-static void openrisc_sim_init(MachineState *machine)
-{
- ram_addr_t ram_size = machine->ram_size;
- const char *cpu_model = machine->cpu_model;
- const char *kernel_filename = machine->kernel_filename;
- OpenRISCCPU *cpu = NULL;
- MemoryRegion *ram;
- int n;
-
- if (!cpu_model) {
- cpu_model = "or1200";
- }
-
- for (n = 0; n < smp_cpus; n++) {
- cpu = cpu_openrisc_init(cpu_model);
- if (cpu == NULL) {
- fprintf(stderr, "Unable to find CPU definition!\n");
- exit(1);
- }
- qemu_register_reset(main_cpu_reset, cpu);
- main_cpu_reset(cpu);
- }
-
- ram = g_malloc(sizeof(*ram));
- memory_region_init_ram(ram, NULL, "openrisc.ram", ram_size, &error_fatal);
- vmstate_register_ram_global(ram);
- memory_region_add_subregion(get_system_memory(), 0, ram);
-
- cpu_openrisc_pic_init(cpu);
- cpu_openrisc_clock_init(cpu);
-
- serial_mm_init(get_system_memory(), 0x90000000, 0, cpu->env.irq[2],
- 115200, serial_hds[0], DEVICE_NATIVE_ENDIAN);
-
- if (nd_table[0].used) {
- openrisc_sim_net_init(get_system_memory(), 0x92000000,
- 0x92000400, cpu->env.irq[4], nd_table);
- }
-
- cpu_openrisc_load_kernel(ram_size, kernel_filename, cpu);
-}
-
-static void openrisc_sim_machine_init(MachineClass *mc)
-{
- mc->desc = "or32 simulation";
- mc->init = openrisc_sim_init;
- mc->max_cpus = 1;
- mc->is_default = 1;
-}
-
-DEFINE_MACHINE("or32-sim", openrisc_sim_machine_init)
diff --git a/qemu/hw/openrisc/pic_cpu.c b/qemu/hw/openrisc/pic_cpu.c
deleted file mode 100644
index 569b443f5..000000000
--- a/qemu/hw/openrisc/pic_cpu.c
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * OpenRISC Programmable Interrupt Controller support.
- *
- * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
- * Feng Gao <gf91597@gmail.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "cpu.h"
-
-/* OpenRISC pic handler */
-static void openrisc_pic_cpu_handler(void *opaque, int irq, int level)
-{
- OpenRISCCPU *cpu = (OpenRISCCPU *)opaque;
- CPUState *cs = CPU(cpu);
- uint32_t irq_bit;
-
- if (irq > 31 || irq < 0) {
- return;
- }
-
- irq_bit = 1U << irq;
-
- if (level) {
- cpu->env.picsr |= irq_bit;
- } else {
- cpu->env.picsr &= ~irq_bit;
- }
-
- if (cpu->env.picsr & cpu->env.picmr) {
- cpu_interrupt(cs, CPU_INTERRUPT_HARD);
- } else {
- cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
- cpu->env.picsr = 0;
- }
-}
-
-void cpu_openrisc_pic_init(OpenRISCCPU *cpu)
-{
- int i;
- qemu_irq *qi;
- qi = qemu_allocate_irqs(openrisc_pic_cpu_handler, cpu, NR_IRQS);
-
- for (i = 0; i < NR_IRQS; i++) {
- cpu->env.irq[i] = qi[i];
- }
-}
diff --git a/qemu/hw/pci-bridge/Makefile.objs b/qemu/hw/pci-bridge/Makefile.objs
deleted file mode 100644
index f2adfe348..000000000
--- a/qemu/hw/pci-bridge/Makefile.objs
+++ /dev/null
@@ -1,7 +0,0 @@
-common-obj-y += pci_bridge_dev.o
-common-obj-y += pci_expander_bridge.o
-common-obj-$(CONFIG_XIO3130) += xio3130_upstream.o xio3130_downstream.o
-common-obj-$(CONFIG_IOH3420) += ioh3420.o
-common-obj-$(CONFIG_I82801B11) += i82801b11.o
-# NewWorld PowerMac
-common-obj-$(CONFIG_DEC_PCI) += dec.o
diff --git a/qemu/hw/pci-bridge/dec.c b/qemu/hw/pci-bridge/dec.c
deleted file mode 100644
index 840c96198..000000000
--- a/qemu/hw/pci-bridge/dec.c
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * QEMU DEC 21154 PCI bridge
- *
- * Copyright (c) 2006-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.
- */
-
-#include "qemu/osdep.h"
-#include "dec.h"
-#include "hw/sysbus.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/pci_host.h"
-#include "hw/pci/pci_bridge.h"
-#include "hw/pci/pci_bus.h"
-
-/* debug DEC */
-//#define DEBUG_DEC
-
-#ifdef DEBUG_DEC
-#define DEC_DPRINTF(fmt, ...) \
- do { printf("DEC: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DEC_DPRINTF(fmt, ...)
-#endif
-
-#define DEC_21154(obj) OBJECT_CHECK(DECState, (obj), TYPE_DEC_21154)
-
-typedef struct DECState {
- PCIHostState parent_obj;
-} DECState;
-
-static int dec_map_irq(PCIDevice *pci_dev, int irq_num)
-{
- return irq_num;
-}
-
-static void dec_pci_bridge_realize(PCIDevice *pci_dev, Error **errp)
-{
- pci_bridge_initfn(pci_dev, TYPE_PCI_BUS);
-}
-
-static void dec_21154_pci_bridge_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = dec_pci_bridge_realize;
- k->exit = pci_bridge_exitfn;
- k->vendor_id = PCI_VENDOR_ID_DEC;
- k->device_id = PCI_DEVICE_ID_DEC_21154;
- k->config_write = pci_bridge_write_config;
- k->is_bridge = 1;
- dc->desc = "DEC 21154 PCI-PCI bridge";
- dc->reset = pci_bridge_reset;
- dc->vmsd = &vmstate_pci_device;
-}
-
-static const TypeInfo dec_21154_pci_bridge_info = {
- .name = "dec-21154-p2p-bridge",
- .parent = TYPE_PCI_BRIDGE,
- .instance_size = sizeof(PCIBridge),
- .class_init = dec_21154_pci_bridge_class_init,
-};
-
-PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn)
-{
- PCIDevice *dev;
- PCIBridge *br;
-
- dev = pci_create_multifunction(parent_bus, devfn, false,
- "dec-21154-p2p-bridge");
- br = PCI_BRIDGE(dev);
- pci_bridge_map_irq(br, "DEC 21154 PCI-PCI bridge", dec_map_irq);
- qdev_init_nofail(&dev->qdev);
- return pci_bridge_get_sec_bus(br);
-}
-
-static int pci_dec_21154_device_init(SysBusDevice *dev)
-{
- PCIHostState *phb;
-
- phb = PCI_HOST_BRIDGE(dev);
-
- memory_region_init_io(&phb->conf_mem, OBJECT(dev), &pci_host_conf_le_ops,
- dev, "pci-conf-idx", 0x1000);
- memory_region_init_io(&phb->data_mem, OBJECT(dev), &pci_host_data_le_ops,
- dev, "pci-data-idx", 0x1000);
- sysbus_init_mmio(dev, &phb->conf_mem);
- sysbus_init_mmio(dev, &phb->data_mem);
- return 0;
-}
-
-static void dec_21154_pci_host_realize(PCIDevice *d, Error **errp)
-{
- /* PCI2PCI bridge same values as PearPC - check this */
-}
-
-static void dec_21154_pci_host_class_init(ObjectClass *klass, void *data)
-{
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- k->realize = dec_21154_pci_host_realize;
- k->vendor_id = PCI_VENDOR_ID_DEC;
- k->device_id = PCI_DEVICE_ID_DEC_21154;
- k->revision = 0x02;
- k->class_id = PCI_CLASS_BRIDGE_PCI;
- k->is_bridge = 1;
- /*
- * PCI-facing part of the host bridge, not usable without the
- * host-facing part, which can't be device_add'ed, yet.
- */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo dec_21154_pci_host_info = {
- .name = "dec-21154",
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(PCIDevice),
- .class_init = dec_21154_pci_host_class_init,
-};
-
-static void pci_dec_21154_device_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
- sdc->init = pci_dec_21154_device_init;
-}
-
-static const TypeInfo pci_dec_21154_device_info = {
- .name = TYPE_DEC_21154,
- .parent = TYPE_PCI_HOST_BRIDGE,
- .instance_size = sizeof(DECState),
- .class_init = pci_dec_21154_device_class_init,
-};
-
-static void dec_register_types(void)
-{
- type_register_static(&pci_dec_21154_device_info);
- type_register_static(&dec_21154_pci_host_info);
- type_register_static(&dec_21154_pci_bridge_info);
-}
-
-type_init(dec_register_types)
diff --git a/qemu/hw/pci-bridge/dec.h b/qemu/hw/pci-bridge/dec.h
deleted file mode 100644
index 17dc0c2b0..000000000
--- a/qemu/hw/pci-bridge/dec.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef DEC_PCI_H
-#define DEC_PCI_H
-
-#include "qemu-common.h"
-
-#define TYPE_DEC_21154 "dec-21154-sysbus"
-
-PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn);
-
-#endif
diff --git a/qemu/hw/pci-bridge/i82801b11.c b/qemu/hw/pci-bridge/i82801b11.c
deleted file mode 100644
index 2404e7eba..000000000
--- a/qemu/hw/pci-bridge/i82801b11.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (c) 2006 Fabrice Bellard
- *
- * 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.
- */
-/*
- * QEMU i82801b11 dmi-to-pci Bridge Emulation
- *
- * Copyright (c) 2009, 2010, 2011
- * Isaku Yamahata <yamahata at valinux co jp>
- * VA Linux Systems Japan K.K.
- * Copyright (C) 2012 Jason Baron <jbaron@redhat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>
- */
-
-#include "qemu/osdep.h"
-#include "hw/pci/pci.h"
-#include "hw/i386/ich9.h"
-
-
-/*****************************************************************************/
-/* ICH9 DMI-to-PCI bridge */
-#define I82801ba_SSVID_OFFSET 0x50
-#define I82801ba_SSVID_SVID 0
-#define I82801ba_SSVID_SSID 0
-
-typedef struct I82801b11Bridge {
- /*< private >*/
- PCIBridge parent_obj;
- /*< public >*/
-} I82801b11Bridge;
-
-static int i82801b11_bridge_initfn(PCIDevice *d)
-{
- int rc;
-
- pci_bridge_initfn(d, TYPE_PCI_BUS);
-
- rc = pci_bridge_ssvid_init(d, I82801ba_SSVID_OFFSET,
- I82801ba_SSVID_SVID, I82801ba_SSVID_SSID);
- if (rc < 0) {
- goto err_bridge;
- }
- pci_config_set_prog_interface(d->config, PCI_CLASS_BRIDGE_PCI_INF_SUB);
- return 0;
-
-err_bridge:
- pci_bridge_exitfn(d);
-
- return rc;
-}
-
-static const VMStateDescription i82801b11_bridge_dev_vmstate = {
- .name = "i82801b11_bridge",
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(parent_obj, PCIBridge),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void i82801b11_bridge_class_init(ObjectClass *klass, void *data)
-{
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- k->is_bridge = 1;
- k->vendor_id = PCI_VENDOR_ID_INTEL;
- k->device_id = PCI_DEVICE_ID_INTEL_82801BA_11;
- k->revision = ICH9_D2P_A2_REVISION;
- k->init = i82801b11_bridge_initfn;
- k->config_write = pci_bridge_write_config;
- dc->vmsd = &i82801b11_bridge_dev_vmstate;
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
-}
-
-static const TypeInfo i82801b11_bridge_info = {
- .name = "i82801b11-bridge",
- .parent = TYPE_PCI_BRIDGE,
- .instance_size = sizeof(I82801b11Bridge),
- .class_init = i82801b11_bridge_class_init,
-};
-
-static void d2pbr_register(void)
-{
- type_register_static(&i82801b11_bridge_info);
-}
-
-type_init(d2pbr_register);
diff --git a/qemu/hw/pci-bridge/ioh3420.c b/qemu/hw/pci-bridge/ioh3420.c
deleted file mode 100644
index 0937fa34b..000000000
--- a/qemu/hw/pci-bridge/ioh3420.c
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * ioh3420.c
- * Intel X58 north bridge IOH
- * PCI Express root port device id 3420
- *
- * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
- * VA Linux Systems Japan K.K.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/pci/pci_ids.h"
-#include "hw/pci/msi.h"
-#include "hw/pci/pcie.h"
-#include "ioh3420.h"
-
-#define PCI_DEVICE_ID_IOH_EPORT 0x3420 /* D0:F0 express mode */
-#define PCI_DEVICE_ID_IOH_REV 0x2
-#define IOH_EP_SSVID_OFFSET 0x40
-#define IOH_EP_SSVID_SVID PCI_VENDOR_ID_INTEL
-#define IOH_EP_SSVID_SSID 0
-#define IOH_EP_MSI_OFFSET 0x60
-#define IOH_EP_MSI_SUPPORTED_FLAGS PCI_MSI_FLAGS_MASKBIT
-#define IOH_EP_MSI_NR_VECTOR 2
-#define IOH_EP_EXP_OFFSET 0x90
-#define IOH_EP_AER_OFFSET 0x100
-
-/*
- * If two MSI vector are allocated, Advanced Error Interrupt Message Number
- * is 1. otherwise 0.
- * 17.12.5.10 RPERRSTS, 32:27 bit Advanced Error Interrupt Message Number.
- */
-static uint8_t ioh3420_aer_vector(const PCIDevice *d)
-{
- switch (msi_nr_vectors_allocated(d)) {
- case 1:
- return 0;
- case 2:
- return 1;
- case 4:
- case 8:
- case 16:
- case 32:
- default:
- break;
- }
- abort();
- return 0;
-}
-
-static void ioh3420_aer_vector_update(PCIDevice *d)
-{
- pcie_aer_root_set_vector(d, ioh3420_aer_vector(d));
-}
-
-static void ioh3420_write_config(PCIDevice *d,
- uint32_t address, uint32_t val, int len)
-{
- uint32_t root_cmd =
- pci_get_long(d->config + d->exp.aer_cap + PCI_ERR_ROOT_COMMAND);
-
- pci_bridge_write_config(d, address, val, len);
- ioh3420_aer_vector_update(d);
- pcie_cap_slot_write_config(d, address, val, len);
- pcie_aer_write_config(d, address, val, len);
- pcie_aer_root_write_config(d, address, val, len, root_cmd);
-}
-
-static void ioh3420_reset(DeviceState *qdev)
-{
- PCIDevice *d = PCI_DEVICE(qdev);
-
- ioh3420_aer_vector_update(d);
- pcie_cap_root_reset(d);
- pcie_cap_deverr_reset(d);
- pcie_cap_slot_reset(d);
- pcie_cap_arifwd_reset(d);
- pcie_aer_root_reset(d);
- pci_bridge_reset(qdev);
- pci_bridge_disable_base_limit(d);
-}
-
-static int ioh3420_initfn(PCIDevice *d)
-{
- PCIEPort *p = PCIE_PORT(d);
- PCIESlot *s = PCIE_SLOT(d);
- int rc;
-
- pci_bridge_initfn(d, TYPE_PCIE_BUS);
- pcie_port_init_reg(d);
-
- rc = pci_bridge_ssvid_init(d, IOH_EP_SSVID_OFFSET,
- IOH_EP_SSVID_SVID, IOH_EP_SSVID_SSID);
- if (rc < 0) {
- goto err_bridge;
- }
- rc = msi_init(d, IOH_EP_MSI_OFFSET, IOH_EP_MSI_NR_VECTOR,
- IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
- IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT);
- if (rc < 0) {
- goto err_bridge;
- }
- rc = pcie_cap_init(d, IOH_EP_EXP_OFFSET, PCI_EXP_TYPE_ROOT_PORT, p->port);
- if (rc < 0) {
- goto err_msi;
- }
-
- pcie_cap_arifwd_init(d);
- pcie_cap_deverr_init(d);
- pcie_cap_slot_init(d, s->slot);
- pcie_chassis_create(s->chassis);
- rc = pcie_chassis_add_slot(s);
- if (rc < 0) {
- goto err_pcie_cap;
- }
- pcie_cap_root_init(d);
- rc = pcie_aer_init(d, IOH_EP_AER_OFFSET, PCI_ERR_SIZEOF);
- if (rc < 0) {
- goto err;
- }
- pcie_aer_root_init(d);
- ioh3420_aer_vector_update(d);
- return 0;
-
-err:
- pcie_chassis_del_slot(s);
-err_pcie_cap:
- pcie_cap_exit(d);
-err_msi:
- msi_uninit(d);
-err_bridge:
- pci_bridge_exitfn(d);
- return rc;
-}
-
-static void ioh3420_exitfn(PCIDevice *d)
-{
- PCIESlot *s = PCIE_SLOT(d);
-
- pcie_aer_exit(d);
- pcie_chassis_del_slot(s);
- pcie_cap_exit(d);
- msi_uninit(d);
- pci_bridge_exitfn(d);
-}
-
-static Property ioh3420_props[] = {
- DEFINE_PROP_BIT(COMPAT_PROP_PCP, PCIDevice, cap_present,
- QEMU_PCIE_SLTCAP_PCP_BITNR, true),
- DEFINE_PROP_END_OF_LIST()
-};
-
-static const VMStateDescription vmstate_ioh3420 = {
- .name = "ioh-3240-express-root-port",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = pcie_cap_slot_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_PCIE_DEVICE(parent_obj.parent_obj.parent_obj, PCIESlot),
- VMSTATE_STRUCT(parent_obj.parent_obj.parent_obj.exp.aer_log,
- PCIESlot, 0, vmstate_pcie_aer_log, PCIEAERLog),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void ioh3420_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->is_express = 1;
- k->is_bridge = 1;
- k->config_write = ioh3420_write_config;
- k->init = ioh3420_initfn;
- k->exit = ioh3420_exitfn;
- k->vendor_id = PCI_VENDOR_ID_INTEL;
- k->device_id = PCI_DEVICE_ID_IOH_EPORT;
- k->revision = PCI_DEVICE_ID_IOH_REV;
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
- dc->desc = "Intel IOH device id 3420 PCIE Root Port";
- dc->reset = ioh3420_reset;
- dc->vmsd = &vmstate_ioh3420;
- dc->props = ioh3420_props;
-}
-
-static const TypeInfo ioh3420_info = {
- .name = "ioh3420",
- .parent = TYPE_PCIE_SLOT,
- .class_init = ioh3420_class_init,
-};
-
-static void ioh3420_register_types(void)
-{
- type_register_static(&ioh3420_info);
-}
-
-type_init(ioh3420_register_types)
-
-/*
- * Local variables:
- * c-indent-level: 4
- * c-basic-offset: 4
- * tab-width: 8
- * indent-tab-mode: nil
- * End:
- */
diff --git a/qemu/hw/pci-bridge/ioh3420.h b/qemu/hw/pci-bridge/ioh3420.h
deleted file mode 100644
index ea423cb99..000000000
--- a/qemu/hw/pci-bridge/ioh3420.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef QEMU_IOH3420_H
-#define QEMU_IOH3420_H
-
-#include "hw/pci/pcie_port.h"
-
-#endif /* QEMU_IOH3420_H */
diff --git a/qemu/hw/pci-bridge/pci_bridge_dev.c b/qemu/hw/pci-bridge/pci_bridge_dev.c
deleted file mode 100644
index 7b582e96a..000000000
--- a/qemu/hw/pci-bridge/pci_bridge_dev.c
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * Standard PCI Bridge Device
- *
- * Copyright (c) 2011 Red Hat Inc. Author: Michael S. Tsirkin <mst@redhat.com>
- *
- * http://www.pcisig.com/specifications/conventional/pci_to_pci_bridge_architecture/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/pci/pci_bridge.h"
-#include "hw/pci/pci_ids.h"
-#include "hw/pci/msi.h"
-#include "hw/pci/shpc.h"
-#include "hw/pci/slotid_cap.h"
-#include "exec/memory.h"
-#include "hw/pci/pci_bus.h"
-#include "hw/hotplug.h"
-
-#define TYPE_PCI_BRIDGE_DEV "pci-bridge"
-#define TYPE_PCI_BRIDGE_SEAT_DEV "pci-bridge-seat"
-#define PCI_BRIDGE_DEV(obj) \
- OBJECT_CHECK(PCIBridgeDev, (obj), TYPE_PCI_BRIDGE_DEV)
-
-struct PCIBridgeDev {
- /*< private >*/
- PCIBridge parent_obj;
- /*< public >*/
-
- MemoryRegion bar;
- uint8_t chassis_nr;
-#define PCI_BRIDGE_DEV_F_MSI_REQ 0
-#define PCI_BRIDGE_DEV_F_SHPC_REQ 1
- uint32_t flags;
-};
-typedef struct PCIBridgeDev PCIBridgeDev;
-
-static int pci_bridge_dev_initfn(PCIDevice *dev)
-{
- PCIBridge *br = PCI_BRIDGE(dev);
- PCIBridgeDev *bridge_dev = PCI_BRIDGE_DEV(dev);
- int err;
-
- pci_bridge_initfn(dev, TYPE_PCI_BUS);
-
- if (bridge_dev->flags & (1 << PCI_BRIDGE_DEV_F_SHPC_REQ)) {
- dev->config[PCI_INTERRUPT_PIN] = 0x1;
- memory_region_init(&bridge_dev->bar, OBJECT(dev), "shpc-bar",
- shpc_bar_size(dev));
- err = shpc_init(dev, &br->sec_bus, &bridge_dev->bar, 0);
- if (err) {
- goto shpc_error;
- }
- } else {
- /* MSI is not applicable without SHPC */
- bridge_dev->flags &= ~(1 << PCI_BRIDGE_DEV_F_MSI_REQ);
- }
- err = slotid_cap_init(dev, 0, bridge_dev->chassis_nr, 0);
- if (err) {
- goto slotid_error;
- }
- if ((bridge_dev->flags & (1 << PCI_BRIDGE_DEV_F_MSI_REQ)) &&
- msi_nonbroken) {
- err = msi_init(dev, 0, 1, true, true);
- if (err < 0) {
- goto msi_error;
- }
- }
- if (shpc_present(dev)) {
- /* TODO: spec recommends using 64 bit prefetcheable BAR.
- * Check whether that works well. */
- pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY |
- PCI_BASE_ADDRESS_MEM_TYPE_64, &bridge_dev->bar);
- }
- return 0;
-msi_error:
- slotid_cap_cleanup(dev);
-slotid_error:
- if (shpc_present(dev)) {
- shpc_cleanup(dev, &bridge_dev->bar);
- }
-shpc_error:
- pci_bridge_exitfn(dev);
-
- return err;
-}
-
-static void pci_bridge_dev_exitfn(PCIDevice *dev)
-{
- PCIBridgeDev *bridge_dev = PCI_BRIDGE_DEV(dev);
- if (msi_present(dev)) {
- msi_uninit(dev);
- }
- slotid_cap_cleanup(dev);
- if (shpc_present(dev)) {
- shpc_cleanup(dev, &bridge_dev->bar);
- }
- pci_bridge_exitfn(dev);
-}
-
-static void pci_bridge_dev_instance_finalize(Object *obj)
-{
- /* this function is idempotent and handles (PCIDevice.shpc == NULL) */
- shpc_free(PCI_DEVICE(obj));
-}
-
-static void pci_bridge_dev_write_config(PCIDevice *d,
- uint32_t address, uint32_t val, int len)
-{
- pci_bridge_write_config(d, address, val, len);
- if (msi_present(d)) {
- msi_write_config(d, address, val, len);
- }
- if (shpc_present(d)) {
- shpc_cap_write_config(d, address, val, len);
- }
-}
-
-static void qdev_pci_bridge_dev_reset(DeviceState *qdev)
-{
- PCIDevice *dev = PCI_DEVICE(qdev);
-
- pci_bridge_reset(qdev);
- if (shpc_present(dev)) {
- shpc_reset(dev);
- }
-}
-
-static Property pci_bridge_dev_properties[] = {
- /* Note: 0 is not a legal chassis number. */
- DEFINE_PROP_UINT8(PCI_BRIDGE_DEV_PROP_CHASSIS_NR, PCIBridgeDev, chassis_nr,
- 0),
- DEFINE_PROP_BIT(PCI_BRIDGE_DEV_PROP_MSI, PCIBridgeDev, flags,
- PCI_BRIDGE_DEV_F_MSI_REQ, true),
- DEFINE_PROP_BIT(PCI_BRIDGE_DEV_PROP_SHPC, PCIBridgeDev, flags,
- PCI_BRIDGE_DEV_F_SHPC_REQ, true),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static bool pci_device_shpc_present(void *opaque, int version_id)
-{
- PCIDevice *dev = opaque;
-
- return shpc_present(dev);
-}
-
-static const VMStateDescription pci_bridge_dev_vmstate = {
- .name = "pci_bridge",
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(parent_obj, PCIBridge),
- SHPC_VMSTATE(shpc, PCIDevice, pci_device_shpc_present),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void pci_bridge_dev_hotplug_cb(HotplugHandler *hotplug_dev,
- DeviceState *dev, Error **errp)
-{
- PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev);
-
- if (!shpc_present(pci_hotplug_dev)) {
- error_setg(errp, "standard hotplug controller has been disabled for "
- "this %s", TYPE_PCI_BRIDGE_DEV);
- return;
- }
- shpc_device_hotplug_cb(hotplug_dev, dev, errp);
-}
-
-static void pci_bridge_dev_hot_unplug_request_cb(HotplugHandler *hotplug_dev,
- DeviceState *dev,
- Error **errp)
-{
- PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev);
-
- if (!shpc_present(pci_hotplug_dev)) {
- error_setg(errp, "standard hotplug controller has been disabled for "
- "this %s", TYPE_PCI_BRIDGE_DEV);
- return;
- }
- shpc_device_hot_unplug_request_cb(hotplug_dev, dev, errp);
-}
-
-static void pci_bridge_dev_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
-
- k->init = pci_bridge_dev_initfn;
- k->exit = pci_bridge_dev_exitfn;
- k->config_write = pci_bridge_dev_write_config;
- k->vendor_id = PCI_VENDOR_ID_REDHAT;
- k->device_id = PCI_DEVICE_ID_REDHAT_BRIDGE;
- k->class_id = PCI_CLASS_BRIDGE_PCI;
- k->is_bridge = 1,
- dc->desc = "Standard PCI Bridge";
- dc->reset = qdev_pci_bridge_dev_reset;
- dc->props = pci_bridge_dev_properties;
- dc->vmsd = &pci_bridge_dev_vmstate;
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
- hc->plug = pci_bridge_dev_hotplug_cb;
- hc->unplug_request = pci_bridge_dev_hot_unplug_request_cb;
-}
-
-static const TypeInfo pci_bridge_dev_info = {
- .name = TYPE_PCI_BRIDGE_DEV,
- .parent = TYPE_PCI_BRIDGE,
- .instance_size = sizeof(PCIBridgeDev),
- .class_init = pci_bridge_dev_class_init,
- .instance_finalize = pci_bridge_dev_instance_finalize,
- .interfaces = (InterfaceInfo[]) {
- { TYPE_HOTPLUG_HANDLER },
- { }
- }
-};
-
-/*
- * Multiseat bridge. Same as the standard pci bridge, only with a
- * different pci id, so we can match it easily in the guest for
- * automagic multiseat configuration. See docs/multiseat.txt for more.
- */
-static void pci_bridge_dev_seat_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->device_id = PCI_DEVICE_ID_REDHAT_BRIDGE_SEAT;
- dc->desc = "Standard PCI Bridge (multiseat)";
-}
-
-static const TypeInfo pci_bridge_dev_seat_info = {
- .name = TYPE_PCI_BRIDGE_SEAT_DEV,
- .parent = TYPE_PCI_BRIDGE_DEV,
- .instance_size = sizeof(PCIBridgeDev),
- .class_init = pci_bridge_dev_seat_class_init,
-};
-
-static void pci_bridge_dev_register(void)
-{
- type_register_static(&pci_bridge_dev_info);
- type_register_static(&pci_bridge_dev_seat_info);
-}
-
-type_init(pci_bridge_dev_register);
diff --git a/qemu/hw/pci-bridge/pci_expander_bridge.c b/qemu/hw/pci-bridge/pci_expander_bridge.c
deleted file mode 100644
index ba320bd85..000000000
--- a/qemu/hw/pci-bridge/pci_expander_bridge.c
+++ /dev/null
@@ -1,363 +0,0 @@
-/*
- * PCI Expander Bridge Device Emulation
- *
- * Copyright (C) 2015 Red Hat Inc
- *
- * Authors:
- * Marcel Apfelbaum <marcel@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/pci_bus.h"
-#include "hw/pci/pci_host.h"
-#include "hw/pci/pci_bus.h"
-#include "hw/pci/pci_bridge.h"
-#include "hw/i386/pc.h"
-#include "qemu/range.h"
-#include "qemu/error-report.h"
-#include "sysemu/numa.h"
-
-#define TYPE_PXB_BUS "pxb-bus"
-#define PXB_BUS(obj) OBJECT_CHECK(PXBBus, (obj), TYPE_PXB_BUS)
-
-#define TYPE_PXB_PCIE_BUS "pxb-pcie-bus"
-#define PXB_PCIE_BUS(obj) OBJECT_CHECK(PXBBus, (obj), TYPE_PXB_PCIE_BUS)
-
-typedef struct PXBBus {
- /*< private >*/
- PCIBus parent_obj;
- /*< public >*/
-
- char bus_path[8];
-} PXBBus;
-
-#define TYPE_PXB_DEVICE "pxb"
-#define PXB_DEV(obj) OBJECT_CHECK(PXBDev, (obj), TYPE_PXB_DEVICE)
-
-#define TYPE_PXB_PCIE_DEVICE "pxb-pcie"
-#define PXB_PCIE_DEV(obj) OBJECT_CHECK(PXBDev, (obj), TYPE_PXB_PCIE_DEVICE)
-
-typedef struct PXBDev {
- /*< private >*/
- PCIDevice parent_obj;
- /*< public >*/
-
- uint8_t bus_nr;
- uint16_t numa_node;
-} PXBDev;
-
-static PXBDev *convert_to_pxb(PCIDevice *dev)
-{
- return pci_bus_is_express(dev->bus) ? PXB_PCIE_DEV(dev) : PXB_DEV(dev);
-}
-
-static GList *pxb_dev_list;
-
-#define TYPE_PXB_HOST "pxb-host"
-
-static int pxb_bus_num(PCIBus *bus)
-{
- PXBDev *pxb = convert_to_pxb(bus->parent_dev);
-
- return pxb->bus_nr;
-}
-
-static bool pxb_is_root(PCIBus *bus)
-{
- return true; /* by definition */
-}
-
-static uint16_t pxb_bus_numa_node(PCIBus *bus)
-{
- PXBDev *pxb = convert_to_pxb(bus->parent_dev);
-
- return pxb->numa_node;
-}
-
-static void pxb_bus_class_init(ObjectClass *class, void *data)
-{
- PCIBusClass *pbc = PCI_BUS_CLASS(class);
-
- pbc->bus_num = pxb_bus_num;
- pbc->is_root = pxb_is_root;
- pbc->numa_node = pxb_bus_numa_node;
-}
-
-static const TypeInfo pxb_bus_info = {
- .name = TYPE_PXB_BUS,
- .parent = TYPE_PCI_BUS,
- .instance_size = sizeof(PXBBus),
- .class_init = pxb_bus_class_init,
-};
-
-static const TypeInfo pxb_pcie_bus_info = {
- .name = TYPE_PXB_PCIE_BUS,
- .parent = TYPE_PCIE_BUS,
- .instance_size = sizeof(PXBBus),
- .class_init = pxb_bus_class_init,
-};
-
-static const char *pxb_host_root_bus_path(PCIHostState *host_bridge,
- PCIBus *rootbus)
-{
- PXBBus *bus = pci_bus_is_express(rootbus) ?
- PXB_PCIE_BUS(rootbus) : PXB_BUS(rootbus);
-
- snprintf(bus->bus_path, 8, "0000:%02x", pxb_bus_num(rootbus));
- return bus->bus_path;
-}
-
-static char *pxb_host_ofw_unit_address(const SysBusDevice *dev)
-{
- const PCIHostState *pxb_host;
- const PCIBus *pxb_bus;
- const PXBDev *pxb_dev;
- int position;
- const DeviceState *pxb_dev_base;
- const PCIHostState *main_host;
- const SysBusDevice *main_host_sbd;
-
- pxb_host = PCI_HOST_BRIDGE(dev);
- pxb_bus = pxb_host->bus;
- pxb_dev = convert_to_pxb(pxb_bus->parent_dev);
- position = g_list_index(pxb_dev_list, pxb_dev);
- assert(position >= 0);
-
- pxb_dev_base = DEVICE(pxb_dev);
- main_host = PCI_HOST_BRIDGE(pxb_dev_base->parent_bus->parent);
- main_host_sbd = SYS_BUS_DEVICE(main_host);
-
- if (main_host_sbd->num_mmio > 0) {
- return g_strdup_printf(TARGET_FMT_plx ",%x",
- main_host_sbd->mmio[0].addr, position + 1);
- }
- if (main_host_sbd->num_pio > 0) {
- return g_strdup_printf("i%04x,%x",
- main_host_sbd->pio[0], position + 1);
- }
- return NULL;
-}
-
-static void pxb_host_class_init(ObjectClass *class, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(class);
- SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(class);
- PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(class);
-
- dc->fw_name = "pci";
- sbc->explicit_ofw_unit_address = pxb_host_ofw_unit_address;
- hc->root_bus_path = pxb_host_root_bus_path;
-}
-
-static const TypeInfo pxb_host_info = {
- .name = TYPE_PXB_HOST,
- .parent = TYPE_PCI_HOST_BRIDGE,
- .class_init = pxb_host_class_init,
-};
-
-/*
- * Registers the PXB bus as a child of the i440fx root bus.
- *
- * Returns 0 on successs, -1 if i440fx host was not
- * found or the bus number is already in use.
- */
-static int pxb_register_bus(PCIDevice *dev, PCIBus *pxb_bus)
-{
- PCIBus *bus = dev->bus;
- int pxb_bus_num = pci_bus_num(pxb_bus);
-
- if (bus->parent_dev) {
- error_report("PXB devices can be attached only to root bus.");
- return -1;
- }
-
- QLIST_FOREACH(bus, &bus->child, sibling) {
- if (pci_bus_num(bus) == pxb_bus_num) {
- error_report("Bus %d is already in use.", pxb_bus_num);
- return -1;
- }
- }
- QLIST_INSERT_HEAD(&dev->bus->child, pxb_bus, sibling);
-
- return 0;
-}
-
-static int pxb_map_irq_fn(PCIDevice *pci_dev, int pin)
-{
- PCIDevice *pxb = pci_dev->bus->parent_dev;
-
- /*
- * The bios does not index the pxb slot number when
- * it computes the IRQ because it resides on bus 0
- * and not on the current bus.
- * However QEMU routes the irq through bus 0 and adds
- * the pxb slot to the IRQ computation of the PXB
- * device.
- *
- * Synchronize between bios and QEMU by canceling
- * pxb's effect.
- */
- return pin - PCI_SLOT(pxb->devfn);
-}
-
-static gint pxb_compare(gconstpointer a, gconstpointer b)
-{
- const PXBDev *pxb_a = a, *pxb_b = b;
-
- return pxb_a->bus_nr < pxb_b->bus_nr ? -1 :
- pxb_a->bus_nr > pxb_b->bus_nr ? 1 :
- 0;
-}
-
-static int pxb_dev_init_common(PCIDevice *dev, bool pcie)
-{
- PXBDev *pxb = convert_to_pxb(dev);
- DeviceState *ds, *bds = NULL;
- PCIBus *bus;
- const char *dev_name = NULL;
-
- if (pxb->numa_node != NUMA_NODE_UNASSIGNED &&
- pxb->numa_node >= nb_numa_nodes) {
- error_report("Illegal numa node %d.", pxb->numa_node);
- return -EINVAL;
- }
-
- if (dev->qdev.id && *dev->qdev.id) {
- dev_name = dev->qdev.id;
- }
-
- ds = qdev_create(NULL, TYPE_PXB_HOST);
- if (pcie) {
- bus = pci_bus_new(ds, dev_name, NULL, NULL, 0, TYPE_PXB_PCIE_BUS);
- } else {
- bus = pci_bus_new(ds, "pxb-internal", NULL, NULL, 0, TYPE_PXB_BUS);
- bds = qdev_create(BUS(bus), "pci-bridge");
- bds->id = dev_name;
- qdev_prop_set_uint8(bds, PCI_BRIDGE_DEV_PROP_CHASSIS_NR, pxb->bus_nr);
- qdev_prop_set_bit(bds, PCI_BRIDGE_DEV_PROP_SHPC, false);
- }
-
- bus->parent_dev = dev;
- bus->address_space_mem = dev->bus->address_space_mem;
- bus->address_space_io = dev->bus->address_space_io;
- bus->map_irq = pxb_map_irq_fn;
-
- PCI_HOST_BRIDGE(ds)->bus = bus;
-
- if (pxb_register_bus(dev, bus)) {
- goto err_register_bus;
- }
-
- qdev_init_nofail(ds);
- if (bds) {
- qdev_init_nofail(bds);
- }
-
- pci_word_test_and_set_mask(dev->config + PCI_STATUS,
- PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
- pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_HOST);
-
- pxb_dev_list = g_list_insert_sorted(pxb_dev_list, pxb, pxb_compare);
- return 0;
-
-err_register_bus:
- object_unref(OBJECT(bds));
- object_unparent(OBJECT(bus));
- object_unref(OBJECT(ds));
- return -EINVAL;
-}
-
-static int pxb_dev_initfn(PCIDevice *dev)
-{
- if (pci_bus_is_express(dev->bus)) {
- error_report("pxb devices cannot reside on a PCIe bus!");
- return -EINVAL;
- }
-
- return pxb_dev_init_common(dev, false);
-}
-
-static void pxb_dev_exitfn(PCIDevice *pci_dev)
-{
- PXBDev *pxb = convert_to_pxb(pci_dev);
-
- pxb_dev_list = g_list_remove(pxb_dev_list, pxb);
-}
-
-static Property pxb_dev_properties[] = {
- /* Note: 0 is not a legal PXB bus number. */
- DEFINE_PROP_UINT8("bus_nr", PXBDev, bus_nr, 0),
- DEFINE_PROP_UINT16("numa_node", PXBDev, numa_node, NUMA_NODE_UNASSIGNED),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pxb_dev_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->init = pxb_dev_initfn;
- k->exit = pxb_dev_exitfn;
- k->vendor_id = PCI_VENDOR_ID_REDHAT;
- k->device_id = PCI_DEVICE_ID_REDHAT_PXB;
- k->class_id = PCI_CLASS_BRIDGE_HOST;
-
- dc->desc = "PCI Expander Bridge";
- dc->props = pxb_dev_properties;
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
-}
-
-static const TypeInfo pxb_dev_info = {
- .name = TYPE_PXB_DEVICE,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(PXBDev),
- .class_init = pxb_dev_class_init,
-};
-
-static int pxb_pcie_dev_initfn(PCIDevice *dev)
-{
- if (!pci_bus_is_express(dev->bus)) {
- error_report("pxb-pcie devices cannot reside on a PCI bus!");
- return -EINVAL;
- }
-
- return pxb_dev_init_common(dev, true);
-}
-
-static void pxb_pcie_dev_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->init = pxb_pcie_dev_initfn;
- k->exit = pxb_dev_exitfn;
- k->vendor_id = PCI_VENDOR_ID_REDHAT;
- k->device_id = PCI_DEVICE_ID_REDHAT_PXB_PCIE;
- k->class_id = PCI_CLASS_BRIDGE_HOST;
-
- dc->desc = "PCI Express Expander Bridge";
- dc->props = pxb_dev_properties;
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
-}
-
-static const TypeInfo pxb_pcie_dev_info = {
- .name = TYPE_PXB_PCIE_DEVICE,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(PXBDev),
- .class_init = pxb_pcie_dev_class_init,
-};
-
-static void pxb_register_types(void)
-{
- type_register_static(&pxb_bus_info);
- type_register_static(&pxb_pcie_bus_info);
- type_register_static(&pxb_host_info);
- type_register_static(&pxb_dev_info);
- type_register_static(&pxb_pcie_dev_info);
-}
-
-type_init(pxb_register_types)
diff --git a/qemu/hw/pci-bridge/xio3130_downstream.c b/qemu/hw/pci-bridge/xio3130_downstream.c
deleted file mode 100644
index cf1ee63ab..000000000
--- a/qemu/hw/pci-bridge/xio3130_downstream.c
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * x3130_downstream.c
- * TI X3130 pci express downstream port switch
- *
- * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
- * VA Linux Systems Japan K.K.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/pci/pci_ids.h"
-#include "hw/pci/msi.h"
-#include "hw/pci/pcie.h"
-#include "xio3130_downstream.h"
-
-#define PCI_DEVICE_ID_TI_XIO3130D 0x8233 /* downstream port */
-#define XIO3130_REVISION 0x1
-#define XIO3130_MSI_OFFSET 0x70
-#define XIO3130_MSI_SUPPORTED_FLAGS PCI_MSI_FLAGS_64BIT
-#define XIO3130_MSI_NR_VECTOR 1
-#define XIO3130_SSVID_OFFSET 0x80
-#define XIO3130_SSVID_SVID 0
-#define XIO3130_SSVID_SSID 0
-#define XIO3130_EXP_OFFSET 0x90
-#define XIO3130_AER_OFFSET 0x100
-
-static void xio3130_downstream_write_config(PCIDevice *d, uint32_t address,
- uint32_t val, int len)
-{
- pci_bridge_write_config(d, address, val, len);
- pcie_cap_flr_write_config(d, address, val, len);
- pcie_cap_slot_write_config(d, address, val, len);
- pcie_aer_write_config(d, address, val, len);
-}
-
-static void xio3130_downstream_reset(DeviceState *qdev)
-{
- PCIDevice *d = PCI_DEVICE(qdev);
-
- pcie_cap_deverr_reset(d);
- pcie_cap_slot_reset(d);
- pcie_cap_arifwd_reset(d);
- pci_bridge_reset(qdev);
-}
-
-static int xio3130_downstream_initfn(PCIDevice *d)
-{
- PCIEPort *p = PCIE_PORT(d);
- PCIESlot *s = PCIE_SLOT(d);
- int rc;
-
- pci_bridge_initfn(d, TYPE_PCIE_BUS);
- pcie_port_init_reg(d);
-
- rc = msi_init(d, XIO3130_MSI_OFFSET, XIO3130_MSI_NR_VECTOR,
- XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
- XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT);
- if (rc < 0) {
- goto err_bridge;
- }
- rc = pci_bridge_ssvid_init(d, XIO3130_SSVID_OFFSET,
- XIO3130_SSVID_SVID, XIO3130_SSVID_SSID);
- if (rc < 0) {
- goto err_bridge;
- }
- rc = pcie_cap_init(d, XIO3130_EXP_OFFSET, PCI_EXP_TYPE_DOWNSTREAM,
- p->port);
- if (rc < 0) {
- goto err_msi;
- }
- pcie_cap_flr_init(d);
- pcie_cap_deverr_init(d);
- pcie_cap_slot_init(d, s->slot);
- pcie_chassis_create(s->chassis);
- rc = pcie_chassis_add_slot(s);
- if (rc < 0) {
- goto err_pcie_cap;
- }
- pcie_cap_arifwd_init(d);
- rc = pcie_aer_init(d, XIO3130_AER_OFFSET, PCI_ERR_SIZEOF);
- if (rc < 0) {
- goto err;
- }
-
- return 0;
-
-err:
- pcie_chassis_del_slot(s);
-err_pcie_cap:
- pcie_cap_exit(d);
-err_msi:
- msi_uninit(d);
-err_bridge:
- pci_bridge_exitfn(d);
- return rc;
-}
-
-static void xio3130_downstream_exitfn(PCIDevice *d)
-{
- PCIESlot *s = PCIE_SLOT(d);
-
- pcie_aer_exit(d);
- pcie_chassis_del_slot(s);
- pcie_cap_exit(d);
- msi_uninit(d);
- pci_bridge_exitfn(d);
-}
-
-PCIESlot *xio3130_downstream_init(PCIBus *bus, int devfn, bool multifunction,
- const char *bus_name, pci_map_irq_fn map_irq,
- uint8_t port, uint8_t chassis,
- uint16_t slot)
-{
- PCIDevice *d;
- PCIBridge *br;
- DeviceState *qdev;
-
- d = pci_create_multifunction(bus, devfn, multifunction,
- "xio3130-downstream");
- if (!d) {
- return NULL;
- }
- br = PCI_BRIDGE(d);
-
- qdev = DEVICE(d);
- pci_bridge_map_irq(br, bus_name, map_irq);
- qdev_prop_set_uint8(qdev, "port", port);
- qdev_prop_set_uint8(qdev, "chassis", chassis);
- qdev_prop_set_uint16(qdev, "slot", slot);
- qdev_init_nofail(qdev);
-
- return PCIE_SLOT(d);
-}
-
-static Property xio3130_downstream_props[] = {
- DEFINE_PROP_BIT(COMPAT_PROP_PCP, PCIDevice, cap_present,
- QEMU_PCIE_SLTCAP_PCP_BITNR, true),
- DEFINE_PROP_END_OF_LIST()
-};
-
-static const VMStateDescription vmstate_xio3130_downstream = {
- .name = "xio3130-express-downstream-port",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = pcie_cap_slot_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_PCIE_DEVICE(parent_obj.parent_obj.parent_obj, PCIESlot),
- VMSTATE_STRUCT(parent_obj.parent_obj.parent_obj.exp.aer_log,
- PCIESlot, 0, vmstate_pcie_aer_log, PCIEAERLog),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void xio3130_downstream_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->is_express = 1;
- k->is_bridge = 1;
- k->config_write = xio3130_downstream_write_config;
- k->init = xio3130_downstream_initfn;
- k->exit = xio3130_downstream_exitfn;
- k->vendor_id = PCI_VENDOR_ID_TI;
- k->device_id = PCI_DEVICE_ID_TI_XIO3130D;
- k->revision = XIO3130_REVISION;
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
- dc->desc = "TI X3130 Downstream Port of PCI Express Switch";
- dc->reset = xio3130_downstream_reset;
- dc->vmsd = &vmstate_xio3130_downstream;
- dc->props = xio3130_downstream_props;
-}
-
-static const TypeInfo xio3130_downstream_info = {
- .name = "xio3130-downstream",
- .parent = TYPE_PCIE_SLOT,
- .class_init = xio3130_downstream_class_init,
-};
-
-static void xio3130_downstream_register_types(void)
-{
- type_register_static(&xio3130_downstream_info);
-}
-
-type_init(xio3130_downstream_register_types)
-
-/*
- * Local variables:
- * c-indent-level: 4
- * c-basic-offset: 4
- * tab-width: 8
- * indent-tab-mode: nil
- * End:
- */
diff --git a/qemu/hw/pci-bridge/xio3130_downstream.h b/qemu/hw/pci-bridge/xio3130_downstream.h
deleted file mode 100644
index 8426d9ffa..000000000
--- a/qemu/hw/pci-bridge/xio3130_downstream.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef QEMU_XIO3130_DOWNSTREAM_H
-#define QEMU_XIO3130_DOWNSTREAM_H
-
-#include "hw/pci/pcie_port.h"
-
-PCIESlot *xio3130_downstream_init(PCIBus *bus, int devfn, bool multifunction,
- const char *bus_name, pci_map_irq_fn map_irq,
- uint8_t port, uint8_t chassis,
- uint16_t slot);
-
-#endif /* QEMU_XIO3130_DOWNSTREAM_H */
diff --git a/qemu/hw/pci-bridge/xio3130_upstream.c b/qemu/hw/pci-bridge/xio3130_upstream.c
deleted file mode 100644
index 164ef58c4..000000000
--- a/qemu/hw/pci-bridge/xio3130_upstream.c
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * xio3130_upstream.c
- * TI X3130 pci express upstream port switch
- *
- * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
- * VA Linux Systems Japan K.K.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/pci/pci_ids.h"
-#include "hw/pci/msi.h"
-#include "hw/pci/pcie.h"
-#include "xio3130_upstream.h"
-
-#define PCI_DEVICE_ID_TI_XIO3130U 0x8232 /* upstream port */
-#define XIO3130_REVISION 0x2
-#define XIO3130_MSI_OFFSET 0x70
-#define XIO3130_MSI_SUPPORTED_FLAGS PCI_MSI_FLAGS_64BIT
-#define XIO3130_MSI_NR_VECTOR 1
-#define XIO3130_SSVID_OFFSET 0x80
-#define XIO3130_SSVID_SVID 0
-#define XIO3130_SSVID_SSID 0
-#define XIO3130_EXP_OFFSET 0x90
-#define XIO3130_AER_OFFSET 0x100
-
-static void xio3130_upstream_write_config(PCIDevice *d, uint32_t address,
- uint32_t val, int len)
-{
- pci_bridge_write_config(d, address, val, len);
- pcie_cap_flr_write_config(d, address, val, len);
- pcie_aer_write_config(d, address, val, len);
-}
-
-static void xio3130_upstream_reset(DeviceState *qdev)
-{
- PCIDevice *d = PCI_DEVICE(qdev);
-
- pci_bridge_reset(qdev);
- pcie_cap_deverr_reset(d);
-}
-
-static int xio3130_upstream_initfn(PCIDevice *d)
-{
- PCIEPort *p = PCIE_PORT(d);
- int rc;
-
- pci_bridge_initfn(d, TYPE_PCIE_BUS);
- pcie_port_init_reg(d);
-
- rc = msi_init(d, XIO3130_MSI_OFFSET, XIO3130_MSI_NR_VECTOR,
- XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
- XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT);
- if (rc < 0) {
- goto err_bridge;
- }
- rc = pci_bridge_ssvid_init(d, XIO3130_SSVID_OFFSET,
- XIO3130_SSVID_SVID, XIO3130_SSVID_SSID);
- if (rc < 0) {
- goto err_bridge;
- }
- rc = pcie_cap_init(d, XIO3130_EXP_OFFSET, PCI_EXP_TYPE_UPSTREAM,
- p->port);
- if (rc < 0) {
- goto err_msi;
- }
- pcie_cap_flr_init(d);
- pcie_cap_deverr_init(d);
- rc = pcie_aer_init(d, XIO3130_AER_OFFSET, PCI_ERR_SIZEOF);
- if (rc < 0) {
- goto err;
- }
-
- return 0;
-
-err:
- pcie_cap_exit(d);
-err_msi:
- msi_uninit(d);
-err_bridge:
- pci_bridge_exitfn(d);
- return rc;
-}
-
-static void xio3130_upstream_exitfn(PCIDevice *d)
-{
- pcie_aer_exit(d);
- pcie_cap_exit(d);
- msi_uninit(d);
- pci_bridge_exitfn(d);
-}
-
-PCIEPort *xio3130_upstream_init(PCIBus *bus, int devfn, bool multifunction,
- const char *bus_name, pci_map_irq_fn map_irq,
- uint8_t port)
-{
- PCIDevice *d;
- PCIBridge *br;
- DeviceState *qdev;
-
- d = pci_create_multifunction(bus, devfn, multifunction, "x3130-upstream");
- if (!d) {
- return NULL;
- }
- br = PCI_BRIDGE(d);
-
- qdev = DEVICE(d);
- pci_bridge_map_irq(br, bus_name, map_irq);
- qdev_prop_set_uint8(qdev, "port", port);
- qdev_init_nofail(qdev);
-
- return PCIE_PORT(d);
-}
-
-static const VMStateDescription vmstate_xio3130_upstream = {
- .name = "xio3130-express-upstream-port",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_PCIE_DEVICE(parent_obj.parent_obj, PCIEPort),
- VMSTATE_STRUCT(parent_obj.parent_obj.exp.aer_log, PCIEPort, 0,
- vmstate_pcie_aer_log, PCIEAERLog),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void xio3130_upstream_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->is_express = 1;
- k->is_bridge = 1;
- k->config_write = xio3130_upstream_write_config;
- k->init = xio3130_upstream_initfn;
- k->exit = xio3130_upstream_exitfn;
- k->vendor_id = PCI_VENDOR_ID_TI;
- k->device_id = PCI_DEVICE_ID_TI_XIO3130U;
- k->revision = XIO3130_REVISION;
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
- dc->desc = "TI X3130 Upstream Port of PCI Express Switch";
- dc->reset = xio3130_upstream_reset;
- dc->vmsd = &vmstate_xio3130_upstream;
-}
-
-static const TypeInfo xio3130_upstream_info = {
- .name = "x3130-upstream",
- .parent = TYPE_PCIE_PORT,
- .class_init = xio3130_upstream_class_init,
-};
-
-static void xio3130_upstream_register_types(void)
-{
- type_register_static(&xio3130_upstream_info);
-}
-
-type_init(xio3130_upstream_register_types)
-
-
-/*
- * Local variables:
- * c-indent-level: 4
- * c-basic-offset: 4
- * tab-width: 8
- * indent-tab-mode: nil
- * End:
- */
diff --git a/qemu/hw/pci-bridge/xio3130_upstream.h b/qemu/hw/pci-bridge/xio3130_upstream.h
deleted file mode 100644
index 08c1d5f75..000000000
--- a/qemu/hw/pci-bridge/xio3130_upstream.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef QEMU_XIO3130_UPSTREAM_H
-#define QEMU_XIO3130_UPSTREAM_H
-
-#include "hw/pci/pcie_port.h"
-
-PCIEPort *xio3130_upstream_init(PCIBus *bus, int devfn, bool multifunction,
- const char *bus_name, pci_map_irq_fn map_irq,
- uint8_t port);
-
-#endif /* QEMU_XIO3130_H */
diff --git a/qemu/hw/pci-host/Makefile.objs b/qemu/hw/pci-host/Makefile.objs
deleted file mode 100644
index 45f1f0eba..000000000
--- a/qemu/hw/pci-host/Makefile.objs
+++ /dev/null
@@ -1,18 +0,0 @@
-common-obj-y += pam.o
-
-# PPC devices
-common-obj-$(CONFIG_PREP_PCI) += prep.o
-common-obj-$(CONFIG_GRACKLE_PCI) += grackle.o
-# NewWorld PowerMac
-common-obj-$(CONFIG_UNIN_PCI) += uninorth.o
-# PowerPC E500 boards
-common-obj-$(CONFIG_PPCE500_PCI) += ppce500.o
-
-# ARM devices
-common-obj-$(CONFIG_VERSATILE_PCI) += versatile.o
-
-common-obj-$(CONFIG_PCI_APB) += apb.o
-common-obj-$(CONFIG_FULONG) += bonito.o
-common-obj-$(CONFIG_PCI_PIIX) += piix.o
-common-obj-$(CONFIG_PCI_Q35) += q35.o
-common-obj-$(CONFIG_PCI_GENERIC) += gpex.o
diff --git a/qemu/hw/pci-host/apb.c b/qemu/hw/pci-host/apb.c
deleted file mode 100644
index aaef7bb3a..000000000
--- a/qemu/hw/pci-host/apb.c
+++ /dev/null
@@ -1,871 +0,0 @@
-/*
- * QEMU Ultrasparc APB PCI host
- *
- * Copyright (c) 2006 Fabrice Bellard
- * Copyright (c) 2012,2013 Artyom Tarasenko
- *
- * 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.
- */
-
-/* XXX This file and most of its contents are somewhat misnamed. The
- Ultrasparc PCI host is called the PCI Bus Module (PBM). The APB is
- the secondary PCI bridge. */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/pci_host.h"
-#include "hw/pci/pci_bridge.h"
-#include "hw/pci/pci_bus.h"
-#include "hw/pci-host/apb.h"
-#include "sysemu/sysemu.h"
-#include "exec/address-spaces.h"
-
-/* debug APB */
-//#define DEBUG_APB
-
-#ifdef DEBUG_APB
-#define APB_DPRINTF(fmt, ...) \
-do { printf("APB: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define APB_DPRINTF(fmt, ...)
-#endif
-
-/* debug IOMMU */
-//#define DEBUG_IOMMU
-
-#ifdef DEBUG_IOMMU
-#define IOMMU_DPRINTF(fmt, ...) \
-do { printf("IOMMU: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define IOMMU_DPRINTF(fmt, ...)
-#endif
-
-/*
- * Chipset docs:
- * PBM: "UltraSPARC IIi User's Manual",
- * http://www.sun.com/processors/manuals/805-0087.pdf
- *
- * APB: "Advanced PCI Bridge (APB) User's Manual",
- * http://www.sun.com/processors/manuals/805-1251.pdf
- */
-
-#define PBM_PCI_IMR_MASK 0x7fffffff
-#define PBM_PCI_IMR_ENABLED 0x80000000
-
-#define POR (1U << 31)
-#define SOFT_POR (1U << 30)
-#define SOFT_XIR (1U << 29)
-#define BTN_POR (1U << 28)
-#define BTN_XIR (1U << 27)
-#define RESET_MASK 0xf8000000
-#define RESET_WCMASK 0x98000000
-#define RESET_WMASK 0x60000000
-
-#define MAX_IVEC 0x40
-#define NO_IRQ_REQUEST (MAX_IVEC + 1)
-
-#define IOMMU_PAGE_SIZE_8K (1ULL << 13)
-#define IOMMU_PAGE_MASK_8K (~(IOMMU_PAGE_SIZE_8K - 1))
-#define IOMMU_PAGE_SIZE_64K (1ULL << 16)
-#define IOMMU_PAGE_MASK_64K (~(IOMMU_PAGE_SIZE_64K - 1))
-
-#define IOMMU_NREGS 3
-
-#define IOMMU_CTRL 0x0
-#define IOMMU_CTRL_TBW_SIZE (1ULL << 2)
-#define IOMMU_CTRL_MMU_EN (1ULL)
-
-#define IOMMU_CTRL_TSB_SHIFT 16
-
-#define IOMMU_BASE 0x8
-#define IOMMU_FLUSH 0x10
-
-#define IOMMU_TTE_DATA_V (1ULL << 63)
-#define IOMMU_TTE_DATA_SIZE (1ULL << 61)
-#define IOMMU_TTE_DATA_W (1ULL << 1)
-
-#define IOMMU_TTE_PHYS_MASK_8K 0x1ffffffe000ULL
-#define IOMMU_TTE_PHYS_MASK_64K 0x1ffffff8000ULL
-
-#define IOMMU_TSB_8K_OFFSET_MASK_8M 0x00000000007fe000ULL
-#define IOMMU_TSB_8K_OFFSET_MASK_16M 0x0000000000ffe000ULL
-#define IOMMU_TSB_8K_OFFSET_MASK_32M 0x0000000001ffe000ULL
-#define IOMMU_TSB_8K_OFFSET_MASK_64M 0x0000000003ffe000ULL
-#define IOMMU_TSB_8K_OFFSET_MASK_128M 0x0000000007ffe000ULL
-#define IOMMU_TSB_8K_OFFSET_MASK_256M 0x000000000fffe000ULL
-#define IOMMU_TSB_8K_OFFSET_MASK_512M 0x000000001fffe000ULL
-#define IOMMU_TSB_8K_OFFSET_MASK_1G 0x000000003fffe000ULL
-
-#define IOMMU_TSB_64K_OFFSET_MASK_64M 0x0000000003ff0000ULL
-#define IOMMU_TSB_64K_OFFSET_MASK_128M 0x0000000007ff0000ULL
-#define IOMMU_TSB_64K_OFFSET_MASK_256M 0x000000000fff0000ULL
-#define IOMMU_TSB_64K_OFFSET_MASK_512M 0x000000001fff0000ULL
-#define IOMMU_TSB_64K_OFFSET_MASK_1G 0x000000003fff0000ULL
-#define IOMMU_TSB_64K_OFFSET_MASK_2G 0x000000007fff0000ULL
-
-typedef struct IOMMUState {
- AddressSpace iommu_as;
- MemoryRegion iommu;
-
- uint64_t regs[IOMMU_NREGS];
-} IOMMUState;
-
-#define TYPE_APB "pbm"
-
-#define APB_DEVICE(obj) \
- OBJECT_CHECK(APBState, (obj), TYPE_APB)
-
-typedef struct APBState {
- PCIHostState parent_obj;
-
- MemoryRegion apb_config;
- MemoryRegion pci_config;
- MemoryRegion pci_mmio;
- MemoryRegion pci_ioport;
- uint64_t pci_irq_in;
- IOMMUState iommu;
- uint32_t pci_control[16];
- uint32_t pci_irq_map[8];
- uint32_t pci_err_irq_map[4];
- uint32_t obio_irq_map[32];
- qemu_irq *pbm_irqs;
- qemu_irq *ivec_irqs;
- unsigned int irq_request;
- uint32_t reset_control;
- unsigned int nr_resets;
-} APBState;
-
-static inline void pbm_set_request(APBState *s, unsigned int irq_num)
-{
- APB_DPRINTF("%s: request irq %d\n", __func__, irq_num);
-
- s->irq_request = irq_num;
- qemu_set_irq(s->ivec_irqs[irq_num], 1);
-}
-
-static inline void pbm_check_irqs(APBState *s)
-{
-
- unsigned int i;
-
- /* Previous request is not acknowledged, resubmit */
- if (s->irq_request != NO_IRQ_REQUEST) {
- pbm_set_request(s, s->irq_request);
- return;
- }
- /* no request pending */
- if (s->pci_irq_in == 0ULL) {
- return;
- }
- for (i = 0; i < 32; i++) {
- if (s->pci_irq_in & (1ULL << i)) {
- if (s->pci_irq_map[i >> 2] & PBM_PCI_IMR_ENABLED) {
- pbm_set_request(s, i);
- return;
- }
- }
- }
- for (i = 32; i < 64; i++) {
- if (s->pci_irq_in & (1ULL << i)) {
- if (s->obio_irq_map[i - 32] & PBM_PCI_IMR_ENABLED) {
- pbm_set_request(s, i);
- break;
- }
- }
- }
-}
-
-static inline void pbm_clear_request(APBState *s, unsigned int irq_num)
-{
- APB_DPRINTF("%s: clear request irq %d\n", __func__, irq_num);
- qemu_set_irq(s->ivec_irqs[irq_num], 0);
- s->irq_request = NO_IRQ_REQUEST;
-}
-
-static AddressSpace *pbm_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
-{
- IOMMUState *is = opaque;
-
- return &is->iommu_as;
-}
-
-/* Called from RCU critical section */
-static IOMMUTLBEntry pbm_translate_iommu(MemoryRegion *iommu, hwaddr addr,
- bool is_write)
-{
- IOMMUState *is = container_of(iommu, IOMMUState, iommu);
- hwaddr baseaddr, offset;
- uint64_t tte;
- uint32_t tsbsize;
- IOMMUTLBEntry ret = {
- .target_as = &address_space_memory,
- .iova = 0,
- .translated_addr = 0,
- .addr_mask = ~(hwaddr)0,
- .perm = IOMMU_NONE,
- };
-
- if (!(is->regs[IOMMU_CTRL >> 3] & IOMMU_CTRL_MMU_EN)) {
- /* IOMMU disabled, passthrough using standard 8K page */
- ret.iova = addr & IOMMU_PAGE_MASK_8K;
- ret.translated_addr = addr;
- ret.addr_mask = IOMMU_PAGE_MASK_8K;
- ret.perm = IOMMU_RW;
-
- return ret;
- }
-
- baseaddr = is->regs[IOMMU_BASE >> 3];
- tsbsize = (is->regs[IOMMU_CTRL >> 3] >> IOMMU_CTRL_TSB_SHIFT) & 0x7;
-
- if (is->regs[IOMMU_CTRL >> 3] & IOMMU_CTRL_TBW_SIZE) {
- /* 64K */
- switch (tsbsize) {
- case 0:
- offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_64M) >> 13;
- break;
- case 1:
- offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_128M) >> 13;
- break;
- case 2:
- offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_256M) >> 13;
- break;
- case 3:
- offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_512M) >> 13;
- break;
- case 4:
- offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_1G) >> 13;
- break;
- case 5:
- offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_2G) >> 13;
- break;
- default:
- /* Not implemented, error */
- return ret;
- }
- } else {
- /* 8K */
- switch (tsbsize) {
- case 0:
- offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_8M) >> 10;
- break;
- case 1:
- offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_16M) >> 10;
- break;
- case 2:
- offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_32M) >> 10;
- break;
- case 3:
- offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_64M) >> 10;
- break;
- case 4:
- offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_128M) >> 10;
- break;
- case 5:
- offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_256M) >> 10;
- break;
- case 6:
- offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_512M) >> 10;
- break;
- case 7:
- offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_1G) >> 10;
- break;
- }
- }
-
- tte = address_space_ldq_be(&address_space_memory, baseaddr + offset,
- MEMTXATTRS_UNSPECIFIED, NULL);
-
- if (!(tte & IOMMU_TTE_DATA_V)) {
- /* Invalid mapping */
- return ret;
- }
-
- if (tte & IOMMU_TTE_DATA_W) {
- /* Writeable */
- ret.perm = IOMMU_RW;
- } else {
- ret.perm = IOMMU_RO;
- }
-
- /* Extract phys */
- if (tte & IOMMU_TTE_DATA_SIZE) {
- /* 64K */
- ret.iova = addr & IOMMU_PAGE_MASK_64K;
- ret.translated_addr = tte & IOMMU_TTE_PHYS_MASK_64K;
- ret.addr_mask = (IOMMU_PAGE_SIZE_64K - 1);
- } else {
- /* 8K */
- ret.iova = addr & IOMMU_PAGE_MASK_8K;
- ret.translated_addr = tte & IOMMU_TTE_PHYS_MASK_8K;
- ret.addr_mask = (IOMMU_PAGE_SIZE_8K - 1);
- }
-
- return ret;
-}
-
-static MemoryRegionIOMMUOps pbm_iommu_ops = {
- .translate = pbm_translate_iommu,
-};
-
-static void iommu_config_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- IOMMUState *is = opaque;
-
- IOMMU_DPRINTF("IOMMU config write: 0x%" HWADDR_PRIx " val: %" PRIx64
- " size: %d\n", addr, val, size);
-
- switch (addr) {
- case IOMMU_CTRL:
- if (size == 4) {
- is->regs[IOMMU_CTRL >> 3] &= 0xffffffffULL;
- is->regs[IOMMU_CTRL >> 3] |= val << 32;
- } else {
- is->regs[IOMMU_CTRL >> 3] = val;
- }
- break;
- case IOMMU_CTRL + 0x4:
- is->regs[IOMMU_CTRL >> 3] &= 0xffffffff00000000ULL;
- is->regs[IOMMU_CTRL >> 3] |= val & 0xffffffffULL;
- break;
- case IOMMU_BASE:
- if (size == 4) {
- is->regs[IOMMU_BASE >> 3] &= 0xffffffffULL;
- is->regs[IOMMU_BASE >> 3] |= val << 32;
- } else {
- is->regs[IOMMU_BASE >> 3] = val;
- }
- break;
- case IOMMU_BASE + 0x4:
- is->regs[IOMMU_BASE >> 3] &= 0xffffffff00000000ULL;
- is->regs[IOMMU_BASE >> 3] |= val & 0xffffffffULL;
- break;
- case IOMMU_FLUSH:
- case IOMMU_FLUSH + 0x4:
- break;
- default:
- qemu_log_mask(LOG_UNIMP,
- "apb iommu: Unimplemented register write "
- "reg 0x%" HWADDR_PRIx " size 0x%x value 0x%" PRIx64 "\n",
- addr, size, val);
- break;
- }
-}
-
-static uint64_t iommu_config_read(void *opaque, hwaddr addr, unsigned size)
-{
- IOMMUState *is = opaque;
- uint64_t val;
-
- switch (addr) {
- case IOMMU_CTRL:
- if (size == 4) {
- val = is->regs[IOMMU_CTRL >> 3] >> 32;
- } else {
- val = is->regs[IOMMU_CTRL >> 3];
- }
- break;
- case IOMMU_CTRL + 0x4:
- val = is->regs[IOMMU_CTRL >> 3] & 0xffffffffULL;
- break;
- case IOMMU_BASE:
- if (size == 4) {
- val = is->regs[IOMMU_BASE >> 3] >> 32;
- } else {
- val = is->regs[IOMMU_BASE >> 3];
- }
- break;
- case IOMMU_BASE + 0x4:
- val = is->regs[IOMMU_BASE >> 3] & 0xffffffffULL;
- break;
- case IOMMU_FLUSH:
- case IOMMU_FLUSH + 0x4:
- val = 0;
- break;
- default:
- qemu_log_mask(LOG_UNIMP,
- "apb iommu: Unimplemented register read "
- "reg 0x%" HWADDR_PRIx " size 0x%x\n",
- addr, size);
- val = 0;
- break;
- }
-
- IOMMU_DPRINTF("IOMMU config read: 0x%" HWADDR_PRIx " val: %" PRIx64
- " size: %d\n", addr, val, size);
-
- return val;
-}
-
-static void apb_config_writel (void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- APBState *s = opaque;
- IOMMUState *is = &s->iommu;
-
- APB_DPRINTF("%s: addr " TARGET_FMT_plx " val %" PRIx64 "\n", __func__, addr, val);
-
- switch (addr & 0xffff) {
- case 0x30 ... 0x4f: /* DMA error registers */
- /* XXX: not implemented yet */
- break;
- case 0x200 ... 0x217: /* IOMMU */
- iommu_config_write(is, (addr & 0x1f), val, size);
- break;
- case 0xc00 ... 0xc3f: /* PCI interrupt control */
- if (addr & 4) {
- unsigned int ino = (addr & 0x3f) >> 3;
- s->pci_irq_map[ino] &= PBM_PCI_IMR_MASK;
- s->pci_irq_map[ino] |= val & ~PBM_PCI_IMR_MASK;
- if ((s->irq_request == ino) && !(val & ~PBM_PCI_IMR_MASK)) {
- pbm_clear_request(s, ino);
- }
- pbm_check_irqs(s);
- }
- break;
- case 0x1000 ... 0x107f: /* OBIO interrupt control */
- if (addr & 4) {
- unsigned int ino = ((addr & 0xff) >> 3);
- s->obio_irq_map[ino] &= PBM_PCI_IMR_MASK;
- s->obio_irq_map[ino] |= val & ~PBM_PCI_IMR_MASK;
- if ((s->irq_request == (ino | 0x20))
- && !(val & ~PBM_PCI_IMR_MASK)) {
- pbm_clear_request(s, ino | 0x20);
- }
- pbm_check_irqs(s);
- }
- break;
- case 0x1400 ... 0x14ff: /* PCI interrupt clear */
- if (addr & 4) {
- unsigned int ino = (addr & 0xff) >> 5;
- if ((s->irq_request / 4) == ino) {
- pbm_clear_request(s, s->irq_request);
- pbm_check_irqs(s);
- }
- }
- break;
- case 0x1800 ... 0x1860: /* OBIO interrupt clear */
- if (addr & 4) {
- unsigned int ino = ((addr & 0xff) >> 3) | 0x20;
- if (s->irq_request == ino) {
- pbm_clear_request(s, ino);
- pbm_check_irqs(s);
- }
- }
- break;
- case 0x2000 ... 0x202f: /* PCI control */
- s->pci_control[(addr & 0x3f) >> 2] = val;
- break;
- case 0xf020 ... 0xf027: /* Reset control */
- if (addr & 4) {
- val &= RESET_MASK;
- s->reset_control &= ~(val & RESET_WCMASK);
- s->reset_control |= val & RESET_WMASK;
- if (val & SOFT_POR) {
- s->nr_resets = 0;
- qemu_system_reset_request();
- } else if (val & SOFT_XIR) {
- qemu_system_reset_request();
- }
- }
- break;
- case 0x5000 ... 0x51cf: /* PIO/DMA diagnostics */
- case 0xa400 ... 0xa67f: /* IOMMU diagnostics */
- case 0xa800 ... 0xa80f: /* Interrupt diagnostics */
- case 0xf000 ... 0xf01f: /* FFB config, memory control */
- /* we don't care */
- default:
- break;
- }
-}
-
-static uint64_t apb_config_readl (void *opaque,
- hwaddr addr, unsigned size)
-{
- APBState *s = opaque;
- IOMMUState *is = &s->iommu;
- uint32_t val;
-
- switch (addr & 0xffff) {
- case 0x30 ... 0x4f: /* DMA error registers */
- val = 0;
- /* XXX: not implemented yet */
- break;
- case 0x200 ... 0x217: /* IOMMU */
- val = iommu_config_read(is, (addr & 0x1f), size);
- break;
- case 0xc00 ... 0xc3f: /* PCI interrupt control */
- if (addr & 4) {
- val = s->pci_irq_map[(addr & 0x3f) >> 3];
- } else {
- val = 0;
- }
- break;
- case 0x1000 ... 0x107f: /* OBIO interrupt control */
- if (addr & 4) {
- val = s->obio_irq_map[(addr & 0xff) >> 3];
- } else {
- val = 0;
- }
- break;
- case 0x1080 ... 0x108f: /* PCI bus error */
- if (addr & 4) {
- val = s->pci_err_irq_map[(addr & 0xf) >> 3];
- } else {
- val = 0;
- }
- break;
- case 0x2000 ... 0x202f: /* PCI control */
- val = s->pci_control[(addr & 0x3f) >> 2];
- break;
- case 0xf020 ... 0xf027: /* Reset control */
- if (addr & 4) {
- val = s->reset_control;
- } else {
- val = 0;
- }
- break;
- case 0x5000 ... 0x51cf: /* PIO/DMA diagnostics */
- case 0xa400 ... 0xa67f: /* IOMMU diagnostics */
- case 0xa800 ... 0xa80f: /* Interrupt diagnostics */
- case 0xf000 ... 0xf01f: /* FFB config, memory control */
- /* we don't care */
- default:
- val = 0;
- break;
- }
- APB_DPRINTF("%s: addr " TARGET_FMT_plx " -> %x\n", __func__, addr, val);
-
- return val;
-}
-
-static const MemoryRegionOps apb_config_ops = {
- .read = apb_config_readl,
- .write = apb_config_writel,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void apb_pci_config_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- APBState *s = opaque;
- PCIHostState *phb = PCI_HOST_BRIDGE(s);
-
- val = qemu_bswap_len(val, size);
- APB_DPRINTF("%s: addr " TARGET_FMT_plx " val %" PRIx64 "\n", __func__, addr, val);
- pci_data_write(phb->bus, addr, val, size);
-}
-
-static uint64_t apb_pci_config_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- uint32_t ret;
- APBState *s = opaque;
- PCIHostState *phb = PCI_HOST_BRIDGE(s);
-
- ret = pci_data_read(phb->bus, addr, size);
- ret = qemu_bswap_len(ret, size);
- APB_DPRINTF("%s: addr " TARGET_FMT_plx " -> %x\n", __func__, addr, ret);
- return ret;
-}
-
-/* The APB host has an IRQ line for each IRQ line of each slot. */
-static int pci_apb_map_irq(PCIDevice *pci_dev, int irq_num)
-{
- return ((pci_dev->devfn & 0x18) >> 1) + irq_num;
-}
-
-static int pci_pbm_map_irq(PCIDevice *pci_dev, int irq_num)
-{
- int bus_offset;
- if (pci_dev->devfn & 1)
- bus_offset = 16;
- else
- bus_offset = 0;
- return (bus_offset + (PCI_SLOT(pci_dev->devfn) << 2) + irq_num) & 0x1f;
-}
-
-static void pci_apb_set_irq(void *opaque, int irq_num, int level)
-{
- APBState *s = opaque;
-
- APB_DPRINTF("%s: set irq_in %d level %d\n", __func__, irq_num, level);
- /* PCI IRQ map onto the first 32 INO. */
- if (irq_num < 32) {
- if (level) {
- s->pci_irq_in |= 1ULL << irq_num;
- if (s->pci_irq_map[irq_num >> 2] & PBM_PCI_IMR_ENABLED) {
- pbm_set_request(s, irq_num);
- }
- } else {
- s->pci_irq_in &= ~(1ULL << irq_num);
- }
- } else {
- /* OBIO IRQ map onto the next 32 INO. */
- if (level) {
- APB_DPRINTF("%s: set irq %d level %d\n", __func__, irq_num, level);
- s->pci_irq_in |= 1ULL << irq_num;
- if ((s->irq_request == NO_IRQ_REQUEST)
- && (s->obio_irq_map[irq_num - 32] & PBM_PCI_IMR_ENABLED)) {
- pbm_set_request(s, irq_num);
- }
- } else {
- s->pci_irq_in &= ~(1ULL << irq_num);
- }
- }
-}
-
-static int apb_pci_bridge_initfn(PCIDevice *dev)
-{
- pci_bridge_initfn(dev, TYPE_PCI_BUS);
-
- /*
- * command register:
- * According to PCI bridge spec, after reset
- * bus master bit is off
- * memory space enable bit is off
- * According to manual (805-1251.pdf).
- * the reset value should be zero unless the boot pin is tied high
- * (which is true) and thus it should be PCI_COMMAND_MEMORY.
- */
- pci_set_word(dev->config + PCI_COMMAND,
- PCI_COMMAND_MEMORY);
- pci_set_word(dev->config + PCI_STATUS,
- PCI_STATUS_FAST_BACK | PCI_STATUS_66MHZ |
- PCI_STATUS_DEVSEL_MEDIUM);
- return 0;
-}
-
-PCIBus *pci_apb_init(hwaddr special_base,
- hwaddr mem_base,
- qemu_irq *ivec_irqs, PCIBus **bus2, PCIBus **bus3,
- qemu_irq **pbm_irqs)
-{
- DeviceState *dev;
- SysBusDevice *s;
- PCIHostState *phb;
- APBState *d;
- IOMMUState *is;
- PCIDevice *pci_dev;
- PCIBridge *br;
-
- /* Ultrasparc PBM main bus */
- dev = qdev_create(NULL, TYPE_APB);
- qdev_init_nofail(dev);
- s = SYS_BUS_DEVICE(dev);
- /* apb_config */
- sysbus_mmio_map(s, 0, special_base);
- /* PCI configuration space */
- sysbus_mmio_map(s, 1, special_base + 0x1000000ULL);
- /* pci_ioport */
- sysbus_mmio_map(s, 2, special_base + 0x2000000ULL);
- d = APB_DEVICE(dev);
-
- memory_region_init(&d->pci_mmio, OBJECT(s), "pci-mmio", 0x100000000ULL);
- memory_region_add_subregion(get_system_memory(), mem_base, &d->pci_mmio);
-
- phb = PCI_HOST_BRIDGE(dev);
- phb->bus = pci_register_bus(DEVICE(phb), "pci",
- pci_apb_set_irq, pci_pbm_map_irq, d,
- &d->pci_mmio,
- get_system_io(),
- 0, 32, TYPE_PCI_BUS);
-
- *pbm_irqs = d->pbm_irqs;
- d->ivec_irqs = ivec_irqs;
-
- pci_create_simple(phb->bus, 0, "pbm-pci");
-
- /* APB IOMMU */
- is = &d->iommu;
- memset(is, 0, sizeof(IOMMUState));
-
- memory_region_init_iommu(&is->iommu, OBJECT(dev), &pbm_iommu_ops,
- "iommu-apb", UINT64_MAX);
- address_space_init(&is->iommu_as, &is->iommu, "pbm-as");
- pci_setup_iommu(phb->bus, pbm_pci_dma_iommu, is);
-
- /* APB secondary busses */
- pci_dev = pci_create_multifunction(phb->bus, PCI_DEVFN(1, 0), true,
- "pbm-bridge");
- br = PCI_BRIDGE(pci_dev);
- pci_bridge_map_irq(br, "Advanced PCI Bus secondary bridge 1",
- pci_apb_map_irq);
- qdev_init_nofail(&pci_dev->qdev);
- *bus2 = pci_bridge_get_sec_bus(br);
-
- pci_dev = pci_create_multifunction(phb->bus, PCI_DEVFN(1, 1), true,
- "pbm-bridge");
- br = PCI_BRIDGE(pci_dev);
- pci_bridge_map_irq(br, "Advanced PCI Bus secondary bridge 2",
- pci_apb_map_irq);
- qdev_init_nofail(&pci_dev->qdev);
- *bus3 = pci_bridge_get_sec_bus(br);
-
- return phb->bus;
-}
-
-static void pci_pbm_reset(DeviceState *d)
-{
- unsigned int i;
- APBState *s = APB_DEVICE(d);
-
- for (i = 0; i < 8; i++) {
- s->pci_irq_map[i] &= PBM_PCI_IMR_MASK;
- }
- for (i = 0; i < 32; i++) {
- s->obio_irq_map[i] &= PBM_PCI_IMR_MASK;
- }
-
- s->irq_request = NO_IRQ_REQUEST;
- s->pci_irq_in = 0ULL;
-
- if (s->nr_resets++ == 0) {
- /* Power on reset */
- s->reset_control = POR;
- }
-}
-
-static const MemoryRegionOps pci_config_ops = {
- .read = apb_pci_config_read,
- .write = apb_pci_config_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int pci_pbm_init_device(SysBusDevice *dev)
-{
- APBState *s;
- unsigned int i;
-
- s = APB_DEVICE(dev);
- for (i = 0; i < 8; i++) {
- s->pci_irq_map[i] = (0x1f << 6) | (i << 2);
- }
- for (i = 0; i < 2; i++) {
- s->pci_err_irq_map[i] = (0x1f << 6) | 0x30;
- }
- for (i = 0; i < 32; i++) {
- s->obio_irq_map[i] = ((0x1f << 6) | 0x20) + i;
- }
- s->pbm_irqs = qemu_allocate_irqs(pci_apb_set_irq, s, MAX_IVEC);
- s->irq_request = NO_IRQ_REQUEST;
- s->pci_irq_in = 0ULL;
-
- /* apb_config */
- memory_region_init_io(&s->apb_config, OBJECT(s), &apb_config_ops, s,
- "apb-config", 0x10000);
- /* at region 0 */
- sysbus_init_mmio(dev, &s->apb_config);
-
- memory_region_init_io(&s->pci_config, OBJECT(s), &pci_config_ops, s,
- "apb-pci-config", 0x1000000);
- /* at region 1 */
- sysbus_init_mmio(dev, &s->pci_config);
-
- /* pci_ioport */
- memory_region_init_alias(&s->pci_ioport, OBJECT(s), "apb-pci-ioport",
- get_system_io(), 0, 0x10000);
- /* at region 2 */
- sysbus_init_mmio(dev, &s->pci_ioport);
-
- return 0;
-}
-
-static void pbm_pci_host_realize(PCIDevice *d, Error **errp)
-{
- pci_set_word(d->config + PCI_COMMAND,
- PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
- pci_set_word(d->config + PCI_STATUS,
- PCI_STATUS_FAST_BACK | PCI_STATUS_66MHZ |
- PCI_STATUS_DEVSEL_MEDIUM);
-}
-
-static void pbm_pci_host_class_init(ObjectClass *klass, void *data)
-{
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- k->realize = pbm_pci_host_realize;
- k->vendor_id = PCI_VENDOR_ID_SUN;
- k->device_id = PCI_DEVICE_ID_SUN_SABRE;
- k->class_id = PCI_CLASS_BRIDGE_HOST;
- /*
- * PCI-facing part of the host bridge, not usable without the
- * host-facing part, which can't be device_add'ed, yet.
- */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo pbm_pci_host_info = {
- .name = "pbm-pci",
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(PCIDevice),
- .class_init = pbm_pci_host_class_init,
-};
-
-static void pbm_host_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = pci_pbm_init_device;
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
- dc->reset = pci_pbm_reset;
-}
-
-static const TypeInfo pbm_host_info = {
- .name = TYPE_APB,
- .parent = TYPE_PCI_HOST_BRIDGE,
- .instance_size = sizeof(APBState),
- .class_init = pbm_host_class_init,
-};
-
-static void pbm_pci_bridge_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->init = apb_pci_bridge_initfn;
- k->exit = pci_bridge_exitfn;
- k->vendor_id = PCI_VENDOR_ID_SUN;
- k->device_id = PCI_DEVICE_ID_SUN_SIMBA;
- k->revision = 0x11;
- k->config_write = pci_bridge_write_config;
- k->is_bridge = 1;
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
- dc->reset = pci_bridge_reset;
- dc->vmsd = &vmstate_pci_device;
-}
-
-static const TypeInfo pbm_pci_bridge_info = {
- .name = "pbm-bridge",
- .parent = TYPE_PCI_BRIDGE,
- .class_init = pbm_pci_bridge_class_init,
-};
-
-static void pbm_register_types(void)
-{
- type_register_static(&pbm_host_info);
- type_register_static(&pbm_pci_host_info);
- type_register_static(&pbm_pci_bridge_info);
-}
-
-type_init(pbm_register_types)
diff --git a/qemu/hw/pci-host/bonito.c b/qemu/hw/pci-host/bonito.c
deleted file mode 100644
index 1999ece59..000000000
--- a/qemu/hw/pci-host/bonito.c
+++ /dev/null
@@ -1,858 +0,0 @@
-/*
- * bonito north bridge support
- *
- * Copyright (c) 2008 yajin (yajin@vm-kernel.org)
- * Copyright (c) 2010 Huacai Chen (zltjiangshi@gmail.com)
- *
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-/*
- * fulong 2e mini pc has a bonito north bridge.
- */
-
-/* what is the meaning of devfn in qemu and IDSEL in bonito northbridge?
- *
- * devfn pci_slot<<3 + funno
- * one pci bus can have 32 devices and each device can have 8 functions.
- *
- * In bonito north bridge, pci slot = IDSEL bit - 12.
- * For example, PCI_IDSEL_VIA686B = 17,
- * pci slot = 17-12=5
- *
- * so
- * VT686B_FUN0's devfn = (5<<3)+0
- * VT686B_FUN1's devfn = (5<<3)+1
- *
- * qemu also uses pci address for north bridge to access pci config register.
- * bus_no [23:16]
- * dev_no [15:11]
- * fun_no [10:8]
- * reg_no [7:2]
- *
- * so function bonito_sbridge_pciaddr for the translation from
- * north bridge address to pci address.
- */
-
-#include "qemu/osdep.h"
-
-#include "hw/hw.h"
-#include "hw/pci/pci.h"
-#include "hw/i386/pc.h"
-#include "hw/mips/mips.h"
-#include "hw/pci/pci_host.h"
-#include "sysemu/sysemu.h"
-#include "exec/address-spaces.h"
-
-//#define DEBUG_BONITO
-
-#ifdef DEBUG_BONITO
-#define DPRINTF(fmt, ...) fprintf(stderr, "%s: " fmt, __FUNCTION__, ##__VA_ARGS__)
-#else
-#define DPRINTF(fmt, ...)
-#endif
-
-/* from linux soure code. include/asm-mips/mips-boards/bonito64.h*/
-#define BONITO_BOOT_BASE 0x1fc00000
-#define BONITO_BOOT_SIZE 0x00100000
-#define BONITO_BOOT_TOP (BONITO_BOOT_BASE+BONITO_BOOT_SIZE-1)
-#define BONITO_FLASH_BASE 0x1c000000
-#define BONITO_FLASH_SIZE 0x03000000
-#define BONITO_FLASH_TOP (BONITO_FLASH_BASE+BONITO_FLASH_SIZE-1)
-#define BONITO_SOCKET_BASE 0x1f800000
-#define BONITO_SOCKET_SIZE 0x00400000
-#define BONITO_SOCKET_TOP (BONITO_SOCKET_BASE+BONITO_SOCKET_SIZE-1)
-#define BONITO_REG_BASE 0x1fe00000
-#define BONITO_REG_SIZE 0x00040000
-#define BONITO_REG_TOP (BONITO_REG_BASE+BONITO_REG_SIZE-1)
-#define BONITO_DEV_BASE 0x1ff00000
-#define BONITO_DEV_SIZE 0x00100000
-#define BONITO_DEV_TOP (BONITO_DEV_BASE+BONITO_DEV_SIZE-1)
-#define BONITO_PCILO_BASE 0x10000000
-#define BONITO_PCILO_BASE_VA 0xb0000000
-#define BONITO_PCILO_SIZE 0x0c000000
-#define BONITO_PCILO_TOP (BONITO_PCILO_BASE+BONITO_PCILO_SIZE-1)
-#define BONITO_PCILO0_BASE 0x10000000
-#define BONITO_PCILO1_BASE 0x14000000
-#define BONITO_PCILO2_BASE 0x18000000
-#define BONITO_PCIHI_BASE 0x20000000
-#define BONITO_PCIHI_SIZE 0x20000000
-#define BONITO_PCIHI_TOP (BONITO_PCIHI_BASE+BONITO_PCIHI_SIZE-1)
-#define BONITO_PCIIO_BASE 0x1fd00000
-#define BONITO_PCIIO_BASE_VA 0xbfd00000
-#define BONITO_PCIIO_SIZE 0x00010000
-#define BONITO_PCIIO_TOP (BONITO_PCIIO_BASE+BONITO_PCIIO_SIZE-1)
-#define BONITO_PCICFG_BASE 0x1fe80000
-#define BONITO_PCICFG_SIZE 0x00080000
-#define BONITO_PCICFG_TOP (BONITO_PCICFG_BASE+BONITO_PCICFG_SIZE-1)
-
-
-#define BONITO_PCICONFIGBASE 0x00
-#define BONITO_REGBASE 0x100
-
-#define BONITO_PCICONFIG_BASE (BONITO_PCICONFIGBASE+BONITO_REG_BASE)
-#define BONITO_PCICONFIG_SIZE (0x100)
-
-#define BONITO_INTERNAL_REG_BASE (BONITO_REGBASE+BONITO_REG_BASE)
-#define BONITO_INTERNAL_REG_SIZE (0x70)
-
-#define BONITO_SPCICONFIG_BASE (BONITO_PCICFG_BASE)
-#define BONITO_SPCICONFIG_SIZE (BONITO_PCICFG_SIZE)
-
-
-
-/* 1. Bonito h/w Configuration */
-/* Power on register */
-
-#define BONITO_BONPONCFG (0x00 >> 2) /* 0x100 */
-#define BONITO_BONGENCFG_OFFSET 0x4
-#define BONITO_BONGENCFG (BONITO_BONGENCFG_OFFSET>>2) /*0x104 */
-
-/* 2. IO & IDE configuration */
-#define BONITO_IODEVCFG (0x08 >> 2) /* 0x108 */
-
-/* 3. IO & IDE configuration */
-#define BONITO_SDCFG (0x0c >> 2) /* 0x10c */
-
-/* 4. PCI address map control */
-#define BONITO_PCIMAP (0x10 >> 2) /* 0x110 */
-#define BONITO_PCIMEMBASECFG (0x14 >> 2) /* 0x114 */
-#define BONITO_PCIMAP_CFG (0x18 >> 2) /* 0x118 */
-
-/* 5. ICU & GPIO regs */
-/* GPIO Regs - r/w */
-#define BONITO_GPIODATA_OFFSET 0x1c
-#define BONITO_GPIODATA (BONITO_GPIODATA_OFFSET >> 2) /* 0x11c */
-#define BONITO_GPIOIE (0x20 >> 2) /* 0x120 */
-
-/* ICU Configuration Regs - r/w */
-#define BONITO_INTEDGE (0x24 >> 2) /* 0x124 */
-#define BONITO_INTSTEER (0x28 >> 2) /* 0x128 */
-#define BONITO_INTPOL (0x2c >> 2) /* 0x12c */
-
-/* ICU Enable Regs - IntEn & IntISR are r/o. */
-#define BONITO_INTENSET (0x30 >> 2) /* 0x130 */
-#define BONITO_INTENCLR (0x34 >> 2) /* 0x134 */
-#define BONITO_INTEN (0x38 >> 2) /* 0x138 */
-#define BONITO_INTISR (0x3c >> 2) /* 0x13c */
-
-/* PCI mail boxes */
-#define BONITO_PCIMAIL0_OFFSET 0x40
-#define BONITO_PCIMAIL1_OFFSET 0x44
-#define BONITO_PCIMAIL2_OFFSET 0x48
-#define BONITO_PCIMAIL3_OFFSET 0x4c
-#define BONITO_PCIMAIL0 (0x40 >> 2) /* 0x140 */
-#define BONITO_PCIMAIL1 (0x44 >> 2) /* 0x144 */
-#define BONITO_PCIMAIL2 (0x48 >> 2) /* 0x148 */
-#define BONITO_PCIMAIL3 (0x4c >> 2) /* 0x14c */
-
-/* 6. PCI cache */
-#define BONITO_PCICACHECTRL (0x50 >> 2) /* 0x150 */
-#define BONITO_PCICACHETAG (0x54 >> 2) /* 0x154 */
-#define BONITO_PCIBADADDR (0x58 >> 2) /* 0x158 */
-#define BONITO_PCIMSTAT (0x5c >> 2) /* 0x15c */
-
-/* 7. other*/
-#define BONITO_TIMECFG (0x60 >> 2) /* 0x160 */
-#define BONITO_CPUCFG (0x64 >> 2) /* 0x164 */
-#define BONITO_DQCFG (0x68 >> 2) /* 0x168 */
-#define BONITO_MEMSIZE (0x6C >> 2) /* 0x16c */
-
-#define BONITO_REGS (0x70 >> 2)
-
-/* PCI config for south bridge. type 0 */
-#define BONITO_PCICONF_IDSEL_MASK 0xfffff800 /* [31:11] */
-#define BONITO_PCICONF_IDSEL_OFFSET 11
-#define BONITO_PCICONF_FUN_MASK 0x700 /* [10:8] */
-#define BONITO_PCICONF_FUN_OFFSET 8
-#define BONITO_PCICONF_REG_MASK 0xFC
-#define BONITO_PCICONF_REG_OFFSET 0
-
-
-/* idsel BIT = pci slot number +12 */
-#define PCI_SLOT_BASE 12
-#define PCI_IDSEL_VIA686B_BIT (17)
-#define PCI_IDSEL_VIA686B (1<<PCI_IDSEL_VIA686B_BIT)
-
-#define PCI_ADDR(busno,devno,funno,regno) \
- ((((busno)<<16)&0xff0000) + (((devno)<<11)&0xf800) + (((funno)<<8)&0x700) + (regno))
-
-typedef struct BonitoState BonitoState;
-
-typedef struct PCIBonitoState
-{
- PCIDevice dev;
-
- BonitoState *pcihost;
- uint32_t regs[BONITO_REGS];
-
- struct bonldma {
- uint32_t ldmactrl;
- uint32_t ldmastat;
- uint32_t ldmaaddr;
- uint32_t ldmago;
- } bonldma;
-
- /* Based at 1fe00300, bonito Copier */
- struct boncop {
- uint32_t copctrl;
- uint32_t copstat;
- uint32_t coppaddr;
- uint32_t copgo;
- } boncop;
-
- /* Bonito registers */
- MemoryRegion iomem;
- MemoryRegion iomem_ldma;
- MemoryRegion iomem_cop;
- MemoryRegion bonito_pciio;
- MemoryRegion bonito_localio;
-
-} PCIBonitoState;
-
-struct BonitoState {
- PCIHostState parent_obj;
- qemu_irq *pic;
- PCIBonitoState *pci_dev;
-};
-
-#define TYPE_BONITO_PCI_HOST_BRIDGE "Bonito-pcihost"
-#define BONITO_PCI_HOST_BRIDGE(obj) \
- OBJECT_CHECK(BonitoState, (obj), TYPE_BONITO_PCI_HOST_BRIDGE)
-
-#define TYPE_PCI_BONITO "Bonito"
-#define PCI_BONITO(obj) \
- OBJECT_CHECK(PCIBonitoState, (obj), TYPE_PCI_BONITO)
-
-static void bonito_writel(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- PCIBonitoState *s = opaque;
- uint32_t saddr;
- int reset = 0;
-
- saddr = addr >> 2;
-
- DPRINTF("bonito_writel "TARGET_FMT_plx" val %x saddr %x\n", addr, val, saddr);
- switch (saddr) {
- case BONITO_BONPONCFG:
- case BONITO_IODEVCFG:
- case BONITO_SDCFG:
- case BONITO_PCIMAP:
- case BONITO_PCIMEMBASECFG:
- case BONITO_PCIMAP_CFG:
- case BONITO_GPIODATA:
- case BONITO_GPIOIE:
- case BONITO_INTEDGE:
- case BONITO_INTSTEER:
- case BONITO_INTPOL:
- case BONITO_PCIMAIL0:
- case BONITO_PCIMAIL1:
- case BONITO_PCIMAIL2:
- case BONITO_PCIMAIL3:
- case BONITO_PCICACHECTRL:
- case BONITO_PCICACHETAG:
- case BONITO_PCIBADADDR:
- case BONITO_PCIMSTAT:
- case BONITO_TIMECFG:
- case BONITO_CPUCFG:
- case BONITO_DQCFG:
- case BONITO_MEMSIZE:
- s->regs[saddr] = val;
- break;
- case BONITO_BONGENCFG:
- if (!(s->regs[saddr] & 0x04) && (val & 0x04)) {
- reset = 1; /* bit 2 jump from 0 to 1 cause reset */
- }
- s->regs[saddr] = val;
- if (reset) {
- qemu_system_reset_request();
- }
- break;
- case BONITO_INTENSET:
- s->regs[BONITO_INTENSET] = val;
- s->regs[BONITO_INTEN] |= val;
- break;
- case BONITO_INTENCLR:
- s->regs[BONITO_INTENCLR] = val;
- s->regs[BONITO_INTEN] &= ~val;
- break;
- case BONITO_INTEN:
- case BONITO_INTISR:
- DPRINTF("write to readonly bonito register %x\n", saddr);
- break;
- default:
- DPRINTF("write to unknown bonito register %x\n", saddr);
- break;
- }
-}
-
-static uint64_t bonito_readl(void *opaque, hwaddr addr,
- unsigned size)
-{
- PCIBonitoState *s = opaque;
- uint32_t saddr;
-
- saddr = addr >> 2;
-
- DPRINTF("bonito_readl "TARGET_FMT_plx"\n", addr);
- switch (saddr) {
- case BONITO_INTISR:
- return s->regs[saddr];
- default:
- return s->regs[saddr];
- }
-}
-
-static const MemoryRegionOps bonito_ops = {
- .read = bonito_readl,
- .write = bonito_writel,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static void bonito_pciconf_writel(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- PCIBonitoState *s = opaque;
- PCIDevice *d = PCI_DEVICE(s);
-
- DPRINTF("bonito_pciconf_writel "TARGET_FMT_plx" val %x\n", addr, val);
- d->config_write(d, addr, val, 4);
-}
-
-static uint64_t bonito_pciconf_readl(void *opaque, hwaddr addr,
- unsigned size)
-{
-
- PCIBonitoState *s = opaque;
- PCIDevice *d = PCI_DEVICE(s);
-
- DPRINTF("bonito_pciconf_readl "TARGET_FMT_plx"\n", addr);
- return d->config_read(d, addr, 4);
-}
-
-/* north bridge PCI configure space. 0x1fe0 0000 - 0x1fe0 00ff */
-
-static const MemoryRegionOps bonito_pciconf_ops = {
- .read = bonito_pciconf_readl,
- .write = bonito_pciconf_writel,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static uint64_t bonito_ldma_readl(void *opaque, hwaddr addr,
- unsigned size)
-{
- uint32_t val;
- PCIBonitoState *s = opaque;
-
- if (addr >= sizeof(s->bonldma)) {
- return 0;
- }
-
- val = ((uint32_t *)(&s->bonldma))[addr/sizeof(uint32_t)];
-
- return val;
-}
-
-static void bonito_ldma_writel(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- PCIBonitoState *s = opaque;
-
- if (addr >= sizeof(s->bonldma)) {
- return;
- }
-
- ((uint32_t *)(&s->bonldma))[addr/sizeof(uint32_t)] = val & 0xffffffff;
-}
-
-static const MemoryRegionOps bonito_ldma_ops = {
- .read = bonito_ldma_readl,
- .write = bonito_ldma_writel,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static uint64_t bonito_cop_readl(void *opaque, hwaddr addr,
- unsigned size)
-{
- uint32_t val;
- PCIBonitoState *s = opaque;
-
- if (addr >= sizeof(s->boncop)) {
- return 0;
- }
-
- val = ((uint32_t *)(&s->boncop))[addr/sizeof(uint32_t)];
-
- return val;
-}
-
-static void bonito_cop_writel(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- PCIBonitoState *s = opaque;
-
- if (addr >= sizeof(s->boncop)) {
- return;
- }
-
- ((uint32_t *)(&s->boncop))[addr/sizeof(uint32_t)] = val & 0xffffffff;
-}
-
-static const MemoryRegionOps bonito_cop_ops = {
- .read = bonito_cop_readl,
- .write = bonito_cop_writel,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static uint32_t bonito_sbridge_pciaddr(void *opaque, hwaddr addr)
-{
- PCIBonitoState *s = opaque;
- PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
- uint32_t cfgaddr;
- uint32_t idsel;
- uint32_t devno;
- uint32_t funno;
- uint32_t regno;
- uint32_t pciaddr;
-
- /* support type0 pci config */
- if ((s->regs[BONITO_PCIMAP_CFG] & 0x10000) != 0x0) {
- return 0xffffffff;
- }
-
- cfgaddr = addr & 0xffff;
- cfgaddr |= (s->regs[BONITO_PCIMAP_CFG] & 0xffff) << 16;
-
- idsel = (cfgaddr & BONITO_PCICONF_IDSEL_MASK) >> BONITO_PCICONF_IDSEL_OFFSET;
- devno = ctz32(idsel);
- funno = (cfgaddr & BONITO_PCICONF_FUN_MASK) >> BONITO_PCICONF_FUN_OFFSET;
- regno = (cfgaddr & BONITO_PCICONF_REG_MASK) >> BONITO_PCICONF_REG_OFFSET;
-
- if (idsel == 0) {
- fprintf(stderr, "error in bonito pci config address " TARGET_FMT_plx
- ",pcimap_cfg=%x\n", addr, s->regs[BONITO_PCIMAP_CFG]);
- exit(1);
- }
- pciaddr = PCI_ADDR(pci_bus_num(phb->bus), devno, funno, regno);
- DPRINTF("cfgaddr %x pciaddr %x busno %x devno %d funno %d regno %d\n",
- cfgaddr, pciaddr, pci_bus_num(phb->bus), devno, funno, regno);
-
- return pciaddr;
-}
-
-static void bonito_spciconf_writeb(void *opaque, hwaddr addr,
- uint32_t val)
-{
- PCIBonitoState *s = opaque;
- PCIDevice *d = PCI_DEVICE(s);
- PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
- uint32_t pciaddr;
- uint16_t status;
-
- DPRINTF("bonito_spciconf_writeb "TARGET_FMT_plx" val %x\n", addr, val);
- pciaddr = bonito_sbridge_pciaddr(s, addr);
-
- if (pciaddr == 0xffffffff) {
- return;
- }
-
- /* set the pci address in s->config_reg */
- phb->config_reg = (pciaddr) | (1u << 31);
- pci_data_write(phb->bus, phb->config_reg, val & 0xff, 1);
-
- /* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */
- status = pci_get_word(d->config + PCI_STATUS);
- status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT);
- pci_set_word(d->config + PCI_STATUS, status);
-}
-
-static void bonito_spciconf_writew(void *opaque, hwaddr addr,
- uint32_t val)
-{
- PCIBonitoState *s = opaque;
- PCIDevice *d = PCI_DEVICE(s);
- PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
- uint32_t pciaddr;
- uint16_t status;
-
- DPRINTF("bonito_spciconf_writew "TARGET_FMT_plx" val %x\n", addr, val);
- assert((addr & 0x1) == 0);
-
- pciaddr = bonito_sbridge_pciaddr(s, addr);
-
- if (pciaddr == 0xffffffff) {
- return;
- }
-
- /* set the pci address in s->config_reg */
- phb->config_reg = (pciaddr) | (1u << 31);
- pci_data_write(phb->bus, phb->config_reg, val, 2);
-
- /* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */
- status = pci_get_word(d->config + PCI_STATUS);
- status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT);
- pci_set_word(d->config + PCI_STATUS, status);
-}
-
-static void bonito_spciconf_writel(void *opaque, hwaddr addr,
- uint32_t val)
-{
- PCIBonitoState *s = opaque;
- PCIDevice *d = PCI_DEVICE(s);
- PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
- uint32_t pciaddr;
- uint16_t status;
-
- DPRINTF("bonito_spciconf_writel "TARGET_FMT_plx" val %x\n", addr, val);
- assert((addr & 0x3) == 0);
-
- pciaddr = bonito_sbridge_pciaddr(s, addr);
-
- if (pciaddr == 0xffffffff) {
- return;
- }
-
- /* set the pci address in s->config_reg */
- phb->config_reg = (pciaddr) | (1u << 31);
- pci_data_write(phb->bus, phb->config_reg, val, 4);
-
- /* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */
- status = pci_get_word(d->config + PCI_STATUS);
- status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT);
- pci_set_word(d->config + PCI_STATUS, status);
-}
-
-static uint32_t bonito_spciconf_readb(void *opaque, hwaddr addr)
-{
- PCIBonitoState *s = opaque;
- PCIDevice *d = PCI_DEVICE(s);
- PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
- uint32_t pciaddr;
- uint16_t status;
-
- DPRINTF("bonito_spciconf_readb "TARGET_FMT_plx"\n", addr);
- pciaddr = bonito_sbridge_pciaddr(s, addr);
-
- if (pciaddr == 0xffffffff) {
- return 0xff;
- }
-
- /* set the pci address in s->config_reg */
- phb->config_reg = (pciaddr) | (1u << 31);
-
- /* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */
- status = pci_get_word(d->config + PCI_STATUS);
- status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT);
- pci_set_word(d->config + PCI_STATUS, status);
-
- return pci_data_read(phb->bus, phb->config_reg, 1);
-}
-
-static uint32_t bonito_spciconf_readw(void *opaque, hwaddr addr)
-{
- PCIBonitoState *s = opaque;
- PCIDevice *d = PCI_DEVICE(s);
- PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
- uint32_t pciaddr;
- uint16_t status;
-
- DPRINTF("bonito_spciconf_readw "TARGET_FMT_plx"\n", addr);
- assert((addr & 0x1) == 0);
-
- pciaddr = bonito_sbridge_pciaddr(s, addr);
-
- if (pciaddr == 0xffffffff) {
- return 0xffff;
- }
-
- /* set the pci address in s->config_reg */
- phb->config_reg = (pciaddr) | (1u << 31);
-
- /* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */
- status = pci_get_word(d->config + PCI_STATUS);
- status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT);
- pci_set_word(d->config + PCI_STATUS, status);
-
- return pci_data_read(phb->bus, phb->config_reg, 2);
-}
-
-static uint32_t bonito_spciconf_readl(void *opaque, hwaddr addr)
-{
- PCIBonitoState *s = opaque;
- PCIDevice *d = PCI_DEVICE(s);
- PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
- uint32_t pciaddr;
- uint16_t status;
-
- DPRINTF("bonito_spciconf_readl "TARGET_FMT_plx"\n", addr);
- assert((addr & 0x3) == 0);
-
- pciaddr = bonito_sbridge_pciaddr(s, addr);
-
- if (pciaddr == 0xffffffff) {
- return 0xffffffff;
- }
-
- /* set the pci address in s->config_reg */
- phb->config_reg = (pciaddr) | (1u << 31);
-
- /* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */
- status = pci_get_word(d->config + PCI_STATUS);
- status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT);
- pci_set_word(d->config + PCI_STATUS, status);
-
- return pci_data_read(phb->bus, phb->config_reg, 4);
-}
-
-/* south bridge PCI configure space. 0x1fe8 0000 - 0x1fef ffff */
-static const MemoryRegionOps bonito_spciconf_ops = {
- .old_mmio = {
- .read = {
- bonito_spciconf_readb,
- bonito_spciconf_readw,
- bonito_spciconf_readl,
- },
- .write = {
- bonito_spciconf_writeb,
- bonito_spciconf_writew,
- bonito_spciconf_writel,
- },
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-#define BONITO_IRQ_BASE 32
-
-static void pci_bonito_set_irq(void *opaque, int irq_num, int level)
-{
- BonitoState *s = opaque;
- qemu_irq *pic = s->pic;
- PCIBonitoState *bonito_state = s->pci_dev;
- int internal_irq = irq_num - BONITO_IRQ_BASE;
-
- if (bonito_state->regs[BONITO_INTEDGE] & (1 << internal_irq)) {
- qemu_irq_pulse(*pic);
- } else { /* level triggered */
- if (bonito_state->regs[BONITO_INTPOL] & (1 << internal_irq)) {
- qemu_irq_raise(*pic);
- } else {
- qemu_irq_lower(*pic);
- }
- }
-}
-
-/* map the original irq (0~3) to bonito irq (16~47, but 16~31 are unused) */
-static int pci_bonito_map_irq(PCIDevice * pci_dev, int irq_num)
-{
- int slot;
-
- slot = (pci_dev->devfn >> 3);
-
- switch (slot) {
- case 5: /* FULONG2E_VIA_SLOT, SouthBridge, IDE, USB, ACPI, AC97, MC97 */
- return irq_num % 4 + BONITO_IRQ_BASE;
- case 6: /* FULONG2E_ATI_SLOT, VGA */
- return 4 + BONITO_IRQ_BASE;
- case 7: /* FULONG2E_RTL_SLOT, RTL8139 */
- return 5 + BONITO_IRQ_BASE;
- case 8 ... 12: /* PCI slot 1 to 4 */
- return (slot - 8 + irq_num) + 6 + BONITO_IRQ_BASE;
- default: /* Unknown device, don't do any translation */
- return irq_num;
- }
-}
-
-static void bonito_reset(void *opaque)
-{
- PCIBonitoState *s = opaque;
-
- /* set the default value of north bridge registers */
-
- s->regs[BONITO_BONPONCFG] = 0xc40;
- s->regs[BONITO_BONGENCFG] = 0x1384;
- s->regs[BONITO_IODEVCFG] = 0x2bff8010;
- s->regs[BONITO_SDCFG] = 0x255e0091;
-
- s->regs[BONITO_GPIODATA] = 0x1ff;
- s->regs[BONITO_GPIOIE] = 0x1ff;
- s->regs[BONITO_DQCFG] = 0x8;
- s->regs[BONITO_MEMSIZE] = 0x10000000;
- s->regs[BONITO_PCIMAP] = 0x6140;
-}
-
-static const VMStateDescription vmstate_bonito = {
- .name = "Bonito",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(dev, PCIBonitoState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static int bonito_pcihost_initfn(SysBusDevice *dev)
-{
- PCIHostState *phb = PCI_HOST_BRIDGE(dev);
-
- phb->bus = pci_register_bus(DEVICE(dev), "pci",
- pci_bonito_set_irq, pci_bonito_map_irq, dev,
- get_system_memory(), get_system_io(),
- 0x28, 32, TYPE_PCI_BUS);
-
- return 0;
-}
-
-static void bonito_realize(PCIDevice *dev, Error **errp)
-{
- PCIBonitoState *s = PCI_BONITO(dev);
- SysBusDevice *sysbus = SYS_BUS_DEVICE(s->pcihost);
- PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
-
- /* Bonito North Bridge, built on FPGA, VENDOR_ID/DEVICE_ID are "undefined" */
- pci_config_set_prog_interface(dev->config, 0x00);
-
- /* set the north bridge register mapping */
- memory_region_init_io(&s->iomem, OBJECT(s), &bonito_ops, s,
- "north-bridge-register", BONITO_INTERNAL_REG_SIZE);
- sysbus_init_mmio(sysbus, &s->iomem);
- sysbus_mmio_map(sysbus, 0, BONITO_INTERNAL_REG_BASE);
-
- /* set the north bridge pci configure mapping */
- memory_region_init_io(&phb->conf_mem, OBJECT(s), &bonito_pciconf_ops, s,
- "north-bridge-pci-config", BONITO_PCICONFIG_SIZE);
- sysbus_init_mmio(sysbus, &phb->conf_mem);
- sysbus_mmio_map(sysbus, 1, BONITO_PCICONFIG_BASE);
-
- /* set the south bridge pci configure mapping */
- memory_region_init_io(&phb->data_mem, OBJECT(s), &bonito_spciconf_ops, s,
- "south-bridge-pci-config", BONITO_SPCICONFIG_SIZE);
- sysbus_init_mmio(sysbus, &phb->data_mem);
- sysbus_mmio_map(sysbus, 2, BONITO_SPCICONFIG_BASE);
-
- memory_region_init_io(&s->iomem_ldma, OBJECT(s), &bonito_ldma_ops, s,
- "ldma", 0x100);
- sysbus_init_mmio(sysbus, &s->iomem_ldma);
- sysbus_mmio_map(sysbus, 3, 0xbfe00200);
-
- memory_region_init_io(&s->iomem_cop, OBJECT(s), &bonito_cop_ops, s,
- "cop", 0x100);
- sysbus_init_mmio(sysbus, &s->iomem_cop);
- sysbus_mmio_map(sysbus, 4, 0xbfe00300);
-
- /* Map PCI IO Space 0x1fd0 0000 - 0x1fd1 0000 */
- memory_region_init_alias(&s->bonito_pciio, OBJECT(s), "isa_mmio",
- get_system_io(), 0, BONITO_PCIIO_SIZE);
- sysbus_init_mmio(sysbus, &s->bonito_pciio);
- sysbus_mmio_map(sysbus, 5, BONITO_PCIIO_BASE);
-
- /* add pci local io mapping */
- memory_region_init_alias(&s->bonito_localio, OBJECT(s), "isa_mmio",
- get_system_io(), 0, BONITO_DEV_SIZE);
- sysbus_init_mmio(sysbus, &s->bonito_localio);
- sysbus_mmio_map(sysbus, 6, BONITO_DEV_BASE);
-
- /* set the default value of north bridge pci config */
- pci_set_word(dev->config + PCI_COMMAND, 0x0000);
- pci_set_word(dev->config + PCI_STATUS, 0x0000);
- pci_set_word(dev->config + PCI_SUBSYSTEM_VENDOR_ID, 0x0000);
- pci_set_word(dev->config + PCI_SUBSYSTEM_ID, 0x0000);
-
- pci_set_byte(dev->config + PCI_INTERRUPT_LINE, 0x00);
- pci_set_byte(dev->config + PCI_INTERRUPT_PIN, 0x01);
- pci_set_byte(dev->config + PCI_MIN_GNT, 0x3c);
- pci_set_byte(dev->config + PCI_MAX_LAT, 0x00);
-
- qemu_register_reset(bonito_reset, s);
-}
-
-PCIBus *bonito_init(qemu_irq *pic)
-{
- DeviceState *dev;
- BonitoState *pcihost;
- PCIHostState *phb;
- PCIBonitoState *s;
- PCIDevice *d;
-
- dev = qdev_create(NULL, TYPE_BONITO_PCI_HOST_BRIDGE);
- phb = PCI_HOST_BRIDGE(dev);
- pcihost = BONITO_PCI_HOST_BRIDGE(dev);
- pcihost->pic = pic;
- qdev_init_nofail(dev);
-
- /* set the pcihost pointer before bonito_initfn is called */
- d = pci_create(phb->bus, PCI_DEVFN(0, 0), TYPE_PCI_BONITO);
- s = PCI_BONITO(d);
- s->pcihost = pcihost;
- pcihost->pci_dev = s;
- qdev_init_nofail(DEVICE(d));
-
- return phb->bus;
-}
-
-static void bonito_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = bonito_realize;
- k->vendor_id = 0xdf53;
- k->device_id = 0x00d5;
- k->revision = 0x01;
- k->class_id = PCI_CLASS_BRIDGE_HOST;
- dc->desc = "Host bridge";
- dc->vmsd = &vmstate_bonito;
- /*
- * PCI-facing part of the host bridge, not usable without the
- * host-facing part, which can't be device_add'ed, yet.
- */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo bonito_info = {
- .name = TYPE_PCI_BONITO,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(PCIBonitoState),
- .class_init = bonito_class_init,
-};
-
-static void bonito_pcihost_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = bonito_pcihost_initfn;
-}
-
-static const TypeInfo bonito_pcihost_info = {
- .name = TYPE_BONITO_PCI_HOST_BRIDGE,
- .parent = TYPE_PCI_HOST_BRIDGE,
- .instance_size = sizeof(BonitoState),
- .class_init = bonito_pcihost_class_init,
-};
-
-static void bonito_register_types(void)
-{
- type_register_static(&bonito_pcihost_info);
- type_register_static(&bonito_info);
-}
-
-type_init(bonito_register_types)
diff --git a/qemu/hw/pci-host/gpex.c b/qemu/hw/pci-host/gpex.c
deleted file mode 100644
index 66055ee5c..000000000
--- a/qemu/hw/pci-host/gpex.c
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * QEMU Generic PCI Express Bridge Emulation
- *
- * Copyright (C) 2015 Alexander Graf <agraf@suse.de>
- *
- * Code loosely based on q35.c.
- *
- * 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.
- *
- * Check out these documents for more information on the device:
- *
- * http://www.kernel.org/doc/Documentation/devicetree/bindings/pci/host-generic-pci.txt
- * http://www.firmware.org/1275/practice/imap/imap0_9d.pdf
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/pci-host/gpex.h"
-
-/****************************************************************************
- * GPEX host
- */
-
-static void gpex_set_irq(void *opaque, int irq_num, int level)
-{
- GPEXHost *s = opaque;
-
- qemu_set_irq(s->irq[irq_num], level);
-}
-
-static void gpex_host_realize(DeviceState *dev, Error **errp)
-{
- PCIHostState *pci = PCI_HOST_BRIDGE(dev);
- GPEXHost *s = GPEX_HOST(dev);
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- PCIExpressHost *pex = PCIE_HOST_BRIDGE(dev);
- int i;
-
- pcie_host_mmcfg_init(pex, PCIE_MMCFG_SIZE_MAX);
- memory_region_init(&s->io_mmio, OBJECT(s), "gpex_mmio", UINT64_MAX);
- memory_region_init(&s->io_ioport, OBJECT(s), "gpex_ioport", 64 * 1024);
-
- sysbus_init_mmio(sbd, &pex->mmio);
- sysbus_init_mmio(sbd, &s->io_mmio);
- sysbus_init_mmio(sbd, &s->io_ioport);
- for (i = 0; i < GPEX_NUM_IRQS; i++) {
- sysbus_init_irq(sbd, &s->irq[i]);
- }
-
- pci->bus = pci_register_bus(dev, "pcie.0", gpex_set_irq,
- pci_swizzle_map_irq_fn, s, &s->io_mmio,
- &s->io_ioport, 0, 4, TYPE_PCIE_BUS);
-
- qdev_set_parent_bus(DEVICE(&s->gpex_root), BUS(pci->bus));
- qdev_init_nofail(DEVICE(&s->gpex_root));
-}
-
-static const char *gpex_host_root_bus_path(PCIHostState *host_bridge,
- PCIBus *rootbus)
-{
- return "0000:00";
-}
-
-static void gpex_host_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
-
- hc->root_bus_path = gpex_host_root_bus_path;
- dc->realize = gpex_host_realize;
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
- dc->fw_name = "pci";
-}
-
-static void gpex_host_initfn(Object *obj)
-{
- GPEXHost *s = GPEX_HOST(obj);
- GPEXRootState *root = &s->gpex_root;
-
- object_initialize(root, sizeof(*root), TYPE_GPEX_ROOT_DEVICE);
- object_property_add_child(obj, "gpex_root", OBJECT(root), NULL);
- qdev_prop_set_uint32(DEVICE(root), "addr", PCI_DEVFN(0, 0));
- qdev_prop_set_bit(DEVICE(root), "multifunction", false);
-}
-
-static const TypeInfo gpex_host_info = {
- .name = TYPE_GPEX_HOST,
- .parent = TYPE_PCIE_HOST_BRIDGE,
- .instance_size = sizeof(GPEXHost),
- .instance_init = gpex_host_initfn,
- .class_init = gpex_host_class_init,
-};
-
-/****************************************************************************
- * GPEX Root D0:F0
- */
-
-static const VMStateDescription vmstate_gpex_root = {
- .name = "gpex_root",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(parent_obj, GPEXRootState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void gpex_root_class_init(ObjectClass *klass, void *data)
-{
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
- dc->desc = "QEMU generic PCIe host bridge";
- dc->vmsd = &vmstate_gpex_root;
- k->vendor_id = PCI_VENDOR_ID_REDHAT;
- k->device_id = PCI_DEVICE_ID_REDHAT_PCIE_HOST;
- k->revision = 0;
- k->class_id = PCI_CLASS_BRIDGE_HOST;
- /*
- * PCI-facing part of the host bridge, not usable without the
- * host-facing part, which can't be device_add'ed, yet.
- */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo gpex_root_info = {
- .name = TYPE_GPEX_ROOT_DEVICE,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(GPEXRootState),
- .class_init = gpex_root_class_init,
-};
-
-static void gpex_register(void)
-{
- type_register_static(&gpex_root_info);
- type_register_static(&gpex_host_info);
-}
-
-type_init(gpex_register)
diff --git a/qemu/hw/pci-host/grackle.c b/qemu/hw/pci-host/grackle.c
deleted file mode 100644
index 8f9121615..000000000
--- a/qemu/hw/pci-host/grackle.c
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * QEMU Grackle PCI host (heathrow OldWorld PowerMac)
- *
- * Copyright (c) 2006-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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/pci/pci_host.h"
-#include "hw/ppc/mac.h"
-#include "hw/pci/pci.h"
-
-/* debug Grackle */
-//#define DEBUG_GRACKLE
-
-#ifdef DEBUG_GRACKLE
-#define GRACKLE_DPRINTF(fmt, ...) \
- do { printf("GRACKLE: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define GRACKLE_DPRINTF(fmt, ...)
-#endif
-
-#define GRACKLE_PCI_HOST_BRIDGE(obj) \
- OBJECT_CHECK(GrackleState, (obj), TYPE_GRACKLE_PCI_HOST_BRIDGE)
-
-typedef struct GrackleState {
- PCIHostState parent_obj;
-
- MemoryRegion pci_mmio;
- MemoryRegion pci_hole;
-} GrackleState;
-
-/* Don't know if this matches real hardware, but it agrees with OHW. */
-static int pci_grackle_map_irq(PCIDevice *pci_dev, int irq_num)
-{
- return (irq_num + (pci_dev->devfn >> 3)) & 3;
-}
-
-static void pci_grackle_set_irq(void *opaque, int irq_num, int level)
-{
- qemu_irq *pic = opaque;
-
- GRACKLE_DPRINTF("set_irq num %d level %d\n", irq_num, level);
- qemu_set_irq(pic[irq_num + 0x15], level);
-}
-
-PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic,
- MemoryRegion *address_space_mem,
- MemoryRegion *address_space_io)
-{
- DeviceState *dev;
- SysBusDevice *s;
- PCIHostState *phb;
- GrackleState *d;
-
- dev = qdev_create(NULL, TYPE_GRACKLE_PCI_HOST_BRIDGE);
- qdev_init_nofail(dev);
- s = SYS_BUS_DEVICE(dev);
- phb = PCI_HOST_BRIDGE(dev);
- d = GRACKLE_PCI_HOST_BRIDGE(dev);
-
- memory_region_init(&d->pci_mmio, OBJECT(s), "pci-mmio", 0x100000000ULL);
- memory_region_init_alias(&d->pci_hole, OBJECT(s), "pci-hole", &d->pci_mmio,
- 0x80000000ULL, 0x7e000000ULL);
- memory_region_add_subregion(address_space_mem, 0x80000000ULL,
- &d->pci_hole);
-
- phb->bus = pci_register_bus(dev, NULL,
- pci_grackle_set_irq,
- pci_grackle_map_irq,
- pic,
- &d->pci_mmio,
- address_space_io,
- 0, 4, TYPE_PCI_BUS);
-
- pci_create_simple(phb->bus, 0, "grackle");
-
- sysbus_mmio_map(s, 0, base);
- sysbus_mmio_map(s, 1, base + 0x00200000);
-
- return phb->bus;
-}
-
-static int pci_grackle_init_device(SysBusDevice *dev)
-{
- PCIHostState *phb;
-
- phb = PCI_HOST_BRIDGE(dev);
-
- memory_region_init_io(&phb->conf_mem, OBJECT(dev), &pci_host_conf_le_ops,
- dev, "pci-conf-idx", 0x1000);
- memory_region_init_io(&phb->data_mem, OBJECT(dev), &pci_host_data_le_ops,
- dev, "pci-data-idx", 0x1000);
- sysbus_init_mmio(dev, &phb->conf_mem);
- sysbus_init_mmio(dev, &phb->data_mem);
-
- return 0;
-}
-
-static void grackle_pci_host_realize(PCIDevice *d, Error **errp)
-{
- d->config[0x09] = 0x01;
-}
-
-static void grackle_pci_class_init(ObjectClass *klass, void *data)
-{
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- k->realize = grackle_pci_host_realize;
- k->vendor_id = PCI_VENDOR_ID_MOTOROLA;
- k->device_id = PCI_DEVICE_ID_MOTOROLA_MPC106;
- k->revision = 0x00;
- k->class_id = PCI_CLASS_BRIDGE_HOST;
- /*
- * PCI-facing part of the host bridge, not usable without the
- * host-facing part, which can't be device_add'ed, yet.
- */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo grackle_pci_info = {
- .name = "grackle",
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(PCIDevice),
- .class_init = grackle_pci_class_init,
-};
-
-static void pci_grackle_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- k->init = pci_grackle_init_device;
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
-}
-
-static const TypeInfo grackle_pci_host_info = {
- .name = TYPE_GRACKLE_PCI_HOST_BRIDGE,
- .parent = TYPE_PCI_HOST_BRIDGE,
- .instance_size = sizeof(GrackleState),
- .class_init = pci_grackle_class_init,
-};
-
-static void grackle_register_types(void)
-{
- type_register_static(&grackle_pci_info);
- type_register_static(&grackle_pci_host_info);
-}
-
-type_init(grackle_register_types)
diff --git a/qemu/hw/pci-host/pam.c b/qemu/hw/pci-host/pam.c
deleted file mode 100644
index e361ecb7e..000000000
--- a/qemu/hw/pci-host/pam.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * QEMU Smram/pam logic implementation
- *
- * Copyright (c) 2006 Fabrice Bellard
- * Copyright (c) 2011 Isaku Yamahata <yamahata at valinux co jp>
- * VA Linux Systems Japan K.K.
- * Copyright (c) 2012 Jason Baron <jbaron@redhat.com>
- *
- * Split out from piix.c
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "qom/object.h"
-#include "sysemu/sysemu.h"
-#include "hw/pci-host/pam.h"
-
-void init_pam(DeviceState *dev, MemoryRegion *ram_memory,
- MemoryRegion *system_memory, MemoryRegion *pci_address_space,
- PAMMemoryRegion *mem, uint32_t start, uint32_t size)
-{
- int i;
-
- /* RAM */
- memory_region_init_alias(&mem->alias[3], OBJECT(dev), "pam-ram", ram_memory,
- start, size);
- /* ROM (XXX: not quite correct) */
- memory_region_init_alias(&mem->alias[1], OBJECT(dev), "pam-rom", ram_memory,
- start, size);
- memory_region_set_readonly(&mem->alias[1], true);
-
- /* XXX: should distinguish read/write cases */
- memory_region_init_alias(&mem->alias[0], OBJECT(dev), "pam-pci", pci_address_space,
- start, size);
- memory_region_init_alias(&mem->alias[2], OBJECT(dev), "pam-pci", ram_memory,
- start, size);
-
- for (i = 0; i < 4; ++i) {
- memory_region_set_enabled(&mem->alias[i], false);
- memory_region_add_subregion_overlap(system_memory, start,
- &mem->alias[i], 1);
- }
- mem->current = 0;
-}
-
-void pam_update(PAMMemoryRegion *pam, int idx, uint8_t val)
-{
- assert(0 <= idx && idx <= 12);
-
- memory_region_set_enabled(&pam->alias[pam->current], false);
- pam->current = (val >> ((!(idx & 1)) * 4)) & PAM_ATTR_MASK;
- memory_region_set_enabled(&pam->alias[pam->current], true);
-}
diff --git a/qemu/hw/pci-host/piix.c b/qemu/hw/pci-host/piix.c
deleted file mode 100644
index df2b0e26f..000000000
--- a/qemu/hw/pci-host/piix.c
+++ /dev/null
@@ -1,888 +0,0 @@
-/*
- * QEMU i440FX/PIIX3 PCI Bridge Emulation
- *
- * Copyright (c) 2006 Fabrice Bellard
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/i386/pc.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/pci_host.h"
-#include "hw/isa/isa.h"
-#include "hw/sysbus.h"
-#include "qapi/error.h"
-#include "qemu/range.h"
-#include "hw/xen/xen.h"
-#include "hw/pci-host/pam.h"
-#include "sysemu/sysemu.h"
-#include "hw/i386/ioapic.h"
-#include "qapi/visitor.h"
-#include "qemu/error-report.h"
-
-/*
- * I440FX chipset data sheet.
- * http://download.intel.com/design/chipsets/datashts/29054901.pdf
- */
-
-#define I440FX_PCI_HOST_BRIDGE(obj) \
- OBJECT_CHECK(I440FXState, (obj), TYPE_I440FX_PCI_HOST_BRIDGE)
-
-typedef struct I440FXState {
- PCIHostState parent_obj;
- PcPciInfo pci_info;
- uint64_t pci_hole64_size;
- uint32_t short_root_bus;
-} I440FXState;
-
-#define PIIX_NUM_PIC_IRQS 16 /* i8259 * 2 */
-#define PIIX_NUM_PIRQS 4ULL /* PIRQ[A-D] */
-#define XEN_PIIX_NUM_PIRQS 128ULL
-#define PIIX_PIRQC 0x60
-
-/*
- * Reset Control Register: PCI-accessible ISA-Compatible Register at address
- * 0xcf9, provided by the PCI/ISA bridge (PIIX3 PCI function 0, 8086:7000).
- */
-#define RCR_IOPORT 0xcf9
-
-typedef struct PIIX3State {
- PCIDevice dev;
-
- /*
- * bitmap to track pic levels.
- * The pic level is the logical OR of all the PCI irqs mapped to it
- * So one PIC level is tracked by PIIX_NUM_PIRQS bits.
- *
- * PIRQ is mapped to PIC pins, we track it by
- * PIIX_NUM_PIRQS * PIIX_NUM_PIC_IRQS = 64 bits with
- * pic_irq * PIIX_NUM_PIRQS + pirq
- */
-#if PIIX_NUM_PIC_IRQS * PIIX_NUM_PIRQS > 64
-#error "unable to encode pic state in 64bit in pic_levels."
-#endif
- uint64_t pic_levels;
-
- qemu_irq *pic;
-
- /* This member isn't used. Just for save/load compatibility */
- int32_t pci_irq_levels_vmstate[PIIX_NUM_PIRQS];
-
- /* Reset Control Register contents */
- uint8_t rcr;
-
- /* IO memory region for Reset Control Register (RCR_IOPORT) */
- MemoryRegion rcr_mem;
-} PIIX3State;
-
-#define TYPE_PIIX3_PCI_DEVICE "pci-piix3"
-#define PIIX3_PCI_DEVICE(obj) \
- OBJECT_CHECK(PIIX3State, (obj), TYPE_PIIX3_PCI_DEVICE)
-
-#define I440FX_PCI_DEVICE(obj) \
- OBJECT_CHECK(PCII440FXState, (obj), TYPE_I440FX_PCI_DEVICE)
-
-struct PCII440FXState {
- /*< private >*/
- PCIDevice parent_obj;
- /*< public >*/
-
- MemoryRegion *system_memory;
- MemoryRegion *pci_address_space;
- MemoryRegion *ram_memory;
- PAMMemoryRegion pam_regions[13];
- MemoryRegion smram_region;
- MemoryRegion smram, low_smram;
-};
-
-
-#define I440FX_PAM 0x59
-#define I440FX_PAM_SIZE 7
-#define I440FX_SMRAM 0x72
-
-/* Older coreboot versions (4.0 and older) read a config register that doesn't
- * exist in real hardware, to get the RAM size from QEMU.
- */
-#define I440FX_COREBOOT_RAM_SIZE 0x57
-
-static void piix3_set_irq(void *opaque, int pirq, int level);
-static PCIINTxRoute piix3_route_intx_pin_to_irq(void *opaque, int pci_intx);
-static void piix3_write_config_xen(PCIDevice *dev,
- uint32_t address, uint32_t val, int len);
-
-/* return the global irq number corresponding to a given device irq
- pin. We could also use the bus number to have a more precise
- mapping. */
-static int pci_slot_get_pirq(PCIDevice *pci_dev, int pci_intx)
-{
- int slot_addend;
- slot_addend = (pci_dev->devfn >> 3) - 1;
- return (pci_intx + slot_addend) & 3;
-}
-
-static void i440fx_update_memory_mappings(PCII440FXState *d)
-{
- int i;
- PCIDevice *pd = PCI_DEVICE(d);
-
- memory_region_transaction_begin();
- for (i = 0; i < 13; i++) {
- pam_update(&d->pam_regions[i], i,
- pd->config[I440FX_PAM + ((i + 1) / 2)]);
- }
- memory_region_set_enabled(&d->smram_region,
- !(pd->config[I440FX_SMRAM] & SMRAM_D_OPEN));
- memory_region_set_enabled(&d->smram,
- pd->config[I440FX_SMRAM] & SMRAM_G_SMRAME);
- memory_region_transaction_commit();
-}
-
-
-static void i440fx_write_config(PCIDevice *dev,
- uint32_t address, uint32_t val, int len)
-{
- PCII440FXState *d = I440FX_PCI_DEVICE(dev);
-
- /* XXX: implement SMRAM.D_LOCK */
- pci_default_write_config(dev, address, val, len);
- if (ranges_overlap(address, len, I440FX_PAM, I440FX_PAM_SIZE) ||
- range_covers_byte(address, len, I440FX_SMRAM)) {
- i440fx_update_memory_mappings(d);
- }
-}
-
-static int i440fx_load_old(QEMUFile* f, void *opaque, int version_id)
-{
- PCII440FXState *d = opaque;
- PCIDevice *pd = PCI_DEVICE(d);
- int ret, i;
- uint8_t smm_enabled;
-
- ret = pci_device_load(pd, f);
- if (ret < 0)
- return ret;
- i440fx_update_memory_mappings(d);
- qemu_get_8s(f, &smm_enabled);
-
- if (version_id == 2) {
- for (i = 0; i < PIIX_NUM_PIRQS; i++) {
- qemu_get_be32(f); /* dummy load for compatibility */
- }
- }
-
- return 0;
-}
-
-static int i440fx_post_load(void *opaque, int version_id)
-{
- PCII440FXState *d = opaque;
-
- i440fx_update_memory_mappings(d);
- return 0;
-}
-
-static const VMStateDescription vmstate_i440fx = {
- .name = "I440FX",
- .version_id = 3,
- .minimum_version_id = 3,
- .minimum_version_id_old = 1,
- .load_state_old = i440fx_load_old,
- .post_load = i440fx_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(parent_obj, PCII440FXState),
- /* Used to be smm_enabled, which was basically always zero because
- * SeaBIOS hardly uses SMM. SMRAM is now handled by CPU code.
- */
- VMSTATE_UNUSED(1),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void i440fx_pcihost_get_pci_hole_start(Object *obj, Visitor *v,
- const char *name, void *opaque,
- Error **errp)
-{
- I440FXState *s = I440FX_PCI_HOST_BRIDGE(obj);
- uint32_t value = s->pci_info.w32.begin;
-
- visit_type_uint32(v, name, &value, errp);
-}
-
-static void i440fx_pcihost_get_pci_hole_end(Object *obj, Visitor *v,
- const char *name, void *opaque,
- Error **errp)
-{
- I440FXState *s = I440FX_PCI_HOST_BRIDGE(obj);
- uint32_t value = s->pci_info.w32.end;
-
- visit_type_uint32(v, name, &value, errp);
-}
-
-static void i440fx_pcihost_get_pci_hole64_start(Object *obj, Visitor *v,
- const char *name,
- void *opaque, Error **errp)
-{
- PCIHostState *h = PCI_HOST_BRIDGE(obj);
- Range w64;
-
- pci_bus_get_w64_range(h->bus, &w64);
-
- visit_type_uint64(v, name, &w64.begin, errp);
-}
-
-static void i440fx_pcihost_get_pci_hole64_end(Object *obj, Visitor *v,
- const char *name, void *opaque,
- Error **errp)
-{
- PCIHostState *h = PCI_HOST_BRIDGE(obj);
- Range w64;
-
- pci_bus_get_w64_range(h->bus, &w64);
-
- visit_type_uint64(v, name, &w64.end, errp);
-}
-
-static void i440fx_pcihost_initfn(Object *obj)
-{
- PCIHostState *s = PCI_HOST_BRIDGE(obj);
- I440FXState *d = I440FX_PCI_HOST_BRIDGE(obj);
-
- memory_region_init_io(&s->conf_mem, obj, &pci_host_conf_le_ops, s,
- "pci-conf-idx", 4);
- memory_region_init_io(&s->data_mem, obj, &pci_host_data_le_ops, s,
- "pci-conf-data", 4);
-
- object_property_add(obj, PCI_HOST_PROP_PCI_HOLE_START, "int",
- i440fx_pcihost_get_pci_hole_start,
- NULL, NULL, NULL, NULL);
-
- object_property_add(obj, PCI_HOST_PROP_PCI_HOLE_END, "int",
- i440fx_pcihost_get_pci_hole_end,
- NULL, NULL, NULL, NULL);
-
- object_property_add(obj, PCI_HOST_PROP_PCI_HOLE64_START, "int",
- i440fx_pcihost_get_pci_hole64_start,
- NULL, NULL, NULL, NULL);
-
- object_property_add(obj, PCI_HOST_PROP_PCI_HOLE64_END, "int",
- i440fx_pcihost_get_pci_hole64_end,
- NULL, NULL, NULL, NULL);
-
- d->pci_info.w32.end = IO_APIC_DEFAULT_ADDRESS;
-}
-
-static void i440fx_pcihost_realize(DeviceState *dev, Error **errp)
-{
- PCIHostState *s = PCI_HOST_BRIDGE(dev);
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
-
- sysbus_add_io(sbd, 0xcf8, &s->conf_mem);
- sysbus_init_ioports(sbd, 0xcf8, 4);
-
- sysbus_add_io(sbd, 0xcfc, &s->data_mem);
- sysbus_init_ioports(sbd, 0xcfc, 4);
-}
-
-static void i440fx_realize(PCIDevice *dev, Error **errp)
-{
- dev->config[I440FX_SMRAM] = 0x02;
-
- if (object_property_get_bool(qdev_get_machine(), "iommu", NULL)) {
- error_report("warning: i440fx doesn't support emulated iommu");
- }
-}
-
-PCIBus *i440fx_init(const char *host_type, const char *pci_type,
- PCII440FXState **pi440fx_state,
- int *piix3_devfn,
- ISABus **isa_bus, qemu_irq *pic,
- MemoryRegion *address_space_mem,
- MemoryRegion *address_space_io,
- ram_addr_t ram_size,
- ram_addr_t below_4g_mem_size,
- ram_addr_t above_4g_mem_size,
- MemoryRegion *pci_address_space,
- MemoryRegion *ram_memory)
-{
- DeviceState *dev;
- PCIBus *b;
- PCIDevice *d;
- PCIHostState *s;
- PIIX3State *piix3;
- PCII440FXState *f;
- unsigned i;
- I440FXState *i440fx;
-
- dev = qdev_create(NULL, host_type);
- s = PCI_HOST_BRIDGE(dev);
- b = pci_bus_new(dev, NULL, pci_address_space,
- address_space_io, 0, TYPE_PCI_BUS);
- s->bus = b;
- object_property_add_child(qdev_get_machine(), "i440fx", OBJECT(dev), NULL);
- qdev_init_nofail(dev);
-
- d = pci_create_simple(b, 0, pci_type);
- *pi440fx_state = I440FX_PCI_DEVICE(d);
- f = *pi440fx_state;
- f->system_memory = address_space_mem;
- f->pci_address_space = pci_address_space;
- f->ram_memory = ram_memory;
-
- i440fx = I440FX_PCI_HOST_BRIDGE(dev);
- i440fx->pci_info.w32.begin = below_4g_mem_size;
-
- /* setup pci memory mapping */
- pc_pci_as_mapping_init(OBJECT(f), f->system_memory,
- f->pci_address_space);
-
- /* if *disabled* show SMRAM to all CPUs */
- memory_region_init_alias(&f->smram_region, OBJECT(d), "smram-region",
- f->pci_address_space, 0xa0000, 0x20000);
- memory_region_add_subregion_overlap(f->system_memory, 0xa0000,
- &f->smram_region, 1);
- memory_region_set_enabled(&f->smram_region, true);
-
- /* smram, as seen by SMM CPUs */
- memory_region_init(&f->smram, OBJECT(d), "smram", 1ull << 32);
- memory_region_set_enabled(&f->smram, true);
- memory_region_init_alias(&f->low_smram, OBJECT(d), "smram-low",
- f->ram_memory, 0xa0000, 0x20000);
- memory_region_set_enabled(&f->low_smram, true);
- memory_region_add_subregion(&f->smram, 0xa0000, &f->low_smram);
- object_property_add_const_link(qdev_get_machine(), "smram",
- OBJECT(&f->smram), &error_abort);
-
- init_pam(dev, f->ram_memory, f->system_memory, f->pci_address_space,
- &f->pam_regions[0], PAM_BIOS_BASE, PAM_BIOS_SIZE);
- for (i = 0; i < 12; ++i) {
- init_pam(dev, f->ram_memory, f->system_memory, f->pci_address_space,
- &f->pam_regions[i+1], PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE,
- PAM_EXPAN_SIZE);
- }
-
- /* Xen supports additional interrupt routes from the PCI devices to
- * the IOAPIC: the four pins of each PCI device on the bus are also
- * connected to the IOAPIC directly.
- * These additional routes can be discovered through ACPI. */
- if (xen_enabled()) {
- PCIDevice *pci_dev = pci_create_simple_multifunction(b,
- -1, true, "PIIX3-xen");
- piix3 = PIIX3_PCI_DEVICE(pci_dev);
- pci_bus_irqs(b, xen_piix3_set_irq, xen_pci_slot_get_pirq,
- piix3, XEN_PIIX_NUM_PIRQS);
- } else {
- PCIDevice *pci_dev = pci_create_simple_multifunction(b,
- -1, true, "PIIX3");
- piix3 = PIIX3_PCI_DEVICE(pci_dev);
- pci_bus_irqs(b, piix3_set_irq, pci_slot_get_pirq, piix3,
- PIIX_NUM_PIRQS);
- pci_bus_set_route_irq_fn(b, piix3_route_intx_pin_to_irq);
- }
- piix3->pic = pic;
- *isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(piix3), "isa.0"));
-
- *piix3_devfn = piix3->dev.devfn;
-
- ram_size = ram_size / 8 / 1024 / 1024;
- if (ram_size > 255) {
- ram_size = 255;
- }
- d->config[I440FX_COREBOOT_RAM_SIZE] = ram_size;
-
- i440fx_update_memory_mappings(f);
-
- return b;
-}
-
-PCIBus *find_i440fx(void)
-{
- PCIHostState *s = OBJECT_CHECK(PCIHostState,
- object_resolve_path("/machine/i440fx", NULL),
- TYPE_PCI_HOST_BRIDGE);
- return s ? s->bus : NULL;
-}
-
-/* PIIX3 PCI to ISA bridge */
-static void piix3_set_irq_pic(PIIX3State *piix3, int pic_irq)
-{
- qemu_set_irq(piix3->pic[pic_irq],
- !!(piix3->pic_levels &
- (((1ULL << PIIX_NUM_PIRQS) - 1) <<
- (pic_irq * PIIX_NUM_PIRQS))));
-}
-
-static void piix3_set_irq_level_internal(PIIX3State *piix3, int pirq, int level)
-{
- int pic_irq;
- uint64_t mask;
-
- pic_irq = piix3->dev.config[PIIX_PIRQC + pirq];
- if (pic_irq >= PIIX_NUM_PIC_IRQS) {
- return;
- }
-
- mask = 1ULL << ((pic_irq * PIIX_NUM_PIRQS) + pirq);
- piix3->pic_levels &= ~mask;
- piix3->pic_levels |= mask * !!level;
-}
-
-static void piix3_set_irq_level(PIIX3State *piix3, int pirq, int level)
-{
- int pic_irq;
-
- pic_irq = piix3->dev.config[PIIX_PIRQC + pirq];
- if (pic_irq >= PIIX_NUM_PIC_IRQS) {
- return;
- }
-
- piix3_set_irq_level_internal(piix3, pirq, level);
-
- piix3_set_irq_pic(piix3, pic_irq);
-}
-
-static void piix3_set_irq(void *opaque, int pirq, int level)
-{
- PIIX3State *piix3 = opaque;
- piix3_set_irq_level(piix3, pirq, level);
-}
-
-static PCIINTxRoute piix3_route_intx_pin_to_irq(void *opaque, int pin)
-{
- PIIX3State *piix3 = opaque;
- int irq = piix3->dev.config[PIIX_PIRQC + pin];
- PCIINTxRoute route;
-
- if (irq < PIIX_NUM_PIC_IRQS) {
- route.mode = PCI_INTX_ENABLED;
- route.irq = irq;
- } else {
- route.mode = PCI_INTX_DISABLED;
- route.irq = -1;
- }
- return route;
-}
-
-/* irq routing is changed. so rebuild bitmap */
-static void piix3_update_irq_levels(PIIX3State *piix3)
-{
- int pirq;
-
- piix3->pic_levels = 0;
- for (pirq = 0; pirq < PIIX_NUM_PIRQS; pirq++) {
- piix3_set_irq_level(piix3, pirq,
- pci_bus_get_irq_level(piix3->dev.bus, pirq));
- }
-}
-
-static void piix3_write_config(PCIDevice *dev,
- uint32_t address, uint32_t val, int len)
-{
- pci_default_write_config(dev, address, val, len);
- if (ranges_overlap(address, len, PIIX_PIRQC, 4)) {
- PIIX3State *piix3 = PIIX3_PCI_DEVICE(dev);
- int pic_irq;
-
- pci_bus_fire_intx_routing_notifier(piix3->dev.bus);
- piix3_update_irq_levels(piix3);
- for (pic_irq = 0; pic_irq < PIIX_NUM_PIC_IRQS; pic_irq++) {
- piix3_set_irq_pic(piix3, pic_irq);
- }
- }
-}
-
-static void piix3_write_config_xen(PCIDevice *dev,
- uint32_t address, uint32_t val, int len)
-{
- xen_piix_pci_write_config_client(address, val, len);
- piix3_write_config(dev, address, val, len);
-}
-
-static void piix3_reset(void *opaque)
-{
- PIIX3State *d = opaque;
- uint8_t *pci_conf = d->dev.config;
-
- pci_conf[0x04] = 0x07; /* master, memory and I/O */
- pci_conf[0x05] = 0x00;
- pci_conf[0x06] = 0x00;
- pci_conf[0x07] = 0x02; /* PCI_status_devsel_medium */
- pci_conf[0x4c] = 0x4d;
- pci_conf[0x4e] = 0x03;
- pci_conf[0x4f] = 0x00;
- pci_conf[0x60] = 0x80;
- pci_conf[0x61] = 0x80;
- pci_conf[0x62] = 0x80;
- pci_conf[0x63] = 0x80;
- pci_conf[0x69] = 0x02;
- pci_conf[0x70] = 0x80;
- pci_conf[0x76] = 0x0c;
- pci_conf[0x77] = 0x0c;
- pci_conf[0x78] = 0x02;
- pci_conf[0x79] = 0x00;
- pci_conf[0x80] = 0x00;
- pci_conf[0x82] = 0x00;
- pci_conf[0xa0] = 0x08;
- pci_conf[0xa2] = 0x00;
- pci_conf[0xa3] = 0x00;
- pci_conf[0xa4] = 0x00;
- pci_conf[0xa5] = 0x00;
- pci_conf[0xa6] = 0x00;
- pci_conf[0xa7] = 0x00;
- pci_conf[0xa8] = 0x0f;
- pci_conf[0xaa] = 0x00;
- pci_conf[0xab] = 0x00;
- pci_conf[0xac] = 0x00;
- pci_conf[0xae] = 0x00;
-
- d->pic_levels = 0;
- d->rcr = 0;
-}
-
-static int piix3_post_load(void *opaque, int version_id)
-{
- PIIX3State *piix3 = opaque;
- int pirq;
-
- /* Because the i8259 has not been deserialized yet, qemu_irq_raise
- * might bring the system to a different state than the saved one;
- * for example, the interrupt could be masked but the i8259 would
- * not know that yet and would trigger an interrupt in the CPU.
- *
- * Here, we update irq levels without raising the interrupt.
- * Interrupt state will be deserialized separately through the i8259.
- */
- piix3->pic_levels = 0;
- for (pirq = 0; pirq < PIIX_NUM_PIRQS; pirq++) {
- piix3_set_irq_level_internal(piix3, pirq,
- pci_bus_get_irq_level(piix3->dev.bus, pirq));
- }
- return 0;
-}
-
-static void piix3_pre_save(void *opaque)
-{
- int i;
- PIIX3State *piix3 = opaque;
-
- for (i = 0; i < ARRAY_SIZE(piix3->pci_irq_levels_vmstate); i++) {
- piix3->pci_irq_levels_vmstate[i] =
- pci_bus_get_irq_level(piix3->dev.bus, i);
- }
-}
-
-static bool piix3_rcr_needed(void *opaque)
-{
- PIIX3State *piix3 = opaque;
-
- return (piix3->rcr != 0);
-}
-
-static const VMStateDescription vmstate_piix3_rcr = {
- .name = "PIIX3/rcr",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = piix3_rcr_needed,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(rcr, PIIX3State),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_piix3 = {
- .name = "PIIX3",
- .version_id = 3,
- .minimum_version_id = 2,
- .post_load = piix3_post_load,
- .pre_save = piix3_pre_save,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(dev, PIIX3State),
- VMSTATE_INT32_ARRAY_V(pci_irq_levels_vmstate, PIIX3State,
- PIIX_NUM_PIRQS, 3),
- VMSTATE_END_OF_LIST()
- },
- .subsections = (const VMStateDescription*[]) {
- &vmstate_piix3_rcr,
- NULL
- }
-};
-
-
-static void rcr_write(void *opaque, hwaddr addr, uint64_t val, unsigned len)
-{
- PIIX3State *d = opaque;
-
- if (val & 4) {
- qemu_system_reset_request();
- return;
- }
- d->rcr = val & 2; /* keep System Reset type only */
-}
-
-static uint64_t rcr_read(void *opaque, hwaddr addr, unsigned len)
-{
- PIIX3State *d = opaque;
-
- return d->rcr;
-}
-
-static const MemoryRegionOps rcr_ops = {
- .read = rcr_read,
- .write = rcr_write,
- .endianness = DEVICE_LITTLE_ENDIAN
-};
-
-static void piix3_realize(PCIDevice *dev, Error **errp)
-{
- PIIX3State *d = PIIX3_PCI_DEVICE(dev);
-
- if (!isa_bus_new(DEVICE(d), get_system_memory(),
- pci_address_space_io(dev), errp)) {
- return;
- }
-
- memory_region_init_io(&d->rcr_mem, OBJECT(dev), &rcr_ops, d,
- "piix3-reset-control", 1);
- memory_region_add_subregion_overlap(pci_address_space_io(dev), RCR_IOPORT,
- &d->rcr_mem, 1);
-
- qemu_register_reset(piix3_reset, d);
-}
-
-static void pci_piix3_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- dc->desc = "ISA bridge";
- dc->vmsd = &vmstate_piix3;
- dc->hotpluggable = false;
- k->realize = piix3_realize;
- k->vendor_id = PCI_VENDOR_ID_INTEL;
- /* 82371SB PIIX3 PCI-to-ISA bridge (Step A1) */
- k->device_id = PCI_DEVICE_ID_INTEL_82371SB_0;
- k->class_id = PCI_CLASS_BRIDGE_ISA;
- /*
- * Reason: part of PIIX3 southbridge, needs to be wired up by
- * pc_piix.c's pc_init1()
- */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo piix3_pci_type_info = {
- .name = TYPE_PIIX3_PCI_DEVICE,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(PIIX3State),
- .abstract = true,
- .class_init = pci_piix3_class_init,
-};
-
-static void piix3_class_init(ObjectClass *klass, void *data)
-{
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->config_write = piix3_write_config;
-}
-
-static const TypeInfo piix3_info = {
- .name = "PIIX3",
- .parent = TYPE_PIIX3_PCI_DEVICE,
- .class_init = piix3_class_init,
-};
-
-static void piix3_xen_class_init(ObjectClass *klass, void *data)
-{
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->config_write = piix3_write_config_xen;
-};
-
-static const TypeInfo piix3_xen_info = {
- .name = "PIIX3-xen",
- .parent = TYPE_PIIX3_PCI_DEVICE,
- .class_init = piix3_xen_class_init,
-};
-
-static void i440fx_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = i440fx_realize;
- k->config_write = i440fx_write_config;
- k->vendor_id = PCI_VENDOR_ID_INTEL;
- k->device_id = PCI_DEVICE_ID_INTEL_82441;
- k->revision = 0x02;
- k->class_id = PCI_CLASS_BRIDGE_HOST;
- dc->desc = "Host bridge";
- dc->vmsd = &vmstate_i440fx;
- /*
- * PCI-facing part of the host bridge, not usable without the
- * host-facing part, which can't be device_add'ed, yet.
- */
- dc->cannot_instantiate_with_device_add_yet = true;
- dc->hotpluggable = false;
-}
-
-static const TypeInfo i440fx_info = {
- .name = TYPE_I440FX_PCI_DEVICE,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(PCII440FXState),
- .class_init = i440fx_class_init,
-};
-
-/* IGD Passthrough Host Bridge. */
-typedef struct {
- uint8_t offset;
- uint8_t len;
-} IGDHostInfo;
-
-/* Here we just expose minimal host bridge offset subset. */
-static const IGDHostInfo igd_host_bridge_infos[] = {
- {0x08, 2}, /* revision id */
- {0x2c, 2}, /* sybsystem vendor id */
- {0x2e, 2}, /* sybsystem id */
- {0x50, 2}, /* SNB: processor graphics control register */
- {0x52, 2}, /* processor graphics control register */
- {0xa4, 4}, /* SNB: graphics base of stolen memory */
- {0xa8, 4}, /* SNB: base of GTT stolen memory */
-};
-
-static int host_pci_config_read(int pos, int len, uint32_t *val)
-{
- char path[PATH_MAX];
- int config_fd;
- ssize_t size = sizeof(path);
- /* Access real host bridge. */
- int rc = snprintf(path, size, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/%s",
- 0, 0, 0, 0, "config");
- int ret = 0;
-
- if (rc >= size || rc < 0) {
- return -ENODEV;
- }
-
- config_fd = open(path, O_RDWR);
- if (config_fd < 0) {
- return -ENODEV;
- }
-
- if (lseek(config_fd, pos, SEEK_SET) != pos) {
- ret = -errno;
- goto out;
- }
-
- do {
- rc = read(config_fd, (uint8_t *)val, len);
- } while (rc < 0 && (errno == EINTR || errno == EAGAIN));
- if (rc != len) {
- ret = -errno;
- }
-
-out:
- close(config_fd);
- return ret;
-}
-
-static int igd_pt_i440fx_initfn(struct PCIDevice *pci_dev)
-{
- uint32_t val = 0;
- int rc, i, num;
- int pos, len;
-
- num = ARRAY_SIZE(igd_host_bridge_infos);
- for (i = 0; i < num; i++) {
- pos = igd_host_bridge_infos[i].offset;
- len = igd_host_bridge_infos[i].len;
- rc = host_pci_config_read(pos, len, &val);
- if (rc) {
- return -ENODEV;
- }
- pci_default_write_config(pci_dev, pos, val, len);
- }
-
- return 0;
-}
-
-static void igd_passthrough_i440fx_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->init = igd_pt_i440fx_initfn;
- dc->desc = "IGD Passthrough Host bridge";
-}
-
-static const TypeInfo igd_passthrough_i440fx_info = {
- .name = TYPE_IGD_PASSTHROUGH_I440FX_PCI_DEVICE,
- .parent = TYPE_I440FX_PCI_DEVICE,
- .instance_size = sizeof(PCII440FXState),
- .class_init = igd_passthrough_i440fx_class_init,
-};
-
-static const char *i440fx_pcihost_root_bus_path(PCIHostState *host_bridge,
- PCIBus *rootbus)
-{
- I440FXState *s = I440FX_PCI_HOST_BRIDGE(host_bridge);
-
- /* For backwards compat with old device paths */
- if (s->short_root_bus) {
- return "0000";
- }
- return "0000:00";
-}
-
-static Property i440fx_props[] = {
- DEFINE_PROP_SIZE(PCI_HOST_PROP_PCI_HOLE64_SIZE, I440FXState,
- pci_hole64_size, DEFAULT_PCI_HOLE64_SIZE),
- DEFINE_PROP_UINT32("short_root_bus", I440FXState, short_root_bus, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void i440fx_pcihost_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
-
- hc->root_bus_path = i440fx_pcihost_root_bus_path;
- dc->realize = i440fx_pcihost_realize;
- dc->fw_name = "pci";
- dc->props = i440fx_props;
-}
-
-static const TypeInfo i440fx_pcihost_info = {
- .name = TYPE_I440FX_PCI_HOST_BRIDGE,
- .parent = TYPE_PCI_HOST_BRIDGE,
- .instance_size = sizeof(I440FXState),
- .instance_init = i440fx_pcihost_initfn,
- .class_init = i440fx_pcihost_class_init,
-};
-
-static void i440fx_register_types(void)
-{
- type_register_static(&i440fx_info);
- type_register_static(&igd_passthrough_i440fx_info);
- type_register_static(&piix3_pci_type_info);
- type_register_static(&piix3_info);
- type_register_static(&piix3_xen_info);
- type_register_static(&i440fx_pcihost_info);
-}
-
-type_init(i440fx_register_types)
diff --git a/qemu/hw/pci-host/ppce500.c b/qemu/hw/pci-host/ppce500.c
deleted file mode 100644
index e502bc050..000000000
--- a/qemu/hw/pci-host/ppce500.c
+++ /dev/null
@@ -1,551 +0,0 @@
-/*
- * QEMU PowerPC E500 embedded processors pci controller emulation
- *
- * Copyright (C) 2009 Freescale Semiconductor, Inc. All rights reserved.
- *
- * Author: Yu Liu, <yu.liu@freescale.com>
- *
- * This file is derived from hw/ppc4xx_pci.c,
- * the copyright for that material belongs to the original owners.
- *
- * This is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/ppc/e500-ccsr.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/pci_host.h"
-#include "qemu/bswap.h"
-#include "hw/pci-host/ppce500.h"
-
-#ifdef DEBUG_PCI
-#define pci_debug(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__)
-#else
-#define pci_debug(fmt, ...)
-#endif
-
-#define PCIE500_CFGADDR 0x0
-#define PCIE500_CFGDATA 0x4
-#define PCIE500_REG_BASE 0xC00
-#define PCIE500_ALL_SIZE 0x1000
-#define PCIE500_REG_SIZE (PCIE500_ALL_SIZE - PCIE500_REG_BASE)
-
-#define PCIE500_PCI_IOLEN 0x10000ULL
-
-#define PPCE500_PCI_CONFIG_ADDR 0x0
-#define PPCE500_PCI_CONFIG_DATA 0x4
-#define PPCE500_PCI_INTACK 0x8
-
-#define PPCE500_PCI_OW1 (0xC20 - PCIE500_REG_BASE)
-#define PPCE500_PCI_OW2 (0xC40 - PCIE500_REG_BASE)
-#define PPCE500_PCI_OW3 (0xC60 - PCIE500_REG_BASE)
-#define PPCE500_PCI_OW4 (0xC80 - PCIE500_REG_BASE)
-#define PPCE500_PCI_IW3 (0xDA0 - PCIE500_REG_BASE)
-#define PPCE500_PCI_IW2 (0xDC0 - PCIE500_REG_BASE)
-#define PPCE500_PCI_IW1 (0xDE0 - PCIE500_REG_BASE)
-
-#define PPCE500_PCI_GASKET_TIMR (0xE20 - PCIE500_REG_BASE)
-
-#define PCI_POTAR 0x0
-#define PCI_POTEAR 0x4
-#define PCI_POWBAR 0x8
-#define PCI_POWAR 0x10
-
-#define PCI_PITAR 0x0
-#define PCI_PIWBAR 0x8
-#define PCI_PIWBEAR 0xC
-#define PCI_PIWAR 0x10
-
-#define PPCE500_PCI_NR_POBS 5
-#define PPCE500_PCI_NR_PIBS 3
-
-#define PIWAR_EN 0x80000000 /* Enable */
-#define PIWAR_PF 0x20000000 /* prefetch */
-#define PIWAR_TGI_LOCAL 0x00f00000 /* target - local memory */
-#define PIWAR_READ_SNOOP 0x00050000
-#define PIWAR_WRITE_SNOOP 0x00005000
-#define PIWAR_SZ_MASK 0x0000003f
-
-struct pci_outbound {
- uint32_t potar;
- uint32_t potear;
- uint32_t powbar;
- uint32_t powar;
- MemoryRegion mem;
-};
-
-struct pci_inbound {
- uint32_t pitar;
- uint32_t piwbar;
- uint32_t piwbear;
- uint32_t piwar;
- MemoryRegion mem;
-};
-
-#define TYPE_PPC_E500_PCI_HOST_BRIDGE "e500-pcihost"
-
-#define PPC_E500_PCI_HOST_BRIDGE(obj) \
- OBJECT_CHECK(PPCE500PCIState, (obj), TYPE_PPC_E500_PCI_HOST_BRIDGE)
-
-struct PPCE500PCIState {
- PCIHostState parent_obj;
-
- struct pci_outbound pob[PPCE500_PCI_NR_POBS];
- struct pci_inbound pib[PPCE500_PCI_NR_PIBS];
- uint32_t gasket_time;
- qemu_irq irq[PCI_NUM_PINS];
- uint32_t irq_num[PCI_NUM_PINS];
- uint32_t first_slot;
- uint32_t first_pin_irq;
- AddressSpace bm_as;
- MemoryRegion bm;
- /* mmio maps */
- MemoryRegion container;
- MemoryRegion iomem;
- MemoryRegion pio;
- MemoryRegion busmem;
-};
-
-#define TYPE_PPC_E500_PCI_BRIDGE "e500-host-bridge"
-#define PPC_E500_PCI_BRIDGE(obj) \
- OBJECT_CHECK(PPCE500PCIBridgeState, (obj), TYPE_PPC_E500_PCI_BRIDGE)
-
-struct PPCE500PCIBridgeState {
- /*< private >*/
- PCIDevice parent;
- /*< public >*/
-
- MemoryRegion bar0;
-};
-
-typedef struct PPCE500PCIBridgeState PPCE500PCIBridgeState;
-typedef struct PPCE500PCIState PPCE500PCIState;
-
-static uint64_t pci_reg_read4(void *opaque, hwaddr addr,
- unsigned size)
-{
- PPCE500PCIState *pci = opaque;
- unsigned long win;
- uint32_t value = 0;
- int idx;
-
- win = addr & 0xfe0;
-
- switch (win) {
- case PPCE500_PCI_OW1:
- case PPCE500_PCI_OW2:
- case PPCE500_PCI_OW3:
- case PPCE500_PCI_OW4:
- idx = (addr >> 5) & 0x7;
- switch (addr & 0x1F) {
- case PCI_POTAR:
- value = pci->pob[idx].potar;
- break;
- case PCI_POTEAR:
- value = pci->pob[idx].potear;
- break;
- case PCI_POWBAR:
- value = pci->pob[idx].powbar;
- break;
- case PCI_POWAR:
- value = pci->pob[idx].powar;
- break;
- default:
- break;
- }
- break;
-
- case PPCE500_PCI_IW3:
- case PPCE500_PCI_IW2:
- case PPCE500_PCI_IW1:
- idx = ((addr >> 5) & 0x3) - 1;
- switch (addr & 0x1F) {
- case PCI_PITAR:
- value = pci->pib[idx].pitar;
- break;
- case PCI_PIWBAR:
- value = pci->pib[idx].piwbar;
- break;
- case PCI_PIWBEAR:
- value = pci->pib[idx].piwbear;
- break;
- case PCI_PIWAR:
- value = pci->pib[idx].piwar;
- break;
- default:
- break;
- };
- break;
-
- case PPCE500_PCI_GASKET_TIMR:
- value = pci->gasket_time;
- break;
-
- default:
- break;
- }
-
- pci_debug("%s: win:%lx(addr:" TARGET_FMT_plx ") -> value:%x\n", __func__,
- win, addr, value);
- return value;
-}
-
-/* DMA mapping */
-static void e500_update_piw(PPCE500PCIState *pci, int idx)
-{
- uint64_t tar = ((uint64_t)pci->pib[idx].pitar) << 12;
- uint64_t wbar = ((uint64_t)pci->pib[idx].piwbar) << 12;
- uint64_t war = pci->pib[idx].piwar;
- uint64_t size = 2ULL << (war & PIWAR_SZ_MASK);
- MemoryRegion *address_space_mem = get_system_memory();
- MemoryRegion *mem = &pci->pib[idx].mem;
- MemoryRegion *bm = &pci->bm;
- char *name;
-
- if (memory_region_is_mapped(mem)) {
- /* Before we modify anything, unmap and destroy the region */
- memory_region_del_subregion(bm, mem);
- object_unparent(OBJECT(mem));
- }
-
- if (!(war & PIWAR_EN)) {
- /* Not enabled, nothing to do */
- return;
- }
-
- name = g_strdup_printf("PCI Inbound Window %d", idx);
- memory_region_init_alias(mem, OBJECT(pci), name, address_space_mem, tar,
- size);
- memory_region_add_subregion_overlap(bm, wbar, mem, -1);
- g_free(name);
-
- pci_debug("%s: Added window of size=%#lx from PCI=%#lx to CPU=%#lx\n",
- __func__, size, wbar, tar);
-}
-
-/* BAR mapping */
-static void e500_update_pow(PPCE500PCIState *pci, int idx)
-{
- uint64_t tar = ((uint64_t)pci->pob[idx].potar) << 12;
- uint64_t wbar = ((uint64_t)pci->pob[idx].powbar) << 12;
- uint64_t war = pci->pob[idx].powar;
- uint64_t size = 2ULL << (war & PIWAR_SZ_MASK);
- MemoryRegion *mem = &pci->pob[idx].mem;
- MemoryRegion *address_space_mem = get_system_memory();
- char *name;
-
- if (memory_region_is_mapped(mem)) {
- /* Before we modify anything, unmap and destroy the region */
- memory_region_del_subregion(address_space_mem, mem);
- object_unparent(OBJECT(mem));
- }
-
- if (!(war & PIWAR_EN)) {
- /* Not enabled, nothing to do */
- return;
- }
-
- name = g_strdup_printf("PCI Outbound Window %d", idx);
- memory_region_init_alias(mem, OBJECT(pci), name, &pci->busmem, tar,
- size);
- memory_region_add_subregion(address_space_mem, wbar, mem);
- g_free(name);
-
- pci_debug("%s: Added window of size=%#lx from CPU=%#lx to PCI=%#lx\n",
- __func__, size, wbar, tar);
-}
-
-static void pci_reg_write4(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- PPCE500PCIState *pci = opaque;
- unsigned long win;
- int idx;
-
- win = addr & 0xfe0;
-
- pci_debug("%s: value:%x -> win:%lx(addr:" TARGET_FMT_plx ")\n",
- __func__, (unsigned)value, win, addr);
-
- switch (win) {
- case PPCE500_PCI_OW1:
- case PPCE500_PCI_OW2:
- case PPCE500_PCI_OW3:
- case PPCE500_PCI_OW4:
- idx = (addr >> 5) & 0x7;
- switch (addr & 0x1F) {
- case PCI_POTAR:
- pci->pob[idx].potar = value;
- e500_update_pow(pci, idx);
- break;
- case PCI_POTEAR:
- pci->pob[idx].potear = value;
- e500_update_pow(pci, idx);
- break;
- case PCI_POWBAR:
- pci->pob[idx].powbar = value;
- e500_update_pow(pci, idx);
- break;
- case PCI_POWAR:
- pci->pob[idx].powar = value;
- e500_update_pow(pci, idx);
- break;
- default:
- break;
- };
- break;
-
- case PPCE500_PCI_IW3:
- case PPCE500_PCI_IW2:
- case PPCE500_PCI_IW1:
- idx = ((addr >> 5) & 0x3) - 1;
- switch (addr & 0x1F) {
- case PCI_PITAR:
- pci->pib[idx].pitar = value;
- e500_update_piw(pci, idx);
- break;
- case PCI_PIWBAR:
- pci->pib[idx].piwbar = value;
- e500_update_piw(pci, idx);
- break;
- case PCI_PIWBEAR:
- pci->pib[idx].piwbear = value;
- e500_update_piw(pci, idx);
- break;
- case PCI_PIWAR:
- pci->pib[idx].piwar = value;
- e500_update_piw(pci, idx);
- break;
- default:
- break;
- };
- break;
-
- case PPCE500_PCI_GASKET_TIMR:
- pci->gasket_time = value;
- break;
-
- default:
- break;
- };
-}
-
-static const MemoryRegionOps e500_pci_reg_ops = {
- .read = pci_reg_read4,
- .write = pci_reg_write4,
- .endianness = DEVICE_BIG_ENDIAN,
-};
-
-static int mpc85xx_pci_map_irq(PCIDevice *pci_dev, int pin)
-{
- int devno = pci_dev->devfn >> 3;
- int ret;
-
- ret = ppce500_pci_map_irq_slot(devno, pin);
-
- pci_debug("%s: devfn %x irq %d -> %d devno:%x\n", __func__,
- pci_dev->devfn, pin, ret, devno);
-
- return ret;
-}
-
-static void mpc85xx_pci_set_irq(void *opaque, int pin, int level)
-{
- PPCE500PCIState *s = opaque;
- qemu_irq *pic = s->irq;
-
- pci_debug("%s: PCI irq %d, level:%d\n", __func__, pin , level);
-
- qemu_set_irq(pic[pin], level);
-}
-
-static PCIINTxRoute e500_route_intx_pin_to_irq(void *opaque, int pin)
-{
- PCIINTxRoute route;
- PPCE500PCIState *s = opaque;
-
- route.mode = PCI_INTX_ENABLED;
- route.irq = s->irq_num[pin];
-
- pci_debug("%s: PCI irq-pin = %d, irq_num= %d\n", __func__, pin, route.irq);
- return route;
-}
-
-static const VMStateDescription vmstate_pci_outbound = {
- .name = "pci_outbound",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(potar, struct pci_outbound),
- VMSTATE_UINT32(potear, struct pci_outbound),
- VMSTATE_UINT32(powbar, struct pci_outbound),
- VMSTATE_UINT32(powar, struct pci_outbound),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_pci_inbound = {
- .name = "pci_inbound",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(pitar, struct pci_inbound),
- VMSTATE_UINT32(piwbar, struct pci_inbound),
- VMSTATE_UINT32(piwbear, struct pci_inbound),
- VMSTATE_UINT32(piwar, struct pci_inbound),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_ppce500_pci = {
- .name = "ppce500_pci",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT_ARRAY(pob, PPCE500PCIState, PPCE500_PCI_NR_POBS, 1,
- vmstate_pci_outbound, struct pci_outbound),
- VMSTATE_STRUCT_ARRAY(pib, PPCE500PCIState, PPCE500_PCI_NR_PIBS, 1,
- vmstate_pci_inbound, struct pci_inbound),
- VMSTATE_UINT32(gasket_time, PPCE500PCIState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-#include "exec/address-spaces.h"
-
-static void e500_pcihost_bridge_realize(PCIDevice *d, Error **errp)
-{
- PPCE500PCIBridgeState *b = PPC_E500_PCI_BRIDGE(d);
- PPCE500CCSRState *ccsr = CCSR(container_get(qdev_get_machine(),
- "/e500-ccsr"));
-
- pci_config_set_class(d->config, PCI_CLASS_BRIDGE_PCI);
- d->config[PCI_HEADER_TYPE] =
- (d->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTION) |
- PCI_HEADER_TYPE_BRIDGE;
-
- memory_region_init_alias(&b->bar0, OBJECT(ccsr), "e500-pci-bar0", &ccsr->ccsr_space,
- 0, int128_get64(ccsr->ccsr_space.size));
- pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &b->bar0);
-}
-
-static AddressSpace *e500_pcihost_set_iommu(PCIBus *bus, void *opaque,
- int devfn)
-{
- PPCE500PCIState *s = opaque;
-
- return &s->bm_as;
-}
-
-static int e500_pcihost_initfn(SysBusDevice *dev)
-{
- PCIHostState *h;
- PPCE500PCIState *s;
- PCIBus *b;
- int i;
-
- h = PCI_HOST_BRIDGE(dev);
- s = PPC_E500_PCI_HOST_BRIDGE(dev);
-
- for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
- sysbus_init_irq(dev, &s->irq[i]);
- }
-
- for (i = 0; i < PCI_NUM_PINS; i++) {
- s->irq_num[i] = s->first_pin_irq + i;
- }
-
- memory_region_init(&s->pio, OBJECT(s), "pci-pio", PCIE500_PCI_IOLEN);
- memory_region_init(&s->busmem, OBJECT(s), "pci bus memory", UINT64_MAX);
-
- /* PIO lives at the bottom of our bus space */
- memory_region_add_subregion_overlap(&s->busmem, 0, &s->pio, -2);
-
- b = pci_register_bus(DEVICE(dev), NULL, mpc85xx_pci_set_irq,
- mpc85xx_pci_map_irq, s, &s->busmem, &s->pio,
- PCI_DEVFN(s->first_slot, 0), 4, TYPE_PCI_BUS);
- h->bus = b;
-
- /* Set up PCI view of memory */
- memory_region_init(&s->bm, OBJECT(s), "bm-e500", UINT64_MAX);
- memory_region_add_subregion(&s->bm, 0x0, &s->busmem);
- address_space_init(&s->bm_as, &s->bm, "pci-bm");
- pci_setup_iommu(b, e500_pcihost_set_iommu, s);
-
- pci_create_simple(b, 0, "e500-host-bridge");
-
- memory_region_init(&s->container, OBJECT(h), "pci-container", PCIE500_ALL_SIZE);
- memory_region_init_io(&h->conf_mem, OBJECT(h), &pci_host_conf_be_ops, h,
- "pci-conf-idx", 4);
- memory_region_init_io(&h->data_mem, OBJECT(h), &pci_host_data_le_ops, h,
- "pci-conf-data", 4);
- memory_region_init_io(&s->iomem, OBJECT(s), &e500_pci_reg_ops, s,
- "pci.reg", PCIE500_REG_SIZE);
- memory_region_add_subregion(&s->container, PCIE500_CFGADDR, &h->conf_mem);
- memory_region_add_subregion(&s->container, PCIE500_CFGDATA, &h->data_mem);
- memory_region_add_subregion(&s->container, PCIE500_REG_BASE, &s->iomem);
- sysbus_init_mmio(dev, &s->container);
- pci_bus_set_route_irq_fn(b, e500_route_intx_pin_to_irq);
-
- return 0;
-}
-
-static void e500_host_bridge_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = e500_pcihost_bridge_realize;
- k->vendor_id = PCI_VENDOR_ID_FREESCALE;
- k->device_id = PCI_DEVICE_ID_MPC8533E;
- k->class_id = PCI_CLASS_PROCESSOR_POWERPC;
- dc->desc = "Host bridge";
- /*
- * PCI-facing part of the host bridge, not usable without the
- * host-facing part, which can't be device_add'ed, yet.
- */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo e500_host_bridge_info = {
- .name = "e500-host-bridge",
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(PPCE500PCIBridgeState),
- .class_init = e500_host_bridge_class_init,
-};
-
-static Property pcihost_properties[] = {
- DEFINE_PROP_UINT32("first_slot", PPCE500PCIState, first_slot, 0x11),
- DEFINE_PROP_UINT32("first_pin_irq", PPCE500PCIState, first_pin_irq, 0x1),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void e500_pcihost_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = e500_pcihost_initfn;
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
- dc->props = pcihost_properties;
- dc->vmsd = &vmstate_ppce500_pci;
-}
-
-static const TypeInfo e500_pcihost_info = {
- .name = TYPE_PPC_E500_PCI_HOST_BRIDGE,
- .parent = TYPE_PCI_HOST_BRIDGE,
- .instance_size = sizeof(PPCE500PCIState),
- .class_init = e500_pcihost_class_init,
-};
-
-static void e500_pci_register_types(void)
-{
- type_register_static(&e500_pcihost_info);
- type_register_static(&e500_host_bridge_info);
-}
-
-type_init(e500_pci_register_types)
diff --git a/qemu/hw/pci-host/prep.c b/qemu/hw/pci-host/prep.c
deleted file mode 100644
index 487e32ecb..000000000
--- a/qemu/hw/pci-host/prep.c
+++ /dev/null
@@ -1,406 +0,0 @@
-/*
- * QEMU PREP PCI host
- *
- * Copyright (c) 2006 Fabrice Bellard
- * Copyright (c) 2011-2013 Andreas Färber
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/hw.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/pci_bus.h"
-#include "hw/pci/pci_host.h"
-#include "hw/i386/pc.h"
-#include "hw/loader.h"
-#include "exec/address-spaces.h"
-#include "elf.h"
-
-#define TYPE_RAVEN_PCI_DEVICE "raven"
-#define TYPE_RAVEN_PCI_HOST_BRIDGE "raven-pcihost"
-
-#define RAVEN_PCI_DEVICE(obj) \
- OBJECT_CHECK(RavenPCIState, (obj), TYPE_RAVEN_PCI_DEVICE)
-
-typedef struct RavenPCIState {
- PCIDevice dev;
-
- uint32_t elf_machine;
- char *bios_name;
- MemoryRegion bios;
-} RavenPCIState;
-
-#define RAVEN_PCI_HOST_BRIDGE(obj) \
- OBJECT_CHECK(PREPPCIState, (obj), TYPE_RAVEN_PCI_HOST_BRIDGE)
-
-typedef struct PRePPCIState {
- PCIHostState parent_obj;
-
- qemu_irq irq[PCI_NUM_PINS];
- PCIBus pci_bus;
- AddressSpace pci_io_as;
- MemoryRegion pci_io;
- MemoryRegion pci_io_non_contiguous;
- MemoryRegion pci_memory;
- MemoryRegion pci_intack;
- MemoryRegion bm;
- MemoryRegion bm_ram_alias;
- MemoryRegion bm_pci_memory_alias;
- AddressSpace bm_as;
- RavenPCIState pci_dev;
-
- int contiguous_map;
-} PREPPCIState;
-
-#define BIOS_SIZE (1024 * 1024)
-
-static inline uint32_t raven_pci_io_config(hwaddr addr)
-{
- int i;
-
- for (i = 0; i < 11; i++) {
- if ((addr & (1 << (11 + i))) != 0) {
- break;
- }
- }
- return (addr & 0x7ff) | (i << 11);
-}
-
-static void raven_pci_io_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned int size)
-{
- PREPPCIState *s = opaque;
- PCIHostState *phb = PCI_HOST_BRIDGE(s);
- pci_data_write(phb->bus, raven_pci_io_config(addr), val, size);
-}
-
-static uint64_t raven_pci_io_read(void *opaque, hwaddr addr,
- unsigned int size)
-{
- PREPPCIState *s = opaque;
- PCIHostState *phb = PCI_HOST_BRIDGE(s);
- return pci_data_read(phb->bus, raven_pci_io_config(addr), size);
-}
-
-static const MemoryRegionOps raven_pci_io_ops = {
- .read = raven_pci_io_read,
- .write = raven_pci_io_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static uint64_t raven_intack_read(void *opaque, hwaddr addr,
- unsigned int size)
-{
- return pic_read_irq(isa_pic);
-}
-
-static const MemoryRegionOps raven_intack_ops = {
- .read = raven_intack_read,
- .valid = {
- .max_access_size = 1,
- },
-};
-
-static inline hwaddr raven_io_address(PREPPCIState *s,
- hwaddr addr)
-{
- if (s->contiguous_map == 0) {
- /* 64 KB contiguous space for IOs */
- addr &= 0xFFFF;
- } else {
- /* 8 MB non-contiguous space for IOs */
- addr = (addr & 0x1F) | ((addr & 0x007FFF000) >> 7);
- }
-
- /* FIXME: handle endianness switch */
-
- return addr;
-}
-
-static uint64_t raven_io_read(void *opaque, hwaddr addr,
- unsigned int size)
-{
- PREPPCIState *s = opaque;
- uint8_t buf[4];
-
- addr = raven_io_address(s, addr);
- address_space_read(&s->pci_io_as, addr + 0x80000000,
- MEMTXATTRS_UNSPECIFIED, buf, size);
-
- if (size == 1) {
- return buf[0];
- } else if (size == 2) {
- return lduw_le_p(buf);
- } else if (size == 4) {
- return ldl_le_p(buf);
- } else {
- g_assert_not_reached();
- }
-}
-
-static void raven_io_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned int size)
-{
- PREPPCIState *s = opaque;
- uint8_t buf[4];
-
- addr = raven_io_address(s, addr);
-
- if (size == 1) {
- buf[0] = val;
- } else if (size == 2) {
- stw_le_p(buf, val);
- } else if (size == 4) {
- stl_le_p(buf, val);
- } else {
- g_assert_not_reached();
- }
-
- address_space_write(&s->pci_io_as, addr + 0x80000000,
- MEMTXATTRS_UNSPECIFIED, buf, size);
-}
-
-static const MemoryRegionOps raven_io_ops = {
- .read = raven_io_read,
- .write = raven_io_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .impl.max_access_size = 4,
- .valid.unaligned = true,
-};
-
-static int raven_map_irq(PCIDevice *pci_dev, int irq_num)
-{
- return (irq_num + (pci_dev->devfn >> 3)) & 1;
-}
-
-static void raven_set_irq(void *opaque, int irq_num, int level)
-{
- qemu_irq *pic = opaque;
-
- qemu_set_irq(pic[irq_num] , level);
-}
-
-static AddressSpace *raven_pcihost_set_iommu(PCIBus *bus, void *opaque,
- int devfn)
-{
- PREPPCIState *s = opaque;
-
- return &s->bm_as;
-}
-
-static void raven_change_gpio(void *opaque, int n, int level)
-{
- PREPPCIState *s = opaque;
-
- s->contiguous_map = level;
-}
-
-static void raven_pcihost_realizefn(DeviceState *d, Error **errp)
-{
- SysBusDevice *dev = SYS_BUS_DEVICE(d);
- PCIHostState *h = PCI_HOST_BRIDGE(dev);
- PREPPCIState *s = RAVEN_PCI_HOST_BRIDGE(dev);
- MemoryRegion *address_space_mem = get_system_memory();
- int i;
-
- for (i = 0; i < PCI_NUM_PINS; i++) {
- sysbus_init_irq(dev, &s->irq[i]);
- }
-
- qdev_init_gpio_in(d, raven_change_gpio, 1);
-
- pci_bus_irqs(&s->pci_bus, raven_set_irq, raven_map_irq, s->irq,
- PCI_NUM_PINS);
-
- memory_region_init_io(&h->conf_mem, OBJECT(h), &pci_host_conf_le_ops, s,
- "pci-conf-idx", 4);
- memory_region_add_subregion(&s->pci_io, 0xcf8, &h->conf_mem);
-
- memory_region_init_io(&h->data_mem, OBJECT(h), &pci_host_data_le_ops, s,
- "pci-conf-data", 4);
- memory_region_add_subregion(&s->pci_io, 0xcfc, &h->data_mem);
-
- memory_region_init_io(&h->mmcfg, OBJECT(s), &raven_pci_io_ops, s,
- "pciio", 0x00400000);
- memory_region_add_subregion(address_space_mem, 0x80800000, &h->mmcfg);
-
- memory_region_init_io(&s->pci_intack, OBJECT(s), &raven_intack_ops, s,
- "pci-intack", 1);
- memory_region_add_subregion(address_space_mem, 0xbffffff0, &s->pci_intack);
-
- /* TODO Remove once realize propagates to child devices. */
- object_property_set_bool(OBJECT(&s->pci_dev), true, "realized", errp);
-}
-
-static void raven_pcihost_initfn(Object *obj)
-{
- PCIHostState *h = PCI_HOST_BRIDGE(obj);
- PREPPCIState *s = RAVEN_PCI_HOST_BRIDGE(obj);
- MemoryRegion *address_space_mem = get_system_memory();
- DeviceState *pci_dev;
-
- memory_region_init(&s->pci_io, obj, "pci-io", 0x3f800000);
- memory_region_init_io(&s->pci_io_non_contiguous, obj, &raven_io_ops, s,
- "pci-io-non-contiguous", 0x00800000);
- memory_region_init(&s->pci_memory, obj, "pci-memory", 0x3f000000);
- address_space_init(&s->pci_io_as, &s->pci_io, "raven-io");
-
- /* CPU address space */
- memory_region_add_subregion(address_space_mem, 0x80000000, &s->pci_io);
- memory_region_add_subregion_overlap(address_space_mem, 0x80000000,
- &s->pci_io_non_contiguous, 1);
- memory_region_add_subregion(address_space_mem, 0xc0000000, &s->pci_memory);
- pci_bus_new_inplace(&s->pci_bus, sizeof(s->pci_bus), DEVICE(obj), NULL,
- &s->pci_memory, &s->pci_io, 0, TYPE_PCI_BUS);
-
- /* Bus master address space */
- memory_region_init(&s->bm, obj, "bm-raven", UINT32_MAX);
- memory_region_init_alias(&s->bm_pci_memory_alias, obj, "bm-pci-memory",
- &s->pci_memory, 0,
- memory_region_size(&s->pci_memory));
- memory_region_init_alias(&s->bm_ram_alias, obj, "bm-system",
- get_system_memory(), 0, 0x80000000);
- memory_region_add_subregion(&s->bm, 0 , &s->bm_pci_memory_alias);
- memory_region_add_subregion(&s->bm, 0x80000000, &s->bm_ram_alias);
- address_space_init(&s->bm_as, &s->bm, "raven-bm");
- pci_setup_iommu(&s->pci_bus, raven_pcihost_set_iommu, s);
-
- h->bus = &s->pci_bus;
-
- object_initialize(&s->pci_dev, sizeof(s->pci_dev), TYPE_RAVEN_PCI_DEVICE);
- pci_dev = DEVICE(&s->pci_dev);
- qdev_set_parent_bus(pci_dev, BUS(&s->pci_bus));
- object_property_set_int(OBJECT(&s->pci_dev), PCI_DEVFN(0, 0), "addr",
- NULL);
- qdev_prop_set_bit(pci_dev, "multifunction", false);
-}
-
-static void raven_realize(PCIDevice *d, Error **errp)
-{
- RavenPCIState *s = RAVEN_PCI_DEVICE(d);
- char *filename;
- int bios_size = -1;
-
- d->config[0x0C] = 0x08; // cache_line_size
- d->config[0x0D] = 0x10; // latency_timer
- d->config[0x34] = 0x00; // capabilities_pointer
-
- memory_region_init_ram(&s->bios, OBJECT(s), "bios", BIOS_SIZE,
- &error_fatal);
- memory_region_set_readonly(&s->bios, true);
- memory_region_add_subregion(get_system_memory(), (uint32_t)(-BIOS_SIZE),
- &s->bios);
- vmstate_register_ram_global(&s->bios);
- if (s->bios_name) {
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, s->bios_name);
- if (filename) {
- if (s->elf_machine != EM_NONE) {
- bios_size = load_elf(filename, NULL, NULL, NULL,
- NULL, NULL, 1, s->elf_machine, 0, 0);
- }
- if (bios_size < 0) {
- bios_size = get_image_size(filename);
- if (bios_size > 0 && bios_size <= BIOS_SIZE) {
- hwaddr bios_addr;
- bios_size = (bios_size + 0xfff) & ~0xfff;
- bios_addr = (uint32_t)(-BIOS_SIZE);
- bios_size = load_image_targphys(filename, bios_addr,
- bios_size);
- }
- }
- }
- if (bios_size < 0 || bios_size > BIOS_SIZE) {
- /* FIXME should error_setg() */
- hw_error("qemu: could not load bios image '%s'\n", s->bios_name);
- }
- g_free(filename);
- }
-}
-
-static const VMStateDescription vmstate_raven = {
- .name = "raven",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(dev, RavenPCIState),
- VMSTATE_END_OF_LIST()
- },
-};
-
-static void raven_class_init(ObjectClass *klass, void *data)
-{
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- k->realize = raven_realize;
- k->vendor_id = PCI_VENDOR_ID_MOTOROLA;
- k->device_id = PCI_DEVICE_ID_MOTOROLA_RAVEN;
- k->revision = 0x00;
- k->class_id = PCI_CLASS_BRIDGE_HOST;
- dc->desc = "PReP Host Bridge - Motorola Raven";
- dc->vmsd = &vmstate_raven;
- /*
- * Reason: PCI-facing part of the host bridge, not usable without
- * the host-facing part, which can't be device_add'ed, yet.
- * Reason: realize() method uses hw_error().
- */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo raven_info = {
- .name = TYPE_RAVEN_PCI_DEVICE,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(RavenPCIState),
- .class_init = raven_class_init,
-};
-
-static Property raven_pcihost_properties[] = {
- DEFINE_PROP_UINT32("elf-machine", PREPPCIState, pci_dev.elf_machine,
- EM_NONE),
- DEFINE_PROP_STRING("bios-name", PREPPCIState, pci_dev.bios_name),
- DEFINE_PROP_END_OF_LIST()
-};
-
-static void raven_pcihost_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
- dc->realize = raven_pcihost_realizefn;
- dc->props = raven_pcihost_properties;
- dc->fw_name = "pci";
-}
-
-static const TypeInfo raven_pcihost_info = {
- .name = TYPE_RAVEN_PCI_HOST_BRIDGE,
- .parent = TYPE_PCI_HOST_BRIDGE,
- .instance_size = sizeof(PREPPCIState),
- .instance_init = raven_pcihost_initfn,
- .class_init = raven_pcihost_class_init,
-};
-
-static void raven_register_types(void)
-{
- type_register_static(&raven_pcihost_info);
- type_register_static(&raven_info);
-}
-
-type_init(raven_register_types)
diff --git a/qemu/hw/pci-host/q35.c b/qemu/hw/pci-host/q35.c
deleted file mode 100644
index 70f897e3a..000000000
--- a/qemu/hw/pci-host/q35.c
+++ /dev/null
@@ -1,560 +0,0 @@
-/*
- * QEMU MCH/ICH9 PCI Bridge Emulation
- *
- * Copyright (c) 2006 Fabrice Bellard
- * Copyright (c) 2009, 2010, 2011
- * Isaku Yamahata <yamahata at valinux co jp>
- * VA Linux Systems Japan K.K.
- * Copyright (C) 2012 Jason Baron <jbaron@redhat.com>
- *
- * This is based on piix.c, but heavily modified.
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/pci-host/q35.h"
-#include "qapi/error.h"
-#include "qapi/visitor.h"
-
-/****************************************************************************
- * Q35 host
- */
-
-static void q35_host_realize(DeviceState *dev, Error **errp)
-{
- PCIHostState *pci = PCI_HOST_BRIDGE(dev);
- Q35PCIHost *s = Q35_HOST_DEVICE(dev);
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
-
- sysbus_add_io(sbd, MCH_HOST_BRIDGE_CONFIG_ADDR, &pci->conf_mem);
- sysbus_init_ioports(sbd, MCH_HOST_BRIDGE_CONFIG_ADDR, 4);
-
- sysbus_add_io(sbd, MCH_HOST_BRIDGE_CONFIG_DATA, &pci->data_mem);
- sysbus_init_ioports(sbd, MCH_HOST_BRIDGE_CONFIG_DATA, 4);
-
- pci->bus = pci_bus_new(DEVICE(s), "pcie.0",
- s->mch.pci_address_space, s->mch.address_space_io,
- 0, TYPE_PCIE_BUS);
- qdev_set_parent_bus(DEVICE(&s->mch), BUS(pci->bus));
- qdev_init_nofail(DEVICE(&s->mch));
-}
-
-static const char *q35_host_root_bus_path(PCIHostState *host_bridge,
- PCIBus *rootbus)
-{
- Q35PCIHost *s = Q35_HOST_DEVICE(host_bridge);
-
- /* For backwards compat with old device paths */
- if (s->mch.short_root_bus) {
- return "0000";
- }
- return "0000:00";
-}
-
-static void q35_host_get_pci_hole_start(Object *obj, Visitor *v,
- const char *name, void *opaque,
- Error **errp)
-{
- Q35PCIHost *s = Q35_HOST_DEVICE(obj);
- uint32_t value = s->mch.pci_info.w32.begin;
-
- visit_type_uint32(v, name, &value, errp);
-}
-
-static void q35_host_get_pci_hole_end(Object *obj, Visitor *v,
- const char *name, void *opaque,
- Error **errp)
-{
- Q35PCIHost *s = Q35_HOST_DEVICE(obj);
- uint32_t value = s->mch.pci_info.w32.end;
-
- visit_type_uint32(v, name, &value, errp);
-}
-
-static void q35_host_get_pci_hole64_start(Object *obj, Visitor *v,
- const char *name, void *opaque,
- Error **errp)
-{
- PCIHostState *h = PCI_HOST_BRIDGE(obj);
- Range w64;
-
- pci_bus_get_w64_range(h->bus, &w64);
-
- visit_type_uint64(v, name, &w64.begin, errp);
-}
-
-static void q35_host_get_pci_hole64_end(Object *obj, Visitor *v,
- const char *name, void *opaque,
- Error **errp)
-{
- PCIHostState *h = PCI_HOST_BRIDGE(obj);
- Range w64;
-
- pci_bus_get_w64_range(h->bus, &w64);
-
- visit_type_uint64(v, name, &w64.end, errp);
-}
-
-static void q35_host_get_mmcfg_size(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- PCIExpressHost *e = PCIE_HOST_BRIDGE(obj);
- uint32_t value = e->size;
-
- visit_type_uint32(v, name, &value, errp);
-}
-
-static Property mch_props[] = {
- DEFINE_PROP_UINT64(PCIE_HOST_MCFG_BASE, Q35PCIHost, parent_obj.base_addr,
- MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT),
- DEFINE_PROP_SIZE(PCI_HOST_PROP_PCI_HOLE64_SIZE, Q35PCIHost,
- mch.pci_hole64_size, DEFAULT_PCI_HOLE64_SIZE),
- DEFINE_PROP_UINT32("short_root_bus", Q35PCIHost, mch.short_root_bus, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void q35_host_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
-
- hc->root_bus_path = q35_host_root_bus_path;
- dc->realize = q35_host_realize;
- dc->props = mch_props;
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
- dc->fw_name = "pci";
-}
-
-static void q35_host_initfn(Object *obj)
-{
- Q35PCIHost *s = Q35_HOST_DEVICE(obj);
- PCIHostState *phb = PCI_HOST_BRIDGE(obj);
-
- memory_region_init_io(&phb->conf_mem, obj, &pci_host_conf_le_ops, phb,
- "pci-conf-idx", 4);
- memory_region_init_io(&phb->data_mem, obj, &pci_host_data_le_ops, phb,
- "pci-conf-data", 4);
-
- object_initialize(&s->mch, sizeof(s->mch), TYPE_MCH_PCI_DEVICE);
- object_property_add_child(OBJECT(s), "mch", OBJECT(&s->mch), NULL);
- qdev_prop_set_uint32(DEVICE(&s->mch), "addr", PCI_DEVFN(0, 0));
- qdev_prop_set_bit(DEVICE(&s->mch), "multifunction", false);
-
- object_property_add(obj, PCI_HOST_PROP_PCI_HOLE_START, "int",
- q35_host_get_pci_hole_start,
- NULL, NULL, NULL, NULL);
-
- object_property_add(obj, PCI_HOST_PROP_PCI_HOLE_END, "int",
- q35_host_get_pci_hole_end,
- NULL, NULL, NULL, NULL);
-
- object_property_add(obj, PCI_HOST_PROP_PCI_HOLE64_START, "int",
- q35_host_get_pci_hole64_start,
- NULL, NULL, NULL, NULL);
-
- object_property_add(obj, PCI_HOST_PROP_PCI_HOLE64_END, "int",
- q35_host_get_pci_hole64_end,
- NULL, NULL, NULL, NULL);
-
- object_property_add(obj, PCIE_HOST_MCFG_SIZE, "int",
- q35_host_get_mmcfg_size,
- NULL, NULL, NULL, NULL);
-
- /* Leave enough space for the biggest MCFG BAR */
- /* TODO: this matches current bios behaviour, but
- * it's not a power of two, which means an MTRR
- * can't cover it exactly.
- */
- s->mch.pci_info.w32.begin = MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT +
- MCH_HOST_BRIDGE_PCIEXBAR_MAX;
- s->mch.pci_info.w32.end = IO_APIC_DEFAULT_ADDRESS;
-}
-
-static const TypeInfo q35_host_info = {
- .name = TYPE_Q35_HOST_DEVICE,
- .parent = TYPE_PCIE_HOST_BRIDGE,
- .instance_size = sizeof(Q35PCIHost),
- .instance_init = q35_host_initfn,
- .class_init = q35_host_class_init,
-};
-
-/****************************************************************************
- * MCH D0:F0
- */
-
-static uint64_t tseg_blackhole_read(void *ptr, hwaddr reg, unsigned size)
-{
- return 0xffffffff;
-}
-
-static void tseg_blackhole_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned width)
-{
- /* nothing */
-}
-
-static const MemoryRegionOps tseg_blackhole_ops = {
- .read = tseg_blackhole_read,
- .write = tseg_blackhole_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid.min_access_size = 1,
- .valid.max_access_size = 4,
- .impl.min_access_size = 4,
- .impl.max_access_size = 4,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-/* PCIe MMCFG */
-static void mch_update_pciexbar(MCHPCIState *mch)
-{
- PCIDevice *pci_dev = PCI_DEVICE(mch);
- BusState *bus = qdev_get_parent_bus(DEVICE(mch));
- PCIExpressHost *pehb = PCIE_HOST_BRIDGE(bus->parent);
-
- uint64_t pciexbar;
- int enable;
- uint64_t addr;
- uint64_t addr_mask;
- uint32_t length;
-
- pciexbar = pci_get_quad(pci_dev->config + MCH_HOST_BRIDGE_PCIEXBAR);
- enable = pciexbar & MCH_HOST_BRIDGE_PCIEXBAREN;
- addr_mask = MCH_HOST_BRIDGE_PCIEXBAR_ADMSK;
- switch (pciexbar & MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_MASK) {
- case MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_256M:
- length = 256 * 1024 * 1024;
- break;
- case MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_128M:
- length = 128 * 1024 * 1024;
- addr_mask |= MCH_HOST_BRIDGE_PCIEXBAR_128ADMSK |
- MCH_HOST_BRIDGE_PCIEXBAR_64ADMSK;
- break;
- case MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_64M:
- length = 64 * 1024 * 1024;
- addr_mask |= MCH_HOST_BRIDGE_PCIEXBAR_64ADMSK;
- break;
- case MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_RVD:
- default:
- enable = 0;
- length = 0;
- abort();
- break;
- }
- addr = pciexbar & addr_mask;
- pcie_host_mmcfg_update(pehb, enable, addr, length);
- /* Leave enough space for the MCFG BAR */
- /*
- * TODO: this matches current bios behaviour, but it's not a power of two,
- * which means an MTRR can't cover it exactly.
- */
- if (enable) {
- mch->pci_info.w32.begin = addr + length;
- } else {
- mch->pci_info.w32.begin = MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT;
- }
-}
-
-/* PAM */
-static void mch_update_pam(MCHPCIState *mch)
-{
- PCIDevice *pd = PCI_DEVICE(mch);
- int i;
-
- memory_region_transaction_begin();
- for (i = 0; i < 13; i++) {
- pam_update(&mch->pam_regions[i], i,
- pd->config[MCH_HOST_BRIDGE_PAM0 + ((i + 1) / 2)]);
- }
- memory_region_transaction_commit();
-}
-
-/* SMRAM */
-static void mch_update_smram(MCHPCIState *mch)
-{
- PCIDevice *pd = PCI_DEVICE(mch);
- bool h_smrame = (pd->config[MCH_HOST_BRIDGE_ESMRAMC] & MCH_HOST_BRIDGE_ESMRAMC_H_SMRAME);
- uint32_t tseg_size;
-
- /* implement SMRAM.D_LCK */
- if (pd->config[MCH_HOST_BRIDGE_SMRAM] & MCH_HOST_BRIDGE_SMRAM_D_LCK) {
- pd->config[MCH_HOST_BRIDGE_SMRAM] &= ~MCH_HOST_BRIDGE_SMRAM_D_OPEN;
- pd->wmask[MCH_HOST_BRIDGE_SMRAM] = MCH_HOST_BRIDGE_SMRAM_WMASK_LCK;
- pd->wmask[MCH_HOST_BRIDGE_ESMRAMC] = MCH_HOST_BRIDGE_ESMRAMC_WMASK_LCK;
- }
-
- memory_region_transaction_begin();
-
- if (pd->config[MCH_HOST_BRIDGE_SMRAM] & SMRAM_D_OPEN) {
- /* Hide (!) low SMRAM if H_SMRAME = 1 */
- memory_region_set_enabled(&mch->smram_region, h_smrame);
- /* Show high SMRAM if H_SMRAME = 1 */
- memory_region_set_enabled(&mch->open_high_smram, h_smrame);
- } else {
- /* Hide high SMRAM and low SMRAM */
- memory_region_set_enabled(&mch->smram_region, true);
- memory_region_set_enabled(&mch->open_high_smram, false);
- }
-
- if (pd->config[MCH_HOST_BRIDGE_SMRAM] & SMRAM_G_SMRAME) {
- memory_region_set_enabled(&mch->low_smram, !h_smrame);
- memory_region_set_enabled(&mch->high_smram, h_smrame);
- } else {
- memory_region_set_enabled(&mch->low_smram, false);
- memory_region_set_enabled(&mch->high_smram, false);
- }
-
- if (pd->config[MCH_HOST_BRIDGE_ESMRAMC] & MCH_HOST_BRIDGE_ESMRAMC_T_EN) {
- switch (pd->config[MCH_HOST_BRIDGE_ESMRAMC] &
- MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK) {
- case MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_1MB:
- tseg_size = 1024 * 1024;
- break;
- case MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_2MB:
- tseg_size = 1024 * 1024 * 2;
- break;
- case MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_8MB:
- tseg_size = 1024 * 1024 * 8;
- break;
- default:
- tseg_size = 0;
- break;
- }
- } else {
- tseg_size = 0;
- }
- memory_region_del_subregion(mch->system_memory, &mch->tseg_blackhole);
- memory_region_set_enabled(&mch->tseg_blackhole, tseg_size);
- memory_region_set_size(&mch->tseg_blackhole, tseg_size);
- memory_region_add_subregion_overlap(mch->system_memory,
- mch->below_4g_mem_size - tseg_size,
- &mch->tseg_blackhole, 1);
-
- memory_region_set_enabled(&mch->tseg_window, tseg_size);
- memory_region_set_size(&mch->tseg_window, tseg_size);
- memory_region_set_address(&mch->tseg_window,
- mch->below_4g_mem_size - tseg_size);
- memory_region_set_alias_offset(&mch->tseg_window,
- mch->below_4g_mem_size - tseg_size);
-
- memory_region_transaction_commit();
-}
-
-static void mch_write_config(PCIDevice *d,
- uint32_t address, uint32_t val, int len)
-{
- MCHPCIState *mch = MCH_PCI_DEVICE(d);
-
- pci_default_write_config(d, address, val, len);
-
- if (ranges_overlap(address, len, MCH_HOST_BRIDGE_PAM0,
- MCH_HOST_BRIDGE_PAM_SIZE)) {
- mch_update_pam(mch);
- }
-
- if (ranges_overlap(address, len, MCH_HOST_BRIDGE_PCIEXBAR,
- MCH_HOST_BRIDGE_PCIEXBAR_SIZE)) {
- mch_update_pciexbar(mch);
- }
-
- if (ranges_overlap(address, len, MCH_HOST_BRIDGE_SMRAM,
- MCH_HOST_BRIDGE_SMRAM_SIZE)) {
- mch_update_smram(mch);
- }
-}
-
-static void mch_update(MCHPCIState *mch)
-{
- mch_update_pciexbar(mch);
- mch_update_pam(mch);
- mch_update_smram(mch);
-}
-
-static int mch_post_load(void *opaque, int version_id)
-{
- MCHPCIState *mch = opaque;
- mch_update(mch);
- return 0;
-}
-
-static const VMStateDescription vmstate_mch = {
- .name = "mch",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = mch_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(parent_obj, MCHPCIState),
- /* Used to be smm_enabled, which was basically always zero because
- * SeaBIOS hardly uses SMM. SMRAM is now handled by CPU code.
- */
- VMSTATE_UNUSED(1),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void mch_reset(DeviceState *qdev)
-{
- PCIDevice *d = PCI_DEVICE(qdev);
- MCHPCIState *mch = MCH_PCI_DEVICE(d);
-
- pci_set_quad(d->config + MCH_HOST_BRIDGE_PCIEXBAR,
- MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT);
-
- d->config[MCH_HOST_BRIDGE_SMRAM] = MCH_HOST_BRIDGE_SMRAM_DEFAULT;
- d->config[MCH_HOST_BRIDGE_ESMRAMC] = MCH_HOST_BRIDGE_ESMRAMC_DEFAULT;
- d->wmask[MCH_HOST_BRIDGE_SMRAM] = MCH_HOST_BRIDGE_SMRAM_WMASK;
- d->wmask[MCH_HOST_BRIDGE_ESMRAMC] = MCH_HOST_BRIDGE_ESMRAMC_WMASK;
-
- mch_update(mch);
-}
-
-static AddressSpace *q35_host_dma_iommu(PCIBus *bus, void *opaque, int devfn)
-{
- IntelIOMMUState *s = opaque;
- VTDAddressSpace *vtd_as;
-
- assert(0 <= devfn && devfn <= VTD_PCI_DEVFN_MAX);
-
- vtd_as = vtd_find_add_as(s, bus, devfn);
- return &vtd_as->as;
-}
-
-static void mch_init_dmar(MCHPCIState *mch)
-{
- PCIBus *pci_bus = PCI_BUS(qdev_get_parent_bus(DEVICE(mch)));
-
- mch->iommu = INTEL_IOMMU_DEVICE(qdev_create(NULL, TYPE_INTEL_IOMMU_DEVICE));
- object_property_add_child(OBJECT(mch), "intel-iommu",
- OBJECT(mch->iommu), NULL);
- qdev_init_nofail(DEVICE(mch->iommu));
- sysbus_mmio_map(SYS_BUS_DEVICE(mch->iommu), 0, Q35_HOST_BRIDGE_IOMMU_ADDR);
-
- pci_setup_iommu(pci_bus, q35_host_dma_iommu, mch->iommu);
-}
-
-static void mch_realize(PCIDevice *d, Error **errp)
-{
- int i;
- MCHPCIState *mch = MCH_PCI_DEVICE(d);
-
- /* setup pci memory mapping */
- pc_pci_as_mapping_init(OBJECT(mch), mch->system_memory,
- mch->pci_address_space);
-
- /* if *disabled* show SMRAM to all CPUs */
- memory_region_init_alias(&mch->smram_region, OBJECT(mch), "smram-region",
- mch->pci_address_space, 0xa0000, 0x20000);
- memory_region_add_subregion_overlap(mch->system_memory, 0xa0000,
- &mch->smram_region, 1);
- memory_region_set_enabled(&mch->smram_region, true);
-
- memory_region_init_alias(&mch->open_high_smram, OBJECT(mch), "smram-open-high",
- mch->ram_memory, 0xa0000, 0x20000);
- memory_region_add_subregion_overlap(mch->system_memory, 0xfeda0000,
- &mch->open_high_smram, 1);
- memory_region_set_enabled(&mch->open_high_smram, false);
-
- /* smram, as seen by SMM CPUs */
- memory_region_init(&mch->smram, OBJECT(mch), "smram", 1ull << 32);
- memory_region_set_enabled(&mch->smram, true);
- memory_region_init_alias(&mch->low_smram, OBJECT(mch), "smram-low",
- mch->ram_memory, 0xa0000, 0x20000);
- memory_region_set_enabled(&mch->low_smram, true);
- memory_region_add_subregion(&mch->smram, 0xa0000, &mch->low_smram);
- memory_region_init_alias(&mch->high_smram, OBJECT(mch), "smram-high",
- mch->ram_memory, 0xa0000, 0x20000);
- memory_region_set_enabled(&mch->high_smram, true);
- memory_region_add_subregion(&mch->smram, 0xfeda0000, &mch->high_smram);
-
- memory_region_init_io(&mch->tseg_blackhole, OBJECT(mch),
- &tseg_blackhole_ops, NULL,
- "tseg-blackhole", 0);
- memory_region_set_enabled(&mch->tseg_blackhole, false);
- memory_region_add_subregion_overlap(mch->system_memory,
- mch->below_4g_mem_size,
- &mch->tseg_blackhole, 1);
-
- memory_region_init_alias(&mch->tseg_window, OBJECT(mch), "tseg-window",
- mch->ram_memory, mch->below_4g_mem_size, 0);
- memory_region_set_enabled(&mch->tseg_window, false);
- memory_region_add_subregion(&mch->smram, mch->below_4g_mem_size,
- &mch->tseg_window);
- object_property_add_const_link(qdev_get_machine(), "smram",
- OBJECT(&mch->smram), &error_abort);
-
- init_pam(DEVICE(mch), mch->ram_memory, mch->system_memory,
- mch->pci_address_space, &mch->pam_regions[0],
- PAM_BIOS_BASE, PAM_BIOS_SIZE);
- for (i = 0; i < 12; ++i) {
- init_pam(DEVICE(mch), mch->ram_memory, mch->system_memory,
- mch->pci_address_space, &mch->pam_regions[i+1],
- PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE, PAM_EXPAN_SIZE);
- }
- /* Intel IOMMU (VT-d) */
- if (object_property_get_bool(qdev_get_machine(), "iommu", NULL)) {
- mch_init_dmar(mch);
- }
-}
-
-uint64_t mch_mcfg_base(void)
-{
- bool ambiguous;
- Object *o = object_resolve_path_type("", TYPE_MCH_PCI_DEVICE, &ambiguous);
- if (!o) {
- return 0;
- }
- return MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT;
-}
-
-static void mch_class_init(ObjectClass *klass, void *data)
-{
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- k->realize = mch_realize;
- k->config_write = mch_write_config;
- dc->reset = mch_reset;
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
- dc->desc = "Host bridge";
- dc->vmsd = &vmstate_mch;
- k->vendor_id = PCI_VENDOR_ID_INTEL;
- k->device_id = PCI_DEVICE_ID_INTEL_Q35_MCH;
- k->revision = MCH_HOST_BRIDGE_REVISION_DEFAULT;
- k->class_id = PCI_CLASS_BRIDGE_HOST;
- /*
- * PCI-facing part of the host bridge, not usable without the
- * host-facing part, which can't be device_add'ed, yet.
- */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo mch_info = {
- .name = TYPE_MCH_PCI_DEVICE,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(MCHPCIState),
- .class_init = mch_class_init,
-};
-
-static void q35_register(void)
-{
- type_register_static(&mch_info);
- type_register_static(&q35_host_info);
-}
-
-type_init(q35_register);
diff --git a/qemu/hw/pci-host/uninorth.c b/qemu/hw/pci-host/uninorth.c
deleted file mode 100644
index 15b105423..000000000
--- a/qemu/hw/pci-host/uninorth.c
+++ /dev/null
@@ -1,533 +0,0 @@
-/*
- * QEMU Uninorth PCI host (for all Mac99 and newer machines)
- *
- * Copyright (c) 2006 Fabrice Bellard
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/ppc/mac.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/pci_host.h"
-
-/* debug UniNorth */
-//#define DEBUG_UNIN
-
-#ifdef DEBUG_UNIN
-#define UNIN_DPRINTF(fmt, ...) \
- do { printf("UNIN: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define UNIN_DPRINTF(fmt, ...)
-#endif
-
-static const int unin_irq_line[] = { 0x1b, 0x1c, 0x1d, 0x1e };
-
-#define TYPE_UNI_NORTH_PCI_HOST_BRIDGE "uni-north-pci-pcihost"
-#define TYPE_UNI_NORTH_AGP_HOST_BRIDGE "uni-north-agp-pcihost"
-#define TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE "uni-north-internal-pci-pcihost"
-#define TYPE_U3_AGP_HOST_BRIDGE "u3-agp-pcihost"
-
-#define UNI_NORTH_PCI_HOST_BRIDGE(obj) \
- OBJECT_CHECK(UNINState, (obj), TYPE_UNI_NORTH_PCI_HOST_BRIDGE)
-#define UNI_NORTH_AGP_HOST_BRIDGE(obj) \
- OBJECT_CHECK(UNINState, (obj), TYPE_UNI_NORTH_AGP_HOST_BRIDGE)
-#define UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE(obj) \
- OBJECT_CHECK(UNINState, (obj), TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE)
-#define U3_AGP_HOST_BRIDGE(obj) \
- OBJECT_CHECK(UNINState, (obj), TYPE_U3_AGP_HOST_BRIDGE)
-
-typedef struct UNINState {
- PCIHostState parent_obj;
-
- MemoryRegion pci_mmio;
- MemoryRegion pci_hole;
-} UNINState;
-
-static int pci_unin_map_irq(PCIDevice *pci_dev, int irq_num)
-{
- int retval;
- int devfn = pci_dev->devfn & 0x00FFFFFF;
-
- retval = (((devfn >> 11) & 0x1F) + irq_num) & 3;
-
- return retval;
-}
-
-static void pci_unin_set_irq(void *opaque, int irq_num, int level)
-{
- qemu_irq *pic = opaque;
-
- UNIN_DPRINTF("%s: setting INT %d = %d\n", __func__,
- unin_irq_line[irq_num], level);
- qemu_set_irq(pic[unin_irq_line[irq_num]], level);
-}
-
-static uint32_t unin_get_config_reg(uint32_t reg, uint32_t addr)
-{
- uint32_t retval;
-
- if (reg & (1u << 31)) {
- /* XXX OpenBIOS compatibility hack */
- retval = reg | (addr & 3);
- } else if (reg & 1) {
- /* CFA1 style */
- retval = (reg & ~7u) | (addr & 7);
- } else {
- uint32_t slot, func;
-
- /* Grab CFA0 style values */
- slot = ctz32(reg & 0xfffff800);
- if (slot == 32) {
- slot = -1; /* XXX: should this be 0? */
- }
- func = (reg >> 8) & 7;
-
- /* ... and then convert them to x86 format */
- /* config pointer */
- retval = (reg & (0xff - 7)) | (addr & 7);
- /* slot */
- retval |= slot << 11;
- /* fn */
- retval |= func << 8;
- }
-
-
- UNIN_DPRINTF("Converted config space accessor %08x/%08x -> %08x\n",
- reg, addr, retval);
-
- return retval;
-}
-
-static void unin_data_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned len)
-{
- UNINState *s = opaque;
- PCIHostState *phb = PCI_HOST_BRIDGE(s);
- UNIN_DPRINTF("write addr " TARGET_FMT_plx " len %d val %"PRIx64"\n",
- addr, len, val);
- pci_data_write(phb->bus,
- unin_get_config_reg(phb->config_reg, addr),
- val, len);
-}
-
-static uint64_t unin_data_read(void *opaque, hwaddr addr,
- unsigned len)
-{
- UNINState *s = opaque;
- PCIHostState *phb = PCI_HOST_BRIDGE(s);
- uint32_t val;
-
- val = pci_data_read(phb->bus,
- unin_get_config_reg(phb->config_reg, addr),
- len);
- UNIN_DPRINTF("read addr " TARGET_FMT_plx " len %d val %x\n",
- addr, len, val);
- return val;
-}
-
-static const MemoryRegionOps unin_data_ops = {
- .read = unin_data_read,
- .write = unin_data_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static int pci_unin_main_init_device(SysBusDevice *dev)
-{
- PCIHostState *h;
-
- /* Use values found on a real PowerMac */
- /* Uninorth main bus */
- h = PCI_HOST_BRIDGE(dev);
-
- memory_region_init_io(&h->conf_mem, OBJECT(h), &pci_host_conf_le_ops,
- dev, "pci-conf-idx", 0x1000);
- memory_region_init_io(&h->data_mem, OBJECT(h), &unin_data_ops, dev,
- "pci-conf-data", 0x1000);
- sysbus_init_mmio(dev, &h->conf_mem);
- sysbus_init_mmio(dev, &h->data_mem);
-
- return 0;
-}
-
-
-static int pci_u3_agp_init_device(SysBusDevice *dev)
-{
- PCIHostState *h;
-
- /* Uninorth U3 AGP bus */
- h = PCI_HOST_BRIDGE(dev);
-
- memory_region_init_io(&h->conf_mem, OBJECT(h), &pci_host_conf_le_ops,
- dev, "pci-conf-idx", 0x1000);
- memory_region_init_io(&h->data_mem, OBJECT(h), &unin_data_ops, dev,
- "pci-conf-data", 0x1000);
- sysbus_init_mmio(dev, &h->conf_mem);
- sysbus_init_mmio(dev, &h->data_mem);
-
- return 0;
-}
-
-static int pci_unin_agp_init_device(SysBusDevice *dev)
-{
- PCIHostState *h;
-
- /* Uninorth AGP bus */
- h = PCI_HOST_BRIDGE(dev);
-
- memory_region_init_io(&h->conf_mem, OBJECT(h), &pci_host_conf_le_ops,
- dev, "pci-conf-idx", 0x1000);
- memory_region_init_io(&h->data_mem, OBJECT(h), &pci_host_data_le_ops,
- dev, "pci-conf-data", 0x1000);
- sysbus_init_mmio(dev, &h->conf_mem);
- sysbus_init_mmio(dev, &h->data_mem);
- return 0;
-}
-
-static int pci_unin_internal_init_device(SysBusDevice *dev)
-{
- PCIHostState *h;
-
- /* Uninorth internal bus */
- h = PCI_HOST_BRIDGE(dev);
-
- memory_region_init_io(&h->conf_mem, OBJECT(h), &pci_host_conf_le_ops,
- dev, "pci-conf-idx", 0x1000);
- memory_region_init_io(&h->data_mem, OBJECT(h), &pci_host_data_le_ops,
- dev, "pci-conf-data", 0x1000);
- sysbus_init_mmio(dev, &h->conf_mem);
- sysbus_init_mmio(dev, &h->data_mem);
- return 0;
-}
-
-PCIBus *pci_pmac_init(qemu_irq *pic,
- MemoryRegion *address_space_mem,
- MemoryRegion *address_space_io)
-{
- DeviceState *dev;
- SysBusDevice *s;
- PCIHostState *h;
- UNINState *d;
-
- /* Use values found on a real PowerMac */
- /* Uninorth main bus */
- dev = qdev_create(NULL, TYPE_UNI_NORTH_PCI_HOST_BRIDGE);
- qdev_init_nofail(dev);
- s = SYS_BUS_DEVICE(dev);
- h = PCI_HOST_BRIDGE(s);
- d = UNI_NORTH_PCI_HOST_BRIDGE(dev);
- memory_region_init(&d->pci_mmio, OBJECT(d), "pci-mmio", 0x100000000ULL);
- memory_region_init_alias(&d->pci_hole, OBJECT(d), "pci-hole", &d->pci_mmio,
- 0x80000000ULL, 0x10000000ULL);
- memory_region_add_subregion(address_space_mem, 0x80000000ULL,
- &d->pci_hole);
-
- h->bus = pci_register_bus(dev, NULL,
- pci_unin_set_irq, pci_unin_map_irq,
- pic,
- &d->pci_mmio,
- address_space_io,
- PCI_DEVFN(11, 0), 4, TYPE_PCI_BUS);
-
-#if 0
- pci_create_simple(h->bus, PCI_DEVFN(11, 0), "uni-north");
-#endif
-
- sysbus_mmio_map(s, 0, 0xf2800000);
- sysbus_mmio_map(s, 1, 0xf2c00000);
-
- /* DEC 21154 bridge */
-#if 0
- /* XXX: not activated as PPC BIOS doesn't handle multiple buses properly */
- pci_create_simple(h->bus, PCI_DEVFN(12, 0), "dec-21154");
-#endif
-
- /* Uninorth AGP bus */
- pci_create_simple(h->bus, PCI_DEVFN(11, 0), "uni-north-agp");
- dev = qdev_create(NULL, TYPE_UNI_NORTH_AGP_HOST_BRIDGE);
- qdev_init_nofail(dev);
- s = SYS_BUS_DEVICE(dev);
- sysbus_mmio_map(s, 0, 0xf0800000);
- sysbus_mmio_map(s, 1, 0xf0c00000);
-
- /* Uninorth internal bus */
-#if 0
- /* XXX: not needed for now */
- pci_create_simple(h->bus, PCI_DEVFN(14, 0),
- "uni-north-internal-pci");
- dev = qdev_create(NULL, TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE);
- qdev_init_nofail(dev);
- s = SYS_BUS_DEVICE(dev);
- sysbus_mmio_map(s, 0, 0xf4800000);
- sysbus_mmio_map(s, 1, 0xf4c00000);
-#endif
-
- return h->bus;
-}
-
-PCIBus *pci_pmac_u3_init(qemu_irq *pic,
- MemoryRegion *address_space_mem,
- MemoryRegion *address_space_io)
-{
- DeviceState *dev;
- SysBusDevice *s;
- PCIHostState *h;
- UNINState *d;
-
- /* Uninorth AGP bus */
-
- dev = qdev_create(NULL, TYPE_U3_AGP_HOST_BRIDGE);
- qdev_init_nofail(dev);
- s = SYS_BUS_DEVICE(dev);
- h = PCI_HOST_BRIDGE(dev);
- d = U3_AGP_HOST_BRIDGE(dev);
-
- memory_region_init(&d->pci_mmio, OBJECT(d), "pci-mmio", 0x100000000ULL);
- memory_region_init_alias(&d->pci_hole, OBJECT(d), "pci-hole", &d->pci_mmio,
- 0x80000000ULL, 0x70000000ULL);
- memory_region_add_subregion(address_space_mem, 0x80000000ULL,
- &d->pci_hole);
-
- h->bus = pci_register_bus(dev, NULL,
- pci_unin_set_irq, pci_unin_map_irq,
- pic,
- &d->pci_mmio,
- address_space_io,
- PCI_DEVFN(11, 0), 4, TYPE_PCI_BUS);
-
- sysbus_mmio_map(s, 0, 0xf0800000);
- sysbus_mmio_map(s, 1, 0xf0c00000);
-
- pci_create_simple(h->bus, 11 << 3, "u3-agp");
-
- return h->bus;
-}
-
-static void unin_main_pci_host_realize(PCIDevice *d, Error **errp)
-{
- d->config[0x0C] = 0x08; // cache_line_size
- d->config[0x0D] = 0x10; // latency_timer
- d->config[0x34] = 0x00; // capabilities_pointer
-}
-
-static void unin_agp_pci_host_realize(PCIDevice *d, Error **errp)
-{
- d->config[0x0C] = 0x08; // cache_line_size
- d->config[0x0D] = 0x10; // latency_timer
- // d->config[0x34] = 0x80; // capabilities_pointer
- /*
- * Set kMacRISCPCIAddressSelect (0x48) register to indicate PCI
- * memory space with base 0x80000000, size 0x10000000 for Apple's
- * AppleMacRiscPCI driver
- */
- d->config[0x48] = 0x0;
- d->config[0x49] = 0x0;
- d->config[0x4a] = 0x0;
- d->config[0x4b] = 0x1;
-}
-
-static void u3_agp_pci_host_realize(PCIDevice *d, Error **errp)
-{
- /* cache line size */
- d->config[0x0C] = 0x08;
- /* latency timer */
- d->config[0x0D] = 0x10;
-}
-
-static void unin_internal_pci_host_realize(PCIDevice *d, Error **errp)
-{
- d->config[0x0C] = 0x08; // cache_line_size
- d->config[0x0D] = 0x10; // latency_timer
- d->config[0x34] = 0x00; // capabilities_pointer
-}
-
-static void unin_main_pci_host_class_init(ObjectClass *klass, void *data)
-{
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- k->realize = unin_main_pci_host_realize;
- k->vendor_id = PCI_VENDOR_ID_APPLE;
- k->device_id = PCI_DEVICE_ID_APPLE_UNI_N_PCI;
- k->revision = 0x00;
- k->class_id = PCI_CLASS_BRIDGE_HOST;
- /*
- * PCI-facing part of the host bridge, not usable without the
- * host-facing part, which can't be device_add'ed, yet.
- */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo unin_main_pci_host_info = {
- .name = "uni-north-pci",
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(PCIDevice),
- .class_init = unin_main_pci_host_class_init,
-};
-
-static void u3_agp_pci_host_class_init(ObjectClass *klass, void *data)
-{
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- k->realize = u3_agp_pci_host_realize;
- k->vendor_id = PCI_VENDOR_ID_APPLE;
- k->device_id = PCI_DEVICE_ID_APPLE_U3_AGP;
- k->revision = 0x00;
- k->class_id = PCI_CLASS_BRIDGE_HOST;
- /*
- * PCI-facing part of the host bridge, not usable without the
- * host-facing part, which can't be device_add'ed, yet.
- */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo u3_agp_pci_host_info = {
- .name = "u3-agp",
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(PCIDevice),
- .class_init = u3_agp_pci_host_class_init,
-};
-
-static void unin_agp_pci_host_class_init(ObjectClass *klass, void *data)
-{
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- k->realize = unin_agp_pci_host_realize;
- k->vendor_id = PCI_VENDOR_ID_APPLE;
- k->device_id = PCI_DEVICE_ID_APPLE_UNI_N_AGP;
- k->revision = 0x00;
- k->class_id = PCI_CLASS_BRIDGE_HOST;
- /*
- * PCI-facing part of the host bridge, not usable without the
- * host-facing part, which can't be device_add'ed, yet.
- */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo unin_agp_pci_host_info = {
- .name = "uni-north-agp",
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(PCIDevice),
- .class_init = unin_agp_pci_host_class_init,
-};
-
-static void unin_internal_pci_host_class_init(ObjectClass *klass, void *data)
-{
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- k->realize = unin_internal_pci_host_realize;
- k->vendor_id = PCI_VENDOR_ID_APPLE;
- k->device_id = PCI_DEVICE_ID_APPLE_UNI_N_I_PCI;
- k->revision = 0x00;
- k->class_id = PCI_CLASS_BRIDGE_HOST;
- /*
- * PCI-facing part of the host bridge, not usable without the
- * host-facing part, which can't be device_add'ed, yet.
- */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo unin_internal_pci_host_info = {
- .name = "uni-north-internal-pci",
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(PCIDevice),
- .class_init = unin_internal_pci_host_class_init,
-};
-
-static void pci_unin_main_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- sbc->init = pci_unin_main_init_device;
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
-}
-
-static const TypeInfo pci_unin_main_info = {
- .name = TYPE_UNI_NORTH_PCI_HOST_BRIDGE,
- .parent = TYPE_PCI_HOST_BRIDGE,
- .instance_size = sizeof(UNINState),
- .class_init = pci_unin_main_class_init,
-};
-
-static void pci_u3_agp_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- sbc->init = pci_u3_agp_init_device;
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
-}
-
-static const TypeInfo pci_u3_agp_info = {
- .name = TYPE_U3_AGP_HOST_BRIDGE,
- .parent = TYPE_PCI_HOST_BRIDGE,
- .instance_size = sizeof(UNINState),
- .class_init = pci_u3_agp_class_init,
-};
-
-static void pci_unin_agp_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- sbc->init = pci_unin_agp_init_device;
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
-}
-
-static const TypeInfo pci_unin_agp_info = {
- .name = TYPE_UNI_NORTH_AGP_HOST_BRIDGE,
- .parent = TYPE_PCI_HOST_BRIDGE,
- .instance_size = sizeof(UNINState),
- .class_init = pci_unin_agp_class_init,
-};
-
-static void pci_unin_internal_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- sbc->init = pci_unin_internal_init_device;
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
-}
-
-static const TypeInfo pci_unin_internal_info = {
- .name = TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE,
- .parent = TYPE_PCI_HOST_BRIDGE,
- .instance_size = sizeof(UNINState),
- .class_init = pci_unin_internal_class_init,
-};
-
-static void unin_register_types(void)
-{
- type_register_static(&unin_main_pci_host_info);
- type_register_static(&u3_agp_pci_host_info);
- type_register_static(&unin_agp_pci_host_info);
- type_register_static(&unin_internal_pci_host_info);
-
- type_register_static(&pci_unin_main_info);
- type_register_static(&pci_u3_agp_info);
- type_register_static(&pci_unin_agp_info);
- type_register_static(&pci_unin_internal_info);
-}
-
-type_init(unin_register_types)
diff --git a/qemu/hw/pci-host/versatile.c b/qemu/hw/pci-host/versatile.c
deleted file mode 100644
index 339ec2c50..000000000
--- a/qemu/hw/pci-host/versatile.c
+++ /dev/null
@@ -1,549 +0,0 @@
-/*
- * ARM Versatile/PB PCI host controller
- *
- * Copyright (c) 2006-2009 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the LGPL.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/pci_bus.h"
-#include "hw/pci/pci_host.h"
-#include "exec/address-spaces.h"
-
-/* Old and buggy versions of QEMU used the wrong mapping from
- * PCI IRQs to system interrupt lines. Unfortunately the Linux
- * kernel also had the corresponding bug in setting up interrupts
- * (so older kernels work on QEMU and not on real hardware).
- * We automatically detect these broken kernels and flip back
- * to the broken irq mapping by spotting guest writes to the
- * PCI_INTERRUPT_LINE register to see where the guest thinks
- * interrupts are going to be routed. So we start in state
- * ASSUME_OK on reset, and transition to either BROKEN or
- * FORCE_OK at the first write to an INTERRUPT_LINE register for
- * a slot where broken and correct interrupt mapping would differ.
- * Once in either BROKEN or FORCE_OK we never transition again;
- * this allows a newer kernel to use the INTERRUPT_LINE
- * registers arbitrarily once it has indicated that it isn't
- * broken in its init code somewhere.
- *
- * Unfortunately we have to cope with multiple different
- * variants on the broken kernel behaviour:
- * phase I (before kernel commit 1bc39ac5d) kernels assume old
- * QEMU behaviour, so they use IRQ 27 for all slots
- * phase II (1bc39ac5d and later, but before e3e92a7be6) kernels
- * swizzle IRQs between slots, but do it wrongly, so they
- * work only for every fourth PCI card, and only if (like old
- * QEMU) the PCI host device is at slot 0 rather than where
- * the h/w actually puts it
- * phase III (e3e92a7be6 and later) kernels still swizzle IRQs between
- * slots wrongly, but add a fixed offset of 64 to everything
- * they write to PCI_INTERRUPT_LINE.
- *
- * We live in hope of a mythical phase IV kernel which might
- * actually behave in ways that work on the hardware. Such a
- * kernel should probably start off by writing some value neither
- * 27 nor 91 to slot zero's PCI_INTERRUPT_LINE register to
- * disable the autodetection. After that it can do what it likes.
- *
- * Slot % 4 | hw | I | II | III
- * -------------------------------
- * 0 | 29 | 27 | 27 | 91
- * 1 | 30 | 27 | 28 | 92
- * 2 | 27 | 27 | 29 | 93
- * 3 | 28 | 27 | 30 | 94
- *
- * Since our autodetection is not perfect we also provide a
- * property so the user can make us start in BROKEN or FORCE_OK
- * on reset if they know they have a bad or good kernel.
- */
-enum {
- PCI_VPB_IRQMAP_ASSUME_OK,
- PCI_VPB_IRQMAP_BROKEN,
- PCI_VPB_IRQMAP_FORCE_OK,
-};
-
-typedef struct {
- PCIHostState parent_obj;
-
- qemu_irq irq[4];
- MemoryRegion controlregs;
- MemoryRegion mem_config;
- MemoryRegion mem_config2;
- /* Containers representing the PCI address spaces */
- MemoryRegion pci_io_space;
- MemoryRegion pci_mem_space;
- /* Alias regions into PCI address spaces which we expose as sysbus regions.
- * The offsets into pci_mem_space are controlled by the imap registers.
- */
- MemoryRegion pci_io_window;
- MemoryRegion pci_mem_window[3];
- PCIBus pci_bus;
- PCIDevice pci_dev;
-
- /* Constant for life of device: */
- int realview;
- uint32_t mem_win_size[3];
- uint8_t irq_mapping_prop;
-
- /* Variable state: */
- uint32_t imap[3];
- uint32_t smap[3];
- uint32_t selfid;
- uint32_t flags;
- uint8_t irq_mapping;
-} PCIVPBState;
-
-static void pci_vpb_update_window(PCIVPBState *s, int i)
-{
- /* Adjust the offset of the alias region we use for
- * the memory window i to account for a change in the
- * value of the corresponding IMAP register.
- * Note that the semantics of the IMAP register differ
- * for realview and versatile variants of the controller.
- */
- hwaddr offset;
- if (s->realview) {
- /* Top bits of register (masked according to window size) provide
- * top bits of PCI address.
- */
- offset = s->imap[i] & ~(s->mem_win_size[i] - 1);
- } else {
- /* Bottom 4 bits of register provide top 4 bits of PCI address */
- offset = s->imap[i] << 28;
- }
- memory_region_set_alias_offset(&s->pci_mem_window[i], offset);
-}
-
-static void pci_vpb_update_all_windows(PCIVPBState *s)
-{
- /* Update all alias windows based on the current register state */
- int i;
-
- for (i = 0; i < 3; i++) {
- pci_vpb_update_window(s, i);
- }
-}
-
-static int pci_vpb_post_load(void *opaque, int version_id)
-{
- PCIVPBState *s = opaque;
- pci_vpb_update_all_windows(s);
- return 0;
-}
-
-static const VMStateDescription pci_vpb_vmstate = {
- .name = "versatile-pci",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = pci_vpb_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(imap, PCIVPBState, 3),
- VMSTATE_UINT32_ARRAY(smap, PCIVPBState, 3),
- VMSTATE_UINT32(selfid, PCIVPBState),
- VMSTATE_UINT32(flags, PCIVPBState),
- VMSTATE_UINT8(irq_mapping, PCIVPBState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-#define TYPE_VERSATILE_PCI "versatile_pci"
-#define PCI_VPB(obj) \
- OBJECT_CHECK(PCIVPBState, (obj), TYPE_VERSATILE_PCI)
-
-#define TYPE_VERSATILE_PCI_HOST "versatile_pci_host"
-#define PCI_VPB_HOST(obj) \
- OBJECT_CHECK(PCIDevice, (obj), TYPE_VERSATILE_PCIHOST)
-
-typedef enum {
- PCI_IMAP0 = 0x0,
- PCI_IMAP1 = 0x4,
- PCI_IMAP2 = 0x8,
- PCI_SELFID = 0xc,
- PCI_FLAGS = 0x10,
- PCI_SMAP0 = 0x14,
- PCI_SMAP1 = 0x18,
- PCI_SMAP2 = 0x1c,
-} PCIVPBControlRegs;
-
-static void pci_vpb_reg_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- PCIVPBState *s = opaque;
-
- switch (addr) {
- case PCI_IMAP0:
- case PCI_IMAP1:
- case PCI_IMAP2:
- {
- int win = (addr - PCI_IMAP0) >> 2;
- s->imap[win] = val;
- pci_vpb_update_window(s, win);
- break;
- }
- case PCI_SELFID:
- s->selfid = val;
- break;
- case PCI_FLAGS:
- s->flags = val;
- break;
- case PCI_SMAP0:
- case PCI_SMAP1:
- case PCI_SMAP2:
- {
- int win = (addr - PCI_SMAP0) >> 2;
- s->smap[win] = val;
- break;
- }
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "pci_vpb_reg_write: Bad offset %x\n", (int)addr);
- break;
- }
-}
-
-static uint64_t pci_vpb_reg_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- PCIVPBState *s = opaque;
-
- switch (addr) {
- case PCI_IMAP0:
- case PCI_IMAP1:
- case PCI_IMAP2:
- {
- int win = (addr - PCI_IMAP0) >> 2;
- return s->imap[win];
- }
- case PCI_SELFID:
- return s->selfid;
- case PCI_FLAGS:
- return s->flags;
- case PCI_SMAP0:
- case PCI_SMAP1:
- case PCI_SMAP2:
- {
- int win = (addr - PCI_SMAP0) >> 2;
- return s->smap[win];
- }
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "pci_vpb_reg_read: Bad offset %x\n", (int)addr);
- return 0;
- }
-}
-
-static const MemoryRegionOps pci_vpb_reg_ops = {
- .read = pci_vpb_reg_read,
- .write = pci_vpb_reg_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static int pci_vpb_broken_irq(int slot, int irq)
-{
- /* Determine whether this IRQ value for this slot represents a
- * known broken Linux kernel behaviour for this slot.
- * Return one of the PCI_VPB_IRQMAP_ constants:
- * BROKEN : if this definitely looks like a broken kernel
- * FORCE_OK : if this definitely looks good
- * ASSUME_OK : if we can't tell
- */
- slot %= PCI_NUM_PINS;
-
- if (irq == 27) {
- if (slot == 2) {
- /* Might be a Phase I kernel, or might be a fixed kernel,
- * since slot 2 is where we expect this IRQ.
- */
- return PCI_VPB_IRQMAP_ASSUME_OK;
- }
- /* Phase I kernel */
- return PCI_VPB_IRQMAP_BROKEN;
- }
- if (irq == slot + 27) {
- /* Phase II kernel */
- return PCI_VPB_IRQMAP_BROKEN;
- }
- if (irq == slot + 27 + 64) {
- /* Phase III kernel */
- return PCI_VPB_IRQMAP_BROKEN;
- }
- /* Anything else must be a fixed kernel, possibly using an
- * arbitrary irq map.
- */
- return PCI_VPB_IRQMAP_FORCE_OK;
-}
-
-static void pci_vpb_config_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- PCIVPBState *s = opaque;
- if (!s->realview && (addr & 0xff) == PCI_INTERRUPT_LINE
- && s->irq_mapping == PCI_VPB_IRQMAP_ASSUME_OK) {
- uint8_t devfn = addr >> 8;
- s->irq_mapping = pci_vpb_broken_irq(PCI_SLOT(devfn), val);
- }
- pci_data_write(&s->pci_bus, addr, val, size);
-}
-
-static uint64_t pci_vpb_config_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- PCIVPBState *s = opaque;
- uint32_t val;
- val = pci_data_read(&s->pci_bus, addr, size);
- return val;
-}
-
-static const MemoryRegionOps pci_vpb_config_ops = {
- .read = pci_vpb_config_read,
- .write = pci_vpb_config_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int pci_vpb_map_irq(PCIDevice *d, int irq_num)
-{
- PCIVPBState *s = container_of(d->bus, PCIVPBState, pci_bus);
-
- if (s->irq_mapping == PCI_VPB_IRQMAP_BROKEN) {
- /* Legacy broken IRQ mapping for compatibility with old and
- * buggy Linux guests
- */
- return irq_num;
- }
-
- /* Slot to IRQ mapping for RealView Platform Baseboard 926 backplane
- * name slot IntA IntB IntC IntD
- * A 31 IRQ28 IRQ29 IRQ30 IRQ27
- * B 30 IRQ27 IRQ28 IRQ29 IRQ30
- * C 29 IRQ30 IRQ27 IRQ28 IRQ29
- * Slot C is for the host bridge; A and B the peripherals.
- * Our output irqs 0..3 correspond to the baseboard's 27..30.
- *
- * This mapping function takes account of an oddity in the PB926
- * board wiring, where the FPGA's P_nINTA input is connected to
- * the INTB connection on the board PCI edge connector, P_nINTB
- * is connected to INTC, and so on, so everything is one number
- * further round from where you might expect.
- */
- return pci_swizzle_map_irq_fn(d, irq_num + 2);
-}
-
-static int pci_vpb_rv_map_irq(PCIDevice *d, int irq_num)
-{
- /* Slot to IRQ mapping for RealView EB and PB1176 backplane
- * name slot IntA IntB IntC IntD
- * A 31 IRQ50 IRQ51 IRQ48 IRQ49
- * B 30 IRQ49 IRQ50 IRQ51 IRQ48
- * C 29 IRQ48 IRQ49 IRQ50 IRQ51
- * Slot C is for the host bridge; A and B the peripherals.
- * Our output irqs 0..3 correspond to the baseboard's 48..51.
- *
- * The PB1176 and EB boards don't have the PB926 wiring oddity
- * described above; P_nINTA connects to INTA, P_nINTB to INTB
- * and so on, which is why this mapping function is different.
- */
- return pci_swizzle_map_irq_fn(d, irq_num + 3);
-}
-
-static void pci_vpb_set_irq(void *opaque, int irq_num, int level)
-{
- qemu_irq *pic = opaque;
-
- qemu_set_irq(pic[irq_num], level);
-}
-
-static void pci_vpb_reset(DeviceState *d)
-{
- PCIVPBState *s = PCI_VPB(d);
-
- s->imap[0] = 0;
- s->imap[1] = 0;
- s->imap[2] = 0;
- s->smap[0] = 0;
- s->smap[1] = 0;
- s->smap[2] = 0;
- s->selfid = 0;
- s->flags = 0;
- s->irq_mapping = s->irq_mapping_prop;
-
- pci_vpb_update_all_windows(s);
-}
-
-static void pci_vpb_init(Object *obj)
-{
- PCIHostState *h = PCI_HOST_BRIDGE(obj);
- PCIVPBState *s = PCI_VPB(obj);
-
- memory_region_init(&s->pci_io_space, OBJECT(s), "pci_io", 1ULL << 32);
- memory_region_init(&s->pci_mem_space, OBJECT(s), "pci_mem", 1ULL << 32);
-
- pci_bus_new_inplace(&s->pci_bus, sizeof(s->pci_bus), DEVICE(obj), "pci",
- &s->pci_mem_space, &s->pci_io_space,
- PCI_DEVFN(11, 0), TYPE_PCI_BUS);
- h->bus = &s->pci_bus;
-
- object_initialize(&s->pci_dev, sizeof(s->pci_dev), TYPE_VERSATILE_PCI_HOST);
- qdev_set_parent_bus(DEVICE(&s->pci_dev), BUS(&s->pci_bus));
-
- /* Window sizes for VersatilePB; realview_pci's init will override */
- s->mem_win_size[0] = 0x0c000000;
- s->mem_win_size[1] = 0x10000000;
- s->mem_win_size[2] = 0x10000000;
-}
-
-static void pci_vpb_realize(DeviceState *dev, Error **errp)
-{
- PCIVPBState *s = PCI_VPB(dev);
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- pci_map_irq_fn mapfn;
- int i;
-
- for (i = 0; i < 4; i++) {
- sysbus_init_irq(sbd, &s->irq[i]);
- }
-
- if (s->realview) {
- mapfn = pci_vpb_rv_map_irq;
- } else {
- mapfn = pci_vpb_map_irq;
- }
-
- pci_bus_irqs(&s->pci_bus, pci_vpb_set_irq, mapfn, s->irq, 4);
-
- /* Our memory regions are:
- * 0 : our control registers
- * 1 : PCI self config window
- * 2 : PCI config window
- * 3 : PCI IO window
- * 4..6 : PCI memory windows
- */
- memory_region_init_io(&s->controlregs, OBJECT(s), &pci_vpb_reg_ops, s,
- "pci-vpb-regs", 0x1000);
- sysbus_init_mmio(sbd, &s->controlregs);
- memory_region_init_io(&s->mem_config, OBJECT(s), &pci_vpb_config_ops, s,
- "pci-vpb-selfconfig", 0x1000000);
- sysbus_init_mmio(sbd, &s->mem_config);
- memory_region_init_io(&s->mem_config2, OBJECT(s), &pci_vpb_config_ops, s,
- "pci-vpb-config", 0x1000000);
- sysbus_init_mmio(sbd, &s->mem_config2);
-
- /* The window into I/O space is always into a fixed base address;
- * its size is the same for both realview and versatile.
- */
- memory_region_init_alias(&s->pci_io_window, OBJECT(s), "pci-vbp-io-window",
- &s->pci_io_space, 0, 0x100000);
-
- sysbus_init_mmio(sbd, &s->pci_io_space);
-
- /* Create the alias regions corresponding to our three windows onto
- * PCI memory space. The sizes vary from board to board; the base
- * offsets are guest controllable via the IMAP registers.
- */
- for (i = 0; i < 3; i++) {
- memory_region_init_alias(&s->pci_mem_window[i], OBJECT(s), "pci-vbp-window",
- &s->pci_mem_space, 0, s->mem_win_size[i]);
- sysbus_init_mmio(sbd, &s->pci_mem_window[i]);
- }
-
- /* TODO Remove once realize propagates to child devices. */
- object_property_set_bool(OBJECT(&s->pci_dev), true, "realized", errp);
-}
-
-static void versatile_pci_host_realize(PCIDevice *d, Error **errp)
-{
- pci_set_word(d->config + PCI_STATUS,
- PCI_STATUS_66MHZ | PCI_STATUS_DEVSEL_MEDIUM);
- pci_set_byte(d->config + PCI_LATENCY_TIMER, 0x10);
-}
-
-static void versatile_pci_host_class_init(ObjectClass *klass, void *data)
-{
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- k->realize = versatile_pci_host_realize;
- k->vendor_id = PCI_VENDOR_ID_XILINX;
- k->device_id = PCI_DEVICE_ID_XILINX_XC2VP30;
- k->class_id = PCI_CLASS_PROCESSOR_CO;
- /*
- * PCI-facing part of the host bridge, not usable without the
- * host-facing part, which can't be device_add'ed, yet.
- */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo versatile_pci_host_info = {
- .name = TYPE_VERSATILE_PCI_HOST,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(PCIDevice),
- .class_init = versatile_pci_host_class_init,
-};
-
-static Property pci_vpb_properties[] = {
- DEFINE_PROP_UINT8("broken-irq-mapping", PCIVPBState, irq_mapping_prop,
- PCI_VPB_IRQMAP_ASSUME_OK),
- DEFINE_PROP_END_OF_LIST()
-};
-
-static void pci_vpb_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = pci_vpb_realize;
- dc->reset = pci_vpb_reset;
- dc->vmsd = &pci_vpb_vmstate;
- dc->props = pci_vpb_properties;
- /* Reason: object_unref() hangs */
- dc->cannot_destroy_with_object_finalize_yet = true;
-}
-
-static const TypeInfo pci_vpb_info = {
- .name = TYPE_VERSATILE_PCI,
- .parent = TYPE_PCI_HOST_BRIDGE,
- .instance_size = sizeof(PCIVPBState),
- .instance_init = pci_vpb_init,
- .class_init = pci_vpb_class_init,
-};
-
-static void pci_realview_init(Object *obj)
-{
- PCIVPBState *s = PCI_VPB(obj);
-
- s->realview = 1;
- /* The PCI window sizes are different on Realview boards */
- s->mem_win_size[0] = 0x01000000;
- s->mem_win_size[1] = 0x04000000;
- s->mem_win_size[2] = 0x08000000;
-}
-
-static void pci_realview_class_init(ObjectClass *class, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(class);
-
- /* Reason: object_unref() hangs */
- dc->cannot_destroy_with_object_finalize_yet = true;
-}
-
-static const TypeInfo pci_realview_info = {
- .name = "realview_pci",
- .parent = TYPE_VERSATILE_PCI,
- .instance_init = pci_realview_init,
- .class_init = pci_realview_class_init,
-};
-
-static void versatile_pci_register_types(void)
-{
- type_register_static(&pci_vpb_info);
- type_register_static(&pci_realview_info);
- type_register_static(&versatile_pci_host_info);
-}
-
-type_init(versatile_pci_register_types)
diff --git a/qemu/hw/pci/Makefile.objs b/qemu/hw/pci/Makefile.objs
deleted file mode 100644
index 9f905e634..000000000
--- a/qemu/hw/pci/Makefile.objs
+++ /dev/null
@@ -1,9 +0,0 @@
-common-obj-$(CONFIG_PCI) += pci.o pci_bridge.o
-common-obj-$(CONFIG_PCI) += msix.o msi.o
-common-obj-$(CONFIG_PCI) += shpc.o
-common-obj-$(CONFIG_PCI) += slotid_cap.o
-common-obj-$(CONFIG_PCI) += pci_host.o pcie_host.o
-common-obj-$(CONFIG_PCI) += pcie.o pcie_aer.o pcie_port.o
-
-common-obj-$(call lnot,$(CONFIG_PCI)) += pci-stub.o
-common-obj-$(CONFIG_ALL) += pci-stub.o
diff --git a/qemu/hw/pci/msi.c b/qemu/hw/pci/msi.c
deleted file mode 100644
index e0e64c2d9..000000000
--- a/qemu/hw/pci/msi.c
+++ /dev/null
@@ -1,421 +0,0 @@
-/*
- * msi.c
- *
- * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
- * VA Linux Systems Japan K.K.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/pci/msi.h"
-#include "hw/xen/xen.h"
-#include "qemu/range.h"
-
-/* PCI_MSI_ADDRESS_LO */
-#define PCI_MSI_ADDRESS_LO_MASK (~0x3)
-
-/* If we get rid of cap allocator, we won't need those. */
-#define PCI_MSI_32_SIZEOF 0x0a
-#define PCI_MSI_64_SIZEOF 0x0e
-#define PCI_MSI_32M_SIZEOF 0x14
-#define PCI_MSI_64M_SIZEOF 0x18
-
-#define PCI_MSI_VECTORS_MAX 32
-
-/*
- * Flag for interrupt controllers to declare broken MSI/MSI-X support.
- * values: false - broken; true - non-broken.
- *
- * Setting this flag to false will remove MSI/MSI-X capability from all devices.
- *
- * It is preferrable for controllers to set this to true (non-broken) even if
- * they do not actually support MSI/MSI-X: guests normally probe the controller
- * type and do not attempt to enable MSI/MSI-X with interrupt controllers not
- * supporting such, so removing the capability is not required, and
- * it seems cleaner to have a given device look the same for all boards.
- *
- * TODO: some existing controllers violate the above rule. Identify and fix them.
- */
-bool msi_nonbroken;
-
-/* If we get rid of cap allocator, we won't need this. */
-static inline uint8_t msi_cap_sizeof(uint16_t flags)
-{
- switch (flags & (PCI_MSI_FLAGS_MASKBIT | PCI_MSI_FLAGS_64BIT)) {
- case PCI_MSI_FLAGS_MASKBIT | PCI_MSI_FLAGS_64BIT:
- return PCI_MSI_64M_SIZEOF;
- case PCI_MSI_FLAGS_64BIT:
- return PCI_MSI_64_SIZEOF;
- case PCI_MSI_FLAGS_MASKBIT:
- return PCI_MSI_32M_SIZEOF;
- case 0:
- return PCI_MSI_32_SIZEOF;
- default:
- abort();
- break;
- }
- return 0;
-}
-
-//#define MSI_DEBUG
-
-#ifdef MSI_DEBUG
-# define MSI_DPRINTF(fmt, ...) \
- fprintf(stderr, "%s:%d " fmt, __func__, __LINE__, ## __VA_ARGS__)
-#else
-# define MSI_DPRINTF(fmt, ...) do { } while (0)
-#endif
-#define MSI_DEV_PRINTF(dev, fmt, ...) \
- MSI_DPRINTF("%s:%x " fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__)
-
-static inline unsigned int msi_nr_vectors(uint16_t flags)
-{
- return 1U <<
- ((flags & PCI_MSI_FLAGS_QSIZE) >> ctz32(PCI_MSI_FLAGS_QSIZE));
-}
-
-static inline uint8_t msi_flags_off(const PCIDevice* dev)
-{
- return dev->msi_cap + PCI_MSI_FLAGS;
-}
-
-static inline uint8_t msi_address_lo_off(const PCIDevice* dev)
-{
- return dev->msi_cap + PCI_MSI_ADDRESS_LO;
-}
-
-static inline uint8_t msi_address_hi_off(const PCIDevice* dev)
-{
- return dev->msi_cap + PCI_MSI_ADDRESS_HI;
-}
-
-static inline uint8_t msi_data_off(const PCIDevice* dev, bool msi64bit)
-{
- return dev->msi_cap + (msi64bit ? PCI_MSI_DATA_64 : PCI_MSI_DATA_32);
-}
-
-static inline uint8_t msi_mask_off(const PCIDevice* dev, bool msi64bit)
-{
- return dev->msi_cap + (msi64bit ? PCI_MSI_MASK_64 : PCI_MSI_MASK_32);
-}
-
-static inline uint8_t msi_pending_off(const PCIDevice* dev, bool msi64bit)
-{
- return dev->msi_cap + (msi64bit ? PCI_MSI_PENDING_64 : PCI_MSI_PENDING_32);
-}
-
-/*
- * Special API for POWER to configure the vectors through
- * a side channel. Should never be used by devices.
- */
-void msi_set_message(PCIDevice *dev, MSIMessage msg)
-{
- uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
- bool msi64bit = flags & PCI_MSI_FLAGS_64BIT;
-
- if (msi64bit) {
- pci_set_quad(dev->config + msi_address_lo_off(dev), msg.address);
- } else {
- pci_set_long(dev->config + msi_address_lo_off(dev), msg.address);
- }
- pci_set_word(dev->config + msi_data_off(dev, msi64bit), msg.data);
-}
-
-MSIMessage msi_get_message(PCIDevice *dev, unsigned int vector)
-{
- uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
- bool msi64bit = flags & PCI_MSI_FLAGS_64BIT;
- unsigned int nr_vectors = msi_nr_vectors(flags);
- MSIMessage msg;
-
- assert(vector < nr_vectors);
-
- if (msi64bit) {
- msg.address = pci_get_quad(dev->config + msi_address_lo_off(dev));
- } else {
- msg.address = pci_get_long(dev->config + msi_address_lo_off(dev));
- }
-
- /* upper bit 31:16 is zero */
- msg.data = pci_get_word(dev->config + msi_data_off(dev, msi64bit));
- if (nr_vectors > 1) {
- msg.data &= ~(nr_vectors - 1);
- msg.data |= vector;
- }
-
- return msg;
-}
-
-bool msi_enabled(const PCIDevice *dev)
-{
- return msi_present(dev) &&
- (pci_get_word(dev->config + msi_flags_off(dev)) &
- PCI_MSI_FLAGS_ENABLE);
-}
-
-int msi_init(struct PCIDevice *dev, uint8_t offset,
- unsigned int nr_vectors, bool msi64bit, bool msi_per_vector_mask)
-{
- unsigned int vectors_order;
- uint16_t flags;
- uint8_t cap_size;
- int config_offset;
-
- if (!msi_nonbroken) {
- return -ENOTSUP;
- }
-
- MSI_DEV_PRINTF(dev,
- "init offset: 0x%"PRIx8" vector: %"PRId8
- " 64bit %d mask %d\n",
- offset, nr_vectors, msi64bit, msi_per_vector_mask);
-
- assert(!(nr_vectors & (nr_vectors - 1))); /* power of 2 */
- assert(nr_vectors > 0);
- assert(nr_vectors <= PCI_MSI_VECTORS_MAX);
- /* the nr of MSI vectors is up to 32 */
- vectors_order = ctz32(nr_vectors);
-
- flags = vectors_order << ctz32(PCI_MSI_FLAGS_QMASK);
- if (msi64bit) {
- flags |= PCI_MSI_FLAGS_64BIT;
- }
- if (msi_per_vector_mask) {
- flags |= PCI_MSI_FLAGS_MASKBIT;
- }
-
- cap_size = msi_cap_sizeof(flags);
- config_offset = pci_add_capability(dev, PCI_CAP_ID_MSI, offset, cap_size);
- if (config_offset < 0) {
- return config_offset;
- }
-
- dev->msi_cap = config_offset;
- dev->cap_present |= QEMU_PCI_CAP_MSI;
-
- pci_set_word(dev->config + msi_flags_off(dev), flags);
- pci_set_word(dev->wmask + msi_flags_off(dev),
- PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE);
- pci_set_long(dev->wmask + msi_address_lo_off(dev),
- PCI_MSI_ADDRESS_LO_MASK);
- if (msi64bit) {
- pci_set_long(dev->wmask + msi_address_hi_off(dev), 0xffffffff);
- }
- pci_set_word(dev->wmask + msi_data_off(dev, msi64bit), 0xffff);
-
- if (msi_per_vector_mask) {
- /* Make mask bits 0 to nr_vectors - 1 writable. */
- pci_set_long(dev->wmask + msi_mask_off(dev, msi64bit),
- 0xffffffff >> (PCI_MSI_VECTORS_MAX - nr_vectors));
- }
- return config_offset;
-}
-
-void msi_uninit(struct PCIDevice *dev)
-{
- uint16_t flags;
- uint8_t cap_size;
-
- if (!msi_present(dev)) {
- return;
- }
- flags = pci_get_word(dev->config + msi_flags_off(dev));
- cap_size = msi_cap_sizeof(flags);
- pci_del_capability(dev, PCI_CAP_ID_MSI, cap_size);
- dev->cap_present &= ~QEMU_PCI_CAP_MSI;
-
- MSI_DEV_PRINTF(dev, "uninit\n");
-}
-
-void msi_reset(PCIDevice *dev)
-{
- uint16_t flags;
- bool msi64bit;
-
- if (!msi_present(dev)) {
- return;
- }
-
- flags = pci_get_word(dev->config + msi_flags_off(dev));
- flags &= ~(PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE);
- msi64bit = flags & PCI_MSI_FLAGS_64BIT;
-
- pci_set_word(dev->config + msi_flags_off(dev), flags);
- pci_set_long(dev->config + msi_address_lo_off(dev), 0);
- if (msi64bit) {
- pci_set_long(dev->config + msi_address_hi_off(dev), 0);
- }
- pci_set_word(dev->config + msi_data_off(dev, msi64bit), 0);
- if (flags & PCI_MSI_FLAGS_MASKBIT) {
- pci_set_long(dev->config + msi_mask_off(dev, msi64bit), 0);
- pci_set_long(dev->config + msi_pending_off(dev, msi64bit), 0);
- }
- MSI_DEV_PRINTF(dev, "reset\n");
-}
-
-static bool msi_is_masked(const PCIDevice *dev, unsigned int vector)
-{
- uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
- uint32_t mask, data;
- bool msi64bit = flags & PCI_MSI_FLAGS_64BIT;
- assert(vector < PCI_MSI_VECTORS_MAX);
-
- if (!(flags & PCI_MSI_FLAGS_MASKBIT)) {
- return false;
- }
-
- data = pci_get_word(dev->config + msi_data_off(dev, msi64bit));
- if (xen_is_pirq_msi(data)) {
- return false;
- }
-
- mask = pci_get_long(dev->config +
- msi_mask_off(dev, flags & PCI_MSI_FLAGS_64BIT));
- return mask & (1U << vector);
-}
-
-void msi_notify(PCIDevice *dev, unsigned int vector)
-{
- uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
- bool msi64bit = flags & PCI_MSI_FLAGS_64BIT;
- unsigned int nr_vectors = msi_nr_vectors(flags);
- MSIMessage msg;
-
- assert(vector < nr_vectors);
- if (msi_is_masked(dev, vector)) {
- assert(flags & PCI_MSI_FLAGS_MASKBIT);
- pci_long_test_and_set_mask(
- dev->config + msi_pending_off(dev, msi64bit), 1U << vector);
- MSI_DEV_PRINTF(dev, "pending vector 0x%x\n", vector);
- return;
- }
-
- msg = msi_get_message(dev, vector);
-
- MSI_DEV_PRINTF(dev,
- "notify vector 0x%x"
- " address: 0x%"PRIx64" data: 0x%"PRIx32"\n",
- vector, msg.address, msg.data);
- msi_send_message(dev, msg);
-}
-
-void msi_send_message(PCIDevice *dev, MSIMessage msg)
-{
- MemTxAttrs attrs = {};
-
- attrs.requester_id = pci_requester_id(dev);
- address_space_stl_le(&dev->bus_master_as, msg.address, msg.data,
- attrs, NULL);
-}
-
-/* Normally called by pci_default_write_config(). */
-void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len)
-{
- uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
- bool msi64bit = flags & PCI_MSI_FLAGS_64BIT;
- bool msi_per_vector_mask = flags & PCI_MSI_FLAGS_MASKBIT;
- unsigned int nr_vectors;
- uint8_t log_num_vecs;
- uint8_t log_max_vecs;
- unsigned int vector;
- uint32_t pending;
-
- if (!msi_present(dev) ||
- !ranges_overlap(addr, len, dev->msi_cap, msi_cap_sizeof(flags))) {
- return;
- }
-
-#ifdef MSI_DEBUG
- MSI_DEV_PRINTF(dev, "addr 0x%"PRIx32" val 0x%"PRIx32" len %d\n",
- addr, val, len);
- MSI_DEV_PRINTF(dev, "ctrl: 0x%"PRIx16" address: 0x%"PRIx32,
- flags,
- pci_get_long(dev->config + msi_address_lo_off(dev)));
- if (msi64bit) {
- fprintf(stderr, " address-hi: 0x%"PRIx32,
- pci_get_long(dev->config + msi_address_hi_off(dev)));
- }
- fprintf(stderr, " data: 0x%"PRIx16,
- pci_get_word(dev->config + msi_data_off(dev, msi64bit)));
- if (flags & PCI_MSI_FLAGS_MASKBIT) {
- fprintf(stderr, " mask 0x%"PRIx32" pending 0x%"PRIx32,
- pci_get_long(dev->config + msi_mask_off(dev, msi64bit)),
- pci_get_long(dev->config + msi_pending_off(dev, msi64bit)));
- }
- fprintf(stderr, "\n");
-#endif
-
- if (!(flags & PCI_MSI_FLAGS_ENABLE)) {
- return;
- }
-
- /*
- * Now MSI is enabled, clear INTx# interrupts.
- * the driver is prohibited from writing enable bit to mask
- * a service request. But the guest OS could do this.
- * So we just discard the interrupts as moderate fallback.
- *
- * 6.8.3.3. Enabling Operation
- * While enabled for MSI or MSI-X operation, a function is prohibited
- * from using its INTx# pin (if implemented) to request
- * service (MSI, MSI-X, and INTx# are mutually exclusive).
- */
- pci_device_deassert_intx(dev);
-
- /*
- * nr_vectors might be set bigger than capable. So clamp it.
- * This is not legal by spec, so we can do anything we like,
- * just don't crash the host
- */
- log_num_vecs =
- (flags & PCI_MSI_FLAGS_QSIZE) >> ctz32(PCI_MSI_FLAGS_QSIZE);
- log_max_vecs =
- (flags & PCI_MSI_FLAGS_QMASK) >> ctz32(PCI_MSI_FLAGS_QMASK);
- if (log_num_vecs > log_max_vecs) {
- flags &= ~PCI_MSI_FLAGS_QSIZE;
- flags |= log_max_vecs << ctz32(PCI_MSI_FLAGS_QSIZE);
- pci_set_word(dev->config + msi_flags_off(dev), flags);
- }
-
- if (!msi_per_vector_mask) {
- /* if per vector masking isn't supported,
- there is no pending interrupt. */
- return;
- }
-
- nr_vectors = msi_nr_vectors(flags);
-
- /* This will discard pending interrupts, if any. */
- pending = pci_get_long(dev->config + msi_pending_off(dev, msi64bit));
- pending &= 0xffffffff >> (PCI_MSI_VECTORS_MAX - nr_vectors);
- pci_set_long(dev->config + msi_pending_off(dev, msi64bit), pending);
-
- /* deliver pending interrupts which are unmasked */
- for (vector = 0; vector < nr_vectors; ++vector) {
- if (msi_is_masked(dev, vector) || !(pending & (1U << vector))) {
- continue;
- }
-
- pci_long_test_and_clear_mask(
- dev->config + msi_pending_off(dev, msi64bit), 1U << vector);
- msi_notify(dev, vector);
- }
-}
-
-unsigned int msi_nr_vectors_allocated(const PCIDevice *dev)
-{
- uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
- return msi_nr_vectors(flags);
-}
diff --git a/qemu/hw/pci/msix.c b/qemu/hw/pci/msix.c
deleted file mode 100644
index b75f0e9c4..000000000
--- a/qemu/hw/pci/msix.c
+++ /dev/null
@@ -1,621 +0,0 @@
-/*
- * MSI-X device support
- *
- * This module includes support for MSI-X in pci devices.
- *
- * Author: Michael S. Tsirkin <mst@redhat.com>
- *
- * Copyright (c) 2009, Red Hat Inc, Michael S. Tsirkin (mst@redhat.com)
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/pci/msi.h"
-#include "hw/pci/msix.h"
-#include "hw/pci/pci.h"
-#include "hw/xen/xen.h"
-#include "qemu/range.h"
-
-#define MSIX_CAP_LENGTH 12
-
-/* MSI enable bit and maskall bit are in byte 1 in FLAGS register */
-#define MSIX_CONTROL_OFFSET (PCI_MSIX_FLAGS + 1)
-#define MSIX_ENABLE_MASK (PCI_MSIX_FLAGS_ENABLE >> 8)
-#define MSIX_MASKALL_MASK (PCI_MSIX_FLAGS_MASKALL >> 8)
-
-MSIMessage msix_get_message(PCIDevice *dev, unsigned vector)
-{
- uint8_t *table_entry = dev->msix_table + vector * PCI_MSIX_ENTRY_SIZE;
- MSIMessage msg;
-
- msg.address = pci_get_quad(table_entry + PCI_MSIX_ENTRY_LOWER_ADDR);
- msg.data = pci_get_long(table_entry + PCI_MSIX_ENTRY_DATA);
- return msg;
-}
-
-/*
- * Special API for POWER to configure the vectors through
- * a side channel. Should never be used by devices.
- */
-void msix_set_message(PCIDevice *dev, int vector, struct MSIMessage msg)
-{
- uint8_t *table_entry = dev->msix_table + vector * PCI_MSIX_ENTRY_SIZE;
-
- pci_set_quad(table_entry + PCI_MSIX_ENTRY_LOWER_ADDR, msg.address);
- pci_set_long(table_entry + PCI_MSIX_ENTRY_DATA, msg.data);
- table_entry[PCI_MSIX_ENTRY_VECTOR_CTRL] &= ~PCI_MSIX_ENTRY_CTRL_MASKBIT;
-}
-
-static uint8_t msix_pending_mask(int vector)
-{
- return 1 << (vector % 8);
-}
-
-static uint8_t *msix_pending_byte(PCIDevice *dev, int vector)
-{
- return dev->msix_pba + vector / 8;
-}
-
-static int msix_is_pending(PCIDevice *dev, int vector)
-{
- return *msix_pending_byte(dev, vector) & msix_pending_mask(vector);
-}
-
-void msix_set_pending(PCIDevice *dev, unsigned int vector)
-{
- *msix_pending_byte(dev, vector) |= msix_pending_mask(vector);
-}
-
-static void msix_clr_pending(PCIDevice *dev, int vector)
-{
- *msix_pending_byte(dev, vector) &= ~msix_pending_mask(vector);
-}
-
-static bool msix_vector_masked(PCIDevice *dev, unsigned int vector, bool fmask)
-{
- unsigned offset = vector * PCI_MSIX_ENTRY_SIZE;
- uint8_t *data = &dev->msix_table[offset + PCI_MSIX_ENTRY_DATA];
- /* MSIs on Xen can be remapped into pirqs. In those cases, masking
- * and unmasking go through the PV evtchn path. */
- if (xen_enabled() && xen_is_pirq_msi(pci_get_long(data))) {
- return false;
- }
- return fmask || dev->msix_table[offset + PCI_MSIX_ENTRY_VECTOR_CTRL] &
- PCI_MSIX_ENTRY_CTRL_MASKBIT;
-}
-
-bool msix_is_masked(PCIDevice *dev, unsigned int vector)
-{
- return msix_vector_masked(dev, vector, dev->msix_function_masked);
-}
-
-static void msix_fire_vector_notifier(PCIDevice *dev,
- unsigned int vector, bool is_masked)
-{
- MSIMessage msg;
- int ret;
-
- if (!dev->msix_vector_use_notifier) {
- return;
- }
- if (is_masked) {
- dev->msix_vector_release_notifier(dev, vector);
- } else {
- msg = msix_get_message(dev, vector);
- ret = dev->msix_vector_use_notifier(dev, vector, msg);
- assert(ret >= 0);
- }
-}
-
-static void msix_handle_mask_update(PCIDevice *dev, int vector, bool was_masked)
-{
- bool is_masked = msix_is_masked(dev, vector);
-
- if (is_masked == was_masked) {
- return;
- }
-
- msix_fire_vector_notifier(dev, vector, is_masked);
-
- if (!is_masked && msix_is_pending(dev, vector)) {
- msix_clr_pending(dev, vector);
- msix_notify(dev, vector);
- }
-}
-
-static void msix_update_function_masked(PCIDevice *dev)
-{
- dev->msix_function_masked = !msix_enabled(dev) ||
- (dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & MSIX_MASKALL_MASK);
-}
-
-/* Handle MSI-X capability config write. */
-void msix_write_config(PCIDevice *dev, uint32_t addr,
- uint32_t val, int len)
-{
- unsigned enable_pos = dev->msix_cap + MSIX_CONTROL_OFFSET;
- int vector;
- bool was_masked;
-
- if (!msix_present(dev) || !range_covers_byte(addr, len, enable_pos)) {
- return;
- }
-
- was_masked = dev->msix_function_masked;
- msix_update_function_masked(dev);
-
- if (!msix_enabled(dev)) {
- return;
- }
-
- pci_device_deassert_intx(dev);
-
- if (dev->msix_function_masked == was_masked) {
- return;
- }
-
- for (vector = 0; vector < dev->msix_entries_nr; ++vector) {
- msix_handle_mask_update(dev, vector,
- msix_vector_masked(dev, vector, was_masked));
- }
-}
-
-static uint64_t msix_table_mmio_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- PCIDevice *dev = opaque;
-
- return pci_get_long(dev->msix_table + addr);
-}
-
-static void msix_table_mmio_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- PCIDevice *dev = opaque;
- int vector = addr / PCI_MSIX_ENTRY_SIZE;
- bool was_masked;
-
- was_masked = msix_is_masked(dev, vector);
- pci_set_long(dev->msix_table + addr, val);
- msix_handle_mask_update(dev, vector, was_masked);
-}
-
-static const MemoryRegionOps msix_table_mmio_ops = {
- .read = msix_table_mmio_read,
- .write = msix_table_mmio_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static uint64_t msix_pba_mmio_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- PCIDevice *dev = opaque;
- if (dev->msix_vector_poll_notifier) {
- unsigned vector_start = addr * 8;
- unsigned vector_end = MIN(addr + size * 8, dev->msix_entries_nr);
- dev->msix_vector_poll_notifier(dev, vector_start, vector_end);
- }
-
- return pci_get_long(dev->msix_pba + addr);
-}
-
-static void msix_pba_mmio_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
-}
-
-static const MemoryRegionOps msix_pba_mmio_ops = {
- .read = msix_pba_mmio_read,
- .write = msix_pba_mmio_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static void msix_mask_all(struct PCIDevice *dev, unsigned nentries)
-{
- int vector;
-
- for (vector = 0; vector < nentries; ++vector) {
- unsigned offset =
- vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL;
- bool was_masked = msix_is_masked(dev, vector);
-
- dev->msix_table[offset] |= PCI_MSIX_ENTRY_CTRL_MASKBIT;
- msix_handle_mask_update(dev, vector, was_masked);
- }
-}
-
-/* Initialize the MSI-X structures */
-int msix_init(struct PCIDevice *dev, unsigned short nentries,
- MemoryRegion *table_bar, uint8_t table_bar_nr,
- unsigned table_offset, MemoryRegion *pba_bar,
- uint8_t pba_bar_nr, unsigned pba_offset, uint8_t cap_pos)
-{
- int cap;
- unsigned table_size, pba_size;
- uint8_t *config;
-
- /* Nothing to do if MSI is not supported by interrupt controller */
- if (!msi_nonbroken) {
- return -ENOTSUP;
- }
-
- if (nentries < 1 || nentries > PCI_MSIX_FLAGS_QSIZE + 1) {
- return -EINVAL;
- }
-
- table_size = nentries * PCI_MSIX_ENTRY_SIZE;
- pba_size = QEMU_ALIGN_UP(nentries, 64) / 8;
-
- /* Sanity test: table & pba don't overlap, fit within BARs, min aligned */
- if ((table_bar_nr == pba_bar_nr &&
- ranges_overlap(table_offset, table_size, pba_offset, pba_size)) ||
- table_offset + table_size > memory_region_size(table_bar) ||
- pba_offset + pba_size > memory_region_size(pba_bar) ||
- (table_offset | pba_offset) & PCI_MSIX_FLAGS_BIRMASK) {
- return -EINVAL;
- }
-
- cap = pci_add_capability(dev, PCI_CAP_ID_MSIX, cap_pos, MSIX_CAP_LENGTH);
- if (cap < 0) {
- return cap;
- }
-
- dev->msix_cap = cap;
- dev->cap_present |= QEMU_PCI_CAP_MSIX;
- config = dev->config + cap;
-
- pci_set_word(config + PCI_MSIX_FLAGS, nentries - 1);
- dev->msix_entries_nr = nentries;
- dev->msix_function_masked = true;
-
- pci_set_long(config + PCI_MSIX_TABLE, table_offset | table_bar_nr);
- pci_set_long(config + PCI_MSIX_PBA, pba_offset | pba_bar_nr);
-
- /* Make flags bit writable. */
- dev->wmask[cap + MSIX_CONTROL_OFFSET] |= MSIX_ENABLE_MASK |
- MSIX_MASKALL_MASK;
-
- dev->msix_table = g_malloc0(table_size);
- dev->msix_pba = g_malloc0(pba_size);
- dev->msix_entry_used = g_malloc0(nentries * sizeof *dev->msix_entry_used);
-
- msix_mask_all(dev, nentries);
-
- memory_region_init_io(&dev->msix_table_mmio, OBJECT(dev), &msix_table_mmio_ops, dev,
- "msix-table", table_size);
- memory_region_add_subregion(table_bar, table_offset, &dev->msix_table_mmio);
- memory_region_init_io(&dev->msix_pba_mmio, OBJECT(dev), &msix_pba_mmio_ops, dev,
- "msix-pba", pba_size);
- memory_region_add_subregion(pba_bar, pba_offset, &dev->msix_pba_mmio);
-
- return 0;
-}
-
-int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries,
- uint8_t bar_nr)
-{
- int ret;
- char *name;
- uint32_t bar_size = 4096;
- uint32_t bar_pba_offset = bar_size / 2;
- uint32_t bar_pba_size = (nentries / 8 + 1) * 8;
-
- /*
- * Migration compatibility dictates that this remains a 4k
- * BAR with the vector table in the lower half and PBA in
- * the upper half for nentries which is lower or equal to 128.
- * No need to care about using more than 65 entries for legacy
- * machine types who has at most 64 queues.
- */
- if (nentries * PCI_MSIX_ENTRY_SIZE > bar_pba_offset) {
- bar_pba_offset = nentries * PCI_MSIX_ENTRY_SIZE;
- }
-
- if (bar_pba_offset + bar_pba_size > 4096) {
- bar_size = bar_pba_offset + bar_pba_size;
- }
-
- bar_size = pow2ceil(bar_size);
-
- name = g_strdup_printf("%s-msix", dev->name);
- memory_region_init(&dev->msix_exclusive_bar, OBJECT(dev), name, bar_size);
- g_free(name);
-
- ret = msix_init(dev, nentries, &dev->msix_exclusive_bar, bar_nr,
- 0, &dev->msix_exclusive_bar,
- bar_nr, bar_pba_offset,
- 0);
- if (ret) {
- return ret;
- }
-
- pci_register_bar(dev, bar_nr, PCI_BASE_ADDRESS_SPACE_MEMORY,
- &dev->msix_exclusive_bar);
-
- return 0;
-}
-
-static void msix_free_irq_entries(PCIDevice *dev)
-{
- int vector;
-
- for (vector = 0; vector < dev->msix_entries_nr; ++vector) {
- dev->msix_entry_used[vector] = 0;
- msix_clr_pending(dev, vector);
- }
-}
-
-static void msix_clear_all_vectors(PCIDevice *dev)
-{
- int vector;
-
- for (vector = 0; vector < dev->msix_entries_nr; ++vector) {
- msix_clr_pending(dev, vector);
- }
-}
-
-/* Clean up resources for the device. */
-void msix_uninit(PCIDevice *dev, MemoryRegion *table_bar, MemoryRegion *pba_bar)
-{
- if (!msix_present(dev)) {
- return;
- }
- pci_del_capability(dev, PCI_CAP_ID_MSIX, MSIX_CAP_LENGTH);
- dev->msix_cap = 0;
- msix_free_irq_entries(dev);
- dev->msix_entries_nr = 0;
- memory_region_del_subregion(pba_bar, &dev->msix_pba_mmio);
- g_free(dev->msix_pba);
- dev->msix_pba = NULL;
- memory_region_del_subregion(table_bar, &dev->msix_table_mmio);
- g_free(dev->msix_table);
- dev->msix_table = NULL;
- g_free(dev->msix_entry_used);
- dev->msix_entry_used = NULL;
- dev->cap_present &= ~QEMU_PCI_CAP_MSIX;
-}
-
-void msix_uninit_exclusive_bar(PCIDevice *dev)
-{
- if (msix_present(dev)) {
- msix_uninit(dev, &dev->msix_exclusive_bar, &dev->msix_exclusive_bar);
- }
-}
-
-void msix_save(PCIDevice *dev, QEMUFile *f)
-{
- unsigned n = dev->msix_entries_nr;
-
- if (!msix_present(dev)) {
- return;
- }
-
- qemu_put_buffer(f, dev->msix_table, n * PCI_MSIX_ENTRY_SIZE);
- qemu_put_buffer(f, dev->msix_pba, (n + 7) / 8);
-}
-
-/* Should be called after restoring the config space. */
-void msix_load(PCIDevice *dev, QEMUFile *f)
-{
- unsigned n = dev->msix_entries_nr;
- unsigned int vector;
-
- if (!msix_present(dev)) {
- return;
- }
-
- msix_clear_all_vectors(dev);
- qemu_get_buffer(f, dev->msix_table, n * PCI_MSIX_ENTRY_SIZE);
- qemu_get_buffer(f, dev->msix_pba, (n + 7) / 8);
- msix_update_function_masked(dev);
-
- for (vector = 0; vector < n; vector++) {
- msix_handle_mask_update(dev, vector, true);
- }
-}
-
-/* Does device support MSI-X? */
-int msix_present(PCIDevice *dev)
-{
- return dev->cap_present & QEMU_PCI_CAP_MSIX;
-}
-
-/* Is MSI-X enabled? */
-int msix_enabled(PCIDevice *dev)
-{
- return (dev->cap_present & QEMU_PCI_CAP_MSIX) &&
- (dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &
- MSIX_ENABLE_MASK);
-}
-
-/* Send an MSI-X message */
-void msix_notify(PCIDevice *dev, unsigned vector)
-{
- MSIMessage msg;
-
- if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector])
- return;
- if (msix_is_masked(dev, vector)) {
- msix_set_pending(dev, vector);
- return;
- }
-
- msg = msix_get_message(dev, vector);
-
- msi_send_message(dev, msg);
-}
-
-void msix_reset(PCIDevice *dev)
-{
- if (!msix_present(dev)) {
- return;
- }
- msix_clear_all_vectors(dev);
- dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &=
- ~dev->wmask[dev->msix_cap + MSIX_CONTROL_OFFSET];
- memset(dev->msix_table, 0, dev->msix_entries_nr * PCI_MSIX_ENTRY_SIZE);
- memset(dev->msix_pba, 0, QEMU_ALIGN_UP(dev->msix_entries_nr, 64) / 8);
- msix_mask_all(dev, dev->msix_entries_nr);
-}
-
-/* PCI spec suggests that devices make it possible for software to configure
- * less vectors than supported by the device, but does not specify a standard
- * mechanism for devices to do so.
- *
- * We support this by asking devices to declare vectors software is going to
- * actually use, and checking this on the notification path. Devices that
- * don't want to follow the spec suggestion can declare all vectors as used. */
-
-/* Mark vector as used. */
-int msix_vector_use(PCIDevice *dev, unsigned vector)
-{
- if (vector >= dev->msix_entries_nr)
- return -EINVAL;
- dev->msix_entry_used[vector]++;
- return 0;
-}
-
-/* Mark vector as unused. */
-void msix_vector_unuse(PCIDevice *dev, unsigned vector)
-{
- if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector]) {
- return;
- }
- if (--dev->msix_entry_used[vector]) {
- return;
- }
- msix_clr_pending(dev, vector);
-}
-
-void msix_unuse_all_vectors(PCIDevice *dev)
-{
- if (!msix_present(dev)) {
- return;
- }
- msix_free_irq_entries(dev);
-}
-
-unsigned int msix_nr_vectors_allocated(const PCIDevice *dev)
-{
- return dev->msix_entries_nr;
-}
-
-static int msix_set_notifier_for_vector(PCIDevice *dev, unsigned int vector)
-{
- MSIMessage msg;
-
- if (msix_is_masked(dev, vector)) {
- return 0;
- }
- msg = msix_get_message(dev, vector);
- return dev->msix_vector_use_notifier(dev, vector, msg);
-}
-
-static void msix_unset_notifier_for_vector(PCIDevice *dev, unsigned int vector)
-{
- if (msix_is_masked(dev, vector)) {
- return;
- }
- dev->msix_vector_release_notifier(dev, vector);
-}
-
-int msix_set_vector_notifiers(PCIDevice *dev,
- MSIVectorUseNotifier use_notifier,
- MSIVectorReleaseNotifier release_notifier,
- MSIVectorPollNotifier poll_notifier)
-{
- int vector, ret;
-
- assert(use_notifier && release_notifier);
-
- dev->msix_vector_use_notifier = use_notifier;
- dev->msix_vector_release_notifier = release_notifier;
- dev->msix_vector_poll_notifier = poll_notifier;
-
- if ((dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &
- (MSIX_ENABLE_MASK | MSIX_MASKALL_MASK)) == MSIX_ENABLE_MASK) {
- for (vector = 0; vector < dev->msix_entries_nr; vector++) {
- ret = msix_set_notifier_for_vector(dev, vector);
- if (ret < 0) {
- goto undo;
- }
- }
- }
- if (dev->msix_vector_poll_notifier) {
- dev->msix_vector_poll_notifier(dev, 0, dev->msix_entries_nr);
- }
- return 0;
-
-undo:
- while (--vector >= 0) {
- msix_unset_notifier_for_vector(dev, vector);
- }
- dev->msix_vector_use_notifier = NULL;
- dev->msix_vector_release_notifier = NULL;
- return ret;
-}
-
-void msix_unset_vector_notifiers(PCIDevice *dev)
-{
- int vector;
-
- assert(dev->msix_vector_use_notifier &&
- dev->msix_vector_release_notifier);
-
- if ((dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &
- (MSIX_ENABLE_MASK | MSIX_MASKALL_MASK)) == MSIX_ENABLE_MASK) {
- for (vector = 0; vector < dev->msix_entries_nr; vector++) {
- msix_unset_notifier_for_vector(dev, vector);
- }
- }
- dev->msix_vector_use_notifier = NULL;
- dev->msix_vector_release_notifier = NULL;
- dev->msix_vector_poll_notifier = NULL;
-}
-
-static void put_msix_state(QEMUFile *f, void *pv, size_t size)
-{
- msix_save(pv, f);
-}
-
-static int get_msix_state(QEMUFile *f, void *pv, size_t size)
-{
- msix_load(pv, f);
- return 0;
-}
-
-static VMStateInfo vmstate_info_msix = {
- .name = "msix state",
- .get = get_msix_state,
- .put = put_msix_state,
-};
-
-const VMStateDescription vmstate_msix = {
- .name = "msix",
- .fields = (VMStateField[]) {
- {
- .name = "msix",
- .version_id = 0,
- .field_exists = NULL,
- .size = 0, /* ouch */
- .info = &vmstate_info_msix,
- .flags = VMS_SINGLE,
- .offset = 0,
- },
- VMSTATE_END_OF_LIST()
- }
-};
diff --git a/qemu/hw/pci/pci-stub.c b/qemu/hw/pci/pci-stub.c
deleted file mode 100644
index 36d2c430c..000000000
--- a/qemu/hw/pci/pci-stub.c
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * PCI stubs for platforms that don't support pci bus.
- *
- * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
- * VA Linux Systems Japan K.K.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "sysemu/sysemu.h"
-#include "monitor/monitor.h"
-#include "qapi/qmp/qerror.h"
-#include "hw/pci/pci.h"
-#include "qmp-commands.h"
-
-PciInfoList *qmp_query_pci(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
-
-void hmp_pcie_aer_inject_error(Monitor *mon, const QDict *qdict)
-{
- monitor_printf(mon, "PCI devices not supported\n");
-}
diff --git a/qemu/hw/pci/pci.c b/qemu/hw/pci/pci.c
deleted file mode 100644
index bb605efae..000000000
--- a/qemu/hw/pci/pci.c
+++ /dev/null
@@ -1,2517 +0,0 @@
-/*
- * QEMU PCI bus manager
- *
- * Copyright (c) 2004 Fabrice Bellard
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/pci_bridge.h"
-#include "hw/pci/pci_bus.h"
-#include "hw/pci/pci_host.h"
-#include "monitor/monitor.h"
-#include "net/net.h"
-#include "sysemu/sysemu.h"
-#include "hw/loader.h"
-#include "qemu/error-report.h"
-#include "qemu/range.h"
-#include "qmp-commands.h"
-#include "trace.h"
-#include "hw/pci/msi.h"
-#include "hw/pci/msix.h"
-#include "exec/address-spaces.h"
-#include "hw/hotplug.h"
-#include "hw/boards.h"
-#include "qemu/cutils.h"
-
-//#define DEBUG_PCI
-#ifdef DEBUG_PCI
-# define PCI_DPRINTF(format, ...) printf(format, ## __VA_ARGS__)
-#else
-# define PCI_DPRINTF(format, ...) do { } while (0)
-#endif
-
-static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent);
-static char *pcibus_get_dev_path(DeviceState *dev);
-static char *pcibus_get_fw_dev_path(DeviceState *dev);
-static void pcibus_reset(BusState *qbus);
-
-static Property pci_props[] = {
- DEFINE_PROP_PCI_DEVFN("addr", PCIDevice, devfn, -1),
- DEFINE_PROP_STRING("romfile", PCIDevice, romfile),
- DEFINE_PROP_UINT32("rombar", PCIDevice, rom_bar, 1),
- DEFINE_PROP_BIT("multifunction", PCIDevice, cap_present,
- QEMU_PCI_CAP_MULTIFUNCTION_BITNR, false),
- DEFINE_PROP_BIT("command_serr_enable", PCIDevice, cap_present,
- QEMU_PCI_CAP_SERR_BITNR, true),
- DEFINE_PROP_END_OF_LIST()
-};
-
-static const VMStateDescription vmstate_pcibus = {
- .name = "PCIBUS",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_INT32_EQUAL(nirq, PCIBus),
- VMSTATE_VARRAY_INT32(irq_count, PCIBus,
- nirq, 0, vmstate_info_int32,
- int32_t),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void pci_bus_realize(BusState *qbus, Error **errp)
-{
- PCIBus *bus = PCI_BUS(qbus);
-
- vmstate_register(NULL, -1, &vmstate_pcibus, bus);
-}
-
-static void pci_bus_unrealize(BusState *qbus, Error **errp)
-{
- PCIBus *bus = PCI_BUS(qbus);
-
- vmstate_unregister(NULL, &vmstate_pcibus, bus);
-}
-
-static bool pcibus_is_root(PCIBus *bus)
-{
- return !bus->parent_dev;
-}
-
-static int pcibus_num(PCIBus *bus)
-{
- if (pcibus_is_root(bus)) {
- return 0; /* pci host bridge */
- }
- return bus->parent_dev->config[PCI_SECONDARY_BUS];
-}
-
-static uint16_t pcibus_numa_node(PCIBus *bus)
-{
- return NUMA_NODE_UNASSIGNED;
-}
-
-static void pci_bus_class_init(ObjectClass *klass, void *data)
-{
- BusClass *k = BUS_CLASS(klass);
- PCIBusClass *pbc = PCI_BUS_CLASS(klass);
-
- k->print_dev = pcibus_dev_print;
- k->get_dev_path = pcibus_get_dev_path;
- k->get_fw_dev_path = pcibus_get_fw_dev_path;
- k->realize = pci_bus_realize;
- k->unrealize = pci_bus_unrealize;
- k->reset = pcibus_reset;
-
- pbc->is_root = pcibus_is_root;
- pbc->bus_num = pcibus_num;
- pbc->numa_node = pcibus_numa_node;
-}
-
-static const TypeInfo pci_bus_info = {
- .name = TYPE_PCI_BUS,
- .parent = TYPE_BUS,
- .instance_size = sizeof(PCIBus),
- .class_size = sizeof(PCIBusClass),
- .class_init = pci_bus_class_init,
-};
-
-static const TypeInfo pcie_bus_info = {
- .name = TYPE_PCIE_BUS,
- .parent = TYPE_PCI_BUS,
-};
-
-static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num);
-static void pci_update_mappings(PCIDevice *d);
-static void pci_irq_handler(void *opaque, int irq_num, int level);
-static void pci_add_option_rom(PCIDevice *pdev, bool is_default_rom, Error **);
-static void pci_del_option_rom(PCIDevice *pdev);
-
-static uint16_t pci_default_sub_vendor_id = PCI_SUBVENDOR_ID_REDHAT_QUMRANET;
-static uint16_t pci_default_sub_device_id = PCI_SUBDEVICE_ID_QEMU;
-
-static QLIST_HEAD(, PCIHostState) pci_host_bridges;
-
-int pci_bar(PCIDevice *d, int reg)
-{
- uint8_t type;
-
- if (reg != PCI_ROM_SLOT)
- return PCI_BASE_ADDRESS_0 + reg * 4;
-
- type = d->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION;
- return type == PCI_HEADER_TYPE_BRIDGE ? PCI_ROM_ADDRESS1 : PCI_ROM_ADDRESS;
-}
-
-static inline int pci_irq_state(PCIDevice *d, int irq_num)
-{
- return (d->irq_state >> irq_num) & 0x1;
-}
-
-static inline void pci_set_irq_state(PCIDevice *d, int irq_num, int level)
-{
- d->irq_state &= ~(0x1 << irq_num);
- d->irq_state |= level << irq_num;
-}
-
-static void pci_change_irq_level(PCIDevice *pci_dev, int irq_num, int change)
-{
- PCIBus *bus;
- for (;;) {
- bus = pci_dev->bus;
- irq_num = bus->map_irq(pci_dev, irq_num);
- if (bus->set_irq)
- break;
- pci_dev = bus->parent_dev;
- }
- bus->irq_count[irq_num] += change;
- bus->set_irq(bus->irq_opaque, irq_num, bus->irq_count[irq_num] != 0);
-}
-
-int pci_bus_get_irq_level(PCIBus *bus, int irq_num)
-{
- assert(irq_num >= 0);
- assert(irq_num < bus->nirq);
- return !!bus->irq_count[irq_num];
-}
-
-/* Update interrupt status bit in config space on interrupt
- * state change. */
-static void pci_update_irq_status(PCIDevice *dev)
-{
- if (dev->irq_state) {
- dev->config[PCI_STATUS] |= PCI_STATUS_INTERRUPT;
- } else {
- dev->config[PCI_STATUS] &= ~PCI_STATUS_INTERRUPT;
- }
-}
-
-void pci_device_deassert_intx(PCIDevice *dev)
-{
- int i;
- for (i = 0; i < PCI_NUM_PINS; ++i) {
- pci_irq_handler(dev, i, 0);
- }
-}
-
-static void pci_do_device_reset(PCIDevice *dev)
-{
- int r;
-
- pci_device_deassert_intx(dev);
- assert(dev->irq_state == 0);
-
- /* Clear all writable bits */
- pci_word_test_and_clear_mask(dev->config + PCI_COMMAND,
- pci_get_word(dev->wmask + PCI_COMMAND) |
- pci_get_word(dev->w1cmask + PCI_COMMAND));
- pci_word_test_and_clear_mask(dev->config + PCI_STATUS,
- pci_get_word(dev->wmask + PCI_STATUS) |
- pci_get_word(dev->w1cmask + PCI_STATUS));
- dev->config[PCI_CACHE_LINE_SIZE] = 0x0;
- dev->config[PCI_INTERRUPT_LINE] = 0x0;
- for (r = 0; r < PCI_NUM_REGIONS; ++r) {
- PCIIORegion *region = &dev->io_regions[r];
- if (!region->size) {
- continue;
- }
-
- if (!(region->type & PCI_BASE_ADDRESS_SPACE_IO) &&
- region->type & PCI_BASE_ADDRESS_MEM_TYPE_64) {
- pci_set_quad(dev->config + pci_bar(dev, r), region->type);
- } else {
- pci_set_long(dev->config + pci_bar(dev, r), region->type);
- }
- }
- pci_update_mappings(dev);
-
- msi_reset(dev);
- msix_reset(dev);
-}
-
-/*
- * This function is called on #RST and FLR.
- * FLR if PCI_EXP_DEVCTL_BCR_FLR is set
- */
-void pci_device_reset(PCIDevice *dev)
-{
- qdev_reset_all(&dev->qdev);
- pci_do_device_reset(dev);
-}
-
-/*
- * Trigger pci bus reset under a given bus.
- * Called via qbus_reset_all on RST# assert, after the devices
- * have been reset qdev_reset_all-ed already.
- */
-static void pcibus_reset(BusState *qbus)
-{
- PCIBus *bus = DO_UPCAST(PCIBus, qbus, qbus);
- int i;
-
- for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) {
- if (bus->devices[i]) {
- pci_do_device_reset(bus->devices[i]);
- }
- }
-
- for (i = 0; i < bus->nirq; i++) {
- assert(bus->irq_count[i] == 0);
- }
-}
-
-static void pci_host_bus_register(DeviceState *host)
-{
- PCIHostState *host_bridge = PCI_HOST_BRIDGE(host);
-
- QLIST_INSERT_HEAD(&pci_host_bridges, host_bridge, next);
-}
-
-PCIBus *pci_find_primary_bus(void)
-{
- PCIBus *primary_bus = NULL;
- PCIHostState *host;
-
- QLIST_FOREACH(host, &pci_host_bridges, next) {
- if (primary_bus) {
- /* We have multiple root buses, refuse to select a primary */
- return NULL;
- }
- primary_bus = host->bus;
- }
-
- return primary_bus;
-}
-
-PCIBus *pci_device_root_bus(const PCIDevice *d)
-{
- PCIBus *bus = d->bus;
-
- while (!pci_bus_is_root(bus)) {
- d = bus->parent_dev;
- assert(d != NULL);
-
- bus = d->bus;
- }
-
- return bus;
-}
-
-const char *pci_root_bus_path(PCIDevice *dev)
-{
- PCIBus *rootbus = pci_device_root_bus(dev);
- PCIHostState *host_bridge = PCI_HOST_BRIDGE(rootbus->qbus.parent);
- PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_GET_CLASS(host_bridge);
-
- assert(host_bridge->bus == rootbus);
-
- if (hc->root_bus_path) {
- return (*hc->root_bus_path)(host_bridge, rootbus);
- }
-
- return rootbus->qbus.name;
-}
-
-static void pci_bus_init(PCIBus *bus, DeviceState *parent,
- MemoryRegion *address_space_mem,
- MemoryRegion *address_space_io,
- uint8_t devfn_min)
-{
- assert(PCI_FUNC(devfn_min) == 0);
- bus->devfn_min = devfn_min;
- bus->address_space_mem = address_space_mem;
- bus->address_space_io = address_space_io;
-
- /* host bridge */
- QLIST_INIT(&bus->child);
-
- pci_host_bus_register(parent);
-}
-
-bool pci_bus_is_express(PCIBus *bus)
-{
- return object_dynamic_cast(OBJECT(bus), TYPE_PCIE_BUS);
-}
-
-bool pci_bus_is_root(PCIBus *bus)
-{
- return PCI_BUS_GET_CLASS(bus)->is_root(bus);
-}
-
-void pci_bus_new_inplace(PCIBus *bus, size_t bus_size, DeviceState *parent,
- const char *name,
- MemoryRegion *address_space_mem,
- MemoryRegion *address_space_io,
- uint8_t devfn_min, const char *typename)
-{
- qbus_create_inplace(bus, bus_size, typename, parent, name);
- pci_bus_init(bus, parent, address_space_mem, address_space_io, devfn_min);
-}
-
-PCIBus *pci_bus_new(DeviceState *parent, const char *name,
- MemoryRegion *address_space_mem,
- MemoryRegion *address_space_io,
- uint8_t devfn_min, const char *typename)
-{
- PCIBus *bus;
-
- bus = PCI_BUS(qbus_create(typename, parent, name));
- pci_bus_init(bus, parent, address_space_mem, address_space_io, devfn_min);
- return bus;
-}
-
-void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
- void *irq_opaque, int nirq)
-{
- bus->set_irq = set_irq;
- bus->map_irq = map_irq;
- bus->irq_opaque = irq_opaque;
- bus->nirq = nirq;
- bus->irq_count = g_malloc0(nirq * sizeof(bus->irq_count[0]));
-}
-
-PCIBus *pci_register_bus(DeviceState *parent, const char *name,
- pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
- void *irq_opaque,
- MemoryRegion *address_space_mem,
- MemoryRegion *address_space_io,
- uint8_t devfn_min, int nirq, const char *typename)
-{
- PCIBus *bus;
-
- bus = pci_bus_new(parent, name, address_space_mem,
- address_space_io, devfn_min, typename);
- pci_bus_irqs(bus, set_irq, map_irq, irq_opaque, nirq);
- return bus;
-}
-
-int pci_bus_num(PCIBus *s)
-{
- return PCI_BUS_GET_CLASS(s)->bus_num(s);
-}
-
-int pci_bus_numa_node(PCIBus *bus)
-{
- return PCI_BUS_GET_CLASS(bus)->numa_node(bus);
-}
-
-static int get_pci_config_device(QEMUFile *f, void *pv, size_t size)
-{
- PCIDevice *s = container_of(pv, PCIDevice, config);
- PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(s);
- uint8_t *config;
- int i;
-
- assert(size == pci_config_size(s));
- config = g_malloc(size);
-
- qemu_get_buffer(f, config, size);
- for (i = 0; i < size; ++i) {
- if ((config[i] ^ s->config[i]) &
- s->cmask[i] & ~s->wmask[i] & ~s->w1cmask[i]) {
- error_report("%s: Bad config data: i=0x%x read: %x device: %x "
- "cmask: %x wmask: %x w1cmask:%x", __func__,
- i, config[i], s->config[i],
- s->cmask[i], s->wmask[i], s->w1cmask[i]);
- g_free(config);
- return -EINVAL;
- }
- }
- memcpy(s->config, config, size);
-
- pci_update_mappings(s);
- if (pc->is_bridge) {
- PCIBridge *b = PCI_BRIDGE(s);
- pci_bridge_update_mappings(b);
- }
-
- memory_region_set_enabled(&s->bus_master_enable_region,
- pci_get_word(s->config + PCI_COMMAND)
- & PCI_COMMAND_MASTER);
-
- g_free(config);
- return 0;
-}
-
-/* just put buffer */
-static void put_pci_config_device(QEMUFile *f, void *pv, size_t size)
-{
- const uint8_t **v = pv;
- assert(size == pci_config_size(container_of(pv, PCIDevice, config)));
- qemu_put_buffer(f, *v, size);
-}
-
-static VMStateInfo vmstate_info_pci_config = {
- .name = "pci config",
- .get = get_pci_config_device,
- .put = put_pci_config_device,
-};
-
-static int get_pci_irq_state(QEMUFile *f, void *pv, size_t size)
-{
- PCIDevice *s = container_of(pv, PCIDevice, irq_state);
- uint32_t irq_state[PCI_NUM_PINS];
- int i;
- for (i = 0; i < PCI_NUM_PINS; ++i) {
- irq_state[i] = qemu_get_be32(f);
- if (irq_state[i] != 0x1 && irq_state[i] != 0) {
- fprintf(stderr, "irq state %d: must be 0 or 1.\n",
- irq_state[i]);
- return -EINVAL;
- }
- }
-
- for (i = 0; i < PCI_NUM_PINS; ++i) {
- pci_set_irq_state(s, i, irq_state[i]);
- }
-
- return 0;
-}
-
-static void put_pci_irq_state(QEMUFile *f, void *pv, size_t size)
-{
- int i;
- PCIDevice *s = container_of(pv, PCIDevice, irq_state);
-
- for (i = 0; i < PCI_NUM_PINS; ++i) {
- qemu_put_be32(f, pci_irq_state(s, i));
- }
-}
-
-static VMStateInfo vmstate_info_pci_irq_state = {
- .name = "pci irq state",
- .get = get_pci_irq_state,
- .put = put_pci_irq_state,
-};
-
-const VMStateDescription vmstate_pci_device = {
- .name = "PCIDevice",
- .version_id = 2,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_INT32_POSITIVE_LE(version_id, PCIDevice),
- VMSTATE_BUFFER_UNSAFE_INFO(config, PCIDevice, 0,
- vmstate_info_pci_config,
- PCI_CONFIG_SPACE_SIZE),
- VMSTATE_BUFFER_UNSAFE_INFO(irq_state, PCIDevice, 2,
- vmstate_info_pci_irq_state,
- PCI_NUM_PINS * sizeof(int32_t)),
- VMSTATE_END_OF_LIST()
- }
-};
-
-const VMStateDescription vmstate_pcie_device = {
- .name = "PCIEDevice",
- .version_id = 2,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_INT32_POSITIVE_LE(version_id, PCIDevice),
- VMSTATE_BUFFER_UNSAFE_INFO(config, PCIDevice, 0,
- vmstate_info_pci_config,
- PCIE_CONFIG_SPACE_SIZE),
- VMSTATE_BUFFER_UNSAFE_INFO(irq_state, PCIDevice, 2,
- vmstate_info_pci_irq_state,
- PCI_NUM_PINS * sizeof(int32_t)),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static inline const VMStateDescription *pci_get_vmstate(PCIDevice *s)
-{
- return pci_is_express(s) ? &vmstate_pcie_device : &vmstate_pci_device;
-}
-
-void pci_device_save(PCIDevice *s, QEMUFile *f)
-{
- /* Clear interrupt status bit: it is implicit
- * in irq_state which we are saving.
- * This makes us compatible with old devices
- * which never set or clear this bit. */
- s->config[PCI_STATUS] &= ~PCI_STATUS_INTERRUPT;
- vmstate_save_state(f, pci_get_vmstate(s), s, NULL);
- /* Restore the interrupt status bit. */
- pci_update_irq_status(s);
-}
-
-int pci_device_load(PCIDevice *s, QEMUFile *f)
-{
- int ret;
- ret = vmstate_load_state(f, pci_get_vmstate(s), s, s->version_id);
- /* Restore the interrupt status bit. */
- pci_update_irq_status(s);
- return ret;
-}
-
-static void pci_set_default_subsystem_id(PCIDevice *pci_dev)
-{
- pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID,
- pci_default_sub_vendor_id);
- pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID,
- pci_default_sub_device_id);
-}
-
-/*
- * Parse [[<domain>:]<bus>:]<slot>, return -1 on error if funcp == NULL
- * [[<domain>:]<bus>:]<slot>.<func>, return -1 on error
- */
-static int pci_parse_devaddr(const char *addr, int *domp, int *busp,
- unsigned int *slotp, unsigned int *funcp)
-{
- const char *p;
- char *e;
- unsigned long val;
- unsigned long dom = 0, bus = 0;
- unsigned int slot = 0;
- unsigned int func = 0;
-
- p = addr;
- val = strtoul(p, &e, 16);
- if (e == p)
- return -1;
- if (*e == ':') {
- bus = val;
- p = e + 1;
- val = strtoul(p, &e, 16);
- if (e == p)
- return -1;
- if (*e == ':') {
- dom = bus;
- bus = val;
- p = e + 1;
- val = strtoul(p, &e, 16);
- if (e == p)
- return -1;
- }
- }
-
- slot = val;
-
- if (funcp != NULL) {
- if (*e != '.')
- return -1;
-
- p = e + 1;
- val = strtoul(p, &e, 16);
- if (e == p)
- return -1;
-
- func = val;
- }
-
- /* if funcp == NULL func is 0 */
- if (dom > 0xffff || bus > 0xff || slot > 0x1f || func > 7)
- return -1;
-
- if (*e)
- return -1;
-
- *domp = dom;
- *busp = bus;
- *slotp = slot;
- if (funcp != NULL)
- *funcp = func;
- return 0;
-}
-
-static PCIBus *pci_get_bus_devfn(int *devfnp, PCIBus *root,
- const char *devaddr)
-{
- int dom, bus;
- unsigned slot;
-
- if (!root) {
- fprintf(stderr, "No primary PCI bus\n");
- return NULL;
- }
-
- assert(!root->parent_dev);
-
- if (!devaddr) {
- *devfnp = -1;
- return pci_find_bus_nr(root, 0);
- }
-
- if (pci_parse_devaddr(devaddr, &dom, &bus, &slot, NULL) < 0) {
- return NULL;
- }
-
- if (dom != 0) {
- fprintf(stderr, "No support for non-zero PCI domains\n");
- return NULL;
- }
-
- *devfnp = PCI_DEVFN(slot, 0);
- return pci_find_bus_nr(root, bus);
-}
-
-static void pci_init_cmask(PCIDevice *dev)
-{
- pci_set_word(dev->cmask + PCI_VENDOR_ID, 0xffff);
- pci_set_word(dev->cmask + PCI_DEVICE_ID, 0xffff);
- dev->cmask[PCI_STATUS] = PCI_STATUS_CAP_LIST;
- dev->cmask[PCI_REVISION_ID] = 0xff;
- dev->cmask[PCI_CLASS_PROG] = 0xff;
- pci_set_word(dev->cmask + PCI_CLASS_DEVICE, 0xffff);
- dev->cmask[PCI_HEADER_TYPE] = 0xff;
- dev->cmask[PCI_CAPABILITY_LIST] = 0xff;
-}
-
-static void pci_init_wmask(PCIDevice *dev)
-{
- int config_size = pci_config_size(dev);
-
- dev->wmask[PCI_CACHE_LINE_SIZE] = 0xff;
- dev->wmask[PCI_INTERRUPT_LINE] = 0xff;
- pci_set_word(dev->wmask + PCI_COMMAND,
- PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
- PCI_COMMAND_INTX_DISABLE);
- if (dev->cap_present & QEMU_PCI_CAP_SERR) {
- pci_word_test_and_set_mask(dev->wmask + PCI_COMMAND, PCI_COMMAND_SERR);
- }
-
- memset(dev->wmask + PCI_CONFIG_HEADER_SIZE, 0xff,
- config_size - PCI_CONFIG_HEADER_SIZE);
-}
-
-static void pci_init_w1cmask(PCIDevice *dev)
-{
- /*
- * Note: It's okay to set w1cmask even for readonly bits as
- * long as their value is hardwired to 0.
- */
- pci_set_word(dev->w1cmask + PCI_STATUS,
- PCI_STATUS_PARITY | PCI_STATUS_SIG_TARGET_ABORT |
- PCI_STATUS_REC_TARGET_ABORT | PCI_STATUS_REC_MASTER_ABORT |
- PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY);
-}
-
-static void pci_init_mask_bridge(PCIDevice *d)
-{
- /* PCI_PRIMARY_BUS, PCI_SECONDARY_BUS, PCI_SUBORDINATE_BUS and
- PCI_SEC_LETENCY_TIMER */
- memset(d->wmask + PCI_PRIMARY_BUS, 0xff, 4);
-
- /* base and limit */
- d->wmask[PCI_IO_BASE] = PCI_IO_RANGE_MASK & 0xff;
- d->wmask[PCI_IO_LIMIT] = PCI_IO_RANGE_MASK & 0xff;
- pci_set_word(d->wmask + PCI_MEMORY_BASE,
- PCI_MEMORY_RANGE_MASK & 0xffff);
- pci_set_word(d->wmask + PCI_MEMORY_LIMIT,
- PCI_MEMORY_RANGE_MASK & 0xffff);
- pci_set_word(d->wmask + PCI_PREF_MEMORY_BASE,
- PCI_PREF_RANGE_MASK & 0xffff);
- pci_set_word(d->wmask + PCI_PREF_MEMORY_LIMIT,
- PCI_PREF_RANGE_MASK & 0xffff);
-
- /* PCI_PREF_BASE_UPPER32 and PCI_PREF_LIMIT_UPPER32 */
- memset(d->wmask + PCI_PREF_BASE_UPPER32, 0xff, 8);
-
- /* Supported memory and i/o types */
- d->config[PCI_IO_BASE] |= PCI_IO_RANGE_TYPE_16;
- d->config[PCI_IO_LIMIT] |= PCI_IO_RANGE_TYPE_16;
- pci_word_test_and_set_mask(d->config + PCI_PREF_MEMORY_BASE,
- PCI_PREF_RANGE_TYPE_64);
- pci_word_test_and_set_mask(d->config + PCI_PREF_MEMORY_LIMIT,
- PCI_PREF_RANGE_TYPE_64);
-
- /*
- * TODO: Bridges default to 10-bit VGA decoding but we currently only
- * implement 16-bit decoding (no alias support).
- */
- pci_set_word(d->wmask + PCI_BRIDGE_CONTROL,
- PCI_BRIDGE_CTL_PARITY |
- PCI_BRIDGE_CTL_SERR |
- PCI_BRIDGE_CTL_ISA |
- PCI_BRIDGE_CTL_VGA |
- PCI_BRIDGE_CTL_VGA_16BIT |
- PCI_BRIDGE_CTL_MASTER_ABORT |
- PCI_BRIDGE_CTL_BUS_RESET |
- PCI_BRIDGE_CTL_FAST_BACK |
- PCI_BRIDGE_CTL_DISCARD |
- PCI_BRIDGE_CTL_SEC_DISCARD |
- PCI_BRIDGE_CTL_DISCARD_SERR);
- /* Below does not do anything as we never set this bit, put here for
- * completeness. */
- pci_set_word(d->w1cmask + PCI_BRIDGE_CONTROL,
- PCI_BRIDGE_CTL_DISCARD_STATUS);
- d->cmask[PCI_IO_BASE] |= PCI_IO_RANGE_TYPE_MASK;
- d->cmask[PCI_IO_LIMIT] |= PCI_IO_RANGE_TYPE_MASK;
- pci_word_test_and_set_mask(d->cmask + PCI_PREF_MEMORY_BASE,
- PCI_PREF_RANGE_TYPE_MASK);
- pci_word_test_and_set_mask(d->cmask + PCI_PREF_MEMORY_LIMIT,
- PCI_PREF_RANGE_TYPE_MASK);
-}
-
-static void pci_init_multifunction(PCIBus *bus, PCIDevice *dev, Error **errp)
-{
- uint8_t slot = PCI_SLOT(dev->devfn);
- uint8_t func;
-
- if (dev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) {
- dev->config[PCI_HEADER_TYPE] |= PCI_HEADER_TYPE_MULTI_FUNCTION;
- }
-
- /*
- * multifunction bit is interpreted in two ways as follows.
- * - all functions must set the bit to 1.
- * Example: Intel X53
- * - function 0 must set the bit, but the rest function (> 0)
- * is allowed to leave the bit to 0.
- * Example: PIIX3(also in qemu), PIIX4(also in qemu), ICH10,
- *
- * So OS (at least Linux) checks the bit of only function 0,
- * and doesn't see the bit of function > 0.
- *
- * The below check allows both interpretation.
- */
- if (PCI_FUNC(dev->devfn)) {
- PCIDevice *f0 = bus->devices[PCI_DEVFN(slot, 0)];
- if (f0 && !(f0->cap_present & QEMU_PCI_CAP_MULTIFUNCTION)) {
- /* function 0 should set multifunction bit */
- error_setg(errp, "PCI: single function device can't be populated "
- "in function %x.%x", slot, PCI_FUNC(dev->devfn));
- return;
- }
- return;
- }
-
- if (dev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) {
- return;
- }
- /* function 0 indicates single function, so function > 0 must be NULL */
- for (func = 1; func < PCI_FUNC_MAX; ++func) {
- if (bus->devices[PCI_DEVFN(slot, func)]) {
- error_setg(errp, "PCI: %x.0 indicates single function, "
- "but %x.%x is already populated.",
- slot, slot, func);
- return;
- }
- }
-}
-
-static void pci_config_alloc(PCIDevice *pci_dev)
-{
- int config_size = pci_config_size(pci_dev);
-
- pci_dev->config = g_malloc0(config_size);
- pci_dev->cmask = g_malloc0(config_size);
- pci_dev->wmask = g_malloc0(config_size);
- pci_dev->w1cmask = g_malloc0(config_size);
- pci_dev->used = g_malloc0(config_size);
-}
-
-static void pci_config_free(PCIDevice *pci_dev)
-{
- g_free(pci_dev->config);
- g_free(pci_dev->cmask);
- g_free(pci_dev->wmask);
- g_free(pci_dev->w1cmask);
- g_free(pci_dev->used);
-}
-
-static void do_pci_unregister_device(PCIDevice *pci_dev)
-{
- pci_dev->bus->devices[pci_dev->devfn] = NULL;
- pci_config_free(pci_dev);
-
- address_space_destroy(&pci_dev->bus_master_as);
-}
-
-/* -1 for devfn means auto assign */
-static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
- const char *name, int devfn,
- Error **errp)
-{
- PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev);
- PCIConfigReadFunc *config_read = pc->config_read;
- PCIConfigWriteFunc *config_write = pc->config_write;
- Error *local_err = NULL;
- AddressSpace *dma_as;
- DeviceState *dev = DEVICE(pci_dev);
-
- pci_dev->bus = bus;
- /* Only pci bridges can be attached to extra PCI root buses */
- if (pci_bus_is_root(bus) && bus->parent_dev && !pc->is_bridge) {
- error_setg(errp,
- "PCI: Only PCI/PCIe bridges can be plugged into %s",
- bus->parent_dev->name);
- return NULL;
- }
-
- if (devfn < 0) {
- for(devfn = bus->devfn_min ; devfn < ARRAY_SIZE(bus->devices);
- devfn += PCI_FUNC_MAX) {
- if (!bus->devices[devfn])
- goto found;
- }
- error_setg(errp, "PCI: no slot/function available for %s, all in use",
- name);
- return NULL;
- found: ;
- } else if (bus->devices[devfn]) {
- error_setg(errp, "PCI: slot %d function %d not available for %s,"
- " in use by %s",
- PCI_SLOT(devfn), PCI_FUNC(devfn), name,
- bus->devices[devfn]->name);
- return NULL;
- } else if (dev->hotplugged &&
- pci_get_function_0(pci_dev)) {
- error_setg(errp, "PCI: slot %d function 0 already ocuppied by %s,"
- " new func %s cannot be exposed to guest.",
- PCI_SLOT(devfn),
- bus->devices[PCI_DEVFN(PCI_SLOT(devfn), 0)]->name,
- name);
-
- return NULL;
- }
-
- pci_dev->devfn = devfn;
- dma_as = pci_device_iommu_address_space(pci_dev);
-
- memory_region_init_alias(&pci_dev->bus_master_enable_region,
- OBJECT(pci_dev), "bus master",
- dma_as->root, 0, memory_region_size(dma_as->root));
- memory_region_set_enabled(&pci_dev->bus_master_enable_region, false);
- address_space_init(&pci_dev->bus_master_as, &pci_dev->bus_master_enable_region,
- name);
-
- pstrcpy(pci_dev->name, sizeof(pci_dev->name), name);
- pci_dev->irq_state = 0;
- pci_config_alloc(pci_dev);
-
- pci_config_set_vendor_id(pci_dev->config, pc->vendor_id);
- pci_config_set_device_id(pci_dev->config, pc->device_id);
- pci_config_set_revision(pci_dev->config, pc->revision);
- pci_config_set_class(pci_dev->config, pc->class_id);
-
- if (!pc->is_bridge) {
- if (pc->subsystem_vendor_id || pc->subsystem_id) {
- pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID,
- pc->subsystem_vendor_id);
- pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID,
- pc->subsystem_id);
- } else {
- pci_set_default_subsystem_id(pci_dev);
- }
- } else {
- /* subsystem_vendor_id/subsystem_id are only for header type 0 */
- assert(!pc->subsystem_vendor_id);
- assert(!pc->subsystem_id);
- }
- pci_init_cmask(pci_dev);
- pci_init_wmask(pci_dev);
- pci_init_w1cmask(pci_dev);
- if (pc->is_bridge) {
- pci_init_mask_bridge(pci_dev);
- }
- pci_init_multifunction(bus, pci_dev, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- do_pci_unregister_device(pci_dev);
- return NULL;
- }
-
- if (!config_read)
- config_read = pci_default_read_config;
- if (!config_write)
- config_write = pci_default_write_config;
- pci_dev->config_read = config_read;
- pci_dev->config_write = config_write;
- bus->devices[devfn] = pci_dev;
- pci_dev->version_id = 2; /* Current pci device vmstate version */
- return pci_dev;
-}
-
-static void pci_unregister_io_regions(PCIDevice *pci_dev)
-{
- PCIIORegion *r;
- int i;
-
- for(i = 0; i < PCI_NUM_REGIONS; i++) {
- r = &pci_dev->io_regions[i];
- if (!r->size || r->addr == PCI_BAR_UNMAPPED)
- continue;
- memory_region_del_subregion(r->address_space, r->memory);
- }
-
- pci_unregister_vga(pci_dev);
-}
-
-static void pci_qdev_unrealize(DeviceState *dev, Error **errp)
-{
- PCIDevice *pci_dev = PCI_DEVICE(dev);
- PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev);
-
- pci_unregister_io_regions(pci_dev);
- pci_del_option_rom(pci_dev);
-
- if (pc->exit) {
- pc->exit(pci_dev);
- }
-
- do_pci_unregister_device(pci_dev);
-}
-
-void pci_register_bar(PCIDevice *pci_dev, int region_num,
- uint8_t type, MemoryRegion *memory)
-{
- PCIIORegion *r;
- uint32_t addr;
- uint64_t wmask;
- pcibus_t size = memory_region_size(memory);
-
- assert(region_num >= 0);
- assert(region_num < PCI_NUM_REGIONS);
- if (size & (size-1)) {
- fprintf(stderr, "ERROR: PCI region size must be pow2 "
- "type=0x%x, size=0x%"FMT_PCIBUS"\n", type, size);
- exit(1);
- }
-
- r = &pci_dev->io_regions[region_num];
- r->addr = PCI_BAR_UNMAPPED;
- r->size = size;
- r->type = type;
- r->memory = NULL;
-
- wmask = ~(size - 1);
- addr = pci_bar(pci_dev, region_num);
- if (region_num == PCI_ROM_SLOT) {
- /* ROM enable bit is writable */
- wmask |= PCI_ROM_ADDRESS_ENABLE;
- }
- pci_set_long(pci_dev->config + addr, type);
- if (!(r->type & PCI_BASE_ADDRESS_SPACE_IO) &&
- r->type & PCI_BASE_ADDRESS_MEM_TYPE_64) {
- pci_set_quad(pci_dev->wmask + addr, wmask);
- pci_set_quad(pci_dev->cmask + addr, ~0ULL);
- } else {
- pci_set_long(pci_dev->wmask + addr, wmask & 0xffffffff);
- pci_set_long(pci_dev->cmask + addr, 0xffffffff);
- }
- pci_dev->io_regions[region_num].memory = memory;
- pci_dev->io_regions[region_num].address_space
- = type & PCI_BASE_ADDRESS_SPACE_IO
- ? pci_dev->bus->address_space_io
- : pci_dev->bus->address_space_mem;
-}
-
-static void pci_update_vga(PCIDevice *pci_dev)
-{
- uint16_t cmd;
-
- if (!pci_dev->has_vga) {
- return;
- }
-
- cmd = pci_get_word(pci_dev->config + PCI_COMMAND);
-
- memory_region_set_enabled(pci_dev->vga_regions[QEMU_PCI_VGA_MEM],
- cmd & PCI_COMMAND_MEMORY);
- memory_region_set_enabled(pci_dev->vga_regions[QEMU_PCI_VGA_IO_LO],
- cmd & PCI_COMMAND_IO);
- memory_region_set_enabled(pci_dev->vga_regions[QEMU_PCI_VGA_IO_HI],
- cmd & PCI_COMMAND_IO);
-}
-
-void pci_register_vga(PCIDevice *pci_dev, MemoryRegion *mem,
- MemoryRegion *io_lo, MemoryRegion *io_hi)
-{
- assert(!pci_dev->has_vga);
-
- assert(memory_region_size(mem) == QEMU_PCI_VGA_MEM_SIZE);
- pci_dev->vga_regions[QEMU_PCI_VGA_MEM] = mem;
- memory_region_add_subregion_overlap(pci_dev->bus->address_space_mem,
- QEMU_PCI_VGA_MEM_BASE, mem, 1);
-
- assert(memory_region_size(io_lo) == QEMU_PCI_VGA_IO_LO_SIZE);
- pci_dev->vga_regions[QEMU_PCI_VGA_IO_LO] = io_lo;
- memory_region_add_subregion_overlap(pci_dev->bus->address_space_io,
- QEMU_PCI_VGA_IO_LO_BASE, io_lo, 1);
-
- assert(memory_region_size(io_hi) == QEMU_PCI_VGA_IO_HI_SIZE);
- pci_dev->vga_regions[QEMU_PCI_VGA_IO_HI] = io_hi;
- memory_region_add_subregion_overlap(pci_dev->bus->address_space_io,
- QEMU_PCI_VGA_IO_HI_BASE, io_hi, 1);
- pci_dev->has_vga = true;
-
- pci_update_vga(pci_dev);
-}
-
-void pci_unregister_vga(PCIDevice *pci_dev)
-{
- if (!pci_dev->has_vga) {
- return;
- }
-
- memory_region_del_subregion(pci_dev->bus->address_space_mem,
- pci_dev->vga_regions[QEMU_PCI_VGA_MEM]);
- memory_region_del_subregion(pci_dev->bus->address_space_io,
- pci_dev->vga_regions[QEMU_PCI_VGA_IO_LO]);
- memory_region_del_subregion(pci_dev->bus->address_space_io,
- pci_dev->vga_regions[QEMU_PCI_VGA_IO_HI]);
- pci_dev->has_vga = false;
-}
-
-pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num)
-{
- return pci_dev->io_regions[region_num].addr;
-}
-
-static pcibus_t pci_bar_address(PCIDevice *d,
- int reg, uint8_t type, pcibus_t size)
-{
- pcibus_t new_addr, last_addr;
- int bar = pci_bar(d, reg);
- uint16_t cmd = pci_get_word(d->config + PCI_COMMAND);
- Object *machine = qdev_get_machine();
- ObjectClass *oc = object_get_class(machine);
- MachineClass *mc = MACHINE_CLASS(oc);
- bool allow_0_address = mc->pci_allow_0_address;
-
- if (type & PCI_BASE_ADDRESS_SPACE_IO) {
- if (!(cmd & PCI_COMMAND_IO)) {
- return PCI_BAR_UNMAPPED;
- }
- new_addr = pci_get_long(d->config + bar) & ~(size - 1);
- last_addr = new_addr + size - 1;
- /* Check if 32 bit BAR wraps around explicitly.
- * TODO: make priorities correct and remove this work around.
- */
- if (last_addr <= new_addr || last_addr >= UINT32_MAX ||
- (!allow_0_address && new_addr == 0)) {
- return PCI_BAR_UNMAPPED;
- }
- return new_addr;
- }
-
- if (!(cmd & PCI_COMMAND_MEMORY)) {
- return PCI_BAR_UNMAPPED;
- }
- if (type & PCI_BASE_ADDRESS_MEM_TYPE_64) {
- new_addr = pci_get_quad(d->config + bar);
- } else {
- new_addr = pci_get_long(d->config + bar);
- }
- /* the ROM slot has a specific enable bit */
- if (reg == PCI_ROM_SLOT && !(new_addr & PCI_ROM_ADDRESS_ENABLE)) {
- return PCI_BAR_UNMAPPED;
- }
- new_addr &= ~(size - 1);
- last_addr = new_addr + size - 1;
- /* NOTE: we do not support wrapping */
- /* XXX: as we cannot support really dynamic
- mappings, we handle specific values as invalid
- mappings. */
- if (last_addr <= new_addr || last_addr == PCI_BAR_UNMAPPED ||
- (!allow_0_address && new_addr == 0)) {
- return PCI_BAR_UNMAPPED;
- }
-
- /* Now pcibus_t is 64bit.
- * Check if 32 bit BAR wraps around explicitly.
- * Without this, PC ide doesn't work well.
- * TODO: remove this work around.
- */
- if (!(type & PCI_BASE_ADDRESS_MEM_TYPE_64) && last_addr >= UINT32_MAX) {
- return PCI_BAR_UNMAPPED;
- }
-
- /*
- * OS is allowed to set BAR beyond its addressable
- * bits. For example, 32 bit OS can set 64bit bar
- * to >4G. Check it. TODO: we might need to support
- * it in the future for e.g. PAE.
- */
- if (last_addr >= HWADDR_MAX) {
- return PCI_BAR_UNMAPPED;
- }
-
- return new_addr;
-}
-
-static void pci_update_mappings(PCIDevice *d)
-{
- PCIIORegion *r;
- int i;
- pcibus_t new_addr;
-
- for(i = 0; i < PCI_NUM_REGIONS; i++) {
- r = &d->io_regions[i];
-
- /* this region isn't registered */
- if (!r->size)
- continue;
-
- new_addr = pci_bar_address(d, i, r->type, r->size);
-
- /* This bar isn't changed */
- if (new_addr == r->addr)
- continue;
-
- /* now do the real mapping */
- if (r->addr != PCI_BAR_UNMAPPED) {
- trace_pci_update_mappings_del(d, pci_bus_num(d->bus),
- PCI_SLOT(d->devfn),
- PCI_FUNC(d->devfn),
- i, r->addr, r->size);
- memory_region_del_subregion(r->address_space, r->memory);
- }
- r->addr = new_addr;
- if (r->addr != PCI_BAR_UNMAPPED) {
- trace_pci_update_mappings_add(d, pci_bus_num(d->bus),
- PCI_SLOT(d->devfn),
- PCI_FUNC(d->devfn),
- i, r->addr, r->size);
- memory_region_add_subregion_overlap(r->address_space,
- r->addr, r->memory, 1);
- }
- }
-
- pci_update_vga(d);
-}
-
-static inline int pci_irq_disabled(PCIDevice *d)
-{
- return pci_get_word(d->config + PCI_COMMAND) & PCI_COMMAND_INTX_DISABLE;
-}
-
-/* Called after interrupt disabled field update in config space,
- * assert/deassert interrupts if necessary.
- * Gets original interrupt disable bit value (before update). */
-static void pci_update_irq_disabled(PCIDevice *d, int was_irq_disabled)
-{
- int i, disabled = pci_irq_disabled(d);
- if (disabled == was_irq_disabled)
- return;
- for (i = 0; i < PCI_NUM_PINS; ++i) {
- int state = pci_irq_state(d, i);
- pci_change_irq_level(d, i, disabled ? -state : state);
- }
-}
-
-uint32_t pci_default_read_config(PCIDevice *d,
- uint32_t address, int len)
-{
- uint32_t val = 0;
-
- memcpy(&val, d->config + address, len);
- return le32_to_cpu(val);
-}
-
-void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val_in, int l)
-{
- int i, was_irq_disabled = pci_irq_disabled(d);
- uint32_t val = val_in;
-
- for (i = 0; i < l; val >>= 8, ++i) {
- uint8_t wmask = d->wmask[addr + i];
- uint8_t w1cmask = d->w1cmask[addr + i];
- assert(!(wmask & w1cmask));
- d->config[addr + i] = (d->config[addr + i] & ~wmask) | (val & wmask);
- d->config[addr + i] &= ~(val & w1cmask); /* W1C: Write 1 to Clear */
- }
- if (ranges_overlap(addr, l, PCI_BASE_ADDRESS_0, 24) ||
- ranges_overlap(addr, l, PCI_ROM_ADDRESS, 4) ||
- ranges_overlap(addr, l, PCI_ROM_ADDRESS1, 4) ||
- range_covers_byte(addr, l, PCI_COMMAND))
- pci_update_mappings(d);
-
- if (range_covers_byte(addr, l, PCI_COMMAND)) {
- pci_update_irq_disabled(d, was_irq_disabled);
- memory_region_set_enabled(&d->bus_master_enable_region,
- pci_get_word(d->config + PCI_COMMAND)
- & PCI_COMMAND_MASTER);
- }
-
- msi_write_config(d, addr, val_in, l);
- msix_write_config(d, addr, val_in, l);
-}
-
-/***********************************************************/
-/* generic PCI irq support */
-
-/* 0 <= irq_num <= 3. level must be 0 or 1 */
-static void pci_irq_handler(void *opaque, int irq_num, int level)
-{
- PCIDevice *pci_dev = opaque;
- int change;
-
- change = level - pci_irq_state(pci_dev, irq_num);
- if (!change)
- return;
-
- pci_set_irq_state(pci_dev, irq_num, level);
- pci_update_irq_status(pci_dev);
- if (pci_irq_disabled(pci_dev))
- return;
- pci_change_irq_level(pci_dev, irq_num, change);
-}
-
-static inline int pci_intx(PCIDevice *pci_dev)
-{
- return pci_get_byte(pci_dev->config + PCI_INTERRUPT_PIN) - 1;
-}
-
-qemu_irq pci_allocate_irq(PCIDevice *pci_dev)
-{
- int intx = pci_intx(pci_dev);
-
- return qemu_allocate_irq(pci_irq_handler, pci_dev, intx);
-}
-
-void pci_set_irq(PCIDevice *pci_dev, int level)
-{
- int intx = pci_intx(pci_dev);
- pci_irq_handler(pci_dev, intx, level);
-}
-
-/* Special hooks used by device assignment */
-void pci_bus_set_route_irq_fn(PCIBus *bus, pci_route_irq_fn route_intx_to_irq)
-{
- assert(pci_bus_is_root(bus));
- bus->route_intx_to_irq = route_intx_to_irq;
-}
-
-PCIINTxRoute pci_device_route_intx_to_irq(PCIDevice *dev, int pin)
-{
- PCIBus *bus;
-
- do {
- bus = dev->bus;
- pin = bus->map_irq(dev, pin);
- dev = bus->parent_dev;
- } while (dev);
-
- if (!bus->route_intx_to_irq) {
- error_report("PCI: Bug - unimplemented PCI INTx routing (%s)",
- object_get_typename(OBJECT(bus->qbus.parent)));
- return (PCIINTxRoute) { PCI_INTX_DISABLED, -1 };
- }
-
- return bus->route_intx_to_irq(bus->irq_opaque, pin);
-}
-
-bool pci_intx_route_changed(PCIINTxRoute *old, PCIINTxRoute *new)
-{
- return old->mode != new->mode || old->irq != new->irq;
-}
-
-void pci_bus_fire_intx_routing_notifier(PCIBus *bus)
-{
- PCIDevice *dev;
- PCIBus *sec;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) {
- dev = bus->devices[i];
- if (dev && dev->intx_routing_notifier) {
- dev->intx_routing_notifier(dev);
- }
- }
-
- QLIST_FOREACH(sec, &bus->child, sibling) {
- pci_bus_fire_intx_routing_notifier(sec);
- }
-}
-
-void pci_device_set_intx_routing_notifier(PCIDevice *dev,
- PCIINTxRoutingNotifier notifier)
-{
- dev->intx_routing_notifier = notifier;
-}
-
-/*
- * PCI-to-PCI bridge specification
- * 9.1: Interrupt routing. Table 9-1
- *
- * the PCI Express Base Specification, Revision 2.1
- * 2.2.8.1: INTx interrutp signaling - Rules
- * the Implementation Note
- * Table 2-20
- */
-/*
- * 0 <= pin <= 3 0 = INTA, 1 = INTB, 2 = INTC, 3 = INTD
- * 0-origin unlike PCI interrupt pin register.
- */
-int pci_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin)
-{
- return (pin + PCI_SLOT(pci_dev->devfn)) % PCI_NUM_PINS;
-}
-
-/***********************************************************/
-/* monitor info on PCI */
-
-typedef struct {
- uint16_t class;
- const char *desc;
- const char *fw_name;
- uint16_t fw_ign_bits;
-} pci_class_desc;
-
-static const pci_class_desc pci_class_descriptions[] =
-{
- { 0x0001, "VGA controller", "display"},
- { 0x0100, "SCSI controller", "scsi"},
- { 0x0101, "IDE controller", "ide"},
- { 0x0102, "Floppy controller", "fdc"},
- { 0x0103, "IPI controller", "ipi"},
- { 0x0104, "RAID controller", "raid"},
- { 0x0106, "SATA controller"},
- { 0x0107, "SAS controller"},
- { 0x0180, "Storage controller"},
- { 0x0200, "Ethernet controller", "ethernet"},
- { 0x0201, "Token Ring controller", "token-ring"},
- { 0x0202, "FDDI controller", "fddi"},
- { 0x0203, "ATM controller", "atm"},
- { 0x0280, "Network controller"},
- { 0x0300, "VGA controller", "display", 0x00ff},
- { 0x0301, "XGA controller"},
- { 0x0302, "3D controller"},
- { 0x0380, "Display controller"},
- { 0x0400, "Video controller", "video"},
- { 0x0401, "Audio controller", "sound"},
- { 0x0402, "Phone"},
- { 0x0403, "Audio controller", "sound"},
- { 0x0480, "Multimedia controller"},
- { 0x0500, "RAM controller", "memory"},
- { 0x0501, "Flash controller", "flash"},
- { 0x0580, "Memory controller"},
- { 0x0600, "Host bridge", "host"},
- { 0x0601, "ISA bridge", "isa"},
- { 0x0602, "EISA bridge", "eisa"},
- { 0x0603, "MC bridge", "mca"},
- { 0x0604, "PCI bridge", "pci-bridge"},
- { 0x0605, "PCMCIA bridge", "pcmcia"},
- { 0x0606, "NUBUS bridge", "nubus"},
- { 0x0607, "CARDBUS bridge", "cardbus"},
- { 0x0608, "RACEWAY bridge"},
- { 0x0680, "Bridge"},
- { 0x0700, "Serial port", "serial"},
- { 0x0701, "Parallel port", "parallel"},
- { 0x0800, "Interrupt controller", "interrupt-controller"},
- { 0x0801, "DMA controller", "dma-controller"},
- { 0x0802, "Timer", "timer"},
- { 0x0803, "RTC", "rtc"},
- { 0x0900, "Keyboard", "keyboard"},
- { 0x0901, "Pen", "pen"},
- { 0x0902, "Mouse", "mouse"},
- { 0x0A00, "Dock station", "dock", 0x00ff},
- { 0x0B00, "i386 cpu", "cpu", 0x00ff},
- { 0x0c00, "Fireware contorller", "fireware"},
- { 0x0c01, "Access bus controller", "access-bus"},
- { 0x0c02, "SSA controller", "ssa"},
- { 0x0c03, "USB controller", "usb"},
- { 0x0c04, "Fibre channel controller", "fibre-channel"},
- { 0x0c05, "SMBus"},
- { 0, NULL}
-};
-
-static void pci_for_each_device_under_bus(PCIBus *bus,
- void (*fn)(PCIBus *b, PCIDevice *d,
- void *opaque),
- void *opaque)
-{
- PCIDevice *d;
- int devfn;
-
- for(devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
- d = bus->devices[devfn];
- if (d) {
- fn(bus, d, opaque);
- }
- }
-}
-
-void pci_for_each_device(PCIBus *bus, int bus_num,
- void (*fn)(PCIBus *b, PCIDevice *d, void *opaque),
- void *opaque)
-{
- bus = pci_find_bus_nr(bus, bus_num);
-
- if (bus) {
- pci_for_each_device_under_bus(bus, fn, opaque);
- }
-}
-
-static const pci_class_desc *get_class_desc(int class)
-{
- const pci_class_desc *desc;
-
- desc = pci_class_descriptions;
- while (desc->desc && class != desc->class) {
- desc++;
- }
-
- return desc;
-}
-
-static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num);
-
-static PciMemoryRegionList *qmp_query_pci_regions(const PCIDevice *dev)
-{
- PciMemoryRegionList *head = NULL, *cur_item = NULL;
- int i;
-
- for (i = 0; i < PCI_NUM_REGIONS; i++) {
- const PCIIORegion *r = &dev->io_regions[i];
- PciMemoryRegionList *region;
-
- if (!r->size) {
- continue;
- }
-
- region = g_malloc0(sizeof(*region));
- region->value = g_malloc0(sizeof(*region->value));
-
- if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
- region->value->type = g_strdup("io");
- } else {
- region->value->type = g_strdup("memory");
- region->value->has_prefetch = true;
- region->value->prefetch = !!(r->type & PCI_BASE_ADDRESS_MEM_PREFETCH);
- region->value->has_mem_type_64 = true;
- region->value->mem_type_64 = !!(r->type & PCI_BASE_ADDRESS_MEM_TYPE_64);
- }
-
- region->value->bar = i;
- region->value->address = r->addr;
- region->value->size = r->size;
-
- /* XXX: waiting for the qapi to support GSList */
- if (!cur_item) {
- head = cur_item = region;
- } else {
- cur_item->next = region;
- cur_item = region;
- }
- }
-
- return head;
-}
-
-static PciBridgeInfo *qmp_query_pci_bridge(PCIDevice *dev, PCIBus *bus,
- int bus_num)
-{
- PciBridgeInfo *info;
- PciMemoryRange *range;
-
- info = g_new0(PciBridgeInfo, 1);
-
- info->bus = g_new0(PciBusInfo, 1);
- info->bus->number = dev->config[PCI_PRIMARY_BUS];
- info->bus->secondary = dev->config[PCI_SECONDARY_BUS];
- info->bus->subordinate = dev->config[PCI_SUBORDINATE_BUS];
-
- range = info->bus->io_range = g_new0(PciMemoryRange, 1);
- range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO);
- range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_IO);
-
- range = info->bus->memory_range = g_new0(PciMemoryRange, 1);
- range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY);
- range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY);
-
- range = info->bus->prefetchable_range = g_new0(PciMemoryRange, 1);
- range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
- range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
-
- if (dev->config[PCI_SECONDARY_BUS] != 0) {
- PCIBus *child_bus = pci_find_bus_nr(bus, dev->config[PCI_SECONDARY_BUS]);
- if (child_bus) {
- info->has_devices = true;
- info->devices = qmp_query_pci_devices(child_bus, dev->config[PCI_SECONDARY_BUS]);
- }
- }
-
- return info;
-}
-
-static PciDeviceInfo *qmp_query_pci_device(PCIDevice *dev, PCIBus *bus,
- int bus_num)
-{
- const pci_class_desc *desc;
- PciDeviceInfo *info;
- uint8_t type;
- int class;
-
- info = g_new0(PciDeviceInfo, 1);
- info->bus = bus_num;
- info->slot = PCI_SLOT(dev->devfn);
- info->function = PCI_FUNC(dev->devfn);
-
- info->class_info = g_new0(PciDeviceClass, 1);
- class = pci_get_word(dev->config + PCI_CLASS_DEVICE);
- info->class_info->q_class = class;
- desc = get_class_desc(class);
- if (desc->desc) {
- info->class_info->has_desc = true;
- info->class_info->desc = g_strdup(desc->desc);
- }
-
- info->id = g_new0(PciDeviceId, 1);
- info->id->vendor = pci_get_word(dev->config + PCI_VENDOR_ID);
- info->id->device = pci_get_word(dev->config + PCI_DEVICE_ID);
- info->regions = qmp_query_pci_regions(dev);
- info->qdev_id = g_strdup(dev->qdev.id ? dev->qdev.id : "");
-
- if (dev->config[PCI_INTERRUPT_PIN] != 0) {
- info->has_irq = true;
- info->irq = dev->config[PCI_INTERRUPT_LINE];
- }
-
- type = dev->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION;
- if (type == PCI_HEADER_TYPE_BRIDGE) {
- info->has_pci_bridge = true;
- info->pci_bridge = qmp_query_pci_bridge(dev, bus, bus_num);
- }
-
- return info;
-}
-
-static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num)
-{
- PciDeviceInfoList *info, *head = NULL, *cur_item = NULL;
- PCIDevice *dev;
- int devfn;
-
- for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
- dev = bus->devices[devfn];
- if (dev) {
- info = g_malloc0(sizeof(*info));
- info->value = qmp_query_pci_device(dev, bus, bus_num);
-
- /* XXX: waiting for the qapi to support GSList */
- if (!cur_item) {
- head = cur_item = info;
- } else {
- cur_item->next = info;
- cur_item = info;
- }
- }
- }
-
- return head;
-}
-
-static PciInfo *qmp_query_pci_bus(PCIBus *bus, int bus_num)
-{
- PciInfo *info = NULL;
-
- bus = pci_find_bus_nr(bus, bus_num);
- if (bus) {
- info = g_malloc0(sizeof(*info));
- info->bus = bus_num;
- info->devices = qmp_query_pci_devices(bus, bus_num);
- }
-
- return info;
-}
-
-PciInfoList *qmp_query_pci(Error **errp)
-{
- PciInfoList *info, *head = NULL, *cur_item = NULL;
- PCIHostState *host_bridge;
-
- QLIST_FOREACH(host_bridge, &pci_host_bridges, next) {
- info = g_malloc0(sizeof(*info));
- info->value = qmp_query_pci_bus(host_bridge->bus,
- pci_bus_num(host_bridge->bus));
-
- /* XXX: waiting for the qapi to support GSList */
- if (!cur_item) {
- head = cur_item = info;
- } else {
- cur_item->next = info;
- cur_item = info;
- }
- }
-
- return head;
-}
-
-static const char * const pci_nic_models[] = {
- "ne2k_pci",
- "i82551",
- "i82557b",
- "i82559er",
- "rtl8139",
- "e1000",
- "pcnet",
- "virtio",
- NULL
-};
-
-static const char * const pci_nic_names[] = {
- "ne2k_pci",
- "i82551",
- "i82557b",
- "i82559er",
- "rtl8139",
- "e1000",
- "pcnet",
- "virtio-net-pci",
- NULL
-};
-
-/* Initialize a PCI NIC. */
-PCIDevice *pci_nic_init_nofail(NICInfo *nd, PCIBus *rootbus,
- const char *default_model,
- const char *default_devaddr)
-{
- const char *devaddr = nd->devaddr ? nd->devaddr : default_devaddr;
- Error *err = NULL;
- PCIBus *bus;
- PCIDevice *pci_dev;
- DeviceState *dev;
- int devfn;
- int i;
-
- if (qemu_show_nic_models(nd->model, pci_nic_models)) {
- exit(0);
- }
-
- i = qemu_find_nic_model(nd, pci_nic_models, default_model);
- if (i < 0) {
- exit(1);
- }
-
- bus = pci_get_bus_devfn(&devfn, rootbus, devaddr);
- if (!bus) {
- error_report("Invalid PCI device address %s for device %s",
- devaddr, pci_nic_names[i]);
- exit(1);
- }
-
- pci_dev = pci_create(bus, devfn, pci_nic_names[i]);
- dev = &pci_dev->qdev;
- qdev_set_nic_properties(dev, nd);
-
- object_property_set_bool(OBJECT(dev), true, "realized", &err);
- if (err) {
- error_report_err(err);
- object_unparent(OBJECT(dev));
- exit(1);
- }
-
- return pci_dev;
-}
-
-PCIDevice *pci_vga_init(PCIBus *bus)
-{
- switch (vga_interface_type) {
- case VGA_CIRRUS:
- return pci_create_simple(bus, -1, "cirrus-vga");
- case VGA_QXL:
- return pci_create_simple(bus, -1, "qxl-vga");
- case VGA_STD:
- return pci_create_simple(bus, -1, "VGA");
- case VGA_VMWARE:
- return pci_create_simple(bus, -1, "vmware-svga");
- case VGA_VIRTIO:
- return pci_create_simple(bus, -1, "virtio-vga");
- case VGA_NONE:
- default: /* Other non-PCI types. Checking for unsupported types is already
- done in vl.c. */
- return NULL;
- }
-}
-
-/* Whether a given bus number is in range of the secondary
- * bus of the given bridge device. */
-static bool pci_secondary_bus_in_range(PCIDevice *dev, int bus_num)
-{
- return !(pci_get_word(dev->config + PCI_BRIDGE_CONTROL) &
- PCI_BRIDGE_CTL_BUS_RESET) /* Don't walk the bus if it's reset. */ &&
- dev->config[PCI_SECONDARY_BUS] <= bus_num &&
- bus_num <= dev->config[PCI_SUBORDINATE_BUS];
-}
-
-/* Whether a given bus number is in a range of a root bus */
-static bool pci_root_bus_in_range(PCIBus *bus, int bus_num)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) {
- PCIDevice *dev = bus->devices[i];
-
- if (dev && PCI_DEVICE_GET_CLASS(dev)->is_bridge) {
- if (pci_secondary_bus_in_range(dev, bus_num)) {
- return true;
- }
- }
- }
-
- return false;
-}
-
-static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num)
-{
- PCIBus *sec;
-
- if (!bus) {
- return NULL;
- }
-
- if (pci_bus_num(bus) == bus_num) {
- return bus;
- }
-
- /* Consider all bus numbers in range for the host pci bridge. */
- if (!pci_bus_is_root(bus) &&
- !pci_secondary_bus_in_range(bus->parent_dev, bus_num)) {
- return NULL;
- }
-
- /* try child bus */
- for (; bus; bus = sec) {
- QLIST_FOREACH(sec, &bus->child, sibling) {
- if (pci_bus_num(sec) == bus_num) {
- return sec;
- }
- /* PXB buses assumed to be children of bus 0 */
- if (pci_bus_is_root(sec)) {
- if (pci_root_bus_in_range(sec, bus_num)) {
- break;
- }
- } else {
- if (pci_secondary_bus_in_range(sec->parent_dev, bus_num)) {
- break;
- }
- }
- }
- }
-
- return NULL;
-}
-
-void pci_for_each_bus_depth_first(PCIBus *bus,
- void *(*begin)(PCIBus *bus, void *parent_state),
- void (*end)(PCIBus *bus, void *state),
- void *parent_state)
-{
- PCIBus *sec;
- void *state;
-
- if (!bus) {
- return;
- }
-
- if (begin) {
- state = begin(bus, parent_state);
- } else {
- state = parent_state;
- }
-
- QLIST_FOREACH(sec, &bus->child, sibling) {
- pci_for_each_bus_depth_first(sec, begin, end, state);
- }
-
- if (end) {
- end(bus, state);
- }
-}
-
-
-PCIDevice *pci_find_device(PCIBus *bus, int bus_num, uint8_t devfn)
-{
- bus = pci_find_bus_nr(bus, bus_num);
-
- if (!bus)
- return NULL;
-
- return bus->devices[devfn];
-}
-
-static void pci_qdev_realize(DeviceState *qdev, Error **errp)
-{
- PCIDevice *pci_dev = (PCIDevice *)qdev;
- PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev);
- Error *local_err = NULL;
- PCIBus *bus;
- bool is_default_rom;
-
- /* initialize cap_present for pci_is_express() and pci_config_size() */
- if (pc->is_express) {
- pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS;
- }
-
- bus = PCI_BUS(qdev_get_parent_bus(qdev));
- pci_dev = do_pci_register_device(pci_dev, bus,
- object_get_typename(OBJECT(qdev)),
- pci_dev->devfn, errp);
- if (pci_dev == NULL)
- return;
-
- if (pc->realize) {
- pc->realize(pci_dev, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- do_pci_unregister_device(pci_dev);
- return;
- }
- }
-
- /* rom loading */
- is_default_rom = false;
- if (pci_dev->romfile == NULL && pc->romfile != NULL) {
- pci_dev->romfile = g_strdup(pc->romfile);
- is_default_rom = true;
- }
-
- pci_add_option_rom(pci_dev, is_default_rom, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- pci_qdev_unrealize(DEVICE(pci_dev), NULL);
- return;
- }
-}
-
-static void pci_default_realize(PCIDevice *dev, Error **errp)
-{
- PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
-
- if (pc->init) {
- if (pc->init(dev) < 0) {
- error_setg(errp, "Device initialization failed");
- return;
- }
- }
-}
-
-PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction,
- const char *name)
-{
- DeviceState *dev;
-
- dev = qdev_create(&bus->qbus, name);
- qdev_prop_set_int32(dev, "addr", devfn);
- qdev_prop_set_bit(dev, "multifunction", multifunction);
- return PCI_DEVICE(dev);
-}
-
-PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn,
- bool multifunction,
- const char *name)
-{
- PCIDevice *dev = pci_create_multifunction(bus, devfn, multifunction, name);
- qdev_init_nofail(&dev->qdev);
- return dev;
-}
-
-PCIDevice *pci_create(PCIBus *bus, int devfn, const char *name)
-{
- return pci_create_multifunction(bus, devfn, false, name);
-}
-
-PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name)
-{
- return pci_create_simple_multifunction(bus, devfn, false, name);
-}
-
-static uint8_t pci_find_space(PCIDevice *pdev, uint8_t size)
-{
- int offset = PCI_CONFIG_HEADER_SIZE;
- int i;
- for (i = PCI_CONFIG_HEADER_SIZE; i < PCI_CONFIG_SPACE_SIZE; ++i) {
- if (pdev->used[i])
- offset = i + 1;
- else if (i - offset + 1 == size)
- return offset;
- }
- return 0;
-}
-
-static uint8_t pci_find_capability_list(PCIDevice *pdev, uint8_t cap_id,
- uint8_t *prev_p)
-{
- uint8_t next, prev;
-
- if (!(pdev->config[PCI_STATUS] & PCI_STATUS_CAP_LIST))
- return 0;
-
- for (prev = PCI_CAPABILITY_LIST; (next = pdev->config[prev]);
- prev = next + PCI_CAP_LIST_NEXT)
- if (pdev->config[next + PCI_CAP_LIST_ID] == cap_id)
- break;
-
- if (prev_p)
- *prev_p = prev;
- return next;
-}
-
-static uint8_t pci_find_capability_at_offset(PCIDevice *pdev, uint8_t offset)
-{
- uint8_t next, prev, found = 0;
-
- if (!(pdev->used[offset])) {
- return 0;
- }
-
- assert(pdev->config[PCI_STATUS] & PCI_STATUS_CAP_LIST);
-
- for (prev = PCI_CAPABILITY_LIST; (next = pdev->config[prev]);
- prev = next + PCI_CAP_LIST_NEXT) {
- if (next <= offset && next > found) {
- found = next;
- }
- }
- return found;
-}
-
-/* Patch the PCI vendor and device ids in a PCI rom image if necessary.
- This is needed for an option rom which is used for more than one device. */
-static void pci_patch_ids(PCIDevice *pdev, uint8_t *ptr, int size)
-{
- uint16_t vendor_id;
- uint16_t device_id;
- uint16_t rom_vendor_id;
- uint16_t rom_device_id;
- uint16_t rom_magic;
- uint16_t pcir_offset;
- uint8_t checksum;
-
- /* Words in rom data are little endian (like in PCI configuration),
- so they can be read / written with pci_get_word / pci_set_word. */
-
- /* Only a valid rom will be patched. */
- rom_magic = pci_get_word(ptr);
- if (rom_magic != 0xaa55) {
- PCI_DPRINTF("Bad ROM magic %04x\n", rom_magic);
- return;
- }
- pcir_offset = pci_get_word(ptr + 0x18);
- if (pcir_offset + 8 >= size || memcmp(ptr + pcir_offset, "PCIR", 4)) {
- PCI_DPRINTF("Bad PCIR offset 0x%x or signature\n", pcir_offset);
- return;
- }
-
- vendor_id = pci_get_word(pdev->config + PCI_VENDOR_ID);
- device_id = pci_get_word(pdev->config + PCI_DEVICE_ID);
- rom_vendor_id = pci_get_word(ptr + pcir_offset + 4);
- rom_device_id = pci_get_word(ptr + pcir_offset + 6);
-
- PCI_DPRINTF("%s: ROM id %04x%04x / PCI id %04x%04x\n", pdev->romfile,
- vendor_id, device_id, rom_vendor_id, rom_device_id);
-
- checksum = ptr[6];
-
- if (vendor_id != rom_vendor_id) {
- /* Patch vendor id and checksum (at offset 6 for etherboot roms). */
- checksum += (uint8_t)rom_vendor_id + (uint8_t)(rom_vendor_id >> 8);
- checksum -= (uint8_t)vendor_id + (uint8_t)(vendor_id >> 8);
- PCI_DPRINTF("ROM checksum %02x / %02x\n", ptr[6], checksum);
- ptr[6] = checksum;
- pci_set_word(ptr + pcir_offset + 4, vendor_id);
- }
-
- if (device_id != rom_device_id) {
- /* Patch device id and checksum (at offset 6 for etherboot roms). */
- checksum += (uint8_t)rom_device_id + (uint8_t)(rom_device_id >> 8);
- checksum -= (uint8_t)device_id + (uint8_t)(device_id >> 8);
- PCI_DPRINTF("ROM checksum %02x / %02x\n", ptr[6], checksum);
- ptr[6] = checksum;
- pci_set_word(ptr + pcir_offset + 6, device_id);
- }
-}
-
-/* Add an option rom for the device */
-static void pci_add_option_rom(PCIDevice *pdev, bool is_default_rom,
- Error **errp)
-{
- int size;
- char *path;
- void *ptr;
- char name[32];
- const VMStateDescription *vmsd;
-
- if (!pdev->romfile)
- return;
- if (strlen(pdev->romfile) == 0)
- return;
-
- if (!pdev->rom_bar) {
- /*
- * Load rom via fw_cfg instead of creating a rom bar,
- * for 0.11 compatibility.
- */
- int class = pci_get_word(pdev->config + PCI_CLASS_DEVICE);
-
- /*
- * Hot-plugged devices can't use the option ROM
- * if the rom bar is disabled.
- */
- if (DEVICE(pdev)->hotplugged) {
- error_setg(errp, "Hot-plugged device without ROM bar"
- " can't have an option ROM");
- return;
- }
-
- if (class == 0x0300) {
- rom_add_vga(pdev->romfile);
- } else {
- rom_add_option(pdev->romfile, -1);
- }
- return;
- }
-
- path = qemu_find_file(QEMU_FILE_TYPE_BIOS, pdev->romfile);
- if (path == NULL) {
- path = g_strdup(pdev->romfile);
- }
-
- size = get_image_size(path);
- if (size < 0) {
- error_setg(errp, "failed to find romfile \"%s\"", pdev->romfile);
- g_free(path);
- return;
- } else if (size == 0) {
- error_setg(errp, "romfile \"%s\" is empty", pdev->romfile);
- g_free(path);
- return;
- }
- size = pow2ceil(size);
-
- vmsd = qdev_get_vmsd(DEVICE(pdev));
-
- if (vmsd) {
- snprintf(name, sizeof(name), "%s.rom", vmsd->name);
- } else {
- snprintf(name, sizeof(name), "%s.rom", object_get_typename(OBJECT(pdev)));
- }
- pdev->has_rom = true;
- memory_region_init_ram(&pdev->rom, OBJECT(pdev), name, size, &error_fatal);
- vmstate_register_ram(&pdev->rom, &pdev->qdev);
- ptr = memory_region_get_ram_ptr(&pdev->rom);
- load_image(path, ptr);
- g_free(path);
-
- if (is_default_rom) {
- /* Only the default rom images will be patched (if needed). */
- pci_patch_ids(pdev, ptr, size);
- }
-
- pci_register_bar(pdev, PCI_ROM_SLOT, 0, &pdev->rom);
-}
-
-static void pci_del_option_rom(PCIDevice *pdev)
-{
- if (!pdev->has_rom)
- return;
-
- vmstate_unregister_ram(&pdev->rom, &pdev->qdev);
- pdev->has_rom = false;
-}
-
-/*
- * if offset = 0,
- * Find and reserve space and add capability to the linked list
- * in pci config space
- */
-int pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
- uint8_t offset, uint8_t size)
-{
- int ret;
- Error *local_err = NULL;
-
- ret = pci_add_capability2(pdev, cap_id, offset, size, &local_err);
- if (local_err) {
- assert(ret < 0);
- error_report_err(local_err);
- } else {
- /* success implies a positive offset in config space */
- assert(ret > 0);
- }
- return ret;
-}
-
-int pci_add_capability2(PCIDevice *pdev, uint8_t cap_id,
- uint8_t offset, uint8_t size,
- Error **errp)
-{
- uint8_t *config;
- int i, overlapping_cap;
-
- if (!offset) {
- offset = pci_find_space(pdev, size);
- if (!offset) {
- error_setg(errp, "out of PCI config space");
- return -ENOSPC;
- }
- } else {
- /* Verify that capabilities don't overlap. Note: device assignment
- * depends on this check to verify that the device is not broken.
- * Should never trigger for emulated devices, but it's helpful
- * for debugging these. */
- for (i = offset; i < offset + size; i++) {
- overlapping_cap = pci_find_capability_at_offset(pdev, i);
- if (overlapping_cap) {
- error_setg(errp, "%s:%02x:%02x.%x "
- "Attempt to add PCI capability %x at offset "
- "%x overlaps existing capability %x at offset %x",
- pci_root_bus_path(pdev), pci_bus_num(pdev->bus),
- PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
- cap_id, offset, overlapping_cap, i);
- return -EINVAL;
- }
- }
- }
-
- config = pdev->config + offset;
- config[PCI_CAP_LIST_ID] = cap_id;
- config[PCI_CAP_LIST_NEXT] = pdev->config[PCI_CAPABILITY_LIST];
- pdev->config[PCI_CAPABILITY_LIST] = offset;
- pdev->config[PCI_STATUS] |= PCI_STATUS_CAP_LIST;
- memset(pdev->used + offset, 0xFF, QEMU_ALIGN_UP(size, 4));
- /* Make capability read-only by default */
- memset(pdev->wmask + offset, 0, size);
- /* Check capability by default */
- memset(pdev->cmask + offset, 0xFF, size);
- return offset;
-}
-
-/* Unlink capability from the pci config space. */
-void pci_del_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size)
-{
- uint8_t prev, offset = pci_find_capability_list(pdev, cap_id, &prev);
- if (!offset)
- return;
- pdev->config[prev] = pdev->config[offset + PCI_CAP_LIST_NEXT];
- /* Make capability writable again */
- memset(pdev->wmask + offset, 0xff, size);
- memset(pdev->w1cmask + offset, 0, size);
- /* Clear cmask as device-specific registers can't be checked */
- memset(pdev->cmask + offset, 0, size);
- memset(pdev->used + offset, 0, QEMU_ALIGN_UP(size, 4));
-
- if (!pdev->config[PCI_CAPABILITY_LIST])
- pdev->config[PCI_STATUS] &= ~PCI_STATUS_CAP_LIST;
-}
-
-uint8_t pci_find_capability(PCIDevice *pdev, uint8_t cap_id)
-{
- return pci_find_capability_list(pdev, cap_id, NULL);
-}
-
-static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent)
-{
- PCIDevice *d = (PCIDevice *)dev;
- const pci_class_desc *desc;
- char ctxt[64];
- PCIIORegion *r;
- int i, class;
-
- class = pci_get_word(d->config + PCI_CLASS_DEVICE);
- desc = pci_class_descriptions;
- while (desc->desc && class != desc->class)
- desc++;
- if (desc->desc) {
- snprintf(ctxt, sizeof(ctxt), "%s", desc->desc);
- } else {
- snprintf(ctxt, sizeof(ctxt), "Class %04x", class);
- }
-
- monitor_printf(mon, "%*sclass %s, addr %02x:%02x.%x, "
- "pci id %04x:%04x (sub %04x:%04x)\n",
- indent, "", ctxt, pci_bus_num(d->bus),
- PCI_SLOT(d->devfn), PCI_FUNC(d->devfn),
- pci_get_word(d->config + PCI_VENDOR_ID),
- pci_get_word(d->config + PCI_DEVICE_ID),
- pci_get_word(d->config + PCI_SUBSYSTEM_VENDOR_ID),
- pci_get_word(d->config + PCI_SUBSYSTEM_ID));
- for (i = 0; i < PCI_NUM_REGIONS; i++) {
- r = &d->io_regions[i];
- if (!r->size)
- continue;
- monitor_printf(mon, "%*sbar %d: %s at 0x%"FMT_PCIBUS
- " [0x%"FMT_PCIBUS"]\n",
- indent, "",
- i, r->type & PCI_BASE_ADDRESS_SPACE_IO ? "i/o" : "mem",
- r->addr, r->addr + r->size - 1);
- }
-}
-
-static char *pci_dev_fw_name(DeviceState *dev, char *buf, int len)
-{
- PCIDevice *d = (PCIDevice *)dev;
- const char *name = NULL;
- const pci_class_desc *desc = pci_class_descriptions;
- int class = pci_get_word(d->config + PCI_CLASS_DEVICE);
-
- while (desc->desc &&
- (class & ~desc->fw_ign_bits) !=
- (desc->class & ~desc->fw_ign_bits)) {
- desc++;
- }
-
- if (desc->desc) {
- name = desc->fw_name;
- }
-
- if (name) {
- pstrcpy(buf, len, name);
- } else {
- snprintf(buf, len, "pci%04x,%04x",
- pci_get_word(d->config + PCI_VENDOR_ID),
- pci_get_word(d->config + PCI_DEVICE_ID));
- }
-
- return buf;
-}
-
-static char *pcibus_get_fw_dev_path(DeviceState *dev)
-{
- PCIDevice *d = (PCIDevice *)dev;
- char path[50], name[33];
- int off;
-
- off = snprintf(path, sizeof(path), "%s@%x",
- pci_dev_fw_name(dev, name, sizeof name),
- PCI_SLOT(d->devfn));
- if (PCI_FUNC(d->devfn))
- snprintf(path + off, sizeof(path) + off, ",%x", PCI_FUNC(d->devfn));
- return g_strdup(path);
-}
-
-static char *pcibus_get_dev_path(DeviceState *dev)
-{
- PCIDevice *d = container_of(dev, PCIDevice, qdev);
- PCIDevice *t;
- int slot_depth;
- /* Path format: Domain:00:Slot.Function:Slot.Function....:Slot.Function.
- * 00 is added here to make this format compatible with
- * domain:Bus:Slot.Func for systems without nested PCI bridges.
- * Slot.Function list specifies the slot and function numbers for all
- * devices on the path from root to the specific device. */
- const char *root_bus_path;
- int root_bus_len;
- char slot[] = ":SS.F";
- int slot_len = sizeof slot - 1 /* For '\0' */;
- int path_len;
- char *path, *p;
- int s;
-
- root_bus_path = pci_root_bus_path(d);
- root_bus_len = strlen(root_bus_path);
-
- /* Calculate # of slots on path between device and root. */;
- slot_depth = 0;
- for (t = d; t; t = t->bus->parent_dev) {
- ++slot_depth;
- }
-
- path_len = root_bus_len + slot_len * slot_depth;
-
- /* Allocate memory, fill in the terminating null byte. */
- path = g_malloc(path_len + 1 /* For '\0' */);
- path[path_len] = '\0';
-
- memcpy(path, root_bus_path, root_bus_len);
-
- /* Fill in slot numbers. We walk up from device to root, so need to print
- * them in the reverse order, last to first. */
- p = path + path_len;
- for (t = d; t; t = t->bus->parent_dev) {
- p -= slot_len;
- s = snprintf(slot, sizeof slot, ":%02x.%x",
- PCI_SLOT(t->devfn), PCI_FUNC(t->devfn));
- assert(s == slot_len);
- memcpy(p, slot, slot_len);
- }
-
- return path;
-}
-
-static int pci_qdev_find_recursive(PCIBus *bus,
- const char *id, PCIDevice **pdev)
-{
- DeviceState *qdev = qdev_find_recursive(&bus->qbus, id);
- if (!qdev) {
- return -ENODEV;
- }
-
- /* roughly check if given qdev is pci device */
- if (object_dynamic_cast(OBJECT(qdev), TYPE_PCI_DEVICE)) {
- *pdev = PCI_DEVICE(qdev);
- return 0;
- }
- return -EINVAL;
-}
-
-int pci_qdev_find_device(const char *id, PCIDevice **pdev)
-{
- PCIHostState *host_bridge;
- int rc = -ENODEV;
-
- QLIST_FOREACH(host_bridge, &pci_host_bridges, next) {
- int tmp = pci_qdev_find_recursive(host_bridge->bus, id, pdev);
- if (!tmp) {
- rc = 0;
- break;
- }
- if (tmp != -ENODEV) {
- rc = tmp;
- }
- }
-
- return rc;
-}
-
-MemoryRegion *pci_address_space(PCIDevice *dev)
-{
- return dev->bus->address_space_mem;
-}
-
-MemoryRegion *pci_address_space_io(PCIDevice *dev)
-{
- return dev->bus->address_space_io;
-}
-
-static void pci_device_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *k = DEVICE_CLASS(klass);
- PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
-
- k->realize = pci_qdev_realize;
- k->unrealize = pci_qdev_unrealize;
- k->bus_type = TYPE_PCI_BUS;
- k->props = pci_props;
- pc->realize = pci_default_realize;
-}
-
-AddressSpace *pci_device_iommu_address_space(PCIDevice *dev)
-{
- PCIBus *bus = PCI_BUS(dev->bus);
- PCIBus *iommu_bus = bus;
-
- while(iommu_bus && !iommu_bus->iommu_fn && iommu_bus->parent_dev) {
- iommu_bus = PCI_BUS(iommu_bus->parent_dev->bus);
- }
- if (iommu_bus && iommu_bus->iommu_fn) {
- return iommu_bus->iommu_fn(bus, iommu_bus->iommu_opaque, dev->devfn);
- }
- return &address_space_memory;
-}
-
-void pci_setup_iommu(PCIBus *bus, PCIIOMMUFunc fn, void *opaque)
-{
- bus->iommu_fn = fn;
- bus->iommu_opaque = opaque;
-}
-
-static void pci_dev_get_w64(PCIBus *b, PCIDevice *dev, void *opaque)
-{
- Range *range = opaque;
- PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
- uint16_t cmd = pci_get_word(dev->config + PCI_COMMAND);
- int i;
-
- if (!(cmd & PCI_COMMAND_MEMORY)) {
- return;
- }
-
- if (pc->is_bridge) {
- pcibus_t base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
- pcibus_t limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
-
- base = MAX(base, 0x1ULL << 32);
-
- if (limit >= base) {
- Range pref_range;
- pref_range.begin = base;
- pref_range.end = limit + 1;
- range_extend(range, &pref_range);
- }
- }
- for (i = 0; i < PCI_NUM_REGIONS; ++i) {
- PCIIORegion *r = &dev->io_regions[i];
- Range region_range;
-
- if (!r->size ||
- (r->type & PCI_BASE_ADDRESS_SPACE_IO) ||
- !(r->type & PCI_BASE_ADDRESS_MEM_TYPE_64)) {
- continue;
- }
- region_range.begin = pci_bar_address(dev, i, r->type, r->size);
- region_range.end = region_range.begin + r->size;
-
- if (region_range.begin == PCI_BAR_UNMAPPED) {
- continue;
- }
-
- region_range.begin = MAX(region_range.begin, 0x1ULL << 32);
-
- if (region_range.end - 1 >= region_range.begin) {
- range_extend(range, &region_range);
- }
- }
-}
-
-void pci_bus_get_w64_range(PCIBus *bus, Range *range)
-{
- range->begin = range->end = 0;
- pci_for_each_device_under_bus(bus, pci_dev_get_w64, range);
-}
-
-static bool pcie_has_upstream_port(PCIDevice *dev)
-{
- PCIDevice *parent_dev = pci_bridge_get_device(dev->bus);
-
- /* Device associated with an upstream port.
- * As there are several types of these, it's easier to check the
- * parent device: upstream ports are always connected to
- * root or downstream ports.
- */
- return parent_dev &&
- pci_is_express(parent_dev) &&
- parent_dev->exp.exp_cap &&
- (pcie_cap_get_type(parent_dev) == PCI_EXP_TYPE_ROOT_PORT ||
- pcie_cap_get_type(parent_dev) == PCI_EXP_TYPE_DOWNSTREAM);
-}
-
-PCIDevice *pci_get_function_0(PCIDevice *pci_dev)
-{
- if(pcie_has_upstream_port(pci_dev)) {
- /* With an upstream PCIe port, we only support 1 device at slot 0 */
- return pci_dev->bus->devices[0];
- } else {
- /* Other bus types might support multiple devices at slots 0-31 */
- return pci_dev->bus->devices[PCI_DEVFN(PCI_SLOT(pci_dev->devfn), 0)];
- }
-}
-
-static const TypeInfo pci_device_type_info = {
- .name = TYPE_PCI_DEVICE,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(PCIDevice),
- .abstract = true,
- .class_size = sizeof(PCIDeviceClass),
- .class_init = pci_device_class_init,
-};
-
-static void pci_register_types(void)
-{
- type_register_static(&pci_bus_info);
- type_register_static(&pcie_bus_info);
- type_register_static(&pci_device_type_info);
-}
-
-type_init(pci_register_types)
diff --git a/qemu/hw/pci/pci_bridge.c b/qemu/hw/pci/pci_bridge.c
deleted file mode 100644
index 3cf30bd33..000000000
--- a/qemu/hw/pci/pci_bridge.c
+++ /dev/null
@@ -1,419 +0,0 @@
-/*
- * QEMU PCI bus manager
- *
- * Copyright (c) 2004 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to dea
-
- * 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.
- */
-/*
- * split out from pci.c
- * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
- * VA Linux Systems Japan K.K.
- */
-
-#include "qemu/osdep.h"
-#include "hw/pci/pci_bridge.h"
-#include "hw/pci/pci_bus.h"
-#include "qemu/range.h"
-
-/* PCI bridge subsystem vendor ID helper functions */
-#define PCI_SSVID_SIZEOF 8
-#define PCI_SSVID_SVID 4
-#define PCI_SSVID_SSID 6
-
-int pci_bridge_ssvid_init(PCIDevice *dev, uint8_t offset,
- uint16_t svid, uint16_t ssid)
-{
- int pos;
- pos = pci_add_capability(dev, PCI_CAP_ID_SSVID, offset, PCI_SSVID_SIZEOF);
- if (pos < 0) {
- return pos;
- }
-
- pci_set_word(dev->config + pos + PCI_SSVID_SVID, svid);
- pci_set_word(dev->config + pos + PCI_SSVID_SSID, ssid);
- return pos;
-}
-
-/* Accessor function to get parent bridge device from pci bus. */
-PCIDevice *pci_bridge_get_device(PCIBus *bus)
-{
- return bus->parent_dev;
-}
-
-/* Accessor function to get secondary bus from pci-to-pci bridge device */
-PCIBus *pci_bridge_get_sec_bus(PCIBridge *br)
-{
- return &br->sec_bus;
-}
-
-static uint32_t pci_config_get_io_base(const PCIDevice *d,
- uint32_t base, uint32_t base_upper16)
-{
- uint32_t val;
-
- val = ((uint32_t)d->config[base] & PCI_IO_RANGE_MASK) << 8;
- if (d->config[base] & PCI_IO_RANGE_TYPE_32) {
- val |= (uint32_t)pci_get_word(d->config + base_upper16) << 16;
- }
- return val;
-}
-
-static pcibus_t pci_config_get_memory_base(const PCIDevice *d, uint32_t base)
-{
- return ((pcibus_t)pci_get_word(d->config + base) & PCI_MEMORY_RANGE_MASK)
- << 16;
-}
-
-static pcibus_t pci_config_get_pref_base(const PCIDevice *d,
- uint32_t base, uint32_t upper)
-{
- pcibus_t tmp;
- pcibus_t val;
-
- tmp = (pcibus_t)pci_get_word(d->config + base);
- val = (tmp & PCI_PREF_RANGE_MASK) << 16;
- if (tmp & PCI_PREF_RANGE_TYPE_64) {
- val |= (pcibus_t)pci_get_long(d->config + upper) << 32;
- }
- return val;
-}
-
-/* accessor function to get bridge filtering base address */
-pcibus_t pci_bridge_get_base(const PCIDevice *bridge, uint8_t type)
-{
- pcibus_t base;
- if (type & PCI_BASE_ADDRESS_SPACE_IO) {
- base = pci_config_get_io_base(bridge,
- PCI_IO_BASE, PCI_IO_BASE_UPPER16);
- } else {
- if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) {
- base = pci_config_get_pref_base(
- bridge, PCI_PREF_MEMORY_BASE, PCI_PREF_BASE_UPPER32);
- } else {
- base = pci_config_get_memory_base(bridge, PCI_MEMORY_BASE);
- }
- }
-
- return base;
-}
-
-/* accessor funciton to get bridge filtering limit */
-pcibus_t pci_bridge_get_limit(const PCIDevice *bridge, uint8_t type)
-{
- pcibus_t limit;
- if (type & PCI_BASE_ADDRESS_SPACE_IO) {
- limit = pci_config_get_io_base(bridge,
- PCI_IO_LIMIT, PCI_IO_LIMIT_UPPER16);
- limit |= 0xfff; /* PCI bridge spec 3.2.5.6. */
- } else {
- if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) {
- limit = pci_config_get_pref_base(
- bridge, PCI_PREF_MEMORY_LIMIT, PCI_PREF_LIMIT_UPPER32);
- } else {
- limit = pci_config_get_memory_base(bridge, PCI_MEMORY_LIMIT);
- }
- limit |= 0xfffff; /* PCI bridge spec 3.2.5.{1, 8}. */
- }
- return limit;
-}
-
-static void pci_bridge_init_alias(PCIBridge *bridge, MemoryRegion *alias,
- uint8_t type, const char *name,
- MemoryRegion *space,
- MemoryRegion *parent_space,
- bool enabled)
-{
- PCIDevice *bridge_dev = PCI_DEVICE(bridge);
- pcibus_t base = pci_bridge_get_base(bridge_dev, type);
- pcibus_t limit = pci_bridge_get_limit(bridge_dev, type);
- /* TODO: this doesn't handle base = 0 limit = 2^64 - 1 correctly.
- * Apparently no way to do this with existing memory APIs. */
- pcibus_t size = enabled && limit >= base ? limit + 1 - base : 0;
-
- memory_region_init_alias(alias, OBJECT(bridge), name, space, base, size);
- memory_region_add_subregion_overlap(parent_space, base, alias, 1);
-}
-
-static void pci_bridge_init_vga_aliases(PCIBridge *br, PCIBus *parent,
- MemoryRegion *alias_vga)
-{
- PCIDevice *pd = PCI_DEVICE(br);
- uint16_t brctl = pci_get_word(pd->config + PCI_BRIDGE_CONTROL);
-
- memory_region_init_alias(&alias_vga[QEMU_PCI_VGA_IO_LO], OBJECT(br),
- "pci_bridge_vga_io_lo", &br->address_space_io,
- QEMU_PCI_VGA_IO_LO_BASE, QEMU_PCI_VGA_IO_LO_SIZE);
- memory_region_init_alias(&alias_vga[QEMU_PCI_VGA_IO_HI], OBJECT(br),
- "pci_bridge_vga_io_hi", &br->address_space_io,
- QEMU_PCI_VGA_IO_HI_BASE, QEMU_PCI_VGA_IO_HI_SIZE);
- memory_region_init_alias(&alias_vga[QEMU_PCI_VGA_MEM], OBJECT(br),
- "pci_bridge_vga_mem", &br->address_space_mem,
- QEMU_PCI_VGA_MEM_BASE, QEMU_PCI_VGA_MEM_SIZE);
-
- if (brctl & PCI_BRIDGE_CTL_VGA) {
- pci_register_vga(pd, &alias_vga[QEMU_PCI_VGA_MEM],
- &alias_vga[QEMU_PCI_VGA_IO_LO],
- &alias_vga[QEMU_PCI_VGA_IO_HI]);
- }
-}
-
-static PCIBridgeWindows *pci_bridge_region_init(PCIBridge *br)
-{
- PCIDevice *pd = PCI_DEVICE(br);
- PCIBus *parent = pd->bus;
- PCIBridgeWindows *w = g_new(PCIBridgeWindows, 1);
- uint16_t cmd = pci_get_word(pd->config + PCI_COMMAND);
-
- pci_bridge_init_alias(br, &w->alias_pref_mem,
- PCI_BASE_ADDRESS_MEM_PREFETCH,
- "pci_bridge_pref_mem",
- &br->address_space_mem,
- parent->address_space_mem,
- cmd & PCI_COMMAND_MEMORY);
- pci_bridge_init_alias(br, &w->alias_mem,
- PCI_BASE_ADDRESS_SPACE_MEMORY,
- "pci_bridge_mem",
- &br->address_space_mem,
- parent->address_space_mem,
- cmd & PCI_COMMAND_MEMORY);
- pci_bridge_init_alias(br, &w->alias_io,
- PCI_BASE_ADDRESS_SPACE_IO,
- "pci_bridge_io",
- &br->address_space_io,
- parent->address_space_io,
- cmd & PCI_COMMAND_IO);
-
- pci_bridge_init_vga_aliases(br, parent, w->alias_vga);
-
- return w;
-}
-
-static void pci_bridge_region_del(PCIBridge *br, PCIBridgeWindows *w)
-{
- PCIDevice *pd = PCI_DEVICE(br);
- PCIBus *parent = pd->bus;
-
- memory_region_del_subregion(parent->address_space_io, &w->alias_io);
- memory_region_del_subregion(parent->address_space_mem, &w->alias_mem);
- memory_region_del_subregion(parent->address_space_mem, &w->alias_pref_mem);
- pci_unregister_vga(pd);
-}
-
-static void pci_bridge_region_cleanup(PCIBridge *br, PCIBridgeWindows *w)
-{
- object_unparent(OBJECT(&w->alias_io));
- object_unparent(OBJECT(&w->alias_mem));
- object_unparent(OBJECT(&w->alias_pref_mem));
- object_unparent(OBJECT(&w->alias_vga[QEMU_PCI_VGA_IO_LO]));
- object_unparent(OBJECT(&w->alias_vga[QEMU_PCI_VGA_IO_HI]));
- object_unparent(OBJECT(&w->alias_vga[QEMU_PCI_VGA_MEM]));
- g_free(w);
-}
-
-void pci_bridge_update_mappings(PCIBridge *br)
-{
- PCIBridgeWindows *w = br->windows;
-
- /* Make updates atomic to: handle the case of one VCPU updating the bridge
- * while another accesses an unaffected region. */
- memory_region_transaction_begin();
- pci_bridge_region_del(br, br->windows);
- br->windows = pci_bridge_region_init(br);
- memory_region_transaction_commit();
- pci_bridge_region_cleanup(br, w);
-}
-
-/* default write_config function for PCI-to-PCI bridge */
-void pci_bridge_write_config(PCIDevice *d,
- uint32_t address, uint32_t val, int len)
-{
- PCIBridge *s = PCI_BRIDGE(d);
- uint16_t oldctl = pci_get_word(d->config + PCI_BRIDGE_CONTROL);
- uint16_t newctl;
-
- pci_default_write_config(d, address, val, len);
-
- if (ranges_overlap(address, len, PCI_COMMAND, 2) ||
-
- /* io base/limit */
- ranges_overlap(address, len, PCI_IO_BASE, 2) ||
-
- /* memory base/limit, prefetchable base/limit and
- io base/limit upper 16 */
- ranges_overlap(address, len, PCI_MEMORY_BASE, 20) ||
-
- /* vga enable */
- ranges_overlap(address, len, PCI_BRIDGE_CONTROL, 2)) {
- pci_bridge_update_mappings(s);
- }
-
- newctl = pci_get_word(d->config + PCI_BRIDGE_CONTROL);
- if (~oldctl & newctl & PCI_BRIDGE_CTL_BUS_RESET) {
- /* Trigger hot reset on 0->1 transition. */
- qbus_reset_all(&s->sec_bus.qbus);
- }
-}
-
-void pci_bridge_disable_base_limit(PCIDevice *dev)
-{
- uint8_t *conf = dev->config;
-
- pci_byte_test_and_set_mask(conf + PCI_IO_BASE,
- PCI_IO_RANGE_MASK & 0xff);
- pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT,
- PCI_IO_RANGE_MASK & 0xff);
- pci_word_test_and_set_mask(conf + PCI_MEMORY_BASE,
- PCI_MEMORY_RANGE_MASK & 0xffff);
- pci_word_test_and_clear_mask(conf + PCI_MEMORY_LIMIT,
- PCI_MEMORY_RANGE_MASK & 0xffff);
- pci_word_test_and_set_mask(conf + PCI_PREF_MEMORY_BASE,
- PCI_PREF_RANGE_MASK & 0xffff);
- pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_LIMIT,
- PCI_PREF_RANGE_MASK & 0xffff);
- pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0);
- pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0);
-}
-
-/* reset bridge specific configuration registers */
-void pci_bridge_reset(DeviceState *qdev)
-{
- PCIDevice *dev = PCI_DEVICE(qdev);
- uint8_t *conf = dev->config;
-
- conf[PCI_PRIMARY_BUS] = 0;
- conf[PCI_SECONDARY_BUS] = 0;
- conf[PCI_SUBORDINATE_BUS] = 0;
- conf[PCI_SEC_LATENCY_TIMER] = 0;
-
- /*
- * the default values for base/limit registers aren't specified
- * in the PCI-to-PCI-bridge spec. So we don't thouch them here.
- * Each implementation can override it.
- * typical implementation does
- * zero base/limit registers or
- * disable forwarding: pci_bridge_disable_base_limit()
- * If disable forwarding is wanted, call pci_bridge_disable_base_limit()
- * after this function.
- */
- pci_byte_test_and_clear_mask(conf + PCI_IO_BASE,
- PCI_IO_RANGE_MASK & 0xff);
- pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT,
- PCI_IO_RANGE_MASK & 0xff);
- pci_word_test_and_clear_mask(conf + PCI_MEMORY_BASE,
- PCI_MEMORY_RANGE_MASK & 0xffff);
- pci_word_test_and_clear_mask(conf + PCI_MEMORY_LIMIT,
- PCI_MEMORY_RANGE_MASK & 0xffff);
- pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_BASE,
- PCI_PREF_RANGE_MASK & 0xffff);
- pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_LIMIT,
- PCI_PREF_RANGE_MASK & 0xffff);
- pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0);
- pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0);
-
- pci_set_word(conf + PCI_BRIDGE_CONTROL, 0);
-}
-
-/* default qdev initialization function for PCI-to-PCI bridge */
-void pci_bridge_initfn(PCIDevice *dev, const char *typename)
-{
- PCIBus *parent = dev->bus;
- PCIBridge *br = PCI_BRIDGE(dev);
- PCIBus *sec_bus = &br->sec_bus;
-
- pci_word_test_and_set_mask(dev->config + PCI_STATUS,
- PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
-
- /*
- * TODO: We implement VGA Enable in the Bridge Control Register
- * therefore per the PCI to PCI bridge spec we must also implement
- * VGA Palette Snooping. When done, set this bit writable:
- *
- * pci_word_test_and_set_mask(dev->wmask + PCI_COMMAND,
- * PCI_COMMAND_VGA_PALETTE);
- */
-
- pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_PCI);
- dev->config[PCI_HEADER_TYPE] =
- (dev->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTION) |
- PCI_HEADER_TYPE_BRIDGE;
- pci_set_word(dev->config + PCI_SEC_STATUS,
- PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
-
- /*
- * If we don't specify the name, the bus will be addressed as <id>.0, where
- * id is the device id.
- * Since PCI Bridge devices have a single bus each, we don't need the index:
- * let users address the bus using the device name.
- */
- if (!br->bus_name && dev->qdev.id && *dev->qdev.id) {
- br->bus_name = dev->qdev.id;
- }
-
- qbus_create_inplace(sec_bus, sizeof(br->sec_bus), typename, DEVICE(dev),
- br->bus_name);
- sec_bus->parent_dev = dev;
- sec_bus->map_irq = br->map_irq ? br->map_irq : pci_swizzle_map_irq_fn;
- sec_bus->address_space_mem = &br->address_space_mem;
- memory_region_init(&br->address_space_mem, OBJECT(br), "pci_bridge_pci", UINT64_MAX);
- sec_bus->address_space_io = &br->address_space_io;
- memory_region_init(&br->address_space_io, OBJECT(br), "pci_bridge_io", 65536);
- br->windows = pci_bridge_region_init(br);
- QLIST_INIT(&sec_bus->child);
- QLIST_INSERT_HEAD(&parent->child, sec_bus, sibling);
-}
-
-/* default qdev clean up function for PCI-to-PCI bridge */
-void pci_bridge_exitfn(PCIDevice *pci_dev)
-{
- PCIBridge *s = PCI_BRIDGE(pci_dev);
- assert(QLIST_EMPTY(&s->sec_bus.child));
- QLIST_REMOVE(&s->sec_bus, sibling);
- pci_bridge_region_del(s, s->windows);
- pci_bridge_region_cleanup(s, s->windows);
- /* object_unparent() is called automatically during device deletion */
-}
-
-/*
- * before qdev initialization(qdev_init()), this function sets bus_name and
- * map_irq callback which are necessry for pci_bridge_initfn() to
- * initialize bus.
- */
-void pci_bridge_map_irq(PCIBridge *br, const char* bus_name,
- pci_map_irq_fn map_irq)
-{
- br->map_irq = map_irq;
- br->bus_name = bus_name;
-}
-
-static const TypeInfo pci_bridge_type_info = {
- .name = TYPE_PCI_BRIDGE,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(PCIBridge),
- .abstract = true,
-};
-
-static void pci_bridge_register_types(void)
-{
- type_register_static(&pci_bridge_type_info);
-}
-
-type_init(pci_bridge_register_types)
diff --git a/qemu/hw/pci/pci_host.c b/qemu/hw/pci/pci_host.c
deleted file mode 100644
index 5eaa935cb..000000000
--- a/qemu/hw/pci/pci_host.c
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * pci_host.c
- *
- * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
- * VA Linux Systems Japan K.K.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/pci_host.h"
-#include "hw/pci/pci_bus.h"
-#include "trace.h"
-
-/* debug PCI */
-//#define DEBUG_PCI
-
-#ifdef DEBUG_PCI
-#define PCI_DPRINTF(fmt, ...) \
-do { printf("pci_host_data: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define PCI_DPRINTF(fmt, ...)
-#endif
-
-/*
- * PCI address
- * bit 16 - 24: bus number
- * bit 8 - 15: devfun number
- * bit 0 - 7: offset in configuration space of a given pci device
- */
-
-/* the helper function to get a PCIDevice* for a given pci address */
-static inline PCIDevice *pci_dev_find_by_addr(PCIBus *bus, uint32_t addr)
-{
- uint8_t bus_num = addr >> 16;
- uint8_t devfn = addr >> 8;
-
- return pci_find_device(bus, bus_num, devfn);
-}
-
-void pci_host_config_write_common(PCIDevice *pci_dev, uint32_t addr,
- uint32_t limit, uint32_t val, uint32_t len)
-{
- assert(len <= 4);
- /* non-zero functions are only exposed when function 0 is present,
- * allowing direct removal of unexposed functions.
- */
- if (pci_dev->qdev.hotplugged && !pci_get_function_0(pci_dev)) {
- return;
- }
-
- trace_pci_cfg_write(pci_dev->name, PCI_SLOT(pci_dev->devfn),
- PCI_FUNC(pci_dev->devfn), addr, val);
- pci_dev->config_write(pci_dev, addr, val, MIN(len, limit - addr));
-}
-
-uint32_t pci_host_config_read_common(PCIDevice *pci_dev, uint32_t addr,
- uint32_t limit, uint32_t len)
-{
- uint32_t ret;
-
- assert(len <= 4);
- /* non-zero functions are only exposed when function 0 is present,
- * allowing direct removal of unexposed functions.
- */
- if (pci_dev->qdev.hotplugged && !pci_get_function_0(pci_dev)) {
- return ~0x0;
- }
-
- ret = pci_dev->config_read(pci_dev, addr, MIN(len, limit - addr));
- trace_pci_cfg_read(pci_dev->name, PCI_SLOT(pci_dev->devfn),
- PCI_FUNC(pci_dev->devfn), addr, ret);
-
- return ret;
-}
-
-void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, int len)
-{
- PCIDevice *pci_dev = pci_dev_find_by_addr(s, addr);
- uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1);
-
- if (!pci_dev) {
- return;
- }
-
- PCI_DPRINTF("%s: %s: addr=%02" PRIx32 " val=%08" PRIx32 " len=%d\n",
- __func__, pci_dev->name, config_addr, val, len);
- pci_host_config_write_common(pci_dev, config_addr, PCI_CONFIG_SPACE_SIZE,
- val, len);
-}
-
-uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len)
-{
- PCIDevice *pci_dev = pci_dev_find_by_addr(s, addr);
- uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1);
- uint32_t val;
-
- if (!pci_dev) {
- return ~0x0;
- }
-
- val = pci_host_config_read_common(pci_dev, config_addr,
- PCI_CONFIG_SPACE_SIZE, len);
- PCI_DPRINTF("%s: %s: addr=%02"PRIx32" val=%08"PRIx32" len=%d\n",
- __func__, pci_dev->name, config_addr, val, len);
-
- return val;
-}
-
-static void pci_host_config_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned len)
-{
- PCIHostState *s = opaque;
-
- PCI_DPRINTF("%s addr " TARGET_FMT_plx " len %d val %"PRIx64"\n",
- __func__, addr, len, val);
- if (addr != 0 || len != 4) {
- return;
- }
- s->config_reg = val;
-}
-
-static uint64_t pci_host_config_read(void *opaque, hwaddr addr,
- unsigned len)
-{
- PCIHostState *s = opaque;
- uint32_t val = s->config_reg;
-
- PCI_DPRINTF("%s addr " TARGET_FMT_plx " len %d val %"PRIx32"\n",
- __func__, addr, len, val);
- return val;
-}
-
-static void pci_host_data_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned len)
-{
- PCIHostState *s = opaque;
- PCI_DPRINTF("write addr " TARGET_FMT_plx " len %d val %x\n",
- addr, len, (unsigned)val);
- if (s->config_reg & (1u << 31))
- pci_data_write(s->bus, s->config_reg | (addr & 3), val, len);
-}
-
-static uint64_t pci_host_data_read(void *opaque,
- hwaddr addr, unsigned len)
-{
- PCIHostState *s = opaque;
- uint32_t val;
- if (!(s->config_reg & (1U << 31))) {
- return 0xffffffff;
- }
- val = pci_data_read(s->bus, s->config_reg | (addr & 3), len);
- PCI_DPRINTF("read addr " TARGET_FMT_plx " len %d val %x\n",
- addr, len, val);
- return val;
-}
-
-const MemoryRegionOps pci_host_conf_le_ops = {
- .read = pci_host_config_read,
- .write = pci_host_config_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-const MemoryRegionOps pci_host_conf_be_ops = {
- .read = pci_host_config_read,
- .write = pci_host_config_write,
- .endianness = DEVICE_BIG_ENDIAN,
-};
-
-const MemoryRegionOps pci_host_data_le_ops = {
- .read = pci_host_data_read,
- .write = pci_host_data_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-const MemoryRegionOps pci_host_data_be_ops = {
- .read = pci_host_data_read,
- .write = pci_host_data_write,
- .endianness = DEVICE_BIG_ENDIAN,
-};
-
-static const TypeInfo pci_host_type_info = {
- .name = TYPE_PCI_HOST_BRIDGE,
- .parent = TYPE_SYS_BUS_DEVICE,
- .abstract = true,
- .class_size = sizeof(PCIHostBridgeClass),
- .instance_size = sizeof(PCIHostState),
-};
-
-static void pci_host_register_types(void)
-{
- type_register_static(&pci_host_type_info);
-}
-
-type_init(pci_host_register_types)
diff --git a/qemu/hw/pci/pcie.c b/qemu/hw/pci/pcie.c
deleted file mode 100644
index 728386ada..000000000
--- a/qemu/hw/pci/pcie.c
+++ /dev/null
@@ -1,649 +0,0 @@
-/*
- * pcie.c
- *
- * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
- * VA Linux Systems Japan K.K.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "hw/pci/pci_bridge.h"
-#include "hw/pci/pcie.h"
-#include "hw/pci/msix.h"
-#include "hw/pci/msi.h"
-#include "hw/pci/pci_bus.h"
-#include "hw/pci/pcie_regs.h"
-#include "qemu/range.h"
-
-//#define DEBUG_PCIE
-#ifdef DEBUG_PCIE
-# define PCIE_DPRINTF(fmt, ...) \
- fprintf(stderr, "%s:%d " fmt, __func__, __LINE__, ## __VA_ARGS__)
-#else
-# define PCIE_DPRINTF(fmt, ...) do {} while (0)
-#endif
-#define PCIE_DEV_PRINTF(dev, fmt, ...) \
- PCIE_DPRINTF("%s:%x "fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__)
-
-
-/***************************************************************************
- * pci express capability helper functions
- */
-int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port)
-{
- int pos;
- uint8_t *exp_cap;
-
- assert(pci_is_express(dev));
-
- pos = pci_add_capability(dev, PCI_CAP_ID_EXP, offset,
- PCI_EXP_VER2_SIZEOF);
- if (pos < 0) {
- return pos;
- }
- dev->exp.exp_cap = pos;
- exp_cap = dev->config + pos;
-
- /* capability register
- interrupt message number defaults to 0 */
- pci_set_word(exp_cap + PCI_EXP_FLAGS,
- ((type << PCI_EXP_FLAGS_TYPE_SHIFT) & PCI_EXP_FLAGS_TYPE) |
- PCI_EXP_FLAGS_VER2);
-
- /* device capability register
- * table 7-12:
- * roll based error reporting bit must be set by all
- * Functions conforming to the ECN, PCI Express Base
- * Specification, Revision 1.1., or subsequent PCI Express Base
- * Specification revisions.
- */
- pci_set_long(exp_cap + PCI_EXP_DEVCAP, PCI_EXP_DEVCAP_RBER);
-
- pci_set_long(exp_cap + PCI_EXP_LNKCAP,
- (port << PCI_EXP_LNKCAP_PN_SHIFT) |
- PCI_EXP_LNKCAP_ASPMS_0S |
- PCI_EXP_LNK_MLW_1 |
- PCI_EXP_LNK_LS_25);
-
- pci_set_word(exp_cap + PCI_EXP_LNKSTA,
- PCI_EXP_LNK_MLW_1 | PCI_EXP_LNK_LS_25 |PCI_EXP_LNKSTA_DLLLA);
-
- pci_set_long(exp_cap + PCI_EXP_DEVCAP2,
- PCI_EXP_DEVCAP2_EFF | PCI_EXP_DEVCAP2_EETLPP);
-
- pci_set_word(dev->wmask + pos + PCI_EXP_DEVCTL2, PCI_EXP_DEVCTL2_EETLPPB);
- return pos;
-}
-
-int pcie_endpoint_cap_init(PCIDevice *dev, uint8_t offset)
-{
- uint8_t type = PCI_EXP_TYPE_ENDPOINT;
-
- /*
- * Windows guests will report Code 10, device cannot start, if
- * a regular Endpoint type is exposed on a root complex. These
- * should instead be Root Complex Integrated Endpoints.
- */
- if (pci_bus_is_express(dev->bus) && pci_bus_is_root(dev->bus)) {
- type = PCI_EXP_TYPE_RC_END;
- }
-
- return pcie_cap_init(dev, offset, type, 0);
-}
-
-void pcie_cap_exit(PCIDevice *dev)
-{
- pci_del_capability(dev, PCI_CAP_ID_EXP, PCI_EXP_VER2_SIZEOF);
-}
-
-uint8_t pcie_cap_get_type(const PCIDevice *dev)
-{
- uint32_t pos = dev->exp.exp_cap;
- assert(pos > 0);
- return (pci_get_word(dev->config + pos + PCI_EXP_FLAGS) &
- PCI_EXP_FLAGS_TYPE) >> PCI_EXP_FLAGS_TYPE_SHIFT;
-}
-
-/* MSI/MSI-X */
-/* pci express interrupt message number */
-/* 7.8.2 PCI Express Capabilities Register: Interrupt Message Number */
-void pcie_cap_flags_set_vector(PCIDevice *dev, uint8_t vector)
-{
- uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
- assert(vector < 32);
- pci_word_test_and_clear_mask(exp_cap + PCI_EXP_FLAGS, PCI_EXP_FLAGS_IRQ);
- pci_word_test_and_set_mask(exp_cap + PCI_EXP_FLAGS,
- vector << PCI_EXP_FLAGS_IRQ_SHIFT);
-}
-
-uint8_t pcie_cap_flags_get_vector(PCIDevice *dev)
-{
- return (pci_get_word(dev->config + dev->exp.exp_cap + PCI_EXP_FLAGS) &
- PCI_EXP_FLAGS_IRQ) >> PCI_EXP_FLAGS_IRQ_SHIFT;
-}
-
-void pcie_cap_deverr_init(PCIDevice *dev)
-{
- uint32_t pos = dev->exp.exp_cap;
- pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_DEVCAP,
- PCI_EXP_DEVCAP_RBER);
- pci_long_test_and_set_mask(dev->wmask + pos + PCI_EXP_DEVCTL,
- PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE |
- PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE);
- pci_long_test_and_set_mask(dev->w1cmask + pos + PCI_EXP_DEVSTA,
- PCI_EXP_DEVSTA_CED | PCI_EXP_DEVSTA_NFED |
- PCI_EXP_DEVSTA_FED | PCI_EXP_DEVSTA_URD);
-}
-
-void pcie_cap_deverr_reset(PCIDevice *dev)
-{
- uint8_t *devctl = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL;
- pci_long_test_and_clear_mask(devctl,
- PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE |
- PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE);
-}
-
-static void hotplug_event_update_event_status(PCIDevice *dev)
-{
- uint32_t pos = dev->exp.exp_cap;
- uint8_t *exp_cap = dev->config + pos;
- uint16_t sltctl = pci_get_word(exp_cap + PCI_EXP_SLTCTL);
- uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
-
- dev->exp.hpev_notified = (sltctl & PCI_EXP_SLTCTL_HPIE) &&
- (sltsta & sltctl & PCI_EXP_HP_EV_SUPPORTED);
-}
-
-static void hotplug_event_notify(PCIDevice *dev)
-{
- bool prev = dev->exp.hpev_notified;
-
- hotplug_event_update_event_status(dev);
-
- if (prev == dev->exp.hpev_notified) {
- return;
- }
-
- /* Note: the logic above does not take into account whether interrupts
- * are masked. The result is that interrupt will be sent when it is
- * subsequently unmasked. This appears to be legal: Section 6.7.3.4:
- * The Port may optionally send an MSI when there are hot-plug events that
- * occur while interrupt generation is disabled, and interrupt generation is
- * subsequently enabled. */
- if (msix_enabled(dev)) {
- msix_notify(dev, pcie_cap_flags_get_vector(dev));
- } else if (msi_enabled(dev)) {
- msi_notify(dev, pcie_cap_flags_get_vector(dev));
- } else {
- pci_set_irq(dev, dev->exp.hpev_notified);
- }
-}
-
-static void hotplug_event_clear(PCIDevice *dev)
-{
- hotplug_event_update_event_status(dev);
- if (!msix_enabled(dev) && !msi_enabled(dev) && !dev->exp.hpev_notified) {
- pci_irq_deassert(dev);
- }
-}
-
-/*
- * A PCI Express Hot-Plug Event has occurred, so update slot status register
- * and notify OS of the event if necessary.
- *
- * 6.7.3 PCI Express Hot-Plug Events
- * 6.7.3.4 Software Notification of Hot-Plug Events
- */
-static void pcie_cap_slot_event(PCIDevice *dev, PCIExpressHotPlugEvent event)
-{
- /* Minor optimization: if nothing changed - no event is needed. */
- if (pci_word_test_and_set_mask(dev->config + dev->exp.exp_cap +
- PCI_EXP_SLTSTA, event)) {
- return;
- }
- hotplug_event_notify(dev);
-}
-
-static void pcie_cap_slot_hotplug_common(PCIDevice *hotplug_dev,
- DeviceState *dev,
- uint8_t **exp_cap, Error **errp)
-{
- *exp_cap = hotplug_dev->config + hotplug_dev->exp.exp_cap;
- uint16_t sltsta = pci_get_word(*exp_cap + PCI_EXP_SLTSTA);
-
- PCIE_DEV_PRINTF(PCI_DEVICE(dev), "hotplug state: 0x%x\n", sltsta);
- if (sltsta & PCI_EXP_SLTSTA_EIS) {
- /* the slot is electromechanically locked.
- * This error is propagated up to qdev and then to HMP/QMP.
- */
- error_setg_errno(errp, EBUSY, "slot is electromechanically locked");
- }
-}
-
-void pcie_cap_slot_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
- Error **errp)
-{
- uint8_t *exp_cap;
- PCIDevice *pci_dev = PCI_DEVICE(dev);
-
- pcie_cap_slot_hotplug_common(PCI_DEVICE(hotplug_dev), dev, &exp_cap, errp);
-
- /* Don't send event when device is enabled during qemu machine creation:
- * it is present on boot, no hotplug event is necessary. We do send an
- * event when the device is disabled later. */
- if (!dev->hotplugged) {
- pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
- PCI_EXP_SLTSTA_PDS);
- return;
- }
-
- /* To enable multifunction hot-plug, we just ensure the function
- * 0 added last. When function 0 is added, we set the sltsta and
- * inform OS via event notification.
- */
- if (pci_get_function_0(pci_dev)) {
- pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
- PCI_EXP_SLTSTA_PDS);
- pcie_cap_slot_event(PCI_DEVICE(hotplug_dev),
- PCI_EXP_HP_EV_PDC | PCI_EXP_HP_EV_ABP);
- }
-}
-
-static void pcie_unplug_device(PCIBus *bus, PCIDevice *dev, void *opaque)
-{
- object_unparent(OBJECT(dev));
-}
-
-void pcie_cap_slot_hot_unplug_request_cb(HotplugHandler *hotplug_dev,
- DeviceState *dev, Error **errp)
-{
- uint8_t *exp_cap;
- PCIDevice *pci_dev = PCI_DEVICE(dev);
- PCIBus *bus = pci_dev->bus;
-
- pcie_cap_slot_hotplug_common(PCI_DEVICE(hotplug_dev), dev, &exp_cap, errp);
-
- /* In case user cancel the operation of multi-function hot-add,
- * remove the function that is unexposed to guest individually,
- * without interaction with guest.
- */
- if (pci_dev->devfn &&
- !bus->devices[0]) {
- pcie_unplug_device(bus, pci_dev, NULL);
-
- return;
- }
-
- pcie_cap_slot_push_attention_button(PCI_DEVICE(hotplug_dev));
-}
-
-/* pci express slot for pci express root/downstream port
- PCI express capability slot registers */
-void pcie_cap_slot_init(PCIDevice *dev, uint16_t slot)
-{
- uint32_t pos = dev->exp.exp_cap;
-
- pci_word_test_and_set_mask(dev->config + pos + PCI_EXP_FLAGS,
- PCI_EXP_FLAGS_SLOT);
-
- pci_long_test_and_clear_mask(dev->config + pos + PCI_EXP_SLTCAP,
- ~PCI_EXP_SLTCAP_PSN);
- pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_SLTCAP,
- (slot << PCI_EXP_SLTCAP_PSN_SHIFT) |
- PCI_EXP_SLTCAP_EIP |
- PCI_EXP_SLTCAP_HPS |
- PCI_EXP_SLTCAP_HPC |
- PCI_EXP_SLTCAP_PIP |
- PCI_EXP_SLTCAP_AIP |
- PCI_EXP_SLTCAP_ABP);
-
- if (dev->cap_present & QEMU_PCIE_SLTCAP_PCP) {
- pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_SLTCAP,
- PCI_EXP_SLTCAP_PCP);
- pci_word_test_and_clear_mask(dev->config + pos + PCI_EXP_SLTCTL,
- PCI_EXP_SLTCTL_PCC);
- pci_word_test_and_set_mask(dev->wmask + pos + PCI_EXP_SLTCTL,
- PCI_EXP_SLTCTL_PCC);
- }
-
- pci_word_test_and_clear_mask(dev->config + pos + PCI_EXP_SLTCTL,
- PCI_EXP_SLTCTL_PIC |
- PCI_EXP_SLTCTL_AIC);
- pci_word_test_and_set_mask(dev->config + pos + PCI_EXP_SLTCTL,
- PCI_EXP_SLTCTL_PIC_OFF |
- PCI_EXP_SLTCTL_AIC_OFF);
- pci_word_test_and_set_mask(dev->wmask + pos + PCI_EXP_SLTCTL,
- PCI_EXP_SLTCTL_PIC |
- PCI_EXP_SLTCTL_AIC |
- PCI_EXP_SLTCTL_HPIE |
- PCI_EXP_SLTCTL_CCIE |
- PCI_EXP_SLTCTL_PDCE |
- PCI_EXP_SLTCTL_ABPE);
- /* Although reading PCI_EXP_SLTCTL_EIC returns always 0,
- * make the bit writable here in order to detect 1b is written.
- * pcie_cap_slot_write_config() test-and-clear the bit, so
- * this bit always returns 0 to the guest.
- */
- pci_word_test_and_set_mask(dev->wmask + pos + PCI_EXP_SLTCTL,
- PCI_EXP_SLTCTL_EIC);
-
- pci_word_test_and_set_mask(dev->w1cmask + pos + PCI_EXP_SLTSTA,
- PCI_EXP_HP_EV_SUPPORTED);
-
- dev->exp.hpev_notified = false;
-
- qbus_set_hotplug_handler(BUS(pci_bridge_get_sec_bus(PCI_BRIDGE(dev))),
- DEVICE(dev), NULL);
-}
-
-void pcie_cap_slot_reset(PCIDevice *dev)
-{
- uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
- uint8_t port_type = pcie_cap_get_type(dev);
-
- assert(port_type == PCI_EXP_TYPE_DOWNSTREAM ||
- port_type == PCI_EXP_TYPE_ROOT_PORT);
-
- PCIE_DEV_PRINTF(dev, "reset\n");
-
- pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTCTL,
- PCI_EXP_SLTCTL_EIC |
- PCI_EXP_SLTCTL_PIC |
- PCI_EXP_SLTCTL_AIC |
- PCI_EXP_SLTCTL_HPIE |
- PCI_EXP_SLTCTL_CCIE |
- PCI_EXP_SLTCTL_PDCE |
- PCI_EXP_SLTCTL_ABPE);
- pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTCTL,
- PCI_EXP_SLTCTL_AIC_OFF);
-
- if (dev->cap_present & QEMU_PCIE_SLTCAP_PCP) {
- /* Downstream ports enforce device number 0. */
- bool populated = pci_bridge_get_sec_bus(PCI_BRIDGE(dev))->devices[0];
- uint16_t pic;
-
- if (populated) {
- pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTCTL,
- PCI_EXP_SLTCTL_PCC);
- } else {
- pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTCTL,
- PCI_EXP_SLTCTL_PCC);
- }
-
- pic = populated ? PCI_EXP_SLTCTL_PIC_ON : PCI_EXP_SLTCTL_PIC_OFF;
- pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTCTL, pic);
- }
-
- pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA,
- PCI_EXP_SLTSTA_EIS |/* on reset,
- the lock is released */
- PCI_EXP_SLTSTA_CC |
- PCI_EXP_SLTSTA_PDC |
- PCI_EXP_SLTSTA_ABP);
-
- hotplug_event_update_event_status(dev);
-}
-
-void pcie_cap_slot_write_config(PCIDevice *dev,
- uint32_t addr, uint32_t val, int len)
-{
- uint32_t pos = dev->exp.exp_cap;
- uint8_t *exp_cap = dev->config + pos;
- uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
-
- if (ranges_overlap(addr, len, pos + PCI_EXP_SLTSTA, 2)) {
- hotplug_event_clear(dev);
- }
-
- if (!ranges_overlap(addr, len, pos + PCI_EXP_SLTCTL, 2)) {
- return;
- }
-
- if (pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTCTL,
- PCI_EXP_SLTCTL_EIC)) {
- sltsta ^= PCI_EXP_SLTSTA_EIS; /* toggle PCI_EXP_SLTSTA_EIS bit */
- pci_set_word(exp_cap + PCI_EXP_SLTSTA, sltsta);
- PCIE_DEV_PRINTF(dev, "PCI_EXP_SLTCTL_EIC: "
- "sltsta -> 0x%02"PRIx16"\n",
- sltsta);
- }
-
- /*
- * If the slot is polulated, power indicator is off and power
- * controller is off, it is safe to detach the devices.
- */
- if ((sltsta & PCI_EXP_SLTSTA_PDS) && (val & PCI_EXP_SLTCTL_PCC) &&
- ((val & PCI_EXP_SLTCTL_PIC_OFF) == PCI_EXP_SLTCTL_PIC_OFF)) {
- PCIBus *sec_bus = pci_bridge_get_sec_bus(PCI_BRIDGE(dev));
- pci_for_each_device(sec_bus, pci_bus_num(sec_bus),
- pcie_unplug_device, NULL);
-
- pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA,
- PCI_EXP_SLTSTA_PDS);
- pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
- PCI_EXP_SLTSTA_PDC);
- }
-
- hotplug_event_notify(dev);
-
- /*
- * 6.7.3.2 Command Completed Events
- *
- * Software issues a command to a hot-plug capable Downstream Port by
- * issuing a write transaction that targets any portion of the Port’s Slot
- * Control register. A single write to the Slot Control register is
- * considered to be a single command, even if the write affects more than
- * one field in the Slot Control register. In response to this transaction,
- * the Port must carry out the requested actions and then set the
- * associated status field for the command completed event. */
-
- /* Real hardware might take a while to complete requested command because
- * physical movement would be involved like locking the electromechanical
- * lock. However in our case, command is completed instantaneously above,
- * so send a command completion event right now.
- */
- pcie_cap_slot_event(dev, PCI_EXP_HP_EV_CCI);
-}
-
-int pcie_cap_slot_post_load(void *opaque, int version_id)
-{
- PCIDevice *dev = opaque;
- hotplug_event_update_event_status(dev);
- return 0;
-}
-
-void pcie_cap_slot_push_attention_button(PCIDevice *dev)
-{
- pcie_cap_slot_event(dev, PCI_EXP_HP_EV_ABP);
-}
-
-/* root control/capabilities/status. PME isn't emulated for now */
-void pcie_cap_root_init(PCIDevice *dev)
-{
- pci_set_word(dev->wmask + dev->exp.exp_cap + PCI_EXP_RTCTL,
- PCI_EXP_RTCTL_SECEE | PCI_EXP_RTCTL_SENFEE |
- PCI_EXP_RTCTL_SEFEE);
-}
-
-void pcie_cap_root_reset(PCIDevice *dev)
-{
- pci_set_word(dev->config + dev->exp.exp_cap + PCI_EXP_RTCTL, 0);
-}
-
-/* function level reset(FLR) */
-void pcie_cap_flr_init(PCIDevice *dev)
-{
- pci_long_test_and_set_mask(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCAP,
- PCI_EXP_DEVCAP_FLR);
-
- /* Although reading BCR_FLR returns always 0,
- * the bit is made writable here in order to detect the 1b is written
- * pcie_cap_flr_write_config() test-and-clear the bit, so
- * this bit always returns 0 to the guest.
- */
- pci_word_test_and_set_mask(dev->wmask + dev->exp.exp_cap + PCI_EXP_DEVCTL,
- PCI_EXP_DEVCTL_BCR_FLR);
-}
-
-void pcie_cap_flr_write_config(PCIDevice *dev,
- uint32_t addr, uint32_t val, int len)
-{
- uint8_t *devctl = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL;
- if (pci_get_word(devctl) & PCI_EXP_DEVCTL_BCR_FLR) {
- /* Clear PCI_EXP_DEVCTL_BCR_FLR after invoking the reset handler
- so the handler can detect FLR by looking at this bit. */
- pci_device_reset(dev);
- pci_word_test_and_clear_mask(devctl, PCI_EXP_DEVCTL_BCR_FLR);
- }
-}
-
-/* Alternative Routing-ID Interpretation (ARI)
- * forwarding support for root and downstream ports
- */
-void pcie_cap_arifwd_init(PCIDevice *dev)
-{
- uint32_t pos = dev->exp.exp_cap;
- pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_DEVCAP2,
- PCI_EXP_DEVCAP2_ARI);
- pci_long_test_and_set_mask(dev->wmask + pos + PCI_EXP_DEVCTL2,
- PCI_EXP_DEVCTL2_ARI);
-}
-
-void pcie_cap_arifwd_reset(PCIDevice *dev)
-{
- uint8_t *devctl2 = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL2;
- pci_long_test_and_clear_mask(devctl2, PCI_EXP_DEVCTL2_ARI);
-}
-
-bool pcie_cap_is_arifwd_enabled(const PCIDevice *dev)
-{
- if (!pci_is_express(dev)) {
- return false;
- }
- if (!dev->exp.exp_cap) {
- return false;
- }
-
- return pci_get_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL2) &
- PCI_EXP_DEVCTL2_ARI;
-}
-
-/**************************************************************************
- * pci express extended capability list management functions
- * uint16_t ext_cap_id (16 bit)
- * uint8_t cap_ver (4 bit)
- * uint16_t cap_offset (12 bit)
- * uint16_t ext_cap_size
- */
-
-static uint16_t pcie_find_capability_list(PCIDevice *dev, uint16_t cap_id,
- uint16_t *prev_p)
-{
- uint16_t prev = 0;
- uint16_t next;
- uint32_t header = pci_get_long(dev->config + PCI_CONFIG_SPACE_SIZE);
-
- if (!header) {
- /* no extended capability */
- next = 0;
- goto out;
- }
- for (next = PCI_CONFIG_SPACE_SIZE; next;
- prev = next, next = PCI_EXT_CAP_NEXT(header)) {
-
- assert(next >= PCI_CONFIG_SPACE_SIZE);
- assert(next <= PCIE_CONFIG_SPACE_SIZE - 8);
-
- header = pci_get_long(dev->config + next);
- if (PCI_EXT_CAP_ID(header) == cap_id) {
- break;
- }
- }
-
-out:
- if (prev_p) {
- *prev_p = prev;
- }
- return next;
-}
-
-uint16_t pcie_find_capability(PCIDevice *dev, uint16_t cap_id)
-{
- return pcie_find_capability_list(dev, cap_id, NULL);
-}
-
-static void pcie_ext_cap_set_next(PCIDevice *dev, uint16_t pos, uint16_t next)
-{
- uint32_t header = pci_get_long(dev->config + pos);
- assert(!(next & (PCI_EXT_CAP_ALIGN - 1)));
- header = (header & ~PCI_EXT_CAP_NEXT_MASK) |
- ((next << PCI_EXT_CAP_NEXT_SHIFT) & PCI_EXT_CAP_NEXT_MASK);
- pci_set_long(dev->config + pos, header);
-}
-
-/*
- * caller must supply valid (offset, size) * such that the range shouldn't
- * overlap with other capability or other registers.
- * This function doesn't check it.
- */
-void pcie_add_capability(PCIDevice *dev,
- uint16_t cap_id, uint8_t cap_ver,
- uint16_t offset, uint16_t size)
-{
- uint32_t header;
- uint16_t next;
-
- assert(offset >= PCI_CONFIG_SPACE_SIZE);
- assert(offset < offset + size);
- assert(offset + size <= PCIE_CONFIG_SPACE_SIZE);
- assert(size >= 8);
- assert(pci_is_express(dev));
-
- if (offset == PCI_CONFIG_SPACE_SIZE) {
- header = pci_get_long(dev->config + offset);
- next = PCI_EXT_CAP_NEXT(header);
- } else {
- uint16_t prev;
-
- /* 0 is reserved cap id. use internally to find the last capability
- in the linked list */
- next = pcie_find_capability_list(dev, 0, &prev);
-
- assert(prev >= PCI_CONFIG_SPACE_SIZE);
- assert(next == 0);
- pcie_ext_cap_set_next(dev, prev, offset);
- }
- pci_set_long(dev->config + offset, PCI_EXT_CAP(cap_id, cap_ver, next));
-
- /* Make capability read-only by default */
- memset(dev->wmask + offset, 0, size);
- memset(dev->w1cmask + offset, 0, size);
- /* Check capability by default */
- memset(dev->cmask + offset, 0xFF, size);
-}
-
-/**************************************************************************
- * pci express extended capability helper functions
- */
-
-/* ARI */
-void pcie_ari_init(PCIDevice *dev, uint16_t offset, uint16_t nextfn)
-{
- pcie_add_capability(dev, PCI_EXT_CAP_ID_ARI, PCI_ARI_VER,
- offset, PCI_ARI_SIZEOF);
- pci_set_long(dev->config + offset + PCI_ARI_CAP, (nextfn & 0xff) << 8);
-}
diff --git a/qemu/hw/pci/pcie_aer.c b/qemu/hw/pci/pcie_aer.c
deleted file mode 100644
index e2d4e68ba..000000000
--- a/qemu/hw/pci/pcie_aer.c
+++ /dev/null
@@ -1,1039 +0,0 @@
-/*
- * pcie_aer.c
- *
- * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
- * VA Linux Systems Japan K.K.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "sysemu/sysemu.h"
-#include "qapi/qmp/types.h"
-#include "monitor/monitor.h"
-#include "hw/pci/pci_bridge.h"
-#include "hw/pci/pcie.h"
-#include "hw/pci/msix.h"
-#include "hw/pci/msi.h"
-#include "hw/pci/pci_bus.h"
-#include "hw/pci/pcie_regs.h"
-
-//#define DEBUG_PCIE
-#ifdef DEBUG_PCIE
-# define PCIE_DPRINTF(fmt, ...) \
- fprintf(stderr, "%s:%d " fmt, __func__, __LINE__, ## __VA_ARGS__)
-#else
-# define PCIE_DPRINTF(fmt, ...) do {} while (0)
-#endif
-#define PCIE_DEV_PRINTF(dev, fmt, ...) \
- PCIE_DPRINTF("%s:%x "fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__)
-
-#define PCI_ERR_SRC_COR_OFFS 0
-#define PCI_ERR_SRC_UNCOR_OFFS 2
-
-/* From 6.2.7 Error Listing and Rules. Table 6-2, 6-3 and 6-4 */
-static uint32_t pcie_aer_uncor_default_severity(uint32_t status)
-{
- switch (status) {
- case PCI_ERR_UNC_INTN:
- case PCI_ERR_UNC_DLP:
- case PCI_ERR_UNC_SDN:
- case PCI_ERR_UNC_RX_OVER:
- case PCI_ERR_UNC_FCP:
- case PCI_ERR_UNC_MALF_TLP:
- return PCI_ERR_ROOT_CMD_FATAL_EN;
- case PCI_ERR_UNC_POISON_TLP:
- case PCI_ERR_UNC_ECRC:
- case PCI_ERR_UNC_UNSUP:
- case PCI_ERR_UNC_COMP_TIME:
- case PCI_ERR_UNC_COMP_ABORT:
- case PCI_ERR_UNC_UNX_COMP:
- case PCI_ERR_UNC_ACSV:
- case PCI_ERR_UNC_MCBTLP:
- case PCI_ERR_UNC_ATOP_EBLOCKED:
- case PCI_ERR_UNC_TLP_PRF_BLOCKED:
- return PCI_ERR_ROOT_CMD_NONFATAL_EN;
- default:
- abort();
- break;
- }
- return PCI_ERR_ROOT_CMD_FATAL_EN;
-}
-
-static int aer_log_add_err(PCIEAERLog *aer_log, const PCIEAERErr *err)
-{
- if (aer_log->log_num == aer_log->log_max) {
- return -1;
- }
- memcpy(&aer_log->log[aer_log->log_num], err, sizeof *err);
- aer_log->log_num++;
- return 0;
-}
-
-static void aer_log_del_err(PCIEAERLog *aer_log, PCIEAERErr *err)
-{
- assert(aer_log->log_num);
- *err = aer_log->log[0];
- aer_log->log_num--;
- memmove(&aer_log->log[0], &aer_log->log[1],
- aer_log->log_num * sizeof *err);
-}
-
-static void aer_log_clear_all_err(PCIEAERLog *aer_log)
-{
- aer_log->log_num = 0;
-}
-
-int pcie_aer_init(PCIDevice *dev, uint16_t offset, uint16_t size)
-{
- PCIExpressDevice *exp;
-
- pcie_add_capability(dev, PCI_EXT_CAP_ID_ERR, PCI_ERR_VER,
- offset, size);
- exp = &dev->exp;
- exp->aer_cap = offset;
-
- /* log_max is property */
- if (dev->exp.aer_log.log_max == PCIE_AER_LOG_MAX_UNSET) {
- dev->exp.aer_log.log_max = PCIE_AER_LOG_MAX_DEFAULT;
- }
- /* clip down the value to avoid unreasobale memory usage */
- if (dev->exp.aer_log.log_max > PCIE_AER_LOG_MAX_LIMIT) {
- return -EINVAL;
- }
- dev->exp.aer_log.log = g_malloc0(sizeof dev->exp.aer_log.log[0] *
- dev->exp.aer_log.log_max);
-
- pci_set_long(dev->w1cmask + offset + PCI_ERR_UNCOR_STATUS,
- PCI_ERR_UNC_SUPPORTED);
-
- pci_set_long(dev->config + offset + PCI_ERR_UNCOR_SEVER,
- PCI_ERR_UNC_SEVERITY_DEFAULT);
- pci_set_long(dev->wmask + offset + PCI_ERR_UNCOR_SEVER,
- PCI_ERR_UNC_SUPPORTED);
-
- pci_long_test_and_set_mask(dev->w1cmask + offset + PCI_ERR_COR_STATUS,
- PCI_ERR_COR_SUPPORTED);
-
- pci_set_long(dev->config + offset + PCI_ERR_COR_MASK,
- PCI_ERR_COR_MASK_DEFAULT);
- pci_set_long(dev->wmask + offset + PCI_ERR_COR_MASK,
- PCI_ERR_COR_SUPPORTED);
-
- /* capabilities and control. multiple header logging is supported */
- if (dev->exp.aer_log.log_max > 0) {
- pci_set_long(dev->config + offset + PCI_ERR_CAP,
- PCI_ERR_CAP_ECRC_GENC | PCI_ERR_CAP_ECRC_CHKC |
- PCI_ERR_CAP_MHRC);
- pci_set_long(dev->wmask + offset + PCI_ERR_CAP,
- PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE |
- PCI_ERR_CAP_MHRE);
- } else {
- pci_set_long(dev->config + offset + PCI_ERR_CAP,
- PCI_ERR_CAP_ECRC_GENC | PCI_ERR_CAP_ECRC_CHKC);
- pci_set_long(dev->wmask + offset + PCI_ERR_CAP,
- PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE);
- }
-
- switch (pcie_cap_get_type(dev)) {
- case PCI_EXP_TYPE_ROOT_PORT:
- /* this case will be set by pcie_aer_root_init() */
- /* fallthrough */
- case PCI_EXP_TYPE_DOWNSTREAM:
- case PCI_EXP_TYPE_UPSTREAM:
- pci_word_test_and_set_mask(dev->wmask + PCI_BRIDGE_CONTROL,
- PCI_BRIDGE_CTL_SERR);
- pci_long_test_and_set_mask(dev->w1cmask + PCI_STATUS,
- PCI_SEC_STATUS_RCV_SYSTEM_ERROR);
- break;
- default:
- /* nothing */
- break;
- }
- return 0;
-}
-
-void pcie_aer_exit(PCIDevice *dev)
-{
- g_free(dev->exp.aer_log.log);
-}
-
-static void pcie_aer_update_uncor_status(PCIDevice *dev)
-{
- uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
- PCIEAERLog *aer_log = &dev->exp.aer_log;
-
- uint16_t i;
- for (i = 0; i < aer_log->log_num; i++) {
- pci_long_test_and_set_mask(aer_cap + PCI_ERR_UNCOR_STATUS,
- dev->exp.aer_log.log[i].status);
- }
-}
-
-/*
- * return value:
- * true: error message needs to be sent up
- * false: error message is masked
- *
- * 6.2.6 Error Message Control
- * Figure 6-3
- * all pci express devices part
- */
-static bool
-pcie_aer_msg_alldev(PCIDevice *dev, const PCIEAERMsg *msg)
-{
- if (!(pcie_aer_msg_is_uncor(msg) &&
- (pci_get_word(dev->config + PCI_COMMAND) & PCI_COMMAND_SERR))) {
- return false;
- }
-
- /* Signaled System Error
- *
- * 7.5.1.1 Command register
- * Bit 8 SERR# Enable
- *
- * When Set, this bit enables reporting of Non-fatal and Fatal
- * errors detected by the Function to the Root Complex. Note that
- * errors are reported if enabled either through this bit or through
- * the PCI Express specific bits in the Device Control register (see
- * Section 7.8.4).
- */
- pci_word_test_and_set_mask(dev->config + PCI_STATUS,
- PCI_STATUS_SIG_SYSTEM_ERROR);
-
- if (!(msg->severity &
- pci_get_word(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL))) {
- return false;
- }
-
- /* send up error message */
- return true;
-}
-
-/*
- * return value:
- * true: error message is sent up
- * false: error message is masked
- *
- * 6.2.6 Error Message Control
- * Figure 6-3
- * virtual pci bridge part
- */
-static bool pcie_aer_msg_vbridge(PCIDevice *dev, const PCIEAERMsg *msg)
-{
- uint16_t bridge_control = pci_get_word(dev->config + PCI_BRIDGE_CONTROL);
-
- if (pcie_aer_msg_is_uncor(msg)) {
- /* Received System Error */
- pci_word_test_and_set_mask(dev->config + PCI_SEC_STATUS,
- PCI_SEC_STATUS_RCV_SYSTEM_ERROR);
- }
-
- if (!(bridge_control & PCI_BRIDGE_CTL_SERR)) {
- return false;
- }
- return true;
-}
-
-void pcie_aer_root_set_vector(PCIDevice *dev, unsigned int vector)
-{
- uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
- assert(vector < PCI_ERR_ROOT_IRQ_MAX);
- pci_long_test_and_clear_mask(aer_cap + PCI_ERR_ROOT_STATUS,
- PCI_ERR_ROOT_IRQ);
- pci_long_test_and_set_mask(aer_cap + PCI_ERR_ROOT_STATUS,
- vector << PCI_ERR_ROOT_IRQ_SHIFT);
-}
-
-static unsigned int pcie_aer_root_get_vector(PCIDevice *dev)
-{
- uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
- uint32_t root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS);
- return (root_status & PCI_ERR_ROOT_IRQ) >> PCI_ERR_ROOT_IRQ_SHIFT;
-}
-
-/* Given a status register, get corresponding bits in the command register */
-static uint32_t pcie_aer_status_to_cmd(uint32_t status)
-{
- uint32_t cmd = 0;
- if (status & PCI_ERR_ROOT_COR_RCV) {
- cmd |= PCI_ERR_ROOT_CMD_COR_EN;
- }
- if (status & PCI_ERR_ROOT_NONFATAL_RCV) {
- cmd |= PCI_ERR_ROOT_CMD_NONFATAL_EN;
- }
- if (status & PCI_ERR_ROOT_FATAL_RCV) {
- cmd |= PCI_ERR_ROOT_CMD_FATAL_EN;
- }
- return cmd;
-}
-
-static void pcie_aer_root_notify(PCIDevice *dev)
-{
- if (msix_enabled(dev)) {
- msix_notify(dev, pcie_aer_root_get_vector(dev));
- } else if (msi_enabled(dev)) {
- msi_notify(dev, pcie_aer_root_get_vector(dev));
- } else {
- pci_irq_assert(dev);
- }
-}
-
-/*
- * 6.2.6 Error Message Control
- * Figure 6-3
- * root port part
- */
-static void pcie_aer_msg_root_port(PCIDevice *dev, const PCIEAERMsg *msg)
-{
- uint16_t cmd;
- uint8_t *aer_cap;
- uint32_t root_cmd;
- uint32_t root_status, prev_status;
-
- cmd = pci_get_word(dev->config + PCI_COMMAND);
- aer_cap = dev->config + dev->exp.aer_cap;
- root_cmd = pci_get_long(aer_cap + PCI_ERR_ROOT_COMMAND);
- prev_status = root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS);
-
- if (cmd & PCI_COMMAND_SERR) {
- /* System Error.
- *
- * The way to report System Error is platform specific and
- * it isn't implemented in qemu right now.
- * So just discard the error for now.
- * OS which cares of aer would receive errors via
- * native aer mechanims, so this wouldn't matter.
- */
- }
-
- /* Errro Message Received: Root Error Status register */
- switch (msg->severity) {
- case PCI_ERR_ROOT_CMD_COR_EN:
- if (root_status & PCI_ERR_ROOT_COR_RCV) {
- root_status |= PCI_ERR_ROOT_MULTI_COR_RCV;
- } else {
- pci_set_word(aer_cap + PCI_ERR_ROOT_ERR_SRC + PCI_ERR_SRC_COR_OFFS,
- msg->source_id);
- }
- root_status |= PCI_ERR_ROOT_COR_RCV;
- break;
- case PCI_ERR_ROOT_CMD_NONFATAL_EN:
- root_status |= PCI_ERR_ROOT_NONFATAL_RCV;
- break;
- case PCI_ERR_ROOT_CMD_FATAL_EN:
- if (!(root_status & PCI_ERR_ROOT_UNCOR_RCV)) {
- root_status |= PCI_ERR_ROOT_FIRST_FATAL;
- }
- root_status |= PCI_ERR_ROOT_FATAL_RCV;
- break;
- default:
- abort();
- break;
- }
- if (pcie_aer_msg_is_uncor(msg)) {
- if (root_status & PCI_ERR_ROOT_UNCOR_RCV) {
- root_status |= PCI_ERR_ROOT_MULTI_UNCOR_RCV;
- } else {
- pci_set_word(aer_cap + PCI_ERR_ROOT_ERR_SRC +
- PCI_ERR_SRC_UNCOR_OFFS, msg->source_id);
- }
- root_status |= PCI_ERR_ROOT_UNCOR_RCV;
- }
- pci_set_long(aer_cap + PCI_ERR_ROOT_STATUS, root_status);
-
- /* 6.2.4.1.2 Interrupt Generation */
- /* All the above did was set some bits in the status register.
- * Specifically these that match message severity.
- * The below code relies on this fact. */
- if (!(root_cmd & msg->severity) ||
- (pcie_aer_status_to_cmd(prev_status) & root_cmd)) {
- /* Condition is not being set or was already true so nothing to do. */
- return;
- }
-
- pcie_aer_root_notify(dev);
-}
-
-/*
- * 6.2.6 Error Message Control Figure 6-3
- *
- * Walk up the bus tree from the device, propagate the error message.
- */
-void pcie_aer_msg(PCIDevice *dev, const PCIEAERMsg *msg)
-{
- uint8_t type;
-
- while (dev) {
- if (!pci_is_express(dev)) {
- /* just ignore it */
- /* TODO: Shouldn't we set PCI_STATUS_SIG_SYSTEM_ERROR?
- * Consider e.g. a PCI bridge above a PCI Express device. */
- return;
- }
-
- type = pcie_cap_get_type(dev);
- if ((type == PCI_EXP_TYPE_ROOT_PORT ||
- type == PCI_EXP_TYPE_UPSTREAM ||
- type == PCI_EXP_TYPE_DOWNSTREAM) &&
- !pcie_aer_msg_vbridge(dev, msg)) {
- return;
- }
- if (!pcie_aer_msg_alldev(dev, msg)) {
- return;
- }
- if (type == PCI_EXP_TYPE_ROOT_PORT) {
- pcie_aer_msg_root_port(dev, msg);
- /* Root port can notify system itself,
- or send the error message to root complex event collector. */
- /*
- * if root port is associated with an event collector,
- * return the root complex event collector here.
- * For now root complex event collector isn't supported.
- */
- return;
- }
- dev = pci_bridge_get_device(dev->bus);
- }
-}
-
-static void pcie_aer_update_log(PCIDevice *dev, const PCIEAERErr *err)
-{
- uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
- uint8_t first_bit = ctz32(err->status);
- uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP);
- int i;
-
- assert(err->status);
- assert(!(err->status & (err->status - 1)));
-
- errcap &= ~(PCI_ERR_CAP_FEP_MASK | PCI_ERR_CAP_TLP);
- errcap |= PCI_ERR_CAP_FEP(first_bit);
-
- if (err->flags & PCIE_AER_ERR_HEADER_VALID) {
- for (i = 0; i < ARRAY_SIZE(err->header); ++i) {
- /* 7.10.8 Header Log Register */
- uint8_t *header_log =
- aer_cap + PCI_ERR_HEADER_LOG + i * sizeof err->header[0];
- stl_be_p(header_log, err->header[i]);
- }
- } else {
- assert(!(err->flags & PCIE_AER_ERR_TLP_PREFIX_PRESENT));
- memset(aer_cap + PCI_ERR_HEADER_LOG, 0, PCI_ERR_HEADER_LOG_SIZE);
- }
-
- if ((err->flags & PCIE_AER_ERR_TLP_PREFIX_PRESENT) &&
- (pci_get_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCAP2) &
- PCI_EXP_DEVCAP2_EETLPP)) {
- for (i = 0; i < ARRAY_SIZE(err->prefix); ++i) {
- /* 7.10.12 tlp prefix log register */
- uint8_t *prefix_log =
- aer_cap + PCI_ERR_TLP_PREFIX_LOG + i * sizeof err->prefix[0];
- stl_be_p(prefix_log, err->prefix[i]);
- }
- errcap |= PCI_ERR_CAP_TLP;
- } else {
- memset(aer_cap + PCI_ERR_TLP_PREFIX_LOG, 0,
- PCI_ERR_TLP_PREFIX_LOG_SIZE);
- }
- pci_set_long(aer_cap + PCI_ERR_CAP, errcap);
-}
-
-static void pcie_aer_clear_log(PCIDevice *dev)
-{
- uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
-
- pci_long_test_and_clear_mask(aer_cap + PCI_ERR_CAP,
- PCI_ERR_CAP_FEP_MASK | PCI_ERR_CAP_TLP);
-
- memset(aer_cap + PCI_ERR_HEADER_LOG, 0, PCI_ERR_HEADER_LOG_SIZE);
- memset(aer_cap + PCI_ERR_TLP_PREFIX_LOG, 0, PCI_ERR_TLP_PREFIX_LOG_SIZE);
-}
-
-static void pcie_aer_clear_error(PCIDevice *dev)
-{
- uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
- uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP);
- PCIEAERLog *aer_log = &dev->exp.aer_log;
- PCIEAERErr err;
-
- if (!(errcap & PCI_ERR_CAP_MHRE) || !aer_log->log_num) {
- pcie_aer_clear_log(dev);
- return;
- }
-
- /*
- * If more errors are queued, set corresponding bits in uncorrectable
- * error status.
- * We emulate uncorrectable error status register as W1CS.
- * So set bit in uncorrectable error status here again for multiple
- * error recording support.
- *
- * 6.2.4.2 Multiple Error Handling(Advanced Error Reporting Capability)
- */
- pcie_aer_update_uncor_status(dev);
-
- aer_log_del_err(aer_log, &err);
- pcie_aer_update_log(dev, &err);
-}
-
-static int pcie_aer_record_error(PCIDevice *dev,
- const PCIEAERErr *err)
-{
- uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
- uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP);
- int fep = PCI_ERR_CAP_FEP(errcap);
-
- assert(err->status);
- assert(!(err->status & (err->status - 1)));
-
- if (errcap & PCI_ERR_CAP_MHRE &&
- (pci_get_long(aer_cap + PCI_ERR_UNCOR_STATUS) & (1U << fep))) {
- /* Not first error. queue error */
- if (aer_log_add_err(&dev->exp.aer_log, err) < 0) {
- /* overflow */
- return -1;
- }
- return 0;
- }
-
- pcie_aer_update_log(dev, err);
- return 0;
-}
-
-typedef struct PCIEAERInject {
- PCIDevice *dev;
- uint8_t *aer_cap;
- const PCIEAERErr *err;
- uint16_t devctl;
- uint16_t devsta;
- uint32_t error_status;
- bool unsupported_request;
- bool log_overflow;
- PCIEAERMsg msg;
-} PCIEAERInject;
-
-static bool pcie_aer_inject_cor_error(PCIEAERInject *inj,
- uint32_t uncor_status,
- bool is_advisory_nonfatal)
-{
- PCIDevice *dev = inj->dev;
-
- inj->devsta |= PCI_EXP_DEVSTA_CED;
- if (inj->unsupported_request) {
- inj->devsta |= PCI_EXP_DEVSTA_URD;
- }
- pci_set_word(dev->config + dev->exp.exp_cap + PCI_EXP_DEVSTA, inj->devsta);
-
- if (inj->aer_cap) {
- uint32_t mask;
- pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_COR_STATUS,
- inj->error_status);
- mask = pci_get_long(inj->aer_cap + PCI_ERR_COR_MASK);
- if (mask & inj->error_status) {
- return false;
- }
- if (is_advisory_nonfatal) {
- uint32_t uncor_mask =
- pci_get_long(inj->aer_cap + PCI_ERR_UNCOR_MASK);
- if (!(uncor_mask & uncor_status)) {
- inj->log_overflow = !!pcie_aer_record_error(dev, inj->err);
- }
- pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_UNCOR_STATUS,
- uncor_status);
- }
- }
-
- if (inj->unsupported_request && !(inj->devctl & PCI_EXP_DEVCTL_URRE)) {
- return false;
- }
- if (!(inj->devctl & PCI_EXP_DEVCTL_CERE)) {
- return false;
- }
-
- inj->msg.severity = PCI_ERR_ROOT_CMD_COR_EN;
- return true;
-}
-
-static bool pcie_aer_inject_uncor_error(PCIEAERInject *inj, bool is_fatal)
-{
- PCIDevice *dev = inj->dev;
- uint16_t cmd;
-
- if (is_fatal) {
- inj->devsta |= PCI_EXP_DEVSTA_FED;
- } else {
- inj->devsta |= PCI_EXP_DEVSTA_NFED;
- }
- if (inj->unsupported_request) {
- inj->devsta |= PCI_EXP_DEVSTA_URD;
- }
- pci_set_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVSTA, inj->devsta);
-
- if (inj->aer_cap) {
- uint32_t mask = pci_get_long(inj->aer_cap + PCI_ERR_UNCOR_MASK);
- if (mask & inj->error_status) {
- pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_UNCOR_STATUS,
- inj->error_status);
- return false;
- }
-
- inj->log_overflow = !!pcie_aer_record_error(dev, inj->err);
- pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_UNCOR_STATUS,
- inj->error_status);
- }
-
- cmd = pci_get_word(dev->config + PCI_COMMAND);
- if (inj->unsupported_request &&
- !(inj->devctl & PCI_EXP_DEVCTL_URRE) && !(cmd & PCI_COMMAND_SERR)) {
- return false;
- }
- if (is_fatal) {
- if (!((cmd & PCI_COMMAND_SERR) ||
- (inj->devctl & PCI_EXP_DEVCTL_FERE))) {
- return false;
- }
- inj->msg.severity = PCI_ERR_ROOT_CMD_FATAL_EN;
- } else {
- if (!((cmd & PCI_COMMAND_SERR) ||
- (inj->devctl & PCI_EXP_DEVCTL_NFERE))) {
- return false;
- }
- inj->msg.severity = PCI_ERR_ROOT_CMD_NONFATAL_EN;
- }
- return true;
-}
-
-/*
- * non-Function specific error must be recorded in all functions.
- * It is the responsibility of the caller of this function.
- * It is also caller's responsibility to determine which function should
- * report the error.
- *
- * 6.2.4 Error Logging
- * 6.2.5 Sequence of Device Error Signaling and Logging Operations
- * Figure 6-2: Flowchart Showing Sequence of Device Error Signaling and Logging
- * Operations
- */
-int pcie_aer_inject_error(PCIDevice *dev, const PCIEAERErr *err)
-{
- uint8_t *aer_cap = NULL;
- uint16_t devctl = 0;
- uint16_t devsta = 0;
- uint32_t error_status = err->status;
- PCIEAERInject inj;
-
- if (!pci_is_express(dev)) {
- return -ENOSYS;
- }
-
- if (err->flags & PCIE_AER_ERR_IS_CORRECTABLE) {
- error_status &= PCI_ERR_COR_SUPPORTED;
- } else {
- error_status &= PCI_ERR_UNC_SUPPORTED;
- }
-
- /* invalid status bit. one and only one bit must be set */
- if (!error_status || (error_status & (error_status - 1))) {
- return -EINVAL;
- }
-
- if (dev->exp.aer_cap) {
- uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
- aer_cap = dev->config + dev->exp.aer_cap;
- devctl = pci_get_long(exp_cap + PCI_EXP_DEVCTL);
- devsta = pci_get_long(exp_cap + PCI_EXP_DEVSTA);
- }
-
- inj.dev = dev;
- inj.aer_cap = aer_cap;
- inj.err = err;
- inj.devctl = devctl;
- inj.devsta = devsta;
- inj.error_status = error_status;
- inj.unsupported_request = !(err->flags & PCIE_AER_ERR_IS_CORRECTABLE) &&
- err->status == PCI_ERR_UNC_UNSUP;
- inj.log_overflow = false;
-
- if (err->flags & PCIE_AER_ERR_IS_CORRECTABLE) {
- if (!pcie_aer_inject_cor_error(&inj, 0, false)) {
- return 0;
- }
- } else {
- bool is_fatal =
- pcie_aer_uncor_default_severity(error_status) ==
- PCI_ERR_ROOT_CMD_FATAL_EN;
- if (aer_cap) {
- is_fatal =
- error_status & pci_get_long(aer_cap + PCI_ERR_UNCOR_SEVER);
- }
- if (!is_fatal && (err->flags & PCIE_AER_ERR_MAYBE_ADVISORY)) {
- inj.error_status = PCI_ERR_COR_ADV_NONFATAL;
- if (!pcie_aer_inject_cor_error(&inj, error_status, true)) {
- return 0;
- }
- } else {
- if (!pcie_aer_inject_uncor_error(&inj, is_fatal)) {
- return 0;
- }
- }
- }
-
- /* send up error message */
- inj.msg.source_id = err->source_id;
- pcie_aer_msg(dev, &inj.msg);
-
- if (inj.log_overflow) {
- PCIEAERErr header_log_overflow = {
- .status = PCI_ERR_COR_HL_OVERFLOW,
- .flags = PCIE_AER_ERR_IS_CORRECTABLE,
- };
- int ret = pcie_aer_inject_error(dev, &header_log_overflow);
- assert(!ret);
- }
- return 0;
-}
-
-void pcie_aer_write_config(PCIDevice *dev,
- uint32_t addr, uint32_t val, int len)
-{
- uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
- uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP);
- uint32_t first_error = 1U << PCI_ERR_CAP_FEP(errcap);
- uint32_t uncorsta = pci_get_long(aer_cap + PCI_ERR_UNCOR_STATUS);
-
- /* uncorrectable error */
- if (!(uncorsta & first_error)) {
- /* the bit that corresponds to the first error is cleared */
- pcie_aer_clear_error(dev);
- } else if (errcap & PCI_ERR_CAP_MHRE) {
- /* When PCI_ERR_CAP_MHRE is enabled and the first error isn't cleared
- * nothing should happen. So we have to revert the modification to
- * the register.
- */
- pcie_aer_update_uncor_status(dev);
- } else {
- /* capability & control
- * PCI_ERR_CAP_MHRE might be cleared, so clear of header log.
- */
- aer_log_clear_all_err(&dev->exp.aer_log);
- }
-}
-
-void pcie_aer_root_init(PCIDevice *dev)
-{
- uint16_t pos = dev->exp.aer_cap;
-
- pci_set_long(dev->wmask + pos + PCI_ERR_ROOT_COMMAND,
- PCI_ERR_ROOT_CMD_EN_MASK);
- pci_set_long(dev->w1cmask + pos + PCI_ERR_ROOT_STATUS,
- PCI_ERR_ROOT_STATUS_REPORT_MASK);
- /* PCI_ERR_ROOT_IRQ is RO but devices change it using a
- * device-specific method.
- */
- pci_set_long(dev->cmask + pos + PCI_ERR_ROOT_STATUS,
- ~PCI_ERR_ROOT_IRQ);
-}
-
-void pcie_aer_root_reset(PCIDevice *dev)
-{
- uint8_t* aer_cap = dev->config + dev->exp.aer_cap;
-
- pci_set_long(aer_cap + PCI_ERR_ROOT_COMMAND, 0);
-
- /*
- * Advanced Error Interrupt Message Number in Root Error Status Register
- * must be updated by chip dependent code because it's chip dependent
- * which number is used.
- */
-}
-
-void pcie_aer_root_write_config(PCIDevice *dev,
- uint32_t addr, uint32_t val, int len,
- uint32_t root_cmd_prev)
-{
- uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
- uint32_t root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS);
- uint32_t enabled_cmd = pcie_aer_status_to_cmd(root_status);
- uint32_t root_cmd = pci_get_long(aer_cap + PCI_ERR_ROOT_COMMAND);
- /* 6.2.4.1.2 Interrupt Generation */
- if (!msix_enabled(dev) && !msi_enabled(dev)) {
- pci_set_irq(dev, !!(root_cmd & enabled_cmd));
- return;
- }
-
- if ((root_cmd_prev & enabled_cmd) || !(root_cmd & enabled_cmd)) {
- /* Send MSI on transition from false to true. */
- return;
- }
-
- pcie_aer_root_notify(dev);
-}
-
-static const VMStateDescription vmstate_pcie_aer_err = {
- .name = "PCIE_AER_ERROR",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(status, PCIEAERErr),
- VMSTATE_UINT16(source_id, PCIEAERErr),
- VMSTATE_UINT16(flags, PCIEAERErr),
- VMSTATE_UINT32_ARRAY(header, PCIEAERErr, 4),
- VMSTATE_UINT32_ARRAY(prefix, PCIEAERErr, 4),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static bool pcie_aer_state_log_num_valid(void *opaque, int version_id)
-{
- PCIEAERLog *s = opaque;
-
- return s->log_num <= s->log_max;
-}
-
-const VMStateDescription vmstate_pcie_aer_log = {
- .name = "PCIE_AER_ERROR_LOG",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT16(log_num, PCIEAERLog),
- VMSTATE_UINT16_EQUAL(log_max, PCIEAERLog),
- VMSTATE_VALIDATE("log_num <= log_max", pcie_aer_state_log_num_valid),
- VMSTATE_STRUCT_VARRAY_POINTER_UINT16(log, PCIEAERLog, log_num,
- vmstate_pcie_aer_err, PCIEAERErr),
- VMSTATE_END_OF_LIST()
- }
-};
-
-typedef struct PCIEAERErrorName {
- const char *name;
- uint32_t val;
- bool correctable;
-} PCIEAERErrorName;
-
-/*
- * AER error name -> value conversion table
- * This naming scheme is same to linux aer-injection tool.
- */
-static const struct PCIEAERErrorName pcie_aer_error_list[] = {
- {
- .name = "DLP",
- .val = PCI_ERR_UNC_DLP,
- .correctable = false,
- }, {
- .name = "SDN",
- .val = PCI_ERR_UNC_SDN,
- .correctable = false,
- }, {
- .name = "POISON_TLP",
- .val = PCI_ERR_UNC_POISON_TLP,
- .correctable = false,
- }, {
- .name = "FCP",
- .val = PCI_ERR_UNC_FCP,
- .correctable = false,
- }, {
- .name = "COMP_TIME",
- .val = PCI_ERR_UNC_COMP_TIME,
- .correctable = false,
- }, {
- .name = "COMP_ABORT",
- .val = PCI_ERR_UNC_COMP_ABORT,
- .correctable = false,
- }, {
- .name = "UNX_COMP",
- .val = PCI_ERR_UNC_UNX_COMP,
- .correctable = false,
- }, {
- .name = "RX_OVER",
- .val = PCI_ERR_UNC_RX_OVER,
- .correctable = false,
- }, {
- .name = "MALF_TLP",
- .val = PCI_ERR_UNC_MALF_TLP,
- .correctable = false,
- }, {
- .name = "ECRC",
- .val = PCI_ERR_UNC_ECRC,
- .correctable = false,
- }, {
- .name = "UNSUP",
- .val = PCI_ERR_UNC_UNSUP,
- .correctable = false,
- }, {
- .name = "ACSV",
- .val = PCI_ERR_UNC_ACSV,
- .correctable = false,
- }, {
- .name = "INTN",
- .val = PCI_ERR_UNC_INTN,
- .correctable = false,
- }, {
- .name = "MCBTLP",
- .val = PCI_ERR_UNC_MCBTLP,
- .correctable = false,
- }, {
- .name = "ATOP_EBLOCKED",
- .val = PCI_ERR_UNC_ATOP_EBLOCKED,
- .correctable = false,
- }, {
- .name = "TLP_PRF_BLOCKED",
- .val = PCI_ERR_UNC_TLP_PRF_BLOCKED,
- .correctable = false,
- }, {
- .name = "RCVR",
- .val = PCI_ERR_COR_RCVR,
- .correctable = true,
- }, {
- .name = "BAD_TLP",
- .val = PCI_ERR_COR_BAD_TLP,
- .correctable = true,
- }, {
- .name = "BAD_DLLP",
- .val = PCI_ERR_COR_BAD_DLLP,
- .correctable = true,
- }, {
- .name = "REP_ROLL",
- .val = PCI_ERR_COR_REP_ROLL,
- .correctable = true,
- }, {
- .name = "REP_TIMER",
- .val = PCI_ERR_COR_REP_TIMER,
- .correctable = true,
- }, {
- .name = "ADV_NONFATAL",
- .val = PCI_ERR_COR_ADV_NONFATAL,
- .correctable = true,
- }, {
- .name = "INTERNAL",
- .val = PCI_ERR_COR_INTERNAL,
- .correctable = true,
- }, {
- .name = "HL_OVERFLOW",
- .val = PCI_ERR_COR_HL_OVERFLOW,
- .correctable = true,
- },
-};
-
-static int pcie_aer_parse_error_string(const char *error_name,
- uint32_t *status, bool *correctable)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(pcie_aer_error_list); i++) {
- const PCIEAERErrorName *e = &pcie_aer_error_list[i];
- if (strcmp(error_name, e->name)) {
- continue;
- }
-
- *status = e->val;
- *correctable = e->correctable;
- return 0;
- }
- return -EINVAL;
-}
-
-static int do_pcie_aer_inject_error(Monitor *mon,
- const QDict *qdict, QObject **ret_data)
-{
- const char *id = qdict_get_str(qdict, "id");
- const char *error_name;
- uint32_t error_status;
- bool correctable;
- PCIDevice *dev;
- PCIEAERErr err;
- int ret;
-
- ret = pci_qdev_find_device(id, &dev);
- if (ret < 0) {
- monitor_printf(mon,
- "id or pci device path is invalid or device not "
- "found. %s\n", id);
- return ret;
- }
- if (!pci_is_express(dev)) {
- monitor_printf(mon, "the device doesn't support pci express. %s\n",
- id);
- return -ENOSYS;
- }
-
- error_name = qdict_get_str(qdict, "error_status");
- if (pcie_aer_parse_error_string(error_name, &error_status, &correctable)) {
- char *e = NULL;
- error_status = strtoul(error_name, &e, 0);
- correctable = qdict_get_try_bool(qdict, "correctable", false);
- if (!e || *e != '\0') {
- monitor_printf(mon, "invalid error status value. \"%s\"",
- error_name);
- return -EINVAL;
- }
- }
- err.status = error_status;
- err.source_id = pci_requester_id(dev);
-
- err.flags = 0;
- if (correctable) {
- err.flags |= PCIE_AER_ERR_IS_CORRECTABLE;
- }
- if (qdict_get_try_bool(qdict, "advisory_non_fatal", false)) {
- err.flags |= PCIE_AER_ERR_MAYBE_ADVISORY;
- }
- if (qdict_haskey(qdict, "header0")) {
- err.flags |= PCIE_AER_ERR_HEADER_VALID;
- }
- if (qdict_haskey(qdict, "prefix0")) {
- err.flags |= PCIE_AER_ERR_TLP_PREFIX_PRESENT;
- }
-
- err.header[0] = qdict_get_try_int(qdict, "header0", 0);
- err.header[1] = qdict_get_try_int(qdict, "header1", 0);
- err.header[2] = qdict_get_try_int(qdict, "header2", 0);
- err.header[3] = qdict_get_try_int(qdict, "header3", 0);
-
- err.prefix[0] = qdict_get_try_int(qdict, "prefix0", 0);
- err.prefix[1] = qdict_get_try_int(qdict, "prefix1", 0);
- err.prefix[2] = qdict_get_try_int(qdict, "prefix2", 0);
- err.prefix[3] = qdict_get_try_int(qdict, "prefix3", 0);
-
- ret = pcie_aer_inject_error(dev, &err);
- *ret_data = qobject_from_jsonf("{'id': %s, "
- "'root_bus': %s, 'bus': %d, 'devfn': %d, "
- "'ret': %d}",
- id, pci_root_bus_path(dev),
- pci_bus_num(dev->bus), dev->devfn,
- ret);
- assert(*ret_data);
-
- return 0;
-}
-
-void hmp_pcie_aer_inject_error(Monitor *mon, const QDict *qdict)
-{
- QObject *data;
- int devfn;
-
- if (do_pcie_aer_inject_error(mon, qdict, &data) < 0) {
- return;
- }
-
- assert(qobject_type(data) == QTYPE_QDICT);
- qdict = qobject_to_qdict(data);
-
- devfn = (int)qdict_get_int(qdict, "devfn");
- monitor_printf(mon, "OK id: %s root bus: %s, bus: %x devfn: %x.%x\n",
- qdict_get_str(qdict, "id"),
- qdict_get_str(qdict, "root_bus"),
- (int) qdict_get_int(qdict, "bus"),
- PCI_SLOT(devfn), PCI_FUNC(devfn));
-}
diff --git a/qemu/hw/pci/pcie_host.c b/qemu/hw/pci/pcie_host.c
deleted file mode 100644
index dcebf57ed..000000000
--- a/qemu/hw/pci/pcie_host.c
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * pcie_host.c
- * utility functions for pci express host bridge.
- *
- * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
- * VA Linux Systems Japan K.K.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/pcie_host.h"
-#include "exec/address-spaces.h"
-
-/* a helper function to get a PCIDevice for a given mmconfig address */
-static inline PCIDevice *pcie_dev_find_by_mmcfg_addr(PCIBus *s,
- uint32_t mmcfg_addr)
-{
- return pci_find_device(s, PCIE_MMCFG_BUS(mmcfg_addr),
- PCIE_MMCFG_DEVFN(mmcfg_addr));
-}
-
-static void pcie_mmcfg_data_write(void *opaque, hwaddr mmcfg_addr,
- uint64_t val, unsigned len)
-{
- PCIExpressHost *e = opaque;
- PCIBus *s = e->pci.bus;
- PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr);
- uint32_t addr;
- uint32_t limit;
-
- if (!pci_dev) {
- return;
- }
- addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr);
- limit = pci_config_size(pci_dev);
- if (limit <= addr) {
- /* conventional pci device can be behind pcie-to-pci bridge.
- 256 <= addr < 4K has no effects. */
- return;
- }
- pci_host_config_write_common(pci_dev, addr, limit, val, len);
-}
-
-static uint64_t pcie_mmcfg_data_read(void *opaque,
- hwaddr mmcfg_addr,
- unsigned len)
-{
- PCIExpressHost *e = opaque;
- PCIBus *s = e->pci.bus;
- PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr);
- uint32_t addr;
- uint32_t limit;
-
- if (!pci_dev) {
- return ~0x0;
- }
- addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr);
- limit = pci_config_size(pci_dev);
- if (limit <= addr) {
- /* conventional pci device can be behind pcie-to-pci bridge.
- 256 <= addr < 4K has no effects. */
- return ~0x0;
- }
- return pci_host_config_read_common(pci_dev, addr, limit, len);
-}
-
-static const MemoryRegionOps pcie_mmcfg_ops = {
- .read = pcie_mmcfg_data_read,
- .write = pcie_mmcfg_data_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void pcie_host_init(Object *obj)
-{
- PCIExpressHost *e = PCIE_HOST_BRIDGE(obj);
-
- e->base_addr = PCIE_BASE_ADDR_UNMAPPED;
- memory_region_init_io(&e->mmio, OBJECT(e), &pcie_mmcfg_ops, e, "pcie-mmcfg-mmio",
- PCIE_MMCFG_SIZE_MAX);
-}
-
-void pcie_host_mmcfg_unmap(PCIExpressHost *e)
-{
- if (e->base_addr != PCIE_BASE_ADDR_UNMAPPED) {
- memory_region_del_subregion(get_system_memory(), &e->mmio);
- e->base_addr = PCIE_BASE_ADDR_UNMAPPED;
- }
-}
-
-void pcie_host_mmcfg_init(PCIExpressHost *e, uint32_t size)
-{
- assert(!(size & (size - 1))); /* power of 2 */
- assert(size >= PCIE_MMCFG_SIZE_MIN);
- assert(size <= PCIE_MMCFG_SIZE_MAX);
- e->size = size;
- memory_region_set_size(&e->mmio, e->size);
-}
-
-void pcie_host_mmcfg_map(PCIExpressHost *e, hwaddr addr,
- uint32_t size)
-{
- pcie_host_mmcfg_init(e, size);
- e->base_addr = addr;
- memory_region_add_subregion(get_system_memory(), e->base_addr, &e->mmio);
-}
-
-void pcie_host_mmcfg_update(PCIExpressHost *e,
- int enable,
- hwaddr addr,
- uint32_t size)
-{
- memory_region_transaction_begin();
- pcie_host_mmcfg_unmap(e);
- if (enable) {
- pcie_host_mmcfg_map(e, addr, size);
- }
- memory_region_transaction_commit();
-}
-
-static const TypeInfo pcie_host_type_info = {
- .name = TYPE_PCIE_HOST_BRIDGE,
- .parent = TYPE_PCI_HOST_BRIDGE,
- .abstract = true,
- .instance_size = sizeof(PCIExpressHost),
- .instance_init = pcie_host_init,
-};
-
-static void pcie_host_register_types(void)
-{
- type_register_static(&pcie_host_type_info);
-}
-
-type_init(pcie_host_register_types)
diff --git a/qemu/hw/pci/pcie_port.c b/qemu/hw/pci/pcie_port.c
deleted file mode 100644
index 6432b9ac1..000000000
--- a/qemu/hw/pci/pcie_port.c
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * pcie_port.c
- *
- * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
- * VA Linux Systems Japan K.K.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/pci/pcie_port.h"
-#include "hw/hotplug.h"
-
-void pcie_port_init_reg(PCIDevice *d)
-{
- /* Unlike pci bridge,
- 66MHz and fast back to back don't apply to pci express port. */
- pci_set_word(d->config + PCI_STATUS, 0);
- pci_set_word(d->config + PCI_SEC_STATUS, 0);
-
- /*
- * Unlike conventional pci bridge, for some bits the spec states:
- * Does not apply to PCI Express and must be hardwired to 0.
- */
- pci_word_test_and_clear_mask(d->wmask + PCI_BRIDGE_CONTROL,
- PCI_BRIDGE_CTL_MASTER_ABORT |
- PCI_BRIDGE_CTL_FAST_BACK |
- PCI_BRIDGE_CTL_DISCARD |
- PCI_BRIDGE_CTL_SEC_DISCARD |
- PCI_BRIDGE_CTL_DISCARD_STATUS |
- PCI_BRIDGE_CTL_DISCARD_SERR);
-}
-
-/**************************************************************************
- * (chassis number, pcie physical slot number) -> pcie slot conversion
- */
-struct PCIEChassis {
- uint8_t number;
-
- QLIST_HEAD(, PCIESlot) slots;
- QLIST_ENTRY(PCIEChassis) next;
-};
-
-static QLIST_HEAD(, PCIEChassis) chassis = QLIST_HEAD_INITIALIZER(chassis);
-
-static struct PCIEChassis *pcie_chassis_find(uint8_t chassis_number)
-{
- struct PCIEChassis *c;
- QLIST_FOREACH(c, &chassis, next) {
- if (c->number == chassis_number) {
- break;
- }
- }
- return c;
-}
-
-void pcie_chassis_create(uint8_t chassis_number)
-{
- struct PCIEChassis *c;
- c = pcie_chassis_find(chassis_number);
- if (c) {
- return;
- }
- c = g_malloc0(sizeof(*c));
- c->number = chassis_number;
- QLIST_INIT(&c->slots);
- QLIST_INSERT_HEAD(&chassis, c, next);
-}
-
-static PCIESlot *pcie_chassis_find_slot_with_chassis(struct PCIEChassis *c,
- uint8_t slot)
-{
- PCIESlot *s;
- QLIST_FOREACH(s, &c->slots, next) {
- if (s->slot == slot) {
- break;
- }
- }
- return s;
-}
-
-PCIESlot *pcie_chassis_find_slot(uint8_t chassis_number, uint16_t slot)
-{
- struct PCIEChassis *c;
- c = pcie_chassis_find(chassis_number);
- if (!c) {
- return NULL;
- }
- return pcie_chassis_find_slot_with_chassis(c, slot);
-}
-
-int pcie_chassis_add_slot(struct PCIESlot *slot)
-{
- struct PCIEChassis *c;
- c = pcie_chassis_find(slot->chassis);
- if (!c) {
- return -ENODEV;
- }
- if (pcie_chassis_find_slot_with_chassis(c, slot->slot)) {
- return -EBUSY;
- }
- QLIST_INSERT_HEAD(&c->slots, slot, next);
- return 0;
-}
-
-void pcie_chassis_del_slot(PCIESlot *s)
-{
- QLIST_REMOVE(s, next);
-}
-
-static Property pcie_port_props[] = {
- DEFINE_PROP_UINT8("port", PCIEPort, port, 0),
- DEFINE_PROP_UINT16("aer_log_max", PCIEPort,
- parent_obj.parent_obj.exp.aer_log.log_max,
- PCIE_AER_LOG_MAX_DEFAULT),
- DEFINE_PROP_END_OF_LIST()
-};
-
-static void pcie_port_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- dc->props = pcie_port_props;
-}
-
-static const TypeInfo pcie_port_type_info = {
- .name = TYPE_PCIE_PORT,
- .parent = TYPE_PCI_BRIDGE,
- .instance_size = sizeof(PCIEPort),
- .abstract = true,
- .class_init = pcie_port_class_init,
-};
-
-static Property pcie_slot_props[] = {
- DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0),
- DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0),
- DEFINE_PROP_END_OF_LIST()
-};
-
-static void pcie_slot_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
- HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
-
- dc->props = pcie_slot_props;
- hc->plug = pcie_cap_slot_hotplug_cb;
- hc->unplug_request = pcie_cap_slot_hot_unplug_request_cb;
-}
-
-static const TypeInfo pcie_slot_type_info = {
- .name = TYPE_PCIE_SLOT,
- .parent = TYPE_PCIE_PORT,
- .instance_size = sizeof(PCIESlot),
- .abstract = true,
- .class_init = pcie_slot_class_init,
- .interfaces = (InterfaceInfo[]) {
- { TYPE_HOTPLUG_HANDLER },
- { }
- }
-};
-
-static void pcie_port_register_types(void)
-{
- type_register_static(&pcie_port_type_info);
- type_register_static(&pcie_slot_type_info);
-}
-
-type_init(pcie_port_register_types)
diff --git a/qemu/hw/pci/shpc.c b/qemu/hw/pci/shpc.c
deleted file mode 100644
index 3dcd472eb..000000000
--- a/qemu/hw/pci/shpc.c
+++ /dev/null
@@ -1,721 +0,0 @@
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "qemu/range.h"
-#include "qemu/error-report.h"
-#include "hw/pci/shpc.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/pci_bus.h"
-#include "hw/pci/msi.h"
-
-/* TODO: model power only and disabled slot states. */
-/* TODO: handle SERR and wakeups */
-/* TODO: consider enabling 66MHz support */
-
-/* TODO: remove fully only on state DISABLED and LED off.
- * track state to properly record this. */
-
-/* SHPC Working Register Set */
-#define SHPC_BASE_OFFSET 0x00 /* 4 bytes */
-#define SHPC_SLOTS_33 0x04 /* 4 bytes. Also encodes PCI-X slots. */
-#define SHPC_SLOTS_66 0x08 /* 4 bytes. */
-#define SHPC_NSLOTS 0x0C /* 1 byte */
-#define SHPC_FIRST_DEV 0x0D /* 1 byte */
-#define SHPC_PHYS_SLOT 0x0E /* 2 byte */
-#define SHPC_PHYS_NUM_MAX 0x7ff
-#define SHPC_PHYS_NUM_UP 0x2000
-#define SHPC_PHYS_MRL 0x4000
-#define SHPC_PHYS_BUTTON 0x8000
-#define SHPC_SEC_BUS 0x10 /* 2 bytes */
-#define SHPC_SEC_BUS_33 0x0
-#define SHPC_SEC_BUS_66 0x1 /* Unused */
-#define SHPC_SEC_BUS_MASK 0x7
-#define SHPC_MSI_CTL 0x12 /* 1 byte */
-#define SHPC_PROG_IFC 0x13 /* 1 byte */
-#define SHPC_PROG_IFC_1_0 0x1
-#define SHPC_CMD_CODE 0x14 /* 1 byte */
-#define SHPC_CMD_TRGT 0x15 /* 1 byte */
-#define SHPC_CMD_TRGT_MIN 0x1
-#define SHPC_CMD_TRGT_MAX 0x1f
-#define SHPC_CMD_STATUS 0x16 /* 2 bytes */
-#define SHPC_CMD_STATUS_BUSY 0x1
-#define SHPC_CMD_STATUS_MRL_OPEN 0x2
-#define SHPC_CMD_STATUS_INVALID_CMD 0x4
-#define SHPC_CMD_STATUS_INVALID_MODE 0x8
-#define SHPC_INT_LOCATOR 0x18 /* 4 bytes */
-#define SHPC_INT_COMMAND 0x1
-#define SHPC_SERR_LOCATOR 0x1C /* 4 bytes */
-#define SHPC_SERR_INT 0x20 /* 4 bytes */
-#define SHPC_INT_DIS 0x1
-#define SHPC_SERR_DIS 0x2
-#define SHPC_CMD_INT_DIS 0x4
-#define SHPC_ARB_SERR_DIS 0x8
-#define SHPC_CMD_DETECTED 0x10000
-#define SHPC_ARB_DETECTED 0x20000
- /* 4 bytes * slot # (start from 0) */
-#define SHPC_SLOT_REG(s) (0x24 + (s) * 4)
- /* 2 bytes */
-#define SHPC_SLOT_STATUS(s) (0x0 + SHPC_SLOT_REG(s))
-
-/* Same slot state masks are used for command and status registers */
-#define SHPC_SLOT_STATE_MASK 0x03
-#define SHPC_SLOT_STATE_SHIFT \
- ctz32(SHPC_SLOT_STATE_MASK)
-
-#define SHPC_STATE_NO 0x0
-#define SHPC_STATE_PWRONLY 0x1
-#define SHPC_STATE_ENABLED 0x2
-#define SHPC_STATE_DISABLED 0x3
-
-#define SHPC_SLOT_PWR_LED_MASK 0xC
-#define SHPC_SLOT_PWR_LED_SHIFT \
- ctz32(SHPC_SLOT_PWR_LED_MASK)
-#define SHPC_SLOT_ATTN_LED_MASK 0x30
-#define SHPC_SLOT_ATTN_LED_SHIFT \
- ctz32(SHPC_SLOT_ATTN_LED_MASK)
-
-#define SHPC_LED_NO 0x0
-#define SHPC_LED_ON 0x1
-#define SHPC_LED_BLINK 0x2
-#define SHPC_LED_OFF 0x3
-
-#define SHPC_SLOT_STATUS_PWR_FAULT 0x40
-#define SHPC_SLOT_STATUS_BUTTON 0x80
-#define SHPC_SLOT_STATUS_MRL_OPEN 0x100
-#define SHPC_SLOT_STATUS_66 0x200
-#define SHPC_SLOT_STATUS_PRSNT_MASK 0xC00
-#define SHPC_SLOT_STATUS_PRSNT_EMPTY 0x3
-#define SHPC_SLOT_STATUS_PRSNT_25W 0x1
-#define SHPC_SLOT_STATUS_PRSNT_15W 0x2
-#define SHPC_SLOT_STATUS_PRSNT_7_5W 0x0
-
-#define SHPC_SLOT_STATUS_PRSNT_PCIX 0x3000
-
-
- /* 1 byte */
-#define SHPC_SLOT_EVENT_LATCH(s) (0x2 + SHPC_SLOT_REG(s))
- /* 1 byte */
-#define SHPC_SLOT_EVENT_SERR_INT_DIS(d, s) (0x3 + SHPC_SLOT_REG(s))
-#define SHPC_SLOT_EVENT_PRESENCE 0x01
-#define SHPC_SLOT_EVENT_ISOLATED_FAULT 0x02
-#define SHPC_SLOT_EVENT_BUTTON 0x04
-#define SHPC_SLOT_EVENT_MRL 0x08
-#define SHPC_SLOT_EVENT_CONNECTED_FAULT 0x10
-/* Bits below are used for Serr/Int disable only */
-#define SHPC_SLOT_EVENT_MRL_SERR_DIS 0x20
-#define SHPC_SLOT_EVENT_CONNECTED_FAULT_SERR_DIS 0x40
-
-#define SHPC_MIN_SLOTS 1
-#define SHPC_MAX_SLOTS 31
-#define SHPC_SIZEOF(d) SHPC_SLOT_REG((d)->shpc->nslots)
-
-/* SHPC Slot identifiers */
-
-/* Hotplug supported at 31 slots out of the total 32. We reserve slot 0,
- and give the rest of them physical *and* pci numbers starting from 1, so
- they match logical numbers. Note: this means that multiple slots must have
- different chassis number values, to make chassis+physical slot unique.
- TODO: make this configurable? */
-#define SHPC_IDX_TO_LOGICAL(slot) ((slot) + 1)
-#define SHPC_LOGICAL_TO_IDX(target) ((target) - 1)
-#define SHPC_IDX_TO_PCI(slot) ((slot) + 1)
-#define SHPC_PCI_TO_IDX(pci_slot) ((pci_slot) - 1)
-#define SHPC_IDX_TO_PHYSICAL(slot) ((slot) + 1)
-
-static int roundup_pow_of_two(int x)
-{
- x |= (x >> 1);
- x |= (x >> 2);
- x |= (x >> 4);
- x |= (x >> 8);
- x |= (x >> 16);
- return x + 1;
-}
-
-static uint16_t shpc_get_status(SHPCDevice *shpc, int slot, uint16_t msk)
-{
- uint8_t *status = shpc->config + SHPC_SLOT_STATUS(slot);
- return (pci_get_word(status) & msk) >> ctz32(msk);
-}
-
-static void shpc_set_status(SHPCDevice *shpc,
- int slot, uint8_t value, uint16_t msk)
-{
- uint8_t *status = shpc->config + SHPC_SLOT_STATUS(slot);
- pci_word_test_and_clear_mask(status, msk);
- pci_word_test_and_set_mask(status, value << ctz32(msk));
-}
-
-static void shpc_interrupt_update(PCIDevice *d)
-{
- SHPCDevice *shpc = d->shpc;
- int slot;
- int level = 0;
- uint32_t serr_int;
- uint32_t int_locator = 0;
-
- /* Update interrupt locator register */
- for (slot = 0; slot < shpc->nslots; ++slot) {
- uint8_t event = shpc->config[SHPC_SLOT_EVENT_LATCH(slot)];
- uint8_t disable = shpc->config[SHPC_SLOT_EVENT_SERR_INT_DIS(d, slot)];
- uint32_t mask = 1U << SHPC_IDX_TO_LOGICAL(slot);
- if (event & ~disable) {
- int_locator |= mask;
- }
- }
- serr_int = pci_get_long(shpc->config + SHPC_SERR_INT);
- if ((serr_int & SHPC_CMD_DETECTED) && !(serr_int & SHPC_CMD_INT_DIS)) {
- int_locator |= SHPC_INT_COMMAND;
- }
- pci_set_long(shpc->config + SHPC_INT_LOCATOR, int_locator);
- level = (!(serr_int & SHPC_INT_DIS) && int_locator) ? 1 : 0;
- if (msi_enabled(d) && shpc->msi_requested != level)
- msi_notify(d, 0);
- else
- pci_set_irq(d, level);
- shpc->msi_requested = level;
-}
-
-static void shpc_set_sec_bus_speed(SHPCDevice *shpc, uint8_t speed)
-{
- switch (speed) {
- case SHPC_SEC_BUS_33:
- shpc->config[SHPC_SEC_BUS] &= ~SHPC_SEC_BUS_MASK;
- shpc->config[SHPC_SEC_BUS] |= speed;
- break;
- default:
- pci_word_test_and_set_mask(shpc->config + SHPC_CMD_STATUS,
- SHPC_CMD_STATUS_INVALID_MODE);
- }
-}
-
-void shpc_reset(PCIDevice *d)
-{
- SHPCDevice *shpc = d->shpc;
- int nslots = shpc->nslots;
- int i;
- memset(shpc->config, 0, SHPC_SIZEOF(d));
- pci_set_byte(shpc->config + SHPC_NSLOTS, nslots);
- pci_set_long(shpc->config + SHPC_SLOTS_33, nslots);
- pci_set_long(shpc->config + SHPC_SLOTS_66, 0);
- pci_set_byte(shpc->config + SHPC_FIRST_DEV, SHPC_IDX_TO_PCI(0));
- pci_set_word(shpc->config + SHPC_PHYS_SLOT,
- SHPC_IDX_TO_PHYSICAL(0) |
- SHPC_PHYS_NUM_UP |
- SHPC_PHYS_MRL |
- SHPC_PHYS_BUTTON);
- pci_set_long(shpc->config + SHPC_SERR_INT, SHPC_INT_DIS |
- SHPC_SERR_DIS |
- SHPC_CMD_INT_DIS |
- SHPC_ARB_SERR_DIS);
- pci_set_byte(shpc->config + SHPC_PROG_IFC, SHPC_PROG_IFC_1_0);
- pci_set_word(shpc->config + SHPC_SEC_BUS, SHPC_SEC_BUS_33);
- for (i = 0; i < shpc->nslots; ++i) {
- pci_set_byte(shpc->config + SHPC_SLOT_EVENT_SERR_INT_DIS(d, i),
- SHPC_SLOT_EVENT_PRESENCE |
- SHPC_SLOT_EVENT_ISOLATED_FAULT |
- SHPC_SLOT_EVENT_BUTTON |
- SHPC_SLOT_EVENT_MRL |
- SHPC_SLOT_EVENT_CONNECTED_FAULT |
- SHPC_SLOT_EVENT_MRL_SERR_DIS |
- SHPC_SLOT_EVENT_CONNECTED_FAULT_SERR_DIS);
- if (shpc->sec_bus->devices[PCI_DEVFN(SHPC_IDX_TO_PCI(i), 0)]) {
- shpc_set_status(shpc, i, SHPC_STATE_ENABLED, SHPC_SLOT_STATE_MASK);
- shpc_set_status(shpc, i, 0, SHPC_SLOT_STATUS_MRL_OPEN);
- shpc_set_status(shpc, i, SHPC_SLOT_STATUS_PRSNT_7_5W,
- SHPC_SLOT_STATUS_PRSNT_MASK);
- shpc_set_status(shpc, i, SHPC_LED_ON, SHPC_SLOT_PWR_LED_MASK);
- } else {
- shpc_set_status(shpc, i, SHPC_STATE_DISABLED, SHPC_SLOT_STATE_MASK);
- shpc_set_status(shpc, i, 1, SHPC_SLOT_STATUS_MRL_OPEN);
- shpc_set_status(shpc, i, SHPC_SLOT_STATUS_PRSNT_EMPTY,
- SHPC_SLOT_STATUS_PRSNT_MASK);
- shpc_set_status(shpc, i, SHPC_LED_OFF, SHPC_SLOT_PWR_LED_MASK);
- }
- shpc_set_status(shpc, i, 0, SHPC_SLOT_STATUS_66);
- }
- shpc_set_sec_bus_speed(shpc, SHPC_SEC_BUS_33);
- shpc->msi_requested = 0;
- shpc_interrupt_update(d);
-}
-
-static void shpc_invalid_command(SHPCDevice *shpc)
-{
- pci_word_test_and_set_mask(shpc->config + SHPC_CMD_STATUS,
- SHPC_CMD_STATUS_INVALID_CMD);
-}
-
-static void shpc_free_devices_in_slot(SHPCDevice *shpc, int slot)
-{
- int devfn;
- int pci_slot = SHPC_IDX_TO_PCI(slot);
- for (devfn = PCI_DEVFN(pci_slot, 0);
- devfn <= PCI_DEVFN(pci_slot, PCI_FUNC_MAX - 1);
- ++devfn) {
- PCIDevice *affected_dev = shpc->sec_bus->devices[devfn];
- if (affected_dev) {
- object_unparent(OBJECT(affected_dev));
- }
- }
-}
-
-static void shpc_slot_command(SHPCDevice *shpc, uint8_t target,
- uint8_t state, uint8_t power, uint8_t attn)
-{
- uint8_t current_state;
- int slot = SHPC_LOGICAL_TO_IDX(target);
- if (target < SHPC_CMD_TRGT_MIN || slot >= shpc->nslots) {
- shpc_invalid_command(shpc);
- return;
- }
- current_state = shpc_get_status(shpc, slot, SHPC_SLOT_STATE_MASK);
- if (current_state == SHPC_STATE_ENABLED && state == SHPC_STATE_PWRONLY) {
- shpc_invalid_command(shpc);
- return;
- }
-
- switch (power) {
- case SHPC_LED_NO:
- break;
- default:
- /* TODO: send event to monitor */
- shpc_set_status(shpc, slot, power, SHPC_SLOT_PWR_LED_MASK);
- }
- switch (attn) {
- case SHPC_LED_NO:
- break;
- default:
- /* TODO: send event to monitor */
- shpc_set_status(shpc, slot, attn, SHPC_SLOT_ATTN_LED_MASK);
- }
-
- if ((current_state == SHPC_STATE_DISABLED && state == SHPC_STATE_PWRONLY) ||
- (current_state == SHPC_STATE_DISABLED && state == SHPC_STATE_ENABLED)) {
- shpc_set_status(shpc, slot, state, SHPC_SLOT_STATE_MASK);
- } else if ((current_state == SHPC_STATE_ENABLED ||
- current_state == SHPC_STATE_PWRONLY) &&
- state == SHPC_STATE_DISABLED) {
- shpc_set_status(shpc, slot, state, SHPC_SLOT_STATE_MASK);
- power = shpc_get_status(shpc, slot, SHPC_SLOT_PWR_LED_MASK);
- /* TODO: track what monitor requested. */
- /* Look at LED to figure out whether it's ok to remove the device. */
- if (power == SHPC_LED_OFF) {
- shpc_free_devices_in_slot(shpc, slot);
- shpc_set_status(shpc, slot, 1, SHPC_SLOT_STATUS_MRL_OPEN);
- shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_EMPTY,
- SHPC_SLOT_STATUS_PRSNT_MASK);
- shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |=
- SHPC_SLOT_EVENT_BUTTON |
- SHPC_SLOT_EVENT_MRL |
- SHPC_SLOT_EVENT_PRESENCE;
- }
- }
-}
-
-static void shpc_command(SHPCDevice *shpc)
-{
- uint8_t code = pci_get_byte(shpc->config + SHPC_CMD_CODE);
- uint8_t speed;
- uint8_t target;
- uint8_t attn;
- uint8_t power;
- uint8_t state;
- int i;
-
- /* Clear status from the previous command. */
- pci_word_test_and_clear_mask(shpc->config + SHPC_CMD_STATUS,
- SHPC_CMD_STATUS_BUSY |
- SHPC_CMD_STATUS_MRL_OPEN |
- SHPC_CMD_STATUS_INVALID_CMD |
- SHPC_CMD_STATUS_INVALID_MODE);
- switch (code) {
- case 0x00 ... 0x3f:
- target = shpc->config[SHPC_CMD_TRGT] & SHPC_CMD_TRGT_MAX;
- state = (code & SHPC_SLOT_STATE_MASK) >> SHPC_SLOT_STATE_SHIFT;
- power = (code & SHPC_SLOT_PWR_LED_MASK) >> SHPC_SLOT_PWR_LED_SHIFT;
- attn = (code & SHPC_SLOT_ATTN_LED_MASK) >> SHPC_SLOT_ATTN_LED_SHIFT;
- shpc_slot_command(shpc, target, state, power, attn);
- break;
- case 0x40 ... 0x47:
- speed = code & SHPC_SEC_BUS_MASK;
- shpc_set_sec_bus_speed(shpc, speed);
- break;
- case 0x48:
- /* Power only all slots */
- /* first verify no slots are enabled */
- for (i = 0; i < shpc->nslots; ++i) {
- state = shpc_get_status(shpc, i, SHPC_SLOT_STATE_MASK);
- if (state == SHPC_STATE_ENABLED) {
- shpc_invalid_command(shpc);
- goto done;
- }
- }
- for (i = 0; i < shpc->nslots; ++i) {
- if (!(shpc_get_status(shpc, i, SHPC_SLOT_STATUS_MRL_OPEN))) {
- shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN,
- SHPC_STATE_PWRONLY, SHPC_LED_ON, SHPC_LED_NO);
- } else {
- shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN,
- SHPC_STATE_NO, SHPC_LED_OFF, SHPC_LED_NO);
- }
- }
- break;
- case 0x49:
- /* Enable all slots */
- /* TODO: Spec says this shall fail if some are already enabled.
- * This doesn't make sense - why not? a spec bug? */
- for (i = 0; i < shpc->nslots; ++i) {
- state = shpc_get_status(shpc, i, SHPC_SLOT_STATE_MASK);
- if (state == SHPC_STATE_ENABLED) {
- shpc_invalid_command(shpc);
- goto done;
- }
- }
- for (i = 0; i < shpc->nslots; ++i) {
- if (!(shpc_get_status(shpc, i, SHPC_SLOT_STATUS_MRL_OPEN))) {
- shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN,
- SHPC_STATE_ENABLED, SHPC_LED_ON, SHPC_LED_NO);
- } else {
- shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN,
- SHPC_STATE_NO, SHPC_LED_OFF, SHPC_LED_NO);
- }
- }
- break;
- default:
- shpc_invalid_command(shpc);
- break;
- }
-done:
- pci_long_test_and_set_mask(shpc->config + SHPC_SERR_INT, SHPC_CMD_DETECTED);
-}
-
-static void shpc_write(PCIDevice *d, unsigned addr, uint64_t val, int l)
-{
- SHPCDevice *shpc = d->shpc;
- int i;
- if (addr >= SHPC_SIZEOF(d)) {
- return;
- }
- l = MIN(l, SHPC_SIZEOF(d) - addr);
-
- /* TODO: code duplicated from pci.c */
- for (i = 0; i < l; val >>= 8, ++i) {
- unsigned a = addr + i;
- uint8_t wmask = shpc->wmask[a];
- uint8_t w1cmask = shpc->w1cmask[a];
- assert(!(wmask & w1cmask));
- shpc->config[a] = (shpc->config[a] & ~wmask) | (val & wmask);
- shpc->config[a] &= ~(val & w1cmask); /* W1C: Write 1 to Clear */
- }
- if (ranges_overlap(addr, l, SHPC_CMD_CODE, 2)) {
- shpc_command(shpc);
- }
- shpc_interrupt_update(d);
-}
-
-static uint64_t shpc_read(PCIDevice *d, unsigned addr, int l)
-{
- uint64_t val = 0x0;
- if (addr >= SHPC_SIZEOF(d)) {
- return val;
- }
- l = MIN(l, SHPC_SIZEOF(d) - addr);
- memcpy(&val, d->shpc->config + addr, l);
- return val;
-}
-
-/* SHPC Bridge Capability */
-#define SHPC_CAP_LENGTH 0x08
-#define SHPC_CAP_DWORD_SELECT 0x2 /* 1 byte */
-#define SHPC_CAP_CxP 0x3 /* 1 byte: CSP, CIP */
-#define SHPC_CAP_DWORD_DATA 0x4 /* 4 bytes */
-#define SHPC_CAP_CSP_MASK 0x4
-#define SHPC_CAP_CIP_MASK 0x8
-
-static uint8_t shpc_cap_dword(PCIDevice *d)
-{
- return pci_get_byte(d->config + d->shpc->cap + SHPC_CAP_DWORD_SELECT);
-}
-
-/* Update dword data capability register */
-static void shpc_cap_update_dword(PCIDevice *d)
-{
- unsigned data;
- data = shpc_read(d, shpc_cap_dword(d) * 4, 4);
- pci_set_long(d->config + d->shpc->cap + SHPC_CAP_DWORD_DATA, data);
-}
-
-/* Add SHPC capability to the config space for the device. */
-static int shpc_cap_add_config(PCIDevice *d)
-{
- uint8_t *config;
- int config_offset;
- config_offset = pci_add_capability(d, PCI_CAP_ID_SHPC,
- 0, SHPC_CAP_LENGTH);
- if (config_offset < 0) {
- return config_offset;
- }
- config = d->config + config_offset;
-
- pci_set_byte(config + SHPC_CAP_DWORD_SELECT, 0);
- pci_set_byte(config + SHPC_CAP_CxP, 0);
- pci_set_long(config + SHPC_CAP_DWORD_DATA, 0);
- d->shpc->cap = config_offset;
- /* Make dword select and data writeable. */
- pci_set_byte(d->wmask + config_offset + SHPC_CAP_DWORD_SELECT, 0xff);
- pci_set_long(d->wmask + config_offset + SHPC_CAP_DWORD_DATA, 0xffffffff);
- return 0;
-}
-
-static uint64_t shpc_mmio_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- return shpc_read(opaque, addr, size);
-}
-
-static void shpc_mmio_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- shpc_write(opaque, addr, val, size);
-}
-
-static const MemoryRegionOps shpc_mmio_ops = {
- .read = shpc_mmio_read,
- .write = shpc_mmio_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .valid = {
- /* SHPC ECN requires dword accesses, but the original 1.0 spec doesn't.
- * It's easier to suppport all sizes than worry about it. */
- .min_access_size = 1,
- .max_access_size = 4,
- },
-};
-static void shpc_device_hotplug_common(PCIDevice *affected_dev, int *slot,
- SHPCDevice *shpc, Error **errp)
-{
- int pci_slot = PCI_SLOT(affected_dev->devfn);
- *slot = SHPC_PCI_TO_IDX(pci_slot);
-
- if (pci_slot < SHPC_IDX_TO_PCI(0) || *slot >= shpc->nslots) {
- error_setg(errp, "Unsupported PCI slot %d for standard hotplug "
- "controller. Valid slots are between %d and %d.",
- pci_slot, SHPC_IDX_TO_PCI(0),
- SHPC_IDX_TO_PCI(shpc->nslots) - 1);
- return;
- }
-}
-
-void shpc_device_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
- Error **errp)
-{
- Error *local_err = NULL;
- PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev);
- SHPCDevice *shpc = pci_hotplug_dev->shpc;
- int slot;
-
- shpc_device_hotplug_common(PCI_DEVICE(dev), &slot, shpc, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- /* Don't send event when device is enabled during qemu machine creation:
- * it is present on boot, no hotplug event is necessary. We do send an
- * event when the device is disabled later. */
- if (!dev->hotplugged) {
- shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_MRL_OPEN);
- shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_7_5W,
- SHPC_SLOT_STATUS_PRSNT_MASK);
- return;
- }
-
- /* This could be a cancellation of the previous removal.
- * We check MRL state to figure out. */
- if (shpc_get_status(shpc, slot, SHPC_SLOT_STATUS_MRL_OPEN)) {
- shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_MRL_OPEN);
- shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_7_5W,
- SHPC_SLOT_STATUS_PRSNT_MASK);
- shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |=
- SHPC_SLOT_EVENT_BUTTON |
- SHPC_SLOT_EVENT_MRL |
- SHPC_SLOT_EVENT_PRESENCE;
- } else {
- /* Press attention button to cancel removal */
- shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |=
- SHPC_SLOT_EVENT_BUTTON;
- }
- shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_66);
- shpc_interrupt_update(pci_hotplug_dev);
-}
-
-void shpc_device_hot_unplug_request_cb(HotplugHandler *hotplug_dev,
- DeviceState *dev, Error **errp)
-{
- Error *local_err = NULL;
- PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev);
- SHPCDevice *shpc = pci_hotplug_dev->shpc;
- uint8_t state;
- uint8_t led;
- int slot;
-
- shpc_device_hotplug_common(PCI_DEVICE(dev), &slot, shpc, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |= SHPC_SLOT_EVENT_BUTTON;
- state = shpc_get_status(shpc, slot, SHPC_SLOT_STATE_MASK);
- led = shpc_get_status(shpc, slot, SHPC_SLOT_PWR_LED_MASK);
- if (state == SHPC_STATE_DISABLED && led == SHPC_LED_OFF) {
- shpc_free_devices_in_slot(shpc, slot);
- shpc_set_status(shpc, slot, 1, SHPC_SLOT_STATUS_MRL_OPEN);
- shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_EMPTY,
- SHPC_SLOT_STATUS_PRSNT_MASK);
- shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |=
- SHPC_SLOT_EVENT_MRL |
- SHPC_SLOT_EVENT_PRESENCE;
- }
- shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_66);
- shpc_interrupt_update(pci_hotplug_dev);
-}
-
-/* Initialize the SHPC structure in bridge's BAR. */
-int shpc_init(PCIDevice *d, PCIBus *sec_bus, MemoryRegion *bar, unsigned offset)
-{
- int i, ret;
- int nslots = SHPC_MAX_SLOTS; /* TODO: qdev property? */
- SHPCDevice *shpc = d->shpc = g_malloc0(sizeof(*d->shpc));
- shpc->sec_bus = sec_bus;
- ret = shpc_cap_add_config(d);
- if (ret) {
- g_free(d->shpc);
- return ret;
- }
- if (nslots < SHPC_MIN_SLOTS) {
- return 0;
- }
- if (nslots > SHPC_MAX_SLOTS ||
- SHPC_IDX_TO_PCI(nslots) > PCI_SLOT_MAX) {
- /* TODO: report an error mesage that makes sense. */
- return -EINVAL;
- }
- shpc->nslots = nslots;
- shpc->config = g_malloc0(SHPC_SIZEOF(d));
- shpc->cmask = g_malloc0(SHPC_SIZEOF(d));
- shpc->wmask = g_malloc0(SHPC_SIZEOF(d));
- shpc->w1cmask = g_malloc0(SHPC_SIZEOF(d));
-
- shpc_reset(d);
-
- pci_set_long(shpc->config + SHPC_BASE_OFFSET, offset);
-
- pci_set_byte(shpc->wmask + SHPC_CMD_CODE, 0xff);
- pci_set_byte(shpc->wmask + SHPC_CMD_TRGT, SHPC_CMD_TRGT_MAX);
- pci_set_byte(shpc->wmask + SHPC_CMD_TRGT, SHPC_CMD_TRGT_MAX);
- pci_set_long(shpc->wmask + SHPC_SERR_INT,
- SHPC_INT_DIS |
- SHPC_SERR_DIS |
- SHPC_CMD_INT_DIS |
- SHPC_ARB_SERR_DIS);
- pci_set_long(shpc->w1cmask + SHPC_SERR_INT,
- SHPC_CMD_DETECTED |
- SHPC_ARB_DETECTED);
- for (i = 0; i < nslots; ++i) {
- pci_set_byte(shpc->wmask +
- SHPC_SLOT_EVENT_SERR_INT_DIS(d, i),
- SHPC_SLOT_EVENT_PRESENCE |
- SHPC_SLOT_EVENT_ISOLATED_FAULT |
- SHPC_SLOT_EVENT_BUTTON |
- SHPC_SLOT_EVENT_MRL |
- SHPC_SLOT_EVENT_CONNECTED_FAULT |
- SHPC_SLOT_EVENT_MRL_SERR_DIS |
- SHPC_SLOT_EVENT_CONNECTED_FAULT_SERR_DIS);
- pci_set_byte(shpc->w1cmask +
- SHPC_SLOT_EVENT_LATCH(i),
- SHPC_SLOT_EVENT_PRESENCE |
- SHPC_SLOT_EVENT_ISOLATED_FAULT |
- SHPC_SLOT_EVENT_BUTTON |
- SHPC_SLOT_EVENT_MRL |
- SHPC_SLOT_EVENT_CONNECTED_FAULT);
- }
-
- /* TODO: init cmask */
- memory_region_init_io(&shpc->mmio, OBJECT(d), &shpc_mmio_ops,
- d, "shpc-mmio", SHPC_SIZEOF(d));
- shpc_cap_update_dword(d);
- memory_region_add_subregion(bar, offset, &shpc->mmio);
-
- qbus_set_hotplug_handler(BUS(sec_bus), DEVICE(d), NULL);
-
- d->cap_present |= QEMU_PCI_CAP_SHPC;
- return 0;
-}
-
-int shpc_bar_size(PCIDevice *d)
-{
- return roundup_pow_of_two(SHPC_SLOT_REG(SHPC_MAX_SLOTS));
-}
-
-void shpc_cleanup(PCIDevice *d, MemoryRegion *bar)
-{
- SHPCDevice *shpc = d->shpc;
- d->cap_present &= ~QEMU_PCI_CAP_SHPC;
- memory_region_del_subregion(bar, &shpc->mmio);
- /* TODO: cleanup config space changes? */
-}
-
-void shpc_free(PCIDevice *d)
-{
- SHPCDevice *shpc = d->shpc;
- if (!shpc) {
- return;
- }
- object_unparent(OBJECT(&shpc->mmio));
- g_free(shpc->config);
- g_free(shpc->cmask);
- g_free(shpc->wmask);
- g_free(shpc->w1cmask);
- g_free(shpc);
- d->shpc = NULL;
-}
-
-void shpc_cap_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l)
-{
- if (!ranges_overlap(addr, l, d->shpc->cap, SHPC_CAP_LENGTH)) {
- return;
- }
- if (ranges_overlap(addr, l, d->shpc->cap + SHPC_CAP_DWORD_DATA, 4)) {
- unsigned dword_data;
- dword_data = pci_get_long(d->shpc->config + d->shpc->cap
- + SHPC_CAP_DWORD_DATA);
- shpc_write(d, shpc_cap_dword(d) * 4, dword_data, 4);
- }
- /* Update cap dword data in case guest is going to read it. */
- shpc_cap_update_dword(d);
-}
-
-static void shpc_save(QEMUFile *f, void *pv, size_t size)
-{
- PCIDevice *d = container_of(pv, PCIDevice, shpc);
- qemu_put_buffer(f, d->shpc->config, SHPC_SIZEOF(d));
-}
-
-static int shpc_load(QEMUFile *f, void *pv, size_t size)
-{
- PCIDevice *d = container_of(pv, PCIDevice, shpc);
- int ret = qemu_get_buffer(f, d->shpc->config, SHPC_SIZEOF(d));
- if (ret != SHPC_SIZEOF(d)) {
- return -EINVAL;
- }
- /* Make sure we don't lose notifications. An extra interrupt is harmless. */
- d->shpc->msi_requested = 0;
- shpc_interrupt_update(d);
- return 0;
-}
-
-VMStateInfo shpc_vmstate_info = {
- .name = "shpc",
- .get = shpc_load,
- .put = shpc_save,
-};
diff --git a/qemu/hw/pci/slotid_cap.c b/qemu/hw/pci/slotid_cap.c
deleted file mode 100644
index aec1e9166..000000000
--- a/qemu/hw/pci/slotid_cap.c
+++ /dev/null
@@ -1,46 +0,0 @@
-#include "qemu/osdep.h"
-#include "hw/pci/slotid_cap.h"
-#include "hw/pci/pci.h"
-#include "qemu/error-report.h"
-
-#define SLOTID_CAP_LENGTH 4
-#define SLOTID_NSLOTS_SHIFT ctz32(PCI_SID_ESR_NSLOTS)
-
-int slotid_cap_init(PCIDevice *d, int nslots,
- uint8_t chassis,
- unsigned offset)
-{
- int cap;
- if (!chassis) {
- error_report("Bridge chassis not specified. Each bridge is required "
- "to be assigned a unique chassis id > 0.");
- return -EINVAL;
- }
- if (nslots < 0 || nslots > (PCI_SID_ESR_NSLOTS >> SLOTID_NSLOTS_SHIFT)) {
- /* TODO: error report? */
- return -EINVAL;
- }
-
- cap = pci_add_capability(d, PCI_CAP_ID_SLOTID, offset, SLOTID_CAP_LENGTH);
- if (cap < 0) {
- return cap;
- }
- /* We make each chassis unique, this way each bridge is First in Chassis */
- d->config[cap + PCI_SID_ESR] = PCI_SID_ESR_FIC |
- (nslots << SLOTID_NSLOTS_SHIFT);
- d->cmask[cap + PCI_SID_ESR] = 0xff;
- d->config[cap + PCI_SID_CHASSIS_NR] = chassis;
- /* Note: Chassis number register is non-volatile,
- so we don't reset it. */
- /* TODO: store in eeprom? */
- d->wmask[cap + PCI_SID_CHASSIS_NR] = 0xff;
-
- d->cap_present |= QEMU_PCI_CAP_SLOTID;
- return 0;
-}
-
-void slotid_cap_cleanup(PCIDevice *d)
-{
- /* TODO: cleanup config space? */
- d->cap_present &= ~QEMU_PCI_CAP_SLOTID;
-}
diff --git a/qemu/hw/pcmcia/Makefile.objs b/qemu/hw/pcmcia/Makefile.objs
deleted file mode 100644
index 4eac060c9..000000000
--- a/qemu/hw/pcmcia/Makefile.objs
+++ /dev/null
@@ -1,2 +0,0 @@
-common-obj-y += pcmcia.o
-obj-$(CONFIG_PXA2XX) += pxa2xx.o
diff --git a/qemu/hw/pcmcia/pcmcia.c b/qemu/hw/pcmcia/pcmcia.c
deleted file mode 100644
index 195672186..000000000
--- a/qemu/hw/pcmcia/pcmcia.c
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * PCMCIA emulation
- *
- * Copyright 2013 SUSE LINUX Products GmbH
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "hw/hw.h"
-#include "hw/pcmcia.h"
-
-static const TypeInfo pcmcia_card_type_info = {
- .name = TYPE_PCMCIA_CARD,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(PCMCIACardState),
- .abstract = true,
- .class_size = sizeof(PCMCIACardClass),
-};
-
-static void pcmcia_register_types(void)
-{
- type_register_static(&pcmcia_card_type_info);
-}
-
-type_init(pcmcia_register_types)
diff --git a/qemu/hw/pcmcia/pxa2xx.c b/qemu/hw/pcmcia/pxa2xx.c
deleted file mode 100644
index 20c9c753d..000000000
--- a/qemu/hw/pcmcia/pxa2xx.c
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * Intel XScale PXA255/270 PC Card and CompactFlash Interface.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GPLv2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "hw/pcmcia.h"
-#include "hw/arm/pxa.h"
-
-#define TYPE_PXA2XX_PCMCIA "pxa2xx-pcmcia"
-#define PXA2XX_PCMCIA(obj) \
- OBJECT_CHECK(PXA2xxPCMCIAState, obj, TYPE_PXA2XX_PCMCIA)
-
-struct PXA2xxPCMCIAState {
- SysBusDevice parent_obj;
-
- PCMCIASocket slot;
- MemoryRegion container_mem;
- MemoryRegion common_iomem;
- MemoryRegion attr_iomem;
- MemoryRegion iomem;
-
- qemu_irq irq;
- qemu_irq cd_irq;
-
- PCMCIACardState *card;
-};
-
-static uint64_t pxa2xx_pcmcia_common_read(void *opaque,
- hwaddr offset, unsigned size)
-{
- PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
- PCMCIACardClass *pcc;
-
- if (s->slot.attached) {
- pcc = PCMCIA_CARD_GET_CLASS(s->card);
- return pcc->common_read(s->card, offset);
- }
-
- return 0;
-}
-
-static void pxa2xx_pcmcia_common_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
- PCMCIACardClass *pcc;
-
- if (s->slot.attached) {
- pcc = PCMCIA_CARD_GET_CLASS(s->card);
- pcc->common_write(s->card, offset, value);
- }
-}
-
-static uint64_t pxa2xx_pcmcia_attr_read(void *opaque,
- hwaddr offset, unsigned size)
-{
- PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
- PCMCIACardClass *pcc;
-
- if (s->slot.attached) {
- pcc = PCMCIA_CARD_GET_CLASS(s->card);
- return pcc->attr_read(s->card, offset);
- }
-
- return 0;
-}
-
-static void pxa2xx_pcmcia_attr_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
- PCMCIACardClass *pcc;
-
- if (s->slot.attached) {
- pcc = PCMCIA_CARD_GET_CLASS(s->card);
- pcc->attr_write(s->card, offset, value);
- }
-}
-
-static uint64_t pxa2xx_pcmcia_io_read(void *opaque,
- hwaddr offset, unsigned size)
-{
- PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
- PCMCIACardClass *pcc;
-
- if (s->slot.attached) {
- pcc = PCMCIA_CARD_GET_CLASS(s->card);
- return pcc->io_read(s->card, offset);
- }
-
- return 0;
-}
-
-static void pxa2xx_pcmcia_io_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
- PCMCIACardClass *pcc;
-
- if (s->slot.attached) {
- pcc = PCMCIA_CARD_GET_CLASS(s->card);
- pcc->io_write(s->card, offset, value);
- }
-}
-
-static const MemoryRegionOps pxa2xx_pcmcia_common_ops = {
- .read = pxa2xx_pcmcia_common_read,
- .write = pxa2xx_pcmcia_common_write,
- .endianness = DEVICE_NATIVE_ENDIAN
-};
-
-static const MemoryRegionOps pxa2xx_pcmcia_attr_ops = {
- .read = pxa2xx_pcmcia_attr_read,
- .write = pxa2xx_pcmcia_attr_write,
- .endianness = DEVICE_NATIVE_ENDIAN
-};
-
-static const MemoryRegionOps pxa2xx_pcmcia_io_ops = {
- .read = pxa2xx_pcmcia_io_read,
- .write = pxa2xx_pcmcia_io_write,
- .endianness = DEVICE_NATIVE_ENDIAN
-};
-
-static void pxa2xx_pcmcia_set_irq(void *opaque, int line, int level)
-{
- PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
- if (!s->irq)
- return;
-
- qemu_set_irq(s->irq, level);
-}
-
-PXA2xxPCMCIAState *pxa2xx_pcmcia_init(MemoryRegion *sysmem,
- hwaddr base)
-{
- DeviceState *dev;
- PXA2xxPCMCIAState *s;
-
- dev = qdev_create(NULL, TYPE_PXA2XX_PCMCIA);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
- s = PXA2XX_PCMCIA(dev);
-
- qdev_init_nofail(dev);
-
- return s;
-}
-
-static void pxa2xx_pcmcia_initfn(Object *obj)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- PXA2xxPCMCIAState *s = PXA2XX_PCMCIA(obj);
-
- memory_region_init(&s->container_mem, obj, "container", 0x10000000);
- sysbus_init_mmio(sbd, &s->container_mem);
-
- /* Socket I/O Memory Space */
- memory_region_init_io(&s->iomem, obj, &pxa2xx_pcmcia_io_ops, s,
- "pxa2xx-pcmcia-io", 0x04000000);
- memory_region_add_subregion(&s->container_mem, 0x00000000,
- &s->iomem);
-
- /* Then next 64 MB is reserved */
-
- /* Socket Attribute Memory Space */
- memory_region_init_io(&s->attr_iomem, obj, &pxa2xx_pcmcia_attr_ops, s,
- "pxa2xx-pcmcia-attribute", 0x04000000);
- memory_region_add_subregion(&s->container_mem, 0x08000000,
- &s->attr_iomem);
-
- /* Socket Common Memory Space */
- memory_region_init_io(&s->common_iomem, obj, &pxa2xx_pcmcia_common_ops, s,
- "pxa2xx-pcmcia-common", 0x04000000);
- memory_region_add_subregion(&s->container_mem, 0x0c000000,
- &s->common_iomem);
-
- s->slot.irq = qemu_allocate_irq(pxa2xx_pcmcia_set_irq, s, 0);
-
- object_property_add_link(obj, "card", TYPE_PCMCIA_CARD,
- (Object **)&s->card,
- NULL, /* read-only property */
- 0, NULL);
-}
-
-/* Insert a new card into a slot */
-int pxa2xx_pcmcia_attach(void *opaque, PCMCIACardState *card)
-{
- PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
- PCMCIACardClass *pcc;
-
- if (s->slot.attached) {
- return -EEXIST;
- }
-
- if (s->cd_irq) {
- qemu_irq_raise(s->cd_irq);
- }
-
- s->card = card;
- pcc = PCMCIA_CARD_GET_CLASS(s->card);
-
- s->slot.attached = true;
- s->card->slot = &s->slot;
- pcc->attach(s->card);
-
- return 0;
-}
-
-/* Eject card from the slot */
-int pxa2xx_pcmcia_detach(void *opaque)
-{
- PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
- PCMCIACardClass *pcc;
-
- if (!s->slot.attached) {
- return -ENOENT;
- }
-
- pcc = PCMCIA_CARD_GET_CLASS(s->card);
- pcc->detach(s->card);
- s->card->slot = NULL;
- s->card = NULL;
-
- s->slot.attached = false;
-
- if (s->irq) {
- qemu_irq_lower(s->irq);
- }
- if (s->cd_irq) {
- qemu_irq_lower(s->cd_irq);
- }
-
- return 0;
-}
-
-/* Who to notify on card events */
-void pxa2xx_pcmcia_set_irq_cb(void *opaque, qemu_irq irq, qemu_irq cd_irq)
-{
- PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
- s->irq = irq;
- s->cd_irq = cd_irq;
-}
-
-static const TypeInfo pxa2xx_pcmcia_type_info = {
- .name = TYPE_PXA2XX_PCMCIA,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PXA2xxPCMCIAState),
- .instance_init = pxa2xx_pcmcia_initfn,
-};
-
-static void pxa2xx_pcmcia_register_types(void)
-{
- type_register_static(&pxa2xx_pcmcia_type_info);
-}
-
-type_init(pxa2xx_pcmcia_register_types)
diff --git a/qemu/hw/ppc/Makefile.objs b/qemu/hw/ppc/Makefile.objs
deleted file mode 100644
index c1ffc7771..000000000
--- a/qemu/hw/ppc/Makefile.objs
+++ /dev/null
@@ -1,23 +0,0 @@
-# shared objects
-obj-y += ppc.o ppc_booke.o
-# IBM pSeries (sPAPR)
-obj-$(CONFIG_PSERIES) += spapr.o spapr_vio.o spapr_events.o
-obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_iommu.o spapr_rtas.o
-obj-$(CONFIG_PSERIES) += spapr_pci.o spapr_rtc.o spapr_drc.o spapr_rng.o
-ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy)
-obj-y += spapr_pci_vfio.o
-endif
-# PowerPC 4xx boards
-obj-y += ppc405_boards.o ppc4xx_devs.o ppc405_uc.o ppc440_bamboo.o
-obj-y += ppc4xx_pci.o
-# PReP
-obj-$(CONFIG_PREP) += prep.o
-# OldWorld PowerMac
-obj-$(CONFIG_MAC) += mac_oldworld.o
-# NewWorld PowerMac
-obj-$(CONFIG_MAC) += mac_newworld.o
-# e500
-obj-$(CONFIG_E500) += e500.o mpc8544ds.o e500plat.o
-obj-$(CONFIG_E500) += mpc8544_guts.o ppce500_spin.o
-# PowerPC 440 Xilinx ML507 reference board.
-obj-$(CONFIG_XILINX) += virtex_ml507.o
diff --git a/qemu/hw/ppc/e500-ccsr.h b/qemu/hw/ppc/e500-ccsr.h
deleted file mode 100644
index 12a2ba4b9..000000000
--- a/qemu/hw/ppc/e500-ccsr.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef E500_CCSR_H
-#define E500_CCSR_H
-
-#include "hw/sysbus.h"
-
-typedef struct PPCE500CCSRState {
- /*< private >*/
- SysBusDevice parent;
- /*< public >*/
-
- MemoryRegion ccsr_space;
-} PPCE500CCSRState;
-
-#define TYPE_CCSR "e500-ccsr"
-#define CCSR(obj) OBJECT_CHECK(PPCE500CCSRState, (obj), TYPE_CCSR)
-
-#endif /* E500_CCSR_H */
diff --git a/qemu/hw/ppc/e500.c b/qemu/hw/ppc/e500.c
deleted file mode 100644
index ee1c60b82..000000000
--- a/qemu/hw/ppc/e500.c
+++ /dev/null
@@ -1,1082 +0,0 @@
-/*
- * QEMU PowerPC e500-based platforms
- *
- * Copyright (C) 2009 Freescale Semiconductor, Inc. All rights reserved.
- *
- * Author: Yu Liu, <yu.liu@freescale.com>
- *
- * This file is derived from hw/ppc440_bamboo.c,
- * the copyright for that material belongs to the original owners.
- *
- * This is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "e500.h"
-#include "e500-ccsr.h"
-#include "net/net.h"
-#include "qemu/config-file.h"
-#include "hw/hw.h"
-#include "hw/char/serial.h"
-#include "hw/pci/pci.h"
-#include "hw/boards.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/kvm.h"
-#include "kvm_ppc.h"
-#include "sysemu/device_tree.h"
-#include "hw/ppc/openpic.h"
-#include "hw/ppc/ppc.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "hw/sysbus.h"
-#include "exec/address-spaces.h"
-#include "qemu/host-utils.h"
-#include "hw/pci-host/ppce500.h"
-#include "qemu/error-report.h"
-#include "hw/platform-bus.h"
-#include "hw/net/fsl_etsec/etsec.h"
-
-#define EPAPR_MAGIC (0x45504150)
-#define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb"
-#define DTC_LOAD_PAD 0x1800000
-#define DTC_PAD_MASK 0xFFFFF
-#define DTB_MAX_SIZE (8 * 1024 * 1024)
-#define INITRD_LOAD_PAD 0x2000000
-#define INITRD_PAD_MASK 0xFFFFFF
-
-#define RAM_SIZES_ALIGN (64UL << 20)
-
-/* TODO: parameterize */
-#define MPC8544_CCSRBAR_SIZE 0x00100000ULL
-#define MPC8544_MPIC_REGS_OFFSET 0x40000ULL
-#define MPC8544_MSI_REGS_OFFSET 0x41600ULL
-#define MPC8544_SERIAL0_REGS_OFFSET 0x4500ULL
-#define MPC8544_SERIAL1_REGS_OFFSET 0x4600ULL
-#define MPC8544_PCI_REGS_OFFSET 0x8000ULL
-#define MPC8544_PCI_REGS_SIZE 0x1000ULL
-#define MPC8544_UTIL_OFFSET 0xe0000ULL
-#define MPC8XXX_GPIO_OFFSET 0x000FF000ULL
-#define MPC8XXX_GPIO_IRQ 47
-
-struct boot_info
-{
- uint32_t dt_base;
- uint32_t dt_size;
- uint32_t entry;
-};
-
-static uint32_t *pci_map_create(void *fdt, uint32_t mpic, int first_slot,
- int nr_slots, int *len)
-{
- int i = 0;
- int slot;
- int pci_irq;
- int host_irq;
- int last_slot = first_slot + nr_slots;
- uint32_t *pci_map;
-
- *len = nr_slots * 4 * 7 * sizeof(uint32_t);
- pci_map = g_malloc(*len);
-
- for (slot = first_slot; slot < last_slot; slot++) {
- for (pci_irq = 0; pci_irq < 4; pci_irq++) {
- pci_map[i++] = cpu_to_be32(slot << 11);
- pci_map[i++] = cpu_to_be32(0x0);
- pci_map[i++] = cpu_to_be32(0x0);
- pci_map[i++] = cpu_to_be32(pci_irq + 1);
- pci_map[i++] = cpu_to_be32(mpic);
- host_irq = ppce500_pci_map_irq_slot(slot, pci_irq);
- pci_map[i++] = cpu_to_be32(host_irq + 1);
- pci_map[i++] = cpu_to_be32(0x1);
- }
- }
-
- assert((i * sizeof(uint32_t)) == *len);
-
- return pci_map;
-}
-
-static void dt_serial_create(void *fdt, unsigned long long offset,
- const char *soc, const char *mpic,
- const char *alias, int idx, bool defcon)
-{
- char ser[128];
-
- snprintf(ser, sizeof(ser), "%s/serial@%llx", soc, offset);
- qemu_fdt_add_subnode(fdt, ser);
- qemu_fdt_setprop_string(fdt, ser, "device_type", "serial");
- qemu_fdt_setprop_string(fdt, ser, "compatible", "ns16550");
- qemu_fdt_setprop_cells(fdt, ser, "reg", offset, 0x100);
- qemu_fdt_setprop_cell(fdt, ser, "cell-index", idx);
- qemu_fdt_setprop_cell(fdt, ser, "clock-frequency", 0);
- qemu_fdt_setprop_cells(fdt, ser, "interrupts", 42, 2);
- qemu_fdt_setprop_phandle(fdt, ser, "interrupt-parent", mpic);
- qemu_fdt_setprop_string(fdt, "/aliases", alias, ser);
-
- if (defcon) {
- qemu_fdt_setprop_string(fdt, "/chosen", "linux,stdout-path", ser);
- }
-}
-
-static void create_dt_mpc8xxx_gpio(void *fdt, const char *soc, const char *mpic)
-{
- hwaddr mmio0 = MPC8XXX_GPIO_OFFSET;
- int irq0 = MPC8XXX_GPIO_IRQ;
- gchar *node = g_strdup_printf("%s/gpio@%"PRIx64, soc, mmio0);
- gchar *poweroff = g_strdup_printf("%s/power-off", soc);
- int gpio_ph;
-
- qemu_fdt_add_subnode(fdt, node);
- qemu_fdt_setprop_string(fdt, node, "compatible", "fsl,qoriq-gpio");
- qemu_fdt_setprop_cells(fdt, node, "reg", mmio0, 0x1000);
- qemu_fdt_setprop_cells(fdt, node, "interrupts", irq0, 0x2);
- qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", mpic);
- qemu_fdt_setprop_cells(fdt, node, "#gpio-cells", 2);
- qemu_fdt_setprop(fdt, node, "gpio-controller", NULL, 0);
- gpio_ph = qemu_fdt_alloc_phandle(fdt);
- qemu_fdt_setprop_cell(fdt, node, "phandle", gpio_ph);
- qemu_fdt_setprop_cell(fdt, node, "linux,phandle", gpio_ph);
-
- /* Power Off Pin */
- qemu_fdt_add_subnode(fdt, poweroff);
- qemu_fdt_setprop_string(fdt, poweroff, "compatible", "gpio-poweroff");
- qemu_fdt_setprop_cells(fdt, poweroff, "gpios", gpio_ph, 0, 0);
-
- g_free(node);
- g_free(poweroff);
-}
-
-typedef struct PlatformDevtreeData {
- void *fdt;
- const char *mpic;
- int irq_start;
- const char *node;
- PlatformBusDevice *pbus;
-} PlatformDevtreeData;
-
-static int create_devtree_etsec(SysBusDevice *sbdev, PlatformDevtreeData *data)
-{
- eTSEC *etsec = ETSEC_COMMON(sbdev);
- PlatformBusDevice *pbus = data->pbus;
- hwaddr mmio0 = platform_bus_get_mmio_addr(pbus, sbdev, 0);
- int irq0 = platform_bus_get_irqn(pbus, sbdev, 0);
- int irq1 = platform_bus_get_irqn(pbus, sbdev, 1);
- int irq2 = platform_bus_get_irqn(pbus, sbdev, 2);
- gchar *node = g_strdup_printf("/platform/ethernet@%"PRIx64, mmio0);
- gchar *group = g_strdup_printf("%s/queue-group", node);
- void *fdt = data->fdt;
-
- assert((int64_t)mmio0 >= 0);
- assert(irq0 >= 0);
- assert(irq1 >= 0);
- assert(irq2 >= 0);
-
- qemu_fdt_add_subnode(fdt, node);
- qemu_fdt_setprop_string(fdt, node, "device_type", "network");
- qemu_fdt_setprop_string(fdt, node, "compatible", "fsl,etsec2");
- qemu_fdt_setprop_string(fdt, node, "model", "eTSEC");
- qemu_fdt_setprop(fdt, node, "local-mac-address", etsec->conf.macaddr.a, 6);
- qemu_fdt_setprop_cells(fdt, node, "fixed-link", 0, 1, 1000, 0, 0);
-
- qemu_fdt_add_subnode(fdt, group);
- qemu_fdt_setprop_cells(fdt, group, "reg", mmio0, 0x1000);
- qemu_fdt_setprop_cells(fdt, group, "interrupts",
- data->irq_start + irq0, 0x2,
- data->irq_start + irq1, 0x2,
- data->irq_start + irq2, 0x2);
-
- g_free(node);
- g_free(group);
-
- return 0;
-}
-
-static int sysbus_device_create_devtree(SysBusDevice *sbdev, void *opaque)
-{
- PlatformDevtreeData *data = opaque;
- bool matched = false;
-
- if (object_dynamic_cast(OBJECT(sbdev), TYPE_ETSEC_COMMON)) {
- create_devtree_etsec(sbdev, data);
- matched = true;
- }
-
- if (!matched) {
- error_report("Device %s is not supported by this machine yet.",
- qdev_fw_name(DEVICE(sbdev)));
- exit(1);
- }
-
- return 0;
-}
-
-static void platform_bus_create_devtree(PPCE500Params *params, void *fdt,
- const char *mpic)
-{
- gchar *node = g_strdup_printf("/platform@%"PRIx64, params->platform_bus_base);
- const char platcomp[] = "qemu,platform\0simple-bus";
- uint64_t addr = params->platform_bus_base;
- uint64_t size = params->platform_bus_size;
- int irq_start = params->platform_bus_first_irq;
- PlatformBusDevice *pbus;
- DeviceState *dev;
-
- /* Create a /platform node that we can put all devices into */
-
- qemu_fdt_add_subnode(fdt, node);
- qemu_fdt_setprop(fdt, node, "compatible", platcomp, sizeof(platcomp));
-
- /* Our platform bus region is less than 32bit big, so 1 cell is enough for
- address and size */
- qemu_fdt_setprop_cells(fdt, node, "#size-cells", 1);
- qemu_fdt_setprop_cells(fdt, node, "#address-cells", 1);
- qemu_fdt_setprop_cells(fdt, node, "ranges", 0, addr >> 32, addr, size);
-
- qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", mpic);
-
- dev = qdev_find_recursive(sysbus_get_default(), TYPE_PLATFORM_BUS_DEVICE);
- pbus = PLATFORM_BUS_DEVICE(dev);
-
- /* We can only create dt nodes for dynamic devices when they're ready */
- if (pbus->done_gathering) {
- PlatformDevtreeData data = {
- .fdt = fdt,
- .mpic = mpic,
- .irq_start = irq_start,
- .node = node,
- .pbus = pbus,
- };
-
- /* Loop through all dynamic sysbus devices and create nodes for them */
- foreach_dynamic_sysbus_device(sysbus_device_create_devtree, &data);
- }
-
- g_free(node);
-}
-
-static int ppce500_load_device_tree(MachineState *machine,
- PPCE500Params *params,
- hwaddr addr,
- hwaddr initrd_base,
- hwaddr initrd_size,
- hwaddr kernel_base,
- hwaddr kernel_size,
- bool dry_run)
-{
- CPUPPCState *env = first_cpu->env_ptr;
- int ret = -1;
- uint64_t mem_reg_property[] = { 0, cpu_to_be64(machine->ram_size) };
- int fdt_size;
- void *fdt;
- uint8_t hypercall[16];
- uint32_t clock_freq = 400000000;
- uint32_t tb_freq = 400000000;
- int i;
- char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus";
- char soc[128];
- char mpic[128];
- uint32_t mpic_ph;
- uint32_t msi_ph;
- char gutil[128];
- char pci[128];
- char msi[128];
- uint32_t *pci_map = NULL;
- int len;
- uint32_t pci_ranges[14] =
- {
- 0x2000000, 0x0, params->pci_mmio_bus_base,
- params->pci_mmio_base >> 32, params->pci_mmio_base,
- 0x0, 0x20000000,
-
- 0x1000000, 0x0, 0x0,
- params->pci_pio_base >> 32, params->pci_pio_base,
- 0x0, 0x10000,
- };
- QemuOpts *machine_opts = qemu_get_machine_opts();
- const char *dtb_file = qemu_opt_get(machine_opts, "dtb");
- const char *toplevel_compat = qemu_opt_get(machine_opts, "dt_compatible");
-
- if (dtb_file) {
- char *filename;
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_file);
- if (!filename) {
- goto out;
- }
-
- fdt = load_device_tree(filename, &fdt_size);
- g_free(filename);
- if (!fdt) {
- goto out;
- }
- goto done;
- }
-
- fdt = create_device_tree(&fdt_size);
- if (fdt == NULL) {
- goto out;
- }
-
- /* Manipulate device tree in memory. */
- qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 2);
- qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 2);
-
- qemu_fdt_add_subnode(fdt, "/memory");
- qemu_fdt_setprop_string(fdt, "/memory", "device_type", "memory");
- qemu_fdt_setprop(fdt, "/memory", "reg", mem_reg_property,
- sizeof(mem_reg_property));
-
- qemu_fdt_add_subnode(fdt, "/chosen");
- if (initrd_size) {
- ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start",
- initrd_base);
- if (ret < 0) {
- fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
- }
-
- ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
- (initrd_base + initrd_size));
- if (ret < 0) {
- fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
- }
-
- }
-
- if (kernel_base != -1ULL) {
- qemu_fdt_setprop_cells(fdt, "/chosen", "qemu,boot-kernel",
- kernel_base >> 32, kernel_base,
- kernel_size >> 32, kernel_size);
- }
-
- ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
- machine->kernel_cmdline);
- if (ret < 0)
- fprintf(stderr, "couldn't set /chosen/bootargs\n");
-
- if (kvm_enabled()) {
- /* Read out host's frequencies */
- clock_freq = kvmppc_get_clockfreq();
- tb_freq = kvmppc_get_tbfreq();
-
- /* indicate KVM hypercall interface */
- qemu_fdt_add_subnode(fdt, "/hypervisor");
- qemu_fdt_setprop_string(fdt, "/hypervisor", "compatible",
- "linux,kvm");
- kvmppc_get_hypercall(env, hypercall, sizeof(hypercall));
- qemu_fdt_setprop(fdt, "/hypervisor", "hcall-instructions",
- hypercall, sizeof(hypercall));
- /* if KVM supports the idle hcall, set property indicating this */
- if (kvmppc_get_hasidle(env)) {
- qemu_fdt_setprop(fdt, "/hypervisor", "has-idle", NULL, 0);
- }
- }
-
- /* Create CPU nodes */
- qemu_fdt_add_subnode(fdt, "/cpus");
- qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 1);
- qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0);
-
- /* We need to generate the cpu nodes in reverse order, so Linux can pick
- the first node as boot node and be happy */
- for (i = smp_cpus - 1; i >= 0; i--) {
- CPUState *cpu;
- PowerPCCPU *pcpu;
- char cpu_name[128];
- uint64_t cpu_release_addr = params->spin_base + (i * 0x20);
-
- cpu = qemu_get_cpu(i);
- if (cpu == NULL) {
- continue;
- }
- env = cpu->env_ptr;
- pcpu = POWERPC_CPU(cpu);
-
- snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x",
- ppc_get_vcpu_dt_id(pcpu));
- qemu_fdt_add_subnode(fdt, cpu_name);
- qemu_fdt_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq);
- qemu_fdt_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq);
- qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu");
- qemu_fdt_setprop_cell(fdt, cpu_name, "reg",
- ppc_get_vcpu_dt_id(pcpu));
- qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-line-size",
- env->dcache_line_size);
- qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-line-size",
- env->icache_line_size);
- qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-size", 0x8000);
- qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-size", 0x8000);
- qemu_fdt_setprop_cell(fdt, cpu_name, "bus-frequency", 0);
- if (cpu->cpu_index) {
- qemu_fdt_setprop_string(fdt, cpu_name, "status", "disabled");
- qemu_fdt_setprop_string(fdt, cpu_name, "enable-method",
- "spin-table");
- qemu_fdt_setprop_u64(fdt, cpu_name, "cpu-release-addr",
- cpu_release_addr);
- } else {
- qemu_fdt_setprop_string(fdt, cpu_name, "status", "okay");
- }
- }
-
- qemu_fdt_add_subnode(fdt, "/aliases");
- /* XXX These should go into their respective devices' code */
- snprintf(soc, sizeof(soc), "/soc@%"PRIx64, params->ccsrbar_base);
- qemu_fdt_add_subnode(fdt, soc);
- qemu_fdt_setprop_string(fdt, soc, "device_type", "soc");
- qemu_fdt_setprop(fdt, soc, "compatible", compatible_sb,
- sizeof(compatible_sb));
- qemu_fdt_setprop_cell(fdt, soc, "#address-cells", 1);
- qemu_fdt_setprop_cell(fdt, soc, "#size-cells", 1);
- qemu_fdt_setprop_cells(fdt, soc, "ranges", 0x0,
- params->ccsrbar_base >> 32, params->ccsrbar_base,
- MPC8544_CCSRBAR_SIZE);
- /* XXX should contain a reasonable value */
- qemu_fdt_setprop_cell(fdt, soc, "bus-frequency", 0);
-
- snprintf(mpic, sizeof(mpic), "%s/pic@%llx", soc, MPC8544_MPIC_REGS_OFFSET);
- qemu_fdt_add_subnode(fdt, mpic);
- qemu_fdt_setprop_string(fdt, mpic, "device_type", "open-pic");
- qemu_fdt_setprop_string(fdt, mpic, "compatible", "fsl,mpic");
- qemu_fdt_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_OFFSET,
- 0x40000);
- qemu_fdt_setprop_cell(fdt, mpic, "#address-cells", 0);
- qemu_fdt_setprop_cell(fdt, mpic, "#interrupt-cells", 2);
- mpic_ph = qemu_fdt_alloc_phandle(fdt);
- qemu_fdt_setprop_cell(fdt, mpic, "phandle", mpic_ph);
- qemu_fdt_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph);
- qemu_fdt_setprop(fdt, mpic, "interrupt-controller", NULL, 0);
-
- /*
- * We have to generate ser1 first, because Linux takes the first
- * device it finds in the dt as serial output device. And we generate
- * devices in reverse order to the dt.
- */
- if (serial_hds[1]) {
- dt_serial_create(fdt, MPC8544_SERIAL1_REGS_OFFSET,
- soc, mpic, "serial1", 1, false);
- }
-
- if (serial_hds[0]) {
- dt_serial_create(fdt, MPC8544_SERIAL0_REGS_OFFSET,
- soc, mpic, "serial0", 0, true);
- }
-
- snprintf(gutil, sizeof(gutil), "%s/global-utilities@%llx", soc,
- MPC8544_UTIL_OFFSET);
- qemu_fdt_add_subnode(fdt, gutil);
- qemu_fdt_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts");
- qemu_fdt_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_OFFSET, 0x1000);
- qemu_fdt_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0);
-
- snprintf(msi, sizeof(msi), "/%s/msi@%llx", soc, MPC8544_MSI_REGS_OFFSET);
- qemu_fdt_add_subnode(fdt, msi);
- qemu_fdt_setprop_string(fdt, msi, "compatible", "fsl,mpic-msi");
- qemu_fdt_setprop_cells(fdt, msi, "reg", MPC8544_MSI_REGS_OFFSET, 0x200);
- msi_ph = qemu_fdt_alloc_phandle(fdt);
- qemu_fdt_setprop_cells(fdt, msi, "msi-available-ranges", 0x0, 0x100);
- qemu_fdt_setprop_phandle(fdt, msi, "interrupt-parent", mpic);
- qemu_fdt_setprop_cells(fdt, msi, "interrupts",
- 0xe0, 0x0,
- 0xe1, 0x0,
- 0xe2, 0x0,
- 0xe3, 0x0,
- 0xe4, 0x0,
- 0xe5, 0x0,
- 0xe6, 0x0,
- 0xe7, 0x0);
- qemu_fdt_setprop_cell(fdt, msi, "phandle", msi_ph);
- qemu_fdt_setprop_cell(fdt, msi, "linux,phandle", msi_ph);
-
- snprintf(pci, sizeof(pci), "/pci@%llx",
- params->ccsrbar_base + MPC8544_PCI_REGS_OFFSET);
- qemu_fdt_add_subnode(fdt, pci);
- qemu_fdt_setprop_cell(fdt, pci, "cell-index", 0);
- qemu_fdt_setprop_string(fdt, pci, "compatible", "fsl,mpc8540-pci");
- qemu_fdt_setprop_string(fdt, pci, "device_type", "pci");
- qemu_fdt_setprop_cells(fdt, pci, "interrupt-map-mask", 0xf800, 0x0,
- 0x0, 0x7);
- pci_map = pci_map_create(fdt, qemu_fdt_get_phandle(fdt, mpic),
- params->pci_first_slot, params->pci_nr_slots,
- &len);
- qemu_fdt_setprop(fdt, pci, "interrupt-map", pci_map, len);
- qemu_fdt_setprop_phandle(fdt, pci, "interrupt-parent", mpic);
- qemu_fdt_setprop_cells(fdt, pci, "interrupts", 24, 2);
- qemu_fdt_setprop_cells(fdt, pci, "bus-range", 0, 255);
- for (i = 0; i < 14; i++) {
- pci_ranges[i] = cpu_to_be32(pci_ranges[i]);
- }
- qemu_fdt_setprop_cell(fdt, pci, "fsl,msi", msi_ph);
- qemu_fdt_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges));
- qemu_fdt_setprop_cells(fdt, pci, "reg",
- (params->ccsrbar_base + MPC8544_PCI_REGS_OFFSET) >> 32,
- (params->ccsrbar_base + MPC8544_PCI_REGS_OFFSET),
- 0, 0x1000);
- qemu_fdt_setprop_cell(fdt, pci, "clock-frequency", 66666666);
- qemu_fdt_setprop_cell(fdt, pci, "#interrupt-cells", 1);
- qemu_fdt_setprop_cell(fdt, pci, "#size-cells", 2);
- qemu_fdt_setprop_cell(fdt, pci, "#address-cells", 3);
- qemu_fdt_setprop_string(fdt, "/aliases", "pci0", pci);
-
- if (params->has_mpc8xxx_gpio) {
- create_dt_mpc8xxx_gpio(fdt, soc, mpic);
- }
-
- if (params->has_platform_bus) {
- platform_bus_create_devtree(params, fdt, mpic);
- }
-
- params->fixup_devtree(params, fdt);
-
- if (toplevel_compat) {
- qemu_fdt_setprop(fdt, "/", "compatible", toplevel_compat,
- strlen(toplevel_compat) + 1);
- }
-
-done:
- if (!dry_run) {
- qemu_fdt_dumpdtb(fdt, fdt_size);
- cpu_physical_memory_write(addr, fdt, fdt_size);
- }
- ret = fdt_size;
-
-out:
- g_free(pci_map);
-
- return ret;
-}
-
-typedef struct DeviceTreeParams {
- MachineState *machine;
- PPCE500Params params;
- hwaddr addr;
- hwaddr initrd_base;
- hwaddr initrd_size;
- hwaddr kernel_base;
- hwaddr kernel_size;
- Notifier notifier;
-} DeviceTreeParams;
-
-static void ppce500_reset_device_tree(void *opaque)
-{
- DeviceTreeParams *p = opaque;
- ppce500_load_device_tree(p->machine, &p->params, p->addr, p->initrd_base,
- p->initrd_size, p->kernel_base, p->kernel_size,
- false);
-}
-
-static void ppce500_init_notify(Notifier *notifier, void *data)
-{
- DeviceTreeParams *p = container_of(notifier, DeviceTreeParams, notifier);
- ppce500_reset_device_tree(p);
-}
-
-static int ppce500_prep_device_tree(MachineState *machine,
- PPCE500Params *params,
- hwaddr addr,
- hwaddr initrd_base,
- hwaddr initrd_size,
- hwaddr kernel_base,
- hwaddr kernel_size)
-{
- DeviceTreeParams *p = g_new(DeviceTreeParams, 1);
- p->machine = machine;
- p->params = *params;
- p->addr = addr;
- p->initrd_base = initrd_base;
- p->initrd_size = initrd_size;
- p->kernel_base = kernel_base;
- p->kernel_size = kernel_size;
-
- qemu_register_reset(ppce500_reset_device_tree, p);
- p->notifier.notify = ppce500_init_notify;
- qemu_add_machine_init_done_notifier(&p->notifier);
-
- /* Issue the device tree loader once, so that we get the size of the blob */
- return ppce500_load_device_tree(machine, params, addr, initrd_base,
- initrd_size, kernel_base, kernel_size,
- true);
-}
-
-/* Create -kernel TLB entries for BookE. */
-static inline hwaddr booke206_page_size_to_tlb(uint64_t size)
-{
- return 63 - clz64(size >> 10);
-}
-
-static int booke206_initial_map_tsize(CPUPPCState *env)
-{
- struct boot_info *bi = env->load_info;
- hwaddr dt_end;
- int ps;
-
- /* Our initial TLB entry needs to cover everything from 0 to
- the device tree top */
- dt_end = bi->dt_base + bi->dt_size;
- ps = booke206_page_size_to_tlb(dt_end) + 1;
- if (ps & 1) {
- /* e500v2 can only do even TLB size bits */
- ps++;
- }
- return ps;
-}
-
-static uint64_t mmubooke_initial_mapsize(CPUPPCState *env)
-{
- int tsize;
-
- tsize = booke206_initial_map_tsize(env);
- return (1ULL << 10 << tsize);
-}
-
-static void mmubooke_create_initial_mapping(CPUPPCState *env)
-{
- ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0);
- hwaddr size;
- int ps;
-
- ps = booke206_initial_map_tsize(env);
- size = (ps << MAS1_TSIZE_SHIFT);
- tlb->mas1 = MAS1_VALID | size;
- tlb->mas2 = 0;
- tlb->mas7_3 = 0;
- tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
-
- env->tlb_dirty = true;
-}
-
-static void ppce500_cpu_reset_sec(void *opaque)
-{
- PowerPCCPU *cpu = opaque;
- CPUState *cs = CPU(cpu);
-
- cpu_reset(cs);
-
- /* Secondary CPU starts in halted state for now. Needs to change when
- implementing non-kernel boot. */
- cs->halted = 1;
- cs->exception_index = EXCP_HLT;
-}
-
-static void ppce500_cpu_reset(void *opaque)
-{
- PowerPCCPU *cpu = opaque;
- CPUState *cs = CPU(cpu);
- CPUPPCState *env = &cpu->env;
- struct boot_info *bi = env->load_info;
-
- cpu_reset(cs);
-
- /* Set initial guest state. */
- cs->halted = 0;
- env->gpr[1] = (16<<20) - 8;
- env->gpr[3] = bi->dt_base;
- env->gpr[4] = 0;
- env->gpr[5] = 0;
- env->gpr[6] = EPAPR_MAGIC;
- env->gpr[7] = mmubooke_initial_mapsize(env);
- env->gpr[8] = 0;
- env->gpr[9] = 0;
- env->nip = bi->entry;
- mmubooke_create_initial_mapping(env);
-}
-
-static DeviceState *ppce500_init_mpic_qemu(PPCE500Params *params,
- qemu_irq **irqs)
-{
- DeviceState *dev;
- SysBusDevice *s;
- int i, j, k;
-
- dev = qdev_create(NULL, TYPE_OPENPIC);
- qdev_prop_set_uint32(dev, "model", params->mpic_version);
- qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus);
-
- qdev_init_nofail(dev);
- s = SYS_BUS_DEVICE(dev);
-
- k = 0;
- for (i = 0; i < smp_cpus; i++) {
- for (j = 0; j < OPENPIC_OUTPUT_NB; j++) {
- sysbus_connect_irq(s, k++, irqs[i][j]);
- }
- }
-
- return dev;
-}
-
-static DeviceState *ppce500_init_mpic_kvm(PPCE500Params *params,
- qemu_irq **irqs, Error **errp)
-{
- Error *err = NULL;
- DeviceState *dev;
- CPUState *cs;
-
- dev = qdev_create(NULL, TYPE_KVM_OPENPIC);
- qdev_prop_set_uint32(dev, "model", params->mpic_version);
-
- object_property_set_bool(OBJECT(dev), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- object_unparent(OBJECT(dev));
- return NULL;
- }
-
- CPU_FOREACH(cs) {
- if (kvm_openpic_connect_vcpu(dev, cs)) {
- fprintf(stderr, "%s: failed to connect vcpu to irqchip\n",
- __func__);
- abort();
- }
- }
-
- return dev;
-}
-
-static qemu_irq *ppce500_init_mpic(MachineState *machine, PPCE500Params *params,
- MemoryRegion *ccsr, qemu_irq **irqs)
-{
- qemu_irq *mpic;
- DeviceState *dev = NULL;
- SysBusDevice *s;
- int i;
-
- mpic = g_new0(qemu_irq, 256);
-
- if (kvm_enabled()) {
- Error *err = NULL;
-
- if (machine_kernel_irqchip_allowed(machine)) {
- dev = ppce500_init_mpic_kvm(params, irqs, &err);
- }
- if (machine_kernel_irqchip_required(machine) && !dev) {
- error_reportf_err(err,
- "kernel_irqchip requested but unavailable: ");
- exit(1);
- }
- }
-
- if (!dev) {
- dev = ppce500_init_mpic_qemu(params, irqs);
- }
-
- for (i = 0; i < 256; i++) {
- mpic[i] = qdev_get_gpio_in(dev, i);
- }
-
- s = SYS_BUS_DEVICE(dev);
- memory_region_add_subregion(ccsr, MPC8544_MPIC_REGS_OFFSET,
- s->mmio[0].memory);
-
- return mpic;
-}
-
-static void ppce500_power_off(void *opaque, int line, int on)
-{
- if (on) {
- qemu_system_shutdown_request();
- }
-}
-
-void ppce500_init(MachineState *machine, PPCE500Params *params)
-{
- MemoryRegion *address_space_mem = get_system_memory();
- MemoryRegion *ram = g_new(MemoryRegion, 1);
- PCIBus *pci_bus;
- CPUPPCState *env = NULL;
- uint64_t loadaddr;
- hwaddr kernel_base = -1LL;
- int kernel_size = 0;
- hwaddr dt_base = 0;
- hwaddr initrd_base = 0;
- int initrd_size = 0;
- hwaddr cur_base = 0;
- char *filename;
- hwaddr bios_entry = 0;
- target_long bios_size;
- struct boot_info *boot_info;
- int dt_size;
- int i;
- /* irq num for pin INTA, INTB, INTC and INTD is 1, 2, 3 and
- * 4 respectively */
- unsigned int pci_irq_nrs[PCI_NUM_PINS] = {1, 2, 3, 4};
- qemu_irq **irqs, *mpic;
- DeviceState *dev;
- CPUPPCState *firstenv = NULL;
- MemoryRegion *ccsr_addr_space;
- SysBusDevice *s;
- PPCE500CCSRState *ccsr;
-
- /* Setup CPUs */
- if (machine->cpu_model == NULL) {
- machine->cpu_model = "e500v2_v30";
- }
-
- irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
- irqs[0] = g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
- for (i = 0; i < smp_cpus; i++) {
- PowerPCCPU *cpu;
- CPUState *cs;
- qemu_irq *input;
-
- cpu = cpu_ppc_init(machine->cpu_model);
- if (cpu == NULL) {
- fprintf(stderr, "Unable to initialize CPU!\n");
- exit(1);
- }
- env = &cpu->env;
- cs = CPU(cpu);
-
- if (!firstenv) {
- firstenv = env;
- }
-
- irqs[i] = irqs[0] + (i * OPENPIC_OUTPUT_NB);
- input = (qemu_irq *)env->irq_inputs;
- irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT];
- irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
- env->spr_cb[SPR_BOOKE_PIR].default_value = cs->cpu_index = i;
- env->mpic_iack = params->ccsrbar_base +
- MPC8544_MPIC_REGS_OFFSET + 0xa0;
-
- ppc_booke_timers_init(cpu, 400000000, PPC_TIMER_E500);
-
- /* Register reset handler */
- if (!i) {
- /* Primary CPU */
- struct boot_info *boot_info;
- boot_info = g_malloc0(sizeof(struct boot_info));
- qemu_register_reset(ppce500_cpu_reset, cpu);
- env->load_info = boot_info;
- } else {
- /* Secondary CPUs */
- qemu_register_reset(ppce500_cpu_reset_sec, cpu);
- }
- }
-
- env = firstenv;
-
- /* Fixup Memory size on a alignment boundary */
- ram_size &= ~(RAM_SIZES_ALIGN - 1);
- machine->ram_size = ram_size;
-
- /* Register Memory */
- memory_region_allocate_system_memory(ram, NULL, "mpc8544ds.ram", ram_size);
- memory_region_add_subregion(address_space_mem, 0, ram);
-
- dev = qdev_create(NULL, "e500-ccsr");
- object_property_add_child(qdev_get_machine(), "e500-ccsr",
- OBJECT(dev), NULL);
- qdev_init_nofail(dev);
- ccsr = CCSR(dev);
- ccsr_addr_space = &ccsr->ccsr_space;
- memory_region_add_subregion(address_space_mem, params->ccsrbar_base,
- ccsr_addr_space);
-
- mpic = ppce500_init_mpic(machine, params, ccsr_addr_space, irqs);
-
- /* Serial */
- if (serial_hds[0]) {
- serial_mm_init(ccsr_addr_space, MPC8544_SERIAL0_REGS_OFFSET,
- 0, mpic[42], 399193,
- serial_hds[0], DEVICE_BIG_ENDIAN);
- }
-
- if (serial_hds[1]) {
- serial_mm_init(ccsr_addr_space, MPC8544_SERIAL1_REGS_OFFSET,
- 0, mpic[42], 399193,
- serial_hds[1], DEVICE_BIG_ENDIAN);
- }
-
- /* General Utility device */
- dev = qdev_create(NULL, "mpc8544-guts");
- qdev_init_nofail(dev);
- s = SYS_BUS_DEVICE(dev);
- memory_region_add_subregion(ccsr_addr_space, MPC8544_UTIL_OFFSET,
- sysbus_mmio_get_region(s, 0));
-
- /* PCI */
- dev = qdev_create(NULL, "e500-pcihost");
- qdev_prop_set_uint32(dev, "first_slot", params->pci_first_slot);
- qdev_prop_set_uint32(dev, "first_pin_irq", pci_irq_nrs[0]);
- qdev_init_nofail(dev);
- s = SYS_BUS_DEVICE(dev);
- for (i = 0; i < PCI_NUM_PINS; i++) {
- sysbus_connect_irq(s, i, mpic[pci_irq_nrs[i]]);
- }
-
- memory_region_add_subregion(ccsr_addr_space, MPC8544_PCI_REGS_OFFSET,
- sysbus_mmio_get_region(s, 0));
-
- pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
- if (!pci_bus)
- printf("couldn't create PCI controller!\n");
-
- if (pci_bus) {
- /* Register network interfaces. */
- for (i = 0; i < nb_nics; i++) {
- pci_nic_init_nofail(&nd_table[i], pci_bus, "virtio", NULL);
- }
- }
-
- /* Register spinning region */
- sysbus_create_simple("e500-spin", params->spin_base, NULL);
-
- if (cur_base < (32 * 1024 * 1024)) {
- /* u-boot occupies memory up to 32MB, so load blobs above */
- cur_base = (32 * 1024 * 1024);
- }
-
- if (params->has_mpc8xxx_gpio) {
- qemu_irq poweroff_irq;
-
- dev = qdev_create(NULL, "mpc8xxx_gpio");
- s = SYS_BUS_DEVICE(dev);
- qdev_init_nofail(dev);
- sysbus_connect_irq(s, 0, mpic[MPC8XXX_GPIO_IRQ]);
- memory_region_add_subregion(ccsr_addr_space, MPC8XXX_GPIO_OFFSET,
- sysbus_mmio_get_region(s, 0));
-
- /* Power Off GPIO at Pin 0 */
- poweroff_irq = qemu_allocate_irq(ppce500_power_off, NULL, 0);
- qdev_connect_gpio_out(dev, 0, poweroff_irq);
- }
-
- /* Platform Bus Device */
- if (params->has_platform_bus) {
- dev = qdev_create(NULL, TYPE_PLATFORM_BUS_DEVICE);
- dev->id = TYPE_PLATFORM_BUS_DEVICE;
- qdev_prop_set_uint32(dev, "num_irqs", params->platform_bus_num_irqs);
- qdev_prop_set_uint32(dev, "mmio_size", params->platform_bus_size);
- qdev_init_nofail(dev);
- s = SYS_BUS_DEVICE(dev);
-
- for (i = 0; i < params->platform_bus_num_irqs; i++) {
- int irqn = params->platform_bus_first_irq + i;
- sysbus_connect_irq(s, i, mpic[irqn]);
- }
-
- memory_region_add_subregion(address_space_mem,
- params->platform_bus_base,
- sysbus_mmio_get_region(s, 0));
- }
-
- /* Load kernel. */
- if (machine->kernel_filename) {
- kernel_base = cur_base;
- kernel_size = load_image_targphys(machine->kernel_filename,
- cur_base,
- ram_size - cur_base);
- if (kernel_size < 0) {
- fprintf(stderr, "qemu: could not load kernel '%s'\n",
- machine->kernel_filename);
- exit(1);
- }
-
- cur_base += kernel_size;
- }
-
- /* Load initrd. */
- if (machine->initrd_filename) {
- initrd_base = (cur_base + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
- initrd_size = load_image_targphys(machine->initrd_filename, initrd_base,
- ram_size - initrd_base);
-
- if (initrd_size < 0) {
- fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
- machine->initrd_filename);
- exit(1);
- }
-
- cur_base = initrd_base + initrd_size;
- }
-
- /*
- * Smart firmware defaults ahead!
- *
- * We follow the following table to select which payload we execute.
- *
- * -kernel | -bios | payload
- * ---------+-------+---------
- * N | Y | u-boot
- * N | N | u-boot
- * Y | Y | u-boot
- * Y | N | kernel
- *
- * This ensures backwards compatibility with how we used to expose
- * -kernel to users but allows them to run through u-boot as well.
- */
- if (bios_name == NULL) {
- if (machine->kernel_filename) {
- bios_name = machine->kernel_filename;
- } else {
- bios_name = "u-boot.e500";
- }
- }
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
-
- bios_size = load_elf(filename, NULL, NULL, &bios_entry, &loadaddr, NULL,
- 1, PPC_ELF_MACHINE, 0, 0);
- if (bios_size < 0) {
- /*
- * Hrm. No ELF image? Try a uImage, maybe someone is giving us an
- * ePAPR compliant kernel
- */
- kernel_size = load_uimage(filename, &bios_entry, &loadaddr, NULL,
- NULL, NULL);
- if (kernel_size < 0) {
- fprintf(stderr, "qemu: could not load firmware '%s'\n", filename);
- exit(1);
- }
- }
- g_free(filename);
-
- /* Reserve space for dtb */
- dt_base = (loadaddr + bios_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
-
- dt_size = ppce500_prep_device_tree(machine, params, dt_base,
- initrd_base, initrd_size,
- kernel_base, kernel_size);
- if (dt_size < 0) {
- fprintf(stderr, "couldn't load device tree\n");
- exit(1);
- }
- assert(dt_size < DTB_MAX_SIZE);
-
- boot_info = env->load_info;
- boot_info->entry = bios_entry;
- boot_info->dt_base = dt_base;
- boot_info->dt_size = dt_size;
-}
-
-static int e500_ccsr_initfn(SysBusDevice *dev)
-{
- PPCE500CCSRState *ccsr;
-
- ccsr = CCSR(dev);
- memory_region_init(&ccsr->ccsr_space, OBJECT(ccsr), "e500-ccsr",
- MPC8544_CCSRBAR_SIZE);
- return 0;
-}
-
-static void e500_ccsr_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- k->init = e500_ccsr_initfn;
-}
-
-static const TypeInfo e500_ccsr_info = {
- .name = TYPE_CCSR,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PPCE500CCSRState),
- .class_init = e500_ccsr_class_init,
-};
-
-static void e500_register_types(void)
-{
- type_register_static(&e500_ccsr_info);
-}
-
-type_init(e500_register_types)
diff --git a/qemu/hw/ppc/e500.h b/qemu/hw/ppc/e500.h
deleted file mode 100644
index ef224ea5e..000000000
--- a/qemu/hw/ppc/e500.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef PPCE500_H
-#define PPCE500_H
-
-#include "hw/boards.h"
-
-typedef struct PPCE500Params {
- int pci_first_slot;
- int pci_nr_slots;
-
- /* required -- must at least add toplevel board compatible */
- void (*fixup_devtree)(struct PPCE500Params *params, void *fdt);
-
- int mpic_version;
- bool has_mpc8xxx_gpio;
- bool has_platform_bus;
- hwaddr platform_bus_base;
- hwaddr platform_bus_size;
- int platform_bus_first_irq;
- int platform_bus_num_irqs;
- hwaddr ccsrbar_base;
- hwaddr pci_pio_base;
- hwaddr pci_mmio_base;
- hwaddr pci_mmio_bus_base;
- hwaddr spin_base;
-} PPCE500Params;
-
-void ppce500_init(MachineState *machine, PPCE500Params *params);
-
-#endif
diff --git a/qemu/hw/ppc/e500plat.c b/qemu/hw/ppc/e500plat.c
deleted file mode 100644
index b00565c3d..000000000
--- a/qemu/hw/ppc/e500plat.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Generic device-tree-driven paravirt PPC e500 platform
- *
- * Copyright 2012 Freescale Semiconductor, Inc.
- *
- * This is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "e500.h"
-#include "hw/boards.h"
-#include "sysemu/device_tree.h"
-#include "hw/pci/pci.h"
-#include "hw/ppc/openpic.h"
-#include "kvm_ppc.h"
-
-static void e500plat_fixup_devtree(PPCE500Params *params, void *fdt)
-{
- const char model[] = "QEMU ppce500";
- const char compatible[] = "fsl,qemu-e500";
-
- qemu_fdt_setprop(fdt, "/", "model", model, sizeof(model));
- qemu_fdt_setprop(fdt, "/", "compatible", compatible,
- sizeof(compatible));
-}
-
-static void e500plat_init(MachineState *machine)
-{
- PPCE500Params params = {
- .pci_first_slot = 0x1,
- .pci_nr_slots = PCI_SLOT_MAX - 1,
- .fixup_devtree = e500plat_fixup_devtree,
- .mpic_version = OPENPIC_MODEL_FSL_MPIC_42,
- .has_mpc8xxx_gpio = true,
- .has_platform_bus = true,
- .platform_bus_base = 0xf00000000ULL,
- .platform_bus_size = (128ULL * 1024 * 1024),
- .platform_bus_first_irq = 5,
- .platform_bus_num_irqs = 10,
- .ccsrbar_base = 0xFE0000000ULL,
- .pci_pio_base = 0xFE1000000ULL,
- .pci_mmio_base = 0xC00000000ULL,
- .pci_mmio_bus_base = 0xE0000000ULL,
- .spin_base = 0xFEF000000ULL,
- };
-
- /* Older KVM versions don't support EPR which breaks guests when we announce
- MPIC variants that support EPR. Revert to an older one for those */
- if (kvm_enabled() && !kvmppc_has_cap_epr()) {
- params.mpic_version = OPENPIC_MODEL_FSL_MPIC_20;
- }
-
- ppce500_init(machine, &params);
-}
-
-static void e500plat_machine_init(MachineClass *mc)
-{
- mc->desc = "generic paravirt e500 platform";
- mc->init = e500plat_init;
- mc->max_cpus = 32;
- mc->has_dynamic_sysbus = true;
-}
-
-DEFINE_MACHINE("ppce500", e500plat_machine_init)
diff --git a/qemu/hw/ppc/mac.h b/qemu/hw/ppc/mac.h
deleted file mode 100644
index 5764b86c2..000000000
--- a/qemu/hw/ppc/mac.h
+++ /dev/null
@@ -1,187 +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"
-#include "hw/sysbus.h"
-#include "hw/ide/internal.h"
-#include "hw/input/adb.h"
-
-/* SMP is not enabled, for now */
-#define MAX_CPUS 1
-
-#define BIOS_SIZE (1024 * 1024)
-#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;
- uint64_t frequency;
- 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;
- uint64_t frequency;
-
- uint8_t last_b;
- uint8_t last_acr;
-
- /* MacOS 9 is racy and requires a delay upon setting the SR_INT bit */
- QEMUTimer *sr_delay_timer;
-
- int data_in_size;
- int data_in_index;
- int data_out_index;
-
- qemu_irq irq;
- uint16_t adb_poll_mask;
- uint8_t autopoll_rate_ms;
- 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;
- IDEDMA dma;
- void *dbdma;
- bool dma_active;
-} 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);
-#endif /* !defined(__PPC_MAC_H__) */
diff --git a/qemu/hw/ppc/mac_newworld.c b/qemu/hw/ppc/mac_newworld.c
deleted file mode 100644
index 32e88b378..000000000
--- a/qemu/hw/ppc/mac_newworld.c
+++ /dev/null
@@ -1,535 +0,0 @@
-/*
- * QEMU PowerPC CHRP (currently NewWorld PowerMac) hardware System Emulator
- *
- * 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.
- *
- * PCI bus layout on a real G5 (U3 based):
- *
- * 0000:f0:0b.0 Host bridge [0600]: Apple Computer Inc. U3 AGP [106b:004b]
- * 0000:f0:10.0 VGA compatible controller [0300]: ATI Technologies Inc RV350 AP [Radeon 9600] [1002:4150]
- * 0001:00:00.0 Host bridge [0600]: Apple Computer Inc. CPC945 HT Bridge [106b:004a]
- * 0001:00:01.0 PCI bridge [0604]: Advanced Micro Devices [AMD] AMD-8131 PCI-X Bridge [1022:7450] (rev 12)
- * 0001:00:02.0 PCI bridge [0604]: Advanced Micro Devices [AMD] AMD-8131 PCI-X Bridge [1022:7450] (rev 12)
- * 0001:00:03.0 PCI bridge [0604]: Apple Computer Inc. K2 HT-PCI Bridge [106b:0045]
- * 0001:00:04.0 PCI bridge [0604]: Apple Computer Inc. K2 HT-PCI Bridge [106b:0046]
- * 0001:00:05.0 PCI bridge [0604]: Apple Computer Inc. K2 HT-PCI Bridge [106b:0047]
- * 0001:00:06.0 PCI bridge [0604]: Apple Computer Inc. K2 HT-PCI Bridge [106b:0048]
- * 0001:00:07.0 PCI bridge [0604]: Apple Computer Inc. K2 HT-PCI Bridge [106b:0049]
- * 0001:01:07.0 Class [ff00]: Apple Computer Inc. K2 KeyLargo Mac/IO [106b:0041] (rev 20)
- * 0001:01:08.0 USB Controller [0c03]: Apple Computer Inc. K2 KeyLargo USB [106b:0040]
- * 0001:01:09.0 USB Controller [0c03]: Apple Computer Inc. K2 KeyLargo USB [106b:0040]
- * 0001:02:0b.0 USB Controller [0c03]: NEC Corporation USB [1033:0035] (rev 43)
- * 0001:02:0b.1 USB Controller [0c03]: NEC Corporation USB [1033:0035] (rev 43)
- * 0001:02:0b.2 USB Controller [0c03]: NEC Corporation USB 2.0 [1033:00e0] (rev 04)
- * 0001:03:0d.0 Class [ff00]: Apple Computer Inc. K2 ATA/100 [106b:0043]
- * 0001:03:0e.0 FireWire (IEEE 1394) [0c00]: Apple Computer Inc. K2 FireWire [106b:0042]
- * 0001:04:0f.0 Ethernet controller [0200]: Apple Computer Inc. K2 GMAC (Sun GEM) [106b:004c]
- * 0001:05:0c.0 IDE interface [0101]: Broadcom K2 SATA [1166:0240]
- *
- */
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/hw.h"
-#include "hw/ppc/ppc.h"
-#include "hw/ppc/mac.h"
-#include "hw/input/adb.h"
-#include "hw/ppc/mac_dbdma.h"
-#include "hw/timer/m48t59.h"
-#include "hw/pci/pci.h"
-#include "net/net.h"
-#include "sysemu/sysemu.h"
-#include "hw/boards.h"
-#include "hw/nvram/fw_cfg.h"
-#include "hw/char/escc.h"
-#include "hw/ppc/openpic.h"
-#include "hw/ide.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "qemu/error-report.h"
-#include "sysemu/kvm.h"
-#include "kvm_ppc.h"
-#include "hw/usb.h"
-#include "sysemu/block-backend.h"
-#include "exec/address-spaces.h"
-#include "hw/sysbus.h"
-#include "qemu/cutils.h"
-
-#define MAX_IDE_BUS 2
-#define CFG_ADDR 0xf0000510
-#define TBFREQ (100UL * 1000UL * 1000UL)
-#define CLOCKFREQ (266UL * 1000UL * 1000UL)
-#define BUSFREQ (100UL * 1000UL * 1000UL)
-
-/* debug UniNorth */
-//#define DEBUG_UNIN
-
-#ifdef DEBUG_UNIN
-#define UNIN_DPRINTF(fmt, ...) \
- do { printf("UNIN: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define UNIN_DPRINTF(fmt, ...)
-#endif
-
-/* UniN device */
-static void unin_write(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
- UNIN_DPRINTF("write addr " TARGET_FMT_plx " val %"PRIx64"\n", addr, value);
- if (addr == 0x0) {
- *(int*)opaque = value;
- }
-}
-
-static uint64_t unin_read(void *opaque, hwaddr addr, unsigned size)
-{
- uint32_t value;
-
- value = 0;
- switch (addr) {
- case 0:
- value = *(int*)opaque;
- }
-
- UNIN_DPRINTF("readl addr " TARGET_FMT_plx " val %x\n", addr, value);
-
- return value;
-}
-
-static const MemoryRegionOps unin_ops = {
- .read = unin_read,
- .write = unin_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void fw_cfg_boot_set(void *opaque, const char *boot_device,
- Error **errp)
-{
- fw_cfg_modify_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
-}
-
-static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
-{
- return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR;
-}
-
-static hwaddr round_page(hwaddr addr)
-{
- return (addr + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
-}
-
-static void ppc_core99_reset(void *opaque)
-{
- PowerPCCPU *cpu = opaque;
-
- cpu_reset(CPU(cpu));
- /* 970 CPUs want to get their initial IP as part of their boot protocol */
- cpu->env.nip = PROM_ADDR + 0x100;
-}
-
-/* PowerPC Mac99 hardware initialisation */
-static void ppc_core99_init(MachineState *machine)
-{
- ram_addr_t ram_size = machine->ram_size;
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- const char *initrd_filename = machine->initrd_filename;
- const char *boot_device = machine->boot_order;
- PowerPCCPU *cpu = NULL;
- CPUPPCState *env = NULL;
- char *filename;
- qemu_irq *pic, **openpic_irqs;
- MemoryRegion *isa = g_new(MemoryRegion, 1);
- MemoryRegion *unin_memory = g_new(MemoryRegion, 1);
- MemoryRegion *unin2_memory = g_new(MemoryRegion, 1);
- int linux_boot, i, j, k;
- MemoryRegion *ram = g_new(MemoryRegion, 1), *bios = g_new(MemoryRegion, 1);
- 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, *escc_mem;
- MemoryRegion *escc_bar = g_new(MemoryRegion, 1);
- int ppc_boot_device;
- DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
- void *fw_cfg;
- int machine_arch;
- SysBusDevice *s;
- DeviceState *dev;
- int *token = g_new(int, 1);
- hwaddr nvram_addr = 0xFFF04000;
- uint64_t tbfreq;
-
- linux_boot = (kernel_filename != NULL);
-
- /* init CPUs */
- if (machine->cpu_model == NULL) {
-#ifdef TARGET_PPC64
- machine->cpu_model = "970fx";
-#else
- machine->cpu_model = "G4";
-#endif
- }
- for (i = 0; i < smp_cpus; i++) {
- cpu = cpu_ppc_init(machine->cpu_model);
- if (cpu == NULL) {
- fprintf(stderr, "Unable to find PowerPC CPU definition\n");
- exit(1);
- }
- env = &cpu->env;
-
- /* Set time-base frequency to 100 Mhz */
- cpu_ppc_tb_init(env, TBFREQ);
- qemu_register_reset(ppc_core99_reset, cpu);
- }
-
- /* allocate RAM */
- memory_region_allocate_system_memory(ram, NULL, "ppc_core99.ram", ram_size);
- memory_region_add_subregion(get_system_memory(), 0, ram);
-
- /* allocate and load BIOS */
- memory_region_init_ram(bios, NULL, "ppc_core99.bios", BIOS_SIZE,
- &error_fatal);
- vmstate_register_ram_global(bios);
-
- if (bios_name == NULL)
- bios_name = PROM_FILENAME;
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
- memory_region_set_readonly(bios, true);
- memory_region_add_subregion(get_system_memory(), PROM_ADDR, bios);
-
- /* Load OpenBIOS (ELF) */
- if (filename) {
- bios_size = load_elf(filename, NULL, NULL, NULL,
- NULL, NULL, 1, PPC_ELF_MACHINE, 0, 0);
-
- g_free(filename);
- } else {
- bios_size = -1;
- }
- if (bios_size < 0 || bios_size > BIOS_SIZE) {
- error_report("could not load PowerPC bios '%s'", bios_name);
- exit(1);
- }
-
- if (linux_boot) {
- uint64_t lowaddr = 0;
- int bswap_needed;
-
-#ifdef BSWAP_NEEDED
- bswap_needed = 1;
-#else
- bswap_needed = 0;
-#endif
- kernel_base = KERNEL_LOAD_ADDR;
-
- kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL,
- NULL, &lowaddr, NULL, 1, PPC_ELF_MACHINE,
- 0, 0);
- if (kernel_size < 0)
- kernel_size = load_aout(kernel_filename, kernel_base,
- ram_size - kernel_base, bswap_needed,
- TARGET_PAGE_SIZE);
- if (kernel_size < 0)
- kernel_size = load_image_targphys(kernel_filename,
- kernel_base,
- ram_size - kernel_base);
- if (kernel_size < 0) {
- error_report("could not load kernel '%s'", kernel_filename);
- exit(1);
- }
- /* load initrd */
- if (initrd_filename) {
- initrd_base = round_page(kernel_base + kernel_size + KERNEL_GAP);
- initrd_size = load_image_targphys(initrd_filename, initrd_base,
- ram_size - initrd_base);
- if (initrd_size < 0) {
- error_report("could not load initial ram disk '%s'",
- initrd_filename);
- exit(1);
- }
- cmdline_base = round_page(initrd_base + initrd_size);
- } else {
- initrd_base = 0;
- initrd_size = 0;
- cmdline_base = round_page(kernel_base + kernel_size + KERNEL_GAP);
- }
- ppc_boot_device = 'm';
- } else {
- kernel_base = 0;
- kernel_size = 0;
- initrd_base = 0;
- initrd_size = 0;
- ppc_boot_device = '\0';
- /* We consider that NewWorld PowerMac never have any floppy drive
- * For now, OHW cannot boot from the network.
- */
- for (i = 0; boot_device[i] != '\0'; i++) {
- if (boot_device[i] >= 'c' && boot_device[i] <= 'f') {
- ppc_boot_device = boot_device[i];
- break;
- }
- }
- if (ppc_boot_device == '\0') {
- fprintf(stderr, "No valid boot device for Mac99 machine\n");
- exit(1);
- }
- }
-
- /* Register 8 MB of ISA IO space */
- memory_region_init_alias(isa, NULL, "isa_mmio",
- get_system_io(), 0, 0x00800000);
- memory_region_add_subregion(get_system_memory(), 0xf2000000, isa);
-
- /* UniN init: XXX should be a real device */
- memory_region_init_io(unin_memory, NULL, &unin_ops, token, "unin", 0x1000);
- memory_region_add_subregion(get_system_memory(), 0xf8000000, unin_memory);
-
- memory_region_init_io(unin2_memory, NULL, &unin_ops, token, "unin", 0x1000);
- memory_region_add_subregion(get_system_memory(), 0xf3000000, unin2_memory);
-
- openpic_irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
- openpic_irqs[0] =
- g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
- for (i = 0; i < smp_cpus; i++) {
- /* Mac99 IRQ connection between OpenPIC outputs pins
- * and PowerPC input pins
- */
- switch (PPC_INPUT(env)) {
- case PPC_FLAGS_INPUT_6xx:
- openpic_irqs[i] = openpic_irqs[0] + (i * OPENPIC_OUTPUT_NB);
- openpic_irqs[i][OPENPIC_OUTPUT_INT] =
- ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT];
- openpic_irqs[i][OPENPIC_OUTPUT_CINT] =
- ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT];
- openpic_irqs[i][OPENPIC_OUTPUT_MCK] =
- ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_MCP];
- /* Not connected ? */
- openpic_irqs[i][OPENPIC_OUTPUT_DEBUG] = NULL;
- /* Check this */
- openpic_irqs[i][OPENPIC_OUTPUT_RESET] =
- ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_HRESET];
- break;
-#if defined(TARGET_PPC64)
- case PPC_FLAGS_INPUT_970:
- openpic_irqs[i] = openpic_irqs[0] + (i * OPENPIC_OUTPUT_NB);
- openpic_irqs[i][OPENPIC_OUTPUT_INT] =
- ((qemu_irq *)env->irq_inputs)[PPC970_INPUT_INT];
- openpic_irqs[i][OPENPIC_OUTPUT_CINT] =
- ((qemu_irq *)env->irq_inputs)[PPC970_INPUT_INT];
- openpic_irqs[i][OPENPIC_OUTPUT_MCK] =
- ((qemu_irq *)env->irq_inputs)[PPC970_INPUT_MCP];
- /* Not connected ? */
- openpic_irqs[i][OPENPIC_OUTPUT_DEBUG] = NULL;
- /* Check this */
- openpic_irqs[i][OPENPIC_OUTPUT_RESET] =
- ((qemu_irq *)env->irq_inputs)[PPC970_INPUT_HRESET];
- break;
-#endif /* defined(TARGET_PPC64) */
- default:
- error_report("Bus model not supported on mac99 machine");
- exit(1);
- }
- }
-
- pic = g_new0(qemu_irq, 64);
-
- dev = qdev_create(NULL, TYPE_OPENPIC);
- qdev_prop_set_uint32(dev, "model", OPENPIC_MODEL_RAVEN);
- qdev_init_nofail(dev);
- s = SYS_BUS_DEVICE(dev);
- pic_mem = s->mmio[0].memory;
- k = 0;
- for (i = 0; i < smp_cpus; i++) {
- for (j = 0; j < OPENPIC_OUTPUT_NB; j++) {
- sysbus_connect_irq(s, k++, openpic_irqs[i][j]);
- }
- }
-
- for (i = 0; i < 64; i++) {
- pic[i] = qdev_get_gpio_in(dev, i);
- }
-
- if (PPC_INPUT(env) == PPC_FLAGS_INPUT_970) {
- /* 970 gets a U3 bus */
- pci_bus = pci_pmac_u3_init(pic, get_system_memory(), get_system_io());
- machine_arch = ARCH_MAC99_U3;
- } else {
- pci_bus = pci_pmac_init(pic, get_system_memory(), get_system_io());
- machine_arch = ARCH_MAC99;
- }
-
- machine->usb |= defaults_enabled() && !machine->usb_disabled;
-
- /* Timebase Frequency */
- if (kvm_enabled()) {
- tbfreq = kvmppc_get_tbfreq();
- } else {
- tbfreq = TBFREQ;
- }
-
- /* init basic PC hardware */
- escc_mem = escc_init(0, pic[0x25], pic[0x24],
- serial_hds[0], serial_hds[1], ESCC_CLOCK, 4);
- memory_region_init_alias(escc_bar, NULL, "escc-bar",
- escc_mem, 0, memory_region_size(escc_mem));
-
- 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[0x03]); /* IDE DMA */
- qdev_prop_set_uint64(dev, "frequency", tbfreq);
- macio_init(macio, pic_mem, escc_bar);
-
- /* We only emulate 2 out of 3 IDE controllers for now */
- ide_drive_get(hd, ARRAY_SIZE(hd));
-
- macio_ide = MACIO_IDE(object_resolve_path_component(OBJECT(macio),
- "ide[0]"));
- macio_ide_init_drives(macio_ide, hd);
-
- macio_ide = MACIO_IDE(object_resolve_path_component(OBJECT(macio),
- "ide[1]"));
- macio_ide_init_drives(macio_ide, &hd[MAX_IDE_DEVS]);
-
- 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 (machine->usb) {
- pci_create_simple(pci_bus, -1, "pci-ohci");
-
- /* U3 needs to use USB for input because Linux doesn't support via-cuda
- on PPC64 */
- if (machine_arch == ARCH_MAC99_U3) {
- USBBus *usb_bus = usb_bus_find(-1);
-
- usb_create_simple(usb_bus, "usb-kbd");
- usb_create_simple(usb_bus, "usb-mouse");
- }
- }
-
- pci_vga_init(pci_bus);
-
- if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8) {
- graphic_depth = 15;
- }
-
- for (i = 0; i < nb_nics; i++) {
- pci_nic_init_nofail(&nd_table[i], pci_bus, "ne2k_pci", NULL);
- }
-
- /* The NewWorld NVRAM is not located in the MacIO device */
-#ifdef CONFIG_KVM
- if (kvm_enabled() && getpagesize() > 4096) {
- /* We can't combine read-write and read-only in a single page, so
- move the NVRAM out of ROM again for KVM */
- nvram_addr = 0xFFE00000;
- }
-#endif
- 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, nvram_addr);
- nvr = MACIO_NVRAM(dev);
- pmac_format_nvram_partition(nvr, 0x2000);
- /* No PCI init: the BIOS will do it */
-
- fw_cfg = fw_cfg_init_mem(CFG_ADDR, CFG_ADDR + 2);
- fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
- 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);
- fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_base);
- fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
- if (kernel_cmdline) {
- fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, cmdline_base);
- pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE, kernel_cmdline);
- } else {
- fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0);
- }
- fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, initrd_base);
- fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size);
- fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, ppc_boot_device);
-
- fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_WIDTH, graphic_width);
- fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_HEIGHT, graphic_height);
- fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_DEPTH, graphic_depth);
-
- fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_IS_KVM, kvm_enabled());
- if (kvm_enabled()) {
-#ifdef CONFIG_KVM
- uint8_t *hypercall;
-
- hypercall = g_malloc(16);
- kvmppc_get_hypercall(env, hypercall, 16);
- fw_cfg_add_bytes(fw_cfg, FW_CFG_PPC_KVM_HC, hypercall, 16);
- fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_KVM_PID, getpid());
-#endif
- }
- fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, tbfreq);
- /* Mac OS X requires a "known good" clock-frequency value; pass it one. */
- fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_CLOCKFREQ, CLOCKFREQ);
- fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_BUSFREQ, BUSFREQ);
- fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_NVRAM_ADDR, nvram_addr);
-
- qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
-}
-
-static int core99_kvm_type(const char *arg)
-{
- /* Always force PR KVM */
- return 2;
-}
-
-static void core99_machine_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "Mac99 based PowerMAC";
- mc->init = ppc_core99_init;
- mc->max_cpus = MAX_CPUS;
- mc->default_boot_order = "cd";
- mc->kvm_type = core99_kvm_type;
-}
-
-static const TypeInfo core99_machine_info = {
- .name = MACHINE_TYPE_NAME("mac99"),
- .parent = TYPE_MACHINE,
- .class_init = core99_machine_class_init,
-};
-
-static void mac_machine_register_types(void)
-{
- type_register_static(&core99_machine_info);
-}
-
-type_init(mac_machine_register_types)
diff --git a/qemu/hw/ppc/mac_oldworld.c b/qemu/hw/ppc/mac_oldworld.c
deleted file mode 100644
index a9bb1c27d..000000000
--- a/qemu/hw/ppc/mac_oldworld.c
+++ /dev/null
@@ -1,379 +0,0 @@
-
-/*
- * QEMU OldWorld PowerMac (currently ~G3 Beige) hardware System Emulator
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/hw.h"
-#include "hw/ppc/ppc.h"
-#include "mac.h"
-#include "hw/input/adb.h"
-#include "hw/timer/m48t59.h"
-#include "sysemu/sysemu.h"
-#include "net/net.h"
-#include "hw/isa/isa.h"
-#include "hw/pci/pci.h"
-#include "hw/boards.h"
-#include "hw/nvram/fw_cfg.h"
-#include "hw/char/escc.h"
-#include "hw/ide.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "qemu/error-report.h"
-#include "sysemu/kvm.h"
-#include "kvm_ppc.h"
-#include "sysemu/block-backend.h"
-#include "exec/address-spaces.h"
-#include "qemu/cutils.h"
-
-#define MAX_IDE_BUS 2
-#define CFG_ADDR 0xf0000510
-#define TBFREQ 16600000UL
-#define CLOCKFREQ 266000000UL
-#define BUSFREQ 66000000UL
-
-static void fw_cfg_boot_set(void *opaque, const char *boot_device,
- Error **errp)
-{
- fw_cfg_modify_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
-}
-
-static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
-{
- return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR;
-}
-
-static hwaddr round_page(hwaddr addr)
-{
- return (addr + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
-}
-
-static void ppc_heathrow_reset(void *opaque)
-{
- PowerPCCPU *cpu = opaque;
-
- cpu_reset(CPU(cpu));
-}
-
-static void ppc_heathrow_init(MachineState *machine)
-{
- ram_addr_t ram_size = machine->ram_size;
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- const char *initrd_filename = machine->initrd_filename;
- const char *boot_device = machine->boot_order;
- MemoryRegion *sysmem = get_system_memory();
- PowerPCCPU *cpu = NULL;
- CPUPPCState *env = NULL;
- char *filename;
- qemu_irq *pic, **heathrow_irqs;
- int linux_boot, i;
- MemoryRegion *ram = g_new(MemoryRegion, 1);
- MemoryRegion *bios = g_new(MemoryRegion, 1);
- MemoryRegion *isa = g_new(MemoryRegion, 1);
- uint32_t kernel_base, initrd_base, cmdline_base = 0;
- int32_t kernel_size, initrd_size;
- PCIBus *pci_bus;
- PCIDevice *macio;
- MACIOIDEState *macio_ide;
- DeviceState *dev;
- BusState *adb_bus;
- int bios_size;
- 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;
- uint64_t tbfreq;
-
- linux_boot = (kernel_filename != NULL);
-
- /* init CPUs */
- if (machine->cpu_model == NULL)
- machine->cpu_model = "G3";
- for (i = 0; i < smp_cpus; i++) {
- cpu = cpu_ppc_init(machine->cpu_model);
- if (cpu == NULL) {
- fprintf(stderr, "Unable to find PowerPC CPU definition\n");
- exit(1);
- }
- env = &cpu->env;
-
- /* Set time-base frequency to 16.6 Mhz */
- cpu_ppc_tb_init(env, TBFREQ);
- qemu_register_reset(ppc_heathrow_reset, cpu);
- }
-
- /* allocate RAM */
- if (ram_size > (2047 << 20)) {
- fprintf(stderr,
- "qemu: Too much memory for this machine: %d MB, maximum 2047 MB\n",
- ((unsigned int)ram_size / (1 << 20)));
- exit(1);
- }
-
- memory_region_allocate_system_memory(ram, NULL, "ppc_heathrow.ram",
- ram_size);
- memory_region_add_subregion(sysmem, 0, ram);
-
- /* allocate and load BIOS */
- memory_region_init_ram(bios, NULL, "ppc_heathrow.bios", BIOS_SIZE,
- &error_fatal);
- vmstate_register_ram_global(bios);
-
- if (bios_name == NULL)
- bios_name = PROM_FILENAME;
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
- memory_region_set_readonly(bios, true);
- memory_region_add_subregion(sysmem, PROM_ADDR, bios);
-
- /* Load OpenBIOS (ELF) */
- if (filename) {
- bios_size = load_elf(filename, 0, NULL, NULL, NULL, NULL,
- 1, PPC_ELF_MACHINE, 0, 0);
- g_free(filename);
- } else {
- bios_size = -1;
- }
- if (bios_size < 0 || bios_size > BIOS_SIZE) {
- error_report("could not load PowerPC bios '%s'", bios_name);
- exit(1);
- }
-
- if (linux_boot) {
- uint64_t lowaddr = 0;
- int bswap_needed;
-
-#ifdef BSWAP_NEEDED
- bswap_needed = 1;
-#else
- bswap_needed = 0;
-#endif
- kernel_base = KERNEL_LOAD_ADDR;
- kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL,
- NULL, &lowaddr, NULL, 1, PPC_ELF_MACHINE,
- 0, 0);
- if (kernel_size < 0)
- kernel_size = load_aout(kernel_filename, kernel_base,
- ram_size - kernel_base, bswap_needed,
- TARGET_PAGE_SIZE);
- if (kernel_size < 0)
- kernel_size = load_image_targphys(kernel_filename,
- kernel_base,
- ram_size - kernel_base);
- if (kernel_size < 0) {
- error_report("could not load kernel '%s'", kernel_filename);
- exit(1);
- }
- /* load initrd */
- if (initrd_filename) {
- initrd_base = round_page(kernel_base + kernel_size + KERNEL_GAP);
- initrd_size = load_image_targphys(initrd_filename, initrd_base,
- ram_size - initrd_base);
- if (initrd_size < 0) {
- error_report("could not load initial ram disk '%s'",
- initrd_filename);
- exit(1);
- }
- cmdline_base = round_page(initrd_base + initrd_size);
- } else {
- initrd_base = 0;
- initrd_size = 0;
- cmdline_base = round_page(kernel_base + kernel_size + KERNEL_GAP);
- }
- ppc_boot_device = 'm';
- } else {
- kernel_base = 0;
- kernel_size = 0;
- initrd_base = 0;
- initrd_size = 0;
- ppc_boot_device = '\0';
- for (i = 0; boot_device[i] != '\0'; i++) {
- /* TOFIX: for now, the second IDE channel is not properly
- * used by OHW. The Mac floppy disk are not emulated.
- * For now, OHW cannot boot from the network.
- */
-#if 0
- if (boot_device[i] >= 'a' && boot_device[i] <= 'f') {
- ppc_boot_device = boot_device[i];
- break;
- }
-#else
- if (boot_device[i] >= 'c' && boot_device[i] <= 'd') {
- ppc_boot_device = boot_device[i];
- break;
- }
-#endif
- }
- if (ppc_boot_device == '\0') {
- fprintf(stderr, "No valid boot device for G3 Beige machine\n");
- exit(1);
- }
- }
-
- /* Register 2 MB of ISA IO space */
- memory_region_init_alias(isa, NULL, "isa_mmio",
- get_system_io(), 0, 0x00200000);
- memory_region_add_subregion(sysmem, 0xfe000000, isa);
-
- /* XXX: we register only 1 output pin for heathrow PIC */
- heathrow_irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
- heathrow_irqs[0] =
- g_malloc0(smp_cpus * sizeof(qemu_irq) * 1);
- /* Connect the heathrow PIC outputs to the 6xx bus */
- for (i = 0; i < smp_cpus; i++) {
- switch (PPC_INPUT(env)) {
- case PPC_FLAGS_INPUT_6xx:
- heathrow_irqs[i] = heathrow_irqs[0] + (i * 1);
- heathrow_irqs[i][0] =
- ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT];
- break;
- default:
- error_report("Bus model not supported on OldWorld Mac machine");
- exit(1);
- }
- }
-
- /* Timebase Frequency */
- if (kvm_enabled()) {
- tbfreq = kvmppc_get_tbfreq();
- } else {
- tbfreq = TBFREQ;
- }
-
- /* init basic PC hardware */
- if (PPC_INPUT(env) != PPC_FLAGS_INPUT_6xx) {
- error_report("Only 6xx bus is supported on heathrow machine");
- exit(1);
- }
- pic = heathrow_pic_init(&pic_mem, 1, heathrow_irqs);
- pci_bus = pci_grackle_init(0xfec00000, pic,
- get_system_memory(),
- get_system_io());
- pci_vga_init(pci_bus);
-
- escc_mem = escc_init(0, pic[0x0f], pic[0x10], serial_hds[0],
- serial_hds[1], ESCC_CLOCK, 4);
- memory_region_init_alias(escc_bar, NULL, "escc-bar",
- escc_mem, 0, memory_region_size(escc_mem));
-
- for(i = 0; i < nb_nics; i++)
- pci_nic_init_nofail(&nd_table[i], pci_bus, "ne2k_pci", NULL);
-
-
- ide_drive_get(hd, ARRAY_SIZE(hd));
-
- 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-0 */
- qdev_connect_gpio_out(dev, 2, pic[0x02]); /* IDE-0 DMA */
- qdev_connect_gpio_out(dev, 3, pic[0x0E]); /* IDE-1 */
- qdev_connect_gpio_out(dev, 4, pic[0x03]); /* IDE-1 DMA */
- qdev_prop_set_uint64(dev, "frequency", tbfreq);
- macio_init(macio, pic_mem, escc_bar);
-
- macio_ide = MACIO_IDE(object_resolve_path_component(OBJECT(macio),
- "ide[0]"));
- macio_ide_init_drives(macio_ide, hd);
-
- macio_ide = MACIO_IDE(object_resolve_path_component(OBJECT(macio),
- "ide[1]"));
- macio_ide_init_drives(macio_ide, &hd[MAX_IDE_DEVS]);
-
- 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()) {
- pci_create_simple(pci_bus, -1, "pci-ohci");
- }
-
- if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8)
- graphic_depth = 15;
-
- /* No PCI init: the BIOS will do it */
-
- fw_cfg = fw_cfg_init_mem(CFG_ADDR, CFG_ADDR + 2);
- fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
- 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);
- fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_base);
- fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
- if (kernel_cmdline) {
- fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, cmdline_base);
- pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE, kernel_cmdline);
- } else {
- fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0);
- }
- fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, initrd_base);
- fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size);
- fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, ppc_boot_device);
-
- fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_WIDTH, graphic_width);
- fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_HEIGHT, graphic_height);
- fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_DEPTH, graphic_depth);
-
- fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_IS_KVM, kvm_enabled());
- if (kvm_enabled()) {
-#ifdef CONFIG_KVM
- uint8_t *hypercall;
-
- hypercall = g_malloc(16);
- kvmppc_get_hypercall(env, hypercall, 16);
- fw_cfg_add_bytes(fw_cfg, FW_CFG_PPC_KVM_HC, hypercall, 16);
- fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_KVM_PID, getpid());
-#endif
- }
- fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, tbfreq);
- /* Mac OS X requires a "known good" clock-frequency value; pass it one. */
- fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_CLOCKFREQ, CLOCKFREQ);
- fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_BUSFREQ, BUSFREQ);
-
- qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
-}
-
-static int heathrow_kvm_type(const char *arg)
-{
- /* Always force PR KVM */
- return 2;
-}
-
-static void heathrow_machine_init(MachineClass *mc)
-{
- mc->desc = "Heathrow based PowerMAC";
- mc->init = ppc_heathrow_init;
- mc->max_cpus = MAX_CPUS;
-#ifndef TARGET_PPC64
- mc->is_default = 1;
-#endif
- /* TOFIX "cad" when Mac floppy is implemented */
- mc->default_boot_order = "cd";
- mc->kvm_type = heathrow_kvm_type;
-}
-
-DEFINE_MACHINE("g3beige", heathrow_machine_init)
diff --git a/qemu/hw/ppc/mpc8544_guts.c b/qemu/hw/ppc/mpc8544_guts.c
deleted file mode 100644
index ba69178d6..000000000
--- a/qemu/hw/ppc/mpc8544_guts.c
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * QEMU PowerPC MPC8544 global util pseudo-device
- *
- * Copyright (C) 2011 Freescale Semiconductor, Inc. All rights reserved.
- *
- * Author: Alexander Graf, <alex@csgraf.de>
- *
- * This is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * *****************************************************************
- *
- * The documentation for this device is noted in the MPC8544 documentation,
- * file name "MPC8544ERM.pdf". You can easily find it on the web.
- *
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/hw.h"
-#include "sysemu/sysemu.h"
-#include "hw/sysbus.h"
-
-#define MPC8544_GUTS_MMIO_SIZE 0x1000
-#define MPC8544_GUTS_RSTCR_RESET 0x02
-
-#define MPC8544_GUTS_ADDR_PORPLLSR 0x00
-#define MPC8544_GUTS_ADDR_PORBMSR 0x04
-#define MPC8544_GUTS_ADDR_PORIMPSCR 0x08
-#define MPC8544_GUTS_ADDR_PORDEVSR 0x0C
-#define MPC8544_GUTS_ADDR_PORDBGMSR 0x10
-#define MPC8544_GUTS_ADDR_PORDEVSR2 0x14
-#define MPC8544_GUTS_ADDR_GPPORCR 0x20
-#define MPC8544_GUTS_ADDR_GPIOCR 0x30
-#define MPC8544_GUTS_ADDR_GPOUTDR 0x40
-#define MPC8544_GUTS_ADDR_GPINDR 0x50
-#define MPC8544_GUTS_ADDR_PMUXCR 0x60
-#define MPC8544_GUTS_ADDR_DEVDISR 0x70
-#define MPC8544_GUTS_ADDR_POWMGTCSR 0x80
-#define MPC8544_GUTS_ADDR_MCPSUMR 0x90
-#define MPC8544_GUTS_ADDR_RSTRSCR 0x94
-#define MPC8544_GUTS_ADDR_PVR 0xA0
-#define MPC8544_GUTS_ADDR_SVR 0xA4
-#define MPC8544_GUTS_ADDR_RSTCR 0xB0
-#define MPC8544_GUTS_ADDR_IOVSELSR 0xC0
-#define MPC8544_GUTS_ADDR_DDRCSR 0xB20
-#define MPC8544_GUTS_ADDR_DDRCDR 0xB24
-#define MPC8544_GUTS_ADDR_DDRCLKDR 0xB28
-#define MPC8544_GUTS_ADDR_CLKOCR 0xE00
-#define MPC8544_GUTS_ADDR_SRDS1CR1 0xF04
-#define MPC8544_GUTS_ADDR_SRDS2CR1 0xF10
-#define MPC8544_GUTS_ADDR_SRDS2CR3 0xF18
-
-#define TYPE_MPC8544_GUTS "mpc8544-guts"
-#define MPC8544_GUTS(obj) OBJECT_CHECK(GutsState, (obj), TYPE_MPC8544_GUTS)
-
-struct GutsState {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- MemoryRegion iomem;
-};
-
-typedef struct GutsState GutsState;
-
-static uint64_t mpc8544_guts_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- uint32_t value = 0;
- PowerPCCPU *cpu = POWERPC_CPU(current_cpu);
- CPUPPCState *env = &cpu->env;
-
- addr &= MPC8544_GUTS_MMIO_SIZE - 1;
- switch (addr) {
- case MPC8544_GUTS_ADDR_PVR:
- value = env->spr[SPR_PVR];
- break;
- case MPC8544_GUTS_ADDR_SVR:
- value = env->spr[SPR_E500_SVR];
- break;
- default:
- fprintf(stderr, "guts: Unknown register read: %x\n", (int)addr);
- break;
- }
-
- return value;
-}
-
-static void mpc8544_guts_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- addr &= MPC8544_GUTS_MMIO_SIZE - 1;
-
- switch (addr) {
- case MPC8544_GUTS_ADDR_RSTCR:
- if (value & MPC8544_GUTS_RSTCR_RESET) {
- qemu_system_reset_request();
- }
- break;
- default:
- fprintf(stderr, "guts: Unknown register write: %x = %x\n",
- (int)addr, (unsigned)value);
- break;
- }
-}
-
-static const MemoryRegionOps mpc8544_guts_ops = {
- .read = mpc8544_guts_read,
- .write = mpc8544_guts_write,
- .endianness = DEVICE_BIG_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static void mpc8544_guts_initfn(Object *obj)
-{
- SysBusDevice *d = SYS_BUS_DEVICE(obj);
- GutsState *s = MPC8544_GUTS(obj);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &mpc8544_guts_ops, s,
- "mpc8544.guts", MPC8544_GUTS_MMIO_SIZE);
- sysbus_init_mmio(d, &s->iomem);
-}
-
-static const TypeInfo mpc8544_guts_info = {
- .name = TYPE_MPC8544_GUTS,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(GutsState),
- .instance_init = mpc8544_guts_initfn,
-};
-
-static void mpc8544_guts_register_types(void)
-{
- type_register_static(&mpc8544_guts_info);
-}
-
-type_init(mpc8544_guts_register_types)
diff --git a/qemu/hw/ppc/mpc8544ds.c b/qemu/hw/ppc/mpc8544ds.c
deleted file mode 100644
index 27b828901..000000000
--- a/qemu/hw/ppc/mpc8544ds.c
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Support for the PPC e500-based mpc8544ds board
- *
- * Copyright 2012 Freescale Semiconductor, Inc.
- *
- * This is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "e500.h"
-#include "hw/boards.h"
-#include "sysemu/device_tree.h"
-#include "hw/ppc/openpic.h"
-#include "qemu/error-report.h"
-
-static void mpc8544ds_fixup_devtree(PPCE500Params *params, void *fdt)
-{
- const char model[] = "MPC8544DS";
- const char compatible[] = "MPC8544DS\0MPC85xxDS";
-
- qemu_fdt_setprop(fdt, "/", "model", model, sizeof(model));
- qemu_fdt_setprop(fdt, "/", "compatible", compatible,
- sizeof(compatible));
-}
-
-static void mpc8544ds_init(MachineState *machine)
-{
- PPCE500Params params = {
- .pci_first_slot = 0x11,
- .pci_nr_slots = 2,
- .fixup_devtree = mpc8544ds_fixup_devtree,
- .mpic_version = OPENPIC_MODEL_FSL_MPIC_20,
- .ccsrbar_base = 0xE0000000ULL,
- .pci_mmio_base = 0xC0000000ULL,
- .pci_mmio_bus_base = 0xC0000000ULL,
- .pci_pio_base = 0xE1000000ULL,
- .spin_base = 0xEF000000ULL,
- };
-
- if (machine->ram_size > 0xc0000000) {
- error_report("The MPC8544DS board only supports up to 3GB of RAM");
- exit(1);
- }
-
- ppce500_init(machine, &params);
-}
-
-
-static void ppce500_machine_init(MachineClass *mc)
-{
- mc->desc = "mpc8544ds";
- mc->init = mpc8544ds_init;
- mc->max_cpus = 15;
-}
-
-DEFINE_MACHINE("mpc8544ds", ppce500_machine_init)
diff --git a/qemu/hw/ppc/ppc.c b/qemu/hw/ppc/ppc.c
deleted file mode 100644
index 38ff2e159..000000000
--- a/qemu/hw/ppc/ppc.c
+++ /dev/null
@@ -1,1345 +0,0 @@
-/*
- * QEMU generic PowerPC hardware System Emulator
- *
- * Copyright (c) 2003-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.
- */
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/hw.h"
-#include "hw/ppc/ppc.h"
-#include "hw/ppc/ppc_e500.h"
-#include "qemu/timer.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/cpus.h"
-#include "hw/timer/m48t59.h"
-#include "qemu/log.h"
-#include "qemu/error-report.h"
-#include "hw/loader.h"
-#include "sysemu/kvm.h"
-#include "kvm_ppc.h"
-#include "trace.h"
-
-//#define PPC_DEBUG_IRQ
-//#define PPC_DEBUG_TB
-
-#ifdef PPC_DEBUG_IRQ
-# define LOG_IRQ(...) qemu_log_mask(CPU_LOG_INT, ## __VA_ARGS__)
-#else
-# define LOG_IRQ(...) do { } while (0)
-#endif
-
-
-#ifdef PPC_DEBUG_TB
-# define LOG_TB(...) qemu_log(__VA_ARGS__)
-#else
-# define LOG_TB(...) do { } while (0)
-#endif
-
-static void cpu_ppc_tb_stop (CPUPPCState *env);
-static void cpu_ppc_tb_start (CPUPPCState *env);
-
-void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level)
-{
- CPUState *cs = CPU(cpu);
- CPUPPCState *env = &cpu->env;
- unsigned int old_pending = env->pending_interrupts;
-
- if (level) {
- env->pending_interrupts |= 1 << n_IRQ;
- cpu_interrupt(cs, CPU_INTERRUPT_HARD);
- } else {
- env->pending_interrupts &= ~(1 << n_IRQ);
- if (env->pending_interrupts == 0) {
- cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
- }
- }
-
- if (old_pending != env->pending_interrupts) {
-#ifdef CONFIG_KVM
- kvmppc_set_interrupt(cpu, n_IRQ, level);
-#endif
- }
-
- LOG_IRQ("%s: %p n_IRQ %d level %d => pending %08" PRIx32
- "req %08x\n", __func__, env, n_IRQ, level,
- env->pending_interrupts, CPU(cpu)->interrupt_request);
-}
-
-/* PowerPC 6xx / 7xx internal IRQ controller */
-static void ppc6xx_set_irq(void *opaque, int pin, int level)
-{
- PowerPCCPU *cpu = opaque;
- CPUPPCState *env = &cpu->env;
- int cur_level;
-
- LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
- env, pin, level);
- cur_level = (env->irq_input_state >> pin) & 1;
- /* Don't generate spurious events */
- if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
- CPUState *cs = CPU(cpu);
-
- switch (pin) {
- case PPC6xx_INPUT_TBEN:
- /* Level sensitive - active high */
- LOG_IRQ("%s: %s the time base\n",
- __func__, level ? "start" : "stop");
- if (level) {
- cpu_ppc_tb_start(env);
- } else {
- cpu_ppc_tb_stop(env);
- }
- case PPC6xx_INPUT_INT:
- /* Level sensitive - active high */
- LOG_IRQ("%s: set the external IRQ state to %d\n",
- __func__, level);
- ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
- break;
- case PPC6xx_INPUT_SMI:
- /* Level sensitive - active high */
- LOG_IRQ("%s: set the SMI IRQ state to %d\n",
- __func__, level);
- ppc_set_irq(cpu, PPC_INTERRUPT_SMI, level);
- break;
- case PPC6xx_INPUT_MCP:
- /* Negative edge sensitive */
- /* XXX: TODO: actual reaction may depends on HID0 status
- * 603/604/740/750: check HID0[EMCP]
- */
- if (cur_level == 1 && level == 0) {
- LOG_IRQ("%s: raise machine check state\n",
- __func__);
- ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1);
- }
- break;
- case PPC6xx_INPUT_CKSTP_IN:
- /* Level sensitive - active low */
- /* XXX: TODO: relay the signal to CKSTP_OUT pin */
- /* XXX: Note that the only way to restart the CPU is to reset it */
- if (level) {
- LOG_IRQ("%s: stop the CPU\n", __func__);
- cs->halted = 1;
- }
- break;
- case PPC6xx_INPUT_HRESET:
- /* Level sensitive - active low */
- if (level) {
- LOG_IRQ("%s: reset the CPU\n", __func__);
- cpu_interrupt(cs, CPU_INTERRUPT_RESET);
- }
- break;
- case PPC6xx_INPUT_SRESET:
- LOG_IRQ("%s: set the RESET IRQ state to %d\n",
- __func__, level);
- ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level);
- break;
- default:
- /* Unknown pin - do nothing */
- LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
- return;
- }
- if (level)
- env->irq_input_state |= 1 << pin;
- else
- env->irq_input_state &= ~(1 << pin);
- }
-}
-
-void ppc6xx_irq_init(CPUPPCState *env)
-{
- PowerPCCPU *cpu = ppc_env_get_cpu(env);
-
- env->irq_inputs = (void **)qemu_allocate_irqs(&ppc6xx_set_irq, cpu,
- PPC6xx_INPUT_NB);
-}
-
-#if defined(TARGET_PPC64)
-/* PowerPC 970 internal IRQ controller */
-static void ppc970_set_irq(void *opaque, int pin, int level)
-{
- PowerPCCPU *cpu = opaque;
- CPUPPCState *env = &cpu->env;
- int cur_level;
-
- LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
- env, pin, level);
- cur_level = (env->irq_input_state >> pin) & 1;
- /* Don't generate spurious events */
- if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
- CPUState *cs = CPU(cpu);
-
- switch (pin) {
- case PPC970_INPUT_INT:
- /* Level sensitive - active high */
- LOG_IRQ("%s: set the external IRQ state to %d\n",
- __func__, level);
- ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
- break;
- case PPC970_INPUT_THINT:
- /* Level sensitive - active high */
- LOG_IRQ("%s: set the SMI IRQ state to %d\n", __func__,
- level);
- ppc_set_irq(cpu, PPC_INTERRUPT_THERM, level);
- break;
- case PPC970_INPUT_MCP:
- /* Negative edge sensitive */
- /* XXX: TODO: actual reaction may depends on HID0 status
- * 603/604/740/750: check HID0[EMCP]
- */
- if (cur_level == 1 && level == 0) {
- LOG_IRQ("%s: raise machine check state\n",
- __func__);
- ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1);
- }
- break;
- case PPC970_INPUT_CKSTP:
- /* Level sensitive - active low */
- /* XXX: TODO: relay the signal to CKSTP_OUT pin */
- if (level) {
- LOG_IRQ("%s: stop the CPU\n", __func__);
- cs->halted = 1;
- } else {
- LOG_IRQ("%s: restart the CPU\n", __func__);
- cs->halted = 0;
- qemu_cpu_kick(cs);
- }
- break;
- case PPC970_INPUT_HRESET:
- /* Level sensitive - active low */
- if (level) {
- cpu_interrupt(cs, CPU_INTERRUPT_RESET);
- }
- break;
- case PPC970_INPUT_SRESET:
- LOG_IRQ("%s: set the RESET IRQ state to %d\n",
- __func__, level);
- ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level);
- break;
- case PPC970_INPUT_TBEN:
- LOG_IRQ("%s: set the TBEN state to %d\n", __func__,
- level);
- /* XXX: TODO */
- break;
- default:
- /* Unknown pin - do nothing */
- LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
- return;
- }
- if (level)
- env->irq_input_state |= 1 << pin;
- else
- env->irq_input_state &= ~(1 << pin);
- }
-}
-
-void ppc970_irq_init(CPUPPCState *env)
-{
- PowerPCCPU *cpu = ppc_env_get_cpu(env);
-
- env->irq_inputs = (void **)qemu_allocate_irqs(&ppc970_set_irq, cpu,
- PPC970_INPUT_NB);
-}
-
-/* POWER7 internal IRQ controller */
-static void power7_set_irq(void *opaque, int pin, int level)
-{
- PowerPCCPU *cpu = opaque;
- CPUPPCState *env = &cpu->env;
-
- LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
- env, pin, level);
-
- switch (pin) {
- case POWER7_INPUT_INT:
- /* Level sensitive - active high */
- LOG_IRQ("%s: set the external IRQ state to %d\n",
- __func__, level);
- ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
- break;
- default:
- /* Unknown pin - do nothing */
- LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
- return;
- }
- if (level) {
- env->irq_input_state |= 1 << pin;
- } else {
- env->irq_input_state &= ~(1 << pin);
- }
-}
-
-void ppcPOWER7_irq_init(CPUPPCState *env)
-{
- PowerPCCPU *cpu = ppc_env_get_cpu(env);
-
- env->irq_inputs = (void **)qemu_allocate_irqs(&power7_set_irq, cpu,
- POWER7_INPUT_NB);
-}
-#endif /* defined(TARGET_PPC64) */
-
-/* PowerPC 40x internal IRQ controller */
-static void ppc40x_set_irq(void *opaque, int pin, int level)
-{
- PowerPCCPU *cpu = opaque;
- CPUPPCState *env = &cpu->env;
- int cur_level;
-
- LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
- env, pin, level);
- cur_level = (env->irq_input_state >> pin) & 1;
- /* Don't generate spurious events */
- if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
- CPUState *cs = CPU(cpu);
-
- switch (pin) {
- case PPC40x_INPUT_RESET_SYS:
- if (level) {
- LOG_IRQ("%s: reset the PowerPC system\n",
- __func__);
- ppc40x_system_reset(cpu);
- }
- break;
- case PPC40x_INPUT_RESET_CHIP:
- if (level) {
- LOG_IRQ("%s: reset the PowerPC chip\n", __func__);
- ppc40x_chip_reset(cpu);
- }
- break;
- case PPC40x_INPUT_RESET_CORE:
- /* XXX: TODO: update DBSR[MRR] */
- if (level) {
- LOG_IRQ("%s: reset the PowerPC core\n", __func__);
- ppc40x_core_reset(cpu);
- }
- break;
- case PPC40x_INPUT_CINT:
- /* Level sensitive - active high */
- LOG_IRQ("%s: set the critical IRQ state to %d\n",
- __func__, level);
- ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level);
- break;
- case PPC40x_INPUT_INT:
- /* Level sensitive - active high */
- LOG_IRQ("%s: set the external IRQ state to %d\n",
- __func__, level);
- ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
- break;
- case PPC40x_INPUT_HALT:
- /* Level sensitive - active low */
- if (level) {
- LOG_IRQ("%s: stop the CPU\n", __func__);
- cs->halted = 1;
- } else {
- LOG_IRQ("%s: restart the CPU\n", __func__);
- cs->halted = 0;
- qemu_cpu_kick(cs);
- }
- break;
- case PPC40x_INPUT_DEBUG:
- /* Level sensitive - active high */
- LOG_IRQ("%s: set the debug pin state to %d\n",
- __func__, level);
- ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level);
- break;
- default:
- /* Unknown pin - do nothing */
- LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
- return;
- }
- if (level)
- env->irq_input_state |= 1 << pin;
- else
- env->irq_input_state &= ~(1 << pin);
- }
-}
-
-void ppc40x_irq_init(CPUPPCState *env)
-{
- PowerPCCPU *cpu = ppc_env_get_cpu(env);
-
- env->irq_inputs = (void **)qemu_allocate_irqs(&ppc40x_set_irq,
- cpu, PPC40x_INPUT_NB);
-}
-
-/* PowerPC E500 internal IRQ controller */
-static void ppce500_set_irq(void *opaque, int pin, int level)
-{
- PowerPCCPU *cpu = opaque;
- CPUPPCState *env = &cpu->env;
- int cur_level;
-
- LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
- env, pin, level);
- cur_level = (env->irq_input_state >> pin) & 1;
- /* Don't generate spurious events */
- if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
- switch (pin) {
- case PPCE500_INPUT_MCK:
- if (level) {
- LOG_IRQ("%s: reset the PowerPC system\n",
- __func__);
- qemu_system_reset_request();
- }
- break;
- case PPCE500_INPUT_RESET_CORE:
- if (level) {
- LOG_IRQ("%s: reset the PowerPC core\n", __func__);
- ppc_set_irq(cpu, PPC_INTERRUPT_MCK, level);
- }
- break;
- case PPCE500_INPUT_CINT:
- /* Level sensitive - active high */
- LOG_IRQ("%s: set the critical IRQ state to %d\n",
- __func__, level);
- ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level);
- break;
- case PPCE500_INPUT_INT:
- /* Level sensitive - active high */
- LOG_IRQ("%s: set the core IRQ state to %d\n",
- __func__, level);
- ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
- break;
- case PPCE500_INPUT_DEBUG:
- /* Level sensitive - active high */
- LOG_IRQ("%s: set the debug pin state to %d\n",
- __func__, level);
- ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level);
- break;
- default:
- /* Unknown pin - do nothing */
- LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
- return;
- }
- if (level)
- env->irq_input_state |= 1 << pin;
- else
- env->irq_input_state &= ~(1 << pin);
- }
-}
-
-void ppce500_irq_init(CPUPPCState *env)
-{
- PowerPCCPU *cpu = ppc_env_get_cpu(env);
-
- env->irq_inputs = (void **)qemu_allocate_irqs(&ppce500_set_irq,
- cpu, PPCE500_INPUT_NB);
-}
-
-/* Enable or Disable the E500 EPR capability */
-void ppce500_set_mpic_proxy(bool enabled)
-{
- CPUState *cs;
-
- CPU_FOREACH(cs) {
- PowerPCCPU *cpu = POWERPC_CPU(cs);
-
- cpu->env.mpic_proxy = enabled;
- if (kvm_enabled()) {
- kvmppc_set_mpic_proxy(cpu, enabled);
- }
- }
-}
-
-/*****************************************************************************/
-/* PowerPC time base and decrementer emulation */
-
-uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset)
-{
- /* TB time in tb periods */
- return muldiv64(vmclk, tb_env->tb_freq, NANOSECONDS_PER_SECOND) + tb_offset;
-}
-
-uint64_t cpu_ppc_load_tbl (CPUPPCState *env)
-{
- ppc_tb_t *tb_env = env->tb_env;
- uint64_t tb;
-
- if (kvm_enabled()) {
- return env->spr[SPR_TBL];
- }
-
- tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset);
- LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb);
-
- return tb;
-}
-
-static inline uint32_t _cpu_ppc_load_tbu(CPUPPCState *env)
-{
- ppc_tb_t *tb_env = env->tb_env;
- uint64_t tb;
-
- tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset);
- LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb);
-
- return tb >> 32;
-}
-
-uint32_t cpu_ppc_load_tbu (CPUPPCState *env)
-{
- if (kvm_enabled()) {
- return env->spr[SPR_TBU];
- }
-
- return _cpu_ppc_load_tbu(env);
-}
-
-static inline void cpu_ppc_store_tb(ppc_tb_t *tb_env, uint64_t vmclk,
- int64_t *tb_offsetp, uint64_t value)
-{
- *tb_offsetp = value -
- muldiv64(vmclk, tb_env->tb_freq, NANOSECONDS_PER_SECOND);
-
- LOG_TB("%s: tb %016" PRIx64 " offset %08" PRIx64 "\n",
- __func__, value, *tb_offsetp);
-}
-
-void cpu_ppc_store_tbl (CPUPPCState *env, uint32_t value)
-{
- ppc_tb_t *tb_env = env->tb_env;
- uint64_t tb;
-
- tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset);
- tb &= 0xFFFFFFFF00000000ULL;
- cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
- &tb_env->tb_offset, tb | (uint64_t)value);
-}
-
-static inline void _cpu_ppc_store_tbu(CPUPPCState *env, uint32_t value)
-{
- ppc_tb_t *tb_env = env->tb_env;
- uint64_t tb;
-
- tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset);
- tb &= 0x00000000FFFFFFFFULL;
- cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
- &tb_env->tb_offset, ((uint64_t)value << 32) | tb);
-}
-
-void cpu_ppc_store_tbu (CPUPPCState *env, uint32_t value)
-{
- _cpu_ppc_store_tbu(env, value);
-}
-
-uint64_t cpu_ppc_load_atbl (CPUPPCState *env)
-{
- ppc_tb_t *tb_env = env->tb_env;
- uint64_t tb;
-
- tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset);
- LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb);
-
- return tb;
-}
-
-uint32_t cpu_ppc_load_atbu (CPUPPCState *env)
-{
- ppc_tb_t *tb_env = env->tb_env;
- uint64_t tb;
-
- tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset);
- LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb);
-
- return tb >> 32;
-}
-
-void cpu_ppc_store_atbl (CPUPPCState *env, uint32_t value)
-{
- ppc_tb_t *tb_env = env->tb_env;
- uint64_t tb;
-
- tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset);
- tb &= 0xFFFFFFFF00000000ULL;
- cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
- &tb_env->atb_offset, tb | (uint64_t)value);
-}
-
-void cpu_ppc_store_atbu (CPUPPCState *env, uint32_t value)
-{
- ppc_tb_t *tb_env = env->tb_env;
- uint64_t tb;
-
- tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset);
- tb &= 0x00000000FFFFFFFFULL;
- cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
- &tb_env->atb_offset, ((uint64_t)value << 32) | tb);
-}
-
-static void cpu_ppc_tb_stop (CPUPPCState *env)
-{
- ppc_tb_t *tb_env = env->tb_env;
- uint64_t tb, atb, vmclk;
-
- /* If the time base is already frozen, do nothing */
- if (tb_env->tb_freq != 0) {
- vmclk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- /* Get the time base */
- tb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->tb_offset);
- /* Get the alternate time base */
- atb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->atb_offset);
- /* Store the time base value (ie compute the current offset) */
- cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb);
- /* Store the alternate time base value (compute the current offset) */
- cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb);
- /* Set the time base frequency to zero */
- tb_env->tb_freq = 0;
- /* Now, the time bases are frozen to tb_offset / atb_offset value */
- }
-}
-
-static void cpu_ppc_tb_start (CPUPPCState *env)
-{
- ppc_tb_t *tb_env = env->tb_env;
- uint64_t tb, atb, vmclk;
-
- /* If the time base is not frozen, do nothing */
- if (tb_env->tb_freq == 0) {
- vmclk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- /* Get the time base from tb_offset */
- tb = tb_env->tb_offset;
- /* Get the alternate time base from atb_offset */
- atb = tb_env->atb_offset;
- /* Restore the tb frequency from the decrementer frequency */
- tb_env->tb_freq = tb_env->decr_freq;
- /* Store the time base value */
- cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb);
- /* Store the alternate time base value */
- cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb);
- }
-}
-
-bool ppc_decr_clear_on_delivery(CPUPPCState *env)
-{
- ppc_tb_t *tb_env = env->tb_env;
- int flags = PPC_DECR_UNDERFLOW_TRIGGERED | PPC_DECR_UNDERFLOW_LEVEL;
- return ((tb_env->flags & flags) == PPC_DECR_UNDERFLOW_TRIGGERED);
-}
-
-static inline uint32_t _cpu_ppc_load_decr(CPUPPCState *env, uint64_t next)
-{
- ppc_tb_t *tb_env = env->tb_env;
- uint32_t decr;
- int64_t diff;
-
- diff = next - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- if (diff >= 0) {
- decr = muldiv64(diff, tb_env->decr_freq, NANOSECONDS_PER_SECOND);
- } else if (tb_env->flags & PPC_TIMER_BOOKE) {
- decr = 0;
- } else {
- decr = -muldiv64(-diff, tb_env->decr_freq, NANOSECONDS_PER_SECOND);
- }
- LOG_TB("%s: %08" PRIx32 "\n", __func__, decr);
-
- return decr;
-}
-
-uint32_t cpu_ppc_load_decr (CPUPPCState *env)
-{
- ppc_tb_t *tb_env = env->tb_env;
-
- if (kvm_enabled()) {
- return env->spr[SPR_DECR];
- }
-
- return _cpu_ppc_load_decr(env, tb_env->decr_next);
-}
-
-uint32_t cpu_ppc_load_hdecr (CPUPPCState *env)
-{
- ppc_tb_t *tb_env = env->tb_env;
-
- return _cpu_ppc_load_decr(env, tb_env->hdecr_next);
-}
-
-uint64_t cpu_ppc_load_purr (CPUPPCState *env)
-{
- ppc_tb_t *tb_env = env->tb_env;
- uint64_t diff;
-
- diff = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - tb_env->purr_start;
-
- return tb_env->purr_load +
- muldiv64(diff, tb_env->tb_freq, NANOSECONDS_PER_SECOND);
-}
-
-/* When decrementer expires,
- * all we need to do is generate or queue a CPU exception
- */
-static inline void cpu_ppc_decr_excp(PowerPCCPU *cpu)
-{
- /* Raise it */
- LOG_TB("raise decrementer exception\n");
- ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 1);
-}
-
-static inline void cpu_ppc_decr_lower(PowerPCCPU *cpu)
-{
- ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 0);
-}
-
-static inline void cpu_ppc_hdecr_excp(PowerPCCPU *cpu)
-{
- /* Raise it */
- LOG_TB("raise decrementer exception\n");
- ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 1);
-}
-
-static inline void cpu_ppc_hdecr_lower(PowerPCCPU *cpu)
-{
- ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 0);
-}
-
-static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp,
- QEMUTimer *timer,
- void (*raise_excp)(void *),
- void (*lower_excp)(PowerPCCPU *),
- uint32_t decr, uint32_t value)
-{
- CPUPPCState *env = &cpu->env;
- ppc_tb_t *tb_env = env->tb_env;
- uint64_t now, next;
-
- LOG_TB("%s: %08" PRIx32 " => %08" PRIx32 "\n", __func__,
- decr, value);
-
- if (kvm_enabled()) {
- /* KVM handles decrementer exceptions, we don't need our own timer */
- return;
- }
-
- /*
- * Going from 2 -> 1, 1 -> 0 or 0 -> -1 is the event to generate a DEC
- * interrupt.
- *
- * If we get a really small DEC value, we can assume that by the time we
- * handled it we should inject an interrupt already.
- *
- * On MSB level based DEC implementations the MSB always means the interrupt
- * is pending, so raise it on those.
- *
- * On MSB edge based DEC implementations the MSB going from 0 -> 1 triggers
- * an edge interrupt, so raise it here too.
- */
- if ((value < 3) ||
- ((tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL) && (value & 0x80000000)) ||
- ((tb_env->flags & PPC_DECR_UNDERFLOW_TRIGGERED) && (value & 0x80000000)
- && !(decr & 0x80000000))) {
- (*raise_excp)(cpu);
- return;
- }
-
- /* On MSB level based systems a 0 for the MSB stops interrupt delivery */
- if (!(value & 0x80000000) && (tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL)) {
- (*lower_excp)(cpu);
- }
-
- /* Calculate the next timer event */
- now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- next = now + muldiv64(value, NANOSECONDS_PER_SECOND, tb_env->decr_freq);
- *nextp = next;
-
- /* Adjust timer */
- timer_mod(timer, next);
-}
-
-static inline void _cpu_ppc_store_decr(PowerPCCPU *cpu, uint32_t decr,
- uint32_t value)
-{
- ppc_tb_t *tb_env = cpu->env.tb_env;
-
- __cpu_ppc_store_decr(cpu, &tb_env->decr_next, tb_env->decr_timer,
- tb_env->decr_timer->cb, &cpu_ppc_decr_lower, decr,
- value);
-}
-
-void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value)
-{
- PowerPCCPU *cpu = ppc_env_get_cpu(env);
-
- _cpu_ppc_store_decr(cpu, cpu_ppc_load_decr(env), value);
-}
-
-static void cpu_ppc_decr_cb(void *opaque)
-{
- PowerPCCPU *cpu = opaque;
-
- cpu_ppc_decr_excp(cpu);
-}
-
-static inline void _cpu_ppc_store_hdecr(PowerPCCPU *cpu, uint32_t hdecr,
- uint32_t value)
-{
- ppc_tb_t *tb_env = cpu->env.tb_env;
-
- if (tb_env->hdecr_timer != NULL) {
- __cpu_ppc_store_decr(cpu, &tb_env->hdecr_next, tb_env->hdecr_timer,
- tb_env->hdecr_timer->cb, &cpu_ppc_hdecr_lower,
- hdecr, value);
- }
-}
-
-void cpu_ppc_store_hdecr (CPUPPCState *env, uint32_t value)
-{
- PowerPCCPU *cpu = ppc_env_get_cpu(env);
-
- _cpu_ppc_store_hdecr(cpu, cpu_ppc_load_hdecr(env), value);
-}
-
-static void cpu_ppc_hdecr_cb(void *opaque)
-{
- PowerPCCPU *cpu = opaque;
-
- cpu_ppc_hdecr_excp(cpu);
-}
-
-static void cpu_ppc_store_purr(PowerPCCPU *cpu, uint64_t value)
-{
- ppc_tb_t *tb_env = cpu->env.tb_env;
-
- tb_env->purr_load = value;
- tb_env->purr_start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-}
-
-static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq)
-{
- CPUPPCState *env = opaque;
- PowerPCCPU *cpu = ppc_env_get_cpu(env);
- ppc_tb_t *tb_env = env->tb_env;
-
- tb_env->tb_freq = freq;
- tb_env->decr_freq = freq;
- /* There is a bug in Linux 2.4 kernels:
- * if a decrementer exception is pending when it enables msr_ee at startup,
- * it's not ready to handle it...
- */
- _cpu_ppc_store_decr(cpu, 0xFFFFFFFF, 0xFFFFFFFF);
- _cpu_ppc_store_hdecr(cpu, 0xFFFFFFFF, 0xFFFFFFFF);
- cpu_ppc_store_purr(cpu, 0x0000000000000000ULL);
-}
-
-static void timebase_pre_save(void *opaque)
-{
- PPCTimebase *tb = opaque;
- uint64_t ticks = cpu_get_host_ticks();
- PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu);
-
- if (!first_ppc_cpu->env.tb_env) {
- error_report("No timebase object");
- return;
- }
-
- tb->time_of_the_day_ns = qemu_clock_get_ns(QEMU_CLOCK_HOST);
- /*
- * tb_offset is only expected to be changed by migration so
- * there is no need to update it from KVM here
- */
- tb->guest_timebase = ticks + first_ppc_cpu->env.tb_env->tb_offset;
-}
-
-static int timebase_post_load(void *opaque, int version_id)
-{
- PPCTimebase *tb_remote = opaque;
- CPUState *cpu;
- PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu);
- int64_t tb_off_adj, tb_off, ns_diff;
- int64_t migration_duration_ns, migration_duration_tb, guest_tb, host_ns;
- unsigned long freq;
-
- if (!first_ppc_cpu->env.tb_env) {
- error_report("No timebase object");
- return -1;
- }
-
- freq = first_ppc_cpu->env.tb_env->tb_freq;
- /*
- * Calculate timebase on the destination side of migration.
- * The destination timebase must be not less than the source timebase.
- * We try to adjust timebase by downtime if host clocks are not
- * too much out of sync (1 second for now).
- */
- host_ns = qemu_clock_get_ns(QEMU_CLOCK_HOST);
- ns_diff = MAX(0, host_ns - tb_remote->time_of_the_day_ns);
- migration_duration_ns = MIN(NANOSECONDS_PER_SECOND, ns_diff);
- migration_duration_tb = muldiv64(migration_duration_ns, freq,
- NANOSECONDS_PER_SECOND);
- guest_tb = tb_remote->guest_timebase + MIN(0, migration_duration_tb);
-
- tb_off_adj = guest_tb - cpu_get_host_ticks();
-
- tb_off = first_ppc_cpu->env.tb_env->tb_offset;
- trace_ppc_tb_adjust(tb_off, tb_off_adj, tb_off_adj - tb_off,
- (tb_off_adj - tb_off) / freq);
-
- /* Set new offset to all CPUs */
- CPU_FOREACH(cpu) {
- PowerPCCPU *pcpu = POWERPC_CPU(cpu);
- pcpu->env.tb_env->tb_offset = tb_off_adj;
- }
-
- return 0;
-}
-
-const VMStateDescription vmstate_ppc_timebase = {
- .name = "timebase",
- .version_id = 1,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .pre_save = timebase_pre_save,
- .post_load = timebase_post_load,
- .fields = (VMStateField []) {
- VMSTATE_UINT64(guest_timebase, PPCTimebase),
- VMSTATE_INT64(time_of_the_day_ns, PPCTimebase),
- VMSTATE_END_OF_LIST()
- },
-};
-
-/* Set up (once) timebase frequency (in Hz) */
-clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq)
-{
- PowerPCCPU *cpu = ppc_env_get_cpu(env);
- ppc_tb_t *tb_env;
-
- tb_env = g_malloc0(sizeof(ppc_tb_t));
- env->tb_env = tb_env;
- tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED;
- if (env->insns_flags & PPC_SEGMENT_64B) {
- /* All Book3S 64bit CPUs implement level based DEC logic */
- tb_env->flags |= PPC_DECR_UNDERFLOW_LEVEL;
- }
- /* Create new timer */
- tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_decr_cb, cpu);
- if (0) {
- /* XXX: find a suitable condition to enable the hypervisor decrementer
- */
- tb_env->hdecr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_hdecr_cb,
- cpu);
- } else {
- tb_env->hdecr_timer = NULL;
- }
- cpu_ppc_set_tb_clk(env, freq);
-
- return &cpu_ppc_set_tb_clk;
-}
-
-/* Specific helpers for POWER & PowerPC 601 RTC */
-#if 0
-static clk_setup_cb cpu_ppc601_rtc_init (CPUPPCState *env)
-{
- return cpu_ppc_tb_init(env, 7812500);
-}
-#endif
-
-void cpu_ppc601_store_rtcu (CPUPPCState *env, uint32_t value)
-{
- _cpu_ppc_store_tbu(env, value);
-}
-
-uint32_t cpu_ppc601_load_rtcu (CPUPPCState *env)
-{
- return _cpu_ppc_load_tbu(env);
-}
-
-void cpu_ppc601_store_rtcl (CPUPPCState *env, uint32_t value)
-{
- cpu_ppc_store_tbl(env, value & 0x3FFFFF80);
-}
-
-uint32_t cpu_ppc601_load_rtcl (CPUPPCState *env)
-{
- return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
-}
-
-/*****************************************************************************/
-/* PowerPC 40x timers */
-
-/* PIT, FIT & WDT */
-typedef struct ppc40x_timer_t ppc40x_timer_t;
-struct ppc40x_timer_t {
- uint64_t pit_reload; /* PIT auto-reload value */
- uint64_t fit_next; /* Tick for next FIT interrupt */
- QEMUTimer *fit_timer;
- uint64_t wdt_next; /* Tick for next WDT interrupt */
- QEMUTimer *wdt_timer;
-
- /* 405 have the PIT, 440 have a DECR. */
- unsigned int decr_excp;
-};
-
-/* Fixed interval timer */
-static void cpu_4xx_fit_cb (void *opaque)
-{
- PowerPCCPU *cpu;
- CPUPPCState *env;
- ppc_tb_t *tb_env;
- ppc40x_timer_t *ppc40x_timer;
- uint64_t now, next;
-
- env = opaque;
- cpu = ppc_env_get_cpu(env);
- tb_env = env->tb_env;
- ppc40x_timer = tb_env->opaque;
- now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- switch ((env->spr[SPR_40x_TCR] >> 24) & 0x3) {
- case 0:
- next = 1 << 9;
- break;
- case 1:
- next = 1 << 13;
- break;
- case 2:
- next = 1 << 17;
- break;
- case 3:
- next = 1 << 21;
- break;
- default:
- /* Cannot occur, but makes gcc happy */
- return;
- }
- next = now + muldiv64(next, NANOSECONDS_PER_SECOND, tb_env->tb_freq);
- if (next == now)
- next++;
- timer_mod(ppc40x_timer->fit_timer, next);
- env->spr[SPR_40x_TSR] |= 1 << 26;
- if ((env->spr[SPR_40x_TCR] >> 23) & 0x1) {
- ppc_set_irq(cpu, PPC_INTERRUPT_FIT, 1);
- }
- LOG_TB("%s: ir %d TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx "\n", __func__,
- (int)((env->spr[SPR_40x_TCR] >> 23) & 0x1),
- env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
-}
-
-/* Programmable interval timer */
-static void start_stop_pit (CPUPPCState *env, ppc_tb_t *tb_env, int is_excp)
-{
- ppc40x_timer_t *ppc40x_timer;
- uint64_t now, next;
-
- ppc40x_timer = tb_env->opaque;
- if (ppc40x_timer->pit_reload <= 1 ||
- !((env->spr[SPR_40x_TCR] >> 26) & 0x1) ||
- (is_excp && !((env->spr[SPR_40x_TCR] >> 22) & 0x1))) {
- /* Stop PIT */
- LOG_TB("%s: stop PIT\n", __func__);
- timer_del(tb_env->decr_timer);
- } else {
- LOG_TB("%s: start PIT %016" PRIx64 "\n",
- __func__, ppc40x_timer->pit_reload);
- now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- next = now + muldiv64(ppc40x_timer->pit_reload,
- NANOSECONDS_PER_SECOND, tb_env->decr_freq);
- if (is_excp)
- next += tb_env->decr_next - now;
- if (next == now)
- next++;
- timer_mod(tb_env->decr_timer, next);
- tb_env->decr_next = next;
- }
-}
-
-static void cpu_4xx_pit_cb (void *opaque)
-{
- PowerPCCPU *cpu;
- CPUPPCState *env;
- ppc_tb_t *tb_env;
- ppc40x_timer_t *ppc40x_timer;
-
- env = opaque;
- cpu = ppc_env_get_cpu(env);
- tb_env = env->tb_env;
- ppc40x_timer = tb_env->opaque;
- env->spr[SPR_40x_TSR] |= 1 << 27;
- if ((env->spr[SPR_40x_TCR] >> 26) & 0x1) {
- ppc_set_irq(cpu, ppc40x_timer->decr_excp, 1);
- }
- start_stop_pit(env, tb_env, 1);
- LOG_TB("%s: ar %d ir %d TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx " "
- "%016" PRIx64 "\n", __func__,
- (int)((env->spr[SPR_40x_TCR] >> 22) & 0x1),
- (int)((env->spr[SPR_40x_TCR] >> 26) & 0x1),
- env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR],
- ppc40x_timer->pit_reload);
-}
-
-/* Watchdog timer */
-static void cpu_4xx_wdt_cb (void *opaque)
-{
- PowerPCCPU *cpu;
- CPUPPCState *env;
- ppc_tb_t *tb_env;
- ppc40x_timer_t *ppc40x_timer;
- uint64_t now, next;
-
- env = opaque;
- cpu = ppc_env_get_cpu(env);
- tb_env = env->tb_env;
- ppc40x_timer = tb_env->opaque;
- now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- switch ((env->spr[SPR_40x_TCR] >> 30) & 0x3) {
- case 0:
- next = 1 << 17;
- break;
- case 1:
- next = 1 << 21;
- break;
- case 2:
- next = 1 << 25;
- break;
- case 3:
- next = 1 << 29;
- break;
- default:
- /* Cannot occur, but makes gcc happy */
- return;
- }
- next = now + muldiv64(next, NANOSECONDS_PER_SECOND, tb_env->decr_freq);
- if (next == now)
- next++;
- LOG_TB("%s: TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx "\n", __func__,
- env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
- switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) {
- case 0x0:
- case 0x1:
- timer_mod(ppc40x_timer->wdt_timer, next);
- ppc40x_timer->wdt_next = next;
- env->spr[SPR_40x_TSR] |= 1U << 31;
- break;
- case 0x2:
- timer_mod(ppc40x_timer->wdt_timer, next);
- ppc40x_timer->wdt_next = next;
- env->spr[SPR_40x_TSR] |= 1 << 30;
- if ((env->spr[SPR_40x_TCR] >> 27) & 0x1) {
- ppc_set_irq(cpu, PPC_INTERRUPT_WDT, 1);
- }
- break;
- case 0x3:
- env->spr[SPR_40x_TSR] &= ~0x30000000;
- env->spr[SPR_40x_TSR] |= env->spr[SPR_40x_TCR] & 0x30000000;
- switch ((env->spr[SPR_40x_TCR] >> 28) & 0x3) {
- case 0x0:
- /* No reset */
- break;
- case 0x1: /* Core reset */
- ppc40x_core_reset(cpu);
- break;
- case 0x2: /* Chip reset */
- ppc40x_chip_reset(cpu);
- break;
- case 0x3: /* System reset */
- ppc40x_system_reset(cpu);
- break;
- }
- }
-}
-
-void store_40x_pit (CPUPPCState *env, target_ulong val)
-{
- ppc_tb_t *tb_env;
- ppc40x_timer_t *ppc40x_timer;
-
- tb_env = env->tb_env;
- ppc40x_timer = tb_env->opaque;
- LOG_TB("%s val" TARGET_FMT_lx "\n", __func__, val);
- ppc40x_timer->pit_reload = val;
- start_stop_pit(env, tb_env, 0);
-}
-
-target_ulong load_40x_pit (CPUPPCState *env)
-{
- return cpu_ppc_load_decr(env);
-}
-
-static void ppc_40x_set_tb_clk (void *opaque, uint32_t freq)
-{
- CPUPPCState *env = opaque;
- ppc_tb_t *tb_env = env->tb_env;
-
- LOG_TB("%s set new frequency to %" PRIu32 "\n", __func__,
- freq);
- tb_env->tb_freq = freq;
- tb_env->decr_freq = freq;
- /* XXX: we should also update all timers */
-}
-
-clk_setup_cb ppc_40x_timers_init (CPUPPCState *env, uint32_t freq,
- unsigned int decr_excp)
-{
- ppc_tb_t *tb_env;
- ppc40x_timer_t *ppc40x_timer;
-
- tb_env = g_malloc0(sizeof(ppc_tb_t));
- env->tb_env = tb_env;
- tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED;
- ppc40x_timer = g_malloc0(sizeof(ppc40x_timer_t));
- tb_env->tb_freq = freq;
- tb_env->decr_freq = freq;
- tb_env->opaque = ppc40x_timer;
- LOG_TB("%s freq %" PRIu32 "\n", __func__, freq);
- if (ppc40x_timer != NULL) {
- /* We use decr timer for PIT */
- tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_pit_cb, env);
- ppc40x_timer->fit_timer =
- timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_fit_cb, env);
- ppc40x_timer->wdt_timer =
- timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_wdt_cb, env);
- ppc40x_timer->decr_excp = decr_excp;
- }
-
- return &ppc_40x_set_tb_clk;
-}
-
-/*****************************************************************************/
-/* Embedded PowerPC Device Control Registers */
-typedef struct ppc_dcrn_t ppc_dcrn_t;
-struct ppc_dcrn_t {
- dcr_read_cb dcr_read;
- dcr_write_cb dcr_write;
- void *opaque;
-};
-
-/* XXX: on 460, DCR addresses are 32 bits wide,
- * using DCRIPR to get the 22 upper bits of the DCR address
- */
-#define DCRN_NB 1024
-struct ppc_dcr_t {
- ppc_dcrn_t dcrn[DCRN_NB];
- int (*read_error)(int dcrn);
- int (*write_error)(int dcrn);
-};
-
-int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp)
-{
- ppc_dcrn_t *dcr;
-
- if (dcrn < 0 || dcrn >= DCRN_NB)
- goto error;
- dcr = &dcr_env->dcrn[dcrn];
- if (dcr->dcr_read == NULL)
- goto error;
- *valp = (*dcr->dcr_read)(dcr->opaque, dcrn);
-
- return 0;
-
- error:
- if (dcr_env->read_error != NULL)
- return (*dcr_env->read_error)(dcrn);
-
- return -1;
-}
-
-int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val)
-{
- ppc_dcrn_t *dcr;
-
- if (dcrn < 0 || dcrn >= DCRN_NB)
- goto error;
- dcr = &dcr_env->dcrn[dcrn];
- if (dcr->dcr_write == NULL)
- goto error;
- (*dcr->dcr_write)(dcr->opaque, dcrn, val);
-
- return 0;
-
- error:
- if (dcr_env->write_error != NULL)
- return (*dcr_env->write_error)(dcrn);
-
- return -1;
-}
-
-int ppc_dcr_register (CPUPPCState *env, int dcrn, void *opaque,
- dcr_read_cb dcr_read, dcr_write_cb dcr_write)
-{
- ppc_dcr_t *dcr_env;
- ppc_dcrn_t *dcr;
-
- dcr_env = env->dcr_env;
- if (dcr_env == NULL)
- return -1;
- if (dcrn < 0 || dcrn >= DCRN_NB)
- return -1;
- dcr = &dcr_env->dcrn[dcrn];
- if (dcr->opaque != NULL ||
- dcr->dcr_read != NULL ||
- dcr->dcr_write != NULL)
- return -1;
- dcr->opaque = opaque;
- dcr->dcr_read = dcr_read;
- dcr->dcr_write = dcr_write;
-
- return 0;
-}
-
-int ppc_dcr_init (CPUPPCState *env, int (*read_error)(int dcrn),
- int (*write_error)(int dcrn))
-{
- ppc_dcr_t *dcr_env;
-
- dcr_env = g_malloc0(sizeof(ppc_dcr_t));
- dcr_env->read_error = read_error;
- dcr_env->write_error = write_error;
- env->dcr_env = dcr_env;
-
- return 0;
-}
-
-/*****************************************************************************/
-/* Debug port */
-void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val)
-{
- addr &= 0xF;
- switch (addr) {
- case 0:
- printf("%c", val);
- break;
- case 1:
- printf("\n");
- fflush(stdout);
- break;
- case 2:
- printf("Set loglevel to %04" PRIx32 "\n", val);
- qemu_set_log(val | 0x100);
- break;
- }
-}
-
-/* CPU device-tree ID helpers */
-int ppc_get_vcpu_dt_id(PowerPCCPU *cpu)
-{
- return cpu->cpu_dt_id;
-}
-
-PowerPCCPU *ppc_get_vcpu_by_dt_id(int cpu_dt_id)
-{
- CPUState *cs;
-
- CPU_FOREACH(cs) {
- PowerPCCPU *cpu = POWERPC_CPU(cs);
-
- if (cpu->cpu_dt_id == cpu_dt_id) {
- return cpu;
- }
- }
-
- return NULL;
-}
diff --git a/qemu/hw/ppc/ppc405.h b/qemu/hw/ppc/ppc405.h
deleted file mode 100644
index 1c5f04fae..000000000
--- a/qemu/hw/ppc/ppc405.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * QEMU PowerPC 405 shared definitions
- *
- * 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_405_H)
-#define PPC_405_H
-
-#include "hw/ppc/ppc4xx.h"
-
-/* Bootinfo as set-up by u-boot */
-typedef struct ppc4xx_bd_info_t ppc4xx_bd_info_t;
-struct ppc4xx_bd_info_t {
- uint32_t bi_memstart;
- uint32_t bi_memsize;
- uint32_t bi_flashstart;
- uint32_t bi_flashsize;
- uint32_t bi_flashoffset; /* 0x10 */
- uint32_t bi_sramstart;
- uint32_t bi_sramsize;
- uint32_t bi_bootflags;
- uint32_t bi_ipaddr; /* 0x20 */
- uint8_t bi_enetaddr[6];
- uint16_t bi_ethspeed;
- uint32_t bi_intfreq;
- uint32_t bi_busfreq; /* 0x30 */
- uint32_t bi_baudrate;
- uint8_t bi_s_version[4];
- uint8_t bi_r_version[32];
- uint32_t bi_procfreq;
- uint32_t bi_plb_busfreq;
- uint32_t bi_pci_busfreq;
- uint8_t bi_pci_enetaddr[6];
- uint32_t bi_pci_enetaddr2[6];
- uint32_t bi_opbfreq;
- uint32_t bi_iic_fast[2];
-};
-
-/* PowerPC 405 core */
-ram_addr_t ppc405_set_bootinfo (CPUPPCState *env, ppc4xx_bd_info_t *bd,
- uint32_t flags);
-
-CPUPPCState *ppc405cr_init(MemoryRegion *address_space_mem,
- MemoryRegion ram_memories[4],
- hwaddr ram_bases[4],
- hwaddr ram_sizes[4],
- uint32_t sysclk, qemu_irq **picp,
- int do_init);
-CPUPPCState *ppc405ep_init(MemoryRegion *address_space_mem,
- MemoryRegion ram_memories[2],
- hwaddr ram_bases[2],
- hwaddr ram_sizes[2],
- uint32_t sysclk, qemu_irq **picp,
- int do_init);
-/* IBM STBxxx microcontrollers */
-CPUPPCState *ppc_stb025_init (MemoryRegion ram_memories[2],
- hwaddr ram_bases[2],
- hwaddr ram_sizes[2],
- uint32_t sysclk, qemu_irq **picp,
- ram_addr_t *offsetp);
-
-#endif /* !defined(PPC_405_H) */
diff --git a/qemu/hw/ppc/ppc405_boards.c b/qemu/hw/ppc/ppc405_boards.c
deleted file mode 100644
index 4b2f07aec..000000000
--- a/qemu/hw/ppc/ppc405_boards.c
+++ /dev/null
@@ -1,664 +0,0 @@
-/*
- * QEMU PowerPC 405 evaluation boards emulation
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/hw.h"
-#include "hw/ppc/ppc.h"
-#include "ppc405.h"
-#include "hw/timer/m48t59.h"
-#include "hw/block/flash.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/qtest.h"
-#include "sysemu/block-backend.h"
-#include "hw/boards.h"
-#include "qemu/log.h"
-#include "qemu/error-report.h"
-#include "hw/loader.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
-#include "exec/address-spaces.h"
-
-#define BIOS_FILENAME "ppc405_rom.bin"
-#define BIOS_SIZE (2048 * 1024)
-
-#define KERNEL_LOAD_ADDR 0x00000000
-#define INITRD_LOAD_ADDR 0x01800000
-
-#define USE_FLASH_BIOS
-
-//#define DEBUG_BOARD_INIT
-
-/*****************************************************************************/
-/* PPC405EP reference board (IBM) */
-/* Standalone board with:
- * - PowerPC 405EP CPU
- * - SDRAM (0x00000000)
- * - Flash (0xFFF80000)
- * - SRAM (0xFFF00000)
- * - NVRAM (0xF0000000)
- * - FPGA (0xF0300000)
- */
-typedef struct ref405ep_fpga_t ref405ep_fpga_t;
-struct ref405ep_fpga_t {
- uint8_t reg0;
- uint8_t reg1;
-};
-
-static uint32_t ref405ep_fpga_readb (void *opaque, hwaddr addr)
-{
- ref405ep_fpga_t *fpga;
- uint32_t ret;
-
- fpga = opaque;
- switch (addr) {
- case 0x0:
- ret = fpga->reg0;
- break;
- case 0x1:
- ret = fpga->reg1;
- break;
- default:
- ret = 0;
- break;
- }
-
- return ret;
-}
-
-static void ref405ep_fpga_writeb (void *opaque,
- hwaddr addr, uint32_t value)
-{
- ref405ep_fpga_t *fpga;
-
- fpga = opaque;
- switch (addr) {
- case 0x0:
- /* Read only */
- break;
- case 0x1:
- fpga->reg1 = value;
- break;
- default:
- break;
- }
-}
-
-static uint32_t ref405ep_fpga_readw (void *opaque, hwaddr addr)
-{
- uint32_t ret;
-
- ret = ref405ep_fpga_readb(opaque, addr) << 8;
- ret |= ref405ep_fpga_readb(opaque, addr + 1);
-
- return ret;
-}
-
-static void ref405ep_fpga_writew (void *opaque,
- hwaddr addr, uint32_t value)
-{
- ref405ep_fpga_writeb(opaque, addr, (value >> 8) & 0xFF);
- ref405ep_fpga_writeb(opaque, addr + 1, value & 0xFF);
-}
-
-static uint32_t ref405ep_fpga_readl (void *opaque, hwaddr addr)
-{
- uint32_t ret;
-
- ret = ref405ep_fpga_readb(opaque, addr) << 24;
- ret |= ref405ep_fpga_readb(opaque, addr + 1) << 16;
- ret |= ref405ep_fpga_readb(opaque, addr + 2) << 8;
- ret |= ref405ep_fpga_readb(opaque, addr + 3);
-
- return ret;
-}
-
-static void ref405ep_fpga_writel (void *opaque,
- hwaddr addr, uint32_t value)
-{
- ref405ep_fpga_writeb(opaque, addr, (value >> 24) & 0xFF);
- ref405ep_fpga_writeb(opaque, addr + 1, (value >> 16) & 0xFF);
- ref405ep_fpga_writeb(opaque, addr + 2, (value >> 8) & 0xFF);
- ref405ep_fpga_writeb(opaque, addr + 3, value & 0xFF);
-}
-
-static const MemoryRegionOps ref405ep_fpga_ops = {
- .old_mmio = {
- .read = {
- ref405ep_fpga_readb, ref405ep_fpga_readw, ref405ep_fpga_readl,
- },
- .write = {
- ref405ep_fpga_writeb, ref405ep_fpga_writew, ref405ep_fpga_writel,
- },
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void ref405ep_fpga_reset (void *opaque)
-{
- ref405ep_fpga_t *fpga;
-
- fpga = opaque;
- fpga->reg0 = 0x00;
- fpga->reg1 = 0x0F;
-}
-
-static void ref405ep_fpga_init(MemoryRegion *sysmem, uint32_t base)
-{
- ref405ep_fpga_t *fpga;
- MemoryRegion *fpga_memory = g_new(MemoryRegion, 1);
-
- fpga = g_malloc0(sizeof(ref405ep_fpga_t));
- memory_region_init_io(fpga_memory, NULL, &ref405ep_fpga_ops, fpga,
- "fpga", 0x00000100);
- memory_region_add_subregion(sysmem, base, fpga_memory);
- qemu_register_reset(&ref405ep_fpga_reset, fpga);
-}
-
-static void ref405ep_init(MachineState *machine)
-{
- ram_addr_t ram_size = machine->ram_size;
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- const char *initrd_filename = machine->initrd_filename;
- char *filename;
- ppc4xx_bd_info_t bd;
- CPUPPCState *env;
- qemu_irq *pic;
- MemoryRegion *bios;
- MemoryRegion *sram = g_new(MemoryRegion, 1);
- ram_addr_t bdloc;
- MemoryRegion *ram_memories = g_malloc(2 * sizeof(*ram_memories));
- hwaddr ram_bases[2], ram_sizes[2];
- target_ulong sram_size;
- long bios_size;
- //int phy_addr = 0;
- //static int phy_addr = 1;
- target_ulong kernel_base, initrd_base;
- long kernel_size, initrd_size;
- int linux_boot;
- int fl_idx, fl_sectors, len;
- DriveInfo *dinfo;
- MemoryRegion *sysmem = get_system_memory();
-
- /* XXX: fix this */
- memory_region_allocate_system_memory(&ram_memories[0], NULL, "ef405ep.ram",
- 0x08000000);
- ram_bases[0] = 0;
- ram_sizes[0] = 0x08000000;
- memory_region_init(&ram_memories[1], NULL, "ef405ep.ram1", 0);
- ram_bases[1] = 0x00000000;
- ram_sizes[1] = 0x00000000;
- ram_size = 128 * 1024 * 1024;
-#ifdef DEBUG_BOARD_INIT
- printf("%s: register cpu\n", __func__);
-#endif
- env = ppc405ep_init(sysmem, ram_memories, ram_bases, ram_sizes,
- 33333333, &pic, kernel_filename == NULL ? 0 : 1);
- /* allocate SRAM */
- sram_size = 512 * 1024;
- memory_region_init_ram(sram, NULL, "ef405ep.sram", sram_size,
- &error_fatal);
- vmstate_register_ram_global(sram);
- memory_region_add_subregion(sysmem, 0xFFF00000, sram);
- /* allocate and load BIOS */
-#ifdef DEBUG_BOARD_INIT
- printf("%s: register BIOS\n", __func__);
-#endif
- fl_idx = 0;
-#ifdef USE_FLASH_BIOS
- dinfo = drive_get(IF_PFLASH, 0, fl_idx);
- if (dinfo) {
- BlockBackend *blk = blk_by_legacy_dinfo(dinfo);
-
- bios_size = blk_getlength(blk);
- fl_sectors = (bios_size + 65535) >> 16;
-#ifdef DEBUG_BOARD_INIT
- printf("Register parallel flash %d size %lx"
- " at addr %lx '%s' %d\n",
- fl_idx, bios_size, -bios_size,
- blk_name(blk), fl_sectors);
-#endif
- pflash_cfi02_register((uint32_t)(-bios_size),
- NULL, "ef405ep.bios", bios_size,
- blk, 65536, fl_sectors, 1,
- 2, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA,
- 1);
- fl_idx++;
- } else
-#endif
- {
-#ifdef DEBUG_BOARD_INIT
- printf("Load BIOS from file\n");
-#endif
- bios = g_new(MemoryRegion, 1);
- memory_region_init_ram(bios, NULL, "ef405ep.bios", BIOS_SIZE,
- &error_fatal);
- vmstate_register_ram_global(bios);
-
- if (bios_name == NULL)
- bios_name = BIOS_FILENAME;
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
- if (filename) {
- bios_size = load_image(filename, memory_region_get_ram_ptr(bios));
- g_free(filename);
- if (bios_size < 0 || bios_size > BIOS_SIZE) {
- error_report("Could not load PowerPC BIOS '%s'", bios_name);
- exit(1);
- }
- bios_size = (bios_size + 0xfff) & ~0xfff;
- memory_region_add_subregion(sysmem, (uint32_t)(-bios_size), bios);
- } else if (!qtest_enabled() || kernel_filename != NULL) {
- error_report("Could not load PowerPC BIOS '%s'", bios_name);
- exit(1);
- } else {
- /* Avoid an uninitialized variable warning */
- bios_size = -1;
- }
- memory_region_set_readonly(bios, true);
- }
- /* Register FPGA */
-#ifdef DEBUG_BOARD_INIT
- printf("%s: register FPGA\n", __func__);
-#endif
- ref405ep_fpga_init(sysmem, 0xF0300000);
- /* Register NVRAM */
-#ifdef DEBUG_BOARD_INIT
- printf("%s: register NVRAM\n", __func__);
-#endif
- m48t59_init(NULL, 0xF0000000, 0, 8192, 1968, 8);
- /* Load kernel */
- linux_boot = (kernel_filename != NULL);
- if (linux_boot) {
-#ifdef DEBUG_BOARD_INIT
- printf("%s: load kernel\n", __func__);
-#endif
- memset(&bd, 0, sizeof(bd));
- bd.bi_memstart = 0x00000000;
- bd.bi_memsize = ram_size;
- bd.bi_flashstart = -bios_size;
- bd.bi_flashsize = -bios_size;
- bd.bi_flashoffset = 0;
- bd.bi_sramstart = 0xFFF00000;
- bd.bi_sramsize = sram_size;
- bd.bi_bootflags = 0;
- bd.bi_intfreq = 133333333;
- bd.bi_busfreq = 33333333;
- bd.bi_baudrate = 115200;
- bd.bi_s_version[0] = 'Q';
- bd.bi_s_version[1] = 'M';
- bd.bi_s_version[2] = 'U';
- bd.bi_s_version[3] = '\0';
- bd.bi_r_version[0] = 'Q';
- bd.bi_r_version[1] = 'E';
- bd.bi_r_version[2] = 'M';
- bd.bi_r_version[3] = 'U';
- bd.bi_r_version[4] = '\0';
- bd.bi_procfreq = 133333333;
- bd.bi_plb_busfreq = 33333333;
- bd.bi_pci_busfreq = 33333333;
- bd.bi_opbfreq = 33333333;
- bdloc = ppc405_set_bootinfo(env, &bd, 0x00000001);
- env->gpr[3] = bdloc;
- kernel_base = KERNEL_LOAD_ADDR;
- /* now we can load the kernel */
- kernel_size = load_image_targphys(kernel_filename, kernel_base,
- ram_size - kernel_base);
- if (kernel_size < 0) {
- fprintf(stderr, "qemu: could not load kernel '%s'\n",
- kernel_filename);
- exit(1);
- }
- printf("Load kernel size %ld at " TARGET_FMT_lx,
- kernel_size, kernel_base);
- /* load initrd */
- if (initrd_filename) {
- initrd_base = INITRD_LOAD_ADDR;
- initrd_size = load_image_targphys(initrd_filename, initrd_base,
- ram_size - initrd_base);
- if (initrd_size < 0) {
- fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
- initrd_filename);
- exit(1);
- }
- } else {
- initrd_base = 0;
- initrd_size = 0;
- }
- env->gpr[4] = initrd_base;
- env->gpr[5] = initrd_size;
- if (kernel_cmdline != NULL) {
- len = strlen(kernel_cmdline);
- bdloc -= ((len + 255) & ~255);
- cpu_physical_memory_write(bdloc, kernel_cmdline, len + 1);
- env->gpr[6] = bdloc;
- env->gpr[7] = bdloc + len;
- } else {
- env->gpr[6] = 0;
- env->gpr[7] = 0;
- }
- env->nip = KERNEL_LOAD_ADDR;
- } else {
- kernel_base = 0;
- kernel_size = 0;
- initrd_base = 0;
- initrd_size = 0;
- bdloc = 0;
- }
-#ifdef DEBUG_BOARD_INIT
- printf("bdloc " RAM_ADDR_FMT "\n", bdloc);
- printf("%s: Done\n", __func__);
-#endif
-}
-
-static void ref405ep_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "ref405ep";
- mc->init = ref405ep_init;
-}
-
-static const TypeInfo ref405ep_type = {
- .name = MACHINE_TYPE_NAME("ref405ep"),
- .parent = TYPE_MACHINE,
- .class_init = ref405ep_class_init,
-};
-
-/*****************************************************************************/
-/* AMCC Taihu evaluation board */
-/* - PowerPC 405EP processor
- * - SDRAM 128 MB at 0x00000000
- * - Boot flash 2 MB at 0xFFE00000
- * - Application flash 32 MB at 0xFC000000
- * - 2 serial ports
- * - 2 ethernet PHY
- * - 1 USB 1.1 device 0x50000000
- * - 1 LCD display 0x50100000
- * - 1 CPLD 0x50100000
- * - 1 I2C EEPROM
- * - 1 I2C thermal sensor
- * - a set of LEDs
- * - bit-bang SPI port using GPIOs
- * - 1 EBC interface connector 0 0x50200000
- * - 1 cardbus controller + expansion slot.
- * - 1 PCI expansion slot.
- */
-typedef struct taihu_cpld_t taihu_cpld_t;
-struct taihu_cpld_t {
- uint8_t reg0;
- uint8_t reg1;
-};
-
-static uint64_t taihu_cpld_read(void *opaque, hwaddr addr, unsigned size)
-{
- taihu_cpld_t *cpld;
- uint32_t ret;
-
- cpld = opaque;
- switch (addr) {
- case 0x0:
- ret = cpld->reg0;
- break;
- case 0x1:
- ret = cpld->reg1;
- break;
- default:
- ret = 0;
- break;
- }
-
- return ret;
-}
-
-static void taihu_cpld_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- taihu_cpld_t *cpld;
-
- cpld = opaque;
- switch (addr) {
- case 0x0:
- /* Read only */
- break;
- case 0x1:
- cpld->reg1 = value;
- break;
- default:
- break;
- }
-}
-
-static const MemoryRegionOps taihu_cpld_ops = {
- .read = taihu_cpld_read,
- .write = taihu_cpld_write,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void taihu_cpld_reset (void *opaque)
-{
- taihu_cpld_t *cpld;
-
- cpld = opaque;
- cpld->reg0 = 0x01;
- cpld->reg1 = 0x80;
-}
-
-static void taihu_cpld_init(MemoryRegion *sysmem, uint32_t base)
-{
- taihu_cpld_t *cpld;
- MemoryRegion *cpld_memory = g_new(MemoryRegion, 1);
-
- cpld = g_malloc0(sizeof(taihu_cpld_t));
- memory_region_init_io(cpld_memory, NULL, &taihu_cpld_ops, cpld, "cpld", 0x100);
- memory_region_add_subregion(sysmem, base, cpld_memory);
- qemu_register_reset(&taihu_cpld_reset, cpld);
-}
-
-static void taihu_405ep_init(MachineState *machine)
-{
- ram_addr_t ram_size = machine->ram_size;
- const char *kernel_filename = machine->kernel_filename;
- const char *initrd_filename = machine->initrd_filename;
- char *filename;
- qemu_irq *pic;
- MemoryRegion *sysmem = get_system_memory();
- MemoryRegion *bios;
- MemoryRegion *ram_memories = g_malloc(2 * sizeof(*ram_memories));
- MemoryRegion *ram = g_malloc0(sizeof(*ram));
- hwaddr ram_bases[2], ram_sizes[2];
- long bios_size;
- target_ulong kernel_base, initrd_base;
- long kernel_size, initrd_size;
- int linux_boot;
- int fl_idx, fl_sectors;
- DriveInfo *dinfo;
-
- /* RAM is soldered to the board so the size cannot be changed */
- ram_size = 0x08000000;
- memory_region_allocate_system_memory(ram, NULL, "taihu_405ep.ram",
- ram_size);
-
- ram_bases[0] = 0;
- ram_sizes[0] = 0x04000000;
- memory_region_init_alias(&ram_memories[0], NULL,
- "taihu_405ep.ram-0", ram, ram_bases[0],
- ram_sizes[0]);
- ram_bases[1] = 0x04000000;
- ram_sizes[1] = 0x04000000;
- memory_region_init_alias(&ram_memories[1], NULL,
- "taihu_405ep.ram-1", ram, ram_bases[1],
- ram_sizes[1]);
-#ifdef DEBUG_BOARD_INIT
- printf("%s: register cpu\n", __func__);
-#endif
- ppc405ep_init(sysmem, ram_memories, ram_bases, ram_sizes,
- 33333333, &pic, kernel_filename == NULL ? 0 : 1);
- /* allocate and load BIOS */
-#ifdef DEBUG_BOARD_INIT
- printf("%s: register BIOS\n", __func__);
-#endif
- fl_idx = 0;
-#if defined(USE_FLASH_BIOS)
- dinfo = drive_get(IF_PFLASH, 0, fl_idx);
- if (dinfo) {
- BlockBackend *blk = blk_by_legacy_dinfo(dinfo);
-
- bios_size = blk_getlength(blk);
- /* XXX: should check that size is 2MB */
- // bios_size = 2 * 1024 * 1024;
- fl_sectors = (bios_size + 65535) >> 16;
-#ifdef DEBUG_BOARD_INIT
- printf("Register parallel flash %d size %lx"
- " at addr %lx '%s' %d\n",
- fl_idx, bios_size, -bios_size,
- blk_name(blk), fl_sectors);
-#endif
- pflash_cfi02_register((uint32_t)(-bios_size),
- NULL, "taihu_405ep.bios", bios_size,
- blk, 65536, fl_sectors, 1,
- 4, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA,
- 1);
- fl_idx++;
- } else
-#endif
- {
-#ifdef DEBUG_BOARD_INIT
- printf("Load BIOS from file\n");
-#endif
- if (bios_name == NULL)
- bios_name = BIOS_FILENAME;
- bios = g_new(MemoryRegion, 1);
- memory_region_init_ram(bios, NULL, "taihu_405ep.bios", BIOS_SIZE,
- &error_fatal);
- vmstate_register_ram_global(bios);
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
- if (filename) {
- bios_size = load_image(filename, memory_region_get_ram_ptr(bios));
- g_free(filename);
- if (bios_size < 0 || bios_size > BIOS_SIZE) {
- error_report("Could not load PowerPC BIOS '%s'", bios_name);
- exit(1);
- }
- bios_size = (bios_size + 0xfff) & ~0xfff;
- memory_region_add_subregion(sysmem, (uint32_t)(-bios_size), bios);
- } else if (!qtest_enabled()) {
- error_report("Could not load PowerPC BIOS '%s'", bios_name);
- exit(1);
- }
- memory_region_set_readonly(bios, true);
- }
- /* Register Linux flash */
- dinfo = drive_get(IF_PFLASH, 0, fl_idx);
- if (dinfo) {
- BlockBackend *blk = blk_by_legacy_dinfo(dinfo);
-
- bios_size = blk_getlength(blk);
- /* XXX: should check that size is 32MB */
- bios_size = 32 * 1024 * 1024;
- fl_sectors = (bios_size + 65535) >> 16;
-#ifdef DEBUG_BOARD_INIT
- printf("Register parallel flash %d size %lx"
- " at addr " TARGET_FMT_lx " '%s'\n",
- fl_idx, bios_size, (target_ulong)0xfc000000,
- blk_name(blk));
-#endif
- pflash_cfi02_register(0xfc000000, NULL, "taihu_405ep.flash", bios_size,
- blk, 65536, fl_sectors, 1,
- 4, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA,
- 1);
- fl_idx++;
- }
- /* Register CLPD & LCD display */
-#ifdef DEBUG_BOARD_INIT
- printf("%s: register CPLD\n", __func__);
-#endif
- taihu_cpld_init(sysmem, 0x50100000);
- /* Load kernel */
- linux_boot = (kernel_filename != NULL);
- if (linux_boot) {
-#ifdef DEBUG_BOARD_INIT
- printf("%s: load kernel\n", __func__);
-#endif
- kernel_base = KERNEL_LOAD_ADDR;
- /* now we can load the kernel */
- kernel_size = load_image_targphys(kernel_filename, kernel_base,
- ram_size - kernel_base);
- if (kernel_size < 0) {
- fprintf(stderr, "qemu: could not load kernel '%s'\n",
- kernel_filename);
- exit(1);
- }
- /* load initrd */
- if (initrd_filename) {
- initrd_base = INITRD_LOAD_ADDR;
- initrd_size = load_image_targphys(initrd_filename, initrd_base,
- ram_size - initrd_base);
- if (initrd_size < 0) {
- fprintf(stderr,
- "qemu: could not load initial ram disk '%s'\n",
- initrd_filename);
- exit(1);
- }
- } else {
- initrd_base = 0;
- initrd_size = 0;
- }
- } else {
- kernel_base = 0;
- kernel_size = 0;
- initrd_base = 0;
- initrd_size = 0;
- }
-#ifdef DEBUG_BOARD_INIT
- printf("%s: Done\n", __func__);
-#endif
-}
-
-static void taihu_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "taihu";
- mc->init = taihu_405ep_init;
-}
-
-static const TypeInfo taihu_type = {
- .name = MACHINE_TYPE_NAME("taihu"),
- .parent = TYPE_MACHINE,
- .class_init = taihu_class_init,
-};
-
-static void ppc405_machine_init(void)
-{
- type_register_static(&ref405ep_type);
- type_register_static(&taihu_type);
-}
-
-type_init(ppc405_machine_init)
diff --git a/qemu/hw/ppc/ppc405_uc.c b/qemu/hw/ppc/ppc405_uc.c
deleted file mode 100644
index d6d3fc2c4..000000000
--- a/qemu/hw/ppc/ppc405_uc.c
+++ /dev/null
@@ -1,2555 +0,0 @@
-/*
- * QEMU PowerPC 405 embedded processors emulation
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/hw.h"
-#include "hw/ppc/ppc.h"
-#include "hw/boards.h"
-#include "ppc405.h"
-#include "hw/char/serial.h"
-#include "qemu/timer.h"
-#include "sysemu/sysemu.h"
-#include "qemu/log.h"
-#include "exec/address-spaces.h"
-
-//#define DEBUG_OPBA
-//#define DEBUG_SDRAM
-//#define DEBUG_GPIO
-//#define DEBUG_SERIAL
-//#define DEBUG_OCM
-//#define DEBUG_I2C
-//#define DEBUG_GPT
-//#define DEBUG_MAL
-//#define DEBUG_CLOCKS
-//#define DEBUG_CLOCKS_LL
-
-ram_addr_t ppc405_set_bootinfo (CPUPPCState *env, ppc4xx_bd_info_t *bd,
- uint32_t flags)
-{
- CPUState *cs = CPU(ppc_env_get_cpu(env));
- ram_addr_t bdloc;
- int i, n;
-
- /* We put the bd structure at the top of memory */
- if (bd->bi_memsize >= 0x01000000UL)
- bdloc = 0x01000000UL - sizeof(struct ppc4xx_bd_info_t);
- else
- bdloc = bd->bi_memsize - sizeof(struct ppc4xx_bd_info_t);
- stl_be_phys(cs->as, bdloc + 0x00, bd->bi_memstart);
- stl_be_phys(cs->as, bdloc + 0x04, bd->bi_memsize);
- stl_be_phys(cs->as, bdloc + 0x08, bd->bi_flashstart);
- stl_be_phys(cs->as, bdloc + 0x0C, bd->bi_flashsize);
- stl_be_phys(cs->as, bdloc + 0x10, bd->bi_flashoffset);
- stl_be_phys(cs->as, bdloc + 0x14, bd->bi_sramstart);
- stl_be_phys(cs->as, bdloc + 0x18, bd->bi_sramsize);
- stl_be_phys(cs->as, bdloc + 0x1C, bd->bi_bootflags);
- stl_be_phys(cs->as, bdloc + 0x20, bd->bi_ipaddr);
- for (i = 0; i < 6; i++) {
- stb_phys(cs->as, bdloc + 0x24 + i, bd->bi_enetaddr[i]);
- }
- stw_be_phys(cs->as, bdloc + 0x2A, bd->bi_ethspeed);
- stl_be_phys(cs->as, bdloc + 0x2C, bd->bi_intfreq);
- stl_be_phys(cs->as, bdloc + 0x30, bd->bi_busfreq);
- stl_be_phys(cs->as, bdloc + 0x34, bd->bi_baudrate);
- for (i = 0; i < 4; i++) {
- stb_phys(cs->as, bdloc + 0x38 + i, bd->bi_s_version[i]);
- }
- for (i = 0; i < 32; i++) {
- stb_phys(cs->as, bdloc + 0x3C + i, bd->bi_r_version[i]);
- }
- stl_be_phys(cs->as, bdloc + 0x5C, bd->bi_plb_busfreq);
- stl_be_phys(cs->as, bdloc + 0x60, bd->bi_pci_busfreq);
- for (i = 0; i < 6; i++) {
- stb_phys(cs->as, bdloc + 0x64 + i, bd->bi_pci_enetaddr[i]);
- }
- n = 0x6A;
- if (flags & 0x00000001) {
- for (i = 0; i < 6; i++)
- stb_phys(cs->as, bdloc + n++, bd->bi_pci_enetaddr2[i]);
- }
- stl_be_phys(cs->as, bdloc + n, bd->bi_opbfreq);
- n += 4;
- for (i = 0; i < 2; i++) {
- stl_be_phys(cs->as, bdloc + n, bd->bi_iic_fast[i]);
- n += 4;
- }
-
- return bdloc;
-}
-
-/*****************************************************************************/
-/* Shared peripherals */
-
-/*****************************************************************************/
-/* Peripheral local bus arbitrer */
-enum {
- PLB0_BESR = 0x084,
- PLB0_BEAR = 0x086,
- PLB0_ACR = 0x087,
-};
-
-typedef struct ppc4xx_plb_t ppc4xx_plb_t;
-struct ppc4xx_plb_t {
- uint32_t acr;
- uint32_t bear;
- uint32_t besr;
-};
-
-static uint32_t dcr_read_plb (void *opaque, int dcrn)
-{
- ppc4xx_plb_t *plb;
- uint32_t ret;
-
- plb = opaque;
- switch (dcrn) {
- case PLB0_ACR:
- ret = plb->acr;
- break;
- case PLB0_BEAR:
- ret = plb->bear;
- break;
- case PLB0_BESR:
- ret = plb->besr;
- break;
- default:
- /* Avoid gcc warning */
- ret = 0;
- break;
- }
-
- return ret;
-}
-
-static void dcr_write_plb (void *opaque, int dcrn, uint32_t val)
-{
- ppc4xx_plb_t *plb;
-
- plb = opaque;
- switch (dcrn) {
- case PLB0_ACR:
- /* We don't care about the actual parameters written as
- * we don't manage any priorities on the bus
- */
- plb->acr = val & 0xF8000000;
- break;
- case PLB0_BEAR:
- /* Read only */
- break;
- case PLB0_BESR:
- /* Write-clear */
- plb->besr &= ~val;
- break;
- }
-}
-
-static void ppc4xx_plb_reset (void *opaque)
-{
- ppc4xx_plb_t *plb;
-
- plb = opaque;
- plb->acr = 0x00000000;
- plb->bear = 0x00000000;
- plb->besr = 0x00000000;
-}
-
-static void ppc4xx_plb_init(CPUPPCState *env)
-{
- ppc4xx_plb_t *plb;
-
- plb = g_malloc0(sizeof(ppc4xx_plb_t));
- ppc_dcr_register(env, PLB0_ACR, plb, &dcr_read_plb, &dcr_write_plb);
- ppc_dcr_register(env, PLB0_BEAR, plb, &dcr_read_plb, &dcr_write_plb);
- ppc_dcr_register(env, PLB0_BESR, plb, &dcr_read_plb, &dcr_write_plb);
- qemu_register_reset(ppc4xx_plb_reset, plb);
-}
-
-/*****************************************************************************/
-/* PLB to OPB bridge */
-enum {
- POB0_BESR0 = 0x0A0,
- POB0_BESR1 = 0x0A2,
- POB0_BEAR = 0x0A4,
-};
-
-typedef struct ppc4xx_pob_t ppc4xx_pob_t;
-struct ppc4xx_pob_t {
- uint32_t bear;
- uint32_t besr0;
- uint32_t besr1;
-};
-
-static uint32_t dcr_read_pob (void *opaque, int dcrn)
-{
- ppc4xx_pob_t *pob;
- uint32_t ret;
-
- pob = opaque;
- switch (dcrn) {
- case POB0_BEAR:
- ret = pob->bear;
- break;
- case POB0_BESR0:
- ret = pob->besr0;
- break;
- case POB0_BESR1:
- ret = pob->besr1;
- break;
- default:
- /* Avoid gcc warning */
- ret = 0;
- break;
- }
-
- return ret;
-}
-
-static void dcr_write_pob (void *opaque, int dcrn, uint32_t val)
-{
- ppc4xx_pob_t *pob;
-
- pob = opaque;
- switch (dcrn) {
- case POB0_BEAR:
- /* Read only */
- break;
- case POB0_BESR0:
- /* Write-clear */
- pob->besr0 &= ~val;
- break;
- case POB0_BESR1:
- /* Write-clear */
- pob->besr1 &= ~val;
- break;
- }
-}
-
-static void ppc4xx_pob_reset (void *opaque)
-{
- ppc4xx_pob_t *pob;
-
- pob = opaque;
- /* No error */
- pob->bear = 0x00000000;
- pob->besr0 = 0x0000000;
- pob->besr1 = 0x0000000;
-}
-
-static void ppc4xx_pob_init(CPUPPCState *env)
-{
- ppc4xx_pob_t *pob;
-
- pob = g_malloc0(sizeof(ppc4xx_pob_t));
- ppc_dcr_register(env, POB0_BEAR, pob, &dcr_read_pob, &dcr_write_pob);
- ppc_dcr_register(env, POB0_BESR0, pob, &dcr_read_pob, &dcr_write_pob);
- ppc_dcr_register(env, POB0_BESR1, pob, &dcr_read_pob, &dcr_write_pob);
- qemu_register_reset(ppc4xx_pob_reset, pob);
-}
-
-/*****************************************************************************/
-/* OPB arbitrer */
-typedef struct ppc4xx_opba_t ppc4xx_opba_t;
-struct ppc4xx_opba_t {
- MemoryRegion io;
- uint8_t cr;
- uint8_t pr;
-};
-
-static uint32_t opba_readb (void *opaque, hwaddr addr)
-{
- ppc4xx_opba_t *opba;
- uint32_t ret;
-
-#ifdef DEBUG_OPBA
- printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
-#endif
- opba = opaque;
- switch (addr) {
- case 0x00:
- ret = opba->cr;
- break;
- case 0x01:
- ret = opba->pr;
- break;
- default:
- ret = 0x00;
- break;
- }
-
- return ret;
-}
-
-static void opba_writeb (void *opaque,
- hwaddr addr, uint32_t value)
-{
- ppc4xx_opba_t *opba;
-
-#ifdef DEBUG_OPBA
- printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
- value);
-#endif
- opba = opaque;
- switch (addr) {
- case 0x00:
- opba->cr = value & 0xF8;
- break;
- case 0x01:
- opba->pr = value & 0xFF;
- break;
- default:
- break;
- }
-}
-
-static uint32_t opba_readw (void *opaque, hwaddr addr)
-{
- uint32_t ret;
-
-#ifdef DEBUG_OPBA
- printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
-#endif
- ret = opba_readb(opaque, addr) << 8;
- ret |= opba_readb(opaque, addr + 1);
-
- return ret;
-}
-
-static void opba_writew (void *opaque,
- hwaddr addr, uint32_t value)
-{
-#ifdef DEBUG_OPBA
- printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
- value);
-#endif
- opba_writeb(opaque, addr, value >> 8);
- opba_writeb(opaque, addr + 1, value);
-}
-
-static uint32_t opba_readl (void *opaque, hwaddr addr)
-{
- uint32_t ret;
-
-#ifdef DEBUG_OPBA
- printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
-#endif
- ret = opba_readb(opaque, addr) << 24;
- ret |= opba_readb(opaque, addr + 1) << 16;
-
- return ret;
-}
-
-static void opba_writel (void *opaque,
- hwaddr addr, uint32_t value)
-{
-#ifdef DEBUG_OPBA
- printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
- value);
-#endif
- opba_writeb(opaque, addr, value >> 24);
- opba_writeb(opaque, addr + 1, value >> 16);
-}
-
-static const MemoryRegionOps opba_ops = {
- .old_mmio = {
- .read = { opba_readb, opba_readw, opba_readl, },
- .write = { opba_writeb, opba_writew, opba_writel, },
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void ppc4xx_opba_reset (void *opaque)
-{
- ppc4xx_opba_t *opba;
-
- opba = opaque;
- opba->cr = 0x00; /* No dynamic priorities - park disabled */
- opba->pr = 0x11;
-}
-
-static void ppc4xx_opba_init(hwaddr base)
-{
- ppc4xx_opba_t *opba;
-
- opba = g_malloc0(sizeof(ppc4xx_opba_t));
-#ifdef DEBUG_OPBA
- printf("%s: offset " TARGET_FMT_plx "\n", __func__, base);
-#endif
- memory_region_init_io(&opba->io, NULL, &opba_ops, opba, "opba", 0x002);
- memory_region_add_subregion(get_system_memory(), base, &opba->io);
- qemu_register_reset(ppc4xx_opba_reset, opba);
-}
-
-/*****************************************************************************/
-/* Code decompression controller */
-/* XXX: TODO */
-
-/*****************************************************************************/
-/* Peripheral controller */
-typedef struct ppc4xx_ebc_t ppc4xx_ebc_t;
-struct ppc4xx_ebc_t {
- uint32_t addr;
- uint32_t bcr[8];
- uint32_t bap[8];
- uint32_t bear;
- uint32_t besr0;
- uint32_t besr1;
- uint32_t cfg;
-};
-
-enum {
- EBC0_CFGADDR = 0x012,
- EBC0_CFGDATA = 0x013,
-};
-
-static uint32_t dcr_read_ebc (void *opaque, int dcrn)
-{
- ppc4xx_ebc_t *ebc;
- uint32_t ret;
-
- ebc = opaque;
- switch (dcrn) {
- case EBC0_CFGADDR:
- ret = ebc->addr;
- break;
- case EBC0_CFGDATA:
- switch (ebc->addr) {
- case 0x00: /* B0CR */
- ret = ebc->bcr[0];
- break;
- case 0x01: /* B1CR */
- ret = ebc->bcr[1];
- break;
- case 0x02: /* B2CR */
- ret = ebc->bcr[2];
- break;
- case 0x03: /* B3CR */
- ret = ebc->bcr[3];
- break;
- case 0x04: /* B4CR */
- ret = ebc->bcr[4];
- break;
- case 0x05: /* B5CR */
- ret = ebc->bcr[5];
- break;
- case 0x06: /* B6CR */
- ret = ebc->bcr[6];
- break;
- case 0x07: /* B7CR */
- ret = ebc->bcr[7];
- break;
- case 0x10: /* B0AP */
- ret = ebc->bap[0];
- break;
- case 0x11: /* B1AP */
- ret = ebc->bap[1];
- break;
- case 0x12: /* B2AP */
- ret = ebc->bap[2];
- break;
- case 0x13: /* B3AP */
- ret = ebc->bap[3];
- break;
- case 0x14: /* B4AP */
- ret = ebc->bap[4];
- break;
- case 0x15: /* B5AP */
- ret = ebc->bap[5];
- break;
- case 0x16: /* B6AP */
- ret = ebc->bap[6];
- break;
- case 0x17: /* B7AP */
- ret = ebc->bap[7];
- break;
- case 0x20: /* BEAR */
- ret = ebc->bear;
- break;
- case 0x21: /* BESR0 */
- ret = ebc->besr0;
- break;
- case 0x22: /* BESR1 */
- ret = ebc->besr1;
- break;
- case 0x23: /* CFG */
- ret = ebc->cfg;
- break;
- default:
- ret = 0x00000000;
- break;
- }
- break;
- default:
- ret = 0x00000000;
- break;
- }
-
- return ret;
-}
-
-static void dcr_write_ebc (void *opaque, int dcrn, uint32_t val)
-{
- ppc4xx_ebc_t *ebc;
-
- ebc = opaque;
- switch (dcrn) {
- case EBC0_CFGADDR:
- ebc->addr = val;
- break;
- case EBC0_CFGDATA:
- switch (ebc->addr) {
- case 0x00: /* B0CR */
- break;
- case 0x01: /* B1CR */
- break;
- case 0x02: /* B2CR */
- break;
- case 0x03: /* B3CR */
- break;
- case 0x04: /* B4CR */
- break;
- case 0x05: /* B5CR */
- break;
- case 0x06: /* B6CR */
- break;
- case 0x07: /* B7CR */
- break;
- case 0x10: /* B0AP */
- break;
- case 0x11: /* B1AP */
- break;
- case 0x12: /* B2AP */
- break;
- case 0x13: /* B3AP */
- break;
- case 0x14: /* B4AP */
- break;
- case 0x15: /* B5AP */
- break;
- case 0x16: /* B6AP */
- break;
- case 0x17: /* B7AP */
- break;
- case 0x20: /* BEAR */
- break;
- case 0x21: /* BESR0 */
- break;
- case 0x22: /* BESR1 */
- break;
- case 0x23: /* CFG */
- break;
- default:
- break;
- }
- break;
- default:
- break;
- }
-}
-
-static void ebc_reset (void *opaque)
-{
- ppc4xx_ebc_t *ebc;
- int i;
-
- ebc = opaque;
- ebc->addr = 0x00000000;
- ebc->bap[0] = 0x7F8FFE80;
- ebc->bcr[0] = 0xFFE28000;
- for (i = 0; i < 8; i++) {
- ebc->bap[i] = 0x00000000;
- ebc->bcr[i] = 0x00000000;
- }
- ebc->besr0 = 0x00000000;
- ebc->besr1 = 0x00000000;
- ebc->cfg = 0x80400000;
-}
-
-static void ppc405_ebc_init(CPUPPCState *env)
-{
- ppc4xx_ebc_t *ebc;
-
- ebc = g_malloc0(sizeof(ppc4xx_ebc_t));
- qemu_register_reset(&ebc_reset, ebc);
- ppc_dcr_register(env, EBC0_CFGADDR,
- ebc, &dcr_read_ebc, &dcr_write_ebc);
- ppc_dcr_register(env, EBC0_CFGDATA,
- ebc, &dcr_read_ebc, &dcr_write_ebc);
-}
-
-/*****************************************************************************/
-/* DMA controller */
-enum {
- DMA0_CR0 = 0x100,
- DMA0_CT0 = 0x101,
- DMA0_DA0 = 0x102,
- DMA0_SA0 = 0x103,
- DMA0_SG0 = 0x104,
- DMA0_CR1 = 0x108,
- DMA0_CT1 = 0x109,
- DMA0_DA1 = 0x10A,
- DMA0_SA1 = 0x10B,
- DMA0_SG1 = 0x10C,
- DMA0_CR2 = 0x110,
- DMA0_CT2 = 0x111,
- DMA0_DA2 = 0x112,
- DMA0_SA2 = 0x113,
- DMA0_SG2 = 0x114,
- DMA0_CR3 = 0x118,
- DMA0_CT3 = 0x119,
- DMA0_DA3 = 0x11A,
- DMA0_SA3 = 0x11B,
- DMA0_SG3 = 0x11C,
- DMA0_SR = 0x120,
- DMA0_SGC = 0x123,
- DMA0_SLP = 0x125,
- DMA0_POL = 0x126,
-};
-
-typedef struct ppc405_dma_t ppc405_dma_t;
-struct ppc405_dma_t {
- qemu_irq irqs[4];
- uint32_t cr[4];
- uint32_t ct[4];
- uint32_t da[4];
- uint32_t sa[4];
- uint32_t sg[4];
- uint32_t sr;
- uint32_t sgc;
- uint32_t slp;
- uint32_t pol;
-};
-
-static uint32_t dcr_read_dma (void *opaque, int dcrn)
-{
- return 0;
-}
-
-static void dcr_write_dma (void *opaque, int dcrn, uint32_t val)
-{
-}
-
-static void ppc405_dma_reset (void *opaque)
-{
- ppc405_dma_t *dma;
- int i;
-
- dma = opaque;
- for (i = 0; i < 4; i++) {
- dma->cr[i] = 0x00000000;
- dma->ct[i] = 0x00000000;
- dma->da[i] = 0x00000000;
- dma->sa[i] = 0x00000000;
- dma->sg[i] = 0x00000000;
- }
- dma->sr = 0x00000000;
- dma->sgc = 0x00000000;
- dma->slp = 0x7C000000;
- dma->pol = 0x00000000;
-}
-
-static void ppc405_dma_init(CPUPPCState *env, qemu_irq irqs[4])
-{
- ppc405_dma_t *dma;
-
- dma = g_malloc0(sizeof(ppc405_dma_t));
- memcpy(dma->irqs, irqs, 4 * sizeof(qemu_irq));
- qemu_register_reset(&ppc405_dma_reset, dma);
- ppc_dcr_register(env, DMA0_CR0,
- dma, &dcr_read_dma, &dcr_write_dma);
- ppc_dcr_register(env, DMA0_CT0,
- dma, &dcr_read_dma, &dcr_write_dma);
- ppc_dcr_register(env, DMA0_DA0,
- dma, &dcr_read_dma, &dcr_write_dma);
- ppc_dcr_register(env, DMA0_SA0,
- dma, &dcr_read_dma, &dcr_write_dma);
- ppc_dcr_register(env, DMA0_SG0,
- dma, &dcr_read_dma, &dcr_write_dma);
- ppc_dcr_register(env, DMA0_CR1,
- dma, &dcr_read_dma, &dcr_write_dma);
- ppc_dcr_register(env, DMA0_CT1,
- dma, &dcr_read_dma, &dcr_write_dma);
- ppc_dcr_register(env, DMA0_DA1,
- dma, &dcr_read_dma, &dcr_write_dma);
- ppc_dcr_register(env, DMA0_SA1,
- dma, &dcr_read_dma, &dcr_write_dma);
- ppc_dcr_register(env, DMA0_SG1,
- dma, &dcr_read_dma, &dcr_write_dma);
- ppc_dcr_register(env, DMA0_CR2,
- dma, &dcr_read_dma, &dcr_write_dma);
- ppc_dcr_register(env, DMA0_CT2,
- dma, &dcr_read_dma, &dcr_write_dma);
- ppc_dcr_register(env, DMA0_DA2,
- dma, &dcr_read_dma, &dcr_write_dma);
- ppc_dcr_register(env, DMA0_SA2,
- dma, &dcr_read_dma, &dcr_write_dma);
- ppc_dcr_register(env, DMA0_SG2,
- dma, &dcr_read_dma, &dcr_write_dma);
- ppc_dcr_register(env, DMA0_CR3,
- dma, &dcr_read_dma, &dcr_write_dma);
- ppc_dcr_register(env, DMA0_CT3,
- dma, &dcr_read_dma, &dcr_write_dma);
- ppc_dcr_register(env, DMA0_DA3,
- dma, &dcr_read_dma, &dcr_write_dma);
- ppc_dcr_register(env, DMA0_SA3,
- dma, &dcr_read_dma, &dcr_write_dma);
- ppc_dcr_register(env, DMA0_SG3,
- dma, &dcr_read_dma, &dcr_write_dma);
- ppc_dcr_register(env, DMA0_SR,
- dma, &dcr_read_dma, &dcr_write_dma);
- ppc_dcr_register(env, DMA0_SGC,
- dma, &dcr_read_dma, &dcr_write_dma);
- ppc_dcr_register(env, DMA0_SLP,
- dma, &dcr_read_dma, &dcr_write_dma);
- ppc_dcr_register(env, DMA0_POL,
- dma, &dcr_read_dma, &dcr_write_dma);
-}
-
-/*****************************************************************************/
-/* GPIO */
-typedef struct ppc405_gpio_t ppc405_gpio_t;
-struct ppc405_gpio_t {
- MemoryRegion io;
- uint32_t or;
- uint32_t tcr;
- uint32_t osrh;
- uint32_t osrl;
- uint32_t tsrh;
- uint32_t tsrl;
- uint32_t odr;
- uint32_t ir;
- uint32_t rr1;
- uint32_t isr1h;
- uint32_t isr1l;
-};
-
-static uint32_t ppc405_gpio_readb (void *opaque, hwaddr addr)
-{
-#ifdef DEBUG_GPIO
- printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
-#endif
-
- return 0;
-}
-
-static void ppc405_gpio_writeb (void *opaque,
- hwaddr addr, uint32_t value)
-{
-#ifdef DEBUG_GPIO
- printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
- value);
-#endif
-}
-
-static uint32_t ppc405_gpio_readw (void *opaque, hwaddr addr)
-{
-#ifdef DEBUG_GPIO
- printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
-#endif
-
- return 0;
-}
-
-static void ppc405_gpio_writew (void *opaque,
- hwaddr addr, uint32_t value)
-{
-#ifdef DEBUG_GPIO
- printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
- value);
-#endif
-}
-
-static uint32_t ppc405_gpio_readl (void *opaque, hwaddr addr)
-{
-#ifdef DEBUG_GPIO
- printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
-#endif
-
- return 0;
-}
-
-static void ppc405_gpio_writel (void *opaque,
- hwaddr addr, uint32_t value)
-{
-#ifdef DEBUG_GPIO
- printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
- value);
-#endif
-}
-
-static const MemoryRegionOps ppc405_gpio_ops = {
- .old_mmio = {
- .read = { ppc405_gpio_readb, ppc405_gpio_readw, ppc405_gpio_readl, },
- .write = { ppc405_gpio_writeb, ppc405_gpio_writew, ppc405_gpio_writel, },
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void ppc405_gpio_reset (void *opaque)
-{
-}
-
-static void ppc405_gpio_init(hwaddr base)
-{
- ppc405_gpio_t *gpio;
-
- gpio = g_malloc0(sizeof(ppc405_gpio_t));
-#ifdef DEBUG_GPIO
- printf("%s: offset " TARGET_FMT_plx "\n", __func__, base);
-#endif
- memory_region_init_io(&gpio->io, NULL, &ppc405_gpio_ops, gpio, "pgio", 0x038);
- memory_region_add_subregion(get_system_memory(), base, &gpio->io);
- qemu_register_reset(&ppc405_gpio_reset, gpio);
-}
-
-/*****************************************************************************/
-/* On Chip Memory */
-enum {
- OCM0_ISARC = 0x018,
- OCM0_ISACNTL = 0x019,
- OCM0_DSARC = 0x01A,
- OCM0_DSACNTL = 0x01B,
-};
-
-typedef struct ppc405_ocm_t ppc405_ocm_t;
-struct ppc405_ocm_t {
- MemoryRegion ram;
- MemoryRegion isarc_ram;
- MemoryRegion dsarc_ram;
- uint32_t isarc;
- uint32_t isacntl;
- uint32_t dsarc;
- uint32_t dsacntl;
-};
-
-static void ocm_update_mappings (ppc405_ocm_t *ocm,
- uint32_t isarc, uint32_t isacntl,
- uint32_t dsarc, uint32_t dsacntl)
-{
-#ifdef DEBUG_OCM
- printf("OCM update ISA %08" PRIx32 " %08" PRIx32 " (%08" PRIx32
- " %08" PRIx32 ") DSA %08" PRIx32 " %08" PRIx32
- " (%08" PRIx32 " %08" PRIx32 ")\n",
- isarc, isacntl, dsarc, dsacntl,
- ocm->isarc, ocm->isacntl, ocm->dsarc, ocm->dsacntl);
-#endif
- if (ocm->isarc != isarc ||
- (ocm->isacntl & 0x80000000) != (isacntl & 0x80000000)) {
- if (ocm->isacntl & 0x80000000) {
- /* Unmap previously assigned memory region */
- printf("OCM unmap ISA %08" PRIx32 "\n", ocm->isarc);
- memory_region_del_subregion(get_system_memory(), &ocm->isarc_ram);
- }
- if (isacntl & 0x80000000) {
- /* Map new instruction memory region */
-#ifdef DEBUG_OCM
- printf("OCM map ISA %08" PRIx32 "\n", isarc);
-#endif
- memory_region_add_subregion(get_system_memory(), isarc,
- &ocm->isarc_ram);
- }
- }
- if (ocm->dsarc != dsarc ||
- (ocm->dsacntl & 0x80000000) != (dsacntl & 0x80000000)) {
- if (ocm->dsacntl & 0x80000000) {
- /* Beware not to unmap the region we just mapped */
- if (!(isacntl & 0x80000000) || ocm->dsarc != isarc) {
- /* Unmap previously assigned memory region */
-#ifdef DEBUG_OCM
- printf("OCM unmap DSA %08" PRIx32 "\n", ocm->dsarc);
-#endif
- memory_region_del_subregion(get_system_memory(),
- &ocm->dsarc_ram);
- }
- }
- if (dsacntl & 0x80000000) {
- /* Beware not to remap the region we just mapped */
- if (!(isacntl & 0x80000000) || dsarc != isarc) {
- /* Map new data memory region */
-#ifdef DEBUG_OCM
- printf("OCM map DSA %08" PRIx32 "\n", dsarc);
-#endif
- memory_region_add_subregion(get_system_memory(), dsarc,
- &ocm->dsarc_ram);
- }
- }
- }
-}
-
-static uint32_t dcr_read_ocm (void *opaque, int dcrn)
-{
- ppc405_ocm_t *ocm;
- uint32_t ret;
-
- ocm = opaque;
- switch (dcrn) {
- case OCM0_ISARC:
- ret = ocm->isarc;
- break;
- case OCM0_ISACNTL:
- ret = ocm->isacntl;
- break;
- case OCM0_DSARC:
- ret = ocm->dsarc;
- break;
- case OCM0_DSACNTL:
- ret = ocm->dsacntl;
- break;
- default:
- ret = 0;
- break;
- }
-
- return ret;
-}
-
-static void dcr_write_ocm (void *opaque, int dcrn, uint32_t val)
-{
- ppc405_ocm_t *ocm;
- uint32_t isarc, dsarc, isacntl, dsacntl;
-
- ocm = opaque;
- isarc = ocm->isarc;
- dsarc = ocm->dsarc;
- isacntl = ocm->isacntl;
- dsacntl = ocm->dsacntl;
- switch (dcrn) {
- case OCM0_ISARC:
- isarc = val & 0xFC000000;
- break;
- case OCM0_ISACNTL:
- isacntl = val & 0xC0000000;
- break;
- case OCM0_DSARC:
- isarc = val & 0xFC000000;
- break;
- case OCM0_DSACNTL:
- isacntl = val & 0xC0000000;
- break;
- }
- ocm_update_mappings(ocm, isarc, isacntl, dsarc, dsacntl);
- ocm->isarc = isarc;
- ocm->dsarc = dsarc;
- ocm->isacntl = isacntl;
- ocm->dsacntl = dsacntl;
-}
-
-static void ocm_reset (void *opaque)
-{
- ppc405_ocm_t *ocm;
- uint32_t isarc, dsarc, isacntl, dsacntl;
-
- ocm = opaque;
- isarc = 0x00000000;
- isacntl = 0x00000000;
- dsarc = 0x00000000;
- dsacntl = 0x00000000;
- ocm_update_mappings(ocm, isarc, isacntl, dsarc, dsacntl);
- ocm->isarc = isarc;
- ocm->dsarc = dsarc;
- ocm->isacntl = isacntl;
- ocm->dsacntl = dsacntl;
-}
-
-static void ppc405_ocm_init(CPUPPCState *env)
-{
- ppc405_ocm_t *ocm;
-
- ocm = g_malloc0(sizeof(ppc405_ocm_t));
- /* XXX: Size is 4096 or 0x04000000 */
- memory_region_init_ram(&ocm->isarc_ram, NULL, "ppc405.ocm", 4096,
- &error_fatal);
- vmstate_register_ram_global(&ocm->isarc_ram);
- memory_region_init_alias(&ocm->dsarc_ram, NULL, "ppc405.dsarc", &ocm->isarc_ram,
- 0, 4096);
- qemu_register_reset(&ocm_reset, ocm);
- ppc_dcr_register(env, OCM0_ISARC,
- ocm, &dcr_read_ocm, &dcr_write_ocm);
- ppc_dcr_register(env, OCM0_ISACNTL,
- ocm, &dcr_read_ocm, &dcr_write_ocm);
- ppc_dcr_register(env, OCM0_DSARC,
- ocm, &dcr_read_ocm, &dcr_write_ocm);
- ppc_dcr_register(env, OCM0_DSACNTL,
- ocm, &dcr_read_ocm, &dcr_write_ocm);
-}
-
-/*****************************************************************************/
-/* I2C controller */
-typedef struct ppc4xx_i2c_t ppc4xx_i2c_t;
-struct ppc4xx_i2c_t {
- qemu_irq irq;
- MemoryRegion iomem;
- uint8_t mdata;
- uint8_t lmadr;
- uint8_t hmadr;
- uint8_t cntl;
- uint8_t mdcntl;
- uint8_t sts;
- uint8_t extsts;
- uint8_t sdata;
- uint8_t lsadr;
- uint8_t hsadr;
- uint8_t clkdiv;
- uint8_t intrmsk;
- uint8_t xfrcnt;
- uint8_t xtcntlss;
- uint8_t directcntl;
-};
-
-static uint32_t ppc4xx_i2c_readb (void *opaque, hwaddr addr)
-{
- ppc4xx_i2c_t *i2c;
- uint32_t ret;
-
-#ifdef DEBUG_I2C
- printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
-#endif
- i2c = opaque;
- switch (addr) {
- case 0x00:
- // i2c_readbyte(&i2c->mdata);
- ret = i2c->mdata;
- break;
- case 0x02:
- ret = i2c->sdata;
- break;
- case 0x04:
- ret = i2c->lmadr;
- break;
- case 0x05:
- ret = i2c->hmadr;
- break;
- case 0x06:
- ret = i2c->cntl;
- break;
- case 0x07:
- ret = i2c->mdcntl;
- break;
- case 0x08:
- ret = i2c->sts;
- break;
- case 0x09:
- ret = i2c->extsts;
- break;
- case 0x0A:
- ret = i2c->lsadr;
- break;
- case 0x0B:
- ret = i2c->hsadr;
- break;
- case 0x0C:
- ret = i2c->clkdiv;
- break;
- case 0x0D:
- ret = i2c->intrmsk;
- break;
- case 0x0E:
- ret = i2c->xfrcnt;
- break;
- case 0x0F:
- ret = i2c->xtcntlss;
- break;
- case 0x10:
- ret = i2c->directcntl;
- break;
- default:
- ret = 0x00;
- break;
- }
-#ifdef DEBUG_I2C
- printf("%s: addr " TARGET_FMT_plx " %02" PRIx32 "\n", __func__, addr, ret);
-#endif
-
- return ret;
-}
-
-static void ppc4xx_i2c_writeb (void *opaque,
- hwaddr addr, uint32_t value)
-{
- ppc4xx_i2c_t *i2c;
-
-#ifdef DEBUG_I2C
- printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
- value);
-#endif
- i2c = opaque;
- switch (addr) {
- case 0x00:
- i2c->mdata = value;
- // i2c_sendbyte(&i2c->mdata);
- break;
- case 0x02:
- i2c->sdata = value;
- break;
- case 0x04:
- i2c->lmadr = value;
- break;
- case 0x05:
- i2c->hmadr = value;
- break;
- case 0x06:
- i2c->cntl = value;
- break;
- case 0x07:
- i2c->mdcntl = value & 0xDF;
- break;
- case 0x08:
- i2c->sts &= ~(value & 0x0A);
- break;
- case 0x09:
- i2c->extsts &= ~(value & 0x8F);
- break;
- case 0x0A:
- i2c->lsadr = value;
- break;
- case 0x0B:
- i2c->hsadr = value;
- break;
- case 0x0C:
- i2c->clkdiv = value;
- break;
- case 0x0D:
- i2c->intrmsk = value;
- break;
- case 0x0E:
- i2c->xfrcnt = value & 0x77;
- break;
- case 0x0F:
- i2c->xtcntlss = value;
- break;
- case 0x10:
- i2c->directcntl = value & 0x7;
- break;
- }
-}
-
-static uint32_t ppc4xx_i2c_readw (void *opaque, hwaddr addr)
-{
- uint32_t ret;
-
-#ifdef DEBUG_I2C
- printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
-#endif
- ret = ppc4xx_i2c_readb(opaque, addr) << 8;
- ret |= ppc4xx_i2c_readb(opaque, addr + 1);
-
- return ret;
-}
-
-static void ppc4xx_i2c_writew (void *opaque,
- hwaddr addr, uint32_t value)
-{
-#ifdef DEBUG_I2C
- printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
- value);
-#endif
- ppc4xx_i2c_writeb(opaque, addr, value >> 8);
- ppc4xx_i2c_writeb(opaque, addr + 1, value);
-}
-
-static uint32_t ppc4xx_i2c_readl (void *opaque, hwaddr addr)
-{
- uint32_t ret;
-
-#ifdef DEBUG_I2C
- printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
-#endif
- ret = ppc4xx_i2c_readb(opaque, addr) << 24;
- ret |= ppc4xx_i2c_readb(opaque, addr + 1) << 16;
- ret |= ppc4xx_i2c_readb(opaque, addr + 2) << 8;
- ret |= ppc4xx_i2c_readb(opaque, addr + 3);
-
- return ret;
-}
-
-static void ppc4xx_i2c_writel (void *opaque,
- hwaddr addr, uint32_t value)
-{
-#ifdef DEBUG_I2C
- printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
- value);
-#endif
- ppc4xx_i2c_writeb(opaque, addr, value >> 24);
- ppc4xx_i2c_writeb(opaque, addr + 1, value >> 16);
- ppc4xx_i2c_writeb(opaque, addr + 2, value >> 8);
- ppc4xx_i2c_writeb(opaque, addr + 3, value);
-}
-
-static const MemoryRegionOps i2c_ops = {
- .old_mmio = {
- .read = { ppc4xx_i2c_readb, ppc4xx_i2c_readw, ppc4xx_i2c_readl, },
- .write = { ppc4xx_i2c_writeb, ppc4xx_i2c_writew, ppc4xx_i2c_writel, },
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void ppc4xx_i2c_reset (void *opaque)
-{
- ppc4xx_i2c_t *i2c;
-
- i2c = opaque;
- i2c->mdata = 0x00;
- i2c->sdata = 0x00;
- i2c->cntl = 0x00;
- i2c->mdcntl = 0x00;
- i2c->sts = 0x00;
- i2c->extsts = 0x00;
- i2c->clkdiv = 0x00;
- i2c->xfrcnt = 0x00;
- i2c->directcntl = 0x0F;
-}
-
-static void ppc405_i2c_init(hwaddr base, qemu_irq irq)
-{
- ppc4xx_i2c_t *i2c;
-
- i2c = g_malloc0(sizeof(ppc4xx_i2c_t));
- i2c->irq = irq;
-#ifdef DEBUG_I2C
- printf("%s: offset " TARGET_FMT_plx "\n", __func__, base);
-#endif
- memory_region_init_io(&i2c->iomem, NULL, &i2c_ops, i2c, "i2c", 0x011);
- memory_region_add_subregion(get_system_memory(), base, &i2c->iomem);
- qemu_register_reset(ppc4xx_i2c_reset, i2c);
-}
-
-/*****************************************************************************/
-/* General purpose timers */
-typedef struct ppc4xx_gpt_t ppc4xx_gpt_t;
-struct ppc4xx_gpt_t {
- MemoryRegion iomem;
- int64_t tb_offset;
- uint32_t tb_freq;
- QEMUTimer *timer;
- qemu_irq irqs[5];
- uint32_t oe;
- uint32_t ol;
- uint32_t im;
- uint32_t is;
- uint32_t ie;
- uint32_t comp[5];
- uint32_t mask[5];
-};
-
-static uint32_t ppc4xx_gpt_readb (void *opaque, hwaddr addr)
-{
-#ifdef DEBUG_GPT
- printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
-#endif
- /* XXX: generate a bus fault */
- return -1;
-}
-
-static void ppc4xx_gpt_writeb (void *opaque,
- hwaddr addr, uint32_t value)
-{
-#ifdef DEBUG_I2C
- printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
- value);
-#endif
- /* XXX: generate a bus fault */
-}
-
-static uint32_t ppc4xx_gpt_readw (void *opaque, hwaddr addr)
-{
-#ifdef DEBUG_GPT
- printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
-#endif
- /* XXX: generate a bus fault */
- return -1;
-}
-
-static void ppc4xx_gpt_writew (void *opaque,
- hwaddr addr, uint32_t value)
-{
-#ifdef DEBUG_I2C
- printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
- value);
-#endif
- /* XXX: generate a bus fault */
-}
-
-static int ppc4xx_gpt_compare (ppc4xx_gpt_t *gpt, int n)
-{
- /* XXX: TODO */
- return 0;
-}
-
-static void ppc4xx_gpt_set_output (ppc4xx_gpt_t *gpt, int n, int level)
-{
- /* XXX: TODO */
-}
-
-static void ppc4xx_gpt_set_outputs (ppc4xx_gpt_t *gpt)
-{
- uint32_t mask;
- int i;
-
- mask = 0x80000000;
- for (i = 0; i < 5; i++) {
- if (gpt->oe & mask) {
- /* Output is enabled */
- if (ppc4xx_gpt_compare(gpt, i)) {
- /* Comparison is OK */
- ppc4xx_gpt_set_output(gpt, i, gpt->ol & mask);
- } else {
- /* Comparison is KO */
- ppc4xx_gpt_set_output(gpt, i, gpt->ol & mask ? 0 : 1);
- }
- }
- mask = mask >> 1;
- }
-}
-
-static void ppc4xx_gpt_set_irqs (ppc4xx_gpt_t *gpt)
-{
- uint32_t mask;
- int i;
-
- mask = 0x00008000;
- for (i = 0; i < 5; i++) {
- if (gpt->is & gpt->im & mask)
- qemu_irq_raise(gpt->irqs[i]);
- else
- qemu_irq_lower(gpt->irqs[i]);
- mask = mask >> 1;
- }
-}
-
-static void ppc4xx_gpt_compute_timer (ppc4xx_gpt_t *gpt)
-{
- /* XXX: TODO */
-}
-
-static uint32_t ppc4xx_gpt_readl (void *opaque, hwaddr addr)
-{
- ppc4xx_gpt_t *gpt;
- uint32_t ret;
- int idx;
-
-#ifdef DEBUG_GPT
- printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
-#endif
- gpt = opaque;
- switch (addr) {
- case 0x00:
- /* Time base counter */
- ret = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + gpt->tb_offset,
- gpt->tb_freq, NANOSECONDS_PER_SECOND);
- break;
- case 0x10:
- /* Output enable */
- ret = gpt->oe;
- break;
- case 0x14:
- /* Output level */
- ret = gpt->ol;
- break;
- case 0x18:
- /* Interrupt mask */
- ret = gpt->im;
- break;
- case 0x1C:
- case 0x20:
- /* Interrupt status */
- ret = gpt->is;
- break;
- case 0x24:
- /* Interrupt enable */
- ret = gpt->ie;
- break;
- case 0x80 ... 0x90:
- /* Compare timer */
- idx = (addr - 0x80) >> 2;
- ret = gpt->comp[idx];
- break;
- case 0xC0 ... 0xD0:
- /* Compare mask */
- idx = (addr - 0xC0) >> 2;
- ret = gpt->mask[idx];
- break;
- default:
- ret = -1;
- break;
- }
-
- return ret;
-}
-
-static void ppc4xx_gpt_writel (void *opaque,
- hwaddr addr, uint32_t value)
-{
- ppc4xx_gpt_t *gpt;
- int idx;
-
-#ifdef DEBUG_I2C
- printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
- value);
-#endif
- gpt = opaque;
- switch (addr) {
- case 0x00:
- /* Time base counter */
- gpt->tb_offset = muldiv64(value, NANOSECONDS_PER_SECOND, gpt->tb_freq)
- - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- ppc4xx_gpt_compute_timer(gpt);
- break;
- case 0x10:
- /* Output enable */
- gpt->oe = value & 0xF8000000;
- ppc4xx_gpt_set_outputs(gpt);
- break;
- case 0x14:
- /* Output level */
- gpt->ol = value & 0xF8000000;
- ppc4xx_gpt_set_outputs(gpt);
- break;
- case 0x18:
- /* Interrupt mask */
- gpt->im = value & 0x0000F800;
- break;
- case 0x1C:
- /* Interrupt status set */
- gpt->is |= value & 0x0000F800;
- ppc4xx_gpt_set_irqs(gpt);
- break;
- case 0x20:
- /* Interrupt status clear */
- gpt->is &= ~(value & 0x0000F800);
- ppc4xx_gpt_set_irqs(gpt);
- break;
- case 0x24:
- /* Interrupt enable */
- gpt->ie = value & 0x0000F800;
- ppc4xx_gpt_set_irqs(gpt);
- break;
- case 0x80 ... 0x90:
- /* Compare timer */
- idx = (addr - 0x80) >> 2;
- gpt->comp[idx] = value & 0xF8000000;
- ppc4xx_gpt_compute_timer(gpt);
- break;
- case 0xC0 ... 0xD0:
- /* Compare mask */
- idx = (addr - 0xC0) >> 2;
- gpt->mask[idx] = value & 0xF8000000;
- ppc4xx_gpt_compute_timer(gpt);
- break;
- }
-}
-
-static const MemoryRegionOps gpt_ops = {
- .old_mmio = {
- .read = { ppc4xx_gpt_readb, ppc4xx_gpt_readw, ppc4xx_gpt_readl, },
- .write = { ppc4xx_gpt_writeb, ppc4xx_gpt_writew, ppc4xx_gpt_writel, },
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void ppc4xx_gpt_cb (void *opaque)
-{
- ppc4xx_gpt_t *gpt;
-
- gpt = opaque;
- ppc4xx_gpt_set_irqs(gpt);
- ppc4xx_gpt_set_outputs(gpt);
- ppc4xx_gpt_compute_timer(gpt);
-}
-
-static void ppc4xx_gpt_reset (void *opaque)
-{
- ppc4xx_gpt_t *gpt;
- int i;
-
- gpt = opaque;
- timer_del(gpt->timer);
- gpt->oe = 0x00000000;
- gpt->ol = 0x00000000;
- gpt->im = 0x00000000;
- gpt->is = 0x00000000;
- gpt->ie = 0x00000000;
- for (i = 0; i < 5; i++) {
- gpt->comp[i] = 0x00000000;
- gpt->mask[i] = 0x00000000;
- }
-}
-
-static void ppc4xx_gpt_init(hwaddr base, qemu_irq irqs[5])
-{
- ppc4xx_gpt_t *gpt;
- int i;
-
- gpt = g_malloc0(sizeof(ppc4xx_gpt_t));
- for (i = 0; i < 5; i++) {
- gpt->irqs[i] = irqs[i];
- }
- gpt->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &ppc4xx_gpt_cb, gpt);
-#ifdef DEBUG_GPT
- printf("%s: offset " TARGET_FMT_plx "\n", __func__, base);
-#endif
- memory_region_init_io(&gpt->iomem, NULL, &gpt_ops, gpt, "gpt", 0x0d4);
- memory_region_add_subregion(get_system_memory(), base, &gpt->iomem);
- qemu_register_reset(ppc4xx_gpt_reset, gpt);
-}
-
-/*****************************************************************************/
-/* MAL */
-enum {
- MAL0_CFG = 0x180,
- MAL0_ESR = 0x181,
- MAL0_IER = 0x182,
- MAL0_TXCASR = 0x184,
- MAL0_TXCARR = 0x185,
- MAL0_TXEOBISR = 0x186,
- MAL0_TXDEIR = 0x187,
- MAL0_RXCASR = 0x190,
- MAL0_RXCARR = 0x191,
- MAL0_RXEOBISR = 0x192,
- MAL0_RXDEIR = 0x193,
- MAL0_TXCTP0R = 0x1A0,
- MAL0_TXCTP1R = 0x1A1,
- MAL0_TXCTP2R = 0x1A2,
- MAL0_TXCTP3R = 0x1A3,
- MAL0_RXCTP0R = 0x1C0,
- MAL0_RXCTP1R = 0x1C1,
- MAL0_RCBS0 = 0x1E0,
- MAL0_RCBS1 = 0x1E1,
-};
-
-typedef struct ppc40x_mal_t ppc40x_mal_t;
-struct ppc40x_mal_t {
- qemu_irq irqs[4];
- uint32_t cfg;
- uint32_t esr;
- uint32_t ier;
- uint32_t txcasr;
- uint32_t txcarr;
- uint32_t txeobisr;
- uint32_t txdeir;
- uint32_t rxcasr;
- uint32_t rxcarr;
- uint32_t rxeobisr;
- uint32_t rxdeir;
- uint32_t txctpr[4];
- uint32_t rxctpr[2];
- uint32_t rcbs[2];
-};
-
-static void ppc40x_mal_reset (void *opaque);
-
-static uint32_t dcr_read_mal (void *opaque, int dcrn)
-{
- ppc40x_mal_t *mal;
- uint32_t ret;
-
- mal = opaque;
- switch (dcrn) {
- case MAL0_CFG:
- ret = mal->cfg;
- break;
- case MAL0_ESR:
- ret = mal->esr;
- break;
- case MAL0_IER:
- ret = mal->ier;
- break;
- case MAL0_TXCASR:
- ret = mal->txcasr;
- break;
- case MAL0_TXCARR:
- ret = mal->txcarr;
- break;
- case MAL0_TXEOBISR:
- ret = mal->txeobisr;
- break;
- case MAL0_TXDEIR:
- ret = mal->txdeir;
- break;
- case MAL0_RXCASR:
- ret = mal->rxcasr;
- break;
- case MAL0_RXCARR:
- ret = mal->rxcarr;
- break;
- case MAL0_RXEOBISR:
- ret = mal->rxeobisr;
- break;
- case MAL0_RXDEIR:
- ret = mal->rxdeir;
- break;
- case MAL0_TXCTP0R:
- ret = mal->txctpr[0];
- break;
- case MAL0_TXCTP1R:
- ret = mal->txctpr[1];
- break;
- case MAL0_TXCTP2R:
- ret = mal->txctpr[2];
- break;
- case MAL0_TXCTP3R:
- ret = mal->txctpr[3];
- break;
- case MAL0_RXCTP0R:
- ret = mal->rxctpr[0];
- break;
- case MAL0_RXCTP1R:
- ret = mal->rxctpr[1];
- break;
- case MAL0_RCBS0:
- ret = mal->rcbs[0];
- break;
- case MAL0_RCBS1:
- ret = mal->rcbs[1];
- break;
- default:
- ret = 0;
- break;
- }
-
- return ret;
-}
-
-static void dcr_write_mal (void *opaque, int dcrn, uint32_t val)
-{
- ppc40x_mal_t *mal;
- int idx;
-
- mal = opaque;
- switch (dcrn) {
- case MAL0_CFG:
- if (val & 0x80000000)
- ppc40x_mal_reset(mal);
- mal->cfg = val & 0x00FFC087;
- break;
- case MAL0_ESR:
- /* Read/clear */
- mal->esr &= ~val;
- break;
- case MAL0_IER:
- mal->ier = val & 0x0000001F;
- break;
- case MAL0_TXCASR:
- mal->txcasr = val & 0xF0000000;
- break;
- case MAL0_TXCARR:
- mal->txcarr = val & 0xF0000000;
- break;
- case MAL0_TXEOBISR:
- /* Read/clear */
- mal->txeobisr &= ~val;
- break;
- case MAL0_TXDEIR:
- /* Read/clear */
- mal->txdeir &= ~val;
- break;
- case MAL0_RXCASR:
- mal->rxcasr = val & 0xC0000000;
- break;
- case MAL0_RXCARR:
- mal->rxcarr = val & 0xC0000000;
- break;
- case MAL0_RXEOBISR:
- /* Read/clear */
- mal->rxeobisr &= ~val;
- break;
- case MAL0_RXDEIR:
- /* Read/clear */
- mal->rxdeir &= ~val;
- break;
- case MAL0_TXCTP0R:
- idx = 0;
- goto update_tx_ptr;
- case MAL0_TXCTP1R:
- idx = 1;
- goto update_tx_ptr;
- case MAL0_TXCTP2R:
- idx = 2;
- goto update_tx_ptr;
- case MAL0_TXCTP3R:
- idx = 3;
- update_tx_ptr:
- mal->txctpr[idx] = val;
- break;
- case MAL0_RXCTP0R:
- idx = 0;
- goto update_rx_ptr;
- case MAL0_RXCTP1R:
- idx = 1;
- update_rx_ptr:
- mal->rxctpr[idx] = val;
- break;
- case MAL0_RCBS0:
- idx = 0;
- goto update_rx_size;
- case MAL0_RCBS1:
- idx = 1;
- update_rx_size:
- mal->rcbs[idx] = val & 0x000000FF;
- break;
- }
-}
-
-static void ppc40x_mal_reset (void *opaque)
-{
- ppc40x_mal_t *mal;
-
- mal = opaque;
- mal->cfg = 0x0007C000;
- mal->esr = 0x00000000;
- mal->ier = 0x00000000;
- mal->rxcasr = 0x00000000;
- mal->rxdeir = 0x00000000;
- mal->rxeobisr = 0x00000000;
- mal->txcasr = 0x00000000;
- mal->txdeir = 0x00000000;
- mal->txeobisr = 0x00000000;
-}
-
-static void ppc405_mal_init(CPUPPCState *env, qemu_irq irqs[4])
-{
- ppc40x_mal_t *mal;
- int i;
-
- mal = g_malloc0(sizeof(ppc40x_mal_t));
- for (i = 0; i < 4; i++)
- mal->irqs[i] = irqs[i];
- qemu_register_reset(&ppc40x_mal_reset, mal);
- ppc_dcr_register(env, MAL0_CFG,
- mal, &dcr_read_mal, &dcr_write_mal);
- ppc_dcr_register(env, MAL0_ESR,
- mal, &dcr_read_mal, &dcr_write_mal);
- ppc_dcr_register(env, MAL0_IER,
- mal, &dcr_read_mal, &dcr_write_mal);
- ppc_dcr_register(env, MAL0_TXCASR,
- mal, &dcr_read_mal, &dcr_write_mal);
- ppc_dcr_register(env, MAL0_TXCARR,
- mal, &dcr_read_mal, &dcr_write_mal);
- ppc_dcr_register(env, MAL0_TXEOBISR,
- mal, &dcr_read_mal, &dcr_write_mal);
- ppc_dcr_register(env, MAL0_TXDEIR,
- mal, &dcr_read_mal, &dcr_write_mal);
- ppc_dcr_register(env, MAL0_RXCASR,
- mal, &dcr_read_mal, &dcr_write_mal);
- ppc_dcr_register(env, MAL0_RXCARR,
- mal, &dcr_read_mal, &dcr_write_mal);
- ppc_dcr_register(env, MAL0_RXEOBISR,
- mal, &dcr_read_mal, &dcr_write_mal);
- ppc_dcr_register(env, MAL0_RXDEIR,
- mal, &dcr_read_mal, &dcr_write_mal);
- ppc_dcr_register(env, MAL0_TXCTP0R,
- mal, &dcr_read_mal, &dcr_write_mal);
- ppc_dcr_register(env, MAL0_TXCTP1R,
- mal, &dcr_read_mal, &dcr_write_mal);
- ppc_dcr_register(env, MAL0_TXCTP2R,
- mal, &dcr_read_mal, &dcr_write_mal);
- ppc_dcr_register(env, MAL0_TXCTP3R,
- mal, &dcr_read_mal, &dcr_write_mal);
- ppc_dcr_register(env, MAL0_RXCTP0R,
- mal, &dcr_read_mal, &dcr_write_mal);
- ppc_dcr_register(env, MAL0_RXCTP1R,
- mal, &dcr_read_mal, &dcr_write_mal);
- ppc_dcr_register(env, MAL0_RCBS0,
- mal, &dcr_read_mal, &dcr_write_mal);
- ppc_dcr_register(env, MAL0_RCBS1,
- mal, &dcr_read_mal, &dcr_write_mal);
-}
-
-/*****************************************************************************/
-/* SPR */
-void ppc40x_core_reset(PowerPCCPU *cpu)
-{
- CPUPPCState *env = &cpu->env;
- target_ulong dbsr;
-
- printf("Reset PowerPC core\n");
- cpu_interrupt(CPU(cpu), CPU_INTERRUPT_RESET);
- dbsr = env->spr[SPR_40x_DBSR];
- dbsr &= ~0x00000300;
- dbsr |= 0x00000100;
- env->spr[SPR_40x_DBSR] = dbsr;
-}
-
-void ppc40x_chip_reset(PowerPCCPU *cpu)
-{
- CPUPPCState *env = &cpu->env;
- target_ulong dbsr;
-
- printf("Reset PowerPC chip\n");
- cpu_interrupt(CPU(cpu), CPU_INTERRUPT_RESET);
- /* XXX: TODO reset all internal peripherals */
- dbsr = env->spr[SPR_40x_DBSR];
- dbsr &= ~0x00000300;
- dbsr |= 0x00000200;
- env->spr[SPR_40x_DBSR] = dbsr;
-}
-
-void ppc40x_system_reset(PowerPCCPU *cpu)
-{
- printf("Reset PowerPC system\n");
- qemu_system_reset_request();
-}
-
-void store_40x_dbcr0 (CPUPPCState *env, uint32_t val)
-{
- PowerPCCPU *cpu = ppc_env_get_cpu(env);
-
- switch ((val >> 28) & 0x3) {
- case 0x0:
- /* No action */
- break;
- case 0x1:
- /* Core reset */
- ppc40x_core_reset(cpu);
- break;
- case 0x2:
- /* Chip reset */
- ppc40x_chip_reset(cpu);
- break;
- case 0x3:
- /* System reset */
- ppc40x_system_reset(cpu);
- break;
- }
-}
-
-/*****************************************************************************/
-/* PowerPC 405CR */
-enum {
- PPC405CR_CPC0_PLLMR = 0x0B0,
- PPC405CR_CPC0_CR0 = 0x0B1,
- PPC405CR_CPC0_CR1 = 0x0B2,
- PPC405CR_CPC0_PSR = 0x0B4,
- PPC405CR_CPC0_JTAGID = 0x0B5,
- PPC405CR_CPC0_ER = 0x0B9,
- PPC405CR_CPC0_FR = 0x0BA,
- PPC405CR_CPC0_SR = 0x0BB,
-};
-
-enum {
- PPC405CR_CPU_CLK = 0,
- PPC405CR_TMR_CLK = 1,
- PPC405CR_PLB_CLK = 2,
- PPC405CR_SDRAM_CLK = 3,
- PPC405CR_OPB_CLK = 4,
- PPC405CR_EXT_CLK = 5,
- PPC405CR_UART_CLK = 6,
- PPC405CR_CLK_NB = 7,
-};
-
-typedef struct ppc405cr_cpc_t ppc405cr_cpc_t;
-struct ppc405cr_cpc_t {
- clk_setup_t clk_setup[PPC405CR_CLK_NB];
- uint32_t sysclk;
- uint32_t psr;
- uint32_t cr0;
- uint32_t cr1;
- uint32_t jtagid;
- uint32_t pllmr;
- uint32_t er;
- uint32_t fr;
-};
-
-static void ppc405cr_clk_setup (ppc405cr_cpc_t *cpc)
-{
- uint64_t VCO_out, PLL_out;
- uint32_t CPU_clk, TMR_clk, SDRAM_clk, PLB_clk, OPB_clk, EXT_clk, UART_clk;
- int M, D0, D1, D2;
-
- D0 = ((cpc->pllmr >> 26) & 0x3) + 1; /* CBDV */
- if (cpc->pllmr & 0x80000000) {
- D1 = (((cpc->pllmr >> 20) - 1) & 0xF) + 1; /* FBDV */
- D2 = 8 - ((cpc->pllmr >> 16) & 0x7); /* FWDVA */
- M = D0 * D1 * D2;
- VCO_out = cpc->sysclk * M;
- if (VCO_out < 400000000 || VCO_out > 800000000) {
- /* PLL cannot lock */
- cpc->pllmr &= ~0x80000000;
- goto bypass_pll;
- }
- PLL_out = VCO_out / D2;
- } else {
- /* Bypass PLL */
- bypass_pll:
- M = D0;
- PLL_out = cpc->sysclk * M;
- }
- CPU_clk = PLL_out;
- if (cpc->cr1 & 0x00800000)
- TMR_clk = cpc->sysclk; /* Should have a separate clock */
- else
- TMR_clk = CPU_clk;
- PLB_clk = CPU_clk / D0;
- SDRAM_clk = PLB_clk;
- D0 = ((cpc->pllmr >> 10) & 0x3) + 1;
- OPB_clk = PLB_clk / D0;
- D0 = ((cpc->pllmr >> 24) & 0x3) + 2;
- EXT_clk = PLB_clk / D0;
- D0 = ((cpc->cr0 >> 1) & 0x1F) + 1;
- UART_clk = CPU_clk / D0;
- /* Setup CPU clocks */
- clk_setup(&cpc->clk_setup[PPC405CR_CPU_CLK], CPU_clk);
- /* Setup time-base clock */
- clk_setup(&cpc->clk_setup[PPC405CR_TMR_CLK], TMR_clk);
- /* Setup PLB clock */
- clk_setup(&cpc->clk_setup[PPC405CR_PLB_CLK], PLB_clk);
- /* Setup SDRAM clock */
- clk_setup(&cpc->clk_setup[PPC405CR_SDRAM_CLK], SDRAM_clk);
- /* Setup OPB clock */
- clk_setup(&cpc->clk_setup[PPC405CR_OPB_CLK], OPB_clk);
- /* Setup external clock */
- clk_setup(&cpc->clk_setup[PPC405CR_EXT_CLK], EXT_clk);
- /* Setup UART clock */
- clk_setup(&cpc->clk_setup[PPC405CR_UART_CLK], UART_clk);
-}
-
-static uint32_t dcr_read_crcpc (void *opaque, int dcrn)
-{
- ppc405cr_cpc_t *cpc;
- uint32_t ret;
-
- cpc = opaque;
- switch (dcrn) {
- case PPC405CR_CPC0_PLLMR:
- ret = cpc->pllmr;
- break;
- case PPC405CR_CPC0_CR0:
- ret = cpc->cr0;
- break;
- case PPC405CR_CPC0_CR1:
- ret = cpc->cr1;
- break;
- case PPC405CR_CPC0_PSR:
- ret = cpc->psr;
- break;
- case PPC405CR_CPC0_JTAGID:
- ret = cpc->jtagid;
- break;
- case PPC405CR_CPC0_ER:
- ret = cpc->er;
- break;
- case PPC405CR_CPC0_FR:
- ret = cpc->fr;
- break;
- case PPC405CR_CPC0_SR:
- ret = ~(cpc->er | cpc->fr) & 0xFFFF0000;
- break;
- default:
- /* Avoid gcc warning */
- ret = 0;
- break;
- }
-
- return ret;
-}
-
-static void dcr_write_crcpc (void *opaque, int dcrn, uint32_t val)
-{
- ppc405cr_cpc_t *cpc;
-
- cpc = opaque;
- switch (dcrn) {
- case PPC405CR_CPC0_PLLMR:
- cpc->pllmr = val & 0xFFF77C3F;
- break;
- case PPC405CR_CPC0_CR0:
- cpc->cr0 = val & 0x0FFFFFFE;
- break;
- case PPC405CR_CPC0_CR1:
- cpc->cr1 = val & 0x00800000;
- break;
- case PPC405CR_CPC0_PSR:
- /* Read-only */
- break;
- case PPC405CR_CPC0_JTAGID:
- /* Read-only */
- break;
- case PPC405CR_CPC0_ER:
- cpc->er = val & 0xBFFC0000;
- break;
- case PPC405CR_CPC0_FR:
- cpc->fr = val & 0xBFFC0000;
- break;
- case PPC405CR_CPC0_SR:
- /* Read-only */
- break;
- }
-}
-
-static void ppc405cr_cpc_reset (void *opaque)
-{
- ppc405cr_cpc_t *cpc;
- int D;
-
- cpc = opaque;
- /* Compute PLLMR value from PSR settings */
- cpc->pllmr = 0x80000000;
- /* PFWD */
- switch ((cpc->psr >> 30) & 3) {
- case 0:
- /* Bypass */
- cpc->pllmr &= ~0x80000000;
- break;
- case 1:
- /* Divide by 3 */
- cpc->pllmr |= 5 << 16;
- break;
- case 2:
- /* Divide by 4 */
- cpc->pllmr |= 4 << 16;
- break;
- case 3:
- /* Divide by 6 */
- cpc->pllmr |= 2 << 16;
- break;
- }
- /* PFBD */
- D = (cpc->psr >> 28) & 3;
- cpc->pllmr |= (D + 1) << 20;
- /* PT */
- D = (cpc->psr >> 25) & 7;
- switch (D) {
- case 0x2:
- cpc->pllmr |= 0x13;
- break;
- case 0x4:
- cpc->pllmr |= 0x15;
- break;
- case 0x5:
- cpc->pllmr |= 0x16;
- break;
- default:
- break;
- }
- /* PDC */
- D = (cpc->psr >> 23) & 3;
- cpc->pllmr |= D << 26;
- /* ODP */
- D = (cpc->psr >> 21) & 3;
- cpc->pllmr |= D << 10;
- /* EBPD */
- D = (cpc->psr >> 17) & 3;
- cpc->pllmr |= D << 24;
- cpc->cr0 = 0x0000003C;
- cpc->cr1 = 0x2B0D8800;
- cpc->er = 0x00000000;
- cpc->fr = 0x00000000;
- ppc405cr_clk_setup(cpc);
-}
-
-static void ppc405cr_clk_init (ppc405cr_cpc_t *cpc)
-{
- int D;
-
- /* XXX: this should be read from IO pins */
- cpc->psr = 0x00000000; /* 8 bits ROM */
- /* PFWD */
- D = 0x2; /* Divide by 4 */
- cpc->psr |= D << 30;
- /* PFBD */
- D = 0x1; /* Divide by 2 */
- cpc->psr |= D << 28;
- /* PDC */
- D = 0x1; /* Divide by 2 */
- cpc->psr |= D << 23;
- /* PT */
- D = 0x5; /* M = 16 */
- cpc->psr |= D << 25;
- /* ODP */
- D = 0x1; /* Divide by 2 */
- cpc->psr |= D << 21;
- /* EBDP */
- D = 0x2; /* Divide by 4 */
- cpc->psr |= D << 17;
-}
-
-static void ppc405cr_cpc_init (CPUPPCState *env, clk_setup_t clk_setup[7],
- uint32_t sysclk)
-{
- ppc405cr_cpc_t *cpc;
-
- cpc = g_malloc0(sizeof(ppc405cr_cpc_t));
- memcpy(cpc->clk_setup, clk_setup,
- PPC405CR_CLK_NB * sizeof(clk_setup_t));
- cpc->sysclk = sysclk;
- cpc->jtagid = 0x42051049;
- ppc_dcr_register(env, PPC405CR_CPC0_PSR, cpc,
- &dcr_read_crcpc, &dcr_write_crcpc);
- ppc_dcr_register(env, PPC405CR_CPC0_CR0, cpc,
- &dcr_read_crcpc, &dcr_write_crcpc);
- ppc_dcr_register(env, PPC405CR_CPC0_CR1, cpc,
- &dcr_read_crcpc, &dcr_write_crcpc);
- ppc_dcr_register(env, PPC405CR_CPC0_JTAGID, cpc,
- &dcr_read_crcpc, &dcr_write_crcpc);
- ppc_dcr_register(env, PPC405CR_CPC0_PLLMR, cpc,
- &dcr_read_crcpc, &dcr_write_crcpc);
- ppc_dcr_register(env, PPC405CR_CPC0_ER, cpc,
- &dcr_read_crcpc, &dcr_write_crcpc);
- ppc_dcr_register(env, PPC405CR_CPC0_FR, cpc,
- &dcr_read_crcpc, &dcr_write_crcpc);
- ppc_dcr_register(env, PPC405CR_CPC0_SR, cpc,
- &dcr_read_crcpc, &dcr_write_crcpc);
- ppc405cr_clk_init(cpc);
- qemu_register_reset(ppc405cr_cpc_reset, cpc);
-}
-
-CPUPPCState *ppc405cr_init(MemoryRegion *address_space_mem,
- MemoryRegion ram_memories[4],
- hwaddr ram_bases[4],
- hwaddr ram_sizes[4],
- uint32_t sysclk, qemu_irq **picp,
- int do_init)
-{
- clk_setup_t clk_setup[PPC405CR_CLK_NB];
- qemu_irq dma_irqs[4];
- PowerPCCPU *cpu;
- CPUPPCState *env;
- qemu_irq *pic, *irqs;
-
- memset(clk_setup, 0, sizeof(clk_setup));
- cpu = ppc4xx_init("405cr", &clk_setup[PPC405CR_CPU_CLK],
- &clk_setup[PPC405CR_TMR_CLK], sysclk);
- env = &cpu->env;
- /* Memory mapped devices registers */
- /* PLB arbitrer */
- ppc4xx_plb_init(env);
- /* PLB to OPB bridge */
- ppc4xx_pob_init(env);
- /* OBP arbitrer */
- ppc4xx_opba_init(0xef600600);
- /* Universal interrupt controller */
- irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
- irqs[PPCUIC_OUTPUT_INT] =
- ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
- irqs[PPCUIC_OUTPUT_CINT] =
- ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
- pic = ppcuic_init(env, irqs, 0x0C0, 0, 1);
- *picp = pic;
- /* SDRAM controller */
- ppc4xx_sdram_init(env, pic[14], 1, ram_memories,
- ram_bases, ram_sizes, do_init);
- /* External bus controller */
- ppc405_ebc_init(env);
- /* DMA controller */
- dma_irqs[0] = pic[26];
- dma_irqs[1] = pic[25];
- dma_irqs[2] = pic[24];
- dma_irqs[3] = pic[23];
- ppc405_dma_init(env, dma_irqs);
- /* Serial ports */
- if (serial_hds[0] != NULL) {
- serial_mm_init(address_space_mem, 0xef600300, 0, pic[0],
- PPC_SERIAL_MM_BAUDBASE, serial_hds[0],
- DEVICE_BIG_ENDIAN);
- }
- if (serial_hds[1] != NULL) {
- serial_mm_init(address_space_mem, 0xef600400, 0, pic[1],
- PPC_SERIAL_MM_BAUDBASE, serial_hds[1],
- DEVICE_BIG_ENDIAN);
- }
- /* IIC controller */
- ppc405_i2c_init(0xef600500, pic[2]);
- /* GPIO */
- ppc405_gpio_init(0xef600700);
- /* CPU control */
- ppc405cr_cpc_init(env, clk_setup, sysclk);
-
- return env;
-}
-
-/*****************************************************************************/
-/* PowerPC 405EP */
-/* CPU control */
-enum {
- PPC405EP_CPC0_PLLMR0 = 0x0F0,
- PPC405EP_CPC0_BOOT = 0x0F1,
- PPC405EP_CPC0_EPCTL = 0x0F3,
- PPC405EP_CPC0_PLLMR1 = 0x0F4,
- PPC405EP_CPC0_UCR = 0x0F5,
- PPC405EP_CPC0_SRR = 0x0F6,
- PPC405EP_CPC0_JTAGID = 0x0F7,
- PPC405EP_CPC0_PCI = 0x0F9,
-#if 0
- PPC405EP_CPC0_ER = xxx,
- PPC405EP_CPC0_FR = xxx,
- PPC405EP_CPC0_SR = xxx,
-#endif
-};
-
-enum {
- PPC405EP_CPU_CLK = 0,
- PPC405EP_PLB_CLK = 1,
- PPC405EP_OPB_CLK = 2,
- PPC405EP_EBC_CLK = 3,
- PPC405EP_MAL_CLK = 4,
- PPC405EP_PCI_CLK = 5,
- PPC405EP_UART0_CLK = 6,
- PPC405EP_UART1_CLK = 7,
- PPC405EP_CLK_NB = 8,
-};
-
-typedef struct ppc405ep_cpc_t ppc405ep_cpc_t;
-struct ppc405ep_cpc_t {
- uint32_t sysclk;
- clk_setup_t clk_setup[PPC405EP_CLK_NB];
- uint32_t boot;
- uint32_t epctl;
- uint32_t pllmr[2];
- uint32_t ucr;
- uint32_t srr;
- uint32_t jtagid;
- uint32_t pci;
- /* Clock and power management */
- uint32_t er;
- uint32_t fr;
- uint32_t sr;
-};
-
-static void ppc405ep_compute_clocks (ppc405ep_cpc_t *cpc)
-{
- uint32_t CPU_clk, PLB_clk, OPB_clk, EBC_clk, MAL_clk, PCI_clk;
- uint32_t UART0_clk, UART1_clk;
- uint64_t VCO_out, PLL_out;
- int M, D;
-
- VCO_out = 0;
- if ((cpc->pllmr[1] & 0x80000000) && !(cpc->pllmr[1] & 0x40000000)) {
- M = (((cpc->pllmr[1] >> 20) - 1) & 0xF) + 1; /* FBMUL */
-#ifdef DEBUG_CLOCKS_LL
- printf("FBMUL %01" PRIx32 " %d\n", (cpc->pllmr[1] >> 20) & 0xF, M);
-#endif
- D = 8 - ((cpc->pllmr[1] >> 16) & 0x7); /* FWDA */
-#ifdef DEBUG_CLOCKS_LL
- printf("FWDA %01" PRIx32 " %d\n", (cpc->pllmr[1] >> 16) & 0x7, D);
-#endif
- VCO_out = cpc->sysclk * M * D;
- if (VCO_out < 500000000UL || VCO_out > 1000000000UL) {
- /* Error - unlock the PLL */
- printf("VCO out of range %" PRIu64 "\n", VCO_out);
-#if 0
- cpc->pllmr[1] &= ~0x80000000;
- goto pll_bypass;
-#endif
- }
- PLL_out = VCO_out / D;
- /* Pretend the PLL is locked */
- cpc->boot |= 0x00000001;
- } else {
-#if 0
- pll_bypass:
-#endif
- PLL_out = cpc->sysclk;
- if (cpc->pllmr[1] & 0x40000000) {
- /* Pretend the PLL is not locked */
- cpc->boot &= ~0x00000001;
- }
- }
- /* Now, compute all other clocks */
- D = ((cpc->pllmr[0] >> 20) & 0x3) + 1; /* CCDV */
-#ifdef DEBUG_CLOCKS_LL
- printf("CCDV %01" PRIx32 " %d\n", (cpc->pllmr[0] >> 20) & 0x3, D);
-#endif
- CPU_clk = PLL_out / D;
- D = ((cpc->pllmr[0] >> 16) & 0x3) + 1; /* CBDV */
-#ifdef DEBUG_CLOCKS_LL
- printf("CBDV %01" PRIx32 " %d\n", (cpc->pllmr[0] >> 16) & 0x3, D);
-#endif
- PLB_clk = CPU_clk / D;
- D = ((cpc->pllmr[0] >> 12) & 0x3) + 1; /* OPDV */
-#ifdef DEBUG_CLOCKS_LL
- printf("OPDV %01" PRIx32 " %d\n", (cpc->pllmr[0] >> 12) & 0x3, D);
-#endif
- OPB_clk = PLB_clk / D;
- D = ((cpc->pllmr[0] >> 8) & 0x3) + 2; /* EPDV */
-#ifdef DEBUG_CLOCKS_LL
- printf("EPDV %01" PRIx32 " %d\n", (cpc->pllmr[0] >> 8) & 0x3, D);
-#endif
- EBC_clk = PLB_clk / D;
- D = ((cpc->pllmr[0] >> 4) & 0x3) + 1; /* MPDV */
-#ifdef DEBUG_CLOCKS_LL
- printf("MPDV %01" PRIx32 " %d\n", (cpc->pllmr[0] >> 4) & 0x3, D);
-#endif
- MAL_clk = PLB_clk / D;
- D = (cpc->pllmr[0] & 0x3) + 1; /* PPDV */
-#ifdef DEBUG_CLOCKS_LL
- printf("PPDV %01" PRIx32 " %d\n", cpc->pllmr[0] & 0x3, D);
-#endif
- PCI_clk = PLB_clk / D;
- D = ((cpc->ucr - 1) & 0x7F) + 1; /* U0DIV */
-#ifdef DEBUG_CLOCKS_LL
- printf("U0DIV %01" PRIx32 " %d\n", cpc->ucr & 0x7F, D);
-#endif
- UART0_clk = PLL_out / D;
- D = (((cpc->ucr >> 8) - 1) & 0x7F) + 1; /* U1DIV */
-#ifdef DEBUG_CLOCKS_LL
- printf("U1DIV %01" PRIx32 " %d\n", (cpc->ucr >> 8) & 0x7F, D);
-#endif
- UART1_clk = PLL_out / D;
-#ifdef DEBUG_CLOCKS
- printf("Setup PPC405EP clocks - sysclk %" PRIu32 " VCO %" PRIu64
- " PLL out %" PRIu64 " Hz\n", cpc->sysclk, VCO_out, PLL_out);
- printf("CPU %" PRIu32 " PLB %" PRIu32 " OPB %" PRIu32 " EBC %" PRIu32
- " MAL %" PRIu32 " PCI %" PRIu32 " UART0 %" PRIu32
- " UART1 %" PRIu32 "\n",
- CPU_clk, PLB_clk, OPB_clk, EBC_clk, MAL_clk, PCI_clk,
- UART0_clk, UART1_clk);
-#endif
- /* Setup CPU clocks */
- clk_setup(&cpc->clk_setup[PPC405EP_CPU_CLK], CPU_clk);
- /* Setup PLB clock */
- clk_setup(&cpc->clk_setup[PPC405EP_PLB_CLK], PLB_clk);
- /* Setup OPB clock */
- clk_setup(&cpc->clk_setup[PPC405EP_OPB_CLK], OPB_clk);
- /* Setup external clock */
- clk_setup(&cpc->clk_setup[PPC405EP_EBC_CLK], EBC_clk);
- /* Setup MAL clock */
- clk_setup(&cpc->clk_setup[PPC405EP_MAL_CLK], MAL_clk);
- /* Setup PCI clock */
- clk_setup(&cpc->clk_setup[PPC405EP_PCI_CLK], PCI_clk);
- /* Setup UART0 clock */
- clk_setup(&cpc->clk_setup[PPC405EP_UART0_CLK], UART0_clk);
- /* Setup UART1 clock */
- clk_setup(&cpc->clk_setup[PPC405EP_UART1_CLK], UART1_clk);
-}
-
-static uint32_t dcr_read_epcpc (void *opaque, int dcrn)
-{
- ppc405ep_cpc_t *cpc;
- uint32_t ret;
-
- cpc = opaque;
- switch (dcrn) {
- case PPC405EP_CPC0_BOOT:
- ret = cpc->boot;
- break;
- case PPC405EP_CPC0_EPCTL:
- ret = cpc->epctl;
- break;
- case PPC405EP_CPC0_PLLMR0:
- ret = cpc->pllmr[0];
- break;
- case PPC405EP_CPC0_PLLMR1:
- ret = cpc->pllmr[1];
- break;
- case PPC405EP_CPC0_UCR:
- ret = cpc->ucr;
- break;
- case PPC405EP_CPC0_SRR:
- ret = cpc->srr;
- break;
- case PPC405EP_CPC0_JTAGID:
- ret = cpc->jtagid;
- break;
- case PPC405EP_CPC0_PCI:
- ret = cpc->pci;
- break;
- default:
- /* Avoid gcc warning */
- ret = 0;
- break;
- }
-
- return ret;
-}
-
-static void dcr_write_epcpc (void *opaque, int dcrn, uint32_t val)
-{
- ppc405ep_cpc_t *cpc;
-
- cpc = opaque;
- switch (dcrn) {
- case PPC405EP_CPC0_BOOT:
- /* Read-only register */
- break;
- case PPC405EP_CPC0_EPCTL:
- /* Don't care for now */
- cpc->epctl = val & 0xC00000F3;
- break;
- case PPC405EP_CPC0_PLLMR0:
- cpc->pllmr[0] = val & 0x00633333;
- ppc405ep_compute_clocks(cpc);
- break;
- case PPC405EP_CPC0_PLLMR1:
- cpc->pllmr[1] = val & 0xC0F73FFF;
- ppc405ep_compute_clocks(cpc);
- break;
- case PPC405EP_CPC0_UCR:
- /* UART control - don't care for now */
- cpc->ucr = val & 0x003F7F7F;
- break;
- case PPC405EP_CPC0_SRR:
- cpc->srr = val;
- break;
- case PPC405EP_CPC0_JTAGID:
- /* Read-only */
- break;
- case PPC405EP_CPC0_PCI:
- cpc->pci = val;
- break;
- }
-}
-
-static void ppc405ep_cpc_reset (void *opaque)
-{
- ppc405ep_cpc_t *cpc = opaque;
-
- cpc->boot = 0x00000010; /* Boot from PCI - IIC EEPROM disabled */
- cpc->epctl = 0x00000000;
- cpc->pllmr[0] = 0x00011010;
- cpc->pllmr[1] = 0x40000000;
- cpc->ucr = 0x00000000;
- cpc->srr = 0x00040000;
- cpc->pci = 0x00000000;
- cpc->er = 0x00000000;
- cpc->fr = 0x00000000;
- cpc->sr = 0x00000000;
- ppc405ep_compute_clocks(cpc);
-}
-
-/* XXX: sysclk should be between 25 and 100 MHz */
-static void ppc405ep_cpc_init (CPUPPCState *env, clk_setup_t clk_setup[8],
- uint32_t sysclk)
-{
- ppc405ep_cpc_t *cpc;
-
- cpc = g_malloc0(sizeof(ppc405ep_cpc_t));
- memcpy(cpc->clk_setup, clk_setup,
- PPC405EP_CLK_NB * sizeof(clk_setup_t));
- cpc->jtagid = 0x20267049;
- cpc->sysclk = sysclk;
- qemu_register_reset(&ppc405ep_cpc_reset, cpc);
- ppc_dcr_register(env, PPC405EP_CPC0_BOOT, cpc,
- &dcr_read_epcpc, &dcr_write_epcpc);
- ppc_dcr_register(env, PPC405EP_CPC0_EPCTL, cpc,
- &dcr_read_epcpc, &dcr_write_epcpc);
- ppc_dcr_register(env, PPC405EP_CPC0_PLLMR0, cpc,
- &dcr_read_epcpc, &dcr_write_epcpc);
- ppc_dcr_register(env, PPC405EP_CPC0_PLLMR1, cpc,
- &dcr_read_epcpc, &dcr_write_epcpc);
- ppc_dcr_register(env, PPC405EP_CPC0_UCR, cpc,
- &dcr_read_epcpc, &dcr_write_epcpc);
- ppc_dcr_register(env, PPC405EP_CPC0_SRR, cpc,
- &dcr_read_epcpc, &dcr_write_epcpc);
- ppc_dcr_register(env, PPC405EP_CPC0_JTAGID, cpc,
- &dcr_read_epcpc, &dcr_write_epcpc);
- ppc_dcr_register(env, PPC405EP_CPC0_PCI, cpc,
- &dcr_read_epcpc, &dcr_write_epcpc);
-#if 0
- ppc_dcr_register(env, PPC405EP_CPC0_ER, cpc,
- &dcr_read_epcpc, &dcr_write_epcpc);
- ppc_dcr_register(env, PPC405EP_CPC0_FR, cpc,
- &dcr_read_epcpc, &dcr_write_epcpc);
- ppc_dcr_register(env, PPC405EP_CPC0_SR, cpc,
- &dcr_read_epcpc, &dcr_write_epcpc);
-#endif
-}
-
-CPUPPCState *ppc405ep_init(MemoryRegion *address_space_mem,
- MemoryRegion ram_memories[2],
- hwaddr ram_bases[2],
- hwaddr ram_sizes[2],
- uint32_t sysclk, qemu_irq **picp,
- int do_init)
-{
- clk_setup_t clk_setup[PPC405EP_CLK_NB], tlb_clk_setup;
- qemu_irq dma_irqs[4], gpt_irqs[5], mal_irqs[4];
- PowerPCCPU *cpu;
- CPUPPCState *env;
- qemu_irq *pic, *irqs;
-
- memset(clk_setup, 0, sizeof(clk_setup));
- /* init CPUs */
- cpu = ppc4xx_init("405ep", &clk_setup[PPC405EP_CPU_CLK],
- &tlb_clk_setup, sysclk);
- env = &cpu->env;
- clk_setup[PPC405EP_CPU_CLK].cb = tlb_clk_setup.cb;
- clk_setup[PPC405EP_CPU_CLK].opaque = tlb_clk_setup.opaque;
- /* Internal devices init */
- /* Memory mapped devices registers */
- /* PLB arbitrer */
- ppc4xx_plb_init(env);
- /* PLB to OPB bridge */
- ppc4xx_pob_init(env);
- /* OBP arbitrer */
- ppc4xx_opba_init(0xef600600);
- /* Initialize timers */
- ppc_booke_timers_init(cpu, sysclk, 0);
- /* Universal interrupt controller */
- irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
- irqs[PPCUIC_OUTPUT_INT] =
- ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
- irqs[PPCUIC_OUTPUT_CINT] =
- ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
- pic = ppcuic_init(env, irqs, 0x0C0, 0, 1);
- *picp = pic;
- /* SDRAM controller */
- /* XXX 405EP has no ECC interrupt */
- ppc4xx_sdram_init(env, pic[17], 2, ram_memories,
- ram_bases, ram_sizes, do_init);
- /* External bus controller */
- ppc405_ebc_init(env);
- /* DMA controller */
- dma_irqs[0] = pic[5];
- dma_irqs[1] = pic[6];
- dma_irqs[2] = pic[7];
- dma_irqs[3] = pic[8];
- ppc405_dma_init(env, dma_irqs);
- /* IIC controller */
- ppc405_i2c_init(0xef600500, pic[2]);
- /* GPIO */
- ppc405_gpio_init(0xef600700);
- /* Serial ports */
- if (serial_hds[0] != NULL) {
- serial_mm_init(address_space_mem, 0xef600300, 0, pic[0],
- PPC_SERIAL_MM_BAUDBASE, serial_hds[0],
- DEVICE_BIG_ENDIAN);
- }
- if (serial_hds[1] != NULL) {
- serial_mm_init(address_space_mem, 0xef600400, 0, pic[1],
- PPC_SERIAL_MM_BAUDBASE, serial_hds[1],
- DEVICE_BIG_ENDIAN);
- }
- /* OCM */
- ppc405_ocm_init(env);
- /* GPT */
- gpt_irqs[0] = pic[19];
- gpt_irqs[1] = pic[20];
- gpt_irqs[2] = pic[21];
- gpt_irqs[3] = pic[22];
- gpt_irqs[4] = pic[23];
- ppc4xx_gpt_init(0xef600000, gpt_irqs);
- /* PCI */
- /* Uses pic[3], pic[16], pic[18] */
- /* MAL */
- mal_irqs[0] = pic[11];
- mal_irqs[1] = pic[12];
- mal_irqs[2] = pic[13];
- mal_irqs[3] = pic[14];
- ppc405_mal_init(env, mal_irqs);
- /* Ethernet */
- /* Uses pic[9], pic[15], pic[17] */
- /* CPU control */
- ppc405ep_cpc_init(env, clk_setup, sysclk);
-
- return env;
-}
diff --git a/qemu/hw/ppc/ppc440_bamboo.c b/qemu/hw/ppc/ppc440_bamboo.c
deleted file mode 100644
index 5c535b18a..000000000
--- a/qemu/hw/ppc/ppc440_bamboo.c
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
- * QEMU PowerPC 440 Bamboo board emulation
- *
- * Copyright 2007 IBM Corporation.
- * Authors:
- * Jerone Young <jyoung5@us.ibm.com>
- * Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
- * Hollis Blanchard <hollisb@us.ibm.com>
- *
- * This work is licensed under the GNU GPL license version 2 or later.
- *
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "net/net.h"
-#include "hw/hw.h"
-#include "hw/pci/pci.h"
-#include "hw/boards.h"
-#include "sysemu/kvm.h"
-#include "kvm_ppc.h"
-#include "sysemu/device_tree.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "exec/address-spaces.h"
-#include "hw/char/serial.h"
-#include "hw/ppc/ppc.h"
-#include "ppc405.h"
-#include "sysemu/sysemu.h"
-#include "hw/sysbus.h"
-
-#define BINARY_DEVICE_TREE_FILE "bamboo.dtb"
-
-/* from u-boot */
-#define KERNEL_ADDR 0x1000000
-#define FDT_ADDR 0x1800000
-#define RAMDISK_ADDR 0x1900000
-
-#define PPC440EP_PCI_CONFIG 0xeec00000
-#define PPC440EP_PCI_INTACK 0xeed00000
-#define PPC440EP_PCI_SPECIAL 0xeed00000
-#define PPC440EP_PCI_REGS 0xef400000
-#define PPC440EP_PCI_IO 0xe8000000
-#define PPC440EP_PCI_IOLEN 0x00010000
-
-#define PPC440EP_SDRAM_NR_BANKS 4
-
-static const unsigned int ppc440ep_sdram_bank_sizes[] = {
- 256<<20, 128<<20, 64<<20, 32<<20, 16<<20, 8<<20, 0
-};
-
-static hwaddr entry;
-
-static int bamboo_load_device_tree(hwaddr addr,
- uint32_t ramsize,
- hwaddr initrd_base,
- hwaddr initrd_size,
- const char *kernel_cmdline)
-{
- int ret = -1;
- uint32_t mem_reg_property[] = { 0, 0, cpu_to_be32(ramsize) };
- char *filename;
- int fdt_size;
- void *fdt;
- uint32_t tb_freq = 400000000;
- uint32_t clock_freq = 400000000;
-
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
- if (!filename) {
- goto out;
- }
- fdt = load_device_tree(filename, &fdt_size);
- g_free(filename);
- if (fdt == NULL) {
- goto out;
- }
-
- /* Manipulate device tree in memory. */
-
- ret = qemu_fdt_setprop(fdt, "/memory", "reg", mem_reg_property,
- sizeof(mem_reg_property));
- if (ret < 0)
- fprintf(stderr, "couldn't set /memory/reg\n");
-
- ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start",
- initrd_base);
- if (ret < 0)
- fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
-
- ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
- (initrd_base + initrd_size));
- if (ret < 0)
- fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
-
- ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
- kernel_cmdline);
- if (ret < 0)
- fprintf(stderr, "couldn't set /chosen/bootargs\n");
-
- /* Copy data from the host device tree into the guest. Since the guest can
- * directly access the timebase without host involvement, we must expose
- * the correct frequencies. */
- if (kvm_enabled()) {
- tb_freq = kvmppc_get_tbfreq();
- clock_freq = kvmppc_get_clockfreq();
- }
-
- qemu_fdt_setprop_cell(fdt, "/cpus/cpu@0", "clock-frequency",
- clock_freq);
- qemu_fdt_setprop_cell(fdt, "/cpus/cpu@0", "timebase-frequency",
- tb_freq);
-
- rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
- g_free(fdt);
- return 0;
-
-out:
-
- return ret;
-}
-
-/* Create reset TLB entries for BookE, spanning the 32bit addr space. */
-static void mmubooke_create_initial_mapping(CPUPPCState *env,
- target_ulong va,
- hwaddr pa)
-{
- ppcemb_tlb_t *tlb = &env->tlb.tlbe[0];
-
- tlb->attr = 0;
- tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
- tlb->size = 1U << 31; /* up to 0x80000000 */
- tlb->EPN = va & TARGET_PAGE_MASK;
- tlb->RPN = pa & TARGET_PAGE_MASK;
- tlb->PID = 0;
-
- tlb = &env->tlb.tlbe[1];
- tlb->attr = 0;
- tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
- tlb->size = 1U << 31; /* up to 0xffffffff */
- tlb->EPN = 0x80000000 & TARGET_PAGE_MASK;
- tlb->RPN = 0x80000000 & TARGET_PAGE_MASK;
- tlb->PID = 0;
-}
-
-static void main_cpu_reset(void *opaque)
-{
- PowerPCCPU *cpu = opaque;
- CPUPPCState *env = &cpu->env;
-
- cpu_reset(CPU(cpu));
- env->gpr[1] = (16<<20) - 8;
- env->gpr[3] = FDT_ADDR;
- env->nip = entry;
-
- /* Create a mapping for the kernel. */
- mmubooke_create_initial_mapping(env, 0, 0);
-}
-
-static void bamboo_init(MachineState *machine)
-{
- ram_addr_t ram_size = machine->ram_size;
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- const char *initrd_filename = machine->initrd_filename;
- unsigned int pci_irq_nrs[4] = { 28, 27, 26, 25 };
- MemoryRegion *address_space_mem = get_system_memory();
- MemoryRegion *isa = g_new(MemoryRegion, 1);
- MemoryRegion *ram_memories
- = g_malloc(PPC440EP_SDRAM_NR_BANKS * sizeof(*ram_memories));
- hwaddr ram_bases[PPC440EP_SDRAM_NR_BANKS];
- hwaddr ram_sizes[PPC440EP_SDRAM_NR_BANKS];
- qemu_irq *pic;
- qemu_irq *irqs;
- PCIBus *pcibus;
- PowerPCCPU *cpu;
- CPUPPCState *env;
- uint64_t elf_entry;
- uint64_t elf_lowaddr;
- hwaddr loadaddr = 0;
- target_long initrd_size = 0;
- DeviceState *dev;
- int success;
- int i;
-
- /* Setup CPU. */
- if (machine->cpu_model == NULL) {
- machine->cpu_model = "440EP";
- }
- cpu = cpu_ppc_init(machine->cpu_model);
- if (cpu == NULL) {
- fprintf(stderr, "Unable to initialize CPU!\n");
- exit(1);
- }
- env = &cpu->env;
-
- qemu_register_reset(main_cpu_reset, cpu);
- ppc_booke_timers_init(cpu, 400000000, 0);
- ppc_dcr_init(env, NULL, NULL);
-
- /* interrupt controller */
- irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
- irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
- irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
- pic = ppcuic_init(env, irqs, 0x0C0, 0, 1);
-
- /* SDRAM controller */
- memset(ram_bases, 0, sizeof(ram_bases));
- memset(ram_sizes, 0, sizeof(ram_sizes));
- ram_size = ppc4xx_sdram_adjust(ram_size, PPC440EP_SDRAM_NR_BANKS,
- ram_memories,
- ram_bases, ram_sizes,
- ppc440ep_sdram_bank_sizes);
- /* XXX 440EP's ECC interrupts are on UIC1, but we've only created UIC0. */
- ppc4xx_sdram_init(env, pic[14], PPC440EP_SDRAM_NR_BANKS, ram_memories,
- ram_bases, ram_sizes, 1);
-
- /* PCI */
- dev = sysbus_create_varargs(TYPE_PPC4xx_PCI_HOST_BRIDGE,
- PPC440EP_PCI_CONFIG,
- pic[pci_irq_nrs[0]], pic[pci_irq_nrs[1]],
- pic[pci_irq_nrs[2]], pic[pci_irq_nrs[3]],
- NULL);
- pcibus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
- if (!pcibus) {
- fprintf(stderr, "couldn't create PCI controller!\n");
- exit(1);
- }
-
- memory_region_init_alias(isa, NULL, "isa_mmio",
- get_system_io(), 0, PPC440EP_PCI_IOLEN);
- memory_region_add_subregion(get_system_memory(), PPC440EP_PCI_IO, isa);
-
- if (serial_hds[0] != NULL) {
- serial_mm_init(address_space_mem, 0xef600300, 0, pic[0],
- PPC_SERIAL_MM_BAUDBASE, serial_hds[0],
- DEVICE_BIG_ENDIAN);
- }
- if (serial_hds[1] != NULL) {
- serial_mm_init(address_space_mem, 0xef600400, 0, pic[1],
- PPC_SERIAL_MM_BAUDBASE, serial_hds[1],
- DEVICE_BIG_ENDIAN);
- }
-
- if (pcibus) {
- /* Register network interfaces. */
- for (i = 0; i < nb_nics; i++) {
- /* There are no PCI NICs on the Bamboo board, but there are
- * PCI slots, so we can pick whatever default model we want. */
- pci_nic_init_nofail(&nd_table[i], pcibus, "e1000", NULL);
- }
- }
-
- /* Load kernel. */
- if (kernel_filename) {
- success = load_uimage(kernel_filename, &entry, &loadaddr, NULL,
- NULL, NULL);
- if (success < 0) {
- success = load_elf(kernel_filename, NULL, NULL, &elf_entry,
- &elf_lowaddr, NULL, 1, PPC_ELF_MACHINE,
- 0, 0);
- entry = elf_entry;
- loadaddr = elf_lowaddr;
- }
- /* XXX try again as binary */
- if (success < 0) {
- fprintf(stderr, "qemu: could not load kernel '%s'\n",
- kernel_filename);
- exit(1);
- }
- }
-
- /* Load initrd. */
- if (initrd_filename) {
- initrd_size = load_image_targphys(initrd_filename, RAMDISK_ADDR,
- ram_size - RAMDISK_ADDR);
-
- if (initrd_size < 0) {
- fprintf(stderr, "qemu: could not load ram disk '%s' at %x\n",
- initrd_filename, RAMDISK_ADDR);
- exit(1);
- }
- }
-
- /* If we're loading a kernel directly, we must load the device tree too. */
- if (kernel_filename) {
- if (bamboo_load_device_tree(FDT_ADDR, ram_size, RAMDISK_ADDR,
- initrd_size, kernel_cmdline) < 0) {
- fprintf(stderr, "couldn't load device tree\n");
- exit(1);
- }
- }
-}
-
-static void bamboo_machine_init(MachineClass *mc)
-{
- mc->desc = "bamboo";
- mc->init = bamboo_init;
-}
-
-DEFINE_MACHINE("bamboo", bamboo_machine_init)
diff --git a/qemu/hw/ppc/ppc4xx_devs.c b/qemu/hw/ppc/ppc4xx_devs.c
deleted file mode 100644
index 7d59018fc..000000000
--- a/qemu/hw/ppc/ppc4xx_devs.c
+++ /dev/null
@@ -1,735 +0,0 @@
-/*
- * QEMU PowerPC 4xx embedded processors shared devices emulation
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/ppc/ppc.h"
-#include "hw/ppc/ppc4xx.h"
-#include "hw/boards.h"
-#include "qemu/log.h"
-#include "exec/address-spaces.h"
-
-#define DEBUG_UIC
-
-
-#ifdef DEBUG_UIC
-# define LOG_UIC(...) qemu_log_mask(CPU_LOG_INT, ## __VA_ARGS__)
-#else
-# define LOG_UIC(...) do { } while (0)
-#endif
-
-static void ppc4xx_reset(void *opaque)
-{
- PowerPCCPU *cpu = opaque;
-
- cpu_reset(CPU(cpu));
-}
-
-/*****************************************************************************/
-/* Generic PowerPC 4xx processor instantiation */
-PowerPCCPU *ppc4xx_init(const char *cpu_model,
- clk_setup_t *cpu_clk, clk_setup_t *tb_clk,
- uint32_t sysclk)
-{
- PowerPCCPU *cpu;
- CPUPPCState *env;
-
- /* init CPUs */
- cpu = cpu_ppc_init(cpu_model);
- if (cpu == NULL) {
- fprintf(stderr, "Unable to find PowerPC %s CPU definition\n",
- cpu_model);
- exit(1);
- }
- env = &cpu->env;
-
- cpu_clk->cb = NULL; /* We don't care about CPU clock frequency changes */
- cpu_clk->opaque = env;
- /* Set time-base frequency to sysclk */
- tb_clk->cb = ppc_40x_timers_init(env, sysclk, PPC_INTERRUPT_PIT);
- tb_clk->opaque = env;
- ppc_dcr_init(env, NULL, NULL);
- /* Register qemu callbacks */
- qemu_register_reset(ppc4xx_reset, cpu);
-
- return cpu;
-}
-
-/*****************************************************************************/
-/* "Universal" Interrupt controller */
-enum {
- DCR_UICSR = 0x000,
- DCR_UICSRS = 0x001,
- DCR_UICER = 0x002,
- DCR_UICCR = 0x003,
- DCR_UICPR = 0x004,
- DCR_UICTR = 0x005,
- DCR_UICMSR = 0x006,
- DCR_UICVR = 0x007,
- DCR_UICVCR = 0x008,
- DCR_UICMAX = 0x009,
-};
-
-#define UIC_MAX_IRQ 32
-typedef struct ppcuic_t ppcuic_t;
-struct ppcuic_t {
- uint32_t dcr_base;
- int use_vectors;
- uint32_t level; /* Remembers the state of level-triggered interrupts. */
- uint32_t uicsr; /* Status register */
- uint32_t uicer; /* Enable register */
- uint32_t uiccr; /* Critical register */
- uint32_t uicpr; /* Polarity register */
- uint32_t uictr; /* Triggering register */
- uint32_t uicvcr; /* Vector configuration register */
- uint32_t uicvr;
- qemu_irq *irqs;
-};
-
-static void ppcuic_trigger_irq (ppcuic_t *uic)
-{
- uint32_t ir, cr;
- int start, end, inc, i;
-
- /* Trigger interrupt if any is pending */
- ir = uic->uicsr & uic->uicer & (~uic->uiccr);
- cr = uic->uicsr & uic->uicer & uic->uiccr;
- LOG_UIC("%s: uicsr %08" PRIx32 " uicer %08" PRIx32
- " uiccr %08" PRIx32 "\n"
- " %08" PRIx32 " ir %08" PRIx32 " cr %08" PRIx32 "\n",
- __func__, uic->uicsr, uic->uicer, uic->uiccr,
- uic->uicsr & uic->uicer, ir, cr);
- if (ir != 0x0000000) {
- LOG_UIC("Raise UIC interrupt\n");
- qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_INT]);
- } else {
- LOG_UIC("Lower UIC interrupt\n");
- qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_INT]);
- }
- /* Trigger critical interrupt if any is pending and update vector */
- if (cr != 0x0000000) {
- qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_CINT]);
- if (uic->use_vectors) {
- /* Compute critical IRQ vector */
- if (uic->uicvcr & 1) {
- start = 31;
- end = 0;
- inc = -1;
- } else {
- start = 0;
- end = 31;
- inc = 1;
- }
- uic->uicvr = uic->uicvcr & 0xFFFFFFFC;
- for (i = start; i <= end; i += inc) {
- if (cr & (1 << i)) {
- uic->uicvr += (i - start) * 512 * inc;
- break;
- }
- }
- }
- LOG_UIC("Raise UIC critical interrupt - "
- "vector %08" PRIx32 "\n", uic->uicvr);
- } else {
- LOG_UIC("Lower UIC critical interrupt\n");
- qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_CINT]);
- uic->uicvr = 0x00000000;
- }
-}
-
-static void ppcuic_set_irq (void *opaque, int irq_num, int level)
-{
- ppcuic_t *uic;
- uint32_t mask, sr;
-
- uic = opaque;
- mask = 1U << (31-irq_num);
- LOG_UIC("%s: irq %d level %d uicsr %08" PRIx32
- " mask %08" PRIx32 " => %08" PRIx32 " %08" PRIx32 "\n",
- __func__, irq_num, level,
- uic->uicsr, mask, uic->uicsr & mask, level << irq_num);
- if (irq_num < 0 || irq_num > 31)
- return;
- sr = uic->uicsr;
-
- /* Update status register */
- if (uic->uictr & mask) {
- /* Edge sensitive interrupt */
- if (level == 1)
- uic->uicsr |= mask;
- } else {
- /* Level sensitive interrupt */
- if (level == 1) {
- uic->uicsr |= mask;
- uic->level |= mask;
- } else {
- uic->uicsr &= ~mask;
- uic->level &= ~mask;
- }
- }
- LOG_UIC("%s: irq %d level %d sr %" PRIx32 " => "
- "%08" PRIx32 "\n", __func__, irq_num, level, uic->uicsr, sr);
- if (sr != uic->uicsr)
- ppcuic_trigger_irq(uic);
-}
-
-static uint32_t dcr_read_uic (void *opaque, int dcrn)
-{
- ppcuic_t *uic;
- uint32_t ret;
-
- uic = opaque;
- dcrn -= uic->dcr_base;
- switch (dcrn) {
- case DCR_UICSR:
- case DCR_UICSRS:
- ret = uic->uicsr;
- break;
- case DCR_UICER:
- ret = uic->uicer;
- break;
- case DCR_UICCR:
- ret = uic->uiccr;
- break;
- case DCR_UICPR:
- ret = uic->uicpr;
- break;
- case DCR_UICTR:
- ret = uic->uictr;
- break;
- case DCR_UICMSR:
- ret = uic->uicsr & uic->uicer;
- break;
- case DCR_UICVR:
- if (!uic->use_vectors)
- goto no_read;
- ret = uic->uicvr;
- break;
- case DCR_UICVCR:
- if (!uic->use_vectors)
- goto no_read;
- ret = uic->uicvcr;
- break;
- default:
- no_read:
- ret = 0x00000000;
- break;
- }
-
- return ret;
-}
-
-static void dcr_write_uic (void *opaque, int dcrn, uint32_t val)
-{
- ppcuic_t *uic;
-
- uic = opaque;
- dcrn -= uic->dcr_base;
- LOG_UIC("%s: dcr %d val 0x%x\n", __func__, dcrn, val);
- switch (dcrn) {
- case DCR_UICSR:
- uic->uicsr &= ~val;
- uic->uicsr |= uic->level;
- ppcuic_trigger_irq(uic);
- break;
- case DCR_UICSRS:
- uic->uicsr |= val;
- ppcuic_trigger_irq(uic);
- break;
- case DCR_UICER:
- uic->uicer = val;
- ppcuic_trigger_irq(uic);
- break;
- case DCR_UICCR:
- uic->uiccr = val;
- ppcuic_trigger_irq(uic);
- break;
- case DCR_UICPR:
- uic->uicpr = val;
- break;
- case DCR_UICTR:
- uic->uictr = val;
- ppcuic_trigger_irq(uic);
- break;
- case DCR_UICMSR:
- break;
- case DCR_UICVR:
- break;
- case DCR_UICVCR:
- uic->uicvcr = val & 0xFFFFFFFD;
- ppcuic_trigger_irq(uic);
- break;
- }
-}
-
-static void ppcuic_reset (void *opaque)
-{
- ppcuic_t *uic;
-
- uic = opaque;
- uic->uiccr = 0x00000000;
- uic->uicer = 0x00000000;
- uic->uicpr = 0x00000000;
- uic->uicsr = 0x00000000;
- uic->uictr = 0x00000000;
- if (uic->use_vectors) {
- uic->uicvcr = 0x00000000;
- uic->uicvr = 0x0000000;
- }
-}
-
-qemu_irq *ppcuic_init (CPUPPCState *env, qemu_irq *irqs,
- uint32_t dcr_base, int has_ssr, int has_vr)
-{
- ppcuic_t *uic;
- int i;
-
- uic = g_malloc0(sizeof(ppcuic_t));
- uic->dcr_base = dcr_base;
- uic->irqs = irqs;
- if (has_vr)
- uic->use_vectors = 1;
- for (i = 0; i < DCR_UICMAX; i++) {
- ppc_dcr_register(env, dcr_base + i, uic,
- &dcr_read_uic, &dcr_write_uic);
- }
- qemu_register_reset(ppcuic_reset, uic);
-
- return qemu_allocate_irqs(&ppcuic_set_irq, uic, UIC_MAX_IRQ);
-}
-
-/*****************************************************************************/
-/* SDRAM controller */
-typedef struct ppc4xx_sdram_t ppc4xx_sdram_t;
-struct ppc4xx_sdram_t {
- uint32_t addr;
- int nbanks;
- MemoryRegion containers[4]; /* used for clipping */
- MemoryRegion *ram_memories;
- hwaddr ram_bases[4];
- hwaddr ram_sizes[4];
- uint32_t besr0;
- uint32_t besr1;
- uint32_t bear;
- uint32_t cfg;
- uint32_t status;
- uint32_t rtr;
- uint32_t pmit;
- uint32_t bcr[4];
- uint32_t tr;
- uint32_t ecccfg;
- uint32_t eccesr;
- qemu_irq irq;
-};
-
-enum {
- SDRAM0_CFGADDR = 0x010,
- SDRAM0_CFGDATA = 0x011,
-};
-
-/* XXX: TOFIX: some patches have made this code become inconsistent:
- * there are type inconsistencies, mixing hwaddr, target_ulong
- * and uint32_t
- */
-static uint32_t sdram_bcr (hwaddr ram_base,
- hwaddr ram_size)
-{
- uint32_t bcr;
-
- switch (ram_size) {
- case (4 * 1024 * 1024):
- bcr = 0x00000000;
- break;
- case (8 * 1024 * 1024):
- bcr = 0x00020000;
- break;
- case (16 * 1024 * 1024):
- bcr = 0x00040000;
- break;
- case (32 * 1024 * 1024):
- bcr = 0x00060000;
- break;
- case (64 * 1024 * 1024):
- bcr = 0x00080000;
- break;
- case (128 * 1024 * 1024):
- bcr = 0x000A0000;
- break;
- case (256 * 1024 * 1024):
- bcr = 0x000C0000;
- break;
- default:
- printf("%s: invalid RAM size " TARGET_FMT_plx "\n", __func__,
- ram_size);
- return 0x00000000;
- }
- bcr |= ram_base & 0xFF800000;
- bcr |= 1;
-
- return bcr;
-}
-
-static inline hwaddr sdram_base(uint32_t bcr)
-{
- return bcr & 0xFF800000;
-}
-
-static target_ulong sdram_size (uint32_t bcr)
-{
- target_ulong size;
- int sh;
-
- sh = (bcr >> 17) & 0x7;
- if (sh == 7)
- size = -1;
- else
- size = (4 * 1024 * 1024) << sh;
-
- return size;
-}
-
-static void sdram_set_bcr(ppc4xx_sdram_t *sdram,
- uint32_t *bcrp, uint32_t bcr, int enabled)
-{
- unsigned n = bcrp - sdram->bcr;
-
- if (*bcrp & 0x00000001) {
- /* Unmap RAM */
-#ifdef DEBUG_SDRAM
- printf("%s: unmap RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n",
- __func__, sdram_base(*bcrp), sdram_size(*bcrp));
-#endif
- memory_region_del_subregion(get_system_memory(),
- &sdram->containers[n]);
- memory_region_del_subregion(&sdram->containers[n],
- &sdram->ram_memories[n]);
- object_unparent(OBJECT(&sdram->containers[n]));
- }
- *bcrp = bcr & 0xFFDEE001;
- if (enabled && (bcr & 0x00000001)) {
-#ifdef DEBUG_SDRAM
- printf("%s: Map RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n",
- __func__, sdram_base(bcr), sdram_size(bcr));
-#endif
- memory_region_init(&sdram->containers[n], NULL, "sdram-containers",
- sdram_size(bcr));
- memory_region_add_subregion(&sdram->containers[n], 0,
- &sdram->ram_memories[n]);
- memory_region_add_subregion(get_system_memory(),
- sdram_base(bcr),
- &sdram->containers[n]);
- }
-}
-
-static void sdram_map_bcr (ppc4xx_sdram_t *sdram)
-{
- int i;
-
- for (i = 0; i < sdram->nbanks; i++) {
- if (sdram->ram_sizes[i] != 0) {
- sdram_set_bcr(sdram,
- &sdram->bcr[i],
- sdram_bcr(sdram->ram_bases[i], sdram->ram_sizes[i]),
- 1);
- } else {
- sdram_set_bcr(sdram, &sdram->bcr[i], 0x00000000, 0);
- }
- }
-}
-
-static void sdram_unmap_bcr (ppc4xx_sdram_t *sdram)
-{
- int i;
-
- for (i = 0; i < sdram->nbanks; i++) {
-#ifdef DEBUG_SDRAM
- printf("%s: Unmap RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n",
- __func__, sdram_base(sdram->bcr[i]), sdram_size(sdram->bcr[i]));
-#endif
- memory_region_del_subregion(get_system_memory(),
- &sdram->ram_memories[i]);
- }
-}
-
-static uint32_t dcr_read_sdram (void *opaque, int dcrn)
-{
- ppc4xx_sdram_t *sdram;
- uint32_t ret;
-
- sdram = opaque;
- switch (dcrn) {
- case SDRAM0_CFGADDR:
- ret = sdram->addr;
- break;
- case SDRAM0_CFGDATA:
- switch (sdram->addr) {
- case 0x00: /* SDRAM_BESR0 */
- ret = sdram->besr0;
- break;
- case 0x08: /* SDRAM_BESR1 */
- ret = sdram->besr1;
- break;
- case 0x10: /* SDRAM_BEAR */
- ret = sdram->bear;
- break;
- case 0x20: /* SDRAM_CFG */
- ret = sdram->cfg;
- break;
- case 0x24: /* SDRAM_STATUS */
- ret = sdram->status;
- break;
- case 0x30: /* SDRAM_RTR */
- ret = sdram->rtr;
- break;
- case 0x34: /* SDRAM_PMIT */
- ret = sdram->pmit;
- break;
- case 0x40: /* SDRAM_B0CR */
- ret = sdram->bcr[0];
- break;
- case 0x44: /* SDRAM_B1CR */
- ret = sdram->bcr[1];
- break;
- case 0x48: /* SDRAM_B2CR */
- ret = sdram->bcr[2];
- break;
- case 0x4C: /* SDRAM_B3CR */
- ret = sdram->bcr[3];
- break;
- case 0x80: /* SDRAM_TR */
- ret = -1; /* ? */
- break;
- case 0x94: /* SDRAM_ECCCFG */
- ret = sdram->ecccfg;
- break;
- case 0x98: /* SDRAM_ECCESR */
- ret = sdram->eccesr;
- break;
- default: /* Error */
- ret = -1;
- break;
- }
- break;
- default:
- /* Avoid gcc warning */
- ret = 0x00000000;
- break;
- }
-
- return ret;
-}
-
-static void dcr_write_sdram (void *opaque, int dcrn, uint32_t val)
-{
- ppc4xx_sdram_t *sdram;
-
- sdram = opaque;
- switch (dcrn) {
- case SDRAM0_CFGADDR:
- sdram->addr = val;
- break;
- case SDRAM0_CFGDATA:
- switch (sdram->addr) {
- case 0x00: /* SDRAM_BESR0 */
- sdram->besr0 &= ~val;
- break;
- case 0x08: /* SDRAM_BESR1 */
- sdram->besr1 &= ~val;
- break;
- case 0x10: /* SDRAM_BEAR */
- sdram->bear = val;
- break;
- case 0x20: /* SDRAM_CFG */
- val &= 0xFFE00000;
- if (!(sdram->cfg & 0x80000000) && (val & 0x80000000)) {
-#ifdef DEBUG_SDRAM
- printf("%s: enable SDRAM controller\n", __func__);
-#endif
- /* validate all RAM mappings */
- sdram_map_bcr(sdram);
- sdram->status &= ~0x80000000;
- } else if ((sdram->cfg & 0x80000000) && !(val & 0x80000000)) {
-#ifdef DEBUG_SDRAM
- printf("%s: disable SDRAM controller\n", __func__);
-#endif
- /* invalidate all RAM mappings */
- sdram_unmap_bcr(sdram);
- sdram->status |= 0x80000000;
- }
- if (!(sdram->cfg & 0x40000000) && (val & 0x40000000))
- sdram->status |= 0x40000000;
- else if ((sdram->cfg & 0x40000000) && !(val & 0x40000000))
- sdram->status &= ~0x40000000;
- sdram->cfg = val;
- break;
- case 0x24: /* SDRAM_STATUS */
- /* Read-only register */
- break;
- case 0x30: /* SDRAM_RTR */
- sdram->rtr = val & 0x3FF80000;
- break;
- case 0x34: /* SDRAM_PMIT */
- sdram->pmit = (val & 0xF8000000) | 0x07C00000;
- break;
- case 0x40: /* SDRAM_B0CR */
- sdram_set_bcr(sdram, &sdram->bcr[0], val, sdram->cfg & 0x80000000);
- break;
- case 0x44: /* SDRAM_B1CR */
- sdram_set_bcr(sdram, &sdram->bcr[1], val, sdram->cfg & 0x80000000);
- break;
- case 0x48: /* SDRAM_B2CR */
- sdram_set_bcr(sdram, &sdram->bcr[2], val, sdram->cfg & 0x80000000);
- break;
- case 0x4C: /* SDRAM_B3CR */
- sdram_set_bcr(sdram, &sdram->bcr[3], val, sdram->cfg & 0x80000000);
- break;
- case 0x80: /* SDRAM_TR */
- sdram->tr = val & 0x018FC01F;
- break;
- case 0x94: /* SDRAM_ECCCFG */
- sdram->ecccfg = val & 0x00F00000;
- break;
- case 0x98: /* SDRAM_ECCESR */
- val &= 0xFFF0F000;
- if (sdram->eccesr == 0 && val != 0)
- qemu_irq_raise(sdram->irq);
- else if (sdram->eccesr != 0 && val == 0)
- qemu_irq_lower(sdram->irq);
- sdram->eccesr = val;
- break;
- default: /* Error */
- break;
- }
- break;
- }
-}
-
-static void sdram_reset (void *opaque)
-{
- ppc4xx_sdram_t *sdram;
-
- sdram = opaque;
- sdram->addr = 0x00000000;
- sdram->bear = 0x00000000;
- sdram->besr0 = 0x00000000; /* No error */
- sdram->besr1 = 0x00000000; /* No error */
- sdram->cfg = 0x00000000;
- sdram->ecccfg = 0x00000000; /* No ECC */
- sdram->eccesr = 0x00000000; /* No error */
- sdram->pmit = 0x07C00000;
- sdram->rtr = 0x05F00000;
- sdram->tr = 0x00854009;
- /* We pre-initialize RAM banks */
- sdram->status = 0x00000000;
- sdram->cfg = 0x00800000;
-}
-
-void ppc4xx_sdram_init (CPUPPCState *env, qemu_irq irq, int nbanks,
- MemoryRegion *ram_memories,
- hwaddr *ram_bases,
- hwaddr *ram_sizes,
- int do_init)
-{
- ppc4xx_sdram_t *sdram;
-
- sdram = g_malloc0(sizeof(ppc4xx_sdram_t));
- sdram->irq = irq;
- sdram->nbanks = nbanks;
- sdram->ram_memories = ram_memories;
- memset(sdram->ram_bases, 0, 4 * sizeof(hwaddr));
- memcpy(sdram->ram_bases, ram_bases,
- nbanks * sizeof(hwaddr));
- memset(sdram->ram_sizes, 0, 4 * sizeof(hwaddr));
- memcpy(sdram->ram_sizes, ram_sizes,
- nbanks * sizeof(hwaddr));
- qemu_register_reset(&sdram_reset, sdram);
- ppc_dcr_register(env, SDRAM0_CFGADDR,
- sdram, &dcr_read_sdram, &dcr_write_sdram);
- ppc_dcr_register(env, SDRAM0_CFGDATA,
- sdram, &dcr_read_sdram, &dcr_write_sdram);
- if (do_init)
- sdram_map_bcr(sdram);
-}
-
-/* Fill in consecutive SDRAM banks with 'ram_size' bytes of memory.
- *
- * sdram_bank_sizes[] must be 0-terminated.
- *
- * The 4xx SDRAM controller supports a small number of banks, and each bank
- * must be one of a small set of sizes. The number of banks and the supported
- * sizes varies by SoC. */
-ram_addr_t ppc4xx_sdram_adjust(ram_addr_t ram_size, int nr_banks,
- MemoryRegion ram_memories[],
- hwaddr ram_bases[],
- hwaddr ram_sizes[],
- const unsigned int sdram_bank_sizes[])
-{
- MemoryRegion *ram = g_malloc0(sizeof(*ram));
- ram_addr_t size_left = ram_size;
- ram_addr_t base = 0;
- unsigned int bank_size;
- int i;
- int j;
-
- for (i = 0; i < nr_banks; i++) {
- for (j = 0; sdram_bank_sizes[j] != 0; j++) {
- bank_size = sdram_bank_sizes[j];
- if (bank_size <= size_left) {
- size_left -= bank_size;
- }
- }
- if (!size_left) {
- /* No need to use the remaining banks. */
- break;
- }
- }
-
- ram_size -= size_left;
- if (size_left) {
- printf("Truncating memory to %d MiB to fit SDRAM controller limits.\n",
- (int)(ram_size >> 20));
- }
-
- memory_region_allocate_system_memory(ram, NULL, "ppc4xx.sdram", ram_size);
-
- size_left = ram_size;
- for (i = 0; i < nr_banks && size_left; i++) {
- for (j = 0; sdram_bank_sizes[j] != 0; j++) {
- bank_size = sdram_bank_sizes[j];
-
- if (bank_size <= size_left) {
- char name[32];
- snprintf(name, sizeof(name), "ppc4xx.sdram%d", i);
- memory_region_init_alias(&ram_memories[i], NULL, name, ram,
- base, bank_size);
- ram_bases[i] = base;
- ram_sizes[i] = bank_size;
- base += bank_size;
- size_left -= bank_size;
- break;
- }
- }
- }
-
- return ram_size;
-}
diff --git a/qemu/hw/ppc/ppc4xx_pci.c b/qemu/hw/ppc/ppc4xx_pci.c
deleted file mode 100644
index 683218e5c..000000000
--- a/qemu/hw/ppc/ppc4xx_pci.c
+++ /dev/null
@@ -1,393 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, version 2, as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- * Copyright IBM Corp. 2008
- *
- * Authors: Hollis Blanchard <hollisb@us.ibm.com>
- */
-
-/* This file implements emulation of the 32-bit PCI controller found in some
- * 4xx SoCs, such as the 440EP. */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/ppc/ppc.h"
-#include "hw/ppc/ppc4xx.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/pci_host.h"
-#include "exec/address-spaces.h"
-
-#undef DEBUG
-#ifdef DEBUG
-#define DPRINTF(fmt, ...) do { printf(fmt, ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...)
-#endif /* DEBUG */
-
-struct PCIMasterMap {
- uint32_t la;
- uint32_t ma;
- uint32_t pcila;
- uint32_t pciha;
-};
-
-struct PCITargetMap {
- uint32_t ms;
- uint32_t la;
-};
-
-#define PPC4xx_PCI_HOST_BRIDGE(obj) \
- OBJECT_CHECK(PPC4xxPCIState, (obj), TYPE_PPC4xx_PCI_HOST_BRIDGE)
-
-#define PPC4xx_PCI_NR_PMMS 3
-#define PPC4xx_PCI_NR_PTMS 2
-
-struct PPC4xxPCIState {
- PCIHostState parent_obj;
-
- struct PCIMasterMap pmm[PPC4xx_PCI_NR_PMMS];
- struct PCITargetMap ptm[PPC4xx_PCI_NR_PTMS];
- qemu_irq irq[4];
-
- MemoryRegion container;
- MemoryRegion iomem;
-};
-typedef struct PPC4xxPCIState PPC4xxPCIState;
-
-#define PCIC0_CFGADDR 0x0
-#define PCIC0_CFGDATA 0x4
-
-/* PLB Memory Map (PMM) registers specify which PLB addresses are translated to
- * PCI accesses. */
-#define PCIL0_PMM0LA 0x0
-#define PCIL0_PMM0MA 0x4
-#define PCIL0_PMM0PCILA 0x8
-#define PCIL0_PMM0PCIHA 0xc
-#define PCIL0_PMM1LA 0x10
-#define PCIL0_PMM1MA 0x14
-#define PCIL0_PMM1PCILA 0x18
-#define PCIL0_PMM1PCIHA 0x1c
-#define PCIL0_PMM2LA 0x20
-#define PCIL0_PMM2MA 0x24
-#define PCIL0_PMM2PCILA 0x28
-#define PCIL0_PMM2PCIHA 0x2c
-
-/* PCI Target Map (PTM) registers specify which PCI addresses are translated to
- * PLB accesses. */
-#define PCIL0_PTM1MS 0x30
-#define PCIL0_PTM1LA 0x34
-#define PCIL0_PTM2MS 0x38
-#define PCIL0_PTM2LA 0x3c
-#define PCI_REG_BASE 0x800000
-#define PCI_REG_SIZE 0x40
-
-#define PCI_ALL_SIZE (PCI_REG_BASE + PCI_REG_SIZE)
-
-static void ppc4xx_pci_reg_write4(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- struct PPC4xxPCIState *pci = opaque;
-
- /* We ignore all target attempts at PCI configuration, effectively
- * assuming a bidirectional 1:1 mapping of PLB and PCI space. */
-
- switch (offset) {
- case PCIL0_PMM0LA:
- pci->pmm[0].la = value;
- break;
- case PCIL0_PMM0MA:
- pci->pmm[0].ma = value;
- break;
- case PCIL0_PMM0PCIHA:
- pci->pmm[0].pciha = value;
- break;
- case PCIL0_PMM0PCILA:
- pci->pmm[0].pcila = value;
- break;
-
- case PCIL0_PMM1LA:
- pci->pmm[1].la = value;
- break;
- case PCIL0_PMM1MA:
- pci->pmm[1].ma = value;
- break;
- case PCIL0_PMM1PCIHA:
- pci->pmm[1].pciha = value;
- break;
- case PCIL0_PMM1PCILA:
- pci->pmm[1].pcila = value;
- break;
-
- case PCIL0_PMM2LA:
- pci->pmm[2].la = value;
- break;
- case PCIL0_PMM2MA:
- pci->pmm[2].ma = value;
- break;
- case PCIL0_PMM2PCIHA:
- pci->pmm[2].pciha = value;
- break;
- case PCIL0_PMM2PCILA:
- pci->pmm[2].pcila = value;
- break;
-
- case PCIL0_PTM1MS:
- pci->ptm[0].ms = value;
- break;
- case PCIL0_PTM1LA:
- pci->ptm[0].la = value;
- break;
- case PCIL0_PTM2MS:
- pci->ptm[1].ms = value;
- break;
- case PCIL0_PTM2LA:
- pci->ptm[1].la = value;
- break;
-
- default:
- printf("%s: unhandled PCI internal register 0x%lx\n", __func__,
- (unsigned long)offset);
- break;
- }
-}
-
-static uint64_t ppc4xx_pci_reg_read4(void *opaque, hwaddr offset,
- unsigned size)
-{
- struct PPC4xxPCIState *pci = opaque;
- uint32_t value;
-
- switch (offset) {
- case PCIL0_PMM0LA:
- value = pci->pmm[0].la;
- break;
- case PCIL0_PMM0MA:
- value = pci->pmm[0].ma;
- break;
- case PCIL0_PMM0PCIHA:
- value = pci->pmm[0].pciha;
- break;
- case PCIL0_PMM0PCILA:
- value = pci->pmm[0].pcila;
- break;
-
- case PCIL0_PMM1LA:
- value = pci->pmm[1].la;
- break;
- case PCIL0_PMM1MA:
- value = pci->pmm[1].ma;
- break;
- case PCIL0_PMM1PCIHA:
- value = pci->pmm[1].pciha;
- break;
- case PCIL0_PMM1PCILA:
- value = pci->pmm[1].pcila;
- break;
-
- case PCIL0_PMM2LA:
- value = pci->pmm[2].la;
- break;
- case PCIL0_PMM2MA:
- value = pci->pmm[2].ma;
- break;
- case PCIL0_PMM2PCIHA:
- value = pci->pmm[2].pciha;
- break;
- case PCIL0_PMM2PCILA:
- value = pci->pmm[2].pcila;
- break;
-
- case PCIL0_PTM1MS:
- value = pci->ptm[0].ms;
- break;
- case PCIL0_PTM1LA:
- value = pci->ptm[0].la;
- break;
- case PCIL0_PTM2MS:
- value = pci->ptm[1].ms;
- break;
- case PCIL0_PTM2LA:
- value = pci->ptm[1].la;
- break;
-
- default:
- printf("%s: invalid PCI internal register 0x%lx\n", __func__,
- (unsigned long)offset);
- value = 0;
- }
-
- return value;
-}
-
-static const MemoryRegionOps pci_reg_ops = {
- .read = ppc4xx_pci_reg_read4,
- .write = ppc4xx_pci_reg_write4,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void ppc4xx_pci_reset(void *opaque)
-{
- struct PPC4xxPCIState *pci = opaque;
-
- memset(pci->pmm, 0, sizeof(pci->pmm));
- memset(pci->ptm, 0, sizeof(pci->ptm));
-}
-
-/* On Bamboo, all pins from each slot are tied to a single board IRQ. This
- * may need further refactoring for other boards. */
-static int ppc4xx_pci_map_irq(PCIDevice *pci_dev, int irq_num)
-{
- int slot = pci_dev->devfn >> 3;
-
- DPRINTF("%s: devfn %x irq %d -> %d\n", __func__,
- pci_dev->devfn, irq_num, slot);
-
- return slot - 1;
-}
-
-static void ppc4xx_pci_set_irq(void *opaque, int irq_num, int level)
-{
- qemu_irq *pci_irqs = opaque;
-
- DPRINTF("%s: PCI irq %d\n", __func__, irq_num);
- if (irq_num < 0) {
- fprintf(stderr, "%s: PCI irq %d\n", __func__, irq_num);
- return;
- }
- qemu_set_irq(pci_irqs[irq_num], level);
-}
-
-static const VMStateDescription vmstate_pci_master_map = {
- .name = "pci_master_map",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(la, struct PCIMasterMap),
- VMSTATE_UINT32(ma, struct PCIMasterMap),
- VMSTATE_UINT32(pcila, struct PCIMasterMap),
- VMSTATE_UINT32(pciha, struct PCIMasterMap),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_pci_target_map = {
- .name = "pci_target_map",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(ms, struct PCITargetMap),
- VMSTATE_UINT32(la, struct PCITargetMap),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_ppc4xx_pci = {
- .name = "ppc4xx_pci",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT_ARRAY(pmm, PPC4xxPCIState, PPC4xx_PCI_NR_PMMS, 1,
- vmstate_pci_master_map,
- struct PCIMasterMap),
- VMSTATE_STRUCT_ARRAY(ptm, PPC4xxPCIState, PPC4xx_PCI_NR_PTMS, 1,
- vmstate_pci_target_map,
- struct PCITargetMap),
- VMSTATE_END_OF_LIST()
- }
-};
-
-/* XXX Interrupt acknowledge cycles not supported. */
-static int ppc4xx_pcihost_initfn(SysBusDevice *dev)
-{
- PPC4xxPCIState *s;
- PCIHostState *h;
- PCIBus *b;
- int i;
-
- h = PCI_HOST_BRIDGE(dev);
- s = PPC4xx_PCI_HOST_BRIDGE(dev);
-
- for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
- sysbus_init_irq(dev, &s->irq[i]);
- }
-
- b = pci_register_bus(DEVICE(dev), NULL, ppc4xx_pci_set_irq,
- ppc4xx_pci_map_irq, s->irq, get_system_memory(),
- get_system_io(), 0, 4, TYPE_PCI_BUS);
- h->bus = b;
-
- pci_create_simple(b, 0, "ppc4xx-host-bridge");
-
- /* XXX split into 2 memory regions, one for config space, one for regs */
- memory_region_init(&s->container, OBJECT(s), "pci-container", PCI_ALL_SIZE);
- memory_region_init_io(&h->conf_mem, OBJECT(s), &pci_host_conf_le_ops, h,
- "pci-conf-idx", 4);
- memory_region_init_io(&h->data_mem, OBJECT(s), &pci_host_data_le_ops, h,
- "pci-conf-data", 4);
- memory_region_init_io(&s->iomem, OBJECT(s), &pci_reg_ops, s,
- "pci.reg", PCI_REG_SIZE);
- memory_region_add_subregion(&s->container, PCIC0_CFGADDR, &h->conf_mem);
- memory_region_add_subregion(&s->container, PCIC0_CFGDATA, &h->data_mem);
- memory_region_add_subregion(&s->container, PCI_REG_BASE, &s->iomem);
- sysbus_init_mmio(dev, &s->container);
- qemu_register_reset(ppc4xx_pci_reset, s);
-
- return 0;
-}
-
-static void ppc4xx_host_bridge_class_init(ObjectClass *klass, void *data)
-{
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->desc = "Host bridge";
- k->vendor_id = PCI_VENDOR_ID_IBM;
- k->device_id = PCI_DEVICE_ID_IBM_440GX;
- k->class_id = PCI_CLASS_BRIDGE_OTHER;
- /*
- * PCI-facing part of the host bridge, not usable without the
- * host-facing part, which can't be device_add'ed, yet.
- */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo ppc4xx_host_bridge_info = {
- .name = "ppc4xx-host-bridge",
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(PCIDevice),
- .class_init = ppc4xx_host_bridge_class_init,
-};
-
-static void ppc4xx_pcihost_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- k->init = ppc4xx_pcihost_initfn;
- dc->vmsd = &vmstate_ppc4xx_pci;
-}
-
-static const TypeInfo ppc4xx_pcihost_info = {
- .name = TYPE_PPC4xx_PCI_HOST_BRIDGE,
- .parent = TYPE_PCI_HOST_BRIDGE,
- .instance_size = sizeof(PPC4xxPCIState),
- .class_init = ppc4xx_pcihost_class_init,
-};
-
-static void ppc4xx_pci_register_types(void)
-{
- type_register_static(&ppc4xx_pcihost_info);
- type_register_static(&ppc4xx_host_bridge_info);
-}
-
-type_init(ppc4xx_pci_register_types)
diff --git a/qemu/hw/ppc/ppc_booke.c b/qemu/hw/ppc/ppc_booke.c
deleted file mode 100644
index ab8d026c3..000000000
--- a/qemu/hw/ppc/ppc_booke.c
+++ /dev/null
@@ -1,368 +0,0 @@
-/*
- * QEMU PowerPC Booke hardware System Emulator
- *
- * Copyright (c) 2011 AdaCore
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/hw.h"
-#include "hw/ppc/ppc.h"
-#include "qemu/timer.h"
-#include "sysemu/sysemu.h"
-#include "hw/timer/m48t59.h"
-#include "qemu/log.h"
-#include "hw/loader.h"
-#include "kvm_ppc.h"
-
-
-/* Timer Control Register */
-
-#define TCR_WP_SHIFT 30 /* Watchdog Timer Period */
-#define TCR_WP_MASK (0x3U << TCR_WP_SHIFT)
-#define TCR_WRC_SHIFT 28 /* Watchdog Timer Reset Control */
-#define TCR_WRC_MASK (0x3U << TCR_WRC_SHIFT)
-#define TCR_WIE (1U << 27) /* Watchdog Timer Interrupt Enable */
-#define TCR_DIE (1U << 26) /* Decrementer Interrupt Enable */
-#define TCR_FP_SHIFT 24 /* Fixed-Interval Timer Period */
-#define TCR_FP_MASK (0x3U << TCR_FP_SHIFT)
-#define TCR_FIE (1U << 23) /* Fixed-Interval Timer Interrupt Enable */
-#define TCR_ARE (1U << 22) /* Auto-Reload Enable */
-
-/* Timer Control Register (e500 specific fields) */
-
-#define TCR_E500_FPEXT_SHIFT 13 /* Fixed-Interval Timer Period Extension */
-#define TCR_E500_FPEXT_MASK (0xf << TCR_E500_FPEXT_SHIFT)
-#define TCR_E500_WPEXT_SHIFT 17 /* Watchdog Timer Period Extension */
-#define TCR_E500_WPEXT_MASK (0xf << TCR_E500_WPEXT_SHIFT)
-
-/* Timer Status Register */
-
-#define TSR_FIS (1U << 26) /* Fixed-Interval Timer Interrupt Status */
-#define TSR_DIS (1U << 27) /* Decrementer Interrupt Status */
-#define TSR_WRS_SHIFT 28 /* Watchdog Timer Reset Status */
-#define TSR_WRS_MASK (0x3U << TSR_WRS_SHIFT)
-#define TSR_WIS (1U << 30) /* Watchdog Timer Interrupt Status */
-#define TSR_ENW (1U << 31) /* Enable Next Watchdog Timer */
-
-typedef struct booke_timer_t booke_timer_t;
-struct booke_timer_t {
-
- uint64_t fit_next;
- QEMUTimer *fit_timer;
-
- uint64_t wdt_next;
- QEMUTimer *wdt_timer;
-
- uint32_t flags;
-};
-
-static void booke_update_irq(PowerPCCPU *cpu)
-{
- CPUPPCState *env = &cpu->env;
-
- ppc_set_irq(cpu, PPC_INTERRUPT_DECR,
- (env->spr[SPR_BOOKE_TSR] & TSR_DIS
- && env->spr[SPR_BOOKE_TCR] & TCR_DIE));
-
- ppc_set_irq(cpu, PPC_INTERRUPT_WDT,
- (env->spr[SPR_BOOKE_TSR] & TSR_WIS
- && env->spr[SPR_BOOKE_TCR] & TCR_WIE));
-
- ppc_set_irq(cpu, PPC_INTERRUPT_FIT,
- (env->spr[SPR_BOOKE_TSR] & TSR_FIS
- && env->spr[SPR_BOOKE_TCR] & TCR_FIE));
-}
-
-/* Return the location of the bit of time base at which the FIT will raise an
- interrupt */
-static uint8_t booke_get_fit_target(CPUPPCState *env, ppc_tb_t *tb_env)
-{
- uint8_t fp = (env->spr[SPR_BOOKE_TCR] & TCR_FP_MASK) >> TCR_FP_SHIFT;
-
- if (tb_env->flags & PPC_TIMER_E500) {
- /* e500 Fixed-interval timer period extension */
- uint32_t fpext = (env->spr[SPR_BOOKE_TCR] & TCR_E500_FPEXT_MASK)
- >> TCR_E500_FPEXT_SHIFT;
- fp = 63 - (fp | fpext << 2);
- } else {
- fp = env->fit_period[fp];
- }
-
- return fp;
-}
-
-/* Return the location of the bit of time base at which the WDT will raise an
- interrupt */
-static uint8_t booke_get_wdt_target(CPUPPCState *env, ppc_tb_t *tb_env)
-{
- uint8_t wp = (env->spr[SPR_BOOKE_TCR] & TCR_WP_MASK) >> TCR_WP_SHIFT;
-
- if (tb_env->flags & PPC_TIMER_E500) {
- /* e500 Watchdog timer period extension */
- uint32_t wpext = (env->spr[SPR_BOOKE_TCR] & TCR_E500_WPEXT_MASK)
- >> TCR_E500_WPEXT_SHIFT;
- wp = 63 - (wp | wpext << 2);
- } else {
- wp = env->wdt_period[wp];
- }
-
- return wp;
-}
-
-static void booke_update_fixed_timer(CPUPPCState *env,
- uint8_t target_bit,
- uint64_t *next,
- QEMUTimer *timer,
- int tsr_bit)
-{
- ppc_tb_t *tb_env = env->tb_env;
- uint64_t delta_tick, ticks = 0;
- uint64_t tb;
- uint64_t period;
- uint64_t now;
-
- if (!(env->spr[SPR_BOOKE_TSR] & tsr_bit)) {
- /*
- * Don't arm the timer again when the guest has the current
- * interrupt still pending. Wait for it to ack it.
- */
- return;
- }
-
- now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- tb = cpu_ppc_get_tb(tb_env, now, tb_env->tb_offset);
- period = 1ULL << target_bit;
- delta_tick = period - (tb & (period - 1));
-
- /* the timer triggers only when the selected bit toggles from 0 to 1 */
- if (tb & period) {
- ticks = period;
- }
-
- if (ticks + delta_tick < ticks) {
- /* Overflow, so assume the biggest number we can express. */
- ticks = UINT64_MAX;
- } else {
- ticks += delta_tick;
- }
-
- *next = now + muldiv64(ticks, NANOSECONDS_PER_SECOND, tb_env->tb_freq);
- if ((*next < now) || (*next > INT64_MAX)) {
- /* Overflow, so assume the biggest number the qemu timer supports. */
- *next = INT64_MAX;
- }
-
- /* XXX: If expire time is now. We can't run the callback because we don't
- * have access to it. So we just set the timer one nanosecond later.
- */
-
- if (*next == now) {
- (*next)++;
- } else {
- /*
- * There's no point to fake any granularity that's more fine grained
- * than milliseconds. Anything beyond that just overloads the system.
- */
- *next = MAX(*next, now + SCALE_MS);
- }
-
- /* Fire the next timer */
- timer_mod(timer, *next);
-}
-
-static void booke_decr_cb(void *opaque)
-{
- PowerPCCPU *cpu = opaque;
- CPUPPCState *env = &cpu->env;
-
- env->spr[SPR_BOOKE_TSR] |= TSR_DIS;
- booke_update_irq(cpu);
-
- if (env->spr[SPR_BOOKE_TCR] & TCR_ARE) {
- /* Auto Reload */
- cpu_ppc_store_decr(env, env->spr[SPR_BOOKE_DECAR]);
- }
-}
-
-static void booke_fit_cb(void *opaque)
-{
- PowerPCCPU *cpu = opaque;
- CPUPPCState *env = &cpu->env;
- ppc_tb_t *tb_env;
- booke_timer_t *booke_timer;
-
- tb_env = env->tb_env;
- booke_timer = tb_env->opaque;
- env->spr[SPR_BOOKE_TSR] |= TSR_FIS;
-
- booke_update_irq(cpu);
-
- booke_update_fixed_timer(env,
- booke_get_fit_target(env, tb_env),
- &booke_timer->fit_next,
- booke_timer->fit_timer,
- TSR_FIS);
-}
-
-static void booke_wdt_cb(void *opaque)
-{
- PowerPCCPU *cpu = opaque;
- CPUPPCState *env = &cpu->env;
- ppc_tb_t *tb_env;
- booke_timer_t *booke_timer;
-
- tb_env = env->tb_env;
- booke_timer = tb_env->opaque;
-
- /* TODO: There's lots of complicated stuff to do here */
-
- booke_update_irq(cpu);
-
- booke_update_fixed_timer(env,
- booke_get_wdt_target(env, tb_env),
- &booke_timer->wdt_next,
- booke_timer->wdt_timer,
- TSR_WIS);
-}
-
-void store_booke_tsr(CPUPPCState *env, target_ulong val)
-{
- PowerPCCPU *cpu = ppc_env_get_cpu(env);
- ppc_tb_t *tb_env = env->tb_env;
- booke_timer_t *booke_timer = tb_env->opaque;
-
- env->spr[SPR_BOOKE_TSR] &= ~val;
- kvmppc_clear_tsr_bits(cpu, val);
-
- if (val & TSR_FIS) {
- booke_update_fixed_timer(env,
- booke_get_fit_target(env, tb_env),
- &booke_timer->fit_next,
- booke_timer->fit_timer,
- TSR_FIS);
- }
-
- if (val & TSR_WIS) {
- booke_update_fixed_timer(env,
- booke_get_wdt_target(env, tb_env),
- &booke_timer->wdt_next,
- booke_timer->wdt_timer,
- TSR_WIS);
- }
-
- booke_update_irq(cpu);
-}
-
-void store_booke_tcr(CPUPPCState *env, target_ulong val)
-{
- PowerPCCPU *cpu = ppc_env_get_cpu(env);
- ppc_tb_t *tb_env = env->tb_env;
- booke_timer_t *booke_timer = tb_env->opaque;
-
- tb_env = env->tb_env;
- env->spr[SPR_BOOKE_TCR] = val;
- kvmppc_set_tcr(cpu);
-
- booke_update_irq(cpu);
-
- booke_update_fixed_timer(env,
- booke_get_fit_target(env, tb_env),
- &booke_timer->fit_next,
- booke_timer->fit_timer,
- TSR_FIS);
-
- booke_update_fixed_timer(env,
- booke_get_wdt_target(env, tb_env),
- &booke_timer->wdt_next,
- booke_timer->wdt_timer,
- TSR_WIS);
-}
-
-static void ppc_booke_timer_reset_handle(void *opaque)
-{
- PowerPCCPU *cpu = opaque;
- CPUPPCState *env = &cpu->env;
-
- store_booke_tcr(env, 0);
- store_booke_tsr(env, -1);
-}
-
-/*
- * This function will be called whenever the CPU state changes.
- * CPU states are defined "typedef enum RunState".
- * Regarding timer, When CPU state changes to running after debug halt
- * or similar cases which takes time then in between final watchdog
- * expiry happenes. This will cause exit to QEMU and configured watchdog
- * action will be taken. To avoid this we always clear the watchdog state when
- * state changes to running.
- */
-static void cpu_state_change_handler(void *opaque, int running, RunState state)
-{
- PowerPCCPU *cpu = opaque;
- CPUPPCState *env = &cpu->env;
-
- if (!running) {
- return;
- }
-
- /*
- * Clear watchdog interrupt condition by clearing TSR.
- */
- store_booke_tsr(env, TSR_ENW | TSR_WIS | TSR_WRS_MASK);
-}
-
-void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags)
-{
- ppc_tb_t *tb_env;
- booke_timer_t *booke_timer;
- int ret = 0;
-
- tb_env = g_malloc0(sizeof(ppc_tb_t));
- booke_timer = g_malloc0(sizeof(booke_timer_t));
-
- cpu->env.tb_env = tb_env;
- tb_env->flags = flags | PPC_TIMER_BOOKE | PPC_DECR_ZERO_TRIGGERED;
-
- tb_env->tb_freq = freq;
- tb_env->decr_freq = freq;
- tb_env->opaque = booke_timer;
- tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &booke_decr_cb, cpu);
-
- booke_timer->fit_timer =
- timer_new_ns(QEMU_CLOCK_VIRTUAL, &booke_fit_cb, cpu);
- booke_timer->wdt_timer =
- timer_new_ns(QEMU_CLOCK_VIRTUAL, &booke_wdt_cb, cpu);
-
- ret = kvmppc_booke_watchdog_enable(cpu);
-
- if (ret) {
- /* TODO: Start the QEMU emulated watchdog if not running on KVM.
- * Also start the QEMU emulated watchdog if KVM does not support
- * emulated watchdog or somehow it is not enabled (supported but
- * not enabled is though some bug and requires debugging :)).
- */
- }
-
- qemu_add_vm_change_state_handler(cpu_state_change_handler, cpu);
-
- qemu_register_reset(ppc_booke_timer_reset_handle, cpu);
-}
diff --git a/qemu/hw/ppc/ppce500_spin.c b/qemu/hw/ppc/ppce500_spin.c
deleted file mode 100644
index 76bd78bfd..000000000
--- a/qemu/hw/ppc/ppce500_spin.c
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * QEMU PowerPC e500v2 ePAPR spinning code
- *
- * Copyright (C) 2011 Freescale Semiconductor, Inc. All rights reserved.
- *
- * Author: Alexander Graf, <agraf@suse.de>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- * This code is not really a device, but models an interface that usually
- * firmware takes care of. It's used when QEMU plays the role of firmware.
- *
- * Specification:
- *
- * https://www.power.org/resources/downloads/Power_ePAPR_APPROVED_v1.1.pdf
- *
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "sysemu/sysemu.h"
-#include "hw/sysbus.h"
-#include "sysemu/kvm.h"
-
-#define MAX_CPUS 32
-
-typedef struct spin_info {
- uint64_t addr;
- uint64_t r3;
- uint32_t resv;
- uint32_t pir;
- uint64_t reserved;
-} QEMU_PACKED SpinInfo;
-
-#define TYPE_E500_SPIN "e500-spin"
-#define E500_SPIN(obj) OBJECT_CHECK(SpinState, (obj), TYPE_E500_SPIN)
-
-typedef struct SpinState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- SpinInfo spin[MAX_CPUS];
-} SpinState;
-
-typedef struct spin_kick {
- PowerPCCPU *cpu;
- SpinInfo *spin;
-} SpinKick;
-
-static void spin_reset(void *opaque)
-{
- SpinState *s = opaque;
- int i;
-
- for (i = 0; i < MAX_CPUS; i++) {
- SpinInfo *info = &s->spin[i];
-
- stl_p(&info->pir, i);
- stq_p(&info->r3, i);
- stq_p(&info->addr, 1);
- }
-}
-
-/* Create -kernel TLB entries for BookE, linearly spanning 256MB. */
-static inline hwaddr booke206_page_size_to_tlb(uint64_t size)
-{
- return ctz32(size >> 10) >> 1;
-}
-
-static void mmubooke_create_initial_mapping(CPUPPCState *env,
- target_ulong va,
- hwaddr pa,
- hwaddr len)
-{
- ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 1);
- hwaddr size;
-
- size = (booke206_page_size_to_tlb(len) << MAS1_TSIZE_SHIFT);
- tlb->mas1 = MAS1_VALID | size;
- tlb->mas2 = (va & TARGET_PAGE_MASK) | MAS2_M;
- tlb->mas7_3 = pa & TARGET_PAGE_MASK;
- tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
- env->tlb_dirty = true;
-}
-
-static void spin_kick(void *data)
-{
- SpinKick *kick = data;
- CPUState *cpu = CPU(kick->cpu);
- CPUPPCState *env = &kick->cpu->env;
- SpinInfo *curspin = kick->spin;
- hwaddr map_size = 64 * 1024 * 1024;
- hwaddr map_start;
-
- cpu_synchronize_state(cpu);
- stl_p(&curspin->pir, env->spr[SPR_PIR]);
- env->nip = ldq_p(&curspin->addr) & (map_size - 1);
- env->gpr[3] = ldq_p(&curspin->r3);
- env->gpr[4] = 0;
- env->gpr[5] = 0;
- env->gpr[6] = 0;
- env->gpr[7] = map_size;
- env->gpr[8] = 0;
- env->gpr[9] = 0;
-
- map_start = ldq_p(&curspin->addr) & ~(map_size - 1);
- mmubooke_create_initial_mapping(env, 0, map_start, map_size);
-
- cpu->halted = 0;
- cpu->exception_index = -1;
- cpu->stopped = false;
- qemu_cpu_kick(cpu);
-}
-
-static void spin_write(void *opaque, hwaddr addr, uint64_t value,
- unsigned len)
-{
- SpinState *s = opaque;
- int env_idx = addr / sizeof(SpinInfo);
- CPUState *cpu;
- SpinInfo *curspin = &s->spin[env_idx];
- uint8_t *curspin_p = (uint8_t*)curspin;
-
- cpu = qemu_get_cpu(env_idx);
- if (cpu == NULL) {
- /* Unknown CPU */
- return;
- }
-
- if (cpu->cpu_index == 0) {
- /* primary CPU doesn't spin */
- return;
- }
-
- curspin_p = &curspin_p[addr % sizeof(SpinInfo)];
- switch (len) {
- case 1:
- stb_p(curspin_p, value);
- break;
- case 2:
- stw_p(curspin_p, value);
- break;
- case 4:
- stl_p(curspin_p, value);
- break;
- }
-
- if (!(ldq_p(&curspin->addr) & 1)) {
- /* run CPU */
- SpinKick kick = {
- .cpu = POWERPC_CPU(cpu),
- .spin = curspin,
- };
-
- run_on_cpu(cpu, spin_kick, &kick);
- }
-}
-
-static uint64_t spin_read(void *opaque, hwaddr addr, unsigned len)
-{
- SpinState *s = opaque;
- uint8_t *spin_p = &((uint8_t*)s->spin)[addr];
-
- switch (len) {
- case 1:
- return ldub_p(spin_p);
- case 2:
- return lduw_p(spin_p);
- case 4:
- return ldl_p(spin_p);
- default:
- hw_error("ppce500: unexpected %s with len = %u", __func__, len);
- }
-}
-
-static const MemoryRegionOps spin_rw_ops = {
- .read = spin_read,
- .write = spin_write,
- .endianness = DEVICE_BIG_ENDIAN,
-};
-
-static int ppce500_spin_initfn(SysBusDevice *dev)
-{
- SpinState *s = E500_SPIN(dev);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &spin_rw_ops, s,
- "e500 spin pv device", sizeof(SpinInfo) * MAX_CPUS);
- sysbus_init_mmio(dev, &s->iomem);
-
- qemu_register_reset(spin_reset, s);
-
- return 0;
-}
-
-static void ppce500_spin_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = ppce500_spin_initfn;
-}
-
-static const TypeInfo ppce500_spin_info = {
- .name = TYPE_E500_SPIN,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(SpinState),
- .class_init = ppce500_spin_class_init,
-};
-
-static void ppce500_spin_register_types(void)
-{
- type_register_static(&ppce500_spin_info);
-}
-
-type_init(ppce500_spin_register_types)
diff --git a/qemu/hw/ppc/prep.c b/qemu/hw/ppc/prep.c
deleted file mode 100644
index 3ffb85e60..000000000
--- a/qemu/hw/ppc/prep.c
+++ /dev/null
@@ -1,679 +0,0 @@
-/*
- * QEMU PPC PREP hardware System Emulator
- *
- * Copyright (c) 2003-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.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/timer/m48t59.h"
-#include "hw/i386/pc.h"
-#include "hw/char/serial.h"
-#include "hw/block/fdc.h"
-#include "net/net.h"
-#include "sysemu/sysemu.h"
-#include "hw/isa/isa.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/pci_host.h"
-#include "hw/ppc/ppc.h"
-#include "hw/boards.h"
-#include "qemu/error-report.h"
-#include "qemu/log.h"
-#include "hw/ide.h"
-#include "hw/loader.h"
-#include "hw/timer/mc146818rtc.h"
-#include "hw/isa/pc87312.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/arch_init.h"
-#include "sysemu/qtest.h"
-#include "exec/address-spaces.h"
-#include "trace.h"
-#include "elf.h"
-#include "qemu/cutils.h"
-
-/* SMP is not enabled, for now */
-#define MAX_CPUS 1
-
-#define MAX_IDE_BUS 2
-
-#define BIOS_SIZE (1024 * 1024)
-#define BIOS_FILENAME "ppc_rom.bin"
-#define KERNEL_LOAD_ADDR 0x01000000
-#define INITRD_LOAD_ADDR 0x01800000
-
-/* Constants for devices init */
-static const int ide_iobase[2] = { 0x1f0, 0x170 };
-static const int ide_iobase2[2] = { 0x3f6, 0x376 };
-static const int ide_irq[2] = { 13, 13 };
-
-#define NE2000_NB_MAX 6
-
-static uint32_t ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360, 0x280, 0x380 };
-static int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 };
-
-/* ISA IO ports bridge */
-#define PPC_IO_BASE 0x80000000
-
-/* PowerPC control and status registers */
-#if 0 // Not used
-static struct {
- /* IDs */
- uint32_t veni_devi;
- uint32_t revi;
- /* Control and status */
- uint32_t gcsr;
- uint32_t xcfr;
- uint32_t ct32;
- uint32_t mcsr;
- /* General purpose registers */
- uint32_t gprg[6];
- /* Exceptions */
- uint32_t feen;
- uint32_t fest;
- uint32_t fema;
- uint32_t fecl;
- uint32_t eeen;
- uint32_t eest;
- uint32_t eecl;
- uint32_t eeint;
- uint32_t eemck0;
- uint32_t eemck1;
- /* Error diagnostic */
-} XCSR;
-
-static void PPC_XCSR_writeb (void *opaque,
- hwaddr addr, uint32_t value)
-{
- printf("%s: 0x" TARGET_FMT_plx " => 0x%08" PRIx32 "\n", __func__, addr,
- value);
-}
-
-static void PPC_XCSR_writew (void *opaque,
- hwaddr addr, uint32_t value)
-{
- printf("%s: 0x" TARGET_FMT_plx " => 0x%08" PRIx32 "\n", __func__, addr,
- value);
-}
-
-static void PPC_XCSR_writel (void *opaque,
- hwaddr addr, uint32_t value)
-{
- printf("%s: 0x" TARGET_FMT_plx " => 0x%08" PRIx32 "\n", __func__, addr,
- value);
-}
-
-static uint32_t PPC_XCSR_readb (void *opaque, hwaddr addr)
-{
- uint32_t retval = 0;
-
- printf("%s: 0x" TARGET_FMT_plx " <= %08" PRIx32 "\n", __func__, addr,
- retval);
-
- return retval;
-}
-
-static uint32_t PPC_XCSR_readw (void *opaque, hwaddr addr)
-{
- uint32_t retval = 0;
-
- printf("%s: 0x" TARGET_FMT_plx " <= %08" PRIx32 "\n", __func__, addr,
- retval);
-
- return retval;
-}
-
-static uint32_t PPC_XCSR_readl (void *opaque, hwaddr addr)
-{
- uint32_t retval = 0;
-
- printf("%s: 0x" TARGET_FMT_plx " <= %08" PRIx32 "\n", __func__, addr,
- retval);
-
- return retval;
-}
-
-static const MemoryRegionOps PPC_XCSR_ops = {
- .old_mmio = {
- .read = { PPC_XCSR_readb, PPC_XCSR_readw, PPC_XCSR_readl, },
- .write = { PPC_XCSR_writeb, PPC_XCSR_writew, PPC_XCSR_writel, },
- },
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-#endif
-
-/* Fake super-io ports for PREP platform (Intel 82378ZB) */
-typedef struct sysctrl_t {
- qemu_irq reset_irq;
- Nvram *nvram;
- uint8_t state;
- uint8_t syscontrol;
- int contiguous_map;
- qemu_irq contiguous_map_irq;
- int endian;
-} sysctrl_t;
-
-enum {
- STATE_HARDFILE = 0x01,
-};
-
-static sysctrl_t *sysctrl;
-
-static void PREP_io_800_writeb (void *opaque, uint32_t addr, uint32_t val)
-{
- sysctrl_t *sysctrl = opaque;
-
- trace_prep_io_800_writeb(addr - PPC_IO_BASE, val);
- switch (addr) {
- case 0x0092:
- /* Special port 92 */
- /* Check soft reset asked */
- if (val & 0x01) {
- qemu_irq_raise(sysctrl->reset_irq);
- } else {
- qemu_irq_lower(sysctrl->reset_irq);
- }
- /* Check LE mode */
- if (val & 0x02) {
- sysctrl->endian = 1;
- } else {
- sysctrl->endian = 0;
- }
- break;
- case 0x0800:
- /* Motorola CPU configuration register : read-only */
- break;
- case 0x0802:
- /* Motorola base module feature register : read-only */
- break;
- case 0x0803:
- /* Motorola base module status register : read-only */
- break;
- case 0x0808:
- /* Hardfile light register */
- if (val & 1)
- sysctrl->state |= STATE_HARDFILE;
- else
- sysctrl->state &= ~STATE_HARDFILE;
- break;
- case 0x0810:
- /* Password protect 1 register */
- if (sysctrl->nvram != NULL) {
- NvramClass *k = NVRAM_GET_CLASS(sysctrl->nvram);
- (k->toggle_lock)(sysctrl->nvram, 1);
- }
- break;
- case 0x0812:
- /* Password protect 2 register */
- if (sysctrl->nvram != NULL) {
- NvramClass *k = NVRAM_GET_CLASS(sysctrl->nvram);
- (k->toggle_lock)(sysctrl->nvram, 2);
- }
- break;
- case 0x0814:
- /* L2 invalidate register */
- // tlb_flush(first_cpu, 1);
- break;
- case 0x081C:
- /* system control register */
- sysctrl->syscontrol = val & 0x0F;
- break;
- case 0x0850:
- /* I/O map type register */
- sysctrl->contiguous_map = val & 0x01;
- qemu_set_irq(sysctrl->contiguous_map_irq, sysctrl->contiguous_map);
- break;
- default:
- printf("ERROR: unaffected IO port write: %04" PRIx32
- " => %02" PRIx32"\n", addr, val);
- break;
- }
-}
-
-static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr)
-{
- sysctrl_t *sysctrl = opaque;
- uint32_t retval = 0xFF;
-
- switch (addr) {
- case 0x0092:
- /* Special port 92 */
- retval = sysctrl->endian << 1;
- break;
- case 0x0800:
- /* Motorola CPU configuration register */
- retval = 0xEF; /* MPC750 */
- break;
- case 0x0802:
- /* Motorola Base module feature register */
- retval = 0xAD; /* No ESCC, PMC slot neither ethernet */
- break;
- case 0x0803:
- /* Motorola base module status register */
- retval = 0xE0; /* Standard MPC750 */
- break;
- case 0x080C:
- /* Equipment present register:
- * no L2 cache
- * no upgrade processor
- * no cards in PCI slots
- * SCSI fuse is bad
- */
- retval = 0x3C;
- break;
- case 0x0810:
- /* Motorola base module extended feature register */
- retval = 0x39; /* No USB, CF and PCI bridge. NVRAM present */
- break;
- case 0x0814:
- /* L2 invalidate: don't care */
- break;
- case 0x0818:
- /* Keylock */
- retval = 0x00;
- break;
- case 0x081C:
- /* system control register
- * 7 - 6 / 1 - 0: L2 cache enable
- */
- retval = sysctrl->syscontrol;
- break;
- case 0x0823:
- /* */
- retval = 0x03; /* no L2 cache */
- break;
- case 0x0850:
- /* I/O map type register */
- retval = sysctrl->contiguous_map;
- break;
- default:
- printf("ERROR: unaffected IO port: %04" PRIx32 " read\n", addr);
- break;
- }
- trace_prep_io_800_readb(addr - PPC_IO_BASE, retval);
-
- return retval;
-}
-
-
-#define NVRAM_SIZE 0x2000
-
-static void ppc_prep_reset(void *opaque)
-{
- PowerPCCPU *cpu = opaque;
-
- cpu_reset(CPU(cpu));
-}
-
-static const MemoryRegionPortio prep_portio_list[] = {
- /* System control ports */
- { 0x0092, 1, 1, .read = PREP_io_800_readb, .write = PREP_io_800_writeb, },
- { 0x0800, 0x52, 1,
- .read = PREP_io_800_readb, .write = PREP_io_800_writeb, },
- /* Special port to get debug messages from Open-Firmware */
- { 0x0F00, 4, 1, .write = PPC_debug_write, },
- PORTIO_END_OF_LIST(),
-};
-
-static PortioList prep_port_list;
-
-/*****************************************************************************/
-/* NVRAM helpers */
-static inline uint32_t nvram_read(Nvram *nvram, uint32_t addr)
-{
- NvramClass *k = NVRAM_GET_CLASS(sysctrl->nvram);
- return (k->read)(nvram, addr);
-}
-
-static inline void nvram_write(Nvram *nvram, uint32_t addr, uint32_t val)
-{
- NvramClass *k = NVRAM_GET_CLASS(sysctrl->nvram);
- (k->write)(nvram, addr, val);
-}
-
-static void NVRAM_set_byte(Nvram *nvram, uint32_t addr, uint8_t value)
-{
- nvram_write(nvram, addr, value);
-}
-
-static uint8_t NVRAM_get_byte(Nvram *nvram, uint32_t addr)
-{
- return nvram_read(nvram, addr);
-}
-
-static void NVRAM_set_word(Nvram *nvram, uint32_t addr, uint16_t value)
-{
- nvram_write(nvram, addr, value >> 8);
- nvram_write(nvram, addr + 1, value & 0xFF);
-}
-
-static uint16_t NVRAM_get_word(Nvram *nvram, uint32_t addr)
-{
- uint16_t tmp;
-
- tmp = nvram_read(nvram, addr) << 8;
- tmp |= nvram_read(nvram, addr + 1);
-
- return tmp;
-}
-
-static void NVRAM_set_lword(Nvram *nvram, uint32_t addr, uint32_t value)
-{
- nvram_write(nvram, addr, value >> 24);
- nvram_write(nvram, addr + 1, (value >> 16) & 0xFF);
- nvram_write(nvram, addr + 2, (value >> 8) & 0xFF);
- nvram_write(nvram, addr + 3, value & 0xFF);
-}
-
-static void NVRAM_set_string(Nvram *nvram, uint32_t addr, const char *str,
- uint32_t max)
-{
- int i;
-
- for (i = 0; i < max && str[i] != '\0'; i++) {
- nvram_write(nvram, addr + i, str[i]);
- }
- nvram_write(nvram, addr + i, str[i]);
- nvram_write(nvram, addr + max - 1, '\0');
-}
-
-static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value)
-{
- uint16_t tmp;
- uint16_t pd, pd1, pd2;
-
- tmp = prev >> 8;
- pd = prev ^ value;
- pd1 = pd & 0x000F;
- pd2 = ((pd >> 4) & 0x000F) ^ pd1;
- tmp ^= (pd1 << 3) | (pd1 << 8);
- tmp ^= pd2 | (pd2 << 7) | (pd2 << 12);
-
- return tmp;
-}
-
-static uint16_t NVRAM_compute_crc (Nvram *nvram, uint32_t start, uint32_t count)
-{
- uint32_t i;
- uint16_t crc = 0xFFFF;
- int odd;
-
- odd = count & 1;
- count &= ~1;
- for (i = 0; i != count; i++) {
- crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i));
- }
- if (odd) {
- crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8);
- }
-
- return crc;
-}
-
-#define CMDLINE_ADDR 0x017ff000
-
-static int PPC_NVRAM_set_params (Nvram *nvram, uint16_t NVRAM_size,
- const char *arch,
- uint32_t RAM_size, int boot_device,
- uint32_t kernel_image, uint32_t kernel_size,
- const char *cmdline,
- uint32_t initrd_image, uint32_t initrd_size,
- uint32_t NVRAM_image,
- int width, int height, int depth)
-{
- uint16_t crc;
-
- /* Set parameters for Open Hack'Ware BIOS */
- NVRAM_set_string(nvram, 0x00, "QEMU_BIOS", 16);
- NVRAM_set_lword(nvram, 0x10, 0x00000002); /* structure v2 */
- NVRAM_set_word(nvram, 0x14, NVRAM_size);
- NVRAM_set_string(nvram, 0x20, arch, 16);
- NVRAM_set_lword(nvram, 0x30, RAM_size);
- NVRAM_set_byte(nvram, 0x34, boot_device);
- NVRAM_set_lword(nvram, 0x38, kernel_image);
- NVRAM_set_lword(nvram, 0x3C, kernel_size);
- if (cmdline) {
- /* XXX: put the cmdline in NVRAM too ? */
- pstrcpy_targphys("cmdline", CMDLINE_ADDR, RAM_size - CMDLINE_ADDR,
- cmdline);
- NVRAM_set_lword(nvram, 0x40, CMDLINE_ADDR);
- NVRAM_set_lword(nvram, 0x44, strlen(cmdline));
- } else {
- NVRAM_set_lword(nvram, 0x40, 0);
- NVRAM_set_lword(nvram, 0x44, 0);
- }
- NVRAM_set_lword(nvram, 0x48, initrd_image);
- NVRAM_set_lword(nvram, 0x4C, initrd_size);
- NVRAM_set_lword(nvram, 0x50, NVRAM_image);
-
- NVRAM_set_word(nvram, 0x54, width);
- NVRAM_set_word(nvram, 0x56, height);
- NVRAM_set_word(nvram, 0x58, depth);
- crc = NVRAM_compute_crc(nvram, 0x00, 0xF8);
- NVRAM_set_word(nvram, 0xFC, crc);
-
- return 0;
-}
-
-/* PowerPC PREP hardware initialisation */
-static void ppc_prep_init(MachineState *machine)
-{
- ram_addr_t ram_size = machine->ram_size;
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- const char *initrd_filename = machine->initrd_filename;
- const char *boot_device = machine->boot_order;
- MemoryRegion *sysmem = get_system_memory();
- PowerPCCPU *cpu = NULL;
- CPUPPCState *env = NULL;
- Nvram *m48t59;
-#if 0
- MemoryRegion *xcsr = g_new(MemoryRegion, 1);
-#endif
- int linux_boot, i, nb_nics1;
- MemoryRegion *ram = g_new(MemoryRegion, 1);
- uint32_t kernel_base, initrd_base;
- long kernel_size, initrd_size;
- DeviceState *dev;
- PCIHostState *pcihost;
- PCIBus *pci_bus;
- PCIDevice *pci;
- ISABus *isa_bus;
- ISADevice *isa;
- int ppc_boot_device;
- DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
-
- sysctrl = g_malloc0(sizeof(sysctrl_t));
-
- linux_boot = (kernel_filename != NULL);
-
- /* init CPUs */
- if (machine->cpu_model == NULL)
- machine->cpu_model = "602";
- for (i = 0; i < smp_cpus; i++) {
- cpu = cpu_ppc_init(machine->cpu_model);
- if (cpu == NULL) {
- fprintf(stderr, "Unable to find PowerPC CPU definition\n");
- exit(1);
- }
- env = &cpu->env;
-
- if (env->flags & POWERPC_FLAG_RTC_CLK) {
- /* POWER / PowerPC 601 RTC clock frequency is 7.8125 MHz */
- cpu_ppc_tb_init(env, 7812500UL);
- } else {
- /* Set time-base frequency to 100 Mhz */
- cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL);
- }
- qemu_register_reset(ppc_prep_reset, cpu);
- }
-
- /* allocate RAM */
- memory_region_allocate_system_memory(ram, NULL, "ppc_prep.ram", ram_size);
- memory_region_add_subregion(sysmem, 0, ram);
-
- if (linux_boot) {
- kernel_base = KERNEL_LOAD_ADDR;
- /* now we can load the kernel */
- kernel_size = load_image_targphys(kernel_filename, kernel_base,
- ram_size - kernel_base);
- if (kernel_size < 0) {
- error_report("could not load kernel '%s'", kernel_filename);
- exit(1);
- }
- /* load initrd */
- if (initrd_filename) {
- initrd_base = INITRD_LOAD_ADDR;
- initrd_size = load_image_targphys(initrd_filename, initrd_base,
- ram_size - initrd_base);
- if (initrd_size < 0) {
- error_report("could not load initial ram disk '%s'",
- initrd_filename);
- exit(1);
- }
- } else {
- initrd_base = 0;
- initrd_size = 0;
- }
- ppc_boot_device = 'm';
- } else {
- kernel_base = 0;
- kernel_size = 0;
- initrd_base = 0;
- initrd_size = 0;
- ppc_boot_device = '\0';
- /* For now, OHW cannot boot from the network. */
- for (i = 0; boot_device[i] != '\0'; i++) {
- if (boot_device[i] >= 'a' && boot_device[i] <= 'f') {
- ppc_boot_device = boot_device[i];
- break;
- }
- }
- if (ppc_boot_device == '\0') {
- fprintf(stderr, "No valid boot device for Mac99 machine\n");
- exit(1);
- }
- }
-
- if (PPC_INPUT(env) != PPC_FLAGS_INPUT_6xx) {
- error_report("Only 6xx bus is supported on PREP machine");
- exit(1);
- }
-
- dev = qdev_create(NULL, "raven-pcihost");
- if (bios_name == NULL) {
- bios_name = BIOS_FILENAME;
- }
- qdev_prop_set_string(dev, "bios-name", bios_name);
- qdev_prop_set_uint32(dev, "elf-machine", PPC_ELF_MACHINE);
- pcihost = PCI_HOST_BRIDGE(dev);
- object_property_add_child(qdev_get_machine(), "raven", OBJECT(dev), NULL);
- qdev_init_nofail(dev);
- pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
- if (pci_bus == NULL) {
- fprintf(stderr, "Couldn't create PCI host controller.\n");
- exit(1);
- }
- sysctrl->contiguous_map_irq = qdev_get_gpio_in(dev, 0);
-
- /* PCI -> ISA bridge */
- pci = pci_create_simple(pci_bus, PCI_DEVFN(1, 0), "i82378");
- cpu = POWERPC_CPU(first_cpu);
- qdev_connect_gpio_out(&pci->qdev, 0,
- cpu->env.irq_inputs[PPC6xx_INPUT_INT]);
- sysbus_connect_irq(&pcihost->busdev, 0, qdev_get_gpio_in(&pci->qdev, 9));
- sysbus_connect_irq(&pcihost->busdev, 1, qdev_get_gpio_in(&pci->qdev, 11));
- sysbus_connect_irq(&pcihost->busdev, 2, qdev_get_gpio_in(&pci->qdev, 9));
- sysbus_connect_irq(&pcihost->busdev, 3, qdev_get_gpio_in(&pci->qdev, 11));
- isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(pci), "isa.0"));
-
- /* Super I/O (parallel + serial ports) */
- isa = isa_create(isa_bus, TYPE_PC87312);
- dev = DEVICE(isa);
- qdev_prop_set_uint8(dev, "config", 13); /* fdc, ser0, ser1, par0 */
- qdev_init_nofail(dev);
-
- /* init basic PC hardware */
- pci_vga_init(pci_bus);
-
- nb_nics1 = nb_nics;
- if (nb_nics1 > NE2000_NB_MAX)
- nb_nics1 = NE2000_NB_MAX;
- for(i = 0; i < nb_nics1; i++) {
- if (nd_table[i].model == NULL) {
- nd_table[i].model = g_strdup("ne2k_isa");
- }
- if (strcmp(nd_table[i].model, "ne2k_isa") == 0) {
- isa_ne2000_init(isa_bus, ne2000_io[i], ne2000_irq[i],
- &nd_table[i]);
- } else {
- pci_nic_init_nofail(&nd_table[i], pci_bus, "ne2k_pci", NULL);
- }
- }
-
- ide_drive_get(hd, ARRAY_SIZE(hd));
- for(i = 0; i < MAX_IDE_BUS; i++) {
- isa_ide_init(isa_bus, ide_iobase[i], ide_iobase2[i], ide_irq[i],
- hd[2 * i],
- hd[2 * i + 1]);
- }
- isa_create_simple(isa_bus, "i8042");
-
- cpu = POWERPC_CPU(first_cpu);
- sysctrl->reset_irq = cpu->env.irq_inputs[PPC6xx_INPUT_HRESET];
-
- portio_list_init(&prep_port_list, NULL, prep_portio_list, sysctrl, "prep");
- portio_list_add(&prep_port_list, isa_address_space_io(isa), 0x0);
-
- /* PowerPC control and status register group */
-#if 0
- memory_region_init_io(xcsr, NULL, &PPC_XCSR_ops, NULL, "ppc-xcsr", 0x1000);
- memory_region_add_subregion(sysmem, 0xFEFF0000, xcsr);
-#endif
-
- if (usb_enabled()) {
- pci_create_simple(pci_bus, -1, "pci-ohci");
- }
-
- m48t59 = m48t59_init_isa(isa_bus, 0x0074, NVRAM_SIZE, 2000, 59);
- if (m48t59 == NULL)
- return;
- sysctrl->nvram = m48t59;
-
- /* Initialise NVRAM */
- PPC_NVRAM_set_params(m48t59, NVRAM_SIZE, "PREP", ram_size,
- ppc_boot_device,
- kernel_base, kernel_size,
- kernel_cmdline,
- initrd_base, initrd_size,
- /* XXX: need an option to load a NVRAM image */
- 0,
- graphic_width, graphic_height, graphic_depth);
-}
-
-static void prep_machine_init(MachineClass *mc)
-{
- mc->desc = "PowerPC PREP platform";
- mc->init = ppc_prep_init;
- mc->max_cpus = MAX_CPUS;
- mc->default_boot_order = "cad";
-}
-
-DEFINE_MACHINE("prep", prep_machine_init)
diff --git a/qemu/hw/ppc/spapr.c b/qemu/hw/ppc/spapr.c
deleted file mode 100644
index b69995e0d..000000000
--- a/qemu/hw/ppc/spapr.c
+++ /dev/null
@@ -1,2485 +0,0 @@
-/*
- * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
- *
- * Copyright (c) 2004-2007 Fabrice Bellard
- * Copyright (c) 2007 Jocelyn Mayer
- * Copyright (c) 2010 David Gibson, IBM Corporation.
- *
- * 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.
- *
- */
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/numa.h"
-#include "hw/hw.h"
-#include "hw/fw-path-provider.h"
-#include "elf.h"
-#include "net/net.h"
-#include "sysemu/device_tree.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/cpus.h"
-#include "sysemu/kvm.h"
-#include "sysemu/device_tree.h"
-#include "kvm_ppc.h"
-#include "migration/migration.h"
-#include "mmu-hash64.h"
-#include "qom/cpu.h"
-
-#include "hw/boards.h"
-#include "hw/ppc/ppc.h"
-#include "hw/loader.h"
-
-#include "hw/ppc/spapr.h"
-#include "hw/ppc/spapr_vio.h"
-#include "hw/pci-host/spapr.h"
-#include "hw/ppc/xics.h"
-#include "hw/pci/msi.h"
-
-#include "hw/pci/pci.h"
-#include "hw/scsi/scsi.h"
-#include "hw/virtio/virtio-scsi.h"
-
-#include "exec/address-spaces.h"
-#include "hw/usb.h"
-#include "qemu/config-file.h"
-#include "qemu/error-report.h"
-#include "trace.h"
-#include "hw/nmi.h"
-
-#include "hw/compat.h"
-#include "qemu/cutils.h"
-
-#include <libfdt.h>
-
-/* SLOF memory layout:
- *
- * SLOF raw image loaded at 0, copies its romfs right below the flat
- * device-tree, then position SLOF itself 31M below that
- *
- * So we set FW_OVERHEAD to 40MB which should account for all of that
- * and more
- *
- * We load our kernel at 4M, leaving space for SLOF initial image
- */
-#define FDT_MAX_SIZE 0x100000
-#define RTAS_MAX_SIZE 0x10000
-#define RTAS_MAX_ADDR 0x80000000 /* RTAS must stay below that */
-#define FW_MAX_SIZE 0x400000
-#define FW_FILE_NAME "slof.bin"
-#define FW_OVERHEAD 0x2800000
-#define KERNEL_LOAD_ADDR FW_MAX_SIZE
-
-#define MIN_RMA_SLOF 128UL
-
-#define TIMEBASE_FREQ 512000000ULL
-
-#define PHANDLE_XICP 0x00001111
-
-#define HTAB_SIZE(spapr) (1ULL << ((spapr)->htab_shift))
-
-static XICSState *try_create_xics(const char *type, int nr_servers,
- int nr_irqs, Error **errp)
-{
- Error *err = NULL;
- DeviceState *dev;
-
- dev = qdev_create(NULL, type);
- qdev_prop_set_uint32(dev, "nr_servers", nr_servers);
- qdev_prop_set_uint32(dev, "nr_irqs", nr_irqs);
- object_property_set_bool(OBJECT(dev), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- object_unparent(OBJECT(dev));
- return NULL;
- }
- return XICS_COMMON(dev);
-}
-
-static XICSState *xics_system_init(MachineState *machine,
- int nr_servers, int nr_irqs, Error **errp)
-{
- XICSState *icp = NULL;
-
- if (kvm_enabled()) {
- Error *err = NULL;
-
- if (machine_kernel_irqchip_allowed(machine)) {
- icp = try_create_xics(TYPE_KVM_XICS, nr_servers, nr_irqs, &err);
- }
- if (machine_kernel_irqchip_required(machine) && !icp) {
- error_reportf_err(err,
- "kernel_irqchip requested but unavailable: ");
- } else {
- error_free(err);
- }
- }
-
- if (!icp) {
- icp = try_create_xics(TYPE_XICS, nr_servers, nr_irqs, errp);
- }
-
- return icp;
-}
-
-static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu,
- int smt_threads)
-{
- int i, ret = 0;
- uint32_t servers_prop[smt_threads];
- uint32_t gservers_prop[smt_threads * 2];
- int index = ppc_get_vcpu_dt_id(cpu);
-
- if (cpu->cpu_version) {
- ret = fdt_setprop_cell(fdt, offset, "cpu-version", cpu->cpu_version);
- if (ret < 0) {
- return ret;
- }
- }
-
- /* Build interrupt servers and gservers properties */
- for (i = 0; i < smt_threads; i++) {
- servers_prop[i] = cpu_to_be32(index + i);
- /* Hack, direct the group queues back to cpu 0 */
- gservers_prop[i*2] = cpu_to_be32(index + i);
- gservers_prop[i*2 + 1] = 0;
- }
- ret = fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s",
- servers_prop, sizeof(servers_prop));
- if (ret < 0) {
- return ret;
- }
- ret = fdt_setprop(fdt, offset, "ibm,ppc-interrupt-gserver#s",
- gservers_prop, sizeof(gservers_prop));
-
- return ret;
-}
-
-static int spapr_fixup_cpu_numa_dt(void *fdt, int offset, CPUState *cs)
-{
- int ret = 0;
- PowerPCCPU *cpu = POWERPC_CPU(cs);
- int index = ppc_get_vcpu_dt_id(cpu);
- uint32_t associativity[] = {cpu_to_be32(0x5),
- cpu_to_be32(0x0),
- cpu_to_be32(0x0),
- cpu_to_be32(0x0),
- cpu_to_be32(cs->numa_node),
- cpu_to_be32(index)};
-
- /* Advertise NUMA via ibm,associativity */
- if (nb_numa_nodes > 1) {
- ret = fdt_setprop(fdt, offset, "ibm,associativity", associativity,
- sizeof(associativity));
- }
-
- return ret;
-}
-
-static int spapr_fixup_cpu_dt(void *fdt, sPAPRMachineState *spapr)
-{
- int ret = 0, offset, cpus_offset;
- CPUState *cs;
- char cpu_model[32];
- int smt = kvmppc_smt_threads();
- uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)};
-
- CPU_FOREACH(cs) {
- PowerPCCPU *cpu = POWERPC_CPU(cs);
- DeviceClass *dc = DEVICE_GET_CLASS(cs);
- int index = ppc_get_vcpu_dt_id(cpu);
-
- if ((index % smt) != 0) {
- continue;
- }
-
- snprintf(cpu_model, 32, "%s@%x", dc->fw_name, index);
-
- cpus_offset = fdt_path_offset(fdt, "/cpus");
- if (cpus_offset < 0) {
- cpus_offset = fdt_add_subnode(fdt, fdt_path_offset(fdt, "/"),
- "cpus");
- if (cpus_offset < 0) {
- return cpus_offset;
- }
- }
- offset = fdt_subnode_offset(fdt, cpus_offset, cpu_model);
- if (offset < 0) {
- offset = fdt_add_subnode(fdt, cpus_offset, cpu_model);
- if (offset < 0) {
- return offset;
- }
- }
-
- ret = fdt_setprop(fdt, offset, "ibm,pft-size",
- pft_size_prop, sizeof(pft_size_prop));
- if (ret < 0) {
- return ret;
- }
-
- ret = spapr_fixup_cpu_numa_dt(fdt, offset, cs);
- if (ret < 0) {
- return ret;
- }
-
- ret = spapr_fixup_cpu_smt_dt(fdt, offset, cpu,
- ppc_get_compat_smt_threads(cpu));
- if (ret < 0) {
- return ret;
- }
- }
- return ret;
-}
-
-
-static size_t create_page_sizes_prop(CPUPPCState *env, uint32_t *prop,
- size_t maxsize)
-{
- size_t maxcells = maxsize / sizeof(uint32_t);
- int i, j, count;
- uint32_t *p = prop;
-
- for (i = 0; i < PPC_PAGE_SIZES_MAX_SZ; i++) {
- struct ppc_one_seg_page_size *sps = &env->sps.sps[i];
-
- if (!sps->page_shift) {
- break;
- }
- for (count = 0; count < PPC_PAGE_SIZES_MAX_SZ; count++) {
- if (sps->enc[count].page_shift == 0) {
- break;
- }
- }
- if ((p - prop) >= (maxcells - 3 - count * 2)) {
- break;
- }
- *(p++) = cpu_to_be32(sps->page_shift);
- *(p++) = cpu_to_be32(sps->slb_enc);
- *(p++) = cpu_to_be32(count);
- for (j = 0; j < count; j++) {
- *(p++) = cpu_to_be32(sps->enc[j].page_shift);
- *(p++) = cpu_to_be32(sps->enc[j].pte_enc);
- }
- }
-
- return (p - prop) * sizeof(uint32_t);
-}
-
-static hwaddr spapr_node0_size(void)
-{
- MachineState *machine = MACHINE(qdev_get_machine());
-
- if (nb_numa_nodes) {
- int i;
- for (i = 0; i < nb_numa_nodes; ++i) {
- if (numa_info[i].node_mem) {
- return MIN(pow2floor(numa_info[i].node_mem),
- machine->ram_size);
- }
- }
- }
- return machine->ram_size;
-}
-
-#define _FDT(exp) \
- do { \
- int ret = (exp); \
- if (ret < 0) { \
- fprintf(stderr, "qemu: error creating device tree: %s: %s\n", \
- #exp, fdt_strerror(ret)); \
- exit(1); \
- } \
- } while (0)
-
-static void add_str(GString *s, const gchar *s1)
-{
- g_string_append_len(s, s1, strlen(s1) + 1);
-}
-
-static void *spapr_create_fdt_skel(hwaddr initrd_base,
- hwaddr initrd_size,
- hwaddr kernel_size,
- bool little_endian,
- const char *kernel_cmdline,
- uint32_t epow_irq)
-{
- void *fdt;
- uint32_t start_prop = cpu_to_be32(initrd_base);
- uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
- GString *hypertas = g_string_sized_new(256);
- GString *qemu_hypertas = g_string_sized_new(256);
- uint32_t refpoints[] = {cpu_to_be32(0x4), cpu_to_be32(0x4)};
- uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(max_cpus)};
- unsigned char vec5[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x80};
- char *buf;
-
- add_str(hypertas, "hcall-pft");
- add_str(hypertas, "hcall-term");
- add_str(hypertas, "hcall-dabr");
- add_str(hypertas, "hcall-interrupt");
- add_str(hypertas, "hcall-tce");
- add_str(hypertas, "hcall-vio");
- add_str(hypertas, "hcall-splpar");
- add_str(hypertas, "hcall-bulk");
- add_str(hypertas, "hcall-set-mode");
- add_str(qemu_hypertas, "hcall-memop1");
-
- fdt = g_malloc0(FDT_MAX_SIZE);
- _FDT((fdt_create(fdt, FDT_MAX_SIZE)));
-
- if (kernel_size) {
- _FDT((fdt_add_reservemap_entry(fdt, KERNEL_LOAD_ADDR, kernel_size)));
- }
- if (initrd_size) {
- _FDT((fdt_add_reservemap_entry(fdt, initrd_base, initrd_size)));
- }
- _FDT((fdt_finish_reservemap(fdt)));
-
- /* Root node */
- _FDT((fdt_begin_node(fdt, "")));
- _FDT((fdt_property_string(fdt, "device_type", "chrp")));
- _FDT((fdt_property_string(fdt, "model", "IBM pSeries (emulated by qemu)")));
- _FDT((fdt_property_string(fdt, "compatible", "qemu,pseries")));
-
- /*
- * Add info to guest to indentify which host is it being run on
- * and what is the uuid of the guest
- */
- if (kvmppc_get_host_model(&buf)) {
- _FDT((fdt_property_string(fdt, "host-model", buf)));
- g_free(buf);
- }
- if (kvmppc_get_host_serial(&buf)) {
- _FDT((fdt_property_string(fdt, "host-serial", buf)));
- g_free(buf);
- }
-
- buf = g_strdup_printf(UUID_FMT, qemu_uuid[0], qemu_uuid[1],
- qemu_uuid[2], qemu_uuid[3], qemu_uuid[4],
- qemu_uuid[5], qemu_uuid[6], qemu_uuid[7],
- qemu_uuid[8], qemu_uuid[9], qemu_uuid[10],
- qemu_uuid[11], qemu_uuid[12], qemu_uuid[13],
- qemu_uuid[14], qemu_uuid[15]);
-
- _FDT((fdt_property_string(fdt, "vm,uuid", buf)));
- if (qemu_uuid_set) {
- _FDT((fdt_property_string(fdt, "system-id", buf)));
- }
- g_free(buf);
-
- if (qemu_get_vm_name()) {
- _FDT((fdt_property_string(fdt, "ibm,partition-name",
- qemu_get_vm_name())));
- }
-
- _FDT((fdt_property_cell(fdt, "#address-cells", 0x2)));
- _FDT((fdt_property_cell(fdt, "#size-cells", 0x2)));
-
- /* /chosen */
- _FDT((fdt_begin_node(fdt, "chosen")));
-
- /* Set Form1_affinity */
- _FDT((fdt_property(fdt, "ibm,architecture-vec-5", vec5, sizeof(vec5))));
-
- _FDT((fdt_property_string(fdt, "bootargs", kernel_cmdline)));
- _FDT((fdt_property(fdt, "linux,initrd-start",
- &start_prop, sizeof(start_prop))));
- _FDT((fdt_property(fdt, "linux,initrd-end",
- &end_prop, sizeof(end_prop))));
- if (kernel_size) {
- uint64_t kprop[2] = { cpu_to_be64(KERNEL_LOAD_ADDR),
- cpu_to_be64(kernel_size) };
-
- _FDT((fdt_property(fdt, "qemu,boot-kernel", &kprop, sizeof(kprop))));
- if (little_endian) {
- _FDT((fdt_property(fdt, "qemu,boot-kernel-le", NULL, 0)));
- }
- }
- if (boot_menu) {
- _FDT((fdt_property_cell(fdt, "qemu,boot-menu", boot_menu)));
- }
- _FDT((fdt_property_cell(fdt, "qemu,graphic-width", graphic_width)));
- _FDT((fdt_property_cell(fdt, "qemu,graphic-height", graphic_height)));
- _FDT((fdt_property_cell(fdt, "qemu,graphic-depth", graphic_depth)));
-
- _FDT((fdt_end_node(fdt)));
-
- /* RTAS */
- _FDT((fdt_begin_node(fdt, "rtas")));
-
- if (!kvm_enabled() || kvmppc_spapr_use_multitce()) {
- add_str(hypertas, "hcall-multi-tce");
- }
- _FDT((fdt_property(fdt, "ibm,hypertas-functions", hypertas->str,
- hypertas->len)));
- g_string_free(hypertas, TRUE);
- _FDT((fdt_property(fdt, "qemu,hypertas-functions", qemu_hypertas->str,
- qemu_hypertas->len)));
- g_string_free(qemu_hypertas, TRUE);
-
- _FDT((fdt_property(fdt, "ibm,associativity-reference-points",
- refpoints, sizeof(refpoints))));
-
- _FDT((fdt_property_cell(fdt, "rtas-error-log-max", RTAS_ERROR_LOG_MAX)));
- _FDT((fdt_property_cell(fdt, "rtas-event-scan-rate",
- RTAS_EVENT_SCAN_RATE)));
-
- if (msi_nonbroken) {
- _FDT((fdt_property(fdt, "ibm,change-msix-capable", NULL, 0)));
- }
-
- /*
- * According to PAPR, rtas ibm,os-term does not guarantee a return
- * back to the guest cpu.
- *
- * While an additional ibm,extended-os-term property indicates that
- * rtas call return will always occur. Set this property.
- */
- _FDT((fdt_property(fdt, "ibm,extended-os-term", NULL, 0)));
-
- _FDT((fdt_end_node(fdt)));
-
- /* interrupt controller */
- _FDT((fdt_begin_node(fdt, "interrupt-controller")));
-
- _FDT((fdt_property_string(fdt, "device_type",
- "PowerPC-External-Interrupt-Presentation")));
- _FDT((fdt_property_string(fdt, "compatible", "IBM,ppc-xicp")));
- _FDT((fdt_property(fdt, "interrupt-controller", NULL, 0)));
- _FDT((fdt_property(fdt, "ibm,interrupt-server-ranges",
- interrupt_server_ranges_prop,
- sizeof(interrupt_server_ranges_prop))));
- _FDT((fdt_property_cell(fdt, "#interrupt-cells", 2)));
- _FDT((fdt_property_cell(fdt, "linux,phandle", PHANDLE_XICP)));
- _FDT((fdt_property_cell(fdt, "phandle", PHANDLE_XICP)));
-
- _FDT((fdt_end_node(fdt)));
-
- /* vdevice */
- _FDT((fdt_begin_node(fdt, "vdevice")));
-
- _FDT((fdt_property_string(fdt, "device_type", "vdevice")));
- _FDT((fdt_property_string(fdt, "compatible", "IBM,vdevice")));
- _FDT((fdt_property_cell(fdt, "#address-cells", 0x1)));
- _FDT((fdt_property_cell(fdt, "#size-cells", 0x0)));
- _FDT((fdt_property_cell(fdt, "#interrupt-cells", 0x2)));
- _FDT((fdt_property(fdt, "interrupt-controller", NULL, 0)));
-
- _FDT((fdt_end_node(fdt)));
-
- /* event-sources */
- spapr_events_fdt_skel(fdt, epow_irq);
-
- /* /hypervisor node */
- if (kvm_enabled()) {
- uint8_t hypercall[16];
-
- /* indicate KVM hypercall interface */
- _FDT((fdt_begin_node(fdt, "hypervisor")));
- _FDT((fdt_property_string(fdt, "compatible", "linux,kvm")));
- if (kvmppc_has_cap_fixup_hcalls()) {
- /*
- * Older KVM versions with older guest kernels were broken with the
- * magic page, don't allow the guest to map it.
- */
- if (!kvmppc_get_hypercall(first_cpu->env_ptr, hypercall,
- sizeof(hypercall))) {
- _FDT((fdt_property(fdt, "hcall-instructions", hypercall,
- sizeof(hypercall))));
- }
- }
- _FDT((fdt_end_node(fdt)));
- }
-
- _FDT((fdt_end_node(fdt))); /* close root node */
- _FDT((fdt_finish(fdt)));
-
- return fdt;
-}
-
-static int spapr_populate_memory_node(void *fdt, int nodeid, hwaddr start,
- hwaddr size)
-{
- uint32_t associativity[] = {
- cpu_to_be32(0x4), /* length */
- cpu_to_be32(0x0), cpu_to_be32(0x0),
- cpu_to_be32(0x0), cpu_to_be32(nodeid)
- };
- char mem_name[32];
- uint64_t mem_reg_property[2];
- int off;
-
- mem_reg_property[0] = cpu_to_be64(start);
- mem_reg_property[1] = cpu_to_be64(size);
-
- sprintf(mem_name, "memory@" TARGET_FMT_lx, start);
- off = fdt_add_subnode(fdt, 0, mem_name);
- _FDT(off);
- _FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));
- _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property,
- sizeof(mem_reg_property))));
- _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity,
- sizeof(associativity))));
- return off;
-}
-
-static int spapr_populate_memory(sPAPRMachineState *spapr, void *fdt)
-{
- MachineState *machine = MACHINE(spapr);
- hwaddr mem_start, node_size;
- int i, nb_nodes = nb_numa_nodes;
- NodeInfo *nodes = numa_info;
- NodeInfo ramnode;
-
- /* No NUMA nodes, assume there is just one node with whole RAM */
- if (!nb_numa_nodes) {
- nb_nodes = 1;
- ramnode.node_mem = machine->ram_size;
- nodes = &ramnode;
- }
-
- for (i = 0, mem_start = 0; i < nb_nodes; ++i) {
- if (!nodes[i].node_mem) {
- continue;
- }
- if (mem_start >= machine->ram_size) {
- node_size = 0;
- } else {
- node_size = nodes[i].node_mem;
- if (node_size > machine->ram_size - mem_start) {
- node_size = machine->ram_size - mem_start;
- }
- }
- if (!mem_start) {
- /* ppc_spapr_init() checks for rma_size <= node0_size already */
- spapr_populate_memory_node(fdt, i, 0, spapr->rma_size);
- mem_start += spapr->rma_size;
- node_size -= spapr->rma_size;
- }
- for ( ; node_size; ) {
- hwaddr sizetmp = pow2floor(node_size);
-
- /* mem_start != 0 here */
- if (ctzl(mem_start) < ctzl(sizetmp)) {
- sizetmp = 1ULL << ctzl(mem_start);
- }
-
- spapr_populate_memory_node(fdt, i, mem_start, sizetmp);
- node_size -= sizetmp;
- mem_start += sizetmp;
- }
- }
-
- return 0;
-}
-
-static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset,
- sPAPRMachineState *spapr)
-{
- PowerPCCPU *cpu = POWERPC_CPU(cs);
- CPUPPCState *env = &cpu->env;
- PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
- int index = ppc_get_vcpu_dt_id(cpu);
- uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
- 0xffffffff, 0xffffffff};
- uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq() : TIMEBASE_FREQ;
- uint32_t cpufreq = kvm_enabled() ? kvmppc_get_clockfreq() : 1000000000;
- uint32_t page_sizes_prop[64];
- size_t page_sizes_prop_size;
- uint32_t vcpus_per_socket = smp_threads * smp_cores;
- uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)};
-
- /* Note: we keep CI large pages off for now because a 64K capable guest
- * provisioned with large pages might otherwise try to map a qemu
- * framebuffer (or other kind of memory mapped PCI BAR) using 64K pages
- * even if that qemu runs on a 4k host.
- *
- * We can later add this bit back when we are confident this is not
- * an issue (!HV KVM or 64K host)
- */
- uint8_t pa_features_206[] = { 6, 0,
- 0xf6, 0x1f, 0xc7, 0x00, 0x80, 0xc0 };
- uint8_t pa_features_207[] = { 24, 0,
- 0xf6, 0x1f, 0xc7, 0xc0, 0x80, 0xf0,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
- 0x80, 0x00, 0x80, 0x00, 0x80, 0x00 };
- uint8_t *pa_features;
- size_t pa_size;
-
- _FDT((fdt_setprop_cell(fdt, offset, "reg", index)));
- _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu")));
-
- _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR])));
- _FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size",
- env->dcache_line_size)));
- _FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size",
- env->dcache_line_size)));
- _FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size",
- env->icache_line_size)));
- _FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size",
- env->icache_line_size)));
-
- if (pcc->l1_dcache_size) {
- _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size",
- pcc->l1_dcache_size)));
- } else {
- fprintf(stderr, "Warning: Unknown L1 dcache size for cpu\n");
- }
- if (pcc->l1_icache_size) {
- _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size",
- pcc->l1_icache_size)));
- } else {
- fprintf(stderr, "Warning: Unknown L1 icache size for cpu\n");
- }
-
- _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq)));
- _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq)));
- _FDT((fdt_setprop_cell(fdt, offset, "slb-size", env->slb_nr)));
- _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", env->slb_nr)));
- _FDT((fdt_setprop_string(fdt, offset, "status", "okay")));
- _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0)));
-
- if (env->spr_cb[SPR_PURR].oea_read) {
- _FDT((fdt_setprop(fdt, offset, "ibm,purr", NULL, 0)));
- }
-
- if (env->mmu_model & POWERPC_MMU_1TSEG) {
- _FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes",
- segs, sizeof(segs))));
- }
-
- /* Advertise VMX/VSX (vector extensions) if available
- * 0 / no property == no vector extensions
- * 1 == VMX / Altivec available
- * 2 == VSX available */
- if (env->insns_flags & PPC_ALTIVEC) {
- uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1;
-
- _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", vmx)));
- }
-
- /* Advertise DFP (Decimal Floating Point) if available
- * 0 / no property == no DFP
- * 1 == DFP available */
- if (env->insns_flags2 & PPC2_DFP) {
- _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1)));
- }
-
- page_sizes_prop_size = create_page_sizes_prop(env, page_sizes_prop,
- sizeof(page_sizes_prop));
- if (page_sizes_prop_size) {
- _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes",
- page_sizes_prop, page_sizes_prop_size)));
- }
-
- /* Do the ibm,pa-features property, adjust it for ci-large-pages */
- if (env->mmu_model == POWERPC_MMU_2_06) {
- pa_features = pa_features_206;
- pa_size = sizeof(pa_features_206);
- } else /* env->mmu_model == POWERPC_MMU_2_07 */ {
- pa_features = pa_features_207;
- pa_size = sizeof(pa_features_207);
- }
- if (env->ci_large_pages) {
- pa_features[3] |= 0x20;
- }
- _FDT((fdt_setprop(fdt, offset, "ibm,pa-features", pa_features, pa_size)));
-
- _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id",
- cs->cpu_index / vcpus_per_socket)));
-
- _FDT((fdt_setprop(fdt, offset, "ibm,pft-size",
- pft_size_prop, sizeof(pft_size_prop))));
-
- _FDT(spapr_fixup_cpu_numa_dt(fdt, offset, cs));
-
- _FDT(spapr_fixup_cpu_smt_dt(fdt, offset, cpu,
- ppc_get_compat_smt_threads(cpu)));
-}
-
-static void spapr_populate_cpus_dt_node(void *fdt, sPAPRMachineState *spapr)
-{
- CPUState *cs;
- int cpus_offset;
- char *nodename;
- int smt = kvmppc_smt_threads();
-
- cpus_offset = fdt_add_subnode(fdt, 0, "cpus");
- _FDT(cpus_offset);
- _FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1)));
- _FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0)));
-
- /*
- * We walk the CPUs in reverse order to ensure that CPU DT nodes
- * created by fdt_add_subnode() end up in the right order in FDT
- * for the guest kernel the enumerate the CPUs correctly.
- */
- CPU_FOREACH_REVERSE(cs) {
- PowerPCCPU *cpu = POWERPC_CPU(cs);
- int index = ppc_get_vcpu_dt_id(cpu);
- DeviceClass *dc = DEVICE_GET_CLASS(cs);
- int offset;
-
- if ((index % smt) != 0) {
- continue;
- }
-
- nodename = g_strdup_printf("%s@%x", dc->fw_name, index);
- offset = fdt_add_subnode(fdt, cpus_offset, nodename);
- g_free(nodename);
- _FDT(offset);
- spapr_populate_cpu_dt(cs, fdt, offset, spapr);
- }
-
-}
-
-/*
- * Adds ibm,dynamic-reconfiguration-memory node.
- * Refer to docs/specs/ppc-spapr-hotplug.txt for the documentation
- * of this device tree node.
- */
-static int spapr_populate_drconf_memory(sPAPRMachineState *spapr, void *fdt)
-{
- MachineState *machine = MACHINE(spapr);
- int ret, i, offset;
- uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
- uint32_t prop_lmb_size[] = {0, cpu_to_be32(lmb_size)};
- uint32_t nr_lmbs = (machine->maxram_size - machine->ram_size)/lmb_size;
- uint32_t *int_buf, *cur_index, buf_len;
- int nr_nodes = nb_numa_nodes ? nb_numa_nodes : 1;
-
- /*
- * Don't create the node if there are no DR LMBs.
- */
- if (!nr_lmbs) {
- return 0;
- }
-
- /*
- * Allocate enough buffer size to fit in ibm,dynamic-memory
- * or ibm,associativity-lookup-arrays
- */
- buf_len = MAX(nr_lmbs * SPAPR_DR_LMB_LIST_ENTRY_SIZE + 1, nr_nodes * 4 + 2)
- * sizeof(uint32_t);
- cur_index = int_buf = g_malloc0(buf_len);
-
- offset = fdt_add_subnode(fdt, 0, "ibm,dynamic-reconfiguration-memory");
-
- ret = fdt_setprop(fdt, offset, "ibm,lmb-size", prop_lmb_size,
- sizeof(prop_lmb_size));
- if (ret < 0) {
- goto out;
- }
-
- ret = fdt_setprop_cell(fdt, offset, "ibm,memory-flags-mask", 0xff);
- if (ret < 0) {
- goto out;
- }
-
- ret = fdt_setprop_cell(fdt, offset, "ibm,memory-preservation-time", 0x0);
- if (ret < 0) {
- goto out;
- }
-
- /* ibm,dynamic-memory */
- int_buf[0] = cpu_to_be32(nr_lmbs);
- cur_index++;
- for (i = 0; i < nr_lmbs; i++) {
- sPAPRDRConnector *drc;
- sPAPRDRConnectorClass *drck;
- uint64_t addr = i * lmb_size + spapr->hotplug_memory.base;;
- uint32_t *dynamic_memory = cur_index;
-
- drc = spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_LMB,
- addr/lmb_size);
- g_assert(drc);
- drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
-
- dynamic_memory[0] = cpu_to_be32(addr >> 32);
- dynamic_memory[1] = cpu_to_be32(addr & 0xffffffff);
- dynamic_memory[2] = cpu_to_be32(drck->get_index(drc));
- dynamic_memory[3] = cpu_to_be32(0); /* reserved */
- dynamic_memory[4] = cpu_to_be32(numa_get_node(addr, NULL));
- if (addr < machine->ram_size ||
- memory_region_present(get_system_memory(), addr)) {
- dynamic_memory[5] = cpu_to_be32(SPAPR_LMB_FLAGS_ASSIGNED);
- } else {
- dynamic_memory[5] = cpu_to_be32(0);
- }
-
- cur_index += SPAPR_DR_LMB_LIST_ENTRY_SIZE;
- }
- ret = fdt_setprop(fdt, offset, "ibm,dynamic-memory", int_buf, buf_len);
- if (ret < 0) {
- goto out;
- }
-
- /* ibm,associativity-lookup-arrays */
- cur_index = int_buf;
- int_buf[0] = cpu_to_be32(nr_nodes);
- int_buf[1] = cpu_to_be32(4); /* Number of entries per associativity list */
- cur_index += 2;
- for (i = 0; i < nr_nodes; i++) {
- uint32_t associativity[] = {
- cpu_to_be32(0x0),
- cpu_to_be32(0x0),
- cpu_to_be32(0x0),
- cpu_to_be32(i)
- };
- memcpy(cur_index, associativity, sizeof(associativity));
- cur_index += 4;
- }
- ret = fdt_setprop(fdt, offset, "ibm,associativity-lookup-arrays", int_buf,
- (cur_index - int_buf) * sizeof(uint32_t));
-out:
- g_free(int_buf);
- return ret;
-}
-
-int spapr_h_cas_compose_response(sPAPRMachineState *spapr,
- target_ulong addr, target_ulong size,
- bool cpu_update, bool memory_update)
-{
- void *fdt, *fdt_skel;
- sPAPRDeviceTreeUpdateHeader hdr = { .version_id = 1 };
- sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(qdev_get_machine());
-
- size -= sizeof(hdr);
-
- /* Create sceleton */
- fdt_skel = g_malloc0(size);
- _FDT((fdt_create(fdt_skel, size)));
- _FDT((fdt_begin_node(fdt_skel, "")));
- _FDT((fdt_end_node(fdt_skel)));
- _FDT((fdt_finish(fdt_skel)));
- fdt = g_malloc0(size);
- _FDT((fdt_open_into(fdt_skel, fdt, size)));
- g_free(fdt_skel);
-
- /* Fixup cpu nodes */
- if (cpu_update) {
- _FDT((spapr_fixup_cpu_dt(fdt, spapr)));
- }
-
- /* Generate ibm,dynamic-reconfiguration-memory node if required */
- if (memory_update && smc->dr_lmb_enabled) {
- _FDT((spapr_populate_drconf_memory(spapr, fdt)));
- }
-
- /* Pack resulting tree */
- _FDT((fdt_pack(fdt)));
-
- if (fdt_totalsize(fdt) + sizeof(hdr) > size) {
- trace_spapr_cas_failed(size);
- return -1;
- }
-
- cpu_physical_memory_write(addr, &hdr, sizeof(hdr));
- cpu_physical_memory_write(addr + sizeof(hdr), fdt, fdt_totalsize(fdt));
- trace_spapr_cas_continue(fdt_totalsize(fdt) + sizeof(hdr));
- g_free(fdt);
-
- return 0;
-}
-
-static void spapr_finalize_fdt(sPAPRMachineState *spapr,
- hwaddr fdt_addr,
- hwaddr rtas_addr,
- hwaddr rtas_size)
-{
- MachineState *machine = MACHINE(qdev_get_machine());
- sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
- const char *boot_device = machine->boot_order;
- int ret, i;
- size_t cb = 0;
- char *bootlist;
- void *fdt;
- sPAPRPHBState *phb;
-
- fdt = g_malloc(FDT_MAX_SIZE);
-
- /* open out the base tree into a temp buffer for the final tweaks */
- _FDT((fdt_open_into(spapr->fdt_skel, fdt, FDT_MAX_SIZE)));
-
- ret = spapr_populate_memory(spapr, fdt);
- if (ret < 0) {
- fprintf(stderr, "couldn't setup memory nodes in fdt\n");
- exit(1);
- }
-
- ret = spapr_populate_vdevice(spapr->vio_bus, fdt);
- if (ret < 0) {
- fprintf(stderr, "couldn't setup vio devices in fdt\n");
- exit(1);
- }
-
- if (object_resolve_path_type("", TYPE_SPAPR_RNG, NULL)) {
- ret = spapr_rng_populate_dt(fdt);
- if (ret < 0) {
- fprintf(stderr, "could not set up rng device in the fdt\n");
- exit(1);
- }
- }
-
- QLIST_FOREACH(phb, &spapr->phbs, list) {
- ret = spapr_populate_pci_dt(phb, PHANDLE_XICP, fdt);
- if (ret < 0) {
- error_report("couldn't setup PCI devices in fdt");
- exit(1);
- }
- }
-
- /* RTAS */
- ret = spapr_rtas_device_tree_setup(fdt, rtas_addr, rtas_size);
- if (ret < 0) {
- fprintf(stderr, "Couldn't set up RTAS device tree properties\n");
- }
-
- /* cpus */
- spapr_populate_cpus_dt_node(fdt, spapr);
-
- bootlist = get_boot_devices_list(&cb, true);
- if (cb && bootlist) {
- int offset = fdt_path_offset(fdt, "/chosen");
- if (offset < 0) {
- exit(1);
- }
- for (i = 0; i < cb; i++) {
- if (bootlist[i] == '\n') {
- bootlist[i] = ' ';
- }
-
- }
- ret = fdt_setprop_string(fdt, offset, "qemu,boot-list", bootlist);
- }
-
- if (boot_device && strlen(boot_device)) {
- int offset = fdt_path_offset(fdt, "/chosen");
-
- if (offset < 0) {
- exit(1);
- }
- fdt_setprop_string(fdt, offset, "qemu,boot-device", boot_device);
- }
-
- if (!spapr->has_graphics) {
- spapr_populate_chosen_stdout(fdt, spapr->vio_bus);
- }
-
- if (smc->dr_lmb_enabled) {
- _FDT(spapr_drc_populate_dt(fdt, 0, NULL, SPAPR_DR_CONNECTOR_TYPE_LMB));
- }
-
- _FDT((fdt_pack(fdt)));
-
- if (fdt_totalsize(fdt) > FDT_MAX_SIZE) {
- error_report("FDT too big ! 0x%x bytes (max is 0x%x)",
- fdt_totalsize(fdt), FDT_MAX_SIZE);
- exit(1);
- }
-
- qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt));
- cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt));
-
- g_free(bootlist);
- g_free(fdt);
-}
-
-static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
-{
- return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR;
-}
-
-static void emulate_spapr_hypercall(PowerPCCPU *cpu)
-{
- CPUPPCState *env = &cpu->env;
-
- if (msr_pr) {
- hcall_dprintf("Hypercall made with MSR[PR]=1\n");
- env->gpr[3] = H_PRIVILEGE;
- } else {
- env->gpr[3] = spapr_hypercall(cpu, env->gpr[3], &env->gpr[4]);
- }
-}
-
-#define HPTE(_table, _i) (void *)(((uint64_t *)(_table)) + ((_i) * 2))
-#define HPTE_VALID(_hpte) (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_VALID)
-#define HPTE_DIRTY(_hpte) (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_HPTE_DIRTY)
-#define CLEAN_HPTE(_hpte) ((*(uint64_t *)(_hpte)) &= tswap64(~HPTE64_V_HPTE_DIRTY))
-#define DIRTY_HPTE(_hpte) ((*(uint64_t *)(_hpte)) |= tswap64(HPTE64_V_HPTE_DIRTY))
-
-/*
- * Get the fd to access the kernel htab, re-opening it if necessary
- */
-static int get_htab_fd(sPAPRMachineState *spapr)
-{
- if (spapr->htab_fd >= 0) {
- return spapr->htab_fd;
- }
-
- spapr->htab_fd = kvmppc_get_htab_fd(false);
- if (spapr->htab_fd < 0) {
- error_report("Unable to open fd for reading hash table from KVM: %s",
- strerror(errno));
- }
-
- return spapr->htab_fd;
-}
-
-static void close_htab_fd(sPAPRMachineState *spapr)
-{
- if (spapr->htab_fd >= 0) {
- close(spapr->htab_fd);
- }
- spapr->htab_fd = -1;
-}
-
-static int spapr_hpt_shift_for_ramsize(uint64_t ramsize)
-{
- int shift;
-
- /* We aim for a hash table of size 1/128 the size of RAM (rounded
- * up). The PAPR recommendation is actually 1/64 of RAM size, but
- * that's much more than is needed for Linux guests */
- shift = ctz64(pow2ceil(ramsize)) - 7;
- shift = MAX(shift, 18); /* Minimum architected size */
- shift = MIN(shift, 46); /* Maximum architected size */
- return shift;
-}
-
-static void spapr_reallocate_hpt(sPAPRMachineState *spapr, int shift,
- Error **errp)
-{
- long rc;
-
- /* Clean up any HPT info from a previous boot */
- g_free(spapr->htab);
- spapr->htab = NULL;
- spapr->htab_shift = 0;
- close_htab_fd(spapr);
-
- rc = kvmppc_reset_htab(shift);
- if (rc < 0) {
- /* kernel-side HPT needed, but couldn't allocate one */
- error_setg_errno(errp, errno,
- "Failed to allocate KVM HPT of order %d (try smaller maxmem?)",
- shift);
- /* This is almost certainly fatal, but if the caller really
- * wants to carry on with shift == 0, it's welcome to try */
- } else if (rc > 0) {
- /* kernel-side HPT allocated */
- if (rc != shift) {
- error_setg(errp,
- "Requested order %d HPT, but kernel allocated order %ld (try smaller maxmem?)",
- shift, rc);
- }
-
- spapr->htab_shift = shift;
- spapr->htab = NULL;
- } else {
- /* kernel-side HPT not needed, allocate in userspace instead */
- size_t size = 1ULL << shift;
- int i;
-
- spapr->htab = qemu_memalign(size, size);
- if (!spapr->htab) {
- error_setg_errno(errp, errno,
- "Could not allocate HPT of order %d", shift);
- return;
- }
-
- memset(spapr->htab, 0, size);
- spapr->htab_shift = shift;
-
- for (i = 0; i < size / HASH_PTE_SIZE_64; i++) {
- DIRTY_HPTE(HPTE(spapr->htab, i));
- }
- }
-}
-
-static int find_unknown_sysbus_device(SysBusDevice *sbdev, void *opaque)
-{
- bool matched = false;
-
- if (object_dynamic_cast(OBJECT(sbdev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
- matched = true;
- }
-
- if (!matched) {
- error_report("Device %s is not supported by this machine yet.",
- qdev_fw_name(DEVICE(sbdev)));
- exit(1);
- }
-
- return 0;
-}
-
-static void ppc_spapr_reset(void)
-{
- MachineState *machine = MACHINE(qdev_get_machine());
- sPAPRMachineState *spapr = SPAPR_MACHINE(machine);
- PowerPCCPU *first_ppc_cpu;
- uint32_t rtas_limit;
-
- /* Check for unknown sysbus devices */
- foreach_dynamic_sysbus_device(find_unknown_sysbus_device, NULL);
-
- /* Allocate and/or reset the hash page table */
- spapr_reallocate_hpt(spapr,
- spapr_hpt_shift_for_ramsize(machine->maxram_size),
- &error_fatal);
-
- /* Update the RMA size if necessary */
- if (spapr->vrma_adjust) {
- spapr->rma_size = kvmppc_rma_size(spapr_node0_size(),
- spapr->htab_shift);
- }
-
- qemu_devices_reset();
-
- /*
- * We place the device tree and RTAS just below either the top of the RMA,
- * or just below 2GB, whichever is lowere, so that it can be
- * processed with 32-bit real mode code if necessary
- */
- rtas_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR);
- spapr->rtas_addr = rtas_limit - RTAS_MAX_SIZE;
- spapr->fdt_addr = spapr->rtas_addr - FDT_MAX_SIZE;
-
- /* Load the fdt */
- spapr_finalize_fdt(spapr, spapr->fdt_addr, spapr->rtas_addr,
- spapr->rtas_size);
-
- /* Copy RTAS over */
- cpu_physical_memory_write(spapr->rtas_addr, spapr->rtas_blob,
- spapr->rtas_size);
-
- /* Set up the entry state */
- first_ppc_cpu = POWERPC_CPU(first_cpu);
- first_ppc_cpu->env.gpr[3] = spapr->fdt_addr;
- first_ppc_cpu->env.gpr[5] = 0;
- first_cpu->halted = 0;
- first_ppc_cpu->env.nip = SPAPR_ENTRY_POINT;
-
-}
-
-static void spapr_cpu_reset(void *opaque)
-{
- sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
- PowerPCCPU *cpu = opaque;
- CPUState *cs = CPU(cpu);
- CPUPPCState *env = &cpu->env;
-
- cpu_reset(cs);
-
- /* All CPUs start halted. CPU0 is unhalted from the machine level
- * reset code and the rest are explicitly started up by the guest
- * using an RTAS call */
- cs->halted = 1;
-
- env->spr[SPR_HIOR] = 0;
-
- ppc_hash64_set_external_hpt(cpu, spapr->htab, spapr->htab_shift,
- &error_fatal);
-}
-
-static void spapr_create_nvram(sPAPRMachineState *spapr)
-{
- DeviceState *dev = qdev_create(&spapr->vio_bus->bus, "spapr-nvram");
- DriveInfo *dinfo = drive_get(IF_PFLASH, 0, 0);
-
- if (dinfo) {
- qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(dinfo),
- &error_fatal);
- }
-
- qdev_init_nofail(dev);
-
- spapr->nvram = (struct sPAPRNVRAM *)dev;
-}
-
-static void spapr_rtc_create(sPAPRMachineState *spapr)
-{
- DeviceState *dev = qdev_create(NULL, TYPE_SPAPR_RTC);
-
- qdev_init_nofail(dev);
- spapr->rtc = dev;
-
- object_property_add_alias(qdev_get_machine(), "rtc-time",
- OBJECT(spapr->rtc), "date", NULL);
-}
-
-/* Returns whether we want to use VGA or not */
-static bool spapr_vga_init(PCIBus *pci_bus, Error **errp)
-{
- switch (vga_interface_type) {
- case VGA_NONE:
- return false;
- case VGA_DEVICE:
- return true;
- case VGA_STD:
- case VGA_VIRTIO:
- return pci_vga_init(pci_bus) != NULL;
- default:
- error_setg(errp,
- "Unsupported VGA mode, only -vga std or -vga virtio is supported");
- return false;
- }
-}
-
-static int spapr_post_load(void *opaque, int version_id)
-{
- sPAPRMachineState *spapr = (sPAPRMachineState *)opaque;
- int err = 0;
-
- /* In earlier versions, there was no separate qdev for the PAPR
- * RTC, so the RTC offset was stored directly in sPAPREnvironment.
- * So when migrating from those versions, poke the incoming offset
- * value into the RTC device */
- if (version_id < 3) {
- err = spapr_rtc_import_offset(spapr->rtc, spapr->rtc_offset);
- }
-
- return err;
-}
-
-static bool version_before_3(void *opaque, int version_id)
-{
- return version_id < 3;
-}
-
-static const VMStateDescription vmstate_spapr = {
- .name = "spapr",
- .version_id = 3,
- .minimum_version_id = 1,
- .post_load = spapr_post_load,
- .fields = (VMStateField[]) {
- /* used to be @next_irq */
- VMSTATE_UNUSED_BUFFER(version_before_3, 0, 4),
-
- /* RTC offset */
- VMSTATE_UINT64_TEST(rtc_offset, sPAPRMachineState, version_before_3),
-
- VMSTATE_PPC_TIMEBASE_V(tb, sPAPRMachineState, 2),
- VMSTATE_END_OF_LIST()
- },
-};
-
-static int htab_save_setup(QEMUFile *f, void *opaque)
-{
- sPAPRMachineState *spapr = opaque;
-
- /* "Iteration" header */
- qemu_put_be32(f, spapr->htab_shift);
-
- if (spapr->htab) {
- spapr->htab_save_index = 0;
- spapr->htab_first_pass = true;
- } else {
- assert(kvm_enabled());
- }
-
-
- return 0;
-}
-
-static void htab_save_first_pass(QEMUFile *f, sPAPRMachineState *spapr,
- int64_t max_ns)
-{
- bool has_timeout = max_ns != -1;
- int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64;
- int index = spapr->htab_save_index;
- int64_t starttime = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
-
- assert(spapr->htab_first_pass);
-
- do {
- int chunkstart;
-
- /* Consume invalid HPTEs */
- while ((index < htabslots)
- && !HPTE_VALID(HPTE(spapr->htab, index))) {
- index++;
- CLEAN_HPTE(HPTE(spapr->htab, index));
- }
-
- /* Consume valid HPTEs */
- chunkstart = index;
- while ((index < htabslots) && (index - chunkstart < USHRT_MAX)
- && HPTE_VALID(HPTE(spapr->htab, index))) {
- index++;
- CLEAN_HPTE(HPTE(spapr->htab, index));
- }
-
- if (index > chunkstart) {
- int n_valid = index - chunkstart;
-
- qemu_put_be32(f, chunkstart);
- qemu_put_be16(f, n_valid);
- qemu_put_be16(f, 0);
- qemu_put_buffer(f, HPTE(spapr->htab, chunkstart),
- HASH_PTE_SIZE_64 * n_valid);
-
- if (has_timeout &&
- (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) > max_ns) {
- break;
- }
- }
- } while ((index < htabslots) && !qemu_file_rate_limit(f));
-
- if (index >= htabslots) {
- assert(index == htabslots);
- index = 0;
- spapr->htab_first_pass = false;
- }
- spapr->htab_save_index = index;
-}
-
-static int htab_save_later_pass(QEMUFile *f, sPAPRMachineState *spapr,
- int64_t max_ns)
-{
- bool final = max_ns < 0;
- int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64;
- int examined = 0, sent = 0;
- int index = spapr->htab_save_index;
- int64_t starttime = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
-
- assert(!spapr->htab_first_pass);
-
- do {
- int chunkstart, invalidstart;
-
- /* Consume non-dirty HPTEs */
- while ((index < htabslots)
- && !HPTE_DIRTY(HPTE(spapr->htab, index))) {
- index++;
- examined++;
- }
-
- chunkstart = index;
- /* Consume valid dirty HPTEs */
- while ((index < htabslots) && (index - chunkstart < USHRT_MAX)
- && HPTE_DIRTY(HPTE(spapr->htab, index))
- && HPTE_VALID(HPTE(spapr->htab, index))) {
- CLEAN_HPTE(HPTE(spapr->htab, index));
- index++;
- examined++;
- }
-
- invalidstart = index;
- /* Consume invalid dirty HPTEs */
- while ((index < htabslots) && (index - invalidstart < USHRT_MAX)
- && HPTE_DIRTY(HPTE(spapr->htab, index))
- && !HPTE_VALID(HPTE(spapr->htab, index))) {
- CLEAN_HPTE(HPTE(spapr->htab, index));
- index++;
- examined++;
- }
-
- if (index > chunkstart) {
- int n_valid = invalidstart - chunkstart;
- int n_invalid = index - invalidstart;
-
- qemu_put_be32(f, chunkstart);
- qemu_put_be16(f, n_valid);
- qemu_put_be16(f, n_invalid);
- qemu_put_buffer(f, HPTE(spapr->htab, chunkstart),
- HASH_PTE_SIZE_64 * n_valid);
- sent += index - chunkstart;
-
- if (!final && (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) > max_ns) {
- break;
- }
- }
-
- if (examined >= htabslots) {
- break;
- }
-
- if (index >= htabslots) {
- assert(index == htabslots);
- index = 0;
- }
- } while ((examined < htabslots) && (!qemu_file_rate_limit(f) || final));
-
- if (index >= htabslots) {
- assert(index == htabslots);
- index = 0;
- }
-
- spapr->htab_save_index = index;
-
- return (examined >= htabslots) && (sent == 0) ? 1 : 0;
-}
-
-#define MAX_ITERATION_NS 5000000 /* 5 ms */
-#define MAX_KVM_BUF_SIZE 2048
-
-static int htab_save_iterate(QEMUFile *f, void *opaque)
-{
- sPAPRMachineState *spapr = opaque;
- int fd;
- int rc = 0;
-
- /* Iteration header */
- qemu_put_be32(f, 0);
-
- if (!spapr->htab) {
- assert(kvm_enabled());
-
- fd = get_htab_fd(spapr);
- if (fd < 0) {
- return fd;
- }
-
- rc = kvmppc_save_htab(f, fd, MAX_KVM_BUF_SIZE, MAX_ITERATION_NS);
- if (rc < 0) {
- return rc;
- }
- } else if (spapr->htab_first_pass) {
- htab_save_first_pass(f, spapr, MAX_ITERATION_NS);
- } else {
- rc = htab_save_later_pass(f, spapr, MAX_ITERATION_NS);
- }
-
- /* End marker */
- qemu_put_be32(f, 0);
- qemu_put_be16(f, 0);
- qemu_put_be16(f, 0);
-
- return rc;
-}
-
-static int htab_save_complete(QEMUFile *f, void *opaque)
-{
- sPAPRMachineState *spapr = opaque;
- int fd;
-
- /* Iteration header */
- qemu_put_be32(f, 0);
-
- if (!spapr->htab) {
- int rc;
-
- assert(kvm_enabled());
-
- fd = get_htab_fd(spapr);
- if (fd < 0) {
- return fd;
- }
-
- rc = kvmppc_save_htab(f, fd, MAX_KVM_BUF_SIZE, -1);
- if (rc < 0) {
- return rc;
- }
- close_htab_fd(spapr);
- } else {
- if (spapr->htab_first_pass) {
- htab_save_first_pass(f, spapr, -1);
- }
- htab_save_later_pass(f, spapr, -1);
- }
-
- /* End marker */
- qemu_put_be32(f, 0);
- qemu_put_be16(f, 0);
- qemu_put_be16(f, 0);
-
- return 0;
-}
-
-static int htab_load(QEMUFile *f, void *opaque, int version_id)
-{
- sPAPRMachineState *spapr = opaque;
- uint32_t section_hdr;
- int fd = -1;
-
- if (version_id < 1 || version_id > 1) {
- error_report("htab_load() bad version");
- return -EINVAL;
- }
-
- section_hdr = qemu_get_be32(f);
-
- if (section_hdr) {
- Error *local_err = NULL;
-
- /* First section gives the htab size */
- spapr_reallocate_hpt(spapr, section_hdr, &local_err);
- if (local_err) {
- error_report_err(local_err);
- return -EINVAL;
- }
- return 0;
- }
-
- if (!spapr->htab) {
- assert(kvm_enabled());
-
- fd = kvmppc_get_htab_fd(true);
- if (fd < 0) {
- error_report("Unable to open fd to restore KVM hash table: %s",
- strerror(errno));
- }
- }
-
- while (true) {
- uint32_t index;
- uint16_t n_valid, n_invalid;
-
- index = qemu_get_be32(f);
- n_valid = qemu_get_be16(f);
- n_invalid = qemu_get_be16(f);
-
- if ((index == 0) && (n_valid == 0) && (n_invalid == 0)) {
- /* End of Stream */
- break;
- }
-
- if ((index + n_valid + n_invalid) >
- (HTAB_SIZE(spapr) / HASH_PTE_SIZE_64)) {
- /* Bad index in stream */
- error_report(
- "htab_load() bad index %d (%hd+%hd entries) in htab stream (htab_shift=%d)",
- index, n_valid, n_invalid, spapr->htab_shift);
- return -EINVAL;
- }
-
- if (spapr->htab) {
- if (n_valid) {
- qemu_get_buffer(f, HPTE(spapr->htab, index),
- HASH_PTE_SIZE_64 * n_valid);
- }
- if (n_invalid) {
- memset(HPTE(spapr->htab, index + n_valid), 0,
- HASH_PTE_SIZE_64 * n_invalid);
- }
- } else {
- int rc;
-
- assert(fd >= 0);
-
- rc = kvmppc_load_htab_chunk(f, fd, index, n_valid, n_invalid);
- if (rc < 0) {
- return rc;
- }
- }
- }
-
- if (!spapr->htab) {
- assert(fd >= 0);
- close(fd);
- }
-
- return 0;
-}
-
-static SaveVMHandlers savevm_htab_handlers = {
- .save_live_setup = htab_save_setup,
- .save_live_iterate = htab_save_iterate,
- .save_live_complete_precopy = htab_save_complete,
- .load_state = htab_load,
-};
-
-static void spapr_boot_set(void *opaque, const char *boot_device,
- Error **errp)
-{
- MachineState *machine = MACHINE(qdev_get_machine());
- machine->boot_order = g_strdup(boot_device);
-}
-
-static void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu,
- Error **errp)
-{
- CPUPPCState *env = &cpu->env;
-
- /* Set time-base frequency to 512 MHz */
- cpu_ppc_tb_init(env, TIMEBASE_FREQ);
-
- /* Enable PAPR mode in TCG or KVM */
- cpu_ppc_set_papr(cpu);
-
- if (cpu->max_compat) {
- Error *local_err = NULL;
-
- ppc_set_compat(cpu, cpu->max_compat, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
- }
-
- xics_cpu_setup(spapr->icp, cpu);
-
- qemu_register_reset(spapr_cpu_reset, cpu);
-}
-
-/*
- * Reset routine for LMB DR devices.
- *
- * Unlike PCI DR devices, LMB DR devices explicitly register this reset
- * routine. Reset for PCI DR devices will be handled by PHB reset routine
- * when it walks all its children devices. LMB devices reset occurs
- * as part of spapr_ppc_reset().
- */
-static void spapr_drc_reset(void *opaque)
-{
- sPAPRDRConnector *drc = opaque;
- DeviceState *d = DEVICE(drc);
-
- if (d) {
- device_reset(d);
- }
-}
-
-static void spapr_create_lmb_dr_connectors(sPAPRMachineState *spapr)
-{
- MachineState *machine = MACHINE(spapr);
- uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
- uint32_t nr_lmbs = (machine->maxram_size - machine->ram_size)/lmb_size;
- int i;
-
- for (i = 0; i < nr_lmbs; i++) {
- sPAPRDRConnector *drc;
- uint64_t addr;
-
- addr = i * lmb_size + spapr->hotplug_memory.base;
- drc = spapr_dr_connector_new(OBJECT(spapr), SPAPR_DR_CONNECTOR_TYPE_LMB,
- addr/lmb_size);
- qemu_register_reset(spapr_drc_reset, drc);
- }
-}
-
-/*
- * If RAM size, maxmem size and individual node mem sizes aren't aligned
- * to SPAPR_MEMORY_BLOCK_SIZE(256MB), then refuse to start the guest
- * since we can't support such unaligned sizes with DRCONF_MEMORY.
- */
-static void spapr_validate_node_memory(MachineState *machine, Error **errp)
-{
- int i;
-
- if (machine->ram_size % SPAPR_MEMORY_BLOCK_SIZE) {
- error_setg(errp, "Memory size 0x" RAM_ADDR_FMT
- " is not aligned to %llu MiB",
- machine->ram_size,
- SPAPR_MEMORY_BLOCK_SIZE / M_BYTE);
- return;
- }
-
- if (machine->maxram_size % SPAPR_MEMORY_BLOCK_SIZE) {
- error_setg(errp, "Maximum memory size 0x" RAM_ADDR_FMT
- " is not aligned to %llu MiB",
- machine->ram_size,
- SPAPR_MEMORY_BLOCK_SIZE / M_BYTE);
- return;
- }
-
- for (i = 0; i < nb_numa_nodes; i++) {
- if (numa_info[i].node_mem % SPAPR_MEMORY_BLOCK_SIZE) {
- error_setg(errp,
- "Node %d memory size 0x%" PRIx64
- " is not aligned to %llu MiB",
- i, numa_info[i].node_mem,
- SPAPR_MEMORY_BLOCK_SIZE / M_BYTE);
- return;
- }
- }
-}
-
-/* pSeries LPAR / sPAPR hardware init */
-static void ppc_spapr_init(MachineState *machine)
-{
- sPAPRMachineState *spapr = SPAPR_MACHINE(machine);
- sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- const char *initrd_filename = machine->initrd_filename;
- PowerPCCPU *cpu;
- PCIHostState *phb;
- int i;
- MemoryRegion *sysmem = get_system_memory();
- MemoryRegion *ram = g_new(MemoryRegion, 1);
- MemoryRegion *rma_region;
- void *rma = NULL;
- hwaddr rma_alloc_size;
- hwaddr node0_size = spapr_node0_size();
- uint32_t initrd_base = 0;
- long kernel_size = 0, initrd_size = 0;
- long load_limit, fw_size;
- bool kernel_le = false;
- char *filename;
-
- msi_nonbroken = true;
-
- QLIST_INIT(&spapr->phbs);
-
- cpu_ppc_hypercall = emulate_spapr_hypercall;
-
- /* Allocate RMA if necessary */
- rma_alloc_size = kvmppc_alloc_rma(&rma);
-
- if (rma_alloc_size == -1) {
- error_report("Unable to create RMA");
- exit(1);
- }
-
- if (rma_alloc_size && (rma_alloc_size < node0_size)) {
- spapr->rma_size = rma_alloc_size;
- } else {
- spapr->rma_size = node0_size;
-
- /* With KVM, we don't actually know whether KVM supports an
- * unbounded RMA (PR KVM) or is limited by the hash table size
- * (HV KVM using VRMA), so we always assume the latter
- *
- * In that case, we also limit the initial allocations for RTAS
- * etc... to 256M since we have no way to know what the VRMA size
- * is going to be as it depends on the size of the hash table
- * isn't determined yet.
- */
- if (kvm_enabled()) {
- spapr->vrma_adjust = 1;
- spapr->rma_size = MIN(spapr->rma_size, 0x10000000);
- }
- }
-
- if (spapr->rma_size > node0_size) {
- error_report("Numa node 0 has to span the RMA (%#08"HWADDR_PRIx")",
- spapr->rma_size);
- exit(1);
- }
-
- /* Setup a load limit for the ramdisk leaving room for SLOF and FDT */
- load_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FW_OVERHEAD;
-
- /* Set up Interrupt Controller before we create the VCPUs */
- spapr->icp = xics_system_init(machine,
- DIV_ROUND_UP(max_cpus * kvmppc_smt_threads(),
- smp_threads),
- XICS_IRQS, &error_fatal);
-
- if (smc->dr_lmb_enabled) {
- spapr_validate_node_memory(machine, &error_fatal);
- }
-
- /* init CPUs */
- if (machine->cpu_model == NULL) {
- machine->cpu_model = kvm_enabled() ? "host" : "POWER7";
- }
- for (i = 0; i < smp_cpus; i++) {
- cpu = cpu_ppc_init(machine->cpu_model);
- if (cpu == NULL) {
- error_report("Unable to find PowerPC CPU definition");
- exit(1);
- }
- spapr_cpu_init(spapr, cpu, &error_fatal);
- }
-
- if (kvm_enabled()) {
- /* Enable H_LOGICAL_CI_* so SLOF can talk to in-kernel devices */
- kvmppc_enable_logical_ci_hcalls();
- kvmppc_enable_set_mode_hcall();
- }
-
- /* allocate RAM */
- memory_region_allocate_system_memory(ram, NULL, "ppc_spapr.ram",
- machine->ram_size);
- memory_region_add_subregion(sysmem, 0, ram);
-
- if (rma_alloc_size && rma) {
- rma_region = g_new(MemoryRegion, 1);
- memory_region_init_ram_ptr(rma_region, NULL, "ppc_spapr.rma",
- rma_alloc_size, rma);
- vmstate_register_ram_global(rma_region);
- memory_region_add_subregion(sysmem, 0, rma_region);
- }
-
- /* initialize hotplug memory address space */
- if (machine->ram_size < machine->maxram_size) {
- ram_addr_t hotplug_mem_size = machine->maxram_size - machine->ram_size;
-
- if (machine->ram_slots > SPAPR_MAX_RAM_SLOTS) {
- error_report("Specified number of memory slots %"
- PRIu64" exceeds max supported %d",
- machine->ram_slots, SPAPR_MAX_RAM_SLOTS);
- exit(1);
- }
-
- spapr->hotplug_memory.base = ROUND_UP(machine->ram_size,
- SPAPR_HOTPLUG_MEM_ALIGN);
- memory_region_init(&spapr->hotplug_memory.mr, OBJECT(spapr),
- "hotplug-memory", hotplug_mem_size);
- memory_region_add_subregion(sysmem, spapr->hotplug_memory.base,
- &spapr->hotplug_memory.mr);
- }
-
- if (smc->dr_lmb_enabled) {
- spapr_create_lmb_dr_connectors(spapr);
- }
-
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin");
- if (!filename) {
- error_report("Could not find LPAR rtas '%s'", "spapr-rtas.bin");
- exit(1);
- }
- spapr->rtas_size = get_image_size(filename);
- spapr->rtas_blob = g_malloc(spapr->rtas_size);
- if (load_image_size(filename, spapr->rtas_blob, spapr->rtas_size) < 0) {
- error_report("Could not load LPAR rtas '%s'", filename);
- exit(1);
- }
- if (spapr->rtas_size > RTAS_MAX_SIZE) {
- error_report("RTAS too big ! 0x%zx bytes (max is 0x%x)",
- (size_t)spapr->rtas_size, RTAS_MAX_SIZE);
- exit(1);
- }
- g_free(filename);
-
- /* Set up EPOW events infrastructure */
- spapr_events_init(spapr);
-
- /* Set up the RTC RTAS interfaces */
- spapr_rtc_create(spapr);
-
- /* Set up VIO bus */
- spapr->vio_bus = spapr_vio_bus_init();
-
- for (i = 0; i < MAX_SERIAL_PORTS; i++) {
- if (serial_hds[i]) {
- spapr_vty_create(spapr->vio_bus, serial_hds[i]);
- }
- }
-
- /* We always have at least the nvram device on VIO */
- spapr_create_nvram(spapr);
-
- /* Set up PCI */
- spapr_pci_rtas_init();
-
- phb = spapr_create_phb(spapr, 0);
-
- for (i = 0; i < nb_nics; i++) {
- NICInfo *nd = &nd_table[i];
-
- if (!nd->model) {
- nd->model = g_strdup("ibmveth");
- }
-
- if (strcmp(nd->model, "ibmveth") == 0) {
- spapr_vlan_create(spapr->vio_bus, nd);
- } else {
- pci_nic_init_nofail(&nd_table[i], phb->bus, nd->model, NULL);
- }
- }
-
- for (i = 0; i <= drive_get_max_bus(IF_SCSI); i++) {
- spapr_vscsi_create(spapr->vio_bus);
- }
-
- /* Graphics */
- if (spapr_vga_init(phb->bus, &error_fatal)) {
- spapr->has_graphics = true;
- machine->usb |= defaults_enabled() && !machine->usb_disabled;
- }
-
- if (machine->usb) {
- if (smc->use_ohci_by_default) {
- pci_create_simple(phb->bus, -1, "pci-ohci");
- } else {
- pci_create_simple(phb->bus, -1, "nec-usb-xhci");
- }
-
- if (spapr->has_graphics) {
- USBBus *usb_bus = usb_bus_find(-1);
-
- usb_create_simple(usb_bus, "usb-kbd");
- usb_create_simple(usb_bus, "usb-mouse");
- }
- }
-
- if (spapr->rma_size < (MIN_RMA_SLOF << 20)) {
- error_report(
- "pSeries SLOF firmware requires >= %ldM guest RMA (Real Mode Area memory)",
- MIN_RMA_SLOF);
- exit(1);
- }
-
- if (kernel_filename) {
- uint64_t lowaddr = 0;
-
- kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL,
- NULL, &lowaddr, NULL, 1, PPC_ELF_MACHINE,
- 0, 0);
- if (kernel_size == ELF_LOAD_WRONG_ENDIAN) {
- kernel_size = load_elf(kernel_filename,
- translate_kernel_address, NULL,
- NULL, &lowaddr, NULL, 0, PPC_ELF_MACHINE,
- 0, 0);
- kernel_le = kernel_size > 0;
- }
- if (kernel_size < 0) {
- error_report("error loading %s: %s",
- kernel_filename, load_elf_strerror(kernel_size));
- exit(1);
- }
-
- /* load initrd */
- if (initrd_filename) {
- /* Try to locate the initrd in the gap between the kernel
- * and the firmware. Add a bit of space just in case
- */
- initrd_base = (KERNEL_LOAD_ADDR + kernel_size + 0x1ffff) & ~0xffff;
- initrd_size = load_image_targphys(initrd_filename, initrd_base,
- load_limit - initrd_base);
- if (initrd_size < 0) {
- error_report("could not load initial ram disk '%s'",
- initrd_filename);
- exit(1);
- }
- } else {
- initrd_base = 0;
- initrd_size = 0;
- }
- }
-
- if (bios_name == NULL) {
- bios_name = FW_FILE_NAME;
- }
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
- if (!filename) {
- error_report("Could not find LPAR firmware '%s'", bios_name);
- exit(1);
- }
- fw_size = load_image_targphys(filename, 0, FW_MAX_SIZE);
- if (fw_size <= 0) {
- error_report("Could not load LPAR firmware '%s'", filename);
- exit(1);
- }
- g_free(filename);
-
- /* FIXME: Should register things through the MachineState's qdev
- * interface, this is a legacy from the sPAPREnvironment structure
- * which predated MachineState but had a similar function */
- vmstate_register(NULL, 0, &vmstate_spapr, spapr);
- register_savevm_live(NULL, "spapr/htab", -1, 1,
- &savevm_htab_handlers, spapr);
-
- /* Prepare the device tree */
- spapr->fdt_skel = spapr_create_fdt_skel(initrd_base, initrd_size,
- kernel_size, kernel_le,
- kernel_cmdline,
- spapr->check_exception_irq);
- assert(spapr->fdt_skel != NULL);
-
- /* used by RTAS */
- QTAILQ_INIT(&spapr->ccs_list);
- qemu_register_reset(spapr_ccs_reset_hook, spapr);
-
- qemu_register_boot_set(spapr_boot_set, spapr);
-}
-
-static int spapr_kvm_type(const char *vm_type)
-{
- if (!vm_type) {
- return 0;
- }
-
- if (!strcmp(vm_type, "HV")) {
- return 1;
- }
-
- if (!strcmp(vm_type, "PR")) {
- return 2;
- }
-
- error_report("Unknown kvm-type specified '%s'", vm_type);
- exit(1);
-}
-
-/*
- * Implementation of an interface to adjust firmware path
- * for the bootindex property handling.
- */
-static char *spapr_get_fw_dev_path(FWPathProvider *p, BusState *bus,
- DeviceState *dev)
-{
-#define CAST(type, obj, name) \
- ((type *)object_dynamic_cast(OBJECT(obj), (name)))
- SCSIDevice *d = CAST(SCSIDevice, dev, TYPE_SCSI_DEVICE);
- sPAPRPHBState *phb = CAST(sPAPRPHBState, dev, TYPE_SPAPR_PCI_HOST_BRIDGE);
-
- if (d) {
- void *spapr = CAST(void, bus->parent, "spapr-vscsi");
- VirtIOSCSI *virtio = CAST(VirtIOSCSI, bus->parent, TYPE_VIRTIO_SCSI);
- USBDevice *usb = CAST(USBDevice, bus->parent, TYPE_USB_DEVICE);
-
- if (spapr) {
- /*
- * Replace "channel@0/disk@0,0" with "disk@8000000000000000":
- * We use SRP luns of the form 8000 | (bus << 8) | (id << 5) | lun
- * in the top 16 bits of the 64-bit LUN
- */
- unsigned id = 0x8000 | (d->id << 8) | d->lun;
- return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
- (uint64_t)id << 48);
- } else if (virtio) {
- /*
- * We use SRP luns of the form 01000000 | (target << 8) | lun
- * in the top 32 bits of the 64-bit LUN
- * Note: the quote above is from SLOF and it is wrong,
- * the actual binding is:
- * swap 0100 or 10 << or 20 << ( target lun-id -- srplun )
- */
- unsigned id = 0x1000000 | (d->id << 16) | d->lun;
- return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
- (uint64_t)id << 32);
- } else if (usb) {
- /*
- * We use SRP luns of the form 01000000 | (usb-port << 16) | lun
- * in the top 32 bits of the 64-bit LUN
- */
- unsigned usb_port = atoi(usb->port->path);
- unsigned id = 0x1000000 | (usb_port << 16) | d->lun;
- return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
- (uint64_t)id << 32);
- }
- }
-
- if (phb) {
- /* Replace "pci" with "pci@800000020000000" */
- return g_strdup_printf("pci@%"PRIX64, phb->buid);
- }
-
- return NULL;
-}
-
-static char *spapr_get_kvm_type(Object *obj, Error **errp)
-{
- sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
-
- return g_strdup(spapr->kvm_type);
-}
-
-static void spapr_set_kvm_type(Object *obj, const char *value, Error **errp)
-{
- sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
-
- g_free(spapr->kvm_type);
- spapr->kvm_type = g_strdup(value);
-}
-
-static void spapr_machine_initfn(Object *obj)
-{
- sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
-
- spapr->htab_fd = -1;
- object_property_add_str(obj, "kvm-type",
- spapr_get_kvm_type, spapr_set_kvm_type, NULL);
- object_property_set_description(obj, "kvm-type",
- "Specifies the KVM virtualization mode (HV, PR)",
- NULL);
-}
-
-static void spapr_machine_finalizefn(Object *obj)
-{
- sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
-
- g_free(spapr->kvm_type);
-}
-
-static void ppc_cpu_do_nmi_on_cpu(void *arg)
-{
- CPUState *cs = arg;
-
- cpu_synchronize_state(cs);
- ppc_cpu_do_system_reset(cs);
-}
-
-static void spapr_nmi(NMIState *n, int cpu_index, Error **errp)
-{
- CPUState *cs;
-
- CPU_FOREACH(cs) {
- async_run_on_cpu(cs, ppc_cpu_do_nmi_on_cpu, cs);
- }
-}
-
-static void spapr_add_lmbs(DeviceState *dev, uint64_t addr, uint64_t size,
- uint32_t node, Error **errp)
-{
- sPAPRDRConnector *drc;
- sPAPRDRConnectorClass *drck;
- uint32_t nr_lmbs = size/SPAPR_MEMORY_BLOCK_SIZE;
- int i, fdt_offset, fdt_size;
- void *fdt;
-
- /*
- * Check for DRC connectors and send hotplug notification to the
- * guest only in case of hotplugged memory. This allows cold plugged
- * memory to be specified at boot time.
- */
- if (!dev->hotplugged) {
- return;
- }
-
- for (i = 0; i < nr_lmbs; i++) {
- drc = spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_LMB,
- addr/SPAPR_MEMORY_BLOCK_SIZE);
- g_assert(drc);
-
- fdt = create_device_tree(&fdt_size);
- fdt_offset = spapr_populate_memory_node(fdt, node, addr,
- SPAPR_MEMORY_BLOCK_SIZE);
-
- drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
- drck->attach(drc, dev, fdt, fdt_offset, !dev->hotplugged, errp);
- addr += SPAPR_MEMORY_BLOCK_SIZE;
- }
- spapr_hotplug_req_add_by_count(SPAPR_DR_CONNECTOR_TYPE_LMB, nr_lmbs);
-}
-
-static void spapr_memory_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
- uint32_t node, Error **errp)
-{
- Error *local_err = NULL;
- sPAPRMachineState *ms = SPAPR_MACHINE(hotplug_dev);
- PCDIMMDevice *dimm = PC_DIMM(dev);
- PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm);
- MemoryRegion *mr = ddc->get_memory_region(dimm);
- uint64_t align = memory_region_get_alignment(mr);
- uint64_t size = memory_region_size(mr);
- uint64_t addr;
-
- if (size % SPAPR_MEMORY_BLOCK_SIZE) {
- error_setg(&local_err, "Hotplugged memory size must be a multiple of "
- "%lld MB", SPAPR_MEMORY_BLOCK_SIZE/M_BYTE);
- goto out;
- }
-
- pc_dimm_memory_plug(dev, &ms->hotplug_memory, mr, align, &local_err);
- if (local_err) {
- goto out;
- }
-
- addr = object_property_get_int(OBJECT(dimm), PC_DIMM_ADDR_PROP, &local_err);
- if (local_err) {
- pc_dimm_memory_unplug(dev, &ms->hotplug_memory, mr);
- goto out;
- }
-
- spapr_add_lmbs(dev, addr, size, node, &error_abort);
-
-out:
- error_propagate(errp, local_err);
-}
-
-static void spapr_machine_device_plug(HotplugHandler *hotplug_dev,
- DeviceState *dev, Error **errp)
-{
- sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(qdev_get_machine());
-
- if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
- int node;
-
- if (!smc->dr_lmb_enabled) {
- error_setg(errp, "Memory hotplug not supported for this machine");
- return;
- }
- node = object_property_get_int(OBJECT(dev), PC_DIMM_NODE_PROP, errp);
- if (*errp) {
- return;
- }
- if (node < 0 || node >= MAX_NODES) {
- error_setg(errp, "Invaild node %d", node);
- return;
- }
-
- /*
- * Currently PowerPC kernel doesn't allow hot-adding memory to
- * memory-less node, but instead will silently add the memory
- * to the first node that has some memory. This causes two
- * unexpected behaviours for the user.
- *
- * - Memory gets hotplugged to a different node than what the user
- * specified.
- * - Since pc-dimm subsystem in QEMU still thinks that memory belongs
- * to memory-less node, a reboot will set things accordingly
- * and the previously hotplugged memory now ends in the right node.
- * This appears as if some memory moved from one node to another.
- *
- * So until kernel starts supporting memory hotplug to memory-less
- * nodes, just prevent such attempts upfront in QEMU.
- */
- if (nb_numa_nodes && !numa_info[node].node_mem) {
- error_setg(errp, "Can't hotplug memory to memory-less node %d",
- node);
- return;
- }
-
- spapr_memory_plug(hotplug_dev, dev, node, errp);
- }
-}
-
-static void spapr_machine_device_unplug(HotplugHandler *hotplug_dev,
- DeviceState *dev, Error **errp)
-{
- if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
- error_setg(errp, "Memory hot unplug not supported by sPAPR");
- }
-}
-
-static HotplugHandler *spapr_get_hotpug_handler(MachineState *machine,
- DeviceState *dev)
-{
- if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
- return HOTPLUG_HANDLER(machine);
- }
- return NULL;
-}
-
-static unsigned spapr_cpu_index_to_socket_id(unsigned cpu_index)
-{
- /* Allocate to NUMA nodes on a "socket" basis (not that concept of
- * socket means much for the paravirtualized PAPR platform) */
- return cpu_index / smp_threads / smp_cores;
-}
-
-static void spapr_machine_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
- sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(oc);
- FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(oc);
- NMIClass *nc = NMI_CLASS(oc);
- HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
-
- mc->desc = "pSeries Logical Partition (PAPR compliant)";
-
- /*
- * We set up the default / latest behaviour here. The class_init
- * functions for the specific versioned machine types can override
- * these details for backwards compatibility
- */
- mc->init = ppc_spapr_init;
- mc->reset = ppc_spapr_reset;
- mc->block_default_type = IF_SCSI;
- mc->max_cpus = MAX_CPUMASK_BITS;
- mc->no_parallel = 1;
- mc->default_boot_order = "";
- mc->default_ram_size = 512 * M_BYTE;
- mc->kvm_type = spapr_kvm_type;
- mc->has_dynamic_sysbus = true;
- mc->pci_allow_0_address = true;
- mc->get_hotplug_handler = spapr_get_hotpug_handler;
- hc->plug = spapr_machine_device_plug;
- hc->unplug = spapr_machine_device_unplug;
- mc->cpu_index_to_socket_id = spapr_cpu_index_to_socket_id;
-
- smc->dr_lmb_enabled = true;
- fwc->get_dev_path = spapr_get_fw_dev_path;
- nc->nmi_monitor_handler = spapr_nmi;
-}
-
-static const TypeInfo spapr_machine_info = {
- .name = TYPE_SPAPR_MACHINE,
- .parent = TYPE_MACHINE,
- .abstract = true,
- .instance_size = sizeof(sPAPRMachineState),
- .instance_init = spapr_machine_initfn,
- .instance_finalize = spapr_machine_finalizefn,
- .class_size = sizeof(sPAPRMachineClass),
- .class_init = spapr_machine_class_init,
- .interfaces = (InterfaceInfo[]) {
- { TYPE_FW_PATH_PROVIDER },
- { TYPE_NMI },
- { TYPE_HOTPLUG_HANDLER },
- { }
- },
-};
-
-#define DEFINE_SPAPR_MACHINE(suffix, verstr, latest) \
- static void spapr_machine_##suffix##_class_init(ObjectClass *oc, \
- void *data) \
- { \
- MachineClass *mc = MACHINE_CLASS(oc); \
- spapr_machine_##suffix##_class_options(mc); \
- if (latest) { \
- mc->alias = "pseries"; \
- mc->is_default = 1; \
- } \
- } \
- static void spapr_machine_##suffix##_instance_init(Object *obj) \
- { \
- MachineState *machine = MACHINE(obj); \
- spapr_machine_##suffix##_instance_options(machine); \
- } \
- static const TypeInfo spapr_machine_##suffix##_info = { \
- .name = MACHINE_TYPE_NAME("pseries-" verstr), \
- .parent = TYPE_SPAPR_MACHINE, \
- .class_init = spapr_machine_##suffix##_class_init, \
- .instance_init = spapr_machine_##suffix##_instance_init, \
- }; \
- static void spapr_machine_register_##suffix(void) \
- { \
- type_register(&spapr_machine_##suffix##_info); \
- } \
- type_init(spapr_machine_register_##suffix)
-
-/*
- * pseries-2.6
- */
-static void spapr_machine_2_6_instance_options(MachineState *machine)
-{
-}
-
-static void spapr_machine_2_6_class_options(MachineClass *mc)
-{
- /* Defaults for the latest behaviour inherited from the base class */
-}
-
-DEFINE_SPAPR_MACHINE(2_6, "2.6", true);
-
-/*
- * pseries-2.5
- */
-#define SPAPR_COMPAT_2_5 \
- HW_COMPAT_2_5 \
- { \
- .driver = "spapr-vlan", \
- .property = "use-rx-buffer-pools", \
- .value = "off", \
- },
-
-static void spapr_machine_2_5_instance_options(MachineState *machine)
-{
-}
-
-static void spapr_machine_2_5_class_options(MachineClass *mc)
-{
- sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
-
- spapr_machine_2_6_class_options(mc);
- smc->use_ohci_by_default = true;
- SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_5);
-}
-
-DEFINE_SPAPR_MACHINE(2_5, "2.5", false);
-
-/*
- * pseries-2.4
- */
-#define SPAPR_COMPAT_2_4 \
- SPAPR_COMPAT_2_5 \
- HW_COMPAT_2_4
-
-static void spapr_machine_2_4_instance_options(MachineState *machine)
-{
- spapr_machine_2_5_instance_options(machine);
-}
-
-static void spapr_machine_2_4_class_options(MachineClass *mc)
-{
- sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
-
- spapr_machine_2_5_class_options(mc);
- smc->dr_lmb_enabled = false;
- SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_4);
-}
-
-DEFINE_SPAPR_MACHINE(2_4, "2.4", false);
-
-/*
- * pseries-2.3
- */
-#define SPAPR_COMPAT_2_3 \
- SPAPR_COMPAT_2_4 \
- HW_COMPAT_2_3 \
- {\
- .driver = "spapr-pci-host-bridge",\
- .property = "dynamic-reconfiguration",\
- .value = "off",\
- },
-
-static void spapr_machine_2_3_instance_options(MachineState *machine)
-{
- spapr_machine_2_4_instance_options(machine);
- savevm_skip_section_footers();
- global_state_set_optional();
- savevm_skip_configuration();
-}
-
-static void spapr_machine_2_3_class_options(MachineClass *mc)
-{
- spapr_machine_2_4_class_options(mc);
- SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_3);
-}
-DEFINE_SPAPR_MACHINE(2_3, "2.3", false);
-
-/*
- * pseries-2.2
- */
-
-#define SPAPR_COMPAT_2_2 \
- SPAPR_COMPAT_2_3 \
- HW_COMPAT_2_2 \
- {\
- .driver = TYPE_SPAPR_PCI_HOST_BRIDGE,\
- .property = "mem_win_size",\
- .value = "0x20000000",\
- },
-
-static void spapr_machine_2_2_instance_options(MachineState *machine)
-{
- spapr_machine_2_3_instance_options(machine);
- machine->suppress_vmdesc = true;
-}
-
-static void spapr_machine_2_2_class_options(MachineClass *mc)
-{
- spapr_machine_2_3_class_options(mc);
- SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_2);
-}
-DEFINE_SPAPR_MACHINE(2_2, "2.2", false);
-
-/*
- * pseries-2.1
- */
-#define SPAPR_COMPAT_2_1 \
- SPAPR_COMPAT_2_2 \
- HW_COMPAT_2_1
-
-static void spapr_machine_2_1_instance_options(MachineState *machine)
-{
- spapr_machine_2_2_instance_options(machine);
-}
-
-static void spapr_machine_2_1_class_options(MachineClass *mc)
-{
- spapr_machine_2_2_class_options(mc);
- SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_1);
-}
-DEFINE_SPAPR_MACHINE(2_1, "2.1", false);
-
-static void spapr_machine_register_types(void)
-{
- type_register_static(&spapr_machine_info);
-}
-
-type_init(spapr_machine_register_types)
diff --git a/qemu/hw/ppc/spapr_drc.c b/qemu/hw/ppc/spapr_drc.c
deleted file mode 100644
index 1f5f1d790..000000000
--- a/qemu/hw/ppc/spapr_drc.c
+++ /dev/null
@@ -1,843 +0,0 @@
-/*
- * QEMU SPAPR Dynamic Reconfiguration Connector Implementation
- *
- * Copyright IBM Corp. 2014
- *
- * Authors:
- * Michael Roth <mdroth@linux.vnet.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "cpu.h"
-#include "qemu/cutils.h"
-#include "hw/ppc/spapr_drc.h"
-#include "qom/object.h"
-#include "hw/qdev.h"
-#include "qapi/visitor.h"
-#include "qemu/error-report.h"
-#include "hw/ppc/spapr.h" /* for RTAS return codes */
-
-/* #define DEBUG_SPAPR_DRC */
-
-#ifdef DEBUG_SPAPR_DRC
-#define DPRINTF(fmt, ...) \
- do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
-#define DPRINTFN(fmt, ...) \
- do { DPRINTF(fmt, ## __VA_ARGS__); fprintf(stderr, "\n"); } while (0)
-#else
-#define DPRINTF(fmt, ...) \
- do { } while (0)
-#define DPRINTFN(fmt, ...) \
- do { } while (0)
-#endif
-
-#define DRC_CONTAINER_PATH "/dr-connector"
-#define DRC_INDEX_TYPE_SHIFT 28
-#define DRC_INDEX_ID_MASK ((1ULL << DRC_INDEX_TYPE_SHIFT) - 1)
-
-static sPAPRDRConnectorTypeShift get_type_shift(sPAPRDRConnectorType type)
-{
- uint32_t shift = 0;
-
- /* make sure this isn't SPAPR_DR_CONNECTOR_TYPE_ANY, or some
- * other wonky value.
- */
- g_assert(is_power_of_2(type));
-
- while (type != (1 << shift)) {
- shift++;
- }
- return shift;
-}
-
-static uint32_t get_index(sPAPRDRConnector *drc)
-{
- /* no set format for a drc index: it only needs to be globally
- * unique. this is how we encode the DRC type on bare-metal
- * however, so might as well do that here
- */
- return (get_type_shift(drc->type) << DRC_INDEX_TYPE_SHIFT) |
- (drc->id & DRC_INDEX_ID_MASK);
-}
-
-static uint32_t set_isolation_state(sPAPRDRConnector *drc,
- sPAPRDRIsolationState state)
-{
- sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
-
- DPRINTFN("drc: %x, set_isolation_state: %x", get_index(drc), state);
-
- if (state == SPAPR_DR_ISOLATION_STATE_UNISOLATED) {
- /* cannot unisolate a non-existant resource, and, or resources
- * which are in an 'UNUSABLE' allocation state. (PAPR 2.7, 13.5.3.5)
- */
- if (!drc->dev ||
- drc->allocation_state == SPAPR_DR_ALLOCATION_STATE_UNUSABLE) {
- return RTAS_OUT_NO_SUCH_INDICATOR;
- }
- }
-
- drc->isolation_state = state;
-
- if (drc->isolation_state == SPAPR_DR_ISOLATION_STATE_ISOLATED) {
- /* if we're awaiting release, but still in an unconfigured state,
- * it's likely the guest is still in the process of configuring
- * the device and is transitioning the devices to an ISOLATED
- * state as a part of that process. so we only complete the
- * removal when this transition happens for a device in a
- * configured state, as suggested by the state diagram from
- * PAPR+ 2.7, 13.4
- */
- if (drc->awaiting_release) {
- if (drc->configured) {
- DPRINTFN("finalizing device removal");
- drck->detach(drc, DEVICE(drc->dev), drc->detach_cb,
- drc->detach_cb_opaque, NULL);
- } else {
- DPRINTFN("deferring device removal on unconfigured device\n");
- }
- }
- drc->configured = false;
- }
-
- return RTAS_OUT_SUCCESS;
-}
-
-static uint32_t set_indicator_state(sPAPRDRConnector *drc,
- sPAPRDRIndicatorState state)
-{
- DPRINTFN("drc: %x, set_indicator_state: %x", get_index(drc), state);
- drc->indicator_state = state;
- return RTAS_OUT_SUCCESS;
-}
-
-static uint32_t set_allocation_state(sPAPRDRConnector *drc,
- sPAPRDRAllocationState state)
-{
- sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
-
- DPRINTFN("drc: %x, set_allocation_state: %x", get_index(drc), state);
-
- if (state == SPAPR_DR_ALLOCATION_STATE_USABLE) {
- /* if there's no resource/device associated with the DRC, there's
- * no way for us to put it in an allocation state consistent with
- * being 'USABLE'. PAPR 2.7, 13.5.3.4 documents that this should
- * result in an RTAS return code of -3 / "no such indicator"
- */
- if (!drc->dev) {
- return RTAS_OUT_NO_SUCH_INDICATOR;
- }
- }
-
- if (drc->type != SPAPR_DR_CONNECTOR_TYPE_PCI) {
- drc->allocation_state = state;
- if (drc->awaiting_release &&
- drc->allocation_state == SPAPR_DR_ALLOCATION_STATE_UNUSABLE) {
- DPRINTFN("finalizing device removal");
- drck->detach(drc, DEVICE(drc->dev), drc->detach_cb,
- drc->detach_cb_opaque, NULL);
- }
- }
- return RTAS_OUT_SUCCESS;
-}
-
-static uint32_t get_type(sPAPRDRConnector *drc)
-{
- return drc->type;
-}
-
-static const char *get_name(sPAPRDRConnector *drc)
-{
- return drc->name;
-}
-
-static const void *get_fdt(sPAPRDRConnector *drc, int *fdt_start_offset)
-{
- if (fdt_start_offset) {
- *fdt_start_offset = drc->fdt_start_offset;
- }
- return drc->fdt;
-}
-
-static void set_configured(sPAPRDRConnector *drc)
-{
- DPRINTFN("drc: %x, set_configured", get_index(drc));
-
- if (drc->isolation_state != SPAPR_DR_ISOLATION_STATE_UNISOLATED) {
- /* guest should be not configuring an isolated device */
- DPRINTFN("drc: %x, set_configured: skipping isolated device",
- get_index(drc));
- return;
- }
- drc->configured = true;
-}
-
-/* has the guest been notified of device attachment? */
-static void set_signalled(sPAPRDRConnector *drc)
-{
- drc->signalled = true;
-}
-
-/*
- * dr-entity-sense sensor value
- * returned via get-sensor-state RTAS calls
- * as expected by state diagram in PAPR+ 2.7, 13.4
- * based on the current allocation/indicator/power states
- * for the DR connector.
- */
-static uint32_t entity_sense(sPAPRDRConnector *drc, sPAPRDREntitySense *state)
-{
- if (drc->dev) {
- if (drc->type != SPAPR_DR_CONNECTOR_TYPE_PCI &&
- drc->allocation_state == SPAPR_DR_ALLOCATION_STATE_UNUSABLE) {
- /* for logical DR, we return a state of UNUSABLE
- * iff the allocation state UNUSABLE.
- * Otherwise, report the state as USABLE/PRESENT,
- * as we would for PCI.
- */
- *state = SPAPR_DR_ENTITY_SENSE_UNUSABLE;
- } else {
- /* this assumes all PCI devices are assigned to
- * a 'live insertion' power domain, where QEMU
- * manages power state automatically as opposed
- * to the guest. present, non-PCI resources are
- * unaffected by power state.
- */
- *state = SPAPR_DR_ENTITY_SENSE_PRESENT;
- }
- } else {
- if (drc->type == SPAPR_DR_CONNECTOR_TYPE_PCI) {
- /* PCI devices, and only PCI devices, use EMPTY
- * in cases where we'd otherwise use UNUSABLE
- */
- *state = SPAPR_DR_ENTITY_SENSE_EMPTY;
- } else {
- *state = SPAPR_DR_ENTITY_SENSE_UNUSABLE;
- }
- }
-
- DPRINTFN("drc: %x, entity_sense: %x", get_index(drc), state);
- return RTAS_OUT_SUCCESS;
-}
-
-static void prop_get_index(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(obj);
- sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
- uint32_t value = (uint32_t)drck->get_index(drc);
- visit_type_uint32(v, name, &value, errp);
-}
-
-static void prop_get_type(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(obj);
- sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
- uint32_t value = (uint32_t)drck->get_type(drc);
- visit_type_uint32(v, name, &value, errp);
-}
-
-static char *prop_get_name(Object *obj, Error **errp)
-{
- sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(obj);
- sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
- return g_strdup(drck->get_name(drc));
-}
-
-static void prop_get_entity_sense(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(obj);
- sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
- uint32_t value;
-
- drck->entity_sense(drc, &value);
- visit_type_uint32(v, name, &value, errp);
-}
-
-static void prop_get_fdt(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(obj);
- Error *err = NULL;
- int fdt_offset_next, fdt_offset, fdt_depth;
- void *fdt;
-
- if (!drc->fdt) {
- visit_start_struct(v, name, NULL, 0, &err);
- if (!err) {
- visit_end_struct(v, &err);
- }
- error_propagate(errp, err);
- return;
- }
-
- fdt = drc->fdt;
- fdt_offset = drc->fdt_start_offset;
- fdt_depth = 0;
-
- do {
- const char *name = NULL;
- const struct fdt_property *prop = NULL;
- int prop_len = 0, name_len = 0;
- uint32_t tag;
-
- tag = fdt_next_tag(fdt, fdt_offset, &fdt_offset_next);
- switch (tag) {
- case FDT_BEGIN_NODE:
- fdt_depth++;
- name = fdt_get_name(fdt, fdt_offset, &name_len);
- visit_start_struct(v, name, NULL, 0, &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- break;
- case FDT_END_NODE:
- /* shouldn't ever see an FDT_END_NODE before FDT_BEGIN_NODE */
- g_assert(fdt_depth > 0);
- visit_end_struct(v, &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- fdt_depth--;
- break;
- case FDT_PROP: {
- int i;
- prop = fdt_get_property_by_offset(fdt, fdt_offset, &prop_len);
- name = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
- visit_start_list(v, name, &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- for (i = 0; i < prop_len; i++) {
- visit_type_uint8(v, NULL, (uint8_t *)&prop->data[i], &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- }
- visit_end_list(v);
- break;
- }
- default:
- error_setg(&error_abort, "device FDT in unexpected state: %d", tag);
- }
- fdt_offset = fdt_offset_next;
- } while (fdt_depth != 0);
-}
-
-static void attach(sPAPRDRConnector *drc, DeviceState *d, void *fdt,
- int fdt_start_offset, bool coldplug, Error **errp)
-{
- DPRINTFN("drc: %x, attach", get_index(drc));
-
- if (drc->isolation_state != SPAPR_DR_ISOLATION_STATE_ISOLATED) {
- error_setg(errp, "an attached device is still awaiting release");
- return;
- }
- if (drc->type == SPAPR_DR_CONNECTOR_TYPE_PCI) {
- g_assert(drc->allocation_state == SPAPR_DR_ALLOCATION_STATE_USABLE);
- }
- g_assert(fdt || coldplug);
-
- /* NOTE: setting initial isolation state to UNISOLATED means we can't
- * detach unless guest has a userspace/kernel that moves this state
- * back to ISOLATED in response to an unplug event, or this is done
- * manually by the admin prior. if we force things while the guest
- * may be accessing the device, we can easily crash the guest, so we
- * we defer completion of removal in such cases to the reset() hook.
- */
- if (drc->type == SPAPR_DR_CONNECTOR_TYPE_PCI) {
- drc->isolation_state = SPAPR_DR_ISOLATION_STATE_UNISOLATED;
- }
- drc->indicator_state = SPAPR_DR_INDICATOR_STATE_ACTIVE;
-
- drc->dev = d;
- drc->fdt = fdt;
- drc->fdt_start_offset = fdt_start_offset;
- drc->configured = coldplug;
- /* 'logical' DR resources such as memory/cpus are in some cases treated
- * as a pool of resources from which the guest is free to choose from
- * based on only a count. for resources that can be assigned in this
- * fashion, we must assume the resource is signalled immediately
- * since a single hotplug request might make an arbitrary number of
- * such attached resources available to the guest, as opposed to
- * 'physical' DR resources such as PCI where each device/resource is
- * signalled individually.
- */
- drc->signalled = (drc->type != SPAPR_DR_CONNECTOR_TYPE_PCI)
- ? true : coldplug;
-
- object_property_add_link(OBJECT(drc), "device",
- object_get_typename(OBJECT(drc->dev)),
- (Object **)(&drc->dev),
- NULL, 0, NULL);
-}
-
-static void detach(sPAPRDRConnector *drc, DeviceState *d,
- spapr_drc_detach_cb *detach_cb,
- void *detach_cb_opaque, Error **errp)
-{
- DPRINTFN("drc: %x, detach", get_index(drc));
-
- drc->detach_cb = detach_cb;
- drc->detach_cb_opaque = detach_cb_opaque;
-
- /* if we've signalled device presence to the guest, or if the guest
- * has gone ahead and configured the device (via manually-executed
- * device add via drmgr in guest, namely), we need to wait
- * for the guest to quiesce the device before completing detach.
- * Otherwise, we can assume the guest hasn't seen it and complete the
- * detach immediately. Note that there is a small race window
- * just before, or during, configuration, which is this context
- * refers mainly to fetching the device tree via RTAS.
- * During this window the device access will be arbitrated by
- * associated DRC, which will simply fail the RTAS calls as invalid.
- * This is recoverable within guest and current implementations of
- * drmgr should be able to cope.
- */
- if (!drc->signalled && !drc->configured) {
- /* if the guest hasn't seen the device we can't rely on it to
- * set it back to an isolated state via RTAS, so do it here manually
- */
- drc->isolation_state = SPAPR_DR_ISOLATION_STATE_ISOLATED;
- }
-
- if (drc->isolation_state != SPAPR_DR_ISOLATION_STATE_ISOLATED) {
- DPRINTFN("awaiting transition to isolated state before removal");
- drc->awaiting_release = true;
- return;
- }
-
- if (drc->type != SPAPR_DR_CONNECTOR_TYPE_PCI &&
- drc->allocation_state != SPAPR_DR_ALLOCATION_STATE_UNUSABLE) {
- DPRINTFN("awaiting transition to unusable state before removal");
- drc->awaiting_release = true;
- return;
- }
-
- drc->indicator_state = SPAPR_DR_INDICATOR_STATE_INACTIVE;
-
- if (drc->detach_cb) {
- drc->detach_cb(drc->dev, drc->detach_cb_opaque);
- }
-
- drc->awaiting_release = false;
- g_free(drc->fdt);
- drc->fdt = NULL;
- drc->fdt_start_offset = 0;
- object_property_del(OBJECT(drc), "device", NULL);
- drc->dev = NULL;
- drc->detach_cb = NULL;
- drc->detach_cb_opaque = NULL;
-}
-
-static bool release_pending(sPAPRDRConnector *drc)
-{
- return drc->awaiting_release;
-}
-
-static void reset(DeviceState *d)
-{
- sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(d);
- sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
- sPAPRDREntitySense state;
-
- DPRINTFN("drc reset: %x", drck->get_index(drc));
- /* immediately upon reset we can safely assume DRCs whose devices
- * are pending removal can be safely removed, and that they will
- * subsequently be left in an ISOLATED state. move the DRC to this
- * state in these cases (which will in turn complete any pending
- * device removals)
- */
- if (drc->awaiting_release) {
- drck->set_isolation_state(drc, SPAPR_DR_ISOLATION_STATE_ISOLATED);
- /* generally this should also finalize the removal, but if the device
- * hasn't yet been configured we normally defer removal under the
- * assumption that this transition is taking place as part of device
- * configuration. so check if we're still waiting after this, and
- * force removal if we are
- */
- if (drc->awaiting_release) {
- drck->detach(drc, DEVICE(drc->dev), drc->detach_cb,
- drc->detach_cb_opaque, NULL);
- }
-
- /* non-PCI devices may be awaiting a transition to UNUSABLE */
- if (drc->type != SPAPR_DR_CONNECTOR_TYPE_PCI &&
- drc->awaiting_release) {
- drck->set_allocation_state(drc, SPAPR_DR_ALLOCATION_STATE_UNUSABLE);
- }
- }
-
- drck->entity_sense(drc, &state);
- if (state == SPAPR_DR_ENTITY_SENSE_PRESENT) {
- drck->set_signalled(drc);
- }
-}
-
-static void realize(DeviceState *d, Error **errp)
-{
- sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(d);
- sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
- Object *root_container;
- char link_name[256];
- gchar *child_name;
- Error *err = NULL;
-
- DPRINTFN("drc realize: %x", drck->get_index(drc));
- /* NOTE: we do this as part of realize/unrealize due to the fact
- * that the guest will communicate with the DRC via RTAS calls
- * referencing the global DRC index. By unlinking the DRC
- * from DRC_CONTAINER_PATH/<drc_index> we effectively make it
- * inaccessible by the guest, since lookups rely on this path
- * existing in the composition tree
- */
- root_container = container_get(object_get_root(), DRC_CONTAINER_PATH);
- snprintf(link_name, sizeof(link_name), "%x", drck->get_index(drc));
- child_name = object_get_canonical_path_component(OBJECT(drc));
- DPRINTFN("drc child name: %s", child_name);
- object_property_add_alias(root_container, link_name,
- drc->owner, child_name, &err);
- if (err) {
- error_report_err(err);
- object_unref(OBJECT(drc));
- }
- g_free(child_name);
- DPRINTFN("drc realize complete");
-}
-
-static void unrealize(DeviceState *d, Error **errp)
-{
- sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(d);
- sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
- Object *root_container;
- char name[256];
- Error *err = NULL;
-
- DPRINTFN("drc unrealize: %x", drck->get_index(drc));
- root_container = container_get(object_get_root(), DRC_CONTAINER_PATH);
- snprintf(name, sizeof(name), "%x", drck->get_index(drc));
- object_property_del(root_container, name, &err);
- if (err) {
- error_report_err(err);
- object_unref(OBJECT(drc));
- }
-}
-
-sPAPRDRConnector *spapr_dr_connector_new(Object *owner,
- sPAPRDRConnectorType type,
- uint32_t id)
-{
- sPAPRDRConnector *drc =
- SPAPR_DR_CONNECTOR(object_new(TYPE_SPAPR_DR_CONNECTOR));
- char *prop_name;
-
- g_assert(type);
-
- drc->type = type;
- drc->id = id;
- drc->owner = owner;
- prop_name = g_strdup_printf("dr-connector[%"PRIu32"]", get_index(drc));
- object_property_add_child(owner, prop_name, OBJECT(drc), NULL);
- object_property_set_bool(OBJECT(drc), true, "realized", NULL);
- g_free(prop_name);
-
- /* human-readable name for a DRC to encode into the DT
- * description. this is mainly only used within a guest in place
- * of the unique DRC index.
- *
- * in the case of VIO/PCI devices, it corresponds to a
- * "location code" that maps a logical device/function (DRC index)
- * to a physical (or virtual in the case of VIO) location in the
- * system by chaining together the "location label" for each
- * encapsulating component.
- *
- * since this is more to do with diagnosing physical hardware
- * issues than guest compatibility, we choose location codes/DRC
- * names that adhere to the documented format, but avoid encoding
- * the entire topology information into the label/code, instead
- * just using the location codes based on the labels for the
- * endpoints (VIO/PCI adaptor connectors), which is basically
- * just "C" followed by an integer ID.
- *
- * DRC names as documented by PAPR+ v2.7, 13.5.2.4
- * location codes as documented by PAPR+ v2.7, 12.3.1.5
- */
- switch (drc->type) {
- case SPAPR_DR_CONNECTOR_TYPE_CPU:
- drc->name = g_strdup_printf("CPU %d", id);
- break;
- case SPAPR_DR_CONNECTOR_TYPE_PHB:
- drc->name = g_strdup_printf("PHB %d", id);
- break;
- case SPAPR_DR_CONNECTOR_TYPE_VIO:
- case SPAPR_DR_CONNECTOR_TYPE_PCI:
- drc->name = g_strdup_printf("C%d", id);
- break;
- case SPAPR_DR_CONNECTOR_TYPE_LMB:
- drc->name = g_strdup_printf("LMB %d", id);
- break;
- default:
- g_assert(false);
- }
-
- /* PCI slot always start in a USABLE state, and stay there */
- if (drc->type == SPAPR_DR_CONNECTOR_TYPE_PCI) {
- drc->allocation_state = SPAPR_DR_ALLOCATION_STATE_USABLE;
- }
-
- return drc;
-}
-
-static void spapr_dr_connector_instance_init(Object *obj)
-{
- sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(obj);
-
- object_property_add_uint32_ptr(obj, "isolation-state",
- &drc->isolation_state, NULL);
- object_property_add_uint32_ptr(obj, "indicator-state",
- &drc->indicator_state, NULL);
- object_property_add_uint32_ptr(obj, "allocation-state",
- &drc->allocation_state, NULL);
- object_property_add_uint32_ptr(obj, "id", &drc->id, NULL);
- object_property_add(obj, "index", "uint32", prop_get_index,
- NULL, NULL, NULL, NULL);
- object_property_add(obj, "connector_type", "uint32", prop_get_type,
- NULL, NULL, NULL, NULL);
- object_property_add_str(obj, "name", prop_get_name, NULL, NULL);
- object_property_add(obj, "entity-sense", "uint32", prop_get_entity_sense,
- NULL, NULL, NULL, NULL);
- object_property_add(obj, "fdt", "struct", prop_get_fdt,
- NULL, NULL, NULL, NULL);
-}
-
-static void spapr_dr_connector_class_init(ObjectClass *k, void *data)
-{
- DeviceClass *dk = DEVICE_CLASS(k);
- sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
-
- dk->reset = reset;
- dk->realize = realize;
- dk->unrealize = unrealize;
- drck->set_isolation_state = set_isolation_state;
- drck->set_indicator_state = set_indicator_state;
- drck->set_allocation_state = set_allocation_state;
- drck->get_index = get_index;
- drck->get_type = get_type;
- drck->get_name = get_name;
- drck->get_fdt = get_fdt;
- drck->set_configured = set_configured;
- drck->entity_sense = entity_sense;
- drck->attach = attach;
- drck->detach = detach;
- drck->release_pending = release_pending;
- drck->set_signalled = set_signalled;
- /*
- * Reason: it crashes FIXME find and document the real reason
- */
- dk->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo spapr_dr_connector_info = {
- .name = TYPE_SPAPR_DR_CONNECTOR,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(sPAPRDRConnector),
- .instance_init = spapr_dr_connector_instance_init,
- .class_size = sizeof(sPAPRDRConnectorClass),
- .class_init = spapr_dr_connector_class_init,
-};
-
-static void spapr_drc_register_types(void)
-{
- type_register_static(&spapr_dr_connector_info);
-}
-
-type_init(spapr_drc_register_types)
-
-/* helper functions for external users */
-
-sPAPRDRConnector *spapr_dr_connector_by_index(uint32_t index)
-{
- Object *obj;
- char name[256];
-
- snprintf(name, sizeof(name), "%s/%x", DRC_CONTAINER_PATH, index);
- obj = object_resolve_path(name, NULL);
-
- return !obj ? NULL : SPAPR_DR_CONNECTOR(obj);
-}
-
-sPAPRDRConnector *spapr_dr_connector_by_id(sPAPRDRConnectorType type,
- uint32_t id)
-{
- return spapr_dr_connector_by_index(
- (get_type_shift(type) << DRC_INDEX_TYPE_SHIFT) |
- (id & DRC_INDEX_ID_MASK));
-}
-
-/* generate a string the describes the DRC to encode into the
- * device tree.
- *
- * as documented by PAPR+ v2.7, 13.5.2.6 and C.6.1
- */
-static const char *spapr_drc_get_type_str(sPAPRDRConnectorType type)
-{
- switch (type) {
- case SPAPR_DR_CONNECTOR_TYPE_CPU:
- return "CPU";
- case SPAPR_DR_CONNECTOR_TYPE_PHB:
- return "PHB";
- case SPAPR_DR_CONNECTOR_TYPE_VIO:
- return "SLOT";
- case SPAPR_DR_CONNECTOR_TYPE_PCI:
- return "28";
- case SPAPR_DR_CONNECTOR_TYPE_LMB:
- return "MEM";
- default:
- g_assert(false);
- }
-
- return NULL;
-}
-
-/**
- * spapr_drc_populate_dt
- *
- * @fdt: libfdt device tree
- * @path: path in the DT to generate properties
- * @owner: parent Object/DeviceState for which to generate DRC
- * descriptions for
- * @drc_type_mask: mask of sPAPRDRConnectorType values corresponding
- * to the types of DRCs to generate entries for
- *
- * generate OF properties to describe DRC topology/indices to guests
- *
- * as documented in PAPR+ v2.1, 13.5.2
- */
-int spapr_drc_populate_dt(void *fdt, int fdt_offset, Object *owner,
- uint32_t drc_type_mask)
-{
- Object *root_container;
- ObjectProperty *prop;
- ObjectPropertyIterator iter;
- uint32_t drc_count = 0;
- GArray *drc_indexes, *drc_power_domains;
- GString *drc_names, *drc_types;
- int ret;
-
- /* the first entry of each properties is a 32-bit integer encoding
- * the number of elements in the array. we won't know this until
- * we complete the iteration through all the matching DRCs, but
- * reserve the space now and set the offsets accordingly so we
- * can fill them in later.
- */
- drc_indexes = g_array_new(false, true, sizeof(uint32_t));
- drc_indexes = g_array_set_size(drc_indexes, 1);
- drc_power_domains = g_array_new(false, true, sizeof(uint32_t));
- drc_power_domains = g_array_set_size(drc_power_domains, 1);
- drc_names = g_string_set_size(g_string_new(NULL), sizeof(uint32_t));
- drc_types = g_string_set_size(g_string_new(NULL), sizeof(uint32_t));
-
- /* aliases for all DRConnector objects will be rooted in QOM
- * composition tree at DRC_CONTAINER_PATH
- */
- root_container = container_get(object_get_root(), DRC_CONTAINER_PATH);
-
- object_property_iter_init(&iter, root_container);
- while ((prop = object_property_iter_next(&iter))) {
- Object *obj;
- sPAPRDRConnector *drc;
- sPAPRDRConnectorClass *drck;
- uint32_t drc_index, drc_power_domain;
-
- if (!strstart(prop->type, "link<", NULL)) {
- continue;
- }
-
- obj = object_property_get_link(root_container, prop->name, NULL);
- drc = SPAPR_DR_CONNECTOR(obj);
- drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
-
- if (owner && (drc->owner != owner)) {
- continue;
- }
-
- if ((drc->type & drc_type_mask) == 0) {
- continue;
- }
-
- drc_count++;
-
- /* ibm,drc-indexes */
- drc_index = cpu_to_be32(drck->get_index(drc));
- g_array_append_val(drc_indexes, drc_index);
-
- /* ibm,drc-power-domains */
- drc_power_domain = cpu_to_be32(-1);
- g_array_append_val(drc_power_domains, drc_power_domain);
-
- /* ibm,drc-names */
- drc_names = g_string_append(drc_names, drck->get_name(drc));
- drc_names = g_string_insert_len(drc_names, -1, "\0", 1);
-
- /* ibm,drc-types */
- drc_types = g_string_append(drc_types,
- spapr_drc_get_type_str(drc->type));
- drc_types = g_string_insert_len(drc_types, -1, "\0", 1);
- }
-
- /* now write the drc count into the space we reserved at the
- * beginning of the arrays previously
- */
- *(uint32_t *)drc_indexes->data = cpu_to_be32(drc_count);
- *(uint32_t *)drc_power_domains->data = cpu_to_be32(drc_count);
- *(uint32_t *)drc_names->str = cpu_to_be32(drc_count);
- *(uint32_t *)drc_types->str = cpu_to_be32(drc_count);
-
- ret = fdt_setprop(fdt, fdt_offset, "ibm,drc-indexes",
- drc_indexes->data,
- drc_indexes->len * sizeof(uint32_t));
- if (ret) {
- fprintf(stderr, "Couldn't create ibm,drc-indexes property\n");
- goto out;
- }
-
- ret = fdt_setprop(fdt, fdt_offset, "ibm,drc-power-domains",
- drc_power_domains->data,
- drc_power_domains->len * sizeof(uint32_t));
- if (ret) {
- fprintf(stderr, "Couldn't finalize ibm,drc-power-domains property\n");
- goto out;
- }
-
- ret = fdt_setprop(fdt, fdt_offset, "ibm,drc-names",
- drc_names->str, drc_names->len);
- if (ret) {
- fprintf(stderr, "Couldn't finalize ibm,drc-names property\n");
- goto out;
- }
-
- ret = fdt_setprop(fdt, fdt_offset, "ibm,drc-types",
- drc_types->str, drc_types->len);
- if (ret) {
- fprintf(stderr, "Couldn't finalize ibm,drc-types property\n");
- goto out;
- }
-
-out:
- g_array_free(drc_indexes, true);
- g_array_free(drc_power_domains, true);
- g_string_free(drc_names, true);
- g_string_free(drc_types, true);
-
- return ret;
-}
diff --git a/qemu/hw/ppc/spapr_events.c b/qemu/hw/ppc/spapr_events.c
deleted file mode 100644
index 049fb1b32..000000000
--- a/qemu/hw/ppc/spapr_events.c
+++ /dev/null
@@ -1,610 +0,0 @@
-/*
- * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
- *
- * RTAS events handling
- *
- * Copyright (c) 2012 David Gibson, IBM Corporation.
- *
- * 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.
- *
- */
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "cpu.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/char.h"
-#include "hw/qdev.h"
-#include "sysemu/device_tree.h"
-
-#include "hw/ppc/spapr.h"
-#include "hw/ppc/spapr_vio.h"
-#include "hw/pci/pci.h"
-#include "hw/pci-host/spapr.h"
-#include "hw/ppc/spapr_drc.h"
-#include "qemu/help_option.h"
-#include "qemu/bcd.h"
-#include <libfdt.h>
-
-struct rtas_error_log {
- uint32_t summary;
-#define RTAS_LOG_VERSION_MASK 0xff000000
-#define RTAS_LOG_VERSION_6 0x06000000
-#define RTAS_LOG_SEVERITY_MASK 0x00e00000
-#define RTAS_LOG_SEVERITY_ALREADY_REPORTED 0x00c00000
-#define RTAS_LOG_SEVERITY_FATAL 0x00a00000
-#define RTAS_LOG_SEVERITY_ERROR 0x00800000
-#define RTAS_LOG_SEVERITY_ERROR_SYNC 0x00600000
-#define RTAS_LOG_SEVERITY_WARNING 0x00400000
-#define RTAS_LOG_SEVERITY_EVENT 0x00200000
-#define RTAS_LOG_SEVERITY_NO_ERROR 0x00000000
-#define RTAS_LOG_DISPOSITION_MASK 0x00180000
-#define RTAS_LOG_DISPOSITION_FULLY_RECOVERED 0x00000000
-#define RTAS_LOG_DISPOSITION_LIMITED_RECOVERY 0x00080000
-#define RTAS_LOG_DISPOSITION_NOT_RECOVERED 0x00100000
-#define RTAS_LOG_OPTIONAL_PART_PRESENT 0x00040000
-#define RTAS_LOG_INITIATOR_MASK 0x0000f000
-#define RTAS_LOG_INITIATOR_UNKNOWN 0x00000000
-#define RTAS_LOG_INITIATOR_CPU 0x00001000
-#define RTAS_LOG_INITIATOR_PCI 0x00002000
-#define RTAS_LOG_INITIATOR_MEMORY 0x00004000
-#define RTAS_LOG_INITIATOR_HOTPLUG 0x00006000
-#define RTAS_LOG_TARGET_MASK 0x00000f00
-#define RTAS_LOG_TARGET_UNKNOWN 0x00000000
-#define RTAS_LOG_TARGET_CPU 0x00000100
-#define RTAS_LOG_TARGET_PCI 0x00000200
-#define RTAS_LOG_TARGET_MEMORY 0x00000400
-#define RTAS_LOG_TARGET_HOTPLUG 0x00000600
-#define RTAS_LOG_TYPE_MASK 0x000000ff
-#define RTAS_LOG_TYPE_OTHER 0x00000000
-#define RTAS_LOG_TYPE_RETRY 0x00000001
-#define RTAS_LOG_TYPE_TCE_ERR 0x00000002
-#define RTAS_LOG_TYPE_INTERN_DEV_FAIL 0x00000003
-#define RTAS_LOG_TYPE_TIMEOUT 0x00000004
-#define RTAS_LOG_TYPE_DATA_PARITY 0x00000005
-#define RTAS_LOG_TYPE_ADDR_PARITY 0x00000006
-#define RTAS_LOG_TYPE_CACHE_PARITY 0x00000007
-#define RTAS_LOG_TYPE_ADDR_INVALID 0x00000008
-#define RTAS_LOG_TYPE_ECC_UNCORR 0x00000009
-#define RTAS_LOG_TYPE_ECC_CORR 0x0000000a
-#define RTAS_LOG_TYPE_EPOW 0x00000040
-#define RTAS_LOG_TYPE_HOTPLUG 0x000000e5
- uint32_t extended_length;
-} QEMU_PACKED;
-
-struct rtas_event_log_v6 {
- uint8_t b0;
-#define RTAS_LOG_V6_B0_VALID 0x80
-#define RTAS_LOG_V6_B0_UNRECOVERABLE_ERROR 0x40
-#define RTAS_LOG_V6_B0_RECOVERABLE_ERROR 0x20
-#define RTAS_LOG_V6_B0_DEGRADED_OPERATION 0x10
-#define RTAS_LOG_V6_B0_PREDICTIVE_ERROR 0x08
-#define RTAS_LOG_V6_B0_NEW_LOG 0x04
-#define RTAS_LOG_V6_B0_BIGENDIAN 0x02
- uint8_t _resv1;
- uint8_t b2;
-#define RTAS_LOG_V6_B2_POWERPC_FORMAT 0x80
-#define RTAS_LOG_V6_B2_LOG_FORMAT_MASK 0x0f
-#define RTAS_LOG_V6_B2_LOG_FORMAT_PLATFORM_EVENT 0x0e
- uint8_t _resv2[9];
- uint32_t company;
-#define RTAS_LOG_V6_COMPANY_IBM 0x49424d00 /* IBM<null> */
-} QEMU_PACKED;
-
-struct rtas_event_log_v6_section_header {
- uint16_t section_id;
- uint16_t section_length;
- uint8_t section_version;
- uint8_t section_subtype;
- uint16_t creator_component_id;
-} QEMU_PACKED;
-
-struct rtas_event_log_v6_maina {
-#define RTAS_LOG_V6_SECTION_ID_MAINA 0x5048 /* PH */
- struct rtas_event_log_v6_section_header hdr;
- uint32_t creation_date; /* BCD: YYYYMMDD */
- uint32_t creation_time; /* BCD: HHMMSS00 */
- uint8_t _platform1[8];
- char creator_id;
- uint8_t _resv1[2];
- uint8_t section_count;
- uint8_t _resv2[4];
- uint8_t _platform2[8];
- uint32_t plid;
- uint8_t _platform3[4];
-} QEMU_PACKED;
-
-struct rtas_event_log_v6_mainb {
-#define RTAS_LOG_V6_SECTION_ID_MAINB 0x5548 /* UH */
- struct rtas_event_log_v6_section_header hdr;
- uint8_t subsystem_id;
- uint8_t _platform1;
- uint8_t event_severity;
- uint8_t event_subtype;
- uint8_t _platform2[4];
- uint8_t _resv1[2];
- uint16_t action_flags;
- uint8_t _resv2[4];
-} QEMU_PACKED;
-
-struct rtas_event_log_v6_epow {
-#define RTAS_LOG_V6_SECTION_ID_EPOW 0x4550 /* EP */
- struct rtas_event_log_v6_section_header hdr;
- uint8_t sensor_value;
-#define RTAS_LOG_V6_EPOW_ACTION_RESET 0
-#define RTAS_LOG_V6_EPOW_ACTION_WARN_COOLING 1
-#define RTAS_LOG_V6_EPOW_ACTION_WARN_POWER 2
-#define RTAS_LOG_V6_EPOW_ACTION_SYSTEM_SHUTDOWN 3
-#define RTAS_LOG_V6_EPOW_ACTION_SYSTEM_HALT 4
-#define RTAS_LOG_V6_EPOW_ACTION_MAIN_ENCLOSURE 5
-#define RTAS_LOG_V6_EPOW_ACTION_POWER_OFF 7
- uint8_t event_modifier;
-#define RTAS_LOG_V6_EPOW_MODIFIER_NORMAL 1
-#define RTAS_LOG_V6_EPOW_MODIFIER_ON_UPS 2
-#define RTAS_LOG_V6_EPOW_MODIFIER_CRITICAL 3
-#define RTAS_LOG_V6_EPOW_MODIFIER_TEMPERATURE 4
- uint8_t extended_modifier;
-#define RTAS_LOG_V6_EPOW_XMODIFIER_SYSTEM_WIDE 0
-#define RTAS_LOG_V6_EPOW_XMODIFIER_PARTITION_SPECIFIC 1
- uint8_t _resv;
- uint64_t reason_code;
-} QEMU_PACKED;
-
-struct epow_log_full {
- struct rtas_error_log hdr;
- struct rtas_event_log_v6 v6hdr;
- struct rtas_event_log_v6_maina maina;
- struct rtas_event_log_v6_mainb mainb;
- struct rtas_event_log_v6_epow epow;
-} QEMU_PACKED;
-
-struct rtas_event_log_v6_hp {
-#define RTAS_LOG_V6_SECTION_ID_HOTPLUG 0x4850 /* HP */
- struct rtas_event_log_v6_section_header hdr;
- uint8_t hotplug_type;
-#define RTAS_LOG_V6_HP_TYPE_CPU 1
-#define RTAS_LOG_V6_HP_TYPE_MEMORY 2
-#define RTAS_LOG_V6_HP_TYPE_SLOT 3
-#define RTAS_LOG_V6_HP_TYPE_PHB 4
-#define RTAS_LOG_V6_HP_TYPE_PCI 5
- uint8_t hotplug_action;
-#define RTAS_LOG_V6_HP_ACTION_ADD 1
-#define RTAS_LOG_V6_HP_ACTION_REMOVE 2
- uint8_t hotplug_identifier;
-#define RTAS_LOG_V6_HP_ID_DRC_NAME 1
-#define RTAS_LOG_V6_HP_ID_DRC_INDEX 2
-#define RTAS_LOG_V6_HP_ID_DRC_COUNT 3
- uint8_t reserved;
- union {
- uint32_t index;
- uint32_t count;
- char name[1];
- } drc;
-} QEMU_PACKED;
-
-struct hp_log_full {
- struct rtas_error_log hdr;
- struct rtas_event_log_v6 v6hdr;
- struct rtas_event_log_v6_maina maina;
- struct rtas_event_log_v6_mainb mainb;
- struct rtas_event_log_v6_hp hp;
-} QEMU_PACKED;
-
-#define EVENT_MASK_INTERNAL_ERRORS 0x80000000
-#define EVENT_MASK_EPOW 0x40000000
-#define EVENT_MASK_HOTPLUG 0x10000000
-#define EVENT_MASK_IO 0x08000000
-
-#define _FDT(exp) \
- do { \
- int ret = (exp); \
- if (ret < 0) { \
- fprintf(stderr, "qemu: error creating device tree: %s: %s\n", \
- #exp, fdt_strerror(ret)); \
- exit(1); \
- } \
- } while (0)
-
-void spapr_events_fdt_skel(void *fdt, uint32_t check_exception_irq)
-{
- uint32_t irq_ranges[] = {cpu_to_be32(check_exception_irq), cpu_to_be32(1)};
- uint32_t interrupts[] = {cpu_to_be32(check_exception_irq), 0};
-
- _FDT((fdt_begin_node(fdt, "event-sources")));
-
- _FDT((fdt_property(fdt, "interrupt-controller", NULL, 0)));
- _FDT((fdt_property_cell(fdt, "#interrupt-cells", 2)));
- _FDT((fdt_property(fdt, "interrupt-ranges",
- irq_ranges, sizeof(irq_ranges))));
-
- _FDT((fdt_begin_node(fdt, "epow-events")));
- _FDT((fdt_property(fdt, "interrupts", interrupts, sizeof(interrupts))));
- _FDT((fdt_end_node(fdt)));
-
- _FDT((fdt_end_node(fdt)));
-}
-
-static void rtas_event_log_queue(int log_type, void *data, bool exception)
-{
- sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
- sPAPREventLogEntry *entry = g_new(sPAPREventLogEntry, 1);
-
- g_assert(data);
- entry->log_type = log_type;
- entry->exception = exception;
- entry->data = data;
- QTAILQ_INSERT_TAIL(&spapr->pending_events, entry, next);
-}
-
-static sPAPREventLogEntry *rtas_event_log_dequeue(uint32_t event_mask,
- bool exception)
-{
- sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
- sPAPREventLogEntry *entry = NULL;
-
- /* we only queue EPOW events atm. */
- if ((event_mask & EVENT_MASK_EPOW) == 0) {
- return NULL;
- }
-
- QTAILQ_FOREACH(entry, &spapr->pending_events, next) {
- if (entry->exception != exception) {
- continue;
- }
-
- /* EPOW and hotplug events are surfaced in the same manner */
- if (entry->log_type == RTAS_LOG_TYPE_EPOW ||
- entry->log_type == RTAS_LOG_TYPE_HOTPLUG) {
- break;
- }
- }
-
- if (entry) {
- QTAILQ_REMOVE(&spapr->pending_events, entry, next);
- }
-
- return entry;
-}
-
-static bool rtas_event_log_contains(uint32_t event_mask, bool exception)
-{
- sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
- sPAPREventLogEntry *entry = NULL;
-
- /* we only queue EPOW events atm. */
- if ((event_mask & EVENT_MASK_EPOW) == 0) {
- return false;
- }
-
- QTAILQ_FOREACH(entry, &spapr->pending_events, next) {
- if (entry->exception != exception) {
- continue;
- }
-
- /* EPOW and hotplug events are surfaced in the same manner */
- if (entry->log_type == RTAS_LOG_TYPE_EPOW ||
- entry->log_type == RTAS_LOG_TYPE_HOTPLUG) {
- return true;
- }
- }
-
- return false;
-}
-
-static uint32_t next_plid;
-
-static void spapr_init_v6hdr(struct rtas_event_log_v6 *v6hdr)
-{
- v6hdr->b0 = RTAS_LOG_V6_B0_VALID | RTAS_LOG_V6_B0_NEW_LOG
- | RTAS_LOG_V6_B0_BIGENDIAN;
- v6hdr->b2 = RTAS_LOG_V6_B2_POWERPC_FORMAT
- | RTAS_LOG_V6_B2_LOG_FORMAT_PLATFORM_EVENT;
- v6hdr->company = cpu_to_be32(RTAS_LOG_V6_COMPANY_IBM);
-}
-
-static void spapr_init_maina(struct rtas_event_log_v6_maina *maina,
- int section_count)
-{
- sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
- struct tm tm;
- int year;
-
- maina->hdr.section_id = cpu_to_be16(RTAS_LOG_V6_SECTION_ID_MAINA);
- maina->hdr.section_length = cpu_to_be16(sizeof(*maina));
- /* FIXME: section version, subtype and creator id? */
- spapr_rtc_read(spapr->rtc, &tm, NULL);
- year = tm.tm_year + 1900;
- maina->creation_date = cpu_to_be32((to_bcd(year / 100) << 24)
- | (to_bcd(year % 100) << 16)
- | (to_bcd(tm.tm_mon + 1) << 8)
- | to_bcd(tm.tm_mday));
- maina->creation_time = cpu_to_be32((to_bcd(tm.tm_hour) << 24)
- | (to_bcd(tm.tm_min) << 16)
- | (to_bcd(tm.tm_sec) << 8));
- maina->creator_id = 'H'; /* Hypervisor */
- maina->section_count = section_count;
- maina->plid = next_plid++;
-}
-
-static void spapr_powerdown_req(Notifier *n, void *opaque)
-{
- sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
- struct rtas_error_log *hdr;
- struct rtas_event_log_v6 *v6hdr;
- struct rtas_event_log_v6_maina *maina;
- struct rtas_event_log_v6_mainb *mainb;
- struct rtas_event_log_v6_epow *epow;
- struct epow_log_full *new_epow;
-
- new_epow = g_malloc0(sizeof(*new_epow));
- hdr = &new_epow->hdr;
- v6hdr = &new_epow->v6hdr;
- maina = &new_epow->maina;
- mainb = &new_epow->mainb;
- epow = &new_epow->epow;
-
- hdr->summary = cpu_to_be32(RTAS_LOG_VERSION_6
- | RTAS_LOG_SEVERITY_EVENT
- | RTAS_LOG_DISPOSITION_NOT_RECOVERED
- | RTAS_LOG_OPTIONAL_PART_PRESENT
- | RTAS_LOG_TYPE_EPOW);
- hdr->extended_length = cpu_to_be32(sizeof(*new_epow)
- - sizeof(new_epow->hdr));
-
- spapr_init_v6hdr(v6hdr);
- spapr_init_maina(maina, 3 /* Main-A, Main-B and EPOW */);
-
- mainb->hdr.section_id = cpu_to_be16(RTAS_LOG_V6_SECTION_ID_MAINB);
- mainb->hdr.section_length = cpu_to_be16(sizeof(*mainb));
- /* FIXME: section version, subtype and creator id? */
- mainb->subsystem_id = 0xa0; /* External environment */
- mainb->event_severity = 0x00; /* Informational / non-error */
- mainb->event_subtype = 0xd0; /* Normal shutdown */
-
- epow->hdr.section_id = cpu_to_be16(RTAS_LOG_V6_SECTION_ID_EPOW);
- epow->hdr.section_length = cpu_to_be16(sizeof(*epow));
- epow->hdr.section_version = 2; /* includes extended modifier */
- /* FIXME: section subtype and creator id? */
- epow->sensor_value = RTAS_LOG_V6_EPOW_ACTION_SYSTEM_SHUTDOWN;
- epow->event_modifier = RTAS_LOG_V6_EPOW_MODIFIER_NORMAL;
- epow->extended_modifier = RTAS_LOG_V6_EPOW_XMODIFIER_PARTITION_SPECIFIC;
-
- rtas_event_log_queue(RTAS_LOG_TYPE_EPOW, new_epow, true);
-
- qemu_irq_pulse(xics_get_qirq(spapr->icp, spapr->check_exception_irq));
-}
-
-static void spapr_hotplug_set_signalled(uint32_t drc_index)
-{
- sPAPRDRConnector *drc = spapr_dr_connector_by_index(drc_index);
- sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
- drck->set_signalled(drc);
-}
-
-static void spapr_hotplug_req_event(uint8_t hp_id, uint8_t hp_action,
- sPAPRDRConnectorType drc_type,
- uint32_t drc)
-{
- sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
- struct hp_log_full *new_hp;
- struct rtas_error_log *hdr;
- struct rtas_event_log_v6 *v6hdr;
- struct rtas_event_log_v6_maina *maina;
- struct rtas_event_log_v6_mainb *mainb;
- struct rtas_event_log_v6_hp *hp;
-
- new_hp = g_malloc0(sizeof(struct hp_log_full));
- hdr = &new_hp->hdr;
- v6hdr = &new_hp->v6hdr;
- maina = &new_hp->maina;
- mainb = &new_hp->mainb;
- hp = &new_hp->hp;
-
- hdr->summary = cpu_to_be32(RTAS_LOG_VERSION_6
- | RTAS_LOG_SEVERITY_EVENT
- | RTAS_LOG_DISPOSITION_NOT_RECOVERED
- | RTAS_LOG_OPTIONAL_PART_PRESENT
- | RTAS_LOG_INITIATOR_HOTPLUG
- | RTAS_LOG_TYPE_HOTPLUG);
- hdr->extended_length = cpu_to_be32(sizeof(*new_hp)
- - sizeof(new_hp->hdr));
-
- spapr_init_v6hdr(v6hdr);
- spapr_init_maina(maina, 3 /* Main-A, Main-B, HP */);
-
- mainb->hdr.section_id = cpu_to_be16(RTAS_LOG_V6_SECTION_ID_MAINB);
- mainb->hdr.section_length = cpu_to_be16(sizeof(*mainb));
- mainb->subsystem_id = 0x80; /* External environment */
- mainb->event_severity = 0x00; /* Informational / non-error */
- mainb->event_subtype = 0x00; /* Normal shutdown */
-
- hp->hdr.section_id = cpu_to_be16(RTAS_LOG_V6_SECTION_ID_HOTPLUG);
- hp->hdr.section_length = cpu_to_be16(sizeof(*hp));
- hp->hdr.section_version = 1; /* includes extended modifier */
- hp->hotplug_action = hp_action;
- hp->hotplug_identifier = hp_id;
-
- switch (drc_type) {
- case SPAPR_DR_CONNECTOR_TYPE_PCI:
- hp->hotplug_type = RTAS_LOG_V6_HP_TYPE_PCI;
- if (hp->hotplug_action == RTAS_LOG_V6_HP_ACTION_ADD) {
- spapr_hotplug_set_signalled(drc);
- }
- break;
- case SPAPR_DR_CONNECTOR_TYPE_LMB:
- hp->hotplug_type = RTAS_LOG_V6_HP_TYPE_MEMORY;
- break;
- default:
- /* we shouldn't be signaling hotplug events for resources
- * that don't support them
- */
- g_assert(false);
- return;
- }
-
- if (hp_id == RTAS_LOG_V6_HP_ID_DRC_COUNT) {
- hp->drc.count = cpu_to_be32(drc);
- } else if (hp_id == RTAS_LOG_V6_HP_ID_DRC_INDEX) {
- hp->drc.index = cpu_to_be32(drc);
- }
-
- rtas_event_log_queue(RTAS_LOG_TYPE_HOTPLUG, new_hp, true);
-
- qemu_irq_pulse(xics_get_qirq(spapr->icp, spapr->check_exception_irq));
-}
-
-void spapr_hotplug_req_add_by_index(sPAPRDRConnector *drc)
-{
- sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
- sPAPRDRConnectorType drc_type = drck->get_type(drc);
- uint32_t index = drck->get_index(drc);
-
- spapr_hotplug_req_event(RTAS_LOG_V6_HP_ID_DRC_INDEX,
- RTAS_LOG_V6_HP_ACTION_ADD, drc_type, index);
-}
-
-void spapr_hotplug_req_remove_by_index(sPAPRDRConnector *drc)
-{
- sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
- sPAPRDRConnectorType drc_type = drck->get_type(drc);
- uint32_t index = drck->get_index(drc);
-
- spapr_hotplug_req_event(RTAS_LOG_V6_HP_ID_DRC_INDEX,
- RTAS_LOG_V6_HP_ACTION_REMOVE, drc_type, index);
-}
-
-void spapr_hotplug_req_add_by_count(sPAPRDRConnectorType drc_type,
- uint32_t count)
-{
- spapr_hotplug_req_event(RTAS_LOG_V6_HP_ID_DRC_COUNT,
- RTAS_LOG_V6_HP_ACTION_ADD, drc_type, count);
-}
-
-void spapr_hotplug_req_remove_by_count(sPAPRDRConnectorType drc_type,
- uint32_t count)
-{
- spapr_hotplug_req_event(RTAS_LOG_V6_HP_ID_DRC_COUNT,
- RTAS_LOG_V6_HP_ACTION_REMOVE, drc_type, count);
-}
-
-static void check_exception(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- uint32_t token, uint32_t nargs,
- target_ulong args,
- uint32_t nret, target_ulong rets)
-{
- uint32_t mask, buf, len, event_len;
- uint64_t xinfo;
- sPAPREventLogEntry *event;
- struct rtas_error_log *hdr;
-
- if ((nargs < 6) || (nargs > 7) || nret != 1) {
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
- return;
- }
-
- xinfo = rtas_ld(args, 1);
- mask = rtas_ld(args, 2);
- buf = rtas_ld(args, 4);
- len = rtas_ld(args, 5);
- if (nargs == 7) {
- xinfo |= (uint64_t)rtas_ld(args, 6) << 32;
- }
-
- event = rtas_event_log_dequeue(mask, true);
- if (!event) {
- goto out_no_events;
- }
-
- hdr = event->data;
- event_len = be32_to_cpu(hdr->extended_length) + sizeof(*hdr);
-
- if (event_len < len) {
- len = event_len;
- }
-
- cpu_physical_memory_write(buf, event->data, len);
- rtas_st(rets, 0, RTAS_OUT_SUCCESS);
- g_free(event->data);
- g_free(event);
-
- /* according to PAPR+, the IRQ must be left asserted, or re-asserted, if
- * there are still pending events to be fetched via check-exception. We
- * do the latter here, since our code relies on edge-triggered
- * interrupts.
- */
- if (rtas_event_log_contains(mask, true)) {
- qemu_irq_pulse(xics_get_qirq(spapr->icp, spapr->check_exception_irq));
- }
-
- return;
-
-out_no_events:
- rtas_st(rets, 0, RTAS_OUT_NO_ERRORS_FOUND);
-}
-
-static void event_scan(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- uint32_t token, uint32_t nargs,
- target_ulong args,
- uint32_t nret, target_ulong rets)
-{
- uint32_t mask, buf, len, event_len;
- sPAPREventLogEntry *event;
- struct rtas_error_log *hdr;
-
- if (nargs != 4 || nret != 1) {
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
- return;
- }
-
- mask = rtas_ld(args, 0);
- buf = rtas_ld(args, 2);
- len = rtas_ld(args, 3);
-
- event = rtas_event_log_dequeue(mask, false);
- if (!event) {
- goto out_no_events;
- }
-
- hdr = event->data;
- event_len = be32_to_cpu(hdr->extended_length) + sizeof(*hdr);
-
- if (event_len < len) {
- len = event_len;
- }
-
- cpu_physical_memory_write(buf, event->data, len);
- rtas_st(rets, 0, RTAS_OUT_SUCCESS);
- g_free(event->data);
- g_free(event);
- return;
-
-out_no_events:
- rtas_st(rets, 0, RTAS_OUT_NO_ERRORS_FOUND);
-}
-
-void spapr_events_init(sPAPRMachineState *spapr)
-{
- QTAILQ_INIT(&spapr->pending_events);
- spapr->check_exception_irq = xics_alloc(spapr->icp, 0, 0, false,
- &error_fatal);
- spapr->epow_notifier.notify = spapr_powerdown_req;
- qemu_register_powerdown_notifier(&spapr->epow_notifier);
- spapr_rtas_register(RTAS_CHECK_EXCEPTION, "check-exception",
- check_exception);
- spapr_rtas_register(RTAS_EVENT_SCAN, "event-scan", event_scan);
-}
diff --git a/qemu/hw/ppc/spapr_hcall.c b/qemu/hw/ppc/spapr_hcall.c
deleted file mode 100644
index 8f40602a5..000000000
--- a/qemu/hw/ppc/spapr_hcall.c
+++ /dev/null
@@ -1,1117 +0,0 @@
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "sysemu/sysemu.h"
-#include "cpu.h"
-#include "helper_regs.h"
-#include "hw/ppc/spapr.h"
-#include "mmu-hash64.h"
-#include "cpu-models.h"
-#include "trace.h"
-#include "kvm_ppc.h"
-
-struct SPRSyncState {
- CPUState *cs;
- int spr;
- target_ulong value;
- target_ulong mask;
-};
-
-static void do_spr_sync(void *arg)
-{
- struct SPRSyncState *s = arg;
- PowerPCCPU *cpu = POWERPC_CPU(s->cs);
- CPUPPCState *env = &cpu->env;
-
- cpu_synchronize_state(s->cs);
- env->spr[s->spr] &= ~s->mask;
- env->spr[s->spr] |= s->value;
-}
-
-static void set_spr(CPUState *cs, int spr, target_ulong value,
- target_ulong mask)
-{
- struct SPRSyncState s = {
- .cs = cs,
- .spr = spr,
- .value = value,
- .mask = mask
- };
- run_on_cpu(cs, do_spr_sync, &s);
-}
-
-static bool has_spr(PowerPCCPU *cpu, int spr)
-{
- /* We can test whether the SPR is defined by checking for a valid name */
- return cpu->env.spr_cb[spr].name != NULL;
-}
-
-static inline bool valid_pte_index(CPUPPCState *env, target_ulong pte_index)
-{
- /*
- * hash value/pteg group index is normalized by htab_mask
- */
- if (((pte_index & ~7ULL) / HPTES_PER_GROUP) & ~env->htab_mask) {
- return false;
- }
- return true;
-}
-
-static bool is_ram_address(sPAPRMachineState *spapr, hwaddr addr)
-{
- MachineState *machine = MACHINE(spapr);
- MemoryHotplugState *hpms = &spapr->hotplug_memory;
-
- if (addr < machine->ram_size) {
- return true;
- }
- if ((addr >= hpms->base)
- && ((addr - hpms->base) < memory_region_size(&hpms->mr))) {
- return true;
- }
-
- return false;
-}
-
-static target_ulong h_enter(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- CPUPPCState *env = &cpu->env;
- target_ulong flags = args[0];
- target_ulong pte_index = args[1];
- target_ulong pteh = args[2];
- target_ulong ptel = args[3];
- unsigned apshift, spshift;
- target_ulong raddr;
- target_ulong index;
- uint64_t token;
-
- apshift = ppc_hash64_hpte_page_shift_noslb(cpu, pteh, ptel, &spshift);
- if (!apshift) {
- /* Bad page size encoding */
- return H_PARAMETER;
- }
-
- raddr = (ptel & HPTE64_R_RPN) & ~((1ULL << apshift) - 1);
-
- if (is_ram_address(spapr, raddr)) {
- /* Regular RAM - should have WIMG=0010 */
- if ((ptel & HPTE64_R_WIMG) != HPTE64_R_M) {
- return H_PARAMETER;
- }
- } else {
- /* Looks like an IO address */
- /* FIXME: What WIMG combinations could be sensible for IO?
- * For now we allow WIMG=010x, but are there others? */
- /* FIXME: Should we check against registered IO addresses? */
- if ((ptel & (HPTE64_R_W | HPTE64_R_I | HPTE64_R_M)) != HPTE64_R_I) {
- return H_PARAMETER;
- }
- }
-
- pteh &= ~0x60ULL;
-
- if (!valid_pte_index(env, pte_index)) {
- return H_PARAMETER;
- }
-
- index = 0;
- if (likely((flags & H_EXACT) == 0)) {
- pte_index &= ~7ULL;
- token = ppc_hash64_start_access(cpu, pte_index);
- for (; index < 8; index++) {
- if (!(ppc_hash64_load_hpte0(cpu, token, index) & HPTE64_V_VALID)) {
- break;
- }
- }
- ppc_hash64_stop_access(cpu, token);
- if (index == 8) {
- return H_PTEG_FULL;
- }
- } else {
- token = ppc_hash64_start_access(cpu, pte_index);
- if (ppc_hash64_load_hpte0(cpu, token, 0) & HPTE64_V_VALID) {
- ppc_hash64_stop_access(cpu, token);
- return H_PTEG_FULL;
- }
- ppc_hash64_stop_access(cpu, token);
- }
-
- ppc_hash64_store_hpte(cpu, pte_index + index,
- pteh | HPTE64_V_HPTE_DIRTY, ptel);
-
- args[0] = pte_index + index;
- return H_SUCCESS;
-}
-
-typedef enum {
- REMOVE_SUCCESS = 0,
- REMOVE_NOT_FOUND = 1,
- REMOVE_PARM = 2,
- REMOVE_HW = 3,
-} RemoveResult;
-
-static RemoveResult remove_hpte(PowerPCCPU *cpu, target_ulong ptex,
- target_ulong avpn,
- target_ulong flags,
- target_ulong *vp, target_ulong *rp)
-{
- CPUPPCState *env = &cpu->env;
- uint64_t token;
- target_ulong v, r;
-
- if (!valid_pte_index(env, ptex)) {
- return REMOVE_PARM;
- }
-
- token = ppc_hash64_start_access(cpu, ptex);
- v = ppc_hash64_load_hpte0(cpu, token, 0);
- r = ppc_hash64_load_hpte1(cpu, token, 0);
- ppc_hash64_stop_access(cpu, token);
-
- if ((v & HPTE64_V_VALID) == 0 ||
- ((flags & H_AVPN) && (v & ~0x7fULL) != avpn) ||
- ((flags & H_ANDCOND) && (v & avpn) != 0)) {
- return REMOVE_NOT_FOUND;
- }
- *vp = v;
- *rp = r;
- ppc_hash64_store_hpte(cpu, ptex, HPTE64_V_HPTE_DIRTY, 0);
- ppc_hash64_tlb_flush_hpte(cpu, ptex, v, r);
- return REMOVE_SUCCESS;
-}
-
-static target_ulong h_remove(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- target_ulong flags = args[0];
- target_ulong pte_index = args[1];
- target_ulong avpn = args[2];
- RemoveResult ret;
-
- ret = remove_hpte(cpu, pte_index, avpn, flags,
- &args[0], &args[1]);
-
- switch (ret) {
- case REMOVE_SUCCESS:
- return H_SUCCESS;
-
- case REMOVE_NOT_FOUND:
- return H_NOT_FOUND;
-
- case REMOVE_PARM:
- return H_PARAMETER;
-
- case REMOVE_HW:
- return H_HARDWARE;
- }
-
- g_assert_not_reached();
-}
-
-#define H_BULK_REMOVE_TYPE 0xc000000000000000ULL
-#define H_BULK_REMOVE_REQUEST 0x4000000000000000ULL
-#define H_BULK_REMOVE_RESPONSE 0x8000000000000000ULL
-#define H_BULK_REMOVE_END 0xc000000000000000ULL
-#define H_BULK_REMOVE_CODE 0x3000000000000000ULL
-#define H_BULK_REMOVE_SUCCESS 0x0000000000000000ULL
-#define H_BULK_REMOVE_NOT_FOUND 0x1000000000000000ULL
-#define H_BULK_REMOVE_PARM 0x2000000000000000ULL
-#define H_BULK_REMOVE_HW 0x3000000000000000ULL
-#define H_BULK_REMOVE_RC 0x0c00000000000000ULL
-#define H_BULK_REMOVE_FLAGS 0x0300000000000000ULL
-#define H_BULK_REMOVE_ABSOLUTE 0x0000000000000000ULL
-#define H_BULK_REMOVE_ANDCOND 0x0100000000000000ULL
-#define H_BULK_REMOVE_AVPN 0x0200000000000000ULL
-#define H_BULK_REMOVE_PTEX 0x00ffffffffffffffULL
-
-#define H_BULK_REMOVE_MAX_BATCH 4
-
-static target_ulong h_bulk_remove(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- int i;
-
- for (i = 0; i < H_BULK_REMOVE_MAX_BATCH; i++) {
- target_ulong *tsh = &args[i*2];
- target_ulong tsl = args[i*2 + 1];
- target_ulong v, r, ret;
-
- if ((*tsh & H_BULK_REMOVE_TYPE) == H_BULK_REMOVE_END) {
- break;
- } else if ((*tsh & H_BULK_REMOVE_TYPE) != H_BULK_REMOVE_REQUEST) {
- return H_PARAMETER;
- }
-
- *tsh &= H_BULK_REMOVE_PTEX | H_BULK_REMOVE_FLAGS;
- *tsh |= H_BULK_REMOVE_RESPONSE;
-
- if ((*tsh & H_BULK_REMOVE_ANDCOND) && (*tsh & H_BULK_REMOVE_AVPN)) {
- *tsh |= H_BULK_REMOVE_PARM;
- return H_PARAMETER;
- }
-
- ret = remove_hpte(cpu, *tsh & H_BULK_REMOVE_PTEX, tsl,
- (*tsh & H_BULK_REMOVE_FLAGS) >> 26,
- &v, &r);
-
- *tsh |= ret << 60;
-
- switch (ret) {
- case REMOVE_SUCCESS:
- *tsh |= (r & (HPTE64_R_C | HPTE64_R_R)) << 43;
- break;
-
- case REMOVE_PARM:
- return H_PARAMETER;
-
- case REMOVE_HW:
- return H_HARDWARE;
- }
- }
-
- return H_SUCCESS;
-}
-
-static target_ulong h_protect(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- CPUPPCState *env = &cpu->env;
- target_ulong flags = args[0];
- target_ulong pte_index = args[1];
- target_ulong avpn = args[2];
- uint64_t token;
- target_ulong v, r;
-
- if (!valid_pte_index(env, pte_index)) {
- return H_PARAMETER;
- }
-
- token = ppc_hash64_start_access(cpu, pte_index);
- v = ppc_hash64_load_hpte0(cpu, token, 0);
- r = ppc_hash64_load_hpte1(cpu, token, 0);
- ppc_hash64_stop_access(cpu, token);
-
- if ((v & HPTE64_V_VALID) == 0 ||
- ((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) {
- return H_NOT_FOUND;
- }
-
- r &= ~(HPTE64_R_PP0 | HPTE64_R_PP | HPTE64_R_N |
- HPTE64_R_KEY_HI | HPTE64_R_KEY_LO);
- r |= (flags << 55) & HPTE64_R_PP0;
- r |= (flags << 48) & HPTE64_R_KEY_HI;
- r |= flags & (HPTE64_R_PP | HPTE64_R_N | HPTE64_R_KEY_LO);
- ppc_hash64_store_hpte(cpu, pte_index,
- (v & ~HPTE64_V_VALID) | HPTE64_V_HPTE_DIRTY, 0);
- ppc_hash64_tlb_flush_hpte(cpu, pte_index, v, r);
- /* Don't need a memory barrier, due to qemu's global lock */
- ppc_hash64_store_hpte(cpu, pte_index, v | HPTE64_V_HPTE_DIRTY, r);
- return H_SUCCESS;
-}
-
-static target_ulong h_read(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- CPUPPCState *env = &cpu->env;
- target_ulong flags = args[0];
- target_ulong pte_index = args[1];
- uint8_t *hpte;
- int i, ridx, n_entries = 1;
-
- if (!valid_pte_index(env, pte_index)) {
- return H_PARAMETER;
- }
-
- if (flags & H_READ_4) {
- /* Clear the two low order bits */
- pte_index &= ~(3ULL);
- n_entries = 4;
- }
-
- hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64);
-
- for (i = 0, ridx = 0; i < n_entries; i++) {
- args[ridx++] = ldq_p(hpte);
- args[ridx++] = ldq_p(hpte + (HASH_PTE_SIZE_64/2));
- hpte += HASH_PTE_SIZE_64;
- }
-
- return H_SUCCESS;
-}
-
-static target_ulong h_set_sprg0(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- cpu_synchronize_state(CPU(cpu));
- cpu->env.spr[SPR_SPRG0] = args[0];
-
- return H_SUCCESS;
-}
-
-static target_ulong h_set_dabr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- if (!has_spr(cpu, SPR_DABR)) {
- return H_HARDWARE; /* DABR register not available */
- }
- cpu_synchronize_state(CPU(cpu));
-
- if (has_spr(cpu, SPR_DABRX)) {
- cpu->env.spr[SPR_DABRX] = 0x3; /* Use Problem and Privileged state */
- } else if (!(args[0] & 0x4)) { /* Breakpoint Translation set? */
- return H_RESERVED_DABR;
- }
-
- cpu->env.spr[SPR_DABR] = args[0];
- return H_SUCCESS;
-}
-
-static target_ulong h_set_xdabr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- target_ulong dabrx = args[1];
-
- if (!has_spr(cpu, SPR_DABR) || !has_spr(cpu, SPR_DABRX)) {
- return H_HARDWARE;
- }
-
- if ((dabrx & ~0xfULL) != 0 || (dabrx & H_DABRX_HYPERVISOR) != 0
- || (dabrx & (H_DABRX_KERNEL | H_DABRX_USER)) == 0) {
- return H_PARAMETER;
- }
-
- cpu_synchronize_state(CPU(cpu));
- cpu->env.spr[SPR_DABRX] = dabrx;
- cpu->env.spr[SPR_DABR] = args[0];
-
- return H_SUCCESS;
-}
-
-static target_ulong h_page_init(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- target_ulong flags = args[0];
- hwaddr dst = args[1];
- hwaddr src = args[2];
- hwaddr len = TARGET_PAGE_SIZE;
- uint8_t *pdst, *psrc;
- target_long ret = H_SUCCESS;
-
- if (flags & ~(H_ICACHE_SYNCHRONIZE | H_ICACHE_INVALIDATE
- | H_COPY_PAGE | H_ZERO_PAGE)) {
- qemu_log_mask(LOG_UNIMP, "h_page_init: Bad flags (" TARGET_FMT_lx "\n",
- flags);
- return H_PARAMETER;
- }
-
- /* Map-in destination */
- if (!is_ram_address(spapr, dst) || (dst & ~TARGET_PAGE_MASK) != 0) {
- return H_PARAMETER;
- }
- pdst = cpu_physical_memory_map(dst, &len, 1);
- if (!pdst || len != TARGET_PAGE_SIZE) {
- return H_PARAMETER;
- }
-
- if (flags & H_COPY_PAGE) {
- /* Map-in source, copy to destination, and unmap source again */
- if (!is_ram_address(spapr, src) || (src & ~TARGET_PAGE_MASK) != 0) {
- ret = H_PARAMETER;
- goto unmap_out;
- }
- psrc = cpu_physical_memory_map(src, &len, 0);
- if (!psrc || len != TARGET_PAGE_SIZE) {
- ret = H_PARAMETER;
- goto unmap_out;
- }
- memcpy(pdst, psrc, len);
- cpu_physical_memory_unmap(psrc, len, 0, len);
- } else if (flags & H_ZERO_PAGE) {
- memset(pdst, 0, len); /* Just clear the destination page */
- }
-
- if (kvm_enabled() && (flags & H_ICACHE_SYNCHRONIZE) != 0) {
- kvmppc_dcbst_range(cpu, pdst, len);
- }
- if (flags & (H_ICACHE_SYNCHRONIZE | H_ICACHE_INVALIDATE)) {
- if (kvm_enabled()) {
- kvmppc_icbi_range(cpu, pdst, len);
- } else {
- tb_flush(CPU(cpu));
- }
- }
-
-unmap_out:
- cpu_physical_memory_unmap(pdst, TARGET_PAGE_SIZE, 1, len);
- return ret;
-}
-
-#define FLAGS_REGISTER_VPA 0x0000200000000000ULL
-#define FLAGS_REGISTER_DTL 0x0000400000000000ULL
-#define FLAGS_REGISTER_SLBSHADOW 0x0000600000000000ULL
-#define FLAGS_DEREGISTER_VPA 0x0000a00000000000ULL
-#define FLAGS_DEREGISTER_DTL 0x0000c00000000000ULL
-#define FLAGS_DEREGISTER_SLBSHADOW 0x0000e00000000000ULL
-
-#define VPA_MIN_SIZE 640
-#define VPA_SIZE_OFFSET 0x4
-#define VPA_SHARED_PROC_OFFSET 0x9
-#define VPA_SHARED_PROC_VAL 0x2
-
-static target_ulong register_vpa(CPUPPCState *env, target_ulong vpa)
-{
- CPUState *cs = CPU(ppc_env_get_cpu(env));
- uint16_t size;
- uint8_t tmp;
-
- if (vpa == 0) {
- hcall_dprintf("Can't cope with registering a VPA at logical 0\n");
- return H_HARDWARE;
- }
-
- if (vpa % env->dcache_line_size) {
- return H_PARAMETER;
- }
- /* FIXME: bounds check the address */
-
- size = lduw_be_phys(cs->as, vpa + 0x4);
-
- if (size < VPA_MIN_SIZE) {
- return H_PARAMETER;
- }
-
- /* VPA is not allowed to cross a page boundary */
- if ((vpa / 4096) != ((vpa + size - 1) / 4096)) {
- return H_PARAMETER;
- }
-
- env->vpa_addr = vpa;
-
- tmp = ldub_phys(cs->as, env->vpa_addr + VPA_SHARED_PROC_OFFSET);
- tmp |= VPA_SHARED_PROC_VAL;
- stb_phys(cs->as, env->vpa_addr + VPA_SHARED_PROC_OFFSET, tmp);
-
- return H_SUCCESS;
-}
-
-static target_ulong deregister_vpa(CPUPPCState *env, target_ulong vpa)
-{
- if (env->slb_shadow_addr) {
- return H_RESOURCE;
- }
-
- if (env->dtl_addr) {
- return H_RESOURCE;
- }
-
- env->vpa_addr = 0;
- return H_SUCCESS;
-}
-
-static target_ulong register_slb_shadow(CPUPPCState *env, target_ulong addr)
-{
- CPUState *cs = CPU(ppc_env_get_cpu(env));
- uint32_t size;
-
- if (addr == 0) {
- hcall_dprintf("Can't cope with SLB shadow at logical 0\n");
- return H_HARDWARE;
- }
-
- size = ldl_be_phys(cs->as, addr + 0x4);
- if (size < 0x8) {
- return H_PARAMETER;
- }
-
- if ((addr / 4096) != ((addr + size - 1) / 4096)) {
- return H_PARAMETER;
- }
-
- if (!env->vpa_addr) {
- return H_RESOURCE;
- }
-
- env->slb_shadow_addr = addr;
- env->slb_shadow_size = size;
-
- return H_SUCCESS;
-}
-
-static target_ulong deregister_slb_shadow(CPUPPCState *env, target_ulong addr)
-{
- env->slb_shadow_addr = 0;
- env->slb_shadow_size = 0;
- return H_SUCCESS;
-}
-
-static target_ulong register_dtl(CPUPPCState *env, target_ulong addr)
-{
- CPUState *cs = CPU(ppc_env_get_cpu(env));
- uint32_t size;
-
- if (addr == 0) {
- hcall_dprintf("Can't cope with DTL at logical 0\n");
- return H_HARDWARE;
- }
-
- size = ldl_be_phys(cs->as, addr + 0x4);
-
- if (size < 48) {
- return H_PARAMETER;
- }
-
- if (!env->vpa_addr) {
- return H_RESOURCE;
- }
-
- env->dtl_addr = addr;
- env->dtl_size = size;
-
- return H_SUCCESS;
-}
-
-static target_ulong deregister_dtl(CPUPPCState *env, target_ulong addr)
-{
- env->dtl_addr = 0;
- env->dtl_size = 0;
-
- return H_SUCCESS;
-}
-
-static target_ulong h_register_vpa(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- target_ulong flags = args[0];
- target_ulong procno = args[1];
- target_ulong vpa = args[2];
- target_ulong ret = H_PARAMETER;
- CPUPPCState *tenv;
- PowerPCCPU *tcpu;
-
- tcpu = ppc_get_vcpu_by_dt_id(procno);
- if (!tcpu) {
- return H_PARAMETER;
- }
- tenv = &tcpu->env;
-
- switch (flags) {
- case FLAGS_REGISTER_VPA:
- ret = register_vpa(tenv, vpa);
- break;
-
- case FLAGS_DEREGISTER_VPA:
- ret = deregister_vpa(tenv, vpa);
- break;
-
- case FLAGS_REGISTER_SLBSHADOW:
- ret = register_slb_shadow(tenv, vpa);
- break;
-
- case FLAGS_DEREGISTER_SLBSHADOW:
- ret = deregister_slb_shadow(tenv, vpa);
- break;
-
- case FLAGS_REGISTER_DTL:
- ret = register_dtl(tenv, vpa);
- break;
-
- case FLAGS_DEREGISTER_DTL:
- ret = deregister_dtl(tenv, vpa);
- break;
- }
-
- return ret;
-}
-
-static target_ulong h_cede(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- CPUPPCState *env = &cpu->env;
- CPUState *cs = CPU(cpu);
-
- env->msr |= (1ULL << MSR_EE);
- hreg_compute_hflags(env);
- if (!cpu_has_work(cs)) {
- cs->halted = 1;
- cs->exception_index = EXCP_HLT;
- cs->exit_request = 1;
- }
- return H_SUCCESS;
-}
-
-static target_ulong h_rtas(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- target_ulong rtas_r3 = args[0];
- uint32_t token = rtas_ld(rtas_r3, 0);
- uint32_t nargs = rtas_ld(rtas_r3, 1);
- uint32_t nret = rtas_ld(rtas_r3, 2);
-
- return spapr_rtas_call(cpu, spapr, token, nargs, rtas_r3 + 12,
- nret, rtas_r3 + 12 + 4*nargs);
-}
-
-static target_ulong h_logical_load(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- CPUState *cs = CPU(cpu);
- target_ulong size = args[0];
- target_ulong addr = args[1];
-
- switch (size) {
- case 1:
- args[0] = ldub_phys(cs->as, addr);
- return H_SUCCESS;
- case 2:
- args[0] = lduw_phys(cs->as, addr);
- return H_SUCCESS;
- case 4:
- args[0] = ldl_phys(cs->as, addr);
- return H_SUCCESS;
- case 8:
- args[0] = ldq_phys(cs->as, addr);
- return H_SUCCESS;
- }
- return H_PARAMETER;
-}
-
-static target_ulong h_logical_store(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- CPUState *cs = CPU(cpu);
-
- target_ulong size = args[0];
- target_ulong addr = args[1];
- target_ulong val = args[2];
-
- switch (size) {
- case 1:
- stb_phys(cs->as, addr, val);
- return H_SUCCESS;
- case 2:
- stw_phys(cs->as, addr, val);
- return H_SUCCESS;
- case 4:
- stl_phys(cs->as, addr, val);
- return H_SUCCESS;
- case 8:
- stq_phys(cs->as, addr, val);
- return H_SUCCESS;
- }
- return H_PARAMETER;
-}
-
-static target_ulong h_logical_memop(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- CPUState *cs = CPU(cpu);
-
- target_ulong dst = args[0]; /* Destination address */
- target_ulong src = args[1]; /* Source address */
- target_ulong esize = args[2]; /* Element size (0=1,1=2,2=4,3=8) */
- target_ulong count = args[3]; /* Element count */
- target_ulong op = args[4]; /* 0 = copy, 1 = invert */
- uint64_t tmp;
- unsigned int mask = (1 << esize) - 1;
- int step = 1 << esize;
-
- if (count > 0x80000000) {
- return H_PARAMETER;
- }
-
- if ((dst & mask) || (src & mask) || (op > 1)) {
- return H_PARAMETER;
- }
-
- if (dst >= src && dst < (src + (count << esize))) {
- dst = dst + ((count - 1) << esize);
- src = src + ((count - 1) << esize);
- step = -step;
- }
-
- while (count--) {
- switch (esize) {
- case 0:
- tmp = ldub_phys(cs->as, src);
- break;
- case 1:
- tmp = lduw_phys(cs->as, src);
- break;
- case 2:
- tmp = ldl_phys(cs->as, src);
- break;
- case 3:
- tmp = ldq_phys(cs->as, src);
- break;
- default:
- return H_PARAMETER;
- }
- if (op == 1) {
- tmp = ~tmp;
- }
- switch (esize) {
- case 0:
- stb_phys(cs->as, dst, tmp);
- break;
- case 1:
- stw_phys(cs->as, dst, tmp);
- break;
- case 2:
- stl_phys(cs->as, dst, tmp);
- break;
- case 3:
- stq_phys(cs->as, dst, tmp);
- break;
- }
- dst = dst + step;
- src = src + step;
- }
-
- return H_SUCCESS;
-}
-
-static target_ulong h_logical_icbi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- /* Nothing to do on emulation, KVM will trap this in the kernel */
- return H_SUCCESS;
-}
-
-static target_ulong h_logical_dcbf(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- /* Nothing to do on emulation, KVM will trap this in the kernel */
- return H_SUCCESS;
-}
-
-static target_ulong h_set_mode_resource_le(PowerPCCPU *cpu,
- target_ulong mflags,
- target_ulong value1,
- target_ulong value2)
-{
- CPUState *cs;
-
- if (value1) {
- return H_P3;
- }
- if (value2) {
- return H_P4;
- }
-
- switch (mflags) {
- case H_SET_MODE_ENDIAN_BIG:
- CPU_FOREACH(cs) {
- set_spr(cs, SPR_LPCR, 0, LPCR_ILE);
- }
- spapr_pci_switch_vga(true);
- return H_SUCCESS;
-
- case H_SET_MODE_ENDIAN_LITTLE:
- CPU_FOREACH(cs) {
- set_spr(cs, SPR_LPCR, LPCR_ILE, LPCR_ILE);
- }
- spapr_pci_switch_vga(false);
- return H_SUCCESS;
- }
-
- return H_UNSUPPORTED_FLAG;
-}
-
-static target_ulong h_set_mode_resource_addr_trans_mode(PowerPCCPU *cpu,
- target_ulong mflags,
- target_ulong value1,
- target_ulong value2)
-{
- CPUState *cs;
- PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
-
- if (!(pcc->insns_flags2 & PPC2_ISA207S)) {
- return H_P2;
- }
- if (value1) {
- return H_P3;
- }
- if (value2) {
- return H_P4;
- }
-
- if (mflags == AIL_RESERVED) {
- return H_UNSUPPORTED_FLAG;
- }
-
- CPU_FOREACH(cs) {
- set_spr(cs, SPR_LPCR, mflags << LPCR_AIL_SHIFT, LPCR_AIL);
- }
-
- return H_SUCCESS;
-}
-
-static target_ulong h_set_mode(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- target_ulong resource = args[1];
- target_ulong ret = H_P2;
-
- switch (resource) {
- case H_SET_MODE_RESOURCE_LE:
- ret = h_set_mode_resource_le(cpu, args[0], args[2], args[3]);
- break;
- case H_SET_MODE_RESOURCE_ADDR_TRANS_MODE:
- ret = h_set_mode_resource_addr_trans_mode(cpu, args[0],
- args[2], args[3]);
- break;
- }
-
- return ret;
-}
-
-/*
- * Return the offset to the requested option vector @vector in the
- * option vector table @table.
- */
-static target_ulong cas_get_option_vector(int vector, target_ulong table)
-{
- int i;
- char nr_vectors, nr_entries;
-
- if (!table) {
- return 0;
- }
-
- nr_vectors = (ldl_phys(&address_space_memory, table) >> 24) + 1;
- if (!vector || vector > nr_vectors) {
- return 0;
- }
- table++; /* skip nr option vectors */
-
- for (i = 0; i < vector - 1; i++) {
- nr_entries = ldl_phys(&address_space_memory, table) >> 24;
- table += nr_entries + 2;
- }
- return table;
-}
-
-typedef struct {
- PowerPCCPU *cpu;
- uint32_t cpu_version;
- Error *err;
-} SetCompatState;
-
-static void do_set_compat(void *arg)
-{
- SetCompatState *s = arg;
-
- cpu_synchronize_state(CPU(s->cpu));
- ppc_set_compat(s->cpu, s->cpu_version, &s->err);
-}
-
-#define get_compat_level(cpuver) ( \
- ((cpuver) == CPU_POWERPC_LOGICAL_2_05) ? 2050 : \
- ((cpuver) == CPU_POWERPC_LOGICAL_2_06) ? 2060 : \
- ((cpuver) == CPU_POWERPC_LOGICAL_2_06_PLUS) ? 2061 : \
- ((cpuver) == CPU_POWERPC_LOGICAL_2_07) ? 2070 : 0)
-
-#define OV5_DRCONF_MEMORY 0x20
-
-static target_ulong h_client_architecture_support(PowerPCCPU *cpu_,
- sPAPRMachineState *spapr,
- target_ulong opcode,
- target_ulong *args)
-{
- target_ulong list = ppc64_phys_to_real(args[0]);
- target_ulong ov_table, ov5;
- PowerPCCPUClass *pcc_ = POWERPC_CPU_GET_CLASS(cpu_);
- CPUState *cs;
- bool cpu_match = false, cpu_update = true, memory_update = false;
- unsigned old_cpu_version = cpu_->cpu_version;
- unsigned compat_lvl = 0, cpu_version = 0;
- unsigned max_lvl = get_compat_level(cpu_->max_compat);
- int counter;
- char ov5_byte2;
-
- /* Parse PVR list */
- for (counter = 0; counter < 512; ++counter) {
- uint32_t pvr, pvr_mask;
-
- pvr_mask = ldl_be_phys(&address_space_memory, list);
- list += 4;
- pvr = ldl_be_phys(&address_space_memory, list);
- list += 4;
-
- trace_spapr_cas_pvr_try(pvr);
- if (!max_lvl &&
- ((cpu_->env.spr[SPR_PVR] & pvr_mask) == (pvr & pvr_mask))) {
- cpu_match = true;
- cpu_version = 0;
- } else if (pvr == cpu_->cpu_version) {
- cpu_match = true;
- cpu_version = cpu_->cpu_version;
- } else if (!cpu_match) {
- /* If it is a logical PVR, try to determine the highest level */
- unsigned lvl = get_compat_level(pvr);
- if (lvl) {
- bool is205 = (pcc_->pcr_mask & PCR_COMPAT_2_05) &&
- (lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_05));
- bool is206 = (pcc_->pcr_mask & PCR_COMPAT_2_06) &&
- ((lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_06)) ||
- (lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_06_PLUS)));
-
- if (is205 || is206) {
- if (!max_lvl) {
- /* User did not set the level, choose the highest */
- if (compat_lvl <= lvl) {
- compat_lvl = lvl;
- cpu_version = pvr;
- }
- } else if (max_lvl >= lvl) {
- /* User chose the level, don't set higher than this */
- compat_lvl = lvl;
- cpu_version = pvr;
- }
- }
- }
- }
- /* Terminator record */
- if (~pvr_mask & pvr) {
- break;
- }
- }
-
- /* Parsing finished */
- trace_spapr_cas_pvr(cpu_->cpu_version, cpu_match,
- cpu_version, pcc_->pcr_mask);
-
- /* Update CPUs */
- if (old_cpu_version != cpu_version) {
- CPU_FOREACH(cs) {
- SetCompatState s = {
- .cpu = POWERPC_CPU(cs),
- .cpu_version = cpu_version,
- .err = NULL,
- };
-
- run_on_cpu(cs, do_set_compat, &s);
-
- if (s.err) {
- error_report_err(s.err);
- return H_HARDWARE;
- }
- }
- }
-
- if (!cpu_version) {
- cpu_update = false;
- }
-
- /* For the future use: here @ov_table points to the first option vector */
- ov_table = list;
-
- ov5 = cas_get_option_vector(5, ov_table);
- if (!ov5) {
- return H_SUCCESS;
- }
-
- /* @list now points to OV 5 */
- ov5_byte2 = ldub_phys(&address_space_memory, ov5 + 2);
- if (ov5_byte2 & OV5_DRCONF_MEMORY) {
- memory_update = true;
- }
-
- if (spapr_h_cas_compose_response(spapr, args[1], args[2],
- cpu_update, memory_update)) {
- qemu_system_reset_request();
- }
-
- return H_SUCCESS;
-}
-
-static spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1];
-static spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX - KVMPPC_HCALL_BASE + 1];
-
-void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn)
-{
- spapr_hcall_fn *slot;
-
- if (opcode <= MAX_HCALL_OPCODE) {
- assert((opcode & 0x3) == 0);
-
- slot = &papr_hypercall_table[opcode / 4];
- } else {
- assert((opcode >= KVMPPC_HCALL_BASE) && (opcode <= KVMPPC_HCALL_MAX));
-
- slot = &kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE];
- }
-
- assert(!(*slot));
- *slot = fn;
-}
-
-target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode,
- target_ulong *args)
-{
- sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
-
- if ((opcode <= MAX_HCALL_OPCODE)
- && ((opcode & 0x3) == 0)) {
- spapr_hcall_fn fn = papr_hypercall_table[opcode / 4];
-
- if (fn) {
- return fn(cpu, spapr, opcode, args);
- }
- } else if ((opcode >= KVMPPC_HCALL_BASE) &&
- (opcode <= KVMPPC_HCALL_MAX)) {
- spapr_hcall_fn fn = kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE];
-
- if (fn) {
- return fn(cpu, spapr, opcode, args);
- }
- }
-
- qemu_log_mask(LOG_UNIMP, "Unimplemented SPAPR hcall 0x" TARGET_FMT_lx "\n",
- opcode);
- return H_FUNCTION;
-}
-
-static void hypercall_register_types(void)
-{
- /* hcall-pft */
- spapr_register_hypercall(H_ENTER, h_enter);
- spapr_register_hypercall(H_REMOVE, h_remove);
- spapr_register_hypercall(H_PROTECT, h_protect);
- spapr_register_hypercall(H_READ, h_read);
-
- /* hcall-bulk */
- spapr_register_hypercall(H_BULK_REMOVE, h_bulk_remove);
-
- /* hcall-splpar */
- spapr_register_hypercall(H_REGISTER_VPA, h_register_vpa);
- spapr_register_hypercall(H_CEDE, h_cede);
-
- /* processor register resource access h-calls */
- spapr_register_hypercall(H_SET_SPRG0, h_set_sprg0);
- spapr_register_hypercall(H_SET_DABR, h_set_dabr);
- spapr_register_hypercall(H_SET_XDABR, h_set_xdabr);
- spapr_register_hypercall(H_PAGE_INIT, h_page_init);
- spapr_register_hypercall(H_SET_MODE, h_set_mode);
-
- /* "debugger" hcalls (also used by SLOF). Note: We do -not- differenciate
- * here between the "CI" and the "CACHE" variants, they will use whatever
- * mapping attributes qemu is using. When using KVM, the kernel will
- * enforce the attributes more strongly
- */
- spapr_register_hypercall(H_LOGICAL_CI_LOAD, h_logical_load);
- spapr_register_hypercall(H_LOGICAL_CI_STORE, h_logical_store);
- spapr_register_hypercall(H_LOGICAL_CACHE_LOAD, h_logical_load);
- spapr_register_hypercall(H_LOGICAL_CACHE_STORE, h_logical_store);
- spapr_register_hypercall(H_LOGICAL_ICBI, h_logical_icbi);
- spapr_register_hypercall(H_LOGICAL_DCBF, h_logical_dcbf);
- spapr_register_hypercall(KVMPPC_H_LOGICAL_MEMOP, h_logical_memop);
-
- /* qemu/KVM-PPC specific hcalls */
- spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas);
-
- /* ibm,client-architecture-support support */
- spapr_register_hypercall(KVMPPC_H_CAS, h_client_architecture_support);
-}
-
-type_init(hypercall_register_types)
diff --git a/qemu/hw/ppc/spapr_iommu.c b/qemu/hw/ppc/spapr_iommu.c
deleted file mode 100644
index 7dd458846..000000000
--- a/qemu/hw/ppc/spapr_iommu.c
+++ /dev/null
@@ -1,512 +0,0 @@
-/*
- * QEMU sPAPR IOMMU (TCE) code
- *
- * Copyright (c) 2010 David Gibson, IBM Corporation <dwg@au1.ibm.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "sysemu/kvm.h"
-#include "hw/qdev.h"
-#include "kvm_ppc.h"
-#include "sysemu/dma.h"
-#include "exec/address-spaces.h"
-#include "trace.h"
-
-#include "hw/ppc/spapr.h"
-#include "hw/ppc/spapr_vio.h"
-
-#include <libfdt.h>
-
-enum sPAPRTCEAccess {
- SPAPR_TCE_FAULT = 0,
- SPAPR_TCE_RO = 1,
- SPAPR_TCE_WO = 2,
- SPAPR_TCE_RW = 3,
-};
-
-#define IOMMU_PAGE_SIZE(shift) (1ULL << (shift))
-#define IOMMU_PAGE_MASK(shift) (~(IOMMU_PAGE_SIZE(shift) - 1))
-
-static QLIST_HEAD(spapr_tce_tables, sPAPRTCETable) spapr_tce_tables;
-
-sPAPRTCETable *spapr_tce_find_by_liobn(target_ulong liobn)
-{
- sPAPRTCETable *tcet;
-
- if (liobn & 0xFFFFFFFF00000000ULL) {
- hcall_dprintf("Request for out-of-bounds LIOBN 0x" TARGET_FMT_lx "\n",
- liobn);
- return NULL;
- }
-
- QLIST_FOREACH(tcet, &spapr_tce_tables, list) {
- if (tcet->liobn == (uint32_t)liobn) {
- return tcet;
- }
- }
-
- return NULL;
-}
-
-static IOMMUAccessFlags spapr_tce_iommu_access_flags(uint64_t tce)
-{
- switch (tce & SPAPR_TCE_RW) {
- case SPAPR_TCE_FAULT:
- return IOMMU_NONE;
- case SPAPR_TCE_RO:
- return IOMMU_RO;
- case SPAPR_TCE_WO:
- return IOMMU_WO;
- default: /* SPAPR_TCE_RW */
- return IOMMU_RW;
- }
-}
-
-/* Called from RCU critical section */
-static IOMMUTLBEntry spapr_tce_translate_iommu(MemoryRegion *iommu, hwaddr addr,
- bool is_write)
-{
- sPAPRTCETable *tcet = container_of(iommu, sPAPRTCETable, iommu);
- uint64_t tce;
- IOMMUTLBEntry ret = {
- .target_as = &address_space_memory,
- .iova = 0,
- .translated_addr = 0,
- .addr_mask = ~(hwaddr)0,
- .perm = IOMMU_NONE,
- };
-
- if ((addr >> tcet->page_shift) < tcet->nb_table) {
- /* Check if we are in bound */
- hwaddr page_mask = IOMMU_PAGE_MASK(tcet->page_shift);
-
- tce = tcet->table[addr >> tcet->page_shift];
- ret.iova = addr & page_mask;
- ret.translated_addr = tce & page_mask;
- ret.addr_mask = ~page_mask;
- ret.perm = spapr_tce_iommu_access_flags(tce);
- }
- trace_spapr_iommu_xlate(tcet->liobn, addr, ret.iova, ret.perm,
- ret.addr_mask);
-
- return ret;
-}
-
-static int spapr_tce_table_post_load(void *opaque, int version_id)
-{
- sPAPRTCETable *tcet = SPAPR_TCE_TABLE(opaque);
-
- if (tcet->vdev) {
- spapr_vio_set_bypass(tcet->vdev, tcet->bypass);
- }
-
- return 0;
-}
-
-static const VMStateDescription vmstate_spapr_tce_table = {
- .name = "spapr_iommu",
- .version_id = 2,
- .minimum_version_id = 2,
- .post_load = spapr_tce_table_post_load,
- .fields = (VMStateField []) {
- /* Sanity check */
- VMSTATE_UINT32_EQUAL(liobn, sPAPRTCETable),
- VMSTATE_UINT32_EQUAL(nb_table, sPAPRTCETable),
-
- /* IOMMU state */
- VMSTATE_BOOL(bypass, sPAPRTCETable),
- VMSTATE_VARRAY_UINT32(table, sPAPRTCETable, nb_table, 0, vmstate_info_uint64, uint64_t),
-
- VMSTATE_END_OF_LIST()
- },
-};
-
-static MemoryRegionIOMMUOps spapr_iommu_ops = {
- .translate = spapr_tce_translate_iommu,
-};
-
-static int spapr_tce_table_realize(DeviceState *dev)
-{
- sPAPRTCETable *tcet = SPAPR_TCE_TABLE(dev);
- uint64_t window_size = (uint64_t)tcet->nb_table << tcet->page_shift;
-
- if (kvm_enabled() && !(window_size >> 32)) {
- tcet->table = kvmppc_create_spapr_tce(tcet->liobn,
- window_size,
- &tcet->fd,
- tcet->need_vfio);
- }
-
- if (!tcet->table) {
- size_t table_size = tcet->nb_table * sizeof(uint64_t);
- tcet->table = g_malloc0(table_size);
- }
-
- trace_spapr_iommu_new_table(tcet->liobn, tcet, tcet->table, tcet->fd);
-
- memory_region_init_iommu(&tcet->iommu, OBJECT(dev), &spapr_iommu_ops,
- "iommu-spapr",
- (uint64_t)tcet->nb_table << tcet->page_shift);
-
- QLIST_INSERT_HEAD(&spapr_tce_tables, tcet, list);
-
- vmstate_register(DEVICE(tcet), tcet->liobn, &vmstate_spapr_tce_table,
- tcet);
-
- return 0;
-}
-
-void spapr_tce_set_need_vfio(sPAPRTCETable *tcet, bool need_vfio)
-{
- size_t table_size = tcet->nb_table * sizeof(uint64_t);
- void *newtable;
-
- if (need_vfio == tcet->need_vfio) {
- /* Nothing to do */
- return;
- }
-
- if (!need_vfio) {
- /* FIXME: We don't support transition back to KVM accelerated
- * TCEs yet */
- return;
- }
-
- tcet->need_vfio = true;
-
- if (tcet->fd < 0) {
- /* Table is already in userspace, nothing to be do */
- return;
- }
-
- newtable = g_malloc(table_size);
- memcpy(newtable, tcet->table, table_size);
-
- kvmppc_remove_spapr_tce(tcet->table, tcet->fd, tcet->nb_table);
-
- tcet->fd = -1;
- tcet->table = newtable;
-}
-
-sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn,
- uint64_t bus_offset,
- uint32_t page_shift,
- uint32_t nb_table,
- bool need_vfio)
-{
- sPAPRTCETable *tcet;
- char tmp[64];
-
- if (spapr_tce_find_by_liobn(liobn)) {
- fprintf(stderr, "Attempted to create TCE table with duplicate"
- " LIOBN 0x%x\n", liobn);
- return NULL;
- }
-
- if (!nb_table) {
- return NULL;
- }
-
- tcet = SPAPR_TCE_TABLE(object_new(TYPE_SPAPR_TCE_TABLE));
- tcet->liobn = liobn;
- tcet->bus_offset = bus_offset;
- tcet->page_shift = page_shift;
- tcet->nb_table = nb_table;
- tcet->need_vfio = need_vfio;
-
- snprintf(tmp, sizeof(tmp), "tce-table-%x", liobn);
- object_property_add_child(OBJECT(owner), tmp, OBJECT(tcet), NULL);
-
- object_property_set_bool(OBJECT(tcet), true, "realized", NULL);
-
- return tcet;
-}
-
-static void spapr_tce_table_unrealize(DeviceState *dev, Error **errp)
-{
- sPAPRTCETable *tcet = SPAPR_TCE_TABLE(dev);
-
- QLIST_REMOVE(tcet, list);
-
- if (!kvm_enabled() ||
- (kvmppc_remove_spapr_tce(tcet->table, tcet->fd,
- tcet->nb_table) != 0)) {
- g_free(tcet->table);
- }
-}
-
-MemoryRegion *spapr_tce_get_iommu(sPAPRTCETable *tcet)
-{
- return &tcet->iommu;
-}
-
-static void spapr_tce_reset(DeviceState *dev)
-{
- sPAPRTCETable *tcet = SPAPR_TCE_TABLE(dev);
- size_t table_size = tcet->nb_table * sizeof(uint64_t);
-
- memset(tcet->table, 0, table_size);
-}
-
-static target_ulong put_tce_emu(sPAPRTCETable *tcet, target_ulong ioba,
- target_ulong tce)
-{
- IOMMUTLBEntry entry;
- hwaddr page_mask = IOMMU_PAGE_MASK(tcet->page_shift);
- unsigned long index = (ioba - tcet->bus_offset) >> tcet->page_shift;
-
- if (index >= tcet->nb_table) {
- hcall_dprintf("spapr_vio_put_tce on out-of-bounds IOBA 0x"
- TARGET_FMT_lx "\n", ioba);
- return H_PARAMETER;
- }
-
- tcet->table[index] = tce;
-
- entry.target_as = &address_space_memory,
- entry.iova = ioba & page_mask;
- entry.translated_addr = tce & page_mask;
- entry.addr_mask = ~page_mask;
- entry.perm = spapr_tce_iommu_access_flags(tce);
- memory_region_notify_iommu(&tcet->iommu, entry);
-
- return H_SUCCESS;
-}
-
-static target_ulong h_put_tce_indirect(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- int i;
- target_ulong liobn = args[0];
- target_ulong ioba = args[1];
- target_ulong ioba1 = ioba;
- target_ulong tce_list = args[2];
- target_ulong npages = args[3];
- target_ulong ret = H_PARAMETER, tce = 0;
- sPAPRTCETable *tcet = spapr_tce_find_by_liobn(liobn);
- CPUState *cs = CPU(cpu);
- hwaddr page_mask, page_size;
-
- if (!tcet) {
- return H_PARAMETER;
- }
-
- if ((npages > 512) || (tce_list & SPAPR_TCE_PAGE_MASK)) {
- return H_PARAMETER;
- }
-
- page_mask = IOMMU_PAGE_MASK(tcet->page_shift);
- page_size = IOMMU_PAGE_SIZE(tcet->page_shift);
- ioba &= page_mask;
-
- for (i = 0; i < npages; ++i, ioba += page_size) {
- tce = ldq_be_phys(cs->as, tce_list + i * sizeof(target_ulong));
-
- ret = put_tce_emu(tcet, ioba, tce);
- if (ret) {
- break;
- }
- }
-
- /* Trace last successful or the first problematic entry */
- i = i ? (i - 1) : 0;
- if (SPAPR_IS_PCI_LIOBN(liobn)) {
- trace_spapr_iommu_pci_indirect(liobn, ioba1, tce_list, i, tce, ret);
- } else {
- trace_spapr_iommu_indirect(liobn, ioba1, tce_list, i, tce, ret);
- }
- return ret;
-}
-
-static target_ulong h_stuff_tce(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- int i;
- target_ulong liobn = args[0];
- target_ulong ioba = args[1];
- target_ulong tce_value = args[2];
- target_ulong npages = args[3];
- target_ulong ret = H_PARAMETER;
- sPAPRTCETable *tcet = spapr_tce_find_by_liobn(liobn);
- hwaddr page_mask, page_size;
-
- if (!tcet) {
- return H_PARAMETER;
- }
-
- if (npages > tcet->nb_table) {
- return H_PARAMETER;
- }
-
- page_mask = IOMMU_PAGE_MASK(tcet->page_shift);
- page_size = IOMMU_PAGE_SIZE(tcet->page_shift);
- ioba &= page_mask;
-
- for (i = 0; i < npages; ++i, ioba += page_size) {
- ret = put_tce_emu(tcet, ioba, tce_value);
- if (ret) {
- break;
- }
- }
- if (SPAPR_IS_PCI_LIOBN(liobn)) {
- trace_spapr_iommu_pci_stuff(liobn, ioba, tce_value, npages, ret);
- } else {
- trace_spapr_iommu_stuff(liobn, ioba, tce_value, npages, ret);
- }
-
- return ret;
-}
-
-static target_ulong h_put_tce(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- target_ulong liobn = args[0];
- target_ulong ioba = args[1];
- target_ulong tce = args[2];
- target_ulong ret = H_PARAMETER;
- sPAPRTCETable *tcet = spapr_tce_find_by_liobn(liobn);
-
- if (tcet) {
- hwaddr page_mask = IOMMU_PAGE_MASK(tcet->page_shift);
-
- ioba &= page_mask;
-
- ret = put_tce_emu(tcet, ioba, tce);
- }
- if (SPAPR_IS_PCI_LIOBN(liobn)) {
- trace_spapr_iommu_pci_put(liobn, ioba, tce, ret);
- } else {
- trace_spapr_iommu_put(liobn, ioba, tce, ret);
- }
-
- return ret;
-}
-
-static target_ulong get_tce_emu(sPAPRTCETable *tcet, target_ulong ioba,
- target_ulong *tce)
-{
- unsigned long index = (ioba - tcet->bus_offset) >> tcet->page_shift;
-
- if (index >= tcet->nb_table) {
- hcall_dprintf("spapr_iommu_get_tce on out-of-bounds IOBA 0x"
- TARGET_FMT_lx "\n", ioba);
- return H_PARAMETER;
- }
-
- *tce = tcet->table[index];
-
- return H_SUCCESS;
-}
-
-static target_ulong h_get_tce(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- target_ulong liobn = args[0];
- target_ulong ioba = args[1];
- target_ulong tce = 0;
- target_ulong ret = H_PARAMETER;
- sPAPRTCETable *tcet = spapr_tce_find_by_liobn(liobn);
-
- if (tcet) {
- hwaddr page_mask = IOMMU_PAGE_MASK(tcet->page_shift);
-
- ioba &= page_mask;
-
- ret = get_tce_emu(tcet, ioba, &tce);
- if (!ret) {
- args[0] = tce;
- }
- }
- if (SPAPR_IS_PCI_LIOBN(liobn)) {
- trace_spapr_iommu_pci_get(liobn, ioba, ret, tce);
- } else {
- trace_spapr_iommu_get(liobn, ioba, ret, tce);
- }
-
- return ret;
-}
-
-int spapr_dma_dt(void *fdt, int node_off, const char *propname,
- uint32_t liobn, uint64_t window, uint32_t size)
-{
- uint32_t dma_prop[5];
- int ret;
-
- dma_prop[0] = cpu_to_be32(liobn);
- dma_prop[1] = cpu_to_be32(window >> 32);
- dma_prop[2] = cpu_to_be32(window & 0xFFFFFFFF);
- dma_prop[3] = 0; /* window size is 32 bits */
- dma_prop[4] = cpu_to_be32(size);
-
- ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-address-cells", 2);
- if (ret < 0) {
- return ret;
- }
-
- ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-size-cells", 2);
- if (ret < 0) {
- return ret;
- }
-
- ret = fdt_setprop(fdt, node_off, propname, dma_prop, sizeof(dma_prop));
- if (ret < 0) {
- return ret;
- }
-
- return 0;
-}
-
-int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname,
- sPAPRTCETable *tcet)
-{
- if (!tcet) {
- return 0;
- }
-
- return spapr_dma_dt(fdt, node_off, propname,
- tcet->liobn, 0, tcet->nb_table << tcet->page_shift);
-}
-
-static void spapr_tce_table_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- dc->init = spapr_tce_table_realize;
- dc->reset = spapr_tce_reset;
- dc->unrealize = spapr_tce_table_unrealize;
-
- QLIST_INIT(&spapr_tce_tables);
-
- /* hcall-tce */
- spapr_register_hypercall(H_PUT_TCE, h_put_tce);
- spapr_register_hypercall(H_GET_TCE, h_get_tce);
- spapr_register_hypercall(H_PUT_TCE_INDIRECT, h_put_tce_indirect);
- spapr_register_hypercall(H_STUFF_TCE, h_stuff_tce);
-}
-
-static TypeInfo spapr_tce_table_info = {
- .name = TYPE_SPAPR_TCE_TABLE,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(sPAPRTCETable),
- .class_init = spapr_tce_table_class_init,
-};
-
-static void register_types(void)
-{
- type_register_static(&spapr_tce_table_info);
-}
-
-type_init(register_types);
diff --git a/qemu/hw/ppc/spapr_pci.c b/qemu/hw/ppc/spapr_pci.c
deleted file mode 100644
index 573e635bf..000000000
--- a/qemu/hw/ppc/spapr_pci.c
+++ /dev/null
@@ -1,1919 +0,0 @@
-/*
- * QEMU sPAPR PCI host originated from Uninorth PCI host
- *
- * Copyright (c) 2011 Alexey Kardashevskiy, IBM Corporation.
- * Copyright (C) 2011 David Gibson, IBM Corporation.
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/msi.h"
-#include "hw/pci/msix.h"
-#include "hw/pci/pci_host.h"
-#include "hw/ppc/spapr.h"
-#include "hw/pci-host/spapr.h"
-#include "exec/address-spaces.h"
-#include <libfdt.h>
-#include "trace.h"
-#include "qemu/error-report.h"
-#include "qapi/qmp/qerror.h"
-
-#include "hw/pci/pci_bridge.h"
-#include "hw/pci/pci_bus.h"
-#include "hw/ppc/spapr_drc.h"
-#include "sysemu/device_tree.h"
-
-#include "hw/vfio/vfio.h"
-
-/* Copied from the kernel arch/powerpc/platforms/pseries/msi.c */
-#define RTAS_QUERY_FN 0
-#define RTAS_CHANGE_FN 1
-#define RTAS_RESET_FN 2
-#define RTAS_CHANGE_MSI_FN 3
-#define RTAS_CHANGE_MSIX_FN 4
-
-/* Interrupt types to return on RTAS_CHANGE_* */
-#define RTAS_TYPE_MSI 1
-#define RTAS_TYPE_MSIX 2
-
-#define FDT_NAME_MAX 128
-
-#define _FDT(exp) \
- do { \
- int ret = (exp); \
- if (ret < 0) { \
- return ret; \
- } \
- } while (0)
-
-sPAPRPHBState *spapr_pci_find_phb(sPAPRMachineState *spapr, uint64_t buid)
-{
- sPAPRPHBState *sphb;
-
- QLIST_FOREACH(sphb, &spapr->phbs, list) {
- if (sphb->buid != buid) {
- continue;
- }
- return sphb;
- }
-
- return NULL;
-}
-
-PCIDevice *spapr_pci_find_dev(sPAPRMachineState *spapr, uint64_t buid,
- uint32_t config_addr)
-{
- sPAPRPHBState *sphb = spapr_pci_find_phb(spapr, buid);
- PCIHostState *phb = PCI_HOST_BRIDGE(sphb);
- int bus_num = (config_addr >> 16) & 0xFF;
- int devfn = (config_addr >> 8) & 0xFF;
-
- if (!phb) {
- return NULL;
- }
-
- return pci_find_device(phb->bus, bus_num, devfn);
-}
-
-static uint32_t rtas_pci_cfgaddr(uint32_t arg)
-{
- /* This handles the encoding of extended config space addresses */
- return ((arg >> 20) & 0xf00) | (arg & 0xff);
-}
-
-static void finish_read_pci_config(sPAPRMachineState *spapr, uint64_t buid,
- uint32_t addr, uint32_t size,
- target_ulong rets)
-{
- PCIDevice *pci_dev;
- uint32_t val;
-
- if ((size != 1) && (size != 2) && (size != 4)) {
- /* access must be 1, 2 or 4 bytes */
- rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
- return;
- }
-
- pci_dev = spapr_pci_find_dev(spapr, buid, addr);
- addr = rtas_pci_cfgaddr(addr);
-
- if (!pci_dev || (addr % size) || (addr >= pci_config_size(pci_dev))) {
- /* Access must be to a valid device, within bounds and
- * naturally aligned */
- rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
- return;
- }
-
- val = pci_host_config_read_common(pci_dev, addr,
- pci_config_size(pci_dev), size);
-
- rtas_st(rets, 0, RTAS_OUT_SUCCESS);
- rtas_st(rets, 1, val);
-}
-
-static void rtas_ibm_read_pci_config(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- uint32_t token, uint32_t nargs,
- target_ulong args,
- uint32_t nret, target_ulong rets)
-{
- uint64_t buid;
- uint32_t size, addr;
-
- if ((nargs != 4) || (nret != 2)) {
- rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
- return;
- }
-
- buid = rtas_ldq(args, 1);
- size = rtas_ld(args, 3);
- addr = rtas_ld(args, 0);
-
- finish_read_pci_config(spapr, buid, addr, size, rets);
-}
-
-static void rtas_read_pci_config(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- uint32_t token, uint32_t nargs,
- target_ulong args,
- uint32_t nret, target_ulong rets)
-{
- uint32_t size, addr;
-
- if ((nargs != 2) || (nret != 2)) {
- rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
- return;
- }
-
- size = rtas_ld(args, 1);
- addr = rtas_ld(args, 0);
-
- finish_read_pci_config(spapr, 0, addr, size, rets);
-}
-
-static void finish_write_pci_config(sPAPRMachineState *spapr, uint64_t buid,
- uint32_t addr, uint32_t size,
- uint32_t val, target_ulong rets)
-{
- PCIDevice *pci_dev;
-
- if ((size != 1) && (size != 2) && (size != 4)) {
- /* access must be 1, 2 or 4 bytes */
- rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
- return;
- }
-
- pci_dev = spapr_pci_find_dev(spapr, buid, addr);
- addr = rtas_pci_cfgaddr(addr);
-
- if (!pci_dev || (addr % size) || (addr >= pci_config_size(pci_dev))) {
- /* Access must be to a valid device, within bounds and
- * naturally aligned */
- rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
- return;
- }
-
- pci_host_config_write_common(pci_dev, addr, pci_config_size(pci_dev),
- val, size);
-
- rtas_st(rets, 0, RTAS_OUT_SUCCESS);
-}
-
-static void rtas_ibm_write_pci_config(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- uint32_t token, uint32_t nargs,
- target_ulong args,
- uint32_t nret, target_ulong rets)
-{
- uint64_t buid;
- uint32_t val, size, addr;
-
- if ((nargs != 5) || (nret != 1)) {
- rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
- return;
- }
-
- buid = rtas_ldq(args, 1);
- val = rtas_ld(args, 4);
- size = rtas_ld(args, 3);
- addr = rtas_ld(args, 0);
-
- finish_write_pci_config(spapr, buid, addr, size, val, rets);
-}
-
-static void rtas_write_pci_config(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- uint32_t token, uint32_t nargs,
- target_ulong args,
- uint32_t nret, target_ulong rets)
-{
- uint32_t val, size, addr;
-
- if ((nargs != 3) || (nret != 1)) {
- rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
- return;
- }
-
-
- val = rtas_ld(args, 2);
- size = rtas_ld(args, 1);
- addr = rtas_ld(args, 0);
-
- finish_write_pci_config(spapr, 0, addr, size, val, rets);
-}
-
-/*
- * Set MSI/MSIX message data.
- * This is required for msi_notify()/msix_notify() which
- * will write at the addresses via spapr_msi_write().
- *
- * If hwaddr == 0, all entries will have .data == first_irq i.e.
- * table will be reset.
- */
-static void spapr_msi_setmsg(PCIDevice *pdev, hwaddr addr, bool msix,
- unsigned first_irq, unsigned req_num)
-{
- unsigned i;
- MSIMessage msg = { .address = addr, .data = first_irq };
-
- if (!msix) {
- msi_set_message(pdev, msg);
- trace_spapr_pci_msi_setup(pdev->name, 0, msg.address);
- return;
- }
-
- for (i = 0; i < req_num; ++i) {
- msix_set_message(pdev, i, msg);
- trace_spapr_pci_msi_setup(pdev->name, i, msg.address);
- if (addr) {
- ++msg.data;
- }
- }
-}
-
-static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- uint32_t token, uint32_t nargs,
- target_ulong args, uint32_t nret,
- target_ulong rets)
-{
- uint32_t config_addr = rtas_ld(args, 0);
- uint64_t buid = rtas_ldq(args, 1);
- unsigned int func = rtas_ld(args, 3);
- unsigned int req_num = rtas_ld(args, 4); /* 0 == remove all */
- unsigned int seq_num = rtas_ld(args, 5);
- unsigned int ret_intr_type;
- unsigned int irq, max_irqs = 0;
- sPAPRPHBState *phb = NULL;
- PCIDevice *pdev = NULL;
- spapr_pci_msi *msi;
- int *config_addr_key;
- Error *err = NULL;
-
- switch (func) {
- case RTAS_CHANGE_MSI_FN:
- case RTAS_CHANGE_FN:
- ret_intr_type = RTAS_TYPE_MSI;
- break;
- case RTAS_CHANGE_MSIX_FN:
- ret_intr_type = RTAS_TYPE_MSIX;
- break;
- default:
- error_report("rtas_ibm_change_msi(%u) is not implemented", func);
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
- return;
- }
-
- /* Fins sPAPRPHBState */
- phb = spapr_pci_find_phb(spapr, buid);
- if (phb) {
- pdev = spapr_pci_find_dev(spapr, buid, config_addr);
- }
- if (!phb || !pdev) {
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
- return;
- }
-
- msi = (spapr_pci_msi *) g_hash_table_lookup(phb->msi, &config_addr);
-
- /* Releasing MSIs */
- if (!req_num) {
- if (!msi) {
- trace_spapr_pci_msi("Releasing wrong config", config_addr);
- rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
- return;
- }
-
- xics_free(spapr->icp, msi->first_irq, msi->num);
- if (msi_present(pdev)) {
- spapr_msi_setmsg(pdev, 0, false, 0, 0);
- }
- if (msix_present(pdev)) {
- spapr_msi_setmsg(pdev, 0, true, 0, 0);
- }
- g_hash_table_remove(phb->msi, &config_addr);
-
- trace_spapr_pci_msi("Released MSIs", config_addr);
- rtas_st(rets, 0, RTAS_OUT_SUCCESS);
- rtas_st(rets, 1, 0);
- return;
- }
-
- /* Enabling MSI */
-
- /* Check if the device supports as many IRQs as requested */
- if (ret_intr_type == RTAS_TYPE_MSI) {
- max_irqs = msi_nr_vectors_allocated(pdev);
- } else if (ret_intr_type == RTAS_TYPE_MSIX) {
- max_irqs = pdev->msix_entries_nr;
- }
- if (!max_irqs) {
- error_report("Requested interrupt type %d is not enabled for device %x",
- ret_intr_type, config_addr);
- rtas_st(rets, 0, -1); /* Hardware error */
- return;
- }
- /* Correct the number if the guest asked for too many */
- if (req_num > max_irqs) {
- trace_spapr_pci_msi_retry(config_addr, req_num, max_irqs);
- req_num = max_irqs;
- irq = 0; /* to avoid misleading trace */
- goto out;
- }
-
- /* Allocate MSIs */
- irq = xics_alloc_block(spapr->icp, 0, req_num, false,
- ret_intr_type == RTAS_TYPE_MSI, &err);
- if (err) {
- error_reportf_err(err, "Can't allocate MSIs for device %x: ",
- config_addr);
- rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
- return;
- }
-
- /* Release previous MSIs */
- if (msi) {
- xics_free(spapr->icp, msi->first_irq, msi->num);
- g_hash_table_remove(phb->msi, &config_addr);
- }
-
- /* Setup MSI/MSIX vectors in the device (via cfgspace or MSIX BAR) */
- spapr_msi_setmsg(pdev, SPAPR_PCI_MSI_WINDOW, ret_intr_type == RTAS_TYPE_MSIX,
- irq, req_num);
-
- /* Add MSI device to cache */
- msi = g_new(spapr_pci_msi, 1);
- msi->first_irq = irq;
- msi->num = req_num;
- config_addr_key = g_new(int, 1);
- *config_addr_key = config_addr;
- g_hash_table_insert(phb->msi, config_addr_key, msi);
-
-out:
- rtas_st(rets, 0, RTAS_OUT_SUCCESS);
- rtas_st(rets, 1, req_num);
- rtas_st(rets, 2, ++seq_num);
- if (nret > 3) {
- rtas_st(rets, 3, ret_intr_type);
- }
-
- trace_spapr_pci_rtas_ibm_change_msi(config_addr, func, req_num, irq);
-}
-
-static void rtas_ibm_query_interrupt_source_number(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
- uint32_t token,
- uint32_t nargs,
- target_ulong args,
- uint32_t nret,
- target_ulong rets)
-{
- uint32_t config_addr = rtas_ld(args, 0);
- uint64_t buid = rtas_ldq(args, 1);
- unsigned int intr_src_num = -1, ioa_intr_num = rtas_ld(args, 3);
- sPAPRPHBState *phb = NULL;
- PCIDevice *pdev = NULL;
- spapr_pci_msi *msi;
-
- /* Find sPAPRPHBState */
- phb = spapr_pci_find_phb(spapr, buid);
- if (phb) {
- pdev = spapr_pci_find_dev(spapr, buid, config_addr);
- }
- if (!phb || !pdev) {
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
- return;
- }
-
- /* Find device descriptor and start IRQ */
- msi = (spapr_pci_msi *) g_hash_table_lookup(phb->msi, &config_addr);
- if (!msi || !msi->first_irq || !msi->num || (ioa_intr_num >= msi->num)) {
- trace_spapr_pci_msi("Failed to return vector", config_addr);
- rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
- return;
- }
- intr_src_num = msi->first_irq + ioa_intr_num;
- trace_spapr_pci_rtas_ibm_query_interrupt_source_number(ioa_intr_num,
- intr_src_num);
-
- rtas_st(rets, 0, RTAS_OUT_SUCCESS);
- rtas_st(rets, 1, intr_src_num);
- rtas_st(rets, 2, 1);/* 0 == level; 1 == edge */
-}
-
-static void rtas_ibm_set_eeh_option(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
- uint32_t token, uint32_t nargs,
- target_ulong args, uint32_t nret,
- target_ulong rets)
-{
- sPAPRPHBState *sphb;
- uint32_t addr, option;
- uint64_t buid;
- int ret;
-
- if ((nargs != 4) || (nret != 1)) {
- goto param_error_exit;
- }
-
- buid = rtas_ldq(args, 1);
- addr = rtas_ld(args, 0);
- option = rtas_ld(args, 3);
-
- sphb = spapr_pci_find_phb(spapr, buid);
- if (!sphb) {
- goto param_error_exit;
- }
-
- if (!spapr_phb_eeh_available(sphb)) {
- goto param_error_exit;
- }
-
- ret = spapr_phb_vfio_eeh_set_option(sphb, addr, option);
- rtas_st(rets, 0, ret);
- return;
-
-param_error_exit:
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
-}
-
-static void rtas_ibm_get_config_addr_info2(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
- uint32_t token, uint32_t nargs,
- target_ulong args, uint32_t nret,
- target_ulong rets)
-{
- sPAPRPHBState *sphb;
- PCIDevice *pdev;
- uint32_t addr, option;
- uint64_t buid;
-
- if ((nargs != 4) || (nret != 2)) {
- goto param_error_exit;
- }
-
- buid = rtas_ldq(args, 1);
- sphb = spapr_pci_find_phb(spapr, buid);
- if (!sphb) {
- goto param_error_exit;
- }
-
- if (!spapr_phb_eeh_available(sphb)) {
- goto param_error_exit;
- }
-
- /*
- * We always have PE address of form "00BB0001". "BB"
- * represents the bus number of PE's primary bus.
- */
- option = rtas_ld(args, 3);
- switch (option) {
- case RTAS_GET_PE_ADDR:
- addr = rtas_ld(args, 0);
- pdev = spapr_pci_find_dev(spapr, buid, addr);
- if (!pdev) {
- goto param_error_exit;
- }
-
- rtas_st(rets, 1, (pci_bus_num(pdev->bus) << 16) + 1);
- break;
- case RTAS_GET_PE_MODE:
- rtas_st(rets, 1, RTAS_PE_MODE_SHARED);
- break;
- default:
- goto param_error_exit;
- }
-
- rtas_st(rets, 0, RTAS_OUT_SUCCESS);
- return;
-
-param_error_exit:
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
-}
-
-static void rtas_ibm_read_slot_reset_state2(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
- uint32_t token, uint32_t nargs,
- target_ulong args, uint32_t nret,
- target_ulong rets)
-{
- sPAPRPHBState *sphb;
- uint64_t buid;
- int state, ret;
-
- if ((nargs != 3) || (nret != 4 && nret != 5)) {
- goto param_error_exit;
- }
-
- buid = rtas_ldq(args, 1);
- sphb = spapr_pci_find_phb(spapr, buid);
- if (!sphb) {
- goto param_error_exit;
- }
-
- if (!spapr_phb_eeh_available(sphb)) {
- goto param_error_exit;
- }
-
- ret = spapr_phb_vfio_eeh_get_state(sphb, &state);
- rtas_st(rets, 0, ret);
- if (ret != RTAS_OUT_SUCCESS) {
- return;
- }
-
- rtas_st(rets, 1, state);
- rtas_st(rets, 2, RTAS_EEH_SUPPORT);
- rtas_st(rets, 3, RTAS_EEH_PE_UNAVAIL_INFO);
- if (nret >= 5) {
- rtas_st(rets, 4, RTAS_EEH_PE_RECOVER_INFO);
- }
- return;
-
-param_error_exit:
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
-}
-
-static void rtas_ibm_set_slot_reset(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
- uint32_t token, uint32_t nargs,
- target_ulong args, uint32_t nret,
- target_ulong rets)
-{
- sPAPRPHBState *sphb;
- uint32_t option;
- uint64_t buid;
- int ret;
-
- if ((nargs != 4) || (nret != 1)) {
- goto param_error_exit;
- }
-
- buid = rtas_ldq(args, 1);
- option = rtas_ld(args, 3);
- sphb = spapr_pci_find_phb(spapr, buid);
- if (!sphb) {
- goto param_error_exit;
- }
-
- if (!spapr_phb_eeh_available(sphb)) {
- goto param_error_exit;
- }
-
- ret = spapr_phb_vfio_eeh_reset(sphb, option);
- rtas_st(rets, 0, ret);
- return;
-
-param_error_exit:
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
-}
-
-static void rtas_ibm_configure_pe(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
- uint32_t token, uint32_t nargs,
- target_ulong args, uint32_t nret,
- target_ulong rets)
-{
- sPAPRPHBState *sphb;
- uint64_t buid;
- int ret;
-
- if ((nargs != 3) || (nret != 1)) {
- goto param_error_exit;
- }
-
- buid = rtas_ldq(args, 1);
- sphb = spapr_pci_find_phb(spapr, buid);
- if (!sphb) {
- goto param_error_exit;
- }
-
- if (!spapr_phb_eeh_available(sphb)) {
- goto param_error_exit;
- }
-
- ret = spapr_phb_vfio_eeh_configure(sphb);
- rtas_st(rets, 0, ret);
- return;
-
-param_error_exit:
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
-}
-
-/* To support it later */
-static void rtas_ibm_slot_error_detail(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
- uint32_t token, uint32_t nargs,
- target_ulong args, uint32_t nret,
- target_ulong rets)
-{
- sPAPRPHBState *sphb;
- int option;
- uint64_t buid;
-
- if ((nargs != 8) || (nret != 1)) {
- goto param_error_exit;
- }
-
- buid = rtas_ldq(args, 1);
- sphb = spapr_pci_find_phb(spapr, buid);
- if (!sphb) {
- goto param_error_exit;
- }
-
- if (!spapr_phb_eeh_available(sphb)) {
- goto param_error_exit;
- }
-
- option = rtas_ld(args, 7);
- switch (option) {
- case RTAS_SLOT_TEMP_ERR_LOG:
- case RTAS_SLOT_PERM_ERR_LOG:
- break;
- default:
- goto param_error_exit;
- }
-
- /* We don't have error log yet */
- rtas_st(rets, 0, RTAS_OUT_NO_ERRORS_FOUND);
- return;
-
-param_error_exit:
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
-}
-
-static int pci_spapr_swizzle(int slot, int pin)
-{
- return (slot + pin) % PCI_NUM_PINS;
-}
-
-static int pci_spapr_map_irq(PCIDevice *pci_dev, int irq_num)
-{
- /*
- * Here we need to convert pci_dev + irq_num to some unique value
- * which is less than number of IRQs on the specific bus (4). We
- * use standard PCI swizzling, that is (slot number + pin number)
- * % 4.
- */
- return pci_spapr_swizzle(PCI_SLOT(pci_dev->devfn), irq_num);
-}
-
-static void pci_spapr_set_irq(void *opaque, int irq_num, int level)
-{
- /*
- * Here we use the number returned by pci_spapr_map_irq to find a
- * corresponding qemu_irq.
- */
- sPAPRPHBState *phb = opaque;
-
- 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);
-}
-
-static PCIINTxRoute spapr_route_intx_pin_to_irq(void *opaque, int pin)
-{
- sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(opaque);
- PCIINTxRoute route;
-
- route.mode = PCI_INTX_ENABLED;
- route.irq = sphb->lsi_table[pin].irq;
-
- return route;
-}
-
-/*
- * MSI/MSIX memory region implementation.
- * The handler handles both MSI and MSIX.
- * For MSI-X, the vector number is encoded as a part of the address,
- * data is set to 0.
- * For MSI, the vector number is encoded in least bits in data.
- */
-static void spapr_msi_write(void *opaque, hwaddr addr,
- uint64_t data, unsigned size)
-{
- sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
- uint32_t irq = data;
-
- trace_spapr_pci_msi_write(addr, data, irq);
-
- qemu_irq_pulse(xics_get_qirq(spapr->icp, irq));
-}
-
-static const MemoryRegionOps spapr_msi_ops = {
- /* There is no .read as the read result is undefined by PCI spec */
- .read = NULL,
- .write = spapr_msi_write,
- .endianness = DEVICE_LITTLE_ENDIAN
-};
-
-/*
- * PHB PCI device
- */
-static AddressSpace *spapr_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
-{
- sPAPRPHBState *phb = opaque;
-
- return &phb->iommu_as;
-}
-
-static char *spapr_phb_vfio_get_loc_code(sPAPRPHBState *sphb, PCIDevice *pdev)
-{
- char *path = NULL, *buf = NULL, *host = NULL;
-
- /* Get the PCI VFIO host id */
- host = object_property_get_str(OBJECT(pdev), "host", NULL);
- if (!host) {
- goto err_out;
- }
-
- /* Construct the path of the file that will give us the DT location */
- path = g_strdup_printf("/sys/bus/pci/devices/%s/devspec", host);
- g_free(host);
- if (!path || !g_file_get_contents(path, &buf, NULL, NULL)) {
- goto err_out;
- }
- g_free(path);
-
- /* Construct and read from host device tree the loc-code */
- path = g_strdup_printf("/proc/device-tree%s/ibm,loc-code", buf);
- g_free(buf);
- if (!path || !g_file_get_contents(path, &buf, NULL, NULL)) {
- goto err_out;
- }
- return buf;
-
-err_out:
- g_free(path);
- return NULL;
-}
-
-static char *spapr_phb_get_loc_code(sPAPRPHBState *sphb, PCIDevice *pdev)
-{
- char *buf;
- const char *devtype = "qemu";
- uint32_t busnr = pci_bus_num(PCI_BUS(qdev_get_parent_bus(DEVICE(pdev))));
-
- if (object_dynamic_cast(OBJECT(pdev), "vfio-pci")) {
- buf = spapr_phb_vfio_get_loc_code(sphb, pdev);
- if (buf) {
- return buf;
- }
- devtype = "vfio";
- }
- /*
- * For emulated devices and VFIO-failure case, make up
- * the loc-code.
- */
- buf = g_strdup_printf("%s_%s:%04x:%02x:%02x.%x",
- devtype, pdev->name, sphb->index, busnr,
- PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
- return buf;
-}
-
-/* Macros to operate with address in OF binding to PCI */
-#define b_x(x, p, l) (((x) & ((1<<(l))-1)) << (p))
-#define b_n(x) b_x((x), 31, 1) /* 0 if relocatable */
-#define b_p(x) b_x((x), 30, 1) /* 1 if prefetchable */
-#define b_t(x) b_x((x), 29, 1) /* 1 if the address is aliased */
-#define b_ss(x) b_x((x), 24, 2) /* the space code */
-#define b_bbbbbbbb(x) b_x((x), 16, 8) /* bus number */
-#define b_ddddd(x) b_x((x), 11, 5) /* device number */
-#define b_fff(x) b_x((x), 8, 3) /* function number */
-#define b_rrrrrrrr(x) b_x((x), 0, 8) /* register number */
-
-/* for 'reg'/'assigned-addresses' OF properties */
-#define RESOURCE_CELLS_SIZE 2
-#define RESOURCE_CELLS_ADDRESS 3
-
-typedef struct ResourceFields {
- uint32_t phys_hi;
- uint32_t phys_mid;
- uint32_t phys_lo;
- uint32_t size_hi;
- uint32_t size_lo;
-} QEMU_PACKED ResourceFields;
-
-typedef struct ResourceProps {
- ResourceFields reg[8];
- ResourceFields assigned[7];
- uint32_t reg_len;
- uint32_t assigned_len;
-} ResourceProps;
-
-/* fill in the 'reg'/'assigned-resources' OF properties for
- * a PCI device. 'reg' describes resource requirements for a
- * device's IO/MEM regions, 'assigned-addresses' describes the
- * actual resource assignments.
- *
- * the properties are arrays of ('phys-addr', 'size') pairs describing
- * the addressable regions of the PCI device, where 'phys-addr' is a
- * RESOURCE_CELLS_ADDRESS-tuple of 32-bit integers corresponding to
- * (phys.hi, phys.mid, phys.lo), and 'size' is a
- * RESOURCE_CELLS_SIZE-tuple corresponding to (size.hi, size.lo).
- *
- * phys.hi = 0xYYXXXXZZ, where:
- * 0xYY = npt000ss
- * ||| |
- * ||| +-- space code
- * ||| |
- * ||| + 00 if configuration space
- * ||| + 01 if IO region,
- * ||| + 10 if 32-bit MEM region
- * ||| + 11 if 64-bit MEM region
- * |||
- * ||+------ for non-relocatable IO: 1 if aliased
- * || for relocatable IO: 1 if below 64KB
- * || for MEM: 1 if below 1MB
- * |+------- 1 if region is prefetchable
- * +-------- 1 if region is non-relocatable
- * 0xXXXX = bbbbbbbb dddddfff, encoding bus, slot, and function
- * bits respectively
- * 0xZZ = rrrrrrrr, the register number of the BAR corresponding
- * to the region
- *
- * phys.mid and phys.lo correspond respectively to the hi/lo portions
- * of the actual address of the region.
- *
- * how the phys-addr/size values are used differ slightly between
- * 'reg' and 'assigned-addresses' properties. namely, 'reg' has
- * an additional description for the config space region of the
- * device, and in the case of QEMU has n=0 and phys.mid=phys.lo=0
- * to describe the region as relocatable, with an address-mapping
- * that corresponds directly to the PHB's address space for the
- * resource. 'assigned-addresses' always has n=1 set with an absolute
- * address assigned for the resource. in general, 'assigned-addresses'
- * won't be populated, since addresses for PCI devices are generally
- * unmapped initially and left to the guest to assign.
- *
- * note also that addresses defined in these properties are, at least
- * for PAPR guests, relative to the PHBs IO/MEM windows, and
- * correspond directly to the addresses in the BARs.
- *
- * in accordance with PCI Bus Binding to Open Firmware,
- * IEEE Std 1275-1994, section 4.1.1, as implemented by PAPR+ v2.7,
- * Appendix C.
- */
-static void populate_resource_props(PCIDevice *d, ResourceProps *rp)
-{
- int bus_num = pci_bus_num(PCI_BUS(qdev_get_parent_bus(DEVICE(d))));
- uint32_t dev_id = (b_bbbbbbbb(bus_num) |
- b_ddddd(PCI_SLOT(d->devfn)) |
- b_fff(PCI_FUNC(d->devfn)));
- ResourceFields *reg, *assigned;
- int i, reg_idx = 0, assigned_idx = 0;
-
- /* config space region */
- reg = &rp->reg[reg_idx++];
- reg->phys_hi = cpu_to_be32(dev_id);
- reg->phys_mid = 0;
- reg->phys_lo = 0;
- reg->size_hi = 0;
- reg->size_lo = 0;
-
- for (i = 0; i < PCI_NUM_REGIONS; i++) {
- if (!d->io_regions[i].size) {
- continue;
- }
-
- reg = &rp->reg[reg_idx++];
-
- reg->phys_hi = cpu_to_be32(dev_id | b_rrrrrrrr(pci_bar(d, i)));
- if (d->io_regions[i].type & PCI_BASE_ADDRESS_SPACE_IO) {
- reg->phys_hi |= cpu_to_be32(b_ss(1));
- } else if (d->io_regions[i].type & PCI_BASE_ADDRESS_MEM_TYPE_64) {
- reg->phys_hi |= cpu_to_be32(b_ss(3));
- } else {
- reg->phys_hi |= cpu_to_be32(b_ss(2));
- }
- reg->phys_mid = 0;
- reg->phys_lo = 0;
- reg->size_hi = cpu_to_be32(d->io_regions[i].size >> 32);
- reg->size_lo = cpu_to_be32(d->io_regions[i].size);
-
- if (d->io_regions[i].addr == PCI_BAR_UNMAPPED) {
- continue;
- }
-
- assigned = &rp->assigned[assigned_idx++];
- assigned->phys_hi = cpu_to_be32(reg->phys_hi | b_n(1));
- assigned->phys_mid = cpu_to_be32(d->io_regions[i].addr >> 32);
- assigned->phys_lo = cpu_to_be32(d->io_regions[i].addr);
- assigned->size_hi = reg->size_hi;
- assigned->size_lo = reg->size_lo;
- }
-
- rp->reg_len = reg_idx * sizeof(ResourceFields);
- rp->assigned_len = assigned_idx * sizeof(ResourceFields);
-}
-
-static uint32_t spapr_phb_get_pci_drc_index(sPAPRPHBState *phb,
- PCIDevice *pdev);
-
-static int spapr_populate_pci_child_dt(PCIDevice *dev, void *fdt, int offset,
- sPAPRPHBState *sphb)
-{
- ResourceProps rp;
- bool is_bridge = false;
- int pci_status, err;
- char *buf = NULL;
- uint32_t drc_index = spapr_phb_get_pci_drc_index(sphb, dev);
- uint32_t max_msi, max_msix;
-
- if (pci_default_read_config(dev, PCI_HEADER_TYPE, 1) ==
- PCI_HEADER_TYPE_BRIDGE) {
- is_bridge = true;
- }
-
- /* in accordance with PAPR+ v2.7 13.6.3, Table 181 */
- _FDT(fdt_setprop_cell(fdt, offset, "vendor-id",
- pci_default_read_config(dev, PCI_VENDOR_ID, 2)));
- _FDT(fdt_setprop_cell(fdt, offset, "device-id",
- pci_default_read_config(dev, PCI_DEVICE_ID, 2)));
- _FDT(fdt_setprop_cell(fdt, offset, "revision-id",
- pci_default_read_config(dev, PCI_REVISION_ID, 1)));
- _FDT(fdt_setprop_cell(fdt, offset, "class-code",
- pci_default_read_config(dev, PCI_CLASS_PROG, 3)));
- if (pci_default_read_config(dev, PCI_INTERRUPT_PIN, 1)) {
- _FDT(fdt_setprop_cell(fdt, offset, "interrupts",
- pci_default_read_config(dev, PCI_INTERRUPT_PIN, 1)));
- }
-
- if (!is_bridge) {
- _FDT(fdt_setprop_cell(fdt, offset, "min-grant",
- pci_default_read_config(dev, PCI_MIN_GNT, 1)));
- _FDT(fdt_setprop_cell(fdt, offset, "max-latency",
- pci_default_read_config(dev, PCI_MAX_LAT, 1)));
- }
-
- if (pci_default_read_config(dev, PCI_SUBSYSTEM_ID, 2)) {
- _FDT(fdt_setprop_cell(fdt, offset, "subsystem-id",
- pci_default_read_config(dev, PCI_SUBSYSTEM_ID, 2)));
- }
-
- if (pci_default_read_config(dev, PCI_SUBSYSTEM_VENDOR_ID, 2)) {
- _FDT(fdt_setprop_cell(fdt, offset, "subsystem-vendor-id",
- pci_default_read_config(dev, PCI_SUBSYSTEM_VENDOR_ID, 2)));
- }
-
- _FDT(fdt_setprop_cell(fdt, offset, "cache-line-size",
- pci_default_read_config(dev, PCI_CACHE_LINE_SIZE, 1)));
-
- /* the following fdt cells are masked off the pci status register */
- pci_status = pci_default_read_config(dev, PCI_STATUS, 2);
- _FDT(fdt_setprop_cell(fdt, offset, "devsel-speed",
- PCI_STATUS_DEVSEL_MASK & pci_status));
-
- if (pci_status & PCI_STATUS_FAST_BACK) {
- _FDT(fdt_setprop(fdt, offset, "fast-back-to-back", NULL, 0));
- }
- if (pci_status & PCI_STATUS_66MHZ) {
- _FDT(fdt_setprop(fdt, offset, "66mhz-capable", NULL, 0));
- }
- if (pci_status & PCI_STATUS_UDF) {
- _FDT(fdt_setprop(fdt, offset, "udf-supported", NULL, 0));
- }
-
- /* NOTE: this is normally generated by firmware via path/unit name,
- * but in our case we must set it manually since it does not get
- * processed by OF beforehand
- */
- _FDT(fdt_setprop_string(fdt, offset, "name", "pci"));
- buf = spapr_phb_get_loc_code(sphb, dev);
- if (!buf) {
- error_report("Failed setting the ibm,loc-code");
- return -1;
- }
-
- err = fdt_setprop_string(fdt, offset, "ibm,loc-code", buf);
- g_free(buf);
- if (err < 0) {
- return err;
- }
-
- if (drc_index) {
- _FDT(fdt_setprop_cell(fdt, offset, "ibm,my-drc-index", drc_index));
- }
-
- _FDT(fdt_setprop_cell(fdt, offset, "#address-cells",
- RESOURCE_CELLS_ADDRESS));
- _FDT(fdt_setprop_cell(fdt, offset, "#size-cells",
- RESOURCE_CELLS_SIZE));
-
- max_msi = msi_nr_vectors_allocated(dev);
- if (max_msi) {
- _FDT(fdt_setprop_cell(fdt, offset, "ibm,req#msi", max_msi));
- }
- max_msix = dev->msix_entries_nr;
- if (max_msix) {
- _FDT(fdt_setprop_cell(fdt, offset, "ibm,req#msi-x", max_msix));
- }
-
- populate_resource_props(dev, &rp);
- _FDT(fdt_setprop(fdt, offset, "reg", (uint8_t *)rp.reg, rp.reg_len));
- _FDT(fdt_setprop(fdt, offset, "assigned-addresses",
- (uint8_t *)rp.assigned, rp.assigned_len));
-
- return 0;
-}
-
-/* create OF node for pci device and required OF DT properties */
-static int spapr_create_pci_child_dt(sPAPRPHBState *phb, PCIDevice *dev,
- void *fdt, int node_offset)
-{
- int offset, ret;
- int slot = PCI_SLOT(dev->devfn);
- int func = PCI_FUNC(dev->devfn);
- char nodename[FDT_NAME_MAX];
-
- if (func != 0) {
- snprintf(nodename, FDT_NAME_MAX, "pci@%x,%x", slot, func);
- } else {
- snprintf(nodename, FDT_NAME_MAX, "pci@%x", slot);
- }
- offset = fdt_add_subnode(fdt, node_offset, nodename);
- ret = spapr_populate_pci_child_dt(dev, fdt, offset, phb);
-
- g_assert(!ret);
- if (ret) {
- return 0;
- }
- return offset;
-}
-
-static void spapr_phb_add_pci_device(sPAPRDRConnector *drc,
- sPAPRPHBState *phb,
- PCIDevice *pdev,
- Error **errp)
-{
- sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
- DeviceState *dev = DEVICE(pdev);
- void *fdt = NULL;
- int fdt_start_offset = 0, fdt_size;
-
- if (object_dynamic_cast(OBJECT(pdev), "vfio-pci")) {
- sPAPRTCETable *tcet = spapr_tce_find_by_liobn(phb->dma_liobn);
-
- spapr_tce_set_need_vfio(tcet, true);
- }
-
- if (dev->hotplugged) {
- fdt = create_device_tree(&fdt_size);
- fdt_start_offset = spapr_create_pci_child_dt(phb, pdev, fdt, 0);
- if (!fdt_start_offset) {
- error_setg(errp, "Failed to create pci child device tree node");
- goto out;
- }
- }
-
- drck->attach(drc, DEVICE(pdev),
- fdt, fdt_start_offset, !dev->hotplugged, errp);
-out:
- if (*errp) {
- g_free(fdt);
- }
-}
-
-static void spapr_phb_remove_pci_device_cb(DeviceState *dev, void *opaque)
-{
- /* some version guests do not wait for completion of a device
- * cleanup (generally done asynchronously by the kernel) before
- * signaling to QEMU that the device is safe, but instead sleep
- * for some 'safe' period of time. unfortunately on a busy host
- * this sleep isn't guaranteed to be long enough, resulting in
- * bad things like IRQ lines being left asserted during final
- * device removal. to deal with this we call reset just prior
- * to finalizing the device, which will put the device back into
- * an 'idle' state, as the device cleanup code expects.
- */
- pci_device_reset(PCI_DEVICE(dev));
- object_unparent(OBJECT(dev));
-}
-
-static void spapr_phb_remove_pci_device(sPAPRDRConnector *drc,
- sPAPRPHBState *phb,
- PCIDevice *pdev,
- Error **errp)
-{
- sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
-
- drck->detach(drc, DEVICE(pdev), spapr_phb_remove_pci_device_cb, phb, errp);
-}
-
-static sPAPRDRConnector *spapr_phb_get_pci_func_drc(sPAPRPHBState *phb,
- uint32_t busnr,
- int32_t devfn)
-{
- return spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_PCI,
- (phb->index << 16) |
- (busnr << 8) |
- devfn);
-}
-
-static sPAPRDRConnector *spapr_phb_get_pci_drc(sPAPRPHBState *phb,
- PCIDevice *pdev)
-{
- uint32_t busnr = pci_bus_num(PCI_BUS(qdev_get_parent_bus(DEVICE(pdev))));
- return spapr_phb_get_pci_func_drc(phb, busnr, pdev->devfn);
-}
-
-static uint32_t spapr_phb_get_pci_drc_index(sPAPRPHBState *phb,
- PCIDevice *pdev)
-{
- sPAPRDRConnector *drc = spapr_phb_get_pci_drc(phb, pdev);
- sPAPRDRConnectorClass *drck;
-
- if (!drc) {
- return 0;
- }
-
- drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
- return drck->get_index(drc);
-}
-
-static void spapr_phb_hot_plug_child(HotplugHandler *plug_handler,
- DeviceState *plugged_dev, Error **errp)
-{
- sPAPRPHBState *phb = SPAPR_PCI_HOST_BRIDGE(DEVICE(plug_handler));
- PCIDevice *pdev = PCI_DEVICE(plugged_dev);
- sPAPRDRConnector *drc = spapr_phb_get_pci_drc(phb, pdev);
- Error *local_err = NULL;
- PCIBus *bus = PCI_BUS(qdev_get_parent_bus(DEVICE(pdev)));
- uint32_t slotnr = PCI_SLOT(pdev->devfn);
-
- /* if DR is disabled we don't need to do anything in the case of
- * hotplug or coldplug callbacks
- */
- if (!phb->dr_enabled) {
- /* if this is a hotplug operation initiated by the user
- * we need to let them know it's not enabled
- */
- if (plugged_dev->hotplugged) {
- error_setg(errp, QERR_BUS_NO_HOTPLUG,
- object_get_typename(OBJECT(phb)));
- }
- return;
- }
-
- g_assert(drc);
-
- /* Following the QEMU convention used for PCIe multifunction
- * hotplug, we do not allow functions to be hotplugged to a
- * slot that already has function 0 present
- */
- if (plugged_dev->hotplugged && bus->devices[PCI_DEVFN(slotnr, 0)] &&
- PCI_FUNC(pdev->devfn) != 0) {
- error_setg(errp, "PCI: slot %d function 0 already ocuppied by %s,"
- " additional functions can no longer be exposed to guest.",
- slotnr, bus->devices[PCI_DEVFN(slotnr, 0)]->name);
- return;
- }
-
- spapr_phb_add_pci_device(drc, phb, pdev, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- /* If this is function 0, signal hotplug for all the device functions.
- * Otherwise defer sending the hotplug event.
- */
- if (plugged_dev->hotplugged && PCI_FUNC(pdev->devfn) == 0) {
- int i;
-
- for (i = 0; i < 8; i++) {
- sPAPRDRConnector *func_drc;
- sPAPRDRConnectorClass *func_drck;
- sPAPRDREntitySense state;
-
- func_drc = spapr_phb_get_pci_func_drc(phb, pci_bus_num(bus),
- PCI_DEVFN(slotnr, i));
- func_drck = SPAPR_DR_CONNECTOR_GET_CLASS(func_drc);
- func_drck->entity_sense(func_drc, &state);
-
- if (state == SPAPR_DR_ENTITY_SENSE_PRESENT) {
- spapr_hotplug_req_add_by_index(func_drc);
- }
- }
- }
-}
-
-static void spapr_phb_hot_unplug_child(HotplugHandler *plug_handler,
- DeviceState *plugged_dev, Error **errp)
-{
- sPAPRPHBState *phb = SPAPR_PCI_HOST_BRIDGE(DEVICE(plug_handler));
- PCIDevice *pdev = PCI_DEVICE(plugged_dev);
- sPAPRDRConnectorClass *drck;
- sPAPRDRConnector *drc = spapr_phb_get_pci_drc(phb, pdev);
- Error *local_err = NULL;
-
- if (!phb->dr_enabled) {
- error_setg(errp, QERR_BUS_NO_HOTPLUG,
- object_get_typename(OBJECT(phb)));
- return;
- }
-
- g_assert(drc);
-
- drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
- if (!drck->release_pending(drc)) {
- PCIBus *bus = PCI_BUS(qdev_get_parent_bus(DEVICE(pdev)));
- uint32_t slotnr = PCI_SLOT(pdev->devfn);
- sPAPRDRConnector *func_drc;
- sPAPRDRConnectorClass *func_drck;
- sPAPRDREntitySense state;
- int i;
-
- /* ensure any other present functions are pending unplug */
- if (PCI_FUNC(pdev->devfn) == 0) {
- for (i = 1; i < 8; i++) {
- func_drc = spapr_phb_get_pci_func_drc(phb, pci_bus_num(bus),
- PCI_DEVFN(slotnr, i));
- func_drck = SPAPR_DR_CONNECTOR_GET_CLASS(func_drc);
- func_drck->entity_sense(func_drc, &state);
- if (state == SPAPR_DR_ENTITY_SENSE_PRESENT
- && !func_drck->release_pending(func_drc)) {
- error_setg(errp,
- "PCI: slot %d, function %d still present. "
- "Must unplug all non-0 functions first.",
- slotnr, i);
- return;
- }
- }
- }
-
- spapr_phb_remove_pci_device(drc, phb, pdev, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- /* if this isn't func 0, defer unplug event. otherwise signal removal
- * for all present functions
- */
- if (PCI_FUNC(pdev->devfn) == 0) {
- for (i = 7; i >= 0; i--) {
- func_drc = spapr_phb_get_pci_func_drc(phb, pci_bus_num(bus),
- PCI_DEVFN(slotnr, i));
- func_drck = SPAPR_DR_CONNECTOR_GET_CLASS(func_drc);
- func_drck->entity_sense(func_drc, &state);
- if (state == SPAPR_DR_ENTITY_SENSE_PRESENT) {
- spapr_hotplug_req_remove_by_index(func_drc);
- }
- }
- }
- }
-}
-
-static void spapr_phb_realize(DeviceState *dev, Error **errp)
-{
- sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
- SysBusDevice *s = SYS_BUS_DEVICE(dev);
- sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(s);
- PCIHostState *phb = PCI_HOST_BRIDGE(s);
- char *namebuf;
- int i;
- PCIBus *bus;
- uint64_t msi_window_size = 4096;
- sPAPRTCETable *tcet;
- uint32_t nb_table;
-
- if (sphb->index != (uint32_t)-1) {
- hwaddr windows_base;
-
- if ((sphb->buid != (uint64_t)-1) || (sphb->dma_liobn != (uint32_t)-1)
- || (sphb->mem_win_addr != (hwaddr)-1)
- || (sphb->io_win_addr != (hwaddr)-1)) {
- error_setg(errp, "Either \"index\" or other parameters must"
- " be specified for PAPR PHB, not both");
- return;
- }
-
- if (sphb->index > SPAPR_PCI_MAX_INDEX) {
- error_setg(errp, "\"index\" for PAPR PHB is too large (max %u)",
- SPAPR_PCI_MAX_INDEX);
- return;
- }
-
- sphb->buid = SPAPR_PCI_BASE_BUID + sphb->index;
- sphb->dma_liobn = SPAPR_PCI_LIOBN(sphb->index, 0);
-
- 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;
- }
-
- if (sphb->buid == (uint64_t)-1) {
- error_setg(errp, "BUID not specified for PHB");
- return;
- }
-
- if (sphb->dma_liobn == (uint32_t)-1) {
- error_setg(errp, "LIOBN not specified for PHB");
- return;
- }
-
- if (sphb->mem_win_addr == (hwaddr)-1) {
- error_setg(errp, "Memory window address not specified for PHB");
- return;
- }
-
- if (sphb->io_win_addr == (hwaddr)-1) {
- error_setg(errp, "IO window address not specified for PHB");
- return;
- }
-
- if (spapr_pci_find_phb(spapr, sphb->buid)) {
- error_setg(errp, "PCI host bridges must have unique BUIDs");
- return;
- }
-
- sphb->dtbusname = g_strdup_printf("pci@%" PRIx64, sphb->buid);
-
- namebuf = alloca(strlen(sphb->dtbusname) + 32);
-
- /* Initialize memory regions */
- sprintf(namebuf, "%s.mmio", sphb->dtbusname);
- memory_region_init(&sphb->memspace, OBJECT(sphb), namebuf, UINT64_MAX);
-
- sprintf(namebuf, "%s.mmio-alias", sphb->dtbusname);
- memory_region_init_alias(&sphb->memwindow, OBJECT(sphb),
- namebuf, &sphb->memspace,
- SPAPR_PCI_MEM_WIN_BUS_OFFSET, sphb->mem_win_size);
- memory_region_add_subregion(get_system_memory(), sphb->mem_win_addr,
- &sphb->memwindow);
-
- /* Initialize IO regions */
- sprintf(namebuf, "%s.io", sphb->dtbusname);
- memory_region_init(&sphb->iospace, OBJECT(sphb),
- namebuf, SPAPR_PCI_IO_WIN_SIZE);
-
- sprintf(namebuf, "%s.io-alias", sphb->dtbusname);
- memory_region_init_alias(&sphb->iowindow, OBJECT(sphb), namebuf,
- &sphb->iospace, 0, SPAPR_PCI_IO_WIN_SIZE);
- memory_region_add_subregion(get_system_memory(), sphb->io_win_addr,
- &sphb->iowindow);
-
- bus = pci_register_bus(dev, NULL,
- pci_spapr_set_irq, pci_spapr_map_irq, sphb,
- &sphb->memspace, &sphb->iospace,
- PCI_DEVFN(0, 0), PCI_NUM_PINS, TYPE_PCI_BUS);
- phb->bus = bus;
- qbus_set_hotplug_handler(BUS(phb->bus), DEVICE(sphb), NULL);
-
- /*
- * Initialize PHB address space.
- * By default there will be at least one subregion for default
- * 32bit DMA window.
- * Later the guest might want to create another DMA window
- * which will become another memory subregion.
- */
- sprintf(namebuf, "%s.iommu-root", sphb->dtbusname);
-
- memory_region_init(&sphb->iommu_root, OBJECT(sphb),
- namebuf, UINT64_MAX);
- address_space_init(&sphb->iommu_as, &sphb->iommu_root,
- sphb->dtbusname);
-
- /*
- * As MSI/MSIX interrupts trigger by writing at MSI/MSIX vectors,
- * we need to allocate some memory to catch those writes coming
- * from msi_notify()/msix_notify().
- * As MSIMessage:addr is going to be the same and MSIMessage:data
- * is going to be a VIRQ number, 4 bytes of the MSI MR will only
- * be used.
- *
- * For KVM we want to ensure that this memory is a full page so that
- * our memory slot is of page size granularity.
- */
-#ifdef CONFIG_KVM
- if (kvm_enabled()) {
- msi_window_size = getpagesize();
- }
-#endif
-
- memory_region_init_io(&sphb->msiwindow, NULL, &spapr_msi_ops, spapr,
- "msi", msi_window_size);
- memory_region_add_subregion(&sphb->iommu_root, SPAPR_PCI_MSI_WINDOW,
- &sphb->msiwindow);
-
- pci_setup_iommu(bus, spapr_pci_dma_iommu, sphb);
-
- pci_bus_set_route_irq_fn(bus, spapr_route_intx_pin_to_irq);
-
- QLIST_INSERT_HEAD(&spapr->phbs, sphb, list);
-
- /* Initialize the LSI table */
- for (i = 0; i < PCI_NUM_PINS; i++) {
- uint32_t irq;
- Error *local_err = NULL;
-
- irq = xics_alloc_block(spapr->icp, 0, 1, true, false, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- error_prepend(errp, "can't allocate LSIs: ");
- return;
- }
-
- sphb->lsi_table[i].irq = irq;
- }
-
- /* allocate connectors for child PCI devices */
- if (sphb->dr_enabled) {
- for (i = 0; i < PCI_SLOT_MAX * 8; i++) {
- spapr_dr_connector_new(OBJECT(phb),
- SPAPR_DR_CONNECTOR_TYPE_PCI,
- (sphb->index << 16) | i);
- }
- }
-
- nb_table = sphb->dma_win_size >> SPAPR_TCE_PAGE_SHIFT;
- tcet = spapr_tce_new_table(DEVICE(sphb), sphb->dma_liobn,
- 0, SPAPR_TCE_PAGE_SHIFT, nb_table, false);
- if (!tcet) {
- error_setg(errp, "Unable to create TCE table for %s",
- sphb->dtbusname);
- return;
- }
-
- /* Register default 32bit DMA window */
- memory_region_add_subregion(&sphb->iommu_root, sphb->dma_win_addr,
- spapr_tce_get_iommu(tcet));
-
- sphb->msi = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, g_free);
-}
-
-static int spapr_phb_children_reset(Object *child, void *opaque)
-{
- DeviceState *dev = (DeviceState *) object_dynamic_cast(child, TYPE_DEVICE);
-
- if (dev) {
- device_reset(dev);
- }
-
- return 0;
-}
-
-static void spapr_phb_reset(DeviceState *qdev)
-{
- /* Reset the IOMMU state */
- object_child_foreach(OBJECT(qdev), spapr_phb_children_reset, NULL);
-
- if (spapr_phb_eeh_available(SPAPR_PCI_HOST_BRIDGE(qdev))) {
- spapr_phb_vfio_reset(qdev);
- }
-}
-
-static Property spapr_phb_properties[] = {
- DEFINE_PROP_UINT32("index", sPAPRPHBState, index, -1),
- DEFINE_PROP_UINT64("buid", sPAPRPHBState, buid, -1),
- DEFINE_PROP_UINT32("liobn", sPAPRPHBState, dma_liobn, -1),
- DEFINE_PROP_UINT64("mem_win_addr", sPAPRPHBState, mem_win_addr, -1),
- DEFINE_PROP_UINT64("mem_win_size", sPAPRPHBState, mem_win_size,
- SPAPR_PCI_MMIO_WIN_SIZE),
- DEFINE_PROP_UINT64("io_win_addr", sPAPRPHBState, io_win_addr, -1),
- DEFINE_PROP_UINT64("io_win_size", sPAPRPHBState, io_win_size,
- SPAPR_PCI_IO_WIN_SIZE),
- DEFINE_PROP_BOOL("dynamic-reconfiguration", sPAPRPHBState, dr_enabled,
- true),
- /* Default DMA window is 0..1GB */
- DEFINE_PROP_UINT64("dma_win_addr", sPAPRPHBState, dma_win_addr, 0),
- DEFINE_PROP_UINT64("dma_win_size", sPAPRPHBState, dma_win_size, 0x40000000),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static const VMStateDescription vmstate_spapr_pci_lsi = {
- .name = "spapr_pci/lsi",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_EQUAL(irq, struct spapr_pci_lsi),
-
- VMSTATE_END_OF_LIST()
- },
-};
-
-static const VMStateDescription vmstate_spapr_pci_msi = {
- .name = "spapr_pci/msi",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField []) {
- VMSTATE_UINT32(key, spapr_pci_msi_mig),
- VMSTATE_UINT32(value.first_irq, spapr_pci_msi_mig),
- VMSTATE_UINT32(value.num, spapr_pci_msi_mig),
- VMSTATE_END_OF_LIST()
- },
-};
-
-static void spapr_pci_pre_save(void *opaque)
-{
- sPAPRPHBState *sphb = opaque;
- GHashTableIter iter;
- gpointer key, value;
- int i;
-
- g_free(sphb->msi_devs);
- sphb->msi_devs = NULL;
- sphb->msi_devs_num = g_hash_table_size(sphb->msi);
- if (!sphb->msi_devs_num) {
- return;
- }
- sphb->msi_devs = g_malloc(sphb->msi_devs_num * sizeof(spapr_pci_msi_mig));
-
- g_hash_table_iter_init(&iter, sphb->msi);
- for (i = 0; g_hash_table_iter_next(&iter, &key, &value); ++i) {
- sphb->msi_devs[i].key = *(uint32_t *) key;
- sphb->msi_devs[i].value = *(spapr_pci_msi *) value;
- }
-}
-
-static int spapr_pci_post_load(void *opaque, int version_id)
-{
- sPAPRPHBState *sphb = opaque;
- gpointer key, value;
- int i;
-
- for (i = 0; i < sphb->msi_devs_num; ++i) {
- key = g_memdup(&sphb->msi_devs[i].key,
- sizeof(sphb->msi_devs[i].key));
- value = g_memdup(&sphb->msi_devs[i].value,
- sizeof(sphb->msi_devs[i].value));
- g_hash_table_insert(sphb->msi, key, value);
- }
- g_free(sphb->msi_devs);
- sphb->msi_devs = NULL;
- sphb->msi_devs_num = 0;
-
- return 0;
-}
-
-static const VMStateDescription vmstate_spapr_pci = {
- .name = "spapr_pci",
- .version_id = 2,
- .minimum_version_id = 2,
- .pre_save = spapr_pci_pre_save,
- .post_load = spapr_pci_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT64_EQUAL(buid, sPAPRPHBState),
- VMSTATE_UINT32_EQUAL(dma_liobn, sPAPRPHBState),
- VMSTATE_UINT64_EQUAL(mem_win_addr, sPAPRPHBState),
- VMSTATE_UINT64_EQUAL(mem_win_size, sPAPRPHBState),
- VMSTATE_UINT64_EQUAL(io_win_addr, sPAPRPHBState),
- VMSTATE_UINT64_EQUAL(io_win_size, sPAPRPHBState),
- VMSTATE_STRUCT_ARRAY(lsi_table, sPAPRPHBState, PCI_NUM_PINS, 0,
- vmstate_spapr_pci_lsi, struct spapr_pci_lsi),
- VMSTATE_INT32(msi_devs_num, sPAPRPHBState),
- VMSTATE_STRUCT_VARRAY_ALLOC(msi_devs, sPAPRPHBState, msi_devs_num, 0,
- vmstate_spapr_pci_msi, spapr_pci_msi_mig),
- VMSTATE_END_OF_LIST()
- },
-};
-
-static const char *spapr_phb_root_bus_path(PCIHostState *host_bridge,
- PCIBus *rootbus)
-{
- sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(host_bridge);
-
- return sphb->dtbusname;
-}
-
-static void spapr_phb_class_init(ObjectClass *klass, void *data)
-{
- PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
- HotplugHandlerClass *hp = HOTPLUG_HANDLER_CLASS(klass);
-
- hc->root_bus_path = spapr_phb_root_bus_path;
- dc->realize = spapr_phb_realize;
- dc->props = spapr_phb_properties;
- dc->reset = spapr_phb_reset;
- dc->vmsd = &vmstate_spapr_pci;
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
- dc->cannot_instantiate_with_device_add_yet = false;
- hp->plug = spapr_phb_hot_plug_child;
- hp->unplug = spapr_phb_hot_unplug_child;
-}
-
-static const TypeInfo spapr_phb_info = {
- .name = TYPE_SPAPR_PCI_HOST_BRIDGE,
- .parent = TYPE_PCI_HOST_BRIDGE,
- .instance_size = sizeof(sPAPRPHBState),
- .class_init = spapr_phb_class_init,
- .interfaces = (InterfaceInfo[]) {
- { TYPE_HOTPLUG_HANDLER },
- { }
- }
-};
-
-PCIHostState *spapr_create_phb(sPAPRMachineState *spapr, int index)
-{
- DeviceState *dev;
-
- dev = qdev_create(NULL, TYPE_SPAPR_PCI_HOST_BRIDGE);
- qdev_prop_set_uint32(dev, "index", index);
- qdev_init_nofail(dev);
-
- return PCI_HOST_BRIDGE(dev);
-}
-
-typedef struct sPAPRFDT {
- void *fdt;
- int node_off;
- sPAPRPHBState *sphb;
-} sPAPRFDT;
-
-static void spapr_populate_pci_devices_dt(PCIBus *bus, PCIDevice *pdev,
- void *opaque)
-{
- PCIBus *sec_bus;
- sPAPRFDT *p = opaque;
- int offset;
- sPAPRFDT s_fdt;
-
- offset = spapr_create_pci_child_dt(p->sphb, pdev, p->fdt, p->node_off);
- if (!offset) {
- error_report("Failed to create pci child device tree node");
- return;
- }
-
- if ((pci_default_read_config(pdev, PCI_HEADER_TYPE, 1) !=
- PCI_HEADER_TYPE_BRIDGE)) {
- return;
- }
-
- sec_bus = pci_bridge_get_sec_bus(PCI_BRIDGE(pdev));
- if (!sec_bus) {
- return;
- }
-
- s_fdt.fdt = p->fdt;
- s_fdt.node_off = offset;
- s_fdt.sphb = p->sphb;
- pci_for_each_device(sec_bus, pci_bus_num(sec_bus),
- spapr_populate_pci_devices_dt,
- &s_fdt);
-}
-
-static void spapr_phb_pci_enumerate_bridge(PCIBus *bus, PCIDevice *pdev,
- void *opaque)
-{
- unsigned int *bus_no = opaque;
- unsigned int primary = *bus_no;
- unsigned int subordinate = 0xff;
- PCIBus *sec_bus = NULL;
-
- if ((pci_default_read_config(pdev, PCI_HEADER_TYPE, 1) !=
- PCI_HEADER_TYPE_BRIDGE)) {
- return;
- }
-
- (*bus_no)++;
- pci_default_write_config(pdev, PCI_PRIMARY_BUS, primary, 1);
- pci_default_write_config(pdev, PCI_SECONDARY_BUS, *bus_no, 1);
- pci_default_write_config(pdev, PCI_SUBORDINATE_BUS, *bus_no, 1);
-
- sec_bus = pci_bridge_get_sec_bus(PCI_BRIDGE(pdev));
- if (!sec_bus) {
- return;
- }
-
- pci_default_write_config(pdev, PCI_SUBORDINATE_BUS, subordinate, 1);
- pci_for_each_device(sec_bus, pci_bus_num(sec_bus),
- spapr_phb_pci_enumerate_bridge, bus_no);
- pci_default_write_config(pdev, PCI_SUBORDINATE_BUS, *bus_no, 1);
-}
-
-static void spapr_phb_pci_enumerate(sPAPRPHBState *phb)
-{
- PCIBus *bus = PCI_HOST_BRIDGE(phb)->bus;
- unsigned int bus_no = 0;
-
- pci_for_each_device(bus, pci_bus_num(bus),
- spapr_phb_pci_enumerate_bridge,
- &bus_no);
-
-}
-
-int spapr_populate_pci_dt(sPAPRPHBState *phb,
- uint32_t xics_phandle,
- void *fdt)
-{
- int bus_off, i, j, ret;
- char nodename[FDT_NAME_MAX];
- uint32_t bus_range[] = { cpu_to_be32(0), cpu_to_be32(0xff) };
- const uint64_t mmiosize = memory_region_size(&phb->memwindow);
- const uint64_t w32max = (1ULL << 32) - SPAPR_PCI_MEM_WIN_BUS_OFFSET;
- const uint64_t w32size = MIN(w32max, mmiosize);
- const uint64_t w64size = (mmiosize > w32size) ? (mmiosize - w32size) : 0;
- struct {
- uint32_t hi;
- uint64_t child;
- uint64_t parent;
- uint64_t size;
- } QEMU_PACKED ranges[] = {
- {
- cpu_to_be32(b_ss(1)), cpu_to_be64(0),
- cpu_to_be64(phb->io_win_addr),
- cpu_to_be64(memory_region_size(&phb->iospace)),
- },
- {
- cpu_to_be32(b_ss(2)), cpu_to_be64(SPAPR_PCI_MEM_WIN_BUS_OFFSET),
- cpu_to_be64(phb->mem_win_addr),
- cpu_to_be64(w32size),
- },
- {
- cpu_to_be32(b_ss(3)), cpu_to_be64(1ULL << 32),
- cpu_to_be64(phb->mem_win_addr + w32size),
- cpu_to_be64(w64size)
- },
- };
- const unsigned sizeof_ranges = (w64size ? 3 : 2) * sizeof(ranges[0]);
- uint64_t bus_reg[] = { cpu_to_be64(phb->buid), 0 };
- uint32_t interrupt_map_mask[] = {
- cpu_to_be32(b_ddddd(-1)|b_fff(0)), 0x0, 0x0, cpu_to_be32(-1)};
- uint32_t interrupt_map[PCI_SLOT_MAX * PCI_NUM_PINS][7];
- sPAPRTCETable *tcet;
- PCIBus *bus = PCI_HOST_BRIDGE(phb)->bus;
- sPAPRFDT s_fdt;
-
- /* Start populating the FDT */
- snprintf(nodename, FDT_NAME_MAX, "pci@%" PRIx64, phb->buid);
- bus_off = fdt_add_subnode(fdt, 0, nodename);
- if (bus_off < 0) {
- return bus_off;
- }
-
- /* Write PHB properties */
- _FDT(fdt_setprop_string(fdt, bus_off, "device_type", "pci"));
- _FDT(fdt_setprop_string(fdt, bus_off, "compatible", "IBM,Logical_PHB"));
- _FDT(fdt_setprop_cell(fdt, bus_off, "#address-cells", 0x3));
- _FDT(fdt_setprop_cell(fdt, bus_off, "#size-cells", 0x2));
- _FDT(fdt_setprop_cell(fdt, bus_off, "#interrupt-cells", 0x1));
- _FDT(fdt_setprop(fdt, bus_off, "used-by-rtas", NULL, 0));
- _FDT(fdt_setprop(fdt, bus_off, "bus-range", &bus_range, sizeof(bus_range)));
- _FDT(fdt_setprop(fdt, bus_off, "ranges", &ranges, sizeof_ranges));
- _FDT(fdt_setprop(fdt, bus_off, "reg", &bus_reg, sizeof(bus_reg)));
- _FDT(fdt_setprop_cell(fdt, bus_off, "ibm,pci-config-space-type", 0x1));
- _FDT(fdt_setprop_cell(fdt, bus_off, "ibm,pe-total-#msi", XICS_IRQS));
-
- /* Build the interrupt-map, this must matches what is done
- * in pci_spapr_map_irq
- */
- _FDT(fdt_setprop(fdt, bus_off, "interrupt-map-mask",
- &interrupt_map_mask, sizeof(interrupt_map_mask)));
- for (i = 0; i < PCI_SLOT_MAX; i++) {
- for (j = 0; j < PCI_NUM_PINS; j++) {
- uint32_t *irqmap = interrupt_map[i*PCI_NUM_PINS + j];
- int lsi_num = pci_spapr_swizzle(i, j);
-
- irqmap[0] = cpu_to_be32(b_ddddd(i)|b_fff(0));
- irqmap[1] = 0;
- irqmap[2] = 0;
- irqmap[3] = cpu_to_be32(j+1);
- irqmap[4] = cpu_to_be32(xics_phandle);
- irqmap[5] = cpu_to_be32(phb->lsi_table[lsi_num].irq);
- irqmap[6] = cpu_to_be32(0x8);
- }
- }
- /* Write interrupt map */
- _FDT(fdt_setprop(fdt, bus_off, "interrupt-map", &interrupt_map,
- sizeof(interrupt_map)));
-
- tcet = spapr_tce_find_by_liobn(SPAPR_PCI_LIOBN(phb->index, 0));
- if (!tcet) {
- return -1;
- }
- spapr_dma_dt(fdt, bus_off, "ibm,dma-window",
- tcet->liobn, tcet->bus_offset,
- tcet->nb_table << tcet->page_shift);
-
- /* Walk the bridges and program the bus numbers*/
- spapr_phb_pci_enumerate(phb);
- _FDT(fdt_setprop_cell(fdt, bus_off, "qemu,phb-enumerated", 0x1));
-
- /* Populate tree nodes with PCI devices attached */
- s_fdt.fdt = fdt;
- s_fdt.node_off = bus_off;
- s_fdt.sphb = phb;
- pci_for_each_device(bus, pci_bus_num(bus),
- spapr_populate_pci_devices_dt,
- &s_fdt);
-
- ret = spapr_drc_populate_dt(fdt, bus_off, OBJECT(phb),
- SPAPR_DR_CONNECTOR_TYPE_PCI);
- if (ret) {
- return ret;
- }
-
- return 0;
-}
-
-void spapr_pci_rtas_init(void)
-{
- spapr_rtas_register(RTAS_READ_PCI_CONFIG, "read-pci-config",
- rtas_read_pci_config);
- spapr_rtas_register(RTAS_WRITE_PCI_CONFIG, "write-pci-config",
- rtas_write_pci_config);
- spapr_rtas_register(RTAS_IBM_READ_PCI_CONFIG, "ibm,read-pci-config",
- rtas_ibm_read_pci_config);
- spapr_rtas_register(RTAS_IBM_WRITE_PCI_CONFIG, "ibm,write-pci-config",
- rtas_ibm_write_pci_config);
- if (msi_nonbroken) {
- spapr_rtas_register(RTAS_IBM_QUERY_INTERRUPT_SOURCE_NUMBER,
- "ibm,query-interrupt-source-number",
- rtas_ibm_query_interrupt_source_number);
- spapr_rtas_register(RTAS_IBM_CHANGE_MSI, "ibm,change-msi",
- rtas_ibm_change_msi);
- }
-
- spapr_rtas_register(RTAS_IBM_SET_EEH_OPTION,
- "ibm,set-eeh-option",
- rtas_ibm_set_eeh_option);
- spapr_rtas_register(RTAS_IBM_GET_CONFIG_ADDR_INFO2,
- "ibm,get-config-addr-info2",
- rtas_ibm_get_config_addr_info2);
- spapr_rtas_register(RTAS_IBM_READ_SLOT_RESET_STATE2,
- "ibm,read-slot-reset-state2",
- rtas_ibm_read_slot_reset_state2);
- spapr_rtas_register(RTAS_IBM_SET_SLOT_RESET,
- "ibm,set-slot-reset",
- rtas_ibm_set_slot_reset);
- spapr_rtas_register(RTAS_IBM_CONFIGURE_PE,
- "ibm,configure-pe",
- rtas_ibm_configure_pe);
- spapr_rtas_register(RTAS_IBM_SLOT_ERROR_DETAIL,
- "ibm,slot-error-detail",
- rtas_ibm_slot_error_detail);
-}
-
-static void spapr_pci_register_types(void)
-{
- type_register_static(&spapr_phb_info);
-}
-
-type_init(spapr_pci_register_types)
-
-static int spapr_switch_one_vga(DeviceState *dev, void *opaque)
-{
- bool be = *(bool *)opaque;
-
- if (object_dynamic_cast(OBJECT(dev), "VGA")
- || object_dynamic_cast(OBJECT(dev), "secondary-vga")) {
- object_property_set_bool(OBJECT(dev), be, "big-endian-framebuffer",
- &error_abort);
- }
- return 0;
-}
-
-void spapr_pci_switch_vga(bool big_endian)
-{
- sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
- sPAPRPHBState *sphb;
-
- /*
- * For backward compatibility with existing guests, we switch
- * the endianness of the VGA controller when changing the guest
- * interrupt mode
- */
- QLIST_FOREACH(sphb, &spapr->phbs, list) {
- BusState *bus = &PCI_HOST_BRIDGE(sphb)->bus->qbus;
- qbus_walk_children(bus, spapr_switch_one_vga, NULL, NULL, NULL,
- &big_endian);
- }
-}
diff --git a/qemu/hw/ppc/spapr_pci_vfio.c b/qemu/hw/ppc/spapr_pci_vfio.c
deleted file mode 100644
index cbd3d23c9..000000000
--- a/qemu/hw/ppc/spapr_pci_vfio.c
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * QEMU sPAPR PCI host for VFIO
- *
- * Copyright (c) 2011-2014 Alexey Kardashevskiy, IBM Corporation.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License,
- * or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/ppc/spapr.h"
-#include "hw/pci-host/spapr.h"
-#include "hw/pci/msix.h"
-#include "linux/vfio.h"
-#include "hw/vfio/vfio.h"
-#include "qemu/error-report.h"
-
-#define TYPE_SPAPR_PCI_VFIO_HOST_BRIDGE "spapr-pci-vfio-host-bridge"
-
-#define SPAPR_PCI_VFIO_HOST_BRIDGE(obj) \
- OBJECT_CHECK(sPAPRPHBVFIOState, (obj), TYPE_SPAPR_PCI_VFIO_HOST_BRIDGE)
-
-typedef struct sPAPRPHBVFIOState sPAPRPHBVFIOState;
-
-struct sPAPRPHBVFIOState {
- sPAPRPHBState phb;
-
- int32_t iommugroupid;
-};
-
-static Property spapr_phb_vfio_properties[] = {
- DEFINE_PROP_INT32("iommu", sPAPRPHBVFIOState, iommugroupid, -1),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void spapr_phb_vfio_instance_init(Object *obj)
-{
- error_report("spapr-pci-vfio-host-bridge is deprecated");
-}
-
-bool spapr_phb_eeh_available(sPAPRPHBState *sphb)
-{
- return vfio_eeh_as_ok(&sphb->iommu_as);
-}
-
-static void spapr_phb_vfio_eeh_reenable(sPAPRPHBState *sphb)
-{
- vfio_eeh_as_op(&sphb->iommu_as, VFIO_EEH_PE_ENABLE);
-}
-
-void spapr_phb_vfio_reset(DeviceState *qdev)
-{
- /*
- * The PE might be in frozen state. To reenable the EEH
- * functionality on it will clean the frozen state, which
- * ensures that the contained PCI devices will work properly
- * after reboot.
- */
- spapr_phb_vfio_eeh_reenable(SPAPR_PCI_HOST_BRIDGE(qdev));
-}
-
-int spapr_phb_vfio_eeh_set_option(sPAPRPHBState *sphb,
- unsigned int addr, int option)
-{
- uint32_t op;
- int ret;
-
- switch (option) {
- case RTAS_EEH_DISABLE:
- op = VFIO_EEH_PE_DISABLE;
- break;
- case RTAS_EEH_ENABLE: {
- PCIHostState *phb;
- PCIDevice *pdev;
-
- /*
- * The EEH functionality is enabled on basis of PCI device,
- * instead of PE. We need check the validity of the PCI
- * device address.
- */
- phb = PCI_HOST_BRIDGE(sphb);
- pdev = pci_find_device(phb->bus,
- (addr >> 16) & 0xFF, (addr >> 8) & 0xFF);
- if (!pdev || !object_dynamic_cast(OBJECT(pdev), "vfio-pci")) {
- return RTAS_OUT_PARAM_ERROR;
- }
-
- op = VFIO_EEH_PE_ENABLE;
- break;
- }
- case RTAS_EEH_THAW_IO:
- op = VFIO_EEH_PE_UNFREEZE_IO;
- break;
- case RTAS_EEH_THAW_DMA:
- op = VFIO_EEH_PE_UNFREEZE_DMA;
- break;
- default:
- return RTAS_OUT_PARAM_ERROR;
- }
-
- ret = vfio_eeh_as_op(&sphb->iommu_as, op);
- if (ret < 0) {
- return RTAS_OUT_HW_ERROR;
- }
-
- return RTAS_OUT_SUCCESS;
-}
-
-int spapr_phb_vfio_eeh_get_state(sPAPRPHBState *sphb, int *state)
-{
- int ret;
-
- ret = vfio_eeh_as_op(&sphb->iommu_as, VFIO_EEH_PE_GET_STATE);
- if (ret < 0) {
- return RTAS_OUT_PARAM_ERROR;
- }
-
- *state = ret;
- return RTAS_OUT_SUCCESS;
-}
-
-static void spapr_phb_vfio_eeh_clear_dev_msix(PCIBus *bus,
- PCIDevice *pdev,
- void *opaque)
-{
- /* Check if the device is VFIO PCI device */
- if (!object_dynamic_cast(OBJECT(pdev), "vfio-pci")) {
- return;
- }
-
- /*
- * The MSIx table will be cleaned out by reset. We need
- * disable it so that it can be reenabled properly. Also,
- * the cached MSIx table should be cleared as it's not
- * reflecting the contents in hardware.
- */
- if (msix_enabled(pdev)) {
- uint16_t flags;
-
- flags = pci_host_config_read_common(pdev,
- pdev->msix_cap + PCI_MSIX_FLAGS,
- pci_config_size(pdev), 2);
- flags &= ~PCI_MSIX_FLAGS_ENABLE;
- pci_host_config_write_common(pdev,
- pdev->msix_cap + PCI_MSIX_FLAGS,
- pci_config_size(pdev), flags, 2);
- }
-
- msix_reset(pdev);
-}
-
-static void spapr_phb_vfio_eeh_clear_bus_msix(PCIBus *bus, void *opaque)
-{
- pci_for_each_device(bus, pci_bus_num(bus),
- spapr_phb_vfio_eeh_clear_dev_msix, NULL);
-}
-
-static void spapr_phb_vfio_eeh_pre_reset(sPAPRPHBState *sphb)
-{
- PCIHostState *phb = PCI_HOST_BRIDGE(sphb);
-
- pci_for_each_bus(phb->bus, spapr_phb_vfio_eeh_clear_bus_msix, NULL);
-}
-
-int spapr_phb_vfio_eeh_reset(sPAPRPHBState *sphb, int option)
-{
- uint32_t op;
- int ret;
-
- switch (option) {
- case RTAS_SLOT_RESET_DEACTIVATE:
- op = VFIO_EEH_PE_RESET_DEACTIVATE;
- break;
- case RTAS_SLOT_RESET_HOT:
- spapr_phb_vfio_eeh_pre_reset(sphb);
- op = VFIO_EEH_PE_RESET_HOT;
- break;
- case RTAS_SLOT_RESET_FUNDAMENTAL:
- spapr_phb_vfio_eeh_pre_reset(sphb);
- op = VFIO_EEH_PE_RESET_FUNDAMENTAL;
- break;
- default:
- return RTAS_OUT_PARAM_ERROR;
- }
-
- ret = vfio_eeh_as_op(&sphb->iommu_as, op);
- if (ret < 0) {
- return RTAS_OUT_HW_ERROR;
- }
-
- return RTAS_OUT_SUCCESS;
-}
-
-int spapr_phb_vfio_eeh_configure(sPAPRPHBState *sphb)
-{
- int ret;
-
- ret = vfio_eeh_as_op(&sphb->iommu_as, VFIO_EEH_PE_CONFIGURE);
- if (ret < 0) {
- return RTAS_OUT_PARAM_ERROR;
- }
-
- return RTAS_OUT_SUCCESS;
-}
-
-static void spapr_phb_vfio_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->props = spapr_phb_vfio_properties;
-}
-
-static const TypeInfo spapr_phb_vfio_info = {
- .name = TYPE_SPAPR_PCI_VFIO_HOST_BRIDGE,
- .parent = TYPE_SPAPR_PCI_HOST_BRIDGE,
- .instance_size = sizeof(sPAPRPHBVFIOState),
- .instance_init = spapr_phb_vfio_instance_init,
- .class_init = spapr_phb_vfio_class_init,
-};
-
-static void spapr_pci_vfio_register_types(void)
-{
- type_register_static(&spapr_phb_vfio_info);
-}
-
-type_init(spapr_pci_vfio_register_types)
diff --git a/qemu/hw/ppc/spapr_rng.c b/qemu/hw/ppc/spapr_rng.c
deleted file mode 100644
index 80515eb54..000000000
--- a/qemu/hw/ppc/spapr_rng.c
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * QEMU sPAPR random number generator "device" for H_RANDOM hypercall
- *
- * Copyright 2015 Thomas Huth, Red Hat Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License,
- * or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "qemu/error-report.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/device_tree.h"
-#include "sysemu/rng.h"
-#include "hw/ppc/spapr.h"
-#include "kvm_ppc.h"
-
-#define SPAPR_RNG(obj) \
- OBJECT_CHECK(sPAPRRngState, (obj), TYPE_SPAPR_RNG)
-
-struct sPAPRRngState {
- /*< private >*/
- DeviceState ds;
- RngBackend *backend;
- bool use_kvm;
-};
-typedef struct sPAPRRngState sPAPRRngState;
-
-struct HRandomData {
- QemuSemaphore sem;
- union {
- uint64_t v64;
- uint8_t v8[8];
- } val;
- int received;
-};
-typedef struct HRandomData HRandomData;
-
-/* Callback function for the RngBackend */
-static void random_recv(void *dest, const void *src, size_t size)
-{
- HRandomData *hrdp = dest;
-
- if (src && size > 0) {
- assert(size + hrdp->received <= sizeof(hrdp->val.v8));
- memcpy(&hrdp->val.v8[hrdp->received], src, size);
- hrdp->received += size;
- }
-
- qemu_sem_post(&hrdp->sem);
-}
-
-/* Handler for the H_RANDOM hypercall */
-static target_ulong h_random(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- sPAPRRngState *rngstate;
- HRandomData hrdata;
-
- rngstate = SPAPR_RNG(object_resolve_path_type("", TYPE_SPAPR_RNG, NULL));
-
- if (!rngstate || !rngstate->backend) {
- return H_HARDWARE;
- }
-
- qemu_sem_init(&hrdata.sem, 0);
- hrdata.val.v64 = 0;
- hrdata.received = 0;
-
- while (hrdata.received < 8) {
- rng_backend_request_entropy(rngstate->backend, 8 - hrdata.received,
- random_recv, &hrdata);
- qemu_mutex_unlock_iothread();
- qemu_sem_wait(&hrdata.sem);
- qemu_mutex_lock_iothread();
- }
-
- qemu_sem_destroy(&hrdata.sem);
- args[0] = hrdata.val.v64;
-
- return H_SUCCESS;
-}
-
-static void spapr_rng_instance_init(Object *obj)
-{
- sPAPRRngState *rngstate = SPAPR_RNG(obj);
-
- if (object_resolve_path_type("", TYPE_SPAPR_RNG, NULL) != NULL) {
- error_report("spapr-rng can not be instantiated twice!");
- return;
- }
-
- object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
- (Object **)&rngstate->backend,
- object_property_allow_set_link,
- OBJ_PROP_LINK_UNREF_ON_RELEASE, NULL);
- object_property_set_description(obj, "rng",
- "ID of the random number generator backend",
- NULL);
-}
-
-static void spapr_rng_realize(DeviceState *dev, Error **errp)
-{
-
- sPAPRRngState *rngstate = SPAPR_RNG(dev);
-
- if (rngstate->use_kvm) {
- if (kvmppc_enable_hwrng() == 0) {
- return;
- }
- /*
- * If user specified both, use-kvm and a backend, we fall back to
- * the backend now. If not, provide an appropriate error message.
- */
- if (!rngstate->backend) {
- error_setg(errp, "Could not initialize in-kernel H_RANDOM call!");
- return;
- }
- }
-
- if (rngstate->backend) {
- spapr_register_hypercall(H_RANDOM, h_random);
- } else {
- error_setg(errp, "spapr-rng needs an RNG backend!");
- }
-}
-
-int spapr_rng_populate_dt(void *fdt)
-{
- int node;
- int ret;
-
- node = qemu_fdt_add_subnode(fdt, "/ibm,platform-facilities");
- if (node <= 0) {
- return -1;
- }
- ret = fdt_setprop_string(fdt, node, "device_type",
- "ibm,platform-facilities");
- ret |= fdt_setprop_cell(fdt, node, "#address-cells", 0x1);
- ret |= fdt_setprop_cell(fdt, node, "#size-cells", 0x0);
-
- node = fdt_add_subnode(fdt, node, "ibm,random-v1");
- if (node <= 0) {
- return -1;
- }
- ret |= fdt_setprop_string(fdt, node, "compatible", "ibm,random");
-
- return ret ? -1 : 0;
-}
-
-static Property spapr_rng_properties[] = {
- DEFINE_PROP_BOOL("use-kvm", sPAPRRngState, use_kvm, false),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void spapr_rng_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- dc->realize = spapr_rng_realize;
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- dc->props = spapr_rng_properties;
- dc->hotpluggable = false;
-}
-
-static const TypeInfo spapr_rng_info = {
- .name = TYPE_SPAPR_RNG,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(sPAPRRngState),
- .instance_init = spapr_rng_instance_init,
- .class_init = spapr_rng_class_init,
-};
-
-static void spapr_rng_register_type(void)
-{
- type_register_static(&spapr_rng_info);
-}
-type_init(spapr_rng_register_type)
diff --git a/qemu/hw/ppc/spapr_rtas.c b/qemu/hw/ppc/spapr_rtas.c
deleted file mode 100644
index f07325831..000000000
--- a/qemu/hw/ppc/spapr_rtas.c
+++ /dev/null
@@ -1,785 +0,0 @@
-/*
- * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
- *
- * Hypercall based emulated RTAS
- *
- * Copyright (c) 2010-2011 David Gibson, IBM Corporation.
- *
- * 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.
- *
- */
-#include "qemu/osdep.h"
-#include "cpu.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/char.h"
-#include "hw/qdev.h"
-#include "sysemu/device_tree.h"
-#include "sysemu/cpus.h"
-
-#include "hw/ppc/spapr.h"
-#include "hw/ppc/spapr_vio.h"
-#include "qapi-event.h"
-#include "hw/boards.h"
-
-#include <libfdt.h>
-#include "hw/ppc/spapr_drc.h"
-#include "qemu/cutils.h"
-
-/* #define DEBUG_SPAPR */
-
-#ifdef DEBUG_SPAPR
-#define DPRINTF(fmt, ...) \
- do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) \
- do { } while (0)
-#endif
-
-static sPAPRConfigureConnectorState *spapr_ccs_find(sPAPRMachineState *spapr,
- uint32_t drc_index)
-{
- sPAPRConfigureConnectorState *ccs = NULL;
-
- QTAILQ_FOREACH(ccs, &spapr->ccs_list, next) {
- if (ccs->drc_index == drc_index) {
- break;
- }
- }
-
- return ccs;
-}
-
-static void spapr_ccs_add(sPAPRMachineState *spapr,
- sPAPRConfigureConnectorState *ccs)
-{
- g_assert(!spapr_ccs_find(spapr, ccs->drc_index));
- QTAILQ_INSERT_HEAD(&spapr->ccs_list, ccs, next);
-}
-
-static void spapr_ccs_remove(sPAPRMachineState *spapr,
- sPAPRConfigureConnectorState *ccs)
-{
- QTAILQ_REMOVE(&spapr->ccs_list, ccs, next);
- g_free(ccs);
-}
-
-void spapr_ccs_reset_hook(void *opaque)
-{
- sPAPRMachineState *spapr = opaque;
- sPAPRConfigureConnectorState *ccs, *ccs_tmp;
-
- QTAILQ_FOREACH_SAFE(ccs, &spapr->ccs_list, next, ccs_tmp) {
- spapr_ccs_remove(spapr, ccs);
- }
-}
-
-static void rtas_display_character(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- uint32_t token, uint32_t nargs,
- target_ulong args,
- uint32_t nret, target_ulong rets)
-{
- uint8_t c = rtas_ld(args, 0);
- VIOsPAPRDevice *sdev = vty_lookup(spapr, 0);
-
- if (!sdev) {
- rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
- } else {
- vty_putchars(sdev, &c, sizeof(c));
- rtas_st(rets, 0, RTAS_OUT_SUCCESS);
- }
-}
-
-static void rtas_power_off(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- uint32_t token, uint32_t nargs, target_ulong args,
- uint32_t nret, target_ulong rets)
-{
- if (nargs != 2 || nret != 1) {
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
- return;
- }
- qemu_system_shutdown_request();
- cpu_stop_current();
- rtas_st(rets, 0, RTAS_OUT_SUCCESS);
-}
-
-static void rtas_system_reboot(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- uint32_t token, uint32_t nargs,
- target_ulong args,
- uint32_t nret, target_ulong rets)
-{
- if (nargs != 0 || nret != 1) {
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
- return;
- }
- qemu_system_reset_request();
- rtas_st(rets, 0, RTAS_OUT_SUCCESS);
-}
-
-static void rtas_query_cpu_stopped_state(PowerPCCPU *cpu_,
- sPAPRMachineState *spapr,
- uint32_t token, uint32_t nargs,
- target_ulong args,
- uint32_t nret, target_ulong rets)
-{
- target_ulong id;
- PowerPCCPU *cpu;
-
- if (nargs != 1 || nret != 2) {
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
- return;
- }
-
- id = rtas_ld(args, 0);
- cpu = ppc_get_vcpu_by_dt_id(id);
- if (cpu != NULL) {
- if (CPU(cpu)->halted) {
- rtas_st(rets, 1, 0);
- } else {
- rtas_st(rets, 1, 2);
- }
-
- rtas_st(rets, 0, RTAS_OUT_SUCCESS);
- return;
- }
-
- /* Didn't find a matching cpu */
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
-}
-
-static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPRMachineState *spapr,
- uint32_t token, uint32_t nargs,
- target_ulong args,
- uint32_t nret, target_ulong rets)
-{
- target_ulong id, start, r3;
- PowerPCCPU *cpu;
-
- if (nargs != 3 || nret != 1) {
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
- return;
- }
-
- id = rtas_ld(args, 0);
- start = rtas_ld(args, 1);
- r3 = rtas_ld(args, 2);
-
- cpu = ppc_get_vcpu_by_dt_id(id);
- if (cpu != NULL) {
- CPUState *cs = CPU(cpu);
- CPUPPCState *env = &cpu->env;
-
- if (!cs->halted) {
- rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
- return;
- }
-
- /* This will make sure qemu state is up to date with kvm, and
- * mark it dirty so our changes get flushed back before the
- * new cpu enters */
- kvm_cpu_synchronize_state(cs);
-
- env->msr = (1ULL << MSR_SF) | (1ULL << MSR_ME);
- env->nip = start;
- env->gpr[3] = r3;
- cs->halted = 0;
-
- qemu_cpu_kick(cs);
-
- rtas_st(rets, 0, RTAS_OUT_SUCCESS);
- return;
- }
-
- /* Didn't find a matching cpu */
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
-}
-
-static void rtas_stop_self(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- uint32_t token, uint32_t nargs,
- target_ulong args,
- uint32_t nret, target_ulong rets)
-{
- CPUState *cs = CPU(cpu);
- CPUPPCState *env = &cpu->env;
-
- cs->halted = 1;
- qemu_cpu_kick(cs);
- /*
- * While stopping a CPU, the guest calls H_CPPR which
- * effectively disables interrupts on XICS level.
- * However decrementer interrupts in TCG can still
- * wake the CPU up so here we disable interrupts in MSR
- * as well.
- * As rtas_start_cpu() resets the whole MSR anyway, there is
- * no need to bother with specific bits, we just clear it.
- */
- env->msr = 0;
-}
-
-static inline int sysparm_st(target_ulong addr, target_ulong len,
- const void *val, uint16_t vallen)
-{
- hwaddr phys = ppc64_phys_to_real(addr);
-
- if (len < 2) {
- return RTAS_OUT_SYSPARM_PARAM_ERROR;
- }
- stw_be_phys(&address_space_memory, phys, vallen);
- cpu_physical_memory_write(phys + 2, val, MIN(len - 2, vallen));
- return RTAS_OUT_SUCCESS;
-}
-
-static void rtas_ibm_get_system_parameter(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
- uint32_t token, uint32_t nargs,
- target_ulong args,
- uint32_t nret, target_ulong rets)
-{
- target_ulong parameter = rtas_ld(args, 0);
- target_ulong buffer = rtas_ld(args, 1);
- target_ulong length = rtas_ld(args, 2);
- target_ulong ret;
-
- switch (parameter) {
- case RTAS_SYSPARM_SPLPAR_CHARACTERISTICS: {
- char *param_val = g_strdup_printf("MaxEntCap=%d,"
- "DesMem=%llu,"
- "DesProcs=%d,"
- "MaxPlatProcs=%d",
- max_cpus,
- current_machine->ram_size / M_BYTE,
- smp_cpus,
- max_cpus);
- ret = sysparm_st(buffer, length, param_val, strlen(param_val) + 1);
- g_free(param_val);
- break;
- }
- case RTAS_SYSPARM_DIAGNOSTICS_RUN_MODE: {
- uint8_t param_val = DIAGNOSTICS_RUN_MODE_DISABLED;
-
- ret = sysparm_st(buffer, length, &param_val, sizeof(param_val));
- break;
- }
- case RTAS_SYSPARM_UUID:
- ret = sysparm_st(buffer, length, qemu_uuid, (qemu_uuid_set ? 16 : 0));
- break;
- default:
- ret = RTAS_OUT_NOT_SUPPORTED;
- }
-
- rtas_st(rets, 0, ret);
-}
-
-static void rtas_ibm_set_system_parameter(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
- uint32_t token, uint32_t nargs,
- target_ulong args,
- uint32_t nret, target_ulong rets)
-{
- target_ulong parameter = rtas_ld(args, 0);
- target_ulong ret = RTAS_OUT_NOT_SUPPORTED;
-
- switch (parameter) {
- case RTAS_SYSPARM_SPLPAR_CHARACTERISTICS:
- case RTAS_SYSPARM_DIAGNOSTICS_RUN_MODE:
- case RTAS_SYSPARM_UUID:
- ret = RTAS_OUT_NOT_AUTHORIZED;
- break;
- }
-
- rtas_st(rets, 0, ret);
-}
-
-static void rtas_ibm_os_term(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
- uint32_t token, uint32_t nargs,
- target_ulong args,
- uint32_t nret, target_ulong rets)
-{
- target_ulong ret = 0;
-
- qapi_event_send_guest_panicked(GUEST_PANIC_ACTION_PAUSE, &error_abort);
-
- rtas_st(rets, 0, ret);
-}
-
-static void rtas_set_power_level(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- uint32_t token, uint32_t nargs,
- target_ulong args, uint32_t nret,
- target_ulong rets)
-{
- int32_t power_domain;
-
- if (nargs != 2 || nret != 2) {
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
- return;
- }
-
- /* we currently only use a single, "live insert" powerdomain for
- * hotplugged/dlpar'd resources, so the power is always live/full (100)
- */
- power_domain = rtas_ld(args, 0);
- if (power_domain != -1) {
- rtas_st(rets, 0, RTAS_OUT_NOT_SUPPORTED);
- return;
- }
-
- rtas_st(rets, 0, RTAS_OUT_SUCCESS);
- rtas_st(rets, 1, 100);
-}
-
-static void rtas_get_power_level(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- uint32_t token, uint32_t nargs,
- target_ulong args, uint32_t nret,
- target_ulong rets)
-{
- int32_t power_domain;
-
- if (nargs != 1 || nret != 2) {
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
- return;
- }
-
- /* we currently only use a single, "live insert" powerdomain for
- * hotplugged/dlpar'd resources, so the power is always live/full (100)
- */
- power_domain = rtas_ld(args, 0);
- if (power_domain != -1) {
- rtas_st(rets, 0, RTAS_OUT_NOT_SUPPORTED);
- return;
- }
-
- rtas_st(rets, 0, RTAS_OUT_SUCCESS);
- rtas_st(rets, 1, 100);
-}
-
-static bool sensor_type_is_dr(uint32_t sensor_type)
-{
- switch (sensor_type) {
- case RTAS_SENSOR_TYPE_ISOLATION_STATE:
- case RTAS_SENSOR_TYPE_DR:
- case RTAS_SENSOR_TYPE_ALLOCATION_STATE:
- return true;
- }
-
- return false;
-}
-
-static void rtas_set_indicator(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- uint32_t token, uint32_t nargs,
- target_ulong args, uint32_t nret,
- target_ulong rets)
-{
- uint32_t sensor_type;
- uint32_t sensor_index;
- uint32_t sensor_state;
- uint32_t ret = RTAS_OUT_SUCCESS;
- sPAPRDRConnector *drc;
- sPAPRDRConnectorClass *drck;
-
- if (nargs != 3 || nret != 1) {
- ret = RTAS_OUT_PARAM_ERROR;
- goto out;
- }
-
- sensor_type = rtas_ld(args, 0);
- sensor_index = rtas_ld(args, 1);
- sensor_state = rtas_ld(args, 2);
-
- if (!sensor_type_is_dr(sensor_type)) {
- goto out_unimplemented;
- }
-
- /* if this is a DR sensor we can assume sensor_index == drc_index */
- drc = spapr_dr_connector_by_index(sensor_index);
- if (!drc) {
- DPRINTF("rtas_set_indicator: invalid sensor/DRC index: %xh\n",
- sensor_index);
- ret = RTAS_OUT_PARAM_ERROR;
- goto out;
- }
- drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
-
- switch (sensor_type) {
- case RTAS_SENSOR_TYPE_ISOLATION_STATE:
- /* if the guest is configuring a device attached to this
- * DRC, we should reset the configuration state at this
- * point since it may no longer be reliable (guest released
- * device and needs to start over, or unplug occurred so
- * the FDT is no longer valid)
- */
- if (sensor_state == SPAPR_DR_ISOLATION_STATE_ISOLATED) {
- sPAPRConfigureConnectorState *ccs = spapr_ccs_find(spapr,
- sensor_index);
- if (ccs) {
- spapr_ccs_remove(spapr, ccs);
- }
- }
- ret = drck->set_isolation_state(drc, sensor_state);
- break;
- case RTAS_SENSOR_TYPE_DR:
- ret = drck->set_indicator_state(drc, sensor_state);
- break;
- case RTAS_SENSOR_TYPE_ALLOCATION_STATE:
- ret = drck->set_allocation_state(drc, sensor_state);
- break;
- default:
- goto out_unimplemented;
- }
-
-out:
- rtas_st(rets, 0, ret);
- return;
-
-out_unimplemented:
- /* currently only DR-related sensors are implemented */
- DPRINTF("rtas_set_indicator: sensor/indicator not implemented: %d\n",
- sensor_type);
- rtas_st(rets, 0, RTAS_OUT_NOT_SUPPORTED);
-}
-
-static void rtas_get_sensor_state(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- uint32_t token, uint32_t nargs,
- target_ulong args, uint32_t nret,
- target_ulong rets)
-{
- uint32_t sensor_type;
- uint32_t sensor_index;
- uint32_t sensor_state = 0;
- sPAPRDRConnector *drc;
- sPAPRDRConnectorClass *drck;
- uint32_t ret = RTAS_OUT_SUCCESS;
-
- if (nargs != 2 || nret != 2) {
- ret = RTAS_OUT_PARAM_ERROR;
- goto out;
- }
-
- sensor_type = rtas_ld(args, 0);
- sensor_index = rtas_ld(args, 1);
-
- if (sensor_type != RTAS_SENSOR_TYPE_ENTITY_SENSE) {
- /* currently only DR-related sensors are implemented */
- DPRINTF("rtas_get_sensor_state: sensor/indicator not implemented: %d\n",
- sensor_type);
- ret = RTAS_OUT_NOT_SUPPORTED;
- goto out;
- }
-
- drc = spapr_dr_connector_by_index(sensor_index);
- if (!drc) {
- DPRINTF("rtas_get_sensor_state: invalid sensor/DRC index: %xh\n",
- sensor_index);
- ret = RTAS_OUT_PARAM_ERROR;
- goto out;
- }
- drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
- ret = drck->entity_sense(drc, &sensor_state);
-
-out:
- rtas_st(rets, 0, ret);
- rtas_st(rets, 1, sensor_state);
-}
-
-/* configure-connector work area offsets, int32_t units for field
- * indexes, bytes for field offset/len values.
- *
- * as documented by PAPR+ v2.7, 13.5.3.5
- */
-#define CC_IDX_NODE_NAME_OFFSET 2
-#define CC_IDX_PROP_NAME_OFFSET 2
-#define CC_IDX_PROP_LEN 3
-#define CC_IDX_PROP_DATA_OFFSET 4
-#define CC_VAL_DATA_OFFSET ((CC_IDX_PROP_DATA_OFFSET + 1) * 4)
-#define CC_WA_LEN 4096
-
-static void configure_connector_st(target_ulong addr, target_ulong offset,
- const void *buf, size_t len)
-{
- cpu_physical_memory_write(ppc64_phys_to_real(addr + offset),
- buf, MIN(len, CC_WA_LEN - offset));
-}
-
-static void rtas_ibm_configure_connector(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
- uint32_t token, uint32_t nargs,
- target_ulong args, uint32_t nret,
- target_ulong rets)
-{
- uint64_t wa_addr;
- uint64_t wa_offset;
- uint32_t drc_index;
- sPAPRDRConnector *drc;
- sPAPRDRConnectorClass *drck;
- sPAPRConfigureConnectorState *ccs;
- sPAPRDRCCResponse resp = SPAPR_DR_CC_RESPONSE_CONTINUE;
- int rc;
- const void *fdt;
-
- if (nargs != 2 || nret != 1) {
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
- return;
- }
-
- wa_addr = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 0);
-
- drc_index = rtas_ld(wa_addr, 0);
- drc = spapr_dr_connector_by_index(drc_index);
- if (!drc) {
- DPRINTF("rtas_ibm_configure_connector: invalid DRC index: %xh\n",
- drc_index);
- rc = RTAS_OUT_PARAM_ERROR;
- goto out;
- }
-
- drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
- fdt = drck->get_fdt(drc, NULL);
- if (!fdt) {
- DPRINTF("rtas_ibm_configure_connector: Missing FDT for DRC index: %xh\n",
- drc_index);
- rc = SPAPR_DR_CC_RESPONSE_NOT_CONFIGURABLE;
- goto out;
- }
-
- ccs = spapr_ccs_find(spapr, drc_index);
- if (!ccs) {
- ccs = g_new0(sPAPRConfigureConnectorState, 1);
- (void)drck->get_fdt(drc, &ccs->fdt_offset);
- ccs->drc_index = drc_index;
- spapr_ccs_add(spapr, ccs);
- }
-
- do {
- uint32_t tag;
- const char *name;
- const struct fdt_property *prop;
- int fdt_offset_next, prop_len;
-
- tag = fdt_next_tag(fdt, ccs->fdt_offset, &fdt_offset_next);
-
- switch (tag) {
- case FDT_BEGIN_NODE:
- ccs->fdt_depth++;
- name = fdt_get_name(fdt, ccs->fdt_offset, NULL);
-
- /* provide the name of the next OF node */
- wa_offset = CC_VAL_DATA_OFFSET;
- rtas_st(wa_addr, CC_IDX_NODE_NAME_OFFSET, wa_offset);
- configure_connector_st(wa_addr, wa_offset, name, strlen(name) + 1);
- resp = SPAPR_DR_CC_RESPONSE_NEXT_CHILD;
- break;
- case FDT_END_NODE:
- ccs->fdt_depth--;
- if (ccs->fdt_depth == 0) {
- /* done sending the device tree, don't need to track
- * the state anymore
- */
- drck->set_configured(drc);
- spapr_ccs_remove(spapr, ccs);
- ccs = NULL;
- resp = SPAPR_DR_CC_RESPONSE_SUCCESS;
- } else {
- resp = SPAPR_DR_CC_RESPONSE_PREV_PARENT;
- }
- break;
- case FDT_PROP:
- prop = fdt_get_property_by_offset(fdt, ccs->fdt_offset,
- &prop_len);
- name = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
-
- /* provide the name of the next OF property */
- wa_offset = CC_VAL_DATA_OFFSET;
- rtas_st(wa_addr, CC_IDX_PROP_NAME_OFFSET, wa_offset);
- configure_connector_st(wa_addr, wa_offset, name, strlen(name) + 1);
-
- /* provide the length and value of the OF property. data gets
- * placed immediately after NULL terminator of the OF property's
- * name string
- */
- wa_offset += strlen(name) + 1,
- rtas_st(wa_addr, CC_IDX_PROP_LEN, prop_len);
- rtas_st(wa_addr, CC_IDX_PROP_DATA_OFFSET, wa_offset);
- configure_connector_st(wa_addr, wa_offset, prop->data, prop_len);
- resp = SPAPR_DR_CC_RESPONSE_NEXT_PROPERTY;
- break;
- case FDT_END:
- resp = SPAPR_DR_CC_RESPONSE_ERROR;
- default:
- /* keep seeking for an actionable tag */
- break;
- }
- if (ccs) {
- ccs->fdt_offset = fdt_offset_next;
- }
- } while (resp == SPAPR_DR_CC_RESPONSE_CONTINUE);
-
- rc = resp;
-out:
- rtas_st(rets, 0, rc);
-}
-
-static struct rtas_call {
- const char *name;
- spapr_rtas_fn fn;
-} rtas_table[RTAS_TOKEN_MAX - RTAS_TOKEN_BASE];
-
-target_ulong spapr_rtas_call(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- uint32_t token, uint32_t nargs, target_ulong args,
- uint32_t nret, target_ulong rets)
-{
- if ((token >= RTAS_TOKEN_BASE) && (token < RTAS_TOKEN_MAX)) {
- struct rtas_call *call = rtas_table + (token - RTAS_TOKEN_BASE);
-
- if (call->fn) {
- call->fn(cpu, spapr, token, nargs, args, nret, rets);
- return H_SUCCESS;
- }
- }
-
- /* HACK: Some Linux early debug code uses RTAS display-character,
- * but assumes the token value is 0xa (which it is on some real
- * machines) without looking it up in the device tree. This
- * special case makes this work */
- if (token == 0xa) {
- rtas_display_character(cpu, spapr, 0xa, nargs, args, nret, rets);
- return H_SUCCESS;
- }
-
- hcall_dprintf("Unknown RTAS token 0x%x\n", token);
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
- return H_PARAMETER;
-}
-
-void spapr_rtas_register(int token, const char *name, spapr_rtas_fn fn)
-{
- assert((token >= RTAS_TOKEN_BASE) && (token < RTAS_TOKEN_MAX));
-
- token -= RTAS_TOKEN_BASE;
-
- assert(!rtas_table[token].name);
-
- rtas_table[token].name = name;
- rtas_table[token].fn = fn;
-}
-
-int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr,
- hwaddr rtas_size)
-{
- int ret;
- int i;
- uint32_t lrdr_capacity[5];
- MachineState *machine = MACHINE(qdev_get_machine());
- sPAPRMachineState *spapr = SPAPR_MACHINE(machine);
- uint64_t max_hotplug_addr = spapr->hotplug_memory.base +
- memory_region_size(&spapr->hotplug_memory.mr);
-
- ret = fdt_add_mem_rsv(fdt, rtas_addr, rtas_size);
- if (ret < 0) {
- fprintf(stderr, "Couldn't add RTAS reserve entry: %s\n",
- fdt_strerror(ret));
- return ret;
- }
-
- ret = qemu_fdt_setprop_cell(fdt, "/rtas", "linux,rtas-base",
- rtas_addr);
- if (ret < 0) {
- fprintf(stderr, "Couldn't add linux,rtas-base property: %s\n",
- fdt_strerror(ret));
- return ret;
- }
-
- ret = qemu_fdt_setprop_cell(fdt, "/rtas", "linux,rtas-entry",
- rtas_addr);
- if (ret < 0) {
- fprintf(stderr, "Couldn't add linux,rtas-entry property: %s\n",
- fdt_strerror(ret));
- return ret;
- }
-
- ret = qemu_fdt_setprop_cell(fdt, "/rtas", "rtas-size",
- rtas_size);
- if (ret < 0) {
- fprintf(stderr, "Couldn't add rtas-size property: %s\n",
- fdt_strerror(ret));
- return ret;
- }
-
- for (i = 0; i < RTAS_TOKEN_MAX - RTAS_TOKEN_BASE; i++) {
- struct rtas_call *call = &rtas_table[i];
-
- if (!call->name) {
- continue;
- }
-
- ret = qemu_fdt_setprop_cell(fdt, "/rtas", call->name,
- i + RTAS_TOKEN_BASE);
- if (ret < 0) {
- fprintf(stderr, "Couldn't add rtas token for %s: %s\n",
- call->name, fdt_strerror(ret));
- return ret;
- }
-
- }
-
- lrdr_capacity[0] = cpu_to_be32(max_hotplug_addr >> 32);
- lrdr_capacity[1] = cpu_to_be32(max_hotplug_addr & 0xffffffff);
- lrdr_capacity[2] = 0;
- lrdr_capacity[3] = cpu_to_be32(SPAPR_MEMORY_BLOCK_SIZE);
- lrdr_capacity[4] = cpu_to_be32(max_cpus/smp_threads);
- ret = qemu_fdt_setprop(fdt, "/rtas", "ibm,lrdr-capacity", lrdr_capacity,
- sizeof(lrdr_capacity));
- if (ret < 0) {
- fprintf(stderr, "Couldn't add ibm,lrdr-capacity rtas property\n");
- return ret;
- }
-
- return 0;
-}
-
-static void core_rtas_register_types(void)
-{
- spapr_rtas_register(RTAS_DISPLAY_CHARACTER, "display-character",
- rtas_display_character);
- spapr_rtas_register(RTAS_POWER_OFF, "power-off", rtas_power_off);
- spapr_rtas_register(RTAS_SYSTEM_REBOOT, "system-reboot",
- rtas_system_reboot);
- spapr_rtas_register(RTAS_QUERY_CPU_STOPPED_STATE, "query-cpu-stopped-state",
- rtas_query_cpu_stopped_state);
- spapr_rtas_register(RTAS_START_CPU, "start-cpu", rtas_start_cpu);
- spapr_rtas_register(RTAS_STOP_SELF, "stop-self", rtas_stop_self);
- spapr_rtas_register(RTAS_IBM_GET_SYSTEM_PARAMETER,
- "ibm,get-system-parameter",
- rtas_ibm_get_system_parameter);
- spapr_rtas_register(RTAS_IBM_SET_SYSTEM_PARAMETER,
- "ibm,set-system-parameter",
- rtas_ibm_set_system_parameter);
- spapr_rtas_register(RTAS_IBM_OS_TERM, "ibm,os-term",
- rtas_ibm_os_term);
- spapr_rtas_register(RTAS_SET_POWER_LEVEL, "set-power-level",
- rtas_set_power_level);
- spapr_rtas_register(RTAS_GET_POWER_LEVEL, "get-power-level",
- rtas_get_power_level);
- spapr_rtas_register(RTAS_SET_INDICATOR, "set-indicator",
- rtas_set_indicator);
- spapr_rtas_register(RTAS_GET_SENSOR_STATE, "get-sensor-state",
- rtas_get_sensor_state);
- spapr_rtas_register(RTAS_IBM_CONFIGURE_CONNECTOR, "ibm,configure-connector",
- rtas_ibm_configure_connector);
-}
-
-type_init(core_rtas_register_types)
diff --git a/qemu/hw/ppc/spapr_rtc.c b/qemu/hw/ppc/spapr_rtc.c
deleted file mode 100644
index 3a17ac42e..000000000
--- a/qemu/hw/ppc/spapr_rtc.c
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
- *
- * RTAS Real Time Clock
- *
- * Copyright (c) 2010-2011 David Gibson, IBM Corporation.
- * Copyright 2014 David Gibson, Red Hat.
- *
- * 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.
- *
- */
-#include "qemu/osdep.h"
-#include "cpu.h"
-#include "qemu/timer.h"
-#include "sysemu/sysemu.h"
-#include "hw/ppc/spapr.h"
-#include "qapi-event.h"
-#include "qemu/cutils.h"
-
-#define SPAPR_RTC(obj) \
- OBJECT_CHECK(sPAPRRTCState, (obj), TYPE_SPAPR_RTC)
-
-typedef struct sPAPRRTCState sPAPRRTCState;
-struct sPAPRRTCState {
- /*< private >*/
- SysBusDevice parent_obj;
- int64_t ns_offset;
-};
-
-void spapr_rtc_read(DeviceState *dev, struct tm *tm, uint32_t *ns)
-{
- sPAPRRTCState *rtc = SPAPR_RTC(dev);
- int64_t host_ns = qemu_clock_get_ns(rtc_clock);
- int64_t guest_ns;
- time_t guest_s;
-
- assert(rtc);
-
- guest_ns = host_ns + rtc->ns_offset;
- guest_s = guest_ns / NANOSECONDS_PER_SECOND;
-
- if (tm) {
- gmtime_r(&guest_s, tm);
- }
- if (ns) {
- *ns = guest_ns;
- }
-}
-
-int spapr_rtc_import_offset(DeviceState *dev, int64_t legacy_offset)
-{
- sPAPRRTCState *rtc;
-
- if (!dev) {
- return -ENODEV;
- }
-
- rtc = SPAPR_RTC(dev);
-
- rtc->ns_offset = legacy_offset * NANOSECONDS_PER_SECOND;
-
- return 0;
-}
-
-static void rtas_get_time_of_day(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- uint32_t token, uint32_t nargs,
- target_ulong args,
- uint32_t nret, target_ulong rets)
-{
- struct tm tm;
- uint32_t ns;
-
- if ((nargs != 0) || (nret != 8)) {
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
- return;
- }
-
- if (!spapr->rtc) {
- rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
- return;
- }
-
- spapr_rtc_read(spapr->rtc, &tm, &ns);
-
- rtas_st(rets, 0, RTAS_OUT_SUCCESS);
- rtas_st(rets, 1, tm.tm_year + 1900);
- rtas_st(rets, 2, tm.tm_mon + 1);
- rtas_st(rets, 3, tm.tm_mday);
- rtas_st(rets, 4, tm.tm_hour);
- rtas_st(rets, 5, tm.tm_min);
- rtas_st(rets, 6, tm.tm_sec);
- rtas_st(rets, 7, ns);
-}
-
-static void rtas_set_time_of_day(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- uint32_t token, uint32_t nargs,
- target_ulong args,
- uint32_t nret, target_ulong rets)
-{
- sPAPRRTCState *rtc;
- struct tm tm;
- time_t new_s;
- int64_t host_ns;
-
- if ((nargs != 7) || (nret != 1)) {
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
- return;
- }
-
- if (!spapr->rtc) {
- rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
- return;
- }
-
- tm.tm_year = rtas_ld(args, 0) - 1900;
- tm.tm_mon = rtas_ld(args, 1) - 1;
- tm.tm_mday = rtas_ld(args, 2);
- tm.tm_hour = rtas_ld(args, 3);
- tm.tm_min = rtas_ld(args, 4);
- tm.tm_sec = rtas_ld(args, 5);
-
- new_s = mktimegm(&tm);
- if (new_s == -1) {
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
- return;
- }
-
- /* Generate a monitor event for the change */
- qapi_event_send_rtc_change(qemu_timedate_diff(&tm), &error_abort);
-
- rtc = SPAPR_RTC(spapr->rtc);
-
- host_ns = qemu_clock_get_ns(rtc_clock);
-
- rtc->ns_offset = (new_s * NANOSECONDS_PER_SECOND) - host_ns;
-
- rtas_st(rets, 0, RTAS_OUT_SUCCESS);
-}
-
-static void spapr_rtc_qom_date(Object *obj, struct tm *current_tm, Error **errp)
-{
- spapr_rtc_read(DEVICE(obj), current_tm, NULL);
-}
-
-static void spapr_rtc_realize(DeviceState *dev, Error **errp)
-{
- sPAPRRTCState *rtc = SPAPR_RTC(dev);
- struct tm tm;
- time_t host_s;
- int64_t rtc_ns;
-
- /* Initialize the RTAS RTC from host time */
-
- qemu_get_timedate(&tm, 0);
- host_s = mktimegm(&tm);
- rtc_ns = qemu_clock_get_ns(rtc_clock);
- rtc->ns_offset = host_s * NANOSECONDS_PER_SECOND - rtc_ns;
-
- object_property_add_tm(OBJECT(rtc), "date", spapr_rtc_qom_date, NULL);
-}
-
-static const VMStateDescription vmstate_spapr_rtc = {
- .name = "spapr/rtc",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_INT64(ns_offset, sPAPRRTCState),
- VMSTATE_END_OF_LIST()
- },
-};
-
-static void spapr_rtc_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- dc->realize = spapr_rtc_realize;
- dc->vmsd = &vmstate_spapr_rtc;
-
- spapr_rtas_register(RTAS_GET_TIME_OF_DAY, "get-time-of-day",
- rtas_get_time_of_day);
- spapr_rtas_register(RTAS_SET_TIME_OF_DAY, "set-time-of-day",
- rtas_set_time_of_day);
-}
-
-static const TypeInfo spapr_rtc_info = {
- .name = TYPE_SPAPR_RTC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(sPAPRRTCState),
- .class_init = spapr_rtc_class_init,
-};
-
-static void spapr_rtc_register_types(void)
-{
- type_register_static(&spapr_rtc_info);
-}
-type_init(spapr_rtc_register_types)
diff --git a/qemu/hw/ppc/spapr_vio.c b/qemu/hw/ppc/spapr_vio.c
deleted file mode 100644
index 8aa021fde..000000000
--- a/qemu/hw/ppc/spapr_vio.c
+++ /dev/null
@@ -1,706 +0,0 @@
-/*
- * QEMU sPAPR VIO code
- *
- * Copyright (c) 2010 David Gibson, IBM Corporation <dwg@au1.ibm.com>
- * Based on the s390 virtio bus code:
- * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/hw.h"
-#include "sysemu/sysemu.h"
-#include "hw/boards.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "hw/sysbus.h"
-#include "sysemu/kvm.h"
-#include "sysemu/device_tree.h"
-#include "kvm_ppc.h"
-
-#include "hw/ppc/spapr.h"
-#include "hw/ppc/spapr_vio.h"
-#include "hw/ppc/xics.h"
-
-#include <libfdt.h>
-
-/* #define DEBUG_SPAPR */
-
-#ifdef DEBUG_SPAPR
-#define DPRINTF(fmt, ...) \
- do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) \
- do { } while (0)
-#endif
-
-static Property spapr_vio_props[] = {
- DEFINE_PROP_UINT32("irq", VIOsPAPRDevice, irq, 0), \
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static char *spapr_vio_get_dev_name(DeviceState *qdev)
-{
- VIOsPAPRDevice *dev = VIO_SPAPR_DEVICE(qdev);
- VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
- char *name;
-
- /* Device tree style name device@reg */
- name = g_strdup_printf("%s@%x", pc->dt_name, dev->reg);
-
- return name;
-}
-
-static void spapr_vio_bus_class_init(ObjectClass *klass, void *data)
-{
- BusClass *k = BUS_CLASS(klass);
-
- k->get_dev_path = spapr_vio_get_dev_name;
- k->get_fw_dev_path = spapr_vio_get_dev_name;
-}
-
-static const TypeInfo spapr_vio_bus_info = {
- .name = TYPE_SPAPR_VIO_BUS,
- .parent = TYPE_BUS,
- .class_init = spapr_vio_bus_class_init,
- .instance_size = sizeof(VIOsPAPRBus),
-};
-
-VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg)
-{
- BusChild *kid;
- VIOsPAPRDevice *dev = NULL;
-
- QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
- dev = (VIOsPAPRDevice *)kid->child;
- if (dev->reg == reg) {
- return dev;
- }
- }
-
- return NULL;
-}
-
-static int vio_make_devnode(VIOsPAPRDevice *dev,
- void *fdt)
-{
- VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
- int vdevice_off, node_off, ret;
- char *dt_name;
-
- vdevice_off = fdt_path_offset(fdt, "/vdevice");
- if (vdevice_off < 0) {
- return vdevice_off;
- }
-
- dt_name = spapr_vio_get_dev_name(DEVICE(dev));
- node_off = fdt_add_subnode(fdt, vdevice_off, dt_name);
- g_free(dt_name);
- if (node_off < 0) {
- return node_off;
- }
-
- ret = fdt_setprop_cell(fdt, node_off, "reg", dev->reg);
- if (ret < 0) {
- return ret;
- }
-
- if (pc->dt_type) {
- ret = fdt_setprop_string(fdt, node_off, "device_type",
- pc->dt_type);
- if (ret < 0) {
- return ret;
- }
- }
-
- if (pc->dt_compatible) {
- ret = fdt_setprop_string(fdt, node_off, "compatible",
- pc->dt_compatible);
- if (ret < 0) {
- return ret;
- }
- }
-
- if (dev->irq) {
- uint32_t ints_prop[] = {cpu_to_be32(dev->irq), 0};
-
- ret = fdt_setprop(fdt, node_off, "interrupts", ints_prop,
- sizeof(ints_prop));
- if (ret < 0) {
- return ret;
- }
- }
-
- ret = spapr_tcet_dma_dt(fdt, node_off, "ibm,my-dma-window", dev->tcet);
- if (ret < 0) {
- return ret;
- }
-
- if (pc->devnode) {
- ret = (pc->devnode)(dev, fdt, node_off);
- if (ret < 0) {
- return ret;
- }
- }
-
- return node_off;
-}
-
-/*
- * CRQ handling
- */
-static target_ulong h_reg_crq(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- target_ulong reg = args[0];
- target_ulong queue_addr = args[1];
- target_ulong queue_len = args[2];
- VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
-
- if (!dev) {
- hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg);
- return H_PARAMETER;
- }
-
- /* We can't grok a queue size bigger than 256M for now */
- if (queue_len < 0x1000 || queue_len > 0x10000000) {
- hcall_dprintf("Queue size too small or too big (0x" TARGET_FMT_lx
- ")\n", queue_len);
- return H_PARAMETER;
- }
-
- /* Check queue alignment */
- if (queue_addr & 0xfff) {
- hcall_dprintf("Queue not aligned (0x" TARGET_FMT_lx ")\n", queue_addr);
- return H_PARAMETER;
- }
-
- /* Check if device supports CRQs */
- if (!dev->crq.SendFunc) {
- hcall_dprintf("Device does not support CRQ\n");
- return H_NOT_FOUND;
- }
-
- /* Already a queue ? */
- if (dev->crq.qsize) {
- hcall_dprintf("CRQ already registered\n");
- return H_RESOURCE;
- }
- dev->crq.qladdr = queue_addr;
- dev->crq.qsize = queue_len;
- dev->crq.qnext = 0;
-
- DPRINTF("CRQ for dev 0x" TARGET_FMT_lx " registered at 0x"
- TARGET_FMT_lx "/0x" TARGET_FMT_lx "\n",
- reg, queue_addr, queue_len);
- return H_SUCCESS;
-}
-
-static target_ulong free_crq(VIOsPAPRDevice *dev)
-{
- dev->crq.qladdr = 0;
- dev->crq.qsize = 0;
- dev->crq.qnext = 0;
-
- DPRINTF("CRQ for dev 0x%" PRIx32 " freed\n", dev->reg);
-
- return H_SUCCESS;
-}
-
-static target_ulong h_free_crq(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- target_ulong reg = args[0];
- VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
-
- if (!dev) {
- hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg);
- return H_PARAMETER;
- }
-
- return free_crq(dev);
-}
-
-static target_ulong h_send_crq(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- target_ulong reg = args[0];
- target_ulong msg_hi = args[1];
- target_ulong msg_lo = args[2];
- VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
- uint64_t crq_mangle[2];
-
- if (!dev) {
- hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg);
- return H_PARAMETER;
- }
- crq_mangle[0] = cpu_to_be64(msg_hi);
- crq_mangle[1] = cpu_to_be64(msg_lo);
-
- if (dev->crq.SendFunc) {
- return dev->crq.SendFunc(dev, (uint8_t *)crq_mangle);
- }
-
- return H_HARDWARE;
-}
-
-static target_ulong h_enable_crq(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- target_ulong reg = args[0];
- VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
-
- if (!dev) {
- hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg);
- return H_PARAMETER;
- }
-
- return 0;
-}
-
-/* Returns negative error, 0 success, or positive: queue full */
-int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq)
-{
- int rc;
- uint8_t byte;
-
- if (!dev->crq.qsize) {
- fprintf(stderr, "spapr_vio_send_creq on uninitialized queue\n");
- return -1;
- }
-
- /* Maybe do a fast path for KVM just writing to the pages */
- rc = spapr_vio_dma_read(dev, dev->crq.qladdr + dev->crq.qnext, &byte, 1);
- if (rc) {
- return rc;
- }
- if (byte != 0) {
- return 1;
- }
-
- rc = spapr_vio_dma_write(dev, dev->crq.qladdr + dev->crq.qnext + 8,
- &crq[8], 8);
- if (rc) {
- return rc;
- }
-
- kvmppc_eieio();
-
- rc = spapr_vio_dma_write(dev, dev->crq.qladdr + dev->crq.qnext, crq, 8);
- if (rc) {
- return rc;
- }
-
- dev->crq.qnext = (dev->crq.qnext + 16) % dev->crq.qsize;
-
- if (dev->signal_state & 1) {
- qemu_irq_pulse(spapr_vio_qirq(dev));
- }
-
- return 0;
-}
-
-/* "quiesce" handling */
-
-static void spapr_vio_quiesce_one(VIOsPAPRDevice *dev)
-{
- if (dev->tcet) {
- device_reset(DEVICE(dev->tcet));
- }
- free_crq(dev);
-}
-
-void spapr_vio_set_bypass(VIOsPAPRDevice *dev, bool bypass)
-{
- if (!dev->tcet) {
- return;
- }
-
- memory_region_set_enabled(&dev->mrbypass, bypass);
- memory_region_set_enabled(spapr_tce_get_iommu(dev->tcet), !bypass);
-
- dev->tcet->bypass = bypass;
-}
-
-static void rtas_set_tce_bypass(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- uint32_t token,
- uint32_t nargs, target_ulong args,
- uint32_t nret, target_ulong rets)
-{
- VIOsPAPRBus *bus = spapr->vio_bus;
- VIOsPAPRDevice *dev;
- uint32_t unit, enable;
-
- if (nargs != 2) {
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
- return;
- }
- unit = rtas_ld(args, 0);
- enable = rtas_ld(args, 1);
- dev = spapr_vio_find_by_reg(bus, unit);
- if (!dev) {
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
- return;
- }
-
- if (!dev->tcet) {
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
- return;
- }
-
- spapr_vio_set_bypass(dev, !!enable);
-
- rtas_st(rets, 0, RTAS_OUT_SUCCESS);
-}
-
-static void rtas_quiesce(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- uint32_t token,
- uint32_t nargs, target_ulong args,
- uint32_t nret, target_ulong rets)
-{
- VIOsPAPRBus *bus = spapr->vio_bus;
- BusChild *kid;
- VIOsPAPRDevice *dev = NULL;
-
- if (nargs != 0) {
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
- return;
- }
-
- QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
- dev = (VIOsPAPRDevice *)kid->child;
- spapr_vio_quiesce_one(dev);
- }
-
- rtas_st(rets, 0, RTAS_OUT_SUCCESS);
-}
-
-static VIOsPAPRDevice *reg_conflict(VIOsPAPRDevice *dev)
-{
- VIOsPAPRBus *bus = SPAPR_VIO_BUS(dev->qdev.parent_bus);
- BusChild *kid;
- VIOsPAPRDevice *other;
-
- /*
- * Check for a device other than the given one which is already
- * using the requested address. We have to open code this because
- * the given dev might already be in the list.
- */
- QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
- other = VIO_SPAPR_DEVICE(kid->child);
-
- if (other != dev && other->reg == dev->reg) {
- return other;
- }
- }
-
- return 0;
-}
-
-static void spapr_vio_busdev_reset(DeviceState *qdev)
-{
- VIOsPAPRDevice *dev = VIO_SPAPR_DEVICE(qdev);
- VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
-
- /* Shut down the request queue and TCEs if necessary */
- spapr_vio_quiesce_one(dev);
-
- dev->signal_state = 0;
-
- spapr_vio_set_bypass(dev, false);
- if (pc->reset) {
- pc->reset(dev);
- }
-}
-
-static void spapr_vio_busdev_realize(DeviceState *qdev, Error **errp)
-{
- sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
- VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
- VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
- char *id;
- Error *local_err = NULL;
-
- if (dev->reg != -1) {
- /*
- * Explicitly assigned address, just verify that no-one else
- * is using it. other mechanism). We have to open code this
- * rather than using spapr_vio_find_by_reg() because sdev
- * itself is already in the list.
- */
- VIOsPAPRDevice *other = reg_conflict(dev);
-
- if (other) {
- error_setg(errp, "%s and %s devices conflict at address %#x",
- object_get_typename(OBJECT(qdev)),
- object_get_typename(OBJECT(&other->qdev)),
- dev->reg);
- return;
- }
- } else {
- /* Need to assign an address */
- VIOsPAPRBus *bus = SPAPR_VIO_BUS(dev->qdev.parent_bus);
-
- do {
- dev->reg = bus->next_reg++;
- } while (reg_conflict(dev));
- }
-
- /* Don't overwrite ids assigned on the command line */
- if (!dev->qdev.id) {
- id = spapr_vio_get_dev_name(DEVICE(dev));
- dev->qdev.id = id;
- }
-
- dev->irq = xics_alloc(spapr->icp, 0, dev->irq, false, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- if (pc->rtce_window_size) {
- uint32_t liobn = SPAPR_VIO_LIOBN(dev->reg);
-
- memory_region_init(&dev->mrroot, OBJECT(dev), "iommu-spapr-root",
- ram_size);
- memory_region_init_alias(&dev->mrbypass, OBJECT(dev),
- "iommu-spapr-bypass", get_system_memory(),
- 0, ram_size);
- memory_region_add_subregion_overlap(&dev->mrroot, 0, &dev->mrbypass, 1);
- address_space_init(&dev->as, &dev->mrroot, qdev->id);
-
- dev->tcet = spapr_tce_new_table(qdev, liobn,
- 0,
- SPAPR_TCE_PAGE_SHIFT,
- pc->rtce_window_size >>
- SPAPR_TCE_PAGE_SHIFT, false);
- dev->tcet->vdev = dev;
- memory_region_add_subregion_overlap(&dev->mrroot, 0,
- spapr_tce_get_iommu(dev->tcet), 2);
- }
-
- pc->realize(dev, errp);
-}
-
-static target_ulong h_vio_signal(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- target_ulong opcode,
- target_ulong *args)
-{
- target_ulong reg = args[0];
- target_ulong mode = args[1];
- VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
- VIOsPAPRDeviceClass *pc;
-
- if (!dev) {
- return H_PARAMETER;
- }
-
- pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
-
- if (mode & ~pc->signal_mask) {
- return H_PARAMETER;
- }
-
- dev->signal_state = mode;
-
- return H_SUCCESS;
-}
-
-VIOsPAPRBus *spapr_vio_bus_init(void)
-{
- VIOsPAPRBus *bus;
- BusState *qbus;
- DeviceState *dev;
-
- /* Create bridge device */
- dev = qdev_create(NULL, TYPE_SPAPR_VIO_BRIDGE);
- qdev_init_nofail(dev);
-
- /* Create bus on bridge device */
- qbus = qbus_create(TYPE_SPAPR_VIO_BUS, dev, "spapr-vio");
- bus = SPAPR_VIO_BUS(qbus);
- bus->next_reg = 0x71000000;
-
- /* hcall-vio */
- spapr_register_hypercall(H_VIO_SIGNAL, h_vio_signal);
-
- /* hcall-crq */
- spapr_register_hypercall(H_REG_CRQ, h_reg_crq);
- spapr_register_hypercall(H_FREE_CRQ, h_free_crq);
- spapr_register_hypercall(H_SEND_CRQ, h_send_crq);
- spapr_register_hypercall(H_ENABLE_CRQ, h_enable_crq);
-
- /* RTAS calls */
- spapr_rtas_register(RTAS_IBM_SET_TCE_BYPASS, "ibm,set-tce-bypass",
- rtas_set_tce_bypass);
- spapr_rtas_register(RTAS_QUIESCE, "quiesce", rtas_quiesce);
-
- return bus;
-}
-
-/* Represents sPAPR hcall VIO devices */
-
-static int spapr_vio_bridge_init(SysBusDevice *dev)
-{
- /* nothing */
- return 0;
-}
-
-static void spapr_vio_bridge_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->fw_name = "vdevice";
- k->init = spapr_vio_bridge_init;
-}
-
-static const TypeInfo spapr_vio_bridge_info = {
- .name = TYPE_SPAPR_VIO_BRIDGE,
- .parent = TYPE_SYS_BUS_DEVICE,
- .class_init = spapr_vio_bridge_class_init,
-};
-
-const VMStateDescription vmstate_spapr_vio = {
- .name = "spapr_vio",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- /* Sanity check */
- VMSTATE_UINT32_EQUAL(reg, VIOsPAPRDevice),
- VMSTATE_UINT32_EQUAL(irq, VIOsPAPRDevice),
-
- /* General VIO device state */
- VMSTATE_UINTTL(signal_state, VIOsPAPRDevice),
- VMSTATE_UINT64(crq.qladdr, VIOsPAPRDevice),
- VMSTATE_UINT32(crq.qsize, VIOsPAPRDevice),
- VMSTATE_UINT32(crq.qnext, VIOsPAPRDevice),
-
- VMSTATE_END_OF_LIST()
- },
-};
-
-static void vio_spapr_device_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *k = DEVICE_CLASS(klass);
- k->realize = spapr_vio_busdev_realize;
- k->reset = spapr_vio_busdev_reset;
- k->bus_type = TYPE_SPAPR_VIO_BUS;
- k->props = spapr_vio_props;
-}
-
-static const TypeInfo spapr_vio_type_info = {
- .name = TYPE_VIO_SPAPR_DEVICE,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(VIOsPAPRDevice),
- .abstract = true,
- .class_size = sizeof(VIOsPAPRDeviceClass),
- .class_init = vio_spapr_device_class_init,
-};
-
-static void spapr_vio_register_types(void)
-{
- type_register_static(&spapr_vio_bus_info);
- type_register_static(&spapr_vio_bridge_info);
- type_register_static(&spapr_vio_type_info);
-}
-
-type_init(spapr_vio_register_types)
-
-static int compare_reg(const void *p1, const void *p2)
-{
- VIOsPAPRDevice const *dev1, *dev2;
-
- dev1 = (VIOsPAPRDevice *)*(DeviceState **)p1;
- dev2 = (VIOsPAPRDevice *)*(DeviceState **)p2;
-
- if (dev1->reg < dev2->reg) {
- return -1;
- }
- if (dev1->reg == dev2->reg) {
- return 0;
- }
-
- /* dev1->reg > dev2->reg */
- return 1;
-}
-
-int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt)
-{
- DeviceState *qdev, **qdevs;
- BusChild *kid;
- int i, num, ret = 0;
-
- /* Count qdevs on the bus list */
- num = 0;
- QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
- num++;
- }
-
- /* Copy out into an array of pointers */
- qdevs = g_malloc(sizeof(qdev) * num);
- num = 0;
- QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
- qdevs[num++] = kid->child;
- }
-
- /* Sort the array */
- qsort(qdevs, num, sizeof(qdev), compare_reg);
-
- /* Hack alert. Give the devices to libfdt in reverse order, we happen
- * to know that will mean they are in forward order in the tree. */
- for (i = num - 1; i >= 0; i--) {
- VIOsPAPRDevice *dev = (VIOsPAPRDevice *)(qdevs[i]);
-
- ret = vio_make_devnode(dev, fdt);
-
- if (ret < 0) {
- goto out;
- }
- }
-
- ret = 0;
-out:
- g_free(qdevs);
-
- return ret;
-}
-
-int spapr_populate_chosen_stdout(void *fdt, VIOsPAPRBus *bus)
-{
- VIOsPAPRDevice *dev;
- char *name, *path;
- int ret, offset;
-
- dev = spapr_vty_get_default(bus);
- if (!dev)
- return 0;
-
- offset = fdt_path_offset(fdt, "/chosen");
- if (offset < 0) {
- return offset;
- }
-
- name = spapr_vio_get_dev_name(DEVICE(dev));
- path = g_strdup_printf("/vdevice/%s", name);
-
- ret = fdt_setprop_string(fdt, offset, "linux,stdout-path", path);
-
- g_free(name);
- g_free(path);
-
- return ret;
-}
diff --git a/qemu/hw/ppc/virtex_ml507.c b/qemu/hw/ppc/virtex_ml507.c
deleted file mode 100644
index b807a08c2..000000000
--- a/qemu/hw/ppc/virtex_ml507.c
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * Model of Xilinx Virtex5 ML507 PPC-440 refdesign.
- *
- * Copyright (c) 2010 Edgar E. Iglesias.
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "hw/hw.h"
-#include "hw/char/serial.h"
-#include "hw/block/flash.h"
-#include "sysemu/sysemu.h"
-#include "hw/devices.h"
-#include "hw/boards.h"
-#include "sysemu/device_tree.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "qemu/error-report.h"
-#include "qemu/log.h"
-#include "exec/address-spaces.h"
-
-#include "hw/ppc/ppc.h"
-#include "hw/ppc/ppc4xx.h"
-#include "ppc405.h"
-
-#include "sysemu/block-backend.h"
-
-#define EPAPR_MAGIC (0x45504150)
-#define FLASH_SIZE (16 * 1024 * 1024)
-
-#define INTC_BASEADDR 0x81800000
-#define UART16550_BASEADDR 0x83e01003
-#define TIMER_BASEADDR 0x83c00000
-#define PFLASH_BASEADDR 0xfc000000
-
-#define TIMER_IRQ 3
-#define UART16550_IRQ 9
-
-static struct boot_info
-{
- uint32_t bootstrap_pc;
- uint32_t cmdline;
- uint32_t fdt;
- uint32_t ima_size;
- void *vfdt;
-} boot_info;
-
-/* Create reset TLB entries for BookE, spanning the 32bit addr space. */
-static void mmubooke_create_initial_mapping(CPUPPCState *env,
- target_ulong va,
- hwaddr pa)
-{
- ppcemb_tlb_t *tlb = &env->tlb.tlbe[0];
-
- tlb->attr = 0;
- tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
- tlb->size = 1U << 31; /* up to 0x80000000 */
- tlb->EPN = va & TARGET_PAGE_MASK;
- tlb->RPN = pa & TARGET_PAGE_MASK;
- tlb->PID = 0;
-
- tlb = &env->tlb.tlbe[1];
- tlb->attr = 0;
- tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
- tlb->size = 1U << 31; /* up to 0xffffffff */
- tlb->EPN = 0x80000000 & TARGET_PAGE_MASK;
- tlb->RPN = 0x80000000 & TARGET_PAGE_MASK;
- tlb->PID = 0;
-}
-
-static PowerPCCPU *ppc440_init_xilinx(ram_addr_t *ram_size,
- int do_init,
- const char *cpu_model,
- uint32_t sysclk)
-{
- PowerPCCPU *cpu;
- CPUPPCState *env;
- qemu_irq *irqs;
-
- cpu = cpu_ppc_init(cpu_model);
- if (cpu == NULL) {
- fprintf(stderr, "Unable to initialize CPU!\n");
- exit(1);
- }
- env = &cpu->env;
-
- ppc_booke_timers_init(cpu, sysclk, 0/* no flags */);
-
- ppc_dcr_init(env, NULL, NULL);
-
- /* interrupt controller */
- irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
- irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
- irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
- ppcuic_init(env, irqs, 0x0C0, 0, 1);
- return cpu;
-}
-
-static void main_cpu_reset(void *opaque)
-{
- PowerPCCPU *cpu = opaque;
- CPUPPCState *env = &cpu->env;
- struct boot_info *bi = env->load_info;
-
- cpu_reset(CPU(cpu));
- /* Linux Kernel Parameters (passing device tree):
- * r3: pointer to the fdt
- * r4: 0
- * r5: 0
- * r6: epapr magic
- * r7: size of IMA in bytes
- * r8: 0
- * r9: 0
- */
- env->gpr[1] = (16<<20) - 8;
- /* Provide a device-tree. */
- env->gpr[3] = bi->fdt;
- env->nip = bi->bootstrap_pc;
-
- /* Create a mapping for the kernel. */
- mmubooke_create_initial_mapping(env, 0, 0);
- env->gpr[6] = tswap32(EPAPR_MAGIC);
- env->gpr[7] = bi->ima_size;
-}
-
-#define BINARY_DEVICE_TREE_FILE "virtex-ml507.dtb"
-static int xilinx_load_device_tree(hwaddr addr,
- uint32_t ramsize,
- hwaddr initrd_base,
- hwaddr initrd_size,
- const char *kernel_cmdline)
-{
- char *path;
- int fdt_size;
- void *fdt = NULL;
- int r;
- const char *dtb_filename;
-
- dtb_filename = qemu_opt_get(qemu_get_machine_opts(), "dtb");
- if (dtb_filename) {
- fdt = load_device_tree(dtb_filename, &fdt_size);
- if (!fdt) {
- error_report("Error while loading device tree file '%s'",
- dtb_filename);
- }
- } else {
- /* Try the local "ppc.dtb" override. */
- fdt = load_device_tree("ppc.dtb", &fdt_size);
- if (!fdt) {
- path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
- if (path) {
- fdt = load_device_tree(path, &fdt_size);
- g_free(path);
- }
- }
- }
- if (!fdt) {
- return 0;
- }
-
- r = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start",
- initrd_base);
- if (r < 0) {
- error_report("couldn't set /chosen/linux,initrd-start");
- }
-
- r = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
- (initrd_base + initrd_size));
- if (r < 0) {
- error_report("couldn't set /chosen/linux,initrd-end");
- }
-
- r = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline);
- if (r < 0)
- fprintf(stderr, "couldn't set /chosen/bootargs\n");
- cpu_physical_memory_write(addr, fdt, fdt_size);
- return fdt_size;
-}
-
-static void virtex_init(MachineState *machine)
-{
- ram_addr_t ram_size = machine->ram_size;
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- hwaddr initrd_base = 0;
- int initrd_size = 0;
- MemoryRegion *address_space_mem = get_system_memory();
- DeviceState *dev;
- PowerPCCPU *cpu;
- CPUPPCState *env;
- hwaddr ram_base = 0;
- DriveInfo *dinfo;
- MemoryRegion *phys_ram = g_new(MemoryRegion, 1);
- qemu_irq irq[32], *cpu_irq;
- int kernel_size;
- int i;
-
- /* init CPUs */
- if (machine->cpu_model == NULL) {
- machine->cpu_model = "440-Xilinx";
- }
-
- cpu = ppc440_init_xilinx(&ram_size, 1, machine->cpu_model, 400000000);
- env = &cpu->env;
- qemu_register_reset(main_cpu_reset, cpu);
-
- memory_region_allocate_system_memory(phys_ram, NULL, "ram", ram_size);
- memory_region_add_subregion(address_space_mem, ram_base, phys_ram);
-
- dinfo = drive_get(IF_PFLASH, 0, 0);
- pflash_cfi01_register(PFLASH_BASEADDR, NULL, "virtex.flash", FLASH_SIZE,
- dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- (64 * 1024), FLASH_SIZE >> 16,
- 1, 0x89, 0x18, 0x0000, 0x0, 1);
-
- cpu_irq = (qemu_irq *) &env->irq_inputs[PPC40x_INPUT_INT];
- dev = qdev_create(NULL, "xlnx.xps-intc");
- qdev_prop_set_uint32(dev, "kind-of-intr", 0);
- qdev_init_nofail(dev);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, INTC_BASEADDR);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, cpu_irq[0]);
- for (i = 0; i < 32; i++) {
- irq[i] = qdev_get_gpio_in(dev, i);
- }
-
- serial_mm_init(address_space_mem, UART16550_BASEADDR, 2, irq[UART16550_IRQ],
- 115200, serial_hds[0], DEVICE_LITTLE_ENDIAN);
-
- /* 2 timers at irq 2 @ 62 Mhz. */
- dev = qdev_create(NULL, "xlnx.xps-timer");
- qdev_prop_set_uint32(dev, "one-timer-only", 0);
- qdev_prop_set_uint32(dev, "clock-frequency", 62 * 1000000);
- qdev_init_nofail(dev);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, TIMER_BASEADDR);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[TIMER_IRQ]);
-
- if (kernel_filename) {
- uint64_t entry, low, high;
- hwaddr boot_offset;
-
- /* Boots a kernel elf binary. */
- kernel_size = load_elf(kernel_filename, NULL, NULL,
- &entry, &low, &high, 1, PPC_ELF_MACHINE,
- 0, 0);
- boot_info.bootstrap_pc = entry & 0x00ffffff;
-
- if (kernel_size < 0) {
- boot_offset = 0x1200000;
- /* If we failed loading ELF's try a raw image. */
- kernel_size = load_image_targphys(kernel_filename,
- boot_offset,
- ram_size);
- boot_info.bootstrap_pc = boot_offset;
- high = boot_info.bootstrap_pc + kernel_size + 8192;
- }
-
- boot_info.ima_size = kernel_size;
-
- /* Load initrd. */
- if (machine->initrd_filename) {
- initrd_base = high = ROUND_UP(high, 4);
- initrd_size = load_image_targphys(machine->initrd_filename,
- high, ram_size - high);
-
- if (initrd_size < 0) {
- error_report("couldn't load ram disk '%s'",
- machine->initrd_filename);
- exit(1);
- }
- high = ROUND_UP(high + initrd_size, 4);
- }
-
- /* Provide a device-tree. */
- boot_info.fdt = high + (8192 * 2);
- boot_info.fdt &= ~8191;
-
- xilinx_load_device_tree(boot_info.fdt, ram_size,
- initrd_base, initrd_size,
- kernel_cmdline);
- }
- env->load_info = &boot_info;
-}
-
-static void virtex_machine_init(MachineClass *mc)
-{
- mc->desc = "Xilinx Virtex ML507 reference design";
- mc->init = virtex_init;
-}
-
-DEFINE_MACHINE("virtex-ml507", virtex_machine_init)
diff --git a/qemu/hw/s390x/Makefile.objs b/qemu/hw/s390x/Makefile.objs
deleted file mode 100644
index 220361782..000000000
--- a/qemu/hw/s390x/Makefile.objs
+++ /dev/null
@@ -1,13 +0,0 @@
-obj-y += s390-virtio.o
-obj-y += s390-virtio-hcall.o
-obj-y += sclp.o
-obj-y += event-facility.o
-obj-y += sclpquiesce.o
-obj-y += sclpcpu.o
-obj-y += ipl.o
-obj-y += css.o
-obj-y += s390-virtio-ccw.o
-obj-y += virtio-ccw.o
-obj-y += s390-pci-bus.o s390-pci-inst.o
-obj-y += s390-skeys.o
-obj-$(CONFIG_KVM) += s390-skeys-kvm.o
diff --git a/qemu/hw/s390x/css.c b/qemu/hw/s390x/css.c
deleted file mode 100644
index 3a1d91958..000000000
--- a/qemu/hw/s390x/css.c
+++ /dev/null
@@ -1,1646 +0,0 @@
-/*
- * Channel subsystem base support.
- *
- * Copyright 2012 IBM Corp.
- * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or (at
- * your option) any later version. See the COPYING file in the top-level
- * directory.
- */
-
-#include "qemu/osdep.h"
-#include <hw/qdev.h>
-#include "qemu/bitops.h"
-#include "exec/address-spaces.h"
-#include "cpu.h"
-#include "ioinst.h"
-#include "css.h"
-#include "trace.h"
-#include "hw/s390x/s390_flic.h"
-
-typedef struct CrwContainer {
- CRW crw;
- QTAILQ_ENTRY(CrwContainer) sibling;
-} CrwContainer;
-
-typedef struct ChpInfo {
- uint8_t in_use;
- uint8_t type;
- uint8_t is_virtual;
-} ChpInfo;
-
-typedef struct SubchSet {
- SubchDev *sch[MAX_SCHID + 1];
- unsigned long schids_used[BITS_TO_LONGS(MAX_SCHID + 1)];
- unsigned long devnos_used[BITS_TO_LONGS(MAX_SCHID + 1)];
-} SubchSet;
-
-typedef struct CssImage {
- SubchSet *sch_set[MAX_SSID + 1];
- ChpInfo chpids[MAX_CHPID + 1];
-} CssImage;
-
-typedef struct IoAdapter {
- uint32_t id;
- uint8_t type;
- uint8_t isc;
- QTAILQ_ENTRY(IoAdapter) sibling;
-} IoAdapter;
-
-typedef struct ChannelSubSys {
- QTAILQ_HEAD(, CrwContainer) pending_crws;
- bool sei_pending;
- bool do_crw_mchk;
- bool crws_lost;
- uint8_t max_cssid;
- uint8_t max_ssid;
- bool chnmon_active;
- uint64_t chnmon_area;
- CssImage *css[MAX_CSSID + 1];
- uint8_t default_cssid;
- QTAILQ_HEAD(, IoAdapter) io_adapters;
- QTAILQ_HEAD(, IndAddr) indicator_addresses;
-} ChannelSubSys;
-
-static ChannelSubSys channel_subsys = {
- .pending_crws = QTAILQ_HEAD_INITIALIZER(channel_subsys.pending_crws),
- .do_crw_mchk = true,
- .sei_pending = false,
- .do_crw_mchk = true,
- .crws_lost = false,
- .chnmon_active = false,
- .io_adapters = QTAILQ_HEAD_INITIALIZER(channel_subsys.io_adapters),
- .indicator_addresses =
- QTAILQ_HEAD_INITIALIZER(channel_subsys.indicator_addresses),
-};
-
-IndAddr *get_indicator(hwaddr ind_addr, int len)
-{
- IndAddr *indicator;
-
- QTAILQ_FOREACH(indicator, &channel_subsys.indicator_addresses, sibling) {
- if (indicator->addr == ind_addr) {
- indicator->refcnt++;
- return indicator;
- }
- }
- indicator = g_new0(IndAddr, 1);
- indicator->addr = ind_addr;
- indicator->len = len;
- indicator->refcnt = 1;
- QTAILQ_INSERT_TAIL(&channel_subsys.indicator_addresses,
- indicator, sibling);
- return indicator;
-}
-
-static int s390_io_adapter_map(AdapterInfo *adapter, uint64_t map_addr,
- bool do_map)
-{
- S390FLICState *fs = s390_get_flic();
- S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs);
-
- return fsc->io_adapter_map(fs, adapter->adapter_id, map_addr, do_map);
-}
-
-void release_indicator(AdapterInfo *adapter, IndAddr *indicator)
-{
- assert(indicator->refcnt > 0);
- indicator->refcnt--;
- if (indicator->refcnt > 0) {
- return;
- }
- QTAILQ_REMOVE(&channel_subsys.indicator_addresses, indicator, sibling);
- if (indicator->map) {
- s390_io_adapter_map(adapter, indicator->map, false);
- }
- g_free(indicator);
-}
-
-int map_indicator(AdapterInfo *adapter, IndAddr *indicator)
-{
- int ret;
-
- if (indicator->map) {
- return 0; /* already mapped is not an error */
- }
- indicator->map = indicator->addr;
- ret = s390_io_adapter_map(adapter, indicator->map, true);
- if ((ret != 0) && (ret != -ENOSYS)) {
- goto out_err;
- }
- return 0;
-
-out_err:
- indicator->map = 0;
- return ret;
-}
-
-int css_create_css_image(uint8_t cssid, bool default_image)
-{
- trace_css_new_image(cssid, default_image ? "(default)" : "");
- if (cssid > MAX_CSSID) {
- return -EINVAL;
- }
- if (channel_subsys.css[cssid]) {
- return -EBUSY;
- }
- channel_subsys.css[cssid] = g_malloc0(sizeof(CssImage));
- if (default_image) {
- channel_subsys.default_cssid = cssid;
- }
- return 0;
-}
-
-int css_register_io_adapter(uint8_t type, uint8_t isc, bool swap,
- bool maskable, uint32_t *id)
-{
- IoAdapter *adapter;
- bool found = false;
- int ret;
- S390FLICState *fs = s390_get_flic();
- S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs);
-
- *id = 0;
- QTAILQ_FOREACH(adapter, &channel_subsys.io_adapters, sibling) {
- if ((adapter->type == type) && (adapter->isc == isc)) {
- *id = adapter->id;
- found = true;
- ret = 0;
- break;
- }
- if (adapter->id >= *id) {
- *id = adapter->id + 1;
- }
- }
- if (found) {
- goto out;
- }
- adapter = g_new0(IoAdapter, 1);
- ret = fsc->register_io_adapter(fs, *id, isc, swap, maskable);
- if (ret == 0) {
- adapter->id = *id;
- adapter->isc = isc;
- adapter->type = type;
- QTAILQ_INSERT_TAIL(&channel_subsys.io_adapters, adapter, sibling);
- } else {
- g_free(adapter);
- fprintf(stderr, "Unexpected error %d when registering adapter %d\n",
- ret, *id);
- }
-out:
- return ret;
-}
-
-uint16_t css_build_subchannel_id(SubchDev *sch)
-{
- if (channel_subsys.max_cssid > 0) {
- return (sch->cssid << 8) | (1 << 3) | (sch->ssid << 1) | 1;
- }
- return (sch->ssid << 1) | 1;
-}
-
-static void css_inject_io_interrupt(SubchDev *sch)
-{
- uint8_t isc = (sch->curr_status.pmcw.flags & PMCW_FLAGS_MASK_ISC) >> 11;
-
- trace_css_io_interrupt(sch->cssid, sch->ssid, sch->schid,
- sch->curr_status.pmcw.intparm, isc, "");
- s390_io_interrupt(css_build_subchannel_id(sch),
- sch->schid,
- sch->curr_status.pmcw.intparm,
- isc << 27);
-}
-
-void css_conditional_io_interrupt(SubchDev *sch)
-{
- /*
- * If the subchannel is not currently status pending, make it pending
- * with alert status.
- */
- if (!(sch->curr_status.scsw.ctrl & SCSW_STCTL_STATUS_PEND)) {
- uint8_t isc = (sch->curr_status.pmcw.flags & PMCW_FLAGS_MASK_ISC) >> 11;
-
- trace_css_io_interrupt(sch->cssid, sch->ssid, sch->schid,
- sch->curr_status.pmcw.intparm, isc,
- "(unsolicited)");
- sch->curr_status.scsw.ctrl &= ~SCSW_CTRL_MASK_STCTL;
- sch->curr_status.scsw.ctrl |=
- SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND;
- /* Inject an I/O interrupt. */
- s390_io_interrupt(css_build_subchannel_id(sch),
- sch->schid,
- sch->curr_status.pmcw.intparm,
- isc << 27);
- }
-}
-
-void css_adapter_interrupt(uint8_t isc)
-{
- uint32_t io_int_word = (isc << 27) | IO_INT_WORD_AI;
-
- trace_css_adapter_interrupt(isc);
- s390_io_interrupt(0, 0, 0, io_int_word);
-}
-
-static void sch_handle_clear_func(SubchDev *sch)
-{
- PMCW *p = &sch->curr_status.pmcw;
- SCSW *s = &sch->curr_status.scsw;
- int path;
-
- /* Path management: In our simple css, we always choose the only path. */
- path = 0x80;
-
- /* Reset values prior to 'issuing the clear signal'. */
- p->lpum = 0;
- p->pom = 0xff;
- s->flags &= ~SCSW_FLAGS_MASK_PNO;
-
- /* We always 'attempt to issue the clear signal', and we always succeed. */
- sch->channel_prog = 0x0;
- sch->last_cmd_valid = false;
- s->ctrl &= ~SCSW_ACTL_CLEAR_PEND;
- s->ctrl |= SCSW_STCTL_STATUS_PEND;
-
- s->dstat = 0;
- s->cstat = 0;
- p->lpum = path;
-
-}
-
-static void sch_handle_halt_func(SubchDev *sch)
-{
-
- PMCW *p = &sch->curr_status.pmcw;
- SCSW *s = &sch->curr_status.scsw;
- hwaddr curr_ccw = sch->channel_prog;
- int path;
-
- /* Path management: In our simple css, we always choose the only path. */
- path = 0x80;
-
- /* We always 'attempt to issue the halt signal', and we always succeed. */
- sch->channel_prog = 0x0;
- sch->last_cmd_valid = false;
- s->ctrl &= ~SCSW_ACTL_HALT_PEND;
- s->ctrl |= SCSW_STCTL_STATUS_PEND;
-
- if ((s->ctrl & (SCSW_ACTL_SUBCH_ACTIVE | SCSW_ACTL_DEVICE_ACTIVE)) ||
- !((s->ctrl & SCSW_ACTL_START_PEND) ||
- (s->ctrl & SCSW_ACTL_SUSP))) {
- s->dstat = SCSW_DSTAT_DEVICE_END;
- }
- if ((s->ctrl & (SCSW_ACTL_SUBCH_ACTIVE | SCSW_ACTL_DEVICE_ACTIVE)) ||
- (s->ctrl & SCSW_ACTL_SUSP)) {
- s->cpa = curr_ccw + 8;
- }
- s->cstat = 0;
- p->lpum = path;
-
-}
-
-static void copy_sense_id_to_guest(SenseId *dest, SenseId *src)
-{
- int i;
-
- dest->reserved = src->reserved;
- dest->cu_type = cpu_to_be16(src->cu_type);
- dest->cu_model = src->cu_model;
- dest->dev_type = cpu_to_be16(src->dev_type);
- dest->dev_model = src->dev_model;
- dest->unused = src->unused;
- for (i = 0; i < ARRAY_SIZE(dest->ciw); i++) {
- dest->ciw[i].type = src->ciw[i].type;
- dest->ciw[i].command = src->ciw[i].command;
- dest->ciw[i].count = cpu_to_be16(src->ciw[i].count);
- }
-}
-
-static CCW1 copy_ccw_from_guest(hwaddr addr, bool fmt1)
-{
- CCW0 tmp0;
- CCW1 tmp1;
- CCW1 ret;
-
- if (fmt1) {
- cpu_physical_memory_read(addr, &tmp1, sizeof(tmp1));
- ret.cmd_code = tmp1.cmd_code;
- ret.flags = tmp1.flags;
- ret.count = be16_to_cpu(tmp1.count);
- ret.cda = be32_to_cpu(tmp1.cda);
- } else {
- cpu_physical_memory_read(addr, &tmp0, sizeof(tmp0));
- ret.cmd_code = tmp0.cmd_code;
- ret.flags = tmp0.flags;
- ret.count = be16_to_cpu(tmp0.count);
- ret.cda = be16_to_cpu(tmp0.cda1) | (tmp0.cda0 << 16);
- if ((ret.cmd_code & 0x0f) == CCW_CMD_TIC) {
- ret.cmd_code &= 0x0f;
- }
- }
- return ret;
-}
-
-static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr,
- bool suspend_allowed)
-{
- int ret;
- bool check_len;
- int len;
- CCW1 ccw;
-
- if (!ccw_addr) {
- return -EIO;
- }
-
- /* Translate everything to format-1 ccws - the information is the same. */
- ccw = copy_ccw_from_guest(ccw_addr, sch->ccw_fmt_1);
-
- /* Check for invalid command codes. */
- if ((ccw.cmd_code & 0x0f) == 0) {
- return -EINVAL;
- }
- if (((ccw.cmd_code & 0x0f) == CCW_CMD_TIC) &&
- ((ccw.cmd_code & 0xf0) != 0)) {
- return -EINVAL;
- }
- if (!sch->ccw_fmt_1 && (ccw.count == 0) &&
- (ccw.cmd_code != CCW_CMD_TIC)) {
- return -EINVAL;
- }
-
- if (ccw.flags & CCW_FLAG_SUSPEND) {
- return suspend_allowed ? -EINPROGRESS : -EINVAL;
- }
-
- check_len = !((ccw.flags & CCW_FLAG_SLI) && !(ccw.flags & CCW_FLAG_DC));
-
- if (!ccw.cda) {
- if (sch->ccw_no_data_cnt == 255) {
- return -EINVAL;
- }
- sch->ccw_no_data_cnt++;
- }
-
- /* Look at the command. */
- switch (ccw.cmd_code) {
- case CCW_CMD_NOOP:
- /* Nothing to do. */
- ret = 0;
- break;
- case CCW_CMD_BASIC_SENSE:
- if (check_len) {
- if (ccw.count != sizeof(sch->sense_data)) {
- ret = -EINVAL;
- break;
- }
- }
- len = MIN(ccw.count, sizeof(sch->sense_data));
- cpu_physical_memory_write(ccw.cda, sch->sense_data, len);
- sch->curr_status.scsw.count = ccw.count - len;
- memset(sch->sense_data, 0, sizeof(sch->sense_data));
- ret = 0;
- break;
- case CCW_CMD_SENSE_ID:
- {
- SenseId sense_id;
-
- copy_sense_id_to_guest(&sense_id, &sch->id);
- /* Sense ID information is device specific. */
- if (check_len) {
- if (ccw.count != sizeof(sense_id)) {
- ret = -EINVAL;
- break;
- }
- }
- len = MIN(ccw.count, sizeof(sense_id));
- /*
- * Only indicate 0xff in the first sense byte if we actually
- * have enough place to store at least bytes 0-3.
- */
- if (len >= 4) {
- sense_id.reserved = 0xff;
- } else {
- sense_id.reserved = 0;
- }
- cpu_physical_memory_write(ccw.cda, &sense_id, len);
- sch->curr_status.scsw.count = ccw.count - len;
- ret = 0;
- break;
- }
- case CCW_CMD_TIC:
- if (sch->last_cmd_valid && (sch->last_cmd.cmd_code == CCW_CMD_TIC)) {
- ret = -EINVAL;
- break;
- }
- if (ccw.flags & (CCW_FLAG_CC | CCW_FLAG_DC)) {
- ret = -EINVAL;
- break;
- }
- sch->channel_prog = ccw.cda;
- ret = -EAGAIN;
- break;
- default:
- if (sch->ccw_cb) {
- /* Handle device specific commands. */
- ret = sch->ccw_cb(sch, ccw);
- } else {
- ret = -ENOSYS;
- }
- break;
- }
- sch->last_cmd = ccw;
- sch->last_cmd_valid = true;
- if (ret == 0) {
- if (ccw.flags & CCW_FLAG_CC) {
- sch->channel_prog += 8;
- ret = -EAGAIN;
- }
- }
-
- return ret;
-}
-
-static void sch_handle_start_func(SubchDev *sch, ORB *orb)
-{
-
- PMCW *p = &sch->curr_status.pmcw;
- SCSW *s = &sch->curr_status.scsw;
- int path;
- int ret;
- bool suspend_allowed;
-
- /* Path management: In our simple css, we always choose the only path. */
- path = 0x80;
-
- if (!(s->ctrl & SCSW_ACTL_SUSP)) {
- s->cstat = 0;
- s->dstat = 0;
- /* Look at the orb and try to execute the channel program. */
- assert(orb != NULL); /* resume does not pass an orb */
- p->intparm = orb->intparm;
- if (!(orb->lpm & path)) {
- /* Generate a deferred cc 3 condition. */
- s->flags |= SCSW_FLAGS_MASK_CC;
- s->ctrl &= ~SCSW_CTRL_MASK_STCTL;
- s->ctrl |= (SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND);
- return;
- }
- sch->ccw_fmt_1 = !!(orb->ctrl0 & ORB_CTRL0_MASK_FMT);
- sch->ccw_no_data_cnt = 0;
- suspend_allowed = !!(orb->ctrl0 & ORB_CTRL0_MASK_SPND);
- } else {
- s->ctrl &= ~(SCSW_ACTL_SUSP | SCSW_ACTL_RESUME_PEND);
- /* The channel program had been suspended before. */
- suspend_allowed = true;
- }
- sch->last_cmd_valid = false;
- do {
- ret = css_interpret_ccw(sch, sch->channel_prog, suspend_allowed);
- switch (ret) {
- case -EAGAIN:
- /* ccw chain, continue processing */
- break;
- case 0:
- /* success */
- s->ctrl &= ~SCSW_ACTL_START_PEND;
- s->ctrl &= ~SCSW_CTRL_MASK_STCTL;
- s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY |
- SCSW_STCTL_STATUS_PEND;
- s->dstat = SCSW_DSTAT_CHANNEL_END | SCSW_DSTAT_DEVICE_END;
- s->cpa = sch->channel_prog + 8;
- break;
- case -ENOSYS:
- /* unsupported command, generate unit check (command reject) */
- s->ctrl &= ~SCSW_ACTL_START_PEND;
- s->dstat = SCSW_DSTAT_UNIT_CHECK;
- /* Set sense bit 0 in ecw0. */
- sch->sense_data[0] = 0x80;
- s->ctrl &= ~SCSW_CTRL_MASK_STCTL;
- s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY |
- SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND;
- s->cpa = sch->channel_prog + 8;
- break;
- case -EFAULT:
- /* memory problem, generate channel data check */
- s->ctrl &= ~SCSW_ACTL_START_PEND;
- s->cstat = SCSW_CSTAT_DATA_CHECK;
- s->ctrl &= ~SCSW_CTRL_MASK_STCTL;
- s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY |
- SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND;
- s->cpa = sch->channel_prog + 8;
- break;
- case -EBUSY:
- /* subchannel busy, generate deferred cc 1 */
- s->flags &= ~SCSW_FLAGS_MASK_CC;
- s->flags |= (1 << 8);
- s->ctrl &= ~SCSW_CTRL_MASK_STCTL;
- s->ctrl |= SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND;
- break;
- case -EINPROGRESS:
- /* channel program has been suspended */
- s->ctrl &= ~SCSW_ACTL_START_PEND;
- s->ctrl |= SCSW_ACTL_SUSP;
- break;
- default:
- /* error, generate channel program check */
- s->ctrl &= ~SCSW_ACTL_START_PEND;
- s->cstat = SCSW_CSTAT_PROG_CHECK;
- s->ctrl &= ~SCSW_CTRL_MASK_STCTL;
- s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY |
- SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND;
- s->cpa = sch->channel_prog + 8;
- break;
- }
- } while (ret == -EAGAIN);
-
-}
-
-/*
- * On real machines, this would run asynchronously to the main vcpus.
- * We might want to make some parts of the ssch handling (interpreting
- * read/writes) asynchronous later on if we start supporting more than
- * our current very simple devices.
- */
-static void do_subchannel_work(SubchDev *sch, ORB *orb)
-{
-
- SCSW *s = &sch->curr_status.scsw;
-
- if (s->ctrl & SCSW_FCTL_CLEAR_FUNC) {
- sch_handle_clear_func(sch);
- } else if (s->ctrl & SCSW_FCTL_HALT_FUNC) {
- sch_handle_halt_func(sch);
- } else if (s->ctrl & SCSW_FCTL_START_FUNC) {
- sch_handle_start_func(sch, orb);
- } else {
- /* Cannot happen. */
- return;
- }
- css_inject_io_interrupt(sch);
-}
-
-static void copy_pmcw_to_guest(PMCW *dest, const PMCW *src)
-{
- int i;
-
- dest->intparm = cpu_to_be32(src->intparm);
- dest->flags = cpu_to_be16(src->flags);
- dest->devno = cpu_to_be16(src->devno);
- dest->lpm = src->lpm;
- dest->pnom = src->pnom;
- dest->lpum = src->lpum;
- dest->pim = src->pim;
- dest->mbi = cpu_to_be16(src->mbi);
- dest->pom = src->pom;
- dest->pam = src->pam;
- for (i = 0; i < ARRAY_SIZE(dest->chpid); i++) {
- dest->chpid[i] = src->chpid[i];
- }
- dest->chars = cpu_to_be32(src->chars);
-}
-
-static void copy_scsw_to_guest(SCSW *dest, const SCSW *src)
-{
- dest->flags = cpu_to_be16(src->flags);
- dest->ctrl = cpu_to_be16(src->ctrl);
- dest->cpa = cpu_to_be32(src->cpa);
- dest->dstat = src->dstat;
- dest->cstat = src->cstat;
- dest->count = cpu_to_be16(src->count);
-}
-
-static void copy_schib_to_guest(SCHIB *dest, const SCHIB *src)
-{
- int i;
-
- copy_pmcw_to_guest(&dest->pmcw, &src->pmcw);
- copy_scsw_to_guest(&dest->scsw, &src->scsw);
- dest->mba = cpu_to_be64(src->mba);
- for (i = 0; i < ARRAY_SIZE(dest->mda); i++) {
- dest->mda[i] = src->mda[i];
- }
-}
-
-int css_do_stsch(SubchDev *sch, SCHIB *schib)
-{
- /* Use current status. */
- copy_schib_to_guest(schib, &sch->curr_status);
- return 0;
-}
-
-static void copy_pmcw_from_guest(PMCW *dest, const PMCW *src)
-{
- int i;
-
- dest->intparm = be32_to_cpu(src->intparm);
- dest->flags = be16_to_cpu(src->flags);
- dest->devno = be16_to_cpu(src->devno);
- dest->lpm = src->lpm;
- dest->pnom = src->pnom;
- dest->lpum = src->lpum;
- dest->pim = src->pim;
- dest->mbi = be16_to_cpu(src->mbi);
- dest->pom = src->pom;
- dest->pam = src->pam;
- for (i = 0; i < ARRAY_SIZE(dest->chpid); i++) {
- dest->chpid[i] = src->chpid[i];
- }
- dest->chars = be32_to_cpu(src->chars);
-}
-
-static void copy_scsw_from_guest(SCSW *dest, const SCSW *src)
-{
- dest->flags = be16_to_cpu(src->flags);
- dest->ctrl = be16_to_cpu(src->ctrl);
- dest->cpa = be32_to_cpu(src->cpa);
- dest->dstat = src->dstat;
- dest->cstat = src->cstat;
- dest->count = be16_to_cpu(src->count);
-}
-
-static void copy_schib_from_guest(SCHIB *dest, const SCHIB *src)
-{
- int i;
-
- copy_pmcw_from_guest(&dest->pmcw, &src->pmcw);
- copy_scsw_from_guest(&dest->scsw, &src->scsw);
- dest->mba = be64_to_cpu(src->mba);
- for (i = 0; i < ARRAY_SIZE(dest->mda); i++) {
- dest->mda[i] = src->mda[i];
- }
-}
-
-int css_do_msch(SubchDev *sch, const SCHIB *orig_schib)
-{
- SCSW *s = &sch->curr_status.scsw;
- PMCW *p = &sch->curr_status.pmcw;
- uint16_t oldflags;
- int ret;
- SCHIB schib;
-
- if (!(sch->curr_status.pmcw.flags & PMCW_FLAGS_MASK_DNV)) {
- ret = 0;
- goto out;
- }
-
- if (s->ctrl & SCSW_STCTL_STATUS_PEND) {
- ret = -EINPROGRESS;
- goto out;
- }
-
- if (s->ctrl &
- (SCSW_FCTL_START_FUNC|SCSW_FCTL_HALT_FUNC|SCSW_FCTL_CLEAR_FUNC)) {
- ret = -EBUSY;
- goto out;
- }
-
- copy_schib_from_guest(&schib, orig_schib);
- /* Only update the program-modifiable fields. */
- p->intparm = schib.pmcw.intparm;
- oldflags = p->flags;
- p->flags &= ~(PMCW_FLAGS_MASK_ISC | PMCW_FLAGS_MASK_ENA |
- PMCW_FLAGS_MASK_LM | PMCW_FLAGS_MASK_MME |
- PMCW_FLAGS_MASK_MP);
- p->flags |= schib.pmcw.flags &
- (PMCW_FLAGS_MASK_ISC | PMCW_FLAGS_MASK_ENA |
- PMCW_FLAGS_MASK_LM | PMCW_FLAGS_MASK_MME |
- PMCW_FLAGS_MASK_MP);
- p->lpm = schib.pmcw.lpm;
- p->mbi = schib.pmcw.mbi;
- p->pom = schib.pmcw.pom;
- p->chars &= ~(PMCW_CHARS_MASK_MBFC | PMCW_CHARS_MASK_CSENSE);
- p->chars |= schib.pmcw.chars &
- (PMCW_CHARS_MASK_MBFC | PMCW_CHARS_MASK_CSENSE);
- sch->curr_status.mba = schib.mba;
-
- /* Has the channel been disabled? */
- if (sch->disable_cb && (oldflags & PMCW_FLAGS_MASK_ENA) != 0
- && (p->flags & PMCW_FLAGS_MASK_ENA) == 0) {
- sch->disable_cb(sch);
- }
-
- ret = 0;
-
-out:
- return ret;
-}
-
-int css_do_xsch(SubchDev *sch)
-{
- SCSW *s = &sch->curr_status.scsw;
- PMCW *p = &sch->curr_status.pmcw;
- int ret;
-
- if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) {
- ret = -ENODEV;
- goto out;
- }
-
- if (!(s->ctrl & SCSW_CTRL_MASK_FCTL) ||
- ((s->ctrl & SCSW_CTRL_MASK_FCTL) != SCSW_FCTL_START_FUNC) ||
- (!(s->ctrl &
- (SCSW_ACTL_RESUME_PEND | SCSW_ACTL_START_PEND | SCSW_ACTL_SUSP))) ||
- (s->ctrl & SCSW_ACTL_SUBCH_ACTIVE)) {
- ret = -EINPROGRESS;
- goto out;
- }
-
- if (s->ctrl & SCSW_CTRL_MASK_STCTL) {
- ret = -EBUSY;
- goto out;
- }
-
- /* Cancel the current operation. */
- s->ctrl &= ~(SCSW_FCTL_START_FUNC |
- SCSW_ACTL_RESUME_PEND |
- SCSW_ACTL_START_PEND |
- SCSW_ACTL_SUSP);
- sch->channel_prog = 0x0;
- sch->last_cmd_valid = false;
- s->dstat = 0;
- s->cstat = 0;
- ret = 0;
-
-out:
- return ret;
-}
-
-int css_do_csch(SubchDev *sch)
-{
- SCSW *s = &sch->curr_status.scsw;
- PMCW *p = &sch->curr_status.pmcw;
- int ret;
-
- if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) {
- ret = -ENODEV;
- goto out;
- }
-
- /* Trigger the clear function. */
- s->ctrl &= ~(SCSW_CTRL_MASK_FCTL | SCSW_CTRL_MASK_ACTL);
- s->ctrl |= SCSW_FCTL_CLEAR_FUNC | SCSW_ACTL_CLEAR_PEND;
-
- do_subchannel_work(sch, NULL);
- ret = 0;
-
-out:
- return ret;
-}
-
-int css_do_hsch(SubchDev *sch)
-{
- SCSW *s = &sch->curr_status.scsw;
- PMCW *p = &sch->curr_status.pmcw;
- int ret;
-
- if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) {
- ret = -ENODEV;
- goto out;
- }
-
- if (((s->ctrl & SCSW_CTRL_MASK_STCTL) == SCSW_STCTL_STATUS_PEND) ||
- (s->ctrl & (SCSW_STCTL_PRIMARY |
- SCSW_STCTL_SECONDARY |
- SCSW_STCTL_ALERT))) {
- ret = -EINPROGRESS;
- goto out;
- }
-
- if (s->ctrl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) {
- ret = -EBUSY;
- goto out;
- }
-
- /* Trigger the halt function. */
- s->ctrl |= SCSW_FCTL_HALT_FUNC;
- s->ctrl &= ~SCSW_FCTL_START_FUNC;
- if (((s->ctrl & SCSW_CTRL_MASK_ACTL) ==
- (SCSW_ACTL_SUBCH_ACTIVE | SCSW_ACTL_DEVICE_ACTIVE)) &&
- ((s->ctrl & SCSW_CTRL_MASK_STCTL) == SCSW_STCTL_INTERMEDIATE)) {
- s->ctrl &= ~SCSW_STCTL_STATUS_PEND;
- }
- s->ctrl |= SCSW_ACTL_HALT_PEND;
-
- do_subchannel_work(sch, NULL);
- ret = 0;
-
-out:
- return ret;
-}
-
-static void css_update_chnmon(SubchDev *sch)
-{
- if (!(sch->curr_status.pmcw.flags & PMCW_FLAGS_MASK_MME)) {
- /* Not active. */
- return;
- }
- /* The counter is conveniently located at the beginning of the struct. */
- if (sch->curr_status.pmcw.chars & PMCW_CHARS_MASK_MBFC) {
- /* Format 1, per-subchannel area. */
- uint32_t count;
-
- count = address_space_ldl(&address_space_memory,
- sch->curr_status.mba,
- MEMTXATTRS_UNSPECIFIED,
- NULL);
- count++;
- address_space_stl(&address_space_memory, sch->curr_status.mba, count,
- MEMTXATTRS_UNSPECIFIED, NULL);
- } else {
- /* Format 0, global area. */
- uint32_t offset;
- uint16_t count;
-
- offset = sch->curr_status.pmcw.mbi << 5;
- count = address_space_lduw(&address_space_memory,
- channel_subsys.chnmon_area + offset,
- MEMTXATTRS_UNSPECIFIED,
- NULL);
- count++;
- address_space_stw(&address_space_memory,
- channel_subsys.chnmon_area + offset, count,
- MEMTXATTRS_UNSPECIFIED, NULL);
- }
-}
-
-int css_do_ssch(SubchDev *sch, ORB *orb)
-{
- SCSW *s = &sch->curr_status.scsw;
- PMCW *p = &sch->curr_status.pmcw;
- int ret;
-
- if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) {
- ret = -ENODEV;
- goto out;
- }
-
- if (s->ctrl & SCSW_STCTL_STATUS_PEND) {
- ret = -EINPROGRESS;
- goto out;
- }
-
- if (s->ctrl & (SCSW_FCTL_START_FUNC |
- SCSW_FCTL_HALT_FUNC |
- SCSW_FCTL_CLEAR_FUNC)) {
- ret = -EBUSY;
- goto out;
- }
-
- /* If monitoring is active, update counter. */
- if (channel_subsys.chnmon_active) {
- css_update_chnmon(sch);
- }
- sch->channel_prog = orb->cpa;
- /* Trigger the start function. */
- s->ctrl |= (SCSW_FCTL_START_FUNC | SCSW_ACTL_START_PEND);
- s->flags &= ~SCSW_FLAGS_MASK_PNO;
-
- do_subchannel_work(sch, orb);
- ret = 0;
-
-out:
- return ret;
-}
-
-static void copy_irb_to_guest(IRB *dest, const IRB *src, PMCW *pmcw,
- int *irb_len)
-{
- int i;
- uint16_t stctl = src->scsw.ctrl & SCSW_CTRL_MASK_STCTL;
- uint16_t actl = src->scsw.ctrl & SCSW_CTRL_MASK_ACTL;
-
- copy_scsw_to_guest(&dest->scsw, &src->scsw);
-
- for (i = 0; i < ARRAY_SIZE(dest->esw); i++) {
- dest->esw[i] = cpu_to_be32(src->esw[i]);
- }
- for (i = 0; i < ARRAY_SIZE(dest->ecw); i++) {
- dest->ecw[i] = cpu_to_be32(src->ecw[i]);
- }
- *irb_len = sizeof(*dest) - sizeof(dest->emw);
-
- /* extended measurements enabled? */
- if ((src->scsw.flags & SCSW_FLAGS_MASK_ESWF) ||
- !(pmcw->flags & PMCW_FLAGS_MASK_TF) ||
- !(pmcw->chars & PMCW_CHARS_MASK_XMWME)) {
- return;
- }
- /* extended measurements pending? */
- if (!(stctl & SCSW_STCTL_STATUS_PEND)) {
- return;
- }
- if ((stctl & SCSW_STCTL_PRIMARY) ||
- (stctl == SCSW_STCTL_SECONDARY) ||
- ((stctl & SCSW_STCTL_INTERMEDIATE) && (actl & SCSW_ACTL_SUSP))) {
- for (i = 0; i < ARRAY_SIZE(dest->emw); i++) {
- dest->emw[i] = cpu_to_be32(src->emw[i]);
- }
- }
- *irb_len = sizeof(*dest);
-}
-
-int css_do_tsch_get_irb(SubchDev *sch, IRB *target_irb, int *irb_len)
-{
- SCSW *s = &sch->curr_status.scsw;
- PMCW *p = &sch->curr_status.pmcw;
- uint16_t stctl;
- IRB irb;
-
- if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) {
- return 3;
- }
-
- stctl = s->ctrl & SCSW_CTRL_MASK_STCTL;
-
- /* Prepare the irb for the guest. */
- memset(&irb, 0, sizeof(IRB));
-
- /* Copy scsw from current status. */
- memcpy(&irb.scsw, s, sizeof(SCSW));
- if (stctl & SCSW_STCTL_STATUS_PEND) {
- if (s->cstat & (SCSW_CSTAT_DATA_CHECK |
- SCSW_CSTAT_CHN_CTRL_CHK |
- SCSW_CSTAT_INTF_CTRL_CHK)) {
- irb.scsw.flags |= SCSW_FLAGS_MASK_ESWF;
- irb.esw[0] = 0x04804000;
- } else {
- irb.esw[0] = 0x00800000;
- }
- /* If a unit check is pending, copy sense data. */
- if ((s->dstat & SCSW_DSTAT_UNIT_CHECK) &&
- (p->chars & PMCW_CHARS_MASK_CSENSE)) {
- int i;
-
- irb.scsw.flags |= SCSW_FLAGS_MASK_ESWF | SCSW_FLAGS_MASK_ECTL;
- /* Attention: sense_data is already BE! */
- memcpy(irb.ecw, sch->sense_data, sizeof(sch->sense_data));
- for (i = 0; i < ARRAY_SIZE(irb.ecw); i++) {
- irb.ecw[i] = be32_to_cpu(irb.ecw[i]);
- }
- irb.esw[1] = 0x01000000 | (sizeof(sch->sense_data) << 8);
- }
- }
- /* Store the irb to the guest. */
- copy_irb_to_guest(target_irb, &irb, p, irb_len);
-
- return ((stctl & SCSW_STCTL_STATUS_PEND) == 0);
-}
-
-void css_do_tsch_update_subch(SubchDev *sch)
-{
- SCSW *s = &sch->curr_status.scsw;
- PMCW *p = &sch->curr_status.pmcw;
- uint16_t stctl;
- uint16_t fctl;
- uint16_t actl;
-
- stctl = s->ctrl & SCSW_CTRL_MASK_STCTL;
- fctl = s->ctrl & SCSW_CTRL_MASK_FCTL;
- actl = s->ctrl & SCSW_CTRL_MASK_ACTL;
-
- /* Clear conditions on subchannel, if applicable. */
- if (stctl & SCSW_STCTL_STATUS_PEND) {
- s->ctrl &= ~SCSW_CTRL_MASK_STCTL;
- if ((stctl != (SCSW_STCTL_INTERMEDIATE | SCSW_STCTL_STATUS_PEND)) ||
- ((fctl & SCSW_FCTL_HALT_FUNC) &&
- (actl & SCSW_ACTL_SUSP))) {
- s->ctrl &= ~SCSW_CTRL_MASK_FCTL;
- }
- if (stctl != (SCSW_STCTL_INTERMEDIATE | SCSW_STCTL_STATUS_PEND)) {
- s->flags &= ~SCSW_FLAGS_MASK_PNO;
- s->ctrl &= ~(SCSW_ACTL_RESUME_PEND |
- SCSW_ACTL_START_PEND |
- SCSW_ACTL_HALT_PEND |
- SCSW_ACTL_CLEAR_PEND |
- SCSW_ACTL_SUSP);
- } else {
- if ((actl & SCSW_ACTL_SUSP) &&
- (fctl & SCSW_FCTL_START_FUNC)) {
- s->flags &= ~SCSW_FLAGS_MASK_PNO;
- if (fctl & SCSW_FCTL_HALT_FUNC) {
- s->ctrl &= ~(SCSW_ACTL_RESUME_PEND |
- SCSW_ACTL_START_PEND |
- SCSW_ACTL_HALT_PEND |
- SCSW_ACTL_CLEAR_PEND |
- SCSW_ACTL_SUSP);
- } else {
- s->ctrl &= ~SCSW_ACTL_RESUME_PEND;
- }
- }
- }
- /* Clear pending sense data. */
- if (p->chars & PMCW_CHARS_MASK_CSENSE) {
- memset(sch->sense_data, 0 , sizeof(sch->sense_data));
- }
- }
-}
-
-static void copy_crw_to_guest(CRW *dest, const CRW *src)
-{
- dest->flags = cpu_to_be16(src->flags);
- dest->rsid = cpu_to_be16(src->rsid);
-}
-
-int css_do_stcrw(CRW *crw)
-{
- CrwContainer *crw_cont;
- int ret;
-
- crw_cont = QTAILQ_FIRST(&channel_subsys.pending_crws);
- if (crw_cont) {
- QTAILQ_REMOVE(&channel_subsys.pending_crws, crw_cont, sibling);
- copy_crw_to_guest(crw, &crw_cont->crw);
- g_free(crw_cont);
- ret = 0;
- } else {
- /* List was empty, turn crw machine checks on again. */
- memset(crw, 0, sizeof(*crw));
- channel_subsys.do_crw_mchk = true;
- ret = 1;
- }
-
- return ret;
-}
-
-static void copy_crw_from_guest(CRW *dest, const CRW *src)
-{
- dest->flags = be16_to_cpu(src->flags);
- dest->rsid = be16_to_cpu(src->rsid);
-}
-
-void css_undo_stcrw(CRW *crw)
-{
- CrwContainer *crw_cont;
-
- crw_cont = g_try_malloc0(sizeof(CrwContainer));
- if (!crw_cont) {
- channel_subsys.crws_lost = true;
- return;
- }
- copy_crw_from_guest(&crw_cont->crw, crw);
-
- QTAILQ_INSERT_HEAD(&channel_subsys.pending_crws, crw_cont, sibling);
-}
-
-int css_do_tpi(IOIntCode *int_code, int lowcore)
-{
- /* No pending interrupts for !KVM. */
- return 0;
- }
-
-int css_collect_chp_desc(int m, uint8_t cssid, uint8_t f_chpid, uint8_t l_chpid,
- int rfmt, void *buf)
-{
- int i, desc_size;
- uint32_t words[8];
- uint32_t chpid_type_word;
- CssImage *css;
-
- if (!m && !cssid) {
- css = channel_subsys.css[channel_subsys.default_cssid];
- } else {
- css = channel_subsys.css[cssid];
- }
- if (!css) {
- return 0;
- }
- desc_size = 0;
- for (i = f_chpid; i <= l_chpid; i++) {
- if (css->chpids[i].in_use) {
- chpid_type_word = 0x80000000 | (css->chpids[i].type << 8) | i;
- if (rfmt == 0) {
- words[0] = cpu_to_be32(chpid_type_word);
- words[1] = 0;
- memcpy(buf + desc_size, words, 8);
- desc_size += 8;
- } else if (rfmt == 1) {
- words[0] = cpu_to_be32(chpid_type_word);
- words[1] = 0;
- words[2] = 0;
- words[3] = 0;
- words[4] = 0;
- words[5] = 0;
- words[6] = 0;
- words[7] = 0;
- memcpy(buf + desc_size, words, 32);
- desc_size += 32;
- }
- }
- }
- return desc_size;
-}
-
-void css_do_schm(uint8_t mbk, int update, int dct, uint64_t mbo)
-{
- /* dct is currently ignored (not really meaningful for our devices) */
- /* TODO: Don't ignore mbk. */
- if (update && !channel_subsys.chnmon_active) {
- /* Enable measuring. */
- channel_subsys.chnmon_area = mbo;
- channel_subsys.chnmon_active = true;
- }
- if (!update && channel_subsys.chnmon_active) {
- /* Disable measuring. */
- channel_subsys.chnmon_area = 0;
- channel_subsys.chnmon_active = false;
- }
-}
-
-int css_do_rsch(SubchDev *sch)
-{
- SCSW *s = &sch->curr_status.scsw;
- PMCW *p = &sch->curr_status.pmcw;
- int ret;
-
- if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) {
- ret = -ENODEV;
- goto out;
- }
-
- if (s->ctrl & SCSW_STCTL_STATUS_PEND) {
- ret = -EINPROGRESS;
- goto out;
- }
-
- if (((s->ctrl & SCSW_CTRL_MASK_FCTL) != SCSW_FCTL_START_FUNC) ||
- (s->ctrl & SCSW_ACTL_RESUME_PEND) ||
- (!(s->ctrl & SCSW_ACTL_SUSP))) {
- ret = -EINVAL;
- goto out;
- }
-
- /* If monitoring is active, update counter. */
- if (channel_subsys.chnmon_active) {
- css_update_chnmon(sch);
- }
-
- s->ctrl |= SCSW_ACTL_RESUME_PEND;
- do_subchannel_work(sch, NULL);
- ret = 0;
-
-out:
- return ret;
-}
-
-int css_do_rchp(uint8_t cssid, uint8_t chpid)
-{
- uint8_t real_cssid;
-
- if (cssid > channel_subsys.max_cssid) {
- return -EINVAL;
- }
- if (channel_subsys.max_cssid == 0) {
- real_cssid = channel_subsys.default_cssid;
- } else {
- real_cssid = cssid;
- }
- if (!channel_subsys.css[real_cssid]) {
- return -EINVAL;
- }
-
- if (!channel_subsys.css[real_cssid]->chpids[chpid].in_use) {
- return -ENODEV;
- }
-
- if (!channel_subsys.css[real_cssid]->chpids[chpid].is_virtual) {
- fprintf(stderr,
- "rchp unsupported for non-virtual chpid %x.%02x!\n",
- real_cssid, chpid);
- return -ENODEV;
- }
-
- /* We don't really use a channel path, so we're done here. */
- css_queue_crw(CRW_RSC_CHP, CRW_ERC_INIT,
- channel_subsys.max_cssid > 0 ? 1 : 0, chpid);
- if (channel_subsys.max_cssid > 0) {
- css_queue_crw(CRW_RSC_CHP, CRW_ERC_INIT, 0, real_cssid << 8);
- }
- return 0;
-}
-
-bool css_schid_final(int m, uint8_t cssid, uint8_t ssid, uint16_t schid)
-{
- SubchSet *set;
- uint8_t real_cssid;
-
- real_cssid = (!m && (cssid == 0)) ? channel_subsys.default_cssid : cssid;
- if (real_cssid > MAX_CSSID || ssid > MAX_SSID ||
- !channel_subsys.css[real_cssid] ||
- !channel_subsys.css[real_cssid]->sch_set[ssid]) {
- return true;
- }
- set = channel_subsys.css[real_cssid]->sch_set[ssid];
- return schid > find_last_bit(set->schids_used,
- (MAX_SCHID + 1) / sizeof(unsigned long));
-}
-
-static int css_add_virtual_chpid(uint8_t cssid, uint8_t chpid, uint8_t type)
-{
- CssImage *css;
-
- trace_css_chpid_add(cssid, chpid, type);
- if (cssid > MAX_CSSID) {
- return -EINVAL;
- }
- css = channel_subsys.css[cssid];
- if (!css) {
- return -EINVAL;
- }
- if (css->chpids[chpid].in_use) {
- return -EEXIST;
- }
- css->chpids[chpid].in_use = 1;
- css->chpids[chpid].type = type;
- css->chpids[chpid].is_virtual = 1;
-
- css_generate_chp_crws(cssid, chpid);
-
- return 0;
-}
-
-void css_sch_build_virtual_schib(SubchDev *sch, uint8_t chpid, uint8_t type)
-{
- PMCW *p = &sch->curr_status.pmcw;
- SCSW *s = &sch->curr_status.scsw;
- int i;
- CssImage *css = channel_subsys.css[sch->cssid];
-
- assert(css != NULL);
- memset(p, 0, sizeof(PMCW));
- p->flags |= PMCW_FLAGS_MASK_DNV;
- p->devno = sch->devno;
- /* single path */
- p->pim = 0x80;
- p->pom = 0xff;
- p->pam = 0x80;
- p->chpid[0] = chpid;
- if (!css->chpids[chpid].in_use) {
- css_add_virtual_chpid(sch->cssid, chpid, type);
- }
-
- memset(s, 0, sizeof(SCSW));
- sch->curr_status.mba = 0;
- for (i = 0; i < ARRAY_SIZE(sch->curr_status.mda); i++) {
- sch->curr_status.mda[i] = 0;
- }
-}
-
-SubchDev *css_find_subch(uint8_t m, uint8_t cssid, uint8_t ssid, uint16_t schid)
-{
- uint8_t real_cssid;
-
- real_cssid = (!m && (cssid == 0)) ? channel_subsys.default_cssid : cssid;
-
- if (!channel_subsys.css[real_cssid]) {
- return NULL;
- }
-
- if (!channel_subsys.css[real_cssid]->sch_set[ssid]) {
- return NULL;
- }
-
- return channel_subsys.css[real_cssid]->sch_set[ssid]->sch[schid];
-}
-
-bool css_subch_visible(SubchDev *sch)
-{
- if (sch->ssid > channel_subsys.max_ssid) {
- return false;
- }
-
- if (sch->cssid != channel_subsys.default_cssid) {
- return (channel_subsys.max_cssid > 0);
- }
-
- return true;
-}
-
-bool css_present(uint8_t cssid)
-{
- return (channel_subsys.css[cssid] != NULL);
-}
-
-bool css_devno_used(uint8_t cssid, uint8_t ssid, uint16_t devno)
-{
- if (!channel_subsys.css[cssid]) {
- return false;
- }
- if (!channel_subsys.css[cssid]->sch_set[ssid]) {
- return false;
- }
-
- return !!test_bit(devno,
- channel_subsys.css[cssid]->sch_set[ssid]->devnos_used);
-}
-
-void css_subch_assign(uint8_t cssid, uint8_t ssid, uint16_t schid,
- uint16_t devno, SubchDev *sch)
-{
- CssImage *css;
- SubchSet *s_set;
-
- trace_css_assign_subch(sch ? "assign" : "deassign", cssid, ssid, schid,
- devno);
- if (!channel_subsys.css[cssid]) {
- fprintf(stderr,
- "Suspicious call to %s (%x.%x.%04x) for non-existing css!\n",
- __func__, cssid, ssid, schid);
- return;
- }
- css = channel_subsys.css[cssid];
-
- if (!css->sch_set[ssid]) {
- css->sch_set[ssid] = g_malloc0(sizeof(SubchSet));
- }
- s_set = css->sch_set[ssid];
-
- s_set->sch[schid] = sch;
- if (sch) {
- set_bit(schid, s_set->schids_used);
- set_bit(devno, s_set->devnos_used);
- } else {
- clear_bit(schid, s_set->schids_used);
- clear_bit(devno, s_set->devnos_used);
- }
-}
-
-void css_queue_crw(uint8_t rsc, uint8_t erc, int chain, uint16_t rsid)
-{
- CrwContainer *crw_cont;
-
- trace_css_crw(rsc, erc, rsid, chain ? "(chained)" : "");
- /* TODO: Maybe use a static crw pool? */
- crw_cont = g_try_malloc0(sizeof(CrwContainer));
- if (!crw_cont) {
- channel_subsys.crws_lost = true;
- return;
- }
- crw_cont->crw.flags = (rsc << 8) | erc;
- if (chain) {
- crw_cont->crw.flags |= CRW_FLAGS_MASK_C;
- }
- crw_cont->crw.rsid = rsid;
- if (channel_subsys.crws_lost) {
- crw_cont->crw.flags |= CRW_FLAGS_MASK_R;
- channel_subsys.crws_lost = false;
- }
-
- QTAILQ_INSERT_TAIL(&channel_subsys.pending_crws, crw_cont, sibling);
-
- if (channel_subsys.do_crw_mchk) {
- channel_subsys.do_crw_mchk = false;
- /* Inject crw pending machine check. */
- s390_crw_mchk();
- }
-}
-
-void css_generate_sch_crws(uint8_t cssid, uint8_t ssid, uint16_t schid,
- int hotplugged, int add)
-{
- uint8_t guest_cssid;
- bool chain_crw;
-
- if (add && !hotplugged) {
- return;
- }
- if (channel_subsys.max_cssid == 0) {
- /* Default cssid shows up as 0. */
- guest_cssid = (cssid == channel_subsys.default_cssid) ? 0 : cssid;
- } else {
- /* Show real cssid to the guest. */
- guest_cssid = cssid;
- }
- /*
- * Only notify for higher subchannel sets/channel subsystems if the
- * guest has enabled it.
- */
- if ((ssid > channel_subsys.max_ssid) ||
- (guest_cssid > channel_subsys.max_cssid) ||
- ((channel_subsys.max_cssid == 0) &&
- (cssid != channel_subsys.default_cssid))) {
- return;
- }
- chain_crw = (channel_subsys.max_ssid > 0) ||
- (channel_subsys.max_cssid > 0);
- css_queue_crw(CRW_RSC_SUBCH, CRW_ERC_IPI, chain_crw ? 1 : 0, schid);
- if (chain_crw) {
- css_queue_crw(CRW_RSC_SUBCH, CRW_ERC_IPI, 0,
- (guest_cssid << 8) | (ssid << 4));
- }
-}
-
-void css_generate_chp_crws(uint8_t cssid, uint8_t chpid)
-{
- /* TODO */
-}
-
-void css_generate_css_crws(uint8_t cssid)
-{
- if (!channel_subsys.sei_pending) {
- css_queue_crw(CRW_RSC_CSS, 0, 0, cssid);
- }
- channel_subsys.sei_pending = true;
-}
-
-void css_clear_sei_pending(void)
-{
- channel_subsys.sei_pending = false;
-}
-
-int css_enable_mcsse(void)
-{
- trace_css_enable_facility("mcsse");
- channel_subsys.max_cssid = MAX_CSSID;
- return 0;
-}
-
-int css_enable_mss(void)
-{
- trace_css_enable_facility("mss");
- channel_subsys.max_ssid = MAX_SSID;
- return 0;
-}
-
-void subch_device_save(SubchDev *s, QEMUFile *f)
-{
- int i;
-
- qemu_put_byte(f, s->cssid);
- qemu_put_byte(f, s->ssid);
- qemu_put_be16(f, s->schid);
- qemu_put_be16(f, s->devno);
- qemu_put_byte(f, s->thinint_active);
- /* SCHIB */
- /* PMCW */
- qemu_put_be32(f, s->curr_status.pmcw.intparm);
- qemu_put_be16(f, s->curr_status.pmcw.flags);
- qemu_put_be16(f, s->curr_status.pmcw.devno);
- qemu_put_byte(f, s->curr_status.pmcw.lpm);
- qemu_put_byte(f, s->curr_status.pmcw.pnom);
- qemu_put_byte(f, s->curr_status.pmcw.lpum);
- qemu_put_byte(f, s->curr_status.pmcw.pim);
- qemu_put_be16(f, s->curr_status.pmcw.mbi);
- qemu_put_byte(f, s->curr_status.pmcw.pom);
- qemu_put_byte(f, s->curr_status.pmcw.pam);
- qemu_put_buffer(f, s->curr_status.pmcw.chpid, 8);
- qemu_put_be32(f, s->curr_status.pmcw.chars);
- /* SCSW */
- qemu_put_be16(f, s->curr_status.scsw.flags);
- qemu_put_be16(f, s->curr_status.scsw.ctrl);
- qemu_put_be32(f, s->curr_status.scsw.cpa);
- qemu_put_byte(f, s->curr_status.scsw.dstat);
- qemu_put_byte(f, s->curr_status.scsw.cstat);
- qemu_put_be16(f, s->curr_status.scsw.count);
- qemu_put_be64(f, s->curr_status.mba);
- qemu_put_buffer(f, s->curr_status.mda, 4);
- /* end SCHIB */
- qemu_put_buffer(f, s->sense_data, 32);
- qemu_put_be64(f, s->channel_prog);
- /* last cmd */
- qemu_put_byte(f, s->last_cmd.cmd_code);
- qemu_put_byte(f, s->last_cmd.flags);
- qemu_put_be16(f, s->last_cmd.count);
- qemu_put_be32(f, s->last_cmd.cda);
- qemu_put_byte(f, s->last_cmd_valid);
- qemu_put_byte(f, s->id.reserved);
- qemu_put_be16(f, s->id.cu_type);
- qemu_put_byte(f, s->id.cu_model);
- qemu_put_be16(f, s->id.dev_type);
- qemu_put_byte(f, s->id.dev_model);
- qemu_put_byte(f, s->id.unused);
- for (i = 0; i < ARRAY_SIZE(s->id.ciw); i++) {
- qemu_put_byte(f, s->id.ciw[i].type);
- qemu_put_byte(f, s->id.ciw[i].command);
- qemu_put_be16(f, s->id.ciw[i].count);
- }
- qemu_put_byte(f, s->ccw_fmt_1);
- qemu_put_byte(f, s->ccw_no_data_cnt);
-}
-
-int subch_device_load(SubchDev *s, QEMUFile *f)
-{
- int i;
-
- s->cssid = qemu_get_byte(f);
- s->ssid = qemu_get_byte(f);
- s->schid = qemu_get_be16(f);
- s->devno = qemu_get_be16(f);
- s->thinint_active = qemu_get_byte(f);
- /* SCHIB */
- /* PMCW */
- s->curr_status.pmcw.intparm = qemu_get_be32(f);
- s->curr_status.pmcw.flags = qemu_get_be16(f);
- s->curr_status.pmcw.devno = qemu_get_be16(f);
- s->curr_status.pmcw.lpm = qemu_get_byte(f);
- s->curr_status.pmcw.pnom = qemu_get_byte(f);
- s->curr_status.pmcw.lpum = qemu_get_byte(f);
- s->curr_status.pmcw.pim = qemu_get_byte(f);
- s->curr_status.pmcw.mbi = qemu_get_be16(f);
- s->curr_status.pmcw.pom = qemu_get_byte(f);
- s->curr_status.pmcw.pam = qemu_get_byte(f);
- qemu_get_buffer(f, s->curr_status.pmcw.chpid, 8);
- s->curr_status.pmcw.chars = qemu_get_be32(f);
- /* SCSW */
- s->curr_status.scsw.flags = qemu_get_be16(f);
- s->curr_status.scsw.ctrl = qemu_get_be16(f);
- s->curr_status.scsw.cpa = qemu_get_be32(f);
- s->curr_status.scsw.dstat = qemu_get_byte(f);
- s->curr_status.scsw.cstat = qemu_get_byte(f);
- s->curr_status.scsw.count = qemu_get_be16(f);
- s->curr_status.mba = qemu_get_be64(f);
- qemu_get_buffer(f, s->curr_status.mda, 4);
- /* end SCHIB */
- qemu_get_buffer(f, s->sense_data, 32);
- s->channel_prog = qemu_get_be64(f);
- /* last cmd */
- s->last_cmd.cmd_code = qemu_get_byte(f);
- s->last_cmd.flags = qemu_get_byte(f);
- s->last_cmd.count = qemu_get_be16(f);
- s->last_cmd.cda = qemu_get_be32(f);
- s->last_cmd_valid = qemu_get_byte(f);
- s->id.reserved = qemu_get_byte(f);
- s->id.cu_type = qemu_get_be16(f);
- s->id.cu_model = qemu_get_byte(f);
- s->id.dev_type = qemu_get_be16(f);
- s->id.dev_model = qemu_get_byte(f);
- s->id.unused = qemu_get_byte(f);
- for (i = 0; i < ARRAY_SIZE(s->id.ciw); i++) {
- s->id.ciw[i].type = qemu_get_byte(f);
- s->id.ciw[i].command = qemu_get_byte(f);
- s->id.ciw[i].count = qemu_get_be16(f);
- }
- s->ccw_fmt_1 = qemu_get_byte(f);
- s->ccw_no_data_cnt = qemu_get_byte(f);
- /*
- * Hack alert. We don't migrate the channel subsystem status (no
- * device!), but we need to find out if the guest enabled mss/mcss-e.
- * If the subchannel is enabled, it certainly was able to access it,
- * so adjust the max_ssid/max_cssid values for relevant ssid/cssid
- * values. This is not watertight, but better than nothing.
- */
- if (s->curr_status.pmcw.flags & PMCW_FLAGS_MASK_ENA) {
- if (s->ssid) {
- channel_subsys.max_ssid = MAX_SSID;
- }
- if (s->cssid != channel_subsys.default_cssid) {
- channel_subsys.max_cssid = MAX_CSSID;
- }
- }
- return 0;
-}
-
-void css_reset_sch(SubchDev *sch)
-{
- PMCW *p = &sch->curr_status.pmcw;
-
- if ((p->flags & PMCW_FLAGS_MASK_ENA) != 0 && sch->disable_cb) {
- sch->disable_cb(sch);
- }
-
- p->intparm = 0;
- p->flags &= ~(PMCW_FLAGS_MASK_ISC | PMCW_FLAGS_MASK_ENA |
- PMCW_FLAGS_MASK_LM | PMCW_FLAGS_MASK_MME |
- PMCW_FLAGS_MASK_MP | PMCW_FLAGS_MASK_TF);
- p->flags |= PMCW_FLAGS_MASK_DNV;
- p->devno = sch->devno;
- p->pim = 0x80;
- p->lpm = p->pim;
- p->pnom = 0;
- p->lpum = 0;
- p->mbi = 0;
- p->pom = 0xff;
- p->pam = 0x80;
- p->chars &= ~(PMCW_CHARS_MASK_MBFC | PMCW_CHARS_MASK_XMWME |
- PMCW_CHARS_MASK_CSENSE);
-
- memset(&sch->curr_status.scsw, 0, sizeof(sch->curr_status.scsw));
- sch->curr_status.mba = 0;
-
- sch->channel_prog = 0x0;
- sch->last_cmd_valid = false;
- sch->thinint_active = false;
-}
-
-void css_reset(void)
-{
- CrwContainer *crw_cont;
-
- /* Clean up monitoring. */
- channel_subsys.chnmon_active = false;
- channel_subsys.chnmon_area = 0;
-
- /* Clear pending CRWs. */
- while ((crw_cont = QTAILQ_FIRST(&channel_subsys.pending_crws))) {
- QTAILQ_REMOVE(&channel_subsys.pending_crws, crw_cont, sibling);
- g_free(crw_cont);
- }
- channel_subsys.sei_pending = false;
- channel_subsys.do_crw_mchk = true;
- channel_subsys.crws_lost = false;
-
- /* Reset maximum ids. */
- channel_subsys.max_cssid = 0;
- channel_subsys.max_ssid = 0;
-}
diff --git a/qemu/hw/s390x/css.h b/qemu/hw/s390x/css.h
deleted file mode 100644
index a320eea59..000000000
--- a/qemu/hw/s390x/css.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Channel subsystem structures and definitions.
- *
- * Copyright 2012 IBM Corp.
- * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or (at
- * your option) any later version. See the COPYING file in the top-level
- * directory.
- */
-
-#ifndef CSS_H
-#define CSS_H
-
-#include "hw/s390x/adapter.h"
-#include "hw/s390x/s390_flic.h"
-#include "ioinst.h"
-
-/* Channel subsystem constants. */
-#define MAX_SCHID 65535
-#define MAX_SSID 3
-#define MAX_CSSID 254 /* 255 is reserved */
-#define MAX_CHPID 255
-
-#define MAX_CIWS 62
-
-typedef struct CIW {
- uint8_t type;
- uint8_t command;
- uint16_t count;
-} QEMU_PACKED CIW;
-
-typedef struct SenseId {
- /* common part */
- uint8_t reserved; /* always 0x'FF' */
- uint16_t cu_type; /* control unit type */
- uint8_t cu_model; /* control unit model */
- uint16_t dev_type; /* device type */
- uint8_t dev_model; /* device model */
- uint8_t unused; /* padding byte */
- /* extended part */
- CIW ciw[MAX_CIWS]; /* variable # of CIWs */
-} QEMU_PACKED SenseId;
-
-/* Channel measurements, from linux/drivers/s390/cio/cmf.c. */
-typedef struct CMB {
- uint16_t ssch_rsch_count;
- uint16_t sample_count;
- uint32_t device_connect_time;
- uint32_t function_pending_time;
- uint32_t device_disconnect_time;
- uint32_t control_unit_queuing_time;
- uint32_t device_active_only_time;
- uint32_t reserved[2];
-} QEMU_PACKED CMB;
-
-typedef struct CMBE {
- uint32_t ssch_rsch_count;
- uint32_t sample_count;
- uint32_t device_connect_time;
- uint32_t function_pending_time;
- uint32_t device_disconnect_time;
- uint32_t control_unit_queuing_time;
- uint32_t device_active_only_time;
- uint32_t device_busy_time;
- uint32_t initial_command_response_time;
- uint32_t reserved[7];
-} QEMU_PACKED CMBE;
-
-struct SubchDev {
- /* channel-subsystem related things: */
- uint8_t cssid;
- uint8_t ssid;
- uint16_t schid;
- uint16_t devno;
- SCHIB curr_status;
- uint8_t sense_data[32];
- hwaddr channel_prog;
- CCW1 last_cmd;
- bool last_cmd_valid;
- bool ccw_fmt_1;
- bool thinint_active;
- uint8_t ccw_no_data_cnt;
- /* transport-provided data: */
- int (*ccw_cb) (SubchDev *, CCW1);
- void (*disable_cb)(SubchDev *);
- SenseId id;
- void *driver_data;
-};
-
-typedef struct IndAddr {
- hwaddr addr;
- uint64_t map;
- unsigned long refcnt;
- int len;
- QTAILQ_ENTRY(IndAddr) sibling;
-} IndAddr;
-
-IndAddr *get_indicator(hwaddr ind_addr, int len);
-void release_indicator(AdapterInfo *adapter, IndAddr *indicator);
-int map_indicator(AdapterInfo *adapter, IndAddr *indicator);
-
-typedef SubchDev *(*css_subch_cb_func)(uint8_t m, uint8_t cssid, uint8_t ssid,
- uint16_t schid);
-void subch_device_save(SubchDev *s, QEMUFile *f);
-int subch_device_load(SubchDev *s, QEMUFile *f);
-int css_create_css_image(uint8_t cssid, bool default_image);
-bool css_devno_used(uint8_t cssid, uint8_t ssid, uint16_t devno);
-void css_subch_assign(uint8_t cssid, uint8_t ssid, uint16_t schid,
- uint16_t devno, SubchDev *sch);
-void css_sch_build_virtual_schib(SubchDev *sch, uint8_t chpid, uint8_t type);
-uint16_t css_build_subchannel_id(SubchDev *sch);
-void css_reset(void);
-void css_reset_sch(SubchDev *sch);
-void css_queue_crw(uint8_t rsc, uint8_t erc, int chain, uint16_t rsid);
-void css_generate_sch_crws(uint8_t cssid, uint8_t ssid, uint16_t schid,
- int hotplugged, int add);
-void css_generate_chp_crws(uint8_t cssid, uint8_t chpid);
-void css_generate_css_crws(uint8_t cssid);
-void css_clear_sei_pending(void);
-void css_adapter_interrupt(uint8_t isc);
-
-#define CSS_IO_ADAPTER_VIRTIO 1
-int css_register_io_adapter(uint8_t type, uint8_t isc, bool swap,
- bool maskable, uint32_t *id);
-#endif
diff --git a/qemu/hw/s390x/event-facility.c b/qemu/hw/s390x/event-facility.c
deleted file mode 100644
index 34b2faf01..000000000
--- a/qemu/hw/s390x/event-facility.c
+++ /dev/null
@@ -1,449 +0,0 @@
-/*
- * SCLP
- * Event Facility
- * handles SCLP event types
- * - Signal Quiesce - system power down
- * - ASCII Console Data - VT220 read and write
- *
- * Copyright IBM, Corp. 2012
- *
- * Authors:
- * Heinz Graalfs <graalfs@de.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or (at your
- * option) any later version. See the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "sysemu/sysemu.h"
-
-#include "hw/s390x/sclp.h"
-#include "hw/s390x/event-facility.h"
-
-typedef struct SCLPEventsBus {
- BusState qbus;
-} SCLPEventsBus;
-
-struct SCLPEventFacility {
- SysBusDevice parent_obj;
- SCLPEventsBus sbus;
- /* guest' receive mask */
- unsigned int receive_mask;
-};
-
-/* return true if any child has event pending set */
-static bool event_pending(SCLPEventFacility *ef)
-{
- BusChild *kid;
- SCLPEvent *event;
- SCLPEventClass *event_class;
-
- QTAILQ_FOREACH(kid, &ef->sbus.qbus.children, sibling) {
- DeviceState *qdev = kid->child;
- event = DO_UPCAST(SCLPEvent, qdev, qdev);
- event_class = SCLP_EVENT_GET_CLASS(event);
- if (event->event_pending &&
- event_class->get_send_mask() & ef->receive_mask) {
- return true;
- }
- }
- return false;
-}
-
-static unsigned int get_host_send_mask(SCLPEventFacility *ef)
-{
- unsigned int mask;
- BusChild *kid;
- SCLPEventClass *child;
-
- mask = 0;
-
- QTAILQ_FOREACH(kid, &ef->sbus.qbus.children, sibling) {
- DeviceState *qdev = kid->child;
- child = SCLP_EVENT_GET_CLASS((SCLPEvent *) qdev);
- mask |= child->get_send_mask();
- }
- return mask;
-}
-
-static unsigned int get_host_receive_mask(SCLPEventFacility *ef)
-{
- unsigned int mask;
- BusChild *kid;
- SCLPEventClass *child;
-
- mask = 0;
-
- QTAILQ_FOREACH(kid, &ef->sbus.qbus.children, sibling) {
- DeviceState *qdev = kid->child;
- child = SCLP_EVENT_GET_CLASS((SCLPEvent *) qdev);
- mask |= child->get_receive_mask();
- }
- return mask;
-}
-
-static uint16_t write_event_length_check(SCCB *sccb)
-{
- int slen;
- unsigned elen = 0;
- EventBufferHeader *event;
- WriteEventData *wed = (WriteEventData *) sccb;
-
- event = (EventBufferHeader *) &wed->ebh;
- for (slen = sccb_data_len(sccb); slen > 0; slen -= elen) {
- elen = be16_to_cpu(event->length);
- if (elen < sizeof(*event) || elen > slen) {
- return SCLP_RC_EVENT_BUFFER_SYNTAX_ERROR;
- }
- event = (void *) event + elen;
- }
- if (slen) {
- return SCLP_RC_INCONSISTENT_LENGTHS;
- }
- return SCLP_RC_NORMAL_COMPLETION;
-}
-
-static uint16_t handle_write_event_buf(SCLPEventFacility *ef,
- EventBufferHeader *event_buf, SCCB *sccb)
-{
- uint16_t rc;
- BusChild *kid;
- SCLPEvent *event;
- SCLPEventClass *ec;
-
- rc = SCLP_RC_INVALID_FUNCTION;
-
- QTAILQ_FOREACH(kid, &ef->sbus.qbus.children, sibling) {
- DeviceState *qdev = kid->child;
- event = (SCLPEvent *) qdev;
- ec = SCLP_EVENT_GET_CLASS(event);
-
- if (ec->write_event_data &&
- ec->can_handle_event(event_buf->type)) {
- rc = ec->write_event_data(event, event_buf);
- break;
- }
- }
- return rc;
-}
-
-static uint16_t handle_sccb_write_events(SCLPEventFacility *ef, SCCB *sccb)
-{
- uint16_t rc;
- int slen;
- unsigned elen = 0;
- EventBufferHeader *event_buf;
- WriteEventData *wed = (WriteEventData *) sccb;
-
- event_buf = &wed->ebh;
- rc = SCLP_RC_NORMAL_COMPLETION;
-
- /* loop over all contained event buffers */
- for (slen = sccb_data_len(sccb); slen > 0; slen -= elen) {
- elen = be16_to_cpu(event_buf->length);
-
- /* in case of a previous error mark all trailing buffers
- * as not accepted */
- if (rc != SCLP_RC_NORMAL_COMPLETION) {
- event_buf->flags &= ~(SCLP_EVENT_BUFFER_ACCEPTED);
- } else {
- rc = handle_write_event_buf(ef, event_buf, sccb);
- }
- event_buf = (void *) event_buf + elen;
- }
- return rc;
-}
-
-static void write_event_data(SCLPEventFacility *ef, SCCB *sccb)
-{
- if (sccb->h.function_code != SCLP_FC_NORMAL_WRITE) {
- sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_FUNCTION);
- goto out;
- }
- if (be16_to_cpu(sccb->h.length) < 8) {
- sccb->h.response_code = cpu_to_be16(SCLP_RC_INSUFFICIENT_SCCB_LENGTH);
- goto out;
- }
- /* first do a sanity check of the write events */
- sccb->h.response_code = cpu_to_be16(write_event_length_check(sccb));
-
- /* if no early error, then execute */
- if (sccb->h.response_code == be16_to_cpu(SCLP_RC_NORMAL_COMPLETION)) {
- sccb->h.response_code =
- cpu_to_be16(handle_sccb_write_events(ef, sccb));
- }
-
-out:
- return;
-}
-
-static uint16_t handle_sccb_read_events(SCLPEventFacility *ef, SCCB *sccb,
- unsigned int mask)
-{
- uint16_t rc;
- int slen;
- unsigned elen;
- BusChild *kid;
- SCLPEvent *event;
- SCLPEventClass *ec;
- EventBufferHeader *event_buf;
- ReadEventData *red = (ReadEventData *) sccb;
-
- event_buf = &red->ebh;
- event_buf->length = 0;
- slen = sizeof(sccb->data);
-
- rc = SCLP_RC_NO_EVENT_BUFFERS_STORED;
-
- QTAILQ_FOREACH(kid, &ef->sbus.qbus.children, sibling) {
- DeviceState *qdev = kid->child;
- event = (SCLPEvent *) qdev;
- ec = SCLP_EVENT_GET_CLASS(event);
-
- if (mask & ec->get_send_mask()) {
- if (ec->read_event_data(event, event_buf, &slen)) {
- elen = be16_to_cpu(event_buf->length);
- event_buf = (EventBufferHeader *) ((char *)event_buf + elen);
- rc = SCLP_RC_NORMAL_COMPLETION;
- }
- }
- }
-
- if (sccb->h.control_mask[2] & SCLP_VARIABLE_LENGTH_RESPONSE) {
- /* architecture suggests to reset variable-length-response bit */
- sccb->h.control_mask[2] &= ~SCLP_VARIABLE_LENGTH_RESPONSE;
- /* with a new length value */
- sccb->h.length = cpu_to_be16(SCCB_SIZE - slen);
- }
- return rc;
-}
-
-static void read_event_data(SCLPEventFacility *ef, SCCB *sccb)
-{
- unsigned int sclp_active_selection_mask;
- unsigned int sclp_cp_receive_mask;
-
- ReadEventData *red = (ReadEventData *) sccb;
-
- if (be16_to_cpu(sccb->h.length) != SCCB_SIZE) {
- sccb->h.response_code = cpu_to_be16(SCLP_RC_INSUFFICIENT_SCCB_LENGTH);
- goto out;
- }
-
- sclp_cp_receive_mask = ef->receive_mask;
-
- /* get active selection mask */
- switch (sccb->h.function_code) {
- case SCLP_UNCONDITIONAL_READ:
- sclp_active_selection_mask = sclp_cp_receive_mask;
- break;
- case SCLP_SELECTIVE_READ:
- sclp_active_selection_mask = be32_to_cpu(red->mask);
- if (!sclp_cp_receive_mask ||
- (sclp_active_selection_mask & ~sclp_cp_receive_mask)) {
- sccb->h.response_code =
- cpu_to_be16(SCLP_RC_INVALID_SELECTION_MASK);
- goto out;
- }
- break;
- default:
- sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_FUNCTION);
- goto out;
- }
- sccb->h.response_code = cpu_to_be16(
- handle_sccb_read_events(ef, sccb, sclp_active_selection_mask));
-
-out:
- return;
-}
-
-static void write_event_mask(SCLPEventFacility *ef, SCCB *sccb)
-{
- WriteEventMask *we_mask = (WriteEventMask *) sccb;
-
- /* Attention: We assume that Linux uses 4-byte masks, what it actually
- does. Architecture allows for masks of variable size, though */
- if (be16_to_cpu(we_mask->mask_length) != 4) {
- sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_MASK_LENGTH);
- goto out;
- }
-
- /* keep track of the guest's capability masks */
- ef->receive_mask = be32_to_cpu(we_mask->cp_receive_mask);
-
- /* return the SCLP's capability masks to the guest */
- we_mask->send_mask = cpu_to_be32(get_host_send_mask(ef));
- we_mask->receive_mask = cpu_to_be32(get_host_receive_mask(ef));
-
- sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_COMPLETION);
-
-out:
- return;
-}
-
-/* qemu object creation and initialization functions */
-
-#define TYPE_SCLP_EVENTS_BUS "s390-sclp-events-bus"
-
-static void sclp_events_bus_realize(BusState *bus, Error **errp)
-{
- BusChild *kid;
-
- /* TODO: recursive realization has to be done in common code */
- QTAILQ_FOREACH(kid, &bus->children, sibling) {
- DeviceState *dev = kid->child;
-
- object_property_set_bool(OBJECT(dev), true, "realized", errp);
- if (*errp) {
- return;
- }
- }
-}
-
-static void sclp_events_bus_class_init(ObjectClass *klass, void *data)
-{
- BusClass *bc = BUS_CLASS(klass);
-
- bc->realize = sclp_events_bus_realize;
-}
-
-static const TypeInfo sclp_events_bus_info = {
- .name = TYPE_SCLP_EVENTS_BUS,
- .parent = TYPE_BUS,
- .class_init = sclp_events_bus_class_init,
-};
-
-static void command_handler(SCLPEventFacility *ef, SCCB *sccb, uint64_t code)
-{
- switch (code & SCLP_CMD_CODE_MASK) {
- case SCLP_CMD_READ_EVENT_DATA:
- read_event_data(ef, sccb);
- break;
- case SCLP_CMD_WRITE_EVENT_DATA:
- write_event_data(ef, sccb);
- break;
- case SCLP_CMD_WRITE_EVENT_MASK:
- write_event_mask(ef, sccb);
- break;
- default:
- sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND);
- break;
- }
-}
-
-static const VMStateDescription vmstate_event_facility = {
- .name = "vmstate-event-facility",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(receive_mask, SCLPEventFacility),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void init_event_facility(Object *obj)
-{
- SCLPEventFacility *event_facility = EVENT_FACILITY(obj);
- DeviceState *sdev = DEVICE(obj);
- Object *new;
-
- /* Spawn a new bus for SCLP events */
- qbus_create_inplace(&event_facility->sbus, sizeof(event_facility->sbus),
- TYPE_SCLP_EVENTS_BUS, sdev, NULL);
-
- new = object_new(TYPE_SCLP_QUIESCE);
- object_property_add_child(obj, TYPE_SCLP_QUIESCE, new, NULL);
- object_unref(new);
- qdev_set_parent_bus(DEVICE(new), &event_facility->sbus.qbus);
-
- new = object_new(TYPE_SCLP_CPU_HOTPLUG);
- object_property_add_child(obj, TYPE_SCLP_CPU_HOTPLUG, new, NULL);
- object_unref(new);
- qdev_set_parent_bus(DEVICE(new), &event_facility->sbus.qbus);
- /* the facility will automatically realize the devices via the bus */
-}
-
-static void reset_event_facility(DeviceState *dev)
-{
- SCLPEventFacility *sdev = EVENT_FACILITY(dev);
-
- sdev->receive_mask = 0;
-}
-
-static void init_event_facility_class(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *sbdc = SYS_BUS_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(sbdc);
- SCLPEventFacilityClass *k = EVENT_FACILITY_CLASS(dc);
-
- dc->reset = reset_event_facility;
- dc->vmsd = &vmstate_event_facility;
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- k->command_handler = command_handler;
- k->event_pending = event_pending;
-}
-
-static const TypeInfo sclp_event_facility_info = {
- .name = TYPE_SCLP_EVENT_FACILITY,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_init = init_event_facility,
- .instance_size = sizeof(SCLPEventFacility),
- .class_init = init_event_facility_class,
- .class_size = sizeof(SCLPEventFacilityClass),
-};
-
-static void event_realize(DeviceState *qdev, Error **errp)
-{
- SCLPEvent *event = SCLP_EVENT(qdev);
- SCLPEventClass *child = SCLP_EVENT_GET_CLASS(event);
-
- if (child->init) {
- int rc = child->init(event);
- if (rc < 0) {
- error_setg(errp, "SCLP event initialization failed.");
- return;
- }
- }
-}
-
-static void event_unrealize(DeviceState *qdev, Error **errp)
-{
- SCLPEvent *event = SCLP_EVENT(qdev);
- SCLPEventClass *child = SCLP_EVENT_GET_CLASS(event);
- if (child->exit) {
- int rc = child->exit(event);
- if (rc < 0) {
- error_setg(errp, "SCLP event exit failed.");
- return;
- }
- }
-}
-
-static void event_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->bus_type = TYPE_SCLP_EVENTS_BUS;
- dc->realize = event_realize;
- dc->unrealize = event_unrealize;
-}
-
-static const TypeInfo sclp_event_type_info = {
- .name = TYPE_SCLP_EVENT,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(SCLPEvent),
- .class_init = event_class_init,
- .class_size = sizeof(SCLPEventClass),
- .abstract = true,
-};
-
-static void register_types(void)
-{
- type_register_static(&sclp_events_bus_info);
- type_register_static(&sclp_event_facility_info);
- type_register_static(&sclp_event_type_info);
-}
-
-type_init(register_types)
diff --git a/qemu/hw/s390x/ipl.c b/qemu/hw/s390x/ipl.c
deleted file mode 100644
index f10420027..000000000
--- a/qemu/hw/s390x/ipl.c
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * bootloader support
- *
- * Copyright IBM, Corp. 2012
- *
- * Authors:
- * Christian Borntraeger <borntraeger@de.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or (at your
- * option) any later version. See the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "sysemu/sysemu.h"
-#include "cpu.h"
-#include "elf.h"
-#include "hw/loader.h"
-#include "hw/s390x/virtio-ccw.h"
-#include "hw/s390x/css.h"
-#include "ipl.h"
-
-#define KERN_IMAGE_START 0x010000UL
-#define KERN_PARM_AREA 0x010480UL
-#define INITRD_START 0x800000UL
-#define INITRD_PARM_START 0x010408UL
-#define INITRD_PARM_SIZE 0x010410UL
-#define PARMFILE_START 0x001000UL
-#define ZIPL_IMAGE_START 0x009000UL
-#define IPL_PSW_MASK (PSW_MASK_32 | PSW_MASK_64)
-
-static const VMStateDescription vmstate_iplb = {
- .name = "ipl/iplb",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8_ARRAY(reserved1, IplParameterBlock, 110),
- VMSTATE_UINT16(devno, IplParameterBlock),
- VMSTATE_UINT8_ARRAY(reserved2, IplParameterBlock, 88),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_ipl = {
- .name = "ipl",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_UINT64(start_addr, S390IPLState),
- VMSTATE_UINT64(bios_start_addr, S390IPLState),
- VMSTATE_STRUCT(iplb, S390IPLState, 0, vmstate_iplb, IplParameterBlock),
- VMSTATE_BOOL(iplb_valid, S390IPLState),
- VMSTATE_UINT8(cssid, S390IPLState),
- VMSTATE_UINT8(ssid, S390IPLState),
- VMSTATE_UINT16(devno, S390IPLState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static S390IPLState *get_ipl_device(void)
-{
- return S390_IPL(object_resolve_path_type("", TYPE_S390_IPL, NULL));
-}
-
-static uint64_t bios_translate_addr(void *opaque, uint64_t srcaddr)
-{
- uint64_t dstaddr = *(uint64_t *) opaque;
- /*
- * Assuming that our s390-ccw.img was linked for starting at address 0,
- * we can simply add the destination address for the final location
- */
- return srcaddr + dstaddr;
-}
-
-static void s390_ipl_realize(DeviceState *dev, Error **errp)
-{
- S390IPLState *ipl = S390_IPL(dev);
- uint64_t pentry = KERN_IMAGE_START;
- int kernel_size;
- Error *err = NULL;
-
- int bios_size;
- char *bios_filename;
-
- /*
- * Always load the bios if it was enforced,
- * even if an external kernel has been defined.
- */
- if (!ipl->kernel || ipl->enforce_bios) {
- uint64_t fwbase = (MIN(ram_size, 0x80000000U) - 0x200000) & ~0xffffUL;
-
- if (bios_name == NULL) {
- bios_name = ipl->firmware;
- }
-
- bios_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
- if (bios_filename == NULL) {
- error_setg(&err, "could not find stage1 bootloader");
- goto error;
- }
-
- bios_size = load_elf(bios_filename, bios_translate_addr, &fwbase,
- &ipl->bios_start_addr, NULL, NULL, 1,
- EM_S390, 0, 0);
- if (bios_size > 0) {
- /* Adjust ELF start address to final location */
- ipl->bios_start_addr += fwbase;
- } else {
- /* Try to load non-ELF file (e.g. s390-ccw.img) */
- bios_size = load_image_targphys(bios_filename, ZIPL_IMAGE_START,
- 4096);
- ipl->bios_start_addr = ZIPL_IMAGE_START;
- }
- g_free(bios_filename);
-
- if (bios_size == -1) {
- error_setg(&err, "could not load bootloader '%s'", bios_name);
- goto error;
- }
-
- /* default boot target is the bios */
- ipl->start_addr = ipl->bios_start_addr;
- }
-
- if (ipl->kernel) {
- kernel_size = load_elf(ipl->kernel, NULL, NULL, &pentry, NULL,
- NULL, 1, EM_S390, 0, 0);
- if (kernel_size < 0) {
- kernel_size = load_image_targphys(ipl->kernel, 0, ram_size);
- }
- if (kernel_size < 0) {
- error_setg(&err, "could not load kernel '%s'", ipl->kernel);
- goto error;
- }
- /*
- * Is it a Linux kernel (starting at 0x10000)? If yes, we fill in the
- * kernel parameters here as well. Note: For old kernels (up to 3.2)
- * we can not rely on the ELF entry point - it was 0x800 (the SALIPL
- * loader) and it won't work. For this case we force it to 0x10000, too.
- */
- if (pentry == KERN_IMAGE_START || pentry == 0x800) {
- ipl->start_addr = KERN_IMAGE_START;
- /* Overwrite parameters in the kernel image, which are "rom" */
- strcpy(rom_ptr(KERN_PARM_AREA), ipl->cmdline);
- } else {
- ipl->start_addr = pentry;
- }
-
- if (ipl->initrd) {
- ram_addr_t initrd_offset;
- int initrd_size;
-
- initrd_offset = INITRD_START;
- while (kernel_size + 0x100000 > initrd_offset) {
- initrd_offset += 0x100000;
- }
- initrd_size = load_image_targphys(ipl->initrd, initrd_offset,
- ram_size - initrd_offset);
- if (initrd_size == -1) {
- error_setg(&err, "could not load initrd '%s'", ipl->initrd);
- goto error;
- }
-
- /*
- * we have to overwrite values in the kernel image,
- * which are "rom"
- */
- stq_p(rom_ptr(INITRD_PARM_START), initrd_offset);
- stq_p(rom_ptr(INITRD_PARM_SIZE), initrd_size);
- }
- }
- qemu_register_reset(qdev_reset_all_fn, dev);
-error:
- error_propagate(errp, err);
-}
-
-static Property s390_ipl_properties[] = {
- DEFINE_PROP_STRING("kernel", S390IPLState, kernel),
- DEFINE_PROP_STRING("initrd", S390IPLState, initrd),
- DEFINE_PROP_STRING("cmdline", S390IPLState, cmdline),
- DEFINE_PROP_STRING("firmware", S390IPLState, firmware),
- DEFINE_PROP_BOOL("enforce_bios", S390IPLState, enforce_bios, false),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-/*
- * In addition to updating the iplstate, this function returns:
- * - 0 if system was ipled with external kernel
- * - -1 if no valid boot device was found
- * - ccw id of the boot device otherwise
- */
-static uint64_t s390_update_iplstate(S390IPLState *ipl)
-{
- DeviceState *dev_st;
-
- if (ipl->iplb_valid) {
- ipl->cssid = 0;
- ipl->ssid = 0;
- ipl->devno = ipl->iplb.devno;
- goto out;
- }
-
- if (ipl->kernel) {
- return 0;
- }
-
- dev_st = get_boot_device(0);
- if (dev_st) {
- VirtioCcwDevice *ccw_dev = (VirtioCcwDevice *) object_dynamic_cast(
- OBJECT(qdev_get_parent_bus(dev_st)->parent),
- TYPE_VIRTIO_CCW_DEVICE);
- if (ccw_dev) {
- ipl->cssid = ccw_dev->sch->cssid;
- ipl->ssid = ccw_dev->sch->ssid;
- ipl->devno = ccw_dev->sch->devno;
- goto out;
- }
- }
-
- return -1;
-out:
- return (uint32_t) (ipl->cssid << 24 | ipl->ssid << 16 | ipl->devno);
-}
-
-void s390_ipl_update_diag308(IplParameterBlock *iplb)
-{
- S390IPLState *ipl = get_ipl_device();
-
- ipl->iplb = *iplb;
- ipl->iplb_valid = true;
-}
-
-IplParameterBlock *s390_ipl_get_iplb(void)
-{
- S390IPLState *ipl = get_ipl_device();
-
- if (!ipl->iplb_valid) {
- return NULL;
- }
- return &ipl->iplb;
-}
-
-void s390_reipl_request(void)
-{
- S390IPLState *ipl = get_ipl_device();
-
- ipl->reipl_requested = true;
- qemu_system_reset_request();
-}
-
-void s390_ipl_prepare_cpu(S390CPU *cpu)
-{
- S390IPLState *ipl = get_ipl_device();
-
- cpu->env.psw.addr = ipl->start_addr;
- cpu->env.psw.mask = IPL_PSW_MASK;
-
- if (!ipl->kernel || ipl->iplb_valid) {
- cpu->env.psw.addr = ipl->bios_start_addr;
- cpu->env.regs[7] = s390_update_iplstate(ipl);
- }
-}
-
-static void s390_ipl_reset(DeviceState *dev)
-{
- S390IPLState *ipl = S390_IPL(dev);
-
- if (!ipl->reipl_requested) {
- ipl->iplb_valid = false;
- }
- ipl->reipl_requested = false;
-}
-
-static void s390_ipl_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = s390_ipl_realize;
- dc->props = s390_ipl_properties;
- dc->reset = s390_ipl_reset;
- dc->vmsd = &vmstate_ipl;
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
-}
-
-static const TypeInfo s390_ipl_info = {
- .class_init = s390_ipl_class_init,
- .parent = TYPE_DEVICE,
- .name = TYPE_S390_IPL,
- .instance_size = sizeof(S390IPLState),
-};
-
-static void s390_ipl_register_types(void)
-{
- type_register_static(&s390_ipl_info);
-}
-
-type_init(s390_ipl_register_types)
diff --git a/qemu/hw/s390x/ipl.h b/qemu/hw/s390x/ipl.h
deleted file mode 100644
index 6b48ed7b9..000000000
--- a/qemu/hw/s390x/ipl.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * s390 IPL device
- *
- * Copyright 2015 IBM Corp.
- * Author(s): Zhang Fan <bjfanzh@cn.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or (at
- * your option) any later version. See the COPYING file in the top-level
- * directory.
- */
-
-#ifndef HW_S390_IPL_H
-#define HW_S390_IPL_H
-
-#include "hw/qdev.h"
-#include "cpu.h"
-
-typedef struct IplParameterBlock {
- uint8_t reserved1[110];
- uint16_t devno;
- uint8_t reserved2[88];
-} IplParameterBlock;
-
-void s390_ipl_update_diag308(IplParameterBlock *iplb);
-void s390_ipl_prepare_cpu(S390CPU *cpu);
-IplParameterBlock *s390_ipl_get_iplb(void);
-void s390_reipl_request(void);
-
-#define TYPE_S390_IPL "s390-ipl"
-#define S390_IPL(obj) OBJECT_CHECK(S390IPLState, (obj), TYPE_S390_IPL)
-
-struct S390IPLState {
- /*< private >*/
- DeviceState parent_obj;
- uint64_t start_addr;
- uint64_t bios_start_addr;
- bool enforce_bios;
- IplParameterBlock iplb;
- bool iplb_valid;
- bool reipl_requested;
-
- /*< public >*/
- char *kernel;
- char *initrd;
- char *cmdline;
- char *firmware;
- uint8_t cssid;
- uint8_t ssid;
- uint16_t devno;
-};
-typedef struct S390IPLState S390IPLState;
-
-#endif
diff --git a/qemu/hw/s390x/s390-pci-bus.c b/qemu/hw/s390x/s390-pci-bus.c
deleted file mode 100644
index 918b58543..000000000
--- a/qemu/hw/s390x/s390-pci-bus.c
+++ /dev/null
@@ -1,621 +0,0 @@
-/*
- * s390 PCI BUS
- *
- * Copyright 2014 IBM Corp.
- * Author(s): Frank Blaschka <frank.blaschka@de.ibm.com>
- * Hong Bo Li <lihbbj@cn.ibm.com>
- * Yi Min Zhao <zyimin@cn.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or (at
- * your option) any later version. See the COPYING file in the top-level
- * directory.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "s390-pci-bus.h"
-#include <hw/pci/pci_bus.h>
-#include <hw/pci/msi.h>
-#include <qemu/error-report.h>
-
-/* #define DEBUG_S390PCI_BUS */
-#ifdef DEBUG_S390PCI_BUS
-#define DPRINTF(fmt, ...) \
- do { fprintf(stderr, "S390pci-bus: " fmt, ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) \
- do { } while (0)
-#endif
-
-int chsc_sei_nt2_get_event(void *res)
-{
- ChscSeiNt2Res *nt2_res = (ChscSeiNt2Res *)res;
- PciCcdfAvail *accdf;
- PciCcdfErr *eccdf;
- int rc = 1;
- SeiContainer *sei_cont;
- S390pciState *s = S390_PCI_HOST_BRIDGE(
- object_resolve_path(TYPE_S390_PCI_HOST_BRIDGE, NULL));
-
- if (!s) {
- return rc;
- }
-
- sei_cont = QTAILQ_FIRST(&s->pending_sei);
- if (sei_cont) {
- QTAILQ_REMOVE(&s->pending_sei, sei_cont, link);
- nt2_res->nt = 2;
- nt2_res->cc = sei_cont->cc;
- nt2_res->length = cpu_to_be16(sizeof(ChscSeiNt2Res));
- switch (sei_cont->cc) {
- case 1: /* error event */
- eccdf = (PciCcdfErr *)nt2_res->ccdf;
- eccdf->fid = cpu_to_be32(sei_cont->fid);
- eccdf->fh = cpu_to_be32(sei_cont->fh);
- eccdf->e = cpu_to_be32(sei_cont->e);
- eccdf->faddr = cpu_to_be64(sei_cont->faddr);
- eccdf->pec = cpu_to_be16(sei_cont->pec);
- break;
- case 2: /* availability event */
- accdf = (PciCcdfAvail *)nt2_res->ccdf;
- accdf->fid = cpu_to_be32(sei_cont->fid);
- accdf->fh = cpu_to_be32(sei_cont->fh);
- accdf->pec = cpu_to_be16(sei_cont->pec);
- break;
- default:
- abort();
- }
- g_free(sei_cont);
- rc = 0;
- }
-
- return rc;
-}
-
-int chsc_sei_nt2_have_event(void)
-{
- S390pciState *s = S390_PCI_HOST_BRIDGE(
- object_resolve_path(TYPE_S390_PCI_HOST_BRIDGE, NULL));
-
- if (!s) {
- return 0;
- }
-
- return !QTAILQ_EMPTY(&s->pending_sei);
-}
-
-S390PCIBusDevice *s390_pci_find_dev_by_fid(uint32_t fid)
-{
- S390PCIBusDevice *pbdev;
- int i;
- S390pciState *s = S390_PCI_HOST_BRIDGE(
- object_resolve_path(TYPE_S390_PCI_HOST_BRIDGE, NULL));
-
- if (!s) {
- return NULL;
- }
-
- for (i = 0; i < PCI_SLOT_MAX; i++) {
- pbdev = &s->pbdev[i];
- if ((pbdev->fh != 0) && (pbdev->fid == fid)) {
- return pbdev;
- }
- }
-
- return NULL;
-}
-
-void s390_pci_sclp_configure(int configure, SCCB *sccb)
-{
- PciCfgSccb *psccb = (PciCfgSccb *)sccb;
- S390PCIBusDevice *pbdev = s390_pci_find_dev_by_fid(be32_to_cpu(psccb->aid));
- uint16_t rc;
-
- if (pbdev) {
- if ((configure == 1 && pbdev->configured == true) ||
- (configure == 0 && pbdev->configured == false)) {
- rc = SCLP_RC_NO_ACTION_REQUIRED;
- } else {
- pbdev->configured = !pbdev->configured;
- rc = SCLP_RC_NORMAL_COMPLETION;
- }
- } else {
- DPRINTF("sclp config %d no dev found\n", configure);
- rc = SCLP_RC_ADAPTER_ID_NOT_RECOGNIZED;
- }
-
- psccb->header.response_code = cpu_to_be16(rc);
-}
-
-static uint32_t s390_pci_get_pfid(PCIDevice *pdev)
-{
- return PCI_SLOT(pdev->devfn);
-}
-
-static uint32_t s390_pci_get_pfh(PCIDevice *pdev)
-{
- return PCI_SLOT(pdev->devfn) | FH_VIRT;
-}
-
-S390PCIBusDevice *s390_pci_find_dev_by_idx(uint32_t idx)
-{
- S390PCIBusDevice *pbdev;
- int i;
- int j = 0;
- S390pciState *s = S390_PCI_HOST_BRIDGE(
- object_resolve_path(TYPE_S390_PCI_HOST_BRIDGE, NULL));
-
- if (!s) {
- return NULL;
- }
-
- for (i = 0; i < PCI_SLOT_MAX; i++) {
- pbdev = &s->pbdev[i];
-
- if (pbdev->fh == 0) {
- continue;
- }
-
- if (j == idx) {
- return pbdev;
- }
- j++;
- }
-
- return NULL;
-}
-
-S390PCIBusDevice *s390_pci_find_dev_by_fh(uint32_t fh)
-{
- S390PCIBusDevice *pbdev;
- int i;
- S390pciState *s = S390_PCI_HOST_BRIDGE(
- object_resolve_path(TYPE_S390_PCI_HOST_BRIDGE, NULL));
-
- if (!s || !fh) {
- return NULL;
- }
-
- for (i = 0; i < PCI_SLOT_MAX; i++) {
- pbdev = &s->pbdev[i];
- if (pbdev->fh == fh) {
- return pbdev;
- }
- }
-
- return NULL;
-}
-
-static void s390_pci_generate_event(uint8_t cc, uint16_t pec, uint32_t fh,
- uint32_t fid, uint64_t faddr, uint32_t e)
-{
- SeiContainer *sei_cont;
- S390pciState *s = S390_PCI_HOST_BRIDGE(
- object_resolve_path(TYPE_S390_PCI_HOST_BRIDGE, NULL));
-
- if (!s) {
- return;
- }
-
- sei_cont = g_malloc0(sizeof(SeiContainer));
- sei_cont->fh = fh;
- sei_cont->fid = fid;
- sei_cont->cc = cc;
- sei_cont->pec = pec;
- sei_cont->faddr = faddr;
- sei_cont->e = e;
-
- QTAILQ_INSERT_TAIL(&s->pending_sei, sei_cont, link);
- css_generate_css_crws(0);
-}
-
-static void s390_pci_generate_plug_event(uint16_t pec, uint32_t fh,
- uint32_t fid)
-{
- s390_pci_generate_event(2, pec, fh, fid, 0, 0);
-}
-
-static void s390_pci_generate_error_event(uint16_t pec, uint32_t fh,
- uint32_t fid, uint64_t faddr,
- uint32_t e)
-{
- s390_pci_generate_event(1, pec, fh, fid, faddr, e);
-}
-
-static void s390_pci_set_irq(void *opaque, int irq, int level)
-{
- /* nothing to do */
-}
-
-static int s390_pci_map_irq(PCIDevice *pci_dev, int irq_num)
-{
- /* nothing to do */
- return 0;
-}
-
-static uint64_t s390_pci_get_table_origin(uint64_t iota)
-{
- return iota & ~ZPCI_IOTA_RTTO_FLAG;
-}
-
-static unsigned int calc_rtx(dma_addr_t ptr)
-{
- return ((unsigned long) ptr >> ZPCI_RT_SHIFT) & ZPCI_INDEX_MASK;
-}
-
-static unsigned int calc_sx(dma_addr_t ptr)
-{
- return ((unsigned long) ptr >> ZPCI_ST_SHIFT) & ZPCI_INDEX_MASK;
-}
-
-static unsigned int calc_px(dma_addr_t ptr)
-{
- return ((unsigned long) ptr >> PAGE_SHIFT) & ZPCI_PT_MASK;
-}
-
-static uint64_t get_rt_sto(uint64_t entry)
-{
- return ((entry & ZPCI_TABLE_TYPE_MASK) == ZPCI_TABLE_TYPE_RTX)
- ? (entry & ZPCI_RTE_ADDR_MASK)
- : 0;
-}
-
-static uint64_t get_st_pto(uint64_t entry)
-{
- return ((entry & ZPCI_TABLE_TYPE_MASK) == ZPCI_TABLE_TYPE_SX)
- ? (entry & ZPCI_STE_ADDR_MASK)
- : 0;
-}
-
-static uint64_t s390_guest_io_table_walk(uint64_t guest_iota,
- uint64_t guest_dma_address)
-{
- uint64_t sto_a, pto_a, px_a;
- uint64_t sto, pto, pte;
- uint32_t rtx, sx, px;
-
- rtx = calc_rtx(guest_dma_address);
- sx = calc_sx(guest_dma_address);
- px = calc_px(guest_dma_address);
-
- sto_a = guest_iota + rtx * sizeof(uint64_t);
- sto = address_space_ldq(&address_space_memory, sto_a,
- MEMTXATTRS_UNSPECIFIED, NULL);
- sto = get_rt_sto(sto);
- if (!sto) {
- pte = 0;
- goto out;
- }
-
- pto_a = sto + sx * sizeof(uint64_t);
- pto = address_space_ldq(&address_space_memory, pto_a,
- MEMTXATTRS_UNSPECIFIED, NULL);
- pto = get_st_pto(pto);
- if (!pto) {
- pte = 0;
- goto out;
- }
-
- px_a = pto + px * sizeof(uint64_t);
- pte = address_space_ldq(&address_space_memory, px_a,
- MEMTXATTRS_UNSPECIFIED, NULL);
-
-out:
- return pte;
-}
-
-static IOMMUTLBEntry s390_translate_iommu(MemoryRegion *iommu, hwaddr addr,
- bool is_write)
-{
- uint64_t pte;
- uint32_t flags;
- S390PCIBusDevice *pbdev = container_of(iommu, S390PCIBusDevice, iommu_mr);
- S390pciState *s;
- IOMMUTLBEntry ret = {
- .target_as = &address_space_memory,
- .iova = 0,
- .translated_addr = 0,
- .addr_mask = ~(hwaddr)0,
- .perm = IOMMU_NONE,
- };
-
- if (!pbdev->configured || !pbdev->pdev || !(pbdev->fh & FH_ENABLED)) {
- return ret;
- }
-
- DPRINTF("iommu trans addr 0x%" PRIx64 "\n", addr);
-
- s = S390_PCI_HOST_BRIDGE(pci_device_root_bus(pbdev->pdev)->qbus.parent);
- /* s390 does not have an APIC mapped to main storage so we use
- * a separate AddressSpace only for msix notifications
- */
- if (addr == ZPCI_MSI_ADDR) {
- ret.target_as = &s->msix_notify_as;
- ret.iova = addr;
- ret.translated_addr = addr;
- ret.addr_mask = 0xfff;
- ret.perm = IOMMU_RW;
- return ret;
- }
-
- if (!pbdev->g_iota) {
- pbdev->error_state = true;
- pbdev->lgstg_blocked = true;
- s390_pci_generate_error_event(ERR_EVENT_INVALAS, pbdev->fh, pbdev->fid,
- addr, 0);
- return ret;
- }
-
- if (addr < pbdev->pba || addr > pbdev->pal) {
- pbdev->error_state = true;
- pbdev->lgstg_blocked = true;
- s390_pci_generate_error_event(ERR_EVENT_OORANGE, pbdev->fh, pbdev->fid,
- addr, 0);
- return ret;
- }
-
- pte = s390_guest_io_table_walk(s390_pci_get_table_origin(pbdev->g_iota),
- addr);
-
- if (!pte) {
- pbdev->error_state = true;
- pbdev->lgstg_blocked = true;
- s390_pci_generate_error_event(ERR_EVENT_SERR, pbdev->fh, pbdev->fid,
- addr, ERR_EVENT_Q_BIT);
- return ret;
- }
-
- flags = pte & ZPCI_PTE_FLAG_MASK;
- ret.iova = addr;
- ret.translated_addr = pte & ZPCI_PTE_ADDR_MASK;
- ret.addr_mask = 0xfff;
-
- if (flags & ZPCI_PTE_INVALID) {
- ret.perm = IOMMU_NONE;
- } else {
- ret.perm = IOMMU_RW;
- }
-
- return ret;
-}
-
-static const MemoryRegionIOMMUOps s390_iommu_ops = {
- .translate = s390_translate_iommu,
-};
-
-static AddressSpace *s390_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
-{
- S390pciState *s = opaque;
-
- return &s->pbdev[PCI_SLOT(devfn)].as;
-}
-
-static uint8_t set_ind_atomic(uint64_t ind_loc, uint8_t to_be_set)
-{
- uint8_t ind_old, ind_new;
- hwaddr len = 1;
- uint8_t *ind_addr;
-
- ind_addr = cpu_physical_memory_map(ind_loc, &len, 1);
- if (!ind_addr) {
- s390_pci_generate_error_event(ERR_EVENT_AIRERR, 0, 0, 0, 0);
- return -1;
- }
- do {
- ind_old = *ind_addr;
- ind_new = ind_old | to_be_set;
- } while (atomic_cmpxchg(ind_addr, ind_old, ind_new) != ind_old);
- cpu_physical_memory_unmap(ind_addr, len, 1, len);
-
- return ind_old;
-}
-
-static void s390_msi_ctrl_write(void *opaque, hwaddr addr, uint64_t data,
- unsigned int size)
-{
- S390PCIBusDevice *pbdev;
- uint32_t io_int_word;
- uint32_t fid = data >> ZPCI_MSI_VEC_BITS;
- uint32_t vec = data & ZPCI_MSI_VEC_MASK;
- uint64_t ind_bit;
- uint32_t sum_bit;
- uint32_t e = 0;
-
- DPRINTF("write_msix data 0x%" PRIx64 " fid %d vec 0x%x\n", data, fid, vec);
-
- pbdev = s390_pci_find_dev_by_fid(fid);
- if (!pbdev) {
- e |= (vec << ERR_EVENT_MVN_OFFSET);
- s390_pci_generate_error_event(ERR_EVENT_NOMSI, 0, fid, addr, e);
- return;
- }
-
- if (!(pbdev->fh & FH_ENABLED)) {
- return;
- }
-
- ind_bit = pbdev->routes.adapter.ind_offset;
- sum_bit = pbdev->routes.adapter.summary_offset;
-
- set_ind_atomic(pbdev->routes.adapter.ind_addr + (ind_bit + vec) / 8,
- 0x80 >> ((ind_bit + vec) % 8));
- if (!set_ind_atomic(pbdev->routes.adapter.summary_addr + sum_bit / 8,
- 0x80 >> (sum_bit % 8))) {
- io_int_word = (pbdev->isc << 27) | IO_INT_WORD_AI;
- s390_io_interrupt(0, 0, 0, io_int_word);
- }
-}
-
-static uint64_t s390_msi_ctrl_read(void *opaque, hwaddr addr, unsigned size)
-{
- return 0xffffffff;
-}
-
-static const MemoryRegionOps s390_msi_ctrl_ops = {
- .write = s390_msi_ctrl_write,
- .read = s390_msi_ctrl_read,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-void s390_pcihost_iommu_configure(S390PCIBusDevice *pbdev, bool enable)
-{
- pbdev->configured = false;
-
- if (enable) {
- uint64_t size = pbdev->pal - pbdev->pba + 1;
- memory_region_init_iommu(&pbdev->iommu_mr, OBJECT(&pbdev->mr),
- &s390_iommu_ops, "iommu-s390", size);
- memory_region_add_subregion(&pbdev->mr, pbdev->pba, &pbdev->iommu_mr);
- } else {
- memory_region_del_subregion(&pbdev->mr, &pbdev->iommu_mr);
- }
-
- pbdev->configured = true;
-}
-
-static void s390_pcihost_init_as(S390pciState *s)
-{
- int i;
- S390PCIBusDevice *pbdev;
-
- for (i = 0; i < PCI_SLOT_MAX; i++) {
- pbdev = &s->pbdev[i];
- memory_region_init(&pbdev->mr, OBJECT(s),
- "iommu-root-s390", UINT64_MAX);
- address_space_init(&pbdev->as, &pbdev->mr, "iommu-pci");
- }
-
- memory_region_init_io(&s->msix_notify_mr, OBJECT(s),
- &s390_msi_ctrl_ops, s, "msix-s390", UINT64_MAX);
- address_space_init(&s->msix_notify_as, &s->msix_notify_mr, "msix-pci");
-}
-
-static int s390_pcihost_init(SysBusDevice *dev)
-{
- PCIBus *b;
- BusState *bus;
- PCIHostState *phb = PCI_HOST_BRIDGE(dev);
- S390pciState *s = S390_PCI_HOST_BRIDGE(dev);
-
- DPRINTF("host_init\n");
-
- b = pci_register_bus(DEVICE(dev), NULL,
- s390_pci_set_irq, s390_pci_map_irq, NULL,
- get_system_memory(), get_system_io(), 0, 64,
- TYPE_PCI_BUS);
- s390_pcihost_init_as(s);
- pci_setup_iommu(b, s390_pci_dma_iommu, s);
-
- bus = BUS(b);
- qbus_set_hotplug_handler(bus, DEVICE(dev), NULL);
- phb->bus = b;
- QTAILQ_INIT(&s->pending_sei);
- return 0;
-}
-
-static int s390_pcihost_setup_msix(S390PCIBusDevice *pbdev)
-{
- uint8_t pos;
- uint16_t ctrl;
- uint32_t table, pba;
-
- pos = pci_find_capability(pbdev->pdev, PCI_CAP_ID_MSIX);
- if (!pos) {
- pbdev->msix.available = false;
- return 0;
- }
-
- ctrl = pci_host_config_read_common(pbdev->pdev, pos + PCI_MSIX_FLAGS,
- pci_config_size(pbdev->pdev), sizeof(ctrl));
- table = pci_host_config_read_common(pbdev->pdev, pos + PCI_MSIX_TABLE,
- pci_config_size(pbdev->pdev), sizeof(table));
- pba = pci_host_config_read_common(pbdev->pdev, pos + PCI_MSIX_PBA,
- pci_config_size(pbdev->pdev), sizeof(pba));
-
- pbdev->msix.table_bar = table & PCI_MSIX_FLAGS_BIRMASK;
- pbdev->msix.table_offset = table & ~PCI_MSIX_FLAGS_BIRMASK;
- pbdev->msix.pba_bar = pba & PCI_MSIX_FLAGS_BIRMASK;
- pbdev->msix.pba_offset = pba & ~PCI_MSIX_FLAGS_BIRMASK;
- pbdev->msix.entries = (ctrl & PCI_MSIX_FLAGS_QSIZE) + 1;
- pbdev->msix.available = true;
- return 0;
-}
-
-static void s390_pcihost_hot_plug(HotplugHandler *hotplug_dev,
- DeviceState *dev, Error **errp)
-{
- PCIDevice *pci_dev = PCI_DEVICE(dev);
- S390PCIBusDevice *pbdev;
- S390pciState *s = S390_PCI_HOST_BRIDGE(pci_device_root_bus(pci_dev)
- ->qbus.parent);
-
- pbdev = &s->pbdev[PCI_SLOT(pci_dev->devfn)];
-
- pbdev->fid = s390_pci_get_pfid(pci_dev);
- pbdev->pdev = pci_dev;
- pbdev->configured = true;
- pbdev->fh = s390_pci_get_pfh(pci_dev);
-
- s390_pcihost_setup_msix(pbdev);
-
- if (dev->hotplugged) {
- s390_pci_generate_plug_event(HP_EVENT_RESERVED_TO_STANDBY,
- pbdev->fh, pbdev->fid);
- s390_pci_generate_plug_event(HP_EVENT_TO_CONFIGURED,
- pbdev->fh, pbdev->fid);
- }
-}
-
-static void s390_pcihost_hot_unplug(HotplugHandler *hotplug_dev,
- DeviceState *dev, Error **errp)
-{
- PCIDevice *pci_dev = PCI_DEVICE(dev);
- S390pciState *s = S390_PCI_HOST_BRIDGE(pci_device_root_bus(pci_dev)
- ->qbus.parent);
- S390PCIBusDevice *pbdev = &s->pbdev[PCI_SLOT(pci_dev->devfn)];
-
- if (pbdev->configured) {
- pbdev->configured = false;
- s390_pci_generate_plug_event(HP_EVENT_CONFIGURED_TO_STBRES,
- pbdev->fh, pbdev->fid);
- }
-
- s390_pci_generate_plug_event(HP_EVENT_STANDBY_TO_RESERVED,
- pbdev->fh, pbdev->fid);
- pbdev->fh = 0;
- pbdev->fid = 0;
- pbdev->pdev = NULL;
- object_unparent(OBJECT(pci_dev));
-}
-
-static void s390_pcihost_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
- HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
-
- dc->cannot_instantiate_with_device_add_yet = true;
- k->init = s390_pcihost_init;
- hc->plug = s390_pcihost_hot_plug;
- hc->unplug = s390_pcihost_hot_unplug;
- msi_nonbroken = true;
-}
-
-static const TypeInfo s390_pcihost_info = {
- .name = TYPE_S390_PCI_HOST_BRIDGE,
- .parent = TYPE_PCI_HOST_BRIDGE,
- .instance_size = sizeof(S390pciState),
- .class_init = s390_pcihost_class_init,
- .interfaces = (InterfaceInfo[]) {
- { TYPE_HOTPLUG_HANDLER },
- { }
- }
-};
-
-static void s390_pci_register_types(void)
-{
- type_register_static(&s390_pcihost_info);
-}
-
-type_init(s390_pci_register_types)
diff --git a/qemu/hw/s390x/s390-pci-bus.h b/qemu/hw/s390x/s390-pci-bus.h
deleted file mode 100644
index 59fd5c958..000000000
--- a/qemu/hw/s390x/s390-pci-bus.h
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * s390 PCI BUS definitions
- *
- * Copyright 2014 IBM Corp.
- * Author(s): Frank Blaschka <frank.blaschka@de.ibm.com>
- * Hong Bo Li <lihbbj@cn.ibm.com>
- * Yi Min Zhao <zyimin@cn.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or (at
- * your option) any later version. See the COPYING file in the top-level
- * directory.
- */
-
-#ifndef HW_S390_PCI_BUS_H
-#define HW_S390_PCI_BUS_H
-
-#include <hw/pci/pci.h>
-#include <hw/pci/pci_host.h>
-#include "hw/s390x/sclp.h"
-#include "hw/s390x/s390_flic.h"
-#include "hw/s390x/css.h"
-
-#define TYPE_S390_PCI_HOST_BRIDGE "s390-pcihost"
-#define FH_VIRT 0x00ff0000
-#define ENABLE_BIT_OFFSET 31
-#define FH_ENABLED (1 << ENABLE_BIT_OFFSET)
-#define S390_PCIPT_ADAPTER 2
-
-#define S390_PCI_HOST_BRIDGE(obj) \
- OBJECT_CHECK(S390pciState, (obj), TYPE_S390_PCI_HOST_BRIDGE)
-
-#define HP_EVENT_TO_CONFIGURED 0x0301
-#define HP_EVENT_RESERVED_TO_STANDBY 0x0302
-#define HP_EVENT_CONFIGURED_TO_STBRES 0x0304
-#define HP_EVENT_STANDBY_TO_RESERVED 0x0308
-
-#define ERR_EVENT_INVALAS 0x1
-#define ERR_EVENT_OORANGE 0x2
-#define ERR_EVENT_INVALTF 0x3
-#define ERR_EVENT_TPROTE 0x4
-#define ERR_EVENT_APROTE 0x5
-#define ERR_EVENT_KEYE 0x6
-#define ERR_EVENT_INVALTE 0x7
-#define ERR_EVENT_INVALTL 0x8
-#define ERR_EVENT_TT 0x9
-#define ERR_EVENT_INVALMS 0xa
-#define ERR_EVENT_SERR 0xb
-#define ERR_EVENT_NOMSI 0x10
-#define ERR_EVENT_INVALBV 0x11
-#define ERR_EVENT_AIBV 0x12
-#define ERR_EVENT_AIRERR 0x13
-#define ERR_EVENT_FMBA 0x2a
-#define ERR_EVENT_FMBUP 0x2b
-#define ERR_EVENT_FMBPRO 0x2c
-#define ERR_EVENT_CCONF 0x30
-#define ERR_EVENT_SERVAC 0x3a
-#define ERR_EVENT_PERMERR 0x3b
-
-#define ERR_EVENT_Q_BIT 0x2
-#define ERR_EVENT_MVN_OFFSET 16
-
-#define ZPCI_MSI_VEC_BITS 11
-#define ZPCI_MSI_VEC_MASK 0x7ff
-
-#define ZPCI_MSI_ADDR 0xfe00000000000000ULL
-#define ZPCI_SDMA_ADDR 0x100000000ULL
-#define ZPCI_EDMA_ADDR 0x1ffffffffffffffULL
-
-#define PAGE_SHIFT 12
-#define PAGE_MASK (~(PAGE_SIZE-1))
-#define PAGE_DEFAULT_ACC 0
-#define PAGE_DEFAULT_KEY (PAGE_DEFAULT_ACC << 4)
-
-/* I/O Translation Anchor (IOTA) */
-enum ZpciIoatDtype {
- ZPCI_IOTA_STO = 0,
- ZPCI_IOTA_RTTO = 1,
- ZPCI_IOTA_RSTO = 2,
- ZPCI_IOTA_RFTO = 3,
- ZPCI_IOTA_PFAA = 4,
- ZPCI_IOTA_IOPFAA = 5,
- ZPCI_IOTA_IOPTO = 7
-};
-
-#define ZPCI_IOTA_IOT_ENABLED 0x800ULL
-#define ZPCI_IOTA_DT_ST (ZPCI_IOTA_STO << 2)
-#define ZPCI_IOTA_DT_RT (ZPCI_IOTA_RTTO << 2)
-#define ZPCI_IOTA_DT_RS (ZPCI_IOTA_RSTO << 2)
-#define ZPCI_IOTA_DT_RF (ZPCI_IOTA_RFTO << 2)
-#define ZPCI_IOTA_DT_PF (ZPCI_IOTA_PFAA << 2)
-#define ZPCI_IOTA_FS_4K 0
-#define ZPCI_IOTA_FS_1M 1
-#define ZPCI_IOTA_FS_2G 2
-#define ZPCI_KEY (PAGE_DEFAULT_KEY << 5)
-
-#define ZPCI_IOTA_STO_FLAG (ZPCI_IOTA_IOT_ENABLED | ZPCI_KEY | ZPCI_IOTA_DT_ST)
-#define ZPCI_IOTA_RTTO_FLAG (ZPCI_IOTA_IOT_ENABLED | ZPCI_KEY | ZPCI_IOTA_DT_RT)
-#define ZPCI_IOTA_RSTO_FLAG (ZPCI_IOTA_IOT_ENABLED | ZPCI_KEY | ZPCI_IOTA_DT_RS)
-#define ZPCI_IOTA_RFTO_FLAG (ZPCI_IOTA_IOT_ENABLED | ZPCI_KEY | ZPCI_IOTA_DT_RF)
-#define ZPCI_IOTA_RFAA_FLAG (ZPCI_IOTA_IOT_ENABLED | ZPCI_KEY |\
- ZPCI_IOTA_DT_PF | ZPCI_IOTA_FS_2G)
-
-/* I/O Region and segment tables */
-#define ZPCI_INDEX_MASK 0x7ffULL
-
-#define ZPCI_TABLE_TYPE_MASK 0xc
-#define ZPCI_TABLE_TYPE_RFX 0xc
-#define ZPCI_TABLE_TYPE_RSX 0x8
-#define ZPCI_TABLE_TYPE_RTX 0x4
-#define ZPCI_TABLE_TYPE_SX 0x0
-
-#define ZPCI_TABLE_LEN_RFX 0x3
-#define ZPCI_TABLE_LEN_RSX 0x3
-#define ZPCI_TABLE_LEN_RTX 0x3
-
-#define ZPCI_TABLE_OFFSET_MASK 0xc0
-#define ZPCI_TABLE_SIZE 0x4000
-#define ZPCI_TABLE_ALIGN ZPCI_TABLE_SIZE
-#define ZPCI_TABLE_ENTRY_SIZE (sizeof(unsigned long))
-#define ZPCI_TABLE_ENTRIES (ZPCI_TABLE_SIZE / ZPCI_TABLE_ENTRY_SIZE)
-
-#define ZPCI_TABLE_BITS 11
-#define ZPCI_PT_BITS 8
-#define ZPCI_ST_SHIFT (ZPCI_PT_BITS + PAGE_SHIFT)
-#define ZPCI_RT_SHIFT (ZPCI_ST_SHIFT + ZPCI_TABLE_BITS)
-
-#define ZPCI_RTE_FLAG_MASK 0x3fffULL
-#define ZPCI_RTE_ADDR_MASK (~ZPCI_RTE_FLAG_MASK)
-#define ZPCI_STE_FLAG_MASK 0x7ffULL
-#define ZPCI_STE_ADDR_MASK (~ZPCI_STE_FLAG_MASK)
-
-/* I/O Page tables */
-#define ZPCI_PTE_VALID_MASK 0x400
-#define ZPCI_PTE_INVALID 0x400
-#define ZPCI_PTE_VALID 0x000
-#define ZPCI_PT_SIZE 0x800
-#define ZPCI_PT_ALIGN ZPCI_PT_SIZE
-#define ZPCI_PT_ENTRIES (ZPCI_PT_SIZE / ZPCI_TABLE_ENTRY_SIZE)
-#define ZPCI_PT_MASK (ZPCI_PT_ENTRIES - 1)
-
-#define ZPCI_PTE_FLAG_MASK 0xfffULL
-#define ZPCI_PTE_ADDR_MASK (~ZPCI_PTE_FLAG_MASK)
-
-/* Shared bits */
-#define ZPCI_TABLE_VALID 0x00
-#define ZPCI_TABLE_INVALID 0x20
-#define ZPCI_TABLE_PROTECTED 0x200
-#define ZPCI_TABLE_UNPROTECTED 0x000
-
-#define ZPCI_TABLE_VALID_MASK 0x20
-#define ZPCI_TABLE_PROT_MASK 0x200
-
-typedef struct SeiContainer {
- QTAILQ_ENTRY(SeiContainer) link;
- uint32_t fid;
- uint32_t fh;
- uint8_t cc;
- uint16_t pec;
- uint64_t faddr;
- uint32_t e;
-} SeiContainer;
-
-typedef struct PciCcdfErr {
- uint32_t reserved1;
- uint32_t fh;
- uint32_t fid;
- uint32_t e;
- uint64_t faddr;
- uint32_t reserved3;
- uint16_t reserved4;
- uint16_t pec;
-} QEMU_PACKED PciCcdfErr;
-
-typedef struct PciCcdfAvail {
- uint32_t reserved1;
- uint32_t fh;
- uint32_t fid;
- uint32_t reserved2;
- uint32_t reserved3;
- uint32_t reserved4;
- uint32_t reserved5;
- uint16_t reserved6;
- uint16_t pec;
-} QEMU_PACKED PciCcdfAvail;
-
-typedef struct ChscSeiNt2Res {
- uint16_t length;
- uint16_t code;
- uint16_t reserved1;
- uint8_t reserved2;
- uint8_t nt;
- uint8_t flags;
- uint8_t reserved3;
- uint8_t reserved4;
- uint8_t cc;
- uint32_t reserved5[13];
- uint8_t ccdf[4016];
-} QEMU_PACKED ChscSeiNt2Res;
-
-typedef struct PciCfgSccb {
- SCCBHeader header;
- uint8_t atype;
- uint8_t reserved1;
- uint16_t reserved2;
- uint32_t aid;
-} QEMU_PACKED PciCfgSccb;
-
-typedef struct S390MsixInfo {
- bool available;
- uint8_t table_bar;
- uint8_t pba_bar;
- uint16_t entries;
- uint32_t table_offset;
- uint32_t pba_offset;
-} S390MsixInfo;
-
-typedef struct S390PCIBusDevice {
- PCIDevice *pdev;
- bool configured;
- bool error_state;
- bool lgstg_blocked;
- uint32_t fh;
- uint32_t fid;
- uint64_t g_iota;
- uint64_t pba;
- uint64_t pal;
- uint64_t fmb_addr;
- uint8_t isc;
- uint16_t noi;
- uint8_t sum;
- S390MsixInfo msix;
- AdapterRoutes routes;
- AddressSpace as;
- MemoryRegion mr;
- MemoryRegion iommu_mr;
- IndAddr *summary_ind;
- IndAddr *indicator;
-} S390PCIBusDevice;
-
-typedef struct S390pciState {
- PCIHostState parent_obj;
- S390PCIBusDevice pbdev[PCI_SLOT_MAX];
- AddressSpace msix_notify_as;
- MemoryRegion msix_notify_mr;
- QTAILQ_HEAD(, SeiContainer) pending_sei;
-} S390pciState;
-
-int chsc_sei_nt2_get_event(void *res);
-int chsc_sei_nt2_have_event(void);
-void s390_pci_sclp_configure(int configure, SCCB *sccb);
-void s390_pcihost_iommu_configure(S390PCIBusDevice *pbdev, bool enable);
-S390PCIBusDevice *s390_pci_find_dev_by_idx(uint32_t idx);
-S390PCIBusDevice *s390_pci_find_dev_by_fh(uint32_t fh);
-S390PCIBusDevice *s390_pci_find_dev_by_fid(uint32_t fid);
-
-#endif
diff --git a/qemu/hw/s390x/s390-pci-inst.c b/qemu/hw/s390x/s390-pci-inst.c
deleted file mode 100644
index b28e7d14f..000000000
--- a/qemu/hw/s390x/s390-pci-inst.c
+++ /dev/null
@@ -1,846 +0,0 @@
-/*
- * s390 PCI instructions
- *
- * Copyright 2014 IBM Corp.
- * Author(s): Frank Blaschka <frank.blaschka@de.ibm.com>
- * Hong Bo Li <lihbbj@cn.ibm.com>
- * Yi Min Zhao <zyimin@cn.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or (at
- * your option) any later version. See the COPYING file in the top-level
- * directory.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "s390-pci-inst.h"
-#include "s390-pci-bus.h"
-#include <exec/memory-internal.h>
-#include <qemu/error-report.h>
-
-/* #define DEBUG_S390PCI_INST */
-#ifdef DEBUG_S390PCI_INST
-#define DPRINTF(fmt, ...) \
- do { fprintf(stderr, "s390pci-inst: " fmt, ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) \
- do { } while (0)
-#endif
-
-static void s390_set_status_code(CPUS390XState *env,
- uint8_t r, uint64_t status_code)
-{
- env->regs[r] &= ~0xff000000ULL;
- env->regs[r] |= (status_code & 0xff) << 24;
-}
-
-static int list_pci(ClpReqRspListPci *rrb, uint8_t *cc)
-{
- S390PCIBusDevice *pbdev;
- uint32_t res_code, initial_l2, g_l2, finish;
- int rc, idx;
- uint64_t resume_token;
-
- rc = 0;
- if (lduw_p(&rrb->request.hdr.len) != 32) {
- res_code = CLP_RC_LEN;
- rc = -EINVAL;
- goto out;
- }
-
- if ((ldl_p(&rrb->request.fmt) & CLP_MASK_FMT) != 0) {
- res_code = CLP_RC_FMT;
- rc = -EINVAL;
- goto out;
- }
-
- if ((ldl_p(&rrb->request.fmt) & ~CLP_MASK_FMT) != 0 ||
- ldq_p(&rrb->request.reserved1) != 0 ||
- ldq_p(&rrb->request.reserved2) != 0) {
- res_code = CLP_RC_RESNOT0;
- rc = -EINVAL;
- goto out;
- }
-
- resume_token = ldq_p(&rrb->request.resume_token);
-
- if (resume_token) {
- pbdev = s390_pci_find_dev_by_idx(resume_token);
- if (!pbdev) {
- res_code = CLP_RC_LISTPCI_BADRT;
- rc = -EINVAL;
- goto out;
- }
- }
-
- if (lduw_p(&rrb->response.hdr.len) < 48) {
- res_code = CLP_RC_8K;
- rc = -EINVAL;
- goto out;
- }
-
- initial_l2 = lduw_p(&rrb->response.hdr.len);
- if ((initial_l2 - LIST_PCI_HDR_LEN) % sizeof(ClpFhListEntry)
- != 0) {
- res_code = CLP_RC_LEN;
- rc = -EINVAL;
- *cc = 3;
- goto out;
- }
-
- stl_p(&rrb->response.fmt, 0);
- stq_p(&rrb->response.reserved1, 0);
- stq_p(&rrb->response.reserved2, 0);
- stl_p(&rrb->response.mdd, FH_VIRT);
- stw_p(&rrb->response.max_fn, PCI_MAX_FUNCTIONS);
- rrb->response.entry_size = sizeof(ClpFhListEntry);
- finish = 0;
- idx = resume_token;
- g_l2 = LIST_PCI_HDR_LEN;
- do {
- pbdev = s390_pci_find_dev_by_idx(idx);
- if (!pbdev) {
- finish = 1;
- break;
- }
- stw_p(&rrb->response.fh_list[idx - resume_token].device_id,
- pci_get_word(pbdev->pdev->config + PCI_DEVICE_ID));
- stw_p(&rrb->response.fh_list[idx - resume_token].vendor_id,
- pci_get_word(pbdev->pdev->config + PCI_VENDOR_ID));
- stl_p(&rrb->response.fh_list[idx - resume_token].config,
- pbdev->configured << 31);
- stl_p(&rrb->response.fh_list[idx - resume_token].fid, pbdev->fid);
- stl_p(&rrb->response.fh_list[idx - resume_token].fh, pbdev->fh);
-
- g_l2 += sizeof(ClpFhListEntry);
- /* Add endian check for DPRINTF? */
- DPRINTF("g_l2 %d vendor id 0x%x device id 0x%x fid 0x%x fh 0x%x\n",
- g_l2,
- lduw_p(&rrb->response.fh_list[idx - resume_token].vendor_id),
- lduw_p(&rrb->response.fh_list[idx - resume_token].device_id),
- ldl_p(&rrb->response.fh_list[idx - resume_token].fid),
- ldl_p(&rrb->response.fh_list[idx - resume_token].fh));
- idx++;
- } while (g_l2 < initial_l2);
-
- if (finish == 1) {
- resume_token = 0;
- } else {
- resume_token = idx;
- }
- stq_p(&rrb->response.resume_token, resume_token);
- stw_p(&rrb->response.hdr.len, g_l2);
- stw_p(&rrb->response.hdr.rsp, CLP_RC_OK);
-out:
- if (rc) {
- DPRINTF("list pci failed rc 0x%x\n", rc);
- stw_p(&rrb->response.hdr.rsp, res_code);
- }
- return rc;
-}
-
-int clp_service_call(S390CPU *cpu, uint8_t r2)
-{
- ClpReqHdr *reqh;
- ClpRspHdr *resh;
- S390PCIBusDevice *pbdev;
- uint32_t req_len;
- uint32_t res_len;
- uint8_t buffer[4096 * 2];
- uint8_t cc = 0;
- CPUS390XState *env = &cpu->env;
- int i;
-
- cpu_synchronize_state(CPU(cpu));
-
- if (env->psw.mask & PSW_MASK_PSTATE) {
- program_interrupt(env, PGM_PRIVILEGED, 4);
- return 0;
- }
-
- if (s390_cpu_virt_mem_read(cpu, env->regs[r2], r2, buffer, sizeof(*reqh))) {
- return 0;
- }
- reqh = (ClpReqHdr *)buffer;
- req_len = lduw_p(&reqh->len);
- if (req_len < 16 || req_len > 8184 || (req_len % 8 != 0)) {
- program_interrupt(env, PGM_OPERAND, 4);
- return 0;
- }
-
- if (s390_cpu_virt_mem_read(cpu, env->regs[r2], r2, buffer,
- req_len + sizeof(*resh))) {
- return 0;
- }
- resh = (ClpRspHdr *)(buffer + req_len);
- res_len = lduw_p(&resh->len);
- if (res_len < 8 || res_len > 8176 || (res_len % 8 != 0)) {
- program_interrupt(env, PGM_OPERAND, 4);
- return 0;
- }
- if ((req_len + res_len) > 8192) {
- program_interrupt(env, PGM_OPERAND, 4);
- return 0;
- }
-
- if (s390_cpu_virt_mem_read(cpu, env->regs[r2], r2, buffer,
- req_len + res_len)) {
- return 0;
- }
-
- if (req_len != 32) {
- stw_p(&resh->rsp, CLP_RC_LEN);
- goto out;
- }
-
- switch (lduw_p(&reqh->cmd)) {
- case CLP_LIST_PCI: {
- ClpReqRspListPci *rrb = (ClpReqRspListPci *)buffer;
- list_pci(rrb, &cc);
- break;
- }
- case CLP_SET_PCI_FN: {
- ClpReqSetPci *reqsetpci = (ClpReqSetPci *)reqh;
- ClpRspSetPci *ressetpci = (ClpRspSetPci *)resh;
-
- pbdev = s390_pci_find_dev_by_fh(ldl_p(&reqsetpci->fh));
- if (!pbdev) {
- stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FH);
- goto out;
- }
-
- switch (reqsetpci->oc) {
- case CLP_SET_ENABLE_PCI_FN:
- pbdev->fh = pbdev->fh | FH_ENABLED;
- stl_p(&ressetpci->fh, pbdev->fh);
- stw_p(&ressetpci->hdr.rsp, CLP_RC_OK);
- break;
- case CLP_SET_DISABLE_PCI_FN:
- pbdev->fh = pbdev->fh & ~FH_ENABLED;
- pbdev->error_state = false;
- pbdev->lgstg_blocked = false;
- stl_p(&ressetpci->fh, pbdev->fh);
- stw_p(&ressetpci->hdr.rsp, CLP_RC_OK);
- break;
- default:
- DPRINTF("unknown set pci command\n");
- stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FHOP);
- break;
- }
- break;
- }
- case CLP_QUERY_PCI_FN: {
- ClpReqQueryPci *reqquery = (ClpReqQueryPci *)reqh;
- ClpRspQueryPci *resquery = (ClpRspQueryPci *)resh;
-
- pbdev = s390_pci_find_dev_by_fh(ldl_p(&reqquery->fh));
- if (!pbdev) {
- DPRINTF("query pci no pci dev\n");
- stw_p(&resquery->hdr.rsp, CLP_RC_SETPCIFN_FH);
- goto out;
- }
-
- for (i = 0; i < PCI_BAR_COUNT; i++) {
- uint32_t data = pci_get_long(pbdev->pdev->config +
- PCI_BASE_ADDRESS_0 + (i * 4));
-
- stl_p(&resquery->bar[i], data);
- resquery->bar_size[i] = pbdev->pdev->io_regions[i].size ?
- ctz64(pbdev->pdev->io_regions[i].size) : 0;
- DPRINTF("bar %d addr 0x%x size 0x%" PRIx64 "barsize 0x%x\n", i,
- ldl_p(&resquery->bar[i]),
- pbdev->pdev->io_regions[i].size,
- resquery->bar_size[i]);
- }
-
- stq_p(&resquery->sdma, ZPCI_SDMA_ADDR);
- stq_p(&resquery->edma, ZPCI_EDMA_ADDR);
- stw_p(&resquery->pchid, 0);
- stw_p(&resquery->ug, 1);
- stl_p(&resquery->uid, pbdev->fid);
- stw_p(&resquery->hdr.rsp, CLP_RC_OK);
- break;
- }
- case CLP_QUERY_PCI_FNGRP: {
- ClpRspQueryPciGrp *resgrp = (ClpRspQueryPciGrp *)resh;
- resgrp->fr = 1;
- stq_p(&resgrp->dasm, 0);
- stq_p(&resgrp->msia, ZPCI_MSI_ADDR);
- stw_p(&resgrp->mui, 0);
- stw_p(&resgrp->i, 128);
- resgrp->version = 0;
-
- stw_p(&resgrp->hdr.rsp, CLP_RC_OK);
- break;
- }
- default:
- DPRINTF("unknown clp command\n");
- stw_p(&resh->rsp, CLP_RC_CMD);
- break;
- }
-
-out:
- if (s390_cpu_virt_mem_write(cpu, env->regs[r2], r2, buffer,
- req_len + res_len)) {
- return 0;
- }
- setcc(cpu, cc);
- return 0;
-}
-
-int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
-{
- CPUS390XState *env = &cpu->env;
- S390PCIBusDevice *pbdev;
- uint64_t offset;
- uint64_t data;
- uint8_t len;
- uint32_t fh;
- uint8_t pcias;
-
- cpu_synchronize_state(CPU(cpu));
-
- if (env->psw.mask & PSW_MASK_PSTATE) {
- program_interrupt(env, PGM_PRIVILEGED, 4);
- return 0;
- }
-
- if (r2 & 0x1) {
- program_interrupt(env, PGM_SPECIFICATION, 4);
- return 0;
- }
-
- fh = env->regs[r2] >> 32;
- pcias = (env->regs[r2] >> 16) & 0xf;
- len = env->regs[r2] & 0xf;
- offset = env->regs[r2 + 1];
-
- pbdev = s390_pci_find_dev_by_fh(fh);
- if (!pbdev || !(pbdev->fh & FH_ENABLED)) {
- DPRINTF("pcilg no pci dev\n");
- setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
- return 0;
- }
-
- if (pbdev->lgstg_blocked) {
- setcc(cpu, ZPCI_PCI_LS_ERR);
- s390_set_status_code(env, r2, ZPCI_PCI_ST_BLOCKED);
- return 0;
- }
-
- if (pcias < 6) {
- if ((8 - (offset & 0x7)) < len) {
- program_interrupt(env, PGM_OPERAND, 4);
- return 0;
- }
- MemoryRegion *mr = pbdev->pdev->io_regions[pcias].memory;
- memory_region_dispatch_read(mr, offset, &data, len,
- MEMTXATTRS_UNSPECIFIED);
- } else if (pcias == 15) {
- if ((4 - (offset & 0x3)) < len) {
- program_interrupt(env, PGM_OPERAND, 4);
- return 0;
- }
- data = pci_host_config_read_common(
- pbdev->pdev, offset, pci_config_size(pbdev->pdev), len);
-
- switch (len) {
- case 1:
- break;
- case 2:
- data = bswap16(data);
- break;
- case 4:
- data = bswap32(data);
- break;
- case 8:
- data = bswap64(data);
- break;
- default:
- program_interrupt(env, PGM_OPERAND, 4);
- return 0;
- }
- } else {
- DPRINTF("invalid space\n");
- setcc(cpu, ZPCI_PCI_LS_ERR);
- s390_set_status_code(env, r2, ZPCI_PCI_ST_INVAL_AS);
- return 0;
- }
-
- env->regs[r1] = data;
- setcc(cpu, ZPCI_PCI_LS_OK);
- return 0;
-}
-
-static void update_msix_table_msg_data(S390PCIBusDevice *pbdev, uint64_t offset,
- uint64_t *data, uint8_t len)
-{
- uint32_t val;
- uint8_t *msg_data;
-
- if (offset % PCI_MSIX_ENTRY_SIZE != 8) {
- return;
- }
-
- if (len != 4) {
- DPRINTF("access msix table msg data but len is %d\n", len);
- return;
- }
-
- msg_data = (uint8_t *)data - offset % PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_VECTOR_CTRL;
- val = pci_get_long(msg_data) | (pbdev->fid << ZPCI_MSI_VEC_BITS);
- pci_set_long(msg_data, val);
- DPRINTF("update msix msg_data to 0x%" PRIx64 "\n", *data);
-}
-
-static int trap_msix(S390PCIBusDevice *pbdev, uint64_t offset, uint8_t pcias)
-{
- if (pbdev->msix.available && pbdev->msix.table_bar == pcias &&
- offset >= pbdev->msix.table_offset &&
- offset <= pbdev->msix.table_offset +
- (pbdev->msix.entries - 1) * PCI_MSIX_ENTRY_SIZE) {
- return 1;
- } else {
- return 0;
- }
-}
-
-int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
-{
- CPUS390XState *env = &cpu->env;
- uint64_t offset, data;
- S390PCIBusDevice *pbdev;
- uint8_t len;
- uint32_t fh;
- uint8_t pcias;
-
- cpu_synchronize_state(CPU(cpu));
-
- if (env->psw.mask & PSW_MASK_PSTATE) {
- program_interrupt(env, PGM_PRIVILEGED, 4);
- return 0;
- }
-
- if (r2 & 0x1) {
- program_interrupt(env, PGM_SPECIFICATION, 4);
- return 0;
- }
-
- fh = env->regs[r2] >> 32;
- pcias = (env->regs[r2] >> 16) & 0xf;
- len = env->regs[r2] & 0xf;
- offset = env->regs[r2 + 1];
-
- pbdev = s390_pci_find_dev_by_fh(fh);
- if (!pbdev || !(pbdev->fh & FH_ENABLED)) {
- DPRINTF("pcistg no pci dev\n");
- setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
- return 0;
- }
-
- if (pbdev->lgstg_blocked) {
- setcc(cpu, ZPCI_PCI_LS_ERR);
- s390_set_status_code(env, r2, ZPCI_PCI_ST_BLOCKED);
- return 0;
- }
-
- data = env->regs[r1];
- if (pcias < 6) {
- if ((8 - (offset & 0x7)) < len) {
- program_interrupt(env, PGM_OPERAND, 4);
- return 0;
- }
- MemoryRegion *mr;
- if (trap_msix(pbdev, offset, pcias)) {
- offset = offset - pbdev->msix.table_offset;
- mr = &pbdev->pdev->msix_table_mmio;
- update_msix_table_msg_data(pbdev, offset, &data, len);
- } else {
- mr = pbdev->pdev->io_regions[pcias].memory;
- }
-
- memory_region_dispatch_write(mr, offset, data, len,
- MEMTXATTRS_UNSPECIFIED);
- } else if (pcias == 15) {
- if ((4 - (offset & 0x3)) < len) {
- program_interrupt(env, PGM_OPERAND, 4);
- return 0;
- }
- switch (len) {
- case 1:
- break;
- case 2:
- data = bswap16(data);
- break;
- case 4:
- data = bswap32(data);
- break;
- case 8:
- data = bswap64(data);
- break;
- default:
- program_interrupt(env, PGM_OPERAND, 4);
- return 0;
- }
-
- pci_host_config_write_common(pbdev->pdev, offset,
- pci_config_size(pbdev->pdev),
- data, len);
- } else {
- DPRINTF("pcistg invalid space\n");
- setcc(cpu, ZPCI_PCI_LS_ERR);
- s390_set_status_code(env, r2, ZPCI_PCI_ST_INVAL_AS);
- return 0;
- }
-
- setcc(cpu, ZPCI_PCI_LS_OK);
- return 0;
-}
-
-int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
-{
- CPUS390XState *env = &cpu->env;
- uint32_t fh;
- S390PCIBusDevice *pbdev;
- hwaddr start, end;
- IOMMUTLBEntry entry;
- MemoryRegion *mr;
-
- cpu_synchronize_state(CPU(cpu));
-
- if (env->psw.mask & PSW_MASK_PSTATE) {
- program_interrupt(env, PGM_PRIVILEGED, 4);
- goto out;
- }
-
- if (r2 & 0x1) {
- program_interrupt(env, PGM_SPECIFICATION, 4);
- goto out;
- }
-
- fh = env->regs[r1] >> 32;
- start = env->regs[r2];
- end = start + env->regs[r2 + 1];
-
- pbdev = s390_pci_find_dev_by_fh(fh);
- if (!pbdev || !(pbdev->fh & FH_ENABLED)) {
- DPRINTF("rpcit no pci dev\n");
- setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
- goto out;
- }
-
- mr = &pbdev->iommu_mr;
- while (start < end) {
- entry = mr->iommu_ops->translate(mr, start, 0);
-
- if (!entry.translated_addr) {
- setcc(cpu, ZPCI_PCI_LS_ERR);
- goto out;
- }
-
- memory_region_notify_iommu(mr, entry);
- start += entry.addr_mask + 1;
- }
-
- setcc(cpu, ZPCI_PCI_LS_OK);
-out:
- return 0;
-}
-
-int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr,
- uint8_t ar)
-{
- CPUS390XState *env = &cpu->env;
- S390PCIBusDevice *pbdev;
- MemoryRegion *mr;
- int i;
- uint32_t fh;
- uint8_t pcias;
- uint8_t len;
- uint8_t buffer[128];
-
- if (env->psw.mask & PSW_MASK_PSTATE) {
- program_interrupt(env, PGM_PRIVILEGED, 6);
- return 0;
- }
-
- fh = env->regs[r1] >> 32;
- pcias = (env->regs[r1] >> 16) & 0xf;
- len = env->regs[r1] & 0xff;
-
- if (pcias > 5) {
- DPRINTF("pcistb invalid space\n");
- setcc(cpu, ZPCI_PCI_LS_ERR);
- s390_set_status_code(env, r1, ZPCI_PCI_ST_INVAL_AS);
- return 0;
- }
-
- switch (len) {
- case 16:
- case 32:
- case 64:
- case 128:
- break;
- default:
- program_interrupt(env, PGM_SPECIFICATION, 6);
- return 0;
- }
-
- pbdev = s390_pci_find_dev_by_fh(fh);
- if (!pbdev || !(pbdev->fh & FH_ENABLED)) {
- DPRINTF("pcistb no pci dev fh 0x%x\n", fh);
- setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
- return 0;
- }
-
- if (pbdev->lgstg_blocked) {
- setcc(cpu, ZPCI_PCI_LS_ERR);
- s390_set_status_code(env, r1, ZPCI_PCI_ST_BLOCKED);
- return 0;
- }
-
- mr = pbdev->pdev->io_regions[pcias].memory;
- if (!memory_region_access_valid(mr, env->regs[r3], len, true)) {
- program_interrupt(env, PGM_ADDRESSING, 6);
- return 0;
- }
-
- if (s390_cpu_virt_mem_read(cpu, gaddr, ar, buffer, len)) {
- return 0;
- }
-
- for (i = 0; i < len / 8; i++) {
- memory_region_dispatch_write(mr, env->regs[r3] + i * 8,
- ldq_p(buffer + i * 8), 8,
- MEMTXATTRS_UNSPECIFIED);
- }
-
- setcc(cpu, ZPCI_PCI_LS_OK);
- return 0;
-}
-
-static int reg_irqs(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib)
-{
- int ret, len;
-
- ret = css_register_io_adapter(S390_PCIPT_ADAPTER,
- FIB_DATA_ISC(ldl_p(&fib.data)), true, false,
- &pbdev->routes.adapter.adapter_id);
- assert(ret == 0);
-
- pbdev->summary_ind = get_indicator(ldq_p(&fib.aisb), sizeof(uint64_t));
- len = BITS_TO_LONGS(FIB_DATA_NOI(ldl_p(&fib.data))) * sizeof(unsigned long);
- pbdev->indicator = get_indicator(ldq_p(&fib.aibv), len);
-
- map_indicator(&pbdev->routes.adapter, pbdev->summary_ind);
- map_indicator(&pbdev->routes.adapter, pbdev->indicator);
-
- pbdev->routes.adapter.summary_addr = ldq_p(&fib.aisb);
- pbdev->routes.adapter.summary_offset = FIB_DATA_AISBO(ldl_p(&fib.data));
- pbdev->routes.adapter.ind_addr = ldq_p(&fib.aibv);
- pbdev->routes.adapter.ind_offset = FIB_DATA_AIBVO(ldl_p(&fib.data));
- pbdev->isc = FIB_DATA_ISC(ldl_p(&fib.data));
- pbdev->noi = FIB_DATA_NOI(ldl_p(&fib.data));
- pbdev->sum = FIB_DATA_SUM(ldl_p(&fib.data));
-
- DPRINTF("reg_irqs adapter id %d\n", pbdev->routes.adapter.adapter_id);
- return 0;
-}
-
-static int dereg_irqs(S390PCIBusDevice *pbdev)
-{
- release_indicator(&pbdev->routes.adapter, pbdev->summary_ind);
- release_indicator(&pbdev->routes.adapter, pbdev->indicator);
-
- pbdev->summary_ind = NULL;
- pbdev->indicator = NULL;
- pbdev->routes.adapter.summary_addr = 0;
- pbdev->routes.adapter.summary_offset = 0;
- pbdev->routes.adapter.ind_addr = 0;
- pbdev->routes.adapter.ind_offset = 0;
- pbdev->isc = 0;
- pbdev->noi = 0;
- pbdev->sum = 0;
-
- DPRINTF("dereg_irqs adapter id %d\n", pbdev->routes.adapter.adapter_id);
- return 0;
-}
-
-static int reg_ioat(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib)
-{
- uint64_t pba = ldq_p(&fib.pba);
- uint64_t pal = ldq_p(&fib.pal);
- uint64_t g_iota = ldq_p(&fib.iota);
- uint8_t dt = (g_iota >> 2) & 0x7;
- uint8_t t = (g_iota >> 11) & 0x1;
-
- if (pba > pal || pba < ZPCI_SDMA_ADDR || pal > ZPCI_EDMA_ADDR) {
- program_interrupt(env, PGM_OPERAND, 6);
- return -EINVAL;
- }
-
- /* currently we only support designation type 1 with translation */
- if (!(dt == ZPCI_IOTA_RTTO && t)) {
- error_report("unsupported ioat dt %d t %d", dt, t);
- program_interrupt(env, PGM_OPERAND, 6);
- return -EINVAL;
- }
-
- pbdev->pba = pba;
- pbdev->pal = pal;
- pbdev->g_iota = g_iota;
-
- s390_pcihost_iommu_configure(pbdev, true);
-
- return 0;
-}
-
-static void dereg_ioat(S390PCIBusDevice *pbdev)
-{
- pbdev->pba = 0;
- pbdev->pal = 0;
- pbdev->g_iota = 0;
-
- s390_pcihost_iommu_configure(pbdev, false);
-}
-
-int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar)
-{
- CPUS390XState *env = &cpu->env;
- uint8_t oc;
- uint32_t fh;
- ZpciFib fib;
- S390PCIBusDevice *pbdev;
- uint64_t cc = ZPCI_PCI_LS_OK;
-
- if (env->psw.mask & PSW_MASK_PSTATE) {
- program_interrupt(env, PGM_PRIVILEGED, 6);
- return 0;
- }
-
- oc = env->regs[r1] & 0xff;
- fh = env->regs[r1] >> 32;
-
- if (fiba & 0x7) {
- program_interrupt(env, PGM_SPECIFICATION, 6);
- return 0;
- }
-
- pbdev = s390_pci_find_dev_by_fh(fh);
- if (!pbdev || !(pbdev->fh & FH_ENABLED)) {
- DPRINTF("mpcifc no pci dev fh 0x%x\n", fh);
- setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
- return 0;
- }
-
- if (s390_cpu_virt_mem_read(cpu, fiba, ar, (uint8_t *)&fib, sizeof(fib))) {
- return 0;
- }
-
- switch (oc) {
- case ZPCI_MOD_FC_REG_INT:
- if (reg_irqs(env, pbdev, fib)) {
- cc = ZPCI_PCI_LS_ERR;
- }
- break;
- case ZPCI_MOD_FC_DEREG_INT:
- dereg_irqs(pbdev);
- break;
- case ZPCI_MOD_FC_REG_IOAT:
- if (reg_ioat(env, pbdev, fib)) {
- cc = ZPCI_PCI_LS_ERR;
- }
- break;
- case ZPCI_MOD_FC_DEREG_IOAT:
- dereg_ioat(pbdev);
- break;
- case ZPCI_MOD_FC_REREG_IOAT:
- dereg_ioat(pbdev);
- if (reg_ioat(env, pbdev, fib)) {
- cc = ZPCI_PCI_LS_ERR;
- }
- break;
- case ZPCI_MOD_FC_RESET_ERROR:
- pbdev->error_state = false;
- pbdev->lgstg_blocked = false;
- break;
- case ZPCI_MOD_FC_RESET_BLOCK:
- pbdev->lgstg_blocked = false;
- break;
- case ZPCI_MOD_FC_SET_MEASURE:
- pbdev->fmb_addr = ldq_p(&fib.fmb_addr);
- break;
- default:
- program_interrupt(&cpu->env, PGM_OPERAND, 6);
- cc = ZPCI_PCI_LS_ERR;
- }
-
- setcc(cpu, cc);
- return 0;
-}
-
-int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar)
-{
- CPUS390XState *env = &cpu->env;
- uint32_t fh;
- ZpciFib fib;
- S390PCIBusDevice *pbdev;
- uint32_t data;
- uint64_t cc = ZPCI_PCI_LS_OK;
-
- if (env->psw.mask & PSW_MASK_PSTATE) {
- program_interrupt(env, PGM_PRIVILEGED, 6);
- return 0;
- }
-
- fh = env->regs[r1] >> 32;
-
- if (fiba & 0x7) {
- program_interrupt(env, PGM_SPECIFICATION, 6);
- return 0;
- }
-
- pbdev = s390_pci_find_dev_by_fh(fh);
- if (!pbdev) {
- setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
- return 0;
- }
-
- memset(&fib, 0, sizeof(fib));
- stq_p(&fib.pba, pbdev->pba);
- stq_p(&fib.pal, pbdev->pal);
- stq_p(&fib.iota, pbdev->g_iota);
- stq_p(&fib.aibv, pbdev->routes.adapter.ind_addr);
- stq_p(&fib.aisb, pbdev->routes.adapter.summary_addr);
- stq_p(&fib.fmb_addr, pbdev->fmb_addr);
-
- data = ((uint32_t)pbdev->isc << 28) | ((uint32_t)pbdev->noi << 16) |
- ((uint32_t)pbdev->routes.adapter.ind_offset << 8) |
- ((uint32_t)pbdev->sum << 7) | pbdev->routes.adapter.summary_offset;
- stl_p(&fib.data, data);
-
- if (pbdev->fh & FH_ENABLED) {
- fib.fc |= 0x80;
- }
-
- if (pbdev->error_state) {
- fib.fc |= 0x40;
- }
-
- if (pbdev->lgstg_blocked) {
- fib.fc |= 0x20;
- }
-
- if (pbdev->g_iota) {
- fib.fc |= 0x10;
- }
-
- if (s390_cpu_virt_mem_write(cpu, fiba, ar, (uint8_t *)&fib, sizeof(fib))) {
- return 0;
- }
-
- setcc(cpu, cc);
- return 0;
-}
diff --git a/qemu/hw/s390x/s390-pci-inst.h b/qemu/hw/s390x/s390-pci-inst.h
deleted file mode 100644
index 70fa71395..000000000
--- a/qemu/hw/s390x/s390-pci-inst.h
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * s390 PCI instruction definitions
- *
- * Copyright 2014 IBM Corp.
- * Author(s): Frank Blaschka <frank.blaschka@de.ibm.com>
- * Hong Bo Li <lihbbj@cn.ibm.com>
- * Yi Min Zhao <zyimin@cn.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or (at
- * your option) any later version. See the COPYING file in the top-level
- * directory.
- */
-
-#ifndef HW_S390_PCI_INST_H
-#define HW_S390_PCI_INST_H
-
-#include <sysemu/dma.h>
-
-/* CLP common request & response block size */
-#define CLP_BLK_SIZE 4096
-#define PCI_BAR_COUNT 6
-#define PCI_MAX_FUNCTIONS 4096
-
-typedef struct ClpReqHdr {
- uint16_t len;
- uint16_t cmd;
-} QEMU_PACKED ClpReqHdr;
-
-typedef struct ClpRspHdr {
- uint16_t len;
- uint16_t rsp;
-} QEMU_PACKED ClpRspHdr;
-
-/* CLP Response Codes */
-#define CLP_RC_OK 0x0010 /* Command request successfully */
-#define CLP_RC_CMD 0x0020 /* Command code not recognized */
-#define CLP_RC_PERM 0x0030 /* Command not authorized */
-#define CLP_RC_FMT 0x0040 /* Invalid command request format */
-#define CLP_RC_LEN 0x0050 /* Invalid command request length */
-#define CLP_RC_8K 0x0060 /* Command requires 8K LPCB */
-#define CLP_RC_RESNOT0 0x0070 /* Reserved field not zero */
-#define CLP_RC_NODATA 0x0080 /* No data available */
-#define CLP_RC_FC_UNKNOWN 0x0100 /* Function code not recognized */
-
-/*
- * Call Logical Processor - Command Codes
- */
-#define CLP_LIST_PCI 0x0002
-#define CLP_QUERY_PCI_FN 0x0003
-#define CLP_QUERY_PCI_FNGRP 0x0004
-#define CLP_SET_PCI_FN 0x0005
-
-/* PCI function handle list entry */
-typedef struct ClpFhListEntry {
- uint16_t device_id;
- uint16_t vendor_id;
-#define CLP_FHLIST_MASK_CONFIG 0x80000000
- uint32_t config;
- uint32_t fid;
- uint32_t fh;
-} QEMU_PACKED ClpFhListEntry;
-
-#define CLP_RC_SETPCIFN_FH 0x0101 /* Invalid PCI fn handle */
-#define CLP_RC_SETPCIFN_FHOP 0x0102 /* Fn handle not valid for op */
-#define CLP_RC_SETPCIFN_DMAAS 0x0103 /* Invalid DMA addr space */
-#define CLP_RC_SETPCIFN_RES 0x0104 /* Insufficient resources */
-#define CLP_RC_SETPCIFN_ALRDY 0x0105 /* Fn already in requested state */
-#define CLP_RC_SETPCIFN_ERR 0x0106 /* Fn in permanent error state */
-#define CLP_RC_SETPCIFN_RECPND 0x0107 /* Error recovery pending */
-#define CLP_RC_SETPCIFN_BUSY 0x0108 /* Fn busy */
-#define CLP_RC_LISTPCI_BADRT 0x010a /* Resume token not recognized */
-#define CLP_RC_QUERYPCIFG_PFGID 0x010b /* Unrecognized PFGID */
-
-/* request or response block header length */
-#define LIST_PCI_HDR_LEN 32
-
-/* Number of function handles fitting in response block */
-#define CLP_FH_LIST_NR_ENTRIES \
- ((CLP_BLK_SIZE - 2 * LIST_PCI_HDR_LEN) \
- / sizeof(ClpFhListEntry))
-
-#define CLP_SET_ENABLE_PCI_FN 0 /* Yes, 0 enables it */
-#define CLP_SET_DISABLE_PCI_FN 1 /* Yes, 1 disables it */
-
-#define CLP_UTIL_STR_LEN 64
-
-#define CLP_MASK_FMT 0xf0000000
-
-/* List PCI functions request */
-typedef struct ClpReqListPci {
- ClpReqHdr hdr;
- uint32_t fmt;
- uint64_t reserved1;
- uint64_t resume_token;
- uint64_t reserved2;
-} QEMU_PACKED ClpReqListPci;
-
-/* List PCI functions response */
-typedef struct ClpRspListPci {
- ClpRspHdr hdr;
- uint32_t fmt;
- uint64_t reserved1;
- uint64_t resume_token;
- uint32_t mdd;
- uint16_t max_fn;
- uint8_t reserved2;
- uint8_t entry_size;
- ClpFhListEntry fh_list[CLP_FH_LIST_NR_ENTRIES];
-} QEMU_PACKED ClpRspListPci;
-
-/* Query PCI function request */
-typedef struct ClpReqQueryPci {
- ClpReqHdr hdr;
- uint32_t fmt;
- uint64_t reserved1;
- uint32_t fh; /* function handle */
- uint32_t reserved2;
- uint64_t reserved3;
-} QEMU_PACKED ClpReqQueryPci;
-
-/* Query PCI function response */
-typedef struct ClpRspQueryPci {
- ClpRspHdr hdr;
- uint32_t fmt;
- uint64_t reserved1;
- uint16_t vfn; /* virtual fn number */
-#define CLP_RSP_QPCI_MASK_UTIL 0x100
-#define CLP_RSP_QPCI_MASK_PFGID 0xff
- uint16_t ug;
- uint32_t fid; /* pci function id */
- uint8_t bar_size[PCI_BAR_COUNT];
- uint16_t pchid;
- uint32_t bar[PCI_BAR_COUNT];
- uint64_t reserved2;
- uint64_t sdma; /* start dma as */
- uint64_t edma; /* end dma as */
- uint32_t reserved3[11];
- uint32_t uid;
- uint8_t util_str[CLP_UTIL_STR_LEN]; /* utility string */
-} QEMU_PACKED ClpRspQueryPci;
-
-/* Query PCI function group request */
-typedef struct ClpReqQueryPciGrp {
- ClpReqHdr hdr;
- uint32_t fmt;
- uint64_t reserved1;
-#define CLP_REQ_QPCIG_MASK_PFGID 0xff
- uint32_t g;
- uint32_t reserved2;
- uint64_t reserved3;
-} QEMU_PACKED ClpReqQueryPciGrp;
-
-/* Query PCI function group response */
-typedef struct ClpRspQueryPciGrp {
- ClpRspHdr hdr;
- uint32_t fmt;
- uint64_t reserved1;
-#define CLP_RSP_QPCIG_MASK_NOI 0xfff
- uint16_t i;
- uint8_t version;
-#define CLP_RSP_QPCIG_MASK_FRAME 0x2
-#define CLP_RSP_QPCIG_MASK_REFRESH 0x1
- uint8_t fr;
- uint16_t reserved2;
- uint16_t mui;
- uint64_t reserved3;
- uint64_t dasm; /* dma address space mask */
- uint64_t msia; /* MSI address */
- uint64_t reserved4;
- uint64_t reserved5;
-} QEMU_PACKED ClpRspQueryPciGrp;
-
-/* Set PCI function request */
-typedef struct ClpReqSetPci {
- ClpReqHdr hdr;
- uint32_t fmt;
- uint64_t reserved1;
- uint32_t fh; /* function handle */
- uint16_t reserved2;
- uint8_t oc; /* operation controls */
- uint8_t ndas; /* number of dma spaces */
- uint64_t reserved3;
-} QEMU_PACKED ClpReqSetPci;
-
-/* Set PCI function response */
-typedef struct ClpRspSetPci {
- ClpRspHdr hdr;
- uint32_t fmt;
- uint64_t reserved1;
- uint32_t fh; /* function handle */
- uint32_t reserved3;
- uint64_t reserved4;
-} QEMU_PACKED ClpRspSetPci;
-
-typedef struct ClpReqRspListPci {
- ClpReqListPci request;
- ClpRspListPci response;
-} QEMU_PACKED ClpReqRspListPci;
-
-typedef struct ClpReqRspSetPci {
- ClpReqSetPci request;
- ClpRspSetPci response;
-} QEMU_PACKED ClpReqRspSetPci;
-
-typedef struct ClpReqRspQueryPci {
- ClpReqQueryPci request;
- ClpRspQueryPci response;
-} QEMU_PACKED ClpReqRspQueryPci;
-
-typedef struct ClpReqRspQueryPciGrp {
- ClpReqQueryPciGrp request;
- ClpRspQueryPciGrp response;
-} QEMU_PACKED ClpReqRspQueryPciGrp;
-
-/* Load/Store status codes */
-#define ZPCI_PCI_ST_FUNC_NOT_ENABLED 4
-#define ZPCI_PCI_ST_FUNC_IN_ERR 8
-#define ZPCI_PCI_ST_BLOCKED 12
-#define ZPCI_PCI_ST_INSUF_RES 16
-#define ZPCI_PCI_ST_INVAL_AS 20
-#define ZPCI_PCI_ST_FUNC_ALREADY_ENABLED 24
-#define ZPCI_PCI_ST_DMA_AS_NOT_ENABLED 28
-#define ZPCI_PCI_ST_2ND_OP_IN_INV_AS 36
-#define ZPCI_PCI_ST_FUNC_NOT_AVAIL 40
-#define ZPCI_PCI_ST_ALREADY_IN_RQ_STATE 44
-
-/* Load/Store return codes */
-#define ZPCI_PCI_LS_OK 0
-#define ZPCI_PCI_LS_ERR 1
-#define ZPCI_PCI_LS_BUSY 2
-#define ZPCI_PCI_LS_INVAL_HANDLE 3
-
-/* Modify PCI Function Controls */
-#define ZPCI_MOD_FC_REG_INT 2
-#define ZPCI_MOD_FC_DEREG_INT 3
-#define ZPCI_MOD_FC_REG_IOAT 4
-#define ZPCI_MOD_FC_DEREG_IOAT 5
-#define ZPCI_MOD_FC_REREG_IOAT 6
-#define ZPCI_MOD_FC_RESET_ERROR 7
-#define ZPCI_MOD_FC_RESET_BLOCK 9
-#define ZPCI_MOD_FC_SET_MEASURE 10
-
-/* FIB function controls */
-#define ZPCI_FIB_FC_ENABLED 0x80
-#define ZPCI_FIB_FC_ERROR 0x40
-#define ZPCI_FIB_FC_LS_BLOCKED 0x20
-#define ZPCI_FIB_FC_DMAAS_REG 0x10
-
-/* FIB function controls */
-#define ZPCI_FIB_FC_ENABLED 0x80
-#define ZPCI_FIB_FC_ERROR 0x40
-#define ZPCI_FIB_FC_LS_BLOCKED 0x20
-#define ZPCI_FIB_FC_DMAAS_REG 0x10
-
-/* Function Information Block */
-typedef struct ZpciFib {
- uint8_t fmt; /* format */
- uint8_t reserved1[7];
- uint8_t fc; /* function controls */
- uint8_t reserved2;
- uint16_t reserved3;
- uint32_t reserved4;
- uint64_t pba; /* PCI base address */
- uint64_t pal; /* PCI address limit */
- uint64_t iota; /* I/O Translation Anchor */
-#define FIB_DATA_ISC(x) (((x) >> 28) & 0x7)
-#define FIB_DATA_NOI(x) (((x) >> 16) & 0xfff)
-#define FIB_DATA_AIBVO(x) (((x) >> 8) & 0x3f)
-#define FIB_DATA_SUM(x) (((x) >> 7) & 0x1)
-#define FIB_DATA_AISBO(x) ((x) & 0x3f)
- uint32_t data;
- uint32_t reserved5;
- uint64_t aibv; /* Adapter int bit vector address */
- uint64_t aisb; /* Adapter int summary bit address */
- uint64_t fmb_addr; /* Function measurement address and key */
- uint32_t reserved6;
- uint32_t gd;
-} QEMU_PACKED ZpciFib;
-
-int clp_service_call(S390CPU *cpu, uint8_t r2);
-int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2);
-int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2);
-int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2);
-int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr,
- uint8_t ar);
-int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar);
-int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar);
-
-#endif
diff --git a/qemu/hw/s390x/s390-skeys-kvm.c b/qemu/hw/s390x/s390-skeys-kvm.c
deleted file mode 100644
index 131da56bb..000000000
--- a/qemu/hw/s390x/s390-skeys-kvm.c
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * s390 storage key device
- *
- * Copyright 2015 IBM Corp.
- * Author(s): Jason J. Herne <jjherne@linux.vnet.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or (at
- * your option) any later version. See the COPYING file in the top-level
- * directory.
- */
-
-#include "qemu/osdep.h"
-#include "hw/s390x/storage-keys.h"
-#include "sysemu/kvm.h"
-#include "qemu/error-report.h"
-
-static int kvm_s390_skeys_enabled(S390SKeysState *ss)
-{
- S390SKeysClass *skeyclass = S390_SKEYS_GET_CLASS(ss);
- uint8_t single_key;
- int r;
-
- r = skeyclass->get_skeys(ss, 0, 1, &single_key);
- if (r != 0 && r != KVM_S390_GET_SKEYS_NONE) {
- error_report("S390_GET_KEYS error %d", r);
- }
- return (r == 0);
-}
-
-static int kvm_s390_skeys_get(S390SKeysState *ss, uint64_t start_gfn,
- uint64_t count, uint8_t *keys)
-{
- struct kvm_s390_skeys args = {
- .start_gfn = start_gfn,
- .count = count,
- .skeydata_addr = (__u64)keys
- };
-
- return kvm_vm_ioctl(kvm_state, KVM_S390_GET_SKEYS, &args);
-}
-
-static int kvm_s390_skeys_set(S390SKeysState *ss, uint64_t start_gfn,
- uint64_t count, uint8_t *keys)
-{
- struct kvm_s390_skeys args = {
- .start_gfn = start_gfn,
- .count = count,
- .skeydata_addr = (__u64)keys
- };
-
- return kvm_vm_ioctl(kvm_state, KVM_S390_SET_SKEYS, &args);
-}
-
-static void kvm_s390_skeys_class_init(ObjectClass *oc, void *data)
-{
- S390SKeysClass *skeyclass = S390_SKEYS_CLASS(oc);
-
- skeyclass->skeys_enabled = kvm_s390_skeys_enabled;
- skeyclass->get_skeys = kvm_s390_skeys_get;
- skeyclass->set_skeys = kvm_s390_skeys_set;
-}
-
-static const TypeInfo kvm_s390_skeys_info = {
- .name = TYPE_KVM_S390_SKEYS,
- .parent = TYPE_S390_SKEYS,
- .instance_size = sizeof(S390SKeysState),
- .class_init = kvm_s390_skeys_class_init,
- .class_size = sizeof(S390SKeysClass),
-};
-
-static void kvm_s390_skeys_register_types(void)
-{
- type_register_static(&kvm_s390_skeys_info);
-}
-
-type_init(kvm_s390_skeys_register_types)
diff --git a/qemu/hw/s390x/s390-skeys.c b/qemu/hw/s390x/s390-skeys.c
deleted file mode 100644
index 6528ffed1..000000000
--- a/qemu/hw/s390x/s390-skeys.c
+++ /dev/null
@@ -1,415 +0,0 @@
-/*
- * s390 storage key device
- *
- * Copyright 2015 IBM Corp.
- * Author(s): Jason J. Herne <jjherne@linux.vnet.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or (at
- * your option) any later version. See the COPYING file in the top-level
- * directory.
- */
-
-#include "qemu/osdep.h"
-#include "hw/boards.h"
-#include "qmp-commands.h"
-#include "migration/qemu-file.h"
-#include "hw/s390x/storage-keys.h"
-#include "qemu/error-report.h"
-
-#define S390_SKEYS_BUFFER_SIZE 131072 /* Room for 128k storage keys */
-#define S390_SKEYS_SAVE_FLAG_EOS 0x01
-#define S390_SKEYS_SAVE_FLAG_SKEYS 0x02
-#define S390_SKEYS_SAVE_FLAG_ERROR 0x04
-
-S390SKeysState *s390_get_skeys_device(void)
-{
- S390SKeysState *ss;
-
- ss = S390_SKEYS(object_resolve_path_type("", TYPE_S390_SKEYS, NULL));
- assert(ss);
- return ss;
-}
-
-void s390_skeys_init(void)
-{
- Object *obj;
-
- if (kvm_enabled()) {
- obj = object_new(TYPE_KVM_S390_SKEYS);
- } else {
- obj = object_new(TYPE_QEMU_S390_SKEYS);
- }
- object_property_add_child(qdev_get_machine(), TYPE_S390_SKEYS,
- obj, NULL);
- object_unref(obj);
-
- qdev_init_nofail(DEVICE(obj));
-}
-
-static void write_keys(QEMUFile *f, uint8_t *keys, uint64_t startgfn,
- uint64_t count, Error **errp)
-{
- uint64_t curpage = startgfn;
- uint64_t maxpage = curpage + count - 1;
- const char *fmt = "page=%03" PRIx64 ": key(%d) => ACC=%X, FP=%d, REF=%d,"
- " ch=%d, reserved=%d\n";
- char buf[128];
- int len;
-
- for (; curpage <= maxpage; curpage++) {
- uint8_t acc = (*keys & 0xF0) >> 4;
- int fp = (*keys & 0x08);
- int ref = (*keys & 0x04);
- int ch = (*keys & 0x02);
- int res = (*keys & 0x01);
-
- len = snprintf(buf, sizeof(buf), fmt, curpage,
- *keys, acc, fp, ref, ch, res);
- assert(len < sizeof(buf));
- qemu_put_buffer(f, (uint8_t *)buf, len);
- keys++;
- }
-}
-
-void hmp_info_skeys(Monitor *mon, const QDict *qdict)
-{
- S390SKeysState *ss = s390_get_skeys_device();
- S390SKeysClass *skeyclass = S390_SKEYS_GET_CLASS(ss);
- uint64_t addr = qdict_get_int(qdict, "addr");
- uint8_t key;
- int r;
-
- /* Quick check to see if guest is using storage keys*/
- if (!skeyclass->skeys_enabled(ss)) {
- monitor_printf(mon, "Error: This guest is not using storage keys\n");
- return;
- }
-
- r = skeyclass->get_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key);
- if (r < 0) {
- monitor_printf(mon, "Error: %s\n", strerror(-r));
- return;
- }
-
- monitor_printf(mon, " key: 0x%X\n", key);
-}
-
-void hmp_dump_skeys(Monitor *mon, const QDict *qdict)
-{
- const char *filename = qdict_get_str(qdict, "filename");
- Error *err = NULL;
-
- qmp_dump_skeys(filename, &err);
- if (err) {
- error_report_err(err);
- }
-}
-
-void qmp_dump_skeys(const char *filename, Error **errp)
-{
- S390SKeysState *ss = s390_get_skeys_device();
- S390SKeysClass *skeyclass = S390_SKEYS_GET_CLASS(ss);
- const uint64_t total_count = ram_size / TARGET_PAGE_SIZE;
- uint64_t handled_count = 0, cur_count;
- Error *lerr = NULL;
- vaddr cur_gfn = 0;
- uint8_t *buf;
- int ret;
- QEMUFile *f;
-
- /* Quick check to see if guest is using storage keys*/
- if (!skeyclass->skeys_enabled(ss)) {
- error_setg(errp, "This guest is not using storage keys - "
- "nothing to dump");
- return;
- }
-
- f = qemu_fopen(filename, "wb");
- if (!f) {
- error_setg_file_open(errp, errno, filename);
- return;
- }
-
- buf = g_try_malloc(S390_SKEYS_BUFFER_SIZE);
- if (!buf) {
- error_setg(errp, "Could not allocate memory");
- goto out;
- }
-
- /* we'll only dump initial memory for now */
- while (handled_count < total_count) {
- /* Calculate how many keys to ask for & handle overflow case */
- cur_count = MIN(total_count - handled_count, S390_SKEYS_BUFFER_SIZE);
-
- ret = skeyclass->get_skeys(ss, cur_gfn, cur_count, buf);
- if (ret < 0) {
- error_setg(errp, "get_keys error %d", ret);
- goto out_free;
- }
-
- /* write keys to stream */
- write_keys(f, buf, cur_gfn, cur_count, &lerr);
- if (lerr) {
- goto out_free;
- }
-
- cur_gfn += cur_count;
- handled_count += cur_count;
- }
-
-out_free:
- error_propagate(errp, lerr);
- g_free(buf);
-out:
- qemu_fclose(f);
-}
-
-static void qemu_s390_skeys_init(Object *obj)
-{
- QEMUS390SKeysState *skeys = QEMU_S390_SKEYS(obj);
- MachineState *machine = MACHINE(qdev_get_machine());
-
- skeys->key_count = machine->maxram_size / TARGET_PAGE_SIZE;
- skeys->keydata = g_malloc0(skeys->key_count);
-}
-
-static int qemu_s390_skeys_enabled(S390SKeysState *ss)
-{
- return 1;
-}
-
-/*
- * TODO: for memory hotplug support qemu_s390_skeys_set and qemu_s390_skeys_get
- * will have to make sure that the given gfn belongs to a memory region and not
- * a memory hole.
- */
-static int qemu_s390_skeys_set(S390SKeysState *ss, uint64_t start_gfn,
- uint64_t count, uint8_t *keys)
-{
- QEMUS390SKeysState *skeydev = QEMU_S390_SKEYS(ss);
- int i;
-
- /* Check for uint64 overflow and access beyond end of key data */
- if (start_gfn + count > skeydev->key_count || start_gfn + count < count) {
- error_report("Error: Setting storage keys for page beyond the end "
- "of memory: gfn=%" PRIx64 " count=%" PRId64,
- start_gfn, count);
- return -EINVAL;
- }
-
- for (i = 0; i < count; i++) {
- skeydev->keydata[start_gfn + i] = keys[i];
- }
- return 0;
-}
-
-static int qemu_s390_skeys_get(S390SKeysState *ss, uint64_t start_gfn,
- uint64_t count, uint8_t *keys)
-{
- QEMUS390SKeysState *skeydev = QEMU_S390_SKEYS(ss);
- int i;
-
- /* Check for uint64 overflow and access beyond end of key data */
- if (start_gfn + count > skeydev->key_count || start_gfn + count < count) {
- error_report("Error: Getting storage keys for page beyond the end "
- "of memory: gfn=%" PRIx64 " count=%" PRId64,
- start_gfn, count);
- return -EINVAL;
- }
-
- for (i = 0; i < count; i++) {
- keys[i] = skeydev->keydata[start_gfn + i];
- }
- return 0;
-}
-
-static void qemu_s390_skeys_class_init(ObjectClass *oc, void *data)
-{
- S390SKeysClass *skeyclass = S390_SKEYS_CLASS(oc);
-
- skeyclass->skeys_enabled = qemu_s390_skeys_enabled;
- skeyclass->get_skeys = qemu_s390_skeys_get;
- skeyclass->set_skeys = qemu_s390_skeys_set;
-}
-
-static const TypeInfo qemu_s390_skeys_info = {
- .name = TYPE_QEMU_S390_SKEYS,
- .parent = TYPE_S390_SKEYS,
- .instance_init = qemu_s390_skeys_init,
- .instance_size = sizeof(QEMUS390SKeysState),
- .class_init = qemu_s390_skeys_class_init,
- .class_size = sizeof(S390SKeysClass),
-};
-
-static void s390_storage_keys_save(QEMUFile *f, void *opaque)
-{
- S390SKeysState *ss = S390_SKEYS(opaque);
- S390SKeysClass *skeyclass = S390_SKEYS_GET_CLASS(ss);
- uint64_t pages_left = ram_size / TARGET_PAGE_SIZE;
- uint64_t read_count, eos = S390_SKEYS_SAVE_FLAG_EOS;
- vaddr cur_gfn = 0;
- int error = 0;
- uint8_t *buf;
-
- if (!skeyclass->skeys_enabled(ss)) {
- goto end_stream;
- }
-
- buf = g_try_malloc(S390_SKEYS_BUFFER_SIZE);
- if (!buf) {
- error_report("storage key save could not allocate memory");
- goto end_stream;
- }
-
- /* We only support initial memory. Standby memory is not handled yet. */
- qemu_put_be64(f, (cur_gfn * TARGET_PAGE_SIZE) | S390_SKEYS_SAVE_FLAG_SKEYS);
- qemu_put_be64(f, pages_left);
-
- while (pages_left) {
- read_count = MIN(pages_left, S390_SKEYS_BUFFER_SIZE);
-
- if (!error) {
- error = skeyclass->get_skeys(ss, cur_gfn, read_count, buf);
- if (error) {
- /*
- * If error: we want to fill the stream with valid data instead
- * of stopping early so we pad the stream with 0x00 values and
- * use S390_SKEYS_SAVE_FLAG_ERROR to indicate failure to the
- * reading side.
- */
- error_report("S390_GET_KEYS error %d", error);
- memset(buf, 0, S390_SKEYS_BUFFER_SIZE);
- eos = S390_SKEYS_SAVE_FLAG_ERROR;
- }
- }
-
- qemu_put_buffer(f, buf, read_count);
- cur_gfn += read_count;
- pages_left -= read_count;
- }
-
- g_free(buf);
-end_stream:
- qemu_put_be64(f, eos);
-}
-
-static int s390_storage_keys_load(QEMUFile *f, void *opaque, int version_id)
-{
- S390SKeysState *ss = S390_SKEYS(opaque);
- S390SKeysClass *skeyclass = S390_SKEYS_GET_CLASS(ss);
- int ret = 0;
-
- while (!ret) {
- ram_addr_t addr;
- int flags;
-
- addr = qemu_get_be64(f);
- flags = addr & ~TARGET_PAGE_MASK;
- addr &= TARGET_PAGE_MASK;
-
- switch (flags) {
- case S390_SKEYS_SAVE_FLAG_SKEYS: {
- const uint64_t total_count = qemu_get_be64(f);
- uint64_t handled_count = 0, cur_count;
- uint64_t cur_gfn = addr / TARGET_PAGE_SIZE;
- uint8_t *buf = g_try_malloc(S390_SKEYS_BUFFER_SIZE);
-
- if (!buf) {
- error_report("storage key load could not allocate memory");
- ret = -ENOMEM;
- break;
- }
-
- while (handled_count < total_count) {
- cur_count = MIN(total_count - handled_count,
- S390_SKEYS_BUFFER_SIZE);
- qemu_get_buffer(f, buf, cur_count);
-
- ret = skeyclass->set_skeys(ss, cur_gfn, cur_count, buf);
- if (ret < 0) {
- error_report("S390_SET_KEYS error %d", ret);
- break;
- }
- handled_count += cur_count;
- cur_gfn += cur_count;
- }
- g_free(buf);
- break;
- }
- case S390_SKEYS_SAVE_FLAG_ERROR: {
- error_report("Storage key data is incomplete");
- ret = -EINVAL;
- break;
- }
- case S390_SKEYS_SAVE_FLAG_EOS:
- /* normal exit */
- return 0;
- default:
- error_report("Unexpected storage key flag data: %#x", flags);
- ret = -EINVAL;
- }
- }
-
- return ret;
-}
-
-static inline bool s390_skeys_get_migration_enabled(Object *obj, Error **errp)
-{
- S390SKeysState *ss = S390_SKEYS(obj);
-
- return ss->migration_enabled;
-}
-
-static inline void s390_skeys_set_migration_enabled(Object *obj, bool value,
- Error **errp)
-{
- S390SKeysState *ss = S390_SKEYS(obj);
-
- /* Prevent double registration of savevm handler */
- if (ss->migration_enabled == value) {
- return;
- }
-
- ss->migration_enabled = value;
-
- if (ss->migration_enabled) {
- register_savevm(NULL, TYPE_S390_SKEYS, 0, 1, s390_storage_keys_save,
- s390_storage_keys_load, ss);
- } else {
- unregister_savevm(DEVICE(ss), TYPE_S390_SKEYS, ss);
- }
-}
-
-static void s390_skeys_instance_init(Object *obj)
-{
- object_property_add_bool(obj, "migration-enabled",
- s390_skeys_get_migration_enabled,
- s390_skeys_set_migration_enabled, NULL);
- object_property_set_bool(obj, true, "migration-enabled", NULL);
-}
-
-static void s390_skeys_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- dc->hotpluggable = false;
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
-}
-
-static const TypeInfo s390_skeys_info = {
- .name = TYPE_S390_SKEYS,
- .parent = TYPE_DEVICE,
- .instance_init = s390_skeys_instance_init,
- .instance_size = sizeof(S390SKeysState),
- .class_init = s390_skeys_class_init,
- .class_size = sizeof(S390SKeysClass),
- .abstract = true,
-};
-
-static void qemu_s390_skeys_register_types(void)
-{
- type_register_static(&s390_skeys_info);
- type_register_static(&qemu_s390_skeys_info);
-}
-
-type_init(qemu_s390_skeys_register_types)
diff --git a/qemu/hw/s390x/s390-virtio-ccw.c b/qemu/hw/s390x/s390-virtio-ccw.c
deleted file mode 100644
index e3df9c78b..000000000
--- a/qemu/hw/s390x/s390-virtio-ccw.c
+++ /dev/null
@@ -1,381 +0,0 @@
-/*
- * virtio ccw machine
- *
- * Copyright 2012 IBM Corp.
- * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or (at
- * your option) any later version. See the COPYING file in the top-level
- * directory.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/boards.h"
-#include "exec/address-spaces.h"
-#include "s390-virtio.h"
-#include "hw/s390x/sclp.h"
-#include "hw/s390x/s390_flic.h"
-#include "ioinst.h"
-#include "css.h"
-#include "virtio-ccw.h"
-#include "qemu/config-file.h"
-#include "s390-pci-bus.h"
-#include "hw/s390x/storage-keys.h"
-#include "hw/compat.h"
-#include "hw/s390x/s390-virtio-ccw.h"
-
-static const char *const reset_dev_types[] = {
- "virtual-css-bridge",
- "s390-sclp-event-facility",
- "s390-flic",
- "diag288",
-};
-
-void subsystem_reset(void)
-{
- DeviceState *dev;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(reset_dev_types); i++) {
- dev = DEVICE(object_resolve_path_type("", reset_dev_types[i], NULL));
- if (dev) {
- qdev_reset_all(dev);
- }
- }
-}
-
-static int virtio_ccw_hcall_notify(const uint64_t *args)
-{
- uint64_t subch_id = args[0];
- uint64_t queue = args[1];
- SubchDev *sch;
- int cssid, ssid, schid, m;
-
- if (ioinst_disassemble_sch_ident(subch_id, &m, &cssid, &ssid, &schid)) {
- return -EINVAL;
- }
- sch = css_find_subch(m, cssid, ssid, schid);
- if (!sch || !css_subch_visible(sch)) {
- return -EINVAL;
- }
- if (queue >= VIRTIO_CCW_QUEUE_MAX) {
- return -EINVAL;
- }
- virtio_queue_notify(virtio_ccw_get_vdev(sch), queue);
- return 0;
-
-}
-
-static int virtio_ccw_hcall_early_printk(const uint64_t *args)
-{
- uint64_t mem = args[0];
-
- if (mem < ram_size) {
- /* Early printk */
- return 0;
- }
- return -EINVAL;
-}
-
-static void virtio_ccw_register_hcalls(void)
-{
- s390_register_virtio_hypercall(KVM_S390_VIRTIO_CCW_NOTIFY,
- virtio_ccw_hcall_notify);
- /* Tolerate early printk. */
- s390_register_virtio_hypercall(KVM_S390_VIRTIO_NOTIFY,
- virtio_ccw_hcall_early_printk);
-}
-
-void s390_memory_init(ram_addr_t mem_size)
-{
- MemoryRegion *sysmem = get_system_memory();
- MemoryRegion *ram = g_new(MemoryRegion, 1);
-
- /* allocate RAM for core */
- memory_region_allocate_system_memory(ram, NULL, "s390.ram", mem_size);
- memory_region_add_subregion(sysmem, 0, ram);
-
- /* Initialize storage key device */
- s390_skeys_init();
-}
-
-static void ccw_init(MachineState *machine)
-{
- int ret;
- VirtualCssBus *css_bus;
- DeviceState *dev;
-
- s390_sclp_init();
- s390_memory_init(machine->ram_size);
-
- /* get a BUS */
- css_bus = virtual_css_bus_init();
- s390_init_ipl_dev(machine->kernel_filename, machine->kernel_cmdline,
- machine->initrd_filename, "s390-ccw.img", true);
- s390_flic_init();
-
- dev = qdev_create(NULL, TYPE_S390_PCI_HOST_BRIDGE);
- object_property_add_child(qdev_get_machine(), TYPE_S390_PCI_HOST_BRIDGE,
- OBJECT(dev), NULL);
- qdev_init_nofail(dev);
-
- /* register hypercalls */
- virtio_ccw_register_hcalls();
-
- /* init CPUs */
- s390_init_cpus(machine);
-
- if (kvm_enabled()) {
- kvm_s390_enable_css_support(s390_cpu_addr2state(0));
- }
- /*
- * Create virtual css and set it as default so that non mcss-e
- * enabled guests only see virtio devices.
- */
- ret = css_create_css_image(VIRTUAL_CSSID, true);
- assert(ret == 0);
-
- /* Create VirtIO network adapters */
- s390_create_virtio_net(BUS(css_bus), "virtio-net-ccw");
-
- /* Register savevm handler for guest TOD clock */
- register_savevm(NULL, "todclock", 0, 1,
- gtod_save, gtod_load, kvm_state);
-}
-
-static void s390_cpu_plug(HotplugHandler *hotplug_dev,
- DeviceState *dev, Error **errp)
-{
- gchar *name;
- S390CPU *cpu = S390_CPU(dev);
- CPUState *cs = CPU(dev);
-
- name = g_strdup_printf("cpu[%i]", cpu->env.cpu_num);
- object_property_set_link(OBJECT(hotplug_dev), OBJECT(cs), name,
- errp);
- g_free(name);
-}
-
-static void s390_machine_device_plug(HotplugHandler *hotplug_dev,
- DeviceState *dev, Error **errp)
-{
- if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
- s390_cpu_plug(hotplug_dev, dev, errp);
- }
-}
-
-static HotplugHandler *s390_get_hotplug_handler(MachineState *machine,
- DeviceState *dev)
-{
- if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
- return HOTPLUG_HANDLER(machine);
- }
- return NULL;
-}
-
-static void s390_hot_add_cpu(const int64_t id, Error **errp)
-{
- MachineState *machine = MACHINE(qdev_get_machine());
- Error *err = NULL;
-
- s390x_new_cpu(machine->cpu_model, id, &err);
- error_propagate(errp, err);
-}
-
-static void ccw_machine_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
- NMIClass *nc = NMI_CLASS(oc);
- HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
-
- mc->init = ccw_init;
- mc->reset = s390_machine_reset;
- mc->hot_add_cpu = s390_hot_add_cpu;
- mc->block_default_type = IF_VIRTIO;
- mc->no_cdrom = 1;
- mc->no_floppy = 1;
- mc->no_serial = 1;
- mc->no_parallel = 1;
- mc->no_sdcard = 1;
- mc->use_sclp = 1;
- mc->max_cpus = 255;
- mc->get_hotplug_handler = s390_get_hotplug_handler;
- hc->plug = s390_machine_device_plug;
- nc->nmi_monitor_handler = s390_nmi;
-}
-
-static inline bool machine_get_aes_key_wrap(Object *obj, Error **errp)
-{
- S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
-
- return ms->aes_key_wrap;
-}
-
-static inline void machine_set_aes_key_wrap(Object *obj, bool value,
- Error **errp)
-{
- S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
-
- ms->aes_key_wrap = value;
-}
-
-static inline bool machine_get_dea_key_wrap(Object *obj, Error **errp)
-{
- S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
-
- return ms->dea_key_wrap;
-}
-
-static inline void machine_set_dea_key_wrap(Object *obj, bool value,
- Error **errp)
-{
- S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
-
- ms->dea_key_wrap = value;
-}
-
-static inline void s390_machine_initfn(Object *obj)
-{
- object_property_add_bool(obj, "aes-key-wrap",
- machine_get_aes_key_wrap,
- machine_set_aes_key_wrap, NULL);
- object_property_set_description(obj, "aes-key-wrap",
- "enable/disable AES key wrapping using the CPACF wrapping key",
- NULL);
- object_property_set_bool(obj, true, "aes-key-wrap", NULL);
-
- object_property_add_bool(obj, "dea-key-wrap",
- machine_get_dea_key_wrap,
- machine_set_dea_key_wrap, NULL);
- object_property_set_description(obj, "dea-key-wrap",
- "enable/disable DEA key wrapping using the CPACF wrapping key",
- NULL);
- object_property_set_bool(obj, true, "dea-key-wrap", NULL);
-}
-
-static const TypeInfo ccw_machine_info = {
- .name = TYPE_S390_CCW_MACHINE,
- .parent = TYPE_MACHINE,
- .abstract = true,
- .instance_size = sizeof(S390CcwMachineState),
- .instance_init = s390_machine_initfn,
- .class_init = ccw_machine_class_init,
- .interfaces = (InterfaceInfo[]) {
- { TYPE_NMI },
- { TYPE_HOTPLUG_HANDLER},
- { }
- },
-};
-
-#define DEFINE_CCW_MACHINE(suffix, verstr, latest) \
- static void ccw_machine_##suffix##_class_init(ObjectClass *oc, \
- void *data) \
- { \
- MachineClass *mc = MACHINE_CLASS(oc); \
- ccw_machine_##suffix##_class_options(mc); \
- mc->desc = "VirtIO-ccw based S390 machine v" verstr; \
- if (latest) { \
- mc->alias = "s390-ccw-virtio"; \
- mc->is_default = 1; \
- } \
- } \
- static void ccw_machine_##suffix##_instance_init(Object *obj) \
- { \
- MachineState *machine = MACHINE(obj); \
- ccw_machine_##suffix##_instance_options(machine); \
- } \
- static const TypeInfo ccw_machine_##suffix##_info = { \
- .name = MACHINE_TYPE_NAME("s390-ccw-virtio-" verstr), \
- .parent = TYPE_S390_CCW_MACHINE, \
- .class_init = ccw_machine_##suffix##_class_init, \
- .instance_init = ccw_machine_##suffix##_instance_init, \
- }; \
- static void ccw_machine_register_##suffix(void) \
- { \
- type_register_static(&ccw_machine_##suffix##_info); \
- } \
- type_init(ccw_machine_register_##suffix)
-
-#define CCW_COMPAT_2_5 \
- HW_COMPAT_2_5
-
-#define CCW_COMPAT_2_4 \
- CCW_COMPAT_2_5 \
- HW_COMPAT_2_4 \
- {\
- .driver = TYPE_S390_SKEYS,\
- .property = "migration-enabled",\
- .value = "off",\
- },{\
- .driver = "virtio-blk-ccw",\
- .property = "max_revision",\
- .value = "0",\
- },{\
- .driver = "virtio-balloon-ccw",\
- .property = "max_revision",\
- .value = "0",\
- },{\
- .driver = "virtio-serial-ccw",\
- .property = "max_revision",\
- .value = "0",\
- },{\
- .driver = "virtio-9p-ccw",\
- .property = "max_revision",\
- .value = "0",\
- },{\
- .driver = "virtio-rng-ccw",\
- .property = "max_revision",\
- .value = "0",\
- },{\
- .driver = "virtio-net-ccw",\
- .property = "max_revision",\
- .value = "0",\
- },{\
- .driver = "virtio-scsi-ccw",\
- .property = "max_revision",\
- .value = "0",\
- },{\
- .driver = "vhost-scsi-ccw",\
- .property = "max_revision",\
- .value = "0",\
- },
-
-static void ccw_machine_2_6_instance_options(MachineState *machine)
-{
-}
-
-static void ccw_machine_2_6_class_options(MachineClass *mc)
-{
-}
-DEFINE_CCW_MACHINE(2_6, "2.6", true);
-
-static void ccw_machine_2_5_instance_options(MachineState *machine)
-{
-}
-
-static void ccw_machine_2_5_class_options(MachineClass *mc)
-{
- SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_5);
-}
-DEFINE_CCW_MACHINE(2_5, "2.5", false);
-
-static void ccw_machine_2_4_instance_options(MachineState *machine)
-{
- ccw_machine_2_5_instance_options(machine);
-}
-
-static void ccw_machine_2_4_class_options(MachineClass *mc)
-{
- SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_4);
-}
-DEFINE_CCW_MACHINE(2_4, "2.4", false);
-
-static void ccw_machine_register_types(void)
-{
- type_register_static(&ccw_machine_info);
-}
-
-type_init(ccw_machine_register_types)
diff --git a/qemu/hw/s390x/s390-virtio-hcall.c b/qemu/hw/s390x/s390-virtio-hcall.c
deleted file mode 100644
index 23d67d617..000000000
--- a/qemu/hw/s390x/s390-virtio-hcall.c
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Support for virtio hypercalls on s390
- *
- * Copyright 2012 IBM Corp.
- * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or (at
- * your option) any later version. See the COPYING file in the top-level
- * directory.
- */
-
-#include "qemu/osdep.h"
-#include "cpu.h"
-#include "hw/s390x/s390-virtio.h"
-
-#define MAX_DIAG_SUBCODES 255
-
-static s390_virtio_fn s390_diag500_table[MAX_DIAG_SUBCODES];
-
-void s390_register_virtio_hypercall(uint64_t code, s390_virtio_fn fn)
-{
- assert(code < MAX_DIAG_SUBCODES);
- assert(!s390_diag500_table[code]);
-
- s390_diag500_table[code] = fn;
-}
-
-int s390_virtio_hypercall(CPUS390XState *env)
-{
- s390_virtio_fn fn;
-
- if (env->regs[1] < MAX_DIAG_SUBCODES) {
- fn = s390_diag500_table[env->regs[1]];
- if (fn) {
- env->regs[2] = fn(&env->regs[2]);
- return 0;
- }
- }
-
- return -EINVAL;
-}
diff --git a/qemu/hw/s390x/s390-virtio.c b/qemu/hw/s390x/s390-virtio.c
deleted file mode 100644
index 544c61643..000000000
--- a/qemu/hw/s390x/s390-virtio.c
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * QEMU S390 virtio target
- *
- * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
- * Copyright IBM Corp 2012
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * Contributions after 2012-10-29 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- *
- * You should have received a copy of the GNU (Lesser) General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/hw.h"
-#include "qapi/qmp/qerror.h"
-#include "qemu/error-report.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
-#include "sysemu/sysemu.h"
-#include "net/net.h"
-#include "hw/boards.h"
-#include "hw/loader.h"
-#include "hw/virtio/virtio.h"
-#include "sysemu/kvm.h"
-#include "exec/address-spaces.h"
-#include "sysemu/qtest.h"
-
-#include "hw/s390x/sclp.h"
-#include "hw/s390x/s390_flic.h"
-#include "hw/s390x/s390-virtio.h"
-#include "hw/s390x/storage-keys.h"
-#include "hw/s390x/ipl.h"
-#include "cpu.h"
-
-//#define DEBUG_S390
-
-#ifdef DEBUG_S390
-#define DPRINTF(fmt, ...) \
- do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) \
- do { } while (0)
-#endif
-
-#define MAX_BLK_DEVS 10
-
-#define S390_TOD_CLOCK_VALUE_MISSING 0x00
-#define S390_TOD_CLOCK_VALUE_PRESENT 0x01
-
-static S390CPU **cpu_states;
-
-S390CPU *s390_cpu_addr2state(uint16_t cpu_addr)
-{
- if (cpu_addr >= max_cpus) {
- return NULL;
- }
-
- /* Fast lookup via CPU ID */
- return cpu_states[cpu_addr];
-}
-
-void s390_init_ipl_dev(const char *kernel_filename,
- const char *kernel_cmdline,
- const char *initrd_filename,
- const char *firmware,
- bool enforce_bios)
-{
- Object *new = object_new(TYPE_S390_IPL);
- DeviceState *dev = DEVICE(new);
-
- if (kernel_filename) {
- qdev_prop_set_string(dev, "kernel", kernel_filename);
- }
- if (initrd_filename) {
- qdev_prop_set_string(dev, "initrd", initrd_filename);
- }
- qdev_prop_set_string(dev, "cmdline", kernel_cmdline);
- qdev_prop_set_string(dev, "firmware", firmware);
- qdev_prop_set_bit(dev, "enforce_bios", enforce_bios);
- object_property_add_child(qdev_get_machine(), TYPE_S390_IPL,
- new, NULL);
- object_unref(new);
- qdev_init_nofail(dev);
-}
-
-void s390_init_cpus(MachineState *machine)
-{
- int i;
- gchar *name;
-
- if (machine->cpu_model == NULL) {
- machine->cpu_model = "host";
- }
-
- cpu_states = g_new0(S390CPU *, max_cpus);
-
- for (i = 0; i < max_cpus; i++) {
- name = g_strdup_printf("cpu[%i]", i);
- object_property_add_link(OBJECT(machine), name, TYPE_S390_CPU,
- (Object **) &cpu_states[i],
- object_property_allow_set_link,
- OBJ_PROP_LINK_UNREF_ON_RELEASE,
- &error_abort);
- g_free(name);
- }
-
- for (i = 0; i < smp_cpus; i++) {
- s390x_new_cpu(machine->cpu_model, i, &error_fatal);
- }
-}
-
-
-void s390_create_virtio_net(BusState *bus, const char *name)
-{
- int i;
-
- for (i = 0; i < nb_nics; i++) {
- NICInfo *nd = &nd_table[i];
- DeviceState *dev;
-
- if (!nd->model) {
- nd->model = g_strdup("virtio");
- }
-
- qemu_check_nic_model(nd, "virtio");
-
- dev = qdev_create(bus, name);
- qdev_set_nic_properties(dev, nd);
- qdev_init_nofail(dev);
- }
-}
-
-void gtod_save(QEMUFile *f, void *opaque)
-{
- uint64_t tod_low;
- uint8_t tod_high;
- int r;
-
- r = s390_get_clock(&tod_high, &tod_low);
- if (r) {
- fprintf(stderr, "WARNING: Unable to get guest clock for migration. "
- "Error code %d. Guest clock will not be migrated "
- "which could cause the guest to hang.\n", r);
- qemu_put_byte(f, S390_TOD_CLOCK_VALUE_MISSING);
- return;
- }
-
- qemu_put_byte(f, S390_TOD_CLOCK_VALUE_PRESENT);
- qemu_put_byte(f, tod_high);
- qemu_put_be64(f, tod_low);
-}
-
-int gtod_load(QEMUFile *f, void *opaque, int version_id)
-{
- uint64_t tod_low;
- uint8_t tod_high;
- int r;
-
- if (qemu_get_byte(f) == S390_TOD_CLOCK_VALUE_MISSING) {
- fprintf(stderr, "WARNING: Guest clock was not migrated. This could "
- "cause the guest to hang.\n");
- return 0;
- }
-
- tod_high = qemu_get_byte(f);
- tod_low = qemu_get_be64(f);
-
- r = s390_set_clock(&tod_high, &tod_low);
- if (r) {
- fprintf(stderr, "WARNING: Unable to set guest clock value. "
- "s390_get_clock returned error %d. This could cause "
- "the guest to hang.\n", r);
- }
-
- return 0;
-}
-
-void s390_nmi(NMIState *n, int cpu_index, Error **errp)
-{
- CPUState *cs = qemu_get_cpu(cpu_index);
-
- if (s390_cpu_restart(S390_CPU(cs))) {
- error_setg(errp, QERR_UNSUPPORTED);
- }
-}
-
-void s390_machine_reset(void)
-{
- S390CPU *ipl_cpu = S390_CPU(qemu_get_cpu(0));
-
- qemu_devices_reset();
- s390_cmma_reset();
- s390_crypto_reset();
-
- /* all cpus are stopped - configure and start the ipl cpu only */
- s390_ipl_prepare_cpu(ipl_cpu);
- s390_cpu_set_state(CPU_STATE_OPERATING, ipl_cpu);
-}
diff --git a/qemu/hw/s390x/s390-virtio.h b/qemu/hw/s390x/s390-virtio.h
deleted file mode 100644
index ffd014cb5..000000000
--- a/qemu/hw/s390x/s390-virtio.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Virtio interfaces for s390
- *
- * Copyright 2012 IBM Corp.
- * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or (at
- * your option) any later version. See the COPYING file in the top-level
- * directory.
- */
-
-#ifndef HW_S390_VIRTIO_H
-#define HW_S390_VIRTIO_H 1
-
-#include "hw/nmi.h"
-#include "standard-headers/asm-s390/kvm_virtio.h"
-#include "standard-headers/asm-s390/virtio-ccw.h"
-
-typedef int (*s390_virtio_fn)(const uint64_t *args);
-void s390_register_virtio_hypercall(uint64_t code, s390_virtio_fn fn);
-
-void s390_init_cpus(MachineState *machine);
-void s390_init_ipl_dev(const char *kernel_filename,
- const char *kernel_cmdline,
- const char *initrd_filename,
- const char *firmware,
- bool enforce_bios);
-void s390_create_virtio_net(BusState *bus, const char *name);
-void s390_nmi(NMIState *n, int cpu_index, Error **errp);
-void s390_machine_reset(void);
-void s390_memory_init(ram_addr_t mem_size);
-#endif
diff --git a/qemu/hw/s390x/sclp.c b/qemu/hw/s390x/sclp.c
deleted file mode 100644
index 85dbe1b60..000000000
--- a/qemu/hw/s390x/sclp.c
+++ /dev/null
@@ -1,618 +0,0 @@
-/*
- * SCLP Support
- *
- * Copyright IBM, Corp. 2012
- *
- * Authors:
- * Christian Borntraeger <borntraeger@de.ibm.com>
- * Heinz Graalfs <graalfs@linux.vnet.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or (at your
- * option) any later version. See the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "cpu.h"
-#include "sysemu/kvm.h"
-#include "exec/memory.h"
-#include "sysemu/sysemu.h"
-#include "exec/address-spaces.h"
-#include "hw/boards.h"
-#include "hw/s390x/sclp.h"
-#include "hw/s390x/event-facility.h"
-#include "hw/s390x/s390-pci-bus.h"
-
-static inline SCLPDevice *get_sclp_device(void)
-{
- return SCLP(object_resolve_path_type("", TYPE_SCLP, NULL));
-}
-
-/* Provide information about the configuration, CPUs and storage */
-static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb)
-{
- ReadInfo *read_info = (ReadInfo *) sccb;
- MachineState *machine = MACHINE(qdev_get_machine());
- sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev();
- CPUState *cpu;
- int cpu_count = 0;
- int i = 0;
- int rnsize, rnmax;
- int slots = MIN(machine->ram_slots, s390_get_memslot_count(kvm_state));
-
- CPU_FOREACH(cpu) {
- cpu_count++;
- }
-
- /* CPU information */
- read_info->entries_cpu = cpu_to_be16(cpu_count);
- read_info->offset_cpu = cpu_to_be16(offsetof(ReadInfo, entries));
- read_info->highest_cpu = cpu_to_be16(max_cpus);
-
- for (i = 0; i < cpu_count; i++) {
- read_info->entries[i].address = i;
- read_info->entries[i].type = 0;
- }
-
- read_info->facilities = cpu_to_be64(SCLP_HAS_CPU_INFO |
- SCLP_HAS_PCI_RECONFIG);
-
- /* Memory Hotplug is only supported for the ccw machine type */
- if (mhd) {
- mhd->standby_subregion_size = MEM_SECTION_SIZE;
- /* Deduct the memory slot already used for core */
- if (slots > 0) {
- while ((mhd->standby_subregion_size * (slots - 1)
- < mhd->standby_mem_size)) {
- mhd->standby_subregion_size = mhd->standby_subregion_size << 1;
- }
- }
- /*
- * Initialize mapping of guest standby memory sections indicating which
- * are and are not online. Assume all standby memory begins offline.
- */
- if (mhd->standby_state_map == 0) {
- if (mhd->standby_mem_size % mhd->standby_subregion_size) {
- mhd->standby_state_map = g_malloc0((mhd->standby_mem_size /
- mhd->standby_subregion_size + 1) *
- (mhd->standby_subregion_size /
- MEM_SECTION_SIZE));
- } else {
- mhd->standby_state_map = g_malloc0(mhd->standby_mem_size /
- MEM_SECTION_SIZE);
- }
- }
- mhd->padded_ram_size = ram_size + mhd->pad_size;
- mhd->rzm = 1 << mhd->increment_size;
-
- read_info->facilities |= cpu_to_be64(SCLP_FC_ASSIGN_ATTACH_READ_STOR);
- }
-
- rnsize = 1 << (sclp->increment_size - 20);
- if (rnsize <= 128) {
- read_info->rnsize = rnsize;
- } else {
- read_info->rnsize = 0;
- read_info->rnsize2 = cpu_to_be32(rnsize);
- }
-
- rnmax = machine->maxram_size >> sclp->increment_size;
- if (rnmax < 0x10000) {
- read_info->rnmax = cpu_to_be16(rnmax);
- } else {
- read_info->rnmax = cpu_to_be16(0);
- read_info->rnmax2 = cpu_to_be64(rnmax);
- }
-
- sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION);
-}
-
-static void read_storage_element0_info(SCLPDevice *sclp, SCCB *sccb)
-{
- int i, assigned;
- int subincrement_id = SCLP_STARTING_SUBINCREMENT_ID;
- ReadStorageElementInfo *storage_info = (ReadStorageElementInfo *) sccb;
- sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev();
-
- if (!mhd) {
- sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND);
- return;
- }
-
- if ((ram_size >> mhd->increment_size) >= 0x10000) {
- sccb->h.response_code = cpu_to_be16(SCLP_RC_SCCB_BOUNDARY_VIOLATION);
- return;
- }
-
- /* Return information regarding core memory */
- storage_info->max_id = cpu_to_be16(mhd->standby_mem_size ? 1 : 0);
- assigned = ram_size >> mhd->increment_size;
- storage_info->assigned = cpu_to_be16(assigned);
-
- for (i = 0; i < assigned; i++) {
- storage_info->entries[i] = cpu_to_be32(subincrement_id);
- subincrement_id += SCLP_INCREMENT_UNIT;
- }
- sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION);
-}
-
-static void read_storage_element1_info(SCLPDevice *sclp, SCCB *sccb)
-{
- ReadStorageElementInfo *storage_info = (ReadStorageElementInfo *) sccb;
- sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev();
-
- if (!mhd) {
- sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND);
- return;
- }
-
- if ((mhd->standby_mem_size >> mhd->increment_size) >= 0x10000) {
- sccb->h.response_code = cpu_to_be16(SCLP_RC_SCCB_BOUNDARY_VIOLATION);
- return;
- }
-
- /* Return information regarding standby memory */
- storage_info->max_id = cpu_to_be16(mhd->standby_mem_size ? 1 : 0);
- storage_info->assigned = cpu_to_be16(mhd->standby_mem_size >>
- mhd->increment_size);
- storage_info->standby = cpu_to_be16(mhd->standby_mem_size >>
- mhd->increment_size);
- sccb->h.response_code = cpu_to_be16(SCLP_RC_STANDBY_READ_COMPLETION);
-}
-
-static void attach_storage_element(SCLPDevice *sclp, SCCB *sccb,
- uint16_t element)
-{
- int i, assigned, subincrement_id;
- AttachStorageElement *attach_info = (AttachStorageElement *) sccb;
- sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev();
-
- if (!mhd) {
- sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND);
- return;
- }
-
- if (element != 1) {
- sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND);
- return;
- }
-
- assigned = mhd->standby_mem_size >> mhd->increment_size;
- attach_info->assigned = cpu_to_be16(assigned);
- subincrement_id = ((ram_size >> mhd->increment_size) << 16)
- + SCLP_STARTING_SUBINCREMENT_ID;
- for (i = 0; i < assigned; i++) {
- attach_info->entries[i] = cpu_to_be32(subincrement_id);
- subincrement_id += SCLP_INCREMENT_UNIT;
- }
- sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_COMPLETION);
-}
-
-static void assign_storage(SCLPDevice *sclp, SCCB *sccb)
-{
- MemoryRegion *mr = NULL;
- uint64_t this_subregion_size;
- AssignStorage *assign_info = (AssignStorage *) sccb;
- sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev();
- ram_addr_t assign_addr;
- MemoryRegion *sysmem = get_system_memory();
-
- if (!mhd) {
- sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND);
- return;
- }
- assign_addr = (assign_info->rn - 1) * mhd->rzm;
-
- if ((assign_addr % MEM_SECTION_SIZE == 0) &&
- (assign_addr >= mhd->padded_ram_size)) {
- /* Re-use existing memory region if found */
- mr = memory_region_find(sysmem, assign_addr, 1).mr;
- memory_region_unref(mr);
- if (!mr) {
-
- MemoryRegion *standby_ram = g_new(MemoryRegion, 1);
-
- /* offset to align to standby_subregion_size for allocation */
- ram_addr_t offset = assign_addr -
- (assign_addr - mhd->padded_ram_size)
- % mhd->standby_subregion_size;
-
- /* strlen("standby.ram") + 4 (Max of KVM_MEMORY_SLOTS) + NULL */
- char id[16];
- snprintf(id, 16, "standby.ram%d",
- (int)((offset - mhd->padded_ram_size) /
- mhd->standby_subregion_size) + 1);
-
- /* Allocate a subregion of the calculated standby_subregion_size */
- if (offset + mhd->standby_subregion_size >
- mhd->padded_ram_size + mhd->standby_mem_size) {
- this_subregion_size = mhd->padded_ram_size +
- mhd->standby_mem_size - offset;
- } else {
- this_subregion_size = mhd->standby_subregion_size;
- }
-
- memory_region_init_ram(standby_ram, NULL, id, this_subregion_size,
- &error_fatal);
- /* This is a hack to make memory hotunplug work again. Once we have
- * subdevices, we have to unparent them when unassigning memory,
- * instead of doing it via the ref count of the MemoryRegion. */
- object_ref(OBJECT(standby_ram));
- object_unparent(OBJECT(standby_ram));
- vmstate_register_ram_global(standby_ram);
- memory_region_add_subregion(sysmem, offset, standby_ram);
- }
- /* The specified subregion is no longer in standby */
- mhd->standby_state_map[(assign_addr - mhd->padded_ram_size)
- / MEM_SECTION_SIZE] = 1;
- }
- sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_COMPLETION);
-}
-
-static void unassign_storage(SCLPDevice *sclp, SCCB *sccb)
-{
- MemoryRegion *mr = NULL;
- AssignStorage *assign_info = (AssignStorage *) sccb;
- sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev();
- ram_addr_t unassign_addr;
- MemoryRegion *sysmem = get_system_memory();
-
- if (!mhd) {
- sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND);
- return;
- }
- unassign_addr = (assign_info->rn - 1) * mhd->rzm;
-
- /* if the addr is a multiple of 256 MB */
- if ((unassign_addr % MEM_SECTION_SIZE == 0) &&
- (unassign_addr >= mhd->padded_ram_size)) {
- mhd->standby_state_map[(unassign_addr -
- mhd->padded_ram_size) / MEM_SECTION_SIZE] = 0;
-
- /* find the specified memory region and destroy it */
- mr = memory_region_find(sysmem, unassign_addr, 1).mr;
- memory_region_unref(mr);
- if (mr) {
- int i;
- int is_removable = 1;
- ram_addr_t map_offset = (unassign_addr - mhd->padded_ram_size -
- (unassign_addr - mhd->padded_ram_size)
- % mhd->standby_subregion_size);
- /* Mark all affected subregions as 'standby' once again */
- for (i = 0;
- i < (mhd->standby_subregion_size / MEM_SECTION_SIZE);
- i++) {
-
- if (mhd->standby_state_map[i + map_offset / MEM_SECTION_SIZE]) {
- is_removable = 0;
- break;
- }
- }
- if (is_removable) {
- memory_region_del_subregion(sysmem, mr);
- object_unref(OBJECT(mr));
- }
- }
- }
- sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_COMPLETION);
-}
-
-/* Provide information about the CPU */
-static void sclp_read_cpu_info(SCLPDevice *sclp, SCCB *sccb)
-{
- ReadCpuInfo *cpu_info = (ReadCpuInfo *) sccb;
- CPUState *cpu;
- int cpu_count = 0;
- int i = 0;
-
- CPU_FOREACH(cpu) {
- cpu_count++;
- }
-
- cpu_info->nr_configured = cpu_to_be16(cpu_count);
- cpu_info->offset_configured = cpu_to_be16(offsetof(ReadCpuInfo, entries));
- cpu_info->nr_standby = cpu_to_be16(0);
-
- /* The standby offset is 16-byte for each CPU */
- cpu_info->offset_standby = cpu_to_be16(cpu_info->offset_configured
- + cpu_info->nr_configured*sizeof(CPUEntry));
-
- for (i = 0; i < cpu_count; i++) {
- cpu_info->entries[i].address = i;
- cpu_info->entries[i].type = 0;
- }
-
- sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION);
-}
-
-static void sclp_execute(SCLPDevice *sclp, SCCB *sccb, uint32_t code)
-{
- SCLPDeviceClass *sclp_c = SCLP_GET_CLASS(sclp);
- SCLPEventFacility *ef = sclp->event_facility;
- SCLPEventFacilityClass *efc = EVENT_FACILITY_GET_CLASS(ef);
-
- switch (code & SCLP_CMD_CODE_MASK) {
- case SCLP_CMDW_READ_SCP_INFO:
- case SCLP_CMDW_READ_SCP_INFO_FORCED:
- sclp_c->read_SCP_info(sclp, sccb);
- break;
- case SCLP_CMDW_READ_CPU_INFO:
- sclp_c->read_cpu_info(sclp, sccb);
- break;
- case SCLP_READ_STORAGE_ELEMENT_INFO:
- if (code & 0xff00) {
- sclp_c->read_storage_element1_info(sclp, sccb);
- } else {
- sclp_c->read_storage_element0_info(sclp, sccb);
- }
- break;
- case SCLP_ATTACH_STORAGE_ELEMENT:
- sclp_c->attach_storage_element(sclp, sccb, (code & 0xff00) >> 8);
- break;
- case SCLP_ASSIGN_STORAGE:
- sclp_c->assign_storage(sclp, sccb);
- break;
- case SCLP_UNASSIGN_STORAGE:
- sclp_c->unassign_storage(sclp, sccb);
- break;
- case SCLP_CMDW_CONFIGURE_PCI:
- s390_pci_sclp_configure(1, sccb);
- break;
- case SCLP_CMDW_DECONFIGURE_PCI:
- s390_pci_sclp_configure(0, sccb);
- break;
- default:
- efc->command_handler(ef, sccb, code);
- break;
- }
-}
-
-int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code)
-{
- SCLPDevice *sclp = get_sclp_device();
- SCLPDeviceClass *sclp_c = SCLP_GET_CLASS(sclp);
- int r = 0;
- SCCB work_sccb;
-
- hwaddr sccb_len = sizeof(SCCB);
-
- /* first some basic checks on program checks */
- if (env->psw.mask & PSW_MASK_PSTATE) {
- r = -PGM_PRIVILEGED;
- goto out;
- }
- if (cpu_physical_memory_is_io(sccb)) {
- r = -PGM_ADDRESSING;
- goto out;
- }
- if ((sccb & ~0x1fffUL) == 0 || (sccb & ~0x1fffUL) == env->psa
- || (sccb & ~0x7ffffff8UL) != 0) {
- r = -PGM_SPECIFICATION;
- goto out;
- }
-
- /*
- * we want to work on a private copy of the sccb, to prevent guests
- * from playing dirty tricks by modifying the memory content after
- * the host has checked the values
- */
- cpu_physical_memory_read(sccb, &work_sccb, sccb_len);
-
- /* Valid sccb sizes */
- if (be16_to_cpu(work_sccb.h.length) < sizeof(SCCBHeader) ||
- be16_to_cpu(work_sccb.h.length) > SCCB_SIZE) {
- r = -PGM_SPECIFICATION;
- goto out;
- }
-
- sclp_c->execute(sclp, (SCCB *)&work_sccb, code);
-
- cpu_physical_memory_write(sccb, &work_sccb,
- be16_to_cpu(work_sccb.h.length));
-
- sclp_c->service_interrupt(sclp, sccb);
-
-out:
- return r;
-}
-
-static void service_interrupt(SCLPDevice *sclp, uint32_t sccb)
-{
- SCLPEventFacility *ef = sclp->event_facility;
- SCLPEventFacilityClass *efc = EVENT_FACILITY_GET_CLASS(ef);
-
- uint32_t param = sccb & ~3;
-
- /* Indicate whether an event is still pending */
- param |= efc->event_pending(ef) ? 1 : 0;
-
- if (!param) {
- /* No need to send an interrupt, there's nothing to be notified about */
- return;
- }
- s390_sclp_extint(param);
-}
-
-void sclp_service_interrupt(uint32_t sccb)
-{
- SCLPDevice *sclp = get_sclp_device();
- SCLPDeviceClass *sclp_c = SCLP_GET_CLASS(sclp);
-
- sclp_c->service_interrupt(sclp, sccb);
-}
-
-/* qemu object creation and initialization functions */
-
-void s390_sclp_init(void)
-{
- Object *new = object_new(TYPE_SCLP);
-
- object_property_add_child(qdev_get_machine(), TYPE_SCLP, new,
- NULL);
- object_unref(OBJECT(new));
- qdev_init_nofail(DEVICE(new));
-}
-
-static void sclp_realize(DeviceState *dev, Error **errp)
-{
- MachineState *machine = MACHINE(qdev_get_machine());
- SCLPDevice *sclp = SCLP(dev);
- Error *err = NULL;
- uint64_t hw_limit;
- int ret;
-
- object_property_set_bool(OBJECT(sclp->event_facility), true, "realized",
- &err);
- if (err) {
- goto out;
- }
- /*
- * qdev_device_add searches the sysbus for TYPE_SCLP_EVENTS_BUS. As long
- * as we can't find a fitting bus via the qom tree, we have to add the
- * event facility to the sysbus, so e.g. a sclp console can be created.
- */
- qdev_set_parent_bus(DEVICE(sclp->event_facility), sysbus_get_default());
-
- ret = s390_set_memory_limit(machine->maxram_size, &hw_limit);
- if (ret == -E2BIG) {
- error_setg(&err, "qemu: host supports a maximum of %" PRIu64 " GB",
- hw_limit >> 30);
- } else if (ret) {
- error_setg(&err, "qemu: setting the guest size failed");
- }
-
-out:
- error_propagate(errp, err);
-}
-
-static void sclp_memory_init(SCLPDevice *sclp)
-{
- MachineState *machine = MACHINE(qdev_get_machine());
- ram_addr_t initial_mem = machine->ram_size;
- ram_addr_t max_mem = machine->maxram_size;
- ram_addr_t standby_mem = max_mem - initial_mem;
- ram_addr_t pad_mem = 0;
- int increment_size = 20;
-
- /* The storage increment size is a multiple of 1M and is a power of 2.
- * The number of storage increments must be MAX_STORAGE_INCREMENTS or fewer.
- * The variable 'increment_size' is an exponent of 2 that can be
- * used to calculate the size (in bytes) of an increment. */
- while ((initial_mem >> increment_size) > MAX_STORAGE_INCREMENTS) {
- increment_size++;
- }
- if (machine->ram_slots) {
- while ((standby_mem >> increment_size) > MAX_STORAGE_INCREMENTS) {
- increment_size++;
- }
- }
- sclp->increment_size = increment_size;
-
- /* The core and standby memory areas need to be aligned with
- * the increment size. In effect, this can cause the
- * user-specified memory size to be rounded down to align
- * with the nearest increment boundary. */
- initial_mem = initial_mem >> increment_size << increment_size;
- standby_mem = standby_mem >> increment_size << increment_size;
-
- /* If the size of ram is not on a MEM_SECTION_SIZE boundary,
- calculate the pad size necessary to force this boundary. */
- if (machine->ram_slots && standby_mem) {
- sclpMemoryHotplugDev *mhd = init_sclp_memory_hotplug_dev();
-
- if (initial_mem % MEM_SECTION_SIZE) {
- pad_mem = MEM_SECTION_SIZE - initial_mem % MEM_SECTION_SIZE;
- }
- mhd->increment_size = increment_size;
- mhd->pad_size = pad_mem;
- mhd->standby_mem_size = standby_mem;
- }
- machine->ram_size = initial_mem;
- machine->maxram_size = initial_mem + pad_mem + standby_mem;
- /* let's propagate the changed ram size into the global variable. */
- ram_size = initial_mem;
-}
-
-static void sclp_init(Object *obj)
-{
- SCLPDevice *sclp = SCLP(obj);
- Object *new;
-
- new = object_new(TYPE_SCLP_EVENT_FACILITY);
- object_property_add_child(obj, TYPE_SCLP_EVENT_FACILITY, new, NULL);
- object_unref(new);
- sclp->event_facility = EVENT_FACILITY(new);
-
- sclp_memory_init(sclp);
-}
-
-static void sclp_class_init(ObjectClass *oc, void *data)
-{
- SCLPDeviceClass *sc = SCLP_CLASS(oc);
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- dc->desc = "SCLP (Service-Call Logical Processor)";
- dc->realize = sclp_realize;
- dc->hotpluggable = false;
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
-
- sc->read_SCP_info = read_SCP_info;
- sc->read_storage_element0_info = read_storage_element0_info;
- sc->read_storage_element1_info = read_storage_element1_info;
- sc->attach_storage_element = attach_storage_element;
- sc->assign_storage = assign_storage;
- sc->unassign_storage = unassign_storage;
- sc->read_cpu_info = sclp_read_cpu_info;
- sc->execute = sclp_execute;
- sc->service_interrupt = service_interrupt;
-}
-
-static TypeInfo sclp_info = {
- .name = TYPE_SCLP,
- .parent = TYPE_DEVICE,
- .instance_init = sclp_init,
- .instance_size = sizeof(SCLPDevice),
- .class_init = sclp_class_init,
- .class_size = sizeof(SCLPDeviceClass),
-};
-
-sclpMemoryHotplugDev *init_sclp_memory_hotplug_dev(void)
-{
- DeviceState *dev;
- dev = qdev_create(NULL, TYPE_SCLP_MEMORY_HOTPLUG_DEV);
- object_property_add_child(qdev_get_machine(),
- TYPE_SCLP_MEMORY_HOTPLUG_DEV,
- OBJECT(dev), NULL);
- qdev_init_nofail(dev);
- return SCLP_MEMORY_HOTPLUG_DEV(object_resolve_path(
- TYPE_SCLP_MEMORY_HOTPLUG_DEV, NULL));
-}
-
-sclpMemoryHotplugDev *get_sclp_memory_hotplug_dev(void)
-{
- return SCLP_MEMORY_HOTPLUG_DEV(object_resolve_path(
- TYPE_SCLP_MEMORY_HOTPLUG_DEV, NULL));
-}
-
-static void sclp_memory_hotplug_dev_class_init(ObjectClass *klass,
- void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
-}
-
-static TypeInfo sclp_memory_hotplug_dev_info = {
- .name = TYPE_SCLP_MEMORY_HOTPLUG_DEV,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(sclpMemoryHotplugDev),
- .class_init = sclp_memory_hotplug_dev_class_init,
-};
-
-static void register_types(void)
-{
- type_register_static(&sclp_memory_hotplug_dev_info);
- type_register_static(&sclp_info);
-}
-type_init(register_types);
diff --git a/qemu/hw/s390x/sclpcpu.c b/qemu/hw/s390x/sclpcpu.c
deleted file mode 100644
index b1f3ef8c7..000000000
--- a/qemu/hw/s390x/sclpcpu.c
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * SCLP event type
- * Signal CPU - Trigger SCLP interrupt for system CPU configure or
- * de-configure
- *
- * Copyright IBM, Corp. 2013
- *
- * Authors:
- * Thang Pham <thang.pham@us.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or (at your
- * option) any later version. See the COPYING file in the top-level directory.
- *
- */
-#include "qemu/osdep.h"
-#include "sysemu/sysemu.h"
-#include "hw/s390x/sclp.h"
-#include "hw/s390x/event-facility.h"
-#include "cpu.h"
-#include "sysemu/cpus.h"
-#include "sysemu/kvm.h"
-
-typedef struct ConfigMgtData {
- EventBufferHeader ebh;
- uint8_t reserved;
- uint8_t event_qualifier;
-} QEMU_PACKED ConfigMgtData;
-
-#define EVENT_QUAL_CPU_CHANGE 1
-
-void raise_irq_cpu_hotplug(void)
-{
- Object *obj = object_resolve_path_type("", TYPE_SCLP_CPU_HOTPLUG, NULL);
-
- SCLP_EVENT(obj)->event_pending = true;
-
- /* Trigger SCLP read operation */
- sclp_service_interrupt(0);
-}
-
-static unsigned int send_mask(void)
-{
- return SCLP_EVENT_MASK_CONFIG_MGT_DATA;
-}
-
-static unsigned int receive_mask(void)
-{
- return 0;
-}
-
-static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
- int *slen)
-{
- ConfigMgtData *cdata = (ConfigMgtData *) evt_buf_hdr;
- if (*slen < sizeof(ConfigMgtData)) {
- return 0;
- }
-
- /* Event is no longer pending */
- if (!event->event_pending) {
- return 0;
- }
- event->event_pending = false;
-
- /* Event header data */
- cdata->ebh.length = cpu_to_be16(sizeof(ConfigMgtData));
- cdata->ebh.type = SCLP_EVENT_CONFIG_MGT_DATA;
- cdata->ebh.flags |= SCLP_EVENT_BUFFER_ACCEPTED;
-
- /* Trigger a rescan of CPUs by setting event qualifier */
- cdata->event_qualifier = EVENT_QUAL_CPU_CHANGE;
- *slen -= sizeof(ConfigMgtData);
-
- return 1;
-}
-
-static void cpu_class_init(ObjectClass *oc, void *data)
-{
- SCLPEventClass *k = SCLP_EVENT_CLASS(oc);
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- k->get_send_mask = send_mask;
- k->get_receive_mask = receive_mask;
- k->read_event_data = read_event_data;
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
-}
-
-static const TypeInfo sclp_cpu_info = {
- .name = TYPE_SCLP_CPU_HOTPLUG,
- .parent = TYPE_SCLP_EVENT,
- .instance_size = sizeof(SCLPEvent),
- .class_init = cpu_class_init,
- .class_size = sizeof(SCLPEventClass),
-};
-
-static void sclp_cpu_register_types(void)
-{
- type_register_static(&sclp_cpu_info);
-}
-
-type_init(sclp_cpu_register_types)
diff --git a/qemu/hw/s390x/sclpquiesce.c b/qemu/hw/s390x/sclpquiesce.c
deleted file mode 100644
index c0ecab9c3..000000000
--- a/qemu/hw/s390x/sclpquiesce.c
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * SCLP event type
- * Signal Quiesce - trigger system powerdown request
- *
- * Copyright IBM, Corp. 2012
- *
- * Authors:
- * Heinz Graalfs <graalfs@de.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or (at your
- * option) any later version. See the COPYING file in the top-level directory.
- *
- */
-#include "qemu/osdep.h"
-#include <hw/qdev.h>
-#include "sysemu/sysemu.h"
-#include "hw/s390x/sclp.h"
-#include "hw/s390x/event-facility.h"
-
-typedef struct SignalQuiesce {
- EventBufferHeader ebh;
- uint16_t timeout;
- uint8_t unit;
-} QEMU_PACKED SignalQuiesce;
-
-static bool can_handle_event(uint8_t type)
-{
- return type == SCLP_EVENT_SIGNAL_QUIESCE;
-}
-
-static unsigned int send_mask(void)
-{
- return SCLP_EVENT_MASK_SIGNAL_QUIESCE;
-}
-
-static unsigned int receive_mask(void)
-{
- return 0;
-}
-
-static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
- int *slen)
-{
- SignalQuiesce *sq = (SignalQuiesce *) evt_buf_hdr;
-
- if (*slen < sizeof(SignalQuiesce)) {
- return 0;
- }
-
- if (!event->event_pending) {
- return 0;
- }
- event->event_pending = false;
-
- sq->ebh.length = cpu_to_be16(sizeof(SignalQuiesce));
- sq->ebh.type = SCLP_EVENT_SIGNAL_QUIESCE;
- sq->ebh.flags |= SCLP_EVENT_BUFFER_ACCEPTED;
- /*
- * system_powerdown does not have a timeout. Fortunately the
- * timeout value is currently ignored by Linux, anyway
- */
- sq->timeout = cpu_to_be16(0);
- sq->unit = cpu_to_be16(0);
- *slen -= sizeof(SignalQuiesce);
-
- return 1;
-}
-
-static const VMStateDescription vmstate_sclpquiesce = {
- .name = TYPE_SCLP_QUIESCE,
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_BOOL(event_pending, SCLPEvent),
- VMSTATE_END_OF_LIST()
- }
-};
-
-typedef struct QuiesceNotifier QuiesceNotifier;
-
-static struct QuiesceNotifier {
- Notifier notifier;
- SCLPEvent *event;
-} qn;
-
-static void quiesce_powerdown_req(Notifier *n, void *opaque)
-{
- QuiesceNotifier *qn = container_of(n, QuiesceNotifier, notifier);
- SCLPEvent *event = qn->event;
-
- event->event_pending = true;
- /* trigger SCLP read operation */
- sclp_service_interrupt(0);
-}
-
-static int quiesce_init(SCLPEvent *event)
-{
- qn.notifier.notify = quiesce_powerdown_req;
- qn.event = event;
-
- qemu_register_powerdown_notifier(&qn.notifier);
-
- return 0;
-}
-
-static void quiesce_reset(DeviceState *dev)
-{
- SCLPEvent *event = SCLP_EVENT(dev);
-
- event->event_pending = false;
-}
-
-static void quiesce_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SCLPEventClass *k = SCLP_EVENT_CLASS(klass);
-
- dc->reset = quiesce_reset;
- dc->vmsd = &vmstate_sclpquiesce;
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- k->init = quiesce_init;
-
- k->get_send_mask = send_mask;
- k->get_receive_mask = receive_mask;
- k->can_handle_event = can_handle_event;
- k->read_event_data = read_event_data;
- k->write_event_data = NULL;
-}
-
-static const TypeInfo sclp_quiesce_info = {
- .name = TYPE_SCLP_QUIESCE,
- .parent = TYPE_SCLP_EVENT,
- .instance_size = sizeof(SCLPEvent),
- .class_init = quiesce_class_init,
- .class_size = sizeof(SCLPEventClass),
-};
-
-static void register_types(void)
-{
- type_register_static(&sclp_quiesce_info);
-}
-
-type_init(register_types)
diff --git a/qemu/hw/s390x/virtio-ccw.c b/qemu/hw/s390x/virtio-ccw.c
deleted file mode 100644
index d51642db0..000000000
--- a/qemu/hw/s390x/virtio-ccw.c
+++ /dev/null
@@ -1,1928 +0,0 @@
-/*
- * virtio ccw target implementation
- *
- * Copyright 2012,2015 IBM Corp.
- * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
- * Pierre Morel <pmorel@linux.vnet.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or (at
- * your option) any later version. See the COPYING file in the top-level
- * directory.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/hw.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
-#include "sysemu/sysemu.h"
-#include "net/net.h"
-#include "hw/virtio/virtio.h"
-#include "hw/virtio/virtio-serial.h"
-#include "hw/virtio/virtio-net.h"
-#include "hw/sysbus.h"
-#include "qemu/bitops.h"
-#include "qemu/error-report.h"
-#include "hw/virtio/virtio-access.h"
-#include "hw/virtio/virtio-bus.h"
-#include "hw/s390x/adapter.h"
-#include "hw/s390x/s390_flic.h"
-
-#include "ioinst.h"
-#include "css.h"
-#include "virtio-ccw.h"
-#include "trace.h"
-
-static void virtio_ccw_bus_new(VirtioBusState *bus, size_t bus_size,
- VirtioCcwDevice *dev);
-
-static void virtual_css_bus_reset(BusState *qbus)
-{
- /* This should actually be modelled via the generic css */
- css_reset();
-}
-
-
-static void virtual_css_bus_class_init(ObjectClass *klass, void *data)
-{
- BusClass *k = BUS_CLASS(klass);
-
- k->reset = virtual_css_bus_reset;
-}
-
-static const TypeInfo virtual_css_bus_info = {
- .name = TYPE_VIRTUAL_CSS_BUS,
- .parent = TYPE_BUS,
- .instance_size = sizeof(VirtualCssBus),
- .class_init = virtual_css_bus_class_init,
-};
-
-VirtIODevice *virtio_ccw_get_vdev(SubchDev *sch)
-{
- VirtIODevice *vdev = NULL;
- VirtioCcwDevice *dev = sch->driver_data;
-
- if (dev) {
- vdev = virtio_bus_get_device(&dev->bus);
- }
- return vdev;
-}
-
-static int virtio_ccw_set_guest2host_notifier(VirtioCcwDevice *dev, int n,
- bool assign, bool set_handler)
-{
- VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
- VirtQueue *vq = virtio_get_queue(vdev, n);
- EventNotifier *notifier = virtio_queue_get_host_notifier(vq);
- int r = 0;
- SubchDev *sch = dev->sch;
- uint32_t sch_id = (css_build_subchannel_id(sch) << 16) | sch->schid;
-
- if (assign) {
- r = event_notifier_init(notifier, 1);
- if (r < 0) {
- error_report("%s: unable to init event notifier: %d", __func__, r);
- return r;
- }
- virtio_queue_set_host_notifier_fd_handler(vq, true, set_handler);
- r = s390_assign_subch_ioeventfd(notifier, sch_id, n, assign);
- if (r < 0) {
- error_report("%s: unable to assign ioeventfd: %d", __func__, r);
- virtio_queue_set_host_notifier_fd_handler(vq, false, false);
- event_notifier_cleanup(notifier);
- return r;
- }
- } else {
- virtio_queue_set_host_notifier_fd_handler(vq, false, false);
- s390_assign_subch_ioeventfd(notifier, sch_id, n, assign);
- event_notifier_cleanup(notifier);
- }
- return r;
-}
-
-static void virtio_ccw_start_ioeventfd(VirtioCcwDevice *dev)
-{
- VirtIODevice *vdev;
- int n, r;
-
- if (!(dev->flags & VIRTIO_CCW_FLAG_USE_IOEVENTFD) ||
- dev->ioeventfd_disabled ||
- dev->ioeventfd_started) {
- return;
- }
- vdev = virtio_bus_get_device(&dev->bus);
- for (n = 0; n < VIRTIO_CCW_QUEUE_MAX; n++) {
- if (!virtio_queue_get_num(vdev, n)) {
- continue;
- }
- r = virtio_ccw_set_guest2host_notifier(dev, n, true, true);
- if (r < 0) {
- goto assign_error;
- }
- }
- dev->ioeventfd_started = true;
- return;
-
- assign_error:
- while (--n >= 0) {
- if (!virtio_queue_get_num(vdev, n)) {
- continue;
- }
- r = virtio_ccw_set_guest2host_notifier(dev, n, false, false);
- assert(r >= 0);
- }
- dev->ioeventfd_started = false;
- /* Disable ioeventfd for this device. */
- dev->flags &= ~VIRTIO_CCW_FLAG_USE_IOEVENTFD;
- error_report("%s: failed. Fallback to userspace (slower).", __func__);
-}
-
-static void virtio_ccw_stop_ioeventfd(VirtioCcwDevice *dev)
-{
- VirtIODevice *vdev;
- int n, r;
-
- if (!dev->ioeventfd_started) {
- return;
- }
- vdev = virtio_bus_get_device(&dev->bus);
- for (n = 0; n < VIRTIO_CCW_QUEUE_MAX; n++) {
- if (!virtio_queue_get_num(vdev, n)) {
- continue;
- }
- r = virtio_ccw_set_guest2host_notifier(dev, n, false, false);
- assert(r >= 0);
- }
- dev->ioeventfd_started = false;
-}
-
-VirtualCssBus *virtual_css_bus_init(void)
-{
- VirtualCssBus *cbus;
- BusState *bus;
- DeviceState *dev;
-
- /* Create bridge device */
- dev = qdev_create(NULL, "virtual-css-bridge");
- qdev_init_nofail(dev);
-
- /* Create bus on bridge device */
- bus = qbus_create(TYPE_VIRTUAL_CSS_BUS, dev, "virtual-css");
- cbus = VIRTUAL_CSS_BUS(bus);
-
- /* Enable hotplugging */
- qbus_set_hotplug_handler(bus, dev, &error_abort);
-
- return cbus;
-}
-
-/* Communication blocks used by several channel commands. */
-typedef struct VqInfoBlockLegacy {
- uint64_t queue;
- uint32_t align;
- uint16_t index;
- uint16_t num;
-} QEMU_PACKED VqInfoBlockLegacy;
-
-typedef struct VqInfoBlock {
- uint64_t desc;
- uint32_t res0;
- uint16_t index;
- uint16_t num;
- uint64_t avail;
- uint64_t used;
-} QEMU_PACKED VqInfoBlock;
-
-typedef struct VqConfigBlock {
- uint16_t index;
- uint16_t num_max;
-} QEMU_PACKED VqConfigBlock;
-
-typedef struct VirtioFeatDesc {
- uint32_t features;
- uint8_t index;
-} QEMU_PACKED VirtioFeatDesc;
-
-typedef struct VirtioThinintInfo {
- hwaddr summary_indicator;
- hwaddr device_indicator;
- uint64_t ind_bit;
- uint8_t isc;
-} QEMU_PACKED VirtioThinintInfo;
-
-typedef struct VirtioRevInfo {
- uint16_t revision;
- uint16_t length;
- uint8_t data[0];
-} QEMU_PACKED VirtioRevInfo;
-
-/* Specify where the virtqueues for the subchannel are in guest memory. */
-static int virtio_ccw_set_vqs(SubchDev *sch, VqInfoBlock *info,
- VqInfoBlockLegacy *linfo)
-{
- VirtIODevice *vdev = virtio_ccw_get_vdev(sch);
- uint16_t index = info ? info->index : linfo->index;
- uint16_t num = info ? info->num : linfo->num;
- uint64_t desc = info ? info->desc : linfo->queue;
-
- if (index >= VIRTIO_CCW_QUEUE_MAX) {
- return -EINVAL;
- }
-
- /* Current code in virtio.c relies on 4K alignment. */
- if (linfo && desc && (linfo->align != 4096)) {
- return -EINVAL;
- }
-
- if (!vdev) {
- return -EINVAL;
- }
-
- if (info) {
- virtio_queue_set_rings(vdev, index, desc, info->avail, info->used);
- } else {
- virtio_queue_set_addr(vdev, index, desc);
- }
- if (!desc) {
- virtio_queue_set_vector(vdev, index, VIRTIO_NO_VECTOR);
- } else {
- if (info) {
- /* virtio-1 allows changing the ring size. */
- if (virtio_queue_get_num(vdev, index) < num) {
- /* Fail if we exceed the maximum number. */
- return -EINVAL;
- }
- virtio_queue_set_num(vdev, index, num);
- } else if (virtio_queue_get_num(vdev, index) > num) {
- /* Fail if we don't have a big enough queue. */
- return -EINVAL;
- }
- /* We ignore possible increased num for legacy for compatibility. */
- virtio_queue_set_vector(vdev, index, index);
- }
- /* tell notify handler in case of config change */
- vdev->config_vector = VIRTIO_CCW_QUEUE_MAX;
- return 0;
-}
-
-static void virtio_ccw_reset_virtio(VirtioCcwDevice *dev, VirtIODevice *vdev)
-{
- virtio_ccw_stop_ioeventfd(dev);
- virtio_reset(vdev);
- if (dev->indicators) {
- release_indicator(&dev->routes.adapter, dev->indicators);
- dev->indicators = NULL;
- }
- if (dev->indicators2) {
- release_indicator(&dev->routes.adapter, dev->indicators2);
- dev->indicators2 = NULL;
- }
- if (dev->summary_indicator) {
- release_indicator(&dev->routes.adapter, dev->summary_indicator);
- dev->summary_indicator = NULL;
- }
- dev->sch->thinint_active = false;
-}
-
-static int virtio_ccw_handle_set_vq(SubchDev *sch, CCW1 ccw, bool check_len,
- bool is_legacy)
-{
- int ret;
- VqInfoBlock info;
- VqInfoBlockLegacy linfo;
- size_t info_len = is_legacy ? sizeof(linfo) : sizeof(info);
-
- if (check_len) {
- if (ccw.count != info_len) {
- return -EINVAL;
- }
- } else if (ccw.count < info_len) {
- /* Can't execute command. */
- return -EINVAL;
- }
- if (!ccw.cda) {
- return -EFAULT;
- }
- if (is_legacy) {
- linfo.queue = address_space_ldq_be(&address_space_memory, ccw.cda,
- MEMTXATTRS_UNSPECIFIED, NULL);
- linfo.align = address_space_ldl_be(&address_space_memory,
- ccw.cda + sizeof(linfo.queue),
- MEMTXATTRS_UNSPECIFIED,
- NULL);
- linfo.index = address_space_lduw_be(&address_space_memory,
- ccw.cda + sizeof(linfo.queue)
- + sizeof(linfo.align),
- MEMTXATTRS_UNSPECIFIED,
- NULL);
- linfo.num = address_space_lduw_be(&address_space_memory,
- ccw.cda + sizeof(linfo.queue)
- + sizeof(linfo.align)
- + sizeof(linfo.index),
- MEMTXATTRS_UNSPECIFIED,
- NULL);
- ret = virtio_ccw_set_vqs(sch, NULL, &linfo);
- } else {
- info.desc = address_space_ldq_be(&address_space_memory, ccw.cda,
- MEMTXATTRS_UNSPECIFIED, NULL);
- info.index = address_space_lduw_be(&address_space_memory,
- ccw.cda + sizeof(info.desc)
- + sizeof(info.res0),
- MEMTXATTRS_UNSPECIFIED, NULL);
- info.num = address_space_lduw_be(&address_space_memory,
- ccw.cda + sizeof(info.desc)
- + sizeof(info.res0)
- + sizeof(info.index),
- MEMTXATTRS_UNSPECIFIED, NULL);
- info.avail = address_space_ldq_be(&address_space_memory,
- ccw.cda + sizeof(info.desc)
- + sizeof(info.res0)
- + sizeof(info.index)
- + sizeof(info.num),
- MEMTXATTRS_UNSPECIFIED, NULL);
- info.used = address_space_ldq_be(&address_space_memory,
- ccw.cda + sizeof(info.desc)
- + sizeof(info.res0)
- + sizeof(info.index)
- + sizeof(info.num)
- + sizeof(info.avail),
- MEMTXATTRS_UNSPECIFIED, NULL);
- ret = virtio_ccw_set_vqs(sch, &info, NULL);
- }
- sch->curr_status.scsw.count = 0;
- return ret;
-}
-
-static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
-{
- int ret;
- VirtioRevInfo revinfo;
- uint8_t status;
- VirtioFeatDesc features;
- void *config;
- hwaddr indicators;
- VqConfigBlock vq_config;
- VirtioCcwDevice *dev = sch->driver_data;
- VirtIODevice *vdev = virtio_ccw_get_vdev(sch);
- bool check_len;
- int len;
- hwaddr hw_len;
- VirtioThinintInfo *thinint;
-
- if (!dev) {
- return -EINVAL;
- }
-
- trace_virtio_ccw_interpret_ccw(sch->cssid, sch->ssid, sch->schid,
- ccw.cmd_code);
- check_len = !((ccw.flags & CCW_FLAG_SLI) && !(ccw.flags & CCW_FLAG_DC));
-
- /* Look at the command. */
- switch (ccw.cmd_code) {
- case CCW_CMD_SET_VQ:
- ret = virtio_ccw_handle_set_vq(sch, ccw, check_len, dev->revision < 1);
- break;
- case CCW_CMD_VDEV_RESET:
- virtio_ccw_reset_virtio(dev, vdev);
- ret = 0;
- break;
- case CCW_CMD_READ_FEAT:
- if (check_len) {
- if (ccw.count != sizeof(features)) {
- ret = -EINVAL;
- break;
- }
- } else if (ccw.count < sizeof(features)) {
- /* Can't execute command. */
- ret = -EINVAL;
- break;
- }
- if (!ccw.cda) {
- ret = -EFAULT;
- } else {
- features.index = address_space_ldub(&address_space_memory,
- ccw.cda
- + sizeof(features.features),
- MEMTXATTRS_UNSPECIFIED,
- NULL);
- if (features.index == 0) {
- if (dev->revision >= 1) {
- /* Don't offer legacy features for modern devices. */
- features.features = (uint32_t)
- (vdev->host_features & ~VIRTIO_LEGACY_FEATURES);
- } else {
- features.features = (uint32_t)vdev->host_features;
- }
- } else if ((features.index == 1) && (dev->revision >= 1)) {
- /*
- * Only offer feature bits beyond 31 if the guest has
- * negotiated at least revision 1.
- */
- features.features = (uint32_t)(vdev->host_features >> 32);
- } else {
- /* Return zeroes if the guest supports more feature bits. */
- features.features = 0;
- }
- address_space_stl_le(&address_space_memory, ccw.cda,
- features.features, MEMTXATTRS_UNSPECIFIED,
- NULL);
- sch->curr_status.scsw.count = ccw.count - sizeof(features);
- ret = 0;
- }
- break;
- case CCW_CMD_WRITE_FEAT:
- if (check_len) {
- if (ccw.count != sizeof(features)) {
- ret = -EINVAL;
- break;
- }
- } else if (ccw.count < sizeof(features)) {
- /* Can't execute command. */
- ret = -EINVAL;
- break;
- }
- if (!ccw.cda) {
- ret = -EFAULT;
- } else {
- features.index = address_space_ldub(&address_space_memory,
- ccw.cda
- + sizeof(features.features),
- MEMTXATTRS_UNSPECIFIED,
- NULL);
- features.features = address_space_ldl_le(&address_space_memory,
- ccw.cda,
- MEMTXATTRS_UNSPECIFIED,
- NULL);
- if (features.index == 0) {
- virtio_set_features(vdev,
- (vdev->guest_features & 0xffffffff00000000ULL) |
- features.features);
- } else if ((features.index == 1) && (dev->revision >= 1)) {
- /*
- * If the guest did not negotiate at least revision 1,
- * we did not offer it any feature bits beyond 31. Such a
- * guest passing us any bit here is therefore buggy.
- */
- virtio_set_features(vdev,
- (vdev->guest_features & 0x00000000ffffffffULL) |
- ((uint64_t)features.features << 32));
- } else {
- /*
- * If the guest supports more feature bits, assert that it
- * passes us zeroes for those we don't support.
- */
- if (features.features) {
- fprintf(stderr, "Guest bug: features[%i]=%x (expected 0)\n",
- features.index, features.features);
- /* XXX: do a unit check here? */
- }
- }
- sch->curr_status.scsw.count = ccw.count - sizeof(features);
- ret = 0;
- }
- break;
- case CCW_CMD_READ_CONF:
- if (check_len) {
- if (ccw.count > vdev->config_len) {
- ret = -EINVAL;
- break;
- }
- }
- len = MIN(ccw.count, vdev->config_len);
- if (!ccw.cda) {
- ret = -EFAULT;
- } else {
- virtio_bus_get_vdev_config(&dev->bus, vdev->config);
- /* XXX config space endianness */
- cpu_physical_memory_write(ccw.cda, vdev->config, len);
- sch->curr_status.scsw.count = ccw.count - len;
- ret = 0;
- }
- break;
- case CCW_CMD_WRITE_CONF:
- if (check_len) {
- if (ccw.count > vdev->config_len) {
- ret = -EINVAL;
- break;
- }
- }
- len = MIN(ccw.count, vdev->config_len);
- hw_len = len;
- if (!ccw.cda) {
- ret = -EFAULT;
- } else {
- config = cpu_physical_memory_map(ccw.cda, &hw_len, 0);
- if (!config) {
- ret = -EFAULT;
- } else {
- len = hw_len;
- /* XXX config space endianness */
- memcpy(vdev->config, config, len);
- cpu_physical_memory_unmap(config, hw_len, 0, hw_len);
- virtio_bus_set_vdev_config(&dev->bus, vdev->config);
- sch->curr_status.scsw.count = ccw.count - len;
- ret = 0;
- }
- }
- break;
- case CCW_CMD_WRITE_STATUS:
- if (check_len) {
- if (ccw.count != sizeof(status)) {
- ret = -EINVAL;
- break;
- }
- } else if (ccw.count < sizeof(status)) {
- /* Can't execute command. */
- ret = -EINVAL;
- break;
- }
- if (!ccw.cda) {
- ret = -EFAULT;
- } else {
- status = address_space_ldub(&address_space_memory, ccw.cda,
- MEMTXATTRS_UNSPECIFIED, NULL);
- if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) {
- virtio_ccw_stop_ioeventfd(dev);
- }
- if (virtio_set_status(vdev, status) == 0) {
- if (vdev->status == 0) {
- virtio_ccw_reset_virtio(dev, vdev);
- }
- if (status & VIRTIO_CONFIG_S_DRIVER_OK) {
- virtio_ccw_start_ioeventfd(dev);
- }
- sch->curr_status.scsw.count = ccw.count - sizeof(status);
- ret = 0;
- } else {
- /* Trigger a command reject. */
- ret = -ENOSYS;
- }
- }
- break;
- case CCW_CMD_SET_IND:
- if (check_len) {
- if (ccw.count != sizeof(indicators)) {
- ret = -EINVAL;
- break;
- }
- } else if (ccw.count < sizeof(indicators)) {
- /* Can't execute command. */
- ret = -EINVAL;
- break;
- }
- if (sch->thinint_active) {
- /* Trigger a command reject. */
- ret = -ENOSYS;
- break;
- }
- if (!ccw.cda) {
- ret = -EFAULT;
- } else {
- indicators = address_space_ldq_be(&address_space_memory, ccw.cda,
- MEMTXATTRS_UNSPECIFIED, NULL);
- dev->indicators = get_indicator(indicators, sizeof(uint64_t));
- sch->curr_status.scsw.count = ccw.count - sizeof(indicators);
- ret = 0;
- }
- break;
- case CCW_CMD_SET_CONF_IND:
- if (check_len) {
- if (ccw.count != sizeof(indicators)) {
- ret = -EINVAL;
- break;
- }
- } else if (ccw.count < sizeof(indicators)) {
- /* Can't execute command. */
- ret = -EINVAL;
- break;
- }
- if (!ccw.cda) {
- ret = -EFAULT;
- } else {
- indicators = address_space_ldq_be(&address_space_memory, ccw.cda,
- MEMTXATTRS_UNSPECIFIED, NULL);
- dev->indicators2 = get_indicator(indicators, sizeof(uint64_t));
- sch->curr_status.scsw.count = ccw.count - sizeof(indicators);
- ret = 0;
- }
- break;
- case CCW_CMD_READ_VQ_CONF:
- if (check_len) {
- if (ccw.count != sizeof(vq_config)) {
- ret = -EINVAL;
- break;
- }
- } else if (ccw.count < sizeof(vq_config)) {
- /* Can't execute command. */
- ret = -EINVAL;
- break;
- }
- if (!ccw.cda) {
- ret = -EFAULT;
- } else {
- vq_config.index = address_space_lduw_be(&address_space_memory,
- ccw.cda,
- MEMTXATTRS_UNSPECIFIED,
- NULL);
- if (vq_config.index >= VIRTIO_CCW_QUEUE_MAX) {
- ret = -EINVAL;
- break;
- }
- vq_config.num_max = virtio_queue_get_num(vdev,
- vq_config.index);
- address_space_stw_be(&address_space_memory,
- ccw.cda + sizeof(vq_config.index),
- vq_config.num_max,
- MEMTXATTRS_UNSPECIFIED,
- NULL);
- sch->curr_status.scsw.count = ccw.count - sizeof(vq_config);
- ret = 0;
- }
- break;
- case CCW_CMD_SET_IND_ADAPTER:
- if (check_len) {
- if (ccw.count != sizeof(*thinint)) {
- ret = -EINVAL;
- break;
- }
- } else if (ccw.count < sizeof(*thinint)) {
- /* Can't execute command. */
- ret = -EINVAL;
- break;
- }
- len = sizeof(*thinint);
- hw_len = len;
- if (!ccw.cda) {
- ret = -EFAULT;
- } else if (dev->indicators && !sch->thinint_active) {
- /* Trigger a command reject. */
- ret = -ENOSYS;
- } else {
- thinint = cpu_physical_memory_map(ccw.cda, &hw_len, 0);
- if (!thinint) {
- ret = -EFAULT;
- } else {
- uint64_t ind_bit = ldq_be_p(&thinint->ind_bit);
-
- len = hw_len;
- dev->summary_indicator =
- get_indicator(ldq_be_p(&thinint->summary_indicator),
- sizeof(uint8_t));
- dev->indicators =
- get_indicator(ldq_be_p(&thinint->device_indicator),
- ind_bit / 8 + 1);
- dev->thinint_isc = thinint->isc;
- dev->routes.adapter.ind_offset = ind_bit;
- dev->routes.adapter.summary_offset = 7;
- cpu_physical_memory_unmap(thinint, hw_len, 0, hw_len);
- ret = css_register_io_adapter(CSS_IO_ADAPTER_VIRTIO,
- dev->thinint_isc, true, false,
- &dev->routes.adapter.adapter_id);
- assert(ret == 0);
- sch->thinint_active = ((dev->indicators != NULL) &&
- (dev->summary_indicator != NULL));
- sch->curr_status.scsw.count = ccw.count - len;
- ret = 0;
- }
- }
- break;
- case CCW_CMD_SET_VIRTIO_REV:
- len = sizeof(revinfo);
- if (ccw.count < len) {
- ret = -EINVAL;
- break;
- }
- if (!ccw.cda) {
- ret = -EFAULT;
- break;
- }
- revinfo.revision =
- address_space_lduw_be(&address_space_memory, ccw.cda,
- MEMTXATTRS_UNSPECIFIED, NULL);
- revinfo.length =
- address_space_lduw_be(&address_space_memory,
- ccw.cda + sizeof(revinfo.revision),
- MEMTXATTRS_UNSPECIFIED, NULL);
- if (ccw.count < len + revinfo.length ||
- (check_len && ccw.count > len + revinfo.length)) {
- ret = -EINVAL;
- break;
- }
- /*
- * Once we start to support revisions with additional data, we'll
- * need to fetch it here. Nothing to do for now, though.
- */
- if (dev->revision >= 0 ||
- revinfo.revision > virtio_ccw_rev_max(dev)) {
- ret = -ENOSYS;
- break;
- }
- ret = 0;
- dev->revision = revinfo.revision;
- break;
- default:
- ret = -ENOSYS;
- break;
- }
- return ret;
-}
-
-static void virtio_sch_disable_cb(SubchDev *sch)
-{
- VirtioCcwDevice *dev = sch->driver_data;
-
- dev->revision = -1;
-}
-
-static void virtio_ccw_device_realize(VirtioCcwDevice *dev, Error **errp)
-{
- unsigned int cssid = 0;
- unsigned int ssid = 0;
- unsigned int schid;
- unsigned int devno;
- bool have_devno = false;
- bool found = false;
- SubchDev *sch;
- int num;
- Error *err = NULL;
- VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_GET_CLASS(dev);
-
- sch = g_malloc0(sizeof(SubchDev));
-
- sch->driver_data = dev;
- dev->sch = sch;
-
- dev->indicators = NULL;
-
- /* Initialize subchannel structure. */
- sch->channel_prog = 0x0;
- sch->last_cmd_valid = false;
- sch->thinint_active = false;
- /*
- * Use a device number if provided. Otherwise, fall back to subchannel
- * number.
- */
- if (dev->bus_id) {
- num = sscanf(dev->bus_id, "%x.%x.%04x", &cssid, &ssid, &devno);
- if (num == 3) {
- if ((cssid > MAX_CSSID) || (ssid > MAX_SSID)) {
- error_setg(errp, "Invalid cssid or ssid: cssid %x, ssid %x",
- cssid, ssid);
- goto out_err;
- }
- /* Enforce use of virtual cssid. */
- if (cssid != VIRTUAL_CSSID) {
- error_setg(errp, "cssid %x not valid for virtio devices",
- cssid);
- goto out_err;
- }
- if (css_devno_used(cssid, ssid, devno)) {
- error_setg(errp, "Device %x.%x.%04x already exists",
- cssid, ssid, devno);
- goto out_err;
- }
- sch->cssid = cssid;
- sch->ssid = ssid;
- sch->devno = devno;
- have_devno = true;
- } else {
- error_setg(errp, "Malformed devno parameter '%s'", dev->bus_id);
- goto out_err;
- }
- }
-
- /* Find the next free id. */
- if (have_devno) {
- for (schid = 0; schid <= MAX_SCHID; schid++) {
- if (!css_find_subch(1, cssid, ssid, schid)) {
- sch->schid = schid;
- css_subch_assign(cssid, ssid, schid, devno, sch);
- found = true;
- break;
- }
- }
- if (!found) {
- error_setg(errp, "No free subchannel found for %x.%x.%04x",
- cssid, ssid, devno);
- goto out_err;
- }
- trace_virtio_ccw_new_device(cssid, ssid, schid, devno,
- "user-configured");
- } else {
- cssid = VIRTUAL_CSSID;
- for (ssid = 0; ssid <= MAX_SSID; ssid++) {
- for (schid = 0; schid <= MAX_SCHID; schid++) {
- if (!css_find_subch(1, cssid, ssid, schid)) {
- sch->cssid = cssid;
- sch->ssid = ssid;
- sch->schid = schid;
- devno = schid;
- /*
- * If the devno is already taken, look further in this
- * subchannel set.
- */
- while (css_devno_used(cssid, ssid, devno)) {
- if (devno == MAX_SCHID) {
- devno = 0;
- } else if (devno == schid - 1) {
- error_setg(errp, "No free devno found");
- goto out_err;
- } else {
- devno++;
- }
- }
- sch->devno = devno;
- css_subch_assign(cssid, ssid, schid, devno, sch);
- found = true;
- break;
- }
- }
- if (found) {
- break;
- }
- }
- if (!found) {
- error_setg(errp, "Virtual channel subsystem is full!");
- goto out_err;
- }
- trace_virtio_ccw_new_device(cssid, ssid, schid, devno,
- "auto-configured");
- }
-
- /* Build initial schib. */
- css_sch_build_virtual_schib(sch, 0, VIRTIO_CCW_CHPID_TYPE);
-
- sch->ccw_cb = virtio_ccw_cb;
- sch->disable_cb = virtio_sch_disable_cb;
-
- /* Build senseid data. */
- memset(&sch->id, 0, sizeof(SenseId));
- sch->id.reserved = 0xff;
- sch->id.cu_type = VIRTIO_CCW_CU_TYPE;
-
- dev->revision = -1;
-
- if (k->realize) {
- k->realize(dev, &err);
- }
- if (err) {
- error_propagate(errp, err);
- css_subch_assign(cssid, ssid, schid, devno, NULL);
- goto out_err;
- }
-
- return;
-
-out_err:
- dev->sch = NULL;
- g_free(sch);
-}
-
-static int virtio_ccw_exit(VirtioCcwDevice *dev)
-{
- SubchDev *sch = dev->sch;
-
- if (sch) {
- css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL);
- g_free(sch);
- }
- if (dev->indicators) {
- release_indicator(&dev->routes.adapter, dev->indicators);
- dev->indicators = NULL;
- }
- return 0;
-}
-
-static void virtio_ccw_net_realize(VirtioCcwDevice *ccw_dev, Error **errp)
-{
- DeviceState *qdev = DEVICE(ccw_dev);
- VirtIONetCcw *dev = VIRTIO_NET_CCW(ccw_dev);
- DeviceState *vdev = DEVICE(&dev->vdev);
- Error *err = NULL;
-
- virtio_net_set_netclient_name(&dev->vdev, qdev->id,
- object_get_typename(OBJECT(qdev)));
- qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
- object_property_set_bool(OBJECT(vdev), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- }
-}
-
-static void virtio_ccw_net_instance_init(Object *obj)
-{
- VirtIONetCcw *dev = VIRTIO_NET_CCW(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VIRTIO_NET);
- object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
- "bootindex", &error_abort);
-}
-
-static void virtio_ccw_blk_realize(VirtioCcwDevice *ccw_dev, Error **errp)
-{
- VirtIOBlkCcw *dev = VIRTIO_BLK_CCW(ccw_dev);
- DeviceState *vdev = DEVICE(&dev->vdev);
- Error *err = NULL;
-
- qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
- object_property_set_bool(OBJECT(vdev), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- }
-}
-
-static void virtio_ccw_blk_instance_init(Object *obj)
-{
- VirtIOBlkCcw *dev = VIRTIO_BLK_CCW(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VIRTIO_BLK);
- object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev),"iothread",
- &error_abort);
- object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
- "bootindex", &error_abort);
-}
-
-static void virtio_ccw_serial_realize(VirtioCcwDevice *ccw_dev, Error **errp)
-{
- VirtioSerialCcw *dev = VIRTIO_SERIAL_CCW(ccw_dev);
- DeviceState *vdev = DEVICE(&dev->vdev);
- DeviceState *proxy = DEVICE(ccw_dev);
- Error *err = NULL;
- char *bus_name;
-
- /*
- * For command line compatibility, this sets the virtio-serial-device bus
- * name as before.
- */
- if (proxy->id) {
- bus_name = g_strdup_printf("%s.0", proxy->id);
- virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name);
- g_free(bus_name);
- }
-
- qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
- object_property_set_bool(OBJECT(vdev), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- }
-}
-
-
-static void virtio_ccw_serial_instance_init(Object *obj)
-{
- VirtioSerialCcw *dev = VIRTIO_SERIAL_CCW(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VIRTIO_SERIAL);
-}
-
-static void virtio_ccw_balloon_realize(VirtioCcwDevice *ccw_dev, Error **errp)
-{
- VirtIOBalloonCcw *dev = VIRTIO_BALLOON_CCW(ccw_dev);
- DeviceState *vdev = DEVICE(&dev->vdev);
- Error *err = NULL;
-
- qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
- object_property_set_bool(OBJECT(vdev), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- }
-}
-
-static void virtio_ccw_balloon_instance_init(Object *obj)
-{
- VirtIOBalloonCcw *dev = VIRTIO_BALLOON_CCW(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VIRTIO_BALLOON);
- object_property_add_alias(obj, "guest-stats", OBJECT(&dev->vdev),
- "guest-stats", &error_abort);
- object_property_add_alias(obj, "guest-stats-polling-interval",
- OBJECT(&dev->vdev),
- "guest-stats-polling-interval", &error_abort);
-}
-
-static void virtio_ccw_scsi_realize(VirtioCcwDevice *ccw_dev, Error **errp)
-{
- VirtIOSCSICcw *dev = VIRTIO_SCSI_CCW(ccw_dev);
- DeviceState *vdev = DEVICE(&dev->vdev);
- DeviceState *qdev = DEVICE(ccw_dev);
- Error *err = NULL;
- char *bus_name;
-
- /*
- * For command line compatibility, this sets the virtio-scsi-device bus
- * name as before.
- */
- if (qdev->id) {
- bus_name = g_strdup_printf("%s.0", qdev->id);
- virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name);
- g_free(bus_name);
- }
-
- qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
- object_property_set_bool(OBJECT(vdev), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- }
-}
-
-static void virtio_ccw_scsi_instance_init(Object *obj)
-{
- VirtIOSCSICcw *dev = VIRTIO_SCSI_CCW(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VIRTIO_SCSI);
- object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev), "iothread",
- &error_abort);
-}
-
-#ifdef CONFIG_VHOST_SCSI
-static void vhost_ccw_scsi_realize(VirtioCcwDevice *ccw_dev, Error **errp)
-{
- VHostSCSICcw *dev = VHOST_SCSI_CCW(ccw_dev);
- DeviceState *vdev = DEVICE(&dev->vdev);
- Error *err = NULL;
-
- qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
- object_property_set_bool(OBJECT(vdev), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- }
-}
-
-static void vhost_ccw_scsi_instance_init(Object *obj)
-{
- VHostSCSICcw *dev = VHOST_SCSI_CCW(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VHOST_SCSI);
-}
-#endif
-
-static void virtio_ccw_rng_realize(VirtioCcwDevice *ccw_dev, Error **errp)
-{
- VirtIORNGCcw *dev = VIRTIO_RNG_CCW(ccw_dev);
- DeviceState *vdev = DEVICE(&dev->vdev);
- Error *err = NULL;
-
- qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
- object_property_set_bool(OBJECT(vdev), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- object_property_set_link(OBJECT(dev),
- OBJECT(dev->vdev.conf.rng), "rng",
- NULL);
-}
-
-/* DeviceState to VirtioCcwDevice. Note: used on datapath,
- * be careful and test performance if you change this.
- */
-static inline VirtioCcwDevice *to_virtio_ccw_dev_fast(DeviceState *d)
-{
- return container_of(d, VirtioCcwDevice, parent_obj);
-}
-
-static uint8_t virtio_set_ind_atomic(SubchDev *sch, uint64_t ind_loc,
- uint8_t to_be_set)
-{
- uint8_t ind_old, ind_new;
- hwaddr len = 1;
- uint8_t *ind_addr;
-
- ind_addr = cpu_physical_memory_map(ind_loc, &len, 1);
- if (!ind_addr) {
- error_report("%s(%x.%x.%04x): unable to access indicator",
- __func__, sch->cssid, sch->ssid, sch->schid);
- return -1;
- }
- do {
- ind_old = *ind_addr;
- ind_new = ind_old | to_be_set;
- } while (atomic_cmpxchg(ind_addr, ind_old, ind_new) != ind_old);
- cpu_physical_memory_unmap(ind_addr, len, 1, len);
-
- return ind_old;
-}
-
-static void virtio_ccw_notify(DeviceState *d, uint16_t vector)
-{
- VirtioCcwDevice *dev = to_virtio_ccw_dev_fast(d);
- SubchDev *sch = dev->sch;
- uint64_t indicators;
-
- /* queue indicators + secondary indicators */
- if (vector >= VIRTIO_CCW_QUEUE_MAX + 64) {
- return;
- }
-
- if (vector < VIRTIO_CCW_QUEUE_MAX) {
- if (!dev->indicators) {
- return;
- }
- if (sch->thinint_active) {
- /*
- * In the adapter interrupt case, indicators points to a
- * memory area that may be (way) larger than 64 bit and
- * ind_bit indicates the start of the indicators in a big
- * endian notation.
- */
- uint64_t ind_bit = dev->routes.adapter.ind_offset;
-
- virtio_set_ind_atomic(sch, dev->indicators->addr +
- (ind_bit + vector) / 8,
- 0x80 >> ((ind_bit + vector) % 8));
- if (!virtio_set_ind_atomic(sch, dev->summary_indicator->addr,
- 0x01)) {
- css_adapter_interrupt(dev->thinint_isc);
- }
- } else {
- indicators = address_space_ldq(&address_space_memory,
- dev->indicators->addr,
- MEMTXATTRS_UNSPECIFIED,
- NULL);
- indicators |= 1ULL << vector;
- address_space_stq(&address_space_memory, dev->indicators->addr,
- indicators, MEMTXATTRS_UNSPECIFIED, NULL);
- css_conditional_io_interrupt(sch);
- }
- } else {
- if (!dev->indicators2) {
- return;
- }
- vector = 0;
- indicators = address_space_ldq(&address_space_memory,
- dev->indicators2->addr,
- MEMTXATTRS_UNSPECIFIED,
- NULL);
- indicators |= 1ULL << vector;
- address_space_stq(&address_space_memory, dev->indicators2->addr,
- indicators, MEMTXATTRS_UNSPECIFIED, NULL);
- css_conditional_io_interrupt(sch);
- }
-}
-
-static void virtio_ccw_reset(DeviceState *d)
-{
- VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
- VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
-
- virtio_ccw_reset_virtio(dev, vdev);
- css_reset_sch(dev->sch);
-}
-
-static void virtio_ccw_vmstate_change(DeviceState *d, bool running)
-{
- VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
-
- if (running) {
- virtio_ccw_start_ioeventfd(dev);
- } else {
- virtio_ccw_stop_ioeventfd(dev);
- }
-}
-
-static bool virtio_ccw_query_guest_notifiers(DeviceState *d)
-{
- VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
-
- return !!(dev->sch->curr_status.pmcw.flags & PMCW_FLAGS_MASK_ENA);
-}
-
-static int virtio_ccw_set_host_notifier(DeviceState *d, int n, bool assign)
-{
- VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
-
- /* Stop using the generic ioeventfd, we are doing eventfd handling
- * ourselves below */
- dev->ioeventfd_disabled = assign;
- if (assign) {
- virtio_ccw_stop_ioeventfd(dev);
- }
- return virtio_ccw_set_guest2host_notifier(dev, n, assign, false);
-}
-
-static int virtio_ccw_get_mappings(VirtioCcwDevice *dev)
-{
- int r;
-
- if (!dev->sch->thinint_active) {
- return -EINVAL;
- }
-
- r = map_indicator(&dev->routes.adapter, dev->summary_indicator);
- if (r) {
- return r;
- }
- r = map_indicator(&dev->routes.adapter, dev->indicators);
- if (r) {
- return r;
- }
- dev->routes.adapter.summary_addr = dev->summary_indicator->map;
- dev->routes.adapter.ind_addr = dev->indicators->map;
-
- return 0;
-}
-
-static int virtio_ccw_setup_irqroutes(VirtioCcwDevice *dev, int nvqs)
-{
- int i;
- VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
- int ret;
- S390FLICState *fs = s390_get_flic();
- S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs);
-
- ret = virtio_ccw_get_mappings(dev);
- if (ret) {
- return ret;
- }
- for (i = 0; i < nvqs; i++) {
- if (!virtio_queue_get_num(vdev, i)) {
- break;
- }
- }
- dev->routes.num_routes = i;
- return fsc->add_adapter_routes(fs, &dev->routes);
-}
-
-static void virtio_ccw_release_irqroutes(VirtioCcwDevice *dev, int nvqs)
-{
- S390FLICState *fs = s390_get_flic();
- S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs);
-
- fsc->release_adapter_routes(fs, &dev->routes);
-}
-
-static int virtio_ccw_add_irqfd(VirtioCcwDevice *dev, int n)
-{
- VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
- VirtQueue *vq = virtio_get_queue(vdev, n);
- EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);
-
- return kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, notifier, NULL,
- dev->routes.gsi[n]);
-}
-
-static void virtio_ccw_remove_irqfd(VirtioCcwDevice *dev, int n)
-{
- VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
- VirtQueue *vq = virtio_get_queue(vdev, n);
- EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);
- int ret;
-
- ret = kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, notifier,
- dev->routes.gsi[n]);
- assert(ret == 0);
-}
-
-static int virtio_ccw_set_guest_notifier(VirtioCcwDevice *dev, int n,
- bool assign, bool with_irqfd)
-{
- VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
- VirtQueue *vq = virtio_get_queue(vdev, n);
- EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);
- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
-
- if (assign) {
- int r = event_notifier_init(notifier, 0);
-
- if (r < 0) {
- return r;
- }
- virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd);
- if (with_irqfd) {
- r = virtio_ccw_add_irqfd(dev, n);
- if (r) {
- virtio_queue_set_guest_notifier_fd_handler(vq, false,
- with_irqfd);
- return r;
- }
- }
- /*
- * We do not support individual masking for channel devices, so we
- * need to manually trigger any guest masking callbacks here.
- */
- if (k->guest_notifier_mask) {
- k->guest_notifier_mask(vdev, n, false);
- }
- /* get lost events and re-inject */
- if (k->guest_notifier_pending &&
- k->guest_notifier_pending(vdev, n)) {
- event_notifier_set(notifier);
- }
- } else {
- if (k->guest_notifier_mask) {
- k->guest_notifier_mask(vdev, n, true);
- }
- if (with_irqfd) {
- virtio_ccw_remove_irqfd(dev, n);
- }
- virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd);
- event_notifier_cleanup(notifier);
- }
- return 0;
-}
-
-static int virtio_ccw_set_guest_notifiers(DeviceState *d, int nvqs,
- bool assigned)
-{
- VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
- VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
- bool with_irqfd = dev->sch->thinint_active && kvm_irqfds_enabled();
- int r, n;
-
- if (with_irqfd && assigned) {
- /* irq routes need to be set up before assigning irqfds */
- r = virtio_ccw_setup_irqroutes(dev, nvqs);
- if (r < 0) {
- goto irqroute_error;
- }
- }
- for (n = 0; n < nvqs; n++) {
- if (!virtio_queue_get_num(vdev, n)) {
- break;
- }
- r = virtio_ccw_set_guest_notifier(dev, n, assigned, with_irqfd);
- if (r < 0) {
- goto assign_error;
- }
- }
- if (with_irqfd && !assigned) {
- /* release irq routes after irqfds have been released */
- virtio_ccw_release_irqroutes(dev, nvqs);
- }
- return 0;
-
-assign_error:
- while (--n >= 0) {
- virtio_ccw_set_guest_notifier(dev, n, !assigned, false);
- }
-irqroute_error:
- if (with_irqfd && assigned) {
- virtio_ccw_release_irqroutes(dev, nvqs);
- }
- return r;
-}
-
-static void virtio_ccw_save_queue(DeviceState *d, int n, QEMUFile *f)
-{
- VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
- VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
-
- qemu_put_be16(f, virtio_queue_vector(vdev, n));
-}
-
-static int virtio_ccw_load_queue(DeviceState *d, int n, QEMUFile *f)
-{
- VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
- VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
- uint16_t vector;
-
- qemu_get_be16s(f, &vector);
- virtio_queue_set_vector(vdev, n , vector);
-
- return 0;
-}
-
-static void virtio_ccw_save_config(DeviceState *d, QEMUFile *f)
-{
- VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
- SubchDev *s = dev->sch;
- VirtIODevice *vdev = virtio_ccw_get_vdev(s);
-
- subch_device_save(s, f);
- if (dev->indicators != NULL) {
- qemu_put_be32(f, dev->indicators->len);
- qemu_put_be64(f, dev->indicators->addr);
- } else {
- qemu_put_be32(f, 0);
- qemu_put_be64(f, 0UL);
- }
- if (dev->indicators2 != NULL) {
- qemu_put_be32(f, dev->indicators2->len);
- qemu_put_be64(f, dev->indicators2->addr);
- } else {
- qemu_put_be32(f, 0);
- qemu_put_be64(f, 0UL);
- }
- if (dev->summary_indicator != NULL) {
- qemu_put_be32(f, dev->summary_indicator->len);
- qemu_put_be64(f, dev->summary_indicator->addr);
- } else {
- qemu_put_be32(f, 0);
- qemu_put_be64(f, 0UL);
- }
- qemu_put_be16(f, vdev->config_vector);
- qemu_put_be64(f, dev->routes.adapter.ind_offset);
- qemu_put_byte(f, dev->thinint_isc);
- qemu_put_be32(f, dev->revision);
-}
-
-static int virtio_ccw_load_config(DeviceState *d, QEMUFile *f)
-{
- VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
- SubchDev *s = dev->sch;
- VirtIODevice *vdev = virtio_ccw_get_vdev(s);
- int len;
-
- s->driver_data = dev;
- subch_device_load(s, f);
- len = qemu_get_be32(f);
- if (len != 0) {
- dev->indicators = get_indicator(qemu_get_be64(f), len);
- } else {
- qemu_get_be64(f);
- dev->indicators = NULL;
- }
- len = qemu_get_be32(f);
- if (len != 0) {
- dev->indicators2 = get_indicator(qemu_get_be64(f), len);
- } else {
- qemu_get_be64(f);
- dev->indicators2 = NULL;
- }
- len = qemu_get_be32(f);
- if (len != 0) {
- dev->summary_indicator = get_indicator(qemu_get_be64(f), len);
- } else {
- qemu_get_be64(f);
- dev->summary_indicator = NULL;
- }
- qemu_get_be16s(f, &vdev->config_vector);
- dev->routes.adapter.ind_offset = qemu_get_be64(f);
- dev->thinint_isc = qemu_get_byte(f);
- dev->revision = qemu_get_be32(f);
- if (s->thinint_active) {
- return css_register_io_adapter(CSS_IO_ADAPTER_VIRTIO,
- dev->thinint_isc, true, false,
- &dev->routes.adapter.adapter_id);
- }
-
- return 0;
-}
-
-/* This is called by virtio-bus just after the device is plugged. */
-static void virtio_ccw_device_plugged(DeviceState *d, Error **errp)
-{
- VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
- VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
- SubchDev *sch = dev->sch;
- int n = virtio_get_num_queues(vdev);
-
- if (virtio_get_num_queues(vdev) > VIRTIO_CCW_QUEUE_MAX) {
- error_setg(errp, "The nubmer of virtqueues %d "
- "exceeds ccw limit %d", n,
- VIRTIO_CCW_QUEUE_MAX);
- return;
- }
-
- if (!kvm_eventfds_enabled()) {
- dev->flags &= ~VIRTIO_CCW_FLAG_USE_IOEVENTFD;
- }
-
- sch->id.cu_model = virtio_bus_get_vdev_id(&dev->bus);
-
- if (dev->max_rev >= 1) {
- virtio_add_feature(&vdev->host_features, VIRTIO_F_VERSION_1);
- }
-
- css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid,
- d->hotplugged, 1);
-}
-
-static void virtio_ccw_post_plugged(DeviceState *d, Error **errp)
-{
- VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
- VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
-
- if (!virtio_host_has_feature(vdev, VIRTIO_F_VERSION_1)) {
- /* A backend didn't support modern virtio. */
- dev->max_rev = 0;
- }
-}
-
-static void virtio_ccw_device_unplugged(DeviceState *d)
-{
- VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
-
- virtio_ccw_stop_ioeventfd(dev);
-}
-/**************** Virtio-ccw Bus Device Descriptions *******************/
-
-static Property virtio_ccw_net_properties[] = {
- DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
- DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
- VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
- DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
- VIRTIO_CCW_MAX_REV),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_ccw_net_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
-
- k->realize = virtio_ccw_net_realize;
- k->exit = virtio_ccw_exit;
- dc->reset = virtio_ccw_reset;
- dc->props = virtio_ccw_net_properties;
- set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
-}
-
-static const TypeInfo virtio_ccw_net = {
- .name = TYPE_VIRTIO_NET_CCW,
- .parent = TYPE_VIRTIO_CCW_DEVICE,
- .instance_size = sizeof(VirtIONetCcw),
- .instance_init = virtio_ccw_net_instance_init,
- .class_init = virtio_ccw_net_class_init,
-};
-
-static Property virtio_ccw_blk_properties[] = {
- DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
- DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
- VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
- DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
- VIRTIO_CCW_MAX_REV),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_ccw_blk_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
-
- k->realize = virtio_ccw_blk_realize;
- k->exit = virtio_ccw_exit;
- dc->reset = virtio_ccw_reset;
- dc->props = virtio_ccw_blk_properties;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
-}
-
-static const TypeInfo virtio_ccw_blk = {
- .name = TYPE_VIRTIO_BLK_CCW,
- .parent = TYPE_VIRTIO_CCW_DEVICE,
- .instance_size = sizeof(VirtIOBlkCcw),
- .instance_init = virtio_ccw_blk_instance_init,
- .class_init = virtio_ccw_blk_class_init,
-};
-
-static Property virtio_ccw_serial_properties[] = {
- DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
- DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
- VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
- DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
- VIRTIO_CCW_MAX_REV),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_ccw_serial_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
-
- k->realize = virtio_ccw_serial_realize;
- k->exit = virtio_ccw_exit;
- dc->reset = virtio_ccw_reset;
- dc->props = virtio_ccw_serial_properties;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
-}
-
-static const TypeInfo virtio_ccw_serial = {
- .name = TYPE_VIRTIO_SERIAL_CCW,
- .parent = TYPE_VIRTIO_CCW_DEVICE,
- .instance_size = sizeof(VirtioSerialCcw),
- .instance_init = virtio_ccw_serial_instance_init,
- .class_init = virtio_ccw_serial_class_init,
-};
-
-static Property virtio_ccw_balloon_properties[] = {
- DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
- DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
- VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
- DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
- VIRTIO_CCW_MAX_REV),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_ccw_balloon_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
-
- k->realize = virtio_ccw_balloon_realize;
- k->exit = virtio_ccw_exit;
- dc->reset = virtio_ccw_reset;
- dc->props = virtio_ccw_balloon_properties;
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
-}
-
-static const TypeInfo virtio_ccw_balloon = {
- .name = TYPE_VIRTIO_BALLOON_CCW,
- .parent = TYPE_VIRTIO_CCW_DEVICE,
- .instance_size = sizeof(VirtIOBalloonCcw),
- .instance_init = virtio_ccw_balloon_instance_init,
- .class_init = virtio_ccw_balloon_class_init,
-};
-
-static Property virtio_ccw_scsi_properties[] = {
- DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
- DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
- VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
- DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
- VIRTIO_CCW_MAX_REV),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_ccw_scsi_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
-
- k->realize = virtio_ccw_scsi_realize;
- k->exit = virtio_ccw_exit;
- dc->reset = virtio_ccw_reset;
- dc->props = virtio_ccw_scsi_properties;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
-}
-
-static const TypeInfo virtio_ccw_scsi = {
- .name = TYPE_VIRTIO_SCSI_CCW,
- .parent = TYPE_VIRTIO_CCW_DEVICE,
- .instance_size = sizeof(VirtIOSCSICcw),
- .instance_init = virtio_ccw_scsi_instance_init,
- .class_init = virtio_ccw_scsi_class_init,
-};
-
-#ifdef CONFIG_VHOST_SCSI
-static Property vhost_ccw_scsi_properties[] = {
- DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
- DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
- VIRTIO_CCW_MAX_REV),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void vhost_ccw_scsi_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
-
- k->realize = vhost_ccw_scsi_realize;
- k->exit = virtio_ccw_exit;
- dc->reset = virtio_ccw_reset;
- dc->props = vhost_ccw_scsi_properties;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
-}
-
-static const TypeInfo vhost_ccw_scsi = {
- .name = TYPE_VHOST_SCSI_CCW,
- .parent = TYPE_VIRTIO_CCW_DEVICE,
- .instance_size = sizeof(VHostSCSICcw),
- .instance_init = vhost_ccw_scsi_instance_init,
- .class_init = vhost_ccw_scsi_class_init,
-};
-#endif
-
-static void virtio_ccw_rng_instance_init(Object *obj)
-{
- VirtIORNGCcw *dev = VIRTIO_RNG_CCW(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VIRTIO_RNG);
- object_property_add_alias(obj, "rng", OBJECT(&dev->vdev),
- "rng", &error_abort);
-}
-
-static Property virtio_ccw_rng_properties[] = {
- DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
- DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
- VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
- DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
- VIRTIO_CCW_MAX_REV),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_ccw_rng_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
-
- k->realize = virtio_ccw_rng_realize;
- k->exit = virtio_ccw_exit;
- dc->reset = virtio_ccw_reset;
- dc->props = virtio_ccw_rng_properties;
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
-}
-
-static const TypeInfo virtio_ccw_rng = {
- .name = TYPE_VIRTIO_RNG_CCW,
- .parent = TYPE_VIRTIO_CCW_DEVICE,
- .instance_size = sizeof(VirtIORNGCcw),
- .instance_init = virtio_ccw_rng_instance_init,
- .class_init = virtio_ccw_rng_class_init,
-};
-
-static void virtio_ccw_busdev_realize(DeviceState *dev, Error **errp)
-{
- VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev;
-
- virtio_ccw_bus_new(&_dev->bus, sizeof(_dev->bus), _dev);
- virtio_ccw_device_realize(_dev, errp);
-}
-
-static int virtio_ccw_busdev_exit(DeviceState *dev)
-{
- VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev;
- VirtIOCCWDeviceClass *_info = VIRTIO_CCW_DEVICE_GET_CLASS(dev);
-
- return _info->exit(_dev);
-}
-
-static void virtio_ccw_busdev_unplug(HotplugHandler *hotplug_dev,
- DeviceState *dev, Error **errp)
-{
- VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev;
- SubchDev *sch = _dev->sch;
-
- virtio_ccw_stop_ioeventfd(_dev);
-
- /*
- * We should arrive here only for device_del, since we don't support
- * direct hot(un)plug of channels, but only through virtio.
- */
- assert(sch != NULL);
- /* Subchannel is now disabled and no longer valid. */
- sch->curr_status.pmcw.flags &= ~(PMCW_FLAGS_MASK_ENA |
- PMCW_FLAGS_MASK_DNV);
-
- css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid, 1, 0);
-
- object_unparent(OBJECT(dev));
-}
-
-static void virtio_ccw_device_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = virtio_ccw_busdev_realize;
- dc->exit = virtio_ccw_busdev_exit;
- dc->bus_type = TYPE_VIRTUAL_CSS_BUS;
-}
-
-static const TypeInfo virtio_ccw_device_info = {
- .name = TYPE_VIRTIO_CCW_DEVICE,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(VirtioCcwDevice),
- .class_init = virtio_ccw_device_class_init,
- .class_size = sizeof(VirtIOCCWDeviceClass),
- .abstract = true,
-};
-
-/***************** Virtual-css Bus Bridge Device ********************/
-/* Only required to have the virtio bus as child in the system bus */
-
-static int virtual_css_bridge_init(SysBusDevice *dev)
-{
- /* nothing */
- return 0;
-}
-
-static void virtual_css_bridge_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- k->init = virtual_css_bridge_init;
- hc->unplug = virtio_ccw_busdev_unplug;
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
-}
-
-static const TypeInfo virtual_css_bridge_info = {
- .name = "virtual-css-bridge",
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(SysBusDevice),
- .class_init = virtual_css_bridge_class_init,
- .interfaces = (InterfaceInfo[]) {
- { TYPE_HOTPLUG_HANDLER },
- { }
- }
-};
-
-/* virtio-ccw-bus */
-
-static void virtio_ccw_bus_new(VirtioBusState *bus, size_t bus_size,
- VirtioCcwDevice *dev)
-{
- DeviceState *qdev = DEVICE(dev);
- char virtio_bus_name[] = "virtio-bus";
-
- qbus_create_inplace(bus, bus_size, TYPE_VIRTIO_CCW_BUS,
- qdev, virtio_bus_name);
-}
-
-static void virtio_ccw_bus_class_init(ObjectClass *klass, void *data)
-{
- VirtioBusClass *k = VIRTIO_BUS_CLASS(klass);
- BusClass *bus_class = BUS_CLASS(klass);
-
- bus_class->max_dev = 1;
- k->notify = virtio_ccw_notify;
- k->vmstate_change = virtio_ccw_vmstate_change;
- k->query_guest_notifiers = virtio_ccw_query_guest_notifiers;
- k->set_host_notifier = virtio_ccw_set_host_notifier;
- k->set_guest_notifiers = virtio_ccw_set_guest_notifiers;
- k->save_queue = virtio_ccw_save_queue;
- k->load_queue = virtio_ccw_load_queue;
- k->save_config = virtio_ccw_save_config;
- k->load_config = virtio_ccw_load_config;
- k->device_plugged = virtio_ccw_device_plugged;
- k->post_plugged = virtio_ccw_post_plugged;
- k->device_unplugged = virtio_ccw_device_unplugged;
-}
-
-static const TypeInfo virtio_ccw_bus_info = {
- .name = TYPE_VIRTIO_CCW_BUS,
- .parent = TYPE_VIRTIO_BUS,
- .instance_size = sizeof(VirtioCcwBusState),
- .class_init = virtio_ccw_bus_class_init,
-};
-
-#ifdef CONFIG_VIRTFS
-static Property virtio_ccw_9p_properties[] = {
- DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
- DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
- VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
- DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
- VIRTIO_CCW_MAX_REV),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_ccw_9p_realize(VirtioCcwDevice *ccw_dev, Error **errp)
-{
- V9fsCCWState *dev = VIRTIO_9P_CCW(ccw_dev);
- DeviceState *vdev = DEVICE(&dev->vdev);
- Error *err = NULL;
-
- qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
- object_property_set_bool(OBJECT(vdev), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- }
-}
-
-static void virtio_ccw_9p_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
-
- k->exit = virtio_ccw_exit;
- k->realize = virtio_ccw_9p_realize;
- dc->reset = virtio_ccw_reset;
- dc->props = virtio_ccw_9p_properties;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
-}
-
-static void virtio_ccw_9p_instance_init(Object *obj)
-{
- V9fsCCWState *dev = VIRTIO_9P_CCW(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VIRTIO_9P);
-}
-
-static const TypeInfo virtio_ccw_9p_info = {
- .name = TYPE_VIRTIO_9P_CCW,
- .parent = TYPE_VIRTIO_CCW_DEVICE,
- .instance_size = sizeof(V9fsCCWState),
- .instance_init = virtio_ccw_9p_instance_init,
- .class_init = virtio_ccw_9p_class_init,
-};
-#endif
-
-static void virtio_ccw_register(void)
-{
- type_register_static(&virtio_ccw_bus_info);
- type_register_static(&virtual_css_bus_info);
- type_register_static(&virtio_ccw_device_info);
- type_register_static(&virtio_ccw_serial);
- type_register_static(&virtio_ccw_blk);
- type_register_static(&virtio_ccw_net);
- type_register_static(&virtio_ccw_balloon);
- type_register_static(&virtio_ccw_scsi);
-#ifdef CONFIG_VHOST_SCSI
- type_register_static(&vhost_ccw_scsi);
-#endif
- type_register_static(&virtio_ccw_rng);
- type_register_static(&virtual_css_bridge_info);
-#ifdef CONFIG_VIRTFS
- type_register_static(&virtio_ccw_9p_info);
-#endif
-}
-
-type_init(virtio_ccw_register)
diff --git a/qemu/hw/s390x/virtio-ccw.h b/qemu/hw/s390x/virtio-ccw.h
deleted file mode 100644
index 66c831ba8..000000000
--- a/qemu/hw/s390x/virtio-ccw.h
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * virtio ccw target definitions
- *
- * Copyright 2012,2015 IBM Corp.
- * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
- * Pierre Morel <pmorel@linux.vnet.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or (at
- * your option) any later version. See the COPYING file in the top-level
- * directory.
- */
-
-#ifndef HW_S390X_VIRTIO_CCW_H
-#define HW_S390X_VIRTIO_CCW_H
-
-#include <hw/virtio/virtio-blk.h>
-#include <hw/virtio/virtio-net.h>
-#include <hw/virtio/virtio-serial.h>
-#include <hw/virtio/virtio-scsi.h>
-#ifdef CONFIG_VHOST_SCSI
-#include <hw/virtio/vhost-scsi.h>
-#endif
-#include <hw/virtio/virtio-balloon.h>
-#include <hw/virtio/virtio-rng.h>
-#include <hw/virtio/virtio-bus.h>
-
-#include "css.h"
-
-#define VIRTUAL_CSSID 0xfe
-
-#define VIRTIO_CCW_CU_TYPE 0x3832
-#define VIRTIO_CCW_CHPID_TYPE 0x32
-
-#define CCW_CMD_SET_VQ 0x13
-#define CCW_CMD_VDEV_RESET 0x33
-#define CCW_CMD_READ_FEAT 0x12
-#define CCW_CMD_WRITE_FEAT 0x11
-#define CCW_CMD_READ_CONF 0x22
-#define CCW_CMD_WRITE_CONF 0x21
-#define CCW_CMD_WRITE_STATUS 0x31
-#define CCW_CMD_SET_IND 0x43
-#define CCW_CMD_SET_CONF_IND 0x53
-#define CCW_CMD_READ_VQ_CONF 0x32
-#define CCW_CMD_SET_IND_ADAPTER 0x73
-#define CCW_CMD_SET_VIRTIO_REV 0x83
-
-#define TYPE_VIRTIO_CCW_DEVICE "virtio-ccw-device"
-#define VIRTIO_CCW_DEVICE(obj) \
- OBJECT_CHECK(VirtioCcwDevice, (obj), TYPE_VIRTIO_CCW_DEVICE)
-#define VIRTIO_CCW_DEVICE_CLASS(klass) \
- OBJECT_CLASS_CHECK(VirtIOCCWDeviceClass, (klass), TYPE_VIRTIO_CCW_DEVICE)
-#define VIRTIO_CCW_DEVICE_GET_CLASS(obj) \
- OBJECT_GET_CLASS(VirtIOCCWDeviceClass, (obj), TYPE_VIRTIO_CCW_DEVICE)
-
-typedef struct VirtioBusState VirtioCcwBusState;
-typedef struct VirtioBusClass VirtioCcwBusClass;
-
-#define TYPE_VIRTIO_CCW_BUS "virtio-ccw-bus"
-#define VIRTIO_CCW_BUS(obj) \
- OBJECT_CHECK(VirtioCcwBus, (obj), TYPE_VIRTIO_CCW_BUS)
-#define VIRTIO_CCW_BUS_GET_CLASS(obj) \
- OBJECT_CHECK(VirtioCcwBusState, (obj), TYPE_VIRTIO_CCW_BUS)
-#define VIRTIO_CCW_BUS_CLASS(klass) \
- OBJECT_CLASS_CHECK(VirtioCcwBusClass, klass, TYPE_VIRTIO_CCW_BUS)
-
-typedef struct VirtioCcwDevice VirtioCcwDevice;
-
-typedef struct VirtIOCCWDeviceClass {
- DeviceClass parent_class;
- void (*realize)(VirtioCcwDevice *dev, Error **errp);
- int (*exit)(VirtioCcwDevice *dev);
-} VirtIOCCWDeviceClass;
-
-/* Performance improves when virtqueue kick processing is decoupled from the
- * vcpu thread using ioeventfd for some devices. */
-#define VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT 1
-#define VIRTIO_CCW_FLAG_USE_IOEVENTFD (1 << VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT)
-
-struct VirtioCcwDevice {
- DeviceState parent_obj;
- SubchDev *sch;
- char *bus_id;
- int revision;
- uint32_t max_rev;
- VirtioBusState bus;
- bool ioeventfd_started;
- bool ioeventfd_disabled;
- uint32_t flags;
- uint8_t thinint_isc;
- AdapterRoutes routes;
- /* Guest provided values: */
- IndAddr *indicators;
- IndAddr *indicators2;
- IndAddr *summary_indicator;
- uint64_t ind_bit;
-};
-
-/* The maximum virtio revision we support. */
-#define VIRTIO_CCW_MAX_REV 1
-static inline int virtio_ccw_rev_max(VirtioCcwDevice *dev)
-{
- return dev->max_rev;
-}
-
-/* virtual css bus type */
-typedef struct VirtualCssBus {
- BusState parent_obj;
-} VirtualCssBus;
-
-#define TYPE_VIRTUAL_CSS_BUS "virtual-css-bus"
-#define VIRTUAL_CSS_BUS(obj) \
- OBJECT_CHECK(VirtualCssBus, (obj), TYPE_VIRTUAL_CSS_BUS)
-
-/* virtio-scsi-ccw */
-
-#define TYPE_VIRTIO_SCSI_CCW "virtio-scsi-ccw"
-#define VIRTIO_SCSI_CCW(obj) \
- OBJECT_CHECK(VirtIOSCSICcw, (obj), TYPE_VIRTIO_SCSI_CCW)
-
-typedef struct VirtIOSCSICcw {
- VirtioCcwDevice parent_obj;
- VirtIOSCSI vdev;
-} VirtIOSCSICcw;
-
-#ifdef CONFIG_VHOST_SCSI
-/* vhost-scsi-ccw */
-
-#define TYPE_VHOST_SCSI_CCW "vhost-scsi-ccw"
-#define VHOST_SCSI_CCW(obj) \
- OBJECT_CHECK(VHostSCSICcw, (obj), TYPE_VHOST_SCSI_CCW)
-
-typedef struct VHostSCSICcw {
- VirtioCcwDevice parent_obj;
- VHostSCSI vdev;
-} VHostSCSICcw;
-#endif
-
-/* virtio-blk-ccw */
-
-#define TYPE_VIRTIO_BLK_CCW "virtio-blk-ccw"
-#define VIRTIO_BLK_CCW(obj) \
- OBJECT_CHECK(VirtIOBlkCcw, (obj), TYPE_VIRTIO_BLK_CCW)
-
-typedef struct VirtIOBlkCcw {
- VirtioCcwDevice parent_obj;
- VirtIOBlock vdev;
-} VirtIOBlkCcw;
-
-/* virtio-balloon-ccw */
-
-#define TYPE_VIRTIO_BALLOON_CCW "virtio-balloon-ccw"
-#define VIRTIO_BALLOON_CCW(obj) \
- OBJECT_CHECK(VirtIOBalloonCcw, (obj), TYPE_VIRTIO_BALLOON_CCW)
-
-typedef struct VirtIOBalloonCcw {
- VirtioCcwDevice parent_obj;
- VirtIOBalloon vdev;
-} VirtIOBalloonCcw;
-
-/* virtio-serial-ccw */
-
-#define TYPE_VIRTIO_SERIAL_CCW "virtio-serial-ccw"
-#define VIRTIO_SERIAL_CCW(obj) \
- OBJECT_CHECK(VirtioSerialCcw, (obj), TYPE_VIRTIO_SERIAL_CCW)
-
-typedef struct VirtioSerialCcw {
- VirtioCcwDevice parent_obj;
- VirtIOSerial vdev;
-} VirtioSerialCcw;
-
-/* virtio-net-ccw */
-
-#define TYPE_VIRTIO_NET_CCW "virtio-net-ccw"
-#define VIRTIO_NET_CCW(obj) \
- OBJECT_CHECK(VirtIONetCcw, (obj), TYPE_VIRTIO_NET_CCW)
-
-typedef struct VirtIONetCcw {
- VirtioCcwDevice parent_obj;
- VirtIONet vdev;
-} VirtIONetCcw;
-
-/* virtio-rng-ccw */
-
-#define TYPE_VIRTIO_RNG_CCW "virtio-rng-ccw"
-#define VIRTIO_RNG_CCW(obj) \
- OBJECT_CHECK(VirtIORNGCcw, (obj), TYPE_VIRTIO_RNG_CCW)
-
-typedef struct VirtIORNGCcw {
- VirtioCcwDevice parent_obj;
- VirtIORNG vdev;
-} VirtIORNGCcw;
-
-VirtualCssBus *virtual_css_bus_init(void);
-void virtio_ccw_device_update_status(SubchDev *sch);
-VirtIODevice *virtio_ccw_get_vdev(SubchDev *sch);
-
-#ifdef CONFIG_VIRTFS
-#include "hw/9pfs/virtio-9p.h"
-
-#define TYPE_VIRTIO_9P_CCW "virtio-9p-ccw"
-#define VIRTIO_9P_CCW(obj) \
- OBJECT_CHECK(V9fsCCWState, (obj), TYPE_VIRTIO_9P_CCW)
-
-typedef struct V9fsCCWState {
- VirtioCcwDevice parent_obj;
- V9fsVirtioState vdev;
-} V9fsCCWState;
-
-#endif /* CONFIG_VIRTFS */
-
-#endif
diff --git a/qemu/hw/scsi/Makefile.objs b/qemu/hw/scsi/Makefile.objs
deleted file mode 100644
index 5a2248be3..000000000
--- a/qemu/hw/scsi/Makefile.objs
+++ /dev/null
@@ -1,14 +0,0 @@
-common-obj-y += scsi-disk.o
-common-obj-y += scsi-generic.o scsi-bus.o
-common-obj-$(CONFIG_LSI_SCSI_PCI) += lsi53c895a.o
-common-obj-$(CONFIG_MPTSAS_SCSI_PCI) += mptsas.o mptconfig.o mptendian.o
-common-obj-$(CONFIG_MEGASAS_SCSI_PCI) += megasas.o
-common-obj-$(CONFIG_VMW_PVSCSI_SCSI_PCI) += vmw_pvscsi.o
-common-obj-$(CONFIG_ESP) += esp.o
-common-obj-$(CONFIG_ESP_PCI) += esp-pci.o
-obj-$(CONFIG_PSERIES) += spapr_vscsi.o
-
-ifeq ($(CONFIG_VIRTIO),y)
-obj-y += virtio-scsi.o virtio-scsi-dataplane.o
-obj-$(CONFIG_VHOST_SCSI) += vhost-scsi.o
-endif
diff --git a/qemu/hw/scsi/esp-pci.c b/qemu/hw/scsi/esp-pci.c
deleted file mode 100644
index 595f88b35..000000000
--- a/qemu/hw/scsi/esp-pci.c
+++ /dev/null
@@ -1,531 +0,0 @@
-/*
- * QEMU ESP/NCR53C9x emulation
- *
- * Copyright (c) 2005-2006 Fabrice Bellard
- * Copyright (c) 2012 Herve Poussineau
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/pci/pci.h"
-#include "hw/nvram/eeprom93xx.h"
-#include "hw/scsi/esp.h"
-#include "trace.h"
-#include "qapi/error.h"
-#include "qemu/log.h"
-
-#define TYPE_AM53C974_DEVICE "am53c974"
-
-#define PCI_ESP(obj) \
- OBJECT_CHECK(PCIESPState, (obj), TYPE_AM53C974_DEVICE)
-
-#define DMA_CMD 0x0
-#define DMA_STC 0x1
-#define DMA_SPA 0x2
-#define DMA_WBC 0x3
-#define DMA_WAC 0x4
-#define DMA_STAT 0x5
-#define DMA_SMDLA 0x6
-#define DMA_WMAC 0x7
-
-#define DMA_CMD_MASK 0x03
-#define DMA_CMD_DIAG 0x04
-#define DMA_CMD_MDL 0x10
-#define DMA_CMD_INTE_P 0x20
-#define DMA_CMD_INTE_D 0x40
-#define DMA_CMD_DIR 0x80
-
-#define DMA_STAT_PWDN 0x01
-#define DMA_STAT_ERROR 0x02
-#define DMA_STAT_ABORT 0x04
-#define DMA_STAT_DONE 0x08
-#define DMA_STAT_SCSIINT 0x10
-#define DMA_STAT_BCMBLT 0x20
-
-#define SBAC_STATUS 0x1000
-
-typedef struct PCIESPState {
- /*< private >*/
- PCIDevice parent_obj;
- /*< public >*/
-
- MemoryRegion io;
- uint32_t dma_regs[8];
- uint32_t sbac;
- ESPState esp;
-} PCIESPState;
-
-static void esp_pci_handle_idle(PCIESPState *pci, uint32_t val)
-{
- trace_esp_pci_dma_idle(val);
- esp_dma_enable(&pci->esp, 0, 0);
-}
-
-static void esp_pci_handle_blast(PCIESPState *pci, uint32_t val)
-{
- trace_esp_pci_dma_blast(val);
- qemu_log_mask(LOG_UNIMP, "am53c974: cmd BLAST not implemented\n");
-}
-
-static void esp_pci_handle_abort(PCIESPState *pci, uint32_t val)
-{
- trace_esp_pci_dma_abort(val);
- if (pci->esp.current_req) {
- scsi_req_cancel(pci->esp.current_req);
- }
-}
-
-static void esp_pci_handle_start(PCIESPState *pci, uint32_t val)
-{
- trace_esp_pci_dma_start(val);
-
- pci->dma_regs[DMA_WBC] = pci->dma_regs[DMA_STC];
- pci->dma_regs[DMA_WAC] = pci->dma_regs[DMA_SPA];
- pci->dma_regs[DMA_WMAC] = pci->dma_regs[DMA_SMDLA];
-
- pci->dma_regs[DMA_STAT] &= ~(DMA_STAT_BCMBLT | DMA_STAT_SCSIINT
- | DMA_STAT_DONE | DMA_STAT_ABORT
- | DMA_STAT_ERROR | DMA_STAT_PWDN);
-
- esp_dma_enable(&pci->esp, 0, 1);
-}
-
-static void esp_pci_dma_write(PCIESPState *pci, uint32_t saddr, uint32_t val)
-{
- trace_esp_pci_dma_write(saddr, pci->dma_regs[saddr], val);
- switch (saddr) {
- case DMA_CMD:
- pci->dma_regs[saddr] = val;
- switch (val & DMA_CMD_MASK) {
- case 0x0: /* IDLE */
- esp_pci_handle_idle(pci, val);
- break;
- case 0x1: /* BLAST */
- esp_pci_handle_blast(pci, val);
- break;
- case 0x2: /* ABORT */
- esp_pci_handle_abort(pci, val);
- break;
- case 0x3: /* START */
- esp_pci_handle_start(pci, val);
- break;
- default: /* can't happen */
- abort();
- }
- break;
- case DMA_STC:
- case DMA_SPA:
- case DMA_SMDLA:
- pci->dma_regs[saddr] = val;
- break;
- case DMA_STAT:
- if (!(pci->sbac & SBAC_STATUS)) {
- /* clear some bits on write */
- uint32_t mask = DMA_STAT_ERROR | DMA_STAT_ABORT | DMA_STAT_DONE;
- pci->dma_regs[DMA_STAT] &= ~(val & mask);
- }
- break;
- default:
- trace_esp_pci_error_invalid_write_dma(val, saddr);
- return;
- }
-}
-
-static uint32_t esp_pci_dma_read(PCIESPState *pci, uint32_t saddr)
-{
- uint32_t val;
-
- val = pci->dma_regs[saddr];
- if (saddr == DMA_STAT) {
- if (pci->esp.rregs[ESP_RSTAT] & STAT_INT) {
- val |= DMA_STAT_SCSIINT;
- }
- if (pci->sbac & SBAC_STATUS) {
- pci->dma_regs[DMA_STAT] &= ~(DMA_STAT_ERROR | DMA_STAT_ABORT |
- DMA_STAT_DONE);
- }
- }
-
- trace_esp_pci_dma_read(saddr, val);
- return val;
-}
-
-static void esp_pci_io_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned int size)
-{
- PCIESPState *pci = opaque;
-
- if (size < 4 || addr & 3) {
- /* need to upgrade request: we only support 4-bytes accesses */
- uint32_t current = 0, mask;
- int shift;
-
- if (addr < 0x40) {
- current = pci->esp.wregs[addr >> 2];
- } else if (addr < 0x60) {
- current = pci->dma_regs[(addr - 0x40) >> 2];
- } else if (addr < 0x74) {
- current = pci->sbac;
- }
-
- shift = (4 - size) * 8;
- mask = (~(uint32_t)0 << shift) >> shift;
-
- shift = ((4 - (addr & 3)) & 3) * 8;
- val <<= shift;
- val |= current & ~(mask << shift);
- addr &= ~3;
- size = 4;
- }
-
- if (addr < 0x40) {
- /* SCSI core reg */
- esp_reg_write(&pci->esp, addr >> 2, val);
- } else if (addr < 0x60) {
- /* PCI DMA CCB */
- esp_pci_dma_write(pci, (addr - 0x40) >> 2, val);
- } else if (addr == 0x70) {
- /* DMA SCSI Bus and control */
- trace_esp_pci_sbac_write(pci->sbac, val);
- pci->sbac = val;
- } else {
- trace_esp_pci_error_invalid_write((int)addr);
- }
-}
-
-static uint64_t esp_pci_io_read(void *opaque, hwaddr addr,
- unsigned int size)
-{
- PCIESPState *pci = opaque;
- uint32_t ret;
-
- if (addr < 0x40) {
- /* SCSI core reg */
- ret = esp_reg_read(&pci->esp, addr >> 2);
- } else if (addr < 0x60) {
- /* PCI DMA CCB */
- ret = esp_pci_dma_read(pci, (addr - 0x40) >> 2);
- } else if (addr == 0x70) {
- /* DMA SCSI Bus and control */
- trace_esp_pci_sbac_read(pci->sbac);
- ret = pci->sbac;
- } else {
- /* Invalid region */
- trace_esp_pci_error_invalid_read((int)addr);
- ret = 0;
- }
-
- /* give only requested data */
- ret >>= (addr & 3) * 8;
- ret &= ~(~(uint64_t)0 << (8 * size));
-
- return ret;
-}
-
-static void esp_pci_dma_memory_rw(PCIESPState *pci, uint8_t *buf, int len,
- DMADirection dir)
-{
- dma_addr_t addr;
- DMADirection expected_dir;
-
- if (pci->dma_regs[DMA_CMD] & DMA_CMD_DIR) {
- expected_dir = DMA_DIRECTION_FROM_DEVICE;
- } else {
- expected_dir = DMA_DIRECTION_TO_DEVICE;
- }
-
- if (dir != expected_dir) {
- trace_esp_pci_error_invalid_dma_direction();
- return;
- }
-
- if (pci->dma_regs[DMA_STAT] & DMA_CMD_MDL) {
- qemu_log_mask(LOG_UNIMP, "am53c974: MDL transfer not implemented\n");
- }
-
- addr = pci->dma_regs[DMA_SPA];
- if (pci->dma_regs[DMA_WBC] < len) {
- len = pci->dma_regs[DMA_WBC];
- }
-
- pci_dma_rw(PCI_DEVICE(pci), addr, buf, len, dir);
-
- /* update status registers */
- pci->dma_regs[DMA_WBC] -= len;
- pci->dma_regs[DMA_WAC] += len;
- if (pci->dma_regs[DMA_WBC] == 0) {
- pci->dma_regs[DMA_STAT] |= DMA_STAT_DONE;
- }
-}
-
-static void esp_pci_dma_memory_read(void *opaque, uint8_t *buf, int len)
-{
- PCIESPState *pci = opaque;
- esp_pci_dma_memory_rw(pci, buf, len, DMA_DIRECTION_TO_DEVICE);
-}
-
-static void esp_pci_dma_memory_write(void *opaque, uint8_t *buf, int len)
-{
- PCIESPState *pci = opaque;
- esp_pci_dma_memory_rw(pci, buf, len, DMA_DIRECTION_FROM_DEVICE);
-}
-
-static const MemoryRegionOps esp_pci_io_ops = {
- .read = esp_pci_io_read,
- .write = esp_pci_io_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 4,
- },
-};
-
-static void esp_pci_hard_reset(DeviceState *dev)
-{
- PCIESPState *pci = PCI_ESP(dev);
- esp_hard_reset(&pci->esp);
- pci->dma_regs[DMA_CMD] &= ~(DMA_CMD_DIR | DMA_CMD_INTE_D | DMA_CMD_INTE_P
- | DMA_CMD_MDL | DMA_CMD_DIAG | DMA_CMD_MASK);
- pci->dma_regs[DMA_WBC] &= ~0xffff;
- pci->dma_regs[DMA_WAC] = 0xffffffff;
- pci->dma_regs[DMA_STAT] &= ~(DMA_STAT_BCMBLT | DMA_STAT_SCSIINT
- | DMA_STAT_DONE | DMA_STAT_ABORT
- | DMA_STAT_ERROR);
- pci->dma_regs[DMA_WMAC] = 0xfffffffd;
-}
-
-static const VMStateDescription vmstate_esp_pci_scsi = {
- .name = "pciespscsi",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(parent_obj, PCIESPState),
- VMSTATE_BUFFER_UNSAFE(dma_regs, PCIESPState, 0, 8 * sizeof(uint32_t)),
- VMSTATE_STRUCT(esp, PCIESPState, 0, vmstate_esp, ESPState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void esp_pci_command_complete(SCSIRequest *req, uint32_t status,
- size_t resid)
-{
- ESPState *s = req->hba_private;
- PCIESPState *pci = container_of(s, PCIESPState, esp);
-
- esp_command_complete(req, status, resid);
- pci->dma_regs[DMA_WBC] = 0;
- pci->dma_regs[DMA_STAT] |= DMA_STAT_DONE;
-}
-
-static const struct SCSIBusInfo esp_pci_scsi_info = {
- .tcq = false,
- .max_target = ESP_MAX_DEVS,
- .max_lun = 7,
-
- .transfer_data = esp_transfer_data,
- .complete = esp_pci_command_complete,
- .cancel = esp_request_cancelled,
-};
-
-static void esp_pci_scsi_realize(PCIDevice *dev, Error **errp)
-{
- PCIESPState *pci = PCI_ESP(dev);
- DeviceState *d = DEVICE(dev);
- ESPState *s = &pci->esp;
- uint8_t *pci_conf;
-
- pci_conf = dev->config;
-
- /* Interrupt pin A */
- pci_conf[PCI_INTERRUPT_PIN] = 0x01;
-
- s->dma_memory_read = esp_pci_dma_memory_read;
- s->dma_memory_write = esp_pci_dma_memory_write;
- s->dma_opaque = pci;
- s->chip_id = TCHI_AM53C974;
- memory_region_init_io(&pci->io, OBJECT(pci), &esp_pci_io_ops, pci,
- "esp-io", 0x80);
-
- pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &pci->io);
- s->irq = pci_allocate_irq(dev);
-
- scsi_bus_new(&s->bus, sizeof(s->bus), d, &esp_pci_scsi_info, NULL);
- if (!d->hotplugged) {
- scsi_bus_legacy_handle_cmdline(&s->bus, errp);
- }
-}
-
-static void esp_pci_scsi_uninit(PCIDevice *d)
-{
- PCIESPState *pci = PCI_ESP(d);
-
- qemu_free_irq(pci->esp.irq);
-}
-
-static void esp_pci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = esp_pci_scsi_realize;
- k->exit = esp_pci_scsi_uninit;
- k->vendor_id = PCI_VENDOR_ID_AMD;
- k->device_id = PCI_DEVICE_ID_AMD_SCSI;
- k->revision = 0x10;
- k->class_id = PCI_CLASS_STORAGE_SCSI;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
- dc->desc = "AMD Am53c974 PCscsi-PCI SCSI adapter";
- dc->reset = esp_pci_hard_reset;
- dc->vmsd = &vmstate_esp_pci_scsi;
-}
-
-static const TypeInfo esp_pci_info = {
- .name = TYPE_AM53C974_DEVICE,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(PCIESPState),
- .class_init = esp_pci_class_init,
-};
-
-typedef struct {
- PCIESPState pci;
- eeprom_t *eeprom;
-} DC390State;
-
-#define TYPE_DC390_DEVICE "dc390"
-#define DC390(obj) \
- OBJECT_CHECK(DC390State, obj, TYPE_DC390_DEVICE)
-
-#define EE_ADAPT_SCSI_ID 64
-#define EE_MODE2 65
-#define EE_DELAY 66
-#define EE_TAG_CMD_NUM 67
-#define EE_ADAPT_OPTIONS 68
-#define EE_BOOT_SCSI_ID 69
-#define EE_BOOT_SCSI_LUN 70
-#define EE_CHKSUM1 126
-#define EE_CHKSUM2 127
-
-#define EE_ADAPT_OPTION_F6_F8_AT_BOOT 0x01
-#define EE_ADAPT_OPTION_BOOT_FROM_CDROM 0x02
-#define EE_ADAPT_OPTION_INT13 0x04
-#define EE_ADAPT_OPTION_SCAM_SUPPORT 0x08
-
-
-static uint32_t dc390_read_config(PCIDevice *dev, uint32_t addr, int l)
-{
- DC390State *pci = DC390(dev);
- uint32_t val;
-
- val = pci_default_read_config(dev, addr, l);
-
- if (addr == 0x00 && l == 1) {
- /* First byte of address space is AND-ed with EEPROM DO line */
- if (!eeprom93xx_read(pci->eeprom)) {
- val &= ~0xff;
- }
- }
-
- return val;
-}
-
-static void dc390_write_config(PCIDevice *dev,
- uint32_t addr, uint32_t val, int l)
-{
- DC390State *pci = DC390(dev);
- if (addr == 0x80) {
- /* EEPROM write */
- int eesk = val & 0x80 ? 1 : 0;
- int eedi = val & 0x40 ? 1 : 0;
- eeprom93xx_write(pci->eeprom, 1, eesk, eedi);
- } else if (addr == 0xc0) {
- /* EEPROM CS low */
- eeprom93xx_write(pci->eeprom, 0, 0, 0);
- } else {
- pci_default_write_config(dev, addr, val, l);
- }
-}
-
-static void dc390_scsi_realize(PCIDevice *dev, Error **errp)
-{
- DC390State *pci = DC390(dev);
- Error *err = NULL;
- uint8_t *contents;
- uint16_t chksum = 0;
- int i;
-
- /* init base class */
- esp_pci_scsi_realize(dev, &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- /* EEPROM */
- pci->eeprom = eeprom93xx_new(DEVICE(dev), 64);
-
- /* set default eeprom values */
- contents = (uint8_t *)eeprom93xx_data(pci->eeprom);
-
- for (i = 0; i < 16; i++) {
- contents[i * 2] = 0x57;
- contents[i * 2 + 1] = 0x00;
- }
- contents[EE_ADAPT_SCSI_ID] = 7;
- contents[EE_MODE2] = 0x0f;
- contents[EE_TAG_CMD_NUM] = 0x04;
- contents[EE_ADAPT_OPTIONS] = EE_ADAPT_OPTION_F6_F8_AT_BOOT
- | EE_ADAPT_OPTION_BOOT_FROM_CDROM
- | EE_ADAPT_OPTION_INT13;
-
- /* update eeprom checksum */
- for (i = 0; i < EE_CHKSUM1; i += 2) {
- chksum += contents[i] + (((uint16_t)contents[i + 1]) << 8);
- }
- chksum = 0x1234 - chksum;
- contents[EE_CHKSUM1] = chksum & 0xff;
- contents[EE_CHKSUM2] = chksum >> 8;
-}
-
-static void dc390_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = dc390_scsi_realize;
- k->config_read = dc390_read_config;
- k->config_write = dc390_write_config;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
- dc->desc = "Tekram DC-390 SCSI adapter";
-}
-
-static const TypeInfo dc390_info = {
- .name = "dc390",
- .parent = TYPE_AM53C974_DEVICE,
- .instance_size = sizeof(DC390State),
- .class_init = dc390_class_init,
-};
-
-static void esp_pci_register_types(void)
-{
- type_register_static(&esp_pci_info);
- type_register_static(&dc390_info);
-}
-
-type_init(esp_pci_register_types)
diff --git a/qemu/hw/scsi/esp.c b/qemu/hw/scsi/esp.c
deleted file mode 100644
index 8961be2f3..000000000
--- a/qemu/hw/scsi/esp.c
+++ /dev/null
@@ -1,745 +0,0 @@
-/*
- * QEMU ESP/NCR53C9x emulation
- *
- * Copyright (c) 2005-2006 Fabrice Bellard
- * Copyright (c) 2012 Herve Poussineau
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "hw/scsi/esp.h"
-#include "trace.h"
-#include "qapi/error.h"
-#include "qemu/log.h"
-
-/*
- * On Sparc32, this is the ESP (NCR53C90) part of chip STP2000 (Master I/O),
- * also produced as NCR89C100. See
- * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt
- * and
- * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR53C9X.txt
- */
-
-static void esp_raise_irq(ESPState *s)
-{
- if (!(s->rregs[ESP_RSTAT] & STAT_INT)) {
- s->rregs[ESP_RSTAT] |= STAT_INT;
- qemu_irq_raise(s->irq);
- trace_esp_raise_irq();
- }
-}
-
-static void esp_lower_irq(ESPState *s)
-{
- if (s->rregs[ESP_RSTAT] & STAT_INT) {
- s->rregs[ESP_RSTAT] &= ~STAT_INT;
- qemu_irq_lower(s->irq);
- trace_esp_lower_irq();
- }
-}
-
-void esp_dma_enable(ESPState *s, int irq, int level)
-{
- if (level) {
- s->dma_enabled = 1;
- trace_esp_dma_enable();
- if (s->dma_cb) {
- s->dma_cb(s);
- s->dma_cb = NULL;
- }
- } else {
- trace_esp_dma_disable();
- s->dma_enabled = 0;
- }
-}
-
-void esp_request_cancelled(SCSIRequest *req)
-{
- ESPState *s = req->hba_private;
-
- if (req == s->current_req) {
- scsi_req_unref(s->current_req);
- s->current_req = NULL;
- s->current_dev = NULL;
- }
-}
-
-static uint32_t get_cmd(ESPState *s, uint8_t *buf)
-{
- uint32_t dmalen;
- int target;
-
- target = s->wregs[ESP_WBUSID] & BUSID_DID;
- if (s->dma) {
- dmalen = s->rregs[ESP_TCLO];
- dmalen |= s->rregs[ESP_TCMID] << 8;
- dmalen |= s->rregs[ESP_TCHI] << 16;
- s->dma_memory_read(s->dma_opaque, buf, dmalen);
- } else {
- dmalen = s->ti_size;
- memcpy(buf, s->ti_buf, dmalen);
- buf[0] = buf[2] >> 5;
- }
- trace_esp_get_cmd(dmalen, target);
-
- s->ti_size = 0;
- s->ti_rptr = 0;
- s->ti_wptr = 0;
-
- if (s->current_req) {
- /* Started a new command before the old one finished. Cancel it. */
- scsi_req_cancel(s->current_req);
- s->async_len = 0;
- }
-
- s->current_dev = scsi_device_find(&s->bus, 0, target, 0);
- if (!s->current_dev) {
- // No such drive
- s->rregs[ESP_RSTAT] = 0;
- s->rregs[ESP_RINTR] = INTR_DC;
- s->rregs[ESP_RSEQ] = SEQ_0;
- esp_raise_irq(s);
- return 0;
- }
- return dmalen;
-}
-
-static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)
-{
- int32_t datalen;
- int lun;
- SCSIDevice *current_lun;
-
- trace_esp_do_busid_cmd(busid);
- lun = busid & 7;
- current_lun = scsi_device_find(&s->bus, 0, s->current_dev->id, lun);
- s->current_req = scsi_req_new(current_lun, 0, lun, buf, s);
- datalen = scsi_req_enqueue(s->current_req);
- s->ti_size = datalen;
- if (datalen != 0) {
- s->rregs[ESP_RSTAT] = STAT_TC;
- s->dma_left = 0;
- s->dma_counter = 0;
- if (datalen > 0) {
- s->rregs[ESP_RSTAT] |= STAT_DI;
- } else {
- s->rregs[ESP_RSTAT] |= STAT_DO;
- }
- scsi_req_continue(s->current_req);
- }
- s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
- s->rregs[ESP_RSEQ] = SEQ_CD;
- esp_raise_irq(s);
-}
-
-static void do_cmd(ESPState *s, uint8_t *buf)
-{
- uint8_t busid = buf[0];
-
- do_busid_cmd(s, &buf[1], busid);
-}
-
-static void handle_satn(ESPState *s)
-{
- uint8_t buf[32];
- int len;
-
- if (s->dma && !s->dma_enabled) {
- s->dma_cb = handle_satn;
- return;
- }
- len = get_cmd(s, buf);
- if (len)
- do_cmd(s, buf);
-}
-
-static void handle_s_without_atn(ESPState *s)
-{
- uint8_t buf[32];
- int len;
-
- if (s->dma && !s->dma_enabled) {
- s->dma_cb = handle_s_without_atn;
- return;
- }
- len = get_cmd(s, buf);
- if (len) {
- do_busid_cmd(s, buf, 0);
- }
-}
-
-static void handle_satn_stop(ESPState *s)
-{
- if (s->dma && !s->dma_enabled) {
- s->dma_cb = handle_satn_stop;
- return;
- }
- s->cmdlen = get_cmd(s, s->cmdbuf);
- if (s->cmdlen) {
- trace_esp_handle_satn_stop(s->cmdlen);
- s->do_cmd = 1;
- s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD;
- s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
- s->rregs[ESP_RSEQ] = SEQ_CD;
- esp_raise_irq(s);
- }
-}
-
-static void write_response(ESPState *s)
-{
- trace_esp_write_response(s->status);
- s->ti_buf[0] = s->status;
- s->ti_buf[1] = 0;
- if (s->dma) {
- s->dma_memory_write(s->dma_opaque, s->ti_buf, 2);
- s->rregs[ESP_RSTAT] = STAT_TC | STAT_ST;
- s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
- s->rregs[ESP_RSEQ] = SEQ_CD;
- } else {
- s->ti_size = 2;
- s->ti_rptr = 0;
- s->ti_wptr = 0;
- s->rregs[ESP_RFLAGS] = 2;
- }
- esp_raise_irq(s);
-}
-
-static void esp_dma_done(ESPState *s)
-{
- s->rregs[ESP_RSTAT] |= STAT_TC;
- s->rregs[ESP_RINTR] = INTR_BS;
- s->rregs[ESP_RSEQ] = 0;
- s->rregs[ESP_RFLAGS] = 0;
- s->rregs[ESP_TCLO] = 0;
- s->rregs[ESP_TCMID] = 0;
- s->rregs[ESP_TCHI] = 0;
- esp_raise_irq(s);
-}
-
-static void esp_do_dma(ESPState *s)
-{
- uint32_t len;
- int to_device;
-
- to_device = (s->ti_size < 0);
- len = s->dma_left;
- if (s->do_cmd) {
- trace_esp_do_dma(s->cmdlen, len);
- s->dma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len);
- s->ti_size = 0;
- s->cmdlen = 0;
- s->do_cmd = 0;
- do_cmd(s, s->cmdbuf);
- return;
- }
- if (s->async_len == 0) {
- /* Defer until data is available. */
- return;
- }
- if (len > s->async_len) {
- len = s->async_len;
- }
- if (to_device) {
- s->dma_memory_read(s->dma_opaque, s->async_buf, len);
- } else {
- s->dma_memory_write(s->dma_opaque, s->async_buf, len);
- }
- s->dma_left -= len;
- s->async_buf += len;
- s->async_len -= len;
- if (to_device)
- s->ti_size += len;
- else
- s->ti_size -= len;
- if (s->async_len == 0) {
- scsi_req_continue(s->current_req);
- /* If there is still data to be read from the device then
- complete the DMA operation immediately. Otherwise defer
- until the scsi layer has completed. */
- if (to_device || s->dma_left != 0 || s->ti_size == 0) {
- return;
- }
- }
-
- /* Partially filled a scsi buffer. Complete immediately. */
- esp_dma_done(s);
-}
-
-void esp_command_complete(SCSIRequest *req, uint32_t status,
- size_t resid)
-{
- ESPState *s = req->hba_private;
-
- trace_esp_command_complete();
- if (s->ti_size != 0) {
- trace_esp_command_complete_unexpected();
- }
- s->ti_size = 0;
- s->dma_left = 0;
- s->async_len = 0;
- if (status) {
- trace_esp_command_complete_fail();
- }
- s->status = status;
- s->rregs[ESP_RSTAT] = STAT_ST;
- esp_dma_done(s);
- if (s->current_req) {
- scsi_req_unref(s->current_req);
- s->current_req = NULL;
- s->current_dev = NULL;
- }
-}
-
-void esp_transfer_data(SCSIRequest *req, uint32_t len)
-{
- ESPState *s = req->hba_private;
-
- trace_esp_transfer_data(s->dma_left, s->ti_size);
- s->async_len = len;
- s->async_buf = scsi_req_get_buf(req);
- if (s->dma_left) {
- esp_do_dma(s);
- } else if (s->dma_counter != 0 && s->ti_size <= 0) {
- /* If this was the last part of a DMA transfer then the
- completion interrupt is deferred to here. */
- esp_dma_done(s);
- }
-}
-
-static void handle_ti(ESPState *s)
-{
- uint32_t dmalen, minlen;
-
- if (s->dma && !s->dma_enabled) {
- s->dma_cb = handle_ti;
- return;
- }
-
- dmalen = s->rregs[ESP_TCLO];
- dmalen |= s->rregs[ESP_TCMID] << 8;
- dmalen |= s->rregs[ESP_TCHI] << 16;
- if (dmalen==0) {
- dmalen=0x10000;
- }
- s->dma_counter = dmalen;
-
- if (s->do_cmd)
- minlen = (dmalen < 32) ? dmalen : 32;
- else if (s->ti_size < 0)
- minlen = (dmalen < -s->ti_size) ? dmalen : -s->ti_size;
- else
- minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size;
- trace_esp_handle_ti(minlen);
- if (s->dma) {
- s->dma_left = minlen;
- s->rregs[ESP_RSTAT] &= ~STAT_TC;
- esp_do_dma(s);
- } else if (s->do_cmd) {
- trace_esp_handle_ti_cmd(s->cmdlen);
- s->ti_size = 0;
- s->cmdlen = 0;
- s->do_cmd = 0;
- do_cmd(s, s->cmdbuf);
- return;
- }
-}
-
-void esp_hard_reset(ESPState *s)
-{
- memset(s->rregs, 0, ESP_REGS);
- memset(s->wregs, 0, ESP_REGS);
- s->tchi_written = 0;
- s->ti_size = 0;
- s->ti_rptr = 0;
- s->ti_wptr = 0;
- s->dma = 0;
- s->do_cmd = 0;
- s->dma_cb = NULL;
-
- s->rregs[ESP_CFG1] = 7;
-}
-
-static void esp_soft_reset(ESPState *s)
-{
- qemu_irq_lower(s->irq);
- esp_hard_reset(s);
-}
-
-static void parent_esp_reset(ESPState *s, int irq, int level)
-{
- if (level) {
- esp_soft_reset(s);
- }
-}
-
-uint64_t esp_reg_read(ESPState *s, uint32_t saddr)
-{
- uint32_t old_val;
-
- trace_esp_mem_readb(saddr, s->rregs[saddr]);
- switch (saddr) {
- case ESP_FIFO:
- if (s->ti_size > 0) {
- s->ti_size--;
- if ((s->rregs[ESP_RSTAT] & STAT_PIO_MASK) == 0) {
- /* Data out. */
- qemu_log_mask(LOG_UNIMP,
- "esp: PIO data read not implemented\n");
- s->rregs[ESP_FIFO] = 0;
- } else {
- s->rregs[ESP_FIFO] = s->ti_buf[s->ti_rptr++];
- }
- esp_raise_irq(s);
- }
- if (s->ti_size == 0) {
- s->ti_rptr = 0;
- s->ti_wptr = 0;
- }
- break;
- case ESP_RINTR:
- /* Clear sequence step, interrupt register and all status bits
- except TC */
- old_val = s->rregs[ESP_RINTR];
- s->rregs[ESP_RINTR] = 0;
- s->rregs[ESP_RSTAT] &= ~STAT_TC;
- s->rregs[ESP_RSEQ] = SEQ_CD;
- esp_lower_irq(s);
-
- return old_val;
- case ESP_TCHI:
- /* Return the unique id if the value has never been written */
- if (!s->tchi_written) {
- return s->chip_id;
- }
- default:
- break;
- }
- return s->rregs[saddr];
-}
-
-void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
-{
- trace_esp_mem_writeb(saddr, s->wregs[saddr], val);
- switch (saddr) {
- case ESP_TCHI:
- s->tchi_written = true;
- /* fall through */
- case ESP_TCLO:
- case ESP_TCMID:
- s->rregs[ESP_RSTAT] &= ~STAT_TC;
- break;
- case ESP_FIFO:
- if (s->do_cmd) {
- s->cmdbuf[s->cmdlen++] = val & 0xff;
- } else if (s->ti_size == TI_BUFSZ - 1) {
- trace_esp_error_fifo_overrun();
- } else {
- s->ti_size++;
- s->ti_buf[s->ti_wptr++] = val & 0xff;
- }
- break;
- case ESP_CMD:
- s->rregs[saddr] = val;
- if (val & CMD_DMA) {
- s->dma = 1;
- /* Reload DMA counter. */
- s->rregs[ESP_TCLO] = s->wregs[ESP_TCLO];
- s->rregs[ESP_TCMID] = s->wregs[ESP_TCMID];
- s->rregs[ESP_TCHI] = s->wregs[ESP_TCHI];
- } else {
- s->dma = 0;
- }
- switch(val & CMD_CMD) {
- case CMD_NOP:
- trace_esp_mem_writeb_cmd_nop(val);
- break;
- case CMD_FLUSH:
- trace_esp_mem_writeb_cmd_flush(val);
- //s->ti_size = 0;
- s->rregs[ESP_RINTR] = INTR_FC;
- s->rregs[ESP_RSEQ] = 0;
- s->rregs[ESP_RFLAGS] = 0;
- break;
- case CMD_RESET:
- trace_esp_mem_writeb_cmd_reset(val);
- esp_soft_reset(s);
- break;
- case CMD_BUSRESET:
- trace_esp_mem_writeb_cmd_bus_reset(val);
- s->rregs[ESP_RINTR] = INTR_RST;
- if (!(s->wregs[ESP_CFG1] & CFG1_RESREPT)) {
- esp_raise_irq(s);
- }
- break;
- case CMD_TI:
- handle_ti(s);
- break;
- case CMD_ICCS:
- trace_esp_mem_writeb_cmd_iccs(val);
- write_response(s);
- s->rregs[ESP_RINTR] = INTR_FC;
- s->rregs[ESP_RSTAT] |= STAT_MI;
- break;
- case CMD_MSGACC:
- trace_esp_mem_writeb_cmd_msgacc(val);
- s->rregs[ESP_RINTR] = INTR_DC;
- s->rregs[ESP_RSEQ] = 0;
- s->rregs[ESP_RFLAGS] = 0;
- esp_raise_irq(s);
- break;
- case CMD_PAD:
- trace_esp_mem_writeb_cmd_pad(val);
- s->rregs[ESP_RSTAT] = STAT_TC;
- s->rregs[ESP_RINTR] = INTR_FC;
- s->rregs[ESP_RSEQ] = 0;
- break;
- case CMD_SATN:
- trace_esp_mem_writeb_cmd_satn(val);
- break;
- case CMD_RSTATN:
- trace_esp_mem_writeb_cmd_rstatn(val);
- break;
- case CMD_SEL:
- trace_esp_mem_writeb_cmd_sel(val);
- handle_s_without_atn(s);
- break;
- case CMD_SELATN:
- trace_esp_mem_writeb_cmd_selatn(val);
- handle_satn(s);
- break;
- case CMD_SELATNS:
- trace_esp_mem_writeb_cmd_selatns(val);
- handle_satn_stop(s);
- break;
- case CMD_ENSEL:
- trace_esp_mem_writeb_cmd_ensel(val);
- s->rregs[ESP_RINTR] = 0;
- break;
- case CMD_DISSEL:
- trace_esp_mem_writeb_cmd_dissel(val);
- s->rregs[ESP_RINTR] = 0;
- esp_raise_irq(s);
- break;
- default:
- trace_esp_error_unhandled_command(val);
- break;
- }
- break;
- case ESP_WBUSID ... ESP_WSYNO:
- break;
- case ESP_CFG1:
- case ESP_CFG2: case ESP_CFG3:
- case ESP_RES3: case ESP_RES4:
- s->rregs[saddr] = val;
- break;
- case ESP_WCCF ... ESP_WTEST:
- break;
- default:
- trace_esp_error_invalid_write(val, saddr);
- return;
- }
- s->wregs[saddr] = val;
-}
-
-static bool esp_mem_accepts(void *opaque, hwaddr addr,
- unsigned size, bool is_write)
-{
- return (size == 1) || (is_write && size == 4);
-}
-
-const VMStateDescription vmstate_esp = {
- .name ="esp",
- .version_id = 3,
- .minimum_version_id = 3,
- .fields = (VMStateField[]) {
- VMSTATE_BUFFER(rregs, ESPState),
- VMSTATE_BUFFER(wregs, ESPState),
- VMSTATE_INT32(ti_size, ESPState),
- VMSTATE_UINT32(ti_rptr, ESPState),
- VMSTATE_UINT32(ti_wptr, ESPState),
- VMSTATE_BUFFER(ti_buf, ESPState),
- VMSTATE_UINT32(status, ESPState),
- VMSTATE_UINT32(dma, ESPState),
- VMSTATE_BUFFER(cmdbuf, ESPState),
- VMSTATE_UINT32(cmdlen, ESPState),
- VMSTATE_UINT32(do_cmd, ESPState),
- VMSTATE_UINT32(dma_left, ESPState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-#define TYPE_ESP "esp"
-#define ESP(obj) OBJECT_CHECK(SysBusESPState, (obj), TYPE_ESP)
-
-typedef struct {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- MemoryRegion iomem;
- uint32_t it_shift;
- ESPState esp;
-} SysBusESPState;
-
-static void sysbus_esp_mem_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned int size)
-{
- SysBusESPState *sysbus = opaque;
- uint32_t saddr;
-
- saddr = addr >> sysbus->it_shift;
- esp_reg_write(&sysbus->esp, saddr, val);
-}
-
-static uint64_t sysbus_esp_mem_read(void *opaque, hwaddr addr,
- unsigned int size)
-{
- SysBusESPState *sysbus = opaque;
- uint32_t saddr;
-
- saddr = addr >> sysbus->it_shift;
- return esp_reg_read(&sysbus->esp, saddr);
-}
-
-static const MemoryRegionOps sysbus_esp_mem_ops = {
- .read = sysbus_esp_mem_read,
- .write = sysbus_esp_mem_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid.accepts = esp_mem_accepts,
-};
-
-void esp_init(hwaddr espaddr, int it_shift,
- ESPDMAMemoryReadWriteFunc dma_memory_read,
- ESPDMAMemoryReadWriteFunc dma_memory_write,
- void *dma_opaque, qemu_irq irq, qemu_irq *reset,
- qemu_irq *dma_enable)
-{
- DeviceState *dev;
- SysBusDevice *s;
- SysBusESPState *sysbus;
- ESPState *esp;
-
- dev = qdev_create(NULL, TYPE_ESP);
- sysbus = ESP(dev);
- esp = &sysbus->esp;
- esp->dma_memory_read = dma_memory_read;
- esp->dma_memory_write = dma_memory_write;
- esp->dma_opaque = dma_opaque;
- sysbus->it_shift = it_shift;
- /* XXX for now until rc4030 has been changed to use DMA enable signal */
- esp->dma_enabled = 1;
- qdev_init_nofail(dev);
- s = SYS_BUS_DEVICE(dev);
- sysbus_connect_irq(s, 0, irq);
- sysbus_mmio_map(s, 0, espaddr);
- *reset = qdev_get_gpio_in(dev, 0);
- *dma_enable = qdev_get_gpio_in(dev, 1);
-}
-
-static const struct SCSIBusInfo esp_scsi_info = {
- .tcq = false,
- .max_target = ESP_MAX_DEVS,
- .max_lun = 7,
-
- .transfer_data = esp_transfer_data,
- .complete = esp_command_complete,
- .cancel = esp_request_cancelled
-};
-
-static void sysbus_esp_gpio_demux(void *opaque, int irq, int level)
-{
- SysBusESPState *sysbus = ESP(opaque);
- ESPState *s = &sysbus->esp;
-
- switch (irq) {
- case 0:
- parent_esp_reset(s, irq, level);
- break;
- case 1:
- esp_dma_enable(opaque, irq, level);
- break;
- }
-}
-
-static void sysbus_esp_realize(DeviceState *dev, Error **errp)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- SysBusESPState *sysbus = ESP(dev);
- ESPState *s = &sysbus->esp;
- Error *err = NULL;
-
- sysbus_init_irq(sbd, &s->irq);
- assert(sysbus->it_shift != -1);
-
- s->chip_id = TCHI_FAS100A;
- memory_region_init_io(&sysbus->iomem, OBJECT(sysbus), &sysbus_esp_mem_ops,
- sysbus, "esp", ESP_REGS << sysbus->it_shift);
- sysbus_init_mmio(sbd, &sysbus->iomem);
-
- qdev_init_gpio_in(dev, sysbus_esp_gpio_demux, 2);
-
- scsi_bus_new(&s->bus, sizeof(s->bus), dev, &esp_scsi_info, NULL);
- scsi_bus_legacy_handle_cmdline(&s->bus, &err);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
-}
-
-static void sysbus_esp_hard_reset(DeviceState *dev)
-{
- SysBusESPState *sysbus = ESP(dev);
- esp_hard_reset(&sysbus->esp);
-}
-
-static const VMStateDescription vmstate_sysbus_esp_scsi = {
- .name = "sysbusespscsi",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT(esp, SysBusESPState, 0, vmstate_esp, ESPState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void sysbus_esp_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = sysbus_esp_realize;
- dc->reset = sysbus_esp_hard_reset;
- dc->vmsd = &vmstate_sysbus_esp_scsi;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
-}
-
-static const TypeInfo sysbus_esp_info = {
- .name = TYPE_ESP,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(SysBusESPState),
- .class_init = sysbus_esp_class_init,
-};
-
-static void esp_register_types(void)
-{
- type_register_static(&sysbus_esp_info);
-}
-
-type_init(esp_register_types)
diff --git a/qemu/hw/scsi/lsi53c895a.c b/qemu/hw/scsi/lsi53c895a.c
deleted file mode 100644
index df205cdaf..000000000
--- a/qemu/hw/scsi/lsi53c895a.c
+++ /dev/null
@@ -1,2163 +0,0 @@
-/*
- * QEMU LSI53C895A SCSI Host Bus Adapter emulation
- *
- * Copyright (c) 2006 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the LGPL.
- */
-
-/* Note:
- * LSI53C810 emulation is incorrect, in the sense that it supports
- * features added in later evolutions. This should not be a problem,
- * as well-behaved operating systems will not try to use them.
- */
-
-#include "qemu/osdep.h"
-
-#include "hw/hw.h"
-#include "hw/pci/pci.h"
-#include "hw/scsi/scsi.h"
-#include "sysemu/dma.h"
-
-//#define DEBUG_LSI
-//#define DEBUG_LSI_REG
-
-#ifdef DEBUG_LSI
-#define DPRINTF(fmt, ...) \
-do { printf("lsi_scsi: " fmt , ## __VA_ARGS__); } while (0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "lsi_scsi: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "lsi_scsi: error: " fmt , ## __VA_ARGS__);} while (0)
-#endif
-
-#define LSI_MAX_DEVS 7
-
-#define LSI_SCNTL0_TRG 0x01
-#define LSI_SCNTL0_AAP 0x02
-#define LSI_SCNTL0_EPC 0x08
-#define LSI_SCNTL0_WATN 0x10
-#define LSI_SCNTL0_START 0x20
-
-#define LSI_SCNTL1_SST 0x01
-#define LSI_SCNTL1_IARB 0x02
-#define LSI_SCNTL1_AESP 0x04
-#define LSI_SCNTL1_RST 0x08
-#define LSI_SCNTL1_CON 0x10
-#define LSI_SCNTL1_DHP 0x20
-#define LSI_SCNTL1_ADB 0x40
-#define LSI_SCNTL1_EXC 0x80
-
-#define LSI_SCNTL2_WSR 0x01
-#define LSI_SCNTL2_VUE0 0x02
-#define LSI_SCNTL2_VUE1 0x04
-#define LSI_SCNTL2_WSS 0x08
-#define LSI_SCNTL2_SLPHBEN 0x10
-#define LSI_SCNTL2_SLPMD 0x20
-#define LSI_SCNTL2_CHM 0x40
-#define LSI_SCNTL2_SDU 0x80
-
-#define LSI_ISTAT0_DIP 0x01
-#define LSI_ISTAT0_SIP 0x02
-#define LSI_ISTAT0_INTF 0x04
-#define LSI_ISTAT0_CON 0x08
-#define LSI_ISTAT0_SEM 0x10
-#define LSI_ISTAT0_SIGP 0x20
-#define LSI_ISTAT0_SRST 0x40
-#define LSI_ISTAT0_ABRT 0x80
-
-#define LSI_ISTAT1_SI 0x01
-#define LSI_ISTAT1_SRUN 0x02
-#define LSI_ISTAT1_FLSH 0x04
-
-#define LSI_SSTAT0_SDP0 0x01
-#define LSI_SSTAT0_RST 0x02
-#define LSI_SSTAT0_WOA 0x04
-#define LSI_SSTAT0_LOA 0x08
-#define LSI_SSTAT0_AIP 0x10
-#define LSI_SSTAT0_OLF 0x20
-#define LSI_SSTAT0_ORF 0x40
-#define LSI_SSTAT0_ILF 0x80
-
-#define LSI_SIST0_PAR 0x01
-#define LSI_SIST0_RST 0x02
-#define LSI_SIST0_UDC 0x04
-#define LSI_SIST0_SGE 0x08
-#define LSI_SIST0_RSL 0x10
-#define LSI_SIST0_SEL 0x20
-#define LSI_SIST0_CMP 0x40
-#define LSI_SIST0_MA 0x80
-
-#define LSI_SIST1_HTH 0x01
-#define LSI_SIST1_GEN 0x02
-#define LSI_SIST1_STO 0x04
-#define LSI_SIST1_SBMC 0x10
-
-#define LSI_SOCL_IO 0x01
-#define LSI_SOCL_CD 0x02
-#define LSI_SOCL_MSG 0x04
-#define LSI_SOCL_ATN 0x08
-#define LSI_SOCL_SEL 0x10
-#define LSI_SOCL_BSY 0x20
-#define LSI_SOCL_ACK 0x40
-#define LSI_SOCL_REQ 0x80
-
-#define LSI_DSTAT_IID 0x01
-#define LSI_DSTAT_SIR 0x04
-#define LSI_DSTAT_SSI 0x08
-#define LSI_DSTAT_ABRT 0x10
-#define LSI_DSTAT_BF 0x20
-#define LSI_DSTAT_MDPE 0x40
-#define LSI_DSTAT_DFE 0x80
-
-#define LSI_DCNTL_COM 0x01
-#define LSI_DCNTL_IRQD 0x02
-#define LSI_DCNTL_STD 0x04
-#define LSI_DCNTL_IRQM 0x08
-#define LSI_DCNTL_SSM 0x10
-#define LSI_DCNTL_PFEN 0x20
-#define LSI_DCNTL_PFF 0x40
-#define LSI_DCNTL_CLSE 0x80
-
-#define LSI_DMODE_MAN 0x01
-#define LSI_DMODE_BOF 0x02
-#define LSI_DMODE_ERMP 0x04
-#define LSI_DMODE_ERL 0x08
-#define LSI_DMODE_DIOM 0x10
-#define LSI_DMODE_SIOM 0x20
-
-#define LSI_CTEST2_DACK 0x01
-#define LSI_CTEST2_DREQ 0x02
-#define LSI_CTEST2_TEOP 0x04
-#define LSI_CTEST2_PCICIE 0x08
-#define LSI_CTEST2_CM 0x10
-#define LSI_CTEST2_CIO 0x20
-#define LSI_CTEST2_SIGP 0x40
-#define LSI_CTEST2_DDIR 0x80
-
-#define LSI_CTEST5_BL2 0x04
-#define LSI_CTEST5_DDIR 0x08
-#define LSI_CTEST5_MASR 0x10
-#define LSI_CTEST5_DFSN 0x20
-#define LSI_CTEST5_BBCK 0x40
-#define LSI_CTEST5_ADCK 0x80
-
-#define LSI_CCNTL0_DILS 0x01
-#define LSI_CCNTL0_DISFC 0x10
-#define LSI_CCNTL0_ENNDJ 0x20
-#define LSI_CCNTL0_PMJCTL 0x40
-#define LSI_CCNTL0_ENPMJ 0x80
-
-#define LSI_CCNTL1_EN64DBMV 0x01
-#define LSI_CCNTL1_EN64TIBMV 0x02
-#define LSI_CCNTL1_64TIMOD 0x04
-#define LSI_CCNTL1_DDAC 0x08
-#define LSI_CCNTL1_ZMOD 0x80
-
-/* Enable Response to Reselection */
-#define LSI_SCID_RRE 0x60
-
-#define LSI_CCNTL1_40BIT (LSI_CCNTL1_EN64TIBMV|LSI_CCNTL1_64TIMOD)
-
-#define PHASE_DO 0
-#define PHASE_DI 1
-#define PHASE_CMD 2
-#define PHASE_ST 3
-#define PHASE_MO 6
-#define PHASE_MI 7
-#define PHASE_MASK 7
-
-/* Maximum length of MSG IN data. */
-#define LSI_MAX_MSGIN_LEN 8
-
-/* Flag set if this is a tagged command. */
-#define LSI_TAG_VALID (1 << 16)
-
-typedef struct lsi_request {
- SCSIRequest *req;
- uint32_t tag;
- uint32_t dma_len;
- uint8_t *dma_buf;
- uint32_t pending;
- int out;
- QTAILQ_ENTRY(lsi_request) next;
-} lsi_request;
-
-typedef struct {
- /*< private >*/
- PCIDevice parent_obj;
- /*< public >*/
-
- MemoryRegion mmio_io;
- MemoryRegion ram_io;
- MemoryRegion io_io;
-
- int carry; /* ??? Should this be an a visible register somewhere? */
- int status;
- /* Action to take at the end of a MSG IN phase.
- 0 = COMMAND, 1 = disconnect, 2 = DATA OUT, 3 = DATA IN. */
- int msg_action;
- int msg_len;
- uint8_t msg[LSI_MAX_MSGIN_LEN];
- /* 0 if SCRIPTS are running or stopped.
- * 1 if a Wait Reselect instruction has been issued.
- * 2 if processing DMA from lsi_execute_script.
- * 3 if a DMA operation is in progress. */
- int waiting;
- SCSIBus bus;
- int current_lun;
- /* The tag is a combination of the device ID and the SCSI tag. */
- uint32_t select_tag;
- int command_complete;
- QTAILQ_HEAD(, lsi_request) queue;
- lsi_request *current;
-
- uint32_t dsa;
- uint32_t temp;
- uint32_t dnad;
- uint32_t dbc;
- uint8_t istat0;
- uint8_t istat1;
- uint8_t dcmd;
- uint8_t dstat;
- uint8_t dien;
- uint8_t sist0;
- uint8_t sist1;
- uint8_t sien0;
- uint8_t sien1;
- uint8_t mbox0;
- uint8_t mbox1;
- uint8_t dfifo;
- uint8_t ctest2;
- uint8_t ctest3;
- uint8_t ctest4;
- uint8_t ctest5;
- uint8_t ccntl0;
- uint8_t ccntl1;
- uint32_t dsp;
- uint32_t dsps;
- uint8_t dmode;
- uint8_t dcntl;
- uint8_t scntl0;
- uint8_t scntl1;
- uint8_t scntl2;
- uint8_t scntl3;
- uint8_t sstat0;
- uint8_t sstat1;
- uint8_t scid;
- uint8_t sxfer;
- uint8_t socl;
- uint8_t sdid;
- uint8_t ssid;
- uint8_t sfbr;
- uint8_t stest1;
- uint8_t stest2;
- uint8_t stest3;
- uint8_t sidl;
- uint8_t stime0;
- uint8_t respid0;
- uint8_t respid1;
- uint32_t mmrs;
- uint32_t mmws;
- uint32_t sfs;
- uint32_t drs;
- uint32_t sbms;
- uint32_t dbms;
- uint32_t dnad64;
- uint32_t pmjad1;
- uint32_t pmjad2;
- uint32_t rbc;
- uint32_t ua;
- uint32_t ia;
- uint32_t sbc;
- uint32_t csbc;
- uint32_t scratch[18]; /* SCRATCHA-SCRATCHR */
- uint8_t sbr;
- uint32_t adder;
-
- /* Script ram is stored as 32-bit words in host byteorder. */
- uint32_t script_ram[2048];
-} LSIState;
-
-#define TYPE_LSI53C810 "lsi53c810"
-#define TYPE_LSI53C895A "lsi53c895a"
-
-#define LSI53C895A(obj) \
- OBJECT_CHECK(LSIState, (obj), TYPE_LSI53C895A)
-
-static inline int lsi_irq_on_rsl(LSIState *s)
-{
- return (s->sien0 & LSI_SIST0_RSL) && (s->scid & LSI_SCID_RRE);
-}
-
-static void lsi_soft_reset(LSIState *s)
-{
- DPRINTF("Reset\n");
- s->carry = 0;
-
- s->msg_action = 0;
- s->msg_len = 0;
- s->waiting = 0;
- s->dsa = 0;
- s->dnad = 0;
- s->dbc = 0;
- s->temp = 0;
- memset(s->scratch, 0, sizeof(s->scratch));
- s->istat0 = 0;
- s->istat1 = 0;
- s->dcmd = 0x40;
- s->dstat = LSI_DSTAT_DFE;
- s->dien = 0;
- s->sist0 = 0;
- s->sist1 = 0;
- s->sien0 = 0;
- s->sien1 = 0;
- s->mbox0 = 0;
- s->mbox1 = 0;
- s->dfifo = 0;
- s->ctest2 = LSI_CTEST2_DACK;
- s->ctest3 = 0;
- s->ctest4 = 0;
- s->ctest5 = 0;
- s->ccntl0 = 0;
- s->ccntl1 = 0;
- s->dsp = 0;
- s->dsps = 0;
- s->dmode = 0;
- s->dcntl = 0;
- s->scntl0 = 0xc0;
- s->scntl1 = 0;
- s->scntl2 = 0;
- s->scntl3 = 0;
- s->sstat0 = 0;
- s->sstat1 = 0;
- s->scid = 7;
- s->sxfer = 0;
- s->socl = 0;
- s->sdid = 0;
- s->ssid = 0;
- s->stest1 = 0;
- s->stest2 = 0;
- s->stest3 = 0;
- s->sidl = 0;
- s->stime0 = 0;
- s->respid0 = 0x80;
- s->respid1 = 0;
- s->mmrs = 0;
- s->mmws = 0;
- s->sfs = 0;
- s->drs = 0;
- s->sbms = 0;
- s->dbms = 0;
- s->dnad64 = 0;
- s->pmjad1 = 0;
- s->pmjad2 = 0;
- s->rbc = 0;
- s->ua = 0;
- s->ia = 0;
- s->sbc = 0;
- s->csbc = 0;
- s->sbr = 0;
- assert(QTAILQ_EMPTY(&s->queue));
- assert(!s->current);
-}
-
-static int lsi_dma_40bit(LSIState *s)
-{
- if ((s->ccntl1 & LSI_CCNTL1_40BIT) == LSI_CCNTL1_40BIT)
- return 1;
- return 0;
-}
-
-static int lsi_dma_ti64bit(LSIState *s)
-{
- if ((s->ccntl1 & LSI_CCNTL1_EN64TIBMV) == LSI_CCNTL1_EN64TIBMV)
- return 1;
- return 0;
-}
-
-static int lsi_dma_64bit(LSIState *s)
-{
- if ((s->ccntl1 & LSI_CCNTL1_EN64DBMV) == LSI_CCNTL1_EN64DBMV)
- return 1;
- return 0;
-}
-
-static uint8_t lsi_reg_readb(LSIState *s, int offset);
-static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val);
-static void lsi_execute_script(LSIState *s);
-static void lsi_reselect(LSIState *s, lsi_request *p);
-
-static inline uint32_t read_dword(LSIState *s, uint32_t addr)
-{
- uint32_t buf;
-
- pci_dma_read(PCI_DEVICE(s), addr, &buf, 4);
- return cpu_to_le32(buf);
-}
-
-static void lsi_stop_script(LSIState *s)
-{
- s->istat1 &= ~LSI_ISTAT1_SRUN;
-}
-
-static void lsi_update_irq(LSIState *s)
-{
- PCIDevice *d = PCI_DEVICE(s);
- int level;
- static int last_level;
- lsi_request *p;
-
- /* It's unclear whether the DIP/SIP bits should be cleared when the
- Interrupt Status Registers are cleared or when istat0 is read.
- We currently do the formwer, which seems to work. */
- level = 0;
- if (s->dstat) {
- if (s->dstat & s->dien)
- level = 1;
- s->istat0 |= LSI_ISTAT0_DIP;
- } else {
- s->istat0 &= ~LSI_ISTAT0_DIP;
- }
-
- if (s->sist0 || s->sist1) {
- if ((s->sist0 & s->sien0) || (s->sist1 & s->sien1))
- level = 1;
- s->istat0 |= LSI_ISTAT0_SIP;
- } else {
- s->istat0 &= ~LSI_ISTAT0_SIP;
- }
- if (s->istat0 & LSI_ISTAT0_INTF)
- level = 1;
-
- if (level != last_level) {
- DPRINTF("Update IRQ level %d dstat %02x sist %02x%02x\n",
- level, s->dstat, s->sist1, s->sist0);
- last_level = level;
- }
- pci_set_irq(d, level);
-
- if (!level && lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON)) {
- DPRINTF("Handled IRQs & disconnected, looking for pending "
- "processes\n");
- QTAILQ_FOREACH(p, &s->queue, next) {
- if (p->pending) {
- lsi_reselect(s, p);
- break;
- }
- }
- }
-}
-
-/* Stop SCRIPTS execution and raise a SCSI interrupt. */
-static void lsi_script_scsi_interrupt(LSIState *s, int stat0, int stat1)
-{
- uint32_t mask0;
- uint32_t mask1;
-
- DPRINTF("SCSI Interrupt 0x%02x%02x prev 0x%02x%02x\n",
- stat1, stat0, s->sist1, s->sist0);
- s->sist0 |= stat0;
- s->sist1 |= stat1;
- /* Stop processor on fatal or unmasked interrupt. As a special hack
- we don't stop processing when raising STO. Instead continue
- execution and stop at the next insn that accesses the SCSI bus. */
- mask0 = s->sien0 | ~(LSI_SIST0_CMP | LSI_SIST0_SEL | LSI_SIST0_RSL);
- mask1 = s->sien1 | ~(LSI_SIST1_GEN | LSI_SIST1_HTH);
- mask1 &= ~LSI_SIST1_STO;
- if (s->sist0 & mask0 || s->sist1 & mask1) {
- lsi_stop_script(s);
- }
- lsi_update_irq(s);
-}
-
-/* Stop SCRIPTS execution and raise a DMA interrupt. */
-static void lsi_script_dma_interrupt(LSIState *s, int stat)
-{
- DPRINTF("DMA Interrupt 0x%x prev 0x%x\n", stat, s->dstat);
- s->dstat |= stat;
- lsi_update_irq(s);
- lsi_stop_script(s);
-}
-
-static inline void lsi_set_phase(LSIState *s, int phase)
-{
- s->sstat1 = (s->sstat1 & ~PHASE_MASK) | phase;
-}
-
-static void lsi_bad_phase(LSIState *s, int out, int new_phase)
-{
- /* Trigger a phase mismatch. */
- if (s->ccntl0 & LSI_CCNTL0_ENPMJ) {
- if ((s->ccntl0 & LSI_CCNTL0_PMJCTL)) {
- s->dsp = out ? s->pmjad1 : s->pmjad2;
- } else {
- s->dsp = (s->scntl2 & LSI_SCNTL2_WSR ? s->pmjad2 : s->pmjad1);
- }
- DPRINTF("Data phase mismatch jump to %08x\n", s->dsp);
- } else {
- DPRINTF("Phase mismatch interrupt\n");
- lsi_script_scsi_interrupt(s, LSI_SIST0_MA, 0);
- lsi_stop_script(s);
- }
- lsi_set_phase(s, new_phase);
-}
-
-
-/* Resume SCRIPTS execution after a DMA operation. */
-static void lsi_resume_script(LSIState *s)
-{
- if (s->waiting != 2) {
- s->waiting = 0;
- lsi_execute_script(s);
- } else {
- s->waiting = 0;
- }
-}
-
-static void lsi_disconnect(LSIState *s)
-{
- s->scntl1 &= ~LSI_SCNTL1_CON;
- s->sstat1 &= ~PHASE_MASK;
-}
-
-static void lsi_bad_selection(LSIState *s, uint32_t id)
-{
- DPRINTF("Selected absent target %d\n", id);
- lsi_script_scsi_interrupt(s, 0, LSI_SIST1_STO);
- lsi_disconnect(s);
-}
-
-/* Initiate a SCSI layer data transfer. */
-static void lsi_do_dma(LSIState *s, int out)
-{
- PCIDevice *pci_dev;
- uint32_t count;
- dma_addr_t addr;
- SCSIDevice *dev;
-
- assert(s->current);
- if (!s->current->dma_len) {
- /* Wait until data is available. */
- DPRINTF("DMA no data available\n");
- return;
- }
-
- pci_dev = PCI_DEVICE(s);
- dev = s->current->req->dev;
- assert(dev);
-
- count = s->dbc;
- if (count > s->current->dma_len)
- count = s->current->dma_len;
-
- addr = s->dnad;
- /* both 40 and Table Indirect 64-bit DMAs store upper bits in dnad64 */
- if (lsi_dma_40bit(s) || lsi_dma_ti64bit(s))
- addr |= ((uint64_t)s->dnad64 << 32);
- else if (s->dbms)
- addr |= ((uint64_t)s->dbms << 32);
- else if (s->sbms)
- addr |= ((uint64_t)s->sbms << 32);
-
- DPRINTF("DMA addr=0x" DMA_ADDR_FMT " len=%d\n", addr, count);
- s->csbc += count;
- s->dnad += count;
- s->dbc -= count;
- if (s->current->dma_buf == NULL) {
- s->current->dma_buf = scsi_req_get_buf(s->current->req);
- }
- /* ??? Set SFBR to first data byte. */
- if (out) {
- pci_dma_read(pci_dev, addr, s->current->dma_buf, count);
- } else {
- pci_dma_write(pci_dev, addr, s->current->dma_buf, count);
- }
- s->current->dma_len -= count;
- if (s->current->dma_len == 0) {
- s->current->dma_buf = NULL;
- scsi_req_continue(s->current->req);
- } else {
- s->current->dma_buf += count;
- lsi_resume_script(s);
- }
-}
-
-
-/* Add a command to the queue. */
-static void lsi_queue_command(LSIState *s)
-{
- lsi_request *p = s->current;
-
- DPRINTF("Queueing tag=0x%x\n", p->tag);
- assert(s->current != NULL);
- assert(s->current->dma_len == 0);
- QTAILQ_INSERT_TAIL(&s->queue, s->current, next);
- s->current = NULL;
-
- p->pending = 0;
- p->out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
-}
-
-/* Queue a byte for a MSG IN phase. */
-static void lsi_add_msg_byte(LSIState *s, uint8_t data)
-{
- if (s->msg_len >= LSI_MAX_MSGIN_LEN) {
- BADF("MSG IN data too long\n");
- } else {
- DPRINTF("MSG IN 0x%02x\n", data);
- s->msg[s->msg_len++] = data;
- }
-}
-
-/* Perform reselection to continue a command. */
-static void lsi_reselect(LSIState *s, lsi_request *p)
-{
- int id;
-
- assert(s->current == NULL);
- QTAILQ_REMOVE(&s->queue, p, next);
- s->current = p;
-
- id = (p->tag >> 8) & 0xf;
- s->ssid = id | 0x80;
- /* LSI53C700 Family Compatibility, see LSI53C895A 4-73 */
- if (!(s->dcntl & LSI_DCNTL_COM)) {
- s->sfbr = 1 << (id & 0x7);
- }
- DPRINTF("Reselected target %d\n", id);
- s->scntl1 |= LSI_SCNTL1_CON;
- lsi_set_phase(s, PHASE_MI);
- s->msg_action = p->out ? 2 : 3;
- s->current->dma_len = p->pending;
- lsi_add_msg_byte(s, 0x80);
- if (s->current->tag & LSI_TAG_VALID) {
- lsi_add_msg_byte(s, 0x20);
- lsi_add_msg_byte(s, p->tag & 0xff);
- }
-
- if (lsi_irq_on_rsl(s)) {
- lsi_script_scsi_interrupt(s, LSI_SIST0_RSL, 0);
- }
-}
-
-static lsi_request *lsi_find_by_tag(LSIState *s, uint32_t tag)
-{
- lsi_request *p;
-
- QTAILQ_FOREACH(p, &s->queue, next) {
- if (p->tag == tag) {
- return p;
- }
- }
-
- return NULL;
-}
-
-static void lsi_request_free(LSIState *s, lsi_request *p)
-{
- if (p == s->current) {
- s->current = NULL;
- } else {
- QTAILQ_REMOVE(&s->queue, p, next);
- }
- g_free(p);
-}
-
-static void lsi_request_cancelled(SCSIRequest *req)
-{
- LSIState *s = LSI53C895A(req->bus->qbus.parent);
- lsi_request *p = req->hba_private;
-
- req->hba_private = NULL;
- lsi_request_free(s, p);
- scsi_req_unref(req);
-}
-
-/* Record that data is available for a queued command. Returns zero if
- the device was reselected, nonzero if the IO is deferred. */
-static int lsi_queue_req(LSIState *s, SCSIRequest *req, uint32_t len)
-{
- lsi_request *p = req->hba_private;
-
- if (p->pending) {
- BADF("Multiple IO pending for request %p\n", p);
- }
- p->pending = len;
- /* Reselect if waiting for it, or if reselection triggers an IRQ
- and the bus is free.
- Since no interrupt stacking is implemented in the emulation, it
- is also required that there are no pending interrupts waiting
- for service from the device driver. */
- if (s->waiting == 1 ||
- (lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON) &&
- !(s->istat0 & (LSI_ISTAT0_SIP | LSI_ISTAT0_DIP)))) {
- /* Reselect device. */
- lsi_reselect(s, p);
- return 0;
- } else {
- DPRINTF("Queueing IO tag=0x%x\n", p->tag);
- p->pending = len;
- return 1;
- }
-}
-
- /* Callback to indicate that the SCSI layer has completed a command. */
-static void lsi_command_complete(SCSIRequest *req, uint32_t status, size_t resid)
-{
- LSIState *s = LSI53C895A(req->bus->qbus.parent);
- int out;
-
- out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
- DPRINTF("Command complete status=%d\n", (int)status);
- s->status = status;
- s->command_complete = 2;
- if (s->waiting && s->dbc != 0) {
- /* Raise phase mismatch for short transfers. */
- lsi_bad_phase(s, out, PHASE_ST);
- } else {
- lsi_set_phase(s, PHASE_ST);
- }
-
- if (req->hba_private == s->current) {
- req->hba_private = NULL;
- lsi_request_free(s, s->current);
- scsi_req_unref(req);
- }
- lsi_resume_script(s);
-}
-
- /* Callback to indicate that the SCSI layer has completed a transfer. */
-static void lsi_transfer_data(SCSIRequest *req, uint32_t len)
-{
- LSIState *s = LSI53C895A(req->bus->qbus.parent);
- int out;
-
- assert(req->hba_private);
- if (s->waiting == 1 || req->hba_private != s->current ||
- (lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON))) {
- if (lsi_queue_req(s, req, len)) {
- return;
- }
- }
-
- out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
-
- /* host adapter (re)connected */
- DPRINTF("Data ready tag=0x%x len=%d\n", req->tag, len);
- s->current->dma_len = len;
- s->command_complete = 1;
- if (s->waiting) {
- if (s->waiting == 1 || s->dbc == 0) {
- lsi_resume_script(s);
- } else {
- lsi_do_dma(s, out);
- }
- }
-}
-
-static void lsi_do_command(LSIState *s)
-{
- SCSIDevice *dev;
- uint8_t buf[16];
- uint32_t id;
- int n;
-
- DPRINTF("Send command len=%d\n", s->dbc);
- if (s->dbc > 16)
- s->dbc = 16;
- pci_dma_read(PCI_DEVICE(s), s->dnad, buf, s->dbc);
- s->sfbr = buf[0];
- s->command_complete = 0;
-
- id = (s->select_tag >> 8) & 0xf;
- dev = scsi_device_find(&s->bus, 0, id, s->current_lun);
- if (!dev) {
- lsi_bad_selection(s, id);
- return;
- }
-
- assert(s->current == NULL);
- s->current = g_new0(lsi_request, 1);
- s->current->tag = s->select_tag;
- s->current->req = scsi_req_new(dev, s->current->tag, s->current_lun, buf,
- s->current);
-
- n = scsi_req_enqueue(s->current->req);
- if (n) {
- if (n > 0) {
- lsi_set_phase(s, PHASE_DI);
- } else if (n < 0) {
- lsi_set_phase(s, PHASE_DO);
- }
- scsi_req_continue(s->current->req);
- }
- if (!s->command_complete) {
- if (n) {
- /* Command did not complete immediately so disconnect. */
- lsi_add_msg_byte(s, 2); /* SAVE DATA POINTER */
- lsi_add_msg_byte(s, 4); /* DISCONNECT */
- /* wait data */
- lsi_set_phase(s, PHASE_MI);
- s->msg_action = 1;
- lsi_queue_command(s);
- } else {
- /* wait command complete */
- lsi_set_phase(s, PHASE_DI);
- }
- }
-}
-
-static void lsi_do_status(LSIState *s)
-{
- uint8_t status;
- DPRINTF("Get status len=%d status=%d\n", s->dbc, s->status);
- if (s->dbc != 1)
- BADF("Bad Status move\n");
- s->dbc = 1;
- status = s->status;
- s->sfbr = status;
- pci_dma_write(PCI_DEVICE(s), s->dnad, &status, 1);
- lsi_set_phase(s, PHASE_MI);
- s->msg_action = 1;
- lsi_add_msg_byte(s, 0); /* COMMAND COMPLETE */
-}
-
-static void lsi_do_msgin(LSIState *s)
-{
- int len;
- DPRINTF("Message in len=%d/%d\n", s->dbc, s->msg_len);
- s->sfbr = s->msg[0];
- len = s->msg_len;
- if (len > s->dbc)
- len = s->dbc;
- pci_dma_write(PCI_DEVICE(s), s->dnad, s->msg, len);
- /* Linux drivers rely on the last byte being in the SIDL. */
- s->sidl = s->msg[len - 1];
- s->msg_len -= len;
- if (s->msg_len) {
- memmove(s->msg, s->msg + len, s->msg_len);
- } else {
- /* ??? Check if ATN (not yet implemented) is asserted and maybe
- switch to PHASE_MO. */
- switch (s->msg_action) {
- case 0:
- lsi_set_phase(s, PHASE_CMD);
- break;
- case 1:
- lsi_disconnect(s);
- break;
- case 2:
- lsi_set_phase(s, PHASE_DO);
- break;
- case 3:
- lsi_set_phase(s, PHASE_DI);
- break;
- default:
- abort();
- }
- }
-}
-
-/* Read the next byte during a MSGOUT phase. */
-static uint8_t lsi_get_msgbyte(LSIState *s)
-{
- uint8_t data;
- pci_dma_read(PCI_DEVICE(s), s->dnad, &data, 1);
- s->dnad++;
- s->dbc--;
- return data;
-}
-
-/* Skip the next n bytes during a MSGOUT phase. */
-static void lsi_skip_msgbytes(LSIState *s, unsigned int n)
-{
- s->dnad += n;
- s->dbc -= n;
-}
-
-static void lsi_do_msgout(LSIState *s)
-{
- uint8_t msg;
- int len;
- uint32_t current_tag;
- lsi_request *current_req, *p, *p_next;
-
- if (s->current) {
- current_tag = s->current->tag;
- current_req = s->current;
- } else {
- current_tag = s->select_tag;
- current_req = lsi_find_by_tag(s, current_tag);
- }
-
- DPRINTF("MSG out len=%d\n", s->dbc);
- while (s->dbc) {
- msg = lsi_get_msgbyte(s);
- s->sfbr = msg;
-
- switch (msg) {
- case 0x04:
- DPRINTF("MSG: Disconnect\n");
- lsi_disconnect(s);
- break;
- case 0x08:
- DPRINTF("MSG: No Operation\n");
- lsi_set_phase(s, PHASE_CMD);
- break;
- case 0x01:
- len = lsi_get_msgbyte(s);
- msg = lsi_get_msgbyte(s);
- (void)len; /* avoid a warning about unused variable*/
- DPRINTF("Extended message 0x%x (len %d)\n", msg, len);
- switch (msg) {
- case 1:
- DPRINTF("SDTR (ignored)\n");
- lsi_skip_msgbytes(s, 2);
- break;
- case 3:
- DPRINTF("WDTR (ignored)\n");
- lsi_skip_msgbytes(s, 1);
- break;
- default:
- goto bad;
- }
- break;
- case 0x20: /* SIMPLE queue */
- s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
- DPRINTF("SIMPLE queue tag=0x%x\n", s->select_tag & 0xff);
- break;
- case 0x21: /* HEAD of queue */
- BADF("HEAD queue not implemented\n");
- s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
- break;
- case 0x22: /* ORDERED queue */
- BADF("ORDERED queue not implemented\n");
- s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
- break;
- case 0x0d:
- /* The ABORT TAG message clears the current I/O process only. */
- DPRINTF("MSG: ABORT TAG tag=0x%x\n", current_tag);
- if (current_req) {
- scsi_req_cancel(current_req->req);
- }
- lsi_disconnect(s);
- break;
- case 0x06:
- case 0x0e:
- case 0x0c:
- /* The ABORT message clears all I/O processes for the selecting
- initiator on the specified logical unit of the target. */
- if (msg == 0x06) {
- DPRINTF("MSG: ABORT tag=0x%x\n", current_tag);
- }
- /* The CLEAR QUEUE message clears all I/O processes for all
- initiators on the specified logical unit of the target. */
- if (msg == 0x0e) {
- DPRINTF("MSG: CLEAR QUEUE tag=0x%x\n", current_tag);
- }
- /* The BUS DEVICE RESET message clears all I/O processes for all
- initiators on all logical units of the target. */
- if (msg == 0x0c) {
- DPRINTF("MSG: BUS DEVICE RESET tag=0x%x\n", current_tag);
- }
-
- /* clear the current I/O process */
- if (s->current) {
- scsi_req_cancel(s->current->req);
- }
-
- /* As the current implemented devices scsi_disk and scsi_generic
- only support one LUN, we don't need to keep track of LUNs.
- Clearing I/O processes for other initiators could be possible
- for scsi_generic by sending a SG_SCSI_RESET to the /dev/sgX
- device, but this is currently not implemented (and seems not
- to be really necessary). So let's simply clear all queued
- commands for the current device: */
- QTAILQ_FOREACH_SAFE(p, &s->queue, next, p_next) {
- if ((p->tag & 0x0000ff00) == (current_tag & 0x0000ff00)) {
- scsi_req_cancel(p->req);
- }
- }
-
- lsi_disconnect(s);
- break;
- default:
- if ((msg & 0x80) == 0) {
- goto bad;
- }
- s->current_lun = msg & 7;
- DPRINTF("Select LUN %d\n", s->current_lun);
- lsi_set_phase(s, PHASE_CMD);
- break;
- }
- }
- return;
-bad:
- BADF("Unimplemented message 0x%02x\n", msg);
- lsi_set_phase(s, PHASE_MI);
- lsi_add_msg_byte(s, 7); /* MESSAGE REJECT */
- s->msg_action = 0;
-}
-
-#define LSI_BUF_SIZE 4096
-static void lsi_memcpy(LSIState *s, uint32_t dest, uint32_t src, int count)
-{
- PCIDevice *d = PCI_DEVICE(s);
- int n;
- uint8_t buf[LSI_BUF_SIZE];
-
- DPRINTF("memcpy dest 0x%08x src 0x%08x count %d\n", dest, src, count);
- while (count) {
- n = (count > LSI_BUF_SIZE) ? LSI_BUF_SIZE : count;
- pci_dma_read(d, src, buf, n);
- pci_dma_write(d, dest, buf, n);
- src += n;
- dest += n;
- count -= n;
- }
-}
-
-static void lsi_wait_reselect(LSIState *s)
-{
- lsi_request *p;
-
- DPRINTF("Wait Reselect\n");
-
- QTAILQ_FOREACH(p, &s->queue, next) {
- if (p->pending) {
- lsi_reselect(s, p);
- break;
- }
- }
- if (s->current == NULL) {
- s->waiting = 1;
- }
-}
-
-static void lsi_execute_script(LSIState *s)
-{
- PCIDevice *pci_dev = PCI_DEVICE(s);
- uint32_t insn;
- uint32_t addr, addr_high;
- int opcode;
- int insn_processed = 0;
-
- s->istat1 |= LSI_ISTAT1_SRUN;
-again:
- insn_processed++;
- insn = read_dword(s, s->dsp);
- if (!insn) {
- /* If we receive an empty opcode increment the DSP by 4 bytes
- instead of 8 and execute the next opcode at that location */
- s->dsp += 4;
- goto again;
- }
- addr = read_dword(s, s->dsp + 4);
- addr_high = 0;
- DPRINTF("SCRIPTS dsp=%08x opcode %08x arg %08x\n", s->dsp, insn, addr);
- s->dsps = addr;
- s->dcmd = insn >> 24;
- s->dsp += 8;
- switch (insn >> 30) {
- case 0: /* Block move. */
- if (s->sist1 & LSI_SIST1_STO) {
- DPRINTF("Delayed select timeout\n");
- lsi_stop_script(s);
- break;
- }
- s->dbc = insn & 0xffffff;
- s->rbc = s->dbc;
- /* ??? Set ESA. */
- s->ia = s->dsp - 8;
- if (insn & (1 << 29)) {
- /* Indirect addressing. */
- addr = read_dword(s, addr);
- } else if (insn & (1 << 28)) {
- uint32_t buf[2];
- int32_t offset;
- /* Table indirect addressing. */
-
- /* 32-bit Table indirect */
- offset = sextract32(addr, 0, 24);
- pci_dma_read(pci_dev, s->dsa + offset, buf, 8);
- /* byte count is stored in bits 0:23 only */
- s->dbc = cpu_to_le32(buf[0]) & 0xffffff;
- s->rbc = s->dbc;
- addr = cpu_to_le32(buf[1]);
-
- /* 40-bit DMA, upper addr bits [39:32] stored in first DWORD of
- * table, bits [31:24] */
- if (lsi_dma_40bit(s))
- addr_high = cpu_to_le32(buf[0]) >> 24;
- else if (lsi_dma_ti64bit(s)) {
- int selector = (cpu_to_le32(buf[0]) >> 24) & 0x1f;
- switch (selector) {
- case 0 ... 0x0f:
- /* offset index into scratch registers since
- * TI64 mode can use registers C to R */
- addr_high = s->scratch[2 + selector];
- break;
- case 0x10:
- addr_high = s->mmrs;
- break;
- case 0x11:
- addr_high = s->mmws;
- break;
- case 0x12:
- addr_high = s->sfs;
- break;
- case 0x13:
- addr_high = s->drs;
- break;
- case 0x14:
- addr_high = s->sbms;
- break;
- case 0x15:
- addr_high = s->dbms;
- break;
- default:
- BADF("Illegal selector specified (0x%x > 0x15)"
- " for 64-bit DMA block move", selector);
- break;
- }
- }
- } else if (lsi_dma_64bit(s)) {
- /* fetch a 3rd dword if 64-bit direct move is enabled and
- only if we're not doing table indirect or indirect addressing */
- s->dbms = read_dword(s, s->dsp);
- s->dsp += 4;
- s->ia = s->dsp - 12;
- }
- if ((s->sstat1 & PHASE_MASK) != ((insn >> 24) & 7)) {
- DPRINTF("Wrong phase got %d expected %d\n",
- s->sstat1 & PHASE_MASK, (insn >> 24) & 7);
- lsi_script_scsi_interrupt(s, LSI_SIST0_MA, 0);
- break;
- }
- s->dnad = addr;
- s->dnad64 = addr_high;
- switch (s->sstat1 & 0x7) {
- case PHASE_DO:
- s->waiting = 2;
- lsi_do_dma(s, 1);
- if (s->waiting)
- s->waiting = 3;
- break;
- case PHASE_DI:
- s->waiting = 2;
- lsi_do_dma(s, 0);
- if (s->waiting)
- s->waiting = 3;
- break;
- case PHASE_CMD:
- lsi_do_command(s);
- break;
- case PHASE_ST:
- lsi_do_status(s);
- break;
- case PHASE_MO:
- lsi_do_msgout(s);
- break;
- case PHASE_MI:
- lsi_do_msgin(s);
- break;
- default:
- BADF("Unimplemented phase %d\n", s->sstat1 & PHASE_MASK);
- exit(1);
- }
- s->dfifo = s->dbc & 0xff;
- s->ctest5 = (s->ctest5 & 0xfc) | ((s->dbc >> 8) & 3);
- s->sbc = s->dbc;
- s->rbc -= s->dbc;
- s->ua = addr + s->dbc;
- break;
-
- case 1: /* IO or Read/Write instruction. */
- opcode = (insn >> 27) & 7;
- if (opcode < 5) {
- uint32_t id;
-
- if (insn & (1 << 25)) {
- id = read_dword(s, s->dsa + sextract32(insn, 0, 24));
- } else {
- id = insn;
- }
- id = (id >> 16) & 0xf;
- if (insn & (1 << 26)) {
- addr = s->dsp + sextract32(addr, 0, 24);
- }
- s->dnad = addr;
- switch (opcode) {
- case 0: /* Select */
- s->sdid = id;
- if (s->scntl1 & LSI_SCNTL1_CON) {
- DPRINTF("Already reselected, jumping to alternative address\n");
- s->dsp = s->dnad;
- break;
- }
- s->sstat0 |= LSI_SSTAT0_WOA;
- s->scntl1 &= ~LSI_SCNTL1_IARB;
- if (!scsi_device_find(&s->bus, 0, id, 0)) {
- lsi_bad_selection(s, id);
- break;
- }
- DPRINTF("Selected target %d%s\n",
- id, insn & (1 << 3) ? " ATN" : "");
- /* ??? Linux drivers compain when this is set. Maybe
- it only applies in low-level mode (unimplemented).
- lsi_script_scsi_interrupt(s, LSI_SIST0_CMP, 0); */
- s->select_tag = id << 8;
- s->scntl1 |= LSI_SCNTL1_CON;
- if (insn & (1 << 3)) {
- s->socl |= LSI_SOCL_ATN;
- }
- lsi_set_phase(s, PHASE_MO);
- break;
- case 1: /* Disconnect */
- DPRINTF("Wait Disconnect\n");
- s->scntl1 &= ~LSI_SCNTL1_CON;
- break;
- case 2: /* Wait Reselect */
- if (!lsi_irq_on_rsl(s)) {
- lsi_wait_reselect(s);
- }
- break;
- case 3: /* Set */
- DPRINTF("Set%s%s%s%s\n",
- insn & (1 << 3) ? " ATN" : "",
- insn & (1 << 6) ? " ACK" : "",
- insn & (1 << 9) ? " TM" : "",
- insn & (1 << 10) ? " CC" : "");
- if (insn & (1 << 3)) {
- s->socl |= LSI_SOCL_ATN;
- lsi_set_phase(s, PHASE_MO);
- }
- if (insn & (1 << 9)) {
- BADF("Target mode not implemented\n");
- exit(1);
- }
- if (insn & (1 << 10))
- s->carry = 1;
- break;
- case 4: /* Clear */
- DPRINTF("Clear%s%s%s%s\n",
- insn & (1 << 3) ? " ATN" : "",
- insn & (1 << 6) ? " ACK" : "",
- insn & (1 << 9) ? " TM" : "",
- insn & (1 << 10) ? " CC" : "");
- if (insn & (1 << 3)) {
- s->socl &= ~LSI_SOCL_ATN;
- }
- if (insn & (1 << 10))
- s->carry = 0;
- break;
- }
- } else {
- uint8_t op0;
- uint8_t op1;
- uint8_t data8;
- int reg;
- int operator;
-#ifdef DEBUG_LSI
- static const char *opcode_names[3] =
- {"Write", "Read", "Read-Modify-Write"};
- static const char *operator_names[8] =
- {"MOV", "SHL", "OR", "XOR", "AND", "SHR", "ADD", "ADC"};
-#endif
-
- reg = ((insn >> 16) & 0x7f) | (insn & 0x80);
- data8 = (insn >> 8) & 0xff;
- opcode = (insn >> 27) & 7;
- operator = (insn >> 24) & 7;
- DPRINTF("%s reg 0x%x %s data8=0x%02x sfbr=0x%02x%s\n",
- opcode_names[opcode - 5], reg,
- operator_names[operator], data8, s->sfbr,
- (insn & (1 << 23)) ? " SFBR" : "");
- op0 = op1 = 0;
- switch (opcode) {
- case 5: /* From SFBR */
- op0 = s->sfbr;
- op1 = data8;
- break;
- case 6: /* To SFBR */
- if (operator)
- op0 = lsi_reg_readb(s, reg);
- op1 = data8;
- break;
- case 7: /* Read-modify-write */
- if (operator)
- op0 = lsi_reg_readb(s, reg);
- if (insn & (1 << 23)) {
- op1 = s->sfbr;
- } else {
- op1 = data8;
- }
- break;
- }
-
- switch (operator) {
- case 0: /* move */
- op0 = op1;
- break;
- case 1: /* Shift left */
- op1 = op0 >> 7;
- op0 = (op0 << 1) | s->carry;
- s->carry = op1;
- break;
- case 2: /* OR */
- op0 |= op1;
- break;
- case 3: /* XOR */
- op0 ^= op1;
- break;
- case 4: /* AND */
- op0 &= op1;
- break;
- case 5: /* SHR */
- op1 = op0 & 1;
- op0 = (op0 >> 1) | (s->carry << 7);
- s->carry = op1;
- break;
- case 6: /* ADD */
- op0 += op1;
- s->carry = op0 < op1;
- break;
- case 7: /* ADC */
- op0 += op1 + s->carry;
- if (s->carry)
- s->carry = op0 <= op1;
- else
- s->carry = op0 < op1;
- break;
- }
-
- switch (opcode) {
- case 5: /* From SFBR */
- case 7: /* Read-modify-write */
- lsi_reg_writeb(s, reg, op0);
- break;
- case 6: /* To SFBR */
- s->sfbr = op0;
- break;
- }
- }
- break;
-
- case 2: /* Transfer Control. */
- {
- int cond;
- int jmp;
-
- if ((insn & 0x002e0000) == 0) {
- DPRINTF("NOP\n");
- break;
- }
- if (s->sist1 & LSI_SIST1_STO) {
- DPRINTF("Delayed select timeout\n");
- lsi_stop_script(s);
- break;
- }
- cond = jmp = (insn & (1 << 19)) != 0;
- if (cond == jmp && (insn & (1 << 21))) {
- DPRINTF("Compare carry %d\n", s->carry == jmp);
- cond = s->carry != 0;
- }
- if (cond == jmp && (insn & (1 << 17))) {
- DPRINTF("Compare phase %d %c= %d\n",
- (s->sstat1 & PHASE_MASK),
- jmp ? '=' : '!',
- ((insn >> 24) & 7));
- cond = (s->sstat1 & PHASE_MASK) == ((insn >> 24) & 7);
- }
- if (cond == jmp && (insn & (1 << 18))) {
- uint8_t mask;
-
- mask = (~insn >> 8) & 0xff;
- DPRINTF("Compare data 0x%x & 0x%x %c= 0x%x\n",
- s->sfbr, mask, jmp ? '=' : '!', insn & mask);
- cond = (s->sfbr & mask) == (insn & mask);
- }
- if (cond == jmp) {
- if (insn & (1 << 23)) {
- /* Relative address. */
- addr = s->dsp + sextract32(addr, 0, 24);
- }
- switch ((insn >> 27) & 7) {
- case 0: /* Jump */
- DPRINTF("Jump to 0x%08x\n", addr);
- s->adder = addr;
- s->dsp = addr;
- break;
- case 1: /* Call */
- DPRINTF("Call 0x%08x\n", addr);
- s->temp = s->dsp;
- s->dsp = addr;
- break;
- case 2: /* Return */
- DPRINTF("Return to 0x%08x\n", s->temp);
- s->dsp = s->temp;
- break;
- case 3: /* Interrupt */
- DPRINTF("Interrupt 0x%08x\n", s->dsps);
- if ((insn & (1 << 20)) != 0) {
- s->istat0 |= LSI_ISTAT0_INTF;
- lsi_update_irq(s);
- } else {
- lsi_script_dma_interrupt(s, LSI_DSTAT_SIR);
- }
- break;
- default:
- DPRINTF("Illegal transfer control\n");
- lsi_script_dma_interrupt(s, LSI_DSTAT_IID);
- break;
- }
- } else {
- DPRINTF("Control condition failed\n");
- }
- }
- break;
-
- case 3:
- if ((insn & (1 << 29)) == 0) {
- /* Memory move. */
- uint32_t dest;
- /* ??? The docs imply the destination address is loaded into
- the TEMP register. However the Linux drivers rely on
- the value being presrved. */
- dest = read_dword(s, s->dsp);
- s->dsp += 4;
- lsi_memcpy(s, dest, addr, insn & 0xffffff);
- } else {
- uint8_t data[7];
- int reg;
- int n;
- int i;
-
- if (insn & (1 << 28)) {
- addr = s->dsa + sextract32(addr, 0, 24);
- }
- n = (insn & 7);
- reg = (insn >> 16) & 0xff;
- if (insn & (1 << 24)) {
- pci_dma_read(pci_dev, addr, data, n);
- DPRINTF("Load reg 0x%x size %d addr 0x%08x = %08x\n", reg, n,
- addr, *(int *)data);
- for (i = 0; i < n; i++) {
- lsi_reg_writeb(s, reg + i, data[i]);
- }
- } else {
- DPRINTF("Store reg 0x%x size %d addr 0x%08x\n", reg, n, addr);
- for (i = 0; i < n; i++) {
- data[i] = lsi_reg_readb(s, reg + i);
- }
- pci_dma_write(pci_dev, addr, data, n);
- }
- }
- }
- if (insn_processed > 10000 && !s->waiting) {
- /* Some windows drivers make the device spin waiting for a memory
- location to change. If we have been executed a lot of code then
- assume this is the case and force an unexpected device disconnect.
- This is apparently sufficient to beat the drivers into submission.
- */
- if (!(s->sien0 & LSI_SIST0_UDC))
- fprintf(stderr, "inf. loop with UDC masked\n");
- lsi_script_scsi_interrupt(s, LSI_SIST0_UDC, 0);
- lsi_disconnect(s);
- } else if (s->istat1 & LSI_ISTAT1_SRUN && !s->waiting) {
- if (s->dcntl & LSI_DCNTL_SSM) {
- lsi_script_dma_interrupt(s, LSI_DSTAT_SSI);
- } else {
- goto again;
- }
- }
- DPRINTF("SCRIPTS execution stopped\n");
-}
-
-static uint8_t lsi_reg_readb(LSIState *s, int offset)
-{
- uint8_t tmp;
-#define CASE_GET_REG24(name, addr) \
- case addr: return s->name & 0xff; \
- case addr + 1: return (s->name >> 8) & 0xff; \
- case addr + 2: return (s->name >> 16) & 0xff;
-
-#define CASE_GET_REG32(name, addr) \
- case addr: return s->name & 0xff; \
- case addr + 1: return (s->name >> 8) & 0xff; \
- case addr + 2: return (s->name >> 16) & 0xff; \
- case addr + 3: return (s->name >> 24) & 0xff;
-
-#ifdef DEBUG_LSI_REG
- DPRINTF("Read reg %x\n", offset);
-#endif
- switch (offset) {
- case 0x00: /* SCNTL0 */
- return s->scntl0;
- case 0x01: /* SCNTL1 */
- return s->scntl1;
- case 0x02: /* SCNTL2 */
- return s->scntl2;
- case 0x03: /* SCNTL3 */
- return s->scntl3;
- case 0x04: /* SCID */
- return s->scid;
- case 0x05: /* SXFER */
- return s->sxfer;
- case 0x06: /* SDID */
- return s->sdid;
- case 0x07: /* GPREG0 */
- return 0x7f;
- case 0x08: /* Revision ID */
- return 0x00;
- case 0x09: /* SOCL */
- return s->socl;
- case 0xa: /* SSID */
- return s->ssid;
- case 0xb: /* SBCL */
- /* ??? This is not correct. However it's (hopefully) only
- used for diagnostics, so should be ok. */
- return 0;
- case 0xc: /* DSTAT */
- tmp = s->dstat | LSI_DSTAT_DFE;
- if ((s->istat0 & LSI_ISTAT0_INTF) == 0)
- s->dstat = 0;
- lsi_update_irq(s);
- return tmp;
- case 0x0d: /* SSTAT0 */
- return s->sstat0;
- case 0x0e: /* SSTAT1 */
- return s->sstat1;
- case 0x0f: /* SSTAT2 */
- return s->scntl1 & LSI_SCNTL1_CON ? 0 : 2;
- CASE_GET_REG32(dsa, 0x10)
- case 0x14: /* ISTAT0 */
- return s->istat0;
- case 0x15: /* ISTAT1 */
- return s->istat1;
- case 0x16: /* MBOX0 */
- return s->mbox0;
- case 0x17: /* MBOX1 */
- return s->mbox1;
- case 0x18: /* CTEST0 */
- return 0xff;
- case 0x19: /* CTEST1 */
- return 0;
- case 0x1a: /* CTEST2 */
- tmp = s->ctest2 | LSI_CTEST2_DACK | LSI_CTEST2_CM;
- if (s->istat0 & LSI_ISTAT0_SIGP) {
- s->istat0 &= ~LSI_ISTAT0_SIGP;
- tmp |= LSI_CTEST2_SIGP;
- }
- return tmp;
- case 0x1b: /* CTEST3 */
- return s->ctest3;
- CASE_GET_REG32(temp, 0x1c)
- case 0x20: /* DFIFO */
- return 0;
- case 0x21: /* CTEST4 */
- return s->ctest4;
- case 0x22: /* CTEST5 */
- return s->ctest5;
- case 0x23: /* CTEST6 */
- return 0;
- CASE_GET_REG24(dbc, 0x24)
- case 0x27: /* DCMD */
- return s->dcmd;
- CASE_GET_REG32(dnad, 0x28)
- CASE_GET_REG32(dsp, 0x2c)
- CASE_GET_REG32(dsps, 0x30)
- CASE_GET_REG32(scratch[0], 0x34)
- case 0x38: /* DMODE */
- return s->dmode;
- case 0x39: /* DIEN */
- return s->dien;
- case 0x3a: /* SBR */
- return s->sbr;
- case 0x3b: /* DCNTL */
- return s->dcntl;
- /* ADDER Output (Debug of relative jump address) */
- CASE_GET_REG32(adder, 0x3c)
- case 0x40: /* SIEN0 */
- return s->sien0;
- case 0x41: /* SIEN1 */
- return s->sien1;
- case 0x42: /* SIST0 */
- tmp = s->sist0;
- s->sist0 = 0;
- lsi_update_irq(s);
- return tmp;
- case 0x43: /* SIST1 */
- tmp = s->sist1;
- s->sist1 = 0;
- lsi_update_irq(s);
- return tmp;
- case 0x46: /* MACNTL */
- return 0x0f;
- case 0x47: /* GPCNTL0 */
- return 0x0f;
- case 0x48: /* STIME0 */
- return s->stime0;
- case 0x4a: /* RESPID0 */
- return s->respid0;
- case 0x4b: /* RESPID1 */
- return s->respid1;
- case 0x4d: /* STEST1 */
- return s->stest1;
- case 0x4e: /* STEST2 */
- return s->stest2;
- case 0x4f: /* STEST3 */
- return s->stest3;
- case 0x50: /* SIDL */
- /* This is needed by the linux drivers. We currently only update it
- during the MSG IN phase. */
- return s->sidl;
- case 0x52: /* STEST4 */
- return 0xe0;
- case 0x56: /* CCNTL0 */
- return s->ccntl0;
- case 0x57: /* CCNTL1 */
- return s->ccntl1;
- case 0x58: /* SBDL */
- /* Some drivers peek at the data bus during the MSG IN phase. */
- if ((s->sstat1 & PHASE_MASK) == PHASE_MI)
- return s->msg[0];
- return 0;
- case 0x59: /* SBDL high */
- return 0;
- CASE_GET_REG32(mmrs, 0xa0)
- CASE_GET_REG32(mmws, 0xa4)
- CASE_GET_REG32(sfs, 0xa8)
- CASE_GET_REG32(drs, 0xac)
- CASE_GET_REG32(sbms, 0xb0)
- CASE_GET_REG32(dbms, 0xb4)
- CASE_GET_REG32(dnad64, 0xb8)
- CASE_GET_REG32(pmjad1, 0xc0)
- CASE_GET_REG32(pmjad2, 0xc4)
- CASE_GET_REG32(rbc, 0xc8)
- CASE_GET_REG32(ua, 0xcc)
- CASE_GET_REG32(ia, 0xd4)
- CASE_GET_REG32(sbc, 0xd8)
- CASE_GET_REG32(csbc, 0xdc)
- }
- if (offset >= 0x5c && offset < 0xa0) {
- int n;
- int shift;
- n = (offset - 0x58) >> 2;
- shift = (offset & 3) * 8;
- return (s->scratch[n] >> shift) & 0xff;
- }
- BADF("readb 0x%x\n", offset);
- exit(1);
-#undef CASE_GET_REG24
-#undef CASE_GET_REG32
-}
-
-static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
-{
-#define CASE_SET_REG24(name, addr) \
- case addr : s->name &= 0xffffff00; s->name |= val; break; \
- case addr + 1: s->name &= 0xffff00ff; s->name |= val << 8; break; \
- case addr + 2: s->name &= 0xff00ffff; s->name |= val << 16; break;
-
-#define CASE_SET_REG32(name, addr) \
- case addr : s->name &= 0xffffff00; s->name |= val; break; \
- case addr + 1: s->name &= 0xffff00ff; s->name |= val << 8; break; \
- case addr + 2: s->name &= 0xff00ffff; s->name |= val << 16; break; \
- case addr + 3: s->name &= 0x00ffffff; s->name |= val << 24; break;
-
-#ifdef DEBUG_LSI_REG
- DPRINTF("Write reg %x = %02x\n", offset, val);
-#endif
- switch (offset) {
- case 0x00: /* SCNTL0 */
- s->scntl0 = val;
- if (val & LSI_SCNTL0_START) {
- BADF("Start sequence not implemented\n");
- }
- break;
- case 0x01: /* SCNTL1 */
- s->scntl1 = val & ~LSI_SCNTL1_SST;
- if (val & LSI_SCNTL1_IARB) {
- BADF("Immediate Arbritration not implemented\n");
- }
- if (val & LSI_SCNTL1_RST) {
- if (!(s->sstat0 & LSI_SSTAT0_RST)) {
- qbus_reset_all(&s->bus.qbus);
- s->sstat0 |= LSI_SSTAT0_RST;
- lsi_script_scsi_interrupt(s, LSI_SIST0_RST, 0);
- }
- } else {
- s->sstat0 &= ~LSI_SSTAT0_RST;
- }
- break;
- case 0x02: /* SCNTL2 */
- val &= ~(LSI_SCNTL2_WSR | LSI_SCNTL2_WSS);
- s->scntl2 = val;
- break;
- case 0x03: /* SCNTL3 */
- s->scntl3 = val;
- break;
- case 0x04: /* SCID */
- s->scid = val;
- break;
- case 0x05: /* SXFER */
- s->sxfer = val;
- break;
- case 0x06: /* SDID */
- if ((s->ssid & 0x80) && (val & 0xf) != (s->ssid & 0xf)) {
- BADF("Destination ID does not match SSID\n");
- }
- s->sdid = val & 0xf;
- break;
- case 0x07: /* GPREG0 */
- break;
- case 0x08: /* SFBR */
- /* The CPU is not allowed to write to this register. However the
- SCRIPTS register move instructions are. */
- s->sfbr = val;
- break;
- case 0x0a: case 0x0b:
- /* Openserver writes to these readonly registers on startup */
- return;
- case 0x0c: case 0x0d: case 0x0e: case 0x0f:
- /* Linux writes to these readonly registers on startup. */
- return;
- CASE_SET_REG32(dsa, 0x10)
- case 0x14: /* ISTAT0 */
- s->istat0 = (s->istat0 & 0x0f) | (val & 0xf0);
- if (val & LSI_ISTAT0_ABRT) {
- lsi_script_dma_interrupt(s, LSI_DSTAT_ABRT);
- }
- if (val & LSI_ISTAT0_INTF) {
- s->istat0 &= ~LSI_ISTAT0_INTF;
- lsi_update_irq(s);
- }
- if (s->waiting == 1 && val & LSI_ISTAT0_SIGP) {
- DPRINTF("Woken by SIGP\n");
- s->waiting = 0;
- s->dsp = s->dnad;
- lsi_execute_script(s);
- }
- if (val & LSI_ISTAT0_SRST) {
- qdev_reset_all(DEVICE(s));
- }
- break;
- case 0x16: /* MBOX0 */
- s->mbox0 = val;
- break;
- case 0x17: /* MBOX1 */
- s->mbox1 = val;
- break;
- case 0x18: /* CTEST0 */
- /* nothing to do */
- break;
- case 0x1a: /* CTEST2 */
- s->ctest2 = val & LSI_CTEST2_PCICIE;
- break;
- case 0x1b: /* CTEST3 */
- s->ctest3 = val & 0x0f;
- break;
- CASE_SET_REG32(temp, 0x1c)
- case 0x21: /* CTEST4 */
- if (val & 7) {
- BADF("Unimplemented CTEST4-FBL 0x%x\n", val);
- }
- s->ctest4 = val;
- break;
- case 0x22: /* CTEST5 */
- if (val & (LSI_CTEST5_ADCK | LSI_CTEST5_BBCK)) {
- BADF("CTEST5 DMA increment not implemented\n");
- }
- s->ctest5 = val;
- break;
- CASE_SET_REG24(dbc, 0x24)
- CASE_SET_REG32(dnad, 0x28)
- case 0x2c: /* DSP[0:7] */
- s->dsp &= 0xffffff00;
- s->dsp |= val;
- break;
- case 0x2d: /* DSP[8:15] */
- s->dsp &= 0xffff00ff;
- s->dsp |= val << 8;
- break;
- case 0x2e: /* DSP[16:23] */
- s->dsp &= 0xff00ffff;
- s->dsp |= val << 16;
- break;
- case 0x2f: /* DSP[24:31] */
- s->dsp &= 0x00ffffff;
- s->dsp |= val << 24;
- if ((s->dmode & LSI_DMODE_MAN) == 0
- && (s->istat1 & LSI_ISTAT1_SRUN) == 0)
- lsi_execute_script(s);
- break;
- CASE_SET_REG32(dsps, 0x30)
- CASE_SET_REG32(scratch[0], 0x34)
- case 0x38: /* DMODE */
- if (val & (LSI_DMODE_SIOM | LSI_DMODE_DIOM)) {
- BADF("IO mappings not implemented\n");
- }
- s->dmode = val;
- break;
- case 0x39: /* DIEN */
- s->dien = val;
- lsi_update_irq(s);
- break;
- case 0x3a: /* SBR */
- s->sbr = val;
- break;
- case 0x3b: /* DCNTL */
- s->dcntl = val & ~(LSI_DCNTL_PFF | LSI_DCNTL_STD);
- if ((val & LSI_DCNTL_STD) && (s->istat1 & LSI_ISTAT1_SRUN) == 0)
- lsi_execute_script(s);
- break;
- case 0x40: /* SIEN0 */
- s->sien0 = val;
- lsi_update_irq(s);
- break;
- case 0x41: /* SIEN1 */
- s->sien1 = val;
- lsi_update_irq(s);
- break;
- case 0x47: /* GPCNTL0 */
- break;
- case 0x48: /* STIME0 */
- s->stime0 = val;
- break;
- case 0x49: /* STIME1 */
- if (val & 0xf) {
- DPRINTF("General purpose timer not implemented\n");
- /* ??? Raising the interrupt immediately seems to be sufficient
- to keep the FreeBSD driver happy. */
- lsi_script_scsi_interrupt(s, 0, LSI_SIST1_GEN);
- }
- break;
- case 0x4a: /* RESPID0 */
- s->respid0 = val;
- break;
- case 0x4b: /* RESPID1 */
- s->respid1 = val;
- break;
- case 0x4d: /* STEST1 */
- s->stest1 = val;
- break;
- case 0x4e: /* STEST2 */
- if (val & 1) {
- BADF("Low level mode not implemented\n");
- }
- s->stest2 = val;
- break;
- case 0x4f: /* STEST3 */
- if (val & 0x41) {
- BADF("SCSI FIFO test mode not implemented\n");
- }
- s->stest3 = val;
- break;
- case 0x56: /* CCNTL0 */
- s->ccntl0 = val;
- break;
- case 0x57: /* CCNTL1 */
- s->ccntl1 = val;
- break;
- CASE_SET_REG32(mmrs, 0xa0)
- CASE_SET_REG32(mmws, 0xa4)
- CASE_SET_REG32(sfs, 0xa8)
- CASE_SET_REG32(drs, 0xac)
- CASE_SET_REG32(sbms, 0xb0)
- CASE_SET_REG32(dbms, 0xb4)
- CASE_SET_REG32(dnad64, 0xb8)
- CASE_SET_REG32(pmjad1, 0xc0)
- CASE_SET_REG32(pmjad2, 0xc4)
- CASE_SET_REG32(rbc, 0xc8)
- CASE_SET_REG32(ua, 0xcc)
- CASE_SET_REG32(ia, 0xd4)
- CASE_SET_REG32(sbc, 0xd8)
- CASE_SET_REG32(csbc, 0xdc)
- default:
- if (offset >= 0x5c && offset < 0xa0) {
- int n;
- int shift;
- n = (offset - 0x58) >> 2;
- shift = (offset & 3) * 8;
- s->scratch[n] = deposit32(s->scratch[n], shift, 8, val);
- } else {
- BADF("Unhandled writeb 0x%x = 0x%x\n", offset, val);
- }
- }
-#undef CASE_SET_REG24
-#undef CASE_SET_REG32
-}
-
-static void lsi_mmio_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- LSIState *s = opaque;
-
- lsi_reg_writeb(s, addr & 0xff, val);
-}
-
-static uint64_t lsi_mmio_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- LSIState *s = opaque;
-
- return lsi_reg_readb(s, addr & 0xff);
-}
-
-static const MemoryRegionOps lsi_mmio_ops = {
- .read = lsi_mmio_read,
- .write = lsi_mmio_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
-};
-
-static void lsi_ram_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- LSIState *s = opaque;
- uint32_t newval;
- uint32_t mask;
- int shift;
-
- newval = s->script_ram[addr >> 2];
- shift = (addr & 3) * 8;
- mask = ((uint64_t)1 << (size * 8)) - 1;
- newval &= ~(mask << shift);
- newval |= val << shift;
- s->script_ram[addr >> 2] = newval;
-}
-
-static uint64_t lsi_ram_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- LSIState *s = opaque;
- uint32_t val;
- uint32_t mask;
-
- val = s->script_ram[addr >> 2];
- mask = ((uint64_t)1 << (size * 8)) - 1;
- val >>= (addr & 3) * 8;
- return val & mask;
-}
-
-static const MemoryRegionOps lsi_ram_ops = {
- .read = lsi_ram_read,
- .write = lsi_ram_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static uint64_t lsi_io_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- LSIState *s = opaque;
- return lsi_reg_readb(s, addr & 0xff);
-}
-
-static void lsi_io_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- LSIState *s = opaque;
- lsi_reg_writeb(s, addr & 0xff, val);
-}
-
-static const MemoryRegionOps lsi_io_ops = {
- .read = lsi_io_read,
- .write = lsi_io_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
-};
-
-static void lsi_scsi_reset(DeviceState *dev)
-{
- LSIState *s = LSI53C895A(dev);
-
- lsi_soft_reset(s);
-}
-
-static void lsi_pre_save(void *opaque)
-{
- LSIState *s = opaque;
-
- if (s->current) {
- assert(s->current->dma_buf == NULL);
- assert(s->current->dma_len == 0);
- }
- assert(QTAILQ_EMPTY(&s->queue));
-}
-
-static const VMStateDescription vmstate_lsi_scsi = {
- .name = "lsiscsi",
- .version_id = 0,
- .minimum_version_id = 0,
- .pre_save = lsi_pre_save,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(parent_obj, LSIState),
-
- VMSTATE_INT32(carry, LSIState),
- VMSTATE_INT32(status, LSIState),
- VMSTATE_INT32(msg_action, LSIState),
- VMSTATE_INT32(msg_len, LSIState),
- VMSTATE_BUFFER(msg, LSIState),
- VMSTATE_INT32(waiting, LSIState),
-
- VMSTATE_UINT32(dsa, LSIState),
- VMSTATE_UINT32(temp, LSIState),
- VMSTATE_UINT32(dnad, LSIState),
- VMSTATE_UINT32(dbc, LSIState),
- VMSTATE_UINT8(istat0, LSIState),
- VMSTATE_UINT8(istat1, LSIState),
- VMSTATE_UINT8(dcmd, LSIState),
- VMSTATE_UINT8(dstat, LSIState),
- VMSTATE_UINT8(dien, LSIState),
- VMSTATE_UINT8(sist0, LSIState),
- VMSTATE_UINT8(sist1, LSIState),
- VMSTATE_UINT8(sien0, LSIState),
- VMSTATE_UINT8(sien1, LSIState),
- VMSTATE_UINT8(mbox0, LSIState),
- VMSTATE_UINT8(mbox1, LSIState),
- VMSTATE_UINT8(dfifo, LSIState),
- VMSTATE_UINT8(ctest2, LSIState),
- VMSTATE_UINT8(ctest3, LSIState),
- VMSTATE_UINT8(ctest4, LSIState),
- VMSTATE_UINT8(ctest5, LSIState),
- VMSTATE_UINT8(ccntl0, LSIState),
- VMSTATE_UINT8(ccntl1, LSIState),
- VMSTATE_UINT32(dsp, LSIState),
- VMSTATE_UINT32(dsps, LSIState),
- VMSTATE_UINT8(dmode, LSIState),
- VMSTATE_UINT8(dcntl, LSIState),
- VMSTATE_UINT8(scntl0, LSIState),
- VMSTATE_UINT8(scntl1, LSIState),
- VMSTATE_UINT8(scntl2, LSIState),
- VMSTATE_UINT8(scntl3, LSIState),
- VMSTATE_UINT8(sstat0, LSIState),
- VMSTATE_UINT8(sstat1, LSIState),
- VMSTATE_UINT8(scid, LSIState),
- VMSTATE_UINT8(sxfer, LSIState),
- VMSTATE_UINT8(socl, LSIState),
- VMSTATE_UINT8(sdid, LSIState),
- VMSTATE_UINT8(ssid, LSIState),
- VMSTATE_UINT8(sfbr, LSIState),
- VMSTATE_UINT8(stest1, LSIState),
- VMSTATE_UINT8(stest2, LSIState),
- VMSTATE_UINT8(stest3, LSIState),
- VMSTATE_UINT8(sidl, LSIState),
- VMSTATE_UINT8(stime0, LSIState),
- VMSTATE_UINT8(respid0, LSIState),
- VMSTATE_UINT8(respid1, LSIState),
- VMSTATE_UINT32(mmrs, LSIState),
- VMSTATE_UINT32(mmws, LSIState),
- VMSTATE_UINT32(sfs, LSIState),
- VMSTATE_UINT32(drs, LSIState),
- VMSTATE_UINT32(sbms, LSIState),
- VMSTATE_UINT32(dbms, LSIState),
- VMSTATE_UINT32(dnad64, LSIState),
- VMSTATE_UINT32(pmjad1, LSIState),
- VMSTATE_UINT32(pmjad2, LSIState),
- VMSTATE_UINT32(rbc, LSIState),
- VMSTATE_UINT32(ua, LSIState),
- VMSTATE_UINT32(ia, LSIState),
- VMSTATE_UINT32(sbc, LSIState),
- VMSTATE_UINT32(csbc, LSIState),
- VMSTATE_BUFFER_UNSAFE(scratch, LSIState, 0, 18 * sizeof(uint32_t)),
- VMSTATE_UINT8(sbr, LSIState),
-
- VMSTATE_BUFFER_UNSAFE(script_ram, LSIState, 0, 2048 * sizeof(uint32_t)),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const struct SCSIBusInfo lsi_scsi_info = {
- .tcq = true,
- .max_target = LSI_MAX_DEVS,
- .max_lun = 0, /* LUN support is buggy */
-
- .transfer_data = lsi_transfer_data,
- .complete = lsi_command_complete,
- .cancel = lsi_request_cancelled
-};
-
-static void lsi_scsi_realize(PCIDevice *dev, Error **errp)
-{
- LSIState *s = LSI53C895A(dev);
- DeviceState *d = DEVICE(dev);
- uint8_t *pci_conf;
-
- pci_conf = dev->config;
-
- /* PCI latency timer = 255 */
- pci_conf[PCI_LATENCY_TIMER] = 0xff;
- /* Interrupt pin A */
- pci_conf[PCI_INTERRUPT_PIN] = 0x01;
-
- memory_region_init_io(&s->mmio_io, OBJECT(s), &lsi_mmio_ops, s,
- "lsi-mmio", 0x400);
- memory_region_init_io(&s->ram_io, OBJECT(s), &lsi_ram_ops, s,
- "lsi-ram", 0x2000);
- memory_region_init_io(&s->io_io, OBJECT(s), &lsi_io_ops, s,
- "lsi-io", 256);
-
- pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_io);
- pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio_io);
- pci_register_bar(dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->ram_io);
- QTAILQ_INIT(&s->queue);
-
- scsi_bus_new(&s->bus, sizeof(s->bus), d, &lsi_scsi_info, NULL);
- if (!d->hotplugged) {
- scsi_bus_legacy_handle_cmdline(&s->bus, errp);
- }
-}
-
-static void lsi_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = lsi_scsi_realize;
- k->vendor_id = PCI_VENDOR_ID_LSI_LOGIC;
- k->device_id = PCI_DEVICE_ID_LSI_53C895A;
- k->class_id = PCI_CLASS_STORAGE_SCSI;
- k->subsystem_id = 0x1000;
- dc->reset = lsi_scsi_reset;
- dc->vmsd = &vmstate_lsi_scsi;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
-}
-
-static const TypeInfo lsi_info = {
- .name = TYPE_LSI53C895A,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(LSIState),
- .class_init = lsi_class_init,
-};
-
-static void lsi53c810_class_init(ObjectClass *klass, void *data)
-{
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->device_id = PCI_DEVICE_ID_LSI_53C810;
-}
-
-static TypeInfo lsi53c810_info = {
- .name = TYPE_LSI53C810,
- .parent = TYPE_LSI53C895A,
- .class_init = lsi53c810_class_init,
-};
-
-static void lsi53c895a_register_types(void)
-{
- type_register_static(&lsi_info);
- type_register_static(&lsi53c810_info);
-}
-
-type_init(lsi53c895a_register_types)
diff --git a/qemu/hw/scsi/megasas.c b/qemu/hw/scsi/megasas.c
deleted file mode 100644
index a63a58155..000000000
--- a/qemu/hw/scsi/megasas.c
+++ /dev/null
@@ -1,2548 +0,0 @@
-/*
- * QEMU MegaRAID SAS 8708EM2 Host Bus Adapter emulation
- * Based on the linux driver code at drivers/scsi/megaraid
- *
- * Copyright (c) 2009-2012 Hannes Reinecke, SUSE Labs
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/pci/pci.h"
-#include "sysemu/dma.h"
-#include "sysemu/block-backend.h"
-#include "hw/pci/msi.h"
-#include "hw/pci/msix.h"
-#include "qemu/iov.h"
-#include "hw/scsi/scsi.h"
-#include "block/scsi.h"
-#include "trace.h"
-
-#include "mfi.h"
-
-#define MEGASAS_VERSION_GEN1 "1.70"
-#define MEGASAS_VERSION_GEN2 "1.80"
-#define MEGASAS_MAX_FRAMES 2048 /* Firmware limit at 65535 */
-#define MEGASAS_DEFAULT_FRAMES 1000 /* Windows requires this */
-#define MEGASAS_GEN2_DEFAULT_FRAMES 1008 /* Windows requires this */
-#define MEGASAS_MAX_SGE 128 /* Firmware limit */
-#define MEGASAS_DEFAULT_SGE 80
-#define MEGASAS_MAX_SECTORS 0xFFFF /* No real limit */
-#define MEGASAS_MAX_ARRAYS 128
-
-#define MEGASAS_HBA_SERIAL "QEMU123456"
-#define NAA_LOCALLY_ASSIGNED_ID 0x3ULL
-#define IEEE_COMPANY_LOCALLY_ASSIGNED 0x525400
-
-#define MEGASAS_FLAG_USE_JBOD 0
-#define MEGASAS_MASK_USE_JBOD (1 << MEGASAS_FLAG_USE_JBOD)
-#define MEGASAS_FLAG_USE_MSI 1
-#define MEGASAS_MASK_USE_MSI (1 << MEGASAS_FLAG_USE_MSI)
-#define MEGASAS_FLAG_USE_MSIX 2
-#define MEGASAS_MASK_USE_MSIX (1 << MEGASAS_FLAG_USE_MSIX)
-#define MEGASAS_FLAG_USE_QUEUE64 3
-#define MEGASAS_MASK_USE_QUEUE64 (1 << MEGASAS_FLAG_USE_QUEUE64)
-
-static const char *mfi_frame_desc[] = {
- "MFI init", "LD Read", "LD Write", "LD SCSI", "PD SCSI",
- "MFI Doorbell", "MFI Abort", "MFI SMP", "MFI Stop"};
-
-typedef struct MegasasCmd {
- uint32_t index;
- uint16_t flags;
- uint16_t count;
- uint64_t context;
-
- hwaddr pa;
- hwaddr pa_size;
- union mfi_frame *frame;
- SCSIRequest *req;
- QEMUSGList qsg;
- void *iov_buf;
- size_t iov_size;
- size_t iov_offset;
- struct MegasasState *state;
-} MegasasCmd;
-
-typedef struct MegasasState {
- /*< private >*/
- PCIDevice parent_obj;
- /*< public >*/
-
- MemoryRegion mmio_io;
- MemoryRegion port_io;
- MemoryRegion queue_io;
- uint32_t frame_hi;
-
- int fw_state;
- uint32_t fw_sge;
- uint32_t fw_cmds;
- uint32_t flags;
- int fw_luns;
- int intr_mask;
- int doorbell;
- int busy;
- int diag;
- int adp_reset;
-
- MegasasCmd *event_cmd;
- int event_locale;
- int event_class;
- int event_count;
- int shutdown_event;
- int boot_event;
-
- uint64_t sas_addr;
- char *hba_serial;
-
- uint64_t reply_queue_pa;
- void *reply_queue;
- int reply_queue_len;
- int reply_queue_head;
- int reply_queue_tail;
- uint64_t consumer_pa;
- uint64_t producer_pa;
-
- MegasasCmd frames[MEGASAS_MAX_FRAMES];
- DECLARE_BITMAP(frame_map, MEGASAS_MAX_FRAMES);
- SCSIBus bus;
-} MegasasState;
-
-typedef struct MegasasBaseClass {
- PCIDeviceClass parent_class;
- const char *product_name;
- const char *product_version;
- int mmio_bar;
- int ioport_bar;
- int osts;
-} MegasasBaseClass;
-
-#define TYPE_MEGASAS_BASE "megasas-base"
-#define TYPE_MEGASAS_GEN1 "megasas"
-#define TYPE_MEGASAS_GEN2 "megasas-gen2"
-
-#define MEGASAS(obj) \
- OBJECT_CHECK(MegasasState, (obj), TYPE_MEGASAS_BASE)
-
-#define MEGASAS_DEVICE_CLASS(oc) \
- OBJECT_CLASS_CHECK(MegasasBaseClass, (oc), TYPE_MEGASAS_BASE)
-#define MEGASAS_DEVICE_GET_CLASS(oc) \
- OBJECT_GET_CLASS(MegasasBaseClass, (oc), TYPE_MEGASAS_BASE)
-
-#define MEGASAS_INTR_DISABLED_MASK 0xFFFFFFFF
-
-static bool megasas_intr_enabled(MegasasState *s)
-{
- if ((s->intr_mask & MEGASAS_INTR_DISABLED_MASK) !=
- MEGASAS_INTR_DISABLED_MASK) {
- return true;
- }
- return false;
-}
-
-static bool megasas_use_queue64(MegasasState *s)
-{
- return s->flags & MEGASAS_MASK_USE_QUEUE64;
-}
-
-static bool megasas_use_msi(MegasasState *s)
-{
- return s->flags & MEGASAS_MASK_USE_MSI;
-}
-
-static bool megasas_use_msix(MegasasState *s)
-{
- return s->flags & MEGASAS_MASK_USE_MSIX;
-}
-
-static bool megasas_is_jbod(MegasasState *s)
-{
- return s->flags & MEGASAS_MASK_USE_JBOD;
-}
-
-static void megasas_frame_set_cmd_status(MegasasState *s,
- unsigned long frame, uint8_t v)
-{
- PCIDevice *pci = &s->parent_obj;
- stb_pci_dma(pci, frame + offsetof(struct mfi_frame_header, cmd_status), v);
-}
-
-static void megasas_frame_set_scsi_status(MegasasState *s,
- unsigned long frame, uint8_t v)
-{
- PCIDevice *pci = &s->parent_obj;
- stb_pci_dma(pci, frame + offsetof(struct mfi_frame_header, scsi_status), v);
-}
-
-/*
- * Context is considered opaque, but the HBA firmware is running
- * in little endian mode. So convert it to little endian, too.
- */
-static uint64_t megasas_frame_get_context(MegasasState *s,
- unsigned long frame)
-{
- PCIDevice *pci = &s->parent_obj;
- return ldq_le_pci_dma(pci, frame + offsetof(struct mfi_frame_header, context));
-}
-
-static bool megasas_frame_is_ieee_sgl(MegasasCmd *cmd)
-{
- return cmd->flags & MFI_FRAME_IEEE_SGL;
-}
-
-static bool megasas_frame_is_sgl64(MegasasCmd *cmd)
-{
- return cmd->flags & MFI_FRAME_SGL64;
-}
-
-static bool megasas_frame_is_sense64(MegasasCmd *cmd)
-{
- return cmd->flags & MFI_FRAME_SENSE64;
-}
-
-static uint64_t megasas_sgl_get_addr(MegasasCmd *cmd,
- union mfi_sgl *sgl)
-{
- uint64_t addr;
-
- if (megasas_frame_is_ieee_sgl(cmd)) {
- addr = le64_to_cpu(sgl->sg_skinny->addr);
- } else if (megasas_frame_is_sgl64(cmd)) {
- addr = le64_to_cpu(sgl->sg64->addr);
- } else {
- addr = le32_to_cpu(sgl->sg32->addr);
- }
- return addr;
-}
-
-static uint32_t megasas_sgl_get_len(MegasasCmd *cmd,
- union mfi_sgl *sgl)
-{
- uint32_t len;
-
- if (megasas_frame_is_ieee_sgl(cmd)) {
- len = le32_to_cpu(sgl->sg_skinny->len);
- } else if (megasas_frame_is_sgl64(cmd)) {
- len = le32_to_cpu(sgl->sg64->len);
- } else {
- len = le32_to_cpu(sgl->sg32->len);
- }
- return len;
-}
-
-static union mfi_sgl *megasas_sgl_next(MegasasCmd *cmd,
- union mfi_sgl *sgl)
-{
- uint8_t *next = (uint8_t *)sgl;
-
- if (megasas_frame_is_ieee_sgl(cmd)) {
- next += sizeof(struct mfi_sg_skinny);
- } else if (megasas_frame_is_sgl64(cmd)) {
- next += sizeof(struct mfi_sg64);
- } else {
- next += sizeof(struct mfi_sg32);
- }
-
- if (next >= (uint8_t *)cmd->frame + cmd->pa_size) {
- return NULL;
- }
- return (union mfi_sgl *)next;
-}
-
-static void megasas_soft_reset(MegasasState *s);
-
-static int megasas_map_sgl(MegasasState *s, MegasasCmd *cmd, union mfi_sgl *sgl)
-{
- int i;
- int iov_count = 0;
- size_t iov_size = 0;
-
- cmd->flags = le16_to_cpu(cmd->frame->header.flags);
- iov_count = cmd->frame->header.sge_count;
- if (iov_count > MEGASAS_MAX_SGE) {
- trace_megasas_iovec_sgl_overflow(cmd->index, iov_count,
- MEGASAS_MAX_SGE);
- return iov_count;
- }
- pci_dma_sglist_init(&cmd->qsg, PCI_DEVICE(s), iov_count);
- for (i = 0; i < iov_count; i++) {
- dma_addr_t iov_pa, iov_size_p;
-
- if (!sgl) {
- trace_megasas_iovec_sgl_underflow(cmd->index, i);
- goto unmap;
- }
- iov_pa = megasas_sgl_get_addr(cmd, sgl);
- iov_size_p = megasas_sgl_get_len(cmd, sgl);
- if (!iov_pa || !iov_size_p) {
- trace_megasas_iovec_sgl_invalid(cmd->index, i,
- iov_pa, iov_size_p);
- goto unmap;
- }
- qemu_sglist_add(&cmd->qsg, iov_pa, iov_size_p);
- sgl = megasas_sgl_next(cmd, sgl);
- iov_size += (size_t)iov_size_p;
- }
- if (cmd->iov_size > iov_size) {
- trace_megasas_iovec_overflow(cmd->index, iov_size, cmd->iov_size);
- } else if (cmd->iov_size < iov_size) {
- trace_megasas_iovec_underflow(cmd->iov_size, iov_size, cmd->iov_size);
- }
- cmd->iov_offset = 0;
- return 0;
-unmap:
- qemu_sglist_destroy(&cmd->qsg);
- return iov_count - i;
-}
-
-static void megasas_unmap_sgl(MegasasCmd *cmd)
-{
- qemu_sglist_destroy(&cmd->qsg);
- cmd->iov_offset = 0;
-}
-
-/*
- * passthrough sense and io sense are at the same offset
- */
-static int megasas_build_sense(MegasasCmd *cmd, uint8_t *sense_ptr,
- uint8_t sense_len)
-{
- PCIDevice *pcid = PCI_DEVICE(cmd->state);
- uint32_t pa_hi = 0, pa_lo;
- hwaddr pa;
-
- if (sense_len > cmd->frame->header.sense_len) {
- sense_len = cmd->frame->header.sense_len;
- }
- if (sense_len) {
- pa_lo = le32_to_cpu(cmd->frame->pass.sense_addr_lo);
- if (megasas_frame_is_sense64(cmd)) {
- pa_hi = le32_to_cpu(cmd->frame->pass.sense_addr_hi);
- }
- pa = ((uint64_t) pa_hi << 32) | pa_lo;
- pci_dma_write(pcid, pa, sense_ptr, sense_len);
- cmd->frame->header.sense_len = sense_len;
- }
- return sense_len;
-}
-
-static void megasas_write_sense(MegasasCmd *cmd, SCSISense sense)
-{
- uint8_t sense_buf[SCSI_SENSE_BUF_SIZE];
- uint8_t sense_len = 18;
-
- memset(sense_buf, 0, sense_len);
- sense_buf[0] = 0xf0;
- sense_buf[2] = sense.key;
- sense_buf[7] = 10;
- sense_buf[12] = sense.asc;
- sense_buf[13] = sense.ascq;
- megasas_build_sense(cmd, sense_buf, sense_len);
-}
-
-static void megasas_copy_sense(MegasasCmd *cmd)
-{
- uint8_t sense_buf[SCSI_SENSE_BUF_SIZE];
- uint8_t sense_len;
-
- sense_len = scsi_req_get_sense(cmd->req, sense_buf,
- SCSI_SENSE_BUF_SIZE);
- megasas_build_sense(cmd, sense_buf, sense_len);
-}
-
-/*
- * Format an INQUIRY CDB
- */
-static int megasas_setup_inquiry(uint8_t *cdb, int pg, int len)
-{
- memset(cdb, 0, 6);
- cdb[0] = INQUIRY;
- if (pg > 0) {
- cdb[1] = 0x1;
- cdb[2] = pg;
- }
- cdb[3] = (len >> 8) & 0xff;
- cdb[4] = (len & 0xff);
- return len;
-}
-
-/*
- * Encode lba and len into a READ_16/WRITE_16 CDB
- */
-static void megasas_encode_lba(uint8_t *cdb, uint64_t lba,
- uint32_t len, bool is_write)
-{
- memset(cdb, 0x0, 16);
- if (is_write) {
- cdb[0] = WRITE_16;
- } else {
- cdb[0] = READ_16;
- }
- cdb[2] = (lba >> 56) & 0xff;
- cdb[3] = (lba >> 48) & 0xff;
- cdb[4] = (lba >> 40) & 0xff;
- cdb[5] = (lba >> 32) & 0xff;
- cdb[6] = (lba >> 24) & 0xff;
- cdb[7] = (lba >> 16) & 0xff;
- cdb[8] = (lba >> 8) & 0xff;
- cdb[9] = (lba) & 0xff;
- cdb[10] = (len >> 24) & 0xff;
- cdb[11] = (len >> 16) & 0xff;
- cdb[12] = (len >> 8) & 0xff;
- cdb[13] = (len) & 0xff;
-}
-
-/*
- * Utility functions
- */
-static uint64_t megasas_fw_time(void)
-{
- struct tm curtime;
- uint64_t bcd_time;
-
- qemu_get_timedate(&curtime, 0);
- bcd_time = ((uint64_t)curtime.tm_sec & 0xff) << 48 |
- ((uint64_t)curtime.tm_min & 0xff) << 40 |
- ((uint64_t)curtime.tm_hour & 0xff) << 32 |
- ((uint64_t)curtime.tm_mday & 0xff) << 24 |
- ((uint64_t)curtime.tm_mon & 0xff) << 16 |
- ((uint64_t)(curtime.tm_year + 1900) & 0xffff);
-
- return bcd_time;
-}
-
-/*
- * Default disk sata address
- * 0x1221 is the magic number as
- * present in real hardware,
- * so use it here, too.
- */
-static uint64_t megasas_get_sata_addr(uint16_t id)
-{
- uint64_t addr = (0x1221ULL << 48);
- return addr | ((uint64_t)id << 24);
-}
-
-/*
- * Frame handling
- */
-static int megasas_next_index(MegasasState *s, int index, int limit)
-{
- index++;
- if (index == limit) {
- index = 0;
- }
- return index;
-}
-
-static MegasasCmd *megasas_lookup_frame(MegasasState *s,
- hwaddr frame)
-{
- MegasasCmd *cmd = NULL;
- int num = 0, index;
-
- index = s->reply_queue_head;
-
- while (num < s->fw_cmds) {
- if (s->frames[index].pa && s->frames[index].pa == frame) {
- cmd = &s->frames[index];
- break;
- }
- index = megasas_next_index(s, index, s->fw_cmds);
- num++;
- }
-
- return cmd;
-}
-
-static void megasas_unmap_frame(MegasasState *s, MegasasCmd *cmd)
-{
- PCIDevice *p = PCI_DEVICE(s);
-
- pci_dma_unmap(p, cmd->frame, cmd->pa_size, 0, 0);
- cmd->frame = NULL;
- cmd->pa = 0;
- clear_bit(cmd->index, s->frame_map);
-}
-
-/*
- * This absolutely needs to be locked if
- * qemu ever goes multithreaded.
- */
-static MegasasCmd *megasas_enqueue_frame(MegasasState *s,
- hwaddr frame, uint64_t context, int count)
-{
- PCIDevice *pcid = PCI_DEVICE(s);
- MegasasCmd *cmd = NULL;
- int frame_size = MFI_FRAME_SIZE * 16;
- hwaddr frame_size_p = frame_size;
- unsigned long index;
-
- index = 0;
- while (index < s->fw_cmds) {
- index = find_next_zero_bit(s->frame_map, s->fw_cmds, index);
- if (!s->frames[index].pa)
- break;
- /* Busy frame found */
- trace_megasas_qf_mapped(index);
- }
- if (index >= s->fw_cmds) {
- /* All frames busy */
- trace_megasas_qf_busy(frame);
- return NULL;
- }
- cmd = &s->frames[index];
- set_bit(index, s->frame_map);
- trace_megasas_qf_new(index, frame);
-
- cmd->pa = frame;
- /* Map all possible frames */
- cmd->frame = pci_dma_map(pcid, frame, &frame_size_p, 0);
- if (frame_size_p != frame_size) {
- trace_megasas_qf_map_failed(cmd->index, (unsigned long)frame);
- if (cmd->frame) {
- megasas_unmap_frame(s, cmd);
- }
- s->event_count++;
- return NULL;
- }
- cmd->pa_size = frame_size_p;
- cmd->context = context;
- if (!megasas_use_queue64(s)) {
- cmd->context &= (uint64_t)0xFFFFFFFF;
- }
- cmd->count = count;
- s->busy++;
-
- if (s->consumer_pa) {
- s->reply_queue_tail = ldl_le_pci_dma(pcid, s->consumer_pa);
- }
- trace_megasas_qf_enqueue(cmd->index, cmd->count, cmd->context,
- s->reply_queue_head, s->reply_queue_tail, s->busy);
-
- return cmd;
-}
-
-static void megasas_complete_frame(MegasasState *s, uint64_t context)
-{
- PCIDevice *pci_dev = PCI_DEVICE(s);
- int tail, queue_offset;
-
- /* Decrement busy count */
- s->busy--;
- if (s->reply_queue_pa) {
- /*
- * Put command on the reply queue.
- * Context is opaque, but emulation is running in
- * little endian. So convert it.
- */
- if (megasas_use_queue64(s)) {
- queue_offset = s->reply_queue_head * sizeof(uint64_t);
- stq_le_pci_dma(pci_dev, s->reply_queue_pa + queue_offset, context);
- } else {
- queue_offset = s->reply_queue_head * sizeof(uint32_t);
- stl_le_pci_dma(pci_dev, s->reply_queue_pa + queue_offset, context);
- }
- s->reply_queue_tail = ldl_le_pci_dma(pci_dev, s->consumer_pa);
- trace_megasas_qf_complete(context, s->reply_queue_head,
- s->reply_queue_tail, s->busy);
- }
-
- if (megasas_intr_enabled(s)) {
- /* Update reply queue pointer */
- s->reply_queue_tail = ldl_le_pci_dma(pci_dev, s->consumer_pa);
- tail = s->reply_queue_head;
- s->reply_queue_head = megasas_next_index(s, tail, s->fw_cmds);
- trace_megasas_qf_update(s->reply_queue_head, s->reply_queue_tail,
- s->busy);
- stl_le_pci_dma(pci_dev, s->producer_pa, s->reply_queue_head);
- /* Notify HBA */
- if (msix_enabled(pci_dev)) {
- trace_megasas_msix_raise(0);
- msix_notify(pci_dev, 0);
- } else if (msi_enabled(pci_dev)) {
- trace_megasas_msi_raise(0);
- msi_notify(pci_dev, 0);
- } else {
- s->doorbell++;
- if (s->doorbell == 1) {
- trace_megasas_irq_raise();
- pci_irq_assert(pci_dev);
- }
- }
- } else {
- trace_megasas_qf_complete_noirq(context);
- }
-}
-
-static void megasas_reset_frames(MegasasState *s)
-{
- int i;
- MegasasCmd *cmd;
-
- for (i = 0; i < s->fw_cmds; i++) {
- cmd = &s->frames[i];
- if (cmd->pa) {
- megasas_unmap_frame(s, cmd);
- }
- }
- bitmap_zero(s->frame_map, MEGASAS_MAX_FRAMES);
-}
-
-static void megasas_abort_command(MegasasCmd *cmd)
-{
- if (cmd->req) {
- scsi_req_cancel(cmd->req);
- cmd->req = NULL;
- }
-}
-
-static int megasas_init_firmware(MegasasState *s, MegasasCmd *cmd)
-{
- PCIDevice *pcid = PCI_DEVICE(s);
- uint32_t pa_hi, pa_lo;
- hwaddr iq_pa, initq_size = sizeof(struct mfi_init_qinfo);
- struct mfi_init_qinfo *initq = NULL;
- uint32_t flags;
- int ret = MFI_STAT_OK;
-
- if (s->reply_queue_pa) {
- trace_megasas_initq_mapped(s->reply_queue_pa);
- goto out;
- }
- pa_lo = le32_to_cpu(cmd->frame->init.qinfo_new_addr_lo);
- pa_hi = le32_to_cpu(cmd->frame->init.qinfo_new_addr_hi);
- iq_pa = (((uint64_t) pa_hi << 32) | pa_lo);
- trace_megasas_init_firmware((uint64_t)iq_pa);
- initq = pci_dma_map(pcid, iq_pa, &initq_size, 0);
- if (!initq || initq_size != sizeof(*initq)) {
- trace_megasas_initq_map_failed(cmd->index);
- s->event_count++;
- ret = MFI_STAT_MEMORY_NOT_AVAILABLE;
- goto out;
- }
- s->reply_queue_len = le32_to_cpu(initq->rq_entries) & 0xFFFF;
- if (s->reply_queue_len > s->fw_cmds) {
- trace_megasas_initq_mismatch(s->reply_queue_len, s->fw_cmds);
- s->event_count++;
- ret = MFI_STAT_INVALID_PARAMETER;
- goto out;
- }
- pa_lo = le32_to_cpu(initq->rq_addr_lo);
- pa_hi = le32_to_cpu(initq->rq_addr_hi);
- s->reply_queue_pa = ((uint64_t) pa_hi << 32) | pa_lo;
- pa_lo = le32_to_cpu(initq->ci_addr_lo);
- pa_hi = le32_to_cpu(initq->ci_addr_hi);
- s->consumer_pa = ((uint64_t) pa_hi << 32) | pa_lo;
- pa_lo = le32_to_cpu(initq->pi_addr_lo);
- pa_hi = le32_to_cpu(initq->pi_addr_hi);
- s->producer_pa = ((uint64_t) pa_hi << 32) | pa_lo;
- s->reply_queue_head = ldl_le_pci_dma(pcid, s->producer_pa);
- s->reply_queue_tail = ldl_le_pci_dma(pcid, s->consumer_pa);
- flags = le32_to_cpu(initq->flags);
- if (flags & MFI_QUEUE_FLAG_CONTEXT64) {
- s->flags |= MEGASAS_MASK_USE_QUEUE64;
- }
- trace_megasas_init_queue((unsigned long)s->reply_queue_pa,
- s->reply_queue_len, s->reply_queue_head,
- s->reply_queue_tail, flags);
- megasas_reset_frames(s);
- s->fw_state = MFI_FWSTATE_OPERATIONAL;
-out:
- if (initq) {
- pci_dma_unmap(pcid, initq, initq_size, 0, 0);
- }
- return ret;
-}
-
-static int megasas_map_dcmd(MegasasState *s, MegasasCmd *cmd)
-{
- dma_addr_t iov_pa, iov_size;
-
- cmd->flags = le16_to_cpu(cmd->frame->header.flags);
- if (!cmd->frame->header.sge_count) {
- trace_megasas_dcmd_zero_sge(cmd->index);
- cmd->iov_size = 0;
- return 0;
- } else if (cmd->frame->header.sge_count > 1) {
- trace_megasas_dcmd_invalid_sge(cmd->index,
- cmd->frame->header.sge_count);
- cmd->iov_size = 0;
- return -1;
- }
- iov_pa = megasas_sgl_get_addr(cmd, &cmd->frame->dcmd.sgl);
- iov_size = megasas_sgl_get_len(cmd, &cmd->frame->dcmd.sgl);
- pci_dma_sglist_init(&cmd->qsg, PCI_DEVICE(s), 1);
- qemu_sglist_add(&cmd->qsg, iov_pa, iov_size);
- cmd->iov_size = iov_size;
- return cmd->iov_size;
-}
-
-static void megasas_finish_dcmd(MegasasCmd *cmd, uint32_t iov_size)
-{
- trace_megasas_finish_dcmd(cmd->index, iov_size);
-
- if (cmd->frame->header.sge_count) {
- qemu_sglist_destroy(&cmd->qsg);
- }
- if (iov_size > cmd->iov_size) {
- if (megasas_frame_is_ieee_sgl(cmd)) {
- cmd->frame->dcmd.sgl.sg_skinny->len = cpu_to_le32(iov_size);
- } else if (megasas_frame_is_sgl64(cmd)) {
- cmd->frame->dcmd.sgl.sg64->len = cpu_to_le32(iov_size);
- } else {
- cmd->frame->dcmd.sgl.sg32->len = cpu_to_le32(iov_size);
- }
- }
- cmd->iov_size = 0;
-}
-
-static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd)
-{
- PCIDevice *pci_dev = PCI_DEVICE(s);
- PCIDeviceClass *pci_class = PCI_DEVICE_GET_CLASS(pci_dev);
- MegasasBaseClass *base_class = MEGASAS_DEVICE_GET_CLASS(s);
- struct mfi_ctrl_info info;
- size_t dcmd_size = sizeof(info);
- BusChild *kid;
- int num_pd_disks = 0;
-
- memset(&info, 0x0, dcmd_size);
- if (cmd->iov_size < dcmd_size) {
- trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size,
- dcmd_size);
- return MFI_STAT_INVALID_PARAMETER;
- }
-
- info.pci.vendor = cpu_to_le16(pci_class->vendor_id);
- info.pci.device = cpu_to_le16(pci_class->device_id);
- info.pci.subvendor = cpu_to_le16(pci_class->subsystem_vendor_id);
- info.pci.subdevice = cpu_to_le16(pci_class->subsystem_id);
-
- /*
- * For some reason the firmware supports
- * only up to 8 device ports.
- * Despite supporting a far larger number
- * of devices for the physical devices.
- * So just display the first 8 devices
- * in the device port list, independent
- * of how many logical devices are actually
- * present.
- */
- info.host.type = MFI_INFO_HOST_PCIE;
- info.device.type = MFI_INFO_DEV_SAS3G;
- info.device.port_count = 8;
- QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
- SCSIDevice *sdev = SCSI_DEVICE(kid->child);
- uint16_t pd_id;
-
- if (num_pd_disks < 8) {
- pd_id = ((sdev->id & 0xFF) << 8) | (sdev->lun & 0xFF);
- info.device.port_addr[num_pd_disks] =
- cpu_to_le64(megasas_get_sata_addr(pd_id));
- }
- num_pd_disks++;
- }
-
- memcpy(info.product_name, base_class->product_name, 24);
- snprintf(info.serial_number, 32, "%s", s->hba_serial);
- snprintf(info.package_version, 0x60, "%s-QEMU", qemu_hw_version());
- memcpy(info.image_component[0].name, "APP", 3);
- snprintf(info.image_component[0].version, 10, "%s-QEMU",
- base_class->product_version);
- memcpy(info.image_component[0].build_date, "Apr 1 2014", 11);
- memcpy(info.image_component[0].build_time, "12:34:56", 8);
- info.image_component_count = 1;
- if (pci_dev->has_rom) {
- uint8_t biosver[32];
- uint8_t *ptr;
-
- ptr = memory_region_get_ram_ptr(&pci_dev->rom);
- memcpy(biosver, ptr + 0x41, 31);
- memcpy(info.image_component[1].name, "BIOS", 4);
- memcpy(info.image_component[1].version, biosver,
- strlen((const char *)biosver));
- info.image_component_count++;
- }
- info.current_fw_time = cpu_to_le32(megasas_fw_time());
- info.max_arms = 32;
- info.max_spans = 8;
- info.max_arrays = MEGASAS_MAX_ARRAYS;
- info.max_lds = MFI_MAX_LD;
- info.max_cmds = cpu_to_le16(s->fw_cmds);
- info.max_sg_elements = cpu_to_le16(s->fw_sge);
- info.max_request_size = cpu_to_le32(MEGASAS_MAX_SECTORS);
- if (!megasas_is_jbod(s))
- info.lds_present = cpu_to_le16(num_pd_disks);
- info.pd_present = cpu_to_le16(num_pd_disks);
- info.pd_disks_present = cpu_to_le16(num_pd_disks);
- info.hw_present = cpu_to_le32(MFI_INFO_HW_NVRAM |
- MFI_INFO_HW_MEM |
- MFI_INFO_HW_FLASH);
- info.memory_size = cpu_to_le16(512);
- info.nvram_size = cpu_to_le16(32);
- info.flash_size = cpu_to_le16(16);
- info.raid_levels = cpu_to_le32(MFI_INFO_RAID_0);
- info.adapter_ops = cpu_to_le32(MFI_INFO_AOPS_RBLD_RATE |
- MFI_INFO_AOPS_SELF_DIAGNOSTIC |
- MFI_INFO_AOPS_MIXED_ARRAY);
- info.ld_ops = cpu_to_le32(MFI_INFO_LDOPS_DISK_CACHE_POLICY |
- MFI_INFO_LDOPS_ACCESS_POLICY |
- MFI_INFO_LDOPS_IO_POLICY |
- MFI_INFO_LDOPS_WRITE_POLICY |
- MFI_INFO_LDOPS_READ_POLICY);
- info.max_strips_per_io = cpu_to_le16(s->fw_sge);
- info.stripe_sz_ops.min = 3;
- info.stripe_sz_ops.max = ctz32(MEGASAS_MAX_SECTORS + 1);
- info.properties.pred_fail_poll_interval = cpu_to_le16(300);
- info.properties.intr_throttle_cnt = cpu_to_le16(16);
- info.properties.intr_throttle_timeout = cpu_to_le16(50);
- info.properties.rebuild_rate = 30;
- info.properties.patrol_read_rate = 30;
- info.properties.bgi_rate = 30;
- info.properties.cc_rate = 30;
- info.properties.recon_rate = 30;
- info.properties.cache_flush_interval = 4;
- info.properties.spinup_drv_cnt = 2;
- info.properties.spinup_delay = 6;
- info.properties.ecc_bucket_size = 15;
- info.properties.ecc_bucket_leak_rate = cpu_to_le16(1440);
- info.properties.expose_encl_devices = 1;
- info.properties.OnOffProperties = cpu_to_le32(MFI_CTRL_PROP_EnableJBOD);
- info.pd_ops = cpu_to_le32(MFI_INFO_PDOPS_FORCE_ONLINE |
- MFI_INFO_PDOPS_FORCE_OFFLINE);
- info.pd_mix_support = cpu_to_le32(MFI_INFO_PDMIX_SAS |
- MFI_INFO_PDMIX_SATA |
- MFI_INFO_PDMIX_LD);
-
- cmd->iov_size -= dma_buf_read((uint8_t *)&info, dcmd_size, &cmd->qsg);
- return MFI_STAT_OK;
-}
-
-static int megasas_mfc_get_defaults(MegasasState *s, MegasasCmd *cmd)
-{
- struct mfi_defaults info;
- size_t dcmd_size = sizeof(struct mfi_defaults);
-
- memset(&info, 0x0, dcmd_size);
- if (cmd->iov_size < dcmd_size) {
- trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size,
- dcmd_size);
- return MFI_STAT_INVALID_PARAMETER;
- }
-
- info.sas_addr = cpu_to_le64(s->sas_addr);
- info.stripe_size = 3;
- info.flush_time = 4;
- info.background_rate = 30;
- info.allow_mix_in_enclosure = 1;
- info.allow_mix_in_ld = 1;
- info.direct_pd_mapping = 1;
- /* Enable for BIOS support */
- info.bios_enumerate_lds = 1;
- info.disable_ctrl_r = 1;
- info.expose_enclosure_devices = 1;
- info.disable_preboot_cli = 1;
- info.cluster_disable = 1;
-
- cmd->iov_size -= dma_buf_read((uint8_t *)&info, dcmd_size, &cmd->qsg);
- return MFI_STAT_OK;
-}
-
-static int megasas_dcmd_get_bios_info(MegasasState *s, MegasasCmd *cmd)
-{
- struct mfi_bios_data info;
- size_t dcmd_size = sizeof(info);
-
- memset(&info, 0x0, dcmd_size);
- if (cmd->iov_size < dcmd_size) {
- trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size,
- dcmd_size);
- return MFI_STAT_INVALID_PARAMETER;
- }
- info.continue_on_error = 1;
- info.verbose = 1;
- if (megasas_is_jbod(s)) {
- info.expose_all_drives = 1;
- }
-
- cmd->iov_size -= dma_buf_read((uint8_t *)&info, dcmd_size, &cmd->qsg);
- return MFI_STAT_OK;
-}
-
-static int megasas_dcmd_get_fw_time(MegasasState *s, MegasasCmd *cmd)
-{
- uint64_t fw_time;
- size_t dcmd_size = sizeof(fw_time);
-
- fw_time = cpu_to_le64(megasas_fw_time());
-
- cmd->iov_size -= dma_buf_read((uint8_t *)&fw_time, dcmd_size, &cmd->qsg);
- return MFI_STAT_OK;
-}
-
-static int megasas_dcmd_set_fw_time(MegasasState *s, MegasasCmd *cmd)
-{
- uint64_t fw_time;
-
- /* This is a dummy; setting of firmware time is not allowed */
- memcpy(&fw_time, cmd->frame->dcmd.mbox, sizeof(fw_time));
-
- trace_megasas_dcmd_set_fw_time(cmd->index, fw_time);
- fw_time = cpu_to_le64(megasas_fw_time());
- return MFI_STAT_OK;
-}
-
-static int megasas_event_info(MegasasState *s, MegasasCmd *cmd)
-{
- struct mfi_evt_log_state info;
- size_t dcmd_size = sizeof(info);
-
- memset(&info, 0, dcmd_size);
-
- info.newest_seq_num = cpu_to_le32(s->event_count);
- info.shutdown_seq_num = cpu_to_le32(s->shutdown_event);
- info.boot_seq_num = cpu_to_le32(s->boot_event);
-
- cmd->iov_size -= dma_buf_read((uint8_t *)&info, dcmd_size, &cmd->qsg);
- return MFI_STAT_OK;
-}
-
-static int megasas_event_wait(MegasasState *s, MegasasCmd *cmd)
-{
- union mfi_evt event;
-
- if (cmd->iov_size < sizeof(struct mfi_evt_detail)) {
- trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size,
- sizeof(struct mfi_evt_detail));
- return MFI_STAT_INVALID_PARAMETER;
- }
- s->event_count = cpu_to_le32(cmd->frame->dcmd.mbox[0]);
- event.word = cpu_to_le32(cmd->frame->dcmd.mbox[4]);
- s->event_locale = event.members.locale;
- s->event_class = event.members.class;
- s->event_cmd = cmd;
- /* Decrease busy count; event frame doesn't count here */
- s->busy--;
- cmd->iov_size = sizeof(struct mfi_evt_detail);
- return MFI_STAT_INVALID_STATUS;
-}
-
-static int megasas_dcmd_pd_get_list(MegasasState *s, MegasasCmd *cmd)
-{
- struct mfi_pd_list info;
- size_t dcmd_size = sizeof(info);
- BusChild *kid;
- uint32_t offset, dcmd_limit, num_pd_disks = 0, max_pd_disks;
-
- memset(&info, 0, dcmd_size);
- offset = 8;
- dcmd_limit = offset + sizeof(struct mfi_pd_address);
- if (cmd->iov_size < dcmd_limit) {
- trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size,
- dcmd_limit);
- return MFI_STAT_INVALID_PARAMETER;
- }
-
- max_pd_disks = (cmd->iov_size - offset) / sizeof(struct mfi_pd_address);
- if (max_pd_disks > MFI_MAX_SYS_PDS) {
- max_pd_disks = MFI_MAX_SYS_PDS;
- }
- QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
- SCSIDevice *sdev = SCSI_DEVICE(kid->child);
- uint16_t pd_id;
-
- if (num_pd_disks >= max_pd_disks)
- break;
-
- pd_id = ((sdev->id & 0xFF) << 8) | (sdev->lun & 0xFF);
- info.addr[num_pd_disks].device_id = cpu_to_le16(pd_id);
- info.addr[num_pd_disks].encl_device_id = 0xFFFF;
- info.addr[num_pd_disks].encl_index = 0;
- info.addr[num_pd_disks].slot_number = sdev->id & 0xFF;
- info.addr[num_pd_disks].scsi_dev_type = sdev->type;
- info.addr[num_pd_disks].connect_port_bitmap = 0x1;
- info.addr[num_pd_disks].sas_addr[0] =
- cpu_to_le64(megasas_get_sata_addr(pd_id));
- num_pd_disks++;
- offset += sizeof(struct mfi_pd_address);
- }
- trace_megasas_dcmd_pd_get_list(cmd->index, num_pd_disks,
- max_pd_disks, offset);
-
- info.size = cpu_to_le32(offset);
- info.count = cpu_to_le32(num_pd_disks);
-
- cmd->iov_size -= dma_buf_read((uint8_t *)&info, offset, &cmd->qsg);
- return MFI_STAT_OK;
-}
-
-static int megasas_dcmd_pd_list_query(MegasasState *s, MegasasCmd *cmd)
-{
- uint16_t flags;
-
- /* mbox0 contains flags */
- flags = le16_to_cpu(cmd->frame->dcmd.mbox[0]);
- trace_megasas_dcmd_pd_list_query(cmd->index, flags);
- if (flags == MR_PD_QUERY_TYPE_ALL ||
- megasas_is_jbod(s)) {
- return megasas_dcmd_pd_get_list(s, cmd);
- }
-
- return MFI_STAT_OK;
-}
-
-static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun,
- MegasasCmd *cmd)
-{
- struct mfi_pd_info *info = cmd->iov_buf;
- size_t dcmd_size = sizeof(struct mfi_pd_info);
- uint64_t pd_size;
- uint16_t pd_id = ((sdev->id & 0xFF) << 8) | (lun & 0xFF);
- uint8_t cmdbuf[6];
- SCSIRequest *req;
- size_t len, resid;
-
- if (!cmd->iov_buf) {
- cmd->iov_buf = g_malloc0(dcmd_size);
- info = cmd->iov_buf;
- info->inquiry_data[0] = 0x7f; /* Force PQual 0x3, PType 0x1f */
- info->vpd_page83[0] = 0x7f;
- megasas_setup_inquiry(cmdbuf, 0, sizeof(info->inquiry_data));
- req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, cmd);
- if (!req) {
- trace_megasas_dcmd_req_alloc_failed(cmd->index,
- "PD get info std inquiry");
- g_free(cmd->iov_buf);
- cmd->iov_buf = NULL;
- return MFI_STAT_FLASH_ALLOC_FAIL;
- }
- trace_megasas_dcmd_internal_submit(cmd->index,
- "PD get info std inquiry", lun);
- len = scsi_req_enqueue(req);
- if (len > 0) {
- cmd->iov_size = len;
- scsi_req_continue(req);
- }
- return MFI_STAT_INVALID_STATUS;
- } else if (info->inquiry_data[0] != 0x7f && info->vpd_page83[0] == 0x7f) {
- megasas_setup_inquiry(cmdbuf, 0x83, sizeof(info->vpd_page83));
- req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, cmd);
- if (!req) {
- trace_megasas_dcmd_req_alloc_failed(cmd->index,
- "PD get info vpd inquiry");
- return MFI_STAT_FLASH_ALLOC_FAIL;
- }
- trace_megasas_dcmd_internal_submit(cmd->index,
- "PD get info vpd inquiry", lun);
- len = scsi_req_enqueue(req);
- if (len > 0) {
- cmd->iov_size = len;
- scsi_req_continue(req);
- }
- return MFI_STAT_INVALID_STATUS;
- }
- /* Finished, set FW state */
- if ((info->inquiry_data[0] >> 5) == 0) {
- if (megasas_is_jbod(cmd->state)) {
- info->fw_state = cpu_to_le16(MFI_PD_STATE_SYSTEM);
- } else {
- info->fw_state = cpu_to_le16(MFI_PD_STATE_ONLINE);
- }
- } else {
- info->fw_state = cpu_to_le16(MFI_PD_STATE_OFFLINE);
- }
-
- info->ref.v.device_id = cpu_to_le16(pd_id);
- info->state.ddf.pd_type = cpu_to_le16(MFI_PD_DDF_TYPE_IN_VD|
- MFI_PD_DDF_TYPE_INTF_SAS);
- blk_get_geometry(sdev->conf.blk, &pd_size);
- info->raw_size = cpu_to_le64(pd_size);
- info->non_coerced_size = cpu_to_le64(pd_size);
- info->coerced_size = cpu_to_le64(pd_size);
- info->encl_device_id = 0xFFFF;
- info->slot_number = (sdev->id & 0xFF);
- info->path_info.count = 1;
- info->path_info.sas_addr[0] =
- cpu_to_le64(megasas_get_sata_addr(pd_id));
- info->connected_port_bitmap = 0x1;
- info->device_speed = 1;
- info->link_speed = 1;
- resid = dma_buf_read(cmd->iov_buf, dcmd_size, &cmd->qsg);
- g_free(cmd->iov_buf);
- cmd->iov_size = dcmd_size - resid;
- cmd->iov_buf = NULL;
- return MFI_STAT_OK;
-}
-
-static int megasas_dcmd_pd_get_info(MegasasState *s, MegasasCmd *cmd)
-{
- size_t dcmd_size = sizeof(struct mfi_pd_info);
- uint16_t pd_id;
- uint8_t target_id, lun_id;
- SCSIDevice *sdev = NULL;
- int retval = MFI_STAT_DEVICE_NOT_FOUND;
-
- if (cmd->iov_size < dcmd_size) {
- return MFI_STAT_INVALID_PARAMETER;
- }
-
- /* mbox0 has the ID */
- pd_id = le16_to_cpu(cmd->frame->dcmd.mbox[0]);
- target_id = (pd_id >> 8) & 0xFF;
- lun_id = pd_id & 0xFF;
- sdev = scsi_device_find(&s->bus, 0, target_id, lun_id);
- trace_megasas_dcmd_pd_get_info(cmd->index, pd_id);
-
- if (sdev) {
- /* Submit inquiry */
- retval = megasas_pd_get_info_submit(sdev, pd_id, cmd);
- }
-
- return retval;
-}
-
-static int megasas_dcmd_ld_get_list(MegasasState *s, MegasasCmd *cmd)
-{
- struct mfi_ld_list info;
- size_t dcmd_size = sizeof(info), resid;
- uint32_t num_ld_disks = 0, max_ld_disks;
- uint64_t ld_size;
- BusChild *kid;
-
- memset(&info, 0, dcmd_size);
- if (cmd->iov_size > dcmd_size) {
- trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size,
- dcmd_size);
- return MFI_STAT_INVALID_PARAMETER;
- }
-
- max_ld_disks = (cmd->iov_size - 8) / 16;
- if (megasas_is_jbod(s)) {
- max_ld_disks = 0;
- }
- if (max_ld_disks > MFI_MAX_LD) {
- max_ld_disks = MFI_MAX_LD;
- }
- QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
- SCSIDevice *sdev = SCSI_DEVICE(kid->child);
-
- if (num_ld_disks >= max_ld_disks) {
- break;
- }
- /* Logical device size is in blocks */
- blk_get_geometry(sdev->conf.blk, &ld_size);
- info.ld_list[num_ld_disks].ld.v.target_id = sdev->id;
- info.ld_list[num_ld_disks].state = MFI_LD_STATE_OPTIMAL;
- info.ld_list[num_ld_disks].size = cpu_to_le64(ld_size);
- num_ld_disks++;
- }
- info.ld_count = cpu_to_le32(num_ld_disks);
- trace_megasas_dcmd_ld_get_list(cmd->index, num_ld_disks, max_ld_disks);
-
- resid = dma_buf_read((uint8_t *)&info, dcmd_size, &cmd->qsg);
- cmd->iov_size = dcmd_size - resid;
- return MFI_STAT_OK;
-}
-
-static int megasas_dcmd_ld_list_query(MegasasState *s, MegasasCmd *cmd)
-{
- uint16_t flags;
- struct mfi_ld_targetid_list info;
- size_t dcmd_size = sizeof(info), resid;
- uint32_t num_ld_disks = 0, max_ld_disks = s->fw_luns;
- BusChild *kid;
-
- /* mbox0 contains flags */
- flags = le16_to_cpu(cmd->frame->dcmd.mbox[0]);
- trace_megasas_dcmd_ld_list_query(cmd->index, flags);
- if (flags != MR_LD_QUERY_TYPE_ALL &&
- flags != MR_LD_QUERY_TYPE_EXPOSED_TO_HOST) {
- max_ld_disks = 0;
- }
-
- memset(&info, 0, dcmd_size);
- if (cmd->iov_size < 12) {
- trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size,
- dcmd_size);
- return MFI_STAT_INVALID_PARAMETER;
- }
- dcmd_size = sizeof(uint32_t) * 2 + 3;
- max_ld_disks = cmd->iov_size - dcmd_size;
- if (megasas_is_jbod(s)) {
- max_ld_disks = 0;
- }
- if (max_ld_disks > MFI_MAX_LD) {
- max_ld_disks = MFI_MAX_LD;
- }
- QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
- SCSIDevice *sdev = SCSI_DEVICE(kid->child);
-
- if (num_ld_disks >= max_ld_disks) {
- break;
- }
- info.targetid[num_ld_disks] = sdev->lun;
- num_ld_disks++;
- dcmd_size++;
- }
- info.ld_count = cpu_to_le32(num_ld_disks);
- info.size = dcmd_size;
- trace_megasas_dcmd_ld_get_list(cmd->index, num_ld_disks, max_ld_disks);
-
- resid = dma_buf_read((uint8_t *)&info, dcmd_size, &cmd->qsg);
- cmd->iov_size = dcmd_size - resid;
- return MFI_STAT_OK;
-}
-
-static int megasas_ld_get_info_submit(SCSIDevice *sdev, int lun,
- MegasasCmd *cmd)
-{
- struct mfi_ld_info *info = cmd->iov_buf;
- size_t dcmd_size = sizeof(struct mfi_ld_info);
- uint8_t cdb[6];
- SCSIRequest *req;
- ssize_t len, resid;
- uint16_t sdev_id = ((sdev->id & 0xFF) << 8) | (lun & 0xFF);
- uint64_t ld_size;
-
- if (!cmd->iov_buf) {
- cmd->iov_buf = g_malloc0(dcmd_size);
- info = cmd->iov_buf;
- megasas_setup_inquiry(cdb, 0x83, sizeof(info->vpd_page83));
- req = scsi_req_new(sdev, cmd->index, lun, cdb, cmd);
- if (!req) {
- trace_megasas_dcmd_req_alloc_failed(cmd->index,
- "LD get info vpd inquiry");
- g_free(cmd->iov_buf);
- cmd->iov_buf = NULL;
- return MFI_STAT_FLASH_ALLOC_FAIL;
- }
- trace_megasas_dcmd_internal_submit(cmd->index,
- "LD get info vpd inquiry", lun);
- len = scsi_req_enqueue(req);
- if (len > 0) {
- cmd->iov_size = len;
- scsi_req_continue(req);
- }
- return MFI_STAT_INVALID_STATUS;
- }
-
- info->ld_config.params.state = MFI_LD_STATE_OPTIMAL;
- info->ld_config.properties.ld.v.target_id = lun;
- info->ld_config.params.stripe_size = 3;
- info->ld_config.params.num_drives = 1;
- info->ld_config.params.is_consistent = 1;
- /* Logical device size is in blocks */
- blk_get_geometry(sdev->conf.blk, &ld_size);
- info->size = cpu_to_le64(ld_size);
- memset(info->ld_config.span, 0, sizeof(info->ld_config.span));
- info->ld_config.span[0].start_block = 0;
- info->ld_config.span[0].num_blocks = info->size;
- info->ld_config.span[0].array_ref = cpu_to_le16(sdev_id);
-
- resid = dma_buf_read(cmd->iov_buf, dcmd_size, &cmd->qsg);
- g_free(cmd->iov_buf);
- cmd->iov_size = dcmd_size - resid;
- cmd->iov_buf = NULL;
- return MFI_STAT_OK;
-}
-
-static int megasas_dcmd_ld_get_info(MegasasState *s, MegasasCmd *cmd)
-{
- struct mfi_ld_info info;
- size_t dcmd_size = sizeof(info);
- uint16_t ld_id;
- uint32_t max_ld_disks = s->fw_luns;
- SCSIDevice *sdev = NULL;
- int retval = MFI_STAT_DEVICE_NOT_FOUND;
-
- if (cmd->iov_size < dcmd_size) {
- return MFI_STAT_INVALID_PARAMETER;
- }
-
- /* mbox0 has the ID */
- ld_id = le16_to_cpu(cmd->frame->dcmd.mbox[0]);
- trace_megasas_dcmd_ld_get_info(cmd->index, ld_id);
-
- if (megasas_is_jbod(s)) {
- return MFI_STAT_DEVICE_NOT_FOUND;
- }
-
- if (ld_id < max_ld_disks) {
- sdev = scsi_device_find(&s->bus, 0, ld_id, 0);
- }
-
- if (sdev) {
- retval = megasas_ld_get_info_submit(sdev, ld_id, cmd);
- }
-
- return retval;
-}
-
-static int megasas_dcmd_cfg_read(MegasasState *s, MegasasCmd *cmd)
-{
- uint8_t data[4096];
- struct mfi_config_data *info;
- int num_pd_disks = 0, array_offset, ld_offset;
- BusChild *kid;
-
- if (cmd->iov_size > 4096) {
- return MFI_STAT_INVALID_PARAMETER;
- }
-
- QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
- num_pd_disks++;
- }
- info = (struct mfi_config_data *)&data;
- /*
- * Array mapping:
- * - One array per SCSI device
- * - One logical drive per SCSI device
- * spanning the entire device
- */
- info->array_count = num_pd_disks;
- info->array_size = sizeof(struct mfi_array) * num_pd_disks;
- info->log_drv_count = num_pd_disks;
- info->log_drv_size = sizeof(struct mfi_ld_config) * num_pd_disks;
- info->spares_count = 0;
- info->spares_size = sizeof(struct mfi_spare);
- info->size = sizeof(struct mfi_config_data) + info->array_size +
- info->log_drv_size;
- if (info->size > 4096) {
- return MFI_STAT_INVALID_PARAMETER;
- }
-
- array_offset = sizeof(struct mfi_config_data);
- ld_offset = array_offset + sizeof(struct mfi_array) * num_pd_disks;
-
- QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
- SCSIDevice *sdev = SCSI_DEVICE(kid->child);
- uint16_t sdev_id = ((sdev->id & 0xFF) << 8) | (sdev->lun & 0xFF);
- struct mfi_array *array;
- struct mfi_ld_config *ld;
- uint64_t pd_size;
- int i;
-
- array = (struct mfi_array *)(data + array_offset);
- blk_get_geometry(sdev->conf.blk, &pd_size);
- array->size = cpu_to_le64(pd_size);
- array->num_drives = 1;
- array->array_ref = cpu_to_le16(sdev_id);
- array->pd[0].ref.v.device_id = cpu_to_le16(sdev_id);
- array->pd[0].ref.v.seq_num = 0;
- array->pd[0].fw_state = MFI_PD_STATE_ONLINE;
- array->pd[0].encl.pd = 0xFF;
- array->pd[0].encl.slot = (sdev->id & 0xFF);
- for (i = 1; i < MFI_MAX_ROW_SIZE; i++) {
- array->pd[i].ref.v.device_id = 0xFFFF;
- array->pd[i].ref.v.seq_num = 0;
- array->pd[i].fw_state = MFI_PD_STATE_UNCONFIGURED_GOOD;
- array->pd[i].encl.pd = 0xFF;
- array->pd[i].encl.slot = 0xFF;
- }
- array_offset += sizeof(struct mfi_array);
- ld = (struct mfi_ld_config *)(data + ld_offset);
- memset(ld, 0, sizeof(struct mfi_ld_config));
- ld->properties.ld.v.target_id = sdev->id;
- ld->properties.default_cache_policy = MR_LD_CACHE_READ_AHEAD |
- MR_LD_CACHE_READ_ADAPTIVE;
- ld->properties.current_cache_policy = MR_LD_CACHE_READ_AHEAD |
- MR_LD_CACHE_READ_ADAPTIVE;
- ld->params.state = MFI_LD_STATE_OPTIMAL;
- ld->params.stripe_size = 3;
- ld->params.num_drives = 1;
- ld->params.span_depth = 1;
- ld->params.is_consistent = 1;
- ld->span[0].start_block = 0;
- ld->span[0].num_blocks = cpu_to_le64(pd_size);
- ld->span[0].array_ref = cpu_to_le16(sdev_id);
- ld_offset += sizeof(struct mfi_ld_config);
- }
-
- cmd->iov_size -= dma_buf_read((uint8_t *)data, info->size, &cmd->qsg);
- return MFI_STAT_OK;
-}
-
-static int megasas_dcmd_get_properties(MegasasState *s, MegasasCmd *cmd)
-{
- struct mfi_ctrl_props info;
- size_t dcmd_size = sizeof(info);
-
- memset(&info, 0x0, dcmd_size);
- if (cmd->iov_size < dcmd_size) {
- trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size,
- dcmd_size);
- return MFI_STAT_INVALID_PARAMETER;
- }
- info.pred_fail_poll_interval = cpu_to_le16(300);
- info.intr_throttle_cnt = cpu_to_le16(16);
- info.intr_throttle_timeout = cpu_to_le16(50);
- info.rebuild_rate = 30;
- info.patrol_read_rate = 30;
- info.bgi_rate = 30;
- info.cc_rate = 30;
- info.recon_rate = 30;
- info.cache_flush_interval = 4;
- info.spinup_drv_cnt = 2;
- info.spinup_delay = 6;
- info.ecc_bucket_size = 15;
- info.ecc_bucket_leak_rate = cpu_to_le16(1440);
- info.expose_encl_devices = 1;
-
- cmd->iov_size -= dma_buf_read((uint8_t *)&info, dcmd_size, &cmd->qsg);
- return MFI_STAT_OK;
-}
-
-static int megasas_cache_flush(MegasasState *s, MegasasCmd *cmd)
-{
- blk_drain_all();
- return MFI_STAT_OK;
-}
-
-static int megasas_ctrl_shutdown(MegasasState *s, MegasasCmd *cmd)
-{
- s->fw_state = MFI_FWSTATE_READY;
- return MFI_STAT_OK;
-}
-
-/* Some implementations use CLUSTER RESET LD to simulate a device reset */
-static int megasas_cluster_reset_ld(MegasasState *s, MegasasCmd *cmd)
-{
- uint16_t target_id;
- int i;
-
- /* mbox0 contains the device index */
- target_id = le16_to_cpu(cmd->frame->dcmd.mbox[0]);
- trace_megasas_dcmd_reset_ld(cmd->index, target_id);
- for (i = 0; i < s->fw_cmds; i++) {
- MegasasCmd *tmp_cmd = &s->frames[i];
- if (tmp_cmd->req && tmp_cmd->req->dev->id == target_id) {
- SCSIDevice *d = tmp_cmd->req->dev;
- qdev_reset_all(&d->qdev);
- }
- }
- return MFI_STAT_OK;
-}
-
-static int megasas_dcmd_set_properties(MegasasState *s, MegasasCmd *cmd)
-{
- struct mfi_ctrl_props info;
- size_t dcmd_size = sizeof(info);
-
- if (cmd->iov_size < dcmd_size) {
- trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size,
- dcmd_size);
- return MFI_STAT_INVALID_PARAMETER;
- }
- dma_buf_write((uint8_t *)&info, cmd->iov_size, &cmd->qsg);
- trace_megasas_dcmd_unsupported(cmd->index, cmd->iov_size);
- return MFI_STAT_OK;
-}
-
-static int megasas_dcmd_dummy(MegasasState *s, MegasasCmd *cmd)
-{
- trace_megasas_dcmd_dummy(cmd->index, cmd->iov_size);
- return MFI_STAT_OK;
-}
-
-static const struct dcmd_cmd_tbl_t {
- int opcode;
- const char *desc;
- int (*func)(MegasasState *s, MegasasCmd *cmd);
-} dcmd_cmd_tbl[] = {
- { MFI_DCMD_CTRL_MFI_HOST_MEM_ALLOC, "CTRL_HOST_MEM_ALLOC",
- megasas_dcmd_dummy },
- { MFI_DCMD_CTRL_GET_INFO, "CTRL_GET_INFO",
- megasas_ctrl_get_info },
- { MFI_DCMD_CTRL_GET_PROPERTIES, "CTRL_GET_PROPERTIES",
- megasas_dcmd_get_properties },
- { MFI_DCMD_CTRL_SET_PROPERTIES, "CTRL_SET_PROPERTIES",
- megasas_dcmd_set_properties },
- { MFI_DCMD_CTRL_ALARM_GET, "CTRL_ALARM_GET",
- megasas_dcmd_dummy },
- { MFI_DCMD_CTRL_ALARM_ENABLE, "CTRL_ALARM_ENABLE",
- megasas_dcmd_dummy },
- { MFI_DCMD_CTRL_ALARM_DISABLE, "CTRL_ALARM_DISABLE",
- megasas_dcmd_dummy },
- { MFI_DCMD_CTRL_ALARM_SILENCE, "CTRL_ALARM_SILENCE",
- megasas_dcmd_dummy },
- { MFI_DCMD_CTRL_ALARM_TEST, "CTRL_ALARM_TEST",
- megasas_dcmd_dummy },
- { MFI_DCMD_CTRL_EVENT_GETINFO, "CTRL_EVENT_GETINFO",
- megasas_event_info },
- { MFI_DCMD_CTRL_EVENT_GET, "CTRL_EVENT_GET",
- megasas_dcmd_dummy },
- { MFI_DCMD_CTRL_EVENT_WAIT, "CTRL_EVENT_WAIT",
- megasas_event_wait },
- { MFI_DCMD_CTRL_SHUTDOWN, "CTRL_SHUTDOWN",
- megasas_ctrl_shutdown },
- { MFI_DCMD_HIBERNATE_STANDBY, "CTRL_STANDBY",
- megasas_dcmd_dummy },
- { MFI_DCMD_CTRL_GET_TIME, "CTRL_GET_TIME",
- megasas_dcmd_get_fw_time },
- { MFI_DCMD_CTRL_SET_TIME, "CTRL_SET_TIME",
- megasas_dcmd_set_fw_time },
- { MFI_DCMD_CTRL_BIOS_DATA_GET, "CTRL_BIOS_DATA_GET",
- megasas_dcmd_get_bios_info },
- { MFI_DCMD_CTRL_FACTORY_DEFAULTS, "CTRL_FACTORY_DEFAULTS",
- megasas_dcmd_dummy },
- { MFI_DCMD_CTRL_MFC_DEFAULTS_GET, "CTRL_MFC_DEFAULTS_GET",
- megasas_mfc_get_defaults },
- { MFI_DCMD_CTRL_MFC_DEFAULTS_SET, "CTRL_MFC_DEFAULTS_SET",
- megasas_dcmd_dummy },
- { MFI_DCMD_CTRL_CACHE_FLUSH, "CTRL_CACHE_FLUSH",
- megasas_cache_flush },
- { MFI_DCMD_PD_GET_LIST, "PD_GET_LIST",
- megasas_dcmd_pd_get_list },
- { MFI_DCMD_PD_LIST_QUERY, "PD_LIST_QUERY",
- megasas_dcmd_pd_list_query },
- { MFI_DCMD_PD_GET_INFO, "PD_GET_INFO",
- megasas_dcmd_pd_get_info },
- { MFI_DCMD_PD_STATE_SET, "PD_STATE_SET",
- megasas_dcmd_dummy },
- { MFI_DCMD_PD_REBUILD, "PD_REBUILD",
- megasas_dcmd_dummy },
- { MFI_DCMD_PD_BLINK, "PD_BLINK",
- megasas_dcmd_dummy },
- { MFI_DCMD_PD_UNBLINK, "PD_UNBLINK",
- megasas_dcmd_dummy },
- { MFI_DCMD_LD_GET_LIST, "LD_GET_LIST",
- megasas_dcmd_ld_get_list},
- { MFI_DCMD_LD_LIST_QUERY, "LD_LIST_QUERY",
- megasas_dcmd_ld_list_query },
- { MFI_DCMD_LD_GET_INFO, "LD_GET_INFO",
- megasas_dcmd_ld_get_info },
- { MFI_DCMD_LD_GET_PROP, "LD_GET_PROP",
- megasas_dcmd_dummy },
- { MFI_DCMD_LD_SET_PROP, "LD_SET_PROP",
- megasas_dcmd_dummy },
- { MFI_DCMD_LD_DELETE, "LD_DELETE",
- megasas_dcmd_dummy },
- { MFI_DCMD_CFG_READ, "CFG_READ",
- megasas_dcmd_cfg_read },
- { MFI_DCMD_CFG_ADD, "CFG_ADD",
- megasas_dcmd_dummy },
- { MFI_DCMD_CFG_CLEAR, "CFG_CLEAR",
- megasas_dcmd_dummy },
- { MFI_DCMD_CFG_FOREIGN_READ, "CFG_FOREIGN_READ",
- megasas_dcmd_dummy },
- { MFI_DCMD_CFG_FOREIGN_IMPORT, "CFG_FOREIGN_IMPORT",
- megasas_dcmd_dummy },
- { MFI_DCMD_BBU_STATUS, "BBU_STATUS",
- megasas_dcmd_dummy },
- { MFI_DCMD_BBU_CAPACITY_INFO, "BBU_CAPACITY_INFO",
- megasas_dcmd_dummy },
- { MFI_DCMD_BBU_DESIGN_INFO, "BBU_DESIGN_INFO",
- megasas_dcmd_dummy },
- { MFI_DCMD_BBU_PROP_GET, "BBU_PROP_GET",
- megasas_dcmd_dummy },
- { MFI_DCMD_CLUSTER, "CLUSTER",
- megasas_dcmd_dummy },
- { MFI_DCMD_CLUSTER_RESET_ALL, "CLUSTER_RESET_ALL",
- megasas_dcmd_dummy },
- { MFI_DCMD_CLUSTER_RESET_LD, "CLUSTER_RESET_LD",
- megasas_cluster_reset_ld },
- { -1, NULL, NULL }
-};
-
-static int megasas_handle_dcmd(MegasasState *s, MegasasCmd *cmd)
-{
- int opcode, len;
- int retval = 0;
- const struct dcmd_cmd_tbl_t *cmdptr = dcmd_cmd_tbl;
-
- opcode = le32_to_cpu(cmd->frame->dcmd.opcode);
- trace_megasas_handle_dcmd(cmd->index, opcode);
- len = megasas_map_dcmd(s, cmd);
- if (len < 0) {
- return MFI_STAT_MEMORY_NOT_AVAILABLE;
- }
- while (cmdptr->opcode != -1 && cmdptr->opcode != opcode) {
- cmdptr++;
- }
- if (cmdptr->opcode == -1) {
- trace_megasas_dcmd_unhandled(cmd->index, opcode, len);
- retval = megasas_dcmd_dummy(s, cmd);
- } else {
- trace_megasas_dcmd_enter(cmd->index, cmdptr->desc, len);
- retval = cmdptr->func(s, cmd);
- }
- if (retval != MFI_STAT_INVALID_STATUS) {
- megasas_finish_dcmd(cmd, len);
- }
- return retval;
-}
-
-static int megasas_finish_internal_dcmd(MegasasCmd *cmd,
- SCSIRequest *req)
-{
- int opcode;
- int retval = MFI_STAT_OK;
- int lun = req->lun;
-
- opcode = le32_to_cpu(cmd->frame->dcmd.opcode);
- scsi_req_unref(req);
- trace_megasas_dcmd_internal_finish(cmd->index, opcode, lun);
- switch (opcode) {
- case MFI_DCMD_PD_GET_INFO:
- retval = megasas_pd_get_info_submit(req->dev, lun, cmd);
- break;
- case MFI_DCMD_LD_GET_INFO:
- retval = megasas_ld_get_info_submit(req->dev, lun, cmd);
- break;
- default:
- trace_megasas_dcmd_internal_invalid(cmd->index, opcode);
- retval = MFI_STAT_INVALID_DCMD;
- break;
- }
- if (retval != MFI_STAT_INVALID_STATUS) {
- megasas_finish_dcmd(cmd, cmd->iov_size);
- }
- return retval;
-}
-
-static int megasas_enqueue_req(MegasasCmd *cmd, bool is_write)
-{
- int len;
-
- len = scsi_req_enqueue(cmd->req);
- if (len < 0) {
- len = -len;
- }
- if (len > 0) {
- if (len > cmd->iov_size) {
- if (is_write) {
- trace_megasas_iov_write_overflow(cmd->index, len,
- cmd->iov_size);
- } else {
- trace_megasas_iov_read_overflow(cmd->index, len,
- cmd->iov_size);
- }
- }
- if (len < cmd->iov_size) {
- if (is_write) {
- trace_megasas_iov_write_underflow(cmd->index, len,
- cmd->iov_size);
- } else {
- trace_megasas_iov_read_underflow(cmd->index, len,
- cmd->iov_size);
- }
- cmd->iov_size = len;
- }
- scsi_req_continue(cmd->req);
- }
- return len;
-}
-
-static int megasas_handle_scsi(MegasasState *s, MegasasCmd *cmd,
- bool is_logical)
-{
- uint8_t *cdb;
- bool is_write;
- struct SCSIDevice *sdev = NULL;
-
- cdb = cmd->frame->pass.cdb;
-
- if (is_logical) {
- if (cmd->frame->header.target_id >= MFI_MAX_LD ||
- cmd->frame->header.lun_id != 0) {
- trace_megasas_scsi_target_not_present(
- mfi_frame_desc[cmd->frame->header.frame_cmd], is_logical,
- cmd->frame->header.target_id, cmd->frame->header.lun_id);
- return MFI_STAT_DEVICE_NOT_FOUND;
- }
- }
- sdev = scsi_device_find(&s->bus, 0, cmd->frame->header.target_id,
- cmd->frame->header.lun_id);
-
- cmd->iov_size = le32_to_cpu(cmd->frame->header.data_len);
- trace_megasas_handle_scsi(mfi_frame_desc[cmd->frame->header.frame_cmd],
- is_logical, cmd->frame->header.target_id,
- cmd->frame->header.lun_id, sdev, cmd->iov_size);
-
- if (!sdev || (megasas_is_jbod(s) && is_logical)) {
- trace_megasas_scsi_target_not_present(
- mfi_frame_desc[cmd->frame->header.frame_cmd], is_logical,
- cmd->frame->header.target_id, cmd->frame->header.lun_id);
- return MFI_STAT_DEVICE_NOT_FOUND;
- }
-
- if (cmd->frame->header.cdb_len > 16) {
- trace_megasas_scsi_invalid_cdb_len(
- mfi_frame_desc[cmd->frame->header.frame_cmd], is_logical,
- cmd->frame->header.target_id, cmd->frame->header.lun_id,
- cmd->frame->header.cdb_len);
- megasas_write_sense(cmd, SENSE_CODE(INVALID_OPCODE));
- cmd->frame->header.scsi_status = CHECK_CONDITION;
- s->event_count++;
- return MFI_STAT_SCSI_DONE_WITH_ERROR;
- }
-
- if (megasas_map_sgl(s, cmd, &cmd->frame->pass.sgl)) {
- megasas_write_sense(cmd, SENSE_CODE(TARGET_FAILURE));
- cmd->frame->header.scsi_status = CHECK_CONDITION;
- s->event_count++;
- return MFI_STAT_SCSI_DONE_WITH_ERROR;
- }
-
- cmd->req = scsi_req_new(sdev, cmd->index,
- cmd->frame->header.lun_id, cdb, cmd);
- if (!cmd->req) {
- trace_megasas_scsi_req_alloc_failed(
- mfi_frame_desc[cmd->frame->header.frame_cmd],
- cmd->frame->header.target_id, cmd->frame->header.lun_id);
- megasas_write_sense(cmd, SENSE_CODE(NO_SENSE));
- cmd->frame->header.scsi_status = BUSY;
- s->event_count++;
- return MFI_STAT_SCSI_DONE_WITH_ERROR;
- }
-
- is_write = (cmd->req->cmd.mode == SCSI_XFER_TO_DEV);
- if (cmd->iov_size) {
- if (is_write) {
- trace_megasas_scsi_write_start(cmd->index, cmd->iov_size);
- } else {
- trace_megasas_scsi_read_start(cmd->index, cmd->iov_size);
- }
- } else {
- trace_megasas_scsi_nodata(cmd->index);
- }
- megasas_enqueue_req(cmd, is_write);
- return MFI_STAT_INVALID_STATUS;
-}
-
-static int megasas_handle_io(MegasasState *s, MegasasCmd *cmd)
-{
- uint32_t lba_count, lba_start_hi, lba_start_lo;
- uint64_t lba_start;
- bool is_write = (cmd->frame->header.frame_cmd == MFI_CMD_LD_WRITE);
- uint8_t cdb[16];
- int len;
- struct SCSIDevice *sdev = NULL;
-
- lba_count = le32_to_cpu(cmd->frame->io.header.data_len);
- lba_start_lo = le32_to_cpu(cmd->frame->io.lba_lo);
- lba_start_hi = le32_to_cpu(cmd->frame->io.lba_hi);
- lba_start = ((uint64_t)lba_start_hi << 32) | lba_start_lo;
-
- if (cmd->frame->header.target_id < MFI_MAX_LD &&
- cmd->frame->header.lun_id == 0) {
- sdev = scsi_device_find(&s->bus, 0, cmd->frame->header.target_id,
- cmd->frame->header.lun_id);
- }
-
- trace_megasas_handle_io(cmd->index,
- mfi_frame_desc[cmd->frame->header.frame_cmd],
- cmd->frame->header.target_id,
- cmd->frame->header.lun_id,
- (unsigned long)lba_start, (unsigned long)lba_count);
- if (!sdev) {
- trace_megasas_io_target_not_present(cmd->index,
- mfi_frame_desc[cmd->frame->header.frame_cmd],
- cmd->frame->header.target_id, cmd->frame->header.lun_id);
- return MFI_STAT_DEVICE_NOT_FOUND;
- }
-
- if (cmd->frame->header.cdb_len > 16) {
- trace_megasas_scsi_invalid_cdb_len(
- mfi_frame_desc[cmd->frame->header.frame_cmd], 1,
- cmd->frame->header.target_id, cmd->frame->header.lun_id,
- cmd->frame->header.cdb_len);
- megasas_write_sense(cmd, SENSE_CODE(INVALID_OPCODE));
- cmd->frame->header.scsi_status = CHECK_CONDITION;
- s->event_count++;
- return MFI_STAT_SCSI_DONE_WITH_ERROR;
- }
-
- cmd->iov_size = lba_count * sdev->blocksize;
- if (megasas_map_sgl(s, cmd, &cmd->frame->io.sgl)) {
- megasas_write_sense(cmd, SENSE_CODE(TARGET_FAILURE));
- cmd->frame->header.scsi_status = CHECK_CONDITION;
- s->event_count++;
- return MFI_STAT_SCSI_DONE_WITH_ERROR;
- }
-
- megasas_encode_lba(cdb, lba_start, lba_count, is_write);
- cmd->req = scsi_req_new(sdev, cmd->index,
- cmd->frame->header.lun_id, cdb, cmd);
- if (!cmd->req) {
- trace_megasas_scsi_req_alloc_failed(
- mfi_frame_desc[cmd->frame->header.frame_cmd],
- cmd->frame->header.target_id, cmd->frame->header.lun_id);
- megasas_write_sense(cmd, SENSE_CODE(NO_SENSE));
- cmd->frame->header.scsi_status = BUSY;
- s->event_count++;
- return MFI_STAT_SCSI_DONE_WITH_ERROR;
- }
- len = megasas_enqueue_req(cmd, is_write);
- if (len > 0) {
- if (is_write) {
- trace_megasas_io_write_start(cmd->index, lba_start, lba_count, len);
- } else {
- trace_megasas_io_read_start(cmd->index, lba_start, lba_count, len);
- }
- }
- return MFI_STAT_INVALID_STATUS;
-}
-
-static int megasas_finish_internal_command(MegasasCmd *cmd,
- SCSIRequest *req, size_t resid)
-{
- int retval = MFI_STAT_INVALID_CMD;
-
- if (cmd->frame->header.frame_cmd == MFI_CMD_DCMD) {
- cmd->iov_size -= resid;
- retval = megasas_finish_internal_dcmd(cmd, req);
- }
- return retval;
-}
-
-static QEMUSGList *megasas_get_sg_list(SCSIRequest *req)
-{
- MegasasCmd *cmd = req->hba_private;
-
- if (cmd->frame->header.frame_cmd == MFI_CMD_DCMD) {
- return NULL;
- } else {
- return &cmd->qsg;
- }
-}
-
-static void megasas_xfer_complete(SCSIRequest *req, uint32_t len)
-{
- MegasasCmd *cmd = req->hba_private;
- uint8_t *buf;
- uint32_t opcode;
-
- trace_megasas_io_complete(cmd->index, len);
-
- if (cmd->frame->header.frame_cmd != MFI_CMD_DCMD) {
- scsi_req_continue(req);
- return;
- }
-
- buf = scsi_req_get_buf(req);
- opcode = le32_to_cpu(cmd->frame->dcmd.opcode);
- if (opcode == MFI_DCMD_PD_GET_INFO && cmd->iov_buf) {
- struct mfi_pd_info *info = cmd->iov_buf;
-
- if (info->inquiry_data[0] == 0x7f) {
- memset(info->inquiry_data, 0, sizeof(info->inquiry_data));
- memcpy(info->inquiry_data, buf, len);
- } else if (info->vpd_page83[0] == 0x7f) {
- memset(info->vpd_page83, 0, sizeof(info->vpd_page83));
- memcpy(info->vpd_page83, buf, len);
- }
- scsi_req_continue(req);
- } else if (opcode == MFI_DCMD_LD_GET_INFO) {
- struct mfi_ld_info *info = cmd->iov_buf;
-
- if (cmd->iov_buf) {
- memcpy(info->vpd_page83, buf, sizeof(info->vpd_page83));
- scsi_req_continue(req);
- }
- }
-}
-
-static void megasas_command_complete(SCSIRequest *req, uint32_t status,
- size_t resid)
-{
- MegasasCmd *cmd = req->hba_private;
- uint8_t cmd_status = MFI_STAT_OK;
-
- trace_megasas_command_complete(cmd->index, status, resid);
-
- if (cmd->req != req) {
- /*
- * Internal command complete
- */
- cmd_status = megasas_finish_internal_command(cmd, req, resid);
- if (cmd_status == MFI_STAT_INVALID_STATUS) {
- return;
- }
- } else {
- req->status = status;
- trace_megasas_scsi_complete(cmd->index, req->status,
- cmd->iov_size, req->cmd.xfer);
- if (req->status != GOOD) {
- cmd_status = MFI_STAT_SCSI_DONE_WITH_ERROR;
- }
- if (req->status == CHECK_CONDITION) {
- megasas_copy_sense(cmd);
- }
-
- megasas_unmap_sgl(cmd);
- cmd->frame->header.scsi_status = req->status;
- scsi_req_unref(cmd->req);
- cmd->req = NULL;
- }
- cmd->frame->header.cmd_status = cmd_status;
- megasas_unmap_frame(cmd->state, cmd);
- megasas_complete_frame(cmd->state, cmd->context);
-}
-
-static void megasas_command_cancel(SCSIRequest *req)
-{
- MegasasCmd *cmd = req->hba_private;
-
- if (cmd) {
- megasas_abort_command(cmd);
- } else {
- scsi_req_unref(req);
- }
-}
-
-static int megasas_handle_abort(MegasasState *s, MegasasCmd *cmd)
-{
- uint64_t abort_ctx = le64_to_cpu(cmd->frame->abort.abort_context);
- hwaddr abort_addr, addr_hi, addr_lo;
- MegasasCmd *abort_cmd;
-
- addr_hi = le32_to_cpu(cmd->frame->abort.abort_mfi_addr_hi);
- addr_lo = le32_to_cpu(cmd->frame->abort.abort_mfi_addr_lo);
- abort_addr = ((uint64_t)addr_hi << 32) | addr_lo;
-
- abort_cmd = megasas_lookup_frame(s, abort_addr);
- if (!abort_cmd) {
- trace_megasas_abort_no_cmd(cmd->index, abort_ctx);
- s->event_count++;
- return MFI_STAT_OK;
- }
- if (!megasas_use_queue64(s)) {
- abort_ctx &= (uint64_t)0xFFFFFFFF;
- }
- if (abort_cmd->context != abort_ctx) {
- trace_megasas_abort_invalid_context(cmd->index, abort_cmd->index,
- abort_cmd->context);
- s->event_count++;
- return MFI_STAT_ABORT_NOT_POSSIBLE;
- }
- trace_megasas_abort_frame(cmd->index, abort_cmd->index);
- megasas_abort_command(abort_cmd);
- if (!s->event_cmd || abort_cmd != s->event_cmd) {
- s->event_cmd = NULL;
- }
- s->event_count++;
- return MFI_STAT_OK;
-}
-
-static void megasas_handle_frame(MegasasState *s, uint64_t frame_addr,
- uint32_t frame_count)
-{
- uint8_t frame_status = MFI_STAT_INVALID_CMD;
- uint64_t frame_context;
- MegasasCmd *cmd;
-
- /*
- * Always read 64bit context, top bits will be
- * masked out if required in megasas_enqueue_frame()
- */
- frame_context = megasas_frame_get_context(s, frame_addr);
-
- cmd = megasas_enqueue_frame(s, frame_addr, frame_context, frame_count);
- if (!cmd) {
- /* reply queue full */
- trace_megasas_frame_busy(frame_addr);
- megasas_frame_set_scsi_status(s, frame_addr, BUSY);
- megasas_frame_set_cmd_status(s, frame_addr, MFI_STAT_SCSI_DONE_WITH_ERROR);
- megasas_complete_frame(s, frame_context);
- s->event_count++;
- return;
- }
- switch (cmd->frame->header.frame_cmd) {
- case MFI_CMD_INIT:
- frame_status = megasas_init_firmware(s, cmd);
- break;
- case MFI_CMD_DCMD:
- frame_status = megasas_handle_dcmd(s, cmd);
- break;
- case MFI_CMD_ABORT:
- frame_status = megasas_handle_abort(s, cmd);
- break;
- case MFI_CMD_PD_SCSI_IO:
- frame_status = megasas_handle_scsi(s, cmd, 0);
- break;
- case MFI_CMD_LD_SCSI_IO:
- frame_status = megasas_handle_scsi(s, cmd, 1);
- break;
- case MFI_CMD_LD_READ:
- case MFI_CMD_LD_WRITE:
- frame_status = megasas_handle_io(s, cmd);
- break;
- default:
- trace_megasas_unhandled_frame_cmd(cmd->index,
- cmd->frame->header.frame_cmd);
- s->event_count++;
- break;
- }
- if (frame_status != MFI_STAT_INVALID_STATUS) {
- if (cmd->frame) {
- cmd->frame->header.cmd_status = frame_status;
- } else {
- megasas_frame_set_cmd_status(s, frame_addr, frame_status);
- }
- megasas_unmap_frame(s, cmd);
- megasas_complete_frame(s, cmd->context);
- }
-}
-
-static uint64_t megasas_mmio_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- MegasasState *s = opaque;
- PCIDevice *pci_dev = PCI_DEVICE(s);
- MegasasBaseClass *base_class = MEGASAS_DEVICE_GET_CLASS(s);
- uint32_t retval = 0;
-
- switch (addr) {
- case MFI_IDB:
- retval = 0;
- trace_megasas_mmio_readl("MFI_IDB", retval);
- break;
- case MFI_OMSG0:
- case MFI_OSP0:
- retval = (msix_present(pci_dev) ? MFI_FWSTATE_MSIX_SUPPORTED : 0) |
- (s->fw_state & MFI_FWSTATE_MASK) |
- ((s->fw_sge & 0xff) << 16) |
- (s->fw_cmds & 0xFFFF);
- trace_megasas_mmio_readl(addr == MFI_OMSG0 ? "MFI_OMSG0" : "MFI_OSP0",
- retval);
- break;
- case MFI_OSTS:
- if (megasas_intr_enabled(s) && s->doorbell) {
- retval = base_class->osts;
- }
- trace_megasas_mmio_readl("MFI_OSTS", retval);
- break;
- case MFI_OMSK:
- retval = s->intr_mask;
- trace_megasas_mmio_readl("MFI_OMSK", retval);
- break;
- case MFI_ODCR0:
- retval = s->doorbell ? 1 : 0;
- trace_megasas_mmio_readl("MFI_ODCR0", retval);
- break;
- case MFI_DIAG:
- retval = s->diag;
- trace_megasas_mmio_readl("MFI_DIAG", retval);
- break;
- case MFI_OSP1:
- retval = 15;
- trace_megasas_mmio_readl("MFI_OSP1", retval);
- break;
- default:
- trace_megasas_mmio_invalid_readl(addr);
- break;
- }
- return retval;
-}
-
-static int adp_reset_seq[] = {0x00, 0x04, 0x0b, 0x02, 0x07, 0x0d};
-
-static void megasas_mmio_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- MegasasState *s = opaque;
- PCIDevice *pci_dev = PCI_DEVICE(s);
- uint64_t frame_addr;
- uint32_t frame_count;
- int i;
-
- switch (addr) {
- case MFI_IDB:
- trace_megasas_mmio_writel("MFI_IDB", val);
- if (val & MFI_FWINIT_ABORT) {
- /* Abort all pending cmds */
- for (i = 0; i < s->fw_cmds; i++) {
- megasas_abort_command(&s->frames[i]);
- }
- }
- if (val & MFI_FWINIT_READY) {
- /* move to FW READY */
- megasas_soft_reset(s);
- }
- if (val & MFI_FWINIT_MFIMODE) {
- /* discard MFIs */
- }
- if (val & MFI_FWINIT_STOP_ADP) {
- /* Terminal error, stop processing */
- s->fw_state = MFI_FWSTATE_FAULT;
- }
- break;
- case MFI_OMSK:
- trace_megasas_mmio_writel("MFI_OMSK", val);
- s->intr_mask = val;
- if (!megasas_intr_enabled(s) &&
- !msi_enabled(pci_dev) &&
- !msix_enabled(pci_dev)) {
- trace_megasas_irq_lower();
- pci_irq_deassert(pci_dev);
- }
- if (megasas_intr_enabled(s)) {
- if (msix_enabled(pci_dev)) {
- trace_megasas_msix_enabled(0);
- } else if (msi_enabled(pci_dev)) {
- trace_megasas_msi_enabled(0);
- } else {
- trace_megasas_intr_enabled();
- }
- } else {
- trace_megasas_intr_disabled();
- megasas_soft_reset(s);
- }
- break;
- case MFI_ODCR0:
- trace_megasas_mmio_writel("MFI_ODCR0", val);
- s->doorbell = 0;
- if (megasas_intr_enabled(s)) {
- if (!msix_enabled(pci_dev) && !msi_enabled(pci_dev)) {
- trace_megasas_irq_lower();
- pci_irq_deassert(pci_dev);
- }
- }
- break;
- case MFI_IQPH:
- trace_megasas_mmio_writel("MFI_IQPH", val);
- /* Received high 32 bits of a 64 bit MFI frame address */
- s->frame_hi = val;
- break;
- case MFI_IQPL:
- trace_megasas_mmio_writel("MFI_IQPL", val);
- /* Received low 32 bits of a 64 bit MFI frame address */
- /* Fallthrough */
- case MFI_IQP:
- if (addr == MFI_IQP) {
- trace_megasas_mmio_writel("MFI_IQP", val);
- /* Received 64 bit MFI frame address */
- s->frame_hi = 0;
- }
- frame_addr = (val & ~0x1F);
- /* Add possible 64 bit offset */
- frame_addr |= ((uint64_t)s->frame_hi << 32);
- s->frame_hi = 0;
- frame_count = (val >> 1) & 0xF;
- megasas_handle_frame(s, frame_addr, frame_count);
- break;
- case MFI_SEQ:
- trace_megasas_mmio_writel("MFI_SEQ", val);
- /* Magic sequence to start ADP reset */
- if (adp_reset_seq[s->adp_reset] == val) {
- s->adp_reset++;
- } else {
- s->adp_reset = 0;
- s->diag = 0;
- }
- if (s->adp_reset == 6) {
- s->diag = MFI_DIAG_WRITE_ENABLE;
- }
- break;
- case MFI_DIAG:
- trace_megasas_mmio_writel("MFI_DIAG", val);
- /* ADP reset */
- if ((s->diag & MFI_DIAG_WRITE_ENABLE) &&
- (val & MFI_DIAG_RESET_ADP)) {
- s->diag |= MFI_DIAG_RESET_ADP;
- megasas_soft_reset(s);
- s->adp_reset = 0;
- s->diag = 0;
- }
- break;
- default:
- trace_megasas_mmio_invalid_writel(addr, val);
- break;
- }
-}
-
-static const MemoryRegionOps megasas_mmio_ops = {
- .read = megasas_mmio_read,
- .write = megasas_mmio_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .impl = {
- .min_access_size = 8,
- .max_access_size = 8,
- }
-};
-
-static uint64_t megasas_port_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- return megasas_mmio_read(opaque, addr & 0xff, size);
-}
-
-static void megasas_port_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- megasas_mmio_write(opaque, addr & 0xff, val, size);
-}
-
-static const MemoryRegionOps megasas_port_ops = {
- .read = megasas_port_read,
- .write = megasas_port_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .impl = {
- .min_access_size = 4,
- .max_access_size = 4,
- }
-};
-
-static uint64_t megasas_queue_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- return 0;
-}
-
-static void megasas_queue_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- return;
-}
-
-static const MemoryRegionOps megasas_queue_ops = {
- .read = megasas_queue_read,
- .write = megasas_queue_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .impl = {
- .min_access_size = 8,
- .max_access_size = 8,
- }
-};
-
-static void megasas_soft_reset(MegasasState *s)
-{
- int i;
- MegasasCmd *cmd;
-
- trace_megasas_reset(s->fw_state);
- for (i = 0; i < s->fw_cmds; i++) {
- cmd = &s->frames[i];
- megasas_abort_command(cmd);
- }
- if (s->fw_state == MFI_FWSTATE_READY) {
- BusChild *kid;
-
- /*
- * The EFI firmware doesn't handle UA,
- * so we need to clear the Power On/Reset UA
- * after the initial reset.
- */
- QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
- SCSIDevice *sdev = SCSI_DEVICE(kid->child);
-
- sdev->unit_attention = SENSE_CODE(NO_SENSE);
- scsi_device_unit_attention_reported(sdev);
- }
- }
- megasas_reset_frames(s);
- s->reply_queue_len = s->fw_cmds;
- s->reply_queue_pa = 0;
- s->consumer_pa = 0;
- s->producer_pa = 0;
- s->fw_state = MFI_FWSTATE_READY;
- s->doorbell = 0;
- s->intr_mask = MEGASAS_INTR_DISABLED_MASK;
- s->frame_hi = 0;
- s->flags &= ~MEGASAS_MASK_USE_QUEUE64;
- s->event_count++;
- s->boot_event = s->event_count;
-}
-
-static void megasas_scsi_reset(DeviceState *dev)
-{
- MegasasState *s = MEGASAS(dev);
-
- megasas_soft_reset(s);
-}
-
-static const VMStateDescription vmstate_megasas_gen1 = {
- .name = "megasas",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(parent_obj, MegasasState),
- VMSTATE_MSIX(parent_obj, MegasasState),
-
- VMSTATE_INT32(fw_state, MegasasState),
- VMSTATE_INT32(intr_mask, MegasasState),
- VMSTATE_INT32(doorbell, MegasasState),
- VMSTATE_UINT64(reply_queue_pa, MegasasState),
- VMSTATE_UINT64(consumer_pa, MegasasState),
- VMSTATE_UINT64(producer_pa, MegasasState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_megasas_gen2 = {
- .name = "megasas-gen2",
- .version_id = 0,
- .minimum_version_id = 0,
- .minimum_version_id_old = 0,
- .fields = (VMStateField[]) {
- VMSTATE_PCIE_DEVICE(parent_obj, MegasasState),
- VMSTATE_MSIX(parent_obj, MegasasState),
-
- VMSTATE_INT32(fw_state, MegasasState),
- VMSTATE_INT32(intr_mask, MegasasState),
- VMSTATE_INT32(doorbell, MegasasState),
- VMSTATE_UINT64(reply_queue_pa, MegasasState),
- VMSTATE_UINT64(consumer_pa, MegasasState),
- VMSTATE_UINT64(producer_pa, MegasasState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void megasas_scsi_uninit(PCIDevice *d)
-{
- MegasasState *s = MEGASAS(d);
-
- if (megasas_use_msix(s)) {
- msix_uninit(d, &s->mmio_io, &s->mmio_io);
- }
- if (megasas_use_msi(s)) {
- msi_uninit(d);
- }
-}
-
-static const struct SCSIBusInfo megasas_scsi_info = {
- .tcq = true,
- .max_target = MFI_MAX_LD,
- .max_lun = 255,
-
- .transfer_data = megasas_xfer_complete,
- .get_sg_list = megasas_get_sg_list,
- .complete = megasas_command_complete,
- .cancel = megasas_command_cancel,
-};
-
-static void megasas_scsi_realize(PCIDevice *dev, Error **errp)
-{
- DeviceState *d = DEVICE(dev);
- MegasasState *s = MEGASAS(dev);
- MegasasBaseClass *b = MEGASAS_DEVICE_GET_CLASS(s);
- uint8_t *pci_conf;
- int i, bar_type;
-
- pci_conf = dev->config;
-
- /* PCI latency timer = 0 */
- pci_conf[PCI_LATENCY_TIMER] = 0;
- /* Interrupt pin 1 */
- pci_conf[PCI_INTERRUPT_PIN] = 0x01;
-
- memory_region_init_io(&s->mmio_io, OBJECT(s), &megasas_mmio_ops, s,
- "megasas-mmio", 0x4000);
- memory_region_init_io(&s->port_io, OBJECT(s), &megasas_port_ops, s,
- "megasas-io", 256);
- memory_region_init_io(&s->queue_io, OBJECT(s), &megasas_queue_ops, s,
- "megasas-queue", 0x40000);
-
- if (megasas_use_msi(s) &&
- msi_init(dev, 0x50, 1, true, false)) {
- s->flags &= ~MEGASAS_MASK_USE_MSI;
- }
- if (megasas_use_msix(s) &&
- msix_init(dev, 15, &s->mmio_io, b->mmio_bar, 0x2000,
- &s->mmio_io, b->mmio_bar, 0x3800, 0x68)) {
- s->flags &= ~MEGASAS_MASK_USE_MSIX;
- }
- if (pci_is_express(dev)) {
- pcie_endpoint_cap_init(dev, 0xa0);
- }
-
- bar_type = PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64;
- pci_register_bar(dev, b->ioport_bar,
- PCI_BASE_ADDRESS_SPACE_IO, &s->port_io);
- pci_register_bar(dev, b->mmio_bar, bar_type, &s->mmio_io);
- pci_register_bar(dev, 3, bar_type, &s->queue_io);
-
- if (megasas_use_msix(s)) {
- msix_vector_use(dev, 0);
- }
-
- s->fw_state = MFI_FWSTATE_READY;
- if (!s->sas_addr) {
- s->sas_addr = ((NAA_LOCALLY_ASSIGNED_ID << 24) |
- IEEE_COMPANY_LOCALLY_ASSIGNED) << 36;
- s->sas_addr |= (pci_bus_num(dev->bus) << 16);
- s->sas_addr |= (PCI_SLOT(dev->devfn) << 8);
- s->sas_addr |= PCI_FUNC(dev->devfn);
- }
- if (!s->hba_serial) {
- s->hba_serial = g_strdup(MEGASAS_HBA_SERIAL);
- }
- if (s->fw_sge >= MEGASAS_MAX_SGE - MFI_PASS_FRAME_SIZE) {
- s->fw_sge = MEGASAS_MAX_SGE - MFI_PASS_FRAME_SIZE;
- } else if (s->fw_sge >= 128 - MFI_PASS_FRAME_SIZE) {
- s->fw_sge = 128 - MFI_PASS_FRAME_SIZE;
- } else {
- s->fw_sge = 64 - MFI_PASS_FRAME_SIZE;
- }
- if (s->fw_cmds > MEGASAS_MAX_FRAMES) {
- s->fw_cmds = MEGASAS_MAX_FRAMES;
- }
- trace_megasas_init(s->fw_sge, s->fw_cmds,
- megasas_is_jbod(s) ? "jbod" : "raid");
-
- if (megasas_is_jbod(s)) {
- s->fw_luns = MFI_MAX_SYS_PDS;
- } else {
- s->fw_luns = MFI_MAX_LD;
- }
- s->producer_pa = 0;
- s->consumer_pa = 0;
- for (i = 0; i < s->fw_cmds; i++) {
- s->frames[i].index = i;
- s->frames[i].context = -1;
- s->frames[i].pa = 0;
- s->frames[i].state = s;
- }
-
- scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(dev),
- &megasas_scsi_info, NULL);
- if (!d->hotplugged) {
- scsi_bus_legacy_handle_cmdline(&s->bus, errp);
- }
-}
-
-static Property megasas_properties_gen1[] = {
- DEFINE_PROP_UINT32("max_sge", MegasasState, fw_sge,
- MEGASAS_DEFAULT_SGE),
- DEFINE_PROP_UINT32("max_cmds", MegasasState, fw_cmds,
- MEGASAS_DEFAULT_FRAMES),
- DEFINE_PROP_STRING("hba_serial", MegasasState, hba_serial),
- DEFINE_PROP_UINT64("sas_address", MegasasState, sas_addr, 0),
- DEFINE_PROP_BIT("use_msi", MegasasState, flags,
- MEGASAS_FLAG_USE_MSI, false),
- DEFINE_PROP_BIT("use_msix", MegasasState, flags,
- MEGASAS_FLAG_USE_MSIX, false),
- DEFINE_PROP_BIT("use_jbod", MegasasState, flags,
- MEGASAS_FLAG_USE_JBOD, false),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static Property megasas_properties_gen2[] = {
- DEFINE_PROP_UINT32("max_sge", MegasasState, fw_sge,
- MEGASAS_DEFAULT_SGE),
- DEFINE_PROP_UINT32("max_cmds", MegasasState, fw_cmds,
- MEGASAS_GEN2_DEFAULT_FRAMES),
- DEFINE_PROP_STRING("hba_serial", MegasasState, hba_serial),
- DEFINE_PROP_UINT64("sas_address", MegasasState, sas_addr, 0),
- DEFINE_PROP_BIT("use_msi", MegasasState, flags,
- MEGASAS_FLAG_USE_MSI, true),
- DEFINE_PROP_BIT("use_msix", MegasasState, flags,
- MEGASAS_FLAG_USE_MSIX, true),
- DEFINE_PROP_BIT("use_jbod", MegasasState, flags,
- MEGASAS_FLAG_USE_JBOD, false),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-typedef struct MegasasInfo {
- const char *name;
- const char *desc;
- const char *product_name;
- const char *product_version;
- uint16_t device_id;
- uint16_t subsystem_id;
- int ioport_bar;
- int mmio_bar;
- bool is_express;
- int osts;
- const VMStateDescription *vmsd;
- Property *props;
-} MegasasInfo;
-
-static struct MegasasInfo megasas_devices[] = {
- {
- .name = TYPE_MEGASAS_GEN1,
- .desc = "LSI MegaRAID SAS 1078",
- .product_name = "LSI MegaRAID SAS 8708EM2",
- .product_version = MEGASAS_VERSION_GEN1,
- .device_id = PCI_DEVICE_ID_LSI_SAS1078,
- .subsystem_id = 0x1013,
- .ioport_bar = 2,
- .mmio_bar = 0,
- .osts = MFI_1078_RM | 1,
- .is_express = false,
- .vmsd = &vmstate_megasas_gen1,
- .props = megasas_properties_gen1,
- },{
- .name = TYPE_MEGASAS_GEN2,
- .desc = "LSI MegaRAID SAS 2108",
- .product_name = "LSI MegaRAID SAS 9260-8i",
- .product_version = MEGASAS_VERSION_GEN2,
- .device_id = PCI_DEVICE_ID_LSI_SAS0079,
- .subsystem_id = 0x9261,
- .ioport_bar = 0,
- .mmio_bar = 1,
- .osts = MFI_GEN2_RM,
- .is_express = true,
- .vmsd = &vmstate_megasas_gen2,
- .props = megasas_properties_gen2,
- }
-};
-
-static void megasas_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
- PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc);
- MegasasBaseClass *e = MEGASAS_DEVICE_CLASS(oc);
- const MegasasInfo *info = data;
-
- pc->realize = megasas_scsi_realize;
- pc->exit = megasas_scsi_uninit;
- pc->vendor_id = PCI_VENDOR_ID_LSI_LOGIC;
- pc->device_id = info->device_id;
- pc->subsystem_vendor_id = PCI_VENDOR_ID_LSI_LOGIC;
- pc->subsystem_id = info->subsystem_id;
- pc->class_id = PCI_CLASS_STORAGE_RAID;
- pc->is_express = info->is_express;
- e->mmio_bar = info->mmio_bar;
- e->ioport_bar = info->ioport_bar;
- e->osts = info->osts;
- e->product_name = info->product_name;
- e->product_version = info->product_version;
- dc->props = info->props;
- dc->reset = megasas_scsi_reset;
- dc->vmsd = info->vmsd;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
- dc->desc = info->desc;
-}
-
-static const TypeInfo megasas_info = {
- .name = TYPE_MEGASAS_BASE,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(MegasasState),
- .class_size = sizeof(MegasasBaseClass),
- .abstract = true,
-};
-
-static void megasas_register_types(void)
-{
- int i;
-
- type_register_static(&megasas_info);
- for (i = 0; i < ARRAY_SIZE(megasas_devices); i++) {
- const MegasasInfo *info = &megasas_devices[i];
- TypeInfo type_info = {};
-
- type_info.name = info->name;
- type_info.parent = TYPE_MEGASAS_BASE;
- type_info.class_data = (void *)info;
- type_info.class_init = megasas_class_init;
-
- type_register(&type_info);
- }
-}
-
-type_init(megasas_register_types)
diff --git a/qemu/hw/scsi/mfi.h b/qemu/hw/scsi/mfi.h
deleted file mode 100644
index 29d41775d..000000000
--- a/qemu/hw/scsi/mfi.h
+++ /dev/null
@@ -1,1272 +0,0 @@
-/*
- * NetBSD header file, copied from
- * http://gitorious.org/freebsd/freebsd/blobs/HEAD/sys/dev/mfi/mfireg.h
- */
-/*-
- * Copyright (c) 2006 IronPort Systems
- * Copyright (c) 2007 LSI Corp.
- * Copyright (c) 2007 Rajesh Prabhakaran.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef MFI_REG_H
-#define MFI_REG_H
-
-/*
- * MegaRAID SAS MFI firmware definitions
- */
-
-/*
- * Start with the register set. All registers are 32 bits wide.
- * The usual Intel IOP style setup.
- */
-#define MFI_IMSG0 0x10 /* Inbound message 0 */
-#define MFI_IMSG1 0x14 /* Inbound message 1 */
-#define MFI_OMSG0 0x18 /* Outbound message 0 */
-#define MFI_OMSG1 0x1c /* Outbound message 1 */
-#define MFI_IDB 0x20 /* Inbound doorbell */
-#define MFI_ISTS 0x24 /* Inbound interrupt status */
-#define MFI_IMSK 0x28 /* Inbound interrupt mask */
-#define MFI_ODB 0x2c /* Outbound doorbell */
-#define MFI_OSTS 0x30 /* Outbound interrupt status */
-#define MFI_OMSK 0x34 /* Outbound interrupt mask */
-#define MFI_IQP 0x40 /* Inbound queue port */
-#define MFI_OQP 0x44 /* Outbound queue port */
-
-/*
- * 1078 specific related register
- */
-#define MFI_ODR0 0x9c /* outbound doorbell register0 */
-#define MFI_ODCR0 0xa0 /* outbound doorbell clear register0 */
-#define MFI_OSP0 0xb0 /* outbound scratch pad0 */
-#define MFI_OSP1 0xb4 /* outbound scratch pad1 */
-#define MFI_IQPL 0xc0 /* Inbound queue port (low bytes) */
-#define MFI_IQPH 0xc4 /* Inbound queue port (high bytes) */
-#define MFI_DIAG 0xf8 /* Host diag */
-#define MFI_SEQ 0xfc /* Sequencer offset */
-#define MFI_1078_EIM 0x80000004 /* 1078 enable intrrupt mask */
-#define MFI_RMI 0x2 /* reply message interrupt */
-#define MFI_1078_RM 0x80000000 /* reply 1078 message interrupt */
-#define MFI_ODC 0x4 /* outbound doorbell change interrupt */
-
-/*
- * gen2 specific changes
- */
-#define MFI_GEN2_EIM 0x00000005 /* gen2 enable interrupt mask */
-#define MFI_GEN2_RM 0x00000001 /* reply gen2 message interrupt */
-
-/*
- * skinny specific changes
- */
-#define MFI_SKINNY_IDB 0x00 /* Inbound doorbell is at 0x00 for skinny */
-#define MFI_SKINNY_RM 0x00000001 /* reply skinny message interrupt */
-
-/* Bits for MFI_OSTS */
-#define MFI_OSTS_INTR_VALID 0x00000002
-
-/*
- * Firmware state values. Found in OMSG0 during initialization.
- */
-#define MFI_FWSTATE_MASK 0xf0000000
-#define MFI_FWSTATE_UNDEFINED 0x00000000
-#define MFI_FWSTATE_BB_INIT 0x10000000
-#define MFI_FWSTATE_FW_INIT 0x40000000
-#define MFI_FWSTATE_WAIT_HANDSHAKE 0x60000000
-#define MFI_FWSTATE_FW_INIT_2 0x70000000
-#define MFI_FWSTATE_DEVICE_SCAN 0x80000000
-#define MFI_FWSTATE_BOOT_MSG_PENDING 0x90000000
-#define MFI_FWSTATE_FLUSH_CACHE 0xa0000000
-#define MFI_FWSTATE_READY 0xb0000000
-#define MFI_FWSTATE_OPERATIONAL 0xc0000000
-#define MFI_FWSTATE_FAULT 0xf0000000
-#define MFI_FWSTATE_MAXSGL_MASK 0x00ff0000
-#define MFI_FWSTATE_MAXCMD_MASK 0x0000ffff
-#define MFI_FWSTATE_MSIX_SUPPORTED 0x04000000
-#define MFI_FWSTATE_HOSTMEMREQD_MASK 0x08000000
-
-/*
- * Control bits to drive the card to ready state. These go into the IDB
- * register.
- */
-#define MFI_FWINIT_ABORT 0x00000001 /* Abort all pending commands */
-#define MFI_FWINIT_READY 0x00000002 /* Move from operational to ready */
-#define MFI_FWINIT_MFIMODE 0x00000004 /* unknown */
-#define MFI_FWINIT_CLEAR_HANDSHAKE 0x00000008 /* Respond to WAIT_HANDSHAKE */
-#define MFI_FWINIT_HOTPLUG 0x00000010
-#define MFI_FWINIT_STOP_ADP 0x00000020 /* Move to operational, stop */
-#define MFI_FWINIT_ADP_RESET 0x00000040 /* Reset ADP */
-
-/*
- * Control bits for the DIAG register
- */
-#define MFI_DIAG_WRITE_ENABLE 0x00000080
-#define MFI_DIAG_RESET_ADP 0x00000004
-
-/* MFI Commands */
-typedef enum {
- MFI_CMD_INIT = 0x00,
- MFI_CMD_LD_READ,
- MFI_CMD_LD_WRITE,
- MFI_CMD_LD_SCSI_IO,
- MFI_CMD_PD_SCSI_IO,
- MFI_CMD_DCMD,
- MFI_CMD_ABORT,
- MFI_CMD_SMP,
- MFI_CMD_STP
-} mfi_cmd_t;
-
-/* Direct commands */
-typedef enum {
- MFI_DCMD_CTRL_MFI_HOST_MEM_ALLOC = 0x0100e100,
- MFI_DCMD_CTRL_GET_INFO = 0x01010000,
- MFI_DCMD_CTRL_GET_PROPERTIES = 0x01020100,
- MFI_DCMD_CTRL_SET_PROPERTIES = 0x01020200,
- MFI_DCMD_CTRL_ALARM = 0x01030000,
- MFI_DCMD_CTRL_ALARM_GET = 0x01030100,
- MFI_DCMD_CTRL_ALARM_ENABLE = 0x01030200,
- MFI_DCMD_CTRL_ALARM_DISABLE = 0x01030300,
- MFI_DCMD_CTRL_ALARM_SILENCE = 0x01030400,
- MFI_DCMD_CTRL_ALARM_TEST = 0x01030500,
- MFI_DCMD_CTRL_EVENT_GETINFO = 0x01040100,
- MFI_DCMD_CTRL_EVENT_CLEAR = 0x01040200,
- MFI_DCMD_CTRL_EVENT_GET = 0x01040300,
- MFI_DCMD_CTRL_EVENT_COUNT = 0x01040400,
- MFI_DCMD_CTRL_EVENT_WAIT = 0x01040500,
- MFI_DCMD_CTRL_SHUTDOWN = 0x01050000,
- MFI_DCMD_HIBERNATE_STANDBY = 0x01060000,
- MFI_DCMD_CTRL_GET_TIME = 0x01080101,
- MFI_DCMD_CTRL_SET_TIME = 0x01080102,
- MFI_DCMD_CTRL_BIOS_DATA_GET = 0x010c0100,
- MFI_DCMD_CTRL_BIOS_DATA_SET = 0x010c0200,
- MFI_DCMD_CTRL_FACTORY_DEFAULTS = 0x010d0000,
- MFI_DCMD_CTRL_MFC_DEFAULTS_GET = 0x010e0201,
- MFI_DCMD_CTRL_MFC_DEFAULTS_SET = 0x010e0202,
- MFI_DCMD_CTRL_CACHE_FLUSH = 0x01101000,
- MFI_DCMD_PD_GET_LIST = 0x02010000,
- MFI_DCMD_PD_LIST_QUERY = 0x02010100,
- MFI_DCMD_PD_GET_INFO = 0x02020000,
- MFI_DCMD_PD_STATE_SET = 0x02030100,
- MFI_DCMD_PD_REBUILD = 0x02040100,
- MFI_DCMD_PD_BLINK = 0x02070100,
- MFI_DCMD_PD_UNBLINK = 0x02070200,
- MFI_DCMD_LD_GET_LIST = 0x03010000,
- MFI_DCMD_LD_LIST_QUERY = 0x03010100,
- MFI_DCMD_LD_GET_INFO = 0x03020000,
- MFI_DCMD_LD_GET_PROP = 0x03030000,
- MFI_DCMD_LD_SET_PROP = 0x03040000,
- MFI_DCMD_LD_DELETE = 0x03090000,
- MFI_DCMD_CFG_READ = 0x04010000,
- MFI_DCMD_CFG_ADD = 0x04020000,
- MFI_DCMD_CFG_CLEAR = 0x04030000,
- MFI_DCMD_CFG_FOREIGN_READ = 0x04060100,
- MFI_DCMD_CFG_FOREIGN_IMPORT = 0x04060400,
- MFI_DCMD_BBU_STATUS = 0x05010000,
- MFI_DCMD_BBU_CAPACITY_INFO = 0x05020000,
- MFI_DCMD_BBU_DESIGN_INFO = 0x05030000,
- MFI_DCMD_BBU_PROP_GET = 0x05050100,
- MFI_DCMD_CLUSTER = 0x08000000,
- MFI_DCMD_CLUSTER_RESET_ALL = 0x08010100,
- MFI_DCMD_CLUSTER_RESET_LD = 0x08010200
-} mfi_dcmd_t;
-
-/* Modifiers for MFI_DCMD_CTRL_FLUSHCACHE */
-#define MFI_FLUSHCACHE_CTRL 0x01
-#define MFI_FLUSHCACHE_DISK 0x02
-
-/* Modifiers for MFI_DCMD_CTRL_SHUTDOWN */
-#define MFI_SHUTDOWN_SPINDOWN 0x01
-
-/*
- * MFI Frame flags
- */
-typedef enum {
- MFI_FRAME_DONT_POST_IN_REPLY_QUEUE = 0x0001,
- MFI_FRAME_SGL64 = 0x0002,
- MFI_FRAME_SENSE64 = 0x0004,
- MFI_FRAME_DIR_WRITE = 0x0008,
- MFI_FRAME_DIR_READ = 0x0010,
- MFI_FRAME_IEEE_SGL = 0x0020,
-} mfi_frame_flags;
-
-/* MFI Status codes */
-typedef enum {
- MFI_STAT_OK = 0x00,
- MFI_STAT_INVALID_CMD,
- MFI_STAT_INVALID_DCMD,
- MFI_STAT_INVALID_PARAMETER,
- MFI_STAT_INVALID_SEQUENCE_NUMBER,
- MFI_STAT_ABORT_NOT_POSSIBLE,
- MFI_STAT_APP_HOST_CODE_NOT_FOUND,
- MFI_STAT_APP_IN_USE,
- MFI_STAT_APP_NOT_INITIALIZED,
- MFI_STAT_ARRAY_INDEX_INVALID,
- MFI_STAT_ARRAY_ROW_NOT_EMPTY,
- MFI_STAT_CONFIG_RESOURCE_CONFLICT,
- MFI_STAT_DEVICE_NOT_FOUND,
- MFI_STAT_DRIVE_TOO_SMALL,
- MFI_STAT_FLASH_ALLOC_FAIL,
- MFI_STAT_FLASH_BUSY,
- MFI_STAT_FLASH_ERROR = 0x10,
- MFI_STAT_FLASH_IMAGE_BAD,
- MFI_STAT_FLASH_IMAGE_INCOMPLETE,
- MFI_STAT_FLASH_NOT_OPEN,
- MFI_STAT_FLASH_NOT_STARTED,
- MFI_STAT_FLUSH_FAILED,
- MFI_STAT_HOST_CODE_NOT_FOUNT,
- MFI_STAT_LD_CC_IN_PROGRESS,
- MFI_STAT_LD_INIT_IN_PROGRESS,
- MFI_STAT_LD_LBA_OUT_OF_RANGE,
- MFI_STAT_LD_MAX_CONFIGURED,
- MFI_STAT_LD_NOT_OPTIMAL,
- MFI_STAT_LD_RBLD_IN_PROGRESS,
- MFI_STAT_LD_RECON_IN_PROGRESS,
- MFI_STAT_LD_WRONG_RAID_LEVEL,
- MFI_STAT_MAX_SPARES_EXCEEDED,
- MFI_STAT_MEMORY_NOT_AVAILABLE = 0x20,
- MFI_STAT_MFC_HW_ERROR,
- MFI_STAT_NO_HW_PRESENT,
- MFI_STAT_NOT_FOUND,
- MFI_STAT_NOT_IN_ENCL,
- MFI_STAT_PD_CLEAR_IN_PROGRESS,
- MFI_STAT_PD_TYPE_WRONG,
- MFI_STAT_PR_DISABLED,
- MFI_STAT_ROW_INDEX_INVALID,
- MFI_STAT_SAS_CONFIG_INVALID_ACTION,
- MFI_STAT_SAS_CONFIG_INVALID_DATA,
- MFI_STAT_SAS_CONFIG_INVALID_PAGE,
- MFI_STAT_SAS_CONFIG_INVALID_TYPE,
- MFI_STAT_SCSI_DONE_WITH_ERROR,
- MFI_STAT_SCSI_IO_FAILED,
- MFI_STAT_SCSI_RESERVATION_CONFLICT,
- MFI_STAT_SHUTDOWN_FAILED = 0x30,
- MFI_STAT_TIME_NOT_SET,
- MFI_STAT_WRONG_STATE,
- MFI_STAT_LD_OFFLINE,
- MFI_STAT_PEER_NOTIFICATION_REJECTED,
- MFI_STAT_PEER_NOTIFICATION_FAILED,
- MFI_STAT_RESERVATION_IN_PROGRESS,
- MFI_STAT_I2C_ERRORS_DETECTED,
- MFI_STAT_PCI_ERRORS_DETECTED,
- MFI_STAT_DIAG_FAILED,
- MFI_STAT_BOOT_MSG_PENDING,
- MFI_STAT_FOREIGN_CONFIG_INCOMPLETE,
- MFI_STAT_INVALID_SGL,
- MFI_STAT_UNSUPPORTED_HW,
- MFI_STAT_CC_SCHEDULE_DISABLED,
- MFI_STAT_PD_COPYBACK_IN_PROGRESS,
- MFI_STAT_MULTIPLE_PDS_IN_ARRAY = 0x40,
- MFI_STAT_FW_DOWNLOAD_ERROR,
- MFI_STAT_FEATURE_SECURITY_NOT_ENABLED,
- MFI_STAT_LOCK_KEY_ALREADY_EXISTS,
- MFI_STAT_LOCK_KEY_BACKUP_NOT_ALLOWED,
- MFI_STAT_LOCK_KEY_VERIFY_NOT_ALLOWED,
- MFI_STAT_LOCK_KEY_VERIFY_FAILED,
- MFI_STAT_LOCK_KEY_REKEY_NOT_ALLOWED,
- MFI_STAT_LOCK_KEY_INVALID,
- MFI_STAT_LOCK_KEY_ESCROW_INVALID,
- MFI_STAT_LOCK_KEY_BACKUP_REQUIRED,
- MFI_STAT_SECURE_LD_EXISTS,
- MFI_STAT_LD_SECURE_NOT_ALLOWED,
- MFI_STAT_REPROVISION_NOT_ALLOWED,
- MFI_STAT_PD_SECURITY_TYPE_WRONG,
- MFI_STAT_LD_ENCRYPTION_TYPE_INVALID,
- MFI_STAT_CONFIG_FDE_NON_FDE_MIX_NOT_ALLOWED = 0x50,
- MFI_STAT_CONFIG_LD_ENCRYPTION_TYPE_MIX_NOT_ALLOWED,
- MFI_STAT_SECRET_KEY_NOT_ALLOWED,
- MFI_STAT_PD_HW_ERRORS_DETECTED,
- MFI_STAT_LD_CACHE_PINNED,
- MFI_STAT_POWER_STATE_SET_IN_PROGRESS,
- MFI_STAT_POWER_STATE_SET_BUSY,
- MFI_STAT_POWER_STATE_WRONG,
- MFI_STAT_PR_NO_AVAILABLE_PD_FOUND,
- MFI_STAT_CTRL_RESET_REQUIRED,
- MFI_STAT_LOCK_KEY_EKM_NO_BOOT_AGENT,
- MFI_STAT_SNAP_NO_SPACE,
- MFI_STAT_SNAP_PARTIAL_FAILURE,
- MFI_STAT_UPGRADE_KEY_INCOMPATIBLE,
- MFI_STAT_PFK_INCOMPATIBLE,
- MFI_STAT_PD_MAX_UNCONFIGURED,
- MFI_STAT_IO_METRICS_DISABLED = 0x60,
- MFI_STAT_AEC_NOT_STOPPED,
- MFI_STAT_PI_TYPE_WRONG,
- MFI_STAT_LD_PD_PI_INCOMPATIBLE,
- MFI_STAT_PI_NOT_ENABLED,
- MFI_STAT_LD_BLOCK_SIZE_MISMATCH,
- MFI_STAT_INVALID_STATUS = 0xFF
-} mfi_status_t;
-
-/* Event classes */
-typedef enum {
- MFI_EVT_CLASS_DEBUG = -2,
- MFI_EVT_CLASS_PROGRESS = -1,
- MFI_EVT_CLASS_INFO = 0,
- MFI_EVT_CLASS_WARNING = 1,
- MFI_EVT_CLASS_CRITICAL = 2,
- MFI_EVT_CLASS_FATAL = 3,
- MFI_EVT_CLASS_DEAD = 4
-} mfi_evt_class_t;
-
-/* Event locales */
-typedef enum {
- MFI_EVT_LOCALE_LD = 0x0001,
- MFI_EVT_LOCALE_PD = 0x0002,
- MFI_EVT_LOCALE_ENCL = 0x0004,
- MFI_EVT_LOCALE_BBU = 0x0008,
- MFI_EVT_LOCALE_SAS = 0x0010,
- MFI_EVT_LOCALE_CTRL = 0x0020,
- MFI_EVT_LOCALE_CONFIG = 0x0040,
- MFI_EVT_LOCALE_CLUSTER = 0x0080,
- MFI_EVT_LOCALE_ALL = 0xffff
-} mfi_evt_locale_t;
-
-/* Event args */
-typedef enum {
- MR_EVT_ARGS_NONE = 0x00,
- MR_EVT_ARGS_CDB_SENSE,
- MR_EVT_ARGS_LD,
- MR_EVT_ARGS_LD_COUNT,
- MR_EVT_ARGS_LD_LBA,
- MR_EVT_ARGS_LD_OWNER,
- MR_EVT_ARGS_LD_LBA_PD_LBA,
- MR_EVT_ARGS_LD_PROG,
- MR_EVT_ARGS_LD_STATE,
- MR_EVT_ARGS_LD_STRIP,
- MR_EVT_ARGS_PD,
- MR_EVT_ARGS_PD_ERR,
- MR_EVT_ARGS_PD_LBA,
- MR_EVT_ARGS_PD_LBA_LD,
- MR_EVT_ARGS_PD_PROG,
- MR_EVT_ARGS_PD_STATE,
- MR_EVT_ARGS_PCI,
- MR_EVT_ARGS_RATE,
- MR_EVT_ARGS_STR,
- MR_EVT_ARGS_TIME,
- MR_EVT_ARGS_ECC,
- MR_EVT_ARGS_LD_PROP,
- MR_EVT_ARGS_PD_SPARE,
- MR_EVT_ARGS_PD_INDEX,
- MR_EVT_ARGS_DIAG_PASS,
- MR_EVT_ARGS_DIAG_FAIL,
- MR_EVT_ARGS_PD_LBA_LBA,
- MR_EVT_ARGS_PORT_PHY,
- MR_EVT_ARGS_PD_MISSING,
- MR_EVT_ARGS_PD_ADDRESS,
- MR_EVT_ARGS_BITMAP,
- MR_EVT_ARGS_CONNECTOR,
- MR_EVT_ARGS_PD_PD,
- MR_EVT_ARGS_PD_FRU,
- MR_EVT_ARGS_PD_PATHINFO,
- MR_EVT_ARGS_PD_POWER_STATE,
- MR_EVT_ARGS_GENERIC,
-} mfi_evt_args;
-
-/* Event codes */
-#define MR_EVT_CFG_CLEARED 0x0004
-#define MR_EVT_CTRL_SHUTDOWN 0x002a
-#define MR_EVT_LD_STATE_CHANGE 0x0051
-#define MR_EVT_PD_INSERTED 0x005b
-#define MR_EVT_PD_REMOVED 0x0070
-#define MR_EVT_PD_STATE_CHANGED 0x0072
-#define MR_EVT_LD_CREATED 0x008a
-#define MR_EVT_LD_DELETED 0x008b
-#define MR_EVT_FOREIGN_CFG_IMPORTED 0x00db
-#define MR_EVT_LD_OFFLINE 0x00fc
-#define MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED 0x0152
-
-typedef enum {
- MR_LD_CACHE_WRITE_BACK = 0x01,
- MR_LD_CACHE_WRITE_ADAPTIVE = 0x02,
- MR_LD_CACHE_READ_AHEAD = 0x04,
- MR_LD_CACHE_READ_ADAPTIVE = 0x08,
- MR_LD_CACHE_WRITE_CACHE_BAD_BBU = 0x10,
- MR_LD_CACHE_ALLOW_WRITE_CACHE = 0x20,
- MR_LD_CACHE_ALLOW_READ_CACHE = 0x40
-} mfi_ld_cache;
-
-typedef enum {
- MR_PD_CACHE_UNCHANGED = 0,
- MR_PD_CACHE_ENABLE = 1,
- MR_PD_CACHE_DISABLE = 2
-} mfi_pd_cache;
-
-typedef enum {
- MR_PD_QUERY_TYPE_ALL = 0,
- MR_PD_QUERY_TYPE_STATE = 1,
- MR_PD_QUERY_TYPE_POWER_STATE = 2,
- MR_PD_QUERY_TYPE_MEDIA_TYPE = 3,
- MR_PD_QUERY_TYPE_SPEED = 4,
- MR_PD_QUERY_TYPE_EXPOSED_TO_HOST = 5, /*query for system drives */
-} mfi_pd_query_type;
-
-typedef enum {
- MR_LD_QUERY_TYPE_ALL = 0,
- MR_LD_QUERY_TYPE_EXPOSED_TO_HOST = 1,
- MR_LD_QUERY_TYPE_USED_TGT_IDS = 2,
- MR_LD_QUERY_TYPE_CLUSTER_ACCESS = 3,
- MR_LD_QUERY_TYPE_CLUSTER_LOCALE = 4,
-} mfi_ld_query_type;
-
-/*
- * Other propertities and definitions
- */
-#define MFI_MAX_PD_CHANNELS 2
-#define MFI_MAX_LD_CHANNELS 2
-#define MFI_MAX_CHANNELS (MFI_MAX_PD_CHANNELS + MFI_MAX_LD_CHANNELS)
-#define MFI_MAX_CHANNEL_DEVS 128
-#define MFI_DEFAULT_ID -1
-#define MFI_MAX_LUN 8
-#define MFI_MAX_LD 64
-
-#define MFI_FRAME_SIZE 64
-#define MFI_MBOX_SIZE 12
-
-/* Firmware flashing can take 40s */
-#define MFI_POLL_TIMEOUT_SECS 50
-
-/* Allow for speedier math calculations */
-#define MFI_SECTOR_LEN 512
-
-/* Scatter Gather elements */
-struct mfi_sg32 {
- uint32_t addr;
- uint32_t len;
-} QEMU_PACKED;
-
-struct mfi_sg64 {
- uint64_t addr;
- uint32_t len;
-} QEMU_PACKED;
-
-struct mfi_sg_skinny {
- uint64_t addr;
- uint32_t len;
- uint32_t flag;
-} QEMU_PACKED;
-
-union mfi_sgl {
- struct mfi_sg32 sg32[1];
- struct mfi_sg64 sg64[1];
- struct mfi_sg_skinny sg_skinny[1];
-} QEMU_PACKED;
-
-/* Message frames. All messages have a common header */
-struct mfi_frame_header {
- uint8_t frame_cmd;
- uint8_t sense_len;
- uint8_t cmd_status;
- uint8_t scsi_status;
- uint8_t target_id;
- uint8_t lun_id;
- uint8_t cdb_len;
- uint8_t sge_count;
- uint64_t context;
- uint16_t flags;
- uint16_t timeout;
- uint32_t data_len;
-} QEMU_PACKED;
-
-struct mfi_init_frame {
- struct mfi_frame_header header;
- uint32_t qinfo_new_addr_lo;
- uint32_t qinfo_new_addr_hi;
- uint32_t qinfo_old_addr_lo;
- uint32_t qinfo_old_addr_hi;
- uint32_t reserved[6];
-};
-
-#define MFI_IO_FRAME_SIZE 40
-struct mfi_io_frame {
- struct mfi_frame_header header;
- uint32_t sense_addr_lo;
- uint32_t sense_addr_hi;
- uint32_t lba_lo;
- uint32_t lba_hi;
- union mfi_sgl sgl;
-} QEMU_PACKED;
-
-#define MFI_PASS_FRAME_SIZE 48
-struct mfi_pass_frame {
- struct mfi_frame_header header;
- uint32_t sense_addr_lo;
- uint32_t sense_addr_hi;
- uint8_t cdb[16];
- union mfi_sgl sgl;
-} QEMU_PACKED;
-
-#define MFI_DCMD_FRAME_SIZE 40
-struct mfi_dcmd_frame {
- struct mfi_frame_header header;
- uint32_t opcode;
- uint8_t mbox[MFI_MBOX_SIZE];
- union mfi_sgl sgl;
-} QEMU_PACKED;
-
-struct mfi_abort_frame {
- struct mfi_frame_header header;
- uint64_t abort_context;
- uint32_t abort_mfi_addr_lo;
- uint32_t abort_mfi_addr_hi;
- uint32_t reserved1[6];
-} QEMU_PACKED;
-
-struct mfi_smp_frame {
- struct mfi_frame_header header;
- uint64_t sas_addr;
- union {
- struct mfi_sg32 sg32[2];
- struct mfi_sg64 sg64[2];
- } sgl;
-} QEMU_PACKED;
-
-struct mfi_stp_frame {
- struct mfi_frame_header header;
- uint16_t fis[10];
- uint32_t stp_flags;
- union {
- struct mfi_sg32 sg32[2];
- struct mfi_sg64 sg64[2];
- } sgl;
-} QEMU_PACKED;
-
-union mfi_frame {
- struct mfi_frame_header header;
- struct mfi_init_frame init;
- struct mfi_io_frame io;
- struct mfi_pass_frame pass;
- struct mfi_dcmd_frame dcmd;
- struct mfi_abort_frame abort;
- struct mfi_smp_frame smp;
- struct mfi_stp_frame stp;
- uint64_t raw[8];
- uint8_t bytes[MFI_FRAME_SIZE];
-};
-
-#define MFI_SENSE_LEN 128
-struct mfi_sense {
- uint8_t data[MFI_SENSE_LEN];
-};
-
-#define MFI_QUEUE_FLAG_CONTEXT64 0x00000002
-
-/* The queue init structure that is passed with the init message */
-struct mfi_init_qinfo {
- uint32_t flags;
- uint32_t rq_entries;
- uint32_t rq_addr_lo;
- uint32_t rq_addr_hi;
- uint32_t pi_addr_lo;
- uint32_t pi_addr_hi;
- uint32_t ci_addr_lo;
- uint32_t ci_addr_hi;
-} QEMU_PACKED;
-
-/* Controller properties */
-struct mfi_ctrl_props {
- uint16_t seq_num;
- uint16_t pred_fail_poll_interval;
- uint16_t intr_throttle_cnt;
- uint16_t intr_throttle_timeout;
- uint8_t rebuild_rate;
- uint8_t patrol_read_rate;
- uint8_t bgi_rate;
- uint8_t cc_rate;
- uint8_t recon_rate;
- uint8_t cache_flush_interval;
- uint8_t spinup_drv_cnt;
- uint8_t spinup_delay;
- uint8_t cluster_enable;
- uint8_t coercion_mode;
- uint8_t alarm_enable;
- uint8_t disable_auto_rebuild;
- uint8_t disable_battery_warn;
- uint8_t ecc_bucket_size;
- uint16_t ecc_bucket_leak_rate;
- uint8_t restore_hotspare_on_insertion;
- uint8_t expose_encl_devices;
- uint8_t maintainPdFailHistory;
- uint8_t disallowHostRequestReordering;
- uint8_t abortCCOnError;
- uint8_t loadBalanceMode;
- uint8_t disableAutoDetectBackplane;
- uint8_t snapVDSpace;
- uint32_t OnOffProperties;
-/* set TRUE to disable copyBack (0=copyback enabled) */
-#define MFI_CTRL_PROP_CopyBackDisabled (1 << 0)
-#define MFI_CTRL_PROP_SMARTerEnabled (1 << 1)
-#define MFI_CTRL_PROP_PRCorrectUnconfiguredAreas (1 << 2)
-#define MFI_CTRL_PROP_UseFdeOnly (1 << 3)
-#define MFI_CTRL_PROP_DisableNCQ (1 << 4)
-#define MFI_CTRL_PROP_SSDSMARTerEnabled (1 << 5)
-#define MFI_CTRL_PROP_SSDPatrolReadEnabled (1 << 6)
-#define MFI_CTRL_PROP_EnableSpinDownUnconfigured (1 << 7)
-#define MFI_CTRL_PROP_AutoEnhancedImport (1 << 8)
-#define MFI_CTRL_PROP_EnableSecretKeyControl (1 << 9)
-#define MFI_CTRL_PROP_DisableOnlineCtrlReset (1 << 10)
-#define MFI_CTRL_PROP_AllowBootWithPinnedCache (1 << 11)
-#define MFI_CTRL_PROP_DisableSpinDownHS (1 << 12)
-#define MFI_CTRL_PROP_EnableJBOD (1 << 13)
-
- uint8_t autoSnapVDSpace; /* % of source LD to be
- * reserved for auto snapshot
- * in snapshot repository, for
- * metadata and user data
- * 1=5%, 2=10%, 3=15% and so on
- */
- uint8_t viewSpace; /* snapshot writeable VIEWs
- * capacity as a % of source LD
- * capacity. 0=READ only
- * 1=5%, 2=10%, 3=15% and so on
- */
- uint16_t spinDownTime; /* # of idle minutes before device
- * is spun down (0=use FW defaults)
- */
- uint8_t reserved[24];
-} QEMU_PACKED;
-
-/* PCI information about the card. */
-struct mfi_info_pci {
- uint16_t vendor;
- uint16_t device;
- uint16_t subvendor;
- uint16_t subdevice;
- uint8_t reserved[24];
-} QEMU_PACKED;
-
-/* Host (front end) interface information */
-struct mfi_info_host {
- uint8_t type;
-#define MFI_INFO_HOST_PCIX 0x01
-#define MFI_INFO_HOST_PCIE 0x02
-#define MFI_INFO_HOST_ISCSI 0x04
-#define MFI_INFO_HOST_SAS3G 0x08
- uint8_t reserved[6];
- uint8_t port_count;
- uint64_t port_addr[8];
-} QEMU_PACKED;
-
-/* Device (back end) interface information */
-struct mfi_info_device {
- uint8_t type;
-#define MFI_INFO_DEV_SPI 0x01
-#define MFI_INFO_DEV_SAS3G 0x02
-#define MFI_INFO_DEV_SATA1 0x04
-#define MFI_INFO_DEV_SATA3G 0x08
-#define MFI_INFO_DEV_PCIE 0x10
- uint8_t reserved[6];
- uint8_t port_count;
- uint64_t port_addr[8];
-} QEMU_PACKED;
-
-/* Firmware component information */
-struct mfi_info_component {
- char name[8];
- char version[32];
- char build_date[16];
- char build_time[16];
-} QEMU_PACKED;
-
-/* Controller default settings */
-struct mfi_defaults {
- uint64_t sas_addr;
- uint8_t phy_polarity;
- uint8_t background_rate;
- uint8_t stripe_size;
- uint8_t flush_time;
- uint8_t write_back;
- uint8_t read_ahead;
- uint8_t cache_when_bbu_bad;
- uint8_t cached_io;
- uint8_t smart_mode;
- uint8_t alarm_disable;
- uint8_t coercion;
- uint8_t zrc_config;
- uint8_t dirty_led_shows_drive_activity;
- uint8_t bios_continue_on_error;
- uint8_t spindown_mode;
- uint8_t allowed_device_types;
- uint8_t allow_mix_in_enclosure;
- uint8_t allow_mix_in_ld;
- uint8_t allow_sata_in_cluster;
- uint8_t max_chained_enclosures;
- uint8_t disable_ctrl_r;
- uint8_t enable_web_bios;
- uint8_t phy_polarity_split;
- uint8_t direct_pd_mapping;
- uint8_t bios_enumerate_lds;
- uint8_t restored_hot_spare_on_insertion;
- uint8_t expose_enclosure_devices;
- uint8_t maintain_pd_fail_history;
- uint8_t disable_puncture;
- uint8_t zero_based_enumeration;
- uint8_t disable_preboot_cli;
- uint8_t show_drive_led_on_activity;
- uint8_t cluster_disable;
- uint8_t sas_disable;
- uint8_t auto_detect_backplane;
- uint8_t fde_only;
- uint8_t delay_during_post;
- uint8_t resv[19];
-} QEMU_PACKED;
-
-/* Controller default settings */
-struct mfi_bios_data {
- uint16_t boot_target_id;
- uint8_t do_not_int_13;
- uint8_t continue_on_error;
- uint8_t verbose;
- uint8_t geometry;
- uint8_t expose_all_drives;
- uint8_t reserved[56];
- uint8_t check_sum;
-} QEMU_PACKED;
-
-/* SAS (?) controller info, returned from MFI_DCMD_CTRL_GETINFO. */
-struct mfi_ctrl_info {
- struct mfi_info_pci pci;
- struct mfi_info_host host;
- struct mfi_info_device device;
-
- /* Firmware components that are present and active. */
- uint32_t image_check_word;
- uint32_t image_component_count;
- struct mfi_info_component image_component[8];
-
- /* Firmware components that have been flashed but are inactive */
- uint32_t pending_image_component_count;
- struct mfi_info_component pending_image_component[8];
-
- uint8_t max_arms;
- uint8_t max_spans;
- uint8_t max_arrays;
- uint8_t max_lds;
- char product_name[80];
- char serial_number[32];
- uint32_t hw_present;
-#define MFI_INFO_HW_BBU 0x01
-#define MFI_INFO_HW_ALARM 0x02
-#define MFI_INFO_HW_NVRAM 0x04
-#define MFI_INFO_HW_UART 0x08
-#define MFI_INFO_HW_MEM 0x10
-#define MFI_INFO_HW_FLASH 0x20
- uint32_t current_fw_time;
- uint16_t max_cmds;
- uint16_t max_sg_elements;
- uint32_t max_request_size;
- uint16_t lds_present;
- uint16_t lds_degraded;
- uint16_t lds_offline;
- uint16_t pd_present;
- uint16_t pd_disks_present;
- uint16_t pd_disks_pred_failure;
- uint16_t pd_disks_failed;
- uint16_t nvram_size;
- uint16_t memory_size;
- uint16_t flash_size;
- uint16_t ram_correctable_errors;
- uint16_t ram_uncorrectable_errors;
- uint8_t cluster_allowed;
- uint8_t cluster_active;
- uint16_t max_strips_per_io;
-
- uint32_t raid_levels;
-#define MFI_INFO_RAID_0 0x01
-#define MFI_INFO_RAID_1 0x02
-#define MFI_INFO_RAID_5 0x04
-#define MFI_INFO_RAID_1E 0x08
-#define MFI_INFO_RAID_6 0x10
-
- uint32_t adapter_ops;
-#define MFI_INFO_AOPS_RBLD_RATE 0x0001
-#define MFI_INFO_AOPS_CC_RATE 0x0002
-#define MFI_INFO_AOPS_BGI_RATE 0x0004
-#define MFI_INFO_AOPS_RECON_RATE 0x0008
-#define MFI_INFO_AOPS_PATROL_RATE 0x0010
-#define MFI_INFO_AOPS_ALARM_CONTROL 0x0020
-#define MFI_INFO_AOPS_CLUSTER_SUPPORTED 0x0040
-#define MFI_INFO_AOPS_BBU 0x0080
-#define MFI_INFO_AOPS_SPANNING_ALLOWED 0x0100
-#define MFI_INFO_AOPS_DEDICATED_SPARES 0x0200
-#define MFI_INFO_AOPS_REVERTIBLE_SPARES 0x0400
-#define MFI_INFO_AOPS_FOREIGN_IMPORT 0x0800
-#define MFI_INFO_AOPS_SELF_DIAGNOSTIC 0x1000
-#define MFI_INFO_AOPS_MIXED_ARRAY 0x2000
-#define MFI_INFO_AOPS_GLOBAL_SPARES 0x4000
-
- uint32_t ld_ops;
-#define MFI_INFO_LDOPS_READ_POLICY 0x01
-#define MFI_INFO_LDOPS_WRITE_POLICY 0x02
-#define MFI_INFO_LDOPS_IO_POLICY 0x04
-#define MFI_INFO_LDOPS_ACCESS_POLICY 0x08
-#define MFI_INFO_LDOPS_DISK_CACHE_POLICY 0x10
-
- struct {
- uint8_t min;
- uint8_t max;
- uint8_t reserved[2];
- } QEMU_PACKED stripe_sz_ops;
-
- uint32_t pd_ops;
-#define MFI_INFO_PDOPS_FORCE_ONLINE 0x01
-#define MFI_INFO_PDOPS_FORCE_OFFLINE 0x02
-#define MFI_INFO_PDOPS_FORCE_REBUILD 0x04
-
- uint32_t pd_mix_support;
-#define MFI_INFO_PDMIX_SAS 0x01
-#define MFI_INFO_PDMIX_SATA 0x02
-#define MFI_INFO_PDMIX_ENCL 0x04
-#define MFI_INFO_PDMIX_LD 0x08
-#define MFI_INFO_PDMIX_SATA_CLUSTER 0x10
-
- uint8_t ecc_bucket_count;
- uint8_t reserved2[11];
- struct mfi_ctrl_props properties;
- char package_version[0x60];
- uint8_t pad[0x800 - 0x6a0];
-} QEMU_PACKED;
-
-/* keep track of an event. */
-union mfi_evt {
- struct {
- uint16_t locale;
- uint8_t reserved;
- int8_t class;
- } members;
- uint32_t word;
-} QEMU_PACKED;
-
-/* event log state. */
-struct mfi_evt_log_state {
- uint32_t newest_seq_num;
- uint32_t oldest_seq_num;
- uint32_t clear_seq_num;
- uint32_t shutdown_seq_num;
- uint32_t boot_seq_num;
-} QEMU_PACKED;
-
-struct mfi_progress {
- uint16_t progress;
- uint16_t elapsed_seconds;
-} QEMU_PACKED;
-
-struct mfi_evt_ld {
- uint16_t target_id;
- uint8_t ld_index;
- uint8_t reserved;
-} QEMU_PACKED;
-
-struct mfi_evt_pd {
- uint16_t device_id;
- uint8_t enclosure_index;
- uint8_t slot_number;
-} QEMU_PACKED;
-
-/* event detail, returned from MFI_DCMD_CTRL_EVENT_WAIT. */
-struct mfi_evt_detail {
- uint32_t seq;
- uint32_t time;
- uint32_t code;
- union mfi_evt class;
- uint8_t arg_type;
- uint8_t reserved1[15];
-
- union {
- struct {
- struct mfi_evt_pd pd;
- uint8_t cdb_len;
- uint8_t sense_len;
- uint8_t reserved[2];
- uint8_t cdb[16];
- uint8_t sense[64];
- } cdb_sense;
-
- struct mfi_evt_ld ld;
-
- struct {
- struct mfi_evt_ld ld;
- uint64_t count;
- } ld_count;
-
- struct {
- uint64_t lba;
- struct mfi_evt_ld ld;
- } ld_lba;
-
- struct {
- struct mfi_evt_ld ld;
- uint32_t pre_owner;
- uint32_t new_owner;
- } ld_owner;
-
- struct {
- uint64_t ld_lba;
- uint64_t pd_lba;
- struct mfi_evt_ld ld;
- struct mfi_evt_pd pd;
- } ld_lba_pd_lba;
-
- struct {
- struct mfi_evt_ld ld;
- struct mfi_progress prog;
- } ld_prog;
-
- struct {
- struct mfi_evt_ld ld;
- uint32_t prev_state;
- uint32_t new_state;
- } ld_state;
-
- struct {
- uint64_t strip;
- struct mfi_evt_ld ld;
- } ld_strip;
-
- struct mfi_evt_pd pd;
-
- struct {
- struct mfi_evt_pd pd;
- uint32_t err;
- } pd_err;
-
- struct {
- uint64_t lba;
- struct mfi_evt_pd pd;
- } pd_lba;
-
- struct {
- uint64_t lba;
- struct mfi_evt_pd pd;
- struct mfi_evt_ld ld;
- } pd_lba_ld;
-
- struct {
- struct mfi_evt_pd pd;
- struct mfi_progress prog;
- } pd_prog;
-
- struct {
- struct mfi_evt_pd ld;
- uint32_t prev_state;
- uint32_t new_state;
- } pd_state;
-
- struct {
- uint16_t venderId;
- uint16_t deviceId;
- uint16_t subVenderId;
- uint16_t subDeviceId;
- } pci;
-
- uint32_t rate;
-
- char str[96];
-
- struct {
- uint32_t rtc;
- uint16_t elapsedSeconds;
- } time;
-
- struct {
- uint32_t ecar;
- uint32_t elog;
- char str[64];
- } ecc;
-
- uint8_t b[96];
- uint16_t s[48];
- uint32_t w[24];
- uint64_t d[12];
- } args;
-
- char description[128];
-} QEMU_PACKED;
-
-struct mfi_evt_list {
- uint32_t count;
- uint32_t reserved;
- struct mfi_evt_detail event[1];
-} QEMU_PACKED;
-
-union mfi_pd_ref {
- struct {
- uint16_t device_id;
- uint16_t seq_num;
- } v;
- uint32_t ref;
-} QEMU_PACKED;
-
-union mfi_pd_ddf_type {
- struct {
- uint16_t pd_type;
-#define MFI_PD_DDF_TYPE_FORCED_PD_GUID (1 << 0)
-#define MFI_PD_DDF_TYPE_IN_VD (1 << 1)
-#define MFI_PD_DDF_TYPE_IS_GLOBAL_SPARE (1 << 2)
-#define MFI_PD_DDF_TYPE_IS_SPARE (1 << 3)
-#define MFI_PD_DDF_TYPE_IS_FOREIGN (1 << 4)
-#define MFI_PD_DDF_TYPE_INTF_SPI (1 << 12)
-#define MFI_PD_DDF_TYPE_INTF_SAS (1 << 13)
-#define MFI_PD_DDF_TYPE_INTF_SATA1 (1 << 14)
-#define MFI_PD_DDF_TYPE_INTF_SATA3G (1 << 15)
- uint16_t reserved;
- } ddf;
- struct {
- uint32_t reserved;
- } non_disk;
- uint32_t type;
-} QEMU_PACKED;
-
-struct mfi_pd_progress {
- uint32_t active;
-#define PD_PROGRESS_ACTIVE_REBUILD (1 << 0)
-#define PD_PROGRESS_ACTIVE_PATROL (1 << 1)
-#define PD_PROGRESS_ACTIVE_CLEAR (1 << 2)
- struct mfi_progress rbld;
- struct mfi_progress patrol;
- struct mfi_progress clear;
- struct mfi_progress reserved[4];
-} QEMU_PACKED;
-
-struct mfi_pd_info {
- union mfi_pd_ref ref;
- uint8_t inquiry_data[96];
- uint8_t vpd_page83[64];
- uint8_t not_supported;
- uint8_t scsi_dev_type;
- uint8_t connected_port_bitmap;
- uint8_t device_speed;
- uint32_t media_err_count;
- uint32_t other_err_count;
- uint32_t pred_fail_count;
- uint32_t last_pred_fail_event_seq_num;
- uint16_t fw_state;
- uint8_t disable_for_removal;
- uint8_t link_speed;
- union mfi_pd_ddf_type state;
- struct {
- uint8_t count;
- uint8_t is_path_broken;
- uint8_t reserved[6];
- uint64_t sas_addr[4];
- } path_info;
- uint64_t raw_size;
- uint64_t non_coerced_size;
- uint64_t coerced_size;
- uint16_t encl_device_id;
- uint8_t encl_index;
- uint8_t slot_number;
- struct mfi_pd_progress prog_info;
- uint8_t bad_block_table_full;
- uint8_t unusable_in_current_config;
- uint8_t vpd_page83_ext[64];
- uint8_t reserved[512-358];
-} QEMU_PACKED;
-
-struct mfi_pd_address {
- uint16_t device_id;
- uint16_t encl_device_id;
- uint8_t encl_index;
- uint8_t slot_number;
- uint8_t scsi_dev_type;
- uint8_t connect_port_bitmap;
- uint64_t sas_addr[2];
-} QEMU_PACKED;
-
-#define MFI_MAX_SYS_PDS 240
-struct mfi_pd_list {
- uint32_t size;
- uint32_t count;
- struct mfi_pd_address addr[MFI_MAX_SYS_PDS];
-} QEMU_PACKED;
-
-union mfi_ld_ref {
- struct {
- uint8_t target_id;
- uint8_t reserved;
- uint16_t seq;
- } v;
- uint32_t ref;
-} QEMU_PACKED;
-
-struct mfi_ld_list {
- uint32_t ld_count;
- uint32_t reserved1;
- struct {
- union mfi_ld_ref ld;
- uint8_t state;
- uint8_t reserved2[3];
- uint64_t size;
- } ld_list[MFI_MAX_LD];
-} QEMU_PACKED;
-
-struct mfi_ld_targetid_list {
- uint32_t size;
- uint32_t ld_count;
- uint8_t pad[3];
- uint8_t targetid[MFI_MAX_LD];
-} QEMU_PACKED;
-
-enum mfi_ld_access {
- MFI_LD_ACCESS_RW = 0,
- MFI_LD_ACCSSS_RO = 2,
- MFI_LD_ACCESS_BLOCKED = 3,
-};
-#define MFI_LD_ACCESS_MASK 3
-
-enum mfi_ld_state {
- MFI_LD_STATE_OFFLINE = 0,
- MFI_LD_STATE_PARTIALLY_DEGRADED = 1,
- MFI_LD_STATE_DEGRADED = 2,
- MFI_LD_STATE_OPTIMAL = 3
-};
-
-enum mfi_syspd_state {
- MFI_PD_STATE_UNCONFIGURED_GOOD = 0x00,
- MFI_PD_STATE_UNCONFIGURED_BAD = 0x01,
- MFI_PD_STATE_HOT_SPARE = 0x02,
- MFI_PD_STATE_OFFLINE = 0x10,
- MFI_PD_STATE_FAILED = 0x11,
- MFI_PD_STATE_REBUILD = 0x14,
- MFI_PD_STATE_ONLINE = 0x18,
- MFI_PD_STATE_COPYBACK = 0x20,
- MFI_PD_STATE_SYSTEM = 0x40
-};
-
-struct mfi_ld_props {
- union mfi_ld_ref ld;
- char name[16];
- uint8_t default_cache_policy;
- uint8_t access_policy;
- uint8_t disk_cache_policy;
- uint8_t current_cache_policy;
- uint8_t no_bgi;
- uint8_t reserved[7];
-} QEMU_PACKED;
-
-struct mfi_ld_params {
- uint8_t primary_raid_level;
- uint8_t raid_level_qualifier;
- uint8_t secondary_raid_level;
- uint8_t stripe_size;
- uint8_t num_drives;
- uint8_t span_depth;
- uint8_t state;
- uint8_t init_state;
- uint8_t is_consistent;
- uint8_t reserved[23];
-} QEMU_PACKED;
-
-struct mfi_ld_progress {
- uint32_t active;
-#define MFI_LD_PROGRESS_CC (1<<0)
-#define MFI_LD_PROGRESS_BGI (1<<1)
-#define MFI_LD_PROGRESS_FGI (1<<2)
-#define MFI_LD_PORGRESS_RECON (1<<3)
- struct mfi_progress cc;
- struct mfi_progress bgi;
- struct mfi_progress fgi;
- struct mfi_progress recon;
- struct mfi_progress reserved[4];
-} QEMU_PACKED;
-
-struct mfi_span {
- uint64_t start_block;
- uint64_t num_blocks;
- uint16_t array_ref;
- uint8_t reserved[6];
-} QEMU_PACKED;
-
-#define MFI_MAX_SPAN_DEPTH 8
-struct mfi_ld_config {
- struct mfi_ld_props properties;
- struct mfi_ld_params params;
- struct mfi_span span[MFI_MAX_SPAN_DEPTH];
-} QEMU_PACKED;
-
-struct mfi_ld_info {
- struct mfi_ld_config ld_config;
- uint64_t size;
- struct mfi_ld_progress progress;
- uint16_t cluster_owner;
- uint8_t reconstruct_active;
- uint8_t reserved1[1];
- uint8_t vpd_page83[64];
- uint8_t reserved2[16];
-} QEMU_PACKED;
-
-union mfi_spare_type {
- uint8_t flags;
-#define MFI_SPARE_IS_DEDICATED (1 << 0)
-#define MFI_SPARE_IS_REVERTABLE (1 << 1)
-#define MFI_SPARE_IS_ENCL_AFFINITY (1 << 2)
- uint8_t type;
-} QEMU_PACKED;
-
-#define MFI_MAX_ARRAYS 16
-struct mfi_spare {
- union mfi_pd_ref ref;
- union mfi_spare_type spare_type;
- uint8_t reserved[2];
- uint8_t array_count;
- uint16_t array_refd[MFI_MAX_ARRAYS];
-} QEMU_PACKED;
-
-#define MFI_MAX_ROW_SIZE 32
-struct mfi_array {
- uint64_t size;
- uint8_t num_drives;
- uint8_t reserved;
- uint16_t array_ref;
- uint8_t pad[20];
- struct {
- union mfi_pd_ref ref;
- uint16_t fw_state; /* enum mfi_syspd_state */
- struct {
- uint8_t pd;
- uint8_t slot;
- } encl;
- } pd[MFI_MAX_ROW_SIZE];
-} QEMU_PACKED;
-
-struct mfi_config_data {
- uint32_t size;
- uint16_t array_count;
- uint16_t array_size;
- uint16_t log_drv_count;
- uint16_t log_drv_size;
- uint16_t spares_count;
- uint16_t spares_size;
- uint8_t reserved[16];
- /*
- struct mfi_array array[];
- struct mfi_ld_config ld[];
- struct mfi_spare spare[];
- */
-} QEMU_PACKED;
-
-#define MFI_SCSI_MAX_TARGETS 128
-#define MFI_SCSI_MAX_LUNS 8
-#define MFI_SCSI_INITIATOR_ID 255
-#define MFI_SCSI_MAX_CMDS 8
-#define MFI_SCSI_MAX_CDB_LEN 16
-
-#endif /* MFI_REG_H */
diff --git a/qemu/hw/scsi/mpi.h b/qemu/hw/scsi/mpi.h
deleted file mode 100644
index 0568e1950..000000000
--- a/qemu/hw/scsi/mpi.h
+++ /dev/null
@@ -1,1153 +0,0 @@
-/*-
- * Based on FreeBSD sys/dev/mpt/mpilib headers.
- *
- * Copyright (c) 2000-2010, LSI Logic Corporation and its contributors.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- * substantially similar to the "NO WARRANTY" disclaimer below
- * ("Disclaimer") and any redistribution must be conditioned upon including
- * a substantially similar Disclaimer requirement for further binary
- * redistribution.
- * 3. Neither the name of the LSI Logic Corporation nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF THE COPYRIGHT
- * OWNER OR CONTRIBUTOR IS ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#ifndef MPI_H
-#define MPI_H
-
-enum {
- MPI_FUNCTION_SCSI_IO_REQUEST = 0x00,
- MPI_FUNCTION_SCSI_TASK_MGMT = 0x01,
- MPI_FUNCTION_IOC_INIT = 0x02,
- MPI_FUNCTION_IOC_FACTS = 0x03,
- MPI_FUNCTION_CONFIG = 0x04,
- MPI_FUNCTION_PORT_FACTS = 0x05,
- MPI_FUNCTION_PORT_ENABLE = 0x06,
- MPI_FUNCTION_EVENT_NOTIFICATION = 0x07,
- MPI_FUNCTION_EVENT_ACK = 0x08,
- MPI_FUNCTION_FW_DOWNLOAD = 0x09,
- MPI_FUNCTION_TARGET_CMD_BUFFER_POST = 0x0A,
- MPI_FUNCTION_TARGET_ASSIST = 0x0B,
- MPI_FUNCTION_TARGET_STATUS_SEND = 0x0C,
- MPI_FUNCTION_TARGET_MODE_ABORT = 0x0D,
- MPI_FUNCTION_FC_LINK_SRVC_BUF_POST = 0x0E,
- MPI_FUNCTION_FC_LINK_SRVC_RSP = 0x0F,
- MPI_FUNCTION_FC_EX_LINK_SRVC_SEND = 0x10,
- MPI_FUNCTION_FC_ABORT = 0x11,
- MPI_FUNCTION_FW_UPLOAD = 0x12,
- MPI_FUNCTION_FC_COMMON_TRANSPORT_SEND = 0x13,
- MPI_FUNCTION_FC_PRIMITIVE_SEND = 0x14,
-
- MPI_FUNCTION_RAID_ACTION = 0x15,
- MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH = 0x16,
-
- MPI_FUNCTION_TOOLBOX = 0x17,
-
- MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR = 0x18,
-
- MPI_FUNCTION_MAILBOX = 0x19,
-
- MPI_FUNCTION_SMP_PASSTHROUGH = 0x1A,
- MPI_FUNCTION_SAS_IO_UNIT_CONTROL = 0x1B,
- MPI_FUNCTION_SATA_PASSTHROUGH = 0x1C,
-
- MPI_FUNCTION_DIAG_BUFFER_POST = 0x1D,
- MPI_FUNCTION_DIAG_RELEASE = 0x1E,
-
- MPI_FUNCTION_SCSI_IO_32 = 0x1F,
-
- MPI_FUNCTION_LAN_SEND = 0x20,
- MPI_FUNCTION_LAN_RECEIVE = 0x21,
- MPI_FUNCTION_LAN_RESET = 0x22,
-
- MPI_FUNCTION_TARGET_ASSIST_EXTENDED = 0x23,
- MPI_FUNCTION_TARGET_CMD_BUF_BASE_POST = 0x24,
- MPI_FUNCTION_TARGET_CMD_BUF_LIST_POST = 0x25,
-
- MPI_FUNCTION_INBAND_BUFFER_POST = 0x28,
- MPI_FUNCTION_INBAND_SEND = 0x29,
- MPI_FUNCTION_INBAND_RSP = 0x2A,
- MPI_FUNCTION_INBAND_ABORT = 0x2B,
-
- MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET = 0x40,
- MPI_FUNCTION_IO_UNIT_RESET = 0x41,
- MPI_FUNCTION_HANDSHAKE = 0x42,
- MPI_FUNCTION_REPLY_FRAME_REMOVAL = 0x43,
- MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL = 0x44,
-};
-
-/****************************************************************************/
-/* Registers */
-/****************************************************************************/
-
-enum {
- MPI_IOC_STATE_RESET = 0x00000000,
- MPI_IOC_STATE_READY = 0x10000000,
- MPI_IOC_STATE_OPERATIONAL = 0x20000000,
- MPI_IOC_STATE_FAULT = 0x40000000,
-
- MPI_DOORBELL_OFFSET = 0x00000000,
- MPI_DOORBELL_ACTIVE = 0x08000000, /* DoorbellUsed */
- MPI_DOORBELL_WHO_INIT_MASK = 0x07000000,
- MPI_DOORBELL_WHO_INIT_SHIFT = 24,
- MPI_DOORBELL_FUNCTION_MASK = 0xFF000000,
- MPI_DOORBELL_FUNCTION_SHIFT = 24,
- MPI_DOORBELL_ADD_DWORDS_MASK = 0x00FF0000,
- MPI_DOORBELL_ADD_DWORDS_SHIFT = 16,
- MPI_DOORBELL_DATA_MASK = 0x0000FFFF,
- MPI_DOORBELL_FUNCTION_SPECIFIC_MASK = 0x0000FFFF,
-
- MPI_DB_HPBAC_VALUE_MASK = 0x0000F000,
- MPI_DB_HPBAC_ENABLE_ACCESS = 0x01,
- MPI_DB_HPBAC_DISABLE_ACCESS = 0x02,
- MPI_DB_HPBAC_FREE_BUFFER = 0x03,
-
- MPI_WRITE_SEQUENCE_OFFSET = 0x00000004,
- MPI_WRSEQ_KEY_VALUE_MASK = 0x0000000F,
- MPI_WRSEQ_1ST_KEY_VALUE = 0x04,
- MPI_WRSEQ_2ND_KEY_VALUE = 0x0B,
- MPI_WRSEQ_3RD_KEY_VALUE = 0x02,
- MPI_WRSEQ_4TH_KEY_VALUE = 0x07,
- MPI_WRSEQ_5TH_KEY_VALUE = 0x0D,
-
- MPI_DIAGNOSTIC_OFFSET = 0x00000008,
- MPI_DIAG_CLEAR_FLASH_BAD_SIG = 0x00000400,
- MPI_DIAG_PREVENT_IOC_BOOT = 0x00000200,
- MPI_DIAG_DRWE = 0x00000080,
- MPI_DIAG_FLASH_BAD_SIG = 0x00000040,
- MPI_DIAG_RESET_HISTORY = 0x00000020,
- MPI_DIAG_RW_ENABLE = 0x00000010,
- MPI_DIAG_RESET_ADAPTER = 0x00000004,
- MPI_DIAG_DISABLE_ARM = 0x00000002,
- MPI_DIAG_MEM_ENABLE = 0x00000001,
-
- MPI_TEST_BASE_ADDRESS_OFFSET = 0x0000000C,
-
- MPI_DIAG_RW_DATA_OFFSET = 0x00000010,
-
- MPI_DIAG_RW_ADDRESS_OFFSET = 0x00000014,
-
- MPI_HOST_INTERRUPT_STATUS_OFFSET = 0x00000030,
- MPI_HIS_IOP_DOORBELL_STATUS = 0x80000000,
- MPI_HIS_REPLY_MESSAGE_INTERRUPT = 0x00000008,
- MPI_HIS_DOORBELL_INTERRUPT = 0x00000001,
-
- MPI_HOST_INTERRUPT_MASK_OFFSET = 0x00000034,
- MPI_HIM_RIM = 0x00000008,
- MPI_HIM_DIM = 0x00000001,
-
- MPI_REQUEST_QUEUE_OFFSET = 0x00000040,
- MPI_REQUEST_POST_FIFO_OFFSET = 0x00000040,
-
- MPI_REPLY_QUEUE_OFFSET = 0x00000044,
- MPI_REPLY_POST_FIFO_OFFSET = 0x00000044,
- MPI_REPLY_FREE_FIFO_OFFSET = 0x00000044,
-
- MPI_HI_PRI_REQUEST_QUEUE_OFFSET = 0x00000048,
-};
-
-#define MPI_ADDRESS_REPLY_A_BIT 0x80000000
-
-/****************************************************************************/
-/* Scatter/gather elements */
-/****************************************************************************/
-
-typedef struct MPISGEntry {
- uint32_t FlagsLength;
- union
- {
- uint32_t Address32;
- uint64_t Address64;
- } u;
-} QEMU_PACKED MPISGEntry;
-
-/* Flags field bit definitions */
-
-enum {
- MPI_SGE_FLAGS_LAST_ELEMENT = 0x80000000,
- MPI_SGE_FLAGS_END_OF_BUFFER = 0x40000000,
- MPI_SGE_FLAGS_ELEMENT_TYPE_MASK = 0x30000000,
- MPI_SGE_FLAGS_LOCAL_ADDRESS = 0x08000000,
- MPI_SGE_FLAGS_DIRECTION = 0x04000000,
- MPI_SGE_FLAGS_64_BIT_ADDRESSING = 0x02000000,
- MPI_SGE_FLAGS_END_OF_LIST = 0x01000000,
-
- MPI_SGE_LENGTH_MASK = 0x00FFFFFF,
- MPI_SGE_CHAIN_LENGTH_MASK = 0x0000FFFF,
-
- MPI_SGE_FLAGS_TRANSACTION_ELEMENT = 0x00000000,
- MPI_SGE_FLAGS_SIMPLE_ELEMENT = 0x10000000,
- MPI_SGE_FLAGS_CHAIN_ELEMENT = 0x30000000,
-
- /* Direction */
-
- MPI_SGE_FLAGS_IOC_TO_HOST = 0x00000000,
- MPI_SGE_FLAGS_HOST_TO_IOC = 0x04000000,
-
- MPI_SGE_CHAIN_OFFSET_MASK = 0x00FF0000,
-};
-
-#define MPI_SGE_CHAIN_OFFSET_SHIFT 16
-
-/****************************************************************************/
-/* Standard message request header for all request messages */
-/****************************************************************************/
-
-typedef struct MPIRequestHeader {
- uint8_t Reserved[2]; /* function specific */
- uint8_t ChainOffset;
- uint8_t Function;
- uint8_t Reserved1[3]; /* function specific */
- uint8_t MsgFlags;
- uint32_t MsgContext;
-} QEMU_PACKED MPIRequestHeader;
-
-
-typedef struct MPIDefaultReply {
- uint8_t Reserved[2]; /* function specific */
- uint8_t MsgLength;
- uint8_t Function;
- uint8_t Reserved1[3]; /* function specific */
- uint8_t MsgFlags;
- uint32_t MsgContext;
- uint8_t Reserved2[2]; /* function specific */
- uint16_t IOCStatus;
- uint32_t IOCLogInfo;
-} QEMU_PACKED MPIDefaultReply;
-
-/* MsgFlags definition for all replies */
-
-#define MPI_MSGFLAGS_CONTINUATION_REPLY (0x80)
-
-enum {
-
- /************************************************************************/
- /* Common IOCStatus values for all replies */
- /************************************************************************/
-
- MPI_IOCSTATUS_SUCCESS = 0x0000,
- MPI_IOCSTATUS_INVALID_FUNCTION = 0x0001,
- MPI_IOCSTATUS_BUSY = 0x0002,
- MPI_IOCSTATUS_INVALID_SGL = 0x0003,
- MPI_IOCSTATUS_INTERNAL_ERROR = 0x0004,
- MPI_IOCSTATUS_RESERVED = 0x0005,
- MPI_IOCSTATUS_INSUFFICIENT_RESOURCES = 0x0006,
- MPI_IOCSTATUS_INVALID_FIELD = 0x0007,
- MPI_IOCSTATUS_INVALID_STATE = 0x0008,
- MPI_IOCSTATUS_OP_STATE_NOT_SUPPORTED = 0x0009,
-
- /************************************************************************/
- /* Config IOCStatus values */
- /************************************************************************/
-
- MPI_IOCSTATUS_CONFIG_INVALID_ACTION = 0x0020,
- MPI_IOCSTATUS_CONFIG_INVALID_TYPE = 0x0021,
- MPI_IOCSTATUS_CONFIG_INVALID_PAGE = 0x0022,
- MPI_IOCSTATUS_CONFIG_INVALID_DATA = 0x0023,
- MPI_IOCSTATUS_CONFIG_NO_DEFAULTS = 0x0024,
- MPI_IOCSTATUS_CONFIG_CANT_COMMIT = 0x0025,
-
- /************************************************************************/
- /* SCSIIO Reply = SPI & FCP, initiator values */
- /************************************************************************/
-
- MPI_IOCSTATUS_SCSI_RECOVERED_ERROR = 0x0040,
- MPI_IOCSTATUS_SCSI_INVALID_BUS = 0x0041,
- MPI_IOCSTATUS_SCSI_INVALID_TARGETID = 0x0042,
- MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE = 0x0043,
- MPI_IOCSTATUS_SCSI_DATA_OVERRUN = 0x0044,
- MPI_IOCSTATUS_SCSI_DATA_UNDERRUN = 0x0045,
- MPI_IOCSTATUS_SCSI_IO_DATA_ERROR = 0x0046,
- MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR = 0x0047,
- MPI_IOCSTATUS_SCSI_TASK_TERMINATED = 0x0048,
- MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH = 0x0049,
- MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED = 0x004A,
- MPI_IOCSTATUS_SCSI_IOC_TERMINATED = 0x004B,
- MPI_IOCSTATUS_SCSI_EXT_TERMINATED = 0x004C,
-
- /************************************************************************/
- /* For use by SCSI Initiator and SCSI Target end-to-end data protection*/
- /************************************************************************/
-
- MPI_IOCSTATUS_EEDP_GUARD_ERROR = 0x004D,
- MPI_IOCSTATUS_EEDP_REF_TAG_ERROR = 0x004E,
- MPI_IOCSTATUS_EEDP_APP_TAG_ERROR = 0x004F,
-
- /************************************************************************/
- /* SCSI Target values */
- /************************************************************************/
-
- MPI_IOCSTATUS_TARGET_PRIORITY_IO = 0x0060,
- MPI_IOCSTATUS_TARGET_INVALID_PORT = 0x0061,
- MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX = 0x0062,
- MPI_IOCSTATUS_TARGET_ABORTED = 0x0063,
- MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE = 0x0064,
- MPI_IOCSTATUS_TARGET_NO_CONNECTION = 0x0065,
- MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH = 0x006A,
- MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT = 0x006B,
- MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR = 0x006D,
- MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA = 0x006E,
- MPI_IOCSTATUS_TARGET_IU_TOO_SHORT = 0x006F,
- MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT = 0x0070,
- MPI_IOCSTATUS_TARGET_NAK_RECEIVED = 0x0071,
-
- /************************************************************************/
- /* Fibre Channel Direct Access values */
- /************************************************************************/
-
- MPI_IOCSTATUS_FC_ABORTED = 0x0066,
- MPI_IOCSTATUS_FC_RX_ID_INVALID = 0x0067,
- MPI_IOCSTATUS_FC_DID_INVALID = 0x0068,
- MPI_IOCSTATUS_FC_NODE_LOGGED_OUT = 0x0069,
- MPI_IOCSTATUS_FC_EXCHANGE_CANCELED = 0x006C,
-
- /************************************************************************/
- /* LAN values */
- /************************************************************************/
-
- MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND = 0x0080,
- MPI_IOCSTATUS_LAN_DEVICE_FAILURE = 0x0081,
- MPI_IOCSTATUS_LAN_TRANSMIT_ERROR = 0x0082,
- MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED = 0x0083,
- MPI_IOCSTATUS_LAN_RECEIVE_ERROR = 0x0084,
- MPI_IOCSTATUS_LAN_RECEIVE_ABORTED = 0x0085,
- MPI_IOCSTATUS_LAN_PARTIAL_PACKET = 0x0086,
- MPI_IOCSTATUS_LAN_CANCELED = 0x0087,
-
- /************************************************************************/
- /* Serial Attached SCSI values */
- /************************************************************************/
-
- MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED = 0x0090,
- MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN = 0x0091,
-
- /************************************************************************/
- /* Inband values */
- /************************************************************************/
-
- MPI_IOCSTATUS_INBAND_ABORTED = 0x0098,
- MPI_IOCSTATUS_INBAND_NO_CONNECTION = 0x0099,
-
- /************************************************************************/
- /* Diagnostic Tools values */
- /************************************************************************/
-
- MPI_IOCSTATUS_DIAGNOSTIC_RELEASED = 0x00A0,
-
- /************************************************************************/
- /* IOCStatus flag to indicate that log info is available */
- /************************************************************************/
-
- MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE = 0x8000,
- MPI_IOCSTATUS_MASK = 0x7FFF,
-
- /************************************************************************/
- /* LogInfo Types */
- /************************************************************************/
-
- MPI_IOCLOGINFO_TYPE_MASK = 0xF0000000,
- MPI_IOCLOGINFO_TYPE_SHIFT = 28,
- MPI_IOCLOGINFO_TYPE_NONE = 0x0,
- MPI_IOCLOGINFO_TYPE_SCSI = 0x1,
- MPI_IOCLOGINFO_TYPE_FC = 0x2,
- MPI_IOCLOGINFO_TYPE_SAS = 0x3,
- MPI_IOCLOGINFO_TYPE_ISCSI = 0x4,
- MPI_IOCLOGINFO_LOG_DATA_MASK = 0x0FFFFFFF,
-};
-
-/****************************************************************************/
-/* SCSI IO messages and associated structures */
-/****************************************************************************/
-
-typedef struct MPIMsgSCSIIORequest {
- uint8_t TargetID; /* 00h */
- uint8_t Bus; /* 01h */
- uint8_t ChainOffset; /* 02h */
- uint8_t Function; /* 03h */
- uint8_t CDBLength; /* 04h */
- uint8_t SenseBufferLength; /* 05h */
- uint8_t Reserved; /* 06h */
- uint8_t MsgFlags; /* 07h */
- uint32_t MsgContext; /* 08h */
- uint8_t LUN[8]; /* 0Ch */
- uint32_t Control; /* 14h */
- uint8_t CDB[16]; /* 18h */
- uint32_t DataLength; /* 28h */
- uint32_t SenseBufferLowAddr; /* 2Ch */
-} QEMU_PACKED MPIMsgSCSIIORequest;
-
-/* SCSI IO MsgFlags bits */
-
-#define MPI_SCSIIO_MSGFLGS_SENSE_WIDTH (0x01)
-#define MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_32 (0x00)
-#define MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64 (0x01)
-
-#define MPI_SCSIIO_MSGFLGS_SENSE_LOCATION (0x02)
-#define MPI_SCSIIO_MSGFLGS_SENSE_LOC_HOST (0x00)
-#define MPI_SCSIIO_MSGFLGS_SENSE_LOC_IOC (0x02)
-
-#define MPI_SCSIIO_MSGFLGS_CMD_DETERMINES_DATA_DIR (0x04)
-
-/* SCSI IO LUN fields */
-
-#define MPI_SCSIIO_LUN_FIRST_LEVEL_ADDRESSING (0x0000FFFF)
-#define MPI_SCSIIO_LUN_SECOND_LEVEL_ADDRESSING (0xFFFF0000)
-#define MPI_SCSIIO_LUN_THIRD_LEVEL_ADDRESSING (0x0000FFFF)
-#define MPI_SCSIIO_LUN_FOURTH_LEVEL_ADDRESSING (0xFFFF0000)
-#define MPI_SCSIIO_LUN_LEVEL_1_WORD (0xFF00)
-#define MPI_SCSIIO_LUN_LEVEL_1_DWORD (0x0000FF00)
-
-/* SCSI IO Control bits */
-
-#define MPI_SCSIIO_CONTROL_DATADIRECTION_MASK (0x03000000)
-#define MPI_SCSIIO_CONTROL_NODATATRANSFER (0x00000000)
-#define MPI_SCSIIO_CONTROL_WRITE (0x01000000)
-#define MPI_SCSIIO_CONTROL_READ (0x02000000)
-
-#define MPI_SCSIIO_CONTROL_ADDCDBLEN_MASK (0x3C000000)
-#define MPI_SCSIIO_CONTROL_ADDCDBLEN_SHIFT (26)
-
-#define MPI_SCSIIO_CONTROL_TASKATTRIBUTE_MASK (0x00000700)
-#define MPI_SCSIIO_CONTROL_SIMPLEQ (0x00000000)
-#define MPI_SCSIIO_CONTROL_HEADOFQ (0x00000100)
-#define MPI_SCSIIO_CONTROL_ORDEREDQ (0x00000200)
-#define MPI_SCSIIO_CONTROL_ACAQ (0x00000400)
-#define MPI_SCSIIO_CONTROL_UNTAGGED (0x00000500)
-#define MPI_SCSIIO_CONTROL_NO_DISCONNECT (0x00000700)
-
-#define MPI_SCSIIO_CONTROL_TASKMANAGE_MASK (0x00FF0000)
-#define MPI_SCSIIO_CONTROL_OBSOLETE (0x00800000)
-#define MPI_SCSIIO_CONTROL_CLEAR_ACA_RSV (0x00400000)
-#define MPI_SCSIIO_CONTROL_TARGET_RESET (0x00200000)
-#define MPI_SCSIIO_CONTROL_LUN_RESET_RSV (0x00100000)
-#define MPI_SCSIIO_CONTROL_RESERVED (0x00080000)
-#define MPI_SCSIIO_CONTROL_CLR_TASK_SET_RSV (0x00040000)
-#define MPI_SCSIIO_CONTROL_ABORT_TASK_SET (0x00020000)
-#define MPI_SCSIIO_CONTROL_RESERVED2 (0x00010000)
-
-/* SCSI IO reply structure */
-typedef struct MPIMsgSCSIIOReply
-{
- uint8_t TargetID; /* 00h */
- uint8_t Bus; /* 01h */
- uint8_t MsgLength; /* 02h */
- uint8_t Function; /* 03h */
- uint8_t CDBLength; /* 04h */
- uint8_t SenseBufferLength; /* 05h */
- uint8_t Reserved; /* 06h */
- uint8_t MsgFlags; /* 07h */
- uint32_t MsgContext; /* 08h */
- uint8_t SCSIStatus; /* 0Ch */
- uint8_t SCSIState; /* 0Dh */
- uint16_t IOCStatus; /* 0Eh */
- uint32_t IOCLogInfo; /* 10h */
- uint32_t TransferCount; /* 14h */
- uint32_t SenseCount; /* 18h */
- uint32_t ResponseInfo; /* 1Ch */
- uint16_t TaskTag; /* 20h */
- uint16_t Reserved1; /* 22h */
-} QEMU_PACKED MPIMsgSCSIIOReply;
-
-/* SCSI IO Reply SCSIStatus values (SAM-2 status codes) */
-
-#define MPI_SCSI_STATUS_SUCCESS (0x00)
-#define MPI_SCSI_STATUS_CHECK_CONDITION (0x02)
-#define MPI_SCSI_STATUS_CONDITION_MET (0x04)
-#define MPI_SCSI_STATUS_BUSY (0x08)
-#define MPI_SCSI_STATUS_INTERMEDIATE (0x10)
-#define MPI_SCSI_STATUS_INTERMEDIATE_CONDMET (0x14)
-#define MPI_SCSI_STATUS_RESERVATION_CONFLICT (0x18)
-#define MPI_SCSI_STATUS_COMMAND_TERMINATED (0x22)
-#define MPI_SCSI_STATUS_TASK_SET_FULL (0x28)
-#define MPI_SCSI_STATUS_ACA_ACTIVE (0x30)
-
-#define MPI_SCSI_STATUS_FCPEXT_DEVICE_LOGGED_OUT (0x80)
-#define MPI_SCSI_STATUS_FCPEXT_NO_LINK (0x81)
-#define MPI_SCSI_STATUS_FCPEXT_UNASSIGNED (0x82)
-
-
-/* SCSI IO Reply SCSIState values */
-
-#define MPI_SCSI_STATE_AUTOSENSE_VALID (0x01)
-#define MPI_SCSI_STATE_AUTOSENSE_FAILED (0x02)
-#define MPI_SCSI_STATE_NO_SCSI_STATUS (0x04)
-#define MPI_SCSI_STATE_TERMINATED (0x08)
-#define MPI_SCSI_STATE_RESPONSE_INFO_VALID (0x10)
-#define MPI_SCSI_STATE_QUEUE_TAG_REJECTED (0x20)
-
-/* SCSI IO Reply ResponseInfo values */
-/* (FCP-1 RSP_CODE values and SPI-3 Packetized Failure codes) */
-
-#define MPI_SCSI_RSP_INFO_FUNCTION_COMPLETE (0x00000000)
-#define MPI_SCSI_RSP_INFO_FCP_BURST_LEN_ERROR (0x01000000)
-#define MPI_SCSI_RSP_INFO_CMND_FIELDS_INVALID (0x02000000)
-#define MPI_SCSI_RSP_INFO_FCP_DATA_RO_ERROR (0x03000000)
-#define MPI_SCSI_RSP_INFO_TASK_MGMT_UNSUPPORTED (0x04000000)
-#define MPI_SCSI_RSP_INFO_TASK_MGMT_FAILED (0x05000000)
-#define MPI_SCSI_RSP_INFO_SPI_LQ_INVALID_TYPE (0x06000000)
-
-#define MPI_SCSI_TASKTAG_UNKNOWN (0xFFFF)
-
-
-/****************************************************************************/
-/* SCSI Task Management messages */
-/****************************************************************************/
-
-typedef struct MPIMsgSCSITaskMgmt {
- uint8_t TargetID; /* 00h */
- uint8_t Bus; /* 01h */
- uint8_t ChainOffset; /* 02h */
- uint8_t Function; /* 03h */
- uint8_t Reserved; /* 04h */
- uint8_t TaskType; /* 05h */
- uint8_t Reserved1; /* 06h */
- uint8_t MsgFlags; /* 07h */
- uint32_t MsgContext; /* 08h */
- uint8_t LUN[8]; /* 0Ch */
- uint32_t Reserved2[7]; /* 14h */
- uint32_t TaskMsgContext; /* 30h */
-} QEMU_PACKED MPIMsgSCSITaskMgmt;
-
-enum {
- /* TaskType values */
-
- MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK = 0x01,
- MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET = 0x02,
- MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET = 0x03,
- MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS = 0x04,
- MPI_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET = 0x05,
- MPI_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET = 0x06,
- MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK = 0x07,
- MPI_SCSITASKMGMT_TASKTYPE_CLR_ACA = 0x08,
-
- /* MsgFlags bits */
-
- MPI_SCSITASKMGMT_MSGFLAGS_DO_NOT_SEND_TASK_IU = 0x01,
-
- MPI_SCSITASKMGMT_MSGFLAGS_TARGET_RESET_OPTION = 0x00,
- MPI_SCSITASKMGMT_MSGFLAGS_LIP_RESET_OPTION = 0x02,
- MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION = 0x04,
-
- MPI_SCSITASKMGMT_MSGFLAGS_SOFT_RESET_OPTION = 0x08,
-};
-
-/* SCSI Task Management Reply */
-typedef struct MPIMsgSCSITaskMgmtReply {
- uint8_t TargetID; /* 00h */
- uint8_t Bus; /* 01h */
- uint8_t MsgLength; /* 02h */
- uint8_t Function; /* 03h */
- uint8_t ResponseCode; /* 04h */
- uint8_t TaskType; /* 05h */
- uint8_t Reserved1; /* 06h */
- uint8_t MsgFlags; /* 07h */
- uint32_t MsgContext; /* 08h */
- uint8_t Reserved2[2]; /* 0Ch */
- uint16_t IOCStatus; /* 0Eh */
- uint32_t IOCLogInfo; /* 10h */
- uint32_t TerminationCount; /* 14h */
-} QEMU_PACKED MPIMsgSCSITaskMgmtReply;
-
-/* ResponseCode values */
-enum {
- MPI_SCSITASKMGMT_RSP_TM_COMPLETE = 0x00,
- MPI_SCSITASKMGMT_RSP_INVALID_FRAME = 0x02,
- MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED = 0x04,
- MPI_SCSITASKMGMT_RSP_TM_FAILED = 0x05,
- MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED = 0x08,
- MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN = 0x09,
- MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC = 0x80,
-};
-
-/****************************************************************************/
-/* IOCInit message */
-/****************************************************************************/
-
-typedef struct MPIMsgIOCInit {
- uint8_t WhoInit; /* 00h */
- uint8_t Reserved; /* 01h */
- uint8_t ChainOffset; /* 02h */
- uint8_t Function; /* 03h */
- uint8_t Flags; /* 04h */
- uint8_t MaxDevices; /* 05h */
- uint8_t MaxBuses; /* 06h */
- uint8_t MsgFlags; /* 07h */
- uint32_t MsgContext; /* 08h */
- uint16_t ReplyFrameSize; /* 0Ch */
- uint8_t Reserved1[2]; /* 0Eh */
- uint32_t HostMfaHighAddr; /* 10h */
- uint32_t SenseBufferHighAddr; /* 14h */
- uint32_t ReplyFifoHostSignalingAddr; /* 18h */
- MPISGEntry HostPageBufferSGE; /* 1Ch */
- uint16_t MsgVersion; /* 28h */
- uint16_t HeaderVersion; /* 2Ah */
-} QEMU_PACKED MPIMsgIOCInit;
-
-enum {
- /* WhoInit values */
-
- MPI_WHOINIT_NO_ONE = 0x00,
- MPI_WHOINIT_SYSTEM_BIOS = 0x01,
- MPI_WHOINIT_ROM_BIOS = 0x02,
- MPI_WHOINIT_PCI_PEER = 0x03,
- MPI_WHOINIT_HOST_DRIVER = 0x04,
- MPI_WHOINIT_MANUFACTURER = 0x05,
-
- /* Flags values */
-
- MPI_IOCINIT_FLAGS_HOST_PAGE_BUFFER_PERSISTENT = 0x04,
- MPI_IOCINIT_FLAGS_REPLY_FIFO_HOST_SIGNAL = 0x02,
- MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE = 0x01,
-
- /* MsgVersion */
-
- MPI_IOCINIT_MSGVERSION_MAJOR_MASK = 0xFF00,
- MPI_IOCINIT_MSGVERSION_MAJOR_SHIFT = 8,
- MPI_IOCINIT_MSGVERSION_MINOR_MASK = 0x00FF,
- MPI_IOCINIT_MSGVERSION_MINOR_SHIFT = 0,
-
- /* HeaderVersion */
-
- MPI_IOCINIT_HEADERVERSION_UNIT_MASK = 0xFF00,
- MPI_IOCINIT_HEADERVERSION_UNIT_SHIFT = 8,
- MPI_IOCINIT_HEADERVERSION_DEV_MASK = 0x00FF,
- MPI_IOCINIT_HEADERVERSION_DEV_SHIFT = 0,
-};
-
-typedef struct MPIMsgIOCInitReply {
- uint8_t WhoInit; /* 00h */
- uint8_t Reserved; /* 01h */
- uint8_t MsgLength; /* 02h */
- uint8_t Function; /* 03h */
- uint8_t Flags; /* 04h */
- uint8_t MaxDevices; /* 05h */
- uint8_t MaxBuses; /* 06h */
- uint8_t MsgFlags; /* 07h */
- uint32_t MsgContext; /* 08h */
- uint16_t Reserved2; /* 0Ch */
- uint16_t IOCStatus; /* 0Eh */
- uint32_t IOCLogInfo; /* 10h */
-} QEMU_PACKED MPIMsgIOCInitReply;
-
-
-
-/****************************************************************************/
-/* IOC Facts message */
-/****************************************************************************/
-
-typedef struct MPIMsgIOCFacts {
- uint8_t Reserved[2]; /* 00h */
- uint8_t ChainOffset; /* 01h */
- uint8_t Function; /* 02h */
- uint8_t Reserved1[3]; /* 03h */
- uint8_t MsgFlags; /* 04h */
- uint32_t MsgContext; /* 08h */
-} QEMU_PACKED MPIMsgIOCFacts;
-
-/* IOC Facts Reply */
-typedef struct MPIMsgIOCFactsReply {
- uint16_t MsgVersion; /* 00h */
- uint8_t MsgLength; /* 02h */
- uint8_t Function; /* 03h */
- uint16_t HeaderVersion; /* 04h */
- uint8_t IOCNumber; /* 06h */
- uint8_t MsgFlags; /* 07h */
- uint32_t MsgContext; /* 08h */
- uint16_t IOCExceptions; /* 0Ch */
- uint16_t IOCStatus; /* 0Eh */
- uint32_t IOCLogInfo; /* 10h */
- uint8_t MaxChainDepth; /* 14h */
- uint8_t WhoInit; /* 15h */
- uint8_t BlockSize; /* 16h */
- uint8_t Flags; /* 17h */
- uint16_t ReplyQueueDepth; /* 18h */
- uint16_t RequestFrameSize; /* 1Ah */
- uint16_t Reserved_0101_FWVersion; /* 1Ch */ /* obsolete 16-bit FWVersion */
- uint16_t ProductID; /* 1Eh */
- uint32_t CurrentHostMfaHighAddr; /* 20h */
- uint16_t GlobalCredits; /* 24h */
- uint8_t NumberOfPorts; /* 26h */
- uint8_t EventState; /* 27h */
- uint32_t CurrentSenseBufferHighAddr; /* 28h */
- uint16_t CurReplyFrameSize; /* 2Ch */
- uint8_t MaxDevices; /* 2Eh */
- uint8_t MaxBuses; /* 2Fh */
- uint32_t FWImageSize; /* 30h */
- uint32_t IOCCapabilities; /* 34h */
- uint8_t FWVersionDev; /* 38h */
- uint8_t FWVersionUnit; /* 39h */
- uint8_t FWVersionMinor; /* 3ah */
- uint8_t FWVersionMajor; /* 3bh */
- uint16_t HighPriorityQueueDepth; /* 3Ch */
- uint16_t Reserved2; /* 3Eh */
- MPISGEntry HostPageBufferSGE; /* 40h */
- uint32_t ReplyFifoHostSignalingAddr; /* 4Ch */
-} QEMU_PACKED MPIMsgIOCFactsReply;
-
-enum {
- MPI_IOCFACTS_MSGVERSION_MAJOR_MASK = 0xFF00,
- MPI_IOCFACTS_MSGVERSION_MAJOR_SHIFT = 8,
- MPI_IOCFACTS_MSGVERSION_MINOR_MASK = 0x00FF,
- MPI_IOCFACTS_MSGVERSION_MINOR_SHIFT = 0,
-
- MPI_IOCFACTS_HDRVERSION_UNIT_MASK = 0xFF00,
- MPI_IOCFACTS_HDRVERSION_UNIT_SHIFT = 8,
- MPI_IOCFACTS_HDRVERSION_DEV_MASK = 0x00FF,
- MPI_IOCFACTS_HDRVERSION_DEV_SHIFT = 0,
-
- MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL = 0x0001,
- MPI_IOCFACTS_EXCEPT_RAID_CONFIG_INVALID = 0x0002,
- MPI_IOCFACTS_EXCEPT_FW_CHECKSUM_FAIL = 0x0004,
- MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL = 0x0008,
- MPI_IOCFACTS_EXCEPT_METADATA_UNSUPPORTED = 0x0010,
-
- MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT = 0x01,
- MPI_IOCFACTS_FLAGS_REPLY_FIFO_HOST_SIGNAL = 0x02,
- MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT = 0x04,
-
- MPI_IOCFACTS_EVENTSTATE_DISABLED = 0x00,
- MPI_IOCFACTS_EVENTSTATE_ENABLED = 0x01,
-
- MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q = 0x00000001,
- MPI_IOCFACTS_CAPABILITY_REPLY_HOST_SIGNAL = 0x00000002,
- MPI_IOCFACTS_CAPABILITY_QUEUE_FULL_HANDLING = 0x00000004,
- MPI_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER = 0x00000008,
- MPI_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER = 0x00000010,
- MPI_IOCFACTS_CAPABILITY_EXTENDED_BUFFER = 0x00000020,
- MPI_IOCFACTS_CAPABILITY_EEDP = 0x00000040,
- MPI_IOCFACTS_CAPABILITY_BIDIRECTIONAL = 0x00000080,
- MPI_IOCFACTS_CAPABILITY_MULTICAST = 0x00000100,
- MPI_IOCFACTS_CAPABILITY_SCSIIO32 = 0x00000200,
- MPI_IOCFACTS_CAPABILITY_NO_SCSIIO16 = 0x00000400,
- MPI_IOCFACTS_CAPABILITY_TLR = 0x00000800,
-};
-
-/****************************************************************************/
-/* Port Facts message and Reply */
-/****************************************************************************/
-
-typedef struct MPIMsgPortFacts {
- uint8_t Reserved[2]; /* 00h */
- uint8_t ChainOffset; /* 02h */
- uint8_t Function; /* 03h */
- uint8_t Reserved1[2]; /* 04h */
- uint8_t PortNumber; /* 06h */
- uint8_t MsgFlags; /* 07h */
- uint32_t MsgContext; /* 08h */
-} QEMU_PACKED MPIMsgPortFacts;
-
-typedef struct MPIMsgPortFactsReply {
- uint16_t Reserved; /* 00h */
- uint8_t MsgLength; /* 02h */
- uint8_t Function; /* 03h */
- uint16_t Reserved1; /* 04h */
- uint8_t PortNumber; /* 06h */
- uint8_t MsgFlags; /* 07h */
- uint32_t MsgContext; /* 08h */
- uint16_t Reserved2; /* 0Ch */
- uint16_t IOCStatus; /* 0Eh */
- uint32_t IOCLogInfo; /* 10h */
- uint8_t Reserved3; /* 14h */
- uint8_t PortType; /* 15h */
- uint16_t MaxDevices; /* 16h */
- uint16_t PortSCSIID; /* 18h */
- uint16_t ProtocolFlags; /* 1Ah */
- uint16_t MaxPostedCmdBuffers; /* 1Ch */
- uint16_t MaxPersistentIDs; /* 1Eh */
- uint16_t MaxLanBuckets; /* 20h */
- uint8_t MaxInitiators; /* 22h */
- uint8_t Reserved4; /* 23h */
- uint32_t Reserved5; /* 24h */
-} QEMU_PACKED MPIMsgPortFactsReply;
-
-
-enum {
- /* PortTypes values */
- MPI_PORTFACTS_PORTTYPE_INACTIVE = 0x00,
- MPI_PORTFACTS_PORTTYPE_SCSI = 0x01,
- MPI_PORTFACTS_PORTTYPE_FC = 0x10,
- MPI_PORTFACTS_PORTTYPE_ISCSI = 0x20,
- MPI_PORTFACTS_PORTTYPE_SAS = 0x30,
-
- /* ProtocolFlags values */
- MPI_PORTFACTS_PROTOCOL_LOGBUSADDR = 0x01,
- MPI_PORTFACTS_PROTOCOL_LAN = 0x02,
- MPI_PORTFACTS_PROTOCOL_TARGET = 0x04,
- MPI_PORTFACTS_PROTOCOL_INITIATOR = 0x08,
-};
-
-
-/****************************************************************************/
-/* Port Enable Message */
-/****************************************************************************/
-
-typedef struct MPIMsgPortEnable {
- uint8_t Reserved[2]; /* 00h */
- uint8_t ChainOffset; /* 02h */
- uint8_t Function; /* 03h */
- uint8_t Reserved1[2]; /* 04h */
- uint8_t PortNumber; /* 06h */
- uint8_t MsgFlags; /* 07h */
- uint32_t MsgContext; /* 08h */
-} QEMU_PACKED MPIMsgPortEnable;
-
-typedef struct MPIMsgPortEnableReply {
- uint8_t Reserved[2]; /* 00h */
- uint8_t MsgLength; /* 02h */
- uint8_t Function; /* 03h */
- uint8_t Reserved1[2]; /* 04h */
- uint8_t PortNumber; /* 05h */
- uint8_t MsgFlags; /* 07h */
- uint32_t MsgContext; /* 08h */
- uint16_t Reserved2; /* 0Ch */
- uint16_t IOCStatus; /* 0Eh */
- uint32_t IOCLogInfo; /* 10h */
-} QEMU_PACKED MPIMsgPortEnableReply;
-
-/****************************************************************************/
-/* Event Notification messages */
-/****************************************************************************/
-
-typedef struct MPIMsgEventNotify {
- uint8_t Switch; /* 00h */
- uint8_t Reserved; /* 01h */
- uint8_t ChainOffset; /* 02h */
- uint8_t Function; /* 03h */
- uint8_t Reserved1[3]; /* 04h */
- uint8_t MsgFlags; /* 07h */
- uint32_t MsgContext; /* 08h */
-} QEMU_PACKED MPIMsgEventNotify;
-
-/* Event Notification Reply */
-
-typedef struct MPIMsgEventNotifyReply {
- uint16_t EventDataLength; /* 00h */
- uint8_t MsgLength; /* 02h */
- uint8_t Function; /* 03h */
- uint8_t Reserved1[2]; /* 04h */
- uint8_t AckRequired; /* 06h */
- uint8_t MsgFlags; /* 07h */
- uint32_t MsgContext; /* 08h */
- uint8_t Reserved2[2]; /* 0Ch */
- uint16_t IOCStatus; /* 0Eh */
- uint32_t IOCLogInfo; /* 10h */
- uint32_t Event; /* 14h */
- uint32_t EventContext; /* 18h */
- uint32_t Data[1]; /* 1Ch */
-} QEMU_PACKED MPIMsgEventNotifyReply;
-
-/* Event Acknowledge */
-
-typedef struct MPIMsgEventAck {
- uint8_t Reserved[2]; /* 00h */
- uint8_t ChainOffset; /* 02h */
- uint8_t Function; /* 03h */
- uint8_t Reserved1[3]; /* 04h */
- uint8_t MsgFlags; /* 07h */
- uint32_t MsgContext; /* 08h */
- uint32_t Event; /* 0Ch */
- uint32_t EventContext; /* 10h */
-} QEMU_PACKED MPIMsgEventAck;
-
-typedef struct MPIMsgEventAckReply {
- uint8_t Reserved[2]; /* 00h */
- uint8_t MsgLength; /* 02h */
- uint8_t Function; /* 03h */
- uint8_t Reserved1[3]; /* 04h */
- uint8_t MsgFlags; /* 07h */
- uint32_t MsgContext; /* 08h */
- uint16_t Reserved2; /* 0Ch */
- uint16_t IOCStatus; /* 0Eh */
- uint32_t IOCLogInfo; /* 10h */
-} QEMU_PACKED MPIMsgEventAckReply;
-
-enum {
- /* Switch */
-
- MPI_EVENT_NOTIFICATION_SWITCH_OFF = 0x00,
- MPI_EVENT_NOTIFICATION_SWITCH_ON = 0x01,
-
- /* Event */
-
- MPI_EVENT_NONE = 0x00000000,
- MPI_EVENT_LOG_DATA = 0x00000001,
- MPI_EVENT_STATE_CHANGE = 0x00000002,
- MPI_EVENT_UNIT_ATTENTION = 0x00000003,
- MPI_EVENT_IOC_BUS_RESET = 0x00000004,
- MPI_EVENT_EXT_BUS_RESET = 0x00000005,
- MPI_EVENT_RESCAN = 0x00000006,
- MPI_EVENT_LINK_STATUS_CHANGE = 0x00000007,
- MPI_EVENT_LOOP_STATE_CHANGE = 0x00000008,
- MPI_EVENT_LOGOUT = 0x00000009,
- MPI_EVENT_EVENT_CHANGE = 0x0000000A,
- MPI_EVENT_INTEGRATED_RAID = 0x0000000B,
- MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE = 0x0000000C,
- MPI_EVENT_ON_BUS_TIMER_EXPIRED = 0x0000000D,
- MPI_EVENT_QUEUE_FULL = 0x0000000E,
- MPI_EVENT_SAS_DEVICE_STATUS_CHANGE = 0x0000000F,
- MPI_EVENT_SAS_SES = 0x00000010,
- MPI_EVENT_PERSISTENT_TABLE_FULL = 0x00000011,
- MPI_EVENT_SAS_PHY_LINK_STATUS = 0x00000012,
- MPI_EVENT_SAS_DISCOVERY_ERROR = 0x00000013,
- MPI_EVENT_IR_RESYNC_UPDATE = 0x00000014,
- MPI_EVENT_IR2 = 0x00000015,
- MPI_EVENT_SAS_DISCOVERY = 0x00000016,
- MPI_EVENT_SAS_BROADCAST_PRIMITIVE = 0x00000017,
- MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE = 0x00000018,
- MPI_EVENT_SAS_INIT_TABLE_OVERFLOW = 0x00000019,
- MPI_EVENT_SAS_SMP_ERROR = 0x0000001A,
- MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE = 0x0000001B,
- MPI_EVENT_LOG_ENTRY_ADDED = 0x00000021,
-
- /* AckRequired field values */
-
- MPI_EVENT_NOTIFICATION_ACK_NOT_REQUIRED = 0x00,
- MPI_EVENT_NOTIFICATION_ACK_REQUIRED = 0x01,
-};
-
-/****************************************************************************
-* Config Request Message
-****************************************************************************/
-
-typedef struct MPIMsgConfig {
- uint8_t Action; /* 00h */
- uint8_t Reserved; /* 01h */
- uint8_t ChainOffset; /* 02h */
- uint8_t Function; /* 03h */
- uint16_t ExtPageLength; /* 04h */
- uint8_t ExtPageType; /* 06h */
- uint8_t MsgFlags; /* 07h */
- uint32_t MsgContext; /* 08h */
- uint8_t Reserved2[8]; /* 0Ch */
- uint8_t PageVersion; /* 14h */
- uint8_t PageLength; /* 15h */
- uint8_t PageNumber; /* 16h */
- uint8_t PageType; /* 17h */
- uint32_t PageAddress; /* 18h */
- MPISGEntry PageBufferSGE; /* 1Ch */
-} QEMU_PACKED MPIMsgConfig;
-
-/* Action field values */
-
-enum {
- MPI_CONFIG_ACTION_PAGE_HEADER = 0x00,
- MPI_CONFIG_ACTION_PAGE_READ_CURRENT = 0x01,
- MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT = 0x02,
- MPI_CONFIG_ACTION_PAGE_DEFAULT = 0x03,
- MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM = 0x04,
- MPI_CONFIG_ACTION_PAGE_READ_DEFAULT = 0x05,
- MPI_CONFIG_ACTION_PAGE_READ_NVRAM = 0x06,
-};
-
-
-/* Config Reply Message */
-typedef struct MPIMsgConfigReply {
- uint8_t Action; /* 00h */
- uint8_t Reserved; /* 01h */
- uint8_t MsgLength; /* 02h */
- uint8_t Function; /* 03h */
- uint16_t ExtPageLength; /* 04h */
- uint8_t ExtPageType; /* 06h */
- uint8_t MsgFlags; /* 07h */
- uint32_t MsgContext; /* 08h */
- uint8_t Reserved2[2]; /* 0Ch */
- uint16_t IOCStatus; /* 0Eh */
- uint32_t IOCLogInfo; /* 10h */
- uint8_t PageVersion; /* 14h */
- uint8_t PageLength; /* 15h */
- uint8_t PageNumber; /* 16h */
- uint8_t PageType; /* 17h */
-} QEMU_PACKED MPIMsgConfigReply;
-
-enum {
- /* PageAddress field values */
- MPI_CONFIG_PAGEATTR_READ_ONLY = 0x00,
- MPI_CONFIG_PAGEATTR_CHANGEABLE = 0x10,
- MPI_CONFIG_PAGEATTR_PERSISTENT = 0x20,
- MPI_CONFIG_PAGEATTR_RO_PERSISTENT = 0x30,
- MPI_CONFIG_PAGEATTR_MASK = 0xF0,
-
- MPI_CONFIG_PAGETYPE_IO_UNIT = 0x00,
- MPI_CONFIG_PAGETYPE_IOC = 0x01,
- MPI_CONFIG_PAGETYPE_BIOS = 0x02,
- MPI_CONFIG_PAGETYPE_SCSI_PORT = 0x03,
- MPI_CONFIG_PAGETYPE_SCSI_DEVICE = 0x04,
- MPI_CONFIG_PAGETYPE_FC_PORT = 0x05,
- MPI_CONFIG_PAGETYPE_FC_DEVICE = 0x06,
- MPI_CONFIG_PAGETYPE_LAN = 0x07,
- MPI_CONFIG_PAGETYPE_RAID_VOLUME = 0x08,
- MPI_CONFIG_PAGETYPE_MANUFACTURING = 0x09,
- MPI_CONFIG_PAGETYPE_RAID_PHYSDISK = 0x0A,
- MPI_CONFIG_PAGETYPE_INBAND = 0x0B,
- MPI_CONFIG_PAGETYPE_EXTENDED = 0x0F,
- MPI_CONFIG_PAGETYPE_MASK = 0x0F,
-
- MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT = 0x10,
- MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER = 0x11,
- MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE = 0x12,
- MPI_CONFIG_EXTPAGETYPE_SAS_PHY = 0x13,
- MPI_CONFIG_EXTPAGETYPE_LOG = 0x14,
- MPI_CONFIG_EXTPAGETYPE_ENCLOSURE = 0x15,
-
- MPI_SCSI_PORT_PGAD_PORT_MASK = 0x000000FF,
-
- MPI_SCSI_DEVICE_FORM_MASK = 0xF0000000,
- MPI_SCSI_DEVICE_FORM_BUS_TID = 0x00000000,
- MPI_SCSI_DEVICE_TARGET_ID_MASK = 0x000000FF,
- MPI_SCSI_DEVICE_TARGET_ID_SHIFT = 0,
- MPI_SCSI_DEVICE_BUS_MASK = 0x0000FF00,
- MPI_SCSI_DEVICE_BUS_SHIFT = 8,
- MPI_SCSI_DEVICE_FORM_TARGET_MODE = 0x10000000,
- MPI_SCSI_DEVICE_TM_RESPOND_ID_MASK = 0x000000FF,
- MPI_SCSI_DEVICE_TM_RESPOND_ID_SHIFT = 0,
- MPI_SCSI_DEVICE_TM_BUS_MASK = 0x0000FF00,
- MPI_SCSI_DEVICE_TM_BUS_SHIFT = 8,
- MPI_SCSI_DEVICE_TM_INIT_ID_MASK = 0x00FF0000,
- MPI_SCSI_DEVICE_TM_INIT_ID_SHIFT = 16,
-
- MPI_FC_PORT_PGAD_PORT_MASK = 0xF0000000,
- MPI_FC_PORT_PGAD_PORT_SHIFT = 28,
- MPI_FC_PORT_PGAD_FORM_MASK = 0x0F000000,
- MPI_FC_PORT_PGAD_FORM_INDEX = 0x01000000,
- MPI_FC_PORT_PGAD_INDEX_MASK = 0x0000FFFF,
- MPI_FC_PORT_PGAD_INDEX_SHIFT = 0,
-
- MPI_FC_DEVICE_PGAD_PORT_MASK = 0xF0000000,
- MPI_FC_DEVICE_PGAD_PORT_SHIFT = 28,
- MPI_FC_DEVICE_PGAD_FORM_MASK = 0x0F000000,
- MPI_FC_DEVICE_PGAD_FORM_NEXT_DID = 0x00000000,
- MPI_FC_DEVICE_PGAD_ND_PORT_MASK = 0xF0000000,
- MPI_FC_DEVICE_PGAD_ND_PORT_SHIFT = 28,
- MPI_FC_DEVICE_PGAD_ND_DID_MASK = 0x00FFFFFF,
- MPI_FC_DEVICE_PGAD_ND_DID_SHIFT = 0,
- MPI_FC_DEVICE_PGAD_FORM_BUS_TID = 0x01000000,
- MPI_FC_DEVICE_PGAD_BT_BUS_MASK = 0x0000FF00,
- MPI_FC_DEVICE_PGAD_BT_BUS_SHIFT = 8,
- MPI_FC_DEVICE_PGAD_BT_TID_MASK = 0x000000FF,
- MPI_FC_DEVICE_PGAD_BT_TID_SHIFT = 0,
-
- MPI_PHYSDISK_PGAD_PHYSDISKNUM_MASK = 0x000000FF,
- MPI_PHYSDISK_PGAD_PHYSDISKNUM_SHIFT = 0,
-
- MPI_SAS_EXPAND_PGAD_FORM_MASK = 0xF0000000,
- MPI_SAS_EXPAND_PGAD_FORM_SHIFT = 28,
- MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE = 0x00000000,
- MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM = 0x00000001,
- MPI_SAS_EXPAND_PGAD_FORM_HANDLE = 0x00000002,
- MPI_SAS_EXPAND_PGAD_GNH_MASK_HANDLE = 0x0000FFFF,
- MPI_SAS_EXPAND_PGAD_GNH_SHIFT_HANDLE = 0,
- MPI_SAS_EXPAND_PGAD_HPN_MASK_PHY = 0x00FF0000,
- MPI_SAS_EXPAND_PGAD_HPN_SHIFT_PHY = 16,
- MPI_SAS_EXPAND_PGAD_HPN_MASK_HANDLE = 0x0000FFFF,
- MPI_SAS_EXPAND_PGAD_HPN_SHIFT_HANDLE = 0,
- MPI_SAS_EXPAND_PGAD_H_MASK_HANDLE = 0x0000FFFF,
- MPI_SAS_EXPAND_PGAD_H_SHIFT_HANDLE = 0,
-
- MPI_SAS_DEVICE_PGAD_FORM_MASK = 0xF0000000,
- MPI_SAS_DEVICE_PGAD_FORM_SHIFT = 28,
- MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE = 0x00000000,
- MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID = 0x00000001,
- MPI_SAS_DEVICE_PGAD_FORM_HANDLE = 0x00000002,
- MPI_SAS_DEVICE_PGAD_GNH_HANDLE_MASK = 0x0000FFFF,
- MPI_SAS_DEVICE_PGAD_GNH_HANDLE_SHIFT = 0,
- MPI_SAS_DEVICE_PGAD_BT_BUS_MASK = 0x0000FF00,
- MPI_SAS_DEVICE_PGAD_BT_BUS_SHIFT = 8,
- MPI_SAS_DEVICE_PGAD_BT_TID_MASK = 0x000000FF,
- MPI_SAS_DEVICE_PGAD_BT_TID_SHIFT = 0,
- MPI_SAS_DEVICE_PGAD_H_HANDLE_MASK = 0x0000FFFF,
- MPI_SAS_DEVICE_PGAD_H_HANDLE_SHIFT = 0,
-
- MPI_SAS_PHY_PGAD_FORM_MASK = 0xF0000000,
- MPI_SAS_PHY_PGAD_FORM_SHIFT = 28,
- MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER = 0x0,
- MPI_SAS_PHY_PGAD_FORM_PHY_TBL_INDEX = 0x1,
- MPI_SAS_PHY_PGAD_PHY_NUMBER_MASK = 0x000000FF,
- MPI_SAS_PHY_PGAD_PHY_NUMBER_SHIFT = 0,
- MPI_SAS_PHY_PGAD_PHY_TBL_INDEX_MASK = 0x0000FFFF,
- MPI_SAS_PHY_PGAD_PHY_TBL_INDEX_SHIFT = 0,
-
- MPI_SAS_ENCLOS_PGAD_FORM_MASK = 0xF0000000,
- MPI_SAS_ENCLOS_PGAD_FORM_SHIFT = 28,
- MPI_SAS_ENCLOS_PGAD_FORM_GET_NEXT_HANDLE = 0x00000000,
- MPI_SAS_ENCLOS_PGAD_FORM_HANDLE = 0x00000001,
- MPI_SAS_ENCLOS_PGAD_GNH_HANDLE_MASK = 0x0000FFFF,
- MPI_SAS_ENCLOS_PGAD_GNH_HANDLE_SHIFT = 0,
- MPI_SAS_ENCLOS_PGAD_H_HANDLE_MASK = 0x0000FFFF,
- MPI_SAS_ENCLOS_PGAD_H_HANDLE_SHIFT = 0,
-};
-
-/* Too many structs and definitions... see mptconfig.c for the few
- * that are used.
- */
-
-/****************************************************************************/
-/* Firmware Upload message and associated structures */
-/****************************************************************************/
-
-enum {
- /* defines for using the ProductId field */
- MPI_FW_HEADER_PID_TYPE_MASK = 0xF000,
- MPI_FW_HEADER_PID_TYPE_SCSI = 0x0000,
- MPI_FW_HEADER_PID_TYPE_FC = 0x1000,
- MPI_FW_HEADER_PID_TYPE_SAS = 0x2000,
-
- MPI_FW_HEADER_PID_PROD_MASK = 0x0F00,
- MPI_FW_HEADER_PID_PROD_INITIATOR_SCSI = 0x0100,
- MPI_FW_HEADER_PID_PROD_TARGET_INITIATOR_SCSI = 0x0200,
- MPI_FW_HEADER_PID_PROD_TARGET_SCSI = 0x0300,
- MPI_FW_HEADER_PID_PROD_IM_SCSI = 0x0400,
- MPI_FW_HEADER_PID_PROD_IS_SCSI = 0x0500,
- MPI_FW_HEADER_PID_PROD_CTX_SCSI = 0x0600,
- MPI_FW_HEADER_PID_PROD_IR_SCSI = 0x0700,
-
- MPI_FW_HEADER_PID_FAMILY_MASK = 0x00FF,
-
- /* SCSI */
- MPI_FW_HEADER_PID_FAMILY_1030A0_SCSI = 0x0001,
- MPI_FW_HEADER_PID_FAMILY_1030B0_SCSI = 0x0002,
- MPI_FW_HEADER_PID_FAMILY_1030B1_SCSI = 0x0003,
- MPI_FW_HEADER_PID_FAMILY_1030C0_SCSI = 0x0004,
- MPI_FW_HEADER_PID_FAMILY_1020A0_SCSI = 0x0005,
- MPI_FW_HEADER_PID_FAMILY_1020B0_SCSI = 0x0006,
- MPI_FW_HEADER_PID_FAMILY_1020B1_SCSI = 0x0007,
- MPI_FW_HEADER_PID_FAMILY_1020C0_SCSI = 0x0008,
- MPI_FW_HEADER_PID_FAMILY_1035A0_SCSI = 0x0009,
- MPI_FW_HEADER_PID_FAMILY_1035B0_SCSI = 0x000A,
- MPI_FW_HEADER_PID_FAMILY_1030TA0_SCSI = 0x000B,
- MPI_FW_HEADER_PID_FAMILY_1020TA0_SCSI = 0x000C,
-
- /* Fibre Channel */
- MPI_FW_HEADER_PID_FAMILY_909_FC = 0x0000,
- MPI_FW_HEADER_PID_FAMILY_919_FC = 0x0001, /* 919 and 929 */
- MPI_FW_HEADER_PID_FAMILY_919X_FC = 0x0002, /* 919X and 929X */
- MPI_FW_HEADER_PID_FAMILY_919XL_FC = 0x0003, /* 919XL and 929XL */
- MPI_FW_HEADER_PID_FAMILY_939X_FC = 0x0004, /* 939X and 949X */
- MPI_FW_HEADER_PID_FAMILY_959_FC = 0x0005,
- MPI_FW_HEADER_PID_FAMILY_949E_FC = 0x0006,
-
- /* SAS */
- MPI_FW_HEADER_PID_FAMILY_1064_SAS = 0x0001,
- MPI_FW_HEADER_PID_FAMILY_1068_SAS = 0x0002,
- MPI_FW_HEADER_PID_FAMILY_1078_SAS = 0x0003,
- MPI_FW_HEADER_PID_FAMILY_106xE_SAS = 0x0004, /* 1068E, 1066E, and 1064E */
-};
-
-#endif
diff --git a/qemu/hw/scsi/mptconfig.c b/qemu/hw/scsi/mptconfig.c
deleted file mode 100644
index 707185469..000000000
--- a/qemu/hw/scsi/mptconfig.c
+++ /dev/null
@@ -1,905 +0,0 @@
-/*
- * QEMU LSI SAS1068 Host Bus Adapter emulation - configuration pages
- *
- * Copyright (c) 2016 Red Hat, Inc.
- *
- * Author: Paolo Bonzini
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/pci/pci.h"
-#include "hw/scsi/scsi.h"
-
-#include "mptsas.h"
-#include "mpi.h"
-#include "trace.h"
-
-/* Generic functions for marshaling and unmarshaling. */
-
-#define repl1(x) x
-#define repl2(x) x x
-#define repl3(x) x x x
-#define repl4(x) x x x x
-#define repl5(x) x x x x x
-#define repl6(x) x x x x x x
-#define repl7(x) x x x x x x x
-#define repl8(x) x x x x x x x x
-
-#define repl(n, x) glue(repl, n)(x)
-
-typedef union PackValue {
- uint64_t ll;
- char *str;
-} PackValue;
-
-static size_t vfill(uint8_t *data, size_t size, const char *fmt, va_list ap)
-{
- size_t ofs;
- PackValue val;
- const char *p;
-
- ofs = 0;
- p = fmt;
- while (*p) {
- memset(&val, 0, sizeof(val));
- switch (*p) {
- case '*':
- p++;
- break;
- case 'b':
- case 'w':
- case 'l':
- val.ll = va_arg(ap, int);
- break;
- case 'q':
- val.ll = va_arg(ap, int64_t);
- break;
- case 's':
- val.str = va_arg(ap, void *);
- break;
- }
- switch (*p++) {
- case 'b':
- if (data) {
- stb_p(data + ofs, val.ll);
- }
- ofs++;
- break;
- case 'w':
- if (data) {
- stw_le_p(data + ofs, val.ll);
- }
- ofs += 2;
- break;
- case 'l':
- if (data) {
- stl_le_p(data + ofs, val.ll);
- }
- ofs += 4;
- break;
- case 'q':
- if (data) {
- stq_le_p(data + ofs, val.ll);
- }
- ofs += 8;
- break;
- case 's':
- {
- int cnt = atoi(p);
- if (data) {
- if (val.str) {
- strncpy((void *)data + ofs, val.str, cnt);
- } else {
- memset((void *)data + ofs, 0, cnt);
- }
- }
- ofs += cnt;
- break;
- }
- }
- }
-
- return ofs;
-}
-
-static size_t vpack(uint8_t **p_data, const char *fmt, va_list ap1)
-{
- size_t size = 0;
- uint8_t *data = NULL;
-
- if (p_data) {
- va_list ap2;
-
- va_copy(ap2, ap1);
- size = vfill(NULL, 0, fmt, ap2);
- *p_data = data = g_malloc(size);
- va_end(ap2);
- }
- return vfill(data, size, fmt, ap1);
-}
-
-static size_t fill(uint8_t *data, size_t size, const char *fmt, ...)
-{
- va_list ap;
- size_t ret;
-
- va_start(ap, fmt);
- ret = vfill(data, size, fmt, ap);
- va_end(ap);
-
- return ret;
-}
-
-/* Functions to build the page header and fill in the length, always used
- * through the macros.
- */
-
-#define MPTSAS_CONFIG_PACK(number, type, version, fmt, ...) \
- mptsas_config_pack(data, "b*bbb" fmt, version, number, type, \
- ## __VA_ARGS__)
-
-static size_t mptsas_config_pack(uint8_t **data, const char *fmt, ...)
-{
- va_list ap;
- size_t ret;
-
- va_start(ap, fmt);
- ret = vpack(data, fmt, ap);
- va_end(ap);
-
- if (data) {
- assert(ret < 256 && (ret % 4) == 0);
- stb_p(*data + 1, ret / 4);
- }
- return ret;
-}
-
-#define MPTSAS_CONFIG_PACK_EXT(number, type, version, fmt, ...) \
- mptsas_config_pack_ext(data, "b*bbb*wb*b" fmt, version, number, \
- MPI_CONFIG_PAGETYPE_EXTENDED, type, ## __VA_ARGS__)
-
-static size_t mptsas_config_pack_ext(uint8_t **data, const char *fmt, ...)
-{
- va_list ap;
- size_t ret;
-
- va_start(ap, fmt);
- ret = vpack(data, fmt, ap);
- va_end(ap);
-
- if (data) {
- assert(ret < 65536 && (ret % 4) == 0);
- stw_le_p(*data + 4, ret / 4);
- }
- return ret;
-}
-
-/* Manufacturing pages */
-
-static
-size_t mptsas_config_manufacturing_0(MPTSASState *s, uint8_t **data, int address)
-{
- return MPTSAS_CONFIG_PACK(0, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x00,
- "s16s8s16s16s16",
- "QEMU MPT Fusion",
- "2.5",
- "QEMU MPT Fusion",
- "QEMU",
- "0000111122223333");
-}
-
-static
-size_t mptsas_config_manufacturing_1(MPTSASState *s, uint8_t **data, int address)
-{
- /* VPD - all zeros */
- return MPTSAS_CONFIG_PACK(1, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x00,
- "s256");
-}
-
-static
-size_t mptsas_config_manufacturing_2(MPTSASState *s, uint8_t **data, int address)
-{
- PCIDeviceClass *pcic = PCI_DEVICE_GET_CLASS(s);
- return MPTSAS_CONFIG_PACK(2, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x00,
- "wb*b*l",
- pcic->device_id, pcic->revision);
-}
-
-static
-size_t mptsas_config_manufacturing_3(MPTSASState *s, uint8_t **data, int address)
-{
- PCIDeviceClass *pcic = PCI_DEVICE_GET_CLASS(s);
- return MPTSAS_CONFIG_PACK(3, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x00,
- "wb*b*l",
- pcic->device_id, pcic->revision);
-}
-
-static
-size_t mptsas_config_manufacturing_4(MPTSASState *s, uint8_t **data, int address)
-{
- /* All zeros */
- return MPTSAS_CONFIG_PACK(4, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x05,
- "*l*b*b*b*b*b*b*w*s56*l*l*l*l*l*l"
- "*b*b*w*b*b*w*l*l");
-}
-
-static
-size_t mptsas_config_manufacturing_5(MPTSASState *s, uint8_t **data, int address)
-{
- return MPTSAS_CONFIG_PACK(5, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x02,
- "q*b*b*w*l*l", s->sas_addr);
-}
-
-static
-size_t mptsas_config_manufacturing_6(MPTSASState *s, uint8_t **data, int address)
-{
- return MPTSAS_CONFIG_PACK(6, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x00,
- "*l");
-}
-
-static
-size_t mptsas_config_manufacturing_7(MPTSASState *s, uint8_t **data, int address)
-{
- return MPTSAS_CONFIG_PACK(7, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x00,
- "*l*l*l*s16*b*b*w", MPTSAS_NUM_PORTS);
-}
-
-static
-size_t mptsas_config_manufacturing_8(MPTSASState *s, uint8_t **data, int address)
-{
- return MPTSAS_CONFIG_PACK(8, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x00,
- "*l");
-}
-
-static
-size_t mptsas_config_manufacturing_9(MPTSASState *s, uint8_t **data, int address)
-{
- return MPTSAS_CONFIG_PACK(9, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x00,
- "*l");
-}
-
-static
-size_t mptsas_config_manufacturing_10(MPTSASState *s, uint8_t **data, int address)
-{
- return MPTSAS_CONFIG_PACK(10, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x00,
- "*l");
-}
-
-/* I/O unit pages */
-
-static
-size_t mptsas_config_io_unit_0(MPTSASState *s, uint8_t **data, int address)
-{
- PCIDevice *pci = PCI_DEVICE(s);
- uint64_t unique_value = 0x53504D554D4551LL; /* "QEMUMPTx" */
-
- unique_value |= (uint64_t)pci->devfn << 56;
- return MPTSAS_CONFIG_PACK(0, MPI_CONFIG_PAGETYPE_IO_UNIT, 0x00,
- "q", unique_value);
-}
-
-static
-size_t mptsas_config_io_unit_1(MPTSASState *s, uint8_t **data, int address)
-{
- return MPTSAS_CONFIG_PACK(1, MPI_CONFIG_PAGETYPE_IO_UNIT, 0x02, "l",
- 0x41 /* single function, RAID disabled */ );
-}
-
-static
-size_t mptsas_config_io_unit_2(MPTSASState *s, uint8_t **data, int address)
-{
- PCIDevice *pci = PCI_DEVICE(s);
- uint8_t devfn = pci->devfn;
- return MPTSAS_CONFIG_PACK(2, MPI_CONFIG_PAGETYPE_IO_UNIT, 0x02,
- "llbbw*b*b*w*b*b*w*b*b*w*l",
- 0, 0x100, 0 /* pci bus? */, devfn, 0);
-}
-
-static
-size_t mptsas_config_io_unit_3(MPTSASState *s, uint8_t **data, int address)
-{
- return MPTSAS_CONFIG_PACK(3, MPI_CONFIG_PAGETYPE_IO_UNIT, 0x01,
- "*b*b*w*l");
-}
-
-static
-size_t mptsas_config_io_unit_4(MPTSASState *s, uint8_t **data, int address)
-{
- return MPTSAS_CONFIG_PACK(4, MPI_CONFIG_PAGETYPE_IO_UNIT, 0x00, "*l*l*q");
-}
-
-/* I/O controller pages */
-
-static
-size_t mptsas_config_ioc_0(MPTSASState *s, uint8_t **data, int address)
-{
- PCIDeviceClass *pcic = PCI_DEVICE_GET_CLASS(s);
-
- return MPTSAS_CONFIG_PACK(0, MPI_CONFIG_PAGETYPE_IOC, 0x01,
- "*l*lwwb*b*b*blww",
- pcic->vendor_id, pcic->device_id, pcic->revision,
- pcic->subsystem_vendor_id,
- pcic->subsystem_id);
-}
-
-static
-size_t mptsas_config_ioc_1(MPTSASState *s, uint8_t **data, int address)
-{
- return MPTSAS_CONFIG_PACK(1, MPI_CONFIG_PAGETYPE_IOC, 0x03,
- "*l*l*b*b*b*b");
-}
-
-static
-size_t mptsas_config_ioc_2(MPTSASState *s, uint8_t **data, int address)
-{
- return MPTSAS_CONFIG_PACK(2, MPI_CONFIG_PAGETYPE_IOC, 0x04,
- "*l*b*b*b*b");
-}
-
-static
-size_t mptsas_config_ioc_3(MPTSASState *s, uint8_t **data, int address)
-{
- return MPTSAS_CONFIG_PACK(3, MPI_CONFIG_PAGETYPE_IOC, 0x00,
- "*b*b*w");
-}
-
-static
-size_t mptsas_config_ioc_4(MPTSASState *s, uint8_t **data, int address)
-{
- return MPTSAS_CONFIG_PACK(4, MPI_CONFIG_PAGETYPE_IOC, 0x00,
- "*b*b*w");
-}
-
-static
-size_t mptsas_config_ioc_5(MPTSASState *s, uint8_t **data, int address)
-{
- return MPTSAS_CONFIG_PACK(5, MPI_CONFIG_PAGETYPE_IOC, 0x00,
- "*l*b*b*w");
-}
-
-static
-size_t mptsas_config_ioc_6(MPTSASState *s, uint8_t **data, int address)
-{
- return MPTSAS_CONFIG_PACK(6, MPI_CONFIG_PAGETYPE_IOC, 0x01,
- "*l*b*b*b*b*b*b*b*b*b*b*w*l*l*l*l*b*b*w"
- "*w*w*w*w*l*l*l");
-}
-
-/* SAS I/O unit pages (extended) */
-
-#define MPTSAS_CONFIG_SAS_IO_UNIT_0_SIZE 16
-
-#define MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION 0x02
-#define MPI_SAS_IOUNIT0_RATE_1_5 0x08
-#define MPI_SAS_IOUNIT0_RATE_3_0 0x09
-
-#define MPI_SAS_DEVICE_INFO_NO_DEVICE 0x00000000
-#define MPI_SAS_DEVICE_INFO_END_DEVICE 0x00000001
-#define MPI_SAS_DEVICE_INFO_SSP_TARGET 0x00000400
-
-#define MPI_SAS_DEVICE0_ASTATUS_NO_ERRORS 0x00
-
-#define MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT 0x0001
-#define MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED 0x0002
-#define MPI_SAS_DEVICE0_FLAGS_MAPPING_PERSISTENT 0x0004
-
-
-
-static SCSIDevice *mptsas_phy_get_device(MPTSASState *s, int i,
- int *phy_handle, int *dev_handle)
-{
- SCSIDevice *d = scsi_device_find(&s->bus, 0, i, 0);
-
- if (phy_handle) {
- *phy_handle = i + 1;
- }
- if (dev_handle) {
- *dev_handle = d ? i + 1 + MPTSAS_NUM_PORTS : 0;
- }
- return d;
-}
-
-static
-size_t mptsas_config_sas_io_unit_0(MPTSASState *s, uint8_t **data, int address)
-{
- size_t size = MPTSAS_CONFIG_PACK_EXT(0, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0x04,
- "*w*wb*b*w"
- repl(MPTSAS_NUM_PORTS, "*s16"),
- MPTSAS_NUM_PORTS);
-
- if (data) {
- size_t ofs = size - MPTSAS_NUM_PORTS * MPTSAS_CONFIG_SAS_IO_UNIT_0_SIZE;
- int i;
-
- for (i = 0; i < MPTSAS_NUM_PORTS; i++) {
- int phy_handle, dev_handle;
- SCSIDevice *dev = mptsas_phy_get_device(s, i, &phy_handle, &dev_handle);
-
- fill(*data + ofs, MPTSAS_CONFIG_SAS_IO_UNIT_0_SIZE,
- "bbbblwwl", i, 0, 0,
- (dev
- ? MPI_SAS_IOUNIT0_RATE_3_0
- : MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION),
- (dev
- ? MPI_SAS_DEVICE_INFO_END_DEVICE | MPI_SAS_DEVICE_INFO_SSP_TARGET
- : MPI_SAS_DEVICE_INFO_NO_DEVICE),
- dev_handle,
- dev_handle,
- 0);
- ofs += MPTSAS_CONFIG_SAS_IO_UNIT_0_SIZE;
- }
- assert(ofs == size);
- }
- return size;
-}
-
-#define MPTSAS_CONFIG_SAS_IO_UNIT_1_SIZE 12
-
-static
-size_t mptsas_config_sas_io_unit_1(MPTSASState *s, uint8_t **data, int address)
-{
- size_t size = MPTSAS_CONFIG_PACK_EXT(1, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0x07,
- "*w*w*w*wb*b*b*b"
- repl(MPTSAS_NUM_PORTS, "*s12"),
- MPTSAS_NUM_PORTS);
-
- if (data) {
- size_t ofs = size - MPTSAS_NUM_PORTS * MPTSAS_CONFIG_SAS_IO_UNIT_1_SIZE;
- int i;
-
- for (i = 0; i < MPTSAS_NUM_PORTS; i++) {
- SCSIDevice *dev = mptsas_phy_get_device(s, i, NULL, NULL);
- fill(*data + ofs, MPTSAS_CONFIG_SAS_IO_UNIT_1_SIZE,
- "bbbblww", i, 0, 0,
- (MPI_SAS_IOUNIT0_RATE_3_0 << 4) | MPI_SAS_IOUNIT0_RATE_1_5,
- (dev
- ? MPI_SAS_DEVICE_INFO_END_DEVICE | MPI_SAS_DEVICE_INFO_SSP_TARGET
- : MPI_SAS_DEVICE_INFO_NO_DEVICE),
- 0, 0);
- ofs += MPTSAS_CONFIG_SAS_IO_UNIT_1_SIZE;
- }
- assert(ofs == size);
- }
- return size;
-}
-
-static
-size_t mptsas_config_sas_io_unit_2(MPTSASState *s, uint8_t **data, int address)
-{
- return MPTSAS_CONFIG_PACK_EXT(2, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0x06,
- "*b*b*w*w*w*b*b*w");
-}
-
-static
-size_t mptsas_config_sas_io_unit_3(MPTSASState *s, uint8_t **data, int address)
-{
- return MPTSAS_CONFIG_PACK_EXT(3, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0x06,
- "*l*l*l*l*l*l*l*l*l");
-}
-
-/* SAS PHY pages (extended) */
-
-static int mptsas_phy_addr_get(MPTSASState *s, int address)
-{
- int i;
- if ((address >> MPI_SAS_PHY_PGAD_FORM_SHIFT) == 0) {
- i = address & 255;
- } else if ((address >> MPI_SAS_PHY_PGAD_FORM_SHIFT) == 1) {
- i = address & 65535;
- } else {
- return -EINVAL;
- }
-
- if (i >= MPTSAS_NUM_PORTS) {
- return -EINVAL;
- }
-
- return i;
-}
-
-static
-size_t mptsas_config_phy_0(MPTSASState *s, uint8_t **data, int address)
-{
- int phy_handle = -1;
- int dev_handle = -1;
- int i = mptsas_phy_addr_get(s, address);
- SCSIDevice *dev;
-
- if (i < 0) {
- trace_mptsas_config_sas_phy(s, address, i, phy_handle, dev_handle, 0);
- return i;
- }
-
- dev = mptsas_phy_get_device(s, i, &phy_handle, &dev_handle);
- trace_mptsas_config_sas_phy(s, address, i, phy_handle, dev_handle, 0);
-
- return MPTSAS_CONFIG_PACK_EXT(0, MPI_CONFIG_EXTPAGETYPE_SAS_PHY, 0x01,
- "w*wqwb*blbb*b*b*l",
- dev_handle, s->sas_addr, dev_handle, i,
- (dev
- ? MPI_SAS_DEVICE_INFO_END_DEVICE /* | MPI_SAS_DEVICE_INFO_SSP_TARGET?? */
- : MPI_SAS_DEVICE_INFO_NO_DEVICE),
- (MPI_SAS_IOUNIT0_RATE_3_0 << 4) | MPI_SAS_IOUNIT0_RATE_1_5,
- (MPI_SAS_IOUNIT0_RATE_3_0 << 4) | MPI_SAS_IOUNIT0_RATE_1_5);
-}
-
-static
-size_t mptsas_config_phy_1(MPTSASState *s, uint8_t **data, int address)
-{
- int phy_handle = -1;
- int dev_handle = -1;
- int i = mptsas_phy_addr_get(s, address);
-
- if (i < 0) {
- trace_mptsas_config_sas_phy(s, address, i, phy_handle, dev_handle, 1);
- return i;
- }
-
- (void) mptsas_phy_get_device(s, i, &phy_handle, &dev_handle);
- trace_mptsas_config_sas_phy(s, address, i, phy_handle, dev_handle, 1);
-
- return MPTSAS_CONFIG_PACK_EXT(1, MPI_CONFIG_EXTPAGETYPE_SAS_PHY, 0x01,
- "*l*l*l*l*l");
-}
-
-/* SAS device pages (extended) */
-
-static int mptsas_device_addr_get(MPTSASState *s, int address)
-{
- uint32_t handle, i;
- uint32_t form = address >> MPI_SAS_PHY_PGAD_FORM_SHIFT;
- if (form == MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE) {
- handle = address & MPI_SAS_DEVICE_PGAD_GNH_HANDLE_MASK;
- do {
- if (handle == 65535) {
- handle = MPTSAS_NUM_PORTS + 1;
- } else {
- ++handle;
- }
- i = handle - 1 - MPTSAS_NUM_PORTS;
- } while (i < MPTSAS_NUM_PORTS && !scsi_device_find(&s->bus, 0, i, 0));
-
- } else if (form == MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID) {
- if (address & MPI_SAS_DEVICE_PGAD_BT_BUS_MASK) {
- return -EINVAL;
- }
- i = address & MPI_SAS_DEVICE_PGAD_BT_TID_MASK;
-
- } else if (form == MPI_SAS_DEVICE_PGAD_FORM_HANDLE) {
- handle = address & MPI_SAS_DEVICE_PGAD_H_HANDLE_MASK;
- i = handle - 1 - MPTSAS_NUM_PORTS;
-
- } else {
- return -EINVAL;
- }
-
- if (i >= MPTSAS_NUM_PORTS) {
- return -EINVAL;
- }
-
- return i;
-}
-
-static
-size_t mptsas_config_sas_device_0(MPTSASState *s, uint8_t **data, int address)
-{
- int phy_handle = -1;
- int dev_handle = -1;
- int i = mptsas_device_addr_get(s, address);
- SCSIDevice *dev = mptsas_phy_get_device(s, i, &phy_handle, &dev_handle);
-
- trace_mptsas_config_sas_device(s, address, i, phy_handle, dev_handle, 0);
- if (!dev) {
- return -ENOENT;
- }
-
- return MPTSAS_CONFIG_PACK_EXT(0, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0x05,
- "*w*wqwbbwbblwb*b",
- dev->wwn, phy_handle, i,
- MPI_SAS_DEVICE0_ASTATUS_NO_ERRORS,
- dev_handle, i, 0,
- MPI_SAS_DEVICE_INFO_END_DEVICE | MPI_SAS_DEVICE_INFO_SSP_TARGET,
- (MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT |
- MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED |
- MPI_SAS_DEVICE0_FLAGS_MAPPING_PERSISTENT), i);
-}
-
-static
-size_t mptsas_config_sas_device_1(MPTSASState *s, uint8_t **data, int address)
-{
- int phy_handle = -1;
- int dev_handle = -1;
- int i = mptsas_device_addr_get(s, address);
- SCSIDevice *dev = mptsas_phy_get_device(s, i, &phy_handle, &dev_handle);
-
- trace_mptsas_config_sas_device(s, address, i, phy_handle, dev_handle, 1);
- if (!dev) {
- return -ENOENT;
- }
-
- return MPTSAS_CONFIG_PACK_EXT(1, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0x00,
- "*lq*lwbb*s20",
- dev->wwn, dev_handle, i, 0);
-}
-
-static
-size_t mptsas_config_sas_device_2(MPTSASState *s, uint8_t **data, int address)
-{
- int phy_handle = -1;
- int dev_handle = -1;
- int i = mptsas_device_addr_get(s, address);
- SCSIDevice *dev = mptsas_phy_get_device(s, i, &phy_handle, &dev_handle);
-
- trace_mptsas_config_sas_device(s, address, i, phy_handle, dev_handle, 2);
- if (!dev) {
- return -ENOENT;
- }
-
- return MPTSAS_CONFIG_PACK_EXT(2, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0x01,
- "ql", dev->wwn, 0);
-}
-
-typedef struct MPTSASConfigPage {
- uint8_t number;
- uint8_t type;
- size_t (*mpt_config_build)(MPTSASState *s, uint8_t **data, int address);
-} MPTSASConfigPage;
-
-static const MPTSASConfigPage mptsas_config_pages[] = {
- {
- 0, MPI_CONFIG_PAGETYPE_MANUFACTURING,
- mptsas_config_manufacturing_0,
- }, {
- 1, MPI_CONFIG_PAGETYPE_MANUFACTURING,
- mptsas_config_manufacturing_1,
- }, {
- 2, MPI_CONFIG_PAGETYPE_MANUFACTURING,
- mptsas_config_manufacturing_2,
- }, {
- 3, MPI_CONFIG_PAGETYPE_MANUFACTURING,
- mptsas_config_manufacturing_3,
- }, {
- 4, MPI_CONFIG_PAGETYPE_MANUFACTURING,
- mptsas_config_manufacturing_4,
- }, {
- 5, MPI_CONFIG_PAGETYPE_MANUFACTURING,
- mptsas_config_manufacturing_5,
- }, {
- 6, MPI_CONFIG_PAGETYPE_MANUFACTURING,
- mptsas_config_manufacturing_6,
- }, {
- 7, MPI_CONFIG_PAGETYPE_MANUFACTURING,
- mptsas_config_manufacturing_7,
- }, {
- 8, MPI_CONFIG_PAGETYPE_MANUFACTURING,
- mptsas_config_manufacturing_8,
- }, {
- 9, MPI_CONFIG_PAGETYPE_MANUFACTURING,
- mptsas_config_manufacturing_9,
- }, {
- 10, MPI_CONFIG_PAGETYPE_MANUFACTURING,
- mptsas_config_manufacturing_10,
- }, {
- 0, MPI_CONFIG_PAGETYPE_IO_UNIT,
- mptsas_config_io_unit_0,
- }, {
- 1, MPI_CONFIG_PAGETYPE_IO_UNIT,
- mptsas_config_io_unit_1,
- }, {
- 2, MPI_CONFIG_PAGETYPE_IO_UNIT,
- mptsas_config_io_unit_2,
- }, {
- 3, MPI_CONFIG_PAGETYPE_IO_UNIT,
- mptsas_config_io_unit_3,
- }, {
- 4, MPI_CONFIG_PAGETYPE_IO_UNIT,
- mptsas_config_io_unit_4,
- }, {
- 0, MPI_CONFIG_PAGETYPE_IOC,
- mptsas_config_ioc_0,
- }, {
- 1, MPI_CONFIG_PAGETYPE_IOC,
- mptsas_config_ioc_1,
- }, {
- 2, MPI_CONFIG_PAGETYPE_IOC,
- mptsas_config_ioc_2,
- }, {
- 3, MPI_CONFIG_PAGETYPE_IOC,
- mptsas_config_ioc_3,
- }, {
- 4, MPI_CONFIG_PAGETYPE_IOC,
- mptsas_config_ioc_4,
- }, {
- 5, MPI_CONFIG_PAGETYPE_IOC,
- mptsas_config_ioc_5,
- }, {
- 6, MPI_CONFIG_PAGETYPE_IOC,
- mptsas_config_ioc_6,
- }, {
- 0, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
- mptsas_config_sas_io_unit_0,
- }, {
- 1, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
- mptsas_config_sas_io_unit_1,
- }, {
- 2, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
- mptsas_config_sas_io_unit_2,
- }, {
- 3, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
- mptsas_config_sas_io_unit_3,
- }, {
- 0, MPI_CONFIG_EXTPAGETYPE_SAS_PHY,
- mptsas_config_phy_0,
- }, {
- 1, MPI_CONFIG_EXTPAGETYPE_SAS_PHY,
- mptsas_config_phy_1,
- }, {
- 0, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE,
- mptsas_config_sas_device_0,
- }, {
- 1, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE,
- mptsas_config_sas_device_1,
- }, {
- 2, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE,
- mptsas_config_sas_device_2,
- }
-};
-
-static const MPTSASConfigPage *mptsas_find_config_page(int type, int number)
-{
- const MPTSASConfigPage *page;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(mptsas_config_pages); i++) {
- page = &mptsas_config_pages[i];
- if (page->type == type && page->number == number) {
- return page;
- }
- }
-
- return NULL;
-}
-
-void mptsas_process_config(MPTSASState *s, MPIMsgConfig *req)
-{
- PCIDevice *pci = PCI_DEVICE(s);
-
- MPIMsgConfigReply reply;
- const MPTSASConfigPage *page;
- size_t length;
- uint8_t type;
- uint8_t *data = NULL;
- uint32_t flags_and_length;
- uint32_t dmalen;
- uint64_t pa;
-
- mptsas_fix_config_endianness(req);
-
- QEMU_BUILD_BUG_ON(sizeof(s->doorbell_msg) < sizeof(*req));
- QEMU_BUILD_BUG_ON(sizeof(s->doorbell_reply) < sizeof(reply));
-
- /* Copy common bits from the request into the reply. */
- memset(&reply, 0, sizeof(reply));
- reply.Action = req->Action;
- reply.Function = req->Function;
- reply.MsgContext = req->MsgContext;
- reply.MsgLength = sizeof(reply) / 4;
- reply.PageType = req->PageType;
- reply.PageNumber = req->PageNumber;
- reply.PageLength = req->PageLength;
- reply.PageVersion = req->PageVersion;
-
- type = req->PageType & MPI_CONFIG_PAGETYPE_MASK;
- if (type == MPI_CONFIG_PAGETYPE_EXTENDED) {
- type = req->ExtPageType;
- if (type <= MPI_CONFIG_PAGETYPE_MASK) {
- reply.IOCStatus = MPI_IOCSTATUS_CONFIG_INVALID_TYPE;
- goto out;
- }
-
- reply.ExtPageType = req->ExtPageType;
- }
-
- page = mptsas_find_config_page(type, req->PageNumber);
-
- switch(req->Action) {
- case MPI_CONFIG_ACTION_PAGE_DEFAULT:
- case MPI_CONFIG_ACTION_PAGE_HEADER:
- case MPI_CONFIG_ACTION_PAGE_READ_NVRAM:
- case MPI_CONFIG_ACTION_PAGE_READ_CURRENT:
- case MPI_CONFIG_ACTION_PAGE_READ_DEFAULT:
- case MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT:
- case MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM:
- break;
-
- default:
- reply.IOCStatus = MPI_IOCSTATUS_CONFIG_INVALID_ACTION;
- goto out;
- }
-
- if (!page) {
- page = mptsas_find_config_page(type, 1);
- if (page) {
- reply.IOCStatus = MPI_IOCSTATUS_CONFIG_INVALID_PAGE;
- } else {
- reply.IOCStatus = MPI_IOCSTATUS_CONFIG_INVALID_TYPE;
- }
- goto out;
- }
-
- if (req->Action == MPI_CONFIG_ACTION_PAGE_DEFAULT ||
- req->Action == MPI_CONFIG_ACTION_PAGE_HEADER) {
- length = page->mpt_config_build(s, NULL, req->PageAddress);
- if ((ssize_t)length < 0) {
- reply.IOCStatus = MPI_IOCSTATUS_CONFIG_INVALID_PAGE;
- goto out;
- } else {
- goto done;
- }
- }
-
- if (req->Action == MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT ||
- req->Action == MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM) {
- length = page->mpt_config_build(s, NULL, req->PageAddress);
- if ((ssize_t)length < 0) {
- reply.IOCStatus = MPI_IOCSTATUS_CONFIG_INVALID_PAGE;
- } else {
- reply.IOCStatus = MPI_IOCSTATUS_CONFIG_CANT_COMMIT;
- }
- goto out;
- }
-
- flags_and_length = req->PageBufferSGE.FlagsLength;
- dmalen = flags_and_length & MPI_SGE_LENGTH_MASK;
- if (dmalen == 0) {
- length = page->mpt_config_build(s, NULL, req->PageAddress);
- if ((ssize_t)length < 0) {
- reply.IOCStatus = MPI_IOCSTATUS_CONFIG_INVALID_PAGE;
- goto out;
- } else {
- goto done;
- }
- }
-
- if (flags_and_length & MPI_SGE_FLAGS_64_BIT_ADDRESSING) {
- pa = req->PageBufferSGE.u.Address64;
- } else {
- pa = req->PageBufferSGE.u.Address32;
- }
-
- /* Only read actions left. */
- length = page->mpt_config_build(s, &data, req->PageAddress);
- if ((ssize_t)length < 0) {
- reply.IOCStatus = MPI_IOCSTATUS_CONFIG_INVALID_PAGE;
- goto out;
- } else {
- assert(data[2] == page->number);
- pci_dma_write(pci, pa, data, MIN(length, dmalen));
- goto done;
- }
-
- abort();
-
-done:
- if (type > MPI_CONFIG_PAGETYPE_MASK) {
- reply.ExtPageLength = length / 4;
- reply.ExtPageType = req->ExtPageType;
- } else {
- reply.PageLength = length / 4;
- }
-
-out:
- mptsas_fix_config_reply_endianness(&reply);
- mptsas_reply(s, (MPIDefaultReply *)&reply);
- g_free(data);
-}
diff --git a/qemu/hw/scsi/mptendian.c b/qemu/hw/scsi/mptendian.c
deleted file mode 100644
index b7fe2a2a3..000000000
--- a/qemu/hw/scsi/mptendian.c
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * QEMU LSI SAS1068 Host Bus Adapter emulation
- * Endianness conversion for MPI data structures
- *
- * Copyright (c) 2016 Red Hat, Inc.
- *
- * Authors: Paolo Bonzini <pbonzini@redhat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/pci/pci.h"
-#include "sysemu/dma.h"
-#include "sysemu/block-backend.h"
-#include "hw/pci/msi.h"
-#include "qemu/iov.h"
-#include "hw/scsi/scsi.h"
-#include "block/scsi.h"
-#include "trace.h"
-
-#include "mptsas.h"
-#include "mpi.h"
-
-static void mptsas_fix_sgentry_endianness(MPISGEntry *sge)
-{
- le32_to_cpus(&sge->FlagsLength);
- if (sge->FlagsLength & MPI_SGE_FLAGS_64_BIT_ADDRESSING) {
- le64_to_cpus(&sge->u.Address64);
- } else {
- le32_to_cpus(&sge->u.Address32);
- }
-}
-
-static void mptsas_fix_sgentry_endianness_reply(MPISGEntry *sge)
-{
- if (sge->FlagsLength & MPI_SGE_FLAGS_64_BIT_ADDRESSING) {
- cpu_to_le64s(&sge->u.Address64);
- } else {
- cpu_to_le32s(&sge->u.Address32);
- }
- cpu_to_le32s(&sge->FlagsLength);
-}
-
-void mptsas_fix_scsi_io_endianness(MPIMsgSCSIIORequest *req)
-{
- le32_to_cpus(&req->MsgContext);
- le32_to_cpus(&req->Control);
- le32_to_cpus(&req->DataLength);
- le32_to_cpus(&req->SenseBufferLowAddr);
-}
-
-void mptsas_fix_scsi_io_reply_endianness(MPIMsgSCSIIOReply *reply)
-{
- cpu_to_le32s(&reply->MsgContext);
- cpu_to_le16s(&reply->IOCStatus);
- cpu_to_le32s(&reply->IOCLogInfo);
- cpu_to_le32s(&reply->TransferCount);
- cpu_to_le32s(&reply->SenseCount);
- cpu_to_le32s(&reply->ResponseInfo);
- cpu_to_le16s(&reply->TaskTag);
-}
-
-void mptsas_fix_scsi_task_mgmt_endianness(MPIMsgSCSITaskMgmt *req)
-{
- le32_to_cpus(&req->MsgContext);
- le32_to_cpus(&req->TaskMsgContext);
-}
-
-void mptsas_fix_scsi_task_mgmt_reply_endianness(MPIMsgSCSITaskMgmtReply *reply)
-{
- cpu_to_le32s(&reply->MsgContext);
- cpu_to_le16s(&reply->IOCStatus);
- cpu_to_le32s(&reply->IOCLogInfo);
- cpu_to_le32s(&reply->TerminationCount);
-}
-
-void mptsas_fix_ioc_init_endianness(MPIMsgIOCInit *req)
-{
- le32_to_cpus(&req->MsgContext);
- le16_to_cpus(&req->ReplyFrameSize);
- le32_to_cpus(&req->HostMfaHighAddr);
- le32_to_cpus(&req->SenseBufferHighAddr);
- le32_to_cpus(&req->ReplyFifoHostSignalingAddr);
- mptsas_fix_sgentry_endianness(&req->HostPageBufferSGE);
- le16_to_cpus(&req->MsgVersion);
- le16_to_cpus(&req->HeaderVersion);
-}
-
-void mptsas_fix_ioc_init_reply_endianness(MPIMsgIOCInitReply *reply)
-{
- cpu_to_le32s(&reply->MsgContext);
- cpu_to_le16s(&reply->IOCStatus);
- cpu_to_le32s(&reply->IOCLogInfo);
-}
-
-void mptsas_fix_ioc_facts_endianness(MPIMsgIOCFacts *req)
-{
- le32_to_cpus(&req->MsgContext);
-}
-
-void mptsas_fix_ioc_facts_reply_endianness(MPIMsgIOCFactsReply *reply)
-{
- cpu_to_le16s(&reply->MsgVersion);
- cpu_to_le16s(&reply->HeaderVersion);
- cpu_to_le32s(&reply->MsgContext);
- cpu_to_le16s(&reply->IOCExceptions);
- cpu_to_le16s(&reply->IOCStatus);
- cpu_to_le32s(&reply->IOCLogInfo);
- cpu_to_le16s(&reply->ReplyQueueDepth);
- cpu_to_le16s(&reply->RequestFrameSize);
- cpu_to_le16s(&reply->ProductID);
- cpu_to_le32s(&reply->CurrentHostMfaHighAddr);
- cpu_to_le16s(&reply->GlobalCredits);
- cpu_to_le32s(&reply->CurrentSenseBufferHighAddr);
- cpu_to_le16s(&reply->CurReplyFrameSize);
- cpu_to_le32s(&reply->FWImageSize);
- cpu_to_le32s(&reply->IOCCapabilities);
- cpu_to_le16s(&reply->HighPriorityQueueDepth);
- mptsas_fix_sgentry_endianness_reply(&reply->HostPageBufferSGE);
- cpu_to_le32s(&reply->ReplyFifoHostSignalingAddr);
-}
-
-void mptsas_fix_config_endianness(MPIMsgConfig *req)
-{
- le16_to_cpus(&req->ExtPageLength);
- le32_to_cpus(&req->MsgContext);
- le32_to_cpus(&req->PageAddress);
- mptsas_fix_sgentry_endianness(&req->PageBufferSGE);
-}
-
-void mptsas_fix_config_reply_endianness(MPIMsgConfigReply *reply)
-{
- cpu_to_le16s(&reply->ExtPageLength);
- cpu_to_le32s(&reply->MsgContext);
- cpu_to_le16s(&reply->IOCStatus);
- cpu_to_le32s(&reply->IOCLogInfo);
-}
-
-void mptsas_fix_port_facts_endianness(MPIMsgPortFacts *req)
-{
- le32_to_cpus(&req->MsgContext);
-}
-
-void mptsas_fix_port_facts_reply_endianness(MPIMsgPortFactsReply *reply)
-{
- cpu_to_le32s(&reply->MsgContext);
- cpu_to_le16s(&reply->IOCStatus);
- cpu_to_le32s(&reply->IOCLogInfo);
- cpu_to_le16s(&reply->MaxDevices);
- cpu_to_le16s(&reply->PortSCSIID);
- cpu_to_le16s(&reply->ProtocolFlags);
- cpu_to_le16s(&reply->MaxPostedCmdBuffers);
- cpu_to_le16s(&reply->MaxPersistentIDs);
- cpu_to_le16s(&reply->MaxLanBuckets);
-}
-
-void mptsas_fix_port_enable_endianness(MPIMsgPortEnable *req)
-{
- le32_to_cpus(&req->MsgContext);
-}
-
-void mptsas_fix_port_enable_reply_endianness(MPIMsgPortEnableReply *reply)
-{
- cpu_to_le32s(&reply->MsgContext);
- cpu_to_le16s(&reply->IOCStatus);
- cpu_to_le32s(&reply->IOCLogInfo);
-}
-
-void mptsas_fix_event_notification_endianness(MPIMsgEventNotify *req)
-{
- le32_to_cpus(&req->MsgContext);
-}
-
-void mptsas_fix_event_notification_reply_endianness(MPIMsgEventNotifyReply *reply)
-{
- int length = reply->EventDataLength;
- int i;
-
- cpu_to_le16s(&reply->EventDataLength);
- cpu_to_le32s(&reply->MsgContext);
- cpu_to_le16s(&reply->IOCStatus);
- cpu_to_le32s(&reply->IOCLogInfo);
- cpu_to_le32s(&reply->Event);
- cpu_to_le32s(&reply->EventContext);
-
- /* Really depends on the event kind. This will do for now. */
- for (i = 0; i < length; i++) {
- cpu_to_le32s(&reply->Data[i]);
- }
-}
-
diff --git a/qemu/hw/scsi/mptsas.c b/qemu/hw/scsi/mptsas.c
deleted file mode 100644
index 499c1465a..000000000
--- a/qemu/hw/scsi/mptsas.c
+++ /dev/null
@@ -1,1442 +0,0 @@
-/*
- * QEMU LSI SAS1068 Host Bus Adapter emulation
- * Based on the QEMU Megaraid emulator
- *
- * Copyright (c) 2009-2012 Hannes Reinecke, SUSE Labs
- * Copyright (c) 2012 Verizon, Inc.
- * Copyright (c) 2016 Red Hat, Inc.
- *
- * Authors: Don Slutz, Paolo Bonzini
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/pci/pci.h"
-#include "sysemu/dma.h"
-#include "sysemu/block-backend.h"
-#include "hw/pci/msi.h"
-#include "qemu/iov.h"
-#include "hw/scsi/scsi.h"
-#include "block/scsi.h"
-#include "trace.h"
-
-#include "mptsas.h"
-#include "mpi.h"
-
-#define NAA_LOCALLY_ASSIGNED_ID 0x3ULL
-#define IEEE_COMPANY_LOCALLY_ASSIGNED 0x525400
-
-#define TYPE_MPTSAS1068 "mptsas1068"
-
-#define MPT_SAS(obj) \
- OBJECT_CHECK(MPTSASState, (obj), TYPE_MPTSAS1068)
-
-#define MPTSAS1068_PRODUCT_ID \
- (MPI_FW_HEADER_PID_FAMILY_1068_SAS | \
- MPI_FW_HEADER_PID_PROD_INITIATOR_SCSI | \
- MPI_FW_HEADER_PID_TYPE_SAS)
-
-struct MPTSASRequest {
- MPIMsgSCSIIORequest scsi_io;
- SCSIRequest *sreq;
- QEMUSGList qsg;
- MPTSASState *dev;
-
- QTAILQ_ENTRY(MPTSASRequest) next;
-};
-
-static void mptsas_update_interrupt(MPTSASState *s)
-{
- PCIDevice *pci = (PCIDevice *) s;
- uint32_t state = s->intr_status & ~(s->intr_mask | MPI_HIS_IOP_DOORBELL_STATUS);
-
- if (s->msi_in_use && msi_enabled(pci)) {
- if (state) {
- trace_mptsas_irq_msi(s);
- msi_notify(pci, 0);
- }
- }
-
- trace_mptsas_irq_intx(s, !!state);
- pci_set_irq(pci, !!state);
-}
-
-static void mptsas_set_fault(MPTSASState *s, uint32_t code)
-{
- if ((s->state & MPI_IOC_STATE_FAULT) == 0) {
- s->state = MPI_IOC_STATE_FAULT | code;
- }
-}
-
-#define MPTSAS_FIFO_INVALID(s, name) \
- ((s)->name##_head > ARRAY_SIZE((s)->name) || \
- (s)->name##_tail > ARRAY_SIZE((s)->name))
-
-#define MPTSAS_FIFO_EMPTY(s, name) \
- ((s)->name##_head == (s)->name##_tail)
-
-#define MPTSAS_FIFO_FULL(s, name) \
- ((s)->name##_head == ((s)->name##_tail + 1) % ARRAY_SIZE((s)->name))
-
-#define MPTSAS_FIFO_GET(s, name) ({ \
- uint32_t _val = (s)->name[(s)->name##_head++]; \
- (s)->name##_head %= ARRAY_SIZE((s)->name); \
- _val; \
-})
-
-#define MPTSAS_FIFO_PUT(s, name, val) do { \
- (s)->name[(s)->name##_tail++] = (val); \
- (s)->name##_tail %= ARRAY_SIZE((s)->name); \
-} while(0)
-
-static void mptsas_post_reply(MPTSASState *s, MPIDefaultReply *reply)
-{
- PCIDevice *pci = (PCIDevice *) s;
- uint32_t addr_lo;
-
- if (MPTSAS_FIFO_EMPTY(s, reply_free) || MPTSAS_FIFO_FULL(s, reply_post)) {
- mptsas_set_fault(s, MPI_IOCSTATUS_INSUFFICIENT_RESOURCES);
- return;
- }
-
- addr_lo = MPTSAS_FIFO_GET(s, reply_free);
-
- pci_dma_write(pci, addr_lo | s->host_mfa_high_addr, reply,
- MIN(s->reply_frame_size, 4 * reply->MsgLength));
-
- MPTSAS_FIFO_PUT(s, reply_post, MPI_ADDRESS_REPLY_A_BIT | (addr_lo >> 1));
-
- s->intr_status |= MPI_HIS_REPLY_MESSAGE_INTERRUPT;
- if (s->doorbell_state == DOORBELL_WRITE) {
- s->doorbell_state = DOORBELL_NONE;
- s->intr_status |= MPI_HIS_DOORBELL_INTERRUPT;
- }
- mptsas_update_interrupt(s);
-}
-
-void mptsas_reply(MPTSASState *s, MPIDefaultReply *reply)
-{
- if (s->doorbell_state == DOORBELL_WRITE) {
- /* The reply is sent out in 16 bit chunks, while the size
- * in the reply is in 32 bit units.
- */
- s->doorbell_state = DOORBELL_READ;
- s->doorbell_reply_idx = 0;
- s->doorbell_reply_size = reply->MsgLength * 2;
- memcpy(s->doorbell_reply, reply, s->doorbell_reply_size * 2);
- s->intr_status |= MPI_HIS_DOORBELL_INTERRUPT;
- mptsas_update_interrupt(s);
- } else {
- mptsas_post_reply(s, reply);
- }
-}
-
-static void mptsas_turbo_reply(MPTSASState *s, uint32_t msgctx)
-{
- if (MPTSAS_FIFO_FULL(s, reply_post)) {
- mptsas_set_fault(s, MPI_IOCSTATUS_INSUFFICIENT_RESOURCES);
- return;
- }
-
- /* The reply is just the message context ID (bit 31 = clear). */
- MPTSAS_FIFO_PUT(s, reply_post, msgctx);
-
- s->intr_status |= MPI_HIS_REPLY_MESSAGE_INTERRUPT;
- mptsas_update_interrupt(s);
-}
-
-#define MPTSAS_MAX_REQUEST_SIZE 52
-
-static const int mpi_request_sizes[] = {
- [MPI_FUNCTION_SCSI_IO_REQUEST] = sizeof(MPIMsgSCSIIORequest),
- [MPI_FUNCTION_SCSI_TASK_MGMT] = sizeof(MPIMsgSCSITaskMgmt),
- [MPI_FUNCTION_IOC_INIT] = sizeof(MPIMsgIOCInit),
- [MPI_FUNCTION_IOC_FACTS] = sizeof(MPIMsgIOCFacts),
- [MPI_FUNCTION_CONFIG] = sizeof(MPIMsgConfig),
- [MPI_FUNCTION_PORT_FACTS] = sizeof(MPIMsgPortFacts),
- [MPI_FUNCTION_PORT_ENABLE] = sizeof(MPIMsgPortEnable),
- [MPI_FUNCTION_EVENT_NOTIFICATION] = sizeof(MPIMsgEventNotify),
-};
-
-static dma_addr_t mptsas_ld_sg_base(MPTSASState *s, uint32_t flags_and_length,
- dma_addr_t *sgaddr)
-{
- PCIDevice *pci = (PCIDevice *) s;
- dma_addr_t addr;
-
- if (flags_and_length & MPI_SGE_FLAGS_64_BIT_ADDRESSING) {
- addr = ldq_le_pci_dma(pci, *sgaddr + 4);
- *sgaddr += 12;
- } else {
- addr = ldl_le_pci_dma(pci, *sgaddr + 4);
- *sgaddr += 8;
- }
- return addr;
-}
-
-static int mptsas_build_sgl(MPTSASState *s, MPTSASRequest *req, hwaddr addr)
-{
- PCIDevice *pci = (PCIDevice *) s;
- hwaddr next_chain_addr;
- uint32_t left;
- hwaddr sgaddr;
- uint32_t chain_offset;
-
- chain_offset = req->scsi_io.ChainOffset;
- next_chain_addr = addr + chain_offset * sizeof(uint32_t);
- sgaddr = addr + sizeof(MPIMsgSCSIIORequest);
- pci_dma_sglist_init(&req->qsg, pci, 4);
- left = req->scsi_io.DataLength;
-
- for(;;) {
- dma_addr_t addr, len;
- uint32_t flags_and_length;
-
- flags_and_length = ldl_le_pci_dma(pci, sgaddr);
- len = flags_and_length & MPI_SGE_LENGTH_MASK;
- if ((flags_and_length & MPI_SGE_FLAGS_ELEMENT_TYPE_MASK)
- != MPI_SGE_FLAGS_SIMPLE_ELEMENT ||
- (!len &&
- !(flags_and_length & MPI_SGE_FLAGS_END_OF_LIST) &&
- !(flags_and_length & MPI_SGE_FLAGS_END_OF_BUFFER))) {
- return MPI_IOCSTATUS_INVALID_SGL;
- }
-
- len = MIN(len, left);
- if (!len) {
- /* We reached the desired transfer length, ignore extra
- * elements of the s/g list.
- */
- break;
- }
-
- addr = mptsas_ld_sg_base(s, flags_and_length, &sgaddr);
- qemu_sglist_add(&req->qsg, addr, len);
- left -= len;
-
- if (flags_and_length & MPI_SGE_FLAGS_END_OF_LIST) {
- break;
- }
-
- if (flags_and_length & MPI_SGE_FLAGS_LAST_ELEMENT) {
- if (!chain_offset) {
- break;
- }
-
- flags_and_length = ldl_le_pci_dma(pci, next_chain_addr);
- if ((flags_and_length & MPI_SGE_FLAGS_ELEMENT_TYPE_MASK)
- != MPI_SGE_FLAGS_CHAIN_ELEMENT) {
- return MPI_IOCSTATUS_INVALID_SGL;
- }
-
- sgaddr = mptsas_ld_sg_base(s, flags_and_length, &next_chain_addr);
- chain_offset =
- (flags_and_length & MPI_SGE_CHAIN_OFFSET_MASK) >> MPI_SGE_CHAIN_OFFSET_SHIFT;
- next_chain_addr = sgaddr + chain_offset * sizeof(uint32_t);
- }
- }
- return 0;
-}
-
-static void mptsas_free_request(MPTSASRequest *req)
-{
- MPTSASState *s = req->dev;
-
- if (req->sreq != NULL) {
- req->sreq->hba_private = NULL;
- scsi_req_unref(req->sreq);
- req->sreq = NULL;
- QTAILQ_REMOVE(&s->pending, req, next);
- }
- qemu_sglist_destroy(&req->qsg);
- g_free(req);
-}
-
-static int mptsas_scsi_device_find(MPTSASState *s, int bus, int target,
- uint8_t *lun, SCSIDevice **sdev)
-{
- if (bus != 0) {
- return MPI_IOCSTATUS_SCSI_INVALID_BUS;
- }
-
- if (target >= s->max_devices) {
- return MPI_IOCSTATUS_SCSI_INVALID_TARGETID;
- }
-
- *sdev = scsi_device_find(&s->bus, bus, target, lun[1]);
- if (!*sdev) {
- return MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE;
- }
-
- return 0;
-}
-
-static int mptsas_process_scsi_io_request(MPTSASState *s,
- MPIMsgSCSIIORequest *scsi_io,
- hwaddr addr)
-{
- MPTSASRequest *req;
- MPIMsgSCSIIOReply reply;
- SCSIDevice *sdev;
- int status;
-
- mptsas_fix_scsi_io_endianness(scsi_io);
-
- trace_mptsas_process_scsi_io_request(s, scsi_io->Bus, scsi_io->TargetID,
- scsi_io->LUN[1], scsi_io->DataLength);
-
- status = mptsas_scsi_device_find(s, scsi_io->Bus, scsi_io->TargetID,
- scsi_io->LUN, &sdev);
- if (status) {
- goto bad;
- }
-
- req = g_new(MPTSASRequest, 1);
- QTAILQ_INSERT_TAIL(&s->pending, req, next);
- req->scsi_io = *scsi_io;
- req->dev = s;
-
- status = mptsas_build_sgl(s, req, addr);
- if (status) {
- goto free_bad;
- }
-
- if (req->qsg.size < scsi_io->DataLength) {
- trace_mptsas_sgl_overflow(s, scsi_io->MsgContext, scsi_io->DataLength,
- req->qsg.size);
- status = MPI_IOCSTATUS_INVALID_SGL;
- goto free_bad;
- }
-
- req->sreq = scsi_req_new(sdev, scsi_io->MsgContext,
- scsi_io->LUN[1], scsi_io->CDB, req);
-
- if (req->sreq->cmd.xfer > scsi_io->DataLength) {
- goto overrun;
- }
- switch (scsi_io->Control & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK) {
- case MPI_SCSIIO_CONTROL_NODATATRANSFER:
- if (req->sreq->cmd.mode != SCSI_XFER_NONE) {
- goto overrun;
- }
- break;
-
- case MPI_SCSIIO_CONTROL_WRITE:
- if (req->sreq->cmd.mode != SCSI_XFER_TO_DEV) {
- goto overrun;
- }
- break;
-
- case MPI_SCSIIO_CONTROL_READ:
- if (req->sreq->cmd.mode != SCSI_XFER_FROM_DEV) {
- goto overrun;
- }
- break;
- }
-
- if (scsi_req_enqueue(req->sreq)) {
- scsi_req_continue(req->sreq);
- }
- return 0;
-
-overrun:
- trace_mptsas_scsi_overflow(s, scsi_io->MsgContext, req->sreq->cmd.xfer,
- scsi_io->DataLength);
- status = MPI_IOCSTATUS_SCSI_DATA_OVERRUN;
-free_bad:
- mptsas_free_request(req);
-bad:
- memset(&reply, 0, sizeof(reply));
- reply.TargetID = scsi_io->TargetID;
- reply.Bus = scsi_io->Bus;
- reply.MsgLength = sizeof(reply) / 4;
- reply.Function = scsi_io->Function;
- reply.CDBLength = scsi_io->CDBLength;
- reply.SenseBufferLength = scsi_io->SenseBufferLength;
- reply.MsgContext = scsi_io->MsgContext;
- reply.SCSIState = MPI_SCSI_STATE_NO_SCSI_STATUS;
- reply.IOCStatus = status;
-
- mptsas_fix_scsi_io_reply_endianness(&reply);
- mptsas_reply(s, (MPIDefaultReply *)&reply);
-
- return 0;
-}
-
-typedef struct {
- Notifier notifier;
- MPTSASState *s;
- MPIMsgSCSITaskMgmtReply *reply;
-} MPTSASCancelNotifier;
-
-static void mptsas_cancel_notify(Notifier *notifier, void *data)
-{
- MPTSASCancelNotifier *n = container_of(notifier,
- MPTSASCancelNotifier,
- notifier);
-
- /* Abusing IOCLogInfo to store the expected number of requests... */
- if (++n->reply->TerminationCount == n->reply->IOCLogInfo) {
- n->reply->IOCLogInfo = 0;
- mptsas_fix_scsi_task_mgmt_reply_endianness(n->reply);
- mptsas_post_reply(n->s, (MPIDefaultReply *)n->reply);
- g_free(n->reply);
- }
- g_free(n);
-}
-
-static void mptsas_process_scsi_task_mgmt(MPTSASState *s, MPIMsgSCSITaskMgmt *req)
-{
- MPIMsgSCSITaskMgmtReply reply;
- MPIMsgSCSITaskMgmtReply *reply_async;
- int status, count;
- SCSIDevice *sdev;
- SCSIRequest *r, *next;
- BusChild *kid;
-
- mptsas_fix_scsi_task_mgmt_endianness(req);
-
- QEMU_BUILD_BUG_ON(MPTSAS_MAX_REQUEST_SIZE < sizeof(*req));
- QEMU_BUILD_BUG_ON(sizeof(s->doorbell_msg) < sizeof(*req));
- QEMU_BUILD_BUG_ON(sizeof(s->doorbell_reply) < sizeof(reply));
-
- memset(&reply, 0, sizeof(reply));
- reply.TargetID = req->TargetID;
- reply.Bus = req->Bus;
- reply.MsgLength = sizeof(reply) / 4;
- reply.Function = req->Function;
- reply.TaskType = req->TaskType;
- reply.MsgContext = req->MsgContext;
-
- switch (req->TaskType) {
- case MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
- case MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK:
- status = mptsas_scsi_device_find(s, req->Bus, req->TargetID,
- req->LUN, &sdev);
- if (status) {
- reply.IOCStatus = status;
- goto out;
- }
- if (sdev->lun != req->LUN[1]) {
- reply.ResponseCode = MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN;
- goto out;
- }
-
- QTAILQ_FOREACH_SAFE(r, &sdev->requests, next, next) {
- MPTSASRequest *cmd_req = r->hba_private;
- if (cmd_req && cmd_req->scsi_io.MsgContext == req->TaskMsgContext) {
- break;
- }
- }
- if (r) {
- /*
- * Assert that the request has not been completed yet, we
- * check for it in the loop above.
- */
- assert(r->hba_private);
- if (req->TaskType == MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK) {
- /* "If the specified command is present in the task set, then
- * return a service response set to FUNCTION SUCCEEDED".
- */
- reply.ResponseCode = MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED;
- } else {
- MPTSASCancelNotifier *notifier;
-
- reply_async = g_memdup(&reply, sizeof(MPIMsgSCSITaskMgmtReply));
- reply_async->IOCLogInfo = INT_MAX;
-
- count = 1;
- notifier = g_new(MPTSASCancelNotifier, 1);
- notifier->s = s;
- notifier->reply = reply_async;
- notifier->notifier.notify = mptsas_cancel_notify;
- scsi_req_cancel_async(r, &notifier->notifier);
- goto reply_maybe_async;
- }
- }
- break;
-
- case MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET:
- case MPI_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET:
- status = mptsas_scsi_device_find(s, req->Bus, req->TargetID,
- req->LUN, &sdev);
- if (status) {
- reply.IOCStatus = status;
- goto out;
- }
- if (sdev->lun != req->LUN[1]) {
- reply.ResponseCode = MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN;
- goto out;
- }
-
- reply_async = g_memdup(&reply, sizeof(MPIMsgSCSITaskMgmtReply));
- reply_async->IOCLogInfo = INT_MAX;
-
- count = 0;
- QTAILQ_FOREACH_SAFE(r, &sdev->requests, next, next) {
- if (r->hba_private) {
- MPTSASCancelNotifier *notifier;
-
- count++;
- notifier = g_new(MPTSASCancelNotifier, 1);
- notifier->s = s;
- notifier->reply = reply_async;
- notifier->notifier.notify = mptsas_cancel_notify;
- scsi_req_cancel_async(r, &notifier->notifier);
- }
- }
-
-reply_maybe_async:
- if (reply_async->TerminationCount < count) {
- reply_async->IOCLogInfo = count;
- return;
- }
- g_free(reply_async);
- reply.TerminationCount = count;
- break;
-
- case MPI_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET:
- status = mptsas_scsi_device_find(s, req->Bus, req->TargetID,
- req->LUN, &sdev);
- if (status) {
- reply.IOCStatus = status;
- goto out;
- }
- if (sdev->lun != req->LUN[1]) {
- reply.ResponseCode = MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN;
- goto out;
- }
- qdev_reset_all(&sdev->qdev);
- break;
-
- case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
- if (req->Bus != 0) {
- reply.IOCStatus = MPI_IOCSTATUS_SCSI_INVALID_BUS;
- goto out;
- }
- if (req->TargetID > s->max_devices) {
- reply.IOCStatus = MPI_IOCSTATUS_SCSI_INVALID_TARGETID;
- goto out;
- }
-
- QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
- sdev = SCSI_DEVICE(kid->child);
- if (sdev->channel == 0 && sdev->id == req->TargetID) {
- qdev_reset_all(kid->child);
- }
- }
- break;
-
- case MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS:
- qbus_reset_all(&s->bus.qbus);
- break;
-
- default:
- reply.ResponseCode = MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED;
- break;
- }
-
-out:
- mptsas_fix_scsi_task_mgmt_reply_endianness(&reply);
- mptsas_post_reply(s, (MPIDefaultReply *)&reply);
-}
-
-static void mptsas_process_ioc_init(MPTSASState *s, MPIMsgIOCInit *req)
-{
- MPIMsgIOCInitReply reply;
-
- mptsas_fix_ioc_init_endianness(req);
-
- QEMU_BUILD_BUG_ON(MPTSAS_MAX_REQUEST_SIZE < sizeof(*req));
- QEMU_BUILD_BUG_ON(sizeof(s->doorbell_msg) < sizeof(*req));
- QEMU_BUILD_BUG_ON(sizeof(s->doorbell_reply) < sizeof(reply));
-
- s->who_init = req->WhoInit;
- s->reply_frame_size = req->ReplyFrameSize;
- s->max_buses = req->MaxBuses;
- s->max_devices = req->MaxDevices ? req->MaxDevices : 256;
- s->host_mfa_high_addr = (hwaddr)req->HostMfaHighAddr << 32;
- s->sense_buffer_high_addr = (hwaddr)req->SenseBufferHighAddr << 32;
-
- if (s->state == MPI_IOC_STATE_READY) {
- s->state = MPI_IOC_STATE_OPERATIONAL;
- }
-
- memset(&reply, 0, sizeof(reply));
- reply.WhoInit = s->who_init;
- reply.MsgLength = sizeof(reply) / 4;
- reply.Function = req->Function;
- reply.MaxDevices = s->max_devices;
- reply.MaxBuses = s->max_buses;
- reply.MsgContext = req->MsgContext;
-
- mptsas_fix_ioc_init_reply_endianness(&reply);
- mptsas_reply(s, (MPIDefaultReply *)&reply);
-}
-
-static void mptsas_process_ioc_facts(MPTSASState *s,
- MPIMsgIOCFacts *req)
-{
- MPIMsgIOCFactsReply reply;
-
- mptsas_fix_ioc_facts_endianness(req);
-
- QEMU_BUILD_BUG_ON(MPTSAS_MAX_REQUEST_SIZE < sizeof(*req));
- QEMU_BUILD_BUG_ON(sizeof(s->doorbell_msg) < sizeof(*req));
- QEMU_BUILD_BUG_ON(sizeof(s->doorbell_reply) < sizeof(reply));
-
- memset(&reply, 0, sizeof(reply));
- reply.MsgVersion = 0x0105;
- reply.MsgLength = sizeof(reply) / 4;
- reply.Function = req->Function;
- reply.MsgContext = req->MsgContext;
- reply.MaxChainDepth = MPTSAS_MAXIMUM_CHAIN_DEPTH;
- reply.WhoInit = s->who_init;
- reply.BlockSize = MPTSAS_MAX_REQUEST_SIZE / sizeof(uint32_t);
- reply.ReplyQueueDepth = ARRAY_SIZE(s->reply_post) - 1;
- QEMU_BUILD_BUG_ON(ARRAY_SIZE(s->reply_post) != ARRAY_SIZE(s->reply_free));
-
- reply.RequestFrameSize = 128;
- reply.ProductID = MPTSAS1068_PRODUCT_ID;
- reply.CurrentHostMfaHighAddr = s->host_mfa_high_addr >> 32;
- reply.GlobalCredits = ARRAY_SIZE(s->request_post) - 1;
- reply.NumberOfPorts = MPTSAS_NUM_PORTS;
- reply.CurrentSenseBufferHighAddr = s->sense_buffer_high_addr >> 32;
- reply.CurReplyFrameSize = s->reply_frame_size;
- reply.MaxDevices = s->max_devices;
- reply.MaxBuses = s->max_buses;
- reply.FWVersionDev = 0;
- reply.FWVersionUnit = 0x92;
- reply.FWVersionMinor = 0x32;
- reply.FWVersionMajor = 0x1;
-
- mptsas_fix_ioc_facts_reply_endianness(&reply);
- mptsas_reply(s, (MPIDefaultReply *)&reply);
-}
-
-static void mptsas_process_port_facts(MPTSASState *s,
- MPIMsgPortFacts *req)
-{
- MPIMsgPortFactsReply reply;
-
- mptsas_fix_port_facts_endianness(req);
-
- QEMU_BUILD_BUG_ON(MPTSAS_MAX_REQUEST_SIZE < sizeof(*req));
- QEMU_BUILD_BUG_ON(sizeof(s->doorbell_msg) < sizeof(*req));
- QEMU_BUILD_BUG_ON(sizeof(s->doorbell_reply) < sizeof(reply));
-
- memset(&reply, 0, sizeof(reply));
- reply.MsgLength = sizeof(reply) / 4;
- reply.Function = req->Function;
- reply.PortNumber = req->PortNumber;
- reply.MsgContext = req->MsgContext;
-
- if (req->PortNumber < MPTSAS_NUM_PORTS) {
- reply.PortType = MPI_PORTFACTS_PORTTYPE_SAS;
- reply.MaxDevices = MPTSAS_NUM_PORTS;
- reply.PortSCSIID = MPTSAS_NUM_PORTS;
- reply.ProtocolFlags = MPI_PORTFACTS_PROTOCOL_LOGBUSADDR | MPI_PORTFACTS_PROTOCOL_INITIATOR;
- }
-
- mptsas_fix_port_facts_reply_endianness(&reply);
- mptsas_reply(s, (MPIDefaultReply *)&reply);
-}
-
-static void mptsas_process_port_enable(MPTSASState *s,
- MPIMsgPortEnable *req)
-{
- MPIMsgPortEnableReply reply;
-
- mptsas_fix_port_enable_endianness(req);
-
- QEMU_BUILD_BUG_ON(MPTSAS_MAX_REQUEST_SIZE < sizeof(*req));
- QEMU_BUILD_BUG_ON(sizeof(s->doorbell_msg) < sizeof(*req));
- QEMU_BUILD_BUG_ON(sizeof(s->doorbell_reply) < sizeof(reply));
-
- memset(&reply, 0, sizeof(reply));
- reply.MsgLength = sizeof(reply) / 4;
- reply.PortNumber = req->PortNumber;
- reply.Function = req->Function;
- reply.MsgContext = req->MsgContext;
-
- mptsas_fix_port_enable_reply_endianness(&reply);
- mptsas_reply(s, (MPIDefaultReply *)&reply);
-}
-
-static void mptsas_process_event_notification(MPTSASState *s,
- MPIMsgEventNotify *req)
-{
- MPIMsgEventNotifyReply reply;
-
- mptsas_fix_event_notification_endianness(req);
-
- QEMU_BUILD_BUG_ON(MPTSAS_MAX_REQUEST_SIZE < sizeof(*req));
- QEMU_BUILD_BUG_ON(sizeof(s->doorbell_msg) < sizeof(*req));
- QEMU_BUILD_BUG_ON(sizeof(s->doorbell_reply) < sizeof(reply));
-
- /* Don't even bother storing whether event notification is enabled,
- * since it is not accessible.
- */
-
- memset(&reply, 0, sizeof(reply));
- reply.EventDataLength = sizeof(reply.Data) / 4;
- reply.MsgLength = sizeof(reply) / 4;
- reply.Function = req->Function;
-
- /* This is set because events are sent through the reply FIFOs. */
- reply.MsgFlags = MPI_MSGFLAGS_CONTINUATION_REPLY;
-
- reply.MsgContext = req->MsgContext;
- reply.Event = MPI_EVENT_EVENT_CHANGE;
- reply.Data[0] = !!req->Switch;
-
- mptsas_fix_event_notification_reply_endianness(&reply);
- mptsas_reply(s, (MPIDefaultReply *)&reply);
-}
-
-static void mptsas_process_message(MPTSASState *s, MPIRequestHeader *req)
-{
- trace_mptsas_process_message(s, req->Function, req->MsgContext);
- switch (req->Function) {
- case MPI_FUNCTION_SCSI_TASK_MGMT:
- mptsas_process_scsi_task_mgmt(s, (MPIMsgSCSITaskMgmt *)req);
- break;
-
- case MPI_FUNCTION_IOC_INIT:
- mptsas_process_ioc_init(s, (MPIMsgIOCInit *)req);
- break;
-
- case MPI_FUNCTION_IOC_FACTS:
- mptsas_process_ioc_facts(s, (MPIMsgIOCFacts *)req);
- break;
-
- case MPI_FUNCTION_PORT_FACTS:
- mptsas_process_port_facts(s, (MPIMsgPortFacts *)req);
- break;
-
- case MPI_FUNCTION_PORT_ENABLE:
- mptsas_process_port_enable(s, (MPIMsgPortEnable *)req);
- break;
-
- case MPI_FUNCTION_EVENT_NOTIFICATION:
- mptsas_process_event_notification(s, (MPIMsgEventNotify *)req);
- break;
-
- case MPI_FUNCTION_CONFIG:
- mptsas_process_config(s, (MPIMsgConfig *)req);
- break;
-
- default:
- trace_mptsas_unhandled_cmd(s, req->Function, 0);
- mptsas_set_fault(s, MPI_IOCSTATUS_INVALID_FUNCTION);
- break;
- }
-}
-
-static void mptsas_fetch_request(MPTSASState *s)
-{
- PCIDevice *pci = (PCIDevice *) s;
- char req[MPTSAS_MAX_REQUEST_SIZE];
- MPIRequestHeader *hdr = (MPIRequestHeader *)req;
- hwaddr addr;
- int size;
-
- if (s->state != MPI_IOC_STATE_OPERATIONAL) {
- mptsas_set_fault(s, MPI_IOCSTATUS_INVALID_STATE);
- return;
- }
-
- /* Read the message header from the guest first. */
- addr = s->host_mfa_high_addr | MPTSAS_FIFO_GET(s, request_post);
- pci_dma_read(pci, addr, req, sizeof(hdr));
-
- if (hdr->Function < ARRAY_SIZE(mpi_request_sizes) &&
- mpi_request_sizes[hdr->Function]) {
- /* Read the rest of the request based on the type. Do not
- * reread everything, as that could cause a TOC/TOU mismatch
- * and leak data from the QEMU stack.
- */
- size = mpi_request_sizes[hdr->Function];
- assert(size <= MPTSAS_MAX_REQUEST_SIZE);
- pci_dma_read(pci, addr + sizeof(hdr), &req[sizeof(hdr)],
- size - sizeof(hdr));
- }
-
- if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
- /* SCSI I/O requests are separate from mptsas_process_message
- * because they cannot be sent through the doorbell yet.
- */
- mptsas_process_scsi_io_request(s, (MPIMsgSCSIIORequest *)req, addr);
- } else {
- mptsas_process_message(s, (MPIRequestHeader *)req);
- }
-}
-
-static void mptsas_fetch_requests(void *opaque)
-{
- MPTSASState *s = opaque;
-
- while (!MPTSAS_FIFO_EMPTY(s, request_post)) {
- mptsas_fetch_request(s);
- }
-}
-
-static void mptsas_soft_reset(MPTSASState *s)
-{
- uint32_t save_mask;
-
- trace_mptsas_reset(s);
-
- /* Temporarily disable interrupts */
- save_mask = s->intr_mask;
- s->intr_mask = MPI_HIM_DIM | MPI_HIM_RIM;
- mptsas_update_interrupt(s);
-
- qbus_reset_all(&s->bus.qbus);
- s->intr_status = 0;
- s->intr_mask = save_mask;
-
- s->reply_free_tail = 0;
- s->reply_free_head = 0;
- s->reply_post_tail = 0;
- s->reply_post_head = 0;
- s->request_post_tail = 0;
- s->request_post_head = 0;
- qemu_bh_cancel(s->request_bh);
-
- s->state = MPI_IOC_STATE_READY;
-}
-
-static uint32_t mptsas_doorbell_read(MPTSASState *s)
-{
- uint32_t ret;
-
- ret = (s->who_init << MPI_DOORBELL_WHO_INIT_SHIFT) & MPI_DOORBELL_WHO_INIT_MASK;
- ret |= s->state;
- switch (s->doorbell_state) {
- case DOORBELL_NONE:
- break;
-
- case DOORBELL_WRITE:
- ret |= MPI_DOORBELL_ACTIVE;
- break;
-
- case DOORBELL_READ:
- /* Get rid of the IOC fault code. */
- ret &= ~MPI_DOORBELL_DATA_MASK;
-
- assert(s->intr_status & MPI_HIS_DOORBELL_INTERRUPT);
- assert(s->doorbell_reply_idx <= s->doorbell_reply_size);
-
- ret |= MPI_DOORBELL_ACTIVE;
- if (s->doorbell_reply_idx < s->doorbell_reply_size) {
- /* For more information about this endian switch, see the
- * commit message for commit 36b62ae ("fw_cfg: fix endianness in
- * fw_cfg_data_mem_read() / _write()", 2015-01-16).
- */
- ret |= le16_to_cpu(s->doorbell_reply[s->doorbell_reply_idx++]);
- }
- break;
-
- default:
- abort();
- }
-
- return ret;
-}
-
-static void mptsas_doorbell_write(MPTSASState *s, uint32_t val)
-{
- if (s->doorbell_state == DOORBELL_WRITE) {
- if (s->doorbell_idx < s->doorbell_cnt) {
- /* For more information about this endian switch, see the
- * commit message for commit 36b62ae ("fw_cfg: fix endianness in
- * fw_cfg_data_mem_read() / _write()", 2015-01-16).
- */
- s->doorbell_msg[s->doorbell_idx++] = cpu_to_le32(val);
- if (s->doorbell_idx == s->doorbell_cnt) {
- mptsas_process_message(s, (MPIRequestHeader *)s->doorbell_msg);
- }
- }
- return;
- }
-
- switch ((val & MPI_DOORBELL_FUNCTION_MASK) >> MPI_DOORBELL_FUNCTION_SHIFT) {
- case MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET:
- mptsas_soft_reset(s);
- break;
- case MPI_FUNCTION_IO_UNIT_RESET:
- break;
- case MPI_FUNCTION_HANDSHAKE:
- s->doorbell_state = DOORBELL_WRITE;
- s->doorbell_idx = 0;
- s->doorbell_cnt = (val & MPI_DOORBELL_ADD_DWORDS_MASK)
- >> MPI_DOORBELL_ADD_DWORDS_SHIFT;
- s->intr_status |= MPI_HIS_DOORBELL_INTERRUPT;
- mptsas_update_interrupt(s);
- break;
- default:
- trace_mptsas_unhandled_doorbell_cmd(s, val);
- break;
- }
-}
-
-static void mptsas_write_sequence_write(MPTSASState *s, uint32_t val)
-{
- /* If the diagnostic register is enabled, any write to this register
- * will disable it. Otherwise, the guest has to do a magic five-write
- * sequence.
- */
- if (s->diagnostic & MPI_DIAG_DRWE) {
- goto disable;
- }
-
- switch (s->diagnostic_idx) {
- case 0:
- if ((val & MPI_WRSEQ_KEY_VALUE_MASK) != MPI_WRSEQ_1ST_KEY_VALUE) {
- goto disable;
- }
- break;
- case 1:
- if ((val & MPI_WRSEQ_KEY_VALUE_MASK) != MPI_WRSEQ_2ND_KEY_VALUE) {
- goto disable;
- }
- break;
- case 2:
- if ((val & MPI_WRSEQ_KEY_VALUE_MASK) != MPI_WRSEQ_3RD_KEY_VALUE) {
- goto disable;
- }
- break;
- case 3:
- if ((val & MPI_WRSEQ_KEY_VALUE_MASK) != MPI_WRSEQ_4TH_KEY_VALUE) {
- goto disable;
- }
- break;
- case 4:
- if ((val & MPI_WRSEQ_KEY_VALUE_MASK) != MPI_WRSEQ_5TH_KEY_VALUE) {
- goto disable;
- }
- /* Prepare Spaceball One for departure, and change the
- * combination on my luggage!
- */
- s->diagnostic |= MPI_DIAG_DRWE;
- break;
- }
- s->diagnostic_idx++;
- return;
-
-disable:
- s->diagnostic &= ~MPI_DIAG_DRWE;
- s->diagnostic_idx = 0;
-}
-
-static int mptsas_hard_reset(MPTSASState *s)
-{
- mptsas_soft_reset(s);
-
- s->intr_mask = MPI_HIM_DIM | MPI_HIM_RIM;
-
- s->host_mfa_high_addr = 0;
- s->sense_buffer_high_addr = 0;
- s->reply_frame_size = 0;
- s->max_devices = MPTSAS_NUM_PORTS;
- s->max_buses = 1;
-
- return 0;
-}
-
-static void mptsas_interrupt_status_write(MPTSASState *s)
-{
- switch (s->doorbell_state) {
- case DOORBELL_NONE:
- case DOORBELL_WRITE:
- s->intr_status &= ~MPI_HIS_DOORBELL_INTERRUPT;
- break;
-
- case DOORBELL_READ:
- /* The reply can be read continuously, so leave the interrupt up. */
- assert(s->intr_status & MPI_HIS_DOORBELL_INTERRUPT);
- if (s->doorbell_reply_idx == s->doorbell_reply_size) {
- s->doorbell_state = DOORBELL_NONE;
- }
- break;
-
- default:
- abort();
- }
- mptsas_update_interrupt(s);
-}
-
-static uint32_t mptsas_reply_post_read(MPTSASState *s)
-{
- uint32_t ret;
-
- if (!MPTSAS_FIFO_EMPTY(s, reply_post)) {
- ret = MPTSAS_FIFO_GET(s, reply_post);
- } else {
- ret = -1;
- s->intr_status &= ~MPI_HIS_REPLY_MESSAGE_INTERRUPT;
- mptsas_update_interrupt(s);
- }
-
- return ret;
-}
-
-static uint64_t mptsas_mmio_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- MPTSASState *s = opaque;
- uint32_t ret = 0;
-
- switch (addr & ~3) {
- case MPI_DOORBELL_OFFSET:
- ret = mptsas_doorbell_read(s);
- break;
-
- case MPI_DIAGNOSTIC_OFFSET:
- ret = s->diagnostic;
- break;
-
- case MPI_HOST_INTERRUPT_STATUS_OFFSET:
- ret = s->intr_status;
- break;
-
- case MPI_HOST_INTERRUPT_MASK_OFFSET:
- ret = s->intr_mask;
- break;
-
- case MPI_REPLY_POST_FIFO_OFFSET:
- ret = mptsas_reply_post_read(s);
- break;
-
- default:
- trace_mptsas_mmio_unhandled_read(s, addr);
- break;
- }
- trace_mptsas_mmio_read(s, addr, ret);
- return ret;
-}
-
-static void mptsas_mmio_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- MPTSASState *s = opaque;
-
- trace_mptsas_mmio_write(s, addr, val);
- switch (addr) {
- case MPI_DOORBELL_OFFSET:
- mptsas_doorbell_write(s, val);
- break;
-
- case MPI_WRITE_SEQUENCE_OFFSET:
- mptsas_write_sequence_write(s, val);
- break;
-
- case MPI_DIAGNOSTIC_OFFSET:
- if (val & MPI_DIAG_RESET_ADAPTER) {
- mptsas_hard_reset(s);
- }
- break;
-
- case MPI_HOST_INTERRUPT_STATUS_OFFSET:
- mptsas_interrupt_status_write(s);
- break;
-
- case MPI_HOST_INTERRUPT_MASK_OFFSET:
- s->intr_mask = val & (MPI_HIM_RIM | MPI_HIM_DIM);
- mptsas_update_interrupt(s);
- break;
-
- case MPI_REQUEST_POST_FIFO_OFFSET:
- if (MPTSAS_FIFO_FULL(s, request_post)) {
- mptsas_set_fault(s, MPI_IOCSTATUS_INSUFFICIENT_RESOURCES);
- } else {
- MPTSAS_FIFO_PUT(s, request_post, val & ~0x03);
- qemu_bh_schedule(s->request_bh);
- }
- break;
-
- case MPI_REPLY_FREE_FIFO_OFFSET:
- if (MPTSAS_FIFO_FULL(s, reply_free)) {
- mptsas_set_fault(s, MPI_IOCSTATUS_INSUFFICIENT_RESOURCES);
- } else {
- MPTSAS_FIFO_PUT(s, reply_free, val);
- }
- break;
-
- default:
- trace_mptsas_mmio_unhandled_write(s, addr, val);
- break;
- }
-}
-
-static const MemoryRegionOps mptsas_mmio_ops = {
- .read = mptsas_mmio_read,
- .write = mptsas_mmio_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .impl = {
- .min_access_size = 4,
- .max_access_size = 4,
- }
-};
-
-static const MemoryRegionOps mptsas_port_ops = {
- .read = mptsas_mmio_read,
- .write = mptsas_mmio_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .impl = {
- .min_access_size = 4,
- .max_access_size = 4,
- }
-};
-
-static uint64_t mptsas_diag_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- MPTSASState *s = opaque;
- trace_mptsas_diag_read(s, addr, 0);
- return 0;
-}
-
-static void mptsas_diag_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- MPTSASState *s = opaque;
- trace_mptsas_diag_write(s, addr, val);
-}
-
-static const MemoryRegionOps mptsas_diag_ops = {
- .read = mptsas_diag_read,
- .write = mptsas_diag_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .impl = {
- .min_access_size = 4,
- .max_access_size = 4,
- }
-};
-
-static QEMUSGList *mptsas_get_sg_list(SCSIRequest *sreq)
-{
- MPTSASRequest *req = sreq->hba_private;
-
- return &req->qsg;
-}
-
-static void mptsas_command_complete(SCSIRequest *sreq,
- uint32_t status, size_t resid)
-{
- MPTSASRequest *req = sreq->hba_private;
- MPTSASState *s = req->dev;
- uint8_t sense_buf[SCSI_SENSE_BUF_SIZE];
- uint8_t sense_len;
-
- hwaddr sense_buffer_addr = req->dev->sense_buffer_high_addr |
- req->scsi_io.SenseBufferLowAddr;
-
- trace_mptsas_command_complete(s, req->scsi_io.MsgContext, status, resid);
-
- sense_len = scsi_req_get_sense(sreq, sense_buf, SCSI_SENSE_BUF_SIZE);
- if (sense_len > 0) {
- pci_dma_write(PCI_DEVICE(s), sense_buffer_addr, sense_buf,
- MIN(req->scsi_io.SenseBufferLength, sense_len));
- }
-
- if (sreq->status != GOOD || resid ||
- req->dev->doorbell_state == DOORBELL_WRITE) {
- MPIMsgSCSIIOReply reply;
-
- memset(&reply, 0, sizeof(reply));
- reply.TargetID = req->scsi_io.TargetID;
- reply.Bus = req->scsi_io.Bus;
- reply.MsgLength = sizeof(reply) / 4;
- reply.Function = req->scsi_io.Function;
- reply.CDBLength = req->scsi_io.CDBLength;
- reply.SenseBufferLength = req->scsi_io.SenseBufferLength;
- reply.MsgFlags = req->scsi_io.MsgFlags;
- reply.MsgContext = req->scsi_io.MsgContext;
- reply.SCSIStatus = sreq->status;
- if (sreq->status == GOOD) {
- reply.TransferCount = req->scsi_io.DataLength - resid;
- if (resid) {
- reply.IOCStatus = MPI_IOCSTATUS_SCSI_DATA_UNDERRUN;
- }
- } else {
- reply.SCSIState = MPI_SCSI_STATE_AUTOSENSE_VALID;
- reply.SenseCount = sense_len;
- reply.IOCStatus = MPI_IOCSTATUS_SCSI_DATA_UNDERRUN;
- }
-
- mptsas_fix_scsi_io_reply_endianness(&reply);
- mptsas_post_reply(req->dev, (MPIDefaultReply *)&reply);
- } else {
- mptsas_turbo_reply(req->dev, req->scsi_io.MsgContext);
- }
-
- mptsas_free_request(req);
-}
-
-static void mptsas_request_cancelled(SCSIRequest *sreq)
-{
- MPTSASRequest *req = sreq->hba_private;
- MPIMsgSCSIIOReply reply;
-
- memset(&reply, 0, sizeof(reply));
- reply.TargetID = req->scsi_io.TargetID;
- reply.Bus = req->scsi_io.Bus;
- reply.MsgLength = sizeof(reply) / 4;
- reply.Function = req->scsi_io.Function;
- reply.CDBLength = req->scsi_io.CDBLength;
- reply.SenseBufferLength = req->scsi_io.SenseBufferLength;
- reply.MsgFlags = req->scsi_io.MsgFlags;
- reply.MsgContext = req->scsi_io.MsgContext;
- reply.SCSIState = MPI_SCSI_STATE_NO_SCSI_STATUS;
- reply.IOCStatus = MPI_IOCSTATUS_SCSI_TASK_TERMINATED;
-
- mptsas_fix_scsi_io_reply_endianness(&reply);
- mptsas_post_reply(req->dev, (MPIDefaultReply *)&reply);
- mptsas_free_request(req);
-}
-
-static void mptsas_save_request(QEMUFile *f, SCSIRequest *sreq)
-{
- MPTSASRequest *req = sreq->hba_private;
- int i;
-
- qemu_put_buffer(f, (unsigned char *)&req->scsi_io, sizeof(req->scsi_io));
- qemu_put_be32(f, req->qsg.nsg);
- for (i = 0; i < req->qsg.nsg; i++) {
- qemu_put_be64(f, req->qsg.sg[i].base);
- qemu_put_be64(f, req->qsg.sg[i].len);
- }
-}
-
-static void *mptsas_load_request(QEMUFile *f, SCSIRequest *sreq)
-{
- SCSIBus *bus = sreq->bus;
- MPTSASState *s = container_of(bus, MPTSASState, bus);
- PCIDevice *pci = PCI_DEVICE(s);
- MPTSASRequest *req;
- int i, n;
-
- req = g_new(MPTSASRequest, 1);
- qemu_get_buffer(f, (unsigned char *)&req->scsi_io, sizeof(req->scsi_io));
-
- n = qemu_get_be32(f);
- /* TODO: add a way for SCSIBusInfo's load_request to fail,
- * and fail migration instead of asserting here.
- * When we do, we might be able to re-enable NDEBUG below.
- */
-#ifdef NDEBUG
-#error building with NDEBUG is not supported
-#endif
- assert(n >= 0);
-
- pci_dma_sglist_init(&req->qsg, pci, n);
- for (i = 0; i < n; i++) {
- uint64_t base = qemu_get_be64(f);
- uint64_t len = qemu_get_be64(f);
- qemu_sglist_add(&req->qsg, base, len);
- }
-
- scsi_req_ref(sreq);
- req->sreq = sreq;
- req->dev = s;
-
- return req;
-}
-
-static const struct SCSIBusInfo mptsas_scsi_info = {
- .tcq = true,
- .max_target = MPTSAS_NUM_PORTS,
- .max_lun = 1,
-
- .get_sg_list = mptsas_get_sg_list,
- .complete = mptsas_command_complete,
- .cancel = mptsas_request_cancelled,
- .save_request = mptsas_save_request,
- .load_request = mptsas_load_request,
-};
-
-static void mptsas_scsi_init(PCIDevice *dev, Error **errp)
-{
- DeviceState *d = DEVICE(dev);
- MPTSASState *s = MPT_SAS(dev);
-
- dev->config[PCI_LATENCY_TIMER] = 0;
- dev->config[PCI_INTERRUPT_PIN] = 0x01;
-
- memory_region_init_io(&s->mmio_io, OBJECT(s), &mptsas_mmio_ops, s,
- "mptsas-mmio", 0x4000);
- memory_region_init_io(&s->port_io, OBJECT(s), &mptsas_port_ops, s,
- "mptsas-io", 256);
- memory_region_init_io(&s->diag_io, OBJECT(s), &mptsas_diag_ops, s,
- "mptsas-diag", 0x10000);
-
- if (s->msi_available &&
- msi_init(dev, 0, 1, true, false) >= 0) {
- s->msi_in_use = true;
- }
-
- pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->port_io);
- pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY |
- PCI_BASE_ADDRESS_MEM_TYPE_32, &s->mmio_io);
- pci_register_bar(dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY |
- PCI_BASE_ADDRESS_MEM_TYPE_32, &s->diag_io);
-
- if (!s->sas_addr) {
- s->sas_addr = ((NAA_LOCALLY_ASSIGNED_ID << 24) |
- IEEE_COMPANY_LOCALLY_ASSIGNED) << 36;
- s->sas_addr |= (pci_bus_num(dev->bus) << 16);
- s->sas_addr |= (PCI_SLOT(dev->devfn) << 8);
- s->sas_addr |= PCI_FUNC(dev->devfn);
- }
- s->max_devices = MPTSAS_NUM_PORTS;
-
- s->request_bh = qemu_bh_new(mptsas_fetch_requests, s);
-
- QTAILQ_INIT(&s->pending);
-
- scsi_bus_new(&s->bus, sizeof(s->bus), &dev->qdev, &mptsas_scsi_info, NULL);
- if (!d->hotplugged) {
- scsi_bus_legacy_handle_cmdline(&s->bus, errp);
- }
-}
-
-static void mptsas_scsi_uninit(PCIDevice *dev)
-{
- MPTSASState *s = MPT_SAS(dev);
-
- qemu_bh_delete(s->request_bh);
- if (s->msi_in_use) {
- msi_uninit(dev);
- }
-}
-
-static void mptsas_reset(DeviceState *dev)
-{
- MPTSASState *s = MPT_SAS(dev);
-
- mptsas_hard_reset(s);
-}
-
-static int mptsas_post_load(void *opaque, int version_id)
-{
- MPTSASState *s = opaque;
-
- if (s->doorbell_idx > s->doorbell_cnt ||
- s->doorbell_cnt > ARRAY_SIZE(s->doorbell_msg) ||
- s->doorbell_reply_idx > s->doorbell_reply_size ||
- s->doorbell_reply_size > ARRAY_SIZE(s->doorbell_reply) ||
- MPTSAS_FIFO_INVALID(s, request_post) ||
- MPTSAS_FIFO_INVALID(s, reply_post) ||
- MPTSAS_FIFO_INVALID(s, reply_free) ||
- s->diagnostic_idx > 4) {
- return -EINVAL;
- }
-
- return 0;
-}
-
-static const VMStateDescription vmstate_mptsas = {
- .name = "mptsas",
- .version_id = 0,
- .minimum_version_id = 0,
- .minimum_version_id_old = 0,
- .post_load = mptsas_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(dev, MPTSASState),
- VMSTATE_BOOL(msi_in_use, MPTSASState),
-
- VMSTATE_UINT32(state, MPTSASState),
- VMSTATE_UINT8(who_init, MPTSASState),
- VMSTATE_UINT8(doorbell_state, MPTSASState),
- VMSTATE_UINT32_ARRAY(doorbell_msg, MPTSASState, 256),
- VMSTATE_INT32(doorbell_idx, MPTSASState),
- VMSTATE_INT32(doorbell_cnt, MPTSASState),
-
- VMSTATE_UINT16_ARRAY(doorbell_reply, MPTSASState, 256),
- VMSTATE_INT32(doorbell_reply_idx, MPTSASState),
- VMSTATE_INT32(doorbell_reply_size, MPTSASState),
-
- VMSTATE_UINT32(diagnostic, MPTSASState),
- VMSTATE_UINT8(diagnostic_idx, MPTSASState),
-
- VMSTATE_UINT32(intr_status, MPTSASState),
- VMSTATE_UINT32(intr_mask, MPTSASState),
-
- VMSTATE_UINT32_ARRAY(request_post, MPTSASState,
- MPTSAS_REQUEST_QUEUE_DEPTH + 1),
- VMSTATE_UINT16(request_post_head, MPTSASState),
- VMSTATE_UINT16(request_post_tail, MPTSASState),
-
- VMSTATE_UINT32_ARRAY(reply_post, MPTSASState,
- MPTSAS_REPLY_QUEUE_DEPTH + 1),
- VMSTATE_UINT16(reply_post_head, MPTSASState),
- VMSTATE_UINT16(reply_post_tail, MPTSASState),
-
- VMSTATE_UINT32_ARRAY(reply_free, MPTSASState,
- MPTSAS_REPLY_QUEUE_DEPTH + 1),
- VMSTATE_UINT16(reply_free_head, MPTSASState),
- VMSTATE_UINT16(reply_free_tail, MPTSASState),
-
- VMSTATE_UINT16(max_buses, MPTSASState),
- VMSTATE_UINT16(max_devices, MPTSASState),
- VMSTATE_UINT16(reply_frame_size, MPTSASState),
- VMSTATE_UINT64(host_mfa_high_addr, MPTSASState),
- VMSTATE_UINT64(sense_buffer_high_addr, MPTSASState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property mptsas_properties[] = {
- DEFINE_PROP_UINT64("sas_address", MPTSASState, sas_addr, 0),
- /* TODO: test MSI support under Windows */
- DEFINE_PROP_BIT("msi", MPTSASState, msi_available, 0, true),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void mptsas1068_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
- PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc);
-
- pc->realize = mptsas_scsi_init;
- pc->exit = mptsas_scsi_uninit;
- pc->romfile = 0;
- pc->vendor_id = PCI_VENDOR_ID_LSI_LOGIC;
- pc->device_id = PCI_DEVICE_ID_LSI_SAS1068;
- pc->subsystem_vendor_id = PCI_VENDOR_ID_LSI_LOGIC;
- pc->subsystem_id = 0x8000;
- pc->class_id = PCI_CLASS_STORAGE_SCSI;
- dc->props = mptsas_properties;
- dc->reset = mptsas_reset;
- dc->vmsd = &vmstate_mptsas;
- dc->desc = "LSI SAS 1068";
-}
-
-static const TypeInfo mptsas_info = {
- .name = TYPE_MPTSAS1068,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(MPTSASState),
- .class_init = mptsas1068_class_init,
-};
-
-static void mptsas_register_types(void)
-{
- type_register(&mptsas_info);
-}
-
-type_init(mptsas_register_types)
diff --git a/qemu/hw/scsi/mptsas.h b/qemu/hw/scsi/mptsas.h
deleted file mode 100644
index 595f81fb5..000000000
--- a/qemu/hw/scsi/mptsas.h
+++ /dev/null
@@ -1,100 +0,0 @@
-#ifndef MPTSAS_H
-#define MPTSAS_H
-
-#include "mpi.h"
-
-#define MPTSAS_NUM_PORTS 8
-#define MPTSAS_MAX_FRAMES 2048 /* Firmware limit at 65535 */
-
-#define MPTSAS_REQUEST_QUEUE_DEPTH 128
-#define MPTSAS_REPLY_QUEUE_DEPTH 128
-
-#define MPTSAS_MAXIMUM_CHAIN_DEPTH 0x22
-
-typedef struct MPTSASState MPTSASState;
-typedef struct MPTSASRequest MPTSASRequest;
-
-enum {
- DOORBELL_NONE,
- DOORBELL_WRITE,
- DOORBELL_READ
-};
-
-struct MPTSASState {
- PCIDevice dev;
- MemoryRegion mmio_io;
- MemoryRegion port_io;
- MemoryRegion diag_io;
- QEMUBH *request_bh;
-
- uint32_t msi_available;
- uint64_t sas_addr;
-
- bool msi_in_use;
-
- /* Doorbell register */
- uint32_t state;
- uint8_t who_init;
- uint8_t doorbell_state;
-
- /* Buffer for requests that are sent through the doorbell register. */
- uint32_t doorbell_msg[256];
- int doorbell_idx;
- int doorbell_cnt;
-
- uint16_t doorbell_reply[256];
- int doorbell_reply_idx;
- int doorbell_reply_size;
-
- /* Other registers */
- uint8_t diagnostic_idx;
- uint32_t diagnostic;
- uint32_t intr_mask;
- uint32_t intr_status;
-
- /* Request queues */
- uint32_t request_post[MPTSAS_REQUEST_QUEUE_DEPTH + 1];
- uint16_t request_post_head;
- uint16_t request_post_tail;
-
- uint32_t reply_post[MPTSAS_REPLY_QUEUE_DEPTH + 1];
- uint16_t reply_post_head;
- uint16_t reply_post_tail;
-
- uint32_t reply_free[MPTSAS_REPLY_QUEUE_DEPTH + 1];
- uint16_t reply_free_head;
- uint16_t reply_free_tail;
-
- /* IOC Facts */
- hwaddr host_mfa_high_addr;
- hwaddr sense_buffer_high_addr;
- uint16_t max_devices;
- uint16_t max_buses;
- uint16_t reply_frame_size;
-
- SCSIBus bus;
- QTAILQ_HEAD(, MPTSASRequest) pending;
-};
-
-void mptsas_fix_scsi_io_endianness(MPIMsgSCSIIORequest *req);
-void mptsas_fix_scsi_io_reply_endianness(MPIMsgSCSIIOReply *reply);
-void mptsas_fix_scsi_task_mgmt_endianness(MPIMsgSCSITaskMgmt *req);
-void mptsas_fix_scsi_task_mgmt_reply_endianness(MPIMsgSCSITaskMgmtReply *reply);
-void mptsas_fix_ioc_init_endianness(MPIMsgIOCInit *req);
-void mptsas_fix_ioc_init_reply_endianness(MPIMsgIOCInitReply *reply);
-void mptsas_fix_ioc_facts_endianness(MPIMsgIOCFacts *req);
-void mptsas_fix_ioc_facts_reply_endianness(MPIMsgIOCFactsReply *reply);
-void mptsas_fix_config_endianness(MPIMsgConfig *req);
-void mptsas_fix_config_reply_endianness(MPIMsgConfigReply *reply);
-void mptsas_fix_port_facts_endianness(MPIMsgPortFacts *req);
-void mptsas_fix_port_facts_reply_endianness(MPIMsgPortFactsReply *reply);
-void mptsas_fix_port_enable_endianness(MPIMsgPortEnable *req);
-void mptsas_fix_port_enable_reply_endianness(MPIMsgPortEnableReply *reply);
-void mptsas_fix_event_notification_endianness(MPIMsgEventNotify *req);
-void mptsas_fix_event_notification_reply_endianness(MPIMsgEventNotifyReply *reply);
-
-void mptsas_reply(MPTSASState *s, MPIDefaultReply *reply);
-
-void mptsas_process_config(MPTSASState *s, MPIMsgConfig *req);
-
-#endif /* MPTSAS_H */
diff --git a/qemu/hw/scsi/scsi-bus.c b/qemu/hw/scsi/scsi-bus.c
deleted file mode 100644
index ad6f398c3..000000000
--- a/qemu/hw/scsi/scsi-bus.c
+++ /dev/null
@@ -1,2062 +0,0 @@
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "qapi/error.h"
-#include "qemu/error-report.h"
-#include "hw/scsi/scsi.h"
-#include "block/scsi.h"
-#include "hw/qdev.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
-#include "trace.h"
-#include "sysemu/dma.h"
-#include "qemu/cutils.h"
-
-static char *scsibus_get_dev_path(DeviceState *dev);
-static char *scsibus_get_fw_dev_path(DeviceState *dev);
-static void scsi_req_dequeue(SCSIRequest *req);
-static uint8_t *scsi_target_alloc_buf(SCSIRequest *req, size_t len);
-static void scsi_target_free_buf(SCSIRequest *req);
-
-static Property scsi_props[] = {
- DEFINE_PROP_UINT32("channel", SCSIDevice, channel, 0),
- DEFINE_PROP_UINT32("scsi-id", SCSIDevice, id, -1),
- DEFINE_PROP_UINT32("lun", SCSIDevice, lun, -1),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void scsi_bus_class_init(ObjectClass *klass, void *data)
-{
- BusClass *k = BUS_CLASS(klass);
- HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
-
- k->get_dev_path = scsibus_get_dev_path;
- k->get_fw_dev_path = scsibus_get_fw_dev_path;
- hc->unplug = qdev_simple_device_unplug_cb;
-}
-
-static const TypeInfo scsi_bus_info = {
- .name = TYPE_SCSI_BUS,
- .parent = TYPE_BUS,
- .instance_size = sizeof(SCSIBus),
- .class_init = scsi_bus_class_init,
- .interfaces = (InterfaceInfo[]) {
- { TYPE_HOTPLUG_HANDLER },
- { }
- }
-};
-static int next_scsi_bus;
-
-static void scsi_device_realize(SCSIDevice *s, Error **errp)
-{
- SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(s);
- if (sc->realize) {
- sc->realize(s, errp);
- }
-}
-
-int scsi_bus_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf,
- void *hba_private)
-{
- SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus);
- int rc;
-
- assert(cmd->len == 0);
- rc = scsi_req_parse_cdb(dev, cmd, buf);
- if (bus->info->parse_cdb) {
- rc = bus->info->parse_cdb(dev, cmd, buf, hba_private);
- }
- return rc;
-}
-
-static SCSIRequest *scsi_device_alloc_req(SCSIDevice *s, uint32_t tag, uint32_t lun,
- uint8_t *buf, void *hba_private)
-{
- SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(s);
- if (sc->alloc_req) {
- return sc->alloc_req(s, tag, lun, buf, hba_private);
- }
-
- return NULL;
-}
-
-void scsi_device_unit_attention_reported(SCSIDevice *s)
-{
- SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(s);
- if (sc->unit_attention_reported) {
- sc->unit_attention_reported(s);
- }
-}
-
-/* Create a scsi bus, and attach devices to it. */
-void scsi_bus_new(SCSIBus *bus, size_t bus_size, DeviceState *host,
- const SCSIBusInfo *info, const char *bus_name)
-{
- qbus_create_inplace(bus, bus_size, TYPE_SCSI_BUS, host, bus_name);
- bus->busnr = next_scsi_bus++;
- bus->info = info;
- qbus_set_bus_hotplug_handler(BUS(bus), &error_abort);
-}
-
-static void scsi_dma_restart_bh(void *opaque)
-{
- SCSIDevice *s = opaque;
- SCSIRequest *req, *next;
-
- qemu_bh_delete(s->bh);
- s->bh = NULL;
-
- QTAILQ_FOREACH_SAFE(req, &s->requests, next, next) {
- scsi_req_ref(req);
- if (req->retry) {
- req->retry = false;
- switch (req->cmd.mode) {
- case SCSI_XFER_FROM_DEV:
- case SCSI_XFER_TO_DEV:
- scsi_req_continue(req);
- break;
- case SCSI_XFER_NONE:
- scsi_req_dequeue(req);
- scsi_req_enqueue(req);
- break;
- }
- }
- scsi_req_unref(req);
- }
-}
-
-void scsi_req_retry(SCSIRequest *req)
-{
- /* No need to save a reference, because scsi_dma_restart_bh just
- * looks at the request list. */
- req->retry = true;
-}
-
-static void scsi_dma_restart_cb(void *opaque, int running, RunState state)
-{
- SCSIDevice *s = opaque;
-
- if (!running) {
- return;
- }
- if (!s->bh) {
- AioContext *ctx = blk_get_aio_context(s->conf.blk);
- s->bh = aio_bh_new(ctx, scsi_dma_restart_bh, s);
- qemu_bh_schedule(s->bh);
- }
-}
-
-static void scsi_qdev_realize(DeviceState *qdev, Error **errp)
-{
- SCSIDevice *dev = SCSI_DEVICE(qdev);
- SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus);
- SCSIDevice *d;
- Error *local_err = NULL;
-
- if (dev->channel > bus->info->max_channel) {
- error_setg(errp, "bad scsi channel id: %d", dev->channel);
- return;
- }
- if (dev->id != -1 && dev->id > bus->info->max_target) {
- error_setg(errp, "bad scsi device id: %d", dev->id);
- return;
- }
- if (dev->lun != -1 && dev->lun > bus->info->max_lun) {
- error_setg(errp, "bad scsi device lun: %d", dev->lun);
- return;
- }
-
- if (dev->id == -1) {
- int id = -1;
- if (dev->lun == -1) {
- dev->lun = 0;
- }
- do {
- d = scsi_device_find(bus, dev->channel, ++id, dev->lun);
- } while (d && d->lun == dev->lun && id < bus->info->max_target);
- if (d && d->lun == dev->lun) {
- error_setg(errp, "no free target");
- return;
- }
- dev->id = id;
- } else if (dev->lun == -1) {
- int lun = -1;
- do {
- d = scsi_device_find(bus, dev->channel, dev->id, ++lun);
- } while (d && d->lun == lun && lun < bus->info->max_lun);
- if (d && d->lun == lun) {
- error_setg(errp, "no free lun");
- return;
- }
- dev->lun = lun;
- } else {
- d = scsi_device_find(bus, dev->channel, dev->id, dev->lun);
- assert(d);
- if (d->lun == dev->lun && dev != d) {
- error_setg(errp, "lun already used by '%s'", d->qdev.id);
- return;
- }
- }
-
- QTAILQ_INIT(&dev->requests);
- scsi_device_realize(dev, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
- dev->vmsentry = qemu_add_vm_change_state_handler(scsi_dma_restart_cb,
- dev);
-}
-
-static void scsi_qdev_unrealize(DeviceState *qdev, Error **errp)
-{
- SCSIDevice *dev = SCSI_DEVICE(qdev);
-
- if (dev->vmsentry) {
- qemu_del_vm_change_state_handler(dev->vmsentry);
- }
-
- scsi_device_purge_requests(dev, SENSE_CODE(NO_SENSE));
- blockdev_mark_auto_del(dev->conf.blk);
-}
-
-/* handle legacy '-drive if=scsi,...' cmd line args */
-SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockBackend *blk,
- int unit, bool removable, int bootindex,
- const char *serial, Error **errp)
-{
- const char *driver;
- char *name;
- DeviceState *dev;
- Error *err = NULL;
-
- driver = blk_is_sg(blk) ? "scsi-generic" : "scsi-disk";
- dev = qdev_create(&bus->qbus, driver);
- name = g_strdup_printf("legacy[%d]", unit);
- object_property_add_child(OBJECT(bus), name, OBJECT(dev), NULL);
- g_free(name);
-
- qdev_prop_set_uint32(dev, "scsi-id", unit);
- if (bootindex >= 0) {
- object_property_set_int(OBJECT(dev), bootindex, "bootindex",
- &error_abort);
- }
- if (object_property_find(OBJECT(dev), "removable", NULL)) {
- qdev_prop_set_bit(dev, "removable", removable);
- }
- if (serial && object_property_find(OBJECT(dev), "serial", NULL)) {
- qdev_prop_set_string(dev, "serial", serial);
- }
- qdev_prop_set_drive(dev, "drive", blk, &err);
- if (err) {
- error_propagate(errp, err);
- object_unparent(OBJECT(dev));
- return NULL;
- }
- object_property_set_bool(OBJECT(dev), true, "realized", &err);
- if (err != NULL) {
- error_propagate(errp, err);
- object_unparent(OBJECT(dev));
- return NULL;
- }
- return SCSI_DEVICE(dev);
-}
-
-void scsi_bus_legacy_handle_cmdline(SCSIBus *bus, Error **errp)
-{
- Location loc;
- DriveInfo *dinfo;
- int unit;
- Error *err = NULL;
-
- loc_push_none(&loc);
- for (unit = 0; unit <= bus->info->max_target; unit++) {
- dinfo = drive_get(IF_SCSI, bus->busnr, unit);
- if (dinfo == NULL) {
- continue;
- }
- qemu_opts_loc_restore(dinfo->opts);
- scsi_bus_legacy_add_drive(bus, blk_by_legacy_dinfo(dinfo),
- unit, false, -1, NULL, &err);
- if (err != NULL) {
- error_propagate(errp, err);
- break;
- }
- }
- loc_pop(&loc);
-}
-
-static int32_t scsi_invalid_field(SCSIRequest *req, uint8_t *buf)
-{
- scsi_req_build_sense(req, SENSE_CODE(INVALID_FIELD));
- scsi_req_complete(req, CHECK_CONDITION);
- return 0;
-}
-
-static const struct SCSIReqOps reqops_invalid_field = {
- .size = sizeof(SCSIRequest),
- .send_command = scsi_invalid_field
-};
-
-/* SCSIReqOps implementation for invalid commands. */
-
-static int32_t scsi_invalid_command(SCSIRequest *req, uint8_t *buf)
-{
- scsi_req_build_sense(req, SENSE_CODE(INVALID_OPCODE));
- scsi_req_complete(req, CHECK_CONDITION);
- return 0;
-}
-
-static const struct SCSIReqOps reqops_invalid_opcode = {
- .size = sizeof(SCSIRequest),
- .send_command = scsi_invalid_command
-};
-
-/* SCSIReqOps implementation for unit attention conditions. */
-
-static int32_t scsi_unit_attention(SCSIRequest *req, uint8_t *buf)
-{
- 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);
- }
- scsi_req_complete(req, CHECK_CONDITION);
- return 0;
-}
-
-static const struct SCSIReqOps reqops_unit_attention = {
- .size = sizeof(SCSIRequest),
- .send_command = scsi_unit_attention
-};
-
-/* SCSIReqOps implementation for REPORT LUNS and for commands sent to
- an invalid LUN. */
-
-typedef struct SCSITargetReq SCSITargetReq;
-
-struct SCSITargetReq {
- SCSIRequest req;
- int len;
- uint8_t *buf;
- int buf_len;
-};
-
-static void store_lun(uint8_t *outbuf, int lun)
-{
- if (lun < 256) {
- outbuf[1] = lun;
- return;
- }
- outbuf[1] = (lun & 255);
- outbuf[0] = (lun >> 8) | 0x40;
-}
-
-static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
-{
- BusChild *kid;
- int i, len, n;
- int channel, id;
- bool found_lun0;
-
- if (r->req.cmd.xfer < 16) {
- return false;
- }
- if (r->req.cmd.buf[2] > 2) {
- return false;
- }
- channel = r->req.dev->channel;
- id = r->req.dev->id;
- found_lun0 = false;
- n = 0;
- QTAILQ_FOREACH(kid, &r->req.bus->qbus.children, sibling) {
- DeviceState *qdev = kid->child;
- SCSIDevice *dev = SCSI_DEVICE(qdev);
-
- if (dev->channel == channel && dev->id == id) {
- if (dev->lun == 0) {
- found_lun0 = true;
- }
- n += 8;
- }
- }
- if (!found_lun0) {
- n += 8;
- }
-
- scsi_target_alloc_buf(&r->req, n + 8);
-
- len = MIN(n + 8, r->req.cmd.xfer & ~7);
- memset(r->buf, 0, len);
- stl_be_p(&r->buf[0], n);
- i = found_lun0 ? 8 : 16;
- QTAILQ_FOREACH(kid, &r->req.bus->qbus.children, sibling) {
- DeviceState *qdev = kid->child;
- SCSIDevice *dev = SCSI_DEVICE(qdev);
-
- if (dev->channel == channel && dev->id == id) {
- store_lun(&r->buf[i], dev->lun);
- i += 8;
- }
- }
- assert(i == n + 8);
- r->len = len;
- return true;
-}
-
-static bool scsi_target_emulate_inquiry(SCSITargetReq *r)
-{
- assert(r->req.dev->lun != r->req.lun);
-
- scsi_target_alloc_buf(&r->req, SCSI_INQUIRY_LEN);
-
- if (r->req.cmd.buf[1] & 0x2) {
- /* Command support data - optional, not implemented */
- return false;
- }
-
- if (r->req.cmd.buf[1] & 0x1) {
- /* Vital product data */
- uint8_t page_code = r->req.cmd.buf[2];
- r->buf[r->len++] = page_code ; /* this page */
- r->buf[r->len++] = 0x00;
-
- switch (page_code) {
- case 0x00: /* Supported page codes, mandatory */
- {
- int pages;
- pages = r->len++;
- r->buf[r->len++] = 0x00; /* list of supported pages (this page) */
- r->buf[pages] = r->len - pages - 1; /* number of pages */
- break;
- }
- default:
- return false;
- }
- /* done with EVPD */
- assert(r->len < r->buf_len);
- r->len = MIN(r->req.cmd.xfer, r->len);
- return true;
- }
-
- /* Standard INQUIRY data */
- if (r->req.cmd.buf[2] != 0) {
- return false;
- }
-
- /* PAGE CODE == 0 */
- r->len = MIN(r->req.cmd.xfer, SCSI_INQUIRY_LEN);
- memset(r->buf, 0, r->len);
- if (r->req.lun != 0) {
- r->buf[0] = TYPE_NO_LUN;
- } else {
- r->buf[0] = TYPE_NOT_PRESENT | TYPE_INACTIVE;
- r->buf[2] = 5; /* Version */
- r->buf[3] = 2 | 0x10; /* HiSup, response data format */
- r->buf[4] = r->len - 5; /* Additional Length = (Len - 1) - 4 */
- r->buf[7] = 0x10 | (r->req.bus->info->tcq ? 0x02 : 0); /* Sync, TCQ. */
- memcpy(&r->buf[8], "QEMU ", 8);
- memcpy(&r->buf[16], "QEMU TARGET ", 16);
- pstrcpy((char *) &r->buf[32], 4, qemu_hw_version());
- }
- return true;
-}
-
-static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf)
-{
- SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req);
-
- switch (buf[0]) {
- case REPORT_LUNS:
- if (!scsi_target_emulate_report_luns(r)) {
- goto illegal_request;
- }
- break;
- case INQUIRY:
- if (!scsi_target_emulate_inquiry(r)) {
- goto illegal_request;
- }
- break;
- case REQUEST_SENSE:
- scsi_target_alloc_buf(&r->req, SCSI_SENSE_LEN);
- r->len = scsi_device_get_sense(r->req.dev, r->buf,
- MIN(req->cmd.xfer, r->buf_len),
- (req->cmd.buf[1] & 1) == 0);
- if (r->req.dev->sense_is_ua) {
- scsi_device_unit_attention_reported(req->dev);
- r->req.dev->sense_len = 0;
- r->req.dev->sense_is_ua = false;
- }
- break;
- case TEST_UNIT_READY:
- break;
- default:
- scsi_req_build_sense(req, SENSE_CODE(LUN_NOT_SUPPORTED));
- scsi_req_complete(req, CHECK_CONDITION);
- return 0;
- illegal_request:
- scsi_req_build_sense(req, SENSE_CODE(INVALID_FIELD));
- scsi_req_complete(req, CHECK_CONDITION);
- return 0;
- }
-
- if (!r->len) {
- scsi_req_complete(req, GOOD);
- }
- return r->len;
-}
-
-static void scsi_target_read_data(SCSIRequest *req)
-{
- SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req);
- uint32_t n;
-
- n = r->len;
- if (n > 0) {
- r->len = 0;
- scsi_req_data(&r->req, n);
- } else {
- scsi_req_complete(&r->req, GOOD);
- }
-}
-
-static uint8_t *scsi_target_get_buf(SCSIRequest *req)
-{
- SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req);
-
- return r->buf;
-}
-
-static uint8_t *scsi_target_alloc_buf(SCSIRequest *req, size_t len)
-{
- SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req);
-
- r->buf = g_malloc(len);
- r->buf_len = len;
-
- return r->buf;
-}
-
-static void scsi_target_free_buf(SCSIRequest *req)
-{
- SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req);
-
- g_free(r->buf);
-}
-
-static const struct SCSIReqOps reqops_target_command = {
- .size = sizeof(SCSITargetReq),
- .send_command = scsi_target_send_command,
- .read_data = scsi_target_read_data,
- .get_buf = scsi_target_get_buf,
- .free_req = scsi_target_free_buf,
-};
-
-
-SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
- uint32_t tag, uint32_t lun, void *hba_private)
-{
- SCSIRequest *req;
- SCSIBus *bus = scsi_bus_from_device(d);
- BusState *qbus = BUS(bus);
- const int memset_off = offsetof(SCSIRequest, sense)
- + sizeof(req->sense);
-
- req = g_malloc(reqops->size);
- memset((uint8_t *)req + memset_off, 0, reqops->size - memset_off);
- req->refcount = 1;
- req->bus = bus;
- req->dev = d;
- req->tag = tag;
- req->lun = lun;
- req->hba_private = hba_private;
- req->status = -1;
- req->ops = reqops;
- object_ref(OBJECT(d));
- object_ref(OBJECT(qbus->parent));
- notifier_list_init(&req->cancel_notifiers);
- trace_scsi_req_alloc(req->dev->id, req->lun, req->tag);
- return req;
-}
-
-SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
- uint8_t *buf, void *hba_private)
-{
- SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, d->qdev.parent_bus);
- const SCSIReqOps *ops;
- SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(d);
- SCSIRequest *req;
- SCSICommand cmd = { .len = 0 };
- int ret;
-
- if ((d->unit_attention.key == UNIT_ATTENTION ||
- bus->unit_attention.key == UNIT_ATTENTION) &&
- (buf[0] != INQUIRY &&
- buf[0] != REPORT_LUNS &&
- buf[0] != GET_CONFIGURATION &&
- buf[0] != GET_EVENT_STATUS_NOTIFICATION &&
-
- /*
- * If we already have a pending unit attention condition,
- * report this one before triggering another one.
- */
- !(buf[0] == REQUEST_SENSE && d->sense_is_ua))) {
- ops = &reqops_unit_attention;
- } else if (lun != d->lun ||
- buf[0] == REPORT_LUNS ||
- (buf[0] == REQUEST_SENSE && d->sense_len)) {
- ops = &reqops_target_command;
- } else {
- ops = NULL;
- }
-
- if (ops != NULL || !sc->parse_cdb) {
- ret = scsi_req_parse_cdb(d, &cmd, buf);
- } else {
- ret = sc->parse_cdb(d, &cmd, buf, hba_private);
- }
-
- if (ret != 0) {
- trace_scsi_req_parse_bad(d->id, lun, tag, buf[0]);
- req = scsi_req_alloc(&reqops_invalid_opcode, d, tag, lun, hba_private);
- } else {
- assert(cmd.len != 0);
- trace_scsi_req_parsed(d->id, lun, tag, buf[0],
- cmd.mode, cmd.xfer);
- if (cmd.lba != -1) {
- trace_scsi_req_parsed_lba(d->id, lun, tag, buf[0],
- cmd.lba);
- }
-
- if (cmd.xfer > INT32_MAX) {
- req = scsi_req_alloc(&reqops_invalid_field, d, tag, lun, hba_private);
- } else if (ops) {
- req = scsi_req_alloc(ops, d, tag, lun, hba_private);
- } else {
- req = scsi_device_alloc_req(d, tag, lun, buf, hba_private);
- }
- }
-
- req->cmd = cmd;
- req->resid = req->cmd.xfer;
-
- switch (buf[0]) {
- case INQUIRY:
- trace_scsi_inquiry(d->id, lun, tag, cmd.buf[1], cmd.buf[2]);
- break;
- case TEST_UNIT_READY:
- trace_scsi_test_unit_ready(d->id, lun, tag);
- break;
- case REPORT_LUNS:
- trace_scsi_report_luns(d->id, lun, tag);
- break;
- case REQUEST_SENSE:
- trace_scsi_request_sense(d->id, lun, tag);
- break;
- default:
- break;
- }
-
- return req;
-}
-
-uint8_t *scsi_req_get_buf(SCSIRequest *req)
-{
- return req->ops->get_buf(req);
-}
-
-static void scsi_clear_unit_attention(SCSIRequest *req)
-{
- SCSISense *ua;
- if (req->dev->unit_attention.key != UNIT_ATTENTION &&
- req->bus->unit_attention.key != UNIT_ATTENTION) {
- return;
- }
-
- /*
- * If an INQUIRY command enters the enabled command state,
- * the device server shall [not] clear any unit attention condition;
- * See also MMC-6, paragraphs 6.5 and 6.6.2.
- */
- if (req->cmd.buf[0] == INQUIRY ||
- req->cmd.buf[0] == GET_CONFIGURATION ||
- req->cmd.buf[0] == GET_EVENT_STATUS_NOTIFICATION) {
- return;
- }
-
- if (req->dev->unit_attention.key == UNIT_ATTENTION) {
- ua = &req->dev->unit_attention;
- } else {
- ua = &req->bus->unit_attention;
- }
-
- /*
- * If a REPORT LUNS command enters the enabled command state, [...]
- * the device server shall clear any pending unit attention condition
- * with an additional sense code of REPORTED LUNS DATA HAS CHANGED.
- */
- if (req->cmd.buf[0] == REPORT_LUNS &&
- !(ua->asc == SENSE_CODE(REPORTED_LUNS_CHANGED).asc &&
- ua->ascq == SENSE_CODE(REPORTED_LUNS_CHANGED).ascq)) {
- return;
- }
-
- *ua = SENSE_CODE(NO_SENSE);
-}
-
-int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len)
-{
- int ret;
-
- assert(len >= 14);
- if (!req->sense_len) {
- return 0;
- }
-
- ret = scsi_build_sense(req->sense, req->sense_len, buf, len, true);
-
- /*
- * FIXME: clearing unit attention conditions upon autosense should be done
- * only if the UA_INTLCK_CTRL field in the Control mode page is set to 00b
- * (SAM-5, 5.14).
- *
- * We assume UA_INTLCK_CTRL to be 00b for HBAs that support autosense, and
- * 10b for HBAs that do not support it (do not call scsi_req_get_sense).
- * Here we handle unit attention clearing for UA_INTLCK_CTRL == 00b.
- */
- if (req->dev->sense_is_ua) {
- scsi_device_unit_attention_reported(req->dev);
- req->dev->sense_len = 0;
- req->dev->sense_is_ua = false;
- }
- return ret;
-}
-
-int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed)
-{
- return scsi_build_sense(dev->sense, dev->sense_len, buf, len, fixed);
-}
-
-void scsi_req_build_sense(SCSIRequest *req, SCSISense sense)
-{
- trace_scsi_req_build_sense(req->dev->id, req->lun, req->tag,
- sense.key, sense.asc, sense.ascq);
- memset(req->sense, 0, 18);
- req->sense[0] = 0x70;
- req->sense[2] = sense.key;
- req->sense[7] = 10;
- req->sense[12] = sense.asc;
- req->sense[13] = sense.ascq;
- req->sense_len = 18;
-}
-
-static void scsi_req_enqueue_internal(SCSIRequest *req)
-{
- assert(!req->enqueued);
- scsi_req_ref(req);
- if (req->bus->info->get_sg_list) {
- req->sg = req->bus->info->get_sg_list(req);
- } else {
- req->sg = NULL;
- }
- req->enqueued = true;
- QTAILQ_INSERT_TAIL(&req->dev->requests, req, next);
-}
-
-int32_t scsi_req_enqueue(SCSIRequest *req)
-{
- int32_t rc;
-
- assert(!req->retry);
- scsi_req_enqueue_internal(req);
- scsi_req_ref(req);
- rc = req->ops->send_command(req, req->cmd.buf);
- scsi_req_unref(req);
- return rc;
-}
-
-static void scsi_req_dequeue(SCSIRequest *req)
-{
- trace_scsi_req_dequeue(req->dev->id, req->lun, req->tag);
- req->retry = false;
- if (req->enqueued) {
- QTAILQ_REMOVE(&req->dev->requests, req, next);
- req->enqueued = false;
- scsi_req_unref(req);
- }
-}
-
-static int scsi_get_performance_length(int num_desc, int type, int data_type)
-{
- /* MMC-6, paragraph 6.7. */
- switch (type) {
- case 0:
- if ((data_type & 3) == 0) {
- /* Each descriptor is as in Table 295 - Nominal performance. */
- return 16 * num_desc + 8;
- } else {
- /* Each descriptor is as in Table 296 - Exceptions. */
- return 6 * num_desc + 8;
- }
- case 1:
- case 4:
- case 5:
- return 8 * num_desc + 8;
- case 2:
- return 2048 * num_desc + 8;
- case 3:
- return 16 * num_desc + 8;
- default:
- return 8;
- }
-}
-
-static int ata_passthrough_xfer_unit(SCSIDevice *dev, uint8_t *buf)
-{
- int byte_block = (buf[2] >> 2) & 0x1;
- int type = (buf[2] >> 4) & 0x1;
- int xfer_unit;
-
- if (byte_block) {
- if (type) {
- xfer_unit = dev->blocksize;
- } else {
- xfer_unit = 512;
- }
- } else {
- xfer_unit = 1;
- }
-
- return xfer_unit;
-}
-
-static int ata_passthrough_12_xfer(SCSIDevice *dev, uint8_t *buf)
-{
- int length = buf[2] & 0x3;
- int xfer;
- int unit = ata_passthrough_xfer_unit(dev, buf);
-
- switch (length) {
- case 0:
- case 3: /* USB-specific. */
- default:
- xfer = 0;
- break;
- case 1:
- xfer = buf[3];
- break;
- case 2:
- xfer = buf[4];
- break;
- }
-
- return xfer * unit;
-}
-
-static int ata_passthrough_16_xfer(SCSIDevice *dev, uint8_t *buf)
-{
- int extend = buf[1] & 0x1;
- int length = buf[2] & 0x3;
- int xfer;
- int unit = ata_passthrough_xfer_unit(dev, buf);
-
- switch (length) {
- case 0:
- case 3: /* USB-specific. */
- default:
- xfer = 0;
- break;
- case 1:
- xfer = buf[4];
- xfer |= (extend ? buf[3] << 8 : 0);
- break;
- case 2:
- xfer = buf[6];
- xfer |= (extend ? buf[5] << 8 : 0);
- break;
- }
-
- return xfer * unit;
-}
-
-uint32_t scsi_data_cdb_xfer(uint8_t *buf)
-{
- if ((buf[0] >> 5) == 0 && buf[4] == 0) {
- return 256;
- } else {
- return scsi_cdb_xfer(buf);
- }
-}
-
-uint32_t scsi_cdb_xfer(uint8_t *buf)
-{
- switch (buf[0] >> 5) {
- case 0:
- return buf[4];
- break;
- case 1:
- case 2:
- return lduw_be_p(&buf[7]);
- break;
- case 4:
- return ldl_be_p(&buf[10]) & 0xffffffffULL;
- break;
- case 5:
- return ldl_be_p(&buf[6]) & 0xffffffffULL;
- break;
- default:
- return -1;
- }
-}
-
-static int scsi_req_xfer(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
-{
- cmd->xfer = scsi_cdb_xfer(buf);
- switch (buf[0]) {
- case TEST_UNIT_READY:
- case REWIND:
- case START_STOP:
- case SET_CAPACITY:
- case WRITE_FILEMARKS:
- case WRITE_FILEMARKS_16:
- case SPACE:
- case RESERVE:
- case RELEASE:
- case ERASE:
- case ALLOW_MEDIUM_REMOVAL:
- case SEEK_10:
- case SYNCHRONIZE_CACHE:
- case SYNCHRONIZE_CACHE_16:
- case LOCATE_16:
- case LOCK_UNLOCK_CACHE:
- case SET_CD_SPEED:
- case SET_LIMITS:
- case WRITE_LONG_10:
- case UPDATE_BLOCK:
- case RESERVE_TRACK:
- case SET_READ_AHEAD:
- case PRE_FETCH:
- case PRE_FETCH_16:
- case ALLOW_OVERWRITE:
- cmd->xfer = 0;
- break;
- case VERIFY_10:
- case VERIFY_12:
- case VERIFY_16:
- if ((buf[1] & 2) == 0) {
- cmd->xfer = 0;
- } else if ((buf[1] & 4) != 0) {
- cmd->xfer = 1;
- }
- cmd->xfer *= dev->blocksize;
- break;
- case MODE_SENSE:
- break;
- case WRITE_SAME_10:
- case WRITE_SAME_16:
- cmd->xfer = dev->blocksize;
- break;
- case READ_CAPACITY_10:
- cmd->xfer = 8;
- break;
- case READ_BLOCK_LIMITS:
- cmd->xfer = 6;
- break;
- case SEND_VOLUME_TAG:
- /* GPCMD_SET_STREAMING from multimedia commands. */
- if (dev->type == TYPE_ROM) {
- cmd->xfer = buf[10] | (buf[9] << 8);
- } else {
- cmd->xfer = buf[9] | (buf[8] << 8);
- }
- break;
- case WRITE_6:
- /* length 0 means 256 blocks */
- if (cmd->xfer == 0) {
- cmd->xfer = 256;
- }
- /* fall through */
- case WRITE_10:
- case WRITE_VERIFY_10:
- case WRITE_12:
- case WRITE_VERIFY_12:
- case WRITE_16:
- case WRITE_VERIFY_16:
- cmd->xfer *= dev->blocksize;
- break;
- case READ_6:
- case READ_REVERSE:
- /* length 0 means 256 blocks */
- if (cmd->xfer == 0) {
- cmd->xfer = 256;
- }
- /* fall through */
- case READ_10:
- case READ_12:
- case READ_16:
- cmd->xfer *= dev->blocksize;
- break;
- case FORMAT_UNIT:
- /* MMC mandates the parameter list to be 12-bytes long. Parameters
- * for block devices are restricted to the header right now. */
- if (dev->type == TYPE_ROM && (buf[1] & 16)) {
- cmd->xfer = 12;
- } else {
- cmd->xfer = (buf[1] & 16) == 0 ? 0 : (buf[1] & 32 ? 8 : 4);
- }
- break;
- case INQUIRY:
- case RECEIVE_DIAGNOSTIC:
- case SEND_DIAGNOSTIC:
- cmd->xfer = buf[4] | (buf[3] << 8);
- break;
- case READ_CD:
- case READ_BUFFER:
- case WRITE_BUFFER:
- case SEND_CUE_SHEET:
- cmd->xfer = buf[8] | (buf[7] << 8) | (buf[6] << 16);
- break;
- case PERSISTENT_RESERVE_OUT:
- cmd->xfer = ldl_be_p(&buf[5]) & 0xffffffffULL;
- break;
- case ERASE_12:
- if (dev->type == TYPE_ROM) {
- /* MMC command GET PERFORMANCE. */
- cmd->xfer = scsi_get_performance_length(buf[9] | (buf[8] << 8),
- buf[10], buf[1] & 0x1f);
- }
- break;
- case MECHANISM_STATUS:
- case READ_DVD_STRUCTURE:
- case SEND_DVD_STRUCTURE:
- case MAINTENANCE_OUT:
- case MAINTENANCE_IN:
- if (dev->type == TYPE_ROM) {
- /* GPCMD_REPORT_KEY and GPCMD_SEND_KEY from multi media commands */
- cmd->xfer = buf[9] | (buf[8] << 8);
- }
- break;
- case ATA_PASSTHROUGH_12:
- if (dev->type == TYPE_ROM) {
- /* BLANK command of MMC */
- cmd->xfer = 0;
- } else {
- cmd->xfer = ata_passthrough_12_xfer(dev, buf);
- }
- break;
- case ATA_PASSTHROUGH_16:
- cmd->xfer = ata_passthrough_16_xfer(dev, buf);
- break;
- }
- return 0;
-}
-
-static int scsi_req_stream_xfer(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
-{
- switch (buf[0]) {
- /* stream commands */
- case ERASE_12:
- case ERASE_16:
- cmd->xfer = 0;
- break;
- case READ_6:
- case READ_REVERSE:
- case RECOVER_BUFFERED_DATA:
- case WRITE_6:
- cmd->xfer = buf[4] | (buf[3] << 8) | (buf[2] << 16);
- if (buf[1] & 0x01) { /* fixed */
- cmd->xfer *= dev->blocksize;
- }
- break;
- case READ_16:
- case READ_REVERSE_16:
- case VERIFY_16:
- case WRITE_16:
- cmd->xfer = buf[14] | (buf[13] << 8) | (buf[12] << 16);
- if (buf[1] & 0x01) { /* fixed */
- cmd->xfer *= dev->blocksize;
- }
- break;
- case REWIND:
- case LOAD_UNLOAD:
- cmd->xfer = 0;
- break;
- case SPACE_16:
- cmd->xfer = buf[13] | (buf[12] << 8);
- break;
- case READ_POSITION:
- switch (buf[1] & 0x1f) /* operation code */ {
- case SHORT_FORM_BLOCK_ID:
- case SHORT_FORM_VENDOR_SPECIFIC:
- cmd->xfer = 20;
- break;
- case LONG_FORM:
- cmd->xfer = 32;
- break;
- case EXTENDED_FORM:
- cmd->xfer = buf[8] | (buf[7] << 8);
- break;
- default:
- return -1;
- }
-
- break;
- case FORMAT_UNIT:
- cmd->xfer = buf[4] | (buf[3] << 8);
- break;
- /* generic commands */
- default:
- return scsi_req_xfer(cmd, dev, buf);
- }
- return 0;
-}
-
-static int scsi_req_medium_changer_xfer(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
-{
- switch (buf[0]) {
- /* medium changer commands */
- case EXCHANGE_MEDIUM:
- case INITIALIZE_ELEMENT_STATUS:
- case INITIALIZE_ELEMENT_STATUS_WITH_RANGE:
- case MOVE_MEDIUM:
- case POSITION_TO_ELEMENT:
- cmd->xfer = 0;
- break;
- case READ_ELEMENT_STATUS:
- cmd->xfer = buf[9] | (buf[8] << 8) | (buf[7] << 16);
- break;
-
- /* generic commands */
- default:
- return scsi_req_xfer(cmd, dev, buf);
- }
- return 0;
-}
-
-
-static void scsi_cmd_xfer_mode(SCSICommand *cmd)
-{
- if (!cmd->xfer) {
- cmd->mode = SCSI_XFER_NONE;
- return;
- }
- switch (cmd->buf[0]) {
- case WRITE_6:
- case WRITE_10:
- case WRITE_VERIFY_10:
- case WRITE_12:
- case WRITE_VERIFY_12:
- case WRITE_16:
- case WRITE_VERIFY_16:
- case VERIFY_10:
- case VERIFY_12:
- case VERIFY_16:
- case COPY:
- case COPY_VERIFY:
- case COMPARE:
- case CHANGE_DEFINITION:
- case LOG_SELECT:
- case MODE_SELECT:
- case MODE_SELECT_10:
- case SEND_DIAGNOSTIC:
- case WRITE_BUFFER:
- case FORMAT_UNIT:
- case REASSIGN_BLOCKS:
- case SEARCH_EQUAL:
- case SEARCH_HIGH:
- case SEARCH_LOW:
- case UPDATE_BLOCK:
- case WRITE_LONG_10:
- case WRITE_SAME_10:
- case WRITE_SAME_16:
- case UNMAP:
- case SEARCH_HIGH_12:
- case SEARCH_EQUAL_12:
- case SEARCH_LOW_12:
- case MEDIUM_SCAN:
- case SEND_VOLUME_TAG:
- case SEND_CUE_SHEET:
- case SEND_DVD_STRUCTURE:
- case PERSISTENT_RESERVE_OUT:
- case MAINTENANCE_OUT:
- cmd->mode = SCSI_XFER_TO_DEV;
- break;
- case ATA_PASSTHROUGH_12:
- case ATA_PASSTHROUGH_16:
- /* T_DIR */
- cmd->mode = (cmd->buf[2] & 0x8) ?
- SCSI_XFER_FROM_DEV : SCSI_XFER_TO_DEV;
- break;
- default:
- cmd->mode = SCSI_XFER_FROM_DEV;
- break;
- }
-}
-
-static uint64_t scsi_cmd_lba(SCSICommand *cmd)
-{
- uint8_t *buf = cmd->buf;
- uint64_t lba;
-
- switch (buf[0] >> 5) {
- case 0:
- lba = ldl_be_p(&buf[0]) & 0x1fffff;
- break;
- case 1:
- case 2:
- case 5:
- lba = ldl_be_p(&buf[2]) & 0xffffffffULL;
- break;
- case 4:
- lba = ldq_be_p(&buf[2]);
- break;
- default:
- lba = -1;
-
- }
- return lba;
-}
-
-int scsi_cdb_length(uint8_t *buf) {
- int cdb_len;
-
- switch (buf[0] >> 5) {
- case 0:
- cdb_len = 6;
- break;
- case 1:
- case 2:
- cdb_len = 10;
- break;
- case 4:
- cdb_len = 16;
- break;
- case 5:
- cdb_len = 12;
- break;
- default:
- cdb_len = -1;
- }
- return cdb_len;
-}
-
-int scsi_req_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf)
-{
- int rc;
- int len;
-
- cmd->lba = -1;
- len = scsi_cdb_length(buf);
- if (len < 0) {
- return -1;
- }
-
- cmd->len = len;
- switch (dev->type) {
- case TYPE_TAPE:
- rc = scsi_req_stream_xfer(cmd, dev, buf);
- break;
- case TYPE_MEDIUM_CHANGER:
- rc = scsi_req_medium_changer_xfer(cmd, dev, buf);
- break;
- default:
- rc = scsi_req_xfer(cmd, dev, buf);
- break;
- }
-
- if (rc != 0)
- return rc;
-
- memcpy(cmd->buf, buf, cmd->len);
- scsi_cmd_xfer_mode(cmd);
- cmd->lba = scsi_cmd_lba(cmd);
- return 0;
-}
-
-void scsi_device_report_change(SCSIDevice *dev, SCSISense sense)
-{
- SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus);
-
- scsi_device_set_ua(dev, sense);
- if (bus->info->change) {
- bus->info->change(bus, dev, sense);
- }
-}
-
-/*
- * Predefined sense codes
- */
-
-/* No sense data available */
-const struct SCSISense sense_code_NO_SENSE = {
- .key = NO_SENSE , .asc = 0x00 , .ascq = 0x00
-};
-
-/* LUN not ready, Manual intervention required */
-const struct SCSISense sense_code_LUN_NOT_READY = {
- .key = NOT_READY, .asc = 0x04, .ascq = 0x03
-};
-
-/* LUN not ready, Medium not present */
-const struct SCSISense sense_code_NO_MEDIUM = {
- .key = NOT_READY, .asc = 0x3a, .ascq = 0x00
-};
-
-/* LUN not ready, medium removal prevented */
-const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED = {
- .key = NOT_READY, .asc = 0x53, .ascq = 0x02
-};
-
-/* Hardware error, internal target failure */
-const struct SCSISense sense_code_TARGET_FAILURE = {
- .key = HARDWARE_ERROR, .asc = 0x44, .ascq = 0x00
-};
-
-/* Illegal request, invalid command operation code */
-const struct SCSISense sense_code_INVALID_OPCODE = {
- .key = ILLEGAL_REQUEST, .asc = 0x20, .ascq = 0x00
-};
-
-/* Illegal request, LBA out of range */
-const struct SCSISense sense_code_LBA_OUT_OF_RANGE = {
- .key = ILLEGAL_REQUEST, .asc = 0x21, .ascq = 0x00
-};
-
-/* Illegal request, Invalid field in CDB */
-const struct SCSISense sense_code_INVALID_FIELD = {
- .key = ILLEGAL_REQUEST, .asc = 0x24, .ascq = 0x00
-};
-
-/* Illegal request, Invalid field in parameter list */
-const struct SCSISense sense_code_INVALID_PARAM = {
- .key = ILLEGAL_REQUEST, .asc = 0x26, .ascq = 0x00
-};
-
-/* Illegal request, Parameter list length error */
-const struct SCSISense sense_code_INVALID_PARAM_LEN = {
- .key = ILLEGAL_REQUEST, .asc = 0x1a, .ascq = 0x00
-};
-
-/* Illegal request, LUN not supported */
-const struct SCSISense sense_code_LUN_NOT_SUPPORTED = {
- .key = ILLEGAL_REQUEST, .asc = 0x25, .ascq = 0x00
-};
-
-/* Illegal request, Saving parameters not supported */
-const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED = {
- .key = ILLEGAL_REQUEST, .asc = 0x39, .ascq = 0x00
-};
-
-/* Illegal request, Incompatible medium installed */
-const struct SCSISense sense_code_INCOMPATIBLE_FORMAT = {
- .key = ILLEGAL_REQUEST, .asc = 0x30, .ascq = 0x00
-};
-
-/* Illegal request, medium removal prevented */
-const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED = {
- .key = ILLEGAL_REQUEST, .asc = 0x53, .ascq = 0x02
-};
-
-/* Illegal request, Invalid Transfer Tag */
-const struct SCSISense sense_code_INVALID_TAG = {
- .key = ILLEGAL_REQUEST, .asc = 0x4b, .ascq = 0x01
-};
-
-/* Command aborted, I/O process terminated */
-const struct SCSISense sense_code_IO_ERROR = {
- .key = ABORTED_COMMAND, .asc = 0x00, .ascq = 0x06
-};
-
-/* Command aborted, I_T Nexus loss occurred */
-const struct SCSISense sense_code_I_T_NEXUS_LOSS = {
- .key = ABORTED_COMMAND, .asc = 0x29, .ascq = 0x07
-};
-
-/* Command aborted, Logical Unit failure */
-const struct SCSISense sense_code_LUN_FAILURE = {
- .key = ABORTED_COMMAND, .asc = 0x3e, .ascq = 0x01
-};
-
-/* Command aborted, Overlapped Commands Attempted */
-const struct SCSISense sense_code_OVERLAPPED_COMMANDS = {
- .key = ABORTED_COMMAND, .asc = 0x4e, .ascq = 0x00
-};
-
-/* Unit attention, Capacity data has changed */
-const struct SCSISense sense_code_CAPACITY_CHANGED = {
- .key = UNIT_ATTENTION, .asc = 0x2a, .ascq = 0x09
-};
-
-/* Unit attention, Power on, reset or bus device reset occurred */
-const struct SCSISense sense_code_RESET = {
- .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x00
-};
-
-/* Unit attention, No medium */
-const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM = {
- .key = UNIT_ATTENTION, .asc = 0x3a, .ascq = 0x00
-};
-
-/* Unit attention, Medium may have changed */
-const struct SCSISense sense_code_MEDIUM_CHANGED = {
- .key = UNIT_ATTENTION, .asc = 0x28, .ascq = 0x00
-};
-
-/* Unit attention, Reported LUNs data has changed */
-const struct SCSISense sense_code_REPORTED_LUNS_CHANGED = {
- .key = UNIT_ATTENTION, .asc = 0x3f, .ascq = 0x0e
-};
-
-/* Unit attention, Device internal reset */
-const struct SCSISense sense_code_DEVICE_INTERNAL_RESET = {
- .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x04
-};
-
-/* Data Protection, Write Protected */
-const struct SCSISense sense_code_WRITE_PROTECTED = {
- .key = DATA_PROTECT, .asc = 0x27, .ascq = 0x00
-};
-
-/* Data Protection, Space Allocation Failed Write Protect */
-const struct SCSISense sense_code_SPACE_ALLOC_FAILED = {
- .key = DATA_PROTECT, .asc = 0x27, .ascq = 0x07
-};
-
-/*
- * scsi_build_sense
- *
- * Convert between fixed and descriptor sense buffers
- */
-int scsi_build_sense(uint8_t *in_buf, int in_len,
- uint8_t *buf, int len, bool fixed)
-{
- bool fixed_in;
- SCSISense sense;
- if (!fixed && len < 8) {
- return 0;
- }
-
- if (in_len == 0) {
- sense.key = NO_SENSE;
- sense.asc = 0;
- sense.ascq = 0;
- } else {
- fixed_in = (in_buf[0] & 2) == 0;
-
- if (fixed == fixed_in) {
- memcpy(buf, in_buf, MIN(len, in_len));
- return MIN(len, in_len);
- }
-
- if (fixed_in) {
- sense.key = in_buf[2];
- sense.asc = in_buf[12];
- sense.ascq = in_buf[13];
- } else {
- sense.key = in_buf[1];
- sense.asc = in_buf[2];
- sense.ascq = in_buf[3];
- }
- }
-
- memset(buf, 0, len);
- if (fixed) {
- /* Return fixed format sense buffer */
- buf[0] = 0x70;
- buf[2] = sense.key;
- buf[7] = 10;
- buf[12] = sense.asc;
- buf[13] = sense.ascq;
- return MIN(len, SCSI_SENSE_LEN);
- } else {
- /* Return descriptor format sense buffer */
- buf[0] = 0x72;
- buf[1] = sense.key;
- buf[2] = sense.asc;
- buf[3] = sense.ascq;
- return 8;
- }
-}
-
-const char *scsi_command_name(uint8_t cmd)
-{
- static const char *names[] = {
- [ TEST_UNIT_READY ] = "TEST_UNIT_READY",
- [ REWIND ] = "REWIND",
- [ REQUEST_SENSE ] = "REQUEST_SENSE",
- [ FORMAT_UNIT ] = "FORMAT_UNIT",
- [ READ_BLOCK_LIMITS ] = "READ_BLOCK_LIMITS",
- [ REASSIGN_BLOCKS ] = "REASSIGN_BLOCKS/INITIALIZE ELEMENT STATUS",
- /* LOAD_UNLOAD and INITIALIZE_ELEMENT_STATUS use the same operation code */
- [ READ_6 ] = "READ_6",
- [ WRITE_6 ] = "WRITE_6",
- [ SET_CAPACITY ] = "SET_CAPACITY",
- [ READ_REVERSE ] = "READ_REVERSE",
- [ WRITE_FILEMARKS ] = "WRITE_FILEMARKS",
- [ SPACE ] = "SPACE",
- [ INQUIRY ] = "INQUIRY",
- [ RECOVER_BUFFERED_DATA ] = "RECOVER_BUFFERED_DATA",
- [ MAINTENANCE_IN ] = "MAINTENANCE_IN",
- [ MAINTENANCE_OUT ] = "MAINTENANCE_OUT",
- [ MODE_SELECT ] = "MODE_SELECT",
- [ RESERVE ] = "RESERVE",
- [ RELEASE ] = "RELEASE",
- [ COPY ] = "COPY",
- [ ERASE ] = "ERASE",
- [ MODE_SENSE ] = "MODE_SENSE",
- [ START_STOP ] = "START_STOP/LOAD_UNLOAD",
- /* LOAD_UNLOAD and START_STOP use the same operation code */
- [ RECEIVE_DIAGNOSTIC ] = "RECEIVE_DIAGNOSTIC",
- [ SEND_DIAGNOSTIC ] = "SEND_DIAGNOSTIC",
- [ ALLOW_MEDIUM_REMOVAL ] = "ALLOW_MEDIUM_REMOVAL",
- [ READ_CAPACITY_10 ] = "READ_CAPACITY_10",
- [ READ_10 ] = "READ_10",
- [ WRITE_10 ] = "WRITE_10",
- [ SEEK_10 ] = "SEEK_10/POSITION_TO_ELEMENT",
- /* SEEK_10 and POSITION_TO_ELEMENT use the same operation code */
- [ WRITE_VERIFY_10 ] = "WRITE_VERIFY_10",
- [ VERIFY_10 ] = "VERIFY_10",
- [ SEARCH_HIGH ] = "SEARCH_HIGH",
- [ SEARCH_EQUAL ] = "SEARCH_EQUAL",
- [ SEARCH_LOW ] = "SEARCH_LOW",
- [ SET_LIMITS ] = "SET_LIMITS",
- [ PRE_FETCH ] = "PRE_FETCH/READ_POSITION",
- /* READ_POSITION and PRE_FETCH use the same operation code */
- [ SYNCHRONIZE_CACHE ] = "SYNCHRONIZE_CACHE",
- [ LOCK_UNLOCK_CACHE ] = "LOCK_UNLOCK_CACHE",
- [ READ_DEFECT_DATA ] = "READ_DEFECT_DATA/INITIALIZE_ELEMENT_STATUS_WITH_RANGE",
- /* READ_DEFECT_DATA and INITIALIZE_ELEMENT_STATUS_WITH_RANGE use the same operation code */
- [ MEDIUM_SCAN ] = "MEDIUM_SCAN",
- [ COMPARE ] = "COMPARE",
- [ COPY_VERIFY ] = "COPY_VERIFY",
- [ WRITE_BUFFER ] = "WRITE_BUFFER",
- [ READ_BUFFER ] = "READ_BUFFER",
- [ UPDATE_BLOCK ] = "UPDATE_BLOCK",
- [ READ_LONG_10 ] = "READ_LONG_10",
- [ WRITE_LONG_10 ] = "WRITE_LONG_10",
- [ CHANGE_DEFINITION ] = "CHANGE_DEFINITION",
- [ WRITE_SAME_10 ] = "WRITE_SAME_10",
- [ UNMAP ] = "UNMAP",
- [ READ_TOC ] = "READ_TOC",
- [ REPORT_DENSITY_SUPPORT ] = "REPORT_DENSITY_SUPPORT",
- [ SANITIZE ] = "SANITIZE",
- [ GET_CONFIGURATION ] = "GET_CONFIGURATION",
- [ LOG_SELECT ] = "LOG_SELECT",
- [ LOG_SENSE ] = "LOG_SENSE",
- [ MODE_SELECT_10 ] = "MODE_SELECT_10",
- [ RESERVE_10 ] = "RESERVE_10",
- [ RELEASE_10 ] = "RELEASE_10",
- [ MODE_SENSE_10 ] = "MODE_SENSE_10",
- [ PERSISTENT_RESERVE_IN ] = "PERSISTENT_RESERVE_IN",
- [ PERSISTENT_RESERVE_OUT ] = "PERSISTENT_RESERVE_OUT",
- [ WRITE_FILEMARKS_16 ] = "WRITE_FILEMARKS_16",
- [ EXTENDED_COPY ] = "EXTENDED_COPY",
- [ ATA_PASSTHROUGH_16 ] = "ATA_PASSTHROUGH_16",
- [ ACCESS_CONTROL_IN ] = "ACCESS_CONTROL_IN",
- [ ACCESS_CONTROL_OUT ] = "ACCESS_CONTROL_OUT",
- [ READ_16 ] = "READ_16",
- [ COMPARE_AND_WRITE ] = "COMPARE_AND_WRITE",
- [ WRITE_16 ] = "WRITE_16",
- [ WRITE_VERIFY_16 ] = "WRITE_VERIFY_16",
- [ VERIFY_16 ] = "VERIFY_16",
- [ PRE_FETCH_16 ] = "PRE_FETCH_16",
- [ SYNCHRONIZE_CACHE_16 ] = "SPACE_16/SYNCHRONIZE_CACHE_16",
- /* SPACE_16 and SYNCHRONIZE_CACHE_16 use the same operation code */
- [ LOCATE_16 ] = "LOCATE_16",
- [ WRITE_SAME_16 ] = "ERASE_16/WRITE_SAME_16",
- /* ERASE_16 and WRITE_SAME_16 use the same operation code */
- [ SERVICE_ACTION_IN_16 ] = "SERVICE_ACTION_IN_16",
- [ WRITE_LONG_16 ] = "WRITE_LONG_16",
- [ REPORT_LUNS ] = "REPORT_LUNS",
- [ ATA_PASSTHROUGH_12 ] = "BLANK/ATA_PASSTHROUGH_12",
- [ MOVE_MEDIUM ] = "MOVE_MEDIUM",
- [ EXCHANGE_MEDIUM ] = "EXCHANGE MEDIUM",
- [ READ_12 ] = "READ_12",
- [ WRITE_12 ] = "WRITE_12",
- [ ERASE_12 ] = "ERASE_12/GET_PERFORMANCE",
- /* ERASE_12 and GET_PERFORMANCE use the same operation code */
- [ SERVICE_ACTION_IN_12 ] = "SERVICE_ACTION_IN_12",
- [ WRITE_VERIFY_12 ] = "WRITE_VERIFY_12",
- [ VERIFY_12 ] = "VERIFY_12",
- [ SEARCH_HIGH_12 ] = "SEARCH_HIGH_12",
- [ SEARCH_EQUAL_12 ] = "SEARCH_EQUAL_12",
- [ SEARCH_LOW_12 ] = "SEARCH_LOW_12",
- [ READ_ELEMENT_STATUS ] = "READ_ELEMENT_STATUS",
- [ SEND_VOLUME_TAG ] = "SEND_VOLUME_TAG/SET_STREAMING",
- /* SEND_VOLUME_TAG and SET_STREAMING use the same operation code */
- [ READ_CD ] = "READ_CD",
- [ READ_DEFECT_DATA_12 ] = "READ_DEFECT_DATA_12",
- [ READ_DVD_STRUCTURE ] = "READ_DVD_STRUCTURE",
- [ RESERVE_TRACK ] = "RESERVE_TRACK",
- [ SEND_CUE_SHEET ] = "SEND_CUE_SHEET",
- [ SEND_DVD_STRUCTURE ] = "SEND_DVD_STRUCTURE",
- [ SET_CD_SPEED ] = "SET_CD_SPEED",
- [ SET_READ_AHEAD ] = "SET_READ_AHEAD",
- [ ALLOW_OVERWRITE ] = "ALLOW_OVERWRITE",
- [ MECHANISM_STATUS ] = "MECHANISM_STATUS",
- [ GET_EVENT_STATUS_NOTIFICATION ] = "GET_EVENT_STATUS_NOTIFICATION",
- [ READ_DISC_INFORMATION ] = "READ_DISC_INFORMATION",
- };
-
- if (cmd >= ARRAY_SIZE(names) || names[cmd] == NULL)
- return "*UNKNOWN*";
- return names[cmd];
-}
-
-SCSIRequest *scsi_req_ref(SCSIRequest *req)
-{
- assert(req->refcount > 0);
- req->refcount++;
- return req;
-}
-
-void scsi_req_unref(SCSIRequest *req)
-{
- assert(req->refcount > 0);
- if (--req->refcount == 0) {
- BusState *qbus = req->dev->qdev.parent_bus;
- SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, qbus);
-
- if (bus->info->free_request && req->hba_private) {
- bus->info->free_request(bus, req->hba_private);
- }
- if (req->ops->free_req) {
- req->ops->free_req(req);
- }
- object_unref(OBJECT(req->dev));
- object_unref(OBJECT(qbus->parent));
- g_free(req);
- }
-}
-
-/* Tell the device that we finished processing this chunk of I/O. It
- will start the next chunk or complete the command. */
-void scsi_req_continue(SCSIRequest *req)
-{
- if (req->io_canceled) {
- trace_scsi_req_continue_canceled(req->dev->id, req->lun, req->tag);
- return;
- }
- trace_scsi_req_continue(req->dev->id, req->lun, req->tag);
- if (req->cmd.mode == SCSI_XFER_TO_DEV) {
- req->ops->write_data(req);
- } else {
- req->ops->read_data(req);
- }
-}
-
-/* Called by the devices when data is ready for the HBA. The HBA should
- start a DMA operation to read or fill the device's data buffer.
- Once it completes, calling scsi_req_continue will restart I/O. */
-void scsi_req_data(SCSIRequest *req, int len)
-{
- uint8_t *buf;
- if (req->io_canceled) {
- trace_scsi_req_data_canceled(req->dev->id, req->lun, req->tag, len);
- return;
- }
- trace_scsi_req_data(req->dev->id, req->lun, req->tag, len);
- assert(req->cmd.mode != SCSI_XFER_NONE);
- if (!req->sg) {
- req->resid -= len;
- req->bus->info->transfer_data(req, len);
- return;
- }
-
- /* If the device calls scsi_req_data and the HBA specified a
- * scatter/gather list, the transfer has to happen in a single
- * step. */
- assert(!req->dma_started);
- req->dma_started = true;
-
- buf = scsi_req_get_buf(req);
- if (req->cmd.mode == SCSI_XFER_FROM_DEV) {
- req->resid = dma_buf_read(buf, len, req->sg);
- } else {
- req->resid = dma_buf_write(buf, len, req->sg);
- }
- scsi_req_continue(req);
-}
-
-void scsi_req_print(SCSIRequest *req)
-{
- FILE *fp = stderr;
- int i;
-
- fprintf(fp, "[%s id=%d] %s",
- req->dev->qdev.parent_bus->name,
- req->dev->id,
- scsi_command_name(req->cmd.buf[0]));
- for (i = 1; i < req->cmd.len; i++) {
- fprintf(fp, " 0x%02x", req->cmd.buf[i]);
- }
- switch (req->cmd.mode) {
- case SCSI_XFER_NONE:
- fprintf(fp, " - none\n");
- break;
- case SCSI_XFER_FROM_DEV:
- fprintf(fp, " - from-dev len=%zd\n", req->cmd.xfer);
- break;
- case SCSI_XFER_TO_DEV:
- fprintf(fp, " - to-dev len=%zd\n", req->cmd.xfer);
- break;
- default:
- fprintf(fp, " - Oops\n");
- break;
- }
-}
-
-void scsi_req_complete(SCSIRequest *req, int status)
-{
- assert(req->status == -1);
- req->status = status;
-
- assert(req->sense_len <= sizeof(req->sense));
- if (status == GOOD) {
- req->sense_len = 0;
- }
-
- if (req->sense_len) {
- memcpy(req->dev->sense, req->sense, req->sense_len);
- req->dev->sense_len = req->sense_len;
- req->dev->sense_is_ua = (req->ops == &reqops_unit_attention);
- } else {
- req->dev->sense_len = 0;
- req->dev->sense_is_ua = false;
- }
-
- /*
- * Unit attention state is now stored in the device's sense buffer
- * if the HBA didn't do autosense. Clear the pending unit attention
- * flags.
- */
- scsi_clear_unit_attention(req);
-
- scsi_req_ref(req);
- scsi_req_dequeue(req);
- req->bus->info->complete(req, req->status, req->resid);
-
- /* Cancelled requests might end up being completed instead of cancelled */
- notifier_list_notify(&req->cancel_notifiers, req);
- scsi_req_unref(req);
-}
-
-/* Called by the devices when the request is canceled. */
-void scsi_req_cancel_complete(SCSIRequest *req)
-{
- assert(req->io_canceled);
- if (req->bus->info->cancel) {
- req->bus->info->cancel(req);
- }
- notifier_list_notify(&req->cancel_notifiers, req);
- scsi_req_unref(req);
-}
-
-/* Cancel @req asynchronously. @notifier is added to @req's cancellation
- * notifier list, the bus will be notified the requests cancellation is
- * completed.
- * */
-void scsi_req_cancel_async(SCSIRequest *req, Notifier *notifier)
-{
- trace_scsi_req_cancel(req->dev->id, req->lun, req->tag);
- if (notifier) {
- notifier_list_add(&req->cancel_notifiers, notifier);
- }
- if (req->io_canceled) {
- /* A blk_aio_cancel_async is pending; when it finishes,
- * scsi_req_cancel_complete will be called and will
- * call the notifier we just added. Just wait for that.
- */
- assert(req->aiocb);
- return;
- }
- /* Dropped in scsi_req_cancel_complete. */
- scsi_req_ref(req);
- scsi_req_dequeue(req);
- req->io_canceled = true;
- if (req->aiocb) {
- blk_aio_cancel_async(req->aiocb);
- } else {
- scsi_req_cancel_complete(req);
- }
-}
-
-void scsi_req_cancel(SCSIRequest *req)
-{
- trace_scsi_req_cancel(req->dev->id, req->lun, req->tag);
- if (!req->enqueued) {
- return;
- }
- assert(!req->io_canceled);
- /* Dropped in scsi_req_cancel_complete. */
- scsi_req_ref(req);
- scsi_req_dequeue(req);
- req->io_canceled = true;
- if (req->aiocb) {
- blk_aio_cancel(req->aiocb);
- } else {
- scsi_req_cancel_complete(req);
- }
-}
-
-static int scsi_ua_precedence(SCSISense sense)
-{
- if (sense.key != UNIT_ATTENTION) {
- return INT_MAX;
- }
- if (sense.asc == 0x29 && sense.ascq == 0x04) {
- /* DEVICE INTERNAL RESET goes with POWER ON OCCURRED */
- return 1;
- } else if (sense.asc == 0x3F && sense.ascq == 0x01) {
- /* MICROCODE HAS BEEN CHANGED goes with SCSI BUS RESET OCCURRED */
- return 2;
- } else if (sense.asc == 0x29 && (sense.ascq == 0x05 || sense.ascq == 0x06)) {
- /* These two go with "all others". */
- ;
- } else if (sense.asc == 0x29 && sense.ascq <= 0x07) {
- /* POWER ON, RESET OR BUS DEVICE RESET OCCURRED = 0
- * POWER ON OCCURRED = 1
- * SCSI BUS RESET OCCURRED = 2
- * BUS DEVICE RESET FUNCTION OCCURRED = 3
- * I_T NEXUS LOSS OCCURRED = 7
- */
- return sense.ascq;
- } else if (sense.asc == 0x2F && sense.ascq == 0x01) {
- /* COMMANDS CLEARED BY POWER LOSS NOTIFICATION */
- return 8;
- }
- return (sense.asc << 8) | sense.ascq;
-}
-
-void scsi_device_set_ua(SCSIDevice *sdev, SCSISense sense)
-{
- int prec1, prec2;
- if (sense.key != UNIT_ATTENTION) {
- return;
- }
- trace_scsi_device_set_ua(sdev->id, sdev->lun, sense.key,
- sense.asc, sense.ascq);
-
- /*
- * Override a pre-existing unit attention condition, except for a more
- * important reset condition.
- */
- prec1 = scsi_ua_precedence(sdev->unit_attention);
- prec2 = scsi_ua_precedence(sense);
- if (prec2 < prec1) {
- sdev->unit_attention = sense;
- }
-}
-
-void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense)
-{
- SCSIRequest *req;
-
- aio_context_acquire(blk_get_aio_context(sdev->conf.blk));
- while (!QTAILQ_EMPTY(&sdev->requests)) {
- req = QTAILQ_FIRST(&sdev->requests);
- scsi_req_cancel_async(req, NULL);
- }
- blk_drain(sdev->conf.blk);
- aio_context_release(blk_get_aio_context(sdev->conf.blk));
- scsi_device_set_ua(sdev, sense);
-}
-
-static char *scsibus_get_dev_path(DeviceState *dev)
-{
- SCSIDevice *d = SCSI_DEVICE(dev);
- DeviceState *hba = dev->parent_bus->parent;
- char *id;
- char *path;
-
- id = qdev_get_dev_path(hba);
- if (id) {
- path = g_strdup_printf("%s/%d:%d:%d", id, d->channel, d->id, d->lun);
- } else {
- path = g_strdup_printf("%d:%d:%d", d->channel, d->id, d->lun);
- }
- g_free(id);
- return path;
-}
-
-static char *scsibus_get_fw_dev_path(DeviceState *dev)
-{
- SCSIDevice *d = SCSI_DEVICE(dev);
- return g_strdup_printf("channel@%x/%s@%x,%x", d->channel,
- qdev_fw_name(dev), d->id, d->lun);
-}
-
-SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int id, int lun)
-{
- BusChild *kid;
- SCSIDevice *target_dev = NULL;
-
- QTAILQ_FOREACH_REVERSE(kid, &bus->qbus.children, ChildrenHead, sibling) {
- DeviceState *qdev = kid->child;
- SCSIDevice *dev = SCSI_DEVICE(qdev);
-
- if (dev->channel == channel && dev->id == id) {
- if (dev->lun == lun) {
- return dev;
- }
- target_dev = dev;
- }
- }
- return target_dev;
-}
-
-/* SCSI request list. For simplicity, pv points to the whole device */
-
-static void put_scsi_requests(QEMUFile *f, void *pv, size_t size)
-{
- SCSIDevice *s = pv;
- SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, s->qdev.parent_bus);
- SCSIRequest *req;
-
- QTAILQ_FOREACH(req, &s->requests, next) {
- assert(!req->io_canceled);
- assert(req->status == -1);
- assert(req->enqueued);
-
- qemu_put_sbyte(f, req->retry ? 1 : 2);
- qemu_put_buffer(f, req->cmd.buf, sizeof(req->cmd.buf));
- qemu_put_be32s(f, &req->tag);
- qemu_put_be32s(f, &req->lun);
- if (bus->info->save_request) {
- bus->info->save_request(f, req);
- }
- if (req->ops->save_request) {
- req->ops->save_request(f, req);
- }
- }
- qemu_put_sbyte(f, 0);
-}
-
-static int get_scsi_requests(QEMUFile *f, void *pv, size_t size)
-{
- SCSIDevice *s = pv;
- SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, s->qdev.parent_bus);
- int8_t sbyte;
-
- while ((sbyte = qemu_get_sbyte(f)) > 0) {
- uint8_t buf[SCSI_CMD_BUF_SIZE];
- uint32_t tag;
- uint32_t lun;
- SCSIRequest *req;
-
- qemu_get_buffer(f, buf, sizeof(buf));
- qemu_get_be32s(f, &tag);
- qemu_get_be32s(f, &lun);
- req = scsi_req_new(s, tag, lun, buf, NULL);
- req->retry = (sbyte == 1);
- if (bus->info->load_request) {
- req->hba_private = bus->info->load_request(f, req);
- }
- if (req->ops->load_request) {
- req->ops->load_request(f, req);
- }
-
- /* Just restart it later. */
- scsi_req_enqueue_internal(req);
-
- /* At this point, the request will be kept alive by the reference
- * added by scsi_req_enqueue_internal, so we can release our reference.
- * The HBA of course will add its own reference in the load_request
- * callback if it needs to hold on the SCSIRequest.
- */
- scsi_req_unref(req);
- }
-
- return 0;
-}
-
-static const VMStateInfo vmstate_info_scsi_requests = {
- .name = "scsi-requests",
- .get = get_scsi_requests,
- .put = put_scsi_requests,
-};
-
-static bool scsi_sense_state_needed(void *opaque)
-{
- SCSIDevice *s = opaque;
-
- return s->sense_len > SCSI_SENSE_BUF_SIZE_OLD;
-}
-
-static const VMStateDescription vmstate_scsi_sense_state = {
- .name = "SCSIDevice/sense",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = scsi_sense_state_needed,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8_SUB_ARRAY(sense, SCSIDevice,
- SCSI_SENSE_BUF_SIZE_OLD,
- SCSI_SENSE_BUF_SIZE - SCSI_SENSE_BUF_SIZE_OLD),
- VMSTATE_END_OF_LIST()
- }
-};
-
-const VMStateDescription vmstate_scsi_device = {
- .name = "SCSIDevice",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(unit_attention.key, SCSIDevice),
- VMSTATE_UINT8(unit_attention.asc, SCSIDevice),
- VMSTATE_UINT8(unit_attention.ascq, SCSIDevice),
- VMSTATE_BOOL(sense_is_ua, SCSIDevice),
- VMSTATE_UINT8_SUB_ARRAY(sense, SCSIDevice, 0, SCSI_SENSE_BUF_SIZE_OLD),
- VMSTATE_UINT32(sense_len, SCSIDevice),
- {
- .name = "requests",
- .version_id = 0,
- .field_exists = NULL,
- .size = 0, /* ouch */
- .info = &vmstate_info_scsi_requests,
- .flags = VMS_SINGLE,
- .offset = 0,
- },
- VMSTATE_END_OF_LIST()
- },
- .subsections = (const VMStateDescription*[]) {
- &vmstate_scsi_sense_state,
- NULL
- }
-};
-
-static void scsi_device_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *k = DEVICE_CLASS(klass);
- set_bit(DEVICE_CATEGORY_STORAGE, k->categories);
- k->bus_type = TYPE_SCSI_BUS;
- k->realize = scsi_qdev_realize;
- k->unrealize = scsi_qdev_unrealize;
- k->props = scsi_props;
-}
-
-static void scsi_dev_instance_init(Object *obj)
-{
- DeviceState *dev = DEVICE(obj);
- SCSIDevice *s = SCSI_DEVICE(dev);
-
- device_add_bootindex_property(obj, &s->conf.bootindex,
- "bootindex", NULL,
- &s->qdev, NULL);
-}
-
-static const TypeInfo scsi_device_type_info = {
- .name = TYPE_SCSI_DEVICE,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(SCSIDevice),
- .abstract = true,
- .class_size = sizeof(SCSIDeviceClass),
- .class_init = scsi_device_class_init,
- .instance_init = scsi_dev_instance_init,
-};
-
-static void scsi_register_types(void)
-{
- type_register_static(&scsi_bus_info);
- type_register_static(&scsi_device_type_info);
-}
-
-type_init(scsi_register_types)
diff --git a/qemu/hw/scsi/scsi-disk.c b/qemu/hw/scsi/scsi-disk.c
deleted file mode 100644
index c3ce54a20..000000000
--- a/qemu/hw/scsi/scsi-disk.c
+++ /dev/null
@@ -1,2828 +0,0 @@
-/*
- * SCSI Device emulation
- *
- * Copyright (c) 2006 CodeSourcery.
- * Based on code by Fabrice Bellard
- *
- * Written by Paul Brook
- * Modifications:
- * 2009-Dec-12 Artyom Tarasenko : implemented stamdard inquiry for the case
- * when the allocation length of CDB is smaller
- * than 36.
- * 2009-Oct-13 Artyom Tarasenko : implemented the block descriptor in the
- * MODE SENSE response.
- *
- * This code is licensed under the LGPL.
- *
- * Note that this file only handles the SCSI architecture model and device
- * commands. Emulation of interface/link layer protocols is handled by
- * the host adapter emulator.
- */
-
-//#define DEBUG_SCSI
-
-#ifdef DEBUG_SCSI
-#define DPRINTF(fmt, ...) \
-do { printf("scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#endif
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu/error-report.h"
-#include "hw/scsi/scsi.h"
-#include "block/scsi.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
-#include "hw/block/block.h"
-#include "sysemu/dma.h"
-#include "qemu/cutils.h"
-
-#ifdef __linux
-#include <scsi/sg.h>
-#endif
-
-#define SCSI_WRITE_SAME_MAX 524288
-#define SCSI_DMA_BUF_SIZE 131072
-#define SCSI_MAX_INQUIRY_LEN 256
-#define SCSI_MAX_MODE_LEN 256
-
-#define DEFAULT_DISCARD_GRANULARITY 4096
-#define DEFAULT_MAX_UNMAP_SIZE (1 << 30) /* 1 GB */
-#define DEFAULT_MAX_IO_SIZE INT_MAX /* 2 GB - 1 block */
-
-typedef struct SCSIDiskState SCSIDiskState;
-
-typedef struct SCSIDiskReq {
- SCSIRequest req;
- /* Both sector and sector_count are in terms of qemu 512 byte blocks. */
- uint64_t sector;
- uint32_t sector_count;
- uint32_t buflen;
- bool started;
- struct iovec iov;
- QEMUIOVector qiov;
- BlockAcctCookie acct;
-} SCSIDiskReq;
-
-#define SCSI_DISK_F_REMOVABLE 0
-#define SCSI_DISK_F_DPOFUA 1
-#define SCSI_DISK_F_NO_REMOVABLE_DEVOPS 2
-
-struct SCSIDiskState
-{
- SCSIDevice qdev;
- uint32_t features;
- bool media_changed;
- bool media_event;
- bool eject_request;
- uint16_t port_index;
- uint64_t max_unmap_size;
- uint64_t max_io_size;
- QEMUBH *bh;
- char *version;
- char *serial;
- char *vendor;
- char *product;
- bool tray_open;
- bool tray_locked;
-};
-
-static int scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed);
-
-static void scsi_free_request(SCSIRequest *req)
-{
- SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
-
- qemu_vfree(r->iov.iov_base);
-}
-
-/* Helper function for command completion with sense. */
-static void scsi_check_condition(SCSIDiskReq *r, SCSISense sense)
-{
- DPRINTF("Command complete tag=0x%x sense=%d/%d/%d\n",
- r->req.tag, sense.key, sense.asc, sense.ascq);
- scsi_req_build_sense(&r->req, sense);
- scsi_req_complete(&r->req, CHECK_CONDITION);
-}
-
-static uint32_t scsi_init_iovec(SCSIDiskReq *r, size_t size)
-{
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
-
- if (!r->iov.iov_base) {
- r->buflen = size;
- r->iov.iov_base = blk_blockalign(s->qdev.conf.blk, r->buflen);
- }
- r->iov.iov_len = MIN(r->sector_count * 512, r->buflen);
- qemu_iovec_init_external(&r->qiov, &r->iov, 1);
- return r->qiov.size / 512;
-}
-
-static void scsi_disk_save_request(QEMUFile *f, SCSIRequest *req)
-{
- SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
-
- qemu_put_be64s(f, &r->sector);
- qemu_put_be32s(f, &r->sector_count);
- qemu_put_be32s(f, &r->buflen);
- if (r->buflen) {
- if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
- qemu_put_buffer(f, r->iov.iov_base, r->iov.iov_len);
- } else if (!req->retry) {
- uint32_t len = r->iov.iov_len;
- qemu_put_be32s(f, &len);
- qemu_put_buffer(f, r->iov.iov_base, r->iov.iov_len);
- }
- }
-}
-
-static void scsi_disk_load_request(QEMUFile *f, SCSIRequest *req)
-{
- SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
-
- qemu_get_be64s(f, &r->sector);
- qemu_get_be32s(f, &r->sector_count);
- qemu_get_be32s(f, &r->buflen);
- if (r->buflen) {
- scsi_init_iovec(r, r->buflen);
- if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
- qemu_get_buffer(f, r->iov.iov_base, r->iov.iov_len);
- } else if (!r->req.retry) {
- uint32_t len;
- qemu_get_be32s(f, &len);
- r->iov.iov_len = len;
- assert(r->iov.iov_len <= r->buflen);
- qemu_get_buffer(f, r->iov.iov_base, r->iov.iov_len);
- }
- }
-
- qemu_iovec_init_external(&r->qiov, &r->iov, 1);
-}
-
-static void scsi_aio_complete(void *opaque, int ret)
-{
- SCSIDiskReq *r = (SCSIDiskReq *)opaque;
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
-
- assert(r->req.aiocb != NULL);
- r->req.aiocb = NULL;
- if (r->req.io_canceled) {
- scsi_req_cancel_complete(&r->req);
- goto done;
- }
-
- if (ret < 0) {
- if (scsi_handle_rw_error(r, -ret, true)) {
- goto done;
- }
- }
-
- block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
- scsi_req_complete(&r->req, GOOD);
-
-done:
- scsi_req_unref(&r->req);
-}
-
-static bool scsi_is_cmd_fua(SCSICommand *cmd)
-{
- switch (cmd->buf[0]) {
- case READ_10:
- case READ_12:
- case READ_16:
- case WRITE_10:
- case WRITE_12:
- case WRITE_16:
- return (cmd->buf[1] & 8) != 0;
-
- case VERIFY_10:
- case VERIFY_12:
- case VERIFY_16:
- case WRITE_VERIFY_10:
- case WRITE_VERIFY_12:
- case WRITE_VERIFY_16:
- return true;
-
- case READ_6:
- case WRITE_6:
- default:
- return false;
- }
-}
-
-static void scsi_write_do_fua(SCSIDiskReq *r)
-{
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
-
- assert(r->req.aiocb == NULL);
-
- if (r->req.io_canceled) {
- scsi_req_cancel_complete(&r->req);
- goto done;
- }
-
- if (scsi_is_cmd_fua(&r->req.cmd)) {
- block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct, 0,
- BLOCK_ACCT_FLUSH);
- r->req.aiocb = blk_aio_flush(s->qdev.conf.blk, scsi_aio_complete, r);
- return;
- }
-
- scsi_req_complete(&r->req, GOOD);
-
-done:
- scsi_req_unref(&r->req);
-}
-
-static void scsi_dma_complete_noio(SCSIDiskReq *r, int ret)
-{
- assert(r->req.aiocb == NULL);
-
- if (r->req.io_canceled) {
- scsi_req_cancel_complete(&r->req);
- goto done;
- }
-
- if (ret < 0) {
- if (scsi_handle_rw_error(r, -ret, false)) {
- goto done;
- }
- }
-
- r->sector += r->sector_count;
- r->sector_count = 0;
- if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
- scsi_write_do_fua(r);
- return;
- } else {
- scsi_req_complete(&r->req, GOOD);
- }
-
-done:
- scsi_req_unref(&r->req);
-}
-
-static void scsi_dma_complete(void *opaque, int ret)
-{
- SCSIDiskReq *r = (SCSIDiskReq *)opaque;
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
-
- assert(r->req.aiocb != NULL);
- r->req.aiocb = NULL;
-
- if (ret < 0) {
- block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct);
- } else {
- block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
- }
- scsi_dma_complete_noio(r, ret);
-}
-
-static void scsi_read_complete(void * opaque, int ret)
-{
- SCSIDiskReq *r = (SCSIDiskReq *)opaque;
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
- int n;
-
- assert(r->req.aiocb != NULL);
- r->req.aiocb = NULL;
- if (r->req.io_canceled) {
- scsi_req_cancel_complete(&r->req);
- goto done;
- }
-
- if (ret < 0) {
- if (scsi_handle_rw_error(r, -ret, true)) {
- goto done;
- }
- }
-
- block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
- DPRINTF("Data ready tag=0x%x len=%zd\n", r->req.tag, r->qiov.size);
-
- n = r->qiov.size / 512;
- r->sector += n;
- r->sector_count -= n;
- scsi_req_data(&r->req, r->qiov.size);
-
-done:
- scsi_req_unref(&r->req);
-}
-
-/* Actually issue a read to the block device. */
-static void scsi_do_read(SCSIDiskReq *r, int ret)
-{
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
- uint32_t n;
-
- assert (r->req.aiocb == NULL);
-
- if (r->req.io_canceled) {
- scsi_req_cancel_complete(&r->req);
- goto done;
- }
-
- if (ret < 0) {
- if (scsi_handle_rw_error(r, -ret, false)) {
- goto done;
- }
- }
-
- /* The request is used as the AIO opaque value, so add a ref. */
- scsi_req_ref(&r->req);
-
- if (r->req.sg) {
- dma_acct_start(s->qdev.conf.blk, &r->acct, r->req.sg, BLOCK_ACCT_READ);
- r->req.resid -= r->req.sg->size;
- r->req.aiocb = dma_blk_read(s->qdev.conf.blk, r->req.sg, r->sector,
- scsi_dma_complete, r);
- } else {
- n = scsi_init_iovec(r, SCSI_DMA_BUF_SIZE);
- block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct,
- n * BDRV_SECTOR_SIZE, BLOCK_ACCT_READ);
- r->req.aiocb = blk_aio_readv(s->qdev.conf.blk, r->sector, &r->qiov, n,
- scsi_read_complete, r);
- }
-
-done:
- scsi_req_unref(&r->req);
-}
-
-static void scsi_do_read_cb(void *opaque, int ret)
-{
- SCSIDiskReq *r = (SCSIDiskReq *)opaque;
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
-
- assert (r->req.aiocb != NULL);
- r->req.aiocb = NULL;
-
- if (ret < 0) {
- block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct);
- } else {
- block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
- }
- scsi_do_read(opaque, ret);
-}
-
-/* Read more data from scsi device into buffer. */
-static void scsi_read_data(SCSIRequest *req)
-{
- SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
- bool first;
-
- DPRINTF("Read sector_count=%d\n", r->sector_count);
- if (r->sector_count == 0) {
- /* This also clears the sense buffer for REQUEST SENSE. */
- scsi_req_complete(&r->req, GOOD);
- return;
- }
-
- /* No data transfer may already be in progress */
- assert(r->req.aiocb == NULL);
-
- /* The request is used as the AIO opaque value, so add a ref. */
- scsi_req_ref(&r->req);
- if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
- DPRINTF("Data transfer direction invalid\n");
- scsi_read_complete(r, -EINVAL);
- return;
- }
-
- if (s->tray_open) {
- scsi_read_complete(r, -ENOMEDIUM);
- return;
- }
-
- first = !r->started;
- r->started = true;
- if (first && scsi_is_cmd_fua(&r->req.cmd)) {
- block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct, 0,
- BLOCK_ACCT_FLUSH);
- r->req.aiocb = blk_aio_flush(s->qdev.conf.blk, scsi_do_read_cb, r);
- } else {
- scsi_do_read(r, 0);
- }
-}
-
-/*
- * scsi_handle_rw_error has two return values. 0 means that the error
- * must be ignored, 1 means that the error has been processed and the
- * caller should not do anything else for this request. Note that
- * scsi_handle_rw_error always manages its reference counts, independent
- * of the return value.
- */
-static int scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed)
-{
- bool is_read = (r->req.cmd.mode == SCSI_XFER_FROM_DEV);
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
- BlockErrorAction action = blk_get_error_action(s->qdev.conf.blk,
- is_read, error);
-
- if (action == BLOCK_ERROR_ACTION_REPORT) {
- if (acct_failed) {
- block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct);
- }
- switch (error) {
- case ENOMEDIUM:
- scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
- break;
- case ENOMEM:
- scsi_check_condition(r, SENSE_CODE(TARGET_FAILURE));
- break;
- case EINVAL:
- scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
- break;
- case ENOSPC:
- scsi_check_condition(r, SENSE_CODE(SPACE_ALLOC_FAILED));
- break;
- default:
- scsi_check_condition(r, SENSE_CODE(IO_ERROR));
- break;
- }
- }
- blk_error_action(s->qdev.conf.blk, action, is_read, error);
- if (action == BLOCK_ERROR_ACTION_STOP) {
- scsi_req_retry(&r->req);
- }
- return action != BLOCK_ERROR_ACTION_IGNORE;
-}
-
-static void scsi_write_complete_noio(SCSIDiskReq *r, int ret)
-{
- uint32_t n;
-
- assert (r->req.aiocb == NULL);
-
- if (r->req.io_canceled) {
- scsi_req_cancel_complete(&r->req);
- goto done;
- }
-
- if (ret < 0) {
- if (scsi_handle_rw_error(r, -ret, false)) {
- goto done;
- }
- }
-
- n = r->qiov.size / 512;
- r->sector += n;
- r->sector_count -= n;
- if (r->sector_count == 0) {
- scsi_write_do_fua(r);
- return;
- } else {
- scsi_init_iovec(r, SCSI_DMA_BUF_SIZE);
- DPRINTF("Write complete tag=0x%x more=%zd\n", r->req.tag, r->qiov.size);
- scsi_req_data(&r->req, r->qiov.size);
- }
-
-done:
- scsi_req_unref(&r->req);
-}
-
-static void scsi_write_complete(void * opaque, int ret)
-{
- SCSIDiskReq *r = (SCSIDiskReq *)opaque;
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
-
- assert (r->req.aiocb != NULL);
- r->req.aiocb = NULL;
-
- if (ret < 0) {
- block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct);
- } else {
- block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
- }
- scsi_write_complete_noio(r, ret);
-}
-
-static void scsi_write_data(SCSIRequest *req)
-{
- SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
- uint32_t n;
-
- /* No data transfer may already be in progress */
- assert(r->req.aiocb == NULL);
-
- /* The request is used as the AIO opaque value, so add a ref. */
- scsi_req_ref(&r->req);
- if (r->req.cmd.mode != SCSI_XFER_TO_DEV) {
- DPRINTF("Data transfer direction invalid\n");
- scsi_write_complete_noio(r, -EINVAL);
- return;
- }
-
- if (!r->req.sg && !r->qiov.size) {
- /* Called for the first time. Ask the driver to send us more data. */
- r->started = true;
- scsi_write_complete_noio(r, 0);
- return;
- }
- if (s->tray_open) {
- scsi_write_complete_noio(r, -ENOMEDIUM);
- return;
- }
-
- if (r->req.cmd.buf[0] == VERIFY_10 || r->req.cmd.buf[0] == VERIFY_12 ||
- r->req.cmd.buf[0] == VERIFY_16) {
- if (r->req.sg) {
- scsi_dma_complete_noio(r, 0);
- } else {
- scsi_write_complete_noio(r, 0);
- }
- return;
- }
-
- if (r->req.sg) {
- dma_acct_start(s->qdev.conf.blk, &r->acct, r->req.sg, BLOCK_ACCT_WRITE);
- r->req.resid -= r->req.sg->size;
- r->req.aiocb = dma_blk_write(s->qdev.conf.blk, r->req.sg, r->sector,
- scsi_dma_complete, r);
- } else {
- n = r->qiov.size / 512;
- block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct,
- n * BDRV_SECTOR_SIZE, BLOCK_ACCT_WRITE);
- r->req.aiocb = blk_aio_writev(s->qdev.conf.blk, r->sector, &r->qiov, n,
- scsi_write_complete, r);
- }
-}
-
-/* Return a pointer to the data buffer. */
-static uint8_t *scsi_get_buf(SCSIRequest *req)
-{
- SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
-
- return (uint8_t *)r->iov.iov_base;
-}
-
-static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
-{
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
- int buflen = 0;
- int start;
-
- if (req->cmd.buf[1] & 0x1) {
- /* Vital product data */
- uint8_t page_code = req->cmd.buf[2];
-
- outbuf[buflen++] = s->qdev.type & 0x1f;
- outbuf[buflen++] = page_code ; // this page
- outbuf[buflen++] = 0x00;
- outbuf[buflen++] = 0x00;
- start = buflen;
-
- switch (page_code) {
- case 0x00: /* Supported page codes, mandatory */
- {
- DPRINTF("Inquiry EVPD[Supported pages] "
- "buffer size %zd\n", req->cmd.xfer);
- outbuf[buflen++] = 0x00; // list of supported pages (this page)
- if (s->serial) {
- outbuf[buflen++] = 0x80; // unit serial number
- }
- outbuf[buflen++] = 0x83; // device identification
- if (s->qdev.type == TYPE_DISK) {
- outbuf[buflen++] = 0xb0; // block limits
- outbuf[buflen++] = 0xb2; // thin provisioning
- }
- break;
- }
- case 0x80: /* Device serial number, optional */
- {
- int l;
-
- if (!s->serial) {
- DPRINTF("Inquiry (EVPD[Serial number] not supported\n");
- return -1;
- }
-
- l = strlen(s->serial);
- if (l > 20) {
- l = 20;
- }
-
- DPRINTF("Inquiry EVPD[Serial number] "
- "buffer size %zd\n", req->cmd.xfer);
- memcpy(outbuf+buflen, s->serial, l);
- buflen += l;
- break;
- }
-
- case 0x83: /* Device identification page, mandatory */
- {
- const char *str = s->serial ?: blk_name(s->qdev.conf.blk);
- int max_len = s->serial ? 20 : 255 - 8;
- int id_len = strlen(str);
-
- if (id_len > max_len) {
- id_len = max_len;
- }
- DPRINTF("Inquiry EVPD[Device identification] "
- "buffer size %zd\n", req->cmd.xfer);
-
- outbuf[buflen++] = 0x2; // ASCII
- outbuf[buflen++] = 0; // not officially assigned
- outbuf[buflen++] = 0; // reserved
- outbuf[buflen++] = id_len; // length of data following
- memcpy(outbuf+buflen, str, id_len);
- buflen += id_len;
-
- if (s->qdev.wwn) {
- outbuf[buflen++] = 0x1; // Binary
- outbuf[buflen++] = 0x3; // NAA
- outbuf[buflen++] = 0; // reserved
- outbuf[buflen++] = 8;
- stq_be_p(&outbuf[buflen], s->qdev.wwn);
- buflen += 8;
- }
-
- if (s->qdev.port_wwn) {
- outbuf[buflen++] = 0x61; // SAS / Binary
- outbuf[buflen++] = 0x93; // PIV / Target port / NAA
- outbuf[buflen++] = 0; // reserved
- outbuf[buflen++] = 8;
- stq_be_p(&outbuf[buflen], s->qdev.port_wwn);
- buflen += 8;
- }
-
- if (s->port_index) {
- outbuf[buflen++] = 0x61; // SAS / Binary
- outbuf[buflen++] = 0x94; // PIV / Target port / relative target port
- outbuf[buflen++] = 0; // reserved
- outbuf[buflen++] = 4;
- stw_be_p(&outbuf[buflen + 2], s->port_index);
- buflen += 4;
- }
- break;
- }
- case 0xb0: /* block limits */
- {
- unsigned int unmap_sectors =
- s->qdev.conf.discard_granularity / s->qdev.blocksize;
- unsigned int min_io_size =
- s->qdev.conf.min_io_size / s->qdev.blocksize;
- unsigned int opt_io_size =
- s->qdev.conf.opt_io_size / s->qdev.blocksize;
- unsigned int max_unmap_sectors =
- s->max_unmap_size / s->qdev.blocksize;
- unsigned int max_io_sectors =
- s->max_io_size / s->qdev.blocksize;
-
- if (s->qdev.type == TYPE_ROM) {
- DPRINTF("Inquiry (EVPD[%02X] not supported for CDROM\n",
- page_code);
- return -1;
- }
- /* required VPD size with unmap support */
- buflen = 0x40;
- memset(outbuf + 4, 0, buflen - 4);
-
- outbuf[4] = 0x1; /* wsnz */
-
- /* optimal transfer length granularity */
- outbuf[6] = (min_io_size >> 8) & 0xff;
- outbuf[7] = min_io_size & 0xff;
-
- /* maximum transfer length */
- outbuf[8] = (max_io_sectors >> 24) & 0xff;
- outbuf[9] = (max_io_sectors >> 16) & 0xff;
- outbuf[10] = (max_io_sectors >> 8) & 0xff;
- outbuf[11] = max_io_sectors & 0xff;
-
- /* optimal transfer length */
- outbuf[12] = (opt_io_size >> 24) & 0xff;
- outbuf[13] = (opt_io_size >> 16) & 0xff;
- outbuf[14] = (opt_io_size >> 8) & 0xff;
- outbuf[15] = opt_io_size & 0xff;
-
- /* max unmap LBA count, default is 1GB */
- outbuf[20] = (max_unmap_sectors >> 24) & 0xff;
- outbuf[21] = (max_unmap_sectors >> 16) & 0xff;
- outbuf[22] = (max_unmap_sectors >> 8) & 0xff;
- outbuf[23] = max_unmap_sectors & 0xff;
-
- /* max unmap descriptors, 255 fit in 4 kb with an 8-byte header. */
- outbuf[24] = 0;
- outbuf[25] = 0;
- outbuf[26] = 0;
- outbuf[27] = 255;
-
- /* optimal unmap granularity */
- outbuf[28] = (unmap_sectors >> 24) & 0xff;
- outbuf[29] = (unmap_sectors >> 16) & 0xff;
- outbuf[30] = (unmap_sectors >> 8) & 0xff;
- outbuf[31] = unmap_sectors & 0xff;
-
- /* max write same size */
- outbuf[36] = 0;
- outbuf[37] = 0;
- outbuf[38] = 0;
- outbuf[39] = 0;
-
- outbuf[40] = (max_io_sectors >> 24) & 0xff;
- outbuf[41] = (max_io_sectors >> 16) & 0xff;
- outbuf[42] = (max_io_sectors >> 8) & 0xff;
- outbuf[43] = max_io_sectors & 0xff;
- break;
- }
- case 0xb2: /* thin provisioning */
- {
- buflen = 8;
- outbuf[4] = 0;
- outbuf[5] = 0xe0; /* unmap & write_same 10/16 all supported */
- outbuf[6] = s->qdev.conf.discard_granularity ? 2 : 1;
- outbuf[7] = 0;
- break;
- }
- default:
- return -1;
- }
- /* done with EVPD */
- assert(buflen - start <= 255);
- outbuf[start - 1] = buflen - start;
- return buflen;
- }
-
- /* Standard INQUIRY data */
- if (req->cmd.buf[2] != 0) {
- return -1;
- }
-
- /* PAGE CODE == 0 */
- buflen = req->cmd.xfer;
- if (buflen > SCSI_MAX_INQUIRY_LEN) {
- buflen = SCSI_MAX_INQUIRY_LEN;
- }
-
- outbuf[0] = s->qdev.type & 0x1f;
- outbuf[1] = (s->features & (1 << SCSI_DISK_F_REMOVABLE)) ? 0x80 : 0;
-
- strpadcpy((char *) &outbuf[16], 16, s->product, ' ');
- strpadcpy((char *) &outbuf[8], 8, s->vendor, ' ');
-
- memset(&outbuf[32], 0, 4);
- memcpy(&outbuf[32], s->version, MIN(4, strlen(s->version)));
- /*
- * We claim conformance to SPC-3, which is required for guests
- * to ask for modern features like READ CAPACITY(16) or the
- * block characteristics VPD page by default. Not all of SPC-3
- * is actually implemented, but we're good enough.
- */
- outbuf[2] = 5;
- outbuf[3] = 2 | 0x10; /* Format 2, HiSup */
-
- if (buflen > 36) {
- outbuf[4] = buflen - 5; /* Additional Length = (Len - 1) - 4 */
- } else {
- /* If the allocation length of CDB is too small,
- the additional length is not adjusted */
- outbuf[4] = 36 - 5;
- }
-
- /* Sync data transfer and TCQ. */
- outbuf[7] = 0x10 | (req->bus->info->tcq ? 0x02 : 0);
- return buflen;
-}
-
-static inline bool media_is_dvd(SCSIDiskState *s)
-{
- uint64_t nb_sectors;
- if (s->qdev.type != TYPE_ROM) {
- return false;
- }
- if (!blk_is_inserted(s->qdev.conf.blk)) {
- return false;
- }
- if (s->tray_open) {
- return false;
- }
- blk_get_geometry(s->qdev.conf.blk, &nb_sectors);
- return nb_sectors > CD_MAX_SECTORS;
-}
-
-static inline bool media_is_cd(SCSIDiskState *s)
-{
- uint64_t nb_sectors;
- if (s->qdev.type != TYPE_ROM) {
- return false;
- }
- if (!blk_is_inserted(s->qdev.conf.blk)) {
- return false;
- }
- if (s->tray_open) {
- return false;
- }
- blk_get_geometry(s->qdev.conf.blk, &nb_sectors);
- return nb_sectors <= CD_MAX_SECTORS;
-}
-
-static int scsi_read_disc_information(SCSIDiskState *s, SCSIDiskReq *r,
- uint8_t *outbuf)
-{
- uint8_t type = r->req.cmd.buf[1] & 7;
-
- if (s->qdev.type != TYPE_ROM) {
- return -1;
- }
-
- /* Types 1/2 are only defined for Blu-Ray. */
- if (type != 0) {
- scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
- return -1;
- }
-
- memset(outbuf, 0, 34);
- outbuf[1] = 32;
- outbuf[2] = 0xe; /* last session complete, disc finalized */
- outbuf[3] = 1; /* first track on disc */
- outbuf[4] = 1; /* # of sessions */
- outbuf[5] = 1; /* first track of last session */
- outbuf[6] = 1; /* last track of last session */
- outbuf[7] = 0x20; /* unrestricted use */
- outbuf[8] = 0x00; /* CD-ROM or DVD-ROM */
- /* 9-10-11: most significant byte corresponding bytes 4-5-6 */
- /* 12-23: not meaningful for CD-ROM or DVD-ROM */
- /* 24-31: disc bar code */
- /* 32: disc application code */
- /* 33: number of OPC tables */
-
- return 34;
-}
-
-static int scsi_read_dvd_structure(SCSIDiskState *s, SCSIDiskReq *r,
- uint8_t *outbuf)
-{
- static const int rds_caps_size[5] = {
- [0] = 2048 + 4,
- [1] = 4 + 4,
- [3] = 188 + 4,
- [4] = 2048 + 4,
- };
-
- uint8_t media = r->req.cmd.buf[1];
- uint8_t layer = r->req.cmd.buf[6];
- uint8_t format = r->req.cmd.buf[7];
- int size = -1;
-
- if (s->qdev.type != TYPE_ROM) {
- return -1;
- }
- if (media != 0) {
- scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
- return -1;
- }
-
- if (format != 0xff) {
- if (s->tray_open || !blk_is_inserted(s->qdev.conf.blk)) {
- scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
- return -1;
- }
- if (media_is_cd(s)) {
- scsi_check_condition(r, SENSE_CODE(INCOMPATIBLE_FORMAT));
- return -1;
- }
- if (format >= ARRAY_SIZE(rds_caps_size)) {
- return -1;
- }
- size = rds_caps_size[format];
- memset(outbuf, 0, size);
- }
-
- switch (format) {
- case 0x00: {
- /* Physical format information */
- uint64_t nb_sectors;
- if (layer != 0) {
- goto fail;
- }
- blk_get_geometry(s->qdev.conf.blk, &nb_sectors);
-
- outbuf[4] = 1; /* DVD-ROM, part version 1 */
- outbuf[5] = 0xf; /* 120mm disc, minimum rate unspecified */
- outbuf[6] = 1; /* one layer, read-only (per MMC-2 spec) */
- outbuf[7] = 0; /* default densities */
-
- stl_be_p(&outbuf[12], (nb_sectors >> 2) - 1); /* end sector */
- stl_be_p(&outbuf[16], (nb_sectors >> 2) - 1); /* l0 end sector */
- break;
- }
-
- case 0x01: /* DVD copyright information, all zeros */
- break;
-
- case 0x03: /* BCA information - invalid field for no BCA info */
- return -1;
-
- case 0x04: /* DVD disc manufacturing information, all zeros */
- break;
-
- case 0xff: { /* List capabilities */
- int i;
- size = 4;
- for (i = 0; i < ARRAY_SIZE(rds_caps_size); i++) {
- if (!rds_caps_size[i]) {
- continue;
- }
- outbuf[size] = i;
- outbuf[size + 1] = 0x40; /* Not writable, readable */
- stw_be_p(&outbuf[size + 2], rds_caps_size[i]);
- size += 4;
- }
- break;
- }
-
- default:
- return -1;
- }
-
- /* Size of buffer, not including 2 byte size field */
- stw_be_p(outbuf, size - 2);
- return size;
-
-fail:
- return -1;
-}
-
-static int scsi_event_status_media(SCSIDiskState *s, uint8_t *outbuf)
-{
- uint8_t event_code, media_status;
-
- media_status = 0;
- if (s->tray_open) {
- media_status = MS_TRAY_OPEN;
- } else if (blk_is_inserted(s->qdev.conf.blk)) {
- media_status = MS_MEDIA_PRESENT;
- }
-
- /* Event notification descriptor */
- event_code = MEC_NO_CHANGE;
- if (media_status != MS_TRAY_OPEN) {
- if (s->media_event) {
- event_code = MEC_NEW_MEDIA;
- s->media_event = false;
- } else if (s->eject_request) {
- event_code = MEC_EJECT_REQUESTED;
- s->eject_request = false;
- }
- }
-
- outbuf[0] = event_code;
- outbuf[1] = media_status;
-
- /* These fields are reserved, just clear them. */
- outbuf[2] = 0;
- outbuf[3] = 0;
- return 4;
-}
-
-static int scsi_get_event_status_notification(SCSIDiskState *s, SCSIDiskReq *r,
- uint8_t *outbuf)
-{
- int size;
- uint8_t *buf = r->req.cmd.buf;
- uint8_t notification_class_request = buf[4];
- if (s->qdev.type != TYPE_ROM) {
- return -1;
- }
- if ((buf[1] & 1) == 0) {
- /* asynchronous */
- return -1;
- }
-
- size = 4;
- outbuf[0] = outbuf[1] = 0;
- outbuf[3] = 1 << GESN_MEDIA; /* supported events */
- if (notification_class_request & (1 << GESN_MEDIA)) {
- outbuf[2] = GESN_MEDIA;
- size += scsi_event_status_media(s, &outbuf[size]);
- } else {
- outbuf[2] = 0x80;
- }
- stw_be_p(outbuf, size - 4);
- return size;
-}
-
-static int scsi_get_configuration(SCSIDiskState *s, uint8_t *outbuf)
-{
- int current;
-
- if (s->qdev.type != TYPE_ROM) {
- return -1;
- }
-
- if (media_is_dvd(s)) {
- current = MMC_PROFILE_DVD_ROM;
- } else if (media_is_cd(s)) {
- current = MMC_PROFILE_CD_ROM;
- } else {
- current = MMC_PROFILE_NONE;
- }
-
- memset(outbuf, 0, 40);
- stl_be_p(&outbuf[0], 36); /* Bytes after the data length field */
- stw_be_p(&outbuf[6], current);
- /* outbuf[8] - outbuf[19]: Feature 0 - Profile list */
- outbuf[10] = 0x03; /* persistent, current */
- outbuf[11] = 8; /* two profiles */
- stw_be_p(&outbuf[12], MMC_PROFILE_DVD_ROM);
- outbuf[14] = (current == MMC_PROFILE_DVD_ROM);
- stw_be_p(&outbuf[16], MMC_PROFILE_CD_ROM);
- outbuf[18] = (current == MMC_PROFILE_CD_ROM);
- /* outbuf[20] - outbuf[31]: Feature 1 - Core feature */
- stw_be_p(&outbuf[20], 1);
- outbuf[22] = 0x08 | 0x03; /* version 2, persistent, current */
- outbuf[23] = 8;
- stl_be_p(&outbuf[24], 1); /* SCSI */
- outbuf[28] = 1; /* DBE = 1, mandatory */
- /* outbuf[32] - outbuf[39]: Feature 3 - Removable media feature */
- stw_be_p(&outbuf[32], 3);
- outbuf[34] = 0x08 | 0x03; /* version 2, persistent, current */
- outbuf[35] = 4;
- outbuf[36] = 0x39; /* tray, load=1, eject=1, unlocked at powerup, lock=1 */
- /* TODO: Random readable, CD read, DVD read, drive serial number,
- power management */
- return 40;
-}
-
-static int scsi_emulate_mechanism_status(SCSIDiskState *s, uint8_t *outbuf)
-{
- if (s->qdev.type != TYPE_ROM) {
- return -1;
- }
- memset(outbuf, 0, 8);
- outbuf[5] = 1; /* CD-ROM */
- return 8;
-}
-
-static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
- int page_control)
-{
- static const int mode_sense_valid[0x3f] = {
- [MODE_PAGE_HD_GEOMETRY] = (1 << TYPE_DISK),
- [MODE_PAGE_FLEXIBLE_DISK_GEOMETRY] = (1 << TYPE_DISK),
- [MODE_PAGE_CACHING] = (1 << TYPE_DISK) | (1 << TYPE_ROM),
- [MODE_PAGE_R_W_ERROR] = (1 << TYPE_DISK) | (1 << TYPE_ROM),
- [MODE_PAGE_AUDIO_CTL] = (1 << TYPE_ROM),
- [MODE_PAGE_CAPABILITIES] = (1 << TYPE_ROM),
- };
-
- uint8_t *p = *p_outbuf + 2;
- int length;
-
- if ((mode_sense_valid[page] & (1 << s->qdev.type)) == 0) {
- return -1;
- }
-
- /*
- * If Changeable Values are requested, a mask denoting those mode parameters
- * that are changeable shall be returned. As we currently don't support
- * parameter changes via MODE_SELECT all bits are returned set to zero.
- * The buffer was already menset to zero by the caller of this function.
- *
- * The offsets here are off by two compared to the descriptions in the
- * SCSI specs, because those include a 2-byte header. This is unfortunate,
- * but it is done so that offsets are consistent within our implementation
- * of MODE SENSE and MODE SELECT. MODE SELECT has to deal with both
- * 2-byte and 4-byte headers.
- */
- switch (page) {
- case MODE_PAGE_HD_GEOMETRY:
- length = 0x16;
- if (page_control == 1) { /* Changeable Values */
- break;
- }
- /* if a geometry hint is available, use it */
- p[0] = (s->qdev.conf.cyls >> 16) & 0xff;
- p[1] = (s->qdev.conf.cyls >> 8) & 0xff;
- p[2] = s->qdev.conf.cyls & 0xff;
- p[3] = s->qdev.conf.heads & 0xff;
- /* Write precomp start cylinder, disabled */
- p[4] = (s->qdev.conf.cyls >> 16) & 0xff;
- p[5] = (s->qdev.conf.cyls >> 8) & 0xff;
- p[6] = s->qdev.conf.cyls & 0xff;
- /* Reduced current start cylinder, disabled */
- p[7] = (s->qdev.conf.cyls >> 16) & 0xff;
- p[8] = (s->qdev.conf.cyls >> 8) & 0xff;
- p[9] = s->qdev.conf.cyls & 0xff;
- /* Device step rate [ns], 200ns */
- p[10] = 0;
- p[11] = 200;
- /* Landing zone cylinder */
- p[12] = 0xff;
- p[13] = 0xff;
- p[14] = 0xff;
- /* Medium rotation rate [rpm], 5400 rpm */
- p[18] = (5400 >> 8) & 0xff;
- p[19] = 5400 & 0xff;
- break;
-
- case MODE_PAGE_FLEXIBLE_DISK_GEOMETRY:
- length = 0x1e;
- if (page_control == 1) { /* Changeable Values */
- break;
- }
- /* Transfer rate [kbit/s], 5Mbit/s */
- p[0] = 5000 >> 8;
- p[1] = 5000 & 0xff;
- /* if a geometry hint is available, use it */
- p[2] = s->qdev.conf.heads & 0xff;
- p[3] = s->qdev.conf.secs & 0xff;
- p[4] = s->qdev.blocksize >> 8;
- p[6] = (s->qdev.conf.cyls >> 8) & 0xff;
- p[7] = s->qdev.conf.cyls & 0xff;
- /* Write precomp start cylinder, disabled */
- p[8] = (s->qdev.conf.cyls >> 8) & 0xff;
- p[9] = s->qdev.conf.cyls & 0xff;
- /* Reduced current start cylinder, disabled */
- p[10] = (s->qdev.conf.cyls >> 8) & 0xff;
- p[11] = s->qdev.conf.cyls & 0xff;
- /* Device step rate [100us], 100us */
- p[12] = 0;
- p[13] = 1;
- /* Device step pulse width [us], 1us */
- p[14] = 1;
- /* Device head settle delay [100us], 100us */
- p[15] = 0;
- p[16] = 1;
- /* Motor on delay [0.1s], 0.1s */
- p[17] = 1;
- /* Motor off delay [0.1s], 0.1s */
- p[18] = 1;
- /* Medium rotation rate [rpm], 5400 rpm */
- p[26] = (5400 >> 8) & 0xff;
- p[27] = 5400 & 0xff;
- break;
-
- case MODE_PAGE_CACHING:
- length = 0x12;
- if (page_control == 1 || /* Changeable Values */
- blk_enable_write_cache(s->qdev.conf.blk)) {
- p[0] = 4; /* WCE */
- }
- break;
-
- case MODE_PAGE_R_W_ERROR:
- length = 10;
- if (page_control == 1) { /* Changeable Values */
- break;
- }
- p[0] = 0x80; /* Automatic Write Reallocation Enabled */
- if (s->qdev.type == TYPE_ROM) {
- p[1] = 0x20; /* Read Retry Count */
- }
- break;
-
- case MODE_PAGE_AUDIO_CTL:
- length = 14;
- break;
-
- case MODE_PAGE_CAPABILITIES:
- length = 0x14;
- if (page_control == 1) { /* Changeable Values */
- break;
- }
-
- p[0] = 0x3b; /* CD-R & CD-RW read */
- p[1] = 0; /* Writing not supported */
- p[2] = 0x7f; /* Audio, composite, digital out,
- mode 2 form 1&2, multi session */
- p[3] = 0xff; /* CD DA, DA accurate, RW supported,
- RW corrected, C2 errors, ISRC,
- UPC, Bar code */
- p[4] = 0x2d | (s->tray_locked ? 2 : 0);
- /* Locking supported, jumper present, eject, tray */
- p[5] = 0; /* no volume & mute control, no
- changer */
- p[6] = (50 * 176) >> 8; /* 50x read speed */
- p[7] = (50 * 176) & 0xff;
- p[8] = 2 >> 8; /* Two volume levels */
- p[9] = 2 & 0xff;
- p[10] = 2048 >> 8; /* 2M buffer */
- p[11] = 2048 & 0xff;
- p[12] = (16 * 176) >> 8; /* 16x read speed current */
- p[13] = (16 * 176) & 0xff;
- p[16] = (16 * 176) >> 8; /* 16x write speed */
- p[17] = (16 * 176) & 0xff;
- p[18] = (16 * 176) >> 8; /* 16x write speed current */
- p[19] = (16 * 176) & 0xff;
- break;
-
- default:
- return -1;
- }
-
- assert(length < 256);
- (*p_outbuf)[0] = page;
- (*p_outbuf)[1] = length;
- *p_outbuf += length + 2;
- return length + 2;
-}
-
-static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf)
-{
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
- uint64_t nb_sectors;
- bool dbd;
- int page, buflen, ret, page_control;
- uint8_t *p;
- uint8_t dev_specific_param;
-
- dbd = (r->req.cmd.buf[1] & 0x8) != 0;
- page = r->req.cmd.buf[2] & 0x3f;
- page_control = (r->req.cmd.buf[2] & 0xc0) >> 6;
- DPRINTF("Mode Sense(%d) (page %d, xfer %zd, page_control %d)\n",
- (r->req.cmd.buf[0] == MODE_SENSE) ? 6 : 10, page, r->req.cmd.xfer, page_control);
- memset(outbuf, 0, r->req.cmd.xfer);
- p = outbuf;
-
- if (s->qdev.type == TYPE_DISK) {
- dev_specific_param = s->features & (1 << SCSI_DISK_F_DPOFUA) ? 0x10 : 0;
- if (blk_is_read_only(s->qdev.conf.blk)) {
- dev_specific_param |= 0x80; /* Readonly. */
- }
- } else {
- /* MMC prescribes that CD/DVD drives have no block descriptors,
- * and defines no device-specific parameter. */
- dev_specific_param = 0x00;
- dbd = true;
- }
-
- if (r->req.cmd.buf[0] == MODE_SENSE) {
- p[1] = 0; /* Default media type. */
- p[2] = dev_specific_param;
- p[3] = 0; /* Block descriptor length. */
- p += 4;
- } else { /* MODE_SENSE_10 */
- p[2] = 0; /* Default media type. */
- p[3] = dev_specific_param;
- p[6] = p[7] = 0; /* Block descriptor length. */
- p += 8;
- }
-
- blk_get_geometry(s->qdev.conf.blk, &nb_sectors);
- if (!dbd && nb_sectors) {
- if (r->req.cmd.buf[0] == MODE_SENSE) {
- outbuf[3] = 8; /* Block descriptor length */
- } else { /* MODE_SENSE_10 */
- outbuf[7] = 8; /* Block descriptor length */
- }
- nb_sectors /= (s->qdev.blocksize / 512);
- if (nb_sectors > 0xffffff) {
- nb_sectors = 0;
- }
- p[0] = 0; /* media density code */
- p[1] = (nb_sectors >> 16) & 0xff;
- p[2] = (nb_sectors >> 8) & 0xff;
- p[3] = nb_sectors & 0xff;
- p[4] = 0; /* reserved */
- p[5] = 0; /* bytes 5-7 are the sector size in bytes */
- p[6] = s->qdev.blocksize >> 8;
- p[7] = 0;
- p += 8;
- }
-
- if (page_control == 3) {
- /* Saved Values */
- scsi_check_condition(r, SENSE_CODE(SAVING_PARAMS_NOT_SUPPORTED));
- return -1;
- }
-
- if (page == 0x3f) {
- for (page = 0; page <= 0x3e; page++) {
- mode_sense_page(s, page, &p, page_control);
- }
- } else {
- ret = mode_sense_page(s, page, &p, page_control);
- if (ret == -1) {
- return -1;
- }
- }
-
- buflen = p - outbuf;
- /*
- * The mode data length field specifies the length in bytes of the
- * following data that is available to be transferred. The mode data
- * length does not include itself.
- */
- if (r->req.cmd.buf[0] == MODE_SENSE) {
- outbuf[0] = buflen - 1;
- } else { /* MODE_SENSE_10 */
- outbuf[0] = ((buflen - 2) >> 8) & 0xff;
- outbuf[1] = (buflen - 2) & 0xff;
- }
- return buflen;
-}
-
-static int scsi_disk_emulate_read_toc(SCSIRequest *req, uint8_t *outbuf)
-{
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
- int start_track, format, msf, toclen;
- uint64_t nb_sectors;
-
- msf = req->cmd.buf[1] & 2;
- format = req->cmd.buf[2] & 0xf;
- start_track = req->cmd.buf[6];
- blk_get_geometry(s->qdev.conf.blk, &nb_sectors);
- DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1);
- nb_sectors /= s->qdev.blocksize / 512;
- switch (format) {
- case 0:
- toclen = cdrom_read_toc(nb_sectors, outbuf, msf, start_track);
- break;
- case 1:
- /* multi session : only a single session defined */
- toclen = 12;
- memset(outbuf, 0, 12);
- outbuf[1] = 0x0a;
- outbuf[2] = 0x01;
- outbuf[3] = 0x01;
- break;
- case 2:
- toclen = cdrom_read_toc_raw(nb_sectors, outbuf, msf, start_track);
- break;
- default:
- return -1;
- }
- return toclen;
-}
-
-static int scsi_disk_emulate_start_stop(SCSIDiskReq *r)
-{
- SCSIRequest *req = &r->req;
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
- bool start = req->cmd.buf[4] & 1;
- bool loej = req->cmd.buf[4] & 2; /* load on start, eject on !start */
- int pwrcnd = req->cmd.buf[4] & 0xf0;
-
- if (pwrcnd) {
- /* eject/load only happens for power condition == 0 */
- return 0;
- }
-
- if ((s->features & (1 << SCSI_DISK_F_REMOVABLE)) && loej) {
- if (!start && !s->tray_open && s->tray_locked) {
- scsi_check_condition(r,
- blk_is_inserted(s->qdev.conf.blk)
- ? SENSE_CODE(ILLEGAL_REQ_REMOVAL_PREVENTED)
- : SENSE_CODE(NOT_READY_REMOVAL_PREVENTED));
- return -1;
- }
-
- if (s->tray_open != !start) {
- blk_eject(s->qdev.conf.blk, !start);
- s->tray_open = !start;
- }
- }
- return 0;
-}
-
-static void scsi_disk_emulate_read_data(SCSIRequest *req)
-{
- SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
- int buflen = r->iov.iov_len;
-
- if (buflen) {
- DPRINTF("Read buf_len=%d\n", buflen);
- r->iov.iov_len = 0;
- r->started = true;
- scsi_req_data(&r->req, buflen);
- return;
- }
-
- /* This also clears the sense buffer for REQUEST SENSE. */
- scsi_req_complete(&r->req, GOOD);
-}
-
-static int scsi_disk_check_mode_select(SCSIDiskState *s, int page,
- uint8_t *inbuf, int inlen)
-{
- uint8_t mode_current[SCSI_MAX_MODE_LEN];
- uint8_t mode_changeable[SCSI_MAX_MODE_LEN];
- uint8_t *p;
- int len, expected_len, changeable_len, i;
-
- /* The input buffer does not include the page header, so it is
- * off by 2 bytes.
- */
- expected_len = inlen + 2;
- if (expected_len > SCSI_MAX_MODE_LEN) {
- return -1;
- }
-
- p = mode_current;
- memset(mode_current, 0, inlen + 2);
- len = mode_sense_page(s, page, &p, 0);
- if (len < 0 || len != expected_len) {
- return -1;
- }
-
- p = mode_changeable;
- memset(mode_changeable, 0, inlen + 2);
- changeable_len = mode_sense_page(s, page, &p, 1);
- assert(changeable_len == len);
-
- /* Check that unchangeable bits are the same as what MODE SENSE
- * would return.
- */
- for (i = 2; i < len; i++) {
- if (((mode_current[i] ^ inbuf[i - 2]) & ~mode_changeable[i]) != 0) {
- return -1;
- }
- }
- return 0;
-}
-
-static void scsi_disk_apply_mode_select(SCSIDiskState *s, int page, uint8_t *p)
-{
- switch (page) {
- case MODE_PAGE_CACHING:
- blk_set_enable_write_cache(s->qdev.conf.blk, (p[0] & 4) != 0);
- break;
-
- default:
- break;
- }
-}
-
-static int mode_select_pages(SCSIDiskReq *r, uint8_t *p, int len, bool change)
-{
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
-
- while (len > 0) {
- int page, subpage, page_len;
-
- /* Parse both possible formats for the mode page headers. */
- page = p[0] & 0x3f;
- if (p[0] & 0x40) {
- if (len < 4) {
- goto invalid_param_len;
- }
- subpage = p[1];
- page_len = lduw_be_p(&p[2]);
- p += 4;
- len -= 4;
- } else {
- if (len < 2) {
- goto invalid_param_len;
- }
- subpage = 0;
- page_len = p[1];
- p += 2;
- len -= 2;
- }
-
- if (subpage) {
- goto invalid_param;
- }
- if (page_len > len) {
- goto invalid_param_len;
- }
-
- if (!change) {
- if (scsi_disk_check_mode_select(s, page, p, page_len) < 0) {
- goto invalid_param;
- }
- } else {
- scsi_disk_apply_mode_select(s, page, p);
- }
-
- p += page_len;
- len -= page_len;
- }
- return 0;
-
-invalid_param:
- scsi_check_condition(r, SENSE_CODE(INVALID_PARAM));
- return -1;
-
-invalid_param_len:
- scsi_check_condition(r, SENSE_CODE(INVALID_PARAM_LEN));
- return -1;
-}
-
-static void scsi_disk_emulate_mode_select(SCSIDiskReq *r, uint8_t *inbuf)
-{
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
- uint8_t *p = inbuf;
- int cmd = r->req.cmd.buf[0];
- int len = r->req.cmd.xfer;
- int hdr_len = (cmd == MODE_SELECT ? 4 : 8);
- int bd_len;
- int pass;
-
- /* We only support PF=1, SP=0. */
- if ((r->req.cmd.buf[1] & 0x11) != 0x10) {
- goto invalid_field;
- }
-
- if (len < hdr_len) {
- goto invalid_param_len;
- }
-
- bd_len = (cmd == MODE_SELECT ? p[3] : lduw_be_p(&p[6]));
- len -= hdr_len;
- p += hdr_len;
- if (len < bd_len) {
- goto invalid_param_len;
- }
- if (bd_len != 0 && bd_len != 8) {
- goto invalid_param;
- }
-
- len -= bd_len;
- p += bd_len;
-
- /* Ensure no change is made if there is an error! */
- for (pass = 0; pass < 2; pass++) {
- if (mode_select_pages(r, p, len, pass == 1) < 0) {
- assert(pass == 0);
- return;
- }
- }
- if (!blk_enable_write_cache(s->qdev.conf.blk)) {
- /* The request is used as the AIO opaque value, so add a ref. */
- scsi_req_ref(&r->req);
- block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct, 0,
- BLOCK_ACCT_FLUSH);
- r->req.aiocb = blk_aio_flush(s->qdev.conf.blk, scsi_aio_complete, r);
- return;
- }
-
- scsi_req_complete(&r->req, GOOD);
- return;
-
-invalid_param:
- scsi_check_condition(r, SENSE_CODE(INVALID_PARAM));
- return;
-
-invalid_param_len:
- scsi_check_condition(r, SENSE_CODE(INVALID_PARAM_LEN));
- return;
-
-invalid_field:
- scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
-}
-
-static inline bool check_lba_range(SCSIDiskState *s,
- uint64_t sector_num, uint32_t nb_sectors)
-{
- /*
- * The first line tests that no overflow happens when computing the last
- * sector. The second line tests that the last accessed sector is in
- * range.
- *
- * Careful, the computations should not underflow for nb_sectors == 0,
- * and a 0-block read to the first LBA beyond the end of device is
- * valid.
- */
- return (sector_num <= sector_num + nb_sectors &&
- sector_num + nb_sectors <= s->qdev.max_lba + 1);
-}
-
-typedef struct UnmapCBData {
- SCSIDiskReq *r;
- uint8_t *inbuf;
- int count;
-} UnmapCBData;
-
-static void scsi_unmap_complete(void *opaque, int ret);
-
-static void scsi_unmap_complete_noio(UnmapCBData *data, int ret)
-{
- SCSIDiskReq *r = data->r;
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
- uint64_t sector_num;
- uint32_t nb_sectors;
-
- assert(r->req.aiocb == NULL);
-
- if (r->req.io_canceled) {
- scsi_req_cancel_complete(&r->req);
- goto done;
- }
-
- if (ret < 0) {
- if (scsi_handle_rw_error(r, -ret, false)) {
- goto done;
- }
- }
-
- if (data->count > 0) {
- sector_num = ldq_be_p(&data->inbuf[0]);
- nb_sectors = ldl_be_p(&data->inbuf[8]) & 0xffffffffULL;
- if (!check_lba_range(s, sector_num, nb_sectors)) {
- scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
- goto done;
- }
-
- r->req.aiocb = blk_aio_discard(s->qdev.conf.blk,
- sector_num * (s->qdev.blocksize / 512),
- nb_sectors * (s->qdev.blocksize / 512),
- scsi_unmap_complete, data);
- data->count--;
- data->inbuf += 16;
- return;
- }
-
- scsi_req_complete(&r->req, GOOD);
-
-done:
- scsi_req_unref(&r->req);
- g_free(data);
-}
-
-static void scsi_unmap_complete(void *opaque, int ret)
-{
- UnmapCBData *data = opaque;
- SCSIDiskReq *r = data->r;
-
- assert(r->req.aiocb != NULL);
- r->req.aiocb = NULL;
-
- scsi_unmap_complete_noio(data, ret);
-}
-
-static void scsi_disk_emulate_unmap(SCSIDiskReq *r, uint8_t *inbuf)
-{
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
- uint8_t *p = inbuf;
- int len = r->req.cmd.xfer;
- UnmapCBData *data;
-
- /* Reject ANCHOR=1. */
- if (r->req.cmd.buf[1] & 0x1) {
- goto invalid_field;
- }
-
- if (len < 8) {
- goto invalid_param_len;
- }
- if (len < lduw_be_p(&p[0]) + 2) {
- goto invalid_param_len;
- }
- if (len < lduw_be_p(&p[2]) + 8) {
- goto invalid_param_len;
- }
- if (lduw_be_p(&p[2]) & 15) {
- goto invalid_param_len;
- }
-
- if (blk_is_read_only(s->qdev.conf.blk)) {
- scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED));
- return;
- }
-
- data = g_new0(UnmapCBData, 1);
- data->r = r;
- data->inbuf = &p[8];
- data->count = lduw_be_p(&p[2]) >> 4;
-
- /* The matching unref is in scsi_unmap_complete, before data is freed. */
- scsi_req_ref(&r->req);
- scsi_unmap_complete_noio(data, 0);
- return;
-
-invalid_param_len:
- scsi_check_condition(r, SENSE_CODE(INVALID_PARAM_LEN));
- return;
-
-invalid_field:
- scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
-}
-
-typedef struct WriteSameCBData {
- SCSIDiskReq *r;
- int64_t sector;
- int nb_sectors;
- QEMUIOVector qiov;
- struct iovec iov;
-} WriteSameCBData;
-
-static void scsi_write_same_complete(void *opaque, int ret)
-{
- WriteSameCBData *data = opaque;
- SCSIDiskReq *r = data->r;
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
-
- assert(r->req.aiocb != NULL);
- r->req.aiocb = NULL;
- if (r->req.io_canceled) {
- scsi_req_cancel_complete(&r->req);
- goto done;
- }
-
- if (ret < 0) {
- if (scsi_handle_rw_error(r, -ret, true)) {
- goto done;
- }
- }
-
- block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
-
- data->nb_sectors -= data->iov.iov_len / 512;
- data->sector += data->iov.iov_len / 512;
- data->iov.iov_len = MIN(data->nb_sectors * 512, data->iov.iov_len);
- if (data->iov.iov_len) {
- block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct,
- data->iov.iov_len, BLOCK_ACCT_WRITE);
- /* blk_aio_write doesn't like the qiov size being different from
- * nb_sectors, make sure they match.
- */
- qemu_iovec_init_external(&data->qiov, &data->iov, 1);
- r->req.aiocb = blk_aio_writev(s->qdev.conf.blk, data->sector,
- &data->qiov, data->iov.iov_len / 512,
- scsi_write_same_complete, data);
- return;
- }
-
- scsi_req_complete(&r->req, GOOD);
-
-done:
- scsi_req_unref(&r->req);
- qemu_vfree(data->iov.iov_base);
- g_free(data);
-}
-
-static void scsi_disk_emulate_write_same(SCSIDiskReq *r, uint8_t *inbuf)
-{
- SCSIRequest *req = &r->req;
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
- uint32_t nb_sectors = scsi_data_cdb_xfer(r->req.cmd.buf);
- WriteSameCBData *data;
- uint8_t *buf;
- int i;
-
- /* Fail if PBDATA=1 or LBDATA=1 or ANCHOR=1. */
- if (nb_sectors == 0 || (req->cmd.buf[1] & 0x16)) {
- scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
- return;
- }
-
- if (blk_is_read_only(s->qdev.conf.blk)) {
- scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED));
- return;
- }
- if (!check_lba_range(s, r->req.cmd.lba, nb_sectors)) {
- scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
- return;
- }
-
- if (buffer_is_zero(inbuf, s->qdev.blocksize)) {
- int flags = (req->cmd.buf[1] & 0x8) ? BDRV_REQ_MAY_UNMAP : 0;
-
- /* The request is used as the AIO opaque value, so add a ref. */
- scsi_req_ref(&r->req);
- block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct,
- nb_sectors * s->qdev.blocksize,
- BLOCK_ACCT_WRITE);
- r->req.aiocb = blk_aio_write_zeroes(s->qdev.conf.blk,
- r->req.cmd.lba * (s->qdev.blocksize / 512),
- nb_sectors * (s->qdev.blocksize / 512),
- flags, scsi_aio_complete, r);
- return;
- }
-
- data = g_new0(WriteSameCBData, 1);
- data->r = r;
- data->sector = r->req.cmd.lba * (s->qdev.blocksize / 512);
- data->nb_sectors = nb_sectors * (s->qdev.blocksize / 512);
- data->iov.iov_len = MIN(data->nb_sectors * 512, SCSI_WRITE_SAME_MAX);
- data->iov.iov_base = buf = blk_blockalign(s->qdev.conf.blk,
- data->iov.iov_len);
- qemu_iovec_init_external(&data->qiov, &data->iov, 1);
-
- for (i = 0; i < data->iov.iov_len; i += s->qdev.blocksize) {
- memcpy(&buf[i], inbuf, s->qdev.blocksize);
- }
-
- scsi_req_ref(&r->req);
- block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct,
- data->iov.iov_len, BLOCK_ACCT_WRITE);
- r->req.aiocb = blk_aio_writev(s->qdev.conf.blk, data->sector,
- &data->qiov, data->iov.iov_len / 512,
- scsi_write_same_complete, data);
-}
-
-static void scsi_disk_emulate_write_data(SCSIRequest *req)
-{
- SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
-
- if (r->iov.iov_len) {
- int buflen = r->iov.iov_len;
- DPRINTF("Write buf_len=%d\n", buflen);
- r->iov.iov_len = 0;
- scsi_req_data(&r->req, buflen);
- return;
- }
-
- switch (req->cmd.buf[0]) {
- case MODE_SELECT:
- case MODE_SELECT_10:
- /* This also clears the sense buffer for REQUEST SENSE. */
- scsi_disk_emulate_mode_select(r, r->iov.iov_base);
- break;
-
- case UNMAP:
- scsi_disk_emulate_unmap(r, r->iov.iov_base);
- break;
-
- case VERIFY_10:
- case VERIFY_12:
- case VERIFY_16:
- if (r->req.status == -1) {
- scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
- }
- break;
-
- case WRITE_SAME_10:
- case WRITE_SAME_16:
- scsi_disk_emulate_write_same(r, r->iov.iov_base);
- break;
-
- default:
- abort();
- }
-}
-
-static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
-{
- SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
- uint64_t nb_sectors;
- uint8_t *outbuf;
- int buflen;
-
- switch (req->cmd.buf[0]) {
- case INQUIRY:
- case MODE_SENSE:
- case MODE_SENSE_10:
- case RESERVE:
- case RESERVE_10:
- case RELEASE:
- case RELEASE_10:
- case START_STOP:
- case ALLOW_MEDIUM_REMOVAL:
- case GET_CONFIGURATION:
- case GET_EVENT_STATUS_NOTIFICATION:
- case MECHANISM_STATUS:
- case REQUEST_SENSE:
- break;
-
- default:
- if (s->tray_open || !blk_is_inserted(s->qdev.conf.blk)) {
- scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
- return 0;
- }
- break;
- }
-
- /*
- * FIXME: we shouldn't return anything bigger than 4k, but the code
- * requires the buffer to be as big as req->cmd.xfer in several
- * places. So, do not allow CDBs with a very large ALLOCATION
- * LENGTH. The real fix would be to modify scsi_read_data and
- * dma_buf_read, so that they return data beyond the buflen
- * as all zeros.
- */
- if (req->cmd.xfer > 65536) {
- goto illegal_request;
- }
- r->buflen = MAX(4096, req->cmd.xfer);
-
- if (!r->iov.iov_base) {
- r->iov.iov_base = blk_blockalign(s->qdev.conf.blk, r->buflen);
- }
-
- buflen = req->cmd.xfer;
- outbuf = r->iov.iov_base;
- memset(outbuf, 0, r->buflen);
- switch (req->cmd.buf[0]) {
- case TEST_UNIT_READY:
- assert(!s->tray_open && blk_is_inserted(s->qdev.conf.blk));
- break;
- case INQUIRY:
- buflen = scsi_disk_emulate_inquiry(req, outbuf);
- if (buflen < 0) {
- goto illegal_request;
- }
- break;
- case MODE_SENSE:
- case MODE_SENSE_10:
- buflen = scsi_disk_emulate_mode_sense(r, outbuf);
- if (buflen < 0) {
- goto illegal_request;
- }
- break;
- case READ_TOC:
- buflen = scsi_disk_emulate_read_toc(req, outbuf);
- if (buflen < 0) {
- goto illegal_request;
- }
- break;
- case RESERVE:
- if (req->cmd.buf[1] & 1) {
- goto illegal_request;
- }
- break;
- case RESERVE_10:
- if (req->cmd.buf[1] & 3) {
- goto illegal_request;
- }
- break;
- case RELEASE:
- if (req->cmd.buf[1] & 1) {
- goto illegal_request;
- }
- break;
- case RELEASE_10:
- if (req->cmd.buf[1] & 3) {
- goto illegal_request;
- }
- break;
- case START_STOP:
- if (scsi_disk_emulate_start_stop(r) < 0) {
- return 0;
- }
- break;
- case ALLOW_MEDIUM_REMOVAL:
- s->tray_locked = req->cmd.buf[4] & 1;
- blk_lock_medium(s->qdev.conf.blk, req->cmd.buf[4] & 1);
- break;
- case READ_CAPACITY_10:
- /* The normal LEN field for this command is zero. */
- memset(outbuf, 0, 8);
- blk_get_geometry(s->qdev.conf.blk, &nb_sectors);
- if (!nb_sectors) {
- scsi_check_condition(r, SENSE_CODE(LUN_NOT_READY));
- return 0;
- }
- if ((req->cmd.buf[8] & 1) == 0 && req->cmd.lba) {
- goto illegal_request;
- }
- nb_sectors /= s->qdev.blocksize / 512;
- /* Returned value is the address of the last sector. */
- nb_sectors--;
- /* Remember the new size for read/write sanity checking. */
- s->qdev.max_lba = nb_sectors;
- /* Clip to 2TB, instead of returning capacity modulo 2TB. */
- if (nb_sectors > UINT32_MAX) {
- nb_sectors = UINT32_MAX;
- }
- outbuf[0] = (nb_sectors >> 24) & 0xff;
- outbuf[1] = (nb_sectors >> 16) & 0xff;
- outbuf[2] = (nb_sectors >> 8) & 0xff;
- outbuf[3] = nb_sectors & 0xff;
- outbuf[4] = 0;
- outbuf[5] = 0;
- outbuf[6] = s->qdev.blocksize >> 8;
- outbuf[7] = 0;
- break;
- case REQUEST_SENSE:
- /* Just return "NO SENSE". */
- buflen = scsi_build_sense(NULL, 0, outbuf, r->buflen,
- (req->cmd.buf[1] & 1) == 0);
- if (buflen < 0) {
- goto illegal_request;
- }
- break;
- case MECHANISM_STATUS:
- buflen = scsi_emulate_mechanism_status(s, outbuf);
- if (buflen < 0) {
- goto illegal_request;
- }
- break;
- case GET_CONFIGURATION:
- buflen = scsi_get_configuration(s, outbuf);
- if (buflen < 0) {
- goto illegal_request;
- }
- break;
- case GET_EVENT_STATUS_NOTIFICATION:
- buflen = scsi_get_event_status_notification(s, r, outbuf);
- if (buflen < 0) {
- goto illegal_request;
- }
- break;
- case READ_DISC_INFORMATION:
- buflen = scsi_read_disc_information(s, r, outbuf);
- if (buflen < 0) {
- goto illegal_request;
- }
- break;
- case READ_DVD_STRUCTURE:
- buflen = scsi_read_dvd_structure(s, r, outbuf);
- if (buflen < 0) {
- goto illegal_request;
- }
- break;
- case SERVICE_ACTION_IN_16:
- /* Service Action In subcommands. */
- if ((req->cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) {
- DPRINTF("SAI READ CAPACITY(16)\n");
- memset(outbuf, 0, req->cmd.xfer);
- blk_get_geometry(s->qdev.conf.blk, &nb_sectors);
- if (!nb_sectors) {
- scsi_check_condition(r, SENSE_CODE(LUN_NOT_READY));
- return 0;
- }
- if ((req->cmd.buf[14] & 1) == 0 && req->cmd.lba) {
- goto illegal_request;
- }
- nb_sectors /= s->qdev.blocksize / 512;
- /* Returned value is the address of the last sector. */
- nb_sectors--;
- /* Remember the new size for read/write sanity checking. */
- s->qdev.max_lba = nb_sectors;
- outbuf[0] = (nb_sectors >> 56) & 0xff;
- outbuf[1] = (nb_sectors >> 48) & 0xff;
- outbuf[2] = (nb_sectors >> 40) & 0xff;
- outbuf[3] = (nb_sectors >> 32) & 0xff;
- outbuf[4] = (nb_sectors >> 24) & 0xff;
- outbuf[5] = (nb_sectors >> 16) & 0xff;
- outbuf[6] = (nb_sectors >> 8) & 0xff;
- outbuf[7] = nb_sectors & 0xff;
- outbuf[8] = 0;
- outbuf[9] = 0;
- outbuf[10] = s->qdev.blocksize >> 8;
- outbuf[11] = 0;
- outbuf[12] = 0;
- outbuf[13] = get_physical_block_exp(&s->qdev.conf);
-
- /* set TPE bit if the format supports discard */
- if (s->qdev.conf.discard_granularity) {
- outbuf[14] = 0x80;
- }
-
- /* Protection, exponent and lowest lba field left blank. */
- break;
- }
- DPRINTF("Unsupported Service Action In\n");
- goto illegal_request;
- case SYNCHRONIZE_CACHE:
- /* The request is used as the AIO opaque value, so add a ref. */
- scsi_req_ref(&r->req);
- block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct, 0,
- BLOCK_ACCT_FLUSH);
- r->req.aiocb = blk_aio_flush(s->qdev.conf.blk, scsi_aio_complete, r);
- return 0;
- case SEEK_10:
- DPRINTF("Seek(10) (sector %" PRId64 ")\n", r->req.cmd.lba);
- if (r->req.cmd.lba > s->qdev.max_lba) {
- goto illegal_lba;
- }
- break;
- case MODE_SELECT:
- DPRINTF("Mode Select(6) (len %lu)\n", (long)r->req.cmd.xfer);
- break;
- case MODE_SELECT_10:
- DPRINTF("Mode Select(10) (len %lu)\n", (long)r->req.cmd.xfer);
- break;
- case UNMAP:
- DPRINTF("Unmap (len %lu)\n", (long)r->req.cmd.xfer);
- break;
- case VERIFY_10:
- case VERIFY_12:
- case VERIFY_16:
- DPRINTF("Verify (bytchk %d)\n", (req->cmd.buf[1] >> 1) & 3);
- if (req->cmd.buf[1] & 6) {
- goto illegal_request;
- }
- break;
- case WRITE_SAME_10:
- case WRITE_SAME_16:
- DPRINTF("WRITE SAME %d (len %lu)\n",
- req->cmd.buf[0] == WRITE_SAME_10 ? 10 : 16,
- (long)r->req.cmd.xfer);
- break;
- default:
- DPRINTF("Unknown SCSI command (%2.2x=%s)\n", buf[0],
- scsi_command_name(buf[0]));
- scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));
- return 0;
- }
- assert(!r->req.aiocb);
- r->iov.iov_len = MIN(r->buflen, req->cmd.xfer);
- if (r->iov.iov_len == 0) {
- scsi_req_complete(&r->req, GOOD);
- }
- if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
- assert(r->iov.iov_len == req->cmd.xfer);
- return -r->iov.iov_len;
- } else {
- return r->iov.iov_len;
- }
-
-illegal_request:
- if (r->req.status == -1) {
- scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
- }
- return 0;
-
-illegal_lba:
- scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
- return 0;
-}
-
-/* Execute a scsi command. Returns the length of the data expected by the
- command. This will be Positive for data transfers from the device
- (eg. disk reads), negative for transfers to the device (eg. disk writes),
- and zero if the command does not transfer any data. */
-
-static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf)
-{
- SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
- uint32_t len;
- uint8_t command;
-
- command = buf[0];
-
- if (s->tray_open || !blk_is_inserted(s->qdev.conf.blk)) {
- scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
- return 0;
- }
-
- len = scsi_data_cdb_xfer(r->req.cmd.buf);
- switch (command) {
- case READ_6:
- case READ_10:
- case READ_12:
- case READ_16:
- DPRINTF("Read (sector %" PRId64 ", count %u)\n", r->req.cmd.lba, len);
- if (r->req.cmd.buf[1] & 0xe0) {
- goto illegal_request;
- }
- if (!check_lba_range(s, r->req.cmd.lba, len)) {
- goto illegal_lba;
- }
- r->sector = r->req.cmd.lba * (s->qdev.blocksize / 512);
- r->sector_count = len * (s->qdev.blocksize / 512);
- break;
- case WRITE_6:
- case WRITE_10:
- case WRITE_12:
- case WRITE_16:
- case WRITE_VERIFY_10:
- case WRITE_VERIFY_12:
- case WRITE_VERIFY_16:
- if (blk_is_read_only(s->qdev.conf.blk)) {
- scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED));
- return 0;
- }
- DPRINTF("Write %s(sector %" PRId64 ", count %u)\n",
- (command & 0xe) == 0xe ? "And Verify " : "",
- r->req.cmd.lba, len);
- if (r->req.cmd.buf[1] & 0xe0) {
- goto illegal_request;
- }
- if (!check_lba_range(s, r->req.cmd.lba, len)) {
- goto illegal_lba;
- }
- r->sector = r->req.cmd.lba * (s->qdev.blocksize / 512);
- r->sector_count = len * (s->qdev.blocksize / 512);
- break;
- default:
- abort();
- illegal_request:
- scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
- return 0;
- illegal_lba:
- scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
- return 0;
- }
- if (r->sector_count == 0) {
- scsi_req_complete(&r->req, GOOD);
- }
- assert(r->iov.iov_len == 0);
- if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
- return -r->sector_count * 512;
- } else {
- return r->sector_count * 512;
- }
-}
-
-static void scsi_disk_reset(DeviceState *dev)
-{
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev.qdev, dev);
- uint64_t nb_sectors;
-
- scsi_device_purge_requests(&s->qdev, SENSE_CODE(RESET));
-
- blk_get_geometry(s->qdev.conf.blk, &nb_sectors);
- nb_sectors /= s->qdev.blocksize / 512;
- if (nb_sectors) {
- nb_sectors--;
- }
- s->qdev.max_lba = nb_sectors;
- /* reset tray statuses */
- s->tray_locked = 0;
- s->tray_open = 0;
-}
-
-static void scsi_disk_resize_cb(void *opaque)
-{
- SCSIDiskState *s = opaque;
-
- /* SPC lists this sense code as available only for
- * direct-access devices.
- */
- if (s->qdev.type == TYPE_DISK) {
- scsi_device_report_change(&s->qdev, SENSE_CODE(CAPACITY_CHANGED));
- }
-}
-
-static void scsi_cd_change_media_cb(void *opaque, bool load)
-{
- SCSIDiskState *s = opaque;
-
- /*
- * When a CD gets changed, we have to report an ejected state and
- * then a loaded state to guests so that they detect tray
- * open/close and media change events. Guests that do not use
- * GET_EVENT_STATUS_NOTIFICATION to detect such tray open/close
- * states rely on this behavior.
- *
- * media_changed governs the state machine used for unit attention
- * report. media_event is used by GET EVENT STATUS NOTIFICATION.
- */
- s->media_changed = load;
- s->tray_open = !load;
- scsi_device_set_ua(&s->qdev, SENSE_CODE(UNIT_ATTENTION_NO_MEDIUM));
- s->media_event = true;
- s->eject_request = false;
-}
-
-static void scsi_cd_eject_request_cb(void *opaque, bool force)
-{
- SCSIDiskState *s = opaque;
-
- s->eject_request = true;
- if (force) {
- s->tray_locked = false;
- }
-}
-
-static bool scsi_cd_is_tray_open(void *opaque)
-{
- return ((SCSIDiskState *)opaque)->tray_open;
-}
-
-static bool scsi_cd_is_medium_locked(void *opaque)
-{
- return ((SCSIDiskState *)opaque)->tray_locked;
-}
-
-static const BlockDevOps scsi_disk_removable_block_ops = {
- .change_media_cb = scsi_cd_change_media_cb,
- .eject_request_cb = scsi_cd_eject_request_cb,
- .is_tray_open = scsi_cd_is_tray_open,
- .is_medium_locked = scsi_cd_is_medium_locked,
-
- .resize_cb = scsi_disk_resize_cb,
-};
-
-static const BlockDevOps scsi_disk_block_ops = {
- .resize_cb = scsi_disk_resize_cb,
-};
-
-static void scsi_disk_unit_attention_reported(SCSIDevice *dev)
-{
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
- if (s->media_changed) {
- s->media_changed = false;
- scsi_device_set_ua(&s->qdev, SENSE_CODE(MEDIUM_CHANGED));
- }
-}
-
-static void scsi_realize(SCSIDevice *dev, Error **errp)
-{
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
- Error *err = NULL;
-
- if (!s->qdev.conf.blk) {
- error_setg(errp, "drive property not set");
- return;
- }
-
- if (!(s->features & (1 << SCSI_DISK_F_REMOVABLE)) &&
- !blk_is_inserted(s->qdev.conf.blk)) {
- error_setg(errp, "Device needs media, but drive is empty");
- return;
- }
-
- blkconf_serial(&s->qdev.conf, &s->serial);
- blkconf_blocksizes(&s->qdev.conf);
- if (dev->type == TYPE_DISK) {
- blkconf_geometry(&dev->conf, NULL, 65535, 255, 255, &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- }
-
- if (s->qdev.conf.discard_granularity == -1) {
- s->qdev.conf.discard_granularity =
- MAX(s->qdev.conf.logical_block_size, DEFAULT_DISCARD_GRANULARITY);
- }
-
- if (!s->version) {
- s->version = g_strdup(qemu_hw_version());
- }
- if (!s->vendor) {
- s->vendor = g_strdup("QEMU");
- }
-
- if (blk_is_sg(s->qdev.conf.blk)) {
- error_setg(errp, "unwanted /dev/sg*");
- return;
- }
-
- if ((s->features & (1 << SCSI_DISK_F_REMOVABLE)) &&
- !(s->features & (1 << SCSI_DISK_F_NO_REMOVABLE_DEVOPS))) {
- blk_set_dev_ops(s->qdev.conf.blk, &scsi_disk_removable_block_ops, s);
- } else {
- blk_set_dev_ops(s->qdev.conf.blk, &scsi_disk_block_ops, s);
- }
- blk_set_guest_block_size(s->qdev.conf.blk, s->qdev.blocksize);
-
- blk_iostatus_enable(s->qdev.conf.blk);
-}
-
-static void scsi_hd_realize(SCSIDevice *dev, Error **errp)
-{
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
- /* can happen for devices without drive. The error message for missing
- * backend will be issued in scsi_realize
- */
- if (s->qdev.conf.blk) {
- blkconf_blocksizes(&s->qdev.conf);
- }
- s->qdev.blocksize = s->qdev.conf.logical_block_size;
- s->qdev.type = TYPE_DISK;
- if (!s->product) {
- s->product = g_strdup("QEMU HARDDISK");
- }
- scsi_realize(&s->qdev, errp);
-}
-
-static void scsi_cd_realize(SCSIDevice *dev, Error **errp)
-{
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
- s->qdev.blocksize = 2048;
- s->qdev.type = TYPE_ROM;
- s->features |= 1 << SCSI_DISK_F_REMOVABLE;
- if (!s->product) {
- s->product = g_strdup("QEMU CD-ROM");
- }
- scsi_realize(&s->qdev, errp);
-}
-
-static void scsi_disk_realize(SCSIDevice *dev, Error **errp)
-{
- DriveInfo *dinfo;
- Error *local_err = NULL;
-
- if (!dev->conf.blk) {
- scsi_realize(dev, &local_err);
- assert(local_err);
- error_propagate(errp, local_err);
- return;
- }
-
- dinfo = blk_legacy_dinfo(dev->conf.blk);
- if (dinfo && dinfo->media_cd) {
- scsi_cd_realize(dev, errp);
- } else {
- scsi_hd_realize(dev, errp);
- }
-}
-
-static const SCSIReqOps scsi_disk_emulate_reqops = {
- .size = sizeof(SCSIDiskReq),
- .free_req = scsi_free_request,
- .send_command = scsi_disk_emulate_command,
- .read_data = scsi_disk_emulate_read_data,
- .write_data = scsi_disk_emulate_write_data,
- .get_buf = scsi_get_buf,
-};
-
-static const SCSIReqOps scsi_disk_dma_reqops = {
- .size = sizeof(SCSIDiskReq),
- .free_req = scsi_free_request,
- .send_command = scsi_disk_dma_command,
- .read_data = scsi_read_data,
- .write_data = scsi_write_data,
- .get_buf = scsi_get_buf,
- .load_request = scsi_disk_load_request,
- .save_request = scsi_disk_save_request,
-};
-
-static const SCSIReqOps *const scsi_disk_reqops_dispatch[256] = {
- [TEST_UNIT_READY] = &scsi_disk_emulate_reqops,
- [INQUIRY] = &scsi_disk_emulate_reqops,
- [MODE_SENSE] = &scsi_disk_emulate_reqops,
- [MODE_SENSE_10] = &scsi_disk_emulate_reqops,
- [START_STOP] = &scsi_disk_emulate_reqops,
- [ALLOW_MEDIUM_REMOVAL] = &scsi_disk_emulate_reqops,
- [READ_CAPACITY_10] = &scsi_disk_emulate_reqops,
- [READ_TOC] = &scsi_disk_emulate_reqops,
- [READ_DVD_STRUCTURE] = &scsi_disk_emulate_reqops,
- [READ_DISC_INFORMATION] = &scsi_disk_emulate_reqops,
- [GET_CONFIGURATION] = &scsi_disk_emulate_reqops,
- [GET_EVENT_STATUS_NOTIFICATION] = &scsi_disk_emulate_reqops,
- [MECHANISM_STATUS] = &scsi_disk_emulate_reqops,
- [SERVICE_ACTION_IN_16] = &scsi_disk_emulate_reqops,
- [REQUEST_SENSE] = &scsi_disk_emulate_reqops,
- [SYNCHRONIZE_CACHE] = &scsi_disk_emulate_reqops,
- [SEEK_10] = &scsi_disk_emulate_reqops,
- [MODE_SELECT] = &scsi_disk_emulate_reqops,
- [MODE_SELECT_10] = &scsi_disk_emulate_reqops,
- [UNMAP] = &scsi_disk_emulate_reqops,
- [WRITE_SAME_10] = &scsi_disk_emulate_reqops,
- [WRITE_SAME_16] = &scsi_disk_emulate_reqops,
- [VERIFY_10] = &scsi_disk_emulate_reqops,
- [VERIFY_12] = &scsi_disk_emulate_reqops,
- [VERIFY_16] = &scsi_disk_emulate_reqops,
-
- [READ_6] = &scsi_disk_dma_reqops,
- [READ_10] = &scsi_disk_dma_reqops,
- [READ_12] = &scsi_disk_dma_reqops,
- [READ_16] = &scsi_disk_dma_reqops,
- [WRITE_6] = &scsi_disk_dma_reqops,
- [WRITE_10] = &scsi_disk_dma_reqops,
- [WRITE_12] = &scsi_disk_dma_reqops,
- [WRITE_16] = &scsi_disk_dma_reqops,
- [WRITE_VERIFY_10] = &scsi_disk_dma_reqops,
- [WRITE_VERIFY_12] = &scsi_disk_dma_reqops,
- [WRITE_VERIFY_16] = &scsi_disk_dma_reqops,
-};
-
-static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
- uint8_t *buf, void *hba_private)
-{
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
- SCSIRequest *req;
- const SCSIReqOps *ops;
- uint8_t command;
-
- command = buf[0];
- ops = scsi_disk_reqops_dispatch[command];
- if (!ops) {
- ops = &scsi_disk_emulate_reqops;
- }
- req = scsi_req_alloc(ops, &s->qdev, tag, lun, hba_private);
-
-#ifdef DEBUG_SCSI
- DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]);
- {
- int i;
- for (i = 1; i < scsi_cdb_length(buf); i++) {
- printf(" 0x%02x", buf[i]);
- }
- printf("\n");
- }
-#endif
-
- return req;
-}
-
-#ifdef __linux__
-static int get_device_type(SCSIDiskState *s)
-{
- uint8_t cmd[16];
- uint8_t buf[36];
- uint8_t sensebuf[8];
- sg_io_hdr_t io_header;
- int ret;
-
- memset(cmd, 0, sizeof(cmd));
- memset(buf, 0, sizeof(buf));
- cmd[0] = INQUIRY;
- cmd[4] = sizeof(buf);
-
- memset(&io_header, 0, sizeof(io_header));
- io_header.interface_id = 'S';
- io_header.dxfer_direction = SG_DXFER_FROM_DEV;
- io_header.dxfer_len = sizeof(buf);
- io_header.dxferp = buf;
- io_header.cmdp = cmd;
- io_header.cmd_len = sizeof(cmd);
- io_header.mx_sb_len = sizeof(sensebuf);
- io_header.sbp = sensebuf;
- io_header.timeout = 6000; /* XXX */
-
- ret = blk_ioctl(s->qdev.conf.blk, SG_IO, &io_header);
- if (ret < 0 || io_header.driver_status || io_header.host_status) {
- return -1;
- }
- s->qdev.type = buf[0];
- if (buf[1] & 0x80) {
- s->features |= 1 << SCSI_DISK_F_REMOVABLE;
- }
- return 0;
-}
-
-static void scsi_block_realize(SCSIDevice *dev, Error **errp)
-{
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
- int sg_version;
- int rc;
-
- if (!s->qdev.conf.blk) {
- error_setg(errp, "drive property not set");
- return;
- }
-
- /* check we are using a driver managing SG_IO (version 3 and after) */
- rc = blk_ioctl(s->qdev.conf.blk, SG_GET_VERSION_NUM, &sg_version);
- if (rc < 0) {
- error_setg(errp, "cannot get SG_IO version number: %s. "
- "Is this a SCSI device?",
- strerror(-rc));
- return;
- }
- if (sg_version < 30000) {
- error_setg(errp, "scsi generic interface too old");
- return;
- }
-
- /* get device type from INQUIRY data */
- rc = get_device_type(s);
- if (rc < 0) {
- error_setg(errp, "INQUIRY failed");
- return;
- }
-
- /* Make a guess for the block size, we'll fix it when the guest sends.
- * READ CAPACITY. If they don't, they likely would assume these sizes
- * anyway. (TODO: check in /sys).
- */
- if (s->qdev.type == TYPE_ROM || s->qdev.type == TYPE_WORM) {
- s->qdev.blocksize = 2048;
- } else {
- s->qdev.blocksize = 512;
- }
-
- /* Makes the scsi-block device not removable by using HMP and QMP eject
- * command.
- */
- s->features |= (1 << SCSI_DISK_F_NO_REMOVABLE_DEVOPS);
-
- scsi_realize(&s->qdev, errp);
- scsi_generic_read_device_identification(&s->qdev);
-}
-
-static bool scsi_block_is_passthrough(SCSIDiskState *s, uint8_t *buf)
-{
- switch (buf[0]) {
- case READ_6:
- case READ_10:
- case READ_12:
- case READ_16:
- case VERIFY_10:
- case VERIFY_12:
- case VERIFY_16:
- case WRITE_6:
- case WRITE_10:
- case WRITE_12:
- case WRITE_16:
- case WRITE_VERIFY_10:
- case WRITE_VERIFY_12:
- case WRITE_VERIFY_16:
- /* If we are not using O_DIRECT, we might read stale data from the
- * host cache if writes were made using other commands than these
- * ones (such as WRITE SAME or EXTENDED COPY, etc.). So, without
- * O_DIRECT everything must go through SG_IO.
- */
- if (!(blk_get_flags(s->qdev.conf.blk) & BDRV_O_NOCACHE)) {
- break;
- }
-
- /* MMC writing cannot be done via pread/pwrite, because it sometimes
- * involves writing beyond the maximum LBA or to negative LBA (lead-in).
- * And once you do these writes, reading from the block device is
- * unreliable, too. It is even possible that reads deliver random data
- * from the host page cache (this is probably a Linux bug).
- *
- * We might use scsi_disk_dma_reqops as long as no writing commands are
- * seen, but performance usually isn't paramount on optical media. So,
- * just make scsi-block operate the same as scsi-generic for them.
- */
- if (s->qdev.type != TYPE_ROM) {
- return false;
- }
- break;
-
- default:
- break;
- }
-
- return true;
-}
-
-
-static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag,
- uint32_t lun, uint8_t *buf,
- void *hba_private)
-{
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
-
- if (scsi_block_is_passthrough(s, buf)) {
- return scsi_req_alloc(&scsi_generic_req_ops, &s->qdev, tag, lun,
- hba_private);
- } else {
- return scsi_req_alloc(&scsi_disk_dma_reqops, &s->qdev, tag, lun,
- hba_private);
- }
-}
-
-static int scsi_block_parse_cdb(SCSIDevice *d, SCSICommand *cmd,
- uint8_t *buf, void *hba_private)
-{
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
-
- if (scsi_block_is_passthrough(s, buf)) {
- return scsi_bus_parse_cdb(&s->qdev, cmd, buf, hba_private);
- } else {
- return scsi_req_parse_cdb(&s->qdev, cmd, buf);
- }
-}
-
-#endif
-
-#define DEFINE_SCSI_DISK_PROPERTIES() \
- DEFINE_BLOCK_PROPERTIES(SCSIDiskState, qdev.conf), \
- DEFINE_PROP_STRING("ver", SCSIDiskState, version), \
- DEFINE_PROP_STRING("serial", SCSIDiskState, serial), \
- DEFINE_PROP_STRING("vendor", SCSIDiskState, vendor), \
- DEFINE_PROP_STRING("product", SCSIDiskState, product)
-
-static Property scsi_hd_properties[] = {
- DEFINE_SCSI_DISK_PROPERTIES(),
- DEFINE_PROP_BIT("removable", SCSIDiskState, features,
- SCSI_DISK_F_REMOVABLE, false),
- DEFINE_PROP_BIT("dpofua", SCSIDiskState, features,
- SCSI_DISK_F_DPOFUA, false),
- DEFINE_PROP_UINT64("wwn", SCSIDiskState, qdev.wwn, 0),
- DEFINE_PROP_UINT64("port_wwn", SCSIDiskState, qdev.port_wwn, 0),
- DEFINE_PROP_UINT16("port_index", SCSIDiskState, port_index, 0),
- DEFINE_PROP_UINT64("max_unmap_size", SCSIDiskState, max_unmap_size,
- DEFAULT_MAX_UNMAP_SIZE),
- DEFINE_PROP_UINT64("max_io_size", SCSIDiskState, max_io_size,
- DEFAULT_MAX_IO_SIZE),
- DEFINE_BLOCK_CHS_PROPERTIES(SCSIDiskState, qdev.conf),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static const VMStateDescription vmstate_scsi_disk_state = {
- .name = "scsi-disk",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_SCSI_DEVICE(qdev, SCSIDiskState),
- VMSTATE_BOOL(media_changed, SCSIDiskState),
- VMSTATE_BOOL(media_event, SCSIDiskState),
- VMSTATE_BOOL(eject_request, SCSIDiskState),
- VMSTATE_BOOL(tray_open, SCSIDiskState),
- VMSTATE_BOOL(tray_locked, SCSIDiskState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void scsi_hd_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
-
- sc->realize = scsi_hd_realize;
- sc->alloc_req = scsi_new_request;
- sc->unit_attention_reported = scsi_disk_unit_attention_reported;
- dc->fw_name = "disk";
- dc->desc = "virtual SCSI disk";
- dc->reset = scsi_disk_reset;
- dc->props = scsi_hd_properties;
- dc->vmsd = &vmstate_scsi_disk_state;
-}
-
-static const TypeInfo scsi_hd_info = {
- .name = "scsi-hd",
- .parent = TYPE_SCSI_DEVICE,
- .instance_size = sizeof(SCSIDiskState),
- .class_init = scsi_hd_class_initfn,
-};
-
-static Property scsi_cd_properties[] = {
- DEFINE_SCSI_DISK_PROPERTIES(),
- DEFINE_PROP_UINT64("wwn", SCSIDiskState, qdev.wwn, 0),
- DEFINE_PROP_UINT64("port_wwn", SCSIDiskState, qdev.port_wwn, 0),
- DEFINE_PROP_UINT16("port_index", SCSIDiskState, port_index, 0),
- DEFINE_PROP_UINT64("max_io_size", SCSIDiskState, max_io_size,
- DEFAULT_MAX_IO_SIZE),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void scsi_cd_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
-
- sc->realize = scsi_cd_realize;
- sc->alloc_req = scsi_new_request;
- sc->unit_attention_reported = scsi_disk_unit_attention_reported;
- dc->fw_name = "disk";
- dc->desc = "virtual SCSI CD-ROM";
- dc->reset = scsi_disk_reset;
- dc->props = scsi_cd_properties;
- dc->vmsd = &vmstate_scsi_disk_state;
-}
-
-static const TypeInfo scsi_cd_info = {
- .name = "scsi-cd",
- .parent = TYPE_SCSI_DEVICE,
- .instance_size = sizeof(SCSIDiskState),
- .class_init = scsi_cd_class_initfn,
-};
-
-#ifdef __linux__
-static Property scsi_block_properties[] = {
- DEFINE_PROP_DRIVE("drive", SCSIDiskState, qdev.conf.blk),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void scsi_block_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
-
- sc->realize = scsi_block_realize;
- sc->alloc_req = scsi_block_new_request;
- sc->parse_cdb = scsi_block_parse_cdb;
- dc->fw_name = "disk";
- dc->desc = "SCSI block device passthrough";
- dc->reset = scsi_disk_reset;
- dc->props = scsi_block_properties;
- dc->vmsd = &vmstate_scsi_disk_state;
-}
-
-static const TypeInfo scsi_block_info = {
- .name = "scsi-block",
- .parent = TYPE_SCSI_DEVICE,
- .instance_size = sizeof(SCSIDiskState),
- .class_init = scsi_block_class_initfn,
-};
-#endif
-
-static Property scsi_disk_properties[] = {
- DEFINE_SCSI_DISK_PROPERTIES(),
- DEFINE_PROP_BIT("removable", SCSIDiskState, features,
- SCSI_DISK_F_REMOVABLE, false),
- DEFINE_PROP_BIT("dpofua", SCSIDiskState, features,
- SCSI_DISK_F_DPOFUA, false),
- DEFINE_PROP_UINT64("wwn", SCSIDiskState, qdev.wwn, 0),
- DEFINE_PROP_UINT64("port_wwn", SCSIDiskState, qdev.port_wwn, 0),
- DEFINE_PROP_UINT16("port_index", SCSIDiskState, port_index, 0),
- DEFINE_PROP_UINT64("max_unmap_size", SCSIDiskState, max_unmap_size,
- DEFAULT_MAX_UNMAP_SIZE),
- DEFINE_PROP_UINT64("max_io_size", SCSIDiskState, max_io_size,
- DEFAULT_MAX_IO_SIZE),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void scsi_disk_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
-
- sc->realize = scsi_disk_realize;
- sc->alloc_req = scsi_new_request;
- sc->unit_attention_reported = scsi_disk_unit_attention_reported;
- dc->fw_name = "disk";
- dc->desc = "virtual SCSI disk or CD-ROM (legacy)";
- dc->reset = scsi_disk_reset;
- dc->props = scsi_disk_properties;
- dc->vmsd = &vmstate_scsi_disk_state;
-}
-
-static const TypeInfo scsi_disk_info = {
- .name = "scsi-disk",
- .parent = TYPE_SCSI_DEVICE,
- .instance_size = sizeof(SCSIDiskState),
- .class_init = scsi_disk_class_initfn,
-};
-
-static void scsi_disk_register_types(void)
-{
- type_register_static(&scsi_hd_info);
- type_register_static(&scsi_cd_info);
-#ifdef __linux__
- type_register_static(&scsi_block_info);
-#endif
- type_register_static(&scsi_disk_info);
-}
-
-type_init(scsi_disk_register_types)
diff --git a/qemu/hw/scsi/scsi-generic.c b/qemu/hw/scsi/scsi-generic.c
deleted file mode 100644
index 7459465f6..000000000
--- a/qemu/hw/scsi/scsi-generic.c
+++ /dev/null
@@ -1,616 +0,0 @@
-/*
- * Generic SCSI Device support
- *
- * Copyright (c) 2007 Bull S.A.S.
- * Based on code by Paul Brook
- * Based on code by Fabrice Bellard
- *
- * Written by Laurent Vivier <Laurent.Vivier@bull.net>
- *
- * This code is licensed under the LGPL.
- *
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "qemu/error-report.h"
-#include "hw/scsi/scsi.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
-
-#ifdef __linux__
-
-//#define DEBUG_SCSI
-
-#ifdef DEBUG_SCSI
-#define DPRINTF(fmt, ...) \
-do { printf("scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#endif
-
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
-
-#include <scsi/sg.h>
-#include "block/scsi.h"
-
-#define SG_ERR_DRIVER_TIMEOUT 0x06
-#define SG_ERR_DRIVER_SENSE 0x08
-
-#define SG_ERR_DID_OK 0x00
-#define SG_ERR_DID_NO_CONNECT 0x01
-#define SG_ERR_DID_BUS_BUSY 0x02
-#define SG_ERR_DID_TIME_OUT 0x03
-
-#ifndef MAX_UINT
-#define MAX_UINT ((unsigned int)-1)
-#endif
-
-typedef struct SCSIGenericReq {
- SCSIRequest req;
- uint8_t *buf;
- int buflen;
- int len;
- sg_io_hdr_t io_header;
-} SCSIGenericReq;
-
-static void scsi_generic_save_request(QEMUFile *f, SCSIRequest *req)
-{
- SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
-
- qemu_put_sbe32s(f, &r->buflen);
- if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) {
- assert(!r->req.sg);
- qemu_put_buffer(f, r->buf, r->req.cmd.xfer);
- }
-}
-
-static void scsi_generic_load_request(QEMUFile *f, SCSIRequest *req)
-{
- SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
-
- qemu_get_sbe32s(f, &r->buflen);
- if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) {
- assert(!r->req.sg);
- qemu_get_buffer(f, r->buf, r->req.cmd.xfer);
- }
-}
-
-static void scsi_free_request(SCSIRequest *req)
-{
- SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
-
- g_free(r->buf);
-}
-
-/* Helper function for command completion. */
-static void scsi_command_complete_noio(SCSIGenericReq *r, int ret)
-{
- int status;
-
- assert(r->req.aiocb == NULL);
-
- if (r->req.io_canceled) {
- scsi_req_cancel_complete(&r->req);
- goto done;
- }
- if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
- r->req.sense_len = r->io_header.sb_len_wr;
- }
-
- if (ret != 0) {
- switch (ret) {
- case -EDOM:
- status = TASK_SET_FULL;
- break;
- case -ENOMEM:
- status = CHECK_CONDITION;
- scsi_req_build_sense(&r->req, SENSE_CODE(TARGET_FAILURE));
- break;
- default:
- status = CHECK_CONDITION;
- scsi_req_build_sense(&r->req, SENSE_CODE(IO_ERROR));
- break;
- }
- } else {
- if (r->io_header.host_status == SG_ERR_DID_NO_CONNECT ||
- r->io_header.host_status == SG_ERR_DID_BUS_BUSY ||
- r->io_header.host_status == SG_ERR_DID_TIME_OUT ||
- (r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT)) {
- status = BUSY;
- BADF("Driver Timeout\n");
- } else if (r->io_header.host_status) {
- status = CHECK_CONDITION;
- scsi_req_build_sense(&r->req, SENSE_CODE(I_T_NEXUS_LOSS));
- } else if (r->io_header.status) {
- status = r->io_header.status;
- } else if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
- status = CHECK_CONDITION;
- } else {
- status = GOOD;
- }
- }
- DPRINTF("Command complete 0x%p tag=0x%x status=%d\n",
- r, r->req.tag, status);
-
- scsi_req_complete(&r->req, status);
-done:
- scsi_req_unref(&r->req);
-}
-
-static void scsi_command_complete(void *opaque, int ret)
-{
- SCSIGenericReq *r = (SCSIGenericReq *)opaque;
-
- assert(r->req.aiocb != NULL);
- r->req.aiocb = NULL;
- scsi_command_complete_noio(r, ret);
-}
-
-static int execute_command(BlockBackend *blk,
- SCSIGenericReq *r, int direction,
- BlockCompletionFunc *complete)
-{
- r->io_header.interface_id = 'S';
- r->io_header.dxfer_direction = direction;
- r->io_header.dxferp = r->buf;
- r->io_header.dxfer_len = r->buflen;
- r->io_header.cmdp = r->req.cmd.buf;
- r->io_header.cmd_len = r->req.cmd.len;
- r->io_header.mx_sb_len = sizeof(r->req.sense);
- r->io_header.sbp = r->req.sense;
- r->io_header.timeout = MAX_UINT;
- r->io_header.usr_ptr = r;
- r->io_header.flags |= SG_FLAG_DIRECT_IO;
-
- r->req.aiocb = blk_aio_ioctl(blk, SG_IO, &r->io_header, complete, r);
- if (r->req.aiocb == NULL) {
- return -EIO;
- }
-
- return 0;
-}
-
-static void scsi_read_complete(void * opaque, int ret)
-{
- SCSIGenericReq *r = (SCSIGenericReq *)opaque;
- SCSIDevice *s = r->req.dev;
- int len;
-
- assert(r->req.aiocb != NULL);
- r->req.aiocb = NULL;
-
- if (ret || r->req.io_canceled) {
- scsi_command_complete_noio(r, ret);
- return;
- }
-
- len = r->io_header.dxfer_len - r->io_header.resid;
- DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, len);
-
- r->len = -1;
- if (len == 0) {
- scsi_command_complete_noio(r, 0);
- return;
- }
-
- /* Snoop READ CAPACITY output to set the blocksize. */
- if (r->req.cmd.buf[0] == READ_CAPACITY_10 &&
- (ldl_be_p(&r->buf[0]) != 0xffffffffU || s->max_lba == 0)) {
- s->blocksize = ldl_be_p(&r->buf[4]);
- s->max_lba = ldl_be_p(&r->buf[0]) & 0xffffffffULL;
- } else if (r->req.cmd.buf[0] == SERVICE_ACTION_IN_16 &&
- (r->req.cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) {
- s->blocksize = ldl_be_p(&r->buf[8]);
- s->max_lba = ldq_be_p(&r->buf[0]);
- }
- blk_set_guest_block_size(s->conf.blk, s->blocksize);
-
- /* Patch MODE SENSE device specific parameters if the BDS is opened
- * readonly.
- */
- if ((s->type == TYPE_DISK || s->type == TYPE_TAPE) &&
- blk_is_read_only(s->conf.blk) &&
- (r->req.cmd.buf[0] == MODE_SENSE ||
- r->req.cmd.buf[0] == MODE_SENSE_10) &&
- (r->req.cmd.buf[1] & 0x8) == 0) {
- if (r->req.cmd.buf[0] == MODE_SENSE) {
- r->buf[2] |= 0x80;
- } else {
- r->buf[3] |= 0x80;
- }
- }
- scsi_req_data(&r->req, len);
- scsi_req_unref(&r->req);
-}
-
-/* Read more data from scsi device into buffer. */
-static void scsi_read_data(SCSIRequest *req)
-{
- SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
- SCSIDevice *s = r->req.dev;
- int ret;
-
- DPRINTF("scsi_read_data 0x%x\n", req->tag);
-
- /* The request is used as the AIO opaque value, so add a ref. */
- scsi_req_ref(&r->req);
- if (r->len == -1) {
- scsi_command_complete_noio(r, 0);
- return;
- }
-
- ret = execute_command(s->conf.blk, r, SG_DXFER_FROM_DEV,
- scsi_read_complete);
- if (ret < 0) {
- scsi_command_complete_noio(r, ret);
- }
-}
-
-static void scsi_write_complete(void * opaque, int ret)
-{
- SCSIGenericReq *r = (SCSIGenericReq *)opaque;
- SCSIDevice *s = r->req.dev;
-
- DPRINTF("scsi_write_complete() ret = %d\n", ret);
-
- assert(r->req.aiocb != NULL);
- r->req.aiocb = NULL;
-
- if (ret || r->req.io_canceled) {
- scsi_command_complete_noio(r, ret);
- return;
- }
-
- if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 &&
- s->type == TYPE_TAPE) {
- s->blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11];
- DPRINTF("block size %d\n", s->blocksize);
- }
-
- scsi_command_complete_noio(r, ret);
-}
-
-/* Write data to a scsi device. Returns nonzero on failure.
- The transfer may complete asynchronously. */
-static void scsi_write_data(SCSIRequest *req)
-{
- SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
- SCSIDevice *s = r->req.dev;
- int ret;
-
- DPRINTF("scsi_write_data 0x%x\n", req->tag);
- if (r->len == 0) {
- r->len = r->buflen;
- scsi_req_data(&r->req, r->len);
- return;
- }
-
- /* The request is used as the AIO opaque value, so add a ref. */
- scsi_req_ref(&r->req);
- ret = execute_command(s->conf.blk, r, SG_DXFER_TO_DEV, scsi_write_complete);
- if (ret < 0) {
- scsi_command_complete_noio(r, ret);
- }
-}
-
-/* Return a pointer to the data buffer. */
-static uint8_t *scsi_get_buf(SCSIRequest *req)
-{
- SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
-
- return r->buf;
-}
-
-/* Execute a scsi command. Returns the length of the data expected by the
- command. This will be Positive for data transfers from the device
- (eg. disk reads), negative for transfers to the device (eg. disk writes),
- and zero if the command does not transfer any data. */
-
-static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
-{
- SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
- SCSIDevice *s = r->req.dev;
- int ret;
-
-#ifdef DEBUG_SCSI
- {
- int i;
- for (i = 1; i < r->req.cmd.len; i++) {
- printf(" 0x%02x", cmd[i]);
- }
- printf("\n");
- }
-#endif
-
- if (r->req.cmd.xfer == 0) {
- g_free(r->buf);
- r->buflen = 0;
- r->buf = NULL;
- /* The request is used as the AIO opaque value, so add a ref. */
- scsi_req_ref(&r->req);
- ret = execute_command(s->conf.blk, r, SG_DXFER_NONE,
- scsi_command_complete);
- if (ret < 0) {
- scsi_command_complete_noio(r, ret);
- return 0;
- }
- return 0;
- }
-
- if (r->buflen != r->req.cmd.xfer) {
- g_free(r->buf);
- r->buf = g_malloc(r->req.cmd.xfer);
- r->buflen = r->req.cmd.xfer;
- }
-
- memset(r->buf, 0, r->buflen);
- r->len = r->req.cmd.xfer;
- if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
- r->len = 0;
- return -r->req.cmd.xfer;
- } else {
- return r->req.cmd.xfer;
- }
-}
-
-static int read_naa_id(const uint8_t *p, uint64_t *p_wwn)
-{
- int i;
-
- if ((p[1] & 0xF) == 3) {
- /* NAA designator type */
- if (p[3] != 8) {
- return -EINVAL;
- }
- *p_wwn = ldq_be_p(p + 4);
- return 0;
- }
-
- if ((p[1] & 0xF) == 8) {
- /* SCSI name string designator type */
- if (p[3] < 20 || memcmp(&p[4], "naa.", 4)) {
- return -EINVAL;
- }
- if (p[3] > 20 && p[24] != ',') {
- return -EINVAL;
- }
- *p_wwn = 0;
- for (i = 8; i < 24; i++) {
- char c = toupper(p[i]);
- c -= (c >= '0' && c <= '9' ? '0' : 'A' - 10);
- *p_wwn = (*p_wwn << 4) | c;
- }
- return 0;
- }
-
- return -EINVAL;
-}
-
-void scsi_generic_read_device_identification(SCSIDevice *s)
-{
- uint8_t cmd[6];
- uint8_t buf[250];
- uint8_t sensebuf[8];
- sg_io_hdr_t io_header;
- int ret;
- int i, len;
-
- memset(cmd, 0, sizeof(cmd));
- memset(buf, 0, sizeof(buf));
- cmd[0] = INQUIRY;
- cmd[1] = 1;
- cmd[2] = 0x83;
- cmd[4] = sizeof(buf);
-
- memset(&io_header, 0, sizeof(io_header));
- io_header.interface_id = 'S';
- io_header.dxfer_direction = SG_DXFER_FROM_DEV;
- io_header.dxfer_len = sizeof(buf);
- io_header.dxferp = buf;
- io_header.cmdp = cmd;
- io_header.cmd_len = sizeof(cmd);
- io_header.mx_sb_len = sizeof(sensebuf);
- io_header.sbp = sensebuf;
- io_header.timeout = 6000; /* XXX */
-
- ret = blk_ioctl(s->conf.blk, SG_IO, &io_header);
- if (ret < 0 || io_header.driver_status || io_header.host_status) {
- return;
- }
-
- len = MIN((buf[2] << 8) | buf[3], sizeof(buf) - 4);
- for (i = 0; i + 3 <= len; ) {
- const uint8_t *p = &buf[i + 4];
- uint64_t wwn;
-
- if (i + (p[3] + 4) > len) {
- break;
- }
-
- if ((p[1] & 0x10) == 0) {
- /* Associated with the logical unit */
- if (read_naa_id(p, &wwn) == 0) {
- s->wwn = wwn;
- }
- } else if ((p[1] & 0x10) == 0x10) {
- /* Associated with the target port */
- if (read_naa_id(p, &wwn) == 0) {
- s->port_wwn = wwn;
- }
- }
-
- i += p[3] + 4;
- }
-}
-
-static int get_stream_blocksize(BlockBackend *blk)
-{
- uint8_t cmd[6];
- uint8_t buf[12];
- uint8_t sensebuf[8];
- sg_io_hdr_t io_header;
- int ret;
-
- memset(cmd, 0, sizeof(cmd));
- memset(buf, 0, sizeof(buf));
- cmd[0] = MODE_SENSE;
- cmd[4] = sizeof(buf);
-
- memset(&io_header, 0, sizeof(io_header));
- io_header.interface_id = 'S';
- io_header.dxfer_direction = SG_DXFER_FROM_DEV;
- io_header.dxfer_len = sizeof(buf);
- io_header.dxferp = buf;
- io_header.cmdp = cmd;
- io_header.cmd_len = sizeof(cmd);
- io_header.mx_sb_len = sizeof(sensebuf);
- io_header.sbp = sensebuf;
- io_header.timeout = 6000; /* XXX */
-
- ret = blk_ioctl(blk, SG_IO, &io_header);
- if (ret < 0 || io_header.driver_status || io_header.host_status) {
- return -1;
- }
- return (buf[9] << 16) | (buf[10] << 8) | buf[11];
-}
-
-static void scsi_generic_reset(DeviceState *dev)
-{
- SCSIDevice *s = SCSI_DEVICE(dev);
-
- scsi_device_purge_requests(s, SENSE_CODE(RESET));
-}
-
-static void scsi_generic_realize(SCSIDevice *s, Error **errp)
-{
- int rc;
- int sg_version;
- struct sg_scsi_id scsiid;
-
- if (!s->conf.blk) {
- error_setg(errp, "drive property not set");
- return;
- }
-
- if (blk_get_on_error(s->conf.blk, 0) != BLOCKDEV_ON_ERROR_ENOSPC) {
- error_setg(errp, "Device doesn't support drive option werror");
- return;
- }
- if (blk_get_on_error(s->conf.blk, 1) != BLOCKDEV_ON_ERROR_REPORT) {
- error_setg(errp, "Device doesn't support drive option rerror");
- return;
- }
-
- /* check we are using a driver managing SG_IO (version 3 and after */
- rc = blk_ioctl(s->conf.blk, SG_GET_VERSION_NUM, &sg_version);
- if (rc < 0) {
- error_setg(errp, "cannot get SG_IO version number: %s. "
- "Is this a SCSI device?",
- strerror(-rc));
- return;
- }
- if (sg_version < 30000) {
- error_setg(errp, "scsi generic interface too old");
- return;
- }
-
- /* get LUN of the /dev/sg? */
- if (blk_ioctl(s->conf.blk, SG_GET_SCSI_ID, &scsiid)) {
- error_setg(errp, "SG_GET_SCSI_ID ioctl failed");
- return;
- }
-
- /* define device state */
- s->type = scsiid.scsi_type;
- DPRINTF("device type %d\n", s->type);
-
- switch (s->type) {
- case TYPE_TAPE:
- s->blocksize = get_stream_blocksize(s->conf.blk);
- if (s->blocksize == -1) {
- s->blocksize = 0;
- }
- break;
-
- /* Make a guess for block devices, we'll fix it when the guest sends.
- * READ CAPACITY. If they don't, they likely would assume these sizes
- * anyway. (TODO: they could also send MODE SENSE).
- */
- case TYPE_ROM:
- case TYPE_WORM:
- s->blocksize = 2048;
- break;
- default:
- s->blocksize = 512;
- break;
- }
-
- DPRINTF("block size %d\n", s->blocksize);
-
- scsi_generic_read_device_identification(s);
-}
-
-const SCSIReqOps scsi_generic_req_ops = {
- .size = sizeof(SCSIGenericReq),
- .free_req = scsi_free_request,
- .send_command = scsi_send_command,
- .read_data = scsi_read_data,
- .write_data = scsi_write_data,
- .get_buf = scsi_get_buf,
- .load_request = scsi_generic_load_request,
- .save_request = scsi_generic_save_request,
-};
-
-static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
- uint8_t *buf, void *hba_private)
-{
- SCSIRequest *req;
-
- req = scsi_req_alloc(&scsi_generic_req_ops, d, tag, lun, hba_private);
- return req;
-}
-
-static Property scsi_generic_properties[] = {
- DEFINE_PROP_DRIVE("drive", SCSIDevice, conf.blk),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static int scsi_generic_parse_cdb(SCSIDevice *dev, SCSICommand *cmd,
- uint8_t *buf, void *hba_private)
-{
- return scsi_bus_parse_cdb(dev, cmd, buf, hba_private);
-}
-
-static void scsi_generic_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
-
- sc->realize = scsi_generic_realize;
- sc->alloc_req = scsi_new_request;
- sc->parse_cdb = scsi_generic_parse_cdb;
- dc->fw_name = "disk";
- dc->desc = "pass through generic scsi device (/dev/sg*)";
- dc->reset = scsi_generic_reset;
- dc->props = scsi_generic_properties;
- dc->vmsd = &vmstate_scsi_device;
-}
-
-static const TypeInfo scsi_generic_info = {
- .name = "scsi-generic",
- .parent = TYPE_SCSI_DEVICE,
- .instance_size = sizeof(SCSIDevice),
- .class_init = scsi_generic_class_initfn,
-};
-
-static void scsi_generic_register_types(void)
-{
- type_register_static(&scsi_generic_info);
-}
-
-type_init(scsi_generic_register_types)
-
-#endif /* __linux__ */
diff --git a/qemu/hw/scsi/spapr_vscsi.c b/qemu/hw/scsi/spapr_vscsi.c
deleted file mode 100644
index b00edf7fd..000000000
--- a/qemu/hw/scsi/spapr_vscsi.c
+++ /dev/null
@@ -1,1304 +0,0 @@
-/*
- * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
- *
- * PAPR Virtual SCSI, aka ibmvscsi
- *
- * Copyright (c) 2010,2011 Benjamin Herrenschmidt, IBM Corporation.
- *
- * 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.
- *
- * TODO:
- *
- * - Cleanups :-)
- * - Sort out better how to assign devices to VSCSI instances
- * - Fix residual counts
- * - Add indirect descriptors support
- * - Maybe do autosense (PAPR seems to mandate it, linux doesn't care)
- */
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/hw.h"
-#include "hw/scsi/scsi.h"
-#include "block/scsi.h"
-#include "srp.h"
-#include "hw/qdev.h"
-#include "hw/ppc/spapr.h"
-#include "hw/ppc/spapr_vio.h"
-#include "viosrp.h"
-
-#include <libfdt.h>
-
-/*#define DEBUG_VSCSI*/
-
-#ifdef DEBUG_VSCSI
-#define DPRINTF(fmt, ...) \
- do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) \
- do { } while (0)
-#endif
-
-/*
- * Virtual SCSI device
- */
-
-/* Random numbers */
-#define VSCSI_MAX_SECTORS 4096
-#define VSCSI_REQ_LIMIT 24
-
-#define SRP_RSP_SENSE_DATA_LEN 18
-
-#define SRP_REPORT_LUNS_WLUN 0xc10100000000000ULL
-
-typedef union vscsi_crq {
- struct viosrp_crq s;
- uint8_t raw[16];
-} vscsi_crq;
-
-typedef struct vscsi_req {
- vscsi_crq crq;
- union viosrp_iu iu;
-
- /* SCSI request tracking */
- SCSIRequest *sreq;
- uint32_t qtag; /* qemu tag != srp tag */
- bool active;
- bool writing;
- bool dma_error;
- uint32_t data_len;
- uint32_t senselen;
- uint8_t sense[SCSI_SENSE_BUF_SIZE];
-
- /* RDMA related bits */
- uint8_t dma_fmt;
- uint16_t local_desc;
- uint16_t total_desc;
- uint16_t cdb_offset;
- uint16_t cur_desc_num;
- uint16_t cur_desc_offset;
-} vscsi_req;
-
-#define TYPE_VIO_SPAPR_VSCSI_DEVICE "spapr-vscsi"
-#define VIO_SPAPR_VSCSI_DEVICE(obj) \
- OBJECT_CHECK(VSCSIState, (obj), TYPE_VIO_SPAPR_VSCSI_DEVICE)
-
-typedef struct {
- VIOsPAPRDevice vdev;
- SCSIBus bus;
- vscsi_req reqs[VSCSI_REQ_LIMIT];
-} VSCSIState;
-
-static struct vscsi_req *vscsi_get_req(VSCSIState *s)
-{
- vscsi_req *req;
- int i;
-
- for (i = 0; i < VSCSI_REQ_LIMIT; i++) {
- req = &s->reqs[i];
- if (!req->active) {
- memset(req, 0, sizeof(*req));
- req->qtag = i;
- req->active = 1;
- return req;
- }
- }
- return NULL;
-}
-
-static struct vscsi_req *vscsi_find_req(VSCSIState *s, uint64_t srp_tag)
-{
- vscsi_req *req;
- int i;
-
- for (i = 0; i < VSCSI_REQ_LIMIT; i++) {
- req = &s->reqs[i];
- if (req->iu.srp.cmd.tag == srp_tag) {
- return req;
- }
- }
- return NULL;
-}
-
-static void vscsi_put_req(vscsi_req *req)
-{
- if (req->sreq != NULL) {
- scsi_req_unref(req->sreq);
- }
- req->sreq = NULL;
- req->active = 0;
-}
-
-static SCSIDevice *vscsi_device_find(SCSIBus *bus, uint64_t srp_lun, int *lun)
-{
- int channel = 0, id = 0;
-
-retry:
- switch (srp_lun >> 62) {
- case 0:
- if ((srp_lun >> 56) != 0) {
- channel = (srp_lun >> 56) & 0x3f;
- id = (srp_lun >> 48) & 0xff;
- srp_lun <<= 16;
- goto retry;
- }
- *lun = (srp_lun >> 48) & 0xff;
- break;
-
- case 1:
- *lun = (srp_lun >> 48) & 0x3fff;
- break;
- case 2:
- channel = (srp_lun >> 53) & 0x7;
- id = (srp_lun >> 56) & 0x3f;
- *lun = (srp_lun >> 48) & 0x1f;
- break;
- case 3:
- *lun = -1;
- return NULL;
- default:
- abort();
- }
-
- return scsi_device_find(bus, channel, id, *lun);
-}
-
-static int vscsi_send_iu(VSCSIState *s, vscsi_req *req,
- uint64_t length, uint8_t format)
-{
- long rc, rc1;
-
- /* First copy the SRP */
- rc = spapr_vio_dma_write(&s->vdev, req->crq.s.IU_data_ptr,
- &req->iu, length);
- if (rc) {
- fprintf(stderr, "vscsi_send_iu: DMA write failure !\n");
- }
-
- req->crq.s.valid = 0x80;
- req->crq.s.format = format;
- req->crq.s.reserved = 0x00;
- req->crq.s.timeout = cpu_to_be16(0x0000);
- req->crq.s.IU_length = cpu_to_be16(length);
- req->crq.s.IU_data_ptr = req->iu.srp.rsp.tag; /* right byte order */
-
- if (rc == 0) {
- req->crq.s.status = VIOSRP_OK;
- } else {
- req->crq.s.status = VIOSRP_ADAPTER_FAIL;
- }
-
- rc1 = spapr_vio_send_crq(&s->vdev, req->crq.raw);
- if (rc1) {
- fprintf(stderr, "vscsi_send_iu: Error sending response\n");
- return rc1;
- }
-
- return rc;
-}
-
-static void vscsi_makeup_sense(VSCSIState *s, vscsi_req *req,
- uint8_t key, uint8_t asc, uint8_t ascq)
-{
- req->senselen = SRP_RSP_SENSE_DATA_LEN;
-
- /* Valid bit and 'current errors' */
- req->sense[0] = (0x1 << 7 | 0x70);
- /* Sense key */
- req->sense[2] = key;
- /* Additional sense length */
- req->sense[7] = 0xa; /* 10 bytes */
- /* Additional sense code */
- req->sense[12] = asc;
- req->sense[13] = ascq;
-}
-
-static int vscsi_send_rsp(VSCSIState *s, vscsi_req *req,
- uint8_t status, int32_t res_in, int32_t res_out)
-{
- union viosrp_iu *iu = &req->iu;
- uint64_t tag = iu->srp.rsp.tag;
- int total_len = sizeof(iu->srp.rsp);
- uint8_t sol_not = iu->srp.cmd.sol_not;
-
- DPRINTF("VSCSI: Sending resp status: 0x%x, "
- "res_in: %d, res_out: %d\n", status, res_in, res_out);
-
- memset(iu, 0, sizeof(struct srp_rsp));
- iu->srp.rsp.opcode = SRP_RSP;
- iu->srp.rsp.req_lim_delta = cpu_to_be32(1);
- iu->srp.rsp.tag = tag;
-
- /* Handle residuals */
- if (res_in < 0) {
- iu->srp.rsp.flags |= SRP_RSP_FLAG_DIUNDER;
- res_in = -res_in;
- } else if (res_in) {
- iu->srp.rsp.flags |= SRP_RSP_FLAG_DIOVER;
- }
- if (res_out < 0) {
- iu->srp.rsp.flags |= SRP_RSP_FLAG_DOUNDER;
- res_out = -res_out;
- } else if (res_out) {
- iu->srp.rsp.flags |= SRP_RSP_FLAG_DOOVER;
- }
- iu->srp.rsp.data_in_res_cnt = cpu_to_be32(res_in);
- iu->srp.rsp.data_out_res_cnt = cpu_to_be32(res_out);
-
- /* We don't do response data */
- /* iu->srp.rsp.flags &= ~SRP_RSP_FLAG_RSPVALID; */
- iu->srp.rsp.resp_data_len = cpu_to_be32(0);
-
- /* Handle success vs. failure */
- iu->srp.rsp.status = status;
- if (status) {
- iu->srp.rsp.sol_not = (sol_not & 0x04) >> 2;
- if (req->senselen) {
- req->iu.srp.rsp.flags |= SRP_RSP_FLAG_SNSVALID;
- req->iu.srp.rsp.sense_data_len = cpu_to_be32(req->senselen);
- memcpy(req->iu.srp.rsp.data, req->sense, req->senselen);
- total_len += req->senselen;
- }
- } else {
- iu->srp.rsp.sol_not = (sol_not & 0x02) >> 1;
- }
-
- vscsi_send_iu(s, req, total_len, VIOSRP_SRP_FORMAT);
- return 0;
-}
-
-static inline struct srp_direct_buf vscsi_swap_desc(struct srp_direct_buf desc)
-{
- desc.va = be64_to_cpu(desc.va);
- desc.len = be32_to_cpu(desc.len);
- return desc;
-}
-
-static int vscsi_fetch_desc(VSCSIState *s, struct vscsi_req *req,
- unsigned n, unsigned buf_offset,
- struct srp_direct_buf *ret)
-{
- struct srp_cmd *cmd = &req->iu.srp.cmd;
-
- switch (req->dma_fmt) {
- case SRP_NO_DATA_DESC: {
- DPRINTF("VSCSI: no data descriptor\n");
- return 0;
- }
- case SRP_DATA_DESC_DIRECT: {
- memcpy(ret, cmd->add_data + req->cdb_offset, sizeof(*ret));
- assert(req->cur_desc_num == 0);
- DPRINTF("VSCSI: direct segment\n");
- break;
- }
- case SRP_DATA_DESC_INDIRECT: {
- struct srp_indirect_buf *tmp = (struct srp_indirect_buf *)
- (cmd->add_data + req->cdb_offset);
- if (n < req->local_desc) {
- *ret = tmp->desc_list[n];
- DPRINTF("VSCSI: indirect segment local tag=0x%x desc#%d/%d\n",
- req->qtag, n, req->local_desc);
-
- } else if (n < req->total_desc) {
- int rc;
- struct srp_direct_buf tbl_desc = vscsi_swap_desc(tmp->table_desc);
- unsigned desc_offset = n * sizeof(struct srp_direct_buf);
-
- if (desc_offset >= tbl_desc.len) {
- DPRINTF("VSCSI: #%d is ouf of range (%d bytes)\n",
- n, desc_offset);
- return -1;
- }
- rc = spapr_vio_dma_read(&s->vdev, tbl_desc.va + desc_offset,
- ret, sizeof(struct srp_direct_buf));
- if (rc) {
- DPRINTF("VSCSI: spapr_vio_dma_read -> %d reading ext_desc\n",
- rc);
- return -1;
- }
- DPRINTF("VSCSI: indirect segment ext. tag=0x%x desc#%d/%d { va=%"PRIx64" len=%x }\n",
- req->qtag, n, req->total_desc, tbl_desc.va, tbl_desc.len);
- } else {
- DPRINTF("VSCSI: Out of descriptors !\n");
- return 0;
- }
- break;
- }
- default:
- fprintf(stderr, "VSCSI: Unknown format %x\n", req->dma_fmt);
- return -1;
- }
-
- *ret = vscsi_swap_desc(*ret);
- if (buf_offset > ret->len) {
- DPRINTF(" offset=%x is out of a descriptor #%d boundary=%x\n",
- buf_offset, req->cur_desc_num, ret->len);
- return -1;
- }
- ret->va += buf_offset;
- ret->len -= buf_offset;
-
- DPRINTF(" cur=%d offs=%x ret { va=%"PRIx64" len=%x }\n",
- req->cur_desc_num, req->cur_desc_offset, ret->va, ret->len);
-
- return ret->len ? 1 : 0;
-}
-
-static int vscsi_srp_direct_data(VSCSIState *s, vscsi_req *req,
- uint8_t *buf, uint32_t len)
-{
- struct srp_direct_buf md;
- uint32_t llen;
- int rc = 0;
-
- rc = vscsi_fetch_desc(s, req, req->cur_desc_num, req->cur_desc_offset, &md);
- if (rc < 0) {
- return -1;
- } else if (rc == 0) {
- return 0;
- }
-
- llen = MIN(len, md.len);
- if (llen) {
- if (req->writing) { /* writing = to device = reading from memory */
- rc = spapr_vio_dma_read(&s->vdev, md.va, buf, llen);
- } else {
- rc = spapr_vio_dma_write(&s->vdev, md.va, buf, llen);
- }
- }
-
- if (rc) {
- return -1;
- }
- req->cur_desc_offset += llen;
-
- return llen;
-}
-
-static int vscsi_srp_indirect_data(VSCSIState *s, vscsi_req *req,
- uint8_t *buf, uint32_t len)
-{
- struct srp_direct_buf md;
- int rc = 0;
- uint32_t llen, total = 0;
-
- DPRINTF("VSCSI: indirect segment 0x%x bytes\n", len);
-
- /* While we have data ... */
- while (len) {
- rc = vscsi_fetch_desc(s, req, req->cur_desc_num, req->cur_desc_offset, &md);
- if (rc < 0) {
- return -1;
- } else if (rc == 0) {
- break;
- }
-
- /* Perform transfer */
- llen = MIN(len, md.len);
- if (req->writing) { /* writing = to device = reading from memory */
- rc = spapr_vio_dma_read(&s->vdev, md.va, buf, llen);
- } else {
- rc = spapr_vio_dma_write(&s->vdev, md.va, buf, llen);
- }
- if (rc) {
- DPRINTF("VSCSI: spapr_vio_dma_r/w(%d) -> %d\n", req->writing, rc);
- break;
- }
- DPRINTF("VSCSI: data: %02x %02x %02x %02x...\n",
- buf[0], buf[1], buf[2], buf[3]);
-
- len -= llen;
- buf += llen;
-
- total += llen;
-
- /* Update current position in the current descriptor */
- req->cur_desc_offset += llen;
- if (md.len == llen) {
- /* Go to the next descriptor if the current one finished */
- ++req->cur_desc_num;
- req->cur_desc_offset = 0;
- }
- }
-
- return rc ? -1 : total;
-}
-
-static int vscsi_srp_transfer_data(VSCSIState *s, vscsi_req *req,
- int writing, uint8_t *buf, uint32_t len)
-{
- int err = 0;
-
- switch (req->dma_fmt) {
- case SRP_NO_DATA_DESC:
- DPRINTF("VSCSI: no data desc transfer, skipping 0x%x bytes\n", len);
- break;
- case SRP_DATA_DESC_DIRECT:
- err = vscsi_srp_direct_data(s, req, buf, len);
- break;
- case SRP_DATA_DESC_INDIRECT:
- err = vscsi_srp_indirect_data(s, req, buf, len);
- break;
- }
- return err;
-}
-
-/* Bits from linux srp */
-static int data_out_desc_size(struct srp_cmd *cmd)
-{
- int size = 0;
- uint8_t fmt = cmd->buf_fmt >> 4;
-
- switch (fmt) {
- case SRP_NO_DATA_DESC:
- break;
- case SRP_DATA_DESC_DIRECT:
- size = sizeof(struct srp_direct_buf);
- break;
- case SRP_DATA_DESC_INDIRECT:
- size = sizeof(struct srp_indirect_buf) +
- sizeof(struct srp_direct_buf)*cmd->data_out_desc_cnt;
- break;
- default:
- break;
- }
- return size;
-}
-
-static int vscsi_preprocess_desc(vscsi_req *req)
-{
- struct srp_cmd *cmd = &req->iu.srp.cmd;
-
- req->cdb_offset = cmd->add_cdb_len & ~3;
-
- if (req->writing) {
- req->dma_fmt = cmd->buf_fmt >> 4;
- } else {
- req->cdb_offset += data_out_desc_size(cmd);
- req->dma_fmt = cmd->buf_fmt & ((1U << 4) - 1);
- }
-
- switch (req->dma_fmt) {
- case SRP_NO_DATA_DESC:
- break;
- case SRP_DATA_DESC_DIRECT:
- req->total_desc = req->local_desc = 1;
- break;
- case SRP_DATA_DESC_INDIRECT: {
- struct srp_indirect_buf *ind_tmp = (struct srp_indirect_buf *)
- (cmd->add_data + req->cdb_offset);
-
- req->total_desc = be32_to_cpu(ind_tmp->table_desc.len) /
- sizeof(struct srp_direct_buf);
- req->local_desc = req->writing ? cmd->data_out_desc_cnt :
- cmd->data_in_desc_cnt;
- break;
- }
- default:
- fprintf(stderr,
- "vscsi_preprocess_desc: Unknown format %x\n", req->dma_fmt);
- return -1;
- }
-
- return 0;
-}
-
-/* Callback to indicate that the SCSI layer has completed a transfer. */
-static void vscsi_transfer_data(SCSIRequest *sreq, uint32_t len)
-{
- VSCSIState *s = VIO_SPAPR_VSCSI_DEVICE(sreq->bus->qbus.parent);
- vscsi_req *req = sreq->hba_private;
- uint8_t *buf;
- int rc = 0;
-
- DPRINTF("VSCSI: SCSI xfer complete tag=0x%x len=0x%x, req=%p\n",
- sreq->tag, len, req);
- if (req == NULL) {
- fprintf(stderr, "VSCSI: Can't find request for tag 0x%x\n", sreq->tag);
- return;
- }
-
- if (len) {
- buf = scsi_req_get_buf(sreq);
- rc = vscsi_srp_transfer_data(s, req, req->writing, buf, len);
- }
- if (rc < 0) {
- fprintf(stderr, "VSCSI: RDMA error rc=%d!\n", rc);
- req->dma_error = true;
- scsi_req_cancel(req->sreq);
- return;
- }
-
- /* Start next chunk */
- req->data_len -= rc;
- scsi_req_continue(sreq);
-}
-
-/* Callback to indicate that the SCSI layer has completed a transfer. */
-static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status, size_t resid)
-{
- VSCSIState *s = VIO_SPAPR_VSCSI_DEVICE(sreq->bus->qbus.parent);
- vscsi_req *req = sreq->hba_private;
- int32_t res_in = 0, res_out = 0;
-
- DPRINTF("VSCSI: SCSI cmd complete, tag=0x%x status=0x%x, req=%p\n",
- sreq->tag, status, req);
- if (req == NULL) {
- fprintf(stderr, "VSCSI: Can't find request for tag 0x%x\n", sreq->tag);
- return;
- }
-
- if (status == CHECK_CONDITION) {
- req->senselen = scsi_req_get_sense(req->sreq, req->sense,
- sizeof(req->sense));
- DPRINTF("VSCSI: Sense data, %d bytes:\n", req->senselen);
- DPRINTF(" %02x %02x %02x %02x %02x %02x %02x %02x\n",
- req->sense[0], req->sense[1], req->sense[2], req->sense[3],
- req->sense[4], req->sense[5], req->sense[6], req->sense[7]);
- DPRINTF(" %02x %02x %02x %02x %02x %02x %02x %02x\n",
- req->sense[8], req->sense[9], req->sense[10], req->sense[11],
- req->sense[12], req->sense[13], req->sense[14], req->sense[15]);
- }
-
- DPRINTF("VSCSI: Command complete err=%d\n", status);
- if (status == 0) {
- /* We handle overflows, not underflows for normal commands,
- * but hopefully nobody cares
- */
- if (req->writing) {
- res_out = req->data_len;
- } else {
- res_in = req->data_len;
- }
- }
- vscsi_send_rsp(s, req, status, res_in, res_out);
- vscsi_put_req(req);
-}
-
-static void vscsi_request_cancelled(SCSIRequest *sreq)
-{
- vscsi_req *req = sreq->hba_private;
-
- if (req->dma_error) {
- VSCSIState *s = VIO_SPAPR_VSCSI_DEVICE(sreq->bus->qbus.parent);
-
- vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0);
- vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
- }
- vscsi_put_req(req);
-}
-
-static const VMStateDescription vmstate_spapr_vscsi_req = {
- .name = "spapr_vscsi_req",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_BUFFER(crq.raw, vscsi_req),
- VMSTATE_BUFFER(iu.srp.reserved, vscsi_req),
- VMSTATE_UINT32(qtag, vscsi_req),
- VMSTATE_BOOL(active, vscsi_req),
- VMSTATE_UINT32(data_len, vscsi_req),
- VMSTATE_BOOL(writing, vscsi_req),
- VMSTATE_UINT32(senselen, vscsi_req),
- VMSTATE_BUFFER(sense, vscsi_req),
- VMSTATE_UINT8(dma_fmt, vscsi_req),
- VMSTATE_UINT16(local_desc, vscsi_req),
- VMSTATE_UINT16(total_desc, vscsi_req),
- VMSTATE_UINT16(cdb_offset, vscsi_req),
- /*Restart SCSI request from the beginning for now */
- /*VMSTATE_UINT16(cur_desc_num, vscsi_req),
- VMSTATE_UINT16(cur_desc_offset, vscsi_req),*/
- VMSTATE_END_OF_LIST()
- },
-};
-
-static void vscsi_save_request(QEMUFile *f, SCSIRequest *sreq)
-{
- vscsi_req *req = sreq->hba_private;
- assert(req->active);
-
- vmstate_save_state(f, &vmstate_spapr_vscsi_req, req, NULL);
-
- DPRINTF("VSCSI: saving tag=%u, current desc#%d, offset=%x\n",
- req->qtag, req->cur_desc_num, req->cur_desc_offset);
-}
-
-static void *vscsi_load_request(QEMUFile *f, SCSIRequest *sreq)
-{
- SCSIBus *bus = sreq->bus;
- VSCSIState *s = VIO_SPAPR_VSCSI_DEVICE(bus->qbus.parent);
- vscsi_req *req;
- int rc;
-
- assert(sreq->tag < VSCSI_REQ_LIMIT);
- req = &s->reqs[sreq->tag];
- assert(!req->active);
-
- memset(req, 0, sizeof(*req));
- rc = vmstate_load_state(f, &vmstate_spapr_vscsi_req, req, 1);
- if (rc) {
- fprintf(stderr, "VSCSI: failed loading request tag#%u\n", sreq->tag);
- return NULL;
- }
- assert(req->active);
-
- req->sreq = scsi_req_ref(sreq);
-
- DPRINTF("VSCSI: restoring tag=%u, current desc#%d, offset=%x\n",
- req->qtag, req->cur_desc_num, req->cur_desc_offset);
-
- return req;
-}
-
-static void vscsi_process_login(VSCSIState *s, vscsi_req *req)
-{
- union viosrp_iu *iu = &req->iu;
- struct srp_login_rsp *rsp = &iu->srp.login_rsp;
- uint64_t tag = iu->srp.rsp.tag;
-
- DPRINTF("VSCSI: Got login, sendin response !\n");
-
- /* TODO handle case that requested size is wrong and
- * buffer format is wrong
- */
- memset(iu, 0, sizeof(struct srp_login_rsp));
- rsp->opcode = SRP_LOGIN_RSP;
- /* Don't advertise quite as many request as we support to
- * keep room for management stuff etc...
- */
- rsp->req_lim_delta = cpu_to_be32(VSCSI_REQ_LIMIT-2);
- rsp->tag = tag;
- rsp->max_it_iu_len = cpu_to_be32(sizeof(union srp_iu));
- rsp->max_ti_iu_len = cpu_to_be32(sizeof(union srp_iu));
- /* direct and indirect */
- rsp->buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT | SRP_BUF_FORMAT_INDIRECT);
-
- vscsi_send_iu(s, req, sizeof(*rsp), VIOSRP_SRP_FORMAT);
-}
-
-static void vscsi_inquiry_no_target(VSCSIState *s, vscsi_req *req)
-{
- uint8_t *cdb = req->iu.srp.cmd.cdb;
- uint8_t resp_data[36];
- int rc, len, alen;
-
- /* We dont do EVPD. Also check that page_code is 0 */
- if ((cdb[1] & 0x01) || cdb[2] != 0) {
- /* Send INVALID FIELD IN CDB */
- vscsi_makeup_sense(s, req, ILLEGAL_REQUEST, 0x24, 0);
- vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
- return;
- }
- alen = cdb[3];
- alen = (alen << 8) | cdb[4];
- len = MIN(alen, 36);
-
- /* Fake up inquiry using PQ=3 */
- memset(resp_data, 0, 36);
- resp_data[0] = 0x7f; /* Not capable of supporting a device here */
- resp_data[2] = 0x06; /* SPS-4 */
- resp_data[3] = 0x02; /* Resp data format */
- resp_data[4] = 36 - 5; /* Additional length */
- resp_data[7] = 0x10; /* Sync transfers */
- memcpy(&resp_data[16], "QEMU EMPTY ", 16);
- memcpy(&resp_data[8], "QEMU ", 8);
-
- req->writing = 0;
- vscsi_preprocess_desc(req);
- rc = vscsi_srp_transfer_data(s, req, 0, resp_data, len);
- if (rc < 0) {
- vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0);
- vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
- } else {
- vscsi_send_rsp(s, req, 0, 36 - rc, 0);
- }
-}
-
-static void vscsi_report_luns(VSCSIState *s, vscsi_req *req)
-{
- BusChild *kid;
- int i, len, n, rc;
- uint8_t *resp_data;
- bool found_lun0;
-
- n = 0;
- found_lun0 = false;
- QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
- SCSIDevice *dev = SCSI_DEVICE(kid->child);
-
- n += 8;
- if (dev->channel == 0 && dev->id == 0 && dev->lun == 0) {
- found_lun0 = true;
- }
- }
- if (!found_lun0) {
- n += 8;
- }
- len = n+8;
-
- resp_data = g_malloc0(len);
- stl_be_p(resp_data, n);
- i = found_lun0 ? 8 : 16;
- QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
- DeviceState *qdev = kid->child;
- SCSIDevice *dev = SCSI_DEVICE(qdev);
-
- if (dev->id == 0 && dev->channel == 0) {
- resp_data[i] = 0; /* Use simple LUN for 0 (SAM5 4.7.7.1) */
- } else {
- resp_data[i] = (2 << 6); /* Otherwise LUN addressing (4.7.7.4) */
- }
- resp_data[i] |= dev->id;
- resp_data[i+1] = (dev->channel << 5);
- resp_data[i+1] |= dev->lun;
- i += 8;
- }
-
- vscsi_preprocess_desc(req);
- rc = vscsi_srp_transfer_data(s, req, 0, resp_data, len);
- g_free(resp_data);
- if (rc < 0) {
- vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0);
- vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
- } else {
- vscsi_send_rsp(s, req, 0, len - rc, 0);
- }
-}
-
-static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req)
-{
- union srp_iu *srp = &req->iu.srp;
- SCSIDevice *sdev;
- int n, lun;
-
- if ((srp->cmd.lun == 0 || be64_to_cpu(srp->cmd.lun) == SRP_REPORT_LUNS_WLUN)
- && srp->cmd.cdb[0] == REPORT_LUNS) {
- vscsi_report_luns(s, req);
- return 0;
- }
-
- sdev = vscsi_device_find(&s->bus, be64_to_cpu(srp->cmd.lun), &lun);
- if (!sdev) {
- DPRINTF("VSCSI: Command for lun %08" PRIx64 " with no drive\n",
- be64_to_cpu(srp->cmd.lun));
- if (srp->cmd.cdb[0] == INQUIRY) {
- vscsi_inquiry_no_target(s, req);
- } else {
- vscsi_makeup_sense(s, req, ILLEGAL_REQUEST, 0x24, 0x00);
- vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
- } return 1;
- }
-
- req->sreq = scsi_req_new(sdev, req->qtag, lun, srp->cmd.cdb, req);
- n = scsi_req_enqueue(req->sreq);
-
- DPRINTF("VSCSI: Queued command tag 0x%x CMD 0x%x=%s LUN %d ret: %d\n",
- req->qtag, srp->cmd.cdb[0], scsi_command_name(srp->cmd.cdb[0]),
- lun, n);
-
- if (n) {
- /* Transfer direction must be set before preprocessing the
- * descriptors
- */
- req->writing = (n < 1);
-
- /* Preprocess RDMA descriptors */
- vscsi_preprocess_desc(req);
-
- /* Get transfer direction and initiate transfer */
- if (n > 0) {
- req->data_len = n;
- } else if (n < 0) {
- req->data_len = -n;
- }
- scsi_req_continue(req->sreq);
- }
- /* Don't touch req here, it may have been recycled already */
-
- return 0;
-}
-
-static int vscsi_process_tsk_mgmt(VSCSIState *s, vscsi_req *req)
-{
- union viosrp_iu *iu = &req->iu;
- vscsi_req *tmpreq;
- int i, lun = 0, resp = SRP_TSK_MGMT_COMPLETE;
- SCSIDevice *d;
- uint64_t tag = iu->srp.rsp.tag;
- uint8_t sol_not = iu->srp.cmd.sol_not;
-
- fprintf(stderr, "vscsi_process_tsk_mgmt %02x\n",
- iu->srp.tsk_mgmt.tsk_mgmt_func);
-
- d = vscsi_device_find(&s->bus, be64_to_cpu(req->iu.srp.tsk_mgmt.lun), &lun);
- if (!d) {
- resp = SRP_TSK_MGMT_FIELDS_INVALID;
- } else {
- switch (iu->srp.tsk_mgmt.tsk_mgmt_func) {
- case SRP_TSK_ABORT_TASK:
- if (d->lun != lun) {
- resp = SRP_TSK_MGMT_FIELDS_INVALID;
- break;
- }
-
- tmpreq = vscsi_find_req(s, req->iu.srp.tsk_mgmt.task_tag);
- if (tmpreq && tmpreq->sreq) {
- assert(tmpreq->sreq->hba_private);
- scsi_req_cancel(tmpreq->sreq);
- }
- break;
-
- case SRP_TSK_LUN_RESET:
- if (d->lun != lun) {
- resp = SRP_TSK_MGMT_FIELDS_INVALID;
- break;
- }
-
- qdev_reset_all(&d->qdev);
- break;
-
- case SRP_TSK_ABORT_TASK_SET:
- case SRP_TSK_CLEAR_TASK_SET:
- if (d->lun != lun) {
- resp = SRP_TSK_MGMT_FIELDS_INVALID;
- break;
- }
-
- for (i = 0; i < VSCSI_REQ_LIMIT; i++) {
- tmpreq = &s->reqs[i];
- if (tmpreq->iu.srp.cmd.lun != req->iu.srp.tsk_mgmt.lun) {
- continue;
- }
- if (!tmpreq->active || !tmpreq->sreq) {
- continue;
- }
- assert(tmpreq->sreq->hba_private);
- scsi_req_cancel(tmpreq->sreq);
- }
- break;
-
- case SRP_TSK_CLEAR_ACA:
- resp = SRP_TSK_MGMT_NOT_SUPPORTED;
- break;
-
- default:
- resp = SRP_TSK_MGMT_FIELDS_INVALID;
- break;
- }
- }
-
- /* Compose the response here as */
- memset(iu, 0, sizeof(struct srp_rsp) + 4);
- iu->srp.rsp.opcode = SRP_RSP;
- iu->srp.rsp.req_lim_delta = cpu_to_be32(1);
- iu->srp.rsp.tag = tag;
- iu->srp.rsp.flags |= SRP_RSP_FLAG_RSPVALID;
- iu->srp.rsp.resp_data_len = cpu_to_be32(4);
- if (resp) {
- iu->srp.rsp.sol_not = (sol_not & 0x04) >> 2;
- } else {
- iu->srp.rsp.sol_not = (sol_not & 0x02) >> 1;
- }
-
- iu->srp.rsp.status = GOOD;
- iu->srp.rsp.data[3] = resp;
-
- vscsi_send_iu(s, req, sizeof(iu->srp.rsp) + 4, VIOSRP_SRP_FORMAT);
-
- return 1;
-}
-
-static int vscsi_handle_srp_req(VSCSIState *s, vscsi_req *req)
-{
- union srp_iu *srp = &req->iu.srp;
- int done = 1;
- uint8_t opcode = srp->rsp.opcode;
-
- switch (opcode) {
- case SRP_LOGIN_REQ:
- vscsi_process_login(s, req);
- break;
- case SRP_TSK_MGMT:
- done = vscsi_process_tsk_mgmt(s, req);
- break;
- case SRP_CMD:
- done = vscsi_queue_cmd(s, req);
- break;
- case SRP_LOGIN_RSP:
- case SRP_I_LOGOUT:
- case SRP_T_LOGOUT:
- case SRP_RSP:
- case SRP_CRED_REQ:
- case SRP_CRED_RSP:
- case SRP_AER_REQ:
- case SRP_AER_RSP:
- fprintf(stderr, "VSCSI: Unsupported opcode %02x\n", opcode);
- break;
- default:
- fprintf(stderr, "VSCSI: Unknown type %02x\n", opcode);
- }
-
- return done;
-}
-
-static int vscsi_send_adapter_info(VSCSIState *s, vscsi_req *req)
-{
- struct viosrp_adapter_info *sinfo;
- struct mad_adapter_info_data info;
- int rc;
-
- sinfo = &req->iu.mad.adapter_info;
-
-#if 0 /* What for ? */
- rc = spapr_vio_dma_read(&s->vdev, be64_to_cpu(sinfo->buffer),
- &info, be16_to_cpu(sinfo->common.length));
- if (rc) {
- fprintf(stderr, "vscsi_send_adapter_info: DMA read failure !\n");
- }
-#endif
- memset(&info, 0, sizeof(info));
- strcpy(info.srp_version, SRP_VERSION);
- memcpy(info.partition_name, "qemu", sizeof("qemu"));
- info.partition_number = cpu_to_be32(0);
- info.mad_version = cpu_to_be32(1);
- info.os_type = cpu_to_be32(2);
- info.port_max_txu[0] = cpu_to_be32(VSCSI_MAX_SECTORS << 9);
-
- rc = spapr_vio_dma_write(&s->vdev, be64_to_cpu(sinfo->buffer),
- &info, be16_to_cpu(sinfo->common.length));
- if (rc) {
- fprintf(stderr, "vscsi_send_adapter_info: DMA write failure !\n");
- }
-
- sinfo->common.status = rc ? cpu_to_be32(1) : 0;
-
- return vscsi_send_iu(s, req, sizeof(*sinfo), VIOSRP_MAD_FORMAT);
-}
-
-static int vscsi_send_capabilities(VSCSIState *s, vscsi_req *req)
-{
- struct viosrp_capabilities *vcap;
- struct capabilities cap = { };
- uint16_t len, req_len;
- uint64_t buffer;
- int rc;
-
- vcap = &req->iu.mad.capabilities;
- req_len = len = be16_to_cpu(vcap->common.length);
- buffer = be64_to_cpu(vcap->buffer);
- if (len > sizeof(cap)) {
- fprintf(stderr, "vscsi_send_capabilities: capabilities size mismatch !\n");
-
- /*
- * Just read and populate the structure that is known.
- * Zero rest of the structure.
- */
- len = sizeof(cap);
- }
- rc = spapr_vio_dma_read(&s->vdev, buffer, &cap, len);
- if (rc) {
- fprintf(stderr, "vscsi_send_capabilities: DMA read failure !\n");
- }
-
- /*
- * Current implementation does not suppport any migration or
- * reservation capabilities. Construct the response telling the
- * guest not to use them.
- */
- cap.flags = 0;
- cap.migration.ecl = 0;
- cap.reserve.type = 0;
- cap.migration.common.server_support = 0;
- cap.reserve.common.server_support = 0;
-
- rc = spapr_vio_dma_write(&s->vdev, buffer, &cap, len);
- if (rc) {
- fprintf(stderr, "vscsi_send_capabilities: DMA write failure !\n");
- }
- if (req_len > len) {
- /*
- * Being paranoid and lets not worry about the error code
- * here. Actual write of the cap is done above.
- */
- spapr_vio_dma_set(&s->vdev, (buffer + len), 0, (req_len - len));
- }
- vcap->common.status = rc ? cpu_to_be32(1) : 0;
- return vscsi_send_iu(s, req, sizeof(*vcap), VIOSRP_MAD_FORMAT);
-}
-
-static int vscsi_handle_mad_req(VSCSIState *s, vscsi_req *req)
-{
- union mad_iu *mad = &req->iu.mad;
- bool request_handled = false;
- uint64_t retlen = 0;
-
- switch (be32_to_cpu(mad->empty_iu.common.type)) {
- case VIOSRP_EMPTY_IU_TYPE:
- fprintf(stderr, "Unsupported EMPTY MAD IU\n");
- retlen = sizeof(mad->empty_iu);
- break;
- case VIOSRP_ERROR_LOG_TYPE:
- fprintf(stderr, "Unsupported ERROR LOG MAD IU\n");
- retlen = sizeof(mad->error_log);
- break;
- case VIOSRP_ADAPTER_INFO_TYPE:
- vscsi_send_adapter_info(s, req);
- request_handled = true;
- break;
- case VIOSRP_HOST_CONFIG_TYPE:
- retlen = sizeof(mad->host_config);
- break;
- case VIOSRP_CAPABILITIES_TYPE:
- vscsi_send_capabilities(s, req);
- request_handled = true;
- break;
- default:
- fprintf(stderr, "VSCSI: Unknown MAD type %02x\n",
- be32_to_cpu(mad->empty_iu.common.type));
- /*
- * PAPR+ says that "The length field is set to the length
- * of the data structure(s) used in the command".
- * As we did not recognize the request type, put zero there.
- */
- retlen = 0;
- }
-
- if (!request_handled) {
- mad->empty_iu.common.status = cpu_to_be16(VIOSRP_MAD_NOT_SUPPORTED);
- vscsi_send_iu(s, req, retlen, VIOSRP_MAD_FORMAT);
- }
-
- return 1;
-}
-
-static void vscsi_got_payload(VSCSIState *s, vscsi_crq *crq)
-{
- vscsi_req *req;
- int done;
-
- req = vscsi_get_req(s);
- if (req == NULL) {
- fprintf(stderr, "VSCSI: Failed to get a request !\n");
- return;
- }
-
- /* We only support a limited number of descriptors, we know
- * the ibmvscsi driver uses up to 10 max, so it should fit
- * in our 256 bytes IUs. If not we'll have to increase the size
- * of the structure.
- */
- if (crq->s.IU_length > sizeof(union viosrp_iu)) {
- fprintf(stderr, "VSCSI: SRP IU too long (%d bytes) !\n",
- crq->s.IU_length);
- vscsi_put_req(req);
- return;
- }
-
- /* XXX Handle failure differently ? */
- if (spapr_vio_dma_read(&s->vdev, crq->s.IU_data_ptr, &req->iu,
- crq->s.IU_length)) {
- fprintf(stderr, "vscsi_got_payload: DMA read failure !\n");
- vscsi_put_req(req);
- return;
- }
- memcpy(&req->crq, crq, sizeof(vscsi_crq));
-
- if (crq->s.format == VIOSRP_MAD_FORMAT) {
- done = vscsi_handle_mad_req(s, req);
- } else {
- done = vscsi_handle_srp_req(s, req);
- }
-
- if (done) {
- vscsi_put_req(req);
- }
-}
-
-
-static int vscsi_do_crq(struct VIOsPAPRDevice *dev, uint8_t *crq_data)
-{
- VSCSIState *s = VIO_SPAPR_VSCSI_DEVICE(dev);
- vscsi_crq crq;
-
- memcpy(crq.raw, crq_data, 16);
- crq.s.timeout = be16_to_cpu(crq.s.timeout);
- crq.s.IU_length = be16_to_cpu(crq.s.IU_length);
- crq.s.IU_data_ptr = be64_to_cpu(crq.s.IU_data_ptr);
-
- DPRINTF("VSCSI: do_crq %02x %02x ...\n", crq.raw[0], crq.raw[1]);
-
- switch (crq.s.valid) {
- case 0xc0: /* Init command/response */
-
- /* Respond to initialization request */
- if (crq.s.format == 0x01) {
- memset(crq.raw, 0, 16);
- crq.s.valid = 0xc0;
- crq.s.format = 0x02;
- spapr_vio_send_crq(dev, crq.raw);
- }
-
- /* Note that in hotplug cases, we might get a 0x02
- * as a result of us emitting the init request
- */
-
- break;
- case 0xff: /* Link event */
-
- /* Not handled for now */
-
- break;
- case 0x80: /* Payloads */
- switch (crq.s.format) {
- case VIOSRP_SRP_FORMAT: /* AKA VSCSI request */
- case VIOSRP_MAD_FORMAT: /* AKA VSCSI response */
- vscsi_got_payload(s, &crq);
- break;
- case VIOSRP_OS400_FORMAT:
- case VIOSRP_AIX_FORMAT:
- case VIOSRP_LINUX_FORMAT:
- case VIOSRP_INLINE_FORMAT:
- fprintf(stderr, "vscsi_do_srq: Unsupported payload format %02x\n",
- crq.s.format);
- break;
- default:
- fprintf(stderr, "vscsi_do_srq: Unknown payload format %02x\n",
- crq.s.format);
- }
- break;
- default:
- fprintf(stderr, "vscsi_do_crq: unknown CRQ %02x %02x ...\n",
- crq.raw[0], crq.raw[1]);
- };
-
- return 0;
-}
-
-static const struct SCSIBusInfo vscsi_scsi_info = {
- .tcq = true,
- .max_channel = 7, /* logical unit addressing format */
- .max_target = 63,
- .max_lun = 31,
-
- .transfer_data = vscsi_transfer_data,
- .complete = vscsi_command_complete,
- .cancel = vscsi_request_cancelled,
- .save_request = vscsi_save_request,
- .load_request = vscsi_load_request,
-};
-
-static void spapr_vscsi_reset(VIOsPAPRDevice *dev)
-{
- VSCSIState *s = VIO_SPAPR_VSCSI_DEVICE(dev);
- int i;
-
- memset(s->reqs, 0, sizeof(s->reqs));
- for (i = 0; i < VSCSI_REQ_LIMIT; i++) {
- s->reqs[i].qtag = i;
- }
-}
-
-static void spapr_vscsi_realize(VIOsPAPRDevice *dev, Error **errp)
-{
- VSCSIState *s = VIO_SPAPR_VSCSI_DEVICE(dev);
-
- dev->crq.SendFunc = vscsi_do_crq;
-
- scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(dev),
- &vscsi_scsi_info, NULL);
- if (!dev->qdev.hotplugged) {
- scsi_bus_legacy_handle_cmdline(&s->bus, errp);
- }
-}
-
-void spapr_vscsi_create(VIOsPAPRBus *bus)
-{
- DeviceState *dev;
-
- dev = qdev_create(&bus->bus, "spapr-vscsi");
-
- qdev_init_nofail(dev);
-}
-
-static int spapr_vscsi_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off)
-{
- int ret;
-
- ret = fdt_setprop_cell(fdt, node_off, "#address-cells", 2);
- if (ret < 0) {
- return ret;
- }
-
- ret = fdt_setprop_cell(fdt, node_off, "#size-cells", 0);
- if (ret < 0) {
- return ret;
- }
-
- return 0;
-}
-
-static Property spapr_vscsi_properties[] = {
- DEFINE_SPAPR_PROPERTIES(VSCSIState, vdev),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static const VMStateDescription vmstate_spapr_vscsi = {
- .name = "spapr_vscsi",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_SPAPR_VIO(vdev, VSCSIState),
- /* VSCSI state */
- /* ???? */
-
- VMSTATE_END_OF_LIST()
- },
-};
-
-static void spapr_vscsi_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
-
- k->realize = spapr_vscsi_realize;
- k->reset = spapr_vscsi_reset;
- k->devnode = spapr_vscsi_devnode;
- k->dt_name = "v-scsi";
- k->dt_type = "vscsi";
- k->dt_compatible = "IBM,v-scsi";
- k->signal_mask = 0x00000001;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
- dc->props = spapr_vscsi_properties;
- k->rtce_window_size = 0x10000000;
- dc->vmsd = &vmstate_spapr_vscsi;
-}
-
-static const TypeInfo spapr_vscsi_info = {
- .name = TYPE_VIO_SPAPR_VSCSI_DEVICE,
- .parent = TYPE_VIO_SPAPR_DEVICE,
- .instance_size = sizeof(VSCSIState),
- .class_init = spapr_vscsi_class_init,
-};
-
-static void spapr_vscsi_register_types(void)
-{
- type_register_static(&spapr_vscsi_info);
-}
-
-type_init(spapr_vscsi_register_types)
diff --git a/qemu/hw/scsi/srp.h b/qemu/hw/scsi/srp.h
deleted file mode 100644
index d27f31d2d..000000000
--- a/qemu/hw/scsi/srp.h
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * Copyright (c) 2005 Cisco Systems. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses. You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * - Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * - Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- *
- */
-
-#ifndef SCSI_SRP_H
-#define SCSI_SRP_H
-
-/*
- * Structures and constants for the SCSI RDMA Protocol (SRP) as
- * defined by the INCITS T10 committee. This file was written using
- * draft Revision 16a of the SRP standard.
- */
-
-enum {
-
- SRP_LOGIN_REQ = 0x00,
- SRP_TSK_MGMT = 0x01,
- SRP_CMD = 0x02,
- SRP_I_LOGOUT = 0x03,
- SRP_LOGIN_RSP = 0xc0,
- SRP_RSP = 0xc1,
- SRP_LOGIN_REJ = 0xc2,
- SRP_T_LOGOUT = 0x80,
- SRP_CRED_REQ = 0x81,
- SRP_AER_REQ = 0x82,
- SRP_CRED_RSP = 0x41,
- SRP_AER_RSP = 0x42
-};
-
-enum {
- SRP_BUF_FORMAT_DIRECT = 1 << 1,
- SRP_BUF_FORMAT_INDIRECT = 1 << 2
-};
-
-enum {
- SRP_NO_DATA_DESC = 0,
- SRP_DATA_DESC_DIRECT = 1,
- SRP_DATA_DESC_INDIRECT = 2
-};
-
-enum {
- SRP_TSK_ABORT_TASK = 0x01,
- SRP_TSK_ABORT_TASK_SET = 0x02,
- SRP_TSK_CLEAR_TASK_SET = 0x04,
- SRP_TSK_LUN_RESET = 0x08,
- SRP_TSK_CLEAR_ACA = 0x40
-};
-
-enum srp_login_rej_reason {
- SRP_LOGIN_REJ_UNABLE_ESTABLISH_CHANNEL = 0x00010000,
- SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES = 0x00010001,
- SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE = 0x00010002,
- SRP_LOGIN_REJ_UNABLE_ASSOCIATE_CHANNEL = 0x00010003,
- SRP_LOGIN_REJ_UNSUPPORTED_DESCRIPTOR_FMT = 0x00010004,
- SRP_LOGIN_REJ_MULTI_CHANNEL_UNSUPPORTED = 0x00010005,
- SRP_LOGIN_REJ_CHANNEL_LIMIT_REACHED = 0x00010006
-};
-
-enum {
- SRP_REV10_IB_IO_CLASS = 0xff00,
- SRP_REV16A_IB_IO_CLASS = 0x0100
-};
-
-enum {
- SRP_TSK_MGMT_COMPLETE = 0x00,
- SRP_TSK_MGMT_FIELDS_INVALID = 0x02,
- SRP_TSK_MGMT_NOT_SUPPORTED = 0x04,
- SRP_TSK_MGMT_FAILED = 0x05
-};
-
-struct srp_direct_buf {
- uint64_t va;
- uint32_t key;
- uint32_t len;
-};
-
-/*
- * We need the packed attribute because the SRP spec puts the list of
- * descriptors at an offset of 20, which is not aligned to the size of
- * struct srp_direct_buf. The whole structure must be packed to avoid
- * having the 20-byte structure padded to 24 bytes on 64-bit architectures.
- */
-struct srp_indirect_buf {
- struct srp_direct_buf table_desc;
- uint32_t len;
- struct srp_direct_buf desc_list[0];
-} QEMU_PACKED;
-
-enum {
- SRP_MULTICHAN_SINGLE = 0,
- SRP_MULTICHAN_MULTI = 1
-};
-
-struct srp_login_req {
- uint8_t opcode;
- uint8_t reserved1[7];
- uint64_t tag;
- uint32_t req_it_iu_len;
- uint8_t reserved2[4];
- uint16_t req_buf_fmt;
- uint8_t req_flags;
- uint8_t reserved3[5];
- uint8_t initiator_port_id[16];
- uint8_t target_port_id[16];
-};
-
-/*
- * The SRP spec defines the size of the LOGIN_RSP structure to be 52
- * bytes, so it needs to be packed to avoid having it padded to 56
- * bytes on 64-bit architectures.
- */
-struct srp_login_rsp {
- uint8_t opcode;
- uint8_t reserved1[3];
- uint32_t req_lim_delta;
- uint64_t tag;
- uint32_t max_it_iu_len;
- uint32_t max_ti_iu_len;
- uint16_t buf_fmt;
- uint8_t rsp_flags;
- uint8_t reserved2[25];
-} QEMU_PACKED;
-
-struct srp_login_rej {
- uint8_t opcode;
- uint8_t reserved1[3];
- uint32_t reason;
- uint64_t tag;
- uint8_t reserved2[8];
- uint16_t buf_fmt;
- uint8_t reserved3[6];
-};
-
-struct srp_i_logout {
- uint8_t opcode;
- uint8_t reserved[7];
- uint64_t tag;
-};
-
-struct srp_t_logout {
- uint8_t opcode;
- uint8_t sol_not;
- uint8_t reserved[2];
- uint32_t reason;
- uint64_t tag;
-};
-
-/*
- * We need the packed attribute because the SRP spec only aligns the
- * 8-byte LUN field to 4 bytes.
- */
-struct srp_tsk_mgmt {
- uint8_t opcode;
- uint8_t sol_not;
- uint8_t reserved1[6];
- uint64_t tag;
- uint8_t reserved2[4];
- uint64_t lun;
- uint8_t reserved3[2];
- uint8_t tsk_mgmt_func;
- uint8_t reserved4;
- uint64_t task_tag;
- uint8_t reserved5[8];
-} QEMU_PACKED;
-
-/*
- * We need the packed attribute because the SRP spec only aligns the
- * 8-byte LUN field to 4 bytes.
- */
-struct srp_cmd {
- uint8_t opcode;
- uint8_t sol_not;
- uint8_t reserved1[3];
- uint8_t buf_fmt;
- uint8_t data_out_desc_cnt;
- uint8_t data_in_desc_cnt;
- uint64_t tag;
- uint8_t reserved2[4];
- uint64_t lun;
- uint8_t reserved3;
- uint8_t task_attr;
- uint8_t reserved4;
- uint8_t add_cdb_len;
- uint8_t cdb[16];
- uint8_t add_data[0];
-} QEMU_PACKED;
-
-enum {
- SRP_RSP_FLAG_RSPVALID = 1 << 0,
- SRP_RSP_FLAG_SNSVALID = 1 << 1,
- SRP_RSP_FLAG_DOOVER = 1 << 2,
- SRP_RSP_FLAG_DOUNDER = 1 << 3,
- SRP_RSP_FLAG_DIOVER = 1 << 4,
- SRP_RSP_FLAG_DIUNDER = 1 << 5
-};
-
-/*
- * The SRP spec defines the size of the RSP structure to be 36 bytes,
- * so it needs to be packed to avoid having it padded to 40 bytes on
- * 64-bit architectures.
- */
-struct srp_rsp {
- uint8_t opcode;
- uint8_t sol_not;
- uint8_t reserved1[2];
- uint32_t req_lim_delta;
- uint64_t tag;
- uint8_t reserved2[2];
- uint8_t flags;
- uint8_t status;
- uint32_t data_out_res_cnt;
- uint32_t data_in_res_cnt;
- uint32_t sense_data_len;
- uint32_t resp_data_len;
- uint8_t data[0];
-} QEMU_PACKED;
-
-#endif /* SCSI_SRP_H */
diff --git a/qemu/hw/scsi/vhost-scsi.c b/qemu/hw/scsi/vhost-scsi.c
deleted file mode 100644
index 9261d51da..000000000
--- a/qemu/hw/scsi/vhost-scsi.c
+++ /dev/null
@@ -1,352 +0,0 @@
-/*
- * vhost_scsi host device
- *
- * Copyright IBM, Corp. 2011
- *
- * Authors:
- * Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
- *
- * Changes for QEMU mainline + tcm_vhost kernel upstream:
- * Nicholas Bellinger <nab@risingtidesystems.com>
- *
- * This work is licensed under the terms of the GNU LGPL, version 2 or later.
- * See the COPYING.LIB file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include <sys/ioctl.h>
-#include "qemu/error-report.h"
-#include "qemu/queue.h"
-#include "monitor/monitor.h"
-#include "migration/migration.h"
-#include "hw/virtio/vhost-scsi.h"
-#include "hw/virtio/vhost.h"
-#include "hw/virtio/virtio-scsi.h"
-#include "hw/virtio/virtio-bus.h"
-#include "hw/virtio/virtio-access.h"
-#include "hw/fw-path-provider.h"
-#include "linux/vhost.h"
-#include "qemu/cutils.h"
-
-/* Features supported by host kernel. */
-static const int kernel_feature_bits[] = {
- VIRTIO_F_NOTIFY_ON_EMPTY,
- VIRTIO_RING_F_INDIRECT_DESC,
- VIRTIO_RING_F_EVENT_IDX,
- VIRTIO_SCSI_F_HOTPLUG,
- VHOST_INVALID_FEATURE_BIT
-};
-
-static int vhost_scsi_set_endpoint(VHostSCSI *s)
-{
- VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
- const VhostOps *vhost_ops = s->dev.vhost_ops;
- struct vhost_scsi_target backend;
- int ret;
-
- memset(&backend, 0, sizeof(backend));
- pstrcpy(backend.vhost_wwpn, sizeof(backend.vhost_wwpn), vs->conf.wwpn);
- ret = vhost_ops->vhost_scsi_set_endpoint(&s->dev, &backend);
- if (ret < 0) {
- return -errno;
- }
- return 0;
-}
-
-static void vhost_scsi_clear_endpoint(VHostSCSI *s)
-{
- VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
- struct vhost_scsi_target backend;
- const VhostOps *vhost_ops = s->dev.vhost_ops;
-
- memset(&backend, 0, sizeof(backend));
- pstrcpy(backend.vhost_wwpn, sizeof(backend.vhost_wwpn), vs->conf.wwpn);
- vhost_ops->vhost_scsi_clear_endpoint(&s->dev, &backend);
-}
-
-static int vhost_scsi_start(VHostSCSI *s)
-{
- int ret, abi_version, i;
- VirtIODevice *vdev = VIRTIO_DEVICE(s);
- BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
- VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
- const VhostOps *vhost_ops = s->dev.vhost_ops;
-
- if (!k->set_guest_notifiers) {
- error_report("binding does not support guest notifiers");
- return -ENOSYS;
- }
-
- ret = vhost_ops->vhost_scsi_get_abi_version(&s->dev, &abi_version);
- if (ret < 0) {
- return -errno;
- }
- if (abi_version > VHOST_SCSI_ABI_VERSION) {
- error_report("vhost-scsi: The running tcm_vhost kernel abi_version:"
- " %d is greater than vhost_scsi userspace supports: %d, please"
- " upgrade your version of QEMU", abi_version,
- VHOST_SCSI_ABI_VERSION);
- return -ENOSYS;
- }
-
- ret = vhost_dev_enable_notifiers(&s->dev, vdev);
- if (ret < 0) {
- return ret;
- }
-
- s->dev.acked_features = vdev->guest_features;
- ret = vhost_dev_start(&s->dev, vdev);
- if (ret < 0) {
- error_report("Error start vhost dev");
- goto err_notifiers;
- }
-
- ret = vhost_scsi_set_endpoint(s);
- if (ret < 0) {
- error_report("Error set vhost-scsi endpoint");
- goto err_vhost_stop;
- }
-
- ret = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, true);
- if (ret < 0) {
- error_report("Error binding guest notifier");
- goto err_endpoint;
- }
-
- /* guest_notifier_mask/pending not used yet, so just unmask
- * everything here. virtio-pci will do the right thing by
- * enabling/disabling irqfd.
- */
- for (i = 0; i < s->dev.nvqs; i++) {
- vhost_virtqueue_mask(&s->dev, vdev, s->dev.vq_index + i, false);
- }
-
- return ret;
-
-err_endpoint:
- vhost_scsi_clear_endpoint(s);
-err_vhost_stop:
- vhost_dev_stop(&s->dev, vdev);
-err_notifiers:
- vhost_dev_disable_notifiers(&s->dev, vdev);
- return ret;
-}
-
-static void vhost_scsi_stop(VHostSCSI *s)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(s);
- BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
- VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
- int ret = 0;
-
- if (k->set_guest_notifiers) {
- ret = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, false);
- if (ret < 0) {
- error_report("vhost guest notifier cleanup failed: %d", ret);
- }
- }
- assert(ret >= 0);
-
- vhost_scsi_clear_endpoint(s);
- vhost_dev_stop(&s->dev, vdev);
- vhost_dev_disable_notifiers(&s->dev, vdev);
-}
-
-static uint64_t vhost_scsi_get_features(VirtIODevice *vdev,
- uint64_t features,
- Error **errp)
-{
- VHostSCSI *s = VHOST_SCSI(vdev);
-
- return vhost_get_features(&s->dev, kernel_feature_bits, features);
-}
-
-static void vhost_scsi_set_config(VirtIODevice *vdev,
- const uint8_t *config)
-{
- VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config;
- VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
-
- if ((uint32_t) virtio_ldl_p(vdev, &scsiconf->sense_size) != vs->sense_size ||
- (uint32_t) virtio_ldl_p(vdev, &scsiconf->cdb_size) != vs->cdb_size) {
- error_report("vhost-scsi does not support changing the sense data and CDB sizes");
- exit(1);
- }
-}
-
-static void vhost_scsi_set_status(VirtIODevice *vdev, uint8_t val)
-{
- VHostSCSI *s = (VHostSCSI *)vdev;
- bool start = (val & VIRTIO_CONFIG_S_DRIVER_OK);
-
- if (s->dev.started == start) {
- return;
- }
-
- if (start) {
- int ret;
-
- ret = vhost_scsi_start(s);
- if (ret < 0) {
- error_report("virtio-scsi: unable to start vhost: %s",
- strerror(-ret));
-
- /* There is no userspace virtio-scsi fallback so exit */
- exit(1);
- }
- } else {
- vhost_scsi_stop(s);
- }
-}
-
-static void vhost_dummy_handle_output(VirtIODevice *vdev, VirtQueue *vq)
-{
-}
-
-static void vhost_scsi_realize(DeviceState *dev, Error **errp)
-{
- VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(dev);
- VHostSCSI *s = VHOST_SCSI(dev);
- Error *err = NULL;
- int vhostfd = -1;
- int ret;
-
- if (!vs->conf.wwpn) {
- error_setg(errp, "vhost-scsi: missing wwpn");
- return;
- }
-
- if (vs->conf.vhostfd) {
- vhostfd = monitor_fd_param(cur_mon, vs->conf.vhostfd, errp);
- if (vhostfd == -1) {
- error_prepend(errp, "vhost-scsi: unable to parse vhostfd: ");
- return;
- }
- } else {
- vhostfd = open("/dev/vhost-scsi", O_RDWR);
- if (vhostfd < 0) {
- error_setg(errp, "vhost-scsi: open vhost char device failed: %s",
- strerror(errno));
- return;
- }
- }
-
- virtio_scsi_common_realize(dev, &err, vhost_dummy_handle_output,
- vhost_dummy_handle_output,
- vhost_dummy_handle_output);
- if (err != NULL) {
- error_propagate(errp, err);
- close(vhostfd);
- return;
- }
-
- s->dev.nvqs = VHOST_SCSI_VQ_NUM_FIXED + vs->conf.num_queues;
- s->dev.vqs = g_new(struct vhost_virtqueue, s->dev.nvqs);
- s->dev.vq_index = 0;
- s->dev.backend_features = 0;
-
- ret = vhost_dev_init(&s->dev, (void *)(uintptr_t)vhostfd,
- VHOST_BACKEND_TYPE_KERNEL);
- if (ret < 0) {
- error_setg(errp, "vhost-scsi: vhost initialization failed: %s",
- strerror(-ret));
- return;
- }
-
- /* At present, channel and lun both are 0 for bootable vhost-scsi disk */
- s->channel = 0;
- s->lun = 0;
- /* Note: we can also get the minimum tpgt from kernel */
- s->target = vs->conf.boot_tpgt;
-
- error_setg(&s->migration_blocker,
- "vhost-scsi does not support migration");
- migrate_add_blocker(s->migration_blocker);
-}
-
-static void vhost_scsi_unrealize(DeviceState *dev, Error **errp)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
- VHostSCSI *s = VHOST_SCSI(dev);
-
- migrate_del_blocker(s->migration_blocker);
- error_free(s->migration_blocker);
-
- /* This will stop vhost backend. */
- vhost_scsi_set_status(vdev, 0);
-
- vhost_dev_cleanup(&s->dev);
- g_free(s->dev.vqs);
-
- virtio_scsi_common_unrealize(dev, errp);
-}
-
-/*
- * Implementation of an interface to adjust firmware path
- * for the bootindex property handling.
- */
-static char *vhost_scsi_get_fw_dev_path(FWPathProvider *p, BusState *bus,
- DeviceState *dev)
-{
- VHostSCSI *s = VHOST_SCSI(dev);
- /* format: channel@channel/vhost-scsi@target,lun */
- return g_strdup_printf("/channel@%x/%s@%x,%x", s->channel,
- qdev_fw_name(dev), s->target, s->lun);
-}
-
-static Property vhost_scsi_properties[] = {
- DEFINE_PROP_STRING("vhostfd", VHostSCSI, parent_obj.conf.vhostfd),
- DEFINE_PROP_STRING("wwpn", VHostSCSI, parent_obj.conf.wwpn),
- DEFINE_PROP_UINT32("boot_tpgt", VHostSCSI, parent_obj.conf.boot_tpgt, 0),
- DEFINE_PROP_UINT32("num_queues", VHostSCSI, parent_obj.conf.num_queues, 1),
- DEFINE_PROP_UINT32("max_sectors", VHostSCSI, parent_obj.conf.max_sectors,
- 0xFFFF),
- DEFINE_PROP_UINT32("cmd_per_lun", VHostSCSI, parent_obj.conf.cmd_per_lun,
- 128),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void vhost_scsi_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
- FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(klass);
-
- dc->props = vhost_scsi_properties;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
- vdc->realize = vhost_scsi_realize;
- vdc->unrealize = vhost_scsi_unrealize;
- vdc->get_features = vhost_scsi_get_features;
- vdc->set_config = vhost_scsi_set_config;
- vdc->set_status = vhost_scsi_set_status;
- fwc->get_dev_path = vhost_scsi_get_fw_dev_path;
-}
-
-static void vhost_scsi_instance_init(Object *obj)
-{
- VHostSCSI *dev = VHOST_SCSI(obj);
-
- device_add_bootindex_property(obj, &dev->bootindex, "bootindex", NULL,
- DEVICE(dev), NULL);
-}
-
-static const TypeInfo vhost_scsi_info = {
- .name = TYPE_VHOST_SCSI,
- .parent = TYPE_VIRTIO_SCSI_COMMON,
- .instance_size = sizeof(VHostSCSI),
- .class_init = vhost_scsi_class_init,
- .instance_init = vhost_scsi_instance_init,
- .interfaces = (InterfaceInfo[]) {
- { TYPE_FW_PATH_PROVIDER },
- { }
- },
-};
-
-static void virtio_register_types(void)
-{
- type_register_static(&vhost_scsi_info);
-}
-
-type_init(virtio_register_types)
diff --git a/qemu/hw/scsi/viosrp.h b/qemu/hw/scsi/viosrp.h
deleted file mode 100644
index d8e365db1..000000000
--- a/qemu/hw/scsi/viosrp.h
+++ /dev/null
@@ -1,216 +0,0 @@
-/*****************************************************************************/
-/* srp.h -- SCSI RDMA Protocol definitions */
-/* */
-/* Written By: Colin Devilbis, IBM Corporation */
-/* */
-/* Copyright (C) 2003 IBM Corporation */
-/* */
-/* This program is free software; you can redistribute it and/or modify */
-/* it under the terms of the GNU General Public License as published by */
-/* the Free Software Foundation; either version 2 of the License, or */
-/* (at your option) any later version. */
-/* */
-/* This program is distributed in the hope that it will be useful, */
-/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
-/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
-/* GNU General Public License for more details. */
-/* */
-/* You should have received a copy of the GNU General Public License */
-/* along with this program; if not, write to the Free Software */
-/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-/* */
-/* */
-/* This file contains structures and definitions for IBM RPA (RS/6000 */
-/* platform architecture) implementation of the SRP (SCSI RDMA Protocol) */
-/* standard. SRP is used on IBM iSeries and pSeries platforms to send SCSI */
-/* commands between logical partitions. */
-/* */
-/* SRP Information Units (IUs) are sent on a "Command/Response Queue" (CRQ) */
-/* between partitions. The definitions in this file are architected, */
-/* and cannot be changed without breaking compatibility with other versions */
-/* of Linux and other operating systems (AIX, OS/400) that talk this protocol*/
-/* between logical partitions */
-/*****************************************************************************/
-#ifndef PPC_VIOSRP_H
-#define PPC_VIOSRP_H
-
-#define SRP_VERSION "16.a"
-#define SRP_MAX_IU_LEN 256
-#define SRP_MAX_LOC_LEN 32
-
-union srp_iu {
- struct srp_login_req login_req;
- struct srp_login_rsp login_rsp;
- struct srp_login_rej login_rej;
- struct srp_i_logout i_logout;
- struct srp_t_logout t_logout;
- struct srp_tsk_mgmt tsk_mgmt;
- struct srp_cmd cmd;
- struct srp_rsp rsp;
- uint8_t reserved[SRP_MAX_IU_LEN];
-};
-
-enum viosrp_crq_formats {
- VIOSRP_SRP_FORMAT = 0x01,
- VIOSRP_MAD_FORMAT = 0x02,
- VIOSRP_OS400_FORMAT = 0x03,
- VIOSRP_AIX_FORMAT = 0x04,
- VIOSRP_LINUX_FORMAT = 0x06,
- VIOSRP_INLINE_FORMAT = 0x07
-};
-
-enum viosrp_crq_status {
- VIOSRP_OK = 0x0,
- VIOSRP_NONRECOVERABLE_ERR = 0x1,
- VIOSRP_VIOLATES_MAX_XFER = 0x2,
- VIOSRP_PARTNER_PANIC = 0x3,
- VIOSRP_DEVICE_BUSY = 0x8,
- VIOSRP_ADAPTER_FAIL = 0x10,
- VIOSRP_OK2 = 0x99,
-};
-
-struct viosrp_crq {
- uint8_t valid; /* used by RPA */
- uint8_t format; /* SCSI vs out-of-band */
- uint8_t reserved;
- uint8_t status; /* non-scsi failure? (e.g. DMA failure) */
- uint16_t timeout; /* in seconds */
- uint16_t IU_length; /* in bytes */
- uint64_t IU_data_ptr; /* the TCE for transferring data */
-};
-
-/* MADs are Management requests above and beyond the IUs defined in the SRP
- * standard.
- */
-enum viosrp_mad_types {
- VIOSRP_EMPTY_IU_TYPE = 0x01,
- VIOSRP_ERROR_LOG_TYPE = 0x02,
- VIOSRP_ADAPTER_INFO_TYPE = 0x03,
- VIOSRP_HOST_CONFIG_TYPE = 0x04,
- VIOSRP_CAPABILITIES_TYPE = 0x05,
- VIOSRP_ENABLE_FAST_FAIL = 0x08,
-};
-
-enum viosrp_mad_status {
- VIOSRP_MAD_SUCCESS = 0x00,
- VIOSRP_MAD_NOT_SUPPORTED = 0xF1,
- VIOSRP_MAD_FAILED = 0xF7,
-};
-
-enum viosrp_capability_type {
- MIGRATION_CAPABILITIES = 0x01,
- RESERVATION_CAPABILITIES = 0x02,
-};
-
-enum viosrp_capability_support {
- SERVER_DOES_NOT_SUPPORTS_CAP = 0x0,
- SERVER_SUPPORTS_CAP = 0x01,
- SERVER_CAP_DATA = 0x02,
-};
-
-enum viosrp_reserve_type {
- CLIENT_RESERVE_SCSI_2 = 0x01,
-};
-
-enum viosrp_capability_flag {
- CLIENT_MIGRATED = 0x01,
- CLIENT_RECONNECT = 0x02,
- CAP_LIST_SUPPORTED = 0x04,
- CAP_LIST_DATA = 0x08,
-};
-
-/*
- * Common MAD header
- */
-struct mad_common {
- uint32_t type;
- uint16_t status;
- uint16_t length;
- uint64_t tag;
-};
-
-/*
- * All SRP (and MAD) requests normally flow from the
- * client to the server. There is no way for the server to send
- * an asynchronous message back to the client. The Empty IU is used
- * to hang out a meaningless request to the server so that it can respond
- * asynchrouously with something like a SCSI AER
- */
-struct viosrp_empty_iu {
- struct mad_common common;
- uint64_t buffer;
- uint32_t port;
-};
-
-struct viosrp_error_log {
- struct mad_common common;
- uint64_t buffer;
-};
-
-struct viosrp_adapter_info {
- struct mad_common common;
- uint64_t buffer;
-};
-
-struct viosrp_host_config {
- struct mad_common common;
- uint64_t buffer;
-};
-
-struct viosrp_fast_fail {
- struct mad_common common;
-};
-
-struct viosrp_capabilities {
- struct mad_common common;
- uint64_t buffer;
-};
-
-struct mad_capability_common {
- uint32_t cap_type;
- uint16_t length;
- uint16_t server_support;
-};
-
-struct mad_reserve_cap {
- struct mad_capability_common common;
- uint32_t type;
-};
-
-struct mad_migration_cap {
- struct mad_capability_common common;
- uint32_t ecl;
-};
-
-struct capabilities {
- uint32_t flags;
- char name[SRP_MAX_LOC_LEN];
- char loc[SRP_MAX_LOC_LEN];
- struct mad_migration_cap migration;
- struct mad_reserve_cap reserve;
-};
-
-union mad_iu {
- struct viosrp_empty_iu empty_iu;
- struct viosrp_error_log error_log;
- struct viosrp_adapter_info adapter_info;
- struct viosrp_host_config host_config;
- struct viosrp_fast_fail fast_fail;
- struct viosrp_capabilities capabilities;
-};
-
-union viosrp_iu {
- union srp_iu srp;
- union mad_iu mad;
-};
-
-struct mad_adapter_info_data {
- char srp_version[8];
- char partition_name[96];
- uint32_t partition_number;
- uint32_t mad_version;
- uint32_t os_type;
- uint32_t port_max_txu[8]; /* per-port maximum transfer */
-};
-
-#endif
diff --git a/qemu/hw/scsi/virtio-scsi-dataplane.c b/qemu/hw/scsi/virtio-scsi-dataplane.c
deleted file mode 100644
index 1a49f1e4b..000000000
--- a/qemu/hw/scsi/virtio-scsi-dataplane.c
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * Virtio SCSI dataplane
- *
- * Copyright Red Hat, Inc. 2014
- *
- * Authors:
- * Fam Zheng <famz@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "hw/virtio/virtio-scsi.h"
-#include "qemu/error-report.h"
-#include "sysemu/block-backend.h"
-#include <hw/scsi/scsi.h>
-#include <block/scsi.h>
-#include <hw/virtio/virtio-bus.h>
-#include "hw/virtio/virtio-access.h"
-
-/* Context: QEMU global mutex held */
-void virtio_scsi_set_iothread(VirtIOSCSI *s, IOThread *iothread)
-{
- BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s)));
- VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
- VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
-
- assert(!s->ctx);
- s->ctx = iothread_get_aio_context(vs->conf.iothread);
-
- /* Don't try if transport does not support notifiers. */
- if (!k->set_guest_notifiers || !k->set_host_notifier) {
- fprintf(stderr, "virtio-scsi: Failed to set iothread "
- "(transport does not support notifiers)");
- exit(1);
- }
-}
-
-static void virtio_scsi_data_plane_handle_cmd(VirtIODevice *vdev,
- VirtQueue *vq)
-{
- VirtIOSCSI *s = (VirtIOSCSI *)vdev;
-
- assert(s->ctx && s->dataplane_started);
- virtio_scsi_handle_cmd_vq(s, vq);
-}
-
-static void virtio_scsi_data_plane_handle_ctrl(VirtIODevice *vdev,
- VirtQueue *vq)
-{
- VirtIOSCSI *s = VIRTIO_SCSI(vdev);
-
- assert(s->ctx && s->dataplane_started);
- virtio_scsi_handle_ctrl_vq(s, vq);
-}
-
-static void virtio_scsi_data_plane_handle_event(VirtIODevice *vdev,
- VirtQueue *vq)
-{
- VirtIOSCSI *s = VIRTIO_SCSI(vdev);
-
- assert(s->ctx && s->dataplane_started);
- virtio_scsi_handle_event_vq(s, vq);
-}
-
-static int virtio_scsi_vring_init(VirtIOSCSI *s, VirtQueue *vq, int n,
- void (*fn)(VirtIODevice *vdev, VirtQueue *vq))
-{
- BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s)));
- VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
- int rc;
-
- /* Set up virtqueue notify */
- rc = k->set_host_notifier(qbus->parent, n, true);
- if (rc != 0) {
- fprintf(stderr, "virtio-scsi: Failed to set host notifier (%d)\n",
- rc);
- s->dataplane_fenced = true;
- return rc;
- }
-
- virtio_queue_aio_set_host_notifier_handler(vq, s->ctx, fn);
- return 0;
-}
-
-void virtio_scsi_dataplane_notify(VirtIODevice *vdev, VirtIOSCSIReq *req)
-{
- if (virtio_should_notify(vdev, req->vq)) {
- event_notifier_set(virtio_queue_get_guest_notifier(req->vq));
- }
-}
-
-/* assumes s->ctx held */
-static void virtio_scsi_clear_aio(VirtIOSCSI *s)
-{
- VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
- int i;
-
- virtio_queue_aio_set_host_notifier_handler(vs->ctrl_vq, s->ctx, NULL);
- virtio_queue_aio_set_host_notifier_handler(vs->event_vq, s->ctx, NULL);
- for (i = 0; i < vs->conf.num_queues; i++) {
- virtio_queue_aio_set_host_notifier_handler(vs->cmd_vqs[i], s->ctx, NULL);
- }
-}
-
-/* Context: QEMU global mutex held */
-void virtio_scsi_dataplane_start(VirtIOSCSI *s)
-{
- int i;
- int rc;
- BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s)));
- VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
- VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
-
- if (s->dataplane_started ||
- s->dataplane_starting ||
- s->dataplane_fenced ||
- s->ctx != iothread_get_aio_context(vs->conf.iothread)) {
- return;
- }
-
- s->dataplane_starting = true;
-
- /* Set up guest notifier (irq) */
- rc = k->set_guest_notifiers(qbus->parent, vs->conf.num_queues + 2, true);
- if (rc != 0) {
- fprintf(stderr, "virtio-scsi: Failed to set guest notifiers (%d), "
- "ensure -enable-kvm is set\n", rc);
- goto fail_guest_notifiers;
- }
-
- aio_context_acquire(s->ctx);
- rc = virtio_scsi_vring_init(s, vs->ctrl_vq, 0,
- virtio_scsi_data_plane_handle_ctrl);
- if (rc) {
- goto fail_vrings;
- }
- rc = virtio_scsi_vring_init(s, vs->event_vq, 1,
- virtio_scsi_data_plane_handle_event);
- if (rc) {
- goto fail_vrings;
- }
- for (i = 0; i < vs->conf.num_queues; i++) {
- rc = virtio_scsi_vring_init(s, vs->cmd_vqs[i], i + 2,
- virtio_scsi_data_plane_handle_cmd);
- if (rc) {
- goto fail_vrings;
- }
- }
-
- s->dataplane_starting = false;
- s->dataplane_started = true;
- aio_context_release(s->ctx);
- return;
-
-fail_vrings:
- virtio_scsi_clear_aio(s);
- aio_context_release(s->ctx);
- for (i = 0; i < vs->conf.num_queues + 2; i++) {
- k->set_host_notifier(qbus->parent, i, false);
- }
- k->set_guest_notifiers(qbus->parent, vs->conf.num_queues + 2, false);
-fail_guest_notifiers:
- s->dataplane_fenced = true;
- s->dataplane_starting = false;
- s->dataplane_started = true;
-}
-
-/* Context: QEMU global mutex held */
-void virtio_scsi_dataplane_stop(VirtIOSCSI *s)
-{
- BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s)));
- VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
- VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
- int i;
-
- if (!s->dataplane_started || s->dataplane_stopping) {
- return;
- }
-
- /* Better luck next time. */
- if (s->dataplane_fenced) {
- s->dataplane_fenced = false;
- s->dataplane_started = false;
- return;
- }
- s->dataplane_stopping = true;
- assert(s->ctx == iothread_get_aio_context(vs->conf.iothread));
-
- aio_context_acquire(s->ctx);
-
- virtio_scsi_clear_aio(s);
-
- blk_drain_all(); /* ensure there are no in-flight requests */
-
- aio_context_release(s->ctx);
-
- for (i = 0; i < vs->conf.num_queues + 2; i++) {
- k->set_host_notifier(qbus->parent, i, false);
- }
-
- /* Clean up guest notifier (irq) */
- k->set_guest_notifiers(qbus->parent, vs->conf.num_queues + 2, false);
- s->dataplane_stopping = false;
- s->dataplane_started = false;
-}
diff --git a/qemu/hw/scsi/virtio-scsi.c b/qemu/hw/scsi/virtio-scsi.c
deleted file mode 100644
index 30415c6a9..000000000
--- a/qemu/hw/scsi/virtio-scsi.c
+++ /dev/null
@@ -1,1054 +0,0 @@
-/*
- * Virtio SCSI HBA
- *
- * Copyright IBM, Corp. 2010
- * Copyright Red Hat, Inc. 2011
- *
- * Authors:
- * Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
- * Paolo Bonzini <pbonzini@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "standard-headers/linux/virtio_ids.h"
-#include "hw/virtio/virtio-scsi.h"
-#include "qemu/error-report.h"
-#include "qemu/iov.h"
-#include "sysemu/block-backend.h"
-#include <hw/scsi/scsi.h>
-#include <block/scsi.h>
-#include <hw/virtio/virtio-bus.h>
-#include "hw/virtio/virtio-access.h"
-
-static inline int virtio_scsi_get_lun(uint8_t *lun)
-{
- return ((lun[2] << 8) | lun[3]) & 0x3FFF;
-}
-
-static inline SCSIDevice *virtio_scsi_device_find(VirtIOSCSI *s, uint8_t *lun)
-{
- if (lun[0] != 1) {
- return NULL;
- }
- if (lun[2] != 0 && !(lun[2] >= 0x40 && lun[2] < 0x80)) {
- return NULL;
- }
- return scsi_device_find(&s->bus, 0, lun[1], virtio_scsi_get_lun(lun));
-}
-
-void virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq, VirtIOSCSIReq *req)
-{
- const size_t zero_skip =
- offsetof(VirtIOSCSIReq, resp_iov) + sizeof(req->resp_iov);
-
- req->vq = vq;
- req->dev = s;
- qemu_sglist_init(&req->qsgl, DEVICE(s), 8, &address_space_memory);
- qemu_iovec_init(&req->resp_iov, 1);
- memset((uint8_t *)req + zero_skip, 0, sizeof(*req) - zero_skip);
-}
-
-void virtio_scsi_free_req(VirtIOSCSIReq *req)
-{
- qemu_iovec_destroy(&req->resp_iov);
- qemu_sglist_destroy(&req->qsgl);
- g_free(req);
-}
-
-static void virtio_scsi_complete_req(VirtIOSCSIReq *req)
-{
- VirtIOSCSI *s = req->dev;
- VirtQueue *vq = req->vq;
- VirtIODevice *vdev = VIRTIO_DEVICE(s);
-
- qemu_iovec_from_buf(&req->resp_iov, 0, &req->resp, req->resp_size);
- virtqueue_push(vq, &req->elem, req->qsgl.size + req->resp_iov.size);
- if (s->dataplane_started && !s->dataplane_fenced) {
- virtio_scsi_dataplane_notify(vdev, req);
- } else {
- virtio_notify(vdev, vq);
- }
-
- if (req->sreq) {
- req->sreq->hba_private = NULL;
- scsi_req_unref(req->sreq);
- }
- virtio_scsi_free_req(req);
-}
-
-static void virtio_scsi_bad_req(void)
-{
- error_report("wrong size for virtio-scsi headers");
- exit(1);
-}
-
-static size_t qemu_sgl_concat(VirtIOSCSIReq *req, struct iovec *iov,
- hwaddr *addr, int num, size_t skip)
-{
- QEMUSGList *qsgl = &req->qsgl;
- size_t copied = 0;
-
- while (num) {
- if (skip >= iov->iov_len) {
- skip -= iov->iov_len;
- } else {
- qemu_sglist_add(qsgl, *addr + skip, iov->iov_len - skip);
- copied += iov->iov_len - skip;
- skip = 0;
- }
- iov++;
- addr++;
- num--;
- }
-
- assert(skip == 0);
- return copied;
-}
-
-static int virtio_scsi_parse_req(VirtIOSCSIReq *req,
- unsigned req_size, unsigned resp_size)
-{
- VirtIODevice *vdev = (VirtIODevice *) req->dev;
- size_t in_size, out_size;
-
- if (iov_to_buf(req->elem.out_sg, req->elem.out_num, 0,
- &req->req, req_size) < req_size) {
- return -EINVAL;
- }
-
- if (qemu_iovec_concat_iov(&req->resp_iov,
- req->elem.in_sg, req->elem.in_num, 0,
- resp_size) < resp_size) {
- return -EINVAL;
- }
-
- req->resp_size = resp_size;
-
- /* Old BIOSes left some padding by mistake after the req_size/resp_size.
- * As a workaround, always consider the first buffer as the virtio-scsi
- * request/response, making the payload start at the second element
- * of the iovec.
- *
- * The actual length of the response header, stored in req->resp_size,
- * does not change.
- *
- * TODO: always disable this workaround for virtio 1.0 devices.
- */
- if (!virtio_vdev_has_feature(vdev, VIRTIO_F_ANY_LAYOUT)) {
- if (req->elem.out_num) {
- req_size = req->elem.out_sg[0].iov_len;
- }
- if (req->elem.in_num) {
- resp_size = req->elem.in_sg[0].iov_len;
- }
- }
-
- out_size = qemu_sgl_concat(req, req->elem.out_sg,
- &req->elem.out_addr[0], req->elem.out_num,
- req_size);
- in_size = qemu_sgl_concat(req, req->elem.in_sg,
- &req->elem.in_addr[0], req->elem.in_num,
- resp_size);
-
- if (out_size && in_size) {
- return -ENOTSUP;
- }
-
- if (out_size) {
- req->mode = SCSI_XFER_TO_DEV;
- } else if (in_size) {
- req->mode = SCSI_XFER_FROM_DEV;
- }
-
- return 0;
-}
-
-static VirtIOSCSIReq *virtio_scsi_pop_req(VirtIOSCSI *s, VirtQueue *vq)
-{
- VirtIOSCSICommon *vs = (VirtIOSCSICommon *)s;
- VirtIOSCSIReq *req;
-
- req = virtqueue_pop(vq, sizeof(VirtIOSCSIReq) + vs->cdb_size);
- if (!req) {
- return NULL;
- }
- virtio_scsi_init_req(s, vq, req);
- return req;
-}
-
-static void virtio_scsi_save_request(QEMUFile *f, SCSIRequest *sreq)
-{
- VirtIOSCSIReq *req = sreq->hba_private;
- VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(req->dev);
- uint32_t n = virtio_queue_get_id(req->vq) - 2;
-
- assert(n < vs->conf.num_queues);
- qemu_put_be32s(f, &n);
- qemu_put_virtqueue_element(f, &req->elem);
-}
-
-static void *virtio_scsi_load_request(QEMUFile *f, SCSIRequest *sreq)
-{
- SCSIBus *bus = sreq->bus;
- VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus);
- VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
- VirtIOSCSIReq *req;
- uint32_t n;
-
- qemu_get_be32s(f, &n);
- assert(n < vs->conf.num_queues);
- req = qemu_get_virtqueue_element(f, sizeof(VirtIOSCSIReq) + vs->cdb_size);
- virtio_scsi_init_req(s, vs->cmd_vqs[n], req);
-
- if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICmdReq) + vs->cdb_size,
- sizeof(VirtIOSCSICmdResp) + vs->sense_size) < 0) {
- error_report("invalid SCSI request migration data");
- exit(1);
- }
-
- scsi_req_ref(sreq);
- req->sreq = sreq;
- if (req->sreq->cmd.mode != SCSI_XFER_NONE) {
- assert(req->sreq->cmd.mode == req->mode);
- }
- return req;
-}
-
-typedef struct {
- Notifier notifier;
- VirtIOSCSIReq *tmf_req;
-} VirtIOSCSICancelNotifier;
-
-static void virtio_scsi_cancel_notify(Notifier *notifier, void *data)
-{
- VirtIOSCSICancelNotifier *n = container_of(notifier,
- VirtIOSCSICancelNotifier,
- notifier);
-
- if (--n->tmf_req->remaining == 0) {
- virtio_scsi_complete_req(n->tmf_req);
- }
- g_free(n);
-}
-
-/* Return 0 if the request is ready to be completed and return to guest;
- * -EINPROGRESS if the request is submitted and will be completed later, in the
- * case of async cancellation. */
-static int virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req)
-{
- SCSIDevice *d = virtio_scsi_device_find(s, req->req.tmf.lun);
- SCSIRequest *r, *next;
- BusChild *kid;
- int target;
- int ret = 0;
-
- if (s->dataplane_started && d) {
- assert(blk_get_aio_context(d->conf.blk) == s->ctx);
- }
- /* Here VIRTIO_SCSI_S_OK means "FUNCTION COMPLETE". */
- req->resp.tmf.response = VIRTIO_SCSI_S_OK;
-
- virtio_tswap32s(VIRTIO_DEVICE(s), &req->req.tmf.subtype);
- switch (req->req.tmf.subtype) {
- case VIRTIO_SCSI_T_TMF_ABORT_TASK:
- case VIRTIO_SCSI_T_TMF_QUERY_TASK:
- if (!d) {
- goto fail;
- }
- if (d->lun != virtio_scsi_get_lun(req->req.tmf.lun)) {
- goto incorrect_lun;
- }
- QTAILQ_FOREACH_SAFE(r, &d->requests, next, next) {
- VirtIOSCSIReq *cmd_req = r->hba_private;
- if (cmd_req && cmd_req->req.cmd.tag == req->req.tmf.tag) {
- break;
- }
- }
- if (r) {
- /*
- * Assert that the request has not been completed yet, we
- * check for it in the loop above.
- */
- assert(r->hba_private);
- if (req->req.tmf.subtype == VIRTIO_SCSI_T_TMF_QUERY_TASK) {
- /* "If the specified command is present in the task set, then
- * return a service response set to FUNCTION SUCCEEDED".
- */
- req->resp.tmf.response = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED;
- } else {
- VirtIOSCSICancelNotifier *notifier;
-
- req->remaining = 1;
- notifier = g_new(VirtIOSCSICancelNotifier, 1);
- notifier->tmf_req = req;
- notifier->notifier.notify = virtio_scsi_cancel_notify;
- scsi_req_cancel_async(r, &notifier->notifier);
- ret = -EINPROGRESS;
- }
- }
- break;
-
- case VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET:
- if (!d) {
- goto fail;
- }
- if (d->lun != virtio_scsi_get_lun(req->req.tmf.lun)) {
- goto incorrect_lun;
- }
- s->resetting++;
- qdev_reset_all(&d->qdev);
- s->resetting--;
- break;
-
- case VIRTIO_SCSI_T_TMF_ABORT_TASK_SET:
- case VIRTIO_SCSI_T_TMF_CLEAR_TASK_SET:
- case VIRTIO_SCSI_T_TMF_QUERY_TASK_SET:
- if (!d) {
- goto fail;
- }
- if (d->lun != virtio_scsi_get_lun(req->req.tmf.lun)) {
- goto incorrect_lun;
- }
-
- /* Add 1 to "remaining" until virtio_scsi_do_tmf returns.
- * This way, if the bus starts calling back to the notifiers
- * even before we finish the loop, virtio_scsi_cancel_notify
- * will not complete the TMF too early.
- */
- req->remaining = 1;
- QTAILQ_FOREACH_SAFE(r, &d->requests, next, next) {
- if (r->hba_private) {
- if (req->req.tmf.subtype == VIRTIO_SCSI_T_TMF_QUERY_TASK_SET) {
- /* "If there is any command present in the task set, then
- * return a service response set to FUNCTION SUCCEEDED".
- */
- req->resp.tmf.response = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED;
- break;
- } else {
- VirtIOSCSICancelNotifier *notifier;
-
- req->remaining++;
- notifier = g_new(VirtIOSCSICancelNotifier, 1);
- notifier->notifier.notify = virtio_scsi_cancel_notify;
- notifier->tmf_req = req;
- scsi_req_cancel_async(r, &notifier->notifier);
- }
- }
- }
- if (--req->remaining > 0) {
- ret = -EINPROGRESS;
- }
- break;
-
- case VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET:
- target = req->req.tmf.lun[1];
- s->resetting++;
- QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
- d = SCSI_DEVICE(kid->child);
- if (d->channel == 0 && d->id == target) {
- qdev_reset_all(&d->qdev);
- }
- }
- s->resetting--;
- break;
-
- case VIRTIO_SCSI_T_TMF_CLEAR_ACA:
- default:
- req->resp.tmf.response = VIRTIO_SCSI_S_FUNCTION_REJECTED;
- break;
- }
-
- return ret;
-
-incorrect_lun:
- req->resp.tmf.response = VIRTIO_SCSI_S_INCORRECT_LUN;
- return ret;
-
-fail:
- req->resp.tmf.response = VIRTIO_SCSI_S_BAD_TARGET;
- return ret;
-}
-
-static void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req)
-{
- VirtIODevice *vdev = (VirtIODevice *)s;
- uint32_t type;
- int r = 0;
-
- if (iov_to_buf(req->elem.out_sg, req->elem.out_num, 0,
- &type, sizeof(type)) < sizeof(type)) {
- virtio_scsi_bad_req();
- return;
- }
-
- virtio_tswap32s(vdev, &type);
- if (type == VIRTIO_SCSI_T_TMF) {
- if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICtrlTMFReq),
- sizeof(VirtIOSCSICtrlTMFResp)) < 0) {
- virtio_scsi_bad_req();
- } else {
- r = virtio_scsi_do_tmf(s, req);
- }
-
- } else if (type == VIRTIO_SCSI_T_AN_QUERY ||
- type == VIRTIO_SCSI_T_AN_SUBSCRIBE) {
- if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICtrlANReq),
- sizeof(VirtIOSCSICtrlANResp)) < 0) {
- virtio_scsi_bad_req();
- } else {
- req->resp.an.event_actual = 0;
- req->resp.an.response = VIRTIO_SCSI_S_OK;
- }
- }
- if (r == 0) {
- virtio_scsi_complete_req(req);
- } else {
- assert(r == -EINPROGRESS);
- }
-}
-
-void virtio_scsi_handle_ctrl_vq(VirtIOSCSI *s, VirtQueue *vq)
-{
- VirtIOSCSIReq *req;
-
- while ((req = virtio_scsi_pop_req(s, vq))) {
- virtio_scsi_handle_ctrl_req(s, req);
- }
-}
-
-static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
-{
- VirtIOSCSI *s = (VirtIOSCSI *)vdev;
-
- if (s->ctx) {
- virtio_scsi_dataplane_start(s);
- if (!s->dataplane_fenced) {
- return;
- }
- }
- virtio_scsi_handle_ctrl_vq(s, vq);
-}
-
-static void virtio_scsi_complete_cmd_req(VirtIOSCSIReq *req)
-{
- /* Sense data is not in req->resp and is copied separately
- * in virtio_scsi_command_complete.
- */
- req->resp_size = sizeof(VirtIOSCSICmdResp);
- virtio_scsi_complete_req(req);
-}
-
-static void virtio_scsi_command_complete(SCSIRequest *r, uint32_t status,
- size_t resid)
-{
- VirtIOSCSIReq *req = r->hba_private;
- uint8_t sense[SCSI_SENSE_BUF_SIZE];
- uint32_t sense_len;
- VirtIODevice *vdev = VIRTIO_DEVICE(req->dev);
-
- if (r->io_canceled) {
- return;
- }
-
- req->resp.cmd.response = VIRTIO_SCSI_S_OK;
- req->resp.cmd.status = status;
- if (req->resp.cmd.status == GOOD) {
- req->resp.cmd.resid = virtio_tswap32(vdev, resid);
- } else {
- req->resp.cmd.resid = 0;
- sense_len = scsi_req_get_sense(r, sense, sizeof(sense));
- sense_len = MIN(sense_len, req->resp_iov.size - sizeof(req->resp.cmd));
- qemu_iovec_from_buf(&req->resp_iov, sizeof(req->resp.cmd),
- sense, sense_len);
- req->resp.cmd.sense_len = virtio_tswap32(vdev, sense_len);
- }
- virtio_scsi_complete_cmd_req(req);
-}
-
-static int virtio_scsi_parse_cdb(SCSIDevice *dev, SCSICommand *cmd,
- uint8_t *buf, void *hba_private)
-{
- VirtIOSCSIReq *req = hba_private;
-
- if (cmd->len == 0) {
- cmd->len = MIN(VIRTIO_SCSI_CDB_DEFAULT_SIZE, SCSI_CMD_BUF_SIZE);
- memcpy(cmd->buf, buf, cmd->len);
- }
-
- /* Extract the direction and mode directly from the request, for
- * host device passthrough.
- */
- cmd->xfer = req->qsgl.size;
- cmd->mode = req->mode;
- return 0;
-}
-
-static QEMUSGList *virtio_scsi_get_sg_list(SCSIRequest *r)
-{
- VirtIOSCSIReq *req = r->hba_private;
-
- return &req->qsgl;
-}
-
-static void virtio_scsi_request_cancelled(SCSIRequest *r)
-{
- VirtIOSCSIReq *req = r->hba_private;
-
- if (!req) {
- return;
- }
- if (req->dev->resetting) {
- req->resp.cmd.response = VIRTIO_SCSI_S_RESET;
- } else {
- req->resp.cmd.response = VIRTIO_SCSI_S_ABORTED;
- }
- virtio_scsi_complete_cmd_req(req);
-}
-
-static void virtio_scsi_fail_cmd_req(VirtIOSCSIReq *req)
-{
- req->resp.cmd.response = VIRTIO_SCSI_S_FAILURE;
- virtio_scsi_complete_cmd_req(req);
-}
-
-static bool virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req)
-{
- VirtIOSCSICommon *vs = &s->parent_obj;
- SCSIDevice *d;
- int rc;
-
- rc = virtio_scsi_parse_req(req, sizeof(VirtIOSCSICmdReq) + vs->cdb_size,
- sizeof(VirtIOSCSICmdResp) + vs->sense_size);
- if (rc < 0) {
- if (rc == -ENOTSUP) {
- virtio_scsi_fail_cmd_req(req);
- } else {
- virtio_scsi_bad_req();
- }
- return false;
- }
-
- d = virtio_scsi_device_find(s, req->req.cmd.lun);
- if (!d) {
- req->resp.cmd.response = VIRTIO_SCSI_S_BAD_TARGET;
- virtio_scsi_complete_cmd_req(req);
- return false;
- }
- if (s->dataplane_started) {
- assert(blk_get_aio_context(d->conf.blk) == s->ctx);
- }
- req->sreq = scsi_req_new(d, req->req.cmd.tag,
- virtio_scsi_get_lun(req->req.cmd.lun),
- req->req.cmd.cdb, req);
-
- if (req->sreq->cmd.mode != SCSI_XFER_NONE
- && (req->sreq->cmd.mode != req->mode ||
- req->sreq->cmd.xfer > req->qsgl.size)) {
- req->resp.cmd.response = VIRTIO_SCSI_S_OVERRUN;
- virtio_scsi_complete_cmd_req(req);
- return false;
- }
- scsi_req_ref(req->sreq);
- blk_io_plug(d->conf.blk);
- return true;
-}
-
-static void virtio_scsi_handle_cmd_req_submit(VirtIOSCSI *s, VirtIOSCSIReq *req)
-{
- SCSIRequest *sreq = req->sreq;
- if (scsi_req_enqueue(sreq)) {
- scsi_req_continue(sreq);
- }
- blk_io_unplug(sreq->dev->conf.blk);
- scsi_req_unref(sreq);
-}
-
-void virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq)
-{
- VirtIOSCSIReq *req, *next;
- QTAILQ_HEAD(, VirtIOSCSIReq) reqs = QTAILQ_HEAD_INITIALIZER(reqs);
-
- while ((req = virtio_scsi_pop_req(s, vq))) {
- if (virtio_scsi_handle_cmd_req_prepare(s, req)) {
- QTAILQ_INSERT_TAIL(&reqs, req, next);
- }
- }
-
- QTAILQ_FOREACH_SAFE(req, &reqs, next, next) {
- virtio_scsi_handle_cmd_req_submit(s, req);
- }
-}
-
-static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq)
-{
- /* use non-QOM casts in the data path */
- VirtIOSCSI *s = (VirtIOSCSI *)vdev;
-
- if (s->ctx) {
- virtio_scsi_dataplane_start(s);
- if (!s->dataplane_fenced) {
- return;
- }
- }
- virtio_scsi_handle_cmd_vq(s, vq);
-}
-
-static void virtio_scsi_get_config(VirtIODevice *vdev,
- uint8_t *config)
-{
- VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config;
- VirtIOSCSICommon *s = VIRTIO_SCSI_COMMON(vdev);
-
- virtio_stl_p(vdev, &scsiconf->num_queues, s->conf.num_queues);
- virtio_stl_p(vdev, &scsiconf->seg_max, 128 - 2);
- virtio_stl_p(vdev, &scsiconf->max_sectors, s->conf.max_sectors);
- virtio_stl_p(vdev, &scsiconf->cmd_per_lun, s->conf.cmd_per_lun);
- virtio_stl_p(vdev, &scsiconf->event_info_size, sizeof(VirtIOSCSIEvent));
- virtio_stl_p(vdev, &scsiconf->sense_size, s->sense_size);
- virtio_stl_p(vdev, &scsiconf->cdb_size, s->cdb_size);
- virtio_stw_p(vdev, &scsiconf->max_channel, VIRTIO_SCSI_MAX_CHANNEL);
- virtio_stw_p(vdev, &scsiconf->max_target, VIRTIO_SCSI_MAX_TARGET);
- virtio_stl_p(vdev, &scsiconf->max_lun, VIRTIO_SCSI_MAX_LUN);
-}
-
-static void virtio_scsi_set_config(VirtIODevice *vdev,
- const uint8_t *config)
-{
- VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config;
- VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
-
- if ((uint32_t) virtio_ldl_p(vdev, &scsiconf->sense_size) >= 65536 ||
- (uint32_t) virtio_ldl_p(vdev, &scsiconf->cdb_size) >= 256) {
- error_report("bad data written to virtio-scsi configuration space");
- exit(1);
- }
-
- vs->sense_size = virtio_ldl_p(vdev, &scsiconf->sense_size);
- vs->cdb_size = virtio_ldl_p(vdev, &scsiconf->cdb_size);
-}
-
-static uint64_t virtio_scsi_get_features(VirtIODevice *vdev,
- uint64_t requested_features,
- Error **errp)
-{
- VirtIOSCSI *s = VIRTIO_SCSI(vdev);
-
- /* Firstly sync all virtio-scsi possible supported features */
- requested_features |= s->host_features;
- return requested_features;
-}
-
-static void virtio_scsi_reset(VirtIODevice *vdev)
-{
- VirtIOSCSI *s = VIRTIO_SCSI(vdev);
- VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
-
- if (s->ctx) {
- virtio_scsi_dataplane_stop(s);
- }
- s->resetting++;
- qbus_reset_all(&s->bus.qbus);
- s->resetting--;
-
- vs->sense_size = VIRTIO_SCSI_SENSE_DEFAULT_SIZE;
- vs->cdb_size = VIRTIO_SCSI_CDB_DEFAULT_SIZE;
- s->events_dropped = false;
-}
-
-/* The device does not have anything to save beyond the virtio data.
- * Request data is saved with callbacks from SCSI devices.
- */
-static void virtio_scsi_save(QEMUFile *f, void *opaque)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(opaque);
- VirtIOSCSI *s = VIRTIO_SCSI(vdev);
-
- if (s->dataplane_started) {
- virtio_scsi_dataplane_stop(s);
- }
- virtio_save(vdev, f);
-}
-
-static int virtio_scsi_load(QEMUFile *f, void *opaque, int version_id)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(opaque);
- int ret;
-
- ret = virtio_load(vdev, f, version_id);
- if (ret) {
- return ret;
- }
- return 0;
-}
-
-void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev,
- uint32_t event, uint32_t reason)
-{
- VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
- VirtIOSCSIReq *req;
- VirtIOSCSIEvent *evt;
- VirtIODevice *vdev = VIRTIO_DEVICE(s);
-
- if (!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) {
- return;
- }
-
- if (s->dataplane_started) {
- assert(s->ctx);
- aio_context_acquire(s->ctx);
- }
-
- req = virtio_scsi_pop_req(s, vs->event_vq);
- if (!req) {
- s->events_dropped = true;
- goto out;
- }
-
- if (s->events_dropped) {
- event |= VIRTIO_SCSI_T_EVENTS_MISSED;
- s->events_dropped = false;
- }
-
- if (virtio_scsi_parse_req(req, 0, sizeof(VirtIOSCSIEvent))) {
- virtio_scsi_bad_req();
- }
-
- evt = &req->resp.event;
- memset(evt, 0, sizeof(VirtIOSCSIEvent));
- evt->event = virtio_tswap32(vdev, event);
- evt->reason = virtio_tswap32(vdev, reason);
- if (!dev) {
- assert(event == VIRTIO_SCSI_T_EVENTS_MISSED);
- } else {
- evt->lun[0] = 1;
- evt->lun[1] = dev->id;
-
- /* Linux wants us to keep the same encoding we use for REPORT LUNS. */
- if (dev->lun >= 256) {
- evt->lun[2] = (dev->lun >> 8) | 0x40;
- }
- evt->lun[3] = dev->lun & 0xFF;
- }
- virtio_scsi_complete_req(req);
-out:
- if (s->dataplane_started) {
- aio_context_release(s->ctx);
- }
-}
-
-void virtio_scsi_handle_event_vq(VirtIOSCSI *s, VirtQueue *vq)
-{
- if (s->events_dropped) {
- virtio_scsi_push_event(s, NULL, VIRTIO_SCSI_T_NO_EVENT, 0);
- }
-}
-
-static void virtio_scsi_handle_event(VirtIODevice *vdev, VirtQueue *vq)
-{
- VirtIOSCSI *s = VIRTIO_SCSI(vdev);
-
- if (s->ctx) {
- virtio_scsi_dataplane_start(s);
- if (!s->dataplane_fenced) {
- return;
- }
- }
- virtio_scsi_handle_event_vq(s, vq);
-}
-
-static void virtio_scsi_change(SCSIBus *bus, SCSIDevice *dev, SCSISense sense)
-{
- VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus);
- VirtIODevice *vdev = VIRTIO_DEVICE(s);
-
- if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_CHANGE) &&
- dev->type != TYPE_ROM) {
- virtio_scsi_push_event(s, dev, VIRTIO_SCSI_T_PARAM_CHANGE,
- sense.asc | (sense.ascq << 8));
- }
-}
-
-static void virtio_scsi_blk_insert_notifier(Notifier *n, void *data)
-{
- VirtIOSCSIBlkChangeNotifier *cn = DO_UPCAST(VirtIOSCSIBlkChangeNotifier,
- n, n);
- assert(cn->sd->conf.blk == data);
- blk_op_block_all(cn->sd->conf.blk, cn->s->blocker);
-}
-
-static void virtio_scsi_blk_remove_notifier(Notifier *n, void *data)
-{
- VirtIOSCSIBlkChangeNotifier *cn = DO_UPCAST(VirtIOSCSIBlkChangeNotifier,
- n, n);
- assert(cn->sd->conf.blk == data);
- blk_op_unblock_all(cn->sd->conf.blk, cn->s->blocker);
-}
-
-static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev,
- Error **errp)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(hotplug_dev);
- VirtIOSCSI *s = VIRTIO_SCSI(vdev);
- SCSIDevice *sd = SCSI_DEVICE(dev);
-
- if (s->ctx && !s->dataplane_fenced) {
- VirtIOSCSIBlkChangeNotifier *insert_notifier, *remove_notifier;
-
- if (blk_op_is_blocked(sd->conf.blk, BLOCK_OP_TYPE_DATAPLANE, errp)) {
- return;
- }
- blk_op_block_all(sd->conf.blk, s->blocker);
- aio_context_acquire(s->ctx);
- blk_set_aio_context(sd->conf.blk, s->ctx);
- aio_context_release(s->ctx);
-
- insert_notifier = g_new0(VirtIOSCSIBlkChangeNotifier, 1);
- insert_notifier->n.notify = virtio_scsi_blk_insert_notifier;
- insert_notifier->s = s;
- insert_notifier->sd = sd;
- blk_add_insert_bs_notifier(sd->conf.blk, &insert_notifier->n);
- QTAILQ_INSERT_TAIL(&s->insert_notifiers, insert_notifier, next);
-
- remove_notifier = g_new0(VirtIOSCSIBlkChangeNotifier, 1);
- remove_notifier->n.notify = virtio_scsi_blk_remove_notifier;
- remove_notifier->s = s;
- remove_notifier->sd = sd;
- blk_add_remove_bs_notifier(sd->conf.blk, &remove_notifier->n);
- QTAILQ_INSERT_TAIL(&s->remove_notifiers, remove_notifier, next);
- }
-
- if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) {
- virtio_scsi_push_event(s, sd,
- VIRTIO_SCSI_T_TRANSPORT_RESET,
- VIRTIO_SCSI_EVT_RESET_RESCAN);
- }
-}
-
-static void virtio_scsi_hotunplug(HotplugHandler *hotplug_dev, DeviceState *dev,
- Error **errp)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(hotplug_dev);
- VirtIOSCSI *s = VIRTIO_SCSI(vdev);
- SCSIDevice *sd = SCSI_DEVICE(dev);
- VirtIOSCSIBlkChangeNotifier *insert_notifier, *remove_notifier;
-
- if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) {
- virtio_scsi_push_event(s, sd,
- VIRTIO_SCSI_T_TRANSPORT_RESET,
- VIRTIO_SCSI_EVT_RESET_REMOVED);
- }
-
- if (s->ctx) {
- blk_op_unblock_all(sd->conf.blk, s->blocker);
- }
-
- QTAILQ_FOREACH(insert_notifier, &s->insert_notifiers, next) {
- if (insert_notifier->sd == sd) {
- notifier_remove(&insert_notifier->n);
- QTAILQ_REMOVE(&s->insert_notifiers, insert_notifier, next);
- g_free(insert_notifier);
- break;
- }
- }
-
- QTAILQ_FOREACH(remove_notifier, &s->remove_notifiers, next) {
- if (remove_notifier->sd == sd) {
- notifier_remove(&remove_notifier->n);
- QTAILQ_REMOVE(&s->remove_notifiers, remove_notifier, next);
- g_free(remove_notifier);
- break;
- }
- }
-
- qdev_simple_device_unplug_cb(hotplug_dev, dev, errp);
-}
-
-static struct SCSIBusInfo virtio_scsi_scsi_info = {
- .tcq = true,
- .max_channel = VIRTIO_SCSI_MAX_CHANNEL,
- .max_target = VIRTIO_SCSI_MAX_TARGET,
- .max_lun = VIRTIO_SCSI_MAX_LUN,
-
- .complete = virtio_scsi_command_complete,
- .cancel = virtio_scsi_request_cancelled,
- .change = virtio_scsi_change,
- .parse_cdb = virtio_scsi_parse_cdb,
- .get_sg_list = virtio_scsi_get_sg_list,
- .save_request = virtio_scsi_save_request,
- .load_request = virtio_scsi_load_request,
-};
-
-void virtio_scsi_common_realize(DeviceState *dev, Error **errp,
- HandleOutput ctrl, HandleOutput evt,
- HandleOutput cmd)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
- VirtIOSCSICommon *s = VIRTIO_SCSI_COMMON(dev);
- int i;
-
- virtio_init(vdev, "virtio-scsi", VIRTIO_ID_SCSI,
- sizeof(VirtIOSCSIConfig));
-
- if (s->conf.num_queues == 0 ||
- s->conf.num_queues > VIRTIO_QUEUE_MAX - 2) {
- error_setg(errp, "Invalid number of queues (= %" PRIu32 "), "
- "must be a positive integer less than %d.",
- s->conf.num_queues, VIRTIO_QUEUE_MAX - 2);
- virtio_cleanup(vdev);
- return;
- }
- s->cmd_vqs = g_new0(VirtQueue *, s->conf.num_queues);
- s->sense_size = VIRTIO_SCSI_SENSE_DEFAULT_SIZE;
- s->cdb_size = VIRTIO_SCSI_CDB_DEFAULT_SIZE;
-
- s->ctrl_vq = virtio_add_queue(vdev, VIRTIO_SCSI_VQ_SIZE,
- ctrl);
- s->event_vq = virtio_add_queue(vdev, VIRTIO_SCSI_VQ_SIZE,
- evt);
- for (i = 0; i < s->conf.num_queues; i++) {
- s->cmd_vqs[i] = virtio_add_queue(vdev, VIRTIO_SCSI_VQ_SIZE,
- cmd);
- }
-
- if (s->conf.iothread) {
- virtio_scsi_set_iothread(VIRTIO_SCSI(s), s->conf.iothread);
- }
-}
-
-static void virtio_scsi_device_realize(DeviceState *dev, Error **errp)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
- VirtIOSCSI *s = VIRTIO_SCSI(dev);
- static int virtio_scsi_id;
- Error *err = NULL;
-
- virtio_scsi_common_realize(dev, &err, virtio_scsi_handle_ctrl,
- virtio_scsi_handle_event,
- virtio_scsi_handle_cmd);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
-
- scsi_bus_new(&s->bus, sizeof(s->bus), dev,
- &virtio_scsi_scsi_info, vdev->bus_name);
- /* override default SCSI bus hotplug-handler, with virtio-scsi's one */
- qbus_set_hotplug_handler(BUS(&s->bus), dev, &error_abort);
-
- if (!dev->hotplugged) {
- scsi_bus_legacy_handle_cmdline(&s->bus, &err);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
- }
-
- register_savevm(dev, "virtio-scsi", virtio_scsi_id++, 1,
- virtio_scsi_save, virtio_scsi_load, s);
-
- error_setg(&s->blocker, "block device is in use by data plane");
-
- QTAILQ_INIT(&s->insert_notifiers);
- QTAILQ_INIT(&s->remove_notifiers);
-}
-
-static void virtio_scsi_instance_init(Object *obj)
-{
- VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(obj);
-
- object_property_add_link(obj, "iothread", TYPE_IOTHREAD,
- (Object **)&vs->conf.iothread,
- qdev_prop_allow_set_link_before_realize,
- OBJ_PROP_LINK_UNREF_ON_RELEASE, &error_abort);
-}
-
-void virtio_scsi_common_unrealize(DeviceState *dev, Error **errp)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
- VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(dev);
-
- g_free(vs->cmd_vqs);
- virtio_cleanup(vdev);
-}
-
-static void virtio_scsi_device_unrealize(DeviceState *dev, Error **errp)
-{
- VirtIOSCSI *s = VIRTIO_SCSI(dev);
-
- error_free(s->blocker);
-
- unregister_savevm(dev, "virtio-scsi", s);
- virtio_scsi_common_unrealize(dev, errp);
-}
-
-static Property virtio_scsi_properties[] = {
- DEFINE_PROP_UINT32("num_queues", VirtIOSCSI, parent_obj.conf.num_queues, 1),
- DEFINE_PROP_UINT32("max_sectors", VirtIOSCSI, parent_obj.conf.max_sectors,
- 0xFFFF),
- DEFINE_PROP_UINT32("cmd_per_lun", VirtIOSCSI, parent_obj.conf.cmd_per_lun,
- 128),
- DEFINE_PROP_BIT("hotplug", VirtIOSCSI, host_features,
- VIRTIO_SCSI_F_HOTPLUG, true),
- DEFINE_PROP_BIT("param_change", VirtIOSCSI, host_features,
- VIRTIO_SCSI_F_CHANGE, true),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_scsi_common_class_init(ObjectClass *klass, void *data)
-{
- VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- vdc->get_config = virtio_scsi_get_config;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
-}
-
-static void virtio_scsi_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
- HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
-
- dc->props = virtio_scsi_properties;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
- vdc->realize = virtio_scsi_device_realize;
- vdc->unrealize = virtio_scsi_device_unrealize;
- vdc->set_config = virtio_scsi_set_config;
- vdc->get_features = virtio_scsi_get_features;
- vdc->reset = virtio_scsi_reset;
- hc->plug = virtio_scsi_hotplug;
- hc->unplug = virtio_scsi_hotunplug;
-}
-
-static const TypeInfo virtio_scsi_common_info = {
- .name = TYPE_VIRTIO_SCSI_COMMON,
- .parent = TYPE_VIRTIO_DEVICE,
- .instance_size = sizeof(VirtIOSCSICommon),
- .abstract = true,
- .class_init = virtio_scsi_common_class_init,
-};
-
-static const TypeInfo virtio_scsi_info = {
- .name = TYPE_VIRTIO_SCSI,
- .parent = TYPE_VIRTIO_SCSI_COMMON,
- .instance_size = sizeof(VirtIOSCSI),
- .instance_init = virtio_scsi_instance_init,
- .class_init = virtio_scsi_class_init,
- .interfaces = (InterfaceInfo[]) {
- { TYPE_HOTPLUG_HANDLER },
- { }
- }
-};
-
-static void virtio_register_types(void)
-{
- type_register_static(&virtio_scsi_common_info);
- type_register_static(&virtio_scsi_info);
-}
-
-type_init(virtio_register_types)
diff --git a/qemu/hw/scsi/vmw_pvscsi.c b/qemu/hw/scsi/vmw_pvscsi.c
deleted file mode 100644
index e690b4ec0..000000000
--- a/qemu/hw/scsi/vmw_pvscsi.c
+++ /dev/null
@@ -1,1305 +0,0 @@
-/*
- * QEMU VMWARE PVSCSI paravirtual SCSI bus
- *
- * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com)
- *
- * Developed by Daynix Computing LTD (http://www.daynix.com)
- *
- * Based on implementation by Paolo Bonzini
- * http://lists.gnu.org/archive/html/qemu-devel/2011-08/msg00729.html
- *
- * Authors:
- * Paolo Bonzini <pbonzini@redhat.com>
- * Dmitry Fleytman <dmitry@daynix.com>
- * Yan Vugenfirer <yan@daynix.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2.
- * See the COPYING file in the top-level directory.
- *
- * NOTE about MSI-X:
- * MSI-X support has been removed for the moment because it leads Windows OS
- * to crash on startup. The crash happens because Windows driver requires
- * MSI-X shared memory to be part of the same BAR used for rings state
- * registers, etc. This is not supported by QEMU infrastructure so separate
- * BAR created from MSI-X purposes. Windows driver fails to deal with 2 BARs.
- *
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/scsi/scsi.h"
-#include <block/scsi.h>
-#include "hw/pci/msi.h"
-#include "vmw_pvscsi.h"
-#include "trace.h"
-
-
-#define PVSCSI_USE_64BIT (true)
-#define PVSCSI_PER_VECTOR_MASK (false)
-
-#define PVSCSI_MAX_DEVS (64)
-#define PVSCSI_MSIX_NUM_VECTORS (1)
-
-#define PVSCSI_MAX_CMD_DATA_WORDS \
- (sizeof(PVSCSICmdDescSetupRings)/sizeof(uint32_t))
-
-#define RS_GET_FIELD(m, field) \
- (ldl_le_pci_dma(&container_of(m, PVSCSIState, rings)->parent_obj, \
- (m)->rs_pa + offsetof(struct PVSCSIRingsState, field)))
-#define RS_SET_FIELD(m, field, val) \
- (stl_le_pci_dma(&container_of(m, PVSCSIState, rings)->parent_obj, \
- (m)->rs_pa + offsetof(struct PVSCSIRingsState, field), val))
-
-typedef struct PVSCSIClass {
- PCIDeviceClass parent_class;
- DeviceRealize parent_dc_realize;
-} PVSCSIClass;
-
-#define TYPE_PVSCSI "pvscsi"
-#define PVSCSI(obj) OBJECT_CHECK(PVSCSIState, (obj), TYPE_PVSCSI)
-
-#define PVSCSI_DEVICE_CLASS(klass) \
- OBJECT_CLASS_CHECK(PVSCSIClass, (klass), TYPE_PVSCSI)
-#define PVSCSI_DEVICE_GET_CLASS(obj) \
- OBJECT_GET_CLASS(PVSCSIClass, (obj), TYPE_PVSCSI)
-
-/* Compatability flags for migration */
-#define PVSCSI_COMPAT_OLD_PCI_CONFIGURATION_BIT 0
-#define PVSCSI_COMPAT_OLD_PCI_CONFIGURATION \
- (1 << PVSCSI_COMPAT_OLD_PCI_CONFIGURATION_BIT)
-#define PVSCSI_COMPAT_DISABLE_PCIE_BIT 1
-#define PVSCSI_COMPAT_DISABLE_PCIE \
- (1 << PVSCSI_COMPAT_DISABLE_PCIE_BIT)
-
-#define PVSCSI_USE_OLD_PCI_CONFIGURATION(s) \
- ((s)->compat_flags & PVSCSI_COMPAT_OLD_PCI_CONFIGURATION)
-#define PVSCSI_MSI_OFFSET(s) \
- (PVSCSI_USE_OLD_PCI_CONFIGURATION(s) ? 0x50 : 0x7c)
-#define PVSCSI_EXP_EP_OFFSET (0x40)
-
-typedef struct PVSCSIRingInfo {
- uint64_t rs_pa;
- uint32_t txr_len_mask;
- uint32_t rxr_len_mask;
- uint32_t msg_len_mask;
- uint64_t req_ring_pages_pa[PVSCSI_SETUP_RINGS_MAX_NUM_PAGES];
- uint64_t cmp_ring_pages_pa[PVSCSI_SETUP_RINGS_MAX_NUM_PAGES];
- uint64_t msg_ring_pages_pa[PVSCSI_SETUP_MSG_RING_MAX_NUM_PAGES];
- uint64_t consumed_ptr;
- uint64_t filled_cmp_ptr;
- uint64_t filled_msg_ptr;
-} PVSCSIRingInfo;
-
-typedef struct PVSCSISGState {
- hwaddr elemAddr;
- hwaddr dataAddr;
- uint32_t resid;
-} PVSCSISGState;
-
-typedef QTAILQ_HEAD(, PVSCSIRequest) PVSCSIRequestList;
-
-typedef struct {
- PCIDevice parent_obj;
- MemoryRegion io_space;
- SCSIBus bus;
- QEMUBH *completion_worker;
- PVSCSIRequestList pending_queue;
- PVSCSIRequestList completion_queue;
-
- uint64_t reg_interrupt_status; /* Interrupt status register value */
- uint64_t reg_interrupt_enabled; /* Interrupt mask register value */
- uint64_t reg_command_status; /* Command status register value */
-
- /* Command data adoption mechanism */
- uint64_t curr_cmd; /* Last command arrived */
- uint32_t curr_cmd_data_cntr; /* Amount of data for last command */
-
- /* Collector for current command data */
- uint32_t curr_cmd_data[PVSCSI_MAX_CMD_DATA_WORDS];
-
- uint8_t rings_info_valid; /* Whether data rings initialized */
- uint8_t msg_ring_info_valid; /* Whether message ring initialized */
- uint8_t use_msg; /* Whether to use message ring */
-
- uint8_t msi_used; /* Whether MSI support was installed successfully */
-
- PVSCSIRingInfo rings; /* Data transfer rings manager */
- uint32_t resetting; /* Reset in progress */
-
- uint32_t compat_flags;
-} PVSCSIState;
-
-typedef struct PVSCSIRequest {
- SCSIRequest *sreq;
- PVSCSIState *dev;
- uint8_t sense_key;
- uint8_t completed;
- int lun;
- QEMUSGList sgl;
- PVSCSISGState sg;
- struct PVSCSIRingReqDesc req;
- struct PVSCSIRingCmpDesc cmp;
- QTAILQ_ENTRY(PVSCSIRequest) next;
-} PVSCSIRequest;
-
-/* Integer binary logarithm */
-static int
-pvscsi_log2(uint32_t input)
-{
- int log = 0;
- assert(input > 0);
- while (input >> ++log) {
- }
- return log;
-}
-
-static void
-pvscsi_ring_init_data(PVSCSIRingInfo *m, PVSCSICmdDescSetupRings *ri)
-{
- int i;
- uint32_t txr_len_log2, rxr_len_log2;
- uint32_t req_ring_size, cmp_ring_size;
- m->rs_pa = ri->ringsStatePPN << VMW_PAGE_SHIFT;
-
- req_ring_size = ri->reqRingNumPages * PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE;
- cmp_ring_size = ri->cmpRingNumPages * PVSCSI_MAX_NUM_CMP_ENTRIES_PER_PAGE;
- txr_len_log2 = pvscsi_log2(req_ring_size - 1);
- rxr_len_log2 = pvscsi_log2(cmp_ring_size - 1);
-
- m->txr_len_mask = MASK(txr_len_log2);
- m->rxr_len_mask = MASK(rxr_len_log2);
-
- m->consumed_ptr = 0;
- m->filled_cmp_ptr = 0;
-
- for (i = 0; i < ri->reqRingNumPages; i++) {
- m->req_ring_pages_pa[i] = ri->reqRingPPNs[i] << VMW_PAGE_SHIFT;
- }
-
- for (i = 0; i < ri->cmpRingNumPages; i++) {
- m->cmp_ring_pages_pa[i] = ri->cmpRingPPNs[i] << VMW_PAGE_SHIFT;
- }
-
- RS_SET_FIELD(m, reqProdIdx, 0);
- RS_SET_FIELD(m, reqConsIdx, 0);
- RS_SET_FIELD(m, reqNumEntriesLog2, txr_len_log2);
-
- RS_SET_FIELD(m, cmpProdIdx, 0);
- RS_SET_FIELD(m, cmpConsIdx, 0);
- RS_SET_FIELD(m, cmpNumEntriesLog2, rxr_len_log2);
-
- trace_pvscsi_ring_init_data(txr_len_log2, rxr_len_log2);
-
- /* Flush ring state page changes */
- smp_wmb();
-}
-
-static void
-pvscsi_ring_init_msg(PVSCSIRingInfo *m, PVSCSICmdDescSetupMsgRing *ri)
-{
- int i;
- uint32_t len_log2;
- uint32_t ring_size;
-
- ring_size = ri->numPages * PVSCSI_MAX_NUM_MSG_ENTRIES_PER_PAGE;
- len_log2 = pvscsi_log2(ring_size - 1);
-
- m->msg_len_mask = MASK(len_log2);
-
- m->filled_msg_ptr = 0;
-
- for (i = 0; i < ri->numPages; i++) {
- m->msg_ring_pages_pa[i] = ri->ringPPNs[i] << VMW_PAGE_SHIFT;
- }
-
- RS_SET_FIELD(m, msgProdIdx, 0);
- RS_SET_FIELD(m, msgConsIdx, 0);
- RS_SET_FIELD(m, msgNumEntriesLog2, len_log2);
-
- trace_pvscsi_ring_init_msg(len_log2);
-
- /* Flush ring state page changes */
- smp_wmb();
-}
-
-static void
-pvscsi_ring_cleanup(PVSCSIRingInfo *mgr)
-{
- mgr->rs_pa = 0;
- mgr->txr_len_mask = 0;
- mgr->rxr_len_mask = 0;
- mgr->msg_len_mask = 0;
- mgr->consumed_ptr = 0;
- mgr->filled_cmp_ptr = 0;
- mgr->filled_msg_ptr = 0;
- memset(mgr->req_ring_pages_pa, 0, sizeof(mgr->req_ring_pages_pa));
- memset(mgr->cmp_ring_pages_pa, 0, sizeof(mgr->cmp_ring_pages_pa));
- memset(mgr->msg_ring_pages_pa, 0, sizeof(mgr->msg_ring_pages_pa));
-}
-
-static hwaddr
-pvscsi_ring_pop_req_descr(PVSCSIRingInfo *mgr)
-{
- uint32_t ready_ptr = RS_GET_FIELD(mgr, reqProdIdx);
-
- if (ready_ptr != mgr->consumed_ptr) {
- uint32_t next_ready_ptr =
- mgr->consumed_ptr++ & mgr->txr_len_mask;
- uint32_t next_ready_page =
- next_ready_ptr / PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE;
- uint32_t inpage_idx =
- next_ready_ptr % PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE;
-
- return mgr->req_ring_pages_pa[next_ready_page] +
- inpage_idx * sizeof(PVSCSIRingReqDesc);
- } else {
- return 0;
- }
-}
-
-static void
-pvscsi_ring_flush_req(PVSCSIRingInfo *mgr)
-{
- RS_SET_FIELD(mgr, reqConsIdx, mgr->consumed_ptr);
-}
-
-static hwaddr
-pvscsi_ring_pop_cmp_descr(PVSCSIRingInfo *mgr)
-{
- /*
- * According to Linux driver code it explicitly verifies that number
- * of requests being processed by device is less then the size of
- * completion queue, so device may omit completion queue overflow
- * conditions check. We assume that this is true for other (Windows)
- * drivers as well.
- */
-
- uint32_t free_cmp_ptr =
- mgr->filled_cmp_ptr++ & mgr->rxr_len_mask;
- uint32_t free_cmp_page =
- free_cmp_ptr / PVSCSI_MAX_NUM_CMP_ENTRIES_PER_PAGE;
- uint32_t inpage_idx =
- free_cmp_ptr % PVSCSI_MAX_NUM_CMP_ENTRIES_PER_PAGE;
- return mgr->cmp_ring_pages_pa[free_cmp_page] +
- inpage_idx * sizeof(PVSCSIRingCmpDesc);
-}
-
-static hwaddr
-pvscsi_ring_pop_msg_descr(PVSCSIRingInfo *mgr)
-{
- uint32_t free_msg_ptr =
- mgr->filled_msg_ptr++ & mgr->msg_len_mask;
- uint32_t free_msg_page =
- free_msg_ptr / PVSCSI_MAX_NUM_MSG_ENTRIES_PER_PAGE;
- uint32_t inpage_idx =
- free_msg_ptr % PVSCSI_MAX_NUM_MSG_ENTRIES_PER_PAGE;
- return mgr->msg_ring_pages_pa[free_msg_page] +
- inpage_idx * sizeof(PVSCSIRingMsgDesc);
-}
-
-static void
-pvscsi_ring_flush_cmp(PVSCSIRingInfo *mgr)
-{
- /* Flush descriptor changes */
- smp_wmb();
-
- trace_pvscsi_ring_flush_cmp(mgr->filled_cmp_ptr);
-
- RS_SET_FIELD(mgr, cmpProdIdx, mgr->filled_cmp_ptr);
-}
-
-static bool
-pvscsi_ring_msg_has_room(PVSCSIRingInfo *mgr)
-{
- uint32_t prodIdx = RS_GET_FIELD(mgr, msgProdIdx);
- uint32_t consIdx = RS_GET_FIELD(mgr, msgConsIdx);
-
- return (prodIdx - consIdx) < (mgr->msg_len_mask + 1);
-}
-
-static void
-pvscsi_ring_flush_msg(PVSCSIRingInfo *mgr)
-{
- /* Flush descriptor changes */
- smp_wmb();
-
- trace_pvscsi_ring_flush_msg(mgr->filled_msg_ptr);
-
- RS_SET_FIELD(mgr, msgProdIdx, mgr->filled_msg_ptr);
-}
-
-static void
-pvscsi_reset_state(PVSCSIState *s)
-{
- s->curr_cmd = PVSCSI_CMD_FIRST;
- s->curr_cmd_data_cntr = 0;
- s->reg_command_status = PVSCSI_COMMAND_PROCESSING_SUCCEEDED;
- s->reg_interrupt_status = 0;
- pvscsi_ring_cleanup(&s->rings);
- s->rings_info_valid = FALSE;
- s->msg_ring_info_valid = FALSE;
- QTAILQ_INIT(&s->pending_queue);
- QTAILQ_INIT(&s->completion_queue);
-}
-
-static void
-pvscsi_update_irq_status(PVSCSIState *s)
-{
- PCIDevice *d = PCI_DEVICE(s);
- bool should_raise = s->reg_interrupt_enabled & s->reg_interrupt_status;
-
- trace_pvscsi_update_irq_level(should_raise, s->reg_interrupt_enabled,
- s->reg_interrupt_status);
-
- if (s->msi_used && msi_enabled(d)) {
- if (should_raise) {
- trace_pvscsi_update_irq_msi();
- msi_notify(d, PVSCSI_VECTOR_COMPLETION);
- }
- return;
- }
-
- pci_set_irq(d, !!should_raise);
-}
-
-static void
-pvscsi_raise_completion_interrupt(PVSCSIState *s)
-{
- s->reg_interrupt_status |= PVSCSI_INTR_CMPL_0;
-
- /* Memory barrier to flush interrupt status register changes*/
- smp_wmb();
-
- pvscsi_update_irq_status(s);
-}
-
-static void
-pvscsi_raise_message_interrupt(PVSCSIState *s)
-{
- s->reg_interrupt_status |= PVSCSI_INTR_MSG_0;
-
- /* Memory barrier to flush interrupt status register changes*/
- smp_wmb();
-
- pvscsi_update_irq_status(s);
-}
-
-static void
-pvscsi_cmp_ring_put(PVSCSIState *s, struct PVSCSIRingCmpDesc *cmp_desc)
-{
- hwaddr cmp_descr_pa;
-
- cmp_descr_pa = pvscsi_ring_pop_cmp_descr(&s->rings);
- trace_pvscsi_cmp_ring_put(cmp_descr_pa);
- cpu_physical_memory_write(cmp_descr_pa, (void *)cmp_desc,
- sizeof(*cmp_desc));
-}
-
-static void
-pvscsi_msg_ring_put(PVSCSIState *s, struct PVSCSIRingMsgDesc *msg_desc)
-{
- hwaddr msg_descr_pa;
-
- msg_descr_pa = pvscsi_ring_pop_msg_descr(&s->rings);
- trace_pvscsi_msg_ring_put(msg_descr_pa);
- cpu_physical_memory_write(msg_descr_pa, (void *)msg_desc,
- sizeof(*msg_desc));
-}
-
-static void
-pvscsi_process_completion_queue(void *opaque)
-{
- PVSCSIState *s = opaque;
- PVSCSIRequest *pvscsi_req;
- bool has_completed = false;
-
- while (!QTAILQ_EMPTY(&s->completion_queue)) {
- pvscsi_req = QTAILQ_FIRST(&s->completion_queue);
- QTAILQ_REMOVE(&s->completion_queue, pvscsi_req, next);
- pvscsi_cmp_ring_put(s, &pvscsi_req->cmp);
- g_free(pvscsi_req);
- has_completed = true;
- }
-
- if (has_completed) {
- pvscsi_ring_flush_cmp(&s->rings);
- pvscsi_raise_completion_interrupt(s);
- }
-}
-
-static void
-pvscsi_reset_adapter(PVSCSIState *s)
-{
- s->resetting++;
- qbus_reset_all_fn(&s->bus);
- s->resetting--;
- pvscsi_process_completion_queue(s);
- assert(QTAILQ_EMPTY(&s->pending_queue));
- pvscsi_reset_state(s);
-}
-
-static void
-pvscsi_schedule_completion_processing(PVSCSIState *s)
-{
- /* Try putting more complete requests on the ring. */
- if (!QTAILQ_EMPTY(&s->completion_queue)) {
- qemu_bh_schedule(s->completion_worker);
- }
-}
-
-static void
-pvscsi_complete_request(PVSCSIState *s, PVSCSIRequest *r)
-{
- assert(!r->completed);
-
- trace_pvscsi_complete_request(r->cmp.context, r->cmp.dataLen,
- r->sense_key);
- if (r->sreq != NULL) {
- scsi_req_unref(r->sreq);
- r->sreq = NULL;
- }
- r->completed = 1;
- QTAILQ_REMOVE(&s->pending_queue, r, next);
- QTAILQ_INSERT_TAIL(&s->completion_queue, r, next);
- pvscsi_schedule_completion_processing(s);
-}
-
-static QEMUSGList *pvscsi_get_sg_list(SCSIRequest *r)
-{
- PVSCSIRequest *req = r->hba_private;
-
- trace_pvscsi_get_sg_list(req->sgl.nsg, req->sgl.size);
-
- return &req->sgl;
-}
-
-static void
-pvscsi_get_next_sg_elem(PVSCSISGState *sg)
-{
- struct PVSCSISGElement elem;
-
- cpu_physical_memory_read(sg->elemAddr, (void *)&elem, sizeof(elem));
- if ((elem.flags & ~PVSCSI_KNOWN_FLAGS) != 0) {
- /*
- * There is PVSCSI_SGE_FLAG_CHAIN_ELEMENT flag described in
- * header file but its value is unknown. This flag requires
- * additional processing, so we put warning here to catch it
- * some day and make proper implementation
- */
- trace_pvscsi_get_next_sg_elem(elem.flags);
- }
-
- sg->elemAddr += sizeof(elem);
- sg->dataAddr = elem.addr;
- sg->resid = elem.length;
-}
-
-static void
-pvscsi_write_sense(PVSCSIRequest *r, uint8_t *sense, int len)
-{
- r->cmp.senseLen = MIN(r->req.senseLen, len);
- r->sense_key = sense[(sense[0] & 2) ? 1 : 2];
- cpu_physical_memory_write(r->req.senseAddr, sense, r->cmp.senseLen);
-}
-
-static void
-pvscsi_command_complete(SCSIRequest *req, uint32_t status, size_t resid)
-{
- PVSCSIRequest *pvscsi_req = req->hba_private;
- PVSCSIState *s;
-
- if (!pvscsi_req) {
- trace_pvscsi_command_complete_not_found(req->tag);
- return;
- }
- s = pvscsi_req->dev;
-
- if (resid) {
- /* Short transfer. */
- trace_pvscsi_command_complete_data_run();
- pvscsi_req->cmp.hostStatus = BTSTAT_DATARUN;
- }
-
- pvscsi_req->cmp.scsiStatus = status;
- if (pvscsi_req->cmp.scsiStatus == CHECK_CONDITION) {
- uint8_t sense[SCSI_SENSE_BUF_SIZE];
- int sense_len =
- scsi_req_get_sense(pvscsi_req->sreq, sense, sizeof(sense));
-
- trace_pvscsi_command_complete_sense_len(sense_len);
- pvscsi_write_sense(pvscsi_req, sense, sense_len);
- }
- qemu_sglist_destroy(&pvscsi_req->sgl);
- pvscsi_complete_request(s, pvscsi_req);
-}
-
-static void
-pvscsi_send_msg(PVSCSIState *s, SCSIDevice *dev, uint32_t msg_type)
-{
- if (s->msg_ring_info_valid && pvscsi_ring_msg_has_room(&s->rings)) {
- PVSCSIMsgDescDevStatusChanged msg = {0};
-
- msg.type = msg_type;
- msg.bus = dev->channel;
- msg.target = dev->id;
- msg.lun[1] = dev->lun;
-
- pvscsi_msg_ring_put(s, (PVSCSIRingMsgDesc *)&msg);
- pvscsi_ring_flush_msg(&s->rings);
- pvscsi_raise_message_interrupt(s);
- }
-}
-
-static void
-pvscsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp)
-{
- PVSCSIState *s = PVSCSI(hotplug_dev);
-
- pvscsi_send_msg(s, SCSI_DEVICE(dev), PVSCSI_MSG_DEV_ADDED);
-}
-
-static void
-pvscsi_hot_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp)
-{
- PVSCSIState *s = PVSCSI(hotplug_dev);
-
- pvscsi_send_msg(s, SCSI_DEVICE(dev), PVSCSI_MSG_DEV_REMOVED);
- qdev_simple_device_unplug_cb(hotplug_dev, dev, errp);
-}
-
-static void
-pvscsi_request_cancelled(SCSIRequest *req)
-{
- PVSCSIRequest *pvscsi_req = req->hba_private;
- PVSCSIState *s = pvscsi_req->dev;
-
- if (pvscsi_req->completed) {
- return;
- }
-
- if (pvscsi_req->dev->resetting) {
- pvscsi_req->cmp.hostStatus = BTSTAT_BUSRESET;
- } else {
- pvscsi_req->cmp.hostStatus = BTSTAT_ABORTQUEUE;
- }
-
- pvscsi_complete_request(s, pvscsi_req);
-}
-
-static SCSIDevice*
-pvscsi_device_find(PVSCSIState *s, int channel, int target,
- uint8_t *requested_lun, uint8_t *target_lun)
-{
- if (requested_lun[0] || requested_lun[2] || requested_lun[3] ||
- requested_lun[4] || requested_lun[5] || requested_lun[6] ||
- requested_lun[7] || (target > PVSCSI_MAX_DEVS)) {
- return NULL;
- } else {
- *target_lun = requested_lun[1];
- return scsi_device_find(&s->bus, channel, target, *target_lun);
- }
-}
-
-static PVSCSIRequest *
-pvscsi_queue_pending_descriptor(PVSCSIState *s, SCSIDevice **d,
- struct PVSCSIRingReqDesc *descr)
-{
- PVSCSIRequest *pvscsi_req;
- uint8_t lun;
-
- pvscsi_req = g_malloc0(sizeof(*pvscsi_req));
- pvscsi_req->dev = s;
- pvscsi_req->req = *descr;
- pvscsi_req->cmp.context = pvscsi_req->req.context;
- QTAILQ_INSERT_TAIL(&s->pending_queue, pvscsi_req, next);
-
- *d = pvscsi_device_find(s, descr->bus, descr->target, descr->lun, &lun);
- if (*d) {
- pvscsi_req->lun = lun;
- }
-
- return pvscsi_req;
-}
-
-static void
-pvscsi_convert_sglist(PVSCSIRequest *r)
-{
- int chunk_size;
- uint64_t data_length = r->req.dataLen;
- PVSCSISGState sg = r->sg;
- while (data_length) {
- while (!sg.resid) {
- pvscsi_get_next_sg_elem(&sg);
- trace_pvscsi_convert_sglist(r->req.context, r->sg.dataAddr,
- r->sg.resid);
- }
- assert(data_length > 0);
- chunk_size = MIN((unsigned) data_length, sg.resid);
- if (chunk_size) {
- qemu_sglist_add(&r->sgl, sg.dataAddr, chunk_size);
- }
-
- sg.dataAddr += chunk_size;
- data_length -= chunk_size;
- sg.resid -= chunk_size;
- }
-}
-
-static void
-pvscsi_build_sglist(PVSCSIState *s, PVSCSIRequest *r)
-{
- PCIDevice *d = PCI_DEVICE(s);
-
- pci_dma_sglist_init(&r->sgl, d, 1);
- if (r->req.flags & PVSCSI_FLAG_CMD_WITH_SG_LIST) {
- pvscsi_convert_sglist(r);
- } else {
- qemu_sglist_add(&r->sgl, r->req.dataAddr, r->req.dataLen);
- }
-}
-
-static void
-pvscsi_process_request_descriptor(PVSCSIState *s,
- struct PVSCSIRingReqDesc *descr)
-{
- SCSIDevice *d;
- PVSCSIRequest *r = pvscsi_queue_pending_descriptor(s, &d, descr);
- int64_t n;
-
- trace_pvscsi_process_req_descr(descr->cdb[0], descr->context);
-
- if (!d) {
- r->cmp.hostStatus = BTSTAT_SELTIMEO;
- trace_pvscsi_process_req_descr_unknown_device();
- pvscsi_complete_request(s, r);
- return;
- }
-
- if (descr->flags & PVSCSI_FLAG_CMD_WITH_SG_LIST) {
- r->sg.elemAddr = descr->dataAddr;
- }
-
- r->sreq = scsi_req_new(d, descr->context, r->lun, descr->cdb, r);
- if (r->sreq->cmd.mode == SCSI_XFER_FROM_DEV &&
- (descr->flags & PVSCSI_FLAG_CMD_DIR_TODEVICE)) {
- r->cmp.hostStatus = BTSTAT_BADMSG;
- trace_pvscsi_process_req_descr_invalid_dir();
- scsi_req_cancel(r->sreq);
- return;
- }
- if (r->sreq->cmd.mode == SCSI_XFER_TO_DEV &&
- (descr->flags & PVSCSI_FLAG_CMD_DIR_TOHOST)) {
- r->cmp.hostStatus = BTSTAT_BADMSG;
- trace_pvscsi_process_req_descr_invalid_dir();
- scsi_req_cancel(r->sreq);
- return;
- }
-
- pvscsi_build_sglist(s, r);
- n = scsi_req_enqueue(r->sreq);
-
- if (n) {
- scsi_req_continue(r->sreq);
- }
-}
-
-static void
-pvscsi_process_io(PVSCSIState *s)
-{
- PVSCSIRingReqDesc descr;
- hwaddr next_descr_pa;
-
- assert(s->rings_info_valid);
- while ((next_descr_pa = pvscsi_ring_pop_req_descr(&s->rings)) != 0) {
-
- /* Only read after production index verification */
- smp_rmb();
-
- trace_pvscsi_process_io(next_descr_pa);
- cpu_physical_memory_read(next_descr_pa, &descr, sizeof(descr));
- pvscsi_process_request_descriptor(s, &descr);
- }
-
- pvscsi_ring_flush_req(&s->rings);
-}
-
-static void
-pvscsi_dbg_dump_tx_rings_config(PVSCSICmdDescSetupRings *rc)
-{
- int i;
- trace_pvscsi_tx_rings_ppn("Rings State", rc->ringsStatePPN);
-
- trace_pvscsi_tx_rings_num_pages("Request Ring", rc->reqRingNumPages);
- for (i = 0; i < rc->reqRingNumPages; i++) {
- trace_pvscsi_tx_rings_ppn("Request Ring", rc->reqRingPPNs[i]);
- }
-
- trace_pvscsi_tx_rings_num_pages("Confirm Ring", rc->cmpRingNumPages);
- for (i = 0; i < rc->cmpRingNumPages; i++) {
- trace_pvscsi_tx_rings_ppn("Confirm Ring", rc->reqRingPPNs[i]);
- }
-}
-
-static uint64_t
-pvscsi_on_cmd_config(PVSCSIState *s)
-{
- trace_pvscsi_on_cmd_noimpl("PVSCSI_CMD_CONFIG");
- return PVSCSI_COMMAND_PROCESSING_FAILED;
-}
-
-static uint64_t
-pvscsi_on_cmd_unplug(PVSCSIState *s)
-{
- trace_pvscsi_on_cmd_noimpl("PVSCSI_CMD_DEVICE_UNPLUG");
- return PVSCSI_COMMAND_PROCESSING_FAILED;
-}
-
-static uint64_t
-pvscsi_on_issue_scsi(PVSCSIState *s)
-{
- trace_pvscsi_on_cmd_noimpl("PVSCSI_CMD_ISSUE_SCSI");
- return PVSCSI_COMMAND_PROCESSING_FAILED;
-}
-
-static uint64_t
-pvscsi_on_cmd_setup_rings(PVSCSIState *s)
-{
- PVSCSICmdDescSetupRings *rc =
- (PVSCSICmdDescSetupRings *) s->curr_cmd_data;
-
- trace_pvscsi_on_cmd_arrived("PVSCSI_CMD_SETUP_RINGS");
-
- pvscsi_dbg_dump_tx_rings_config(rc);
- pvscsi_ring_init_data(&s->rings, rc);
- s->rings_info_valid = TRUE;
- return PVSCSI_COMMAND_PROCESSING_SUCCEEDED;
-}
-
-static uint64_t
-pvscsi_on_cmd_abort(PVSCSIState *s)
-{
- PVSCSICmdDescAbortCmd *cmd = (PVSCSICmdDescAbortCmd *) s->curr_cmd_data;
- PVSCSIRequest *r, *next;
-
- trace_pvscsi_on_cmd_abort(cmd->context, cmd->target);
-
- QTAILQ_FOREACH_SAFE(r, &s->pending_queue, next, next) {
- if (r->req.context == cmd->context) {
- break;
- }
- }
- if (r) {
- assert(!r->completed);
- r->cmp.hostStatus = BTSTAT_ABORTQUEUE;
- scsi_req_cancel(r->sreq);
- }
-
- return PVSCSI_COMMAND_PROCESSING_SUCCEEDED;
-}
-
-static uint64_t
-pvscsi_on_cmd_unknown(PVSCSIState *s)
-{
- trace_pvscsi_on_cmd_unknown_data(s->curr_cmd_data[0]);
- return PVSCSI_COMMAND_PROCESSING_FAILED;
-}
-
-static uint64_t
-pvscsi_on_cmd_reset_device(PVSCSIState *s)
-{
- uint8_t target_lun = 0;
- struct PVSCSICmdDescResetDevice *cmd =
- (struct PVSCSICmdDescResetDevice *) s->curr_cmd_data;
- SCSIDevice *sdev;
-
- sdev = pvscsi_device_find(s, 0, cmd->target, cmd->lun, &target_lun);
-
- trace_pvscsi_on_cmd_reset_dev(cmd->target, (int) target_lun, sdev);
-
- if (sdev != NULL) {
- s->resetting++;
- device_reset(&sdev->qdev);
- s->resetting--;
- return PVSCSI_COMMAND_PROCESSING_SUCCEEDED;
- }
-
- return PVSCSI_COMMAND_PROCESSING_FAILED;
-}
-
-static uint64_t
-pvscsi_on_cmd_reset_bus(PVSCSIState *s)
-{
- trace_pvscsi_on_cmd_arrived("PVSCSI_CMD_RESET_BUS");
-
- s->resetting++;
- qbus_reset_all_fn(&s->bus);
- s->resetting--;
- return PVSCSI_COMMAND_PROCESSING_SUCCEEDED;
-}
-
-static uint64_t
-pvscsi_on_cmd_setup_msg_ring(PVSCSIState *s)
-{
- PVSCSICmdDescSetupMsgRing *rc =
- (PVSCSICmdDescSetupMsgRing *) s->curr_cmd_data;
-
- trace_pvscsi_on_cmd_arrived("PVSCSI_CMD_SETUP_MSG_RING");
-
- if (!s->use_msg) {
- return PVSCSI_COMMAND_PROCESSING_FAILED;
- }
-
- if (s->rings_info_valid) {
- pvscsi_ring_init_msg(&s->rings, rc);
- s->msg_ring_info_valid = TRUE;
- }
- return sizeof(PVSCSICmdDescSetupMsgRing) / sizeof(uint32_t);
-}
-
-static uint64_t
-pvscsi_on_cmd_adapter_reset(PVSCSIState *s)
-{
- trace_pvscsi_on_cmd_arrived("PVSCSI_CMD_ADAPTER_RESET");
-
- pvscsi_reset_adapter(s);
- return PVSCSI_COMMAND_PROCESSING_SUCCEEDED;
-}
-
-static const struct {
- int data_size;
- uint64_t (*handler_fn)(PVSCSIState *s);
-} pvscsi_commands[] = {
- [PVSCSI_CMD_FIRST] = {
- .data_size = 0,
- .handler_fn = pvscsi_on_cmd_unknown,
- },
-
- /* Not implemented, data size defined based on what arrives on windows */
- [PVSCSI_CMD_CONFIG] = {
- .data_size = 6 * sizeof(uint32_t),
- .handler_fn = pvscsi_on_cmd_config,
- },
-
- /* Command not implemented, data size is unknown */
- [PVSCSI_CMD_ISSUE_SCSI] = {
- .data_size = 0,
- .handler_fn = pvscsi_on_issue_scsi,
- },
-
- /* Command not implemented, data size is unknown */
- [PVSCSI_CMD_DEVICE_UNPLUG] = {
- .data_size = 0,
- .handler_fn = pvscsi_on_cmd_unplug,
- },
-
- [PVSCSI_CMD_SETUP_RINGS] = {
- .data_size = sizeof(PVSCSICmdDescSetupRings),
- .handler_fn = pvscsi_on_cmd_setup_rings,
- },
-
- [PVSCSI_CMD_RESET_DEVICE] = {
- .data_size = sizeof(struct PVSCSICmdDescResetDevice),
- .handler_fn = pvscsi_on_cmd_reset_device,
- },
-
- [PVSCSI_CMD_RESET_BUS] = {
- .data_size = 0,
- .handler_fn = pvscsi_on_cmd_reset_bus,
- },
-
- [PVSCSI_CMD_SETUP_MSG_RING] = {
- .data_size = sizeof(PVSCSICmdDescSetupMsgRing),
- .handler_fn = pvscsi_on_cmd_setup_msg_ring,
- },
-
- [PVSCSI_CMD_ADAPTER_RESET] = {
- .data_size = 0,
- .handler_fn = pvscsi_on_cmd_adapter_reset,
- },
-
- [PVSCSI_CMD_ABORT_CMD] = {
- .data_size = sizeof(struct PVSCSICmdDescAbortCmd),
- .handler_fn = pvscsi_on_cmd_abort,
- },
-};
-
-static void
-pvscsi_do_command_processing(PVSCSIState *s)
-{
- size_t bytes_arrived = s->curr_cmd_data_cntr * sizeof(uint32_t);
-
- assert(s->curr_cmd < PVSCSI_CMD_LAST);
- if (bytes_arrived >= pvscsi_commands[s->curr_cmd].data_size) {
- s->reg_command_status = pvscsi_commands[s->curr_cmd].handler_fn(s);
- s->curr_cmd = PVSCSI_CMD_FIRST;
- s->curr_cmd_data_cntr = 0;
- }
-}
-
-static void
-pvscsi_on_command_data(PVSCSIState *s, uint32_t value)
-{
- size_t bytes_arrived = s->curr_cmd_data_cntr * sizeof(uint32_t);
-
- assert(bytes_arrived < sizeof(s->curr_cmd_data));
- s->curr_cmd_data[s->curr_cmd_data_cntr++] = value;
-
- pvscsi_do_command_processing(s);
-}
-
-static void
-pvscsi_on_command(PVSCSIState *s, uint64_t cmd_id)
-{
- if ((cmd_id > PVSCSI_CMD_FIRST) && (cmd_id < PVSCSI_CMD_LAST)) {
- s->curr_cmd = cmd_id;
- } else {
- s->curr_cmd = PVSCSI_CMD_FIRST;
- trace_pvscsi_on_cmd_unknown(cmd_id);
- }
-
- s->curr_cmd_data_cntr = 0;
- s->reg_command_status = PVSCSI_COMMAND_NOT_ENOUGH_DATA;
-
- pvscsi_do_command_processing(s);
-}
-
-static void
-pvscsi_io_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- PVSCSIState *s = opaque;
-
- switch (addr) {
- case PVSCSI_REG_OFFSET_COMMAND:
- pvscsi_on_command(s, val);
- break;
-
- case PVSCSI_REG_OFFSET_COMMAND_DATA:
- pvscsi_on_command_data(s, (uint32_t) val);
- break;
-
- case PVSCSI_REG_OFFSET_INTR_STATUS:
- trace_pvscsi_io_write("PVSCSI_REG_OFFSET_INTR_STATUS", val);
- s->reg_interrupt_status &= ~val;
- pvscsi_update_irq_status(s);
- pvscsi_schedule_completion_processing(s);
- break;
-
- case PVSCSI_REG_OFFSET_INTR_MASK:
- trace_pvscsi_io_write("PVSCSI_REG_OFFSET_INTR_MASK", val);
- s->reg_interrupt_enabled = val;
- pvscsi_update_irq_status(s);
- break;
-
- case PVSCSI_REG_OFFSET_KICK_NON_RW_IO:
- trace_pvscsi_io_write("PVSCSI_REG_OFFSET_KICK_NON_RW_IO", val);
- pvscsi_process_io(s);
- break;
-
- case PVSCSI_REG_OFFSET_KICK_RW_IO:
- trace_pvscsi_io_write("PVSCSI_REG_OFFSET_KICK_RW_IO", val);
- pvscsi_process_io(s);
- break;
-
- case PVSCSI_REG_OFFSET_DEBUG:
- trace_pvscsi_io_write("PVSCSI_REG_OFFSET_DEBUG", val);
- break;
-
- default:
- trace_pvscsi_io_write_unknown(addr, size, val);
- break;
- }
-
-}
-
-static uint64_t
-pvscsi_io_read(void *opaque, hwaddr addr, unsigned size)
-{
- PVSCSIState *s = opaque;
-
- switch (addr) {
- case PVSCSI_REG_OFFSET_INTR_STATUS:
- trace_pvscsi_io_read("PVSCSI_REG_OFFSET_INTR_STATUS",
- s->reg_interrupt_status);
- return s->reg_interrupt_status;
-
- case PVSCSI_REG_OFFSET_INTR_MASK:
- trace_pvscsi_io_read("PVSCSI_REG_OFFSET_INTR_MASK",
- s->reg_interrupt_status);
- return s->reg_interrupt_enabled;
-
- case PVSCSI_REG_OFFSET_COMMAND_STATUS:
- trace_pvscsi_io_read("PVSCSI_REG_OFFSET_COMMAND_STATUS",
- s->reg_interrupt_status);
- return s->reg_command_status;
-
- default:
- trace_pvscsi_io_read_unknown(addr, size);
- return 0;
- }
-}
-
-
-static bool
-pvscsi_init_msi(PVSCSIState *s)
-{
- int res;
- PCIDevice *d = PCI_DEVICE(s);
-
- res = msi_init(d, PVSCSI_MSI_OFFSET(s), PVSCSI_MSIX_NUM_VECTORS,
- PVSCSI_USE_64BIT, PVSCSI_PER_VECTOR_MASK);
- if (res < 0) {
- trace_pvscsi_init_msi_fail(res);
- s->msi_used = false;
- } else {
- s->msi_used = true;
- }
-
- return s->msi_used;
-}
-
-static void
-pvscsi_cleanup_msi(PVSCSIState *s)
-{
- PCIDevice *d = PCI_DEVICE(s);
-
- if (s->msi_used) {
- msi_uninit(d);
- }
-}
-
-static const MemoryRegionOps pvscsi_ops = {
- .read = pvscsi_io_read,
- .write = pvscsi_io_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .impl = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static const struct SCSIBusInfo pvscsi_scsi_info = {
- .tcq = true,
- .max_target = PVSCSI_MAX_DEVS,
- .max_channel = 0,
- .max_lun = 0,
-
- .get_sg_list = pvscsi_get_sg_list,
- .complete = pvscsi_command_complete,
- .cancel = pvscsi_request_cancelled,
-};
-
-static int
-pvscsi_init(PCIDevice *pci_dev)
-{
- PVSCSIState *s = PVSCSI(pci_dev);
-
- trace_pvscsi_state("init");
-
- /* PCI subsystem ID, subsystem vendor ID, revision */
- if (PVSCSI_USE_OLD_PCI_CONFIGURATION(s)) {
- pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID, 0x1000);
- } else {
- pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID,
- PCI_VENDOR_ID_VMWARE);
- pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID,
- PCI_DEVICE_ID_VMWARE_PVSCSI);
- pci_config_set_revision(pci_dev->config, 0x2);
- }
-
- /* PCI latency timer = 255 */
- pci_dev->config[PCI_LATENCY_TIMER] = 0xff;
-
- /* Interrupt pin A */
- pci_config_set_interrupt_pin(pci_dev->config, 1);
-
- memory_region_init_io(&s->io_space, OBJECT(s), &pvscsi_ops, s,
- "pvscsi-io", PVSCSI_MEM_SPACE_SIZE);
- pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->io_space);
-
- pvscsi_init_msi(s);
-
- if (pci_is_express(pci_dev) && pci_bus_is_express(pci_dev->bus)) {
- pcie_endpoint_cap_init(pci_dev, PVSCSI_EXP_EP_OFFSET);
- }
-
- s->completion_worker = qemu_bh_new(pvscsi_process_completion_queue, s);
- if (!s->completion_worker) {
- pvscsi_cleanup_msi(s);
- return -ENOMEM;
- }
-
- scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(pci_dev),
- &pvscsi_scsi_info, NULL);
- /* override default SCSI bus hotplug-handler, with pvscsi's one */
- qbus_set_hotplug_handler(BUS(&s->bus), DEVICE(s), &error_abort);
- pvscsi_reset_state(s);
-
- return 0;
-}
-
-static void
-pvscsi_uninit(PCIDevice *pci_dev)
-{
- PVSCSIState *s = PVSCSI(pci_dev);
-
- trace_pvscsi_state("uninit");
- qemu_bh_delete(s->completion_worker);
-
- pvscsi_cleanup_msi(s);
-}
-
-static void
-pvscsi_reset(DeviceState *dev)
-{
- PCIDevice *d = PCI_DEVICE(dev);
- PVSCSIState *s = PVSCSI(d);
-
- trace_pvscsi_state("reset");
- pvscsi_reset_adapter(s);
-}
-
-static void
-pvscsi_pre_save(void *opaque)
-{
- PVSCSIState *s = (PVSCSIState *) opaque;
-
- trace_pvscsi_state("presave");
-
- assert(QTAILQ_EMPTY(&s->pending_queue));
- assert(QTAILQ_EMPTY(&s->completion_queue));
-}
-
-static int
-pvscsi_post_load(void *opaque, int version_id)
-{
- trace_pvscsi_state("postload");
- return 0;
-}
-
-static bool pvscsi_vmstate_need_pcie_device(void *opaque)
-{
- PVSCSIState *s = PVSCSI(opaque);
-
- return !(s->compat_flags & PVSCSI_COMPAT_DISABLE_PCIE);
-}
-
-static bool pvscsi_vmstate_test_pci_device(void *opaque, int version_id)
-{
- return !pvscsi_vmstate_need_pcie_device(opaque);
-}
-
-static const VMStateDescription vmstate_pvscsi_pcie_device = {
- .name = "pvscsi/pcie",
- .needed = pvscsi_vmstate_need_pcie_device,
- .fields = (VMStateField[]) {
- VMSTATE_PCIE_DEVICE(parent_obj, PVSCSIState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_pvscsi = {
- .name = "pvscsi",
- .version_id = 0,
- .minimum_version_id = 0,
- .pre_save = pvscsi_pre_save,
- .post_load = pvscsi_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT_TEST(parent_obj, PVSCSIState,
- pvscsi_vmstate_test_pci_device, 0,
- vmstate_pci_device, PCIDevice),
- VMSTATE_UINT8(msi_used, PVSCSIState),
- VMSTATE_UINT32(resetting, PVSCSIState),
- VMSTATE_UINT64(reg_interrupt_status, PVSCSIState),
- VMSTATE_UINT64(reg_interrupt_enabled, PVSCSIState),
- VMSTATE_UINT64(reg_command_status, PVSCSIState),
- VMSTATE_UINT64(curr_cmd, PVSCSIState),
- VMSTATE_UINT32(curr_cmd_data_cntr, PVSCSIState),
- VMSTATE_UINT32_ARRAY(curr_cmd_data, PVSCSIState,
- ARRAY_SIZE(((PVSCSIState *)NULL)->curr_cmd_data)),
- VMSTATE_UINT8(rings_info_valid, PVSCSIState),
- VMSTATE_UINT8(msg_ring_info_valid, PVSCSIState),
- VMSTATE_UINT8(use_msg, PVSCSIState),
-
- VMSTATE_UINT64(rings.rs_pa, PVSCSIState),
- VMSTATE_UINT32(rings.txr_len_mask, PVSCSIState),
- VMSTATE_UINT32(rings.rxr_len_mask, PVSCSIState),
- VMSTATE_UINT64_ARRAY(rings.req_ring_pages_pa, PVSCSIState,
- PVSCSI_SETUP_RINGS_MAX_NUM_PAGES),
- VMSTATE_UINT64_ARRAY(rings.cmp_ring_pages_pa, PVSCSIState,
- PVSCSI_SETUP_RINGS_MAX_NUM_PAGES),
- VMSTATE_UINT64(rings.consumed_ptr, PVSCSIState),
- VMSTATE_UINT64(rings.filled_cmp_ptr, PVSCSIState),
-
- VMSTATE_END_OF_LIST()
- },
- .subsections = (const VMStateDescription*[]) {
- &vmstate_pvscsi_pcie_device,
- NULL
- }
-};
-
-static Property pvscsi_properties[] = {
- DEFINE_PROP_UINT8("use_msg", PVSCSIState, use_msg, 1),
- DEFINE_PROP_BIT("x-old-pci-configuration", PVSCSIState, compat_flags,
- PVSCSI_COMPAT_OLD_PCI_CONFIGURATION_BIT, false),
- DEFINE_PROP_BIT("x-disable-pcie", PVSCSIState, compat_flags,
- PVSCSI_COMPAT_DISABLE_PCIE_BIT, false),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pvscsi_realize(DeviceState *qdev, Error **errp)
-{
- PVSCSIClass *pvs_c = PVSCSI_DEVICE_GET_CLASS(qdev);
- PCIDevice *pci_dev = PCI_DEVICE(qdev);
- PVSCSIState *s = PVSCSI(qdev);
-
- if (!(s->compat_flags & PVSCSI_COMPAT_DISABLE_PCIE)) {
- pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS;
- }
-
- pvs_c->parent_dc_realize(qdev, errp);
-}
-
-static void pvscsi_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- PVSCSIClass *pvs_k = PVSCSI_DEVICE_CLASS(klass);
- HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
-
- k->init = pvscsi_init;
- k->exit = pvscsi_uninit;
- k->vendor_id = PCI_VENDOR_ID_VMWARE;
- k->device_id = PCI_DEVICE_ID_VMWARE_PVSCSI;
- k->class_id = PCI_CLASS_STORAGE_SCSI;
- k->subsystem_id = 0x1000;
- pvs_k->parent_dc_realize = dc->realize;
- dc->realize = pvscsi_realize;
- dc->reset = pvscsi_reset;
- dc->vmsd = &vmstate_pvscsi;
- dc->props = pvscsi_properties;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
- hc->unplug = pvscsi_hot_unplug;
- hc->plug = pvscsi_hotplug;
-}
-
-static const TypeInfo pvscsi_info = {
- .name = TYPE_PVSCSI,
- .parent = TYPE_PCI_DEVICE,
- .class_size = sizeof(PVSCSIClass),
- .instance_size = sizeof(PVSCSIState),
- .class_init = pvscsi_class_init,
- .interfaces = (InterfaceInfo[]) {
- { TYPE_HOTPLUG_HANDLER },
- { }
- }
-};
-
-static void
-pvscsi_register_types(void)
-{
- type_register_static(&pvscsi_info);
-}
-
-type_init(pvscsi_register_types);
diff --git a/qemu/hw/scsi/vmw_pvscsi.h b/qemu/hw/scsi/vmw_pvscsi.h
deleted file mode 100644
index 17fcf6627..000000000
--- a/qemu/hw/scsi/vmw_pvscsi.h
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- * VMware PVSCSI header file
- *
- * Copyright (C) 2008-2009, VMware, Inc. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; version 2 of the License and no later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Maintained by: Arvind Kumar <arvindkumar@vmware.com>
- *
- */
-
-#ifndef VMW_PVSCSI_H
-#define VMW_PVSCSI_H
-
-#define VMW_PAGE_SIZE (4096)
-#define VMW_PAGE_SHIFT (12)
-
-#define MASK(n) ((1 << (n)) - 1) /* make an n-bit mask */
-
-/*
- * host adapter status/error codes
- */
-enum HostBusAdapterStatus {
- BTSTAT_SUCCESS = 0x00, /* CCB complete normally with no errors */
- BTSTAT_LINKED_COMMAND_COMPLETED = 0x0a,
- BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG = 0x0b,
- BTSTAT_DATA_UNDERRUN = 0x0c,
- BTSTAT_SELTIMEO = 0x11, /* SCSI selection timeout */
- BTSTAT_DATARUN = 0x12, /* data overrun/underrun */
- BTSTAT_BUSFREE = 0x13, /* unexpected bus free */
- BTSTAT_INVPHASE = 0x14, /* invalid bus phase or sequence */
- /* requested by target */
- BTSTAT_LUNMISMATCH = 0x17, /* linked CCB has different LUN */
- /* from first CCB */
- BTSTAT_SENSFAILED = 0x1b, /* auto request sense failed */
- BTSTAT_TAGREJECT = 0x1c, /* SCSI II tagged queueing message */
- /* rejected by target */
- BTSTAT_BADMSG = 0x1d, /* unsupported message received by */
- /* the host adapter */
- BTSTAT_HAHARDWARE = 0x20, /* host adapter hardware failed */
- BTSTAT_NORESPONSE = 0x21, /* target did not respond to SCSI ATN, */
- /* sent a SCSI RST */
- BTSTAT_SENTRST = 0x22, /* host adapter asserted a SCSI RST */
- BTSTAT_RECVRST = 0x23, /* other SCSI devices asserted a SCSI RST */
- BTSTAT_DISCONNECT = 0x24, /* target device reconnected improperly */
- /* (w/o tag) */
- BTSTAT_BUSRESET = 0x25, /* host adapter issued BUS device reset */
- BTSTAT_ABORTQUEUE = 0x26, /* abort queue generated */
- BTSTAT_HASOFTWARE = 0x27, /* host adapter software error */
- BTSTAT_HATIMEOUT = 0x30, /* host adapter hardware timeout error */
- BTSTAT_SCSIPARITY = 0x34, /* SCSI parity error detected */
-};
-
-/*
- * Register offsets.
- *
- * These registers are accessible both via i/o space and mm i/o.
- */
-
-enum PVSCSIRegOffset {
- PVSCSI_REG_OFFSET_COMMAND = 0x0,
- PVSCSI_REG_OFFSET_COMMAND_DATA = 0x4,
- PVSCSI_REG_OFFSET_COMMAND_STATUS = 0x8,
- PVSCSI_REG_OFFSET_LAST_STS_0 = 0x100,
- PVSCSI_REG_OFFSET_LAST_STS_1 = 0x104,
- PVSCSI_REG_OFFSET_LAST_STS_2 = 0x108,
- PVSCSI_REG_OFFSET_LAST_STS_3 = 0x10c,
- PVSCSI_REG_OFFSET_INTR_STATUS = 0x100c,
- PVSCSI_REG_OFFSET_INTR_MASK = 0x2010,
- PVSCSI_REG_OFFSET_KICK_NON_RW_IO = 0x3014,
- PVSCSI_REG_OFFSET_DEBUG = 0x3018,
- PVSCSI_REG_OFFSET_KICK_RW_IO = 0x4018,
-};
-
-/*
- * Virtual h/w commands.
- */
-
-enum PVSCSICommands {
- PVSCSI_CMD_FIRST = 0, /* has to be first */
-
- PVSCSI_CMD_ADAPTER_RESET = 1,
- PVSCSI_CMD_ISSUE_SCSI = 2,
- PVSCSI_CMD_SETUP_RINGS = 3,
- PVSCSI_CMD_RESET_BUS = 4,
- PVSCSI_CMD_RESET_DEVICE = 5,
- PVSCSI_CMD_ABORT_CMD = 6,
- PVSCSI_CMD_CONFIG = 7,
- PVSCSI_CMD_SETUP_MSG_RING = 8,
- PVSCSI_CMD_DEVICE_UNPLUG = 9,
-
- PVSCSI_CMD_LAST = 10 /* has to be last */
-};
-
-#define PVSCSI_COMMAND_PROCESSING_SUCCEEDED (0)
-#define PVSCSI_COMMAND_PROCESSING_FAILED (-1)
-#define PVSCSI_COMMAND_NOT_ENOUGH_DATA (-2)
-
-/*
- * Command descriptor for PVSCSI_CMD_RESET_DEVICE --
- */
-
-struct PVSCSICmdDescResetDevice {
- uint32_t target;
- uint8_t lun[8];
-} QEMU_PACKED;
-
-typedef struct PVSCSICmdDescResetDevice PVSCSICmdDescResetDevice;
-
-/*
- * Command descriptor for PVSCSI_CMD_ABORT_CMD --
- *
- * - currently does not support specifying the LUN.
- * - pad should be 0.
- */
-
-struct PVSCSICmdDescAbortCmd {
- uint64_t context;
- uint32_t target;
- uint32_t pad;
-} QEMU_PACKED;
-
-typedef struct PVSCSICmdDescAbortCmd PVSCSICmdDescAbortCmd;
-
-/*
- * Command descriptor for PVSCSI_CMD_SETUP_RINGS --
- *
- * Notes:
- * - reqRingNumPages and cmpRingNumPages need to be power of two.
- * - reqRingNumPages and cmpRingNumPages need to be different from 0,
- * - reqRingNumPages and cmpRingNumPages need to be inferior to
- * PVSCSI_SETUP_RINGS_MAX_NUM_PAGES.
- */
-
-#define PVSCSI_SETUP_RINGS_MAX_NUM_PAGES 32
-struct PVSCSICmdDescSetupRings {
- uint32_t reqRingNumPages;
- uint32_t cmpRingNumPages;
- uint64_t ringsStatePPN;
- uint64_t reqRingPPNs[PVSCSI_SETUP_RINGS_MAX_NUM_PAGES];
- uint64_t cmpRingPPNs[PVSCSI_SETUP_RINGS_MAX_NUM_PAGES];
-} QEMU_PACKED;
-
-typedef struct PVSCSICmdDescSetupRings PVSCSICmdDescSetupRings;
-
-/*
- * Command descriptor for PVSCSI_CMD_SETUP_MSG_RING --
- *
- * Notes:
- * - this command was not supported in the initial revision of the h/w
- * interface. Before using it, you need to check that it is supported by
- * writing PVSCSI_CMD_SETUP_MSG_RING to the 'command' register, then
- * immediately after read the 'command status' register:
- * * a value of -1 means that the cmd is NOT supported,
- * * a value != -1 means that the cmd IS supported.
- * If it's supported the 'command status' register should return:
- * sizeof(PVSCSICmdDescSetupMsgRing) / sizeof(uint32_t).
- * - this command should be issued _after_ the usual SETUP_RINGS so that the
- * RingsState page is already setup. If not, the command is a nop.
- * - numPages needs to be a power of two,
- * - numPages needs to be different from 0,
- * - pad should be zero.
- */
-
-#define PVSCSI_SETUP_MSG_RING_MAX_NUM_PAGES 16
-
-struct PVSCSICmdDescSetupMsgRing {
- uint32_t numPages;
- uint32_t pad;
- uint64_t ringPPNs[PVSCSI_SETUP_MSG_RING_MAX_NUM_PAGES];
-} QEMU_PACKED;
-
-typedef struct PVSCSICmdDescSetupMsgRing PVSCSICmdDescSetupMsgRing;
-
-enum PVSCSIMsgType {
- PVSCSI_MSG_DEV_ADDED = 0,
- PVSCSI_MSG_DEV_REMOVED = 1,
- PVSCSI_MSG_LAST = 2,
-};
-
-/*
- * Msg descriptor.
- *
- * sizeof(struct PVSCSIRingMsgDesc) == 128.
- *
- * - type is of type enum PVSCSIMsgType.
- * - the content of args depend on the type of event being delivered.
- */
-
-struct PVSCSIRingMsgDesc {
- uint32_t type;
- uint32_t args[31];
-} QEMU_PACKED;
-
-typedef struct PVSCSIRingMsgDesc PVSCSIRingMsgDesc;
-
-struct PVSCSIMsgDescDevStatusChanged {
- uint32_t type; /* PVSCSI_MSG_DEV _ADDED / _REMOVED */
- uint32_t bus;
- uint32_t target;
- uint8_t lun[8];
- uint32_t pad[27];
-} QEMU_PACKED;
-
-typedef struct PVSCSIMsgDescDevStatusChanged PVSCSIMsgDescDevStatusChanged;
-
-/*
- * Rings state.
- *
- * - the fields:
- * . msgProdIdx,
- * . msgConsIdx,
- * . msgNumEntriesLog2,
- * .. are only used once the SETUP_MSG_RING cmd has been issued.
- * - 'pad' helps to ensure that the msg related fields are on their own
- * cache-line.
- */
-
-struct PVSCSIRingsState {
- uint32_t reqProdIdx;
- uint32_t reqConsIdx;
- uint32_t reqNumEntriesLog2;
-
- uint32_t cmpProdIdx;
- uint32_t cmpConsIdx;
- uint32_t cmpNumEntriesLog2;
-
- uint8_t pad[104];
-
- uint32_t msgProdIdx;
- uint32_t msgConsIdx;
- uint32_t msgNumEntriesLog2;
-} QEMU_PACKED;
-
-typedef struct PVSCSIRingsState PVSCSIRingsState;
-
-/*
- * Request descriptor.
- *
- * sizeof(RingReqDesc) = 128
- *
- * - context: is a unique identifier of a command. It could normally be any
- * 64bit value, however we currently store it in the serialNumber variable
- * of struct SCSI_Command, so we have the following restrictions due to the
- * way this field is handled in the vmkernel storage stack:
- * * this value can't be 0,
- * * the upper 32bit need to be 0 since serialNumber is as a uint32_t.
- * Currently tracked as PR 292060.
- * - dataLen: contains the total number of bytes that need to be transferred.
- * - dataAddr:
- * * if PVSCSI_FLAG_CMD_WITH_SG_LIST is set: dataAddr is the PA of the first
- * s/g table segment, each s/g segment is entirely contained on a single
- * page of physical memory,
- * * if PVSCSI_FLAG_CMD_WITH_SG_LIST is NOT set, then dataAddr is the PA of
- * the buffer used for the DMA transfer,
- * - flags:
- * * PVSCSI_FLAG_CMD_WITH_SG_LIST: see dataAddr above,
- * * PVSCSI_FLAG_CMD_DIR_NONE: no DMA involved,
- * * PVSCSI_FLAG_CMD_DIR_TOHOST: transfer from device to main memory,
- * * PVSCSI_FLAG_CMD_DIR_TODEVICE: transfer from main memory to device,
- * * PVSCSI_FLAG_CMD_OUT_OF_BAND_CDB: reserved to handle CDBs larger than
- * 16bytes. To be specified.
- * - vcpuHint: vcpuId of the processor that will be most likely waiting for the
- * completion of the i/o. For guest OSes that use lowest priority message
- * delivery mode (such as windows), we use this "hint" to deliver the
- * completion action to the proper vcpu. For now, we can use the vcpuId of
- * the processor that initiated the i/o as a likely candidate for the vcpu
- * that will be waiting for the completion..
- * - bus should be 0: we currently only support bus 0 for now.
- * - unused should be zero'd.
- */
-
-#define PVSCSI_FLAG_CMD_WITH_SG_LIST (1 << 0)
-#define PVSCSI_FLAG_CMD_OUT_OF_BAND_CDB (1 << 1)
-#define PVSCSI_FLAG_CMD_DIR_NONE (1 << 2)
-#define PVSCSI_FLAG_CMD_DIR_TOHOST (1 << 3)
-#define PVSCSI_FLAG_CMD_DIR_TODEVICE (1 << 4)
-
-#define PVSCSI_KNOWN_FLAGS \
- (PVSCSI_FLAG_CMD_WITH_SG_LIST | \
- PVSCSI_FLAG_CMD_OUT_OF_BAND_CDB | \
- PVSCSI_FLAG_CMD_DIR_NONE | \
- PVSCSI_FLAG_CMD_DIR_TOHOST | \
- PVSCSI_FLAG_CMD_DIR_TODEVICE)
-
-struct PVSCSIRingReqDesc {
- uint64_t context;
- uint64_t dataAddr;
- uint64_t dataLen;
- uint64_t senseAddr;
- uint32_t senseLen;
- uint32_t flags;
- uint8_t cdb[16];
- uint8_t cdbLen;
- uint8_t lun[8];
- uint8_t tag;
- uint8_t bus;
- uint8_t target;
- uint8_t vcpuHint;
- uint8_t unused[59];
-} QEMU_PACKED;
-
-typedef struct PVSCSIRingReqDesc PVSCSIRingReqDesc;
-
-/*
- * Scatter-gather list management.
- *
- * As described above, when PVSCSI_FLAG_CMD_WITH_SG_LIST is set in the
- * RingReqDesc.flags, then RingReqDesc.dataAddr is the PA of the first s/g
- * table segment.
- *
- * - each segment of the s/g table contain a succession of struct
- * PVSCSISGElement.
- * - each segment is entirely contained on a single physical page of memory.
- * - a "chain" s/g element has the flag PVSCSI_SGE_FLAG_CHAIN_ELEMENT set in
- * PVSCSISGElement.flags and in this case:
- * * addr is the PA of the next s/g segment,
- * * length is undefined, assumed to be 0.
- */
-
-struct PVSCSISGElement {
- uint64_t addr;
- uint32_t length;
- uint32_t flags;
-} QEMU_PACKED;
-
-typedef struct PVSCSISGElement PVSCSISGElement;
-
-/*
- * Completion descriptor.
- *
- * sizeof(RingCmpDesc) = 32
- *
- * - context: identifier of the command. The same thing that was specified
- * under "context" as part of struct RingReqDesc at initiation time,
- * - dataLen: number of bytes transferred for the actual i/o operation,
- * - senseLen: number of bytes written into the sense buffer,
- * - hostStatus: adapter status,
- * - scsiStatus: device status,
- * - pad should be zero.
- */
-
-struct PVSCSIRingCmpDesc {
- uint64_t context;
- uint64_t dataLen;
- uint32_t senseLen;
- uint16_t hostStatus;
- uint16_t scsiStatus;
- uint32_t pad[2];
-} QEMU_PACKED;
-
-typedef struct PVSCSIRingCmpDesc PVSCSIRingCmpDesc;
-
-/*
- * Interrupt status / IRQ bits.
- */
-
-#define PVSCSI_INTR_CMPL_0 (1 << 0)
-#define PVSCSI_INTR_CMPL_1 (1 << 1)
-#define PVSCSI_INTR_CMPL_MASK MASK(2)
-
-#define PVSCSI_INTR_MSG_0 (1 << 2)
-#define PVSCSI_INTR_MSG_1 (1 << 3)
-#define PVSCSI_INTR_MSG_MASK (MASK(2) << 2)
-
-#define PVSCSI_INTR_ALL_SUPPORTED MASK(4)
-
-/*
- * Number of MSI-X vectors supported.
- */
-#define PVSCSI_MAX_INTRS 24
-
-/*
- * Enumeration of supported MSI-X vectors
- */
-#define PVSCSI_VECTOR_COMPLETION 0
-
-/*
- * Misc constants for the rings.
- */
-
-#define PVSCSI_MAX_NUM_PAGES_REQ_RING PVSCSI_SETUP_RINGS_MAX_NUM_PAGES
-#define PVSCSI_MAX_NUM_PAGES_CMP_RING PVSCSI_SETUP_RINGS_MAX_NUM_PAGES
-#define PVSCSI_MAX_NUM_PAGES_MSG_RING PVSCSI_SETUP_MSG_RING_MAX_NUM_PAGES
-
-#define PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE \
- (VMW_PAGE_SIZE / sizeof(struct PVSCSIRingReqDesc))
-
-#define PVSCSI_MAX_NUM_CMP_ENTRIES_PER_PAGE \
- (VMW_PAGE_SIZE / sizeof(PVSCSIRingCmpDesc))
-
-#define PVSCSI_MAX_NUM_MSG_ENTRIES_PER_PAGE \
- (VMW_PAGE_SIZE / sizeof(PVSCSIRingMsgDesc))
-
-#define PVSCSI_MAX_REQ_QUEUE_DEPTH \
- (PVSCSI_MAX_NUM_PAGES_REQ_RING * PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE)
-
-#define PVSCSI_MEM_SPACE_COMMAND_NUM_PAGES 1
-#define PVSCSI_MEM_SPACE_INTR_STATUS_NUM_PAGES 1
-#define PVSCSI_MEM_SPACE_MISC_NUM_PAGES 2
-#define PVSCSI_MEM_SPACE_KICK_IO_NUM_PAGES 2
-#define PVSCSI_MEM_SPACE_MSIX_NUM_PAGES 2
-
-enum PVSCSIMemSpace {
- PVSCSI_MEM_SPACE_COMMAND_PAGE = 0,
- PVSCSI_MEM_SPACE_INTR_STATUS_PAGE = 1,
- PVSCSI_MEM_SPACE_MISC_PAGE = 2,
- PVSCSI_MEM_SPACE_KICK_IO_PAGE = 4,
- PVSCSI_MEM_SPACE_MSIX_TABLE_PAGE = 6,
- PVSCSI_MEM_SPACE_MSIX_PBA_PAGE = 7,
-};
-
-#define PVSCSI_MEM_SPACE_NUM_PAGES \
- (PVSCSI_MEM_SPACE_COMMAND_NUM_PAGES + \
- PVSCSI_MEM_SPACE_INTR_STATUS_NUM_PAGES + \
- PVSCSI_MEM_SPACE_MISC_NUM_PAGES + \
- PVSCSI_MEM_SPACE_KICK_IO_NUM_PAGES + \
- PVSCSI_MEM_SPACE_MSIX_NUM_PAGES)
-
-#define PVSCSI_MEM_SPACE_SIZE (PVSCSI_MEM_SPACE_NUM_PAGES * VMW_PAGE_SIZE)
-
-#endif /* VMW_PVSCSI_H */
diff --git a/qemu/hw/sd/Makefile.objs b/qemu/hw/sd/Makefile.objs
deleted file mode 100644
index 31c83308f..000000000
--- a/qemu/hw/sd/Makefile.objs
+++ /dev/null
@@ -1,8 +0,0 @@
-common-obj-$(CONFIG_PL181) += pl181.o
-common-obj-$(CONFIG_SSI_SD) += ssi-sd.o
-common-obj-$(CONFIG_SD) += sd.o core.o
-common-obj-$(CONFIG_SDHCI) += sdhci.o
-
-obj-$(CONFIG_MILKYMIST) += milkymist-memcard.o
-obj-$(CONFIG_OMAP) += omap_mmc.o
-obj-$(CONFIG_PXA2XX) += pxa2xx_mmci.o
diff --git a/qemu/hw/sd/core.c b/qemu/hw/sd/core.c
deleted file mode 100644
index 14c2bdf27..000000000
--- a/qemu/hw/sd/core.c
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * SD card bus interface code.
- *
- * Copyright (c) 2015 Linaro Limited
- *
- * Author:
- * Peter Maydell <peter.maydell@linaro.org>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2 or later, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/qdev-core.h"
-#include "sysemu/block-backend.h"
-#include "hw/sd/sd.h"
-
-static SDState *get_card(SDBus *sdbus)
-{
- /* We only ever have one child on the bus so just return it */
- BusChild *kid = QTAILQ_FIRST(&sdbus->qbus.children);
-
- if (!kid) {
- return NULL;
- }
- return SD_CARD(kid->child);
-}
-
-int sdbus_do_command(SDBus *sdbus, SDRequest *req, uint8_t *response)
-{
- SDState *card = get_card(sdbus);
-
- if (card) {
- SDCardClass *sc = SD_CARD_GET_CLASS(card);
-
- return sc->do_command(card, req, response);
- }
-
- return 0;
-}
-
-void sdbus_write_data(SDBus *sdbus, uint8_t value)
-{
- SDState *card = get_card(sdbus);
-
- if (card) {
- SDCardClass *sc = SD_CARD_GET_CLASS(card);
-
- sc->write_data(card, value);
- }
-}
-
-uint8_t sdbus_read_data(SDBus *sdbus)
-{
- SDState *card = get_card(sdbus);
-
- if (card) {
- SDCardClass *sc = SD_CARD_GET_CLASS(card);
-
- return sc->read_data(card);
- }
-
- return 0;
-}
-
-bool sdbus_data_ready(SDBus *sdbus)
-{
- SDState *card = get_card(sdbus);
-
- if (card) {
- SDCardClass *sc = SD_CARD_GET_CLASS(card);
-
- return sc->data_ready(card);
- }
-
- return false;
-}
-
-bool sdbus_get_inserted(SDBus *sdbus)
-{
- SDState *card = get_card(sdbus);
-
- if (card) {
- SDCardClass *sc = SD_CARD_GET_CLASS(card);
-
- return sc->get_inserted(card);
- }
-
- return false;
-}
-
-bool sdbus_get_readonly(SDBus *sdbus)
-{
- SDState *card = get_card(sdbus);
-
- if (card) {
- SDCardClass *sc = SD_CARD_GET_CLASS(card);
-
- return sc->get_readonly(card);
- }
-
- return false;
-}
-
-void sdbus_set_inserted(SDBus *sdbus, bool inserted)
-{
- SDBusClass *sbc = SD_BUS_GET_CLASS(sdbus);
- BusState *qbus = BUS(sdbus);
-
- if (sbc->set_inserted) {
- sbc->set_inserted(qbus->parent, inserted);
- }
-}
-
-void sdbus_set_readonly(SDBus *sdbus, bool readonly)
-{
- SDBusClass *sbc = SD_BUS_GET_CLASS(sdbus);
- BusState *qbus = BUS(sdbus);
-
- if (sbc->set_readonly) {
- sbc->set_readonly(qbus->parent, readonly);
- }
-}
-
-static const TypeInfo sd_bus_info = {
- .name = TYPE_SD_BUS,
- .parent = TYPE_BUS,
- .instance_size = sizeof(SDBus),
- .class_size = sizeof(SDBusClass),
-};
-
-static void sd_bus_register_types(void)
-{
- type_register_static(&sd_bus_info);
-}
-
-type_init(sd_bus_register_types)
diff --git a/qemu/hw/sd/milkymist-memcard.c b/qemu/hw/sd/milkymist-memcard.c
deleted file mode 100644
index c04ff02fa..000000000
--- a/qemu/hw/sd/milkymist-memcard.c
+++ /dev/null
@@ -1,317 +0,0 @@
-/*
- * QEMU model of the Milkymist SD Card Controller.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * Specification available at:
- * http://www.milkymist.org/socdoc/memcard.pdf
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "sysemu/sysemu.h"
-#include "trace.h"
-#include "qemu/error-report.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
-#include "hw/sd/sd.h"
-
-enum {
- ENABLE_CMD_TX = (1<<0),
- ENABLE_CMD_RX = (1<<1),
- ENABLE_DAT_TX = (1<<2),
- ENABLE_DAT_RX = (1<<3),
-};
-
-enum {
- PENDING_CMD_TX = (1<<0),
- PENDING_CMD_RX = (1<<1),
- PENDING_DAT_TX = (1<<2),
- PENDING_DAT_RX = (1<<3),
-};
-
-enum {
- START_CMD_TX = (1<<0),
- START_DAT_RX = (1<<1),
-};
-
-enum {
- R_CLK2XDIV = 0,
- R_ENABLE,
- R_PENDING,
- R_START,
- R_CMD,
- R_DAT,
- R_MAX
-};
-
-#define TYPE_MILKYMIST_MEMCARD "milkymist-memcard"
-#define MILKYMIST_MEMCARD(obj) \
- OBJECT_CHECK(MilkymistMemcardState, (obj), TYPE_MILKYMIST_MEMCARD)
-
-struct MilkymistMemcardState {
- SysBusDevice parent_obj;
-
- MemoryRegion regs_region;
- SDState *card;
-
- int command_write_ptr;
- int response_read_ptr;
- int response_len;
- int ignore_next_cmd;
- int enabled;
- uint8_t command[6];
- uint8_t response[17];
- uint32_t regs[R_MAX];
-};
-typedef struct MilkymistMemcardState MilkymistMemcardState;
-
-static void update_pending_bits(MilkymistMemcardState *s)
-{
- /* transmits are instantaneous, thus tx pending bits are never set */
- s->regs[R_PENDING] = 0;
- /* if rx is enabled the corresponding pending bits are always set */
- if (s->regs[R_ENABLE] & ENABLE_CMD_RX) {
- s->regs[R_PENDING] |= PENDING_CMD_RX;
- }
- if (s->regs[R_ENABLE] & ENABLE_DAT_RX) {
- s->regs[R_PENDING] |= PENDING_DAT_RX;
- }
-}
-
-static void memcard_sd_command(MilkymistMemcardState *s)
-{
- SDRequest req;
-
- req.cmd = s->command[0] & 0x3f;
- req.arg = (s->command[1] << 24) | (s->command[2] << 16)
- | (s->command[3] << 8) | s->command[4];
- req.crc = s->command[5];
-
- s->response[0] = req.cmd;
- s->response_len = sd_do_command(s->card, &req, s->response+1);
- s->response_read_ptr = 0;
-
- if (s->response_len == 16) {
- /* R2 response */
- s->response[0] = 0x3f;
- s->response_len += 1;
- } else if (s->response_len == 4) {
- /* no crc calculation, insert dummy byte */
- s->response[5] = 0;
- s->response_len += 2;
- }
-
- if (req.cmd == 0) {
- /* next write is a dummy byte to clock the initialization of the sd
- * card */
- s->ignore_next_cmd = 1;
- }
-}
-
-static uint64_t memcard_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- MilkymistMemcardState *s = opaque;
- uint32_t r = 0;
-
- addr >>= 2;
- switch (addr) {
- case R_CMD:
- if (!s->enabled) {
- r = 0xff;
- } else {
- r = s->response[s->response_read_ptr++];
- if (s->response_read_ptr > s->response_len) {
- error_report("milkymist_memcard: "
- "read more cmd bytes than available. Clipping.");
- s->response_read_ptr = 0;
- }
- }
- break;
- case R_DAT:
- if (!s->enabled) {
- r = 0xffffffff;
- } else {
- r = 0;
- r |= sd_read_data(s->card) << 24;
- r |= sd_read_data(s->card) << 16;
- r |= sd_read_data(s->card) << 8;
- r |= sd_read_data(s->card);
- }
- break;
- case R_CLK2XDIV:
- case R_ENABLE:
- case R_PENDING:
- case R_START:
- r = s->regs[addr];
- break;
-
- default:
- error_report("milkymist_memcard: read access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-
- trace_milkymist_memcard_memory_read(addr << 2, r);
-
- return r;
-}
-
-static void memcard_write(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
- MilkymistMemcardState *s = opaque;
-
- trace_milkymist_memcard_memory_write(addr, value);
-
- addr >>= 2;
- switch (addr) {
- case R_PENDING:
- /* clear rx pending bits */
- s->regs[R_PENDING] &= ~(value & (PENDING_CMD_RX | PENDING_DAT_RX));
- update_pending_bits(s);
- break;
- case R_CMD:
- if (!s->enabled) {
- break;
- }
- if (s->ignore_next_cmd) {
- s->ignore_next_cmd = 0;
- break;
- }
- s->command[s->command_write_ptr] = value & 0xff;
- s->command_write_ptr = (s->command_write_ptr + 1) % 6;
- if (s->command_write_ptr == 0) {
- memcard_sd_command(s);
- }
- break;
- case R_DAT:
- if (!s->enabled) {
- break;
- }
- sd_write_data(s->card, (value >> 24) & 0xff);
- sd_write_data(s->card, (value >> 16) & 0xff);
- sd_write_data(s->card, (value >> 8) & 0xff);
- sd_write_data(s->card, value & 0xff);
- break;
- case R_ENABLE:
- s->regs[addr] = value;
- update_pending_bits(s);
- break;
- case R_CLK2XDIV:
- case R_START:
- s->regs[addr] = value;
- break;
-
- default:
- error_report("milkymist_memcard: write access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-}
-
-static const MemoryRegionOps memcard_mmio_ops = {
- .read = memcard_read,
- .write = memcard_write,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void milkymist_memcard_reset(DeviceState *d)
-{
- MilkymistMemcardState *s = MILKYMIST_MEMCARD(d);
- int i;
-
- s->command_write_ptr = 0;
- s->response_read_ptr = 0;
- s->response_len = 0;
-
- for (i = 0; i < R_MAX; i++) {
- s->regs[i] = 0;
- }
-}
-
-static int milkymist_memcard_init(SysBusDevice *dev)
-{
- MilkymistMemcardState *s = MILKYMIST_MEMCARD(dev);
- DriveInfo *dinfo;
- BlockBackend *blk;
-
- /* FIXME use a qdev drive property instead of drive_get_next() */
- dinfo = drive_get_next(IF_SD);
- blk = dinfo ? blk_by_legacy_dinfo(dinfo) : NULL;
- s->card = sd_init(blk, false);
- if (s->card == NULL) {
- return -1;
- }
-
- s->enabled = blk && blk_is_inserted(blk);
-
- memory_region_init_io(&s->regs_region, OBJECT(s), &memcard_mmio_ops, s,
- "milkymist-memcard", R_MAX * 4);
- sysbus_init_mmio(dev, &s->regs_region);
-
- return 0;
-}
-
-static const VMStateDescription vmstate_milkymist_memcard = {
- .name = "milkymist-memcard",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_INT32(command_write_ptr, MilkymistMemcardState),
- VMSTATE_INT32(response_read_ptr, MilkymistMemcardState),
- VMSTATE_INT32(response_len, MilkymistMemcardState),
- VMSTATE_INT32(ignore_next_cmd, MilkymistMemcardState),
- VMSTATE_INT32(enabled, MilkymistMemcardState),
- VMSTATE_UINT8_ARRAY(command, MilkymistMemcardState, 6),
- VMSTATE_UINT8_ARRAY(response, MilkymistMemcardState, 17),
- VMSTATE_UINT32_ARRAY(regs, MilkymistMemcardState, R_MAX),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void milkymist_memcard_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = milkymist_memcard_init;
- dc->reset = milkymist_memcard_reset;
- dc->vmsd = &vmstate_milkymist_memcard;
- /* Reason: init() method uses drive_get_next() */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo milkymist_memcard_info = {
- .name = TYPE_MILKYMIST_MEMCARD,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(MilkymistMemcardState),
- .class_init = milkymist_memcard_class_init,
-};
-
-static void milkymist_memcard_register_types(void)
-{
- type_register_static(&milkymist_memcard_info);
-}
-
-type_init(milkymist_memcard_register_types)
diff --git a/qemu/hw/sd/omap_mmc.c b/qemu/hw/sd/omap_mmc.c
deleted file mode 100644
index e934cd365..000000000
--- a/qemu/hw/sd/omap_mmc.c
+++ /dev/null
@@ -1,647 +0,0 @@
-/*
- * OMAP on-chip MMC/SD host emulation.
- *
- * Copyright (C) 2006-2007 Andrzej Zaborowski <balrog@zabor.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/arm/omap.h"
-#include "hw/sd/sd.h"
-
-struct omap_mmc_s {
- qemu_irq irq;
- qemu_irq *dma;
- qemu_irq coverswitch;
- MemoryRegion iomem;
- omap_clk clk;
- SDState *card;
- uint16_t last_cmd;
- uint16_t sdio;
- uint16_t rsp[8];
- uint32_t arg;
- int lines;
- int dw;
- int mode;
- int enable;
- int be;
- int rev;
- uint16_t status;
- uint16_t mask;
- uint8_t cto;
- uint16_t dto;
- int clkdiv;
- uint16_t fifo[32];
- int fifo_start;
- int fifo_len;
- uint16_t blen;
- uint16_t blen_counter;
- uint16_t nblk;
- uint16_t nblk_counter;
- int tx_dma;
- int rx_dma;
- int af_level;
- int ae_level;
-
- int ddir;
- int transfer;
-
- int cdet_wakeup;
- int cdet_enable;
- int cdet_state;
- qemu_irq cdet;
-};
-
-static void omap_mmc_interrupts_update(struct omap_mmc_s *s)
-{
- qemu_set_irq(s->irq, !!(s->status & s->mask));
-}
-
-static void omap_mmc_fifolevel_update(struct omap_mmc_s *host)
-{
- if (!host->transfer && !host->fifo_len) {
- host->status &= 0xf3ff;
- return;
- }
-
- if (host->fifo_len > host->af_level && host->ddir) {
- if (host->rx_dma) {
- host->status &= 0xfbff;
- qemu_irq_raise(host->dma[1]);
- } else
- host->status |= 0x0400;
- } else {
- host->status &= 0xfbff;
- qemu_irq_lower(host->dma[1]);
- }
-
- if (host->fifo_len < host->ae_level && !host->ddir) {
- if (host->tx_dma) {
- host->status &= 0xf7ff;
- qemu_irq_raise(host->dma[0]);
- } else
- host->status |= 0x0800;
- } else {
- qemu_irq_lower(host->dma[0]);
- host->status &= 0xf7ff;
- }
-}
-
-typedef enum {
- sd_nore = 0, /* no response */
- sd_r1, /* normal response command */
- sd_r2, /* CID, CSD registers */
- sd_r3, /* OCR register */
- sd_r6 = 6, /* Published RCA response */
- sd_r1b = -1,
-} sd_rsp_type_t;
-
-static void omap_mmc_command(struct omap_mmc_s *host, int cmd, int dir,
- sd_cmd_type_t type, int busy, sd_rsp_type_t resptype, int init)
-{
- uint32_t rspstatus, mask;
- int rsplen, timeout;
- SDRequest request;
- uint8_t response[16];
-
- if (init && cmd == 0) {
- host->status |= 0x0001;
- return;
- }
-
- if (resptype == sd_r1 && busy)
- resptype = sd_r1b;
-
- if (type == sd_adtc) {
- host->fifo_start = 0;
- host->fifo_len = 0;
- host->transfer = 1;
- host->ddir = dir;
- } else
- host->transfer = 0;
- timeout = 0;
- mask = 0;
- rspstatus = 0;
-
- request.cmd = cmd;
- request.arg = host->arg;
- request.crc = 0; /* FIXME */
-
- rsplen = sd_do_command(host->card, &request, response);
-
- /* TODO: validate CRCs */
- switch (resptype) {
- case sd_nore:
- rsplen = 0;
- break;
-
- case sd_r1:
- case sd_r1b:
- if (rsplen < 4) {
- timeout = 1;
- break;
- }
- rsplen = 4;
-
- mask = OUT_OF_RANGE | ADDRESS_ERROR | BLOCK_LEN_ERROR |
- ERASE_SEQ_ERROR | ERASE_PARAM | WP_VIOLATION |
- LOCK_UNLOCK_FAILED | COM_CRC_ERROR | ILLEGAL_COMMAND |
- CARD_ECC_FAILED | CC_ERROR | SD_ERROR |
- CID_CSD_OVERWRITE;
- if (host->sdio & (1 << 13))
- mask |= AKE_SEQ_ERROR;
- rspstatus = (response[0] << 24) | (response[1] << 16) |
- (response[2] << 8) | (response[3] << 0);
- break;
-
- case sd_r2:
- if (rsplen < 16) {
- timeout = 1;
- break;
- }
- rsplen = 16;
- break;
-
- case sd_r3:
- if (rsplen < 4) {
- timeout = 1;
- break;
- }
- rsplen = 4;
-
- rspstatus = (response[0] << 24) | (response[1] << 16) |
- (response[2] << 8) | (response[3] << 0);
- if (rspstatus & 0x80000000)
- host->status &= 0xe000;
- else
- host->status |= 0x1000;
- break;
-
- case sd_r6:
- if (rsplen < 4) {
- timeout = 1;
- break;
- }
- rsplen = 4;
-
- mask = 0xe000 | AKE_SEQ_ERROR;
- rspstatus = (response[2] << 8) | (response[3] << 0);
- }
-
- if (rspstatus & mask)
- host->status |= 0x4000;
- else
- host->status &= 0xb000;
-
- if (rsplen)
- for (rsplen = 0; rsplen < 8; rsplen ++)
- host->rsp[~rsplen & 7] = response[(rsplen << 1) | 1] |
- (response[(rsplen << 1) | 0] << 8);
-
- if (timeout)
- host->status |= 0x0080;
- else if (cmd == 12)
- host->status |= 0x0005; /* Makes it more real */
- else
- host->status |= 0x0001;
-}
-
-static void omap_mmc_transfer(struct omap_mmc_s *host)
-{
- uint8_t value;
-
- if (!host->transfer)
- return;
-
- while (1) {
- if (host->ddir) {
- if (host->fifo_len > host->af_level)
- break;
-
- value = sd_read_data(host->card);
- host->fifo[(host->fifo_start + host->fifo_len) & 31] = value;
- if (-- host->blen_counter) {
- value = sd_read_data(host->card);
- host->fifo[(host->fifo_start + host->fifo_len) & 31] |=
- value << 8;
- host->blen_counter --;
- }
-
- host->fifo_len ++;
- } else {
- if (!host->fifo_len)
- break;
-
- value = host->fifo[host->fifo_start] & 0xff;
- sd_write_data(host->card, value);
- if (-- host->blen_counter) {
- value = host->fifo[host->fifo_start] >> 8;
- sd_write_data(host->card, value);
- host->blen_counter --;
- }
-
- host->fifo_start ++;
- host->fifo_len --;
- host->fifo_start &= 31;
- }
-
- if (host->blen_counter == 0) {
- host->nblk_counter --;
- host->blen_counter = host->blen;
-
- if (host->nblk_counter == 0) {
- host->nblk_counter = host->nblk;
- host->transfer = 0;
- host->status |= 0x0008;
- break;
- }
- }
- }
-}
-
-static void omap_mmc_update(void *opaque)
-{
- struct omap_mmc_s *s = opaque;
- omap_mmc_transfer(s);
- omap_mmc_fifolevel_update(s);
- omap_mmc_interrupts_update(s);
-}
-
-void omap_mmc_reset(struct omap_mmc_s *host)
-{
- host->last_cmd = 0;
- memset(host->rsp, 0, sizeof(host->rsp));
- host->arg = 0;
- host->dw = 0;
- host->mode = 0;
- host->enable = 0;
- host->status = 0;
- host->mask = 0;
- host->cto = 0;
- host->dto = 0;
- host->fifo_len = 0;
- host->blen = 0;
- host->blen_counter = 0;
- host->nblk = 0;
- host->nblk_counter = 0;
- host->tx_dma = 0;
- host->rx_dma = 0;
- host->ae_level = 0x00;
- host->af_level = 0x1f;
- host->transfer = 0;
- host->cdet_wakeup = 0;
- host->cdet_enable = 0;
- qemu_set_irq(host->coverswitch, host->cdet_state);
- host->clkdiv = 0;
-}
-
-static uint64_t omap_mmc_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- uint16_t i;
- struct omap_mmc_s *s = (struct omap_mmc_s *) opaque;
-
- if (size != 2) {
- return omap_badwidth_read16(opaque, offset);
- }
-
- switch (offset) {
- case 0x00: /* MMC_CMD */
- return s->last_cmd;
-
- case 0x04: /* MMC_ARGL */
- return s->arg & 0x0000ffff;
-
- case 0x08: /* MMC_ARGH */
- return s->arg >> 16;
-
- case 0x0c: /* MMC_CON */
- return (s->dw << 15) | (s->mode << 12) | (s->enable << 11) |
- (s->be << 10) | s->clkdiv;
-
- case 0x10: /* MMC_STAT */
- return s->status;
-
- case 0x14: /* MMC_IE */
- return s->mask;
-
- case 0x18: /* MMC_CTO */
- return s->cto;
-
- case 0x1c: /* MMC_DTO */
- return s->dto;
-
- case 0x20: /* MMC_DATA */
- /* TODO: support 8-bit access */
- i = s->fifo[s->fifo_start];
- if (s->fifo_len == 0) {
- printf("MMC: FIFO underrun\n");
- return i;
- }
- s->fifo_start ++;
- s->fifo_len --;
- s->fifo_start &= 31;
- omap_mmc_transfer(s);
- omap_mmc_fifolevel_update(s);
- omap_mmc_interrupts_update(s);
- return i;
-
- case 0x24: /* MMC_BLEN */
- return s->blen_counter;
-
- case 0x28: /* MMC_NBLK */
- return s->nblk_counter;
-
- case 0x2c: /* MMC_BUF */
- return (s->rx_dma << 15) | (s->af_level << 8) |
- (s->tx_dma << 7) | s->ae_level;
-
- case 0x30: /* MMC_SPI */
- return 0x0000;
- case 0x34: /* MMC_SDIO */
- return (s->cdet_wakeup << 2) | (s->cdet_enable) | s->sdio;
- case 0x38: /* MMC_SYST */
- return 0x0000;
-
- case 0x3c: /* MMC_REV */
- return s->rev;
-
- case 0x40: /* MMC_RSP0 */
- case 0x44: /* MMC_RSP1 */
- case 0x48: /* MMC_RSP2 */
- case 0x4c: /* MMC_RSP3 */
- case 0x50: /* MMC_RSP4 */
- case 0x54: /* MMC_RSP5 */
- case 0x58: /* MMC_RSP6 */
- case 0x5c: /* MMC_RSP7 */
- return s->rsp[(offset - 0x40) >> 2];
-
- /* OMAP2-specific */
- case 0x60: /* MMC_IOSR */
- case 0x64: /* MMC_SYSC */
- return 0;
- case 0x68: /* MMC_SYSS */
- return 1; /* RSTD */
- }
-
- OMAP_BAD_REG(offset);
- return 0;
-}
-
-static void omap_mmc_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- int i;
- struct omap_mmc_s *s = (struct omap_mmc_s *) opaque;
-
- if (size != 2) {
- omap_badwidth_write16(opaque, offset, value);
- return;
- }
-
- switch (offset) {
- case 0x00: /* MMC_CMD */
- if (!s->enable)
- break;
-
- s->last_cmd = value;
- for (i = 0; i < 8; i ++)
- s->rsp[i] = 0x0000;
- omap_mmc_command(s, value & 63, (value >> 15) & 1,
- (sd_cmd_type_t) ((value >> 12) & 3),
- (value >> 11) & 1,
- (sd_rsp_type_t) ((value >> 8) & 7),
- (value >> 7) & 1);
- omap_mmc_update(s);
- break;
-
- case 0x04: /* MMC_ARGL */
- s->arg &= 0xffff0000;
- s->arg |= 0x0000ffff & value;
- break;
-
- case 0x08: /* MMC_ARGH */
- s->arg &= 0x0000ffff;
- s->arg |= value << 16;
- break;
-
- case 0x0c: /* MMC_CON */
- s->dw = (value >> 15) & 1;
- s->mode = (value >> 12) & 3;
- s->enable = (value >> 11) & 1;
- s->be = (value >> 10) & 1;
- s->clkdiv = (value >> 0) & (s->rev >= 2 ? 0x3ff : 0xff);
- if (s->mode != 0)
- printf("SD mode %i unimplemented!\n", s->mode);
- if (s->be != 0)
- printf("SD FIFO byte sex unimplemented!\n");
- if (s->dw != 0 && s->lines < 4)
- printf("4-bit SD bus enabled\n");
- if (!s->enable)
- omap_mmc_reset(s);
- break;
-
- case 0x10: /* MMC_STAT */
- s->status &= ~value;
- omap_mmc_interrupts_update(s);
- break;
-
- case 0x14: /* MMC_IE */
- s->mask = value & 0x7fff;
- omap_mmc_interrupts_update(s);
- break;
-
- case 0x18: /* MMC_CTO */
- s->cto = value & 0xff;
- if (s->cto > 0xfd && s->rev <= 1)
- printf("MMC: CTO of 0xff and 0xfe cannot be used!\n");
- break;
-
- case 0x1c: /* MMC_DTO */
- s->dto = value & 0xffff;
- break;
-
- case 0x20: /* MMC_DATA */
- /* TODO: support 8-bit access */
- if (s->fifo_len == 32)
- break;
- s->fifo[(s->fifo_start + s->fifo_len) & 31] = value;
- s->fifo_len ++;
- omap_mmc_transfer(s);
- omap_mmc_fifolevel_update(s);
- omap_mmc_interrupts_update(s);
- break;
-
- case 0x24: /* MMC_BLEN */
- s->blen = (value & 0x07ff) + 1;
- s->blen_counter = s->blen;
- break;
-
- case 0x28: /* MMC_NBLK */
- s->nblk = (value & 0x07ff) + 1;
- s->nblk_counter = s->nblk;
- s->blen_counter = s->blen;
- break;
-
- case 0x2c: /* MMC_BUF */
- s->rx_dma = (value >> 15) & 1;
- s->af_level = (value >> 8) & 0x1f;
- s->tx_dma = (value >> 7) & 1;
- s->ae_level = value & 0x1f;
-
- if (s->rx_dma)
- s->status &= 0xfbff;
- if (s->tx_dma)
- s->status &= 0xf7ff;
- omap_mmc_fifolevel_update(s);
- omap_mmc_interrupts_update(s);
- break;
-
- /* SPI, SDIO and TEST modes unimplemented */
- case 0x30: /* MMC_SPI (OMAP1 only) */
- break;
- case 0x34: /* MMC_SDIO */
- s->sdio = value & (s->rev >= 2 ? 0xfbf3 : 0x2020);
- s->cdet_wakeup = (value >> 9) & 1;
- s->cdet_enable = (value >> 2) & 1;
- break;
- case 0x38: /* MMC_SYST */
- break;
-
- case 0x3c: /* MMC_REV */
- case 0x40: /* MMC_RSP0 */
- case 0x44: /* MMC_RSP1 */
- case 0x48: /* MMC_RSP2 */
- case 0x4c: /* MMC_RSP3 */
- case 0x50: /* MMC_RSP4 */
- case 0x54: /* MMC_RSP5 */
- case 0x58: /* MMC_RSP6 */
- case 0x5c: /* MMC_RSP7 */
- OMAP_RO_REG(offset);
- break;
-
- /* OMAP2-specific */
- case 0x60: /* MMC_IOSR */
- if (value & 0xf)
- printf("MMC: SDIO bits used!\n");
- break;
- case 0x64: /* MMC_SYSC */
- if (value & (1 << 2)) /* SRTS */
- omap_mmc_reset(s);
- break;
- case 0x68: /* MMC_SYSS */
- OMAP_RO_REG(offset);
- break;
-
- default:
- OMAP_BAD_REG(offset);
- }
-}
-
-static const MemoryRegionOps omap_mmc_ops = {
- .read = omap_mmc_read,
- .write = omap_mmc_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void omap_mmc_cover_cb(void *opaque, int line, int level)
-{
- struct omap_mmc_s *host = (struct omap_mmc_s *) opaque;
-
- if (!host->cdet_state && level) {
- host->status |= 0x0002;
- omap_mmc_interrupts_update(host);
- if (host->cdet_wakeup) {
- /* TODO: Assert wake-up */
- }
- }
-
- if (host->cdet_state != level) {
- qemu_set_irq(host->coverswitch, level);
- host->cdet_state = level;
- }
-}
-
-struct omap_mmc_s *omap_mmc_init(hwaddr base,
- MemoryRegion *sysmem,
- BlockBackend *blk,
- qemu_irq irq, qemu_irq dma[], omap_clk clk)
-{
- struct omap_mmc_s *s = g_new0(struct omap_mmc_s, 1);
-
- s->irq = irq;
- s->dma = dma;
- s->clk = clk;
- s->lines = 1; /* TODO: needs to be settable per-board */
- s->rev = 1;
-
- omap_mmc_reset(s);
-
- memory_region_init_io(&s->iomem, NULL, &omap_mmc_ops, s, "omap.mmc", 0x800);
- memory_region_add_subregion(sysmem, base, &s->iomem);
-
- /* Instantiate the storage */
- s->card = sd_init(blk, false);
- if (s->card == NULL) {
- exit(1);
- }
-
- return s;
-}
-
-struct omap_mmc_s *omap2_mmc_init(struct omap_target_agent_s *ta,
- BlockBackend *blk, qemu_irq irq, qemu_irq dma[],
- omap_clk fclk, omap_clk iclk)
-{
- struct omap_mmc_s *s = g_new0(struct omap_mmc_s, 1);
-
- s->irq = irq;
- s->dma = dma;
- s->clk = fclk;
- s->lines = 4;
- s->rev = 2;
-
- omap_mmc_reset(s);
-
- memory_region_init_io(&s->iomem, NULL, &omap_mmc_ops, s, "omap.mmc",
- omap_l4_region_size(ta, 0));
- omap_l4_attach(ta, 0, &s->iomem);
-
- /* Instantiate the storage */
- s->card = sd_init(blk, false);
- if (s->card == NULL) {
- exit(1);
- }
-
- s->cdet = qemu_allocate_irq(omap_mmc_cover_cb, s, 0);
- sd_set_cb(s->card, NULL, s->cdet);
-
- return s;
-}
-
-void omap_mmc_handlers(struct omap_mmc_s *s, qemu_irq ro, qemu_irq cover)
-{
- if (s->cdet) {
- sd_set_cb(s->card, ro, s->cdet);
- s->coverswitch = cover;
- qemu_set_irq(cover, s->cdet_state);
- } else
- sd_set_cb(s->card, ro, cover);
-}
-
-void omap_mmc_enable(struct omap_mmc_s *s, int enable)
-{
- sd_enable(s->card, enable);
-}
diff --git a/qemu/hw/sd/pl181.c b/qemu/hw/sd/pl181.c
deleted file mode 100644
index e87abb205..000000000
--- a/qemu/hw/sd/pl181.c
+++ /dev/null
@@ -1,528 +0,0 @@
-/*
- * Arm PrimeCell PL181 MultiMedia Card Interface
- *
- * Copyright (c) 2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-#include "qemu/osdep.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
-#include "hw/sysbus.h"
-#include "hw/sd/sd.h"
-
-//#define DEBUG_PL181 1
-
-#ifdef DEBUG_PL181
-#define DPRINTF(fmt, ...) \
-do { printf("pl181: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#endif
-
-#define PL181_FIFO_LEN 16
-
-#define TYPE_PL181 "pl181"
-#define PL181(obj) OBJECT_CHECK(PL181State, (obj), TYPE_PL181)
-
-typedef struct PL181State {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- SDState *card;
- uint32_t clock;
- uint32_t power;
- uint32_t cmdarg;
- uint32_t cmd;
- uint32_t datatimer;
- uint32_t datalength;
- uint32_t respcmd;
- uint32_t response[4];
- uint32_t datactrl;
- uint32_t datacnt;
- uint32_t status;
- uint32_t mask[2];
- int32_t fifo_pos;
- int32_t fifo_len;
- /* The linux 2.6.21 driver is buggy, and misbehaves if new data arrives
- while it is reading the FIFO. We hack around this by deferring
- subsequent transfers until after the driver polls the status word.
- http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=4446/1
- */
- int32_t linux_hack;
- uint32_t fifo[PL181_FIFO_LEN];
- qemu_irq irq[2];
- /* GPIO outputs for 'card is readonly' and 'card inserted' */
- qemu_irq cardstatus[2];
-} PL181State;
-
-static const VMStateDescription vmstate_pl181 = {
- .name = "pl181",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(clock, PL181State),
- VMSTATE_UINT32(power, PL181State),
- VMSTATE_UINT32(cmdarg, PL181State),
- VMSTATE_UINT32(cmd, PL181State),
- VMSTATE_UINT32(datatimer, PL181State),
- VMSTATE_UINT32(datalength, PL181State),
- VMSTATE_UINT32(respcmd, PL181State),
- VMSTATE_UINT32_ARRAY(response, PL181State, 4),
- VMSTATE_UINT32(datactrl, PL181State),
- VMSTATE_UINT32(datacnt, PL181State),
- VMSTATE_UINT32(status, PL181State),
- VMSTATE_UINT32_ARRAY(mask, PL181State, 2),
- VMSTATE_INT32(fifo_pos, PL181State),
- VMSTATE_INT32(fifo_len, PL181State),
- VMSTATE_INT32(linux_hack, PL181State),
- VMSTATE_UINT32_ARRAY(fifo, PL181State, PL181_FIFO_LEN),
- VMSTATE_END_OF_LIST()
- }
-};
-
-#define PL181_CMD_INDEX 0x3f
-#define PL181_CMD_RESPONSE (1 << 6)
-#define PL181_CMD_LONGRESP (1 << 7)
-#define PL181_CMD_INTERRUPT (1 << 8)
-#define PL181_CMD_PENDING (1 << 9)
-#define PL181_CMD_ENABLE (1 << 10)
-
-#define PL181_DATA_ENABLE (1 << 0)
-#define PL181_DATA_DIRECTION (1 << 1)
-#define PL181_DATA_MODE (1 << 2)
-#define PL181_DATA_DMAENABLE (1 << 3)
-
-#define PL181_STATUS_CMDCRCFAIL (1 << 0)
-#define PL181_STATUS_DATACRCFAIL (1 << 1)
-#define PL181_STATUS_CMDTIMEOUT (1 << 2)
-#define PL181_STATUS_DATATIMEOUT (1 << 3)
-#define PL181_STATUS_TXUNDERRUN (1 << 4)
-#define PL181_STATUS_RXOVERRUN (1 << 5)
-#define PL181_STATUS_CMDRESPEND (1 << 6)
-#define PL181_STATUS_CMDSENT (1 << 7)
-#define PL181_STATUS_DATAEND (1 << 8)
-#define PL181_STATUS_DATABLOCKEND (1 << 10)
-#define PL181_STATUS_CMDACTIVE (1 << 11)
-#define PL181_STATUS_TXACTIVE (1 << 12)
-#define PL181_STATUS_RXACTIVE (1 << 13)
-#define PL181_STATUS_TXFIFOHALFEMPTY (1 << 14)
-#define PL181_STATUS_RXFIFOHALFFULL (1 << 15)
-#define PL181_STATUS_TXFIFOFULL (1 << 16)
-#define PL181_STATUS_RXFIFOFULL (1 << 17)
-#define PL181_STATUS_TXFIFOEMPTY (1 << 18)
-#define PL181_STATUS_RXFIFOEMPTY (1 << 19)
-#define PL181_STATUS_TXDATAAVLBL (1 << 20)
-#define PL181_STATUS_RXDATAAVLBL (1 << 21)
-
-#define PL181_STATUS_TX_FIFO (PL181_STATUS_TXACTIVE \
- |PL181_STATUS_TXFIFOHALFEMPTY \
- |PL181_STATUS_TXFIFOFULL \
- |PL181_STATUS_TXFIFOEMPTY \
- |PL181_STATUS_TXDATAAVLBL)
-#define PL181_STATUS_RX_FIFO (PL181_STATUS_RXACTIVE \
- |PL181_STATUS_RXFIFOHALFFULL \
- |PL181_STATUS_RXFIFOFULL \
- |PL181_STATUS_RXFIFOEMPTY \
- |PL181_STATUS_RXDATAAVLBL)
-
-static const unsigned char pl181_id[] =
-{ 0x81, 0x11, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
-
-static void pl181_update(PL181State *s)
-{
- int i;
- for (i = 0; i < 2; i++) {
- qemu_set_irq(s->irq[i], (s->status & s->mask[i]) != 0);
- }
-}
-
-static void pl181_fifo_push(PL181State *s, uint32_t value)
-{
- int n;
-
- if (s->fifo_len == PL181_FIFO_LEN) {
- fprintf(stderr, "pl181: FIFO overflow\n");
- return;
- }
- n = (s->fifo_pos + s->fifo_len) & (PL181_FIFO_LEN - 1);
- s->fifo_len++;
- s->fifo[n] = value;
- DPRINTF("FIFO push %08x\n", (int)value);
-}
-
-static uint32_t pl181_fifo_pop(PL181State *s)
-{
- uint32_t value;
-
- if (s->fifo_len == 0) {
- fprintf(stderr, "pl181: FIFO underflow\n");
- return 0;
- }
- value = s->fifo[s->fifo_pos];
- s->fifo_len--;
- s->fifo_pos = (s->fifo_pos + 1) & (PL181_FIFO_LEN - 1);
- DPRINTF("FIFO pop %08x\n", (int)value);
- return value;
-}
-
-static void pl181_send_command(PL181State *s)
-{
- SDRequest request;
- uint8_t response[16];
- int rlen;
-
- request.cmd = s->cmd & PL181_CMD_INDEX;
- request.arg = s->cmdarg;
- DPRINTF("Command %d %08x\n", request.cmd, request.arg);
- rlen = sd_do_command(s->card, &request, response);
- if (rlen < 0)
- goto error;
- if (s->cmd & PL181_CMD_RESPONSE) {
-#define RWORD(n) (((uint32_t)response[n] << 24) | (response[n + 1] << 16) \
- | (response[n + 2] << 8) | response[n + 3])
- if (rlen == 0 || (rlen == 4 && (s->cmd & PL181_CMD_LONGRESP)))
- goto error;
- if (rlen != 4 && rlen != 16)
- goto error;
- s->response[0] = RWORD(0);
- if (rlen == 4) {
- s->response[1] = s->response[2] = s->response[3] = 0;
- } else {
- s->response[1] = RWORD(4);
- s->response[2] = RWORD(8);
- s->response[3] = RWORD(12) & ~1;
- }
- DPRINTF("Response received\n");
- s->status |= PL181_STATUS_CMDRESPEND;
-#undef RWORD
- } else {
- DPRINTF("Command sent\n");
- s->status |= PL181_STATUS_CMDSENT;
- }
- return;
-
-error:
- DPRINTF("Timeout\n");
- s->status |= PL181_STATUS_CMDTIMEOUT;
-}
-
-/* Transfer data between the card and the FIFO. This is complicated by
- the FIFO holding 32-bit words and the card taking data in single byte
- chunks. FIFO bytes are transferred in little-endian order. */
-
-static void pl181_fifo_run(PL181State *s)
-{
- uint32_t bits;
- uint32_t value = 0;
- int n;
- int is_read;
-
- is_read = (s->datactrl & PL181_DATA_DIRECTION) != 0;
- if (s->datacnt != 0 && (!is_read || sd_data_ready(s->card))
- && !s->linux_hack) {
- if (is_read) {
- n = 0;
- while (s->datacnt && s->fifo_len < PL181_FIFO_LEN) {
- value |= (uint32_t)sd_read_data(s->card) << (n * 8);
- s->datacnt--;
- n++;
- if (n == 4) {
- pl181_fifo_push(s, value);
- n = 0;
- value = 0;
- }
- }
- if (n != 0) {
- pl181_fifo_push(s, value);
- }
- } else { /* write */
- n = 0;
- while (s->datacnt > 0 && (s->fifo_len > 0 || n > 0)) {
- if (n == 0) {
- value = pl181_fifo_pop(s);
- n = 4;
- }
- n--;
- s->datacnt--;
- sd_write_data(s->card, value & 0xff);
- value >>= 8;
- }
- }
- }
- s->status &= ~(PL181_STATUS_RX_FIFO | PL181_STATUS_TX_FIFO);
- if (s->datacnt == 0) {
- s->status |= PL181_STATUS_DATAEND;
- /* HACK: */
- s->status |= PL181_STATUS_DATABLOCKEND;
- DPRINTF("Transfer Complete\n");
- }
- if (s->datacnt == 0 && s->fifo_len == 0) {
- s->datactrl &= ~PL181_DATA_ENABLE;
- DPRINTF("Data engine idle\n");
- } else {
- /* Update FIFO bits. */
- bits = PL181_STATUS_TXACTIVE | PL181_STATUS_RXACTIVE;
- if (s->fifo_len == 0) {
- bits |= PL181_STATUS_TXFIFOEMPTY;
- bits |= PL181_STATUS_RXFIFOEMPTY;
- } else {
- bits |= PL181_STATUS_TXDATAAVLBL;
- bits |= PL181_STATUS_RXDATAAVLBL;
- }
- if (s->fifo_len == 16) {
- bits |= PL181_STATUS_TXFIFOFULL;
- bits |= PL181_STATUS_RXFIFOFULL;
- }
- if (s->fifo_len <= 8) {
- bits |= PL181_STATUS_TXFIFOHALFEMPTY;
- }
- if (s->fifo_len >= 8) {
- bits |= PL181_STATUS_RXFIFOHALFFULL;
- }
- if (s->datactrl & PL181_DATA_DIRECTION) {
- bits &= PL181_STATUS_RX_FIFO;
- } else {
- bits &= PL181_STATUS_TX_FIFO;
- }
- s->status |= bits;
- }
-}
-
-static uint64_t pl181_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- PL181State *s = (PL181State *)opaque;
- uint32_t tmp;
-
- if (offset >= 0xfe0 && offset < 0x1000) {
- return pl181_id[(offset - 0xfe0) >> 2];
- }
- switch (offset) {
- case 0x00: /* Power */
- return s->power;
- case 0x04: /* Clock */
- return s->clock;
- case 0x08: /* Argument */
- return s->cmdarg;
- case 0x0c: /* Command */
- return s->cmd;
- case 0x10: /* RespCmd */
- return s->respcmd;
- case 0x14: /* Response0 */
- return s->response[0];
- case 0x18: /* Response1 */
- return s->response[1];
- case 0x1c: /* Response2 */
- return s->response[2];
- case 0x20: /* Response3 */
- return s->response[3];
- case 0x24: /* DataTimer */
- return s->datatimer;
- case 0x28: /* DataLength */
- return s->datalength;
- case 0x2c: /* DataCtrl */
- return s->datactrl;
- case 0x30: /* DataCnt */
- return s->datacnt;
- case 0x34: /* Status */
- tmp = s->status;
- if (s->linux_hack) {
- s->linux_hack = 0;
- pl181_fifo_run(s);
- pl181_update(s);
- }
- return tmp;
- case 0x3c: /* Mask0 */
- return s->mask[0];
- case 0x40: /* Mask1 */
- return s->mask[1];
- case 0x48: /* FifoCnt */
- /* The documentation is somewhat vague about exactly what FifoCnt
- does. On real hardware it appears to be when decrememnted
- when a word is transferred between the FIFO and the serial
- data engine. DataCnt is decremented after each byte is
- transferred between the serial engine and the card.
- We don't emulate this level of detail, so both can be the same. */
- tmp = (s->datacnt + 3) >> 2;
- if (s->linux_hack) {
- s->linux_hack = 0;
- pl181_fifo_run(s);
- pl181_update(s);
- }
- return tmp;
- case 0x80: case 0x84: case 0x88: case 0x8c: /* FifoData */
- case 0x90: case 0x94: case 0x98: case 0x9c:
- case 0xa0: case 0xa4: case 0xa8: case 0xac:
- case 0xb0: case 0xb4: case 0xb8: case 0xbc:
- if (s->fifo_len == 0) {
- qemu_log_mask(LOG_GUEST_ERROR, "pl181: Unexpected FIFO read\n");
- return 0;
- } else {
- uint32_t value;
- value = pl181_fifo_pop(s);
- s->linux_hack = 1;
- pl181_fifo_run(s);
- pl181_update(s);
- return value;
- }
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "pl181_read: Bad offset %x\n", (int)offset);
- return 0;
- }
-}
-
-static void pl181_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PL181State *s = (PL181State *)opaque;
-
- switch (offset) {
- case 0x00: /* Power */
- s->power = value & 0xff;
- break;
- case 0x04: /* Clock */
- s->clock = value & 0xff;
- break;
- case 0x08: /* Argument */
- s->cmdarg = value;
- break;
- case 0x0c: /* Command */
- s->cmd = value;
- if (s->cmd & PL181_CMD_ENABLE) {
- if (s->cmd & PL181_CMD_INTERRUPT) {
- qemu_log_mask(LOG_UNIMP,
- "pl181: Interrupt mode not implemented\n");
- } if (s->cmd & PL181_CMD_PENDING) {
- qemu_log_mask(LOG_UNIMP,
- "pl181: Pending commands not implemented\n");
- } else {
- pl181_send_command(s);
- pl181_fifo_run(s);
- }
- /* The command has completed one way or the other. */
- s->cmd &= ~PL181_CMD_ENABLE;
- }
- break;
- case 0x24: /* DataTimer */
- s->datatimer = value;
- break;
- case 0x28: /* DataLength */
- s->datalength = value & 0xffff;
- break;
- case 0x2c: /* DataCtrl */
- s->datactrl = value & 0xff;
- if (value & PL181_DATA_ENABLE) {
- s->datacnt = s->datalength;
- pl181_fifo_run(s);
- }
- break;
- case 0x38: /* Clear */
- s->status &= ~(value & 0x7ff);
- break;
- case 0x3c: /* Mask0 */
- s->mask[0] = value;
- break;
- case 0x40: /* Mask1 */
- s->mask[1] = value;
- break;
- case 0x80: case 0x84: case 0x88: case 0x8c: /* FifoData */
- case 0x90: case 0x94: case 0x98: case 0x9c:
- case 0xa0: case 0xa4: case 0xa8: case 0xac:
- case 0xb0: case 0xb4: case 0xb8: case 0xbc:
- if (s->datacnt == 0) {
- qemu_log_mask(LOG_GUEST_ERROR, "pl181: Unexpected FIFO write\n");
- } else {
- pl181_fifo_push(s, value);
- pl181_fifo_run(s);
- }
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "pl181_write: Bad offset %x\n", (int)offset);
- }
- pl181_update(s);
-}
-
-static const MemoryRegionOps pl181_ops = {
- .read = pl181_read,
- .write = pl181_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void pl181_reset(DeviceState *d)
-{
- PL181State *s = PL181(d);
-
- s->power = 0;
- s->cmdarg = 0;
- s->cmd = 0;
- s->datatimer = 0;
- s->datalength = 0;
- s->respcmd = 0;
- s->response[0] = 0;
- s->response[1] = 0;
- s->response[2] = 0;
- s->response[3] = 0;
- s->datatimer = 0;
- s->datalength = 0;
- s->datactrl = 0;
- s->datacnt = 0;
- s->status = 0;
- s->linux_hack = 0;
- s->mask[0] = 0;
- s->mask[1] = 0;
-
- /* We can assume our GPIO outputs have been wired up now */
- sd_set_cb(s->card, s->cardstatus[0], s->cardstatus[1]);
-}
-
-static int pl181_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- PL181State *s = PL181(dev);
- DriveInfo *dinfo;
-
- memory_region_init_io(&s->iomem, OBJECT(s), &pl181_ops, s, "pl181", 0x1000);
- sysbus_init_mmio(sbd, &s->iomem);
- sysbus_init_irq(sbd, &s->irq[0]);
- sysbus_init_irq(sbd, &s->irq[1]);
- qdev_init_gpio_out(dev, s->cardstatus, 2);
- /* FIXME use a qdev drive property instead of drive_get_next() */
- dinfo = drive_get_next(IF_SD);
- s->card = sd_init(dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, false);
- if (s->card == NULL) {
- return -1;
- }
-
- return 0;
-}
-
-static void pl181_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
- DeviceClass *k = DEVICE_CLASS(klass);
-
- sdc->init = pl181_init;
- k->vmsd = &vmstate_pl181;
- k->reset = pl181_reset;
- /* Reason: init() method uses drive_get_next() */
- k->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo pl181_info = {
- .name = TYPE_PL181,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PL181State),
- .class_init = pl181_class_init,
-};
-
-static void pl181_register_types(void)
-{
- type_register_static(&pl181_info);
-}
-
-type_init(pl181_register_types)
diff --git a/qemu/hw/sd/pxa2xx_mmci.c b/qemu/hw/sd/pxa2xx_mmci.c
deleted file mode 100644
index 3deccf02c..000000000
--- a/qemu/hw/sd/pxa2xx_mmci.c
+++ /dev/null
@@ -1,598 +0,0 @@
-/*
- * Intel XScale PXA255/270 MultiMediaCard/SD/SDIO Controller emulation.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GPLv2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "hw/arm/pxa.h"
-#include "hw/sd/sd.h"
-#include "hw/qdev.h"
-#include "hw/qdev-properties.h"
-#include "qemu/error-report.h"
-
-#define TYPE_PXA2XX_MMCI "pxa2xx-mmci"
-#define PXA2XX_MMCI(obj) OBJECT_CHECK(PXA2xxMMCIState, (obj), TYPE_PXA2XX_MMCI)
-
-#define TYPE_PXA2XX_MMCI_BUS "pxa2xx-mmci-bus"
-#define PXA2XX_MMCI_BUS(obj) OBJECT_CHECK(SDBus, (obj), TYPE_PXA2XX_MMCI_BUS)
-
-struct PXA2xxMMCIState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- qemu_irq irq;
- qemu_irq rx_dma;
- qemu_irq tx_dma;
- qemu_irq inserted;
- qemu_irq readonly;
-
- BlockBackend *blk;
- SDBus sdbus;
-
- uint32_t status;
- uint32_t clkrt;
- uint32_t spi;
- uint32_t cmdat;
- uint32_t resp_tout;
- uint32_t read_tout;
- int32_t blklen;
- int32_t numblk;
- uint32_t intmask;
- uint32_t intreq;
- int32_t cmd;
- uint32_t arg;
-
- int32_t active;
- int32_t bytesleft;
- uint8_t tx_fifo[64];
- uint32_t tx_start;
- uint32_t tx_len;
- uint8_t rx_fifo[32];
- uint32_t rx_start;
- uint32_t rx_len;
- uint16_t resp_fifo[9];
- uint32_t resp_len;
-
- int32_t cmdreq;
-};
-
-static bool pxa2xx_mmci_vmstate_validate(void *opaque, int version_id)
-{
- PXA2xxMMCIState *s = opaque;
-
- return s->tx_start < ARRAY_SIZE(s->tx_fifo)
- && s->rx_start < ARRAY_SIZE(s->rx_fifo)
- && s->tx_len <= ARRAY_SIZE(s->tx_fifo)
- && s->rx_len <= ARRAY_SIZE(s->rx_fifo)
- && s->resp_len <= ARRAY_SIZE(s->resp_fifo);
-}
-
-
-static const VMStateDescription vmstate_pxa2xx_mmci = {
- .name = "pxa2xx-mmci",
- .version_id = 2,
- .minimum_version_id = 2,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(status, PXA2xxMMCIState),
- VMSTATE_UINT32(clkrt, PXA2xxMMCIState),
- VMSTATE_UINT32(spi, PXA2xxMMCIState),
- VMSTATE_UINT32(cmdat, PXA2xxMMCIState),
- VMSTATE_UINT32(resp_tout, PXA2xxMMCIState),
- VMSTATE_UINT32(read_tout, PXA2xxMMCIState),
- VMSTATE_INT32(blklen, PXA2xxMMCIState),
- VMSTATE_INT32(numblk, PXA2xxMMCIState),
- VMSTATE_UINT32(intmask, PXA2xxMMCIState),
- VMSTATE_UINT32(intreq, PXA2xxMMCIState),
- VMSTATE_INT32(cmd, PXA2xxMMCIState),
- VMSTATE_UINT32(arg, PXA2xxMMCIState),
- VMSTATE_INT32(cmdreq, PXA2xxMMCIState),
- VMSTATE_INT32(active, PXA2xxMMCIState),
- VMSTATE_INT32(bytesleft, PXA2xxMMCIState),
- VMSTATE_UINT32(tx_start, PXA2xxMMCIState),
- VMSTATE_UINT32(tx_len, PXA2xxMMCIState),
- VMSTATE_UINT32(rx_start, PXA2xxMMCIState),
- VMSTATE_UINT32(rx_len, PXA2xxMMCIState),
- VMSTATE_UINT32(resp_len, PXA2xxMMCIState),
- VMSTATE_VALIDATE("fifo size incorrect", pxa2xx_mmci_vmstate_validate),
- VMSTATE_UINT8_ARRAY(tx_fifo, PXA2xxMMCIState, 64),
- VMSTATE_UINT8_ARRAY(rx_fifo, PXA2xxMMCIState, 32),
- VMSTATE_UINT16_ARRAY(resp_fifo, PXA2xxMMCIState, 9),
- VMSTATE_END_OF_LIST()
- }
-};
-
-#define MMC_STRPCL 0x00 /* MMC Clock Start/Stop register */
-#define MMC_STAT 0x04 /* MMC Status register */
-#define MMC_CLKRT 0x08 /* MMC Clock Rate register */
-#define MMC_SPI 0x0c /* MMC SPI Mode register */
-#define MMC_CMDAT 0x10 /* MMC Command/Data register */
-#define MMC_RESTO 0x14 /* MMC Response Time-Out register */
-#define MMC_RDTO 0x18 /* MMC Read Time-Out register */
-#define MMC_BLKLEN 0x1c /* MMC Block Length register */
-#define MMC_NUMBLK 0x20 /* MMC Number of Blocks register */
-#define MMC_PRTBUF 0x24 /* MMC Buffer Partly Full register */
-#define MMC_I_MASK 0x28 /* MMC Interrupt Mask register */
-#define MMC_I_REG 0x2c /* MMC Interrupt Request register */
-#define MMC_CMD 0x30 /* MMC Command register */
-#define MMC_ARGH 0x34 /* MMC Argument High register */
-#define MMC_ARGL 0x38 /* MMC Argument Low register */
-#define MMC_RES 0x3c /* MMC Response FIFO */
-#define MMC_RXFIFO 0x40 /* MMC Receive FIFO */
-#define MMC_TXFIFO 0x44 /* MMC Transmit FIFO */
-#define MMC_RDWAIT 0x48 /* MMC RD_WAIT register */
-#define MMC_BLKS_REM 0x4c /* MMC Blocks Remaining register */
-
-/* Bitfield masks */
-#define STRPCL_STOP_CLK (1 << 0)
-#define STRPCL_STRT_CLK (1 << 1)
-#define STAT_TOUT_RES (1 << 1)
-#define STAT_CLK_EN (1 << 8)
-#define STAT_DATA_DONE (1 << 11)
-#define STAT_PRG_DONE (1 << 12)
-#define STAT_END_CMDRES (1 << 13)
-#define SPI_SPI_MODE (1 << 0)
-#define CMDAT_RES_TYPE (3 << 0)
-#define CMDAT_DATA_EN (1 << 2)
-#define CMDAT_WR_RD (1 << 3)
-#define CMDAT_DMA_EN (1 << 7)
-#define CMDAT_STOP_TRAN (1 << 10)
-#define INT_DATA_DONE (1 << 0)
-#define INT_PRG_DONE (1 << 1)
-#define INT_END_CMD (1 << 2)
-#define INT_STOP_CMD (1 << 3)
-#define INT_CLK_OFF (1 << 4)
-#define INT_RXFIFO_REQ (1 << 5)
-#define INT_TXFIFO_REQ (1 << 6)
-#define INT_TINT (1 << 7)
-#define INT_DAT_ERR (1 << 8)
-#define INT_RES_ERR (1 << 9)
-#define INT_RD_STALLED (1 << 10)
-#define INT_SDIO_INT (1 << 11)
-#define INT_SDIO_SACK (1 << 12)
-#define PRTBUF_PRT_BUF (1 << 0)
-
-/* Route internal interrupt lines to the global IC and DMA */
-static void pxa2xx_mmci_int_update(PXA2xxMMCIState *s)
-{
- uint32_t mask = s->intmask;
- if (s->cmdat & CMDAT_DMA_EN) {
- mask |= INT_RXFIFO_REQ | INT_TXFIFO_REQ;
-
- qemu_set_irq(s->rx_dma, !!(s->intreq & INT_RXFIFO_REQ));
- qemu_set_irq(s->tx_dma, !!(s->intreq & INT_TXFIFO_REQ));
- }
-
- qemu_set_irq(s->irq, !!(s->intreq & ~mask));
-}
-
-static void pxa2xx_mmci_fifo_update(PXA2xxMMCIState *s)
-{
- if (!s->active)
- return;
-
- if (s->cmdat & CMDAT_WR_RD) {
- while (s->bytesleft && s->tx_len) {
- sdbus_write_data(&s->sdbus, s->tx_fifo[s->tx_start++]);
- s->tx_start &= 0x1f;
- s->tx_len --;
- s->bytesleft --;
- }
- if (s->bytesleft)
- s->intreq |= INT_TXFIFO_REQ;
- } else
- while (s->bytesleft && s->rx_len < 32) {
- s->rx_fifo[(s->rx_start + (s->rx_len ++)) & 0x1f] =
- sdbus_read_data(&s->sdbus);
- s->bytesleft --;
- s->intreq |= INT_RXFIFO_REQ;
- }
-
- if (!s->bytesleft) {
- s->active = 0;
- s->intreq |= INT_DATA_DONE;
- s->status |= STAT_DATA_DONE;
-
- if (s->cmdat & CMDAT_WR_RD) {
- s->intreq |= INT_PRG_DONE;
- s->status |= STAT_PRG_DONE;
- }
- }
-
- pxa2xx_mmci_int_update(s);
-}
-
-static void pxa2xx_mmci_wakequeues(PXA2xxMMCIState *s)
-{
- int rsplen, i;
- SDRequest request;
- uint8_t response[16];
-
- s->active = 1;
- s->rx_len = 0;
- s->tx_len = 0;
- s->cmdreq = 0;
-
- request.cmd = s->cmd;
- request.arg = s->arg;
- request.crc = 0; /* FIXME */
-
- rsplen = sdbus_do_command(&s->sdbus, &request, response);
- s->intreq |= INT_END_CMD;
-
- memset(s->resp_fifo, 0, sizeof(s->resp_fifo));
- switch (s->cmdat & CMDAT_RES_TYPE) {
-#define PXAMMCI_RESP(wd, value0, value1) \
- s->resp_fifo[(wd) + 0] |= (value0); \
- s->resp_fifo[(wd) + 1] |= (value1) << 8;
- case 0: /* No response */
- goto complete;
-
- case 1: /* R1, R4, R5 or R6 */
- if (rsplen < 4)
- goto timeout;
- goto complete;
-
- case 2: /* R2 */
- if (rsplen < 16)
- goto timeout;
- goto complete;
-
- case 3: /* R3 */
- if (rsplen < 4)
- goto timeout;
- goto complete;
-
- complete:
- for (i = 0; rsplen > 0; i ++, rsplen -= 2) {
- PXAMMCI_RESP(i, response[i * 2], response[i * 2 + 1]);
- }
- s->status |= STAT_END_CMDRES;
-
- if (!(s->cmdat & CMDAT_DATA_EN))
- s->active = 0;
- else
- s->bytesleft = s->numblk * s->blklen;
-
- s->resp_len = 0;
- break;
-
- timeout:
- s->active = 0;
- s->status |= STAT_TOUT_RES;
- break;
- }
-
- pxa2xx_mmci_fifo_update(s);
-}
-
-static uint64_t pxa2xx_mmci_read(void *opaque, hwaddr offset, unsigned size)
-{
- PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
- uint32_t ret;
-
- switch (offset) {
- case MMC_STRPCL:
- return 0;
- case MMC_STAT:
- return s->status;
- case MMC_CLKRT:
- return s->clkrt;
- case MMC_SPI:
- return s->spi;
- case MMC_CMDAT:
- return s->cmdat;
- case MMC_RESTO:
- return s->resp_tout;
- case MMC_RDTO:
- return s->read_tout;
- case MMC_BLKLEN:
- return s->blklen;
- case MMC_NUMBLK:
- return s->numblk;
- case MMC_PRTBUF:
- return 0;
- case MMC_I_MASK:
- return s->intmask;
- case MMC_I_REG:
- return s->intreq;
- case MMC_CMD:
- return s->cmd | 0x40;
- case MMC_ARGH:
- return s->arg >> 16;
- case MMC_ARGL:
- return s->arg & 0xffff;
- case MMC_RES:
- if (s->resp_len < 9)
- return s->resp_fifo[s->resp_len ++];
- return 0;
- case MMC_RXFIFO:
- ret = 0;
- while (size-- && s->rx_len) {
- ret |= s->rx_fifo[s->rx_start++] << (size << 3);
- s->rx_start &= 0x1f;
- s->rx_len --;
- }
- s->intreq &= ~INT_RXFIFO_REQ;
- pxa2xx_mmci_fifo_update(s);
- return ret;
- case MMC_RDWAIT:
- return 0;
- case MMC_BLKS_REM:
- return s->numblk;
- default:
- hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
- }
-
- return 0;
-}
-
-static void pxa2xx_mmci_write(void *opaque,
- hwaddr offset, uint64_t value, unsigned size)
-{
- PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
-
- switch (offset) {
- case MMC_STRPCL:
- if (value & STRPCL_STRT_CLK) {
- s->status |= STAT_CLK_EN;
- s->intreq &= ~INT_CLK_OFF;
-
- if (s->cmdreq && !(s->cmdat & CMDAT_STOP_TRAN)) {
- s->status &= STAT_CLK_EN;
- pxa2xx_mmci_wakequeues(s);
- }
- }
-
- if (value & STRPCL_STOP_CLK) {
- s->status &= ~STAT_CLK_EN;
- s->intreq |= INT_CLK_OFF;
- s->active = 0;
- }
-
- pxa2xx_mmci_int_update(s);
- break;
-
- case MMC_CLKRT:
- s->clkrt = value & 7;
- break;
-
- case MMC_SPI:
- s->spi = value & 0xf;
- if (value & SPI_SPI_MODE)
- printf("%s: attempted to use card in SPI mode\n", __FUNCTION__);
- break;
-
- case MMC_CMDAT:
- s->cmdat = value & 0x3dff;
- s->active = 0;
- s->cmdreq = 1;
- if (!(value & CMDAT_STOP_TRAN)) {
- s->status &= STAT_CLK_EN;
-
- if (s->status & STAT_CLK_EN)
- pxa2xx_mmci_wakequeues(s);
- }
-
- pxa2xx_mmci_int_update(s);
- break;
-
- case MMC_RESTO:
- s->resp_tout = value & 0x7f;
- break;
-
- case MMC_RDTO:
- s->read_tout = value & 0xffff;
- break;
-
- case MMC_BLKLEN:
- s->blklen = value & 0xfff;
- break;
-
- case MMC_NUMBLK:
- s->numblk = value & 0xffff;
- break;
-
- case MMC_PRTBUF:
- if (value & PRTBUF_PRT_BUF) {
- s->tx_start ^= 32;
- s->tx_len = 0;
- }
- pxa2xx_mmci_fifo_update(s);
- break;
-
- case MMC_I_MASK:
- s->intmask = value & 0x1fff;
- pxa2xx_mmci_int_update(s);
- break;
-
- case MMC_CMD:
- s->cmd = value & 0x3f;
- break;
-
- case MMC_ARGH:
- s->arg &= 0x0000ffff;
- s->arg |= value << 16;
- break;
-
- case MMC_ARGL:
- s->arg &= 0xffff0000;
- s->arg |= value & 0x0000ffff;
- break;
-
- case MMC_TXFIFO:
- while (size-- && s->tx_len < 0x20)
- s->tx_fifo[(s->tx_start + (s->tx_len ++)) & 0x1f] =
- (value >> (size << 3)) & 0xff;
- s->intreq &= ~INT_TXFIFO_REQ;
- pxa2xx_mmci_fifo_update(s);
- break;
-
- case MMC_RDWAIT:
- case MMC_BLKS_REM:
- break;
-
- default:
- hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
- }
-}
-
-static const MemoryRegionOps pxa2xx_mmci_ops = {
- .read = pxa2xx_mmci_read,
- .write = pxa2xx_mmci_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-PXA2xxMMCIState *pxa2xx_mmci_init(MemoryRegion *sysmem,
- hwaddr base,
- BlockBackend *blk, qemu_irq irq,
- qemu_irq rx_dma, qemu_irq tx_dma)
-{
- DeviceState *dev, *carddev;
- SysBusDevice *sbd;
- PXA2xxMMCIState *s;
- Error *err = NULL;
-
- dev = qdev_create(NULL, TYPE_PXA2XX_MMCI);
- s = PXA2XX_MMCI(dev);
- sbd = SYS_BUS_DEVICE(dev);
- sysbus_mmio_map(sbd, 0, base);
- sysbus_connect_irq(sbd, 0, irq);
- qdev_connect_gpio_out_named(dev, "rx-dma", 0, rx_dma);
- qdev_connect_gpio_out_named(dev, "tx-dma", 0, tx_dma);
-
- /* Create and plug in the sd card */
- carddev = qdev_create(qdev_get_child_bus(dev, "sd-bus"), TYPE_SD_CARD);
- qdev_prop_set_drive(carddev, "drive", blk, &err);
- if (err) {
- error_report("failed to init SD card: %s", error_get_pretty(err));
- return NULL;
- }
- object_property_set_bool(OBJECT(carddev), true, "realized", &err);
- if (err) {
- error_report("failed to init SD card: %s", error_get_pretty(err));
- return NULL;
- }
-
- return s;
-}
-
-static void pxa2xx_mmci_set_inserted(DeviceState *dev, bool inserted)
-{
- PXA2xxMMCIState *s = PXA2XX_MMCI(dev);
-
- qemu_set_irq(s->inserted, inserted);
-}
-
-static void pxa2xx_mmci_set_readonly(DeviceState *dev, bool readonly)
-{
- PXA2xxMMCIState *s = PXA2XX_MMCI(dev);
-
- qemu_set_irq(s->readonly, readonly);
-}
-
-void pxa2xx_mmci_handlers(PXA2xxMMCIState *s, qemu_irq readonly,
- qemu_irq coverswitch)
-{
- DeviceState *dev = DEVICE(s);
-
- s->readonly = readonly;
- s->inserted = coverswitch;
-
- pxa2xx_mmci_set_inserted(dev, sdbus_get_inserted(&s->sdbus));
- pxa2xx_mmci_set_readonly(dev, sdbus_get_readonly(&s->sdbus));
-}
-
-static void pxa2xx_mmci_reset(DeviceState *d)
-{
- PXA2xxMMCIState *s = PXA2XX_MMCI(d);
-
- s->status = 0;
- s->clkrt = 0;
- s->spi = 0;
- s->cmdat = 0;
- s->resp_tout = 0;
- s->read_tout = 0;
- s->blklen = 0;
- s->numblk = 0;
- s->intmask = 0;
- s->intreq = 0;
- s->cmd = 0;
- s->arg = 0;
- s->active = 0;
- s->bytesleft = 0;
- s->tx_start = 0;
- s->tx_len = 0;
- s->rx_start = 0;
- s->rx_len = 0;
- s->resp_len = 0;
- s->cmdreq = 0;
- memset(s->tx_fifo, 0, sizeof(s->tx_fifo));
- memset(s->rx_fifo, 0, sizeof(s->rx_fifo));
- memset(s->resp_fifo, 0, sizeof(s->resp_fifo));
-}
-
-static void pxa2xx_mmci_instance_init(Object *obj)
-{
- PXA2xxMMCIState *s = PXA2XX_MMCI(obj);
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- DeviceState *dev = DEVICE(obj);
-
- memory_region_init_io(&s->iomem, obj, &pxa2xx_mmci_ops, s,
- "pxa2xx-mmci", 0x00100000);
- sysbus_init_mmio(sbd, &s->iomem);
- sysbus_init_irq(sbd, &s->irq);
- qdev_init_gpio_out_named(dev, &s->rx_dma, "rx-dma", 1);
- qdev_init_gpio_out_named(dev, &s->tx_dma, "tx-dma", 1);
-
- qbus_create_inplace(&s->sdbus, sizeof(s->sdbus),
- TYPE_PXA2XX_MMCI_BUS, DEVICE(obj), "sd-bus");
-}
-
-static void pxa2xx_mmci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->vmsd = &vmstate_pxa2xx_mmci;
- dc->reset = pxa2xx_mmci_reset;
-}
-
-static void pxa2xx_mmci_bus_class_init(ObjectClass *klass, void *data)
-{
- SDBusClass *sbc = SD_BUS_CLASS(klass);
-
- sbc->set_inserted = pxa2xx_mmci_set_inserted;
- sbc->set_readonly = pxa2xx_mmci_set_readonly;
-}
-
-static const TypeInfo pxa2xx_mmci_info = {
- .name = TYPE_PXA2XX_MMCI,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PXA2xxMMCIState),
- .instance_init = pxa2xx_mmci_instance_init,
- .class_init = pxa2xx_mmci_class_init,
-};
-
-static const TypeInfo pxa2xx_mmci_bus_info = {
- .name = TYPE_PXA2XX_MMCI_BUS,
- .parent = TYPE_SD_BUS,
- .instance_size = sizeof(SDBus),
- .class_init = pxa2xx_mmci_bus_class_init,
-};
-
-static void pxa2xx_mmci_register_types(void)
-{
- type_register_static(&pxa2xx_mmci_info);
- type_register_static(&pxa2xx_mmci_bus_info);
-}
-
-type_init(pxa2xx_mmci_register_types)
diff --git a/qemu/hw/sd/sd.c b/qemu/hw/sd/sd.c
deleted file mode 100644
index b66e5d2db..000000000
--- a/qemu/hw/sd/sd.c
+++ /dev/null
@@ -1,1979 +0,0 @@
-/*
- * SD Memory Card emulation as defined in the "SD Memory Card Physical
- * layer specification, Version 1.10."
- *
- * Copyright (c) 2006 Andrzej Zaborowski <balrog@zabor.org>
- * Copyright (c) 2007 CodeSourcery
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "qemu/osdep.h"
-#include "hw/qdev.h"
-#include "hw/hw.h"
-#include "sysemu/block-backend.h"
-#include "hw/sd/sd.h"
-#include "qapi/error.h"
-#include "qemu/bitmap.h"
-#include "hw/qdev-properties.h"
-#include "qemu/error-report.h"
-#include "qemu/timer.h"
-
-//#define DEBUG_SD 1
-
-#ifdef DEBUG_SD
-#define DPRINTF(fmt, ...) \
-do { fprintf(stderr, "SD: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#endif
-
-#define ACMD41_ENQUIRY_MASK 0x00ffffff
-#define OCR_POWER_UP 0x80000000
-#define OCR_POWER_DELAY_NS 500000 /* 0.5ms */
-
-typedef enum {
- sd_r0 = 0, /* no response */
- sd_r1, /* normal response command */
- sd_r2_i, /* CID register */
- sd_r2_s, /* CSD register */
- sd_r3, /* OCR register */
- sd_r6 = 6, /* Published RCA response */
- sd_r7, /* Operating voltage */
- sd_r1b = -1,
- sd_illegal = -2,
-} sd_rsp_type_t;
-
-enum SDCardModes {
- sd_inactive,
- sd_card_identification_mode,
- sd_data_transfer_mode,
-};
-
-enum SDCardStates {
- sd_inactive_state = -1,
- sd_idle_state = 0,
- sd_ready_state,
- sd_identification_state,
- sd_standby_state,
- sd_transfer_state,
- sd_sendingdata_state,
- sd_receivingdata_state,
- sd_programming_state,
- sd_disconnect_state,
-};
-
-struct SDState {
- DeviceState parent_obj;
-
- uint32_t mode; /* current card mode, one of SDCardModes */
- int32_t state; /* current card state, one of SDCardStates */
- uint32_t ocr;
- QEMUTimer *ocr_power_timer;
- uint8_t scr[8];
- uint8_t cid[16];
- uint8_t csd[16];
- uint16_t rca;
- uint32_t card_status;
- uint8_t sd_status[64];
- uint32_t vhs;
- bool wp_switch;
- unsigned long *wp_groups;
- int32_t wpgrps_size;
- uint64_t size;
- uint32_t blk_len;
- uint32_t multi_blk_cnt;
- uint32_t erase_start;
- uint32_t erase_end;
- uint8_t pwd[16];
- uint32_t pwd_len;
- uint8_t function_group[6];
-
- bool spi;
- uint8_t current_cmd;
- /* True if we will handle the next command as an ACMD. Note that this does
- * *not* track the APP_CMD status bit!
- */
- bool expecting_acmd;
- uint32_t blk_written;
- uint64_t data_start;
- uint32_t data_offset;
- uint8_t data[512];
- qemu_irq readonly_cb;
- qemu_irq inserted_cb;
- BlockBackend *blk;
- uint8_t *buf;
-
- bool enable;
-};
-
-static void sd_set_mode(SDState *sd)
-{
- switch (sd->state) {
- case sd_inactive_state:
- sd->mode = sd_inactive;
- break;
-
- case sd_idle_state:
- case sd_ready_state:
- case sd_identification_state:
- sd->mode = sd_card_identification_mode;
- break;
-
- case sd_standby_state:
- case sd_transfer_state:
- case sd_sendingdata_state:
- case sd_receivingdata_state:
- case sd_programming_state:
- case sd_disconnect_state:
- sd->mode = sd_data_transfer_mode;
- break;
- }
-}
-
-static const sd_cmd_type_t sd_cmd_type[64] = {
- sd_bc, sd_none, sd_bcr, sd_bcr, sd_none, sd_none, sd_none, sd_ac,
- sd_bcr, sd_ac, sd_ac, sd_adtc, sd_ac, sd_ac, sd_none, sd_ac,
- sd_ac, sd_adtc, sd_adtc, sd_none, sd_none, sd_none, sd_none, sd_none,
- sd_adtc, sd_adtc, sd_adtc, sd_adtc, sd_ac, sd_ac, sd_adtc, sd_none,
- sd_ac, sd_ac, sd_none, sd_none, sd_none, sd_none, sd_ac, sd_none,
- sd_none, sd_none, sd_bc, sd_none, sd_none, sd_none, sd_none, sd_none,
- sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_ac,
- sd_adtc, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none,
-};
-
-static const int sd_cmd_class[64] = {
- 0, 0, 0, 0, 0, 9, 10, 0, 0, 0, 0, 1, 0, 0, 0, 0,
- 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 6, 6, 6, 6,
- 5, 5, 10, 10, 10, 10, 5, 9, 9, 9, 7, 7, 7, 7, 7, 7,
- 7, 7, 10, 7, 9, 9, 9, 8, 8, 10, 8, 8, 8, 8, 8, 8,
-};
-
-static uint8_t sd_crc7(void *message, size_t width)
-{
- int i, bit;
- uint8_t shift_reg = 0x00;
- uint8_t *msg = (uint8_t *) message;
-
- for (i = 0; i < width; i ++, msg ++)
- for (bit = 7; bit >= 0; bit --) {
- shift_reg <<= 1;
- if ((shift_reg >> 7) ^ ((*msg >> bit) & 1))
- shift_reg ^= 0x89;
- }
-
- return shift_reg;
-}
-
-static uint16_t sd_crc16(void *message, size_t width)
-{
- int i, bit;
- uint16_t shift_reg = 0x0000;
- uint16_t *msg = (uint16_t *) message;
- width <<= 1;
-
- for (i = 0; i < width; i ++, msg ++)
- for (bit = 15; bit >= 0; bit --) {
- shift_reg <<= 1;
- if ((shift_reg >> 15) ^ ((*msg >> bit) & 1))
- shift_reg ^= 0x1011;
- }
-
- return shift_reg;
-}
-
-static void sd_set_ocr(SDState *sd)
-{
- /* All voltages OK, Standard Capacity SD Memory Card, not yet powered up */
- sd->ocr = 0x00ffff00;
-}
-
-static void sd_ocr_powerup(void *opaque)
-{
- SDState *sd = opaque;
-
- /* Set powered up bit in OCR */
- assert(!(sd->ocr & OCR_POWER_UP));
- sd->ocr |= OCR_POWER_UP;
-}
-
-static void sd_set_scr(SDState *sd)
-{
- sd->scr[0] = 0x00; /* SCR Structure */
- sd->scr[1] = 0x2f; /* SD Security Support */
- sd->scr[2] = 0x00;
- sd->scr[3] = 0x00;
- sd->scr[4] = 0x00;
- sd->scr[5] = 0x00;
- sd->scr[6] = 0x00;
- sd->scr[7] = 0x00;
-}
-
-#define MID 0xaa
-#define OID "XY"
-#define PNM "QEMU!"
-#define PRV 0x01
-#define MDT_YR 2006
-#define MDT_MON 2
-
-static void sd_set_cid(SDState *sd)
-{
- sd->cid[0] = MID; /* Fake card manufacturer ID (MID) */
- sd->cid[1] = OID[0]; /* OEM/Application ID (OID) */
- sd->cid[2] = OID[1];
- sd->cid[3] = PNM[0]; /* Fake product name (PNM) */
- sd->cid[4] = PNM[1];
- sd->cid[5] = PNM[2];
- sd->cid[6] = PNM[3];
- sd->cid[7] = PNM[4];
- sd->cid[8] = PRV; /* Fake product revision (PRV) */
- sd->cid[9] = 0xde; /* Fake serial number (PSN) */
- sd->cid[10] = 0xad;
- sd->cid[11] = 0xbe;
- sd->cid[12] = 0xef;
- sd->cid[13] = 0x00 | /* Manufacture date (MDT) */
- ((MDT_YR - 2000) / 10);
- sd->cid[14] = ((MDT_YR % 10) << 4) | MDT_MON;
- sd->cid[15] = (sd_crc7(sd->cid, 15) << 1) | 1;
-}
-
-#define HWBLOCK_SHIFT 9 /* 512 bytes */
-#define SECTOR_SHIFT 5 /* 16 kilobytes */
-#define WPGROUP_SHIFT 7 /* 2 megs */
-#define CMULT_SHIFT 9 /* 512 times HWBLOCK_SIZE */
-#define WPGROUP_SIZE (1 << (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT))
-
-static const uint8_t sd_csd_rw_mask[16] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfe,
-};
-
-static void sd_set_csd(SDState *sd, uint64_t size)
-{
- uint32_t csize = (size >> (CMULT_SHIFT + HWBLOCK_SHIFT)) - 1;
- uint32_t sectsize = (1 << (SECTOR_SHIFT + 1)) - 1;
- uint32_t wpsize = (1 << (WPGROUP_SHIFT + 1)) - 1;
-
- if (size <= 0x40000000) { /* Standard Capacity SD */
- sd->csd[0] = 0x00; /* CSD structure */
- sd->csd[1] = 0x26; /* Data read access-time-1 */
- sd->csd[2] = 0x00; /* Data read access-time-2 */
- sd->csd[3] = 0x5a; /* Max. data transfer rate */
- sd->csd[4] = 0x5f; /* Card Command Classes */
- sd->csd[5] = 0x50 | /* Max. read data block length */
- HWBLOCK_SHIFT;
- sd->csd[6] = 0xe0 | /* Partial block for read allowed */
- ((csize >> 10) & 0x03);
- sd->csd[7] = 0x00 | /* Device size */
- ((csize >> 2) & 0xff);
- sd->csd[8] = 0x3f | /* Max. read current */
- ((csize << 6) & 0xc0);
- sd->csd[9] = 0xfc | /* Max. write current */
- ((CMULT_SHIFT - 2) >> 1);
- sd->csd[10] = 0x40 | /* Erase sector size */
- (((CMULT_SHIFT - 2) << 7) & 0x80) | (sectsize >> 1);
- sd->csd[11] = 0x00 | /* Write protect group size */
- ((sectsize << 7) & 0x80) | wpsize;
- sd->csd[12] = 0x90 | /* Write speed factor */
- (HWBLOCK_SHIFT >> 2);
- sd->csd[13] = 0x20 | /* Max. write data block length */
- ((HWBLOCK_SHIFT << 6) & 0xc0);
- sd->csd[14] = 0x00; /* File format group */
- sd->csd[15] = (sd_crc7(sd->csd, 15) << 1) | 1;
- } else { /* SDHC */
- size /= 512 * 1024;
- size -= 1;
- sd->csd[0] = 0x40;
- sd->csd[1] = 0x0e;
- sd->csd[2] = 0x00;
- sd->csd[3] = 0x32;
- sd->csd[4] = 0x5b;
- sd->csd[5] = 0x59;
- sd->csd[6] = 0x00;
- sd->csd[7] = (size >> 16) & 0xff;
- sd->csd[8] = (size >> 8) & 0xff;
- sd->csd[9] = (size & 0xff);
- sd->csd[10] = 0x7f;
- sd->csd[11] = 0x80;
- sd->csd[12] = 0x0a;
- sd->csd[13] = 0x40;
- sd->csd[14] = 0x00;
- sd->csd[15] = 0x00;
- sd->ocr |= 1 << 30; /* High Capacity SD Memory Card */
- }
-}
-
-static void sd_set_rca(SDState *sd)
-{
- sd->rca += 0x4567;
-}
-
-/* Card status bits, split by clear condition:
- * A : According to the card current state
- * B : Always related to the previous command
- * C : Cleared by read
- */
-#define CARD_STATUS_A 0x02004100
-#define CARD_STATUS_B 0x00c01e00
-#define CARD_STATUS_C 0xfd39a028
-
-static void sd_set_cardstatus(SDState *sd)
-{
- sd->card_status = 0x00000100;
-}
-
-static void sd_set_sdstatus(SDState *sd)
-{
- memset(sd->sd_status, 0, 64);
-}
-
-static int sd_req_crc_validate(SDRequest *req)
-{
- uint8_t buffer[5];
- buffer[0] = 0x40 | req->cmd;
- buffer[1] = (req->arg >> 24) & 0xff;
- buffer[2] = (req->arg >> 16) & 0xff;
- buffer[3] = (req->arg >> 8) & 0xff;
- buffer[4] = (req->arg >> 0) & 0xff;
- return 0;
- return sd_crc7(buffer, 5) != req->crc; /* TODO */
-}
-
-static void sd_response_r1_make(SDState *sd, uint8_t *response)
-{
- uint32_t status = sd->card_status;
- /* Clear the "clear on read" status bits */
- sd->card_status &= ~CARD_STATUS_C;
-
- response[0] = (status >> 24) & 0xff;
- response[1] = (status >> 16) & 0xff;
- response[2] = (status >> 8) & 0xff;
- response[3] = (status >> 0) & 0xff;
-}
-
-static void sd_response_r3_make(SDState *sd, uint8_t *response)
-{
- response[0] = (sd->ocr >> 24) & 0xff;
- response[1] = (sd->ocr >> 16) & 0xff;
- response[2] = (sd->ocr >> 8) & 0xff;
- response[3] = (sd->ocr >> 0) & 0xff;
-}
-
-static void sd_response_r6_make(SDState *sd, uint8_t *response)
-{
- uint16_t arg;
- uint16_t status;
-
- arg = sd->rca;
- status = ((sd->card_status >> 8) & 0xc000) |
- ((sd->card_status >> 6) & 0x2000) |
- (sd->card_status & 0x1fff);
- sd->card_status &= ~(CARD_STATUS_C & 0xc81fff);
-
- response[0] = (arg >> 8) & 0xff;
- response[1] = arg & 0xff;
- response[2] = (status >> 8) & 0xff;
- response[3] = status & 0xff;
-}
-
-static void sd_response_r7_make(SDState *sd, uint8_t *response)
-{
- response[0] = (sd->vhs >> 24) & 0xff;
- response[1] = (sd->vhs >> 16) & 0xff;
- response[2] = (sd->vhs >> 8) & 0xff;
- response[3] = (sd->vhs >> 0) & 0xff;
-}
-
-static inline uint64_t sd_addr_to_wpnum(uint64_t addr)
-{
- return addr >> (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT);
-}
-
-static void sd_reset(DeviceState *dev)
-{
- SDState *sd = SD_CARD(dev);
- uint64_t size;
- uint64_t sect;
-
- if (sd->blk) {
- blk_get_geometry(sd->blk, &sect);
- } else {
- sect = 0;
- }
- size = sect << 9;
-
- sect = sd_addr_to_wpnum(size) + 1;
-
- sd->state = sd_idle_state;
- sd->rca = 0x0000;
- sd_set_ocr(sd);
- sd_set_scr(sd);
- sd_set_cid(sd);
- sd_set_csd(sd, size);
- sd_set_cardstatus(sd);
- sd_set_sdstatus(sd);
-
- g_free(sd->wp_groups);
- sd->wp_switch = sd->blk ? blk_is_read_only(sd->blk) : false;
- sd->wpgrps_size = sect;
- sd->wp_groups = bitmap_new(sd->wpgrps_size);
- memset(sd->function_group, 0, sizeof(sd->function_group));
- sd->erase_start = 0;
- sd->erase_end = 0;
- sd->size = size;
- sd->blk_len = 0x200;
- sd->pwd_len = 0;
- sd->expecting_acmd = false;
- sd->multi_blk_cnt = 0;
-}
-
-static bool sd_get_inserted(SDState *sd)
-{
- return sd->blk && blk_is_inserted(sd->blk);
-}
-
-static bool sd_get_readonly(SDState *sd)
-{
- return sd->wp_switch;
-}
-
-static void sd_cardchange(void *opaque, bool load)
-{
- SDState *sd = opaque;
- DeviceState *dev = DEVICE(sd);
- SDBus *sdbus = SD_BUS(qdev_get_parent_bus(dev));
- bool inserted = sd_get_inserted(sd);
- bool readonly = sd_get_readonly(sd);
-
- if (inserted) {
- sd_reset(dev);
- }
-
- /* The IRQ notification is for legacy non-QOM SD controller devices;
- * QOMified controllers use the SDBus APIs.
- */
- if (sdbus) {
- sdbus_set_inserted(sdbus, inserted);
- if (inserted) {
- sdbus_set_readonly(sdbus, readonly);
- }
- } else {
- qemu_set_irq(sd->inserted_cb, inserted);
- if (inserted) {
- qemu_set_irq(sd->readonly_cb, readonly);
- }
- }
-}
-
-static const BlockDevOps sd_block_ops = {
- .change_media_cb = sd_cardchange,
-};
-
-static bool sd_ocr_vmstate_needed(void *opaque)
-{
- SDState *sd = opaque;
-
- /* Include the OCR state (and timer) if it is not yet powered up */
- return !(sd->ocr & OCR_POWER_UP);
-}
-
-static const VMStateDescription sd_ocr_vmstate = {
- .name = "sd-card/ocr-state",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = sd_ocr_vmstate_needed,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(ocr, SDState),
- VMSTATE_TIMER_PTR(ocr_power_timer, SDState),
- VMSTATE_END_OF_LIST()
- },
-};
-
-static int sd_vmstate_pre_load(void *opaque)
-{
- SDState *sd = opaque;
-
- /* If the OCR state is not included (prior versions, or not
- * needed), then the OCR must be set as powered up. If the OCR state
- * is included, this will be replaced by the state restore.
- */
- sd_ocr_powerup(sd);
-
- return 0;
-}
-
-static const VMStateDescription sd_vmstate = {
- .name = "sd-card",
- .version_id = 1,
- .minimum_version_id = 1,
- .pre_load = sd_vmstate_pre_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(mode, SDState),
- VMSTATE_INT32(state, SDState),
- VMSTATE_UINT8_ARRAY(cid, SDState, 16),
- VMSTATE_UINT8_ARRAY(csd, SDState, 16),
- VMSTATE_UINT16(rca, SDState),
- VMSTATE_UINT32(card_status, SDState),
- VMSTATE_PARTIAL_BUFFER(sd_status, SDState, 1),
- VMSTATE_UINT32(vhs, SDState),
- VMSTATE_BITMAP(wp_groups, SDState, 0, wpgrps_size),
- VMSTATE_UINT32(blk_len, SDState),
- VMSTATE_UINT32(multi_blk_cnt, SDState),
- VMSTATE_UINT32(erase_start, SDState),
- VMSTATE_UINT32(erase_end, SDState),
- VMSTATE_UINT8_ARRAY(pwd, SDState, 16),
- VMSTATE_UINT32(pwd_len, SDState),
- VMSTATE_UINT8_ARRAY(function_group, SDState, 6),
- VMSTATE_UINT8(current_cmd, SDState),
- VMSTATE_BOOL(expecting_acmd, SDState),
- VMSTATE_UINT32(blk_written, SDState),
- VMSTATE_UINT64(data_start, SDState),
- VMSTATE_UINT32(data_offset, SDState),
- VMSTATE_UINT8_ARRAY(data, SDState, 512),
- VMSTATE_BUFFER_POINTER_UNSAFE(buf, SDState, 1, 512),
- VMSTATE_BOOL(enable, SDState),
- VMSTATE_END_OF_LIST()
- },
- .subsections = (const VMStateDescription*[]) {
- &sd_ocr_vmstate,
- NULL
- },
-};
-
-/* Legacy initialization function for use by non-qdevified callers */
-SDState *sd_init(BlockBackend *blk, bool is_spi)
-{
- Object *obj;
- DeviceState *dev;
- Error *err = NULL;
-
- obj = object_new(TYPE_SD_CARD);
- dev = DEVICE(obj);
- qdev_prop_set_drive(dev, "drive", blk, &err);
- if (err) {
- error_report("sd_init failed: %s", error_get_pretty(err));
- return NULL;
- }
- qdev_prop_set_bit(dev, "spi", is_spi);
- object_property_set_bool(obj, true, "realized", &err);
- if (err) {
- error_report("sd_init failed: %s", error_get_pretty(err));
- return NULL;
- }
-
- return SD_CARD(dev);
-}
-
-void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert)
-{
- sd->readonly_cb = readonly;
- sd->inserted_cb = insert;
- qemu_set_irq(readonly, sd->blk ? blk_is_read_only(sd->blk) : 0);
- qemu_set_irq(insert, sd->blk ? blk_is_inserted(sd->blk) : 0);
-}
-
-static void sd_erase(SDState *sd)
-{
- int i;
- uint64_t erase_start = sd->erase_start;
- uint64_t erase_end = sd->erase_end;
-
- if (!sd->erase_start || !sd->erase_end) {
- sd->card_status |= ERASE_SEQ_ERROR;
- return;
- }
-
- if (extract32(sd->ocr, OCR_CCS_BITN, 1)) {
- /* High capacity memory card: erase units are 512 byte blocks */
- erase_start *= 512;
- erase_end *= 512;
- }
-
- erase_start = sd_addr_to_wpnum(erase_start);
- erase_end = sd_addr_to_wpnum(erase_end);
- sd->erase_start = 0;
- sd->erase_end = 0;
- sd->csd[14] |= 0x40;
-
- for (i = erase_start; i <= erase_end; i++) {
- if (test_bit(i, sd->wp_groups)) {
- sd->card_status |= WP_ERASE_SKIP;
- }
- }
-}
-
-static uint32_t sd_wpbits(SDState *sd, uint64_t addr)
-{
- uint32_t i, wpnum;
- uint32_t ret = 0;
-
- wpnum = sd_addr_to_wpnum(addr);
-
- for (i = 0; i < 32; i++, wpnum++, addr += WPGROUP_SIZE) {
- if (addr < sd->size && test_bit(wpnum, sd->wp_groups)) {
- ret |= (1 << i);
- }
- }
-
- return ret;
-}
-
-static void sd_function_switch(SDState *sd, uint32_t arg)
-{
- int i, mode, new_func, crc;
- mode = !!(arg & 0x80000000);
-
- sd->data[0] = 0x00; /* Maximum current consumption */
- sd->data[1] = 0x01;
- sd->data[2] = 0x80; /* Supported group 6 functions */
- sd->data[3] = 0x01;
- sd->data[4] = 0x80; /* Supported group 5 functions */
- sd->data[5] = 0x01;
- sd->data[6] = 0x80; /* Supported group 4 functions */
- sd->data[7] = 0x01;
- sd->data[8] = 0x80; /* Supported group 3 functions */
- sd->data[9] = 0x01;
- sd->data[10] = 0x80; /* Supported group 2 functions */
- sd->data[11] = 0x43;
- sd->data[12] = 0x80; /* Supported group 1 functions */
- sd->data[13] = 0x03;
- for (i = 0; i < 6; i ++) {
- new_func = (arg >> (i * 4)) & 0x0f;
- if (mode && new_func != 0x0f)
- sd->function_group[i] = new_func;
- sd->data[14 + (i >> 1)] = new_func << ((i * 4) & 4);
- }
- memset(&sd->data[17], 0, 47);
- crc = sd_crc16(sd->data, 64);
- sd->data[65] = crc >> 8;
- sd->data[66] = crc & 0xff;
-}
-
-static inline bool sd_wp_addr(SDState *sd, uint64_t addr)
-{
- return test_bit(sd_addr_to_wpnum(addr), sd->wp_groups);
-}
-
-static void sd_lock_command(SDState *sd)
-{
- int erase, lock, clr_pwd, set_pwd, pwd_len;
- erase = !!(sd->data[0] & 0x08);
- lock = sd->data[0] & 0x04;
- clr_pwd = sd->data[0] & 0x02;
- set_pwd = sd->data[0] & 0x01;
-
- if (sd->blk_len > 1)
- pwd_len = sd->data[1];
- else
- pwd_len = 0;
-
- if (erase) {
- if (!(sd->card_status & CARD_IS_LOCKED) || sd->blk_len > 1 ||
- set_pwd || clr_pwd || lock || sd->wp_switch ||
- (sd->csd[14] & 0x20)) {
- sd->card_status |= LOCK_UNLOCK_FAILED;
- return;
- }
- bitmap_zero(sd->wp_groups, sd->wpgrps_size);
- sd->csd[14] &= ~0x10;
- sd->card_status &= ~CARD_IS_LOCKED;
- sd->pwd_len = 0;
- /* Erasing the entire card here! */
- fprintf(stderr, "SD: Card force-erased by CMD42\n");
- return;
- }
-
- if (sd->blk_len < 2 + pwd_len ||
- pwd_len <= sd->pwd_len ||
- pwd_len > sd->pwd_len + 16) {
- sd->card_status |= LOCK_UNLOCK_FAILED;
- return;
- }
-
- if (sd->pwd_len && memcmp(sd->pwd, sd->data + 2, sd->pwd_len)) {
- sd->card_status |= LOCK_UNLOCK_FAILED;
- return;
- }
-
- pwd_len -= sd->pwd_len;
- if ((pwd_len && !set_pwd) ||
- (clr_pwd && (set_pwd || lock)) ||
- (lock && !sd->pwd_len && !set_pwd) ||
- (!set_pwd && !clr_pwd &&
- (((sd->card_status & CARD_IS_LOCKED) && lock) ||
- (!(sd->card_status & CARD_IS_LOCKED) && !lock)))) {
- sd->card_status |= LOCK_UNLOCK_FAILED;
- return;
- }
-
- if (set_pwd) {
- memcpy(sd->pwd, sd->data + 2 + sd->pwd_len, pwd_len);
- sd->pwd_len = pwd_len;
- }
-
- if (clr_pwd) {
- sd->pwd_len = 0;
- }
-
- if (lock)
- sd->card_status |= CARD_IS_LOCKED;
- else
- sd->card_status &= ~CARD_IS_LOCKED;
-}
-
-static sd_rsp_type_t sd_normal_command(SDState *sd,
- SDRequest req)
-{
- uint32_t rca = 0x0000;
- uint64_t addr = (sd->ocr & (1 << 30)) ? (uint64_t) req.arg << 9 : req.arg;
-
- /* Not interpreting this as an app command */
- sd->card_status &= ~APP_CMD;
-
- if (sd_cmd_type[req.cmd & 0x3F] == sd_ac
- || sd_cmd_type[req.cmd & 0x3F] == sd_adtc) {
- rca = req.arg >> 16;
- }
-
- /* CMD23 (set block count) must be immediately followed by CMD18 or CMD25
- * if not, its effects are cancelled */
- if (sd->multi_blk_cnt != 0 && !(req.cmd == 18 || req.cmd == 25)) {
- sd->multi_blk_cnt = 0;
- }
-
- DPRINTF("CMD%d 0x%08x state %d\n", req.cmd, req.arg, sd->state);
- switch (req.cmd) {
- /* Basic commands (Class 0 and Class 1) */
- case 0: /* CMD0: GO_IDLE_STATE */
- switch (sd->state) {
- case sd_inactive_state:
- return sd->spi ? sd_r1 : sd_r0;
-
- default:
- sd->state = sd_idle_state;
- sd_reset(DEVICE(sd));
- return sd->spi ? sd_r1 : sd_r0;
- }
- break;
-
- case 1: /* CMD1: SEND_OP_CMD */
- if (!sd->spi)
- goto bad_cmd;
-
- sd->state = sd_transfer_state;
- return sd_r1;
-
- case 2: /* CMD2: ALL_SEND_CID */
- if (sd->spi)
- goto bad_cmd;
- switch (sd->state) {
- case sd_ready_state:
- sd->state = sd_identification_state;
- return sd_r2_i;
-
- default:
- break;
- }
- break;
-
- case 3: /* CMD3: SEND_RELATIVE_ADDR */
- if (sd->spi)
- goto bad_cmd;
- switch (sd->state) {
- case sd_identification_state:
- case sd_standby_state:
- sd->state = sd_standby_state;
- sd_set_rca(sd);
- return sd_r6;
-
- default:
- break;
- }
- break;
-
- case 4: /* CMD4: SEND_DSR */
- if (sd->spi)
- goto bad_cmd;
- switch (sd->state) {
- case sd_standby_state:
- break;
-
- default:
- break;
- }
- break;
-
- case 5: /* CMD5: reserved for SDIO cards */
- return sd_illegal;
-
- case 6: /* CMD6: SWITCH_FUNCTION */
- if (sd->spi)
- goto bad_cmd;
- switch (sd->mode) {
- case sd_data_transfer_mode:
- sd_function_switch(sd, req.arg);
- sd->state = sd_sendingdata_state;
- sd->data_start = 0;
- sd->data_offset = 0;
- return sd_r1;
-
- default:
- break;
- }
- break;
-
- case 7: /* CMD7: SELECT/DESELECT_CARD */
- if (sd->spi)
- goto bad_cmd;
- switch (sd->state) {
- case sd_standby_state:
- if (sd->rca != rca)
- return sd_r0;
-
- sd->state = sd_transfer_state;
- return sd_r1b;
-
- case sd_transfer_state:
- case sd_sendingdata_state:
- if (sd->rca == rca)
- break;
-
- sd->state = sd_standby_state;
- return sd_r1b;
-
- case sd_disconnect_state:
- if (sd->rca != rca)
- return sd_r0;
-
- sd->state = sd_programming_state;
- return sd_r1b;
-
- case sd_programming_state:
- if (sd->rca == rca)
- break;
-
- sd->state = sd_disconnect_state;
- return sd_r1b;
-
- default:
- break;
- }
- break;
-
- case 8: /* CMD8: SEND_IF_COND */
- /* Physical Layer Specification Version 2.00 command */
- switch (sd->state) {
- case sd_idle_state:
- sd->vhs = 0;
-
- /* No response if not exactly one VHS bit is set. */
- if (!(req.arg >> 8) || (req.arg >> (ctz32(req.arg & ~0xff) + 1))) {
- return sd->spi ? sd_r7 : sd_r0;
- }
-
- /* Accept. */
- sd->vhs = req.arg;
- return sd_r7;
-
- default:
- break;
- }
- break;
-
- case 9: /* CMD9: SEND_CSD */
- switch (sd->state) {
- case sd_standby_state:
- if (sd->rca != rca)
- return sd_r0;
-
- return sd_r2_s;
-
- case sd_transfer_state:
- if (!sd->spi)
- break;
- sd->state = sd_sendingdata_state;
- memcpy(sd->data, sd->csd, 16);
- sd->data_start = addr;
- sd->data_offset = 0;
- return sd_r1;
-
- default:
- break;
- }
- break;
-
- case 10: /* CMD10: SEND_CID */
- switch (sd->state) {
- case sd_standby_state:
- if (sd->rca != rca)
- return sd_r0;
-
- return sd_r2_i;
-
- case sd_transfer_state:
- if (!sd->spi)
- break;
- sd->state = sd_sendingdata_state;
- memcpy(sd->data, sd->cid, 16);
- sd->data_start = addr;
- sd->data_offset = 0;
- return sd_r1;
-
- default:
- break;
- }
- break;
-
- case 11: /* CMD11: READ_DAT_UNTIL_STOP */
- if (sd->spi)
- goto bad_cmd;
- switch (sd->state) {
- case sd_transfer_state:
- sd->state = sd_sendingdata_state;
- sd->data_start = req.arg;
- sd->data_offset = 0;
-
- if (sd->data_start + sd->blk_len > sd->size)
- sd->card_status |= ADDRESS_ERROR;
- return sd_r0;
-
- default:
- break;
- }
- break;
-
- case 12: /* CMD12: STOP_TRANSMISSION */
- switch (sd->state) {
- case sd_sendingdata_state:
- sd->state = sd_transfer_state;
- return sd_r1b;
-
- case sd_receivingdata_state:
- sd->state = sd_programming_state;
- /* Bzzzzzzztt .... Operation complete. */
- sd->state = sd_transfer_state;
- return sd_r1b;
-
- default:
- break;
- }
- break;
-
- case 13: /* CMD13: SEND_STATUS */
- switch (sd->mode) {
- case sd_data_transfer_mode:
- if (sd->rca != rca)
- return sd_r0;
-
- return sd_r1;
-
- default:
- break;
- }
- break;
-
- case 15: /* CMD15: GO_INACTIVE_STATE */
- if (sd->spi)
- goto bad_cmd;
- switch (sd->mode) {
- case sd_data_transfer_mode:
- if (sd->rca != rca)
- return sd_r0;
-
- sd->state = sd_inactive_state;
- return sd_r0;
-
- default:
- break;
- }
- break;
-
- /* Block read commands (Classs 2) */
- case 16: /* CMD16: SET_BLOCKLEN */
- switch (sd->state) {
- case sd_transfer_state:
- if (req.arg > (1 << HWBLOCK_SHIFT))
- sd->card_status |= BLOCK_LEN_ERROR;
- else
- sd->blk_len = req.arg;
-
- return sd_r1;
-
- default:
- break;
- }
- break;
-
- case 17: /* CMD17: READ_SINGLE_BLOCK */
- switch (sd->state) {
- case sd_transfer_state:
- sd->state = sd_sendingdata_state;
- sd->data_start = addr;
- sd->data_offset = 0;
-
- if (sd->data_start + sd->blk_len > sd->size)
- sd->card_status |= ADDRESS_ERROR;
- return sd_r1;
-
- default:
- break;
- }
- break;
-
- case 18: /* CMD18: READ_MULTIPLE_BLOCK */
- switch (sd->state) {
- case sd_transfer_state:
- sd->state = sd_sendingdata_state;
- sd->data_start = addr;
- sd->data_offset = 0;
-
- if (sd->data_start + sd->blk_len > sd->size)
- sd->card_status |= ADDRESS_ERROR;
- return sd_r1;
-
- default:
- break;
- }
- break;
-
- case 23: /* CMD23: SET_BLOCK_COUNT */
- switch (sd->state) {
- case sd_transfer_state:
- sd->multi_blk_cnt = req.arg;
- return sd_r1;
-
- default:
- break;
- }
- break;
-
- /* Block write commands (Class 4) */
- case 24: /* CMD24: WRITE_SINGLE_BLOCK */
- if (sd->spi)
- goto unimplemented_cmd;
- switch (sd->state) {
- case sd_transfer_state:
- /* Writing in SPI mode not implemented. */
- if (sd->spi)
- break;
- sd->state = sd_receivingdata_state;
- sd->data_start = addr;
- sd->data_offset = 0;
- sd->blk_written = 0;
-
- if (sd->data_start + sd->blk_len > sd->size)
- sd->card_status |= ADDRESS_ERROR;
- if (sd_wp_addr(sd, sd->data_start))
- sd->card_status |= WP_VIOLATION;
- if (sd->csd[14] & 0x30)
- sd->card_status |= WP_VIOLATION;
- return sd_r1;
-
- default:
- break;
- }
- break;
-
- case 25: /* CMD25: WRITE_MULTIPLE_BLOCK */
- if (sd->spi)
- goto unimplemented_cmd;
- switch (sd->state) {
- case sd_transfer_state:
- /* Writing in SPI mode not implemented. */
- if (sd->spi)
- break;
- sd->state = sd_receivingdata_state;
- sd->data_start = addr;
- sd->data_offset = 0;
- sd->blk_written = 0;
-
- if (sd->data_start + sd->blk_len > sd->size)
- sd->card_status |= ADDRESS_ERROR;
- if (sd_wp_addr(sd, sd->data_start))
- sd->card_status |= WP_VIOLATION;
- if (sd->csd[14] & 0x30)
- sd->card_status |= WP_VIOLATION;
- return sd_r1;
-
- default:
- break;
- }
- break;
-
- case 26: /* CMD26: PROGRAM_CID */
- if (sd->spi)
- goto bad_cmd;
- switch (sd->state) {
- case sd_transfer_state:
- sd->state = sd_receivingdata_state;
- sd->data_start = 0;
- sd->data_offset = 0;
- return sd_r1;
-
- default:
- break;
- }
- break;
-
- case 27: /* CMD27: PROGRAM_CSD */
- if (sd->spi)
- goto unimplemented_cmd;
- switch (sd->state) {
- case sd_transfer_state:
- sd->state = sd_receivingdata_state;
- sd->data_start = 0;
- sd->data_offset = 0;
- return sd_r1;
-
- default:
- break;
- }
- break;
-
- /* Write protection (Class 6) */
- case 28: /* CMD28: SET_WRITE_PROT */
- switch (sd->state) {
- case sd_transfer_state:
- if (addr >= sd->size) {
- sd->card_status |= ADDRESS_ERROR;
- return sd_r1b;
- }
-
- sd->state = sd_programming_state;
- set_bit(sd_addr_to_wpnum(addr), sd->wp_groups);
- /* Bzzzzzzztt .... Operation complete. */
- sd->state = sd_transfer_state;
- return sd_r1b;
-
- default:
- break;
- }
- break;
-
- case 29: /* CMD29: CLR_WRITE_PROT */
- switch (sd->state) {
- case sd_transfer_state:
- if (addr >= sd->size) {
- sd->card_status |= ADDRESS_ERROR;
- return sd_r1b;
- }
-
- sd->state = sd_programming_state;
- clear_bit(sd_addr_to_wpnum(addr), sd->wp_groups);
- /* Bzzzzzzztt .... Operation complete. */
- sd->state = sd_transfer_state;
- return sd_r1b;
-
- default:
- break;
- }
- break;
-
- case 30: /* CMD30: SEND_WRITE_PROT */
- switch (sd->state) {
- case sd_transfer_state:
- sd->state = sd_sendingdata_state;
- *(uint32_t *) sd->data = sd_wpbits(sd, req.arg);
- sd->data_start = addr;
- sd->data_offset = 0;
- return sd_r1b;
-
- default:
- break;
- }
- break;
-
- /* Erase commands (Class 5) */
- case 32: /* CMD32: ERASE_WR_BLK_START */
- switch (sd->state) {
- case sd_transfer_state:
- sd->erase_start = req.arg;
- return sd_r1;
-
- default:
- break;
- }
- break;
-
- case 33: /* CMD33: ERASE_WR_BLK_END */
- switch (sd->state) {
- case sd_transfer_state:
- sd->erase_end = req.arg;
- return sd_r1;
-
- default:
- break;
- }
- break;
-
- case 38: /* CMD38: ERASE */
- switch (sd->state) {
- case sd_transfer_state:
- if (sd->csd[14] & 0x30) {
- sd->card_status |= WP_VIOLATION;
- return sd_r1b;
- }
-
- sd->state = sd_programming_state;
- sd_erase(sd);
- /* Bzzzzzzztt .... Operation complete. */
- sd->state = sd_transfer_state;
- return sd_r1b;
-
- default:
- break;
- }
- break;
-
- /* Lock card commands (Class 7) */
- case 42: /* CMD42: LOCK_UNLOCK */
- if (sd->spi)
- goto unimplemented_cmd;
- switch (sd->state) {
- case sd_transfer_state:
- sd->state = sd_receivingdata_state;
- sd->data_start = 0;
- sd->data_offset = 0;
- return sd_r1;
-
- default:
- break;
- }
- break;
-
- case 52:
- case 53:
- /* CMD52, CMD53: reserved for SDIO cards
- * (see the SDIO Simplified Specification V2.0)
- * Handle as illegal command but do not complain
- * on stderr, as some OSes may use these in their
- * probing for presence of an SDIO card.
- */
- return sd_illegal;
-
- /* Application specific commands (Class 8) */
- case 55: /* CMD55: APP_CMD */
- if (sd->rca != rca)
- return sd_r0;
-
- sd->expecting_acmd = true;
- sd->card_status |= APP_CMD;
- return sd_r1;
-
- case 56: /* CMD56: GEN_CMD */
- fprintf(stderr, "SD: GEN_CMD 0x%08x\n", req.arg);
-
- switch (sd->state) {
- case sd_transfer_state:
- sd->data_offset = 0;
- if (req.arg & 1)
- sd->state = sd_sendingdata_state;
- else
- sd->state = sd_receivingdata_state;
- return sd_r1;
-
- default:
- break;
- }
- break;
-
- default:
- bad_cmd:
- qemu_log_mask(LOG_GUEST_ERROR, "SD: Unknown CMD%i\n", req.cmd);
- return sd_illegal;
-
- unimplemented_cmd:
- /* Commands that are recognised but not yet implemented in SPI mode. */
- qemu_log_mask(LOG_UNIMP, "SD: CMD%i not implemented in SPI mode\n",
- req.cmd);
- return sd_illegal;
- }
-
- qemu_log_mask(LOG_GUEST_ERROR, "SD: CMD%i in a wrong state\n", req.cmd);
- return sd_illegal;
-}
-
-static sd_rsp_type_t sd_app_command(SDState *sd,
- SDRequest req)
-{
- DPRINTF("ACMD%d 0x%08x\n", req.cmd, req.arg);
- sd->card_status |= APP_CMD;
- switch (req.cmd) {
- case 6: /* ACMD6: SET_BUS_WIDTH */
- switch (sd->state) {
- case sd_transfer_state:
- sd->sd_status[0] &= 0x3f;
- sd->sd_status[0] |= (req.arg & 0x03) << 6;
- return sd_r1;
-
- default:
- break;
- }
- break;
-
- case 13: /* ACMD13: SD_STATUS */
- switch (sd->state) {
- case sd_transfer_state:
- sd->state = sd_sendingdata_state;
- sd->data_start = 0;
- sd->data_offset = 0;
- return sd_r1;
-
- default:
- break;
- }
- break;
-
- case 22: /* ACMD22: SEND_NUM_WR_BLOCKS */
- switch (sd->state) {
- case sd_transfer_state:
- *(uint32_t *) sd->data = sd->blk_written;
-
- sd->state = sd_sendingdata_state;
- sd->data_start = 0;
- sd->data_offset = 0;
- return sd_r1;
-
- default:
- break;
- }
- break;
-
- case 23: /* ACMD23: SET_WR_BLK_ERASE_COUNT */
- switch (sd->state) {
- case sd_transfer_state:
- return sd_r1;
-
- default:
- break;
- }
- break;
-
- case 41: /* ACMD41: SD_APP_OP_COND */
- if (sd->spi) {
- /* SEND_OP_CMD */
- sd->state = sd_transfer_state;
- return sd_r1;
- }
- switch (sd->state) {
- case sd_idle_state:
- /* If it's the first ACMD41 since reset, we need to decide
- * whether to power up. If this is not an enquiry ACMD41,
- * we immediately report power on and proceed below to the
- * ready state, but if it is, we set a timer to model a
- * delay for power up. This works around a bug in EDK2
- * UEFI, which sends an initial enquiry ACMD41, but
- * assumes that the card is in ready state as soon as it
- * sees the power up bit set. */
- if (!(sd->ocr & OCR_POWER_UP)) {
- if ((req.arg & ACMD41_ENQUIRY_MASK) != 0) {
- timer_del(sd->ocr_power_timer);
- sd_ocr_powerup(sd);
- } else if (!timer_pending(sd->ocr_power_timer)) {
- timer_mod_ns(sd->ocr_power_timer,
- (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)
- + OCR_POWER_DELAY_NS));
- }
- }
-
- /* We accept any voltage. 10000 V is nothing.
- *
- * Once we're powered up, we advance straight to ready state
- * unless it's an enquiry ACMD41 (bits 23:0 == 0).
- */
- if (req.arg & ACMD41_ENQUIRY_MASK) {
- sd->state = sd_ready_state;
- }
-
- return sd_r3;
-
- default:
- break;
- }
- break;
-
- case 42: /* ACMD42: SET_CLR_CARD_DETECT */
- switch (sd->state) {
- case sd_transfer_state:
- /* Bringing in the 50KOhm pull-up resistor... Done. */
- return sd_r1;
-
- default:
- break;
- }
- break;
-
- case 51: /* ACMD51: SEND_SCR */
- switch (sd->state) {
- case sd_transfer_state:
- sd->state = sd_sendingdata_state;
- sd->data_start = 0;
- sd->data_offset = 0;
- return sd_r1;
-
- default:
- break;
- }
- break;
-
- default:
- /* Fall back to standard commands. */
- return sd_normal_command(sd, req);
- }
-
- qemu_log_mask(LOG_GUEST_ERROR, "SD: ACMD%i in a wrong state\n", req.cmd);
- return sd_illegal;
-}
-
-static int cmd_valid_while_locked(SDState *sd, SDRequest *req)
-{
- /* Valid commands in locked state:
- * basic class (0)
- * lock card class (7)
- * CMD16
- * implicitly, the ACMD prefix CMD55
- * ACMD41 and ACMD42
- * Anything else provokes an "illegal command" response.
- */
- if (sd->expecting_acmd) {
- return req->cmd == 41 || req->cmd == 42;
- }
- if (req->cmd == 16 || req->cmd == 55) {
- return 1;
- }
- return sd_cmd_class[req->cmd & 0x3F] == 0
- || sd_cmd_class[req->cmd & 0x3F] == 7;
-}
-
-int sd_do_command(SDState *sd, SDRequest *req,
- uint8_t *response) {
- int last_state;
- sd_rsp_type_t rtype;
- int rsplen;
-
- if (!sd->blk || !blk_is_inserted(sd->blk) || !sd->enable) {
- return 0;
- }
-
- if (sd_req_crc_validate(req)) {
- sd->card_status |= COM_CRC_ERROR;
- rtype = sd_illegal;
- goto send_response;
- }
-
- if (sd->card_status & CARD_IS_LOCKED) {
- if (!cmd_valid_while_locked(sd, req)) {
- sd->card_status |= ILLEGAL_COMMAND;
- sd->expecting_acmd = false;
- qemu_log_mask(LOG_GUEST_ERROR, "SD: Card is locked\n");
- rtype = sd_illegal;
- goto send_response;
- }
- }
-
- last_state = sd->state;
- sd_set_mode(sd);
-
- if (sd->expecting_acmd) {
- sd->expecting_acmd = false;
- rtype = sd_app_command(sd, *req);
- } else {
- rtype = sd_normal_command(sd, *req);
- }
-
- if (rtype == sd_illegal) {
- sd->card_status |= ILLEGAL_COMMAND;
- } else {
- /* Valid command, we can update the 'state before command' bits.
- * (Do this now so they appear in r1 responses.)
- */
- sd->current_cmd = req->cmd;
- sd->card_status &= ~CURRENT_STATE;
- sd->card_status |= (last_state << 9);
- }
-
-send_response:
- switch (rtype) {
- case sd_r1:
- case sd_r1b:
- sd_response_r1_make(sd, response);
- rsplen = 4;
- break;
-
- case sd_r2_i:
- memcpy(response, sd->cid, sizeof(sd->cid));
- rsplen = 16;
- break;
-
- case sd_r2_s:
- memcpy(response, sd->csd, sizeof(sd->csd));
- rsplen = 16;
- break;
-
- case sd_r3:
- sd_response_r3_make(sd, response);
- rsplen = 4;
- break;
-
- case sd_r6:
- sd_response_r6_make(sd, response);
- rsplen = 4;
- break;
-
- case sd_r7:
- sd_response_r7_make(sd, response);
- rsplen = 4;
- break;
-
- case sd_r0:
- case sd_illegal:
- default:
- rsplen = 0;
- break;
- }
-
- if (rtype != sd_illegal) {
- /* Clear the "clear on valid command" status bits now we've
- * sent any response
- */
- sd->card_status &= ~CARD_STATUS_B;
- }
-
-#ifdef DEBUG_SD
- if (rsplen) {
- int i;
- DPRINTF("Response:");
- for (i = 0; i < rsplen; i++)
- fprintf(stderr, " %02x", response[i]);
- fprintf(stderr, " state %d\n", sd->state);
- } else {
- DPRINTF("No response %d\n", sd->state);
- }
-#endif
-
- return rsplen;
-}
-
-static void sd_blk_read(SDState *sd, uint64_t addr, uint32_t len)
-{
- uint64_t end = addr + len;
-
- DPRINTF("sd_blk_read: addr = 0x%08llx, len = %d\n",
- (unsigned long long) addr, len);
- if (!sd->blk || blk_read(sd->blk, addr >> 9, sd->buf, 1) < 0) {
- fprintf(stderr, "sd_blk_read: read error on host side\n");
- return;
- }
-
- if (end > (addr & ~511) + 512) {
- memcpy(sd->data, sd->buf + (addr & 511), 512 - (addr & 511));
-
- if (blk_read(sd->blk, end >> 9, sd->buf, 1) < 0) {
- fprintf(stderr, "sd_blk_read: read error on host side\n");
- return;
- }
- memcpy(sd->data + 512 - (addr & 511), sd->buf, end & 511);
- } else
- memcpy(sd->data, sd->buf + (addr & 511), len);
-}
-
-static void sd_blk_write(SDState *sd, uint64_t addr, uint32_t len)
-{
- uint64_t end = addr + len;
-
- if ((addr & 511) || len < 512)
- if (!sd->blk || blk_read(sd->blk, addr >> 9, sd->buf, 1) < 0) {
- fprintf(stderr, "sd_blk_write: read error on host side\n");
- return;
- }
-
- if (end > (addr & ~511) + 512) {
- memcpy(sd->buf + (addr & 511), sd->data, 512 - (addr & 511));
- if (blk_write(sd->blk, addr >> 9, sd->buf, 1) < 0) {
- fprintf(stderr, "sd_blk_write: write error on host side\n");
- return;
- }
-
- if (blk_read(sd->blk, end >> 9, sd->buf, 1) < 0) {
- fprintf(stderr, "sd_blk_write: read error on host side\n");
- return;
- }
- memcpy(sd->buf, sd->data + 512 - (addr & 511), end & 511);
- if (blk_write(sd->blk, end >> 9, sd->buf, 1) < 0) {
- fprintf(stderr, "sd_blk_write: write error on host side\n");
- }
- } else {
- memcpy(sd->buf + (addr & 511), sd->data, len);
- if (!sd->blk || blk_write(sd->blk, addr >> 9, sd->buf, 1) < 0) {
- fprintf(stderr, "sd_blk_write: write error on host side\n");
- }
- }
-}
-
-#define BLK_READ_BLOCK(a, len) sd_blk_read(sd, a, len)
-#define BLK_WRITE_BLOCK(a, len) sd_blk_write(sd, a, len)
-#define APP_READ_BLOCK(a, len) memset(sd->data, 0xec, len)
-#define APP_WRITE_BLOCK(a, len)
-
-void sd_write_data(SDState *sd, uint8_t value)
-{
- int i;
-
- if (!sd->blk || !blk_is_inserted(sd->blk) || !sd->enable)
- return;
-
- if (sd->state != sd_receivingdata_state) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "sd_write_data: not in Receiving-Data state\n");
- return;
- }
-
- if (sd->card_status & (ADDRESS_ERROR | WP_VIOLATION))
- return;
-
- switch (sd->current_cmd) {
- case 24: /* CMD24: WRITE_SINGLE_BLOCK */
- sd->data[sd->data_offset ++] = value;
- if (sd->data_offset >= sd->blk_len) {
- /* TODO: Check CRC before committing */
- sd->state = sd_programming_state;
- BLK_WRITE_BLOCK(sd->data_start, sd->data_offset);
- sd->blk_written ++;
- sd->csd[14] |= 0x40;
- /* Bzzzzzzztt .... Operation complete. */
- sd->state = sd_transfer_state;
- }
- break;
-
- case 25: /* CMD25: WRITE_MULTIPLE_BLOCK */
- if (sd->data_offset == 0) {
- /* Start of the block - let's check the address is valid */
- if (sd->data_start + sd->blk_len > sd->size) {
- sd->card_status |= ADDRESS_ERROR;
- break;
- }
- if (sd_wp_addr(sd, sd->data_start)) {
- sd->card_status |= WP_VIOLATION;
- break;
- }
- }
- sd->data[sd->data_offset++] = value;
- if (sd->data_offset >= sd->blk_len) {
- /* TODO: Check CRC before committing */
- sd->state = sd_programming_state;
- BLK_WRITE_BLOCK(sd->data_start, sd->data_offset);
- sd->blk_written++;
- sd->data_start += sd->blk_len;
- sd->data_offset = 0;
- sd->csd[14] |= 0x40;
-
- /* Bzzzzzzztt .... Operation complete. */
- if (sd->multi_blk_cnt != 0) {
- if (--sd->multi_blk_cnt == 0) {
- /* Stop! */
- sd->state = sd_transfer_state;
- break;
- }
- }
-
- sd->state = sd_receivingdata_state;
- }
- break;
-
- case 26: /* CMD26: PROGRAM_CID */
- sd->data[sd->data_offset ++] = value;
- if (sd->data_offset >= sizeof(sd->cid)) {
- /* TODO: Check CRC before committing */
- sd->state = sd_programming_state;
- for (i = 0; i < sizeof(sd->cid); i ++)
- if ((sd->cid[i] | 0x00) != sd->data[i])
- sd->card_status |= CID_CSD_OVERWRITE;
-
- if (!(sd->card_status & CID_CSD_OVERWRITE))
- for (i = 0; i < sizeof(sd->cid); i ++) {
- sd->cid[i] |= 0x00;
- sd->cid[i] &= sd->data[i];
- }
- /* Bzzzzzzztt .... Operation complete. */
- sd->state = sd_transfer_state;
- }
- break;
-
- case 27: /* CMD27: PROGRAM_CSD */
- sd->data[sd->data_offset ++] = value;
- if (sd->data_offset >= sizeof(sd->csd)) {
- /* TODO: Check CRC before committing */
- sd->state = sd_programming_state;
- for (i = 0; i < sizeof(sd->csd); i ++)
- if ((sd->csd[i] | sd_csd_rw_mask[i]) !=
- (sd->data[i] | sd_csd_rw_mask[i]))
- sd->card_status |= CID_CSD_OVERWRITE;
-
- /* Copy flag (OTP) & Permanent write protect */
- if (sd->csd[14] & ~sd->data[14] & 0x60)
- sd->card_status |= CID_CSD_OVERWRITE;
-
- if (!(sd->card_status & CID_CSD_OVERWRITE))
- for (i = 0; i < sizeof(sd->csd); i ++) {
- sd->csd[i] |= sd_csd_rw_mask[i];
- sd->csd[i] &= sd->data[i];
- }
- /* Bzzzzzzztt .... Operation complete. */
- sd->state = sd_transfer_state;
- }
- break;
-
- case 42: /* CMD42: LOCK_UNLOCK */
- sd->data[sd->data_offset ++] = value;
- if (sd->data_offset >= sd->blk_len) {
- /* TODO: Check CRC before committing */
- sd->state = sd_programming_state;
- sd_lock_command(sd);
- /* Bzzzzzzztt .... Operation complete. */
- sd->state = sd_transfer_state;
- }
- break;
-
- case 56: /* CMD56: GEN_CMD */
- sd->data[sd->data_offset ++] = value;
- if (sd->data_offset >= sd->blk_len) {
- APP_WRITE_BLOCK(sd->data_start, sd->data_offset);
- sd->state = sd_transfer_state;
- }
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "sd_write_data: unknown command\n");
- break;
- }
-}
-
-uint8_t sd_read_data(SDState *sd)
-{
- /* TODO: Append CRCs */
- uint8_t ret;
- int io_len;
-
- if (!sd->blk || !blk_is_inserted(sd->blk) || !sd->enable)
- return 0x00;
-
- if (sd->state != sd_sendingdata_state) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "sd_read_data: not in Sending-Data state\n");
- return 0x00;
- }
-
- if (sd->card_status & (ADDRESS_ERROR | WP_VIOLATION))
- return 0x00;
-
- io_len = (sd->ocr & (1 << 30)) ? 512 : sd->blk_len;
-
- switch (sd->current_cmd) {
- case 6: /* CMD6: SWITCH_FUNCTION */
- ret = sd->data[sd->data_offset ++];
-
- if (sd->data_offset >= 64)
- sd->state = sd_transfer_state;
- break;
-
- case 9: /* CMD9: SEND_CSD */
- case 10: /* CMD10: SEND_CID */
- ret = sd->data[sd->data_offset ++];
-
- if (sd->data_offset >= 16)
- sd->state = sd_transfer_state;
- break;
-
- case 11: /* CMD11: READ_DAT_UNTIL_STOP */
- if (sd->data_offset == 0)
- BLK_READ_BLOCK(sd->data_start, io_len);
- ret = sd->data[sd->data_offset ++];
-
- if (sd->data_offset >= io_len) {
- sd->data_start += io_len;
- sd->data_offset = 0;
- if (sd->data_start + io_len > sd->size) {
- sd->card_status |= ADDRESS_ERROR;
- break;
- }
- }
- break;
-
- case 13: /* ACMD13: SD_STATUS */
- ret = sd->sd_status[sd->data_offset ++];
-
- if (sd->data_offset >= sizeof(sd->sd_status))
- sd->state = sd_transfer_state;
- break;
-
- case 17: /* CMD17: READ_SINGLE_BLOCK */
- if (sd->data_offset == 0)
- BLK_READ_BLOCK(sd->data_start, io_len);
- ret = sd->data[sd->data_offset ++];
-
- if (sd->data_offset >= io_len)
- sd->state = sd_transfer_state;
- break;
-
- case 18: /* CMD18: READ_MULTIPLE_BLOCK */
- if (sd->data_offset == 0)
- BLK_READ_BLOCK(sd->data_start, io_len);
- ret = sd->data[sd->data_offset ++];
-
- if (sd->data_offset >= io_len) {
- sd->data_start += io_len;
- sd->data_offset = 0;
-
- if (sd->multi_blk_cnt != 0) {
- if (--sd->multi_blk_cnt == 0) {
- /* Stop! */
- sd->state = sd_transfer_state;
- break;
- }
- }
-
- if (sd->data_start + io_len > sd->size) {
- sd->card_status |= ADDRESS_ERROR;
- break;
- }
- }
- break;
-
- case 22: /* ACMD22: SEND_NUM_WR_BLOCKS */
- ret = sd->data[sd->data_offset ++];
-
- if (sd->data_offset >= 4)
- sd->state = sd_transfer_state;
- break;
-
- case 30: /* CMD30: SEND_WRITE_PROT */
- ret = sd->data[sd->data_offset ++];
-
- if (sd->data_offset >= 4)
- sd->state = sd_transfer_state;
- break;
-
- case 51: /* ACMD51: SEND_SCR */
- ret = sd->scr[sd->data_offset ++];
-
- if (sd->data_offset >= sizeof(sd->scr))
- sd->state = sd_transfer_state;
- break;
-
- case 56: /* CMD56: GEN_CMD */
- if (sd->data_offset == 0)
- APP_READ_BLOCK(sd->data_start, sd->blk_len);
- ret = sd->data[sd->data_offset ++];
-
- if (sd->data_offset >= sd->blk_len)
- sd->state = sd_transfer_state;
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "sd_read_data: unknown command\n");
- return 0x00;
- }
-
- return ret;
-}
-
-bool sd_data_ready(SDState *sd)
-{
- return sd->state == sd_sendingdata_state;
-}
-
-void sd_enable(SDState *sd, bool enable)
-{
- sd->enable = enable;
-}
-
-static void sd_instance_init(Object *obj)
-{
- SDState *sd = SD_CARD(obj);
-
- sd->enable = true;
- sd->ocr_power_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sd_ocr_powerup, sd);
-}
-
-static void sd_realize(DeviceState *dev, Error **errp)
-{
- SDState *sd = SD_CARD(dev);
-
- if (sd->blk && blk_is_read_only(sd->blk)) {
- error_setg(errp, "Cannot use read-only drive as SD card");
- return;
- }
-
- sd->buf = blk_blockalign(sd->blk, 512);
-
- if (sd->blk) {
- blk_set_dev_ops(sd->blk, &sd_block_ops, sd);
- }
-}
-
-static Property sd_properties[] = {
- DEFINE_PROP_DRIVE("drive", SDState, blk),
- /* We do not model the chip select pin, so allow the board to select
- * whether card should be in SSI or MMC/SD mode. It is also up to the
- * board to ensure that ssi transfers only occur when the chip select
- * is asserted. */
- DEFINE_PROP_BOOL("spi", SDState, spi, false),
- DEFINE_PROP_END_OF_LIST()
-};
-
-static void sd_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SDCardClass *sc = SD_CARD_CLASS(klass);
-
- dc->realize = sd_realize;
- dc->props = sd_properties;
- dc->vmsd = &sd_vmstate;
- dc->reset = sd_reset;
- dc->bus_type = TYPE_SD_BUS;
-
- sc->do_command = sd_do_command;
- sc->write_data = sd_write_data;
- sc->read_data = sd_read_data;
- sc->data_ready = sd_data_ready;
- sc->enable = sd_enable;
- sc->get_inserted = sd_get_inserted;
- sc->get_readonly = sd_get_readonly;
-}
-
-static const TypeInfo sd_info = {
- .name = TYPE_SD_CARD,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(SDState),
- .class_size = sizeof(SDCardClass),
- .class_init = sd_class_init,
- .instance_init = sd_instance_init,
-};
-
-static void sd_register_types(void)
-{
- type_register_static(&sd_info);
-}
-
-type_init(sd_register_types)
diff --git a/qemu/hw/sd/sdhci-internal.h b/qemu/hw/sd/sdhci-internal.h
deleted file mode 100644
index 161177cf3..000000000
--- a/qemu/hw/sd/sdhci-internal.h
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * SD Association Host Standard Specification v2.0 controller emulation
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- * Mitsyanko Igor <i.mitsyanko@samsung.com>
- * Peter A.G. Crosthwaite <peter.crosthwaite@petalogix.com>
- *
- * Based on MMC controller for Samsung S5PC1xx-based board emulation
- * by Alexey Merkulov and Vladimir Monakhov.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#ifndef SDHCI_INTERNAL_H
-#define SDHCI_INTERNAL_H
-
-#include "hw/sd/sdhci.h"
-
-/* R/W SDMA System Address register 0x0 */
-#define SDHC_SYSAD 0x00
-
-/* R/W Host DMA Buffer Boundary and Transfer Block Size Register 0x0 */
-#define SDHC_BLKSIZE 0x04
-
-/* R/W Blocks count for current transfer 0x0 */
-#define SDHC_BLKCNT 0x06
-
-/* R/W Command Argument Register 0x0 */
-#define SDHC_ARGUMENT 0x08
-
-/* R/W Transfer Mode Setting Register 0x0 */
-#define SDHC_TRNMOD 0x0C
-#define SDHC_TRNS_DMA 0x0001
-#define SDHC_TRNS_BLK_CNT_EN 0x0002
-#define SDHC_TRNS_ACMD12 0x0004
-#define SDHC_TRNS_READ 0x0010
-#define SDHC_TRNS_MULTI 0x0020
-
-/* R/W Command Register 0x0 */
-#define SDHC_CMDREG 0x0E
-#define SDHC_CMD_RSP_WITH_BUSY (3 << 0)
-#define SDHC_CMD_DATA_PRESENT (1 << 5)
-#define SDHC_CMD_SUSPEND (1 << 6)
-#define SDHC_CMD_RESUME (1 << 7)
-#define SDHC_CMD_ABORT ((1 << 6)|(1 << 7))
-#define SDHC_CMD_TYPE_MASK ((1 << 6)|(1 << 7))
-#define SDHC_COMMAND_TYPE(x) ((x) & SDHC_CMD_TYPE_MASK)
-
-/* ROC Response Register 0 0x0 */
-#define SDHC_RSPREG0 0x10
-/* ROC Response Register 1 0x0 */
-#define SDHC_RSPREG1 0x14
-/* ROC Response Register 2 0x0 */
-#define SDHC_RSPREG2 0x18
-/* ROC Response Register 3 0x0 */
-#define SDHC_RSPREG3 0x1C
-
-/* R/W Buffer Data Register 0x0 */
-#define SDHC_BDATA 0x20
-
-/* R/ROC Present State Register 0x000A0000 */
-#define SDHC_PRNSTS 0x24
-#define SDHC_CMD_INHIBIT 0x00000001
-#define SDHC_DATA_INHIBIT 0x00000002
-#define SDHC_DAT_LINE_ACTIVE 0x00000004
-#define SDHC_DOING_WRITE 0x00000100
-#define SDHC_DOING_READ 0x00000200
-#define SDHC_SPACE_AVAILABLE 0x00000400
-#define SDHC_DATA_AVAILABLE 0x00000800
-#define SDHC_CARD_PRESENT 0x00010000
-#define SDHC_CARD_DETECT 0x00040000
-#define SDHC_WRITE_PROTECT 0x00080000
-#define TRANSFERRING_DATA(x) \
- ((x) & (SDHC_DOING_READ | SDHC_DOING_WRITE))
-
-/* R/W Host control Register 0x0 */
-#define SDHC_HOSTCTL 0x28
-#define SDHC_CTRL_DMA_CHECK_MASK 0x18
-#define SDHC_CTRL_SDMA 0x00
-#define SDHC_CTRL_ADMA1_32 0x08
-#define SDHC_CTRL_ADMA2_32 0x10
-#define SDHC_CTRL_ADMA2_64 0x18
-#define SDHC_DMA_TYPE(x) ((x) & SDHC_CTRL_DMA_CHECK_MASK)
-
-/* R/W Power Control Register 0x0 */
-#define SDHC_PWRCON 0x29
-#define SDHC_POWER_ON (1 << 0)
-
-/* R/W Block Gap Control Register 0x0 */
-#define SDHC_BLKGAP 0x2A
-#define SDHC_STOP_AT_GAP_REQ 0x01
-#define SDHC_CONTINUE_REQ 0x02
-
-/* R/W WakeUp Control Register 0x0 */
-#define SDHC_WAKCON 0x2B
-#define SDHC_WKUP_ON_INS (1 << 1)
-#define SDHC_WKUP_ON_RMV (1 << 2)
-
-/* CLKCON */
-#define SDHC_CLKCON 0x2C
-#define SDHC_CLOCK_INT_STABLE 0x0002
-#define SDHC_CLOCK_INT_EN 0x0001
-#define SDHC_CLOCK_SDCLK_EN (1 << 2)
-#define SDHC_CLOCK_CHK_MASK 0x0007
-#define SDHC_CLOCK_IS_ON(x) \
- (((x) & SDHC_CLOCK_CHK_MASK) == SDHC_CLOCK_CHK_MASK)
-
-/* R/W Timeout Control Register 0x0 */
-#define SDHC_TIMEOUTCON 0x2E
-
-/* R/W Software Reset Register 0x0 */
-#define SDHC_SWRST 0x2F
-#define SDHC_RESET_ALL 0x01
-#define SDHC_RESET_CMD 0x02
-#define SDHC_RESET_DATA 0x04
-
-/* ROC/RW1C Normal Interrupt Status Register 0x0 */
-#define SDHC_NORINTSTS 0x30
-#define SDHC_NIS_ERR 0x8000
-#define SDHC_NIS_CMDCMP 0x0001
-#define SDHC_NIS_TRSCMP 0x0002
-#define SDHC_NIS_BLKGAP 0x0004
-#define SDHC_NIS_DMA 0x0008
-#define SDHC_NIS_WBUFRDY 0x0010
-#define SDHC_NIS_RBUFRDY 0x0020
-#define SDHC_NIS_INSERT 0x0040
-#define SDHC_NIS_REMOVE 0x0080
-#define SDHC_NIS_CARDINT 0x0100
-
-/* ROC/RW1C Error Interrupt Status Register 0x0 */
-#define SDHC_ERRINTSTS 0x32
-#define SDHC_EIS_CMDTIMEOUT 0x0001
-#define SDHC_EIS_BLKGAP 0x0004
-#define SDHC_EIS_CMDIDX 0x0008
-#define SDHC_EIS_CMD12ERR 0x0100
-#define SDHC_EIS_ADMAERR 0x0200
-
-/* R/W Normal Interrupt Status Enable Register 0x0 */
-#define SDHC_NORINTSTSEN 0x34
-#define SDHC_NISEN_CMDCMP 0x0001
-#define SDHC_NISEN_TRSCMP 0x0002
-#define SDHC_NISEN_DMA 0x0008
-#define SDHC_NISEN_WBUFRDY 0x0010
-#define SDHC_NISEN_RBUFRDY 0x0020
-#define SDHC_NISEN_INSERT 0x0040
-#define SDHC_NISEN_REMOVE 0x0080
-#define SDHC_NISEN_CARDINT 0x0100
-
-/* R/W Error Interrupt Status Enable Register 0x0 */
-#define SDHC_ERRINTSTSEN 0x36
-#define SDHC_EISEN_CMDTIMEOUT 0x0001
-#define SDHC_EISEN_BLKGAP 0x0004
-#define SDHC_EISEN_CMDIDX 0x0008
-#define SDHC_EISEN_ADMAERR 0x0200
-
-/* R/W Normal Interrupt Signal Enable Register 0x0 */
-#define SDHC_NORINTSIGEN 0x38
-#define SDHC_NORINTSIG_INSERT (1 << 6)
-#define SDHC_NORINTSIG_REMOVE (1 << 7)
-
-/* R/W Error Interrupt Signal Enable Register 0x0 */
-#define SDHC_ERRINTSIGEN 0x3A
-
-/* ROC Auto CMD12 error status register 0x0 */
-#define SDHC_ACMD12ERRSTS 0x3C
-
-/* HWInit Capabilities Register 0x05E80080 */
-#define SDHC_CAPAREG 0x40
-#define SDHC_CAN_DO_DMA 0x00400000
-#define SDHC_CAN_DO_ADMA2 0x00080000
-#define SDHC_CAN_DO_ADMA1 0x00100000
-#define SDHC_64_BIT_BUS_SUPPORT (1 << 28)
-#define SDHC_CAPAB_BLOCKSIZE(x) (((x) >> 16) & 0x3)
-
-/* HWInit Maximum Current Capabilities Register 0x0 */
-#define SDHC_MAXCURR 0x48
-
-/* W Force Event Auto CMD12 Error Interrupt Register 0x0000 */
-#define SDHC_FEAER 0x50
-/* W Force Event Error Interrupt Register Error Interrupt 0x0000 */
-#define SDHC_FEERR 0x52
-
-/* R/W ADMA Error Status Register 0x00 */
-#define SDHC_ADMAERR 0x54
-#define SDHC_ADMAERR_LENGTH_MISMATCH (1 << 2)
-#define SDHC_ADMAERR_STATE_ST_STOP (0 << 0)
-#define SDHC_ADMAERR_STATE_ST_FDS (1 << 0)
-#define SDHC_ADMAERR_STATE_ST_TFR (3 << 0)
-#define SDHC_ADMAERR_STATE_MASK (3 << 0)
-
-/* R/W ADMA System Address Register 0x00 */
-#define SDHC_ADMASYSADDR 0x58
-#define SDHC_ADMA_ATTR_SET_LEN (1 << 4)
-#define SDHC_ADMA_ATTR_ACT_TRAN (1 << 5)
-#define SDHC_ADMA_ATTR_ACT_LINK (3 << 4)
-#define SDHC_ADMA_ATTR_INT (1 << 2)
-#define SDHC_ADMA_ATTR_END (1 << 1)
-#define SDHC_ADMA_ATTR_VALID (1 << 0)
-#define SDHC_ADMA_ATTR_ACT_MASK ((1 << 4)|(1 << 5))
-
-/* Slot interrupt status */
-#define SDHC_SLOT_INT_STATUS 0xFC
-
-/* HWInit Host Controller Version Register 0x0401 */
-#define SDHC_HCVER 0xFE
-#define SD_HOST_SPECv2_VERS 0x2401
-
-#define SDHC_REGISTERS_MAP_SIZE 0x100
-#define SDHC_INSERTION_DELAY (NANOSECONDS_PER_SECOND)
-#define SDHC_TRANSFER_DELAY 100
-#define SDHC_ADMA_DESCS_PER_DELAY 5
-#define SDHC_CMD_RESPONSE (3 << 0)
-
-enum {
- sdhc_not_stopped = 0, /* normal SDHC state */
- sdhc_gap_read = 1, /* SDHC stopped at block gap during read operation */
- sdhc_gap_write = 2 /* SDHC stopped at block gap during write operation */
-};
-
-extern const VMStateDescription sdhci_vmstate;
-
-#endif
diff --git a/qemu/hw/sd/sdhci.c b/qemu/hw/sd/sdhci.c
deleted file mode 100644
index d28b5871f..000000000
--- a/qemu/hw/sd/sdhci.c
+++ /dev/null
@@ -1,1394 +0,0 @@
-/*
- * SD Association Host Standard Specification v2.0 controller emulation
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- * Mitsyanko Igor <i.mitsyanko@samsung.com>
- * Peter A.G. Crosthwaite <peter.crosthwaite@petalogix.com>
- *
- * Based on MMC controller for Samsung S5PC1xx-based board emulation
- * by Alexey Merkulov and Vladimir Monakhov.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
-#include "sysemu/dma.h"
-#include "qemu/timer.h"
-#include "qemu/bitops.h"
-#include "sdhci-internal.h"
-
-/* host controller debug messages */
-#ifndef SDHC_DEBUG
-#define SDHC_DEBUG 0
-#endif
-
-#define DPRINT_L1(fmt, args...) \
- do { \
- if (SDHC_DEBUG) { \
- fprintf(stderr, "QEMU SDHC: " fmt, ## args); \
- } \
- } while (0)
-#define DPRINT_L2(fmt, args...) \
- do { \
- if (SDHC_DEBUG > 1) { \
- fprintf(stderr, "QEMU SDHC: " fmt, ## args); \
- } \
- } while (0)
-#define ERRPRINT(fmt, args...) \
- do { \
- if (SDHC_DEBUG) { \
- fprintf(stderr, "QEMU SDHC ERROR: " fmt, ## args); \
- } \
- } while (0)
-
-#define TYPE_SDHCI_BUS "sdhci-bus"
-#define SDHCI_BUS(obj) OBJECT_CHECK(SDBus, (obj), TYPE_SDHCI_BUS)
-
-/* Default SD/MMC host controller features information, which will be
- * presented in CAPABILITIES register of generic SD host controller at reset.
- * If not stated otherwise:
- * 0 - not supported, 1 - supported, other - prohibited.
- */
-#define SDHC_CAPAB_64BITBUS 0ul /* 64-bit System Bus Support */
-#define SDHC_CAPAB_18V 1ul /* Voltage support 1.8v */
-#define SDHC_CAPAB_30V 0ul /* Voltage support 3.0v */
-#define SDHC_CAPAB_33V 1ul /* Voltage support 3.3v */
-#define SDHC_CAPAB_SUSPRESUME 0ul /* Suspend/resume support */
-#define SDHC_CAPAB_SDMA 1ul /* SDMA support */
-#define SDHC_CAPAB_HIGHSPEED 1ul /* High speed support */
-#define SDHC_CAPAB_ADMA1 1ul /* ADMA1 support */
-#define SDHC_CAPAB_ADMA2 1ul /* ADMA2 support */
-/* Maximum host controller R/W buffers size
- * Possible values: 512, 1024, 2048 bytes */
-#define SDHC_CAPAB_MAXBLOCKLENGTH 512ul
-/* Maximum clock frequency for SDclock in MHz
- * value in range 10-63 MHz, 0 - not defined */
-#define SDHC_CAPAB_BASECLKFREQ 52ul
-#define SDHC_CAPAB_TOUNIT 1ul /* Timeout clock unit 0 - kHz, 1 - MHz */
-/* Timeout clock frequency 1-63, 0 - not defined */
-#define SDHC_CAPAB_TOCLKFREQ 52ul
-
-/* Now check all parameters and calculate CAPABILITIES REGISTER value */
-#if SDHC_CAPAB_64BITBUS > 1 || SDHC_CAPAB_18V > 1 || SDHC_CAPAB_30V > 1 || \
- SDHC_CAPAB_33V > 1 || SDHC_CAPAB_SUSPRESUME > 1 || SDHC_CAPAB_SDMA > 1 || \
- SDHC_CAPAB_HIGHSPEED > 1 || SDHC_CAPAB_ADMA2 > 1 || SDHC_CAPAB_ADMA1 > 1 ||\
- SDHC_CAPAB_TOUNIT > 1
-#error Capabilities features can have value 0 or 1 only!
-#endif
-
-#if SDHC_CAPAB_MAXBLOCKLENGTH == 512
-#define MAX_BLOCK_LENGTH 0ul
-#elif SDHC_CAPAB_MAXBLOCKLENGTH == 1024
-#define MAX_BLOCK_LENGTH 1ul
-#elif SDHC_CAPAB_MAXBLOCKLENGTH == 2048
-#define MAX_BLOCK_LENGTH 2ul
-#else
-#error Max host controller block size can have value 512, 1024 or 2048 only!
-#endif
-
-#if (SDHC_CAPAB_BASECLKFREQ > 0 && SDHC_CAPAB_BASECLKFREQ < 10) || \
- SDHC_CAPAB_BASECLKFREQ > 63
-#error SDclock frequency can have value in range 0, 10-63 only!
-#endif
-
-#if SDHC_CAPAB_TOCLKFREQ > 63
-#error Timeout clock frequency can have value in range 0-63 only!
-#endif
-
-#define SDHC_CAPAB_REG_DEFAULT \
- ((SDHC_CAPAB_64BITBUS << 28) | (SDHC_CAPAB_18V << 26) | \
- (SDHC_CAPAB_30V << 25) | (SDHC_CAPAB_33V << 24) | \
- (SDHC_CAPAB_SUSPRESUME << 23) | (SDHC_CAPAB_SDMA << 22) | \
- (SDHC_CAPAB_HIGHSPEED << 21) | (SDHC_CAPAB_ADMA1 << 20) | \
- (SDHC_CAPAB_ADMA2 << 19) | (MAX_BLOCK_LENGTH << 16) | \
- (SDHC_CAPAB_BASECLKFREQ << 8) | (SDHC_CAPAB_TOUNIT << 7) | \
- (SDHC_CAPAB_TOCLKFREQ))
-
-#define MASKED_WRITE(reg, mask, val) (reg = (reg & (mask)) | (val))
-
-static uint8_t sdhci_slotint(SDHCIState *s)
-{
- return (s->norintsts & s->norintsigen) || (s->errintsts & s->errintsigen) ||
- ((s->norintsts & SDHC_NIS_INSERT) && (s->wakcon & SDHC_WKUP_ON_INS)) ||
- ((s->norintsts & SDHC_NIS_REMOVE) && (s->wakcon & SDHC_WKUP_ON_RMV));
-}
-
-static inline void sdhci_update_irq(SDHCIState *s)
-{
- qemu_set_irq(s->irq, sdhci_slotint(s));
-}
-
-static void sdhci_raise_insertion_irq(void *opaque)
-{
- SDHCIState *s = (SDHCIState *)opaque;
-
- if (s->norintsts & SDHC_NIS_REMOVE) {
- timer_mod(s->insert_timer,
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + SDHC_INSERTION_DELAY);
- } else {
- s->prnsts = 0x1ff0000;
- if (s->norintstsen & SDHC_NISEN_INSERT) {
- s->norintsts |= SDHC_NIS_INSERT;
- }
- sdhci_update_irq(s);
- }
-}
-
-static void sdhci_set_inserted(DeviceState *dev, bool level)
-{
- SDHCIState *s = (SDHCIState *)dev;
- DPRINT_L1("Card state changed: %s!\n", level ? "insert" : "eject");
-
- if ((s->norintsts & SDHC_NIS_REMOVE) && level) {
- /* Give target some time to notice card ejection */
- timer_mod(s->insert_timer,
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + SDHC_INSERTION_DELAY);
- } else {
- if (level) {
- s->prnsts = 0x1ff0000;
- if (s->norintstsen & SDHC_NISEN_INSERT) {
- s->norintsts |= SDHC_NIS_INSERT;
- }
- } else {
- s->prnsts = 0x1fa0000;
- s->pwrcon &= ~SDHC_POWER_ON;
- s->clkcon &= ~SDHC_CLOCK_SDCLK_EN;
- if (s->norintstsen & SDHC_NISEN_REMOVE) {
- s->norintsts |= SDHC_NIS_REMOVE;
- }
- }
- sdhci_update_irq(s);
- }
-}
-
-static void sdhci_set_readonly(DeviceState *dev, bool level)
-{
- SDHCIState *s = (SDHCIState *)dev;
-
- if (level) {
- s->prnsts &= ~SDHC_WRITE_PROTECT;
- } else {
- /* Write enabled */
- s->prnsts |= SDHC_WRITE_PROTECT;
- }
-}
-
-static void sdhci_reset(SDHCIState *s)
-{
- DeviceState *dev = DEVICE(s);
-
- timer_del(s->insert_timer);
- timer_del(s->transfer_timer);
- /* Set all registers to 0. Capabilities registers are not cleared
- * and assumed to always preserve their value, given to them during
- * initialization */
- memset(&s->sdmasysad, 0, (uintptr_t)&s->capareg - (uintptr_t)&s->sdmasysad);
-
- /* Reset other state based on current card insertion/readonly status */
- sdhci_set_inserted(dev, sdbus_get_inserted(&s->sdbus));
- sdhci_set_readonly(dev, sdbus_get_readonly(&s->sdbus));
-
- s->data_count = 0;
- s->stopped_state = sdhc_not_stopped;
- s->pending_insert_state = false;
-}
-
-static void sdhci_poweron_reset(DeviceState *dev)
-{
- /* QOM (ie power-on) reset. This is identical to reset
- * commanded via device register apart from handling of the
- * 'pending insert on powerup' quirk.
- */
- SDHCIState *s = (SDHCIState *)dev;
-
- sdhci_reset(s);
-
- if (s->pending_insert_quirk) {
- s->pending_insert_state = true;
- }
-}
-
-static void sdhci_data_transfer(void *opaque);
-
-static void sdhci_send_command(SDHCIState *s)
-{
- SDRequest request;
- uint8_t response[16];
- int rlen;
-
- s->errintsts = 0;
- s->acmd12errsts = 0;
- request.cmd = s->cmdreg >> 8;
- request.arg = s->argument;
- DPRINT_L1("sending CMD%u ARG[0x%08x]\n", request.cmd, request.arg);
- rlen = sdbus_do_command(&s->sdbus, &request, response);
-
- if (s->cmdreg & SDHC_CMD_RESPONSE) {
- if (rlen == 4) {
- s->rspreg[0] = (response[0] << 24) | (response[1] << 16) |
- (response[2] << 8) | response[3];
- s->rspreg[1] = s->rspreg[2] = s->rspreg[3] = 0;
- DPRINT_L1("Response: RSPREG[31..0]=0x%08x\n", s->rspreg[0]);
- } else if (rlen == 16) {
- s->rspreg[0] = (response[11] << 24) | (response[12] << 16) |
- (response[13] << 8) | response[14];
- s->rspreg[1] = (response[7] << 24) | (response[8] << 16) |
- (response[9] << 8) | response[10];
- s->rspreg[2] = (response[3] << 24) | (response[4] << 16) |
- (response[5] << 8) | response[6];
- s->rspreg[3] = (response[0] << 16) | (response[1] << 8) |
- response[2];
- DPRINT_L1("Response received:\n RSPREG[127..96]=0x%08x, RSPREG[95.."
- "64]=0x%08x,\n RSPREG[63..32]=0x%08x, RSPREG[31..0]=0x%08x\n",
- s->rspreg[3], s->rspreg[2], s->rspreg[1], s->rspreg[0]);
- } else {
- ERRPRINT("Timeout waiting for command response\n");
- if (s->errintstsen & SDHC_EISEN_CMDTIMEOUT) {
- s->errintsts |= SDHC_EIS_CMDTIMEOUT;
- s->norintsts |= SDHC_NIS_ERR;
- }
- }
-
- if ((s->norintstsen & SDHC_NISEN_TRSCMP) &&
- (s->cmdreg & SDHC_CMD_RESPONSE) == SDHC_CMD_RSP_WITH_BUSY) {
- s->norintsts |= SDHC_NIS_TRSCMP;
- }
- }
-
- if (s->norintstsen & SDHC_NISEN_CMDCMP) {
- s->norintsts |= SDHC_NIS_CMDCMP;
- }
-
- sdhci_update_irq(s);
-
- if (s->blksize && (s->cmdreg & SDHC_CMD_DATA_PRESENT)) {
- s->data_count = 0;
- sdhci_data_transfer(s);
- }
-}
-
-static void sdhci_end_transfer(SDHCIState *s)
-{
- /* Automatically send CMD12 to stop transfer if AutoCMD12 enabled */
- if ((s->trnmod & SDHC_TRNS_ACMD12) != 0) {
- SDRequest request;
- uint8_t response[16];
-
- request.cmd = 0x0C;
- request.arg = 0;
- DPRINT_L1("Automatically issue CMD%d %08x\n", request.cmd, request.arg);
- sdbus_do_command(&s->sdbus, &request, response);
- /* Auto CMD12 response goes to the upper Response register */
- s->rspreg[3] = (response[0] << 24) | (response[1] << 16) |
- (response[2] << 8) | response[3];
- }
-
- s->prnsts &= ~(SDHC_DOING_READ | SDHC_DOING_WRITE |
- SDHC_DAT_LINE_ACTIVE | SDHC_DATA_INHIBIT |
- SDHC_SPACE_AVAILABLE | SDHC_DATA_AVAILABLE);
-
- if (s->norintstsen & SDHC_NISEN_TRSCMP) {
- s->norintsts |= SDHC_NIS_TRSCMP;
- }
-
- sdhci_update_irq(s);
-}
-
-/*
- * Programmed i/o data transfer
- */
-
-/* Fill host controller's read buffer with BLKSIZE bytes of data from card */
-static void sdhci_read_block_from_card(SDHCIState *s)
-{
- int index = 0;
-
- if ((s->trnmod & SDHC_TRNS_MULTI) &&
- (s->trnmod & SDHC_TRNS_BLK_CNT_EN) && (s->blkcnt == 0)) {
- return;
- }
-
- for (index = 0; index < (s->blksize & 0x0fff); index++) {
- s->fifo_buffer[index] = sdbus_read_data(&s->sdbus);
- }
-
- /* New data now available for READ through Buffer Port Register */
- s->prnsts |= SDHC_DATA_AVAILABLE;
- if (s->norintstsen & SDHC_NISEN_RBUFRDY) {
- s->norintsts |= SDHC_NIS_RBUFRDY;
- }
-
- /* Clear DAT line active status if that was the last block */
- if ((s->trnmod & SDHC_TRNS_MULTI) == 0 ||
- ((s->trnmod & SDHC_TRNS_MULTI) && s->blkcnt == 1)) {
- s->prnsts &= ~SDHC_DAT_LINE_ACTIVE;
- }
-
- /* If stop at block gap request was set and it's not the last block of
- * data - generate Block Event interrupt */
- if (s->stopped_state == sdhc_gap_read && (s->trnmod & SDHC_TRNS_MULTI) &&
- s->blkcnt != 1) {
- s->prnsts &= ~SDHC_DAT_LINE_ACTIVE;
- if (s->norintstsen & SDHC_EISEN_BLKGAP) {
- s->norintsts |= SDHC_EIS_BLKGAP;
- }
- }
-
- sdhci_update_irq(s);
-}
-
-/* Read @size byte of data from host controller @s BUFFER DATA PORT register */
-static uint32_t sdhci_read_dataport(SDHCIState *s, unsigned size)
-{
- uint32_t value = 0;
- int i;
-
- /* first check that a valid data exists in host controller input buffer */
- if ((s->prnsts & SDHC_DATA_AVAILABLE) == 0) {
- ERRPRINT("Trying to read from empty buffer\n");
- return 0;
- }
-
- for (i = 0; i < size; i++) {
- value |= s->fifo_buffer[s->data_count] << i * 8;
- s->data_count++;
- /* check if we've read all valid data (blksize bytes) from buffer */
- if ((s->data_count) >= (s->blksize & 0x0fff)) {
- DPRINT_L2("All %u bytes of data have been read from input buffer\n",
- s->data_count);
- s->prnsts &= ~SDHC_DATA_AVAILABLE; /* no more data in a buffer */
- s->data_count = 0; /* next buff read must start at position [0] */
-
- if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) {
- s->blkcnt--;
- }
-
- /* if that was the last block of data */
- if ((s->trnmod & SDHC_TRNS_MULTI) == 0 ||
- ((s->trnmod & SDHC_TRNS_BLK_CNT_EN) && (s->blkcnt == 0)) ||
- /* stop at gap request */
- (s->stopped_state == sdhc_gap_read &&
- !(s->prnsts & SDHC_DAT_LINE_ACTIVE))) {
- sdhci_end_transfer(s);
- } else { /* if there are more data, read next block from card */
- sdhci_read_block_from_card(s);
- }
- break;
- }
- }
-
- return value;
-}
-
-/* Write data from host controller FIFO to card */
-static void sdhci_write_block_to_card(SDHCIState *s)
-{
- int index = 0;
-
- if (s->prnsts & SDHC_SPACE_AVAILABLE) {
- if (s->norintstsen & SDHC_NISEN_WBUFRDY) {
- s->norintsts |= SDHC_NIS_WBUFRDY;
- }
- sdhci_update_irq(s);
- return;
- }
-
- if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) {
- if (s->blkcnt == 0) {
- return;
- } else {
- s->blkcnt--;
- }
- }
-
- for (index = 0; index < (s->blksize & 0x0fff); index++) {
- sdbus_write_data(&s->sdbus, s->fifo_buffer[index]);
- }
-
- /* Next data can be written through BUFFER DATORT register */
- s->prnsts |= SDHC_SPACE_AVAILABLE;
-
- /* Finish transfer if that was the last block of data */
- if ((s->trnmod & SDHC_TRNS_MULTI) == 0 ||
- ((s->trnmod & SDHC_TRNS_MULTI) &&
- (s->trnmod & SDHC_TRNS_BLK_CNT_EN) && (s->blkcnt == 0))) {
- sdhci_end_transfer(s);
- } else if (s->norintstsen & SDHC_NISEN_WBUFRDY) {
- s->norintsts |= SDHC_NIS_WBUFRDY;
- }
-
- /* Generate Block Gap Event if requested and if not the last block */
- if (s->stopped_state == sdhc_gap_write && (s->trnmod & SDHC_TRNS_MULTI) &&
- s->blkcnt > 0) {
- s->prnsts &= ~SDHC_DOING_WRITE;
- if (s->norintstsen & SDHC_EISEN_BLKGAP) {
- s->norintsts |= SDHC_EIS_BLKGAP;
- }
- sdhci_end_transfer(s);
- }
-
- sdhci_update_irq(s);
-}
-
-/* Write @size bytes of @value data to host controller @s Buffer Data Port
- * register */
-static void sdhci_write_dataport(SDHCIState *s, uint32_t value, unsigned size)
-{
- unsigned i;
-
- /* Check that there is free space left in a buffer */
- if (!(s->prnsts & SDHC_SPACE_AVAILABLE)) {
- ERRPRINT("Can't write to data buffer: buffer full\n");
- return;
- }
-
- for (i = 0; i < size; i++) {
- s->fifo_buffer[s->data_count] = value & 0xFF;
- s->data_count++;
- value >>= 8;
- if (s->data_count >= (s->blksize & 0x0fff)) {
- DPRINT_L2("write buffer filled with %u bytes of data\n",
- s->data_count);
- s->data_count = 0;
- s->prnsts &= ~SDHC_SPACE_AVAILABLE;
- if (s->prnsts & SDHC_DOING_WRITE) {
- sdhci_write_block_to_card(s);
- }
- }
- }
-}
-
-/*
- * Single DMA data transfer
- */
-
-/* Multi block SDMA transfer */
-static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s)
-{
- bool page_aligned = false;
- unsigned int n, begin;
- const uint16_t block_size = s->blksize & 0x0fff;
- uint32_t boundary_chk = 1 << (((s->blksize & 0xf000) >> 12) + 12);
- uint32_t boundary_count = boundary_chk - (s->sdmasysad % boundary_chk);
-
- /* XXX: Some sd/mmc drivers (for example, u-boot-slp) do not account for
- * possible stop at page boundary if initial address is not page aligned,
- * allow them to work properly */
- if ((s->sdmasysad % boundary_chk) == 0) {
- page_aligned = true;
- }
-
- if (s->trnmod & SDHC_TRNS_READ) {
- s->prnsts |= SDHC_DOING_READ | SDHC_DATA_INHIBIT |
- SDHC_DAT_LINE_ACTIVE;
- while (s->blkcnt) {
- if (s->data_count == 0) {
- for (n = 0; n < block_size; n++) {
- s->fifo_buffer[n] = sdbus_read_data(&s->sdbus);
- }
- }
- begin = s->data_count;
- if (((boundary_count + begin) < block_size) && page_aligned) {
- s->data_count = boundary_count + begin;
- boundary_count = 0;
- } else {
- s->data_count = block_size;
- boundary_count -= block_size - begin;
- if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) {
- s->blkcnt--;
- }
- }
- dma_memory_write(&address_space_memory, s->sdmasysad,
- &s->fifo_buffer[begin], s->data_count - begin);
- s->sdmasysad += s->data_count - begin;
- if (s->data_count == block_size) {
- s->data_count = 0;
- }
- if (page_aligned && boundary_count == 0) {
- break;
- }
- }
- } else {
- s->prnsts |= SDHC_DOING_WRITE | SDHC_DATA_INHIBIT |
- SDHC_DAT_LINE_ACTIVE;
- while (s->blkcnt) {
- begin = s->data_count;
- if (((boundary_count + begin) < block_size) && page_aligned) {
- s->data_count = boundary_count + begin;
- boundary_count = 0;
- } else {
- s->data_count = block_size;
- boundary_count -= block_size - begin;
- }
- dma_memory_read(&address_space_memory, s->sdmasysad,
- &s->fifo_buffer[begin], s->data_count);
- s->sdmasysad += s->data_count - begin;
- if (s->data_count == block_size) {
- for (n = 0; n < block_size; n++) {
- sdbus_write_data(&s->sdbus, s->fifo_buffer[n]);
- }
- s->data_count = 0;
- if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) {
- s->blkcnt--;
- }
- }
- if (page_aligned && boundary_count == 0) {
- break;
- }
- }
- }
-
- if (s->blkcnt == 0) {
- sdhci_end_transfer(s);
- } else {
- if (s->norintstsen & SDHC_NISEN_DMA) {
- s->norintsts |= SDHC_NIS_DMA;
- }
- sdhci_update_irq(s);
- }
-}
-
-/* single block SDMA transfer */
-
-static void sdhci_sdma_transfer_single_block(SDHCIState *s)
-{
- int n;
- uint32_t datacnt = s->blksize & 0x0fff;
-
- if (s->trnmod & SDHC_TRNS_READ) {
- for (n = 0; n < datacnt; n++) {
- s->fifo_buffer[n] = sdbus_read_data(&s->sdbus);
- }
- dma_memory_write(&address_space_memory, s->sdmasysad, s->fifo_buffer,
- datacnt);
- } else {
- dma_memory_read(&address_space_memory, s->sdmasysad, s->fifo_buffer,
- datacnt);
- for (n = 0; n < datacnt; n++) {
- sdbus_write_data(&s->sdbus, s->fifo_buffer[n]);
- }
- }
-
- if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) {
- s->blkcnt--;
- }
-
- sdhci_end_transfer(s);
-}
-
-typedef struct ADMADescr {
- hwaddr addr;
- uint16_t length;
- uint8_t attr;
- uint8_t incr;
-} ADMADescr;
-
-static void get_adma_description(SDHCIState *s, ADMADescr *dscr)
-{
- uint32_t adma1 = 0;
- uint64_t adma2 = 0;
- hwaddr entry_addr = (hwaddr)s->admasysaddr;
- switch (SDHC_DMA_TYPE(s->hostctl)) {
- case SDHC_CTRL_ADMA2_32:
- dma_memory_read(&address_space_memory, entry_addr, (uint8_t *)&adma2,
- sizeof(adma2));
- adma2 = le64_to_cpu(adma2);
- /* The spec does not specify endianness of descriptor table.
- * We currently assume that it is LE.
- */
- dscr->addr = (hwaddr)extract64(adma2, 32, 32) & ~0x3ull;
- dscr->length = (uint16_t)extract64(adma2, 16, 16);
- dscr->attr = (uint8_t)extract64(adma2, 0, 7);
- dscr->incr = 8;
- break;
- case SDHC_CTRL_ADMA1_32:
- dma_memory_read(&address_space_memory, entry_addr, (uint8_t *)&adma1,
- sizeof(adma1));
- adma1 = le32_to_cpu(adma1);
- dscr->addr = (hwaddr)(adma1 & 0xFFFFF000);
- dscr->attr = (uint8_t)extract32(adma1, 0, 7);
- dscr->incr = 4;
- if ((dscr->attr & SDHC_ADMA_ATTR_ACT_MASK) == SDHC_ADMA_ATTR_SET_LEN) {
- dscr->length = (uint16_t)extract32(adma1, 12, 16);
- } else {
- dscr->length = 4096;
- }
- break;
- case SDHC_CTRL_ADMA2_64:
- dma_memory_read(&address_space_memory, entry_addr,
- (uint8_t *)(&dscr->attr), 1);
- dma_memory_read(&address_space_memory, entry_addr + 2,
- (uint8_t *)(&dscr->length), 2);
- dscr->length = le16_to_cpu(dscr->length);
- dma_memory_read(&address_space_memory, entry_addr + 4,
- (uint8_t *)(&dscr->addr), 8);
- dscr->attr = le64_to_cpu(dscr->attr);
- dscr->attr &= 0xfffffff8;
- dscr->incr = 12;
- break;
- }
-}
-
-/* Advanced DMA data transfer */
-
-static void sdhci_do_adma(SDHCIState *s)
-{
- unsigned int n, begin, length;
- const uint16_t block_size = s->blksize & 0x0fff;
- ADMADescr dscr;
- int i;
-
- for (i = 0; i < SDHC_ADMA_DESCS_PER_DELAY; ++i) {
- s->admaerr &= ~SDHC_ADMAERR_LENGTH_MISMATCH;
-
- get_adma_description(s, &dscr);
- DPRINT_L2("ADMA loop: addr=" TARGET_FMT_plx ", len=%d, attr=%x\n",
- dscr.addr, dscr.length, dscr.attr);
-
- if ((dscr.attr & SDHC_ADMA_ATTR_VALID) == 0) {
- /* Indicate that error occurred in ST_FDS state */
- s->admaerr &= ~SDHC_ADMAERR_STATE_MASK;
- s->admaerr |= SDHC_ADMAERR_STATE_ST_FDS;
-
- /* Generate ADMA error interrupt */
- if (s->errintstsen & SDHC_EISEN_ADMAERR) {
- s->errintsts |= SDHC_EIS_ADMAERR;
- s->norintsts |= SDHC_NIS_ERR;
- }
-
- sdhci_update_irq(s);
- return;
- }
-
- length = dscr.length ? dscr.length : 65536;
-
- switch (dscr.attr & SDHC_ADMA_ATTR_ACT_MASK) {
- case SDHC_ADMA_ATTR_ACT_TRAN: /* data transfer */
-
- if (s->trnmod & SDHC_TRNS_READ) {
- while (length) {
- if (s->data_count == 0) {
- for (n = 0; n < block_size; n++) {
- s->fifo_buffer[n] = sdbus_read_data(&s->sdbus);
- }
- }
- begin = s->data_count;
- if ((length + begin) < block_size) {
- s->data_count = length + begin;
- length = 0;
- } else {
- s->data_count = block_size;
- length -= block_size - begin;
- }
- dma_memory_write(&address_space_memory, dscr.addr,
- &s->fifo_buffer[begin],
- s->data_count - begin);
- dscr.addr += s->data_count - begin;
- if (s->data_count == block_size) {
- s->data_count = 0;
- if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) {
- s->blkcnt--;
- if (s->blkcnt == 0) {
- break;
- }
- }
- }
- }
- } else {
- while (length) {
- begin = s->data_count;
- if ((length + begin) < block_size) {
- s->data_count = length + begin;
- length = 0;
- } else {
- s->data_count = block_size;
- length -= block_size - begin;
- }
- dma_memory_read(&address_space_memory, dscr.addr,
- &s->fifo_buffer[begin],
- s->data_count - begin);
- dscr.addr += s->data_count - begin;
- if (s->data_count == block_size) {
- for (n = 0; n < block_size; n++) {
- sdbus_write_data(&s->sdbus, s->fifo_buffer[n]);
- }
- s->data_count = 0;
- if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) {
- s->blkcnt--;
- if (s->blkcnt == 0) {
- break;
- }
- }
- }
- }
- }
- s->admasysaddr += dscr.incr;
- break;
- case SDHC_ADMA_ATTR_ACT_LINK: /* link to next descriptor table */
- s->admasysaddr = dscr.addr;
- DPRINT_L1("ADMA link: admasysaddr=0x%" PRIx64 "\n",
- s->admasysaddr);
- break;
- default:
- s->admasysaddr += dscr.incr;
- break;
- }
-
- if (dscr.attr & SDHC_ADMA_ATTR_INT) {
- DPRINT_L1("ADMA interrupt: admasysaddr=0x%" PRIx64 "\n",
- s->admasysaddr);
- if (s->norintstsen & SDHC_NISEN_DMA) {
- s->norintsts |= SDHC_NIS_DMA;
- }
-
- sdhci_update_irq(s);
- }
-
- /* ADMA transfer terminates if blkcnt == 0 or by END attribute */
- if (((s->trnmod & SDHC_TRNS_BLK_CNT_EN) &&
- (s->blkcnt == 0)) || (dscr.attr & SDHC_ADMA_ATTR_END)) {
- DPRINT_L2("ADMA transfer completed\n");
- if (length || ((dscr.attr & SDHC_ADMA_ATTR_END) &&
- (s->trnmod & SDHC_TRNS_BLK_CNT_EN) &&
- s->blkcnt != 0)) {
- ERRPRINT("SD/MMC host ADMA length mismatch\n");
- s->admaerr |= SDHC_ADMAERR_LENGTH_MISMATCH |
- SDHC_ADMAERR_STATE_ST_TFR;
- if (s->errintstsen & SDHC_EISEN_ADMAERR) {
- ERRPRINT("Set ADMA error flag\n");
- s->errintsts |= SDHC_EIS_ADMAERR;
- s->norintsts |= SDHC_NIS_ERR;
- }
-
- sdhci_update_irq(s);
- }
- sdhci_end_transfer(s);
- return;
- }
-
- }
-
- /* we have unfinished business - reschedule to continue ADMA */
- timer_mod(s->transfer_timer,
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + SDHC_TRANSFER_DELAY);
-}
-
-/* Perform data transfer according to controller configuration */
-
-static void sdhci_data_transfer(void *opaque)
-{
- SDHCIState *s = (SDHCIState *)opaque;
-
- if (s->trnmod & SDHC_TRNS_DMA) {
- switch (SDHC_DMA_TYPE(s->hostctl)) {
- case SDHC_CTRL_SDMA:
- if ((s->trnmod & SDHC_TRNS_MULTI) &&
- (!(s->trnmod & SDHC_TRNS_BLK_CNT_EN) || s->blkcnt == 0)) {
- break;
- }
-
- if ((s->blkcnt == 1) || !(s->trnmod & SDHC_TRNS_MULTI)) {
- sdhci_sdma_transfer_single_block(s);
- } else {
- sdhci_sdma_transfer_multi_blocks(s);
- }
-
- break;
- case SDHC_CTRL_ADMA1_32:
- if (!(s->capareg & SDHC_CAN_DO_ADMA1)) {
- ERRPRINT("ADMA1 not supported\n");
- break;
- }
-
- sdhci_do_adma(s);
- break;
- case SDHC_CTRL_ADMA2_32:
- if (!(s->capareg & SDHC_CAN_DO_ADMA2)) {
- ERRPRINT("ADMA2 not supported\n");
- break;
- }
-
- sdhci_do_adma(s);
- break;
- case SDHC_CTRL_ADMA2_64:
- if (!(s->capareg & SDHC_CAN_DO_ADMA2) ||
- !(s->capareg & SDHC_64_BIT_BUS_SUPPORT)) {
- ERRPRINT("64 bit ADMA not supported\n");
- break;
- }
-
- sdhci_do_adma(s);
- break;
- default:
- ERRPRINT("Unsupported DMA type\n");
- break;
- }
- } else {
- if ((s->trnmod & SDHC_TRNS_READ) && sdbus_data_ready(&s->sdbus)) {
- s->prnsts |= SDHC_DOING_READ | SDHC_DATA_INHIBIT |
- SDHC_DAT_LINE_ACTIVE;
- sdhci_read_block_from_card(s);
- } else {
- s->prnsts |= SDHC_DOING_WRITE | SDHC_DAT_LINE_ACTIVE |
- SDHC_SPACE_AVAILABLE | SDHC_DATA_INHIBIT;
- sdhci_write_block_to_card(s);
- }
- }
-}
-
-static bool sdhci_can_issue_command(SDHCIState *s)
-{
- if (!SDHC_CLOCK_IS_ON(s->clkcon) ||
- (((s->prnsts & SDHC_DATA_INHIBIT) || s->stopped_state) &&
- ((s->cmdreg & SDHC_CMD_DATA_PRESENT) ||
- ((s->cmdreg & SDHC_CMD_RESPONSE) == SDHC_CMD_RSP_WITH_BUSY &&
- !(SDHC_COMMAND_TYPE(s->cmdreg) == SDHC_CMD_ABORT))))) {
- return false;
- }
-
- return true;
-}
-
-/* The Buffer Data Port register must be accessed in sequential and
- * continuous manner */
-static inline bool
-sdhci_buff_access_is_sequential(SDHCIState *s, unsigned byte_num)
-{
- if ((s->data_count & 0x3) != byte_num) {
- ERRPRINT("Non-sequential access to Buffer Data Port register"
- "is prohibited\n");
- return false;
- }
- return true;
-}
-
-static uint64_t sdhci_read(void *opaque, hwaddr offset, unsigned size)
-{
- SDHCIState *s = (SDHCIState *)opaque;
- uint32_t ret = 0;
-
- switch (offset & ~0x3) {
- case SDHC_SYSAD:
- ret = s->sdmasysad;
- break;
- case SDHC_BLKSIZE:
- ret = s->blksize | (s->blkcnt << 16);
- break;
- case SDHC_ARGUMENT:
- ret = s->argument;
- break;
- case SDHC_TRNMOD:
- ret = s->trnmod | (s->cmdreg << 16);
- break;
- case SDHC_RSPREG0 ... SDHC_RSPREG3:
- ret = s->rspreg[((offset & ~0x3) - SDHC_RSPREG0) >> 2];
- break;
- case SDHC_BDATA:
- if (sdhci_buff_access_is_sequential(s, offset - SDHC_BDATA)) {
- ret = sdhci_read_dataport(s, size);
- DPRINT_L2("read %ub: addr[0x%04x] -> %u(0x%x)\n", size, (int)offset,
- ret, ret);
- return ret;
- }
- break;
- case SDHC_PRNSTS:
- ret = s->prnsts;
- break;
- case SDHC_HOSTCTL:
- ret = s->hostctl | (s->pwrcon << 8) | (s->blkgap << 16) |
- (s->wakcon << 24);
- break;
- case SDHC_CLKCON:
- ret = s->clkcon | (s->timeoutcon << 16);
- break;
- case SDHC_NORINTSTS:
- ret = s->norintsts | (s->errintsts << 16);
- break;
- case SDHC_NORINTSTSEN:
- ret = s->norintstsen | (s->errintstsen << 16);
- break;
- case SDHC_NORINTSIGEN:
- ret = s->norintsigen | (s->errintsigen << 16);
- break;
- case SDHC_ACMD12ERRSTS:
- ret = s->acmd12errsts;
- break;
- case SDHC_CAPAREG:
- ret = s->capareg;
- break;
- case SDHC_MAXCURR:
- ret = s->maxcurr;
- break;
- case SDHC_ADMAERR:
- ret = s->admaerr;
- break;
- case SDHC_ADMASYSADDR:
- ret = (uint32_t)s->admasysaddr;
- break;
- case SDHC_ADMASYSADDR + 4:
- ret = (uint32_t)(s->admasysaddr >> 32);
- break;
- case SDHC_SLOT_INT_STATUS:
- ret = (SD_HOST_SPECv2_VERS << 16) | sdhci_slotint(s);
- break;
- default:
- ERRPRINT("bad %ub read: addr[0x%04x]\n", size, (int)offset);
- break;
- }
-
- ret >>= (offset & 0x3) * 8;
- ret &= (1ULL << (size * 8)) - 1;
- DPRINT_L2("read %ub: addr[0x%04x] -> %u(0x%x)\n", size, (int)offset, ret, ret);
- return ret;
-}
-
-static inline void sdhci_blkgap_write(SDHCIState *s, uint8_t value)
-{
- if ((value & SDHC_STOP_AT_GAP_REQ) && (s->blkgap & SDHC_STOP_AT_GAP_REQ)) {
- return;
- }
- s->blkgap = value & SDHC_STOP_AT_GAP_REQ;
-
- if ((value & SDHC_CONTINUE_REQ) && s->stopped_state &&
- (s->blkgap & SDHC_STOP_AT_GAP_REQ) == 0) {
- if (s->stopped_state == sdhc_gap_read) {
- s->prnsts |= SDHC_DAT_LINE_ACTIVE | SDHC_DOING_READ;
- sdhci_read_block_from_card(s);
- } else {
- s->prnsts |= SDHC_DAT_LINE_ACTIVE | SDHC_DOING_WRITE;
- sdhci_write_block_to_card(s);
- }
- s->stopped_state = sdhc_not_stopped;
- } else if (!s->stopped_state && (value & SDHC_STOP_AT_GAP_REQ)) {
- if (s->prnsts & SDHC_DOING_READ) {
- s->stopped_state = sdhc_gap_read;
- } else if (s->prnsts & SDHC_DOING_WRITE) {
- s->stopped_state = sdhc_gap_write;
- }
- }
-}
-
-static inline void sdhci_reset_write(SDHCIState *s, uint8_t value)
-{
- switch (value) {
- case SDHC_RESET_ALL:
- sdhci_reset(s);
- break;
- case SDHC_RESET_CMD:
- s->prnsts &= ~SDHC_CMD_INHIBIT;
- s->norintsts &= ~SDHC_NIS_CMDCMP;
- break;
- case SDHC_RESET_DATA:
- s->data_count = 0;
- s->prnsts &= ~(SDHC_SPACE_AVAILABLE | SDHC_DATA_AVAILABLE |
- SDHC_DOING_READ | SDHC_DOING_WRITE |
- SDHC_DATA_INHIBIT | SDHC_DAT_LINE_ACTIVE);
- s->blkgap &= ~(SDHC_STOP_AT_GAP_REQ | SDHC_CONTINUE_REQ);
- s->stopped_state = sdhc_not_stopped;
- s->norintsts &= ~(SDHC_NIS_WBUFRDY | SDHC_NIS_RBUFRDY |
- SDHC_NIS_DMA | SDHC_NIS_TRSCMP | SDHC_NIS_BLKGAP);
- break;
- }
-}
-
-static void
-sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
-{
- SDHCIState *s = (SDHCIState *)opaque;
- unsigned shift = 8 * (offset & 0x3);
- uint32_t mask = ~(((1ULL << (size * 8)) - 1) << shift);
- uint32_t value = val;
- value <<= shift;
-
- switch (offset & ~0x3) {
- case SDHC_SYSAD:
- s->sdmasysad = (s->sdmasysad & mask) | value;
- MASKED_WRITE(s->sdmasysad, mask, value);
- /* Writing to last byte of sdmasysad might trigger transfer */
- if (!(mask & 0xFF000000) && TRANSFERRING_DATA(s->prnsts) && s->blkcnt &&
- s->blksize && SDHC_DMA_TYPE(s->hostctl) == SDHC_CTRL_SDMA) {
- sdhci_sdma_transfer_multi_blocks(s);
- }
- break;
- case SDHC_BLKSIZE:
- if (!TRANSFERRING_DATA(s->prnsts)) {
- MASKED_WRITE(s->blksize, mask, value);
- MASKED_WRITE(s->blkcnt, mask >> 16, value >> 16);
- }
-
- /* Limit block size to the maximum buffer size */
- if (extract32(s->blksize, 0, 12) > s->buf_maxsz) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Size 0x%x is larger than " \
- "the maximum buffer 0x%x", __func__, s->blksize,
- s->buf_maxsz);
-
- s->blksize = deposit32(s->blksize, 0, 12, s->buf_maxsz);
- }
-
- break;
- case SDHC_ARGUMENT:
- MASKED_WRITE(s->argument, mask, value);
- break;
- case SDHC_TRNMOD:
- /* DMA can be enabled only if it is supported as indicated by
- * capabilities register */
- if (!(s->capareg & SDHC_CAN_DO_DMA)) {
- value &= ~SDHC_TRNS_DMA;
- }
- MASKED_WRITE(s->trnmod, mask, value);
- MASKED_WRITE(s->cmdreg, mask >> 16, value >> 16);
-
- /* Writing to the upper byte of CMDREG triggers SD command generation */
- if ((mask & 0xFF000000) || !sdhci_can_issue_command(s)) {
- break;
- }
-
- sdhci_send_command(s);
- break;
- case SDHC_BDATA:
- if (sdhci_buff_access_is_sequential(s, offset - SDHC_BDATA)) {
- sdhci_write_dataport(s, value >> shift, size);
- }
- break;
- case SDHC_HOSTCTL:
- if (!(mask & 0xFF0000)) {
- sdhci_blkgap_write(s, value >> 16);
- }
- MASKED_WRITE(s->hostctl, mask, value);
- MASKED_WRITE(s->pwrcon, mask >> 8, value >> 8);
- MASKED_WRITE(s->wakcon, mask >> 24, value >> 24);
- if (!(s->prnsts & SDHC_CARD_PRESENT) || ((s->pwrcon >> 1) & 0x7) < 5 ||
- !(s->capareg & (1 << (31 - ((s->pwrcon >> 1) & 0x7))))) {
- s->pwrcon &= ~SDHC_POWER_ON;
- }
- break;
- case SDHC_CLKCON:
- if (!(mask & 0xFF000000)) {
- sdhci_reset_write(s, value >> 24);
- }
- MASKED_WRITE(s->clkcon, mask, value);
- MASKED_WRITE(s->timeoutcon, mask >> 16, value >> 16);
- if (s->clkcon & SDHC_CLOCK_INT_EN) {
- s->clkcon |= SDHC_CLOCK_INT_STABLE;
- } else {
- s->clkcon &= ~SDHC_CLOCK_INT_STABLE;
- }
- break;
- case SDHC_NORINTSTS:
- if (s->norintstsen & SDHC_NISEN_CARDINT) {
- value &= ~SDHC_NIS_CARDINT;
- }
- s->norintsts &= mask | ~value;
- s->errintsts &= (mask >> 16) | ~(value >> 16);
- if (s->errintsts) {
- s->norintsts |= SDHC_NIS_ERR;
- } else {
- s->norintsts &= ~SDHC_NIS_ERR;
- }
- sdhci_update_irq(s);
- break;
- case SDHC_NORINTSTSEN:
- MASKED_WRITE(s->norintstsen, mask, value);
- MASKED_WRITE(s->errintstsen, mask >> 16, value >> 16);
- s->norintsts &= s->norintstsen;
- s->errintsts &= s->errintstsen;
- if (s->errintsts) {
- s->norintsts |= SDHC_NIS_ERR;
- } else {
- s->norintsts &= ~SDHC_NIS_ERR;
- }
- /* Quirk for Raspberry Pi: pending card insert interrupt
- * appears when first enabled after power on */
- if ((s->norintstsen & SDHC_NISEN_INSERT) && s->pending_insert_state) {
- assert(s->pending_insert_quirk);
- s->norintsts |= SDHC_NIS_INSERT;
- s->pending_insert_state = false;
- }
- sdhci_update_irq(s);
- break;
- case SDHC_NORINTSIGEN:
- MASKED_WRITE(s->norintsigen, mask, value);
- MASKED_WRITE(s->errintsigen, mask >> 16, value >> 16);
- sdhci_update_irq(s);
- break;
- case SDHC_ADMAERR:
- MASKED_WRITE(s->admaerr, mask, value);
- break;
- case SDHC_ADMASYSADDR:
- s->admasysaddr = (s->admasysaddr & (0xFFFFFFFF00000000ULL |
- (uint64_t)mask)) | (uint64_t)value;
- break;
- case SDHC_ADMASYSADDR + 4:
- s->admasysaddr = (s->admasysaddr & (0x00000000FFFFFFFFULL |
- ((uint64_t)mask << 32))) | ((uint64_t)value << 32);
- break;
- case SDHC_FEAER:
- s->acmd12errsts |= value;
- s->errintsts |= (value >> 16) & s->errintstsen;
- if (s->acmd12errsts) {
- s->errintsts |= SDHC_EIS_CMD12ERR;
- }
- if (s->errintsts) {
- s->norintsts |= SDHC_NIS_ERR;
- }
- sdhci_update_irq(s);
- break;
- default:
- ERRPRINT("bad %ub write offset: addr[0x%04x] <- %u(0x%x)\n",
- size, (int)offset, value >> shift, value >> shift);
- break;
- }
- DPRINT_L2("write %ub: addr[0x%04x] <- %u(0x%x)\n",
- size, (int)offset, value >> shift, value >> shift);
-}
-
-static const MemoryRegionOps sdhci_mmio_ops = {
- .read = sdhci_read,
- .write = sdhci_write,
- .valid = {
- .min_access_size = 1,
- .max_access_size = 4,
- .unaligned = false
- },
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static inline unsigned int sdhci_get_fifolen(SDHCIState *s)
-{
- switch (SDHC_CAPAB_BLOCKSIZE(s->capareg)) {
- case 0:
- return 512;
- case 1:
- return 1024;
- case 2:
- return 2048;
- default:
- hw_error("SDHC: unsupported value for maximum block size\n");
- return 0;
- }
-}
-
-static void sdhci_initfn(SDHCIState *s)
-{
- qbus_create_inplace(&s->sdbus, sizeof(s->sdbus),
- TYPE_SDHCI_BUS, DEVICE(s), "sd-bus");
-
- s->insert_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sdhci_raise_insertion_irq, s);
- s->transfer_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sdhci_data_transfer, s);
-}
-
-static void sdhci_uninitfn(SDHCIState *s)
-{
- timer_del(s->insert_timer);
- timer_free(s->insert_timer);
- timer_del(s->transfer_timer);
- timer_free(s->transfer_timer);
- qemu_free_irq(s->eject_cb);
- qemu_free_irq(s->ro_cb);
-
- g_free(s->fifo_buffer);
- s->fifo_buffer = NULL;
-}
-
-static bool sdhci_pending_insert_vmstate_needed(void *opaque)
-{
- SDHCIState *s = opaque;
-
- return s->pending_insert_state;
-}
-
-static const VMStateDescription sdhci_pending_insert_vmstate = {
- .name = "sdhci/pending-insert",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = sdhci_pending_insert_vmstate_needed,
- .fields = (VMStateField[]) {
- VMSTATE_BOOL(pending_insert_state, SDHCIState),
- VMSTATE_END_OF_LIST()
- },
-};
-
-const VMStateDescription sdhci_vmstate = {
- .name = "sdhci",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(sdmasysad, SDHCIState),
- VMSTATE_UINT16(blksize, SDHCIState),
- VMSTATE_UINT16(blkcnt, SDHCIState),
- VMSTATE_UINT32(argument, SDHCIState),
- VMSTATE_UINT16(trnmod, SDHCIState),
- VMSTATE_UINT16(cmdreg, SDHCIState),
- VMSTATE_UINT32_ARRAY(rspreg, SDHCIState, 4),
- VMSTATE_UINT32(prnsts, SDHCIState),
- VMSTATE_UINT8(hostctl, SDHCIState),
- VMSTATE_UINT8(pwrcon, SDHCIState),
- VMSTATE_UINT8(blkgap, SDHCIState),
- VMSTATE_UINT8(wakcon, SDHCIState),
- VMSTATE_UINT16(clkcon, SDHCIState),
- VMSTATE_UINT8(timeoutcon, SDHCIState),
- VMSTATE_UINT8(admaerr, SDHCIState),
- VMSTATE_UINT16(norintsts, SDHCIState),
- VMSTATE_UINT16(errintsts, SDHCIState),
- VMSTATE_UINT16(norintstsen, SDHCIState),
- VMSTATE_UINT16(errintstsen, SDHCIState),
- VMSTATE_UINT16(norintsigen, SDHCIState),
- VMSTATE_UINT16(errintsigen, SDHCIState),
- VMSTATE_UINT16(acmd12errsts, SDHCIState),
- VMSTATE_UINT16(data_count, SDHCIState),
- VMSTATE_UINT64(admasysaddr, SDHCIState),
- VMSTATE_UINT8(stopped_state, SDHCIState),
- VMSTATE_VBUFFER_UINT32(fifo_buffer, SDHCIState, 1, NULL, 0, buf_maxsz),
- VMSTATE_TIMER_PTR(insert_timer, SDHCIState),
- VMSTATE_TIMER_PTR(transfer_timer, SDHCIState),
- VMSTATE_END_OF_LIST()
- },
- .subsections = (const VMStateDescription*[]) {
- &sdhci_pending_insert_vmstate,
- NULL
- },
-};
-
-/* Capabilities registers provide information on supported features of this
- * specific host controller implementation */
-static Property sdhci_pci_properties[] = {
- DEFINE_PROP_UINT32("capareg", SDHCIState, capareg,
- SDHC_CAPAB_REG_DEFAULT),
- DEFINE_PROP_UINT32("maxcurr", SDHCIState, maxcurr, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void sdhci_pci_realize(PCIDevice *dev, Error **errp)
-{
- SDHCIState *s = PCI_SDHCI(dev);
- dev->config[PCI_CLASS_PROG] = 0x01; /* Standard Host supported DMA */
- dev->config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */
- sdhci_initfn(s);
- s->buf_maxsz = sdhci_get_fifolen(s);
- s->fifo_buffer = g_malloc0(s->buf_maxsz);
- s->irq = pci_allocate_irq(dev);
- memory_region_init_io(&s->iomem, OBJECT(s), &sdhci_mmio_ops, s, "sdhci",
- SDHC_REGISTERS_MAP_SIZE);
- pci_register_bar(dev, 0, 0, &s->iomem);
-}
-
-static void sdhci_pci_exit(PCIDevice *dev)
-{
- SDHCIState *s = PCI_SDHCI(dev);
- sdhci_uninitfn(s);
-}
-
-static void sdhci_pci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = sdhci_pci_realize;
- k->exit = sdhci_pci_exit;
- k->vendor_id = PCI_VENDOR_ID_REDHAT;
- k->device_id = PCI_DEVICE_ID_REDHAT_SDHCI;
- k->class_id = PCI_CLASS_SYSTEM_SDHCI;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
- dc->vmsd = &sdhci_vmstate;
- dc->props = sdhci_pci_properties;
- dc->reset = sdhci_poweron_reset;
-}
-
-static const TypeInfo sdhci_pci_info = {
- .name = TYPE_PCI_SDHCI,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(SDHCIState),
- .class_init = sdhci_pci_class_init,
-};
-
-static Property sdhci_sysbus_properties[] = {
- DEFINE_PROP_UINT32("capareg", SDHCIState, capareg,
- SDHC_CAPAB_REG_DEFAULT),
- DEFINE_PROP_UINT32("maxcurr", SDHCIState, maxcurr, 0),
- DEFINE_PROP_BOOL("pending-insert-quirk", SDHCIState, pending_insert_quirk,
- false),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void sdhci_sysbus_init(Object *obj)
-{
- SDHCIState *s = SYSBUS_SDHCI(obj);
-
- sdhci_initfn(s);
-}
-
-static void sdhci_sysbus_finalize(Object *obj)
-{
- SDHCIState *s = SYSBUS_SDHCI(obj);
- sdhci_uninitfn(s);
-}
-
-static void sdhci_sysbus_realize(DeviceState *dev, Error ** errp)
-{
- SDHCIState *s = SYSBUS_SDHCI(dev);
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
-
- s->buf_maxsz = sdhci_get_fifolen(s);
- s->fifo_buffer = g_malloc0(s->buf_maxsz);
- sysbus_init_irq(sbd, &s->irq);
- memory_region_init_io(&s->iomem, OBJECT(s), &sdhci_mmio_ops, s, "sdhci",
- SDHC_REGISTERS_MAP_SIZE);
- sysbus_init_mmio(sbd, &s->iomem);
-}
-
-static void sdhci_sysbus_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->vmsd = &sdhci_vmstate;
- dc->props = sdhci_sysbus_properties;
- dc->realize = sdhci_sysbus_realize;
- dc->reset = sdhci_poweron_reset;
-}
-
-static const TypeInfo sdhci_sysbus_info = {
- .name = TYPE_SYSBUS_SDHCI,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(SDHCIState),
- .instance_init = sdhci_sysbus_init,
- .instance_finalize = sdhci_sysbus_finalize,
- .class_init = sdhci_sysbus_class_init,
-};
-
-static void sdhci_bus_class_init(ObjectClass *klass, void *data)
-{
- SDBusClass *sbc = SD_BUS_CLASS(klass);
-
- sbc->set_inserted = sdhci_set_inserted;
- sbc->set_readonly = sdhci_set_readonly;
-}
-
-static const TypeInfo sdhci_bus_info = {
- .name = TYPE_SDHCI_BUS,
- .parent = TYPE_SD_BUS,
- .instance_size = sizeof(SDBus),
- .class_init = sdhci_bus_class_init,
-};
-
-static void sdhci_register_types(void)
-{
- type_register_static(&sdhci_pci_info);
- type_register_static(&sdhci_sysbus_info);
- type_register_static(&sdhci_bus_info);
-}
-
-type_init(sdhci_register_types)
diff --git a/qemu/hw/sd/ssi-sd.c b/qemu/hw/sd/ssi-sd.c
deleted file mode 100644
index 075e4ed5d..000000000
--- a/qemu/hw/sd/ssi-sd.c
+++ /dev/null
@@ -1,290 +0,0 @@
-/*
- * SSI to SD card adapter.
- *
- * Copyright (c) 2007-2009 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
-#include "hw/ssi/ssi.h"
-#include "hw/sd/sd.h"
-
-//#define DEBUG_SSI_SD 1
-
-#ifdef DEBUG_SSI_SD
-#define DPRINTF(fmt, ...) \
-do { printf("ssi_sd: " fmt , ## __VA_ARGS__); } while (0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "ssi_sd: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "ssi_sd: error: " fmt , ## __VA_ARGS__);} while (0)
-#endif
-
-typedef enum {
- SSI_SD_CMD,
- SSI_SD_CMDARG,
- SSI_SD_RESPONSE,
- SSI_SD_DATA_START,
- SSI_SD_DATA_READ,
-} ssi_sd_mode;
-
-typedef struct {
- SSISlave ssidev;
- ssi_sd_mode mode;
- int cmd;
- uint8_t cmdarg[4];
- uint8_t response[5];
- int arglen;
- int response_pos;
- int stopping;
- SDState *sd;
-} ssi_sd_state;
-
-/* State word bits. */
-#define SSI_SDR_LOCKED 0x0001
-#define SSI_SDR_WP_ERASE 0x0002
-#define SSI_SDR_ERROR 0x0004
-#define SSI_SDR_CC_ERROR 0x0008
-#define SSI_SDR_ECC_FAILED 0x0010
-#define SSI_SDR_WP_VIOLATION 0x0020
-#define SSI_SDR_ERASE_PARAM 0x0040
-#define SSI_SDR_OUT_OF_RANGE 0x0080
-#define SSI_SDR_IDLE 0x0100
-#define SSI_SDR_ERASE_RESET 0x0200
-#define SSI_SDR_ILLEGAL_COMMAND 0x0400
-#define SSI_SDR_COM_CRC_ERROR 0x0800
-#define SSI_SDR_ERASE_SEQ_ERROR 0x1000
-#define SSI_SDR_ADDRESS_ERROR 0x2000
-#define SSI_SDR_PARAMETER_ERROR 0x4000
-
-static uint32_t ssi_sd_transfer(SSISlave *dev, uint32_t val)
-{
- ssi_sd_state *s = FROM_SSI_SLAVE(ssi_sd_state, dev);
-
- /* Special case: allow CMD12 (STOP TRANSMISSION) while reading data. */
- if (s->mode == SSI_SD_DATA_READ && val == 0x4d) {
- s->mode = SSI_SD_CMD;
- /* There must be at least one byte delay before the card responds. */
- s->stopping = 1;
- }
-
- switch (s->mode) {
- case SSI_SD_CMD:
- if (val == 0xff) {
- DPRINTF("NULL command\n");
- return 0xff;
- }
- s->cmd = val & 0x3f;
- s->mode = SSI_SD_CMDARG;
- s->arglen = 0;
- return 0xff;
- case SSI_SD_CMDARG:
- if (s->arglen == 4) {
- SDRequest request;
- uint8_t longresp[16];
- /* FIXME: Check CRC. */
- request.cmd = s->cmd;
- request.arg = (s->cmdarg[0] << 24) | (s->cmdarg[1] << 16)
- | (s->cmdarg[2] << 8) | s->cmdarg[3];
- DPRINTF("CMD%d arg 0x%08x\n", s->cmd, request.arg);
- s->arglen = sd_do_command(s->sd, &request, longresp);
- if (s->arglen <= 0) {
- s->arglen = 1;
- s->response[0] = 4;
- DPRINTF("SD command failed\n");
- } else if (s->cmd == 58) {
- /* CMD58 returns R3 response (OCR) */
- DPRINTF("Returned OCR\n");
- s->arglen = 5;
- s->response[0] = 1;
- memcpy(&s->response[1], longresp, 4);
- } else if (s->arglen != 4) {
- BADF("Unexpected response to cmd %d\n", s->cmd);
- /* Illegal command is about as near as we can get. */
- s->arglen = 1;
- s->response[0] = 4;
- } else {
- /* All other commands return status. */
- uint32_t cardstatus;
- uint16_t status;
- /* CMD13 returns a 2-byte statuse work. Other commands
- only return the first byte. */
- s->arglen = (s->cmd == 13) ? 2 : 1;
- cardstatus = (longresp[0] << 24) | (longresp[1] << 16)
- | (longresp[2] << 8) | longresp[3];
- status = 0;
- if (((cardstatus >> 9) & 0xf) < 4)
- status |= SSI_SDR_IDLE;
- if (cardstatus & ERASE_RESET)
- status |= SSI_SDR_ERASE_RESET;
- if (cardstatus & ILLEGAL_COMMAND)
- status |= SSI_SDR_ILLEGAL_COMMAND;
- if (cardstatus & COM_CRC_ERROR)
- status |= SSI_SDR_COM_CRC_ERROR;
- if (cardstatus & ERASE_SEQ_ERROR)
- status |= SSI_SDR_ERASE_SEQ_ERROR;
- if (cardstatus & ADDRESS_ERROR)
- status |= SSI_SDR_ADDRESS_ERROR;
- if (cardstatus & CARD_IS_LOCKED)
- status |= SSI_SDR_LOCKED;
- if (cardstatus & (LOCK_UNLOCK_FAILED | WP_ERASE_SKIP))
- status |= SSI_SDR_WP_ERASE;
- if (cardstatus & SD_ERROR)
- status |= SSI_SDR_ERROR;
- if (cardstatus & CC_ERROR)
- status |= SSI_SDR_CC_ERROR;
- if (cardstatus & CARD_ECC_FAILED)
- status |= SSI_SDR_ECC_FAILED;
- if (cardstatus & WP_VIOLATION)
- status |= SSI_SDR_WP_VIOLATION;
- if (cardstatus & ERASE_PARAM)
- status |= SSI_SDR_ERASE_PARAM;
- if (cardstatus & (OUT_OF_RANGE | CID_CSD_OVERWRITE))
- status |= SSI_SDR_OUT_OF_RANGE;
- /* ??? Don't know what Parameter Error really means, so
- assume it's set if the second byte is nonzero. */
- if (status & 0xff)
- status |= SSI_SDR_PARAMETER_ERROR;
- s->response[0] = status >> 8;
- s->response[1] = status;
- DPRINTF("Card status 0x%02x\n", status);
- }
- s->mode = SSI_SD_RESPONSE;
- s->response_pos = 0;
- } else {
- s->cmdarg[s->arglen++] = val;
- }
- return 0xff;
- case SSI_SD_RESPONSE:
- if (s->stopping) {
- s->stopping = 0;
- return 0xff;
- }
- if (s->response_pos < s->arglen) {
- DPRINTF("Response 0x%02x\n", s->response[s->response_pos]);
- return s->response[s->response_pos++];
- }
- if (sd_data_ready(s->sd)) {
- DPRINTF("Data read\n");
- s->mode = SSI_SD_DATA_START;
- } else {
- DPRINTF("End of command\n");
- s->mode = SSI_SD_CMD;
- }
- return 0xff;
- case SSI_SD_DATA_START:
- DPRINTF("Start read block\n");
- s->mode = SSI_SD_DATA_READ;
- return 0xfe;
- case SSI_SD_DATA_READ:
- val = sd_read_data(s->sd);
- if (!sd_data_ready(s->sd)) {
- DPRINTF("Data read end\n");
- s->mode = SSI_SD_CMD;
- }
- return val;
- }
- /* Should never happen. */
- return 0xff;
-}
-
-static void ssi_sd_save(QEMUFile *f, void *opaque)
-{
- SSISlave *ss = SSI_SLAVE(opaque);
- ssi_sd_state *s = (ssi_sd_state *)opaque;
- int i;
-
- qemu_put_be32(f, s->mode);
- qemu_put_be32(f, s->cmd);
- for (i = 0; i < 4; i++)
- qemu_put_be32(f, s->cmdarg[i]);
- for (i = 0; i < 5; i++)
- qemu_put_be32(f, s->response[i]);
- qemu_put_be32(f, s->arglen);
- qemu_put_be32(f, s->response_pos);
- qemu_put_be32(f, s->stopping);
-
- qemu_put_be32(f, ss->cs);
-}
-
-static int ssi_sd_load(QEMUFile *f, void *opaque, int version_id)
-{
- SSISlave *ss = SSI_SLAVE(opaque);
- ssi_sd_state *s = (ssi_sd_state *)opaque;
- int i;
-
- if (version_id != 1)
- return -EINVAL;
-
- s->mode = qemu_get_be32(f);
- s->cmd = qemu_get_be32(f);
- for (i = 0; i < 4; i++)
- s->cmdarg[i] = qemu_get_be32(f);
- for (i = 0; i < 5; i++)
- s->response[i] = qemu_get_be32(f);
- s->arglen = qemu_get_be32(f);
- if (s->mode == SSI_SD_CMDARG &&
- (s->arglen < 0 || s->arglen >= ARRAY_SIZE(s->cmdarg))) {
- return -EINVAL;
- }
- s->response_pos = qemu_get_be32(f);
- s->stopping = qemu_get_be32(f);
- if (s->mode == SSI_SD_RESPONSE &&
- (s->response_pos < 0 || s->response_pos >= ARRAY_SIZE(s->response) ||
- (!s->stopping && s->arglen > ARRAY_SIZE(s->response)))) {
- return -EINVAL;
- }
-
- ss->cs = qemu_get_be32(f);
-
- return 0;
-}
-
-static int ssi_sd_init(SSISlave *d)
-{
- DeviceState *dev = DEVICE(d);
- ssi_sd_state *s = FROM_SSI_SLAVE(ssi_sd_state, d);
- DriveInfo *dinfo;
-
- s->mode = SSI_SD_CMD;
- /* FIXME use a qdev drive property instead of drive_get_next() */
- dinfo = drive_get_next(IF_SD);
- s->sd = sd_init(dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, true);
- if (s->sd == NULL) {
- return -1;
- }
- register_savevm(dev, "ssi_sd", -1, 1, ssi_sd_save, ssi_sd_load, s);
- return 0;
-}
-
-static void ssi_sd_class_init(ObjectClass *klass, void *data)
-{
- SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
-
- k->init = ssi_sd_init;
- k->transfer = ssi_sd_transfer;
- k->cs_polarity = SSI_CS_LOW;
-}
-
-static const TypeInfo ssi_sd_info = {
- .name = "ssi-sd",
- .parent = TYPE_SSI_SLAVE,
- .instance_size = sizeof(ssi_sd_state),
- .class_init = ssi_sd_class_init,
-};
-
-static void ssi_sd_register_types(void)
-{
- type_register_static(&ssi_sd_info);
-}
-
-type_init(ssi_sd_register_types)
diff --git a/qemu/hw/sh4/Makefile.objs b/qemu/hw/sh4/Makefile.objs
deleted file mode 100644
index 2393702c5..000000000
--- a/qemu/hw/sh4/Makefile.objs
+++ /dev/null
@@ -1,4 +0,0 @@
-obj-y += shix.o r2d.o
-
-obj-y += sh7750.o sh7750_regnames.o
-obj-y += sh_pci.o
diff --git a/qemu/hw/sh4/r2d.c b/qemu/hw/sh4/r2d.c
deleted file mode 100644
index db373c70c..000000000
--- a/qemu/hw/sh4/r2d.c
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- * Renesas SH7751R R2D-PLUS emulation
- *
- * Copyright (c) 2007 Magnus Damm
- * Copyright (c) 2008 Paul Mundt
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/sysbus.h"
-#include "hw/hw.h"
-#include "hw/sh4/sh.h"
-#include "hw/devices.h"
-#include "sysemu/sysemu.h"
-#include "hw/boards.h"
-#include "hw/pci/pci.h"
-#include "net/net.h"
-#include "sh7750_regs.h"
-#include "hw/ide.h"
-#include "hw/loader.h"
-#include "hw/usb.h"
-#include "hw/block/flash.h"
-#include "sysemu/block-backend.h"
-#include "exec/address-spaces.h"
-
-#define FLASH_BASE 0x00000000
-#define FLASH_SIZE 0x02000000
-
-#define SDRAM_BASE 0x0c000000 /* Physical location of SDRAM: Area 3 */
-#define SDRAM_SIZE 0x04000000
-
-#define SM501_VRAM_SIZE 0x800000
-
-#define BOOT_PARAMS_OFFSET 0x0010000
-/* CONFIG_BOOT_LINK_OFFSET of Linux kernel */
-#define LINUX_LOAD_OFFSET 0x0800000
-#define INITRD_LOAD_OFFSET 0x1800000
-
-#define PA_IRLMSK 0x00
-#define PA_POWOFF 0x30
-#define PA_VERREG 0x32
-#define PA_OUTPORT 0x36
-
-typedef struct {
- uint16_t bcr;
- uint16_t irlmsk;
- uint16_t irlmon;
- uint16_t cfctl;
- uint16_t cfpow;
- uint16_t dispctl;
- uint16_t sdmpow;
- uint16_t rtcce;
- uint16_t pcicd;
- uint16_t voyagerrts;
- uint16_t cfrst;
- uint16_t admrts;
- uint16_t extrst;
- uint16_t cfcdintclr;
- uint16_t keyctlclr;
- uint16_t pad0;
- uint16_t pad1;
- uint16_t verreg;
- uint16_t inport;
- uint16_t outport;
- uint16_t bverreg;
-
-/* output pin */
- qemu_irq irl;
- MemoryRegion iomem;
-} r2d_fpga_t;
-
-enum r2d_fpga_irq {
- PCI_INTD, CF_IDE, CF_CD, PCI_INTC, SM501, KEY, RTC_A, RTC_T,
- SDCARD, PCI_INTA, PCI_INTB, EXT, TP,
- NR_IRQS
-};
-
-static const struct { short irl; uint16_t msk; } irqtab[NR_IRQS] = {
- [CF_IDE] = { 1, 1<<9 },
- [CF_CD] = { 2, 1<<8 },
- [PCI_INTA] = { 9, 1<<14 },
- [PCI_INTB] = { 10, 1<<13 },
- [PCI_INTC] = { 3, 1<<12 },
- [PCI_INTD] = { 0, 1<<11 },
- [SM501] = { 4, 1<<10 },
- [KEY] = { 5, 1<<6 },
- [RTC_A] = { 6, 1<<5 },
- [RTC_T] = { 7, 1<<4 },
- [SDCARD] = { 8, 1<<7 },
- [EXT] = { 11, 1<<0 },
- [TP] = { 12, 1<<15 },
-};
-
-static void update_irl(r2d_fpga_t *fpga)
-{
- int i, irl = 15;
- for (i = 0; i < NR_IRQS; i++)
- if (fpga->irlmon & fpga->irlmsk & irqtab[i].msk)
- if (irqtab[i].irl < irl)
- irl = irqtab[i].irl;
- qemu_set_irq(fpga->irl, irl ^ 15);
-}
-
-static void r2d_fpga_irq_set(void *opaque, int n, int level)
-{
- r2d_fpga_t *fpga = opaque;
- if (level)
- fpga->irlmon |= irqtab[n].msk;
- else
- fpga->irlmon &= ~irqtab[n].msk;
- update_irl(fpga);
-}
-
-static uint64_t r2d_fpga_read(void *opaque, hwaddr addr, unsigned int size)
-{
- r2d_fpga_t *s = opaque;
-
- switch (addr) {
- case PA_IRLMSK:
- return s->irlmsk;
- case PA_OUTPORT:
- return s->outport;
- case PA_POWOFF:
- return 0x00;
- case PA_VERREG:
- return 0x10;
- }
-
- return 0;
-}
-
-static void
-r2d_fpga_write(void *opaque, hwaddr addr, uint64_t value, unsigned int size)
-{
- r2d_fpga_t *s = opaque;
-
- switch (addr) {
- case PA_IRLMSK:
- s->irlmsk = value;
- update_irl(s);
- break;
- case PA_OUTPORT:
- s->outport = value;
- break;
- case PA_POWOFF:
- if (value & 1) {
- qemu_system_shutdown_request();
- }
- break;
- case PA_VERREG:
- /* Discard writes */
- break;
- }
-}
-
-static const MemoryRegionOps r2d_fpga_ops = {
- .read = r2d_fpga_read,
- .write = r2d_fpga_write,
- .impl.min_access_size = 2,
- .impl.max_access_size = 2,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static qemu_irq *r2d_fpga_init(MemoryRegion *sysmem,
- hwaddr base, qemu_irq irl)
-{
- r2d_fpga_t *s;
-
- s = g_malloc0(sizeof(r2d_fpga_t));
-
- s->irl = irl;
-
- memory_region_init_io(&s->iomem, NULL, &r2d_fpga_ops, s, "r2d-fpga", 0x40);
- memory_region_add_subregion(sysmem, base, &s->iomem);
- return qemu_allocate_irqs(r2d_fpga_irq_set, s, NR_IRQS);
-}
-
-typedef struct ResetData {
- SuperHCPU *cpu;
- uint32_t vector;
-} ResetData;
-
-static void main_cpu_reset(void *opaque)
-{
- ResetData *s = (ResetData *)opaque;
- CPUSH4State *env = &s->cpu->env;
-
- cpu_reset(CPU(s->cpu));
- env->pc = s->vector;
-}
-
-static struct QEMU_PACKED
-{
- int mount_root_rdonly;
- int ramdisk_flags;
- int orig_root_dev;
- int loader_type;
- int initrd_start;
- int initrd_size;
-
- char pad[232];
-
- char kernel_cmdline[256];
-} boot_params;
-
-static void r2d_init(MachineState *machine)
-{
- const char *cpu_model = machine->cpu_model;
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- const char *initrd_filename = machine->initrd_filename;
- SuperHCPU *cpu;
- CPUSH4State *env;
- ResetData *reset_info;
- struct SH7750State *s;
- MemoryRegion *sdram = g_new(MemoryRegion, 1);
- qemu_irq *irq;
- DriveInfo *dinfo;
- int i;
- DeviceState *dev;
- SysBusDevice *busdev;
- MemoryRegion *address_space_mem = get_system_memory();
- PCIBus *pci_bus;
-
- if (cpu_model == NULL) {
- cpu_model = "SH7751R";
- }
-
- cpu = cpu_sh4_init(cpu_model);
- if (cpu == NULL) {
- fprintf(stderr, "Unable to find CPU definition\n");
- exit(1);
- }
- env = &cpu->env;
-
- reset_info = g_malloc0(sizeof(ResetData));
- reset_info->cpu = cpu;
- reset_info->vector = env->pc;
- qemu_register_reset(main_cpu_reset, reset_info);
-
- /* Allocate memory space */
- memory_region_init_ram(sdram, NULL, "r2d.sdram", SDRAM_SIZE, &error_fatal);
- vmstate_register_ram_global(sdram);
- memory_region_add_subregion(address_space_mem, SDRAM_BASE, sdram);
- /* Register peripherals */
- s = sh7750_init(cpu, address_space_mem);
- irq = r2d_fpga_init(address_space_mem, 0x04000000, sh7750_irl(s));
-
- dev = qdev_create(NULL, "sh_pci");
- busdev = SYS_BUS_DEVICE(dev);
- qdev_init_nofail(dev);
- pci_bus = PCI_BUS(qdev_get_child_bus(dev, "pci"));
- sysbus_mmio_map(busdev, 0, P4ADDR(0x1e200000));
- sysbus_mmio_map(busdev, 1, A7ADDR(0x1e200000));
- sysbus_connect_irq(busdev, 0, irq[PCI_INTA]);
- sysbus_connect_irq(busdev, 1, irq[PCI_INTB]);
- sysbus_connect_irq(busdev, 2, irq[PCI_INTC]);
- sysbus_connect_irq(busdev, 3, irq[PCI_INTD]);
-
- sm501_init(address_space_mem, 0x10000000, SM501_VRAM_SIZE,
- irq[SM501], serial_hds[2]);
-
- /* onboard CF (True IDE mode, Master only). */
- dinfo = drive_get(IF_IDE, 0, 0);
- dev = qdev_create(NULL, "mmio-ide");
- busdev = SYS_BUS_DEVICE(dev);
- sysbus_connect_irq(busdev, 0, irq[CF_IDE]);
- qdev_prop_set_uint32(dev, "shift", 1);
- qdev_init_nofail(dev);
- sysbus_mmio_map(busdev, 0, 0x14001000);
- sysbus_mmio_map(busdev, 1, 0x1400080c);
- mmio_ide_init_drives(dev, dinfo, NULL);
-
- /* onboard flash memory */
- dinfo = drive_get(IF_PFLASH, 0, 0);
- pflash_cfi02_register(0x0, NULL, "r2d.flash", FLASH_SIZE,
- dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- (16 * 1024), FLASH_SIZE >> 16,
- 1, 4, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x555, 0x2aa, 0);
-
- /* NIC: rtl8139 on-board, and 2 slots. */
- for (i = 0; i < nb_nics; i++)
- pci_nic_init_nofail(&nd_table[i], pci_bus,
- "rtl8139", i==0 ? "2" : NULL);
-
- /* USB keyboard */
- usb_create_simple(usb_bus_find(-1), "usb-kbd");
-
- /* Todo: register on board registers */
- memset(&boot_params, 0, sizeof(boot_params));
-
- if (kernel_filename) {
- int kernel_size;
-
- kernel_size = load_image_targphys(kernel_filename,
- SDRAM_BASE + LINUX_LOAD_OFFSET,
- INITRD_LOAD_OFFSET - LINUX_LOAD_OFFSET);
- if (kernel_size < 0) {
- fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename);
- exit(1);
- }
-
- /* initialization which should be done by firmware */
- address_space_stl(&address_space_memory, SH7750_BCR1, 1 << 3,
- MEMTXATTRS_UNSPECIFIED, NULL); /* cs3 SDRAM */
- address_space_stw(&address_space_memory, SH7750_BCR2, 3 << (3 * 2),
- MEMTXATTRS_UNSPECIFIED, NULL); /* cs3 32bit */
- reset_info->vector = (SDRAM_BASE + LINUX_LOAD_OFFSET) | 0xa0000000; /* Start from P2 area */
- }
-
- if (initrd_filename) {
- int initrd_size;
-
- initrd_size = load_image_targphys(initrd_filename,
- SDRAM_BASE + INITRD_LOAD_OFFSET,
- SDRAM_SIZE - INITRD_LOAD_OFFSET);
-
- if (initrd_size < 0) {
- fprintf(stderr, "qemu: could not load initrd '%s'\n", initrd_filename);
- exit(1);
- }
-
- /* initialization which should be done by firmware */
- boot_params.loader_type = tswap32(1);
- boot_params.initrd_start = tswap32(INITRD_LOAD_OFFSET);
- boot_params.initrd_size = tswap32(initrd_size);
- }
-
- if (kernel_cmdline) {
- /* I see no evidence that this .kernel_cmdline buffer requires
- NUL-termination, so using strncpy should be ok. */
- strncpy(boot_params.kernel_cmdline, kernel_cmdline,
- sizeof(boot_params.kernel_cmdline));
- }
-
- rom_add_blob_fixed("boot_params", &boot_params, sizeof(boot_params),
- SDRAM_BASE + BOOT_PARAMS_OFFSET);
-}
-
-static void r2d_machine_init(MachineClass *mc)
-{
- mc->desc = "r2d-plus board";
- mc->init = r2d_init;
-}
-
-DEFINE_MACHINE("r2d", r2d_machine_init)
diff --git a/qemu/hw/sh4/sh7750.c b/qemu/hw/sh4/sh7750.c
deleted file mode 100644
index a1ea760f6..000000000
--- a/qemu/hw/sh4/sh7750.c
+++ /dev/null
@@ -1,842 +0,0 @@
-/*
- * SH7750 device
- *
- * Copyright (c) 2007 Magnus Damm
- * Copyright (c) 2005 Samuel Tardieu
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/sh4/sh.h"
-#include "sysemu/sysemu.h"
-#include "sh7750_regs.h"
-#include "sh7750_regnames.h"
-#include "hw/sh4/sh_intc.h"
-#include "cpu.h"
-#include "exec/address-spaces.h"
-
-#define NB_DEVICES 4
-
-typedef struct SH7750State {
- MemoryRegion iomem;
- MemoryRegion iomem_1f0;
- MemoryRegion iomem_ff0;
- MemoryRegion iomem_1f8;
- MemoryRegion iomem_ff8;
- MemoryRegion iomem_1fc;
- MemoryRegion iomem_ffc;
- MemoryRegion mmct_iomem;
- /* CPU */
- SuperHCPU *cpu;
- /* Peripheral frequency in Hz */
- uint32_t periph_freq;
- /* SDRAM controller */
- uint32_t bcr1;
- uint16_t bcr2;
- uint16_t bcr3;
- uint32_t bcr4;
- uint16_t rfcr;
- /* PCMCIA controller */
- uint16_t pcr;
- /* IO ports */
- uint16_t gpioic;
- uint32_t pctra;
- uint32_t pctrb;
- uint16_t portdira; /* Cached */
- uint16_t portpullupa; /* Cached */
- uint16_t portdirb; /* Cached */
- uint16_t portpullupb; /* Cached */
- uint16_t pdtra;
- uint16_t pdtrb;
- uint16_t periph_pdtra; /* Imposed by the peripherals */
- uint16_t periph_portdira; /* Direction seen from the peripherals */
- uint16_t periph_pdtrb; /* Imposed by the peripherals */
- uint16_t periph_portdirb; /* Direction seen from the peripherals */
- sh7750_io_device *devices[NB_DEVICES]; /* External peripherals */
-
- /* Cache */
- uint32_t ccr;
-
- struct intc_desc intc;
-} SH7750State;
-
-static inline int has_bcr3_and_bcr4(SH7750State * s)
-{
- return s->cpu->env.features & SH_FEATURE_BCR3_AND_BCR4;
-}
-/**********************************************************************
- I/O ports
-**********************************************************************/
-
-int sh7750_register_io_device(SH7750State * s, sh7750_io_device * device)
-{
- int i;
-
- for (i = 0; i < NB_DEVICES; i++) {
- if (s->devices[i] == NULL) {
- s->devices[i] = device;
- return 0;
- }
- }
- return -1;
-}
-
-static uint16_t portdir(uint32_t v)
-{
-#define EVENPORTMASK(n) ((v & (1<<((n)<<1))) >> (n))
- return
- EVENPORTMASK(15) | EVENPORTMASK(14) | EVENPORTMASK(13) |
- EVENPORTMASK(12) | EVENPORTMASK(11) | EVENPORTMASK(10) |
- EVENPORTMASK(9) | EVENPORTMASK(8) | EVENPORTMASK(7) |
- EVENPORTMASK(6) | EVENPORTMASK(5) | EVENPORTMASK(4) |
- EVENPORTMASK(3) | EVENPORTMASK(2) | EVENPORTMASK(1) |
- EVENPORTMASK(0);
-}
-
-static uint16_t portpullup(uint32_t v)
-{
-#define ODDPORTMASK(n) ((v & (1<<(((n)<<1)+1))) >> (n))
- return
- ODDPORTMASK(15) | ODDPORTMASK(14) | ODDPORTMASK(13) |
- ODDPORTMASK(12) | ODDPORTMASK(11) | ODDPORTMASK(10) |
- ODDPORTMASK(9) | ODDPORTMASK(8) | ODDPORTMASK(7) | ODDPORTMASK(6) |
- ODDPORTMASK(5) | ODDPORTMASK(4) | ODDPORTMASK(3) | ODDPORTMASK(2) |
- ODDPORTMASK(1) | ODDPORTMASK(0);
-}
-
-static uint16_t porta_lines(SH7750State * s)
-{
- return (s->portdira & s->pdtra) | /* CPU */
- (s->periph_portdira & s->periph_pdtra) | /* Peripherals */
- (~(s->portdira | s->periph_portdira) & s->portpullupa); /* Pullups */
-}
-
-static uint16_t portb_lines(SH7750State * s)
-{
- return (s->portdirb & s->pdtrb) | /* CPU */
- (s->periph_portdirb & s->periph_pdtrb) | /* Peripherals */
- (~(s->portdirb | s->periph_portdirb) & s->portpullupb); /* Pullups */
-}
-
-static void gen_port_interrupts(SH7750State * s)
-{
- /* XXXXX interrupts not generated */
-}
-
-static void porta_changed(SH7750State * s, uint16_t prev)
-{
- uint16_t currenta, changes;
- int i, r = 0;
-
-#if 0
- fprintf(stderr, "porta changed from 0x%04x to 0x%04x\n",
- prev, porta_lines(s));
- fprintf(stderr, "pdtra=0x%04x, pctra=0x%08x\n", s->pdtra, s->pctra);
-#endif
- currenta = porta_lines(s);
- if (currenta == prev)
- return;
- changes = currenta ^ prev;
-
- for (i = 0; i < NB_DEVICES; i++) {
- if (s->devices[i] && (s->devices[i]->portamask_trigger & changes)) {
- r |= s->devices[i]->port_change_cb(currenta, portb_lines(s),
- &s->periph_pdtra,
- &s->periph_portdira,
- &s->periph_pdtrb,
- &s->periph_portdirb);
- }
- }
-
- if (r)
- gen_port_interrupts(s);
-}
-
-static void portb_changed(SH7750State * s, uint16_t prev)
-{
- uint16_t currentb, changes;
- int i, r = 0;
-
- currentb = portb_lines(s);
- if (currentb == prev)
- return;
- changes = currentb ^ prev;
-
- for (i = 0; i < NB_DEVICES; i++) {
- if (s->devices[i] && (s->devices[i]->portbmask_trigger & changes)) {
- r |= s->devices[i]->port_change_cb(portb_lines(s), currentb,
- &s->periph_pdtra,
- &s->periph_portdira,
- &s->periph_pdtrb,
- &s->periph_portdirb);
- }
- }
-
- if (r)
- gen_port_interrupts(s);
-}
-
-/**********************************************************************
- Memory
-**********************************************************************/
-
-static void error_access(const char *kind, hwaddr addr)
-{
- fprintf(stderr, "%s to %s (0x" TARGET_FMT_plx ") not supported\n",
- kind, regname(addr), addr);
-}
-
-static void ignore_access(const char *kind, hwaddr addr)
-{
- fprintf(stderr, "%s to %s (0x" TARGET_FMT_plx ") ignored\n",
- kind, regname(addr), addr);
-}
-
-static uint32_t sh7750_mem_readb(void *opaque, hwaddr addr)
-{
- switch (addr) {
- default:
- error_access("byte read", addr);
- abort();
- }
-}
-
-static uint32_t sh7750_mem_readw(void *opaque, hwaddr addr)
-{
- SH7750State *s = opaque;
-
- switch (addr) {
- case SH7750_BCR2_A7:
- return s->bcr2;
- case SH7750_BCR3_A7:
- if(!has_bcr3_and_bcr4(s))
- error_access("word read", addr);
- return s->bcr3;
- case SH7750_FRQCR_A7:
- return 0;
- case SH7750_PCR_A7:
- return s->pcr;
- case SH7750_RFCR_A7:
- fprintf(stderr,
- "Read access to refresh count register, incrementing\n");
- return s->rfcr++;
- case SH7750_PDTRA_A7:
- return porta_lines(s);
- case SH7750_PDTRB_A7:
- return portb_lines(s);
- case SH7750_RTCOR_A7:
- case SH7750_RTCNT_A7:
- case SH7750_RTCSR_A7:
- ignore_access("word read", addr);
- return 0;
- default:
- error_access("word read", addr);
- abort();
- }
-}
-
-static uint32_t sh7750_mem_readl(void *opaque, hwaddr addr)
-{
- SH7750State *s = opaque;
- SuperHCPUClass *scc;
-
- switch (addr) {
- case SH7750_BCR1_A7:
- return s->bcr1;
- case SH7750_BCR4_A7:
- if(!has_bcr3_and_bcr4(s))
- error_access("long read", addr);
- return s->bcr4;
- case SH7750_WCR1_A7:
- case SH7750_WCR2_A7:
- case SH7750_WCR3_A7:
- case SH7750_MCR_A7:
- ignore_access("long read", addr);
- return 0;
- case SH7750_MMUCR_A7:
- return s->cpu->env.mmucr;
- case SH7750_PTEH_A7:
- return s->cpu->env.pteh;
- case SH7750_PTEL_A7:
- return s->cpu->env.ptel;
- case SH7750_TTB_A7:
- return s->cpu->env.ttb;
- case SH7750_TEA_A7:
- return s->cpu->env.tea;
- case SH7750_TRA_A7:
- return s->cpu->env.tra;
- case SH7750_EXPEVT_A7:
- return s->cpu->env.expevt;
- case SH7750_INTEVT_A7:
- return s->cpu->env.intevt;
- case SH7750_CCR_A7:
- return s->ccr;
- case 0x1f000030: /* Processor version */
- scc = SUPERH_CPU_GET_CLASS(s->cpu);
- return scc->pvr;
- case 0x1f000040: /* Cache version */
- scc = SUPERH_CPU_GET_CLASS(s->cpu);
- return scc->cvr;
- case 0x1f000044: /* Processor revision */
- scc = SUPERH_CPU_GET_CLASS(s->cpu);
- return scc->prr;
- default:
- error_access("long read", addr);
- abort();
- }
-}
-
-#define is_in_sdrmx(a, x) (a >= SH7750_SDMR ## x ## _A7 \
- && a <= (SH7750_SDMR ## x ## _A7 + SH7750_SDMR ## x ## _REGNB))
-static void sh7750_mem_writeb(void *opaque, hwaddr addr,
- uint32_t mem_value)
-{
-
- if (is_in_sdrmx(addr, 2) || is_in_sdrmx(addr, 3)) {
- ignore_access("byte write", addr);
- return;
- }
-
- error_access("byte write", addr);
- abort();
-}
-
-static void sh7750_mem_writew(void *opaque, hwaddr addr,
- uint32_t mem_value)
-{
- SH7750State *s = opaque;
- uint16_t temp;
-
- switch (addr) {
- /* SDRAM controller */
- case SH7750_BCR2_A7:
- s->bcr2 = mem_value;
- return;
- case SH7750_BCR3_A7:
- if(!has_bcr3_and_bcr4(s))
- error_access("word write", addr);
- s->bcr3 = mem_value;
- return;
- case SH7750_PCR_A7:
- s->pcr = mem_value;
- return;
- case SH7750_RTCNT_A7:
- case SH7750_RTCOR_A7:
- case SH7750_RTCSR_A7:
- ignore_access("word write", addr);
- return;
- /* IO ports */
- case SH7750_PDTRA_A7:
- temp = porta_lines(s);
- s->pdtra = mem_value;
- porta_changed(s, temp);
- return;
- case SH7750_PDTRB_A7:
- temp = portb_lines(s);
- s->pdtrb = mem_value;
- portb_changed(s, temp);
- return;
- case SH7750_RFCR_A7:
- fprintf(stderr, "Write access to refresh count register\n");
- s->rfcr = mem_value;
- return;
- case SH7750_GPIOIC_A7:
- s->gpioic = mem_value;
- if (mem_value != 0) {
- fprintf(stderr, "I/O interrupts not implemented\n");
- abort();
- }
- return;
- default:
- error_access("word write", addr);
- abort();
- }
-}
-
-static void sh7750_mem_writel(void *opaque, hwaddr addr,
- uint32_t mem_value)
-{
- SH7750State *s = opaque;
- uint16_t temp;
-
- switch (addr) {
- /* SDRAM controller */
- case SH7750_BCR1_A7:
- s->bcr1 = mem_value;
- return;
- case SH7750_BCR4_A7:
- if(!has_bcr3_and_bcr4(s))
- error_access("long write", addr);
- s->bcr4 = mem_value;
- return;
- case SH7750_WCR1_A7:
- case SH7750_WCR2_A7:
- case SH7750_WCR3_A7:
- case SH7750_MCR_A7:
- ignore_access("long write", addr);
- return;
- /* IO ports */
- case SH7750_PCTRA_A7:
- temp = porta_lines(s);
- s->pctra = mem_value;
- s->portdira = portdir(mem_value);
- s->portpullupa = portpullup(mem_value);
- porta_changed(s, temp);
- return;
- case SH7750_PCTRB_A7:
- temp = portb_lines(s);
- s->pctrb = mem_value;
- s->portdirb = portdir(mem_value);
- s->portpullupb = portpullup(mem_value);
- portb_changed(s, temp);
- return;
- case SH7750_MMUCR_A7:
- if (mem_value & MMUCR_TI) {
- cpu_sh4_invalidate_tlb(&s->cpu->env);
- }
- s->cpu->env.mmucr = mem_value & ~MMUCR_TI;
- return;
- case SH7750_PTEH_A7:
- /* If asid changes, clear all registered tlb entries. */
- if ((s->cpu->env.pteh & 0xff) != (mem_value & 0xff)) {
- tlb_flush(CPU(s->cpu), 1);
- }
- s->cpu->env.pteh = mem_value;
- return;
- case SH7750_PTEL_A7:
- s->cpu->env.ptel = mem_value;
- return;
- case SH7750_PTEA_A7:
- s->cpu->env.ptea = mem_value & 0x0000000f;
- return;
- case SH7750_TTB_A7:
- s->cpu->env.ttb = mem_value;
- return;
- case SH7750_TEA_A7:
- s->cpu->env.tea = mem_value;
- return;
- case SH7750_TRA_A7:
- s->cpu->env.tra = mem_value & 0x000007ff;
- return;
- case SH7750_EXPEVT_A7:
- s->cpu->env.expevt = mem_value & 0x000007ff;
- return;
- case SH7750_INTEVT_A7:
- s->cpu->env.intevt = mem_value & 0x000007ff;
- return;
- case SH7750_CCR_A7:
- s->ccr = mem_value;
- return;
- default:
- error_access("long write", addr);
- abort();
- }
-}
-
-static const MemoryRegionOps sh7750_mem_ops = {
- .old_mmio = {
- .read = {sh7750_mem_readb,
- sh7750_mem_readw,
- sh7750_mem_readl },
- .write = {sh7750_mem_writeb,
- sh7750_mem_writew,
- sh7750_mem_writel },
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-/* sh775x interrupt controller tables for sh_intc.c
- * stolen from linux/arch/sh/kernel/cpu/sh4/setup-sh7750.c
- */
-
-enum {
- UNUSED = 0,
-
- /* interrupt sources */
- IRL_0, IRL_1, IRL_2, IRL_3, IRL_4, IRL_5, IRL_6, IRL_7,
- IRL_8, IRL_9, IRL_A, IRL_B, IRL_C, IRL_D, IRL_E,
- IRL0, IRL1, IRL2, IRL3,
- HUDI, GPIOI,
- DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2, DMAC_DMTE3,
- DMAC_DMTE4, DMAC_DMTE5, DMAC_DMTE6, DMAC_DMTE7,
- DMAC_DMAE,
- PCIC0_PCISERR, PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON,
- PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, PCIC1_PCIDMA3,
- TMU3, TMU4, TMU0, TMU1, TMU2_TUNI, TMU2_TICPI,
- RTC_ATI, RTC_PRI, RTC_CUI,
- SCI1_ERI, SCI1_RXI, SCI1_TXI, SCI1_TEI,
- SCIF_ERI, SCIF_RXI, SCIF_BRI, SCIF_TXI,
- WDT,
- REF_RCMI, REF_ROVI,
-
- /* interrupt groups */
- DMAC, PCIC1, TMU2, RTC, SCI1, SCIF, REF,
- /* irl bundle */
- IRL,
-
- NR_SOURCES,
-};
-
-static struct intc_vect vectors[] = {
- INTC_VECT(HUDI, 0x600), INTC_VECT(GPIOI, 0x620),
- INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
- INTC_VECT(TMU2_TUNI, 0x440), INTC_VECT(TMU2_TICPI, 0x460),
- INTC_VECT(RTC_ATI, 0x480), INTC_VECT(RTC_PRI, 0x4a0),
- INTC_VECT(RTC_CUI, 0x4c0),
- INTC_VECT(SCI1_ERI, 0x4e0), INTC_VECT(SCI1_RXI, 0x500),
- INTC_VECT(SCI1_TXI, 0x520), INTC_VECT(SCI1_TEI, 0x540),
- INTC_VECT(SCIF_ERI, 0x700), INTC_VECT(SCIF_RXI, 0x720),
- INTC_VECT(SCIF_BRI, 0x740), INTC_VECT(SCIF_TXI, 0x760),
- INTC_VECT(WDT, 0x560),
- INTC_VECT(REF_RCMI, 0x580), INTC_VECT(REF_ROVI, 0x5a0),
-};
-
-static struct intc_group groups[] = {
- INTC_GROUP(TMU2, TMU2_TUNI, TMU2_TICPI),
- INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
- INTC_GROUP(SCI1, SCI1_ERI, SCI1_RXI, SCI1_TXI, SCI1_TEI),
- INTC_GROUP(SCIF, SCIF_ERI, SCIF_RXI, SCIF_BRI, SCIF_TXI),
- INTC_GROUP(REF, REF_RCMI, REF_ROVI),
-};
-
-static struct intc_prio_reg prio_registers[] = {
- { 0xffd00004, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } },
- { 0xffd00008, 0, 16, 4, /* IPRB */ { WDT, REF, SCI1, 0 } },
- { 0xffd0000c, 0, 16, 4, /* IPRC */ { GPIOI, DMAC, SCIF, HUDI } },
- { 0xffd00010, 0, 16, 4, /* IPRD */ { IRL0, IRL1, IRL2, IRL3 } },
- { 0xfe080000, 0, 32, 4, /* INTPRI00 */ { 0, 0, 0, 0,
- TMU4, TMU3,
- PCIC1, PCIC0_PCISERR } },
-};
-
-/* SH7750, SH7750S, SH7751 and SH7091 all have 4-channel DMA controllers */
-
-static struct intc_vect vectors_dma4[] = {
- INTC_VECT(DMAC_DMTE0, 0x640), INTC_VECT(DMAC_DMTE1, 0x660),
- INTC_VECT(DMAC_DMTE2, 0x680), INTC_VECT(DMAC_DMTE3, 0x6a0),
- INTC_VECT(DMAC_DMAE, 0x6c0),
-};
-
-static struct intc_group groups_dma4[] = {
- INTC_GROUP(DMAC, DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2,
- DMAC_DMTE3, DMAC_DMAE),
-};
-
-/* SH7750R and SH7751R both have 8-channel DMA controllers */
-
-static struct intc_vect vectors_dma8[] = {
- INTC_VECT(DMAC_DMTE0, 0x640), INTC_VECT(DMAC_DMTE1, 0x660),
- INTC_VECT(DMAC_DMTE2, 0x680), INTC_VECT(DMAC_DMTE3, 0x6a0),
- INTC_VECT(DMAC_DMTE4, 0x780), INTC_VECT(DMAC_DMTE5, 0x7a0),
- INTC_VECT(DMAC_DMTE6, 0x7c0), INTC_VECT(DMAC_DMTE7, 0x7e0),
- INTC_VECT(DMAC_DMAE, 0x6c0),
-};
-
-static struct intc_group groups_dma8[] = {
- INTC_GROUP(DMAC, DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2,
- DMAC_DMTE3, DMAC_DMTE4, DMAC_DMTE5,
- DMAC_DMTE6, DMAC_DMTE7, DMAC_DMAE),
-};
-
-/* SH7750R, SH7751 and SH7751R all have two extra timer channels */
-
-static struct intc_vect vectors_tmu34[] = {
- INTC_VECT(TMU3, 0xb00), INTC_VECT(TMU4, 0xb80),
-};
-
-static struct intc_mask_reg mask_registers[] = {
- { 0xfe080040, 0xfe080060, 32, /* INTMSK00 / INTMSKCLR00 */
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, TMU4, TMU3,
- PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON,
- PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2,
- PCIC1_PCIDMA3, PCIC0_PCISERR } },
-};
-
-/* SH7750S, SH7750R, SH7751 and SH7751R all have IRLM priority registers */
-
-static struct intc_vect vectors_irlm[] = {
- INTC_VECT(IRL0, 0x240), INTC_VECT(IRL1, 0x2a0),
- INTC_VECT(IRL2, 0x300), INTC_VECT(IRL3, 0x360),
-};
-
-/* SH7751 and SH7751R both have PCI */
-
-static struct intc_vect vectors_pci[] = {
- INTC_VECT(PCIC0_PCISERR, 0xa00), INTC_VECT(PCIC1_PCIERR, 0xae0),
- INTC_VECT(PCIC1_PCIPWDWN, 0xac0), INTC_VECT(PCIC1_PCIPWON, 0xaa0),
- INTC_VECT(PCIC1_PCIDMA0, 0xa80), INTC_VECT(PCIC1_PCIDMA1, 0xa60),
- INTC_VECT(PCIC1_PCIDMA2, 0xa40), INTC_VECT(PCIC1_PCIDMA3, 0xa20),
-};
-
-static struct intc_group groups_pci[] = {
- INTC_GROUP(PCIC1, PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON,
- PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, PCIC1_PCIDMA3),
-};
-
-static struct intc_vect vectors_irl[] = {
- INTC_VECT(IRL_0, 0x200),
- INTC_VECT(IRL_1, 0x220),
- INTC_VECT(IRL_2, 0x240),
- INTC_VECT(IRL_3, 0x260),
- INTC_VECT(IRL_4, 0x280),
- INTC_VECT(IRL_5, 0x2a0),
- INTC_VECT(IRL_6, 0x2c0),
- INTC_VECT(IRL_7, 0x2e0),
- INTC_VECT(IRL_8, 0x300),
- INTC_VECT(IRL_9, 0x320),
- INTC_VECT(IRL_A, 0x340),
- INTC_VECT(IRL_B, 0x360),
- INTC_VECT(IRL_C, 0x380),
- INTC_VECT(IRL_D, 0x3a0),
- INTC_VECT(IRL_E, 0x3c0),
-};
-
-static struct intc_group groups_irl[] = {
- INTC_GROUP(IRL, IRL_0, IRL_1, IRL_2, IRL_3, IRL_4, IRL_5, IRL_6,
- IRL_7, IRL_8, IRL_9, IRL_A, IRL_B, IRL_C, IRL_D, IRL_E),
-};
-
-/**********************************************************************
- Memory mapped cache and TLB
-**********************************************************************/
-
-#define MM_REGION_MASK 0x07000000
-#define MM_ICACHE_ADDR (0)
-#define MM_ICACHE_DATA (1)
-#define MM_ITLB_ADDR (2)
-#define MM_ITLB_DATA (3)
-#define MM_OCACHE_ADDR (4)
-#define MM_OCACHE_DATA (5)
-#define MM_UTLB_ADDR (6)
-#define MM_UTLB_DATA (7)
-#define MM_REGION_TYPE(addr) ((addr & MM_REGION_MASK) >> 24)
-
-static uint64_t invalid_read(void *opaque, hwaddr addr)
-{
- abort();
-
- return 0;
-}
-
-static uint64_t sh7750_mmct_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- SH7750State *s = opaque;
- uint32_t ret = 0;
-
- if (size != 4) {
- return invalid_read(opaque, addr);
- }
-
- switch (MM_REGION_TYPE(addr)) {
- case MM_ICACHE_ADDR:
- case MM_ICACHE_DATA:
- /* do nothing */
- break;
- case MM_ITLB_ADDR:
- ret = cpu_sh4_read_mmaped_itlb_addr(&s->cpu->env, addr);
- break;
- case MM_ITLB_DATA:
- ret = cpu_sh4_read_mmaped_itlb_data(&s->cpu->env, addr);
- break;
- case MM_OCACHE_ADDR:
- case MM_OCACHE_DATA:
- /* do nothing */
- break;
- case MM_UTLB_ADDR:
- ret = cpu_sh4_read_mmaped_utlb_addr(&s->cpu->env, addr);
- break;
- case MM_UTLB_DATA:
- ret = cpu_sh4_read_mmaped_utlb_data(&s->cpu->env, addr);
- break;
- default:
- abort();
- }
-
- return ret;
-}
-
-static void invalid_write(void *opaque, hwaddr addr,
- uint64_t mem_value)
-{
- abort();
-}
-
-static void sh7750_mmct_write(void *opaque, hwaddr addr,
- uint64_t mem_value, unsigned size)
-{
- SH7750State *s = opaque;
-
- if (size != 4) {
- invalid_write(opaque, addr, mem_value);
- }
-
- switch (MM_REGION_TYPE(addr)) {
- case MM_ICACHE_ADDR:
- case MM_ICACHE_DATA:
- /* do nothing */
- break;
- case MM_ITLB_ADDR:
- cpu_sh4_write_mmaped_itlb_addr(&s->cpu->env, addr, mem_value);
- break;
- case MM_ITLB_DATA:
- cpu_sh4_write_mmaped_itlb_data(&s->cpu->env, addr, mem_value);
- abort();
- break;
- case MM_OCACHE_ADDR:
- case MM_OCACHE_DATA:
- /* do nothing */
- break;
- case MM_UTLB_ADDR:
- cpu_sh4_write_mmaped_utlb_addr(&s->cpu->env, addr, mem_value);
- break;
- case MM_UTLB_DATA:
- cpu_sh4_write_mmaped_utlb_data(&s->cpu->env, addr, mem_value);
- break;
- default:
- abort();
- break;
- }
-}
-
-static const MemoryRegionOps sh7750_mmct_ops = {
- .read = sh7750_mmct_read,
- .write = sh7750_mmct_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-SH7750State *sh7750_init(SuperHCPU *cpu, MemoryRegion *sysmem)
-{
- SH7750State *s;
-
- s = g_malloc0(sizeof(SH7750State));
- s->cpu = cpu;
- s->periph_freq = 60000000; /* 60MHz */
- memory_region_init_io(&s->iomem, NULL, &sh7750_mem_ops, s,
- "memory", 0x1fc01000);
-
- memory_region_init_alias(&s->iomem_1f0, NULL, "memory-1f0",
- &s->iomem, 0x1f000000, 0x1000);
- memory_region_add_subregion(sysmem, 0x1f000000, &s->iomem_1f0);
-
- memory_region_init_alias(&s->iomem_ff0, NULL, "memory-ff0",
- &s->iomem, 0x1f000000, 0x1000);
- memory_region_add_subregion(sysmem, 0xff000000, &s->iomem_ff0);
-
- memory_region_init_alias(&s->iomem_1f8, NULL, "memory-1f8",
- &s->iomem, 0x1f800000, 0x1000);
- memory_region_add_subregion(sysmem, 0x1f800000, &s->iomem_1f8);
-
- memory_region_init_alias(&s->iomem_ff8, NULL, "memory-ff8",
- &s->iomem, 0x1f800000, 0x1000);
- memory_region_add_subregion(sysmem, 0xff800000, &s->iomem_ff8);
-
- memory_region_init_alias(&s->iomem_1fc, NULL, "memory-1fc",
- &s->iomem, 0x1fc00000, 0x1000);
- memory_region_add_subregion(sysmem, 0x1fc00000, &s->iomem_1fc);
-
- memory_region_init_alias(&s->iomem_ffc, NULL, "memory-ffc",
- &s->iomem, 0x1fc00000, 0x1000);
- memory_region_add_subregion(sysmem, 0xffc00000, &s->iomem_ffc);
-
- memory_region_init_io(&s->mmct_iomem, NULL, &sh7750_mmct_ops, s,
- "cache-and-tlb", 0x08000000);
- memory_region_add_subregion(sysmem, 0xf0000000, &s->mmct_iomem);
-
- sh_intc_init(sysmem, &s->intc, NR_SOURCES,
- _INTC_ARRAY(mask_registers),
- _INTC_ARRAY(prio_registers));
-
- sh_intc_register_sources(&s->intc,
- _INTC_ARRAY(vectors),
- _INTC_ARRAY(groups));
-
- cpu->env.intc_handle = &s->intc;
-
- sh_serial_init(sysmem, 0x1fe00000,
- 0, s->periph_freq, serial_hds[0],
- s->intc.irqs[SCI1_ERI],
- s->intc.irqs[SCI1_RXI],
- s->intc.irqs[SCI1_TXI],
- s->intc.irqs[SCI1_TEI],
- NULL);
- sh_serial_init(sysmem, 0x1fe80000,
- SH_SERIAL_FEAT_SCIF,
- s->periph_freq, serial_hds[1],
- s->intc.irqs[SCIF_ERI],
- s->intc.irqs[SCIF_RXI],
- s->intc.irqs[SCIF_TXI],
- NULL,
- s->intc.irqs[SCIF_BRI]);
-
- tmu012_init(sysmem, 0x1fd80000,
- TMU012_FEAT_TOCR | TMU012_FEAT_3CHAN | TMU012_FEAT_EXTCLK,
- s->periph_freq,
- s->intc.irqs[TMU0],
- s->intc.irqs[TMU1],
- s->intc.irqs[TMU2_TUNI],
- s->intc.irqs[TMU2_TICPI]);
-
- if (cpu->env.id & (SH_CPU_SH7750 | SH_CPU_SH7750S | SH_CPU_SH7751)) {
- sh_intc_register_sources(&s->intc,
- _INTC_ARRAY(vectors_dma4),
- _INTC_ARRAY(groups_dma4));
- }
-
- if (cpu->env.id & (SH_CPU_SH7750R | SH_CPU_SH7751R)) {
- sh_intc_register_sources(&s->intc,
- _INTC_ARRAY(vectors_dma8),
- _INTC_ARRAY(groups_dma8));
- }
-
- if (cpu->env.id & (SH_CPU_SH7750R | SH_CPU_SH7751 | SH_CPU_SH7751R)) {
- sh_intc_register_sources(&s->intc,
- _INTC_ARRAY(vectors_tmu34),
- NULL, 0);
- tmu012_init(sysmem, 0x1e100000, 0, s->periph_freq,
- s->intc.irqs[TMU3],
- s->intc.irqs[TMU4],
- NULL, NULL);
- }
-
- if (cpu->env.id & (SH_CPU_SH7751_ALL)) {
- sh_intc_register_sources(&s->intc,
- _INTC_ARRAY(vectors_pci),
- _INTC_ARRAY(groups_pci));
- }
-
- if (cpu->env.id & (SH_CPU_SH7750S | SH_CPU_SH7750R | SH_CPU_SH7751_ALL)) {
- sh_intc_register_sources(&s->intc,
- _INTC_ARRAY(vectors_irlm),
- NULL, 0);
- }
-
- sh_intc_register_sources(&s->intc,
- _INTC_ARRAY(vectors_irl),
- _INTC_ARRAY(groups_irl));
- return s;
-}
-
-qemu_irq sh7750_irl(SH7750State *s)
-{
- sh_intc_toggle_source(sh_intc_source(&s->intc, IRL), 1, 0); /* enable */
- return qemu_allocate_irq(sh_intc_set_irl, sh_intc_source(&s->intc, IRL), 0);
-}
diff --git a/qemu/hw/sh4/sh7750_regnames.c b/qemu/hw/sh4/sh7750_regnames.c
deleted file mode 100644
index 34b4f99b8..000000000
--- a/qemu/hw/sh4/sh7750_regnames.c
+++ /dev/null
@@ -1,98 +0,0 @@
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/sh4/sh.h"
-#include "sh7750_regs.h"
-#include "sh7750_regnames.h"
-
-#define REGNAME(r) {r, #r},
-
-typedef struct {
- uint32_t regaddr;
- const char *regname;
-} regname_t;
-
-static regname_t regnames[] = {
- REGNAME(SH7750_PTEH_A7)
- REGNAME(SH7750_PTEL_A7)
- REGNAME(SH7750_PTEA_A7)
- REGNAME(SH7750_TTB_A7)
- REGNAME(SH7750_TEA_A7)
- REGNAME(SH7750_MMUCR_A7)
- REGNAME(SH7750_CCR_A7)
- REGNAME(SH7750_QACR0_A7)
- REGNAME(SH7750_QACR1_A7)
- REGNAME(SH7750_TRA_A7)
- REGNAME(SH7750_EXPEVT_A7)
- REGNAME(SH7750_INTEVT_A7)
- REGNAME(SH7750_STBCR_A7)
- REGNAME(SH7750_STBCR2_A7)
- REGNAME(SH7750_FRQCR_A7)
- REGNAME(SH7750_WTCNT_A7)
- REGNAME(SH7750_WTCSR_A7)
- REGNAME(SH7750_R64CNT_A7)
- REGNAME(SH7750_RSECCNT_A7)
- REGNAME(SH7750_RMINCNT_A7)
- REGNAME(SH7750_RHRCNT_A7)
- REGNAME(SH7750_RWKCNT_A7)
- REGNAME(SH7750_RDAYCNT_A7)
- REGNAME(SH7750_RMONCNT_A7)
- REGNAME(SH7750_RYRCNT_A7)
- REGNAME(SH7750_RSECAR_A7)
- REGNAME(SH7750_RMINAR_A7)
- REGNAME(SH7750_RHRAR_A7)
- REGNAME(SH7750_RWKAR_A7)
- REGNAME(SH7750_RDAYAR_A7)
- REGNAME(SH7750_RMONAR_A7)
- REGNAME(SH7750_RCR1_A7)
- REGNAME(SH7750_RCR2_A7)
- REGNAME(SH7750_BCR1_A7)
- REGNAME(SH7750_BCR2_A7)
- REGNAME(SH7750_WCR1_A7)
- REGNAME(SH7750_WCR2_A7)
- REGNAME(SH7750_WCR3_A7)
- REGNAME(SH7750_MCR_A7)
- REGNAME(SH7750_PCR_A7)
- REGNAME(SH7750_RTCSR_A7)
- REGNAME(SH7750_RTCNT_A7)
- REGNAME(SH7750_RTCOR_A7)
- REGNAME(SH7750_RFCR_A7)
- REGNAME(SH7750_SAR0_A7)
- REGNAME(SH7750_SAR1_A7)
- REGNAME(SH7750_SAR2_A7)
- REGNAME(SH7750_SAR3_A7)
- REGNAME(SH7750_DAR0_A7)
- REGNAME(SH7750_DAR1_A7)
- REGNAME(SH7750_DAR2_A7)
- REGNAME(SH7750_DAR3_A7)
- REGNAME(SH7750_DMATCR0_A7)
- REGNAME(SH7750_DMATCR1_A7)
- REGNAME(SH7750_DMATCR2_A7)
- REGNAME(SH7750_DMATCR3_A7)
- REGNAME(SH7750_CHCR0_A7)
- REGNAME(SH7750_CHCR1_A7)
- REGNAME(SH7750_CHCR2_A7)
- REGNAME(SH7750_CHCR3_A7)
- REGNAME(SH7750_DMAOR_A7)
- REGNAME(SH7750_PCTRA_A7)
- REGNAME(SH7750_PDTRA_A7)
- REGNAME(SH7750_PCTRB_A7)
- REGNAME(SH7750_PDTRB_A7)
- REGNAME(SH7750_GPIOIC_A7)
- REGNAME(SH7750_ICR_A7)
- REGNAME(SH7750_BCR3_A7)
- REGNAME(SH7750_BCR4_A7)
- REGNAME(SH7750_SDMR2_A7)
- REGNAME(SH7750_SDMR3_A7) {(uint32_t) - 1, NULL}
-};
-
-const char *regname(uint32_t addr)
-{
- unsigned int i;
-
- for (i = 0; regnames[i].regaddr != (uint32_t) - 1; i++) {
- if (regnames[i].regaddr == addr)
- return regnames[i].regname;
- }
-
- return "<unknown reg>";
-}
diff --git a/qemu/hw/sh4/sh7750_regnames.h b/qemu/hw/sh4/sh7750_regnames.h
deleted file mode 100644
index 7463709b4..000000000
--- a/qemu/hw/sh4/sh7750_regnames.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _SH7750_REGNAMES_H
-#define _SH7750_REGNAMES_H
-
-const char *regname(uint32_t addr);
-
-#endif /* _SH7750_REGNAMES_H */
diff --git a/qemu/hw/sh4/sh7750_regs.h b/qemu/hw/sh4/sh7750_regs.h
deleted file mode 100644
index 534aa4840..000000000
--- a/qemu/hw/sh4/sh7750_regs.h
+++ /dev/null
@@ -1,1277 +0,0 @@
-/*
- * SH-7750 memory-mapped registers
- * This file based on information provided in the following document:
- * "Hitachi SuperH (tm) RISC engine. SH7750 Series (SH7750, SH7750S)
- * Hardware Manual"
- * Document Number ADE-602-124C, Rev. 4.0, 4/21/00, Hitachi Ltd.
- *
- * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
- * Author: Alexandra Kossovsky <sasha@oktet.ru>
- * Victor V. Vengerov <vvv@oktet.ru>
- *
- * The license and distribution terms for this file may be
- * found in the file LICENSE in this distribution or at
- * http://www.rtems.com/license/LICENSE.
- *
- * @(#) sh7750_regs.h,v 1.2.4.1 2003/09/04 18:46:00 joel Exp
- */
-
-#ifndef __SH7750_REGS_H__
-#define __SH7750_REGS_H__
-
-/*
- * All register has 2 addresses: in 0xff000000 - 0xffffffff (P4 address) and
- * in 0x1f000000 - 0x1fffffff (area 7 address)
- */
-#define SH7750_P4_BASE 0xff000000 /* Accessible only in
- privileged mode */
-#define SH7750_A7_BASE 0x1f000000 /* Accessible only using TLB */
-
-#define SH7750_P4_REG32(ofs) (SH7750_P4_BASE + (ofs))
-#define SH7750_A7_REG32(ofs) (SH7750_A7_BASE + (ofs))
-
-/*
- * MMU Registers
- */
-
-/* Page Table Entry High register - PTEH */
-#define SH7750_PTEH_REGOFS 0x000000 /* offset */
-#define SH7750_PTEH SH7750_P4_REG32(SH7750_PTEH_REGOFS)
-#define SH7750_PTEH_A7 SH7750_A7_REG32(SH7750_PTEH_REGOFS)
-#define SH7750_PTEH_VPN 0xfffffd00 /* Virtual page number */
-#define SH7750_PTEH_VPN_S 10
-#define SH7750_PTEH_ASID 0x000000ff /* Address space identifier */
-#define SH7750_PTEH_ASID_S 0
-
-/* Page Table Entry Low register - PTEL */
-#define SH7750_PTEL_REGOFS 0x000004 /* offset */
-#define SH7750_PTEL SH7750_P4_REG32(SH7750_PTEL_REGOFS)
-#define SH7750_PTEL_A7 SH7750_A7_REG32(SH7750_PTEL_REGOFS)
-#define SH7750_PTEL_PPN 0x1ffffc00 /* Physical page number */
-#define SH7750_PTEL_PPN_S 10
-#define SH7750_PTEL_V 0x00000100 /* Validity (0-entry is invalid) */
-#define SH7750_PTEL_SZ1 0x00000080 /* Page size bit 1 */
-#define SH7750_PTEL_SZ0 0x00000010 /* Page size bit 0 */
-#define SH7750_PTEL_SZ_1KB 0x00000000 /* 1-kbyte page */
-#define SH7750_PTEL_SZ_4KB 0x00000010 /* 4-kbyte page */
-#define SH7750_PTEL_SZ_64KB 0x00000080 /* 64-kbyte page */
-#define SH7750_PTEL_SZ_1MB 0x00000090 /* 1-Mbyte page */
-#define SH7750_PTEL_PR 0x00000060 /* Protection Key Data */
-#define SH7750_PTEL_PR_ROPO 0x00000000 /* read-only in priv mode */
-#define SH7750_PTEL_PR_RWPO 0x00000020 /* read-write in priv mode */
-#define SH7750_PTEL_PR_ROPU 0x00000040 /* read-only in priv or user mode */
-#define SH7750_PTEL_PR_RWPU 0x00000060 /* read-write in priv or user mode */
-#define SH7750_PTEL_C 0x00000008 /* Cacheability
- (0 - page not cacheable) */
-#define SH7750_PTEL_D 0x00000004 /* Dirty bit (1 - write has been
- performed to a page) */
-#define SH7750_PTEL_SH 0x00000002 /* Share Status bit (1 - page are
- shared by processes) */
-#define SH7750_PTEL_WT 0x00000001 /* Write-through bit, specifies the
- cache write mode:
- 0 - Copy-back mode
- 1 - Write-through mode */
-
-/* Page Table Entry Assistance register - PTEA */
-#define SH7750_PTEA_REGOFS 0x000034 /* offset */
-#define SH7750_PTEA SH7750_P4_REG32(SH7750_PTEA_REGOFS)
-#define SH7750_PTEA_A7 SH7750_A7_REG32(SH7750_PTEA_REGOFS)
-#define SH7750_PTEA_TC 0x00000008 /* Timing Control bit
- 0 - use area 5 wait states
- 1 - use area 6 wait states */
-#define SH7750_PTEA_SA 0x00000007 /* Space Attribute bits: */
-#define SH7750_PTEA_SA_UNDEF 0x00000000 /* 0 - undefined */
-#define SH7750_PTEA_SA_IOVAR 0x00000001 /* 1 - variable-size I/O space */
-#define SH7750_PTEA_SA_IO8 0x00000002 /* 2 - 8-bit I/O space */
-#define SH7750_PTEA_SA_IO16 0x00000003 /* 3 - 16-bit I/O space */
-#define SH7750_PTEA_SA_CMEM8 0x00000004 /* 4 - 8-bit common memory space */
-#define SH7750_PTEA_SA_CMEM16 0x00000005 /* 5 - 16-bit common memory space */
-#define SH7750_PTEA_SA_AMEM8 0x00000006 /* 6 - 8-bit attr memory space */
-#define SH7750_PTEA_SA_AMEM16 0x00000007 /* 7 - 16-bit attr memory space */
-
-
-/* Translation table base register */
-#define SH7750_TTB_REGOFS 0x000008 /* offset */
-#define SH7750_TTB SH7750_P4_REG32(SH7750_TTB_REGOFS)
-#define SH7750_TTB_A7 SH7750_A7_REG32(SH7750_TTB_REGOFS)
-
-/* TLB exeption address register - TEA */
-#define SH7750_TEA_REGOFS 0x00000c /* offset */
-#define SH7750_TEA SH7750_P4_REG32(SH7750_TEA_REGOFS)
-#define SH7750_TEA_A7 SH7750_A7_REG32(SH7750_TEA_REGOFS)
-
-/* MMU control register - MMUCR */
-#define SH7750_MMUCR_REGOFS 0x000010 /* offset */
-#define SH7750_MMUCR SH7750_P4_REG32(SH7750_MMUCR_REGOFS)
-#define SH7750_MMUCR_A7 SH7750_A7_REG32(SH7750_MMUCR_REGOFS)
-#define SH7750_MMUCR_AT 0x00000001 /* Address translation bit */
-#define SH7750_MMUCR_TI 0x00000004 /* TLB invalidate */
-#define SH7750_MMUCR_SV 0x00000100 /* Single Virtual Mode bit */
-#define SH7750_MMUCR_SQMD 0x00000200 /* Store Queue Mode bit */
-#define SH7750_MMUCR_URC 0x0000FC00 /* UTLB Replace Counter */
-#define SH7750_MMUCR_URC_S 10
-#define SH7750_MMUCR_URB 0x00FC0000 /* UTLB Replace Boundary */
-#define SH7750_MMUCR_URB_S 18
-#define SH7750_MMUCR_LRUI 0xFC000000 /* Least Recently Used ITLB */
-#define SH7750_MMUCR_LRUI_S 26
-
-
-
-
-/*
- * Cache registers
- * IC -- instructions cache
- * OC -- operand cache
- */
-
-/* Cache Control Register - CCR */
-#define SH7750_CCR_REGOFS 0x00001c /* offset */
-#define SH7750_CCR SH7750_P4_REG32(SH7750_CCR_REGOFS)
-#define SH7750_CCR_A7 SH7750_A7_REG32(SH7750_CCR_REGOFS)
-
-#define SH7750_CCR_IIX 0x00008000 /* IC index enable bit */
-#define SH7750_CCR_ICI 0x00000800 /* IC invalidation bit:
- set it to clear IC */
-#define SH7750_CCR_ICE 0x00000100 /* IC enable bit */
-#define SH7750_CCR_OIX 0x00000080 /* OC index enable bit */
-#define SH7750_CCR_ORA 0x00000020 /* OC RAM enable bit
- if you set OCE = 0,
- you should set ORA = 0 */
-#define SH7750_CCR_OCI 0x00000008 /* OC invalidation bit */
-#define SH7750_CCR_CB 0x00000004 /* Copy-back bit for P1 area */
-#define SH7750_CCR_WT 0x00000002 /* Write-through bit for P0,U0,P3 area */
-#define SH7750_CCR_OCE 0x00000001 /* OC enable bit */
-
-/* Queue address control register 0 - QACR0 */
-#define SH7750_QACR0_REGOFS 0x000038 /* offset */
-#define SH7750_QACR0 SH7750_P4_REG32(SH7750_QACR0_REGOFS)
-#define SH7750_QACR0_A7 SH7750_A7_REG32(SH7750_QACR0_REGOFS)
-
-/* Queue address control register 1 - QACR1 */
-#define SH7750_QACR1_REGOFS 0x00003c /* offset */
-#define SH7750_QACR1 SH7750_P4_REG32(SH7750_QACR1_REGOFS)
-#define SH7750_QACR1_A7 SH7750_A7_REG32(SH7750_QACR1_REGOFS)
-
-
-/*
- * Exeption-related registers
- */
-
-/* Immediate data for TRAPA instruction - TRA */
-#define SH7750_TRA_REGOFS 0x000020 /* offset */
-#define SH7750_TRA SH7750_P4_REG32(SH7750_TRA_REGOFS)
-#define SH7750_TRA_A7 SH7750_A7_REG32(SH7750_TRA_REGOFS)
-
-#define SH7750_TRA_IMM 0x000003fd /* Immediate data operand */
-#define SH7750_TRA_IMM_S 2
-
-/* Exeption event register - EXPEVT */
-#define SH7750_EXPEVT_REGOFS 0x000024
-#define SH7750_EXPEVT SH7750_P4_REG32(SH7750_EXPEVT_REGOFS)
-#define SH7750_EXPEVT_A7 SH7750_A7_REG32(SH7750_EXPEVT_REGOFS)
-
-#define SH7750_EXPEVT_EX 0x00000fff /* Exeption code */
-#define SH7750_EXPEVT_EX_S 0
-
-/* Interrupt event register */
-#define SH7750_INTEVT_REGOFS 0x000028
-#define SH7750_INTEVT SH7750_P4_REG32(SH7750_INTEVT_REGOFS)
-#define SH7750_INTEVT_A7 SH7750_A7_REG32(SH7750_INTEVT_REGOFS)
-#define SH7750_INTEVT_EX 0x00000fff /* Exeption code */
-#define SH7750_INTEVT_EX_S 0
-
-/*
- * Exception/interrupt codes
- */
-#define SH7750_EVT_TO_NUM(evt) ((evt) >> 5)
-
-/* Reset exception category */
-#define SH7750_EVT_POWER_ON_RST 0x000 /* Power-on reset */
-#define SH7750_EVT_MANUAL_RST 0x020 /* Manual reset */
-#define SH7750_EVT_TLB_MULT_HIT 0x140 /* TLB multiple-hit exception */
-
-/* General exception category */
-#define SH7750_EVT_USER_BREAK 0x1E0 /* User break */
-#define SH7750_EVT_IADDR_ERR 0x0E0 /* Instruction address error */
-#define SH7750_EVT_TLB_READ_MISS 0x040 /* ITLB miss exception /
- DTLB miss exception (read) */
-#define SH7750_EVT_TLB_READ_PROTV 0x0A0 /* ITLB protection violation /
- DTLB protection violation (read) */
-#define SH7750_EVT_ILLEGAL_INSTR 0x180 /* General Illegal Instruction
- exception */
-#define SH7750_EVT_SLOT_ILLEGAL_INSTR 0x1A0 /* Slot Illegal Instruction
- exception */
-#define SH7750_EVT_FPU_DISABLE 0x800 /* General FPU disable exception */
-#define SH7750_EVT_SLOT_FPU_DISABLE 0x820 /* Slot FPU disable exception */
-#define SH7750_EVT_DATA_READ_ERR 0x0E0 /* Data address error (read) */
-#define SH7750_EVT_DATA_WRITE_ERR 0x100 /* Data address error (write) */
-#define SH7750_EVT_DTLB_WRITE_MISS 0x060 /* DTLB miss exception (write) */
-#define SH7750_EVT_DTLB_WRITE_PROTV 0x0C0 /* DTLB protection violation
- exception (write) */
-#define SH7750_EVT_FPU_EXCEPTION 0x120 /* FPU exception */
-#define SH7750_EVT_INITIAL_PGWRITE 0x080 /* Initial Page Write exception */
-#define SH7750_EVT_TRAPA 0x160 /* Unconditional trap (TRAPA) */
-
-/* Interrupt exception category */
-#define SH7750_EVT_NMI 0x1C0 /* Non-maskable interrupt */
-#define SH7750_EVT_IRQ0 0x200 /* External Interrupt 0 */
-#define SH7750_EVT_IRQ1 0x220 /* External Interrupt 1 */
-#define SH7750_EVT_IRQ2 0x240 /* External Interrupt 2 */
-#define SH7750_EVT_IRQ3 0x260 /* External Interrupt 3 */
-#define SH7750_EVT_IRQ4 0x280 /* External Interrupt 4 */
-#define SH7750_EVT_IRQ5 0x2A0 /* External Interrupt 5 */
-#define SH7750_EVT_IRQ6 0x2C0 /* External Interrupt 6 */
-#define SH7750_EVT_IRQ7 0x2E0 /* External Interrupt 7 */
-#define SH7750_EVT_IRQ8 0x300 /* External Interrupt 8 */
-#define SH7750_EVT_IRQ9 0x320 /* External Interrupt 9 */
-#define SH7750_EVT_IRQA 0x340 /* External Interrupt A */
-#define SH7750_EVT_IRQB 0x360 /* External Interrupt B */
-#define SH7750_EVT_IRQC 0x380 /* External Interrupt C */
-#define SH7750_EVT_IRQD 0x3A0 /* External Interrupt D */
-#define SH7750_EVT_IRQE 0x3C0 /* External Interrupt E */
-
-/* Peripheral Module Interrupts - Timer Unit (TMU) */
-#define SH7750_EVT_TUNI0 0x400 /* TMU Underflow Interrupt 0 */
-#define SH7750_EVT_TUNI1 0x420 /* TMU Underflow Interrupt 1 */
-#define SH7750_EVT_TUNI2 0x440 /* TMU Underflow Interrupt 2 */
-#define SH7750_EVT_TICPI2 0x460 /* TMU Input Capture Interrupt 2 */
-
-/* Peripheral Module Interrupts - Real-Time Clock (RTC) */
-#define SH7750_EVT_RTC_ATI 0x480 /* Alarm Interrupt Request */
-#define SH7750_EVT_RTC_PRI 0x4A0 /* Periodic Interrupt Request */
-#define SH7750_EVT_RTC_CUI 0x4C0 /* Carry Interrupt Request */
-
-/* Peripheral Module Interrupts - Serial Communication Interface (SCI) */
-#define SH7750_EVT_SCI_ERI 0x4E0 /* Receive Error */
-#define SH7750_EVT_SCI_RXI 0x500 /* Receive Data Register Full */
-#define SH7750_EVT_SCI_TXI 0x520 /* Transmit Data Register Empty */
-#define SH7750_EVT_SCI_TEI 0x540 /* Transmit End */
-
-/* Peripheral Module Interrupts - Watchdog Timer (WDT) */
-#define SH7750_EVT_WDT_ITI 0x560 /* Interval Timer Interrupt
- (used when WDT operates in
- interval timer mode) */
-
-/* Peripheral Module Interrupts - Memory Refresh Unit (REF) */
-#define SH7750_EVT_REF_RCMI 0x580 /* Compare-match Interrupt */
-#define SH7750_EVT_REF_ROVI 0x5A0 /* Refresh Counter Overflow
- interrupt */
-
-/* Peripheral Module Interrupts - Hitachi User Debug Interface (H-UDI) */
-#define SH7750_EVT_HUDI 0x600 /* UDI interrupt */
-
-/* Peripheral Module Interrupts - General-Purpose I/O (GPIO) */
-#define SH7750_EVT_GPIO 0x620 /* GPIO Interrupt */
-
-/* Peripheral Module Interrupts - DMA Controller (DMAC) */
-#define SH7750_EVT_DMAC_DMTE0 0x640 /* DMAC 0 Transfer End Interrupt */
-#define SH7750_EVT_DMAC_DMTE1 0x660 /* DMAC 1 Transfer End Interrupt */
-#define SH7750_EVT_DMAC_DMTE2 0x680 /* DMAC 2 Transfer End Interrupt */
-#define SH7750_EVT_DMAC_DMTE3 0x6A0 /* DMAC 3 Transfer End Interrupt */
-#define SH7750_EVT_DMAC_DMAE 0x6C0 /* DMAC Address Error Interrupt */
-
-/* Peripheral Module Interrupts - Serial Communication Interface with FIFO */
-/* (SCIF) */
-#define SH7750_EVT_SCIF_ERI 0x700 /* Receive Error */
-#define SH7750_EVT_SCIF_RXI 0x720 /* Receive FIFO Data Full or
- Receive Data ready interrupt */
-#define SH7750_EVT_SCIF_BRI 0x740 /* Break or overrun error */
-#define SH7750_EVT_SCIF_TXI 0x760 /* Transmit FIFO Data Empty */
-
-/*
- * Power Management
- */
-#define SH7750_STBCR_REGOFS 0xC00004 /* offset */
-#define SH7750_STBCR SH7750_P4_REG32(SH7750_STBCR_REGOFS)
-#define SH7750_STBCR_A7 SH7750_A7_REG32(SH7750_STBCR_REGOFS)
-
-#define SH7750_STBCR_STBY 0x80 /* Specifies a transition to standby mode:
- 0 - Transition to SLEEP mode on SLEEP
- 1 - Transition to STANDBY mode on SLEEP */
-#define SH7750_STBCR_PHZ 0x40 /* State of peripheral module pins in
- standby mode:
- 0 - normal state
- 1 - high-impendance state */
-
-#define SH7750_STBCR_PPU 0x20 /* Peripheral module pins pull-up controls */
-#define SH7750_STBCR_MSTP4 0x10 /* Stopping the clock supply to DMAC */
-#define SH7750_STBCR_DMAC_STP SH7750_STBCR_MSTP4
-#define SH7750_STBCR_MSTP3 0x08 /* Stopping the clock supply to SCIF */
-#define SH7750_STBCR_SCIF_STP SH7750_STBCR_MSTP3
-#define SH7750_STBCR_MSTP2 0x04 /* Stopping the clock supply to TMU */
-#define SH7750_STBCR_TMU_STP SH7750_STBCR_MSTP2
-#define SH7750_STBCR_MSTP1 0x02 /* Stopping the clock supply to RTC */
-#define SH7750_STBCR_RTC_STP SH7750_STBCR_MSTP1
-#define SH7750_STBCR_MSPT0 0x01 /* Stopping the clock supply to SCI */
-#define SH7750_STBCR_SCI_STP SH7750_STBCR_MSTP0
-
-#define SH7750_STBCR_STBY 0x80
-
-
-#define SH7750_STBCR2_REGOFS 0xC00010 /* offset */
-#define SH7750_STBCR2 SH7750_P4_REG32(SH7750_STBCR2_REGOFS)
-#define SH7750_STBCR2_A7 SH7750_A7_REG32(SH7750_STBCR2_REGOFS)
-
-#define SH7750_STBCR2_DSLP 0x80 /* Specifies transition to deep sleep mode:
- 0 - transition to sleep or standby mode
- as it is specified in STBY bit
- 1 - transition to deep sleep mode on
- execution of SLEEP instruction */
-#define SH7750_STBCR2_MSTP6 0x02 /* Stopping the clock supply to Store Queue
- in the cache controller */
-#define SH7750_STBCR2_SQ_STP SH7750_STBCR2_MSTP6
-#define SH7750_STBCR2_MSTP5 0x01 /* Stopping the clock supply to the User
- Break Controller (UBC) */
-#define SH7750_STBCR2_UBC_STP SH7750_STBCR2_MSTP5
-
-/*
- * Clock Pulse Generator (CPG)
- */
-#define SH7750_FRQCR_REGOFS 0xC00000 /* offset */
-#define SH7750_FRQCR SH7750_P4_REG32(SH7750_FRQCR_REGOFS)
-#define SH7750_FRQCR_A7 SH7750_A7_REG32(SH7750_FRQCR_REGOFS)
-
-#define SH7750_FRQCR_CKOEN 0x0800 /* Clock Output Enable
- 0 - CKIO pin goes to HiZ/pullup
- 1 - Clock is output from CKIO */
-#define SH7750_FRQCR_PLL1EN 0x0400 /* PLL circuit 1 enable */
-#define SH7750_FRQCR_PLL2EN 0x0200 /* PLL circuit 2 enable */
-
-#define SH7750_FRQCR_IFC 0x01C0 /* CPU clock frequency division ratio: */
-#define SH7750_FRQCR_IFCDIV1 0x0000 /* 0 - * 1 */
-#define SH7750_FRQCR_IFCDIV2 0x0040 /* 1 - * 1/2 */
-#define SH7750_FRQCR_IFCDIV3 0x0080 /* 2 - * 1/3 */
-#define SH7750_FRQCR_IFCDIV4 0x00C0 /* 3 - * 1/4 */
-#define SH7750_FRQCR_IFCDIV6 0x0100 /* 4 - * 1/6 */
-#define SH7750_FRQCR_IFCDIV8 0x0140 /* 5 - * 1/8 */
-
-#define SH7750_FRQCR_BFC 0x0038 /* Bus clock frequency division ratio: */
-#define SH7750_FRQCR_BFCDIV1 0x0000 /* 0 - * 1 */
-#define SH7750_FRQCR_BFCDIV2 0x0008 /* 1 - * 1/2 */
-#define SH7750_FRQCR_BFCDIV3 0x0010 /* 2 - * 1/3 */
-#define SH7750_FRQCR_BFCDIV4 0x0018 /* 3 - * 1/4 */
-#define SH7750_FRQCR_BFCDIV6 0x0020 /* 4 - * 1/6 */
-#define SH7750_FRQCR_BFCDIV8 0x0028 /* 5 - * 1/8 */
-
-#define SH7750_FRQCR_PFC 0x0007 /* Peripheral module clock frequency
- division ratio: */
-#define SH7750_FRQCR_PFCDIV2 0x0000 /* 0 - * 1/2 */
-#define SH7750_FRQCR_PFCDIV3 0x0001 /* 1 - * 1/3 */
-#define SH7750_FRQCR_PFCDIV4 0x0002 /* 2 - * 1/4 */
-#define SH7750_FRQCR_PFCDIV6 0x0003 /* 3 - * 1/6 */
-#define SH7750_FRQCR_PFCDIV8 0x0004 /* 4 - * 1/8 */
-
-/*
- * Watchdog Timer (WDT)
- */
-
-/* Watchdog Timer Counter register - WTCNT */
-#define SH7750_WTCNT_REGOFS 0xC00008 /* offset */
-#define SH7750_WTCNT SH7750_P4_REG32(SH7750_WTCNT_REGOFS)
-#define SH7750_WTCNT_A7 SH7750_A7_REG32(SH7750_WTCNT_REGOFS)
-#define SH7750_WTCNT_KEY 0x5A00 /* When WTCNT byte register written,
- you have to set the upper byte to
- 0x5A */
-
-/* Watchdog Timer Control/Status register - WTCSR */
-#define SH7750_WTCSR_REGOFS 0xC0000C /* offset */
-#define SH7750_WTCSR SH7750_P4_REG32(SH7750_WTCSR_REGOFS)
-#define SH7750_WTCSR_A7 SH7750_A7_REG32(SH7750_WTCSR_REGOFS)
-#define SH7750_WTCSR_KEY 0xA500 /* When WTCSR byte register written,
- you have to set the upper byte to
- 0xA5 */
-#define SH7750_WTCSR_TME 0x80 /* Timer enable (1-upcount start) */
-#define SH7750_WTCSR_MODE 0x40 /* Timer Mode Select: */
-#define SH7750_WTCSR_MODE_WT 0x40 /* Watchdog Timer Mode */
-#define SH7750_WTCSR_MODE_IT 0x00 /* Interval Timer Mode */
-#define SH7750_WTCSR_RSTS 0x20 /* Reset Select: */
-#define SH7750_WTCSR_RST_MAN 0x20 /* Manual Reset */
-#define SH7750_WTCSR_RST_PWR 0x00 /* Power-on Reset */
-#define SH7750_WTCSR_WOVF 0x10 /* Watchdog Timer Overflow Flag */
-#define SH7750_WTCSR_IOVF 0x08 /* Interval Timer Overflow Flag */
-#define SH7750_WTCSR_CKS 0x07 /* Clock Select: */
-#define SH7750_WTCSR_CKS_DIV32 0x00 /* 1/32 of frequency divider 2 input */
-#define SH7750_WTCSR_CKS_DIV64 0x01 /* 1/64 */
-#define SH7750_WTCSR_CKS_DIV128 0x02 /* 1/128 */
-#define SH7750_WTCSR_CKS_DIV256 0x03 /* 1/256 */
-#define SH7750_WTCSR_CKS_DIV512 0x04 /* 1/512 */
-#define SH7750_WTCSR_CKS_DIV1024 0x05 /* 1/1024 */
-#define SH7750_WTCSR_CKS_DIV2048 0x06 /* 1/2048 */
-#define SH7750_WTCSR_CKS_DIV4096 0x07 /* 1/4096 */
-
-/*
- * Real-Time Clock (RTC)
- */
-/* 64-Hz Counter Register (byte, read-only) - R64CNT */
-#define SH7750_R64CNT_REGOFS 0xC80000 /* offset */
-#define SH7750_R64CNT SH7750_P4_REG32(SH7750_R64CNT_REGOFS)
-#define SH7750_R64CNT_A7 SH7750_A7_REG32(SH7750_R64CNT_REGOFS)
-
-/* Second Counter Register (byte, BCD-coded) - RSECCNT */
-#define SH7750_RSECCNT_REGOFS 0xC80004 /* offset */
-#define SH7750_RSECCNT SH7750_P4_REG32(SH7750_RSECCNT_REGOFS)
-#define SH7750_RSECCNT_A7 SH7750_A7_REG32(SH7750_RSECCNT_REGOFS)
-
-/* Minute Counter Register (byte, BCD-coded) - RMINCNT */
-#define SH7750_RMINCNT_REGOFS 0xC80008 /* offset */
-#define SH7750_RMINCNT SH7750_P4_REG32(SH7750_RMINCNT_REGOFS)
-#define SH7750_RMINCNT_A7 SH7750_A7_REG32(SH7750_RMINCNT_REGOFS)
-
-/* Hour Counter Register (byte, BCD-coded) - RHRCNT */
-#define SH7750_RHRCNT_REGOFS 0xC8000C /* offset */
-#define SH7750_RHRCNT SH7750_P4_REG32(SH7750_RHRCNT_REGOFS)
-#define SH7750_RHRCNT_A7 SH7750_A7_REG32(SH7750_RHRCNT_REGOFS)
-
-/* Day-of-Week Counter Register (byte) - RWKCNT */
-#define SH7750_RWKCNT_REGOFS 0xC80010 /* offset */
-#define SH7750_RWKCNT SH7750_P4_REG32(SH7750_RWKCNT_REGOFS)
-#define SH7750_RWKCNT_A7 SH7750_A7_REG32(SH7750_RWKCNT_REGOFS)
-
-#define SH7750_RWKCNT_SUN 0 /* Sunday */
-#define SH7750_RWKCNT_MON 1 /* Monday */
-#define SH7750_RWKCNT_TUE 2 /* Tuesday */
-#define SH7750_RWKCNT_WED 3 /* Wednesday */
-#define SH7750_RWKCNT_THU 4 /* Thursday */
-#define SH7750_RWKCNT_FRI 5 /* Friday */
-#define SH7750_RWKCNT_SAT 6 /* Saturday */
-
-/* Day Counter Register (byte, BCD-coded) - RDAYCNT */
-#define SH7750_RDAYCNT_REGOFS 0xC80014 /* offset */
-#define SH7750_RDAYCNT SH7750_P4_REG32(SH7750_RDAYCNT_REGOFS)
-#define SH7750_RDAYCNT_A7 SH7750_A7_REG32(SH7750_RDAYCNT_REGOFS)
-
-/* Month Counter Register (byte, BCD-coded) - RMONCNT */
-#define SH7750_RMONCNT_REGOFS 0xC80018 /* offset */
-#define SH7750_RMONCNT SH7750_P4_REG32(SH7750_RMONCNT_REGOFS)
-#define SH7750_RMONCNT_A7 SH7750_A7_REG32(SH7750_RMONCNT_REGOFS)
-
-/* Year Counter Register (half, BCD-coded) - RYRCNT */
-#define SH7750_RYRCNT_REGOFS 0xC8001C /* offset */
-#define SH7750_RYRCNT SH7750_P4_REG32(SH7750_RYRCNT_REGOFS)
-#define SH7750_RYRCNT_A7 SH7750_A7_REG32(SH7750_RYRCNT_REGOFS)
-
-/* Second Alarm Register (byte, BCD-coded) - RSECAR */
-#define SH7750_RSECAR_REGOFS 0xC80020 /* offset */
-#define SH7750_RSECAR SH7750_P4_REG32(SH7750_RSECAR_REGOFS)
-#define SH7750_RSECAR_A7 SH7750_A7_REG32(SH7750_RSECAR_REGOFS)
-#define SH7750_RSECAR_ENB 0x80 /* Second Alarm Enable */
-
-/* Minute Alarm Register (byte, BCD-coded) - RMINAR */
-#define SH7750_RMINAR_REGOFS 0xC80024 /* offset */
-#define SH7750_RMINAR SH7750_P4_REG32(SH7750_RMINAR_REGOFS)
-#define SH7750_RMINAR_A7 SH7750_A7_REG32(SH7750_RMINAR_REGOFS)
-#define SH7750_RMINAR_ENB 0x80 /* Minute Alarm Enable */
-
-/* Hour Alarm Register (byte, BCD-coded) - RHRAR */
-#define SH7750_RHRAR_REGOFS 0xC80028 /* offset */
-#define SH7750_RHRAR SH7750_P4_REG32(SH7750_RHRAR_REGOFS)
-#define SH7750_RHRAR_A7 SH7750_A7_REG32(SH7750_RHRAR_REGOFS)
-#define SH7750_RHRAR_ENB 0x80 /* Hour Alarm Enable */
-
-/* Day-of-Week Alarm Register (byte) - RWKAR */
-#define SH7750_RWKAR_REGOFS 0xC8002C /* offset */
-#define SH7750_RWKAR SH7750_P4_REG32(SH7750_RWKAR_REGOFS)
-#define SH7750_RWKAR_A7 SH7750_A7_REG32(SH7750_RWKAR_REGOFS)
-#define SH7750_RWKAR_ENB 0x80 /* Day-of-week Alarm Enable */
-
-#define SH7750_RWKAR_SUN 0 /* Sunday */
-#define SH7750_RWKAR_MON 1 /* Monday */
-#define SH7750_RWKAR_TUE 2 /* Tuesday */
-#define SH7750_RWKAR_WED 3 /* Wednesday */
-#define SH7750_RWKAR_THU 4 /* Thursday */
-#define SH7750_RWKAR_FRI 5 /* Friday */
-#define SH7750_RWKAR_SAT 6 /* Saturday */
-
-/* Day Alarm Register (byte, BCD-coded) - RDAYAR */
-#define SH7750_RDAYAR_REGOFS 0xC80030 /* offset */
-#define SH7750_RDAYAR SH7750_P4_REG32(SH7750_RDAYAR_REGOFS)
-#define SH7750_RDAYAR_A7 SH7750_A7_REG32(SH7750_RDAYAR_REGOFS)
-#define SH7750_RDAYAR_ENB 0x80 /* Day Alarm Enable */
-
-/* Month Counter Register (byte, BCD-coded) - RMONAR */
-#define SH7750_RMONAR_REGOFS 0xC80034 /* offset */
-#define SH7750_RMONAR SH7750_P4_REG32(SH7750_RMONAR_REGOFS)
-#define SH7750_RMONAR_A7 SH7750_A7_REG32(SH7750_RMONAR_REGOFS)
-#define SH7750_RMONAR_ENB 0x80 /* Month Alarm Enable */
-
-/* RTC Control Register 1 (byte) - RCR1 */
-#define SH7750_RCR1_REGOFS 0xC80038 /* offset */
-#define SH7750_RCR1 SH7750_P4_REG32(SH7750_RCR1_REGOFS)
-#define SH7750_RCR1_A7 SH7750_A7_REG32(SH7750_RCR1_REGOFS)
-#define SH7750_RCR1_CF 0x80 /* Carry Flag */
-#define SH7750_RCR1_CIE 0x10 /* Carry Interrupt Enable */
-#define SH7750_RCR1_AIE 0x08 /* Alarm Interrupt Enable */
-#define SH7750_RCR1_AF 0x01 /* Alarm Flag */
-
-/* RTC Control Register 2 (byte) - RCR2 */
-#define SH7750_RCR2_REGOFS 0xC8003C /* offset */
-#define SH7750_RCR2 SH7750_P4_REG32(SH7750_RCR2_REGOFS)
-#define SH7750_RCR2_A7 SH7750_A7_REG32(SH7750_RCR2_REGOFS)
-#define SH7750_RCR2_PEF 0x80 /* Periodic Interrupt Flag */
-#define SH7750_RCR2_PES 0x70 /* Periodic Interrupt Enable: */
-#define SH7750_RCR2_PES_DIS 0x00 /* Periodic Interrupt Disabled */
-#define SH7750_RCR2_PES_DIV256 0x10 /* Generated at 1/256 sec interval */
-#define SH7750_RCR2_PES_DIV64 0x20 /* Generated at 1/64 sec interval */
-#define SH7750_RCR2_PES_DIV16 0x30 /* Generated at 1/16 sec interval */
-#define SH7750_RCR2_PES_DIV4 0x40 /* Generated at 1/4 sec interval */
-#define SH7750_RCR2_PES_DIV2 0x50 /* Generated at 1/2 sec interval */
-#define SH7750_RCR2_PES_x1 0x60 /* Generated at 1 sec interval */
-#define SH7750_RCR2_PES_x2 0x70 /* Generated at 2 sec interval */
-#define SH7750_RCR2_RTCEN 0x08 /* RTC Crystal Oscillator is Operated */
-#define SH7750_RCR2_ADJ 0x04 /* 30-Second Adjastment */
-#define SH7750_RCR2_RESET 0x02 /* Frequency divider circuits are reset */
-#define SH7750_RCR2_START 0x01 /* 0 - sec, min, hr, day-of-week, month,
- year counters are stopped
- 1 - sec, min, hr, day-of-week, month,
- year counters operate normally */
-/*
- * Bus State Controller - BSC
- */
-/* Bus Control Register 1 - BCR1 */
-#define SH7750_BCR1_REGOFS 0x800000 /* offset */
-#define SH7750_BCR1 SH7750_P4_REG32(SH7750_BCR1_REGOFS)
-#define SH7750_BCR1_A7 SH7750_A7_REG32(SH7750_BCR1_REGOFS)
-#define SH7750_BCR1_ENDIAN 0x80000000 /* Endianness (1 - little endian) */
-#define SH7750_BCR1_MASTER 0x40000000 /* Master/Slave mode (1-master) */
-#define SH7750_BCR1_A0MPX 0x20000000 /* Area 0 Memory Type (0-SRAM,1-MPX) */
-#define SH7750_BCR1_IPUP 0x02000000 /* Input Pin Pull-up Control:
- 0 - pull-up resistor is on for
- control input pins
- 1 - pull-up resistor is off */
-#define SH7750_BCR1_OPUP 0x01000000 /* Output Pin Pull-up Control:
- 0 - pull-up resistor is on for
- control output pins
- 1 - pull-up resistor is off */
-#define SH7750_BCR1_A1MBC 0x00200000 /* Area 1 SRAM Byte Control Mode:
- 0 - Area 1 SRAM is set to
- normal mode
- 1 - Area 1 SRAM is set to byte
- control mode */
-#define SH7750_BCR1_A4MBC 0x00100000 /* Area 4 SRAM Byte Control Mode:
- 0 - Area 4 SRAM is set to
- normal mode
- 1 - Area 4 SRAM is set to byte
- control mode */
-#define SH7750_BCR1_BREQEN 0x00080000 /* BREQ Enable:
- 0 - External requests are not
- accepted
- 1 - External requests are
- accepted */
-#define SH7750_BCR1_PSHR 0x00040000 /* Partial Sharing Bit:
- 0 - Master Mode
- 1 - Partial-sharing Mode */
-#define SH7750_BCR1_MEMMPX 0x00020000 /* Area 1 to 6 MPX Interface:
- 0 - SRAM/burst ROM interface
- 1 - MPX interface */
-#define SH7750_BCR1_HIZMEM 0x00008000 /* High Impendance Control. Specifies
- the state of A[25:0], BS\, CSn\,
- RD/WR\, CE2A\, CE2B\ in standby
- mode and when bus is released:
- 0 - signals go to High-Z mode
- 1 - signals driven */
-#define SH7750_BCR1_HIZCNT 0x00004000 /* High Impendance Control. Specifies
- the state of the RAS\, RAS2\, WEn\,
- CASn\, DQMn, RD\, CASS\, FRAME\,
- RD2\ signals in standby mode and
- when bus is released:
- 0 - signals go to High-Z mode
- 1 - signals driven */
-#define SH7750_BCR1_A0BST 0x00003800 /* Area 0 Burst ROM Control */
-#define SH7750_BCR1_A0BST_SRAM 0x0000 /* Area 0 accessed as SRAM i/f */
-#define SH7750_BCR1_A0BST_ROM4 0x0800 /* Area 0 accessed as burst ROM
- interface, 4 cosequtive access */
-#define SH7750_BCR1_A0BST_ROM8 0x1000 /* Area 0 accessed as burst ROM
- interface, 8 cosequtive access */
-#define SH7750_BCR1_A0BST_ROM16 0x1800 /* Area 0 accessed as burst ROM
- interface, 16 cosequtive access */
-#define SH7750_BCR1_A0BST_ROM32 0x2000 /* Area 0 accessed as burst ROM
- interface, 32 cosequtive access */
-
-#define SH7750_BCR1_A5BST 0x00000700 /* Area 5 Burst ROM Control */
-#define SH7750_BCR1_A5BST_SRAM 0x0000 /* Area 5 accessed as SRAM i/f */
-#define SH7750_BCR1_A5BST_ROM4 0x0100 /* Area 5 accessed as burst ROM
- interface, 4 cosequtive access */
-#define SH7750_BCR1_A5BST_ROM8 0x0200 /* Area 5 accessed as burst ROM
- interface, 8 cosequtive access */
-#define SH7750_BCR1_A5BST_ROM16 0x0300 /* Area 5 accessed as burst ROM
- interface, 16 cosequtive access */
-#define SH7750_BCR1_A5BST_ROM32 0x0400 /* Area 5 accessed as burst ROM
- interface, 32 cosequtive access */
-
-#define SH7750_BCR1_A6BST 0x000000E0 /* Area 6 Burst ROM Control */
-#define SH7750_BCR1_A6BST_SRAM 0x0000 /* Area 6 accessed as SRAM i/f */
-#define SH7750_BCR1_A6BST_ROM4 0x0020 /* Area 6 accessed as burst ROM
- interface, 4 cosequtive access */
-#define SH7750_BCR1_A6BST_ROM8 0x0040 /* Area 6 accessed as burst ROM
- interface, 8 cosequtive access */
-#define SH7750_BCR1_A6BST_ROM16 0x0060 /* Area 6 accessed as burst ROM
- interface, 16 cosequtive access */
-#define SH7750_BCR1_A6BST_ROM32 0x0080 /* Area 6 accessed as burst ROM
- interface, 32 cosequtive access */
-
-#define SH7750_BCR1_DRAMTP 0x001C /* Area 2 and 3 Memory Type */
-#define SH7750_BCR1_DRAMTP_2SRAM_3SRAM 0x0000 /* Area 2 and 3 are SRAM or MPX
- interface. */
-#define SH7750_BCR1_DRAMTP_2SRAM_3SDRAM 0x0008 /* Area 2 - SRAM/MPX, Area 3 -
- synchronous DRAM */
-#define SH7750_BCR1_DRAMTP_2SDRAM_3SDRAM 0x000C /* Area 2 and 3 are synchronous
- DRAM interface */
-#define SH7750_BCR1_DRAMTP_2SRAM_3DRAM 0x0010 /* Area 2 - SRAM/MPX, Area 3 -
- DRAM interface */
-#define SH7750_BCR1_DRAMTP_2DRAM_3DRAM 0x0014 /* Area 2 and 3 are DRAM
- interface */
-
-#define SH7750_BCR1_A56PCM 0x00000001 /* Area 5 and 6 Bus Type:
- 0 - SRAM interface
- 1 - PCMCIA interface */
-
-/* Bus Control Register 2 (half) - BCR2 */
-#define SH7750_BCR2_REGOFS 0x800004 /* offset */
-#define SH7750_BCR2 SH7750_P4_REG32(SH7750_BCR2_REGOFS)
-#define SH7750_BCR2_A7 SH7750_A7_REG32(SH7750_BCR2_REGOFS)
-
-#define SH7750_BCR2_A0SZ 0xC000 /* Area 0 Bus Width */
-#define SH7750_BCR2_A0SZ_S 14
-#define SH7750_BCR2_A6SZ 0x3000 /* Area 6 Bus Width */
-#define SH7750_BCR2_A6SZ_S 12
-#define SH7750_BCR2_A5SZ 0x0C00 /* Area 5 Bus Width */
-#define SH7750_BCR2_A5SZ_S 10
-#define SH7750_BCR2_A4SZ 0x0300 /* Area 4 Bus Width */
-#define SH7750_BCR2_A4SZ_S 8
-#define SH7750_BCR2_A3SZ 0x00C0 /* Area 3 Bus Width */
-#define SH7750_BCR2_A3SZ_S 6
-#define SH7750_BCR2_A2SZ 0x0030 /* Area 2 Bus Width */
-#define SH7750_BCR2_A2SZ_S 4
-#define SH7750_BCR2_A1SZ 0x000C /* Area 1 Bus Width */
-#define SH7750_BCR2_A1SZ_S 2
-#define SH7750_BCR2_SZ_64 0 /* 64 bits */
-#define SH7750_BCR2_SZ_8 1 /* 8 bits */
-#define SH7750_BCR2_SZ_16 2 /* 16 bits */
-#define SH7750_BCR2_SZ_32 3 /* 32 bits */
-#define SH7750_BCR2_PORTEN 0x0001 /* Port Function Enable :
- 0 - D51-D32 are not used as a port
- 1 - D51-D32 are used as a port */
-
-/* Wait Control Register 1 - WCR1 */
-#define SH7750_WCR1_REGOFS 0x800008 /* offset */
-#define SH7750_WCR1 SH7750_P4_REG32(SH7750_WCR1_REGOFS)
-#define SH7750_WCR1_A7 SH7750_A7_REG32(SH7750_WCR1_REGOFS)
-#define SH7750_WCR1_DMAIW 0x70000000 /* DACK Device Inter-Cycle Idle
- specification */
-#define SH7750_WCR1_DMAIW_S 28
-#define SH7750_WCR1_A6IW 0x07000000 /* Area 6 Inter-Cycle Idle spec. */
-#define SH7750_WCR1_A6IW_S 24
-#define SH7750_WCR1_A5IW 0x00700000 /* Area 5 Inter-Cycle Idle spec. */
-#define SH7750_WCR1_A5IW_S 20
-#define SH7750_WCR1_A4IW 0x00070000 /* Area 4 Inter-Cycle Idle spec. */
-#define SH7750_WCR1_A4IW_S 16
-#define SH7750_WCR1_A3IW 0x00007000 /* Area 3 Inter-Cycle Idle spec. */
-#define SH7750_WCR1_A3IW_S 12
-#define SH7750_WCR1_A2IW 0x00000700 /* Area 2 Inter-Cycle Idle spec. */
-#define SH7750_WCR1_A2IW_S 8
-#define SH7750_WCR1_A1IW 0x00000070 /* Area 1 Inter-Cycle Idle spec. */
-#define SH7750_WCR1_A1IW_S 4
-#define SH7750_WCR1_A0IW 0x00000007 /* Area 0 Inter-Cycle Idle spec. */
-#define SH7750_WCR1_A0IW_S 0
-
-/* Wait Control Register 2 - WCR2 */
-#define SH7750_WCR2_REGOFS 0x80000C /* offset */
-#define SH7750_WCR2 SH7750_P4_REG32(SH7750_WCR2_REGOFS)
-#define SH7750_WCR2_A7 SH7750_A7_REG32(SH7750_WCR2_REGOFS)
-
-#define SH7750_WCR2_A6W 0xE0000000 /* Area 6 Wait Control */
-#define SH7750_WCR2_A6W_S 29
-#define SH7750_WCR2_A6B 0x1C000000 /* Area 6 Burst Pitch */
-#define SH7750_WCR2_A6B_S 26
-#define SH7750_WCR2_A5W 0x03800000 /* Area 5 Wait Control */
-#define SH7750_WCR2_A5W_S 23
-#define SH7750_WCR2_A5B 0x00700000 /* Area 5 Burst Pitch */
-#define SH7750_WCR2_A5B_S 20
-#define SH7750_WCR2_A4W 0x000E0000 /* Area 4 Wait Control */
-#define SH7750_WCR2_A4W_S 17
-#define SH7750_WCR2_A3W 0x0000E000 /* Area 3 Wait Control */
-#define SH7750_WCR2_A3W_S 13
-#define SH7750_WCR2_A2W 0x00000E00 /* Area 2 Wait Control */
-#define SH7750_WCR2_A2W_S 9
-#define SH7750_WCR2_A1W 0x000001C0 /* Area 1 Wait Control */
-#define SH7750_WCR2_A1W_S 6
-#define SH7750_WCR2_A0W 0x00000038 /* Area 0 Wait Control */
-#define SH7750_WCR2_A0W_S 3
-#define SH7750_WCR2_A0B 0x00000007 /* Area 0 Burst Pitch */
-#define SH7750_WCR2_A0B_S 0
-
-#define SH7750_WCR2_WS0 0 /* 0 wait states inserted */
-#define SH7750_WCR2_WS1 1 /* 1 wait states inserted */
-#define SH7750_WCR2_WS2 2 /* 2 wait states inserted */
-#define SH7750_WCR2_WS3 3 /* 3 wait states inserted */
-#define SH7750_WCR2_WS6 4 /* 6 wait states inserted */
-#define SH7750_WCR2_WS9 5 /* 9 wait states inserted */
-#define SH7750_WCR2_WS12 6 /* 12 wait states inserted */
-#define SH7750_WCR2_WS15 7 /* 15 wait states inserted */
-
-#define SH7750_WCR2_BPWS0 0 /* 0 wait states inserted from 2nd access */
-#define SH7750_WCR2_BPWS1 1 /* 1 wait states inserted from 2nd access */
-#define SH7750_WCR2_BPWS2 2 /* 2 wait states inserted from 2nd access */
-#define SH7750_WCR2_BPWS3 3 /* 3 wait states inserted from 2nd access */
-#define SH7750_WCR2_BPWS4 4 /* 4 wait states inserted from 2nd access */
-#define SH7750_WCR2_BPWS5 5 /* 5 wait states inserted from 2nd access */
-#define SH7750_WCR2_BPWS6 6 /* 6 wait states inserted from 2nd access */
-#define SH7750_WCR2_BPWS7 7 /* 7 wait states inserted from 2nd access */
-
-/* DRAM CAS\ Assertion Delay (area 3,2) */
-#define SH7750_WCR2_DRAM_CAS_ASW1 0 /* 1 cycle */
-#define SH7750_WCR2_DRAM_CAS_ASW2 1 /* 2 cycles */
-#define SH7750_WCR2_DRAM_CAS_ASW3 2 /* 3 cycles */
-#define SH7750_WCR2_DRAM_CAS_ASW4 3 /* 4 cycles */
-#define SH7750_WCR2_DRAM_CAS_ASW7 4 /* 7 cycles */
-#define SH7750_WCR2_DRAM_CAS_ASW10 5 /* 10 cycles */
-#define SH7750_WCR2_DRAM_CAS_ASW13 6 /* 13 cycles */
-#define SH7750_WCR2_DRAM_CAS_ASW16 7 /* 16 cycles */
-
-/* SDRAM CAS\ Latency Cycles */
-#define SH7750_WCR2_SDRAM_CAS_LAT1 1 /* 1 cycle */
-#define SH7750_WCR2_SDRAM_CAS_LAT2 2 /* 2 cycles */
-#define SH7750_WCR2_SDRAM_CAS_LAT3 3 /* 3 cycles */
-#define SH7750_WCR2_SDRAM_CAS_LAT4 4 /* 4 cycles */
-#define SH7750_WCR2_SDRAM_CAS_LAT5 5 /* 5 cycles */
-
-/* Wait Control Register 3 - WCR3 */
-#define SH7750_WCR3_REGOFS 0x800010 /* offset */
-#define SH7750_WCR3 SH7750_P4_REG32(SH7750_WCR3_REGOFS)
-#define SH7750_WCR3_A7 SH7750_A7_REG32(SH7750_WCR3_REGOFS)
-
-#define SH7750_WCR3_A6S 0x04000000 /* Area 6 Write Strobe Setup time */
-#define SH7750_WCR3_A6H 0x03000000 /* Area 6 Data Hold Time */
-#define SH7750_WCR3_A6H_S 24
-#define SH7750_WCR3_A5S 0x00400000 /* Area 5 Write Strobe Setup time */
-#define SH7750_WCR3_A5H 0x00300000 /* Area 5 Data Hold Time */
-#define SH7750_WCR3_A5H_S 20
-#define SH7750_WCR3_A4S 0x00040000 /* Area 4 Write Strobe Setup time */
-#define SH7750_WCR3_A4H 0x00030000 /* Area 4 Data Hold Time */
-#define SH7750_WCR3_A4H_S 16
-#define SH7750_WCR3_A3S 0x00004000 /* Area 3 Write Strobe Setup time */
-#define SH7750_WCR3_A3H 0x00003000 /* Area 3 Data Hold Time */
-#define SH7750_WCR3_A3H_S 12
-#define SH7750_WCR3_A2S 0x00000400 /* Area 2 Write Strobe Setup time */
-#define SH7750_WCR3_A2H 0x00000300 /* Area 2 Data Hold Time */
-#define SH7750_WCR3_A2H_S 8
-#define SH7750_WCR3_A1S 0x00000040 /* Area 1 Write Strobe Setup time */
-#define SH7750_WCR3_A1H 0x00000030 /* Area 1 Data Hold Time */
-#define SH7750_WCR3_A1H_S 4
-#define SH7750_WCR3_A0S 0x00000004 /* Area 0 Write Strobe Setup time */
-#define SH7750_WCR3_A0H 0x00000003 /* Area 0 Data Hold Time */
-#define SH7750_WCR3_A0H_S 0
-
-#define SH7750_WCR3_DHWS_0 0 /* 0 wait states data hold time */
-#define SH7750_WCR3_DHWS_1 1 /* 1 wait states data hold time */
-#define SH7750_WCR3_DHWS_2 2 /* 2 wait states data hold time */
-#define SH7750_WCR3_DHWS_3 3 /* 3 wait states data hold time */
-
-#define SH7750_MCR_REGOFS 0x800014 /* offset */
-#define SH7750_MCR SH7750_P4_REG32(SH7750_MCR_REGOFS)
-#define SH7750_MCR_A7 SH7750_A7_REG32(SH7750_MCR_REGOFS)
-
-#define SH7750_MCR_RASD 0x80000000 /* RAS Down mode */
-#define SH7750_MCR_MRSET 0x40000000 /* SDRAM Mode Register Set */
-#define SH7750_MCR_PALL 0x00000000 /* SDRAM Precharge All cmd. Mode */
-#define SH7750_MCR_TRC 0x38000000 /* RAS Precharge Time at End of
- Refresh: */
-#define SH7750_MCR_TRC_0 0x00000000 /* 0 */
-#define SH7750_MCR_TRC_3 0x08000000 /* 3 */
-#define SH7750_MCR_TRC_6 0x10000000 /* 6 */
-#define SH7750_MCR_TRC_9 0x18000000 /* 9 */
-#define SH7750_MCR_TRC_12 0x20000000 /* 12 */
-#define SH7750_MCR_TRC_15 0x28000000 /* 15 */
-#define SH7750_MCR_TRC_18 0x30000000 /* 18 */
-#define SH7750_MCR_TRC_21 0x38000000 /* 21 */
-
-#define SH7750_MCR_TCAS 0x00800000 /* CAS Negation Period */
-#define SH7750_MCR_TCAS_1 0x00000000 /* 1 */
-#define SH7750_MCR_TCAS_2 0x00800000 /* 2 */
-
-#define SH7750_MCR_TPC 0x00380000 /* DRAM: RAS Precharge Period
- SDRAM: minimum number of cycles
- until the next bank active cmd
- is output after precharging */
-#define SH7750_MCR_TPC_S 19
-#define SH7750_MCR_TPC_SDRAM_1 0x00000000 /* 1 cycle */
-#define SH7750_MCR_TPC_SDRAM_2 0x00080000 /* 2 cycles */
-#define SH7750_MCR_TPC_SDRAM_3 0x00100000 /* 3 cycles */
-#define SH7750_MCR_TPC_SDRAM_4 0x00180000 /* 4 cycles */
-#define SH7750_MCR_TPC_SDRAM_5 0x00200000 /* 5 cycles */
-#define SH7750_MCR_TPC_SDRAM_6 0x00280000 /* 6 cycles */
-#define SH7750_MCR_TPC_SDRAM_7 0x00300000 /* 7 cycles */
-#define SH7750_MCR_TPC_SDRAM_8 0x00380000 /* 8 cycles */
-
-#define SH7750_MCR_RCD 0x00030000 /* DRAM: RAS-CAS Assertion Delay time
- SDRAM: bank active-read/write cmd
- delay time */
-#define SH7750_MCR_RCD_DRAM_2 0x00000000 /* DRAM delay 2 clocks */
-#define SH7750_MCR_RCD_DRAM_3 0x00010000 /* DRAM delay 3 clocks */
-#define SH7750_MCR_RCD_DRAM_4 0x00020000 /* DRAM delay 4 clocks */
-#define SH7750_MCR_RCD_DRAM_5 0x00030000 /* DRAM delay 5 clocks */
-#define SH7750_MCR_RCD_SDRAM_2 0x00010000 /* DRAM delay 2 clocks */
-#define SH7750_MCR_RCD_SDRAM_3 0x00020000 /* DRAM delay 3 clocks */
-#define SH7750_MCR_RCD_SDRAM_4 0x00030000 /* DRAM delay 4 clocks */
-
-#define SH7750_MCR_TRWL 0x0000E000 /* SDRAM Write Precharge Delay */
-#define SH7750_MCR_TRWL_1 0x00000000 /* 1 */
-#define SH7750_MCR_TRWL_2 0x00002000 /* 2 */
-#define SH7750_MCR_TRWL_3 0x00004000 /* 3 */
-#define SH7750_MCR_TRWL_4 0x00006000 /* 4 */
-#define SH7750_MCR_TRWL_5 0x00008000 /* 5 */
-
-#define SH7750_MCR_TRAS 0x00001C00 /* DRAM: CAS-Before-RAS Refresh RAS
- asserting period
- SDRAM: Command interval after
- synchronous DRAM refresh */
-#define SH7750_MCR_TRAS_DRAM_2 0x00000000 /* 2 */
-#define SH7750_MCR_TRAS_DRAM_3 0x00000400 /* 3 */
-#define SH7750_MCR_TRAS_DRAM_4 0x00000800 /* 4 */
-#define SH7750_MCR_TRAS_DRAM_5 0x00000C00 /* 5 */
-#define SH7750_MCR_TRAS_DRAM_6 0x00001000 /* 6 */
-#define SH7750_MCR_TRAS_DRAM_7 0x00001400 /* 7 */
-#define SH7750_MCR_TRAS_DRAM_8 0x00001800 /* 8 */
-#define SH7750_MCR_TRAS_DRAM_9 0x00001C00 /* 9 */
-
-#define SH7750_MCR_TRAS_SDRAM_TRC_4 0x00000000 /* 4 + TRC */
-#define SH7750_MCR_TRAS_SDRAM_TRC_5 0x00000400 /* 5 + TRC */
-#define SH7750_MCR_TRAS_SDRAM_TRC_6 0x00000800 /* 6 + TRC */
-#define SH7750_MCR_TRAS_SDRAM_TRC_7 0x00000C00 /* 7 + TRC */
-#define SH7750_MCR_TRAS_SDRAM_TRC_8 0x00001000 /* 8 + TRC */
-#define SH7750_MCR_TRAS_SDRAM_TRC_9 0x00001400 /* 9 + TRC */
-#define SH7750_MCR_TRAS_SDRAM_TRC_10 0x00001800 /* 10 + TRC */
-#define SH7750_MCR_TRAS_SDRAM_TRC_11 0x00001C00 /* 11 + TRC */
-
-#define SH7750_MCR_BE 0x00000200 /* Burst Enable */
-#define SH7750_MCR_SZ 0x00000180 /* Memory Data Size */
-#define SH7750_MCR_SZ_64 0x00000000 /* 64 bits */
-#define SH7750_MCR_SZ_16 0x00000100 /* 16 bits */
-#define SH7750_MCR_SZ_32 0x00000180 /* 32 bits */
-
-#define SH7750_MCR_AMX 0x00000078 /* Address Multiplexing */
-#define SH7750_MCR_AMX_S 3
-#define SH7750_MCR_AMX_DRAM_8BIT_COL 0x00000000 /* 8-bit column addr */
-#define SH7750_MCR_AMX_DRAM_9BIT_COL 0x00000008 /* 9-bit column addr */
-#define SH7750_MCR_AMX_DRAM_10BIT_COL 0x00000010 /* 10-bit column addr */
-#define SH7750_MCR_AMX_DRAM_11BIT_COL 0x00000018 /* 11-bit column addr */
-#define SH7750_MCR_AMX_DRAM_12BIT_COL 0x00000020 /* 12-bit column addr */
-/* See SH7750 Hardware Manual for SDRAM address multiplexor selection */
-
-#define SH7750_MCR_RFSH 0x00000004 /* Refresh Control */
-#define SH7750_MCR_RMODE 0x00000002 /* Refresh Mode: */
-#define SH7750_MCR_RMODE_NORMAL 0x00000000 /* Normal Refresh Mode */
-#define SH7750_MCR_RMODE_SELF 0x00000002 /* Self-Refresh Mode */
-#define SH7750_MCR_RMODE_EDO 0x00000001 /* EDO Mode */
-
-/* SDRAM Mode Set address */
-#define SH7750_SDRAM_MODE_A2_BASE 0xFF900000
-#define SH7750_SDRAM_MODE_A3_BASE 0xFF940000
-#define SH7750_SDRAM_MODE_A2_32BIT(x) (SH7750_SDRAM_MODE_A2_BASE + ((x) << 2))
-#define SH7750_SDRAM_MODE_A3_32BIT(x) (SH7750_SDRAM_MODE_A3_BASE + ((x) << 2))
-#define SH7750_SDRAM_MODE_A2_64BIT(x) (SH7750_SDRAM_MODE_A2_BASE + ((x) << 3))
-#define SH7750_SDRAM_MODE_A3_64BIT(x) (SH7750_SDRAM_MODE_A3_BASE + ((x) << 3))
-
-
-/* PCMCIA Control Register (half) - PCR */
-#define SH7750_PCR_REGOFS 0x800018 /* offset */
-#define SH7750_PCR SH7750_P4_REG32(SH7750_PCR_REGOFS)
-#define SH7750_PCR_A7 SH7750_A7_REG32(SH7750_PCR_REGOFS)
-
-#define SH7750_PCR_A5PCW 0xC000 /* Area 5 PCMCIA Wait - Number of wait
- states to be added to the number of
- waits specified by WCR2 in a low-speed
- PCMCIA wait cycle */
-#define SH7750_PCR_A5PCW_0 0x0000 /* 0 waits inserted */
-#define SH7750_PCR_A5PCW_15 0x4000 /* 15 waits inserted */
-#define SH7750_PCR_A5PCW_30 0x8000 /* 30 waits inserted */
-#define SH7750_PCR_A5PCW_50 0xC000 /* 50 waits inserted */
-
-#define SH7750_PCR_A6PCW 0x3000 /* Area 6 PCMCIA Wait - Number of wait
- states to be added to the number of
- waits specified by WCR2 in a low-speed
- PCMCIA wait cycle */
-#define SH7750_PCR_A6PCW_0 0x0000 /* 0 waits inserted */
-#define SH7750_PCR_A6PCW_15 0x1000 /* 15 waits inserted */
-#define SH7750_PCR_A6PCW_30 0x2000 /* 30 waits inserted */
-#define SH7750_PCR_A6PCW_50 0x3000 /* 50 waits inserted */
-
-#define SH7750_PCR_A5TED 0x0E00 /* Area 5 Address-OE\/WE\ Assertion Delay,
- delay time from address output to
- OE\/WE\ assertion on the connected
- PCMCIA interface */
-#define SH7750_PCR_A5TED_S 9
-#define SH7750_PCR_A6TED 0x01C0 /* Area 6 Address-OE\/WE\ Assertion Delay */
-#define SH7750_PCR_A6TED_S 6
-
-#define SH7750_PCR_TED_0WS 0 /* 0 Waits inserted */
-#define SH7750_PCR_TED_1WS 1 /* 1 Waits inserted */
-#define SH7750_PCR_TED_2WS 2 /* 2 Waits inserted */
-#define SH7750_PCR_TED_3WS 3 /* 3 Waits inserted */
-#define SH7750_PCR_TED_6WS 4 /* 6 Waits inserted */
-#define SH7750_PCR_TED_9WS 5 /* 9 Waits inserted */
-#define SH7750_PCR_TED_12WS 6 /* 12 Waits inserted */
-#define SH7750_PCR_TED_15WS 7 /* 15 Waits inserted */
-
-#define SH7750_PCR_A5TEH 0x0038 /* Area 5 OE\/WE\ Negation Address delay,
- address hold delay time from OE\/WE\
- negation in a write on the connected
- PCMCIA interface */
-#define SH7750_PCR_A5TEH_S 3
-
-#define SH7750_PCR_A6TEH 0x0007 /* Area 6 OE\/WE\ Negation Address delay */
-#define SH7750_PCR_A6TEH_S 0
-
-#define SH7750_PCR_TEH_0WS 0 /* 0 Waits inserted */
-#define SH7750_PCR_TEH_1WS 1 /* 1 Waits inserted */
-#define SH7750_PCR_TEH_2WS 2 /* 2 Waits inserted */
-#define SH7750_PCR_TEH_3WS 3 /* 3 Waits inserted */
-#define SH7750_PCR_TEH_6WS 4 /* 6 Waits inserted */
-#define SH7750_PCR_TEH_9WS 5 /* 9 Waits inserted */
-#define SH7750_PCR_TEH_12WS 6 /* 12 Waits inserted */
-#define SH7750_PCR_TEH_15WS 7 /* 15 Waits inserted */
-
-/* Refresh Timer Control/Status Register (half) - RTSCR */
-#define SH7750_RTCSR_REGOFS 0x80001C /* offset */
-#define SH7750_RTCSR SH7750_P4_REG32(SH7750_RTCSR_REGOFS)
-#define SH7750_RTCSR_A7 SH7750_A7_REG32(SH7750_RTCSR_REGOFS)
-
-#define SH7750_RTCSR_KEY 0xA500 /* RTCSR write key */
-#define SH7750_RTCSR_CMF 0x0080 /* Compare-Match Flag (indicates a
- match between the refresh timer
- counter and refresh time constant) */
-#define SH7750_RTCSR_CMIE 0x0040 /* Compare-Match Interrupt Enable */
-#define SH7750_RTCSR_CKS 0x0038 /* Refresh Counter Clock Selects */
-#define SH7750_RTCSR_CKS_DIS 0x0000 /* Clock Input Disabled */
-#define SH7750_RTCSR_CKS_CKIO_DIV4 0x0008 /* Bus Clock / 4 */
-#define SH7750_RTCSR_CKS_CKIO_DIV16 0x0010 /* Bus Clock / 16 */
-#define SH7750_RTCSR_CKS_CKIO_DIV64 0x0018 /* Bus Clock / 64 */
-#define SH7750_RTCSR_CKS_CKIO_DIV256 0x0020 /* Bus Clock / 256 */
-#define SH7750_RTCSR_CKS_CKIO_DIV1024 0x0028 /* Bus Clock / 1024 */
-#define SH7750_RTCSR_CKS_CKIO_DIV2048 0x0030 /* Bus Clock / 2048 */
-#define SH7750_RTCSR_CKS_CKIO_DIV4096 0x0038 /* Bus Clock / 4096 */
-
-#define SH7750_RTCSR_OVF 0x0004 /* Refresh Count Overflow Flag */
-#define SH7750_RTCSR_OVIE 0x0002 /* Refresh Count Overflow Interrupt
- Enable */
-#define SH7750_RTCSR_LMTS 0x0001 /* Refresh Count Overflow Limit Select */
-#define SH7750_RTCSR_LMTS_1024 0x0000 /* Count Limit is 1024 */
-#define SH7750_RTCSR_LMTS_512 0x0001 /* Count Limit is 512 */
-
-/* Refresh Timer Counter (half) - RTCNT */
-#define SH7750_RTCNT_REGOFS 0x800020 /* offset */
-#define SH7750_RTCNT SH7750_P4_REG32(SH7750_RTCNT_REGOFS)
-#define SH7750_RTCNT_A7 SH7750_A7_REG32(SH7750_RTCNT_REGOFS)
-
-#define SH7750_RTCNT_KEY 0xA500 /* RTCNT write key */
-
-/* Refresh Time Constant Register (half) - RTCOR */
-#define SH7750_RTCOR_REGOFS 0x800024 /* offset */
-#define SH7750_RTCOR SH7750_P4_REG32(SH7750_RTCOR_REGOFS)
-#define SH7750_RTCOR_A7 SH7750_A7_REG32(SH7750_RTCOR_REGOFS)
-
-#define SH7750_RTCOR_KEY 0xA500 /* RTCOR write key */
-
-/* Refresh Count Register (half) - RFCR */
-#define SH7750_RFCR_REGOFS 0x800028 /* offset */
-#define SH7750_RFCR SH7750_P4_REG32(SH7750_RFCR_REGOFS)
-#define SH7750_RFCR_A7 SH7750_A7_REG32(SH7750_RFCR_REGOFS)
-
-#define SH7750_RFCR_KEY 0xA400 /* RFCR write key */
-
-/* Synchronous DRAM mode registers - SDMR */
-#define SH7750_SDMR2_REGOFS 0x900000 /* base offset */
-#define SH7750_SDMR2_REGNB 0x0FFC /* nb of register */
-#define SH7750_SDMR2 SH7750_P4_REG32(SH7750_SDMR2_REGOFS)
-#define SH7750_SDMR2_A7 SH7750_A7_REG32(SH7750_SDMR2_REGOFS)
-
-#define SH7750_SDMR3_REGOFS 0x940000 /* offset */
-#define SH7750_SDMR3_REGNB 0x0FFC /* nb of register */
-#define SH7750_SDMR3 SH7750_P4_REG32(SH7750_SDMR3_REGOFS)
-#define SH7750_SDMR3_A7 SH7750_A7_REG32(SH7750_SDMR3_REGOFS)
-
-/*
- * Direct Memory Access Controller (DMAC)
- */
-
-/* DMA Source Address Register - SAR0, SAR1, SAR2, SAR3 */
-#define SH7750_SAR_REGOFS(n) (0xA00000 + ((n)*16)) /* offset */
-#define SH7750_SAR(n) SH7750_P4_REG32(SH7750_SAR_REGOFS(n))
-#define SH7750_SAR_A7(n) SH7750_A7_REG32(SH7750_SAR_REGOFS(n))
-#define SH7750_SAR0 SH7750_SAR(0)
-#define SH7750_SAR1 SH7750_SAR(1)
-#define SH7750_SAR2 SH7750_SAR(2)
-#define SH7750_SAR3 SH7750_SAR(3)
-#define SH7750_SAR0_A7 SH7750_SAR_A7(0)
-#define SH7750_SAR1_A7 SH7750_SAR_A7(1)
-#define SH7750_SAR2_A7 SH7750_SAR_A7(2)
-#define SH7750_SAR3_A7 SH7750_SAR_A7(3)
-
-/* DMA Destination Address Register - DAR0, DAR1, DAR2, DAR3 */
-#define SH7750_DAR_REGOFS(n) (0xA00004 + ((n)*16)) /* offset */
-#define SH7750_DAR(n) SH7750_P4_REG32(SH7750_DAR_REGOFS(n))
-#define SH7750_DAR_A7(n) SH7750_A7_REG32(SH7750_DAR_REGOFS(n))
-#define SH7750_DAR0 SH7750_DAR(0)
-#define SH7750_DAR1 SH7750_DAR(1)
-#define SH7750_DAR2 SH7750_DAR(2)
-#define SH7750_DAR3 SH7750_DAR(3)
-#define SH7750_DAR0_A7 SH7750_DAR_A7(0)
-#define SH7750_DAR1_A7 SH7750_DAR_A7(1)
-#define SH7750_DAR2_A7 SH7750_DAR_A7(2)
-#define SH7750_DAR3_A7 SH7750_DAR_A7(3)
-
-/* DMA Transfer Count Register - DMATCR0, DMATCR1, DMATCR2, DMATCR3 */
-#define SH7750_DMATCR_REGOFS(n) (0xA00008 + ((n)*16)) /* offset */
-#define SH7750_DMATCR(n) SH7750_P4_REG32(SH7750_DMATCR_REGOFS(n))
-#define SH7750_DMATCR_A7(n) SH7750_A7_REG32(SH7750_DMATCR_REGOFS(n))
-#define SH7750_DMATCR0_P4 SH7750_DMATCR(0)
-#define SH7750_DMATCR1_P4 SH7750_DMATCR(1)
-#define SH7750_DMATCR2_P4 SH7750_DMATCR(2)
-#define SH7750_DMATCR3_P4 SH7750_DMATCR(3)
-#define SH7750_DMATCR0_A7 SH7750_DMATCR_A7(0)
-#define SH7750_DMATCR1_A7 SH7750_DMATCR_A7(1)
-#define SH7750_DMATCR2_A7 SH7750_DMATCR_A7(2)
-#define SH7750_DMATCR3_A7 SH7750_DMATCR_A7(3)
-
-/* DMA Channel Control Register - CHCR0, CHCR1, CHCR2, CHCR3 */
-#define SH7750_CHCR_REGOFS(n) (0xA0000C + ((n)*16)) /* offset */
-#define SH7750_CHCR(n) SH7750_P4_REG32(SH7750_CHCR_REGOFS(n))
-#define SH7750_CHCR_A7(n) SH7750_A7_REG32(SH7750_CHCR_REGOFS(n))
-#define SH7750_CHCR0 SH7750_CHCR(0)
-#define SH7750_CHCR1 SH7750_CHCR(1)
-#define SH7750_CHCR2 SH7750_CHCR(2)
-#define SH7750_CHCR3 SH7750_CHCR(3)
-#define SH7750_CHCR0_A7 SH7750_CHCR_A7(0)
-#define SH7750_CHCR1_A7 SH7750_CHCR_A7(1)
-#define SH7750_CHCR2_A7 SH7750_CHCR_A7(2)
-#define SH7750_CHCR3_A7 SH7750_CHCR_A7(3)
-
-#define SH7750_CHCR_SSA 0xE0000000 /* Source Address Space Attribute */
-#define SH7750_CHCR_SSA_PCMCIA 0x00000000 /* Reserved in PCMCIA access */
-#define SH7750_CHCR_SSA_DYNBSZ 0x20000000 /* Dynamic Bus Sizing I/O space */
-#define SH7750_CHCR_SSA_IO8 0x40000000 /* 8-bit I/O space */
-#define SH7750_CHCR_SSA_IO16 0x60000000 /* 16-bit I/O space */
-#define SH7750_CHCR_SSA_CMEM8 0x80000000 /* 8-bit common memory space */
-#define SH7750_CHCR_SSA_CMEM16 0xA0000000 /* 16-bit common memory space */
-#define SH7750_CHCR_SSA_AMEM8 0xC0000000 /* 8-bit attribute memory space */
-#define SH7750_CHCR_SSA_AMEM16 0xE0000000 /* 16-bit attribute memory space */
-
-#define SH7750_CHCR_STC 0x10000000 /* Source Address Wait Control Select,
- specifies CS5 or CS6 space wait
- control for PCMCIA access */
-
-#define SH7750_CHCR_DSA 0x0E000000 /* Source Address Space Attribute */
-#define SH7750_CHCR_DSA_PCMCIA 0x00000000 /* Reserved in PCMCIA access */
-#define SH7750_CHCR_DSA_DYNBSZ 0x02000000 /* Dynamic Bus Sizing I/O space */
-#define SH7750_CHCR_DSA_IO8 0x04000000 /* 8-bit I/O space */
-#define SH7750_CHCR_DSA_IO16 0x06000000 /* 16-bit I/O space */
-#define SH7750_CHCR_DSA_CMEM8 0x08000000 /* 8-bit common memory space */
-#define SH7750_CHCR_DSA_CMEM16 0x0A000000 /* 16-bit common memory space */
-#define SH7750_CHCR_DSA_AMEM8 0x0C000000 /* 8-bit attribute memory space */
-#define SH7750_CHCR_DSA_AMEM16 0x0E000000 /* 16-bit attribute memory space */
-
-#define SH7750_CHCR_DTC 0x01000000 /* Destination Address Wait Control
- Select, specifies CS5 or CS6
- space wait control for PCMCIA
- access */
-
-#define SH7750_CHCR_DS 0x00080000 /* DREQ\ Select : */
-#define SH7750_CHCR_DS_LOWLVL 0x00000000 /* Low Level Detection */
-#define SH7750_CHCR_DS_FALL 0x00080000 /* Falling Edge Detection */
-
-#define SH7750_CHCR_RL 0x00040000 /* Request Check Level: */
-#define SH7750_CHCR_RL_ACTH 0x00000000 /* DRAK is an active high out */
-#define SH7750_CHCR_RL_ACTL 0x00040000 /* DRAK is an active low out */
-
-#define SH7750_CHCR_AM 0x00020000 /* Acknowledge Mode: */
-#define SH7750_CHCR_AM_RD 0x00000000 /* DACK is output in read cycle */
-#define SH7750_CHCR_AM_WR 0x00020000 /* DACK is output in write cycle */
-
-#define SH7750_CHCR_AL 0x00010000 /* Acknowledge Level: */
-#define SH7750_CHCR_AL_ACTH 0x00000000 /* DACK is an active high out */
-#define SH7750_CHCR_AL_ACTL 0x00010000 /* DACK is an active low out */
-
-#define SH7750_CHCR_DM 0x0000C000 /* Destination Address Mode: */
-#define SH7750_CHCR_DM_FIX 0x00000000 /* Destination Addr Fixed */
-#define SH7750_CHCR_DM_INC 0x00004000 /* Destination Addr Incremented */
-#define SH7750_CHCR_DM_DEC 0x00008000 /* Destination Addr Decremented */
-
-#define SH7750_CHCR_SM 0x00003000 /* Source Address Mode: */
-#define SH7750_CHCR_SM_FIX 0x00000000 /* Source Addr Fixed */
-#define SH7750_CHCR_SM_INC 0x00001000 /* Source Addr Incremented */
-#define SH7750_CHCR_SM_DEC 0x00002000 /* Source Addr Decremented */
-
-#define SH7750_CHCR_RS 0x00000F00 /* Request Source Select: */
-#define SH7750_CHCR_RS_ER_DA_EA_TO_EA 0x000 /* External Request, Dual Address
- Mode (External Addr Space->
- External Addr Space) */
-#define SH7750_CHCR_RS_ER_SA_EA_TO_ED 0x200 /* External Request, Single
- Address Mode (External Addr
- Space -> External Device) */
-#define SH7750_CHCR_RS_ER_SA_ED_TO_EA 0x300 /* External Request, Single
- Address Mode, (External
- Device -> External Addr
- Space) */
-#define SH7750_CHCR_RS_AR_EA_TO_EA 0x400 /* Auto-Request (External Addr
- Space -> External Addr Space) */
-
-#define SH7750_CHCR_RS_AR_EA_TO_OCP 0x500 /* Auto-Request (External Addr
- Space -> On-chip Peripheral
- Module) */
-#define SH7750_CHCR_RS_AR_OCP_TO_EA 0x600 /* Auto-Request (On-chip
- Peripheral Module ->
- External Addr Space */
-#define SH7750_CHCR_RS_SCITX_EA_TO_SC 0x800 /* SCI Transmit-Data-Empty intr
- transfer request (external
- address space -> SCTDR1) */
-#define SH7750_CHCR_RS_SCIRX_SC_TO_EA 0x900 /* SCI Receive-Data-Full intr
- transfer request (SCRDR1 ->
- External Addr Space) */
-#define SH7750_CHCR_RS_SCIFTX_EA_TO_SC 0xA00 /* SCIF Transmit-Data-Empty intr
- transfer request (external
- address space -> SCFTDR1) */
-#define SH7750_CHCR_RS_SCIFRX_SC_TO_EA 0xB00 /* SCIF Receive-Data-Full intr
- transfer request (SCFRDR2 ->
- External Addr Space) */
-#define SH7750_CHCR_RS_TMU2_EA_TO_EA 0xC00 /* TMU Channel 2 (input capture
- interrupt), (external address
- space -> external address
- space) */
-#define SH7750_CHCR_RS_TMU2_EA_TO_OCP 0xD00 /* TMU Channel 2 (input capture
- interrupt), (external address
- space -> on-chip peripheral
- module) */
-#define SH7750_CHCR_RS_TMU2_OCP_TO_EA 0xE00 /* TMU Channel 2 (input capture
- interrupt), (on-chip
- peripheral module -> external
- address space) */
-
-#define SH7750_CHCR_TM 0x00000080 /* Transmit mode: */
-#define SH7750_CHCR_TM_CSTEAL 0x00000000 /* Cycle Steal Mode */
-#define SH7750_CHCR_TM_BURST 0x00000080 /* Burst Mode */
-
-#define SH7750_CHCR_TS 0x00000070 /* Transmit Size: */
-#define SH7750_CHCR_TS_QUAD 0x00000000 /* Quadword Size (64 bits) */
-#define SH7750_CHCR_TS_BYTE 0x00000010 /* Byte Size (8 bit) */
-#define SH7750_CHCR_TS_WORD 0x00000020 /* Word Size (16 bit) */
-#define SH7750_CHCR_TS_LONG 0x00000030 /* Longword Size (32 bit) */
-#define SH7750_CHCR_TS_BLOCK 0x00000040 /* 32-byte block transfer */
-
-#define SH7750_CHCR_IE 0x00000004 /* Interrupt Enable */
-#define SH7750_CHCR_TE 0x00000002 /* Transfer End */
-#define SH7750_CHCR_DE 0x00000001 /* DMAC Enable */
-
-/* DMA Operation Register - DMAOR */
-#define SH7750_DMAOR_REGOFS 0xA00040 /* offset */
-#define SH7750_DMAOR SH7750_P4_REG32(SH7750_DMAOR_REGOFS)
-#define SH7750_DMAOR_A7 SH7750_A7_REG32(SH7750_DMAOR_REGOFS)
-
-#define SH7750_DMAOR_DDT 0x00008000 /* On-Demand Data Transfer Mode */
-
-#define SH7750_DMAOR_PR 0x00000300 /* Priority Mode: */
-#define SH7750_DMAOR_PR_0123 0x00000000 /* CH0 > CH1 > CH2 > CH3 */
-#define SH7750_DMAOR_PR_0231 0x00000100 /* CH0 > CH2 > CH3 > CH1 */
-#define SH7750_DMAOR_PR_2013 0x00000200 /* CH2 > CH0 > CH1 > CH3 */
-#define SH7750_DMAOR_PR_RR 0x00000300 /* Round-robin mode */
-
-#define SH7750_DMAOR_COD 0x00000010 /* Check Overrun for DREQ\ */
-#define SH7750_DMAOR_AE 0x00000004 /* Address Error flag */
-#define SH7750_DMAOR_NMIF 0x00000002 /* NMI Flag */
-#define SH7750_DMAOR_DME 0x00000001 /* DMAC Master Enable */
-
-/*
- * I/O Ports
- */
-/* Port Control Register A - PCTRA */
-#define SH7750_PCTRA_REGOFS 0x80002C /* offset */
-#define SH7750_PCTRA SH7750_P4_REG32(SH7750_PCTRA_REGOFS)
-#define SH7750_PCTRA_A7 SH7750_A7_REG32(SH7750_PCTRA_REGOFS)
-
-#define SH7750_PCTRA_PBPUP(n) 0 /* Bit n is pulled up */
-#define SH7750_PCTRA_PBNPUP(n) (1 << ((n)*2+1)) /* Bit n is not pulled up */
-#define SH7750_PCTRA_PBINP(n) 0 /* Bit n is an input */
-#define SH7750_PCTRA_PBOUT(n) (1 << ((n)*2)) /* Bit n is an output */
-
-/* Port Data Register A - PDTRA(half) */
-#define SH7750_PDTRA_REGOFS 0x800030 /* offset */
-#define SH7750_PDTRA SH7750_P4_REG32(SH7750_PDTRA_REGOFS)
-#define SH7750_PDTRA_A7 SH7750_A7_REG32(SH7750_PDTRA_REGOFS)
-
-#define SH7750_PDTRA_BIT(n) (1 << (n))
-
-/* Port Control Register B - PCTRB */
-#define SH7750_PCTRB_REGOFS 0x800040 /* offset */
-#define SH7750_PCTRB SH7750_P4_REG32(SH7750_PCTRB_REGOFS)
-#define SH7750_PCTRB_A7 SH7750_A7_REG32(SH7750_PCTRB_REGOFS)
-
-#define SH7750_PCTRB_PBPUP(n) 0 /* Bit n is pulled up */
-#define SH7750_PCTRB_PBNPUP(n) (1 << ((n-16)*2+1)) /* Bit n is not pulled up */
-#define SH7750_PCTRB_PBINP(n) 0 /* Bit n is an input */
-#define SH7750_PCTRB_PBOUT(n) (1 << ((n-16)*2)) /* Bit n is an output */
-
-/* Port Data Register B - PDTRB(half) */
-#define SH7750_PDTRB_REGOFS 0x800044 /* offset */
-#define SH7750_PDTRB SH7750_P4_REG32(SH7750_PDTRB_REGOFS)
-#define SH7750_PDTRB_A7 SH7750_A7_REG32(SH7750_PDTRB_REGOFS)
-
-#define SH7750_PDTRB_BIT(n) (1 << ((n)-16))
-
-/* GPIO Interrupt Control Register - GPIOIC(half) */
-#define SH7750_GPIOIC_REGOFS 0x800048 /* offset */
-#define SH7750_GPIOIC SH7750_P4_REG32(SH7750_GPIOIC_REGOFS)
-#define SH7750_GPIOIC_A7 SH7750_A7_REG32(SH7750_GPIOIC_REGOFS)
-
-#define SH7750_GPIOIC_PTIREN(n) (1 << (n)) /* Port n is used as a GPIO int */
-
-/*
- * Interrupt Controller - INTC
- */
-/* Interrupt Control Register - ICR (half) */
-#define SH7750_ICR_REGOFS 0xD00000 /* offset */
-#define SH7750_ICR SH7750_P4_REG32(SH7750_ICR_REGOFS)
-#define SH7750_ICR_A7 SH7750_A7_REG32(SH7750_ICR_REGOFS)
-
-#define SH7750_ICR_NMIL 0x8000 /* NMI Input Level */
-#define SH7750_ICR_MAI 0x4000 /* NMI Interrupt Mask */
-
-#define SH7750_ICR_NMIB 0x0200 /* NMI Block Mode: */
-#define SH7750_ICR_NMIB_BLK 0x0000 /* NMI requests held pending while
- SR.BL bit is set to 1 */
-#define SH7750_ICR_NMIB_NBLK 0x0200 /* NMI requests detected when SR.BL bit
- set to 1 */
-
-#define SH7750_ICR_NMIE 0x0100 /* NMI Edge Select: */
-#define SH7750_ICR_NMIE_FALL 0x0000 /* Interrupt request detected on falling
- edge of NMI input */
-#define SH7750_ICR_NMIE_RISE 0x0100 /* Interrupt request detected on rising
- edge of NMI input */
-
-#define SH7750_ICR_IRLM 0x0080 /* IRL Pin Mode: */
-#define SH7750_ICR_IRLM_ENC 0x0000 /* IRL\ pins used as a level-encoded
- interrupt requests */
-#define SH7750_ICR_IRLM_RAW 0x0080 /* IRL\ pins used as a four independent
- interrupt requests */
-
-/*
- * User Break Controller registers
- */
-#define SH7750_BARA 0x200000 /* Break address regiser A */
-#define SH7750_BAMRA 0x200004 /* Break address mask regiser A */
-#define SH7750_BBRA 0x200008 /* Break bus cycle regiser A */
-#define SH7750_BARB 0x20000c /* Break address regiser B */
-#define SH7750_BAMRB 0x200010 /* Break address mask regiser B */
-#define SH7750_BBRB 0x200014 /* Break bus cycle regiser B */
-#define SH7750_BASRB 0x000018 /* Break ASID regiser B */
-#define SH7750_BDRB 0x200018 /* Break data regiser B */
-#define SH7750_BDMRB 0x20001c /* Break data mask regiser B */
-#define SH7750_BRCR 0x200020 /* Break control register */
-
-#define SH7750_BRCR_UDBE 0x0001 /* User break debug enable bit */
-
-/*
- * Missing in RTEMS, added for QEMU
- */
-#define SH7750_BCR3_A7 0x1f800050
-#define SH7750_BCR4_A7 0x1e0a00f0
-
-#endif
diff --git a/qemu/hw/sh4/sh_pci.c b/qemu/hw/sh4/sh_pci.c
deleted file mode 100644
index e820a3230..000000000
--- a/qemu/hw/sh4/sh_pci.c
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * SuperH on-chip PCIC emulation.
- *
- * Copyright (c) 2008 Takashi YOSHII
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "hw/sh4/sh.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/pci_host.h"
-#include "qemu/bswap.h"
-#include "exec/address-spaces.h"
-
-#define TYPE_SH_PCI_HOST_BRIDGE "sh_pci"
-
-#define SH_PCI_HOST_BRIDGE(obj) \
- OBJECT_CHECK(SHPCIState, (obj), TYPE_SH_PCI_HOST_BRIDGE)
-
-typedef struct SHPCIState {
- PCIHostState parent_obj;
-
- PCIDevice *dev;
- qemu_irq irq[4];
- MemoryRegion memconfig_p4;
- MemoryRegion memconfig_a7;
- MemoryRegion isa;
- uint32_t par;
- uint32_t mbr;
- uint32_t iobr;
-} SHPCIState;
-
-static void sh_pci_reg_write (void *p, hwaddr addr, uint64_t val,
- unsigned size)
-{
- SHPCIState *pcic = p;
- PCIHostState *phb = PCI_HOST_BRIDGE(pcic);
-
- switch(addr) {
- case 0 ... 0xfc:
- cpu_to_le32w((uint32_t*)(pcic->dev->config + addr), val);
- break;
- case 0x1c0:
- pcic->par = val;
- break;
- case 0x1c4:
- pcic->mbr = val & 0xff000001;
- break;
- case 0x1c8:
- if ((val & 0xfffc0000) != (pcic->iobr & 0xfffc0000)) {
- memory_region_del_subregion(get_system_memory(), &pcic->isa);
- pcic->iobr = val & 0xfffc0001;
- memory_region_add_subregion(get_system_memory(),
- pcic->iobr & 0xfffc0000, &pcic->isa);
- }
- break;
- case 0x220:
- pci_data_write(phb->bus, pcic->par, val, 4);
- break;
- }
-}
-
-static uint64_t sh_pci_reg_read (void *p, hwaddr addr,
- unsigned size)
-{
- SHPCIState *pcic = p;
- PCIHostState *phb = PCI_HOST_BRIDGE(pcic);
-
- switch(addr) {
- case 0 ... 0xfc:
- return le32_to_cpup((uint32_t*)(pcic->dev->config + addr));
- case 0x1c0:
- return pcic->par;
- case 0x1c4:
- return pcic->mbr;
- case 0x1c8:
- return pcic->iobr;
- case 0x220:
- return pci_data_read(phb->bus, pcic->par, 4);
- }
- return 0;
-}
-
-static const MemoryRegionOps sh_pci_reg_ops = {
- .read = sh_pci_reg_read,
- .write = sh_pci_reg_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static int sh_pci_map_irq(PCIDevice *d, int irq_num)
-{
- return (d->devfn >> 3);
-}
-
-static void sh_pci_set_irq(void *opaque, int irq_num, int level)
-{
- qemu_irq *pic = opaque;
-
- qemu_set_irq(pic[irq_num], level);
-}
-
-static int sh_pci_device_init(SysBusDevice *dev)
-{
- PCIHostState *phb;
- SHPCIState *s;
- int i;
-
- s = SH_PCI_HOST_BRIDGE(dev);
- phb = PCI_HOST_BRIDGE(s);
- for (i = 0; i < 4; i++) {
- sysbus_init_irq(dev, &s->irq[i]);
- }
- phb->bus = pci_register_bus(DEVICE(dev), "pci",
- sh_pci_set_irq, sh_pci_map_irq,
- s->irq,
- get_system_memory(),
- get_system_io(),
- PCI_DEVFN(0, 0), 4, TYPE_PCI_BUS);
- memory_region_init_io(&s->memconfig_p4, OBJECT(s), &sh_pci_reg_ops, s,
- "sh_pci", 0x224);
- memory_region_init_alias(&s->memconfig_a7, OBJECT(s), "sh_pci.2",
- &s->memconfig_p4, 0, 0x224);
- memory_region_init_alias(&s->isa, OBJECT(s), "sh_pci.isa",
- get_system_io(), 0, 0x40000);
- sysbus_init_mmio(dev, &s->memconfig_p4);
- sysbus_init_mmio(dev, &s->memconfig_a7);
- s->iobr = 0xfe240000;
- memory_region_add_subregion(get_system_memory(), s->iobr, &s->isa);
-
- s->dev = pci_create_simple(phb->bus, PCI_DEVFN(0, 0), "sh_pci_host");
- return 0;
-}
-
-static void sh_pci_host_realize(PCIDevice *d, Error **errp)
-{
- pci_set_word(d->config + PCI_COMMAND, PCI_COMMAND_WAIT);
- pci_set_word(d->config + PCI_STATUS, PCI_STATUS_CAP_LIST |
- PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM);
-}
-
-static void sh_pci_host_class_init(ObjectClass *klass, void *data)
-{
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- k->realize = sh_pci_host_realize;
- k->vendor_id = PCI_VENDOR_ID_HITACHI;
- k->device_id = PCI_DEVICE_ID_HITACHI_SH7751R;
- /*
- * PCI-facing part of the host bridge, not usable without the
- * host-facing part, which can't be device_add'ed, yet.
- */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo sh_pci_host_info = {
- .name = "sh_pci_host",
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(PCIDevice),
- .class_init = sh_pci_host_class_init,
-};
-
-static void sh_pci_device_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
- sdc->init = sh_pci_device_init;
-}
-
-static const TypeInfo sh_pci_device_info = {
- .name = TYPE_SH_PCI_HOST_BRIDGE,
- .parent = TYPE_PCI_HOST_BRIDGE,
- .instance_size = sizeof(SHPCIState),
- .class_init = sh_pci_device_class_init,
-};
-
-static void sh_pci_register_types(void)
-{
- type_register_static(&sh_pci_device_info);
- type_register_static(&sh_pci_host_info);
-}
-
-type_init(sh_pci_register_types)
diff --git a/qemu/hw/sh4/shix.c b/qemu/hw/sh4/shix.c
deleted file mode 100644
index ccc9e7589..000000000
--- a/qemu/hw/sh4/shix.c
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * SHIX 2.0 board description
- *
- * Copyright (c) 2005 Samuel Tardieu
- *
- * 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.
- */
-/*
- Shix 2.0 board by Alexis Polti, described at
- http://perso.enst.fr/~polti/realisations/shix20/
-
- More information in target-sh4/README.sh4
-*/
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/hw.h"
-#include "hw/sh4/sh.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/qtest.h"
-#include "hw/boards.h"
-#include "hw/loader.h"
-#include "exec/address-spaces.h"
-#include "qemu/error-report.h"
-
-#define BIOS_FILENAME "shix_bios.bin"
-#define BIOS_ADDRESS 0xA0000000
-
-static void shix_init(MachineState *machine)
-{
- const char *cpu_model = machine->cpu_model;
- int ret;
- SuperHCPU *cpu;
- struct SH7750State *s;
- MemoryRegion *sysmem = get_system_memory();
- MemoryRegion *rom = g_new(MemoryRegion, 1);
- MemoryRegion *sdram = g_new(MemoryRegion, 2);
-
- if (!cpu_model)
- cpu_model = "any";
-
- cpu = cpu_sh4_init(cpu_model);
- if (cpu == NULL) {
- fprintf(stderr, "Unable to find CPU definition\n");
- exit(1);
- }
-
- /* Allocate memory space */
- memory_region_init_ram(rom, NULL, "shix.rom", 0x4000, &error_fatal);
- vmstate_register_ram_global(rom);
- memory_region_set_readonly(rom, true);
- memory_region_add_subregion(sysmem, 0x00000000, rom);
- memory_region_init_ram(&sdram[0], NULL, "shix.sdram1", 0x01000000,
- &error_fatal);
- vmstate_register_ram_global(&sdram[0]);
- memory_region_add_subregion(sysmem, 0x08000000, &sdram[0]);
- memory_region_init_ram(&sdram[1], NULL, "shix.sdram2", 0x01000000,
- &error_fatal);
- vmstate_register_ram_global(&sdram[1]);
- memory_region_add_subregion(sysmem, 0x0c000000, &sdram[1]);
-
- /* Load BIOS in 0 (and access it through P2, 0xA0000000) */
- if (bios_name == NULL)
- bios_name = BIOS_FILENAME;
- ret = load_image_targphys(bios_name, 0, 0x4000);
- if (ret < 0 && !qtest_enabled()) {
- error_report("Could not load SHIX bios '%s'", bios_name);
- exit(1);
- }
-
- /* Register peripherals */
- s = sh7750_init(cpu, sysmem);
- /* XXXXX Check success */
- tc58128_init(s, "shix_linux_nand.bin", NULL);
-}
-
-static void shix_machine_init(MachineClass *mc)
-{
- mc->desc = "shix card";
- mc->init = shix_init;
- mc->is_default = 1;
-}
-
-DEFINE_MACHINE("shix", shix_machine_init)
diff --git a/qemu/hw/smbios/Makefile.objs b/qemu/hw/smbios/Makefile.objs
deleted file mode 100644
index f69a92f96..000000000
--- a/qemu/hw/smbios/Makefile.objs
+++ /dev/null
@@ -1 +0,0 @@
-common-obj-$(CONFIG_SMBIOS) += smbios.o
diff --git a/qemu/hw/smbios/smbios.c b/qemu/hw/smbios/smbios.c
deleted file mode 100644
index cb8a11110..000000000
--- a/qemu/hw/smbios/smbios.c
+++ /dev/null
@@ -1,1112 +0,0 @@
-/*
- * SMBIOS Support
- *
- * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
- * Copyright (C) 2013 Red Hat, Inc.
- *
- * Authors:
- * Alex Williamson <alex.williamson@hp.com>
- * Markus Armbruster <armbru@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu/config-file.h"
-#include "qemu/error-report.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/cpus.h"
-#include "hw/smbios/smbios.h"
-#include "hw/loader.h"
-#include "exec/cpu-common.h"
-
-/* legacy structures and constants for <= 2.0 machines */
-struct smbios_header {
- uint16_t length;
- uint8_t type;
-} QEMU_PACKED;
-
-struct smbios_field {
- struct smbios_header header;
- uint8_t type;
- uint16_t offset;
- uint8_t data[];
-} QEMU_PACKED;
-
-struct smbios_table {
- struct smbios_header header;
- uint8_t data[];
-} QEMU_PACKED;
-
-#define SMBIOS_FIELD_ENTRY 0
-#define SMBIOS_TABLE_ENTRY 1
-
-static uint8_t *smbios_entries;
-static size_t smbios_entries_len;
-static bool smbios_legacy = true;
-static bool smbios_uuid_encoded = true;
-/* end: legacy structures & constants for <= 2.0 machines */
-
-
-static uint8_t *smbios_tables;
-static size_t smbios_tables_len;
-static unsigned smbios_table_max;
-static unsigned smbios_table_cnt;
-static SmbiosEntryPointType smbios_ep_type = SMBIOS_ENTRY_POINT_21;
-
-static SmbiosEntryPoint ep;
-
-static int smbios_type4_count = 0;
-static bool smbios_immutable;
-static bool smbios_have_defaults;
-static uint32_t smbios_cpuid_version, smbios_cpuid_features, smbios_smp_sockets;
-
-static DECLARE_BITMAP(have_binfile_bitmap, SMBIOS_MAX_TYPE+1);
-static DECLARE_BITMAP(have_fields_bitmap, SMBIOS_MAX_TYPE+1);
-
-static struct {
- const char *vendor, *version, *date;
- bool have_major_minor, uefi;
- uint8_t major, minor;
-} type0;
-
-static struct {
- const char *manufacturer, *product, *version, *serial, *sku, *family;
- /* uuid is in qemu_uuid[] */
-} type1;
-
-static struct {
- const char *manufacturer, *product, *version, *serial, *asset, *location;
-} type2;
-
-static struct {
- const char *manufacturer, *version, *serial, *asset, *sku;
-} type3;
-
-static struct {
- const char *sock_pfx, *manufacturer, *version, *serial, *asset, *part;
-} type4;
-
-static struct {
- const char *loc_pfx, *bank, *manufacturer, *serial, *asset, *part;
- uint16_t speed;
-} type17;
-
-static QemuOptsList qemu_smbios_opts = {
- .name = "smbios",
- .head = QTAILQ_HEAD_INITIALIZER(qemu_smbios_opts.head),
- .desc = {
- /*
- * no elements => accept any params
- * validation will happen later
- */
- { /* end of list */ }
- }
-};
-
-static const QemuOptDesc qemu_smbios_file_opts[] = {
- {
- .name = "file",
- .type = QEMU_OPT_STRING,
- .help = "binary file containing an SMBIOS element",
- },
- { /* end of list */ }
-};
-
-static const QemuOptDesc qemu_smbios_type0_opts[] = {
- {
- .name = "type",
- .type = QEMU_OPT_NUMBER,
- .help = "SMBIOS element type",
- },{
- .name = "vendor",
- .type = QEMU_OPT_STRING,
- .help = "vendor name",
- },{
- .name = "version",
- .type = QEMU_OPT_STRING,
- .help = "version number",
- },{
- .name = "date",
- .type = QEMU_OPT_STRING,
- .help = "release date",
- },{
- .name = "release",
- .type = QEMU_OPT_STRING,
- .help = "revision number",
- },{
- .name = "uefi",
- .type = QEMU_OPT_BOOL,
- .help = "uefi support",
- },
- { /* end of list */ }
-};
-
-static const QemuOptDesc qemu_smbios_type1_opts[] = {
- {
- .name = "type",
- .type = QEMU_OPT_NUMBER,
- .help = "SMBIOS element type",
- },{
- .name = "manufacturer",
- .type = QEMU_OPT_STRING,
- .help = "manufacturer name",
- },{
- .name = "product",
- .type = QEMU_OPT_STRING,
- .help = "product name",
- },{
- .name = "version",
- .type = QEMU_OPT_STRING,
- .help = "version number",
- },{
- .name = "serial",
- .type = QEMU_OPT_STRING,
- .help = "serial number",
- },{
- .name = "uuid",
- .type = QEMU_OPT_STRING,
- .help = "UUID",
- },{
- .name = "sku",
- .type = QEMU_OPT_STRING,
- .help = "SKU number",
- },{
- .name = "family",
- .type = QEMU_OPT_STRING,
- .help = "family name",
- },
- { /* end of list */ }
-};
-
-static const QemuOptDesc qemu_smbios_type2_opts[] = {
- {
- .name = "type",
- .type = QEMU_OPT_NUMBER,
- .help = "SMBIOS element type",
- },{
- .name = "manufacturer",
- .type = QEMU_OPT_STRING,
- .help = "manufacturer name",
- },{
- .name = "product",
- .type = QEMU_OPT_STRING,
- .help = "product name",
- },{
- .name = "version",
- .type = QEMU_OPT_STRING,
- .help = "version number",
- },{
- .name = "serial",
- .type = QEMU_OPT_STRING,
- .help = "serial number",
- },{
- .name = "asset",
- .type = QEMU_OPT_STRING,
- .help = "asset tag number",
- },{
- .name = "location",
- .type = QEMU_OPT_STRING,
- .help = "location in chassis",
- },
- { /* end of list */ }
-};
-
-static const QemuOptDesc qemu_smbios_type3_opts[] = {
- {
- .name = "type",
- .type = QEMU_OPT_NUMBER,
- .help = "SMBIOS element type",
- },{
- .name = "manufacturer",
- .type = QEMU_OPT_STRING,
- .help = "manufacturer name",
- },{
- .name = "version",
- .type = QEMU_OPT_STRING,
- .help = "version number",
- },{
- .name = "serial",
- .type = QEMU_OPT_STRING,
- .help = "serial number",
- },{
- .name = "asset",
- .type = QEMU_OPT_STRING,
- .help = "asset tag number",
- },{
- .name = "sku",
- .type = QEMU_OPT_STRING,
- .help = "SKU number",
- },
- { /* end of list */ }
-};
-
-static const QemuOptDesc qemu_smbios_type4_opts[] = {
- {
- .name = "type",
- .type = QEMU_OPT_NUMBER,
- .help = "SMBIOS element type",
- },{
- .name = "sock_pfx",
- .type = QEMU_OPT_STRING,
- .help = "socket designation string prefix",
- },{
- .name = "manufacturer",
- .type = QEMU_OPT_STRING,
- .help = "manufacturer name",
- },{
- .name = "version",
- .type = QEMU_OPT_STRING,
- .help = "version number",
- },{
- .name = "serial",
- .type = QEMU_OPT_STRING,
- .help = "serial number",
- },{
- .name = "asset",
- .type = QEMU_OPT_STRING,
- .help = "asset tag number",
- },{
- .name = "part",
- .type = QEMU_OPT_STRING,
- .help = "part number",
- },
- { /* end of list */ }
-};
-
-static const QemuOptDesc qemu_smbios_type17_opts[] = {
- {
- .name = "type",
- .type = QEMU_OPT_NUMBER,
- .help = "SMBIOS element type",
- },{
- .name = "loc_pfx",
- .type = QEMU_OPT_STRING,
- .help = "device locator string prefix",
- },{
- .name = "bank",
- .type = QEMU_OPT_STRING,
- .help = "bank locator string",
- },{
- .name = "manufacturer",
- .type = QEMU_OPT_STRING,
- .help = "manufacturer name",
- },{
- .name = "serial",
- .type = QEMU_OPT_STRING,
- .help = "serial number",
- },{
- .name = "asset",
- .type = QEMU_OPT_STRING,
- .help = "asset tag number",
- },{
- .name = "part",
- .type = QEMU_OPT_STRING,
- .help = "part number",
- },{
- .name = "speed",
- .type = QEMU_OPT_NUMBER,
- .help = "maximum capable speed",
- },
- { /* end of list */ }
-};
-
-static void smbios_register_config(void)
-{
- qemu_add_opts(&qemu_smbios_opts);
-}
-
-opts_init(smbios_register_config);
-
-static void smbios_validate_table(void)
-{
- uint32_t expect_t4_count = smbios_legacy ? smp_cpus : smbios_smp_sockets;
-
- if (smbios_type4_count && smbios_type4_count != expect_t4_count) {
- error_report("Expected %d SMBIOS Type 4 tables, got %d instead",
- expect_t4_count, smbios_type4_count);
- exit(1);
- }
-}
-
-
-/* legacy setup functions for <= 2.0 machines */
-static void smbios_add_field(int type, int offset, const void *data, size_t len)
-{
- struct smbios_field *field;
-
- if (!smbios_entries) {
- smbios_entries_len = sizeof(uint16_t);
- smbios_entries = g_malloc0(smbios_entries_len);
- }
- smbios_entries = g_realloc(smbios_entries, smbios_entries_len +
- sizeof(*field) + len);
- field = (struct smbios_field *)(smbios_entries + smbios_entries_len);
- field->header.type = SMBIOS_FIELD_ENTRY;
- field->header.length = cpu_to_le16(sizeof(*field) + len);
-
- field->type = type;
- field->offset = cpu_to_le16(offset);
- memcpy(field->data, data, len);
-
- smbios_entries_len += sizeof(*field) + len;
- (*(uint16_t *)smbios_entries) =
- cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1);
-}
-
-static void smbios_maybe_add_str(int type, int offset, const char *data)
-{
- if (data) {
- smbios_add_field(type, offset, data, strlen(data) + 1);
- }
-}
-
-static void smbios_build_type_0_fields(void)
-{
- smbios_maybe_add_str(0, offsetof(struct smbios_type_0, vendor_str),
- type0.vendor);
- smbios_maybe_add_str(0, offsetof(struct smbios_type_0, bios_version_str),
- type0.version);
- smbios_maybe_add_str(0, offsetof(struct smbios_type_0,
- bios_release_date_str),
- type0.date);
- if (type0.have_major_minor) {
- smbios_add_field(0, offsetof(struct smbios_type_0,
- system_bios_major_release),
- &type0.major, 1);
- smbios_add_field(0, offsetof(struct smbios_type_0,
- system_bios_minor_release),
- &type0.minor, 1);
- }
-}
-
-static void smbios_build_type_1_fields(void)
-{
- smbios_maybe_add_str(1, offsetof(struct smbios_type_1, manufacturer_str),
- type1.manufacturer);
- smbios_maybe_add_str(1, offsetof(struct smbios_type_1, product_name_str),
- type1.product);
- smbios_maybe_add_str(1, offsetof(struct smbios_type_1, version_str),
- type1.version);
- smbios_maybe_add_str(1, offsetof(struct smbios_type_1, serial_number_str),
- type1.serial);
- smbios_maybe_add_str(1, offsetof(struct smbios_type_1, sku_number_str),
- type1.sku);
- smbios_maybe_add_str(1, offsetof(struct smbios_type_1, family_str),
- type1.family);
- if (qemu_uuid_set) {
- /* We don't encode the UUID in the "wire format" here because this
- * function is for legacy mode and needs to keep the guest ABI, and
- * because we don't know what's the SMBIOS version advertised by the
- * BIOS.
- */
- smbios_add_field(1, offsetof(struct smbios_type_1, uuid),
- qemu_uuid, 16);
- }
-}
-
-uint8_t *smbios_get_table_legacy(size_t *length)
-{
- if (!smbios_legacy) {
- *length = 0;
- return NULL;
- }
-
- if (!smbios_immutable) {
- smbios_build_type_0_fields();
- smbios_build_type_1_fields();
- smbios_validate_table();
- smbios_immutable = true;
- }
- *length = smbios_entries_len;
- return smbios_entries;
-}
-/* end: legacy setup functions for <= 2.0 machines */
-
-
-static bool smbios_skip_table(uint8_t type, bool required_table)
-{
- if (test_bit(type, have_binfile_bitmap)) {
- return true; /* user provided their own binary blob(s) */
- }
- if (test_bit(type, have_fields_bitmap)) {
- return false; /* user provided fields via command line */
- }
- if (smbios_have_defaults && required_table) {
- return false; /* we're building tables, and this one's required */
- }
- return true;
-}
-
-#define SMBIOS_BUILD_TABLE_PRE(tbl_type, tbl_handle, tbl_required) \
- struct smbios_type_##tbl_type *t; \
- size_t t_off; /* table offset into smbios_tables */ \
- int str_index = 0; \
- do { \
- /* should we skip building this table ? */ \
- if (smbios_skip_table(tbl_type, tbl_required)) { \
- return; \
- } \
- \
- /* use offset of table t within smbios_tables */ \
- /* (pointer must be updated after each realloc) */ \
- t_off = smbios_tables_len; \
- smbios_tables_len += sizeof(*t); \
- smbios_tables = g_realloc(smbios_tables, smbios_tables_len); \
- t = (struct smbios_type_##tbl_type *)(smbios_tables + t_off); \
- \
- t->header.type = tbl_type; \
- t->header.length = sizeof(*t); \
- t->header.handle = cpu_to_le16(tbl_handle); \
- } while (0)
-
-#define SMBIOS_TABLE_SET_STR(tbl_type, field, value) \
- do { \
- int len = (value != NULL) ? strlen(value) + 1 : 0; \
- if (len > 1) { \
- smbios_tables = g_realloc(smbios_tables, \
- smbios_tables_len + len); \
- memcpy(smbios_tables + smbios_tables_len, value, len); \
- smbios_tables_len += len; \
- /* update pointer post-realloc */ \
- t = (struct smbios_type_##tbl_type *)(smbios_tables + t_off); \
- t->field = ++str_index; \
- } else { \
- t->field = 0; \
- } \
- } while (0)
-
-#define SMBIOS_BUILD_TABLE_POST \
- do { \
- size_t term_cnt, t_size; \
- \
- /* add '\0' terminator (add two if no strings defined) */ \
- term_cnt = (str_index == 0) ? 2 : 1; \
- smbios_tables = g_realloc(smbios_tables, \
- smbios_tables_len + term_cnt); \
- memset(smbios_tables + smbios_tables_len, 0, term_cnt); \
- smbios_tables_len += term_cnt; \
- \
- /* update smbios max. element size */ \
- t_size = smbios_tables_len - t_off; \
- if (t_size > smbios_table_max) { \
- smbios_table_max = t_size; \
- } \
- \
- /* update smbios element count */ \
- smbios_table_cnt++; \
- } while (0)
-
-static void smbios_build_type_0_table(void)
-{
- SMBIOS_BUILD_TABLE_PRE(0, 0x000, false); /* optional, leave up to BIOS */
-
- SMBIOS_TABLE_SET_STR(0, vendor_str, type0.vendor);
- SMBIOS_TABLE_SET_STR(0, bios_version_str, type0.version);
-
- t->bios_starting_address_segment = cpu_to_le16(0xE800); /* from SeaBIOS */
-
- SMBIOS_TABLE_SET_STR(0, bios_release_date_str, type0.date);
-
- t->bios_rom_size = 0; /* hardcoded in SeaBIOS with FIXME comment */
-
- t->bios_characteristics = cpu_to_le64(0x08); /* Not supported */
- t->bios_characteristics_extension_bytes[0] = 0;
- t->bios_characteristics_extension_bytes[1] = 0x14; /* TCD/SVVP | VM */
- if (type0.uefi) {
- t->bios_characteristics_extension_bytes[1] |= 0x08; /* |= UEFI */
- }
-
- if (type0.have_major_minor) {
- t->system_bios_major_release = type0.major;
- t->system_bios_minor_release = type0.minor;
- } else {
- t->system_bios_major_release = 0;
- t->system_bios_minor_release = 0;
- }
-
- /* hardcoded in SeaBIOS */
- t->embedded_controller_major_release = 0xFF;
- t->embedded_controller_minor_release = 0xFF;
-
- SMBIOS_BUILD_TABLE_POST;
-}
-
-/* Encode UUID from the big endian encoding described on RFC4122 to the wire
- * format specified by SMBIOS version 2.6.
- */
-static void smbios_encode_uuid(struct smbios_uuid *uuid, const uint8_t *buf)
-{
- memcpy(uuid, buf, 16);
- if (smbios_uuid_encoded) {
- uuid->time_low = bswap32(uuid->time_low);
- uuid->time_mid = bswap16(uuid->time_mid);
- uuid->time_hi_and_version = bswap16(uuid->time_hi_and_version);
- }
-}
-
-static void smbios_build_type_1_table(void)
-{
- SMBIOS_BUILD_TABLE_PRE(1, 0x100, true); /* required */
-
- SMBIOS_TABLE_SET_STR(1, manufacturer_str, type1.manufacturer);
- SMBIOS_TABLE_SET_STR(1, product_name_str, type1.product);
- SMBIOS_TABLE_SET_STR(1, version_str, type1.version);
- SMBIOS_TABLE_SET_STR(1, serial_number_str, type1.serial);
- if (qemu_uuid_set) {
- smbios_encode_uuid(&t->uuid, qemu_uuid);
- } else {
- memset(&t->uuid, 0, 16);
- }
- t->wake_up_type = 0x06; /* power switch */
- SMBIOS_TABLE_SET_STR(1, sku_number_str, type1.sku);
- SMBIOS_TABLE_SET_STR(1, family_str, type1.family);
-
- SMBIOS_BUILD_TABLE_POST;
-}
-
-static void smbios_build_type_2_table(void)
-{
- SMBIOS_BUILD_TABLE_PRE(2, 0x200, false); /* optional */
-
- SMBIOS_TABLE_SET_STR(2, manufacturer_str, type2.manufacturer);
- SMBIOS_TABLE_SET_STR(2, product_str, type2.product);
- SMBIOS_TABLE_SET_STR(2, version_str, type2.version);
- SMBIOS_TABLE_SET_STR(2, serial_number_str, type2.serial);
- SMBIOS_TABLE_SET_STR(2, asset_tag_number_str, type2.asset);
- t->feature_flags = 0x01; /* Motherboard */
- SMBIOS_TABLE_SET_STR(2, location_str, type2.location);
- t->chassis_handle = cpu_to_le16(0x300); /* Type 3 (System enclosure) */
- t->board_type = 0x0A; /* Motherboard */
- t->contained_element_count = 0;
-
- SMBIOS_BUILD_TABLE_POST;
-}
-
-static void smbios_build_type_3_table(void)
-{
- SMBIOS_BUILD_TABLE_PRE(3, 0x300, true); /* required */
-
- SMBIOS_TABLE_SET_STR(3, manufacturer_str, type3.manufacturer);
- t->type = 0x01; /* Other */
- SMBIOS_TABLE_SET_STR(3, version_str, type3.version);
- SMBIOS_TABLE_SET_STR(3, serial_number_str, type3.serial);
- SMBIOS_TABLE_SET_STR(3, asset_tag_number_str, type3.asset);
- t->boot_up_state = 0x03; /* Safe */
- t->power_supply_state = 0x03; /* Safe */
- t->thermal_state = 0x03; /* Safe */
- t->security_status = 0x02; /* Unknown */
- t->oem_defined = cpu_to_le32(0);
- t->height = 0;
- t->number_of_power_cords = 0;
- t->contained_element_count = 0;
- SMBIOS_TABLE_SET_STR(3, sku_number_str, type3.sku);
-
- SMBIOS_BUILD_TABLE_POST;
-}
-
-static void smbios_build_type_4_table(unsigned instance)
-{
- char sock_str[128];
-
- SMBIOS_BUILD_TABLE_PRE(4, 0x400 + instance, true); /* required */
-
- snprintf(sock_str, sizeof(sock_str), "%s%2x", type4.sock_pfx, instance);
- SMBIOS_TABLE_SET_STR(4, socket_designation_str, sock_str);
- t->processor_type = 0x03; /* CPU */
- t->processor_family = 0x01; /* Other */
- SMBIOS_TABLE_SET_STR(4, processor_manufacturer_str, type4.manufacturer);
- t->processor_id[0] = cpu_to_le32(smbios_cpuid_version);
- t->processor_id[1] = cpu_to_le32(smbios_cpuid_features);
- SMBIOS_TABLE_SET_STR(4, processor_version_str, type4.version);
- t->voltage = 0;
- t->external_clock = cpu_to_le16(0); /* Unknown */
- /* SVVP requires max_speed and current_speed to not be unknown. */
- t->max_speed = cpu_to_le16(2000); /* 2000 MHz */
- t->current_speed = cpu_to_le16(2000); /* 2000 MHz */
- t->status = 0x41; /* Socket populated, CPU enabled */
- t->processor_upgrade = 0x01; /* Other */
- t->l1_cache_handle = cpu_to_le16(0xFFFF); /* N/A */
- t->l2_cache_handle = cpu_to_le16(0xFFFF); /* N/A */
- t->l3_cache_handle = cpu_to_le16(0xFFFF); /* N/A */
- SMBIOS_TABLE_SET_STR(4, serial_number_str, type4.serial);
- SMBIOS_TABLE_SET_STR(4, asset_tag_number_str, type4.asset);
- SMBIOS_TABLE_SET_STR(4, part_number_str, type4.part);
- t->core_count = t->core_enabled = smp_cores;
- t->thread_count = smp_threads;
- t->processor_characteristics = cpu_to_le16(0x02); /* Unknown */
- t->processor_family2 = cpu_to_le16(0x01); /* Other */
-
- SMBIOS_BUILD_TABLE_POST;
- smbios_type4_count++;
-}
-
-#define ONE_KB ((ram_addr_t)1 << 10)
-#define ONE_MB ((ram_addr_t)1 << 20)
-#define ONE_GB ((ram_addr_t)1 << 30)
-
-#define MAX_T16_STD_SZ 0x80000000 /* 2T in Kilobytes */
-
-static void smbios_build_type_16_table(unsigned dimm_cnt)
-{
- uint64_t size_kb;
-
- SMBIOS_BUILD_TABLE_PRE(16, 0x1000, true); /* required */
-
- t->location = 0x01; /* Other */
- t->use = 0x03; /* System memory */
- t->error_correction = 0x06; /* Multi-bit ECC (for Microsoft, per SeaBIOS) */
- size_kb = QEMU_ALIGN_UP(ram_size, ONE_KB) / ONE_KB;
- if (size_kb < MAX_T16_STD_SZ) {
- t->maximum_capacity = cpu_to_le32(size_kb);
- t->extended_maximum_capacity = cpu_to_le64(0);
- } else {
- t->maximum_capacity = cpu_to_le32(MAX_T16_STD_SZ);
- t->extended_maximum_capacity = cpu_to_le64(ram_size);
- }
- t->memory_error_information_handle = cpu_to_le16(0xFFFE); /* Not provided */
- t->number_of_memory_devices = cpu_to_le16(dimm_cnt);
-
- SMBIOS_BUILD_TABLE_POST;
-}
-
-#define MAX_T17_STD_SZ 0x7FFF /* (32G - 1M), in Megabytes */
-#define MAX_T17_EXT_SZ 0x80000000 /* 2P, in Megabytes */
-
-static void smbios_build_type_17_table(unsigned instance, uint64_t size)
-{
- char loc_str[128];
- uint64_t size_mb;
-
- SMBIOS_BUILD_TABLE_PRE(17, 0x1100 + instance, true); /* required */
-
- t->physical_memory_array_handle = cpu_to_le16(0x1000); /* Type 16 above */
- t->memory_error_information_handle = cpu_to_le16(0xFFFE); /* Not provided */
- t->total_width = cpu_to_le16(0xFFFF); /* Unknown */
- t->data_width = cpu_to_le16(0xFFFF); /* Unknown */
- size_mb = QEMU_ALIGN_UP(size, ONE_MB) / ONE_MB;
- if (size_mb < MAX_T17_STD_SZ) {
- t->size = cpu_to_le16(size_mb);
- t->extended_size = cpu_to_le32(0);
- } else {
- assert(size_mb < MAX_T17_EXT_SZ);
- t->size = cpu_to_le16(MAX_T17_STD_SZ);
- t->extended_size = cpu_to_le32(size_mb);
- }
- t->form_factor = 0x09; /* DIMM */
- t->device_set = 0; /* Not in a set */
- snprintf(loc_str, sizeof(loc_str), "%s %d", type17.loc_pfx, instance);
- SMBIOS_TABLE_SET_STR(17, device_locator_str, loc_str);
- SMBIOS_TABLE_SET_STR(17, bank_locator_str, type17.bank);
- t->memory_type = 0x07; /* RAM */
- t->type_detail = cpu_to_le16(0x02); /* Other */
- t->speed = cpu_to_le16(type17.speed);
- SMBIOS_TABLE_SET_STR(17, manufacturer_str, type17.manufacturer);
- SMBIOS_TABLE_SET_STR(17, serial_number_str, type17.serial);
- SMBIOS_TABLE_SET_STR(17, asset_tag_number_str, type17.asset);
- SMBIOS_TABLE_SET_STR(17, part_number_str, type17.part);
- t->attributes = 0; /* Unknown */
- t->configured_clock_speed = t->speed; /* reuse value for max speed */
- t->minimum_voltage = cpu_to_le16(0); /* Unknown */
- t->maximum_voltage = cpu_to_le16(0); /* Unknown */
- t->configured_voltage = cpu_to_le16(0); /* Unknown */
-
- SMBIOS_BUILD_TABLE_POST;
-}
-
-static void smbios_build_type_19_table(unsigned instance,
- uint64_t start, uint64_t size)
-{
- uint64_t end, start_kb, end_kb;
-
- SMBIOS_BUILD_TABLE_PRE(19, 0x1300 + instance, true); /* required */
-
- end = start + size - 1;
- assert(end > start);
- start_kb = start / ONE_KB;
- end_kb = end / ONE_KB;
- if (start_kb < UINT32_MAX && end_kb < UINT32_MAX) {
- t->starting_address = cpu_to_le32(start_kb);
- t->ending_address = cpu_to_le32(end_kb);
- t->extended_starting_address =
- t->extended_ending_address = cpu_to_le64(0);
- } else {
- t->starting_address = t->ending_address = cpu_to_le32(UINT32_MAX);
- t->extended_starting_address = cpu_to_le64(start);
- t->extended_ending_address = cpu_to_le64(end);
- }
- t->memory_array_handle = cpu_to_le16(0x1000); /* Type 16 above */
- t->partition_width = 1; /* One device per row */
-
- SMBIOS_BUILD_TABLE_POST;
-}
-
-static void smbios_build_type_32_table(void)
-{
- SMBIOS_BUILD_TABLE_PRE(32, 0x2000, true); /* required */
-
- memset(t->reserved, 0, 6);
- t->boot_status = 0; /* No errors detected */
-
- SMBIOS_BUILD_TABLE_POST;
-}
-
-static void smbios_build_type_127_table(void)
-{
- SMBIOS_BUILD_TABLE_PRE(127, 0x7F00, true); /* required */
- SMBIOS_BUILD_TABLE_POST;
-}
-
-void smbios_set_cpuid(uint32_t version, uint32_t features)
-{
- smbios_cpuid_version = version;
- smbios_cpuid_features = features;
-}
-
-#define SMBIOS_SET_DEFAULT(field, value) \
- if (!field) { \
- field = value; \
- }
-
-void smbios_set_defaults(const char *manufacturer, const char *product,
- const char *version, bool legacy_mode,
- bool uuid_encoded, SmbiosEntryPointType ep_type)
-{
- smbios_have_defaults = true;
- smbios_legacy = legacy_mode;
- smbios_uuid_encoded = uuid_encoded;
- smbios_ep_type = ep_type;
-
- /* drop unwanted version of command-line file blob(s) */
- if (smbios_legacy) {
- g_free(smbios_tables);
- /* in legacy mode, also complain if fields were given for types > 1 */
- if (find_next_bit(have_fields_bitmap,
- SMBIOS_MAX_TYPE+1, 2) < SMBIOS_MAX_TYPE+1) {
- error_report("can't process fields for smbios "
- "types > 1 on machine versions < 2.1!");
- exit(1);
- }
- } else {
- g_free(smbios_entries);
- }
-
- SMBIOS_SET_DEFAULT(type1.manufacturer, manufacturer);
- SMBIOS_SET_DEFAULT(type1.product, product);
- SMBIOS_SET_DEFAULT(type1.version, version);
- SMBIOS_SET_DEFAULT(type2.manufacturer, manufacturer);
- SMBIOS_SET_DEFAULT(type2.product, product);
- SMBIOS_SET_DEFAULT(type2.version, version);
- SMBIOS_SET_DEFAULT(type3.manufacturer, manufacturer);
- SMBIOS_SET_DEFAULT(type3.version, version);
- SMBIOS_SET_DEFAULT(type4.sock_pfx, "CPU");
- SMBIOS_SET_DEFAULT(type4.manufacturer, manufacturer);
- SMBIOS_SET_DEFAULT(type4.version, version);
- SMBIOS_SET_DEFAULT(type17.loc_pfx, "DIMM");
- SMBIOS_SET_DEFAULT(type17.manufacturer, manufacturer);
-}
-
-static void smbios_entry_point_setup(void)
-{
- switch (smbios_ep_type) {
- case SMBIOS_ENTRY_POINT_21:
- memcpy(ep.ep21.anchor_string, "_SM_", 4);
- memcpy(ep.ep21.intermediate_anchor_string, "_DMI_", 5);
- ep.ep21.length = sizeof(struct smbios_21_entry_point);
- ep.ep21.entry_point_revision = 0; /* formatted_area reserved */
- memset(ep.ep21.formatted_area, 0, 5);
-
- /* compliant with smbios spec v2.8 */
- ep.ep21.smbios_major_version = 2;
- ep.ep21.smbios_minor_version = 8;
- ep.ep21.smbios_bcd_revision = 0x28;
-
- /* set during table construction, but BIOS may override: */
- ep.ep21.structure_table_length = cpu_to_le16(smbios_tables_len);
- ep.ep21.max_structure_size = cpu_to_le16(smbios_table_max);
- ep.ep21.number_of_structures = cpu_to_le16(smbios_table_cnt);
-
- /* BIOS must recalculate */
- ep.ep21.checksum = 0;
- ep.ep21.intermediate_checksum = 0;
- ep.ep21.structure_table_address = cpu_to_le32(0);
-
- break;
- case SMBIOS_ENTRY_POINT_30:
- memcpy(ep.ep30.anchor_string, "_SM3_", 5);
- ep.ep30.length = sizeof(struct smbios_30_entry_point);
- ep.ep30.entry_point_revision = 1;
- ep.ep30.reserved = 0;
-
- /* compliant with smbios spec 3.0 */
- ep.ep30.smbios_major_version = 3;
- ep.ep30.smbios_minor_version = 0;
- ep.ep30.smbios_doc_rev = 0;
-
- /* set during table construct, but BIOS might override */
- ep.ep30.structure_table_max_size = cpu_to_le32(smbios_tables_len);
-
- /* BIOS must recalculate */
- ep.ep30.checksum = 0;
- ep.ep30.structure_table_address = cpu_to_le64(0);
-
- break;
- default:
- abort();
- break;
- }
-}
-
-void smbios_get_tables(const struct smbios_phys_mem_area *mem_array,
- const unsigned int mem_array_size,
- uint8_t **tables, size_t *tables_len,
- uint8_t **anchor, size_t *anchor_len)
-{
- unsigned i, dimm_cnt;
-
- if (smbios_legacy) {
- *tables = *anchor = NULL;
- *tables_len = *anchor_len = 0;
- return;
- }
-
- if (!smbios_immutable) {
- smbios_build_type_0_table();
- smbios_build_type_1_table();
- smbios_build_type_2_table();
- smbios_build_type_3_table();
-
- smbios_smp_sockets = DIV_ROUND_UP(smp_cpus, smp_cores * smp_threads);
- assert(smbios_smp_sockets >= 1);
-
- for (i = 0; i < smbios_smp_sockets; i++) {
- smbios_build_type_4_table(i);
- }
-
-#define MAX_DIMM_SZ (16ll * ONE_GB)
-#define GET_DIMM_SZ ((i < dimm_cnt - 1) ? MAX_DIMM_SZ \
- : ((ram_size - 1) % MAX_DIMM_SZ) + 1)
-
- dimm_cnt = QEMU_ALIGN_UP(ram_size, MAX_DIMM_SZ) / MAX_DIMM_SZ;
-
- smbios_build_type_16_table(dimm_cnt);
-
- for (i = 0; i < dimm_cnt; i++) {
- smbios_build_type_17_table(i, GET_DIMM_SZ);
- }
-
- for (i = 0; i < mem_array_size; i++) {
- smbios_build_type_19_table(i, mem_array[i].address,
- mem_array[i].length);
- }
-
- smbios_build_type_32_table();
- smbios_build_type_127_table();
-
- smbios_validate_table();
- smbios_entry_point_setup();
- smbios_immutable = true;
- }
-
- /* return tables blob and entry point (anchor), and their sizes */
- *tables = smbios_tables;
- *tables_len = smbios_tables_len;
- *anchor = (uint8_t *)&ep;
-
- /* calculate length based on anchor string */
- if (!strncmp((char *)&ep, "_SM_", 4)) {
- *anchor_len = sizeof(struct smbios_21_entry_point);
- } else if (!strncmp((char *)&ep, "_SM3_", 5)) {
- *anchor_len = sizeof(struct smbios_30_entry_point);
- } else {
- abort();
- }
-}
-
-static void save_opt(const char **dest, QemuOpts *opts, const char *name)
-{
- const char *val = qemu_opt_get(opts, name);
-
- if (val) {
- *dest = val;
- }
-}
-
-void smbios_entry_add(QemuOpts *opts)
-{
- const char *val;
-
- assert(!smbios_immutable);
-
- val = qemu_opt_get(opts, "file");
- if (val) {
- struct smbios_structure_header *header;
- int size;
- struct smbios_table *table; /* legacy mode only */
-
- qemu_opts_validate(opts, qemu_smbios_file_opts, &error_fatal);
-
- size = get_image_size(val);
- if (size == -1 || size < sizeof(struct smbios_structure_header)) {
- error_report("Cannot read SMBIOS file %s", val);
- exit(1);
- }
-
- /*
- * NOTE: standard double '\0' terminator expected, per smbios spec.
- * (except in legacy mode, where the second '\0' is implicit and
- * will be inserted by the BIOS).
- */
- smbios_tables = g_realloc(smbios_tables, smbios_tables_len + size);
- header = (struct smbios_structure_header *)(smbios_tables +
- smbios_tables_len);
-
- if (load_image(val, (uint8_t *)header) != size) {
- error_report("Failed to load SMBIOS file %s", val);
- exit(1);
- }
-
- if (test_bit(header->type, have_fields_bitmap)) {
- error_report("can't load type %d struct, fields already specified!",
- header->type);
- exit(1);
- }
- set_bit(header->type, have_binfile_bitmap);
-
- if (header->type == 4) {
- smbios_type4_count++;
- }
-
- smbios_tables_len += size;
- if (size > smbios_table_max) {
- smbios_table_max = size;
- }
- smbios_table_cnt++;
-
- /* add a copy of the newly loaded blob to legacy smbios_entries */
- /* NOTE: This code runs before smbios_set_defaults(), so we don't
- * yet know which mode (legacy vs. aggregate-table) will be
- * required. We therefore add the binary blob to both legacy
- * (smbios_entries) and aggregate (smbios_tables) tables, and
- * delete the one we don't need from smbios_set_defaults(),
- * once we know which machine version has been requested.
- */
- if (!smbios_entries) {
- smbios_entries_len = sizeof(uint16_t);
- smbios_entries = g_malloc0(smbios_entries_len);
- }
- smbios_entries = g_realloc(smbios_entries, smbios_entries_len +
- size + sizeof(*table));
- table = (struct smbios_table *)(smbios_entries + smbios_entries_len);
- table->header.type = SMBIOS_TABLE_ENTRY;
- table->header.length = cpu_to_le16(sizeof(*table) + size);
- memcpy(table->data, header, size);
- smbios_entries_len += sizeof(*table) + size;
- (*(uint16_t *)smbios_entries) =
- cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1);
- /* end: add a copy of the newly loaded blob to legacy smbios_entries */
-
- return;
- }
-
- val = qemu_opt_get(opts, "type");
- if (val) {
- unsigned long type = strtoul(val, NULL, 0);
-
- if (type > SMBIOS_MAX_TYPE) {
- error_report("out of range!");
- exit(1);
- }
-
- if (test_bit(type, have_binfile_bitmap)) {
- error_report("can't add fields, binary file already loaded!");
- exit(1);
- }
- set_bit(type, have_fields_bitmap);
-
- switch (type) {
- case 0:
- qemu_opts_validate(opts, qemu_smbios_type0_opts, &error_fatal);
- save_opt(&type0.vendor, opts, "vendor");
- save_opt(&type0.version, opts, "version");
- save_opt(&type0.date, opts, "date");
- type0.uefi = qemu_opt_get_bool(opts, "uefi", false);
-
- val = qemu_opt_get(opts, "release");
- if (val) {
- if (sscanf(val, "%hhu.%hhu", &type0.major, &type0.minor) != 2) {
- error_report("Invalid release");
- exit(1);
- }
- type0.have_major_minor = true;
- }
- return;
- case 1:
- qemu_opts_validate(opts, qemu_smbios_type1_opts, &error_fatal);
- save_opt(&type1.manufacturer, opts, "manufacturer");
- save_opt(&type1.product, opts, "product");
- save_opt(&type1.version, opts, "version");
- save_opt(&type1.serial, opts, "serial");
- save_opt(&type1.sku, opts, "sku");
- save_opt(&type1.family, opts, "family");
-
- val = qemu_opt_get(opts, "uuid");
- if (val) {
- if (qemu_uuid_parse(val, qemu_uuid) != 0) {
- error_report("Invalid UUID");
- exit(1);
- }
- qemu_uuid_set = true;
- }
- return;
- case 2:
- qemu_opts_validate(opts, qemu_smbios_type2_opts, &error_fatal);
- save_opt(&type2.manufacturer, opts, "manufacturer");
- save_opt(&type2.product, opts, "product");
- save_opt(&type2.version, opts, "version");
- save_opt(&type2.serial, opts, "serial");
- save_opt(&type2.asset, opts, "asset");
- save_opt(&type2.location, opts, "location");
- return;
- case 3:
- qemu_opts_validate(opts, qemu_smbios_type3_opts, &error_fatal);
- save_opt(&type3.manufacturer, opts, "manufacturer");
- save_opt(&type3.version, opts, "version");
- save_opt(&type3.serial, opts, "serial");
- save_opt(&type3.asset, opts, "asset");
- save_opt(&type3.sku, opts, "sku");
- return;
- case 4:
- qemu_opts_validate(opts, qemu_smbios_type4_opts, &error_fatal);
- save_opt(&type4.sock_pfx, opts, "sock_pfx");
- save_opt(&type4.manufacturer, opts, "manufacturer");
- save_opt(&type4.version, opts, "version");
- save_opt(&type4.serial, opts, "serial");
- save_opt(&type4.asset, opts, "asset");
- save_opt(&type4.part, opts, "part");
- return;
- case 17:
- qemu_opts_validate(opts, qemu_smbios_type17_opts, &error_fatal);
- save_opt(&type17.loc_pfx, opts, "loc_pfx");
- save_opt(&type17.bank, opts, "bank");
- save_opt(&type17.manufacturer, opts, "manufacturer");
- save_opt(&type17.serial, opts, "serial");
- save_opt(&type17.asset, opts, "asset");
- save_opt(&type17.part, opts, "part");
- type17.speed = qemu_opt_get_number(opts, "speed", 0);
- return;
- default:
- error_report("Don't know how to build fields for SMBIOS type %ld",
- type);
- exit(1);
- }
- }
-
- error_report("Must specify type= or file=");
- exit(1);
-}
diff --git a/qemu/hw/sparc/Makefile.objs b/qemu/hw/sparc/Makefile.objs
deleted file mode 100644
index c987b5b5d..000000000
--- a/qemu/hw/sparc/Makefile.objs
+++ /dev/null
@@ -1 +0,0 @@
-obj-y += sun4m.o leon3.o
diff --git a/qemu/hw/sparc/leon3.c b/qemu/hw/sparc/leon3.c
deleted file mode 100644
index dbae41f3a..000000000
--- a/qemu/hw/sparc/leon3.c
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * QEMU Leon3 System Emulator
- *
- * Copyright (c) 2010-2011 AdaCore
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/hw.h"
-#include "qemu/timer.h"
-#include "hw/ptimer.h"
-#include "sysemu/char.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/qtest.h"
-#include "hw/boards.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "trace.h"
-#include "exec/address-spaces.h"
-
-#include "hw/sparc/grlib.h"
-
-/* Default system clock. */
-#define CPU_CLK (40 * 1000 * 1000)
-
-#define PROM_FILENAME "u-boot.bin"
-
-#define MAX_PILS 16
-
-typedef struct ResetData {
- SPARCCPU *cpu;
- uint32_t entry; /* save kernel entry in case of reset */
- target_ulong sp; /* initial stack pointer */
-} ResetData;
-
-static void main_cpu_reset(void *opaque)
-{
- ResetData *s = (ResetData *)opaque;
- CPUState *cpu = CPU(s->cpu);
- CPUSPARCState *env = &s->cpu->env;
-
- cpu_reset(cpu);
-
- cpu->halted = 0;
- env->pc = s->entry;
- env->npc = s->entry + 4;
- env->regbase[6] = s->sp;
-}
-
-void leon3_irq_ack(void *irq_manager, int intno)
-{
- grlib_irqmp_ack((DeviceState *)irq_manager, intno);
-}
-
-static void leon3_set_pil_in(void *opaque, uint32_t pil_in)
-{
- CPUSPARCState *env = (CPUSPARCState *)opaque;
- CPUState *cs;
-
- assert(env != NULL);
-
- env->pil_in = pil_in;
-
- if (env->pil_in && (env->interrupt_index == 0 ||
- (env->interrupt_index & ~15) == TT_EXTINT)) {
- unsigned int i;
-
- for (i = 15; i > 0; i--) {
- if (env->pil_in & (1 << i)) {
- int old_interrupt = env->interrupt_index;
-
- env->interrupt_index = TT_EXTINT | i;
- if (old_interrupt != env->interrupt_index) {
- cs = CPU(sparc_env_get_cpu(env));
- trace_leon3_set_irq(i);
- cpu_interrupt(cs, CPU_INTERRUPT_HARD);
- }
- break;
- }
- }
- } else if (!env->pil_in && (env->interrupt_index & ~15) == TT_EXTINT) {
- cs = CPU(sparc_env_get_cpu(env));
- trace_leon3_reset_irq(env->interrupt_index & 15);
- env->interrupt_index = 0;
- cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
- }
-}
-
-static void leon3_generic_hw_init(MachineState *machine)
-{
- ram_addr_t ram_size = machine->ram_size;
- const char *cpu_model = machine->cpu_model;
- const char *kernel_filename = machine->kernel_filename;
- SPARCCPU *cpu;
- CPUSPARCState *env;
- MemoryRegion *address_space_mem = get_system_memory();
- MemoryRegion *ram = g_new(MemoryRegion, 1);
- MemoryRegion *prom = g_new(MemoryRegion, 1);
- int ret;
- char *filename;
- qemu_irq *cpu_irqs = NULL;
- int bios_size;
- int prom_size;
- ResetData *reset_info;
-
- /* Init CPU */
- if (!cpu_model) {
- cpu_model = "LEON3";
- }
-
- cpu = cpu_sparc_init(cpu_model);
- if (cpu == NULL) {
- fprintf(stderr, "qemu: Unable to find Sparc CPU definition\n");
- exit(1);
- }
- env = &cpu->env;
-
- cpu_sparc_set_id(env, 0);
-
- /* Reset data */
- reset_info = g_malloc0(sizeof(ResetData));
- reset_info->cpu = cpu;
- reset_info->sp = 0x40000000 + ram_size;
- qemu_register_reset(main_cpu_reset, reset_info);
-
- /* Allocate IRQ manager */
- grlib_irqmp_create(0x80000200, env, &cpu_irqs, MAX_PILS, &leon3_set_pil_in);
-
- env->qemu_irq_ack = leon3_irq_manager;
-
- /* Allocate RAM */
- if ((uint64_t)ram_size > (1UL << 30)) {
- fprintf(stderr,
- "qemu: Too much memory for this machine: %d, maximum 1G\n",
- (unsigned int)(ram_size / (1024 * 1024)));
- exit(1);
- }
-
- memory_region_allocate_system_memory(ram, NULL, "leon3.ram", ram_size);
- memory_region_add_subregion(address_space_mem, 0x40000000, ram);
-
- /* Allocate BIOS */
- prom_size = 8 * 1024 * 1024; /* 8Mb */
- memory_region_init_ram(prom, NULL, "Leon3.bios", prom_size, &error_fatal);
- vmstate_register_ram_global(prom);
- memory_region_set_readonly(prom, true);
- memory_region_add_subregion(address_space_mem, 0x00000000, prom);
-
- /* Load boot prom */
- if (bios_name == NULL) {
- bios_name = PROM_FILENAME;
- }
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
-
- bios_size = get_image_size(filename);
-
- if (bios_size > prom_size) {
- fprintf(stderr, "qemu: could not load prom '%s': file too big\n",
- filename);
- exit(1);
- }
-
- if (bios_size > 0) {
- ret = load_image_targphys(filename, 0x00000000, bios_size);
- if (ret < 0 || ret > prom_size) {
- fprintf(stderr, "qemu: could not load prom '%s'\n", filename);
- exit(1);
- }
- } else if (kernel_filename == NULL && !qtest_enabled()) {
- fprintf(stderr, "Can't read bios image %s\n", filename);
- exit(1);
- }
- g_free(filename);
-
- /* Can directly load an application. */
- if (kernel_filename != NULL) {
- long kernel_size;
- uint64_t entry;
-
- kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL,
- 1 /* big endian */, EM_SPARC, 0, 0);
- if (kernel_size < 0) {
- fprintf(stderr, "qemu: could not load kernel '%s'\n",
- kernel_filename);
- exit(1);
- }
- if (bios_size <= 0) {
- /* If there is no bios/monitor, start the application. */
- env->pc = entry;
- env->npc = entry + 4;
- reset_info->entry = entry;
- }
- }
-
- /* Allocate timers */
- grlib_gptimer_create(0x80000300, 2, CPU_CLK, cpu_irqs, 6);
-
- /* Allocate uart */
- if (serial_hds[0]) {
- grlib_apbuart_create(0x80000100, serial_hds[0], cpu_irqs[3]);
- }
-}
-
-static void leon3_generic_machine_init(MachineClass *mc)
-{
- mc->desc = "Leon-3 generic";
- mc->init = leon3_generic_hw_init;
-}
-
-DEFINE_MACHINE("leon3_generic", leon3_generic_machine_init)
diff --git a/qemu/hw/sparc/sun4m.c b/qemu/hw/sparc/sun4m.c
deleted file mode 100644
index 7bfc00abc..000000000
--- a/qemu/hw/sparc/sun4m.c
+++ /dev/null
@@ -1,1572 +0,0 @@
-/*
- * QEMU Sun4m & Sun4d & Sun4c System Emulator
- *
- * Copyright (c) 2003-2005 Fabrice Bellard
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/sysbus.h"
-#include "qemu/error-report.h"
-#include "qemu/timer.h"
-#include "hw/sparc/sun4m.h"
-#include "hw/timer/m48t59.h"
-#include "hw/sparc/sparc32_dma.h"
-#include "hw/block/fdc.h"
-#include "sysemu/sysemu.h"
-#include "net/net.h"
-#include "hw/boards.h"
-#include "hw/nvram/openbios_firmware_abi.h"
-#include "hw/scsi/esp.h"
-#include "hw/i386/pc.h"
-#include "hw/isa/isa.h"
-#include "hw/nvram/fw_cfg.h"
-#include "hw/char/escc.h"
-#include "hw/empty_slot.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "sysemu/block-backend.h"
-#include "trace.h"
-#include "qemu/cutils.h"
-
-/*
- * Sun4m architecture was used in the following machines:
- *
- * SPARCserver 6xxMP/xx
- * SPARCclassic (SPARCclassic Server)(SPARCstation LC) (4/15),
- * SPARCclassic X (4/10)
- * SPARCstation LX/ZX (4/30)
- * SPARCstation Voyager
- * SPARCstation 10/xx, SPARCserver 10/xx
- * SPARCstation 5, SPARCserver 5
- * SPARCstation 20/xx, SPARCserver 20
- * SPARCstation 4
- *
- * See for example: http://www.sunhelp.org/faq/sunref1.html
- */
-
-#define KERNEL_LOAD_ADDR 0x00004000
-#define CMDLINE_ADDR 0x007ff000
-#define INITRD_LOAD_ADDR 0x00800000
-#define PROM_SIZE_MAX (1024 * 1024)
-#define PROM_VADDR 0xffd00000
-#define PROM_FILENAME "openbios-sparc32"
-#define CFG_ADDR 0xd00000510ULL
-#define FW_CFG_SUN4M_DEPTH (FW_CFG_ARCH_LOCAL + 0x00)
-#define FW_CFG_SUN4M_WIDTH (FW_CFG_ARCH_LOCAL + 0x01)
-#define FW_CFG_SUN4M_HEIGHT (FW_CFG_ARCH_LOCAL + 0x02)
-
-#define MAX_CPUS 16
-#define MAX_PILS 16
-#define MAX_VSIMMS 4
-
-#define ESCC_CLOCK 4915200
-
-struct sun4m_hwdef {
- hwaddr iommu_base, iommu_pad_base, iommu_pad_len, slavio_base;
- hwaddr intctl_base, counter_base, nvram_base, ms_kb_base;
- hwaddr serial_base, fd_base;
- hwaddr afx_base, idreg_base, dma_base, esp_base, le_base;
- hwaddr tcx_base, cs_base, apc_base, aux1_base, aux2_base;
- hwaddr bpp_base, dbri_base, sx_base;
- struct {
- hwaddr reg_base, vram_base;
- } vsimm[MAX_VSIMMS];
- hwaddr ecc_base;
- uint64_t max_mem;
- const char * const default_cpu_model;
- uint32_t ecc_version;
- uint32_t iommu_version;
- uint16_t machine_id;
- uint8_t nvram_machine_id;
-};
-
-void DMA_init(ISABus *bus, int high_page_enable)
-{
-}
-
-static void fw_cfg_boot_set(void *opaque, const char *boot_device,
- Error **errp)
-{
- fw_cfg_modify_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
-}
-
-static void nvram_init(Nvram *nvram, uint8_t *macaddr,
- const char *cmdline, const char *boot_devices,
- ram_addr_t RAM_size, uint32_t kernel_size,
- int width, int height, int depth,
- int nvram_machine_id, const char *arch)
-{
- unsigned int i;
- uint32_t start, end;
- uint8_t image[0x1ff0];
- struct OpenBIOS_nvpart_v1 *part_header;
- NvramClass *k = NVRAM_GET_CLASS(nvram);
-
- memset(image, '\0', sizeof(image));
-
- start = 0;
-
- // OpenBIOS nvram variables
- // Variable partition
- part_header = (struct OpenBIOS_nvpart_v1 *)&image[start];
- part_header->signature = OPENBIOS_PART_SYSTEM;
- pstrcpy(part_header->name, sizeof(part_header->name), "system");
-
- end = start + sizeof(struct OpenBIOS_nvpart_v1);
- for (i = 0; i < nb_prom_envs; i++)
- end = OpenBIOS_set_var(image, end, prom_envs[i]);
-
- // End marker
- image[end++] = '\0';
-
- end = start + ((end - start + 15) & ~15);
- OpenBIOS_finish_partition(part_header, end - start);
-
- // free partition
- start = end;
- part_header = (struct OpenBIOS_nvpart_v1 *)&image[start];
- part_header->signature = OPENBIOS_PART_FREE;
- pstrcpy(part_header->name, sizeof(part_header->name), "free");
-
- end = 0x1fd0;
- OpenBIOS_finish_partition(part_header, end - start);
-
- Sun_init_header((struct Sun_nvram *)&image[0x1fd8], macaddr,
- nvram_machine_id);
-
- for (i = 0; i < sizeof(image); i++) {
- (k->write)(nvram, i, image[i]);
- }
-}
-
-static DeviceState *slavio_intctl;
-
-void sun4m_hmp_info_pic(Monitor *mon, const QDict *qdict)
-{
- if (slavio_intctl)
- slavio_pic_info(mon, slavio_intctl);
-}
-
-void sun4m_hmp_info_irq(Monitor *mon, const QDict *qdict)
-{
- if (slavio_intctl)
- slavio_irq_info(mon, slavio_intctl);
-}
-
-void cpu_check_irqs(CPUSPARCState *env)
-{
- CPUState *cs;
-
- if (env->pil_in && (env->interrupt_index == 0 ||
- (env->interrupt_index & ~15) == TT_EXTINT)) {
- unsigned int i;
-
- for (i = 15; i > 0; i--) {
- if (env->pil_in & (1 << i)) {
- int old_interrupt = env->interrupt_index;
-
- env->interrupt_index = TT_EXTINT | i;
- if (old_interrupt != env->interrupt_index) {
- cs = CPU(sparc_env_get_cpu(env));
- trace_sun4m_cpu_interrupt(i);
- cpu_interrupt(cs, CPU_INTERRUPT_HARD);
- }
- break;
- }
- }
- } else if (!env->pil_in && (env->interrupt_index & ~15) == TT_EXTINT) {
- cs = CPU(sparc_env_get_cpu(env));
- trace_sun4m_cpu_reset_interrupt(env->interrupt_index & 15);
- env->interrupt_index = 0;
- cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
- }
-}
-
-static void cpu_kick_irq(SPARCCPU *cpu)
-{
- CPUSPARCState *env = &cpu->env;
- CPUState *cs = CPU(cpu);
-
- cs->halted = 0;
- cpu_check_irqs(env);
- qemu_cpu_kick(cs);
-}
-
-static void cpu_set_irq(void *opaque, int irq, int level)
-{
- SPARCCPU *cpu = opaque;
- CPUSPARCState *env = &cpu->env;
-
- if (level) {
- trace_sun4m_cpu_set_irq_raise(irq);
- env->pil_in |= 1 << irq;
- cpu_kick_irq(cpu);
- } else {
- trace_sun4m_cpu_set_irq_lower(irq);
- env->pil_in &= ~(1 << irq);
- cpu_check_irqs(env);
- }
-}
-
-static void dummy_cpu_set_irq(void *opaque, int irq, int level)
-{
-}
-
-static void main_cpu_reset(void *opaque)
-{
- SPARCCPU *cpu = opaque;
- CPUState *cs = CPU(cpu);
-
- cpu_reset(cs);
- cs->halted = 0;
-}
-
-static void secondary_cpu_reset(void *opaque)
-{
- SPARCCPU *cpu = opaque;
- CPUState *cs = CPU(cpu);
-
- cpu_reset(cs);
- cs->halted = 1;
-}
-
-static void cpu_halt_signal(void *opaque, int irq, int level)
-{
- if (level && current_cpu) {
- cpu_interrupt(current_cpu, CPU_INTERRUPT_HALT);
- }
-}
-
-static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
-{
- return addr - 0xf0000000ULL;
-}
-
-static unsigned long sun4m_load_kernel(const char *kernel_filename,
- const char *initrd_filename,
- ram_addr_t RAM_size)
-{
- int linux_boot;
- unsigned int i;
- long initrd_size, kernel_size;
- uint8_t *ptr;
-
- linux_boot = (kernel_filename != NULL);
-
- kernel_size = 0;
- if (linux_boot) {
- int bswap_needed;
-
-#ifdef BSWAP_NEEDED
- bswap_needed = 1;
-#else
- bswap_needed = 0;
-#endif
- kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL,
- NULL, NULL, NULL, 1, EM_SPARC, 0, 0);
- if (kernel_size < 0)
- kernel_size = load_aout(kernel_filename, KERNEL_LOAD_ADDR,
- RAM_size - KERNEL_LOAD_ADDR, bswap_needed,
- TARGET_PAGE_SIZE);
- if (kernel_size < 0)
- kernel_size = load_image_targphys(kernel_filename,
- KERNEL_LOAD_ADDR,
- RAM_size - KERNEL_LOAD_ADDR);
- if (kernel_size < 0) {
- fprintf(stderr, "qemu: could not load kernel '%s'\n",
- kernel_filename);
- exit(1);
- }
-
- /* load initrd */
- initrd_size = 0;
- if (initrd_filename) {
- initrd_size = load_image_targphys(initrd_filename,
- INITRD_LOAD_ADDR,
- RAM_size - INITRD_LOAD_ADDR);
- if (initrd_size < 0) {
- fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
- initrd_filename);
- exit(1);
- }
- }
- if (initrd_size > 0) {
- for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) {
- ptr = rom_ptr(KERNEL_LOAD_ADDR + i);
- if (ldl_p(ptr) == 0x48647253) { // HdrS
- stl_p(ptr + 16, INITRD_LOAD_ADDR);
- stl_p(ptr + 20, initrd_size);
- break;
- }
- }
- }
- }
- return kernel_size;
-}
-
-static void *iommu_init(hwaddr addr, uint32_t version, qemu_irq irq)
-{
- DeviceState *dev;
- SysBusDevice *s;
-
- dev = qdev_create(NULL, "iommu");
- qdev_prop_set_uint32(dev, "version", version);
- qdev_init_nofail(dev);
- s = SYS_BUS_DEVICE(dev);
- sysbus_connect_irq(s, 0, irq);
- sysbus_mmio_map(s, 0, addr);
-
- return s;
-}
-
-static void *sparc32_dma_init(hwaddr daddr, qemu_irq parent_irq,
- void *iommu, qemu_irq *dev_irq, int is_ledma)
-{
- DeviceState *dev;
- SysBusDevice *s;
-
- dev = qdev_create(NULL, "sparc32_dma");
- qdev_prop_set_ptr(dev, "iommu_opaque", iommu);
- qdev_prop_set_uint32(dev, "is_ledma", is_ledma);
- qdev_init_nofail(dev);
- s = SYS_BUS_DEVICE(dev);
- sysbus_connect_irq(s, 0, parent_irq);
- *dev_irq = qdev_get_gpio_in(dev, 0);
- sysbus_mmio_map(s, 0, daddr);
-
- return s;
-}
-
-static void lance_init(NICInfo *nd, hwaddr leaddr,
- void *dma_opaque, qemu_irq irq)
-{
- DeviceState *dev;
- SysBusDevice *s;
- qemu_irq reset;
-
- qemu_check_nic_model(&nd_table[0], "lance");
-
- dev = qdev_create(NULL, "lance");
- qdev_set_nic_properties(dev, nd);
- qdev_prop_set_ptr(dev, "dma", dma_opaque);
- qdev_init_nofail(dev);
- s = SYS_BUS_DEVICE(dev);
- sysbus_mmio_map(s, 0, leaddr);
- sysbus_connect_irq(s, 0, irq);
- reset = qdev_get_gpio_in(dev, 0);
- qdev_connect_gpio_out(dma_opaque, 0, reset);
-}
-
-static DeviceState *slavio_intctl_init(hwaddr addr,
- hwaddr addrg,
- qemu_irq **parent_irq)
-{
- DeviceState *dev;
- SysBusDevice *s;
- unsigned int i, j;
-
- dev = qdev_create(NULL, "slavio_intctl");
- qdev_init_nofail(dev);
-
- s = SYS_BUS_DEVICE(dev);
-
- for (i = 0; i < MAX_CPUS; i++) {
- for (j = 0; j < MAX_PILS; j++) {
- sysbus_connect_irq(s, i * MAX_PILS + j, parent_irq[i][j]);
- }
- }
- sysbus_mmio_map(s, 0, addrg);
- for (i = 0; i < MAX_CPUS; i++) {
- sysbus_mmio_map(s, i + 1, addr + i * TARGET_PAGE_SIZE);
- }
-
- return dev;
-}
-
-#define SYS_TIMER_OFFSET 0x10000ULL
-#define CPU_TIMER_OFFSET(cpu) (0x1000ULL * cpu)
-
-static void slavio_timer_init_all(hwaddr addr, qemu_irq master_irq,
- qemu_irq *cpu_irqs, unsigned int num_cpus)
-{
- DeviceState *dev;
- SysBusDevice *s;
- unsigned int i;
-
- dev = qdev_create(NULL, "slavio_timer");
- qdev_prop_set_uint32(dev, "num_cpus", num_cpus);
- qdev_init_nofail(dev);
- s = SYS_BUS_DEVICE(dev);
- sysbus_connect_irq(s, 0, master_irq);
- sysbus_mmio_map(s, 0, addr + SYS_TIMER_OFFSET);
-
- for (i = 0; i < MAX_CPUS; i++) {
- sysbus_mmio_map(s, i + 1, addr + (hwaddr)CPU_TIMER_OFFSET(i));
- sysbus_connect_irq(s, i + 1, cpu_irqs[i]);
- }
-}
-
-static qemu_irq slavio_system_powerdown;
-
-static void slavio_powerdown_req(Notifier *n, void *opaque)
-{
- qemu_irq_raise(slavio_system_powerdown);
-}
-
-static Notifier slavio_system_powerdown_notifier = {
- .notify = slavio_powerdown_req
-};
-
-#define MISC_LEDS 0x01600000
-#define MISC_CFG 0x01800000
-#define MISC_DIAG 0x01a00000
-#define MISC_MDM 0x01b00000
-#define MISC_SYS 0x01f00000
-
-static void slavio_misc_init(hwaddr base,
- hwaddr aux1_base,
- hwaddr aux2_base, qemu_irq irq,
- qemu_irq fdc_tc)
-{
- DeviceState *dev;
- SysBusDevice *s;
-
- dev = qdev_create(NULL, "slavio_misc");
- qdev_init_nofail(dev);
- s = SYS_BUS_DEVICE(dev);
- if (base) {
- /* 8 bit registers */
- /* Slavio control */
- sysbus_mmio_map(s, 0, base + MISC_CFG);
- /* Diagnostics */
- sysbus_mmio_map(s, 1, base + MISC_DIAG);
- /* Modem control */
- sysbus_mmio_map(s, 2, base + MISC_MDM);
- /* 16 bit registers */
- /* ss600mp diag LEDs */
- sysbus_mmio_map(s, 3, base + MISC_LEDS);
- /* 32 bit registers */
- /* System control */
- sysbus_mmio_map(s, 4, base + MISC_SYS);
- }
- if (aux1_base) {
- /* AUX 1 (Misc System Functions) */
- sysbus_mmio_map(s, 5, aux1_base);
- }
- if (aux2_base) {
- /* AUX 2 (Software Powerdown Control) */
- sysbus_mmio_map(s, 6, aux2_base);
- }
- sysbus_connect_irq(s, 0, irq);
- sysbus_connect_irq(s, 1, fdc_tc);
- slavio_system_powerdown = qdev_get_gpio_in(dev, 0);
- qemu_register_powerdown_notifier(&slavio_system_powerdown_notifier);
-}
-
-static void ecc_init(hwaddr base, qemu_irq irq, uint32_t version)
-{
- DeviceState *dev;
- SysBusDevice *s;
-
- dev = qdev_create(NULL, "eccmemctl");
- qdev_prop_set_uint32(dev, "version", version);
- qdev_init_nofail(dev);
- s = SYS_BUS_DEVICE(dev);
- sysbus_connect_irq(s, 0, irq);
- sysbus_mmio_map(s, 0, base);
- if (version == 0) { // SS-600MP only
- sysbus_mmio_map(s, 1, base + 0x1000);
- }
-}
-
-static void apc_init(hwaddr power_base, qemu_irq cpu_halt)
-{
- DeviceState *dev;
- SysBusDevice *s;
-
- dev = qdev_create(NULL, "apc");
- qdev_init_nofail(dev);
- s = SYS_BUS_DEVICE(dev);
- /* Power management (APC) XXX: not a Slavio device */
- sysbus_mmio_map(s, 0, power_base);
- sysbus_connect_irq(s, 0, cpu_halt);
-}
-
-static void tcx_init(hwaddr addr, qemu_irq irq, int vram_size, int width,
- int height, int depth)
-{
- DeviceState *dev;
- SysBusDevice *s;
-
- dev = qdev_create(NULL, "SUNW,tcx");
- qdev_prop_set_uint32(dev, "vram_size", vram_size);
- qdev_prop_set_uint16(dev, "width", width);
- qdev_prop_set_uint16(dev, "height", height);
- qdev_prop_set_uint16(dev, "depth", depth);
- qdev_prop_set_uint64(dev, "prom_addr", addr);
- qdev_init_nofail(dev);
- s = SYS_BUS_DEVICE(dev);
-
- /* 10/ROM : FCode ROM */
- sysbus_mmio_map(s, 0, addr);
- /* 2/STIP : Stipple */
- sysbus_mmio_map(s, 1, addr + 0x04000000ULL);
- /* 3/BLIT : Blitter */
- sysbus_mmio_map(s, 2, addr + 0x06000000ULL);
- /* 5/RSTIP : Raw Stipple */
- sysbus_mmio_map(s, 3, addr + 0x0c000000ULL);
- /* 6/RBLIT : Raw Blitter */
- sysbus_mmio_map(s, 4, addr + 0x0e000000ULL);
- /* 7/TEC : Transform Engine */
- sysbus_mmio_map(s, 5, addr + 0x00700000ULL);
- /* 8/CMAP : DAC */
- sysbus_mmio_map(s, 6, addr + 0x00200000ULL);
- /* 9/THC : */
- if (depth == 8) {
- sysbus_mmio_map(s, 7, addr + 0x00300000ULL);
- } else {
- sysbus_mmio_map(s, 7, addr + 0x00301000ULL);
- }
- /* 11/DHC : */
- sysbus_mmio_map(s, 8, addr + 0x00240000ULL);
- /* 12/ALT : */
- sysbus_mmio_map(s, 9, addr + 0x00280000ULL);
- /* 0/DFB8 : 8-bit plane */
- sysbus_mmio_map(s, 10, addr + 0x00800000ULL);
- /* 1/DFB24 : 24bit plane */
- sysbus_mmio_map(s, 11, addr + 0x02000000ULL);
- /* 4/RDFB32: Raw framebuffer. Control plane */
- sysbus_mmio_map(s, 12, addr + 0x0a000000ULL);
- /* 9/THC24bits : NetBSD writes here even with 8-bit display: dummy */
- if (depth == 8) {
- sysbus_mmio_map(s, 13, addr + 0x00301000ULL);
- }
-
- sysbus_connect_irq(s, 0, irq);
-}
-
-static void cg3_init(hwaddr addr, qemu_irq irq, int vram_size, int width,
- int height, int depth)
-{
- DeviceState *dev;
- SysBusDevice *s;
-
- dev = qdev_create(NULL, "cgthree");
- qdev_prop_set_uint32(dev, "vram-size", vram_size);
- qdev_prop_set_uint16(dev, "width", width);
- qdev_prop_set_uint16(dev, "height", height);
- qdev_prop_set_uint16(dev, "depth", depth);
- qdev_prop_set_uint64(dev, "prom-addr", addr);
- qdev_init_nofail(dev);
- s = SYS_BUS_DEVICE(dev);
-
- /* FCode ROM */
- sysbus_mmio_map(s, 0, addr);
- /* DAC */
- sysbus_mmio_map(s, 1, addr + 0x400000ULL);
- /* 8-bit plane */
- sysbus_mmio_map(s, 2, addr + 0x800000ULL);
-
- sysbus_connect_irq(s, 0, irq);
-}
-
-/* NCR89C100/MACIO Internal ID register */
-
-#define TYPE_MACIO_ID_REGISTER "macio_idreg"
-
-static const uint8_t idreg_data[] = { 0xfe, 0x81, 0x01, 0x03 };
-
-static void idreg_init(hwaddr addr)
-{
- DeviceState *dev;
- SysBusDevice *s;
-
- dev = qdev_create(NULL, TYPE_MACIO_ID_REGISTER);
- qdev_init_nofail(dev);
- s = SYS_BUS_DEVICE(dev);
-
- sysbus_mmio_map(s, 0, addr);
- cpu_physical_memory_write_rom(&address_space_memory,
- addr, idreg_data, sizeof(idreg_data));
-}
-
-#define MACIO_ID_REGISTER(obj) \
- OBJECT_CHECK(IDRegState, (obj), TYPE_MACIO_ID_REGISTER)
-
-typedef struct IDRegState {
- SysBusDevice parent_obj;
-
- MemoryRegion mem;
-} IDRegState;
-
-static int idreg_init1(SysBusDevice *dev)
-{
- IDRegState *s = MACIO_ID_REGISTER(dev);
-
- memory_region_init_ram(&s->mem, OBJECT(s),
- "sun4m.idreg", sizeof(idreg_data), &error_fatal);
- vmstate_register_ram_global(&s->mem);
- memory_region_set_readonly(&s->mem, true);
- sysbus_init_mmio(dev, &s->mem);
- return 0;
-}
-
-static void idreg_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = idreg_init1;
-}
-
-static const TypeInfo idreg_info = {
- .name = TYPE_MACIO_ID_REGISTER,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(IDRegState),
- .class_init = idreg_class_init,
-};
-
-#define TYPE_TCX_AFX "tcx_afx"
-#define TCX_AFX(obj) OBJECT_CHECK(AFXState, (obj), TYPE_TCX_AFX)
-
-typedef struct AFXState {
- SysBusDevice parent_obj;
-
- MemoryRegion mem;
-} AFXState;
-
-/* SS-5 TCX AFX register */
-static void afx_init(hwaddr addr)
-{
- DeviceState *dev;
- SysBusDevice *s;
-
- dev = qdev_create(NULL, TYPE_TCX_AFX);
- qdev_init_nofail(dev);
- s = SYS_BUS_DEVICE(dev);
-
- sysbus_mmio_map(s, 0, addr);
-}
-
-static int afx_init1(SysBusDevice *dev)
-{
- AFXState *s = TCX_AFX(dev);
-
- memory_region_init_ram(&s->mem, OBJECT(s), "sun4m.afx", 4, &error_fatal);
- vmstate_register_ram_global(&s->mem);
- sysbus_init_mmio(dev, &s->mem);
- return 0;
-}
-
-static void afx_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = afx_init1;
-}
-
-static const TypeInfo afx_info = {
- .name = TYPE_TCX_AFX,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(AFXState),
- .class_init = afx_class_init,
-};
-
-#define TYPE_OPENPROM "openprom"
-#define OPENPROM(obj) OBJECT_CHECK(PROMState, (obj), TYPE_OPENPROM)
-
-typedef struct PROMState {
- SysBusDevice parent_obj;
-
- MemoryRegion prom;
-} PROMState;
-
-/* Boot PROM (OpenBIOS) */
-static uint64_t translate_prom_address(void *opaque, uint64_t addr)
-{
- hwaddr *base_addr = (hwaddr *)opaque;
- return addr + *base_addr - PROM_VADDR;
-}
-
-static void prom_init(hwaddr addr, const char *bios_name)
-{
- DeviceState *dev;
- SysBusDevice *s;
- char *filename;
- int ret;
-
- dev = qdev_create(NULL, TYPE_OPENPROM);
- qdev_init_nofail(dev);
- s = SYS_BUS_DEVICE(dev);
-
- sysbus_mmio_map(s, 0, addr);
-
- /* load boot prom */
- if (bios_name == NULL) {
- bios_name = PROM_FILENAME;
- }
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
- if (filename) {
- ret = load_elf(filename, translate_prom_address, &addr, NULL,
- NULL, NULL, 1, EM_SPARC, 0, 0);
- if (ret < 0 || ret > PROM_SIZE_MAX) {
- ret = load_image_targphys(filename, addr, PROM_SIZE_MAX);
- }
- g_free(filename);
- } else {
- ret = -1;
- }
- if (ret < 0 || ret > PROM_SIZE_MAX) {
- fprintf(stderr, "qemu: could not load prom '%s'\n", bios_name);
- exit(1);
- }
-}
-
-static int prom_init1(SysBusDevice *dev)
-{
- PROMState *s = OPENPROM(dev);
-
- memory_region_init_ram(&s->prom, OBJECT(s), "sun4m.prom", PROM_SIZE_MAX,
- &error_fatal);
- vmstate_register_ram_global(&s->prom);
- memory_region_set_readonly(&s->prom, true);
- sysbus_init_mmio(dev, &s->prom);
- return 0;
-}
-
-static Property prom_properties[] = {
- {/* end of property list */},
-};
-
-static void prom_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = prom_init1;
- dc->props = prom_properties;
-}
-
-static const TypeInfo prom_info = {
- .name = TYPE_OPENPROM,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PROMState),
- .class_init = prom_class_init,
-};
-
-#define TYPE_SUN4M_MEMORY "memory"
-#define SUN4M_RAM(obj) OBJECT_CHECK(RamDevice, (obj), TYPE_SUN4M_MEMORY)
-
-typedef struct RamDevice {
- SysBusDevice parent_obj;
-
- MemoryRegion ram;
- uint64_t size;
-} RamDevice;
-
-/* System RAM */
-static int ram_init1(SysBusDevice *dev)
-{
- RamDevice *d = SUN4M_RAM(dev);
-
- memory_region_allocate_system_memory(&d->ram, OBJECT(d), "sun4m.ram",
- d->size);
- sysbus_init_mmio(dev, &d->ram);
- return 0;
-}
-
-static void ram_init(hwaddr addr, ram_addr_t RAM_size,
- uint64_t max_mem)
-{
- DeviceState *dev;
- SysBusDevice *s;
- RamDevice *d;
-
- /* allocate RAM */
- if ((uint64_t)RAM_size > max_mem) {
- fprintf(stderr,
- "qemu: Too much memory for this machine: %d, maximum %d\n",
- (unsigned int)(RAM_size / (1024 * 1024)),
- (unsigned int)(max_mem / (1024 * 1024)));
- exit(1);
- }
- dev = qdev_create(NULL, "memory");
- s = SYS_BUS_DEVICE(dev);
-
- d = SUN4M_RAM(dev);
- d->size = RAM_size;
- qdev_init_nofail(dev);
-
- sysbus_mmio_map(s, 0, addr);
-}
-
-static Property ram_properties[] = {
- DEFINE_PROP_UINT64("size", RamDevice, size, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void ram_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = ram_init1;
- dc->props = ram_properties;
-}
-
-static const TypeInfo ram_info = {
- .name = TYPE_SUN4M_MEMORY,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(RamDevice),
- .class_init = ram_class_init,
-};
-
-static void cpu_devinit(const char *cpu_model, unsigned int id,
- uint64_t prom_addr, qemu_irq **cpu_irqs)
-{
- CPUState *cs;
- SPARCCPU *cpu;
- CPUSPARCState *env;
-
- cpu = cpu_sparc_init(cpu_model);
- if (cpu == NULL) {
- fprintf(stderr, "qemu: Unable to find Sparc CPU definition\n");
- exit(1);
- }
- env = &cpu->env;
-
- cpu_sparc_set_id(env, id);
- if (id == 0) {
- qemu_register_reset(main_cpu_reset, cpu);
- } else {
- qemu_register_reset(secondary_cpu_reset, cpu);
- cs = CPU(cpu);
- cs->halted = 1;
- }
- *cpu_irqs = qemu_allocate_irqs(cpu_set_irq, cpu, MAX_PILS);
- env->prom_addr = prom_addr;
-}
-
-static void dummy_fdc_tc(void *opaque, int irq, int level)
-{
-}
-
-static void sun4m_hw_init(const struct sun4m_hwdef *hwdef,
- MachineState *machine)
-{
- const char *cpu_model = machine->cpu_model;
- unsigned int i;
- void *iommu, *espdma, *ledma, *nvram;
- qemu_irq *cpu_irqs[MAX_CPUS], slavio_irq[32], slavio_cpu_irq[MAX_CPUS],
- espdma_irq, ledma_irq;
- qemu_irq esp_reset, dma_enable;
- qemu_irq fdc_tc;
- unsigned long kernel_size;
- DriveInfo *fd[MAX_FD];
- FWCfgState *fw_cfg;
- unsigned int num_vsimms;
-
- /* init CPUs */
- if (!cpu_model)
- cpu_model = hwdef->default_cpu_model;
-
- for(i = 0; i < smp_cpus; i++) {
- cpu_devinit(cpu_model, i, hwdef->slavio_base, &cpu_irqs[i]);
- }
-
- for (i = smp_cpus; i < MAX_CPUS; i++)
- cpu_irqs[i] = qemu_allocate_irqs(dummy_cpu_set_irq, NULL, MAX_PILS);
-
-
- /* set up devices */
- ram_init(0, machine->ram_size, hwdef->max_mem);
- /* models without ECC don't trap when missing ram is accessed */
- if (!hwdef->ecc_base) {
- empty_slot_init(machine->ram_size, hwdef->max_mem - machine->ram_size);
- }
-
- prom_init(hwdef->slavio_base, bios_name);
-
- slavio_intctl = slavio_intctl_init(hwdef->intctl_base,
- hwdef->intctl_base + 0x10000ULL,
- cpu_irqs);
-
- for (i = 0; i < 32; i++) {
- slavio_irq[i] = qdev_get_gpio_in(slavio_intctl, i);
- }
- for (i = 0; i < MAX_CPUS; i++) {
- slavio_cpu_irq[i] = qdev_get_gpio_in(slavio_intctl, 32 + i);
- }
-
- if (hwdef->idreg_base) {
- idreg_init(hwdef->idreg_base);
- }
-
- if (hwdef->afx_base) {
- afx_init(hwdef->afx_base);
- }
-
- iommu = iommu_init(hwdef->iommu_base, hwdef->iommu_version,
- slavio_irq[30]);
-
- if (hwdef->iommu_pad_base) {
- /* On the real hardware (SS-5, LX) the MMU is not padded, but aliased.
- Software shouldn't use aliased addresses, neither should it crash
- when does. Using empty_slot instead of aliasing can help with
- debugging such accesses */
- empty_slot_init(hwdef->iommu_pad_base,hwdef->iommu_pad_len);
- }
-
- espdma = sparc32_dma_init(hwdef->dma_base, slavio_irq[18],
- iommu, &espdma_irq, 0);
-
- ledma = sparc32_dma_init(hwdef->dma_base + 16ULL,
- slavio_irq[16], iommu, &ledma_irq, 1);
-
- if (graphic_depth != 8 && graphic_depth != 24) {
- error_report("Unsupported depth: %d", graphic_depth);
- exit (1);
- }
- num_vsimms = 0;
- if (num_vsimms == 0) {
- if (vga_interface_type == VGA_CG3) {
- if (graphic_depth != 8) {
- error_report("Unsupported depth: %d", graphic_depth);
- exit(1);
- }
-
- if (!(graphic_width == 1024 && graphic_height == 768) &&
- !(graphic_width == 1152 && graphic_height == 900)) {
- error_report("Unsupported resolution: %d x %d", graphic_width,
- graphic_height);
- exit(1);
- }
-
- /* sbus irq 5 */
- cg3_init(hwdef->tcx_base, slavio_irq[11], 0x00100000,
- graphic_width, graphic_height, graphic_depth);
- } else {
- /* If no display specified, default to TCX */
- if (graphic_depth != 8 && graphic_depth != 24) {
- error_report("Unsupported depth: %d", graphic_depth);
- exit(1);
- }
-
- if (!(graphic_width == 1024 && graphic_height == 768)) {
- error_report("Unsupported resolution: %d x %d",
- graphic_width, graphic_height);
- exit(1);
- }
-
- tcx_init(hwdef->tcx_base, slavio_irq[11], 0x00100000,
- graphic_width, graphic_height, graphic_depth);
- }
- }
-
- for (i = num_vsimms; i < MAX_VSIMMS; i++) {
- /* vsimm registers probed by OBP */
- if (hwdef->vsimm[i].reg_base) {
- empty_slot_init(hwdef->vsimm[i].reg_base, 0x2000);
- }
- }
-
- if (hwdef->sx_base) {
- empty_slot_init(hwdef->sx_base, 0x2000);
- }
-
- lance_init(&nd_table[0], hwdef->le_base, ledma, ledma_irq);
-
- nvram = m48t59_init(slavio_irq[0], hwdef->nvram_base, 0, 0x2000, 1968, 8);
-
- slavio_timer_init_all(hwdef->counter_base, slavio_irq[19], slavio_cpu_irq, smp_cpus);
-
- slavio_serial_ms_kbd_init(hwdef->ms_kb_base, slavio_irq[14],
- display_type == DT_NOGRAPHIC, ESCC_CLOCK, 1);
- /* Slavio TTYA (base+4, Linux ttyS0) is the first QEMU serial device
- Slavio TTYB (base+0, Linux ttyS1) is the second QEMU serial device */
- escc_init(hwdef->serial_base, slavio_irq[15], slavio_irq[15],
- serial_hds[0], serial_hds[1], ESCC_CLOCK, 1);
-
- if (hwdef->apc_base) {
- apc_init(hwdef->apc_base, qemu_allocate_irq(cpu_halt_signal, NULL, 0));
- }
-
- if (hwdef->fd_base) {
- /* there is zero or one floppy drive */
- memset(fd, 0, sizeof(fd));
- fd[0] = drive_get(IF_FLOPPY, 0, 0);
- sun4m_fdctrl_init(slavio_irq[22], hwdef->fd_base, fd,
- &fdc_tc);
- } else {
- fdc_tc = qemu_allocate_irq(dummy_fdc_tc, NULL, 0);
- }
-
- slavio_misc_init(hwdef->slavio_base, hwdef->aux1_base, hwdef->aux2_base,
- slavio_irq[30], fdc_tc);
-
- if (drive_get_max_bus(IF_SCSI) > 0) {
- fprintf(stderr, "qemu: too many SCSI bus\n");
- exit(1);
- }
-
- esp_init(hwdef->esp_base, 2,
- espdma_memory_read, espdma_memory_write,
- espdma, espdma_irq, &esp_reset, &dma_enable);
-
- qdev_connect_gpio_out(espdma, 0, esp_reset);
- qdev_connect_gpio_out(espdma, 1, dma_enable);
-
- if (hwdef->cs_base) {
- sysbus_create_simple("SUNW,CS4231", hwdef->cs_base,
- slavio_irq[5]);
- }
-
- if (hwdef->dbri_base) {
- /* ISDN chip with attached CS4215 audio codec */
- /* prom space */
- empty_slot_init(hwdef->dbri_base+0x1000, 0x30);
- /* reg space */
- empty_slot_init(hwdef->dbri_base+0x10000, 0x100);
- }
-
- if (hwdef->bpp_base) {
- /* parallel port */
- empty_slot_init(hwdef->bpp_base, 0x20);
- }
-
- kernel_size = sun4m_load_kernel(machine->kernel_filename,
- machine->initrd_filename,
- machine->ram_size);
-
- nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, machine->kernel_cmdline,
- machine->boot_order, machine->ram_size, kernel_size,
- graphic_width, graphic_height, graphic_depth,
- hwdef->nvram_machine_id, "Sun4m");
-
- if (hwdef->ecc_base)
- ecc_init(hwdef->ecc_base, slavio_irq[28],
- hwdef->ecc_version);
-
- fw_cfg = fw_cfg_init_mem(CFG_ADDR, CFG_ADDR + 2);
- fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
- 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);
- fw_cfg_add_i16(fw_cfg, FW_CFG_SUN4M_DEPTH, graphic_depth);
- fw_cfg_add_i16(fw_cfg, FW_CFG_SUN4M_WIDTH, graphic_width);
- fw_cfg_add_i16(fw_cfg, FW_CFG_SUN4M_HEIGHT, graphic_height);
- fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, KERNEL_LOAD_ADDR);
- fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
- if (machine->kernel_cmdline) {
- fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR);
- pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE,
- machine->kernel_cmdline);
- fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, machine->kernel_cmdline);
- fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE,
- strlen(machine->kernel_cmdline) + 1);
- } else {
- fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0);
- fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, 0);
- }
- fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, INITRD_LOAD_ADDR);
- fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, 0); // not used
- fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, machine->boot_order[0]);
- qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
-}
-
-enum {
- ss5_id = 32,
- vger_id,
- lx_id,
- ss4_id,
- scls_id,
- sbook_id,
- ss10_id = 64,
- ss20_id,
- ss600mp_id,
-};
-
-static const struct sun4m_hwdef sun4m_hwdefs[] = {
- /* SS-5 */
- {
- .iommu_base = 0x10000000,
- .iommu_pad_base = 0x10004000,
- .iommu_pad_len = 0x0fffb000,
- .tcx_base = 0x50000000,
- .cs_base = 0x6c000000,
- .slavio_base = 0x70000000,
- .ms_kb_base = 0x71000000,
- .serial_base = 0x71100000,
- .nvram_base = 0x71200000,
- .fd_base = 0x71400000,
- .counter_base = 0x71d00000,
- .intctl_base = 0x71e00000,
- .idreg_base = 0x78000000,
- .dma_base = 0x78400000,
- .esp_base = 0x78800000,
- .le_base = 0x78c00000,
- .apc_base = 0x6a000000,
- .afx_base = 0x6e000000,
- .aux1_base = 0x71900000,
- .aux2_base = 0x71910000,
- .nvram_machine_id = 0x80,
- .machine_id = ss5_id,
- .iommu_version = 0x05000000,
- .max_mem = 0x10000000,
- .default_cpu_model = "Fujitsu MB86904",
- },
- /* SS-10 */
- {
- .iommu_base = 0xfe0000000ULL,
- .tcx_base = 0xe20000000ULL,
- .slavio_base = 0xff0000000ULL,
- .ms_kb_base = 0xff1000000ULL,
- .serial_base = 0xff1100000ULL,
- .nvram_base = 0xff1200000ULL,
- .fd_base = 0xff1700000ULL,
- .counter_base = 0xff1300000ULL,
- .intctl_base = 0xff1400000ULL,
- .idreg_base = 0xef0000000ULL,
- .dma_base = 0xef0400000ULL,
- .esp_base = 0xef0800000ULL,
- .le_base = 0xef0c00000ULL,
- .apc_base = 0xefa000000ULL, // XXX should not exist
- .aux1_base = 0xff1800000ULL,
- .aux2_base = 0xff1a01000ULL,
- .ecc_base = 0xf00000000ULL,
- .ecc_version = 0x10000000, // version 0, implementation 1
- .nvram_machine_id = 0x72,
- .machine_id = ss10_id,
- .iommu_version = 0x03000000,
- .max_mem = 0xf00000000ULL,
- .default_cpu_model = "TI SuperSparc II",
- },
- /* SS-600MP */
- {
- .iommu_base = 0xfe0000000ULL,
- .tcx_base = 0xe20000000ULL,
- .slavio_base = 0xff0000000ULL,
- .ms_kb_base = 0xff1000000ULL,
- .serial_base = 0xff1100000ULL,
- .nvram_base = 0xff1200000ULL,
- .counter_base = 0xff1300000ULL,
- .intctl_base = 0xff1400000ULL,
- .dma_base = 0xef0081000ULL,
- .esp_base = 0xef0080000ULL,
- .le_base = 0xef0060000ULL,
- .apc_base = 0xefa000000ULL, // XXX should not exist
- .aux1_base = 0xff1800000ULL,
- .aux2_base = 0xff1a01000ULL, // XXX should not exist
- .ecc_base = 0xf00000000ULL,
- .ecc_version = 0x00000000, // version 0, implementation 0
- .nvram_machine_id = 0x71,
- .machine_id = ss600mp_id,
- .iommu_version = 0x01000000,
- .max_mem = 0xf00000000ULL,
- .default_cpu_model = "TI SuperSparc II",
- },
- /* SS-20 */
- {
- .iommu_base = 0xfe0000000ULL,
- .tcx_base = 0xe20000000ULL,
- .slavio_base = 0xff0000000ULL,
- .ms_kb_base = 0xff1000000ULL,
- .serial_base = 0xff1100000ULL,
- .nvram_base = 0xff1200000ULL,
- .fd_base = 0xff1700000ULL,
- .counter_base = 0xff1300000ULL,
- .intctl_base = 0xff1400000ULL,
- .idreg_base = 0xef0000000ULL,
- .dma_base = 0xef0400000ULL,
- .esp_base = 0xef0800000ULL,
- .le_base = 0xef0c00000ULL,
- .bpp_base = 0xef4800000ULL,
- .apc_base = 0xefa000000ULL, // XXX should not exist
- .aux1_base = 0xff1800000ULL,
- .aux2_base = 0xff1a01000ULL,
- .dbri_base = 0xee0000000ULL,
- .sx_base = 0xf80000000ULL,
- .vsimm = {
- {
- .reg_base = 0x9c000000ULL,
- .vram_base = 0xfc000000ULL
- }, {
- .reg_base = 0x90000000ULL,
- .vram_base = 0xf0000000ULL
- }, {
- .reg_base = 0x94000000ULL
- }, {
- .reg_base = 0x98000000ULL
- }
- },
- .ecc_base = 0xf00000000ULL,
- .ecc_version = 0x20000000, // version 0, implementation 2
- .nvram_machine_id = 0x72,
- .machine_id = ss20_id,
- .iommu_version = 0x13000000,
- .max_mem = 0xf00000000ULL,
- .default_cpu_model = "TI SuperSparc II",
- },
- /* Voyager */
- {
- .iommu_base = 0x10000000,
- .tcx_base = 0x50000000,
- .slavio_base = 0x70000000,
- .ms_kb_base = 0x71000000,
- .serial_base = 0x71100000,
- .nvram_base = 0x71200000,
- .fd_base = 0x71400000,
- .counter_base = 0x71d00000,
- .intctl_base = 0x71e00000,
- .idreg_base = 0x78000000,
- .dma_base = 0x78400000,
- .esp_base = 0x78800000,
- .le_base = 0x78c00000,
- .apc_base = 0x71300000, // pmc
- .aux1_base = 0x71900000,
- .aux2_base = 0x71910000,
- .nvram_machine_id = 0x80,
- .machine_id = vger_id,
- .iommu_version = 0x05000000,
- .max_mem = 0x10000000,
- .default_cpu_model = "Fujitsu MB86904",
- },
- /* LX */
- {
- .iommu_base = 0x10000000,
- .iommu_pad_base = 0x10004000,
- .iommu_pad_len = 0x0fffb000,
- .tcx_base = 0x50000000,
- .slavio_base = 0x70000000,
- .ms_kb_base = 0x71000000,
- .serial_base = 0x71100000,
- .nvram_base = 0x71200000,
- .fd_base = 0x71400000,
- .counter_base = 0x71d00000,
- .intctl_base = 0x71e00000,
- .idreg_base = 0x78000000,
- .dma_base = 0x78400000,
- .esp_base = 0x78800000,
- .le_base = 0x78c00000,
- .aux1_base = 0x71900000,
- .aux2_base = 0x71910000,
- .nvram_machine_id = 0x80,
- .machine_id = lx_id,
- .iommu_version = 0x04000000,
- .max_mem = 0x10000000,
- .default_cpu_model = "TI MicroSparc I",
- },
- /* SS-4 */
- {
- .iommu_base = 0x10000000,
- .tcx_base = 0x50000000,
- .cs_base = 0x6c000000,
- .slavio_base = 0x70000000,
- .ms_kb_base = 0x71000000,
- .serial_base = 0x71100000,
- .nvram_base = 0x71200000,
- .fd_base = 0x71400000,
- .counter_base = 0x71d00000,
- .intctl_base = 0x71e00000,
- .idreg_base = 0x78000000,
- .dma_base = 0x78400000,
- .esp_base = 0x78800000,
- .le_base = 0x78c00000,
- .apc_base = 0x6a000000,
- .aux1_base = 0x71900000,
- .aux2_base = 0x71910000,
- .nvram_machine_id = 0x80,
- .machine_id = ss4_id,
- .iommu_version = 0x05000000,
- .max_mem = 0x10000000,
- .default_cpu_model = "Fujitsu MB86904",
- },
- /* SPARCClassic */
- {
- .iommu_base = 0x10000000,
- .tcx_base = 0x50000000,
- .slavio_base = 0x70000000,
- .ms_kb_base = 0x71000000,
- .serial_base = 0x71100000,
- .nvram_base = 0x71200000,
- .fd_base = 0x71400000,
- .counter_base = 0x71d00000,
- .intctl_base = 0x71e00000,
- .idreg_base = 0x78000000,
- .dma_base = 0x78400000,
- .esp_base = 0x78800000,
- .le_base = 0x78c00000,
- .apc_base = 0x6a000000,
- .aux1_base = 0x71900000,
- .aux2_base = 0x71910000,
- .nvram_machine_id = 0x80,
- .machine_id = scls_id,
- .iommu_version = 0x05000000,
- .max_mem = 0x10000000,
- .default_cpu_model = "TI MicroSparc I",
- },
- /* SPARCbook */
- {
- .iommu_base = 0x10000000,
- .tcx_base = 0x50000000, // XXX
- .slavio_base = 0x70000000,
- .ms_kb_base = 0x71000000,
- .serial_base = 0x71100000,
- .nvram_base = 0x71200000,
- .fd_base = 0x71400000,
- .counter_base = 0x71d00000,
- .intctl_base = 0x71e00000,
- .idreg_base = 0x78000000,
- .dma_base = 0x78400000,
- .esp_base = 0x78800000,
- .le_base = 0x78c00000,
- .apc_base = 0x6a000000,
- .aux1_base = 0x71900000,
- .aux2_base = 0x71910000,
- .nvram_machine_id = 0x80,
- .machine_id = sbook_id,
- .iommu_version = 0x05000000,
- .max_mem = 0x10000000,
- .default_cpu_model = "TI MicroSparc I",
- },
-};
-
-/* SPARCstation 5 hardware initialisation */
-static void ss5_init(MachineState *machine)
-{
- sun4m_hw_init(&sun4m_hwdefs[0], machine);
-}
-
-/* SPARCstation 10 hardware initialisation */
-static void ss10_init(MachineState *machine)
-{
- sun4m_hw_init(&sun4m_hwdefs[1], machine);
-}
-
-/* SPARCserver 600MP hardware initialisation */
-static void ss600mp_init(MachineState *machine)
-{
- sun4m_hw_init(&sun4m_hwdefs[2], machine);
-}
-
-/* SPARCstation 20 hardware initialisation */
-static void ss20_init(MachineState *machine)
-{
- sun4m_hw_init(&sun4m_hwdefs[3], machine);
-}
-
-/* SPARCstation Voyager hardware initialisation */
-static void vger_init(MachineState *machine)
-{
- sun4m_hw_init(&sun4m_hwdefs[4], machine);
-}
-
-/* SPARCstation LX hardware initialisation */
-static void ss_lx_init(MachineState *machine)
-{
- sun4m_hw_init(&sun4m_hwdefs[5], machine);
-}
-
-/* SPARCstation 4 hardware initialisation */
-static void ss4_init(MachineState *machine)
-{
- sun4m_hw_init(&sun4m_hwdefs[6], machine);
-}
-
-/* SPARCClassic hardware initialisation */
-static void scls_init(MachineState *machine)
-{
- sun4m_hw_init(&sun4m_hwdefs[7], machine);
-}
-
-/* SPARCbook hardware initialisation */
-static void sbook_init(MachineState *machine)
-{
- sun4m_hw_init(&sun4m_hwdefs[8], machine);
-}
-
-static void ss5_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "Sun4m platform, SPARCstation 5";
- mc->init = ss5_init;
- mc->block_default_type = IF_SCSI;
- mc->is_default = 1;
- mc->default_boot_order = "c";
-}
-
-static const TypeInfo ss5_type = {
- .name = MACHINE_TYPE_NAME("SS-5"),
- .parent = TYPE_MACHINE,
- .class_init = ss5_class_init,
-};
-
-static void ss10_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "Sun4m platform, SPARCstation 10";
- mc->init = ss10_init;
- mc->block_default_type = IF_SCSI;
- mc->max_cpus = 4;
- mc->default_boot_order = "c";
-}
-
-static const TypeInfo ss10_type = {
- .name = MACHINE_TYPE_NAME("SS-10"),
- .parent = TYPE_MACHINE,
- .class_init = ss10_class_init,
-};
-
-static void ss600mp_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "Sun4m platform, SPARCserver 600MP";
- mc->init = ss600mp_init;
- mc->block_default_type = IF_SCSI;
- mc->max_cpus = 4;
- mc->default_boot_order = "c";
-}
-
-static const TypeInfo ss600mp_type = {
- .name = MACHINE_TYPE_NAME("SS-600MP"),
- .parent = TYPE_MACHINE,
- .class_init = ss600mp_class_init,
-};
-
-static void ss20_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "Sun4m platform, SPARCstation 20";
- mc->init = ss20_init;
- mc->block_default_type = IF_SCSI;
- mc->max_cpus = 4;
- mc->default_boot_order = "c";
-}
-
-static const TypeInfo ss20_type = {
- .name = MACHINE_TYPE_NAME("SS-20"),
- .parent = TYPE_MACHINE,
- .class_init = ss20_class_init,
-};
-
-static void voyager_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "Sun4m platform, SPARCstation Voyager";
- mc->init = vger_init;
- mc->block_default_type = IF_SCSI;
- mc->default_boot_order = "c";
-}
-
-static const TypeInfo voyager_type = {
- .name = MACHINE_TYPE_NAME("Voyager"),
- .parent = TYPE_MACHINE,
- .class_init = voyager_class_init,
-};
-
-static void ss_lx_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "Sun4m platform, SPARCstation LX";
- mc->init = ss_lx_init;
- mc->block_default_type = IF_SCSI;
- mc->default_boot_order = "c";
-}
-
-static const TypeInfo ss_lx_type = {
- .name = MACHINE_TYPE_NAME("LX"),
- .parent = TYPE_MACHINE,
- .class_init = ss_lx_class_init,
-};
-
-static void ss4_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "Sun4m platform, SPARCstation 4";
- mc->init = ss4_init;
- mc->block_default_type = IF_SCSI;
- mc->default_boot_order = "c";
-}
-
-static const TypeInfo ss4_type = {
- .name = MACHINE_TYPE_NAME("SS-4"),
- .parent = TYPE_MACHINE,
- .class_init = ss4_class_init,
-};
-
-static void scls_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "Sun4m platform, SPARCClassic";
- mc->init = scls_init;
- mc->block_default_type = IF_SCSI;
- mc->default_boot_order = "c";
-}
-
-static const TypeInfo scls_type = {
- .name = MACHINE_TYPE_NAME("SPARCClassic"),
- .parent = TYPE_MACHINE,
- .class_init = scls_class_init,
-};
-
-static void sbook_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "Sun4m platform, SPARCbook";
- mc->init = sbook_init;
- mc->block_default_type = IF_SCSI;
- mc->default_boot_order = "c";
-}
-
-static const TypeInfo sbook_type = {
- .name = MACHINE_TYPE_NAME("SPARCbook"),
- .parent = TYPE_MACHINE,
- .class_init = sbook_class_init,
-};
-
-static void sun4m_register_types(void)
-{
- type_register_static(&idreg_info);
- type_register_static(&afx_info);
- type_register_static(&prom_info);
- type_register_static(&ram_info);
-
- type_register_static(&ss5_type);
- type_register_static(&ss10_type);
- type_register_static(&ss600mp_type);
- type_register_static(&ss20_type);
- type_register_static(&voyager_type);
- type_register_static(&ss_lx_type);
- type_register_static(&ss4_type);
- type_register_static(&scls_type);
- type_register_static(&sbook_type);
-}
-
-type_init(sun4m_register_types)
diff --git a/qemu/hw/sparc64/Makefile.objs b/qemu/hw/sparc64/Makefile.objs
deleted file mode 100644
index a84cfe3ec..000000000
--- a/qemu/hw/sparc64/Makefile.objs
+++ /dev/null
@@ -1 +0,0 @@
-obj-y += sun4u.o
diff --git a/qemu/hw/sparc64/sun4u.c b/qemu/hw/sparc64/sun4u.c
deleted file mode 100644
index 3165e18eb..000000000
--- a/qemu/hw/sparc64/sun4u.c
+++ /dev/null
@@ -1,1010 +0,0 @@
-/*
- * QEMU Sun4u/Sun4v System Emulator
- *
- * Copyright (c) 2005 Fabrice Bellard
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/hw.h"
-#include "hw/pci/pci.h"
-#include "hw/pci-host/apb.h"
-#include "hw/i386/pc.h"
-#include "hw/char/serial.h"
-#include "hw/timer/m48t59.h"
-#include "hw/block/fdc.h"
-#include "net/net.h"
-#include "qemu/timer.h"
-#include "sysemu/sysemu.h"
-#include "hw/boards.h"
-#include "hw/nvram/openbios_firmware_abi.h"
-#include "hw/nvram/fw_cfg.h"
-#include "hw/sysbus.h"
-#include "hw/ide.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "sysemu/block-backend.h"
-#include "exec/address-spaces.h"
-#include "qemu/cutils.h"
-
-//#define DEBUG_IRQ
-//#define DEBUG_EBUS
-//#define DEBUG_TIMER
-
-#ifdef DEBUG_IRQ
-#define CPUIRQ_DPRINTF(fmt, ...) \
- do { printf("CPUIRQ: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define CPUIRQ_DPRINTF(fmt, ...)
-#endif
-
-#ifdef DEBUG_EBUS
-#define EBUS_DPRINTF(fmt, ...) \
- do { printf("EBUS: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define EBUS_DPRINTF(fmt, ...)
-#endif
-
-#ifdef DEBUG_TIMER
-#define TIMER_DPRINTF(fmt, ...) \
- do { printf("TIMER: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define TIMER_DPRINTF(fmt, ...)
-#endif
-
-#define KERNEL_LOAD_ADDR 0x00404000
-#define CMDLINE_ADDR 0x003ff000
-#define PROM_SIZE_MAX (4 * 1024 * 1024)
-#define PROM_VADDR 0x000ffd00000ULL
-#define APB_SPECIAL_BASE 0x1fe00000000ULL
-#define APB_MEM_BASE 0x1ff00000000ULL
-#define APB_PCI_IO_BASE (APB_SPECIAL_BASE + 0x02000000ULL)
-#define PROM_FILENAME "openbios-sparc64"
-#define NVRAM_SIZE 0x2000
-#define MAX_IDE_BUS 2
-#define BIOS_CFG_IOPORT 0x510
-#define FW_CFG_SPARC64_WIDTH (FW_CFG_ARCH_LOCAL + 0x00)
-#define FW_CFG_SPARC64_HEIGHT (FW_CFG_ARCH_LOCAL + 0x01)
-#define FW_CFG_SPARC64_DEPTH (FW_CFG_ARCH_LOCAL + 0x02)
-
-#define IVEC_MAX 0x40
-
-#define TICK_MAX 0x7fffffffffffffffULL
-
-struct hwdef {
- const char * const default_cpu_model;
- uint16_t machine_id;
- uint64_t prom_addr;
- uint64_t console_serial_base;
-};
-
-typedef struct EbusState {
- PCIDevice pci_dev;
- MemoryRegion bar0;
- MemoryRegion bar1;
-} EbusState;
-
-void DMA_init(ISABus *bus, int high_page_enable)
-{
-}
-
-static void fw_cfg_boot_set(void *opaque, const char *boot_device,
- Error **errp)
-{
- fw_cfg_modify_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
-}
-
-static int sun4u_NVRAM_set_params(Nvram *nvram, uint16_t NVRAM_size,
- const char *arch, ram_addr_t RAM_size,
- const char *boot_devices,
- uint32_t kernel_image, uint32_t kernel_size,
- const char *cmdline,
- uint32_t initrd_image, uint32_t initrd_size,
- uint32_t NVRAM_image,
- int width, int height, int depth,
- const uint8_t *macaddr)
-{
- unsigned int i;
- uint32_t start, end;
- uint8_t image[0x1ff0];
- struct OpenBIOS_nvpart_v1 *part_header;
- NvramClass *k = NVRAM_GET_CLASS(nvram);
-
- memset(image, '\0', sizeof(image));
-
- start = 0;
-
- // OpenBIOS nvram variables
- // Variable partition
- part_header = (struct OpenBIOS_nvpart_v1 *)&image[start];
- part_header->signature = OPENBIOS_PART_SYSTEM;
- pstrcpy(part_header->name, sizeof(part_header->name), "system");
-
- end = start + sizeof(struct OpenBIOS_nvpart_v1);
- for (i = 0; i < nb_prom_envs; i++)
- end = OpenBIOS_set_var(image, end, prom_envs[i]);
-
- // End marker
- image[end++] = '\0';
-
- end = start + ((end - start + 15) & ~15);
- OpenBIOS_finish_partition(part_header, end - start);
-
- // free partition
- start = end;
- part_header = (struct OpenBIOS_nvpart_v1 *)&image[start];
- part_header->signature = OPENBIOS_PART_FREE;
- pstrcpy(part_header->name, sizeof(part_header->name), "free");
-
- end = 0x1fd0;
- OpenBIOS_finish_partition(part_header, end - start);
-
- Sun_init_header((struct Sun_nvram *)&image[0x1fd8], macaddr, 0x80);
-
- for (i = 0; i < sizeof(image); i++) {
- (k->write)(nvram, i, image[i]);
- }
-
- return 0;
-}
-
-static uint64_t sun4u_load_kernel(const char *kernel_filename,
- const char *initrd_filename,
- ram_addr_t RAM_size, uint64_t *initrd_size,
- uint64_t *initrd_addr, uint64_t *kernel_addr,
- uint64_t *kernel_entry)
-{
- int linux_boot;
- unsigned int i;
- long kernel_size;
- uint8_t *ptr;
- uint64_t kernel_top;
-
- linux_boot = (kernel_filename != NULL);
-
- kernel_size = 0;
- if (linux_boot) {
- int bswap_needed;
-
-#ifdef BSWAP_NEEDED
- bswap_needed = 1;
-#else
- bswap_needed = 0;
-#endif
- kernel_size = load_elf(kernel_filename, NULL, NULL, kernel_entry,
- kernel_addr, &kernel_top, 1, EM_SPARCV9, 0, 0);
- if (kernel_size < 0) {
- *kernel_addr = KERNEL_LOAD_ADDR;
- *kernel_entry = KERNEL_LOAD_ADDR;
- kernel_size = load_aout(kernel_filename, KERNEL_LOAD_ADDR,
- RAM_size - KERNEL_LOAD_ADDR, bswap_needed,
- TARGET_PAGE_SIZE);
- }
- if (kernel_size < 0) {
- kernel_size = load_image_targphys(kernel_filename,
- KERNEL_LOAD_ADDR,
- RAM_size - KERNEL_LOAD_ADDR);
- }
- if (kernel_size < 0) {
- fprintf(stderr, "qemu: could not load kernel '%s'\n",
- kernel_filename);
- exit(1);
- }
- /* load initrd above kernel */
- *initrd_size = 0;
- if (initrd_filename) {
- *initrd_addr = TARGET_PAGE_ALIGN(kernel_top);
-
- *initrd_size = load_image_targphys(initrd_filename,
- *initrd_addr,
- RAM_size - *initrd_addr);
- if ((int)*initrd_size < 0) {
- fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
- initrd_filename);
- exit(1);
- }
- }
- if (*initrd_size > 0) {
- for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) {
- ptr = rom_ptr(*kernel_addr + i);
- if (ldl_p(ptr + 8) == 0x48647253) { /* HdrS */
- stl_p(ptr + 24, *initrd_addr + *kernel_addr);
- stl_p(ptr + 28, *initrd_size);
- break;
- }
- }
- }
- }
- return kernel_size;
-}
-
-void cpu_check_irqs(CPUSPARCState *env)
-{
- CPUState *cs;
- uint32_t pil = env->pil_in |
- (env->softint & ~(SOFTINT_TIMER | SOFTINT_STIMER));
-
- /* TT_IVEC has a higher priority (16) than TT_EXTINT (31..17) */
- if (env->ivec_status & 0x20) {
- return;
- }
- cs = CPU(sparc_env_get_cpu(env));
- /* check if TM or SM in SOFTINT are set
- setting these also causes interrupt 14 */
- if (env->softint & (SOFTINT_TIMER | SOFTINT_STIMER)) {
- pil |= 1 << 14;
- }
-
- /* The bit corresponding to psrpil is (1<< psrpil), the next bit
- is (2 << psrpil). */
- if (pil < (2 << env->psrpil)){
- if (cs->interrupt_request & CPU_INTERRUPT_HARD) {
- CPUIRQ_DPRINTF("Reset CPU IRQ (current interrupt %x)\n",
- env->interrupt_index);
- env->interrupt_index = 0;
- cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
- }
- return;
- }
-
- if (cpu_interrupts_enabled(env)) {
-
- unsigned int i;
-
- for (i = 15; i > env->psrpil; i--) {
- if (pil & (1 << i)) {
- int old_interrupt = env->interrupt_index;
- int new_interrupt = TT_EXTINT | i;
-
- if (unlikely(env->tl > 0 && cpu_tsptr(env)->tt > new_interrupt
- && ((cpu_tsptr(env)->tt & 0x1f0) == TT_EXTINT))) {
- CPUIRQ_DPRINTF("Not setting CPU IRQ: TL=%d "
- "current %x >= pending %x\n",
- env->tl, cpu_tsptr(env)->tt, new_interrupt);
- } else if (old_interrupt != new_interrupt) {
- env->interrupt_index = new_interrupt;
- CPUIRQ_DPRINTF("Set CPU IRQ %d old=%x new=%x\n", i,
- old_interrupt, new_interrupt);
- cpu_interrupt(cs, CPU_INTERRUPT_HARD);
- }
- break;
- }
- }
- } else if (cs->interrupt_request & CPU_INTERRUPT_HARD) {
- CPUIRQ_DPRINTF("Interrupts disabled, pil=%08x pil_in=%08x softint=%08x "
- "current interrupt %x\n",
- pil, env->pil_in, env->softint, env->interrupt_index);
- env->interrupt_index = 0;
- cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
- }
-}
-
-static void cpu_kick_irq(SPARCCPU *cpu)
-{
- CPUState *cs = CPU(cpu);
- CPUSPARCState *env = &cpu->env;
-
- cs->halted = 0;
- cpu_check_irqs(env);
- qemu_cpu_kick(cs);
-}
-
-static void cpu_set_ivec_irq(void *opaque, int irq, int level)
-{
- SPARCCPU *cpu = opaque;
- CPUSPARCState *env = &cpu->env;
- CPUState *cs;
-
- if (level) {
- if (!(env->ivec_status & 0x20)) {
- CPUIRQ_DPRINTF("Raise IVEC IRQ %d\n", irq);
- cs = CPU(cpu);
- cs->halted = 0;
- env->interrupt_index = TT_IVEC;
- env->ivec_status |= 0x20;
- env->ivec_data[0] = (0x1f << 6) | irq;
- env->ivec_data[1] = 0;
- env->ivec_data[2] = 0;
- cpu_interrupt(cs, CPU_INTERRUPT_HARD);
- }
- } else {
- if (env->ivec_status & 0x20) {
- CPUIRQ_DPRINTF("Lower IVEC IRQ %d\n", irq);
- cs = CPU(cpu);
- env->ivec_status &= ~0x20;
- cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
- }
- }
-}
-
-typedef struct ResetData {
- SPARCCPU *cpu;
- uint64_t prom_addr;
-} ResetData;
-
-static CPUTimer *cpu_timer_create(const char *name, SPARCCPU *cpu,
- QEMUBHFunc *cb, uint32_t frequency,
- uint64_t disabled_mask, uint64_t npt_mask)
-{
- CPUTimer *timer = g_malloc0(sizeof (CPUTimer));
-
- timer->name = name;
- timer->frequency = frequency;
- timer->disabled_mask = disabled_mask;
- timer->npt_mask = npt_mask;
-
- timer->disabled = 1;
- timer->npt = 1;
- timer->clock_offset = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-
- timer->qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cb, cpu);
-
- return timer;
-}
-
-static void cpu_timer_reset(CPUTimer *timer)
-{
- timer->disabled = 1;
- timer->clock_offset = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-
- timer_del(timer->qtimer);
-}
-
-static void main_cpu_reset(void *opaque)
-{
- ResetData *s = (ResetData *)opaque;
- CPUSPARCState *env = &s->cpu->env;
- static unsigned int nr_resets;
-
- cpu_reset(CPU(s->cpu));
-
- cpu_timer_reset(env->tick);
- cpu_timer_reset(env->stick);
- cpu_timer_reset(env->hstick);
-
- env->gregs[1] = 0; // Memory start
- env->gregs[2] = ram_size; // Memory size
- env->gregs[3] = 0; // Machine description XXX
- if (nr_resets++ == 0) {
- /* Power on reset */
- env->pc = s->prom_addr + 0x20ULL;
- } else {
- env->pc = s->prom_addr + 0x40ULL;
- }
- env->npc = env->pc + 4;
-}
-
-static void tick_irq(void *opaque)
-{
- SPARCCPU *cpu = opaque;
- CPUSPARCState *env = &cpu->env;
-
- CPUTimer* timer = env->tick;
-
- if (timer->disabled) {
- CPUIRQ_DPRINTF("tick_irq: softint disabled\n");
- return;
- } else {
- CPUIRQ_DPRINTF("tick: fire\n");
- }
-
- env->softint |= SOFTINT_TIMER;
- cpu_kick_irq(cpu);
-}
-
-static void stick_irq(void *opaque)
-{
- SPARCCPU *cpu = opaque;
- CPUSPARCState *env = &cpu->env;
-
- CPUTimer* timer = env->stick;
-
- if (timer->disabled) {
- CPUIRQ_DPRINTF("stick_irq: softint disabled\n");
- return;
- } else {
- CPUIRQ_DPRINTF("stick: fire\n");
- }
-
- env->softint |= SOFTINT_STIMER;
- cpu_kick_irq(cpu);
-}
-
-static void hstick_irq(void *opaque)
-{
- SPARCCPU *cpu = opaque;
- CPUSPARCState *env = &cpu->env;
-
- CPUTimer* timer = env->hstick;
-
- if (timer->disabled) {
- CPUIRQ_DPRINTF("hstick_irq: softint disabled\n");
- return;
- } else {
- CPUIRQ_DPRINTF("hstick: fire\n");
- }
-
- env->softint |= SOFTINT_STIMER;
- cpu_kick_irq(cpu);
-}
-
-static int64_t cpu_to_timer_ticks(int64_t cpu_ticks, uint32_t frequency)
-{
- return muldiv64(cpu_ticks, NANOSECONDS_PER_SECOND, frequency);
-}
-
-static uint64_t timer_to_cpu_ticks(int64_t timer_ticks, uint32_t frequency)
-{
- return muldiv64(timer_ticks, frequency, NANOSECONDS_PER_SECOND);
-}
-
-void cpu_tick_set_count(CPUTimer *timer, uint64_t count)
-{
- uint64_t real_count = count & ~timer->npt_mask;
- uint64_t npt_bit = count & timer->npt_mask;
-
- int64_t vm_clock_offset = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) -
- cpu_to_timer_ticks(real_count, timer->frequency);
-
- TIMER_DPRINTF("%s set_count count=0x%016lx (npt %s) p=%p\n",
- timer->name, real_count,
- timer->npt ? "disabled" : "enabled", timer);
-
- timer->npt = npt_bit ? 1 : 0;
- timer->clock_offset = vm_clock_offset;
-}
-
-uint64_t cpu_tick_get_count(CPUTimer *timer)
-{
- uint64_t real_count = timer_to_cpu_ticks(
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - timer->clock_offset,
- timer->frequency);
-
- TIMER_DPRINTF("%s get_count count=0x%016lx (npt %s) p=%p\n",
- timer->name, real_count,
- timer->npt ? "disabled" : "enabled", timer);
-
- if (timer->npt) {
- real_count |= timer->npt_mask;
- }
-
- return real_count;
-}
-
-void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit)
-{
- int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-
- uint64_t real_limit = limit & ~timer->disabled_mask;
- timer->disabled = (limit & timer->disabled_mask) ? 1 : 0;
-
- int64_t expires = cpu_to_timer_ticks(real_limit, timer->frequency) +
- timer->clock_offset;
-
- if (expires < now) {
- expires = now + 1;
- }
-
- TIMER_DPRINTF("%s set_limit limit=0x%016lx (%s) p=%p "
- "called with limit=0x%016lx at 0x%016lx (delta=0x%016lx)\n",
- timer->name, real_limit,
- timer->disabled?"disabled":"enabled",
- timer, limit,
- timer_to_cpu_ticks(now - timer->clock_offset,
- timer->frequency),
- timer_to_cpu_ticks(expires - now, timer->frequency));
-
- if (!real_limit) {
- TIMER_DPRINTF("%s set_limit limit=ZERO - not starting timer\n",
- timer->name);
- timer_del(timer->qtimer);
- } else if (timer->disabled) {
- timer_del(timer->qtimer);
- } else {
- timer_mod(timer->qtimer, expires);
- }
-}
-
-static void isa_irq_handler(void *opaque, int n, int level)
-{
- static const int isa_irq_to_ivec[16] = {
- [1] = 0x29, /* keyboard */
- [4] = 0x2b, /* serial */
- [6] = 0x27, /* floppy */
- [7] = 0x22, /* parallel */
- [12] = 0x2a, /* mouse */
- };
- qemu_irq *irqs = opaque;
- int ivec;
-
- assert(n < 16);
- ivec = isa_irq_to_ivec[n];
- EBUS_DPRINTF("Set ISA IRQ %d level %d -> ivec 0x%x\n", n, level, ivec);
- if (ivec) {
- qemu_set_irq(irqs[ivec], level);
- }
-}
-
-/* EBUS (Eight bit bus) bridge */
-static ISABus *
-pci_ebus_init(PCIBus *bus, int devfn, qemu_irq *irqs)
-{
- qemu_irq *isa_irq;
- PCIDevice *pci_dev;
- ISABus *isa_bus;
-
- pci_dev = pci_create_simple(bus, devfn, "ebus");
- isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(pci_dev), "isa.0"));
- isa_irq = qemu_allocate_irqs(isa_irq_handler, irqs, 16);
- isa_bus_irqs(isa_bus, isa_irq);
- return isa_bus;
-}
-
-static void pci_ebus_realize(PCIDevice *pci_dev, Error **errp)
-{
- EbusState *s = DO_UPCAST(EbusState, pci_dev, pci_dev);
-
- if (!isa_bus_new(DEVICE(pci_dev), get_system_memory(),
- pci_address_space_io(pci_dev), errp)) {
- return;
- }
-
- pci_dev->config[0x04] = 0x06; // command = bus master, pci mem
- pci_dev->config[0x05] = 0x00;
- pci_dev->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
- pci_dev->config[0x07] = 0x03; // status = medium devsel
- pci_dev->config[0x09] = 0x00; // programming i/f
- pci_dev->config[0x0D] = 0x0a; // latency_timer
-
- memory_region_init_alias(&s->bar0, OBJECT(s), "bar0", get_system_io(),
- 0, 0x1000000);
- pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar0);
- memory_region_init_alias(&s->bar1, OBJECT(s), "bar1", get_system_io(),
- 0, 0x4000);
- pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->bar1);
-}
-
-static void ebus_class_init(ObjectClass *klass, void *data)
-{
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = pci_ebus_realize;
- k->vendor_id = PCI_VENDOR_ID_SUN;
- k->device_id = PCI_DEVICE_ID_SUN_EBUS;
- k->revision = 0x01;
- k->class_id = PCI_CLASS_BRIDGE_OTHER;
-}
-
-static const TypeInfo ebus_info = {
- .name = "ebus",
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(EbusState),
- .class_init = ebus_class_init,
-};
-
-#define TYPE_OPENPROM "openprom"
-#define OPENPROM(obj) OBJECT_CHECK(PROMState, (obj), TYPE_OPENPROM)
-
-typedef struct PROMState {
- SysBusDevice parent_obj;
-
- MemoryRegion prom;
-} PROMState;
-
-static uint64_t translate_prom_address(void *opaque, uint64_t addr)
-{
- hwaddr *base_addr = (hwaddr *)opaque;
- return addr + *base_addr - PROM_VADDR;
-}
-
-/* Boot PROM (OpenBIOS) */
-static void prom_init(hwaddr addr, const char *bios_name)
-{
- DeviceState *dev;
- SysBusDevice *s;
- char *filename;
- int ret;
-
- dev = qdev_create(NULL, TYPE_OPENPROM);
- qdev_init_nofail(dev);
- s = SYS_BUS_DEVICE(dev);
-
- sysbus_mmio_map(s, 0, addr);
-
- /* load boot prom */
- if (bios_name == NULL) {
- bios_name = PROM_FILENAME;
- }
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
- if (filename) {
- ret = load_elf(filename, translate_prom_address, &addr,
- NULL, NULL, NULL, 1, EM_SPARCV9, 0, 0);
- if (ret < 0 || ret > PROM_SIZE_MAX) {
- ret = load_image_targphys(filename, addr, PROM_SIZE_MAX);
- }
- g_free(filename);
- } else {
- ret = -1;
- }
- if (ret < 0 || ret > PROM_SIZE_MAX) {
- fprintf(stderr, "qemu: could not load prom '%s'\n", bios_name);
- exit(1);
- }
-}
-
-static int prom_init1(SysBusDevice *dev)
-{
- PROMState *s = OPENPROM(dev);
-
- memory_region_init_ram(&s->prom, OBJECT(s), "sun4u.prom", PROM_SIZE_MAX,
- &error_fatal);
- vmstate_register_ram_global(&s->prom);
- memory_region_set_readonly(&s->prom, true);
- sysbus_init_mmio(dev, &s->prom);
- return 0;
-}
-
-static Property prom_properties[] = {
- {/* end of property list */},
-};
-
-static void prom_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = prom_init1;
- dc->props = prom_properties;
-}
-
-static const TypeInfo prom_info = {
- .name = TYPE_OPENPROM,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PROMState),
- .class_init = prom_class_init,
-};
-
-
-#define TYPE_SUN4U_MEMORY "memory"
-#define SUN4U_RAM(obj) OBJECT_CHECK(RamDevice, (obj), TYPE_SUN4U_MEMORY)
-
-typedef struct RamDevice {
- SysBusDevice parent_obj;
-
- MemoryRegion ram;
- uint64_t size;
-} RamDevice;
-
-/* System RAM */
-static int ram_init1(SysBusDevice *dev)
-{
- RamDevice *d = SUN4U_RAM(dev);
-
- memory_region_init_ram(&d->ram, OBJECT(d), "sun4u.ram", d->size,
- &error_fatal);
- vmstate_register_ram_global(&d->ram);
- sysbus_init_mmio(dev, &d->ram);
- return 0;
-}
-
-static void ram_init(hwaddr addr, ram_addr_t RAM_size)
-{
- DeviceState *dev;
- SysBusDevice *s;
- RamDevice *d;
-
- /* allocate RAM */
- dev = qdev_create(NULL, TYPE_SUN4U_MEMORY);
- s = SYS_BUS_DEVICE(dev);
-
- d = SUN4U_RAM(dev);
- d->size = RAM_size;
- qdev_init_nofail(dev);
-
- sysbus_mmio_map(s, 0, addr);
-}
-
-static Property ram_properties[] = {
- DEFINE_PROP_UINT64("size", RamDevice, size, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void ram_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = ram_init1;
- dc->props = ram_properties;
-}
-
-static const TypeInfo ram_info = {
- .name = TYPE_SUN4U_MEMORY,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(RamDevice),
- .class_init = ram_class_init,
-};
-
-static SPARCCPU *cpu_devinit(const char *cpu_model, const struct hwdef *hwdef)
-{
- SPARCCPU *cpu;
- CPUSPARCState *env;
- ResetData *reset_info;
-
- uint32_t tick_frequency = 100*1000000;
- uint32_t stick_frequency = 100*1000000;
- uint32_t hstick_frequency = 100*1000000;
-
- if (cpu_model == NULL) {
- cpu_model = hwdef->default_cpu_model;
- }
- cpu = cpu_sparc_init(cpu_model);
- if (cpu == NULL) {
- fprintf(stderr, "Unable to find Sparc CPU definition\n");
- exit(1);
- }
- env = &cpu->env;
-
- env->tick = cpu_timer_create("tick", cpu, tick_irq,
- tick_frequency, TICK_INT_DIS,
- TICK_NPT_MASK);
-
- env->stick = cpu_timer_create("stick", cpu, stick_irq,
- stick_frequency, TICK_INT_DIS,
- TICK_NPT_MASK);
-
- env->hstick = cpu_timer_create("hstick", cpu, hstick_irq,
- hstick_frequency, TICK_INT_DIS,
- TICK_NPT_MASK);
-
- reset_info = g_malloc0(sizeof(ResetData));
- reset_info->cpu = cpu;
- reset_info->prom_addr = hwdef->prom_addr;
- qemu_register_reset(main_cpu_reset, reset_info);
-
- return cpu;
-}
-
-static void sun4uv_init(MemoryRegion *address_space_mem,
- MachineState *machine,
- const struct hwdef *hwdef)
-{
- SPARCCPU *cpu;
- Nvram *nvram;
- unsigned int i;
- uint64_t initrd_addr, initrd_size, kernel_addr, kernel_size, kernel_entry;
- PCIBus *pci_bus, *pci_bus2, *pci_bus3;
- ISABus *isa_bus;
- SysBusDevice *s;
- qemu_irq *ivec_irqs, *pbm_irqs;
- DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
- DriveInfo *fd[MAX_FD];
- DeviceState *dev;
- FWCfgState *fw_cfg;
-
- /* init CPUs */
- cpu = cpu_devinit(machine->cpu_model, hwdef);
-
- /* set up devices */
- ram_init(0, machine->ram_size);
-
- prom_init(hwdef->prom_addr, bios_name);
-
- ivec_irqs = qemu_allocate_irqs(cpu_set_ivec_irq, cpu, IVEC_MAX);
- pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, ivec_irqs, &pci_bus2,
- &pci_bus3, &pbm_irqs);
- pci_vga_init(pci_bus);
-
- // XXX Should be pci_bus3
- isa_bus = pci_ebus_init(pci_bus, -1, pbm_irqs);
-
- i = 0;
- if (hwdef->console_serial_base) {
- serial_mm_init(address_space_mem, hwdef->console_serial_base, 0,
- NULL, 115200, serial_hds[i], DEVICE_BIG_ENDIAN);
- i++;
- }
-
- serial_hds_isa_init(isa_bus, MAX_SERIAL_PORTS);
- parallel_hds_isa_init(isa_bus, MAX_PARALLEL_PORTS);
-
- for(i = 0; i < nb_nics; i++)
- pci_nic_init_nofail(&nd_table[i], pci_bus, "ne2k_pci", NULL);
-
- ide_drive_get(hd, ARRAY_SIZE(hd));
-
- pci_cmd646_ide_init(pci_bus, hd, 1);
-
- isa_create_simple(isa_bus, "i8042");
-
- /* Floppy */
- for(i = 0; i < MAX_FD; i++) {
- fd[i] = drive_get(IF_FLOPPY, 0, i);
- }
- dev = DEVICE(isa_create(isa_bus, TYPE_ISA_FDC));
- if (fd[0]) {
- qdev_prop_set_drive(dev, "driveA", blk_by_legacy_dinfo(fd[0]),
- &error_abort);
- }
- if (fd[1]) {
- qdev_prop_set_drive(dev, "driveB", blk_by_legacy_dinfo(fd[1]),
- &error_abort);
- }
- qdev_prop_set_uint32(dev, "dma", -1);
- qdev_init_nofail(dev);
-
- /* Map NVRAM into I/O (ebus) space */
- nvram = m48t59_init(NULL, 0, 0, NVRAM_SIZE, 1968, 59);
- s = SYS_BUS_DEVICE(nvram);
- memory_region_add_subregion(get_system_io(), 0x2000,
- sysbus_mmio_get_region(s, 0));
-
- initrd_size = 0;
- initrd_addr = 0;
- kernel_size = sun4u_load_kernel(machine->kernel_filename,
- machine->initrd_filename,
- ram_size, &initrd_size, &initrd_addr,
- &kernel_addr, &kernel_entry);
-
- sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", machine->ram_size,
- machine->boot_order,
- kernel_addr, kernel_size,
- machine->kernel_cmdline,
- initrd_addr, initrd_size,
- /* XXX: need an option to load a NVRAM image */
- 0,
- graphic_width, graphic_height, graphic_depth,
- (uint8_t *)&nd_table[0].macaddr);
-
- fw_cfg = fw_cfg_init_io(BIOS_CFG_IOPORT);
- fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
- 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);
- fw_cfg_add_i64(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_entry);
- fw_cfg_add_i64(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
- if (machine->kernel_cmdline) {
- fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE,
- strlen(machine->kernel_cmdline) + 1);
- fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, machine->kernel_cmdline);
- } else {
- fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, 0);
- }
- fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_ADDR, initrd_addr);
- fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size);
- fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, machine->boot_order[0]);
-
- fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_WIDTH, graphic_width);
- fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_HEIGHT, graphic_height);
- fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_DEPTH, graphic_depth);
-
- qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
-}
-
-enum {
- sun4u_id = 0,
- sun4v_id = 64,
- niagara_id,
-};
-
-static const struct hwdef hwdefs[] = {
- /* Sun4u generic PC-like machine */
- {
- .default_cpu_model = "TI UltraSparc IIi",
- .machine_id = sun4u_id,
- .prom_addr = 0x1fff0000000ULL,
- .console_serial_base = 0,
- },
- /* Sun4v generic PC-like machine */
- {
- .default_cpu_model = "Sun UltraSparc T1",
- .machine_id = sun4v_id,
- .prom_addr = 0x1fff0000000ULL,
- .console_serial_base = 0,
- },
- /* Sun4v generic Niagara machine */
- {
- .default_cpu_model = "Sun UltraSparc T1",
- .machine_id = niagara_id,
- .prom_addr = 0xfff0000000ULL,
- .console_serial_base = 0xfff0c2c000ULL,
- },
-};
-
-/* Sun4u hardware initialisation */
-static void sun4u_init(MachineState *machine)
-{
- sun4uv_init(get_system_memory(), machine, &hwdefs[0]);
-}
-
-/* Sun4v hardware initialisation */
-static void sun4v_init(MachineState *machine)
-{
- sun4uv_init(get_system_memory(), machine, &hwdefs[1]);
-}
-
-/* Niagara hardware initialisation */
-static void niagara_init(MachineState *machine)
-{
- sun4uv_init(get_system_memory(), machine, &hwdefs[2]);
-}
-
-static void sun4u_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "Sun4u platform";
- mc->init = sun4u_init;
- mc->max_cpus = 1; /* XXX for now */
- mc->is_default = 1;
- mc->default_boot_order = "c";
-}
-
-static const TypeInfo sun4u_type = {
- .name = MACHINE_TYPE_NAME("sun4u"),
- .parent = TYPE_MACHINE,
- .class_init = sun4u_class_init,
-};
-
-static void sun4v_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "Sun4v platform";
- mc->init = sun4v_init;
- mc->max_cpus = 1; /* XXX for now */
- mc->default_boot_order = "c";
-}
-
-static const TypeInfo sun4v_type = {
- .name = MACHINE_TYPE_NAME("sun4v"),
- .parent = TYPE_MACHINE,
- .class_init = sun4v_class_init,
-};
-
-static void niagara_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "Sun4v platform, Niagara";
- mc->init = niagara_init;
- mc->max_cpus = 1; /* XXX for now */
- mc->default_boot_order = "c";
-}
-
-static const TypeInfo niagara_type = {
- .name = MACHINE_TYPE_NAME("Niagara"),
- .parent = TYPE_MACHINE,
- .class_init = niagara_class_init,
-};
-
-static void sun4u_register_types(void)
-{
- type_register_static(&ebus_info);
- type_register_static(&prom_info);
- type_register_static(&ram_info);
-
- type_register_static(&sun4u_type);
- type_register_static(&sun4v_type);
- type_register_static(&niagara_type);
-}
-
-type_init(sun4u_register_types)
diff --git a/qemu/hw/ssi/Makefile.objs b/qemu/hw/ssi/Makefile.objs
deleted file mode 100644
index 9555825ac..000000000
--- a/qemu/hw/ssi/Makefile.objs
+++ /dev/null
@@ -1,6 +0,0 @@
-common-obj-$(CONFIG_PL022) += pl022.o
-common-obj-$(CONFIG_SSI) += ssi.o
-common-obj-$(CONFIG_XILINX_SPI) += xilinx_spi.o
-common-obj-$(CONFIG_XILINX_SPIPS) += xilinx_spips.o
-
-obj-$(CONFIG_OMAP) += omap_spi.o
diff --git a/qemu/hw/ssi/omap_spi.c b/qemu/hw/ssi/omap_spi.c
deleted file mode 100644
index 22034656b..000000000
--- a/qemu/hw/ssi/omap_spi.c
+++ /dev/null
@@ -1,374 +0,0 @@
-/*
- * TI OMAP processor's Multichannel SPI emulation.
- *
- * Copyright (C) 2007-2009 Nokia Corporation
- *
- * Original code for OMAP2 by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) any later version of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/arm/omap.h"
-
-/* Multichannel SPI */
-struct omap_mcspi_s {
- MemoryRegion iomem;
- qemu_irq irq;
- int chnum;
-
- uint32_t sysconfig;
- uint32_t systest;
- uint32_t irqst;
- uint32_t irqen;
- uint32_t wken;
- uint32_t control;
-
- struct omap_mcspi_ch_s {
- qemu_irq txdrq;
- qemu_irq rxdrq;
- uint32_t (*txrx)(void *opaque, uint32_t, int);
- void *opaque;
-
- uint32_t tx;
- uint32_t rx;
-
- uint32_t config;
- uint32_t status;
- uint32_t control;
- } ch[4];
-};
-
-static inline void omap_mcspi_interrupt_update(struct omap_mcspi_s *s)
-{
- qemu_set_irq(s->irq, s->irqst & s->irqen);
-}
-
-static inline void omap_mcspi_dmarequest_update(struct omap_mcspi_ch_s *ch)
-{
- qemu_set_irq(ch->txdrq,
- (ch->control & 1) && /* EN */
- (ch->config & (1 << 14)) && /* DMAW */
- (ch->status & (1 << 1)) && /* TXS */
- ((ch->config >> 12) & 3) != 1); /* TRM */
- qemu_set_irq(ch->rxdrq,
- (ch->control & 1) && /* EN */
- (ch->config & (1 << 15)) && /* DMAW */
- (ch->status & (1 << 0)) && /* RXS */
- ((ch->config >> 12) & 3) != 2); /* TRM */
-}
-
-static void omap_mcspi_transfer_run(struct omap_mcspi_s *s, int chnum)
-{
- struct omap_mcspi_ch_s *ch = s->ch + chnum;
-
- if (!(ch->control & 1)) /* EN */
- return;
- if ((ch->status & (1 << 0)) && /* RXS */
- ((ch->config >> 12) & 3) != 2 && /* TRM */
- !(ch->config & (1 << 19))) /* TURBO */
- goto intr_update;
- if ((ch->status & (1 << 1)) && /* TXS */
- ((ch->config >> 12) & 3) != 1) /* TRM */
- goto intr_update;
-
- if (!(s->control & 1) || /* SINGLE */
- (ch->config & (1 << 20))) { /* FORCE */
- if (ch->txrx)
- ch->rx = ch->txrx(ch->opaque, ch->tx, /* WL */
- 1 + (0x1f & (ch->config >> 7)));
- }
-
- ch->tx = 0;
- ch->status |= 1 << 2; /* EOT */
- ch->status |= 1 << 1; /* TXS */
- if (((ch->config >> 12) & 3) != 2) /* TRM */
- ch->status |= 1 << 0; /* RXS */
-
-intr_update:
- if ((ch->status & (1 << 0)) && /* RXS */
- ((ch->config >> 12) & 3) != 2 && /* TRM */
- !(ch->config & (1 << 19))) /* TURBO */
- s->irqst |= 1 << (2 + 4 * chnum); /* RX_FULL */
- if ((ch->status & (1 << 1)) && /* TXS */
- ((ch->config >> 12) & 3) != 1) /* TRM */
- s->irqst |= 1 << (0 + 4 * chnum); /* TX_EMPTY */
- omap_mcspi_interrupt_update(s);
- omap_mcspi_dmarequest_update(ch);
-}
-
-void omap_mcspi_reset(struct omap_mcspi_s *s)
-{
- int ch;
-
- s->sysconfig = 0;
- s->systest = 0;
- s->irqst = 0;
- s->irqen = 0;
- s->wken = 0;
- s->control = 4;
-
- for (ch = 0; ch < 4; ch ++) {
- s->ch[ch].config = 0x060000;
- s->ch[ch].status = 2; /* TXS */
- s->ch[ch].control = 0;
-
- omap_mcspi_dmarequest_update(s->ch + ch);
- }
-
- omap_mcspi_interrupt_update(s);
-}
-
-static uint64_t omap_mcspi_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_mcspi_s *s = (struct omap_mcspi_s *) opaque;
- int ch = 0;
- uint32_t ret;
-
- if (size != 4) {
- return omap_badwidth_read32(opaque, addr);
- }
-
- switch (addr) {
- case 0x00: /* MCSPI_REVISION */
- return 0x91;
-
- case 0x10: /* MCSPI_SYSCONFIG */
- return s->sysconfig;
-
- case 0x14: /* MCSPI_SYSSTATUS */
- return 1; /* RESETDONE */
-
- case 0x18: /* MCSPI_IRQSTATUS */
- return s->irqst;
-
- case 0x1c: /* MCSPI_IRQENABLE */
- return s->irqen;
-
- case 0x20: /* MCSPI_WAKEUPENABLE */
- return s->wken;
-
- case 0x24: /* MCSPI_SYST */
- return s->systest;
-
- case 0x28: /* MCSPI_MODULCTRL */
- 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;
- omap_mcspi_transfer_run(s, ch);
- return ret;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_mcspi_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_mcspi_s *s = (struct omap_mcspi_s *) opaque;
- int ch = 0;
-
- if (size != 4) {
- omap_badwidth_write32(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x00: /* MCSPI_REVISION */
- case 0x14: /* MCSPI_SYSSTATUS */
- case 0x30: /* MCSPI_CHSTAT0 */
- case 0x3c: /* MCSPI_RX0 */
- case 0x44: /* MCSPI_CHSTAT1 */
- case 0x50: /* MCSPI_RX1 */
- case 0x58: /* MCSPI_CHSTAT2 */
- case 0x64: /* MCSPI_RX2 */
- case 0x6c: /* MCSPI_CHSTAT3 */
- case 0x78: /* MCSPI_RX3 */
- OMAP_RO_REG(addr);
- return;
-
- case 0x10: /* MCSPI_SYSCONFIG */
- if (value & (1 << 1)) /* SOFTRESET */
- omap_mcspi_reset(s);
- s->sysconfig = value & 0x31d;
- break;
-
- case 0x18: /* MCSPI_IRQSTATUS */
- if (!((s->control & (1 << 3)) && (s->systest & (1 << 11)))) {
- s->irqst &= ~value;
- omap_mcspi_interrupt_update(s);
- }
- break;
-
- case 0x1c: /* MCSPI_IRQENABLE */
- s->irqen = value & 0x1777f;
- omap_mcspi_interrupt_update(s);
- break;
-
- case 0x20: /* MCSPI_WAKEUPENABLE */
- s->wken = value & 1;
- break;
-
- case 0x24: /* MCSPI_SYST */
- if (s->control & (1 << 3)) /* SYSTEM_TEST */
- if (value & (1 << 11)) { /* SSB */
- s->irqst |= 0x1777f;
- omap_mcspi_interrupt_update(s);
- }
- s->systest = value & 0xfff;
- break;
-
- case 0x28: /* MCSPI_MODULCTRL */
- if (value & (1 << 3)) /* SYSTEM_TEST */
- if (s->systest & (1 << 11)) { /* SSB */
- s->irqst |= 0x1777f;
- omap_mcspi_interrupt_update(s);
- }
- s->control = value & 0xf;
- 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);
- if (((value >> 12) & 3) == 3) /* TRM */
- fprintf(stderr, "%s: invalid TRM value (3)\n", __FUNCTION__);
- if (((value >> 7) & 0x1f) < 3) /* WL */
- fprintf(stderr, "%s: invalid WL value (%" PRIx64 ")\n",
- __FUNCTION__, (value >> 7) & 0x1f);
- s->ch[ch].config = value & 0x7fffff;
- 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;
- omap_mcspi_transfer_run(s, ch);
- } else
- s->ch[ch].control = value & 1;
- 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 */
- omap_mcspi_transfer_run(s, ch);
- break;
-
- default:
- OMAP_BAD_REG(addr);
- return;
- }
-}
-
-static const MemoryRegionOps omap_mcspi_ops = {
- .read = omap_mcspi_read,
- .write = omap_mcspi_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct omap_mcspi_s *omap_mcspi_init(struct omap_target_agent_s *ta, int chnum,
- qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk)
-{
- struct omap_mcspi_s *s = g_new0(struct omap_mcspi_s, 1);
- struct omap_mcspi_ch_s *ch = s->ch;
-
- s->irq = irq;
- s->chnum = chnum;
- while (chnum --) {
- ch->txdrq = *drq ++;
- ch->rxdrq = *drq ++;
- ch ++;
- }
- omap_mcspi_reset(s);
-
- memory_region_init_io(&s->iomem, NULL, &omap_mcspi_ops, s, "omap.mcspi",
- omap_l4_region_size(ta, 0));
- omap_l4_attach(ta, 0, &s->iomem);
-
- return s;
-}
-
-void omap_mcspi_attach(struct omap_mcspi_s *s,
- uint32_t (*txrx)(void *opaque, uint32_t, int), void *opaque,
- int chipselect)
-{
- if (chipselect < 0 || chipselect >= s->chnum)
- hw_error("%s: Bad chipselect %i\n", __FUNCTION__, chipselect);
-
- s->ch[chipselect].txrx = txrx;
- s->ch[chipselect].opaque = opaque;
-}
diff --git a/qemu/hw/ssi/pl022.c b/qemu/hw/ssi/pl022.c
deleted file mode 100644
index 564a0d36e..000000000
--- a/qemu/hw/ssi/pl022.c
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
- * Arm PrimeCell PL022 Synchronous Serial Port
- *
- * Copyright (c) 2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "hw/ssi/ssi.h"
-
-//#define DEBUG_PL022 1
-
-#ifdef DEBUG_PL022
-#define DPRINTF(fmt, ...) \
-do { printf("pl022: " fmt , ## __VA_ARGS__); } while (0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "pl022: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "pl022: error: " fmt , ## __VA_ARGS__);} while (0)
-#endif
-
-#define PL022_CR1_LBM 0x01
-#define PL022_CR1_SSE 0x02
-#define PL022_CR1_MS 0x04
-#define PL022_CR1_SDO 0x08
-
-#define PL022_SR_TFE 0x01
-#define PL022_SR_TNF 0x02
-#define PL022_SR_RNE 0x04
-#define PL022_SR_RFF 0x08
-#define PL022_SR_BSY 0x10
-
-#define PL022_INT_ROR 0x01
-#define PL022_INT_RT 0x04
-#define PL022_INT_RX 0x04
-#define PL022_INT_TX 0x08
-
-#define TYPE_PL022 "pl022"
-#define PL022(obj) OBJECT_CHECK(PL022State, (obj), TYPE_PL022)
-
-typedef struct PL022State {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- uint32_t cr0;
- uint32_t cr1;
- uint32_t bitmask;
- uint32_t sr;
- uint32_t cpsr;
- uint32_t is;
- uint32_t im;
- /* The FIFO head points to the next empty entry. */
- int tx_fifo_head;
- int rx_fifo_head;
- int tx_fifo_len;
- int rx_fifo_len;
- uint16_t tx_fifo[8];
- uint16_t rx_fifo[8];
- qemu_irq irq;
- SSIBus *ssi;
-} PL022State;
-
-static const unsigned char pl022_id[8] =
- { 0x22, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
-
-static void pl022_update(PL022State *s)
-{
- s->sr = 0;
- if (s->tx_fifo_len == 0)
- s->sr |= PL022_SR_TFE;
- if (s->tx_fifo_len != 8)
- s->sr |= PL022_SR_TNF;
- if (s->rx_fifo_len != 0)
- s->sr |= PL022_SR_RNE;
- if (s->rx_fifo_len == 8)
- s->sr |= PL022_SR_RFF;
- if (s->tx_fifo_len)
- s->sr |= PL022_SR_BSY;
- s->is = 0;
- if (s->rx_fifo_len >= 4)
- s->is |= PL022_INT_RX;
- if (s->tx_fifo_len <= 4)
- s->is |= PL022_INT_TX;
-
- qemu_set_irq(s->irq, (s->is & s->im) != 0);
-}
-
-static void pl022_xfer(PL022State *s)
-{
- int i;
- int o;
- int val;
-
- if ((s->cr1 & PL022_CR1_SSE) == 0) {
- pl022_update(s);
- DPRINTF("Disabled\n");
- return;
- }
-
- DPRINTF("Maybe xfer %d/%d\n", s->tx_fifo_len, s->rx_fifo_len);
- i = (s->tx_fifo_head - s->tx_fifo_len) & 7;
- o = s->rx_fifo_head;
- /* ??? We do not emulate the line speed.
- This may break some applications. The are two problematic cases:
- (a) A driver feeds data into the TX FIFO until it is full,
- and only then drains the RX FIFO. On real hardware the CPU can
- feed data fast enough that the RX fifo never gets chance to overflow.
- (b) A driver transmits data, deliberately allowing the RX FIFO to
- overflow because it ignores the RX data anyway.
-
- We choose to support (a) by stalling the transmit engine if it would
- cause the RX FIFO to overflow. In practice much transmit-only code
- falls into (a) because it flushes the RX FIFO to determine when
- the transfer has completed. */
- while (s->tx_fifo_len && s->rx_fifo_len < 8) {
- DPRINTF("xfer\n");
- val = s->tx_fifo[i];
- if (s->cr1 & PL022_CR1_LBM) {
- /* Loopback mode. */
- } else {
- val = ssi_transfer(s->ssi, val);
- }
- s->rx_fifo[o] = val & s->bitmask;
- i = (i + 1) & 7;
- o = (o + 1) & 7;
- s->tx_fifo_len--;
- s->rx_fifo_len++;
- }
- s->rx_fifo_head = o;
- pl022_update(s);
-}
-
-static uint64_t pl022_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- PL022State *s = (PL022State *)opaque;
- int val;
-
- if (offset >= 0xfe0 && offset < 0x1000) {
- return pl022_id[(offset - 0xfe0) >> 2];
- }
- switch (offset) {
- case 0x00: /* CR0 */
- return s->cr0;
- case 0x04: /* CR1 */
- return s->cr1;
- case 0x08: /* DR */
- if (s->rx_fifo_len) {
- val = s->rx_fifo[(s->rx_fifo_head - s->rx_fifo_len) & 7];
- DPRINTF("RX %02x\n", val);
- s->rx_fifo_len--;
- pl022_xfer(s);
- } else {
- val = 0;
- }
- return val;
- case 0x0c: /* SR */
- return s->sr;
- case 0x10: /* CPSR */
- return s->cpsr;
- case 0x14: /* IMSC */
- return s->im;
- case 0x18: /* RIS */
- return s->is;
- case 0x1c: /* MIS */
- return s->im & s->is;
- case 0x20: /* DMACR */
- /* Not implemented. */
- return 0;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "pl022_read: Bad offset %x\n", (int)offset);
- return 0;
- }
-}
-
-static void pl022_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PL022State *s = (PL022State *)opaque;
-
- switch (offset) {
- case 0x00: /* CR0 */
- s->cr0 = value;
- /* Clock rate and format are ignored. */
- s->bitmask = (1 << ((value & 15) + 1)) - 1;
- break;
- case 0x04: /* CR1 */
- s->cr1 = value;
- if ((s->cr1 & (PL022_CR1_MS | PL022_CR1_SSE))
- == (PL022_CR1_MS | PL022_CR1_SSE)) {
- BADF("SPI slave mode not implemented\n");
- }
- pl022_xfer(s);
- break;
- case 0x08: /* DR */
- if (s->tx_fifo_len < 8) {
- DPRINTF("TX %02x\n", (unsigned)value);
- s->tx_fifo[s->tx_fifo_head] = value & s->bitmask;
- s->tx_fifo_head = (s->tx_fifo_head + 1) & 7;
- s->tx_fifo_len++;
- pl022_xfer(s);
- }
- break;
- case 0x10: /* CPSR */
- /* Prescaler. Ignored. */
- s->cpsr = value & 0xff;
- break;
- case 0x14: /* IMSC */
- s->im = value;
- pl022_update(s);
- break;
- case 0x20: /* DMACR */
- if (value) {
- qemu_log_mask(LOG_UNIMP, "pl022: DMA not implemented\n");
- }
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "pl022_write: Bad offset %x\n", (int)offset);
- }
-}
-
-static void pl022_reset(PL022State *s)
-{
- s->rx_fifo_len = 0;
- s->tx_fifo_len = 0;
- s->im = 0;
- s->is = PL022_INT_TX;
- s->sr = PL022_SR_TFE | PL022_SR_TNF;
-}
-
-static const MemoryRegionOps pl022_ops = {
- .read = pl022_read,
- .write = pl022_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int pl022_post_load(void *opaque, int version_id)
-{
- PL022State *s = opaque;
-
- if (s->tx_fifo_head < 0 ||
- s->tx_fifo_head >= ARRAY_SIZE(s->tx_fifo) ||
- s->rx_fifo_head < 0 ||
- s->rx_fifo_head >= ARRAY_SIZE(s->rx_fifo)) {
- return -1;
- }
- return 0;
-}
-
-static const VMStateDescription vmstate_pl022 = {
- .name = "pl022_ssp",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = pl022_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(cr0, PL022State),
- VMSTATE_UINT32(cr1, PL022State),
- VMSTATE_UINT32(bitmask, PL022State),
- VMSTATE_UINT32(sr, PL022State),
- VMSTATE_UINT32(cpsr, PL022State),
- VMSTATE_UINT32(is, PL022State),
- VMSTATE_UINT32(im, PL022State),
- VMSTATE_INT32(tx_fifo_head, PL022State),
- VMSTATE_INT32(rx_fifo_head, PL022State),
- VMSTATE_INT32(tx_fifo_len, PL022State),
- VMSTATE_INT32(rx_fifo_len, PL022State),
- VMSTATE_UINT16(tx_fifo[0], PL022State),
- VMSTATE_UINT16(rx_fifo[0], PL022State),
- VMSTATE_UINT16(tx_fifo[1], PL022State),
- VMSTATE_UINT16(rx_fifo[1], PL022State),
- VMSTATE_UINT16(tx_fifo[2], PL022State),
- VMSTATE_UINT16(rx_fifo[2], PL022State),
- VMSTATE_UINT16(tx_fifo[3], PL022State),
- VMSTATE_UINT16(rx_fifo[3], PL022State),
- VMSTATE_UINT16(tx_fifo[4], PL022State),
- VMSTATE_UINT16(rx_fifo[4], PL022State),
- VMSTATE_UINT16(tx_fifo[5], PL022State),
- VMSTATE_UINT16(rx_fifo[5], PL022State),
- VMSTATE_UINT16(tx_fifo[6], PL022State),
- VMSTATE_UINT16(rx_fifo[6], PL022State),
- VMSTATE_UINT16(tx_fifo[7], PL022State),
- VMSTATE_UINT16(rx_fifo[7], PL022State),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static int pl022_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- PL022State *s = PL022(dev);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &pl022_ops, s, "pl022", 0x1000);
- sysbus_init_mmio(sbd, &s->iomem);
- sysbus_init_irq(sbd, &s->irq);
- s->ssi = ssi_create_bus(dev, "ssi");
- pl022_reset(s);
- vmstate_register(dev, -1, &vmstate_pl022, s);
- return 0;
-}
-
-static void pl022_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
- sdc->init = pl022_init;
-}
-
-static const TypeInfo pl022_info = {
- .name = TYPE_PL022,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PL022State),
- .class_init = pl022_class_init,
-};
-
-static void pl022_register_types(void)
-{
- type_register_static(&pl022_info);
-}
-
-type_init(pl022_register_types)
diff --git a/qemu/hw/ssi/ssi.c b/qemu/hw/ssi/ssi.c
deleted file mode 100644
index 9791c0d94..000000000
--- a/qemu/hw/ssi/ssi.c
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * QEMU Synchronous Serial Interface support
- *
- * Copyright (c) 2009 CodeSourcery.
- * Copyright (c) 2012 Peter A.G. Crosthwaite (peter.crosthwaite@petalogix.com)
- * Copyright (c) 2012 PetaLogix Pty Ltd.
- * Written by Paul Brook
- *
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "hw/ssi/ssi.h"
-
-struct SSIBus {
- BusState parent_obj;
-};
-
-#define TYPE_SSI_BUS "SSI"
-#define SSI_BUS(obj) OBJECT_CHECK(SSIBus, (obj), TYPE_SSI_BUS)
-
-static const TypeInfo ssi_bus_info = {
- .name = TYPE_SSI_BUS,
- .parent = TYPE_BUS,
- .instance_size = sizeof(SSIBus),
-};
-
-static void ssi_cs_default(void *opaque, int n, int level)
-{
- SSISlave *s = SSI_SLAVE(opaque);
- bool cs = !!level;
- assert(n == 0);
- if (s->cs != cs) {
- SSISlaveClass *ssc = SSI_SLAVE_GET_CLASS(s);
- if (ssc->set_cs) {
- ssc->set_cs(s, cs);
- }
- }
- s->cs = cs;
-}
-
-static uint32_t ssi_transfer_raw_default(SSISlave *dev, uint32_t val)
-{
- SSISlaveClass *ssc = SSI_SLAVE_GET_CLASS(dev);
-
- if ((dev->cs && ssc->cs_polarity == SSI_CS_HIGH) ||
- (!dev->cs && ssc->cs_polarity == SSI_CS_LOW) ||
- ssc->cs_polarity == SSI_CS_NONE) {
- return ssc->transfer(dev, val);
- }
- return 0;
-}
-
-static int ssi_slave_init(DeviceState *dev)
-{
- SSISlave *s = SSI_SLAVE(dev);
- SSISlaveClass *ssc = SSI_SLAVE_GET_CLASS(s);
-
- if (ssc->transfer_raw == ssi_transfer_raw_default &&
- ssc->cs_polarity != SSI_CS_NONE) {
- qdev_init_gpio_in_named(dev, ssi_cs_default, SSI_GPIO_CS, 1);
- }
-
- return ssc->init(s);
-}
-
-static void ssi_slave_class_init(ObjectClass *klass, void *data)
-{
- SSISlaveClass *ssc = SSI_SLAVE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->init = ssi_slave_init;
- dc->bus_type = TYPE_SSI_BUS;
- if (!ssc->transfer_raw) {
- ssc->transfer_raw = ssi_transfer_raw_default;
- }
-}
-
-static const TypeInfo ssi_slave_info = {
- .name = TYPE_SSI_SLAVE,
- .parent = TYPE_DEVICE,
- .class_init = ssi_slave_class_init,
- .class_size = sizeof(SSISlaveClass),
- .abstract = true,
-};
-
-DeviceState *ssi_create_slave_no_init(SSIBus *bus, const char *name)
-{
- return qdev_create(BUS(bus), name);
-}
-
-DeviceState *ssi_create_slave(SSIBus *bus, const char *name)
-{
- DeviceState *dev = ssi_create_slave_no_init(bus, name);
-
- qdev_init_nofail(dev);
- return dev;
-}
-
-SSIBus *ssi_create_bus(DeviceState *parent, const char *name)
-{
- BusState *bus;
- bus = qbus_create(TYPE_SSI_BUS, parent, name);
- return SSI_BUS(bus);
-}
-
-uint32_t ssi_transfer(SSIBus *bus, uint32_t val)
-{
- BusState *b = BUS(bus);
- BusChild *kid;
- SSISlaveClass *ssc;
- uint32_t r = 0;
-
- QTAILQ_FOREACH(kid, &b->children, sibling) {
- SSISlave *slave = SSI_SLAVE(kid->child);
- ssc = SSI_SLAVE_GET_CLASS(slave);
- r |= ssc->transfer_raw(slave, val);
- }
-
- return r;
-}
-
-const VMStateDescription vmstate_ssi_slave = {
- .name = "SSISlave",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_BOOL(cs, SSISlave),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void ssi_slave_register_types(void)
-{
- type_register_static(&ssi_bus_info);
- type_register_static(&ssi_slave_info);
-}
-
-type_init(ssi_slave_register_types)
-
-typedef struct SSIAutoConnectArg {
- qemu_irq **cs_linep;
- SSIBus *bus;
-} SSIAutoConnectArg;
-
-static int ssi_auto_connect_slave(Object *child, void *opaque)
-{
- SSIAutoConnectArg *arg = opaque;
- SSISlave *dev = (SSISlave *)object_dynamic_cast(child, TYPE_SSI_SLAVE);
- qemu_irq cs_line;
-
- if (!dev) {
- return 0;
- }
-
- cs_line = qdev_get_gpio_in_named(DEVICE(dev), SSI_GPIO_CS, 0);
- qdev_set_parent_bus(DEVICE(dev), BUS(arg->bus));
- **arg->cs_linep = cs_line;
- (*arg->cs_linep)++;
- return 0;
-}
-
-void ssi_auto_connect_slaves(DeviceState *parent, qemu_irq *cs_line,
- SSIBus *bus)
-{
- SSIAutoConnectArg arg = {
- .cs_linep = &cs_line,
- .bus = bus
- };
-
- object_child_foreach(OBJECT(parent), ssi_auto_connect_slave, &arg);
-}
diff --git a/qemu/hw/ssi/xilinx_spi.c b/qemu/hw/ssi/xilinx_spi.c
deleted file mode 100644
index 33482f04d..000000000
--- a/qemu/hw/ssi/xilinx_spi.c
+++ /dev/null
@@ -1,391 +0,0 @@
-/*
- * QEMU model of the Xilinx SPI Controller
- *
- * Copyright (C) 2010 Edgar E. Iglesias.
- * Copyright (C) 2012 Peter A. G. Crosthwaite <peter.crosthwaite@petalogix.com>
- * Copyright (C) 2012 PetaLogix
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "sysemu/sysemu.h"
-#include "qemu/log.h"
-#include "qemu/fifo8.h"
-
-#include "hw/ssi/ssi.h"
-
-#ifdef XILINX_SPI_ERR_DEBUG
-#define DB_PRINT(...) do { \
- fprintf(stderr, ": %s: ", __func__); \
- fprintf(stderr, ## __VA_ARGS__); \
- } while (0);
-#else
- #define DB_PRINT(...)
-#endif
-
-#define R_DGIER (0x1c / 4)
-#define R_DGIER_IE (1 << 31)
-
-#define R_IPISR (0x20 / 4)
-#define IRQ_DRR_NOT_EMPTY (1 << (31 - 23))
-#define IRQ_DRR_OVERRUN (1 << (31 - 26))
-#define IRQ_DRR_FULL (1 << (31 - 27))
-#define IRQ_TX_FF_HALF_EMPTY (1 << 6)
-#define IRQ_DTR_UNDERRUN (1 << 3)
-#define IRQ_DTR_EMPTY (1 << (31 - 29))
-
-#define R_IPIER (0x28 / 4)
-#define R_SRR (0x40 / 4)
-#define R_SPICR (0x60 / 4)
-#define R_SPICR_TXFF_RST (1 << 5)
-#define R_SPICR_RXFF_RST (1 << 6)
-#define R_SPICR_MTI (1 << 8)
-
-#define R_SPISR (0x64 / 4)
-#define SR_TX_FULL (1 << 3)
-#define SR_TX_EMPTY (1 << 2)
-#define SR_RX_FULL (1 << 1)
-#define SR_RX_EMPTY (1 << 0)
-
-#define R_SPIDTR (0x68 / 4)
-#define R_SPIDRR (0x6C / 4)
-#define R_SPISSR (0x70 / 4)
-#define R_TX_FF_OCY (0x74 / 4)
-#define R_RX_FF_OCY (0x78 / 4)
-#define R_MAX (0x7C / 4)
-
-#define FIFO_CAPACITY 256
-
-#define TYPE_XILINX_SPI "xlnx.xps-spi"
-#define XILINX_SPI(obj) OBJECT_CHECK(XilinxSPI, (obj), TYPE_XILINX_SPI)
-
-typedef struct XilinxSPI {
- SysBusDevice parent_obj;
-
- MemoryRegion mmio;
-
- qemu_irq irq;
- int irqline;
-
- uint8_t num_cs;
- qemu_irq *cs_lines;
-
- SSIBus *spi;
-
- Fifo8 rx_fifo;
- Fifo8 tx_fifo;
-
- uint32_t regs[R_MAX];
-} XilinxSPI;
-
-static void txfifo_reset(XilinxSPI *s)
-{
- fifo8_reset(&s->tx_fifo);
-
- s->regs[R_SPISR] &= ~SR_TX_FULL;
- s->regs[R_SPISR] |= SR_TX_EMPTY;
-}
-
-static void rxfifo_reset(XilinxSPI *s)
-{
- fifo8_reset(&s->rx_fifo);
-
- s->regs[R_SPISR] |= SR_RX_EMPTY;
- s->regs[R_SPISR] &= ~SR_RX_FULL;
-}
-
-static void xlx_spi_update_cs(XilinxSPI *s)
-{
- int i;
-
- for (i = 0; i < s->num_cs; ++i) {
- qemu_set_irq(s->cs_lines[i], !(~s->regs[R_SPISSR] & 1 << i));
- }
-}
-
-static void xlx_spi_update_irq(XilinxSPI *s)
-{
- uint32_t pending;
-
- s->regs[R_IPISR] |=
- (!fifo8_is_empty(&s->rx_fifo) ? IRQ_DRR_NOT_EMPTY : 0) |
- (fifo8_is_full(&s->rx_fifo) ? IRQ_DRR_FULL : 0);
-
- pending = s->regs[R_IPISR] & s->regs[R_IPIER];
-
- pending = pending && (s->regs[R_DGIER] & R_DGIER_IE);
- pending = !!pending;
-
- /* This call lies right in the data paths so don't call the
- irq chain unless things really changed. */
- if (pending != s->irqline) {
- s->irqline = pending;
- DB_PRINT("irq_change of state %d ISR:%x IER:%X\n",
- pending, s->regs[R_IPISR], s->regs[R_IPIER]);
- qemu_set_irq(s->irq, pending);
- }
-
-}
-
-static void xlx_spi_do_reset(XilinxSPI *s)
-{
- memset(s->regs, 0, sizeof s->regs);
-
- rxfifo_reset(s);
- txfifo_reset(s);
-
- s->regs[R_SPISSR] = ~0;
- xlx_spi_update_irq(s);
- xlx_spi_update_cs(s);
-}
-
-static void xlx_spi_reset(DeviceState *d)
-{
- xlx_spi_do_reset(XILINX_SPI(d));
-}
-
-static inline int spi_master_enabled(XilinxSPI *s)
-{
- return !(s->regs[R_SPICR] & R_SPICR_MTI);
-}
-
-static void spi_flush_txfifo(XilinxSPI *s)
-{
- uint32_t tx;
- uint32_t rx;
-
- while (!fifo8_is_empty(&s->tx_fifo)) {
- tx = (uint32_t)fifo8_pop(&s->tx_fifo);
- DB_PRINT("data tx:%x\n", tx);
- rx = ssi_transfer(s->spi, tx);
- DB_PRINT("data rx:%x\n", rx);
- if (fifo8_is_full(&s->rx_fifo)) {
- s->regs[R_IPISR] |= IRQ_DRR_OVERRUN;
- } else {
- fifo8_push(&s->rx_fifo, (uint8_t)rx);
- if (fifo8_is_full(&s->rx_fifo)) {
- s->regs[R_SPISR] |= SR_RX_FULL;
- s->regs[R_IPISR] |= IRQ_DRR_FULL;
- }
- }
-
- s->regs[R_SPISR] &= ~SR_RX_EMPTY;
- s->regs[R_SPISR] &= ~SR_TX_FULL;
- s->regs[R_SPISR] |= SR_TX_EMPTY;
-
- s->regs[R_IPISR] |= IRQ_DTR_EMPTY;
- s->regs[R_IPISR] |= IRQ_DRR_NOT_EMPTY;
- }
-
-}
-
-static uint64_t
-spi_read(void *opaque, hwaddr addr, unsigned int size)
-{
- XilinxSPI *s = opaque;
- uint32_t r = 0;
-
- addr >>= 2;
- switch (addr) {
- case R_SPIDRR:
- if (fifo8_is_empty(&s->rx_fifo)) {
- DB_PRINT("Read from empty FIFO!\n");
- return 0xdeadbeef;
- }
-
- s->regs[R_SPISR] &= ~SR_RX_FULL;
- r = fifo8_pop(&s->rx_fifo);
- if (fifo8_is_empty(&s->rx_fifo)) {
- s->regs[R_SPISR] |= SR_RX_EMPTY;
- }
- break;
-
- case R_SPISR:
- r = s->regs[addr];
- break;
-
- default:
- if (addr < ARRAY_SIZE(s->regs)) {
- r = s->regs[addr];
- }
- break;
-
- }
- DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr * 4, r);
- xlx_spi_update_irq(s);
- return r;
-}
-
-static void
-spi_write(void *opaque, hwaddr addr,
- uint64_t val64, unsigned int size)
-{
- XilinxSPI *s = opaque;
- uint32_t value = val64;
-
- DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr, value);
- addr >>= 2;
- switch (addr) {
- case R_SRR:
- if (value != 0xa) {
- DB_PRINT("Invalid write to SRR %x\n", value);
- } else {
- xlx_spi_do_reset(s);
- }
- break;
-
- case R_SPIDTR:
- s->regs[R_SPISR] &= ~SR_TX_EMPTY;
- fifo8_push(&s->tx_fifo, (uint8_t)value);
- if (fifo8_is_full(&s->tx_fifo)) {
- s->regs[R_SPISR] |= SR_TX_FULL;
- }
- if (!spi_master_enabled(s)) {
- goto done;
- } else {
- DB_PRINT("DTR and master enabled\n");
- }
- spi_flush_txfifo(s);
- break;
-
- case R_SPISR:
- DB_PRINT("Invalid write to SPISR %x\n", value);
- break;
-
- case R_IPISR:
- /* Toggle the bits. */
- s->regs[addr] ^= value;
- break;
-
- /* Slave Select Register. */
- case R_SPISSR:
- s->regs[addr] = value;
- xlx_spi_update_cs(s);
- break;
-
- case R_SPICR:
- /* FIXME: reset irq and sr state to empty queues. */
- if (value & R_SPICR_RXFF_RST) {
- rxfifo_reset(s);
- }
-
- if (value & R_SPICR_TXFF_RST) {
- txfifo_reset(s);
- }
- value &= ~(R_SPICR_RXFF_RST | R_SPICR_TXFF_RST);
- s->regs[addr] = value;
-
- if (!(value & R_SPICR_MTI)) {
- spi_flush_txfifo(s);
- }
- break;
-
- default:
- if (addr < ARRAY_SIZE(s->regs)) {
- s->regs[addr] = value;
- }
- break;
- }
-
-done:
- xlx_spi_update_irq(s);
-}
-
-static const MemoryRegionOps spi_ops = {
- .read = spi_read,
- .write = spi_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4
- }
-};
-
-static int xilinx_spi_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- XilinxSPI *s = XILINX_SPI(dev);
- int i;
-
- DB_PRINT("\n");
-
- s->spi = ssi_create_bus(dev, "spi");
-
- sysbus_init_irq(sbd, &s->irq);
- s->cs_lines = g_new0(qemu_irq, s->num_cs);
- ssi_auto_connect_slaves(dev, s->cs_lines, s->spi);
- for (i = 0; i < s->num_cs; ++i) {
- sysbus_init_irq(sbd, &s->cs_lines[i]);
- }
-
- memory_region_init_io(&s->mmio, OBJECT(s), &spi_ops, s,
- "xilinx-spi", R_MAX * 4);
- sysbus_init_mmio(sbd, &s->mmio);
-
- s->irqline = -1;
-
- fifo8_create(&s->tx_fifo, FIFO_CAPACITY);
- fifo8_create(&s->rx_fifo, FIFO_CAPACITY);
-
- return 0;
-}
-
-static const VMStateDescription vmstate_xilinx_spi = {
- .name = "xilinx_spi",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_FIFO8(tx_fifo, XilinxSPI),
- VMSTATE_FIFO8(rx_fifo, XilinxSPI),
- VMSTATE_UINT32_ARRAY(regs, XilinxSPI, R_MAX),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property xilinx_spi_properties[] = {
- DEFINE_PROP_UINT8("num-ss-bits", XilinxSPI, num_cs, 1),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void xilinx_spi_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = xilinx_spi_init;
- dc->reset = xlx_spi_reset;
- dc->props = xilinx_spi_properties;
- dc->vmsd = &vmstate_xilinx_spi;
-}
-
-static const TypeInfo xilinx_spi_info = {
- .name = TYPE_XILINX_SPI,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(XilinxSPI),
- .class_init = xilinx_spi_class_init,
-};
-
-static void xilinx_spi_register_types(void)
-{
- type_register_static(&xilinx_spi_info);
-}
-
-type_init(xilinx_spi_register_types)
diff --git a/qemu/hw/ssi/xilinx_spips.c b/qemu/hw/ssi/xilinx_spips.c
deleted file mode 100644
index e2b77dc3d..000000000
--- a/qemu/hw/ssi/xilinx_spips.c
+++ /dev/null
@@ -1,734 +0,0 @@
-/*
- * QEMU model of the Xilinx Zynq SPI controller
- *
- * Copyright (c) 2012 Peter A. G. Crosthwaite
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "sysemu/sysemu.h"
-#include "hw/ptimer.h"
-#include "qemu/log.h"
-#include "qemu/fifo8.h"
-#include "hw/ssi/ssi.h"
-#include "qemu/bitops.h"
-#include "hw/ssi/xilinx_spips.h"
-
-#ifndef XILINX_SPIPS_ERR_DEBUG
-#define XILINX_SPIPS_ERR_DEBUG 0
-#endif
-
-#define DB_PRINT_L(level, ...) do { \
- if (XILINX_SPIPS_ERR_DEBUG > (level)) { \
- fprintf(stderr, ": %s: ", __func__); \
- fprintf(stderr, ## __VA_ARGS__); \
- } \
-} while (0);
-
-/* config register */
-#define R_CONFIG (0x00 / 4)
-#define IFMODE (1U << 31)
-#define ENDIAN (1 << 26)
-#define MODEFAIL_GEN_EN (1 << 17)
-#define MAN_START_COM (1 << 16)
-#define MAN_START_EN (1 << 15)
-#define MANUAL_CS (1 << 14)
-#define CS (0xF << 10)
-#define CS_SHIFT (10)
-#define PERI_SEL (1 << 9)
-#define REF_CLK (1 << 8)
-#define FIFO_WIDTH (3 << 6)
-#define BAUD_RATE_DIV (7 << 3)
-#define CLK_PH (1 << 2)
-#define CLK_POL (1 << 1)
-#define MODE_SEL (1 << 0)
-#define R_CONFIG_RSVD (0x7bf40000)
-
-/* interrupt mechanism */
-#define R_INTR_STATUS (0x04 / 4)
-#define R_INTR_EN (0x08 / 4)
-#define R_INTR_DIS (0x0C / 4)
-#define R_INTR_MASK (0x10 / 4)
-#define IXR_TX_FIFO_UNDERFLOW (1 << 6)
-#define IXR_RX_FIFO_FULL (1 << 5)
-#define IXR_RX_FIFO_NOT_EMPTY (1 << 4)
-#define IXR_TX_FIFO_FULL (1 << 3)
-#define IXR_TX_FIFO_NOT_FULL (1 << 2)
-#define IXR_TX_FIFO_MODE_FAIL (1 << 1)
-#define IXR_RX_FIFO_OVERFLOW (1 << 0)
-#define IXR_ALL ((IXR_TX_FIFO_UNDERFLOW<<1)-1)
-
-#define R_EN (0x14 / 4)
-#define R_DELAY (0x18 / 4)
-#define R_TX_DATA (0x1C / 4)
-#define R_RX_DATA (0x20 / 4)
-#define R_SLAVE_IDLE_COUNT (0x24 / 4)
-#define R_TX_THRES (0x28 / 4)
-#define R_RX_THRES (0x2C / 4)
-#define R_TXD1 (0x80 / 4)
-#define R_TXD2 (0x84 / 4)
-#define R_TXD3 (0x88 / 4)
-
-#define R_LQSPI_CFG (0xa0 / 4)
-#define R_LQSPI_CFG_RESET 0x03A002EB
-#define LQSPI_CFG_LQ_MODE (1U << 31)
-#define LQSPI_CFG_TWO_MEM (1 << 30)
-#define LQSPI_CFG_SEP_BUS (1 << 30)
-#define LQSPI_CFG_U_PAGE (1 << 28)
-#define LQSPI_CFG_MODE_EN (1 << 25)
-#define LQSPI_CFG_MODE_WIDTH 8
-#define LQSPI_CFG_MODE_SHIFT 16
-#define LQSPI_CFG_DUMMY_WIDTH 3
-#define LQSPI_CFG_DUMMY_SHIFT 8
-#define LQSPI_CFG_INST_CODE 0xFF
-
-#define R_LQSPI_STS (0xA4 / 4)
-#define LQSPI_STS_WR_RECVD (1 << 1)
-
-#define R_MOD_ID (0xFC / 4)
-
-/* size of TXRX FIFOs */
-#define RXFF_A 32
-#define TXFF_A 32
-
-#define RXFF_A_Q (64 * 4)
-#define TXFF_A_Q (64 * 4)
-
-/* 16MB per linear region */
-#define LQSPI_ADDRESS_BITS 24
-/* Bite off 4k chunks at a time */
-#define LQSPI_CACHE_SIZE 1024
-
-#define SNOOP_CHECKING 0xFF
-#define SNOOP_NONE 0xFE
-#define SNOOP_STRIPING 0
-
-typedef enum {
- READ = 0x3,
- FAST_READ = 0xb,
- DOR = 0x3b,
- QOR = 0x6b,
- DIOR = 0xbb,
- QIOR = 0xeb,
-
- PP = 0x2,
- DPP = 0xa2,
- QPP = 0x32,
-} FlashCMD;
-
-typedef struct {
- XilinxSPIPS parent_obj;
-
- uint8_t lqspi_buf[LQSPI_CACHE_SIZE];
- hwaddr lqspi_cached_addr;
-} XilinxQSPIPS;
-
-typedef struct XilinxSPIPSClass {
- SysBusDeviceClass parent_class;
-
- const MemoryRegionOps *reg_ops;
-
- uint32_t rx_fifo_size;
- uint32_t tx_fifo_size;
-} XilinxSPIPSClass;
-
-static inline int num_effective_busses(XilinxSPIPS *s)
-{
- return (s->regs[R_LQSPI_CFG] & LQSPI_CFG_SEP_BUS &&
- s->regs[R_LQSPI_CFG] & LQSPI_CFG_TWO_MEM) ? s->num_busses : 1;
-}
-
-static inline bool xilinx_spips_cs_is_set(XilinxSPIPS *s, int i, int field)
-{
- return ~field & (1 << i) && (s->regs[R_CONFIG] & MANUAL_CS
- || !fifo8_is_empty(&s->tx_fifo));
-}
-
-static void xilinx_spips_update_cs_lines(XilinxSPIPS *s)
-{
- int i, j;
- bool found = false;
- int field = s->regs[R_CONFIG] >> CS_SHIFT;
-
- for (i = 0; i < s->num_cs; i++) {
- for (j = 0; j < num_effective_busses(s); j++) {
- int upage = !!(s->regs[R_LQSPI_STS] & LQSPI_CFG_U_PAGE);
- int cs_to_set = (j * s->num_cs + i + upage) %
- (s->num_cs * s->num_busses);
-
- if (xilinx_spips_cs_is_set(s, i, field) && !found) {
- DB_PRINT_L(0, "selecting slave %d\n", i);
- qemu_set_irq(s->cs_lines[cs_to_set], 0);
- } else {
- DB_PRINT_L(0, "deselecting slave %d\n", i);
- qemu_set_irq(s->cs_lines[cs_to_set], 1);
- }
- }
- if (xilinx_spips_cs_is_set(s, i, field)) {
- found = true;
- }
- }
- if (!found) {
- s->snoop_state = SNOOP_CHECKING;
- DB_PRINT_L(1, "moving to snoop check state\n");
- }
-}
-
-static void xilinx_spips_update_ixr(XilinxSPIPS *s)
-{
- if (s->regs[R_LQSPI_CFG] & LQSPI_CFG_LQ_MODE) {
- return;
- }
- /* These are set/cleared as they occur */
- s->regs[R_INTR_STATUS] &= (IXR_TX_FIFO_UNDERFLOW | IXR_RX_FIFO_OVERFLOW |
- IXR_TX_FIFO_MODE_FAIL);
- /* these are pure functions of fifo state, set them here */
- s->regs[R_INTR_STATUS] |=
- (fifo8_is_full(&s->rx_fifo) ? IXR_RX_FIFO_FULL : 0) |
- (s->rx_fifo.num >= s->regs[R_RX_THRES] ? IXR_RX_FIFO_NOT_EMPTY : 0) |
- (fifo8_is_full(&s->tx_fifo) ? IXR_TX_FIFO_FULL : 0) |
- (s->tx_fifo.num < s->regs[R_TX_THRES] ? IXR_TX_FIFO_NOT_FULL : 0);
- /* drive external interrupt pin */
- int new_irqline = !!(s->regs[R_INTR_MASK] & s->regs[R_INTR_STATUS] &
- IXR_ALL);
- if (new_irqline != s->irqline) {
- s->irqline = new_irqline;
- qemu_set_irq(s->irq, s->irqline);
- }
-}
-
-static void xilinx_spips_reset(DeviceState *d)
-{
- XilinxSPIPS *s = XILINX_SPIPS(d);
-
- int i;
- for (i = 0; i < XLNX_SPIPS_R_MAX; i++) {
- s->regs[i] = 0;
- }
-
- fifo8_reset(&s->rx_fifo);
- fifo8_reset(&s->rx_fifo);
- /* non zero resets */
- s->regs[R_CONFIG] |= MODEFAIL_GEN_EN;
- s->regs[R_SLAVE_IDLE_COUNT] = 0xFF;
- s->regs[R_TX_THRES] = 1;
- s->regs[R_RX_THRES] = 1;
- /* FIXME: move magic number definition somewhere sensible */
- s->regs[R_MOD_ID] = 0x01090106;
- s->regs[R_LQSPI_CFG] = R_LQSPI_CFG_RESET;
- s->snoop_state = SNOOP_CHECKING;
- xilinx_spips_update_ixr(s);
- xilinx_spips_update_cs_lines(s);
-}
-
-/* N way (num) in place bit striper. Lay out row wise bits (LSB to MSB)
- * column wise (from element 0 to N-1). num is the length of x, and dir
- * reverses the direction of the transform. Best illustrated by example:
- * Each digit in the below array is a single bit (num == 3):
- *
- * {{ 76543210, } ----- stripe (dir == false) -----> {{ FCheb630, }
- * { hgfedcba, } { GDAfc741, }
- * { HGFEDCBA, }} <---- upstripe (dir == true) ----- { HEBgda52, }}
- */
-
-static inline void stripe8(uint8_t *x, int num, bool dir)
-{
- uint8_t r[num];
- memset(r, 0, sizeof(uint8_t) * num);
- int idx[2] = {0, 0};
- int bit[2] = {0, 0};
- int d = dir;
-
- for (idx[0] = 0; idx[0] < num; ++idx[0]) {
- for (bit[0] = 0; bit[0] < 8; ++bit[0]) {
- r[idx[d]] |= x[idx[!d]] & 1 << bit[!d] ? 1 << bit[d] : 0;
- idx[1] = (idx[1] + 1) % num;
- if (!idx[1]) {
- bit[1]++;
- }
- }
- }
- memcpy(x, r, sizeof(uint8_t) * num);
-}
-
-static void xilinx_spips_flush_txfifo(XilinxSPIPS *s)
-{
- int debug_level = 0;
-
- for (;;) {
- int i;
- uint8_t tx = 0;
- uint8_t tx_rx[num_effective_busses(s)];
-
- if (fifo8_is_empty(&s->tx_fifo)) {
- if (!(s->regs[R_LQSPI_CFG] & LQSPI_CFG_LQ_MODE)) {
- s->regs[R_INTR_STATUS] |= IXR_TX_FIFO_UNDERFLOW;
- }
- xilinx_spips_update_ixr(s);
- return;
- } else if (s->snoop_state == SNOOP_STRIPING) {
- for (i = 0; i < num_effective_busses(s); ++i) {
- tx_rx[i] = fifo8_pop(&s->tx_fifo);
- }
- stripe8(tx_rx, num_effective_busses(s), false);
- } else {
- tx = fifo8_pop(&s->tx_fifo);
- for (i = 0; i < num_effective_busses(s); ++i) {
- tx_rx[i] = tx;
- }
- }
-
- for (i = 0; i < num_effective_busses(s); ++i) {
- DB_PRINT_L(debug_level, "tx = %02x\n", tx_rx[i]);
- tx_rx[i] = ssi_transfer(s->spi[i], (uint32_t)tx_rx[i]);
- DB_PRINT_L(debug_level, "rx = %02x\n", tx_rx[i]);
- }
-
- if (fifo8_is_full(&s->rx_fifo)) {
- s->regs[R_INTR_STATUS] |= IXR_RX_FIFO_OVERFLOW;
- DB_PRINT_L(0, "rx FIFO overflow");
- } else if (s->snoop_state == SNOOP_STRIPING) {
- stripe8(tx_rx, num_effective_busses(s), true);
- for (i = 0; i < num_effective_busses(s); ++i) {
- fifo8_push(&s->rx_fifo, (uint8_t)tx_rx[i]);
- }
- } else {
- fifo8_push(&s->rx_fifo, (uint8_t)tx_rx[0]);
- }
-
- DB_PRINT_L(debug_level, "initial snoop state: %x\n",
- (unsigned)s->snoop_state);
- switch (s->snoop_state) {
- case (SNOOP_CHECKING):
- switch (tx) { /* new instruction code */
- case READ: /* 3 address bytes, no dummy bytes/cycles */
- case PP:
- case DPP:
- case QPP:
- s->snoop_state = 3;
- break;
- case FAST_READ: /* 3 address bytes, 1 dummy byte */
- case DOR:
- case QOR:
- case DIOR: /* FIXME: these vary between vendor - set to spansion */
- s->snoop_state = 4;
- break;
- case QIOR: /* 3 address bytes, 2 dummy bytes */
- s->snoop_state = 6;
- break;
- default:
- s->snoop_state = SNOOP_NONE;
- }
- break;
- case (SNOOP_STRIPING):
- case (SNOOP_NONE):
- /* Once we hit the boring stuff - squelch debug noise */
- if (!debug_level) {
- DB_PRINT_L(0, "squelching debug info ....\n");
- debug_level = 1;
- }
- break;
- default:
- s->snoop_state--;
- }
- DB_PRINT_L(debug_level, "final snoop state: %x\n",
- (unsigned)s->snoop_state);
- }
-}
-
-static inline void rx_data_bytes(XilinxSPIPS *s, uint8_t *value, int max)
-{
- int i;
-
- for (i = 0; i < max && !fifo8_is_empty(&s->rx_fifo); ++i) {
- value[i] = fifo8_pop(&s->rx_fifo);
- }
-}
-
-static uint64_t xilinx_spips_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- XilinxSPIPS *s = opaque;
- uint32_t mask = ~0;
- uint32_t ret;
- uint8_t rx_buf[4];
-
- addr >>= 2;
- switch (addr) {
- case R_CONFIG:
- mask = ~(R_CONFIG_RSVD | MAN_START_COM);
- break;
- case R_INTR_STATUS:
- ret = s->regs[addr] & IXR_ALL;
- s->regs[addr] = 0;
- DB_PRINT_L(0, "addr=" TARGET_FMT_plx " = %x\n", addr * 4, ret);
- return ret;
- case R_INTR_MASK:
- mask = IXR_ALL;
- break;
- case R_EN:
- mask = 0x1;
- break;
- case R_SLAVE_IDLE_COUNT:
- mask = 0xFF;
- break;
- case R_MOD_ID:
- mask = 0x01FFFFFF;
- break;
- case R_INTR_EN:
- case R_INTR_DIS:
- case R_TX_DATA:
- mask = 0;
- break;
- case R_RX_DATA:
- memset(rx_buf, 0, sizeof(rx_buf));
- rx_data_bytes(s, rx_buf, s->num_txrx_bytes);
- ret = s->regs[R_CONFIG] & ENDIAN ? cpu_to_be32(*(uint32_t *)rx_buf)
- : cpu_to_le32(*(uint32_t *)rx_buf);
- DB_PRINT_L(0, "addr=" TARGET_FMT_plx " = %x\n", addr * 4, ret);
- xilinx_spips_update_ixr(s);
- return ret;
- }
- DB_PRINT_L(0, "addr=" TARGET_FMT_plx " = %x\n", addr * 4,
- s->regs[addr] & mask);
- return s->regs[addr] & mask;
-
-}
-
-static inline void tx_data_bytes(XilinxSPIPS *s, uint32_t value, int num)
-{
- int i;
- for (i = 0; i < num && !fifo8_is_full(&s->tx_fifo); ++i) {
- if (s->regs[R_CONFIG] & ENDIAN) {
- fifo8_push(&s->tx_fifo, (uint8_t)(value >> 24));
- value <<= 8;
- } else {
- fifo8_push(&s->tx_fifo, (uint8_t)value);
- value >>= 8;
- }
- }
-}
-
-static void xilinx_spips_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- int mask = ~0;
- int man_start_com = 0;
- XilinxSPIPS *s = opaque;
-
- DB_PRINT_L(0, "addr=" TARGET_FMT_plx " = %x\n", addr, (unsigned)value);
- addr >>= 2;
- switch (addr) {
- case R_CONFIG:
- mask = ~(R_CONFIG_RSVD | MAN_START_COM);
- if (value & MAN_START_COM) {
- man_start_com = 1;
- }
- break;
- case R_INTR_STATUS:
- mask = IXR_ALL;
- s->regs[R_INTR_STATUS] &= ~(mask & value);
- goto no_reg_update;
- case R_INTR_DIS:
- mask = IXR_ALL;
- s->regs[R_INTR_MASK] &= ~(mask & value);
- goto no_reg_update;
- case R_INTR_EN:
- mask = IXR_ALL;
- s->regs[R_INTR_MASK] |= mask & value;
- goto no_reg_update;
- case R_EN:
- mask = 0x1;
- break;
- case R_SLAVE_IDLE_COUNT:
- mask = 0xFF;
- break;
- case R_RX_DATA:
- case R_INTR_MASK:
- case R_MOD_ID:
- mask = 0;
- break;
- case R_TX_DATA:
- tx_data_bytes(s, (uint32_t)value, s->num_txrx_bytes);
- goto no_reg_update;
- case R_TXD1:
- tx_data_bytes(s, (uint32_t)value, 1);
- goto no_reg_update;
- case R_TXD2:
- tx_data_bytes(s, (uint32_t)value, 2);
- goto no_reg_update;
- case R_TXD3:
- tx_data_bytes(s, (uint32_t)value, 3);
- goto no_reg_update;
- }
- s->regs[addr] = (s->regs[addr] & ~mask) | (value & mask);
-no_reg_update:
- xilinx_spips_update_cs_lines(s);
- if ((man_start_com && s->regs[R_CONFIG] & MAN_START_EN) ||
- (fifo8_is_empty(&s->tx_fifo) && s->regs[R_CONFIG] & MAN_START_EN)) {
- xilinx_spips_flush_txfifo(s);
- }
- xilinx_spips_update_cs_lines(s);
- xilinx_spips_update_ixr(s);
-}
-
-static const MemoryRegionOps spips_ops = {
- .read = xilinx_spips_read,
- .write = xilinx_spips_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void xilinx_qspips_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- XilinxQSPIPS *q = XILINX_QSPIPS(opaque);
-
- xilinx_spips_write(opaque, addr, value, size);
- addr >>= 2;
-
- if (addr == R_LQSPI_CFG) {
- q->lqspi_cached_addr = ~0ULL;
- }
-}
-
-static const MemoryRegionOps qspips_ops = {
- .read = xilinx_spips_read,
- .write = xilinx_qspips_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-#define LQSPI_CACHE_SIZE 1024
-
-static uint64_t
-lqspi_read(void *opaque, hwaddr addr, unsigned int size)
-{
- int i;
- XilinxQSPIPS *q = opaque;
- XilinxSPIPS *s = opaque;
- uint32_t ret;
-
- if (addr >= q->lqspi_cached_addr &&
- addr <= q->lqspi_cached_addr + LQSPI_CACHE_SIZE - 4) {
- uint8_t *retp = &q->lqspi_buf[addr - q->lqspi_cached_addr];
- ret = cpu_to_le32(*(uint32_t *)retp);
- DB_PRINT_L(1, "addr: %08x, data: %08x\n", (unsigned)addr,
- (unsigned)ret);
- return ret;
- } else {
- int flash_addr = (addr / num_effective_busses(s));
- int slave = flash_addr >> LQSPI_ADDRESS_BITS;
- int cache_entry = 0;
- uint32_t u_page_save = s->regs[R_LQSPI_STS] & ~LQSPI_CFG_U_PAGE;
-
- s->regs[R_LQSPI_STS] &= ~LQSPI_CFG_U_PAGE;
- s->regs[R_LQSPI_STS] |= slave ? LQSPI_CFG_U_PAGE : 0;
-
- DB_PRINT_L(0, "config reg status: %08x\n", s->regs[R_LQSPI_CFG]);
-
- fifo8_reset(&s->tx_fifo);
- fifo8_reset(&s->rx_fifo);
-
- /* instruction */
- DB_PRINT_L(0, "pushing read instruction: %02x\n",
- (unsigned)(uint8_t)(s->regs[R_LQSPI_CFG] &
- LQSPI_CFG_INST_CODE));
- fifo8_push(&s->tx_fifo, s->regs[R_LQSPI_CFG] & LQSPI_CFG_INST_CODE);
- /* read address */
- DB_PRINT_L(0, "pushing read address %06x\n", flash_addr);
- fifo8_push(&s->tx_fifo, (uint8_t)(flash_addr >> 16));
- fifo8_push(&s->tx_fifo, (uint8_t)(flash_addr >> 8));
- fifo8_push(&s->tx_fifo, (uint8_t)flash_addr);
- /* mode bits */
- if (s->regs[R_LQSPI_CFG] & LQSPI_CFG_MODE_EN) {
- fifo8_push(&s->tx_fifo, extract32(s->regs[R_LQSPI_CFG],
- LQSPI_CFG_MODE_SHIFT,
- LQSPI_CFG_MODE_WIDTH));
- }
- /* dummy bytes */
- for (i = 0; i < (extract32(s->regs[R_LQSPI_CFG], LQSPI_CFG_DUMMY_SHIFT,
- LQSPI_CFG_DUMMY_WIDTH)); ++i) {
- DB_PRINT_L(0, "pushing dummy byte\n");
- fifo8_push(&s->tx_fifo, 0);
- }
- xilinx_spips_update_cs_lines(s);
- xilinx_spips_flush_txfifo(s);
- fifo8_reset(&s->rx_fifo);
-
- DB_PRINT_L(0, "starting QSPI data read\n");
-
- while (cache_entry < LQSPI_CACHE_SIZE) {
- for (i = 0; i < 64; ++i) {
- tx_data_bytes(s, 0, 1);
- }
- xilinx_spips_flush_txfifo(s);
- for (i = 0; i < 64; ++i) {
- rx_data_bytes(s, &q->lqspi_buf[cache_entry++], 1);
- }
- }
-
- s->regs[R_LQSPI_STS] &= ~LQSPI_CFG_U_PAGE;
- s->regs[R_LQSPI_STS] |= u_page_save;
- xilinx_spips_update_cs_lines(s);
-
- q->lqspi_cached_addr = flash_addr * num_effective_busses(s);
- return lqspi_read(opaque, addr, size);
- }
-}
-
-static const MemoryRegionOps lqspi_ops = {
- .read = lqspi_read,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 1,
- .max_access_size = 4
- }
-};
-
-static void xilinx_spips_realize(DeviceState *dev, Error **errp)
-{
- XilinxSPIPS *s = XILINX_SPIPS(dev);
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- XilinxSPIPSClass *xsc = XILINX_SPIPS_GET_CLASS(s);
- int i;
-
- DB_PRINT_L(0, "realized spips\n");
-
- s->spi = g_new(SSIBus *, s->num_busses);
- for (i = 0; i < s->num_busses; ++i) {
- char bus_name[16];
- snprintf(bus_name, 16, "spi%d", i);
- s->spi[i] = ssi_create_bus(dev, bus_name);
- }
-
- s->cs_lines = g_new0(qemu_irq, s->num_cs * s->num_busses);
- ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi[0]);
- ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi[1]);
- sysbus_init_irq(sbd, &s->irq);
- for (i = 0; i < s->num_cs * s->num_busses; ++i) {
- sysbus_init_irq(sbd, &s->cs_lines[i]);
- }
-
- memory_region_init_io(&s->iomem, OBJECT(s), xsc->reg_ops, s,
- "spi", XLNX_SPIPS_R_MAX * 4);
- sysbus_init_mmio(sbd, &s->iomem);
-
- s->irqline = -1;
-
- fifo8_create(&s->rx_fifo, xsc->rx_fifo_size);
- fifo8_create(&s->tx_fifo, xsc->tx_fifo_size);
-}
-
-static void xilinx_qspips_realize(DeviceState *dev, Error **errp)
-{
- XilinxSPIPS *s = XILINX_SPIPS(dev);
- XilinxQSPIPS *q = XILINX_QSPIPS(dev);
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
-
- DB_PRINT_L(0, "realized qspips\n");
-
- s->num_busses = 2;
- s->num_cs = 2;
- s->num_txrx_bytes = 4;
-
- xilinx_spips_realize(dev, errp);
- memory_region_init_io(&s->mmlqspi, OBJECT(s), &lqspi_ops, s, "lqspi",
- (1 << LQSPI_ADDRESS_BITS) * 2);
- sysbus_init_mmio(sbd, &s->mmlqspi);
-
- q->lqspi_cached_addr = ~0ULL;
-}
-
-static int xilinx_spips_post_load(void *opaque, int version_id)
-{
- xilinx_spips_update_ixr((XilinxSPIPS *)opaque);
- xilinx_spips_update_cs_lines((XilinxSPIPS *)opaque);
- return 0;
-}
-
-static const VMStateDescription vmstate_xilinx_spips = {
- .name = "xilinx_spips",
- .version_id = 2,
- .minimum_version_id = 2,
- .post_load = xilinx_spips_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_FIFO8(tx_fifo, XilinxSPIPS),
- VMSTATE_FIFO8(rx_fifo, XilinxSPIPS),
- VMSTATE_UINT32_ARRAY(regs, XilinxSPIPS, XLNX_SPIPS_R_MAX),
- VMSTATE_UINT8(snoop_state, XilinxSPIPS),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property xilinx_spips_properties[] = {
- DEFINE_PROP_UINT8("num-busses", XilinxSPIPS, num_busses, 1),
- DEFINE_PROP_UINT8("num-ss-bits", XilinxSPIPS, num_cs, 4),
- DEFINE_PROP_UINT8("num-txrx-bytes", XilinxSPIPS, num_txrx_bytes, 1),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void xilinx_qspips_class_init(ObjectClass *klass, void * data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- XilinxSPIPSClass *xsc = XILINX_SPIPS_CLASS(klass);
-
- dc->realize = xilinx_qspips_realize;
- xsc->reg_ops = &qspips_ops;
- xsc->rx_fifo_size = RXFF_A_Q;
- xsc->tx_fifo_size = TXFF_A_Q;
-}
-
-static void xilinx_spips_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- XilinxSPIPSClass *xsc = XILINX_SPIPS_CLASS(klass);
-
- dc->realize = xilinx_spips_realize;
- dc->reset = xilinx_spips_reset;
- dc->props = xilinx_spips_properties;
- dc->vmsd = &vmstate_xilinx_spips;
-
- xsc->reg_ops = &spips_ops;
- xsc->rx_fifo_size = RXFF_A;
- xsc->tx_fifo_size = TXFF_A;
-}
-
-static const TypeInfo xilinx_spips_info = {
- .name = TYPE_XILINX_SPIPS,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(XilinxSPIPS),
- .class_init = xilinx_spips_class_init,
- .class_size = sizeof(XilinxSPIPSClass),
-};
-
-static const TypeInfo xilinx_qspips_info = {
- .name = TYPE_XILINX_QSPIPS,
- .parent = TYPE_XILINX_SPIPS,
- .instance_size = sizeof(XilinxQSPIPS),
- .class_init = xilinx_qspips_class_init,
-};
-
-static void xilinx_spips_register_types(void)
-{
- type_register_static(&xilinx_spips_info);
- type_register_static(&xilinx_qspips_info);
-}
-
-type_init(xilinx_spips_register_types)
diff --git a/qemu/hw/timer/Makefile.objs b/qemu/hw/timer/Makefile.objs
deleted file mode 100644
index 003c14fa2..000000000
--- a/qemu/hw/timer/Makefile.objs
+++ /dev/null
@@ -1,35 +0,0 @@
-common-obj-$(CONFIG_ARM_TIMER) += arm_timer.o
-common-obj-$(CONFIG_ARM_MPTIMER) += arm_mptimer.o
-common-obj-$(CONFIG_A9_GTIMER) += a9gtimer.o
-common-obj-$(CONFIG_CADENCE) += cadence_ttc.o
-common-obj-$(CONFIG_DS1338) += ds1338.o
-common-obj-$(CONFIG_HPET) += hpet.o
-common-obj-$(CONFIG_I8254) += i8254_common.o i8254.o
-common-obj-$(CONFIG_M48T59) += m48t59.o
-common-obj-$(CONFIG_PL031) += pl031.o
-common-obj-$(CONFIG_PUV3) += puv3_ost.o
-common-obj-$(CONFIG_TWL92230) += twl92230.o
-common-obj-$(CONFIG_XILINX) += xilinx_timer.o
-common-obj-$(CONFIG_SLAVIO) += slavio_timer.o
-common-obj-$(CONFIG_ETRAXFS) += etraxfs_timer.o
-common-obj-$(CONFIG_GRLIB) += grlib_gptimer.o
-common-obj-$(CONFIG_IMX) += imx_epit.o
-common-obj-$(CONFIG_IMX) += imx_gpt.o
-common-obj-$(CONFIG_LM32) += lm32_timer.o
-common-obj-$(CONFIG_MILKYMIST) += milkymist-sysctl.o
-
-obj-$(CONFIG_EXYNOS4) += exynos4210_mct.o
-obj-$(CONFIG_EXYNOS4) += exynos4210_pwm.o
-obj-$(CONFIG_EXYNOS4) += exynos4210_rtc.o
-obj-$(CONFIG_OMAP) += omap_gptimer.o
-obj-$(CONFIG_OMAP) += omap_synctimer.o
-obj-$(CONFIG_PXA2XX) += pxa2xx_timer.o
-obj-$(CONFIG_SH4) += sh_timer.o
-obj-$(CONFIG_DIGIC) += digic-timer.o
-
-obj-$(CONFIG_MC146818RTC) += mc146818rtc.o
-
-obj-$(CONFIG_ALLWINNER_A10_PIT) += allwinner-a10-pit.o
-
-common-obj-$(CONFIG_STM32F2XX_TIMER) += stm32f2xx_timer.o
-common-obj-$(CONFIG_ASPEED_SOC) += aspeed_timer.o
diff --git a/qemu/hw/timer/a9gtimer.c b/qemu/hw/timer/a9gtimer.c
deleted file mode 100644
index afe577c76..000000000
--- a/qemu/hw/timer/a9gtimer.c
+++ /dev/null
@@ -1,372 +0,0 @@
-/*
- * Global peripheral timer block for ARM A9MP
- *
- * (C) 2013 Xilinx Inc.
- *
- * Written by François LEGAL
- * Written by Peter Crosthwaite <peter.crosthwaite@xilinx.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/timer/a9gtimer.h"
-#include "qapi/error.h"
-#include "qemu/timer.h"
-#include "qemu/bitops.h"
-#include "qemu/log.h"
-#include "qom/cpu.h"
-
-#ifndef A9_GTIMER_ERR_DEBUG
-#define A9_GTIMER_ERR_DEBUG 0
-#endif
-
-#define DB_PRINT_L(level, ...) do { \
- if (A9_GTIMER_ERR_DEBUG > (level)) { \
- fprintf(stderr, ": %s: ", __func__); \
- fprintf(stderr, ## __VA_ARGS__); \
- } \
-} while (0);
-
-#define DB_PRINT(...) DB_PRINT_L(0, ## __VA_ARGS__)
-
-static inline int a9_gtimer_get_current_cpu(A9GTimerState *s)
-{
- if (current_cpu->cpu_index >= s->num_cpu) {
- hw_error("a9gtimer: num-cpu %d but this cpu is %d!\n",
- s->num_cpu, current_cpu->cpu_index);
- }
- return current_cpu->cpu_index;
-}
-
-static inline uint64_t a9_gtimer_get_conv(A9GTimerState *s)
-{
- uint64_t prescale = extract32(s->control, R_CONTROL_PRESCALER_SHIFT,
- R_CONTROL_PRESCALER_LEN);
-
- return (prescale + 1) * 10;
-}
-
-static A9GTimerUpdate a9_gtimer_get_update(A9GTimerState *s)
-{
- A9GTimerUpdate ret;
-
- ret.now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- ret.new = s->ref_counter +
- (ret.now - s->cpu_ref_time) / a9_gtimer_get_conv(s);
- return ret;
-}
-
-static void a9_gtimer_update(A9GTimerState *s, bool sync)
-{
-
- A9GTimerUpdate update = a9_gtimer_get_update(s);
- int i;
- int64_t next_cdiff = 0;
-
- for (i = 0; i < s->num_cpu; ++i) {
- A9GTimerPerCPU *gtb = &s->per_cpu[i];
- int64_t cdiff = 0;
-
- if ((s->control & R_CONTROL_TIMER_ENABLE) &&
- (gtb->control & R_CONTROL_COMP_ENABLE)) {
- /* R2p0+, where the compare function is >= */
- while (gtb->compare < update.new) {
- DB_PRINT("Compare event happened for CPU %d\n", i);
- gtb->status = 1;
- if (gtb->control & R_CONTROL_AUTO_INCREMENT) {
- DB_PRINT("Auto incrementing timer compare by %" PRId32 "\n",
- gtb->inc);
- gtb->compare += gtb->inc;
- } else {
- break;
- }
- }
- cdiff = (int64_t)gtb->compare - (int64_t)update.new + 1;
- if (cdiff > 0 && (cdiff < next_cdiff || !next_cdiff)) {
- next_cdiff = cdiff;
- }
- }
-
- qemu_set_irq(gtb->irq,
- gtb->status && (gtb->control & R_CONTROL_IRQ_ENABLE));
- }
-
- timer_del(s->timer);
- if (next_cdiff) {
- DB_PRINT("scheduling qemu_timer to fire again in %"
- PRIx64 " cycles\n", next_cdiff);
- timer_mod(s->timer, update.now + next_cdiff * a9_gtimer_get_conv(s));
- }
-
- if (s->control & R_CONTROL_TIMER_ENABLE) {
- s->counter = update.new;
- }
-
- if (sync) {
- s->cpu_ref_time = update.now;
- s->ref_counter = s->counter;
- }
-}
-
-static void a9_gtimer_update_no_sync(void *opaque)
-{
- A9GTimerState *s = A9_GTIMER(opaque);
-
- a9_gtimer_update(s, false);
-}
-
-static uint64_t a9_gtimer_read(void *opaque, hwaddr addr, unsigned size)
-{
- A9GTimerPerCPU *gtb = (A9GTimerPerCPU *)opaque;
- A9GTimerState *s = gtb->parent;
- A9GTimerUpdate update;
- uint64_t ret = 0;
- int shift = 0;
-
- switch (addr) {
- case R_COUNTER_HI:
- shift = 32;
- /* fallthrough */
- case R_COUNTER_LO:
- update = a9_gtimer_get_update(s);
- ret = extract64(update.new, shift, 32);
- break;
- case R_CONTROL:
- ret = s->control | gtb->control;
- break;
- case R_INTERRUPT_STATUS:
- ret = gtb->status;
- break;
- case R_COMPARATOR_HI:
- shift = 32;
- /* fallthrough */
- case R_COMPARATOR_LO:
- ret = extract64(gtb->compare, shift, 32);
- break;
- case R_AUTO_INCREMENT:
- ret = gtb->inc;
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "bad a9gtimer register: %x\n",
- (unsigned)addr);
- return 0;
- }
-
- DB_PRINT("addr:%#x data:%#08" PRIx64 "\n", (unsigned)addr, ret);
- return ret;
-}
-
-static void a9_gtimer_write(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
- A9GTimerPerCPU *gtb = (A9GTimerPerCPU *)opaque;
- A9GTimerState *s = gtb->parent;
- int shift = 0;
-
- DB_PRINT("addr:%#x data:%#08" PRIx64 "\n", (unsigned)addr, value);
-
- switch (addr) {
- case R_COUNTER_HI:
- shift = 32;
- /* fallthrough */
- case R_COUNTER_LO:
- /*
- * Keep it simple - ARM docco explicitly says to disable timer before
- * modding it, so dont bother trying to do all the difficult on the fly
- * timer modifications - (if they even work in real hardware??).
- */
- if (s->control & R_CONTROL_TIMER_ENABLE) {
- qemu_log_mask(LOG_GUEST_ERROR, "Cannot mod running ARM gtimer\n");
- return;
- }
- s->counter = deposit64(s->counter, shift, 32, value);
- return;
- case R_CONTROL:
- a9_gtimer_update(s, (value ^ s->control) & R_CONTROL_NEEDS_SYNC);
- gtb->control = value & R_CONTROL_BANKED;
- s->control = value & ~R_CONTROL_BANKED;
- break;
- case R_INTERRUPT_STATUS:
- a9_gtimer_update(s, false);
- gtb->status &= ~value;
- break;
- case R_COMPARATOR_HI:
- shift = 32;
- /* fallthrough */
- case R_COMPARATOR_LO:
- a9_gtimer_update(s, false);
- gtb->compare = deposit64(gtb->compare, shift, 32, value);
- break;
- case R_AUTO_INCREMENT:
- gtb->inc = value;
- return;
- default:
- return;
- }
-
- a9_gtimer_update(s, false);
-}
-
-/* Wrapper functions to implement the "read global timer for
- * the current CPU" memory regions.
- */
-static uint64_t a9_gtimer_this_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- A9GTimerState *s = A9_GTIMER(opaque);
- int id = a9_gtimer_get_current_cpu(s);
-
- /* no \n so concatenates with message from read fn */
- DB_PRINT("CPU:%d:", id);
-
- return a9_gtimer_read(&s->per_cpu[id], addr, size);
-}
-
-static void a9_gtimer_this_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- A9GTimerState *s = A9_GTIMER(opaque);
- int id = a9_gtimer_get_current_cpu(s);
-
- /* no \n so concatenates with message from write fn */
- DB_PRINT("CPU:%d:", id);
-
- a9_gtimer_write(&s->per_cpu[id], addr, value, size);
-}
-
-static const MemoryRegionOps a9_gtimer_this_ops = {
- .read = a9_gtimer_this_read,
- .write = a9_gtimer_this_write,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const MemoryRegionOps a9_gtimer_ops = {
- .read = a9_gtimer_read,
- .write = a9_gtimer_write,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void a9_gtimer_reset(DeviceState *dev)
-{
- A9GTimerState *s = A9_GTIMER(dev);
- int i;
-
- s->counter = 0;
- s->control = 0;
-
- for (i = 0; i < s->num_cpu; i++) {
- A9GTimerPerCPU *gtb = &s->per_cpu[i];
-
- gtb->control = 0;
- gtb->status = 0;
- gtb->compare = 0;
- gtb->inc = 0;
- }
- a9_gtimer_update(s, false);
-}
-
-static void a9_gtimer_realize(DeviceState *dev, Error **errp)
-{
- A9GTimerState *s = A9_GTIMER(dev);
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- int i;
-
- if (s->num_cpu < 1 || s->num_cpu > A9_GTIMER_MAX_CPUS) {
- error_setg(errp, "%s: num-cpu must be between 1 and %d",
- __func__, A9_GTIMER_MAX_CPUS);
- return;
- }
-
- memory_region_init_io(&s->iomem, OBJECT(dev), &a9_gtimer_this_ops, s,
- "a9gtimer shared", 0x20);
- sysbus_init_mmio(sbd, &s->iomem);
- s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, a9_gtimer_update_no_sync, s);
-
- for (i = 0; i < s->num_cpu; i++) {
- A9GTimerPerCPU *gtb = &s->per_cpu[i];
-
- gtb->parent = s;
- sysbus_init_irq(sbd, &gtb->irq);
- memory_region_init_io(&gtb->iomem, OBJECT(dev), &a9_gtimer_ops, gtb,
- "a9gtimer per cpu", 0x20);
- sysbus_init_mmio(sbd, &gtb->iomem);
- }
-}
-
-static const VMStateDescription vmstate_a9_gtimer_per_cpu = {
- .name = "arm.cortex-a9-global-timer.percpu",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(control, A9GTimerPerCPU),
- VMSTATE_UINT64(compare, A9GTimerPerCPU),
- VMSTATE_UINT32(status, A9GTimerPerCPU),
- VMSTATE_UINT32(inc, A9GTimerPerCPU),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_a9_gtimer = {
- .name = "arm.cortex-a9-global-timer",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_TIMER_PTR(timer, A9GTimerState),
- VMSTATE_UINT64(counter, A9GTimerState),
- VMSTATE_UINT64(ref_counter, A9GTimerState),
- VMSTATE_UINT64(cpu_ref_time, A9GTimerState),
- VMSTATE_STRUCT_VARRAY_UINT32(per_cpu, A9GTimerState, num_cpu,
- 1, vmstate_a9_gtimer_per_cpu,
- A9GTimerPerCPU),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property a9_gtimer_properties[] = {
- DEFINE_PROP_UINT32("num-cpu", A9GTimerState, num_cpu, 0),
- DEFINE_PROP_END_OF_LIST()
-};
-
-static void a9_gtimer_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = a9_gtimer_realize;
- dc->vmsd = &vmstate_a9_gtimer;
- dc->reset = a9_gtimer_reset;
- dc->props = a9_gtimer_properties;
-}
-
-static const TypeInfo a9_gtimer_info = {
- .name = TYPE_A9_GTIMER,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(A9GTimerState),
- .class_init = a9_gtimer_class_init,
-};
-
-static void a9_gtimer_register_types(void)
-{
- type_register_static(&a9_gtimer_info);
-}
-
-type_init(a9_gtimer_register_types)
diff --git a/qemu/hw/timer/allwinner-a10-pit.c b/qemu/hw/timer/allwinner-a10-pit.c
deleted file mode 100644
index 51cdc98f3..000000000
--- a/qemu/hw/timer/allwinner-a10-pit.c
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
- * Allwinner A10 timer device emulation
- *
- * Copyright (C) 2013 Li Guang
- * Written by Li Guang <lig.fnst@cn.fujitsu.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "sysemu/sysemu.h"
-#include "hw/timer/allwinner-a10-pit.h"
-
-static void a10_pit_update_irq(AwA10PITState *s)
-{
- int i;
-
- for (i = 0; i < AW_A10_PIT_TIMER_NR; i++) {
- qemu_set_irq(s->irq[i], !!(s->irq_status & s->irq_enable & (1 << i)));
- }
-}
-
-static uint64_t a10_pit_read(void *opaque, hwaddr offset, unsigned size)
-{
- AwA10PITState *s = AW_A10_PIT(opaque);
- uint8_t index;
-
- switch (offset) {
- case AW_A10_PIT_TIMER_IRQ_EN:
- return s->irq_enable;
- case AW_A10_PIT_TIMER_IRQ_ST:
- return s->irq_status;
- case AW_A10_PIT_TIMER_BASE ... AW_A10_PIT_TIMER_BASE_END:
- index = offset & 0xf0;
- index >>= 4;
- index -= 1;
- switch (offset & 0x0f) {
- case AW_A10_PIT_TIMER_CONTROL:
- return s->control[index];
- case AW_A10_PIT_TIMER_INTERVAL:
- return s->interval[index];
- case AW_A10_PIT_TIMER_COUNT:
- s->count[index] = ptimer_get_count(s->timer[index]);
- return s->count[index];
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad offset 0x%x\n", __func__, (int)offset);
- break;
- }
- case AW_A10_PIT_WDOG_CONTROL:
- break;
- case AW_A10_PIT_WDOG_MODE:
- break;
- case AW_A10_PIT_COUNT_LO:
- return s->count_lo;
- case AW_A10_PIT_COUNT_HI:
- return s->count_hi;
- case AW_A10_PIT_COUNT_CTL:
- return s->count_ctl;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad offset 0x%x\n", __func__, (int)offset);
- break;
- }
-
- return 0;
-}
-
-static void a10_pit_set_freq(AwA10PITState *s, int index)
-{
- uint32_t prescaler, source, source_freq;
-
- prescaler = 1 << extract32(s->control[index], 4, 3);
- source = extract32(s->control[index], 2, 2);
- source_freq = s->clk_freq[source];
-
- if (source_freq) {
- ptimer_set_freq(s->timer[index], source_freq / prescaler);
- } else {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid clock source %u\n",
- __func__, source);
- }
-}
-
-static void a10_pit_write(void *opaque, hwaddr offset, uint64_t value,
- unsigned size)
-{
- AwA10PITState *s = AW_A10_PIT(opaque);
- uint8_t index;
-
- switch (offset) {
- case AW_A10_PIT_TIMER_IRQ_EN:
- s->irq_enable = value;
- a10_pit_update_irq(s);
- break;
- case AW_A10_PIT_TIMER_IRQ_ST:
- s->irq_status &= ~value;
- a10_pit_update_irq(s);
- break;
- case AW_A10_PIT_TIMER_BASE ... AW_A10_PIT_TIMER_BASE_END:
- index = offset & 0xf0;
- index >>= 4;
- index -= 1;
- switch (offset & 0x0f) {
- case AW_A10_PIT_TIMER_CONTROL:
- s->control[index] = value;
- a10_pit_set_freq(s, index);
- if (s->control[index] & AW_A10_PIT_TIMER_RELOAD) {
- ptimer_set_count(s->timer[index], s->interval[index]);
- }
- if (s->control[index] & AW_A10_PIT_TIMER_EN) {
- int oneshot = 0;
- if (s->control[index] & AW_A10_PIT_TIMER_MODE) {
- oneshot = 1;
- }
- ptimer_run(s->timer[index], oneshot);
- } else {
- ptimer_stop(s->timer[index]);
- }
- break;
- case AW_A10_PIT_TIMER_INTERVAL:
- s->interval[index] = value;
- ptimer_set_limit(s->timer[index], s->interval[index], 1);
- break;
- case AW_A10_PIT_TIMER_COUNT:
- s->count[index] = value;
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad offset 0x%x\n", __func__, (int)offset);
- }
- break;
- case AW_A10_PIT_WDOG_CONTROL:
- s->watch_dog_control = value;
- break;
- case AW_A10_PIT_WDOG_MODE:
- s->watch_dog_mode = value;
- break;
- case AW_A10_PIT_COUNT_LO:
- s->count_lo = value;
- break;
- case AW_A10_PIT_COUNT_HI:
- s->count_hi = value;
- break;
- case AW_A10_PIT_COUNT_CTL:
- s->count_ctl = value;
- if (s->count_ctl & AW_A10_PIT_COUNT_RL_EN) {
- uint64_t tmp_count = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-
- s->count_lo = tmp_count;
- s->count_hi = tmp_count >> 32;
- s->count_ctl &= ~AW_A10_PIT_COUNT_RL_EN;
- }
- if (s->count_ctl & AW_A10_PIT_COUNT_CLR_EN) {
- s->count_lo = 0;
- s->count_hi = 0;
- s->count_ctl &= ~AW_A10_PIT_COUNT_CLR_EN;
- }
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad offset 0x%x\n", __func__, (int)offset);
- break;
- }
-}
-
-static const MemoryRegionOps a10_pit_ops = {
- .read = a10_pit_read,
- .write = a10_pit_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static Property a10_pit_properties[] = {
- DEFINE_PROP_UINT32("clk0-freq", AwA10PITState, clk_freq[0], 0),
- DEFINE_PROP_UINT32("clk1-freq", AwA10PITState, clk_freq[1], 0),
- DEFINE_PROP_UINT32("clk2-freq", AwA10PITState, clk_freq[2], 0),
- DEFINE_PROP_UINT32("clk3-freq", AwA10PITState, clk_freq[3], 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static const VMStateDescription vmstate_a10_pit = {
- .name = "a10.pit",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(irq_enable, AwA10PITState),
- VMSTATE_UINT32(irq_status, AwA10PITState),
- VMSTATE_UINT32_ARRAY(control, AwA10PITState, AW_A10_PIT_TIMER_NR),
- VMSTATE_UINT32_ARRAY(interval, AwA10PITState, AW_A10_PIT_TIMER_NR),
- VMSTATE_UINT32_ARRAY(count, AwA10PITState, AW_A10_PIT_TIMER_NR),
- VMSTATE_UINT32(watch_dog_mode, AwA10PITState),
- VMSTATE_UINT32(watch_dog_control, AwA10PITState),
- VMSTATE_UINT32(count_lo, AwA10PITState),
- VMSTATE_UINT32(count_hi, AwA10PITState),
- VMSTATE_UINT32(count_ctl, AwA10PITState),
- VMSTATE_PTIMER_ARRAY(timer, AwA10PITState, AW_A10_PIT_TIMER_NR),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void a10_pit_reset(DeviceState *dev)
-{
- AwA10PITState *s = AW_A10_PIT(dev);
- uint8_t i;
-
- s->irq_enable = 0;
- s->irq_status = 0;
- a10_pit_update_irq(s);
-
- for (i = 0; i < 6; i++) {
- s->control[i] = AW_A10_PIT_DEFAULT_CLOCK;
- s->interval[i] = 0;
- s->count[i] = 0;
- ptimer_stop(s->timer[i]);
- a10_pit_set_freq(s, i);
- }
- s->watch_dog_mode = 0;
- s->watch_dog_control = 0;
- s->count_lo = 0;
- s->count_hi = 0;
- s->count_ctl = 0;
-}
-
-static void a10_pit_timer_cb(void *opaque)
-{
- AwA10TimerContext *tc = opaque;
- AwA10PITState *s = tc->container;
- uint8_t i = tc->index;
-
- if (s->control[i] & AW_A10_PIT_TIMER_EN) {
- s->irq_status |= 1 << i;
- if (s->control[i] & AW_A10_PIT_TIMER_MODE) {
- ptimer_stop(s->timer[i]);
- s->control[i] &= ~AW_A10_PIT_TIMER_EN;
- }
- a10_pit_update_irq(s);
- }
-}
-
-static void a10_pit_init(Object *obj)
-{
- AwA10PITState *s = AW_A10_PIT(obj);
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- QEMUBH * bh[AW_A10_PIT_TIMER_NR];
- uint8_t i;
-
- for (i = 0; i < AW_A10_PIT_TIMER_NR; i++) {
- sysbus_init_irq(sbd, &s->irq[i]);
- }
- memory_region_init_io(&s->iomem, OBJECT(s), &a10_pit_ops, s,
- TYPE_AW_A10_PIT, 0x400);
- sysbus_init_mmio(sbd, &s->iomem);
-
- for (i = 0; i < AW_A10_PIT_TIMER_NR; i++) {
- AwA10TimerContext *tc = &s->timer_context[i];
-
- tc->container = s;
- tc->index = i;
- bh[i] = qemu_bh_new(a10_pit_timer_cb, tc);
- s->timer[i] = ptimer_init(bh[i]);
- }
-}
-
-static void a10_pit_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->reset = a10_pit_reset;
- dc->props = a10_pit_properties;
- dc->desc = "allwinner a10 timer";
- dc->vmsd = &vmstate_a10_pit;
-}
-
-static const TypeInfo a10_pit_info = {
- .name = TYPE_AW_A10_PIT,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(AwA10PITState),
- .instance_init = a10_pit_init,
- .class_init = a10_pit_class_init,
-};
-
-static void a10_register_types(void)
-{
- type_register_static(&a10_pit_info);
-}
-
-type_init(a10_register_types);
diff --git a/qemu/hw/timer/arm_mptimer.c b/qemu/hw/timer/arm_mptimer.c
deleted file mode 100644
index d66bbf01b..000000000
--- a/qemu/hw/timer/arm_mptimer.c
+++ /dev/null
@@ -1,303 +0,0 @@
-/*
- * Private peripheral timer/watchdog blocks for ARM 11MPCore and A9MP
- *
- * Copyright (c) 2006-2007 CodeSourcery.
- * Copyright (c) 2011 Linaro Limited
- * Written by Paul Brook, Peter Maydell
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/timer/arm_mptimer.h"
-#include "qapi/error.h"
-#include "qemu/timer.h"
-#include "qom/cpu.h"
-
-/* This device implements the per-cpu private timer and watchdog block
- * which is used in both the ARM11MPCore and Cortex-A9MP.
- */
-
-static inline int get_current_cpu(ARMMPTimerState *s)
-{
- if (current_cpu->cpu_index >= s->num_cpu) {
- hw_error("arm_mptimer: num-cpu %d but this cpu is %d!\n",
- s->num_cpu, current_cpu->cpu_index);
- }
- return current_cpu->cpu_index;
-}
-
-static inline void timerblock_update_irq(TimerBlock *tb)
-{
- qemu_set_irq(tb->irq, tb->status && (tb->control & 4));
-}
-
-/* Return conversion factor from mpcore timer ticks to qemu timer ticks. */
-static inline uint32_t timerblock_scale(TimerBlock *tb)
-{
- return (((tb->control >> 8) & 0xff) + 1) * 10;
-}
-
-static void timerblock_reload(TimerBlock *tb, int restart)
-{
- if (tb->count == 0) {
- return;
- }
- if (restart) {
- tb->tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- }
- tb->tick += (int64_t)tb->count * timerblock_scale(tb);
- timer_mod(tb->timer, tb->tick);
-}
-
-static void timerblock_tick(void *opaque)
-{
- TimerBlock *tb = (TimerBlock *)opaque;
- tb->status = 1;
- if (tb->control & 2) {
- tb->count = tb->load;
- timerblock_reload(tb, 0);
- } else {
- tb->count = 0;
- }
- timerblock_update_irq(tb);
-}
-
-static uint64_t timerblock_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- TimerBlock *tb = (TimerBlock *)opaque;
- int64_t val;
- switch (addr) {
- case 0: /* Load */
- return tb->load;
- case 4: /* Counter. */
- if (((tb->control & 1) == 0) || (tb->count == 0)) {
- return 0;
- }
- /* Slow and ugly, but hopefully won't happen too often. */
- val = tb->tick - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- val /= timerblock_scale(tb);
- if (val < 0) {
- val = 0;
- }
- return val;
- case 8: /* Control. */
- return tb->control;
- case 12: /* Interrupt status. */
- return tb->status;
- default:
- return 0;
- }
-}
-
-static void timerblock_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- TimerBlock *tb = (TimerBlock *)opaque;
- int64_t old;
- switch (addr) {
- case 0: /* Load */
- tb->load = value;
- /* Fall through. */
- case 4: /* Counter. */
- if ((tb->control & 1) && tb->count) {
- /* Cancel the previous timer. */
- timer_del(tb->timer);
- }
- tb->count = value;
- if (tb->control & 1) {
- timerblock_reload(tb, 1);
- }
- break;
- case 8: /* Control. */
- old = tb->control;
- tb->control = value;
- if (value & 1) {
- if ((old & 1) && (tb->count != 0)) {
- /* Do nothing if timer is ticking right now. */
- break;
- }
- if (tb->control & 2) {
- tb->count = tb->load;
- }
- timerblock_reload(tb, 1);
- } else if (old & 1) {
- /* Shutdown the timer. */
- timer_del(tb->timer);
- }
- break;
- case 12: /* Interrupt status. */
- tb->status &= ~value;
- timerblock_update_irq(tb);
- break;
- }
-}
-
-/* Wrapper functions to implement the "read timer/watchdog for
- * the current CPU" memory regions.
- */
-static uint64_t arm_thistimer_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- ARMMPTimerState *s = (ARMMPTimerState *)opaque;
- int id = get_current_cpu(s);
- return timerblock_read(&s->timerblock[id], addr, size);
-}
-
-static void arm_thistimer_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- ARMMPTimerState *s = (ARMMPTimerState *)opaque;
- int id = get_current_cpu(s);
- timerblock_write(&s->timerblock[id], addr, value, size);
-}
-
-static const MemoryRegionOps arm_thistimer_ops = {
- .read = arm_thistimer_read,
- .write = arm_thistimer_write,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const MemoryRegionOps timerblock_ops = {
- .read = timerblock_read,
- .write = timerblock_write,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void timerblock_reset(TimerBlock *tb)
-{
- tb->count = 0;
- tb->load = 0;
- tb->control = 0;
- tb->status = 0;
- tb->tick = 0;
- if (tb->timer) {
- timer_del(tb->timer);
- }
-}
-
-static void arm_mptimer_reset(DeviceState *dev)
-{
- ARMMPTimerState *s = ARM_MPTIMER(dev);
- int i;
-
- for (i = 0; i < ARRAY_SIZE(s->timerblock); i++) {
- timerblock_reset(&s->timerblock[i]);
- }
-}
-
-static void arm_mptimer_init(Object *obj)
-{
- ARMMPTimerState *s = ARM_MPTIMER(obj);
-
- memory_region_init_io(&s->iomem, obj, &arm_thistimer_ops, s,
- "arm_mptimer_timer", 0x20);
- sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
-}
-
-static void arm_mptimer_realize(DeviceState *dev, Error **errp)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- ARMMPTimerState *s = ARM_MPTIMER(dev);
- int i;
-
- if (s->num_cpu < 1 || s->num_cpu > ARM_MPTIMER_MAX_CPUS) {
- error_setg(errp, "num-cpu must be between 1 and %d",
- ARM_MPTIMER_MAX_CPUS);
- return;
- }
- /* We implement one timer block per CPU, and expose multiple MMIO regions:
- * * region 0 is "timer for this core"
- * * region 1 is "timer for core 0"
- * * region 2 is "timer for core 1"
- * and so on.
- * The outgoing interrupt lines are
- * * timer for core 0
- * * timer for core 1
- * and so on.
- */
- for (i = 0; i < s->num_cpu; i++) {
- TimerBlock *tb = &s->timerblock[i];
- tb->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, timerblock_tick, tb);
- sysbus_init_irq(sbd, &tb->irq);
- memory_region_init_io(&tb->iomem, OBJECT(s), &timerblock_ops, tb,
- "arm_mptimer_timerblock", 0x20);
- sysbus_init_mmio(sbd, &tb->iomem);
- }
-}
-
-static const VMStateDescription vmstate_timerblock = {
- .name = "arm_mptimer_timerblock",
- .version_id = 2,
- .minimum_version_id = 2,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(count, TimerBlock),
- VMSTATE_UINT32(load, TimerBlock),
- VMSTATE_UINT32(control, TimerBlock),
- VMSTATE_UINT32(status, TimerBlock),
- VMSTATE_INT64(tick, TimerBlock),
- VMSTATE_TIMER_PTR(timer, TimerBlock),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_arm_mptimer = {
- .name = "arm_mptimer",
- .version_id = 2,
- .minimum_version_id = 2,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT_VARRAY_UINT32(timerblock, ARMMPTimerState, num_cpu,
- 2, vmstate_timerblock, TimerBlock),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property arm_mptimer_properties[] = {
- DEFINE_PROP_UINT32("num-cpu", ARMMPTimerState, num_cpu, 0),
- DEFINE_PROP_END_OF_LIST()
-};
-
-static void arm_mptimer_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = arm_mptimer_realize;
- dc->vmsd = &vmstate_arm_mptimer;
- dc->reset = arm_mptimer_reset;
- dc->props = arm_mptimer_properties;
-}
-
-static const TypeInfo arm_mptimer_info = {
- .name = TYPE_ARM_MPTIMER,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(ARMMPTimerState),
- .instance_init = arm_mptimer_init,
- .class_init = arm_mptimer_class_init,
-};
-
-static void arm_mptimer_register_types(void)
-{
- type_register_static(&arm_mptimer_info);
-}
-
-type_init(arm_mptimer_register_types)
diff --git a/qemu/hw/timer/arm_timer.c b/qemu/hw/timer/arm_timer.c
deleted file mode 100644
index f1ede5f53..000000000
--- a/qemu/hw/timer/arm_timer.c
+++ /dev/null
@@ -1,409 +0,0 @@
-/*
- * ARM PrimeCell Timer modules.
- *
- * Copyright (c) 2005-2006 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "qemu/timer.h"
-#include "qemu-common.h"
-#include "hw/qdev.h"
-#include "hw/ptimer.h"
-#include "qemu/main-loop.h"
-
-/* Common timer implementation. */
-
-#define TIMER_CTRL_ONESHOT (1 << 0)
-#define TIMER_CTRL_32BIT (1 << 1)
-#define TIMER_CTRL_DIV1 (0 << 2)
-#define TIMER_CTRL_DIV16 (1 << 2)
-#define TIMER_CTRL_DIV256 (2 << 2)
-#define TIMER_CTRL_IE (1 << 5)
-#define TIMER_CTRL_PERIODIC (1 << 6)
-#define TIMER_CTRL_ENABLE (1 << 7)
-
-typedef struct {
- ptimer_state *timer;
- uint32_t control;
- uint32_t limit;
- int freq;
- int int_level;
- qemu_irq irq;
-} arm_timer_state;
-
-/* Check all active timers, and schedule the next timer interrupt. */
-
-static void arm_timer_update(arm_timer_state *s)
-{
- /* Update interrupts. */
- if (s->int_level && (s->control & TIMER_CTRL_IE)) {
- qemu_irq_raise(s->irq);
- } else {
- qemu_irq_lower(s->irq);
- }
-}
-
-static uint32_t arm_timer_read(void *opaque, hwaddr offset)
-{
- arm_timer_state *s = (arm_timer_state *)opaque;
-
- switch (offset >> 2) {
- case 0: /* TimerLoad */
- case 6: /* TimerBGLoad */
- return s->limit;
- case 1: /* TimerValue */
- return ptimer_get_count(s->timer);
- case 2: /* TimerControl */
- return s->control;
- case 4: /* TimerRIS */
- return s->int_level;
- case 5: /* TimerMIS */
- if ((s->control & TIMER_CTRL_IE) == 0)
- return 0;
- return s->int_level;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad offset %x\n", __func__, (int)offset);
- return 0;
- }
-}
-
-/* Reset the timer limit after settings have changed. */
-static void arm_timer_recalibrate(arm_timer_state *s, int reload)
-{
- uint32_t limit;
-
- if ((s->control & (TIMER_CTRL_PERIODIC | TIMER_CTRL_ONESHOT)) == 0) {
- /* Free running. */
- if (s->control & TIMER_CTRL_32BIT)
- limit = 0xffffffff;
- else
- limit = 0xffff;
- } else {
- /* Periodic. */
- limit = s->limit;
- }
- ptimer_set_limit(s->timer, limit, reload);
-}
-
-static void arm_timer_write(void *opaque, hwaddr offset,
- uint32_t value)
-{
- arm_timer_state *s = (arm_timer_state *)opaque;
- int freq;
-
- switch (offset >> 2) {
- case 0: /* TimerLoad */
- s->limit = value;
- arm_timer_recalibrate(s, 1);
- break;
- case 1: /* TimerValue */
- /* ??? Linux seems to want to write to this readonly register.
- Ignore it. */
- break;
- case 2: /* TimerControl */
- if (s->control & TIMER_CTRL_ENABLE) {
- /* Pause the timer if it is running. This may cause some
- inaccuracy dure to rounding, but avoids a whole lot of other
- messyness. */
- ptimer_stop(s->timer);
- }
- s->control = value;
- freq = s->freq;
- /* ??? Need to recalculate expiry time after changing divisor. */
- switch ((value >> 2) & 3) {
- case 1: freq >>= 4; break;
- case 2: freq >>= 8; break;
- }
- arm_timer_recalibrate(s, s->control & TIMER_CTRL_ENABLE);
- ptimer_set_freq(s->timer, freq);
- if (s->control & TIMER_CTRL_ENABLE) {
- /* Restart the timer if still enabled. */
- ptimer_run(s->timer, (s->control & TIMER_CTRL_ONESHOT) != 0);
- }
- break;
- case 3: /* TimerIntClr */
- s->int_level = 0;
- break;
- case 6: /* TimerBGLoad */
- s->limit = value;
- arm_timer_recalibrate(s, 0);
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad offset %x\n", __func__, (int)offset);
- }
- arm_timer_update(s);
-}
-
-static void arm_timer_tick(void *opaque)
-{
- arm_timer_state *s = (arm_timer_state *)opaque;
- s->int_level = 1;
- arm_timer_update(s);
-}
-
-static const VMStateDescription vmstate_arm_timer = {
- .name = "arm_timer",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(control, arm_timer_state),
- VMSTATE_UINT32(limit, arm_timer_state),
- VMSTATE_INT32(int_level, arm_timer_state),
- VMSTATE_PTIMER(timer, arm_timer_state),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static arm_timer_state *arm_timer_init(uint32_t freq)
-{
- arm_timer_state *s;
- QEMUBH *bh;
-
- s = (arm_timer_state *)g_malloc0(sizeof(arm_timer_state));
- s->freq = freq;
- s->control = TIMER_CTRL_IE;
-
- bh = qemu_bh_new(arm_timer_tick, s);
- s->timer = ptimer_init(bh);
- vmstate_register(NULL, -1, &vmstate_arm_timer, s);
- return s;
-}
-
-/* ARM PrimeCell SP804 dual timer module.
- * Docs at
- * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0271d/index.html
-*/
-
-#define TYPE_SP804 "sp804"
-#define SP804(obj) OBJECT_CHECK(SP804State, (obj), TYPE_SP804)
-
-typedef struct SP804State {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- arm_timer_state *timer[2];
- uint32_t freq0, freq1;
- int level[2];
- qemu_irq irq;
-} SP804State;
-
-static const uint8_t sp804_ids[] = {
- /* Timer ID */
- 0x04, 0x18, 0x14, 0,
- /* PrimeCell ID */
- 0xd, 0xf0, 0x05, 0xb1
-};
-
-/* Merge the IRQs from the two component devices. */
-static void sp804_set_irq(void *opaque, int irq, int level)
-{
- SP804State *s = (SP804State *)opaque;
-
- s->level[irq] = level;
- qemu_set_irq(s->irq, s->level[0] || s->level[1]);
-}
-
-static uint64_t sp804_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- SP804State *s = (SP804State *)opaque;
-
- if (offset < 0x20) {
- return arm_timer_read(s->timer[0], offset);
- }
- if (offset < 0x40) {
- return arm_timer_read(s->timer[1], offset - 0x20);
- }
-
- /* TimerPeriphID */
- if (offset >= 0xfe0 && offset <= 0xffc) {
- return sp804_ids[(offset - 0xfe0) >> 2];
- }
-
- switch (offset) {
- /* Integration Test control registers, which we won't support */
- case 0xf00: /* TimerITCR */
- case 0xf04: /* TimerITOP (strictly write only but..) */
- qemu_log_mask(LOG_UNIMP,
- "%s: integration test registers unimplemented\n",
- __func__);
- return 0;
- }
-
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad offset %x\n", __func__, (int)offset);
- return 0;
-}
-
-static void sp804_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- SP804State *s = (SP804State *)opaque;
-
- if (offset < 0x20) {
- arm_timer_write(s->timer[0], offset, value);
- return;
- }
-
- if (offset < 0x40) {
- arm_timer_write(s->timer[1], offset - 0x20, value);
- return;
- }
-
- /* Technically we could be writing to the Test Registers, but not likely */
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %x\n",
- __func__, (int)offset);
-}
-
-static const MemoryRegionOps sp804_ops = {
- .read = sp804_read,
- .write = sp804_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_sp804 = {
- .name = "sp804",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_INT32_ARRAY(level, SP804State, 2),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void sp804_init(Object *obj)
-{
- SP804State *s = SP804(obj);
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
-
- sysbus_init_irq(sbd, &s->irq);
- memory_region_init_io(&s->iomem, obj, &sp804_ops, s,
- "sp804", 0x1000);
- sysbus_init_mmio(sbd, &s->iomem);
-}
-
-static void sp804_realize(DeviceState *dev, Error **errp)
-{
- SP804State *s = SP804(dev);
-
- s->timer[0] = arm_timer_init(s->freq0);
- s->timer[1] = arm_timer_init(s->freq1);
- s->timer[0]->irq = qemu_allocate_irq(sp804_set_irq, s, 0);
- s->timer[1]->irq = qemu_allocate_irq(sp804_set_irq, s, 1);
-}
-
-/* Integrator/CP timer module. */
-
-#define TYPE_INTEGRATOR_PIT "integrator_pit"
-#define INTEGRATOR_PIT(obj) \
- OBJECT_CHECK(icp_pit_state, (obj), TYPE_INTEGRATOR_PIT)
-
-typedef struct {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- arm_timer_state *timer[3];
-} icp_pit_state;
-
-static uint64_t icp_pit_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- icp_pit_state *s = (icp_pit_state *)opaque;
- int n;
-
- /* ??? Don't know the PrimeCell ID for this device. */
- n = offset >> 8;
- if (n > 2) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad timer %d\n", __func__, n);
- return 0;
- }
-
- return arm_timer_read(s->timer[n], offset & 0xff);
-}
-
-static void icp_pit_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- icp_pit_state *s = (icp_pit_state *)opaque;
- int n;
-
- n = offset >> 8;
- if (n > 2) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad timer %d\n", __func__, n);
- return;
- }
-
- arm_timer_write(s->timer[n], offset & 0xff, value);
-}
-
-static const MemoryRegionOps icp_pit_ops = {
- .read = icp_pit_read,
- .write = icp_pit_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void icp_pit_init(Object *obj)
-{
- icp_pit_state *s = INTEGRATOR_PIT(obj);
- SysBusDevice *dev = SYS_BUS_DEVICE(obj);
-
- /* Timer 0 runs at the system clock speed (40MHz). */
- s->timer[0] = arm_timer_init(40000000);
- /* The other two timers run at 1MHz. */
- s->timer[1] = arm_timer_init(1000000);
- s->timer[2] = arm_timer_init(1000000);
-
- sysbus_init_irq(dev, &s->timer[0]->irq);
- sysbus_init_irq(dev, &s->timer[1]->irq);
- sysbus_init_irq(dev, &s->timer[2]->irq);
-
- memory_region_init_io(&s->iomem, obj, &icp_pit_ops, s,
- "icp_pit", 0x1000);
- sysbus_init_mmio(dev, &s->iomem);
- /* This device has no state to save/restore. The component timers will
- save themselves. */
-}
-
-static const TypeInfo icp_pit_info = {
- .name = TYPE_INTEGRATOR_PIT,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(icp_pit_state),
- .instance_init = icp_pit_init,
-};
-
-static Property sp804_properties[] = {
- DEFINE_PROP_UINT32("freq0", SP804State, freq0, 1000000),
- DEFINE_PROP_UINT32("freq1", SP804State, freq1, 1000000),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void sp804_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *k = DEVICE_CLASS(klass);
-
- k->realize = sp804_realize;
- k->props = sp804_properties;
- k->vmsd = &vmstate_sp804;
-}
-
-static const TypeInfo sp804_info = {
- .name = TYPE_SP804,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(SP804State),
- .instance_init = sp804_init,
- .class_init = sp804_class_init,
-};
-
-static void arm_timer_register_types(void)
-{
- type_register_static(&icp_pit_info);
- type_register_static(&sp804_info);
-}
-
-type_init(arm_timer_register_types)
diff --git a/qemu/hw/timer/aspeed_timer.c b/qemu/hw/timer/aspeed_timer.c
deleted file mode 100644
index 51e8303cd..000000000
--- a/qemu/hw/timer/aspeed_timer.c
+++ /dev/null
@@ -1,449 +0,0 @@
-/*
- * ASPEED AST2400 Timer
- *
- * Andrew Jeffery <andrew@aj.id.au>
- *
- * Copyright (C) 2016 IBM Corp.
- *
- * This code is licensed under the GPL version 2 or later. See
- * the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "hw/ptimer.h"
-#include "hw/sysbus.h"
-#include "hw/timer/aspeed_timer.h"
-#include "qemu-common.h"
-#include "qemu/bitops.h"
-#include "qemu/main-loop.h"
-#include "qemu/timer.h"
-#include "trace.h"
-
-#define TIMER_NR_REGS 4
-
-#define TIMER_CTRL_BITS 4
-#define TIMER_CTRL_MASK ((1 << TIMER_CTRL_BITS) - 1)
-
-#define TIMER_CLOCK_USE_EXT true
-#define TIMER_CLOCK_EXT_HZ 1000000
-#define TIMER_CLOCK_USE_APB false
-#define TIMER_CLOCK_APB_HZ 24000000
-
-#define TIMER_REG_STATUS 0
-#define TIMER_REG_RELOAD 1
-#define TIMER_REG_MATCH_FIRST 2
-#define TIMER_REG_MATCH_SECOND 3
-
-#define TIMER_FIRST_CAP_PULSE 4
-
-enum timer_ctrl_op {
- op_enable = 0,
- op_external_clock,
- op_overflow_interrupt,
- op_pulse_enable
-};
-
-/**
- * Avoid mutual references between AspeedTimerCtrlState and AspeedTimer
- * structs, as it's a waste of memory. The ptimer BH callback needs to know
- * whether a specific AspeedTimer is enabled, but this information is held in
- * AspeedTimerCtrlState. So, provide a helper to hoist ourselves from an
- * arbitrary AspeedTimer to AspeedTimerCtrlState.
- */
-static inline AspeedTimerCtrlState *timer_to_ctrl(AspeedTimer *t)
-{
- const AspeedTimer (*timers)[] = (void *)t - (t->id * sizeof(*t));
- return container_of(timers, AspeedTimerCtrlState, timers);
-}
-
-static inline bool timer_ctrl_status(AspeedTimer *t, enum timer_ctrl_op op)
-{
- return !!(timer_to_ctrl(t)->ctrl & BIT(t->id * TIMER_CTRL_BITS + op));
-}
-
-static inline bool timer_enabled(AspeedTimer *t)
-{
- return timer_ctrl_status(t, op_enable);
-}
-
-static inline bool timer_overflow_interrupt(AspeedTimer *t)
-{
- return timer_ctrl_status(t, op_overflow_interrupt);
-}
-
-static inline bool timer_can_pulse(AspeedTimer *t)
-{
- return t->id >= TIMER_FIRST_CAP_PULSE;
-}
-
-static void aspeed_timer_expire(void *opaque)
-{
- AspeedTimer *t = opaque;
-
- /* Only support interrupts on match values of zero for the moment - this is
- * sufficient to boot an aspeed_defconfig Linux kernel.
- *
- * TODO: matching on arbitrary values (see e.g. hw/timer/a9gtimer.c)
- */
- bool match = !(t->match[0] && t->match[1]);
- bool interrupt = timer_overflow_interrupt(t) || match;
- if (timer_enabled(t) && interrupt) {
- t->level = !t->level;
- qemu_set_irq(t->irq, t->level);
- }
-}
-
-static uint64_t aspeed_timer_get_value(AspeedTimer *t, int reg)
-{
- uint64_t value;
-
- switch (reg) {
- case TIMER_REG_STATUS:
- value = ptimer_get_count(t->timer);
- break;
- case TIMER_REG_RELOAD:
- value = t->reload;
- break;
- case TIMER_REG_MATCH_FIRST:
- case TIMER_REG_MATCH_SECOND:
- value = t->match[reg - 2];
- break;
- default:
- qemu_log_mask(LOG_UNIMP, "%s: Programming error: unexpected reg: %d\n",
- __func__, reg);
- value = 0;
- break;
- }
- return value;
-}
-
-static uint64_t aspeed_timer_read(void *opaque, hwaddr offset, unsigned size)
-{
- AspeedTimerCtrlState *s = opaque;
- const int reg = (offset & 0xf) / 4;
- uint64_t value;
-
- switch (offset) {
- case 0x30: /* Control Register */
- value = s->ctrl;
- break;
- case 0x34: /* Control Register 2 */
- value = s->ctrl2;
- break;
- case 0x00 ... 0x2c: /* Timers 1 - 4 */
- value = aspeed_timer_get_value(&s->timers[(offset >> 4)], reg);
- break;
- case 0x40 ... 0x8c: /* Timers 5 - 8 */
- value = aspeed_timer_get_value(&s->timers[(offset >> 4) - 1], reg);
- break;
- /* Illegal */
- case 0x38:
- case 0x3C:
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
- __func__, offset);
- value = 0;
- break;
- }
- trace_aspeed_timer_read(offset, size, value);
- return value;
-}
-
-static void aspeed_timer_set_value(AspeedTimerCtrlState *s, int timer, int reg,
- uint32_t value)
-{
- AspeedTimer *t;
-
- trace_aspeed_timer_set_value(timer, reg, value);
- t = &s->timers[timer];
- switch (reg) {
- case TIMER_REG_STATUS:
- if (timer_enabled(t)) {
- ptimer_set_count(t->timer, value);
- }
- break;
- case TIMER_REG_RELOAD:
- t->reload = value;
- ptimer_set_limit(t->timer, value, 1);
- break;
- case TIMER_REG_MATCH_FIRST:
- case TIMER_REG_MATCH_SECOND:
- if (value) {
- /* Non-zero match values are unsupported. As such an interrupt will
- * always be triggered when the timer reaches zero even if the
- * overflow interrupt control bit is clear.
- */
- qemu_log_mask(LOG_UNIMP, "%s: Match value unsupported by device: "
- "0x%" PRIx32 "\n", __func__, value);
- } else {
- t->match[reg - 2] = value;
- }
- break;
- default:
- qemu_log_mask(LOG_UNIMP, "%s: Programming error: unexpected reg: %d\n",
- __func__, reg);
- break;
- }
-}
-
-/* Control register operations are broken out into helpers that can be
- * explictly called on aspeed_timer_reset(), but also from
- * aspeed_timer_ctrl_op().
- */
-
-static void aspeed_timer_ctrl_enable(AspeedTimer *t, bool enable)
-{
- trace_aspeed_timer_ctrl_enable(t->id, enable);
- if (enable) {
- ptimer_run(t->timer, 0);
- } else {
- ptimer_stop(t->timer);
- ptimer_set_limit(t->timer, t->reload, 1);
- }
-}
-
-static void aspeed_timer_ctrl_external_clock(AspeedTimer *t, bool enable)
-{
- trace_aspeed_timer_ctrl_external_clock(t->id, enable);
- if (enable) {
- ptimer_set_freq(t->timer, TIMER_CLOCK_EXT_HZ);
- } else {
- ptimer_set_freq(t->timer, TIMER_CLOCK_APB_HZ);
- }
-}
-
-static void aspeed_timer_ctrl_overflow_interrupt(AspeedTimer *t, bool enable)
-{
- trace_aspeed_timer_ctrl_overflow_interrupt(t->id, enable);
-}
-
-static void aspeed_timer_ctrl_pulse_enable(AspeedTimer *t, bool enable)
-{
- if (timer_can_pulse(t)) {
- trace_aspeed_timer_ctrl_pulse_enable(t->id, enable);
- } else {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Timer does not support pulse mode\n", __func__);
- }
-}
-
-/**
- * Given the actions are fixed in number and completely described in helper
- * functions, dispatch with a lookup table rather than manage control flow with
- * a switch statement.
- */
-static void (*const ctrl_ops[])(AspeedTimer *, bool) = {
- [op_enable] = aspeed_timer_ctrl_enable,
- [op_external_clock] = aspeed_timer_ctrl_external_clock,
- [op_overflow_interrupt] = aspeed_timer_ctrl_overflow_interrupt,
- [op_pulse_enable] = aspeed_timer_ctrl_pulse_enable,
-};
-
-/**
- * Conditionally affect changes chosen by a timer's control bit.
- *
- * The aspeed_timer_ctrl_op() interface is convenient for the
- * aspeed_timer_set_ctrl() function as the "no change" early exit can be
- * calculated for all operations, which cleans up the caller code. However the
- * interface isn't convenient for the reset function where we want to enter a
- * specific state without artificially constructing old and new values that
- * will fall through the change guard (and motivates extracting the actions
- * out to helper functions).
- *
- * @t: The timer to manipulate
- * @op: The type of operation to be performed
- * @old: The old state of the timer's control bits
- * @new: The incoming state for the timer's control bits
- */
-static void aspeed_timer_ctrl_op(AspeedTimer *t, enum timer_ctrl_op op,
- uint8_t old, uint8_t new)
-{
- const uint8_t mask = BIT(op);
- const bool enable = !!(new & mask);
- const bool changed = ((old ^ new) & mask);
- if (!changed) {
- return;
- }
- ctrl_ops[op](t, enable);
-}
-
-static void aspeed_timer_set_ctrl(AspeedTimerCtrlState *s, uint32_t reg)
-{
- int i;
- int shift;
- uint8_t t_old, t_new;
- AspeedTimer *t;
- const uint8_t enable_mask = BIT(op_enable);
-
- /* Handle a dependency between the 'enable' and remaining three
- * configuration bits - i.e. if more than one bit in the control set has
- * changed, including the 'enable' bit, then we want either disable the
- * timer and perform configuration, or perform configuration and then
- * enable the timer
- */
- for (i = 0; i < ASPEED_TIMER_NR_TIMERS; i++) {
- t = &s->timers[i];
- shift = (i * TIMER_CTRL_BITS);
- t_old = (s->ctrl >> shift) & TIMER_CTRL_MASK;
- t_new = (reg >> shift) & TIMER_CTRL_MASK;
-
- /* If we are disabling, do so first */
- if ((t_old & enable_mask) && !(t_new & enable_mask)) {
- aspeed_timer_ctrl_enable(t, false);
- }
- aspeed_timer_ctrl_op(t, op_external_clock, t_old, t_new);
- aspeed_timer_ctrl_op(t, op_overflow_interrupt, t_old, t_new);
- aspeed_timer_ctrl_op(t, op_pulse_enable, t_old, t_new);
- /* If we are enabling, do so last */
- if (!(t_old & enable_mask) && (t_new & enable_mask)) {
- aspeed_timer_ctrl_enable(t, true);
- }
- }
- s->ctrl = reg;
-}
-
-static void aspeed_timer_set_ctrl2(AspeedTimerCtrlState *s, uint32_t value)
-{
- trace_aspeed_timer_set_ctrl2(value);
-}
-
-static void aspeed_timer_write(void *opaque, hwaddr offset, uint64_t value,
- unsigned size)
-{
- const uint32_t tv = (uint32_t)(value & 0xFFFFFFFF);
- const int reg = (offset & 0xf) / 4;
- AspeedTimerCtrlState *s = opaque;
-
- switch (offset) {
- /* Control Registers */
- case 0x30:
- aspeed_timer_set_ctrl(s, tv);
- break;
- case 0x34:
- aspeed_timer_set_ctrl2(s, tv);
- break;
- /* Timer Registers */
- case 0x00 ... 0x2c:
- aspeed_timer_set_value(s, (offset >> TIMER_NR_REGS), reg, tv);
- break;
- case 0x40 ... 0x8c:
- aspeed_timer_set_value(s, (offset >> TIMER_NR_REGS) - 1, reg, tv);
- break;
- /* Illegal */
- case 0x38:
- case 0x3C:
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
- __func__, offset);
- break;
- }
-}
-
-static const MemoryRegionOps aspeed_timer_ops = {
- .read = aspeed_timer_read,
- .write = aspeed_timer_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .valid.min_access_size = 4,
- .valid.max_access_size = 4,
- .valid.unaligned = false,
-};
-
-static void aspeed_init_one_timer(AspeedTimerCtrlState *s, uint8_t id)
-{
- QEMUBH *bh;
- AspeedTimer *t = &s->timers[id];
-
- t->id = id;
- bh = qemu_bh_new(aspeed_timer_expire, t);
- t->timer = ptimer_init(bh);
-}
-
-static void aspeed_timer_realize(DeviceState *dev, Error **errp)
-{
- int i;
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- AspeedTimerCtrlState *s = ASPEED_TIMER(dev);
-
- for (i = 0; i < ASPEED_TIMER_NR_TIMERS; i++) {
- aspeed_init_one_timer(s, i);
- sysbus_init_irq(sbd, &s->timers[i].irq);
- }
- memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_timer_ops, s,
- TYPE_ASPEED_TIMER, 0x1000);
- sysbus_init_mmio(sbd, &s->iomem);
-}
-
-static void aspeed_timer_reset(DeviceState *dev)
-{
- int i;
- AspeedTimerCtrlState *s = ASPEED_TIMER(dev);
-
- for (i = 0; i < ASPEED_TIMER_NR_TIMERS; i++) {
- AspeedTimer *t = &s->timers[i];
- /* Explictly call helpers to avoid any conditional behaviour through
- * aspeed_timer_set_ctrl().
- */
- aspeed_timer_ctrl_enable(t, false);
- aspeed_timer_ctrl_external_clock(t, TIMER_CLOCK_USE_APB);
- aspeed_timer_ctrl_overflow_interrupt(t, false);
- aspeed_timer_ctrl_pulse_enable(t, false);
- t->level = 0;
- t->reload = 0;
- t->match[0] = 0;
- t->match[1] = 0;
- }
- s->ctrl = 0;
- s->ctrl2 = 0;
-}
-
-static const VMStateDescription vmstate_aspeed_timer = {
- .name = "aspeed.timer",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(id, AspeedTimer),
- VMSTATE_INT32(level, AspeedTimer),
- VMSTATE_PTIMER(timer, AspeedTimer),
- VMSTATE_UINT32(reload, AspeedTimer),
- VMSTATE_UINT32_ARRAY(match, AspeedTimer, 2),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_aspeed_timer_state = {
- .name = "aspeed.timerctrl",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(ctrl, AspeedTimerCtrlState),
- VMSTATE_UINT32(ctrl2, AspeedTimerCtrlState),
- VMSTATE_STRUCT_ARRAY(timers, AspeedTimerCtrlState,
- ASPEED_TIMER_NR_TIMERS, 1, vmstate_aspeed_timer,
- AspeedTimer),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void timer_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = aspeed_timer_realize;
- dc->reset = aspeed_timer_reset;
- dc->desc = "ASPEED Timer";
- dc->vmsd = &vmstate_aspeed_timer_state;
-}
-
-static const TypeInfo aspeed_timer_info = {
- .name = TYPE_ASPEED_TIMER,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(AspeedTimerCtrlState),
- .class_init = timer_class_init,
-};
-
-static void aspeed_timer_register_types(void)
-{
- type_register_static(&aspeed_timer_info);
-}
-
-type_init(aspeed_timer_register_types)
diff --git a/qemu/hw/timer/cadence_ttc.c b/qemu/hw/timer/cadence_ttc.c
deleted file mode 100644
index 03f5b9c20..000000000
--- a/qemu/hw/timer/cadence_ttc.c
+++ /dev/null
@@ -1,492 +0,0 @@
-/*
- * Xilinx Zynq cadence TTC model
- *
- * Copyright (c) 2011 Xilinx Inc.
- * Copyright (c) 2012 Peter A.G. Crosthwaite (peter.crosthwaite@petalogix.com)
- * Copyright (c) 2012 PetaLogix Pty Ltd.
- * Written By Haibing Ma
- * M. Habib
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "qemu/timer.h"
-
-#ifdef CADENCE_TTC_ERR_DEBUG
-#define DB_PRINT(...) do { \
- fprintf(stderr, ": %s: ", __func__); \
- fprintf(stderr, ## __VA_ARGS__); \
- } while (0);
-#else
- #define DB_PRINT(...)
-#endif
-
-#define COUNTER_INTR_IV 0x00000001
-#define COUNTER_INTR_M1 0x00000002
-#define COUNTER_INTR_M2 0x00000004
-#define COUNTER_INTR_M3 0x00000008
-#define COUNTER_INTR_OV 0x00000010
-#define COUNTER_INTR_EV 0x00000020
-
-#define COUNTER_CTRL_DIS 0x00000001
-#define COUNTER_CTRL_INT 0x00000002
-#define COUNTER_CTRL_DEC 0x00000004
-#define COUNTER_CTRL_MATCH 0x00000008
-#define COUNTER_CTRL_RST 0x00000010
-
-#define CLOCK_CTRL_PS_EN 0x00000001
-#define CLOCK_CTRL_PS_V 0x0000001e
-
-typedef struct {
- QEMUTimer *timer;
- int freq;
-
- uint32_t reg_clock;
- uint32_t reg_count;
- uint32_t reg_value;
- uint16_t reg_interval;
- uint16_t reg_match[3];
- uint32_t reg_intr;
- uint32_t reg_intr_en;
- uint32_t reg_event_ctrl;
- uint32_t reg_event;
-
- uint64_t cpu_time;
- unsigned int cpu_time_valid;
-
- qemu_irq irq;
-} CadenceTimerState;
-
-#define TYPE_CADENCE_TTC "cadence_ttc"
-#define CADENCE_TTC(obj) \
- OBJECT_CHECK(CadenceTTCState, (obj), TYPE_CADENCE_TTC)
-
-typedef struct CadenceTTCState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- CadenceTimerState timer[3];
-} CadenceTTCState;
-
-static void cadence_timer_update(CadenceTimerState *s)
-{
- qemu_set_irq(s->irq, !!(s->reg_intr & s->reg_intr_en));
-}
-
-static CadenceTimerState *cadence_timer_from_addr(void *opaque,
- hwaddr offset)
-{
- unsigned int index;
- CadenceTTCState *s = (CadenceTTCState *)opaque;
-
- index = (offset >> 2) % 3;
-
- return &s->timer[index];
-}
-
-static uint64_t cadence_timer_get_ns(CadenceTimerState *s, uint64_t timer_steps)
-{
- /* timer_steps has max value of 0x100000000. double check it
- * (or overflow can happen below) */
- assert(timer_steps <= 1ULL << 32);
-
- uint64_t r = timer_steps * 1000000000ULL;
- if (s->reg_clock & CLOCK_CTRL_PS_EN) {
- r >>= 16 - (((s->reg_clock & CLOCK_CTRL_PS_V) >> 1) + 1);
- } else {
- r >>= 16;
- }
- r /= (uint64_t)s->freq;
- return r;
-}
-
-static uint64_t cadence_timer_get_steps(CadenceTimerState *s, uint64_t ns)
-{
- uint64_t to_divide = 1000000000ULL;
-
- uint64_t r = ns;
- /* for very large intervals (> 8s) do some division first to stop
- * overflow (costs some prescision) */
- while (r >= 8ULL << 30 && to_divide > 1) {
- r /= 1000;
- to_divide /= 1000;
- }
- r <<= 16;
- /* keep early-dividing as needed */
- while (r >= 8ULL << 30 && to_divide > 1) {
- r /= 1000;
- to_divide /= 1000;
- }
- r *= (uint64_t)s->freq;
- if (s->reg_clock & CLOCK_CTRL_PS_EN) {
- r /= 1 << (((s->reg_clock & CLOCK_CTRL_PS_V) >> 1) + 1);
- }
-
- r /= to_divide;
- return r;
-}
-
-/* determine if x is in between a and b, exclusive of a, inclusive of b */
-
-static inline int64_t is_between(int64_t x, int64_t a, int64_t b)
-{
- if (a < b) {
- return x > a && x <= b;
- }
- return x < a && x >= b;
-}
-
-static void cadence_timer_run(CadenceTimerState *s)
-{
- int i;
- int64_t event_interval, next_value;
-
- assert(s->cpu_time_valid); /* cadence_timer_sync must be called first */
-
- if (s->reg_count & COUNTER_CTRL_DIS) {
- s->cpu_time_valid = 0;
- return;
- }
-
- { /* figure out what's going to happen next (rollover or match) */
- int64_t interval = (uint64_t)((s->reg_count & COUNTER_CTRL_INT) ?
- (int64_t)s->reg_interval + 1 : 0x10000ULL) << 16;
- next_value = (s->reg_count & COUNTER_CTRL_DEC) ? -1ULL : interval;
- for (i = 0; i < 3; ++i) {
- int64_t cand = (uint64_t)s->reg_match[i] << 16;
- if (is_between(cand, (uint64_t)s->reg_value, next_value)) {
- next_value = cand;
- }
- }
- }
- DB_PRINT("next timer event value: %09llx\n",
- (unsigned long long)next_value);
-
- event_interval = next_value - (int64_t)s->reg_value;
- event_interval = (event_interval < 0) ? -event_interval : event_interval;
-
- timer_mod(s->timer, s->cpu_time +
- cadence_timer_get_ns(s, event_interval));
-}
-
-static void cadence_timer_sync(CadenceTimerState *s)
-{
- int i;
- int64_t r, x;
- int64_t interval = ((s->reg_count & COUNTER_CTRL_INT) ?
- (int64_t)s->reg_interval + 1 : 0x10000ULL) << 16;
- uint64_t old_time = s->cpu_time;
-
- s->cpu_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- DB_PRINT("cpu time: %lld ns\n", (long long)old_time);
-
- if (!s->cpu_time_valid || old_time == s->cpu_time) {
- s->cpu_time_valid = 1;
- return;
- }
-
- r = (int64_t)cadence_timer_get_steps(s, s->cpu_time - old_time);
- x = (int64_t)s->reg_value + ((s->reg_count & COUNTER_CTRL_DEC) ? -r : r);
-
- for (i = 0; i < 3; ++i) {
- int64_t m = (int64_t)s->reg_match[i] << 16;
- if (m > interval) {
- continue;
- }
- /* check to see if match event has occurred. check m +/- interval
- * to account for match events in wrap around cases */
- if (is_between(m, s->reg_value, x) ||
- is_between(m + interval, s->reg_value, x) ||
- is_between(m - interval, s->reg_value, x)) {
- s->reg_intr |= (2 << i);
- }
- }
- if ((x < 0) || (x >= interval)) {
- s->reg_intr |= (s->reg_count & COUNTER_CTRL_INT) ?
- COUNTER_INTR_IV : COUNTER_INTR_OV;
- }
- while (x < 0) {
- x += interval;
- }
- s->reg_value = (uint32_t)(x % interval);
- cadence_timer_update(s);
-}
-
-static void cadence_timer_tick(void *opaque)
-{
- CadenceTimerState *s = opaque;
-
- DB_PRINT("\n");
- cadence_timer_sync(s);
- cadence_timer_run(s);
-}
-
-static uint32_t cadence_ttc_read_imp(void *opaque, hwaddr offset)
-{
- CadenceTimerState *s = cadence_timer_from_addr(opaque, offset);
- uint32_t value;
-
- cadence_timer_sync(s);
- cadence_timer_run(s);
-
- switch (offset) {
- case 0x00: /* clock control */
- case 0x04:
- case 0x08:
- return s->reg_clock;
-
- case 0x0c: /* counter control */
- case 0x10:
- case 0x14:
- return s->reg_count;
-
- case 0x18: /* counter value */
- case 0x1c:
- case 0x20:
- return (uint16_t)(s->reg_value >> 16);
-
- case 0x24: /* reg_interval counter */
- case 0x28:
- case 0x2c:
- return s->reg_interval;
-
- case 0x30: /* match 1 counter */
- case 0x34:
- case 0x38:
- return s->reg_match[0];
-
- case 0x3c: /* match 2 counter */
- case 0x40:
- case 0x44:
- return s->reg_match[1];
-
- case 0x48: /* match 3 counter */
- case 0x4c:
- case 0x50:
- return s->reg_match[2];
-
- case 0x54: /* interrupt register */
- case 0x58:
- case 0x5c:
- /* cleared after read */
- value = s->reg_intr;
- s->reg_intr = 0;
- cadence_timer_update(s);
- return value;
-
- case 0x60: /* interrupt enable */
- case 0x64:
- case 0x68:
- return s->reg_intr_en;
-
- case 0x6c:
- case 0x70:
- case 0x74:
- return s->reg_event_ctrl;
-
- case 0x78:
- case 0x7c:
- case 0x80:
- return s->reg_event;
-
- default:
- return 0;
- }
-}
-
-static uint64_t cadence_ttc_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- uint32_t ret = cadence_ttc_read_imp(opaque, offset);
-
- DB_PRINT("addr: %08x data: %08x\n", (unsigned)offset, (unsigned)ret);
- return ret;
-}
-
-static void cadence_ttc_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- CadenceTimerState *s = cadence_timer_from_addr(opaque, offset);
-
- DB_PRINT("addr: %08x data %08x\n", (unsigned)offset, (unsigned)value);
-
- cadence_timer_sync(s);
-
- switch (offset) {
- case 0x00: /* clock control */
- case 0x04:
- case 0x08:
- s->reg_clock = value & 0x3F;
- break;
-
- case 0x0c: /* counter control */
- case 0x10:
- case 0x14:
- if (value & COUNTER_CTRL_RST) {
- s->reg_value = 0;
- }
- s->reg_count = value & 0x3f & ~COUNTER_CTRL_RST;
- break;
-
- case 0x24: /* interval register */
- case 0x28:
- case 0x2c:
- s->reg_interval = value & 0xffff;
- break;
-
- case 0x30: /* match register */
- case 0x34:
- case 0x38:
- s->reg_match[0] = value & 0xffff;
- break;
-
- case 0x3c: /* match register */
- case 0x40:
- case 0x44:
- s->reg_match[1] = value & 0xffff;
- break;
-
- case 0x48: /* match register */
- case 0x4c:
- case 0x50:
- s->reg_match[2] = value & 0xffff;
- break;
-
- case 0x54: /* interrupt register */
- case 0x58:
- case 0x5c:
- break;
-
- case 0x60: /* interrupt enable */
- case 0x64:
- case 0x68:
- s->reg_intr_en = value & 0x3f;
- break;
-
- case 0x6c: /* event control */
- case 0x70:
- case 0x74:
- s->reg_event_ctrl = value & 0x07;
- break;
-
- default:
- return;
- }
-
- cadence_timer_run(s);
- cadence_timer_update(s);
-}
-
-static const MemoryRegionOps cadence_ttc_ops = {
- .read = cadence_ttc_read,
- .write = cadence_ttc_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void cadence_timer_reset(CadenceTimerState *s)
-{
- s->reg_count = 0x21;
-}
-
-static void cadence_timer_init(uint32_t freq, CadenceTimerState *s)
-{
- memset(s, 0, sizeof(CadenceTimerState));
- s->freq = freq;
-
- cadence_timer_reset(s);
-
- s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cadence_timer_tick, s);
-}
-
-static void cadence_ttc_init(Object *obj)
-{
- CadenceTTCState *s = CADENCE_TTC(obj);
- int i;
-
- for (i = 0; i < 3; ++i) {
- cadence_timer_init(133000000, &s->timer[i]);
- sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->timer[i].irq);
- }
-
- memory_region_init_io(&s->iomem, obj, &cadence_ttc_ops, s,
- "timer", 0x1000);
- sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
-}
-
-static void cadence_timer_pre_save(void *opaque)
-{
- cadence_timer_sync((CadenceTimerState *)opaque);
-}
-
-static int cadence_timer_post_load(void *opaque, int version_id)
-{
- CadenceTimerState *s = opaque;
-
- s->cpu_time_valid = 0;
- cadence_timer_sync(s);
- cadence_timer_run(s);
- cadence_timer_update(s);
- return 0;
-}
-
-static const VMStateDescription vmstate_cadence_timer = {
- .name = "cadence_timer",
- .version_id = 1,
- .minimum_version_id = 1,
- .pre_save = cadence_timer_pre_save,
- .post_load = cadence_timer_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(reg_clock, CadenceTimerState),
- VMSTATE_UINT32(reg_count, CadenceTimerState),
- VMSTATE_UINT32(reg_value, CadenceTimerState),
- VMSTATE_UINT16(reg_interval, CadenceTimerState),
- VMSTATE_UINT16_ARRAY(reg_match, CadenceTimerState, 3),
- VMSTATE_UINT32(reg_intr, CadenceTimerState),
- VMSTATE_UINT32(reg_intr_en, CadenceTimerState),
- VMSTATE_UINT32(reg_event_ctrl, CadenceTimerState),
- VMSTATE_UINT32(reg_event, CadenceTimerState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_cadence_ttc = {
- .name = "cadence_TTC",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT_ARRAY(timer, CadenceTTCState, 3, 0,
- vmstate_cadence_timer,
- CadenceTimerState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void cadence_ttc_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->vmsd = &vmstate_cadence_ttc;
-}
-
-static const TypeInfo cadence_ttc_info = {
- .name = TYPE_CADENCE_TTC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(CadenceTTCState),
- .instance_init = cadence_ttc_init,
- .class_init = cadence_ttc_class_init,
-};
-
-static void cadence_ttc_register_types(void)
-{
- type_register_static(&cadence_ttc_info);
-}
-
-type_init(cadence_ttc_register_types)
diff --git a/qemu/hw/timer/digic-timer.c b/qemu/hw/timer/digic-timer.c
deleted file mode 100644
index 5b97e1e1a..000000000
--- a/qemu/hw/timer/digic-timer.c
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * QEMU model of the Canon DIGIC timer block.
- *
- * Copyright (C) 2013 Antony Pavlov <antonynpavlov@gmail.com>
- *
- * This model is based on reverse engineering efforts
- * made by CHDK (http://chdk.wikia.com) and
- * Magic Lantern (http://www.magiclantern.fm) projects
- * contributors.
- *
- * See "Timer/Clock Module" docs here:
- * http://magiclantern.wikia.com/wiki/Register_Map
- *
- * The QEMU model of the OSTimer in PKUnity SoC by Guan Xuetao
- * is used as a template.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "hw/ptimer.h"
-#include "qemu/main-loop.h"
-
-#include "hw/timer/digic-timer.h"
-
-static const VMStateDescription vmstate_digic_timer = {
- .name = "digic.timer",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_PTIMER(ptimer, DigicTimerState),
- VMSTATE_UINT32(control, DigicTimerState),
- VMSTATE_UINT32(relvalue, DigicTimerState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void digic_timer_reset(DeviceState *dev)
-{
- DigicTimerState *s = DIGIC_TIMER(dev);
-
- ptimer_stop(s->ptimer);
- s->control = 0;
- s->relvalue = 0;
-}
-
-static uint64_t digic_timer_read(void *opaque, hwaddr offset, unsigned size)
-{
- DigicTimerState *s = opaque;
- uint64_t ret = 0;
-
- switch (offset) {
- case DIGIC_TIMER_CONTROL:
- ret = s->control;
- break;
- case DIGIC_TIMER_RELVALUE:
- ret = s->relvalue;
- break;
- case DIGIC_TIMER_VALUE:
- ret = ptimer_get_count(s->ptimer) & 0xffff;
- break;
- default:
- qemu_log_mask(LOG_UNIMP,
- "digic-timer: read access to unknown register 0x"
- TARGET_FMT_plx, offset);
- }
-
- return ret;
-}
-
-static void digic_timer_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- DigicTimerState *s = opaque;
-
- switch (offset) {
- case DIGIC_TIMER_CONTROL:
- if (value & DIGIC_TIMER_CONTROL_RST) {
- digic_timer_reset((DeviceState *)s);
- break;
- }
-
- if (value & DIGIC_TIMER_CONTROL_EN) {
- ptimer_run(s->ptimer, 0);
- }
-
- s->control = (uint32_t)value;
- break;
-
- case DIGIC_TIMER_RELVALUE:
- s->relvalue = extract32(value, 0, 16);
- ptimer_set_limit(s->ptimer, s->relvalue, 1);
- break;
-
- case DIGIC_TIMER_VALUE:
- break;
-
- default:
- qemu_log_mask(LOG_UNIMP,
- "digic-timer: read access to unknown register 0x"
- TARGET_FMT_plx, offset);
- }
-}
-
-static const MemoryRegionOps digic_timer_ops = {
- .read = digic_timer_read,
- .write = digic_timer_write,
- .impl = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void digic_timer_init(Object *obj)
-{
- DigicTimerState *s = DIGIC_TIMER(obj);
-
- s->ptimer = ptimer_init(NULL);
-
- /*
- * FIXME: there is no documentation on Digic timer
- * frequency setup so let it always run at 1 MHz
- */
- ptimer_set_freq(s->ptimer, 1 * 1000 * 1000);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &digic_timer_ops, s,
- TYPE_DIGIC_TIMER, 0x100);
- sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
-}
-
-static void digic_timer_class_init(ObjectClass *klass, void *class_data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->reset = digic_timer_reset;
- dc->vmsd = &vmstate_digic_timer;
-}
-
-static const TypeInfo digic_timer_info = {
- .name = TYPE_DIGIC_TIMER,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(DigicTimerState),
- .instance_init = digic_timer_init,
- .class_init = digic_timer_class_init,
-};
-
-static void digic_timer_register_type(void)
-{
- type_register_static(&digic_timer_info);
-}
-
-type_init(digic_timer_register_type)
diff --git a/qemu/hw/timer/ds1338.c b/qemu/hw/timer/ds1338.c
deleted file mode 100644
index 0112949e2..000000000
--- a/qemu/hw/timer/ds1338.c
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * MAXIM DS1338 I2C RTC+NVRAM
- *
- * Copyright (c) 2009 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "hw/i2c/i2c.h"
-#include "qemu/bcd.h"
-
-/* Size of NVRAM including both the user-accessible area and the
- * secondary register area.
- */
-#define NVRAM_SIZE 64
-
-/* Flags definitions */
-#define SECONDS_CH 0x80
-#define HOURS_12 0x40
-#define HOURS_PM 0x20
-#define CTRL_OSF 0x20
-
-#define TYPE_DS1338 "ds1338"
-#define DS1338(obj) OBJECT_CHECK(DS1338State, (obj), TYPE_DS1338)
-
-typedef struct DS1338State {
- I2CSlave parent_obj;
-
- int64_t offset;
- uint8_t wday_offset;
- uint8_t nvram[NVRAM_SIZE];
- int32_t ptr;
- bool addr_byte;
-} DS1338State;
-
-static const VMStateDescription vmstate_ds1338 = {
- .name = "ds1338",
- .version_id = 2,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_I2C_SLAVE(parent_obj, DS1338State),
- VMSTATE_INT64(offset, DS1338State),
- VMSTATE_UINT8_V(wday_offset, DS1338State, 2),
- VMSTATE_UINT8_ARRAY(nvram, DS1338State, NVRAM_SIZE),
- VMSTATE_INT32(ptr, DS1338State),
- VMSTATE_BOOL(addr_byte, DS1338State),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void capture_current_time(DS1338State *s)
-{
- /* Capture the current time into the secondary registers
- * which will be actually read by the data transfer operation.
- */
- struct tm now;
- qemu_get_timedate(&now, s->offset);
- s->nvram[0] = to_bcd(now.tm_sec);
- s->nvram[1] = to_bcd(now.tm_min);
- if (s->nvram[2] & HOURS_12) {
- int tmp = now.tm_hour;
- if (tmp % 12 == 0) {
- tmp += 12;
- }
- if (tmp <= 12) {
- s->nvram[2] = HOURS_12 | to_bcd(tmp);
- } else {
- s->nvram[2] = HOURS_12 | HOURS_PM | to_bcd(tmp - 12);
- }
- } else {
- s->nvram[2] = to_bcd(now.tm_hour);
- }
- s->nvram[3] = (now.tm_wday + s->wday_offset) % 7 + 1;
- s->nvram[4] = to_bcd(now.tm_mday);
- s->nvram[5] = to_bcd(now.tm_mon + 1);
- s->nvram[6] = to_bcd(now.tm_year - 100);
-}
-
-static void inc_regptr(DS1338State *s)
-{
- /* The register pointer wraps around after 0x3F; wraparound
- * causes the current time/date to be retransferred into
- * the secondary registers.
- */
- s->ptr = (s->ptr + 1) & (NVRAM_SIZE - 1);
- if (!s->ptr) {
- capture_current_time(s);
- }
-}
-
-static void ds1338_event(I2CSlave *i2c, enum i2c_event event)
-{
- DS1338State *s = DS1338(i2c);
-
- switch (event) {
- case I2C_START_RECV:
- /* In h/w, capture happens on any START condition, not just a
- * START_RECV, but there is no need to actually capture on
- * START_SEND, because the guest can't get at that data
- * without going through a START_RECV which would overwrite it.
- */
- capture_current_time(s);
- break;
- case I2C_START_SEND:
- s->addr_byte = true;
- break;
- default:
- break;
- }
-}
-
-static int ds1338_recv(I2CSlave *i2c)
-{
- DS1338State *s = DS1338(i2c);
- uint8_t res;
-
- res = s->nvram[s->ptr];
- inc_regptr(s);
- return res;
-}
-
-static int ds1338_send(I2CSlave *i2c, uint8_t data)
-{
- DS1338State *s = DS1338(i2c);
-
- if (s->addr_byte) {
- s->ptr = data & (NVRAM_SIZE - 1);
- s->addr_byte = false;
- return 0;
- }
- if (s->ptr < 7) {
- /* Time register. */
- struct tm now;
- qemu_get_timedate(&now, s->offset);
- switch(s->ptr) {
- case 0:
- /* TODO: Implement CH (stop) bit. */
- now.tm_sec = from_bcd(data & 0x7f);
- break;
- case 1:
- now.tm_min = from_bcd(data & 0x7f);
- break;
- case 2:
- if (data & HOURS_12) {
- int tmp = from_bcd(data & (HOURS_PM - 1));
- if (data & HOURS_PM) {
- tmp += 12;
- }
- if (tmp % 12 == 0) {
- tmp -= 12;
- }
- now.tm_hour = tmp;
- } else {
- now.tm_hour = from_bcd(data & (HOURS_12 - 1));
- }
- break;
- case 3:
- {
- /* The day field is supposed to contain a value in
- the range 1-7. Otherwise behavior is undefined.
- */
- int user_wday = (data & 7) - 1;
- s->wday_offset = (user_wday - now.tm_wday + 7) % 7;
- }
- break;
- case 4:
- now.tm_mday = from_bcd(data & 0x3f);
- break;
- case 5:
- now.tm_mon = from_bcd(data & 0x1f) - 1;
- break;
- case 6:
- now.tm_year = from_bcd(data) + 100;
- break;
- }
- s->offset = qemu_timedate_diff(&now);
- } else if (s->ptr == 7) {
- /* Control register. */
-
- /* Ensure bits 2, 3 and 6 will read back as zero. */
- data &= 0xB3;
-
- /* Attempting to write the OSF flag to logic 1 leaves the
- value unchanged. */
- data = (data & ~CTRL_OSF) | (data & s->nvram[s->ptr] & CTRL_OSF);
-
- s->nvram[s->ptr] = data;
- } else {
- s->nvram[s->ptr] = data;
- }
- inc_regptr(s);
- return 0;
-}
-
-static int ds1338_init(I2CSlave *i2c)
-{
- return 0;
-}
-
-static void ds1338_reset(DeviceState *dev)
-{
- DS1338State *s = DS1338(dev);
-
- /* The clock is running and synchronized with the host */
- s->offset = 0;
- s->wday_offset = 0;
- memset(s->nvram, 0, NVRAM_SIZE);
- s->ptr = 0;
- s->addr_byte = false;
-}
-
-static void ds1338_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
-
- k->init = ds1338_init;
- k->event = ds1338_event;
- k->recv = ds1338_recv;
- k->send = ds1338_send;
- dc->reset = ds1338_reset;
- dc->vmsd = &vmstate_ds1338;
-}
-
-static const TypeInfo ds1338_info = {
- .name = TYPE_DS1338,
- .parent = TYPE_I2C_SLAVE,
- .instance_size = sizeof(DS1338State),
- .class_init = ds1338_class_init,
-};
-
-static void ds1338_register_types(void)
-{
- type_register_static(&ds1338_info);
-}
-
-type_init(ds1338_register_types)
diff --git a/qemu/hw/timer/etraxfs_timer.c b/qemu/hw/timer/etraxfs_timer.c
deleted file mode 100644
index 36d8f462c..000000000
--- a/qemu/hw/timer/etraxfs_timer.c
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
- * QEMU ETRAX Timers
- *
- * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB.
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "sysemu/sysemu.h"
-#include "qemu/timer.h"
-#include "hw/ptimer.h"
-
-#define D(x)
-
-#define RW_TMR0_DIV 0x00
-#define R_TMR0_DATA 0x04
-#define RW_TMR0_CTRL 0x08
-#define RW_TMR1_DIV 0x10
-#define R_TMR1_DATA 0x14
-#define RW_TMR1_CTRL 0x18
-#define R_TIME 0x38
-#define RW_WD_CTRL 0x40
-#define R_WD_STAT 0x44
-#define RW_INTR_MASK 0x48
-#define RW_ACK_INTR 0x4c
-#define R_INTR 0x50
-#define R_MASKED_INTR 0x54
-
-#define TYPE_ETRAX_FS_TIMER "etraxfs,timer"
-#define ETRAX_TIMER(obj) \
- OBJECT_CHECK(ETRAXTimerState, (obj), TYPE_ETRAX_FS_TIMER)
-
-typedef struct ETRAXTimerState {
- SysBusDevice parent_obj;
-
- MemoryRegion mmio;
- qemu_irq irq;
- qemu_irq nmi;
-
- QEMUBH *bh_t0;
- QEMUBH *bh_t1;
- QEMUBH *bh_wd;
- ptimer_state *ptimer_t0;
- ptimer_state *ptimer_t1;
- ptimer_state *ptimer_wd;
-
- int wd_hits;
-
- /* Control registers. */
- uint32_t rw_tmr0_div;
- uint32_t r_tmr0_data;
- uint32_t rw_tmr0_ctrl;
-
- uint32_t rw_tmr1_div;
- uint32_t r_tmr1_data;
- uint32_t rw_tmr1_ctrl;
-
- uint32_t rw_wd_ctrl;
-
- uint32_t rw_intr_mask;
- uint32_t rw_ack_intr;
- uint32_t r_intr;
- uint32_t r_masked_intr;
-} ETRAXTimerState;
-
-static uint64_t
-timer_read(void *opaque, hwaddr addr, unsigned int size)
-{
- ETRAXTimerState *t = opaque;
- uint32_t r = 0;
-
- switch (addr) {
- case R_TMR0_DATA:
- r = ptimer_get_count(t->ptimer_t0);
- break;
- case R_TMR1_DATA:
- r = ptimer_get_count(t->ptimer_t1);
- break;
- case R_TIME:
- r = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / 10;
- break;
- case RW_INTR_MASK:
- r = t->rw_intr_mask;
- break;
- case R_MASKED_INTR:
- r = t->r_intr & t->rw_intr_mask;
- break;
- default:
- D(printf ("%s %x\n", __func__, addr));
- break;
- }
- return r;
-}
-
-static void update_ctrl(ETRAXTimerState *t, int tnum)
-{
- unsigned int op;
- unsigned int freq;
- unsigned int freq_hz;
- unsigned int div;
- uint32_t ctrl;
-
- ptimer_state *timer;
-
- if (tnum == 0) {
- ctrl = t->rw_tmr0_ctrl;
- div = t->rw_tmr0_div;
- timer = t->ptimer_t0;
- } else {
- ctrl = t->rw_tmr1_ctrl;
- div = t->rw_tmr1_div;
- timer = t->ptimer_t1;
- }
-
-
- op = ctrl & 3;
- freq = ctrl >> 2;
- freq_hz = 32000000;
-
- switch (freq)
- {
- case 0:
- case 1:
- D(printf ("extern or disabled timer clock?\n"));
- break;
- case 4: freq_hz = 29493000; break;
- case 5: freq_hz = 32000000; break;
- case 6: freq_hz = 32768000; break;
- case 7: freq_hz = 100000000; break;
- default:
- abort();
- break;
- }
-
- D(printf ("freq_hz=%d div=%d\n", freq_hz, div));
- ptimer_set_freq(timer, freq_hz);
- ptimer_set_limit(timer, div, 0);
-
- switch (op)
- {
- case 0:
- /* Load. */
- ptimer_set_limit(timer, div, 1);
- break;
- case 1:
- /* Hold. */
- ptimer_stop(timer);
- break;
- case 2:
- /* Run. */
- ptimer_run(timer, 0);
- break;
- default:
- abort();
- break;
- }
-}
-
-static void timer_update_irq(ETRAXTimerState *t)
-{
- t->r_intr &= ~(t->rw_ack_intr);
- t->r_masked_intr = t->r_intr & t->rw_intr_mask;
-
- D(printf("%s: masked_intr=%x\n", __func__, t->r_masked_intr));
- qemu_set_irq(t->irq, !!t->r_masked_intr);
-}
-
-static void timer0_hit(void *opaque)
-{
- ETRAXTimerState *t = opaque;
- t->r_intr |= 1;
- timer_update_irq(t);
-}
-
-static void timer1_hit(void *opaque)
-{
- ETRAXTimerState *t = opaque;
- t->r_intr |= 2;
- timer_update_irq(t);
-}
-
-static void watchdog_hit(void *opaque)
-{
- ETRAXTimerState *t = opaque;
- if (t->wd_hits == 0) {
- /* real hw gives a single tick before reseting but we are
- a bit friendlier to compensate for our slower execution. */
- ptimer_set_count(t->ptimer_wd, 10);
- ptimer_run(t->ptimer_wd, 1);
- qemu_irq_raise(t->nmi);
- }
- else
- qemu_system_reset_request();
-
- t->wd_hits++;
-}
-
-static inline void timer_watchdog_update(ETRAXTimerState *t, uint32_t value)
-{
- unsigned int wd_en = t->rw_wd_ctrl & (1 << 8);
- unsigned int wd_key = t->rw_wd_ctrl >> 9;
- unsigned int wd_cnt = t->rw_wd_ctrl & 511;
- unsigned int new_key = value >> 9 & ((1 << 7) - 1);
- unsigned int new_cmd = (value >> 8) & 1;
-
- /* If the watchdog is enabled, they written key must match the
- complement of the previous. */
- wd_key = ~wd_key & ((1 << 7) - 1);
-
- if (wd_en && wd_key != new_key)
- return;
-
- D(printf("en=%d new_key=%x oldkey=%x cmd=%d cnt=%d\n",
- wd_en, new_key, wd_key, new_cmd, wd_cnt));
-
- if (t->wd_hits)
- qemu_irq_lower(t->nmi);
-
- t->wd_hits = 0;
-
- ptimer_set_freq(t->ptimer_wd, 760);
- if (wd_cnt == 0)
- wd_cnt = 256;
- ptimer_set_count(t->ptimer_wd, wd_cnt);
- if (new_cmd)
- ptimer_run(t->ptimer_wd, 1);
- else
- ptimer_stop(t->ptimer_wd);
-
- t->rw_wd_ctrl = value;
-}
-
-static void
-timer_write(void *opaque, hwaddr addr,
- uint64_t val64, unsigned int size)
-{
- ETRAXTimerState *t = opaque;
- uint32_t value = val64;
-
- switch (addr)
- {
- case RW_TMR0_DIV:
- t->rw_tmr0_div = value;
- break;
- case RW_TMR0_CTRL:
- D(printf ("RW_TMR0_CTRL=%x\n", value));
- t->rw_tmr0_ctrl = value;
- update_ctrl(t, 0);
- break;
- case RW_TMR1_DIV:
- t->rw_tmr1_div = value;
- break;
- case RW_TMR1_CTRL:
- D(printf ("RW_TMR1_CTRL=%x\n", value));
- t->rw_tmr1_ctrl = value;
- update_ctrl(t, 1);
- break;
- case RW_INTR_MASK:
- D(printf ("RW_INTR_MASK=%x\n", value));
- t->rw_intr_mask = value;
- timer_update_irq(t);
- break;
- case RW_WD_CTRL:
- timer_watchdog_update(t, value);
- break;
- case RW_ACK_INTR:
- t->rw_ack_intr = value;
- timer_update_irq(t);
- t->rw_ack_intr = 0;
- break;
- default:
- printf ("%s " TARGET_FMT_plx " %x\n",
- __func__, addr, value);
- break;
- }
-}
-
-static const MemoryRegionOps timer_ops = {
- .read = timer_read,
- .write = timer_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4
- }
-};
-
-static void etraxfs_timer_reset(void *opaque)
-{
- ETRAXTimerState *t = opaque;
-
- ptimer_stop(t->ptimer_t0);
- ptimer_stop(t->ptimer_t1);
- ptimer_stop(t->ptimer_wd);
- t->rw_wd_ctrl = 0;
- t->r_intr = 0;
- t->rw_intr_mask = 0;
- qemu_irq_lower(t->irq);
-}
-
-static int etraxfs_timer_init(SysBusDevice *dev)
-{
- ETRAXTimerState *t = ETRAX_TIMER(dev);
-
- t->bh_t0 = qemu_bh_new(timer0_hit, t);
- t->bh_t1 = qemu_bh_new(timer1_hit, t);
- t->bh_wd = qemu_bh_new(watchdog_hit, t);
- t->ptimer_t0 = ptimer_init(t->bh_t0);
- t->ptimer_t1 = ptimer_init(t->bh_t1);
- t->ptimer_wd = ptimer_init(t->bh_wd);
-
- sysbus_init_irq(dev, &t->irq);
- sysbus_init_irq(dev, &t->nmi);
-
- memory_region_init_io(&t->mmio, OBJECT(t), &timer_ops, t,
- "etraxfs-timer", 0x5c);
- sysbus_init_mmio(dev, &t->mmio);
- qemu_register_reset(etraxfs_timer_reset, t);
- return 0;
-}
-
-static void etraxfs_timer_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
- sdc->init = etraxfs_timer_init;
-}
-
-static const TypeInfo etraxfs_timer_info = {
- .name = TYPE_ETRAX_FS_TIMER,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(ETRAXTimerState),
- .class_init = etraxfs_timer_class_init,
-};
-
-static void etraxfs_timer_register_types(void)
-{
- type_register_static(&etraxfs_timer_info);
-}
-
-type_init(etraxfs_timer_register_types)
diff --git a/qemu/hw/timer/exynos4210_mct.c b/qemu/hw/timer/exynos4210_mct.c
deleted file mode 100644
index ae69345f0..000000000
--- a/qemu/hw/timer/exynos4210_mct.c
+++ /dev/null
@@ -1,1480 +0,0 @@
-/*
- * Samsung exynos4210 Multi Core timer
- *
- * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
- * All rights reserved.
- *
- * Evgeny Voevodin <e.voevodin@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * Global Timer:
- *
- * Consists of two timers. First represents Free Running Counter and second
- * is used to measure interval from FRC to nearest comparator.
- *
- * 0 UINT64_MAX
- * | timer0 |
- * | <-------------------------------------------------------------- |
- * | --------------------------------------------frc---------------> |
- * |______________________________________________|__________________|
- * CMP0 CMP1 CMP2 | CMP3
- * __| |_
- * | timer1 |
- * | -------------> |
- * frc CMPx
- *
- * Problem: when implementing global timer as is, overflow arises.
- * next_time = cur_time + period * count;
- * period and count are 64 bits width.
- * Lets arm timer for MCT_GT_COUNTER_STEP count and update internal G_CNT
- * register during each event.
- *
- * Problem: both timers need to be implemented using MCT_XT_COUNTER_STEP because
- * local timer contains two counters: TCNT and ICNT. TCNT == 0 -> ICNT--.
- * IRQ is generated when ICNT riches zero. Implementation where TCNT == 0
- * generates IRQs suffers from too frequently events. Better to have one
- * uint64_t counter equal to TCNT*ICNT and arm ptimer.c for a minimum(TCNT*ICNT,
- * MCT_GT_COUNTER_STEP); (yes, if target tunes ICNT * TCNT to be too low values,
- * there is no way to avoid frequently events).
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "qemu/timer.h"
-#include "qemu/main-loop.h"
-#include "qemu-common.h"
-#include "hw/ptimer.h"
-
-#include "hw/arm/exynos4210.h"
-
-//#define DEBUG_MCT
-
-#ifdef DEBUG_MCT
-#define DPRINTF(fmt, ...) \
- do { fprintf(stdout, "MCT: [%24s:%5d] " fmt, __func__, __LINE__, \
- ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while (0)
-#endif
-
-#define MCT_CFG 0x000
-#define G_CNT_L 0x100
-#define G_CNT_U 0x104
-#define G_CNT_WSTAT 0x110
-#define G_COMP0_L 0x200
-#define G_COMP0_U 0x204
-#define G_COMP0_ADD_INCR 0x208
-#define G_COMP1_L 0x210
-#define G_COMP1_U 0x214
-#define G_COMP1_ADD_INCR 0x218
-#define G_COMP2_L 0x220
-#define G_COMP2_U 0x224
-#define G_COMP2_ADD_INCR 0x228
-#define G_COMP3_L 0x230
-#define G_COMP3_U 0x234
-#define G_COMP3_ADD_INCR 0x238
-#define G_TCON 0x240
-#define G_INT_CSTAT 0x244
-#define G_INT_ENB 0x248
-#define G_WSTAT 0x24C
-#define L0_TCNTB 0x300
-#define L0_TCNTO 0x304
-#define L0_ICNTB 0x308
-#define L0_ICNTO 0x30C
-#define L0_FRCNTB 0x310
-#define L0_FRCNTO 0x314
-#define L0_TCON 0x320
-#define L0_INT_CSTAT 0x330
-#define L0_INT_ENB 0x334
-#define L0_WSTAT 0x340
-#define L1_TCNTB 0x400
-#define L1_TCNTO 0x404
-#define L1_ICNTB 0x408
-#define L1_ICNTO 0x40C
-#define L1_FRCNTB 0x410
-#define L1_FRCNTO 0x414
-#define L1_TCON 0x420
-#define L1_INT_CSTAT 0x430
-#define L1_INT_ENB 0x434
-#define L1_WSTAT 0x440
-
-#define MCT_CFG_GET_PRESCALER(x) ((x) & 0xFF)
-#define MCT_CFG_GET_DIVIDER(x) (1 << ((x) >> 8 & 7))
-
-#define GET_G_COMP_IDX(offset) (((offset) - G_COMP0_L) / 0x10)
-#define GET_G_COMP_ADD_INCR_IDX(offset) (((offset) - G_COMP0_ADD_INCR) / 0x10)
-
-#define G_COMP_L(x) (G_COMP0_L + (x) * 0x10)
-#define G_COMP_U(x) (G_COMP0_U + (x) * 0x10)
-
-#define G_COMP_ADD_INCR(x) (G_COMP0_ADD_INCR + (x) * 0x10)
-
-/* MCT bits */
-#define G_TCON_COMP_ENABLE(x) (1 << 2 * (x))
-#define G_TCON_AUTO_ICREMENT(x) (1 << (2 * (x) + 1))
-#define G_TCON_TIMER_ENABLE (1 << 8)
-
-#define G_INT_ENABLE(x) (1 << (x))
-#define G_INT_CSTAT_COMP(x) (1 << (x))
-
-#define G_CNT_WSTAT_L 1
-#define G_CNT_WSTAT_U 2
-
-#define G_WSTAT_COMP_L(x) (1 << 4 * (x))
-#define G_WSTAT_COMP_U(x) (1 << ((4 * (x)) + 1))
-#define G_WSTAT_COMP_ADDINCR(x) (1 << ((4 * (x)) + 2))
-#define G_WSTAT_TCON_WRITE (1 << 16)
-
-#define GET_L_TIMER_IDX(offset) ((((offset) & 0xF00) - L0_TCNTB) / 0x100)
-#define GET_L_TIMER_CNT_REG_IDX(offset, lt_i) \
- (((offset) - (L0_TCNTB + 0x100 * (lt_i))) >> 2)
-
-#define L_ICNTB_MANUAL_UPDATE (1 << 31)
-
-#define L_TCON_TICK_START (1)
-#define L_TCON_INT_START (1 << 1)
-#define L_TCON_INTERVAL_MODE (1 << 2)
-#define L_TCON_FRC_START (1 << 3)
-
-#define L_INT_CSTAT_INTCNT (1 << 0)
-#define L_INT_CSTAT_FRCCNT (1 << 1)
-
-#define L_INT_INTENB_ICNTEIE (1 << 0)
-#define L_INT_INTENB_FRCEIE (1 << 1)
-
-#define L_WSTAT_TCNTB_WRITE (1 << 0)
-#define L_WSTAT_ICNTB_WRITE (1 << 1)
-#define L_WSTAT_FRCCNTB_WRITE (1 << 2)
-#define L_WSTAT_TCON_WRITE (1 << 3)
-
-enum LocalTimerRegCntIndexes {
- L_REG_CNT_TCNTB,
- L_REG_CNT_TCNTO,
- L_REG_CNT_ICNTB,
- L_REG_CNT_ICNTO,
- L_REG_CNT_FRCCNTB,
- L_REG_CNT_FRCCNTO,
-
- L_REG_CNT_AMOUNT
-};
-
-#define MCT_NIRQ 6
-#define MCT_SFR_SIZE 0x444
-
-#define MCT_GT_CMP_NUM 4
-
-#define MCT_GT_MAX_VAL UINT64_MAX
-
-#define MCT_GT_COUNTER_STEP 0x100000000ULL
-#define MCT_LT_COUNTER_STEP 0x100000000ULL
-#define MCT_LT_CNT_LOW_LIMIT 0x100
-
-/* global timer */
-typedef struct {
- qemu_irq irq[MCT_GT_CMP_NUM];
-
- struct gregs {
- uint64_t cnt;
- uint32_t cnt_wstat;
- uint32_t tcon;
- uint32_t int_cstat;
- uint32_t int_enb;
- uint32_t wstat;
- uint64_t comp[MCT_GT_CMP_NUM];
- uint32_t comp_add_incr[MCT_GT_CMP_NUM];
- } reg;
-
- uint64_t count; /* Value FRC was armed with */
- int32_t curr_comp; /* Current comparator FRC is running to */
-
- ptimer_state *ptimer_frc; /* FRC timer */
-
-} Exynos4210MCTGT;
-
-/* local timer */
-typedef struct {
- int id; /* timer id */
- qemu_irq irq; /* local timer irq */
-
- struct tick_timer {
- uint32_t cnt_run; /* cnt timer is running */
- uint32_t int_run; /* int timer is running */
-
- uint32_t last_icnto;
- uint32_t last_tcnto;
- uint32_t tcntb; /* initial value for TCNTB */
- uint32_t icntb; /* initial value for ICNTB */
-
- /* for step mode */
- uint64_t distance; /* distance to count to the next event */
- uint64_t progress; /* progress when counting by steps */
- uint64_t count; /* count to arm timer with */
-
- ptimer_state *ptimer_tick; /* timer for tick counter */
- } tick_timer;
-
- /* use ptimer.c to represent count down timer */
-
- ptimer_state *ptimer_frc; /* timer for free running counter */
-
- /* registers */
- struct lregs {
- uint32_t cnt[L_REG_CNT_AMOUNT];
- uint32_t tcon;
- uint32_t int_cstat;
- uint32_t int_enb;
- uint32_t wstat;
- } reg;
-
-} Exynos4210MCTLT;
-
-#define TYPE_EXYNOS4210_MCT "exynos4210.mct"
-#define EXYNOS4210_MCT(obj) \
- OBJECT_CHECK(Exynos4210MCTState, (obj), TYPE_EXYNOS4210_MCT)
-
-typedef struct Exynos4210MCTState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
-
- /* Registers */
- uint32_t reg_mct_cfg;
-
- Exynos4210MCTLT l_timer[2];
- Exynos4210MCTGT g_timer;
-
- uint32_t freq; /* all timers tick frequency, TCLK */
-} Exynos4210MCTState;
-
-/*** VMState ***/
-static const VMStateDescription vmstate_tick_timer = {
- .name = "exynos4210.mct.tick_timer",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(cnt_run, struct tick_timer),
- VMSTATE_UINT32(int_run, struct tick_timer),
- VMSTATE_UINT32(last_icnto, struct tick_timer),
- VMSTATE_UINT32(last_tcnto, struct tick_timer),
- VMSTATE_UINT32(tcntb, struct tick_timer),
- VMSTATE_UINT32(icntb, struct tick_timer),
- VMSTATE_UINT64(distance, struct tick_timer),
- VMSTATE_UINT64(progress, struct tick_timer),
- VMSTATE_UINT64(count, struct tick_timer),
- VMSTATE_PTIMER(ptimer_tick, struct tick_timer),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_lregs = {
- .name = "exynos4210.mct.lregs",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(cnt, struct lregs, L_REG_CNT_AMOUNT),
- VMSTATE_UINT32(tcon, struct lregs),
- VMSTATE_UINT32(int_cstat, struct lregs),
- VMSTATE_UINT32(int_enb, struct lregs),
- VMSTATE_UINT32(wstat, struct lregs),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_exynos4210_mct_lt = {
- .name = "exynos4210.mct.lt",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_INT32(id, Exynos4210MCTLT),
- VMSTATE_STRUCT(tick_timer, Exynos4210MCTLT, 0,
- vmstate_tick_timer,
- struct tick_timer),
- VMSTATE_PTIMER(ptimer_frc, Exynos4210MCTLT),
- VMSTATE_STRUCT(reg, Exynos4210MCTLT, 0,
- vmstate_lregs,
- struct lregs),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_gregs = {
- .name = "exynos4210.mct.lregs",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT64(cnt, struct gregs),
- VMSTATE_UINT32(cnt_wstat, struct gregs),
- VMSTATE_UINT32(tcon, struct gregs),
- VMSTATE_UINT32(int_cstat, struct gregs),
- VMSTATE_UINT32(int_enb, struct gregs),
- VMSTATE_UINT32(wstat, struct gregs),
- VMSTATE_UINT64_ARRAY(comp, struct gregs, MCT_GT_CMP_NUM),
- VMSTATE_UINT32_ARRAY(comp_add_incr, struct gregs,
- MCT_GT_CMP_NUM),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_exynos4210_mct_gt = {
- .name = "exynos4210.mct.lt",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT(reg, Exynos4210MCTGT, 0, vmstate_gregs,
- struct gregs),
- VMSTATE_UINT64(count, Exynos4210MCTGT),
- VMSTATE_INT32(curr_comp, Exynos4210MCTGT),
- VMSTATE_PTIMER(ptimer_frc, Exynos4210MCTGT),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_exynos4210_mct_state = {
- .name = "exynos4210.mct",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(reg_mct_cfg, Exynos4210MCTState),
- VMSTATE_STRUCT_ARRAY(l_timer, Exynos4210MCTState, 2, 0,
- vmstate_exynos4210_mct_lt, Exynos4210MCTLT),
- VMSTATE_STRUCT(g_timer, Exynos4210MCTState, 0,
- vmstate_exynos4210_mct_gt, Exynos4210MCTGT),
- VMSTATE_UINT32(freq, Exynos4210MCTState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void exynos4210_mct_update_freq(Exynos4210MCTState *s);
-
-/*
- * Set counter of FRC global timer.
- */
-static void exynos4210_gfrc_set_count(Exynos4210MCTGT *s, uint64_t count)
-{
- s->count = count;
- DPRINTF("global timer frc set count 0x%llx\n", count);
- ptimer_set_count(s->ptimer_frc, count);
-}
-
-/*
- * Get counter of FRC global timer.
- */
-static uint64_t exynos4210_gfrc_get_count(Exynos4210MCTGT *s)
-{
- uint64_t count = 0;
- count = ptimer_get_count(s->ptimer_frc);
- count = s->count - count;
- return s->reg.cnt + count;
-}
-
-/*
- * Stop global FRC timer
- */
-static void exynos4210_gfrc_stop(Exynos4210MCTGT *s)
-{
- DPRINTF("global timer frc stop\n");
-
- ptimer_stop(s->ptimer_frc);
-}
-
-/*
- * Start global FRC timer
- */
-static void exynos4210_gfrc_start(Exynos4210MCTGT *s)
-{
- DPRINTF("global timer frc start\n");
-
- ptimer_run(s->ptimer_frc, 1);
-}
-
-/*
- * Find next nearest Comparator. If current Comparator value equals to other
- * Comparator value, skip them both
- */
-static int32_t exynos4210_gcomp_find(Exynos4210MCTState *s)
-{
- int res;
- int i;
- int enabled;
- uint64_t min;
- int min_comp_i;
- uint64_t gfrc;
- uint64_t distance;
- uint64_t distance_min;
- int comp_i;
-
- /* get gfrc count */
- gfrc = exynos4210_gfrc_get_count(&s->g_timer);
-
- min = UINT64_MAX;
- distance_min = UINT64_MAX;
- comp_i = MCT_GT_CMP_NUM;
- min_comp_i = MCT_GT_CMP_NUM;
- enabled = 0;
-
- /* lookup for nearest comparator */
- for (i = 0; i < MCT_GT_CMP_NUM; i++) {
-
- if (s->g_timer.reg.tcon & G_TCON_COMP_ENABLE(i)) {
-
- enabled = 1;
-
- if (s->g_timer.reg.comp[i] > gfrc) {
- /* Comparator is upper then FRC */
- distance = s->g_timer.reg.comp[i] - gfrc;
-
- if (distance <= distance_min) {
- distance_min = distance;
- comp_i = i;
- }
- } else {
- /* Comparator is below FRC, find the smallest */
-
- if (s->g_timer.reg.comp[i] <= min) {
- min = s->g_timer.reg.comp[i];
- min_comp_i = i;
- }
- }
- }
- }
-
- if (!enabled) {
- /* All Comparators disabled */
- res = -1;
- } else if (comp_i < MCT_GT_CMP_NUM) {
- /* Found upper Comparator */
- res = comp_i;
- } else {
- /* All Comparators are below or equal to FRC */
- res = min_comp_i;
- }
-
- DPRINTF("found comparator %d: comp 0x%llx distance 0x%llx, gfrc 0x%llx\n",
- res,
- s->g_timer.reg.comp[res],
- distance_min,
- gfrc);
-
- return res;
-}
-
-/*
- * Get distance to nearest Comparator
- */
-static uint64_t exynos4210_gcomp_get_distance(Exynos4210MCTState *s, int32_t id)
-{
- if (id == -1) {
- /* no enabled Comparators, choose max distance */
- return MCT_GT_COUNTER_STEP;
- }
- if (s->g_timer.reg.comp[id] - s->g_timer.reg.cnt < MCT_GT_COUNTER_STEP) {
- return s->g_timer.reg.comp[id] - s->g_timer.reg.cnt;
- } else {
- return MCT_GT_COUNTER_STEP;
- }
-}
-
-/*
- * Restart global FRC timer
- */
-static void exynos4210_gfrc_restart(Exynos4210MCTState *s)
-{
- uint64_t distance;
-
- exynos4210_gfrc_stop(&s->g_timer);
-
- s->g_timer.curr_comp = exynos4210_gcomp_find(s);
-
- distance = exynos4210_gcomp_get_distance(s, s->g_timer.curr_comp);
-
- if (distance > MCT_GT_COUNTER_STEP || !distance) {
- distance = MCT_GT_COUNTER_STEP;
- }
-
- exynos4210_gfrc_set_count(&s->g_timer, distance);
- exynos4210_gfrc_start(&s->g_timer);
-}
-
-/*
- * Raise global timer CMP IRQ
- */
-static void exynos4210_gcomp_raise_irq(void *opaque, uint32_t id)
-{
- Exynos4210MCTGT *s = opaque;
-
- /* If CSTAT is pending and IRQ is enabled */
- if ((s->reg.int_cstat & G_INT_CSTAT_COMP(id)) &&
- (s->reg.int_enb & G_INT_ENABLE(id))) {
- DPRINTF("gcmp timer[%d] IRQ\n", id);
- qemu_irq_raise(s->irq[id]);
- }
-}
-
-/*
- * Lower global timer CMP IRQ
- */
-static void exynos4210_gcomp_lower_irq(void *opaque, uint32_t id)
-{
- Exynos4210MCTGT *s = opaque;
- qemu_irq_lower(s->irq[id]);
-}
-
-/*
- * Global timer FRC event handler.
- * Each event occurs when internal counter reaches counter + MCT_GT_COUNTER_STEP
- * Every time we arm global FRC timer to count for MCT_GT_COUNTER_STEP value
- */
-static void exynos4210_gfrc_event(void *opaque)
-{
- Exynos4210MCTState *s = (Exynos4210MCTState *)opaque;
- int i;
- uint64_t distance;
-
- DPRINTF("\n");
-
- s->g_timer.reg.cnt += s->g_timer.count;
-
- /* Process all comparators */
- for (i = 0; i < MCT_GT_CMP_NUM; i++) {
-
- if (s->g_timer.reg.cnt == s->g_timer.reg.comp[i]) {
- /* reached nearest comparator */
-
- s->g_timer.reg.int_cstat |= G_INT_CSTAT_COMP(i);
-
- /* Auto increment */
- if (s->g_timer.reg.tcon & G_TCON_AUTO_ICREMENT(i)) {
- s->g_timer.reg.comp[i] += s->g_timer.reg.comp_add_incr[i];
- }
-
- /* IRQ */
- exynos4210_gcomp_raise_irq(&s->g_timer, i);
- }
- }
-
- /* Reload FRC to reach nearest comparator */
- s->g_timer.curr_comp = exynos4210_gcomp_find(s);
- distance = exynos4210_gcomp_get_distance(s, s->g_timer.curr_comp);
- if (distance > MCT_GT_COUNTER_STEP || !distance) {
- distance = MCT_GT_COUNTER_STEP;
- }
- exynos4210_gfrc_set_count(&s->g_timer, distance);
-
- exynos4210_gfrc_start(&s->g_timer);
-}
-
-/*
- * Get counter of FRC local timer.
- */
-static uint64_t exynos4210_lfrc_get_count(Exynos4210MCTLT *s)
-{
- return ptimer_get_count(s->ptimer_frc);
-}
-
-/*
- * Set counter of FRC local timer.
- */
-static void exynos4210_lfrc_update_count(Exynos4210MCTLT *s)
-{
- if (!s->reg.cnt[L_REG_CNT_FRCCNTB]) {
- ptimer_set_count(s->ptimer_frc, MCT_LT_COUNTER_STEP);
- } else {
- ptimer_set_count(s->ptimer_frc, s->reg.cnt[L_REG_CNT_FRCCNTB]);
- }
-}
-
-/*
- * Start local FRC timer
- */
-static void exynos4210_lfrc_start(Exynos4210MCTLT *s)
-{
- ptimer_run(s->ptimer_frc, 1);
-}
-
-/*
- * Stop local FRC timer
- */
-static void exynos4210_lfrc_stop(Exynos4210MCTLT *s)
-{
- ptimer_stop(s->ptimer_frc);
-}
-
-/*
- * Local timer free running counter tick handler
- */
-static void exynos4210_lfrc_event(void *opaque)
-{
- Exynos4210MCTLT * s = (Exynos4210MCTLT *)opaque;
-
- /* local frc expired */
-
- DPRINTF("\n");
-
- s->reg.int_cstat |= L_INT_CSTAT_FRCCNT;
-
- /* update frc counter */
- exynos4210_lfrc_update_count(s);
-
- /* raise irq */
- if (s->reg.int_enb & L_INT_INTENB_FRCEIE) {
- qemu_irq_raise(s->irq);
- }
-
- /* we reached here, this means that timer is enabled */
- exynos4210_lfrc_start(s);
-}
-
-static uint32_t exynos4210_ltick_int_get_cnto(struct tick_timer *s);
-static uint32_t exynos4210_ltick_cnt_get_cnto(struct tick_timer *s);
-static void exynos4210_ltick_recalc_count(struct tick_timer *s);
-
-/*
- * Action on enabling local tick int timer
- */
-static void exynos4210_ltick_int_start(struct tick_timer *s)
-{
- if (!s->int_run) {
- s->int_run = 1;
- }
-}
-
-/*
- * Action on disabling local tick int timer
- */
-static void exynos4210_ltick_int_stop(struct tick_timer *s)
-{
- if (s->int_run) {
- s->last_icnto = exynos4210_ltick_int_get_cnto(s);
- s->int_run = 0;
- }
-}
-
-/*
- * Get count for INT timer
- */
-static uint32_t exynos4210_ltick_int_get_cnto(struct tick_timer *s)
-{
- uint32_t icnto;
- uint64_t remain;
- uint64_t count;
- uint64_t counted;
- uint64_t cur_progress;
-
- count = ptimer_get_count(s->ptimer_tick);
- if (count) {
- /* timer is still counting, called not from event */
- counted = s->count - ptimer_get_count(s->ptimer_tick);
- cur_progress = s->progress + counted;
- } else {
- /* timer expired earlier */
- cur_progress = s->progress;
- }
-
- remain = s->distance - cur_progress;
-
- if (!s->int_run) {
- /* INT is stopped. */
- icnto = s->last_icnto;
- } else {
- /* Both are counting */
- icnto = remain / s->tcntb;
- }
-
- return icnto;
-}
-
-/*
- * Start local tick cnt timer.
- */
-static void exynos4210_ltick_cnt_start(struct tick_timer *s)
-{
- if (!s->cnt_run) {
-
- exynos4210_ltick_recalc_count(s);
- ptimer_set_count(s->ptimer_tick, s->count);
- ptimer_run(s->ptimer_tick, 1);
-
- s->cnt_run = 1;
- }
-}
-
-/*
- * Stop local tick cnt timer.
- */
-static void exynos4210_ltick_cnt_stop(struct tick_timer *s)
-{
- if (s->cnt_run) {
-
- s->last_tcnto = exynos4210_ltick_cnt_get_cnto(s);
-
- if (s->int_run) {
- exynos4210_ltick_int_stop(s);
- }
-
- ptimer_stop(s->ptimer_tick);
-
- s->cnt_run = 0;
- }
-}
-
-/*
- * Get counter for CNT timer
- */
-static uint32_t exynos4210_ltick_cnt_get_cnto(struct tick_timer *s)
-{
- uint32_t tcnto;
- uint32_t icnto;
- uint64_t remain;
- uint64_t counted;
- uint64_t count;
- uint64_t cur_progress;
-
- count = ptimer_get_count(s->ptimer_tick);
- if (count) {
- /* timer is still counting, called not from event */
- counted = s->count - ptimer_get_count(s->ptimer_tick);
- cur_progress = s->progress + counted;
- } else {
- /* timer expired earlier */
- cur_progress = s->progress;
- }
-
- remain = s->distance - cur_progress;
-
- if (!s->cnt_run) {
- /* Both are stopped. */
- tcnto = s->last_tcnto;
- } else if (!s->int_run) {
- /* INT counter is stopped, progress is by CNT timer */
- tcnto = remain % s->tcntb;
- } else {
- /* Both are counting */
- icnto = remain / s->tcntb;
- if (icnto) {
- tcnto = remain % (icnto * s->tcntb);
- } else {
- tcnto = remain % s->tcntb;
- }
- }
-
- return tcnto;
-}
-
-/*
- * Set new values of counters for CNT and INT timers
- */
-static void exynos4210_ltick_set_cntb(struct tick_timer *s, uint32_t new_cnt,
- uint32_t new_int)
-{
- uint32_t cnt_stopped = 0;
- uint32_t int_stopped = 0;
-
- if (s->cnt_run) {
- exynos4210_ltick_cnt_stop(s);
- cnt_stopped = 1;
- }
-
- if (s->int_run) {
- exynos4210_ltick_int_stop(s);
- int_stopped = 1;
- }
-
- s->tcntb = new_cnt + 1;
- s->icntb = new_int + 1;
-
- if (cnt_stopped) {
- exynos4210_ltick_cnt_start(s);
- }
- if (int_stopped) {
- exynos4210_ltick_int_start(s);
- }
-
-}
-
-/*
- * Calculate new counter value for tick timer
- */
-static void exynos4210_ltick_recalc_count(struct tick_timer *s)
-{
- uint64_t to_count;
-
- if ((s->cnt_run && s->last_tcnto) || (s->int_run && s->last_icnto)) {
- /*
- * one or both timers run and not counted to the end;
- * distance is not passed, recalculate with last_tcnto * last_icnto
- */
-
- if (s->last_tcnto) {
- to_count = (uint64_t)s->last_tcnto * s->last_icnto;
- } else {
- to_count = s->last_icnto;
- }
- } else {
- /* distance is passed, recalculate with tcnto * icnto */
- if (s->icntb) {
- s->distance = (uint64_t)s->tcntb * s->icntb;
- } else {
- s->distance = s->tcntb;
- }
-
- to_count = s->distance;
- s->progress = 0;
- }
-
- if (to_count > MCT_LT_COUNTER_STEP) {
- /* count by step */
- s->count = MCT_LT_COUNTER_STEP;
- } else {
- s->count = to_count;
- }
-}
-
-/*
- * Initialize tick_timer
- */
-static void exynos4210_ltick_timer_init(struct tick_timer *s)
-{
- exynos4210_ltick_int_stop(s);
- exynos4210_ltick_cnt_stop(s);
-
- s->count = 0;
- s->distance = 0;
- s->progress = 0;
- s->icntb = 0;
- s->tcntb = 0;
-}
-
-/*
- * tick_timer event.
- * Raises when abstract tick_timer expires.
- */
-static void exynos4210_ltick_timer_event(struct tick_timer *s)
-{
- s->progress += s->count;
-}
-
-/*
- * Local timer tick counter handler.
- * Don't use reloaded timers. If timer counter = zero
- * then handler called but after handler finished no
- * timer reload occurs.
- */
-static void exynos4210_ltick_event(void *opaque)
-{
- Exynos4210MCTLT * s = (Exynos4210MCTLT *)opaque;
- uint32_t tcnto;
- uint32_t icnto;
-#ifdef DEBUG_MCT
- static uint64_t time1[2] = {0};
- static uint64_t time2[2] = {0};
-#endif
-
- /* Call tick_timer event handler, it will update its tcntb and icntb. */
- exynos4210_ltick_timer_event(&s->tick_timer);
-
- /* get tick_timer cnt */
- tcnto = exynos4210_ltick_cnt_get_cnto(&s->tick_timer);
-
- /* get tick_timer int */
- icnto = exynos4210_ltick_int_get_cnto(&s->tick_timer);
-
- /* raise IRQ if needed */
- if (!icnto && s->reg.tcon & L_TCON_INT_START) {
- /* INT counter enabled and expired */
-
- s->reg.int_cstat |= L_INT_CSTAT_INTCNT;
-
- /* raise interrupt if enabled */
- if (s->reg.int_enb & L_INT_INTENB_ICNTEIE) {
-#ifdef DEBUG_MCT
- time2[s->id] = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- DPRINTF("local timer[%d] IRQ: %llx\n", s->id,
- time2[s->id] - time1[s->id]);
- time1[s->id] = time2[s->id];
-#endif
- qemu_irq_raise(s->irq);
- }
-
- /* reload ICNTB */
- if (s->reg.tcon & L_TCON_INTERVAL_MODE) {
- exynos4210_ltick_set_cntb(&s->tick_timer,
- s->reg.cnt[L_REG_CNT_TCNTB],
- s->reg.cnt[L_REG_CNT_ICNTB]);
- }
- } else {
- /* reload TCNTB */
- if (!tcnto) {
- exynos4210_ltick_set_cntb(&s->tick_timer,
- s->reg.cnt[L_REG_CNT_TCNTB],
- icnto);
- }
- }
-
- /* start tick_timer cnt */
- exynos4210_ltick_cnt_start(&s->tick_timer);
-
- /* start tick_timer int */
- exynos4210_ltick_int_start(&s->tick_timer);
-}
-
-/* update timer frequency */
-static void exynos4210_mct_update_freq(Exynos4210MCTState *s)
-{
- uint32_t freq = s->freq;
- s->freq = 24000000 /
- ((MCT_CFG_GET_PRESCALER(s->reg_mct_cfg)+1) *
- MCT_CFG_GET_DIVIDER(s->reg_mct_cfg));
-
- if (freq != s->freq) {
- DPRINTF("freq=%dHz\n", s->freq);
-
- /* global timer */
- ptimer_set_freq(s->g_timer.ptimer_frc, s->freq);
-
- /* local timer */
- ptimer_set_freq(s->l_timer[0].tick_timer.ptimer_tick, s->freq);
- ptimer_set_freq(s->l_timer[0].ptimer_frc, s->freq);
- ptimer_set_freq(s->l_timer[1].tick_timer.ptimer_tick, s->freq);
- ptimer_set_freq(s->l_timer[1].ptimer_frc, s->freq);
- }
-}
-
-/* set defaul_timer values for all fields */
-static void exynos4210_mct_reset(DeviceState *d)
-{
- Exynos4210MCTState *s = EXYNOS4210_MCT(d);
- uint32_t i;
-
- s->reg_mct_cfg = 0;
-
- /* global timer */
- memset(&s->g_timer.reg, 0, sizeof(s->g_timer.reg));
- exynos4210_gfrc_stop(&s->g_timer);
-
- /* local timer */
- memset(s->l_timer[0].reg.cnt, 0, sizeof(s->l_timer[0].reg.cnt));
- memset(s->l_timer[1].reg.cnt, 0, sizeof(s->l_timer[1].reg.cnt));
- for (i = 0; i < 2; i++) {
- s->l_timer[i].reg.int_cstat = 0;
- s->l_timer[i].reg.int_enb = 0;
- s->l_timer[i].reg.tcon = 0;
- s->l_timer[i].reg.wstat = 0;
- s->l_timer[i].tick_timer.count = 0;
- s->l_timer[i].tick_timer.distance = 0;
- s->l_timer[i].tick_timer.progress = 0;
- ptimer_stop(s->l_timer[i].ptimer_frc);
-
- exynos4210_ltick_timer_init(&s->l_timer[i].tick_timer);
- }
-
- exynos4210_mct_update_freq(s);
-
-}
-
-/* Multi Core Timer read */
-static uint64_t exynos4210_mct_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- Exynos4210MCTState *s = (Exynos4210MCTState *)opaque;
- int index;
- int shift;
- uint64_t count;
- uint32_t value;
- int lt_i;
-
- switch (offset) {
-
- case MCT_CFG:
- value = s->reg_mct_cfg;
- break;
-
- case G_CNT_L: case G_CNT_U:
- shift = 8 * (offset & 0x4);
- count = exynos4210_gfrc_get_count(&s->g_timer);
- value = UINT32_MAX & (count >> shift);
- DPRINTF("read FRC=0x%llx\n", count);
- break;
-
- case G_CNT_WSTAT:
- value = s->g_timer.reg.cnt_wstat;
- break;
-
- case G_COMP_L(0): case G_COMP_L(1): case G_COMP_L(2): case G_COMP_L(3):
- case G_COMP_U(0): case G_COMP_U(1): case G_COMP_U(2): case G_COMP_U(3):
- index = GET_G_COMP_IDX(offset);
- shift = 8 * (offset & 0x4);
- value = UINT32_MAX & (s->g_timer.reg.comp[index] >> shift);
- break;
-
- case G_TCON:
- value = s->g_timer.reg.tcon;
- break;
-
- case G_INT_CSTAT:
- value = s->g_timer.reg.int_cstat;
- break;
-
- case G_INT_ENB:
- value = s->g_timer.reg.int_enb;
- break;
- case G_WSTAT:
- value = s->g_timer.reg.wstat;
- break;
-
- case G_COMP0_ADD_INCR: case G_COMP1_ADD_INCR:
- case G_COMP2_ADD_INCR: case G_COMP3_ADD_INCR:
- value = s->g_timer.reg.comp_add_incr[GET_G_COMP_ADD_INCR_IDX(offset)];
- break;
-
- /* Local timers */
- case L0_TCNTB: case L0_ICNTB: case L0_FRCNTB:
- case L1_TCNTB: case L1_ICNTB: case L1_FRCNTB:
- lt_i = GET_L_TIMER_IDX(offset);
- index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i);
- value = s->l_timer[lt_i].reg.cnt[index];
- break;
-
- case L0_TCNTO: case L1_TCNTO:
- lt_i = GET_L_TIMER_IDX(offset);
-
- value = exynos4210_ltick_cnt_get_cnto(&s->l_timer[lt_i].tick_timer);
- DPRINTF("local timer[%d] read TCNTO %x\n", lt_i, value);
- break;
-
- case L0_ICNTO: case L1_ICNTO:
- lt_i = GET_L_TIMER_IDX(offset);
-
- value = exynos4210_ltick_int_get_cnto(&s->l_timer[lt_i].tick_timer);
- DPRINTF("local timer[%d] read ICNTO %x\n", lt_i, value);
- break;
-
- case L0_FRCNTO: case L1_FRCNTO:
- lt_i = GET_L_TIMER_IDX(offset);
-
- value = exynos4210_lfrc_get_count(&s->l_timer[lt_i]);
-
- break;
-
- case L0_TCON: case L1_TCON:
- lt_i = ((offset & 0xF00) - L0_TCNTB) / 0x100;
- value = s->l_timer[lt_i].reg.tcon;
- break;
-
- case L0_INT_CSTAT: case L1_INT_CSTAT:
- lt_i = ((offset & 0xF00) - L0_TCNTB) / 0x100;
- value = s->l_timer[lt_i].reg.int_cstat;
- break;
-
- case L0_INT_ENB: case L1_INT_ENB:
- lt_i = ((offset & 0xF00) - L0_TCNTB) / 0x100;
- value = s->l_timer[lt_i].reg.int_enb;
- break;
-
- case L0_WSTAT: case L1_WSTAT:
- lt_i = ((offset & 0xF00) - L0_TCNTB) / 0x100;
- value = s->l_timer[lt_i].reg.wstat;
- break;
-
- default:
- hw_error("exynos4210.mct: bad read offset "
- TARGET_FMT_plx "\n", offset);
- break;
- }
- return value;
-}
-
-/* MCT write */
-static void exynos4210_mct_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- Exynos4210MCTState *s = (Exynos4210MCTState *)opaque;
- int index; /* index in buffer which represents register set */
- int shift;
- int lt_i;
- uint64_t new_frc;
- uint32_t i;
- uint32_t old_val;
-#ifdef DEBUG_MCT
- static uint32_t icntb_max[2] = {0};
- static uint32_t icntb_min[2] = {UINT32_MAX, UINT32_MAX};
- static uint32_t tcntb_max[2] = {0};
- static uint32_t tcntb_min[2] = {UINT32_MAX, UINT32_MAX};
-#endif
-
- new_frc = s->g_timer.reg.cnt;
-
- switch (offset) {
-
- case MCT_CFG:
- s->reg_mct_cfg = value;
- exynos4210_mct_update_freq(s);
- break;
-
- case G_CNT_L:
- case G_CNT_U:
- if (offset == G_CNT_L) {
-
- DPRINTF("global timer write to reg.cntl %llx\n", value);
-
- new_frc = (s->g_timer.reg.cnt & (uint64_t)UINT32_MAX << 32) + value;
- s->g_timer.reg.cnt_wstat |= G_CNT_WSTAT_L;
- }
- if (offset == G_CNT_U) {
-
- DPRINTF("global timer write to reg.cntu %llx\n", value);
-
- new_frc = (s->g_timer.reg.cnt & UINT32_MAX) +
- ((uint64_t)value << 32);
- s->g_timer.reg.cnt_wstat |= G_CNT_WSTAT_U;
- }
-
- s->g_timer.reg.cnt = new_frc;
- exynos4210_gfrc_restart(s);
- break;
-
- case G_CNT_WSTAT:
- s->g_timer.reg.cnt_wstat &= ~(value);
- break;
-
- case G_COMP_L(0): case G_COMP_L(1): case G_COMP_L(2): case G_COMP_L(3):
- case G_COMP_U(0): case G_COMP_U(1): case G_COMP_U(2): case G_COMP_U(3):
- index = GET_G_COMP_IDX(offset);
- shift = 8 * (offset & 0x4);
- s->g_timer.reg.comp[index] =
- (s->g_timer.reg.comp[index] &
- (((uint64_t)UINT32_MAX << 32) >> shift)) +
- (value << shift);
-
- DPRINTF("comparator %d write 0x%llx val << %d\n", index, value, shift);
-
- if (offset&0x4) {
- s->g_timer.reg.wstat |= G_WSTAT_COMP_U(index);
- } else {
- s->g_timer.reg.wstat |= G_WSTAT_COMP_L(index);
- }
-
- exynos4210_gfrc_restart(s);
- break;
-
- case G_TCON:
- old_val = s->g_timer.reg.tcon;
- s->g_timer.reg.tcon = value;
- s->g_timer.reg.wstat |= G_WSTAT_TCON_WRITE;
-
- DPRINTF("global timer write to reg.g_tcon %llx\n", value);
-
- /* Start FRC if transition from disabled to enabled */
- if ((value & G_TCON_TIMER_ENABLE) > (old_val &
- G_TCON_TIMER_ENABLE)) {
- exynos4210_gfrc_start(&s->g_timer);
- }
- if ((value & G_TCON_TIMER_ENABLE) < (old_val &
- G_TCON_TIMER_ENABLE)) {
- exynos4210_gfrc_stop(&s->g_timer);
- }
-
- /* Start CMP if transition from disabled to enabled */
- for (i = 0; i < MCT_GT_CMP_NUM; i++) {
- if ((value & G_TCON_COMP_ENABLE(i)) != (old_val &
- G_TCON_COMP_ENABLE(i))) {
- exynos4210_gfrc_restart(s);
- }
- }
- break;
-
- case G_INT_CSTAT:
- s->g_timer.reg.int_cstat &= ~(value);
- for (i = 0; i < MCT_GT_CMP_NUM; i++) {
- if (value & G_INT_CSTAT_COMP(i)) {
- exynos4210_gcomp_lower_irq(&s->g_timer, i);
- }
- }
- break;
-
- case G_INT_ENB:
-
- /* Raise IRQ if transition from disabled to enabled and CSTAT pending */
- for (i = 0; i < MCT_GT_CMP_NUM; i++) {
- if ((value & G_INT_ENABLE(i)) > (s->g_timer.reg.tcon &
- G_INT_ENABLE(i))) {
- if (s->g_timer.reg.int_cstat & G_INT_CSTAT_COMP(i)) {
- exynos4210_gcomp_raise_irq(&s->g_timer, i);
- }
- }
-
- if ((value & G_INT_ENABLE(i)) < (s->g_timer.reg.tcon &
- G_INT_ENABLE(i))) {
- exynos4210_gcomp_lower_irq(&s->g_timer, i);
- }
- }
-
- DPRINTF("global timer INT enable %llx\n", value);
- s->g_timer.reg.int_enb = value;
- break;
-
- case G_WSTAT:
- s->g_timer.reg.wstat &= ~(value);
- break;
-
- case G_COMP0_ADD_INCR: case G_COMP1_ADD_INCR:
- case G_COMP2_ADD_INCR: case G_COMP3_ADD_INCR:
- index = GET_G_COMP_ADD_INCR_IDX(offset);
- s->g_timer.reg.comp_add_incr[index] = value;
- s->g_timer.reg.wstat |= G_WSTAT_COMP_ADDINCR(index);
- break;
-
- /* Local timers */
- case L0_TCON: case L1_TCON:
- lt_i = GET_L_TIMER_IDX(offset);
- old_val = s->l_timer[lt_i].reg.tcon;
-
- s->l_timer[lt_i].reg.wstat |= L_WSTAT_TCON_WRITE;
- s->l_timer[lt_i].reg.tcon = value;
-
- /* Stop local CNT */
- if ((value & L_TCON_TICK_START) <
- (old_val & L_TCON_TICK_START)) {
- DPRINTF("local timer[%d] stop cnt\n", lt_i);
- exynos4210_ltick_cnt_stop(&s->l_timer[lt_i].tick_timer);
- }
-
- /* Stop local INT */
- if ((value & L_TCON_INT_START) <
- (old_val & L_TCON_INT_START)) {
- DPRINTF("local timer[%d] stop int\n", lt_i);
- exynos4210_ltick_int_stop(&s->l_timer[lt_i].tick_timer);
- }
-
- /* Start local CNT */
- if ((value & L_TCON_TICK_START) >
- (old_val & L_TCON_TICK_START)) {
- DPRINTF("local timer[%d] start cnt\n", lt_i);
- exynos4210_ltick_cnt_start(&s->l_timer[lt_i].tick_timer);
- }
-
- /* Start local INT */
- if ((value & L_TCON_INT_START) >
- (old_val & L_TCON_INT_START)) {
- DPRINTF("local timer[%d] start int\n", lt_i);
- exynos4210_ltick_int_start(&s->l_timer[lt_i].tick_timer);
- }
-
- /* Start or Stop local FRC if TCON changed */
- if ((value & L_TCON_FRC_START) >
- (s->l_timer[lt_i].reg.tcon & L_TCON_FRC_START)) {
- DPRINTF("local timer[%d] start frc\n", lt_i);
- exynos4210_lfrc_start(&s->l_timer[lt_i]);
- }
- if ((value & L_TCON_FRC_START) <
- (s->l_timer[lt_i].reg.tcon & L_TCON_FRC_START)) {
- DPRINTF("local timer[%d] stop frc\n", lt_i);
- exynos4210_lfrc_stop(&s->l_timer[lt_i]);
- }
- break;
-
- case L0_TCNTB: case L1_TCNTB:
-
- lt_i = GET_L_TIMER_IDX(offset);
- index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i);
-
- /*
- * TCNTB is updated to internal register only after CNT expired.
- * Due to this we should reload timer to nearest moment when CNT is
- * expired and then in event handler update tcntb to new TCNTB value.
- */
- exynos4210_ltick_set_cntb(&s->l_timer[lt_i].tick_timer, value,
- s->l_timer[lt_i].tick_timer.icntb);
-
- s->l_timer[lt_i].reg.wstat |= L_WSTAT_TCNTB_WRITE;
- s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB] = value;
-
-#ifdef DEBUG_MCT
- if (tcntb_min[lt_i] > value) {
- tcntb_min[lt_i] = value;
- }
- if (tcntb_max[lt_i] < value) {
- tcntb_max[lt_i] = value;
- }
- DPRINTF("local timer[%d] TCNTB write %llx; max=%x, min=%x\n",
- lt_i, value, tcntb_max[lt_i], tcntb_min[lt_i]);
-#endif
- break;
-
- case L0_ICNTB: case L1_ICNTB:
-
- lt_i = GET_L_TIMER_IDX(offset);
- index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i);
-
- s->l_timer[lt_i].reg.wstat |= L_WSTAT_ICNTB_WRITE;
- s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] = value &
- ~L_ICNTB_MANUAL_UPDATE;
-
- /*
- * We need to avoid too small values for TCNTB*ICNTB. If not, IRQ event
- * could raise too fast disallowing QEMU to execute target code.
- */
- if (s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] *
- s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB] < MCT_LT_CNT_LOW_LIMIT) {
- if (!s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB]) {
- s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] =
- MCT_LT_CNT_LOW_LIMIT;
- } else {
- s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] =
- MCT_LT_CNT_LOW_LIMIT /
- s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB];
- }
- }
-
- if (value & L_ICNTB_MANUAL_UPDATE) {
- exynos4210_ltick_set_cntb(&s->l_timer[lt_i].tick_timer,
- s->l_timer[lt_i].tick_timer.tcntb,
- s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB]);
- }
-
-#ifdef DEBUG_MCT
- if (icntb_min[lt_i] > value) {
- icntb_min[lt_i] = value;
- }
- if (icntb_max[lt_i] < value) {
- icntb_max[lt_i] = value;
- }
-DPRINTF("local timer[%d] ICNTB write %llx; max=%x, min=%x\n\n",
- lt_i, value, icntb_max[lt_i], icntb_min[lt_i]);
-#endif
-break;
-
- case L0_FRCNTB: case L1_FRCNTB:
-
- lt_i = GET_L_TIMER_IDX(offset);
- index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i);
-
- DPRINTF("local timer[%d] FRCNTB write %llx\n", lt_i, value);
-
- s->l_timer[lt_i].reg.wstat |= L_WSTAT_FRCCNTB_WRITE;
- s->l_timer[lt_i].reg.cnt[L_REG_CNT_FRCCNTB] = value;
-
- break;
-
- case L0_TCNTO: case L1_TCNTO:
- case L0_ICNTO: case L1_ICNTO:
- case L0_FRCNTO: case L1_FRCNTO:
- fprintf(stderr, "\n[exynos4210.mct: write to RO register "
- TARGET_FMT_plx "]\n\n", offset);
- break;
-
- case L0_INT_CSTAT: case L1_INT_CSTAT:
- lt_i = GET_L_TIMER_IDX(offset);
-
- DPRINTF("local timer[%d] CSTAT write %llx\n", lt_i, value);
-
- s->l_timer[lt_i].reg.int_cstat &= ~value;
- if (!s->l_timer[lt_i].reg.int_cstat) {
- qemu_irq_lower(s->l_timer[lt_i].irq);
- }
- break;
-
- case L0_INT_ENB: case L1_INT_ENB:
- lt_i = GET_L_TIMER_IDX(offset);
- old_val = s->l_timer[lt_i].reg.int_enb;
-
- /* Raise Local timer IRQ if cstat is pending */
- if ((value & L_INT_INTENB_ICNTEIE) > (old_val & L_INT_INTENB_ICNTEIE)) {
- if (s->l_timer[lt_i].reg.int_cstat & L_INT_CSTAT_INTCNT) {
- qemu_irq_raise(s->l_timer[lt_i].irq);
- }
- }
-
- s->l_timer[lt_i].reg.int_enb = value;
-
- break;
-
- case L0_WSTAT: case L1_WSTAT:
- lt_i = GET_L_TIMER_IDX(offset);
-
- s->l_timer[lt_i].reg.wstat &= ~value;
- break;
-
- default:
- hw_error("exynos4210.mct: bad write offset "
- TARGET_FMT_plx "\n", offset);
- break;
- }
-}
-
-static const MemoryRegionOps exynos4210_mct_ops = {
- .read = exynos4210_mct_read,
- .write = exynos4210_mct_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-/* MCT init */
-static void exynos4210_mct_init(Object *obj)
-{
- int i;
- Exynos4210MCTState *s = EXYNOS4210_MCT(obj);
- SysBusDevice *dev = SYS_BUS_DEVICE(obj);
- QEMUBH *bh[2];
-
- /* Global timer */
- bh[0] = qemu_bh_new(exynos4210_gfrc_event, s);
- s->g_timer.ptimer_frc = ptimer_init(bh[0]);
- memset(&s->g_timer.reg, 0, sizeof(struct gregs));
-
- /* Local timers */
- for (i = 0; i < 2; i++) {
- bh[0] = qemu_bh_new(exynos4210_ltick_event, &s->l_timer[i]);
- bh[1] = qemu_bh_new(exynos4210_lfrc_event, &s->l_timer[i]);
- s->l_timer[i].tick_timer.ptimer_tick = ptimer_init(bh[0]);
- s->l_timer[i].ptimer_frc = ptimer_init(bh[1]);
- s->l_timer[i].id = i;
- }
-
- /* IRQs */
- for (i = 0; i < MCT_GT_CMP_NUM; i++) {
- sysbus_init_irq(dev, &s->g_timer.irq[i]);
- }
- for (i = 0; i < 2; i++) {
- sysbus_init_irq(dev, &s->l_timer[i].irq);
- }
-
- memory_region_init_io(&s->iomem, obj, &exynos4210_mct_ops, s,
- "exynos4210-mct", MCT_SFR_SIZE);
- sysbus_init_mmio(dev, &s->iomem);
-}
-
-static void exynos4210_mct_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->reset = exynos4210_mct_reset;
- dc->vmsd = &vmstate_exynos4210_mct_state;
-}
-
-static const TypeInfo exynos4210_mct_info = {
- .name = TYPE_EXYNOS4210_MCT,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(Exynos4210MCTState),
- .instance_init = exynos4210_mct_init,
- .class_init = exynos4210_mct_class_init,
-};
-
-static void exynos4210_mct_register_types(void)
-{
- type_register_static(&exynos4210_mct_info);
-}
-
-type_init(exynos4210_mct_register_types)
diff --git a/qemu/hw/timer/exynos4210_pwm.c b/qemu/hw/timer/exynos4210_pwm.c
deleted file mode 100644
index 0e9e2e9bf..000000000
--- a/qemu/hw/timer/exynos4210_pwm.c
+++ /dev/null
@@ -1,424 +0,0 @@
-/*
- * Samsung exynos4210 Pulse Width Modulation Timer
- *
- * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
- * All rights reserved.
- *
- * Evgeny Voevodin <e.voevodin@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "qemu/timer.h"
-#include "qemu-common.h"
-#include "qemu/main-loop.h"
-#include "hw/ptimer.h"
-
-#include "hw/arm/exynos4210.h"
-
-//#define DEBUG_PWM
-
-#ifdef DEBUG_PWM
-#define DPRINTF(fmt, ...) \
- do { fprintf(stdout, "PWM: [%24s:%5d] " fmt, __func__, __LINE__, \
- ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while (0)
-#endif
-
-#define EXYNOS4210_PWM_TIMERS_NUM 5
-#define EXYNOS4210_PWM_REG_MEM_SIZE 0x50
-
-#define TCFG0 0x0000
-#define TCFG1 0x0004
-#define TCON 0x0008
-#define TCNTB0 0x000C
-#define TCMPB0 0x0010
-#define TCNTO0 0x0014
-#define TCNTB1 0x0018
-#define TCMPB1 0x001C
-#define TCNTO1 0x0020
-#define TCNTB2 0x0024
-#define TCMPB2 0x0028
-#define TCNTO2 0x002C
-#define TCNTB3 0x0030
-#define TCMPB3 0x0034
-#define TCNTO3 0x0038
-#define TCNTB4 0x003C
-#define TCNTO4 0x0040
-#define TINT_CSTAT 0x0044
-
-#define TCNTB(x) (0xC * (x))
-#define TCMPB(x) (0xC * (x) + 1)
-#define TCNTO(x) (0xC * (x) + 2)
-
-#define GET_PRESCALER(reg, x) (((reg) & (0xFF << (8 * (x)))) >> 8 * (x))
-#define GET_DIVIDER(reg, x) (1 << (((reg) & (0xF << (4 * (x)))) >> (4 * (x))))
-
-/*
- * Attention! Timer4 doesn't have OUTPUT_INVERTER,
- * so Auto Reload bit is not accessible by macros!
- */
-#define TCON_TIMER_BASE(x) (((x) ? 1 : 0) * 4 + 4 * (x))
-#define TCON_TIMER_START(x) (1 << (TCON_TIMER_BASE(x) + 0))
-#define TCON_TIMER_MANUAL_UPD(x) (1 << (TCON_TIMER_BASE(x) + 1))
-#define TCON_TIMER_OUTPUT_INV(x) (1 << (TCON_TIMER_BASE(x) + 2))
-#define TCON_TIMER_AUTO_RELOAD(x) (1 << (TCON_TIMER_BASE(x) + 3))
-#define TCON_TIMER4_AUTO_RELOAD (1 << 22)
-
-#define TINT_CSTAT_STATUS(x) (1 << (5 + (x)))
-#define TINT_CSTAT_ENABLE(x) (1 << (x))
-
-/* timer struct */
-typedef struct {
- uint32_t id; /* timer id */
- qemu_irq irq; /* local timer irq */
- uint32_t freq; /* timer frequency */
-
- /* use ptimer.c to represent count down timer */
- ptimer_state *ptimer; /* timer */
-
- /* registers */
- uint32_t reg_tcntb; /* counter register buffer */
- uint32_t reg_tcmpb; /* compare register buffer */
-
- struct Exynos4210PWMState *parent;
-
-} Exynos4210PWM;
-
-#define TYPE_EXYNOS4210_PWM "exynos4210.pwm"
-#define EXYNOS4210_PWM(obj) \
- OBJECT_CHECK(Exynos4210PWMState, (obj), TYPE_EXYNOS4210_PWM)
-
-typedef struct Exynos4210PWMState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
-
- uint32_t reg_tcfg[2];
- uint32_t reg_tcon;
- uint32_t reg_tint_cstat;
-
- Exynos4210PWM timer[EXYNOS4210_PWM_TIMERS_NUM];
-
-} Exynos4210PWMState;
-
-/*** VMState ***/
-static const VMStateDescription vmstate_exynos4210_pwm = {
- .name = "exynos4210.pwm.pwm",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(id, Exynos4210PWM),
- VMSTATE_UINT32(freq, Exynos4210PWM),
- VMSTATE_PTIMER(ptimer, Exynos4210PWM),
- VMSTATE_UINT32(reg_tcntb, Exynos4210PWM),
- VMSTATE_UINT32(reg_tcmpb, Exynos4210PWM),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_exynos4210_pwm_state = {
- .name = "exynos4210.pwm",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(reg_tcfg, Exynos4210PWMState, 2),
- VMSTATE_UINT32(reg_tcon, Exynos4210PWMState),
- VMSTATE_UINT32(reg_tint_cstat, Exynos4210PWMState),
- VMSTATE_STRUCT_ARRAY(timer, Exynos4210PWMState,
- EXYNOS4210_PWM_TIMERS_NUM, 0,
- vmstate_exynos4210_pwm, Exynos4210PWM),
- VMSTATE_END_OF_LIST()
- }
-};
-
-/*
- * PWM update frequency
- */
-static void exynos4210_pwm_update_freq(Exynos4210PWMState *s, uint32_t id)
-{
- uint32_t freq;
- freq = s->timer[id].freq;
- if (id > 1) {
- s->timer[id].freq = 24000000 /
- ((GET_PRESCALER(s->reg_tcfg[0], 1) + 1) *
- (GET_DIVIDER(s->reg_tcfg[1], id)));
- } else {
- s->timer[id].freq = 24000000 /
- ((GET_PRESCALER(s->reg_tcfg[0], 0) + 1) *
- (GET_DIVIDER(s->reg_tcfg[1], id)));
- }
-
- if (freq != s->timer[id].freq) {
- ptimer_set_freq(s->timer[id].ptimer, s->timer[id].freq);
- DPRINTF("freq=%dHz\n", s->timer[id].freq);
- }
-}
-
-/*
- * Counter tick handler
- */
-static void exynos4210_pwm_tick(void *opaque)
-{
- Exynos4210PWM *s = (Exynos4210PWM *)opaque;
- Exynos4210PWMState *p = (Exynos4210PWMState *)s->parent;
- uint32_t id = s->id;
- bool cmp;
-
- DPRINTF("timer %d tick\n", id);
-
- /* set irq status */
- p->reg_tint_cstat |= TINT_CSTAT_STATUS(id);
-
- /* raise IRQ */
- if (p->reg_tint_cstat & TINT_CSTAT_ENABLE(id)) {
- DPRINTF("timer %d IRQ\n", id);
- qemu_irq_raise(p->timer[id].irq);
- }
-
- /* reload timer */
- if (id != 4) {
- cmp = p->reg_tcon & TCON_TIMER_AUTO_RELOAD(id);
- } else {
- cmp = p->reg_tcon & TCON_TIMER4_AUTO_RELOAD;
- }
-
- if (cmp) {
- DPRINTF("auto reload timer %d count to %x\n", id,
- p->timer[id].reg_tcntb);
- ptimer_set_count(p->timer[id].ptimer, p->timer[id].reg_tcntb);
- ptimer_run(p->timer[id].ptimer, 1);
- } else {
- /* stop timer, set status to STOP, see Basic Timer Operation */
- p->reg_tcon &= ~TCON_TIMER_START(id);
- ptimer_stop(p->timer[id].ptimer);
- }
-}
-
-/*
- * PWM Read
- */
-static uint64_t exynos4210_pwm_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- Exynos4210PWMState *s = (Exynos4210PWMState *)opaque;
- uint32_t value = 0;
- int index;
-
- switch (offset) {
- case TCFG0: case TCFG1:
- index = (offset - TCFG0) >> 2;
- value = s->reg_tcfg[index];
- break;
-
- case TCON:
- value = s->reg_tcon;
- break;
-
- case TCNTB0: case TCNTB1:
- case TCNTB2: case TCNTB3: case TCNTB4:
- index = (offset - TCNTB0) / 0xC;
- value = s->timer[index].reg_tcntb;
- break;
-
- case TCMPB0: case TCMPB1:
- case TCMPB2: case TCMPB3:
- index = (offset - TCMPB0) / 0xC;
- value = s->timer[index].reg_tcmpb;
- break;
-
- case TCNTO0: case TCNTO1:
- case TCNTO2: case TCNTO3: case TCNTO4:
- index = (offset == TCNTO4) ? 4 : (offset - TCNTO0) / 0xC;
- value = ptimer_get_count(s->timer[index].ptimer);
- break;
-
- case TINT_CSTAT:
- value = s->reg_tint_cstat;
- break;
-
- default:
- fprintf(stderr,
- "[exynos4210.pwm: bad read offset " TARGET_FMT_plx "]\n",
- offset);
- break;
- }
- return value;
-}
-
-/*
- * PWM Write
- */
-static void exynos4210_pwm_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- Exynos4210PWMState *s = (Exynos4210PWMState *)opaque;
- int index;
- uint32_t new_val;
- int i;
-
- switch (offset) {
- case TCFG0: case TCFG1:
- index = (offset - TCFG0) >> 2;
- s->reg_tcfg[index] = value;
-
- /* update timers frequencies */
- for (i = 0; i < EXYNOS4210_PWM_TIMERS_NUM; i++) {
- exynos4210_pwm_update_freq(s, s->timer[i].id);
- }
- break;
-
- case TCON:
- for (i = 0; i < EXYNOS4210_PWM_TIMERS_NUM; i++) {
- if ((value & TCON_TIMER_MANUAL_UPD(i)) >
- (s->reg_tcon & TCON_TIMER_MANUAL_UPD(i))) {
- /*
- * TCNTB and TCMPB are loaded into TCNT and TCMP.
- * Update timers.
- */
-
- /* this will start timer to run, this ok, because
- * during processing start bit timer will be stopped
- * if needed */
- ptimer_set_count(s->timer[i].ptimer, s->timer[i].reg_tcntb);
- DPRINTF("set timer %d count to %x\n", i,
- s->timer[i].reg_tcntb);
- }
-
- if ((value & TCON_TIMER_START(i)) >
- (s->reg_tcon & TCON_TIMER_START(i))) {
- /* changed to start */
- ptimer_run(s->timer[i].ptimer, 1);
- DPRINTF("run timer %d\n", i);
- }
-
- if ((value & TCON_TIMER_START(i)) <
- (s->reg_tcon & TCON_TIMER_START(i))) {
- /* changed to stop */
- ptimer_stop(s->timer[i].ptimer);
- DPRINTF("stop timer %d\n", i);
- }
- }
- s->reg_tcon = value;
- break;
-
- case TCNTB0: case TCNTB1:
- case TCNTB2: case TCNTB3: case TCNTB4:
- index = (offset - TCNTB0) / 0xC;
- s->timer[index].reg_tcntb = value;
- break;
-
- case TCMPB0: case TCMPB1:
- case TCMPB2: case TCMPB3:
- index = (offset - TCMPB0) / 0xC;
- s->timer[index].reg_tcmpb = value;
- break;
-
- case TINT_CSTAT:
- new_val = (s->reg_tint_cstat & 0x3E0) + (0x1F & value);
- new_val &= ~(0x3E0 & value);
-
- for (i = 0; i < EXYNOS4210_PWM_TIMERS_NUM; i++) {
- if ((new_val & TINT_CSTAT_STATUS(i)) <
- (s->reg_tint_cstat & TINT_CSTAT_STATUS(i))) {
- qemu_irq_lower(s->timer[i].irq);
- }
- }
-
- s->reg_tint_cstat = new_val;
- break;
-
- default:
- fprintf(stderr,
- "[exynos4210.pwm: bad write offset " TARGET_FMT_plx "]\n",
- offset);
- break;
-
- }
-}
-
-/*
- * Set default values to timer fields and registers
- */
-static void exynos4210_pwm_reset(DeviceState *d)
-{
- Exynos4210PWMState *s = EXYNOS4210_PWM(d);
- int i;
- s->reg_tcfg[0] = 0x0101;
- s->reg_tcfg[1] = 0x0;
- s->reg_tcon = 0;
- s->reg_tint_cstat = 0;
- for (i = 0; i < EXYNOS4210_PWM_TIMERS_NUM; i++) {
- s->timer[i].reg_tcmpb = 0;
- s->timer[i].reg_tcntb = 0;
-
- exynos4210_pwm_update_freq(s, s->timer[i].id);
- ptimer_stop(s->timer[i].ptimer);
- }
-}
-
-static const MemoryRegionOps exynos4210_pwm_ops = {
- .read = exynos4210_pwm_read,
- .write = exynos4210_pwm_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-/*
- * PWM timer initialization
- */
-static void exynos4210_pwm_init(Object *obj)
-{
- Exynos4210PWMState *s = EXYNOS4210_PWM(obj);
- SysBusDevice *dev = SYS_BUS_DEVICE(obj);
- int i;
- QEMUBH *bh;
-
- for (i = 0; i < EXYNOS4210_PWM_TIMERS_NUM; i++) {
- bh = qemu_bh_new(exynos4210_pwm_tick, &s->timer[i]);
- sysbus_init_irq(dev, &s->timer[i].irq);
- s->timer[i].ptimer = ptimer_init(bh);
- s->timer[i].id = i;
- s->timer[i].parent = s;
- }
-
- memory_region_init_io(&s->iomem, obj, &exynos4210_pwm_ops, s,
- "exynos4210-pwm", EXYNOS4210_PWM_REG_MEM_SIZE);
- sysbus_init_mmio(dev, &s->iomem);
-}
-
-static void exynos4210_pwm_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->reset = exynos4210_pwm_reset;
- dc->vmsd = &vmstate_exynos4210_pwm_state;
-}
-
-static const TypeInfo exynos4210_pwm_info = {
- .name = TYPE_EXYNOS4210_PWM,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(Exynos4210PWMState),
- .instance_init = exynos4210_pwm_init,
- .class_init = exynos4210_pwm_class_init,
-};
-
-static void exynos4210_pwm_register_types(void)
-{
- type_register_static(&exynos4210_pwm_info);
-}
-
-type_init(exynos4210_pwm_register_types)
diff --git a/qemu/hw/timer/exynos4210_rtc.c b/qemu/hw/timer/exynos4210_rtc.c
deleted file mode 100644
index da4dd451b..000000000
--- a/qemu/hw/timer/exynos4210_rtc.c
+++ /dev/null
@@ -1,595 +0,0 @@
-/*
- * Samsung exynos4210 Real Time Clock
- *
- * Copyright (c) 2012 Samsung Electronics Co., Ltd.
- * Ogurtsov Oleg <o.ogurtsov@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-/* Description:
- * Register RTCCON:
- * CLKSEL Bit[1] not used
- * CLKOUTEN Bit[9] not used
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "qemu/timer.h"
-#include "qemu-common.h"
-#include "qemu/bcd.h"
-#include "hw/ptimer.h"
-
-#include "hw/hw.h"
-#include "sysemu/sysemu.h"
-
-#include "hw/arm/exynos4210.h"
-
-#define DEBUG_RTC 0
-
-#if DEBUG_RTC
-#define DPRINTF(fmt, ...) \
- do { fprintf(stdout, "RTC: [%24s:%5d] " fmt, __func__, __LINE__, \
- ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while (0)
-#endif
-
-#define EXYNOS4210_RTC_REG_MEM_SIZE 0x0100
-
-#define INTP 0x0030
-#define RTCCON 0x0040
-#define TICCNT 0x0044
-#define RTCALM 0x0050
-#define ALMSEC 0x0054
-#define ALMMIN 0x0058
-#define ALMHOUR 0x005C
-#define ALMDAY 0x0060
-#define ALMMON 0x0064
-#define ALMYEAR 0x0068
-#define BCDSEC 0x0070
-#define BCDMIN 0x0074
-#define BCDHOUR 0x0078
-#define BCDDAY 0x007C
-#define BCDDAYWEEK 0x0080
-#define BCDMON 0x0084
-#define BCDYEAR 0x0088
-#define CURTICNT 0x0090
-
-#define TICK_TIMER_ENABLE 0x0100
-#define TICNT_THRESHOLD 2
-
-
-#define RTC_ENABLE 0x0001
-
-#define INTP_TICK_ENABLE 0x0001
-#define INTP_ALM_ENABLE 0x0002
-
-#define ALARM_INT_ENABLE 0x0040
-
-#define RTC_BASE_FREQ 32768
-
-#define TYPE_EXYNOS4210_RTC "exynos4210.rtc"
-#define EXYNOS4210_RTC(obj) \
- OBJECT_CHECK(Exynos4210RTCState, (obj), TYPE_EXYNOS4210_RTC)
-
-typedef struct Exynos4210RTCState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
-
- /* registers */
- uint32_t reg_intp;
- uint32_t reg_rtccon;
- uint32_t reg_ticcnt;
- uint32_t reg_rtcalm;
- uint32_t reg_almsec;
- uint32_t reg_almmin;
- uint32_t reg_almhour;
- uint32_t reg_almday;
- uint32_t reg_almmon;
- uint32_t reg_almyear;
- uint32_t reg_curticcnt;
-
- ptimer_state *ptimer; /* tick timer */
- ptimer_state *ptimer_1Hz; /* clock timer */
- uint32_t freq;
-
- qemu_irq tick_irq; /* Time Tick Generator irq */
- qemu_irq alm_irq; /* alarm irq */
-
- struct tm current_tm; /* current time */
-} Exynos4210RTCState;
-
-#define TICCKSEL(value) ((value & (0x0F << 4)) >> 4)
-
-/*** VMState ***/
-static const VMStateDescription vmstate_exynos4210_rtc_state = {
- .name = "exynos4210.rtc",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(reg_intp, Exynos4210RTCState),
- VMSTATE_UINT32(reg_rtccon, Exynos4210RTCState),
- VMSTATE_UINT32(reg_ticcnt, Exynos4210RTCState),
- VMSTATE_UINT32(reg_rtcalm, Exynos4210RTCState),
- VMSTATE_UINT32(reg_almsec, Exynos4210RTCState),
- VMSTATE_UINT32(reg_almmin, Exynos4210RTCState),
- VMSTATE_UINT32(reg_almhour, Exynos4210RTCState),
- VMSTATE_UINT32(reg_almday, Exynos4210RTCState),
- VMSTATE_UINT32(reg_almmon, Exynos4210RTCState),
- VMSTATE_UINT32(reg_almyear, Exynos4210RTCState),
- VMSTATE_UINT32(reg_curticcnt, Exynos4210RTCState),
- VMSTATE_PTIMER(ptimer, Exynos4210RTCState),
- VMSTATE_PTIMER(ptimer_1Hz, Exynos4210RTCState),
- VMSTATE_UINT32(freq, Exynos4210RTCState),
- VMSTATE_INT32(current_tm.tm_sec, Exynos4210RTCState),
- VMSTATE_INT32(current_tm.tm_min, Exynos4210RTCState),
- VMSTATE_INT32(current_tm.tm_hour, Exynos4210RTCState),
- VMSTATE_INT32(current_tm.tm_wday, Exynos4210RTCState),
- VMSTATE_INT32(current_tm.tm_mday, Exynos4210RTCState),
- VMSTATE_INT32(current_tm.tm_mon, Exynos4210RTCState),
- VMSTATE_INT32(current_tm.tm_year, Exynos4210RTCState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-#define BCD3DIGITS(x) \
- ((uint32_t)to_bcd((uint8_t)(x % 100)) + \
- ((uint32_t)to_bcd((uint8_t)((x % 1000) / 100)) << 8))
-
-static void check_alarm_raise(Exynos4210RTCState *s)
-{
- unsigned int alarm_raise = 0;
- struct tm stm = s->current_tm;
-
- if ((s->reg_rtcalm & 0x01) &&
- (to_bcd((uint8_t)stm.tm_sec) == (uint8_t)s->reg_almsec)) {
- alarm_raise = 1;
- }
- if ((s->reg_rtcalm & 0x02) &&
- (to_bcd((uint8_t)stm.tm_min) == (uint8_t)s->reg_almmin)) {
- alarm_raise = 1;
- }
- if ((s->reg_rtcalm & 0x04) &&
- (to_bcd((uint8_t)stm.tm_hour) == (uint8_t)s->reg_almhour)) {
- alarm_raise = 1;
- }
- if ((s->reg_rtcalm & 0x08) &&
- (to_bcd((uint8_t)stm.tm_mday) == (uint8_t)s->reg_almday)) {
- alarm_raise = 1;
- }
- if ((s->reg_rtcalm & 0x10) &&
- (to_bcd((uint8_t)stm.tm_mon) == (uint8_t)s->reg_almmon)) {
- alarm_raise = 1;
- }
- if ((s->reg_rtcalm & 0x20) &&
- (BCD3DIGITS(stm.tm_year) == s->reg_almyear)) {
- alarm_raise = 1;
- }
-
- if (alarm_raise) {
- DPRINTF("ALARM IRQ\n");
- /* set irq status */
- s->reg_intp |= INTP_ALM_ENABLE;
- qemu_irq_raise(s->alm_irq);
- }
-}
-
-/*
- * RTC update frequency
- * Parameters:
- * reg_value - current RTCCON register or his new value
- */
-static void exynos4210_rtc_update_freq(Exynos4210RTCState *s,
- uint32_t reg_value)
-{
- uint32_t freq;
-
- freq = s->freq;
- /* set frequncy for time generator */
- s->freq = RTC_BASE_FREQ / (1 << TICCKSEL(reg_value));
-
- if (freq != s->freq) {
- ptimer_set_freq(s->ptimer, s->freq);
- DPRINTF("freq=%dHz\n", s->freq);
- }
-}
-
-/* month is between 0 and 11. */
-static int get_days_in_month(int month, int year)
-{
- static const int days_tab[12] = {
- 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
- };
- int d;
- if ((unsigned)month >= 12) {
- return 31;
- }
- d = days_tab[month];
- if (month == 1) {
- if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0)) {
- d++;
- }
- }
- return d;
-}
-
-/* update 'tm' to the next second */
-static void rtc_next_second(struct tm *tm)
-{
- int days_in_month;
-
- tm->tm_sec++;
- if ((unsigned)tm->tm_sec >= 60) {
- tm->tm_sec = 0;
- tm->tm_min++;
- if ((unsigned)tm->tm_min >= 60) {
- tm->tm_min = 0;
- tm->tm_hour++;
- if ((unsigned)tm->tm_hour >= 24) {
- tm->tm_hour = 0;
- /* next day */
- tm->tm_wday++;
- if ((unsigned)tm->tm_wday >= 7) {
- tm->tm_wday = 0;
- }
- days_in_month = get_days_in_month(tm->tm_mon,
- tm->tm_year + 1900);
- tm->tm_mday++;
- if (tm->tm_mday < 1) {
- tm->tm_mday = 1;
- } else if (tm->tm_mday > days_in_month) {
- tm->tm_mday = 1;
- tm->tm_mon++;
- if (tm->tm_mon >= 12) {
- tm->tm_mon = 0;
- tm->tm_year++;
- }
- }
- }
- }
- }
-}
-
-/*
- * tick handler
- */
-static void exynos4210_rtc_tick(void *opaque)
-{
- Exynos4210RTCState *s = (Exynos4210RTCState *)opaque;
-
- DPRINTF("TICK IRQ\n");
- /* set irq status */
- s->reg_intp |= INTP_TICK_ENABLE;
- /* raise IRQ */
- qemu_irq_raise(s->tick_irq);
-
- /* restart timer */
- ptimer_set_count(s->ptimer, s->reg_ticcnt);
- ptimer_run(s->ptimer, 1);
-}
-
-/*
- * 1Hz clock handler
- */
-static void exynos4210_rtc_1Hz_tick(void *opaque)
-{
- Exynos4210RTCState *s = (Exynos4210RTCState *)opaque;
-
- rtc_next_second(&s->current_tm);
- /* DPRINTF("1Hz tick\n"); */
-
- /* raise IRQ */
- if (s->reg_rtcalm & ALARM_INT_ENABLE) {
- check_alarm_raise(s);
- }
-
- ptimer_set_count(s->ptimer_1Hz, RTC_BASE_FREQ);
- ptimer_run(s->ptimer_1Hz, 1);
-}
-
-/*
- * RTC Read
- */
-static uint64_t exynos4210_rtc_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- uint32_t value = 0;
- Exynos4210RTCState *s = (Exynos4210RTCState *)opaque;
-
- switch (offset) {
- case INTP:
- value = s->reg_intp;
- break;
- case RTCCON:
- value = s->reg_rtccon;
- break;
- case TICCNT:
- value = s->reg_ticcnt;
- break;
- case RTCALM:
- value = s->reg_rtcalm;
- break;
- case ALMSEC:
- value = s->reg_almsec;
- break;
- case ALMMIN:
- value = s->reg_almmin;
- break;
- case ALMHOUR:
- value = s->reg_almhour;
- break;
- case ALMDAY:
- value = s->reg_almday;
- break;
- case ALMMON:
- value = s->reg_almmon;
- break;
- case ALMYEAR:
- value = s->reg_almyear;
- break;
-
- case BCDSEC:
- value = (uint32_t)to_bcd((uint8_t)s->current_tm.tm_sec);
- break;
- case BCDMIN:
- value = (uint32_t)to_bcd((uint8_t)s->current_tm.tm_min);
- break;
- case BCDHOUR:
- value = (uint32_t)to_bcd((uint8_t)s->current_tm.tm_hour);
- break;
- case BCDDAYWEEK:
- value = (uint32_t)to_bcd((uint8_t)s->current_tm.tm_wday);
- break;
- case BCDDAY:
- value = (uint32_t)to_bcd((uint8_t)s->current_tm.tm_mday);
- break;
- case BCDMON:
- value = (uint32_t)to_bcd((uint8_t)s->current_tm.tm_mon + 1);
- break;
- case BCDYEAR:
- value = BCD3DIGITS(s->current_tm.tm_year);
- break;
-
- case CURTICNT:
- s->reg_curticcnt = ptimer_get_count(s->ptimer);
- value = s->reg_curticcnt;
- break;
-
- default:
- fprintf(stderr,
- "[exynos4210.rtc: bad read offset " TARGET_FMT_plx "]\n",
- offset);
- break;
- }
- return value;
-}
-
-/*
- * RTC Write
- */
-static void exynos4210_rtc_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- Exynos4210RTCState *s = (Exynos4210RTCState *)opaque;
-
- switch (offset) {
- case INTP:
- if (value & INTP_ALM_ENABLE) {
- qemu_irq_lower(s->alm_irq);
- s->reg_intp &= (~INTP_ALM_ENABLE);
- }
- if (value & INTP_TICK_ENABLE) {
- qemu_irq_lower(s->tick_irq);
- s->reg_intp &= (~INTP_TICK_ENABLE);
- }
- break;
- case RTCCON:
- if (value & RTC_ENABLE) {
- exynos4210_rtc_update_freq(s, value);
- }
- if ((value & RTC_ENABLE) > (s->reg_rtccon & RTC_ENABLE)) {
- /* clock timer */
- ptimer_set_count(s->ptimer_1Hz, RTC_BASE_FREQ);
- ptimer_run(s->ptimer_1Hz, 1);
- DPRINTF("run clock timer\n");
- }
- if ((value & RTC_ENABLE) < (s->reg_rtccon & RTC_ENABLE)) {
- /* tick timer */
- ptimer_stop(s->ptimer);
- /* clock timer */
- ptimer_stop(s->ptimer_1Hz);
- DPRINTF("stop all timers\n");
- }
- if (value & RTC_ENABLE) {
- if ((value & TICK_TIMER_ENABLE) >
- (s->reg_rtccon & TICK_TIMER_ENABLE) &&
- (s->reg_ticcnt)) {
- ptimer_set_count(s->ptimer, s->reg_ticcnt);
- ptimer_run(s->ptimer, 1);
- DPRINTF("run tick timer\n");
- }
- if ((value & TICK_TIMER_ENABLE) <
- (s->reg_rtccon & TICK_TIMER_ENABLE)) {
- ptimer_stop(s->ptimer);
- }
- }
- s->reg_rtccon = value;
- break;
- case TICCNT:
- if (value > TICNT_THRESHOLD) {
- s->reg_ticcnt = value;
- } else {
- fprintf(stderr,
- "[exynos4210.rtc: bad TICNT value %u ]\n",
- (uint32_t)value);
- }
- break;
-
- case RTCALM:
- s->reg_rtcalm = value;
- break;
- case ALMSEC:
- s->reg_almsec = (value & 0x7f);
- break;
- case ALMMIN:
- s->reg_almmin = (value & 0x7f);
- break;
- case ALMHOUR:
- s->reg_almhour = (value & 0x3f);
- break;
- case ALMDAY:
- s->reg_almday = (value & 0x3f);
- break;
- case ALMMON:
- s->reg_almmon = (value & 0x1f);
- break;
- case ALMYEAR:
- s->reg_almyear = (value & 0x0fff);
- break;
-
- case BCDSEC:
- if (s->reg_rtccon & RTC_ENABLE) {
- s->current_tm.tm_sec = (int)from_bcd((uint8_t)value);
- }
- break;
- case BCDMIN:
- if (s->reg_rtccon & RTC_ENABLE) {
- s->current_tm.tm_min = (int)from_bcd((uint8_t)value);
- }
- break;
- case BCDHOUR:
- if (s->reg_rtccon & RTC_ENABLE) {
- s->current_tm.tm_hour = (int)from_bcd((uint8_t)value);
- }
- break;
- case BCDDAYWEEK:
- if (s->reg_rtccon & RTC_ENABLE) {
- s->current_tm.tm_wday = (int)from_bcd((uint8_t)value);
- }
- break;
- case BCDDAY:
- if (s->reg_rtccon & RTC_ENABLE) {
- s->current_tm.tm_mday = (int)from_bcd((uint8_t)value);
- }
- break;
- case BCDMON:
- if (s->reg_rtccon & RTC_ENABLE) {
- s->current_tm.tm_mon = (int)from_bcd((uint8_t)value) - 1;
- }
- break;
- case BCDYEAR:
- if (s->reg_rtccon & RTC_ENABLE) {
- /* 3 digits */
- s->current_tm.tm_year = (int)from_bcd((uint8_t)value) +
- (int)from_bcd((uint8_t)((value >> 8) & 0x0f)) * 100;
- }
- break;
-
- default:
- fprintf(stderr,
- "[exynos4210.rtc: bad write offset " TARGET_FMT_plx "]\n",
- offset);
- break;
-
- }
-}
-
-/*
- * Set default values to timer fields and registers
- */
-static void exynos4210_rtc_reset(DeviceState *d)
-{
- Exynos4210RTCState *s = EXYNOS4210_RTC(d);
-
- qemu_get_timedate(&s->current_tm, 0);
-
- DPRINTF("Get time from host: %d-%d-%d %2d:%02d:%02d\n",
- s->current_tm.tm_year, s->current_tm.tm_mon, s->current_tm.tm_mday,
- s->current_tm.tm_hour, s->current_tm.tm_min, s->current_tm.tm_sec);
-
- s->reg_intp = 0;
- s->reg_rtccon = 0;
- s->reg_ticcnt = 0;
- s->reg_rtcalm = 0;
- s->reg_almsec = 0;
- s->reg_almmin = 0;
- s->reg_almhour = 0;
- s->reg_almday = 0;
- s->reg_almmon = 0;
- s->reg_almyear = 0;
-
- s->reg_curticcnt = 0;
-
- exynos4210_rtc_update_freq(s, s->reg_rtccon);
- ptimer_stop(s->ptimer);
- ptimer_stop(s->ptimer_1Hz);
-}
-
-static const MemoryRegionOps exynos4210_rtc_ops = {
- .read = exynos4210_rtc_read,
- .write = exynos4210_rtc_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-/*
- * RTC timer initialization
- */
-static void exynos4210_rtc_init(Object *obj)
-{
- Exynos4210RTCState *s = EXYNOS4210_RTC(obj);
- SysBusDevice *dev = SYS_BUS_DEVICE(obj);
- QEMUBH *bh;
-
- bh = qemu_bh_new(exynos4210_rtc_tick, s);
- s->ptimer = ptimer_init(bh);
- ptimer_set_freq(s->ptimer, RTC_BASE_FREQ);
- exynos4210_rtc_update_freq(s, 0);
-
- bh = qemu_bh_new(exynos4210_rtc_1Hz_tick, s);
- s->ptimer_1Hz = ptimer_init(bh);
- ptimer_set_freq(s->ptimer_1Hz, RTC_BASE_FREQ);
-
- sysbus_init_irq(dev, &s->alm_irq);
- sysbus_init_irq(dev, &s->tick_irq);
-
- memory_region_init_io(&s->iomem, obj, &exynos4210_rtc_ops, s,
- "exynos4210-rtc", EXYNOS4210_RTC_REG_MEM_SIZE);
- sysbus_init_mmio(dev, &s->iomem);
-}
-
-static void exynos4210_rtc_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->reset = exynos4210_rtc_reset;
- dc->vmsd = &vmstate_exynos4210_rtc_state;
-}
-
-static const TypeInfo exynos4210_rtc_info = {
- .name = TYPE_EXYNOS4210_RTC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(Exynos4210RTCState),
- .instance_init = exynos4210_rtc_init,
- .class_init = exynos4210_rtc_class_init,
-};
-
-static void exynos4210_rtc_register_types(void)
-{
- type_register_static(&exynos4210_rtc_info);
-}
-
-type_init(exynos4210_rtc_register_types)
diff --git a/qemu/hw/timer/grlib_gptimer.c b/qemu/hw/timer/grlib_gptimer.c
deleted file mode 100644
index dd000f5af..000000000
--- a/qemu/hw/timer/grlib_gptimer.c
+++ /dev/null
@@ -1,412 +0,0 @@
-/*
- * QEMU GRLIB GPTimer Emulator
- *
- * Copyright (c) 2010-2011 AdaCore
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "qemu/timer.h"
-#include "hw/ptimer.h"
-#include "qemu/timer.h"
-#include "qemu/main-loop.h"
-
-#include "trace.h"
-
-#define UNIT_REG_SIZE 16 /* Size of memory mapped regs for the unit */
-#define GPTIMER_REG_SIZE 16 /* Size of memory mapped regs for a GPTimer */
-
-#define GPTIMER_MAX_TIMERS 8
-
-/* GPTimer Config register fields */
-#define GPTIMER_ENABLE (1 << 0)
-#define GPTIMER_RESTART (1 << 1)
-#define GPTIMER_LOAD (1 << 2)
-#define GPTIMER_INT_ENABLE (1 << 3)
-#define GPTIMER_INT_PENDING (1 << 4)
-#define GPTIMER_CHAIN (1 << 5) /* Not supported */
-#define GPTIMER_DEBUG_HALT (1 << 6) /* Not supported */
-
-/* Memory mapped register offsets */
-#define SCALER_OFFSET 0x00
-#define SCALER_RELOAD_OFFSET 0x04
-#define CONFIG_OFFSET 0x08
-#define COUNTER_OFFSET 0x00
-#define COUNTER_RELOAD_OFFSET 0x04
-#define TIMER_BASE 0x10
-
-#define TYPE_GRLIB_GPTIMER "grlib,gptimer"
-#define GRLIB_GPTIMER(obj) \
- OBJECT_CHECK(GPTimerUnit, (obj), TYPE_GRLIB_GPTIMER)
-
-typedef struct GPTimer GPTimer;
-typedef struct GPTimerUnit GPTimerUnit;
-
-struct GPTimer {
- QEMUBH *bh;
- struct ptimer_state *ptimer;
-
- qemu_irq irq;
- int id;
- GPTimerUnit *unit;
-
- /* registers */
- uint32_t counter;
- uint32_t reload;
- uint32_t config;
-};
-
-struct GPTimerUnit {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
-
- uint32_t nr_timers; /* Number of timers available */
- uint32_t freq_hz; /* System frequency */
- uint32_t irq_line; /* Base irq line */
-
- GPTimer *timers;
-
- /* registers */
- uint32_t scaler;
- uint32_t reload;
- uint32_t config;
-};
-
-static void grlib_gptimer_enable(GPTimer *timer)
-{
- assert(timer != NULL);
-
-
- ptimer_stop(timer->ptimer);
-
- if (!(timer->config & GPTIMER_ENABLE)) {
- /* Timer disabled */
- trace_grlib_gptimer_disabled(timer->id, timer->config);
- return;
- }
-
- /* ptimer is triggered when the counter reach 0 but GPTimer is triggered at
- underflow. Set count + 1 to simulate the GPTimer behavior. */
-
- trace_grlib_gptimer_enable(timer->id, timer->counter);
-
- ptimer_set_count(timer->ptimer, (uint64_t)timer->counter + 1);
- ptimer_run(timer->ptimer, 1);
-}
-
-static void grlib_gptimer_restart(GPTimer *timer)
-{
- assert(timer != NULL);
-
- trace_grlib_gptimer_restart(timer->id, timer->reload);
-
- timer->counter = timer->reload;
- grlib_gptimer_enable(timer);
-}
-
-static void grlib_gptimer_set_scaler(GPTimerUnit *unit, uint32_t scaler)
-{
- int i = 0;
- uint32_t value = 0;
-
- assert(unit != NULL);
-
- if (scaler > 0) {
- value = unit->freq_hz / (scaler + 1);
- } else {
- value = unit->freq_hz;
- }
-
- trace_grlib_gptimer_set_scaler(scaler, value);
-
- for (i = 0; i < unit->nr_timers; i++) {
- ptimer_set_freq(unit->timers[i].ptimer, value);
- }
-}
-
-static void grlib_gptimer_hit(void *opaque)
-{
- GPTimer *timer = opaque;
- assert(timer != NULL);
-
- trace_grlib_gptimer_hit(timer->id);
-
- /* Timer expired */
-
- if (timer->config & GPTIMER_INT_ENABLE) {
- /* Set the pending bit (only unset by write in the config register) */
- timer->config |= GPTIMER_INT_PENDING;
- qemu_irq_pulse(timer->irq);
- }
-
- if (timer->config & GPTIMER_RESTART) {
- grlib_gptimer_restart(timer);
- }
-}
-
-static uint64_t grlib_gptimer_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- GPTimerUnit *unit = opaque;
- hwaddr timer_addr;
- int id;
- uint32_t value = 0;
-
- addr &= 0xff;
-
- /* Unit registers */
- switch (addr) {
- case SCALER_OFFSET:
- trace_grlib_gptimer_readl(-1, addr, unit->scaler);
- return unit->scaler;
-
- case SCALER_RELOAD_OFFSET:
- trace_grlib_gptimer_readl(-1, addr, unit->reload);
- return unit->reload;
-
- case CONFIG_OFFSET:
- trace_grlib_gptimer_readl(-1, addr, unit->config);
- return unit->config;
-
- default:
- break;
- }
-
- timer_addr = (addr % TIMER_BASE);
- id = (addr - TIMER_BASE) / TIMER_BASE;
-
- if (id >= 0 && id < unit->nr_timers) {
-
- /* GPTimer registers */
- switch (timer_addr) {
- case COUNTER_OFFSET:
- value = ptimer_get_count(unit->timers[id].ptimer);
- trace_grlib_gptimer_readl(id, addr, value);
- return value;
-
- case COUNTER_RELOAD_OFFSET:
- value = unit->timers[id].reload;
- trace_grlib_gptimer_readl(id, addr, value);
- return value;
-
- case CONFIG_OFFSET:
- trace_grlib_gptimer_readl(id, addr, unit->timers[id].config);
- return unit->timers[id].config;
-
- default:
- break;
- }
-
- }
-
- trace_grlib_gptimer_readl(-1, addr, 0);
- return 0;
-}
-
-static void grlib_gptimer_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- GPTimerUnit *unit = opaque;
- hwaddr timer_addr;
- int id;
-
- addr &= 0xff;
-
- /* Unit registers */
- switch (addr) {
- case SCALER_OFFSET:
- value &= 0xFFFF; /* clean up the value */
- unit->scaler = value;
- trace_grlib_gptimer_writel(-1, addr, unit->scaler);
- return;
-
- case SCALER_RELOAD_OFFSET:
- value &= 0xFFFF; /* clean up the value */
- unit->reload = value;
- trace_grlib_gptimer_writel(-1, addr, unit->reload);
- grlib_gptimer_set_scaler(unit, value);
- return;
-
- case CONFIG_OFFSET:
- /* Read Only (disable timer freeze not supported) */
- trace_grlib_gptimer_writel(-1, addr, 0);
- return;
-
- default:
- break;
- }
-
- timer_addr = (addr % TIMER_BASE);
- id = (addr - TIMER_BASE) / TIMER_BASE;
-
- if (id >= 0 && id < unit->nr_timers) {
-
- /* GPTimer registers */
- switch (timer_addr) {
- case COUNTER_OFFSET:
- trace_grlib_gptimer_writel(id, addr, value);
- unit->timers[id].counter = value;
- grlib_gptimer_enable(&unit->timers[id]);
- return;
-
- case COUNTER_RELOAD_OFFSET:
- trace_grlib_gptimer_writel(id, addr, value);
- unit->timers[id].reload = value;
- return;
-
- case CONFIG_OFFSET:
- trace_grlib_gptimer_writel(id, addr, value);
-
- if (value & GPTIMER_INT_PENDING) {
- /* clear pending bit */
- value &= ~GPTIMER_INT_PENDING;
- } else {
- /* keep pending bit */
- value |= unit->timers[id].config & GPTIMER_INT_PENDING;
- }
-
- unit->timers[id].config = value;
-
- /* gptimer_restart calls gptimer_enable, so if "enable" and "load"
- bits are present, we just have to call restart. */
-
- if (value & GPTIMER_LOAD) {
- grlib_gptimer_restart(&unit->timers[id]);
- } else if (value & GPTIMER_ENABLE) {
- grlib_gptimer_enable(&unit->timers[id]);
- }
-
- /* These fields must always be read as 0 */
- value &= ~(GPTIMER_LOAD & GPTIMER_DEBUG_HALT);
-
- unit->timers[id].config = value;
- return;
-
- default:
- break;
- }
-
- }
-
- trace_grlib_gptimer_writel(-1, addr, value);
-}
-
-static const MemoryRegionOps grlib_gptimer_ops = {
- .read = grlib_gptimer_read,
- .write = grlib_gptimer_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static void grlib_gptimer_reset(DeviceState *d)
-{
- GPTimerUnit *unit = GRLIB_GPTIMER(d);
- int i = 0;
-
- assert(unit != NULL);
-
- unit->scaler = 0;
- unit->reload = 0;
-
- unit->config = unit->nr_timers;
- unit->config |= unit->irq_line << 3;
- unit->config |= 1 << 8; /* separate interrupt */
- unit->config |= 1 << 9; /* Disable timer freeze */
-
-
- for (i = 0; i < unit->nr_timers; i++) {
- GPTimer *timer = &unit->timers[i];
-
- timer->counter = 0;
- timer->reload = 0;
- timer->config = 0;
- ptimer_stop(timer->ptimer);
- ptimer_set_count(timer->ptimer, 0);
- ptimer_set_freq(timer->ptimer, unit->freq_hz);
- }
-}
-
-static int grlib_gptimer_init(SysBusDevice *dev)
-{
- GPTimerUnit *unit = GRLIB_GPTIMER(dev);
- unsigned int i;
-
- assert(unit->nr_timers > 0);
- assert(unit->nr_timers <= GPTIMER_MAX_TIMERS);
-
- unit->timers = g_malloc0(sizeof unit->timers[0] * unit->nr_timers);
-
- for (i = 0; i < unit->nr_timers; i++) {
- GPTimer *timer = &unit->timers[i];
-
- timer->unit = unit;
- timer->bh = qemu_bh_new(grlib_gptimer_hit, timer);
- timer->ptimer = ptimer_init(timer->bh);
- timer->id = i;
-
- /* One IRQ line for each timer */
- sysbus_init_irq(dev, &timer->irq);
-
- ptimer_set_freq(timer->ptimer, unit->freq_hz);
- }
-
- memory_region_init_io(&unit->iomem, OBJECT(unit), &grlib_gptimer_ops,
- unit, "gptimer",
- UNIT_REG_SIZE + GPTIMER_REG_SIZE * unit->nr_timers);
-
- sysbus_init_mmio(dev, &unit->iomem);
- return 0;
-}
-
-static Property grlib_gptimer_properties[] = {
- DEFINE_PROP_UINT32("frequency", GPTimerUnit, freq_hz, 40000000),
- DEFINE_PROP_UINT32("irq-line", GPTimerUnit, irq_line, 8),
- DEFINE_PROP_UINT32("nr-timers", GPTimerUnit, nr_timers, 2),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void grlib_gptimer_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = grlib_gptimer_init;
- dc->reset = grlib_gptimer_reset;
- dc->props = grlib_gptimer_properties;
-}
-
-static const TypeInfo grlib_gptimer_info = {
- .name = TYPE_GRLIB_GPTIMER,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(GPTimerUnit),
- .class_init = grlib_gptimer_class_init,
-};
-
-static void grlib_gptimer_register_types(void)
-{
- type_register_static(&grlib_gptimer_info);
-}
-
-type_init(grlib_gptimer_register_types)
diff --git a/qemu/hw/timer/hpet.c b/qemu/hw/timer/hpet.c
deleted file mode 100644
index a2c18b30c..000000000
--- a/qemu/hw/timer/hpet.c
+++ /dev/null
@@ -1,789 +0,0 @@
-/*
- * High Precision Event Timer emulation
- *
- * Copyright (c) 2007 Alexander Graf
- * Copyright (c) 2008 IBM Corporation
- *
- * Authors: Beth Kon <bkon@us.ibm.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- * *****************************************************************
- *
- * This driver attempts to emulate an HPET device in software.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/i386/pc.h"
-#include "ui/console.h"
-#include "qapi/error.h"
-#include "qemu/error-report.h"
-#include "qemu/timer.h"
-#include "hw/timer/hpet.h"
-#include "hw/sysbus.h"
-#include "hw/timer/mc146818rtc.h"
-#include "hw/timer/i8254.h"
-
-//#define HPET_DEBUG
-#ifdef HPET_DEBUG
-#define DPRINTF printf
-#else
-#define DPRINTF(...)
-#endif
-
-#define HPET_MSI_SUPPORT 0
-
-#define HPET(obj) OBJECT_CHECK(HPETState, (obj), TYPE_HPET)
-
-struct HPETState;
-typedef struct HPETTimer { /* timers */
- uint8_t tn; /*timer number*/
- QEMUTimer *qemu_timer;
- struct HPETState *state;
- /* Memory-mapped, software visible timer registers */
- uint64_t config; /* configuration/cap */
- uint64_t cmp; /* comparator */
- uint64_t fsb; /* FSB route */
- /* Hidden register state */
- uint64_t period; /* Last value written to comparator */
- uint8_t wrap_flag; /* timer pop will indicate wrap for one-shot 32-bit
- * mode. Next pop will be actual timer expiration.
- */
-} HPETTimer;
-
-typedef struct HPETState {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- MemoryRegion iomem;
- uint64_t hpet_offset;
- qemu_irq irqs[HPET_NUM_IRQ_ROUTES];
- uint32_t flags;
- uint8_t rtc_irq_level;
- qemu_irq pit_enabled;
- uint8_t num_timers;
- uint32_t intcap;
- HPETTimer timer[HPET_MAX_TIMERS];
-
- /* Memory-mapped, software visible registers */
- uint64_t capability; /* capabilities */
- uint64_t config; /* configuration */
- uint64_t isr; /* interrupt status reg */
- uint64_t hpet_counter; /* main counter */
- uint8_t hpet_id; /* instance id */
-} HPETState;
-
-static uint32_t hpet_in_legacy_mode(HPETState *s)
-{
- return s->config & HPET_CFG_LEGACY;
-}
-
-static uint32_t timer_int_route(struct HPETTimer *timer)
-{
- return (timer->config & HPET_TN_INT_ROUTE_MASK) >> HPET_TN_INT_ROUTE_SHIFT;
-}
-
-static uint32_t timer_fsb_route(HPETTimer *t)
-{
- return t->config & HPET_TN_FSB_ENABLE;
-}
-
-static uint32_t hpet_enabled(HPETState *s)
-{
- return s->config & HPET_CFG_ENABLE;
-}
-
-static uint32_t timer_is_periodic(HPETTimer *t)
-{
- return t->config & HPET_TN_PERIODIC;
-}
-
-static uint32_t timer_enabled(HPETTimer *t)
-{
- return t->config & HPET_TN_ENABLE;
-}
-
-static uint32_t hpet_time_after(uint64_t a, uint64_t b)
-{
- return ((int32_t)(b - a) < 0);
-}
-
-static uint32_t hpet_time_after64(uint64_t a, uint64_t b)
-{
- return ((int64_t)(b - a) < 0);
-}
-
-static uint64_t ticks_to_ns(uint64_t value)
-{
- return value * HPET_CLK_PERIOD;
-}
-
-static uint64_t ns_to_ticks(uint64_t value)
-{
- return value / HPET_CLK_PERIOD;
-}
-
-static uint64_t hpet_fixup_reg(uint64_t new, uint64_t old, uint64_t mask)
-{
- new &= mask;
- new |= old & ~mask;
- return new;
-}
-
-static int activating_bit(uint64_t old, uint64_t new, uint64_t mask)
-{
- return (!(old & mask) && (new & mask));
-}
-
-static int deactivating_bit(uint64_t old, uint64_t new, uint64_t mask)
-{
- return ((old & mask) && !(new & mask));
-}
-
-static uint64_t hpet_get_ticks(HPETState *s)
-{
- return ns_to_ticks(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->hpet_offset);
-}
-
-/*
- * calculate diff between comparator value and current ticks
- */
-static inline uint64_t hpet_calculate_diff(HPETTimer *t, uint64_t current)
-{
-
- if (t->config & HPET_TN_32BIT) {
- uint32_t diff, cmp;
-
- cmp = (uint32_t)t->cmp;
- diff = cmp - (uint32_t)current;
- diff = (int32_t)diff > 0 ? diff : (uint32_t)1;
- return (uint64_t)diff;
- } else {
- uint64_t diff, cmp;
-
- cmp = t->cmp;
- diff = cmp - current;
- diff = (int64_t)diff > 0 ? diff : (uint64_t)1;
- return diff;
- }
-}
-
-static void update_irq(struct HPETTimer *timer, int set)
-{
- uint64_t mask;
- HPETState *s;
- int route;
-
- if (timer->tn <= 1 && hpet_in_legacy_mode(timer->state)) {
- /* if LegacyReplacementRoute bit is set, HPET specification requires
- * timer0 be routed to IRQ0 in NON-APIC or IRQ2 in the I/O APIC,
- * timer1 be routed to IRQ8 in NON-APIC or IRQ8 in the I/O APIC.
- */
- route = (timer->tn == 0) ? 0 : RTC_ISA_IRQ;
- } else {
- route = timer_int_route(timer);
- }
- s = timer->state;
- mask = 1 << timer->tn;
- if (!set || !timer_enabled(timer) || !hpet_enabled(timer->state)) {
- s->isr &= ~mask;
- if (!timer_fsb_route(timer)) {
- qemu_irq_lower(s->irqs[route]);
- }
- } else if (timer_fsb_route(timer)) {
- address_space_stl_le(&address_space_memory, timer->fsb >> 32,
- timer->fsb & 0xffffffff, MEMTXATTRS_UNSPECIFIED,
- NULL);
- } else if (timer->config & HPET_TN_TYPE_LEVEL) {
- s->isr |= mask;
- qemu_irq_raise(s->irqs[route]);
- } else {
- s->isr &= ~mask;
- qemu_irq_pulse(s->irqs[route]);
- }
-}
-
-static void hpet_pre_save(void *opaque)
-{
- HPETState *s = opaque;
-
- /* save current counter value */
- s->hpet_counter = hpet_get_ticks(s);
-}
-
-static int hpet_pre_load(void *opaque)
-{
- HPETState *s = opaque;
-
- /* version 1 only supports 3, later versions will load the actual value */
- s->num_timers = HPET_MIN_TIMERS;
- return 0;
-}
-
-static bool hpet_validate_num_timers(void *opaque, int version_id)
-{
- HPETState *s = opaque;
-
- if (s->num_timers < HPET_MIN_TIMERS) {
- return false;
- } else if (s->num_timers > HPET_MAX_TIMERS) {
- return false;
- }
- return true;
-}
-
-static int hpet_post_load(void *opaque, int version_id)
-{
- HPETState *s = opaque;
-
- /* Recalculate the offset between the main counter and guest time */
- s->hpet_offset = ticks_to_ns(s->hpet_counter) - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-
- /* Push number of timers into capability returned via HPET_ID */
- s->capability &= ~HPET_ID_NUM_TIM_MASK;
- s->capability |= (s->num_timers - 1) << HPET_ID_NUM_TIM_SHIFT;
- hpet_cfg.hpet[s->hpet_id].event_timer_block_id = (uint32_t)s->capability;
-
- /* Derive HPET_MSI_SUPPORT from the capability of the first timer. */
- s->flags &= ~(1 << HPET_MSI_SUPPORT);
- if (s->timer[0].config & HPET_TN_FSB_CAP) {
- s->flags |= 1 << HPET_MSI_SUPPORT;
- }
- return 0;
-}
-
-static bool hpet_rtc_irq_level_needed(void *opaque)
-{
- HPETState *s = opaque;
-
- return s->rtc_irq_level != 0;
-}
-
-static const VMStateDescription vmstate_hpet_rtc_irq_level = {
- .name = "hpet/rtc_irq_level",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = hpet_rtc_irq_level_needed,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(rtc_irq_level, HPETState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_hpet_timer = {
- .name = "hpet_timer",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(tn, HPETTimer),
- VMSTATE_UINT64(config, HPETTimer),
- VMSTATE_UINT64(cmp, HPETTimer),
- VMSTATE_UINT64(fsb, HPETTimer),
- VMSTATE_UINT64(period, HPETTimer),
- VMSTATE_UINT8(wrap_flag, HPETTimer),
- VMSTATE_TIMER_PTR(qemu_timer, HPETTimer),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_hpet = {
- .name = "hpet",
- .version_id = 2,
- .minimum_version_id = 1,
- .pre_save = hpet_pre_save,
- .pre_load = hpet_pre_load,
- .post_load = hpet_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT64(config, HPETState),
- VMSTATE_UINT64(isr, HPETState),
- VMSTATE_UINT64(hpet_counter, HPETState),
- VMSTATE_UINT8_V(num_timers, HPETState, 2),
- VMSTATE_VALIDATE("num_timers in range", hpet_validate_num_timers),
- VMSTATE_STRUCT_VARRAY_UINT8(timer, HPETState, num_timers, 0,
- vmstate_hpet_timer, HPETTimer),
- VMSTATE_END_OF_LIST()
- },
- .subsections = (const VMStateDescription*[]) {
- &vmstate_hpet_rtc_irq_level,
- NULL
- }
-};
-
-/*
- * timer expiration callback
- */
-static void hpet_timer(void *opaque)
-{
- HPETTimer *t = opaque;
- uint64_t diff;
-
- uint64_t period = t->period;
- uint64_t cur_tick = hpet_get_ticks(t->state);
-
- if (timer_is_periodic(t) && period != 0) {
- if (t->config & HPET_TN_32BIT) {
- while (hpet_time_after(cur_tick, t->cmp)) {
- t->cmp = (uint32_t)(t->cmp + t->period);
- }
- } else {
- while (hpet_time_after64(cur_tick, t->cmp)) {
- t->cmp += period;
- }
- }
- diff = hpet_calculate_diff(t, cur_tick);
- timer_mod(t->qemu_timer,
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + (int64_t)ticks_to_ns(diff));
- } else if (t->config & HPET_TN_32BIT && !timer_is_periodic(t)) {
- if (t->wrap_flag) {
- diff = hpet_calculate_diff(t, cur_tick);
- timer_mod(t->qemu_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- (int64_t)ticks_to_ns(diff));
- t->wrap_flag = 0;
- }
- }
- update_irq(t, 1);
-}
-
-static void hpet_set_timer(HPETTimer *t)
-{
- uint64_t diff;
- uint32_t wrap_diff; /* how many ticks until we wrap? */
- uint64_t cur_tick = hpet_get_ticks(t->state);
-
- /* whenever new timer is being set up, make sure wrap_flag is 0 */
- t->wrap_flag = 0;
- diff = hpet_calculate_diff(t, cur_tick);
-
- /* hpet spec says in one-shot 32-bit mode, generate an interrupt when
- * counter wraps in addition to an interrupt with comparator match.
- */
- if (t->config & HPET_TN_32BIT && !timer_is_periodic(t)) {
- wrap_diff = 0xffffffff - (uint32_t)cur_tick;
- if (wrap_diff < (uint32_t)diff) {
- diff = wrap_diff;
- t->wrap_flag = 1;
- }
- }
- timer_mod(t->qemu_timer,
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + (int64_t)ticks_to_ns(diff));
-}
-
-static void hpet_del_timer(HPETTimer *t)
-{
- timer_del(t->qemu_timer);
- update_irq(t, 0);
-}
-
-#ifdef HPET_DEBUG
-static uint32_t hpet_ram_readb(void *opaque, hwaddr addr)
-{
- printf("qemu: hpet_read b at %" PRIx64 "\n", addr);
- return 0;
-}
-
-static uint32_t hpet_ram_readw(void *opaque, hwaddr addr)
-{
- printf("qemu: hpet_read w at %" PRIx64 "\n", addr);
- return 0;
-}
-#endif
-
-static uint64_t hpet_ram_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- HPETState *s = opaque;
- uint64_t cur_tick, index;
-
- DPRINTF("qemu: Enter hpet_ram_readl at %" PRIx64 "\n", addr);
- index = addr;
- /*address range of all TN regs*/
- if (index >= 0x100 && index <= 0x3ff) {
- uint8_t timer_id = (addr - 0x100) / 0x20;
- HPETTimer *timer = &s->timer[timer_id];
-
- if (timer_id > s->num_timers) {
- DPRINTF("qemu: timer id out of range\n");
- return 0;
- }
-
- switch ((addr - 0x100) % 0x20) {
- case HPET_TN_CFG:
- return timer->config;
- case HPET_TN_CFG + 4: // Interrupt capabilities
- return timer->config >> 32;
- case HPET_TN_CMP: // comparator register
- return timer->cmp;
- case HPET_TN_CMP + 4:
- return timer->cmp >> 32;
- case HPET_TN_ROUTE:
- return timer->fsb;
- case HPET_TN_ROUTE + 4:
- return timer->fsb >> 32;
- default:
- DPRINTF("qemu: invalid hpet_ram_readl\n");
- break;
- }
- } else {
- switch (index) {
- case HPET_ID:
- return s->capability;
- case HPET_PERIOD:
- return s->capability >> 32;
- case HPET_CFG:
- return s->config;
- case HPET_CFG + 4:
- DPRINTF("qemu: invalid HPET_CFG + 4 hpet_ram_readl\n");
- return 0;
- case HPET_COUNTER:
- if (hpet_enabled(s)) {
- cur_tick = hpet_get_ticks(s);
- } else {
- cur_tick = s->hpet_counter;
- }
- DPRINTF("qemu: reading counter = %" PRIx64 "\n", cur_tick);
- return cur_tick;
- case HPET_COUNTER + 4:
- if (hpet_enabled(s)) {
- cur_tick = hpet_get_ticks(s);
- } else {
- cur_tick = s->hpet_counter;
- }
- DPRINTF("qemu: reading counter + 4 = %" PRIx64 "\n", cur_tick);
- return cur_tick >> 32;
- case HPET_STATUS:
- return s->isr;
- default:
- DPRINTF("qemu: invalid hpet_ram_readl\n");
- break;
- }
- }
- return 0;
-}
-
-static void hpet_ram_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- int i;
- HPETState *s = opaque;
- uint64_t old_val, new_val, val, index;
-
- DPRINTF("qemu: Enter hpet_ram_writel at %" PRIx64 " = %#x\n", addr, value);
- index = addr;
- old_val = hpet_ram_read(opaque, addr, 4);
- new_val = value;
-
- /*address range of all TN regs*/
- if (index >= 0x100 && index <= 0x3ff) {
- uint8_t timer_id = (addr - 0x100) / 0x20;
- HPETTimer *timer = &s->timer[timer_id];
-
- DPRINTF("qemu: hpet_ram_writel timer_id = %#x\n", timer_id);
- if (timer_id > s->num_timers) {
- DPRINTF("qemu: timer id out of range\n");
- return;
- }
- switch ((addr - 0x100) % 0x20) {
- case HPET_TN_CFG:
- DPRINTF("qemu: hpet_ram_writel HPET_TN_CFG\n");
- if (activating_bit(old_val, new_val, HPET_TN_FSB_ENABLE)) {
- update_irq(timer, 0);
- }
- val = hpet_fixup_reg(new_val, old_val, HPET_TN_CFG_WRITE_MASK);
- timer->config = (timer->config & 0xffffffff00000000ULL) | val;
- if (new_val & HPET_TN_32BIT) {
- timer->cmp = (uint32_t)timer->cmp;
- timer->period = (uint32_t)timer->period;
- }
- if (activating_bit(old_val, new_val, HPET_TN_ENABLE) &&
- hpet_enabled(s)) {
- hpet_set_timer(timer);
- } else if (deactivating_bit(old_val, new_val, HPET_TN_ENABLE)) {
- hpet_del_timer(timer);
- }
- break;
- case HPET_TN_CFG + 4: // Interrupt capabilities
- DPRINTF("qemu: invalid HPET_TN_CFG+4 write\n");
- break;
- case HPET_TN_CMP: // comparator register
- DPRINTF("qemu: hpet_ram_writel HPET_TN_CMP\n");
- if (timer->config & HPET_TN_32BIT) {
- new_val = (uint32_t)new_val;
- }
- if (!timer_is_periodic(timer)
- || (timer->config & HPET_TN_SETVAL)) {
- timer->cmp = (timer->cmp & 0xffffffff00000000ULL) | new_val;
- }
- if (timer_is_periodic(timer)) {
- /*
- * FIXME: Clamp period to reasonable min value?
- * Clamp period to reasonable max value
- */
- new_val &= (timer->config & HPET_TN_32BIT ? ~0u : ~0ull) >> 1;
- timer->period =
- (timer->period & 0xffffffff00000000ULL) | new_val;
- }
- timer->config &= ~HPET_TN_SETVAL;
- if (hpet_enabled(s)) {
- hpet_set_timer(timer);
- }
- break;
- case HPET_TN_CMP + 4: // comparator register high order
- DPRINTF("qemu: hpet_ram_writel HPET_TN_CMP + 4\n");
- if (!timer_is_periodic(timer)
- || (timer->config & HPET_TN_SETVAL)) {
- timer->cmp = (timer->cmp & 0xffffffffULL) | new_val << 32;
- } else {
- /*
- * FIXME: Clamp period to reasonable min value?
- * Clamp period to reasonable max value
- */
- new_val &= (timer->config & HPET_TN_32BIT ? ~0u : ~0ull) >> 1;
- timer->period =
- (timer->period & 0xffffffffULL) | new_val << 32;
- }
- timer->config &= ~HPET_TN_SETVAL;
- if (hpet_enabled(s)) {
- hpet_set_timer(timer);
- }
- break;
- case HPET_TN_ROUTE:
- timer->fsb = (timer->fsb & 0xffffffff00000000ULL) | new_val;
- break;
- case HPET_TN_ROUTE + 4:
- timer->fsb = (new_val << 32) | (timer->fsb & 0xffffffff);
- break;
- default:
- DPRINTF("qemu: invalid hpet_ram_writel\n");
- break;
- }
- return;
- } else {
- switch (index) {
- case HPET_ID:
- return;
- case HPET_CFG:
- val = hpet_fixup_reg(new_val, old_val, HPET_CFG_WRITE_MASK);
- s->config = (s->config & 0xffffffff00000000ULL) | val;
- if (activating_bit(old_val, new_val, HPET_CFG_ENABLE)) {
- /* Enable main counter and interrupt generation. */
- s->hpet_offset =
- ticks_to_ns(s->hpet_counter) - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- for (i = 0; i < s->num_timers; i++) {
- if ((&s->timer[i])->cmp != ~0ULL) {
- hpet_set_timer(&s->timer[i]);
- }
- }
- } else if (deactivating_bit(old_val, new_val, HPET_CFG_ENABLE)) {
- /* Halt main counter and disable interrupt generation. */
- s->hpet_counter = hpet_get_ticks(s);
- for (i = 0; i < s->num_timers; i++) {
- hpet_del_timer(&s->timer[i]);
- }
- }
- /* i8254 and RTC output pins are disabled
- * when HPET is in legacy mode */
- if (activating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
- qemu_set_irq(s->pit_enabled, 0);
- qemu_irq_lower(s->irqs[0]);
- qemu_irq_lower(s->irqs[RTC_ISA_IRQ]);
- } else if (deactivating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
- qemu_irq_lower(s->irqs[0]);
- qemu_set_irq(s->pit_enabled, 1);
- qemu_set_irq(s->irqs[RTC_ISA_IRQ], s->rtc_irq_level);
- }
- break;
- case HPET_CFG + 4:
- DPRINTF("qemu: invalid HPET_CFG+4 write\n");
- break;
- case HPET_STATUS:
- val = new_val & s->isr;
- for (i = 0; i < s->num_timers; i++) {
- if (val & (1 << i)) {
- update_irq(&s->timer[i], 0);
- }
- }
- break;
- case HPET_COUNTER:
- if (hpet_enabled(s)) {
- DPRINTF("qemu: Writing counter while HPET enabled!\n");
- }
- s->hpet_counter =
- (s->hpet_counter & 0xffffffff00000000ULL) | value;
- DPRINTF("qemu: HPET counter written. ctr = %#x -> %" PRIx64 "\n",
- value, s->hpet_counter);
- break;
- case HPET_COUNTER + 4:
- if (hpet_enabled(s)) {
- DPRINTF("qemu: Writing counter while HPET enabled!\n");
- }
- s->hpet_counter =
- (s->hpet_counter & 0xffffffffULL) | (((uint64_t)value) << 32);
- DPRINTF("qemu: HPET counter + 4 written. ctr = %#x -> %" PRIx64 "\n",
- value, s->hpet_counter);
- break;
- default:
- DPRINTF("qemu: invalid hpet_ram_writel\n");
- break;
- }
- }
-}
-
-static const MemoryRegionOps hpet_ram_ops = {
- .read = hpet_ram_read,
- .write = hpet_ram_write,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void hpet_reset(DeviceState *d)
-{
- HPETState *s = HPET(d);
- SysBusDevice *sbd = SYS_BUS_DEVICE(d);
- int i;
-
- for (i = 0; i < s->num_timers; i++) {
- HPETTimer *timer = &s->timer[i];
-
- hpet_del_timer(timer);
- timer->cmp = ~0ULL;
- timer->config = HPET_TN_PERIODIC_CAP | HPET_TN_SIZE_CAP;
- if (s->flags & (1 << HPET_MSI_SUPPORT)) {
- timer->config |= HPET_TN_FSB_CAP;
- }
- /* advertise availability of ioapic int */
- timer->config |= (uint64_t)s->intcap << 32;
- timer->period = 0ULL;
- timer->wrap_flag = 0;
- }
-
- qemu_set_irq(s->pit_enabled, 1);
- s->hpet_counter = 0ULL;
- s->hpet_offset = 0ULL;
- s->config = 0ULL;
- hpet_cfg.hpet[s->hpet_id].event_timer_block_id = (uint32_t)s->capability;
- hpet_cfg.hpet[s->hpet_id].address = sbd->mmio[0].addr;
-
- /* to document that the RTC lowers its output on reset as well */
- s->rtc_irq_level = 0;
-}
-
-static void hpet_handle_legacy_irq(void *opaque, int n, int level)
-{
- HPETState *s = HPET(opaque);
-
- if (n == HPET_LEGACY_PIT_INT) {
- if (!hpet_in_legacy_mode(s)) {
- qemu_set_irq(s->irqs[0], level);
- }
- } else {
- s->rtc_irq_level = level;
- if (!hpet_in_legacy_mode(s)) {
- qemu_set_irq(s->irqs[RTC_ISA_IRQ], level);
- }
- }
-}
-
-static void hpet_init(Object *obj)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- HPETState *s = HPET(obj);
-
- /* HPET Area */
- memory_region_init_io(&s->iomem, obj, &hpet_ram_ops, s, "hpet", HPET_LEN);
- sysbus_init_mmio(sbd, &s->iomem);
-}
-
-static void hpet_realize(DeviceState *dev, Error **errp)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- HPETState *s = HPET(dev);
- int i;
- HPETTimer *timer;
-
- if (!s->intcap) {
- error_printf("Hpet's intcap not initialized.\n");
- }
- if (hpet_cfg.count == UINT8_MAX) {
- /* first instance */
- hpet_cfg.count = 0;
- }
-
- if (hpet_cfg.count == 8) {
- error_setg(errp, "Only 8 instances of HPET is allowed");
- return;
- }
-
- s->hpet_id = hpet_cfg.count++;
-
- for (i = 0; i < HPET_NUM_IRQ_ROUTES; i++) {
- sysbus_init_irq(sbd, &s->irqs[i]);
- }
-
- if (s->num_timers < HPET_MIN_TIMERS) {
- s->num_timers = HPET_MIN_TIMERS;
- } else if (s->num_timers > HPET_MAX_TIMERS) {
- s->num_timers = HPET_MAX_TIMERS;
- }
- for (i = 0; i < HPET_MAX_TIMERS; i++) {
- timer = &s->timer[i];
- timer->qemu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, hpet_timer, timer);
- timer->tn = i;
- timer->state = s;
- }
-
- /* 64-bit main counter; LegacyReplacementRoute. */
- s->capability = 0x8086a001ULL;
- s->capability |= (s->num_timers - 1) << HPET_ID_NUM_TIM_SHIFT;
- s->capability |= ((uint64_t)(HPET_CLK_PERIOD * FS_PER_NS) << 32);
-
- qdev_init_gpio_in(dev, hpet_handle_legacy_irq, 2);
- qdev_init_gpio_out(dev, &s->pit_enabled, 1);
-}
-
-static Property hpet_device_properties[] = {
- DEFINE_PROP_UINT8("timers", HPETState, num_timers, HPET_MIN_TIMERS),
- DEFINE_PROP_BIT("msi", HPETState, flags, HPET_MSI_SUPPORT, false),
- DEFINE_PROP_UINT32(HPET_INTCAP, HPETState, intcap, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void hpet_device_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = hpet_realize;
- dc->reset = hpet_reset;
- dc->vmsd = &vmstate_hpet;
- dc->props = hpet_device_properties;
-}
-
-static const TypeInfo hpet_device_info = {
- .name = TYPE_HPET,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(HPETState),
- .instance_init = hpet_init,
- .class_init = hpet_device_class_init,
-};
-
-static void hpet_register_types(void)
-{
- type_register_static(&hpet_device_info);
-}
-
-type_init(hpet_register_types)
diff --git a/qemu/hw/timer/i8254.c b/qemu/hw/timer/i8254.c
deleted file mode 100644
index 5e61ad50a..000000000
--- a/qemu/hw/timer/i8254.c
+++ /dev/null
@@ -1,384 +0,0 @@
-/*
- * QEMU 8253/8254 interval timer emulation
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/i386/pc.h"
-#include "hw/isa/isa.h"
-#include "qemu/timer.h"
-#include "hw/timer/i8254.h"
-#include "hw/timer/i8254_internal.h"
-
-//#define DEBUG_PIT
-
-#define RW_STATE_LSB 1
-#define RW_STATE_MSB 2
-#define RW_STATE_WORD0 3
-#define RW_STATE_WORD1 4
-
-#define PIT_CLASS(class) OBJECT_CLASS_CHECK(PITClass, (class), TYPE_I8254)
-#define PIT_GET_CLASS(obj) OBJECT_GET_CLASS(PITClass, (obj), TYPE_I8254)
-
-typedef struct PITClass {
- PITCommonClass parent_class;
-
- DeviceRealize parent_realize;
-} PITClass;
-
-static void pit_irq_timer_update(PITChannelState *s, int64_t current_time);
-
-static int pit_get_count(PITChannelState *s)
-{
- uint64_t d;
- int counter;
-
- d = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - s->count_load_time, PIT_FREQ,
- NANOSECONDS_PER_SECOND);
- switch(s->mode) {
- case 0:
- case 1:
- case 4:
- case 5:
- counter = (s->count - d) & 0xffff;
- break;
- case 3:
- /* XXX: may be incorrect for odd counts */
- counter = s->count - ((2 * d) % s->count);
- break;
- default:
- counter = s->count - (d % s->count);
- break;
- }
- return counter;
-}
-
-/* val must be 0 or 1 */
-static void pit_set_channel_gate(PITCommonState *s, PITChannelState *sc,
- int val)
-{
- switch (sc->mode) {
- default:
- case 0:
- case 4:
- /* XXX: just disable/enable counting */
- break;
- case 1:
- case 5:
- if (sc->gate < val) {
- /* restart counting on rising edge */
- sc->count_load_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- pit_irq_timer_update(sc, sc->count_load_time);
- }
- break;
- case 2:
- case 3:
- if (sc->gate < val) {
- /* restart counting on rising edge */
- sc->count_load_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- pit_irq_timer_update(sc, sc->count_load_time);
- }
- /* XXX: disable/enable counting */
- break;
- }
- sc->gate = val;
-}
-
-static inline void pit_load_count(PITChannelState *s, int val)
-{
- if (val == 0)
- val = 0x10000;
- s->count_load_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- s->count = val;
- pit_irq_timer_update(s, s->count_load_time);
-}
-
-/* if already latched, do not latch again */
-static void pit_latch_count(PITChannelState *s)
-{
- if (!s->count_latched) {
- s->latched_count = pit_get_count(s);
- s->count_latched = s->rw_mode;
- }
-}
-
-static void pit_ioport_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- PITCommonState *pit = opaque;
- int channel, access;
- PITChannelState *s;
-
- addr &= 3;
- if (addr == 3) {
- channel = val >> 6;
- if (channel == 3) {
- /* read back command */
- for(channel = 0; channel < 3; channel++) {
- s = &pit->channels[channel];
- if (val & (2 << channel)) {
- if (!(val & 0x20)) {
- pit_latch_count(s);
- }
- if (!(val & 0x10) && !s->status_latched) {
- /* status latch */
- /* XXX: add BCD and null count */
- s->status =
- (pit_get_out(s,
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)) << 7) |
- (s->rw_mode << 4) |
- (s->mode << 1) |
- s->bcd;
- s->status_latched = 1;
- }
- }
- }
- } else {
- s = &pit->channels[channel];
- access = (val >> 4) & 3;
- if (access == 0) {
- pit_latch_count(s);
- } else {
- s->rw_mode = access;
- s->read_state = access;
- s->write_state = access;
-
- s->mode = (val >> 1) & 7;
- s->bcd = val & 1;
- /* XXX: update irq timer ? */
- }
- }
- } else {
- s = &pit->channels[addr];
- switch(s->write_state) {
- default:
- case RW_STATE_LSB:
- pit_load_count(s, val);
- break;
- case RW_STATE_MSB:
- pit_load_count(s, val << 8);
- break;
- case RW_STATE_WORD0:
- s->write_latch = val;
- s->write_state = RW_STATE_WORD1;
- break;
- case RW_STATE_WORD1:
- pit_load_count(s, s->write_latch | (val << 8));
- s->write_state = RW_STATE_WORD0;
- break;
- }
- }
-}
-
-static uint64_t pit_ioport_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- PITCommonState *pit = opaque;
- int ret, count;
- PITChannelState *s;
-
- addr &= 3;
-
- if (addr == 3) {
- /* Mode/Command register is write only, read is ignored */
- return 0;
- }
-
- s = &pit->channels[addr];
- if (s->status_latched) {
- s->status_latched = 0;
- ret = s->status;
- } else if (s->count_latched) {
- switch(s->count_latched) {
- default:
- case RW_STATE_LSB:
- ret = s->latched_count & 0xff;
- s->count_latched = 0;
- break;
- case RW_STATE_MSB:
- ret = s->latched_count >> 8;
- s->count_latched = 0;
- break;
- case RW_STATE_WORD0:
- ret = s->latched_count & 0xff;
- s->count_latched = RW_STATE_MSB;
- break;
- }
- } else {
- switch(s->read_state) {
- default:
- case RW_STATE_LSB:
- count = pit_get_count(s);
- ret = count & 0xff;
- break;
- case RW_STATE_MSB:
- count = pit_get_count(s);
- ret = (count >> 8) & 0xff;
- break;
- case RW_STATE_WORD0:
- count = pit_get_count(s);
- ret = count & 0xff;
- s->read_state = RW_STATE_WORD1;
- break;
- case RW_STATE_WORD1:
- count = pit_get_count(s);
- ret = (count >> 8) & 0xff;
- s->read_state = RW_STATE_WORD0;
- break;
- }
- }
- return ret;
-}
-
-static void pit_irq_timer_update(PITChannelState *s, int64_t current_time)
-{
- int64_t expire_time;
- int irq_level;
-
- if (!s->irq_timer || s->irq_disabled) {
- return;
- }
- expire_time = pit_get_next_transition_time(s, current_time);
- irq_level = pit_get_out(s, current_time);
- qemu_set_irq(s->irq, irq_level);
-#ifdef DEBUG_PIT
- printf("irq_level=%d next_delay=%f\n",
- irq_level,
- (double)(expire_time - current_time) / NANOSECONDS_PER_SECOND);
-#endif
- s->next_transition_time = expire_time;
- if (expire_time != -1)
- timer_mod(s->irq_timer, expire_time);
- else
- timer_del(s->irq_timer);
-}
-
-static void pit_irq_timer(void *opaque)
-{
- PITChannelState *s = opaque;
-
- pit_irq_timer_update(s, s->next_transition_time);
-}
-
-static void pit_reset(DeviceState *dev)
-{
- PITCommonState *pit = PIT_COMMON(dev);
- PITChannelState *s;
-
- pit_reset_common(pit);
-
- s = &pit->channels[0];
- if (!s->irq_disabled) {
- timer_mod(s->irq_timer, s->next_transition_time);
- }
-}
-
-/* When HPET is operating in legacy mode, suppress the ignored timer IRQ,
- * reenable it when legacy mode is left again. */
-static void pit_irq_control(void *opaque, int n, int enable)
-{
- PITCommonState *pit = opaque;
- PITChannelState *s = &pit->channels[0];
-
- if (enable) {
- s->irq_disabled = 0;
- pit_irq_timer_update(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
- } else {
- s->irq_disabled = 1;
- timer_del(s->irq_timer);
- }
-}
-
-static const MemoryRegionOps pit_ioport_ops = {
- .read = pit_ioport_read,
- .write = pit_ioport_write,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void pit_post_load(PITCommonState *s)
-{
- PITChannelState *sc = &s->channels[0];
-
- if (sc->next_transition_time != -1) {
- timer_mod(sc->irq_timer, sc->next_transition_time);
- } else {
- timer_del(sc->irq_timer);
- }
-}
-
-static void pit_realizefn(DeviceState *dev, Error **errp)
-{
- PITCommonState *pit = PIT_COMMON(dev);
- PITClass *pc = PIT_GET_CLASS(dev);
- PITChannelState *s;
-
- s = &pit->channels[0];
- /* the timer 0 is connected to an IRQ */
- s->irq_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, pit_irq_timer, s);
- qdev_init_gpio_out(dev, &s->irq, 1);
-
- memory_region_init_io(&pit->ioports, OBJECT(pit), &pit_ioport_ops,
- pit, "pit", 4);
-
- qdev_init_gpio_in(dev, pit_irq_control, 1);
-
- pc->parent_realize(dev, errp);
-}
-
-static Property pit_properties[] = {
- DEFINE_PROP_UINT32("iobase", PITCommonState, iobase, -1),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pit_class_initfn(ObjectClass *klass, void *data)
-{
- PITClass *pc = PIT_CLASS(klass);
- PITCommonClass *k = PIT_COMMON_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- pc->parent_realize = dc->realize;
- dc->realize = pit_realizefn;
- k->set_channel_gate = pit_set_channel_gate;
- k->get_channel_info = pit_get_channel_info_common;
- k->post_load = pit_post_load;
- dc->reset = pit_reset;
- dc->props = pit_properties;
-}
-
-static const TypeInfo pit_info = {
- .name = TYPE_I8254,
- .parent = TYPE_PIT_COMMON,
- .instance_size = sizeof(PITCommonState),
- .class_init = pit_class_initfn,
- .class_size = sizeof(PITClass),
-};
-
-static void pit_register_types(void)
-{
- type_register_static(&pit_info);
-}
-
-type_init(pit_register_types)
diff --git a/qemu/hw/timer/i8254_common.c b/qemu/hw/timer/i8254_common.c
deleted file mode 100644
index e18299a48..000000000
--- a/qemu/hw/timer/i8254_common.c
+++ /dev/null
@@ -1,307 +0,0 @@
-/*
- * QEMU 8253/8254 - common bits of emulated and KVM kernel model
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- * Copyright (c) 2012 Jan Kiszka, Siemens AG
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/i386/pc.h"
-#include "hw/isa/isa.h"
-#include "qemu/timer.h"
-#include "hw/timer/i8254.h"
-#include "hw/timer/i8254_internal.h"
-
-/* val must be 0 or 1 */
-void pit_set_gate(ISADevice *dev, int channel, int val)
-{
- PITCommonState *pit = PIT_COMMON(dev);
- PITChannelState *s = &pit->channels[channel];
- PITCommonClass *c = PIT_COMMON_GET_CLASS(pit);
-
- c->set_channel_gate(pit, s, val);
-}
-
-/* get pit output bit */
-int pit_get_out(PITChannelState *s, int64_t current_time)
-{
- uint64_t d;
- int out;
-
- d = muldiv64(current_time - s->count_load_time, PIT_FREQ,
- NANOSECONDS_PER_SECOND);
- switch (s->mode) {
- default:
- case 0:
- out = (d >= s->count);
- break;
- case 1:
- out = (d < s->count);
- break;
- case 2:
- if ((d % s->count) == 0 && d != 0) {
- out = 1;
- } else {
- out = 0;
- }
- break;
- case 3:
- out = (d % s->count) < ((s->count + 1) >> 1);
- break;
- case 4:
- case 5:
- out = (d == s->count);
- break;
- }
- return out;
-}
-
-/* return -1 if no transition will occur. */
-int64_t pit_get_next_transition_time(PITChannelState *s, int64_t current_time)
-{
- uint64_t d, next_time, base;
- int period2;
-
- d = muldiv64(current_time - s->count_load_time, PIT_FREQ,
- NANOSECONDS_PER_SECOND);
- switch (s->mode) {
- default:
- case 0:
- case 1:
- if (d < s->count) {
- next_time = s->count;
- } else {
- return -1;
- }
- break;
- case 2:
- base = (d / s->count) * s->count;
- if ((d - base) == 0 && d != 0) {
- next_time = base + s->count;
- } else {
- next_time = base + s->count + 1;
- }
- break;
- case 3:
- base = (d / s->count) * s->count;
- period2 = ((s->count + 1) >> 1);
- if ((d - base) < period2) {
- next_time = base + period2;
- } else {
- next_time = base + s->count;
- }
- break;
- case 4:
- case 5:
- if (d < s->count) {
- next_time = s->count;
- } else if (d == s->count) {
- next_time = s->count + 1;
- } else {
- return -1;
- }
- break;
- }
- /* convert to timer units */
- next_time = s->count_load_time + muldiv64(next_time, NANOSECONDS_PER_SECOND,
- PIT_FREQ);
- /* fix potential rounding problems */
- /* XXX: better solution: use a clock at PIT_FREQ Hz */
- if (next_time <= current_time) {
- next_time = current_time + 1;
- }
- return next_time;
-}
-
-void pit_get_channel_info_common(PITCommonState *s, PITChannelState *sc,
- PITChannelInfo *info)
-{
- info->gate = sc->gate;
- info->mode = sc->mode;
- info->initial_count = sc->count;
- info->out = pit_get_out(sc, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
-}
-
-void pit_get_channel_info(ISADevice *dev, int channel, PITChannelInfo *info)
-{
- PITCommonState *pit = PIT_COMMON(dev);
- PITChannelState *s = &pit->channels[channel];
- PITCommonClass *c = PIT_COMMON_GET_CLASS(pit);
-
- c->get_channel_info(pit, s, info);
-}
-
-void pit_reset_common(PITCommonState *pit)
-{
- PITChannelState *s;
- int i;
-
- for (i = 0; i < 3; i++) {
- s = &pit->channels[i];
- s->mode = 3;
- s->gate = (i != 2);
- s->count_load_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- s->count = 0x10000;
- if (i == 0 && !s->irq_disabled) {
- s->next_transition_time =
- pit_get_next_transition_time(s, s->count_load_time);
- }
- }
-}
-
-static void pit_common_realize(DeviceState *dev, Error **errp)
-{
- ISADevice *isadev = ISA_DEVICE(dev);
- PITCommonState *pit = PIT_COMMON(dev);
-
- isa_register_ioport(isadev, &pit->ioports, pit->iobase);
-
- qdev_set_legacy_instance_id(dev, pit->iobase, 2);
-}
-
-static const VMStateDescription vmstate_pit_channel = {
- .name = "pit channel",
- .version_id = 2,
- .minimum_version_id = 2,
- .fields = (VMStateField[]) {
- VMSTATE_INT32(count, PITChannelState),
- VMSTATE_UINT16(latched_count, PITChannelState),
- VMSTATE_UINT8(count_latched, PITChannelState),
- VMSTATE_UINT8(status_latched, PITChannelState),
- VMSTATE_UINT8(status, PITChannelState),
- VMSTATE_UINT8(read_state, PITChannelState),
- VMSTATE_UINT8(write_state, PITChannelState),
- VMSTATE_UINT8(write_latch, PITChannelState),
- VMSTATE_UINT8(rw_mode, PITChannelState),
- VMSTATE_UINT8(mode, PITChannelState),
- VMSTATE_UINT8(bcd, PITChannelState),
- VMSTATE_UINT8(gate, PITChannelState),
- VMSTATE_INT64(count_load_time, PITChannelState),
- VMSTATE_INT64(next_transition_time, PITChannelState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static int pit_load_old(QEMUFile *f, void *opaque, int version_id)
-{
- PITCommonState *pit = opaque;
- PITCommonClass *c = PIT_COMMON_GET_CLASS(pit);
- PITChannelState *s;
- int i;
-
- if (version_id != 1) {
- return -EINVAL;
- }
-
- for (i = 0; i < 3; i++) {
- s = &pit->channels[i];
- s->count = qemu_get_be32(f);
- qemu_get_be16s(f, &s->latched_count);
- qemu_get_8s(f, &s->count_latched);
- qemu_get_8s(f, &s->status_latched);
- qemu_get_8s(f, &s->status);
- qemu_get_8s(f, &s->read_state);
- qemu_get_8s(f, &s->write_state);
- qemu_get_8s(f, &s->write_latch);
- qemu_get_8s(f, &s->rw_mode);
- qemu_get_8s(f, &s->mode);
- qemu_get_8s(f, &s->bcd);
- qemu_get_8s(f, &s->gate);
- s->count_load_time = qemu_get_be64(f);
- s->irq_disabled = 0;
- if (i == 0) {
- s->next_transition_time = qemu_get_be64(f);
- }
- }
- if (c->post_load) {
- c->post_load(pit);
- }
- return 0;
-}
-
-static void pit_dispatch_pre_save(void *opaque)
-{
- PITCommonState *s = opaque;
- PITCommonClass *c = PIT_COMMON_GET_CLASS(s);
-
- if (c->pre_save) {
- c->pre_save(s);
- }
-}
-
-static int pit_dispatch_post_load(void *opaque, int version_id)
-{
- PITCommonState *s = opaque;
- PITCommonClass *c = PIT_COMMON_GET_CLASS(s);
-
- if (c->post_load) {
- c->post_load(s);
- }
- return 0;
-}
-
-static const VMStateDescription vmstate_pit_common = {
- .name = "i8254",
- .version_id = 3,
- .minimum_version_id = 2,
- .minimum_version_id_old = 1,
- .load_state_old = pit_load_old,
- .pre_save = pit_dispatch_pre_save,
- .post_load = pit_dispatch_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_V(channels[0].irq_disabled, PITCommonState, 3),
- VMSTATE_STRUCT_ARRAY(channels, PITCommonState, 3, 2,
- vmstate_pit_channel, PITChannelState),
- VMSTATE_INT64(channels[0].next_transition_time,
- PITCommonState), /* formerly irq_timer */
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void pit_common_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = pit_common_realize;
- dc->vmsd = &vmstate_pit_common;
- /*
- * Reason: unlike ordinary ISA devices, the PIT may need to be
- * wired to the HPET, and because of that, some wiring is always
- * done by board code.
- */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static const TypeInfo pit_common_type = {
- .name = TYPE_PIT_COMMON,
- .parent = TYPE_ISA_DEVICE,
- .instance_size = sizeof(PITCommonState),
- .class_size = sizeof(PITCommonClass),
- .class_init = pit_common_class_init,
- .abstract = true,
-};
-
-static void register_devices(void)
-{
- type_register_static(&pit_common_type);
-}
-
-type_init(register_devices);
diff --git a/qemu/hw/timer/imx_epit.c b/qemu/hw/timer/imx_epit.c
deleted file mode 100644
index f5836e21f..000000000
--- a/qemu/hw/timer/imx_epit.c
+++ /dev/null
@@ -1,344 +0,0 @@
-/*
- * IMX EPIT Timer
- *
- * Copyright (c) 2008 OK Labs
- * Copyright (c) 2011 NICTA Pty Ltd
- * Originally written by Hans Jiang
- * Updated by Peter Chubb
- * Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
- *
- * This code is licensed under GPL version 2 or later. See
- * the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "hw/timer/imx_epit.h"
-#include "hw/misc/imx_ccm.h"
-#include "qemu/main-loop.h"
-
-#ifndef DEBUG_IMX_EPIT
-#define DEBUG_IMX_EPIT 0
-#endif
-
-#define DPRINTF(fmt, args...) \
- do { \
- if (DEBUG_IMX_EPIT) { \
- fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_EPIT, \
- __func__, ##args); \
- } \
- } while (0)
-
-static char const *imx_epit_reg_name(uint32_t reg)
-{
- switch (reg) {
- case 0:
- return "CR";
- case 1:
- return "SR";
- case 2:
- return "LR";
- case 3:
- return "CMP";
- case 4:
- return "CNT";
- default:
- return "[?]";
- }
-}
-
-/*
- * Exact clock frequencies vary from board to board.
- * These are typical.
- */
-static const IMXClk imx_epit_clocks[] = {
- CLK_NONE, /* 00 disabled */
- CLK_IPG, /* 01 ipg_clk, ~532MHz */
- CLK_IPG_HIGH, /* 10 ipg_clk_highfreq */
- CLK_32k, /* 11 ipg_clk_32k -- ~32kHz */
-};
-
-/*
- * Update interrupt status
- */
-static void imx_epit_update_int(IMXEPITState *s)
-{
- if (s->sr && (s->cr & CR_OCIEN) && (s->cr & CR_EN)) {
- qemu_irq_raise(s->irq);
- } else {
- qemu_irq_lower(s->irq);
- }
-}
-
-static void imx_epit_set_freq(IMXEPITState *s)
-{
- uint32_t clksrc;
- uint32_t prescaler;
-
- clksrc = extract32(s->cr, CR_CLKSRC_SHIFT, 2);
- prescaler = 1 + extract32(s->cr, CR_PRESCALE_SHIFT, 12);
-
- s->freq = imx_ccm_get_clock_frequency(s->ccm,
- imx_epit_clocks[clksrc]) / prescaler;
-
- DPRINTF("Setting ptimer frequency to %u\n", s->freq);
-
- if (s->freq) {
- ptimer_set_freq(s->timer_reload, s->freq);
- ptimer_set_freq(s->timer_cmp, s->freq);
- }
-}
-
-static void imx_epit_reset(DeviceState *dev)
-{
- IMXEPITState *s = IMX_EPIT(dev);
-
- /*
- * Soft reset doesn't touch some bits; hard reset clears them
- */
- s->cr &= (CR_EN|CR_ENMOD|CR_STOPEN|CR_DOZEN|CR_WAITEN|CR_DBGEN);
- s->sr = 0;
- s->lr = EPIT_TIMER_MAX;
- s->cmp = 0;
- s->cnt = 0;
- /* stop both timers */
- ptimer_stop(s->timer_cmp);
- ptimer_stop(s->timer_reload);
- /* compute new frequency */
- imx_epit_set_freq(s);
- /* init both timers to EPIT_TIMER_MAX */
- ptimer_set_limit(s->timer_cmp, EPIT_TIMER_MAX, 1);
- ptimer_set_limit(s->timer_reload, EPIT_TIMER_MAX, 1);
- if (s->freq && (s->cr & CR_EN)) {
- /* if the timer is still enabled, restart it */
- ptimer_run(s->timer_reload, 0);
- }
-}
-
-static uint32_t imx_epit_update_count(IMXEPITState *s)
-{
- s->cnt = ptimer_get_count(s->timer_reload);
-
- return s->cnt;
-}
-
-static uint64_t imx_epit_read(void *opaque, hwaddr offset, unsigned size)
-{
- IMXEPITState *s = IMX_EPIT(opaque);
- uint32_t reg_value = 0;
-
- switch (offset >> 2) {
- case 0: /* Control Register */
- reg_value = s->cr;
- break;
-
- case 1: /* Status Register */
- reg_value = s->sr;
- break;
-
- case 2: /* LR - ticks*/
- reg_value = s->lr;
- break;
-
- case 3: /* CMP */
- reg_value = s->cmp;
- break;
-
- case 4: /* CNT */
- imx_epit_update_count(s);
- reg_value = s->cnt;
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
- HWADDR_PRIx "\n", TYPE_IMX_EPIT, __func__, offset);
- break;
- }
-
- DPRINTF("(%s) = 0x%08x\n", imx_epit_reg_name(offset >> 2), reg_value);
-
- return reg_value;
-}
-
-static void imx_epit_reload_compare_timer(IMXEPITState *s)
-{
- if ((s->cr & (CR_EN | CR_OCIEN)) == (CR_EN | CR_OCIEN)) {
- /* if the compare feature is on and timers are running */
- uint32_t tmp = imx_epit_update_count(s);
- uint64_t next;
- if (tmp > s->cmp) {
- /* It'll fire in this round of the timer */
- next = tmp - s->cmp;
- } else { /* catch it next time around */
- next = tmp - s->cmp + ((s->cr & CR_RLD) ? EPIT_TIMER_MAX : s->lr);
- }
- ptimer_set_count(s->timer_cmp, next);
- }
-}
-
-static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value,
- unsigned size)
-{
- IMXEPITState *s = IMX_EPIT(opaque);
- uint64_t oldcr;
-
- DPRINTF("(%s, value = 0x%08x)\n", imx_epit_reg_name(offset >> 2),
- (uint32_t)value);
-
- switch (offset >> 2) {
- case 0: /* CR */
-
- oldcr = s->cr;
- s->cr = value & 0x03ffffff;
- if (s->cr & CR_SWR) {
- /* handle the reset */
- imx_epit_reset(DEVICE(s));
- } else {
- imx_epit_set_freq(s);
- }
-
- if (s->freq && (s->cr & CR_EN) && !(oldcr & CR_EN)) {
- if (s->cr & CR_ENMOD) {
- if (s->cr & CR_RLD) {
- ptimer_set_limit(s->timer_reload, s->lr, 1);
- ptimer_set_limit(s->timer_cmp, s->lr, 1);
- } else {
- ptimer_set_limit(s->timer_reload, EPIT_TIMER_MAX, 1);
- ptimer_set_limit(s->timer_cmp, EPIT_TIMER_MAX, 1);
- }
- }
-
- imx_epit_reload_compare_timer(s);
- ptimer_run(s->timer_reload, 0);
- if (s->cr & CR_OCIEN) {
- ptimer_run(s->timer_cmp, 0);
- } else {
- ptimer_stop(s->timer_cmp);
- }
- } else if (!(s->cr & CR_EN)) {
- /* stop both timers */
- ptimer_stop(s->timer_reload);
- ptimer_stop(s->timer_cmp);
- } else if (s->cr & CR_OCIEN) {
- if (!(oldcr & CR_OCIEN)) {
- imx_epit_reload_compare_timer(s);
- ptimer_run(s->timer_cmp, 0);
- }
- } else {
- ptimer_stop(s->timer_cmp);
- }
- break;
-
- case 1: /* SR - ACK*/
- /* writing 1 to OCIF clear the OCIF bit */
- if (value & 0x01) {
- s->sr = 0;
- imx_epit_update_int(s);
- }
- break;
-
- case 2: /* LR - set ticks */
- s->lr = value;
-
- if (s->cr & CR_RLD) {
- /* Also set the limit if the LRD bit is set */
- /* If IOVW bit is set then set the timer value */
- ptimer_set_limit(s->timer_reload, s->lr, s->cr & CR_IOVW);
- ptimer_set_limit(s->timer_cmp, s->lr, 0);
- } else if (s->cr & CR_IOVW) {
- /* If IOVW bit is set then set the timer value */
- ptimer_set_count(s->timer_reload, s->lr);
- }
-
- imx_epit_reload_compare_timer(s);
- break;
-
- case 3: /* CMP */
- s->cmp = value;
-
- imx_epit_reload_compare_timer(s);
-
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
- HWADDR_PRIx "\n", TYPE_IMX_EPIT, __func__, offset);
-
- break;
- }
-}
-static void imx_epit_cmp(void *opaque)
-{
- IMXEPITState *s = IMX_EPIT(opaque);
-
- DPRINTF("sr was %d\n", s->sr);
-
- s->sr = 1;
- imx_epit_update_int(s);
-}
-
-static const MemoryRegionOps imx_epit_ops = {
- .read = imx_epit_read,
- .write = imx_epit_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_imx_timer_epit = {
- .name = TYPE_IMX_EPIT,
- .version_id = 2,
- .minimum_version_id = 2,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(cr, IMXEPITState),
- VMSTATE_UINT32(sr, IMXEPITState),
- VMSTATE_UINT32(lr, IMXEPITState),
- VMSTATE_UINT32(cmp, IMXEPITState),
- VMSTATE_UINT32(cnt, IMXEPITState),
- VMSTATE_UINT32(freq, IMXEPITState),
- VMSTATE_PTIMER(timer_reload, IMXEPITState),
- VMSTATE_PTIMER(timer_cmp, IMXEPITState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void imx_epit_realize(DeviceState *dev, Error **errp)
-{
- IMXEPITState *s = IMX_EPIT(dev);
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- QEMUBH *bh;
-
- DPRINTF("\n");
-
- sysbus_init_irq(sbd, &s->irq);
- memory_region_init_io(&s->iomem, OBJECT(s), &imx_epit_ops, s, TYPE_IMX_EPIT,
- 0x00001000);
- sysbus_init_mmio(sbd, &s->iomem);
-
- s->timer_reload = ptimer_init(NULL);
-
- bh = qemu_bh_new(imx_epit_cmp, s);
- s->timer_cmp = ptimer_init(bh);
-}
-
-static void imx_epit_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = imx_epit_realize;
- dc->reset = imx_epit_reset;
- dc->vmsd = &vmstate_imx_timer_epit;
- dc->desc = "i.MX periodic timer";
-}
-
-static const TypeInfo imx_epit_info = {
- .name = TYPE_IMX_EPIT,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(IMXEPITState),
- .class_init = imx_epit_class_init,
-};
-
-static void imx_epit_register_types(void)
-{
- type_register_static(&imx_epit_info);
-}
-
-type_init(imx_epit_register_types)
diff --git a/qemu/hw/timer/imx_gpt.c b/qemu/hw/timer/imx_gpt.c
deleted file mode 100644
index ab2e213a1..000000000
--- a/qemu/hw/timer/imx_gpt.c
+++ /dev/null
@@ -1,467 +0,0 @@
-/*
- * IMX GPT Timer
- *
- * Copyright (c) 2008 OK Labs
- * Copyright (c) 2011 NICTA Pty Ltd
- * Originally written by Hans Jiang
- * Updated by Peter Chubb
- * Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
- *
- * This code is licensed under GPL version 2 or later. See
- * the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "hw/timer/imx_gpt.h"
-#include "hw/misc/imx_ccm.h"
-#include "qemu/main-loop.h"
-
-#ifndef DEBUG_IMX_GPT
-#define DEBUG_IMX_GPT 0
-#endif
-
-#define DPRINTF(fmt, args...) \
- do { \
- if (DEBUG_IMX_GPT) { \
- fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_GPT, \
- __func__, ##args); \
- } \
- } while (0)
-
-static char const *imx_gpt_reg_name(uint32_t reg)
-{
- switch (reg) {
- case 0:
- return "CR";
- case 1:
- return "PR";
- case 2:
- return "SR";
- case 3:
- return "IR";
- case 4:
- return "OCR1";
- case 5:
- return "OCR2";
- case 6:
- return "OCR3";
- case 7:
- return "ICR1";
- case 8:
- return "ICR2";
- case 9:
- return "CNT";
- default:
- return "[?]";
- }
-}
-
-static const VMStateDescription vmstate_imx_timer_gpt = {
- .name = TYPE_IMX_GPT,
- .version_id = 3,
- .minimum_version_id = 3,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(cr, IMXGPTState),
- VMSTATE_UINT32(pr, IMXGPTState),
- VMSTATE_UINT32(sr, IMXGPTState),
- VMSTATE_UINT32(ir, IMXGPTState),
- VMSTATE_UINT32(ocr1, IMXGPTState),
- VMSTATE_UINT32(ocr2, IMXGPTState),
- VMSTATE_UINT32(ocr3, IMXGPTState),
- VMSTATE_UINT32(icr1, IMXGPTState),
- VMSTATE_UINT32(icr2, IMXGPTState),
- VMSTATE_UINT32(cnt, IMXGPTState),
- VMSTATE_UINT32(next_timeout, IMXGPTState),
- VMSTATE_UINT32(next_int, IMXGPTState),
- VMSTATE_UINT32(freq, IMXGPTState),
- VMSTATE_PTIMER(timer, IMXGPTState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const IMXClk imx_gpt_clocks[] = {
- CLK_NONE, /* 000 No clock source */
- CLK_IPG, /* 001 ipg_clk, 532MHz*/
- CLK_IPG_HIGH, /* 010 ipg_clk_highfreq */
- CLK_NONE, /* 011 not defined */
- CLK_32k, /* 100 ipg_clk_32k */
- CLK_NONE, /* 101 not defined */
- CLK_NONE, /* 110 not defined */
- CLK_NONE, /* 111 not defined */
-};
-
-static void imx_gpt_set_freq(IMXGPTState *s)
-{
- uint32_t clksrc = extract32(s->cr, GPT_CR_CLKSRC_SHIFT, 3);
-
- s->freq = imx_ccm_get_clock_frequency(s->ccm,
- imx_gpt_clocks[clksrc]) / (1 + s->pr);
-
- DPRINTF("Setting clksrc %d to frequency %d\n", clksrc, s->freq);
-
- if (s->freq) {
- ptimer_set_freq(s->timer, s->freq);
- }
-}
-
-static void imx_gpt_update_int(IMXGPTState *s)
-{
- if ((s->sr & s->ir) && (s->cr & GPT_CR_EN)) {
- qemu_irq_raise(s->irq);
- } else {
- qemu_irq_lower(s->irq);
- }
-}
-
-static uint32_t imx_gpt_update_count(IMXGPTState *s)
-{
- s->cnt = s->next_timeout - (uint32_t)ptimer_get_count(s->timer);
-
- return s->cnt;
-}
-
-static inline uint32_t imx_gpt_find_limit(uint32_t count, uint32_t reg,
- uint32_t timeout)
-{
- if ((count < reg) && (timeout > reg)) {
- timeout = reg;
- }
-
- return timeout;
-}
-
-static void imx_gpt_compute_next_timeout(IMXGPTState *s, bool event)
-{
- uint32_t timeout = GPT_TIMER_MAX;
- uint32_t count;
- long long limit;
-
- if (!(s->cr & GPT_CR_EN)) {
- /* if not enabled just return */
- return;
- }
-
- /* update the count */
- count = imx_gpt_update_count(s);
-
- if (event) {
- /*
- * This is an event (the ptimer reached 0 and stopped), and the
- * timer counter is now equal to s->next_timeout.
- */
- if (!(s->cr & GPT_CR_FRR) && (count == s->ocr1)) {
- /* We are in restart mode and we crossed the compare channel 1
- * value. We need to reset the counter to 0.
- */
- count = s->cnt = s->next_timeout = 0;
- } else if (count == GPT_TIMER_MAX) {
- /* We reached GPT_TIMER_MAX so we need to rollover */
- count = s->cnt = s->next_timeout = 0;
- }
- }
-
- /* now, find the next timeout related to count */
-
- if (s->ir & GPT_IR_OF1IE) {
- timeout = imx_gpt_find_limit(count, s->ocr1, timeout);
- }
- if (s->ir & GPT_IR_OF2IE) {
- timeout = imx_gpt_find_limit(count, s->ocr2, timeout);
- }
- if (s->ir & GPT_IR_OF3IE) {
- timeout = imx_gpt_find_limit(count, s->ocr3, timeout);
- }
-
- /* find the next set of interrupts to raise for next timer event */
-
- s->next_int = 0;
- if ((s->ir & GPT_IR_OF1IE) && (timeout == s->ocr1)) {
- s->next_int |= GPT_SR_OF1;
- }
- if ((s->ir & GPT_IR_OF2IE) && (timeout == s->ocr2)) {
- s->next_int |= GPT_SR_OF2;
- }
- if ((s->ir & GPT_IR_OF3IE) && (timeout == s->ocr3)) {
- s->next_int |= GPT_SR_OF3;
- }
- if ((s->ir & GPT_IR_ROVIE) && (timeout == GPT_TIMER_MAX)) {
- s->next_int |= GPT_SR_ROV;
- }
-
- /* the new range to count down from */
- limit = timeout - imx_gpt_update_count(s);
-
- if (limit < 0) {
- /*
- * if we reach here, then QEMU is running too slow and we pass the
- * timeout limit while computing it. Let's deliver the interrupt
- * and compute a new limit.
- */
- s->sr |= s->next_int;
-
- imx_gpt_compute_next_timeout(s, event);
-
- imx_gpt_update_int(s);
- } else {
- /* New timeout value */
- s->next_timeout = timeout;
-
- /* reset the limit to the computed range */
- ptimer_set_limit(s->timer, limit, 1);
- }
-}
-
-static uint64_t imx_gpt_read(void *opaque, hwaddr offset, unsigned size)
-{
- IMXGPTState *s = IMX_GPT(opaque);
- uint32_t reg_value = 0;
-
- switch (offset >> 2) {
- case 0: /* Control Register */
- reg_value = s->cr;
- break;
-
- case 1: /* prescaler */
- reg_value = s->pr;
- break;
-
- case 2: /* Status Register */
- reg_value = s->sr;
- break;
-
- case 3: /* Interrupt Register */
- reg_value = s->ir;
- break;
-
- case 4: /* Output Compare Register 1 */
- reg_value = s->ocr1;
- break;
-
- case 5: /* Output Compare Register 2 */
- reg_value = s->ocr2;
- break;
-
- case 6: /* Output Compare Register 3 */
- reg_value = s->ocr3;
- break;
-
- case 7: /* input Capture Register 1 */
- qemu_log_mask(LOG_UNIMP, "[%s]%s: icr1 feature is not implemented\n",
- TYPE_IMX_GPT, __func__);
- reg_value = s->icr1;
- break;
-
- case 8: /* input Capture Register 2 */
- qemu_log_mask(LOG_UNIMP, "[%s]%s: icr2 feature is not implemented\n",
- TYPE_IMX_GPT, __func__);
- reg_value = s->icr2;
- break;
-
- case 9: /* cnt */
- imx_gpt_update_count(s);
- reg_value = s->cnt;
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
- HWADDR_PRIx "\n", TYPE_IMX_GPT, __func__, offset);
- break;
- }
-
- DPRINTF("(%s) = 0x%08x\n", imx_gpt_reg_name(offset >> 2), reg_value);
-
- return reg_value;
-}
-
-static void imx_gpt_reset(DeviceState *dev)
-{
- IMXGPTState *s = IMX_GPT(dev);
-
- /* stop timer */
- ptimer_stop(s->timer);
-
- /*
- * Soft reset doesn't touch some bits; hard reset clears them
- */
- s->cr &= ~(GPT_CR_EN|GPT_CR_ENMOD|GPT_CR_STOPEN|GPT_CR_DOZEN|
- GPT_CR_WAITEN|GPT_CR_DBGEN);
- s->sr = 0;
- s->pr = 0;
- s->ir = 0;
- s->cnt = 0;
- s->ocr1 = GPT_TIMER_MAX;
- s->ocr2 = GPT_TIMER_MAX;
- s->ocr3 = GPT_TIMER_MAX;
- s->icr1 = 0;
- s->icr2 = 0;
-
- s->next_timeout = GPT_TIMER_MAX;
- s->next_int = 0;
-
- /* compute new freq */
- imx_gpt_set_freq(s);
-
- /* reset the limit to GPT_TIMER_MAX */
- ptimer_set_limit(s->timer, GPT_TIMER_MAX, 1);
-
- /* if the timer is still enabled, restart it */
- if (s->freq && (s->cr & GPT_CR_EN)) {
- ptimer_run(s->timer, 1);
- }
-}
-
-static void imx_gpt_write(void *opaque, hwaddr offset, uint64_t value,
- unsigned size)
-{
- IMXGPTState *s = IMX_GPT(opaque);
- uint32_t oldreg;
-
- DPRINTF("(%s, value = 0x%08x)\n", imx_gpt_reg_name(offset >> 2),
- (uint32_t)value);
-
- switch (offset >> 2) {
- case 0:
- oldreg = s->cr;
- s->cr = value & ~0x7c14;
- if (s->cr & GPT_CR_SWR) { /* force reset */
- /* handle the reset */
- imx_gpt_reset(DEVICE(s));
- } else {
- /* set our freq, as the source might have changed */
- imx_gpt_set_freq(s);
-
- if ((oldreg ^ s->cr) & GPT_CR_EN) {
- if (s->cr & GPT_CR_EN) {
- if (s->cr & GPT_CR_ENMOD) {
- s->next_timeout = GPT_TIMER_MAX;
- ptimer_set_count(s->timer, GPT_TIMER_MAX);
- imx_gpt_compute_next_timeout(s, false);
- }
- ptimer_run(s->timer, 1);
- } else {
- /* stop timer */
- ptimer_stop(s->timer);
- }
- }
- }
- break;
-
- case 1: /* Prescaler */
- s->pr = value & 0xfff;
- imx_gpt_set_freq(s);
- break;
-
- case 2: /* SR */
- s->sr &= ~(value & 0x3f);
- imx_gpt_update_int(s);
- break;
-
- case 3: /* IR -- interrupt register */
- s->ir = value & 0x3f;
- imx_gpt_update_int(s);
-
- imx_gpt_compute_next_timeout(s, false);
-
- break;
-
- case 4: /* OCR1 -- output compare register */
- s->ocr1 = value;
-
- /* In non-freerun mode, reset count when this register is written */
- if (!(s->cr & GPT_CR_FRR)) {
- s->next_timeout = GPT_TIMER_MAX;
- ptimer_set_limit(s->timer, GPT_TIMER_MAX, 1);
- }
-
- /* compute the new timeout */
- imx_gpt_compute_next_timeout(s, false);
-
- break;
-
- case 5: /* OCR2 -- output compare register */
- s->ocr2 = value;
-
- /* compute the new timeout */
- imx_gpt_compute_next_timeout(s, false);
-
- break;
-
- case 6: /* OCR3 -- output compare register */
- s->ocr3 = value;
-
- /* compute the new timeout */
- imx_gpt_compute_next_timeout(s, false);
-
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
- HWADDR_PRIx "\n", TYPE_IMX_GPT, __func__, offset);
- break;
- }
-}
-
-static void imx_gpt_timeout(void *opaque)
-{
- IMXGPTState *s = IMX_GPT(opaque);
-
- DPRINTF("\n");
-
- s->sr |= s->next_int;
- s->next_int = 0;
-
- imx_gpt_compute_next_timeout(s, true);
-
- imx_gpt_update_int(s);
-
- if (s->freq && (s->cr & GPT_CR_EN)) {
- ptimer_run(s->timer, 1);
- }
-}
-
-static const MemoryRegionOps imx_gpt_ops = {
- .read = imx_gpt_read,
- .write = imx_gpt_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-
-static void imx_gpt_realize(DeviceState *dev, Error **errp)
-{
- IMXGPTState *s = IMX_GPT(dev);
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- QEMUBH *bh;
-
- sysbus_init_irq(sbd, &s->irq);
- memory_region_init_io(&s->iomem, OBJECT(s), &imx_gpt_ops, s, TYPE_IMX_GPT,
- 0x00001000);
- sysbus_init_mmio(sbd, &s->iomem);
-
- bh = qemu_bh_new(imx_gpt_timeout, s);
- s->timer = ptimer_init(bh);
-}
-
-static void imx_gpt_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = imx_gpt_realize;
- dc->reset = imx_gpt_reset;
- dc->vmsd = &vmstate_imx_timer_gpt;
- dc->desc = "i.MX general timer";
-}
-
-static const TypeInfo imx_gpt_info = {
- .name = TYPE_IMX_GPT,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(IMXGPTState),
- .class_init = imx_gpt_class_init,
-};
-
-static void imx_gpt_register_types(void)
-{
- type_register_static(&imx_gpt_info);
-}
-
-type_init(imx_gpt_register_types)
diff --git a/qemu/hw/timer/lm32_timer.c b/qemu/hw/timer/lm32_timer.c
deleted file mode 100644
index 3198355aa..000000000
--- a/qemu/hw/timer/lm32_timer.c
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * QEMU model of the LatticeMico32 timer block.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * Specification available at:
- * http://www.latticesemi.com/documents/mico32timer.pdf
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "qemu/timer.h"
-#include "hw/ptimer.h"
-#include "qemu/error-report.h"
-#include "qemu/main-loop.h"
-
-#define DEFAULT_FREQUENCY (50*1000000)
-
-enum {
- R_SR = 0,
- R_CR,
- R_PERIOD,
- R_SNAPSHOT,
- R_MAX
-};
-
-enum {
- SR_TO = (1 << 0),
- SR_RUN = (1 << 1),
-};
-
-enum {
- CR_ITO = (1 << 0),
- CR_CONT = (1 << 1),
- CR_START = (1 << 2),
- CR_STOP = (1 << 3),
-};
-
-#define TYPE_LM32_TIMER "lm32-timer"
-#define LM32_TIMER(obj) OBJECT_CHECK(LM32TimerState, (obj), TYPE_LM32_TIMER)
-
-struct LM32TimerState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
-
- QEMUBH *bh;
- ptimer_state *ptimer;
-
- qemu_irq irq;
- uint32_t freq_hz;
-
- uint32_t regs[R_MAX];
-};
-typedef struct LM32TimerState LM32TimerState;
-
-static void timer_update_irq(LM32TimerState *s)
-{
- int state = (s->regs[R_SR] & SR_TO) && (s->regs[R_CR] & CR_ITO);
-
- trace_lm32_timer_irq_state(state);
- qemu_set_irq(s->irq, state);
-}
-
-static uint64_t timer_read(void *opaque, hwaddr addr, unsigned size)
-{
- LM32TimerState *s = opaque;
- uint32_t r = 0;
-
- addr >>= 2;
- switch (addr) {
- case R_SR:
- case R_CR:
- case R_PERIOD:
- r = s->regs[addr];
- break;
- case R_SNAPSHOT:
- r = (uint32_t)ptimer_get_count(s->ptimer);
- break;
- default:
- error_report("lm32_timer: read access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-
- trace_lm32_timer_memory_read(addr << 2, r);
- return r;
-}
-
-static void timer_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- LM32TimerState *s = opaque;
-
- trace_lm32_timer_memory_write(addr, value);
-
- addr >>= 2;
- switch (addr) {
- case R_SR:
- s->regs[R_SR] &= ~SR_TO;
- break;
- case R_CR:
- s->regs[R_CR] = value;
- if (s->regs[R_CR] & CR_START) {
- ptimer_run(s->ptimer, 1);
- }
- if (s->regs[R_CR] & CR_STOP) {
- ptimer_stop(s->ptimer);
- }
- break;
- case R_PERIOD:
- s->regs[R_PERIOD] = value;
- ptimer_set_count(s->ptimer, value);
- break;
- case R_SNAPSHOT:
- error_report("lm32_timer: write access to read only register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- default:
- error_report("lm32_timer: write access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
- timer_update_irq(s);
-}
-
-static const MemoryRegionOps timer_ops = {
- .read = timer_read,
- .write = timer_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static void timer_hit(void *opaque)
-{
- LM32TimerState *s = opaque;
-
- trace_lm32_timer_hit();
-
- s->regs[R_SR] |= SR_TO;
-
- if (s->regs[R_CR] & CR_CONT) {
- ptimer_set_count(s->ptimer, s->regs[R_PERIOD]);
- ptimer_run(s->ptimer, 1);
- }
- timer_update_irq(s);
-}
-
-static void timer_reset(DeviceState *d)
-{
- LM32TimerState *s = LM32_TIMER(d);
- int i;
-
- for (i = 0; i < R_MAX; i++) {
- s->regs[i] = 0;
- }
- ptimer_stop(s->ptimer);
-}
-
-static int lm32_timer_init(SysBusDevice *dev)
-{
- LM32TimerState *s = LM32_TIMER(dev);
-
- sysbus_init_irq(dev, &s->irq);
-
- s->bh = qemu_bh_new(timer_hit, s);
- s->ptimer = ptimer_init(s->bh);
- ptimer_set_freq(s->ptimer, s->freq_hz);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &timer_ops, s,
- "timer", R_MAX * 4);
- sysbus_init_mmio(dev, &s->iomem);
-
- return 0;
-}
-
-static const VMStateDescription vmstate_lm32_timer = {
- .name = "lm32-timer",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_PTIMER(ptimer, LM32TimerState),
- VMSTATE_UINT32(freq_hz, LM32TimerState),
- VMSTATE_UINT32_ARRAY(regs, LM32TimerState, R_MAX),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property lm32_timer_properties[] = {
- DEFINE_PROP_UINT32("frequency", LM32TimerState, freq_hz, DEFAULT_FREQUENCY),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void lm32_timer_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = lm32_timer_init;
- dc->reset = timer_reset;
- dc->vmsd = &vmstate_lm32_timer;
- dc->props = lm32_timer_properties;
-}
-
-static const TypeInfo lm32_timer_info = {
- .name = TYPE_LM32_TIMER,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(LM32TimerState),
- .class_init = lm32_timer_class_init,
-};
-
-static void lm32_timer_register_types(void)
-{
- type_register_static(&lm32_timer_info);
-}
-
-type_init(lm32_timer_register_types)
diff --git a/qemu/hw/timer/m48t59.c b/qemu/hw/timer/m48t59.c
deleted file mode 100644
index e46ca8839..000000000
--- a/qemu/hw/timer/m48t59.c
+++ /dev/null
@@ -1,947 +0,0 @@
-/*
- * QEMU M48T59 and M48T08 NVRAM emulation for PPC PREP and Sparc platforms
- *
- * Copyright (c) 2003-2005, 2007 Jocelyn Mayer
- * Copyright (c) 2013 Hervé Poussineau
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/timer/m48t59.h"
-#include "qapi/error.h"
-#include "qemu/timer.h"
-#include "sysemu/sysemu.h"
-#include "hw/sysbus.h"
-#include "hw/isa/isa.h"
-#include "exec/address-spaces.h"
-#include "qemu/bcd.h"
-
-//#define DEBUG_NVRAM
-
-#if defined(DEBUG_NVRAM)
-#define NVRAM_PRINTF(fmt, ...) do { printf(fmt , ## __VA_ARGS__); } while (0)
-#else
-#define NVRAM_PRINTF(fmt, ...) do { } while (0)
-#endif
-
-#define TYPE_M48TXX_SYS_BUS "sysbus-m48txx"
-#define M48TXX_SYS_BUS_GET_CLASS(obj) \
- OBJECT_GET_CLASS(M48txxSysBusDeviceClass, (obj), TYPE_M48TXX_SYS_BUS)
-#define M48TXX_SYS_BUS_CLASS(klass) \
- OBJECT_CLASS_CHECK(M48txxSysBusDeviceClass, (klass), TYPE_M48TXX_SYS_BUS)
-#define M48TXX_SYS_BUS(obj) \
- OBJECT_CHECK(M48txxSysBusState, (obj), TYPE_M48TXX_SYS_BUS)
-
-#define TYPE_M48TXX_ISA "isa-m48txx"
-#define M48TXX_ISA_GET_CLASS(obj) \
- OBJECT_GET_CLASS(M48txxISADeviceClass, (obj), TYPE_M48TXX_ISA)
-#define M48TXX_ISA_CLASS(klass) \
- OBJECT_CLASS_CHECK(M48txxISADeviceClass, (klass), TYPE_M48TXX_ISA)
-#define M48TXX_ISA(obj) \
- OBJECT_CHECK(M48txxISAState, (obj), TYPE_M48TXX_ISA)
-
-/*
- * The M48T02, M48T08 and M48T59 chips are very similar. The newer '59 has
- * alarm and a watchdog timer and related control registers. In the
- * PPC platform there is also a nvram lock function.
- */
-
-typedef struct M48txxInfo {
- const char *isa_name;
- const char *sysbus_name;
- uint32_t model; /* 2 = m48t02, 8 = m48t08, 59 = m48t59 */
- uint32_t size;
-} M48txxInfo;
-
-/*
- * Chipset docs:
- * http://www.st.com/stonline/products/literature/ds/2410/m48t02.pdf
- * http://www.st.com/stonline/products/literature/ds/2411/m48t08.pdf
- * http://www.st.com/stonline/products/literature/od/7001/m48t59y.pdf
- */
-
-typedef struct M48t59State {
- /* Hardware parameters */
- qemu_irq IRQ;
- MemoryRegion iomem;
- uint32_t size;
- int32_t base_year;
- /* RTC management */
- time_t time_offset;
- time_t stop_time;
- /* Alarm & watchdog */
- struct tm alarm;
- QEMUTimer *alrm_timer;
- QEMUTimer *wd_timer;
- /* NVRAM storage */
- uint8_t *buffer;
- /* Model parameters */
- uint32_t model; /* 2 = m48t02, 8 = m48t08, 59 = m48t59 */
- /* NVRAM storage */
- uint16_t addr;
- uint8_t lock;
-} M48t59State;
-
-typedef struct M48txxISAState {
- ISADevice parent_obj;
- M48t59State state;
- uint32_t io_base;
- MemoryRegion io;
-} M48txxISAState;
-
-typedef struct M48txxISADeviceClass {
- ISADeviceClass parent_class;
- M48txxInfo info;
-} M48txxISADeviceClass;
-
-typedef struct M48txxSysBusState {
- SysBusDevice parent_obj;
- M48t59State state;
- MemoryRegion io;
-} M48txxSysBusState;
-
-typedef struct M48txxSysBusDeviceClass {
- SysBusDeviceClass parent_class;
- M48txxInfo info;
-} M48txxSysBusDeviceClass;
-
-static M48txxInfo m48txx_info[] = {
- {
- .sysbus_name = "sysbus-m48t02",
- .model = 2,
- .size = 0x800,
- },{
- .sysbus_name = "sysbus-m48t08",
- .model = 8,
- .size = 0x2000,
- },{
- .sysbus_name = "sysbus-m48t59",
- .model = 59,
- .size = 0x2000,
- },{
- .isa_name = "isa-m48t59",
- .model = 59,
- .size = 0x2000,
- }
-};
-
-
-/* Fake timer functions */
-
-/* Alarm management */
-static void alarm_cb (void *opaque)
-{
- struct tm tm;
- uint64_t next_time;
- M48t59State *NVRAM = opaque;
-
- qemu_set_irq(NVRAM->IRQ, 1);
- if ((NVRAM->buffer[0x1FF5] & 0x80) == 0 &&
- (NVRAM->buffer[0x1FF4] & 0x80) == 0 &&
- (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
- (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
- /* Repeat once a month */
- qemu_get_timedate(&tm, NVRAM->time_offset);
- tm.tm_mon++;
- if (tm.tm_mon == 13) {
- tm.tm_mon = 1;
- tm.tm_year++;
- }
- next_time = qemu_timedate_diff(&tm) - NVRAM->time_offset;
- } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
- (NVRAM->buffer[0x1FF4] & 0x80) == 0 &&
- (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
- (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
- /* Repeat once a day */
- next_time = 24 * 60 * 60;
- } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
- (NVRAM->buffer[0x1FF4] & 0x80) != 0 &&
- (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
- (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
- /* Repeat once an hour */
- next_time = 60 * 60;
- } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
- (NVRAM->buffer[0x1FF4] & 0x80) != 0 &&
- (NVRAM->buffer[0x1FF3] & 0x80) != 0 &&
- (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
- /* Repeat once a minute */
- next_time = 60;
- } else {
- /* Repeat once a second */
- next_time = 1;
- }
- timer_mod(NVRAM->alrm_timer, qemu_clock_get_ns(rtc_clock) +
- next_time * 1000);
- qemu_set_irq(NVRAM->IRQ, 0);
-}
-
-static void set_alarm(M48t59State *NVRAM)
-{
- int diff;
- if (NVRAM->alrm_timer != NULL) {
- timer_del(NVRAM->alrm_timer);
- diff = qemu_timedate_diff(&NVRAM->alarm) - NVRAM->time_offset;
- if (diff > 0)
- timer_mod(NVRAM->alrm_timer, diff * 1000);
- }
-}
-
-/* RTC management helpers */
-static inline void get_time(M48t59State *NVRAM, struct tm *tm)
-{
- qemu_get_timedate(tm, NVRAM->time_offset);
-}
-
-static void set_time(M48t59State *NVRAM, struct tm *tm)
-{
- NVRAM->time_offset = qemu_timedate_diff(tm);
- set_alarm(NVRAM);
-}
-
-/* Watchdog management */
-static void watchdog_cb (void *opaque)
-{
- M48t59State *NVRAM = opaque;
-
- NVRAM->buffer[0x1FF0] |= 0x80;
- if (NVRAM->buffer[0x1FF7] & 0x80) {
- NVRAM->buffer[0x1FF7] = 0x00;
- NVRAM->buffer[0x1FFC] &= ~0x40;
- /* May it be a hw CPU Reset instead ? */
- qemu_system_reset_request();
- } else {
- qemu_set_irq(NVRAM->IRQ, 1);
- qemu_set_irq(NVRAM->IRQ, 0);
- }
-}
-
-static void set_up_watchdog(M48t59State *NVRAM, uint8_t value)
-{
- uint64_t interval; /* in 1/16 seconds */
-
- NVRAM->buffer[0x1FF0] &= ~0x80;
- if (NVRAM->wd_timer != NULL) {
- timer_del(NVRAM->wd_timer);
- if (value != 0) {
- interval = (1 << (2 * (value & 0x03))) * ((value >> 2) & 0x1F);
- timer_mod(NVRAM->wd_timer, ((uint64_t)time(NULL) * 1000) +
- ((interval * 1000) >> 4));
- }
- }
-}
-
-/* Direct access to NVRAM */
-static void m48t59_write(M48t59State *NVRAM, uint32_t addr, uint32_t val)
-{
- struct tm tm;
- int tmp;
-
- if (addr > 0x1FF8 && addr < 0x2000)
- NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, addr, val);
-
- /* check for NVRAM access */
- if ((NVRAM->model == 2 && addr < 0x7f8) ||
- (NVRAM->model == 8 && addr < 0x1ff8) ||
- (NVRAM->model == 59 && addr < 0x1ff0)) {
- goto do_write;
- }
-
- /* TOD access */
- switch (addr) {
- case 0x1FF0:
- /* flags register : read-only */
- break;
- case 0x1FF1:
- /* unused */
- break;
- case 0x1FF2:
- /* alarm seconds */
- tmp = from_bcd(val & 0x7F);
- if (tmp >= 0 && tmp <= 59) {
- NVRAM->alarm.tm_sec = tmp;
- NVRAM->buffer[0x1FF2] = val;
- set_alarm(NVRAM);
- }
- break;
- case 0x1FF3:
- /* alarm minutes */
- tmp = from_bcd(val & 0x7F);
- if (tmp >= 0 && tmp <= 59) {
- NVRAM->alarm.tm_min = tmp;
- NVRAM->buffer[0x1FF3] = val;
- set_alarm(NVRAM);
- }
- break;
- case 0x1FF4:
- /* alarm hours */
- tmp = from_bcd(val & 0x3F);
- if (tmp >= 0 && tmp <= 23) {
- NVRAM->alarm.tm_hour = tmp;
- NVRAM->buffer[0x1FF4] = val;
- set_alarm(NVRAM);
- }
- break;
- case 0x1FF5:
- /* alarm date */
- tmp = from_bcd(val & 0x3F);
- if (tmp != 0) {
- NVRAM->alarm.tm_mday = tmp;
- NVRAM->buffer[0x1FF5] = val;
- set_alarm(NVRAM);
- }
- break;
- case 0x1FF6:
- /* interrupts */
- NVRAM->buffer[0x1FF6] = val;
- break;
- case 0x1FF7:
- /* watchdog */
- NVRAM->buffer[0x1FF7] = val;
- set_up_watchdog(NVRAM, val);
- break;
- case 0x1FF8:
- case 0x07F8:
- /* control */
- NVRAM->buffer[addr] = (val & ~0xA0) | 0x90;
- break;
- case 0x1FF9:
- case 0x07F9:
- /* seconds (BCD) */
- tmp = from_bcd(val & 0x7F);
- if (tmp >= 0 && tmp <= 59) {
- get_time(NVRAM, &tm);
- tm.tm_sec = tmp;
- set_time(NVRAM, &tm);
- }
- if ((val & 0x80) ^ (NVRAM->buffer[addr] & 0x80)) {
- if (val & 0x80) {
- NVRAM->stop_time = time(NULL);
- } else {
- NVRAM->time_offset += NVRAM->stop_time - time(NULL);
- NVRAM->stop_time = 0;
- }
- }
- NVRAM->buffer[addr] = val & 0x80;
- break;
- case 0x1FFA:
- case 0x07FA:
- /* minutes (BCD) */
- tmp = from_bcd(val & 0x7F);
- if (tmp >= 0 && tmp <= 59) {
- get_time(NVRAM, &tm);
- tm.tm_min = tmp;
- set_time(NVRAM, &tm);
- }
- break;
- case 0x1FFB:
- case 0x07FB:
- /* hours (BCD) */
- tmp = from_bcd(val & 0x3F);
- if (tmp >= 0 && tmp <= 23) {
- get_time(NVRAM, &tm);
- tm.tm_hour = tmp;
- set_time(NVRAM, &tm);
- }
- break;
- case 0x1FFC:
- case 0x07FC:
- /* day of the week / century */
- tmp = from_bcd(val & 0x07);
- get_time(NVRAM, &tm);
- tm.tm_wday = tmp;
- set_time(NVRAM, &tm);
- NVRAM->buffer[addr] = val & 0x40;
- break;
- case 0x1FFD:
- case 0x07FD:
- /* date (BCD) */
- tmp = from_bcd(val & 0x3F);
- if (tmp != 0) {
- get_time(NVRAM, &tm);
- tm.tm_mday = tmp;
- set_time(NVRAM, &tm);
- }
- break;
- case 0x1FFE:
- case 0x07FE:
- /* month */
- tmp = from_bcd(val & 0x1F);
- if (tmp >= 1 && tmp <= 12) {
- get_time(NVRAM, &tm);
- tm.tm_mon = tmp - 1;
- set_time(NVRAM, &tm);
- }
- break;
- case 0x1FFF:
- case 0x07FF:
- /* year */
- tmp = from_bcd(val);
- if (tmp >= 0 && tmp <= 99) {
- get_time(NVRAM, &tm);
- tm.tm_year = from_bcd(val) + NVRAM->base_year - 1900;
- set_time(NVRAM, &tm);
- }
- break;
- default:
- /* Check lock registers state */
- if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1))
- break;
- if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2))
- break;
- do_write:
- if (addr < NVRAM->size) {
- NVRAM->buffer[addr] = val & 0xFF;
- }
- break;
- }
-}
-
-static uint32_t m48t59_read(M48t59State *NVRAM, uint32_t addr)
-{
- struct tm tm;
- uint32_t retval = 0xFF;
-
- /* check for NVRAM access */
- if ((NVRAM->model == 2 && addr < 0x078f) ||
- (NVRAM->model == 8 && addr < 0x1ff8) ||
- (NVRAM->model == 59 && addr < 0x1ff0)) {
- goto do_read;
- }
-
- /* TOD access */
- switch (addr) {
- case 0x1FF0:
- /* flags register */
- goto do_read;
- case 0x1FF1:
- /* unused */
- retval = 0;
- break;
- case 0x1FF2:
- /* alarm seconds */
- goto do_read;
- case 0x1FF3:
- /* alarm minutes */
- goto do_read;
- case 0x1FF4:
- /* alarm hours */
- goto do_read;
- case 0x1FF5:
- /* alarm date */
- goto do_read;
- case 0x1FF6:
- /* interrupts */
- goto do_read;
- case 0x1FF7:
- /* A read resets the watchdog */
- set_up_watchdog(NVRAM, NVRAM->buffer[0x1FF7]);
- goto do_read;
- case 0x1FF8:
- case 0x07F8:
- /* control */
- goto do_read;
- case 0x1FF9:
- case 0x07F9:
- /* seconds (BCD) */
- get_time(NVRAM, &tm);
- retval = (NVRAM->buffer[addr] & 0x80) | to_bcd(tm.tm_sec);
- break;
- case 0x1FFA:
- case 0x07FA:
- /* minutes (BCD) */
- get_time(NVRAM, &tm);
- retval = to_bcd(tm.tm_min);
- break;
- case 0x1FFB:
- case 0x07FB:
- /* hours (BCD) */
- get_time(NVRAM, &tm);
- retval = to_bcd(tm.tm_hour);
- break;
- case 0x1FFC:
- case 0x07FC:
- /* day of the week / century */
- get_time(NVRAM, &tm);
- retval = NVRAM->buffer[addr] | tm.tm_wday;
- break;
- case 0x1FFD:
- case 0x07FD:
- /* date */
- get_time(NVRAM, &tm);
- retval = to_bcd(tm.tm_mday);
- break;
- case 0x1FFE:
- case 0x07FE:
- /* month */
- get_time(NVRAM, &tm);
- retval = to_bcd(tm.tm_mon + 1);
- break;
- case 0x1FFF:
- case 0x07FF:
- /* year */
- get_time(NVRAM, &tm);
- retval = to_bcd((tm.tm_year + 1900 - NVRAM->base_year) % 100);
- break;
- default:
- /* Check lock registers state */
- if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1))
- break;
- if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2))
- break;
- do_read:
- if (addr < NVRAM->size) {
- retval = NVRAM->buffer[addr];
- }
- break;
- }
- if (addr > 0x1FF9 && addr < 0x2000)
- NVRAM_PRINTF("%s: 0x%08x <= 0x%08x\n", __func__, addr, retval);
-
- return retval;
-}
-
-static void m48t59_toggle_lock(M48t59State *NVRAM, int lock)
-{
- NVRAM->lock ^= 1 << lock;
-}
-
-/* IO access to NVRAM */
-static void NVRAM_writeb(void *opaque, hwaddr addr, uint64_t val,
- unsigned size)
-{
- M48t59State *NVRAM = opaque;
-
- NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, addr, val);
- switch (addr) {
- case 0:
- NVRAM->addr &= ~0x00FF;
- NVRAM->addr |= val;
- break;
- case 1:
- NVRAM->addr &= ~0xFF00;
- NVRAM->addr |= val << 8;
- break;
- case 3:
- m48t59_write(NVRAM, NVRAM->addr, val);
- NVRAM->addr = 0x0000;
- break;
- default:
- break;
- }
-}
-
-static uint64_t NVRAM_readb(void *opaque, hwaddr addr, unsigned size)
-{
- M48t59State *NVRAM = opaque;
- uint32_t retval;
-
- switch (addr) {
- case 3:
- retval = m48t59_read(NVRAM, NVRAM->addr);
- break;
- default:
- retval = -1;
- break;
- }
- NVRAM_PRINTF("%s: 0x%08x <= 0x%08x\n", __func__, addr, retval);
-
- return retval;
-}
-
-static void nvram_writeb (void *opaque, hwaddr addr, uint32_t value)
-{
- M48t59State *NVRAM = opaque;
-
- m48t59_write(NVRAM, addr, value & 0xff);
-}
-
-static void nvram_writew (void *opaque, hwaddr addr, uint32_t value)
-{
- M48t59State *NVRAM = opaque;
-
- m48t59_write(NVRAM, addr, (value >> 8) & 0xff);
- m48t59_write(NVRAM, addr + 1, value & 0xff);
-}
-
-static void nvram_writel (void *opaque, hwaddr addr, uint32_t value)
-{
- M48t59State *NVRAM = opaque;
-
- m48t59_write(NVRAM, addr, (value >> 24) & 0xff);
- m48t59_write(NVRAM, addr + 1, (value >> 16) & 0xff);
- m48t59_write(NVRAM, addr + 2, (value >> 8) & 0xff);
- m48t59_write(NVRAM, addr + 3, value & 0xff);
-}
-
-static uint32_t nvram_readb (void *opaque, hwaddr addr)
-{
- M48t59State *NVRAM = opaque;
-
- return m48t59_read(NVRAM, addr);
-}
-
-static uint32_t nvram_readw (void *opaque, hwaddr addr)
-{
- M48t59State *NVRAM = opaque;
- uint32_t retval;
-
- retval = m48t59_read(NVRAM, addr) << 8;
- retval |= m48t59_read(NVRAM, addr + 1);
- return retval;
-}
-
-static uint32_t nvram_readl (void *opaque, hwaddr addr)
-{
- M48t59State *NVRAM = opaque;
- uint32_t retval;
-
- retval = m48t59_read(NVRAM, addr) << 24;
- retval |= m48t59_read(NVRAM, addr + 1) << 16;
- retval |= m48t59_read(NVRAM, addr + 2) << 8;
- retval |= m48t59_read(NVRAM, addr + 3);
- return retval;
-}
-
-static const MemoryRegionOps nvram_ops = {
- .old_mmio = {
- .read = { nvram_readb, nvram_readw, nvram_readl, },
- .write = { nvram_writeb, nvram_writew, nvram_writel, },
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_m48t59 = {
- .name = "m48t59",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(lock, M48t59State),
- VMSTATE_UINT16(addr, M48t59State),
- VMSTATE_VBUFFER_UINT32(buffer, M48t59State, 0, NULL, 0, size),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void m48t59_reset_common(M48t59State *NVRAM)
-{
- NVRAM->addr = 0;
- NVRAM->lock = 0;
- if (NVRAM->alrm_timer != NULL)
- timer_del(NVRAM->alrm_timer);
-
- if (NVRAM->wd_timer != NULL)
- timer_del(NVRAM->wd_timer);
-}
-
-static void m48t59_reset_isa(DeviceState *d)
-{
- M48txxISAState *isa = M48TXX_ISA(d);
- M48t59State *NVRAM = &isa->state;
-
- m48t59_reset_common(NVRAM);
-}
-
-static void m48t59_reset_sysbus(DeviceState *d)
-{
- M48txxSysBusState *sys = M48TXX_SYS_BUS(d);
- M48t59State *NVRAM = &sys->state;
-
- m48t59_reset_common(NVRAM);
-}
-
-static const MemoryRegionOps m48t59_io_ops = {
- .read = NVRAM_readb,
- .write = NVRAM_writeb,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-/* Initialisation routine */
-Nvram *m48t59_init(qemu_irq IRQ, hwaddr mem_base,
- uint32_t io_base, uint16_t size, int base_year,
- int model)
-{
- DeviceState *dev;
- SysBusDevice *s;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(m48txx_info); i++) {
- if (!m48txx_info[i].sysbus_name ||
- m48txx_info[i].size != size ||
- m48txx_info[i].model != model) {
- continue;
- }
-
- dev = qdev_create(NULL, m48txx_info[i].sysbus_name);
- qdev_prop_set_int32(dev, "base-year", base_year);
- qdev_init_nofail(dev);
- s = SYS_BUS_DEVICE(dev);
- sysbus_connect_irq(s, 0, IRQ);
- if (io_base != 0) {
- memory_region_add_subregion(get_system_io(), io_base,
- sysbus_mmio_get_region(s, 1));
- }
- if (mem_base != 0) {
- sysbus_mmio_map(s, 0, mem_base);
- }
-
- return NVRAM(s);
- }
-
- assert(false);
- return NULL;
-}
-
-Nvram *m48t59_init_isa(ISABus *bus, uint32_t io_base, uint16_t size,
- int base_year, int model)
-{
- DeviceState *dev;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(m48txx_info); i++) {
- if (!m48txx_info[i].isa_name ||
- m48txx_info[i].size != size ||
- m48txx_info[i].model != model) {
- continue;
- }
-
- dev = DEVICE(isa_create(bus, m48txx_info[i].isa_name));
- qdev_prop_set_uint32(dev, "iobase", io_base);
- qdev_prop_set_int32(dev, "base-year", base_year);
- qdev_init_nofail(dev);
- return NVRAM(dev);
- }
-
- assert(false);
- return NULL;
-}
-
-static void m48t59_realize_common(M48t59State *s, Error **errp)
-{
- s->buffer = g_malloc0(s->size);
- if (s->model == 59) {
- s->alrm_timer = timer_new_ns(rtc_clock, &alarm_cb, s);
- s->wd_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &watchdog_cb, s);
- }
- qemu_get_timedate(&s->alarm, 0);
-
- vmstate_register(NULL, -1, &vmstate_m48t59, s);
-}
-
-static void m48t59_isa_realize(DeviceState *dev, Error **errp)
-{
- M48txxISADeviceClass *u = M48TXX_ISA_GET_CLASS(dev);
- ISADevice *isadev = ISA_DEVICE(dev);
- M48txxISAState *d = M48TXX_ISA(dev);
- M48t59State *s = &d->state;
-
- s->model = u->info.model;
- s->size = u->info.size;
- isa_init_irq(isadev, &s->IRQ, 8);
- m48t59_realize_common(s, errp);
- memory_region_init_io(&d->io, OBJECT(dev), &m48t59_io_ops, s, "m48t59", 4);
- if (d->io_base != 0) {
- isa_register_ioport(isadev, &d->io, d->io_base);
- }
-}
-
-static int m48t59_init1(SysBusDevice *dev)
-{
- M48txxSysBusDeviceClass *u = M48TXX_SYS_BUS_GET_CLASS(dev);
- M48txxSysBusState *d = M48TXX_SYS_BUS(dev);
- Object *o = OBJECT(dev);
- M48t59State *s = &d->state;
- Error *err = NULL;
-
- s->model = u->info.model;
- s->size = u->info.size;
- sysbus_init_irq(dev, &s->IRQ);
-
- memory_region_init_io(&s->iomem, o, &nvram_ops, s, "m48t59.nvram",
- s->size);
- memory_region_init_io(&d->io, o, &m48t59_io_ops, s, "m48t59", 4);
- sysbus_init_mmio(dev, &s->iomem);
- sysbus_init_mmio(dev, &d->io);
- m48t59_realize_common(s, &err);
- if (err != NULL) {
- error_free(err);
- return -1;
- }
-
- return 0;
-}
-
-static uint32_t m48txx_isa_read(Nvram *obj, uint32_t addr)
-{
- M48txxISAState *d = M48TXX_ISA(obj);
- return m48t59_read(&d->state, addr);
-}
-
-static void m48txx_isa_write(Nvram *obj, uint32_t addr, uint32_t val)
-{
- M48txxISAState *d = M48TXX_ISA(obj);
- m48t59_write(&d->state, addr, val);
-}
-
-static void m48txx_isa_toggle_lock(Nvram *obj, int lock)
-{
- M48txxISAState *d = M48TXX_ISA(obj);
- m48t59_toggle_lock(&d->state, lock);
-}
-
-static Property m48t59_isa_properties[] = {
- DEFINE_PROP_INT32("base-year", M48txxISAState, state.base_year, 0),
- DEFINE_PROP_UINT32("iobase", M48txxISAState, io_base, 0x74),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void m48txx_isa_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- NvramClass *nc = NVRAM_CLASS(klass);
-
- dc->realize = m48t59_isa_realize;
- dc->reset = m48t59_reset_isa;
- dc->props = m48t59_isa_properties;
- nc->read = m48txx_isa_read;
- nc->write = m48txx_isa_write;
- nc->toggle_lock = m48txx_isa_toggle_lock;
-}
-
-static void m48txx_isa_concrete_class_init(ObjectClass *klass, void *data)
-{
- M48txxISADeviceClass *u = M48TXX_ISA_CLASS(klass);
- M48txxInfo *info = data;
-
- u->info = *info;
-}
-
-static uint32_t m48txx_sysbus_read(Nvram *obj, uint32_t addr)
-{
- M48txxSysBusState *d = M48TXX_SYS_BUS(obj);
- return m48t59_read(&d->state, addr);
-}
-
-static void m48txx_sysbus_write(Nvram *obj, uint32_t addr, uint32_t val)
-{
- M48txxSysBusState *d = M48TXX_SYS_BUS(obj);
- m48t59_write(&d->state, addr, val);
-}
-
-static void m48txx_sysbus_toggle_lock(Nvram *obj, int lock)
-{
- M48txxSysBusState *d = M48TXX_SYS_BUS(obj);
- m48t59_toggle_lock(&d->state, lock);
-}
-
-static Property m48t59_sysbus_properties[] = {
- DEFINE_PROP_INT32("base-year", M48txxSysBusState, state.base_year, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void m48txx_sysbus_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- NvramClass *nc = NVRAM_CLASS(klass);
-
- k->init = m48t59_init1;
- dc->reset = m48t59_reset_sysbus;
- dc->props = m48t59_sysbus_properties;
- nc->read = m48txx_sysbus_read;
- nc->write = m48txx_sysbus_write;
- nc->toggle_lock = m48txx_sysbus_toggle_lock;
-}
-
-static void m48txx_sysbus_concrete_class_init(ObjectClass *klass, void *data)
-{
- M48txxSysBusDeviceClass *u = M48TXX_SYS_BUS_CLASS(klass);
- M48txxInfo *info = data;
-
- u->info = *info;
-}
-
-static const TypeInfo nvram_info = {
- .name = TYPE_NVRAM,
- .parent = TYPE_INTERFACE,
- .class_size = sizeof(NvramClass),
-};
-
-static const TypeInfo m48txx_sysbus_type_info = {
- .name = TYPE_M48TXX_SYS_BUS,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(M48txxSysBusState),
- .abstract = true,
- .class_init = m48txx_sysbus_class_init,
- .interfaces = (InterfaceInfo[]) {
- { TYPE_NVRAM },
- { }
- }
-};
-
-static const TypeInfo m48txx_isa_type_info = {
- .name = TYPE_M48TXX_ISA,
- .parent = TYPE_ISA_DEVICE,
- .instance_size = sizeof(M48txxISAState),
- .abstract = true,
- .class_init = m48txx_isa_class_init,
- .interfaces = (InterfaceInfo[]) {
- { TYPE_NVRAM },
- { }
- }
-};
-
-static void m48t59_register_types(void)
-{
- TypeInfo sysbus_type_info = {
- .parent = TYPE_M48TXX_SYS_BUS,
- .class_size = sizeof(M48txxSysBusDeviceClass),
- .class_init = m48txx_sysbus_concrete_class_init,
- };
- TypeInfo isa_type_info = {
- .parent = TYPE_M48TXX_ISA,
- .class_size = sizeof(M48txxISADeviceClass),
- .class_init = m48txx_isa_concrete_class_init,
- };
- int i;
-
- type_register_static(&nvram_info);
- type_register_static(&m48txx_sysbus_type_info);
- type_register_static(&m48txx_isa_type_info);
-
- for (i = 0; i < ARRAY_SIZE(m48txx_info); i++) {
- if (m48txx_info[i].sysbus_name) {
- sysbus_type_info.name = m48txx_info[i].sysbus_name;
- sysbus_type_info.class_data = &m48txx_info[i];
- type_register(&sysbus_type_info);
- }
-
- if (m48txx_info[i].isa_name) {
- isa_type_info.name = m48txx_info[i].isa_name;
- isa_type_info.class_data = &m48txx_info[i];
- type_register(&isa_type_info);
- }
- }
-}
-
-type_init(m48t59_register_types)
diff --git a/qemu/hw/timer/mc146818rtc.c b/qemu/hw/timer/mc146818rtc.c
deleted file mode 100644
index 2ac0fd3e4..000000000
--- a/qemu/hw/timer/mc146818rtc.c
+++ /dev/null
@@ -1,971 +0,0 @@
-/*
- * QEMU MC146818 RTC emulation
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "config-target.h"
-#include "qemu/cutils.h"
-#include "qemu/bcd.h"
-#include "hw/hw.h"
-#include "qemu/timer.h"
-#include "sysemu/sysemu.h"
-#include "hw/timer/mc146818rtc.h"
-#include "qapi/visitor.h"
-#include "qapi-event.h"
-#include "qmp-commands.h"
-
-#ifdef TARGET_I386
-#include "hw/i386/apic.h"
-#endif
-
-//#define DEBUG_CMOS
-//#define DEBUG_COALESCED
-
-#ifdef DEBUG_CMOS
-# define CMOS_DPRINTF(format, ...) printf(format, ## __VA_ARGS__)
-#else
-# define CMOS_DPRINTF(format, ...) do { } while (0)
-#endif
-
-#ifdef DEBUG_COALESCED
-# define DPRINTF_C(format, ...) printf(format, ## __VA_ARGS__)
-#else
-# define DPRINTF_C(format, ...) do { } while (0)
-#endif
-
-#define SEC_PER_MIN 60
-#define MIN_PER_HOUR 60
-#define SEC_PER_HOUR 3600
-#define HOUR_PER_DAY 24
-#define SEC_PER_DAY 86400
-
-#define RTC_REINJECT_ON_ACK_COUNT 20
-#define RTC_CLOCK_RATE 32768
-#define UIP_HOLD_LENGTH (8 * NANOSECONDS_PER_SECOND / 32768)
-
-#define MC146818_RTC(obj) OBJECT_CHECK(RTCState, (obj), TYPE_MC146818_RTC)
-
-typedef struct RTCState {
- ISADevice parent_obj;
-
- MemoryRegion io;
- uint8_t cmos_data[128];
- uint8_t cmos_index;
- int32_t base_year;
- uint64_t base_rtc;
- uint64_t last_update;
- int64_t offset;
- qemu_irq irq;
- int it_shift;
- /* periodic timer */
- QEMUTimer *periodic_timer;
- int64_t next_periodic_time;
- /* update-ended timer */
- QEMUTimer *update_timer;
- uint64_t next_alarm_time;
- uint16_t irq_reinject_on_ack_count;
- uint32_t irq_coalesced;
- uint32_t period;
- QEMUTimer *coalesced_timer;
- Notifier clock_reset_notifier;
- LostTickPolicy lost_tick_policy;
- Notifier suspend_notifier;
- QLIST_ENTRY(RTCState) link;
-} RTCState;
-
-static void rtc_set_time(RTCState *s);
-static void rtc_update_time(RTCState *s);
-static void rtc_set_cmos(RTCState *s, const struct tm *tm);
-static inline int rtc_from_bcd(RTCState *s, int a);
-static uint64_t get_next_alarm(RTCState *s);
-
-static inline bool rtc_running(RTCState *s)
-{
- return (!(s->cmos_data[RTC_REG_B] & REG_B_SET) &&
- (s->cmos_data[RTC_REG_A] & 0x70) <= 0x20);
-}
-
-static uint64_t get_guest_rtc_ns(RTCState *s)
-{
- uint64_t guest_rtc;
- uint64_t guest_clock = qemu_clock_get_ns(rtc_clock);
-
- guest_rtc = s->base_rtc * NANOSECONDS_PER_SECOND +
- guest_clock - s->last_update + s->offset;
- return guest_rtc;
-}
-
-#ifdef TARGET_I386
-static void rtc_coalesced_timer_update(RTCState *s)
-{
- if (s->irq_coalesced == 0) {
- timer_del(s->coalesced_timer);
- } else {
- /* divide each RTC interval to 2 - 8 smaller intervals */
- int c = MIN(s->irq_coalesced, 7) + 1;
- int64_t next_clock = qemu_clock_get_ns(rtc_clock) +
- muldiv64(s->period / c, NANOSECONDS_PER_SECOND, RTC_CLOCK_RATE);
- timer_mod(s->coalesced_timer, next_clock);
- }
-}
-
-static void rtc_coalesced_timer(void *opaque)
-{
- RTCState *s = opaque;
-
- if (s->irq_coalesced != 0) {
- apic_reset_irq_delivered();
- s->cmos_data[RTC_REG_C] |= 0xc0;
- DPRINTF_C("cmos: injecting from timer\n");
- qemu_irq_raise(s->irq);
- if (apic_get_irq_delivered()) {
- s->irq_coalesced--;
- DPRINTF_C("cmos: coalesced irqs decreased to %d\n",
- s->irq_coalesced);
- }
- }
-
- rtc_coalesced_timer_update(s);
-}
-#endif
-
-/* handle periodic timer */
-static void periodic_timer_update(RTCState *s, int64_t current_time)
-{
- int period_code, period;
- int64_t cur_clock, next_irq_clock;
-
- period_code = s->cmos_data[RTC_REG_A] & 0x0f;
- if (period_code != 0
- && (s->cmos_data[RTC_REG_B] & REG_B_PIE)) {
- if (period_code <= 2)
- period_code += 7;
- /* period in 32 Khz cycles */
- period = 1 << (period_code - 1);
-#ifdef TARGET_I386
- if (period != s->period) {
- s->irq_coalesced = (s->irq_coalesced * s->period) / period;
- DPRINTF_C("cmos: coalesced irqs scaled to %d\n", s->irq_coalesced);
- }
- s->period = period;
-#endif
- /* compute 32 khz clock */
- cur_clock =
- muldiv64(current_time, RTC_CLOCK_RATE, NANOSECONDS_PER_SECOND);
-
- next_irq_clock = (cur_clock & ~(period - 1)) + period;
- s->next_periodic_time = muldiv64(next_irq_clock, NANOSECONDS_PER_SECOND,
- RTC_CLOCK_RATE) + 1;
- timer_mod(s->periodic_timer, s->next_periodic_time);
- } else {
-#ifdef TARGET_I386
- s->irq_coalesced = 0;
-#endif
- timer_del(s->periodic_timer);
- }
-}
-
-static void rtc_periodic_timer(void *opaque)
-{
- RTCState *s = opaque;
-
- periodic_timer_update(s, s->next_periodic_time);
- s->cmos_data[RTC_REG_C] |= REG_C_PF;
- if (s->cmos_data[RTC_REG_B] & REG_B_PIE) {
- s->cmos_data[RTC_REG_C] |= REG_C_IRQF;
-#ifdef TARGET_I386
- if (s->lost_tick_policy == LOST_TICK_POLICY_SLEW) {
- if (s->irq_reinject_on_ack_count >= RTC_REINJECT_ON_ACK_COUNT)
- s->irq_reinject_on_ack_count = 0;
- apic_reset_irq_delivered();
- qemu_irq_raise(s->irq);
- if (!apic_get_irq_delivered()) {
- s->irq_coalesced++;
- rtc_coalesced_timer_update(s);
- DPRINTF_C("cmos: coalesced irqs increased to %d\n",
- s->irq_coalesced);
- }
- } else
-#endif
- qemu_irq_raise(s->irq);
- }
-}
-
-/* handle update-ended timer */
-static void check_update_timer(RTCState *s)
-{
- uint64_t next_update_time;
- uint64_t guest_nsec;
- int next_alarm_sec;
-
- /* From the data sheet: "Holding the dividers in reset prevents
- * interrupts from operating, while setting the SET bit allows"
- * them to occur. However, it will prevent an alarm interrupt
- * from occurring, because the time of day is not updated.
- */
- if ((s->cmos_data[RTC_REG_A] & 0x60) == 0x60) {
- timer_del(s->update_timer);
- return;
- }
- if ((s->cmos_data[RTC_REG_C] & REG_C_UF) &&
- (s->cmos_data[RTC_REG_B] & REG_B_SET)) {
- timer_del(s->update_timer);
- return;
- }
- if ((s->cmos_data[RTC_REG_C] & REG_C_UF) &&
- (s->cmos_data[RTC_REG_C] & REG_C_AF)) {
- timer_del(s->update_timer);
- return;
- }
-
- guest_nsec = get_guest_rtc_ns(s) % NANOSECONDS_PER_SECOND;
- /* if UF is clear, reprogram to next second */
- next_update_time = qemu_clock_get_ns(rtc_clock)
- + NANOSECONDS_PER_SECOND - guest_nsec;
-
- /* Compute time of next alarm. One second is already accounted
- * for in next_update_time.
- */
- next_alarm_sec = get_next_alarm(s);
- s->next_alarm_time = next_update_time +
- (next_alarm_sec - 1) * NANOSECONDS_PER_SECOND;
-
- if (s->cmos_data[RTC_REG_C] & REG_C_UF) {
- /* UF is set, but AF is clear. Program the timer to target
- * the alarm time. */
- next_update_time = s->next_alarm_time;
- }
- if (next_update_time != timer_expire_time_ns(s->update_timer)) {
- timer_mod(s->update_timer, next_update_time);
- }
-}
-
-static inline uint8_t convert_hour(RTCState *s, uint8_t hour)
-{
- if (!(s->cmos_data[RTC_REG_B] & REG_B_24H)) {
- hour %= 12;
- if (s->cmos_data[RTC_HOURS] & 0x80) {
- hour += 12;
- }
- }
- return hour;
-}
-
-static uint64_t get_next_alarm(RTCState *s)
-{
- int32_t alarm_sec, alarm_min, alarm_hour, cur_hour, cur_min, cur_sec;
- int32_t hour, min, sec;
-
- rtc_update_time(s);
-
- alarm_sec = rtc_from_bcd(s, s->cmos_data[RTC_SECONDS_ALARM]);
- alarm_min = rtc_from_bcd(s, s->cmos_data[RTC_MINUTES_ALARM]);
- alarm_hour = rtc_from_bcd(s, s->cmos_data[RTC_HOURS_ALARM]);
- alarm_hour = alarm_hour == -1 ? -1 : convert_hour(s, alarm_hour);
-
- cur_sec = rtc_from_bcd(s, s->cmos_data[RTC_SECONDS]);
- cur_min = rtc_from_bcd(s, s->cmos_data[RTC_MINUTES]);
- cur_hour = rtc_from_bcd(s, s->cmos_data[RTC_HOURS]);
- cur_hour = convert_hour(s, cur_hour);
-
- if (alarm_hour == -1) {
- alarm_hour = cur_hour;
- if (alarm_min == -1) {
- alarm_min = cur_min;
- if (alarm_sec == -1) {
- alarm_sec = cur_sec + 1;
- } else if (cur_sec > alarm_sec) {
- alarm_min++;
- }
- } else if (cur_min == alarm_min) {
- if (alarm_sec == -1) {
- alarm_sec = cur_sec + 1;
- } else {
- if (cur_sec > alarm_sec) {
- alarm_hour++;
- }
- }
- if (alarm_sec == SEC_PER_MIN) {
- /* wrap to next hour, minutes is not in don't care mode */
- alarm_sec = 0;
- alarm_hour++;
- }
- } else if (cur_min > alarm_min) {
- alarm_hour++;
- }
- } else if (cur_hour == alarm_hour) {
- if (alarm_min == -1) {
- alarm_min = cur_min;
- if (alarm_sec == -1) {
- alarm_sec = cur_sec + 1;
- } else if (cur_sec > alarm_sec) {
- alarm_min++;
- }
-
- if (alarm_sec == SEC_PER_MIN) {
- alarm_sec = 0;
- alarm_min++;
- }
- /* wrap to next day, hour is not in don't care mode */
- alarm_min %= MIN_PER_HOUR;
- } else if (cur_min == alarm_min) {
- if (alarm_sec == -1) {
- alarm_sec = cur_sec + 1;
- }
- /* wrap to next day, hours+minutes not in don't care mode */
- alarm_sec %= SEC_PER_MIN;
- }
- }
-
- /* values that are still don't care fire at the next min/sec */
- if (alarm_min == -1) {
- alarm_min = 0;
- }
- if (alarm_sec == -1) {
- alarm_sec = 0;
- }
-
- /* keep values in range */
- if (alarm_sec == SEC_PER_MIN) {
- alarm_sec = 0;
- alarm_min++;
- }
- if (alarm_min == MIN_PER_HOUR) {
- alarm_min = 0;
- alarm_hour++;
- }
- alarm_hour %= HOUR_PER_DAY;
-
- hour = alarm_hour - cur_hour;
- min = hour * MIN_PER_HOUR + alarm_min - cur_min;
- sec = min * SEC_PER_MIN + alarm_sec - cur_sec;
- return sec <= 0 ? sec + SEC_PER_DAY : sec;
-}
-
-static void rtc_update_timer(void *opaque)
-{
- RTCState *s = opaque;
- int32_t irqs = REG_C_UF;
- int32_t new_irqs;
-
- assert((s->cmos_data[RTC_REG_A] & 0x60) != 0x60);
-
- /* UIP might have been latched, update time and clear it. */
- rtc_update_time(s);
- s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
-
- if (qemu_clock_get_ns(rtc_clock) >= s->next_alarm_time) {
- irqs |= REG_C_AF;
- if (s->cmos_data[RTC_REG_B] & REG_B_AIE) {
- qemu_system_wakeup_request(QEMU_WAKEUP_REASON_RTC);
- }
- }
-
- new_irqs = irqs & ~s->cmos_data[RTC_REG_C];
- s->cmos_data[RTC_REG_C] |= irqs;
- if ((new_irqs & s->cmos_data[RTC_REG_B]) != 0) {
- s->cmos_data[RTC_REG_C] |= REG_C_IRQF;
- qemu_irq_raise(s->irq);
- }
- check_update_timer(s);
-}
-
-static void cmos_ioport_write(void *opaque, hwaddr addr,
- uint64_t data, unsigned size)
-{
- RTCState *s = opaque;
-
- if ((addr & 1) == 0) {
- s->cmos_index = data & 0x7f;
- } else {
- CMOS_DPRINTF("cmos: write index=0x%02x val=0x%02" PRIx64 "\n",
- s->cmos_index, data);
- switch(s->cmos_index) {
- case RTC_SECONDS_ALARM:
- case RTC_MINUTES_ALARM:
- case RTC_HOURS_ALARM:
- s->cmos_data[s->cmos_index] = data;
- check_update_timer(s);
- break;
- case RTC_IBM_PS2_CENTURY_BYTE:
- s->cmos_index = RTC_CENTURY;
- /* fall through */
- case RTC_CENTURY:
- case RTC_SECONDS:
- case RTC_MINUTES:
- case RTC_HOURS:
- case RTC_DAY_OF_WEEK:
- case RTC_DAY_OF_MONTH:
- case RTC_MONTH:
- case RTC_YEAR:
- s->cmos_data[s->cmos_index] = data;
- /* if in set mode, do not update the time */
- if (rtc_running(s)) {
- rtc_set_time(s);
- check_update_timer(s);
- }
- break;
- case RTC_REG_A:
- if ((data & 0x60) == 0x60) {
- if (rtc_running(s)) {
- rtc_update_time(s);
- }
- /* What happens to UIP when divider reset is enabled is
- * unclear from the datasheet. Shouldn't matter much
- * though.
- */
- s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
- } else if (((s->cmos_data[RTC_REG_A] & 0x60) == 0x60) &&
- (data & 0x70) <= 0x20) {
- /* when the divider reset is removed, the first update cycle
- * begins one-half second later*/
- if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
- s->offset = 500000000;
- rtc_set_time(s);
- }
- s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
- }
- /* UIP bit is read only */
- s->cmos_data[RTC_REG_A] = (data & ~REG_A_UIP) |
- (s->cmos_data[RTC_REG_A] & REG_A_UIP);
- periodic_timer_update(s, qemu_clock_get_ns(rtc_clock));
- check_update_timer(s);
- break;
- case RTC_REG_B:
- if (data & REG_B_SET) {
- /* update cmos to when the rtc was stopping */
- if (rtc_running(s)) {
- rtc_update_time(s);
- }
- /* set mode: reset UIP mode */
- s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
- data &= ~REG_B_UIE;
- } else {
- /* if disabling set mode, update the time */
- if ((s->cmos_data[RTC_REG_B] & REG_B_SET) &&
- (s->cmos_data[RTC_REG_A] & 0x70) <= 0x20) {
- s->offset = get_guest_rtc_ns(s) % NANOSECONDS_PER_SECOND;
- rtc_set_time(s);
- }
- }
- /* if an interrupt flag is already set when the interrupt
- * becomes enabled, raise an interrupt immediately. */
- if (data & s->cmos_data[RTC_REG_C] & REG_C_MASK) {
- s->cmos_data[RTC_REG_C] |= REG_C_IRQF;
- qemu_irq_raise(s->irq);
- } else {
- s->cmos_data[RTC_REG_C] &= ~REG_C_IRQF;
- qemu_irq_lower(s->irq);
- }
- s->cmos_data[RTC_REG_B] = data;
- periodic_timer_update(s, qemu_clock_get_ns(rtc_clock));
- check_update_timer(s);
- break;
- case RTC_REG_C:
- case RTC_REG_D:
- /* cannot write to them */
- break;
- default:
- s->cmos_data[s->cmos_index] = data;
- break;
- }
- }
-}
-
-static inline int rtc_to_bcd(RTCState *s, int a)
-{
- if (s->cmos_data[RTC_REG_B] & REG_B_DM) {
- return a;
- } else {
- return ((a / 10) << 4) | (a % 10);
- }
-}
-
-static inline int rtc_from_bcd(RTCState *s, int a)
-{
- if ((a & 0xc0) == 0xc0) {
- return -1;
- }
- if (s->cmos_data[RTC_REG_B] & REG_B_DM) {
- return a;
- } else {
- return ((a >> 4) * 10) + (a & 0x0f);
- }
-}
-
-static void rtc_get_time(RTCState *s, struct tm *tm)
-{
- tm->tm_sec = rtc_from_bcd(s, s->cmos_data[RTC_SECONDS]);
- tm->tm_min = rtc_from_bcd(s, s->cmos_data[RTC_MINUTES]);
- tm->tm_hour = rtc_from_bcd(s, s->cmos_data[RTC_HOURS] & 0x7f);
- if (!(s->cmos_data[RTC_REG_B] & REG_B_24H)) {
- tm->tm_hour %= 12;
- if (s->cmos_data[RTC_HOURS] & 0x80) {
- tm->tm_hour += 12;
- }
- }
- tm->tm_wday = rtc_from_bcd(s, s->cmos_data[RTC_DAY_OF_WEEK]) - 1;
- tm->tm_mday = rtc_from_bcd(s, s->cmos_data[RTC_DAY_OF_MONTH]);
- tm->tm_mon = rtc_from_bcd(s, s->cmos_data[RTC_MONTH]) - 1;
- tm->tm_year =
- rtc_from_bcd(s, s->cmos_data[RTC_YEAR]) + s->base_year +
- rtc_from_bcd(s, s->cmos_data[RTC_CENTURY]) * 100 - 1900;
-}
-
-static QLIST_HEAD(, RTCState) rtc_devices =
- QLIST_HEAD_INITIALIZER(rtc_devices);
-
-#ifdef TARGET_I386
-void qmp_rtc_reset_reinjection(Error **errp)
-{
- RTCState *s;
-
- QLIST_FOREACH(s, &rtc_devices, link) {
- s->irq_coalesced = 0;
- }
-}
-#endif
-
-static void rtc_set_time(RTCState *s)
-{
- struct tm tm;
-
- rtc_get_time(s, &tm);
- s->base_rtc = mktimegm(&tm);
- s->last_update = qemu_clock_get_ns(rtc_clock);
-
- qapi_event_send_rtc_change(qemu_timedate_diff(&tm), &error_abort);
-}
-
-static void rtc_set_cmos(RTCState *s, const struct tm *tm)
-{
- int year;
-
- s->cmos_data[RTC_SECONDS] = rtc_to_bcd(s, tm->tm_sec);
- s->cmos_data[RTC_MINUTES] = rtc_to_bcd(s, tm->tm_min);
- if (s->cmos_data[RTC_REG_B] & REG_B_24H) {
- /* 24 hour format */
- s->cmos_data[RTC_HOURS] = rtc_to_bcd(s, tm->tm_hour);
- } else {
- /* 12 hour format */
- int h = (tm->tm_hour % 12) ? tm->tm_hour % 12 : 12;
- s->cmos_data[RTC_HOURS] = rtc_to_bcd(s, h);
- if (tm->tm_hour >= 12)
- s->cmos_data[RTC_HOURS] |= 0x80;
- }
- s->cmos_data[RTC_DAY_OF_WEEK] = rtc_to_bcd(s, tm->tm_wday + 1);
- s->cmos_data[RTC_DAY_OF_MONTH] = rtc_to_bcd(s, tm->tm_mday);
- s->cmos_data[RTC_MONTH] = rtc_to_bcd(s, tm->tm_mon + 1);
- year = tm->tm_year + 1900 - s->base_year;
- s->cmos_data[RTC_YEAR] = rtc_to_bcd(s, year % 100);
- s->cmos_data[RTC_CENTURY] = rtc_to_bcd(s, year / 100);
-}
-
-static void rtc_update_time(RTCState *s)
-{
- struct tm ret;
- time_t guest_sec;
- int64_t guest_nsec;
-
- guest_nsec = get_guest_rtc_ns(s);
- guest_sec = guest_nsec / NANOSECONDS_PER_SECOND;
- gmtime_r(&guest_sec, &ret);
-
- /* Is SET flag of Register B disabled? */
- if ((s->cmos_data[RTC_REG_B] & REG_B_SET) == 0) {
- rtc_set_cmos(s, &ret);
- }
-}
-
-static int update_in_progress(RTCState *s)
-{
- int64_t guest_nsec;
-
- if (!rtc_running(s)) {
- return 0;
- }
- if (timer_pending(s->update_timer)) {
- int64_t next_update_time = timer_expire_time_ns(s->update_timer);
- /* Latch UIP until the timer expires. */
- if (qemu_clock_get_ns(rtc_clock) >=
- (next_update_time - UIP_HOLD_LENGTH)) {
- s->cmos_data[RTC_REG_A] |= REG_A_UIP;
- return 1;
- }
- }
-
- guest_nsec = get_guest_rtc_ns(s);
- /* UIP bit will be set at last 244us of every second. */
- if ((guest_nsec % NANOSECONDS_PER_SECOND) >=
- (NANOSECONDS_PER_SECOND - UIP_HOLD_LENGTH)) {
- return 1;
- }
- return 0;
-}
-
-static uint64_t cmos_ioport_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- RTCState *s = opaque;
- int ret;
- if ((addr & 1) == 0) {
- return 0xff;
- } else {
- switch(s->cmos_index) {
- case RTC_IBM_PS2_CENTURY_BYTE:
- s->cmos_index = RTC_CENTURY;
- /* fall through */
- case RTC_CENTURY:
- case RTC_SECONDS:
- case RTC_MINUTES:
- case RTC_HOURS:
- case RTC_DAY_OF_WEEK:
- case RTC_DAY_OF_MONTH:
- case RTC_MONTH:
- case RTC_YEAR:
- /* if not in set mode, calibrate cmos before
- * reading*/
- if (rtc_running(s)) {
- rtc_update_time(s);
- }
- ret = s->cmos_data[s->cmos_index];
- break;
- case RTC_REG_A:
- if (update_in_progress(s)) {
- s->cmos_data[s->cmos_index] |= REG_A_UIP;
- } else {
- s->cmos_data[s->cmos_index] &= ~REG_A_UIP;
- }
- ret = s->cmos_data[s->cmos_index];
- break;
- case RTC_REG_C:
- ret = s->cmos_data[s->cmos_index];
- qemu_irq_lower(s->irq);
- s->cmos_data[RTC_REG_C] = 0x00;
- if (ret & (REG_C_UF | REG_C_AF)) {
- check_update_timer(s);
- }
-#ifdef TARGET_I386
- if(s->irq_coalesced &&
- (s->cmos_data[RTC_REG_B] & REG_B_PIE) &&
- s->irq_reinject_on_ack_count < RTC_REINJECT_ON_ACK_COUNT) {
- s->irq_reinject_on_ack_count++;
- s->cmos_data[RTC_REG_C] |= REG_C_IRQF | REG_C_PF;
- apic_reset_irq_delivered();
- DPRINTF_C("cmos: injecting on ack\n");
- qemu_irq_raise(s->irq);
- if (apic_get_irq_delivered()) {
- s->irq_coalesced--;
- DPRINTF_C("cmos: coalesced irqs decreased to %d\n",
- s->irq_coalesced);
- }
- }
-#endif
- break;
- default:
- ret = s->cmos_data[s->cmos_index];
- break;
- }
- CMOS_DPRINTF("cmos: read index=0x%02x val=0x%02x\n",
- s->cmos_index, ret);
- return ret;
- }
-}
-
-void rtc_set_memory(ISADevice *dev, int addr, int val)
-{
- RTCState *s = MC146818_RTC(dev);
- if (addr >= 0 && addr <= 127)
- s->cmos_data[addr] = val;
-}
-
-int rtc_get_memory(ISADevice *dev, int addr)
-{
- RTCState *s = MC146818_RTC(dev);
- assert(addr >= 0 && addr <= 127);
- return s->cmos_data[addr];
-}
-
-static void rtc_set_date_from_host(ISADevice *dev)
-{
- RTCState *s = MC146818_RTC(dev);
- struct tm tm;
-
- qemu_get_timedate(&tm, 0);
-
- s->base_rtc = mktimegm(&tm);
- s->last_update = qemu_clock_get_ns(rtc_clock);
- s->offset = 0;
-
- /* set the CMOS date */
- rtc_set_cmos(s, &tm);
-}
-
-static int rtc_post_load(void *opaque, int version_id)
-{
- RTCState *s = opaque;
-
- if (version_id <= 2) {
- rtc_set_time(s);
- s->offset = 0;
- check_update_timer(s);
- }
-
- uint64_t now = qemu_clock_get_ns(rtc_clock);
- if (now < s->next_periodic_time ||
- now > (s->next_periodic_time + get_max_clock_jump())) {
- periodic_timer_update(s, qemu_clock_get_ns(rtc_clock));
- }
-
-#ifdef TARGET_I386
- if (version_id >= 2) {
- if (s->lost_tick_policy == LOST_TICK_POLICY_SLEW) {
- rtc_coalesced_timer_update(s);
- }
- }
-#endif
- return 0;
-}
-
-static bool rtc_irq_reinject_on_ack_count_needed(void *opaque)
-{
- RTCState *s = (RTCState *)opaque;
- return s->irq_reinject_on_ack_count != 0;
-}
-
-static const VMStateDescription vmstate_rtc_irq_reinject_on_ack_count = {
- .name = "mc146818rtc/irq_reinject_on_ack_count",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = rtc_irq_reinject_on_ack_count_needed,
- .fields = (VMStateField[]) {
- VMSTATE_UINT16(irq_reinject_on_ack_count, RTCState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_rtc = {
- .name = "mc146818rtc",
- .version_id = 3,
- .minimum_version_id = 1,
- .post_load = rtc_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_BUFFER(cmos_data, RTCState),
- VMSTATE_UINT8(cmos_index, RTCState),
- VMSTATE_UNUSED(7*4),
- VMSTATE_TIMER_PTR(periodic_timer, RTCState),
- VMSTATE_INT64(next_periodic_time, RTCState),
- VMSTATE_UNUSED(3*8),
- VMSTATE_UINT32_V(irq_coalesced, RTCState, 2),
- VMSTATE_UINT32_V(period, RTCState, 2),
- VMSTATE_UINT64_V(base_rtc, RTCState, 3),
- VMSTATE_UINT64_V(last_update, RTCState, 3),
- VMSTATE_INT64_V(offset, RTCState, 3),
- VMSTATE_TIMER_PTR_V(update_timer, RTCState, 3),
- VMSTATE_UINT64_V(next_alarm_time, RTCState, 3),
- VMSTATE_END_OF_LIST()
- },
- .subsections = (const VMStateDescription*[]) {
- &vmstate_rtc_irq_reinject_on_ack_count,
- NULL
- }
-};
-
-static void rtc_notify_clock_reset(Notifier *notifier, void *data)
-{
- RTCState *s = container_of(notifier, RTCState, clock_reset_notifier);
- int64_t now = *(int64_t *)data;
-
- rtc_set_date_from_host(ISA_DEVICE(s));
- periodic_timer_update(s, now);
- check_update_timer(s);
-#ifdef TARGET_I386
- if (s->lost_tick_policy == LOST_TICK_POLICY_SLEW) {
- rtc_coalesced_timer_update(s);
- }
-#endif
-}
-
-/* set CMOS shutdown status register (index 0xF) as S3_resume(0xFE)
- BIOS will read it and start S3 resume at POST Entry */
-static void rtc_notify_suspend(Notifier *notifier, void *data)
-{
- RTCState *s = container_of(notifier, RTCState, suspend_notifier);
- rtc_set_memory(ISA_DEVICE(s), 0xF, 0xFE);
-}
-
-static void rtc_reset(void *opaque)
-{
- RTCState *s = opaque;
-
- s->cmos_data[RTC_REG_B] &= ~(REG_B_PIE | REG_B_AIE | REG_B_SQWE);
- s->cmos_data[RTC_REG_C] &= ~(REG_C_UF | REG_C_IRQF | REG_C_PF | REG_C_AF);
- check_update_timer(s);
-
- qemu_irq_lower(s->irq);
-
-#ifdef TARGET_I386
- if (s->lost_tick_policy == LOST_TICK_POLICY_SLEW) {
- s->irq_coalesced = 0;
- s->irq_reinject_on_ack_count = 0;
- }
-#endif
-}
-
-static const MemoryRegionOps cmos_ops = {
- .read = cmos_ioport_read,
- .write = cmos_ioport_write,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void rtc_get_date(Object *obj, struct tm *current_tm, Error **errp)
-{
- RTCState *s = MC146818_RTC(obj);
-
- rtc_update_time(s);
- rtc_get_time(s, current_tm);
-}
-
-static void rtc_realizefn(DeviceState *dev, Error **errp)
-{
- ISADevice *isadev = ISA_DEVICE(dev);
- RTCState *s = MC146818_RTC(dev);
- int base = 0x70;
-
- s->cmos_data[RTC_REG_A] = 0x26;
- s->cmos_data[RTC_REG_B] = 0x02;
- s->cmos_data[RTC_REG_C] = 0x00;
- s->cmos_data[RTC_REG_D] = 0x80;
-
- /* This is for historical reasons. The default base year qdev property
- * was set to 2000 for most machine types before the century byte was
- * implemented.
- *
- * This if statement means that the century byte will be always 0
- * (at least until 2079...) for base_year = 1980, but will be set
- * correctly for base_year = 2000.
- */
- if (s->base_year == 2000) {
- s->base_year = 0;
- }
-
- rtc_set_date_from_host(isadev);
-
-#ifdef TARGET_I386
- switch (s->lost_tick_policy) {
- case LOST_TICK_POLICY_SLEW:
- s->coalesced_timer =
- timer_new_ns(rtc_clock, rtc_coalesced_timer, s);
- break;
- case LOST_TICK_POLICY_DISCARD:
- break;
- default:
- error_setg(errp, "Invalid lost tick policy.");
- return;
- }
-#endif
-
- s->periodic_timer = timer_new_ns(rtc_clock, rtc_periodic_timer, s);
- s->update_timer = timer_new_ns(rtc_clock, rtc_update_timer, s);
- check_update_timer(s);
-
- s->clock_reset_notifier.notify = rtc_notify_clock_reset;
- qemu_clock_register_reset_notifier(rtc_clock,
- &s->clock_reset_notifier);
-
- s->suspend_notifier.notify = rtc_notify_suspend;
- qemu_register_suspend_notifier(&s->suspend_notifier);
-
- memory_region_init_io(&s->io, OBJECT(s), &cmos_ops, s, "rtc", 2);
- isa_register_ioport(isadev, &s->io, base);
-
- qdev_set_legacy_instance_id(dev, base, 3);
- qemu_register_reset(rtc_reset, s);
-
- object_property_add_tm(OBJECT(s), "date", rtc_get_date, NULL);
-
- object_property_add_alias(qdev_get_machine(), "rtc-time",
- OBJECT(s), "date", NULL);
-}
-
-ISADevice *rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq)
-{
- DeviceState *dev;
- ISADevice *isadev;
- RTCState *s;
-
- isadev = isa_create(bus, TYPE_MC146818_RTC);
- dev = DEVICE(isadev);
- s = MC146818_RTC(isadev);
- qdev_prop_set_int32(dev, "base_year", base_year);
- qdev_init_nofail(dev);
- if (intercept_irq) {
- s->irq = intercept_irq;
- } else {
- isa_init_irq(isadev, &s->irq, RTC_ISA_IRQ);
- }
- QLIST_INSERT_HEAD(&rtc_devices, s, link);
-
- return isadev;
-}
-
-static Property mc146818rtc_properties[] = {
- DEFINE_PROP_INT32("base_year", RTCState, base_year, 1980),
- DEFINE_PROP_LOSTTICKPOLICY("lost_tick_policy", RTCState,
- lost_tick_policy, LOST_TICK_POLICY_DISCARD),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void rtc_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = rtc_realizefn;
- dc->vmsd = &vmstate_rtc;
- dc->props = mc146818rtc_properties;
- /* Reason: needs to be wired up by rtc_init() */
- dc->cannot_instantiate_with_device_add_yet = true;
-}
-
-static void rtc_finalize(Object *obj)
-{
- object_property_del(qdev_get_machine(), "rtc", NULL);
-}
-
-static const TypeInfo mc146818rtc_info = {
- .name = TYPE_MC146818_RTC,
- .parent = TYPE_ISA_DEVICE,
- .instance_size = sizeof(RTCState),
- .class_init = rtc_class_initfn,
- .instance_finalize = rtc_finalize,
-};
-
-static void mc146818rtc_register_types(void)
-{
- type_register_static(&mc146818rtc_info);
-}
-
-type_init(mc146818rtc_register_types)
diff --git a/qemu/hw/timer/milkymist-sysctl.c b/qemu/hw/timer/milkymist-sysctl.c
deleted file mode 100644
index 5f2948037..000000000
--- a/qemu/hw/timer/milkymist-sysctl.c
+++ /dev/null
@@ -1,342 +0,0 @@
-/*
- * QEMU model of the Milkymist System Controller.
- *
- * Copyright (c) 2010-2012 Michael Walle <michael@walle.cc>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * Specification available at:
- * http://www.milkymist.org/socdoc/sysctl.pdf
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "sysemu/sysemu.h"
-#include "trace.h"
-#include "qemu/timer.h"
-#include "hw/ptimer.h"
-#include "qemu/error-report.h"
-
-enum {
- CTRL_ENABLE = (1<<0),
- CTRL_AUTORESTART = (1<<1),
-};
-
-enum {
- ICAP_READY = (1<<0),
-};
-
-enum {
- R_GPIO_IN = 0,
- R_GPIO_OUT,
- R_GPIO_INTEN,
- R_TIMER0_CONTROL = 4,
- R_TIMER0_COMPARE,
- R_TIMER0_COUNTER,
- R_TIMER1_CONTROL = 8,
- R_TIMER1_COMPARE,
- R_TIMER1_COUNTER,
- R_ICAP = 16,
- R_DBG_SCRATCHPAD = 20,
- R_DBG_WRITE_LOCK,
- R_CLK_FREQUENCY = 29,
- R_CAPABILITIES,
- R_SYSTEM_ID,
- R_MAX
-};
-
-#define TYPE_MILKYMIST_SYSCTL "milkymist-sysctl"
-#define MILKYMIST_SYSCTL(obj) \
- OBJECT_CHECK(MilkymistSysctlState, (obj), TYPE_MILKYMIST_SYSCTL)
-
-struct MilkymistSysctlState {
- SysBusDevice parent_obj;
-
- MemoryRegion regs_region;
-
- QEMUBH *bh0;
- QEMUBH *bh1;
- ptimer_state *ptimer0;
- ptimer_state *ptimer1;
-
- uint32_t freq_hz;
- uint32_t capabilities;
- uint32_t systemid;
- uint32_t strappings;
-
- uint32_t regs[R_MAX];
-
- qemu_irq gpio_irq;
- qemu_irq timer0_irq;
- qemu_irq timer1_irq;
-};
-typedef struct MilkymistSysctlState MilkymistSysctlState;
-
-static void sysctl_icap_write(MilkymistSysctlState *s, uint32_t value)
-{
- trace_milkymist_sysctl_icap_write(value);
- switch (value & 0xffff) {
- case 0x000e:
- qemu_system_shutdown_request();
- break;
- }
-}
-
-static uint64_t sysctl_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- MilkymistSysctlState *s = opaque;
- uint32_t r = 0;
-
- addr >>= 2;
- switch (addr) {
- case R_TIMER0_COUNTER:
- r = (uint32_t)ptimer_get_count(s->ptimer0);
- /* milkymist timer counts up */
- r = s->regs[R_TIMER0_COMPARE] - r;
- break;
- case R_TIMER1_COUNTER:
- r = (uint32_t)ptimer_get_count(s->ptimer1);
- /* milkymist timer counts up */
- r = s->regs[R_TIMER1_COMPARE] - r;
- break;
- case R_GPIO_IN:
- case R_GPIO_OUT:
- case R_GPIO_INTEN:
- case R_TIMER0_CONTROL:
- case R_TIMER0_COMPARE:
- case R_TIMER1_CONTROL:
- case R_TIMER1_COMPARE:
- case R_ICAP:
- case R_DBG_SCRATCHPAD:
- case R_DBG_WRITE_LOCK:
- case R_CLK_FREQUENCY:
- case R_CAPABILITIES:
- case R_SYSTEM_ID:
- r = s->regs[addr];
- break;
-
- default:
- error_report("milkymist_sysctl: read access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-
- trace_milkymist_sysctl_memory_read(addr << 2, r);
-
- return r;
-}
-
-static void sysctl_write(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
- MilkymistSysctlState *s = opaque;
-
- trace_milkymist_sysctl_memory_write(addr, value);
-
- addr >>= 2;
- switch (addr) {
- case R_GPIO_OUT:
- case R_GPIO_INTEN:
- case R_TIMER0_COUNTER:
- case R_TIMER1_COUNTER:
- case R_DBG_SCRATCHPAD:
- s->regs[addr] = value;
- break;
- case R_TIMER0_COMPARE:
- ptimer_set_limit(s->ptimer0, value, 0);
- s->regs[addr] = value;
- break;
- case R_TIMER1_COMPARE:
- ptimer_set_limit(s->ptimer1, value, 0);
- s->regs[addr] = value;
- break;
- case R_TIMER0_CONTROL:
- s->regs[addr] = value;
- if (s->regs[R_TIMER0_CONTROL] & CTRL_ENABLE) {
- trace_milkymist_sysctl_start_timer0();
- ptimer_set_count(s->ptimer0,
- s->regs[R_TIMER0_COMPARE] - s->regs[R_TIMER0_COUNTER]);
- ptimer_run(s->ptimer0, 0);
- } else {
- trace_milkymist_sysctl_stop_timer0();
- ptimer_stop(s->ptimer0);
- }
- break;
- case R_TIMER1_CONTROL:
- s->regs[addr] = value;
- if (s->regs[R_TIMER1_CONTROL] & CTRL_ENABLE) {
- trace_milkymist_sysctl_start_timer1();
- ptimer_set_count(s->ptimer1,
- s->regs[R_TIMER1_COMPARE] - s->regs[R_TIMER1_COUNTER]);
- ptimer_run(s->ptimer1, 0);
- } else {
- trace_milkymist_sysctl_stop_timer1();
- ptimer_stop(s->ptimer1);
- }
- break;
- case R_ICAP:
- sysctl_icap_write(s, value);
- break;
- case R_DBG_WRITE_LOCK:
- s->regs[addr] = 1;
- break;
- case R_SYSTEM_ID:
- qemu_system_reset_request();
- break;
-
- case R_GPIO_IN:
- case R_CLK_FREQUENCY:
- case R_CAPABILITIES:
- error_report("milkymist_sysctl: write to read-only register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
-
- default:
- error_report("milkymist_sysctl: write access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-}
-
-static const MemoryRegionOps sysctl_mmio_ops = {
- .read = sysctl_read,
- .write = sysctl_write,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void timer0_hit(void *opaque)
-{
- MilkymistSysctlState *s = opaque;
-
- if (!(s->regs[R_TIMER0_CONTROL] & CTRL_AUTORESTART)) {
- s->regs[R_TIMER0_CONTROL] &= ~CTRL_ENABLE;
- trace_milkymist_sysctl_stop_timer0();
- ptimer_stop(s->ptimer0);
- }
-
- trace_milkymist_sysctl_pulse_irq_timer0();
- qemu_irq_pulse(s->timer0_irq);
-}
-
-static void timer1_hit(void *opaque)
-{
- MilkymistSysctlState *s = opaque;
-
- if (!(s->regs[R_TIMER1_CONTROL] & CTRL_AUTORESTART)) {
- s->regs[R_TIMER1_CONTROL] &= ~CTRL_ENABLE;
- trace_milkymist_sysctl_stop_timer1();
- ptimer_stop(s->ptimer1);
- }
-
- trace_milkymist_sysctl_pulse_irq_timer1();
- qemu_irq_pulse(s->timer1_irq);
-}
-
-static void milkymist_sysctl_reset(DeviceState *d)
-{
- MilkymistSysctlState *s = MILKYMIST_SYSCTL(d);
- int i;
-
- for (i = 0; i < R_MAX; i++) {
- s->regs[i] = 0;
- }
-
- ptimer_stop(s->ptimer0);
- ptimer_stop(s->ptimer1);
-
- /* defaults */
- s->regs[R_ICAP] = ICAP_READY;
- s->regs[R_SYSTEM_ID] = s->systemid;
- s->regs[R_CLK_FREQUENCY] = s->freq_hz;
- s->regs[R_CAPABILITIES] = s->capabilities;
- s->regs[R_GPIO_IN] = s->strappings;
-}
-
-static int milkymist_sysctl_init(SysBusDevice *dev)
-{
- MilkymistSysctlState *s = MILKYMIST_SYSCTL(dev);
-
- sysbus_init_irq(dev, &s->gpio_irq);
- sysbus_init_irq(dev, &s->timer0_irq);
- sysbus_init_irq(dev, &s->timer1_irq);
-
- s->bh0 = qemu_bh_new(timer0_hit, s);
- s->bh1 = qemu_bh_new(timer1_hit, s);
- s->ptimer0 = ptimer_init(s->bh0);
- s->ptimer1 = ptimer_init(s->bh1);
- ptimer_set_freq(s->ptimer0, s->freq_hz);
- ptimer_set_freq(s->ptimer1, s->freq_hz);
-
- memory_region_init_io(&s->regs_region, OBJECT(s), &sysctl_mmio_ops, s,
- "milkymist-sysctl", R_MAX * 4);
- sysbus_init_mmio(dev, &s->regs_region);
-
- return 0;
-}
-
-static const VMStateDescription vmstate_milkymist_sysctl = {
- .name = "milkymist-sysctl",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, MilkymistSysctlState, R_MAX),
- VMSTATE_PTIMER(ptimer0, MilkymistSysctlState),
- VMSTATE_PTIMER(ptimer1, MilkymistSysctlState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property milkymist_sysctl_properties[] = {
- DEFINE_PROP_UINT32("frequency", MilkymistSysctlState,
- freq_hz, 80000000),
- DEFINE_PROP_UINT32("capabilities", MilkymistSysctlState,
- capabilities, 0x00000000),
- DEFINE_PROP_UINT32("systemid", MilkymistSysctlState,
- systemid, 0x10014d31),
- DEFINE_PROP_UINT32("gpio_strappings", MilkymistSysctlState,
- strappings, 0x00000001),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void milkymist_sysctl_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = milkymist_sysctl_init;
- dc->reset = milkymist_sysctl_reset;
- dc->vmsd = &vmstate_milkymist_sysctl;
- dc->props = milkymist_sysctl_properties;
-}
-
-static const TypeInfo milkymist_sysctl_info = {
- .name = TYPE_MILKYMIST_SYSCTL,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(MilkymistSysctlState),
- .class_init = milkymist_sysctl_class_init,
-};
-
-static void milkymist_sysctl_register_types(void)
-{
- type_register_static(&milkymist_sysctl_info);
-}
-
-type_init(milkymist_sysctl_register_types)
diff --git a/qemu/hw/timer/omap_gptimer.c b/qemu/hw/timer/omap_gptimer.c
deleted file mode 100644
index 3a4386304..000000000
--- a/qemu/hw/timer/omap_gptimer.c
+++ /dev/null
@@ -1,488 +0,0 @@
-/*
- * TI OMAP2 general purpose timers emulation.
- *
- * Copyright (C) 2007-2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) any later version of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "qemu/timer.h"
-#include "hw/arm/omap.h"
-
-/* GP timers */
-struct omap_gp_timer_s {
- MemoryRegion iomem;
- qemu_irq irq;
- qemu_irq wkup;
- qemu_irq in;
- qemu_irq out;
- omap_clk clk;
- QEMUTimer *timer;
- QEMUTimer *match;
- struct omap_target_agent_s *ta;
-
- int in_val;
- int out_val;
- int64_t time;
- int64_t rate;
- int64_t ticks_per_sec;
-
- int16_t config;
- int status;
- int it_ena;
- int wu_ena;
- int enable;
- int inout;
- int capt2;
- int pt;
- enum {
- gpt_trigger_none, gpt_trigger_overflow, gpt_trigger_both
- } trigger;
- enum {
- gpt_capture_none, gpt_capture_rising,
- gpt_capture_falling, gpt_capture_both
- } capture;
- int scpwm;
- int ce;
- int pre;
- int ptv;
- int ar;
- int st;
- int posted;
- uint32_t val;
- uint32_t load_val;
- uint32_t capture_val[2];
- uint32_t match_val;
- int capt_num;
-
- uint16_t writeh; /* LSB */
- uint16_t readh; /* MSB */
-};
-
-#define GPT_TCAR_IT (1 << 2)
-#define GPT_OVF_IT (1 << 1)
-#define GPT_MAT_IT (1 << 0)
-
-static inline void omap_gp_timer_intr(struct omap_gp_timer_s *timer, int it)
-{
- if (timer->it_ena & it) {
- if (!timer->status)
- qemu_irq_raise(timer->irq);
-
- timer->status |= it;
- /* Or are the status bits set even when masked?
- * i.e. is masking applied before or after the status register? */
- }
-
- if (timer->wu_ena & it)
- qemu_irq_pulse(timer->wkup);
-}
-
-static inline void omap_gp_timer_out(struct omap_gp_timer_s *timer, int level)
-{
- if (!timer->inout && timer->out_val != level) {
- timer->out_val = level;
- qemu_set_irq(timer->out, level);
- }
-}
-
-static inline uint32_t omap_gp_timer_read(struct omap_gp_timer_s *timer)
-{
- uint64_t distance;
-
- if (timer->st && timer->rate) {
- distance = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - timer->time;
- distance = muldiv64(distance, timer->rate, timer->ticks_per_sec);
-
- if (distance >= 0xffffffff - timer->val)
- return 0xffffffff;
- else
- return timer->val + distance;
- } else
- return timer->val;
-}
-
-static inline void omap_gp_timer_sync(struct omap_gp_timer_s *timer)
-{
- if (timer->st) {
- timer->val = omap_gp_timer_read(timer);
- timer->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- }
-}
-
-static inline void omap_gp_timer_update(struct omap_gp_timer_s *timer)
-{
- int64_t expires, matches;
-
- if (timer->st && timer->rate) {
- expires = muldiv64(0x100000000ll - timer->val,
- timer->ticks_per_sec, timer->rate);
- timer_mod(timer->timer, timer->time + expires);
-
- if (timer->ce && timer->match_val >= timer->val) {
- matches = muldiv64(timer->match_val - timer->val,
- timer->ticks_per_sec, timer->rate);
- timer_mod(timer->match, timer->time + matches);
- } else
- timer_del(timer->match);
- } else {
- timer_del(timer->timer);
- timer_del(timer->match);
- omap_gp_timer_out(timer, timer->scpwm);
- }
-}
-
-static inline void omap_gp_timer_trigger(struct omap_gp_timer_s *timer)
-{
- if (timer->pt)
- /* TODO in overflow-and-match mode if the first event to
- * occur is the match, don't toggle. */
- omap_gp_timer_out(timer, !timer->out_val);
- else
- /* TODO inverted pulse on timer->out_val == 1? */
- qemu_irq_pulse(timer->out);
-}
-
-static void omap_gp_timer_tick(void *opaque)
-{
- struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque;
-
- if (!timer->ar) {
- timer->st = 0;
- timer->val = 0;
- } else {
- timer->val = timer->load_val;
- timer->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- }
-
- if (timer->trigger == gpt_trigger_overflow ||
- timer->trigger == gpt_trigger_both)
- omap_gp_timer_trigger(timer);
-
- omap_gp_timer_intr(timer, GPT_OVF_IT);
- omap_gp_timer_update(timer);
-}
-
-static void omap_gp_timer_match(void *opaque)
-{
- struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque;
-
- if (timer->trigger == gpt_trigger_both)
- omap_gp_timer_trigger(timer);
-
- omap_gp_timer_intr(timer, GPT_MAT_IT);
-}
-
-static void omap_gp_timer_input(void *opaque, int line, int on)
-{
- struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
- int trigger;
-
- switch (s->capture) {
- default:
- case gpt_capture_none:
- trigger = 0;
- break;
- case gpt_capture_rising:
- trigger = !s->in_val && on;
- break;
- case gpt_capture_falling:
- trigger = s->in_val && !on;
- break;
- case gpt_capture_both:
- trigger = (s->in_val == !on);
- break;
- }
- s->in_val = on;
-
- if (s->inout && trigger && s->capt_num < 2) {
- s->capture_val[s->capt_num] = omap_gp_timer_read(s);
-
- if (s->capt2 == s->capt_num ++)
- omap_gp_timer_intr(s, GPT_TCAR_IT);
- }
-}
-
-static void omap_gp_timer_clk_update(void *opaque, int line, int on)
-{
- struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque;
-
- omap_gp_timer_sync(timer);
- timer->rate = on ? omap_clk_getrate(timer->clk) : 0;
- omap_gp_timer_update(timer);
-}
-
-static void omap_gp_timer_clk_setup(struct omap_gp_timer_s *timer)
-{
- omap_clk_adduser(timer->clk,
- qemu_allocate_irq(omap_gp_timer_clk_update, timer, 0));
- timer->rate = omap_clk_getrate(timer->clk);
-}
-
-void omap_gp_timer_reset(struct omap_gp_timer_s *s)
-{
- s->config = 0x000;
- s->status = 0;
- s->it_ena = 0;
- s->wu_ena = 0;
- s->inout = 0;
- s->capt2 = 0;
- s->capt_num = 0;
- s->pt = 0;
- s->trigger = gpt_trigger_none;
- s->capture = gpt_capture_none;
- s->scpwm = 0;
- s->ce = 0;
- s->pre = 0;
- s->ptv = 0;
- s->ar = 0;
- s->st = 0;
- s->posted = 1;
- s->val = 0x00000000;
- s->load_val = 0x00000000;
- s->capture_val[0] = 0x00000000;
- s->capture_val[1] = 0x00000000;
- s->match_val = 0x00000000;
- omap_gp_timer_update(s);
-}
-
-static uint32_t omap_gp_timer_readw(void *opaque, hwaddr addr)
-{
- struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
-
- switch (addr) {
- case 0x00: /* TIDR */
- return 0x21;
-
- case 0x10: /* TIOCP_CFG */
- return s->config;
-
- case 0x14: /* TISTAT */
- /* ??? When's this bit reset? */
- return 1; /* RESETDONE */
-
- case 0x18: /* TISR */
- return s->status;
-
- case 0x1c: /* TIER */
- return s->it_ena;
-
- case 0x20: /* TWER */
- return s->wu_ena;
-
- case 0x24: /* TCLR */
- return (s->inout << 14) |
- (s->capt2 << 13) |
- (s->pt << 12) |
- (s->trigger << 10) |
- (s->capture << 8) |
- (s->scpwm << 7) |
- (s->ce << 6) |
- (s->pre << 5) |
- (s->ptv << 2) |
- (s->ar << 1) |
- (s->st << 0);
-
- case 0x28: /* TCRR */
- return omap_gp_timer_read(s);
-
- case 0x2c: /* TLDR */
- return s->load_val;
-
- case 0x30: /* TTGR */
- return 0xffffffff;
-
- case 0x34: /* TWPS */
- return 0x00000000; /* No posted writes pending. */
-
- case 0x38: /* TMAR */
- return s->match_val;
-
- case 0x3c: /* TCAR1 */
- return s->capture_val[0];
-
- case 0x40: /* TSICR */
- return s->posted << 2;
-
- case 0x44: /* TCAR2 */
- return s->capture_val[1];
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static uint32_t omap_gp_timer_readh(void *opaque, hwaddr addr)
-{
- struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
- uint32_t ret;
-
- if (addr & 2)
- return s->readh;
- else {
- ret = omap_gp_timer_readw(opaque, addr);
- s->readh = ret >> 16;
- return ret & 0xffff;
- }
-}
-
-static void omap_gp_timer_write(void *opaque, hwaddr addr,
- uint32_t value)
-{
- struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
-
- switch (addr) {
- case 0x00: /* TIDR */
- case 0x14: /* TISTAT */
- case 0x34: /* TWPS */
- case 0x3c: /* TCAR1 */
- case 0x44: /* TCAR2 */
- OMAP_RO_REG(addr);
- break;
-
- case 0x10: /* TIOCP_CFG */
- s->config = value & 0x33d;
- if (((value >> 3) & 3) == 3) /* IDLEMODE */
- fprintf(stderr, "%s: illegal IDLEMODE value in TIOCP_CFG\n",
- __FUNCTION__);
- if (value & 2) /* SOFTRESET */
- omap_gp_timer_reset(s);
- break;
-
- case 0x18: /* TISR */
- if (value & GPT_TCAR_IT)
- s->capt_num = 0;
- if (s->status && !(s->status &= ~value))
- qemu_irq_lower(s->irq);
- break;
-
- case 0x1c: /* TIER */
- s->it_ena = value & 7;
- break;
-
- case 0x20: /* TWER */
- s->wu_ena = value & 7;
- break;
-
- case 0x24: /* TCLR */
- omap_gp_timer_sync(s);
- s->inout = (value >> 14) & 1;
- s->capt2 = (value >> 13) & 1;
- s->pt = (value >> 12) & 1;
- s->trigger = (value >> 10) & 3;
- if (s->capture == gpt_capture_none &&
- ((value >> 8) & 3) != gpt_capture_none)
- s->capt_num = 0;
- s->capture = (value >> 8) & 3;
- s->scpwm = (value >> 7) & 1;
- s->ce = (value >> 6) & 1;
- s->pre = (value >> 5) & 1;
- s->ptv = (value >> 2) & 7;
- s->ar = (value >> 1) & 1;
- s->st = (value >> 0) & 1;
- if (s->inout && s->trigger != gpt_trigger_none)
- fprintf(stderr, "%s: GP timer pin must be an output "
- "for this trigger mode\n", __FUNCTION__);
- if (!s->inout && s->capture != gpt_capture_none)
- fprintf(stderr, "%s: GP timer pin must be an input "
- "for this capture mode\n", __FUNCTION__);
- if (s->trigger == gpt_trigger_none)
- omap_gp_timer_out(s, s->scpwm);
- /* TODO: make sure this doesn't overflow 32-bits */
- s->ticks_per_sec = NANOSECONDS_PER_SECOND << (s->pre ? s->ptv + 1 : 0);
- omap_gp_timer_update(s);
- break;
-
- case 0x28: /* TCRR */
- s->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- s->val = value;
- omap_gp_timer_update(s);
- break;
-
- case 0x2c: /* TLDR */
- s->load_val = value;
- break;
-
- case 0x30: /* TTGR */
- s->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- s->val = s->load_val;
- omap_gp_timer_update(s);
- break;
-
- case 0x38: /* TMAR */
- omap_gp_timer_sync(s);
- s->match_val = value;
- omap_gp_timer_update(s);
- break;
-
- case 0x40: /* TSICR */
- s->posted = (value >> 2) & 1;
- if (value & 2) /* How much exactly are we supposed to reset? */
- omap_gp_timer_reset(s);
- break;
-
- default:
- OMAP_BAD_REG(addr);
- }
-}
-
-static void omap_gp_timer_writeh(void *opaque, hwaddr addr,
- uint32_t value)
-{
- struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
-
- if (addr & 2)
- omap_gp_timer_write(opaque, addr, (value << 16) | s->writeh);
- else
- s->writeh = (uint16_t) value;
-}
-
-static const MemoryRegionOps omap_gp_timer_ops = {
- .old_mmio = {
- .read = {
- omap_badwidth_read32,
- omap_gp_timer_readh,
- omap_gp_timer_readw,
- },
- .write = {
- omap_badwidth_write32,
- omap_gp_timer_writeh,
- omap_gp_timer_write,
- },
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct omap_gp_timer_s *omap_gp_timer_init(struct omap_target_agent_s *ta,
- qemu_irq irq, omap_clk fclk, omap_clk iclk)
-{
- struct omap_gp_timer_s *s = g_new0(struct omap_gp_timer_s, 1);
-
- s->ta = ta;
- s->irq = irq;
- s->clk = fclk;
- s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, omap_gp_timer_tick, s);
- s->match = timer_new_ns(QEMU_CLOCK_VIRTUAL, omap_gp_timer_match, s);
- s->in = qemu_allocate_irq(omap_gp_timer_input, s, 0);
- omap_gp_timer_reset(s);
- omap_gp_timer_clk_setup(s);
-
- memory_region_init_io(&s->iomem, NULL, &omap_gp_timer_ops, s, "omap.gptimer",
- omap_l4_region_size(ta, 0));
- omap_l4_attach(ta, 0, &s->iomem);
-
- return s;
-}
diff --git a/qemu/hw/timer/omap_synctimer.c b/qemu/hw/timer/omap_synctimer.c
deleted file mode 100644
index 9ee651979..000000000
--- a/qemu/hw/timer/omap_synctimer.c
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * TI OMAP2 32kHz sync timer emulation.
- *
- * Copyright (C) 2007-2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) any later version of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "qemu/timer.h"
-#include "hw/arm/omap.h"
-struct omap_synctimer_s {
- MemoryRegion iomem;
- uint32_t val;
- uint16_t readh;
-};
-
-/* 32-kHz Sync Timer of the OMAP2 */
-static uint32_t omap_synctimer_read(struct omap_synctimer_s *s) {
- return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 0x8000,
- NANOSECONDS_PER_SECOND);
-}
-
-void omap_synctimer_reset(struct omap_synctimer_s *s)
-{
- s->val = omap_synctimer_read(s);
-}
-
-static uint32_t omap_synctimer_readw(void *opaque, hwaddr addr)
-{
- struct omap_synctimer_s *s = (struct omap_synctimer_s *) opaque;
-
- switch (addr) {
- case 0x00: /* 32KSYNCNT_REV */
- return 0x21;
-
- case 0x10: /* CR */
- return omap_synctimer_read(s) - s->val;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static uint32_t omap_synctimer_readh(void *opaque, hwaddr addr)
-{
- struct omap_synctimer_s *s = (struct omap_synctimer_s *) opaque;
- uint32_t ret;
-
- if (addr & 2)
- return s->readh;
- else {
- ret = omap_synctimer_readw(opaque, addr);
- s->readh = ret >> 16;
- return ret & 0xffff;
- }
-}
-
-static void omap_synctimer_write(void *opaque, hwaddr addr,
- uint32_t value)
-{
- OMAP_BAD_REG(addr);
-}
-
-static const MemoryRegionOps omap_synctimer_ops = {
- .old_mmio = {
- .read = {
- omap_badwidth_read32,
- omap_synctimer_readh,
- omap_synctimer_readw,
- },
- .write = {
- omap_badwidth_write32,
- omap_synctimer_write,
- omap_synctimer_write,
- },
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct omap_synctimer_s *omap_synctimer_init(struct omap_target_agent_s *ta,
- struct omap_mpu_state_s *mpu, omap_clk fclk, omap_clk iclk)
-{
- struct omap_synctimer_s *s = g_malloc0(sizeof(*s));
-
- omap_synctimer_reset(s);
- memory_region_init_io(&s->iomem, NULL, &omap_synctimer_ops, s, "omap.synctimer",
- omap_l4_region_size(ta, 0));
- omap_l4_attach(ta, 0, &s->iomem);
-
- return s;
-}
diff --git a/qemu/hw/timer/pl031.c b/qemu/hw/timer/pl031.c
deleted file mode 100644
index 38e0cb5ad..000000000
--- a/qemu/hw/timer/pl031.c
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * ARM AMBA PrimeCell PL031 RTC
- *
- * Copyright (c) 2007 CodeSourcery
- *
- * This file is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "qemu/timer.h"
-#include "sysemu/sysemu.h"
-#include "qemu/cutils.h"
-
-//#define DEBUG_PL031
-
-#ifdef DEBUG_PL031
-#define DPRINTF(fmt, ...) \
-do { printf("pl031: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#endif
-
-#define RTC_DR 0x00 /* Data read register */
-#define RTC_MR 0x04 /* Match register */
-#define RTC_LR 0x08 /* Data load register */
-#define RTC_CR 0x0c /* Control register */
-#define RTC_IMSC 0x10 /* Interrupt mask and set register */
-#define RTC_RIS 0x14 /* Raw interrupt status register */
-#define RTC_MIS 0x18 /* Masked interrupt status register */
-#define RTC_ICR 0x1c /* Interrupt clear register */
-
-#define TYPE_PL031 "pl031"
-#define PL031(obj) OBJECT_CHECK(PL031State, (obj), TYPE_PL031)
-
-typedef struct PL031State {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- QEMUTimer *timer;
- qemu_irq irq;
-
- /* Needed to preserve the tick_count across migration, even if the
- * absolute value of the rtc_clock is different on the source and
- * destination.
- */
- uint32_t tick_offset_vmstate;
- uint32_t tick_offset;
-
- uint32_t mr;
- uint32_t lr;
- uint32_t cr;
- uint32_t im;
- uint32_t is;
-} PL031State;
-
-static const unsigned char pl031_id[] = {
- 0x31, 0x10, 0x14, 0x00, /* Device ID */
- 0x0d, 0xf0, 0x05, 0xb1 /* Cell ID */
-};
-
-static void pl031_update(PL031State *s)
-{
- qemu_set_irq(s->irq, s->is & s->im);
-}
-
-static void pl031_interrupt(void * opaque)
-{
- PL031State *s = (PL031State *)opaque;
-
- s->is = 1;
- DPRINTF("Alarm raised\n");
- pl031_update(s);
-}
-
-static uint32_t pl031_get_count(PL031State *s)
-{
- int64_t now = qemu_clock_get_ns(rtc_clock);
- return s->tick_offset + now / NANOSECONDS_PER_SECOND;
-}
-
-static void pl031_set_alarm(PL031State *s)
-{
- uint32_t ticks;
-
- /* The timer wraps around. This subtraction also wraps in the same way,
- and gives correct results when alarm < now_ticks. */
- ticks = s->mr - pl031_get_count(s);
- DPRINTF("Alarm set in %ud ticks\n", ticks);
- if (ticks == 0) {
- timer_del(s->timer);
- pl031_interrupt(s);
- } else {
- int64_t now = qemu_clock_get_ns(rtc_clock);
- timer_mod(s->timer, now + (int64_t)ticks * NANOSECONDS_PER_SECOND);
- }
-}
-
-static uint64_t pl031_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- PL031State *s = (PL031State *)opaque;
-
- if (offset >= 0xfe0 && offset < 0x1000)
- return pl031_id[(offset - 0xfe0) >> 2];
-
- switch (offset) {
- case RTC_DR:
- return pl031_get_count(s);
- case RTC_MR:
- return s->mr;
- case RTC_IMSC:
- return s->im;
- case RTC_RIS:
- return s->is;
- case RTC_LR:
- return s->lr;
- case RTC_CR:
- /* RTC is permanently enabled. */
- return 1;
- case RTC_MIS:
- return s->is & s->im;
- case RTC_ICR:
- qemu_log_mask(LOG_GUEST_ERROR,
- "pl031: read of write-only register at offset 0x%x\n",
- (int)offset);
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "pl031_read: Bad offset 0x%x\n", (int)offset);
- break;
- }
-
- return 0;
-}
-
-static void pl031_write(void * opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PL031State *s = (PL031State *)opaque;
-
-
- switch (offset) {
- case RTC_LR:
- s->tick_offset += value - pl031_get_count(s);
- pl031_set_alarm(s);
- break;
- case RTC_MR:
- s->mr = value;
- pl031_set_alarm(s);
- break;
- case RTC_IMSC:
- s->im = value & 1;
- DPRINTF("Interrupt mask %d\n", s->im);
- pl031_update(s);
- break;
- case RTC_ICR:
- /* The PL031 documentation (DDI0224B) states that the interrupt is
- cleared when bit 0 of the written value is set. However the
- arm926e documentation (DDI0287B) states that the interrupt is
- cleared when any value is written. */
- DPRINTF("Interrupt cleared");
- s->is = 0;
- pl031_update(s);
- break;
- case RTC_CR:
- /* Written value is ignored. */
- break;
-
- case RTC_DR:
- case RTC_MIS:
- case RTC_RIS:
- qemu_log_mask(LOG_GUEST_ERROR,
- "pl031: write to read-only register at offset 0x%x\n",
- (int)offset);
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "pl031_write: Bad offset 0x%x\n", (int)offset);
- break;
- }
-}
-
-static const MemoryRegionOps pl031_ops = {
- .read = pl031_read,
- .write = pl031_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void pl031_init(Object *obj)
-{
- PL031State *s = PL031(obj);
- SysBusDevice *dev = SYS_BUS_DEVICE(obj);
- struct tm tm;
-
- memory_region_init_io(&s->iomem, obj, &pl031_ops, s, "pl031", 0x1000);
- sysbus_init_mmio(dev, &s->iomem);
-
- sysbus_init_irq(dev, &s->irq);
- qemu_get_timedate(&tm, 0);
- s->tick_offset = mktimegm(&tm) -
- qemu_clock_get_ns(rtc_clock) / NANOSECONDS_PER_SECOND;
-
- s->timer = timer_new_ns(rtc_clock, pl031_interrupt, s);
-}
-
-static void pl031_pre_save(void *opaque)
-{
- PL031State *s = opaque;
-
- /* tick_offset is base_time - rtc_clock base time. Instead, we want to
- * store the base time relative to the QEMU_CLOCK_VIRTUAL for backwards-compatibility. */
- int64_t delta = qemu_clock_get_ns(rtc_clock) - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- s->tick_offset_vmstate = s->tick_offset + delta / NANOSECONDS_PER_SECOND;
-}
-
-static int pl031_post_load(void *opaque, int version_id)
-{
- PL031State *s = opaque;
-
- int64_t delta = qemu_clock_get_ns(rtc_clock) - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- s->tick_offset = s->tick_offset_vmstate - delta / NANOSECONDS_PER_SECOND;
- pl031_set_alarm(s);
- return 0;
-}
-
-static const VMStateDescription vmstate_pl031 = {
- .name = "pl031",
- .version_id = 1,
- .minimum_version_id = 1,
- .pre_save = pl031_pre_save,
- .post_load = pl031_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(tick_offset_vmstate, PL031State),
- VMSTATE_UINT32(mr, PL031State),
- VMSTATE_UINT32(lr, PL031State),
- VMSTATE_UINT32(cr, PL031State),
- VMSTATE_UINT32(im, PL031State),
- VMSTATE_UINT32(is, PL031State),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void pl031_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->vmsd = &vmstate_pl031;
-}
-
-static const TypeInfo pl031_info = {
- .name = TYPE_PL031,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PL031State),
- .instance_init = pl031_init,
- .class_init = pl031_class_init,
-};
-
-static void pl031_register_types(void)
-{
- type_register_static(&pl031_info);
-}
-
-type_init(pl031_register_types)
diff --git a/qemu/hw/timer/puv3_ost.c b/qemu/hw/timer/puv3_ost.c
deleted file mode 100644
index 93650b799..000000000
--- a/qemu/hw/timer/puv3_ost.c
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * OSTimer device simulation in PKUnity SoC
- *
- * Copyright (C) 2010-2012 Guan Xuetao
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation, or any later version.
- * See the COPYING file in the top-level directory.
- */
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "hw/ptimer.h"
-#include "qemu/main-loop.h"
-
-#undef DEBUG_PUV3
-#include "hw/unicore32/puv3.h"
-
-#define TYPE_PUV3_OST "puv3_ost"
-#define PUV3_OST(obj) OBJECT_CHECK(PUV3OSTState, (obj), TYPE_PUV3_OST)
-
-/* puv3 ostimer implementation. */
-typedef struct PUV3OSTState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- QEMUBH *bh;
- qemu_irq irq;
- ptimer_state *ptimer;
-
- uint32_t reg_OSMR0;
- uint32_t reg_OSCR;
- uint32_t reg_OSSR;
- uint32_t reg_OIER;
-} PUV3OSTState;
-
-static uint64_t puv3_ost_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- PUV3OSTState *s = opaque;
- uint32_t ret = 0;
-
- switch (offset) {
- case 0x10: /* Counter Register */
- ret = s->reg_OSMR0 - (uint32_t)ptimer_get_count(s->ptimer);
- break;
- case 0x14: /* Status Register */
- ret = s->reg_OSSR;
- break;
- case 0x1c: /* Interrupt Enable Register */
- ret = s->reg_OIER;
- break;
- default:
- DPRINTF("Bad offset %x\n", (int)offset);
- }
- DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
- return ret;
-}
-
-static void puv3_ost_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PUV3OSTState *s = opaque;
-
- DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
- switch (offset) {
- case 0x00: /* Match Register 0 */
- s->reg_OSMR0 = value;
- if (s->reg_OSMR0 > s->reg_OSCR) {
- ptimer_set_count(s->ptimer, s->reg_OSMR0 - s->reg_OSCR);
- } else {
- ptimer_set_count(s->ptimer, s->reg_OSMR0 +
- (0xffffffff - s->reg_OSCR));
- }
- ptimer_run(s->ptimer, 2);
- break;
- case 0x14: /* Status Register */
- assert(value == 0);
- if (s->reg_OSSR) {
- s->reg_OSSR = value;
- qemu_irq_lower(s->irq);
- }
- break;
- case 0x1c: /* Interrupt Enable Register */
- s->reg_OIER = value;
- break;
- default:
- DPRINTF("Bad offset %x\n", (int)offset);
- }
-}
-
-static const MemoryRegionOps puv3_ost_ops = {
- .read = puv3_ost_read,
- .write = puv3_ost_write,
- .impl = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void puv3_ost_tick(void *opaque)
-{
- PUV3OSTState *s = opaque;
-
- DPRINTF("ost hit when ptimer counter from 0x%x to 0x%x!\n",
- s->reg_OSCR, s->reg_OSMR0);
-
- s->reg_OSCR = s->reg_OSMR0;
- if (s->reg_OIER) {
- s->reg_OSSR = 1;
- qemu_irq_raise(s->irq);
- }
-}
-
-static int puv3_ost_init(SysBusDevice *dev)
-{
- PUV3OSTState *s = PUV3_OST(dev);
-
- s->reg_OIER = 0;
- s->reg_OSSR = 0;
- s->reg_OSMR0 = 0;
- s->reg_OSCR = 0;
-
- sysbus_init_irq(dev, &s->irq);
-
- s->bh = qemu_bh_new(puv3_ost_tick, s);
- s->ptimer = ptimer_init(s->bh);
- ptimer_set_freq(s->ptimer, 50 * 1000 * 1000);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &puv3_ost_ops, s, "puv3_ost",
- PUV3_REGS_OFFSET);
- sysbus_init_mmio(dev, &s->iomem);
-
- return 0;
-}
-
-static void puv3_ost_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
- sdc->init = puv3_ost_init;
-}
-
-static const TypeInfo puv3_ost_info = {
- .name = TYPE_PUV3_OST,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PUV3OSTState),
- .class_init = puv3_ost_class_init,
-};
-
-static void puv3_ost_register_type(void)
-{
- type_register_static(&puv3_ost_info);
-}
-
-type_init(puv3_ost_register_type)
diff --git a/qemu/hw/timer/pxa2xx_timer.c b/qemu/hw/timer/pxa2xx_timer.c
deleted file mode 100644
index 59002b407..000000000
--- a/qemu/hw/timer/pxa2xx_timer.c
+++ /dev/null
@@ -1,605 +0,0 @@
-/*
- * Intel XScale PXA255/270 OS Timers.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Copyright (c) 2006 Thorsten Zitterell
- *
- * This code is licensed under the GPL.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "qemu/timer.h"
-#include "sysemu/sysemu.h"
-#include "hw/arm/pxa.h"
-#include "hw/sysbus.h"
-
-#define OSMR0 0x00
-#define OSMR1 0x04
-#define OSMR2 0x08
-#define OSMR3 0x0c
-#define OSMR4 0x80
-#define OSMR5 0x84
-#define OSMR6 0x88
-#define OSMR7 0x8c
-#define OSMR8 0x90
-#define OSMR9 0x94
-#define OSMR10 0x98
-#define OSMR11 0x9c
-#define OSCR 0x10 /* OS Timer Count */
-#define OSCR4 0x40
-#define OSCR5 0x44
-#define OSCR6 0x48
-#define OSCR7 0x4c
-#define OSCR8 0x50
-#define OSCR9 0x54
-#define OSCR10 0x58
-#define OSCR11 0x5c
-#define OSSR 0x14 /* Timer status register */
-#define OWER 0x18
-#define OIER 0x1c /* Interrupt enable register 3-0 to E3-E0 */
-#define OMCR4 0xc0 /* OS Match Control registers */
-#define OMCR5 0xc4
-#define OMCR6 0xc8
-#define OMCR7 0xcc
-#define OMCR8 0xd0
-#define OMCR9 0xd4
-#define OMCR10 0xd8
-#define OMCR11 0xdc
-#define OSNR 0x20
-
-#define PXA25X_FREQ 3686400 /* 3.6864 MHz */
-#define PXA27X_FREQ 3250000 /* 3.25 MHz */
-
-static int pxa2xx_timer4_freq[8] = {
- [0] = 0,
- [1] = 32768,
- [2] = 1000,
- [3] = 1,
- [4] = 1000000,
- /* [5] is the "Externally supplied clock". Assign if necessary. */
- [5 ... 7] = 0,
-};
-
-#define TYPE_PXA2XX_TIMER "pxa2xx-timer"
-#define PXA2XX_TIMER(obj) \
- OBJECT_CHECK(PXA2xxTimerInfo, (obj), TYPE_PXA2XX_TIMER)
-
-typedef struct PXA2xxTimerInfo PXA2xxTimerInfo;
-
-typedef struct {
- uint32_t value;
- qemu_irq irq;
- QEMUTimer *qtimer;
- int num;
- PXA2xxTimerInfo *info;
-} PXA2xxTimer0;
-
-typedef struct {
- PXA2xxTimer0 tm;
- int32_t oldclock;
- int32_t clock;
- uint64_t lastload;
- uint32_t freq;
- uint32_t control;
-} PXA2xxTimer4;
-
-struct PXA2xxTimerInfo {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- uint32_t flags;
-
- int32_t clock;
- int32_t oldclock;
- uint64_t lastload;
- uint32_t freq;
- PXA2xxTimer0 timer[4];
- uint32_t events;
- uint32_t irq_enabled;
- uint32_t reset3;
- uint32_t snapshot;
-
- qemu_irq irq4;
- PXA2xxTimer4 tm4[8];
-};
-
-#define PXA2XX_TIMER_HAVE_TM4 0
-
-static inline int pxa2xx_timer_has_tm4(PXA2xxTimerInfo *s)
-{
- return s->flags & (1 << PXA2XX_TIMER_HAVE_TM4);
-}
-
-static void pxa2xx_timer_update(void *opaque, uint64_t now_qemu)
-{
- PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
- int i;
- uint32_t now_vm;
- uint64_t new_qemu;
-
- now_vm = s->clock +
- muldiv64(now_qemu - s->lastload, s->freq, NANOSECONDS_PER_SECOND);
-
- for (i = 0; i < 4; i ++) {
- new_qemu = now_qemu + muldiv64((uint32_t) (s->timer[i].value - now_vm),
- NANOSECONDS_PER_SECOND, s->freq);
- timer_mod(s->timer[i].qtimer, new_qemu);
- }
-}
-
-static void pxa2xx_timer_update4(void *opaque, uint64_t now_qemu, int n)
-{
- PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
- uint32_t now_vm;
- uint64_t new_qemu;
- static const int counters[8] = { 0, 0, 0, 0, 4, 4, 6, 6 };
- int counter;
-
- if (s->tm4[n].control & (1 << 7))
- counter = n;
- else
- counter = counters[n];
-
- if (!s->tm4[counter].freq) {
- timer_del(s->tm4[n].tm.qtimer);
- return;
- }
-
- now_vm = s->tm4[counter].clock + muldiv64(now_qemu -
- s->tm4[counter].lastload,
- s->tm4[counter].freq, NANOSECONDS_PER_SECOND);
-
- new_qemu = now_qemu + muldiv64((uint32_t) (s->tm4[n].tm.value - now_vm),
- NANOSECONDS_PER_SECOND, s->tm4[counter].freq);
- timer_mod(s->tm4[n].tm.qtimer, new_qemu);
-}
-
-static uint64_t pxa2xx_timer_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
- int tm = 0;
-
- 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;
- return s->tm4[tm].tm.value;
- case OSCR:
- return s->clock + muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) -
- s->lastload, s->freq, NANOSECONDS_PER_SECOND);
- 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;
-
- if ((tm == 9 - 4 || tm == 11 - 4) && (s->tm4[tm].control & (1 << 9))) {
- if (s->tm4[tm - 1].freq)
- s->snapshot = s->tm4[tm - 1].clock + muldiv64(
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) -
- s->tm4[tm - 1].lastload,
- s->tm4[tm - 1].freq, NANOSECONDS_PER_SECOND);
- else
- s->snapshot = s->tm4[tm - 1].clock;
- }
-
- if (!s->tm4[tm].freq)
- return s->tm4[tm].clock;
- return s->tm4[tm].clock +
- muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) -
- s->tm4[tm].lastload, s->tm4[tm].freq,
- NANOSECONDS_PER_SECOND);
- case OIER:
- return s->irq_enabled;
- case OSSR: /* Status register */
- return s->events;
- 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;
- return s->tm4[tm].control;
- case OSNR:
- return s->snapshot;
- default:
- badreg:
- hw_error("pxa2xx_timer_read: Bad offset " REG_FMT "\n", offset);
- }
-
- return 0;
-}
-
-static void pxa2xx_timer_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- int i, tm = 0;
- PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
-
- 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_clock_get_ns(QEMU_CLOCK_VIRTUAL));
- 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;
- s->tm4[tm].tm.value = value;
- pxa2xx_timer_update4(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tm);
- break;
- case OSCR:
- s->oldclock = s->clock;
- s->lastload = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- s->clock = value;
- 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;
- s->tm4[tm].oldclock = s->tm4[tm].clock;
- s->tm4[tm].lastload = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- s->tm4[tm].clock = value;
- pxa2xx_timer_update4(s, s->tm4[tm].lastload, tm);
- break;
- case OIER:
- s->irq_enabled = value & 0xfff;
- break;
- case OSSR: /* Status register */
- value &= s->events;
- s->events &= ~value;
- for (i = 0; i < 4; i ++, value >>= 1)
- if (value & 1)
- qemu_irq_lower(s->timer[i].irq);
- if (pxa2xx_timer_has_tm4(s) && !(s->events & 0xff0) && value)
- qemu_irq_lower(s->irq4);
- break;
- case OWER: /* XXX: Reset on OSMR3 match? */
- 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;
- s->tm4[tm].control = value & 0x0ff;
- /* XXX Stop if running (shouldn't happen) */
- if ((value & (1 << 7)) || tm == 0)
- s->tm4[tm].freq = pxa2xx_timer4_freq[value & 7];
- else {
- s->tm4[tm].freq = 0;
- pxa2xx_timer_update4(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tm);
- }
- 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;
- s->tm4[tm].control = value & 0x3ff;
- /* XXX Stop if running (shouldn't happen) */
- if ((value & (1 << 7)) || !(tm & 1))
- s->tm4[tm].freq =
- pxa2xx_timer4_freq[(value & (1 << 8)) ? 0 : (value & 7)];
- else {
- s->tm4[tm].freq = 0;
- pxa2xx_timer_update4(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tm);
- }
- break;
- default:
- badreg:
- hw_error("pxa2xx_timer_write: Bad offset " REG_FMT "\n", offset);
- }
-}
-
-static const MemoryRegionOps pxa2xx_timer_ops = {
- .read = pxa2xx_timer_read,
- .write = pxa2xx_timer_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void pxa2xx_timer_tick(void *opaque)
-{
- PXA2xxTimer0 *t = (PXA2xxTimer0 *) opaque;
- PXA2xxTimerInfo *i = t->info;
-
- if (i->irq_enabled & (1 << t->num)) {
- i->events |= 1 << t->num;
- qemu_irq_raise(t->irq);
- }
-
- if (t->num == 3)
- if (i->reset3 & 1) {
- i->reset3 = 0;
- qemu_system_reset_request();
- }
-}
-
-static void pxa2xx_timer_tick4(void *opaque)
-{
- PXA2xxTimer4 *t = (PXA2xxTimer4 *) opaque;
- PXA2xxTimerInfo *i = (PXA2xxTimerInfo *) t->tm.info;
-
- pxa2xx_timer_tick(&t->tm);
- if (t->control & (1 << 3))
- t->clock = 0;
- if (t->control & (1 << 6))
- pxa2xx_timer_update4(i, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), t->tm.num - 4);
- if (i->events & 0xff0)
- qemu_irq_raise(i->irq4);
-}
-
-static int pxa25x_timer_post_load(void *opaque, int version_id)
-{
- PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
- int64_t now;
- int i;
-
- now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- pxa2xx_timer_update(s, now);
-
- if (pxa2xx_timer_has_tm4(s))
- for (i = 0; i < 8; i ++)
- pxa2xx_timer_update4(s, now, i);
-
- return 0;
-}
-
-static void pxa2xx_timer_init(Object *obj)
-{
- PXA2xxTimerInfo *s = PXA2XX_TIMER(obj);
- SysBusDevice *dev = SYS_BUS_DEVICE(obj);
-
- s->irq_enabled = 0;
- s->oldclock = 0;
- s->clock = 0;
- s->lastload = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- s->reset3 = 0;
-
- memory_region_init_io(&s->iomem, obj, &pxa2xx_timer_ops, s,
- "pxa2xx-timer", 0x00001000);
- sysbus_init_mmio(dev, &s->iomem);
-}
-
-static void pxa2xx_timer_realize(DeviceState *dev, Error **errp)
-{
- PXA2xxTimerInfo *s = PXA2XX_TIMER(dev);
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- int i;
-
- for (i = 0; i < 4; i ++) {
- s->timer[i].value = 0;
- sysbus_init_irq(sbd, &s->timer[i].irq);
- s->timer[i].info = s;
- s->timer[i].num = i;
- s->timer[i].qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
- pxa2xx_timer_tick, &s->timer[i]);
- }
-
- if (s->flags & (1 << PXA2XX_TIMER_HAVE_TM4)) {
- sysbus_init_irq(sbd, &s->irq4);
-
- for (i = 0; i < 8; i ++) {
- s->tm4[i].tm.value = 0;
- s->tm4[i].tm.info = s;
- s->tm4[i].tm.num = i + 4;
- s->tm4[i].freq = 0;
- s->tm4[i].control = 0x0;
- s->tm4[i].tm.qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
- pxa2xx_timer_tick4, &s->tm4[i]);
- }
- }
-}
-
-static const VMStateDescription vmstate_pxa2xx_timer0_regs = {
- .name = "pxa2xx_timer0",
- .version_id = 2,
- .minimum_version_id = 2,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(value, PXA2xxTimer0),
- VMSTATE_END_OF_LIST(),
- },
-};
-
-static const VMStateDescription vmstate_pxa2xx_timer4_regs = {
- .name = "pxa2xx_timer4",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT(tm, PXA2xxTimer4, 1,
- vmstate_pxa2xx_timer0_regs, PXA2xxTimer0),
- VMSTATE_INT32(oldclock, PXA2xxTimer4),
- VMSTATE_INT32(clock, PXA2xxTimer4),
- VMSTATE_UINT64(lastload, PXA2xxTimer4),
- VMSTATE_UINT32(freq, PXA2xxTimer4),
- VMSTATE_UINT32(control, PXA2xxTimer4),
- VMSTATE_END_OF_LIST(),
- },
-};
-
-static bool pxa2xx_timer_has_tm4_test(void *opaque, int version_id)
-{
- return pxa2xx_timer_has_tm4(opaque);
-}
-
-static const VMStateDescription vmstate_pxa2xx_timer_regs = {
- .name = "pxa2xx_timer",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = pxa25x_timer_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_INT32(clock, PXA2xxTimerInfo),
- VMSTATE_INT32(oldclock, PXA2xxTimerInfo),
- VMSTATE_UINT64(lastload, PXA2xxTimerInfo),
- VMSTATE_STRUCT_ARRAY(timer, PXA2xxTimerInfo, 4, 1,
- vmstate_pxa2xx_timer0_regs, PXA2xxTimer0),
- VMSTATE_UINT32(events, PXA2xxTimerInfo),
- VMSTATE_UINT32(irq_enabled, PXA2xxTimerInfo),
- VMSTATE_UINT32(reset3, PXA2xxTimerInfo),
- VMSTATE_UINT32(snapshot, PXA2xxTimerInfo),
- VMSTATE_STRUCT_ARRAY_TEST(tm4, PXA2xxTimerInfo, 8,
- pxa2xx_timer_has_tm4_test, 0,
- vmstate_pxa2xx_timer4_regs, PXA2xxTimer4),
- VMSTATE_END_OF_LIST(),
- }
-};
-
-static Property pxa25x_timer_dev_properties[] = {
- DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA25X_FREQ),
- DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags,
- PXA2XX_TIMER_HAVE_TM4, false),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pxa25x_timer_dev_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->desc = "PXA25x timer";
- dc->props = pxa25x_timer_dev_properties;
-}
-
-static const TypeInfo pxa25x_timer_dev_info = {
- .name = "pxa25x-timer",
- .parent = TYPE_PXA2XX_TIMER,
- .instance_size = sizeof(PXA2xxTimerInfo),
- .class_init = pxa25x_timer_dev_class_init,
-};
-
-static Property pxa27x_timer_dev_properties[] = {
- DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA27X_FREQ),
- DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags,
- PXA2XX_TIMER_HAVE_TM4, true),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pxa27x_timer_dev_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->desc = "PXA27x timer";
- dc->props = pxa27x_timer_dev_properties;
-}
-
-static const TypeInfo pxa27x_timer_dev_info = {
- .name = "pxa27x-timer",
- .parent = TYPE_PXA2XX_TIMER,
- .instance_size = sizeof(PXA2xxTimerInfo),
- .class_init = pxa27x_timer_dev_class_init,
-};
-
-static void pxa2xx_timer_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- dc->realize = pxa2xx_timer_realize;
- dc->vmsd = &vmstate_pxa2xx_timer_regs;
-}
-
-static const TypeInfo pxa2xx_timer_type_info = {
- .name = TYPE_PXA2XX_TIMER,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PXA2xxTimerInfo),
- .instance_init = pxa2xx_timer_init,
- .abstract = true,
- .class_init = pxa2xx_timer_class_init,
-};
-
-static void pxa2xx_timer_register_types(void)
-{
- type_register_static(&pxa2xx_timer_type_info);
- type_register_static(&pxa25x_timer_dev_info);
- type_register_static(&pxa27x_timer_dev_info);
-}
-
-type_init(pxa2xx_timer_register_types)
diff --git a/qemu/hw/timer/sh_timer.c b/qemu/hw/timer/sh_timer.c
deleted file mode 100644
index 255b2fc91..000000000
--- a/qemu/hw/timer/sh_timer.c
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * SuperH Timer modules.
- *
- * Copyright (c) 2007 Magnus Damm
- * Based on arm_timer.c by Paul Brook
- * Copyright (c) 2005-2006 CodeSourcery.
- *
- * This code is licensed under the GPL.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/sh4/sh.h"
-#include "qemu/timer.h"
-#include "qemu/main-loop.h"
-#include "exec/address-spaces.h"
-#include "hw/ptimer.h"
-
-//#define DEBUG_TIMER
-
-#define TIMER_TCR_TPSC (7 << 0)
-#define TIMER_TCR_CKEG (3 << 3)
-#define TIMER_TCR_UNIE (1 << 5)
-#define TIMER_TCR_ICPE (3 << 6)
-#define TIMER_TCR_UNF (1 << 8)
-#define TIMER_TCR_ICPF (1 << 9)
-#define TIMER_TCR_RESERVED (0x3f << 10)
-
-#define TIMER_FEAT_CAPT (1 << 0)
-#define TIMER_FEAT_EXTCLK (1 << 1)
-
-#define OFFSET_TCOR 0
-#define OFFSET_TCNT 1
-#define OFFSET_TCR 2
-#define OFFSET_TCPR 3
-
-typedef struct {
- ptimer_state *timer;
- uint32_t tcnt;
- uint32_t tcor;
- uint32_t tcr;
- uint32_t tcpr;
- int freq;
- int int_level;
- int old_level;
- int feat;
- int enabled;
- qemu_irq irq;
-} sh_timer_state;
-
-/* Check all active timers, and schedule the next timer interrupt. */
-
-static void sh_timer_update(sh_timer_state *s)
-{
- int new_level = s->int_level && (s->tcr & TIMER_TCR_UNIE);
-
- if (new_level != s->old_level)
- qemu_set_irq (s->irq, new_level);
-
- s->old_level = s->int_level;
- s->int_level = new_level;
-}
-
-static uint32_t sh_timer_read(void *opaque, hwaddr offset)
-{
- sh_timer_state *s = (sh_timer_state *)opaque;
-
- switch (offset >> 2) {
- case OFFSET_TCOR:
- return s->tcor;
- case OFFSET_TCNT:
- return ptimer_get_count(s->timer);
- case OFFSET_TCR:
- return s->tcr | (s->int_level ? TIMER_TCR_UNF : 0);
- case OFFSET_TCPR:
- if (s->feat & TIMER_FEAT_CAPT)
- return s->tcpr;
- default:
- hw_error("sh_timer_read: Bad offset %x\n", (int)offset);
- return 0;
- }
-}
-
-static void sh_timer_write(void *opaque, hwaddr offset,
- uint32_t value)
-{
- sh_timer_state *s = (sh_timer_state *)opaque;
- int freq;
-
- switch (offset >> 2) {
- case OFFSET_TCOR:
- s->tcor = value;
- ptimer_set_limit(s->timer, s->tcor, 0);
- break;
- case OFFSET_TCNT:
- s->tcnt = value;
- ptimer_set_count(s->timer, s->tcnt);
- break;
- case OFFSET_TCR:
- if (s->enabled) {
- /* Pause the timer if it is running. This may cause some
- inaccuracy dure to rounding, but avoids a whole lot of other
- messyness. */
- ptimer_stop(s->timer);
- }
- freq = s->freq;
- /* ??? Need to recalculate expiry time after changing divisor. */
- switch (value & TIMER_TCR_TPSC) {
- case 0: freq >>= 2; break;
- case 1: freq >>= 4; break;
- case 2: freq >>= 6; break;
- case 3: freq >>= 8; break;
- case 4: freq >>= 10; break;
- case 6:
- case 7: if (s->feat & TIMER_FEAT_EXTCLK) break;
- default: hw_error("sh_timer_write: Reserved TPSC value\n"); break;
- }
- switch ((value & TIMER_TCR_CKEG) >> 3) {
- case 0: break;
- case 1:
- case 2:
- case 3: if (s->feat & TIMER_FEAT_EXTCLK) break;
- default: hw_error("sh_timer_write: Reserved CKEG value\n"); break;
- }
- switch ((value & TIMER_TCR_ICPE) >> 6) {
- case 0: break;
- case 2:
- case 3: if (s->feat & TIMER_FEAT_CAPT) break;
- default: hw_error("sh_timer_write: Reserved ICPE value\n"); break;
- }
- if ((value & TIMER_TCR_UNF) == 0)
- s->int_level = 0;
-
- value &= ~TIMER_TCR_UNF;
-
- if ((value & TIMER_TCR_ICPF) && (!(s->feat & TIMER_FEAT_CAPT)))
- hw_error("sh_timer_write: Reserved ICPF value\n");
-
- value &= ~TIMER_TCR_ICPF; /* capture not supported */
-
- if (value & TIMER_TCR_RESERVED)
- hw_error("sh_timer_write: Reserved TCR bits set\n");
- s->tcr = value;
- ptimer_set_limit(s->timer, s->tcor, 0);
- ptimer_set_freq(s->timer, freq);
- if (s->enabled) {
- /* Restart the timer if still enabled. */
- ptimer_run(s->timer, 0);
- }
- break;
- case OFFSET_TCPR:
- if (s->feat & TIMER_FEAT_CAPT) {
- s->tcpr = value;
- break;
- }
- default:
- hw_error("sh_timer_write: Bad offset %x\n", (int)offset);
- }
- sh_timer_update(s);
-}
-
-static void sh_timer_start_stop(void *opaque, int enable)
-{
- sh_timer_state *s = (sh_timer_state *)opaque;
-
-#ifdef DEBUG_TIMER
- printf("sh_timer_start_stop %d (%d)\n", enable, s->enabled);
-#endif
-
- if (s->enabled && !enable) {
- ptimer_stop(s->timer);
- }
- if (!s->enabled && enable) {
- ptimer_run(s->timer, 0);
- }
- s->enabled = !!enable;
-
-#ifdef DEBUG_TIMER
- printf("sh_timer_start_stop done %d\n", s->enabled);
-#endif
-}
-
-static void sh_timer_tick(void *opaque)
-{
- sh_timer_state *s = (sh_timer_state *)opaque;
- s->int_level = s->enabled;
- sh_timer_update(s);
-}
-
-static void *sh_timer_init(uint32_t freq, int feat, qemu_irq irq)
-{
- sh_timer_state *s;
- QEMUBH *bh;
-
- s = (sh_timer_state *)g_malloc0(sizeof(sh_timer_state));
- s->freq = freq;
- s->feat = feat;
- s->tcor = 0xffffffff;
- s->tcnt = 0xffffffff;
- s->tcpr = 0xdeadbeef;
- s->tcr = 0;
- s->enabled = 0;
- s->irq = irq;
-
- bh = qemu_bh_new(sh_timer_tick, s);
- s->timer = ptimer_init(bh);
-
- sh_timer_write(s, OFFSET_TCOR >> 2, s->tcor);
- sh_timer_write(s, OFFSET_TCNT >> 2, s->tcnt);
- sh_timer_write(s, OFFSET_TCPR >> 2, s->tcpr);
- sh_timer_write(s, OFFSET_TCR >> 2, s->tcpr);
- /* ??? Save/restore. */
- return s;
-}
-
-typedef struct {
- MemoryRegion iomem;
- MemoryRegion iomem_p4;
- MemoryRegion iomem_a7;
- void *timer[3];
- int level[3];
- uint32_t tocr;
- uint32_t tstr;
- int feat;
-} tmu012_state;
-
-static uint64_t tmu012_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- tmu012_state *s = (tmu012_state *)opaque;
-
-#ifdef DEBUG_TIMER
- printf("tmu012_read 0x%lx\n", (unsigned long) offset);
-#endif
-
- if (offset >= 0x20) {
- if (!(s->feat & TMU012_FEAT_3CHAN))
- hw_error("tmu012_write: Bad channel offset %x\n", (int)offset);
- return sh_timer_read(s->timer[2], offset - 0x20);
- }
-
- if (offset >= 0x14)
- return sh_timer_read(s->timer[1], offset - 0x14);
-
- if (offset >= 0x08)
- return sh_timer_read(s->timer[0], offset - 0x08);
-
- if (offset == 4)
- return s->tstr;
-
- if ((s->feat & TMU012_FEAT_TOCR) && offset == 0)
- return s->tocr;
-
- hw_error("tmu012_write: Bad offset %x\n", (int)offset);
- return 0;
-}
-
-static void tmu012_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- tmu012_state *s = (tmu012_state *)opaque;
-
-#ifdef DEBUG_TIMER
- printf("tmu012_write 0x%lx 0x%08x\n", (unsigned long) offset, value);
-#endif
-
- if (offset >= 0x20) {
- if (!(s->feat & TMU012_FEAT_3CHAN))
- hw_error("tmu012_write: Bad channel offset %x\n", (int)offset);
- sh_timer_write(s->timer[2], offset - 0x20, value);
- return;
- }
-
- if (offset >= 0x14) {
- sh_timer_write(s->timer[1], offset - 0x14, value);
- return;
- }
-
- if (offset >= 0x08) {
- sh_timer_write(s->timer[0], offset - 0x08, value);
- return;
- }
-
- if (offset == 4) {
- sh_timer_start_stop(s->timer[0], value & (1 << 0));
- sh_timer_start_stop(s->timer[1], value & (1 << 1));
- if (s->feat & TMU012_FEAT_3CHAN)
- sh_timer_start_stop(s->timer[2], value & (1 << 2));
- else
- if (value & (1 << 2))
- hw_error("tmu012_write: Bad channel\n");
-
- s->tstr = value;
- return;
- }
-
- if ((s->feat & TMU012_FEAT_TOCR) && offset == 0) {
- s->tocr = value & (1 << 0);
- }
-}
-
-static const MemoryRegionOps tmu012_ops = {
- .read = tmu012_read,
- .write = tmu012_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-void tmu012_init(MemoryRegion *sysmem, hwaddr base,
- int feat, uint32_t freq,
- qemu_irq ch0_irq, qemu_irq ch1_irq,
- qemu_irq ch2_irq0, qemu_irq ch2_irq1)
-{
- tmu012_state *s;
- int timer_feat = (feat & TMU012_FEAT_EXTCLK) ? TIMER_FEAT_EXTCLK : 0;
-
- s = (tmu012_state *)g_malloc0(sizeof(tmu012_state));
- s->feat = feat;
- s->timer[0] = sh_timer_init(freq, timer_feat, ch0_irq);
- s->timer[1] = sh_timer_init(freq, timer_feat, ch1_irq);
- if (feat & TMU012_FEAT_3CHAN)
- s->timer[2] = sh_timer_init(freq, timer_feat | TIMER_FEAT_CAPT,
- ch2_irq0); /* ch2_irq1 not supported */
-
- memory_region_init_io(&s->iomem, NULL, &tmu012_ops, s,
- "timer", 0x100000000ULL);
-
- memory_region_init_alias(&s->iomem_p4, NULL, "timer-p4",
- &s->iomem, 0, 0x1000);
- memory_region_add_subregion(sysmem, P4ADDR(base), &s->iomem_p4);
-
- memory_region_init_alias(&s->iomem_a7, NULL, "timer-a7",
- &s->iomem, 0, 0x1000);
- memory_region_add_subregion(sysmem, A7ADDR(base), &s->iomem_a7);
- /* ??? Save/restore. */
-}
diff --git a/qemu/hw/timer/slavio_timer.c b/qemu/hw/timer/slavio_timer.c
deleted file mode 100644
index fb3e08bed..000000000
--- a/qemu/hw/timer/slavio_timer.c
+++ /dev/null
@@ -1,435 +0,0 @@
-/*
- * QEMU Sparc SLAVIO timer controller emulation
- *
- * Copyright (c) 2003-2005 Fabrice Bellard
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sparc/sun4m.h"
-#include "qemu/timer.h"
-#include "hw/ptimer.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "qemu/main-loop.h"
-
-/*
- * Registers of hardware timer in sun4m.
- *
- * This is the timer/counter part of chip STP2001 (Slave I/O), also
- * produced as NCR89C105. See
- * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
- *
- * The 31-bit counter is incremented every 500ns by bit 9. Bits 8..0
- * are zero. Bit 31 is 1 when count has been reached.
- *
- * Per-CPU timers interrupt local CPU, system timer uses normal
- * interrupt routing.
- *
- */
-
-#define MAX_CPUS 16
-
-typedef struct CPUTimerState {
- qemu_irq irq;
- ptimer_state *timer;
- uint32_t count, counthigh, reached;
- /* processor only */
- uint32_t run;
- uint64_t limit;
-} CPUTimerState;
-
-#define TYPE_SLAVIO_TIMER "slavio_timer"
-#define SLAVIO_TIMER(obj) \
- OBJECT_CHECK(SLAVIO_TIMERState, (obj), TYPE_SLAVIO_TIMER)
-
-typedef struct SLAVIO_TIMERState {
- SysBusDevice parent_obj;
-
- uint32_t num_cpus;
- uint32_t cputimer_mode;
- CPUTimerState cputimer[MAX_CPUS + 1];
-} SLAVIO_TIMERState;
-
-typedef struct TimerContext {
- MemoryRegion iomem;
- SLAVIO_TIMERState *s;
- unsigned int timer_index; /* 0 for system, 1 ... MAX_CPUS for CPU timers */
-} TimerContext;
-
-#define SYS_TIMER_SIZE 0x14
-#define CPU_TIMER_SIZE 0x10
-
-#define TIMER_LIMIT 0
-#define TIMER_COUNTER 1
-#define TIMER_COUNTER_NORST 2
-#define TIMER_STATUS 3
-#define TIMER_MODE 4
-
-#define TIMER_COUNT_MASK32 0xfffffe00
-#define TIMER_LIMIT_MASK32 0x7fffffff
-#define TIMER_MAX_COUNT64 0x7ffffffffffffe00ULL
-#define TIMER_MAX_COUNT32 0x7ffffe00ULL
-#define TIMER_REACHED 0x80000000
-#define TIMER_PERIOD 500ULL // 500ns
-#define LIMIT_TO_PERIODS(l) (((l) >> 9) - 1)
-#define PERIODS_TO_LIMIT(l) (((l) + 1) << 9)
-
-static int slavio_timer_is_user(TimerContext *tc)
-{
- SLAVIO_TIMERState *s = tc->s;
- unsigned int timer_index = tc->timer_index;
-
- return timer_index != 0 && (s->cputimer_mode & (1 << (timer_index - 1)));
-}
-
-// Update count, set irq, update expire_time
-// Convert from ptimer countdown units
-static void slavio_timer_get_out(CPUTimerState *t)
-{
- uint64_t count, limit;
-
- if (t->limit == 0) { /* free-run system or processor counter */
- limit = TIMER_MAX_COUNT32;
- } else {
- limit = t->limit;
- }
- count = limit - PERIODS_TO_LIMIT(ptimer_get_count(t->timer));
-
- trace_slavio_timer_get_out(t->limit, t->counthigh, t->count);
- t->count = count & TIMER_COUNT_MASK32;
- t->counthigh = count >> 32;
-}
-
-// timer callback
-static void slavio_timer_irq(void *opaque)
-{
- TimerContext *tc = opaque;
- SLAVIO_TIMERState *s = tc->s;
- CPUTimerState *t = &s->cputimer[tc->timer_index];
-
- slavio_timer_get_out(t);
- trace_slavio_timer_irq(t->counthigh, t->count);
- /* if limit is 0 (free-run), there will be no match */
- if (t->limit != 0) {
- t->reached = TIMER_REACHED;
- }
- /* there is no interrupt if user timer or free-run */
- if (!slavio_timer_is_user(tc) && t->limit != 0) {
- qemu_irq_raise(t->irq);
- }
-}
-
-static uint64_t slavio_timer_mem_readl(void *opaque, hwaddr addr,
- unsigned size)
-{
- TimerContext *tc = opaque;
- SLAVIO_TIMERState *s = tc->s;
- uint32_t saddr, ret;
- unsigned int timer_index = tc->timer_index;
- CPUTimerState *t = &s->cputimer[timer_index];
-
- saddr = addr >> 2;
- switch (saddr) {
- case TIMER_LIMIT:
- // read limit (system counter mode) or read most signifying
- // part of counter (user mode)
- if (slavio_timer_is_user(tc)) {
- // read user timer MSW
- slavio_timer_get_out(t);
- ret = t->counthigh | t->reached;
- } else {
- // read limit
- // clear irq
- qemu_irq_lower(t->irq);
- t->reached = 0;
- ret = t->limit & TIMER_LIMIT_MASK32;
- }
- break;
- case TIMER_COUNTER:
- // read counter and reached bit (system mode) or read lsbits
- // of counter (user mode)
- slavio_timer_get_out(t);
- if (slavio_timer_is_user(tc)) { // read user timer LSW
- ret = t->count & TIMER_MAX_COUNT64;
- } else { // read limit
- ret = (t->count & TIMER_MAX_COUNT32) |
- t->reached;
- }
- break;
- case TIMER_STATUS:
- // only available in processor counter/timer
- // read start/stop status
- if (timer_index > 0) {
- ret = t->run;
- } else {
- ret = 0;
- }
- break;
- case TIMER_MODE:
- // only available in system counter
- // read user/system mode
- ret = s->cputimer_mode;
- break;
- default:
- trace_slavio_timer_mem_readl_invalid(addr);
- ret = 0;
- break;
- }
- trace_slavio_timer_mem_readl(addr, ret);
- return ret;
-}
-
-static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- TimerContext *tc = opaque;
- SLAVIO_TIMERState *s = tc->s;
- uint32_t saddr;
- unsigned int timer_index = tc->timer_index;
- CPUTimerState *t = &s->cputimer[timer_index];
-
- trace_slavio_timer_mem_writel(addr, val);
- saddr = addr >> 2;
- switch (saddr) {
- case TIMER_LIMIT:
- if (slavio_timer_is_user(tc)) {
- uint64_t count;
-
- // set user counter MSW, reset counter
- t->limit = TIMER_MAX_COUNT64;
- t->counthigh = val & (TIMER_MAX_COUNT64 >> 32);
- t->reached = 0;
- count = ((uint64_t)t->counthigh << 32) | t->count;
- trace_slavio_timer_mem_writel_limit(timer_index, count);
- ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count));
- } else {
- // set limit, reset counter
- qemu_irq_lower(t->irq);
- t->limit = val & TIMER_MAX_COUNT32;
- if (t->timer) {
- if (t->limit == 0) { /* free-run */
- ptimer_set_limit(t->timer,
- LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
- } else {
- ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 1);
- }
- }
- }
- break;
- case TIMER_COUNTER:
- if (slavio_timer_is_user(tc)) {
- uint64_t count;
-
- // set user counter LSW, reset counter
- t->limit = TIMER_MAX_COUNT64;
- t->count = val & TIMER_MAX_COUNT64;
- t->reached = 0;
- count = ((uint64_t)t->counthigh) << 32 | t->count;
- trace_slavio_timer_mem_writel_limit(timer_index, count);
- ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count));
- } else {
- trace_slavio_timer_mem_writel_counter_invalid();
- }
- break;
- case TIMER_COUNTER_NORST:
- // set limit without resetting counter
- t->limit = val & TIMER_MAX_COUNT32;
- if (t->limit == 0) { /* free-run */
- ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 0);
- } else {
- ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 0);
- }
- break;
- case TIMER_STATUS:
- if (slavio_timer_is_user(tc)) {
- // start/stop user counter
- if (val & 1) {
- trace_slavio_timer_mem_writel_status_start(timer_index);
- ptimer_run(t->timer, 0);
- } else {
- trace_slavio_timer_mem_writel_status_stop(timer_index);
- ptimer_stop(t->timer);
- }
- }
- t->run = val & 1;
- break;
- case TIMER_MODE:
- if (timer_index == 0) {
- unsigned int i;
-
- for (i = 0; i < s->num_cpus; i++) {
- unsigned int processor = 1 << i;
- CPUTimerState *curr_timer = &s->cputimer[i + 1];
-
- // check for a change in timer mode for this processor
- if ((val & processor) != (s->cputimer_mode & processor)) {
- if (val & processor) { // counter -> user timer
- qemu_irq_lower(curr_timer->irq);
- // counters are always running
- if (!curr_timer->run) {
- ptimer_stop(curr_timer->timer);
- }
- // user timer limit is always the same
- curr_timer->limit = TIMER_MAX_COUNT64;
- ptimer_set_limit(curr_timer->timer,
- LIMIT_TO_PERIODS(curr_timer->limit),
- 1);
- // set this processors user timer bit in config
- // register
- s->cputimer_mode |= processor;
- trace_slavio_timer_mem_writel_mode_user(timer_index);
- } else { // user timer -> counter
- // start the counter
- ptimer_run(curr_timer->timer, 0);
- // clear this processors user timer bit in config
- // register
- s->cputimer_mode &= ~processor;
- trace_slavio_timer_mem_writel_mode_counter(timer_index);
- }
- }
- }
- } else {
- trace_slavio_timer_mem_writel_mode_invalid();
- }
- break;
- default:
- trace_slavio_timer_mem_writel_invalid(addr);
- break;
- }
-}
-
-static const MemoryRegionOps slavio_timer_mem_ops = {
- .read = slavio_timer_mem_readl,
- .write = slavio_timer_mem_writel,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static const VMStateDescription vmstate_timer = {
- .name ="timer",
- .version_id = 3,
- .minimum_version_id = 3,
- .fields = (VMStateField[]) {
- VMSTATE_UINT64(limit, CPUTimerState),
- VMSTATE_UINT32(count, CPUTimerState),
- VMSTATE_UINT32(counthigh, CPUTimerState),
- VMSTATE_UINT32(reached, CPUTimerState),
- VMSTATE_UINT32(run , CPUTimerState),
- VMSTATE_PTIMER(timer, CPUTimerState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_slavio_timer = {
- .name ="slavio_timer",
- .version_id = 3,
- .minimum_version_id = 3,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT_ARRAY(cputimer, SLAVIO_TIMERState, MAX_CPUS + 1, 3,
- vmstate_timer, CPUTimerState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void slavio_timer_reset(DeviceState *d)
-{
- SLAVIO_TIMERState *s = SLAVIO_TIMER(d);
- unsigned int i;
- CPUTimerState *curr_timer;
-
- for (i = 0; i <= MAX_CPUS; i++) {
- curr_timer = &s->cputimer[i];
- curr_timer->limit = 0;
- curr_timer->count = 0;
- curr_timer->reached = 0;
- if (i <= s->num_cpus) {
- ptimer_set_limit(curr_timer->timer,
- LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
- ptimer_run(curr_timer->timer, 0);
- curr_timer->run = 1;
- }
- }
- s->cputimer_mode = 0;
-}
-
-static int slavio_timer_init1(SysBusDevice *dev)
-{
- SLAVIO_TIMERState *s = SLAVIO_TIMER(dev);
- QEMUBH *bh;
- unsigned int i;
- TimerContext *tc;
-
- for (i = 0; i <= MAX_CPUS; i++) {
- uint64_t size;
- char timer_name[20];
-
- tc = g_malloc0(sizeof(TimerContext));
- tc->s = s;
- tc->timer_index = i;
-
- bh = qemu_bh_new(slavio_timer_irq, tc);
- s->cputimer[i].timer = ptimer_init(bh);
- ptimer_set_period(s->cputimer[i].timer, TIMER_PERIOD);
-
- size = i == 0 ? SYS_TIMER_SIZE : CPU_TIMER_SIZE;
- snprintf(timer_name, sizeof(timer_name), "timer-%i", i);
- memory_region_init_io(&tc->iomem, OBJECT(s), &slavio_timer_mem_ops, tc,
- timer_name, size);
- sysbus_init_mmio(dev, &tc->iomem);
-
- sysbus_init_irq(dev, &s->cputimer[i].irq);
- }
-
- return 0;
-}
-
-static Property slavio_timer_properties[] = {
- DEFINE_PROP_UINT32("num_cpus", SLAVIO_TIMERState, num_cpus, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void slavio_timer_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = slavio_timer_init1;
- dc->reset = slavio_timer_reset;
- dc->vmsd = &vmstate_slavio_timer;
- dc->props = slavio_timer_properties;
-}
-
-static const TypeInfo slavio_timer_info = {
- .name = TYPE_SLAVIO_TIMER,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(SLAVIO_TIMERState),
- .class_init = slavio_timer_class_init,
-};
-
-static void slavio_timer_register_types(void)
-{
- type_register_static(&slavio_timer_info);
-}
-
-type_init(slavio_timer_register_types)
diff --git a/qemu/hw/timer/stm32f2xx_timer.c b/qemu/hw/timer/stm32f2xx_timer.c
deleted file mode 100644
index 55dacbbe3..000000000
--- a/qemu/hw/timer/stm32f2xx_timer.c
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * STM32F2XX Timer
- *
- * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/timer/stm32f2xx_timer.h"
-
-#ifndef STM_TIMER_ERR_DEBUG
-#define STM_TIMER_ERR_DEBUG 0
-#endif
-
-#define DB_PRINT_L(lvl, fmt, args...) do { \
- if (STM_TIMER_ERR_DEBUG >= lvl) { \
- qemu_log("%s: " fmt, __func__, ## args); \
- } \
-} while (0);
-
-#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args)
-
-static void stm32f2xx_timer_set_alarm(STM32F2XXTimerState *s, int64_t now);
-
-static void stm32f2xx_timer_interrupt(void *opaque)
-{
- STM32F2XXTimerState *s = opaque;
-
- DB_PRINT("Interrupt\n");
-
- if (s->tim_dier & TIM_DIER_UIE && s->tim_cr1 & TIM_CR1_CEN) {
- s->tim_sr |= 1;
- qemu_irq_pulse(s->irq);
- stm32f2xx_timer_set_alarm(s, s->hit_time);
- }
-}
-
-static inline int64_t stm32f2xx_ns_to_ticks(STM32F2XXTimerState *s, int64_t t)
-{
- return muldiv64(t, s->freq_hz, 1000000000ULL) / (s->tim_psc + 1);
-}
-
-static void stm32f2xx_timer_set_alarm(STM32F2XXTimerState *s, int64_t now)
-{
- uint64_t ticks;
- int64_t now_ticks;
-
- if (s->tim_arr == 0) {
- return;
- }
-
- DB_PRINT("Alarm set at: 0x%x\n", s->tim_cr1);
-
- now_ticks = stm32f2xx_ns_to_ticks(s, now);
- ticks = s->tim_arr - (now_ticks - s->tick_offset);
-
- DB_PRINT("Alarm set in %d ticks\n", (int) ticks);
-
- s->hit_time = muldiv64((ticks + (uint64_t) now_ticks) * (s->tim_psc + 1),
- 1000000000ULL, s->freq_hz);
-
- timer_mod(s->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->hit_time);
- DB_PRINT("Wait Time: %" PRId64 " ticks\n", s->hit_time);
-}
-
-static void stm32f2xx_timer_reset(DeviceState *dev)
-{
- STM32F2XXTimerState *s = STM32F2XXTIMER(dev);
- int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-
- s->tim_cr1 = 0;
- s->tim_cr2 = 0;
- s->tim_smcr = 0;
- s->tim_dier = 0;
- s->tim_sr = 0;
- s->tim_egr = 0;
- s->tim_ccmr1 = 0;
- s->tim_ccmr2 = 0;
- s->tim_ccer = 0;
- s->tim_psc = 0;
- s->tim_arr = 0;
- s->tim_ccr1 = 0;
- s->tim_ccr2 = 0;
- s->tim_ccr3 = 0;
- s->tim_ccr4 = 0;
- s->tim_dcr = 0;
- s->tim_dmar = 0;
- s->tim_or = 0;
-
- s->tick_offset = stm32f2xx_ns_to_ticks(s, now);
-}
-
-static uint64_t stm32f2xx_timer_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- STM32F2XXTimerState *s = opaque;
-
- DB_PRINT("Read 0x%"HWADDR_PRIx"\n", offset);
-
- switch (offset) {
- case TIM_CR1:
- return s->tim_cr1;
- case TIM_CR2:
- return s->tim_cr2;
- case TIM_SMCR:
- return s->tim_smcr;
- case TIM_DIER:
- return s->tim_dier;
- case TIM_SR:
- return s->tim_sr;
- case TIM_EGR:
- return s->tim_egr;
- case TIM_CCMR1:
- return s->tim_ccmr1;
- case TIM_CCMR2:
- return s->tim_ccmr2;
- case TIM_CCER:
- return s->tim_ccer;
- case TIM_CNT:
- return stm32f2xx_ns_to_ticks(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)) -
- s->tick_offset;
- case TIM_PSC:
- return s->tim_psc;
- case TIM_ARR:
- return s->tim_arr;
- case TIM_CCR1:
- return s->tim_ccr1;
- case TIM_CCR2:
- return s->tim_ccr2;
- case TIM_CCR3:
- return s->tim_ccr3;
- case TIM_CCR4:
- return s->tim_ccr4;
- case TIM_DCR:
- return s->tim_dcr;
- case TIM_DMAR:
- return s->tim_dmar;
- case TIM_OR:
- return s->tim_or;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, offset);
- }
-
- return 0;
-}
-
-static void stm32f2xx_timer_write(void *opaque, hwaddr offset,
- uint64_t val64, unsigned size)
-{
- STM32F2XXTimerState *s = opaque;
- uint32_t value = val64;
- int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- uint32_t timer_val = 0;
-
- DB_PRINT("Write 0x%x, 0x%"HWADDR_PRIx"\n", value, offset);
-
- switch (offset) {
- case TIM_CR1:
- s->tim_cr1 = value;
- return;
- case TIM_CR2:
- s->tim_cr2 = value;
- return;
- case TIM_SMCR:
- s->tim_smcr = value;
- return;
- case TIM_DIER:
- s->tim_dier = value;
- return;
- case TIM_SR:
- /* This is set by hardware and cleared by software */
- s->tim_sr &= value;
- return;
- case TIM_EGR:
- s->tim_egr = value;
- if (s->tim_egr & TIM_EGR_UG) {
- timer_val = 0;
- break;
- }
- return;
- case TIM_CCMR1:
- s->tim_ccmr1 = value;
- return;
- case TIM_CCMR2:
- s->tim_ccmr2 = value;
- return;
- case TIM_CCER:
- s->tim_ccer = value;
- return;
- case TIM_PSC:
- timer_val = stm32f2xx_ns_to_ticks(s, now) - s->tick_offset;
- s->tim_psc = value;
- value = timer_val;
- break;
- case TIM_CNT:
- timer_val = value;
- break;
- case TIM_ARR:
- s->tim_arr = value;
- stm32f2xx_timer_set_alarm(s, now);
- return;
- case TIM_CCR1:
- s->tim_ccr1 = value;
- return;
- case TIM_CCR2:
- s->tim_ccr2 = value;
- return;
- case TIM_CCR3:
- s->tim_ccr3 = value;
- return;
- case TIM_CCR4:
- s->tim_ccr4 = value;
- return;
- case TIM_DCR:
- s->tim_dcr = value;
- return;
- case TIM_DMAR:
- s->tim_dmar = value;
- return;
- case TIM_OR:
- s->tim_or = value;
- return;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, offset);
- return;
- }
-
- /* This means that a register write has affected the timer in a way that
- * requires a refresh of both tick_offset and the alarm.
- */
- s->tick_offset = stm32f2xx_ns_to_ticks(s, now) - timer_val;
- stm32f2xx_timer_set_alarm(s, now);
-}
-
-static const MemoryRegionOps stm32f2xx_timer_ops = {
- .read = stm32f2xx_timer_read,
- .write = stm32f2xx_timer_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_stm32f2xx_timer = {
- .name = TYPE_STM32F2XX_TIMER,
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_INT64(tick_offset, STM32F2XXTimerState),
- VMSTATE_UINT32(tim_cr1, STM32F2XXTimerState),
- VMSTATE_UINT32(tim_cr2, STM32F2XXTimerState),
- VMSTATE_UINT32(tim_smcr, STM32F2XXTimerState),
- VMSTATE_UINT32(tim_dier, STM32F2XXTimerState),
- VMSTATE_UINT32(tim_sr, STM32F2XXTimerState),
- VMSTATE_UINT32(tim_egr, STM32F2XXTimerState),
- VMSTATE_UINT32(tim_ccmr1, STM32F2XXTimerState),
- VMSTATE_UINT32(tim_ccmr2, STM32F2XXTimerState),
- VMSTATE_UINT32(tim_ccer, STM32F2XXTimerState),
- VMSTATE_UINT32(tim_psc, STM32F2XXTimerState),
- VMSTATE_UINT32(tim_arr, STM32F2XXTimerState),
- VMSTATE_UINT32(tim_ccr1, STM32F2XXTimerState),
- VMSTATE_UINT32(tim_ccr2, STM32F2XXTimerState),
- VMSTATE_UINT32(tim_ccr3, STM32F2XXTimerState),
- VMSTATE_UINT32(tim_ccr4, STM32F2XXTimerState),
- VMSTATE_UINT32(tim_dcr, STM32F2XXTimerState),
- VMSTATE_UINT32(tim_dmar, STM32F2XXTimerState),
- VMSTATE_UINT32(tim_or, STM32F2XXTimerState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property stm32f2xx_timer_properties[] = {
- DEFINE_PROP_UINT64("clock-frequency", struct STM32F2XXTimerState,
- freq_hz, 1000000000),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void stm32f2xx_timer_init(Object *obj)
-{
- STM32F2XXTimerState *s = STM32F2XXTIMER(obj);
-
- sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
-
- memory_region_init_io(&s->iomem, obj, &stm32f2xx_timer_ops, s,
- "stm32f2xx_timer", 0x4000);
- sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
-
- s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, stm32f2xx_timer_interrupt, s);
-}
-
-static void stm32f2xx_timer_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->reset = stm32f2xx_timer_reset;
- dc->props = stm32f2xx_timer_properties;
- dc->vmsd = &vmstate_stm32f2xx_timer;
-}
-
-static const TypeInfo stm32f2xx_timer_info = {
- .name = TYPE_STM32F2XX_TIMER,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(STM32F2XXTimerState),
- .instance_init = stm32f2xx_timer_init,
- .class_init = stm32f2xx_timer_class_init,
-};
-
-static void stm32f2xx_timer_register_types(void)
-{
- type_register_static(&stm32f2xx_timer_info);
-}
-
-type_init(stm32f2xx_timer_register_types)
diff --git a/qemu/hw/timer/twl92230.c b/qemu/hw/timer/twl92230.c
deleted file mode 100644
index 7ba4e9a7c..000000000
--- a/qemu/hw/timer/twl92230.c
+++ /dev/null
@@ -1,889 +0,0 @@
-/*
- * TI TWL92230C energy-management companion device for the OMAP24xx.
- * Aka. Menelaus (N4200 MENELAUS1_V2.2)
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "qemu/timer.h"
-#include "hw/i2c/i2c.h"
-#include "sysemu/sysemu.h"
-#include "ui/console.h"
-#include "qemu/bcd.h"
-
-#define VERBOSE 1
-
-#define TYPE_TWL92230 "twl92230"
-#define TWL92230(obj) OBJECT_CHECK(MenelausState, (obj), TYPE_TWL92230)
-
-typedef struct MenelausState {
- I2CSlave parent_obj;
-
- int firstbyte;
- uint8_t reg;
-
- uint8_t vcore[5];
- uint8_t dcdc[3];
- uint8_t ldo[8];
- uint8_t sleep[2];
- uint8_t osc;
- uint8_t detect;
- uint16_t mask;
- uint16_t status;
- uint8_t dir;
- uint8_t inputs;
- uint8_t outputs;
- uint8_t bbsms;
- uint8_t pull[4];
- uint8_t mmc_ctrl[3];
- uint8_t mmc_debounce;
- struct {
- uint8_t ctrl;
- uint16_t comp;
- QEMUTimer *hz_tm;
- int64_t next;
- struct tm tm;
- struct tm new;
- struct tm alm;
- int sec_offset;
- int alm_sec;
- int next_comp;
- } rtc;
- uint16_t rtc_next_vmstate;
- qemu_irq out[4];
- uint8_t pwrbtn_state;
-} MenelausState;
-
-static inline void menelaus_update(MenelausState *s)
-{
- qemu_set_irq(s->out[3], s->status & ~s->mask);
-}
-
-static inline void menelaus_rtc_start(MenelausState *s)
-{
- s->rtc.next += qemu_clock_get_ms(rtc_clock);
- timer_mod(s->rtc.hz_tm, s->rtc.next);
-}
-
-static inline void menelaus_rtc_stop(MenelausState *s)
-{
- timer_del(s->rtc.hz_tm);
- s->rtc.next -= qemu_clock_get_ms(rtc_clock);
- if (s->rtc.next < 1)
- s->rtc.next = 1;
-}
-
-static void menelaus_rtc_update(MenelausState *s)
-{
- qemu_get_timedate(&s->rtc.tm, s->rtc.sec_offset);
-}
-
-static void menelaus_alm_update(MenelausState *s)
-{
- if ((s->rtc.ctrl & 3) == 3)
- s->rtc.alm_sec = qemu_timedate_diff(&s->rtc.alm) - s->rtc.sec_offset;
-}
-
-static void menelaus_rtc_hz(void *opaque)
-{
- MenelausState *s = (MenelausState *) opaque;
-
- s->rtc.next_comp --;
- s->rtc.alm_sec --;
- s->rtc.next += 1000;
- timer_mod(s->rtc.hz_tm, s->rtc.next);
- if ((s->rtc.ctrl >> 3) & 3) { /* EVERY */
- menelaus_rtc_update(s);
- if (((s->rtc.ctrl >> 3) & 3) == 1 && !s->rtc.tm.tm_sec)
- s->status |= 1 << 8; /* RTCTMR */
- else if (((s->rtc.ctrl >> 3) & 3) == 2 && !s->rtc.tm.tm_min)
- s->status |= 1 << 8; /* RTCTMR */
- else if (!s->rtc.tm.tm_hour)
- s->status |= 1 << 8; /* RTCTMR */
- } else
- s->status |= 1 << 8; /* RTCTMR */
- if ((s->rtc.ctrl >> 1) & 1) { /* RTC_AL_EN */
- if (s->rtc.alm_sec == 0)
- s->status |= 1 << 9; /* RTCALM */
- /* TODO: wake-up */
- }
- if (s->rtc.next_comp <= 0) {
- s->rtc.next -= muldiv64((int16_t) s->rtc.comp, 1000, 0x8000);
- s->rtc.next_comp = 3600;
- }
- menelaus_update(s);
-}
-
-static void menelaus_reset(I2CSlave *i2c)
-{
- MenelausState *s = TWL92230(i2c);
-
- s->reg = 0x00;
-
- s->vcore[0] = 0x0c; /* XXX: X-loader needs 0x8c? check! */
- s->vcore[1] = 0x05;
- s->vcore[2] = 0x02;
- s->vcore[3] = 0x0c;
- s->vcore[4] = 0x03;
- s->dcdc[0] = 0x33; /* Depends on wiring */
- s->dcdc[1] = 0x03;
- s->dcdc[2] = 0x00;
- s->ldo[0] = 0x95;
- s->ldo[1] = 0x7e;
- s->ldo[2] = 0x00;
- s->ldo[3] = 0x00; /* Depends on wiring */
- s->ldo[4] = 0x03; /* Depends on wiring */
- s->ldo[5] = 0x00;
- s->ldo[6] = 0x00;
- s->ldo[7] = 0x00;
- s->sleep[0] = 0x00;
- s->sleep[1] = 0x00;
- s->osc = 0x01;
- s->detect = 0x09;
- s->mask = 0x0fff;
- s->status = 0;
- s->dir = 0x07;
- s->outputs = 0x00;
- s->bbsms = 0x00;
- s->pull[0] = 0x00;
- s->pull[1] = 0x00;
- s->pull[2] = 0x00;
- s->pull[3] = 0x00;
- s->mmc_ctrl[0] = 0x03;
- s->mmc_ctrl[1] = 0xc0;
- s->mmc_ctrl[2] = 0x00;
- s->mmc_debounce = 0x05;
-
- if (s->rtc.ctrl & 1)
- menelaus_rtc_stop(s);
- s->rtc.ctrl = 0x00;
- s->rtc.comp = 0x0000;
- s->rtc.next = 1000;
- s->rtc.sec_offset = 0;
- s->rtc.next_comp = 1800;
- s->rtc.alm_sec = 1800;
- s->rtc.alm.tm_sec = 0x00;
- s->rtc.alm.tm_min = 0x00;
- s->rtc.alm.tm_hour = 0x00;
- s->rtc.alm.tm_mday = 0x01;
- s->rtc.alm.tm_mon = 0x00;
- s->rtc.alm.tm_year = 2004;
- menelaus_update(s);
-}
-
-static void menelaus_gpio_set(void *opaque, int line, int level)
-{
- MenelausState *s = (MenelausState *) opaque;
-
- if (line < 3) {
- /* No interrupt generated */
- s->inputs &= ~(1 << line);
- s->inputs |= level << line;
- return;
- }
-
- if (!s->pwrbtn_state && level) {
- s->status |= 1 << 11; /* PSHBTN */
- menelaus_update(s);
- }
- s->pwrbtn_state = level;
-}
-
-#define MENELAUS_REV 0x01
-#define MENELAUS_VCORE_CTRL1 0x02
-#define MENELAUS_VCORE_CTRL2 0x03
-#define MENELAUS_VCORE_CTRL3 0x04
-#define MENELAUS_VCORE_CTRL4 0x05
-#define MENELAUS_VCORE_CTRL5 0x06
-#define MENELAUS_DCDC_CTRL1 0x07
-#define MENELAUS_DCDC_CTRL2 0x08
-#define MENELAUS_DCDC_CTRL3 0x09
-#define MENELAUS_LDO_CTRL1 0x0a
-#define MENELAUS_LDO_CTRL2 0x0b
-#define MENELAUS_LDO_CTRL3 0x0c
-#define MENELAUS_LDO_CTRL4 0x0d
-#define MENELAUS_LDO_CTRL5 0x0e
-#define MENELAUS_LDO_CTRL6 0x0f
-#define MENELAUS_LDO_CTRL7 0x10
-#define MENELAUS_LDO_CTRL8 0x11
-#define MENELAUS_SLEEP_CTRL1 0x12
-#define MENELAUS_SLEEP_CTRL2 0x13
-#define MENELAUS_DEVICE_OFF 0x14
-#define MENELAUS_OSC_CTRL 0x15
-#define MENELAUS_DETECT_CTRL 0x16
-#define MENELAUS_INT_MASK1 0x17
-#define MENELAUS_INT_MASK2 0x18
-#define MENELAUS_INT_STATUS1 0x19
-#define MENELAUS_INT_STATUS2 0x1a
-#define MENELAUS_INT_ACK1 0x1b
-#define MENELAUS_INT_ACK2 0x1c
-#define MENELAUS_GPIO_CTRL 0x1d
-#define MENELAUS_GPIO_IN 0x1e
-#define MENELAUS_GPIO_OUT 0x1f
-#define MENELAUS_BBSMS 0x20
-#define MENELAUS_RTC_CTRL 0x21
-#define MENELAUS_RTC_UPDATE 0x22
-#define MENELAUS_RTC_SEC 0x23
-#define MENELAUS_RTC_MIN 0x24
-#define MENELAUS_RTC_HR 0x25
-#define MENELAUS_RTC_DAY 0x26
-#define MENELAUS_RTC_MON 0x27
-#define MENELAUS_RTC_YR 0x28
-#define MENELAUS_RTC_WKDAY 0x29
-#define MENELAUS_RTC_AL_SEC 0x2a
-#define MENELAUS_RTC_AL_MIN 0x2b
-#define MENELAUS_RTC_AL_HR 0x2c
-#define MENELAUS_RTC_AL_DAY 0x2d
-#define MENELAUS_RTC_AL_MON 0x2e
-#define MENELAUS_RTC_AL_YR 0x2f
-#define MENELAUS_RTC_COMP_MSB 0x30
-#define MENELAUS_RTC_COMP_LSB 0x31
-#define MENELAUS_S1_PULL_EN 0x32
-#define MENELAUS_S1_PULL_DIR 0x33
-#define MENELAUS_S2_PULL_EN 0x34
-#define MENELAUS_S2_PULL_DIR 0x35
-#define MENELAUS_MCT_CTRL1 0x36
-#define MENELAUS_MCT_CTRL2 0x37
-#define MENELAUS_MCT_CTRL3 0x38
-#define MENELAUS_MCT_PIN_ST 0x39
-#define MENELAUS_DEBOUNCE1 0x3a
-
-static uint8_t menelaus_read(void *opaque, uint8_t addr)
-{
- MenelausState *s = (MenelausState *) opaque;
- int reg = 0;
-
- switch (addr) {
- case MENELAUS_REV:
- return 0x22;
-
- case MENELAUS_VCORE_CTRL5: reg ++;
- case MENELAUS_VCORE_CTRL4: reg ++;
- case MENELAUS_VCORE_CTRL3: reg ++;
- case MENELAUS_VCORE_CTRL2: reg ++;
- case MENELAUS_VCORE_CTRL1:
- return s->vcore[reg];
-
- case MENELAUS_DCDC_CTRL3: reg ++;
- case MENELAUS_DCDC_CTRL2: reg ++;
- case MENELAUS_DCDC_CTRL1:
- return s->dcdc[reg];
-
- case MENELAUS_LDO_CTRL8: reg ++;
- case MENELAUS_LDO_CTRL7: reg ++;
- case MENELAUS_LDO_CTRL6: reg ++;
- case MENELAUS_LDO_CTRL5: reg ++;
- case MENELAUS_LDO_CTRL4: reg ++;
- case MENELAUS_LDO_CTRL3: reg ++;
- case MENELAUS_LDO_CTRL2: reg ++;
- case MENELAUS_LDO_CTRL1:
- return s->ldo[reg];
-
- case MENELAUS_SLEEP_CTRL2: reg ++;
- case MENELAUS_SLEEP_CTRL1:
- return s->sleep[reg];
-
- case MENELAUS_DEVICE_OFF:
- return 0;
-
- case MENELAUS_OSC_CTRL:
- return s->osc | (1 << 7); /* CLK32K_GOOD */
-
- case MENELAUS_DETECT_CTRL:
- return s->detect;
-
- case MENELAUS_INT_MASK1:
- return (s->mask >> 0) & 0xff;
- case MENELAUS_INT_MASK2:
- return (s->mask >> 8) & 0xff;
-
- case MENELAUS_INT_STATUS1:
- return (s->status >> 0) & 0xff;
- case MENELAUS_INT_STATUS2:
- return (s->status >> 8) & 0xff;
-
- case MENELAUS_INT_ACK1:
- case MENELAUS_INT_ACK2:
- return 0;
-
- case MENELAUS_GPIO_CTRL:
- return s->dir;
- case MENELAUS_GPIO_IN:
- return s->inputs | (~s->dir & s->outputs);
- case MENELAUS_GPIO_OUT:
- return s->outputs;
-
- case MENELAUS_BBSMS:
- return s->bbsms;
-
- case MENELAUS_RTC_CTRL:
- return s->rtc.ctrl;
- case MENELAUS_RTC_UPDATE:
- return 0x00;
- case MENELAUS_RTC_SEC:
- menelaus_rtc_update(s);
- return to_bcd(s->rtc.tm.tm_sec);
- case MENELAUS_RTC_MIN:
- menelaus_rtc_update(s);
- return to_bcd(s->rtc.tm.tm_min);
- case MENELAUS_RTC_HR:
- menelaus_rtc_update(s);
- if ((s->rtc.ctrl >> 2) & 1) /* MODE12_n24 */
- return to_bcd((s->rtc.tm.tm_hour % 12) + 1) |
- (!!(s->rtc.tm.tm_hour >= 12) << 7); /* PM_nAM */
- else
- return to_bcd(s->rtc.tm.tm_hour);
- case MENELAUS_RTC_DAY:
- menelaus_rtc_update(s);
- return to_bcd(s->rtc.tm.tm_mday);
- case MENELAUS_RTC_MON:
- menelaus_rtc_update(s);
- return to_bcd(s->rtc.tm.tm_mon + 1);
- case MENELAUS_RTC_YR:
- menelaus_rtc_update(s);
- return to_bcd(s->rtc.tm.tm_year - 2000);
- case MENELAUS_RTC_WKDAY:
- menelaus_rtc_update(s);
- return to_bcd(s->rtc.tm.tm_wday);
- case MENELAUS_RTC_AL_SEC:
- return to_bcd(s->rtc.alm.tm_sec);
- case MENELAUS_RTC_AL_MIN:
- return to_bcd(s->rtc.alm.tm_min);
- case MENELAUS_RTC_AL_HR:
- if ((s->rtc.ctrl >> 2) & 1) /* MODE12_n24 */
- return to_bcd((s->rtc.alm.tm_hour % 12) + 1) |
- (!!(s->rtc.alm.tm_hour >= 12) << 7);/* AL_PM_nAM */
- else
- return to_bcd(s->rtc.alm.tm_hour);
- case MENELAUS_RTC_AL_DAY:
- return to_bcd(s->rtc.alm.tm_mday);
- case MENELAUS_RTC_AL_MON:
- return to_bcd(s->rtc.alm.tm_mon + 1);
- case MENELAUS_RTC_AL_YR:
- return to_bcd(s->rtc.alm.tm_year - 2000);
- case MENELAUS_RTC_COMP_MSB:
- return (s->rtc.comp >> 8) & 0xff;
- case MENELAUS_RTC_COMP_LSB:
- return (s->rtc.comp >> 0) & 0xff;
-
- case MENELAUS_S1_PULL_EN:
- return s->pull[0];
- case MENELAUS_S1_PULL_DIR:
- return s->pull[1];
- case MENELAUS_S2_PULL_EN:
- return s->pull[2];
- case MENELAUS_S2_PULL_DIR:
- return s->pull[3];
-
- case MENELAUS_MCT_CTRL3: reg ++;
- case MENELAUS_MCT_CTRL2: reg ++;
- case MENELAUS_MCT_CTRL1:
- return s->mmc_ctrl[reg];
- case MENELAUS_MCT_PIN_ST:
- /* TODO: return the real Card Detect */
- return 0;
- case MENELAUS_DEBOUNCE1:
- return s->mmc_debounce;
-
- default:
-#ifdef VERBOSE
- printf("%s: unknown register %02x\n", __FUNCTION__, addr);
-#endif
- break;
- }
- return 0;
-}
-
-static void menelaus_write(void *opaque, uint8_t addr, uint8_t value)
-{
- MenelausState *s = (MenelausState *) opaque;
- int line;
- int reg = 0;
- struct tm tm;
-
- switch (addr) {
- case MENELAUS_VCORE_CTRL1:
- s->vcore[0] = (value & 0xe) | MIN(value & 0x1f, 0x12);
- break;
- case MENELAUS_VCORE_CTRL2:
- s->vcore[1] = value;
- break;
- case MENELAUS_VCORE_CTRL3:
- s->vcore[2] = MIN(value & 0x1f, 0x12);
- break;
- case MENELAUS_VCORE_CTRL4:
- s->vcore[3] = MIN(value & 0x1f, 0x12);
- break;
- case MENELAUS_VCORE_CTRL5:
- s->vcore[4] = value & 3;
- /* XXX
- * auto set to 3 on M_Active, nRESWARM
- * auto set to 0 on M_WaitOn, M_Backup
- */
- break;
-
- case MENELAUS_DCDC_CTRL1:
- s->dcdc[0] = value & 0x3f;
- break;
- case MENELAUS_DCDC_CTRL2:
- s->dcdc[1] = value & 0x07;
- /* XXX
- * auto set to 3 on M_Active, nRESWARM
- * auto set to 0 on M_WaitOn, M_Backup
- */
- break;
- case MENELAUS_DCDC_CTRL3:
- s->dcdc[2] = value & 0x07;
- break;
-
- case MENELAUS_LDO_CTRL1:
- s->ldo[0] = value;
- break;
- case MENELAUS_LDO_CTRL2:
- s->ldo[1] = value & 0x7f;
- /* XXX
- * auto set to 0x7e on M_WaitOn, M_Backup
- */
- break;
- case MENELAUS_LDO_CTRL3:
- s->ldo[2] = value & 3;
- /* XXX
- * auto set to 3 on M_Active, nRESWARM
- * auto set to 0 on M_WaitOn, M_Backup
- */
- break;
- case MENELAUS_LDO_CTRL4:
- s->ldo[3] = value & 3;
- /* XXX
- * auto set to 3 on M_Active, nRESWARM
- * auto set to 0 on M_WaitOn, M_Backup
- */
- break;
- case MENELAUS_LDO_CTRL5:
- s->ldo[4] = value & 3;
- /* XXX
- * auto set to 3 on M_Active, nRESWARM
- * auto set to 0 on M_WaitOn, M_Backup
- */
- break;
- case MENELAUS_LDO_CTRL6:
- s->ldo[5] = value & 3;
- break;
- case MENELAUS_LDO_CTRL7:
- s->ldo[6] = value & 3;
- break;
- case MENELAUS_LDO_CTRL8:
- s->ldo[7] = value & 3;
- break;
-
- case MENELAUS_SLEEP_CTRL2: reg ++;
- case MENELAUS_SLEEP_CTRL1:
- s->sleep[reg] = value;
- break;
-
- case MENELAUS_DEVICE_OFF:
- if (value & 1) {
- menelaus_reset(I2C_SLAVE(s));
- }
- break;
-
- case MENELAUS_OSC_CTRL:
- s->osc = value & 7;
- break;
-
- case MENELAUS_DETECT_CTRL:
- s->detect = value & 0x7f;
- break;
-
- case MENELAUS_INT_MASK1:
- s->mask &= 0xf00;
- s->mask |= value << 0;
- menelaus_update(s);
- break;
- case MENELAUS_INT_MASK2:
- s->mask &= 0x0ff;
- s->mask |= value << 8;
- menelaus_update(s);
- break;
-
- case MENELAUS_INT_ACK1:
- s->status &= ~(((uint16_t) value) << 0);
- menelaus_update(s);
- break;
- case MENELAUS_INT_ACK2:
- s->status &= ~(((uint16_t) value) << 8);
- menelaus_update(s);
- break;
-
- case MENELAUS_GPIO_CTRL:
- for (line = 0; line < 3; line ++) {
- if (((s->dir ^ value) >> line) & 1) {
- qemu_set_irq(s->out[line],
- ((s->outputs & ~s->dir) >> line) & 1);
- }
- }
- s->dir = value & 0x67;
- break;
- case MENELAUS_GPIO_OUT:
- for (line = 0; line < 3; line ++) {
- if ((((s->outputs ^ value) & ~s->dir) >> line) & 1) {
- qemu_set_irq(s->out[line], (s->outputs >> line) & 1);
- }
- }
- s->outputs = value & 0x07;
- break;
-
- case MENELAUS_BBSMS:
- s->bbsms = 0x0d;
- break;
-
- case MENELAUS_RTC_CTRL:
- if ((s->rtc.ctrl ^ value) & 1) { /* RTC_EN */
- if (value & 1)
- menelaus_rtc_start(s);
- else
- menelaus_rtc_stop(s);
- }
- s->rtc.ctrl = value & 0x1f;
- menelaus_alm_update(s);
- break;
- case MENELAUS_RTC_UPDATE:
- menelaus_rtc_update(s);
- memcpy(&tm, &s->rtc.tm, sizeof(tm));
- switch (value & 0xf) {
- case 0:
- break;
- case 1:
- tm.tm_sec = s->rtc.new.tm_sec;
- break;
- case 2:
- tm.tm_min = s->rtc.new.tm_min;
- break;
- case 3:
- if (s->rtc.new.tm_hour > 23)
- goto rtc_badness;
- tm.tm_hour = s->rtc.new.tm_hour;
- break;
- case 4:
- if (s->rtc.new.tm_mday < 1)
- goto rtc_badness;
- /* TODO check range */
- tm.tm_mday = s->rtc.new.tm_mday;
- break;
- case 5:
- if (s->rtc.new.tm_mon < 0 || s->rtc.new.tm_mon > 11)
- goto rtc_badness;
- tm.tm_mon = s->rtc.new.tm_mon;
- break;
- case 6:
- tm.tm_year = s->rtc.new.tm_year;
- break;
- case 7:
- /* TODO set .tm_mday instead */
- tm.tm_wday = s->rtc.new.tm_wday;
- break;
- case 8:
- if (s->rtc.new.tm_hour > 23)
- goto rtc_badness;
- if (s->rtc.new.tm_mday < 1)
- goto rtc_badness;
- if (s->rtc.new.tm_mon < 0 || s->rtc.new.tm_mon > 11)
- goto rtc_badness;
- tm.tm_sec = s->rtc.new.tm_sec;
- tm.tm_min = s->rtc.new.tm_min;
- tm.tm_hour = s->rtc.new.tm_hour;
- tm.tm_mday = s->rtc.new.tm_mday;
- tm.tm_mon = s->rtc.new.tm_mon;
- tm.tm_year = s->rtc.new.tm_year;
- break;
- rtc_badness:
- default:
- fprintf(stderr, "%s: bad RTC_UPDATE value %02x\n",
- __FUNCTION__, value);
- s->status |= 1 << 10; /* RTCERR */
- menelaus_update(s);
- }
- s->rtc.sec_offset = qemu_timedate_diff(&tm);
- break;
- case MENELAUS_RTC_SEC:
- s->rtc.tm.tm_sec = from_bcd(value & 0x7f);
- break;
- case MENELAUS_RTC_MIN:
- s->rtc.tm.tm_min = from_bcd(value & 0x7f);
- break;
- case MENELAUS_RTC_HR:
- s->rtc.tm.tm_hour = (s->rtc.ctrl & (1 << 2)) ? /* MODE12_n24 */
- MIN(from_bcd(value & 0x3f), 12) + ((value >> 7) ? 11 : -1) :
- from_bcd(value & 0x3f);
- break;
- case MENELAUS_RTC_DAY:
- s->rtc.tm.tm_mday = from_bcd(value);
- break;
- case MENELAUS_RTC_MON:
- s->rtc.tm.tm_mon = MAX(1, from_bcd(value)) - 1;
- break;
- case MENELAUS_RTC_YR:
- s->rtc.tm.tm_year = 2000 + from_bcd(value);
- break;
- case MENELAUS_RTC_WKDAY:
- s->rtc.tm.tm_mday = from_bcd(value);
- break;
- case MENELAUS_RTC_AL_SEC:
- s->rtc.alm.tm_sec = from_bcd(value & 0x7f);
- menelaus_alm_update(s);
- break;
- case MENELAUS_RTC_AL_MIN:
- s->rtc.alm.tm_min = from_bcd(value & 0x7f);
- menelaus_alm_update(s);
- break;
- case MENELAUS_RTC_AL_HR:
- s->rtc.alm.tm_hour = (s->rtc.ctrl & (1 << 2)) ? /* MODE12_n24 */
- MIN(from_bcd(value & 0x3f), 12) + ((value >> 7) ? 11 : -1) :
- from_bcd(value & 0x3f);
- menelaus_alm_update(s);
- break;
- case MENELAUS_RTC_AL_DAY:
- s->rtc.alm.tm_mday = from_bcd(value);
- menelaus_alm_update(s);
- break;
- case MENELAUS_RTC_AL_MON:
- s->rtc.alm.tm_mon = MAX(1, from_bcd(value)) - 1;
- menelaus_alm_update(s);
- break;
- case MENELAUS_RTC_AL_YR:
- s->rtc.alm.tm_year = 2000 + from_bcd(value);
- menelaus_alm_update(s);
- break;
- case MENELAUS_RTC_COMP_MSB:
- s->rtc.comp &= 0xff;
- s->rtc.comp |= value << 8;
- break;
- case MENELAUS_RTC_COMP_LSB:
- s->rtc.comp &= 0xff << 8;
- s->rtc.comp |= value;
- break;
-
- case MENELAUS_S1_PULL_EN:
- s->pull[0] = value;
- break;
- case MENELAUS_S1_PULL_DIR:
- s->pull[1] = value & 0x1f;
- break;
- case MENELAUS_S2_PULL_EN:
- s->pull[2] = value;
- break;
- case MENELAUS_S2_PULL_DIR:
- s->pull[3] = value & 0x1f;
- break;
-
- case MENELAUS_MCT_CTRL1:
- s->mmc_ctrl[0] = value & 0x7f;
- break;
- case MENELAUS_MCT_CTRL2:
- s->mmc_ctrl[1] = value;
- /* TODO update Card Detect interrupts */
- break;
- case MENELAUS_MCT_CTRL3:
- s->mmc_ctrl[2] = value & 0xf;
- break;
- case MENELAUS_DEBOUNCE1:
- s->mmc_debounce = value & 0x3f;
- break;
-
- default:
-#ifdef VERBOSE
- printf("%s: unknown register %02x\n", __FUNCTION__, addr);
-#endif
- }
-}
-
-static void menelaus_event(I2CSlave *i2c, enum i2c_event event)
-{
- MenelausState *s = TWL92230(i2c);
-
- if (event == I2C_START_SEND)
- s->firstbyte = 1;
-}
-
-static int menelaus_tx(I2CSlave *i2c, uint8_t data)
-{
- MenelausState *s = TWL92230(i2c);
-
- /* Interpret register address byte */
- if (s->firstbyte) {
- s->reg = data;
- s->firstbyte = 0;
- } else
- menelaus_write(s, s->reg ++, data);
-
- return 0;
-}
-
-static int menelaus_rx(I2CSlave *i2c)
-{
- MenelausState *s = TWL92230(i2c);
-
- return menelaus_read(s, s->reg ++);
-}
-
-/* Save restore 32 bit int as uint16_t
- This is a Big hack, but it is how the old state did it.
- Or we broke compatibility in the state, or we can't use struct tm
- */
-
-static int get_int32_as_uint16(QEMUFile *f, void *pv, size_t size)
-{
- int *v = pv;
- *v = qemu_get_be16(f);
- return 0;
-}
-
-static void put_int32_as_uint16(QEMUFile *f, void *pv, size_t size)
-{
- int *v = pv;
- qemu_put_be16(f, *v);
-}
-
-static const VMStateInfo vmstate_hack_int32_as_uint16 = {
- .name = "int32_as_uint16",
- .get = get_int32_as_uint16,
- .put = put_int32_as_uint16,
-};
-
-#define VMSTATE_UINT16_HACK(_f, _s) \
- VMSTATE_SINGLE(_f, _s, 0, vmstate_hack_int32_as_uint16, int32_t)
-
-
-static const VMStateDescription vmstate_menelaus_tm = {
- .name = "menelaus_tm",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_UINT16_HACK(tm_sec, struct tm),
- VMSTATE_UINT16_HACK(tm_min, struct tm),
- VMSTATE_UINT16_HACK(tm_hour, struct tm),
- VMSTATE_UINT16_HACK(tm_mday, struct tm),
- VMSTATE_UINT16_HACK(tm_min, struct tm),
- VMSTATE_UINT16_HACK(tm_year, struct tm),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void menelaus_pre_save(void *opaque)
-{
- MenelausState *s = opaque;
- /* Should be <= 1000 */
- s->rtc_next_vmstate = s->rtc.next - qemu_clock_get_ms(rtc_clock);
-}
-
-static int menelaus_post_load(void *opaque, int version_id)
-{
- MenelausState *s = opaque;
-
- if (s->rtc.ctrl & 1) /* RTC_EN */
- menelaus_rtc_stop(s);
-
- s->rtc.next = s->rtc_next_vmstate;
-
- menelaus_alm_update(s);
- menelaus_update(s);
- if (s->rtc.ctrl & 1) /* RTC_EN */
- menelaus_rtc_start(s);
- return 0;
-}
-
-static const VMStateDescription vmstate_menelaus = {
- .name = "menelaus",
- .version_id = 0,
- .minimum_version_id = 0,
- .pre_save = menelaus_pre_save,
- .post_load = menelaus_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_INT32(firstbyte, MenelausState),
- VMSTATE_UINT8(reg, MenelausState),
- VMSTATE_UINT8_ARRAY(vcore, MenelausState, 5),
- VMSTATE_UINT8_ARRAY(dcdc, MenelausState, 3),
- VMSTATE_UINT8_ARRAY(ldo, MenelausState, 8),
- VMSTATE_UINT8_ARRAY(sleep, MenelausState, 2),
- VMSTATE_UINT8(osc, MenelausState),
- VMSTATE_UINT8(detect, MenelausState),
- VMSTATE_UINT16(mask, MenelausState),
- VMSTATE_UINT16(status, MenelausState),
- VMSTATE_UINT8(dir, MenelausState),
- VMSTATE_UINT8(inputs, MenelausState),
- VMSTATE_UINT8(outputs, MenelausState),
- VMSTATE_UINT8(bbsms, MenelausState),
- VMSTATE_UINT8_ARRAY(pull, MenelausState, 4),
- VMSTATE_UINT8_ARRAY(mmc_ctrl, MenelausState, 3),
- VMSTATE_UINT8(mmc_debounce, MenelausState),
- VMSTATE_UINT8(rtc.ctrl, MenelausState),
- VMSTATE_UINT16(rtc.comp, MenelausState),
- VMSTATE_UINT16(rtc_next_vmstate, MenelausState),
- VMSTATE_STRUCT(rtc.new, MenelausState, 0, vmstate_menelaus_tm,
- struct tm),
- VMSTATE_STRUCT(rtc.alm, MenelausState, 0, vmstate_menelaus_tm,
- struct tm),
- VMSTATE_UINT8(pwrbtn_state, MenelausState),
- VMSTATE_I2C_SLAVE(parent_obj, MenelausState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static int twl92230_init(I2CSlave *i2c)
-{
- DeviceState *dev = DEVICE(i2c);
- MenelausState *s = TWL92230(i2c);
-
- s->rtc.hz_tm = timer_new_ms(rtc_clock, menelaus_rtc_hz, s);
- /* Three output pins plus one interrupt pin. */
- qdev_init_gpio_out(dev, s->out, 4);
-
- /* Three input pins plus one power-button pin. */
- qdev_init_gpio_in(dev, menelaus_gpio_set, 4);
-
- menelaus_reset(i2c);
-
- return 0;
-}
-
-static void twl92230_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
-
- sc->init = twl92230_init;
- sc->event = menelaus_event;
- sc->recv = menelaus_rx;
- sc->send = menelaus_tx;
- dc->vmsd = &vmstate_menelaus;
-}
-
-static const TypeInfo twl92230_info = {
- .name = TYPE_TWL92230,
- .parent = TYPE_I2C_SLAVE,
- .instance_size = sizeof(MenelausState),
- .class_init = twl92230_class_init,
-};
-
-static void twl92230_register_types(void)
-{
- type_register_static(&twl92230_info);
-}
-
-type_init(twl92230_register_types)
diff --git a/qemu/hw/timer/xilinx_timer.c b/qemu/hw/timer/xilinx_timer.c
deleted file mode 100644
index 2ea970dc9..000000000
--- a/qemu/hw/timer/xilinx_timer.c
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * QEMU model of the Xilinx timer block.
- *
- * Copyright (c) 2009 Edgar E. Iglesias.
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "hw/ptimer.h"
-#include "qemu/log.h"
-#include "qemu/main-loop.h"
-
-#define D(x)
-
-#define R_TCSR 0
-#define R_TLR 1
-#define R_TCR 2
-#define R_MAX 4
-
-#define TCSR_MDT (1<<0)
-#define TCSR_UDT (1<<1)
-#define TCSR_GENT (1<<2)
-#define TCSR_CAPT (1<<3)
-#define TCSR_ARHT (1<<4)
-#define TCSR_LOAD (1<<5)
-#define TCSR_ENIT (1<<6)
-#define TCSR_ENT (1<<7)
-#define TCSR_TINT (1<<8)
-#define TCSR_PWMA (1<<9)
-#define TCSR_ENALL (1<<10)
-
-struct xlx_timer
-{
- QEMUBH *bh;
- ptimer_state *ptimer;
- void *parent;
- int nr; /* for debug. */
-
- unsigned long timer_div;
-
- uint32_t regs[R_MAX];
-};
-
-#define TYPE_XILINX_TIMER "xlnx.xps-timer"
-#define XILINX_TIMER(obj) \
- OBJECT_CHECK(struct timerblock, (obj), TYPE_XILINX_TIMER)
-
-struct timerblock
-{
- SysBusDevice parent_obj;
-
- MemoryRegion mmio;
- qemu_irq irq;
- uint8_t one_timer_only;
- uint32_t freq_hz;
- struct xlx_timer *timers;
-};
-
-static inline unsigned int num_timers(struct timerblock *t)
-{
- return 2 - t->one_timer_only;
-}
-
-static inline unsigned int timer_from_addr(hwaddr addr)
-{
- /* Timers get a 4x32bit control reg area each. */
- return addr >> 2;
-}
-
-static void timer_update_irq(struct timerblock *t)
-{
- unsigned int i, irq = 0;
- uint32_t csr;
-
- for (i = 0; i < num_timers(t); i++) {
- csr = t->timers[i].regs[R_TCSR];
- irq |= (csr & TCSR_TINT) && (csr & TCSR_ENIT);
- }
-
- /* All timers within the same slave share a single IRQ line. */
- qemu_set_irq(t->irq, !!irq);
-}
-
-static uint64_t
-timer_read(void *opaque, hwaddr addr, unsigned int size)
-{
- struct timerblock *t = opaque;
- struct xlx_timer *xt;
- uint32_t r = 0;
- unsigned int timer;
-
- addr >>= 2;
- timer = timer_from_addr(addr);
- xt = &t->timers[timer];
- /* Further decoding to address a specific timers reg. */
- addr &= 0x3;
- switch (addr)
- {
- case R_TCR:
- r = ptimer_get_count(xt->ptimer);
- if (!(xt->regs[R_TCSR] & TCSR_UDT))
- r = ~r;
- D(qemu_log("xlx_timer t=%d read counter=%x udt=%d\n",
- timer, r, xt->regs[R_TCSR] & TCSR_UDT));
- break;
- default:
- if (addr < ARRAY_SIZE(xt->regs))
- r = xt->regs[addr];
- break;
-
- }
- D(fprintf(stderr, "%s timer=%d %x=%x\n", __func__, timer, addr * 4, r));
- return r;
-}
-
-static void timer_enable(struct xlx_timer *xt)
-{
- uint64_t count;
-
- D(fprintf(stderr, "%s timer=%d down=%d\n", __func__,
- xt->nr, xt->regs[R_TCSR] & TCSR_UDT));
-
- ptimer_stop(xt->ptimer);
-
- if (xt->regs[R_TCSR] & TCSR_UDT)
- count = xt->regs[R_TLR];
- else
- count = ~0 - xt->regs[R_TLR];
- ptimer_set_limit(xt->ptimer, count, 1);
- ptimer_run(xt->ptimer, 1);
-}
-
-static void
-timer_write(void *opaque, hwaddr addr,
- uint64_t val64, unsigned int size)
-{
- struct timerblock *t = opaque;
- struct xlx_timer *xt;
- unsigned int timer;
- uint32_t value = val64;
-
- addr >>= 2;
- timer = timer_from_addr(addr);
- xt = &t->timers[timer];
- D(fprintf(stderr, "%s addr=%x val=%x (timer=%d off=%d)\n",
- __func__, addr * 4, value, timer, addr & 3));
- /* Further decoding to address a specific timers reg. */
- addr &= 3;
- switch (addr)
- {
- case R_TCSR:
- if (value & TCSR_TINT)
- value &= ~TCSR_TINT;
-
- xt->regs[addr] = value & 0x7ff;
- if (value & TCSR_ENT)
- timer_enable(xt);
- break;
-
- default:
- if (addr < ARRAY_SIZE(xt->regs))
- xt->regs[addr] = value;
- break;
- }
- timer_update_irq(t);
-}
-
-static const MemoryRegionOps timer_ops = {
- .read = timer_read,
- .write = timer_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4
- }
-};
-
-static void timer_hit(void *opaque)
-{
- struct xlx_timer *xt = opaque;
- struct timerblock *t = xt->parent;
- D(fprintf(stderr, "%s %d\n", __func__, xt->nr));
- xt->regs[R_TCSR] |= TCSR_TINT;
-
- if (xt->regs[R_TCSR] & TCSR_ARHT)
- timer_enable(xt);
- timer_update_irq(t);
-}
-
-static void xilinx_timer_realize(DeviceState *dev, Error **errp)
-{
- struct timerblock *t = XILINX_TIMER(dev);
- unsigned int i;
-
- /* Init all the ptimers. */
- t->timers = g_malloc0(sizeof t->timers[0] * num_timers(t));
- for (i = 0; i < num_timers(t); i++) {
- struct xlx_timer *xt = &t->timers[i];
-
- xt->parent = t;
- xt->nr = i;
- xt->bh = qemu_bh_new(timer_hit, xt);
- xt->ptimer = ptimer_init(xt->bh);
- ptimer_set_freq(xt->ptimer, t->freq_hz);
- }
-
- memory_region_init_io(&t->mmio, OBJECT(t), &timer_ops, t, "xlnx.xps-timer",
- R_MAX * 4 * num_timers(t));
- sysbus_init_mmio(SYS_BUS_DEVICE(dev), &t->mmio);
-}
-
-static void xilinx_timer_init(Object *obj)
-{
- struct timerblock *t = XILINX_TIMER(obj);
-
- /* All timers share a single irq line. */
- sysbus_init_irq(SYS_BUS_DEVICE(obj), &t->irq);
-}
-
-static Property xilinx_timer_properties[] = {
- DEFINE_PROP_UINT32("clock-frequency", struct timerblock, freq_hz,
- 62 * 1000000),
- DEFINE_PROP_UINT8("one-timer-only", struct timerblock, one_timer_only, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void xilinx_timer_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = xilinx_timer_realize;
- dc->props = xilinx_timer_properties;
-}
-
-static const TypeInfo xilinx_timer_info = {
- .name = TYPE_XILINX_TIMER,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(struct timerblock),
- .instance_init = xilinx_timer_init,
- .class_init = xilinx_timer_class_init,
-};
-
-static void xilinx_timer_register_types(void)
-{
- type_register_static(&xilinx_timer_info);
-}
-
-type_init(xilinx_timer_register_types)
diff --git a/qemu/hw/tpm/Makefile.objs b/qemu/hw/tpm/Makefile.objs
deleted file mode 100644
index 64cecc3b6..000000000
--- a/qemu/hw/tpm/Makefile.objs
+++ /dev/null
@@ -1,2 +0,0 @@
-common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
-common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o tpm_util.o
diff --git a/qemu/hw/tpm/tpm_int.h b/qemu/hw/tpm/tpm_int.h
deleted file mode 100644
index f2f285b3c..000000000
--- a/qemu/hw/tpm/tpm_int.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * TPM configuration
- *
- * Copyright (C) 2011-2013 IBM Corporation
- *
- * Authors:
- * Stefan Berger <stefanb@us.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-#ifndef TPM_TPM_INT_H
-#define TPM_TPM_INT_H
-
-#include "exec/memory.h"
-#include "tpm_tis.h"
-
-/* overall state of the TPM interface */
-struct TPMState {
- ISADevice busdev;
- MemoryRegion mmio;
-
- union {
- TPMTISEmuState tis;
- } s;
-
- uint8_t locty_number;
- TPMLocality *locty_data;
-
- char *backend;
- TPMBackend *be_driver;
- TPMVersion be_tpm_version;
-};
-
-#define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS)
-
-#define TPM_STANDARD_CMDLINE_OPTS \
- { \
- .name = "type", \
- .type = QEMU_OPT_STRING, \
- .help = "Type of TPM backend", \
- }
-
-struct tpm_req_hdr {
- uint16_t tag;
- uint32_t len;
- uint32_t ordinal;
-} QEMU_PACKED;
-
-struct tpm_resp_hdr {
- uint16_t tag;
- uint32_t len;
- uint32_t errcode;
-} QEMU_PACKED;
-
-#define TPM_TAG_RQU_COMMAND 0xc1
-#define TPM_TAG_RQU_AUTH1_COMMAND 0xc2
-#define TPM_TAG_RQU_AUTH2_COMMAND 0xc3
-
-#define TPM_TAG_RSP_COMMAND 0xc4
-#define TPM_TAG_RSP_AUTH1_COMMAND 0xc5
-#define TPM_TAG_RSP_AUTH2_COMMAND 0xc6
-
-#define TPM_FAIL 9
-
-#define TPM_ORD_ContinueSelfTest 0x53
-#define TPM_ORD_GetTicks 0xf1
-
-
-/* TPM2 defines */
-#define TPM2_ST_NO_SESSIONS 0x8001
-
-#define TPM2_CC_ReadClock 0x00000181
-
-#endif /* TPM_TPM_INT_H */
diff --git a/qemu/hw/tpm/tpm_passthrough.c b/qemu/hw/tpm/tpm_passthrough.c
deleted file mode 100644
index e88c0d20b..000000000
--- a/qemu/hw/tpm/tpm_passthrough.c
+++ /dev/null
@@ -1,566 +0,0 @@
-/*
- * passthrough TPM driver
- *
- * Copyright (c) 2010 - 2013 IBM Corporation
- * Authors:
- * Stefan Berger <stefanb@us.ibm.com>
- *
- * Copyright (C) 2011 IAIK, Graz University of Technology
- * Author: Andreas Niederl
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "qemu/error-report.h"
-#include "qemu/sockets.h"
-#include "sysemu/tpm_backend.h"
-#include "tpm_int.h"
-#include "hw/hw.h"
-#include "hw/i386/pc.h"
-#include "sysemu/tpm_backend_int.h"
-#include "tpm_tis.h"
-#include "tpm_util.h"
-
-#define DEBUG_TPM 0
-
-#define DPRINTF(fmt, ...) do { \
- if (DEBUG_TPM) { \
- fprintf(stderr, fmt, ## __VA_ARGS__); \
- } \
-} while (0);
-
-#define TYPE_TPM_PASSTHROUGH "tpm-passthrough"
-#define TPM_PASSTHROUGH(obj) \
- OBJECT_CHECK(TPMPassthruState, (obj), TYPE_TPM_PASSTHROUGH)
-
-static const TPMDriverOps tpm_passthrough_driver;
-
-/* data structures */
-typedef struct TPMPassthruThreadParams {
- TPMState *tpm_state;
-
- TPMRecvDataCB *recv_data_callback;
- TPMBackend *tb;
-} TPMPassthruThreadParams;
-
-struct TPMPassthruState {
- TPMBackend parent;
-
- TPMBackendThread tbt;
-
- TPMPassthruThreadParams tpm_thread_params;
-
- char *tpm_dev;
- int tpm_fd;
- bool tpm_executing;
- bool tpm_op_canceled;
- int cancel_fd;
- bool had_startup_error;
-
- TPMVersion tpm_version;
-};
-
-typedef struct TPMPassthruState TPMPassthruState;
-
-#define TPM_PASSTHROUGH_DEFAULT_DEVICE "/dev/tpm0"
-
-/* functions */
-
-static void tpm_passthrough_cancel_cmd(TPMBackend *tb);
-
-static int tpm_passthrough_unix_write(int fd, const uint8_t *buf, uint32_t len)
-{
- int ret, remain;
-
- remain = len;
- while (remain > 0) {
- ret = write(fd, buf, remain);
- if (ret < 0) {
- if (errno != EINTR && errno != EAGAIN) {
- return -1;
- }
- } else if (ret == 0) {
- break;
- } else {
- buf += ret;
- remain -= ret;
- }
- }
- return len - remain;
-}
-
-static int tpm_passthrough_unix_read(int fd, uint8_t *buf, uint32_t len)
-{
- int ret;
- reread:
- ret = read(fd, buf, len);
- if (ret < 0) {
- if (errno != EINTR && errno != EAGAIN) {
- return -1;
- }
- goto reread;
- }
- return ret;
-}
-
-static uint32_t tpm_passthrough_get_size_from_buffer(const uint8_t *buf)
-{
- struct tpm_resp_hdr *resp = (struct tpm_resp_hdr *)buf;
-
- return be32_to_cpu(resp->len);
-}
-
-/*
- * Write an error message in the given output buffer.
- */
-static void tpm_write_fatal_error_response(uint8_t *out, uint32_t out_len)
-{
- if (out_len >= sizeof(struct tpm_resp_hdr)) {
- struct tpm_resp_hdr *resp = (struct tpm_resp_hdr *)out;
-
- resp->tag = cpu_to_be16(TPM_TAG_RSP_COMMAND);
- resp->len = cpu_to_be32(sizeof(struct tpm_resp_hdr));
- resp->errcode = cpu_to_be32(TPM_FAIL);
- }
-}
-
-static bool tpm_passthrough_is_selftest(const uint8_t *in, uint32_t in_len)
-{
- struct tpm_req_hdr *hdr = (struct tpm_req_hdr *)in;
-
- if (in_len >= sizeof(*hdr)) {
- return (be32_to_cpu(hdr->ordinal) == TPM_ORD_ContinueSelfTest);
- }
-
- return false;
-}
-
-static int tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt,
- const uint8_t *in, uint32_t in_len,
- uint8_t *out, uint32_t out_len,
- bool *selftest_done)
-{
- int ret;
- bool is_selftest;
- const struct tpm_resp_hdr *hdr;
-
- tpm_pt->tpm_op_canceled = false;
- tpm_pt->tpm_executing = true;
- *selftest_done = false;
-
- is_selftest = tpm_passthrough_is_selftest(in, in_len);
-
- ret = tpm_passthrough_unix_write(tpm_pt->tpm_fd, in, in_len);
- if (ret != in_len) {
- if (!tpm_pt->tpm_op_canceled ||
- (tpm_pt->tpm_op_canceled && errno != ECANCELED)) {
- error_report("tpm_passthrough: error while transmitting data "
- "to TPM: %s (%i)",
- strerror(errno), errno);
- }
- goto err_exit;
- }
-
- tpm_pt->tpm_executing = false;
-
- ret = tpm_passthrough_unix_read(tpm_pt->tpm_fd, out, out_len);
- if (ret < 0) {
- if (!tpm_pt->tpm_op_canceled ||
- (tpm_pt->tpm_op_canceled && errno != ECANCELED)) {
- error_report("tpm_passthrough: error while reading data from "
- "TPM: %s (%i)",
- strerror(errno), errno);
- }
- } else if (ret < sizeof(struct tpm_resp_hdr) ||
- tpm_passthrough_get_size_from_buffer(out) != ret) {
- ret = -1;
- error_report("tpm_passthrough: received invalid response "
- "packet from TPM");
- }
-
- if (is_selftest && (ret >= sizeof(struct tpm_resp_hdr))) {
- hdr = (struct tpm_resp_hdr *)out;
- *selftest_done = (be32_to_cpu(hdr->errcode) == 0);
- }
-
-err_exit:
- if (ret < 0) {
- tpm_write_fatal_error_response(out, out_len);
- }
-
- tpm_pt->tpm_executing = false;
-
- return ret;
-}
-
-static int tpm_passthrough_unix_transfer(TPMPassthruState *tpm_pt,
- const TPMLocality *locty_data,
- bool *selftest_done)
-{
- return tpm_passthrough_unix_tx_bufs(tpm_pt,
- locty_data->w_buffer.buffer,
- locty_data->w_offset,
- locty_data->r_buffer.buffer,
- locty_data->r_buffer.size,
- selftest_done);
-}
-
-static void tpm_passthrough_worker_thread(gpointer data,
- gpointer user_data)
-{
- TPMPassthruThreadParams *thr_parms = user_data;
- TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(thr_parms->tb);
- TPMBackendCmd cmd = (TPMBackendCmd)data;
- bool selftest_done = false;
-
- DPRINTF("tpm_passthrough: processing command type %d\n", cmd);
-
- switch (cmd) {
- case TPM_BACKEND_CMD_PROCESS_CMD:
- tpm_passthrough_unix_transfer(tpm_pt,
- thr_parms->tpm_state->locty_data,
- &selftest_done);
-
- thr_parms->recv_data_callback(thr_parms->tpm_state,
- thr_parms->tpm_state->locty_number,
- selftest_done);
- break;
- case TPM_BACKEND_CMD_INIT:
- case TPM_BACKEND_CMD_END:
- case TPM_BACKEND_CMD_TPM_RESET:
- /* nothing to do */
- break;
- }
-}
-
-/*
- * Start the TPM (thread). If it had been started before, then terminate
- * and start it again.
- */
-static int tpm_passthrough_startup_tpm(TPMBackend *tb)
-{
- TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
-
- /* terminate a running TPM */
- tpm_backend_thread_end(&tpm_pt->tbt);
-
- tpm_backend_thread_create(&tpm_pt->tbt,
- tpm_passthrough_worker_thread,
- &tpm_pt->tpm_thread_params);
-
- return 0;
-}
-
-static void tpm_passthrough_reset(TPMBackend *tb)
-{
- TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
-
- DPRINTF("tpm_passthrough: CALL TO TPM_RESET!\n");
-
- tpm_passthrough_cancel_cmd(tb);
-
- tpm_backend_thread_end(&tpm_pt->tbt);
-
- tpm_pt->had_startup_error = false;
-}
-
-static int tpm_passthrough_init(TPMBackend *tb, TPMState *s,
- TPMRecvDataCB *recv_data_cb)
-{
- TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
-
- tpm_pt->tpm_thread_params.tpm_state = s;
- tpm_pt->tpm_thread_params.recv_data_callback = recv_data_cb;
- tpm_pt->tpm_thread_params.tb = tb;
-
- return 0;
-}
-
-static bool tpm_passthrough_get_tpm_established_flag(TPMBackend *tb)
-{
- return false;
-}
-
-static int tpm_passthrough_reset_tpm_established_flag(TPMBackend *tb,
- uint8_t locty)
-{
- /* only a TPM 2.0 will support this */
- return 0;
-}
-
-static bool tpm_passthrough_get_startup_error(TPMBackend *tb)
-{
- TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
-
- return tpm_pt->had_startup_error;
-}
-
-static size_t tpm_passthrough_realloc_buffer(TPMSizedBuffer *sb)
-{
- size_t wanted_size = 4096; /* Linux tpm.c buffer size */
-
- if (sb->size != wanted_size) {
- sb->buffer = g_realloc(sb->buffer, wanted_size);
- sb->size = wanted_size;
- }
- return sb->size;
-}
-
-static void tpm_passthrough_deliver_request(TPMBackend *tb)
-{
- TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
-
- tpm_backend_thread_deliver_request(&tpm_pt->tbt);
-}
-
-static void tpm_passthrough_cancel_cmd(TPMBackend *tb)
-{
- TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
- int n;
-
- /*
- * As of Linux 3.7 the tpm_tis driver does not properly cancel
- * commands on all TPM manufacturers' TPMs.
- * Only cancel if we're busy so we don't cancel someone else's
- * command, e.g., a command executed on the host.
- */
- if (tpm_pt->tpm_executing) {
- if (tpm_pt->cancel_fd >= 0) {
- n = write(tpm_pt->cancel_fd, "-", 1);
- if (n != 1) {
- error_report("Canceling TPM command failed: %s",
- strerror(errno));
- } else {
- tpm_pt->tpm_op_canceled = true;
- }
- } else {
- error_report("Cannot cancel TPM command due to missing "
- "TPM sysfs cancel entry");
- }
- }
-}
-
-static const char *tpm_passthrough_create_desc(void)
-{
- return "Passthrough TPM backend driver";
-}
-
-static TPMVersion tpm_passthrough_get_tpm_version(TPMBackend *tb)
-{
- TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
-
- return tpm_pt->tpm_version;
-}
-
-/*
- * Unless path or file descriptor set has been provided by user,
- * determine the sysfs cancel file following kernel documentation
- * in Documentation/ABI/stable/sysfs-class-tpm.
- * From /dev/tpm0 create /sys/class/misc/tpm0/device/cancel
- */
-static int tpm_passthrough_open_sysfs_cancel(TPMBackend *tb)
-{
- TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
- int fd = -1;
- char *dev;
- char path[PATH_MAX];
-
- if (tb->cancel_path) {
- fd = qemu_open(tb->cancel_path, O_WRONLY);
- if (fd < 0) {
- error_report("Could not open TPM cancel path : %s",
- strerror(errno));
- }
- return fd;
- }
-
- dev = strrchr(tpm_pt->tpm_dev, '/');
- if (dev) {
- dev++;
- if (snprintf(path, sizeof(path), "/sys/class/misc/%s/device/cancel",
- dev) < sizeof(path)) {
- fd = qemu_open(path, O_WRONLY);
- if (fd >= 0) {
- tb->cancel_path = g_strdup(path);
- } else {
- error_report("tpm_passthrough: Could not open TPM cancel "
- "path %s : %s", path, strerror(errno));
- }
- }
- } else {
- error_report("tpm_passthrough: Bad TPM device path %s",
- tpm_pt->tpm_dev);
- }
-
- return fd;
-}
-
-static int tpm_passthrough_handle_device_opts(QemuOpts *opts, TPMBackend *tb)
-{
- TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
- const char *value;
-
- value = qemu_opt_get(opts, "cancel-path");
- tb->cancel_path = g_strdup(value);
-
- value = qemu_opt_get(opts, "path");
- if (!value) {
- value = TPM_PASSTHROUGH_DEFAULT_DEVICE;
- }
-
- tpm_pt->tpm_dev = g_strdup(value);
-
- tb->path = g_strdup(tpm_pt->tpm_dev);
-
- tpm_pt->tpm_fd = qemu_open(tpm_pt->tpm_dev, O_RDWR);
- if (tpm_pt->tpm_fd < 0) {
- error_report("Cannot access TPM device using '%s': %s",
- tpm_pt->tpm_dev, strerror(errno));
- goto err_free_parameters;
- }
-
- if (tpm_util_test_tpmdev(tpm_pt->tpm_fd, &tpm_pt->tpm_version)) {
- error_report("'%s' is not a TPM device.",
- tpm_pt->tpm_dev);
- goto err_close_tpmdev;
- }
-
- return 0;
-
- err_close_tpmdev:
- qemu_close(tpm_pt->tpm_fd);
- tpm_pt->tpm_fd = -1;
-
- err_free_parameters:
- g_free(tb->path);
- tb->path = NULL;
-
- g_free(tpm_pt->tpm_dev);
- tpm_pt->tpm_dev = NULL;
-
- return 1;
-}
-
-static TPMBackend *tpm_passthrough_create(QemuOpts *opts, const char *id)
-{
- Object *obj = object_new(TYPE_TPM_PASSTHROUGH);
- TPMBackend *tb = TPM_BACKEND(obj);
- TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
-
- tb->id = g_strdup(id);
- /* let frontend set the fe_model to proper value */
- tb->fe_model = -1;
-
- tb->ops = &tpm_passthrough_driver;
-
- if (tpm_passthrough_handle_device_opts(opts, tb)) {
- goto err_exit;
- }
-
- tpm_pt->cancel_fd = tpm_passthrough_open_sysfs_cancel(tb);
- if (tpm_pt->cancel_fd < 0) {
- goto err_exit;
- }
-
- return tb;
-
-err_exit:
- g_free(tb->id);
-
- return NULL;
-}
-
-static void tpm_passthrough_destroy(TPMBackend *tb)
-{
- TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
-
- tpm_passthrough_cancel_cmd(tb);
-
- tpm_backend_thread_end(&tpm_pt->tbt);
-
- qemu_close(tpm_pt->tpm_fd);
- qemu_close(tpm_pt->cancel_fd);
-
- g_free(tb->id);
- g_free(tb->path);
- g_free(tb->cancel_path);
- g_free(tpm_pt->tpm_dev);
-}
-
-static const QemuOptDesc tpm_passthrough_cmdline_opts[] = {
- TPM_STANDARD_CMDLINE_OPTS,
- {
- .name = "cancel-path",
- .type = QEMU_OPT_STRING,
- .help = "Sysfs file entry for canceling TPM commands",
- },
- {
- .name = "path",
- .type = QEMU_OPT_STRING,
- .help = "Path to TPM device on the host",
- },
- { /* end of list */ },
-};
-
-static const TPMDriverOps tpm_passthrough_driver = {
- .type = TPM_TYPE_PASSTHROUGH,
- .opts = tpm_passthrough_cmdline_opts,
- .desc = tpm_passthrough_create_desc,
- .create = tpm_passthrough_create,
- .destroy = tpm_passthrough_destroy,
- .init = tpm_passthrough_init,
- .startup_tpm = tpm_passthrough_startup_tpm,
- .realloc_buffer = tpm_passthrough_realloc_buffer,
- .reset = tpm_passthrough_reset,
- .had_startup_error = tpm_passthrough_get_startup_error,
- .deliver_request = tpm_passthrough_deliver_request,
- .cancel_cmd = tpm_passthrough_cancel_cmd,
- .get_tpm_established_flag = tpm_passthrough_get_tpm_established_flag,
- .reset_tpm_established_flag = tpm_passthrough_reset_tpm_established_flag,
- .get_tpm_version = tpm_passthrough_get_tpm_version,
-};
-
-static void tpm_passthrough_inst_init(Object *obj)
-{
-}
-
-static void tpm_passthrough_inst_finalize(Object *obj)
-{
-}
-
-static void tpm_passthrough_class_init(ObjectClass *klass, void *data)
-{
- TPMBackendClass *tbc = TPM_BACKEND_CLASS(klass);
-
- tbc->ops = &tpm_passthrough_driver;
-}
-
-static const TypeInfo tpm_passthrough_info = {
- .name = TYPE_TPM_PASSTHROUGH,
- .parent = TYPE_TPM_BACKEND,
- .instance_size = sizeof(TPMPassthruState),
- .class_init = tpm_passthrough_class_init,
- .instance_init = tpm_passthrough_inst_init,
- .instance_finalize = tpm_passthrough_inst_finalize,
-};
-
-static void tpm_passthrough_register(void)
-{
- type_register_static(&tpm_passthrough_info);
- tpm_register_driver(&tpm_passthrough_driver);
-}
-
-type_init(tpm_passthrough_register)
diff --git a/qemu/hw/tpm/tpm_tis.c b/qemu/hw/tpm/tpm_tis.c
deleted file mode 100644
index 381e7266e..000000000
--- a/qemu/hw/tpm/tpm_tis.c
+++ /dev/null
@@ -1,1101 +0,0 @@
-/*
- * tpm_tis.c - QEMU's TPM TIS interface emulator
- *
- * Copyright (C) 2006,2010-2013 IBM Corporation
- *
- * Authors:
- * Stefan Berger <stefanb@us.ibm.com>
- * David Safford <safford@us.ibm.com>
- *
- * Xen 4 support: Andrease Niederl <andreas.niederl@iaik.tugraz.at>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- * Implementation of the TIS interface according to specs found at
- * http://www.trustedcomputinggroup.org. This implementation currently
- * supports version 1.3, 21 March 2013
- * In the developers menu choose the PC Client section then find the TIS
- * specification.
- *
- * TPM TIS for TPM 2 implementation following TCG PC Client Platform
- * TPM Profile (PTP) Specification, Familiy 2.0, Revision 00.43
- */
-
-#include "qemu/osdep.h"
-#include "sysemu/tpm_backend.h"
-#include "tpm_int.h"
-#include "sysemu/block-backend.h"
-#include "exec/address-spaces.h"
-#include "hw/hw.h"
-#include "hw/i386/pc.h"
-#include "hw/pci/pci_ids.h"
-#include "tpm_tis.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "qemu/main-loop.h"
-#include "sysemu/tpm_backend.h"
-
-#define DEBUG_TIS 0
-
-#define DPRINTF(fmt, ...) do { \
- if (DEBUG_TIS) { \
- printf(fmt, ## __VA_ARGS__); \
- } \
-} while (0);
-
-/* whether the STS interrupt is supported */
-#define RAISE_STS_IRQ
-
-/* tis registers */
-#define TPM_TIS_REG_ACCESS 0x00
-#define TPM_TIS_REG_INT_ENABLE 0x08
-#define TPM_TIS_REG_INT_VECTOR 0x0c
-#define TPM_TIS_REG_INT_STATUS 0x10
-#define TPM_TIS_REG_INTF_CAPABILITY 0x14
-#define TPM_TIS_REG_STS 0x18
-#define TPM_TIS_REG_DATA_FIFO 0x24
-#define TPM_TIS_REG_INTERFACE_ID 0x30
-#define TPM_TIS_REG_DATA_XFIFO 0x80
-#define TPM_TIS_REG_DATA_XFIFO_END 0xbc
-#define TPM_TIS_REG_DID_VID 0xf00
-#define TPM_TIS_REG_RID 0xf04
-
-/* vendor-specific registers */
-#define TPM_TIS_REG_DEBUG 0xf90
-
-#define TPM_TIS_STS_TPM_FAMILY_MASK (0x3 << 26)/* TPM 2.0 */
-#define TPM_TIS_STS_TPM_FAMILY1_2 (0 << 26) /* TPM 2.0 */
-#define TPM_TIS_STS_TPM_FAMILY2_0 (1 << 26) /* TPM 2.0 */
-#define TPM_TIS_STS_RESET_ESTABLISHMENT_BIT (1 << 25) /* TPM 2.0 */
-#define TPM_TIS_STS_COMMAND_CANCEL (1 << 24) /* TPM 2.0 */
-
-#define TPM_TIS_STS_VALID (1 << 7)
-#define TPM_TIS_STS_COMMAND_READY (1 << 6)
-#define TPM_TIS_STS_TPM_GO (1 << 5)
-#define TPM_TIS_STS_DATA_AVAILABLE (1 << 4)
-#define TPM_TIS_STS_EXPECT (1 << 3)
-#define TPM_TIS_STS_SELFTEST_DONE (1 << 2)
-#define TPM_TIS_STS_RESPONSE_RETRY (1 << 1)
-
-#define TPM_TIS_BURST_COUNT_SHIFT 8
-#define TPM_TIS_BURST_COUNT(X) \
- ((X) << TPM_TIS_BURST_COUNT_SHIFT)
-
-#define TPM_TIS_ACCESS_TPM_REG_VALID_STS (1 << 7)
-#define TPM_TIS_ACCESS_ACTIVE_LOCALITY (1 << 5)
-#define TPM_TIS_ACCESS_BEEN_SEIZED (1 << 4)
-#define TPM_TIS_ACCESS_SEIZE (1 << 3)
-#define TPM_TIS_ACCESS_PENDING_REQUEST (1 << 2)
-#define TPM_TIS_ACCESS_REQUEST_USE (1 << 1)
-#define TPM_TIS_ACCESS_TPM_ESTABLISHMENT (1 << 0)
-
-#define TPM_TIS_INT_ENABLED (1 << 31)
-#define TPM_TIS_INT_DATA_AVAILABLE (1 << 0)
-#define TPM_TIS_INT_STS_VALID (1 << 1)
-#define TPM_TIS_INT_LOCALITY_CHANGED (1 << 2)
-#define TPM_TIS_INT_COMMAND_READY (1 << 7)
-
-#define TPM_TIS_INT_POLARITY_MASK (3 << 3)
-#define TPM_TIS_INT_POLARITY_LOW_LEVEL (1 << 3)
-
-#ifndef RAISE_STS_IRQ
-
-#define TPM_TIS_INTERRUPTS_SUPPORTED (TPM_TIS_INT_LOCALITY_CHANGED | \
- TPM_TIS_INT_DATA_AVAILABLE | \
- TPM_TIS_INT_COMMAND_READY)
-
-#else
-
-#define TPM_TIS_INTERRUPTS_SUPPORTED (TPM_TIS_INT_LOCALITY_CHANGED | \
- TPM_TIS_INT_DATA_AVAILABLE | \
- TPM_TIS_INT_STS_VALID | \
- TPM_TIS_INT_COMMAND_READY)
-
-#endif
-
-#define TPM_TIS_CAP_INTERFACE_VERSION1_3 (2 << 28)
-#define TPM_TIS_CAP_INTERFACE_VERSION1_3_FOR_TPM2_0 (3 << 28)
-#define TPM_TIS_CAP_DATA_TRANSFER_64B (3 << 9)
-#define TPM_TIS_CAP_DATA_TRANSFER_LEGACY (0 << 9)
-#define TPM_TIS_CAP_BURST_COUNT_DYNAMIC (0 << 8)
-#define TPM_TIS_CAP_INTERRUPT_LOW_LEVEL (1 << 4) /* support is mandatory */
-#define TPM_TIS_CAPABILITIES_SUPPORTED1_3 \
- (TPM_TIS_CAP_INTERRUPT_LOW_LEVEL | \
- TPM_TIS_CAP_BURST_COUNT_DYNAMIC | \
- TPM_TIS_CAP_DATA_TRANSFER_64B | \
- TPM_TIS_CAP_INTERFACE_VERSION1_3 | \
- TPM_TIS_INTERRUPTS_SUPPORTED)
-
-#define TPM_TIS_CAPABILITIES_SUPPORTED2_0 \
- (TPM_TIS_CAP_INTERRUPT_LOW_LEVEL | \
- TPM_TIS_CAP_BURST_COUNT_DYNAMIC | \
- TPM_TIS_CAP_DATA_TRANSFER_64B | \
- TPM_TIS_CAP_INTERFACE_VERSION1_3_FOR_TPM2_0 | \
- TPM_TIS_INTERRUPTS_SUPPORTED)
-
-#define TPM_TIS_IFACE_ID_INTERFACE_TIS1_3 (0xf) /* TPM 2.0 */
-#define TPM_TIS_IFACE_ID_INTERFACE_FIFO (0x0) /* TPM 2.0 */
-#define TPM_TIS_IFACE_ID_INTERFACE_VER_FIFO (0 << 4) /* TPM 2.0 */
-#define TPM_TIS_IFACE_ID_CAP_5_LOCALITIES (1 << 8) /* TPM 2.0 */
-#define TPM_TIS_IFACE_ID_CAP_TIS_SUPPORTED (1 << 13) /* TPM 2.0 */
-#define TPM_TIS_IFACE_ID_INT_SEL_LOCK (1 << 19) /* TPM 2.0 */
-
-#define TPM_TIS_IFACE_ID_SUPPORTED_FLAGS1_3 \
- (TPM_TIS_IFACE_ID_INTERFACE_TIS1_3 | \
- (~0u << 4)/* all of it is don't care */)
-
-/* if backend was a TPM 2.0: */
-#define TPM_TIS_IFACE_ID_SUPPORTED_FLAGS2_0 \
- (TPM_TIS_IFACE_ID_INTERFACE_FIFO | \
- TPM_TIS_IFACE_ID_INTERFACE_VER_FIFO | \
- TPM_TIS_IFACE_ID_CAP_5_LOCALITIES | \
- TPM_TIS_IFACE_ID_CAP_TIS_SUPPORTED)
-
-#define TPM_TIS_TPM_DID 0x0001
-#define TPM_TIS_TPM_VID PCI_VENDOR_ID_IBM
-#define TPM_TIS_TPM_RID 0x0001
-
-#define TPM_TIS_NO_DATA_BYTE 0xff
-
-/* local prototypes */
-
-static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
- unsigned size);
-
-/* utility functions */
-
-static uint8_t tpm_tis_locality_from_addr(hwaddr addr)
-{
- return (uint8_t)((addr >> TPM_TIS_LOCALITY_SHIFT) & 0x7);
-}
-
-static uint32_t tpm_tis_get_size_from_buffer(const TPMSizedBuffer *sb)
-{
- return be32_to_cpu(*(uint32_t *)&sb->buffer[2]);
-}
-
-static void tpm_tis_show_buffer(const TPMSizedBuffer *sb, const char *string)
-{
-#ifdef DEBUG_TIS
- uint32_t len, i;
-
- len = tpm_tis_get_size_from_buffer(sb);
- DPRINTF("tpm_tis: %s length = %d\n", string, len);
- for (i = 0; i < len; i++) {
- if (i && !(i % 16)) {
- DPRINTF("\n");
- }
- DPRINTF("%.2X ", sb->buffer[i]);
- }
- DPRINTF("\n");
-#endif
-}
-
-/*
- * Set the given flags in the STS register by clearing the register but
- * preserving the SELFTEST_DONE and TPM_FAMILY_MASK flags and then setting
- * the new flags.
- *
- * The SELFTEST_DONE flag is acquired from the backend that determines it by
- * peeking into TPM commands.
- *
- * A VM suspend/resume will preserve the flag by storing it into the VM
- * device state, but the backend will not remember it when QEMU is started
- * again. Therefore, we cache the flag here. Once set, it will not be unset
- * except by a reset.
- */
-static void tpm_tis_sts_set(TPMLocality *l, uint32_t flags)
-{
- l->sts &= TPM_TIS_STS_SELFTEST_DONE | TPM_TIS_STS_TPM_FAMILY_MASK;
- l->sts |= flags;
-}
-
-/*
- * Send a request to the TPM.
- */
-static void tpm_tis_tpm_send(TPMState *s, uint8_t locty)
-{
- TPMTISEmuState *tis = &s->s.tis;
-
- tpm_tis_show_buffer(&tis->loc[locty].w_buffer, "tpm_tis: To TPM");
-
- s->locty_number = locty;
- s->locty_data = &tis->loc[locty];
-
- /*
- * w_offset serves as length indicator for length of data;
- * it's reset when the response comes back
- */
- tis->loc[locty].state = TPM_TIS_STATE_EXECUTION;
-
- tpm_backend_deliver_request(s->be_driver);
-}
-
-/* raise an interrupt if allowed */
-static void tpm_tis_raise_irq(TPMState *s, uint8_t locty, uint32_t irqmask)
-{
- TPMTISEmuState *tis = &s->s.tis;
-
- if (!TPM_TIS_IS_VALID_LOCTY(locty)) {
- return;
- }
-
- if ((tis->loc[locty].inte & TPM_TIS_INT_ENABLED) &&
- (tis->loc[locty].inte & irqmask)) {
- DPRINTF("tpm_tis: Raising IRQ for flag %08x\n", irqmask);
- qemu_irq_raise(s->s.tis.irq);
- tis->loc[locty].ints |= irqmask;
- }
-}
-
-static uint32_t tpm_tis_check_request_use_except(TPMState *s, uint8_t locty)
-{
- uint8_t l;
-
- for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) {
- if (l == locty) {
- continue;
- }
- if ((s->s.tis.loc[l].access & TPM_TIS_ACCESS_REQUEST_USE)) {
- return 1;
- }
- }
-
- return 0;
-}
-
-static void tpm_tis_new_active_locality(TPMState *s, uint8_t new_active_locty)
-{
- TPMTISEmuState *tis = &s->s.tis;
- bool change = (s->s.tis.active_locty != new_active_locty);
- bool is_seize;
- uint8_t mask;
-
- if (change && TPM_TIS_IS_VALID_LOCTY(s->s.tis.active_locty)) {
- is_seize = TPM_TIS_IS_VALID_LOCTY(new_active_locty) &&
- tis->loc[new_active_locty].access & TPM_TIS_ACCESS_SEIZE;
-
- if (is_seize) {
- mask = ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY);
- } else {
- mask = ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY|
- TPM_TIS_ACCESS_REQUEST_USE);
- }
- /* reset flags on the old active locality */
- tis->loc[s->s.tis.active_locty].access &= mask;
-
- if (is_seize) {
- tis->loc[tis->active_locty].access |= TPM_TIS_ACCESS_BEEN_SEIZED;
- }
- }
-
- tis->active_locty = new_active_locty;
-
- DPRINTF("tpm_tis: Active locality is now %d\n", s->s.tis.active_locty);
-
- if (TPM_TIS_IS_VALID_LOCTY(new_active_locty)) {
- /* set flags on the new active locality */
- tis->loc[new_active_locty].access |= TPM_TIS_ACCESS_ACTIVE_LOCALITY;
- tis->loc[new_active_locty].access &= ~(TPM_TIS_ACCESS_REQUEST_USE |
- TPM_TIS_ACCESS_SEIZE);
- }
-
- if (change) {
- tpm_tis_raise_irq(s, tis->active_locty, TPM_TIS_INT_LOCALITY_CHANGED);
- }
-}
-
-/* abort -- this function switches the locality */
-static void tpm_tis_abort(TPMState *s, uint8_t locty)
-{
- TPMTISEmuState *tis = &s->s.tis;
-
- tis->loc[locty].r_offset = 0;
- tis->loc[locty].w_offset = 0;
-
- DPRINTF("tpm_tis: tis_abort: new active locality is %d\n", tis->next_locty);
-
- /*
- * Need to react differently depending on who's aborting now and
- * which locality will become active afterwards.
- */
- if (tis->aborting_locty == tis->next_locty) {
- tis->loc[tis->aborting_locty].state = TPM_TIS_STATE_READY;
- tpm_tis_sts_set(&tis->loc[tis->aborting_locty],
- TPM_TIS_STS_COMMAND_READY);
- tpm_tis_raise_irq(s, tis->aborting_locty, TPM_TIS_INT_COMMAND_READY);
- }
-
- /* locality after abort is another one than the current one */
- tpm_tis_new_active_locality(s, tis->next_locty);
-
- tis->next_locty = TPM_TIS_NO_LOCALITY;
- /* nobody's aborting a command anymore */
- tis->aborting_locty = TPM_TIS_NO_LOCALITY;
-}
-
-/* prepare aborting current command */
-static void tpm_tis_prep_abort(TPMState *s, uint8_t locty, uint8_t newlocty)
-{
- TPMTISEmuState *tis = &s->s.tis;
- uint8_t busy_locty;
-
- tis->aborting_locty = locty;
- tis->next_locty = newlocty; /* locality after successful abort */
-
- /*
- * only abort a command using an interrupt if currently executing
- * a command AND if there's a valid connection to the vTPM.
- */
- for (busy_locty = 0; busy_locty < TPM_TIS_NUM_LOCALITIES; busy_locty++) {
- if (tis->loc[busy_locty].state == TPM_TIS_STATE_EXECUTION) {
- /*
- * request the backend to cancel. Some backends may not
- * support it
- */
- tpm_backend_cancel_cmd(s->be_driver);
- return;
- }
- }
-
- tpm_tis_abort(s, locty);
-}
-
-static void tpm_tis_receive_bh(void *opaque)
-{
- TPMState *s = opaque;
- TPMTISEmuState *tis = &s->s.tis;
- uint8_t locty = s->locty_number;
-
- tpm_tis_sts_set(&tis->loc[locty],
- TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE);
- tis->loc[locty].state = TPM_TIS_STATE_COMPLETION;
- tis->loc[locty].r_offset = 0;
- tis->loc[locty].w_offset = 0;
-
- if (TPM_TIS_IS_VALID_LOCTY(tis->next_locty)) {
- tpm_tis_abort(s, locty);
- }
-
-#ifndef RAISE_STS_IRQ
- tpm_tis_raise_irq(s, locty, TPM_TIS_INT_DATA_AVAILABLE);
-#else
- tpm_tis_raise_irq(s, locty,
- TPM_TIS_INT_DATA_AVAILABLE | TPM_TIS_INT_STS_VALID);
-#endif
-}
-
-/*
- * Callback from the TPM to indicate that the response was received.
- */
-static void tpm_tis_receive_cb(TPMState *s, uint8_t locty,
- bool is_selftest_done)
-{
- TPMTISEmuState *tis = &s->s.tis;
- uint8_t l;
-
- assert(s->locty_number == locty);
-
- if (is_selftest_done) {
- for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) {
- tis->loc[locty].sts |= TPM_TIS_STS_SELFTEST_DONE;
- }
- }
-
- qemu_bh_schedule(tis->bh);
-}
-
-/*
- * Read a byte of response data
- */
-static uint32_t tpm_tis_data_read(TPMState *s, uint8_t locty)
-{
- TPMTISEmuState *tis = &s->s.tis;
- uint32_t ret = TPM_TIS_NO_DATA_BYTE;
- uint16_t len;
-
- if ((tis->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) {
- len = tpm_tis_get_size_from_buffer(&tis->loc[locty].r_buffer);
-
- ret = tis->loc[locty].r_buffer.buffer[tis->loc[locty].r_offset++];
- if (tis->loc[locty].r_offset >= len) {
- /* got last byte */
- tpm_tis_sts_set(&tis->loc[locty], TPM_TIS_STS_VALID);
-#ifdef RAISE_STS_IRQ
- tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID);
-#endif
- }
- DPRINTF("tpm_tis: tpm_tis_data_read byte 0x%02x [%d]\n",
- ret, tis->loc[locty].r_offset-1);
- }
-
- return ret;
-}
-
-#ifdef DEBUG_TIS
-static void tpm_tis_dump_state(void *opaque, hwaddr addr)
-{
- static const unsigned regs[] = {
- TPM_TIS_REG_ACCESS,
- TPM_TIS_REG_INT_ENABLE,
- TPM_TIS_REG_INT_VECTOR,
- TPM_TIS_REG_INT_STATUS,
- TPM_TIS_REG_INTF_CAPABILITY,
- TPM_TIS_REG_STS,
- TPM_TIS_REG_DID_VID,
- TPM_TIS_REG_RID,
- 0xfff};
- int idx;
- uint8_t locty = tpm_tis_locality_from_addr(addr);
- hwaddr base = addr & ~0xfff;
- TPMState *s = opaque;
- TPMTISEmuState *tis = &s->s.tis;
-
- DPRINTF("tpm_tis: active locality : %d\n"
- "tpm_tis: state of locality %d : %d\n"
- "tpm_tis: register dump:\n",
- tis->active_locty,
- locty, tis->loc[locty].state);
-
- for (idx = 0; regs[idx] != 0xfff; idx++) {
- DPRINTF("tpm_tis: 0x%04x : 0x%08x\n", regs[idx],
- (int)tpm_tis_mmio_read(opaque, base + regs[idx], 4));
- }
-
- DPRINTF("tpm_tis: read offset : %d\n"
- "tpm_tis: result buffer : ",
- tis->loc[locty].r_offset);
- for (idx = 0;
- idx < tpm_tis_get_size_from_buffer(&tis->loc[locty].r_buffer);
- idx++) {
- DPRINTF("%c%02x%s",
- tis->loc[locty].r_offset == idx ? '>' : ' ',
- tis->loc[locty].r_buffer.buffer[idx],
- ((idx & 0xf) == 0xf) ? "\ntpm_tis: " : "");
- }
- DPRINTF("\n"
- "tpm_tis: write offset : %d\n"
- "tpm_tis: request buffer: ",
- tis->loc[locty].w_offset);
- for (idx = 0;
- idx < tpm_tis_get_size_from_buffer(&tis->loc[locty].w_buffer);
- idx++) {
- DPRINTF("%c%02x%s",
- tis->loc[locty].w_offset == idx ? '>' : ' ',
- tis->loc[locty].w_buffer.buffer[idx],
- ((idx & 0xf) == 0xf) ? "\ntpm_tis: " : "");
- }
- DPRINTF("\n");
-}
-#endif
-
-/*
- * Read a register of the TIS interface
- * See specs pages 33-63 for description of the registers
- */
-static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- TPMState *s = opaque;
- TPMTISEmuState *tis = &s->s.tis;
- uint16_t offset = addr & 0xffc;
- uint8_t shift = (addr & 0x3) * 8;
- uint32_t val = 0xffffffff;
- uint8_t locty = tpm_tis_locality_from_addr(addr);
- uint32_t avail;
- uint8_t v;
-
- if (tpm_backend_had_startup_error(s->be_driver)) {
- return val;
- }
-
- switch (offset) {
- case TPM_TIS_REG_ACCESS:
- /* never show the SEIZE flag even though we use it internally */
- val = tis->loc[locty].access & ~TPM_TIS_ACCESS_SEIZE;
- /* the pending flag is always calculated */
- if (tpm_tis_check_request_use_except(s, locty)) {
- val |= TPM_TIS_ACCESS_PENDING_REQUEST;
- }
- val |= !tpm_backend_get_tpm_established_flag(s->be_driver);
- break;
- case TPM_TIS_REG_INT_ENABLE:
- val = tis->loc[locty].inte;
- break;
- case TPM_TIS_REG_INT_VECTOR:
- val = tis->irq_num;
- break;
- case TPM_TIS_REG_INT_STATUS:
- val = tis->loc[locty].ints;
- break;
- case TPM_TIS_REG_INTF_CAPABILITY:
- switch (s->be_tpm_version) {
- case TPM_VERSION_UNSPEC:
- val = 0;
- break;
- case TPM_VERSION_1_2:
- val = TPM_TIS_CAPABILITIES_SUPPORTED1_3;
- break;
- case TPM_VERSION_2_0:
- val = TPM_TIS_CAPABILITIES_SUPPORTED2_0;
- break;
- }
- break;
- case TPM_TIS_REG_STS:
- if (tis->active_locty == locty) {
- if ((tis->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) {
- val = TPM_TIS_BURST_COUNT(
- tpm_tis_get_size_from_buffer(&tis->loc[locty].r_buffer)
- - tis->loc[locty].r_offset) | tis->loc[locty].sts;
- } else {
- avail = tis->loc[locty].w_buffer.size
- - tis->loc[locty].w_offset;
- /*
- * byte-sized reads should not return 0x00 for 0x100
- * available bytes.
- */
- if (size == 1 && avail > 0xff) {
- avail = 0xff;
- }
- val = TPM_TIS_BURST_COUNT(avail) | tis->loc[locty].sts;
- }
- }
- break;
- case TPM_TIS_REG_DATA_FIFO:
- case TPM_TIS_REG_DATA_XFIFO ... TPM_TIS_REG_DATA_XFIFO_END:
- if (tis->active_locty == locty) {
- if (size > 4 - (addr & 0x3)) {
- /* prevent access beyond FIFO */
- size = 4 - (addr & 0x3);
- }
- val = 0;
- shift = 0;
- while (size > 0) {
- switch (tis->loc[locty].state) {
- case TPM_TIS_STATE_COMPLETION:
- v = tpm_tis_data_read(s, locty);
- break;
- default:
- v = TPM_TIS_NO_DATA_BYTE;
- break;
- }
- val |= (v << shift);
- shift += 8;
- size--;
- }
- shift = 0; /* no more adjustments */
- }
- break;
- case TPM_TIS_REG_INTERFACE_ID:
- val = tis->loc[locty].iface_id;
- break;
- case TPM_TIS_REG_DID_VID:
- val = (TPM_TIS_TPM_DID << 16) | TPM_TIS_TPM_VID;
- break;
- case TPM_TIS_REG_RID:
- val = TPM_TIS_TPM_RID;
- break;
-#ifdef DEBUG_TIS
- case TPM_TIS_REG_DEBUG:
- tpm_tis_dump_state(opaque, addr);
- break;
-#endif
- }
-
- if (shift) {
- val >>= shift;
- }
-
- DPRINTF("tpm_tis: read.%u(%08x) = %08x\n", size, (int)addr, (int)val);
-
- return val;
-}
-
-/*
- * Write a value to a register of the TIS interface
- * See specs pages 33-63 for description of the registers
- */
-static void tpm_tis_mmio_write_intern(void *opaque, hwaddr addr,
- uint64_t val, unsigned size,
- bool hw_access)
-{
- TPMState *s = opaque;
- TPMTISEmuState *tis = &s->s.tis;
- uint16_t off = addr & 0xffc;
- uint8_t shift = (addr & 0x3) * 8;
- uint8_t locty = tpm_tis_locality_from_addr(addr);
- uint8_t active_locty, l;
- int c, set_new_locty = 1;
- uint16_t len;
- uint32_t mask = (size == 1) ? 0xff : ((size == 2) ? 0xffff : ~0);
-
- DPRINTF("tpm_tis: write.%u(%08x) = %08x\n", size, (int)addr, (int)val);
-
- if (locty == 4 && !hw_access) {
- DPRINTF("tpm_tis: Access to locality 4 only allowed from hardware\n");
- return;
- }
-
- if (tpm_backend_had_startup_error(s->be_driver)) {
- return;
- }
-
- val &= mask;
-
- if (shift) {
- val <<= shift;
- mask <<= shift;
- }
-
- mask ^= 0xffffffff;
-
- switch (off) {
- case TPM_TIS_REG_ACCESS:
-
- if ((val & TPM_TIS_ACCESS_SEIZE)) {
- val &= ~(TPM_TIS_ACCESS_REQUEST_USE |
- TPM_TIS_ACCESS_ACTIVE_LOCALITY);
- }
-
- active_locty = tis->active_locty;
-
- if ((val & TPM_TIS_ACCESS_ACTIVE_LOCALITY)) {
- /* give up locality if currently owned */
- if (tis->active_locty == locty) {
- DPRINTF("tpm_tis: Releasing locality %d\n", locty);
-
- uint8_t newlocty = TPM_TIS_NO_LOCALITY;
- /* anybody wants the locality ? */
- for (c = TPM_TIS_NUM_LOCALITIES - 1; c >= 0; c--) {
- if ((tis->loc[c].access & TPM_TIS_ACCESS_REQUEST_USE)) {
- DPRINTF("tpm_tis: Locality %d requests use.\n", c);
- newlocty = c;
- break;
- }
- }
- DPRINTF("tpm_tis: TPM_TIS_ACCESS_ACTIVE_LOCALITY: "
- "Next active locality: %d\n",
- newlocty);
-
- if (TPM_TIS_IS_VALID_LOCTY(newlocty)) {
- set_new_locty = 0;
- tpm_tis_prep_abort(s, locty, newlocty);
- } else {
- active_locty = TPM_TIS_NO_LOCALITY;
- }
- } else {
- /* not currently the owner; clear a pending request */
- tis->loc[locty].access &= ~TPM_TIS_ACCESS_REQUEST_USE;
- }
- }
-
- if ((val & TPM_TIS_ACCESS_BEEN_SEIZED)) {
- tis->loc[locty].access &= ~TPM_TIS_ACCESS_BEEN_SEIZED;
- }
-
- if ((val & TPM_TIS_ACCESS_SEIZE)) {
- /*
- * allow seize if a locality is active and the requesting
- * locality is higher than the one that's active
- * OR
- * allow seize for requesting locality if no locality is
- * active
- */
- while ((TPM_TIS_IS_VALID_LOCTY(tis->active_locty) &&
- locty > tis->active_locty) ||
- !TPM_TIS_IS_VALID_LOCTY(tis->active_locty)) {
- bool higher_seize = FALSE;
-
- /* already a pending SEIZE ? */
- if ((tis->loc[locty].access & TPM_TIS_ACCESS_SEIZE)) {
- break;
- }
-
- /* check for ongoing seize by a higher locality */
- for (l = locty + 1; l < TPM_TIS_NUM_LOCALITIES; l++) {
- if ((tis->loc[l].access & TPM_TIS_ACCESS_SEIZE)) {
- higher_seize = TRUE;
- break;
- }
- }
-
- if (higher_seize) {
- break;
- }
-
- /* cancel any seize by a lower locality */
- for (l = 0; l < locty - 1; l++) {
- tis->loc[l].access &= ~TPM_TIS_ACCESS_SEIZE;
- }
-
- tis->loc[locty].access |= TPM_TIS_ACCESS_SEIZE;
- DPRINTF("tpm_tis: TPM_TIS_ACCESS_SEIZE: "
- "Locality %d seized from locality %d\n",
- locty, tis->active_locty);
- DPRINTF("tpm_tis: TPM_TIS_ACCESS_SEIZE: Initiating abort.\n");
- set_new_locty = 0;
- tpm_tis_prep_abort(s, tis->active_locty, locty);
- break;
- }
- }
-
- if ((val & TPM_TIS_ACCESS_REQUEST_USE)) {
- if (tis->active_locty != locty) {
- if (TPM_TIS_IS_VALID_LOCTY(tis->active_locty)) {
- tis->loc[locty].access |= TPM_TIS_ACCESS_REQUEST_USE;
- } else {
- /* no locality active -> make this one active now */
- active_locty = locty;
- }
- }
- }
-
- if (set_new_locty) {
- tpm_tis_new_active_locality(s, active_locty);
- }
-
- break;
- case TPM_TIS_REG_INT_ENABLE:
- if (tis->active_locty != locty) {
- break;
- }
-
- tis->loc[locty].inte &= mask;
- tis->loc[locty].inte |= (val & (TPM_TIS_INT_ENABLED |
- TPM_TIS_INT_POLARITY_MASK |
- TPM_TIS_INTERRUPTS_SUPPORTED));
- break;
- case TPM_TIS_REG_INT_VECTOR:
- /* hard wired -- ignore */
- break;
- case TPM_TIS_REG_INT_STATUS:
- if (tis->active_locty != locty) {
- break;
- }
-
- /* clearing of interrupt flags */
- if (((val & TPM_TIS_INTERRUPTS_SUPPORTED)) &&
- (tis->loc[locty].ints & TPM_TIS_INTERRUPTS_SUPPORTED)) {
- tis->loc[locty].ints &= ~val;
- if (tis->loc[locty].ints == 0) {
- qemu_irq_lower(tis->irq);
- DPRINTF("tpm_tis: Lowering IRQ\n");
- }
- }
- tis->loc[locty].ints &= ~(val & TPM_TIS_INTERRUPTS_SUPPORTED);
- break;
- case TPM_TIS_REG_STS:
- if (tis->active_locty != locty) {
- break;
- }
-
- if (s->be_tpm_version == TPM_VERSION_2_0) {
- /* some flags that are only supported for TPM 2 */
- if (val & TPM_TIS_STS_COMMAND_CANCEL) {
- if (tis->loc[locty].state == TPM_TIS_STATE_EXECUTION) {
- /*
- * request the backend to cancel. Some backends may not
- * support it
- */
- tpm_backend_cancel_cmd(s->be_driver);
- }
- }
-
- if (val & TPM_TIS_STS_RESET_ESTABLISHMENT_BIT) {
- if (locty == 3 || locty == 4) {
- tpm_backend_reset_tpm_established_flag(s->be_driver, locty);
- }
- }
- }
-
- val &= (TPM_TIS_STS_COMMAND_READY | TPM_TIS_STS_TPM_GO |
- TPM_TIS_STS_RESPONSE_RETRY);
-
- if (val == TPM_TIS_STS_COMMAND_READY) {
- switch (tis->loc[locty].state) {
-
- case TPM_TIS_STATE_READY:
- tis->loc[locty].w_offset = 0;
- tis->loc[locty].r_offset = 0;
- break;
-
- case TPM_TIS_STATE_IDLE:
- tpm_tis_sts_set(&tis->loc[locty], TPM_TIS_STS_COMMAND_READY);
- tis->loc[locty].state = TPM_TIS_STATE_READY;
- tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY);
- break;
-
- case TPM_TIS_STATE_EXECUTION:
- case TPM_TIS_STATE_RECEPTION:
- /* abort currently running command */
- DPRINTF("tpm_tis: %s: Initiating abort.\n",
- __func__);
- tpm_tis_prep_abort(s, locty, locty);
- break;
-
- case TPM_TIS_STATE_COMPLETION:
- tis->loc[locty].w_offset = 0;
- tis->loc[locty].r_offset = 0;
- /* shortcut to ready state with C/R set */
- tis->loc[locty].state = TPM_TIS_STATE_READY;
- if (!(tis->loc[locty].sts & TPM_TIS_STS_COMMAND_READY)) {
- tpm_tis_sts_set(&tis->loc[locty],
- TPM_TIS_STS_COMMAND_READY);
- tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY);
- }
- tis->loc[locty].sts &= ~(TPM_TIS_STS_DATA_AVAILABLE);
- break;
-
- }
- } else if (val == TPM_TIS_STS_TPM_GO) {
- switch (tis->loc[locty].state) {
- case TPM_TIS_STATE_RECEPTION:
- if ((tis->loc[locty].sts & TPM_TIS_STS_EXPECT) == 0) {
- tpm_tis_tpm_send(s, locty);
- }
- break;
- default:
- /* ignore */
- break;
- }
- } else if (val == TPM_TIS_STS_RESPONSE_RETRY) {
- switch (tis->loc[locty].state) {
- case TPM_TIS_STATE_COMPLETION:
- tis->loc[locty].r_offset = 0;
- tpm_tis_sts_set(&tis->loc[locty],
- TPM_TIS_STS_VALID|
- TPM_TIS_STS_DATA_AVAILABLE);
- break;
- default:
- /* ignore */
- break;
- }
- }
- break;
- case TPM_TIS_REG_DATA_FIFO:
- case TPM_TIS_REG_DATA_XFIFO ... TPM_TIS_REG_DATA_XFIFO_END:
- /* data fifo */
- if (tis->active_locty != locty) {
- break;
- }
-
- if (tis->loc[locty].state == TPM_TIS_STATE_IDLE ||
- tis->loc[locty].state == TPM_TIS_STATE_EXECUTION ||
- tis->loc[locty].state == TPM_TIS_STATE_COMPLETION) {
- /* drop the byte */
- } else {
- DPRINTF("tpm_tis: Data to send to TPM: %08x (size=%d)\n",
- (int)val, size);
- if (tis->loc[locty].state == TPM_TIS_STATE_READY) {
- tis->loc[locty].state = TPM_TIS_STATE_RECEPTION;
- tpm_tis_sts_set(&tis->loc[locty],
- TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID);
- }
-
- val >>= shift;
- if (size > 4 - (addr & 0x3)) {
- /* prevent access beyond FIFO */
- size = 4 - (addr & 0x3);
- }
-
- while ((tis->loc[locty].sts & TPM_TIS_STS_EXPECT) && size > 0) {
- if (tis->loc[locty].w_offset < tis->loc[locty].w_buffer.size) {
- tis->loc[locty].w_buffer.
- buffer[tis->loc[locty].w_offset++] = (uint8_t)val;
- val >>= 8;
- size--;
- } else {
- tpm_tis_sts_set(&tis->loc[locty], TPM_TIS_STS_VALID);
- }
- }
-
- /* check for complete packet */
- if (tis->loc[locty].w_offset > 5 &&
- (tis->loc[locty].sts & TPM_TIS_STS_EXPECT)) {
- /* we have a packet length - see if we have all of it */
-#ifdef RAISE_STS_IRQ
- bool need_irq = !(tis->loc[locty].sts & TPM_TIS_STS_VALID);
-#endif
- len = tpm_tis_get_size_from_buffer(&tis->loc[locty].w_buffer);
- if (len > tis->loc[locty].w_offset) {
- tpm_tis_sts_set(&tis->loc[locty],
- TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID);
- } else {
- /* packet complete */
- tpm_tis_sts_set(&tis->loc[locty], TPM_TIS_STS_VALID);
- }
-#ifdef RAISE_STS_IRQ
- if (need_irq) {
- tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID);
- }
-#endif
- }
- }
- break;
- case TPM_TIS_REG_INTERFACE_ID:
- if (val & TPM_TIS_IFACE_ID_INT_SEL_LOCK) {
- for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) {
- tis->loc[l].iface_id |= TPM_TIS_IFACE_ID_INT_SEL_LOCK;
- }
- }
- break;
- }
-}
-
-static void tpm_tis_mmio_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- tpm_tis_mmio_write_intern(opaque, addr, val, size, false);
-}
-
-static const MemoryRegionOps tpm_tis_memory_ops = {
- .read = tpm_tis_mmio_read,
- .write = tpm_tis_mmio_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .valid = {
- .min_access_size = 1,
- .max_access_size = 4,
- },
-};
-
-static int tpm_tis_do_startup_tpm(TPMState *s)
-{
- return tpm_backend_startup_tpm(s->be_driver);
-}
-
-/*
- * Get the TPMVersion of the backend device being used
- */
-TPMVersion tpm_tis_get_tpm_version(Object *obj)
-{
- TPMState *s = TPM(obj);
-
- return tpm_backend_get_tpm_version(s->be_driver);
-}
-
-/*
- * This function is called when the machine starts, resets or due to
- * S3 resume.
- */
-static void tpm_tis_reset(DeviceState *dev)
-{
- TPMState *s = TPM(dev);
- TPMTISEmuState *tis = &s->s.tis;
- int c;
-
- s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver);
-
- tpm_backend_reset(s->be_driver);
-
- tis->active_locty = TPM_TIS_NO_LOCALITY;
- tis->next_locty = TPM_TIS_NO_LOCALITY;
- tis->aborting_locty = TPM_TIS_NO_LOCALITY;
-
- for (c = 0; c < TPM_TIS_NUM_LOCALITIES; c++) {
- tis->loc[c].access = TPM_TIS_ACCESS_TPM_REG_VALID_STS;
- switch (s->be_tpm_version) {
- case TPM_VERSION_UNSPEC:
- break;
- case TPM_VERSION_1_2:
- tis->loc[c].sts = TPM_TIS_STS_TPM_FAMILY1_2;
- tis->loc[c].iface_id = TPM_TIS_IFACE_ID_SUPPORTED_FLAGS1_3;
- break;
- case TPM_VERSION_2_0:
- tis->loc[c].sts = TPM_TIS_STS_TPM_FAMILY2_0;
- tis->loc[c].iface_id = TPM_TIS_IFACE_ID_SUPPORTED_FLAGS2_0;
- break;
- }
- tis->loc[c].inte = TPM_TIS_INT_POLARITY_LOW_LEVEL;
- tis->loc[c].ints = 0;
- tis->loc[c].state = TPM_TIS_STATE_IDLE;
-
- tis->loc[c].w_offset = 0;
- tpm_backend_realloc_buffer(s->be_driver, &tis->loc[c].w_buffer);
- tis->loc[c].r_offset = 0;
- tpm_backend_realloc_buffer(s->be_driver, &tis->loc[c].r_buffer);
- }
-
- tpm_tis_do_startup_tpm(s);
-}
-
-static const VMStateDescription vmstate_tpm_tis = {
- .name = "tpm",
- .unmigratable = 1,
-};
-
-static Property tpm_tis_properties[] = {
- DEFINE_PROP_UINT32("irq", TPMState,
- s.tis.irq_num, TPM_TIS_IRQ),
- DEFINE_PROP_STRING("tpmdev", TPMState, backend),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void tpm_tis_realizefn(DeviceState *dev, Error **errp)
-{
- TPMState *s = TPM(dev);
- TPMTISEmuState *tis = &s->s.tis;
-
- s->be_driver = qemu_find_tpm(s->backend);
- if (!s->be_driver) {
- error_setg(errp, "tpm_tis: backend driver with id %s could not be "
- "found", s->backend);
- return;
- }
-
- s->be_driver->fe_model = TPM_MODEL_TPM_TIS;
-
- if (tpm_backend_init(s->be_driver, s, tpm_tis_receive_cb)) {
- error_setg(errp, "tpm_tis: backend driver with id %s could not be "
- "initialized", s->backend);
- return;
- }
-
- if (tis->irq_num > 15) {
- error_setg(errp, "tpm_tis: IRQ %d for TPM TIS is outside valid range "
- "of 0 to 15", tis->irq_num);
- return;
- }
-
- tis->bh = qemu_bh_new(tpm_tis_receive_bh, s);
-
- isa_init_irq(&s->busdev, &tis->irq, tis->irq_num);
-
- memory_region_add_subregion(isa_address_space(ISA_DEVICE(dev)),
- TPM_TIS_ADDR_BASE, &s->mmio);
-}
-
-static void tpm_tis_initfn(Object *obj)
-{
- TPMState *s = TPM(obj);
-
- memory_region_init_io(&s->mmio, OBJECT(s), &tpm_tis_memory_ops,
- s, "tpm-tis-mmio",
- TPM_TIS_NUM_LOCALITIES << TPM_TIS_LOCALITY_SHIFT);
-}
-
-static void tpm_tis_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = tpm_tis_realizefn;
- dc->props = tpm_tis_properties;
- dc->reset = tpm_tis_reset;
- dc->vmsd = &vmstate_tpm_tis;
-}
-
-static const TypeInfo tpm_tis_info = {
- .name = TYPE_TPM_TIS,
- .parent = TYPE_ISA_DEVICE,
- .instance_size = sizeof(TPMState),
- .instance_init = tpm_tis_initfn,
- .class_init = tpm_tis_class_init,
-};
-
-static void tpm_tis_register(void)
-{
- type_register_static(&tpm_tis_info);
- tpm_register_model(TPM_MODEL_TPM_TIS);
-}
-
-type_init(tpm_tis_register)
diff --git a/qemu/hw/tpm/tpm_tis.h b/qemu/hw/tpm/tpm_tis.h
deleted file mode 100644
index a1df41fa2..000000000
--- a/qemu/hw/tpm/tpm_tis.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * tpm_tis.h - QEMU's TPM TIS interface emulator
- *
- * Copyright (C) 2006, 2010-2013 IBM Corporation
- *
- * Authors:
- * Stefan Berger <stefanb@us.ibm.com>
- * David Safford <safford@us.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- * Implementation of the TIS interface according to specs found at
- * http://www.trustedcomputinggroup.org
- *
- */
-#ifndef TPM_TPM_TIS_H
-#define TPM_TPM_TIS_H
-
-#include "hw/isa/isa.h"
-#include "hw/acpi/tpm.h"
-#include "qemu-common.h"
-
-#define TPM_TIS_NUM_LOCALITIES 5 /* per spec */
-#define TPM_TIS_LOCALITY_SHIFT 12
-#define TPM_TIS_NO_LOCALITY 0xff
-
-#define TPM_TIS_IS_VALID_LOCTY(x) ((x) < TPM_TIS_NUM_LOCALITIES)
-
-#define TPM_TIS_BUFFER_MAX 4096
-
-typedef enum {
- TPM_TIS_STATE_IDLE = 0,
- TPM_TIS_STATE_READY,
- TPM_TIS_STATE_COMPLETION,
- TPM_TIS_STATE_EXECUTION,
- TPM_TIS_STATE_RECEPTION,
-} TPMTISState;
-
-/* locality data -- all fields are persisted */
-typedef struct TPMLocality {
- TPMTISState state;
- uint8_t access;
- uint32_t sts;
- uint32_t iface_id;
- uint32_t inte;
- uint32_t ints;
-
- uint16_t w_offset;
- uint16_t r_offset;
- TPMSizedBuffer w_buffer;
- TPMSizedBuffer r_buffer;
-} TPMLocality;
-
-typedef struct TPMTISEmuState {
- QEMUBH *bh;
- uint32_t offset;
- uint8_t buf[TPM_TIS_BUFFER_MAX];
-
- uint8_t active_locty;
- uint8_t aborting_locty;
- uint8_t next_locty;
-
- TPMLocality loc[TPM_TIS_NUM_LOCALITIES];
-
- qemu_irq irq;
- uint32_t irq_num;
-} TPMTISEmuState;
-
-#endif /* TPM_TPM_TIS_H */
diff --git a/qemu/hw/tpm/tpm_util.c b/qemu/hw/tpm/tpm_util.c
deleted file mode 100644
index 7b3542972..000000000
--- a/qemu/hw/tpm/tpm_util.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * TPM utility functions
- *
- * Copyright (c) 2010 - 2015 IBM Corporation
- * Authors:
- * Stefan Berger <stefanb@us.ibm.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>
- */
-
-#include "qemu/osdep.h"
-#include "tpm_util.h"
-#include "tpm_int.h"
-
-/*
- * A basic test of a TPM device. We expect a well formatted response header
- * (error response is fine) within one second.
- */
-static int tpm_util_test(int fd,
- unsigned char *request,
- size_t requestlen,
- uint16_t *return_tag)
-{
- struct tpm_resp_hdr *resp;
- fd_set readfds;
- int n;
- struct timeval tv = {
- .tv_sec = 1,
- .tv_usec = 0,
- };
- unsigned char buf[1024];
-
- n = write(fd, request, requestlen);
- if (n < 0) {
- return errno;
- }
- if (n != requestlen) {
- return EFAULT;
- }
-
- FD_ZERO(&readfds);
- FD_SET(fd, &readfds);
-
- /* wait for a second */
- n = select(fd + 1, &readfds, NULL, NULL, &tv);
- if (n != 1) {
- return errno;
- }
-
- n = read(fd, &buf, sizeof(buf));
- if (n < sizeof(struct tpm_resp_hdr)) {
- return EFAULT;
- }
-
- resp = (struct tpm_resp_hdr *)buf;
- /* check the header */
- if (be32_to_cpu(resp->len) != n) {
- return EBADMSG;
- }
-
- *return_tag = be16_to_cpu(resp->tag);
-
- return 0;
-}
-
-/*
- * Probe for the TPM device in the back
- * Returns 0 on success with the version of the probed TPM set, 1 on failure.
- */
-int tpm_util_test_tpmdev(int tpm_fd, TPMVersion *tpm_version)
-{
- /*
- * Sending a TPM1.2 command to a TPM2 should return a TPM1.2
- * header (tag = 0xc4) and error code (TPM_BADTAG = 0x1e)
- *
- * Sending a TPM2 command to a TPM 2 will give a TPM 2 tag in the
- * header.
- * Sending a TPM2 command to a TPM 1.2 will give a TPM 1.2 tag
- * in the header and an error code.
- */
- const struct tpm_req_hdr test_req = {
- .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND),
- .len = cpu_to_be32(sizeof(test_req)),
- .ordinal = cpu_to_be32(TPM_ORD_GetTicks),
- };
-
- const struct tpm_req_hdr test_req_tpm2 = {
- .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
- .len = cpu_to_be32(sizeof(test_req_tpm2)),
- .ordinal = cpu_to_be32(TPM2_CC_ReadClock),
- };
- uint16_t return_tag;
- int ret;
-
- /* Send TPM 2 command */
- ret = tpm_util_test(tpm_fd, (unsigned char *)&test_req_tpm2,
- sizeof(test_req_tpm2), &return_tag);
- /* TPM 2 would respond with a tag of TPM2_ST_NO_SESSIONS */
- if (!ret && return_tag == TPM2_ST_NO_SESSIONS) {
- *tpm_version = TPM_VERSION_2_0;
- return 0;
- }
-
- /* Send TPM 1.2 command */
- ret = tpm_util_test(tpm_fd, (unsigned char *)&test_req,
- sizeof(test_req), &return_tag);
- if (!ret && return_tag == TPM_TAG_RSP_COMMAND) {
- *tpm_version = TPM_VERSION_1_2;
- /* this is a TPM 1.2 */
- return 0;
- }
-
- *tpm_version = TPM_VERSION_UNSPEC;
-
- return 1;
-}
diff --git a/qemu/hw/tpm/tpm_util.h b/qemu/hw/tpm/tpm_util.h
deleted file mode 100644
index e7f354a52..000000000
--- a/qemu/hw/tpm/tpm_util.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * TPM utility functions
- *
- * Copyright (c) 2010 - 2015 IBM Corporation
- * Authors:
- * Stefan Berger <stefanb@us.ibm.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>
- */
-#ifndef TPM_TPM_UTILS_H
-#define TPM_TPM_UTILS_H
-
-#include "sysemu/tpm_backend.h"
-
-int tpm_util_test_tpmdev(int tpm_fd, TPMVersion *tpm_version);
-
-#endif /* TPM_TPM_UTILS_H */
diff --git a/qemu/hw/tricore/Makefile.objs b/qemu/hw/tricore/Makefile.objs
deleted file mode 100644
index 435e095cf..000000000
--- a/qemu/hw/tricore/Makefile.objs
+++ /dev/null
@@ -1 +0,0 @@
-obj-y += tricore_testboard.o
diff --git a/qemu/hw/tricore/tricore_testboard.c b/qemu/hw/tricore/tricore_testboard.c
deleted file mode 100644
index 8d3520f5b..000000000
--- a/qemu/hw/tricore/tricore_testboard.c
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * TriCore Baseboard System emulation.
- *
- * Copyright (c) 2013-2014 Bastian Koppelmann C-Lab/University Paderborn
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "hw/hw.h"
-#include "hw/devices.h"
-#include "net/net.h"
-#include "sysemu/sysemu.h"
-#include "hw/boards.h"
-#include "hw/loader.h"
-#include "sysemu/block-backend.h"
-#include "exec/address-spaces.h"
-#include "hw/block/flash.h"
-#include "elf.h"
-#include "hw/tricore/tricore.h"
-#include "qemu/error-report.h"
-
-
-/* Board init. */
-
-static struct tricore_boot_info tricoretb_binfo;
-
-static void tricore_load_kernel(CPUTriCoreState *env)
-{
- uint64_t entry;
- long kernel_size;
-
- kernel_size = load_elf(tricoretb_binfo.kernel_filename, NULL,
- NULL, (uint64_t *)&entry, NULL,
- NULL, 0,
- EM_TRICORE, 1, 0);
- if (kernel_size <= 0) {
- error_report("qemu: no kernel file '%s'",
- tricoretb_binfo.kernel_filename);
- exit(1);
- }
- env->PC = entry;
-
-}
-
-static void tricore_testboard_init(MachineState *machine, int board_id)
-{
- TriCoreCPU *cpu;
- CPUTriCoreState *env;
-
- MemoryRegion *sysmem = get_system_memory();
- MemoryRegion *ext_cram = g_new(MemoryRegion, 1);
- MemoryRegion *ext_dram = g_new(MemoryRegion, 1);
- MemoryRegion *int_cram = g_new(MemoryRegion, 1);
- MemoryRegion *int_dram = g_new(MemoryRegion, 1);
- MemoryRegion *pcp_data = g_new(MemoryRegion, 1);
- MemoryRegion *pcp_text = g_new(MemoryRegion, 1);
-
- if (!machine->cpu_model) {
- machine->cpu_model = "tc1796";
- }
- cpu = cpu_tricore_init(machine->cpu_model);
- if (!cpu) {
- error_report("Unable to find CPU definition");
- exit(1);
- }
- env = &cpu->env;
- memory_region_init_ram(ext_cram, NULL, "powerlink_ext_c.ram", 2*1024*1024,
- &error_fatal);
- vmstate_register_ram_global(ext_cram);
- memory_region_init_ram(ext_dram, NULL, "powerlink_ext_d.ram", 4*1024*1024,
- &error_fatal);
- vmstate_register_ram_global(ext_dram);
- memory_region_init_ram(int_cram, NULL, "powerlink_int_c.ram", 48*1024,
- &error_fatal);
- vmstate_register_ram_global(int_cram);
- memory_region_init_ram(int_dram, NULL, "powerlink_int_d.ram", 48*1024,
- &error_fatal);
- vmstate_register_ram_global(int_dram);
- memory_region_init_ram(pcp_data, NULL, "powerlink_pcp_data.ram", 16*1024,
- &error_fatal);
- vmstate_register_ram_global(pcp_data);
- memory_region_init_ram(pcp_text, NULL, "powerlink_pcp_text.ram", 32*1024,
- &error_fatal);
- vmstate_register_ram_global(pcp_text);
-
- memory_region_add_subregion(sysmem, 0x80000000, ext_cram);
- memory_region_add_subregion(sysmem, 0xa1000000, ext_dram);
- memory_region_add_subregion(sysmem, 0xd4000000, int_cram);
- memory_region_add_subregion(sysmem, 0xd0000000, int_dram);
- memory_region_add_subregion(sysmem, 0xf0050000, pcp_data);
- memory_region_add_subregion(sysmem, 0xf0060000, pcp_text);
-
- tricoretb_binfo.ram_size = machine->ram_size;
- tricoretb_binfo.kernel_filename = machine->kernel_filename;
-
- if (machine->kernel_filename) {
- tricore_load_kernel(env);
- }
-}
-
-static void tricoreboard_init(MachineState *machine)
-{
- tricore_testboard_init(machine, 0x183);
-}
-
-static void ttb_machine_init(MachineClass *mc)
-{
- mc->desc = "a minimal TriCore board";
- mc->init = tricoreboard_init;
- mc->is_default = 0;
-}
-
-DEFINE_MACHINE("tricore_testboard", ttb_machine_init)
diff --git a/qemu/hw/unicore32/Makefile.objs b/qemu/hw/unicore32/Makefile.objs
deleted file mode 100644
index e0fd62852..000000000
--- a/qemu/hw/unicore32/Makefile.objs
+++ /dev/null
@@ -1,4 +0,0 @@
-# For UniCore32 machines and boards
-
-# PKUnity-v3 SoC and board information
-obj-${CONFIG_PUV3} += puv3.o
diff --git a/qemu/hw/unicore32/puv3.c b/qemu/hw/unicore32/puv3.c
deleted file mode 100644
index 31cd17101..000000000
--- a/qemu/hw/unicore32/puv3.c
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Generic PKUnity SoC machine and board descriptor
- *
- * Copyright (C) 2010-2012 Guan Xuetao
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation, or any later version.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "qemu-common.h"
-#include "ui/console.h"
-#include "elf.h"
-#include "exec/address-spaces.h"
-#include "hw/sysbus.h"
-#include "hw/boards.h"
-#include "hw/loader.h"
-#include "hw/i386/pc.h"
-#include "qemu/error-report.h"
-#include "sysemu/qtest.h"
-
-#undef DEBUG_PUV3
-#include "hw/unicore32/puv3.h"
-
-#define KERNEL_LOAD_ADDR 0x03000000
-#define KERNEL_MAX_SIZE 0x00800000 /* Just a guess */
-
-static void puv3_intc_cpu_handler(void *opaque, int irq, int level)
-{
- UniCore32CPU *cpu = opaque;
- CPUState *cs = CPU(cpu);
-
- assert(irq == 0);
- if (level) {
- cpu_interrupt(cs, CPU_INTERRUPT_HARD);
- } else {
- cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
- }
-}
-
-static void puv3_soc_init(CPUUniCore32State *env)
-{
- qemu_irq cpu_intc, irqs[PUV3_IRQS_NR];
- DeviceState *dev;
- MemoryRegion *i8042 = g_new(MemoryRegion, 1);
- int i;
-
- /* Initialize interrupt controller */
- cpu_intc = qemu_allocate_irq(puv3_intc_cpu_handler,
- uc32_env_get_cpu(env), 0);
- dev = sysbus_create_simple("puv3_intc", PUV3_INTC_BASE, cpu_intc);
- for (i = 0; i < PUV3_IRQS_NR; i++) {
- irqs[i] = qdev_get_gpio_in(dev, i);
- }
-
- /* Initialize minimal necessary devices for kernel booting */
- sysbus_create_simple("puv3_pm", PUV3_PM_BASE, NULL);
- sysbus_create_simple("puv3_dma", PUV3_DMA_BASE, NULL);
- sysbus_create_simple("puv3_ost", PUV3_OST_BASE, irqs[PUV3_IRQS_OST0]);
- sysbus_create_varargs("puv3_gpio", PUV3_GPIO_BASE,
- irqs[PUV3_IRQS_GPIOLOW0], irqs[PUV3_IRQS_GPIOLOW1],
- irqs[PUV3_IRQS_GPIOLOW2], irqs[PUV3_IRQS_GPIOLOW3],
- irqs[PUV3_IRQS_GPIOLOW4], irqs[PUV3_IRQS_GPIOLOW5],
- irqs[PUV3_IRQS_GPIOLOW6], irqs[PUV3_IRQS_GPIOLOW7],
- irqs[PUV3_IRQS_GPIOHIGH], NULL);
-
- /* Keyboard (i8042), mouse disabled for nographic */
- i8042_mm_init(irqs[PUV3_IRQS_PS2_KBD], NULL, i8042, PUV3_REGS_OFFSET, 4);
- memory_region_add_subregion(get_system_memory(), PUV3_PS2_BASE, i8042);
-}
-
-static void puv3_board_init(CPUUniCore32State *env, ram_addr_t ram_size)
-{
- MemoryRegion *ram_memory = g_new(MemoryRegion, 1);
-
- /* SDRAM at address zero. */
- memory_region_init_ram(ram_memory, NULL, "puv3.ram", ram_size,
- &error_fatal);
- vmstate_register_ram_global(ram_memory);
- memory_region_add_subregion(get_system_memory(), 0, ram_memory);
-}
-
-static const GraphicHwOps no_ops;
-
-static void puv3_load_kernel(const char *kernel_filename)
-{
- int size;
-
- if (kernel_filename == NULL && qtest_enabled()) {
- return;
- }
- assert(kernel_filename != NULL);
-
- /* only zImage format supported */
- size = load_image_targphys(kernel_filename, KERNEL_LOAD_ADDR,
- KERNEL_MAX_SIZE);
- if (size < 0) {
- error_report("Load kernel error: '%s'", kernel_filename);
- exit(1);
- }
-
- /* cheat curses that we have a graphic console, only under ocd console */
- graphic_console_init(NULL, 0, &no_ops, NULL);
-}
-
-static void puv3_init(MachineState *machine)
-{
- ram_addr_t ram_size = machine->ram_size;
- const char *cpu_model = machine->cpu_model;
- const char *kernel_filename = machine->kernel_filename;
- const char *initrd_filename = machine->initrd_filename;
- CPUUniCore32State *env;
- UniCore32CPU *cpu;
-
- if (initrd_filename) {
- error_report("Please use kernel built-in initramdisk");
- exit(1);
- }
-
- if (!cpu_model) {
- cpu_model = "UniCore-II";
- }
-
- cpu = uc32_cpu_init(cpu_model);
- if (!cpu) {
- error_report("Unable to find CPU definition");
- exit(1);
- }
- env = &cpu->env;
-
- puv3_soc_init(env);
- puv3_board_init(env, ram_size);
- puv3_load_kernel(kernel_filename);
-}
-
-static void puv3_machine_init(MachineClass *mc)
-{
- mc->desc = "PKUnity Version-3 based on UniCore32";
- mc->init = puv3_init;
- mc->is_default = 1;
-}
-
-DEFINE_MACHINE("puv3", puv3_machine_init)
diff --git a/qemu/hw/usb/Makefile.objs b/qemu/hw/usb/Makefile.objs
deleted file mode 100644
index 2717027d3..000000000
--- a/qemu/hw/usb/Makefile.objs
+++ /dev/null
@@ -1,40 +0,0 @@
-# usb subsystem core
-common-obj-y += core.o combined-packet.o bus.o libhw.o
-common-obj-$(CONFIG_USB) += desc.o desc-msos.o
-
-# usb host adapters
-common-obj-$(CONFIG_USB_UHCI) += hcd-uhci.o
-common-obj-$(CONFIG_USB_OHCI) += hcd-ohci.o
-common-obj-$(CONFIG_USB_EHCI) += hcd-ehci.o hcd-ehci-pci.o
-common-obj-$(CONFIG_USB_EHCI_SYSBUS) += hcd-ehci-sysbus.o
-common-obj-$(CONFIG_USB_XHCI) += hcd-xhci.o
-common-obj-$(CONFIG_USB_MUSB) += hcd-musb.o
-
-obj-$(CONFIG_TUSB6010) += tusb6010.o
-
-# emulated usb devices
-common-obj-$(CONFIG_USB) += dev-hub.o
-common-obj-$(CONFIG_USB) += dev-hid.o
-common-obj-$(CONFIG_USB_TABLET_WACOM) += dev-wacom.o
-common-obj-$(CONFIG_USB_STORAGE_BOT) += dev-storage.o
-common-obj-$(CONFIG_USB_STORAGE_UAS) += dev-uas.o
-common-obj-$(CONFIG_USB_AUDIO) += dev-audio.o
-common-obj-$(CONFIG_USB_SERIAL) += dev-serial.o
-common-obj-$(CONFIG_USB_NETWORK) += dev-network.o
-common-obj-$(CONFIG_USB_BLUETOOTH) += dev-bluetooth.o
-
-ifeq ($(CONFIG_USB_SMARTCARD),y)
-common-obj-y += dev-smartcard-reader.o
-common-obj-$(CONFIG_SMARTCARD) += ccid-card-passthru.o
-common-obj-$(CONFIG_SMARTCARD) += ccid-card-emulated.o
-endif
-
-ifeq ($(CONFIG_POSIX),y)
-common-obj-$(CONFIG_USB_STORAGE_MTP) += dev-mtp.o
-endif
-
-# usb redirection
-common-obj-$(CONFIG_USB_REDIR) += redirect.o quirks.o
-
-# usb pass-through
-common-obj-y += $(patsubst %,host-%.o,$(HOST_USB))
diff --git a/qemu/hw/usb/bus.c b/qemu/hw/usb/bus.c
deleted file mode 100644
index 16c3461d9..000000000
--- a/qemu/hw/usb/bus.c
+++ /dev/null
@@ -1,763 +0,0 @@
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/usb.h"
-#include "hw/qdev.h"
-#include "qapi/error.h"
-#include "qemu/error-report.h"
-#include "sysemu/sysemu.h"
-#include "monitor/monitor.h"
-#include "trace.h"
-#include "qemu/cutils.h"
-
-static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent);
-
-static char *usb_get_dev_path(DeviceState *dev);
-static char *usb_get_fw_dev_path(DeviceState *qdev);
-static void usb_qdev_unrealize(DeviceState *qdev, Error **errp);
-
-static Property usb_props[] = {
- DEFINE_PROP_STRING("port", USBDevice, port_path),
- DEFINE_PROP_STRING("serial", USBDevice, serial),
- DEFINE_PROP_BIT("full-path", USBDevice, flags,
- USB_DEV_FLAG_FULL_PATH, true),
- DEFINE_PROP_BIT("msos-desc", USBDevice, flags,
- USB_DEV_FLAG_MSOS_DESC_ENABLE, true),
- DEFINE_PROP_END_OF_LIST()
-};
-
-static void usb_bus_class_init(ObjectClass *klass, void *data)
-{
- BusClass *k = BUS_CLASS(klass);
- HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
-
- k->print_dev = usb_bus_dev_print;
- k->get_dev_path = usb_get_dev_path;
- k->get_fw_dev_path = usb_get_fw_dev_path;
- hc->unplug = qdev_simple_device_unplug_cb;
-}
-
-static const TypeInfo usb_bus_info = {
- .name = TYPE_USB_BUS,
- .parent = TYPE_BUS,
- .instance_size = sizeof(USBBus),
- .class_init = usb_bus_class_init,
- .interfaces = (InterfaceInfo[]) {
- { TYPE_HOTPLUG_HANDLER },
- { }
- }
-};
-
-static int next_usb_bus = 0;
-static QTAILQ_HEAD(, USBBus) busses = QTAILQ_HEAD_INITIALIZER(busses);
-
-static int usb_device_post_load(void *opaque, int version_id)
-{
- USBDevice *dev = opaque;
-
- if (dev->state == USB_STATE_NOTATTACHED) {
- dev->attached = 0;
- } else {
- dev->attached = 1;
- }
- if (dev->setup_index < 0 ||
- dev->setup_len < 0 ||
- dev->setup_index > dev->setup_len ||
- dev->setup_len > sizeof(dev->data_buf)) {
- return -EINVAL;
- }
- return 0;
-}
-
-const VMStateDescription vmstate_usb_device = {
- .name = "USBDevice",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = usb_device_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(addr, USBDevice),
- VMSTATE_INT32(state, USBDevice),
- VMSTATE_INT32(remote_wakeup, USBDevice),
- VMSTATE_INT32(setup_state, USBDevice),
- VMSTATE_INT32(setup_len, USBDevice),
- VMSTATE_INT32(setup_index, USBDevice),
- VMSTATE_UINT8_ARRAY(setup_buf, USBDevice, 8),
- VMSTATE_END_OF_LIST(),
- }
-};
-
-void usb_bus_new(USBBus *bus, size_t bus_size,
- USBBusOps *ops, DeviceState *host)
-{
- qbus_create_inplace(bus, bus_size, TYPE_USB_BUS, host, NULL);
- qbus_set_bus_hotplug_handler(BUS(bus), &error_abort);
- bus->ops = ops;
- bus->busnr = next_usb_bus++;
- QTAILQ_INIT(&bus->free);
- QTAILQ_INIT(&bus->used);
- QTAILQ_INSERT_TAIL(&busses, bus, next);
-}
-
-void usb_bus_release(USBBus *bus)
-{
- assert(next_usb_bus > 0);
-
- QTAILQ_REMOVE(&busses, bus, next);
-}
-
-USBBus *usb_bus_find(int busnr)
-{
- USBBus *bus;
-
- if (-1 == busnr)
- return QTAILQ_FIRST(&busses);
- QTAILQ_FOREACH(bus, &busses, next) {
- if (bus->busnr == busnr)
- return bus;
- }
- return NULL;
-}
-
-static void usb_device_realize(USBDevice *dev, Error **errp)
-{
- USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
-
- if (klass->realize) {
- klass->realize(dev, errp);
- }
-}
-
-USBDevice *usb_device_find_device(USBDevice *dev, uint8_t addr)
-{
- USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
- if (klass->find_device) {
- return klass->find_device(dev, addr);
- }
- return NULL;
-}
-
-static void usb_device_handle_destroy(USBDevice *dev)
-{
- USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
- if (klass->handle_destroy) {
- klass->handle_destroy(dev);
- }
-}
-
-void usb_device_cancel_packet(USBDevice *dev, USBPacket *p)
-{
- USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
- if (klass->cancel_packet) {
- klass->cancel_packet(dev, p);
- }
-}
-
-void usb_device_handle_attach(USBDevice *dev)
-{
- USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
- if (klass->handle_attach) {
- klass->handle_attach(dev);
- }
-}
-
-void usb_device_handle_reset(USBDevice *dev)
-{
- USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
- if (klass->handle_reset) {
- klass->handle_reset(dev);
- }
-}
-
-void usb_device_handle_control(USBDevice *dev, USBPacket *p, int request,
- int value, int index, int length, uint8_t *data)
-{
- USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
- if (klass->handle_control) {
- klass->handle_control(dev, p, request, value, index, length, data);
- }
-}
-
-void usb_device_handle_data(USBDevice *dev, USBPacket *p)
-{
- USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
- if (klass->handle_data) {
- klass->handle_data(dev, p);
- }
-}
-
-const char *usb_device_get_product_desc(USBDevice *dev)
-{
- USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
- return klass->product_desc;
-}
-
-const USBDesc *usb_device_get_usb_desc(USBDevice *dev)
-{
- USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
- if (dev->usb_desc) {
- return dev->usb_desc;
- }
- return klass->usb_desc;
-}
-
-void usb_device_set_interface(USBDevice *dev, int interface,
- int alt_old, int alt_new)
-{
- USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
- if (klass->set_interface) {
- klass->set_interface(dev, interface, alt_old, alt_new);
- }
-}
-
-void usb_device_flush_ep_queue(USBDevice *dev, USBEndpoint *ep)
-{
- USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
- if (klass->flush_ep_queue) {
- klass->flush_ep_queue(dev, ep);
- }
-}
-
-void usb_device_ep_stopped(USBDevice *dev, USBEndpoint *ep)
-{
- USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
- if (klass->ep_stopped) {
- klass->ep_stopped(dev, ep);
- }
-}
-
-int usb_device_alloc_streams(USBDevice *dev, USBEndpoint **eps, int nr_eps,
- int streams)
-{
- USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
- if (klass->alloc_streams) {
- return klass->alloc_streams(dev, eps, nr_eps, streams);
- }
- return 0;
-}
-
-void usb_device_free_streams(USBDevice *dev, USBEndpoint **eps, int nr_eps)
-{
- USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
- if (klass->free_streams) {
- klass->free_streams(dev, eps, nr_eps);
- }
-}
-
-static void usb_qdev_realize(DeviceState *qdev, Error **errp)
-{
- USBDevice *dev = USB_DEVICE(qdev);
- Error *local_err = NULL;
-
- pstrcpy(dev->product_desc, sizeof(dev->product_desc),
- usb_device_get_product_desc(dev));
- dev->auto_attach = 1;
- QLIST_INIT(&dev->strings);
- usb_ep_init(dev);
-
- usb_claim_port(dev, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- usb_device_realize(dev, &local_err);
- if (local_err) {
- usb_release_port(dev);
- error_propagate(errp, local_err);
- return;
- }
-
- if (dev->auto_attach) {
- usb_device_attach(dev, &local_err);
- if (local_err) {
- usb_qdev_unrealize(qdev, NULL);
- error_propagate(errp, local_err);
- return;
- }
- }
-}
-
-static void usb_qdev_unrealize(DeviceState *qdev, Error **errp)
-{
- USBDevice *dev = USB_DEVICE(qdev);
-
- if (dev->attached) {
- usb_device_detach(dev);
- }
- usb_device_handle_destroy(dev);
- if (dev->port) {
- usb_release_port(dev);
- }
-}
-
-typedef struct LegacyUSBFactory
-{
- const char *name;
- const char *usbdevice_name;
- USBDevice *(*usbdevice_init)(USBBus *bus, const char *params);
-} LegacyUSBFactory;
-
-static GSList *legacy_usb_factory;
-
-void usb_legacy_register(const char *typename, const char *usbdevice_name,
- USBDevice *(*usbdevice_init)(USBBus *bus,
- const char *params))
-{
- if (usbdevice_name) {
- LegacyUSBFactory *f = g_malloc0(sizeof(*f));
- f->name = typename;
- f->usbdevice_name = usbdevice_name;
- f->usbdevice_init = usbdevice_init;
- legacy_usb_factory = g_slist_append(legacy_usb_factory, f);
- }
-}
-
-USBDevice *usb_create(USBBus *bus, const char *name)
-{
- DeviceState *dev;
-
- dev = qdev_create(&bus->qbus, name);
- return USB_DEVICE(dev);
-}
-
-static USBDevice *usb_try_create_simple(USBBus *bus, const char *name,
- Error **errp)
-{
- Error *err = NULL;
- USBDevice *dev;
-
- dev = USB_DEVICE(qdev_try_create(&bus->qbus, name));
- if (!dev) {
- error_setg(errp, "Failed to create USB device '%s'", name);
- return NULL;
- }
- object_property_set_bool(OBJECT(dev), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- error_prepend(errp, "Failed to initialize USB device '%s': ",
- name);
- object_unparent(OBJECT(dev));
- return NULL;
- }
- return dev;
-}
-
-USBDevice *usb_create_simple(USBBus *bus, const char *name)
-{
- return usb_try_create_simple(bus, name, &error_abort);
-}
-
-static void usb_fill_port(USBPort *port, void *opaque, int index,
- USBPortOps *ops, int speedmask)
-{
- port->opaque = opaque;
- port->index = index;
- port->ops = ops;
- port->speedmask = speedmask;
- usb_port_location(port, NULL, index + 1);
-}
-
-void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index,
- USBPortOps *ops, int speedmask)
-{
- usb_fill_port(port, opaque, index, ops, speedmask);
- QTAILQ_INSERT_TAIL(&bus->free, port, next);
- bus->nfree++;
-}
-
-void usb_register_companion(const char *masterbus, USBPort *ports[],
- uint32_t portcount, uint32_t firstport,
- void *opaque, USBPortOps *ops, int speedmask,
- Error **errp)
-{
- USBBus *bus;
- int i;
-
- QTAILQ_FOREACH(bus, &busses, next) {
- if (strcmp(bus->qbus.name, masterbus) == 0) {
- break;
- }
- }
-
- if (!bus) {
- error_setg(errp, "USB bus '%s' not found", masterbus);
- return;
- }
- if (!bus->ops->register_companion) {
- error_setg(errp, "Can't use USB bus '%s' as masterbus,"
- " it doesn't support companion controllers",
- masterbus);
- return;
- }
-
- for (i = 0; i < portcount; i++) {
- usb_fill_port(ports[i], opaque, i, ops, speedmask);
- }
-
- bus->ops->register_companion(bus, ports, portcount, firstport, errp);
-}
-
-void usb_port_location(USBPort *downstream, USBPort *upstream, int portnr)
-{
- if (upstream) {
- snprintf(downstream->path, sizeof(downstream->path), "%s.%d",
- upstream->path, portnr);
- downstream->hubcount = upstream->hubcount + 1;
- } else {
- snprintf(downstream->path, sizeof(downstream->path), "%d", portnr);
- downstream->hubcount = 0;
- }
-}
-
-void usb_unregister_port(USBBus *bus, USBPort *port)
-{
- if (port->dev) {
- object_unparent(OBJECT(port->dev));
- }
- QTAILQ_REMOVE(&bus->free, port, next);
- bus->nfree--;
-}
-
-void usb_claim_port(USBDevice *dev, Error **errp)
-{
- USBBus *bus = usb_bus_from_device(dev);
- USBPort *port;
-
- assert(dev->port == NULL);
-
- if (dev->port_path) {
- QTAILQ_FOREACH(port, &bus->free, next) {
- if (strcmp(port->path, dev->port_path) == 0) {
- break;
- }
- }
- if (port == NULL) {
- error_setg(errp, "usb port %s (bus %s) not found (in use?)",
- dev->port_path, bus->qbus.name);
- return;
- }
- } else {
- if (bus->nfree == 1 && strcmp(object_get_typename(OBJECT(dev)), "usb-hub") != 0) {
- /* Create a new hub and chain it on */
- usb_try_create_simple(bus, "usb-hub", NULL);
- }
- if (bus->nfree == 0) {
- error_setg(errp, "tried to attach usb device %s to a bus "
- "with no free ports", dev->product_desc);
- return;
- }
- port = QTAILQ_FIRST(&bus->free);
- }
- trace_usb_port_claim(bus->busnr, port->path);
-
- QTAILQ_REMOVE(&bus->free, port, next);
- bus->nfree--;
-
- dev->port = port;
- port->dev = dev;
-
- QTAILQ_INSERT_TAIL(&bus->used, port, next);
- bus->nused++;
-}
-
-void usb_release_port(USBDevice *dev)
-{
- USBBus *bus = usb_bus_from_device(dev);
- USBPort *port = dev->port;
-
- assert(port != NULL);
- trace_usb_port_release(bus->busnr, port->path);
-
- QTAILQ_REMOVE(&bus->used, port, next);
- bus->nused--;
-
- dev->port = NULL;
- port->dev = NULL;
-
- QTAILQ_INSERT_TAIL(&bus->free, port, next);
- bus->nfree++;
-}
-
-static void usb_mask_to_str(char *dest, size_t size,
- unsigned int speedmask)
-{
- static const struct {
- unsigned int mask;
- const char *name;
- } speeds[] = {
- { .mask = USB_SPEED_MASK_FULL, .name = "full" },
- { .mask = USB_SPEED_MASK_HIGH, .name = "high" },
- { .mask = USB_SPEED_MASK_SUPER, .name = "super" },
- };
- int i, pos = 0;
-
- for (i = 0; i < ARRAY_SIZE(speeds); i++) {
- if (speeds[i].mask & speedmask) {
- pos += snprintf(dest + pos, size - pos, "%s%s",
- pos ? "+" : "",
- speeds[i].name);
- }
- }
-}
-
-void usb_check_attach(USBDevice *dev, Error **errp)
-{
- USBBus *bus = usb_bus_from_device(dev);
- USBPort *port = dev->port;
- char devspeed[32], portspeed[32];
-
- assert(port != NULL);
- assert(!dev->attached);
- usb_mask_to_str(devspeed, sizeof(devspeed), dev->speedmask);
- usb_mask_to_str(portspeed, sizeof(portspeed), port->speedmask);
- trace_usb_port_attach(bus->busnr, port->path,
- devspeed, portspeed);
-
- if (!(port->speedmask & dev->speedmask)) {
- error_setg(errp, "Warning: speed mismatch trying to attach"
- " usb device \"%s\" (%s speed)"
- " to bus \"%s\", port \"%s\" (%s speed)",
- dev->product_desc, devspeed,
- bus->qbus.name, port->path, portspeed);
- return;
- }
-}
-
-void usb_device_attach(USBDevice *dev, Error **errp)
-{
- USBPort *port = dev->port;
- Error *local_err = NULL;
-
- usb_check_attach(dev, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- dev->attached++;
- usb_attach(port);
-}
-
-int usb_device_detach(USBDevice *dev)
-{
- USBBus *bus = usb_bus_from_device(dev);
- USBPort *port = dev->port;
-
- assert(port != NULL);
- assert(dev->attached);
- trace_usb_port_detach(bus->busnr, port->path);
-
- usb_detach(port);
- dev->attached--;
- return 0;
-}
-
-int usb_device_delete_addr(int busnr, int addr)
-{
- USBBus *bus;
- USBPort *port;
- USBDevice *dev;
-
- bus = usb_bus_find(busnr);
- if (!bus)
- return -1;
-
- QTAILQ_FOREACH(port, &bus->used, next) {
- if (port->dev->addr == addr)
- break;
- }
- if (!port)
- return -1;
- dev = port->dev;
-
- object_unparent(OBJECT(dev));
- return 0;
-}
-
-static const char *usb_speed(unsigned int speed)
-{
- static const char *txt[] = {
- [ USB_SPEED_LOW ] = "1.5",
- [ USB_SPEED_FULL ] = "12",
- [ USB_SPEED_HIGH ] = "480",
- [ USB_SPEED_SUPER ] = "5000",
- };
- if (speed >= ARRAY_SIZE(txt))
- return "?";
- return txt[speed];
-}
-
-static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
-{
- USBDevice *dev = USB_DEVICE(qdev);
- USBBus *bus = usb_bus_from_device(dev);
-
- monitor_printf(mon, "%*saddr %d.%d, port %s, speed %s, name %s%s\n",
- indent, "", bus->busnr, dev->addr,
- dev->port ? dev->port->path : "-",
- usb_speed(dev->speed), dev->product_desc,
- dev->attached ? ", attached" : "");
-}
-
-static char *usb_get_dev_path(DeviceState *qdev)
-{
- USBDevice *dev = USB_DEVICE(qdev);
- DeviceState *hcd = qdev->parent_bus->parent;
- char *id = NULL;
-
- if (dev->flags & (1 << USB_DEV_FLAG_FULL_PATH)) {
- id = qdev_get_dev_path(hcd);
- }
- if (id) {
- char *ret = g_strdup_printf("%s/%s", id, dev->port->path);
- g_free(id);
- return ret;
- } else {
- return g_strdup(dev->port->path);
- }
-}
-
-static char *usb_get_fw_dev_path(DeviceState *qdev)
-{
- USBDevice *dev = USB_DEVICE(qdev);
- char *fw_path, *in;
- ssize_t pos = 0, fw_len;
- long nr;
-
- fw_len = 32 + strlen(dev->port->path) * 6;
- fw_path = g_malloc(fw_len);
- in = dev->port->path;
- while (fw_len - pos > 0) {
- nr = strtol(in, &in, 10);
- if (in[0] == '.') {
- /* some hub between root port and device */
- pos += snprintf(fw_path + pos, fw_len - pos, "hub@%lx/", nr);
- in++;
- } else {
- /* the device itself */
- pos += snprintf(fw_path + pos, fw_len - pos, "%s@%lx",
- qdev_fw_name(qdev), nr);
- break;
- }
- }
- return fw_path;
-}
-
-void hmp_info_usb(Monitor *mon, const QDict *qdict)
-{
- USBBus *bus;
- USBDevice *dev;
- USBPort *port;
-
- if (QTAILQ_EMPTY(&busses)) {
- monitor_printf(mon, "USB support not enabled\n");
- return;
- }
-
- QTAILQ_FOREACH(bus, &busses, next) {
- QTAILQ_FOREACH(port, &bus->used, next) {
- dev = port->dev;
- if (!dev)
- continue;
- monitor_printf(mon, " Device %d.%d, Port %s, Speed %s Mb/s, "
- "Product %s%s%s\n",
- bus->busnr, dev->addr, port->path,
- usb_speed(dev->speed), dev->product_desc,
- dev->qdev.id ? ", ID: " : "",
- dev->qdev.id ?: "");
- }
- }
-}
-
-/* handle legacy -usbdevice cmd line option */
-USBDevice *usbdevice_create(const char *cmdline)
-{
- USBBus *bus = usb_bus_find(-1 /* any */);
- LegacyUSBFactory *f = NULL;
- Error *err = NULL;
- GSList *i;
- char driver[32];
- const char *params;
- int len;
- USBDevice *dev;
-
- params = strchr(cmdline,':');
- if (params) {
- params++;
- len = params - cmdline;
- if (len > sizeof(driver))
- len = sizeof(driver);
- pstrcpy(driver, len, cmdline);
- } else {
- params = "";
- pstrcpy(driver, sizeof(driver), cmdline);
- }
-
- for (i = legacy_usb_factory; i; i = i->next) {
- f = i->data;
- if (strcmp(f->usbdevice_name, driver) == 0) {
- break;
- }
- }
- if (i == NULL) {
-#if 0
- /* no error because some drivers are not converted (yet) */
- error_report("usbdevice %s not found", driver);
-#endif
- return NULL;
- }
-
- if (!bus) {
- error_report("Error: no usb bus to attach usbdevice %s, "
- "please try -machine usb=on and check that "
- "the machine model supports USB", driver);
- return NULL;
- }
-
- if (f->usbdevice_init) {
- dev = f->usbdevice_init(bus, params);
- } else {
- if (*params) {
- error_report("usbdevice %s accepts no params", driver);
- return NULL;
- }
- dev = usb_create(bus, f->name);
- }
- if (!dev) {
- error_report("Failed to create USB device '%s'", f->name);
- return NULL;
- }
- object_property_set_bool(OBJECT(dev), true, "realized", &err);
- if (err) {
- error_reportf_err(err, "Failed to initialize USB device '%s': ",
- f->name);
- object_unparent(OBJECT(dev));
- return NULL;
- }
- return dev;
-}
-
-static void usb_device_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *k = DEVICE_CLASS(klass);
- k->bus_type = TYPE_USB_BUS;
- k->realize = usb_qdev_realize;
- k->unrealize = usb_qdev_unrealize;
- k->props = usb_props;
-}
-
-static const TypeInfo usb_device_type_info = {
- .name = TYPE_USB_DEVICE,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(USBDevice),
- .abstract = true,
- .class_size = sizeof(USBDeviceClass),
- .class_init = usb_device_class_init,
-};
-
-static void usb_register_types(void)
-{
- type_register_static(&usb_bus_info);
- type_register_static(&usb_device_type_info);
-}
-
-type_init(usb_register_types)
diff --git a/qemu/hw/usb/ccid-card-emulated.c b/qemu/hw/usb/ccid-card-emulated.c
deleted file mode 100644
index 3213f9f8a..000000000
--- a/qemu/hw/usb/ccid-card-emulated.c
+++ /dev/null
@@ -1,606 +0,0 @@
-/*
- * CCID Card Device. Emulated card.
- *
- * Copyright (c) 2011 Red Hat.
- * Written by Alon Levy.
- *
- * This code is licensed under the GNU LGPL, version 2 or later.
- */
-
-/*
- * It can be used to provide access to the local hardware in a non exclusive
- * way, or it can use certificates. It requires the usb-ccid bus.
- *
- * Usage 1: standard, mirror hardware reader+card:
- * qemu .. -usb -device usb-ccid -device ccid-card-emulated
- *
- * Usage 2: use certificates, no hardware required
- * one time: create the certificates:
- * for i in 1 2 3; do
- * certutil -d /etc/pki/nssdb -x -t "CT,CT,CT" -S -s "CN=user$i" -n user$i
- * done
- * qemu .. -usb -device usb-ccid \
- * -device ccid-card-emulated,cert1=user1,cert2=user2,cert3=user3
- *
- * If you use a non default db for the certificates you can specify it using
- * the db parameter.
- */
-
-#include "qemu/osdep.h"
-#include <eventt.h>
-#include <vevent.h>
-#include <vreader.h>
-#include <vcard_emul.h>
-
-#include "qemu/thread.h"
-#include "sysemu/char.h"
-#include "ccid.h"
-
-#define DPRINTF(card, lvl, fmt, ...) \
-do {\
- if (lvl <= card->debug) {\
- printf("ccid-card-emul: %s: " fmt , __func__, ## __VA_ARGS__);\
- } \
-} while (0)
-
-
-#define TYPE_EMULATED_CCID "ccid-card-emulated"
-#define EMULATED_CCID_CARD(obj) \
- OBJECT_CHECK(EmulatedState, (obj), TYPE_EMULATED_CCID)
-
-#define BACKEND_NSS_EMULATED_NAME "nss-emulated"
-#define BACKEND_CERTIFICATES_NAME "certificates"
-
-enum {
- BACKEND_NSS_EMULATED = 1,
- BACKEND_CERTIFICATES
-};
-
-#define DEFAULT_BACKEND BACKEND_NSS_EMULATED
-
-typedef struct EmulatedState EmulatedState;
-
-enum {
- EMUL_READER_INSERT = 0,
- EMUL_READER_REMOVE,
- EMUL_CARD_INSERT,
- EMUL_CARD_REMOVE,
- EMUL_GUEST_APDU,
- EMUL_RESPONSE_APDU,
- EMUL_ERROR,
-};
-
-static const char *emul_event_to_string(uint32_t emul_event)
-{
- switch (emul_event) {
- case EMUL_READER_INSERT:
- return "EMUL_READER_INSERT";
- case EMUL_READER_REMOVE:
- return "EMUL_READER_REMOVE";
- case EMUL_CARD_INSERT:
- return "EMUL_CARD_INSERT";
- case EMUL_CARD_REMOVE:
- return "EMUL_CARD_REMOVE";
- case EMUL_GUEST_APDU:
- return "EMUL_GUEST_APDU";
- case EMUL_RESPONSE_APDU:
- return "EMUL_RESPONSE_APDU";
- case EMUL_ERROR:
- return "EMUL_ERROR";
- }
- return "UNKNOWN";
-}
-
-typedef struct EmulEvent {
- QSIMPLEQ_ENTRY(EmulEvent) entry;
- union {
- struct {
- uint32_t type;
- } gen;
- struct {
- uint32_t type;
- uint64_t code;
- } error;
- struct {
- uint32_t type;
- uint32_t len;
- uint8_t data[];
- } data;
- } p;
-} EmulEvent;
-
-#define MAX_ATR_SIZE 40
-struct EmulatedState {
- CCIDCardState base;
- uint8_t debug;
- char *backend_str;
- uint32_t backend;
- char *cert1;
- char *cert2;
- char *cert3;
- char *db;
- uint8_t atr[MAX_ATR_SIZE];
- uint8_t atr_length;
- QSIMPLEQ_HEAD(event_list, EmulEvent) event_list;
- QemuMutex event_list_mutex;
- QemuThread event_thread_id;
- VReader *reader;
- QSIMPLEQ_HEAD(guest_apdu_list, EmulEvent) guest_apdu_list;
- QemuMutex vreader_mutex; /* and guest_apdu_list mutex */
- QemuMutex handle_apdu_mutex;
- QemuCond handle_apdu_cond;
- EventNotifier notifier;
- int quit_apdu_thread;
- QemuThread apdu_thread_id;
-};
-
-static void emulated_apdu_from_guest(CCIDCardState *base,
- const uint8_t *apdu, uint32_t len)
-{
- EmulatedState *card = EMULATED_CCID_CARD(base);
- EmulEvent *event = (EmulEvent *)g_malloc(sizeof(EmulEvent) + len);
-
- assert(event);
- event->p.data.type = EMUL_GUEST_APDU;
- event->p.data.len = len;
- memcpy(event->p.data.data, apdu, len);
- qemu_mutex_lock(&card->vreader_mutex);
- QSIMPLEQ_INSERT_TAIL(&card->guest_apdu_list, event, entry);
- qemu_mutex_unlock(&card->vreader_mutex);
- qemu_mutex_lock(&card->handle_apdu_mutex);
- qemu_cond_signal(&card->handle_apdu_cond);
- qemu_mutex_unlock(&card->handle_apdu_mutex);
-}
-
-static const uint8_t *emulated_get_atr(CCIDCardState *base, uint32_t *len)
-{
- EmulatedState *card = EMULATED_CCID_CARD(base);
-
- *len = card->atr_length;
- return card->atr;
-}
-
-static void emulated_push_event(EmulatedState *card, EmulEvent *event)
-{
- qemu_mutex_lock(&card->event_list_mutex);
- QSIMPLEQ_INSERT_TAIL(&(card->event_list), event, entry);
- qemu_mutex_unlock(&card->event_list_mutex);
- event_notifier_set(&card->notifier);
-}
-
-static void emulated_push_type(EmulatedState *card, uint32_t type)
-{
- EmulEvent *event = g_new(EmulEvent, 1);
-
- assert(event);
- event->p.gen.type = type;
- emulated_push_event(card, event);
-}
-
-static void emulated_push_error(EmulatedState *card, uint64_t code)
-{
- EmulEvent *event = g_new(EmulEvent, 1);
-
- assert(event);
- event->p.error.type = EMUL_ERROR;
- event->p.error.code = code;
- emulated_push_event(card, event);
-}
-
-static void emulated_push_data_type(EmulatedState *card, uint32_t type,
- const uint8_t *data, uint32_t len)
-{
- EmulEvent *event = (EmulEvent *)g_malloc(sizeof(EmulEvent) + len);
-
- assert(event);
- event->p.data.type = type;
- event->p.data.len = len;
- memcpy(event->p.data.data, data, len);
- emulated_push_event(card, event);
-}
-
-static void emulated_push_reader_insert(EmulatedState *card)
-{
- emulated_push_type(card, EMUL_READER_INSERT);
-}
-
-static void emulated_push_reader_remove(EmulatedState *card)
-{
- emulated_push_type(card, EMUL_READER_REMOVE);
-}
-
-static void emulated_push_card_insert(EmulatedState *card,
- const uint8_t *atr, uint32_t len)
-{
- emulated_push_data_type(card, EMUL_CARD_INSERT, atr, len);
-}
-
-static void emulated_push_card_remove(EmulatedState *card)
-{
- emulated_push_type(card, EMUL_CARD_REMOVE);
-}
-
-static void emulated_push_response_apdu(EmulatedState *card,
- const uint8_t *apdu, uint32_t len)
-{
- emulated_push_data_type(card, EMUL_RESPONSE_APDU, apdu, len);
-}
-
-#define APDU_BUF_SIZE 270
-static void *handle_apdu_thread(void* arg)
-{
- EmulatedState *card = arg;
- uint8_t recv_data[APDU_BUF_SIZE];
- int recv_len;
- VReaderStatus reader_status;
- EmulEvent *event;
-
- while (1) {
- qemu_mutex_lock(&card->handle_apdu_mutex);
- qemu_cond_wait(&card->handle_apdu_cond, &card->handle_apdu_mutex);
- qemu_mutex_unlock(&card->handle_apdu_mutex);
- if (card->quit_apdu_thread) {
- card->quit_apdu_thread = 0; /* debugging */
- break;
- }
- qemu_mutex_lock(&card->vreader_mutex);
- while (!QSIMPLEQ_EMPTY(&card->guest_apdu_list)) {
- event = QSIMPLEQ_FIRST(&card->guest_apdu_list);
- assert((unsigned long)event > 1000);
- QSIMPLEQ_REMOVE_HEAD(&card->guest_apdu_list, entry);
- if (event->p.data.type != EMUL_GUEST_APDU) {
- DPRINTF(card, 1, "unexpected message in handle_apdu_thread\n");
- g_free(event);
- continue;
- }
- if (card->reader == NULL) {
- DPRINTF(card, 1, "reader is NULL\n");
- g_free(event);
- continue;
- }
- recv_len = sizeof(recv_data);
- reader_status = vreader_xfr_bytes(card->reader,
- event->p.data.data, event->p.data.len,
- recv_data, &recv_len);
- DPRINTF(card, 2, "got back apdu of length %d\n", recv_len);
- if (reader_status == VREADER_OK) {
- emulated_push_response_apdu(card, recv_data, recv_len);
- } else {
- emulated_push_error(card, reader_status);
- }
- g_free(event);
- }
- qemu_mutex_unlock(&card->vreader_mutex);
- }
- return NULL;
-}
-
-static void *event_thread(void *arg)
-{
- int atr_len = MAX_ATR_SIZE;
- uint8_t atr[MAX_ATR_SIZE];
- VEvent *event = NULL;
- EmulatedState *card = arg;
-
- while (1) {
- const char *reader_name;
-
- event = vevent_wait_next_vevent();
- if (event == NULL || event->type == VEVENT_LAST) {
- break;
- }
- if (event->type != VEVENT_READER_INSERT) {
- if (card->reader == NULL && event->reader != NULL) {
- /* Happens after device_add followed by card remove or insert.
- * XXX: create synthetic add_reader events if vcard_emul_init
- * already called, which happens if device_del and device_add
- * are called */
- card->reader = vreader_reference(event->reader);
- } else {
- if (event->reader != card->reader) {
- fprintf(stderr,
- "ERROR: wrong reader: quiting event_thread\n");
- break;
- }
- }
- }
- switch (event->type) {
- case VEVENT_READER_INSERT:
- /* TODO: take a specific reader. i.e. track which reader
- * we are seeing here, check it is the one we want (the first,
- * or by a particular name), and ignore if we don't want it.
- */
- reader_name = vreader_get_name(event->reader);
- if (card->reader != NULL) {
- DPRINTF(card, 2, "READER INSERT - replacing %s with %s\n",
- vreader_get_name(card->reader), reader_name);
- qemu_mutex_lock(&card->vreader_mutex);
- vreader_free(card->reader);
- qemu_mutex_unlock(&card->vreader_mutex);
- emulated_push_reader_remove(card);
- }
- qemu_mutex_lock(&card->vreader_mutex);
- DPRINTF(card, 2, "READER INSERT %s\n", reader_name);
- card->reader = vreader_reference(event->reader);
- qemu_mutex_unlock(&card->vreader_mutex);
- emulated_push_reader_insert(card);
- break;
- case VEVENT_READER_REMOVE:
- DPRINTF(card, 2, " READER REMOVE: %s\n",
- vreader_get_name(event->reader));
- qemu_mutex_lock(&card->vreader_mutex);
- vreader_free(card->reader);
- card->reader = NULL;
- qemu_mutex_unlock(&card->vreader_mutex);
- emulated_push_reader_remove(card);
- break;
- case VEVENT_CARD_INSERT:
- /* get the ATR (intended as a response to a power on from the
- * reader */
- atr_len = MAX_ATR_SIZE;
- vreader_power_on(event->reader, atr, &atr_len);
- card->atr_length = (uint8_t)atr_len;
- DPRINTF(card, 2, " CARD INSERT\n");
- emulated_push_card_insert(card, atr, atr_len);
- break;
- case VEVENT_CARD_REMOVE:
- DPRINTF(card, 2, " CARD REMOVE\n");
- emulated_push_card_remove(card);
- break;
- case VEVENT_LAST: /* quit */
- vevent_delete(event);
- return NULL;
- break;
- default:
- break;
- }
- vevent_delete(event);
- }
- return NULL;
-}
-
-static void card_event_handler(EventNotifier *notifier)
-{
- EmulatedState *card = container_of(notifier, EmulatedState, notifier);
- EmulEvent *event, *next;
-
- event_notifier_test_and_clear(&card->notifier);
- qemu_mutex_lock(&card->event_list_mutex);
- QSIMPLEQ_FOREACH_SAFE(event, &card->event_list, entry, next) {
- DPRINTF(card, 2, "event %s\n", emul_event_to_string(event->p.gen.type));
- switch (event->p.gen.type) {
- case EMUL_RESPONSE_APDU:
- ccid_card_send_apdu_to_guest(&card->base, event->p.data.data,
- event->p.data.len);
- break;
- case EMUL_READER_INSERT:
- ccid_card_ccid_attach(&card->base);
- break;
- case EMUL_READER_REMOVE:
- ccid_card_ccid_detach(&card->base);
- break;
- case EMUL_CARD_INSERT:
- assert(event->p.data.len <= MAX_ATR_SIZE);
- card->atr_length = event->p.data.len;
- memcpy(card->atr, event->p.data.data, card->atr_length);
- ccid_card_card_inserted(&card->base);
- break;
- case EMUL_CARD_REMOVE:
- ccid_card_card_removed(&card->base);
- break;
- case EMUL_ERROR:
- ccid_card_card_error(&card->base, event->p.error.code);
- break;
- default:
- DPRINTF(card, 2, "unexpected event\n");
- break;
- }
- g_free(event);
- }
- QSIMPLEQ_INIT(&card->event_list);
- qemu_mutex_unlock(&card->event_list_mutex);
-}
-
-static int init_event_notifier(EmulatedState *card)
-{
- if (event_notifier_init(&card->notifier, false) < 0) {
- DPRINTF(card, 2, "event notifier creation failed\n");
- return -1;
- }
- event_notifier_set_handler(&card->notifier, false, card_event_handler);
- return 0;
-}
-
-#define CERTIFICATES_DEFAULT_DB "/etc/pki/nssdb"
-#define CERTIFICATES_ARGS_TEMPLATE\
- "db=\"%s\" use_hw=no soft=(,Virtual Reader,CAC,,%s,%s,%s)"
-
-static int wrap_vcard_emul_init(VCardEmulOptions *options)
-{
- static int called;
- static int options_was_null;
-
- if (called) {
- if ((options == NULL) != options_was_null) {
- printf("%s: warning: running emulated with certificates"
- " and emulated side by side is not supported\n",
- __func__);
- return VCARD_EMUL_FAIL;
- }
- vcard_emul_replay_insertion_events();
- return VCARD_EMUL_OK;
- }
- options_was_null = (options == NULL);
- called = 1;
- return vcard_emul_init(options);
-}
-
-static int emulated_initialize_vcard_from_certificates(EmulatedState *card)
-{
- char emul_args[200];
- VCardEmulOptions *options = NULL;
-
- snprintf(emul_args, sizeof(emul_args) - 1, CERTIFICATES_ARGS_TEMPLATE,
- card->db ? card->db : CERTIFICATES_DEFAULT_DB,
- card->cert1, card->cert2, card->cert3);
- options = vcard_emul_options(emul_args);
- if (options == NULL) {
- printf("%s: warning: not using certificates due to"
- " initialization error\n", __func__);
- }
- return wrap_vcard_emul_init(options);
-}
-
-typedef struct EnumTable {
- const char *name;
- uint32_t value;
-} EnumTable;
-
-static const EnumTable backend_enum_table[] = {
- {BACKEND_NSS_EMULATED_NAME, BACKEND_NSS_EMULATED},
- {BACKEND_CERTIFICATES_NAME, BACKEND_CERTIFICATES},
- {NULL, 0},
-};
-
-static uint32_t parse_enumeration(char *str,
- const EnumTable *table, uint32_t not_found_value)
-{
- uint32_t ret = not_found_value;
-
- if (str == NULL)
- return 0;
-
- while (table->name != NULL) {
- if (strcmp(table->name, str) == 0) {
- ret = table->value;
- break;
- }
- table++;
- }
- return ret;
-}
-
-static int emulated_initfn(CCIDCardState *base)
-{
- EmulatedState *card = EMULATED_CCID_CARD(base);
- VCardEmulError ret;
- const EnumTable *ptable;
-
- QSIMPLEQ_INIT(&card->event_list);
- QSIMPLEQ_INIT(&card->guest_apdu_list);
- qemu_mutex_init(&card->event_list_mutex);
- qemu_mutex_init(&card->vreader_mutex);
- qemu_mutex_init(&card->handle_apdu_mutex);
- qemu_cond_init(&card->handle_apdu_cond);
- card->reader = NULL;
- card->quit_apdu_thread = 0;
- if (init_event_notifier(card) < 0) {
- return -1;
- }
-
- card->backend = 0;
- if (card->backend_str) {
- card->backend = parse_enumeration(card->backend_str,
- backend_enum_table, 0);
- }
-
- if (card->backend == 0) {
- printf("backend must be one of:\n");
- for (ptable = backend_enum_table; ptable->name != NULL; ++ptable) {
- printf("%s\n", ptable->name);
- }
- return -1;
- }
-
- /* TODO: a passthru backened that works on local machine. third card type?*/
- if (card->backend == BACKEND_CERTIFICATES) {
- if (card->cert1 != NULL && card->cert2 != NULL && card->cert3 != NULL) {
- ret = emulated_initialize_vcard_from_certificates(card);
- } else {
- printf("%s: you must provide all three certs for"
- " certificates backend\n", TYPE_EMULATED_CCID);
- return -1;
- }
- } else {
- if (card->backend != BACKEND_NSS_EMULATED) {
- printf("%s: bad backend specified. The options are:\n%s (default),"
- " %s.\n", TYPE_EMULATED_CCID, BACKEND_NSS_EMULATED_NAME,
- BACKEND_CERTIFICATES_NAME);
- return -1;
- }
- if (card->cert1 != NULL || card->cert2 != NULL || card->cert3 != NULL) {
- printf("%s: unexpected cert parameters to nss emulated backend\n",
- TYPE_EMULATED_CCID);
- return -1;
- }
- /* default to mirroring the local hardware readers */
- ret = wrap_vcard_emul_init(NULL);
- }
- if (ret != VCARD_EMUL_OK) {
- printf("%s: failed to initialize vcard\n", TYPE_EMULATED_CCID);
- return -1;
- }
- qemu_thread_create(&card->event_thread_id, "ccid/event", event_thread,
- card, QEMU_THREAD_JOINABLE);
- qemu_thread_create(&card->apdu_thread_id, "ccid/apdu", handle_apdu_thread,
- card, QEMU_THREAD_JOINABLE);
- return 0;
-}
-
-static int emulated_exitfn(CCIDCardState *base)
-{
- EmulatedState *card = EMULATED_CCID_CARD(base);
- VEvent *vevent = vevent_new(VEVENT_LAST, NULL, NULL);
-
- vevent_queue_vevent(vevent); /* stop vevent thread */
- qemu_thread_join(&card->event_thread_id);
-
- card->quit_apdu_thread = 1; /* stop handle_apdu thread */
- qemu_cond_signal(&card->handle_apdu_cond);
- qemu_thread_join(&card->apdu_thread_id);
-
- /* threads exited, can destroy all condvars/mutexes */
- qemu_cond_destroy(&card->handle_apdu_cond);
- qemu_mutex_destroy(&card->handle_apdu_mutex);
- qemu_mutex_destroy(&card->vreader_mutex);
- qemu_mutex_destroy(&card->event_list_mutex);
- return 0;
-}
-
-static Property emulated_card_properties[] = {
- DEFINE_PROP_STRING("backend", EmulatedState, backend_str),
- DEFINE_PROP_STRING("cert1", EmulatedState, cert1),
- DEFINE_PROP_STRING("cert2", EmulatedState, cert2),
- DEFINE_PROP_STRING("cert3", EmulatedState, cert3),
- DEFINE_PROP_STRING("db", EmulatedState, db),
- DEFINE_PROP_UINT8("debug", EmulatedState, debug, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void emulated_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- CCIDCardClass *cc = CCID_CARD_CLASS(klass);
-
- cc->initfn = emulated_initfn;
- cc->exitfn = emulated_exitfn;
- cc->get_atr = emulated_get_atr;
- cc->apdu_from_guest = emulated_apdu_from_guest;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
- dc->desc = "emulated smartcard";
- dc->props = emulated_card_properties;
-}
-
-static const TypeInfo emulated_card_info = {
- .name = TYPE_EMULATED_CCID,
- .parent = TYPE_CCID_CARD,
- .instance_size = sizeof(EmulatedState),
- .class_init = emulated_class_initfn,
-};
-
-static void ccid_card_emulated_register_types(void)
-{
- type_register_static(&emulated_card_info);
-}
-
-type_init(ccid_card_emulated_register_types)
diff --git a/qemu/hw/usb/ccid-card-passthru.c b/qemu/hw/usb/ccid-card-passthru.c
deleted file mode 100644
index c0e90e501..000000000
--- a/qemu/hw/usb/ccid-card-passthru.c
+++ /dev/null
@@ -1,416 +0,0 @@
-/*
- * CCID Passthru Card Device emulation
- *
- * Copyright (c) 2011 Red Hat.
- * Written by Alon Levy.
- *
- * This work is licensed under the terms of the GNU GPL, version 2.1 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "sysemu/char.h"
-#include "qemu/error-report.h"
-#include "qemu/sockets.h"
-#include "ccid.h"
-#include "cacard/vscard_common.h"
-
-#define DPRINTF(card, lvl, fmt, ...) \
-do { \
- if (lvl <= card->debug) { \
- printf("ccid-card-passthru: " fmt , ## __VA_ARGS__); \
- } \
-} while (0)
-
-#define D_WARN 1
-#define D_INFO 2
-#define D_MORE_INFO 3
-#define D_VERBOSE 4
-
-/* TODO: do we still need this? */
-static const uint8_t DEFAULT_ATR[] = {
-/*
- * From some example somewhere
- * 0x3B, 0xB0, 0x18, 0x00, 0xD1, 0x81, 0x05, 0xB1, 0x40, 0x38, 0x1F, 0x03, 0x28
- */
-
-/* From an Athena smart card */
- 0x3B, 0xD5, 0x18, 0xFF, 0x80, 0x91, 0xFE, 0x1F, 0xC3, 0x80, 0x73, 0xC8, 0x21,
- 0x13, 0x08
-};
-
-#define VSCARD_IN_SIZE 65536
-
-/* maximum size of ATR - from 7816-3 */
-#define MAX_ATR_SIZE 40
-
-typedef struct PassthruState PassthruState;
-
-struct PassthruState {
- CCIDCardState base;
- CharDriverState *cs;
- uint8_t vscard_in_data[VSCARD_IN_SIZE];
- uint32_t vscard_in_pos;
- uint32_t vscard_in_hdr;
- uint8_t atr[MAX_ATR_SIZE];
- uint8_t atr_length;
- uint8_t debug;
-};
-
-#define TYPE_CCID_PASSTHRU "ccid-card-passthru"
-#define PASSTHRU_CCID_CARD(obj) \
- OBJECT_CHECK(PassthruState, (obj), TYPE_CCID_PASSTHRU)
-
-/*
- * VSCard protocol over chardev
- * This code should not depend on the card type.
- */
-
-static void ccid_card_vscard_send_msg(PassthruState *s,
- VSCMsgType type, uint32_t reader_id,
- const uint8_t *payload, uint32_t length)
-{
- VSCMsgHeader scr_msg_header;
-
- scr_msg_header.type = htonl(type);
- scr_msg_header.reader_id = htonl(reader_id);
- scr_msg_header.length = htonl(length);
- qemu_chr_fe_write(s->cs, (uint8_t *)&scr_msg_header, sizeof(VSCMsgHeader));
- qemu_chr_fe_write(s->cs, payload, length);
-}
-
-static void ccid_card_vscard_send_apdu(PassthruState *s,
- const uint8_t *apdu, uint32_t length)
-{
- ccid_card_vscard_send_msg(
- s, VSC_APDU, VSCARD_MINIMAL_READER_ID, apdu, length);
-}
-
-static void ccid_card_vscard_send_error(PassthruState *s,
- uint32_t reader_id, VSCErrorCode code)
-{
- VSCMsgError msg = {.code = htonl(code)};
-
- ccid_card_vscard_send_msg(
- s, VSC_Error, reader_id, (uint8_t *)&msg, sizeof(msg));
-}
-
-static void ccid_card_vscard_send_init(PassthruState *s)
-{
- VSCMsgInit msg = {
- .version = htonl(VSCARD_VERSION),
- .magic = VSCARD_MAGIC,
- .capabilities = {0}
- };
-
- ccid_card_vscard_send_msg(s, VSC_Init, VSCARD_UNDEFINED_READER_ID,
- (uint8_t *)&msg, sizeof(msg));
-}
-
-static int ccid_card_vscard_can_read(void *opaque)
-{
- PassthruState *card = opaque;
-
- return VSCARD_IN_SIZE >= card->vscard_in_pos ?
- VSCARD_IN_SIZE - card->vscard_in_pos : 0;
-}
-
-static void ccid_card_vscard_handle_init(
- PassthruState *card, VSCMsgHeader *hdr, VSCMsgInit *init)
-{
- uint32_t *capabilities;
- int num_capabilities;
- int i;
-
- capabilities = init->capabilities;
- num_capabilities =
- 1 + ((hdr->length - sizeof(VSCMsgInit)) / sizeof(uint32_t));
- init->version = ntohl(init->version);
- for (i = 0 ; i < num_capabilities; ++i) {
- capabilities[i] = ntohl(capabilities[i]);
- }
- if (init->magic != VSCARD_MAGIC) {
- error_report("wrong magic");
- /* we can't disconnect the chardev */
- }
- if (init->version != VSCARD_VERSION) {
- DPRINTF(card, D_WARN,
- "got version %d, have %d", init->version, VSCARD_VERSION);
- }
- /* future handling of capabilities, none exist atm */
- ccid_card_vscard_send_init(card);
-}
-
-static int check_atr(PassthruState *card, uint8_t *data, int len)
-{
- int historical_length, opt_bytes;
- int td_count = 0;
- int td;
-
- if (len < 2) {
- return 0;
- }
- historical_length = data[1] & 0xf;
- opt_bytes = 0;
- if (data[0] != 0x3b && data[0] != 0x3f) {
- DPRINTF(card, D_WARN, "atr's T0 is 0x%X, not in {0x3b, 0x3f}\n",
- data[0]);
- return 0;
- }
- td_count = 0;
- td = data[1] >> 4;
- while (td && td_count < 2 && opt_bytes + historical_length + 2 < len) {
- td_count++;
- if (td & 0x1) {
- opt_bytes++;
- }
- if (td & 0x2) {
- opt_bytes++;
- }
- if (td & 0x4) {
- opt_bytes++;
- }
- if (td & 0x8) {
- opt_bytes++;
- td = data[opt_bytes + 2] >> 4;
- }
- }
- if (len < 2 + historical_length + opt_bytes) {
- DPRINTF(card, D_WARN,
- "atr too short: len %d, but historical_len %d, T1 0x%X\n",
- len, historical_length, data[1]);
- return 0;
- }
- if (len > 2 + historical_length + opt_bytes) {
- DPRINTF(card, D_WARN,
- "atr too long: len %d, but hist/opt %d/%d, T1 0x%X\n",
- len, historical_length, opt_bytes, data[1]);
- /* let it through */
- }
- DPRINTF(card, D_VERBOSE,
- "atr passes check: %d total length, %d historical, %d optional\n",
- len, historical_length, opt_bytes);
-
- return 1;
-}
-
-static void ccid_card_vscard_handle_message(PassthruState *card,
- VSCMsgHeader *scr_msg_header)
-{
- uint8_t *data = (uint8_t *)&scr_msg_header[1];
-
- switch (scr_msg_header->type) {
- case VSC_ATR:
- DPRINTF(card, D_INFO, "VSC_ATR %d\n", scr_msg_header->length);
- if (scr_msg_header->length > MAX_ATR_SIZE) {
- error_report("ATR size exceeds spec, ignoring");
- ccid_card_vscard_send_error(card, scr_msg_header->reader_id,
- VSC_GENERAL_ERROR);
- break;
- }
- if (!check_atr(card, data, scr_msg_header->length)) {
- error_report("ATR is inconsistent, ignoring");
- ccid_card_vscard_send_error(card, scr_msg_header->reader_id,
- VSC_GENERAL_ERROR);
- break;
- }
- memcpy(card->atr, data, scr_msg_header->length);
- card->atr_length = scr_msg_header->length;
- ccid_card_card_inserted(&card->base);
- ccid_card_vscard_send_error(card, scr_msg_header->reader_id,
- VSC_SUCCESS);
- break;
- case VSC_APDU:
- ccid_card_send_apdu_to_guest(
- &card->base, data, scr_msg_header->length);
- break;
- case VSC_CardRemove:
- DPRINTF(card, D_INFO, "VSC_CardRemove\n");
- ccid_card_card_removed(&card->base);
- ccid_card_vscard_send_error(card,
- scr_msg_header->reader_id, VSC_SUCCESS);
- break;
- case VSC_Init:
- ccid_card_vscard_handle_init(
- card, scr_msg_header, (VSCMsgInit *)data);
- break;
- case VSC_Error:
- ccid_card_card_error(&card->base, *(uint32_t *)data);
- break;
- case VSC_ReaderAdd:
- if (ccid_card_ccid_attach(&card->base) < 0) {
- ccid_card_vscard_send_error(card, VSCARD_UNDEFINED_READER_ID,
- VSC_CANNOT_ADD_MORE_READERS);
- } else {
- ccid_card_vscard_send_error(card, VSCARD_MINIMAL_READER_ID,
- VSC_SUCCESS);
- }
- break;
- case VSC_ReaderRemove:
- ccid_card_ccid_detach(&card->base);
- ccid_card_vscard_send_error(card,
- scr_msg_header->reader_id, VSC_SUCCESS);
- break;
- default:
- printf("usb-ccid: chardev: unexpected message of type %X\n",
- scr_msg_header->type);
- ccid_card_vscard_send_error(card, scr_msg_header->reader_id,
- VSC_GENERAL_ERROR);
- }
-}
-
-static void ccid_card_vscard_drop_connection(PassthruState *card)
-{
- qemu_chr_delete(card->cs);
- card->vscard_in_pos = card->vscard_in_hdr = 0;
-}
-
-static void ccid_card_vscard_read(void *opaque, const uint8_t *buf, int size)
-{
- PassthruState *card = opaque;
- VSCMsgHeader *hdr;
-
- if (card->vscard_in_pos + size > VSCARD_IN_SIZE) {
- error_report(
- "no room for data: pos %d + size %d > %d. dropping connection.",
- card->vscard_in_pos, size, VSCARD_IN_SIZE);
- ccid_card_vscard_drop_connection(card);
- return;
- }
- assert(card->vscard_in_pos < VSCARD_IN_SIZE);
- assert(card->vscard_in_hdr < VSCARD_IN_SIZE);
- memcpy(card->vscard_in_data + card->vscard_in_pos, buf, size);
- card->vscard_in_pos += size;
- hdr = (VSCMsgHeader *)(card->vscard_in_data + card->vscard_in_hdr);
-
- while ((card->vscard_in_pos - card->vscard_in_hdr >= sizeof(VSCMsgHeader))
- &&(card->vscard_in_pos - card->vscard_in_hdr >=
- sizeof(VSCMsgHeader) + ntohl(hdr->length))) {
- hdr->reader_id = ntohl(hdr->reader_id);
- hdr->length = ntohl(hdr->length);
- hdr->type = ntohl(hdr->type);
- ccid_card_vscard_handle_message(card, hdr);
- card->vscard_in_hdr += hdr->length + sizeof(VSCMsgHeader);
- hdr = (VSCMsgHeader *)(card->vscard_in_data + card->vscard_in_hdr);
- }
- if (card->vscard_in_hdr == card->vscard_in_pos) {
- card->vscard_in_pos = card->vscard_in_hdr = 0;
- }
-}
-
-static void ccid_card_vscard_event(void *opaque, int event)
-{
- PassthruState *card = opaque;
-
- switch (event) {
- case CHR_EVENT_BREAK:
- card->vscard_in_pos = card->vscard_in_hdr = 0;
- break;
- case CHR_EVENT_FOCUS:
- break;
- case CHR_EVENT_OPENED:
- DPRINTF(card, D_INFO, "%s: CHR_EVENT_OPENED\n", __func__);
- break;
- }
-}
-
-/* End VSCard handling */
-
-static void passthru_apdu_from_guest(
- CCIDCardState *base, const uint8_t *apdu, uint32_t len)
-{
- PassthruState *card = PASSTHRU_CCID_CARD(base);
-
- if (!card->cs) {
- printf("ccid-passthru: no chardev, discarding apdu length %d\n", len);
- return;
- }
- ccid_card_vscard_send_apdu(card, apdu, len);
-}
-
-static const uint8_t *passthru_get_atr(CCIDCardState *base, uint32_t *len)
-{
- PassthruState *card = PASSTHRU_CCID_CARD(base);
-
- *len = card->atr_length;
- return card->atr;
-}
-
-static int passthru_initfn(CCIDCardState *base)
-{
- PassthruState *card = PASSTHRU_CCID_CARD(base);
-
- card->vscard_in_pos = 0;
- card->vscard_in_hdr = 0;
- if (card->cs) {
- DPRINTF(card, D_INFO, "initing chardev\n");
- qemu_chr_add_handlers(card->cs,
- ccid_card_vscard_can_read,
- ccid_card_vscard_read,
- ccid_card_vscard_event, card);
- ccid_card_vscard_send_init(card);
- } else {
- error_report("missing chardev");
- return -1;
- }
- card->debug = parse_debug_env("QEMU_CCID_PASSTHRU_DEBUG", D_VERBOSE,
- card->debug);
- assert(sizeof(DEFAULT_ATR) <= MAX_ATR_SIZE);
- memcpy(card->atr, DEFAULT_ATR, sizeof(DEFAULT_ATR));
- card->atr_length = sizeof(DEFAULT_ATR);
- return 0;
-}
-
-static int passthru_exitfn(CCIDCardState *base)
-{
- return 0;
-}
-
-static VMStateDescription passthru_vmstate = {
- .name = "ccid-card-passthru",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_BUFFER(vscard_in_data, PassthruState),
- VMSTATE_UINT32(vscard_in_pos, PassthruState),
- VMSTATE_UINT32(vscard_in_hdr, PassthruState),
- VMSTATE_BUFFER(atr, PassthruState),
- VMSTATE_UINT8(atr_length, PassthruState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property passthru_card_properties[] = {
- DEFINE_PROP_CHR("chardev", PassthruState, cs),
- DEFINE_PROP_UINT8("debug", PassthruState, debug, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void passthru_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- CCIDCardClass *cc = CCID_CARD_CLASS(klass);
-
- cc->initfn = passthru_initfn;
- cc->exitfn = passthru_exitfn;
- cc->get_atr = passthru_get_atr;
- cc->apdu_from_guest = passthru_apdu_from_guest;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
- dc->desc = "passthrough smartcard";
- dc->vmsd = &passthru_vmstate;
- dc->props = passthru_card_properties;
-}
-
-static const TypeInfo passthru_card_info = {
- .name = TYPE_CCID_PASSTHRU,
- .parent = TYPE_CCID_CARD,
- .instance_size = sizeof(PassthruState),
- .class_init = passthru_class_initfn,
-};
-
-static void ccid_card_passthru_register_types(void)
-{
- type_register_static(&passthru_card_info);
-}
-
-type_init(ccid_card_passthru_register_types)
diff --git a/qemu/hw/usb/ccid.h b/qemu/hw/usb/ccid.h
deleted file mode 100644
index 9334da8ac..000000000
--- a/qemu/hw/usb/ccid.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * CCID Passthru Card Device emulation
- *
- * Copyright (c) 2011 Red Hat.
- * Written by Alon Levy.
- *
- * This code is licensed under the GNU LGPL, version 2 or later.
- */
-
-#ifndef CCID_H
-#define CCID_H
-
-#include "hw/qdev.h"
-
-typedef struct CCIDCardState CCIDCardState;
-typedef struct CCIDCardInfo CCIDCardInfo;
-
-#define TYPE_CCID_CARD "ccid-card"
-#define CCID_CARD(obj) \
- OBJECT_CHECK(CCIDCardState, (obj), TYPE_CCID_CARD)
-#define CCID_CARD_CLASS(klass) \
- OBJECT_CLASS_CHECK(CCIDCardClass, (klass), TYPE_CCID_CARD)
-#define CCID_CARD_GET_CLASS(obj) \
- OBJECT_GET_CLASS(CCIDCardClass, (obj), TYPE_CCID_CARD)
-
-/*
- * callbacks to be used by the CCID device (hw/usb-ccid.c) to call
- * into the smartcard device (hw/ccid-card-*.c)
- */
-typedef struct CCIDCardClass {
- DeviceClass parent_class;
- const uint8_t *(*get_atr)(CCIDCardState *card, uint32_t *len);
- void (*apdu_from_guest)(CCIDCardState *card,
- const uint8_t *apdu,
- uint32_t len);
- int (*exitfn)(CCIDCardState *card);
- int (*initfn)(CCIDCardState *card);
-} CCIDCardClass;
-
-/*
- * state of the CCID Card device (i.e. hw/ccid-card-*.c)
- */
-struct CCIDCardState {
- DeviceState qdev;
- uint32_t slot; /* For future use with multiple slot reader. */
-};
-
-/*
- * API for smartcard calling the CCID device (used by hw/ccid-card-*.c)
- */
-void ccid_card_send_apdu_to_guest(CCIDCardState *card,
- uint8_t *apdu,
- uint32_t len);
-void ccid_card_card_removed(CCIDCardState *card);
-void ccid_card_card_inserted(CCIDCardState *card);
-void ccid_card_card_error(CCIDCardState *card, uint64_t error);
-
-/*
- * support guest visible insertion/removal of ccid devices based on actual
- * devices connected/removed. Called by card implementation (passthru, local)
- */
-int ccid_card_ccid_attach(CCIDCardState *card);
-void ccid_card_ccid_detach(CCIDCardState *card);
-
-#endif /* CCID_H */
diff --git a/qemu/hw/usb/combined-packet.c b/qemu/hw/usb/combined-packet.c
deleted file mode 100644
index 48cac87f6..000000000
--- a/qemu/hw/usb/combined-packet.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * QEMU USB packet combining code (for input pipelining)
- *
- * Copyright(c) 2012 Red Hat, Inc.
- *
- * Red Hat Authors:
- * Hans de Goede <hdegoede@redhat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or(at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "hw/usb.h"
-#include "qemu/iov.h"
-#include "trace.h"
-
-static void usb_combined_packet_add(USBCombinedPacket *combined, USBPacket *p)
-{
- qemu_iovec_concat(&combined->iov, &p->iov, 0, p->iov.size);
- QTAILQ_INSERT_TAIL(&combined->packets, p, combined_entry);
- p->combined = combined;
-}
-
-/* Note will free combined when the last packet gets removed */
-static void usb_combined_packet_remove(USBCombinedPacket *combined,
- USBPacket *p)
-{
- assert(p->combined == combined);
- p->combined = NULL;
- QTAILQ_REMOVE(&combined->packets, p, combined_entry);
- if (QTAILQ_EMPTY(&combined->packets)) {
- qemu_iovec_destroy(&combined->iov);
- g_free(combined);
- }
-}
-
-/* Also handles completion of non combined packets for pipelined input eps */
-void usb_combined_input_packet_complete(USBDevice *dev, USBPacket *p)
-{
- USBCombinedPacket *combined = p->combined;
- USBEndpoint *ep = p->ep;
- USBPacket *next;
- int status, actual_length;
- bool short_not_ok, done = false;
-
- if (combined == NULL) {
- usb_packet_complete_one(dev, p);
- goto leave;
- }
-
- assert(combined->first == p && p == QTAILQ_FIRST(&combined->packets));
-
- status = combined->first->status;
- actual_length = combined->first->actual_length;
- short_not_ok = QTAILQ_LAST(&combined->packets, packets_head)->short_not_ok;
-
- QTAILQ_FOREACH_SAFE(p, &combined->packets, combined_entry, next) {
- if (!done) {
- /* Distribute data over uncombined packets */
- if (actual_length >= p->iov.size) {
- p->actual_length = p->iov.size;
- } else {
- /* Send short or error packet to complete the transfer */
- p->actual_length = actual_length;
- done = true;
- }
- /* Report status on the last packet */
- if (done || next == NULL) {
- p->status = status;
- } else {
- p->status = USB_RET_SUCCESS;
- }
- p->short_not_ok = short_not_ok;
- /* Note will free combined when the last packet gets removed! */
- usb_combined_packet_remove(combined, p);
- usb_packet_complete_one(dev, p);
- actual_length -= p->actual_length;
- } else {
- /* Remove any leftover packets from the queue */
- p->status = USB_RET_REMOVE_FROM_QUEUE;
- /* Note will free combined on the last packet! */
- dev->port->ops->complete(dev->port, p);
- }
- }
- /* Do not use combined here, it has been freed! */
-leave:
- /* Check if there are packets in the queue waiting for our completion */
- usb_ep_combine_input_packets(ep);
-}
-
-/* May only be called for combined packets! */
-void usb_combined_packet_cancel(USBDevice *dev, USBPacket *p)
-{
- USBCombinedPacket *combined = p->combined;
- assert(combined != NULL);
- USBPacket *first = p->combined->first;
-
- /* Note will free combined on the last packet! */
- usb_combined_packet_remove(combined, p);
- if (p == first) {
- usb_device_cancel_packet(dev, p);
- }
-}
-
-/*
- * Large input transfers can get split into multiple input packets, this
- * function recombines them, removing the short_not_ok checks which all but
- * the last packet of such splits transfers have, thereby allowing input
- * transfer pipelining (which we cannot do on short_not_ok transfers)
- */
-void usb_ep_combine_input_packets(USBEndpoint *ep)
-{
- USBPacket *p, *u, *next, *prev = NULL, *first = NULL;
- USBPort *port = ep->dev->port;
- int totalsize;
-
- assert(ep->pipeline);
- assert(ep->pid == USB_TOKEN_IN);
-
- QTAILQ_FOREACH_SAFE(p, &ep->queue, queue, next) {
- /* Empty the queue on a halt */
- if (ep->halted) {
- p->status = USB_RET_REMOVE_FROM_QUEUE;
- port->ops->complete(port, p);
- continue;
- }
-
- /* Skip packets already submitted to the device */
- if (p->state == USB_PACKET_ASYNC) {
- prev = p;
- continue;
- }
- usb_packet_check_state(p, USB_PACKET_QUEUED);
-
- /*
- * If the previous (combined) packet has the short_not_ok flag set
- * stop, as we must not submit packets to the device after a transfer
- * ending with short_not_ok packet.
- */
- if (prev && prev->short_not_ok) {
- break;
- }
-
- if (first) {
- if (first->combined == NULL) {
- USBCombinedPacket *combined = g_new0(USBCombinedPacket, 1);
-
- combined->first = first;
- QTAILQ_INIT(&combined->packets);
- qemu_iovec_init(&combined->iov, 2);
- usb_combined_packet_add(combined, first);
- }
- usb_combined_packet_add(first->combined, p);
- } else {
- first = p;
- }
-
- /* Is this packet the last one of a (combined) transfer? */
- totalsize = (p->combined) ? p->combined->iov.size : p->iov.size;
- if ((p->iov.size % ep->max_packet_size) != 0 || !p->short_not_ok ||
- next == NULL ||
- /* Work around for Linux usbfs bulk splitting + migration */
- (totalsize == 16348 && p->int_req)) {
- usb_device_handle_data(ep->dev, first);
- assert(first->status == USB_RET_ASYNC);
- if (first->combined) {
- QTAILQ_FOREACH(u, &first->combined->packets, combined_entry) {
- usb_packet_set_state(u, USB_PACKET_ASYNC);
- }
- } else {
- usb_packet_set_state(first, USB_PACKET_ASYNC);
- }
- first = NULL;
- prev = p;
- }
- }
-}
diff --git a/qemu/hw/usb/core.c b/qemu/hw/usb/core.c
deleted file mode 100644
index 45fa00c51..000000000
--- a/qemu/hw/usb/core.c
+++ /dev/null
@@ -1,795 +0,0 @@
-/*
- * QEMU USB emulation
- *
- * Copyright (c) 2005 Fabrice Bellard
- *
- * 2008 Generic packet handler rewrite by Max Krasnyansky
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "hw/usb.h"
-#include "qemu/iov.h"
-#include "trace.h"
-
-void usb_pick_speed(USBPort *port)
-{
- static const int speeds[] = {
- USB_SPEED_SUPER,
- USB_SPEED_HIGH,
- USB_SPEED_FULL,
- USB_SPEED_LOW,
- };
- USBDevice *udev = port->dev;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(speeds); i++) {
- if ((udev->speedmask & (1 << speeds[i])) &&
- (port->speedmask & (1 << speeds[i]))) {
- udev->speed = speeds[i];
- return;
- }
- }
-}
-
-void usb_attach(USBPort *port)
-{
- USBDevice *dev = port->dev;
-
- assert(dev != NULL);
- assert(dev->attached);
- assert(dev->state == USB_STATE_NOTATTACHED);
- usb_pick_speed(port);
- port->ops->attach(port);
- dev->state = USB_STATE_ATTACHED;
- usb_device_handle_attach(dev);
-}
-
-void usb_detach(USBPort *port)
-{
- USBDevice *dev = port->dev;
-
- assert(dev != NULL);
- assert(dev->state != USB_STATE_NOTATTACHED);
- port->ops->detach(port);
- dev->state = USB_STATE_NOTATTACHED;
-}
-
-void usb_port_reset(USBPort *port)
-{
- USBDevice *dev = port->dev;
-
- assert(dev != NULL);
- usb_detach(port);
- usb_attach(port);
- usb_device_reset(dev);
-}
-
-void usb_device_reset(USBDevice *dev)
-{
- if (dev == NULL || !dev->attached) {
- return;
- }
- dev->remote_wakeup = 0;
- dev->addr = 0;
- dev->state = USB_STATE_DEFAULT;
- usb_device_handle_reset(dev);
-}
-
-void usb_wakeup(USBEndpoint *ep, unsigned int stream)
-{
- USBDevice *dev = ep->dev;
- USBBus *bus = usb_bus_from_device(dev);
-
- if (dev->remote_wakeup && dev->port && dev->port->ops->wakeup) {
- dev->port->ops->wakeup(dev->port);
- }
- if (bus->ops->wakeup_endpoint) {
- bus->ops->wakeup_endpoint(bus, ep, stream);
- }
-}
-
-/**********************/
-
-/* generic USB device helpers (you are not forced to use them when
- writing your USB device driver, but they help handling the
- protocol)
-*/
-
-#define SETUP_STATE_IDLE 0
-#define SETUP_STATE_SETUP 1
-#define SETUP_STATE_DATA 2
-#define SETUP_STATE_ACK 3
-#define SETUP_STATE_PARAM 4
-
-static void do_token_setup(USBDevice *s, USBPacket *p)
-{
- int request, value, index;
-
- if (p->iov.size != 8) {
- p->status = USB_RET_STALL;
- return;
- }
-
- usb_packet_copy(p, s->setup_buf, p->iov.size);
- s->setup_index = 0;
- p->actual_length = 0;
- s->setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6];
- if (s->setup_len > sizeof(s->data_buf)) {
- fprintf(stderr,
- "usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n",
- s->setup_len, sizeof(s->data_buf));
- p->status = USB_RET_STALL;
- return;
- }
-
- request = (s->setup_buf[0] << 8) | s->setup_buf[1];
- value = (s->setup_buf[3] << 8) | s->setup_buf[2];
- index = (s->setup_buf[5] << 8) | s->setup_buf[4];
-
- if (s->setup_buf[0] & USB_DIR_IN) {
- usb_device_handle_control(s, p, request, value, index,
- s->setup_len, s->data_buf);
- if (p->status == USB_RET_ASYNC) {
- s->setup_state = SETUP_STATE_SETUP;
- }
- if (p->status != USB_RET_SUCCESS) {
- return;
- }
-
- if (p->actual_length < s->setup_len) {
- s->setup_len = p->actual_length;
- }
- s->setup_state = SETUP_STATE_DATA;
- } else {
- if (s->setup_len == 0)
- s->setup_state = SETUP_STATE_ACK;
- else
- s->setup_state = SETUP_STATE_DATA;
- }
-
- p->actual_length = 8;
-}
-
-static void do_token_in(USBDevice *s, USBPacket *p)
-{
- int request, value, index;
-
- assert(p->ep->nr == 0);
-
- request = (s->setup_buf[0] << 8) | s->setup_buf[1];
- value = (s->setup_buf[3] << 8) | s->setup_buf[2];
- index = (s->setup_buf[5] << 8) | s->setup_buf[4];
-
- switch(s->setup_state) {
- case SETUP_STATE_ACK:
- if (!(s->setup_buf[0] & USB_DIR_IN)) {
- usb_device_handle_control(s, p, request, value, index,
- s->setup_len, s->data_buf);
- if (p->status == USB_RET_ASYNC) {
- return;
- }
- s->setup_state = SETUP_STATE_IDLE;
- p->actual_length = 0;
- }
- break;
-
- case SETUP_STATE_DATA:
- if (s->setup_buf[0] & USB_DIR_IN) {
- int len = s->setup_len - s->setup_index;
- if (len > p->iov.size) {
- len = p->iov.size;
- }
- usb_packet_copy(p, s->data_buf + s->setup_index, len);
- s->setup_index += len;
- if (s->setup_index >= s->setup_len) {
- s->setup_state = SETUP_STATE_ACK;
- }
- return;
- }
- s->setup_state = SETUP_STATE_IDLE;
- p->status = USB_RET_STALL;
- break;
-
- default:
- p->status = USB_RET_STALL;
- }
-}
-
-static void do_token_out(USBDevice *s, USBPacket *p)
-{
- assert(p->ep->nr == 0);
-
- switch(s->setup_state) {
- case SETUP_STATE_ACK:
- if (s->setup_buf[0] & USB_DIR_IN) {
- s->setup_state = SETUP_STATE_IDLE;
- /* transfer OK */
- } else {
- /* ignore additional output */
- }
- break;
-
- case SETUP_STATE_DATA:
- if (!(s->setup_buf[0] & USB_DIR_IN)) {
- int len = s->setup_len - s->setup_index;
- if (len > p->iov.size) {
- len = p->iov.size;
- }
- usb_packet_copy(p, s->data_buf + s->setup_index, len);
- s->setup_index += len;
- if (s->setup_index >= s->setup_len) {
- s->setup_state = SETUP_STATE_ACK;
- }
- return;
- }
- s->setup_state = SETUP_STATE_IDLE;
- p->status = USB_RET_STALL;
- break;
-
- default:
- p->status = USB_RET_STALL;
- }
-}
-
-static void do_parameter(USBDevice *s, USBPacket *p)
-{
- int i, request, value, index;
-
- for (i = 0; i < 8; i++) {
- s->setup_buf[i] = p->parameter >> (i*8);
- }
-
- s->setup_state = SETUP_STATE_PARAM;
- s->setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6];
- s->setup_index = 0;
-
- request = (s->setup_buf[0] << 8) | s->setup_buf[1];
- value = (s->setup_buf[3] << 8) | s->setup_buf[2];
- index = (s->setup_buf[5] << 8) | s->setup_buf[4];
-
- if (s->setup_len > sizeof(s->data_buf)) {
- fprintf(stderr,
- "usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n",
- s->setup_len, sizeof(s->data_buf));
- p->status = USB_RET_STALL;
- return;
- }
-
- if (p->pid == USB_TOKEN_OUT) {
- usb_packet_copy(p, s->data_buf, s->setup_len);
- }
-
- usb_device_handle_control(s, p, request, value, index,
- s->setup_len, s->data_buf);
- if (p->status == USB_RET_ASYNC) {
- return;
- }
-
- if (p->actual_length < s->setup_len) {
- s->setup_len = p->actual_length;
- }
- if (p->pid == USB_TOKEN_IN) {
- p->actual_length = 0;
- usb_packet_copy(p, s->data_buf, s->setup_len);
- }
-}
-
-/* ctrl complete function for devices which use usb_generic_handle_packet and
- may return USB_RET_ASYNC from their handle_control callback. Device code
- which does this *must* call this function instead of the normal
- usb_packet_complete to complete their async control packets. */
-void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p)
-{
- if (p->status < 0) {
- s->setup_state = SETUP_STATE_IDLE;
- }
-
- switch (s->setup_state) {
- case SETUP_STATE_SETUP:
- if (p->actual_length < s->setup_len) {
- s->setup_len = p->actual_length;
- }
- s->setup_state = SETUP_STATE_DATA;
- p->actual_length = 8;
- break;
-
- case SETUP_STATE_ACK:
- s->setup_state = SETUP_STATE_IDLE;
- p->actual_length = 0;
- break;
-
- case SETUP_STATE_PARAM:
- if (p->actual_length < s->setup_len) {
- s->setup_len = p->actual_length;
- }
- if (p->pid == USB_TOKEN_IN) {
- p->actual_length = 0;
- usb_packet_copy(p, s->data_buf, s->setup_len);
- }
- break;
-
- default:
- break;
- }
- usb_packet_complete(s, p);
-}
-
-USBDevice *usb_find_device(USBPort *port, uint8_t addr)
-{
- USBDevice *dev = port->dev;
-
- if (dev == NULL || !dev->attached || dev->state != USB_STATE_DEFAULT) {
- return NULL;
- }
- if (dev->addr == addr) {
- return dev;
- }
- return usb_device_find_device(dev, addr);
-}
-
-static void usb_process_one(USBPacket *p)
-{
- USBDevice *dev = p->ep->dev;
-
- /*
- * Handlers expect status to be initialized to USB_RET_SUCCESS, but it
- * can be USB_RET_NAK here from a previous usb_process_one() call,
- * or USB_RET_ASYNC from going through usb_queue_one().
- */
- p->status = USB_RET_SUCCESS;
-
- if (p->ep->nr == 0) {
- /* control pipe */
- if (p->parameter) {
- do_parameter(dev, p);
- return;
- }
- switch (p->pid) {
- case USB_TOKEN_SETUP:
- do_token_setup(dev, p);
- break;
- case USB_TOKEN_IN:
- do_token_in(dev, p);
- break;
- case USB_TOKEN_OUT:
- do_token_out(dev, p);
- break;
- default:
- p->status = USB_RET_STALL;
- }
- } else {
- /* data pipe */
- usb_device_handle_data(dev, p);
- }
-}
-
-static void usb_queue_one(USBPacket *p)
-{
- usb_packet_set_state(p, USB_PACKET_QUEUED);
- QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue);
- p->status = USB_RET_ASYNC;
-}
-
-/* Hand over a packet to a device for processing. p->status ==
- USB_RET_ASYNC indicates the processing isn't finished yet, the
- driver will call usb_packet_complete() when done processing it. */
-void usb_handle_packet(USBDevice *dev, USBPacket *p)
-{
- if (dev == NULL) {
- p->status = USB_RET_NODEV;
- return;
- }
- assert(dev == p->ep->dev);
- assert(dev->state == USB_STATE_DEFAULT);
- usb_packet_check_state(p, USB_PACKET_SETUP);
- assert(p->ep != NULL);
-
- /* Submitting a new packet clears halt */
- if (p->ep->halted) {
- assert(QTAILQ_EMPTY(&p->ep->queue));
- p->ep->halted = false;
- }
-
- if (QTAILQ_EMPTY(&p->ep->queue) || p->ep->pipeline || p->stream) {
- usb_process_one(p);
- if (p->status == USB_RET_ASYNC) {
- /* hcd drivers cannot handle async for isoc */
- assert(p->ep->type != USB_ENDPOINT_XFER_ISOC);
- /* using async for interrupt packets breaks migration */
- assert(p->ep->type != USB_ENDPOINT_XFER_INT ||
- (dev->flags & (1 << USB_DEV_FLAG_IS_HOST)));
- usb_packet_set_state(p, USB_PACKET_ASYNC);
- QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue);
- } else if (p->status == USB_RET_ADD_TO_QUEUE) {
- usb_queue_one(p);
- } else {
- /*
- * When pipelining is enabled usb-devices must always return async,
- * otherwise packets can complete out of order!
- */
- assert(p->stream || !p->ep->pipeline ||
- QTAILQ_EMPTY(&p->ep->queue));
- if (p->status != USB_RET_NAK) {
- usb_packet_set_state(p, USB_PACKET_COMPLETE);
- }
- }
- } else {
- usb_queue_one(p);
- }
-}
-
-void usb_packet_complete_one(USBDevice *dev, USBPacket *p)
-{
- USBEndpoint *ep = p->ep;
-
- assert(p->stream || QTAILQ_FIRST(&ep->queue) == p);
- assert(p->status != USB_RET_ASYNC && p->status != USB_RET_NAK);
-
- if (p->status != USB_RET_SUCCESS ||
- (p->short_not_ok && (p->actual_length < p->iov.size))) {
- ep->halted = true;
- }
- usb_packet_set_state(p, USB_PACKET_COMPLETE);
- QTAILQ_REMOVE(&ep->queue, p, queue);
- dev->port->ops->complete(dev->port, p);
-}
-
-/* Notify the controller that an async packet is complete. This should only
- be called for packets previously deferred by returning USB_RET_ASYNC from
- handle_packet. */
-void usb_packet_complete(USBDevice *dev, USBPacket *p)
-{
- USBEndpoint *ep = p->ep;
-
- usb_packet_check_state(p, USB_PACKET_ASYNC);
- usb_packet_complete_one(dev, p);
-
- while (!QTAILQ_EMPTY(&ep->queue)) {
- p = QTAILQ_FIRST(&ep->queue);
- if (ep->halted) {
- /* Empty the queue on a halt */
- p->status = USB_RET_REMOVE_FROM_QUEUE;
- dev->port->ops->complete(dev->port, p);
- continue;
- }
- if (p->state == USB_PACKET_ASYNC) {
- break;
- }
- usb_packet_check_state(p, USB_PACKET_QUEUED);
- usb_process_one(p);
- if (p->status == USB_RET_ASYNC) {
- usb_packet_set_state(p, USB_PACKET_ASYNC);
- break;
- }
- usb_packet_complete_one(ep->dev, p);
- }
-}
-
-/* Cancel an active packet. The packed must have been deferred by
- returning USB_RET_ASYNC from handle_packet, and not yet
- completed. */
-void usb_cancel_packet(USBPacket * p)
-{
- bool callback = (p->state == USB_PACKET_ASYNC);
- assert(usb_packet_is_inflight(p));
- usb_packet_set_state(p, USB_PACKET_CANCELED);
- QTAILQ_REMOVE(&p->ep->queue, p, queue);
- if (callback) {
- usb_device_cancel_packet(p->ep->dev, p);
- }
-}
-
-
-void usb_packet_init(USBPacket *p)
-{
- qemu_iovec_init(&p->iov, 1);
-}
-
-static const char *usb_packet_state_name(USBPacketState state)
-{
- static const char *name[] = {
- [USB_PACKET_UNDEFINED] = "undef",
- [USB_PACKET_SETUP] = "setup",
- [USB_PACKET_QUEUED] = "queued",
- [USB_PACKET_ASYNC] = "async",
- [USB_PACKET_COMPLETE] = "complete",
- [USB_PACKET_CANCELED] = "canceled",
- };
- if (state < ARRAY_SIZE(name)) {
- return name[state];
- }
- return "INVALID";
-}
-
-void usb_packet_check_state(USBPacket *p, USBPacketState expected)
-{
- USBDevice *dev;
- USBBus *bus;
-
- if (p->state == expected) {
- return;
- }
- dev = p->ep->dev;
- bus = usb_bus_from_device(dev);
- trace_usb_packet_state_fault(bus->busnr, dev->port->path, p->ep->nr, p,
- usb_packet_state_name(p->state),
- usb_packet_state_name(expected));
- assert(!"usb packet state check failed");
-}
-
-void usb_packet_set_state(USBPacket *p, USBPacketState state)
-{
- if (p->ep) {
- USBDevice *dev = p->ep->dev;
- USBBus *bus = usb_bus_from_device(dev);
- trace_usb_packet_state_change(bus->busnr, dev->port->path, p->ep->nr, p,
- usb_packet_state_name(p->state),
- usb_packet_state_name(state));
- } else {
- trace_usb_packet_state_change(-1, "", -1, p,
- usb_packet_state_name(p->state),
- usb_packet_state_name(state));
- }
- p->state = state;
-}
-
-void usb_packet_setup(USBPacket *p, int pid,
- USBEndpoint *ep, unsigned int stream,
- uint64_t id, bool short_not_ok, bool int_req)
-{
- assert(!usb_packet_is_inflight(p));
- assert(p->iov.iov != NULL);
- p->id = id;
- p->pid = pid;
- p->ep = ep;
- p->stream = stream;
- p->status = USB_RET_SUCCESS;
- p->actual_length = 0;
- p->parameter = 0;
- p->short_not_ok = short_not_ok;
- p->int_req = int_req;
- p->combined = NULL;
- qemu_iovec_reset(&p->iov);
- usb_packet_set_state(p, USB_PACKET_SETUP);
-}
-
-void usb_packet_addbuf(USBPacket *p, void *ptr, size_t len)
-{
- qemu_iovec_add(&p->iov, ptr, len);
-}
-
-void usb_packet_copy(USBPacket *p, void *ptr, size_t bytes)
-{
- QEMUIOVector *iov = p->combined ? &p->combined->iov : &p->iov;
-
- assert(p->actual_length >= 0);
- assert(p->actual_length + bytes <= iov->size);
- switch (p->pid) {
- case USB_TOKEN_SETUP:
- case USB_TOKEN_OUT:
- iov_to_buf(iov->iov, iov->niov, p->actual_length, ptr, bytes);
- break;
- case USB_TOKEN_IN:
- iov_from_buf(iov->iov, iov->niov, p->actual_length, ptr, bytes);
- break;
- default:
- fprintf(stderr, "%s: invalid pid: %x\n", __func__, p->pid);
- abort();
- }
- p->actual_length += bytes;
-}
-
-void usb_packet_skip(USBPacket *p, size_t bytes)
-{
- QEMUIOVector *iov = p->combined ? &p->combined->iov : &p->iov;
-
- assert(p->actual_length >= 0);
- assert(p->actual_length + bytes <= iov->size);
- if (p->pid == USB_TOKEN_IN) {
- iov_memset(iov->iov, iov->niov, p->actual_length, 0, bytes);
- }
- p->actual_length += bytes;
-}
-
-size_t usb_packet_size(USBPacket *p)
-{
- return p->combined ? p->combined->iov.size : p->iov.size;
-}
-
-void usb_packet_cleanup(USBPacket *p)
-{
- assert(!usb_packet_is_inflight(p));
- qemu_iovec_destroy(&p->iov);
-}
-
-void usb_ep_reset(USBDevice *dev)
-{
- int ep;
-
- dev->ep_ctl.nr = 0;
- dev->ep_ctl.type = USB_ENDPOINT_XFER_CONTROL;
- dev->ep_ctl.ifnum = 0;
- dev->ep_ctl.max_packet_size = 64;
- dev->ep_ctl.max_streams = 0;
- dev->ep_ctl.dev = dev;
- dev->ep_ctl.pipeline = false;
- for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) {
- dev->ep_in[ep].nr = ep + 1;
- dev->ep_out[ep].nr = ep + 1;
- dev->ep_in[ep].pid = USB_TOKEN_IN;
- dev->ep_out[ep].pid = USB_TOKEN_OUT;
- dev->ep_in[ep].type = USB_ENDPOINT_XFER_INVALID;
- dev->ep_out[ep].type = USB_ENDPOINT_XFER_INVALID;
- dev->ep_in[ep].ifnum = USB_INTERFACE_INVALID;
- dev->ep_out[ep].ifnum = USB_INTERFACE_INVALID;
- dev->ep_in[ep].max_packet_size = 0;
- dev->ep_out[ep].max_packet_size = 0;
- dev->ep_in[ep].max_streams = 0;
- dev->ep_out[ep].max_streams = 0;
- dev->ep_in[ep].dev = dev;
- dev->ep_out[ep].dev = dev;
- dev->ep_in[ep].pipeline = false;
- dev->ep_out[ep].pipeline = false;
- }
-}
-
-void usb_ep_init(USBDevice *dev)
-{
- int ep;
-
- usb_ep_reset(dev);
- QTAILQ_INIT(&dev->ep_ctl.queue);
- for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) {
- QTAILQ_INIT(&dev->ep_in[ep].queue);
- QTAILQ_INIT(&dev->ep_out[ep].queue);
- }
-}
-
-void usb_ep_dump(USBDevice *dev)
-{
- static const char *tname[] = {
- [USB_ENDPOINT_XFER_CONTROL] = "control",
- [USB_ENDPOINT_XFER_ISOC] = "isoc",
- [USB_ENDPOINT_XFER_BULK] = "bulk",
- [USB_ENDPOINT_XFER_INT] = "int",
- };
- int ifnum, ep, first;
-
- fprintf(stderr, "Device \"%s\", config %d\n",
- dev->product_desc, dev->configuration);
- for (ifnum = 0; ifnum < 16; ifnum++) {
- first = 1;
- for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) {
- if (dev->ep_in[ep].type != USB_ENDPOINT_XFER_INVALID &&
- dev->ep_in[ep].ifnum == ifnum) {
- if (first) {
- first = 0;
- fprintf(stderr, " Interface %d, alternative %d\n",
- ifnum, dev->altsetting[ifnum]);
- }
- fprintf(stderr, " Endpoint %d, IN, %s, %d max\n", ep,
- tname[dev->ep_in[ep].type],
- dev->ep_in[ep].max_packet_size);
- }
- if (dev->ep_out[ep].type != USB_ENDPOINT_XFER_INVALID &&
- dev->ep_out[ep].ifnum == ifnum) {
- if (first) {
- first = 0;
- fprintf(stderr, " Interface %d, alternative %d\n",
- ifnum, dev->altsetting[ifnum]);
- }
- fprintf(stderr, " Endpoint %d, OUT, %s, %d max\n", ep,
- tname[dev->ep_out[ep].type],
- dev->ep_out[ep].max_packet_size);
- }
- }
- }
- fprintf(stderr, "--\n");
-}
-
-struct USBEndpoint *usb_ep_get(USBDevice *dev, int pid, int ep)
-{
- struct USBEndpoint *eps;
-
- if (dev == NULL) {
- return NULL;
- }
- eps = (pid == USB_TOKEN_IN) ? dev->ep_in : dev->ep_out;
- if (ep == 0) {
- return &dev->ep_ctl;
- }
- assert(pid == USB_TOKEN_IN || pid == USB_TOKEN_OUT);
- assert(ep > 0 && ep <= USB_MAX_ENDPOINTS);
- return eps + ep - 1;
-}
-
-uint8_t usb_ep_get_type(USBDevice *dev, int pid, int ep)
-{
- struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
- return uep->type;
-}
-
-void usb_ep_set_type(USBDevice *dev, int pid, int ep, uint8_t type)
-{
- struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
- uep->type = type;
-}
-
-void usb_ep_set_ifnum(USBDevice *dev, int pid, int ep, uint8_t ifnum)
-{
- struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
- uep->ifnum = ifnum;
-}
-
-void usb_ep_set_max_packet_size(USBDevice *dev, int pid, int ep,
- uint16_t raw)
-{
- struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
- int size, microframes;
-
- size = raw & 0x7ff;
- switch ((raw >> 11) & 3) {
- case 1:
- microframes = 2;
- break;
- case 2:
- microframes = 3;
- break;
- default:
- microframes = 1;
- break;
- }
- uep->max_packet_size = size * microframes;
-}
-
-void usb_ep_set_max_streams(USBDevice *dev, int pid, int ep, uint8_t raw)
-{
- struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
- int MaxStreams;
-
- MaxStreams = raw & 0x1f;
- if (MaxStreams) {
- uep->max_streams = 1 << MaxStreams;
- } else {
- uep->max_streams = 0;
- }
-}
-
-void usb_ep_set_halted(USBDevice *dev, int pid, int ep, bool halted)
-{
- struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
- uep->halted = halted;
-}
-
-USBPacket *usb_ep_find_packet_by_id(USBDevice *dev, int pid, int ep,
- uint64_t id)
-{
- struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
- USBPacket *p;
-
- QTAILQ_FOREACH(p, &uep->queue, queue) {
- if (p->id == id) {
- return p;
- }
- }
-
- return NULL;
-}
diff --git a/qemu/hw/usb/desc-msos.c b/qemu/hw/usb/desc-msos.c
deleted file mode 100644
index 365291981..000000000
--- a/qemu/hw/usb/desc-msos.c
+++ /dev/null
@@ -1,239 +0,0 @@
-#include "qemu/osdep.h"
-#include "hw/usb.h"
-#include "hw/usb/desc.h"
-
-/*
- * Microsoft OS Descriptors
- *
- * Windows tries to fetch some special descriptors with informations
- * specifically for windows. Presence is indicated using a special
- * string @ index 0xee. There are two kinds of descriptors:
- *
- * compatid descriptor
- * Used to bind drivers, if usb class isn't specific enougth.
- * Used for PTP/MTP for example (both share the same usb class).
- *
- * properties descriptor
- * Does carry registry entries. They show up in
- * HLM\SYSTEM\CurrentControlSet\Enum\USB\<devid>\<serial>\Device Parameters
- *
- * Note that Windows caches the stuff it got in the registry, so when
- * playing with this you have to delete registry subtrees to make
- * windows query the device again:
- * HLM\SYSTEM\CurrentControlSet\Control\usbflags
- * HLM\SYSTEM\CurrentControlSet\Enum\USB
- * Windows will complain it can't delete entries on the second one.
- * It has deleted everything it had permissions too, which is enouth
- * as this includes "Device Parameters".
- *
- * http://msdn.microsoft.com/en-us/library/windows/hardware/ff537430.aspx
- *
- */
-
-/* ------------------------------------------------------------------ */
-
-typedef struct msos_compat_hdr {
- uint32_t dwLength;
- uint8_t bcdVersion_lo;
- uint8_t bcdVersion_hi;
- uint8_t wIndex_lo;
- uint8_t wIndex_hi;
- uint8_t bCount;
- uint8_t reserved[7];
-} QEMU_PACKED msos_compat_hdr;
-
-typedef struct msos_compat_func {
- uint8_t bFirstInterfaceNumber;
- uint8_t reserved_1;
- char compatibleId[8];
- uint8_t subCompatibleId[8];
- uint8_t reserved_2[6];
-} QEMU_PACKED msos_compat_func;
-
-static int usb_desc_msos_compat(const USBDesc *desc, uint8_t *dest)
-{
- msos_compat_hdr *hdr = (void *)dest;
- msos_compat_func *func;
- int length = sizeof(*hdr);
- int count = 0;
-
- func = (void *)(dest + length);
- func->bFirstInterfaceNumber = 0;
- func->reserved_1 = 0x01;
- if (desc->msos->CompatibleID) {
- snprintf(func->compatibleId, sizeof(func->compatibleId),
- "%s", desc->msos->CompatibleID);
- }
- length += sizeof(*func);
- count++;
-
- hdr->dwLength = cpu_to_le32(length);
- hdr->bcdVersion_lo = 0x00;
- hdr->bcdVersion_hi = 0x01;
- hdr->wIndex_lo = 0x04;
- hdr->wIndex_hi = 0x00;
- hdr->bCount = count;
- return length;
-}
-
-/* ------------------------------------------------------------------ */
-
-typedef struct msos_prop_hdr {
- uint32_t dwLength;
- uint8_t bcdVersion_lo;
- uint8_t bcdVersion_hi;
- uint8_t wIndex_lo;
- uint8_t wIndex_hi;
- uint8_t wCount_lo;
- uint8_t wCount_hi;
-} QEMU_PACKED msos_prop_hdr;
-
-typedef struct msos_prop {
- uint32_t dwLength;
- uint32_t dwPropertyDataType;
- uint8_t dwPropertyNameLength_lo;
- uint8_t dwPropertyNameLength_hi;
- uint8_t bPropertyName[];
-} QEMU_PACKED msos_prop;
-
-typedef struct msos_prop_data {
- uint32_t dwPropertyDataLength;
- uint8_t bPropertyData[];
-} QEMU_PACKED msos_prop_data;
-
-typedef enum msos_prop_type {
- MSOS_REG_SZ = 1,
- MSOS_REG_EXPAND_SZ = 2,
- MSOS_REG_BINARY = 3,
- MSOS_REG_DWORD_LE = 4,
- MSOS_REG_DWORD_BE = 5,
- MSOS_REG_LINK = 6,
- MSOS_REG_MULTI_SZ = 7,
-} msos_prop_type;
-
-static int usb_desc_msos_prop_name(struct msos_prop *prop,
- const wchar_t *name)
-{
- int length = wcslen(name) + 1;
- int i;
-
- prop->dwPropertyNameLength_lo = usb_lo(length*2);
- prop->dwPropertyNameLength_hi = usb_hi(length*2);
- for (i = 0; i < length; i++) {
- prop->bPropertyName[i*2] = usb_lo(name[i]);
- prop->bPropertyName[i*2+1] = usb_hi(name[i]);
- }
- return length*2;
-}
-
-static int usb_desc_msos_prop_str(uint8_t *dest, msos_prop_type type,
- const wchar_t *name, const wchar_t *value)
-{
- struct msos_prop *prop = (void *)dest;
- struct msos_prop_data *data;
- int length = sizeof(*prop);
- int i, vlen = wcslen(value) + 1;
-
- prop->dwPropertyDataType = cpu_to_le32(type);
- length += usb_desc_msos_prop_name(prop, name);
- data = (void *)(dest + length);
-
- data->dwPropertyDataLength = cpu_to_le32(vlen*2);
- length += sizeof(*prop);
-
- for (i = 0; i < vlen; i++) {
- data->bPropertyData[i*2] = usb_lo(value[i]);
- data->bPropertyData[i*2+1] = usb_hi(value[i]);
- }
- length += vlen*2;
-
- prop->dwLength = cpu_to_le32(length);
- return length;
-}
-
-static int usb_desc_msos_prop_dword(uint8_t *dest, const wchar_t *name,
- uint32_t value)
-{
- struct msos_prop *prop = (void *)dest;
- struct msos_prop_data *data;
- int length = sizeof(*prop);
-
- prop->dwPropertyDataType = cpu_to_le32(MSOS_REG_DWORD_LE);
- length += usb_desc_msos_prop_name(prop, name);
- data = (void *)(dest + length);
-
- data->dwPropertyDataLength = cpu_to_le32(4);
- data->bPropertyData[0] = (value) & 0xff;
- data->bPropertyData[1] = (value >> 8) & 0xff;
- data->bPropertyData[2] = (value >> 16) & 0xff;
- data->bPropertyData[3] = (value >> 24) & 0xff;
- length += sizeof(*prop) + 4;
-
- prop->dwLength = cpu_to_le32(length);
- return length;
-}
-
-static int usb_desc_msos_prop(const USBDesc *desc, uint8_t *dest)
-{
- msos_prop_hdr *hdr = (void *)dest;
- int length = sizeof(*hdr);
- int count = 0;
-
- if (desc->msos->Label) {
- /*
- * Given as example in the specs. Havn't figured yet where
- * this label shows up in the windows gui.
- */
- length += usb_desc_msos_prop_str(dest+length, MSOS_REG_SZ,
- L"Label", desc->msos->Label);
- count++;
- }
-
- if (desc->msos->SelectiveSuspendEnabled) {
- /*
- * Signaling remote wakeup capability in the standard usb
- * descriptors isn't enouth to make windows actually use it.
- * This is the "Yes, we really mean it" registy entry to flip
- * the switch in the windows drivers.
- */
- length += usb_desc_msos_prop_dword(dest+length,
- L"SelectiveSuspendEnabled", 1);
- count++;
- }
-
- hdr->dwLength = cpu_to_le32(length);
- hdr->bcdVersion_lo = 0x00;
- hdr->bcdVersion_hi = 0x01;
- hdr->wIndex_lo = 0x05;
- hdr->wIndex_hi = 0x00;
- hdr->wCount_lo = usb_lo(count);
- hdr->wCount_hi = usb_hi(count);
- return length;
-}
-
-/* ------------------------------------------------------------------ */
-
-int usb_desc_msos(const USBDesc *desc, USBPacket *p,
- int index, uint8_t *dest, size_t len)
-{
- void *buf = g_malloc0(4096);
- int length = 0;
-
- switch (index) {
- case 0x0004:
- length = usb_desc_msos_compat(desc, buf);
- break;
- case 0x0005:
- length = usb_desc_msos_prop(desc, buf);
- break;
- }
-
- if (length > len) {
- length = len;
- }
- memcpy(dest, buf, length);
- g_free(buf);
-
- p->actual_length = length;
- return 0;
-}
diff --git a/qemu/hw/usb/desc.c b/qemu/hw/usb/desc.c
deleted file mode 100644
index adb026e43..000000000
--- a/qemu/hw/usb/desc.c
+++ /dev/null
@@ -1,804 +0,0 @@
-#include "qemu/osdep.h"
-
-#include "hw/usb.h"
-#include "hw/usb/desc.h"
-#include "trace.h"
-
-/* ------------------------------------------------------------------ */
-
-int usb_desc_device(const USBDescID *id, const USBDescDevice *dev,
- bool msos, uint8_t *dest, size_t len)
-{
- uint8_t bLength = 0x12;
- USBDescriptor *d = (void *)dest;
-
- if (len < bLength) {
- return -1;
- }
-
- d->bLength = bLength;
- d->bDescriptorType = USB_DT_DEVICE;
-
- if (msos && dev->bcdUSB < 0x0200) {
- /*
- * Version 2.0+ required for microsoft os descriptors to work.
- * Done this way so msos-desc compat property will handle both
- * the version and the new descriptors being present.
- */
- d->u.device.bcdUSB_lo = usb_lo(0x0200);
- d->u.device.bcdUSB_hi = usb_hi(0x0200);
- } else {
- d->u.device.bcdUSB_lo = usb_lo(dev->bcdUSB);
- d->u.device.bcdUSB_hi = usb_hi(dev->bcdUSB);
- }
- d->u.device.bDeviceClass = dev->bDeviceClass;
- d->u.device.bDeviceSubClass = dev->bDeviceSubClass;
- d->u.device.bDeviceProtocol = dev->bDeviceProtocol;
- d->u.device.bMaxPacketSize0 = dev->bMaxPacketSize0;
-
- d->u.device.idVendor_lo = usb_lo(id->idVendor);
- d->u.device.idVendor_hi = usb_hi(id->idVendor);
- d->u.device.idProduct_lo = usb_lo(id->idProduct);
- d->u.device.idProduct_hi = usb_hi(id->idProduct);
- d->u.device.bcdDevice_lo = usb_lo(id->bcdDevice);
- d->u.device.bcdDevice_hi = usb_hi(id->bcdDevice);
- d->u.device.iManufacturer = id->iManufacturer;
- d->u.device.iProduct = id->iProduct;
- d->u.device.iSerialNumber = id->iSerialNumber;
-
- d->u.device.bNumConfigurations = dev->bNumConfigurations;
-
- return bLength;
-}
-
-int usb_desc_device_qualifier(const USBDescDevice *dev,
- uint8_t *dest, size_t len)
-{
- uint8_t bLength = 0x0a;
- USBDescriptor *d = (void *)dest;
-
- if (len < bLength) {
- return -1;
- }
-
- d->bLength = bLength;
- d->bDescriptorType = USB_DT_DEVICE_QUALIFIER;
-
- d->u.device_qualifier.bcdUSB_lo = usb_lo(dev->bcdUSB);
- d->u.device_qualifier.bcdUSB_hi = usb_hi(dev->bcdUSB);
- d->u.device_qualifier.bDeviceClass = dev->bDeviceClass;
- d->u.device_qualifier.bDeviceSubClass = dev->bDeviceSubClass;
- d->u.device_qualifier.bDeviceProtocol = dev->bDeviceProtocol;
- d->u.device_qualifier.bMaxPacketSize0 = dev->bMaxPacketSize0;
- d->u.device_qualifier.bNumConfigurations = dev->bNumConfigurations;
- d->u.device_qualifier.bReserved = 0;
-
- return bLength;
-}
-
-int usb_desc_config(const USBDescConfig *conf, int flags,
- uint8_t *dest, size_t len)
-{
- uint8_t bLength = 0x09;
- uint16_t wTotalLength = 0;
- USBDescriptor *d = (void *)dest;
- int i, rc;
-
- if (len < bLength) {
- return -1;
- }
-
- d->bLength = bLength;
- d->bDescriptorType = USB_DT_CONFIG;
-
- d->u.config.bNumInterfaces = conf->bNumInterfaces;
- d->u.config.bConfigurationValue = conf->bConfigurationValue;
- d->u.config.iConfiguration = conf->iConfiguration;
- d->u.config.bmAttributes = conf->bmAttributes;
- d->u.config.bMaxPower = conf->bMaxPower;
- wTotalLength += bLength;
-
- /* handle grouped interfaces if any */
- for (i = 0; i < conf->nif_groups; i++) {
- rc = usb_desc_iface_group(&(conf->if_groups[i]), flags,
- dest + wTotalLength,
- len - wTotalLength);
- if (rc < 0) {
- return rc;
- }
- wTotalLength += rc;
- }
-
- /* handle normal (ungrouped / no IAD) interfaces if any */
- for (i = 0; i < conf->nif; i++) {
- rc = usb_desc_iface(conf->ifs + i, flags,
- dest + wTotalLength, len - wTotalLength);
- if (rc < 0) {
- return rc;
- }
- wTotalLength += rc;
- }
-
- d->u.config.wTotalLength_lo = usb_lo(wTotalLength);
- d->u.config.wTotalLength_hi = usb_hi(wTotalLength);
- return wTotalLength;
-}
-
-int usb_desc_iface_group(const USBDescIfaceAssoc *iad, int flags,
- uint8_t *dest, size_t len)
-{
- int pos = 0;
- int i = 0;
-
- /* handle interface association descriptor */
- uint8_t bLength = 0x08;
-
- if (len < bLength) {
- return -1;
- }
-
- dest[0x00] = bLength;
- dest[0x01] = USB_DT_INTERFACE_ASSOC;
- dest[0x02] = iad->bFirstInterface;
- dest[0x03] = iad->bInterfaceCount;
- dest[0x04] = iad->bFunctionClass;
- dest[0x05] = iad->bFunctionSubClass;
- dest[0x06] = iad->bFunctionProtocol;
- dest[0x07] = iad->iFunction;
- pos += bLength;
-
- /* handle associated interfaces in this group */
- for (i = 0; i < iad->nif; i++) {
- int rc = usb_desc_iface(&(iad->ifs[i]), flags, dest + pos, len - pos);
- if (rc < 0) {
- return rc;
- }
- pos += rc;
- }
-
- return pos;
-}
-
-int usb_desc_iface(const USBDescIface *iface, int flags,
- uint8_t *dest, size_t len)
-{
- uint8_t bLength = 0x09;
- int i, rc, pos = 0;
- USBDescriptor *d = (void *)dest;
-
- if (len < bLength) {
- return -1;
- }
-
- d->bLength = bLength;
- d->bDescriptorType = USB_DT_INTERFACE;
-
- d->u.interface.bInterfaceNumber = iface->bInterfaceNumber;
- d->u.interface.bAlternateSetting = iface->bAlternateSetting;
- d->u.interface.bNumEndpoints = iface->bNumEndpoints;
- d->u.interface.bInterfaceClass = iface->bInterfaceClass;
- d->u.interface.bInterfaceSubClass = iface->bInterfaceSubClass;
- d->u.interface.bInterfaceProtocol = iface->bInterfaceProtocol;
- d->u.interface.iInterface = iface->iInterface;
- pos += bLength;
-
- for (i = 0; i < iface->ndesc; i++) {
- rc = usb_desc_other(iface->descs + i, dest + pos, len - pos);
- if (rc < 0) {
- return rc;
- }
- pos += rc;
- }
-
- for (i = 0; i < iface->bNumEndpoints; i++) {
- rc = usb_desc_endpoint(iface->eps + i, flags, dest + pos, len - pos);
- if (rc < 0) {
- return rc;
- }
- pos += rc;
- }
-
- return pos;
-}
-
-int usb_desc_endpoint(const USBDescEndpoint *ep, int flags,
- uint8_t *dest, size_t len)
-{
- uint8_t bLength = ep->is_audio ? 0x09 : 0x07;
- uint8_t extralen = ep->extra ? ep->extra[0] : 0;
- uint8_t superlen = (flags & USB_DESC_FLAG_SUPER) ? 0x06 : 0;
- USBDescriptor *d = (void *)dest;
-
- if (len < bLength + extralen + superlen) {
- return -1;
- }
-
- d->bLength = bLength;
- d->bDescriptorType = USB_DT_ENDPOINT;
-
- d->u.endpoint.bEndpointAddress = ep->bEndpointAddress;
- d->u.endpoint.bmAttributes = ep->bmAttributes;
- d->u.endpoint.wMaxPacketSize_lo = usb_lo(ep->wMaxPacketSize);
- d->u.endpoint.wMaxPacketSize_hi = usb_hi(ep->wMaxPacketSize);
- d->u.endpoint.bInterval = ep->bInterval;
- if (ep->is_audio) {
- d->u.endpoint.bRefresh = ep->bRefresh;
- d->u.endpoint.bSynchAddress = ep->bSynchAddress;
- }
-
- if (superlen) {
- USBDescriptor *d = (void *)(dest + bLength);
-
- d->bLength = 0x06;
- d->bDescriptorType = USB_DT_ENDPOINT_COMPANION;
-
- d->u.super_endpoint.bMaxBurst = ep->bMaxBurst;
- d->u.super_endpoint.bmAttributes = ep->bmAttributes_super;
- d->u.super_endpoint.wBytesPerInterval_lo =
- usb_lo(ep->wBytesPerInterval);
- d->u.super_endpoint.wBytesPerInterval_hi =
- usb_hi(ep->wBytesPerInterval);
- }
-
- if (ep->extra) {
- memcpy(dest + bLength + superlen, ep->extra, extralen);
- }
-
- return bLength + extralen + superlen;
-}
-
-int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len)
-{
- int bLength = desc->length ? desc->length : desc->data[0];
-
- if (len < bLength) {
- return -1;
- }
-
- memcpy(dest, desc->data, bLength);
- return bLength;
-}
-
-static int usb_desc_cap_usb2_ext(const USBDesc *desc, uint8_t *dest, size_t len)
-{
- uint8_t bLength = 0x07;
- USBDescriptor *d = (void *)dest;
-
- if (len < bLength) {
- return -1;
- }
-
- d->bLength = bLength;
- d->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
- d->u.cap.bDevCapabilityType = USB_DEV_CAP_USB2_EXT;
-
- d->u.cap.u.usb2_ext.bmAttributes_1 = (1 << 1); /* LPM */
- d->u.cap.u.usb2_ext.bmAttributes_2 = 0;
- d->u.cap.u.usb2_ext.bmAttributes_3 = 0;
- d->u.cap.u.usb2_ext.bmAttributes_4 = 0;
-
- return bLength;
-}
-
-static int usb_desc_cap_super(const USBDesc *desc, uint8_t *dest, size_t len)
-{
- uint8_t bLength = 0x0a;
- USBDescriptor *d = (void *)dest;
-
- if (len < bLength) {
- return -1;
- }
-
- d->bLength = bLength;
- d->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
- d->u.cap.bDevCapabilityType = USB_DEV_CAP_SUPERSPEED;
-
- d->u.cap.u.super.bmAttributes = 0;
- d->u.cap.u.super.wSpeedsSupported_lo = 0;
- d->u.cap.u.super.wSpeedsSupported_hi = 0;
- d->u.cap.u.super.bFunctionalitySupport = 0;
- d->u.cap.u.super.bU1DevExitLat = 0x0a;
- d->u.cap.u.super.wU2DevExitLat_lo = 0x20;
- d->u.cap.u.super.wU2DevExitLat_hi = 0;
-
- if (desc->full) {
- d->u.cap.u.super.wSpeedsSupported_lo |= (1 << 1);
- d->u.cap.u.super.bFunctionalitySupport = 1;
- }
- if (desc->high) {
- d->u.cap.u.super.wSpeedsSupported_lo |= (1 << 2);
- if (!d->u.cap.u.super.bFunctionalitySupport) {
- d->u.cap.u.super.bFunctionalitySupport = 2;
- }
- }
- if (desc->super) {
- d->u.cap.u.super.wSpeedsSupported_lo |= (1 << 3);
- if (!d->u.cap.u.super.bFunctionalitySupport) {
- d->u.cap.u.super.bFunctionalitySupport = 3;
- }
- }
-
- return bLength;
-}
-
-static int usb_desc_bos(const USBDesc *desc, uint8_t *dest, size_t len)
-{
- uint8_t bLength = 0x05;
- uint16_t wTotalLength = 0;
- uint8_t bNumDeviceCaps = 0;
- USBDescriptor *d = (void *)dest;
- int rc;
-
- if (len < bLength) {
- return -1;
- }
-
- d->bLength = bLength;
- d->bDescriptorType = USB_DT_BOS;
-
- wTotalLength += bLength;
-
- if (desc->high != NULL) {
- rc = usb_desc_cap_usb2_ext(desc, dest + wTotalLength,
- len - wTotalLength);
- if (rc < 0) {
- return rc;
- }
- wTotalLength += rc;
- bNumDeviceCaps++;
- }
-
- if (desc->super != NULL) {
- rc = usb_desc_cap_super(desc, dest + wTotalLength,
- len - wTotalLength);
- if (rc < 0) {
- return rc;
- }
- wTotalLength += rc;
- bNumDeviceCaps++;
- }
-
- d->u.bos.wTotalLength_lo = usb_lo(wTotalLength);
- d->u.bos.wTotalLength_hi = usb_hi(wTotalLength);
- d->u.bos.bNumDeviceCaps = bNumDeviceCaps;
- return wTotalLength;
-}
-
-/* ------------------------------------------------------------------ */
-
-static void usb_desc_ep_init(USBDevice *dev)
-{
- const USBDescIface *iface;
- int i, e, pid, ep;
-
- usb_ep_init(dev);
- for (i = 0; i < dev->ninterfaces; i++) {
- iface = dev->ifaces[i];
- if (iface == NULL) {
- continue;
- }
- for (e = 0; e < iface->bNumEndpoints; e++) {
- pid = (iface->eps[e].bEndpointAddress & USB_DIR_IN) ?
- USB_TOKEN_IN : USB_TOKEN_OUT;
- ep = iface->eps[e].bEndpointAddress & 0x0f;
- usb_ep_set_type(dev, pid, ep, iface->eps[e].bmAttributes & 0x03);
- usb_ep_set_ifnum(dev, pid, ep, iface->bInterfaceNumber);
- usb_ep_set_max_packet_size(dev, pid, ep,
- iface->eps[e].wMaxPacketSize);
- usb_ep_set_max_streams(dev, pid, ep,
- iface->eps[e].bmAttributes_super);
- }
- }
-}
-
-static const USBDescIface *usb_desc_find_interface(USBDevice *dev,
- int nif, int alt)
-{
- const USBDescIface *iface;
- int g, i;
-
- if (!dev->config) {
- return NULL;
- }
- for (g = 0; g < dev->config->nif_groups; g++) {
- for (i = 0; i < dev->config->if_groups[g].nif; i++) {
- iface = &dev->config->if_groups[g].ifs[i];
- if (iface->bInterfaceNumber == nif &&
- iface->bAlternateSetting == alt) {
- return iface;
- }
- }
- }
- for (i = 0; i < dev->config->nif; i++) {
- iface = &dev->config->ifs[i];
- if (iface->bInterfaceNumber == nif &&
- iface->bAlternateSetting == alt) {
- return iface;
- }
- }
- return NULL;
-}
-
-static int usb_desc_set_interface(USBDevice *dev, int index, int value)
-{
- const USBDescIface *iface;
- int old;
-
- iface = usb_desc_find_interface(dev, index, value);
- if (iface == NULL) {
- return -1;
- }
-
- old = dev->altsetting[index];
- dev->altsetting[index] = value;
- dev->ifaces[index] = iface;
- usb_desc_ep_init(dev);
-
- if (old != value) {
- usb_device_set_interface(dev, index, old, value);
- }
- return 0;
-}
-
-static int usb_desc_set_config(USBDevice *dev, int value)
-{
- int i;
-
- if (value == 0) {
- dev->configuration = 0;
- dev->ninterfaces = 0;
- dev->config = NULL;
- } else {
- for (i = 0; i < dev->device->bNumConfigurations; i++) {
- if (dev->device->confs[i].bConfigurationValue == value) {
- dev->configuration = value;
- dev->ninterfaces = dev->device->confs[i].bNumInterfaces;
- dev->config = dev->device->confs + i;
- assert(dev->ninterfaces <= USB_MAX_INTERFACES);
- }
- }
- if (i < dev->device->bNumConfigurations) {
- return -1;
- }
- }
-
- for (i = 0; i < dev->ninterfaces; i++) {
- usb_desc_set_interface(dev, i, 0);
- }
- for (; i < USB_MAX_INTERFACES; i++) {
- dev->altsetting[i] = 0;
- dev->ifaces[i] = NULL;
- }
-
- return 0;
-}
-
-static void usb_desc_setdefaults(USBDevice *dev)
-{
- const USBDesc *desc = usb_device_get_usb_desc(dev);
-
- assert(desc != NULL);
- switch (dev->speed) {
- case USB_SPEED_LOW:
- case USB_SPEED_FULL:
- dev->device = desc->full;
- break;
- case USB_SPEED_HIGH:
- dev->device = desc->high;
- break;
- case USB_SPEED_SUPER:
- dev->device = desc->super;
- break;
- }
- usb_desc_set_config(dev, 0);
-}
-
-void usb_desc_init(USBDevice *dev)
-{
- const USBDesc *desc = usb_device_get_usb_desc(dev);
-
- assert(desc != NULL);
- dev->speed = USB_SPEED_FULL;
- dev->speedmask = 0;
- if (desc->full) {
- dev->speedmask |= USB_SPEED_MASK_FULL;
- }
- if (desc->high) {
- dev->speedmask |= USB_SPEED_MASK_HIGH;
- }
- if (desc->super) {
- dev->speedmask |= USB_SPEED_MASK_SUPER;
- }
- if (desc->msos && (dev->flags & (1 << USB_DEV_FLAG_MSOS_DESC_ENABLE))) {
- dev->flags |= (1 << USB_DEV_FLAG_MSOS_DESC_IN_USE);
- usb_desc_set_string(dev, 0xee, "MSFT100Q");
- }
- usb_desc_setdefaults(dev);
-}
-
-void usb_desc_attach(USBDevice *dev)
-{
- usb_desc_setdefaults(dev);
-}
-
-void usb_desc_set_string(USBDevice *dev, uint8_t index, const char *str)
-{
- USBDescString *s;
-
- QLIST_FOREACH(s, &dev->strings, next) {
- if (s->index == index) {
- break;
- }
- }
- if (s == NULL) {
- s = g_malloc0(sizeof(*s));
- s->index = index;
- QLIST_INSERT_HEAD(&dev->strings, s, next);
- }
- g_free(s->str);
- s->str = g_strdup(str);
-}
-
-/*
- * This function creates a serial number for a usb device.
- * The serial number should:
- * (a) Be unique within the virtual machine.
- * (b) Be constant, so you don't get a new one each
- * time the guest is started.
- * So we are using the physical location to generate a serial number
- * from it. It has three pieces: First a fixed, device-specific
- * prefix. Second the device path of the host controller (which is
- * the pci address in most cases). Third the physical port path.
- * Results in serial numbers like this: "314159-0000:00:1d.7-3".
- */
-void usb_desc_create_serial(USBDevice *dev)
-{
- DeviceState *hcd = dev->qdev.parent_bus->parent;
- const USBDesc *desc = usb_device_get_usb_desc(dev);
- int index = desc->id.iSerialNumber;
- char serial[64];
- char *path;
- int dst;
-
- if (dev->serial) {
- /* 'serial' usb bus property has priority if present */
- usb_desc_set_string(dev, index, dev->serial);
- return;
- }
-
- assert(index != 0 && desc->str[index] != NULL);
- dst = snprintf(serial, sizeof(serial), "%s", desc->str[index]);
- path = qdev_get_dev_path(hcd);
- if (path) {
- dst += snprintf(serial+dst, sizeof(serial)-dst, "-%s", path);
- }
- dst += snprintf(serial+dst, sizeof(serial)-dst, "-%s", dev->port->path);
- usb_desc_set_string(dev, index, serial);
-}
-
-const char *usb_desc_get_string(USBDevice *dev, uint8_t index)
-{
- USBDescString *s;
-
- QLIST_FOREACH(s, &dev->strings, next) {
- if (s->index == index) {
- return s->str;
- }
- }
- return NULL;
-}
-
-int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len)
-{
- uint8_t bLength, pos, i;
- const char *str;
-
- if (len < 4) {
- return -1;
- }
-
- if (index == 0) {
- /* language ids */
- dest[0] = 4;
- dest[1] = USB_DT_STRING;
- dest[2] = 0x09;
- dest[3] = 0x04;
- return 4;
- }
-
- str = usb_desc_get_string(dev, index);
- if (str == NULL) {
- str = usb_device_get_usb_desc(dev)->str[index];
- if (str == NULL) {
- return 0;
- }
- }
-
- bLength = strlen(str) * 2 + 2;
- dest[0] = bLength;
- dest[1] = USB_DT_STRING;
- i = 0; pos = 2;
- while (pos+1 < bLength && pos+1 < len) {
- dest[pos++] = str[i++];
- dest[pos++] = 0;
- }
- return pos;
-}
-
-int usb_desc_get_descriptor(USBDevice *dev, USBPacket *p,
- int value, uint8_t *dest, size_t len)
-{
- bool msos = (dev->flags & (1 << USB_DEV_FLAG_MSOS_DESC_IN_USE));
- const USBDesc *desc = usb_device_get_usb_desc(dev);
- const USBDescDevice *other_dev;
- uint8_t buf[256];
- uint8_t type = value >> 8;
- uint8_t index = value & 0xff;
- int flags, ret = -1;
-
- if (dev->speed == USB_SPEED_HIGH) {
- other_dev = usb_device_get_usb_desc(dev)->full;
- } else {
- other_dev = usb_device_get_usb_desc(dev)->high;
- }
-
- flags = 0;
- if (dev->device->bcdUSB >= 0x0300) {
- flags |= USB_DESC_FLAG_SUPER;
- }
-
- switch(type) {
- case USB_DT_DEVICE:
- ret = usb_desc_device(&desc->id, dev->device, msos, buf, sizeof(buf));
- trace_usb_desc_device(dev->addr, len, ret);
- break;
- case USB_DT_CONFIG:
- if (index < dev->device->bNumConfigurations) {
- ret = usb_desc_config(dev->device->confs + index, flags,
- buf, sizeof(buf));
- }
- trace_usb_desc_config(dev->addr, index, len, ret);
- break;
- case USB_DT_STRING:
- ret = usb_desc_string(dev, index, buf, sizeof(buf));
- trace_usb_desc_string(dev->addr, index, len, ret);
- break;
- case USB_DT_DEVICE_QUALIFIER:
- if (other_dev != NULL) {
- ret = usb_desc_device_qualifier(other_dev, buf, sizeof(buf));
- }
- trace_usb_desc_device_qualifier(dev->addr, len, ret);
- break;
- case USB_DT_OTHER_SPEED_CONFIG:
- if (other_dev != NULL && index < other_dev->bNumConfigurations) {
- ret = usb_desc_config(other_dev->confs + index, flags,
- buf, sizeof(buf));
- buf[0x01] = USB_DT_OTHER_SPEED_CONFIG;
- }
- trace_usb_desc_other_speed_config(dev->addr, index, len, ret);
- break;
- case USB_DT_BOS:
- ret = usb_desc_bos(desc, buf, sizeof(buf));
- trace_usb_desc_bos(dev->addr, len, ret);
- break;
-
- case USB_DT_DEBUG:
- /* ignore silently */
- break;
-
- default:
- fprintf(stderr, "%s: %d unknown type %d (len %zd)\n", __FUNCTION__,
- dev->addr, type, len);
- break;
- }
-
- if (ret > 0) {
- if (ret > len) {
- ret = len;
- }
- memcpy(dest, buf, ret);
- p->actual_length = ret;
- ret = 0;
- }
- return ret;
-}
-
-int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
- int request, int value, int index, int length, uint8_t *data)
-{
- bool msos = (dev->flags & (1 << USB_DEV_FLAG_MSOS_DESC_IN_USE));
- const USBDesc *desc = usb_device_get_usb_desc(dev);
- int ret = -1;
-
- assert(desc != NULL);
- switch(request) {
- case DeviceOutRequest | USB_REQ_SET_ADDRESS:
- dev->addr = value;
- trace_usb_set_addr(dev->addr);
- ret = 0;
- break;
-
- case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
- ret = usb_desc_get_descriptor(dev, p, value, data, length);
- break;
-
- case DeviceRequest | USB_REQ_GET_CONFIGURATION:
- /*
- * 9.4.2: 0 should be returned if the device is unconfigured, otherwise
- * the non zero value of bConfigurationValue.
- */
- data[0] = dev->config ? dev->config->bConfigurationValue : 0;
- p->actual_length = 1;
- ret = 0;
- break;
- case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
- ret = usb_desc_set_config(dev, value);
- trace_usb_set_config(dev->addr, value, ret);
- break;
-
- case DeviceRequest | USB_REQ_GET_STATUS: {
- const USBDescConfig *config = dev->config ?
- dev->config : &dev->device->confs[0];
-
- data[0] = 0;
- /*
- * Default state: Device behavior when this request is received while
- * the device is in the Default state is not specified.
- * We return the same value that a configured device would return if
- * it used the first configuration.
- */
- if (config->bmAttributes & USB_CFG_ATT_SELFPOWER) {
- data[0] |= 1 << USB_DEVICE_SELF_POWERED;
- }
- if (dev->remote_wakeup) {
- data[0] |= 1 << USB_DEVICE_REMOTE_WAKEUP;
- }
- data[1] = 0x00;
- p->actual_length = 2;
- ret = 0;
- break;
- }
- case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
- if (value == USB_DEVICE_REMOTE_WAKEUP) {
- dev->remote_wakeup = 0;
- ret = 0;
- }
- trace_usb_clear_device_feature(dev->addr, value, ret);
- break;
- case DeviceOutRequest | USB_REQ_SET_FEATURE:
- if (value == USB_DEVICE_REMOTE_WAKEUP) {
- dev->remote_wakeup = 1;
- ret = 0;
- }
- trace_usb_set_device_feature(dev->addr, value, ret);
- break;
-
- case InterfaceRequest | USB_REQ_GET_INTERFACE:
- if (index < 0 || index >= dev->ninterfaces) {
- break;
- }
- data[0] = dev->altsetting[index];
- p->actual_length = 1;
- ret = 0;
- break;
- case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
- ret = usb_desc_set_interface(dev, index, value);
- trace_usb_set_interface(dev->addr, index, value, ret);
- break;
-
- case VendorDeviceRequest | 'Q':
- if (msos) {
- ret = usb_desc_msos(desc, p, index, data, length);
- trace_usb_desc_msos(dev->addr, index, length, ret);
- }
- break;
- case VendorInterfaceRequest | 'Q':
- if (msos) {
- ret = usb_desc_msos(desc, p, index, data, length);
- trace_usb_desc_msos(dev->addr, index, length, ret);
- }
- break;
-
- }
- return ret;
-}
diff --git a/qemu/hw/usb/desc.h b/qemu/hw/usb/desc.h
deleted file mode 100644
index 4d81c68e0..000000000
--- a/qemu/hw/usb/desc.h
+++ /dev/null
@@ -1,244 +0,0 @@
-#ifndef QEMU_HW_USB_DESC_H
-#define QEMU_HW_USB_DESC_H
-
-#include <wchar.h>
-
-/* binary representation */
-typedef struct USBDescriptor {
- uint8_t bLength;
- uint8_t bDescriptorType;
- union {
- struct {
- uint8_t bcdUSB_lo;
- uint8_t bcdUSB_hi;
- uint8_t bDeviceClass;
- uint8_t bDeviceSubClass;
- uint8_t bDeviceProtocol;
- uint8_t bMaxPacketSize0;
- uint8_t idVendor_lo;
- uint8_t idVendor_hi;
- uint8_t idProduct_lo;
- uint8_t idProduct_hi;
- uint8_t bcdDevice_lo;
- uint8_t bcdDevice_hi;
- uint8_t iManufacturer;
- uint8_t iProduct;
- uint8_t iSerialNumber;
- uint8_t bNumConfigurations;
- } device;
- struct {
- uint8_t bcdUSB_lo;
- uint8_t bcdUSB_hi;
- uint8_t bDeviceClass;
- uint8_t bDeviceSubClass;
- uint8_t bDeviceProtocol;
- uint8_t bMaxPacketSize0;
- uint8_t bNumConfigurations;
- uint8_t bReserved;
- } device_qualifier;
- struct {
- uint8_t wTotalLength_lo;
- uint8_t wTotalLength_hi;
- uint8_t bNumInterfaces;
- uint8_t bConfigurationValue;
- uint8_t iConfiguration;
- uint8_t bmAttributes;
- uint8_t bMaxPower;
- } config;
- struct {
- uint8_t bInterfaceNumber;
- uint8_t bAlternateSetting;
- uint8_t bNumEndpoints;
- uint8_t bInterfaceClass;
- uint8_t bInterfaceSubClass;
- uint8_t bInterfaceProtocol;
- uint8_t iInterface;
- } interface;
- struct {
- uint8_t bEndpointAddress;
- uint8_t bmAttributes;
- uint8_t wMaxPacketSize_lo;
- uint8_t wMaxPacketSize_hi;
- uint8_t bInterval;
- uint8_t bRefresh; /* only audio ep */
- uint8_t bSynchAddress; /* only audio ep */
- } endpoint;
- struct {
- uint8_t bMaxBurst;
- uint8_t bmAttributes;
- uint8_t wBytesPerInterval_lo;
- uint8_t wBytesPerInterval_hi;
- } super_endpoint;
- struct {
- uint8_t wTotalLength_lo;
- uint8_t wTotalLength_hi;
- uint8_t bNumDeviceCaps;
- } bos;
- struct {
- uint8_t bDevCapabilityType;
- union {
- struct {
- uint8_t bmAttributes_1;
- uint8_t bmAttributes_2;
- uint8_t bmAttributes_3;
- uint8_t bmAttributes_4;
- } usb2_ext;
- struct {
- uint8_t bmAttributes;
- uint8_t wSpeedsSupported_lo;
- uint8_t wSpeedsSupported_hi;
- uint8_t bFunctionalitySupport;
- uint8_t bU1DevExitLat;
- uint8_t wU2DevExitLat_lo;
- uint8_t wU2DevExitLat_hi;
- } super;
- } u;
- } cap;
- } u;
-} QEMU_PACKED USBDescriptor;
-
-struct USBDescID {
- uint16_t idVendor;
- uint16_t idProduct;
- uint16_t bcdDevice;
- uint8_t iManufacturer;
- uint8_t iProduct;
- uint8_t iSerialNumber;
-};
-
-struct USBDescDevice {
- uint16_t bcdUSB;
- uint8_t bDeviceClass;
- uint8_t bDeviceSubClass;
- uint8_t bDeviceProtocol;
- uint8_t bMaxPacketSize0;
- uint8_t bNumConfigurations;
-
- const USBDescConfig *confs;
-};
-
-struct USBDescConfig {
- uint8_t bNumInterfaces;
- uint8_t bConfigurationValue;
- uint8_t iConfiguration;
- uint8_t bmAttributes;
- uint8_t bMaxPower;
-
- /* grouped interfaces */
- uint8_t nif_groups;
- const USBDescIfaceAssoc *if_groups;
-
- /* "normal" interfaces */
- uint8_t nif;
- const USBDescIface *ifs;
-};
-
-/* conceptually an Interface Association Descriptor, and releated interfaces */
-struct USBDescIfaceAssoc {
- uint8_t bFirstInterface;
- uint8_t bInterfaceCount;
- uint8_t bFunctionClass;
- uint8_t bFunctionSubClass;
- uint8_t bFunctionProtocol;
- uint8_t iFunction;
-
- uint8_t nif;
- const USBDescIface *ifs;
-};
-
-struct USBDescIface {
- uint8_t bInterfaceNumber;
- uint8_t bAlternateSetting;
- uint8_t bNumEndpoints;
- uint8_t bInterfaceClass;
- uint8_t bInterfaceSubClass;
- uint8_t bInterfaceProtocol;
- uint8_t iInterface;
-
- uint8_t ndesc;
- USBDescOther *descs;
- USBDescEndpoint *eps;
-};
-
-struct USBDescEndpoint {
- uint8_t bEndpointAddress;
- uint8_t bmAttributes;
- uint16_t wMaxPacketSize;
- uint8_t bInterval;
- uint8_t bRefresh;
- uint8_t bSynchAddress;
-
- uint8_t is_audio; /* has bRefresh + bSynchAddress */
- uint8_t *extra;
-
- /* superspeed endpoint companion */
- uint8_t bMaxBurst;
- uint8_t bmAttributes_super;
- uint16_t wBytesPerInterval;
-};
-
-struct USBDescOther {
- uint8_t length;
- const uint8_t *data;
-};
-
-struct USBDescMSOS {
- const char *CompatibleID;
- const wchar_t *Label;
- bool SelectiveSuspendEnabled;
-};
-
-typedef const char *USBDescStrings[256];
-
-struct USBDesc {
- USBDescID id;
- const USBDescDevice *full;
- const USBDescDevice *high;
- const USBDescDevice *super;
- const char* const *str;
- const USBDescMSOS *msos;
-};
-
-#define USB_DESC_FLAG_SUPER (1 << 1)
-
-/* little helpers */
-static inline uint8_t usb_lo(uint16_t val)
-{
- return val & 0xff;
-}
-
-static inline uint8_t usb_hi(uint16_t val)
-{
- return (val >> 8) & 0xff;
-}
-
-/* generate usb packages from structs */
-int usb_desc_device(const USBDescID *id, const USBDescDevice *dev,
- bool msos, uint8_t *dest, size_t len);
-int usb_desc_device_qualifier(const USBDescDevice *dev,
- uint8_t *dest, size_t len);
-int usb_desc_config(const USBDescConfig *conf, int flags,
- uint8_t *dest, size_t len);
-int usb_desc_iface_group(const USBDescIfaceAssoc *iad, int flags,
- uint8_t *dest, size_t len);
-int usb_desc_iface(const USBDescIface *iface, int flags,
- uint8_t *dest, size_t len);
-int usb_desc_endpoint(const USBDescEndpoint *ep, int flags,
- uint8_t *dest, size_t len);
-int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len);
-int usb_desc_msos(const USBDesc *desc, USBPacket *p,
- int index, uint8_t *dest, size_t len);
-
-/* control message emulation helpers */
-void usb_desc_init(USBDevice *dev);
-void usb_desc_attach(USBDevice *dev);
-void usb_desc_set_string(USBDevice *dev, uint8_t index, const char *str);
-void usb_desc_create_serial(USBDevice *dev);
-const char *usb_desc_get_string(USBDevice *dev, uint8_t index);
-int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len);
-int usb_desc_get_descriptor(USBDevice *dev, USBPacket *p,
- int value, uint8_t *dest, size_t len);
-int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
- int request, int value, int index, int length, uint8_t *data);
-
-#endif /* QEMU_HW_USB_DESC_H */
diff --git a/qemu/hw/usb/dev-audio.c b/qemu/hw/usb/dev-audio.c
deleted file mode 100644
index 87cab0a3d..000000000
--- a/qemu/hw/usb/dev-audio.c
+++ /dev/null
@@ -1,703 +0,0 @@
-/*
- * QEMU USB audio device
- *
- * written by:
- * H. Peter Anvin <hpa@linux.intel.com>
- * Gerd Hoffmann <kraxel@redhat.com>
- *
- * lousely based on usb net device code which is:
- *
- * Copyright (c) 2006 Thomas Sailer
- * Copyright (c) 2008 Andrzej Zaborowski
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "hw/usb.h"
-#include "hw/usb/desc.h"
-#include "hw/hw.h"
-#include "audio/audio.h"
-
-#define USBAUDIO_VENDOR_NUM 0x46f4 /* CRC16() of "QEMU" */
-#define USBAUDIO_PRODUCT_NUM 0x0002
-
-#define DEV_CONFIG_VALUE 1 /* The one and only */
-
-/* Descriptor subtypes for AC interfaces */
-#define DST_AC_HEADER 1
-#define DST_AC_INPUT_TERMINAL 2
-#define DST_AC_OUTPUT_TERMINAL 3
-#define DST_AC_FEATURE_UNIT 6
-/* Descriptor subtypes for AS interfaces */
-#define DST_AS_GENERAL 1
-#define DST_AS_FORMAT_TYPE 2
-/* Descriptor subtypes for endpoints */
-#define DST_EP_GENERAL 1
-
-enum usb_audio_strings {
- STRING_NULL,
- STRING_MANUFACTURER,
- STRING_PRODUCT,
- STRING_SERIALNUMBER,
- STRING_CONFIG,
- STRING_USBAUDIO_CONTROL,
- STRING_INPUT_TERMINAL,
- STRING_FEATURE_UNIT,
- STRING_OUTPUT_TERMINAL,
- STRING_NULL_STREAM,
- STRING_REAL_STREAM,
-};
-
-static const USBDescStrings usb_audio_stringtable = {
- [STRING_MANUFACTURER] = "QEMU",
- [STRING_PRODUCT] = "QEMU USB Audio",
- [STRING_SERIALNUMBER] = "1",
- [STRING_CONFIG] = "Audio Configuration",
- [STRING_USBAUDIO_CONTROL] = "Audio Device",
- [STRING_INPUT_TERMINAL] = "Audio Output Pipe",
- [STRING_FEATURE_UNIT] = "Audio Output Volume Control",
- [STRING_OUTPUT_TERMINAL] = "Audio Output Terminal",
- [STRING_NULL_STREAM] = "Audio Output - Disabled",
- [STRING_REAL_STREAM] = "Audio Output - 48 kHz Stereo",
-};
-
-#define U16(x) ((x) & 0xff), (((x) >> 8) & 0xff)
-#define U24(x) U16(x), (((x) >> 16) & 0xff)
-#define U32(x) U24(x), (((x) >> 24) & 0xff)
-
-/*
- * A Basic Audio Device uses these specific values
- */
-#define USBAUDIO_PACKET_SIZE 192
-#define USBAUDIO_SAMPLE_RATE 48000
-#define USBAUDIO_PACKET_INTERVAL 1
-
-static const USBDescIface desc_iface[] = {
- {
- .bInterfaceNumber = 0,
- .bNumEndpoints = 0,
- .bInterfaceClass = USB_CLASS_AUDIO,
- .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL,
- .bInterfaceProtocol = 0x04,
- .iInterface = STRING_USBAUDIO_CONTROL,
- .ndesc = 4,
- .descs = (USBDescOther[]) {
- {
- /* Headphone Class-Specific AC Interface Header Descriptor */
- .data = (uint8_t[]) {
- 0x09, /* u8 bLength */
- USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
- DST_AC_HEADER, /* u8 bDescriptorSubtype */
- U16(0x0100), /* u16 bcdADC */
- U16(0x2b), /* u16 wTotalLength */
- 0x01, /* u8 bInCollection */
- 0x01, /* u8 baInterfaceNr */
- }
- },{
- /* Generic Stereo Input Terminal ID1 Descriptor */
- .data = (uint8_t[]) {
- 0x0c, /* u8 bLength */
- USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
- DST_AC_INPUT_TERMINAL, /* u8 bDescriptorSubtype */
- 0x01, /* u8 bTerminalID */
- U16(0x0101), /* u16 wTerminalType */
- 0x00, /* u8 bAssocTerminal */
- 0x02, /* u16 bNrChannels */
- U16(0x0003), /* u16 wChannelConfig */
- 0x00, /* u8 iChannelNames */
- STRING_INPUT_TERMINAL, /* u8 iTerminal */
- }
- },{
- /* Generic Stereo Feature Unit ID2 Descriptor */
- .data = (uint8_t[]) {
- 0x0d, /* u8 bLength */
- USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
- DST_AC_FEATURE_UNIT, /* u8 bDescriptorSubtype */
- 0x02, /* u8 bUnitID */
- 0x01, /* u8 bSourceID */
- 0x02, /* u8 bControlSize */
- U16(0x0001), /* u16 bmaControls(0) */
- U16(0x0002), /* u16 bmaControls(1) */
- U16(0x0002), /* u16 bmaControls(2) */
- STRING_FEATURE_UNIT, /* u8 iFeature */
- }
- },{
- /* Headphone Ouptut Terminal ID3 Descriptor */
- .data = (uint8_t[]) {
- 0x09, /* u8 bLength */
- USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
- DST_AC_OUTPUT_TERMINAL, /* u8 bDescriptorSubtype */
- 0x03, /* u8 bUnitID */
- U16(0x0301), /* u16 wTerminalType (SPK) */
- 0x00, /* u8 bAssocTerminal */
- 0x02, /* u8 bSourceID */
- STRING_OUTPUT_TERMINAL, /* u8 iTerminal */
- }
- }
- },
- },{
- .bInterfaceNumber = 1,
- .bAlternateSetting = 0,
- .bNumEndpoints = 0,
- .bInterfaceClass = USB_CLASS_AUDIO,
- .bInterfaceSubClass = USB_SUBCLASS_AUDIO_STREAMING,
- .iInterface = STRING_NULL_STREAM,
- },{
- .bInterfaceNumber = 1,
- .bAlternateSetting = 1,
- .bNumEndpoints = 1,
- .bInterfaceClass = USB_CLASS_AUDIO,
- .bInterfaceSubClass = USB_SUBCLASS_AUDIO_STREAMING,
- .iInterface = STRING_REAL_STREAM,
- .ndesc = 2,
- .descs = (USBDescOther[]) {
- {
- /* Headphone Class-specific AS General Interface Descriptor */
- .data = (uint8_t[]) {
- 0x07, /* u8 bLength */
- USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
- DST_AS_GENERAL, /* u8 bDescriptorSubtype */
- 0x01, /* u8 bTerminalLink */
- 0x00, /* u8 bDelay */
- 0x01, 0x00, /* u16 wFormatTag */
- }
- },{
- /* Headphone Type I Format Type Descriptor */
- .data = (uint8_t[]) {
- 0x0b, /* u8 bLength */
- USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
- DST_AS_FORMAT_TYPE, /* u8 bDescriptorSubtype */
- 0x01, /* u8 bFormatType */
- 0x02, /* u8 bNrChannels */
- 0x02, /* u8 bSubFrameSize */
- 0x10, /* u8 bBitResolution */
- 0x01, /* u8 bSamFreqType */
- U24(USBAUDIO_SAMPLE_RATE), /* u24 tSamFreq */
- }
- }
- },
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_OUT | 0x01,
- .bmAttributes = 0x0d,
- .wMaxPacketSize = USBAUDIO_PACKET_SIZE,
- .bInterval = 1,
- .is_audio = 1,
- /* Stereo Headphone Class-specific
- AS Audio Data Endpoint Descriptor */
- .extra = (uint8_t[]) {
- 0x07, /* u8 bLength */
- USB_DT_CS_ENDPOINT, /* u8 bDescriptorType */
- DST_EP_GENERAL, /* u8 bDescriptorSubtype */
- 0x00, /* u8 bmAttributes */
- 0x00, /* u8 bLockDelayUnits */
- U16(0x0000), /* u16 wLockDelay */
- },
- },
- }
- }
-};
-
-static const USBDescDevice desc_device = {
- .bcdUSB = 0x0100,
- .bMaxPacketSize0 = 64,
- .bNumConfigurations = 1,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 2,
- .bConfigurationValue = DEV_CONFIG_VALUE,
- .iConfiguration = STRING_CONFIG,
- .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
- .bMaxPower = 0x32,
- .nif = ARRAY_SIZE(desc_iface),
- .ifs = desc_iface,
- },
- },
-};
-
-static const USBDesc desc_audio = {
- .id = {
- .idVendor = USBAUDIO_VENDOR_NUM,
- .idProduct = USBAUDIO_PRODUCT_NUM,
- .bcdDevice = 0,
- .iManufacturer = STRING_MANUFACTURER,
- .iProduct = STRING_PRODUCT,
- .iSerialNumber = STRING_SERIALNUMBER,
- },
- .full = &desc_device,
- .str = usb_audio_stringtable,
-};
-
-/*
- * A USB audio device supports an arbitrary number of alternate
- * interface settings for each interface. Each corresponds to a block
- * diagram of parameterized blocks. This can thus refer to things like
- * number of channels, data rates, or in fact completely different
- * block diagrams. Alternative setting 0 is always the null block diagram,
- * which is used by a disabled device.
- */
-enum usb_audio_altset {
- ALTSET_OFF = 0x00, /* No endpoint */
- ALTSET_ON = 0x01, /* Single endpoint */
-};
-
-/*
- * Class-specific control requests
- */
-#define CR_SET_CUR 0x01
-#define CR_GET_CUR 0x81
-#define CR_SET_MIN 0x02
-#define CR_GET_MIN 0x82
-#define CR_SET_MAX 0x03
-#define CR_GET_MAX 0x83
-#define CR_SET_RES 0x04
-#define CR_GET_RES 0x84
-#define CR_SET_MEM 0x05
-#define CR_GET_MEM 0x85
-#define CR_GET_STAT 0xff
-
-/*
- * Feature Unit Control Selectors
- */
-#define MUTE_CONTROL 0x01
-#define VOLUME_CONTROL 0x02
-#define BASS_CONTROL 0x03
-#define MID_CONTROL 0x04
-#define TREBLE_CONTROL 0x05
-#define GRAPHIC_EQUALIZER_CONTROL 0x06
-#define AUTOMATIC_GAIN_CONTROL 0x07
-#define DELAY_CONTROL 0x08
-#define BASS_BOOST_CONTROL 0x09
-#define LOUDNESS_CONTROL 0x0a
-
-/*
- * buffering
- */
-
-struct streambuf {
- uint8_t *data;
- uint32_t size;
- uint32_t prod;
- uint32_t cons;
-};
-
-static void streambuf_init(struct streambuf *buf, uint32_t size)
-{
- g_free(buf->data);
- buf->size = size - (size % USBAUDIO_PACKET_SIZE);
- buf->data = g_malloc(buf->size);
- buf->prod = 0;
- buf->cons = 0;
-}
-
-static void streambuf_fini(struct streambuf *buf)
-{
- g_free(buf->data);
- buf->data = NULL;
-}
-
-static int streambuf_put(struct streambuf *buf, USBPacket *p)
-{
- uint32_t free = buf->size - (buf->prod - buf->cons);
-
- if (!free) {
- return 0;
- }
- assert(free >= USBAUDIO_PACKET_SIZE);
- usb_packet_copy(p, buf->data + (buf->prod % buf->size),
- USBAUDIO_PACKET_SIZE);
- buf->prod += USBAUDIO_PACKET_SIZE;
- return USBAUDIO_PACKET_SIZE;
-}
-
-static uint8_t *streambuf_get(struct streambuf *buf)
-{
- uint32_t used = buf->prod - buf->cons;
- uint8_t *data;
-
- if (!used) {
- return NULL;
- }
- assert(used >= USBAUDIO_PACKET_SIZE);
- data = buf->data + (buf->cons % buf->size);
- buf->cons += USBAUDIO_PACKET_SIZE;
- return data;
-}
-
-typedef struct USBAudioState {
- /* qemu interfaces */
- USBDevice dev;
- QEMUSoundCard card;
-
- /* state */
- struct {
- enum usb_audio_altset altset;
- struct audsettings as;
- SWVoiceOut *voice;
- bool mute;
- uint8_t vol[2];
- struct streambuf buf;
- } out;
-
- /* properties */
- uint32_t debug;
- uint32_t buffer;
-} USBAudioState;
-
-#define TYPE_USB_AUDIO "usb-audio"
-#define USB_AUDIO(obj) OBJECT_CHECK(USBAudioState, (obj), TYPE_USB_AUDIO)
-
-static void output_callback(void *opaque, int avail)
-{
- USBAudioState *s = opaque;
- uint8_t *data;
-
- for (;;) {
- if (avail < USBAUDIO_PACKET_SIZE) {
- return;
- }
- data = streambuf_get(&s->out.buf);
- if (!data) {
- return;
- }
- AUD_write(s->out.voice, data, USBAUDIO_PACKET_SIZE);
- avail -= USBAUDIO_PACKET_SIZE;
- }
-}
-
-static int usb_audio_set_output_altset(USBAudioState *s, int altset)
-{
- switch (altset) {
- case ALTSET_OFF:
- streambuf_init(&s->out.buf, s->buffer);
- AUD_set_active_out(s->out.voice, false);
- break;
- case ALTSET_ON:
- AUD_set_active_out(s->out.voice, true);
- break;
- default:
- return -1;
- }
-
- if (s->debug) {
- fprintf(stderr, "usb-audio: set interface %d\n", altset);
- }
- s->out.altset = altset;
- return 0;
-}
-
-/*
- * Note: we arbitrarily map the volume control range onto -inf..+8 dB
- */
-#define ATTRIB_ID(cs, attrib, idif) \
- (((cs) << 24) | ((attrib) << 16) | (idif))
-
-static int usb_audio_get_control(USBAudioState *s, uint8_t attrib,
- uint16_t cscn, uint16_t idif,
- int length, uint8_t *data)
-{
- uint8_t cs = cscn >> 8;
- uint8_t cn = cscn - 1; /* -1 for the non-present master control */
- uint32_t aid = ATTRIB_ID(cs, attrib, idif);
- int ret = USB_RET_STALL;
-
- switch (aid) {
- case ATTRIB_ID(MUTE_CONTROL, CR_GET_CUR, 0x0200):
- data[0] = s->out.mute;
- ret = 1;
- break;
- case ATTRIB_ID(VOLUME_CONTROL, CR_GET_CUR, 0x0200):
- if (cn < 2) {
- uint16_t vol = (s->out.vol[cn] * 0x8800 + 127) / 255 + 0x8000;
- data[0] = vol;
- data[1] = vol >> 8;
- ret = 2;
- }
- break;
- case ATTRIB_ID(VOLUME_CONTROL, CR_GET_MIN, 0x0200):
- if (cn < 2) {
- data[0] = 0x01;
- data[1] = 0x80;
- ret = 2;
- }
- break;
- case ATTRIB_ID(VOLUME_CONTROL, CR_GET_MAX, 0x0200):
- if (cn < 2) {
- data[0] = 0x00;
- data[1] = 0x08;
- ret = 2;
- }
- break;
- case ATTRIB_ID(VOLUME_CONTROL, CR_GET_RES, 0x0200):
- if (cn < 2) {
- data[0] = 0x88;
- data[1] = 0x00;
- ret = 2;
- }
- break;
- }
-
- return ret;
-}
-static int usb_audio_set_control(USBAudioState *s, uint8_t attrib,
- uint16_t cscn, uint16_t idif,
- int length, uint8_t *data)
-{
- uint8_t cs = cscn >> 8;
- uint8_t cn = cscn - 1; /* -1 for the non-present master control */
- uint32_t aid = ATTRIB_ID(cs, attrib, idif);
- int ret = USB_RET_STALL;
- bool set_vol = false;
-
- switch (aid) {
- case ATTRIB_ID(MUTE_CONTROL, CR_SET_CUR, 0x0200):
- s->out.mute = data[0] & 1;
- set_vol = true;
- ret = 0;
- break;
- case ATTRIB_ID(VOLUME_CONTROL, CR_SET_CUR, 0x0200):
- if (cn < 2) {
- uint16_t vol = data[0] + (data[1] << 8);
-
- if (s->debug) {
- fprintf(stderr, "usb-audio: vol %04x\n", (uint16_t)vol);
- }
-
- vol -= 0x8000;
- vol = (vol * 255 + 0x4400) / 0x8800;
- if (vol > 255) {
- vol = 255;
- }
-
- s->out.vol[cn] = vol;
- set_vol = true;
- ret = 0;
- }
- break;
- }
-
- if (set_vol) {
- if (s->debug) {
- fprintf(stderr, "usb-audio: mute %d, lvol %3d, rvol %3d\n",
- s->out.mute, s->out.vol[0], s->out.vol[1]);
- }
- AUD_set_volume_out(s->out.voice, s->out.mute,
- s->out.vol[0], s->out.vol[1]);
- }
-
- return ret;
-}
-
-static void usb_audio_handle_control(USBDevice *dev, USBPacket *p,
- int request, int value, int index,
- int length, uint8_t *data)
-{
- USBAudioState *s = USB_AUDIO(dev);
- int ret = 0;
-
- if (s->debug) {
- fprintf(stderr, "usb-audio: control transaction: "
- "request 0x%04x value 0x%04x index 0x%04x length 0x%04x\n",
- request, value, index, length);
- }
-
- ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
- if (ret >= 0) {
- return;
- }
-
- switch (request) {
- case ClassInterfaceRequest | CR_GET_CUR:
- case ClassInterfaceRequest | CR_GET_MIN:
- case ClassInterfaceRequest | CR_GET_MAX:
- case ClassInterfaceRequest | CR_GET_RES:
- ret = usb_audio_get_control(s, request & 0xff, value, index,
- length, data);
- if (ret < 0) {
- if (s->debug) {
- fprintf(stderr, "usb-audio: fail: get control\n");
- }
- goto fail;
- }
- p->actual_length = ret;
- break;
-
- case ClassInterfaceOutRequest | CR_SET_CUR:
- case ClassInterfaceOutRequest | CR_SET_MIN:
- case ClassInterfaceOutRequest | CR_SET_MAX:
- case ClassInterfaceOutRequest | CR_SET_RES:
- ret = usb_audio_set_control(s, request & 0xff, value, index,
- length, data);
- if (ret < 0) {
- if (s->debug) {
- fprintf(stderr, "usb-audio: fail: set control\n");
- }
- goto fail;
- }
- break;
-
- default:
-fail:
- if (s->debug) {
- fprintf(stderr, "usb-audio: failed control transaction: "
- "request 0x%04x value 0x%04x index 0x%04x length 0x%04x\n",
- request, value, index, length);
- }
- p->status = USB_RET_STALL;
- break;
- }
-}
-
-static void usb_audio_set_interface(USBDevice *dev, int iface,
- int old, int value)
-{
- USBAudioState *s = USB_AUDIO(dev);
-
- if (iface == 1) {
- usb_audio_set_output_altset(s, value);
- }
-}
-
-static void usb_audio_handle_reset(USBDevice *dev)
-{
- USBAudioState *s = USB_AUDIO(dev);
-
- if (s->debug) {
- fprintf(stderr, "usb-audio: reset\n");
- }
- usb_audio_set_output_altset(s, ALTSET_OFF);
-}
-
-static void usb_audio_handle_dataout(USBAudioState *s, USBPacket *p)
-{
- if (s->out.altset == ALTSET_OFF) {
- p->status = USB_RET_STALL;
- return;
- }
-
- streambuf_put(&s->out.buf, p);
- if (p->actual_length < p->iov.size && s->debug > 1) {
- fprintf(stderr, "usb-audio: output overrun (%zd bytes)\n",
- p->iov.size - p->actual_length);
- }
-}
-
-static void usb_audio_handle_data(USBDevice *dev, USBPacket *p)
-{
- USBAudioState *s = (USBAudioState *) dev;
-
- if (p->pid == USB_TOKEN_OUT && p->ep->nr == 1) {
- usb_audio_handle_dataout(s, p);
- return;
- }
-
- p->status = USB_RET_STALL;
- if (s->debug) {
- fprintf(stderr, "usb-audio: failed data transaction: "
- "pid 0x%x ep 0x%x len 0x%zx\n",
- p->pid, p->ep->nr, p->iov.size);
- }
-}
-
-static void usb_audio_handle_destroy(USBDevice *dev)
-{
- USBAudioState *s = USB_AUDIO(dev);
-
- if (s->debug) {
- fprintf(stderr, "usb-audio: destroy\n");
- }
-
- usb_audio_set_output_altset(s, ALTSET_OFF);
- AUD_close_out(&s->card, s->out.voice);
- AUD_remove_card(&s->card);
-
- streambuf_fini(&s->out.buf);
-}
-
-static void usb_audio_realize(USBDevice *dev, Error **errp)
-{
- USBAudioState *s = USB_AUDIO(dev);
-
- usb_desc_create_serial(dev);
- usb_desc_init(dev);
- s->dev.opaque = s;
- AUD_register_card(TYPE_USB_AUDIO, &s->card);
-
- s->out.altset = ALTSET_OFF;
- s->out.mute = false;
- s->out.vol[0] = 240; /* 0 dB */
- s->out.vol[1] = 240; /* 0 dB */
- s->out.as.freq = USBAUDIO_SAMPLE_RATE;
- s->out.as.nchannels = 2;
- s->out.as.fmt = AUD_FMT_S16;
- s->out.as.endianness = 0;
- streambuf_init(&s->out.buf, s->buffer);
-
- s->out.voice = AUD_open_out(&s->card, s->out.voice, TYPE_USB_AUDIO,
- s, output_callback, &s->out.as);
- AUD_set_volume_out(s->out.voice, s->out.mute, s->out.vol[0], s->out.vol[1]);
- AUD_set_active_out(s->out.voice, 0);
-}
-
-static const VMStateDescription vmstate_usb_audio = {
- .name = TYPE_USB_AUDIO,
- .unmigratable = 1,
-};
-
-static Property usb_audio_properties[] = {
- DEFINE_PROP_UINT32("debug", USBAudioState, debug, 0),
- DEFINE_PROP_UINT32("buffer", USBAudioState, buffer,
- 32 * USBAUDIO_PACKET_SIZE),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void usb_audio_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- USBDeviceClass *k = USB_DEVICE_CLASS(klass);
-
- dc->vmsd = &vmstate_usb_audio;
- dc->props = usb_audio_properties;
- set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
- k->product_desc = "QEMU USB Audio Interface";
- k->usb_desc = &desc_audio;
- k->realize = usb_audio_realize;
- k->handle_reset = usb_audio_handle_reset;
- k->handle_control = usb_audio_handle_control;
- k->handle_data = usb_audio_handle_data;
- k->handle_destroy = usb_audio_handle_destroy;
- k->set_interface = usb_audio_set_interface;
-}
-
-static const TypeInfo usb_audio_info = {
- .name = TYPE_USB_AUDIO,
- .parent = TYPE_USB_DEVICE,
- .instance_size = sizeof(USBAudioState),
- .class_init = usb_audio_class_init,
-};
-
-static void usb_audio_register_types(void)
-{
- type_register_static(&usb_audio_info);
- usb_legacy_register(TYPE_USB_AUDIO, "audio", NULL);
-}
-
-type_init(usb_audio_register_types)
diff --git a/qemu/hw/usb/dev-bluetooth.c b/qemu/hw/usb/dev-bluetooth.c
deleted file mode 100644
index 91a4a0b8b..000000000
--- a/qemu/hw/usb/dev-bluetooth.c
+++ /dev/null
@@ -1,580 +0,0 @@
-/*
- * QEMU Bluetooth HCI USB Transport Layer v1.0
- *
- * Copyright (C) 2007 OpenMoko, Inc.
- * Copyright (C) 2008 Andrzej Zaborowski <balrog@zabor.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "qemu/error-report.h"
-#include "hw/usb.h"
-#include "hw/usb/desc.h"
-#include "sysemu/bt.h"
-#include "hw/bt.h"
-
-struct USBBtState {
- USBDevice dev;
- struct HCIInfo *hci;
- USBEndpoint *intr;
-
- int config;
-
-#define CFIFO_LEN_MASK 255
-#define DFIFO_LEN_MASK 4095
- struct usb_hci_in_fifo_s {
- uint8_t data[(DFIFO_LEN_MASK + 1) * 2];
- struct {
- uint8_t *data;
- int len;
- } fifo[CFIFO_LEN_MASK + 1];
- int dstart, dlen, dsize, start, len;
- } evt, acl, sco;
-
- struct usb_hci_out_fifo_s {
- uint8_t data[4096];
- int len;
- } outcmd, outacl, outsco;
-};
-
-#define TYPE_USB_BT "usb-bt-dongle"
-#define USB_BT(obj) OBJECT_CHECK(struct USBBtState, (obj), TYPE_USB_BT)
-
-#define USB_EVT_EP 1
-#define USB_ACL_EP 2
-#define USB_SCO_EP 3
-
-enum {
- STR_MANUFACTURER = 1,
- STR_SERIALNUMBER,
-};
-
-static const USBDescStrings desc_strings = {
- [STR_MANUFACTURER] = "QEMU",
- [STR_SERIALNUMBER] = "1",
-};
-
-static const USBDescIface desc_iface_bluetooth[] = {
- {
- .bInterfaceNumber = 0,
- .bNumEndpoints = 3,
- .bInterfaceClass = 0xe0, /* Wireless */
- .bInterfaceSubClass = 0x01, /* Radio Frequency */
- .bInterfaceProtocol = 0x01, /* Bluetooth */
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | USB_EVT_EP,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = 0x10,
- .bInterval = 0x02,
- },
- {
- .bEndpointAddress = USB_DIR_OUT | USB_ACL_EP,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 0x40,
- .bInterval = 0x0a,
- },
- {
- .bEndpointAddress = USB_DIR_IN | USB_ACL_EP,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 0x40,
- .bInterval = 0x0a,
- },
- },
- },{
- .bInterfaceNumber = 1,
- .bAlternateSetting = 0,
- .bNumEndpoints = 2,
- .bInterfaceClass = 0xe0, /* Wireless */
- .bInterfaceSubClass = 0x01, /* Radio Frequency */
- .bInterfaceProtocol = 0x01, /* Bluetooth */
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP,
- .bmAttributes = USB_ENDPOINT_XFER_ISOC,
- .wMaxPacketSize = 0,
- .bInterval = 0x01,
- },
- {
- .bEndpointAddress = USB_DIR_IN | USB_SCO_EP,
- .bmAttributes = USB_ENDPOINT_XFER_ISOC,
- .wMaxPacketSize = 0,
- .bInterval = 0x01,
- },
- },
- },{
- .bInterfaceNumber = 1,
- .bAlternateSetting = 1,
- .bNumEndpoints = 2,
- .bInterfaceClass = 0xe0, /* Wireless */
- .bInterfaceSubClass = 0x01, /* Radio Frequency */
- .bInterfaceProtocol = 0x01, /* Bluetooth */
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP,
- .bmAttributes = USB_ENDPOINT_XFER_ISOC,
- .wMaxPacketSize = 0x09,
- .bInterval = 0x01,
- },
- {
- .bEndpointAddress = USB_DIR_IN | USB_SCO_EP,
- .bmAttributes = USB_ENDPOINT_XFER_ISOC,
- .wMaxPacketSize = 0x09,
- .bInterval = 0x01,
- },
- },
- },{
- .bInterfaceNumber = 1,
- .bAlternateSetting = 2,
- .bNumEndpoints = 2,
- .bInterfaceClass = 0xe0, /* Wireless */
- .bInterfaceSubClass = 0x01, /* Radio Frequency */
- .bInterfaceProtocol = 0x01, /* Bluetooth */
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP,
- .bmAttributes = USB_ENDPOINT_XFER_ISOC,
- .wMaxPacketSize = 0x11,
- .bInterval = 0x01,
- },
- {
- .bEndpointAddress = USB_DIR_IN | USB_SCO_EP,
- .bmAttributes = USB_ENDPOINT_XFER_ISOC,
- .wMaxPacketSize = 0x11,
- .bInterval = 0x01,
- },
- },
- },{
- .bInterfaceNumber = 1,
- .bAlternateSetting = 3,
- .bNumEndpoints = 2,
- .bInterfaceClass = 0xe0, /* Wireless */
- .bInterfaceSubClass = 0x01, /* Radio Frequency */
- .bInterfaceProtocol = 0x01, /* Bluetooth */
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP,
- .bmAttributes = USB_ENDPOINT_XFER_ISOC,
- .wMaxPacketSize = 0x19,
- .bInterval = 0x01,
- },
- {
- .bEndpointAddress = USB_DIR_IN | USB_SCO_EP,
- .bmAttributes = USB_ENDPOINT_XFER_ISOC,
- .wMaxPacketSize = 0x19,
- .bInterval = 0x01,
- },
- },
- },{
- .bInterfaceNumber = 1,
- .bAlternateSetting = 4,
- .bNumEndpoints = 2,
- .bInterfaceClass = 0xe0, /* Wireless */
- .bInterfaceSubClass = 0x01, /* Radio Frequency */
- .bInterfaceProtocol = 0x01, /* Bluetooth */
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP,
- .bmAttributes = USB_ENDPOINT_XFER_ISOC,
- .wMaxPacketSize = 0x21,
- .bInterval = 0x01,
- },
- {
- .bEndpointAddress = USB_DIR_IN | USB_SCO_EP,
- .bmAttributes = USB_ENDPOINT_XFER_ISOC,
- .wMaxPacketSize = 0x21,
- .bInterval = 0x01,
- },
- },
- },{
- .bInterfaceNumber = 1,
- .bAlternateSetting = 5,
- .bNumEndpoints = 2,
- .bInterfaceClass = 0xe0, /* Wireless */
- .bInterfaceSubClass = 0x01, /* Radio Frequency */
- .bInterfaceProtocol = 0x01, /* Bluetooth */
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP,
- .bmAttributes = USB_ENDPOINT_XFER_ISOC,
- .wMaxPacketSize = 0x31,
- .bInterval = 0x01,
- },
- {
- .bEndpointAddress = USB_DIR_IN | USB_SCO_EP,
- .bmAttributes = USB_ENDPOINT_XFER_ISOC,
- .wMaxPacketSize = 0x31,
- .bInterval = 0x01,
- },
- },
- }
-};
-
-static const USBDescDevice desc_device_bluetooth = {
- .bcdUSB = 0x0110,
- .bDeviceClass = 0xe0, /* Wireless */
- .bDeviceSubClass = 0x01, /* Radio Frequency */
- .bDeviceProtocol = 0x01, /* Bluetooth */
- .bMaxPacketSize0 = 64,
- .bNumConfigurations = 1,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 2,
- .bConfigurationValue = 1,
- .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
- .bMaxPower = 0,
- .nif = ARRAY_SIZE(desc_iface_bluetooth),
- .ifs = desc_iface_bluetooth,
- },
- },
-};
-
-static const USBDesc desc_bluetooth = {
- .id = {
- .idVendor = 0x0a12,
- .idProduct = 0x0001,
- .bcdDevice = 0x1958,
- .iManufacturer = STR_MANUFACTURER,
- .iProduct = 0,
- .iSerialNumber = STR_SERIALNUMBER,
- },
- .full = &desc_device_bluetooth,
- .str = desc_strings,
-};
-
-static void usb_bt_fifo_reset(struct usb_hci_in_fifo_s *fifo)
-{
- fifo->dstart = 0;
- fifo->dlen = 0;
- fifo->dsize = DFIFO_LEN_MASK + 1;
- fifo->start = 0;
- fifo->len = 0;
-}
-
-static void usb_bt_fifo_enqueue(struct usb_hci_in_fifo_s *fifo,
- const uint8_t *data, int len)
-{
- int off = fifo->dstart + fifo->dlen;
- uint8_t *buf;
-
- fifo->dlen += len;
- if (off <= DFIFO_LEN_MASK) {
- if (off + len > DFIFO_LEN_MASK + 1 &&
- (fifo->dsize = off + len) > (DFIFO_LEN_MASK + 1) * 2) {
- fprintf(stderr, "%s: can't alloc %i bytes\n", __FUNCTION__, len);
- exit(-1);
- }
- buf = fifo->data + off;
- } else {
- if (fifo->dlen > fifo->dsize) {
- fprintf(stderr, "%s: can't alloc %i bytes\n", __FUNCTION__, len);
- exit(-1);
- }
- buf = fifo->data + off - fifo->dsize;
- }
-
- off = (fifo->start + fifo->len ++) & CFIFO_LEN_MASK;
- fifo->fifo[off].data = memcpy(buf, data, len);
- fifo->fifo[off].len = len;
-}
-
-static inline void usb_bt_fifo_dequeue(struct usb_hci_in_fifo_s *fifo,
- USBPacket *p)
-{
- int len;
-
- assert(fifo->len != 0);
-
- len = MIN(p->iov.size, fifo->fifo[fifo->start].len);
- usb_packet_copy(p, fifo->fifo[fifo->start].data, len);
- if (len == p->iov.size) {
- fifo->fifo[fifo->start].len -= len;
- fifo->fifo[fifo->start].data += len;
- } else {
- fifo->start ++;
- fifo->start &= CFIFO_LEN_MASK;
- fifo->len --;
- }
-
- fifo->dstart += len;
- fifo->dlen -= len;
- if (fifo->dstart >= fifo->dsize) {
- fifo->dstart = 0;
- fifo->dsize = DFIFO_LEN_MASK + 1;
- }
-}
-
-static inline void usb_bt_fifo_out_enqueue(struct USBBtState *s,
- struct usb_hci_out_fifo_s *fifo,
- void (*send)(struct HCIInfo *, const uint8_t *, int),
- int (*complete)(const uint8_t *, int),
- USBPacket *p)
-{
- usb_packet_copy(p, fifo->data + fifo->len, p->iov.size);
- fifo->len += p->iov.size;
- if (complete(fifo->data, fifo->len)) {
- send(s->hci, fifo->data, fifo->len);
- fifo->len = 0;
- }
-
- /* TODO: do we need to loop? */
-}
-
-static int usb_bt_hci_cmd_complete(const uint8_t *data, int len)
-{
- len -= HCI_COMMAND_HDR_SIZE;
- return len >= 0 &&
- len >= ((struct hci_command_hdr *) data)->plen;
-}
-
-static int usb_bt_hci_acl_complete(const uint8_t *data, int len)
-{
- len -= HCI_ACL_HDR_SIZE;
- return len >= 0 &&
- len >= le16_to_cpu(((struct hci_acl_hdr *) data)->dlen);
-}
-
-static int usb_bt_hci_sco_complete(const uint8_t *data, int len)
-{
- len -= HCI_SCO_HDR_SIZE;
- return len >= 0 &&
- len >= ((struct hci_sco_hdr *) data)->dlen;
-}
-
-static void usb_bt_handle_reset(USBDevice *dev)
-{
- struct USBBtState *s = (struct USBBtState *) dev->opaque;
-
- usb_bt_fifo_reset(&s->evt);
- usb_bt_fifo_reset(&s->acl);
- usb_bt_fifo_reset(&s->sco);
- s->outcmd.len = 0;
- s->outacl.len = 0;
- s->outsco.len = 0;
-}
-
-static void usb_bt_handle_control(USBDevice *dev, USBPacket *p,
- int request, int value, int index, int length, uint8_t *data)
-{
- struct USBBtState *s = (struct USBBtState *) dev->opaque;
- int ret;
-
- ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
- if (ret >= 0) {
- switch (request) {
- case DeviceRequest | USB_REQ_GET_CONFIGURATION:
- s->config = 0;
- break;
- case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
- s->config = 1;
- usb_bt_fifo_reset(&s->evt);
- usb_bt_fifo_reset(&s->acl);
- usb_bt_fifo_reset(&s->sco);
- break;
- }
- return;
- }
-
- switch (request) {
- case InterfaceRequest | USB_REQ_GET_STATUS:
- case EndpointRequest | USB_REQ_GET_STATUS:
- data[0] = 0x00;
- data[1] = 0x00;
- p->actual_length = 2;
- break;
- case InterfaceOutRequest | USB_REQ_CLEAR_FEATURE:
- case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
- goto fail;
- case InterfaceOutRequest | USB_REQ_SET_FEATURE:
- case EndpointOutRequest | USB_REQ_SET_FEATURE:
- goto fail;
- break;
- case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_DEVICE) << 8):
- if (s->config)
- usb_bt_fifo_out_enqueue(s, &s->outcmd, s->hci->cmd_send,
- usb_bt_hci_cmd_complete, p);
- break;
- default:
- fail:
- p->status = USB_RET_STALL;
- break;
- }
-}
-
-static void usb_bt_handle_data(USBDevice *dev, USBPacket *p)
-{
- struct USBBtState *s = (struct USBBtState *) dev->opaque;
-
- if (!s->config)
- goto fail;
-
- switch (p->pid) {
- case USB_TOKEN_IN:
- switch (p->ep->nr) {
- case USB_EVT_EP:
- if (s->evt.len == 0) {
- p->status = USB_RET_NAK;
- break;
- }
- usb_bt_fifo_dequeue(&s->evt, p);
- break;
-
- case USB_ACL_EP:
- if (s->evt.len == 0) {
- p->status = USB_RET_STALL;
- break;
- }
- usb_bt_fifo_dequeue(&s->acl, p);
- break;
-
- case USB_SCO_EP:
- if (s->evt.len == 0) {
- p->status = USB_RET_STALL;
- break;
- }
- usb_bt_fifo_dequeue(&s->sco, p);
- break;
-
- default:
- goto fail;
- }
- break;
-
- case USB_TOKEN_OUT:
- switch (p->ep->nr) {
- case USB_ACL_EP:
- usb_bt_fifo_out_enqueue(s, &s->outacl, s->hci->acl_send,
- usb_bt_hci_acl_complete, p);
- break;
-
- case USB_SCO_EP:
- usb_bt_fifo_out_enqueue(s, &s->outsco, s->hci->sco_send,
- usb_bt_hci_sco_complete, p);
- break;
-
- default:
- goto fail;
- }
- break;
-
- default:
- fail:
- p->status = USB_RET_STALL;
- break;
- }
-}
-
-static void usb_bt_out_hci_packet_event(void *opaque,
- const uint8_t *data, int len)
-{
- struct USBBtState *s = (struct USBBtState *) opaque;
-
- if (s->evt.len == 0) {
- usb_wakeup(s->intr, 0);
- }
- usb_bt_fifo_enqueue(&s->evt, data, len);
-}
-
-static void usb_bt_out_hci_packet_acl(void *opaque,
- const uint8_t *data, int len)
-{
- struct USBBtState *s = (struct USBBtState *) opaque;
-
- usb_bt_fifo_enqueue(&s->acl, data, len);
-}
-
-static void usb_bt_handle_destroy(USBDevice *dev)
-{
- struct USBBtState *s = (struct USBBtState *) dev->opaque;
-
- s->hci->opaque = NULL;
- s->hci->evt_recv = NULL;
- s->hci->acl_recv = NULL;
-}
-
-static void usb_bt_realize(USBDevice *dev, Error **errp)
-{
- struct USBBtState *s = USB_BT(dev);
-
- usb_desc_create_serial(dev);
- usb_desc_init(dev);
- s->dev.opaque = s;
- if (!s->hci) {
- s->hci = bt_new_hci(qemu_find_bt_vlan(0));
- }
- s->hci->opaque = s;
- s->hci->evt_recv = usb_bt_out_hci_packet_event;
- s->hci->acl_recv = usb_bt_out_hci_packet_acl;
- usb_bt_handle_reset(&s->dev);
- s->intr = usb_ep_get(dev, USB_TOKEN_IN, USB_EVT_EP);
-}
-
-static USBDevice *usb_bt_init(USBBus *bus, const char *cmdline)
-{
- USBDevice *dev;
- struct USBBtState *s;
- HCIInfo *hci;
- const char *name = TYPE_USB_BT;
-
- if (*cmdline) {
- hci = hci_init(cmdline);
- } else {
- hci = bt_new_hci(qemu_find_bt_vlan(0));
- }
- if (!hci)
- return NULL;
-
- dev = usb_create(bus, name);
- s = USB_BT(dev);
- s->hci = hci;
- return dev;
-}
-
-static const VMStateDescription vmstate_usb_bt = {
- .name = "usb-bt",
- .unmigratable = 1,
-};
-
-static void usb_bt_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
-
- uc->realize = usb_bt_realize;
- uc->product_desc = "QEMU BT dongle";
- uc->usb_desc = &desc_bluetooth;
- uc->handle_reset = usb_bt_handle_reset;
- uc->handle_control = usb_bt_handle_control;
- uc->handle_data = usb_bt_handle_data;
- uc->handle_destroy = usb_bt_handle_destroy;
- dc->vmsd = &vmstate_usb_bt;
- set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
-}
-
-static const TypeInfo bt_info = {
- .name = TYPE_USB_BT,
- .parent = TYPE_USB_DEVICE,
- .instance_size = sizeof(struct USBBtState),
- .class_init = usb_bt_class_initfn,
-};
-
-static void usb_bt_register_types(void)
-{
- type_register_static(&bt_info);
- usb_legacy_register(TYPE_USB_BT, "bt", usb_bt_init);
-}
-
-type_init(usb_bt_register_types)
diff --git a/qemu/hw/usb/dev-hid.c b/qemu/hw/usb/dev-hid.c
deleted file mode 100644
index 24d05f76f..000000000
--- a/qemu/hw/usb/dev-hid.c
+++ /dev/null
@@ -1,883 +0,0 @@
-/*
- * QEMU USB HID devices
- *
- * Copyright (c) 2005 Fabrice Bellard
- * Copyright (c) 2007 OpenMoko, Inc. (andrew@openedhand.com)
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "ui/console.h"
-#include "hw/usb.h"
-#include "hw/usb/desc.h"
-#include "qapi/error.h"
-#include "qemu/timer.h"
-#include "hw/input/hid.h"
-
-/* HID interface requests */
-#define GET_REPORT 0xa101
-#define GET_IDLE 0xa102
-#define GET_PROTOCOL 0xa103
-#define SET_REPORT 0x2109
-#define SET_IDLE 0x210a
-#define SET_PROTOCOL 0x210b
-
-/* HID descriptor types */
-#define USB_DT_HID 0x21
-#define USB_DT_REPORT 0x22
-#define USB_DT_PHY 0x23
-
-typedef struct USBHIDState {
- USBDevice dev;
- USBEndpoint *intr;
- HIDState hid;
- uint32_t usb_version;
- char *display;
- uint32_t head;
-} USBHIDState;
-
-#define TYPE_USB_HID "usb-hid"
-#define USB_HID(obj) OBJECT_CHECK(USBHIDState, (obj), TYPE_USB_HID)
-
-enum {
- STR_MANUFACTURER = 1,
- STR_PRODUCT_MOUSE,
- STR_PRODUCT_TABLET,
- STR_PRODUCT_KEYBOARD,
- STR_SERIALNUMBER,
- STR_CONFIG_MOUSE,
- STR_CONFIG_TABLET,
- STR_CONFIG_KEYBOARD,
-};
-
-static const USBDescStrings desc_strings = {
- [STR_MANUFACTURER] = "QEMU",
- [STR_PRODUCT_MOUSE] = "QEMU USB Mouse",
- [STR_PRODUCT_TABLET] = "QEMU USB Tablet",
- [STR_PRODUCT_KEYBOARD] = "QEMU USB Keyboard",
- [STR_SERIALNUMBER] = "42", /* == remote wakeup works */
- [STR_CONFIG_MOUSE] = "HID Mouse",
- [STR_CONFIG_TABLET] = "HID Tablet",
- [STR_CONFIG_KEYBOARD] = "HID Keyboard",
-};
-
-static const USBDescIface desc_iface_mouse = {
- .bInterfaceNumber = 0,
- .bNumEndpoints = 1,
- .bInterfaceClass = USB_CLASS_HID,
- .bInterfaceSubClass = 0x01, /* boot */
- .bInterfaceProtocol = 0x02,
- .ndesc = 1,
- .descs = (USBDescOther[]) {
- {
- /* HID descriptor */
- .data = (uint8_t[]) {
- 0x09, /* u8 bLength */
- USB_DT_HID, /* u8 bDescriptorType */
- 0x01, 0x00, /* u16 HID_class */
- 0x00, /* u8 country_code */
- 0x01, /* u8 num_descriptors */
- USB_DT_REPORT, /* u8 type: Report */
- 52, 0, /* u16 len */
- },
- },
- },
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | 0x01,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = 4,
- .bInterval = 0x0a,
- },
- },
-};
-
-static const USBDescIface desc_iface_mouse2 = {
- .bInterfaceNumber = 0,
- .bNumEndpoints = 1,
- .bInterfaceClass = USB_CLASS_HID,
- .bInterfaceSubClass = 0x01, /* boot */
- .bInterfaceProtocol = 0x02,
- .ndesc = 1,
- .descs = (USBDescOther[]) {
- {
- /* HID descriptor */
- .data = (uint8_t[]) {
- 0x09, /* u8 bLength */
- USB_DT_HID, /* u8 bDescriptorType */
- 0x01, 0x00, /* u16 HID_class */
- 0x00, /* u8 country_code */
- 0x01, /* u8 num_descriptors */
- USB_DT_REPORT, /* u8 type: Report */
- 52, 0, /* u16 len */
- },
- },
- },
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | 0x01,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = 4,
- .bInterval = 7, /* 2 ^ (8-1) * 125 usecs = 8 ms */
- },
- },
-};
-
-static const USBDescIface desc_iface_tablet = {
- .bInterfaceNumber = 0,
- .bNumEndpoints = 1,
- .bInterfaceClass = USB_CLASS_HID,
- .bInterfaceProtocol = 0x02,
- .ndesc = 1,
- .descs = (USBDescOther[]) {
- {
- /* HID descriptor */
- .data = (uint8_t[]) {
- 0x09, /* u8 bLength */
- USB_DT_HID, /* u8 bDescriptorType */
- 0x01, 0x00, /* u16 HID_class */
- 0x00, /* u8 country_code */
- 0x01, /* u8 num_descriptors */
- USB_DT_REPORT, /* u8 type: Report */
- 74, 0, /* u16 len */
- },
- },
- },
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | 0x01,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = 8,
- .bInterval = 0x0a,
- },
- },
-};
-
-static const USBDescIface desc_iface_tablet2 = {
- .bInterfaceNumber = 0,
- .bNumEndpoints = 1,
- .bInterfaceClass = USB_CLASS_HID,
- .bInterfaceProtocol = 0x02,
- .ndesc = 1,
- .descs = (USBDescOther[]) {
- {
- /* HID descriptor */
- .data = (uint8_t[]) {
- 0x09, /* u8 bLength */
- USB_DT_HID, /* u8 bDescriptorType */
- 0x01, 0x00, /* u16 HID_class */
- 0x00, /* u8 country_code */
- 0x01, /* u8 num_descriptors */
- USB_DT_REPORT, /* u8 type: Report */
- 74, 0, /* u16 len */
- },
- },
- },
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | 0x01,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = 8,
- .bInterval = 4, /* 2 ^ (4-1) * 125 usecs = 1 ms */
- },
- },
-};
-
-static const USBDescIface desc_iface_keyboard = {
- .bInterfaceNumber = 0,
- .bNumEndpoints = 1,
- .bInterfaceClass = USB_CLASS_HID,
- .bInterfaceSubClass = 0x01, /* boot */
- .bInterfaceProtocol = 0x01, /* keyboard */
- .ndesc = 1,
- .descs = (USBDescOther[]) {
- {
- /* HID descriptor */
- .data = (uint8_t[]) {
- 0x09, /* u8 bLength */
- USB_DT_HID, /* u8 bDescriptorType */
- 0x11, 0x01, /* u16 HID_class */
- 0x00, /* u8 country_code */
- 0x01, /* u8 num_descriptors */
- USB_DT_REPORT, /* u8 type: Report */
- 0x3f, 0, /* u16 len */
- },
- },
- },
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | 0x01,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = 8,
- .bInterval = 0x0a,
- },
- },
-};
-
-static const USBDescIface desc_iface_keyboard2 = {
- .bInterfaceNumber = 0,
- .bNumEndpoints = 1,
- .bInterfaceClass = USB_CLASS_HID,
- .bInterfaceSubClass = 0x01, /* boot */
- .bInterfaceProtocol = 0x01, /* keyboard */
- .ndesc = 1,
- .descs = (USBDescOther[]) {
- {
- /* HID descriptor */
- .data = (uint8_t[]) {
- 0x09, /* u8 bLength */
- USB_DT_HID, /* u8 bDescriptorType */
- 0x11, 0x01, /* u16 HID_class */
- 0x00, /* u8 country_code */
- 0x01, /* u8 num_descriptors */
- USB_DT_REPORT, /* u8 type: Report */
- 0x3f, 0, /* u16 len */
- },
- },
- },
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | 0x01,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = 8,
- .bInterval = 7, /* 2 ^ (8-1) * 125 usecs = 8 ms */
- },
- },
-};
-
-static const USBDescDevice desc_device_mouse = {
- .bcdUSB = 0x0100,
- .bMaxPacketSize0 = 8,
- .bNumConfigurations = 1,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 1,
- .bConfigurationValue = 1,
- .iConfiguration = STR_CONFIG_MOUSE,
- .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_WAKEUP,
- .bMaxPower = 50,
- .nif = 1,
- .ifs = &desc_iface_mouse,
- },
- },
-};
-
-static const USBDescDevice desc_device_mouse2 = {
- .bcdUSB = 0x0200,
- .bMaxPacketSize0 = 64,
- .bNumConfigurations = 1,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 1,
- .bConfigurationValue = 1,
- .iConfiguration = STR_CONFIG_MOUSE,
- .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_WAKEUP,
- .bMaxPower = 50,
- .nif = 1,
- .ifs = &desc_iface_mouse2,
- },
- },
-};
-
-static const USBDescDevice desc_device_tablet = {
- .bcdUSB = 0x0100,
- .bMaxPacketSize0 = 8,
- .bNumConfigurations = 1,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 1,
- .bConfigurationValue = 1,
- .iConfiguration = STR_CONFIG_TABLET,
- .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_WAKEUP,
- .bMaxPower = 50,
- .nif = 1,
- .ifs = &desc_iface_tablet,
- },
- },
-};
-
-static const USBDescDevice desc_device_tablet2 = {
- .bcdUSB = 0x0200,
- .bMaxPacketSize0 = 64,
- .bNumConfigurations = 1,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 1,
- .bConfigurationValue = 1,
- .iConfiguration = STR_CONFIG_TABLET,
- .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_WAKEUP,
- .bMaxPower = 50,
- .nif = 1,
- .ifs = &desc_iface_tablet2,
- },
- },
-};
-
-static const USBDescDevice desc_device_keyboard = {
- .bcdUSB = 0x0100,
- .bMaxPacketSize0 = 8,
- .bNumConfigurations = 1,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 1,
- .bConfigurationValue = 1,
- .iConfiguration = STR_CONFIG_KEYBOARD,
- .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_WAKEUP,
- .bMaxPower = 50,
- .nif = 1,
- .ifs = &desc_iface_keyboard,
- },
- },
-};
-
-static const USBDescDevice desc_device_keyboard2 = {
- .bcdUSB = 0x0200,
- .bMaxPacketSize0 = 64,
- .bNumConfigurations = 1,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 1,
- .bConfigurationValue = 1,
- .iConfiguration = STR_CONFIG_KEYBOARD,
- .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_WAKEUP,
- .bMaxPower = 50,
- .nif = 1,
- .ifs = &desc_iface_keyboard2,
- },
- },
-};
-
-static const USBDescMSOS desc_msos_suspend = {
- .SelectiveSuspendEnabled = true,
-};
-
-static const USBDesc desc_mouse = {
- .id = {
- .idVendor = 0x0627,
- .idProduct = 0x0001,
- .bcdDevice = 0,
- .iManufacturer = STR_MANUFACTURER,
- .iProduct = STR_PRODUCT_MOUSE,
- .iSerialNumber = STR_SERIALNUMBER,
- },
- .full = &desc_device_mouse,
- .str = desc_strings,
- .msos = &desc_msos_suspend,
-};
-
-static const USBDesc desc_mouse2 = {
- .id = {
- .idVendor = 0x0627,
- .idProduct = 0x0001,
- .bcdDevice = 0,
- .iManufacturer = STR_MANUFACTURER,
- .iProduct = STR_PRODUCT_MOUSE,
- .iSerialNumber = STR_SERIALNUMBER,
- },
- .full = &desc_device_mouse,
- .high = &desc_device_mouse2,
- .str = desc_strings,
- .msos = &desc_msos_suspend,
-};
-
-static const USBDesc desc_tablet = {
- .id = {
- .idVendor = 0x0627,
- .idProduct = 0x0001,
- .bcdDevice = 0,
- .iManufacturer = STR_MANUFACTURER,
- .iProduct = STR_PRODUCT_TABLET,
- .iSerialNumber = STR_SERIALNUMBER,
- },
- .full = &desc_device_tablet,
- .str = desc_strings,
- .msos = &desc_msos_suspend,
-};
-
-static const USBDesc desc_tablet2 = {
- .id = {
- .idVendor = 0x0627,
- .idProduct = 0x0001,
- .bcdDevice = 0,
- .iManufacturer = STR_MANUFACTURER,
- .iProduct = STR_PRODUCT_TABLET,
- .iSerialNumber = STR_SERIALNUMBER,
- },
- .full = &desc_device_tablet,
- .high = &desc_device_tablet2,
- .str = desc_strings,
- .msos = &desc_msos_suspend,
-};
-
-static const USBDesc desc_keyboard = {
- .id = {
- .idVendor = 0x0627,
- .idProduct = 0x0001,
- .bcdDevice = 0,
- .iManufacturer = STR_MANUFACTURER,
- .iProduct = STR_PRODUCT_KEYBOARD,
- .iSerialNumber = STR_SERIALNUMBER,
- },
- .full = &desc_device_keyboard,
- .str = desc_strings,
- .msos = &desc_msos_suspend,
-};
-
-static const USBDesc desc_keyboard2 = {
- .id = {
- .idVendor = 0x0627,
- .idProduct = 0x0001,
- .bcdDevice = 0,
- .iManufacturer = STR_MANUFACTURER,
- .iProduct = STR_PRODUCT_KEYBOARD,
- .iSerialNumber = STR_SERIALNUMBER,
- },
- .full = &desc_device_keyboard,
- .high = &desc_device_keyboard2,
- .str = desc_strings,
- .msos = &desc_msos_suspend,
-};
-
-static const uint8_t qemu_mouse_hid_report_descriptor[] = {
- 0x05, 0x01, /* Usage Page (Generic Desktop) */
- 0x09, 0x02, /* Usage (Mouse) */
- 0xa1, 0x01, /* Collection (Application) */
- 0x09, 0x01, /* Usage (Pointer) */
- 0xa1, 0x00, /* Collection (Physical) */
- 0x05, 0x09, /* Usage Page (Button) */
- 0x19, 0x01, /* Usage Minimum (1) */
- 0x29, 0x03, /* Usage Maximum (3) */
- 0x15, 0x00, /* Logical Minimum (0) */
- 0x25, 0x01, /* Logical Maximum (1) */
- 0x95, 0x03, /* Report Count (3) */
- 0x75, 0x01, /* Report Size (1) */
- 0x81, 0x02, /* Input (Data, Variable, Absolute) */
- 0x95, 0x01, /* Report Count (1) */
- 0x75, 0x05, /* Report Size (5) */
- 0x81, 0x01, /* Input (Constant) */
- 0x05, 0x01, /* Usage Page (Generic Desktop) */
- 0x09, 0x30, /* Usage (X) */
- 0x09, 0x31, /* Usage (Y) */
- 0x09, 0x38, /* Usage (Wheel) */
- 0x15, 0x81, /* Logical Minimum (-0x7f) */
- 0x25, 0x7f, /* Logical Maximum (0x7f) */
- 0x75, 0x08, /* Report Size (8) */
- 0x95, 0x03, /* Report Count (3) */
- 0x81, 0x06, /* Input (Data, Variable, Relative) */
- 0xc0, /* End Collection */
- 0xc0, /* End Collection */
-};
-
-static const uint8_t qemu_tablet_hid_report_descriptor[] = {
- 0x05, 0x01, /* Usage Page (Generic Desktop) */
- 0x09, 0x01, /* Usage (Pointer) */
- 0xa1, 0x01, /* Collection (Application) */
- 0x09, 0x01, /* Usage (Pointer) */
- 0xa1, 0x00, /* Collection (Physical) */
- 0x05, 0x09, /* Usage Page (Button) */
- 0x19, 0x01, /* Usage Minimum (1) */
- 0x29, 0x03, /* Usage Maximum (3) */
- 0x15, 0x00, /* Logical Minimum (0) */
- 0x25, 0x01, /* Logical Maximum (1) */
- 0x95, 0x03, /* Report Count (3) */
- 0x75, 0x01, /* Report Size (1) */
- 0x81, 0x02, /* Input (Data, Variable, Absolute) */
- 0x95, 0x01, /* Report Count (1) */
- 0x75, 0x05, /* Report Size (5) */
- 0x81, 0x01, /* Input (Constant) */
- 0x05, 0x01, /* Usage Page (Generic Desktop) */
- 0x09, 0x30, /* Usage (X) */
- 0x09, 0x31, /* Usage (Y) */
- 0x15, 0x00, /* Logical Minimum (0) */
- 0x26, 0xff, 0x7f, /* Logical Maximum (0x7fff) */
- 0x35, 0x00, /* Physical Minimum (0) */
- 0x46, 0xff, 0x7f, /* Physical Maximum (0x7fff) */
- 0x75, 0x10, /* Report Size (16) */
- 0x95, 0x02, /* Report Count (2) */
- 0x81, 0x02, /* Input (Data, Variable, Absolute) */
- 0x05, 0x01, /* Usage Page (Generic Desktop) */
- 0x09, 0x38, /* Usage (Wheel) */
- 0x15, 0x81, /* Logical Minimum (-0x7f) */
- 0x25, 0x7f, /* Logical Maximum (0x7f) */
- 0x35, 0x00, /* Physical Minimum (same as logical) */
- 0x45, 0x00, /* Physical Maximum (same as logical) */
- 0x75, 0x08, /* Report Size (8) */
- 0x95, 0x01, /* Report Count (1) */
- 0x81, 0x06, /* Input (Data, Variable, Relative) */
- 0xc0, /* End Collection */
- 0xc0, /* End Collection */
-};
-
-static const uint8_t qemu_keyboard_hid_report_descriptor[] = {
- 0x05, 0x01, /* Usage Page (Generic Desktop) */
- 0x09, 0x06, /* Usage (Keyboard) */
- 0xa1, 0x01, /* Collection (Application) */
- 0x75, 0x01, /* Report Size (1) */
- 0x95, 0x08, /* Report Count (8) */
- 0x05, 0x07, /* Usage Page (Key Codes) */
- 0x19, 0xe0, /* Usage Minimum (224) */
- 0x29, 0xe7, /* Usage Maximum (231) */
- 0x15, 0x00, /* Logical Minimum (0) */
- 0x25, 0x01, /* Logical Maximum (1) */
- 0x81, 0x02, /* Input (Data, Variable, Absolute) */
- 0x95, 0x01, /* Report Count (1) */
- 0x75, 0x08, /* Report Size (8) */
- 0x81, 0x01, /* Input (Constant) */
- 0x95, 0x05, /* Report Count (5) */
- 0x75, 0x01, /* Report Size (1) */
- 0x05, 0x08, /* Usage Page (LEDs) */
- 0x19, 0x01, /* Usage Minimum (1) */
- 0x29, 0x05, /* Usage Maximum (5) */
- 0x91, 0x02, /* Output (Data, Variable, Absolute) */
- 0x95, 0x01, /* Report Count (1) */
- 0x75, 0x03, /* Report Size (3) */
- 0x91, 0x01, /* Output (Constant) */
- 0x95, 0x06, /* Report Count (6) */
- 0x75, 0x08, /* Report Size (8) */
- 0x15, 0x00, /* Logical Minimum (0) */
- 0x25, 0xff, /* Logical Maximum (255) */
- 0x05, 0x07, /* Usage Page (Key Codes) */
- 0x19, 0x00, /* Usage Minimum (0) */
- 0x29, 0xff, /* Usage Maximum (255) */
- 0x81, 0x00, /* Input (Data, Array) */
- 0xc0, /* End Collection */
-};
-
-static void usb_hid_changed(HIDState *hs)
-{
- USBHIDState *us = container_of(hs, USBHIDState, hid);
-
- usb_wakeup(us->intr, 0);
-}
-
-static void usb_hid_handle_reset(USBDevice *dev)
-{
- USBHIDState *us = USB_HID(dev);
-
- hid_reset(&us->hid);
-}
-
-static void usb_hid_handle_control(USBDevice *dev, USBPacket *p,
- int request, int value, int index, int length, uint8_t *data)
-{
- USBHIDState *us = USB_HID(dev);
- HIDState *hs = &us->hid;
- int ret;
-
- ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
- if (ret >= 0) {
- return;
- }
-
- switch (request) {
- /* hid specific requests */
- case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
- switch (value >> 8) {
- case 0x22:
- if (hs->kind == HID_MOUSE) {
- memcpy(data, qemu_mouse_hid_report_descriptor,
- sizeof(qemu_mouse_hid_report_descriptor));
- p->actual_length = sizeof(qemu_mouse_hid_report_descriptor);
- } else if (hs->kind == HID_TABLET) {
- memcpy(data, qemu_tablet_hid_report_descriptor,
- sizeof(qemu_tablet_hid_report_descriptor));
- p->actual_length = sizeof(qemu_tablet_hid_report_descriptor);
- } else if (hs->kind == HID_KEYBOARD) {
- memcpy(data, qemu_keyboard_hid_report_descriptor,
- sizeof(qemu_keyboard_hid_report_descriptor));
- p->actual_length = sizeof(qemu_keyboard_hid_report_descriptor);
- }
- break;
- default:
- goto fail;
- }
- break;
- case GET_REPORT:
- if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
- p->actual_length = hid_pointer_poll(hs, data, length);
- } else if (hs->kind == HID_KEYBOARD) {
- p->actual_length = hid_keyboard_poll(hs, data, length);
- }
- break;
- case SET_REPORT:
- if (hs->kind == HID_KEYBOARD) {
- p->actual_length = hid_keyboard_write(hs, data, length);
- } else {
- goto fail;
- }
- break;
- case GET_PROTOCOL:
- if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) {
- goto fail;
- }
- data[0] = hs->protocol;
- p->actual_length = 1;
- break;
- case SET_PROTOCOL:
- if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) {
- goto fail;
- }
- hs->protocol = value;
- break;
- case GET_IDLE:
- data[0] = hs->idle;
- p->actual_length = 1;
- break;
- case SET_IDLE:
- hs->idle = (uint8_t) (value >> 8);
- hid_set_next_idle(hs);
- if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
- hid_pointer_activate(hs);
- }
- break;
- default:
- fail:
- p->status = USB_RET_STALL;
- break;
- }
-}
-
-static void usb_hid_handle_data(USBDevice *dev, USBPacket *p)
-{
- USBHIDState *us = USB_HID(dev);
- HIDState *hs = &us->hid;
- uint8_t buf[p->iov.size];
- int len = 0;
-
- switch (p->pid) {
- case USB_TOKEN_IN:
- if (p->ep->nr == 1) {
- if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
- hid_pointer_activate(hs);
- }
- if (!hid_has_events(hs)) {
- p->status = USB_RET_NAK;
- return;
- }
- hid_set_next_idle(hs);
- if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
- len = hid_pointer_poll(hs, buf, p->iov.size);
- } else if (hs->kind == HID_KEYBOARD) {
- len = hid_keyboard_poll(hs, buf, p->iov.size);
- }
- usb_packet_copy(p, buf, len);
- } else {
- goto fail;
- }
- break;
- case USB_TOKEN_OUT:
- default:
- fail:
- p->status = USB_RET_STALL;
- break;
- }
-}
-
-static void usb_hid_handle_destroy(USBDevice *dev)
-{
- USBHIDState *us = USB_HID(dev);
-
- hid_free(&us->hid);
-}
-
-static void usb_hid_initfn(USBDevice *dev, int kind,
- const USBDesc *usb1, const USBDesc *usb2,
- Error **errp)
-{
- USBHIDState *us = USB_HID(dev);
- switch (us->usb_version) {
- case 1:
- dev->usb_desc = usb1;
- break;
- case 2:
- dev->usb_desc = usb2;
- break;
- default:
- dev->usb_desc = NULL;
- }
- if (!dev->usb_desc) {
- error_setg(errp, "Invalid usb version %d for usb hid device",
- us->usb_version);
- return;
- }
-
- if (dev->serial) {
- usb_desc_set_string(dev, STR_SERIALNUMBER, dev->serial);
- }
- usb_desc_init(dev);
- us->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
- hid_init(&us->hid, kind, usb_hid_changed);
- if (us->display && us->hid.s) {
- qemu_input_handler_bind(us->hid.s, us->display, us->head, NULL);
- }
-}
-
-static void usb_tablet_realize(USBDevice *dev, Error **errp)
-{
-
- usb_hid_initfn(dev, HID_TABLET, &desc_tablet, &desc_tablet2, errp);
-}
-
-static void usb_mouse_realize(USBDevice *dev, Error **errp)
-{
- usb_hid_initfn(dev, HID_MOUSE, &desc_mouse, &desc_mouse2, errp);
-}
-
-static void usb_keyboard_realize(USBDevice *dev, Error **errp)
-{
- usb_hid_initfn(dev, HID_KEYBOARD, &desc_keyboard, &desc_keyboard2, errp);
-}
-
-static int usb_ptr_post_load(void *opaque, int version_id)
-{
- USBHIDState *s = opaque;
-
- if (s->dev.remote_wakeup) {
- hid_pointer_activate(&s->hid);
- }
- return 0;
-}
-
-static const VMStateDescription vmstate_usb_ptr = {
- .name = "usb-ptr",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = usb_ptr_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_USB_DEVICE(dev, USBHIDState),
- VMSTATE_HID_POINTER_DEVICE(hid, USBHIDState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_usb_kbd = {
- .name = "usb-kbd",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_USB_DEVICE(dev, USBHIDState),
- VMSTATE_HID_KEYBOARD_DEVICE(hid, USBHIDState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void usb_hid_class_initfn(ObjectClass *klass, void *data)
-{
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
-
- uc->handle_reset = usb_hid_handle_reset;
- uc->handle_control = usb_hid_handle_control;
- uc->handle_data = usb_hid_handle_data;
- uc->handle_destroy = usb_hid_handle_destroy;
- uc->handle_attach = usb_desc_attach;
-}
-
-static const TypeInfo usb_hid_type_info = {
- .name = TYPE_USB_HID,
- .parent = TYPE_USB_DEVICE,
- .instance_size = sizeof(USBHIDState),
- .abstract = true,
- .class_init = usb_hid_class_initfn,
-};
-
-static Property usb_tablet_properties[] = {
- DEFINE_PROP_UINT32("usb_version", USBHIDState, usb_version, 2),
- DEFINE_PROP_STRING("display", USBHIDState, display),
- DEFINE_PROP_UINT32("head", USBHIDState, head, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void usb_tablet_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
-
- uc->realize = usb_tablet_realize;
- uc->product_desc = "QEMU USB Tablet";
- dc->vmsd = &vmstate_usb_ptr;
- dc->props = usb_tablet_properties;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
-}
-
-static const TypeInfo usb_tablet_info = {
- .name = "usb-tablet",
- .parent = TYPE_USB_HID,
- .class_init = usb_tablet_class_initfn,
-};
-
-static Property usb_mouse_properties[] = {
- DEFINE_PROP_UINT32("usb_version", USBHIDState, usb_version, 2),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void usb_mouse_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
-
- uc->realize = usb_mouse_realize;
- uc->product_desc = "QEMU USB Mouse";
- dc->vmsd = &vmstate_usb_ptr;
- dc->props = usb_mouse_properties;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
-}
-
-static const TypeInfo usb_mouse_info = {
- .name = "usb-mouse",
- .parent = TYPE_USB_HID,
- .class_init = usb_mouse_class_initfn,
-};
-
-static Property usb_keyboard_properties[] = {
- DEFINE_PROP_UINT32("usb_version", USBHIDState, usb_version, 2),
- DEFINE_PROP_STRING("display", USBHIDState, display),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void usb_keyboard_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
-
- uc->realize = usb_keyboard_realize;
- uc->product_desc = "QEMU USB Keyboard";
- dc->vmsd = &vmstate_usb_kbd;
- dc->props = usb_keyboard_properties;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
-}
-
-static const TypeInfo usb_keyboard_info = {
- .name = "usb-kbd",
- .parent = TYPE_USB_HID,
- .class_init = usb_keyboard_class_initfn,
-};
-
-static void usb_hid_register_types(void)
-{
- type_register_static(&usb_hid_type_info);
- type_register_static(&usb_tablet_info);
- usb_legacy_register("usb-tablet", "tablet", NULL);
- type_register_static(&usb_mouse_info);
- usb_legacy_register("usb-mouse", "mouse", NULL);
- type_register_static(&usb_keyboard_info);
- usb_legacy_register("usb-kbd", "keyboard", NULL);
-}
-
-type_init(usb_hid_register_types)
diff --git a/qemu/hw/usb/dev-hub.c b/qemu/hw/usb/dev-hub.c
deleted file mode 100644
index a33f21cb3..000000000
--- a/qemu/hw/usb/dev-hub.c
+++ /dev/null
@@ -1,596 +0,0 @@
-/*
- * QEMU USB HUB emulation
- *
- * Copyright (c) 2005 Fabrice Bellard
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "trace.h"
-#include "hw/usb.h"
-#include "hw/usb/desc.h"
-#include "qemu/error-report.h"
-
-#define NUM_PORTS 8
-
-typedef struct USBHubPort {
- USBPort port;
- uint16_t wPortStatus;
- uint16_t wPortChange;
-} USBHubPort;
-
-typedef struct USBHubState {
- USBDevice dev;
- USBEndpoint *intr;
- USBHubPort ports[NUM_PORTS];
-} USBHubState;
-
-#define TYPE_USB_HUB "usb-hub"
-#define USB_HUB(obj) OBJECT_CHECK(USBHubState, (obj), TYPE_USB_HUB)
-
-#define ClearHubFeature (0x2000 | USB_REQ_CLEAR_FEATURE)
-#define ClearPortFeature (0x2300 | USB_REQ_CLEAR_FEATURE)
-#define GetHubDescriptor (0xa000 | USB_REQ_GET_DESCRIPTOR)
-#define GetHubStatus (0xa000 | USB_REQ_GET_STATUS)
-#define GetPortStatus (0xa300 | USB_REQ_GET_STATUS)
-#define SetHubFeature (0x2000 | USB_REQ_SET_FEATURE)
-#define SetPortFeature (0x2300 | USB_REQ_SET_FEATURE)
-
-#define PORT_STAT_CONNECTION 0x0001
-#define PORT_STAT_ENABLE 0x0002
-#define PORT_STAT_SUSPEND 0x0004
-#define PORT_STAT_OVERCURRENT 0x0008
-#define PORT_STAT_RESET 0x0010
-#define PORT_STAT_POWER 0x0100
-#define PORT_STAT_LOW_SPEED 0x0200
-#define PORT_STAT_HIGH_SPEED 0x0400
-#define PORT_STAT_TEST 0x0800
-#define PORT_STAT_INDICATOR 0x1000
-
-#define PORT_STAT_C_CONNECTION 0x0001
-#define PORT_STAT_C_ENABLE 0x0002
-#define PORT_STAT_C_SUSPEND 0x0004
-#define PORT_STAT_C_OVERCURRENT 0x0008
-#define PORT_STAT_C_RESET 0x0010
-
-#define PORT_CONNECTION 0
-#define PORT_ENABLE 1
-#define PORT_SUSPEND 2
-#define PORT_OVERCURRENT 3
-#define PORT_RESET 4
-#define PORT_POWER 8
-#define PORT_LOWSPEED 9
-#define PORT_HIGHSPEED 10
-#define PORT_C_CONNECTION 16
-#define PORT_C_ENABLE 17
-#define PORT_C_SUSPEND 18
-#define PORT_C_OVERCURRENT 19
-#define PORT_C_RESET 20
-#define PORT_TEST 21
-#define PORT_INDICATOR 22
-
-/* same as Linux kernel root hubs */
-
-enum {
- STR_MANUFACTURER = 1,
- STR_PRODUCT,
- STR_SERIALNUMBER,
-};
-
-static const USBDescStrings desc_strings = {
- [STR_MANUFACTURER] = "QEMU",
- [STR_PRODUCT] = "QEMU USB Hub",
- [STR_SERIALNUMBER] = "314159",
-};
-
-static const USBDescIface desc_iface_hub = {
- .bInterfaceNumber = 0,
- .bNumEndpoints = 1,
- .bInterfaceClass = USB_CLASS_HUB,
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | 0x01,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = 1 + (NUM_PORTS + 7) / 8,
- .bInterval = 0xff,
- },
- }
-};
-
-static const USBDescDevice desc_device_hub = {
- .bcdUSB = 0x0110,
- .bDeviceClass = USB_CLASS_HUB,
- .bMaxPacketSize0 = 8,
- .bNumConfigurations = 1,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 1,
- .bConfigurationValue = 1,
- .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER |
- USB_CFG_ATT_WAKEUP,
- .nif = 1,
- .ifs = &desc_iface_hub,
- },
- },
-};
-
-static const USBDesc desc_hub = {
- .id = {
- .idVendor = 0x0409,
- .idProduct = 0x55aa,
- .bcdDevice = 0x0101,
- .iManufacturer = STR_MANUFACTURER,
- .iProduct = STR_PRODUCT,
- .iSerialNumber = STR_SERIALNUMBER,
- },
- .full = &desc_device_hub,
- .str = desc_strings,
-};
-
-static const uint8_t qemu_hub_hub_descriptor[] =
-{
- 0x00, /* u8 bLength; patched in later */
- 0x29, /* u8 bDescriptorType; Hub-descriptor */
- 0x00, /* u8 bNbrPorts; (patched later) */
- 0x0a, /* u16 wHubCharacteristics; */
- 0x00, /* (per-port OC, no power switching) */
- 0x01, /* u8 bPwrOn2pwrGood; 2ms */
- 0x00 /* u8 bHubContrCurrent; 0 mA */
-
- /* DeviceRemovable and PortPwrCtrlMask patched in later */
-};
-
-static void usb_hub_attach(USBPort *port1)
-{
- USBHubState *s = port1->opaque;
- USBHubPort *port = &s->ports[port1->index];
-
- trace_usb_hub_attach(s->dev.addr, port1->index + 1);
- port->wPortStatus |= PORT_STAT_CONNECTION;
- port->wPortChange |= PORT_STAT_C_CONNECTION;
- if (port->port.dev->speed == USB_SPEED_LOW) {
- port->wPortStatus |= PORT_STAT_LOW_SPEED;
- } else {
- port->wPortStatus &= ~PORT_STAT_LOW_SPEED;
- }
- usb_wakeup(s->intr, 0);
-}
-
-static void usb_hub_detach(USBPort *port1)
-{
- USBHubState *s = port1->opaque;
- USBHubPort *port = &s->ports[port1->index];
-
- trace_usb_hub_detach(s->dev.addr, port1->index + 1);
- usb_wakeup(s->intr, 0);
-
- /* Let upstream know the device on this port is gone */
- s->dev.port->ops->child_detach(s->dev.port, port1->dev);
-
- port->wPortStatus &= ~PORT_STAT_CONNECTION;
- port->wPortChange |= PORT_STAT_C_CONNECTION;
- if (port->wPortStatus & PORT_STAT_ENABLE) {
- port->wPortStatus &= ~PORT_STAT_ENABLE;
- port->wPortChange |= PORT_STAT_C_ENABLE;
- }
- usb_wakeup(s->intr, 0);
-}
-
-static void usb_hub_child_detach(USBPort *port1, USBDevice *child)
-{
- USBHubState *s = port1->opaque;
-
- /* Pass along upstream */
- s->dev.port->ops->child_detach(s->dev.port, child);
-}
-
-static void usb_hub_wakeup(USBPort *port1)
-{
- USBHubState *s = port1->opaque;
- USBHubPort *port = &s->ports[port1->index];
-
- if (port->wPortStatus & PORT_STAT_SUSPEND) {
- port->wPortChange |= PORT_STAT_C_SUSPEND;
- usb_wakeup(s->intr, 0);
- }
-}
-
-static void usb_hub_complete(USBPort *port, USBPacket *packet)
-{
- USBHubState *s = port->opaque;
-
- /*
- * Just pass it along upstream for now.
- *
- * If we ever implement usb 2.0 split transactions this will
- * become a little more complicated ...
- *
- * Can't use usb_packet_complete() here because packet->owner is
- * cleared already, go call the ->complete() callback directly
- * instead.
- */
- s->dev.port->ops->complete(s->dev.port, packet);
-}
-
-static USBDevice *usb_hub_find_device(USBDevice *dev, uint8_t addr)
-{
- USBHubState *s = USB_HUB(dev);
- USBHubPort *port;
- USBDevice *downstream;
- int i;
-
- for (i = 0; i < NUM_PORTS; i++) {
- port = &s->ports[i];
- if (!(port->wPortStatus & PORT_STAT_ENABLE)) {
- continue;
- }
- downstream = usb_find_device(&port->port, addr);
- if (downstream != NULL) {
- return downstream;
- }
- }
- return NULL;
-}
-
-static void usb_hub_handle_reset(USBDevice *dev)
-{
- USBHubState *s = USB_HUB(dev);
- USBHubPort *port;
- int i;
-
- trace_usb_hub_reset(s->dev.addr);
- for (i = 0; i < NUM_PORTS; i++) {
- port = s->ports + i;
- port->wPortStatus = PORT_STAT_POWER;
- port->wPortChange = 0;
- if (port->port.dev && port->port.dev->attached) {
- port->wPortStatus |= PORT_STAT_CONNECTION;
- port->wPortChange |= PORT_STAT_C_CONNECTION;
- if (port->port.dev->speed == USB_SPEED_LOW) {
- port->wPortStatus |= PORT_STAT_LOW_SPEED;
- }
- }
- }
-}
-
-static const char *feature_name(int feature)
-{
- static const char *name[] = {
- [PORT_CONNECTION] = "connection",
- [PORT_ENABLE] = "enable",
- [PORT_SUSPEND] = "suspend",
- [PORT_OVERCURRENT] = "overcurrent",
- [PORT_RESET] = "reset",
- [PORT_POWER] = "power",
- [PORT_LOWSPEED] = "lowspeed",
- [PORT_HIGHSPEED] = "highspeed",
- [PORT_C_CONNECTION] = "change connection",
- [PORT_C_ENABLE] = "change enable",
- [PORT_C_SUSPEND] = "change suspend",
- [PORT_C_OVERCURRENT] = "change overcurrent",
- [PORT_C_RESET] = "change reset",
- [PORT_TEST] = "test",
- [PORT_INDICATOR] = "indicator",
- };
- if (feature < 0 || feature >= ARRAY_SIZE(name)) {
- return "?";
- }
- return name[feature] ?: "?";
-}
-
-static void usb_hub_handle_control(USBDevice *dev, USBPacket *p,
- int request, int value, int index, int length, uint8_t *data)
-{
- USBHubState *s = (USBHubState *)dev;
- int ret;
-
- trace_usb_hub_control(s->dev.addr, request, value, index, length);
-
- ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
- if (ret >= 0) {
- return;
- }
-
- switch(request) {
- case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
- if (value == 0 && index != 0x81) { /* clear ep halt */
- goto fail;
- }
- break;
- /* usb specific requests */
- case GetHubStatus:
- data[0] = 0;
- data[1] = 0;
- data[2] = 0;
- data[3] = 0;
- p->actual_length = 4;
- break;
- case GetPortStatus:
- {
- unsigned int n = index - 1;
- USBHubPort *port;
- if (n >= NUM_PORTS) {
- goto fail;
- }
- port = &s->ports[n];
- trace_usb_hub_get_port_status(s->dev.addr, index,
- port->wPortStatus,
- port->wPortChange);
- data[0] = port->wPortStatus;
- data[1] = port->wPortStatus >> 8;
- data[2] = port->wPortChange;
- data[3] = port->wPortChange >> 8;
- p->actual_length = 4;
- }
- break;
- case SetHubFeature:
- case ClearHubFeature:
- if (value != 0 && value != 1) {
- goto fail;
- }
- break;
- case SetPortFeature:
- {
- unsigned int n = index - 1;
- USBHubPort *port;
- USBDevice *dev;
-
- trace_usb_hub_set_port_feature(s->dev.addr, index,
- feature_name(value));
-
- if (n >= NUM_PORTS) {
- goto fail;
- }
- port = &s->ports[n];
- dev = port->port.dev;
- switch(value) {
- case PORT_SUSPEND:
- port->wPortStatus |= PORT_STAT_SUSPEND;
- break;
- case PORT_RESET:
- if (dev && dev->attached) {
- usb_device_reset(dev);
- port->wPortChange |= PORT_STAT_C_RESET;
- /* set enable bit */
- port->wPortStatus |= PORT_STAT_ENABLE;
- usb_wakeup(s->intr, 0);
- }
- break;
- case PORT_POWER:
- break;
- default:
- goto fail;
- }
- }
- break;
- case ClearPortFeature:
- {
- unsigned int n = index - 1;
- USBHubPort *port;
-
- trace_usb_hub_clear_port_feature(s->dev.addr, index,
- feature_name(value));
-
- if (n >= NUM_PORTS) {
- goto fail;
- }
- port = &s->ports[n];
- switch(value) {
- case PORT_ENABLE:
- port->wPortStatus &= ~PORT_STAT_ENABLE;
- break;
- case PORT_C_ENABLE:
- port->wPortChange &= ~PORT_STAT_C_ENABLE;
- break;
- case PORT_SUSPEND:
- port->wPortStatus &= ~PORT_STAT_SUSPEND;
- break;
- case PORT_C_SUSPEND:
- port->wPortChange &= ~PORT_STAT_C_SUSPEND;
- break;
- case PORT_C_CONNECTION:
- port->wPortChange &= ~PORT_STAT_C_CONNECTION;
- break;
- case PORT_C_OVERCURRENT:
- port->wPortChange &= ~PORT_STAT_C_OVERCURRENT;
- break;
- case PORT_C_RESET:
- port->wPortChange &= ~PORT_STAT_C_RESET;
- break;
- default:
- goto fail;
- }
- }
- break;
- case GetHubDescriptor:
- {
- unsigned int n, limit, var_hub_size = 0;
- memcpy(data, qemu_hub_hub_descriptor,
- sizeof(qemu_hub_hub_descriptor));
- data[2] = NUM_PORTS;
-
- /* fill DeviceRemovable bits */
- limit = ((NUM_PORTS + 1 + 7) / 8) + 7;
- for (n = 7; n < limit; n++) {
- data[n] = 0x00;
- var_hub_size++;
- }
-
- /* fill PortPwrCtrlMask bits */
- limit = limit + ((NUM_PORTS + 7) / 8);
- for (;n < limit; n++) {
- data[n] = 0xff;
- var_hub_size++;
- }
-
- p->actual_length = sizeof(qemu_hub_hub_descriptor) + var_hub_size;
- data[0] = p->actual_length;
- break;
- }
- default:
- fail:
- p->status = USB_RET_STALL;
- break;
- }
-}
-
-static void usb_hub_handle_data(USBDevice *dev, USBPacket *p)
-{
- USBHubState *s = (USBHubState *)dev;
-
- switch(p->pid) {
- case USB_TOKEN_IN:
- if (p->ep->nr == 1) {
- USBHubPort *port;
- unsigned int status;
- uint8_t buf[4];
- int i, n;
- n = (NUM_PORTS + 1 + 7) / 8;
- if (p->iov.size == 1) { /* FreeBSD workaround */
- n = 1;
- } else if (n > p->iov.size) {
- p->status = USB_RET_BABBLE;
- return;
- }
- status = 0;
- for(i = 0; i < NUM_PORTS; i++) {
- port = &s->ports[i];
- if (port->wPortChange)
- status |= (1 << (i + 1));
- }
- if (status != 0) {
- trace_usb_hub_status_report(s->dev.addr, status);
- for(i = 0; i < n; i++) {
- buf[i] = status >> (8 * i);
- }
- usb_packet_copy(p, buf, n);
- } else {
- p->status = USB_RET_NAK; /* usb11 11.13.1 */
- }
- } else {
- goto fail;
- }
- break;
- case USB_TOKEN_OUT:
- default:
- fail:
- p->status = USB_RET_STALL;
- break;
- }
-}
-
-static void usb_hub_handle_destroy(USBDevice *dev)
-{
- USBHubState *s = (USBHubState *)dev;
- int i;
-
- for (i = 0; i < NUM_PORTS; i++) {
- usb_unregister_port(usb_bus_from_device(dev),
- &s->ports[i].port);
- }
-}
-
-static USBPortOps usb_hub_port_ops = {
- .attach = usb_hub_attach,
- .detach = usb_hub_detach,
- .child_detach = usb_hub_child_detach,
- .wakeup = usb_hub_wakeup,
- .complete = usb_hub_complete,
-};
-
-static void usb_hub_realize(USBDevice *dev, Error **errp)
-{
- USBHubState *s = USB_HUB(dev);
- USBHubPort *port;
- int i;
-
- if (dev->port->hubcount == 5) {
- error_setg(errp, "usb hub chain too deep");
- return;
- }
-
- usb_desc_create_serial(dev);
- usb_desc_init(dev);
- s->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
- for (i = 0; i < NUM_PORTS; i++) {
- port = &s->ports[i];
- usb_register_port(usb_bus_from_device(dev),
- &port->port, s, i, &usb_hub_port_ops,
- USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
- usb_port_location(&port->port, dev->port, i+1);
- }
- usb_hub_handle_reset(dev);
-}
-
-static const VMStateDescription vmstate_usb_hub_port = {
- .name = "usb-hub-port",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT16(wPortStatus, USBHubPort),
- VMSTATE_UINT16(wPortChange, USBHubPort),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_usb_hub = {
- .name = "usb-hub",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_USB_DEVICE(dev, USBHubState),
- VMSTATE_STRUCT_ARRAY(ports, USBHubState, NUM_PORTS, 0,
- vmstate_usb_hub_port, USBHubPort),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void usb_hub_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
-
- uc->realize = usb_hub_realize;
- uc->product_desc = "QEMU USB Hub";
- uc->usb_desc = &desc_hub;
- uc->find_device = usb_hub_find_device;
- uc->handle_reset = usb_hub_handle_reset;
- uc->handle_control = usb_hub_handle_control;
- uc->handle_data = usb_hub_handle_data;
- uc->handle_destroy = usb_hub_handle_destroy;
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
- dc->fw_name = "hub";
- dc->vmsd = &vmstate_usb_hub;
-}
-
-static const TypeInfo hub_info = {
- .name = TYPE_USB_HUB,
- .parent = TYPE_USB_DEVICE,
- .instance_size = sizeof(USBHubState),
- .class_init = usb_hub_class_initfn,
-};
-
-static void usb_hub_register_types(void)
-{
- type_register_static(&hub_info);
-}
-
-type_init(usb_hub_register_types)
diff --git a/qemu/hw/usb/dev-mtp.c b/qemu/hw/usb/dev-mtp.c
deleted file mode 100644
index bda84a64b..000000000
--- a/qemu/hw/usb/dev-mtp.c
+++ /dev/null
@@ -1,1414 +0,0 @@
-/*
- * Media Transfer Protocol implementation, backed by host filesystem.
- *
- * Copyright Red Hat, Inc 2014
- *
- * Author:
- * Gerd Hoffmann <kraxel@redhat.com>
- *
- * This code is licensed under the GPL v2 or later.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include <wchar.h>
-#include <dirent.h>
-
-#include <sys/statvfs.h>
-#ifdef CONFIG_INOTIFY1
-#include <sys/inotify.h>
-#include "qapi/error.h"
-#include "qemu/main-loop.h"
-#endif
-
-#include "qemu-common.h"
-#include "qemu/iov.h"
-#include "trace.h"
-#include "hw/usb.h"
-#include "hw/usb/desc.h"
-
-/* ----------------------------------------------------------------------- */
-
-enum mtp_container_type {
- TYPE_COMMAND = 1,
- TYPE_DATA = 2,
- TYPE_RESPONSE = 3,
- TYPE_EVENT = 4,
-};
-
-enum mtp_code {
- /* command codes */
- CMD_GET_DEVICE_INFO = 0x1001,
- CMD_OPEN_SESSION = 0x1002,
- CMD_CLOSE_SESSION = 0x1003,
- CMD_GET_STORAGE_IDS = 0x1004,
- CMD_GET_STORAGE_INFO = 0x1005,
- CMD_GET_NUM_OBJECTS = 0x1006,
- CMD_GET_OBJECT_HANDLES = 0x1007,
- CMD_GET_OBJECT_INFO = 0x1008,
- CMD_GET_OBJECT = 0x1009,
- CMD_GET_PARTIAL_OBJECT = 0x101b,
-
- /* response codes */
- RES_OK = 0x2001,
- RES_GENERAL_ERROR = 0x2002,
- RES_SESSION_NOT_OPEN = 0x2003,
- RES_INVALID_TRANSACTION_ID = 0x2004,
- RES_OPERATION_NOT_SUPPORTED = 0x2005,
- RES_PARAMETER_NOT_SUPPORTED = 0x2006,
- RES_INCOMPLETE_TRANSFER = 0x2007,
- RES_INVALID_STORAGE_ID = 0x2008,
- RES_INVALID_OBJECT_HANDLE = 0x2009,
- RES_SPEC_BY_FORMAT_UNSUPPORTED = 0x2014,
- RES_INVALID_PARENT_OBJECT = 0x201a,
- RES_INVALID_PARAMETER = 0x201d,
- RES_SESSION_ALREADY_OPEN = 0x201e,
-
- /* format codes */
- FMT_UNDEFINED_OBJECT = 0x3000,
- FMT_ASSOCIATION = 0x3001,
-
- /* event codes */
- EVT_OBJ_ADDED = 0x4002,
- EVT_OBJ_REMOVED = 0x4003,
- EVT_OBJ_INFO_CHANGED = 0x4007,
-};
-
-typedef struct {
- uint32_t length;
- uint16_t type;
- uint16_t code;
- uint32_t trans;
-} QEMU_PACKED mtp_container;
-
-/* ----------------------------------------------------------------------- */
-
-typedef struct MTPState MTPState;
-typedef struct MTPControl MTPControl;
-typedef struct MTPData MTPData;
-typedef struct MTPObject MTPObject;
-
-enum {
- EP_DATA_IN = 1,
- EP_DATA_OUT,
- EP_EVENT,
-};
-
-#ifdef CONFIG_INOTIFY1
-typedef struct MTPMonEntry MTPMonEntry;
-
-struct MTPMonEntry {
- uint32_t event;
- uint32_t handle;
-
- QTAILQ_ENTRY(MTPMonEntry) next;
-};
-#endif
-
-struct MTPControl {
- uint16_t code;
- uint32_t trans;
- int argc;
- uint32_t argv[5];
-};
-
-struct MTPData {
- uint16_t code;
- uint32_t trans;
- uint32_t offset;
- uint32_t length;
- uint32_t alloc;
- uint8_t *data;
- bool first;
- int fd;
-};
-
-struct MTPObject {
- uint32_t handle;
- uint16_t format;
- char *name;
- char *path;
- struct stat stat;
-#ifdef CONFIG_INOTIFY1
- /* inotify watch cookie */
- int watchfd;
-#endif
- MTPObject *parent;
- uint32_t nchildren;
- QLIST_HEAD(, MTPObject) children;
- QLIST_ENTRY(MTPObject) list;
- bool have_children;
- QTAILQ_ENTRY(MTPObject) next;
-};
-
-struct MTPState {
- USBDevice dev;
- char *root;
- char *desc;
- uint32_t flags;
-
- MTPData *data_in;
- MTPData *data_out;
- MTPControl *result;
- uint32_t session;
- uint32_t next_handle;
-
- QTAILQ_HEAD(, MTPObject) objects;
-#ifdef CONFIG_INOTIFY1
- /* inotify descriptor */
- int inotifyfd;
- QTAILQ_HEAD(events, MTPMonEntry) events;
-#endif
-};
-
-#define TYPE_USB_MTP "usb-mtp"
-#define USB_MTP(obj) OBJECT_CHECK(MTPState, (obj), TYPE_USB_MTP)
-
-#define QEMU_STORAGE_ID 0x00010001
-
-#define MTP_FLAG_WRITABLE 0
-
-#define FLAG_SET(_mtp, _flag) ((_mtp)->flags & (1 << (_flag)))
-
-/* ----------------------------------------------------------------------- */
-
-#define MTP_MANUFACTURER "QEMU"
-#define MTP_PRODUCT "QEMU filesharing"
-
-enum {
- STR_MANUFACTURER = 1,
- STR_PRODUCT,
- STR_SERIALNUMBER,
- STR_MTP,
- STR_CONFIG_FULL,
- STR_CONFIG_HIGH,
- STR_CONFIG_SUPER,
-};
-
-static const USBDescStrings desc_strings = {
- [STR_MANUFACTURER] = MTP_MANUFACTURER,
- [STR_PRODUCT] = MTP_PRODUCT,
- [STR_SERIALNUMBER] = "34617",
- [STR_MTP] = "MTP",
- [STR_CONFIG_FULL] = "Full speed config (usb 1.1)",
- [STR_CONFIG_HIGH] = "High speed config (usb 2.0)",
- [STR_CONFIG_SUPER] = "Super speed config (usb 3.0)",
-};
-
-static const USBDescIface desc_iface_full = {
- .bInterfaceNumber = 0,
- .bNumEndpoints = 3,
- .bInterfaceClass = USB_CLASS_STILL_IMAGE,
- .bInterfaceSubClass = 0x01,
- .bInterfaceProtocol = 0x01,
- .iInterface = STR_MTP,
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | EP_DATA_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 64,
- },{
- .bEndpointAddress = USB_DIR_OUT | EP_DATA_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 64,
- },{
- .bEndpointAddress = USB_DIR_IN | EP_EVENT,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = 64,
- .bInterval = 0x0a,
- },
- }
-};
-
-static const USBDescDevice desc_device_full = {
- .bcdUSB = 0x0200,
- .bMaxPacketSize0 = 8,
- .bNumConfigurations = 1,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 1,
- .bConfigurationValue = 1,
- .iConfiguration = STR_CONFIG_FULL,
- .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_WAKEUP,
- .bMaxPower = 2,
- .nif = 1,
- .ifs = &desc_iface_full,
- },
- },
-};
-
-static const USBDescIface desc_iface_high = {
- .bInterfaceNumber = 0,
- .bNumEndpoints = 3,
- .bInterfaceClass = USB_CLASS_STILL_IMAGE,
- .bInterfaceSubClass = 0x01,
- .bInterfaceProtocol = 0x01,
- .iInterface = STR_MTP,
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | EP_DATA_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 512,
- },{
- .bEndpointAddress = USB_DIR_OUT | EP_DATA_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 512,
- },{
- .bEndpointAddress = USB_DIR_IN | EP_EVENT,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = 64,
- .bInterval = 0x0a,
- },
- }
-};
-
-static const USBDescDevice desc_device_high = {
- .bcdUSB = 0x0200,
- .bMaxPacketSize0 = 64,
- .bNumConfigurations = 1,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 1,
- .bConfigurationValue = 1,
- .iConfiguration = STR_CONFIG_HIGH,
- .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_WAKEUP,
- .bMaxPower = 2,
- .nif = 1,
- .ifs = &desc_iface_high,
- },
- },
-};
-
-static const USBDescMSOS desc_msos = {
- .CompatibleID = "MTP",
- .SelectiveSuspendEnabled = true,
-};
-
-static const USBDesc desc = {
- .id = {
- .idVendor = 0x46f4, /* CRC16() of "QEMU" */
- .idProduct = 0x0004,
- .bcdDevice = 0,
- .iManufacturer = STR_MANUFACTURER,
- .iProduct = STR_PRODUCT,
- .iSerialNumber = STR_SERIALNUMBER,
- },
- .full = &desc_device_full,
- .high = &desc_device_high,
- .str = desc_strings,
- .msos = &desc_msos,
-};
-
-/* ----------------------------------------------------------------------- */
-
-static MTPObject *usb_mtp_object_alloc(MTPState *s, uint32_t handle,
- MTPObject *parent, char *name)
-{
- MTPObject *o = g_new0(MTPObject, 1);
-
- if (name[0] == '.') {
- goto ignore;
- }
-
- o->handle = handle;
- o->parent = parent;
- o->name = g_strdup(name);
- if (parent == NULL) {
- o->path = g_strdup(name);
- } else {
- o->path = g_strdup_printf("%s/%s", parent->path, name);
- }
-
- if (lstat(o->path, &o->stat) != 0) {
- goto ignore;
- }
- if (S_ISREG(o->stat.st_mode)) {
- o->format = FMT_UNDEFINED_OBJECT;
- } else if (S_ISDIR(o->stat.st_mode)) {
- o->format = FMT_ASSOCIATION;
- } else {
- goto ignore;
- }
-
- if (access(o->path, R_OK) != 0) {
- goto ignore;
- }
-
- trace_usb_mtp_object_alloc(s->dev.addr, o->handle, o->path);
-
- QTAILQ_INSERT_TAIL(&s->objects, o, next);
- return o;
-
-ignore:
- g_free(o->name);
- g_free(o->path);
- g_free(o);
- return NULL;
-}
-
-static void usb_mtp_object_free(MTPState *s, MTPObject *o)
-{
- MTPObject *iter;
-
- if (!o) {
- return;
- }
-
- trace_usb_mtp_object_free(s->dev.addr, o->handle, o->path);
-
- QTAILQ_REMOVE(&s->objects, o, next);
- if (o->parent) {
- QLIST_REMOVE(o, list);
- o->parent->nchildren--;
- }
-
- while (!QLIST_EMPTY(&o->children)) {
- iter = QLIST_FIRST(&o->children);
- usb_mtp_object_free(s, iter);
- }
- g_free(o->name);
- g_free(o->path);
- g_free(o);
-}
-
-static MTPObject *usb_mtp_object_lookup(MTPState *s, uint32_t handle)
-{
- MTPObject *o;
-
- QTAILQ_FOREACH(o, &s->objects, next) {
- if (o->handle == handle) {
- return o;
- }
- }
- return NULL;
-}
-
-static MTPObject *usb_mtp_add_child(MTPState *s, MTPObject *o,
- char *name)
-{
- MTPObject *child =
- usb_mtp_object_alloc(s, s->next_handle++, o, name);
-
- if (child) {
- trace_usb_mtp_add_child(s->dev.addr, child->handle, child->path);
- QLIST_INSERT_HEAD(&o->children, child, list);
- o->nchildren++;
-
- if (child->format == FMT_ASSOCIATION) {
- QLIST_INIT(&child->children);
- }
- }
-
- return child;
-}
-
-#ifdef CONFIG_INOTIFY1
-static MTPObject *usb_mtp_object_lookup_name(MTPObject *parent,
- char *name, int len)
-{
- MTPObject *iter;
-
- QLIST_FOREACH(iter, &parent->children, list) {
- if (strncmp(iter->name, name, len) == 0) {
- return iter;
- }
- }
-
- return NULL;
-}
-
-static MTPObject *usb_mtp_object_lookup_wd(MTPState *s, int wd)
-{
- MTPObject *iter;
-
- QTAILQ_FOREACH(iter, &s->objects, next) {
- if (iter->watchfd == wd) {
- return iter;
- }
- }
-
- return NULL;
-}
-
-static void inotify_watchfn(void *arg)
-{
- MTPState *s = arg;
- ssize_t bytes;
- /* From the man page: atleast one event can be read */
- int pos;
- char buf[sizeof(struct inotify_event) + NAME_MAX + 1];
-
- for (;;) {
- bytes = read(s->inotifyfd, buf, sizeof(buf));
- pos = 0;
-
- if (bytes <= 0) {
- /* Better luck next time */
- return;
- }
-
- /*
- * TODO: Ignore initiator initiated events.
- * For now we are good because the store is RO
- */
- while (bytes > 0) {
- char *p = buf + pos;
- struct inotify_event *event = (struct inotify_event *)p;
- int watchfd = 0;
- uint32_t mask = event->mask & (IN_CREATE | IN_DELETE |
- IN_MODIFY | IN_IGNORED);
- MTPObject *parent = usb_mtp_object_lookup_wd(s, event->wd);
- MTPMonEntry *entry = NULL;
- MTPObject *o;
-
- pos = pos + sizeof(struct inotify_event) + event->len;
- bytes = bytes - pos;
-
- if (!parent) {
- continue;
- }
-
- switch (mask) {
- case IN_CREATE:
- if (usb_mtp_object_lookup_name
- (parent, event->name, event->len)) {
- /* Duplicate create event */
- continue;
- }
- entry = g_new0(MTPMonEntry, 1);
- entry->handle = s->next_handle;
- entry->event = EVT_OBJ_ADDED;
- o = usb_mtp_add_child(s, parent, event->name);
- if (!o) {
- g_free(entry);
- continue;
- }
- o->watchfd = watchfd;
- trace_usb_mtp_inotify_event(s->dev.addr, event->name,
- event->mask, "Obj Added");
- break;
-
- case IN_DELETE:
- /*
- * The kernel issues a IN_IGNORED event
- * when a dir containing a watchpoint is
- * deleted, so we don't have to delete the
- * watchpoint
- */
- o = usb_mtp_object_lookup_name(parent, event->name, event->len);
- if (!o) {
- continue;
- }
- entry = g_new0(MTPMonEntry, 1);
- entry->handle = o->handle;
- entry->event = EVT_OBJ_REMOVED;
- trace_usb_mtp_inotify_event(s->dev.addr, o->path,
- event->mask, "Obj Deleted");
- usb_mtp_object_free(s, o);
- break;
-
- case IN_MODIFY:
- o = usb_mtp_object_lookup_name(parent, event->name, event->len);
- if (!o) {
- continue;
- }
- entry = g_new0(MTPMonEntry, 1);
- entry->handle = o->handle;
- entry->event = EVT_OBJ_INFO_CHANGED;
- trace_usb_mtp_inotify_event(s->dev.addr, o->path,
- event->mask, "Obj Modified");
- break;
-
- case IN_IGNORED:
- o = usb_mtp_object_lookup_name(parent, event->name, event->len);
- trace_usb_mtp_inotify_event(s->dev.addr, o->path,
- event->mask, "Obj ignored");
- break;
-
- default:
- fprintf(stderr, "usb-mtp: failed to parse inotify event\n");
- continue;
- }
-
- if (entry) {
- QTAILQ_INSERT_HEAD(&s->events, entry, next);
- }
- }
- }
-}
-
-static int usb_mtp_inotify_init(MTPState *s)
-{
- int fd;
-
- fd = inotify_init1(IN_NONBLOCK);
- if (fd == -1) {
- return 1;
- }
-
- QTAILQ_INIT(&s->events);
- s->inotifyfd = fd;
-
- qemu_set_fd_handler(fd, inotify_watchfn, NULL, s);
-
- return 0;
-}
-
-static void usb_mtp_inotify_cleanup(MTPState *s)
-{
- MTPMonEntry *e, *p;
-
- if (!s->inotifyfd) {
- return;
- }
-
- qemu_set_fd_handler(s->inotifyfd, NULL, NULL, s);
- close(s->inotifyfd);
-
- QTAILQ_FOREACH_SAFE(e, &s->events, next, p) {
- QTAILQ_REMOVE(&s->events, e, next);
- g_free(e);
- }
-}
-
-static int usb_mtp_add_watch(int inotifyfd, char *path)
-{
- uint32_t mask = IN_CREATE | IN_DELETE | IN_MODIFY |
- IN_ISDIR;
-
- return inotify_add_watch(inotifyfd, path, mask);
-}
-#endif
-
-static void usb_mtp_object_readdir(MTPState *s, MTPObject *o)
-{
- struct dirent *entry;
- DIR *dir;
-
- if (o->have_children) {
- return;
- }
- o->have_children = true;
-
- dir = opendir(o->path);
- if (!dir) {
- return;
- }
-#ifdef CONFIG_INOTIFY1
- int watchfd = usb_mtp_add_watch(s->inotifyfd, o->path);
- if (watchfd == -1) {
- fprintf(stderr, "usb-mtp: failed to add watch for %s\n", o->path);
- } else {
- trace_usb_mtp_inotify_event(s->dev.addr, o->path,
- 0, "Watch Added");
- o->watchfd = watchfd;
- }
-#endif
- while ((entry = readdir(dir)) != NULL) {
- usb_mtp_add_child(s, o, entry->d_name);
- }
- closedir(dir);
-}
-
-/* ----------------------------------------------------------------------- */
-
-static MTPData *usb_mtp_data_alloc(MTPControl *c)
-{
- MTPData *data = g_new0(MTPData, 1);
-
- data->code = c->code;
- data->trans = c->trans;
- data->fd = -1;
- data->first = true;
- return data;
-}
-
-static void usb_mtp_data_free(MTPData *data)
-{
- if (data == NULL) {
- return;
- }
- if (data->fd != -1) {
- close(data->fd);
- }
- g_free(data->data);
- g_free(data);
-}
-
-static void usb_mtp_realloc(MTPData *data, uint32_t bytes)
-{
- if (data->length + bytes <= data->alloc) {
- return;
- }
- data->alloc = (data->length + bytes + 0xff) & ~0xff;
- data->data = g_realloc(data->data, data->alloc);
-}
-
-static void usb_mtp_add_u8(MTPData *data, uint8_t val)
-{
- usb_mtp_realloc(data, 1);
- data->data[data->length++] = val;
-}
-
-static void usb_mtp_add_u16(MTPData *data, uint16_t val)
-{
- usb_mtp_realloc(data, 2);
- data->data[data->length++] = (val >> 0) & 0xff;
- data->data[data->length++] = (val >> 8) & 0xff;
-}
-
-static void usb_mtp_add_u32(MTPData *data, uint32_t val)
-{
- usb_mtp_realloc(data, 4);
- data->data[data->length++] = (val >> 0) & 0xff;
- data->data[data->length++] = (val >> 8) & 0xff;
- data->data[data->length++] = (val >> 16) & 0xff;
- data->data[data->length++] = (val >> 24) & 0xff;
-}
-
-static void usb_mtp_add_u64(MTPData *data, uint64_t val)
-{
- usb_mtp_realloc(data, 8);
- data->data[data->length++] = (val >> 0) & 0xff;
- data->data[data->length++] = (val >> 8) & 0xff;
- data->data[data->length++] = (val >> 16) & 0xff;
- data->data[data->length++] = (val >> 24) & 0xff;
- data->data[data->length++] = (val >> 32) & 0xff;
- data->data[data->length++] = (val >> 40) & 0xff;
- data->data[data->length++] = (val >> 48) & 0xff;
- data->data[data->length++] = (val >> 56) & 0xff;
-}
-
-static void usb_mtp_add_u16_array(MTPData *data, uint32_t len,
- const uint16_t *vals)
-{
- int i;
-
- usb_mtp_add_u32(data, len);
- for (i = 0; i < len; i++) {
- usb_mtp_add_u16(data, vals[i]);
- }
-}
-
-static void usb_mtp_add_u32_array(MTPData *data, uint32_t len,
- const uint32_t *vals)
-{
- int i;
-
- usb_mtp_add_u32(data, len);
- for (i = 0; i < len; i++) {
- usb_mtp_add_u32(data, vals[i]);
- }
-}
-
-static void usb_mtp_add_wstr(MTPData *data, const wchar_t *str)
-{
- uint32_t len = wcslen(str);
- int i;
-
- if (len > 0) {
- len++; /* include terminating L'\0' */
- }
-
- usb_mtp_add_u8(data, len);
- for (i = 0; i < len; i++) {
- usb_mtp_add_u16(data, str[i]);
- }
-}
-
-static void usb_mtp_add_str(MTPData *data, const char *str)
-{
- uint32_t len = strlen(str)+1;
- wchar_t *wstr = g_new(wchar_t, len);
- size_t ret;
-
- ret = mbstowcs(wstr, str, len);
- if (ret == -1) {
- usb_mtp_add_wstr(data, L"Oops");
- } else {
- usb_mtp_add_wstr(data, wstr);
- }
-
- g_free(wstr);
-}
-
-static void usb_mtp_add_time(MTPData *data, time_t time)
-{
- char buf[16];
- struct tm tm;
-
- gmtime_r(&time, &tm);
- strftime(buf, sizeof(buf), "%Y%m%dT%H%M%S", &tm);
- usb_mtp_add_str(data, buf);
-}
-
-/* ----------------------------------------------------------------------- */
-
-static void usb_mtp_queue_result(MTPState *s, uint16_t code, uint32_t trans,
- int argc, uint32_t arg0, uint32_t arg1)
-{
- MTPControl *c = g_new0(MTPControl, 1);
-
- c->code = code;
- c->trans = trans;
- c->argc = argc;
- if (argc > 0) {
- c->argv[0] = arg0;
- }
- if (argc > 1) {
- c->argv[1] = arg1;
- }
-
- assert(s->result == NULL);
- s->result = c;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static MTPData *usb_mtp_get_device_info(MTPState *s, MTPControl *c)
-{
- static const uint16_t ops[] = {
- CMD_GET_DEVICE_INFO,
- CMD_OPEN_SESSION,
- CMD_CLOSE_SESSION,
- CMD_GET_STORAGE_IDS,
- CMD_GET_STORAGE_INFO,
- CMD_GET_NUM_OBJECTS,
- CMD_GET_OBJECT_HANDLES,
- CMD_GET_OBJECT_INFO,
- CMD_GET_OBJECT,
- CMD_GET_PARTIAL_OBJECT,
- };
- static const uint16_t fmt[] = {
- FMT_UNDEFINED_OBJECT,
- FMT_ASSOCIATION,
- };
- MTPData *d = usb_mtp_data_alloc(c);
-
- trace_usb_mtp_op_get_device_info(s->dev.addr);
-
- usb_mtp_add_u16(d, 100);
- usb_mtp_add_u32(d, 0xffffffff);
- usb_mtp_add_u16(d, 0x0101);
- usb_mtp_add_wstr(d, L"");
- usb_mtp_add_u16(d, 0x0000);
-
- usb_mtp_add_u16_array(d, ARRAY_SIZE(ops), ops);
- usb_mtp_add_u16_array(d, 0, NULL);
- usb_mtp_add_u16_array(d, 0, NULL);
- usb_mtp_add_u16_array(d, 0, NULL);
- usb_mtp_add_u16_array(d, ARRAY_SIZE(fmt), fmt);
-
- usb_mtp_add_wstr(d, L"" MTP_MANUFACTURER);
- usb_mtp_add_wstr(d, L"" MTP_PRODUCT);
- usb_mtp_add_wstr(d, L"0.1");
- usb_mtp_add_wstr(d, L"0123456789abcdef0123456789abcdef");
-
- return d;
-}
-
-static MTPData *usb_mtp_get_storage_ids(MTPState *s, MTPControl *c)
-{
- static const uint32_t ids[] = {
- QEMU_STORAGE_ID,
- };
- MTPData *d = usb_mtp_data_alloc(c);
-
- trace_usb_mtp_op_get_storage_ids(s->dev.addr);
-
- usb_mtp_add_u32_array(d, ARRAY_SIZE(ids), ids);
-
- return d;
-}
-
-static MTPData *usb_mtp_get_storage_info(MTPState *s, MTPControl *c)
-{
- MTPData *d = usb_mtp_data_alloc(c);
- struct statvfs buf;
- int rc;
-
- trace_usb_mtp_op_get_storage_info(s->dev.addr);
-
- if (FLAG_SET(s, MTP_FLAG_WRITABLE)) {
- usb_mtp_add_u16(d, 0x0003);
- usb_mtp_add_u16(d, 0x0002);
- usb_mtp_add_u16(d, 0x0000);
- } else {
- usb_mtp_add_u16(d, 0x0001);
- usb_mtp_add_u16(d, 0x0002);
- usb_mtp_add_u16(d, 0x0001);
- }
-
- rc = statvfs(s->root, &buf);
- if (rc == 0) {
- usb_mtp_add_u64(d, (uint64_t)buf.f_frsize * buf.f_blocks);
- usb_mtp_add_u64(d, (uint64_t)buf.f_bavail * buf.f_blocks);
- usb_mtp_add_u32(d, buf.f_ffree);
- } else {
- usb_mtp_add_u64(d, 0xffffffff);
- usb_mtp_add_u64(d, 0xffffffff);
- usb_mtp_add_u32(d, 0xffffffff);
- }
-
- usb_mtp_add_str(d, s->desc);
- usb_mtp_add_wstr(d, L"123456789abcdef");
- return d;
-}
-
-static MTPData *usb_mtp_get_object_handles(MTPState *s, MTPControl *c,
- MTPObject *o)
-{
- MTPData *d = usb_mtp_data_alloc(c);
- uint32_t i = 0, handles[o->nchildren];
- MTPObject *iter;
-
- trace_usb_mtp_op_get_object_handles(s->dev.addr, o->handle, o->path);
-
- QLIST_FOREACH(iter, &o->children, list) {
- handles[i++] = iter->handle;
- }
- assert(i == o->nchildren);
- usb_mtp_add_u32_array(d, o->nchildren, handles);
-
- return d;
-}
-
-static MTPData *usb_mtp_get_object_info(MTPState *s, MTPControl *c,
- MTPObject *o)
-{
- MTPData *d = usb_mtp_data_alloc(c);
-
- trace_usb_mtp_op_get_object_info(s->dev.addr, o->handle, o->path);
-
- usb_mtp_add_u32(d, QEMU_STORAGE_ID);
- usb_mtp_add_u16(d, o->format);
- usb_mtp_add_u16(d, 0);
- usb_mtp_add_u32(d, o->stat.st_size);
-
- usb_mtp_add_u16(d, 0);
- usb_mtp_add_u32(d, 0);
- usb_mtp_add_u32(d, 0);
- usb_mtp_add_u32(d, 0);
- usb_mtp_add_u32(d, 0);
- usb_mtp_add_u32(d, 0);
- usb_mtp_add_u32(d, 0);
-
- if (o->parent) {
- usb_mtp_add_u32(d, o->parent->handle);
- } else {
- usb_mtp_add_u32(d, 0);
- }
- if (o->format == FMT_ASSOCIATION) {
- usb_mtp_add_u16(d, 0x0001);
- usb_mtp_add_u32(d, 0x00000001);
- usb_mtp_add_u32(d, 0);
- } else {
- usb_mtp_add_u16(d, 0);
- usb_mtp_add_u32(d, 0);
- usb_mtp_add_u32(d, 0);
- }
-
- usb_mtp_add_str(d, o->name);
- usb_mtp_add_time(d, o->stat.st_ctime);
- usb_mtp_add_time(d, o->stat.st_mtime);
- usb_mtp_add_wstr(d, L"");
-
- return d;
-}
-
-static MTPData *usb_mtp_get_object(MTPState *s, MTPControl *c,
- MTPObject *o)
-{
- MTPData *d = usb_mtp_data_alloc(c);
-
- trace_usb_mtp_op_get_object(s->dev.addr, o->handle, o->path);
-
- d->fd = open(o->path, O_RDONLY);
- if (d->fd == -1) {
- usb_mtp_data_free(d);
- return NULL;
- }
- d->length = o->stat.st_size;
- d->alloc = 512;
- d->data = g_malloc(d->alloc);
- return d;
-}
-
-static MTPData *usb_mtp_get_partial_object(MTPState *s, MTPControl *c,
- MTPObject *o)
-{
- MTPData *d = usb_mtp_data_alloc(c);
- off_t offset;
-
- trace_usb_mtp_op_get_partial_object(s->dev.addr, o->handle, o->path,
- c->argv[1], c->argv[2]);
-
- d->fd = open(o->path, O_RDONLY);
- if (d->fd == -1) {
- usb_mtp_data_free(d);
- return NULL;
- }
-
- offset = c->argv[1];
- if (offset > o->stat.st_size) {
- offset = o->stat.st_size;
- }
- if (lseek(d->fd, offset, SEEK_SET) < 0) {
- usb_mtp_data_free(d);
- return NULL;
- }
-
- d->length = c->argv[2];
- if (d->length > o->stat.st_size - offset) {
- d->length = o->stat.st_size - offset;
- }
-
- return d;
-}
-
-static void usb_mtp_command(MTPState *s, MTPControl *c)
-{
- MTPData *data_in = NULL;
- MTPObject *o;
- uint32_t nres = 0, res0 = 0;
-
- /* sanity checks */
- if (c->code >= CMD_CLOSE_SESSION && s->session == 0) {
- usb_mtp_queue_result(s, RES_SESSION_NOT_OPEN,
- c->trans, 0, 0, 0);
- return;
- }
-
- /* process commands */
- switch (c->code) {
- case CMD_GET_DEVICE_INFO:
- data_in = usb_mtp_get_device_info(s, c);
- break;
- case CMD_OPEN_SESSION:
- if (s->session) {
- usb_mtp_queue_result(s, RES_SESSION_ALREADY_OPEN,
- c->trans, 1, s->session, 0);
- return;
- }
- if (c->argv[0] == 0) {
- usb_mtp_queue_result(s, RES_INVALID_PARAMETER,
- c->trans, 0, 0, 0);
- return;
- }
- trace_usb_mtp_op_open_session(s->dev.addr);
- s->session = c->argv[0];
- usb_mtp_object_alloc(s, s->next_handle++, NULL, s->root);
-#ifdef CONFIG_INOTIFY1
- if (usb_mtp_inotify_init(s)) {
- fprintf(stderr, "usb-mtp: file monitoring init failed\n");
- }
-#endif
- break;
- case CMD_CLOSE_SESSION:
- trace_usb_mtp_op_close_session(s->dev.addr);
- s->session = 0;
- s->next_handle = 0;
-#ifdef CONFIG_INOTIFY1
- usb_mtp_inotify_cleanup(s);
-#endif
- usb_mtp_object_free(s, QTAILQ_FIRST(&s->objects));
- assert(QTAILQ_EMPTY(&s->objects));
- break;
- case CMD_GET_STORAGE_IDS:
- data_in = usb_mtp_get_storage_ids(s, c);
- break;
- case CMD_GET_STORAGE_INFO:
- if (c->argv[0] != QEMU_STORAGE_ID &&
- c->argv[0] != 0xffffffff) {
- usb_mtp_queue_result(s, RES_INVALID_STORAGE_ID,
- c->trans, 0, 0, 0);
- return;
- }
- data_in = usb_mtp_get_storage_info(s, c);
- break;
- case CMD_GET_NUM_OBJECTS:
- case CMD_GET_OBJECT_HANDLES:
- if (c->argv[0] != QEMU_STORAGE_ID &&
- c->argv[0] != 0xffffffff) {
- usb_mtp_queue_result(s, RES_INVALID_STORAGE_ID,
- c->trans, 0, 0, 0);
- return;
- }
- if (c->argv[1] != 0x00000000) {
- usb_mtp_queue_result(s, RES_SPEC_BY_FORMAT_UNSUPPORTED,
- c->trans, 0, 0, 0);
- return;
- }
- if (c->argv[2] == 0x00000000 ||
- c->argv[2] == 0xffffffff) {
- o = QTAILQ_FIRST(&s->objects);
- } else {
- o = usb_mtp_object_lookup(s, c->argv[2]);
- }
- if (o == NULL) {
- usb_mtp_queue_result(s, RES_INVALID_OBJECT_HANDLE,
- c->trans, 0, 0, 0);
- return;
- }
- if (o->format != FMT_ASSOCIATION) {
- usb_mtp_queue_result(s, RES_INVALID_PARENT_OBJECT,
- c->trans, 0, 0, 0);
- return;
- }
- usb_mtp_object_readdir(s, o);
- if (c->code == CMD_GET_NUM_OBJECTS) {
- trace_usb_mtp_op_get_num_objects(s->dev.addr, o->handle, o->path);
- nres = 1;
- res0 = o->nchildren;
- } else {
- data_in = usb_mtp_get_object_handles(s, c, o);
- }
- break;
- case CMD_GET_OBJECT_INFO:
- o = usb_mtp_object_lookup(s, c->argv[0]);
- if (o == NULL) {
- usb_mtp_queue_result(s, RES_INVALID_OBJECT_HANDLE,
- c->trans, 0, 0, 0);
- return;
- }
- data_in = usb_mtp_get_object_info(s, c, o);
- break;
- case CMD_GET_OBJECT:
- o = usb_mtp_object_lookup(s, c->argv[0]);
- if (o == NULL) {
- usb_mtp_queue_result(s, RES_INVALID_OBJECT_HANDLE,
- c->trans, 0, 0, 0);
- return;
- }
- if (o->format == FMT_ASSOCIATION) {
- usb_mtp_queue_result(s, RES_INVALID_OBJECT_HANDLE,
- c->trans, 0, 0, 0);
- return;
- }
- data_in = usb_mtp_get_object(s, c, o);
- if (data_in == NULL) {
- usb_mtp_queue_result(s, RES_GENERAL_ERROR,
- c->trans, 0, 0, 0);
- return;
- }
- break;
- case CMD_GET_PARTIAL_OBJECT:
- o = usb_mtp_object_lookup(s, c->argv[0]);
- if (o == NULL) {
- usb_mtp_queue_result(s, RES_INVALID_OBJECT_HANDLE,
- c->trans, 0, 0, 0);
- return;
- }
- if (o->format == FMT_ASSOCIATION) {
- usb_mtp_queue_result(s, RES_INVALID_OBJECT_HANDLE,
- c->trans, 0, 0, 0);
- return;
- }
- data_in = usb_mtp_get_partial_object(s, c, o);
- if (data_in == NULL) {
- usb_mtp_queue_result(s, RES_GENERAL_ERROR,
- c->trans, 0, 0, 0);
- return;
- }
- nres = 1;
- res0 = data_in->length;
- break;
- default:
- trace_usb_mtp_op_unknown(s->dev.addr, c->code);
- usb_mtp_queue_result(s, RES_OPERATION_NOT_SUPPORTED,
- c->trans, 0, 0, 0);
- return;
- }
-
- /* return results on success */
- if (data_in) {
- assert(s->data_in == NULL);
- s->data_in = data_in;
- }
- usb_mtp_queue_result(s, RES_OK, c->trans, nres, res0, 0);
-}
-
-/* ----------------------------------------------------------------------- */
-
-static void usb_mtp_handle_reset(USBDevice *dev)
-{
- MTPState *s = USB_MTP(dev);
-
- trace_usb_mtp_reset(s->dev.addr);
-
-#ifdef CONFIG_INOTIFY1
- usb_mtp_inotify_cleanup(s);
-#endif
- usb_mtp_object_free(s, QTAILQ_FIRST(&s->objects));
- s->session = 0;
- usb_mtp_data_free(s->data_in);
- s->data_in = NULL;
- usb_mtp_data_free(s->data_out);
- s->data_out = NULL;
- g_free(s->result);
- s->result = NULL;
-}
-
-static void usb_mtp_handle_control(USBDevice *dev, USBPacket *p,
- int request, int value, int index,
- int length, uint8_t *data)
-{
- int ret;
-
- ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
- if (ret >= 0) {
- return;
- }
-
- trace_usb_mtp_stall(dev->addr, "unknown control request");
- p->status = USB_RET_STALL;
-}
-
-static void usb_mtp_cancel_packet(USBDevice *dev, USBPacket *p)
-{
- /* we don't use async packets, so this should never be called */
- fprintf(stderr, "%s\n", __func__);
-}
-
-static void usb_mtp_handle_data(USBDevice *dev, USBPacket *p)
-{
- MTPState *s = USB_MTP(dev);
- MTPControl cmd;
- mtp_container container;
- uint32_t params[5];
- int i, rc;
-
- switch (p->ep->nr) {
- case EP_DATA_IN:
- if (s->data_out != NULL) {
- /* guest bug */
- trace_usb_mtp_stall(s->dev.addr, "awaiting data-out");
- p->status = USB_RET_STALL;
- return;
- }
- if (p->iov.size < sizeof(container)) {
- trace_usb_mtp_stall(s->dev.addr, "packet too small");
- p->status = USB_RET_STALL;
- return;
- }
- if (s->data_in != NULL) {
- MTPData *d = s->data_in;
- int dlen = d->length - d->offset;
- if (d->first) {
- trace_usb_mtp_data_in(s->dev.addr, d->trans, d->length);
- container.length = cpu_to_le32(d->length + sizeof(container));
- container.type = cpu_to_le16(TYPE_DATA);
- container.code = cpu_to_le16(d->code);
- container.trans = cpu_to_le32(d->trans);
- usb_packet_copy(p, &container, sizeof(container));
- d->first = false;
- if (dlen > p->iov.size - sizeof(container)) {
- dlen = p->iov.size - sizeof(container);
- }
- } else {
- if (dlen > p->iov.size) {
- dlen = p->iov.size;
- }
- }
- if (d->fd == -1) {
- usb_packet_copy(p, d->data + d->offset, dlen);
- } else {
- if (d->alloc < p->iov.size) {
- d->alloc = p->iov.size;
- d->data = g_realloc(d->data, d->alloc);
- }
- rc = read(d->fd, d->data, dlen);
- if (rc != dlen) {
- memset(d->data, 0, dlen);
- s->result->code = RES_INCOMPLETE_TRANSFER;
- }
- usb_packet_copy(p, d->data, dlen);
- }
- d->offset += dlen;
- if (d->offset == d->length) {
- usb_mtp_data_free(s->data_in);
- s->data_in = NULL;
- }
- } else if (s->result != NULL) {
- MTPControl *r = s->result;
- int length = sizeof(container) + r->argc * sizeof(uint32_t);
- if (r->code == RES_OK) {
- trace_usb_mtp_success(s->dev.addr, r->trans,
- (r->argc > 0) ? r->argv[0] : 0,
- (r->argc > 1) ? r->argv[1] : 0);
- } else {
- trace_usb_mtp_error(s->dev.addr, r->code, r->trans,
- (r->argc > 0) ? r->argv[0] : 0,
- (r->argc > 1) ? r->argv[1] : 0);
- }
- container.length = cpu_to_le32(length);
- container.type = cpu_to_le16(TYPE_RESPONSE);
- container.code = cpu_to_le16(r->code);
- container.trans = cpu_to_le32(r->trans);
- for (i = 0; i < r->argc; i++) {
- params[i] = cpu_to_le32(r->argv[i]);
- }
- usb_packet_copy(p, &container, sizeof(container));
- usb_packet_copy(p, &params, length - sizeof(container));
- g_free(s->result);
- s->result = NULL;
- }
- break;
- case EP_DATA_OUT:
- if (p->iov.size < sizeof(container)) {
- trace_usb_mtp_stall(s->dev.addr, "packet too small");
- p->status = USB_RET_STALL;
- return;
- }
- usb_packet_copy(p, &container, sizeof(container));
- switch (le16_to_cpu(container.type)) {
- case TYPE_COMMAND:
- if (s->data_in || s->data_out || s->result) {
- trace_usb_mtp_stall(s->dev.addr, "transaction inflight");
- p->status = USB_RET_STALL;
- return;
- }
- cmd.code = le16_to_cpu(container.code);
- cmd.argc = (le32_to_cpu(container.length) - sizeof(container))
- / sizeof(uint32_t);
- cmd.trans = le32_to_cpu(container.trans);
- if (cmd.argc > ARRAY_SIZE(cmd.argv)) {
- cmd.argc = ARRAY_SIZE(cmd.argv);
- }
- if (p->iov.size < sizeof(container) + cmd.argc * sizeof(uint32_t)) {
- trace_usb_mtp_stall(s->dev.addr, "packet too small");
- p->status = USB_RET_STALL;
- return;
- }
- usb_packet_copy(p, &params, cmd.argc * sizeof(uint32_t));
- for (i = 0; i < cmd.argc; i++) {
- cmd.argv[i] = le32_to_cpu(params[i]);
- }
- trace_usb_mtp_command(s->dev.addr, cmd.code, cmd.trans,
- (cmd.argc > 0) ? cmd.argv[0] : 0,
- (cmd.argc > 1) ? cmd.argv[1] : 0,
- (cmd.argc > 2) ? cmd.argv[2] : 0,
- (cmd.argc > 3) ? cmd.argv[3] : 0,
- (cmd.argc > 4) ? cmd.argv[4] : 0);
- usb_mtp_command(s, &cmd);
- break;
- default:
- /* not needed as long as the mtp device is read-only */
- p->status = USB_RET_STALL;
- return;
- }
- break;
- case EP_EVENT:
-#ifdef CONFIG_INOTIFY1
- if (!QTAILQ_EMPTY(&s->events)) {
- struct MTPMonEntry *e = QTAILQ_LAST(&s->events, events);
- uint32_t handle;
- int len = sizeof(container) + sizeof(uint32_t);
-
- if (p->iov.size < len) {
- trace_usb_mtp_stall(s->dev.addr,
- "packet too small to send event");
- p->status = USB_RET_STALL;
- return;
- }
-
- QTAILQ_REMOVE(&s->events, e, next);
- container.length = cpu_to_le32(len);
- container.type = cpu_to_le32(TYPE_EVENT);
- container.code = cpu_to_le16(e->event);
- container.trans = 0; /* no trans specific events */
- handle = cpu_to_le32(e->handle);
- usb_packet_copy(p, &container, sizeof(container));
- usb_packet_copy(p, &handle, sizeof(uint32_t));
- g_free(e);
- return;
- }
-#endif
- p->status = USB_RET_NAK;
- return;
- default:
- trace_usb_mtp_stall(s->dev.addr, "invalid endpoint");
- p->status = USB_RET_STALL;
- return;
- }
-
- if (p->actual_length == 0) {
- trace_usb_mtp_nak(s->dev.addr, p->ep->nr);
- p->status = USB_RET_NAK;
- return;
- } else {
- trace_usb_mtp_xfer(s->dev.addr, p->ep->nr, p->actual_length,
- p->iov.size);
- return;
- }
-}
-
-static void usb_mtp_realize(USBDevice *dev, Error **errp)
-{
- MTPState *s = USB_MTP(dev);
-
- usb_desc_create_serial(dev);
- usb_desc_init(dev);
- QTAILQ_INIT(&s->objects);
- if (s->desc == NULL) {
- if (s->root == NULL) {
- error_setg(errp, "usb-mtp: x-root property must be configured");
- return;
- }
- s->desc = strrchr(s->root, '/');
- if (s->desc && s->desc[0]) {
- s->desc = g_strdup(s->desc + 1);
- } else {
- s->desc = g_strdup("none");
- }
- }
-}
-
-static const VMStateDescription vmstate_usb_mtp = {
- .name = "usb-mtp",
- .unmigratable = 1,
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_USB_DEVICE(dev, MTPState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property mtp_properties[] = {
- DEFINE_PROP_STRING("x-root", MTPState, root),
- DEFINE_PROP_STRING("desc", MTPState, desc),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void usb_mtp_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
-
- uc->realize = usb_mtp_realize;
- uc->product_desc = "QEMU USB MTP";
- uc->usb_desc = &desc;
- uc->cancel_packet = usb_mtp_cancel_packet;
- uc->handle_attach = usb_desc_attach;
- uc->handle_reset = usb_mtp_handle_reset;
- uc->handle_control = usb_mtp_handle_control;
- uc->handle_data = usb_mtp_handle_data;
- dc->fw_name = "mtp";
- dc->vmsd = &vmstate_usb_mtp;
- dc->props = mtp_properties;
-}
-
-static TypeInfo mtp_info = {
- .name = TYPE_USB_MTP,
- .parent = TYPE_USB_DEVICE,
- .instance_size = sizeof(MTPState),
- .class_init = usb_mtp_class_initfn,
-};
-
-static void usb_mtp_register_types(void)
-{
- type_register_static(&mtp_info);
-}
-
-type_init(usb_mtp_register_types)
diff --git a/qemu/hw/usb/dev-network.c b/qemu/hw/usb/dev-network.c
deleted file mode 100644
index 74306b58e..000000000
--- a/qemu/hw/usb/dev-network.c
+++ /dev/null
@@ -1,1455 +0,0 @@
-/*
- * QEMU USB Net devices
- *
- * Copyright (c) 2006 Thomas Sailer
- * Copyright (c) 2008 Andrzej Zaborowski
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "hw/usb.h"
-#include "hw/usb/desc.h"
-#include "net/net.h"
-#include "qemu/error-report.h"
-#include "qemu/queue.h"
-#include "qemu/config-file.h"
-#include "sysemu/sysemu.h"
-#include "qemu/iov.h"
-#include "qemu/cutils.h"
-
-/*#define TRAFFIC_DEBUG*/
-/* Thanks to NetChip Technologies for donating this product ID.
- * It's for devices with only CDC Ethernet configurations.
- */
-#define CDC_VENDOR_NUM 0x0525 /* NetChip */
-#define CDC_PRODUCT_NUM 0xa4a1 /* Linux-USB Ethernet Gadget */
-/* For hardware that can talk RNDIS and either of the above protocols,
- * use this ID ... the windows INF files will know it.
- */
-#define RNDIS_VENDOR_NUM 0x0525 /* NetChip */
-#define RNDIS_PRODUCT_NUM 0xa4a2 /* Ethernet/RNDIS Gadget */
-
-enum usbstring_idx {
- STRING_MANUFACTURER = 1,
- STRING_PRODUCT,
- STRING_ETHADDR,
- STRING_DATA,
- STRING_CONTROL,
- STRING_RNDIS_CONTROL,
- STRING_CDC,
- STRING_SUBSET,
- STRING_RNDIS,
- STRING_SERIALNUMBER,
-};
-
-#define DEV_CONFIG_VALUE 1 /* CDC or a subset */
-#define DEV_RNDIS_CONFIG_VALUE 2 /* RNDIS; optional */
-
-#define USB_CDC_SUBCLASS_ACM 0x02
-#define USB_CDC_SUBCLASS_ETHERNET 0x06
-
-#define USB_CDC_PROTO_NONE 0
-#define USB_CDC_ACM_PROTO_VENDOR 0xff
-
-#define USB_CDC_HEADER_TYPE 0x00 /* header_desc */
-#define USB_CDC_CALL_MANAGEMENT_TYPE 0x01 /* call_mgmt_descriptor */
-#define USB_CDC_ACM_TYPE 0x02 /* acm_descriptor */
-#define USB_CDC_UNION_TYPE 0x06 /* union_desc */
-#define USB_CDC_ETHERNET_TYPE 0x0f /* ether_desc */
-
-#define USB_CDC_SEND_ENCAPSULATED_COMMAND 0x00
-#define USB_CDC_GET_ENCAPSULATED_RESPONSE 0x01
-#define USB_CDC_REQ_SET_LINE_CODING 0x20
-#define USB_CDC_REQ_GET_LINE_CODING 0x21
-#define USB_CDC_REQ_SET_CONTROL_LINE_STATE 0x22
-#define USB_CDC_REQ_SEND_BREAK 0x23
-#define USB_CDC_SET_ETHERNET_MULTICAST_FILTERS 0x40
-#define USB_CDC_SET_ETHERNET_PM_PATTERN_FILTER 0x41
-#define USB_CDC_GET_ETHERNET_PM_PATTERN_FILTER 0x42
-#define USB_CDC_SET_ETHERNET_PACKET_FILTER 0x43
-#define USB_CDC_GET_ETHERNET_STATISTIC 0x44
-
-#define LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */
-#define STATUS_BYTECOUNT 16 /* 8 byte header + data */
-
-#define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */
-
-static const USBDescStrings usb_net_stringtable = {
- [STRING_MANUFACTURER] = "QEMU",
- [STRING_PRODUCT] = "RNDIS/QEMU USB Network Device",
- [STRING_ETHADDR] = "400102030405",
- [STRING_DATA] = "QEMU USB Net Data Interface",
- [STRING_CONTROL] = "QEMU USB Net Control Interface",
- [STRING_RNDIS_CONTROL] = "QEMU USB Net RNDIS Control Interface",
- [STRING_CDC] = "QEMU USB Net CDC",
- [STRING_SUBSET] = "QEMU USB Net Subset",
- [STRING_RNDIS] = "QEMU USB Net RNDIS",
- [STRING_SERIALNUMBER] = "1",
-};
-
-static const USBDescIface desc_iface_rndis[] = {
- {
- /* RNDIS Control Interface */
- .bInterfaceNumber = 0,
- .bNumEndpoints = 1,
- .bInterfaceClass = USB_CLASS_COMM,
- .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
- .bInterfaceProtocol = USB_CDC_ACM_PROTO_VENDOR,
- .iInterface = STRING_RNDIS_CONTROL,
- .ndesc = 4,
- .descs = (USBDescOther[]) {
- {
- /* Header Descriptor */
- .data = (uint8_t[]) {
- 0x05, /* u8 bLength */
- USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
- USB_CDC_HEADER_TYPE, /* u8 bDescriptorSubType */
- 0x10, 0x01, /* le16 bcdCDC */
- },
- },{
- /* Call Management Descriptor */
- .data = (uint8_t[]) {
- 0x05, /* u8 bLength */
- USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
- USB_CDC_CALL_MANAGEMENT_TYPE, /* u8 bDescriptorSubType */
- 0x00, /* u8 bmCapabilities */
- 0x01, /* u8 bDataInterface */
- },
- },{
- /* ACM Descriptor */
- .data = (uint8_t[]) {
- 0x04, /* u8 bLength */
- USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
- USB_CDC_ACM_TYPE, /* u8 bDescriptorSubType */
- 0x00, /* u8 bmCapabilities */
- },
- },{
- /* Union Descriptor */
- .data = (uint8_t[]) {
- 0x05, /* u8 bLength */
- USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
- USB_CDC_UNION_TYPE, /* u8 bDescriptorSubType */
- 0x00, /* u8 bMasterInterface0 */
- 0x01, /* u8 bSlaveInterface0 */
- },
- },
- },
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | 0x01,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = STATUS_BYTECOUNT,
- .bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC,
- },
- }
- },{
- /* RNDIS Data Interface */
- .bInterfaceNumber = 1,
- .bNumEndpoints = 2,
- .bInterfaceClass = USB_CLASS_CDC_DATA,
- .iInterface = STRING_DATA,
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | 0x02,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 0x40,
- },{
- .bEndpointAddress = USB_DIR_OUT | 0x02,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 0x40,
- }
- }
- }
-};
-
-static const USBDescIface desc_iface_cdc[] = {
- {
- /* CDC Control Interface */
- .bInterfaceNumber = 0,
- .bNumEndpoints = 1,
- .bInterfaceClass = USB_CLASS_COMM,
- .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET,
- .bInterfaceProtocol = USB_CDC_PROTO_NONE,
- .iInterface = STRING_CONTROL,
- .ndesc = 3,
- .descs = (USBDescOther[]) {
- {
- /* Header Descriptor */
- .data = (uint8_t[]) {
- 0x05, /* u8 bLength */
- USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
- USB_CDC_HEADER_TYPE, /* u8 bDescriptorSubType */
- 0x10, 0x01, /* le16 bcdCDC */
- },
- },{
- /* Union Descriptor */
- .data = (uint8_t[]) {
- 0x05, /* u8 bLength */
- USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
- USB_CDC_UNION_TYPE, /* u8 bDescriptorSubType */
- 0x00, /* u8 bMasterInterface0 */
- 0x01, /* u8 bSlaveInterface0 */
- },
- },{
- /* Ethernet Descriptor */
- .data = (uint8_t[]) {
- 0x0d, /* u8 bLength */
- USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
- USB_CDC_ETHERNET_TYPE, /* u8 bDescriptorSubType */
- STRING_ETHADDR, /* u8 iMACAddress */
- 0x00, 0x00, 0x00, 0x00, /* le32 bmEthernetStatistics */
- ETH_FRAME_LEN & 0xff,
- ETH_FRAME_LEN >> 8, /* le16 wMaxSegmentSize */
- 0x00, 0x00, /* le16 wNumberMCFilters */
- 0x00, /* u8 bNumberPowerFilters */
- },
- },
- },
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | 0x01,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = STATUS_BYTECOUNT,
- .bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC,
- },
- }
- },{
- /* CDC Data Interface (off) */
- .bInterfaceNumber = 1,
- .bAlternateSetting = 0,
- .bNumEndpoints = 0,
- .bInterfaceClass = USB_CLASS_CDC_DATA,
- },{
- /* CDC Data Interface */
- .bInterfaceNumber = 1,
- .bAlternateSetting = 1,
- .bNumEndpoints = 2,
- .bInterfaceClass = USB_CLASS_CDC_DATA,
- .iInterface = STRING_DATA,
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | 0x02,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 0x40,
- },{
- .bEndpointAddress = USB_DIR_OUT | 0x02,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 0x40,
- }
- }
- }
-};
-
-static const USBDescDevice desc_device_net = {
- .bcdUSB = 0x0200,
- .bDeviceClass = USB_CLASS_COMM,
- .bMaxPacketSize0 = 0x40,
- .bNumConfigurations = 2,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 2,
- .bConfigurationValue = DEV_RNDIS_CONFIG_VALUE,
- .iConfiguration = STRING_RNDIS,
- .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
- .bMaxPower = 0x32,
- .nif = ARRAY_SIZE(desc_iface_rndis),
- .ifs = desc_iface_rndis,
- },{
- .bNumInterfaces = 2,
- .bConfigurationValue = DEV_CONFIG_VALUE,
- .iConfiguration = STRING_CDC,
- .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
- .bMaxPower = 0x32,
- .nif = ARRAY_SIZE(desc_iface_cdc),
- .ifs = desc_iface_cdc,
- }
- },
-};
-
-static const USBDesc desc_net = {
- .id = {
- .idVendor = RNDIS_VENDOR_NUM,
- .idProduct = RNDIS_PRODUCT_NUM,
- .bcdDevice = 0,
- .iManufacturer = STRING_MANUFACTURER,
- .iProduct = STRING_PRODUCT,
- .iSerialNumber = STRING_SERIALNUMBER,
- },
- .full = &desc_device_net,
- .str = usb_net_stringtable,
-};
-
-/*
- * RNDIS Definitions - in theory not specific to USB.
- */
-#define RNDIS_MAXIMUM_FRAME_SIZE 1518
-#define RNDIS_MAX_TOTAL_SIZE 1558
-
-/* Remote NDIS Versions */
-#define RNDIS_MAJOR_VERSION 1
-#define RNDIS_MINOR_VERSION 0
-
-/* Status Values */
-#define RNDIS_STATUS_SUCCESS 0x00000000U /* Success */
-#define RNDIS_STATUS_FAILURE 0xc0000001U /* Unspecified error */
-#define RNDIS_STATUS_INVALID_DATA 0xc0010015U /* Invalid data */
-#define RNDIS_STATUS_NOT_SUPPORTED 0xc00000bbU /* Unsupported request */
-#define RNDIS_STATUS_MEDIA_CONNECT 0x4001000bU /* Device connected */
-#define RNDIS_STATUS_MEDIA_DISCONNECT 0x4001000cU /* Device disconnected */
-
-/* Message Set for Connectionless (802.3) Devices */
-enum {
- RNDIS_PACKET_MSG = 1,
- RNDIS_INITIALIZE_MSG = 2, /* Initialize device */
- RNDIS_HALT_MSG = 3,
- RNDIS_QUERY_MSG = 4,
- RNDIS_SET_MSG = 5,
- RNDIS_RESET_MSG = 6,
- RNDIS_INDICATE_STATUS_MSG = 7,
- RNDIS_KEEPALIVE_MSG = 8,
-};
-
-/* Message completion */
-enum {
- RNDIS_INITIALIZE_CMPLT = 0x80000002U,
- RNDIS_QUERY_CMPLT = 0x80000004U,
- RNDIS_SET_CMPLT = 0x80000005U,
- RNDIS_RESET_CMPLT = 0x80000006U,
- RNDIS_KEEPALIVE_CMPLT = 0x80000008U,
-};
-
-/* Device Flags */
-enum {
- RNDIS_DF_CONNECTIONLESS = 1,
- RNDIS_DF_CONNECTIONORIENTED = 2,
-};
-
-#define RNDIS_MEDIUM_802_3 0x00000000U
-
-/* from drivers/net/sk98lin/h/skgepnmi.h */
-#define OID_PNP_CAPABILITIES 0xfd010100
-#define OID_PNP_SET_POWER 0xfd010101
-#define OID_PNP_QUERY_POWER 0xfd010102
-#define OID_PNP_ADD_WAKE_UP_PATTERN 0xfd010103
-#define OID_PNP_REMOVE_WAKE_UP_PATTERN 0xfd010104
-#define OID_PNP_ENABLE_WAKE_UP 0xfd010106
-
-typedef uint32_t le32;
-
-typedef struct rndis_init_msg_type {
- le32 MessageType;
- le32 MessageLength;
- le32 RequestID;
- le32 MajorVersion;
- le32 MinorVersion;
- le32 MaxTransferSize;
-} rndis_init_msg_type;
-
-typedef struct rndis_init_cmplt_type {
- le32 MessageType;
- le32 MessageLength;
- le32 RequestID;
- le32 Status;
- le32 MajorVersion;
- le32 MinorVersion;
- le32 DeviceFlags;
- le32 Medium;
- le32 MaxPacketsPerTransfer;
- le32 MaxTransferSize;
- le32 PacketAlignmentFactor;
- le32 AFListOffset;
- le32 AFListSize;
-} rndis_init_cmplt_type;
-
-typedef struct rndis_halt_msg_type {
- le32 MessageType;
- le32 MessageLength;
- le32 RequestID;
-} rndis_halt_msg_type;
-
-typedef struct rndis_query_msg_type {
- le32 MessageType;
- le32 MessageLength;
- le32 RequestID;
- le32 OID;
- le32 InformationBufferLength;
- le32 InformationBufferOffset;
- le32 DeviceVcHandle;
-} rndis_query_msg_type;
-
-typedef struct rndis_query_cmplt_type {
- le32 MessageType;
- le32 MessageLength;
- le32 RequestID;
- le32 Status;
- le32 InformationBufferLength;
- le32 InformationBufferOffset;
-} rndis_query_cmplt_type;
-
-typedef struct rndis_set_msg_type {
- le32 MessageType;
- le32 MessageLength;
- le32 RequestID;
- le32 OID;
- le32 InformationBufferLength;
- le32 InformationBufferOffset;
- le32 DeviceVcHandle;
-} rndis_set_msg_type;
-
-typedef struct rndis_set_cmplt_type {
- le32 MessageType;
- le32 MessageLength;
- le32 RequestID;
- le32 Status;
-} rndis_set_cmplt_type;
-
-typedef struct rndis_reset_msg_type {
- le32 MessageType;
- le32 MessageLength;
- le32 Reserved;
-} rndis_reset_msg_type;
-
-typedef struct rndis_reset_cmplt_type {
- le32 MessageType;
- le32 MessageLength;
- le32 Status;
- le32 AddressingReset;
-} rndis_reset_cmplt_type;
-
-typedef struct rndis_indicate_status_msg_type {
- le32 MessageType;
- le32 MessageLength;
- le32 Status;
- le32 StatusBufferLength;
- le32 StatusBufferOffset;
-} rndis_indicate_status_msg_type;
-
-typedef struct rndis_keepalive_msg_type {
- le32 MessageType;
- le32 MessageLength;
- le32 RequestID;
-} rndis_keepalive_msg_type;
-
-typedef struct rndis_keepalive_cmplt_type {
- le32 MessageType;
- le32 MessageLength;
- le32 RequestID;
- le32 Status;
-} rndis_keepalive_cmplt_type;
-
-struct rndis_packet_msg_type {
- le32 MessageType;
- le32 MessageLength;
- le32 DataOffset;
- le32 DataLength;
- le32 OOBDataOffset;
- le32 OOBDataLength;
- le32 NumOOBDataElements;
- le32 PerPacketInfoOffset;
- le32 PerPacketInfoLength;
- le32 VcHandle;
- le32 Reserved;
-};
-
-struct rndis_config_parameter {
- le32 ParameterNameOffset;
- le32 ParameterNameLength;
- le32 ParameterType;
- le32 ParameterValueOffset;
- le32 ParameterValueLength;
-};
-
-/* implementation specific */
-enum rndis_state
-{
- RNDIS_UNINITIALIZED,
- RNDIS_INITIALIZED,
- RNDIS_DATA_INITIALIZED,
-};
-
-/* from ndis.h */
-enum ndis_oid {
- /* Required Object IDs (OIDs) */
- OID_GEN_SUPPORTED_LIST = 0x00010101,
- OID_GEN_HARDWARE_STATUS = 0x00010102,
- OID_GEN_MEDIA_SUPPORTED = 0x00010103,
- OID_GEN_MEDIA_IN_USE = 0x00010104,
- OID_GEN_MAXIMUM_LOOKAHEAD = 0x00010105,
- OID_GEN_MAXIMUM_FRAME_SIZE = 0x00010106,
- OID_GEN_LINK_SPEED = 0x00010107,
- OID_GEN_TRANSMIT_BUFFER_SPACE = 0x00010108,
- OID_GEN_RECEIVE_BUFFER_SPACE = 0x00010109,
- OID_GEN_TRANSMIT_BLOCK_SIZE = 0x0001010a,
- OID_GEN_RECEIVE_BLOCK_SIZE = 0x0001010b,
- OID_GEN_VENDOR_ID = 0x0001010c,
- OID_GEN_VENDOR_DESCRIPTION = 0x0001010d,
- OID_GEN_CURRENT_PACKET_FILTER = 0x0001010e,
- OID_GEN_CURRENT_LOOKAHEAD = 0x0001010f,
- OID_GEN_DRIVER_VERSION = 0x00010110,
- OID_GEN_MAXIMUM_TOTAL_SIZE = 0x00010111,
- OID_GEN_PROTOCOL_OPTIONS = 0x00010112,
- OID_GEN_MAC_OPTIONS = 0x00010113,
- OID_GEN_MEDIA_CONNECT_STATUS = 0x00010114,
- OID_GEN_MAXIMUM_SEND_PACKETS = 0x00010115,
- OID_GEN_VENDOR_DRIVER_VERSION = 0x00010116,
- OID_GEN_SUPPORTED_GUIDS = 0x00010117,
- OID_GEN_NETWORK_LAYER_ADDRESSES = 0x00010118,
- OID_GEN_TRANSPORT_HEADER_OFFSET = 0x00010119,
- OID_GEN_MACHINE_NAME = 0x0001021a,
- OID_GEN_RNDIS_CONFIG_PARAMETER = 0x0001021b,
- OID_GEN_VLAN_ID = 0x0001021c,
-
- /* Optional OIDs */
- OID_GEN_MEDIA_CAPABILITIES = 0x00010201,
- OID_GEN_PHYSICAL_MEDIUM = 0x00010202,
-
- /* Required statistics OIDs */
- OID_GEN_XMIT_OK = 0x00020101,
- OID_GEN_RCV_OK = 0x00020102,
- OID_GEN_XMIT_ERROR = 0x00020103,
- OID_GEN_RCV_ERROR = 0x00020104,
- OID_GEN_RCV_NO_BUFFER = 0x00020105,
-
- /* Optional statistics OIDs */
- OID_GEN_DIRECTED_BYTES_XMIT = 0x00020201,
- OID_GEN_DIRECTED_FRAMES_XMIT = 0x00020202,
- OID_GEN_MULTICAST_BYTES_XMIT = 0x00020203,
- OID_GEN_MULTICAST_FRAMES_XMIT = 0x00020204,
- OID_GEN_BROADCAST_BYTES_XMIT = 0x00020205,
- OID_GEN_BROADCAST_FRAMES_XMIT = 0x00020206,
- OID_GEN_DIRECTED_BYTES_RCV = 0x00020207,
- OID_GEN_DIRECTED_FRAMES_RCV = 0x00020208,
- OID_GEN_MULTICAST_BYTES_RCV = 0x00020209,
- OID_GEN_MULTICAST_FRAMES_RCV = 0x0002020a,
- OID_GEN_BROADCAST_BYTES_RCV = 0x0002020b,
- OID_GEN_BROADCAST_FRAMES_RCV = 0x0002020c,
- OID_GEN_RCV_CRC_ERROR = 0x0002020d,
- OID_GEN_TRANSMIT_QUEUE_LENGTH = 0x0002020e,
- OID_GEN_GET_TIME_CAPS = 0x0002020f,
- OID_GEN_GET_NETCARD_TIME = 0x00020210,
- OID_GEN_NETCARD_LOAD = 0x00020211,
- OID_GEN_DEVICE_PROFILE = 0x00020212,
- OID_GEN_INIT_TIME_MS = 0x00020213,
- OID_GEN_RESET_COUNTS = 0x00020214,
- OID_GEN_MEDIA_SENSE_COUNTS = 0x00020215,
- OID_GEN_FRIENDLY_NAME = 0x00020216,
- OID_GEN_MINIPORT_INFO = 0x00020217,
- OID_GEN_RESET_VERIFY_PARAMETERS = 0x00020218,
-
- /* IEEE 802.3 (Ethernet) OIDs */
- OID_802_3_PERMANENT_ADDRESS = 0x01010101,
- OID_802_3_CURRENT_ADDRESS = 0x01010102,
- OID_802_3_MULTICAST_LIST = 0x01010103,
- OID_802_3_MAXIMUM_LIST_SIZE = 0x01010104,
- OID_802_3_MAC_OPTIONS = 0x01010105,
- OID_802_3_RCV_ERROR_ALIGNMENT = 0x01020101,
- OID_802_3_XMIT_ONE_COLLISION = 0x01020102,
- OID_802_3_XMIT_MORE_COLLISIONS = 0x01020103,
- OID_802_3_XMIT_DEFERRED = 0x01020201,
- OID_802_3_XMIT_MAX_COLLISIONS = 0x01020202,
- OID_802_3_RCV_OVERRUN = 0x01020203,
- OID_802_3_XMIT_UNDERRUN = 0x01020204,
- OID_802_3_XMIT_HEARTBEAT_FAILURE = 0x01020205,
- OID_802_3_XMIT_TIMES_CRS_LOST = 0x01020206,
- OID_802_3_XMIT_LATE_COLLISIONS = 0x01020207,
-};
-
-static const uint32_t oid_supported_list[] =
-{
- /* the general stuff */
- OID_GEN_SUPPORTED_LIST,
- OID_GEN_HARDWARE_STATUS,
- OID_GEN_MEDIA_SUPPORTED,
- OID_GEN_MEDIA_IN_USE,
- OID_GEN_MAXIMUM_FRAME_SIZE,
- OID_GEN_LINK_SPEED,
- OID_GEN_TRANSMIT_BLOCK_SIZE,
- OID_GEN_RECEIVE_BLOCK_SIZE,
- OID_GEN_VENDOR_ID,
- OID_GEN_VENDOR_DESCRIPTION,
- OID_GEN_VENDOR_DRIVER_VERSION,
- OID_GEN_CURRENT_PACKET_FILTER,
- OID_GEN_MAXIMUM_TOTAL_SIZE,
- OID_GEN_MEDIA_CONNECT_STATUS,
- OID_GEN_PHYSICAL_MEDIUM,
-
- /* the statistical stuff */
- OID_GEN_XMIT_OK,
- OID_GEN_RCV_OK,
- OID_GEN_XMIT_ERROR,
- OID_GEN_RCV_ERROR,
- OID_GEN_RCV_NO_BUFFER,
-
- /* IEEE 802.3 */
- /* the general stuff */
- OID_802_3_PERMANENT_ADDRESS,
- OID_802_3_CURRENT_ADDRESS,
- OID_802_3_MULTICAST_LIST,
- OID_802_3_MAC_OPTIONS,
- OID_802_3_MAXIMUM_LIST_SIZE,
-
- /* the statistical stuff */
- OID_802_3_RCV_ERROR_ALIGNMENT,
- OID_802_3_XMIT_ONE_COLLISION,
- OID_802_3_XMIT_MORE_COLLISIONS,
-};
-
-#define NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA (1 << 0)
-#define NDIS_MAC_OPTION_RECEIVE_SERIALIZED (1 << 1)
-#define NDIS_MAC_OPTION_TRANSFERS_NOT_PEND (1 << 2)
-#define NDIS_MAC_OPTION_NO_LOOPBACK (1 << 3)
-#define NDIS_MAC_OPTION_FULL_DUPLEX (1 << 4)
-#define NDIS_MAC_OPTION_EOTX_INDICATION (1 << 5)
-#define NDIS_MAC_OPTION_8021P_PRIORITY (1 << 6)
-
-struct rndis_response {
- QTAILQ_ENTRY(rndis_response) entries;
- uint32_t length;
- uint8_t buf[0];
-};
-
-typedef struct USBNetState {
- USBDevice dev;
-
- enum rndis_state rndis_state;
- uint32_t medium;
- uint32_t speed;
- uint32_t media_state;
- uint16_t filter;
- uint32_t vendorid;
-
- unsigned int out_ptr;
- uint8_t out_buf[2048];
-
- unsigned int in_ptr, in_len;
- uint8_t in_buf[2048];
-
- USBEndpoint *intr;
-
- char usbstring_mac[13];
- NICState *nic;
- NICConf conf;
- QTAILQ_HEAD(rndis_resp_head, rndis_response) rndis_resp;
-} USBNetState;
-
-#define TYPE_USB_NET "usb-net"
-#define USB_NET(obj) OBJECT_CHECK(USBNetState, (obj), TYPE_USB_NET)
-
-static int is_rndis(USBNetState *s)
-{
- return s->dev.config ?
- s->dev.config->bConfigurationValue == DEV_RNDIS_CONFIG_VALUE : 0;
-}
-
-static int ndis_query(USBNetState *s, uint32_t oid,
- uint8_t *inbuf, unsigned int inlen, uint8_t *outbuf,
- size_t outlen)
-{
- unsigned int i;
-
- switch (oid) {
- /* general oids (table 4-1) */
- /* mandatory */
- case OID_GEN_SUPPORTED_LIST:
- for (i = 0; i < ARRAY_SIZE(oid_supported_list); i++)
- ((le32 *) outbuf)[i] = cpu_to_le32(oid_supported_list[i]);
- return sizeof(oid_supported_list);
-
- /* mandatory */
- case OID_GEN_HARDWARE_STATUS:
- *((le32 *) outbuf) = cpu_to_le32(0);
- return sizeof(le32);
-
- /* mandatory */
- case OID_GEN_MEDIA_SUPPORTED:
- *((le32 *) outbuf) = cpu_to_le32(s->medium);
- return sizeof(le32);
-
- /* mandatory */
- case OID_GEN_MEDIA_IN_USE:
- *((le32 *) outbuf) = cpu_to_le32(s->medium);
- return sizeof(le32);
-
- /* mandatory */
- case OID_GEN_MAXIMUM_FRAME_SIZE:
- *((le32 *) outbuf) = cpu_to_le32(ETH_FRAME_LEN);
- return sizeof(le32);
-
- /* mandatory */
- case OID_GEN_LINK_SPEED:
- *((le32 *) outbuf) = cpu_to_le32(s->speed);
- return sizeof(le32);
-
- /* mandatory */
- case OID_GEN_TRANSMIT_BLOCK_SIZE:
- *((le32 *) outbuf) = cpu_to_le32(ETH_FRAME_LEN);
- return sizeof(le32);
-
- /* mandatory */
- case OID_GEN_RECEIVE_BLOCK_SIZE:
- *((le32 *) outbuf) = cpu_to_le32(ETH_FRAME_LEN);
- return sizeof(le32);
-
- /* mandatory */
- case OID_GEN_VENDOR_ID:
- *((le32 *) outbuf) = cpu_to_le32(s->vendorid);
- return sizeof(le32);
-
- /* mandatory */
- case OID_GEN_VENDOR_DESCRIPTION:
- pstrcpy((char *)outbuf, outlen, "QEMU USB RNDIS Net");
- return strlen((char *)outbuf) + 1;
-
- case OID_GEN_VENDOR_DRIVER_VERSION:
- *((le32 *) outbuf) = cpu_to_le32(1);
- return sizeof(le32);
-
- /* mandatory */
- case OID_GEN_CURRENT_PACKET_FILTER:
- *((le32 *) outbuf) = cpu_to_le32(s->filter);
- return sizeof(le32);
-
- /* mandatory */
- case OID_GEN_MAXIMUM_TOTAL_SIZE:
- *((le32 *) outbuf) = cpu_to_le32(RNDIS_MAX_TOTAL_SIZE);
- return sizeof(le32);
-
- /* mandatory */
- case OID_GEN_MEDIA_CONNECT_STATUS:
- *((le32 *) outbuf) = cpu_to_le32(s->media_state);
- return sizeof(le32);
-
- case OID_GEN_PHYSICAL_MEDIUM:
- *((le32 *) outbuf) = cpu_to_le32(0);
- return sizeof(le32);
-
- case OID_GEN_MAC_OPTIONS:
- *((le32 *) outbuf) = cpu_to_le32(
- NDIS_MAC_OPTION_RECEIVE_SERIALIZED |
- NDIS_MAC_OPTION_FULL_DUPLEX);
- return sizeof(le32);
-
- /* statistics OIDs (table 4-2) */
- /* mandatory */
- case OID_GEN_XMIT_OK:
- *((le32 *) outbuf) = cpu_to_le32(0);
- return sizeof(le32);
-
- /* mandatory */
- case OID_GEN_RCV_OK:
- *((le32 *) outbuf) = cpu_to_le32(0);
- return sizeof(le32);
-
- /* mandatory */
- case OID_GEN_XMIT_ERROR:
- *((le32 *) outbuf) = cpu_to_le32(0);
- return sizeof(le32);
-
- /* mandatory */
- case OID_GEN_RCV_ERROR:
- *((le32 *) outbuf) = cpu_to_le32(0);
- return sizeof(le32);
-
- /* mandatory */
- case OID_GEN_RCV_NO_BUFFER:
- *((le32 *) outbuf) = cpu_to_le32(0);
- return sizeof(le32);
-
- /* ieee802.3 OIDs (table 4-3) */
- /* mandatory */
- case OID_802_3_PERMANENT_ADDRESS:
- memcpy(outbuf, s->conf.macaddr.a, 6);
- return 6;
-
- /* mandatory */
- case OID_802_3_CURRENT_ADDRESS:
- memcpy(outbuf, s->conf.macaddr.a, 6);
- return 6;
-
- /* mandatory */
- case OID_802_3_MULTICAST_LIST:
- *((le32 *) outbuf) = cpu_to_le32(0xe0000000);
- return sizeof(le32);
-
- /* mandatory */
- case OID_802_3_MAXIMUM_LIST_SIZE:
- *((le32 *) outbuf) = cpu_to_le32(1);
- return sizeof(le32);
-
- case OID_802_3_MAC_OPTIONS:
- return 0;
-
- /* ieee802.3 statistics OIDs (table 4-4) */
- /* mandatory */
- case OID_802_3_RCV_ERROR_ALIGNMENT:
- *((le32 *) outbuf) = cpu_to_le32(0);
- return sizeof(le32);
-
- /* mandatory */
- case OID_802_3_XMIT_ONE_COLLISION:
- *((le32 *) outbuf) = cpu_to_le32(0);
- return sizeof(le32);
-
- /* mandatory */
- case OID_802_3_XMIT_MORE_COLLISIONS:
- *((le32 *) outbuf) = cpu_to_le32(0);
- return sizeof(le32);
-
- default:
- fprintf(stderr, "usbnet: unknown OID 0x%08x\n", oid);
- return 0;
- }
- return -1;
-}
-
-static int ndis_set(USBNetState *s, uint32_t oid,
- uint8_t *inbuf, unsigned int inlen)
-{
- switch (oid) {
- case OID_GEN_CURRENT_PACKET_FILTER:
- s->filter = le32_to_cpup((le32 *) inbuf);
- if (s->filter) {
- s->rndis_state = RNDIS_DATA_INITIALIZED;
- } else {
- s->rndis_state = RNDIS_INITIALIZED;
- }
- return 0;
-
- case OID_802_3_MULTICAST_LIST:
- return 0;
- }
- return -1;
-}
-
-static int rndis_get_response(USBNetState *s, uint8_t *buf)
-{
- int ret = 0;
- struct rndis_response *r = s->rndis_resp.tqh_first;
-
- if (!r)
- return ret;
-
- QTAILQ_REMOVE(&s->rndis_resp, r, entries);
- ret = r->length;
- memcpy(buf, r->buf, r->length);
- g_free(r);
-
- return ret;
-}
-
-static void *rndis_queue_response(USBNetState *s, unsigned int length)
-{
- struct rndis_response *r =
- g_malloc0(sizeof(struct rndis_response) + length);
-
- if (QTAILQ_EMPTY(&s->rndis_resp)) {
- usb_wakeup(s->intr, 0);
- }
-
- QTAILQ_INSERT_TAIL(&s->rndis_resp, r, entries);
- r->length = length;
-
- return &r->buf[0];
-}
-
-static void rndis_clear_responsequeue(USBNetState *s)
-{
- struct rndis_response *r;
-
- while ((r = s->rndis_resp.tqh_first)) {
- QTAILQ_REMOVE(&s->rndis_resp, r, entries);
- g_free(r);
- }
-}
-
-static int rndis_init_response(USBNetState *s, rndis_init_msg_type *buf)
-{
- rndis_init_cmplt_type *resp =
- rndis_queue_response(s, sizeof(rndis_init_cmplt_type));
-
- if (!resp)
- return USB_RET_STALL;
-
- resp->MessageType = cpu_to_le32(RNDIS_INITIALIZE_CMPLT);
- resp->MessageLength = cpu_to_le32(sizeof(rndis_init_cmplt_type));
- resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
- resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
- resp->MajorVersion = cpu_to_le32(RNDIS_MAJOR_VERSION);
- resp->MinorVersion = cpu_to_le32(RNDIS_MINOR_VERSION);
- resp->DeviceFlags = cpu_to_le32(RNDIS_DF_CONNECTIONLESS);
- resp->Medium = cpu_to_le32(RNDIS_MEDIUM_802_3);
- resp->MaxPacketsPerTransfer = cpu_to_le32(1);
- resp->MaxTransferSize = cpu_to_le32(ETH_FRAME_LEN +
- sizeof(struct rndis_packet_msg_type) + 22);
- resp->PacketAlignmentFactor = cpu_to_le32(0);
- resp->AFListOffset = cpu_to_le32(0);
- resp->AFListSize = cpu_to_le32(0);
- return 0;
-}
-
-static int rndis_query_response(USBNetState *s,
- rndis_query_msg_type *buf, unsigned int length)
-{
- rndis_query_cmplt_type *resp;
- /* oid_supported_list is the largest data reply */
- uint8_t infobuf[sizeof(oid_supported_list)];
- uint32_t bufoffs, buflen;
- int infobuflen;
- unsigned int resplen;
-
- bufoffs = le32_to_cpu(buf->InformationBufferOffset) + 8;
- buflen = le32_to_cpu(buf->InformationBufferLength);
- if (buflen > length || bufoffs >= length || bufoffs + buflen > length) {
- return USB_RET_STALL;
- }
-
- infobuflen = ndis_query(s, le32_to_cpu(buf->OID),
- bufoffs + (uint8_t *) buf, buflen, infobuf,
- sizeof(infobuf));
- resplen = sizeof(rndis_query_cmplt_type) +
- ((infobuflen < 0) ? 0 : infobuflen);
- resp = rndis_queue_response(s, resplen);
- if (!resp)
- return USB_RET_STALL;
-
- resp->MessageType = cpu_to_le32(RNDIS_QUERY_CMPLT);
- resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
- resp->MessageLength = cpu_to_le32(resplen);
-
- if (infobuflen < 0) {
- /* OID not supported */
- resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED);
- resp->InformationBufferLength = cpu_to_le32(0);
- resp->InformationBufferOffset = cpu_to_le32(0);
- return 0;
- }
-
- resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
- resp->InformationBufferOffset =
- cpu_to_le32(infobuflen ? sizeof(rndis_query_cmplt_type) - 8 : 0);
- resp->InformationBufferLength = cpu_to_le32(infobuflen);
- memcpy(resp + 1, infobuf, infobuflen);
-
- return 0;
-}
-
-static int rndis_set_response(USBNetState *s,
- rndis_set_msg_type *buf, unsigned int length)
-{
- rndis_set_cmplt_type *resp =
- rndis_queue_response(s, sizeof(rndis_set_cmplt_type));
- uint32_t bufoffs, buflen;
- int ret;
-
- if (!resp)
- return USB_RET_STALL;
-
- bufoffs = le32_to_cpu(buf->InformationBufferOffset) + 8;
- buflen = le32_to_cpu(buf->InformationBufferLength);
- if (buflen > length || bufoffs >= length || bufoffs + buflen > length) {
- return USB_RET_STALL;
- }
-
- ret = ndis_set(s, le32_to_cpu(buf->OID),
- bufoffs + (uint8_t *) buf, buflen);
- resp->MessageType = cpu_to_le32(RNDIS_SET_CMPLT);
- resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
- resp->MessageLength = cpu_to_le32(sizeof(rndis_set_cmplt_type));
- if (ret < 0) {
- /* OID not supported */
- resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED);
- return 0;
- }
- resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
-
- return 0;
-}
-
-static int rndis_reset_response(USBNetState *s, rndis_reset_msg_type *buf)
-{
- rndis_reset_cmplt_type *resp =
- rndis_queue_response(s, sizeof(rndis_reset_cmplt_type));
-
- if (!resp)
- return USB_RET_STALL;
-
- resp->MessageType = cpu_to_le32(RNDIS_RESET_CMPLT);
- resp->MessageLength = cpu_to_le32(sizeof(rndis_reset_cmplt_type));
- resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
- resp->AddressingReset = cpu_to_le32(1); /* reset information */
-
- return 0;
-}
-
-static int rndis_keepalive_response(USBNetState *s,
- rndis_keepalive_msg_type *buf)
-{
- rndis_keepalive_cmplt_type *resp =
- rndis_queue_response(s, sizeof(rndis_keepalive_cmplt_type));
-
- if (!resp)
- return USB_RET_STALL;
-
- resp->MessageType = cpu_to_le32(RNDIS_KEEPALIVE_CMPLT);
- resp->MessageLength = cpu_to_le32(sizeof(rndis_keepalive_cmplt_type));
- resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
- resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
-
- return 0;
-}
-
-/* Prepare to receive the next packet */
-static void usb_net_reset_in_buf(USBNetState *s)
-{
- s->in_ptr = s->in_len = 0;
- qemu_flush_queued_packets(qemu_get_queue(s->nic));
-}
-
-static int rndis_parse(USBNetState *s, uint8_t *data, int length)
-{
- uint32_t msg_type;
- le32 *tmp = (le32 *) data;
-
- msg_type = le32_to_cpup(tmp);
-
- switch (msg_type) {
- case RNDIS_INITIALIZE_MSG:
- s->rndis_state = RNDIS_INITIALIZED;
- return rndis_init_response(s, (rndis_init_msg_type *) data);
-
- case RNDIS_HALT_MSG:
- s->rndis_state = RNDIS_UNINITIALIZED;
- return 0;
-
- case RNDIS_QUERY_MSG:
- return rndis_query_response(s, (rndis_query_msg_type *) data, length);
-
- case RNDIS_SET_MSG:
- return rndis_set_response(s, (rndis_set_msg_type *) data, length);
-
- case RNDIS_RESET_MSG:
- rndis_clear_responsequeue(s);
- s->out_ptr = 0;
- usb_net_reset_in_buf(s);
- return rndis_reset_response(s, (rndis_reset_msg_type *) data);
-
- case RNDIS_KEEPALIVE_MSG:
- /* For USB: host does this every 5 seconds */
- return rndis_keepalive_response(s, (rndis_keepalive_msg_type *) data);
- }
-
- return USB_RET_STALL;
-}
-
-static void usb_net_handle_reset(USBDevice *dev)
-{
-}
-
-static void usb_net_handle_control(USBDevice *dev, USBPacket *p,
- int request, int value, int index, int length, uint8_t *data)
-{
- USBNetState *s = (USBNetState *) dev;
- int ret;
-
- ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
- if (ret >= 0) {
- return;
- }
-
- switch(request) {
- case ClassInterfaceOutRequest | USB_CDC_SEND_ENCAPSULATED_COMMAND:
- if (!is_rndis(s) || value || index != 0) {
- goto fail;
- }
-#ifdef TRAFFIC_DEBUG
- {
- unsigned int i;
- fprintf(stderr, "SEND_ENCAPSULATED_COMMAND:");
- for (i = 0; i < length; i++) {
- if (!(i & 15))
- fprintf(stderr, "\n%04x:", i);
- fprintf(stderr, " %02x", data[i]);
- }
- fprintf(stderr, "\n\n");
- }
-#endif
- ret = rndis_parse(s, data, length);
- if (ret < 0) {
- p->status = ret;
- }
- break;
-
- case ClassInterfaceRequest | USB_CDC_GET_ENCAPSULATED_RESPONSE:
- if (!is_rndis(s) || value || index != 0) {
- goto fail;
- }
- p->actual_length = rndis_get_response(s, data);
- if (p->actual_length == 0) {
- data[0] = 0;
- p->actual_length = 1;
- }
-#ifdef TRAFFIC_DEBUG
- {
- unsigned int i;
- fprintf(stderr, "GET_ENCAPSULATED_RESPONSE:");
- for (i = 0; i < p->actual_length; i++) {
- if (!(i & 15))
- fprintf(stderr, "\n%04x:", i);
- fprintf(stderr, " %02x", data[i]);
- }
- fprintf(stderr, "\n\n");
- }
-#endif
- break;
-
- default:
- fail:
- fprintf(stderr, "usbnet: failed control transaction: "
- "request 0x%x value 0x%x index 0x%x length 0x%x\n",
- request, value, index, length);
- p->status = USB_RET_STALL;
- break;
- }
-}
-
-static void usb_net_handle_statusin(USBNetState *s, USBPacket *p)
-{
- le32 buf[2];
-
- if (p->iov.size < 8) {
- p->status = USB_RET_STALL;
- return;
- }
-
- buf[0] = cpu_to_le32(1);
- buf[1] = cpu_to_le32(0);
- usb_packet_copy(p, buf, 8);
- if (!s->rndis_resp.tqh_first) {
- p->status = USB_RET_NAK;
- }
-
-#ifdef TRAFFIC_DEBUG
- fprintf(stderr, "usbnet: interrupt poll len %zu return %d",
- p->iov.size, p->status);
- iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", p->status);
-#endif
-}
-
-static void usb_net_handle_datain(USBNetState *s, USBPacket *p)
-{
- int len;
-
- if (s->in_ptr > s->in_len) {
- usb_net_reset_in_buf(s);
- p->status = USB_RET_NAK;
- return;
- }
- if (!s->in_len) {
- p->status = USB_RET_NAK;
- return;
- }
- len = s->in_len - s->in_ptr;
- if (len > p->iov.size) {
- len = p->iov.size;
- }
- usb_packet_copy(p, &s->in_buf[s->in_ptr], len);
- s->in_ptr += len;
- if (s->in_ptr >= s->in_len &&
- (is_rndis(s) || (s->in_len & (64 - 1)) || !len)) {
- /* no short packet necessary */
- usb_net_reset_in_buf(s);
- }
-
-#ifdef TRAFFIC_DEBUG
- fprintf(stderr, "usbnet: data in len %zu return %d", p->iov.size, len);
- iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", len);
-#endif
-}
-
-static void usb_net_handle_dataout(USBNetState *s, USBPacket *p)
-{
- int sz = sizeof(s->out_buf) - s->out_ptr;
- struct rndis_packet_msg_type *msg =
- (struct rndis_packet_msg_type *) s->out_buf;
- uint32_t len;
-
-#ifdef TRAFFIC_DEBUG
- fprintf(stderr, "usbnet: data out len %zu\n", p->iov.size);
- iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", p->iov.size);
-#endif
-
- if (sz > p->iov.size) {
- sz = p->iov.size;
- }
- usb_packet_copy(p, &s->out_buf[s->out_ptr], sz);
- s->out_ptr += sz;
-
- if (!is_rndis(s)) {
- if (p->iov.size < 64) {
- qemu_send_packet(qemu_get_queue(s->nic), s->out_buf, s->out_ptr);
- s->out_ptr = 0;
- }
- return;
- }
- len = le32_to_cpu(msg->MessageLength);
- if (s->out_ptr < 8 || s->out_ptr < len) {
- return;
- }
- if (le32_to_cpu(msg->MessageType) == RNDIS_PACKET_MSG) {
- uint32_t offs = 8 + le32_to_cpu(msg->DataOffset);
- uint32_t size = le32_to_cpu(msg->DataLength);
- if (offs < len && size < len && offs + size <= len) {
- qemu_send_packet(qemu_get_queue(s->nic), s->out_buf + offs, size);
- }
- }
- s->out_ptr -= len;
- memmove(s->out_buf, &s->out_buf[len], s->out_ptr);
-}
-
-static void usb_net_handle_data(USBDevice *dev, USBPacket *p)
-{
- USBNetState *s = (USBNetState *) dev;
-
- switch(p->pid) {
- case USB_TOKEN_IN:
- switch (p->ep->nr) {
- case 1:
- usb_net_handle_statusin(s, p);
- break;
-
- case 2:
- usb_net_handle_datain(s, p);
- break;
-
- default:
- goto fail;
- }
- break;
-
- case USB_TOKEN_OUT:
- switch (p->ep->nr) {
- case 2:
- usb_net_handle_dataout(s, p);
- break;
-
- default:
- goto fail;
- }
- break;
-
- default:
- fail:
- p->status = USB_RET_STALL;
- break;
- }
-
- if (p->status == USB_RET_STALL) {
- fprintf(stderr, "usbnet: failed data transaction: "
- "pid 0x%x ep 0x%x len 0x%zx\n",
- p->pid, p->ep->nr, p->iov.size);
- }
-}
-
-static ssize_t usbnet_receive(NetClientState *nc, const uint8_t *buf, size_t size)
-{
- USBNetState *s = qemu_get_nic_opaque(nc);
- uint8_t *in_buf = s->in_buf;
- size_t total_size = size;
-
- if (!s->dev.config) {
- return -1;
- }
-
- if (is_rndis(s)) {
- if (s->rndis_state != RNDIS_DATA_INITIALIZED) {
- return -1;
- }
- total_size += sizeof(struct rndis_packet_msg_type);
- }
- if (total_size > sizeof(s->in_buf)) {
- return -1;
- }
-
- /* Only accept packet if input buffer is empty */
- if (s->in_len > 0) {
- return 0;
- }
-
- if (is_rndis(s)) {
- struct rndis_packet_msg_type *msg;
-
- msg = (struct rndis_packet_msg_type *)in_buf;
- memset(msg, 0, sizeof(struct rndis_packet_msg_type));
- msg->MessageType = cpu_to_le32(RNDIS_PACKET_MSG);
- msg->MessageLength = cpu_to_le32(size + sizeof(*msg));
- msg->DataOffset = cpu_to_le32(sizeof(*msg) - 8);
- msg->DataLength = cpu_to_le32(size);
- /* msg->OOBDataOffset;
- * msg->OOBDataLength;
- * msg->NumOOBDataElements;
- * msg->PerPacketInfoOffset;
- * msg->PerPacketInfoLength;
- * msg->VcHandle;
- * msg->Reserved;
- */
- in_buf += sizeof(*msg);
- }
-
- memcpy(in_buf, buf, size);
- s->in_len = total_size;
- s->in_ptr = 0;
- return size;
-}
-
-static void usbnet_cleanup(NetClientState *nc)
-{
- USBNetState *s = qemu_get_nic_opaque(nc);
-
- s->nic = NULL;
-}
-
-static void usb_net_handle_destroy(USBDevice *dev)
-{
- USBNetState *s = (USBNetState *) dev;
-
- /* TODO: remove the nd_table[] entry */
- rndis_clear_responsequeue(s);
- qemu_del_nic(s->nic);
-}
-
-static NetClientInfo net_usbnet_info = {
- .type = NET_CLIENT_OPTIONS_KIND_NIC,
- .size = sizeof(NICState),
- .receive = usbnet_receive,
- .cleanup = usbnet_cleanup,
-};
-
-static void usb_net_realize(USBDevice *dev, Error **errrp)
-{
- USBNetState *s = USB_NET(dev);
-
- usb_desc_create_serial(dev);
- usb_desc_init(dev);
-
- s->rndis_state = RNDIS_UNINITIALIZED;
- QTAILQ_INIT(&s->rndis_resp);
-
- s->medium = 0; /* NDIS_MEDIUM_802_3 */
- s->speed = 1000000; /* 100MBps, in 100Bps units */
- s->media_state = 0; /* NDIS_MEDIA_STATE_CONNECTED */;
- s->filter = 0;
- s->vendorid = 0x1234;
- s->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
-
- qemu_macaddr_default_if_unset(&s->conf.macaddr);
- s->nic = qemu_new_nic(&net_usbnet_info, &s->conf,
- object_get_typename(OBJECT(s)), s->dev.qdev.id, s);
- qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
- snprintf(s->usbstring_mac, sizeof(s->usbstring_mac),
- "%02x%02x%02x%02x%02x%02x",
- 0x40,
- s->conf.macaddr.a[1],
- s->conf.macaddr.a[2],
- s->conf.macaddr.a[3],
- s->conf.macaddr.a[4],
- s->conf.macaddr.a[5]);
- usb_desc_set_string(dev, STRING_ETHADDR, s->usbstring_mac);
-}
-
-static void usb_net_instance_init(Object *obj)
-{
- USBDevice *dev = USB_DEVICE(obj);
- USBNetState *s = USB_NET(dev);
-
- device_add_bootindex_property(obj, &s->conf.bootindex,
- "bootindex", "/ethernet-phy@0",
- &dev->qdev, NULL);
-}
-
-static USBDevice *usb_net_init(USBBus *bus, const char *cmdline)
-{
- Error *local_err = NULL;
- USBDevice *dev;
- QemuOpts *opts;
- int idx;
-
- opts = qemu_opts_parse_noisily(qemu_find_opts("net"), cmdline, false);
- if (!opts) {
- return NULL;
- }
- qemu_opt_set(opts, "type", "nic", &error_abort);
- qemu_opt_set(opts, "model", "usb", &error_abort);
-
- idx = net_client_init(opts, 0, &local_err);
- if (local_err) {
- error_report_err(local_err);
- return NULL;
- }
-
- dev = usb_create(bus, "usb-net");
- qdev_set_nic_properties(&dev->qdev, &nd_table[idx]);
- return dev;
-}
-
-static const VMStateDescription vmstate_usb_net = {
- .name = "usb-net",
- .unmigratable = 1,
-};
-
-static Property net_properties[] = {
- DEFINE_NIC_PROPERTIES(USBNetState, conf),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void usb_net_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
-
- uc->realize = usb_net_realize;
- uc->product_desc = "QEMU USB Network Interface";
- uc->usb_desc = &desc_net;
- uc->handle_reset = usb_net_handle_reset;
- uc->handle_control = usb_net_handle_control;
- uc->handle_data = usb_net_handle_data;
- uc->handle_destroy = usb_net_handle_destroy;
- set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
- dc->fw_name = "network";
- dc->vmsd = &vmstate_usb_net;
- dc->props = net_properties;
-}
-
-static const TypeInfo net_info = {
- .name = TYPE_USB_NET,
- .parent = TYPE_USB_DEVICE,
- .instance_size = sizeof(USBNetState),
- .class_init = usb_net_class_initfn,
- .instance_init = usb_net_instance_init,
-};
-
-static void usb_net_register_types(void)
-{
- type_register_static(&net_info);
- usb_legacy_register(TYPE_USB_NET, "net", usb_net_init);
-}
-
-type_init(usb_net_register_types)
diff --git a/qemu/hw/usb/dev-serial.c b/qemu/hw/usb/dev-serial.c
deleted file mode 100644
index ba8538e60..000000000
--- a/qemu/hw/usb/dev-serial.c
+++ /dev/null
@@ -1,652 +0,0 @@
-/*
- * FTDI FT232BM Device emulation
- *
- * Copyright (c) 2006 CodeSourcery.
- * Copyright (c) 2008 Samuel Thibault <samuel.thibault@ens-lyon.org>
- * Written by Paul Brook, reused for FTDI by Samuel Thibault
- *
- * This code is licensed under the LGPL.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "qemu/cutils.h"
-#include "qemu/error-report.h"
-#include "hw/usb.h"
-#include "hw/usb/desc.h"
-#include "sysemu/char.h"
-
-//#define DEBUG_Serial
-
-#ifdef DEBUG_Serial
-#define DPRINTF(fmt, ...) \
-do { printf("usb-serial: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#endif
-
-#define RECV_BUF 384
-
-/* Commands */
-#define FTDI_RESET 0
-#define FTDI_SET_MDM_CTRL 1
-#define FTDI_SET_FLOW_CTRL 2
-#define FTDI_SET_BAUD 3
-#define FTDI_SET_DATA 4
-#define FTDI_GET_MDM_ST 5
-#define FTDI_SET_EVENT_CHR 6
-#define FTDI_SET_ERROR_CHR 7
-#define FTDI_SET_LATENCY 9
-#define FTDI_GET_LATENCY 10
-
-#define DeviceOutVendor ((USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<8)
-#define DeviceInVendor ((USB_DIR_IN |USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<8)
-
-/* RESET */
-
-#define FTDI_RESET_SIO 0
-#define FTDI_RESET_RX 1
-#define FTDI_RESET_TX 2
-
-/* SET_MDM_CTRL */
-
-#define FTDI_DTR 1
-#define FTDI_SET_DTR (FTDI_DTR << 8)
-#define FTDI_RTS 2
-#define FTDI_SET_RTS (FTDI_RTS << 8)
-
-/* SET_FLOW_CTRL */
-
-#define FTDI_RTS_CTS_HS 1
-#define FTDI_DTR_DSR_HS 2
-#define FTDI_XON_XOFF_HS 4
-
-/* SET_DATA */
-
-#define FTDI_PARITY (0x7 << 8)
-#define FTDI_ODD (0x1 << 8)
-#define FTDI_EVEN (0x2 << 8)
-#define FTDI_MARK (0x3 << 8)
-#define FTDI_SPACE (0x4 << 8)
-
-#define FTDI_STOP (0x3 << 11)
-#define FTDI_STOP1 (0x0 << 11)
-#define FTDI_STOP15 (0x1 << 11)
-#define FTDI_STOP2 (0x2 << 11)
-
-/* GET_MDM_ST */
-/* TODO: should be sent every 40ms */
-#define FTDI_CTS (1<<4) // CTS line status
-#define FTDI_DSR (1<<5) // DSR line status
-#define FTDI_RI (1<<6) // RI line status
-#define FTDI_RLSD (1<<7) // Receive Line Signal Detect
-
-/* Status */
-
-#define FTDI_DR (1<<0) // Data Ready
-#define FTDI_OE (1<<1) // Overrun Err
-#define FTDI_PE (1<<2) // Parity Err
-#define FTDI_FE (1<<3) // Framing Err
-#define FTDI_BI (1<<4) // Break Interrupt
-#define FTDI_THRE (1<<5) // Transmitter Holding Register
-#define FTDI_TEMT (1<<6) // Transmitter Empty
-#define FTDI_FIFO (1<<7) // Error in FIFO
-
-typedef struct {
- USBDevice dev;
- uint8_t recv_buf[RECV_BUF];
- uint16_t recv_ptr;
- uint16_t recv_used;
- uint8_t event_chr;
- uint8_t error_chr;
- uint8_t event_trigger;
- QEMUSerialSetParams params;
- int latency; /* ms */
- CharDriverState *cs;
-} USBSerialState;
-
-#define TYPE_USB_SERIAL "usb-serial-dev"
-#define USB_SERIAL_DEV(obj) OBJECT_CHECK(USBSerialState, (obj), TYPE_USB_SERIAL)
-
-enum {
- STR_MANUFACTURER = 1,
- STR_PRODUCT_SERIAL,
- STR_PRODUCT_BRAILLE,
- STR_SERIALNUMBER,
-};
-
-static const USBDescStrings desc_strings = {
- [STR_MANUFACTURER] = "QEMU",
- [STR_PRODUCT_SERIAL] = "QEMU USB SERIAL",
- [STR_PRODUCT_BRAILLE] = "QEMU USB BAUM BRAILLE",
- [STR_SERIALNUMBER] = "1",
-};
-
-static const USBDescIface desc_iface0 = {
- .bInterfaceNumber = 0,
- .bNumEndpoints = 2,
- .bInterfaceClass = 0xff,
- .bInterfaceSubClass = 0xff,
- .bInterfaceProtocol = 0xff,
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | 0x01,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 64,
- },{
- .bEndpointAddress = USB_DIR_OUT | 0x02,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 64,
- },
- }
-};
-
-static const USBDescDevice desc_device = {
- .bcdUSB = 0x0200,
- .bMaxPacketSize0 = 8,
- .bNumConfigurations = 1,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 1,
- .bConfigurationValue = 1,
- .bmAttributes = USB_CFG_ATT_ONE,
- .bMaxPower = 50,
- .nif = 1,
- .ifs = &desc_iface0,
- },
- },
-};
-
-static const USBDesc desc_serial = {
- .id = {
- .idVendor = 0x0403,
- .idProduct = 0x6001,
- .bcdDevice = 0x0400,
- .iManufacturer = STR_MANUFACTURER,
- .iProduct = STR_PRODUCT_SERIAL,
- .iSerialNumber = STR_SERIALNUMBER,
- },
- .full = &desc_device,
- .str = desc_strings,
-};
-
-static const USBDesc desc_braille = {
- .id = {
- .idVendor = 0x0403,
- .idProduct = 0xfe72,
- .bcdDevice = 0x0400,
- .iManufacturer = STR_MANUFACTURER,
- .iProduct = STR_PRODUCT_BRAILLE,
- .iSerialNumber = STR_SERIALNUMBER,
- },
- .full = &desc_device,
- .str = desc_strings,
-};
-
-static void usb_serial_reset(USBSerialState *s)
-{
- /* TODO: Set flow control to none */
- s->event_chr = 0x0d;
- s->event_trigger = 0;
- s->recv_ptr = 0;
- s->recv_used = 0;
- /* TODO: purge in char driver */
-}
-
-static void usb_serial_handle_reset(USBDevice *dev)
-{
- USBSerialState *s = (USBSerialState *)dev;
-
- DPRINTF("Reset\n");
-
- usb_serial_reset(s);
- /* TODO: Reset char device, send BREAK? */
-}
-
-static uint8_t usb_get_modem_lines(USBSerialState *s)
-{
- int flags;
- uint8_t ret;
-
- if (qemu_chr_fe_ioctl(s->cs, CHR_IOCTL_SERIAL_GET_TIOCM, &flags) == -ENOTSUP)
- return FTDI_CTS|FTDI_DSR|FTDI_RLSD;
-
- ret = 0;
- if (flags & CHR_TIOCM_CTS)
- ret |= FTDI_CTS;
- if (flags & CHR_TIOCM_DSR)
- ret |= FTDI_DSR;
- if (flags & CHR_TIOCM_RI)
- ret |= FTDI_RI;
- if (flags & CHR_TIOCM_CAR)
- ret |= FTDI_RLSD;
-
- return ret;
-}
-
-static void usb_serial_handle_control(USBDevice *dev, USBPacket *p,
- int request, int value, int index, int length, uint8_t *data)
-{
- USBSerialState *s = (USBSerialState *)dev;
- int ret;
-
- DPRINTF("got control %x, value %x\n",request, value);
- ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
- if (ret >= 0) {
- return;
- }
-
- switch (request) {
- case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
- break;
-
- /* Class specific requests. */
- case DeviceOutVendor | FTDI_RESET:
- switch (value) {
- case FTDI_RESET_SIO:
- usb_serial_reset(s);
- break;
- case FTDI_RESET_RX:
- s->recv_ptr = 0;
- s->recv_used = 0;
- /* TODO: purge from char device */
- break;
- case FTDI_RESET_TX:
- /* TODO: purge from char device */
- break;
- }
- break;
- case DeviceOutVendor | FTDI_SET_MDM_CTRL:
- {
- static int flags;
- qemu_chr_fe_ioctl(s->cs,CHR_IOCTL_SERIAL_GET_TIOCM, &flags);
- if (value & FTDI_SET_RTS) {
- if (value & FTDI_RTS)
- flags |= CHR_TIOCM_RTS;
- else
- flags &= ~CHR_TIOCM_RTS;
- }
- if (value & FTDI_SET_DTR) {
- if (value & FTDI_DTR)
- flags |= CHR_TIOCM_DTR;
- else
- flags &= ~CHR_TIOCM_DTR;
- }
- qemu_chr_fe_ioctl(s->cs,CHR_IOCTL_SERIAL_SET_TIOCM, &flags);
- break;
- }
- case DeviceOutVendor | FTDI_SET_FLOW_CTRL:
- /* TODO: ioctl */
- break;
- case DeviceOutVendor | FTDI_SET_BAUD: {
- static const int subdivisors8[8] = { 0, 4, 2, 1, 3, 5, 6, 7 };
- int subdivisor8 = subdivisors8[((value & 0xc000) >> 14)
- | ((index & 1) << 2)];
- int divisor = value & 0x3fff;
-
- /* chip special cases */
- if (divisor == 1 && subdivisor8 == 0)
- subdivisor8 = 4;
- if (divisor == 0 && subdivisor8 == 0)
- divisor = 1;
-
- s->params.speed = (48000000 / 2) / (8 * divisor + subdivisor8);
- qemu_chr_fe_ioctl(s->cs, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params);
- break;
- }
- case DeviceOutVendor | FTDI_SET_DATA:
- switch (value & FTDI_PARITY) {
- case 0:
- s->params.parity = 'N';
- break;
- case FTDI_ODD:
- s->params.parity = 'O';
- break;
- case FTDI_EVEN:
- s->params.parity = 'E';
- break;
- default:
- DPRINTF("unsupported parity %d\n", value & FTDI_PARITY);
- goto fail;
- }
- switch (value & FTDI_STOP) {
- case FTDI_STOP1:
- s->params.stop_bits = 1;
- break;
- case FTDI_STOP2:
- s->params.stop_bits = 2;
- break;
- default:
- DPRINTF("unsupported stop bits %d\n", value & FTDI_STOP);
- goto fail;
- }
- qemu_chr_fe_ioctl(s->cs, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params);
- /* TODO: TX ON/OFF */
- break;
- case DeviceInVendor | FTDI_GET_MDM_ST:
- data[0] = usb_get_modem_lines(s) | 1;
- data[1] = 0;
- p->actual_length = 2;
- break;
- case DeviceOutVendor | FTDI_SET_EVENT_CHR:
- /* TODO: handle it */
- s->event_chr = value;
- break;
- case DeviceOutVendor | FTDI_SET_ERROR_CHR:
- /* TODO: handle it */
- s->error_chr = value;
- break;
- case DeviceOutVendor | FTDI_SET_LATENCY:
- s->latency = value;
- break;
- case DeviceInVendor | FTDI_GET_LATENCY:
- data[0] = s->latency;
- p->actual_length = 1;
- break;
- default:
- fail:
- DPRINTF("got unsupported/bogus control %x, value %x\n", request, value);
- p->status = USB_RET_STALL;
- break;
- }
-}
-
-static void usb_serial_handle_data(USBDevice *dev, USBPacket *p)
-{
- USBSerialState *s = (USBSerialState *)dev;
- uint8_t devep = p->ep->nr;
- struct iovec *iov;
- uint8_t header[2];
- int i, first_len, len;
-
- switch (p->pid) {
- case USB_TOKEN_OUT:
- if (devep != 2)
- goto fail;
- for (i = 0; i < p->iov.niov; i++) {
- iov = p->iov.iov + i;
- qemu_chr_fe_write(s->cs, iov->iov_base, iov->iov_len);
- }
- p->actual_length = p->iov.size;
- break;
-
- case USB_TOKEN_IN:
- if (devep != 1)
- goto fail;
- first_len = RECV_BUF - s->recv_ptr;
- len = p->iov.size;
- if (len <= 2) {
- p->status = USB_RET_NAK;
- break;
- }
- header[0] = usb_get_modem_lines(s) | 1;
- /* We do not have the uart details */
- /* handle serial break */
- if (s->event_trigger && s->event_trigger & FTDI_BI) {
- s->event_trigger &= ~FTDI_BI;
- header[1] = FTDI_BI;
- usb_packet_copy(p, header, 2);
- break;
- } else {
- header[1] = 0;
- }
- len -= 2;
- if (len > s->recv_used)
- len = s->recv_used;
- if (!len) {
- p->status = USB_RET_NAK;
- break;
- }
- if (first_len > len)
- first_len = len;
- usb_packet_copy(p, header, 2);
- usb_packet_copy(p, s->recv_buf + s->recv_ptr, first_len);
- if (len > first_len)
- usb_packet_copy(p, s->recv_buf, len - first_len);
- s->recv_used -= len;
- s->recv_ptr = (s->recv_ptr + len) % RECV_BUF;
- break;
-
- default:
- DPRINTF("Bad token\n");
- fail:
- p->status = USB_RET_STALL;
- break;
- }
-}
-
-static int usb_serial_can_read(void *opaque)
-{
- USBSerialState *s = opaque;
-
- if (!s->dev.attached) {
- return 0;
- }
- return RECV_BUF - s->recv_used;
-}
-
-static void usb_serial_read(void *opaque, const uint8_t *buf, int size)
-{
- USBSerialState *s = opaque;
- int first_size, start;
-
- /* room in the buffer? */
- if (size > (RECV_BUF - s->recv_used))
- size = RECV_BUF - s->recv_used;
-
- start = s->recv_ptr + s->recv_used;
- if (start < RECV_BUF) {
- /* copy data to end of buffer */
- first_size = RECV_BUF - start;
- if (first_size > size)
- first_size = size;
-
- memcpy(s->recv_buf + start, buf, first_size);
-
- /* wrap around to front if needed */
- if (size > first_size)
- memcpy(s->recv_buf, buf + first_size, size - first_size);
- } else {
- start -= RECV_BUF;
- memcpy(s->recv_buf + start, buf, size);
- }
- s->recv_used += size;
-}
-
-static void usb_serial_event(void *opaque, int event)
-{
- USBSerialState *s = opaque;
-
- switch (event) {
- case CHR_EVENT_BREAK:
- s->event_trigger |= FTDI_BI;
- break;
- case CHR_EVENT_FOCUS:
- break;
- case CHR_EVENT_OPENED:
- if (!s->dev.attached) {
- usb_device_attach(&s->dev, &error_abort);
- }
- break;
- case CHR_EVENT_CLOSED:
- if (s->dev.attached) {
- usb_device_detach(&s->dev);
- }
- break;
- }
-}
-
-static void usb_serial_realize(USBDevice *dev, Error **errp)
-{
- USBSerialState *s = USB_SERIAL_DEV(dev);
- Error *local_err = NULL;
-
- usb_desc_create_serial(dev);
- usb_desc_init(dev);
- dev->auto_attach = 0;
-
- if (!s->cs) {
- error_setg(errp, "Property chardev is required");
- return;
- }
-
- usb_check_attach(dev, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- qemu_chr_add_handlers(s->cs, usb_serial_can_read, usb_serial_read,
- usb_serial_event, s);
- usb_serial_handle_reset(dev);
-
- if (s->cs->be_open && !dev->attached) {
- usb_device_attach(dev, &error_abort);
- }
-}
-
-static USBDevice *usb_serial_init(USBBus *bus, const char *filename)
-{
- USBDevice *dev;
- CharDriverState *cdrv;
- uint32_t vendorid = 0, productid = 0;
- char label[32];
- static int index;
-
- while (*filename && *filename != ':') {
- const char *p;
- char *e;
- if (strstart(filename, "vendorid=", &p)) {
- vendorid = strtol(p, &e, 16);
- if (e == p || (*e && *e != ',' && *e != ':')) {
- error_report("bogus vendor ID %s", p);
- return NULL;
- }
- filename = e;
- } else if (strstart(filename, "productid=", &p)) {
- productid = strtol(p, &e, 16);
- if (e == p || (*e && *e != ',' && *e != ':')) {
- error_report("bogus product ID %s", p);
- return NULL;
- }
- filename = e;
- } else {
- error_report("unrecognized serial USB option %s", filename);
- return NULL;
- }
- while(*filename == ',')
- filename++;
- }
- if (!*filename) {
- error_report("character device specification needed");
- return NULL;
- }
- filename++;
-
- snprintf(label, sizeof(label), "usbserial%d", index++);
- cdrv = qemu_chr_new(label, filename, NULL);
- if (!cdrv)
- return NULL;
-
- dev = usb_create(bus, "usb-serial");
- qdev_prop_set_chr(&dev->qdev, "chardev", cdrv);
- if (vendorid)
- qdev_prop_set_uint16(&dev->qdev, "vendorid", vendorid);
- if (productid)
- qdev_prop_set_uint16(&dev->qdev, "productid", productid);
- return dev;
-}
-
-static USBDevice *usb_braille_init(USBBus *bus, const char *unused)
-{
- USBDevice *dev;
- CharDriverState *cdrv;
-
- cdrv = qemu_chr_new("braille", "braille", NULL);
- if (!cdrv)
- return NULL;
-
- dev = usb_create(bus, "usb-braille");
- qdev_prop_set_chr(&dev->qdev, "chardev", cdrv);
- return dev;
-}
-
-static const VMStateDescription vmstate_usb_serial = {
- .name = "usb-serial",
- .unmigratable = 1,
-};
-
-static Property serial_properties[] = {
- DEFINE_PROP_CHR("chardev", USBSerialState, cs),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void usb_serial_dev_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
-
- uc->realize = usb_serial_realize;
- uc->handle_reset = usb_serial_handle_reset;
- uc->handle_control = usb_serial_handle_control;
- uc->handle_data = usb_serial_handle_data;
- dc->vmsd = &vmstate_usb_serial;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
-}
-
-static const TypeInfo usb_serial_dev_type_info = {
- .name = TYPE_USB_SERIAL,
- .parent = TYPE_USB_DEVICE,
- .instance_size = sizeof(USBSerialState),
- .abstract = true,
- .class_init = usb_serial_dev_class_init,
-};
-
-static void usb_serial_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
-
- uc->product_desc = "QEMU USB Serial";
- uc->usb_desc = &desc_serial;
- dc->props = serial_properties;
-}
-
-static const TypeInfo serial_info = {
- .name = "usb-serial",
- .parent = TYPE_USB_SERIAL,
- .class_init = usb_serial_class_initfn,
-};
-
-static Property braille_properties[] = {
- DEFINE_PROP_CHR("chardev", USBSerialState, cs),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void usb_braille_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
-
- uc->product_desc = "QEMU USB Braille";
- uc->usb_desc = &desc_braille;
- dc->props = braille_properties;
-}
-
-static const TypeInfo braille_info = {
- .name = "usb-braille",
- .parent = TYPE_USB_SERIAL,
- .class_init = usb_braille_class_initfn,
-};
-
-static void usb_serial_register_types(void)
-{
- type_register_static(&usb_serial_dev_type_info);
- type_register_static(&serial_info);
- usb_legacy_register("usb-serial", "serial", usb_serial_init);
- type_register_static(&braille_info);
- usb_legacy_register("usb-braille", "braille", usb_braille_init);
-}
-
-type_init(usb_serial_register_types)
diff --git a/qemu/hw/usb/dev-smartcard-reader.c b/qemu/hw/usb/dev-smartcard-reader.c
deleted file mode 100644
index af4b85135..000000000
--- a/qemu/hw/usb/dev-smartcard-reader.c
+++ /dev/null
@@ -1,1507 +0,0 @@
-/*
- * Copyright (C) 2011 Red Hat, Inc.
- *
- * CCID Device emulation
- *
- * Written by Alon Levy, with contributions from Robert Relyea.
- *
- * Based on usb-serial.c, see its copyright and attributions below.
- *
- * This work is licensed under the terms of the GNU GPL, version 2.1 or later.
- * See the COPYING file in the top-level directory.
- * ------- (original copyright & attribution for usb-serial.c below) --------
- * Copyright (c) 2006 CodeSourcery.
- * Copyright (c) 2008 Samuel Thibault <samuel.thibault@ens-lyon.org>
- * Written by Paul Brook, reused for FTDI by Samuel Thibault,
- */
-
-/*
- * References:
- *
- * CCID Specification Revision 1.1 April 22nd 2005
- * "Universal Serial Bus, Device Class: Smart Card"
- * Specification for Integrated Circuit(s) Cards Interface Devices
- *
- * Endianness note: from the spec (1.3)
- * "Fields that are larger than a byte are stored in little endian"
- *
- * KNOWN BUGS
- * 1. remove/insert can sometimes result in removed state instead of inserted.
- * This is a result of the following:
- * symptom: dmesg shows ERMOTEIO (-121), pcscd shows -99. This can happen
- * when a short packet is sent, as seen in uhci-usb.c, resulting from a urb
- * from the guest requesting SPD and us returning a smaller packet.
- * Not sure which messages trigger this.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "qemu/error-report.h"
-#include "hw/usb.h"
-#include "hw/usb/desc.h"
-
-#include "ccid.h"
-
-#define DPRINTF(s, lvl, fmt, ...) \
-do { \
- if (lvl <= s->debug) { \
- printf("usb-ccid: " fmt , ## __VA_ARGS__); \
- } \
-} while (0)
-
-#define D_WARN 1
-#define D_INFO 2
-#define D_MORE_INFO 3
-#define D_VERBOSE 4
-
-#define CCID_DEV_NAME "usb-ccid"
-#define USB_CCID_DEV(obj) OBJECT_CHECK(USBCCIDState, (obj), CCID_DEV_NAME)
-/*
- * The two options for variable sized buffers:
- * make them constant size, for large enough constant,
- * or handle the migration complexity - VMState doesn't handle this case.
- * sizes are expected never to be exceeded, unless guest misbehaves.
- */
-#define BULK_OUT_DATA_SIZE 65536
-#define PENDING_ANSWERS_NUM 128
-
-#define BULK_IN_BUF_SIZE 384
-#define BULK_IN_PENDING_NUM 8
-
-#define CCID_MAX_PACKET_SIZE 64
-
-#define CCID_CONTROL_ABORT 0x1
-#define CCID_CONTROL_GET_CLOCK_FREQUENCIES 0x2
-#define CCID_CONTROL_GET_DATA_RATES 0x3
-
-#define CCID_PRODUCT_DESCRIPTION "QEMU USB CCID"
-#define CCID_VENDOR_DESCRIPTION "QEMU"
-#define CCID_INTERFACE_NAME "CCID Interface"
-#define CCID_SERIAL_NUMBER_STRING "1"
-/*
- * Using Gemplus Vendor and Product id
- * Effect on various drivers:
- * usbccid.sys (winxp, others untested) is a class driver so it doesn't care.
- * linux has a number of class drivers, but openct filters based on
- * vendor/product (/etc/openct.conf under fedora), hence Gemplus.
- */
-#define CCID_VENDOR_ID 0x08e6
-#define CCID_PRODUCT_ID 0x4433
-#define CCID_DEVICE_VERSION 0x0000
-
-/*
- * BULK_OUT messages from PC to Reader
- * Defined in CCID Rev 1.1 6.1 (page 26)
- */
-#define CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOn 0x62
-#define CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOff 0x63
-#define CCID_MESSAGE_TYPE_PC_to_RDR_GetSlotStatus 0x65
-#define CCID_MESSAGE_TYPE_PC_to_RDR_XfrBlock 0x6f
-#define CCID_MESSAGE_TYPE_PC_to_RDR_GetParameters 0x6c
-#define CCID_MESSAGE_TYPE_PC_to_RDR_ResetParameters 0x6d
-#define CCID_MESSAGE_TYPE_PC_to_RDR_SetParameters 0x61
-#define CCID_MESSAGE_TYPE_PC_to_RDR_Escape 0x6b
-#define CCID_MESSAGE_TYPE_PC_to_RDR_IccClock 0x6e
-#define CCID_MESSAGE_TYPE_PC_to_RDR_T0APDU 0x6a
-#define CCID_MESSAGE_TYPE_PC_to_RDR_Secure 0x69
-#define CCID_MESSAGE_TYPE_PC_to_RDR_Mechanical 0x71
-#define CCID_MESSAGE_TYPE_PC_to_RDR_Abort 0x72
-#define CCID_MESSAGE_TYPE_PC_to_RDR_SetDataRateAndClockFrequency 0x73
-
-/*
- * BULK_IN messages from Reader to PC
- * Defined in CCID Rev 1.1 6.2 (page 48)
- */
-#define CCID_MESSAGE_TYPE_RDR_to_PC_DataBlock 0x80
-#define CCID_MESSAGE_TYPE_RDR_to_PC_SlotStatus 0x81
-#define CCID_MESSAGE_TYPE_RDR_to_PC_Parameters 0x82
-#define CCID_MESSAGE_TYPE_RDR_to_PC_Escape 0x83
-#define CCID_MESSAGE_TYPE_RDR_to_PC_DataRateAndClockFrequency 0x84
-
-/*
- * INTERRUPT_IN messages from Reader to PC
- * Defined in CCID Rev 1.1 6.3 (page 56)
- */
-#define CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange 0x50
-#define CCID_MESSAGE_TYPE_RDR_to_PC_HardwareError 0x51
-
-/*
- * Endpoints for CCID - addresses are up to us to decide.
- * To support slot insertion and removal we must have an interrupt in ep
- * in addition we need a bulk in and bulk out ep
- * 5.2, page 20
- */
-#define CCID_INT_IN_EP 1
-#define CCID_BULK_IN_EP 2
-#define CCID_BULK_OUT_EP 3
-
-/* bmSlotICCState masks */
-#define SLOT_0_STATE_MASK 1
-#define SLOT_0_CHANGED_MASK 2
-
-/* Status codes that go in bStatus (see 6.2.6) */
-enum {
- ICC_STATUS_PRESENT_ACTIVE = 0,
- ICC_STATUS_PRESENT_INACTIVE,
- ICC_STATUS_NOT_PRESENT
-};
-
-enum {
- COMMAND_STATUS_NO_ERROR = 0,
- COMMAND_STATUS_FAILED,
- COMMAND_STATUS_TIME_EXTENSION_REQUIRED
-};
-
-/* Error codes that go in bError (see 6.2.6) */
-enum {
- ERROR_CMD_NOT_SUPPORTED = 0,
- ERROR_CMD_ABORTED = -1,
- ERROR_ICC_MUTE = -2,
- ERROR_XFR_PARITY_ERROR = -3,
- ERROR_XFR_OVERRUN = -4,
- ERROR_HW_ERROR = -5,
-};
-
-/* 6.2.6 RDR_to_PC_SlotStatus definitions */
-enum {
- CLOCK_STATUS_RUNNING = 0,
- /*
- * 0 - Clock Running, 1 - Clock stopped in State L, 2 - H,
- * 3 - unknown state. rest are RFU
- */
-};
-
-typedef struct QEMU_PACKED CCID_Header {
- uint8_t bMessageType;
- uint32_t dwLength;
- uint8_t bSlot;
- uint8_t bSeq;
-} CCID_Header;
-
-typedef struct QEMU_PACKED CCID_BULK_IN {
- CCID_Header hdr;
- uint8_t bStatus; /* Only used in BULK_IN */
- uint8_t bError; /* Only used in BULK_IN */
-} CCID_BULK_IN;
-
-typedef struct QEMU_PACKED CCID_SlotStatus {
- CCID_BULK_IN b;
- uint8_t bClockStatus;
-} CCID_SlotStatus;
-
-typedef struct QEMU_PACKED CCID_T0ProtocolDataStructure {
- uint8_t bmFindexDindex;
- uint8_t bmTCCKST0;
- uint8_t bGuardTimeT0;
- uint8_t bWaitingIntegerT0;
- uint8_t bClockStop;
-} CCID_T0ProtocolDataStructure;
-
-typedef struct QEMU_PACKED CCID_T1ProtocolDataStructure {
- uint8_t bmFindexDindex;
- uint8_t bmTCCKST1;
- uint8_t bGuardTimeT1;
- uint8_t bWaitingIntegerT1;
- uint8_t bClockStop;
- uint8_t bIFSC;
- uint8_t bNadValue;
-} CCID_T1ProtocolDataStructure;
-
-typedef union CCID_ProtocolDataStructure {
- CCID_T0ProtocolDataStructure t0;
- CCID_T1ProtocolDataStructure t1;
- uint8_t data[7]; /* must be = max(sizeof(t0), sizeof(t1)) */
-} CCID_ProtocolDataStructure;
-
-typedef struct QEMU_PACKED CCID_Parameter {
- CCID_BULK_IN b;
- uint8_t bProtocolNum;
- CCID_ProtocolDataStructure abProtocolDataStructure;
-} CCID_Parameter;
-
-typedef struct QEMU_PACKED CCID_DataBlock {
- CCID_BULK_IN b;
- uint8_t bChainParameter;
- uint8_t abData[0];
-} CCID_DataBlock;
-
-/* 6.1.4 PC_to_RDR_XfrBlock */
-typedef struct QEMU_PACKED CCID_XferBlock {
- CCID_Header hdr;
- uint8_t bBWI; /* Block Waiting Timeout */
- uint16_t wLevelParameter; /* XXX currently unused */
- uint8_t abData[0];
-} CCID_XferBlock;
-
-typedef struct QEMU_PACKED CCID_IccPowerOn {
- CCID_Header hdr;
- uint8_t bPowerSelect;
- uint16_t abRFU;
-} CCID_IccPowerOn;
-
-typedef struct QEMU_PACKED CCID_IccPowerOff {
- CCID_Header hdr;
- uint16_t abRFU;
-} CCID_IccPowerOff;
-
-typedef struct QEMU_PACKED CCID_SetParameters {
- CCID_Header hdr;
- uint8_t bProtocolNum;
- uint16_t abRFU;
- CCID_ProtocolDataStructure abProtocolDataStructure;
-} CCID_SetParameters;
-
-typedef struct CCID_Notify_Slot_Change {
- uint8_t bMessageType; /* CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange */
- uint8_t bmSlotICCState;
-} CCID_Notify_Slot_Change;
-
-/* used for DataBlock response to XferBlock */
-typedef struct Answer {
- uint8_t slot;
- uint8_t seq;
-} Answer;
-
-/* pending BULK_IN messages */
-typedef struct BulkIn {
- uint8_t data[BULK_IN_BUF_SIZE];
- uint32_t len;
- uint32_t pos;
-} BulkIn;
-
-enum {
- MIGRATION_NONE,
- MIGRATION_MIGRATED,
-};
-
-typedef struct CCIDBus {
- BusState qbus;
-} CCIDBus;
-
-/*
- * powered - defaults to true, changed by PowerOn/PowerOff messages
- */
-typedef struct USBCCIDState {
- USBDevice dev;
- USBEndpoint *intr;
- USBEndpoint *bulk;
- CCIDBus bus;
- CCIDCardState *card;
- BulkIn bulk_in_pending[BULK_IN_PENDING_NUM]; /* circular */
- uint32_t bulk_in_pending_start;
- uint32_t bulk_in_pending_end; /* first free */
- uint32_t bulk_in_pending_num;
- BulkIn *current_bulk_in;
- uint8_t bulk_out_data[BULK_OUT_DATA_SIZE];
- uint32_t bulk_out_pos;
- uint64_t last_answer_error;
- Answer pending_answers[PENDING_ANSWERS_NUM];
- uint32_t pending_answers_start;
- uint32_t pending_answers_end;
- uint32_t pending_answers_num;
- uint8_t bError;
- uint8_t bmCommandStatus;
- uint8_t bProtocolNum;
- CCID_ProtocolDataStructure abProtocolDataStructure;
- uint32_t ulProtocolDataStructureSize;
- uint32_t state_vmstate;
- uint32_t migration_target_ip;
- uint16_t migration_target_port;
- uint8_t migration_state;
- uint8_t bmSlotICCState;
- uint8_t powered;
- uint8_t notify_slot_change;
- uint8_t debug;
-} USBCCIDState;
-
-/*
- * CCID Spec chapter 4: CCID uses a standard device descriptor per Chapter 9,
- * "USB Device Framework", section 9.6.1, in the Universal Serial Bus
- * Specification.
- *
- * This device implemented based on the spec and with an Athena Smart Card
- * Reader as reference:
- * 0dc3:1004 Athena Smartcard Solutions, Inc.
- */
-
-static const uint8_t qemu_ccid_descriptor[] = {
- /* Smart Card Device Class Descriptor */
- 0x36, /* u8 bLength; */
- 0x21, /* u8 bDescriptorType; Functional */
- 0x10, 0x01, /* u16 bcdCCID; CCID Specification Release Number. */
- 0x00, /*
- * u8 bMaxSlotIndex; The index of the highest available
- * slot on this device. All slots are consecutive starting
- * at 00h.
- */
- 0x07, /* u8 bVoltageSupport; 01h - 5.0v, 02h - 3.0, 03 - 1.8 */
-
- 0x00, 0x00, /* u32 dwProtocols; RRRR PPPP. RRRR = 0000h.*/
- 0x01, 0x00, /* PPPP: 0001h = Protocol T=0, 0002h = Protocol T=1 */
- /* u32 dwDefaultClock; in kHZ (0x0fa0 is 4 MHz) */
- 0xa0, 0x0f, 0x00, 0x00,
- /* u32 dwMaximumClock; */
- 0x00, 0x00, 0x01, 0x00,
- 0x00, /* u8 bNumClockSupported; *
- * 0 means just the default and max. */
- /* u32 dwDataRate ;bps. 9600 == 00002580h */
- 0x80, 0x25, 0x00, 0x00,
- /* u32 dwMaxDataRate ; 11520 bps == 0001C200h */
- 0x00, 0xC2, 0x01, 0x00,
- 0x00, /* u8 bNumDataRatesSupported; 00 means all rates between
- * default and max */
- /* u32 dwMaxIFSD; *
- * maximum IFSD supported by CCID for protocol *
- * T=1 (Maximum seen from various cards) */
- 0xfe, 0x00, 0x00, 0x00,
- /* u32 dwSyncProtocols; 1 - 2-wire, 2 - 3-wire, 4 - I2C */
- 0x00, 0x00, 0x00, 0x00,
- /* u32 dwMechanical; 0 - no special characteristics. */
- 0x00, 0x00, 0x00, 0x00,
- /*
- * u32 dwFeatures;
- * 0 - No special characteristics
- * + 2 Automatic parameter configuration based on ATR data
- * + 4 Automatic activation of ICC on inserting
- * + 8 Automatic ICC voltage selection
- * + 10 Automatic ICC clock frequency change
- * + 20 Automatic baud rate change
- * + 40 Automatic parameters negotiation made by the CCID
- * + 80 automatic PPS made by the CCID
- * 100 CCID can set ICC in clock stop mode
- * 200 NAD value other then 00 accepted (T=1 protocol)
- * + 400 Automatic IFSD exchange as first exchange (T=1)
- * One of the following only:
- * + 10000 TPDU level exchanges with CCID
- * 20000 Short APDU level exchange with CCID
- * 40000 Short and Extended APDU level exchange with CCID
- *
- * 100000 USB Wake up signaling supported on card
- * insertion and removal. Must set bit 5 in bmAttributes
- * in Configuration descriptor if 100000 is set.
- */
- 0xfe, 0x04, 0x01, 0x00,
- /*
- * u32 dwMaxCCIDMessageLength; For extended APDU in
- * [261 + 10 , 65544 + 10]. Otherwise the minimum is
- * wMaxPacketSize of the Bulk-OUT endpoint
- */
- 0x12, 0x00, 0x01, 0x00,
- 0xFF, /*
- * u8 bClassGetResponse; Significant only for CCID that
- * offers an APDU level for exchanges. Indicates the
- * default class value used by the CCID when it sends a
- * Get Response command to perform the transportation of
- * an APDU by T=0 protocol
- * FFh indicates that the CCID echos the class of the APDU.
- */
- 0xFF, /*
- * u8 bClassEnvelope; EAPDU only. Envelope command for
- * T=0
- */
- 0x00, 0x00, /*
- * u16 wLcdLayout; XXYY Number of lines (XX) and chars per
- * line for LCD display used for PIN entry. 0000 - no LCD
- */
- 0x01, /*
- * u8 bPINSupport; 01h PIN Verification,
- * 02h PIN Modification
- */
- 0x01, /* u8 bMaxCCIDBusySlots; */
-};
-
-enum {
- STR_MANUFACTURER = 1,
- STR_PRODUCT,
- STR_SERIALNUMBER,
- STR_INTERFACE,
-};
-
-static const USBDescStrings desc_strings = {
- [STR_MANUFACTURER] = "QEMU",
- [STR_PRODUCT] = "QEMU USB CCID",
- [STR_SERIALNUMBER] = "1",
- [STR_INTERFACE] = "CCID Interface",
-};
-
-static const USBDescIface desc_iface0 = {
- .bInterfaceNumber = 0,
- .bNumEndpoints = 3,
- .bInterfaceClass = USB_CLASS_CSCID,
- .bInterfaceSubClass = USB_SUBCLASS_UNDEFINED,
- .bInterfaceProtocol = 0x00,
- .iInterface = STR_INTERFACE,
- .ndesc = 1,
- .descs = (USBDescOther[]) {
- {
- /* smartcard descriptor */
- .data = qemu_ccid_descriptor,
- },
- },
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | CCID_INT_IN_EP,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .bInterval = 255,
- .wMaxPacketSize = 64,
- },{
- .bEndpointAddress = USB_DIR_IN | CCID_BULK_IN_EP,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 64,
- },{
- .bEndpointAddress = USB_DIR_OUT | CCID_BULK_OUT_EP,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 64,
- },
- }
-};
-
-static const USBDescDevice desc_device = {
- .bcdUSB = 0x0110,
- .bMaxPacketSize0 = 64,
- .bNumConfigurations = 1,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 1,
- .bConfigurationValue = 1,
- .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER |
- USB_CFG_ATT_WAKEUP,
- .bMaxPower = 50,
- .nif = 1,
- .ifs = &desc_iface0,
- },
- },
-};
-
-static const USBDesc desc_ccid = {
- .id = {
- .idVendor = CCID_VENDOR_ID,
- .idProduct = CCID_PRODUCT_ID,
- .bcdDevice = CCID_DEVICE_VERSION,
- .iManufacturer = STR_MANUFACTURER,
- .iProduct = STR_PRODUCT,
- .iSerialNumber = STR_SERIALNUMBER,
- },
- .full = &desc_device,
- .str = desc_strings,
-};
-
-static const uint8_t *ccid_card_get_atr(CCIDCardState *card, uint32_t *len)
-{
- CCIDCardClass *cc = CCID_CARD_GET_CLASS(card);
-
- if (cc->get_atr) {
- return cc->get_atr(card, len);
- }
- return NULL;
-}
-
-static void ccid_card_apdu_from_guest(CCIDCardState *card,
- const uint8_t *apdu,
- uint32_t len)
-{
- CCIDCardClass *cc = CCID_CARD_GET_CLASS(card);
-
- if (cc->apdu_from_guest) {
- cc->apdu_from_guest(card, apdu, len);
- }
-}
-
-static int ccid_card_exitfn(CCIDCardState *card)
-{
- CCIDCardClass *cc = CCID_CARD_GET_CLASS(card);
-
- if (cc->exitfn) {
- return cc->exitfn(card);
- }
- return 0;
-}
-
-static int ccid_card_initfn(CCIDCardState *card)
-{
- CCIDCardClass *cc = CCID_CARD_GET_CLASS(card);
-
- if (cc->initfn) {
- return cc->initfn(card);
- }
- return 0;
-}
-
-static bool ccid_has_pending_answers(USBCCIDState *s)
-{
- return s->pending_answers_num > 0;
-}
-
-static void ccid_clear_pending_answers(USBCCIDState *s)
-{
- s->pending_answers_num = 0;
- s->pending_answers_start = 0;
- s->pending_answers_end = 0;
-}
-
-static void ccid_print_pending_answers(USBCCIDState *s)
-{
- Answer *answer;
- int i, count;
-
- DPRINTF(s, D_VERBOSE, "usb-ccid: pending answers:");
- if (!ccid_has_pending_answers(s)) {
- DPRINTF(s, D_VERBOSE, " empty\n");
- return;
- }
- for (i = s->pending_answers_start, count = s->pending_answers_num ;
- count > 0; count--, i++) {
- answer = &s->pending_answers[i % PENDING_ANSWERS_NUM];
- if (count == 1) {
- DPRINTF(s, D_VERBOSE, "%d:%d\n", answer->slot, answer->seq);
- } else {
- DPRINTF(s, D_VERBOSE, "%d:%d,", answer->slot, answer->seq);
- }
- }
-}
-
-static void ccid_add_pending_answer(USBCCIDState *s, CCID_Header *hdr)
-{
- Answer *answer;
-
- assert(s->pending_answers_num < PENDING_ANSWERS_NUM);
- s->pending_answers_num++;
- answer =
- &s->pending_answers[(s->pending_answers_end++) % PENDING_ANSWERS_NUM];
- answer->slot = hdr->bSlot;
- answer->seq = hdr->bSeq;
- ccid_print_pending_answers(s);
-}
-
-static void ccid_remove_pending_answer(USBCCIDState *s,
- uint8_t *slot, uint8_t *seq)
-{
- Answer *answer;
-
- assert(s->pending_answers_num > 0);
- s->pending_answers_num--;
- answer =
- &s->pending_answers[(s->pending_answers_start++) % PENDING_ANSWERS_NUM];
- *slot = answer->slot;
- *seq = answer->seq;
- ccid_print_pending_answers(s);
-}
-
-static void ccid_bulk_in_clear(USBCCIDState *s)
-{
- s->bulk_in_pending_start = 0;
- s->bulk_in_pending_end = 0;
- s->bulk_in_pending_num = 0;
-}
-
-static void ccid_bulk_in_release(USBCCIDState *s)
-{
- assert(s->current_bulk_in != NULL);
- s->current_bulk_in->pos = 0;
- s->current_bulk_in = NULL;
-}
-
-static void ccid_bulk_in_get(USBCCIDState *s)
-{
- if (s->current_bulk_in != NULL || s->bulk_in_pending_num == 0) {
- return;
- }
- assert(s->bulk_in_pending_num > 0);
- s->bulk_in_pending_num--;
- s->current_bulk_in =
- &s->bulk_in_pending[(s->bulk_in_pending_start++) % BULK_IN_PENDING_NUM];
-}
-
-static void *ccid_reserve_recv_buf(USBCCIDState *s, uint16_t len)
-{
- BulkIn *bulk_in;
-
- DPRINTF(s, D_VERBOSE, "%s: QUEUE: reserve %d bytes\n", __func__, len);
-
- /* look for an existing element */
- if (len > BULK_IN_BUF_SIZE) {
- DPRINTF(s, D_WARN, "usb-ccid.c: %s: len larger then max (%d>%d). "
- "discarding message.\n",
- __func__, len, BULK_IN_BUF_SIZE);
- return NULL;
- }
- if (s->bulk_in_pending_num >= BULK_IN_PENDING_NUM) {
- DPRINTF(s, D_WARN, "usb-ccid.c: %s: No free bulk_in buffers. "
- "discarding message.\n", __func__);
- return NULL;
- }
- bulk_in =
- &s->bulk_in_pending[(s->bulk_in_pending_end++) % BULK_IN_PENDING_NUM];
- s->bulk_in_pending_num++;
- bulk_in->len = len;
- return bulk_in->data;
-}
-
-static void ccid_reset(USBCCIDState *s)
-{
- ccid_bulk_in_clear(s);
- ccid_clear_pending_answers(s);
-}
-
-static void ccid_detach(USBCCIDState *s)
-{
- ccid_reset(s);
-}
-
-static void ccid_handle_reset(USBDevice *dev)
-{
- USBCCIDState *s = USB_CCID_DEV(dev);
-
- DPRINTF(s, 1, "Reset\n");
-
- ccid_reset(s);
-}
-
-static const char *ccid_control_to_str(USBCCIDState *s, int request)
-{
- switch (request) {
- /* generic - should be factored out if there are other debugees */
- case DeviceOutRequest | USB_REQ_SET_ADDRESS:
- return "(generic) set address";
- case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
- return "(generic) get descriptor";
- case DeviceRequest | USB_REQ_GET_CONFIGURATION:
- return "(generic) get configuration";
- case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
- return "(generic) set configuration";
- case DeviceRequest | USB_REQ_GET_STATUS:
- return "(generic) get status";
- case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
- return "(generic) clear feature";
- case DeviceOutRequest | USB_REQ_SET_FEATURE:
- return "(generic) set_feature";
- case InterfaceRequest | USB_REQ_GET_INTERFACE:
- return "(generic) get interface";
- case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
- return "(generic) set interface";
- /* class requests */
- case ClassInterfaceOutRequest | CCID_CONTROL_ABORT:
- return "ABORT";
- case ClassInterfaceRequest | CCID_CONTROL_GET_CLOCK_FREQUENCIES:
- return "GET_CLOCK_FREQUENCIES";
- case ClassInterfaceRequest | CCID_CONTROL_GET_DATA_RATES:
- return "GET_DATA_RATES";
- }
- return "unknown";
-}
-
-static void ccid_handle_control(USBDevice *dev, USBPacket *p, int request,
- int value, int index, int length, uint8_t *data)
-{
- USBCCIDState *s = USB_CCID_DEV(dev);
- int ret;
-
- DPRINTF(s, 1, "%s: got control %s (%x), value %x\n", __func__,
- ccid_control_to_str(s, request), request, value);
- ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
- if (ret >= 0) {
- return;
- }
-
- switch (request) {
- /* Class specific requests. */
- case ClassInterfaceOutRequest | CCID_CONTROL_ABORT:
- DPRINTF(s, 1, "ccid_control abort UNIMPLEMENTED\n");
- p->status = USB_RET_STALL;
- break;
- case ClassInterfaceRequest | CCID_CONTROL_GET_CLOCK_FREQUENCIES:
- DPRINTF(s, 1, "ccid_control get clock frequencies UNIMPLEMENTED\n");
- p->status = USB_RET_STALL;
- break;
- case ClassInterfaceRequest | CCID_CONTROL_GET_DATA_RATES:
- DPRINTF(s, 1, "ccid_control get data rates UNIMPLEMENTED\n");
- p->status = USB_RET_STALL;
- break;
- default:
- DPRINTF(s, 1, "got unsupported/bogus control %x, value %x\n",
- request, value);
- p->status = USB_RET_STALL;
- break;
- }
-}
-
-static bool ccid_card_inserted(USBCCIDState *s)
-{
- return s->bmSlotICCState & SLOT_0_STATE_MASK;
-}
-
-static uint8_t ccid_card_status(USBCCIDState *s)
-{
- return ccid_card_inserted(s)
- ? (s->powered ?
- ICC_STATUS_PRESENT_ACTIVE
- : ICC_STATUS_PRESENT_INACTIVE
- )
- : ICC_STATUS_NOT_PRESENT;
-}
-
-static uint8_t ccid_calc_status(USBCCIDState *s)
-{
- /*
- * page 55, 6.2.6, calculation of bStatus from bmICCStatus and
- * bmCommandStatus
- */
- uint8_t ret = ccid_card_status(s) | (s->bmCommandStatus << 6);
- DPRINTF(s, D_VERBOSE, "%s: status = %d\n", __func__, ret);
- return ret;
-}
-
-static void ccid_reset_error_status(USBCCIDState *s)
-{
- s->bError = ERROR_CMD_NOT_SUPPORTED;
- s->bmCommandStatus = COMMAND_STATUS_NO_ERROR;
-}
-
-static void ccid_write_slot_status(USBCCIDState *s, CCID_Header *recv)
-{
- CCID_SlotStatus *h = ccid_reserve_recv_buf(s, sizeof(CCID_SlotStatus));
- if (h == NULL) {
- return;
- }
- h->b.hdr.bMessageType = CCID_MESSAGE_TYPE_RDR_to_PC_SlotStatus;
- h->b.hdr.dwLength = 0;
- h->b.hdr.bSlot = recv->bSlot;
- h->b.hdr.bSeq = recv->bSeq;
- h->b.bStatus = ccid_calc_status(s);
- h->b.bError = s->bError;
- h->bClockStatus = CLOCK_STATUS_RUNNING;
- ccid_reset_error_status(s);
- usb_wakeup(s->bulk, 0);
-}
-
-static void ccid_write_parameters(USBCCIDState *s, CCID_Header *recv)
-{
- CCID_Parameter *h;
- uint32_t len = s->ulProtocolDataStructureSize;
-
- h = ccid_reserve_recv_buf(s, sizeof(CCID_Parameter) + len);
- if (h == NULL) {
- return;
- }
- h->b.hdr.bMessageType = CCID_MESSAGE_TYPE_RDR_to_PC_Parameters;
- h->b.hdr.dwLength = 0;
- h->b.hdr.bSlot = recv->bSlot;
- h->b.hdr.bSeq = recv->bSeq;
- h->b.bStatus = ccid_calc_status(s);
- h->b.bError = s->bError;
- h->bProtocolNum = s->bProtocolNum;
- h->abProtocolDataStructure = s->abProtocolDataStructure;
- ccid_reset_error_status(s);
- usb_wakeup(s->bulk, 0);
-}
-
-static void ccid_write_data_block(USBCCIDState *s, uint8_t slot, uint8_t seq,
- const uint8_t *data, uint32_t len)
-{
- CCID_DataBlock *p = ccid_reserve_recv_buf(s, sizeof(*p) + len);
-
- if (p == NULL) {
- return;
- }
- p->b.hdr.bMessageType = CCID_MESSAGE_TYPE_RDR_to_PC_DataBlock;
- p->b.hdr.dwLength = cpu_to_le32(len);
- p->b.hdr.bSlot = slot;
- p->b.hdr.bSeq = seq;
- p->b.bStatus = ccid_calc_status(s);
- p->b.bError = s->bError;
- if (p->b.bError) {
- DPRINTF(s, D_VERBOSE, "error %d\n", p->b.bError);
- }
- memcpy(p->abData, data, len);
- ccid_reset_error_status(s);
- usb_wakeup(s->bulk, 0);
-}
-
-static void ccid_report_error_failed(USBCCIDState *s, uint8_t error)
-{
- s->bmCommandStatus = COMMAND_STATUS_FAILED;
- s->bError = error;
-}
-
-static void ccid_write_data_block_answer(USBCCIDState *s,
- const uint8_t *data, uint32_t len)
-{
- uint8_t seq;
- uint8_t slot;
-
- if (!ccid_has_pending_answers(s)) {
- DPRINTF(s, D_WARN, "error: no pending answer to return to guest\n");
- ccid_report_error_failed(s, ERROR_ICC_MUTE);
- return;
- }
- ccid_remove_pending_answer(s, &slot, &seq);
- ccid_write_data_block(s, slot, seq, data, len);
-}
-
-static uint8_t atr_get_protocol_num(const uint8_t *atr, uint32_t len)
-{
- int i;
-
- if (len < 2 || !(atr[1] & 0x80)) {
- /* too short or TD1 not included */
- return 0; /* T=0, default */
- }
- i = 1 + !!(atr[1] & 0x10) + !!(atr[1] & 0x20) + !!(atr[1] & 0x40);
- i += !!(atr[1] & 0x80);
- return atr[i] & 0x0f;
-}
-
-static void ccid_write_data_block_atr(USBCCIDState *s, CCID_Header *recv)
-{
- const uint8_t *atr = NULL;
- uint32_t len = 0;
- uint8_t atr_protocol_num;
- CCID_T0ProtocolDataStructure *t0 = &s->abProtocolDataStructure.t0;
- CCID_T1ProtocolDataStructure *t1 = &s->abProtocolDataStructure.t1;
-
- if (s->card) {
- atr = ccid_card_get_atr(s->card, &len);
- }
- atr_protocol_num = atr_get_protocol_num(atr, len);
- DPRINTF(s, D_VERBOSE, "%s: atr contains protocol=%d\n", __func__,
- atr_protocol_num);
- /* set parameters from ATR - see spec page 109 */
- s->bProtocolNum = (atr_protocol_num <= 1 ? atr_protocol_num
- : s->bProtocolNum);
- switch (atr_protocol_num) {
- case 0:
- /* TODO: unimplemented ATR T0 parameters */
- t0->bmFindexDindex = 0;
- t0->bmTCCKST0 = 0;
- t0->bGuardTimeT0 = 0;
- t0->bWaitingIntegerT0 = 0;
- t0->bClockStop = 0;
- break;
- case 1:
- /* TODO: unimplemented ATR T1 parameters */
- t1->bmFindexDindex = 0;
- t1->bmTCCKST1 = 0;
- t1->bGuardTimeT1 = 0;
- t1->bWaitingIntegerT1 = 0;
- t1->bClockStop = 0;
- t1->bIFSC = 0;
- t1->bNadValue = 0;
- break;
- default:
- DPRINTF(s, D_WARN, "%s: error: unsupported ATR protocol %d\n",
- __func__, atr_protocol_num);
- }
- ccid_write_data_block(s, recv->bSlot, recv->bSeq, atr, len);
-}
-
-static void ccid_set_parameters(USBCCIDState *s, CCID_Header *recv)
-{
- CCID_SetParameters *ph = (CCID_SetParameters *) recv;
- uint32_t protocol_num = ph->bProtocolNum & 3;
-
- if (protocol_num != 0 && protocol_num != 1) {
- ccid_report_error_failed(s, ERROR_CMD_NOT_SUPPORTED);
- return;
- }
- s->bProtocolNum = protocol_num;
- s->abProtocolDataStructure = ph->abProtocolDataStructure;
-}
-
-/*
- * must be 5 bytes for T=0, 7 bytes for T=1
- * See page 52
- */
-static const CCID_ProtocolDataStructure defaultProtocolDataStructure = {
- .t1 = {
- .bmFindexDindex = 0x77,
- .bmTCCKST1 = 0x00,
- .bGuardTimeT1 = 0x00,
- .bWaitingIntegerT1 = 0x00,
- .bClockStop = 0x00,
- .bIFSC = 0xfe,
- .bNadValue = 0x00,
- }
-};
-
-static void ccid_reset_parameters(USBCCIDState *s)
-{
- s->bProtocolNum = 0; /* T=0 */
- s->abProtocolDataStructure = defaultProtocolDataStructure;
-}
-
-/* NOTE: only a single slot is supported (SLOT_0) */
-static void ccid_on_slot_change(USBCCIDState *s, bool full)
-{
- /* RDR_to_PC_NotifySlotChange, 6.3.1 page 56 */
- uint8_t current = s->bmSlotICCState;
- if (full) {
- s->bmSlotICCState |= SLOT_0_STATE_MASK;
- } else {
- s->bmSlotICCState &= ~SLOT_0_STATE_MASK;
- }
- if (current != s->bmSlotICCState) {
- s->bmSlotICCState |= SLOT_0_CHANGED_MASK;
- }
- s->notify_slot_change = true;
- usb_wakeup(s->intr, 0);
-}
-
-static void ccid_write_data_block_error(
- USBCCIDState *s, uint8_t slot, uint8_t seq)
-{
- ccid_write_data_block(s, slot, seq, NULL, 0);
-}
-
-static void ccid_on_apdu_from_guest(USBCCIDState *s, CCID_XferBlock *recv)
-{
- uint32_t len;
-
- if (ccid_card_status(s) != ICC_STATUS_PRESENT_ACTIVE) {
- DPRINTF(s, 1,
- "usb-ccid: not sending apdu to client, no card connected\n");
- ccid_write_data_block_error(s, recv->hdr.bSlot, recv->hdr.bSeq);
- return;
- }
- len = le32_to_cpu(recv->hdr.dwLength);
- DPRINTF(s, 1, "%s: seq %d, len %d\n", __func__,
- recv->hdr.bSeq, len);
- ccid_add_pending_answer(s, (CCID_Header *)recv);
- if (s->card) {
- ccid_card_apdu_from_guest(s->card, recv->abData, len);
- } else {
- DPRINTF(s, D_WARN, "warning: discarded apdu\n");
- }
-}
-
-static const char *ccid_message_type_to_str(uint8_t type)
-{
- switch (type) {
- case CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOn: return "IccPowerOn";
- case CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOff: return "IccPowerOff";
- case CCID_MESSAGE_TYPE_PC_to_RDR_GetSlotStatus: return "GetSlotStatus";
- case CCID_MESSAGE_TYPE_PC_to_RDR_XfrBlock: return "XfrBlock";
- case CCID_MESSAGE_TYPE_PC_to_RDR_GetParameters: return "GetParameters";
- case CCID_MESSAGE_TYPE_PC_to_RDR_ResetParameters: return "ResetParameters";
- case CCID_MESSAGE_TYPE_PC_to_RDR_SetParameters: return "SetParameters";
- case CCID_MESSAGE_TYPE_PC_to_RDR_Escape: return "Escape";
- case CCID_MESSAGE_TYPE_PC_to_RDR_IccClock: return "IccClock";
- case CCID_MESSAGE_TYPE_PC_to_RDR_T0APDU: return "T0APDU";
- case CCID_MESSAGE_TYPE_PC_to_RDR_Secure: return "Secure";
- case CCID_MESSAGE_TYPE_PC_to_RDR_Mechanical: return "Mechanical";
- case CCID_MESSAGE_TYPE_PC_to_RDR_Abort: return "Abort";
- case CCID_MESSAGE_TYPE_PC_to_RDR_SetDataRateAndClockFrequency:
- return "SetDataRateAndClockFrequency";
- }
- return "unknown";
-}
-
-static void ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p)
-{
- CCID_Header *ccid_header;
-
- if (p->iov.size + s->bulk_out_pos > BULK_OUT_DATA_SIZE) {
- p->status = USB_RET_STALL;
- return;
- }
- ccid_header = (CCID_Header *)s->bulk_out_data;
- usb_packet_copy(p, s->bulk_out_data + s->bulk_out_pos, p->iov.size);
- s->bulk_out_pos += p->iov.size;
- if (p->iov.size == CCID_MAX_PACKET_SIZE) {
- DPRINTF(s, D_VERBOSE,
- "usb-ccid: bulk_in: expecting more packets (%zd/%d)\n",
- p->iov.size, ccid_header->dwLength);
- return;
- }
- if (s->bulk_out_pos < 10) {
- DPRINTF(s, 1,
- "%s: bad USB_TOKEN_OUT length, should be at least 10 bytes\n",
- __func__);
- } else {
- DPRINTF(s, D_MORE_INFO, "%s %x %s\n", __func__,
- ccid_header->bMessageType,
- ccid_message_type_to_str(ccid_header->bMessageType));
- switch (ccid_header->bMessageType) {
- case CCID_MESSAGE_TYPE_PC_to_RDR_GetSlotStatus:
- ccid_write_slot_status(s, ccid_header);
- break;
- case CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOn:
- DPRINTF(s, 1, "%s: PowerOn: %d\n", __func__,
- ((CCID_IccPowerOn *)(ccid_header))->bPowerSelect);
- s->powered = true;
- if (!ccid_card_inserted(s)) {
- ccid_report_error_failed(s, ERROR_ICC_MUTE);
- }
- /* atr is written regardless of error. */
- ccid_write_data_block_atr(s, ccid_header);
- break;
- case CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOff:
- ccid_reset_error_status(s);
- s->powered = false;
- ccid_write_slot_status(s, ccid_header);
- break;
- case CCID_MESSAGE_TYPE_PC_to_RDR_XfrBlock:
- ccid_on_apdu_from_guest(s, (CCID_XferBlock *)s->bulk_out_data);
- break;
- case CCID_MESSAGE_TYPE_PC_to_RDR_SetParameters:
- ccid_reset_error_status(s);
- ccid_set_parameters(s, ccid_header);
- ccid_write_parameters(s, ccid_header);
- break;
- case CCID_MESSAGE_TYPE_PC_to_RDR_ResetParameters:
- ccid_reset_error_status(s);
- ccid_reset_parameters(s);
- ccid_write_parameters(s, ccid_header);
- break;
- case CCID_MESSAGE_TYPE_PC_to_RDR_GetParameters:
- ccid_reset_error_status(s);
- ccid_write_parameters(s, ccid_header);
- break;
- case CCID_MESSAGE_TYPE_PC_to_RDR_Mechanical:
- ccid_report_error_failed(s, 0);
- ccid_write_slot_status(s, ccid_header);
- break;
- default:
- DPRINTF(s, 1,
- "handle_data: ERROR: unhandled message type %Xh\n",
- ccid_header->bMessageType);
- /*
- * The caller is expecting the device to respond, tell it we
- * don't support the operation.
- */
- ccid_report_error_failed(s, ERROR_CMD_NOT_SUPPORTED);
- ccid_write_slot_status(s, ccid_header);
- break;
- }
- }
- s->bulk_out_pos = 0;
-}
-
-static void ccid_bulk_in_copy_to_guest(USBCCIDState *s, USBPacket *p)
-{
- int len = 0;
-
- ccid_bulk_in_get(s);
- if (s->current_bulk_in != NULL) {
- len = MIN(s->current_bulk_in->len - s->current_bulk_in->pos,
- p->iov.size);
- usb_packet_copy(p, s->current_bulk_in->data +
- s->current_bulk_in->pos, len);
- s->current_bulk_in->pos += len;
- if (s->current_bulk_in->pos == s->current_bulk_in->len) {
- ccid_bulk_in_release(s);
- }
- } else {
- /* return when device has no data - usb 2.0 spec Table 8-4 */
- p->status = USB_RET_NAK;
- }
- if (len) {
- DPRINTF(s, D_MORE_INFO,
- "%s: %zd/%d req/act to guest (BULK_IN)\n",
- __func__, p->iov.size, len);
- }
- if (len < p->iov.size) {
- DPRINTF(s, 1,
- "%s: returning short (EREMOTEIO) %d < %zd\n",
- __func__, len, p->iov.size);
- }
-}
-
-static void ccid_handle_data(USBDevice *dev, USBPacket *p)
-{
- USBCCIDState *s = USB_CCID_DEV(dev);
- uint8_t buf[2];
-
- switch (p->pid) {
- case USB_TOKEN_OUT:
- ccid_handle_bulk_out(s, p);
- break;
-
- case USB_TOKEN_IN:
- switch (p->ep->nr) {
- case CCID_BULK_IN_EP:
- ccid_bulk_in_copy_to_guest(s, p);
- break;
- case CCID_INT_IN_EP:
- if (s->notify_slot_change) {
- /* page 56, RDR_to_PC_NotifySlotChange */
- buf[0] = CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange;
- buf[1] = s->bmSlotICCState;
- usb_packet_copy(p, buf, 2);
- s->notify_slot_change = false;
- s->bmSlotICCState &= ~SLOT_0_CHANGED_MASK;
- DPRINTF(s, D_INFO,
- "handle_data: int_in: notify_slot_change %X, "
- "requested len %zd\n",
- s->bmSlotICCState, p->iov.size);
- } else {
- p->status = USB_RET_NAK;
- }
- break;
- default:
- DPRINTF(s, 1, "Bad endpoint\n");
- p->status = USB_RET_STALL;
- break;
- }
- break;
- default:
- DPRINTF(s, 1, "Bad token\n");
- p->status = USB_RET_STALL;
- break;
- }
-}
-
-static void ccid_handle_destroy(USBDevice *dev)
-{
- USBCCIDState *s = USB_CCID_DEV(dev);
-
- ccid_bulk_in_clear(s);
-}
-
-static void ccid_flush_pending_answers(USBCCIDState *s)
-{
- while (ccid_has_pending_answers(s)) {
- ccid_write_data_block_answer(s, NULL, 0);
- }
-}
-
-static Answer *ccid_peek_next_answer(USBCCIDState *s)
-{
- return s->pending_answers_num == 0
- ? NULL
- : &s->pending_answers[s->pending_answers_start % PENDING_ANSWERS_NUM];
-}
-
-static Property ccid_props[] = {
- DEFINE_PROP_UINT32("slot", struct CCIDCardState, slot, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-#define TYPE_CCID_BUS "ccid-bus"
-#define CCID_BUS(obj) OBJECT_CHECK(CCIDBus, (obj), TYPE_CCID_BUS)
-
-static const TypeInfo ccid_bus_info = {
- .name = TYPE_CCID_BUS,
- .parent = TYPE_BUS,
- .instance_size = sizeof(CCIDBus),
-};
-
-void ccid_card_send_apdu_to_guest(CCIDCardState *card,
- uint8_t *apdu, uint32_t len)
-{
- DeviceState *qdev = DEVICE(card);
- USBDevice *dev = USB_DEVICE(qdev->parent_bus->parent);
- USBCCIDState *s = USB_CCID_DEV(dev);
- Answer *answer;
-
- if (!ccid_has_pending_answers(s)) {
- DPRINTF(s, 1, "CCID ERROR: got an APDU without pending answers\n");
- return;
- }
- s->bmCommandStatus = COMMAND_STATUS_NO_ERROR;
- answer = ccid_peek_next_answer(s);
- if (answer == NULL) {
- DPRINTF(s, D_WARN, "%s: error: unexpected lack of answer\n", __func__);
- ccid_report_error_failed(s, ERROR_HW_ERROR);
- return;
- }
- DPRINTF(s, 1, "APDU returned to guest %d (answer seq %d, slot %d)\n",
- len, answer->seq, answer->slot);
- ccid_write_data_block_answer(s, apdu, len);
-}
-
-void ccid_card_card_removed(CCIDCardState *card)
-{
- DeviceState *qdev = DEVICE(card);
- USBDevice *dev = USB_DEVICE(qdev->parent_bus->parent);
- USBCCIDState *s = USB_CCID_DEV(dev);
-
- ccid_on_slot_change(s, false);
- ccid_flush_pending_answers(s);
- ccid_reset(s);
-}
-
-int ccid_card_ccid_attach(CCIDCardState *card)
-{
- DeviceState *qdev = DEVICE(card);
- USBDevice *dev = USB_DEVICE(qdev->parent_bus->parent);
- USBCCIDState *s = USB_CCID_DEV(dev);
-
- DPRINTF(s, 1, "CCID Attach\n");
- if (s->migration_state == MIGRATION_MIGRATED) {
- s->migration_state = MIGRATION_NONE;
- }
- return 0;
-}
-
-void ccid_card_ccid_detach(CCIDCardState *card)
-{
- DeviceState *qdev = DEVICE(card);
- USBDevice *dev = USB_DEVICE(qdev->parent_bus->parent);
- USBCCIDState *s = USB_CCID_DEV(dev);
-
- DPRINTF(s, 1, "CCID Detach\n");
- if (ccid_card_inserted(s)) {
- ccid_on_slot_change(s, false);
- }
- ccid_detach(s);
-}
-
-void ccid_card_card_error(CCIDCardState *card, uint64_t error)
-{
- DeviceState *qdev = DEVICE(card);
- USBDevice *dev = USB_DEVICE(qdev->parent_bus->parent);
- USBCCIDState *s = USB_CCID_DEV(dev);
-
- s->bmCommandStatus = COMMAND_STATUS_FAILED;
- s->last_answer_error = error;
- DPRINTF(s, 1, "VSC_Error: %" PRIX64 "\n", s->last_answer_error);
- /* TODO: these errors should be more verbose and propagated to the guest.*/
- /*
- * We flush all pending answers on CardRemove message in ccid-card-passthru,
- * so check that first to not trigger abort
- */
- if (ccid_has_pending_answers(s)) {
- ccid_write_data_block_answer(s, NULL, 0);
- }
-}
-
-void ccid_card_card_inserted(CCIDCardState *card)
-{
- DeviceState *qdev = DEVICE(card);
- USBDevice *dev = USB_DEVICE(qdev->parent_bus->parent);
- USBCCIDState *s = USB_CCID_DEV(dev);
-
- s->bmCommandStatus = COMMAND_STATUS_NO_ERROR;
- ccid_flush_pending_answers(s);
- ccid_on_slot_change(s, true);
-}
-
-static int ccid_card_exit(DeviceState *qdev)
-{
- int ret = 0;
- CCIDCardState *card = CCID_CARD(qdev);
- USBDevice *dev = USB_DEVICE(qdev->parent_bus->parent);
- USBCCIDState *s = USB_CCID_DEV(dev);
-
- if (ccid_card_inserted(s)) {
- ccid_card_card_removed(card);
- }
- ret = ccid_card_exitfn(card);
- s->card = NULL;
- return ret;
-}
-
-static int ccid_card_init(DeviceState *qdev)
-{
- CCIDCardState *card = CCID_CARD(qdev);
- USBDevice *dev = USB_DEVICE(qdev->parent_bus->parent);
- USBCCIDState *s = USB_CCID_DEV(dev);
- int ret = 0;
-
- if (card->slot != 0) {
- error_report("Warning: usb-ccid supports one slot, can't add %d",
- card->slot);
- return -1;
- }
- if (s->card != NULL) {
- error_report("Warning: usb-ccid card already full, not adding");
- return -1;
- }
- ret = ccid_card_initfn(card);
- if (ret == 0) {
- s->card = card;
- }
- return ret;
-}
-
-static void ccid_realize(USBDevice *dev, Error **errp)
-{
- USBCCIDState *s = USB_CCID_DEV(dev);
-
- usb_desc_create_serial(dev);
- usb_desc_init(dev);
- qbus_create_inplace(&s->bus, sizeof(s->bus), TYPE_CCID_BUS, DEVICE(dev),
- NULL);
- qbus_set_hotplug_handler(BUS(&s->bus), DEVICE(dev), &error_abort);
- s->intr = usb_ep_get(dev, USB_TOKEN_IN, CCID_INT_IN_EP);
- s->bulk = usb_ep_get(dev, USB_TOKEN_IN, CCID_BULK_IN_EP);
- s->card = NULL;
- s->migration_state = MIGRATION_NONE;
- s->migration_target_ip = 0;
- s->migration_target_port = 0;
- s->dev.speed = USB_SPEED_FULL;
- s->dev.speedmask = USB_SPEED_MASK_FULL;
- s->notify_slot_change = false;
- s->powered = true;
- s->pending_answers_num = 0;
- s->last_answer_error = 0;
- s->bulk_in_pending_start = 0;
- s->bulk_in_pending_end = 0;
- s->current_bulk_in = NULL;
- ccid_reset_error_status(s);
- s->bulk_out_pos = 0;
- ccid_reset_parameters(s);
- ccid_reset(s);
- s->debug = parse_debug_env("QEMU_CCID_DEBUG", D_VERBOSE, s->debug);
-}
-
-static int ccid_post_load(void *opaque, int version_id)
-{
- USBCCIDState *s = opaque;
-
- /*
- * This must be done after usb_device_attach, which sets state to ATTACHED,
- * while it must be DEFAULT in order to accept packets (like it is after
- * reset, but reset will reset our addr and call our reset handler which
- * may change state, and we don't want to do that when migrating).
- */
- s->dev.state = s->state_vmstate;
- return 0;
-}
-
-static void ccid_pre_save(void *opaque)
-{
- USBCCIDState *s = opaque;
-
- s->state_vmstate = s->dev.state;
- if (s->dev.attached) {
- /*
- * Migrating an open device, ignore reconnection CHR_EVENT to avoid an
- * erroneous detach.
- */
- s->migration_state = MIGRATION_MIGRATED;
- }
-}
-
-static VMStateDescription bulk_in_vmstate = {
- .name = "CCID BulkIn state",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_BUFFER(data, BulkIn),
- VMSTATE_UINT32(len, BulkIn),
- VMSTATE_UINT32(pos, BulkIn),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static VMStateDescription answer_vmstate = {
- .name = "CCID Answer state",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(slot, Answer),
- VMSTATE_UINT8(seq, Answer),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static VMStateDescription usb_device_vmstate = {
- .name = "usb_device",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(addr, USBDevice),
- VMSTATE_BUFFER(setup_buf, USBDevice),
- VMSTATE_BUFFER(data_buf, USBDevice),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static VMStateDescription ccid_vmstate = {
- .name = "usb-ccid",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = ccid_post_load,
- .pre_save = ccid_pre_save,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT(dev, USBCCIDState, 1, usb_device_vmstate, USBDevice),
- VMSTATE_UINT8(debug, USBCCIDState),
- VMSTATE_BUFFER(bulk_out_data, USBCCIDState),
- VMSTATE_UINT32(bulk_out_pos, USBCCIDState),
- VMSTATE_UINT8(bmSlotICCState, USBCCIDState),
- VMSTATE_UINT8(powered, USBCCIDState),
- VMSTATE_UINT8(notify_slot_change, USBCCIDState),
- VMSTATE_UINT64(last_answer_error, USBCCIDState),
- VMSTATE_UINT8(bError, USBCCIDState),
- VMSTATE_UINT8(bmCommandStatus, USBCCIDState),
- VMSTATE_UINT8(bProtocolNum, USBCCIDState),
- VMSTATE_BUFFER(abProtocolDataStructure.data, USBCCIDState),
- VMSTATE_UINT32(ulProtocolDataStructureSize, USBCCIDState),
- VMSTATE_STRUCT_ARRAY(bulk_in_pending, USBCCIDState,
- BULK_IN_PENDING_NUM, 1, bulk_in_vmstate, BulkIn),
- VMSTATE_UINT32(bulk_in_pending_start, USBCCIDState),
- VMSTATE_UINT32(bulk_in_pending_end, USBCCIDState),
- VMSTATE_STRUCT_ARRAY(pending_answers, USBCCIDState,
- PENDING_ANSWERS_NUM, 1, answer_vmstate, Answer),
- VMSTATE_UINT32(pending_answers_num, USBCCIDState),
- VMSTATE_UINT8(migration_state, USBCCIDState),
- VMSTATE_UINT32(state_vmstate, USBCCIDState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property ccid_properties[] = {
- DEFINE_PROP_UINT8("debug", USBCCIDState, debug, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void ccid_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
- HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
-
- uc->realize = ccid_realize;
- uc->product_desc = "QEMU USB CCID";
- uc->usb_desc = &desc_ccid;
- uc->handle_reset = ccid_handle_reset;
- uc->handle_control = ccid_handle_control;
- uc->handle_data = ccid_handle_data;
- uc->handle_destroy = ccid_handle_destroy;
- dc->desc = "CCID Rev 1.1 smartcard reader";
- dc->vmsd = &ccid_vmstate;
- dc->props = ccid_properties;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
- hc->unplug = qdev_simple_device_unplug_cb;
-}
-
-static const TypeInfo ccid_info = {
- .name = CCID_DEV_NAME,
- .parent = TYPE_USB_DEVICE,
- .instance_size = sizeof(USBCCIDState),
- .class_init = ccid_class_initfn,
- .interfaces = (InterfaceInfo[]) {
- { TYPE_HOTPLUG_HANDLER },
- { }
- }
-};
-
-static void ccid_card_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *k = DEVICE_CLASS(klass);
- k->bus_type = TYPE_CCID_BUS;
- k->init = ccid_card_init;
- k->exit = ccid_card_exit;
- k->props = ccid_props;
-}
-
-static const TypeInfo ccid_card_type_info = {
- .name = TYPE_CCID_CARD,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(CCIDCardState),
- .abstract = true,
- .class_size = sizeof(CCIDCardClass),
- .class_init = ccid_card_class_init,
-};
-
-static void ccid_register_types(void)
-{
- type_register_static(&ccid_bus_info);
- type_register_static(&ccid_card_type_info);
- type_register_static(&ccid_info);
- usb_legacy_register(CCID_DEV_NAME, "ccid", NULL);
-}
-
-type_init(ccid_register_types)
diff --git a/qemu/hw/usb/dev-storage.c b/qemu/hw/usb/dev-storage.c
deleted file mode 100644
index 248a58045..000000000
--- a/qemu/hw/usb/dev-storage.c
+++ /dev/null
@@ -1,872 +0,0 @@
-/*
- * USB Mass Storage Device emulation
- *
- * Copyright (c) 2006 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the LGPL.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "qemu/error-report.h"
-#include "qemu/option.h"
-#include "qemu/config-file.h"
-#include "hw/usb.h"
-#include "hw/usb/desc.h"
-#include "hw/scsi/scsi.h"
-#include "ui/console.h"
-#include "monitor/monitor.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
-#include "qapi/visitor.h"
-#include "qemu/cutils.h"
-
-//#define DEBUG_MSD
-
-#ifdef DEBUG_MSD
-#define DPRINTF(fmt, ...) \
-do { printf("usb-msd: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#endif
-
-/* USB requests. */
-#define MassStorageReset 0xff
-#define GetMaxLun 0xfe
-
-enum USBMSDMode {
- USB_MSDM_CBW, /* Command Block. */
- USB_MSDM_DATAOUT, /* Transfer data to device. */
- USB_MSDM_DATAIN, /* Transfer data from device. */
- USB_MSDM_CSW /* Command Status. */
-};
-
-struct usb_msd_csw {
- uint32_t sig;
- uint32_t tag;
- uint32_t residue;
- uint8_t status;
-};
-
-typedef struct {
- USBDevice dev;
- enum USBMSDMode mode;
- uint32_t scsi_off;
- uint32_t scsi_len;
- uint32_t data_len;
- struct usb_msd_csw csw;
- SCSIRequest *req;
- SCSIBus bus;
- /* For async completion. */
- USBPacket *packet;
- /* usb-storage only */
- BlockConf conf;
- uint32_t removable;
- SCSIDevice *scsi_dev;
-} MSDState;
-
-#define TYPE_USB_STORAGE "usb-storage-dev"
-#define USB_STORAGE_DEV(obj) OBJECT_CHECK(MSDState, (obj), TYPE_USB_STORAGE)
-
-struct usb_msd_cbw {
- uint32_t sig;
- uint32_t tag;
- uint32_t data_len;
- uint8_t flags;
- uint8_t lun;
- uint8_t cmd_len;
- uint8_t cmd[16];
-};
-
-enum {
- STR_MANUFACTURER = 1,
- STR_PRODUCT,
- STR_SERIALNUMBER,
- STR_CONFIG_FULL,
- STR_CONFIG_HIGH,
- STR_CONFIG_SUPER,
-};
-
-static const USBDescStrings desc_strings = {
- [STR_MANUFACTURER] = "QEMU",
- [STR_PRODUCT] = "QEMU USB HARDDRIVE",
- [STR_SERIALNUMBER] = "1",
- [STR_CONFIG_FULL] = "Full speed config (usb 1.1)",
- [STR_CONFIG_HIGH] = "High speed config (usb 2.0)",
- [STR_CONFIG_SUPER] = "Super speed config (usb 3.0)",
-};
-
-static const USBDescIface desc_iface_full = {
- .bInterfaceNumber = 0,
- .bNumEndpoints = 2,
- .bInterfaceClass = USB_CLASS_MASS_STORAGE,
- .bInterfaceSubClass = 0x06, /* SCSI */
- .bInterfaceProtocol = 0x50, /* Bulk */
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | 0x01,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 64,
- },{
- .bEndpointAddress = USB_DIR_OUT | 0x02,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 64,
- },
- }
-};
-
-static const USBDescDevice desc_device_full = {
- .bcdUSB = 0x0200,
- .bMaxPacketSize0 = 8,
- .bNumConfigurations = 1,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 1,
- .bConfigurationValue = 1,
- .iConfiguration = STR_CONFIG_FULL,
- .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
- .nif = 1,
- .ifs = &desc_iface_full,
- },
- },
-};
-
-static const USBDescIface desc_iface_high = {
- .bInterfaceNumber = 0,
- .bNumEndpoints = 2,
- .bInterfaceClass = USB_CLASS_MASS_STORAGE,
- .bInterfaceSubClass = 0x06, /* SCSI */
- .bInterfaceProtocol = 0x50, /* Bulk */
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | 0x01,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 512,
- },{
- .bEndpointAddress = USB_DIR_OUT | 0x02,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 512,
- },
- }
-};
-
-static const USBDescDevice desc_device_high = {
- .bcdUSB = 0x0200,
- .bMaxPacketSize0 = 64,
- .bNumConfigurations = 1,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 1,
- .bConfigurationValue = 1,
- .iConfiguration = STR_CONFIG_HIGH,
- .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
- .nif = 1,
- .ifs = &desc_iface_high,
- },
- },
-};
-
-static const USBDescIface desc_iface_super = {
- .bInterfaceNumber = 0,
- .bNumEndpoints = 2,
- .bInterfaceClass = USB_CLASS_MASS_STORAGE,
- .bInterfaceSubClass = 0x06, /* SCSI */
- .bInterfaceProtocol = 0x50, /* Bulk */
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | 0x01,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 1024,
- .bMaxBurst = 15,
- },{
- .bEndpointAddress = USB_DIR_OUT | 0x02,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 1024,
- .bMaxBurst = 15,
- },
- }
-};
-
-static const USBDescDevice desc_device_super = {
- .bcdUSB = 0x0300,
- .bMaxPacketSize0 = 9,
- .bNumConfigurations = 1,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 1,
- .bConfigurationValue = 1,
- .iConfiguration = STR_CONFIG_SUPER,
- .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
- .nif = 1,
- .ifs = &desc_iface_super,
- },
- },
-};
-
-static const USBDesc desc = {
- .id = {
- .idVendor = 0x46f4, /* CRC16() of "QEMU" */
- .idProduct = 0x0001,
- .bcdDevice = 0,
- .iManufacturer = STR_MANUFACTURER,
- .iProduct = STR_PRODUCT,
- .iSerialNumber = STR_SERIALNUMBER,
- },
- .full = &desc_device_full,
- .high = &desc_device_high,
- .super = &desc_device_super,
- .str = desc_strings,
-};
-
-static void usb_msd_copy_data(MSDState *s, USBPacket *p)
-{
- uint32_t len;
- len = p->iov.size - p->actual_length;
- if (len > s->scsi_len)
- len = s->scsi_len;
- usb_packet_copy(p, scsi_req_get_buf(s->req) + s->scsi_off, len);
- s->scsi_len -= len;
- s->scsi_off += len;
- s->data_len -= len;
- if (s->scsi_len == 0 || s->data_len == 0) {
- scsi_req_continue(s->req);
- }
-}
-
-static void usb_msd_send_status(MSDState *s, USBPacket *p)
-{
- int len;
-
- DPRINTF("Command status %d tag 0x%x, len %zd\n",
- s->csw.status, le32_to_cpu(s->csw.tag), p->iov.size);
-
- assert(s->csw.sig == cpu_to_le32(0x53425355));
- len = MIN(sizeof(s->csw), p->iov.size);
- usb_packet_copy(p, &s->csw, len);
- memset(&s->csw, 0, sizeof(s->csw));
-}
-
-static void usb_msd_packet_complete(MSDState *s)
-{
- USBPacket *p = s->packet;
-
- /* Set s->packet to NULL before calling usb_packet_complete
- because another request may be issued before
- usb_packet_complete returns. */
- DPRINTF("Packet complete %p\n", p);
- s->packet = NULL;
- usb_packet_complete(&s->dev, p);
-}
-
-static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len)
-{
- MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
- USBPacket *p = s->packet;
-
- assert((s->mode == USB_MSDM_DATAOUT) == (req->cmd.mode == SCSI_XFER_TO_DEV));
- s->scsi_len = len;
- s->scsi_off = 0;
- if (p) {
- usb_msd_copy_data(s, p);
- p = s->packet;
- if (p && p->actual_length == p->iov.size) {
- p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
- usb_msd_packet_complete(s);
- }
- }
-}
-
-static void usb_msd_command_complete(SCSIRequest *req, uint32_t status, size_t resid)
-{
- MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
- USBPacket *p = s->packet;
-
- DPRINTF("Command complete %d tag 0x%x\n", status, req->tag);
-
- s->csw.sig = cpu_to_le32(0x53425355);
- s->csw.tag = cpu_to_le32(req->tag);
- s->csw.residue = cpu_to_le32(s->data_len);
- s->csw.status = status != 0;
-
- if (s->packet) {
- if (s->data_len == 0 && s->mode == USB_MSDM_DATAOUT) {
- /* A deferred packet with no write data remaining must be
- the status read packet. */
- usb_msd_send_status(s, p);
- s->mode = USB_MSDM_CBW;
- } else if (s->mode == USB_MSDM_CSW) {
- usb_msd_send_status(s, p);
- s->mode = USB_MSDM_CBW;
- } else {
- if (s->data_len) {
- int len = (p->iov.size - p->actual_length);
- usb_packet_skip(p, len);
- s->data_len -= len;
- }
- if (s->data_len == 0) {
- s->mode = USB_MSDM_CSW;
- }
- }
- p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
- usb_msd_packet_complete(s);
- } else if (s->data_len == 0) {
- s->mode = USB_MSDM_CSW;
- }
- scsi_req_unref(req);
- s->req = NULL;
-}
-
-static void usb_msd_request_cancelled(SCSIRequest *req)
-{
- MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
-
- if (req == s->req) {
- scsi_req_unref(s->req);
- s->req = NULL;
- s->scsi_len = 0;
- }
-}
-
-static void usb_msd_handle_reset(USBDevice *dev)
-{
- MSDState *s = (MSDState *)dev;
-
- DPRINTF("Reset\n");
- if (s->req) {
- scsi_req_cancel(s->req);
- }
- assert(s->req == NULL);
-
- if (s->packet) {
- s->packet->status = USB_RET_STALL;
- usb_msd_packet_complete(s);
- }
-
- s->mode = USB_MSDM_CBW;
-}
-
-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;
- SCSIDevice *scsi_dev;
- int ret, maxlun;
-
- ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
- if (ret >= 0) {
- return;
- }
-
- switch (request) {
- case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
- break;
- /* Class specific requests. */
- case ClassInterfaceOutRequest | MassStorageReset:
- /* Reset state ready for the next CBW. */
- s->mode = USB_MSDM_CBW;
- break;
- case ClassInterfaceRequest | GetMaxLun:
- 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:
- p->status = USB_RET_STALL;
- break;
- }
-}
-
-static void usb_msd_cancel_io(USBDevice *dev, USBPacket *p)
-{
- MSDState *s = USB_STORAGE_DEV(dev);
-
- assert(s->packet == p);
- s->packet = NULL;
-
- if (s->req) {
- scsi_req_cancel(s->req);
- }
-}
-
-static void usb_msd_handle_data(USBDevice *dev, USBPacket *p)
-{
- MSDState *s = (MSDState *)dev;
- uint32_t tag;
- struct usb_msd_cbw cbw;
- uint8_t devep = p->ep->nr;
- SCSIDevice *scsi_dev;
- uint32_t len;
-
- switch (p->pid) {
- case USB_TOKEN_OUT:
- if (devep != 2)
- goto fail;
-
- switch (s->mode) {
- case USB_MSDM_CBW:
- if (p->iov.size != 31) {
- error_report("usb-msd: Bad CBW size");
- goto fail;
- }
- usb_packet_copy(p, &cbw, 31);
- if (le32_to_cpu(cbw.sig) != 0x43425355) {
- error_report("usb-msd: Bad signature %08x",
- le32_to_cpu(cbw.sig));
- goto fail;
- }
- DPRINTF("Command on LUN %d\n", cbw.lun);
- scsi_dev = scsi_device_find(&s->bus, 0, 0, cbw.lun);
- if (scsi_dev == NULL) {
- error_report("usb-msd: Bad LUN %d", cbw.lun);
- goto fail;
- }
- tag = le32_to_cpu(cbw.tag);
- s->data_len = le32_to_cpu(cbw.data_len);
- if (s->data_len == 0) {
- s->mode = USB_MSDM_CSW;
- } else if (cbw.flags & 0x80) {
- s->mode = USB_MSDM_DATAIN;
- } else {
- s->mode = USB_MSDM_DATAOUT;
- }
- DPRINTF("Command tag 0x%x flags %08x len %d data %d\n",
- 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(scsi_dev, tag, cbw.lun, cbw.cmd, NULL);
-#ifdef DEBUG_MSD
- scsi_req_print(s->req);
-#endif
- len = scsi_req_enqueue(s->req);
- if (len) {
- scsi_req_continue(s->req);
- }
- break;
-
- case USB_MSDM_DATAOUT:
- DPRINTF("Data out %zd/%d\n", p->iov.size, s->data_len);
- if (p->iov.size > s->data_len) {
- goto fail;
- }
-
- if (s->scsi_len) {
- usb_msd_copy_data(s, p);
- }
- if (le32_to_cpu(s->csw.residue)) {
- int len = p->iov.size - p->actual_length;
- if (len) {
- usb_packet_skip(p, len);
- s->data_len -= len;
- if (s->data_len == 0) {
- s->mode = USB_MSDM_CSW;
- }
- }
- }
- if (p->actual_length < p->iov.size) {
- DPRINTF("Deferring packet %p [wait data-out]\n", p);
- s->packet = p;
- p->status = USB_RET_ASYNC;
- }
- break;
-
- default:
- DPRINTF("Unexpected write (len %zd)\n", p->iov.size);
- goto fail;
- }
- break;
-
- case USB_TOKEN_IN:
- if (devep != 1)
- goto fail;
-
- switch (s->mode) {
- case USB_MSDM_DATAOUT:
- if (s->data_len != 0 || p->iov.size < 13) {
- goto fail;
- }
- /* Waiting for SCSI write to complete. */
- s->packet = p;
- p->status = USB_RET_ASYNC;
- break;
-
- case USB_MSDM_CSW:
- if (p->iov.size < 13) {
- goto fail;
- }
-
- if (s->req) {
- /* still in flight */
- DPRINTF("Deferring packet %p [wait status]\n", p);
- s->packet = p;
- p->status = USB_RET_ASYNC;
- } else {
- usb_msd_send_status(s, p);
- s->mode = USB_MSDM_CBW;
- }
- break;
-
- case USB_MSDM_DATAIN:
- DPRINTF("Data in %zd/%d, scsi_len %d\n",
- p->iov.size, s->data_len, s->scsi_len);
- if (s->scsi_len) {
- usb_msd_copy_data(s, p);
- }
- if (le32_to_cpu(s->csw.residue)) {
- int len = p->iov.size - p->actual_length;
- if (len) {
- usb_packet_skip(p, len);
- s->data_len -= len;
- if (s->data_len == 0) {
- s->mode = USB_MSDM_CSW;
- }
- }
- }
- if (p->actual_length < p->iov.size) {
- DPRINTF("Deferring packet %p [wait data-in]\n", p);
- s->packet = p;
- p->status = USB_RET_ASYNC;
- }
- break;
-
- default:
- DPRINTF("Unexpected read (len %zd)\n", p->iov.size);
- goto fail;
- }
- break;
-
- default:
- DPRINTF("Bad token\n");
- fail:
- p->status = USB_RET_STALL;
- break;
- }
-}
-
-static void usb_msd_password_cb(void *opaque, int err)
-{
- MSDState *s = opaque;
- Error *local_err = NULL;
-
- if (!err) {
- usb_device_attach(&s->dev, &local_err);
- }
-
- if (local_err) {
- error_report_err(local_err);
- qdev_unplug(&s->dev.qdev, NULL);
- }
-}
-
-static void *usb_msd_load_request(QEMUFile *f, SCSIRequest *req)
-{
- MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
-
- /* nothing to load, just store req in our state struct */
- assert(s->req == NULL);
- scsi_req_ref(req);
- s->req = req;
- return NULL;
-}
-
-static const struct SCSIBusInfo usb_msd_scsi_info_storage = {
- .tcq = false,
- .max_target = 0,
- .max_lun = 0,
-
- .transfer_data = usb_msd_transfer_data,
- .complete = usb_msd_command_complete,
- .cancel = usb_msd_request_cancelled,
- .load_request = usb_msd_load_request,
-};
-
-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 void usb_msd_realize_storage(USBDevice *dev, Error **errp)
-{
- MSDState *s = USB_STORAGE_DEV(dev);
- BlockBackend *blk = s->conf.blk;
- SCSIDevice *scsi_dev;
- Error *err = NULL;
-
- if (!blk) {
- error_setg(errp, "drive property not set");
- return;
- }
-
- if (blk_bs(blk)) {
- bdrv_add_key(blk_bs(blk), NULL, &err);
- if (err) {
- if (monitor_cur_is_qmp()) {
- error_propagate(errp, err);
- return;
- }
- error_free(err);
- err = NULL;
- if (cur_mon) {
- monitor_read_bdrv_key_start(cur_mon, blk_bs(blk),
- usb_msd_password_cb, s);
- s->dev.auto_attach = 0;
- } else {
- autostart = 0;
- }
- }
- }
-
- blkconf_serial(&s->conf, &dev->serial);
- blkconf_blocksizes(&s->conf);
-
- /*
- * Hack alert: this pretends to be a block device, but it's really
- * a SCSI bus that can serve only a single device, which it
- * creates automatically. But first it needs to detach from its
- * blockdev, or else scsi_bus_legacy_add_drive() dies when it
- * attaches again.
- *
- * The hack is probably a bad idea.
- */
- blk_detach_dev(blk, &s->dev.qdev);
- s->conf.blk = NULL;
-
- usb_desc_create_serial(dev);
- usb_desc_init(dev);
- scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(dev),
- &usb_msd_scsi_info_storage, NULL);
- scsi_dev = scsi_bus_legacy_add_drive(&s->bus, blk, 0, !!s->removable,
- s->conf.bootindex, dev->serial,
- &err);
- if (!scsi_dev) {
- error_propagate(errp, err);
- return;
- }
- usb_msd_handle_reset(dev);
- s->scsi_dev = scsi_dev;
-}
-
-static void usb_msd_realize_bot(USBDevice *dev, Error **errp)
-{
- MSDState *s = USB_STORAGE_DEV(dev);
-
- usb_desc_create_serial(dev);
- usb_desc_init(dev);
- scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(dev),
- &usb_msd_scsi_info_bot, NULL);
- usb_msd_handle_reset(dev);
-}
-
-static USBDevice *usb_msd_init(USBBus *bus, const char *filename)
-{
- static int nr=0;
- Error *err = NULL;
- char id[8];
- QemuOpts *opts;
- DriveInfo *dinfo;
- USBDevice *dev;
- const char *p1;
- char fmt[32];
-
- /* parse -usbdevice disk: syntax into drive opts */
- do {
- snprintf(id, sizeof(id), "usb%d", nr++);
- opts = qemu_opts_create(qemu_find_opts("drive"), id, 1, NULL);
- } while (!opts);
-
- p1 = strchr(filename, ':');
- if (p1++) {
- const char *p2;
-
- if (strstart(filename, "format=", &p2)) {
- int len = MIN(p1 - p2, sizeof(fmt));
- pstrcpy(fmt, len, p2);
- qemu_opt_set(opts, "format", fmt, &error_abort);
- } else if (*filename != ':') {
- error_report("unrecognized USB mass-storage option %s", filename);
- return NULL;
- }
- filename = p1;
- }
- if (!*filename) {
- error_report("block device specification needed");
- return NULL;
- }
- qemu_opt_set(opts, "file", filename, &error_abort);
- qemu_opt_set(opts, "if", "none", &error_abort);
-
- /* create host drive */
- dinfo = drive_new(opts, 0);
- if (!dinfo) {
- qemu_opts_del(opts);
- return NULL;
- }
-
- /* create guest device */
- dev = usb_create(bus, "usb-storage");
- qdev_prop_set_drive(&dev->qdev, "drive", blk_by_legacy_dinfo(dinfo),
- &err);
- if (err) {
- error_report_err(err);
- object_unparent(OBJECT(dev));
- return NULL;
- }
- return dev;
-}
-
-static const VMStateDescription vmstate_usb_msd = {
- .name = "usb-storage",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_USB_DEVICE(dev, MSDState),
- VMSTATE_UINT32(mode, MSDState),
- VMSTATE_UINT32(scsi_len, MSDState),
- VMSTATE_UINT32(scsi_off, MSDState),
- VMSTATE_UINT32(data_len, MSDState),
- VMSTATE_UINT32(csw.sig, MSDState),
- VMSTATE_UINT32(csw.tag, MSDState),
- VMSTATE_UINT32(csw.residue, MSDState),
- VMSTATE_UINT8(csw.status, MSDState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property msd_properties[] = {
- DEFINE_BLOCK_PROPERTIES(MSDState, conf),
- DEFINE_PROP_BIT("removable", MSDState, removable, 0, false),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void usb_msd_class_initfn_common(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
-
- uc->product_desc = "QEMU USB MSD";
- uc->usb_desc = &desc;
- uc->cancel_packet = usb_msd_cancel_io;
- uc->handle_attach = usb_desc_attach;
- uc->handle_reset = usb_msd_handle_reset;
- uc->handle_control = usb_msd_handle_control;
- uc->handle_data = usb_msd_handle_data;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
- 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->realize = usb_msd_realize_storage;
- dc->props = msd_properties;
-}
-
-static void usb_msd_get_bootindex(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- USBDevice *dev = USB_DEVICE(obj);
- MSDState *s = USB_STORAGE_DEV(dev);
-
- visit_type_int32(v, name, &s->conf.bootindex, errp);
-}
-
-static void usb_msd_set_bootindex(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- USBDevice *dev = USB_DEVICE(obj);
- MSDState *s = USB_STORAGE_DEV(dev);
- int32_t boot_index;
- Error *local_err = NULL;
-
- visit_type_int32(v, name, &boot_index, &local_err);
- if (local_err) {
- goto out;
- }
- /* check whether bootindex is present in fw_boot_order list */
- check_boot_index(boot_index, &local_err);
- if (local_err) {
- goto out;
- }
- /* change bootindex to a new one */
- s->conf.bootindex = boot_index;
-
- if (s->scsi_dev) {
- object_property_set_int(OBJECT(s->scsi_dev), boot_index, "bootindex",
- &error_abort);
- }
-
-out:
- if (local_err) {
- error_propagate(errp, local_err);
- }
-}
-
-static const TypeInfo usb_storage_dev_type_info = {
- .name = TYPE_USB_STORAGE,
- .parent = TYPE_USB_DEVICE,
- .instance_size = sizeof(MSDState),
- .abstract = true,
- .class_init = usb_msd_class_initfn_common,
-};
-
-static void usb_msd_instance_init(Object *obj)
-{
- object_property_add(obj, "bootindex", "int32",
- usb_msd_get_bootindex,
- usb_msd_set_bootindex, NULL, NULL, NULL);
- object_property_set_int(obj, -1, "bootindex", NULL);
-}
-
-static void usb_msd_class_initfn_bot(ObjectClass *klass, void *data)
-{
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- uc->realize = usb_msd_realize_bot;
- dc->hotpluggable = false;
-}
-
-static const TypeInfo msd_info = {
- .name = "usb-storage",
- .parent = TYPE_USB_STORAGE,
- .class_init = usb_msd_class_initfn_storage,
- .instance_init = usb_msd_instance_init,
-};
-
-static const TypeInfo bot_info = {
- .name = "usb-bot",
- .parent = TYPE_USB_STORAGE,
- .class_init = usb_msd_class_initfn_bot,
-};
-
-static void usb_msd_register_types(void)
-{
- type_register_static(&usb_storage_dev_type_info);
- type_register_static(&msd_info);
- type_register_static(&bot_info);
- usb_legacy_register("usb-storage", "disk", usb_msd_init);
-}
-
-type_init(usb_msd_register_types)
diff --git a/qemu/hw/usb/dev-uas.c b/qemu/hw/usb/dev-uas.c
deleted file mode 100644
index 0678b1b05..000000000
--- a/qemu/hw/usb/dev-uas.c
+++ /dev/null
@@ -1,961 +0,0 @@
-/*
- * UAS (USB Attached SCSI) emulation
- *
- * Copyright Red Hat, Inc. 2012
- *
- * Author: Gerd Hoffmann <kraxel@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "qemu/option.h"
-#include "qemu/config-file.h"
-#include "trace.h"
-#include "qemu/error-report.h"
-
-#include "hw/usb.h"
-#include "hw/usb/desc.h"
-#include "hw/scsi/scsi.h"
-#include "block/scsi.h"
-
-/* --------------------------------------------------------------------- */
-
-#define UAS_UI_COMMAND 0x01
-#define UAS_UI_SENSE 0x03
-#define UAS_UI_RESPONSE 0x04
-#define UAS_UI_TASK_MGMT 0x05
-#define UAS_UI_READ_READY 0x06
-#define UAS_UI_WRITE_READY 0x07
-
-#define UAS_RC_TMF_COMPLETE 0x00
-#define UAS_RC_INVALID_INFO_UNIT 0x02
-#define UAS_RC_TMF_NOT_SUPPORTED 0x04
-#define UAS_RC_TMF_FAILED 0x05
-#define UAS_RC_TMF_SUCCEEDED 0x08
-#define UAS_RC_INCORRECT_LUN 0x09
-#define UAS_RC_OVERLAPPED_TAG 0x0a
-
-#define UAS_TMF_ABORT_TASK 0x01
-#define UAS_TMF_ABORT_TASK_SET 0x02
-#define UAS_TMF_CLEAR_TASK_SET 0x04
-#define UAS_TMF_LOGICAL_UNIT_RESET 0x08
-#define UAS_TMF_I_T_NEXUS_RESET 0x10
-#define UAS_TMF_CLEAR_ACA 0x40
-#define UAS_TMF_QUERY_TASK 0x80
-#define UAS_TMF_QUERY_TASK_SET 0x81
-#define UAS_TMF_QUERY_ASYNC_EVENT 0x82
-
-#define UAS_PIPE_ID_COMMAND 0x01
-#define UAS_PIPE_ID_STATUS 0x02
-#define UAS_PIPE_ID_DATA_IN 0x03
-#define UAS_PIPE_ID_DATA_OUT 0x04
-
-typedef struct {
- uint8_t id;
- uint8_t reserved;
- uint16_t tag;
-} QEMU_PACKED uas_iu_header;
-
-typedef struct {
- uint8_t prio_taskattr; /* 6:3 priority, 2:0 task attribute */
- uint8_t reserved_1;
- uint8_t add_cdb_length; /* 7:2 additional adb length (dwords) */
- uint8_t reserved_2;
- uint64_t lun;
- uint8_t cdb[16];
- uint8_t add_cdb[];
-} QEMU_PACKED uas_iu_command;
-
-typedef struct {
- uint16_t status_qualifier;
- uint8_t status;
- uint8_t reserved[7];
- uint16_t sense_length;
- uint8_t sense_data[18];
-} QEMU_PACKED uas_iu_sense;
-
-typedef struct {
- uint8_t add_response_info[3];
- uint8_t response_code;
-} QEMU_PACKED uas_iu_response;
-
-typedef struct {
- uint8_t function;
- uint8_t reserved;
- uint16_t task_tag;
- uint64_t lun;
-} QEMU_PACKED uas_iu_task_mgmt;
-
-typedef struct {
- uas_iu_header hdr;
- union {
- uas_iu_command command;
- uas_iu_sense sense;
- uas_iu_task_mgmt task;
- uas_iu_response response;
- };
-} QEMU_PACKED uas_iu;
-
-/* --------------------------------------------------------------------- */
-
-#define UAS_STREAM_BM_ATTR 4
-#define UAS_MAX_STREAMS (1 << UAS_STREAM_BM_ATTR)
-
-typedef struct UASDevice UASDevice;
-typedef struct UASRequest UASRequest;
-typedef struct UASStatus UASStatus;
-
-struct UASDevice {
- USBDevice dev;
- SCSIBus bus;
- QEMUBH *status_bh;
- QTAILQ_HEAD(, UASStatus) results;
- QTAILQ_HEAD(, UASRequest) requests;
-
- /* properties */
- uint32_t requestlog;
-
- /* usb 2.0 only */
- USBPacket *status2;
- UASRequest *datain2;
- UASRequest *dataout2;
-
- /* usb 3.0 only */
- USBPacket *data3[UAS_MAX_STREAMS + 1];
- USBPacket *status3[UAS_MAX_STREAMS + 1];
-};
-
-#define TYPE_USB_UAS "usb-uas"
-#define USB_UAS(obj) OBJECT_CHECK(UASDevice, (obj), TYPE_USB_UAS)
-
-struct UASRequest {
- uint16_t tag;
- uint64_t lun;
- UASDevice *uas;
- SCSIDevice *dev;
- SCSIRequest *req;
- USBPacket *data;
- bool data_async;
- bool active;
- bool complete;
- uint32_t buf_off;
- uint32_t buf_size;
- uint32_t data_off;
- uint32_t data_size;
- QTAILQ_ENTRY(UASRequest) next;
-};
-
-struct UASStatus {
- uint32_t stream;
- uas_iu status;
- uint32_t length;
- QTAILQ_ENTRY(UASStatus) next;
-};
-
-/* --------------------------------------------------------------------- */
-
-enum {
- STR_MANUFACTURER = 1,
- STR_PRODUCT,
- STR_SERIALNUMBER,
- STR_CONFIG_HIGH,
- STR_CONFIG_SUPER,
-};
-
-static const USBDescStrings desc_strings = {
- [STR_MANUFACTURER] = "QEMU",
- [STR_PRODUCT] = "USB Attached SCSI HBA",
- [STR_SERIALNUMBER] = "27842",
- [STR_CONFIG_HIGH] = "High speed config (usb 2.0)",
- [STR_CONFIG_SUPER] = "Super speed config (usb 3.0)",
-};
-
-static const USBDescIface desc_iface_high = {
- .bInterfaceNumber = 0,
- .bNumEndpoints = 4,
- .bInterfaceClass = USB_CLASS_MASS_STORAGE,
- .bInterfaceSubClass = 0x06, /* SCSI */
- .bInterfaceProtocol = 0x62, /* UAS */
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_OUT | UAS_PIPE_ID_COMMAND,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 512,
- .extra = (uint8_t[]) {
- 0x04, /* u8 bLength */
- 0x24, /* u8 bDescriptorType */
- UAS_PIPE_ID_COMMAND,
- 0x00, /* u8 bReserved */
- },
- },{
- .bEndpointAddress = USB_DIR_IN | UAS_PIPE_ID_STATUS,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 512,
- .extra = (uint8_t[]) {
- 0x04, /* u8 bLength */
- 0x24, /* u8 bDescriptorType */
- UAS_PIPE_ID_STATUS,
- 0x00, /* u8 bReserved */
- },
- },{
- .bEndpointAddress = USB_DIR_IN | UAS_PIPE_ID_DATA_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 512,
- .extra = (uint8_t[]) {
- 0x04, /* u8 bLength */
- 0x24, /* u8 bDescriptorType */
- UAS_PIPE_ID_DATA_IN,
- 0x00, /* u8 bReserved */
- },
- },{
- .bEndpointAddress = USB_DIR_OUT | UAS_PIPE_ID_DATA_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 512,
- .extra = (uint8_t[]) {
- 0x04, /* u8 bLength */
- 0x24, /* u8 bDescriptorType */
- UAS_PIPE_ID_DATA_OUT,
- 0x00, /* u8 bReserved */
- },
- },
- }
-};
-
-static const USBDescIface desc_iface_super = {
- .bInterfaceNumber = 0,
- .bNumEndpoints = 4,
- .bInterfaceClass = USB_CLASS_MASS_STORAGE,
- .bInterfaceSubClass = 0x06, /* SCSI */
- .bInterfaceProtocol = 0x62, /* UAS */
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_OUT | UAS_PIPE_ID_COMMAND,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 1024,
- .bMaxBurst = 15,
- .extra = (uint8_t[]) {
- 0x04, /* u8 bLength */
- 0x24, /* u8 bDescriptorType */
- UAS_PIPE_ID_COMMAND,
- 0x00, /* u8 bReserved */
- },
- },{
- .bEndpointAddress = USB_DIR_IN | UAS_PIPE_ID_STATUS,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 1024,
- .bMaxBurst = 15,
- .bmAttributes_super = UAS_STREAM_BM_ATTR,
- .extra = (uint8_t[]) {
- 0x04, /* u8 bLength */
- 0x24, /* u8 bDescriptorType */
- UAS_PIPE_ID_STATUS,
- 0x00, /* u8 bReserved */
- },
- },{
- .bEndpointAddress = USB_DIR_IN | UAS_PIPE_ID_DATA_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 1024,
- .bMaxBurst = 15,
- .bmAttributes_super = UAS_STREAM_BM_ATTR,
- .extra = (uint8_t[]) {
- 0x04, /* u8 bLength */
- 0x24, /* u8 bDescriptorType */
- UAS_PIPE_ID_DATA_IN,
- 0x00, /* u8 bReserved */
- },
- },{
- .bEndpointAddress = USB_DIR_OUT | UAS_PIPE_ID_DATA_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 1024,
- .bMaxBurst = 15,
- .bmAttributes_super = UAS_STREAM_BM_ATTR,
- .extra = (uint8_t[]) {
- 0x04, /* u8 bLength */
- 0x24, /* u8 bDescriptorType */
- UAS_PIPE_ID_DATA_OUT,
- 0x00, /* u8 bReserved */
- },
- },
- }
-};
-
-static const USBDescDevice desc_device_high = {
- .bcdUSB = 0x0200,
- .bMaxPacketSize0 = 64,
- .bNumConfigurations = 1,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 1,
- .bConfigurationValue = 1,
- .iConfiguration = STR_CONFIG_HIGH,
- .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
- .nif = 1,
- .ifs = &desc_iface_high,
- },
- },
-};
-
-static const USBDescDevice desc_device_super = {
- .bcdUSB = 0x0300,
- .bMaxPacketSize0 = 64,
- .bNumConfigurations = 1,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 1,
- .bConfigurationValue = 1,
- .iConfiguration = STR_CONFIG_SUPER,
- .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
- .nif = 1,
- .ifs = &desc_iface_super,
- },
- },
-};
-
-static const USBDesc desc = {
- .id = {
- .idVendor = 0x46f4, /* CRC16() of "QEMU" */
- .idProduct = 0x0003,
- .bcdDevice = 0,
- .iManufacturer = STR_MANUFACTURER,
- .iProduct = STR_PRODUCT,
- .iSerialNumber = STR_SERIALNUMBER,
- },
- .high = &desc_device_high,
- .super = &desc_device_super,
- .str = desc_strings,
-};
-
-/* --------------------------------------------------------------------- */
-
-static bool uas_using_streams(UASDevice *uas)
-{
- return uas->dev.speed == USB_SPEED_SUPER;
-}
-
-/* --------------------------------------------------------------------- */
-
-static UASStatus *usb_uas_alloc_status(UASDevice *uas, uint8_t id, uint16_t tag)
-{
- UASStatus *st = g_new0(UASStatus, 1);
-
- st->status.hdr.id = id;
- st->status.hdr.tag = cpu_to_be16(tag);
- st->length = sizeof(uas_iu_header);
- if (uas_using_streams(uas)) {
- st->stream = tag;
- }
- return st;
-}
-
-static void usb_uas_send_status_bh(void *opaque)
-{
- UASDevice *uas = opaque;
- UASStatus *st;
- USBPacket *p;
-
- while ((st = QTAILQ_FIRST(&uas->results)) != NULL) {
- if (uas_using_streams(uas)) {
- p = uas->status3[st->stream];
- uas->status3[st->stream] = NULL;
- } else {
- p = uas->status2;
- uas->status2 = NULL;
- }
- if (p == NULL) {
- break;
- }
-
- usb_packet_copy(p, &st->status, st->length);
- QTAILQ_REMOVE(&uas->results, st, next);
- g_free(st);
-
- p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
- usb_packet_complete(&uas->dev, p);
- }
-}
-
-static void usb_uas_queue_status(UASDevice *uas, UASStatus *st, int length)
-{
- USBPacket *p = uas_using_streams(uas) ?
- uas->status3[st->stream] : uas->status2;
-
- st->length += length;
- QTAILQ_INSERT_TAIL(&uas->results, st, next);
- if (p) {
- /*
- * Just schedule bh make sure any in-flight data transaction
- * is finished before completing (sending) the status packet.
- */
- qemu_bh_schedule(uas->status_bh);
- } else {
- USBEndpoint *ep = usb_ep_get(&uas->dev, USB_TOKEN_IN,
- UAS_PIPE_ID_STATUS);
- usb_wakeup(ep, st->stream);
- }
-}
-
-static void usb_uas_queue_response(UASDevice *uas, uint16_t tag, uint8_t code)
-{
- UASStatus *st = usb_uas_alloc_status(uas, UAS_UI_RESPONSE, tag);
-
- trace_usb_uas_response(uas->dev.addr, tag, code);
- st->status.response.response_code = code;
- usb_uas_queue_status(uas, st, sizeof(uas_iu_response));
-}
-
-static void usb_uas_queue_sense(UASRequest *req, uint8_t status)
-{
- UASStatus *st = usb_uas_alloc_status(req->uas, UAS_UI_SENSE, req->tag);
- int len, slen = 0;
-
- trace_usb_uas_sense(req->uas->dev.addr, req->tag, status);
- st->status.sense.status = status;
- st->status.sense.status_qualifier = cpu_to_be16(0);
- if (status != GOOD) {
- slen = scsi_req_get_sense(req->req, st->status.sense.sense_data,
- sizeof(st->status.sense.sense_data));
- st->status.sense.sense_length = cpu_to_be16(slen);
- }
- len = sizeof(uas_iu_sense) - sizeof(st->status.sense.sense_data) + slen;
- usb_uas_queue_status(req->uas, st, len);
-}
-
-static void usb_uas_queue_fake_sense(UASDevice *uas, uint16_t tag,
- struct SCSISense sense)
-{
- UASStatus *st = usb_uas_alloc_status(uas, UAS_UI_SENSE, tag);
- int len, slen = 0;
-
- st->status.sense.status = CHECK_CONDITION;
- st->status.sense.status_qualifier = cpu_to_be16(0);
- st->status.sense.sense_data[0] = 0x70;
- st->status.sense.sense_data[2] = sense.key;
- st->status.sense.sense_data[7] = 10;
- st->status.sense.sense_data[12] = sense.asc;
- st->status.sense.sense_data[13] = sense.ascq;
- slen = 18;
- len = sizeof(uas_iu_sense) - sizeof(st->status.sense.sense_data) + slen;
- usb_uas_queue_status(uas, st, len);
-}
-
-static void usb_uas_queue_read_ready(UASRequest *req)
-{
- UASStatus *st = usb_uas_alloc_status(req->uas, UAS_UI_READ_READY,
- req->tag);
-
- trace_usb_uas_read_ready(req->uas->dev.addr, req->tag);
- usb_uas_queue_status(req->uas, st, 0);
-}
-
-static void usb_uas_queue_write_ready(UASRequest *req)
-{
- UASStatus *st = usb_uas_alloc_status(req->uas, UAS_UI_WRITE_READY,
- req->tag);
-
- trace_usb_uas_write_ready(req->uas->dev.addr, req->tag);
- usb_uas_queue_status(req->uas, st, 0);
-}
-
-/* --------------------------------------------------------------------- */
-
-static int usb_uas_get_lun(uint64_t lun64)
-{
- return (lun64 >> 48) & 0xff;
-}
-
-static SCSIDevice *usb_uas_get_dev(UASDevice *uas, uint64_t lun64)
-{
- if ((lun64 >> 56) != 0x00) {
- return NULL;
- }
- return scsi_device_find(&uas->bus, 0, 0, usb_uas_get_lun(lun64));
-}
-
-static void usb_uas_complete_data_packet(UASRequest *req)
-{
- USBPacket *p;
-
- if (!req->data_async) {
- return;
- }
- p = req->data;
- req->data = NULL;
- req->data_async = false;
- p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
- usb_packet_complete(&req->uas->dev, p);
-}
-
-static void usb_uas_copy_data(UASRequest *req)
-{
- uint32_t length;
-
- length = MIN(req->buf_size - req->buf_off,
- req->data->iov.size - req->data->actual_length);
- trace_usb_uas_xfer_data(req->uas->dev.addr, req->tag, length,
- req->data->actual_length, req->data->iov.size,
- req->buf_off, req->buf_size);
- usb_packet_copy(req->data, scsi_req_get_buf(req->req) + req->buf_off,
- length);
- req->buf_off += length;
- req->data_off += length;
-
- if (req->data->actual_length == req->data->iov.size) {
- usb_uas_complete_data_packet(req);
- }
- if (req->buf_size && req->buf_off == req->buf_size) {
- req->buf_off = 0;
- req->buf_size = 0;
- scsi_req_continue(req->req);
- }
-}
-
-static void usb_uas_start_next_transfer(UASDevice *uas)
-{
- UASRequest *req;
-
- if (uas_using_streams(uas)) {
- return;
- }
-
- QTAILQ_FOREACH(req, &uas->requests, next) {
- if (req->active || req->complete) {
- continue;
- }
- if (req->req->cmd.mode == SCSI_XFER_FROM_DEV && uas->datain2 == NULL) {
- uas->datain2 = req;
- usb_uas_queue_read_ready(req);
- req->active = true;
- return;
- }
- if (req->req->cmd.mode == SCSI_XFER_TO_DEV && uas->dataout2 == NULL) {
- uas->dataout2 = req;
- usb_uas_queue_write_ready(req);
- req->active = true;
- return;
- }
- }
-}
-
-static UASRequest *usb_uas_alloc_request(UASDevice *uas, uas_iu *iu)
-{
- UASRequest *req;
-
- req = g_new0(UASRequest, 1);
- req->uas = uas;
- req->tag = be16_to_cpu(iu->hdr.tag);
- req->lun = be64_to_cpu(iu->command.lun);
- req->dev = usb_uas_get_dev(req->uas, req->lun);
- return req;
-}
-
-static void usb_uas_scsi_free_request(SCSIBus *bus, void *priv)
-{
- UASRequest *req = priv;
- UASDevice *uas = req->uas;
-
- if (req == uas->datain2) {
- uas->datain2 = NULL;
- }
- if (req == uas->dataout2) {
- uas->dataout2 = NULL;
- }
- QTAILQ_REMOVE(&uas->requests, req, next);
- g_free(req);
- usb_uas_start_next_transfer(uas);
-}
-
-static UASRequest *usb_uas_find_request(UASDevice *uas, uint16_t tag)
-{
- UASRequest *req;
-
- QTAILQ_FOREACH(req, &uas->requests, next) {
- if (req->tag == tag) {
- return req;
- }
- }
- return NULL;
-}
-
-static void usb_uas_scsi_transfer_data(SCSIRequest *r, uint32_t len)
-{
- UASRequest *req = r->hba_private;
-
- trace_usb_uas_scsi_data(req->uas->dev.addr, req->tag, len);
- req->buf_off = 0;
- req->buf_size = len;
- if (req->data) {
- usb_uas_copy_data(req);
- } else {
- usb_uas_start_next_transfer(req->uas);
- }
-}
-
-static void usb_uas_scsi_command_complete(SCSIRequest *r,
- uint32_t status, size_t resid)
-{
- UASRequest *req = r->hba_private;
-
- trace_usb_uas_scsi_complete(req->uas->dev.addr, req->tag, status, resid);
- req->complete = true;
- if (req->data) {
- usb_uas_complete_data_packet(req);
- }
- usb_uas_queue_sense(req, status);
- scsi_req_unref(req->req);
-}
-
-static void usb_uas_scsi_request_cancelled(SCSIRequest *r)
-{
- UASRequest *req = r->hba_private;
-
- /* FIXME: queue notification to status pipe? */
- scsi_req_unref(req->req);
-}
-
-static const struct SCSIBusInfo usb_uas_scsi_info = {
- .tcq = true,
- .max_target = 0,
- .max_lun = 255,
-
- .transfer_data = usb_uas_scsi_transfer_data,
- .complete = usb_uas_scsi_command_complete,
- .cancel = usb_uas_scsi_request_cancelled,
- .free_request = usb_uas_scsi_free_request,
-};
-
-/* --------------------------------------------------------------------- */
-
-static void usb_uas_handle_reset(USBDevice *dev)
-{
- UASDevice *uas = USB_UAS(dev);
- UASRequest *req, *nreq;
- UASStatus *st, *nst;
-
- trace_usb_uas_reset(dev->addr);
- QTAILQ_FOREACH_SAFE(req, &uas->requests, next, nreq) {
- scsi_req_cancel(req->req);
- }
- QTAILQ_FOREACH_SAFE(st, &uas->results, next, nst) {
- QTAILQ_REMOVE(&uas->results, st, next);
- g_free(st);
- }
-}
-
-static void usb_uas_handle_control(USBDevice *dev, USBPacket *p,
- int request, int value, int index, int length, uint8_t *data)
-{
- int ret;
-
- ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
- if (ret >= 0) {
- return;
- }
- error_report("%s: unhandled control request", __func__);
- p->status = USB_RET_STALL;
-}
-
-static void usb_uas_cancel_io(USBDevice *dev, USBPacket *p)
-{
- UASDevice *uas = USB_UAS(dev);
- UASRequest *req, *nreq;
- int i;
-
- if (uas->status2 == p) {
- uas->status2 = NULL;
- qemu_bh_cancel(uas->status_bh);
- return;
- }
- if (uas_using_streams(uas)) {
- for (i = 0; i <= UAS_MAX_STREAMS; i++) {
- if (uas->status3[i] == p) {
- uas->status3[i] = NULL;
- return;
- }
- if (uas->data3[i] == p) {
- uas->data3[i] = NULL;
- return;
- }
- }
- }
- QTAILQ_FOREACH_SAFE(req, &uas->requests, next, nreq) {
- if (req->data == p) {
- req->data = NULL;
- return;
- }
- }
- assert(!"canceled usb packet not found");
-}
-
-static void usb_uas_command(UASDevice *uas, uas_iu *iu)
-{
- UASRequest *req;
- uint32_t len;
- uint16_t tag = be16_to_cpu(iu->hdr.tag);
-
- if (uas_using_streams(uas) && tag > UAS_MAX_STREAMS) {
- goto invalid_tag;
- }
- req = usb_uas_find_request(uas, tag);
- if (req) {
- goto overlapped_tag;
- }
- req = usb_uas_alloc_request(uas, iu);
- if (req->dev == NULL) {
- goto bad_target;
- }
-
- trace_usb_uas_command(uas->dev.addr, req->tag,
- usb_uas_get_lun(req->lun),
- req->lun >> 32, req->lun & 0xffffffff);
- QTAILQ_INSERT_TAIL(&uas->requests, req, next);
- if (uas_using_streams(uas) && uas->data3[req->tag] != NULL) {
- req->data = uas->data3[req->tag];
- req->data_async = true;
- uas->data3[req->tag] = NULL;
- }
-
- req->req = scsi_req_new(req->dev, req->tag,
- usb_uas_get_lun(req->lun),
- iu->command.cdb, req);
- if (uas->requestlog) {
- scsi_req_print(req->req);
- }
- len = scsi_req_enqueue(req->req);
- if (len) {
- req->data_size = len;
- scsi_req_continue(req->req);
- }
- return;
-
-invalid_tag:
- usb_uas_queue_fake_sense(uas, tag, sense_code_INVALID_TAG);
- return;
-
-overlapped_tag:
- usb_uas_queue_fake_sense(uas, tag, sense_code_OVERLAPPED_COMMANDS);
- return;
-
-bad_target:
- usb_uas_queue_fake_sense(uas, tag, sense_code_LUN_NOT_SUPPORTED);
- g_free(req);
-}
-
-static void usb_uas_task(UASDevice *uas, uas_iu *iu)
-{
- uint16_t tag = be16_to_cpu(iu->hdr.tag);
- uint64_t lun64 = be64_to_cpu(iu->task.lun);
- SCSIDevice *dev = usb_uas_get_dev(uas, lun64);
- int lun = usb_uas_get_lun(lun64);
- UASRequest *req;
- uint16_t task_tag;
-
- if (uas_using_streams(uas) && tag > UAS_MAX_STREAMS) {
- goto invalid_tag;
- }
- req = usb_uas_find_request(uas, be16_to_cpu(iu->hdr.tag));
- if (req) {
- goto overlapped_tag;
- }
- if (dev == NULL) {
- goto incorrect_lun;
- }
-
- switch (iu->task.function) {
- case UAS_TMF_ABORT_TASK:
- task_tag = be16_to_cpu(iu->task.task_tag);
- trace_usb_uas_tmf_abort_task(uas->dev.addr, tag, task_tag);
- req = usb_uas_find_request(uas, task_tag);
- if (req && req->dev == dev) {
- scsi_req_cancel(req->req);
- }
- usb_uas_queue_response(uas, tag, UAS_RC_TMF_COMPLETE);
- break;
-
- case UAS_TMF_LOGICAL_UNIT_RESET:
- trace_usb_uas_tmf_logical_unit_reset(uas->dev.addr, tag, lun);
- qdev_reset_all(&dev->qdev);
- usb_uas_queue_response(uas, tag, UAS_RC_TMF_COMPLETE);
- break;
-
- default:
- trace_usb_uas_tmf_unsupported(uas->dev.addr, tag, iu->task.function);
- usb_uas_queue_response(uas, tag, UAS_RC_TMF_NOT_SUPPORTED);
- break;
- }
- return;
-
-invalid_tag:
- usb_uas_queue_response(uas, tag, UAS_RC_INVALID_INFO_UNIT);
- return;
-
-overlapped_tag:
- usb_uas_queue_response(uas, req->tag, UAS_RC_OVERLAPPED_TAG);
- return;
-
-incorrect_lun:
- usb_uas_queue_response(uas, tag, UAS_RC_INCORRECT_LUN);
-}
-
-static void usb_uas_handle_data(USBDevice *dev, USBPacket *p)
-{
- UASDevice *uas = USB_UAS(dev);
- uas_iu iu;
- UASStatus *st;
- UASRequest *req;
- int length;
-
- switch (p->ep->nr) {
- case UAS_PIPE_ID_COMMAND:
- length = MIN(sizeof(iu), p->iov.size);
- usb_packet_copy(p, &iu, length);
- switch (iu.hdr.id) {
- case UAS_UI_COMMAND:
- usb_uas_command(uas, &iu);
- break;
- case UAS_UI_TASK_MGMT:
- usb_uas_task(uas, &iu);
- break;
- default:
- error_report("%s: unknown command iu: id 0x%x",
- __func__, iu.hdr.id);
- p->status = USB_RET_STALL;
- break;
- }
- break;
- case UAS_PIPE_ID_STATUS:
- if (p->stream) {
- QTAILQ_FOREACH(st, &uas->results, next) {
- if (st->stream == p->stream) {
- break;
- }
- }
- if (st == NULL) {
- assert(uas->status3[p->stream] == NULL);
- uas->status3[p->stream] = p;
- p->status = USB_RET_ASYNC;
- break;
- }
- } else {
- st = QTAILQ_FIRST(&uas->results);
- if (st == NULL) {
- assert(uas->status2 == NULL);
- uas->status2 = p;
- p->status = USB_RET_ASYNC;
- break;
- }
- }
- usb_packet_copy(p, &st->status, st->length);
- QTAILQ_REMOVE(&uas->results, st, next);
- g_free(st);
- break;
- case UAS_PIPE_ID_DATA_IN:
- case UAS_PIPE_ID_DATA_OUT:
- if (p->stream) {
- req = usb_uas_find_request(uas, p->stream);
- } else {
- req = (p->ep->nr == UAS_PIPE_ID_DATA_IN)
- ? uas->datain2 : uas->dataout2;
- }
- if (req == NULL) {
- if (p->stream) {
- assert(uas->data3[p->stream] == NULL);
- uas->data3[p->stream] = p;
- p->status = USB_RET_ASYNC;
- break;
- } else {
- error_report("%s: no inflight request", __func__);
- p->status = USB_RET_STALL;
- break;
- }
- }
- scsi_req_ref(req->req);
- req->data = p;
- usb_uas_copy_data(req);
- if (p->actual_length == p->iov.size || req->complete) {
- req->data = NULL;
- } else {
- req->data_async = true;
- p->status = USB_RET_ASYNC;
- }
- scsi_req_unref(req->req);
- usb_uas_start_next_transfer(uas);
- break;
- default:
- error_report("%s: invalid endpoint %d", __func__, p->ep->nr);
- p->status = USB_RET_STALL;
- break;
- }
-}
-
-static void usb_uas_handle_destroy(USBDevice *dev)
-{
- UASDevice *uas = USB_UAS(dev);
-
- qemu_bh_delete(uas->status_bh);
-}
-
-static void usb_uas_realize(USBDevice *dev, Error **errp)
-{
- UASDevice *uas = USB_UAS(dev);
-
- usb_desc_create_serial(dev);
- usb_desc_init(dev);
-
- QTAILQ_INIT(&uas->results);
- QTAILQ_INIT(&uas->requests);
- uas->status_bh = qemu_bh_new(usb_uas_send_status_bh, uas);
-
- scsi_bus_new(&uas->bus, sizeof(uas->bus), DEVICE(dev),
- &usb_uas_scsi_info, NULL);
-}
-
-static const VMStateDescription vmstate_usb_uas = {
- .name = "usb-uas",
- .unmigratable = 1,
- .fields = (VMStateField[]) {
- VMSTATE_USB_DEVICE(dev, UASDevice),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property uas_properties[] = {
- DEFINE_PROP_UINT32("log-scsi-req", UASDevice, requestlog, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void usb_uas_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
-
- uc->realize = usb_uas_realize;
- uc->product_desc = desc_strings[STR_PRODUCT];
- uc->usb_desc = &desc;
- uc->cancel_packet = usb_uas_cancel_io;
- uc->handle_attach = usb_desc_attach;
- uc->handle_reset = usb_uas_handle_reset;
- uc->handle_control = usb_uas_handle_control;
- uc->handle_data = usb_uas_handle_data;
- uc->handle_destroy = usb_uas_handle_destroy;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
- dc->fw_name = "storage";
- dc->vmsd = &vmstate_usb_uas;
- dc->props = uas_properties;
-}
-
-static const TypeInfo uas_info = {
- .name = TYPE_USB_UAS,
- .parent = TYPE_USB_DEVICE,
- .instance_size = sizeof(UASDevice),
- .class_init = usb_uas_class_initfn,
-};
-
-static void usb_uas_register_types(void)
-{
- type_register_static(&uas_info);
-}
-
-type_init(usb_uas_register_types)
diff --git a/qemu/hw/usb/dev-wacom.c b/qemu/hw/usb/dev-wacom.c
deleted file mode 100644
index c4702dbba..000000000
--- a/qemu/hw/usb/dev-wacom.c
+++ /dev/null
@@ -1,386 +0,0 @@
-/*
- * Wacom PenPartner USB tablet emulation.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Author: Andrzej Zaborowski <balrog@zabor.org>
- *
- * Based on hw/usb-hid.c:
- * Copyright (c) 2005 Fabrice Bellard
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "ui/console.h"
-#include "hw/usb.h"
-#include "hw/usb/desc.h"
-
-/* Interface requests */
-#define WACOM_GET_REPORT 0x2101
-#define WACOM_SET_REPORT 0x2109
-
-/* HID interface requests */
-#define HID_GET_REPORT 0xa101
-#define HID_GET_IDLE 0xa102
-#define HID_GET_PROTOCOL 0xa103
-#define HID_SET_IDLE 0x210a
-#define HID_SET_PROTOCOL 0x210b
-
-typedef struct USBWacomState {
- USBDevice dev;
- USBEndpoint *intr;
- QEMUPutMouseEntry *eh_entry;
- int dx, dy, dz, buttons_state;
- int x, y;
- int mouse_grabbed;
- enum {
- WACOM_MODE_HID = 1,
- WACOM_MODE_WACOM = 2,
- } mode;
- uint8_t idle;
- int changed;
-} USBWacomState;
-
-#define TYPE_USB_WACOM "usb-wacom-tablet"
-#define USB_WACOM(obj) OBJECT_CHECK(USBWacomState, (obj), TYPE_USB_WACOM)
-
-enum {
- STR_MANUFACTURER = 1,
- STR_PRODUCT,
- STR_SERIALNUMBER,
-};
-
-static const USBDescStrings desc_strings = {
- [STR_MANUFACTURER] = "QEMU",
- [STR_PRODUCT] = "Wacom PenPartner",
- [STR_SERIALNUMBER] = "1",
-};
-
-static const USBDescIface desc_iface_wacom = {
- .bInterfaceNumber = 0,
- .bNumEndpoints = 1,
- .bInterfaceClass = USB_CLASS_HID,
- .bInterfaceSubClass = 0x01, /* boot */
- .bInterfaceProtocol = 0x02,
- .ndesc = 1,
- .descs = (USBDescOther[]) {
- {
- /* HID descriptor */
- .data = (uint8_t[]) {
- 0x09, /* u8 bLength */
- 0x21, /* u8 bDescriptorType */
- 0x01, 0x10, /* u16 HID_class */
- 0x00, /* u8 country_code */
- 0x01, /* u8 num_descriptors */
- 0x22, /* u8 type: Report */
- 0x6e, 0, /* u16 len */
- },
- },
- },
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | 0x01,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = 8,
- .bInterval = 0x0a,
- },
- },
-};
-
-static const USBDescDevice desc_device_wacom = {
- .bcdUSB = 0x0110,
- .bMaxPacketSize0 = 8,
- .bNumConfigurations = 1,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 1,
- .bConfigurationValue = 1,
- .bmAttributes = USB_CFG_ATT_ONE,
- .bMaxPower = 40,
- .nif = 1,
- .ifs = &desc_iface_wacom,
- },
- },
-};
-
-static const USBDesc desc_wacom = {
- .id = {
- .idVendor = 0x056a,
- .idProduct = 0x0000,
- .bcdDevice = 0x4210,
- .iManufacturer = STR_MANUFACTURER,
- .iProduct = STR_PRODUCT,
- .iSerialNumber = STR_SERIALNUMBER,
- },
- .full = &desc_device_wacom,
- .str = desc_strings,
-};
-
-static void usb_mouse_event(void *opaque,
- int dx1, int dy1, int dz1, int buttons_state)
-{
- USBWacomState *s = opaque;
-
- s->dx += dx1;
- s->dy += dy1;
- s->dz += dz1;
- s->buttons_state = buttons_state;
- s->changed = 1;
- usb_wakeup(s->intr, 0);
-}
-
-static void usb_wacom_event(void *opaque,
- int x, int y, int dz, int buttons_state)
-{
- USBWacomState *s = opaque;
-
- /* scale to Penpartner resolution */
- s->x = (x * 5040 / 0x7FFF);
- s->y = (y * 3780 / 0x7FFF);
- s->dz += dz;
- s->buttons_state = buttons_state;
- s->changed = 1;
- usb_wakeup(s->intr, 0);
-}
-
-static inline int int_clamp(int val, int vmin, int vmax)
-{
- if (val < vmin)
- return vmin;
- else if (val > vmax)
- return vmax;
- else
- return val;
-}
-
-static int usb_mouse_poll(USBWacomState *s, uint8_t *buf, int len)
-{
- int dx, dy, dz, b, l;
-
- if (!s->mouse_grabbed) {
- s->eh_entry = qemu_add_mouse_event_handler(usb_mouse_event, s, 0,
- "QEMU PenPartner tablet");
- qemu_activate_mouse_event_handler(s->eh_entry);
- s->mouse_grabbed = 1;
- }
-
- dx = int_clamp(s->dx, -128, 127);
- dy = int_clamp(s->dy, -128, 127);
- dz = int_clamp(s->dz, -128, 127);
-
- s->dx -= dx;
- s->dy -= dy;
- s->dz -= dz;
-
- b = 0;
- if (s->buttons_state & MOUSE_EVENT_LBUTTON)
- b |= 0x01;
- if (s->buttons_state & MOUSE_EVENT_RBUTTON)
- b |= 0x02;
- if (s->buttons_state & MOUSE_EVENT_MBUTTON)
- b |= 0x04;
-
- buf[0] = b;
- buf[1] = dx;
- buf[2] = dy;
- l = 3;
- if (len >= 4) {
- buf[3] = dz;
- l = 4;
- }
- return l;
-}
-
-static int usb_wacom_poll(USBWacomState *s, uint8_t *buf, int len)
-{
- int b;
-
- if (!s->mouse_grabbed) {
- s->eh_entry = qemu_add_mouse_event_handler(usb_wacom_event, s, 1,
- "QEMU PenPartner tablet");
- qemu_activate_mouse_event_handler(s->eh_entry);
- s->mouse_grabbed = 1;
- }
-
- b = 0;
- if (s->buttons_state & MOUSE_EVENT_LBUTTON)
- b |= 0x01;
- if (s->buttons_state & MOUSE_EVENT_RBUTTON)
- b |= 0x40;
- if (s->buttons_state & MOUSE_EVENT_MBUTTON)
- b |= 0x20; /* eraser */
-
- if (len < 7)
- return 0;
-
- buf[0] = s->mode;
- buf[5] = 0x00 | (b & 0xf0);
- buf[1] = s->x & 0xff;
- buf[2] = s->x >> 8;
- buf[3] = s->y & 0xff;
- buf[4] = s->y >> 8;
- if (b & 0x3f) {
- buf[6] = 0;
- } else {
- buf[6] = (unsigned char) -127;
- }
-
- return 7;
-}
-
-static void usb_wacom_handle_reset(USBDevice *dev)
-{
- USBWacomState *s = (USBWacomState *) dev;
-
- s->dx = 0;
- s->dy = 0;
- s->dz = 0;
- s->x = 0;
- s->y = 0;
- s->buttons_state = 0;
- s->mode = WACOM_MODE_HID;
-}
-
-static void usb_wacom_handle_control(USBDevice *dev, USBPacket *p,
- int request, int value, int index, int length, uint8_t *data)
-{
- USBWacomState *s = (USBWacomState *) dev;
- int ret;
-
- ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
- if (ret >= 0) {
- return;
- }
-
- switch (request) {
- case WACOM_SET_REPORT:
- if (s->mouse_grabbed) {
- qemu_remove_mouse_event_handler(s->eh_entry);
- s->mouse_grabbed = 0;
- }
- s->mode = data[0];
- break;
- case WACOM_GET_REPORT:
- data[0] = 0;
- data[1] = s->mode;
- p->actual_length = 2;
- break;
- /* USB HID requests */
- case HID_GET_REPORT:
- if (s->mode == WACOM_MODE_HID)
- p->actual_length = usb_mouse_poll(s, data, length);
- else if (s->mode == WACOM_MODE_WACOM)
- p->actual_length = usb_wacom_poll(s, data, length);
- break;
- case HID_GET_IDLE:
- data[0] = s->idle;
- p->actual_length = 1;
- break;
- case HID_SET_IDLE:
- s->idle = (uint8_t) (value >> 8);
- break;
- default:
- p->status = USB_RET_STALL;
- break;
- }
-}
-
-static void usb_wacom_handle_data(USBDevice *dev, USBPacket *p)
-{
- USBWacomState *s = (USBWacomState *) dev;
- uint8_t buf[p->iov.size];
- int len = 0;
-
- switch (p->pid) {
- case USB_TOKEN_IN:
- if (p->ep->nr == 1) {
- if (!(s->changed || s->idle)) {
- p->status = USB_RET_NAK;
- return;
- }
- s->changed = 0;
- if (s->mode == WACOM_MODE_HID)
- len = usb_mouse_poll(s, buf, p->iov.size);
- else if (s->mode == WACOM_MODE_WACOM)
- len = usb_wacom_poll(s, buf, p->iov.size);
- usb_packet_copy(p, buf, len);
- break;
- }
- /* Fall through. */
- case USB_TOKEN_OUT:
- default:
- p->status = USB_RET_STALL;
- }
-}
-
-static void usb_wacom_handle_destroy(USBDevice *dev)
-{
- USBWacomState *s = (USBWacomState *) dev;
-
- if (s->mouse_grabbed) {
- qemu_remove_mouse_event_handler(s->eh_entry);
- s->mouse_grabbed = 0;
- }
-}
-
-static void usb_wacom_realize(USBDevice *dev, Error **errp)
-{
- USBWacomState *s = USB_WACOM(dev);
- usb_desc_create_serial(dev);
- usb_desc_init(dev);
- s->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
- s->changed = 1;
-}
-
-static const VMStateDescription vmstate_usb_wacom = {
- .name = "usb-wacom",
- .unmigratable = 1,
-};
-
-static void usb_wacom_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
-
- uc->product_desc = "QEMU PenPartner Tablet";
- uc->usb_desc = &desc_wacom;
- uc->realize = usb_wacom_realize;
- uc->handle_reset = usb_wacom_handle_reset;
- uc->handle_control = usb_wacom_handle_control;
- uc->handle_data = usb_wacom_handle_data;
- uc->handle_destroy = usb_wacom_handle_destroy;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
- dc->desc = "QEMU PenPartner Tablet";
- dc->vmsd = &vmstate_usb_wacom;
-}
-
-static const TypeInfo wacom_info = {
- .name = TYPE_USB_WACOM,
- .parent = TYPE_USB_DEVICE,
- .instance_size = sizeof(USBWacomState),
- .class_init = usb_wacom_class_init,
-};
-
-static void usb_wacom_register_types(void)
-{
- type_register_static(&wacom_info);
- usb_legacy_register(TYPE_USB_WACOM, "wacom-tablet", NULL);
-}
-
-type_init(usb_wacom_register_types)
diff --git a/qemu/hw/usb/hcd-ehci-pci.c b/qemu/hw/usb/hcd-ehci-pci.c
deleted file mode 100644
index 56577051e..000000000
--- a/qemu/hw/usb/hcd-ehci-pci.c
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * QEMU USB EHCI Emulation
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or(at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/usb/hcd-ehci.h"
-#include "qemu/range.h"
-
-typedef struct EHCIPCIInfo {
- const char *name;
- uint16_t vendor_id;
- uint16_t device_id;
- uint8_t revision;
- bool companion;
-} EHCIPCIInfo;
-
-static void usb_ehci_pci_realize(PCIDevice *dev, Error **errp)
-{
- EHCIPCIState *i = PCI_EHCI(dev);
- EHCIState *s = &i->ehci;
- uint8_t *pci_conf = dev->config;
-
- pci_set_byte(&pci_conf[PCI_CLASS_PROG], 0x20);
-
- /* capabilities pointer */
- pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x00);
- /* pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x50); */
-
- pci_set_byte(&pci_conf[PCI_INTERRUPT_PIN], 4); /* interrupt pin D */
- pci_set_byte(&pci_conf[PCI_MIN_GNT], 0);
- pci_set_byte(&pci_conf[PCI_MAX_LAT], 0);
-
- /* pci_conf[0x50] = 0x01; *//* power management caps */
-
- pci_set_byte(&pci_conf[USB_SBRN], USB_RELEASE_2); /* release # (2.1.4) */
- pci_set_byte(&pci_conf[0x61], 0x20); /* frame length adjustment (2.1.5) */
- pci_set_word(&pci_conf[0x62], 0x00); /* port wake up capability (2.1.6) */
-
- pci_conf[0x64] = 0x00;
- pci_conf[0x65] = 0x00;
- pci_conf[0x66] = 0x00;
- pci_conf[0x67] = 0x00;
- pci_conf[0x68] = 0x01;
- pci_conf[0x69] = 0x00;
- pci_conf[0x6a] = 0x00;
- pci_conf[0x6b] = 0x00; /* USBLEGSUP */
- pci_conf[0x6c] = 0x00;
- pci_conf[0x6d] = 0x00;
- pci_conf[0x6e] = 0x00;
- pci_conf[0x6f] = 0xc0; /* USBLEFCTLSTS */
-
- s->irq = pci_allocate_irq(dev);
- s->as = pci_get_address_space(dev);
-
- usb_ehci_realize(s, DEVICE(dev), NULL);
- pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem);
-}
-
-static void usb_ehci_pci_init(Object *obj)
-{
- DeviceClass *dc = OBJECT_GET_CLASS(DeviceClass, obj, TYPE_DEVICE);
- EHCIPCIState *i = PCI_EHCI(obj);
- EHCIState *s = &i->ehci;
-
- s->caps[0x09] = 0x68; /* EECP */
-
- s->capsbase = 0x00;
- s->opregbase = 0x20;
- s->portscbase = 0x44;
- s->portnr = NB_PORTS;
-
- if (!dc->hotpluggable) {
- s->companion_enable = true;
- }
-
- usb_ehci_init(s, DEVICE(obj));
-}
-
-static void usb_ehci_pci_exit(PCIDevice *dev)
-{
- EHCIPCIState *i = PCI_EHCI(dev);
- EHCIState *s = &i->ehci;
-
- usb_ehci_unrealize(s, DEVICE(dev), NULL);
-
- g_free(s->irq);
- s->irq = NULL;
-}
-
-static void usb_ehci_pci_reset(DeviceState *dev)
-{
- PCIDevice *pci_dev = PCI_DEVICE(dev);
- EHCIPCIState *i = PCI_EHCI(pci_dev);
- EHCIState *s = &i->ehci;
-
- ehci_reset(s);
-}
-
-static void usb_ehci_pci_write_config(PCIDevice *dev, uint32_t addr,
- uint32_t val, int l)
-{
- EHCIPCIState *i = PCI_EHCI(dev);
- bool busmaster;
-
- pci_default_write_config(dev, addr, val, l);
-
- if (!range_covers_byte(addr, l, PCI_COMMAND)) {
- return;
- }
- busmaster = pci_get_word(dev->config + PCI_COMMAND) & PCI_COMMAND_MASTER;
- i->ehci.as = busmaster ? pci_get_address_space(dev) : &address_space_memory;
-}
-
-static Property ehci_pci_properties[] = {
- DEFINE_PROP_UINT32("maxframes", EHCIPCIState, ehci.maxframes, 128),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static const VMStateDescription vmstate_ehci_pci = {
- .name = "ehci",
- .version_id = 2,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(pcidev, EHCIPCIState),
- VMSTATE_STRUCT(ehci, EHCIPCIState, 2, vmstate_ehci, EHCIState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void ehci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = usb_ehci_pci_realize;
- k->exit = usb_ehci_pci_exit;
- k->class_id = PCI_CLASS_SERIAL_USB;
- k->config_write = usb_ehci_pci_write_config;
- dc->vmsd = &vmstate_ehci_pci;
- dc->props = ehci_pci_properties;
- dc->reset = usb_ehci_pci_reset;
-}
-
-static const TypeInfo ehci_pci_type_info = {
- .name = TYPE_PCI_EHCI,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(EHCIPCIState),
- .instance_init = usb_ehci_pci_init,
- .abstract = true,
- .class_init = ehci_class_init,
-};
-
-static void ehci_data_class_init(ObjectClass *klass, void *data)
-{
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
- EHCIPCIInfo *i = data;
-
- k->vendor_id = i->vendor_id;
- k->device_id = i->device_id;
- k->revision = i->revision;
- set_bit(DEVICE_CATEGORY_USB, dc->categories);
- if (i->companion) {
- dc->hotpluggable = false;
- }
-}
-
-static struct EHCIPCIInfo ehci_pci_info[] = {
- {
- .name = "usb-ehci",
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82801D, /* ich4 */
- .revision = 0x10,
- },{
- .name = "ich9-usb-ehci1", /* 00:1d.7 */
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82801I_EHCI1,
- .revision = 0x03,
- .companion = true,
- },{
- .name = "ich9-usb-ehci2", /* 00:1a.7 */
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82801I_EHCI2,
- .revision = 0x03,
- .companion = true,
- }
-};
-
-static void ehci_pci_register_types(void)
-{
- TypeInfo ehci_type_info = {
- .parent = TYPE_PCI_EHCI,
- .class_init = ehci_data_class_init,
- };
- int i;
-
- type_register_static(&ehci_pci_type_info);
-
- for (i = 0; i < ARRAY_SIZE(ehci_pci_info); i++) {
- ehci_type_info.name = ehci_pci_info[i].name;
- ehci_type_info.class_data = ehci_pci_info + i;
- type_register(&ehci_type_info);
- }
-}
-
-type_init(ehci_pci_register_types)
-
-struct ehci_companions {
- const char *name;
- int func;
- int port;
-};
-
-static const struct ehci_companions ich9_1d[] = {
- { .name = "ich9-usb-uhci1", .func = 0, .port = 0 },
- { .name = "ich9-usb-uhci2", .func = 1, .port = 2 },
- { .name = "ich9-usb-uhci3", .func = 2, .port = 4 },
-};
-
-static const struct ehci_companions ich9_1a[] = {
- { .name = "ich9-usb-uhci4", .func = 0, .port = 0 },
- { .name = "ich9-usb-uhci5", .func = 1, .port = 2 },
- { .name = "ich9-usb-uhci6", .func = 2, .port = 4 },
-};
-
-int ehci_create_ich9_with_companions(PCIBus *bus, int slot)
-{
- const struct ehci_companions *comp;
- PCIDevice *ehci, *uhci;
- BusState *usbbus;
- const char *name;
- int i;
-
- switch (slot) {
- case 0x1d:
- name = "ich9-usb-ehci1";
- comp = ich9_1d;
- break;
- case 0x1a:
- name = "ich9-usb-ehci2";
- comp = ich9_1a;
- break;
- default:
- return -1;
- }
-
- ehci = pci_create_multifunction(bus, PCI_DEVFN(slot, 7), true, name);
- qdev_init_nofail(&ehci->qdev);
- usbbus = QLIST_FIRST(&ehci->qdev.child_bus);
-
- for (i = 0; i < 3; i++) {
- uhci = pci_create_multifunction(bus, PCI_DEVFN(slot, comp[i].func),
- true, comp[i].name);
- qdev_prop_set_string(&uhci->qdev, "masterbus", usbbus->name);
- qdev_prop_set_uint32(&uhci->qdev, "firstport", comp[i].port);
- qdev_init_nofail(&uhci->qdev);
- }
- return 0;
-}
diff --git a/qemu/hw/usb/hcd-ehci-sysbus.c b/qemu/hw/usb/hcd-ehci-sysbus.c
deleted file mode 100644
index 6c20604d0..000000000
--- a/qemu/hw/usb/hcd-ehci-sysbus.c
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * QEMU USB EHCI Emulation
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or(at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/usb/hcd-ehci.h"
-
-static const VMStateDescription vmstate_ehci_sysbus = {
- .name = "ehci-sysbus",
- .version_id = 2,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT(ehci, EHCISysBusState, 2, vmstate_ehci, EHCIState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property ehci_sysbus_properties[] = {
- DEFINE_PROP_UINT32("maxframes", EHCISysBusState, ehci.maxframes, 128),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void usb_ehci_sysbus_realize(DeviceState *dev, Error **errp)
-{
- SysBusDevice *d = SYS_BUS_DEVICE(dev);
- EHCISysBusState *i = SYS_BUS_EHCI(dev);
- EHCIState *s = &i->ehci;
-
- usb_ehci_realize(s, dev, errp);
- sysbus_init_irq(d, &s->irq);
-}
-
-static void usb_ehci_sysbus_reset(DeviceState *dev)
-{
- SysBusDevice *d = SYS_BUS_DEVICE(dev);
- EHCISysBusState *i = SYS_BUS_EHCI(d);
- EHCIState *s = &i->ehci;
-
- ehci_reset(s);
-}
-
-static void ehci_sysbus_init(Object *obj)
-{
- SysBusDevice *d = SYS_BUS_DEVICE(obj);
- EHCISysBusState *i = SYS_BUS_EHCI(obj);
- SysBusEHCIClass *sec = SYS_BUS_EHCI_GET_CLASS(obj);
- EHCIState *s = &i->ehci;
-
- s->capsbase = sec->capsbase;
- s->opregbase = sec->opregbase;
- s->portscbase = sec->portscbase;
- s->portnr = sec->portnr;
- s->as = &address_space_memory;
-
- usb_ehci_init(s, DEVICE(obj));
- sysbus_init_mmio(d, &s->mem);
-}
-
-static void ehci_sysbus_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(klass);
-
- sec->portscbase = 0x44;
- sec->portnr = NB_PORTS;
-
- dc->realize = usb_ehci_sysbus_realize;
- dc->vmsd = &vmstate_ehci_sysbus;
- dc->props = ehci_sysbus_properties;
- dc->reset = usb_ehci_sysbus_reset;
- set_bit(DEVICE_CATEGORY_USB, dc->categories);
-}
-
-static const TypeInfo ehci_type_info = {
- .name = TYPE_SYS_BUS_EHCI,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(EHCISysBusState),
- .instance_init = ehci_sysbus_init,
- .abstract = true,
- .class_init = ehci_sysbus_class_init,
- .class_size = sizeof(SysBusEHCIClass),
-};
-
-static void ehci_xlnx_class_init(ObjectClass *oc, void *data)
-{
- SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- set_bit(DEVICE_CATEGORY_USB, dc->categories);
- sec->capsbase = 0x100;
- sec->opregbase = 0x140;
-}
-
-static const TypeInfo ehci_xlnx_type_info = {
- .name = "xlnx,ps7-usb",
- .parent = TYPE_SYS_BUS_EHCI,
- .class_init = ehci_xlnx_class_init,
-};
-
-static void ehci_exynos4210_class_init(ObjectClass *oc, void *data)
-{
- SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- sec->capsbase = 0x0;
- sec->opregbase = 0x10;
- set_bit(DEVICE_CATEGORY_USB, dc->categories);
-}
-
-static const TypeInfo ehci_exynos4210_type_info = {
- .name = TYPE_EXYNOS4210_EHCI,
- .parent = TYPE_SYS_BUS_EHCI,
- .class_init = ehci_exynos4210_class_init,
-};
-
-static void ehci_tegra2_class_init(ObjectClass *oc, void *data)
-{
- SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- sec->capsbase = 0x100;
- sec->opregbase = 0x140;
- set_bit(DEVICE_CATEGORY_USB, dc->categories);
-}
-
-static const TypeInfo ehci_tegra2_type_info = {
- .name = TYPE_TEGRA2_EHCI,
- .parent = TYPE_SYS_BUS_EHCI,
- .class_init = ehci_tegra2_class_init,
-};
-
-/*
- * Faraday FUSBH200 USB 2.0 EHCI
- */
-
-/**
- * FUSBH200EHCIRegs:
- * @FUSBH200_REG_EOF_ASTR: EOF/Async. Sleep Timer Register
- * @FUSBH200_REG_BMCSR: Bus Monitor Control/Status Register
- */
-enum FUSBH200EHCIRegs {
- FUSBH200_REG_EOF_ASTR = 0x34,
- FUSBH200_REG_BMCSR = 0x40,
-};
-
-static uint64_t fusbh200_ehci_read(void *opaque, hwaddr addr, unsigned size)
-{
- EHCIState *s = opaque;
- hwaddr off = s->opregbase + s->portscbase + 4 * s->portnr + addr;
-
- switch (off) {
- case FUSBH200_REG_EOF_ASTR:
- return 0x00000041;
- case FUSBH200_REG_BMCSR:
- /* High-Speed, VBUS valid, interrupt level-high active */
- return (2 << 9) | (1 << 8) | (1 << 3);
- }
-
- return 0;
-}
-
-static void fusbh200_ehci_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned size)
-{
-}
-
-static const MemoryRegionOps fusbh200_ehci_mmio_ops = {
- .read = fusbh200_ehci_read,
- .write = fusbh200_ehci_write,
- .valid.min_access_size = 4,
- .valid.max_access_size = 4,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void fusbh200_ehci_init(Object *obj)
-{
- EHCISysBusState *i = SYS_BUS_EHCI(obj);
- FUSBH200EHCIState *f = FUSBH200_EHCI(obj);
- EHCIState *s = &i->ehci;
-
- memory_region_init_io(&f->mem_vendor, OBJECT(f), &fusbh200_ehci_mmio_ops, s,
- "fusbh200", 0x4c);
- memory_region_add_subregion(&s->mem,
- s->opregbase + s->portscbase + 4 * s->portnr,
- &f->mem_vendor);
-}
-
-static void fusbh200_ehci_class_init(ObjectClass *oc, void *data)
-{
- SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- sec->capsbase = 0x0;
- sec->opregbase = 0x10;
- sec->portscbase = 0x20;
- sec->portnr = 1;
- set_bit(DEVICE_CATEGORY_USB, dc->categories);
-}
-
-static const TypeInfo ehci_fusbh200_type_info = {
- .name = TYPE_FUSBH200_EHCI,
- .parent = TYPE_SYS_BUS_EHCI,
- .instance_size = sizeof(FUSBH200EHCIState),
- .instance_init = fusbh200_ehci_init,
- .class_init = fusbh200_ehci_class_init,
-};
-
-static void ehci_sysbus_register_types(void)
-{
- type_register_static(&ehci_type_info);
- type_register_static(&ehci_xlnx_type_info);
- type_register_static(&ehci_exynos4210_type_info);
- type_register_static(&ehci_tegra2_type_info);
- type_register_static(&ehci_fusbh200_type_info);
-}
-
-type_init(ehci_sysbus_register_types)
diff --git a/qemu/hw/usb/hcd-ehci.c b/qemu/hw/usb/hcd-ehci.c
deleted file mode 100644
index 43a8f7abc..000000000
--- a/qemu/hw/usb/hcd-ehci.c
+++ /dev/null
@@ -1,2549 +0,0 @@
-/*
- * QEMU USB EHCI Emulation
- *
- * Copyright(c) 2008 Emutex Ltd. (address@hidden)
- * Copyright(c) 2011-2012 Red Hat, Inc.
- *
- * Red Hat Authors:
- * Gerd Hoffmann <kraxel@redhat.com>
- * Hans de Goede <hdegoede@redhat.com>
- *
- * EHCI project was started by Mark Burkley, with contributions by
- * Niels de Vos. David S. Ahern continued working on it. Kevin Wolf,
- * Jan Kiszka and Vincent Palatin contributed bugfixes.
- *
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or(at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/usb/ehci-regs.h"
-#include "hw/usb/hcd-ehci.h"
-#include "trace.h"
-
-#define FRAME_TIMER_FREQ 1000
-#define FRAME_TIMER_NS (NANOSECONDS_PER_SECOND / FRAME_TIMER_FREQ)
-#define UFRAME_TIMER_NS (FRAME_TIMER_NS / 8)
-
-#define NB_MAXINTRATE 8 // Max rate at which controller issues ints
-#define BUFF_SIZE 5*4096 // Max bytes to transfer per transaction
-#define MAX_QH 100 // Max allowable queue heads in a chain
-#define MIN_UFR_PER_TICK 24 /* Min frames to process when catching up */
-#define PERIODIC_ACTIVE 512 /* Micro-frames */
-
-/* Internal periodic / asynchronous schedule state machine states
- */
-typedef enum {
- EST_INACTIVE = 1000,
- EST_ACTIVE,
- EST_EXECUTING,
- EST_SLEEPING,
- /* The following states are internal to the state machine function
- */
- EST_WAITLISTHEAD,
- EST_FETCHENTRY,
- EST_FETCHQH,
- EST_FETCHITD,
- EST_FETCHSITD,
- EST_ADVANCEQUEUE,
- EST_FETCHQTD,
- EST_EXECUTE,
- EST_WRITEBACK,
- EST_HORIZONTALQH
-} EHCI_STATES;
-
-/* macros for accessing fields within next link pointer entry */
-#define NLPTR_GET(x) ((x) & 0xffffffe0)
-#define NLPTR_TYPE_GET(x) (((x) >> 1) & 3)
-#define NLPTR_TBIT(x) ((x) & 1) // 1=invalid, 0=valid
-
-/* link pointer types */
-#define NLPTR_TYPE_ITD 0 // isoc xfer descriptor
-#define NLPTR_TYPE_QH 1 // queue head
-#define NLPTR_TYPE_STITD 2 // split xaction, isoc xfer descriptor
-#define NLPTR_TYPE_FSTN 3 // frame span traversal node
-
-#define SET_LAST_RUN_CLOCK(s) \
- (s)->last_run_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-
-/* nifty macros from Arnon's EHCI version */
-#define get_field(data, field) \
- (((data) & field##_MASK) >> field##_SH)
-
-#define set_field(data, newval, field) do { \
- uint32_t val = *data; \
- val &= ~ field##_MASK; \
- val |= ((newval) << field##_SH) & field##_MASK; \
- *data = val; \
- } while(0)
-
-static const char *ehci_state_names[] = {
- [EST_INACTIVE] = "INACTIVE",
- [EST_ACTIVE] = "ACTIVE",
- [EST_EXECUTING] = "EXECUTING",
- [EST_SLEEPING] = "SLEEPING",
- [EST_WAITLISTHEAD] = "WAITLISTHEAD",
- [EST_FETCHENTRY] = "FETCH ENTRY",
- [EST_FETCHQH] = "FETCH QH",
- [EST_FETCHITD] = "FETCH ITD",
- [EST_ADVANCEQUEUE] = "ADVANCEQUEUE",
- [EST_FETCHQTD] = "FETCH QTD",
- [EST_EXECUTE] = "EXECUTE",
- [EST_WRITEBACK] = "WRITEBACK",
- [EST_HORIZONTALQH] = "HORIZONTALQH",
-};
-
-static const char *ehci_mmio_names[] = {
- [USBCMD] = "USBCMD",
- [USBSTS] = "USBSTS",
- [USBINTR] = "USBINTR",
- [FRINDEX] = "FRINDEX",
- [PERIODICLISTBASE] = "P-LIST BASE",
- [ASYNCLISTADDR] = "A-LIST ADDR",
- [CONFIGFLAG] = "CONFIGFLAG",
-};
-
-static int ehci_state_executing(EHCIQueue *q);
-static int ehci_state_writeback(EHCIQueue *q);
-static int ehci_state_advqueue(EHCIQueue *q);
-static int ehci_fill_queue(EHCIPacket *p);
-static void ehci_free_packet(EHCIPacket *p);
-
-static const char *nr2str(const char **n, size_t len, uint32_t nr)
-{
- if (nr < len && n[nr] != NULL) {
- return n[nr];
- } else {
- return "unknown";
- }
-}
-
-static const char *state2str(uint32_t state)
-{
- return nr2str(ehci_state_names, ARRAY_SIZE(ehci_state_names), state);
-}
-
-static const char *addr2str(hwaddr addr)
-{
- return nr2str(ehci_mmio_names, ARRAY_SIZE(ehci_mmio_names), addr);
-}
-
-static void ehci_trace_usbsts(uint32_t mask, int state)
-{
- /* interrupts */
- if (mask & USBSTS_INT) {
- trace_usb_ehci_usbsts("INT", state);
- }
- if (mask & USBSTS_ERRINT) {
- trace_usb_ehci_usbsts("ERRINT", state);
- }
- if (mask & USBSTS_PCD) {
- trace_usb_ehci_usbsts("PCD", state);
- }
- if (mask & USBSTS_FLR) {
- trace_usb_ehci_usbsts("FLR", state);
- }
- if (mask & USBSTS_HSE) {
- trace_usb_ehci_usbsts("HSE", state);
- }
- if (mask & USBSTS_IAA) {
- trace_usb_ehci_usbsts("IAA", state);
- }
-
- /* status */
- if (mask & USBSTS_HALT) {
- trace_usb_ehci_usbsts("HALT", state);
- }
- if (mask & USBSTS_REC) {
- trace_usb_ehci_usbsts("REC", state);
- }
- if (mask & USBSTS_PSS) {
- trace_usb_ehci_usbsts("PSS", state);
- }
- if (mask & USBSTS_ASS) {
- trace_usb_ehci_usbsts("ASS", state);
- }
-}
-
-static inline void ehci_set_usbsts(EHCIState *s, int mask)
-{
- if ((s->usbsts & mask) == mask) {
- return;
- }
- ehci_trace_usbsts(mask, 1);
- s->usbsts |= mask;
-}
-
-static inline void ehci_clear_usbsts(EHCIState *s, int mask)
-{
- if ((s->usbsts & mask) == 0) {
- return;
- }
- ehci_trace_usbsts(mask, 0);
- s->usbsts &= ~mask;
-}
-
-/* update irq line */
-static inline void ehci_update_irq(EHCIState *s)
-{
- int level = 0;
-
- if ((s->usbsts & USBINTR_MASK) & s->usbintr) {
- level = 1;
- }
-
- trace_usb_ehci_irq(level, s->frindex, s->usbsts, s->usbintr);
- qemu_set_irq(s->irq, level);
-}
-
-/* flag interrupt condition */
-static inline void ehci_raise_irq(EHCIState *s, int intr)
-{
- if (intr & (USBSTS_PCD | USBSTS_FLR | USBSTS_HSE)) {
- s->usbsts |= intr;
- ehci_update_irq(s);
- } else {
- s->usbsts_pending |= intr;
- }
-}
-
-/*
- * Commit pending interrupts (added via ehci_raise_irq),
- * at the rate allowed by "Interrupt Threshold Control".
- */
-static inline void ehci_commit_irq(EHCIState *s)
-{
- uint32_t itc;
-
- if (!s->usbsts_pending) {
- return;
- }
- if (s->usbsts_frindex > s->frindex) {
- return;
- }
-
- itc = (s->usbcmd >> 16) & 0xff;
- s->usbsts |= s->usbsts_pending;
- s->usbsts_pending = 0;
- s->usbsts_frindex = s->frindex + itc;
- ehci_update_irq(s);
-}
-
-static void ehci_update_halt(EHCIState *s)
-{
- if (s->usbcmd & USBCMD_RUNSTOP) {
- ehci_clear_usbsts(s, USBSTS_HALT);
- } else {
- if (s->astate == EST_INACTIVE && s->pstate == EST_INACTIVE) {
- ehci_set_usbsts(s, USBSTS_HALT);
- }
- }
-}
-
-static void ehci_set_state(EHCIState *s, int async, int state)
-{
- if (async) {
- trace_usb_ehci_state("async", state2str(state));
- s->astate = state;
- if (s->astate == EST_INACTIVE) {
- ehci_clear_usbsts(s, USBSTS_ASS);
- ehci_update_halt(s);
- } else {
- ehci_set_usbsts(s, USBSTS_ASS);
- }
- } else {
- trace_usb_ehci_state("periodic", state2str(state));
- s->pstate = state;
- if (s->pstate == EST_INACTIVE) {
- ehci_clear_usbsts(s, USBSTS_PSS);
- ehci_update_halt(s);
- } else {
- ehci_set_usbsts(s, USBSTS_PSS);
- }
- }
-}
-
-static int ehci_get_state(EHCIState *s, int async)
-{
- return async ? s->astate : s->pstate;
-}
-
-static void ehci_set_fetch_addr(EHCIState *s, int async, uint32_t addr)
-{
- if (async) {
- s->a_fetch_addr = addr;
- } else {
- s->p_fetch_addr = addr;
- }
-}
-
-static int ehci_get_fetch_addr(EHCIState *s, int async)
-{
- return async ? s->a_fetch_addr : s->p_fetch_addr;
-}
-
-static void ehci_trace_qh(EHCIQueue *q, hwaddr addr, EHCIqh *qh)
-{
- /* need three here due to argument count limits */
- trace_usb_ehci_qh_ptrs(q, addr, qh->next,
- qh->current_qtd, qh->next_qtd, qh->altnext_qtd);
- trace_usb_ehci_qh_fields(addr,
- get_field(qh->epchar, QH_EPCHAR_RL),
- get_field(qh->epchar, QH_EPCHAR_MPLEN),
- get_field(qh->epchar, QH_EPCHAR_EPS),
- get_field(qh->epchar, QH_EPCHAR_EP),
- get_field(qh->epchar, QH_EPCHAR_DEVADDR));
- trace_usb_ehci_qh_bits(addr,
- (bool)(qh->epchar & QH_EPCHAR_C),
- (bool)(qh->epchar & QH_EPCHAR_H),
- (bool)(qh->epchar & QH_EPCHAR_DTC),
- (bool)(qh->epchar & QH_EPCHAR_I));
-}
-
-static void ehci_trace_qtd(EHCIQueue *q, hwaddr addr, EHCIqtd *qtd)
-{
- /* need three here due to argument count limits */
- trace_usb_ehci_qtd_ptrs(q, addr, qtd->next, qtd->altnext);
- trace_usb_ehci_qtd_fields(addr,
- get_field(qtd->token, QTD_TOKEN_TBYTES),
- get_field(qtd->token, QTD_TOKEN_CPAGE),
- get_field(qtd->token, QTD_TOKEN_CERR),
- get_field(qtd->token, QTD_TOKEN_PID));
- trace_usb_ehci_qtd_bits(addr,
- (bool)(qtd->token & QTD_TOKEN_IOC),
- (bool)(qtd->token & QTD_TOKEN_ACTIVE),
- (bool)(qtd->token & QTD_TOKEN_HALT),
- (bool)(qtd->token & QTD_TOKEN_BABBLE),
- (bool)(qtd->token & QTD_TOKEN_XACTERR));
-}
-
-static void ehci_trace_itd(EHCIState *s, hwaddr addr, EHCIitd *itd)
-{
- trace_usb_ehci_itd(addr, itd->next,
- get_field(itd->bufptr[1], ITD_BUFPTR_MAXPKT),
- get_field(itd->bufptr[2], ITD_BUFPTR_MULT),
- get_field(itd->bufptr[0], ITD_BUFPTR_EP),
- get_field(itd->bufptr[0], ITD_BUFPTR_DEVADDR));
-}
-
-static void ehci_trace_sitd(EHCIState *s, hwaddr addr,
- EHCIsitd *sitd)
-{
- trace_usb_ehci_sitd(addr, sitd->next,
- (bool)(sitd->results & SITD_RESULTS_ACTIVE));
-}
-
-static void ehci_trace_guest_bug(EHCIState *s, const char *message)
-{
- trace_usb_ehci_guest_bug(message);
- fprintf(stderr, "ehci warning: %s\n", message);
-}
-
-static inline bool ehci_enabled(EHCIState *s)
-{
- return s->usbcmd & USBCMD_RUNSTOP;
-}
-
-static inline bool ehci_async_enabled(EHCIState *s)
-{
- return ehci_enabled(s) && (s->usbcmd & USBCMD_ASE);
-}
-
-static inline bool ehci_periodic_enabled(EHCIState *s)
-{
- return ehci_enabled(s) && (s->usbcmd & USBCMD_PSE);
-}
-
-/* Get an array of dwords from main memory */
-static inline int get_dwords(EHCIState *ehci, uint32_t addr,
- uint32_t *buf, int num)
-{
- int i;
-
- if (!ehci->as) {
- ehci_raise_irq(ehci, USBSTS_HSE);
- ehci->usbcmd &= ~USBCMD_RUNSTOP;
- trace_usb_ehci_dma_error();
- return -1;
- }
-
- for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
- dma_memory_read(ehci->as, addr, buf, sizeof(*buf));
- *buf = le32_to_cpu(*buf);
- }
-
- return num;
-}
-
-/* Put an array of dwords in to main memory */
-static inline int put_dwords(EHCIState *ehci, uint32_t addr,
- uint32_t *buf, int num)
-{
- int i;
-
- if (!ehci->as) {
- ehci_raise_irq(ehci, USBSTS_HSE);
- ehci->usbcmd &= ~USBCMD_RUNSTOP;
- trace_usb_ehci_dma_error();
- return -1;
- }
-
- for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
- uint32_t tmp = cpu_to_le32(*buf);
- dma_memory_write(ehci->as, addr, &tmp, sizeof(tmp));
- }
-
- return num;
-}
-
-static int ehci_get_pid(EHCIqtd *qtd)
-{
- switch (get_field(qtd->token, QTD_TOKEN_PID)) {
- case 0:
- return USB_TOKEN_OUT;
- case 1:
- return USB_TOKEN_IN;
- case 2:
- return USB_TOKEN_SETUP;
- default:
- fprintf(stderr, "bad token\n");
- return 0;
- }
-}
-
-static bool ehci_verify_qh(EHCIQueue *q, EHCIqh *qh)
-{
- uint32_t devaddr = get_field(qh->epchar, QH_EPCHAR_DEVADDR);
- uint32_t endp = get_field(qh->epchar, QH_EPCHAR_EP);
- if ((devaddr != get_field(q->qh.epchar, QH_EPCHAR_DEVADDR)) ||
- (endp != get_field(q->qh.epchar, QH_EPCHAR_EP)) ||
- (qh->current_qtd != q->qh.current_qtd) ||
- (q->async && qh->next_qtd != q->qh.next_qtd) ||
- (memcmp(&qh->altnext_qtd, &q->qh.altnext_qtd,
- 7 * sizeof(uint32_t)) != 0) ||
- (q->dev != NULL && q->dev->addr != devaddr)) {
- return false;
- } else {
- return true;
- }
-}
-
-static bool ehci_verify_qtd(EHCIPacket *p, EHCIqtd *qtd)
-{
- if (p->qtdaddr != p->queue->qtdaddr ||
- (p->queue->async && !NLPTR_TBIT(p->qtd.next) &&
- (p->qtd.next != qtd->next)) ||
- (!NLPTR_TBIT(p->qtd.altnext) && (p->qtd.altnext != qtd->altnext)) ||
- p->qtd.token != qtd->token ||
- p->qtd.bufptr[0] != qtd->bufptr[0]) {
- return false;
- } else {
- return true;
- }
-}
-
-static bool ehci_verify_pid(EHCIQueue *q, EHCIqtd *qtd)
-{
- int ep = get_field(q->qh.epchar, QH_EPCHAR_EP);
- int pid = ehci_get_pid(qtd);
-
- /* Note the pid changing is normal for ep 0 (the control ep) */
- if (q->last_pid && ep != 0 && pid != q->last_pid) {
- return false;
- } else {
- return true;
- }
-}
-
-/* Finish executing and writeback a packet outside of the regular
- fetchqh -> fetchqtd -> execute -> writeback cycle */
-static void ehci_writeback_async_complete_packet(EHCIPacket *p)
-{
- EHCIQueue *q = p->queue;
- EHCIqtd qtd;
- EHCIqh qh;
- int state;
-
- /* Verify the qh + qtd, like we do when going through fetchqh & fetchqtd */
- get_dwords(q->ehci, NLPTR_GET(q->qhaddr),
- (uint32_t *) &qh, sizeof(EHCIqh) >> 2);
- get_dwords(q->ehci, NLPTR_GET(q->qtdaddr),
- (uint32_t *) &qtd, sizeof(EHCIqtd) >> 2);
- if (!ehci_verify_qh(q, &qh) || !ehci_verify_qtd(p, &qtd)) {
- p->async = EHCI_ASYNC_INITIALIZED;
- ehci_free_packet(p);
- return;
- }
-
- state = ehci_get_state(q->ehci, q->async);
- ehci_state_executing(q);
- ehci_state_writeback(q); /* Frees the packet! */
- if (!(q->qh.token & QTD_TOKEN_HALT)) {
- ehci_state_advqueue(q);
- }
- ehci_set_state(q->ehci, q->async, state);
-}
-
-/* packet management */
-
-static EHCIPacket *ehci_alloc_packet(EHCIQueue *q)
-{
- EHCIPacket *p;
-
- p = g_new0(EHCIPacket, 1);
- p->queue = q;
- usb_packet_init(&p->packet);
- QTAILQ_INSERT_TAIL(&q->packets, p, next);
- trace_usb_ehci_packet_action(p->queue, p, "alloc");
- return p;
-}
-
-static void ehci_free_packet(EHCIPacket *p)
-{
- if (p->async == EHCI_ASYNC_FINISHED &&
- !(p->queue->qh.token & QTD_TOKEN_HALT)) {
- ehci_writeback_async_complete_packet(p);
- return;
- }
- trace_usb_ehci_packet_action(p->queue, p, "free");
- if (p->async == EHCI_ASYNC_INFLIGHT) {
- usb_cancel_packet(&p->packet);
- }
- if (p->async == EHCI_ASYNC_FINISHED &&
- p->packet.status == USB_RET_SUCCESS) {
- fprintf(stderr,
- "EHCI: Dropping completed packet from halted %s ep %02X\n",
- (p->pid == USB_TOKEN_IN) ? "in" : "out",
- get_field(p->queue->qh.epchar, QH_EPCHAR_EP));
- }
- if (p->async != EHCI_ASYNC_NONE) {
- usb_packet_unmap(&p->packet, &p->sgl);
- qemu_sglist_destroy(&p->sgl);
- }
- QTAILQ_REMOVE(&p->queue->packets, p, next);
- usb_packet_cleanup(&p->packet);
- g_free(p);
-}
-
-/* queue management */
-
-static EHCIQueue *ehci_alloc_queue(EHCIState *ehci, uint32_t addr, int async)
-{
- EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
- EHCIQueue *q;
-
- q = g_malloc0(sizeof(*q));
- q->ehci = ehci;
- q->qhaddr = addr;
- q->async = async;
- QTAILQ_INIT(&q->packets);
- QTAILQ_INSERT_HEAD(head, q, next);
- trace_usb_ehci_queue_action(q, "alloc");
- return q;
-}
-
-static void ehci_queue_stopped(EHCIQueue *q)
-{
- int endp = get_field(q->qh.epchar, QH_EPCHAR_EP);
-
- if (!q->last_pid || !q->dev) {
- return;
- }
-
- usb_device_ep_stopped(q->dev, usb_ep_get(q->dev, q->last_pid, endp));
-}
-
-static int ehci_cancel_queue(EHCIQueue *q)
-{
- EHCIPacket *p;
- int packets = 0;
-
- p = QTAILQ_FIRST(&q->packets);
- if (p == NULL) {
- goto leave;
- }
-
- trace_usb_ehci_queue_action(q, "cancel");
- do {
- ehci_free_packet(p);
- packets++;
- } while ((p = QTAILQ_FIRST(&q->packets)) != NULL);
-
-leave:
- ehci_queue_stopped(q);
- return packets;
-}
-
-static int ehci_reset_queue(EHCIQueue *q)
-{
- int packets;
-
- trace_usb_ehci_queue_action(q, "reset");
- packets = ehci_cancel_queue(q);
- q->dev = NULL;
- q->qtdaddr = 0;
- q->last_pid = 0;
- return packets;
-}
-
-static void ehci_free_queue(EHCIQueue *q, const char *warn)
-{
- EHCIQueueHead *head = q->async ? &q->ehci->aqueues : &q->ehci->pqueues;
- int cancelled;
-
- trace_usb_ehci_queue_action(q, "free");
- cancelled = ehci_cancel_queue(q);
- if (warn && cancelled > 0) {
- ehci_trace_guest_bug(q->ehci, warn);
- }
- QTAILQ_REMOVE(head, q, next);
- g_free(q);
-}
-
-static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr,
- int async)
-{
- EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
- EHCIQueue *q;
-
- QTAILQ_FOREACH(q, head, next) {
- if (addr == q->qhaddr) {
- return q;
- }
- }
- return NULL;
-}
-
-static void ehci_queues_rip_unused(EHCIState *ehci, int async)
-{
- EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
- const char *warn = async ? "guest unlinked busy QH" : NULL;
- uint64_t maxage = FRAME_TIMER_NS * ehci->maxframes * 4;
- EHCIQueue *q, *tmp;
-
- QTAILQ_FOREACH_SAFE(q, head, next, tmp) {
- if (q->seen) {
- q->seen = 0;
- q->ts = ehci->last_run_ns;
- continue;
- }
- if (ehci->last_run_ns < q->ts + maxage) {
- continue;
- }
- ehci_free_queue(q, warn);
- }
-}
-
-static void ehci_queues_rip_unseen(EHCIState *ehci, int async)
-{
- EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
- EHCIQueue *q, *tmp;
-
- QTAILQ_FOREACH_SAFE(q, head, next, tmp) {
- if (!q->seen) {
- ehci_free_queue(q, NULL);
- }
- }
-}
-
-static void ehci_queues_rip_device(EHCIState *ehci, USBDevice *dev, int async)
-{
- EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
- EHCIQueue *q, *tmp;
-
- QTAILQ_FOREACH_SAFE(q, head, next, tmp) {
- if (q->dev != dev) {
- continue;
- }
- ehci_free_queue(q, NULL);
- }
-}
-
-static void ehci_queues_rip_all(EHCIState *ehci, int async)
-{
- EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
- const char *warn = async ? "guest stopped busy async schedule" : NULL;
- EHCIQueue *q, *tmp;
-
- QTAILQ_FOREACH_SAFE(q, head, next, tmp) {
- ehci_free_queue(q, warn);
- }
-}
-
-/* Attach or detach a device on root hub */
-
-static void ehci_attach(USBPort *port)
-{
- EHCIState *s = port->opaque;
- uint32_t *portsc = &s->portsc[port->index];
- const char *owner = (*portsc & PORTSC_POWNER) ? "comp" : "ehci";
-
- trace_usb_ehci_port_attach(port->index, owner, port->dev->product_desc);
-
- if (*portsc & PORTSC_POWNER) {
- USBPort *companion = s->companion_ports[port->index];
- companion->dev = port->dev;
- companion->ops->attach(companion);
- return;
- }
-
- *portsc |= PORTSC_CONNECT;
- *portsc |= PORTSC_CSC;
-
- ehci_raise_irq(s, USBSTS_PCD);
-}
-
-static void ehci_detach(USBPort *port)
-{
- EHCIState *s = port->opaque;
- uint32_t *portsc = &s->portsc[port->index];
- const char *owner = (*portsc & PORTSC_POWNER) ? "comp" : "ehci";
-
- trace_usb_ehci_port_detach(port->index, owner);
-
- if (*portsc & PORTSC_POWNER) {
- USBPort *companion = s->companion_ports[port->index];
- companion->ops->detach(companion);
- companion->dev = NULL;
- /*
- * EHCI spec 4.2.2: "When a disconnect occurs... On the event,
- * the port ownership is returned immediately to the EHCI controller."
- */
- *portsc &= ~PORTSC_POWNER;
- return;
- }
-
- ehci_queues_rip_device(s, port->dev, 0);
- ehci_queues_rip_device(s, port->dev, 1);
-
- *portsc &= ~(PORTSC_CONNECT|PORTSC_PED|PORTSC_SUSPEND);
- *portsc |= PORTSC_CSC;
-
- ehci_raise_irq(s, USBSTS_PCD);
-}
-
-static void ehci_child_detach(USBPort *port, USBDevice *child)
-{
- EHCIState *s = port->opaque;
- uint32_t portsc = s->portsc[port->index];
-
- if (portsc & PORTSC_POWNER) {
- USBPort *companion = s->companion_ports[port->index];
- companion->ops->child_detach(companion, child);
- return;
- }
-
- ehci_queues_rip_device(s, child, 0);
- ehci_queues_rip_device(s, child, 1);
-}
-
-static void ehci_wakeup(USBPort *port)
-{
- EHCIState *s = port->opaque;
- uint32_t *portsc = &s->portsc[port->index];
-
- if (*portsc & PORTSC_POWNER) {
- USBPort *companion = s->companion_ports[port->index];
- if (companion->ops->wakeup) {
- companion->ops->wakeup(companion);
- }
- return;
- }
-
- if (*portsc & PORTSC_SUSPEND) {
- trace_usb_ehci_port_wakeup(port->index);
- *portsc |= PORTSC_FPRES;
- ehci_raise_irq(s, USBSTS_PCD);
- }
-
- qemu_bh_schedule(s->async_bh);
-}
-
-static void ehci_register_companion(USBBus *bus, USBPort *ports[],
- uint32_t portcount, uint32_t firstport,
- Error **errp)
-{
- EHCIState *s = container_of(bus, EHCIState, bus);
- uint32_t i;
-
- if (firstport + portcount > NB_PORTS) {
- error_setg(errp, "firstport must be between 0 and %u",
- NB_PORTS - portcount);
- return;
- }
-
- for (i = 0; i < portcount; i++) {
- if (s->companion_ports[firstport + i]) {
- error_setg(errp, "firstport %u asks for ports %u-%u,"
- " but port %u has a companion assigned already",
- firstport, firstport, firstport + portcount - 1,
- firstport + i);
- return;
- }
- }
-
- for (i = 0; i < portcount; i++) {
- s->companion_ports[firstport + i] = ports[i];
- s->ports[firstport + i].speedmask |=
- USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL;
- /* Ensure devs attached before the initial reset go to the companion */
- s->portsc[firstport + i] = PORTSC_POWNER;
- }
-
- s->companion_count++;
- s->caps[0x05] = (s->companion_count << 4) | portcount;
-}
-
-static void ehci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep,
- unsigned int stream)
-{
- EHCIState *s = container_of(bus, EHCIState, bus);
- uint32_t portsc = s->portsc[ep->dev->port->index];
-
- if (portsc & PORTSC_POWNER) {
- return;
- }
-
- s->periodic_sched_active = PERIODIC_ACTIVE;
- qemu_bh_schedule(s->async_bh);
-}
-
-static USBDevice *ehci_find_device(EHCIState *ehci, uint8_t addr)
-{
- USBDevice *dev;
- USBPort *port;
- int i;
-
- for (i = 0; i < NB_PORTS; i++) {
- port = &ehci->ports[i];
- if (!(ehci->portsc[i] & PORTSC_PED)) {
- DPRINTF("Port %d not enabled\n", i);
- continue;
- }
- dev = usb_find_device(port, addr);
- if (dev != NULL) {
- return dev;
- }
- }
- return NULL;
-}
-
-/* 4.1 host controller initialization */
-void ehci_reset(void *opaque)
-{
- EHCIState *s = opaque;
- int i;
- USBDevice *devs[NB_PORTS];
-
- trace_usb_ehci_reset();
-
- /*
- * Do the detach before touching portsc, so that it correctly gets send to
- * us or to our companion based on PORTSC_POWNER before the reset.
- */
- for(i = 0; i < NB_PORTS; i++) {
- devs[i] = s->ports[i].dev;
- if (devs[i] && devs[i]->attached) {
- usb_detach(&s->ports[i]);
- }
- }
-
- memset(&s->opreg, 0x00, sizeof(s->opreg));
- memset(&s->portsc, 0x00, sizeof(s->portsc));
-
- s->usbcmd = NB_MAXINTRATE << USBCMD_ITC_SH;
- s->usbsts = USBSTS_HALT;
- s->usbsts_pending = 0;
- s->usbsts_frindex = 0;
- ehci_update_irq(s);
-
- s->astate = EST_INACTIVE;
- s->pstate = EST_INACTIVE;
-
- for(i = 0; i < NB_PORTS; i++) {
- if (s->companion_ports[i]) {
- s->portsc[i] = PORTSC_POWNER | PORTSC_PPOWER;
- } else {
- s->portsc[i] = PORTSC_PPOWER;
- }
- if (devs[i] && devs[i]->attached) {
- usb_attach(&s->ports[i]);
- usb_device_reset(devs[i]);
- }
- }
- ehci_queues_rip_all(s, 0);
- ehci_queues_rip_all(s, 1);
- timer_del(s->frame_timer);
- qemu_bh_cancel(s->async_bh);
-}
-
-static uint64_t ehci_caps_read(void *ptr, hwaddr addr,
- unsigned size)
-{
- EHCIState *s = ptr;
- return s->caps[addr];
-}
-
-static void ehci_caps_write(void *ptr, hwaddr addr,
- uint64_t val, unsigned size)
-{
-}
-
-static uint64_t ehci_opreg_read(void *ptr, hwaddr addr,
- unsigned size)
-{
- EHCIState *s = ptr;
- uint32_t val;
-
- switch (addr) {
- case FRINDEX:
- /* Round down to mult of 8, else it can go backwards on migration */
- val = s->frindex & ~7;
- break;
- default:
- val = s->opreg[addr >> 2];
- }
-
- trace_usb_ehci_opreg_read(addr + s->opregbase, addr2str(addr), val);
- return val;
-}
-
-static uint64_t ehci_port_read(void *ptr, hwaddr addr,
- unsigned size)
-{
- EHCIState *s = ptr;
- uint32_t val;
-
- val = s->portsc[addr >> 2];
- trace_usb_ehci_portsc_read(addr + s->portscbase, addr >> 2, val);
- return val;
-}
-
-static void handle_port_owner_write(EHCIState *s, int port, uint32_t owner)
-{
- USBDevice *dev = s->ports[port].dev;
- uint32_t *portsc = &s->portsc[port];
- uint32_t orig;
-
- if (s->companion_ports[port] == NULL)
- return;
-
- owner = owner & PORTSC_POWNER;
- orig = *portsc & PORTSC_POWNER;
-
- if (!(owner ^ orig)) {
- return;
- }
-
- if (dev && dev->attached) {
- usb_detach(&s->ports[port]);
- }
-
- *portsc &= ~PORTSC_POWNER;
- *portsc |= owner;
-
- if (dev && dev->attached) {
- usb_attach(&s->ports[port]);
- }
-}
-
-static void ehci_port_write(void *ptr, hwaddr addr,
- uint64_t val, unsigned size)
-{
- EHCIState *s = ptr;
- int port = addr >> 2;
- uint32_t *portsc = &s->portsc[port];
- uint32_t old = *portsc;
- USBDevice *dev = s->ports[port].dev;
-
- trace_usb_ehci_portsc_write(addr + s->portscbase, addr >> 2, val);
-
- /* Clear rwc bits */
- *portsc &= ~(val & PORTSC_RWC_MASK);
- /* The guest may clear, but not set the PED bit */
- *portsc &= val | ~PORTSC_PED;
- /* POWNER is masked out by RO_MASK as it is RO when we've no companion */
- handle_port_owner_write(s, port, val);
- /* And finally apply RO_MASK */
- val &= PORTSC_RO_MASK;
-
- if ((val & PORTSC_PRESET) && !(*portsc & PORTSC_PRESET)) {
- trace_usb_ehci_port_reset(port, 1);
- }
-
- if (!(val & PORTSC_PRESET) &&(*portsc & PORTSC_PRESET)) {
- trace_usb_ehci_port_reset(port, 0);
- if (dev && dev->attached) {
- usb_port_reset(&s->ports[port]);
- *portsc &= ~PORTSC_CSC;
- }
-
- /*
- * Table 2.16 Set the enable bit(and enable bit change) to indicate
- * to SW that this port has a high speed device attached
- */
- if (dev && dev->attached && (dev->speedmask & USB_SPEED_MASK_HIGH)) {
- val |= PORTSC_PED;
- }
- }
-
- if ((val & PORTSC_SUSPEND) && !(*portsc & PORTSC_SUSPEND)) {
- trace_usb_ehci_port_suspend(port);
- }
- if (!(val & PORTSC_FPRES) && (*portsc & PORTSC_FPRES)) {
- trace_usb_ehci_port_resume(port);
- val &= ~PORTSC_SUSPEND;
- }
-
- *portsc &= ~PORTSC_RO_MASK;
- *portsc |= val;
- trace_usb_ehci_portsc_change(addr + s->portscbase, addr >> 2, *portsc, old);
-}
-
-static void ehci_opreg_write(void *ptr, hwaddr addr,
- uint64_t val, unsigned size)
-{
- EHCIState *s = ptr;
- uint32_t *mmio = s->opreg + (addr >> 2);
- uint32_t old = *mmio;
- int i;
-
- trace_usb_ehci_opreg_write(addr + s->opregbase, addr2str(addr), val);
-
- switch (addr) {
- case USBCMD:
- if (val & USBCMD_HCRESET) {
- ehci_reset(s);
- val = s->usbcmd;
- break;
- }
-
- /* not supporting dynamic frame list size at the moment */
- if ((val & USBCMD_FLS) && !(s->usbcmd & USBCMD_FLS)) {
- fprintf(stderr, "attempt to set frame list size -- value %d\n",
- (int)val & USBCMD_FLS);
- val &= ~USBCMD_FLS;
- }
-
- if (val & USBCMD_IAAD) {
- /*
- * Process IAAD immediately, otherwise the Linux IAAD watchdog may
- * trigger and re-use a qh without us seeing the unlink.
- */
- s->async_stepdown = 0;
- qemu_bh_schedule(s->async_bh);
- trace_usb_ehci_doorbell_ring();
- }
-
- if (((USBCMD_RUNSTOP | USBCMD_PSE | USBCMD_ASE) & val) !=
- ((USBCMD_RUNSTOP | USBCMD_PSE | USBCMD_ASE) & s->usbcmd)) {
- if (s->pstate == EST_INACTIVE) {
- SET_LAST_RUN_CLOCK(s);
- }
- s->usbcmd = val; /* Set usbcmd for ehci_update_halt() */
- ehci_update_halt(s);
- s->async_stepdown = 0;
- qemu_bh_schedule(s->async_bh);
- }
- break;
-
- case USBSTS:
- val &= USBSTS_RO_MASK; // bits 6 through 31 are RO
- ehci_clear_usbsts(s, val); // bits 0 through 5 are R/WC
- val = s->usbsts;
- ehci_update_irq(s);
- break;
-
- case USBINTR:
- val &= USBINTR_MASK;
- if (ehci_enabled(s) && (USBSTS_FLR & val)) {
- qemu_bh_schedule(s->async_bh);
- }
- break;
-
- case FRINDEX:
- val &= 0x00003fff; /* frindex is 14bits */
- s->usbsts_frindex = val;
- break;
-
- case CONFIGFLAG:
- val &= 0x1;
- if (val) {
- for(i = 0; i < NB_PORTS; i++)
- handle_port_owner_write(s, i, 0);
- }
- break;
-
- case PERIODICLISTBASE:
- if (ehci_periodic_enabled(s)) {
- fprintf(stderr,
- "ehci: PERIODIC list base register set while periodic schedule\n"
- " is enabled and HC is enabled\n");
- }
- break;
-
- case ASYNCLISTADDR:
- if (ehci_async_enabled(s)) {
- fprintf(stderr,
- "ehci: ASYNC list address register set while async schedule\n"
- " is enabled and HC is enabled\n");
- }
- break;
- }
-
- *mmio = val;
- trace_usb_ehci_opreg_change(addr + s->opregbase, addr2str(addr),
- *mmio, old);
-}
-
-/*
- * Write the qh back to guest physical memory. This step isn't
- * in the EHCI spec but we need to do it since we don't share
- * physical memory with our guest VM.
- *
- * The first three dwords are read-only for the EHCI, so skip them
- * when writing back the qh.
- */
-static void ehci_flush_qh(EHCIQueue *q)
-{
- uint32_t *qh = (uint32_t *) &q->qh;
- uint32_t dwords = sizeof(EHCIqh) >> 2;
- uint32_t addr = NLPTR_GET(q->qhaddr);
-
- put_dwords(q->ehci, addr + 3 * sizeof(uint32_t), qh + 3, dwords - 3);
-}
-
-// 4.10.2
-
-static int ehci_qh_do_overlay(EHCIQueue *q)
-{
- EHCIPacket *p = QTAILQ_FIRST(&q->packets);
- int i;
- int dtoggle;
- int ping;
- int eps;
- int reload;
-
- assert(p != NULL);
- assert(p->qtdaddr == q->qtdaddr);
-
- // remember values in fields to preserve in qh after overlay
-
- dtoggle = q->qh.token & QTD_TOKEN_DTOGGLE;
- ping = q->qh.token & QTD_TOKEN_PING;
-
- q->qh.current_qtd = p->qtdaddr;
- q->qh.next_qtd = p->qtd.next;
- q->qh.altnext_qtd = p->qtd.altnext;
- q->qh.token = p->qtd.token;
-
-
- eps = get_field(q->qh.epchar, QH_EPCHAR_EPS);
- if (eps == EHCI_QH_EPS_HIGH) {
- q->qh.token &= ~QTD_TOKEN_PING;
- q->qh.token |= ping;
- }
-
- reload = get_field(q->qh.epchar, QH_EPCHAR_RL);
- set_field(&q->qh.altnext_qtd, reload, QH_ALTNEXT_NAKCNT);
-
- for (i = 0; i < 5; i++) {
- q->qh.bufptr[i] = p->qtd.bufptr[i];
- }
-
- if (!(q->qh.epchar & QH_EPCHAR_DTC)) {
- // preserve QH DT bit
- q->qh.token &= ~QTD_TOKEN_DTOGGLE;
- q->qh.token |= dtoggle;
- }
-
- q->qh.bufptr[1] &= ~BUFPTR_CPROGMASK_MASK;
- q->qh.bufptr[2] &= ~BUFPTR_FRAMETAG_MASK;
-
- ehci_flush_qh(q);
-
- return 0;
-}
-
-static int ehci_init_transfer(EHCIPacket *p)
-{
- uint32_t cpage, offset, bytes, plen;
- dma_addr_t page;
-
- cpage = get_field(p->qtd.token, QTD_TOKEN_CPAGE);
- bytes = get_field(p->qtd.token, QTD_TOKEN_TBYTES);
- offset = p->qtd.bufptr[0] & ~QTD_BUFPTR_MASK;
- qemu_sglist_init(&p->sgl, p->queue->ehci->device, 5, p->queue->ehci->as);
-
- while (bytes > 0) {
- if (cpage > 4) {
- fprintf(stderr, "cpage out of range (%d)\n", cpage);
- return -1;
- }
-
- page = p->qtd.bufptr[cpage] & QTD_BUFPTR_MASK;
- page += offset;
- plen = bytes;
- if (plen > 4096 - offset) {
- plen = 4096 - offset;
- offset = 0;
- cpage++;
- }
-
- qemu_sglist_add(&p->sgl, page, plen);
- bytes -= plen;
- }
- return 0;
-}
-
-static void ehci_finish_transfer(EHCIQueue *q, int len)
-{
- uint32_t cpage, offset;
-
- if (len > 0) {
- /* update cpage & offset */
- cpage = get_field(q->qh.token, QTD_TOKEN_CPAGE);
- offset = q->qh.bufptr[0] & ~QTD_BUFPTR_MASK;
-
- offset += len;
- cpage += offset >> QTD_BUFPTR_SH;
- offset &= ~QTD_BUFPTR_MASK;
-
- set_field(&q->qh.token, cpage, QTD_TOKEN_CPAGE);
- q->qh.bufptr[0] &= QTD_BUFPTR_MASK;
- q->qh.bufptr[0] |= offset;
- }
-}
-
-static void ehci_async_complete_packet(USBPort *port, USBPacket *packet)
-{
- EHCIPacket *p;
- EHCIState *s = port->opaque;
- uint32_t portsc = s->portsc[port->index];
-
- if (portsc & PORTSC_POWNER) {
- USBPort *companion = s->companion_ports[port->index];
- companion->ops->complete(companion, packet);
- return;
- }
-
- p = container_of(packet, EHCIPacket, packet);
- assert(p->async == EHCI_ASYNC_INFLIGHT);
-
- if (packet->status == USB_RET_REMOVE_FROM_QUEUE) {
- trace_usb_ehci_packet_action(p->queue, p, "remove");
- ehci_free_packet(p);
- return;
- }
-
- trace_usb_ehci_packet_action(p->queue, p, "wakeup");
- p->async = EHCI_ASYNC_FINISHED;
-
- if (!p->queue->async) {
- s->periodic_sched_active = PERIODIC_ACTIVE;
- }
- qemu_bh_schedule(s->async_bh);
-}
-
-static void ehci_execute_complete(EHCIQueue *q)
-{
- EHCIPacket *p = QTAILQ_FIRST(&q->packets);
- uint32_t tbytes;
-
- assert(p != NULL);
- assert(p->qtdaddr == q->qtdaddr);
- assert(p->async == EHCI_ASYNC_INITIALIZED ||
- p->async == EHCI_ASYNC_FINISHED);
-
- DPRINTF("execute_complete: qhaddr 0x%x, next 0x%x, qtdaddr 0x%x, "
- "status %d, actual_length %d\n",
- q->qhaddr, q->qh.next, q->qtdaddr,
- p->packet.status, p->packet.actual_length);
-
- switch (p->packet.status) {
- case USB_RET_SUCCESS:
- break;
- case USB_RET_IOERROR:
- case USB_RET_NODEV:
- q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_XACTERR);
- set_field(&q->qh.token, 0, QTD_TOKEN_CERR);
- ehci_raise_irq(q->ehci, USBSTS_ERRINT);
- break;
- case USB_RET_STALL:
- q->qh.token |= QTD_TOKEN_HALT;
- ehci_raise_irq(q->ehci, USBSTS_ERRINT);
- break;
- case USB_RET_NAK:
- set_field(&q->qh.altnext_qtd, 0, QH_ALTNEXT_NAKCNT);
- return; /* We're not done yet with this transaction */
- case USB_RET_BABBLE:
- q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_BABBLE);
- ehci_raise_irq(q->ehci, USBSTS_ERRINT);
- break;
- default:
- /* should not be triggerable */
- fprintf(stderr, "USB invalid response %d\n", p->packet.status);
- g_assert_not_reached();
- break;
- }
-
- /* TODO check 4.12 for splits */
- tbytes = get_field(q->qh.token, QTD_TOKEN_TBYTES);
- if (tbytes && p->pid == USB_TOKEN_IN) {
- tbytes -= p->packet.actual_length;
- if (tbytes) {
- /* 4.15.1.2 must raise int on a short input packet */
- ehci_raise_irq(q->ehci, USBSTS_INT);
- if (q->async) {
- q->ehci->int_req_by_async = true;
- }
- }
- } else {
- tbytes = 0;
- }
- DPRINTF("updating tbytes to %d\n", tbytes);
- set_field(&q->qh.token, tbytes, QTD_TOKEN_TBYTES);
-
- ehci_finish_transfer(q, p->packet.actual_length);
- usb_packet_unmap(&p->packet, &p->sgl);
- qemu_sglist_destroy(&p->sgl);
- p->async = EHCI_ASYNC_NONE;
-
- q->qh.token ^= QTD_TOKEN_DTOGGLE;
- q->qh.token &= ~QTD_TOKEN_ACTIVE;
-
- if (q->qh.token & QTD_TOKEN_IOC) {
- ehci_raise_irq(q->ehci, USBSTS_INT);
- if (q->async) {
- q->ehci->int_req_by_async = true;
- }
- }
-}
-
-/* 4.10.3 returns "again" */
-static int ehci_execute(EHCIPacket *p, const char *action)
-{
- USBEndpoint *ep;
- int endp;
- bool spd;
-
- assert(p->async == EHCI_ASYNC_NONE ||
- p->async == EHCI_ASYNC_INITIALIZED);
-
- if (!(p->qtd.token & QTD_TOKEN_ACTIVE)) {
- fprintf(stderr, "Attempting to execute inactive qtd\n");
- return -1;
- }
-
- if (get_field(p->qtd.token, QTD_TOKEN_TBYTES) > BUFF_SIZE) {
- ehci_trace_guest_bug(p->queue->ehci,
- "guest requested more bytes than allowed");
- return -1;
- }
-
- if (!ehci_verify_pid(p->queue, &p->qtd)) {
- ehci_queue_stopped(p->queue); /* Mark the ep in the prev dir stopped */
- }
- p->pid = ehci_get_pid(&p->qtd);
- p->queue->last_pid = p->pid;
- endp = get_field(p->queue->qh.epchar, QH_EPCHAR_EP);
- ep = usb_ep_get(p->queue->dev, p->pid, endp);
-
- if (p->async == EHCI_ASYNC_NONE) {
- if (ehci_init_transfer(p) != 0) {
- return -1;
- }
-
- spd = (p->pid == USB_TOKEN_IN && NLPTR_TBIT(p->qtd.altnext) == 0);
- usb_packet_setup(&p->packet, p->pid, ep, 0, p->qtdaddr, spd,
- (p->qtd.token & QTD_TOKEN_IOC) != 0);
- usb_packet_map(&p->packet, &p->sgl);
- p->async = EHCI_ASYNC_INITIALIZED;
- }
-
- trace_usb_ehci_packet_action(p->queue, p, action);
- usb_handle_packet(p->queue->dev, &p->packet);
- DPRINTF("submit: qh 0x%x next 0x%x qtd 0x%x pid 0x%x len %zd endp 0x%x "
- "status %d actual_length %d\n", p->queue->qhaddr, p->qtd.next,
- p->qtdaddr, p->pid, p->packet.iov.size, endp, p->packet.status,
- p->packet.actual_length);
-
- if (p->packet.actual_length > BUFF_SIZE) {
- fprintf(stderr, "ret from usb_handle_packet > BUFF_SIZE\n");
- return -1;
- }
-
- return 1;
-}
-
-/* 4.7.2
- */
-
-static int ehci_process_itd(EHCIState *ehci,
- EHCIitd *itd,
- uint32_t addr)
-{
- USBDevice *dev;
- USBEndpoint *ep;
- uint32_t i, len, pid, dir, devaddr, endp;
- uint32_t pg, off, ptr1, ptr2, max, mult;
-
- ehci->periodic_sched_active = PERIODIC_ACTIVE;
-
- dir =(itd->bufptr[1] & ITD_BUFPTR_DIRECTION);
- devaddr = get_field(itd->bufptr[0], ITD_BUFPTR_DEVADDR);
- endp = get_field(itd->bufptr[0], ITD_BUFPTR_EP);
- max = get_field(itd->bufptr[1], ITD_BUFPTR_MAXPKT);
- mult = get_field(itd->bufptr[2], ITD_BUFPTR_MULT);
-
- for(i = 0; i < 8; i++) {
- if (itd->transact[i] & ITD_XACT_ACTIVE) {
- pg = get_field(itd->transact[i], ITD_XACT_PGSEL);
- off = itd->transact[i] & ITD_XACT_OFFSET_MASK;
- len = get_field(itd->transact[i], ITD_XACT_LENGTH);
-
- if (len > max * mult) {
- len = max * mult;
- }
- if (len > BUFF_SIZE || pg > 6) {
- return -1;
- }
-
- ptr1 = (itd->bufptr[pg] & ITD_BUFPTR_MASK);
- qemu_sglist_init(&ehci->isgl, ehci->device, 2, ehci->as);
- if (off + len > 4096) {
- /* transfer crosses page border */
- if (pg == 6) {
- return -1; /* avoid page pg + 1 */
- }
- ptr2 = (itd->bufptr[pg + 1] & ITD_BUFPTR_MASK);
- uint32_t len2 = off + len - 4096;
- uint32_t len1 = len - len2;
- qemu_sglist_add(&ehci->isgl, ptr1 + off, len1);
- qemu_sglist_add(&ehci->isgl, ptr2, len2);
- } else {
- qemu_sglist_add(&ehci->isgl, ptr1 + off, len);
- }
-
- pid = dir ? USB_TOKEN_IN : USB_TOKEN_OUT;
-
- dev = ehci_find_device(ehci, devaddr);
- ep = usb_ep_get(dev, pid, endp);
- if (ep && ep->type == USB_ENDPOINT_XFER_ISOC) {
- usb_packet_setup(&ehci->ipacket, pid, ep, 0, addr, false,
- (itd->transact[i] & ITD_XACT_IOC) != 0);
- usb_packet_map(&ehci->ipacket, &ehci->isgl);
- usb_handle_packet(dev, &ehci->ipacket);
- usb_packet_unmap(&ehci->ipacket, &ehci->isgl);
- } else {
- DPRINTF("ISOCH: attempt to addess non-iso endpoint\n");
- ehci->ipacket.status = USB_RET_NAK;
- ehci->ipacket.actual_length = 0;
- }
- qemu_sglist_destroy(&ehci->isgl);
-
- switch (ehci->ipacket.status) {
- case USB_RET_SUCCESS:
- break;
- default:
- fprintf(stderr, "Unexpected iso usb result: %d\n",
- ehci->ipacket.status);
- /* Fall through */
- case USB_RET_IOERROR:
- case USB_RET_NODEV:
- /* 3.3.2: XACTERR is only allowed on IN transactions */
- if (dir) {
- itd->transact[i] |= ITD_XACT_XACTERR;
- ehci_raise_irq(ehci, USBSTS_ERRINT);
- }
- break;
- case USB_RET_BABBLE:
- itd->transact[i] |= ITD_XACT_BABBLE;
- ehci_raise_irq(ehci, USBSTS_ERRINT);
- break;
- case USB_RET_NAK:
- /* no data for us, so do a zero-length transfer */
- ehci->ipacket.actual_length = 0;
- break;
- }
- if (!dir) {
- set_field(&itd->transact[i], len - ehci->ipacket.actual_length,
- ITD_XACT_LENGTH); /* OUT */
- } else {
- set_field(&itd->transact[i], ehci->ipacket.actual_length,
- ITD_XACT_LENGTH); /* IN */
- }
- if (itd->transact[i] & ITD_XACT_IOC) {
- ehci_raise_irq(ehci, USBSTS_INT);
- }
- itd->transact[i] &= ~ITD_XACT_ACTIVE;
- }
- }
- return 0;
-}
-
-
-/* This state is the entry point for asynchronous schedule
- * processing. Entry here consitutes a EHCI start event state (4.8.5)
- */
-static int ehci_state_waitlisthead(EHCIState *ehci, int async)
-{
- EHCIqh qh;
- int i = 0;
- int again = 0;
- uint32_t entry = ehci->asynclistaddr;
-
- /* set reclamation flag at start event (4.8.6) */
- if (async) {
- ehci_set_usbsts(ehci, USBSTS_REC);
- }
-
- ehci_queues_rip_unused(ehci, async);
-
- /* Find the head of the list (4.9.1.1) */
- for(i = 0; i < MAX_QH; i++) {
- if (get_dwords(ehci, NLPTR_GET(entry), (uint32_t *) &qh,
- sizeof(EHCIqh) >> 2) < 0) {
- return 0;
- }
- ehci_trace_qh(NULL, NLPTR_GET(entry), &qh);
-
- if (qh.epchar & QH_EPCHAR_H) {
- if (async) {
- entry |= (NLPTR_TYPE_QH << 1);
- }
-
- ehci_set_fetch_addr(ehci, async, entry);
- ehci_set_state(ehci, async, EST_FETCHENTRY);
- again = 1;
- goto out;
- }
-
- entry = qh.next;
- if (entry == ehci->asynclistaddr) {
- break;
- }
- }
-
- /* no head found for list. */
-
- ehci_set_state(ehci, async, EST_ACTIVE);
-
-out:
- return again;
-}
-
-
-/* This state is the entry point for periodic schedule processing as
- * well as being a continuation state for async processing.
- */
-static int ehci_state_fetchentry(EHCIState *ehci, int async)
-{
- int again = 0;
- uint32_t entry = ehci_get_fetch_addr(ehci, async);
-
- if (NLPTR_TBIT(entry)) {
- ehci_set_state(ehci, async, EST_ACTIVE);
- goto out;
- }
-
- /* section 4.8, only QH in async schedule */
- if (async && (NLPTR_TYPE_GET(entry) != NLPTR_TYPE_QH)) {
- fprintf(stderr, "non queue head request in async schedule\n");
- return -1;
- }
-
- switch (NLPTR_TYPE_GET(entry)) {
- case NLPTR_TYPE_QH:
- ehci_set_state(ehci, async, EST_FETCHQH);
- again = 1;
- break;
-
- case NLPTR_TYPE_ITD:
- ehci_set_state(ehci, async, EST_FETCHITD);
- again = 1;
- break;
-
- case NLPTR_TYPE_STITD:
- ehci_set_state(ehci, async, EST_FETCHSITD);
- again = 1;
- break;
-
- default:
- /* TODO: handle FSTN type */
- fprintf(stderr, "FETCHENTRY: entry at %X is of type %d "
- "which is not supported yet\n", entry, NLPTR_TYPE_GET(entry));
- return -1;
- }
-
-out:
- return again;
-}
-
-static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
-{
- uint32_t entry;
- EHCIQueue *q;
- EHCIqh qh;
-
- entry = ehci_get_fetch_addr(ehci, async);
- q = ehci_find_queue_by_qh(ehci, entry, async);
- if (q == NULL) {
- q = ehci_alloc_queue(ehci, entry, async);
- }
-
- q->seen++;
- if (q->seen > 1) {
- /* we are going in circles -- stop processing */
- ehci_set_state(ehci, async, EST_ACTIVE);
- q = NULL;
- goto out;
- }
-
- if (get_dwords(ehci, NLPTR_GET(q->qhaddr),
- (uint32_t *) &qh, sizeof(EHCIqh) >> 2) < 0) {
- q = NULL;
- goto out;
- }
- ehci_trace_qh(q, NLPTR_GET(q->qhaddr), &qh);
-
- /*
- * The overlay area of the qh should never be changed by the guest,
- * except when idle, in which case the reset is a nop.
- */
- if (!ehci_verify_qh(q, &qh)) {
- if (ehci_reset_queue(q) > 0) {
- ehci_trace_guest_bug(ehci, "guest updated active QH");
- }
- }
- q->qh = qh;
-
- q->transact_ctr = get_field(q->qh.epcap, QH_EPCAP_MULT);
- if (q->transact_ctr == 0) { /* Guest bug in some versions of windows */
- q->transact_ctr = 4;
- }
-
- if (q->dev == NULL) {
- q->dev = ehci_find_device(q->ehci,
- get_field(q->qh.epchar, QH_EPCHAR_DEVADDR));
- }
-
- if (async && (q->qh.epchar & QH_EPCHAR_H)) {
-
- /* EHCI spec version 1.0 Section 4.8.3 & 4.10.1 */
- if (ehci->usbsts & USBSTS_REC) {
- ehci_clear_usbsts(ehci, USBSTS_REC);
- } else {
- DPRINTF("FETCHQH: QH 0x%08x. H-bit set, reclamation status reset"
- " - done processing\n", q->qhaddr);
- ehci_set_state(ehci, async, EST_ACTIVE);
- q = NULL;
- goto out;
- }
- }
-
-#if EHCI_DEBUG
- if (q->qhaddr != q->qh.next) {
- DPRINTF("FETCHQH: QH 0x%08x (h %x halt %x active %x) next 0x%08x\n",
- q->qhaddr,
- q->qh.epchar & QH_EPCHAR_H,
- q->qh.token & QTD_TOKEN_HALT,
- q->qh.token & QTD_TOKEN_ACTIVE,
- q->qh.next);
- }
-#endif
-
- if (q->qh.token & QTD_TOKEN_HALT) {
- ehci_set_state(ehci, async, EST_HORIZONTALQH);
-
- } else if ((q->qh.token & QTD_TOKEN_ACTIVE) &&
- (NLPTR_TBIT(q->qh.current_qtd) == 0)) {
- q->qtdaddr = q->qh.current_qtd;
- ehci_set_state(ehci, async, EST_FETCHQTD);
-
- } else {
- /* EHCI spec version 1.0 Section 4.10.2 */
- ehci_set_state(ehci, async, EST_ADVANCEQUEUE);
- }
-
-out:
- return q;
-}
-
-static int ehci_state_fetchitd(EHCIState *ehci, int async)
-{
- uint32_t entry;
- EHCIitd itd;
-
- assert(!async);
- entry = ehci_get_fetch_addr(ehci, async);
-
- if (get_dwords(ehci, NLPTR_GET(entry), (uint32_t *) &itd,
- sizeof(EHCIitd) >> 2) < 0) {
- return -1;
- }
- ehci_trace_itd(ehci, entry, &itd);
-
- if (ehci_process_itd(ehci, &itd, entry) != 0) {
- return -1;
- }
-
- put_dwords(ehci, NLPTR_GET(entry), (uint32_t *) &itd,
- sizeof(EHCIitd) >> 2);
- ehci_set_fetch_addr(ehci, async, itd.next);
- ehci_set_state(ehci, async, EST_FETCHENTRY);
-
- return 1;
-}
-
-static int ehci_state_fetchsitd(EHCIState *ehci, int async)
-{
- uint32_t entry;
- EHCIsitd sitd;
-
- assert(!async);
- entry = ehci_get_fetch_addr(ehci, async);
-
- if (get_dwords(ehci, NLPTR_GET(entry), (uint32_t *)&sitd,
- sizeof(EHCIsitd) >> 2) < 0) {
- return 0;
- }
- ehci_trace_sitd(ehci, entry, &sitd);
-
- if (!(sitd.results & SITD_RESULTS_ACTIVE)) {
- /* siTD is not active, nothing to do */;
- } else {
- /* TODO: split transfers are not implemented */
- fprintf(stderr, "WARNING: Skipping active siTD\n");
- }
-
- ehci_set_fetch_addr(ehci, async, sitd.next);
- ehci_set_state(ehci, async, EST_FETCHENTRY);
- return 1;
-}
-
-/* Section 4.10.2 - paragraph 3 */
-static int ehci_state_advqueue(EHCIQueue *q)
-{
-#if 0
- /* TO-DO: 4.10.2 - paragraph 2
- * if I-bit is set to 1 and QH is not active
- * go to horizontal QH
- */
- if (I-bit set) {
- ehci_set_state(ehci, async, EST_HORIZONTALQH);
- goto out;
- }
-#endif
-
- /*
- * want data and alt-next qTD is valid
- */
- if (((q->qh.token & QTD_TOKEN_TBYTES_MASK) != 0) &&
- (NLPTR_TBIT(q->qh.altnext_qtd) == 0)) {
- q->qtdaddr = q->qh.altnext_qtd;
- ehci_set_state(q->ehci, q->async, EST_FETCHQTD);
-
- /*
- * next qTD is valid
- */
- } else if (NLPTR_TBIT(q->qh.next_qtd) == 0) {
- q->qtdaddr = q->qh.next_qtd;
- ehci_set_state(q->ehci, q->async, EST_FETCHQTD);
-
- /*
- * no valid qTD, try next QH
- */
- } else {
- ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
- }
-
- return 1;
-}
-
-/* Section 4.10.2 - paragraph 4 */
-static int ehci_state_fetchqtd(EHCIQueue *q)
-{
- EHCIqtd qtd;
- EHCIPacket *p;
- int again = 1;
-
- if (get_dwords(q->ehci, NLPTR_GET(q->qtdaddr), (uint32_t *) &qtd,
- sizeof(EHCIqtd) >> 2) < 0) {
- return 0;
- }
- ehci_trace_qtd(q, NLPTR_GET(q->qtdaddr), &qtd);
-
- p = QTAILQ_FIRST(&q->packets);
- if (p != NULL) {
- if (!ehci_verify_qtd(p, &qtd)) {
- ehci_cancel_queue(q);
- if (qtd.token & QTD_TOKEN_ACTIVE) {
- ehci_trace_guest_bug(q->ehci, "guest updated active qTD");
- }
- p = NULL;
- } else {
- p->qtd = qtd;
- ehci_qh_do_overlay(q);
- }
- }
-
- if (!(qtd.token & QTD_TOKEN_ACTIVE)) {
- ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
- } else if (p != NULL) {
- switch (p->async) {
- case EHCI_ASYNC_NONE:
- case EHCI_ASYNC_INITIALIZED:
- /* Not yet executed (MULT), or previously nacked (int) packet */
- ehci_set_state(q->ehci, q->async, EST_EXECUTE);
- break;
- case EHCI_ASYNC_INFLIGHT:
- /* Check if the guest has added new tds to the queue */
- again = ehci_fill_queue(QTAILQ_LAST(&q->packets, pkts_head));
- /* Unfinished async handled packet, go horizontal */
- ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
- break;
- case EHCI_ASYNC_FINISHED:
- /* Complete executing of the packet */
- ehci_set_state(q->ehci, q->async, EST_EXECUTING);
- break;
- }
- } else {
- p = ehci_alloc_packet(q);
- p->qtdaddr = q->qtdaddr;
- p->qtd = qtd;
- ehci_set_state(q->ehci, q->async, EST_EXECUTE);
- }
-
- return again;
-}
-
-static int ehci_state_horizqh(EHCIQueue *q)
-{
- int again = 0;
-
- if (ehci_get_fetch_addr(q->ehci, q->async) != q->qh.next) {
- ehci_set_fetch_addr(q->ehci, q->async, q->qh.next);
- ehci_set_state(q->ehci, q->async, EST_FETCHENTRY);
- again = 1;
- } else {
- ehci_set_state(q->ehci, q->async, EST_ACTIVE);
- }
-
- return again;
-}
-
-/* Returns "again" */
-static int ehci_fill_queue(EHCIPacket *p)
-{
- USBEndpoint *ep = p->packet.ep;
- EHCIQueue *q = p->queue;
- EHCIqtd qtd = p->qtd;
- uint32_t qtdaddr;
-
- for (;;) {
- if (NLPTR_TBIT(qtd.next) != 0) {
- break;
- }
- qtdaddr = qtd.next;
- /*
- * Detect circular td lists, Windows creates these, counting on the
- * active bit going low after execution to make the queue stop.
- */
- QTAILQ_FOREACH(p, &q->packets, next) {
- if (p->qtdaddr == qtdaddr) {
- goto leave;
- }
- }
- if (get_dwords(q->ehci, NLPTR_GET(qtdaddr),
- (uint32_t *) &qtd, sizeof(EHCIqtd) >> 2) < 0) {
- return -1;
- }
- ehci_trace_qtd(q, NLPTR_GET(qtdaddr), &qtd);
- if (!(qtd.token & QTD_TOKEN_ACTIVE)) {
- break;
- }
- if (!ehci_verify_pid(q, &qtd)) {
- ehci_trace_guest_bug(q->ehci, "guest queued token with wrong pid");
- break;
- }
- p = ehci_alloc_packet(q);
- p->qtdaddr = qtdaddr;
- p->qtd = qtd;
- if (ehci_execute(p, "queue") == -1) {
- return -1;
- }
- assert(p->packet.status == USB_RET_ASYNC);
- p->async = EHCI_ASYNC_INFLIGHT;
- }
-leave:
- usb_device_flush_ep_queue(ep->dev, ep);
- return 1;
-}
-
-static int ehci_state_execute(EHCIQueue *q)
-{
- EHCIPacket *p = QTAILQ_FIRST(&q->packets);
- int again = 0;
-
- assert(p != NULL);
- assert(p->qtdaddr == q->qtdaddr);
-
- if (ehci_qh_do_overlay(q) != 0) {
- return -1;
- }
-
- // TODO verify enough time remains in the uframe as in 4.4.1.1
- // TODO write back ptr to async list when done or out of time
-
- /* 4.10.3, bottom of page 82, go horizontal on transaction counter == 0 */
- if (!q->async && q->transact_ctr == 0) {
- ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
- again = 1;
- goto out;
- }
-
- if (q->async) {
- ehci_set_usbsts(q->ehci, USBSTS_REC);
- }
-
- again = ehci_execute(p, "process");
- if (again == -1) {
- goto out;
- }
- if (p->packet.status == USB_RET_ASYNC) {
- ehci_flush_qh(q);
- trace_usb_ehci_packet_action(p->queue, p, "async");
- p->async = EHCI_ASYNC_INFLIGHT;
- ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
- if (q->async) {
- again = ehci_fill_queue(p);
- } else {
- again = 1;
- }
- goto out;
- }
-
- ehci_set_state(q->ehci, q->async, EST_EXECUTING);
- again = 1;
-
-out:
- return again;
-}
-
-static int ehci_state_executing(EHCIQueue *q)
-{
- EHCIPacket *p = QTAILQ_FIRST(&q->packets);
-
- assert(p != NULL);
- assert(p->qtdaddr == q->qtdaddr);
-
- ehci_execute_complete(q);
-
- /* 4.10.3 */
- if (!q->async && q->transact_ctr > 0) {
- q->transact_ctr--;
- }
-
- /* 4.10.5 */
- if (p->packet.status == USB_RET_NAK) {
- ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
- } else {
- ehci_set_state(q->ehci, q->async, EST_WRITEBACK);
- }
-
- ehci_flush_qh(q);
- return 1;
-}
-
-
-static int ehci_state_writeback(EHCIQueue *q)
-{
- EHCIPacket *p = QTAILQ_FIRST(&q->packets);
- uint32_t *qtd, addr;
- int again = 0;
-
- /* Write back the QTD from the QH area */
- assert(p != NULL);
- assert(p->qtdaddr == q->qtdaddr);
-
- ehci_trace_qtd(q, NLPTR_GET(p->qtdaddr), (EHCIqtd *) &q->qh.next_qtd);
- qtd = (uint32_t *) &q->qh.next_qtd;
- addr = NLPTR_GET(p->qtdaddr);
- put_dwords(q->ehci, addr + 2 * sizeof(uint32_t), qtd + 2, 2);
- ehci_free_packet(p);
-
- /*
- * EHCI specs say go horizontal here.
- *
- * We can also advance the queue here for performance reasons. We
- * need to take care to only take that shortcut in case we've
- * processed the qtd just written back without errors, i.e. halt
- * bit is clear.
- */
- if (q->qh.token & QTD_TOKEN_HALT) {
- ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
- again = 1;
- } else {
- ehci_set_state(q->ehci, q->async, EST_ADVANCEQUEUE);
- again = 1;
- }
- return again;
-}
-
-/*
- * This is the state machine that is common to both async and periodic
- */
-
-static void ehci_advance_state(EHCIState *ehci, int async)
-{
- EHCIQueue *q = NULL;
- int itd_count = 0;
- int again;
-
- do {
- switch(ehci_get_state(ehci, async)) {
- case EST_WAITLISTHEAD:
- again = ehci_state_waitlisthead(ehci, async);
- break;
-
- case EST_FETCHENTRY:
- again = ehci_state_fetchentry(ehci, async);
- break;
-
- case EST_FETCHQH:
- q = ehci_state_fetchqh(ehci, async);
- if (q != NULL) {
- assert(q->async == async);
- again = 1;
- } else {
- again = 0;
- }
- break;
-
- case EST_FETCHITD:
- again = ehci_state_fetchitd(ehci, async);
- itd_count++;
- break;
-
- case EST_FETCHSITD:
- again = ehci_state_fetchsitd(ehci, async);
- itd_count++;
- break;
-
- case EST_ADVANCEQUEUE:
- assert(q != NULL);
- again = ehci_state_advqueue(q);
- break;
-
- case EST_FETCHQTD:
- assert(q != NULL);
- again = ehci_state_fetchqtd(q);
- break;
-
- case EST_HORIZONTALQH:
- assert(q != NULL);
- again = ehci_state_horizqh(q);
- break;
-
- case EST_EXECUTE:
- assert(q != NULL);
- again = ehci_state_execute(q);
- if (async) {
- ehci->async_stepdown = 0;
- }
- break;
-
- case EST_EXECUTING:
- assert(q != NULL);
- if (async) {
- ehci->async_stepdown = 0;
- }
- again = ehci_state_executing(q);
- break;
-
- case EST_WRITEBACK:
- assert(q != NULL);
- again = ehci_state_writeback(q);
- if (!async) {
- ehci->periodic_sched_active = PERIODIC_ACTIVE;
- }
- break;
-
- default:
- fprintf(stderr, "Bad state!\n");
- again = -1;
- g_assert_not_reached();
- break;
- }
-
- if (again < 0 || itd_count > 16) {
- /* TODO: notify guest (raise HSE irq?) */
- fprintf(stderr, "processing error - resetting ehci HC\n");
- ehci_reset(ehci);
- again = 0;
- }
- }
- while (again);
-}
-
-static void ehci_advance_async_state(EHCIState *ehci)
-{
- const int async = 1;
-
- switch(ehci_get_state(ehci, async)) {
- case EST_INACTIVE:
- if (!ehci_async_enabled(ehci)) {
- break;
- }
- ehci_set_state(ehci, async, EST_ACTIVE);
- // No break, fall through to ACTIVE
-
- case EST_ACTIVE:
- if (!ehci_async_enabled(ehci)) {
- ehci_queues_rip_all(ehci, async);
- ehci_set_state(ehci, async, EST_INACTIVE);
- break;
- }
-
- /* make sure guest has acknowledged the doorbell interrupt */
- /* TO-DO: is this really needed? */
- if (ehci->usbsts & USBSTS_IAA) {
- DPRINTF("IAA status bit still set.\n");
- break;
- }
-
- /* check that address register has been set */
- if (ehci->asynclistaddr == 0) {
- break;
- }
-
- ehci_set_state(ehci, async, EST_WAITLISTHEAD);
- ehci_advance_state(ehci, async);
-
- /* If the doorbell is set, the guest wants to make a change to the
- * schedule. The host controller needs to release cached data.
- * (section 4.8.2)
- */
- if (ehci->usbcmd & USBCMD_IAAD) {
- /* Remove all unseen qhs from the async qhs queue */
- ehci_queues_rip_unseen(ehci, async);
- trace_usb_ehci_doorbell_ack();
- ehci->usbcmd &= ~USBCMD_IAAD;
- ehci_raise_irq(ehci, USBSTS_IAA);
- }
- break;
-
- default:
- /* this should only be due to a developer mistake */
- fprintf(stderr, "ehci: Bad asynchronous state %d. "
- "Resetting to active\n", ehci->astate);
- g_assert_not_reached();
- }
-}
-
-static void ehci_advance_periodic_state(EHCIState *ehci)
-{
- uint32_t entry;
- uint32_t list;
- const int async = 0;
-
- // 4.6
-
- switch(ehci_get_state(ehci, async)) {
- case EST_INACTIVE:
- if (!(ehci->frindex & 7) && ehci_periodic_enabled(ehci)) {
- ehci_set_state(ehci, async, EST_ACTIVE);
- // No break, fall through to ACTIVE
- } else
- break;
-
- case EST_ACTIVE:
- if (!(ehci->frindex & 7) && !ehci_periodic_enabled(ehci)) {
- ehci_queues_rip_all(ehci, async);
- ehci_set_state(ehci, async, EST_INACTIVE);
- break;
- }
-
- list = ehci->periodiclistbase & 0xfffff000;
- /* check that register has been set */
- if (list == 0) {
- break;
- }
- list |= ((ehci->frindex & 0x1ff8) >> 1);
-
- if (get_dwords(ehci, list, &entry, 1) < 0) {
- break;
- }
-
- DPRINTF("PERIODIC state adv fr=%d. [%08X] -> %08X\n",
- ehci->frindex / 8, list, entry);
- ehci_set_fetch_addr(ehci, async,entry);
- ehci_set_state(ehci, async, EST_FETCHENTRY);
- ehci_advance_state(ehci, async);
- ehci_queues_rip_unused(ehci, async);
- break;
-
- default:
- /* this should only be due to a developer mistake */
- fprintf(stderr, "ehci: Bad periodic state %d. "
- "Resetting to active\n", ehci->pstate);
- g_assert_not_reached();
- }
-}
-
-static void ehci_update_frindex(EHCIState *ehci, int uframes)
-{
- int i;
-
- if (!ehci_enabled(ehci) && ehci->pstate == EST_INACTIVE) {
- return;
- }
-
- for (i = 0; i < uframes; i++) {
- ehci->frindex++;
-
- if (ehci->frindex == 0x00002000) {
- ehci_raise_irq(ehci, USBSTS_FLR);
- }
-
- if (ehci->frindex == 0x00004000) {
- ehci_raise_irq(ehci, USBSTS_FLR);
- ehci->frindex = 0;
- if (ehci->usbsts_frindex >= 0x00004000) {
- ehci->usbsts_frindex -= 0x00004000;
- } else {
- ehci->usbsts_frindex = 0;
- }
- }
- }
-}
-
-static void ehci_frame_timer(void *opaque)
-{
- EHCIState *ehci = opaque;
- int need_timer = 0;
- int64_t expire_time, t_now;
- uint64_t ns_elapsed;
- int uframes, skipped_uframes;
- int i;
-
- t_now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- ns_elapsed = t_now - ehci->last_run_ns;
- uframes = ns_elapsed / UFRAME_TIMER_NS;
-
- if (ehci_periodic_enabled(ehci) || ehci->pstate != EST_INACTIVE) {
- need_timer++;
-
- if (uframes > (ehci->maxframes * 8)) {
- skipped_uframes = uframes - (ehci->maxframes * 8);
- ehci_update_frindex(ehci, skipped_uframes);
- ehci->last_run_ns += UFRAME_TIMER_NS * skipped_uframes;
- uframes -= skipped_uframes;
- DPRINTF("WARNING - EHCI skipped %d uframes\n", skipped_uframes);
- }
-
- for (i = 0; i < uframes; i++) {
- /*
- * If we're running behind schedule, we should not catch up
- * too fast, as that will make some guests unhappy:
- * 1) We must process a minimum of MIN_UFR_PER_TICK frames,
- * otherwise we will never catch up
- * 2) Process frames until the guest has requested an irq (IOC)
- */
- if (i >= MIN_UFR_PER_TICK) {
- ehci_commit_irq(ehci);
- if ((ehci->usbsts & USBINTR_MASK) & ehci->usbintr) {
- break;
- }
- }
- if (ehci->periodic_sched_active) {
- ehci->periodic_sched_active--;
- }
- ehci_update_frindex(ehci, 1);
- if ((ehci->frindex & 7) == 0) {
- ehci_advance_periodic_state(ehci);
- }
- ehci->last_run_ns += UFRAME_TIMER_NS;
- }
- } else {
- ehci->periodic_sched_active = 0;
- ehci_update_frindex(ehci, uframes);
- ehci->last_run_ns += UFRAME_TIMER_NS * uframes;
- }
-
- if (ehci->periodic_sched_active) {
- ehci->async_stepdown = 0;
- } else if (ehci->async_stepdown < ehci->maxframes / 2) {
- ehci->async_stepdown++;
- }
-
- /* Async is not inside loop since it executes everything it can once
- * called
- */
- if (ehci_async_enabled(ehci) || ehci->astate != EST_INACTIVE) {
- need_timer++;
- ehci_advance_async_state(ehci);
- }
-
- ehci_commit_irq(ehci);
- if (ehci->usbsts_pending) {
- need_timer++;
- ehci->async_stepdown = 0;
- }
-
- if (ehci_enabled(ehci) && (ehci->usbintr & USBSTS_FLR)) {
- need_timer++;
- }
-
- if (need_timer) {
- /* If we've raised int, we speed up the timer, so that we quickly
- * notice any new packets queued up in response */
- if (ehci->int_req_by_async && (ehci->usbsts & USBSTS_INT)) {
- expire_time = t_now +
- NANOSECONDS_PER_SECOND / (FRAME_TIMER_FREQ * 4);
- ehci->int_req_by_async = false;
- } else {
- expire_time = t_now + (NANOSECONDS_PER_SECOND
- * (ehci->async_stepdown+1) / FRAME_TIMER_FREQ);
- }
- timer_mod(ehci->frame_timer, expire_time);
- }
-}
-
-static const MemoryRegionOps ehci_mmio_caps_ops = {
- .read = ehci_caps_read,
- .write = ehci_caps_write,
- .valid.min_access_size = 1,
- .valid.max_access_size = 4,
- .impl.min_access_size = 1,
- .impl.max_access_size = 1,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static const MemoryRegionOps ehci_mmio_opreg_ops = {
- .read = ehci_opreg_read,
- .write = ehci_opreg_write,
- .valid.min_access_size = 4,
- .valid.max_access_size = 4,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static const MemoryRegionOps ehci_mmio_port_ops = {
- .read = ehci_port_read,
- .write = ehci_port_write,
- .valid.min_access_size = 4,
- .valid.max_access_size = 4,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static USBPortOps ehci_port_ops = {
- .attach = ehci_attach,
- .detach = ehci_detach,
- .child_detach = ehci_child_detach,
- .wakeup = ehci_wakeup,
- .complete = ehci_async_complete_packet,
-};
-
-static USBBusOps ehci_bus_ops_companion = {
- .register_companion = ehci_register_companion,
- .wakeup_endpoint = ehci_wakeup_endpoint,
-};
-static USBBusOps ehci_bus_ops_standalone = {
- .wakeup_endpoint = ehci_wakeup_endpoint,
-};
-
-static void usb_ehci_pre_save(void *opaque)
-{
- EHCIState *ehci = opaque;
- uint32_t new_frindex;
-
- /* Round down frindex to a multiple of 8 for migration compatibility */
- new_frindex = ehci->frindex & ~7;
- ehci->last_run_ns -= (ehci->frindex - new_frindex) * UFRAME_TIMER_NS;
- ehci->frindex = new_frindex;
-}
-
-static int usb_ehci_post_load(void *opaque, int version_id)
-{
- EHCIState *s = opaque;
- int i;
-
- for (i = 0; i < NB_PORTS; i++) {
- USBPort *companion = s->companion_ports[i];
- if (companion == NULL) {
- continue;
- }
- if (s->portsc[i] & PORTSC_POWNER) {
- companion->dev = s->ports[i].dev;
- } else {
- companion->dev = NULL;
- }
- }
-
- return 0;
-}
-
-static void usb_ehci_vm_state_change(void *opaque, int running, RunState state)
-{
- EHCIState *ehci = opaque;
-
- /*
- * We don't migrate the EHCIQueue-s, instead we rebuild them for the
- * schedule in guest memory. We must do the rebuilt ASAP, so that
- * USB-devices which have async handled packages have a packet in the
- * ep queue to match the completion with.
- */
- if (state == RUN_STATE_RUNNING) {
- ehci_advance_async_state(ehci);
- }
-
- /*
- * The schedule rebuilt from guest memory could cause the migration dest
- * to miss a QH unlink, and fail to cancel packets, since the unlinked QH
- * will never have existed on the destination. Therefor we must flush the
- * async schedule on savevm to catch any not yet noticed unlinks.
- */
- if (state == RUN_STATE_SAVE_VM) {
- ehci_advance_async_state(ehci);
- ehci_queues_rip_unseen(ehci, 1);
- }
-}
-
-const VMStateDescription vmstate_ehci = {
- .name = "ehci-core",
- .version_id = 2,
- .minimum_version_id = 1,
- .pre_save = usb_ehci_pre_save,
- .post_load = usb_ehci_post_load,
- .fields = (VMStateField[]) {
- /* mmio registers */
- VMSTATE_UINT32(usbcmd, EHCIState),
- VMSTATE_UINT32(usbsts, EHCIState),
- VMSTATE_UINT32_V(usbsts_pending, EHCIState, 2),
- VMSTATE_UINT32_V(usbsts_frindex, EHCIState, 2),
- VMSTATE_UINT32(usbintr, EHCIState),
- VMSTATE_UINT32(frindex, EHCIState),
- VMSTATE_UINT32(ctrldssegment, EHCIState),
- VMSTATE_UINT32(periodiclistbase, EHCIState),
- VMSTATE_UINT32(asynclistaddr, EHCIState),
- VMSTATE_UINT32(configflag, EHCIState),
- VMSTATE_UINT32(portsc[0], EHCIState),
- VMSTATE_UINT32(portsc[1], EHCIState),
- VMSTATE_UINT32(portsc[2], EHCIState),
- VMSTATE_UINT32(portsc[3], EHCIState),
- VMSTATE_UINT32(portsc[4], EHCIState),
- VMSTATE_UINT32(portsc[5], EHCIState),
- /* frame timer */
- VMSTATE_TIMER_PTR(frame_timer, EHCIState),
- VMSTATE_UINT64(last_run_ns, EHCIState),
- VMSTATE_UINT32(async_stepdown, EHCIState),
- /* schedule state */
- VMSTATE_UINT32(astate, EHCIState),
- VMSTATE_UINT32(pstate, EHCIState),
- VMSTATE_UINT32(a_fetch_addr, EHCIState),
- VMSTATE_UINT32(p_fetch_addr, EHCIState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-void usb_ehci_realize(EHCIState *s, DeviceState *dev, Error **errp)
-{
- int i;
-
- if (s->portnr > NB_PORTS) {
- error_setg(errp, "Too many ports! Max. port number is %d.",
- NB_PORTS);
- return;
- }
-
- usb_bus_new(&s->bus, sizeof(s->bus), s->companion_enable ?
- &ehci_bus_ops_companion : &ehci_bus_ops_standalone, dev);
- for (i = 0; i < s->portnr; i++) {
- usb_register_port(&s->bus, &s->ports[i], s, i, &ehci_port_ops,
- USB_SPEED_MASK_HIGH);
- s->ports[i].dev = 0;
- }
-
- s->frame_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ehci_frame_timer, s);
- s->async_bh = qemu_bh_new(ehci_frame_timer, s);
- s->device = dev;
-
- s->vmstate = qemu_add_vm_change_state_handler(usb_ehci_vm_state_change, s);
-}
-
-void usb_ehci_unrealize(EHCIState *s, DeviceState *dev, Error **errp)
-{
- trace_usb_ehci_unrealize();
-
- if (s->frame_timer) {
- timer_del(s->frame_timer);
- timer_free(s->frame_timer);
- s->frame_timer = NULL;
- }
- if (s->async_bh) {
- qemu_bh_delete(s->async_bh);
- }
-
- ehci_queues_rip_all(s, 0);
- ehci_queues_rip_all(s, 1);
-
- memory_region_del_subregion(&s->mem, &s->mem_caps);
- memory_region_del_subregion(&s->mem, &s->mem_opreg);
- memory_region_del_subregion(&s->mem, &s->mem_ports);
-
- usb_bus_release(&s->bus);
-
- if (s->vmstate) {
- qemu_del_vm_change_state_handler(s->vmstate);
- }
-}
-
-void usb_ehci_init(EHCIState *s, DeviceState *dev)
-{
- /* 2.2 host controller interface version */
- s->caps[0x00] = (uint8_t)(s->opregbase - s->capsbase);
- s->caps[0x01] = 0x00;
- s->caps[0x02] = 0x00;
- s->caps[0x03] = 0x01; /* HC version */
- s->caps[0x04] = s->portnr; /* Number of downstream ports */
- s->caps[0x05] = 0x00; /* No companion ports at present */
- s->caps[0x06] = 0x00;
- s->caps[0x07] = 0x00;
- s->caps[0x08] = 0x80; /* We can cache whole frame, no 64-bit */
- s->caps[0x0a] = 0x00;
- s->caps[0x0b] = 0x00;
-
- QTAILQ_INIT(&s->aqueues);
- QTAILQ_INIT(&s->pqueues);
- usb_packet_init(&s->ipacket);
-
- memory_region_init(&s->mem, OBJECT(dev), "ehci", MMIO_SIZE);
- memory_region_init_io(&s->mem_caps, OBJECT(dev), &ehci_mmio_caps_ops, s,
- "capabilities", CAPA_SIZE);
- memory_region_init_io(&s->mem_opreg, OBJECT(dev), &ehci_mmio_opreg_ops, s,
- "operational", s->portscbase);
- memory_region_init_io(&s->mem_ports, OBJECT(dev), &ehci_mmio_port_ops, s,
- "ports", 4 * s->portnr);
-
- memory_region_add_subregion(&s->mem, s->capsbase, &s->mem_caps);
- memory_region_add_subregion(&s->mem, s->opregbase, &s->mem_opreg);
- memory_region_add_subregion(&s->mem, s->opregbase + s->portscbase,
- &s->mem_ports);
-}
-
-/*
- * vim: expandtab ts=4
- */
diff --git a/qemu/hw/usb/hcd-ehci.h b/qemu/hw/usb/hcd-ehci.h
deleted file mode 100644
index 30218423c..000000000
--- a/qemu/hw/usb/hcd-ehci.h
+++ /dev/null
@@ -1,383 +0,0 @@
-/*
- * QEMU USB EHCI Emulation
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or(at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#ifndef HW_USB_EHCI_H
-#define HW_USB_EHCI_H 1
-
-#include "hw/hw.h"
-#include "qemu/timer.h"
-#include "hw/usb.h"
-#include "sysemu/dma.h"
-#include "sysemu/sysemu.h"
-#include "hw/pci/pci.h"
-#include "hw/sysbus.h"
-
-#ifndef EHCI_DEBUG
-#define EHCI_DEBUG 0
-#endif
-
-#if EHCI_DEBUG
-#define DPRINTF printf
-#else
-#define DPRINTF(...)
-#endif
-
-#define MMIO_SIZE 0x1000
-#define CAPA_SIZE 0x10
-
-#define NB_PORTS 6 /* Max. Number of downstream ports */
-
-typedef struct EHCIPacket EHCIPacket;
-typedef struct EHCIQueue EHCIQueue;
-typedef struct EHCIState EHCIState;
-
-/* EHCI spec version 1.0 Section 3.3
- */
-typedef struct EHCIitd {
- uint32_t next;
-
- uint32_t transact[8];
-#define ITD_XACT_ACTIVE (1 << 31)
-#define ITD_XACT_DBERROR (1 << 30)
-#define ITD_XACT_BABBLE (1 << 29)
-#define ITD_XACT_XACTERR (1 << 28)
-#define ITD_XACT_LENGTH_MASK 0x0fff0000
-#define ITD_XACT_LENGTH_SH 16
-#define ITD_XACT_IOC (1 << 15)
-#define ITD_XACT_PGSEL_MASK 0x00007000
-#define ITD_XACT_PGSEL_SH 12
-#define ITD_XACT_OFFSET_MASK 0x00000fff
-
- uint32_t bufptr[7];
-#define ITD_BUFPTR_MASK 0xfffff000
-#define ITD_BUFPTR_SH 12
-#define ITD_BUFPTR_EP_MASK 0x00000f00
-#define ITD_BUFPTR_EP_SH 8
-#define ITD_BUFPTR_DEVADDR_MASK 0x0000007f
-#define ITD_BUFPTR_DEVADDR_SH 0
-#define ITD_BUFPTR_DIRECTION (1 << 11)
-#define ITD_BUFPTR_MAXPKT_MASK 0x000007ff
-#define ITD_BUFPTR_MAXPKT_SH 0
-#define ITD_BUFPTR_MULT_MASK 0x00000003
-#define ITD_BUFPTR_MULT_SH 0
-} EHCIitd;
-
-/* EHCI spec version 1.0 Section 3.4
- */
-typedef struct EHCIsitd {
- uint32_t next; /* Standard next link pointer */
- uint32_t epchar;
-#define SITD_EPCHAR_IO (1 << 31)
-#define SITD_EPCHAR_PORTNUM_MASK 0x7f000000
-#define SITD_EPCHAR_PORTNUM_SH 24
-#define SITD_EPCHAR_HUBADD_MASK 0x007f0000
-#define SITD_EPCHAR_HUBADDR_SH 16
-#define SITD_EPCHAR_EPNUM_MASK 0x00000f00
-#define SITD_EPCHAR_EPNUM_SH 8
-#define SITD_EPCHAR_DEVADDR_MASK 0x0000007f
-
- uint32_t uframe;
-#define SITD_UFRAME_CMASK_MASK 0x0000ff00
-#define SITD_UFRAME_CMASK_SH 8
-#define SITD_UFRAME_SMASK_MASK 0x000000ff
-
- uint32_t results;
-#define SITD_RESULTS_IOC (1 << 31)
-#define SITD_RESULTS_PGSEL (1 << 30)
-#define SITD_RESULTS_TBYTES_MASK 0x03ff0000
-#define SITD_RESULTS_TYBYTES_SH 16
-#define SITD_RESULTS_CPROGMASK_MASK 0x0000ff00
-#define SITD_RESULTS_CPROGMASK_SH 8
-#define SITD_RESULTS_ACTIVE (1 << 7)
-#define SITD_RESULTS_ERR (1 << 6)
-#define SITD_RESULTS_DBERR (1 << 5)
-#define SITD_RESULTS_BABBLE (1 << 4)
-#define SITD_RESULTS_XACTERR (1 << 3)
-#define SITD_RESULTS_MISSEDUF (1 << 2)
-#define SITD_RESULTS_SPLITXSTATE (1 << 1)
-
- uint32_t bufptr[2];
-#define SITD_BUFPTR_MASK 0xfffff000
-#define SITD_BUFPTR_CURROFF_MASK 0x00000fff
-#define SITD_BUFPTR_TPOS_MASK 0x00000018
-#define SITD_BUFPTR_TPOS_SH 3
-#define SITD_BUFPTR_TCNT_MASK 0x00000007
-
- uint32_t backptr; /* Standard next link pointer */
-} EHCIsitd;
-
-/* EHCI spec version 1.0 Section 3.5
- */
-typedef struct EHCIqtd {
- uint32_t next; /* Standard next link pointer */
- uint32_t altnext; /* Standard next link pointer */
- uint32_t token;
-#define QTD_TOKEN_DTOGGLE (1 << 31)
-#define QTD_TOKEN_TBYTES_MASK 0x7fff0000
-#define QTD_TOKEN_TBYTES_SH 16
-#define QTD_TOKEN_IOC (1 << 15)
-#define QTD_TOKEN_CPAGE_MASK 0x00007000
-#define QTD_TOKEN_CPAGE_SH 12
-#define QTD_TOKEN_CERR_MASK 0x00000c00
-#define QTD_TOKEN_CERR_SH 10
-#define QTD_TOKEN_PID_MASK 0x00000300
-#define QTD_TOKEN_PID_SH 8
-#define QTD_TOKEN_ACTIVE (1 << 7)
-#define QTD_TOKEN_HALT (1 << 6)
-#define QTD_TOKEN_DBERR (1 << 5)
-#define QTD_TOKEN_BABBLE (1 << 4)
-#define QTD_TOKEN_XACTERR (1 << 3)
-#define QTD_TOKEN_MISSEDUF (1 << 2)
-#define QTD_TOKEN_SPLITXSTATE (1 << 1)
-#define QTD_TOKEN_PING (1 << 0)
-
- uint32_t bufptr[5]; /* Standard buffer pointer */
-#define QTD_BUFPTR_MASK 0xfffff000
-#define QTD_BUFPTR_SH 12
-} EHCIqtd;
-
-/* EHCI spec version 1.0 Section 3.6
- */
-typedef struct EHCIqh {
- uint32_t next; /* Standard next link pointer */
-
- /* endpoint characteristics */
- uint32_t epchar;
-#define QH_EPCHAR_RL_MASK 0xf0000000
-#define QH_EPCHAR_RL_SH 28
-#define QH_EPCHAR_C (1 << 27)
-#define QH_EPCHAR_MPLEN_MASK 0x07FF0000
-#define QH_EPCHAR_MPLEN_SH 16
-#define QH_EPCHAR_H (1 << 15)
-#define QH_EPCHAR_DTC (1 << 14)
-#define QH_EPCHAR_EPS_MASK 0x00003000
-#define QH_EPCHAR_EPS_SH 12
-#define EHCI_QH_EPS_FULL 0
-#define EHCI_QH_EPS_LOW 1
-#define EHCI_QH_EPS_HIGH 2
-#define EHCI_QH_EPS_RESERVED 3
-
-#define QH_EPCHAR_EP_MASK 0x00000f00
-#define QH_EPCHAR_EP_SH 8
-#define QH_EPCHAR_I (1 << 7)
-#define QH_EPCHAR_DEVADDR_MASK 0x0000007f
-#define QH_EPCHAR_DEVADDR_SH 0
-
- /* endpoint capabilities */
- uint32_t epcap;
-#define QH_EPCAP_MULT_MASK 0xc0000000
-#define QH_EPCAP_MULT_SH 30
-#define QH_EPCAP_PORTNUM_MASK 0x3f800000
-#define QH_EPCAP_PORTNUM_SH 23
-#define QH_EPCAP_HUBADDR_MASK 0x007f0000
-#define QH_EPCAP_HUBADDR_SH 16
-#define QH_EPCAP_CMASK_MASK 0x0000ff00
-#define QH_EPCAP_CMASK_SH 8
-#define QH_EPCAP_SMASK_MASK 0x000000ff
-#define QH_EPCAP_SMASK_SH 0
-
- uint32_t current_qtd; /* Standard next link pointer */
- uint32_t next_qtd; /* Standard next link pointer */
- uint32_t altnext_qtd;
-#define QH_ALTNEXT_NAKCNT_MASK 0x0000001e
-#define QH_ALTNEXT_NAKCNT_SH 1
-
- uint32_t token; /* Same as QTD token */
- uint32_t bufptr[5]; /* Standard buffer pointer */
-#define BUFPTR_CPROGMASK_MASK 0x000000ff
-#define BUFPTR_FRAMETAG_MASK 0x0000001f
-#define BUFPTR_SBYTES_MASK 0x00000fe0
-#define BUFPTR_SBYTES_SH 5
-} EHCIqh;
-
-/* EHCI spec version 1.0 Section 3.7
- */
-typedef struct EHCIfstn {
- uint32_t next; /* Standard next link pointer */
- uint32_t backptr; /* Standard next link pointer */
-} EHCIfstn;
-
-enum async_state {
- EHCI_ASYNC_NONE = 0,
- EHCI_ASYNC_INITIALIZED,
- EHCI_ASYNC_INFLIGHT,
- EHCI_ASYNC_FINISHED,
-};
-
-struct EHCIPacket {
- EHCIQueue *queue;
- QTAILQ_ENTRY(EHCIPacket) next;
-
- EHCIqtd qtd; /* copy of current QTD (being worked on) */
- uint32_t qtdaddr; /* address QTD read from */
-
- USBPacket packet;
- QEMUSGList sgl;
- int pid;
- enum async_state async;
-};
-
-struct EHCIQueue {
- EHCIState *ehci;
- QTAILQ_ENTRY(EHCIQueue) next;
- uint32_t seen;
- uint64_t ts;
- int async;
- int transact_ctr;
-
- /* cached data from guest - needs to be flushed
- * when guest removes an entry (doorbell, handshake sequence)
- */
- EHCIqh qh; /* copy of current QH (being worked on) */
- uint32_t qhaddr; /* address QH read from */
- uint32_t qtdaddr; /* address QTD read from */
- int last_pid; /* pid of last packet executed */
- USBDevice *dev;
- QTAILQ_HEAD(pkts_head, EHCIPacket) packets;
-};
-
-typedef QTAILQ_HEAD(EHCIQueueHead, EHCIQueue) EHCIQueueHead;
-
-struct EHCIState {
- USBBus bus;
- DeviceState *device;
- qemu_irq irq;
- MemoryRegion mem;
- AddressSpace *as;
- MemoryRegion mem_caps;
- MemoryRegion mem_opreg;
- MemoryRegion mem_ports;
- int companion_count;
- bool companion_enable;
- uint16_t capsbase;
- uint16_t opregbase;
- uint16_t portscbase;
- uint16_t portnr;
-
- /* properties */
- uint32_t maxframes;
-
- /*
- * EHCI spec version 1.0 Section 2.3
- * Host Controller Operational Registers
- */
- uint8_t caps[CAPA_SIZE];
- union {
- uint32_t opreg[0x44/sizeof(uint32_t)];
- struct {
- uint32_t usbcmd;
- uint32_t usbsts;
- uint32_t usbintr;
- uint32_t frindex;
- uint32_t ctrldssegment;
- uint32_t periodiclistbase;
- uint32_t asynclistaddr;
- uint32_t notused[9];
- uint32_t configflag;
- };
- };
- uint32_t portsc[NB_PORTS];
-
- /*
- * Internal states, shadow registers, etc
- */
- QEMUTimer *frame_timer;
- QEMUBH *async_bh;
- uint32_t astate; /* Current state in asynchronous schedule */
- uint32_t pstate; /* Current state in periodic schedule */
- USBPort ports[NB_PORTS];
- USBPort *companion_ports[NB_PORTS];
- uint32_t usbsts_pending;
- uint32_t usbsts_frindex;
- EHCIQueueHead aqueues;
- EHCIQueueHead pqueues;
-
- /* which address to look at next */
- uint32_t a_fetch_addr;
- uint32_t p_fetch_addr;
-
- USBPacket ipacket;
- QEMUSGList isgl;
-
- uint64_t last_run_ns;
- uint32_t async_stepdown;
- uint32_t periodic_sched_active;
- bool int_req_by_async;
- VMChangeStateEntry *vmstate;
-};
-
-extern const VMStateDescription vmstate_ehci;
-
-void usb_ehci_init(EHCIState *s, DeviceState *dev);
-void usb_ehci_realize(EHCIState *s, DeviceState *dev, Error **errp);
-void usb_ehci_unrealize(EHCIState *s, DeviceState *dev, Error **errp);
-void ehci_reset(void *opaque);
-
-#define TYPE_PCI_EHCI "pci-ehci-usb"
-#define PCI_EHCI(obj) OBJECT_CHECK(EHCIPCIState, (obj), TYPE_PCI_EHCI)
-
-typedef struct EHCIPCIState {
- /*< private >*/
- PCIDevice pcidev;
- /*< public >*/
-
- EHCIState ehci;
-} EHCIPCIState;
-
-
-#define TYPE_SYS_BUS_EHCI "sysbus-ehci-usb"
-#define TYPE_EXYNOS4210_EHCI "exynos4210-ehci-usb"
-#define TYPE_TEGRA2_EHCI "tegra2-ehci-usb"
-#define TYPE_FUSBH200_EHCI "fusbh200-ehci-usb"
-
-#define SYS_BUS_EHCI(obj) \
- OBJECT_CHECK(EHCISysBusState, (obj), TYPE_SYS_BUS_EHCI)
-#define SYS_BUS_EHCI_CLASS(class) \
- OBJECT_CLASS_CHECK(SysBusEHCIClass, (class), TYPE_SYS_BUS_EHCI)
-#define SYS_BUS_EHCI_GET_CLASS(obj) \
- OBJECT_GET_CLASS(SysBusEHCIClass, (obj), TYPE_SYS_BUS_EHCI)
-
-typedef struct EHCISysBusState {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- EHCIState ehci;
-} EHCISysBusState;
-
-typedef struct SysBusEHCIClass {
- /*< private >*/
- SysBusDeviceClass parent_class;
- /*< public >*/
-
- uint16_t capsbase;
- uint16_t opregbase;
- uint16_t portscbase;
- uint16_t portnr;
-} SysBusEHCIClass;
-
-#define FUSBH200_EHCI(obj) \
- OBJECT_CHECK(FUSBH200EHCIState, (obj), TYPE_FUSBH200_EHCI)
-
-typedef struct FUSBH200EHCIState {
- /*< private >*/
- EHCISysBusState parent_obj;
- /*< public >*/
-
- MemoryRegion mem_vendor;
-} FUSBH200EHCIState;
-
-#endif
diff --git a/qemu/hw/usb/hcd-musb.c b/qemu/hw/usb/hcd-musb.c
deleted file mode 100644
index 27d9d0bd8..000000000
--- a/qemu/hw/usb/hcd-musb.c
+++ /dev/null
@@ -1,1553 +0,0 @@
-/*
- * "Inventra" High-speed Dual-Role Controller (MUSB-HDRC), Mentor Graphics,
- * USB2.0 OTG compliant core used in various chips.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- * Only host-mode and non-DMA accesses are currently supported.
- */
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "qemu/timer.h"
-#include "hw/usb.h"
-#include "hw/irq.h"
-#include "hw/hw.h"
-
-/* Common USB registers */
-#define MUSB_HDRC_FADDR 0x00 /* 8-bit */
-#define MUSB_HDRC_POWER 0x01 /* 8-bit */
-
-#define MUSB_HDRC_INTRTX 0x02 /* 16-bit */
-#define MUSB_HDRC_INTRRX 0x04
-#define MUSB_HDRC_INTRTXE 0x06
-#define MUSB_HDRC_INTRRXE 0x08
-#define MUSB_HDRC_INTRUSB 0x0a /* 8 bit */
-#define MUSB_HDRC_INTRUSBE 0x0b /* 8 bit */
-#define MUSB_HDRC_FRAME 0x0c /* 16-bit */
-#define MUSB_HDRC_INDEX 0x0e /* 8 bit */
-#define MUSB_HDRC_TESTMODE 0x0f /* 8 bit */
-
-/* Per-EP registers in indexed mode */
-#define MUSB_HDRC_EP_IDX 0x10 /* 8-bit */
-
-/* EP FIFOs */
-#define MUSB_HDRC_FIFO 0x20
-
-/* Additional Control Registers */
-#define MUSB_HDRC_DEVCTL 0x60 /* 8 bit */
-
-/* These are indexed */
-#define MUSB_HDRC_TXFIFOSZ 0x62 /* 8 bit (see masks) */
-#define MUSB_HDRC_RXFIFOSZ 0x63 /* 8 bit (see masks) */
-#define MUSB_HDRC_TXFIFOADDR 0x64 /* 16 bit offset shifted right 3 */
-#define MUSB_HDRC_RXFIFOADDR 0x66 /* 16 bit offset shifted right 3 */
-
-/* Some more registers */
-#define MUSB_HDRC_VCTRL 0x68 /* 8 bit */
-#define MUSB_HDRC_HWVERS 0x6c /* 8 bit */
-
-/* Added in HDRC 1.9(?) & MHDRC 1.4 */
-/* ULPI pass-through */
-#define MUSB_HDRC_ULPI_VBUSCTL 0x70
-#define MUSB_HDRC_ULPI_REGDATA 0x74
-#define MUSB_HDRC_ULPI_REGADDR 0x75
-#define MUSB_HDRC_ULPI_REGCTL 0x76
-
-/* Extended config & PHY control */
-#define MUSB_HDRC_ENDCOUNT 0x78 /* 8 bit */
-#define MUSB_HDRC_DMARAMCFG 0x79 /* 8 bit */
-#define MUSB_HDRC_PHYWAIT 0x7a /* 8 bit */
-#define MUSB_HDRC_PHYVPLEN 0x7b /* 8 bit */
-#define MUSB_HDRC_HS_EOF1 0x7c /* 8 bit, units of 546.1 us */
-#define MUSB_HDRC_FS_EOF1 0x7d /* 8 bit, units of 533.3 ns */
-#define MUSB_HDRC_LS_EOF1 0x7e /* 8 bit, units of 1.067 us */
-
-/* Per-EP BUSCTL registers */
-#define MUSB_HDRC_BUSCTL 0x80
-
-/* Per-EP registers in flat mode */
-#define MUSB_HDRC_EP 0x100
-
-/* offsets to registers in flat model */
-#define MUSB_HDRC_TXMAXP 0x00 /* 16 bit apparently */
-#define MUSB_HDRC_TXCSR 0x02 /* 16 bit apparently */
-#define MUSB_HDRC_CSR0 MUSB_HDRC_TXCSR /* re-used for EP0 */
-#define MUSB_HDRC_RXMAXP 0x04 /* 16 bit apparently */
-#define MUSB_HDRC_RXCSR 0x06 /* 16 bit apparently */
-#define MUSB_HDRC_RXCOUNT 0x08 /* 16 bit apparently */
-#define MUSB_HDRC_COUNT0 MUSB_HDRC_RXCOUNT /* re-used for EP0 */
-#define MUSB_HDRC_TXTYPE 0x0a /* 8 bit apparently */
-#define MUSB_HDRC_TYPE0 MUSB_HDRC_TXTYPE /* re-used for EP0 */
-#define MUSB_HDRC_TXINTERVAL 0x0b /* 8 bit apparently */
-#define MUSB_HDRC_NAKLIMIT0 MUSB_HDRC_TXINTERVAL /* re-used for EP0 */
-#define MUSB_HDRC_RXTYPE 0x0c /* 8 bit apparently */
-#define MUSB_HDRC_RXINTERVAL 0x0d /* 8 bit apparently */
-#define MUSB_HDRC_FIFOSIZE 0x0f /* 8 bit apparently */
-#define MUSB_HDRC_CONFIGDATA MGC_O_HDRC_FIFOSIZE /* re-used for EP0 */
-
-/* "Bus control" registers */
-#define MUSB_HDRC_TXFUNCADDR 0x00
-#define MUSB_HDRC_TXHUBADDR 0x02
-#define MUSB_HDRC_TXHUBPORT 0x03
-
-#define MUSB_HDRC_RXFUNCADDR 0x04
-#define MUSB_HDRC_RXHUBADDR 0x06
-#define MUSB_HDRC_RXHUBPORT 0x07
-
-/*
- * MUSBHDRC Register bit masks
- */
-
-/* POWER */
-#define MGC_M_POWER_ISOUPDATE 0x80
-#define MGC_M_POWER_SOFTCONN 0x40
-#define MGC_M_POWER_HSENAB 0x20
-#define MGC_M_POWER_HSMODE 0x10
-#define MGC_M_POWER_RESET 0x08
-#define MGC_M_POWER_RESUME 0x04
-#define MGC_M_POWER_SUSPENDM 0x02
-#define MGC_M_POWER_ENSUSPEND 0x01
-
-/* INTRUSB */
-#define MGC_M_INTR_SUSPEND 0x01
-#define MGC_M_INTR_RESUME 0x02
-#define MGC_M_INTR_RESET 0x04
-#define MGC_M_INTR_BABBLE 0x04
-#define MGC_M_INTR_SOF 0x08
-#define MGC_M_INTR_CONNECT 0x10
-#define MGC_M_INTR_DISCONNECT 0x20
-#define MGC_M_INTR_SESSREQ 0x40
-#define MGC_M_INTR_VBUSERROR 0x80 /* FOR SESSION END */
-#define MGC_M_INTR_EP0 0x01 /* FOR EP0 INTERRUPT */
-
-/* DEVCTL */
-#define MGC_M_DEVCTL_BDEVICE 0x80
-#define MGC_M_DEVCTL_FSDEV 0x40
-#define MGC_M_DEVCTL_LSDEV 0x20
-#define MGC_M_DEVCTL_VBUS 0x18
-#define MGC_S_DEVCTL_VBUS 3
-#define MGC_M_DEVCTL_HM 0x04
-#define MGC_M_DEVCTL_HR 0x02
-#define MGC_M_DEVCTL_SESSION 0x01
-
-/* TESTMODE */
-#define MGC_M_TEST_FORCE_HOST 0x80
-#define MGC_M_TEST_FIFO_ACCESS 0x40
-#define MGC_M_TEST_FORCE_FS 0x20
-#define MGC_M_TEST_FORCE_HS 0x10
-#define MGC_M_TEST_PACKET 0x08
-#define MGC_M_TEST_K 0x04
-#define MGC_M_TEST_J 0x02
-#define MGC_M_TEST_SE0_NAK 0x01
-
-/* CSR0 */
-#define MGC_M_CSR0_FLUSHFIFO 0x0100
-#define MGC_M_CSR0_TXPKTRDY 0x0002
-#define MGC_M_CSR0_RXPKTRDY 0x0001
-
-/* CSR0 in Peripheral mode */
-#define MGC_M_CSR0_P_SVDSETUPEND 0x0080
-#define MGC_M_CSR0_P_SVDRXPKTRDY 0x0040
-#define MGC_M_CSR0_P_SENDSTALL 0x0020
-#define MGC_M_CSR0_P_SETUPEND 0x0010
-#define MGC_M_CSR0_P_DATAEND 0x0008
-#define MGC_M_CSR0_P_SENTSTALL 0x0004
-
-/* CSR0 in Host mode */
-#define MGC_M_CSR0_H_NO_PING 0x0800
-#define MGC_M_CSR0_H_WR_DATATOGGLE 0x0400 /* set to allow setting: */
-#define MGC_M_CSR0_H_DATATOGGLE 0x0200 /* data toggle control */
-#define MGC_M_CSR0_H_NAKTIMEOUT 0x0080
-#define MGC_M_CSR0_H_STATUSPKT 0x0040
-#define MGC_M_CSR0_H_REQPKT 0x0020
-#define MGC_M_CSR0_H_ERROR 0x0010
-#define MGC_M_CSR0_H_SETUPPKT 0x0008
-#define MGC_M_CSR0_H_RXSTALL 0x0004
-
-/* CONFIGDATA */
-#define MGC_M_CONFIGDATA_MPRXE 0x80 /* auto bulk pkt combining */
-#define MGC_M_CONFIGDATA_MPTXE 0x40 /* auto bulk pkt splitting */
-#define MGC_M_CONFIGDATA_BIGENDIAN 0x20
-#define MGC_M_CONFIGDATA_HBRXE 0x10 /* HB-ISO for RX */
-#define MGC_M_CONFIGDATA_HBTXE 0x08 /* HB-ISO for TX */
-#define MGC_M_CONFIGDATA_DYNFIFO 0x04 /* dynamic FIFO sizing */
-#define MGC_M_CONFIGDATA_SOFTCONE 0x02 /* SoftConnect */
-#define MGC_M_CONFIGDATA_UTMIDW 0x01 /* Width, 0 => 8b, 1 => 16b */
-
-/* TXCSR in Peripheral and Host mode */
-#define MGC_M_TXCSR_AUTOSET 0x8000
-#define MGC_M_TXCSR_ISO 0x4000
-#define MGC_M_TXCSR_MODE 0x2000
-#define MGC_M_TXCSR_DMAENAB 0x1000
-#define MGC_M_TXCSR_FRCDATATOG 0x0800
-#define MGC_M_TXCSR_DMAMODE 0x0400
-#define MGC_M_TXCSR_CLRDATATOG 0x0040
-#define MGC_M_TXCSR_FLUSHFIFO 0x0008
-#define MGC_M_TXCSR_FIFONOTEMPTY 0x0002
-#define MGC_M_TXCSR_TXPKTRDY 0x0001
-
-/* TXCSR in Peripheral mode */
-#define MGC_M_TXCSR_P_INCOMPTX 0x0080
-#define MGC_M_TXCSR_P_SENTSTALL 0x0020
-#define MGC_M_TXCSR_P_SENDSTALL 0x0010
-#define MGC_M_TXCSR_P_UNDERRUN 0x0004
-
-/* TXCSR in Host mode */
-#define MGC_M_TXCSR_H_WR_DATATOGGLE 0x0200
-#define MGC_M_TXCSR_H_DATATOGGLE 0x0100
-#define MGC_M_TXCSR_H_NAKTIMEOUT 0x0080
-#define MGC_M_TXCSR_H_RXSTALL 0x0020
-#define MGC_M_TXCSR_H_ERROR 0x0004
-
-/* RXCSR in Peripheral and Host mode */
-#define MGC_M_RXCSR_AUTOCLEAR 0x8000
-#define MGC_M_RXCSR_DMAENAB 0x2000
-#define MGC_M_RXCSR_DISNYET 0x1000
-#define MGC_M_RXCSR_DMAMODE 0x0800
-#define MGC_M_RXCSR_INCOMPRX 0x0100
-#define MGC_M_RXCSR_CLRDATATOG 0x0080
-#define MGC_M_RXCSR_FLUSHFIFO 0x0010
-#define MGC_M_RXCSR_DATAERROR 0x0008
-#define MGC_M_RXCSR_FIFOFULL 0x0002
-#define MGC_M_RXCSR_RXPKTRDY 0x0001
-
-/* RXCSR in Peripheral mode */
-#define MGC_M_RXCSR_P_ISO 0x4000
-#define MGC_M_RXCSR_P_SENTSTALL 0x0040
-#define MGC_M_RXCSR_P_SENDSTALL 0x0020
-#define MGC_M_RXCSR_P_OVERRUN 0x0004
-
-/* RXCSR in Host mode */
-#define MGC_M_RXCSR_H_AUTOREQ 0x4000
-#define MGC_M_RXCSR_H_WR_DATATOGGLE 0x0400
-#define MGC_M_RXCSR_H_DATATOGGLE 0x0200
-#define MGC_M_RXCSR_H_RXSTALL 0x0040
-#define MGC_M_RXCSR_H_REQPKT 0x0020
-#define MGC_M_RXCSR_H_ERROR 0x0004
-
-/* HUBADDR */
-#define MGC_M_HUBADDR_MULTI_TT 0x80
-
-/* ULPI: Added in HDRC 1.9(?) & MHDRC 1.4 */
-#define MGC_M_ULPI_VBCTL_USEEXTVBUSIND 0x02
-#define MGC_M_ULPI_VBCTL_USEEXTVBUS 0x01
-#define MGC_M_ULPI_REGCTL_INT_ENABLE 0x08
-#define MGC_M_ULPI_REGCTL_READNOTWRITE 0x04
-#define MGC_M_ULPI_REGCTL_COMPLETE 0x02
-#define MGC_M_ULPI_REGCTL_REG 0x01
-
-/* #define MUSB_DEBUG */
-
-#ifdef MUSB_DEBUG
-#define TRACE(fmt,...) fprintf(stderr, "%s@%d: " fmt "\n", __FUNCTION__, \
- __LINE__, ##__VA_ARGS__)
-#else
-#define TRACE(...)
-#endif
-
-
-static void musb_attach(USBPort *port);
-static void musb_detach(USBPort *port);
-static void musb_child_detach(USBPort *port, USBDevice *child);
-static void musb_schedule_cb(USBPort *port, USBPacket *p);
-static void musb_async_cancel_device(MUSBState *s, USBDevice *dev);
-
-static USBPortOps musb_port_ops = {
- .attach = musb_attach,
- .detach = musb_detach,
- .child_detach = musb_child_detach,
- .complete = musb_schedule_cb,
-};
-
-static USBBusOps musb_bus_ops = {
-};
-
-typedef struct MUSBPacket MUSBPacket;
-typedef struct MUSBEndPoint MUSBEndPoint;
-
-struct MUSBPacket {
- USBPacket p;
- MUSBEndPoint *ep;
- int dir;
-};
-
-struct MUSBEndPoint {
- uint16_t faddr[2];
- uint8_t haddr[2];
- uint8_t hport[2];
- uint16_t csr[2];
- uint16_t maxp[2];
- uint16_t rxcount;
- uint8_t type[2];
- uint8_t interval[2];
- uint8_t config;
- uint8_t fifosize;
- int timeout[2]; /* Always in microframes */
-
- uint8_t *buf[2];
- int fifolen[2];
- int fifostart[2];
- int fifoaddr[2];
- MUSBPacket packey[2];
- int status[2];
- int ext_size[2];
-
- /* For callbacks' use */
- int epnum;
- int interrupt[2];
- MUSBState *musb;
- USBCallback *delayed_cb[2];
- QEMUTimer *intv_timer[2];
-};
-
-struct MUSBState {
- qemu_irq irqs[musb_irq_max];
- USBBus bus;
- USBPort port;
-
- int idx;
- uint8_t devctl;
- uint8_t power;
- uint8_t faddr;
-
- uint8_t intr;
- uint8_t mask;
- uint16_t tx_intr;
- uint16_t tx_mask;
- uint16_t rx_intr;
- uint16_t rx_mask;
-
- int setup_len;
- int session;
-
- uint8_t buf[0x8000];
-
- /* Duplicating the world since 2008!... probably we should have 32
- * logical, single endpoints instead. */
- MUSBEndPoint ep[16];
-};
-
-void musb_reset(MUSBState *s)
-{
- int i;
-
- s->faddr = 0x00;
- s->devctl = 0;
- s->power = MGC_M_POWER_HSENAB;
- s->tx_intr = 0x0000;
- s->rx_intr = 0x0000;
- s->tx_mask = 0xffff;
- s->rx_mask = 0xffff;
- s->intr = 0x00;
- s->mask = 0x06;
- s->idx = 0;
-
- s->setup_len = 0;
- s->session = 0;
- memset(s->buf, 0, sizeof(s->buf));
-
- /* TODO: _DW */
- s->ep[0].config = MGC_M_CONFIGDATA_SOFTCONE | MGC_M_CONFIGDATA_DYNFIFO;
- for (i = 0; i < 16; i ++) {
- s->ep[i].fifosize = 64;
- s->ep[i].maxp[0] = 0x40;
- s->ep[i].maxp[1] = 0x40;
- s->ep[i].musb = s;
- s->ep[i].epnum = i;
- usb_packet_init(&s->ep[i].packey[0].p);
- usb_packet_init(&s->ep[i].packey[1].p);
- }
-}
-
-struct MUSBState *musb_init(DeviceState *parent_device, int gpio_base)
-{
- MUSBState *s = g_malloc0(sizeof(*s));
- int i;
-
- for (i = 0; i < musb_irq_max; i++) {
- s->irqs[i] = qdev_get_gpio_in(parent_device, gpio_base + i);
- }
-
- musb_reset(s);
-
- usb_bus_new(&s->bus, sizeof(s->bus), &musb_bus_ops, parent_device);
- usb_register_port(&s->bus, &s->port, s, 0, &musb_port_ops,
- USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
-
- return s;
-}
-
-static void musb_vbus_set(MUSBState *s, int level)
-{
- if (level)
- s->devctl |= 3 << MGC_S_DEVCTL_VBUS;
- else
- s->devctl &= ~MGC_M_DEVCTL_VBUS;
-
- qemu_set_irq(s->irqs[musb_set_vbus], level);
-}
-
-static void musb_intr_set(MUSBState *s, int line, int level)
-{
- if (!level) {
- s->intr &= ~(1 << line);
- qemu_irq_lower(s->irqs[line]);
- } else if (s->mask & (1 << line)) {
- s->intr |= 1 << line;
- qemu_irq_raise(s->irqs[line]);
- }
-}
-
-static void musb_tx_intr_set(MUSBState *s, int line, int level)
-{
- if (!level) {
- s->tx_intr &= ~(1 << line);
- if (!s->tx_intr)
- qemu_irq_lower(s->irqs[musb_irq_tx]);
- } else if (s->tx_mask & (1 << line)) {
- s->tx_intr |= 1 << line;
- qemu_irq_raise(s->irqs[musb_irq_tx]);
- }
-}
-
-static void musb_rx_intr_set(MUSBState *s, int line, int level)
-{
- if (line) {
- if (!level) {
- s->rx_intr &= ~(1 << line);
- if (!s->rx_intr)
- qemu_irq_lower(s->irqs[musb_irq_rx]);
- } else if (s->rx_mask & (1 << line)) {
- s->rx_intr |= 1 << line;
- qemu_irq_raise(s->irqs[musb_irq_rx]);
- }
- } else
- musb_tx_intr_set(s, line, level);
-}
-
-uint32_t musb_core_intr_get(MUSBState *s)
-{
- return (s->rx_intr << 15) | s->tx_intr;
-}
-
-void musb_core_intr_clear(MUSBState *s, uint32_t mask)
-{
- if (s->rx_intr) {
- s->rx_intr &= mask >> 15;
- if (!s->rx_intr)
- qemu_irq_lower(s->irqs[musb_irq_rx]);
- }
-
- if (s->tx_intr) {
- s->tx_intr &= mask & 0xffff;
- if (!s->tx_intr)
- qemu_irq_lower(s->irqs[musb_irq_tx]);
- }
-}
-
-void musb_set_size(MUSBState *s, int epnum, int size, int is_tx)
-{
- s->ep[epnum].ext_size[!is_tx] = size;
- s->ep[epnum].fifostart[0] = 0;
- s->ep[epnum].fifostart[1] = 0;
- s->ep[epnum].fifolen[0] = 0;
- s->ep[epnum].fifolen[1] = 0;
-}
-
-static void musb_session_update(MUSBState *s, int prev_dev, int prev_sess)
-{
- int detect_prev = prev_dev && prev_sess;
- int detect = !!s->port.dev && s->session;
-
- if (detect && !detect_prev) {
- /* Let's skip the ID pin sense and VBUS sense formalities and
- * and signal a successful SRP directly. This should work at least
- * for the Linux driver stack. */
- musb_intr_set(s, musb_irq_connect, 1);
-
- if (s->port.dev->speed == USB_SPEED_LOW) {
- s->devctl &= ~MGC_M_DEVCTL_FSDEV;
- s->devctl |= MGC_M_DEVCTL_LSDEV;
- } else {
- s->devctl |= MGC_M_DEVCTL_FSDEV;
- s->devctl &= ~MGC_M_DEVCTL_LSDEV;
- }
-
- /* A-mode? */
- s->devctl &= ~MGC_M_DEVCTL_BDEVICE;
-
- /* Host-mode bit? */
- s->devctl |= MGC_M_DEVCTL_HM;
-#if 1
- musb_vbus_set(s, 1);
-#endif
- } else if (!detect && detect_prev) {
-#if 1
- musb_vbus_set(s, 0);
-#endif
- }
-}
-
-/* Attach or detach a device on our only port. */
-static void musb_attach(USBPort *port)
-{
- MUSBState *s = (MUSBState *) port->opaque;
-
- musb_intr_set(s, musb_irq_vbus_request, 1);
- musb_session_update(s, 0, s->session);
-}
-
-static void musb_detach(USBPort *port)
-{
- MUSBState *s = (MUSBState *) port->opaque;
-
- musb_async_cancel_device(s, port->dev);
-
- musb_intr_set(s, musb_irq_disconnect, 1);
- musb_session_update(s, 1, s->session);
-}
-
-static void musb_child_detach(USBPort *port, USBDevice *child)
-{
- MUSBState *s = (MUSBState *) port->opaque;
-
- musb_async_cancel_device(s, child);
-}
-
-static void musb_cb_tick0(void *opaque)
-{
- MUSBEndPoint *ep = (MUSBEndPoint *) opaque;
-
- ep->delayed_cb[0](&ep->packey[0].p, opaque);
-}
-
-static void musb_cb_tick1(void *opaque)
-{
- MUSBEndPoint *ep = (MUSBEndPoint *) opaque;
-
- ep->delayed_cb[1](&ep->packey[1].p, opaque);
-}
-
-#define musb_cb_tick (dir ? musb_cb_tick1 : musb_cb_tick0)
-
-static void musb_schedule_cb(USBPort *port, USBPacket *packey)
-{
- MUSBPacket *p = container_of(packey, MUSBPacket, p);
- MUSBEndPoint *ep = p->ep;
- int dir = p->dir;
- int timeout = 0;
-
- if (ep->status[dir] == USB_RET_NAK)
- timeout = ep->timeout[dir];
- else if (ep->interrupt[dir])
- timeout = 8;
- else {
- musb_cb_tick(ep);
- return;
- }
-
- if (!ep->intv_timer[dir])
- ep->intv_timer[dir] = timer_new_ns(QEMU_CLOCK_VIRTUAL, musb_cb_tick, ep);
-
- timer_mod(ep->intv_timer[dir], qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- muldiv64(timeout, NANOSECONDS_PER_SECOND, 8000));
-}
-
-static int musb_timeout(int ttype, int speed, int val)
-{
-#if 1
- return val << 3;
-#endif
-
- switch (ttype) {
- case USB_ENDPOINT_XFER_CONTROL:
- if (val < 2)
- return 0;
- else if (speed == USB_SPEED_HIGH)
- return 1 << (val - 1);
- else
- return 8 << (val - 1);
-
- case USB_ENDPOINT_XFER_INT:
- if (speed == USB_SPEED_HIGH)
- if (val < 2)
- return 0;
- else
- return 1 << (val - 1);
- else
- return val << 3;
-
- case USB_ENDPOINT_XFER_BULK:
- case USB_ENDPOINT_XFER_ISOC:
- if (val < 2)
- return 0;
- else if (speed == USB_SPEED_HIGH)
- return 1 << (val - 1);
- else
- return 8 << (val - 1);
- /* TODO: what with low-speed Bulk and Isochronous? */
- }
-
- hw_error("bad interval\n");
-}
-
-static void musb_packet(MUSBState *s, MUSBEndPoint *ep,
- int epnum, int pid, int len, USBCallback cb, int dir)
-{
- USBDevice *dev;
- USBEndpoint *uep;
- int idx = epnum && dir;
- int id;
- int ttype;
-
- /* ep->type[0,1] contains:
- * in bits 7:6 the speed (0 - invalid, 1 - high, 2 - full, 3 - slow)
- * in bits 5:4 the transfer type (BULK / INT)
- * in bits 3:0 the EP num
- */
- ttype = epnum ? (ep->type[idx] >> 4) & 3 : 0;
-
- ep->timeout[dir] = musb_timeout(ttype,
- ep->type[idx] >> 6, ep->interval[idx]);
- ep->interrupt[dir] = ttype == USB_ENDPOINT_XFER_INT;
- ep->delayed_cb[dir] = cb;
-
- /* A wild guess on the FADDR semantics... */
- dev = usb_find_device(&s->port, ep->faddr[idx]);
- uep = usb_ep_get(dev, pid, ep->type[idx] & 0xf);
- id = pid;
- if (uep) {
- id |= (dev->addr << 16) | (uep->nr << 8);
- }
- usb_packet_setup(&ep->packey[dir].p, pid, uep, 0, id, false, true);
- usb_packet_addbuf(&ep->packey[dir].p, ep->buf[idx], len);
- ep->packey[dir].ep = ep;
- ep->packey[dir].dir = dir;
-
- usb_handle_packet(dev, &ep->packey[dir].p);
-
- if (ep->packey[dir].p.status == USB_RET_ASYNC) {
- usb_device_flush_ep_queue(dev, uep);
- ep->status[dir] = len;
- return;
- }
-
- if (ep->packey[dir].p.status == USB_RET_SUCCESS) {
- ep->status[dir] = ep->packey[dir].p.actual_length;
- } else {
- ep->status[dir] = ep->packey[dir].p.status;
- }
- musb_schedule_cb(&s->port, &ep->packey[dir].p);
-}
-
-static void musb_tx_packet_complete(USBPacket *packey, void *opaque)
-{
- /* Unfortunately we can't use packey->devep because that's the remote
- * endpoint number and may be different than our local. */
- MUSBEndPoint *ep = (MUSBEndPoint *) opaque;
- int epnum = ep->epnum;
- MUSBState *s = ep->musb;
-
- ep->fifostart[0] = 0;
- ep->fifolen[0] = 0;
-#ifdef CLEAR_NAK
- if (ep->status[0] != USB_RET_NAK) {
-#endif
- if (epnum)
- ep->csr[0] &= ~(MGC_M_TXCSR_FIFONOTEMPTY | MGC_M_TXCSR_TXPKTRDY);
- else
- ep->csr[0] &= ~MGC_M_CSR0_TXPKTRDY;
-#ifdef CLEAR_NAK
- }
-#endif
-
- /* Clear all of the error bits first */
- if (epnum)
- ep->csr[0] &= ~(MGC_M_TXCSR_H_ERROR | MGC_M_TXCSR_H_RXSTALL |
- MGC_M_TXCSR_H_NAKTIMEOUT);
- else
- ep->csr[0] &= ~(MGC_M_CSR0_H_ERROR | MGC_M_CSR0_H_RXSTALL |
- MGC_M_CSR0_H_NAKTIMEOUT | MGC_M_CSR0_H_NO_PING);
-
- if (ep->status[0] == USB_RET_STALL) {
- /* Command not supported by target! */
- ep->status[0] = 0;
-
- if (epnum)
- ep->csr[0] |= MGC_M_TXCSR_H_RXSTALL;
- else
- ep->csr[0] |= MGC_M_CSR0_H_RXSTALL;
- }
-
- if (ep->status[0] == USB_RET_NAK) {
- ep->status[0] = 0;
-
- /* NAK timeouts are only generated in Bulk transfers and
- * Data-errors in Isochronous. */
- if (ep->interrupt[0]) {
- return;
- }
-
- if (epnum)
- ep->csr[0] |= MGC_M_TXCSR_H_NAKTIMEOUT;
- else
- ep->csr[0] |= MGC_M_CSR0_H_NAKTIMEOUT;
- }
-
- if (ep->status[0] < 0) {
- if (ep->status[0] == USB_RET_BABBLE)
- musb_intr_set(s, musb_irq_rst_babble, 1);
-
- /* Pretend we've tried three times already and failed (in
- * case of USB_TOKEN_SETUP). */
- if (epnum)
- ep->csr[0] |= MGC_M_TXCSR_H_ERROR;
- else
- ep->csr[0] |= MGC_M_CSR0_H_ERROR;
-
- musb_tx_intr_set(s, epnum, 1);
- return;
- }
- /* TODO: check len for over/underruns of an OUT packet? */
-
-#ifdef SETUPLEN_HACK
- if (!epnum && ep->packey[0].pid == USB_TOKEN_SETUP)
- s->setup_len = ep->packey[0].data[6];
-#endif
-
- /* In DMA mode: if no error, assert DMA request for this EP,
- * and skip the interrupt. */
- musb_tx_intr_set(s, epnum, 1);
-}
-
-static void musb_rx_packet_complete(USBPacket *packey, void *opaque)
-{
- /* Unfortunately we can't use packey->devep because that's the remote
- * endpoint number and may be different than our local. */
- MUSBEndPoint *ep = (MUSBEndPoint *) opaque;
- int epnum = ep->epnum;
- MUSBState *s = ep->musb;
-
- ep->fifostart[1] = 0;
- ep->fifolen[1] = 0;
-
-#ifdef CLEAR_NAK
- if (ep->status[1] != USB_RET_NAK) {
-#endif
- ep->csr[1] &= ~MGC_M_RXCSR_H_REQPKT;
- if (!epnum)
- ep->csr[0] &= ~MGC_M_CSR0_H_REQPKT;
-#ifdef CLEAR_NAK
- }
-#endif
-
- /* Clear all of the imaginable error bits first */
- ep->csr[1] &= ~(MGC_M_RXCSR_H_ERROR | MGC_M_RXCSR_H_RXSTALL |
- MGC_M_RXCSR_DATAERROR);
- if (!epnum)
- ep->csr[0] &= ~(MGC_M_CSR0_H_ERROR | MGC_M_CSR0_H_RXSTALL |
- MGC_M_CSR0_H_NAKTIMEOUT | MGC_M_CSR0_H_NO_PING);
-
- if (ep->status[1] == USB_RET_STALL) {
- ep->status[1] = 0;
-
- ep->csr[1] |= MGC_M_RXCSR_H_RXSTALL;
- if (!epnum)
- ep->csr[0] |= MGC_M_CSR0_H_RXSTALL;
- }
-
- if (ep->status[1] == USB_RET_NAK) {
- ep->status[1] = 0;
-
- /* NAK timeouts are only generated in Bulk transfers and
- * Data-errors in Isochronous. */
- if (ep->interrupt[1]) {
- musb_packet(s, ep, epnum, USB_TOKEN_IN,
- packey->iov.size, musb_rx_packet_complete, 1);
- return;
- }
-
- ep->csr[1] |= MGC_M_RXCSR_DATAERROR;
- if (!epnum)
- ep->csr[0] |= MGC_M_CSR0_H_NAKTIMEOUT;
- }
-
- if (ep->status[1] < 0) {
- if (ep->status[1] == USB_RET_BABBLE) {
- musb_intr_set(s, musb_irq_rst_babble, 1);
- return;
- }
-
- /* Pretend we've tried three times already and failed (in
- * case of a control transfer). */
- ep->csr[1] |= MGC_M_RXCSR_H_ERROR;
- if (!epnum)
- ep->csr[0] |= MGC_M_CSR0_H_ERROR;
-
- musb_rx_intr_set(s, epnum, 1);
- return;
- }
- /* TODO: check len for over/underruns of an OUT packet? */
- /* TODO: perhaps make use of e->ext_size[1] here. */
-
- if (!(ep->csr[1] & (MGC_M_RXCSR_H_RXSTALL | MGC_M_RXCSR_DATAERROR))) {
- ep->csr[1] |= MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY;
- if (!epnum)
- ep->csr[0] |= MGC_M_CSR0_RXPKTRDY;
-
- ep->rxcount = ep->status[1]; /* XXX: MIN(packey->len, ep->maxp[1]); */
- /* In DMA mode: assert DMA request for this EP */
- }
-
- /* Only if DMA has not been asserted */
- musb_rx_intr_set(s, epnum, 1);
-}
-
-static void musb_async_cancel_device(MUSBState *s, USBDevice *dev)
-{
- int ep, dir;
-
- for (ep = 0; ep < 16; ep++) {
- for (dir = 0; dir < 2; dir++) {
- if (!usb_packet_is_inflight(&s->ep[ep].packey[dir].p) ||
- s->ep[ep].packey[dir].p.ep->dev != dev) {
- continue;
- }
- usb_cancel_packet(&s->ep[ep].packey[dir].p);
- /* status updates needed here? */
- }
- }
-}
-
-static void musb_tx_rdy(MUSBState *s, int epnum)
-{
- MUSBEndPoint *ep = s->ep + epnum;
- int pid;
- int total, valid = 0;
- TRACE("start %d, len %d", ep->fifostart[0], ep->fifolen[0] );
- ep->fifostart[0] += ep->fifolen[0];
- ep->fifolen[0] = 0;
-
- /* XXX: how's the total size of the packet retrieved exactly in
- * the generic case? */
- total = ep->maxp[0] & 0x3ff;
-
- if (ep->ext_size[0]) {
- total = ep->ext_size[0];
- ep->ext_size[0] = 0;
- valid = 1;
- }
-
- /* If the packet is not fully ready yet, wait for a next segment. */
- if (epnum && (ep->fifostart[0]) < total)
- return;
-
- if (!valid)
- total = ep->fifostart[0];
-
- pid = USB_TOKEN_OUT;
- if (!epnum && (ep->csr[0] & MGC_M_CSR0_H_SETUPPKT)) {
- pid = USB_TOKEN_SETUP;
- if (total != 8) {
- TRACE("illegal SETUPPKT length of %i bytes", total);
- }
- /* Controller should retry SETUP packets three times on errors
- * but it doesn't make sense for us to do that. */
- }
-
- musb_packet(s, ep, epnum, pid, total, musb_tx_packet_complete, 0);
-}
-
-static void musb_rx_req(MUSBState *s, int epnum)
-{
- MUSBEndPoint *ep = s->ep + epnum;
- int total;
-
- /* If we already have a packet, which didn't fit into the
- * 64 bytes of the FIFO, only move the FIFO start and return. (Obsolete) */
- if (ep->packey[1].p.pid == USB_TOKEN_IN && ep->status[1] >= 0 &&
- (ep->fifostart[1]) + ep->rxcount <
- ep->packey[1].p.iov.size) {
- TRACE("0x%08x, %d", ep->fifostart[1], ep->rxcount );
- ep->fifostart[1] += ep->rxcount;
- ep->fifolen[1] = 0;
-
- ep->rxcount = MIN(ep->packey[0].p.iov.size - (ep->fifostart[1]),
- ep->maxp[1]);
-
- ep->csr[1] &= ~MGC_M_RXCSR_H_REQPKT;
- if (!epnum)
- ep->csr[0] &= ~MGC_M_CSR0_H_REQPKT;
-
- /* Clear all of the error bits first */
- ep->csr[1] &= ~(MGC_M_RXCSR_H_ERROR | MGC_M_RXCSR_H_RXSTALL |
- MGC_M_RXCSR_DATAERROR);
- if (!epnum)
- ep->csr[0] &= ~(MGC_M_CSR0_H_ERROR | MGC_M_CSR0_H_RXSTALL |
- MGC_M_CSR0_H_NAKTIMEOUT | MGC_M_CSR0_H_NO_PING);
-
- ep->csr[1] |= MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY;
- if (!epnum)
- ep->csr[0] |= MGC_M_CSR0_RXPKTRDY;
- musb_rx_intr_set(s, epnum, 1);
- return;
- }
-
- /* The driver sets maxp[1] to 64 or less because it knows the hardware
- * FIFO is this deep. Bigger packets get split in
- * usb_generic_handle_packet but we can also do the splitting locally
- * for performance. It turns out we can also have a bigger FIFO and
- * ignore the limit set in ep->maxp[1]. The Linux MUSB driver deals
- * OK with single packets of even 32KB and we avoid splitting, however
- * usb_msd.c sometimes sends a packet bigger than what Linux expects
- * (e.g. 8192 bytes instead of 4096) and we get an OVERRUN. Splitting
- * hides this overrun from Linux. Up to 4096 everything is fine
- * though. Currently this is disabled.
- *
- * XXX: mind ep->fifosize. */
- total = MIN(ep->maxp[1] & 0x3ff, sizeof(s->buf));
-
-#ifdef SETUPLEN_HACK
- /* Why should *we* do that instead of Linux? */
- if (!epnum) {
- if (ep->packey[0].p.devaddr == 2) {
- total = MIN(s->setup_len, 8);
- } else {
- total = MIN(s->setup_len, 64);
- }
- s->setup_len -= total;
- }
-#endif
-
- musb_packet(s, ep, epnum, USB_TOKEN_IN, total, musb_rx_packet_complete, 1);
-}
-
-static uint8_t musb_read_fifo(MUSBEndPoint *ep)
-{
- uint8_t value;
- if (ep->fifolen[1] >= 64) {
- /* We have a FIFO underrun */
- TRACE("EP%d FIFO is now empty, stop reading", ep->epnum);
- return 0x00000000;
- }
- /* In DMA mode clear RXPKTRDY and set REQPKT automatically
- * (if AUTOREQ is set) */
-
- ep->csr[1] &= ~MGC_M_RXCSR_FIFOFULL;
- value=ep->buf[1][ep->fifostart[1] + ep->fifolen[1] ++];
- TRACE("EP%d 0x%02x, %d", ep->epnum, value, ep->fifolen[1] );
- return value;
-}
-
-static void musb_write_fifo(MUSBEndPoint *ep, uint8_t value)
-{
- TRACE("EP%d = %02x", ep->epnum, value);
- if (ep->fifolen[0] >= 64) {
- /* We have a FIFO overrun */
- TRACE("EP%d FIFO exceeded 64 bytes, stop feeding data", ep->epnum);
- return;
- }
-
- ep->buf[0][ep->fifostart[0] + ep->fifolen[0] ++] = value;
- ep->csr[0] |= MGC_M_TXCSR_FIFONOTEMPTY;
-}
-
-static void musb_ep_frame_cancel(MUSBEndPoint *ep, int dir)
-{
- if (ep->intv_timer[dir])
- timer_del(ep->intv_timer[dir]);
-}
-
-/* Bus control */
-static uint8_t musb_busctl_readb(void *opaque, int ep, int addr)
-{
- MUSBState *s = (MUSBState *) opaque;
-
- switch (addr) {
- /* For USB2.0 HS hubs only */
- case MUSB_HDRC_TXHUBADDR:
- return s->ep[ep].haddr[0];
- case MUSB_HDRC_TXHUBPORT:
- return s->ep[ep].hport[0];
- case MUSB_HDRC_RXHUBADDR:
- return s->ep[ep].haddr[1];
- case MUSB_HDRC_RXHUBPORT:
- return s->ep[ep].hport[1];
-
- default:
- TRACE("unknown register 0x%02x", addr);
- return 0x00;
- };
-}
-
-static void musb_busctl_writeb(void *opaque, int ep, int addr, uint8_t value)
-{
- MUSBState *s = (MUSBState *) opaque;
-
- switch (addr) {
- case MUSB_HDRC_TXFUNCADDR:
- s->ep[ep].faddr[0] = value;
- break;
- case MUSB_HDRC_RXFUNCADDR:
- s->ep[ep].faddr[1] = value;
- break;
- case MUSB_HDRC_TXHUBADDR:
- s->ep[ep].haddr[0] = value;
- break;
- case MUSB_HDRC_TXHUBPORT:
- s->ep[ep].hport[0] = value;
- break;
- case MUSB_HDRC_RXHUBADDR:
- s->ep[ep].haddr[1] = value;
- break;
- case MUSB_HDRC_RXHUBPORT:
- s->ep[ep].hport[1] = value;
- break;
-
- default:
- TRACE("unknown register 0x%02x", addr);
- break;
- };
-}
-
-static uint16_t musb_busctl_readh(void *opaque, int ep, int addr)
-{
- MUSBState *s = (MUSBState *) opaque;
-
- switch (addr) {
- case MUSB_HDRC_TXFUNCADDR:
- return s->ep[ep].faddr[0];
- case MUSB_HDRC_RXFUNCADDR:
- return s->ep[ep].faddr[1];
-
- default:
- return musb_busctl_readb(s, ep, addr) |
- (musb_busctl_readb(s, ep, addr | 1) << 8);
- };
-}
-
-static void musb_busctl_writeh(void *opaque, int ep, int addr, uint16_t value)
-{
- MUSBState *s = (MUSBState *) opaque;
-
- switch (addr) {
- case MUSB_HDRC_TXFUNCADDR:
- s->ep[ep].faddr[0] = value;
- break;
- case MUSB_HDRC_RXFUNCADDR:
- s->ep[ep].faddr[1] = value;
- break;
-
- default:
- musb_busctl_writeb(s, ep, addr, value & 0xff);
- musb_busctl_writeb(s, ep, addr | 1, value >> 8);
- };
-}
-
-/* Endpoint control */
-static uint8_t musb_ep_readb(void *opaque, int ep, int addr)
-{
- MUSBState *s = (MUSBState *) opaque;
-
- switch (addr) {
- case MUSB_HDRC_TXTYPE:
- return s->ep[ep].type[0];
- case MUSB_HDRC_TXINTERVAL:
- return s->ep[ep].interval[0];
- case MUSB_HDRC_RXTYPE:
- return s->ep[ep].type[1];
- case MUSB_HDRC_RXINTERVAL:
- return s->ep[ep].interval[1];
- case (MUSB_HDRC_FIFOSIZE & ~1):
- return 0x00;
- case MUSB_HDRC_FIFOSIZE:
- return ep ? s->ep[ep].fifosize : s->ep[ep].config;
- case MUSB_HDRC_RXCOUNT:
- return s->ep[ep].rxcount;
-
- default:
- TRACE("unknown register 0x%02x", addr);
- return 0x00;
- };
-}
-
-static void musb_ep_writeb(void *opaque, int ep, int addr, uint8_t value)
-{
- MUSBState *s = (MUSBState *) opaque;
-
- switch (addr) {
- case MUSB_HDRC_TXTYPE:
- s->ep[ep].type[0] = value;
- break;
- case MUSB_HDRC_TXINTERVAL:
- s->ep[ep].interval[0] = value;
- musb_ep_frame_cancel(&s->ep[ep], 0);
- break;
- case MUSB_HDRC_RXTYPE:
- s->ep[ep].type[1] = value;
- break;
- case MUSB_HDRC_RXINTERVAL:
- s->ep[ep].interval[1] = value;
- musb_ep_frame_cancel(&s->ep[ep], 1);
- break;
- case (MUSB_HDRC_FIFOSIZE & ~1):
- break;
- case MUSB_HDRC_FIFOSIZE:
- TRACE("somebody messes with fifosize (now %i bytes)", value);
- s->ep[ep].fifosize = value;
- break;
- default:
- TRACE("unknown register 0x%02x", addr);
- break;
- };
-}
-
-static uint16_t musb_ep_readh(void *opaque, int ep, int addr)
-{
- MUSBState *s = (MUSBState *) opaque;
- uint16_t ret;
-
- switch (addr) {
- case MUSB_HDRC_TXMAXP:
- return s->ep[ep].maxp[0];
- case MUSB_HDRC_TXCSR:
- return s->ep[ep].csr[0];
- case MUSB_HDRC_RXMAXP:
- return s->ep[ep].maxp[1];
- case MUSB_HDRC_RXCSR:
- ret = s->ep[ep].csr[1];
-
- /* TODO: This and other bits probably depend on
- * ep->csr[1] & MGC_M_RXCSR_AUTOCLEAR. */
- if (s->ep[ep].csr[1] & MGC_M_RXCSR_AUTOCLEAR)
- s->ep[ep].csr[1] &= ~MGC_M_RXCSR_RXPKTRDY;
-
- return ret;
- case MUSB_HDRC_RXCOUNT:
- return s->ep[ep].rxcount;
-
- default:
- return musb_ep_readb(s, ep, addr) |
- (musb_ep_readb(s, ep, addr | 1) << 8);
- };
-}
-
-static void musb_ep_writeh(void *opaque, int ep, int addr, uint16_t value)
-{
- MUSBState *s = (MUSBState *) opaque;
-
- switch (addr) {
- case MUSB_HDRC_TXMAXP:
- s->ep[ep].maxp[0] = value;
- break;
- case MUSB_HDRC_TXCSR:
- if (ep) {
- s->ep[ep].csr[0] &= value & 0xa6;
- s->ep[ep].csr[0] |= value & 0xff59;
- } else {
- s->ep[ep].csr[0] &= value & 0x85;
- s->ep[ep].csr[0] |= value & 0xf7a;
- }
-
- musb_ep_frame_cancel(&s->ep[ep], 0);
-
- if ((ep && (value & MGC_M_TXCSR_FLUSHFIFO)) ||
- (!ep && (value & MGC_M_CSR0_FLUSHFIFO))) {
- s->ep[ep].fifolen[0] = 0;
- s->ep[ep].fifostart[0] = 0;
- if (ep)
- s->ep[ep].csr[0] &=
- ~(MGC_M_TXCSR_FIFONOTEMPTY | MGC_M_TXCSR_TXPKTRDY);
- else
- s->ep[ep].csr[0] &=
- ~(MGC_M_CSR0_TXPKTRDY | MGC_M_CSR0_RXPKTRDY);
- }
- if (
- (ep &&
-#ifdef CLEAR_NAK
- (value & MGC_M_TXCSR_TXPKTRDY) &&
- !(value & MGC_M_TXCSR_H_NAKTIMEOUT)) ||
-#else
- (value & MGC_M_TXCSR_TXPKTRDY)) ||
-#endif
- (!ep &&
-#ifdef CLEAR_NAK
- (value & MGC_M_CSR0_TXPKTRDY) &&
- !(value & MGC_M_CSR0_H_NAKTIMEOUT)))
-#else
- (value & MGC_M_CSR0_TXPKTRDY)))
-#endif
- musb_tx_rdy(s, ep);
- if (!ep &&
- (value & MGC_M_CSR0_H_REQPKT) &&
-#ifdef CLEAR_NAK
- !(value & (MGC_M_CSR0_H_NAKTIMEOUT |
- MGC_M_CSR0_RXPKTRDY)))
-#else
- !(value & MGC_M_CSR0_RXPKTRDY))
-#endif
- musb_rx_req(s, ep);
- break;
-
- case MUSB_HDRC_RXMAXP:
- s->ep[ep].maxp[1] = value;
- break;
- case MUSB_HDRC_RXCSR:
- /* (DMA mode only) */
- if (
- (value & MGC_M_RXCSR_H_AUTOREQ) &&
- !(value & MGC_M_RXCSR_RXPKTRDY) &&
- (s->ep[ep].csr[1] & MGC_M_RXCSR_RXPKTRDY))
- value |= MGC_M_RXCSR_H_REQPKT;
-
- s->ep[ep].csr[1] &= 0x102 | (value & 0x4d);
- s->ep[ep].csr[1] |= value & 0xfeb0;
-
- musb_ep_frame_cancel(&s->ep[ep], 1);
-
- if (value & MGC_M_RXCSR_FLUSHFIFO) {
- s->ep[ep].fifolen[1] = 0;
- s->ep[ep].fifostart[1] = 0;
- s->ep[ep].csr[1] &= ~(MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY);
- /* If double buffering and we have two packets ready, flush
- * only the first one and set up the fifo at the second packet. */
- }
-#ifdef CLEAR_NAK
- if ((value & MGC_M_RXCSR_H_REQPKT) && !(value & MGC_M_RXCSR_DATAERROR))
-#else
- if (value & MGC_M_RXCSR_H_REQPKT)
-#endif
- musb_rx_req(s, ep);
- break;
- case MUSB_HDRC_RXCOUNT:
- s->ep[ep].rxcount = value;
- break;
-
- default:
- musb_ep_writeb(s, ep, addr, value & 0xff);
- musb_ep_writeb(s, ep, addr | 1, value >> 8);
- };
-}
-
-/* Generic control */
-static uint32_t musb_readb(void *opaque, hwaddr addr)
-{
- MUSBState *s = (MUSBState *) opaque;
- int ep, i;
- uint8_t ret;
-
- switch (addr) {
- case MUSB_HDRC_FADDR:
- return s->faddr;
- case MUSB_HDRC_POWER:
- return s->power;
- case MUSB_HDRC_INTRUSB:
- ret = s->intr;
- for (i = 0; i < sizeof(ret) * 8; i ++)
- if (ret & (1 << i))
- musb_intr_set(s, i, 0);
- return ret;
- case MUSB_HDRC_INTRUSBE:
- return s->mask;
- case MUSB_HDRC_INDEX:
- return s->idx;
- case MUSB_HDRC_TESTMODE:
- return 0x00;
-
- case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf):
- return musb_ep_readb(s, s->idx, addr & 0xf);
-
- case MUSB_HDRC_DEVCTL:
- return s->devctl;
-
- case MUSB_HDRC_TXFIFOSZ:
- case MUSB_HDRC_RXFIFOSZ:
- case MUSB_HDRC_VCTRL:
- /* TODO */
- return 0x00;
-
- case MUSB_HDRC_HWVERS:
- return (1 << 10) | 400;
-
- case (MUSB_HDRC_VCTRL | 1):
- case (MUSB_HDRC_HWVERS | 1):
- case (MUSB_HDRC_DEVCTL | 1):
- return 0x00;
-
- case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f):
- ep = (addr >> 3) & 0xf;
- return musb_busctl_readb(s, ep, addr & 0x7);
-
- case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff):
- ep = (addr >> 4) & 0xf;
- return musb_ep_readb(s, ep, addr & 0xf);
-
- case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
- ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
- return musb_read_fifo(s->ep + ep);
-
- default:
- TRACE("unknown register 0x%02x", (int) addr);
- return 0x00;
- };
-}
-
-static void musb_writeb(void *opaque, hwaddr addr, uint32_t value)
-{
- MUSBState *s = (MUSBState *) opaque;
- int ep;
-
- switch (addr) {
- case MUSB_HDRC_FADDR:
- s->faddr = value & 0x7f;
- break;
- case MUSB_HDRC_POWER:
- s->power = (value & 0xef) | (s->power & 0x10);
- /* MGC_M_POWER_RESET is also read-only in Peripheral Mode */
- if ((value & MGC_M_POWER_RESET) && s->port.dev) {
- usb_device_reset(s->port.dev);
- /* Negotiate high-speed operation if MGC_M_POWER_HSENAB is set. */
- if ((value & MGC_M_POWER_HSENAB) &&
- s->port.dev->speed == USB_SPEED_HIGH)
- s->power |= MGC_M_POWER_HSMODE; /* Success */
- /* Restart frame counting. */
- }
- if (value & MGC_M_POWER_SUSPENDM) {
- /* When all transfers finish, suspend and if MGC_M_POWER_ENSUSPEND
- * is set, also go into low power mode. Frame counting stops. */
- /* XXX: Cleared when the interrupt register is read */
- }
- if (value & MGC_M_POWER_RESUME) {
- /* Wait 20ms and signal resuming on the bus. Frame counting
- * restarts. */
- }
- break;
- case MUSB_HDRC_INTRUSB:
- break;
- case MUSB_HDRC_INTRUSBE:
- s->mask = value & 0xff;
- break;
- case MUSB_HDRC_INDEX:
- s->idx = value & 0xf;
- break;
- case MUSB_HDRC_TESTMODE:
- break;
-
- case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf):
- musb_ep_writeb(s, s->idx, addr & 0xf, value);
- break;
-
- case MUSB_HDRC_DEVCTL:
- s->session = !!(value & MGC_M_DEVCTL_SESSION);
- musb_session_update(s,
- !!s->port.dev,
- !!(s->devctl & MGC_M_DEVCTL_SESSION));
-
- /* It seems this is the only R/W bit in this register? */
- s->devctl &= ~MGC_M_DEVCTL_SESSION;
- s->devctl |= value & MGC_M_DEVCTL_SESSION;
- break;
-
- case MUSB_HDRC_TXFIFOSZ:
- case MUSB_HDRC_RXFIFOSZ:
- case MUSB_HDRC_VCTRL:
- /* TODO */
- break;
-
- case (MUSB_HDRC_VCTRL | 1):
- case (MUSB_HDRC_DEVCTL | 1):
- break;
-
- case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f):
- ep = (addr >> 3) & 0xf;
- musb_busctl_writeb(s, ep, addr & 0x7, value);
- break;
-
- case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff):
- ep = (addr >> 4) & 0xf;
- musb_ep_writeb(s, ep, addr & 0xf, value);
- break;
-
- case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
- ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
- musb_write_fifo(s->ep + ep, value & 0xff);
- break;
-
- default:
- TRACE("unknown register 0x%02x", (int) addr);
- break;
- };
-}
-
-static uint32_t musb_readh(void *opaque, hwaddr addr)
-{
- MUSBState *s = (MUSBState *) opaque;
- int ep, i;
- uint16_t ret;
-
- switch (addr) {
- case MUSB_HDRC_INTRTX:
- ret = s->tx_intr;
- /* Auto clear */
- for (i = 0; i < sizeof(ret) * 8; i ++)
- if (ret & (1 << i))
- musb_tx_intr_set(s, i, 0);
- return ret;
- case MUSB_HDRC_INTRRX:
- ret = s->rx_intr;
- /* Auto clear */
- for (i = 0; i < sizeof(ret) * 8; i ++)
- if (ret & (1 << i))
- musb_rx_intr_set(s, i, 0);
- return ret;
- case MUSB_HDRC_INTRTXE:
- return s->tx_mask;
- case MUSB_HDRC_INTRRXE:
- return s->rx_mask;
-
- case MUSB_HDRC_FRAME:
- /* TODO */
- return 0x0000;
- case MUSB_HDRC_TXFIFOADDR:
- return s->ep[s->idx].fifoaddr[0];
- case MUSB_HDRC_RXFIFOADDR:
- return s->ep[s->idx].fifoaddr[1];
-
- case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf):
- return musb_ep_readh(s, s->idx, addr & 0xf);
-
- case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f):
- ep = (addr >> 3) & 0xf;
- return musb_busctl_readh(s, ep, addr & 0x7);
-
- case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff):
- ep = (addr >> 4) & 0xf;
- return musb_ep_readh(s, ep, addr & 0xf);
-
- case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
- ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
- return (musb_read_fifo(s->ep + ep) | musb_read_fifo(s->ep + ep) << 8);
-
- default:
- return musb_readb(s, addr) | (musb_readb(s, addr | 1) << 8);
- };
-}
-
-static void musb_writeh(void *opaque, hwaddr addr, uint32_t value)
-{
- MUSBState *s = (MUSBState *) opaque;
- int ep;
-
- switch (addr) {
- case MUSB_HDRC_INTRTXE:
- s->tx_mask = value;
- /* XXX: the masks seem to apply on the raising edge like with
- * edge-triggered interrupts, thus no need to update. I may be
- * wrong though. */
- break;
- case MUSB_HDRC_INTRRXE:
- s->rx_mask = value;
- break;
-
- case MUSB_HDRC_FRAME:
- /* TODO */
- break;
- case MUSB_HDRC_TXFIFOADDR:
- s->ep[s->idx].fifoaddr[0] = value;
- s->ep[s->idx].buf[0] =
- s->buf + ((value << 3) & 0x7ff );
- break;
- case MUSB_HDRC_RXFIFOADDR:
- s->ep[s->idx].fifoaddr[1] = value;
- s->ep[s->idx].buf[1] =
- s->buf + ((value << 3) & 0x7ff);
- break;
-
- case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf):
- musb_ep_writeh(s, s->idx, addr & 0xf, value);
- break;
-
- case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f):
- ep = (addr >> 3) & 0xf;
- musb_busctl_writeh(s, ep, addr & 0x7, value);
- break;
-
- case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff):
- ep = (addr >> 4) & 0xf;
- musb_ep_writeh(s, ep, addr & 0xf, value);
- break;
-
- case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
- ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
- musb_write_fifo(s->ep + ep, value & 0xff);
- musb_write_fifo(s->ep + ep, (value >> 8) & 0xff);
- break;
-
- default:
- musb_writeb(s, addr, value & 0xff);
- musb_writeb(s, addr | 1, value >> 8);
- };
-}
-
-static uint32_t musb_readw(void *opaque, hwaddr addr)
-{
- MUSBState *s = (MUSBState *) opaque;
- int ep;
-
- switch (addr) {
- case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
- ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
- return ( musb_read_fifo(s->ep + ep) |
- musb_read_fifo(s->ep + ep) << 8 |
- musb_read_fifo(s->ep + ep) << 16 |
- musb_read_fifo(s->ep + ep) << 24 );
- default:
- TRACE("unknown register 0x%02x", (int) addr);
- return 0x00000000;
- };
-}
-
-static void musb_writew(void *opaque, hwaddr addr, uint32_t value)
-{
- MUSBState *s = (MUSBState *) opaque;
- int ep;
-
- switch (addr) {
- case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
- ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
- musb_write_fifo(s->ep + ep, value & 0xff);
- musb_write_fifo(s->ep + ep, (value >> 8 ) & 0xff);
- musb_write_fifo(s->ep + ep, (value >> 16) & 0xff);
- musb_write_fifo(s->ep + ep, (value >> 24) & 0xff);
- break;
- default:
- TRACE("unknown register 0x%02x", (int) addr);
- break;
- };
-}
-
-CPUReadMemoryFunc * const musb_read[] = {
- musb_readb,
- musb_readh,
- musb_readw,
-};
-
-CPUWriteMemoryFunc * const musb_write[] = {
- musb_writeb,
- musb_writeh,
- musb_writew,
-};
diff --git a/qemu/hw/usb/hcd-ohci.c b/qemu/hw/usb/hcd-ohci.c
deleted file mode 100644
index ffab561cf..000000000
--- a/qemu/hw/usb/hcd-ohci.c
+++ /dev/null
@@ -1,2164 +0,0 @@
-/*
- * QEMU USB OHCI Emulation
- * Copyright (c) 2004 Gianni Tedesco
- * Copyright (c) 2006 CodeSourcery
- * Copyright (c) 2006 Openedhand Ltd.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- * TODO:
- * o Isochronous transfers
- * o Allocate bandwidth in frames properly
- * o Disable timers when nothing needs to be done, or remove timer usage
- * all together.
- * o BIOS work to boot from USB storage
-*/
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "qapi/error.h"
-#include "qemu/timer.h"
-#include "hw/usb.h"
-#include "hw/pci/pci.h"
-#include "hw/sysbus.h"
-#include "hw/qdev-dma.h"
-#include "trace.h"
-
-/* This causes frames to occur 1000x slower */
-//#define OHCI_TIME_WARP 1
-
-/* Number of Downstream Ports on the root hub. */
-
-#define OHCI_MAX_PORTS 15
-
-static int64_t usb_frame_time;
-static int64_t usb_bit_time;
-
-typedef struct OHCIPort {
- USBPort port;
- uint32_t ctrl;
-} OHCIPort;
-
-typedef struct {
- USBBus bus;
- qemu_irq irq;
- MemoryRegion mem;
- AddressSpace *as;
- int num_ports;
- const char *name;
-
- QEMUTimer *eof_timer;
- int64_t sof_time;
-
- /* OHCI state */
- /* Control partition */
- uint32_t ctl, status;
- uint32_t intr_status;
- uint32_t intr;
-
- /* memory pointer partition */
- uint32_t hcca;
- uint32_t ctrl_head, ctrl_cur;
- uint32_t bulk_head, bulk_cur;
- uint32_t per_cur;
- uint32_t done;
- int32_t done_count;
-
- /* Frame counter partition */
- uint16_t fsmps;
- uint8_t fit;
- uint16_t fi;
- uint8_t frt;
- uint16_t frame_number;
- uint16_t padding;
- uint32_t pstart;
- uint32_t lst;
-
- /* Root Hub partition */
- uint32_t rhdesc_a, rhdesc_b;
- uint32_t rhstatus;
- OHCIPort rhport[OHCI_MAX_PORTS];
-
- /* PXA27x Non-OHCI events */
- uint32_t hstatus;
- uint32_t hmask;
- uint32_t hreset;
- uint32_t htest;
-
- /* SM501 local memory offset */
- dma_addr_t localmem_base;
-
- /* Active packets. */
- uint32_t old_ctl;
- USBPacket usb_packet;
- uint8_t usb_buf[8192];
- uint32_t async_td;
- bool async_complete;
-
-} OHCIState;
-
-/* Host Controller Communications Area */
-struct ohci_hcca {
- uint32_t intr[32];
- uint16_t frame, pad;
- uint32_t done;
-};
-#define HCCA_WRITEBACK_OFFSET offsetof(struct ohci_hcca, frame)
-#define HCCA_WRITEBACK_SIZE 8 /* frame, pad, done */
-
-#define ED_WBACK_OFFSET offsetof(struct ohci_ed, head)
-#define ED_WBACK_SIZE 4
-
-static void ohci_bus_stop(OHCIState *ohci);
-static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev);
-
-/* Bitfields for the first word of an Endpoint Desciptor. */
-#define OHCI_ED_FA_SHIFT 0
-#define OHCI_ED_FA_MASK (0x7f<<OHCI_ED_FA_SHIFT)
-#define OHCI_ED_EN_SHIFT 7
-#define OHCI_ED_EN_MASK (0xf<<OHCI_ED_EN_SHIFT)
-#define OHCI_ED_D_SHIFT 11
-#define OHCI_ED_D_MASK (3<<OHCI_ED_D_SHIFT)
-#define OHCI_ED_S (1<<13)
-#define OHCI_ED_K (1<<14)
-#define OHCI_ED_F (1<<15)
-#define OHCI_ED_MPS_SHIFT 16
-#define OHCI_ED_MPS_MASK (0x7ff<<OHCI_ED_MPS_SHIFT)
-
-/* Flags in the head field of an Endpoint Desciptor. */
-#define OHCI_ED_H 1
-#define OHCI_ED_C 2
-
-/* Bitfields for the first word of a Transfer Desciptor. */
-#define OHCI_TD_R (1<<18)
-#define OHCI_TD_DP_SHIFT 19
-#define OHCI_TD_DP_MASK (3<<OHCI_TD_DP_SHIFT)
-#define OHCI_TD_DI_SHIFT 21
-#define OHCI_TD_DI_MASK (7<<OHCI_TD_DI_SHIFT)
-#define OHCI_TD_T0 (1<<24)
-#define OHCI_TD_T1 (1<<25)
-#define OHCI_TD_EC_SHIFT 26
-#define OHCI_TD_EC_MASK (3<<OHCI_TD_EC_SHIFT)
-#define OHCI_TD_CC_SHIFT 28
-#define OHCI_TD_CC_MASK (0xf<<OHCI_TD_CC_SHIFT)
-
-/* Bitfields for the first word of an Isochronous Transfer Desciptor. */
-/* CC & DI - same as in the General Transfer Desciptor */
-#define OHCI_TD_SF_SHIFT 0
-#define OHCI_TD_SF_MASK (0xffff<<OHCI_TD_SF_SHIFT)
-#define OHCI_TD_FC_SHIFT 24
-#define OHCI_TD_FC_MASK (7<<OHCI_TD_FC_SHIFT)
-
-/* Isochronous Transfer Desciptor - Offset / PacketStatusWord */
-#define OHCI_TD_PSW_CC_SHIFT 12
-#define OHCI_TD_PSW_CC_MASK (0xf<<OHCI_TD_PSW_CC_SHIFT)
-#define OHCI_TD_PSW_SIZE_SHIFT 0
-#define OHCI_TD_PSW_SIZE_MASK (0xfff<<OHCI_TD_PSW_SIZE_SHIFT)
-
-#define OHCI_PAGE_MASK 0xfffff000
-#define OHCI_OFFSET_MASK 0xfff
-
-#define OHCI_DPTR_MASK 0xfffffff0
-
-#define OHCI_BM(val, field) \
- (((val) & OHCI_##field##_MASK) >> OHCI_##field##_SHIFT)
-
-#define OHCI_SET_BM(val, field, newval) do { \
- val &= ~OHCI_##field##_MASK; \
- val |= ((newval) << OHCI_##field##_SHIFT) & OHCI_##field##_MASK; \
- } while(0)
-
-/* endpoint descriptor */
-struct ohci_ed {
- uint32_t flags;
- uint32_t tail;
- uint32_t head;
- uint32_t next;
-};
-
-/* General transfer descriptor */
-struct ohci_td {
- uint32_t flags;
- uint32_t cbp;
- uint32_t next;
- uint32_t be;
-};
-
-/* Isochronous transfer descriptor */
-struct ohci_iso_td {
- uint32_t flags;
- uint32_t bp;
- uint32_t next;
- uint32_t be;
- uint16_t offset[8];
-};
-
-#define USB_HZ 12000000
-
-/* OHCI Local stuff */
-#define OHCI_CTL_CBSR ((1<<0)|(1<<1))
-#define OHCI_CTL_PLE (1<<2)
-#define OHCI_CTL_IE (1<<3)
-#define OHCI_CTL_CLE (1<<4)
-#define OHCI_CTL_BLE (1<<5)
-#define OHCI_CTL_HCFS ((1<<6)|(1<<7))
-#define OHCI_USB_RESET 0x00
-#define OHCI_USB_RESUME 0x40
-#define OHCI_USB_OPERATIONAL 0x80
-#define OHCI_USB_SUSPEND 0xc0
-#define OHCI_CTL_IR (1<<8)
-#define OHCI_CTL_RWC (1<<9)
-#define OHCI_CTL_RWE (1<<10)
-
-#define OHCI_STATUS_HCR (1<<0)
-#define OHCI_STATUS_CLF (1<<1)
-#define OHCI_STATUS_BLF (1<<2)
-#define OHCI_STATUS_OCR (1<<3)
-#define OHCI_STATUS_SOC ((1<<6)|(1<<7))
-
-#define OHCI_INTR_SO (1U<<0) /* Scheduling overrun */
-#define OHCI_INTR_WD (1U<<1) /* HcDoneHead writeback */
-#define OHCI_INTR_SF (1U<<2) /* Start of frame */
-#define OHCI_INTR_RD (1U<<3) /* Resume detect */
-#define OHCI_INTR_UE (1U<<4) /* Unrecoverable error */
-#define OHCI_INTR_FNO (1U<<5) /* Frame number overflow */
-#define OHCI_INTR_RHSC (1U<<6) /* Root hub status change */
-#define OHCI_INTR_OC (1U<<30) /* Ownership change */
-#define OHCI_INTR_MIE (1U<<31) /* Master Interrupt Enable */
-
-#define OHCI_HCCA_SIZE 0x100
-#define OHCI_HCCA_MASK 0xffffff00
-
-#define OHCI_EDPTR_MASK 0xfffffff0
-
-#define OHCI_FMI_FI 0x00003fff
-#define OHCI_FMI_FSMPS 0xffff0000
-#define OHCI_FMI_FIT 0x80000000
-
-#define OHCI_FR_RT (1U<<31)
-
-#define OHCI_LS_THRESH 0x628
-
-#define OHCI_RHA_RW_MASK 0x00000000 /* Mask of supported features. */
-#define OHCI_RHA_PSM (1<<8)
-#define OHCI_RHA_NPS (1<<9)
-#define OHCI_RHA_DT (1<<10)
-#define OHCI_RHA_OCPM (1<<11)
-#define OHCI_RHA_NOCP (1<<12)
-#define OHCI_RHA_POTPGT_MASK 0xff000000
-
-#define OHCI_RHS_LPS (1U<<0)
-#define OHCI_RHS_OCI (1U<<1)
-#define OHCI_RHS_DRWE (1U<<15)
-#define OHCI_RHS_LPSC (1U<<16)
-#define OHCI_RHS_OCIC (1U<<17)
-#define OHCI_RHS_CRWE (1U<<31)
-
-#define OHCI_PORT_CCS (1<<0)
-#define OHCI_PORT_PES (1<<1)
-#define OHCI_PORT_PSS (1<<2)
-#define OHCI_PORT_POCI (1<<3)
-#define OHCI_PORT_PRS (1<<4)
-#define OHCI_PORT_PPS (1<<8)
-#define OHCI_PORT_LSDA (1<<9)
-#define OHCI_PORT_CSC (1<<16)
-#define OHCI_PORT_PESC (1<<17)
-#define OHCI_PORT_PSSC (1<<18)
-#define OHCI_PORT_OCIC (1<<19)
-#define OHCI_PORT_PRSC (1<<20)
-#define OHCI_PORT_WTC (OHCI_PORT_CSC|OHCI_PORT_PESC|OHCI_PORT_PSSC \
- |OHCI_PORT_OCIC|OHCI_PORT_PRSC)
-
-#define OHCI_TD_DIR_SETUP 0x0
-#define OHCI_TD_DIR_OUT 0x1
-#define OHCI_TD_DIR_IN 0x2
-#define OHCI_TD_DIR_RESERVED 0x3
-
-#define OHCI_CC_NOERROR 0x0
-#define OHCI_CC_CRC 0x1
-#define OHCI_CC_BITSTUFFING 0x2
-#define OHCI_CC_DATATOGGLEMISMATCH 0x3
-#define OHCI_CC_STALL 0x4
-#define OHCI_CC_DEVICENOTRESPONDING 0x5
-#define OHCI_CC_PIDCHECKFAILURE 0x6
-#define OHCI_CC_UNDEXPETEDPID 0x7
-#define OHCI_CC_DATAOVERRUN 0x8
-#define OHCI_CC_DATAUNDERRUN 0x9
-#define OHCI_CC_BUFFEROVERRUN 0xc
-#define OHCI_CC_BUFFERUNDERRUN 0xd
-
-#define OHCI_HRESET_FSBIR (1 << 0)
-
-static void ohci_die(OHCIState *ohci);
-
-/* Update IRQ levels */
-static inline void ohci_intr_update(OHCIState *ohci)
-{
- int level = 0;
-
- if ((ohci->intr & OHCI_INTR_MIE) &&
- (ohci->intr_status & ohci->intr))
- level = 1;
-
- qemu_set_irq(ohci->irq, level);
-}
-
-/* Set an interrupt */
-static inline void ohci_set_interrupt(OHCIState *ohci, uint32_t intr)
-{
- ohci->intr_status |= intr;
- ohci_intr_update(ohci);
-}
-
-/* Attach or detach a device on a root hub port. */
-static void ohci_attach(USBPort *port1)
-{
- OHCIState *s = port1->opaque;
- OHCIPort *port = &s->rhport[port1->index];
- uint32_t old_state = port->ctrl;
-
- /* set connect status */
- port->ctrl |= OHCI_PORT_CCS | OHCI_PORT_CSC;
-
- /* update speed */
- if (port->port.dev->speed == USB_SPEED_LOW) {
- port->ctrl |= OHCI_PORT_LSDA;
- } else {
- port->ctrl &= ~OHCI_PORT_LSDA;
- }
-
- /* notify of remote-wakeup */
- if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND) {
- ohci_set_interrupt(s, OHCI_INTR_RD);
- }
-
- trace_usb_ohci_port_attach(port1->index);
-
- if (old_state != port->ctrl) {
- ohci_set_interrupt(s, OHCI_INTR_RHSC);
- }
-}
-
-static void ohci_detach(USBPort *port1)
-{
- OHCIState *s = port1->opaque;
- OHCIPort *port = &s->rhport[port1->index];
- uint32_t old_state = port->ctrl;
-
- ohci_async_cancel_device(s, port1->dev);
-
- /* set connect status */
- if (port->ctrl & OHCI_PORT_CCS) {
- port->ctrl &= ~OHCI_PORT_CCS;
- port->ctrl |= OHCI_PORT_CSC;
- }
- /* disable port */
- if (port->ctrl & OHCI_PORT_PES) {
- port->ctrl &= ~OHCI_PORT_PES;
- port->ctrl |= OHCI_PORT_PESC;
- }
- trace_usb_ohci_port_detach(port1->index);
-
- if (old_state != port->ctrl) {
- ohci_set_interrupt(s, OHCI_INTR_RHSC);
- }
-}
-
-static void ohci_wakeup(USBPort *port1)
-{
- OHCIState *s = port1->opaque;
- OHCIPort *port = &s->rhport[port1->index];
- uint32_t intr = 0;
- if (port->ctrl & OHCI_PORT_PSS) {
- trace_usb_ohci_port_wakeup(port1->index);
- port->ctrl |= OHCI_PORT_PSSC;
- port->ctrl &= ~OHCI_PORT_PSS;
- intr = OHCI_INTR_RHSC;
- }
- /* Note that the controller can be suspended even if this port is not */
- if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND) {
- trace_usb_ohci_remote_wakeup(s->name);
- /* This is the one state transition the controller can do by itself */
- s->ctl &= ~OHCI_CTL_HCFS;
- s->ctl |= OHCI_USB_RESUME;
- /* In suspend mode only ResumeDetected is possible, not RHSC:
- * see the OHCI spec 5.1.2.3.
- */
- intr = OHCI_INTR_RD;
- }
- ohci_set_interrupt(s, intr);
-}
-
-static void ohci_child_detach(USBPort *port1, USBDevice *child)
-{
- OHCIState *s = port1->opaque;
-
- ohci_async_cancel_device(s, child);
-}
-
-static USBDevice *ohci_find_device(OHCIState *ohci, uint8_t addr)
-{
- USBDevice *dev;
- int i;
-
- for (i = 0; i < ohci->num_ports; i++) {
- if ((ohci->rhport[i].ctrl & OHCI_PORT_PES) == 0) {
- continue;
- }
- dev = usb_find_device(&ohci->rhport[i].port, addr);
- if (dev != NULL) {
- return dev;
- }
- }
- return NULL;
-}
-
-static void ohci_stop_endpoints(OHCIState *ohci)
-{
- USBDevice *dev;
- int i, j;
-
- for (i = 0; i < ohci->num_ports; i++) {
- dev = ohci->rhport[i].port.dev;
- if (dev && dev->attached) {
- usb_device_ep_stopped(dev, &dev->ep_ctl);
- for (j = 0; j < USB_MAX_ENDPOINTS; j++) {
- usb_device_ep_stopped(dev, &dev->ep_in[j]);
- usb_device_ep_stopped(dev, &dev->ep_out[j]);
- }
- }
- }
-}
-
-static void ohci_roothub_reset(OHCIState *ohci)
-{
- OHCIPort *port;
- int i;
-
- ohci_bus_stop(ohci);
- ohci->rhdesc_a = OHCI_RHA_NPS | ohci->num_ports;
- ohci->rhdesc_b = 0x0; /* Impl. specific */
- ohci->rhstatus = 0;
-
- for (i = 0; i < ohci->num_ports; i++) {
- port = &ohci->rhport[i];
- port->ctrl = 0;
- if (port->port.dev && port->port.dev->attached) {
- usb_port_reset(&port->port);
- }
- }
- if (ohci->async_td) {
- usb_cancel_packet(&ohci->usb_packet);
- ohci->async_td = 0;
- }
- ohci_stop_endpoints(ohci);
-}
-
-/* Reset the controller */
-static void ohci_soft_reset(OHCIState *ohci)
-{
- trace_usb_ohci_reset(ohci->name);
-
- ohci_bus_stop(ohci);
- ohci->ctl = (ohci->ctl & OHCI_CTL_IR) | OHCI_USB_SUSPEND;
- ohci->old_ctl = 0;
- ohci->status = 0;
- ohci->intr_status = 0;
- ohci->intr = OHCI_INTR_MIE;
-
- ohci->hcca = 0;
- ohci->ctrl_head = ohci->ctrl_cur = 0;
- ohci->bulk_head = ohci->bulk_cur = 0;
- ohci->per_cur = 0;
- ohci->done = 0;
- ohci->done_count = 7;
-
- /* FSMPS is marked TBD in OCHI 1.0, what gives ffs?
- * I took the value linux sets ...
- */
- ohci->fsmps = 0x2778;
- ohci->fi = 0x2edf;
- ohci->fit = 0;
- ohci->frt = 0;
- ohci->frame_number = 0;
- ohci->pstart = 0;
- ohci->lst = OHCI_LS_THRESH;
-}
-
-static void ohci_hard_reset(OHCIState *ohci)
-{
- ohci_soft_reset(ohci);
- ohci->ctl = 0;
- ohci_roothub_reset(ohci);
-}
-
-/* Get an array of dwords from main memory */
-static inline int get_dwords(OHCIState *ohci,
- dma_addr_t addr, uint32_t *buf, int num)
-{
- int i;
-
- addr += ohci->localmem_base;
-
- for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
- if (dma_memory_read(ohci->as, addr, buf, sizeof(*buf))) {
- return -1;
- }
- *buf = le32_to_cpu(*buf);
- }
-
- return 0;
-}
-
-/* Put an array of dwords in to main memory */
-static inline int put_dwords(OHCIState *ohci,
- dma_addr_t addr, uint32_t *buf, int num)
-{
- int i;
-
- addr += ohci->localmem_base;
-
- for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
- uint32_t tmp = cpu_to_le32(*buf);
- if (dma_memory_write(ohci->as, addr, &tmp, sizeof(tmp))) {
- return -1;
- }
- }
-
- return 0;
-}
-
-/* Get an array of words from main memory */
-static inline int get_words(OHCIState *ohci,
- dma_addr_t addr, uint16_t *buf, int num)
-{
- int i;
-
- addr += ohci->localmem_base;
-
- for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
- if (dma_memory_read(ohci->as, addr, buf, sizeof(*buf))) {
- return -1;
- }
- *buf = le16_to_cpu(*buf);
- }
-
- return 0;
-}
-
-/* Put an array of words in to main memory */
-static inline int put_words(OHCIState *ohci,
- dma_addr_t addr, uint16_t *buf, int num)
-{
- int i;
-
- addr += ohci->localmem_base;
-
- for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
- uint16_t tmp = cpu_to_le16(*buf);
- if (dma_memory_write(ohci->as, addr, &tmp, sizeof(tmp))) {
- return -1;
- }
- }
-
- return 0;
-}
-
-static inline int ohci_read_ed(OHCIState *ohci,
- dma_addr_t addr, struct ohci_ed *ed)
-{
- return get_dwords(ohci, addr, (uint32_t *)ed, sizeof(*ed) >> 2);
-}
-
-static inline int ohci_read_td(OHCIState *ohci,
- dma_addr_t addr, struct ohci_td *td)
-{
- return get_dwords(ohci, addr, (uint32_t *)td, sizeof(*td) >> 2);
-}
-
-static inline int ohci_read_iso_td(OHCIState *ohci,
- dma_addr_t addr, struct ohci_iso_td *td)
-{
- return get_dwords(ohci, addr, (uint32_t *)td, 4) ||
- get_words(ohci, addr + 16, td->offset, 8);
-}
-
-static inline int ohci_read_hcca(OHCIState *ohci,
- dma_addr_t addr, struct ohci_hcca *hcca)
-{
- return dma_memory_read(ohci->as, addr + ohci->localmem_base,
- hcca, sizeof(*hcca));
-}
-
-static inline int ohci_put_ed(OHCIState *ohci,
- dma_addr_t addr, struct ohci_ed *ed)
-{
- /* ed->tail is under control of the HCD.
- * Since just ed->head is changed by HC, just write back this
- */
-
- return put_dwords(ohci, addr + ED_WBACK_OFFSET,
- (uint32_t *)((char *)ed + ED_WBACK_OFFSET),
- ED_WBACK_SIZE >> 2);
-}
-
-static inline int ohci_put_td(OHCIState *ohci,
- dma_addr_t addr, struct ohci_td *td)
-{
- return put_dwords(ohci, addr, (uint32_t *)td, sizeof(*td) >> 2);
-}
-
-static inline int ohci_put_iso_td(OHCIState *ohci,
- dma_addr_t addr, struct ohci_iso_td *td)
-{
- return put_dwords(ohci, addr, (uint32_t *)td, 4) ||
- put_words(ohci, addr + 16, td->offset, 8);
-}
-
-static inline int ohci_put_hcca(OHCIState *ohci,
- dma_addr_t addr, struct ohci_hcca *hcca)
-{
- return dma_memory_write(ohci->as,
- addr + ohci->localmem_base + HCCA_WRITEBACK_OFFSET,
- (char *)hcca + HCCA_WRITEBACK_OFFSET,
- HCCA_WRITEBACK_SIZE);
-}
-
-/* Read/Write the contents of a TD from/to main memory. */
-static int ohci_copy_td(OHCIState *ohci, struct ohci_td *td,
- uint8_t *buf, int len, DMADirection dir)
-{
- dma_addr_t ptr, n;
-
- ptr = td->cbp;
- n = 0x1000 - (ptr & 0xfff);
- if (n > len)
- n = len;
-
- if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf, n, dir)) {
- return -1;
- }
- if (n == len) {
- return 0;
- }
- ptr = td->be & ~0xfffu;
- buf += n;
- if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf,
- len - n, dir)) {
- return -1;
- }
- return 0;
-}
-
-/* Read/Write the contents of an ISO TD from/to main memory. */
-static int ohci_copy_iso_td(OHCIState *ohci,
- uint32_t start_addr, uint32_t end_addr,
- uint8_t *buf, int len, DMADirection dir)
-{
- dma_addr_t ptr, n;
-
- ptr = start_addr;
- n = 0x1000 - (ptr & 0xfff);
- if (n > len)
- n = len;
-
- if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf, n, dir)) {
- return -1;
- }
- if (n == len) {
- return 0;
- }
- ptr = end_addr & ~0xfffu;
- buf += n;
- if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf,
- len - n, dir)) {
- return -1;
- }
- return 0;
-}
-
-static void ohci_process_lists(OHCIState *ohci, int completion);
-
-static void ohci_async_complete_packet(USBPort *port, USBPacket *packet)
-{
- OHCIState *ohci = container_of(packet, OHCIState, usb_packet);
-
- trace_usb_ohci_async_complete();
- ohci->async_complete = true;
- ohci_process_lists(ohci, 1);
-}
-
-#define USUB(a, b) ((int16_t)((uint16_t)(a) - (uint16_t)(b)))
-
-static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
- int completion)
-{
- int dir;
- size_t len = 0;
- const char *str = NULL;
- int pid;
- int ret;
- int i;
- USBDevice *dev;
- USBEndpoint *ep;
- struct ohci_iso_td iso_td;
- uint32_t addr;
- uint16_t starting_frame;
- int16_t relative_frame_number;
- int frame_count;
- uint32_t start_offset, next_offset, end_offset = 0;
- uint32_t start_addr, end_addr;
-
- addr = ed->head & OHCI_DPTR_MASK;
-
- if (ohci_read_iso_td(ohci, addr, &iso_td)) {
- trace_usb_ohci_iso_td_read_failed(addr);
- ohci_die(ohci);
- return 0;
- }
-
- starting_frame = OHCI_BM(iso_td.flags, TD_SF);
- frame_count = OHCI_BM(iso_td.flags, TD_FC);
- relative_frame_number = USUB(ohci->frame_number, starting_frame);
-
- trace_usb_ohci_iso_td_head(
- ed->head & OHCI_DPTR_MASK, ed->tail & OHCI_DPTR_MASK,
- iso_td.flags, iso_td.bp, iso_td.next, iso_td.be,
- ohci->frame_number, starting_frame,
- frame_count, relative_frame_number);
- trace_usb_ohci_iso_td_head_offset(
- iso_td.offset[0], iso_td.offset[1],
- iso_td.offset[2], iso_td.offset[3],
- iso_td.offset[4], iso_td.offset[5],
- iso_td.offset[6], iso_td.offset[7]);
-
- if (relative_frame_number < 0) {
- trace_usb_ohci_iso_td_relative_frame_number_neg(relative_frame_number);
- return 1;
- } else if (relative_frame_number > frame_count) {
- /* ISO TD expired - retire the TD to the Done Queue and continue with
- the next ISO TD of the same ED */
- trace_usb_ohci_iso_td_relative_frame_number_big(relative_frame_number,
- frame_count);
- OHCI_SET_BM(iso_td.flags, TD_CC, OHCI_CC_DATAOVERRUN);
- ed->head &= ~OHCI_DPTR_MASK;
- ed->head |= (iso_td.next & OHCI_DPTR_MASK);
- iso_td.next = ohci->done;
- ohci->done = addr;
- i = OHCI_BM(iso_td.flags, TD_DI);
- if (i < ohci->done_count)
- ohci->done_count = i;
- if (ohci_put_iso_td(ohci, addr, &iso_td)) {
- ohci_die(ohci);
- return 1;
- }
- return 0;
- }
-
- dir = OHCI_BM(ed->flags, ED_D);
- switch (dir) {
- case OHCI_TD_DIR_IN:
- str = "in";
- pid = USB_TOKEN_IN;
- break;
- case OHCI_TD_DIR_OUT:
- str = "out";
- pid = USB_TOKEN_OUT;
- break;
- case OHCI_TD_DIR_SETUP:
- str = "setup";
- pid = USB_TOKEN_SETUP;
- break;
- default:
- trace_usb_ohci_iso_td_bad_direction(dir);
- return 1;
- }
-
- if (!iso_td.bp || !iso_td.be) {
- trace_usb_ohci_iso_td_bad_bp_be(iso_td.bp, iso_td.be);
- return 1;
- }
-
- start_offset = iso_td.offset[relative_frame_number];
- next_offset = iso_td.offset[relative_frame_number + 1];
-
- if (!(OHCI_BM(start_offset, TD_PSW_CC) & 0xe) ||
- ((relative_frame_number < frame_count) &&
- !(OHCI_BM(next_offset, TD_PSW_CC) & 0xe))) {
- trace_usb_ohci_iso_td_bad_cc_not_accessed(start_offset, next_offset);
- return 1;
- }
-
- if ((relative_frame_number < frame_count) && (start_offset > next_offset)) {
- trace_usb_ohci_iso_td_bad_cc_overrun(start_offset, next_offset);
- return 1;
- }
-
- if ((start_offset & 0x1000) == 0) {
- start_addr = (iso_td.bp & OHCI_PAGE_MASK) |
- (start_offset & OHCI_OFFSET_MASK);
- } else {
- start_addr = (iso_td.be & OHCI_PAGE_MASK) |
- (start_offset & OHCI_OFFSET_MASK);
- }
-
- if (relative_frame_number < frame_count) {
- end_offset = next_offset - 1;
- if ((end_offset & 0x1000) == 0) {
- end_addr = (iso_td.bp & OHCI_PAGE_MASK) |
- (end_offset & OHCI_OFFSET_MASK);
- } else {
- end_addr = (iso_td.be & OHCI_PAGE_MASK) |
- (end_offset & OHCI_OFFSET_MASK);
- }
- } else {
- /* Last packet in the ISO TD */
- end_addr = iso_td.be;
- }
-
- if ((start_addr & OHCI_PAGE_MASK) != (end_addr & OHCI_PAGE_MASK)) {
- len = (end_addr & OHCI_OFFSET_MASK) + 0x1001
- - (start_addr & OHCI_OFFSET_MASK);
- } else {
- len = end_addr - start_addr + 1;
- }
-
- if (len && dir != OHCI_TD_DIR_IN) {
- if (ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, len,
- DMA_DIRECTION_TO_DEVICE)) {
- ohci_die(ohci);
- return 1;
- }
- }
-
- if (!completion) {
- bool int_req = relative_frame_number == frame_count &&
- OHCI_BM(iso_td.flags, TD_DI) == 0;
- dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA));
- ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN));
- usb_packet_setup(&ohci->usb_packet, pid, ep, 0, addr, false, int_req);
- usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len);
- usb_handle_packet(dev, &ohci->usb_packet);
- if (ohci->usb_packet.status == USB_RET_ASYNC) {
- usb_device_flush_ep_queue(dev, ep);
- return 1;
- }
- }
- if (ohci->usb_packet.status == USB_RET_SUCCESS) {
- ret = ohci->usb_packet.actual_length;
- } else {
- ret = ohci->usb_packet.status;
- }
-
- trace_usb_ohci_iso_td_so(start_offset, end_offset, start_addr, end_addr,
- str, len, ret);
-
- /* Writeback */
- if (dir == OHCI_TD_DIR_IN && ret >= 0 && ret <= len) {
- /* IN transfer succeeded */
- if (ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, ret,
- DMA_DIRECTION_FROM_DEVICE)) {
- ohci_die(ohci);
- return 1;
- }
- OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
- OHCI_CC_NOERROR);
- OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, ret);
- } else if (dir == OHCI_TD_DIR_OUT && ret == len) {
- /* OUT transfer succeeded */
- OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
- OHCI_CC_NOERROR);
- OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, 0);
- } else {
- if (ret > (ssize_t) len) {
- trace_usb_ohci_iso_td_data_overrun(ret, len);
- OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
- OHCI_CC_DATAOVERRUN);
- OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE,
- len);
- } else if (ret >= 0) {
- trace_usb_ohci_iso_td_data_underrun(ret);
- OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
- OHCI_CC_DATAUNDERRUN);
- } else {
- switch (ret) {
- case USB_RET_IOERROR:
- case USB_RET_NODEV:
- OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
- OHCI_CC_DEVICENOTRESPONDING);
- OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE,
- 0);
- break;
- case USB_RET_NAK:
- case USB_RET_STALL:
- trace_usb_ohci_iso_td_nak(ret);
- OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
- OHCI_CC_STALL);
- OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE,
- 0);
- break;
- default:
- trace_usb_ohci_iso_td_bad_response(ret);
- OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
- OHCI_CC_UNDEXPETEDPID);
- break;
- }
- }
- }
-
- if (relative_frame_number == frame_count) {
- /* Last data packet of ISO TD - retire the TD to the Done Queue */
- OHCI_SET_BM(iso_td.flags, TD_CC, OHCI_CC_NOERROR);
- ed->head &= ~OHCI_DPTR_MASK;
- ed->head |= (iso_td.next & OHCI_DPTR_MASK);
- iso_td.next = ohci->done;
- ohci->done = addr;
- i = OHCI_BM(iso_td.flags, TD_DI);
- if (i < ohci->done_count)
- ohci->done_count = i;
- }
- if (ohci_put_iso_td(ohci, addr, &iso_td)) {
- ohci_die(ohci);
- }
- return 1;
-}
-
-#ifdef trace_event_get_state
-static void ohci_td_pkt(const char *msg, const uint8_t *buf, size_t len)
-{
- bool print16 = !!trace_event_get_state(TRACE_USB_OHCI_TD_PKT_SHORT);
- bool printall = !!trace_event_get_state(TRACE_USB_OHCI_TD_PKT_FULL);
- const int width = 16;
- int i;
- char tmp[3 * width + 1];
- char *p = tmp;
-
- if (!printall && !print16) {
- return;
- }
-
- for (i = 0; ; i++) {
- if (i && (!(i % width) || (i == len))) {
- if (!printall) {
- trace_usb_ohci_td_pkt_short(msg, tmp);
- break;
- }
- trace_usb_ohci_td_pkt_full(msg, tmp);
- p = tmp;
- *p = 0;
- }
- if (i == len) {
- break;
- }
-
- p += sprintf(p, " %.2x", buf[i]);
- }
-}
-#else
-static void ohci_td_pkt(const char *msg, const uint8_t *buf, size_t len)
-{
-}
-#endif
-
-/* Service a transport descriptor.
- Returns nonzero to terminate processing of this endpoint. */
-
-static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
-{
- int dir;
- size_t len = 0, pktlen = 0;
- const char *str = NULL;
- int pid;
- int ret;
- int i;
- USBDevice *dev;
- USBEndpoint *ep;
- struct ohci_td td;
- uint32_t addr;
- int flag_r;
- int completion;
-
- addr = ed->head & OHCI_DPTR_MASK;
- /* See if this TD has already been submitted to the device. */
- completion = (addr == ohci->async_td);
- if (completion && !ohci->async_complete) {
- trace_usb_ohci_td_skip_async();
- return 1;
- }
- if (ohci_read_td(ohci, addr, &td)) {
- trace_usb_ohci_td_read_error(addr);
- ohci_die(ohci);
- return 0;
- }
-
- dir = OHCI_BM(ed->flags, ED_D);
- switch (dir) {
- case OHCI_TD_DIR_OUT:
- case OHCI_TD_DIR_IN:
- /* Same value. */
- break;
- default:
- dir = OHCI_BM(td.flags, TD_DP);
- break;
- }
-
- switch (dir) {
- case OHCI_TD_DIR_IN:
- str = "in";
- pid = USB_TOKEN_IN;
- break;
- case OHCI_TD_DIR_OUT:
- str = "out";
- pid = USB_TOKEN_OUT;
- break;
- case OHCI_TD_DIR_SETUP:
- str = "setup";
- pid = USB_TOKEN_SETUP;
- break;
- default:
- trace_usb_ohci_td_bad_direction(dir);
- return 1;
- }
- if (td.cbp && td.be) {
- if ((td.cbp & 0xfffff000) != (td.be & 0xfffff000)) {
- len = (td.be & 0xfff) + 0x1001 - (td.cbp & 0xfff);
- } else {
- len = (td.be - td.cbp) + 1;
- }
-
- pktlen = len;
- if (len && dir != OHCI_TD_DIR_IN) {
- /* The endpoint may not allow us to transfer it all now */
- pktlen = (ed->flags & OHCI_ED_MPS_MASK) >> OHCI_ED_MPS_SHIFT;
- if (pktlen > len) {
- pktlen = len;
- }
- if (!completion) {
- if (ohci_copy_td(ohci, &td, ohci->usb_buf, pktlen,
- DMA_DIRECTION_TO_DEVICE)) {
- ohci_die(ohci);
- }
- }
- }
- }
-
- flag_r = (td.flags & OHCI_TD_R) != 0;
- trace_usb_ohci_td_pkt_hdr(addr, (int64_t)pktlen, (int64_t)len, str,
- flag_r, td.cbp, td.be);
- ohci_td_pkt("OUT", ohci->usb_buf, pktlen);
-
- if (completion) {
- ohci->async_td = 0;
- ohci->async_complete = false;
- } else {
- if (ohci->async_td) {
- /* ??? The hardware should allow one active packet per
- endpoint. We only allow one active packet per controller.
- This should be sufficient as long as devices respond in a
- timely manner.
- */
- trace_usb_ohci_td_too_many_pending();
- return 1;
- }
- dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA));
- ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN));
- usb_packet_setup(&ohci->usb_packet, pid, ep, 0, addr, !flag_r,
- OHCI_BM(td.flags, TD_DI) == 0);
- usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, pktlen);
- usb_handle_packet(dev, &ohci->usb_packet);
- trace_usb_ohci_td_packet_status(ohci->usb_packet.status);
-
- if (ohci->usb_packet.status == USB_RET_ASYNC) {
- usb_device_flush_ep_queue(dev, ep);
- ohci->async_td = addr;
- return 1;
- }
- }
- if (ohci->usb_packet.status == USB_RET_SUCCESS) {
- ret = ohci->usb_packet.actual_length;
- } else {
- ret = ohci->usb_packet.status;
- }
-
- if (ret >= 0) {
- if (dir == OHCI_TD_DIR_IN) {
- if (ohci_copy_td(ohci, &td, ohci->usb_buf, ret,
- DMA_DIRECTION_FROM_DEVICE)) {
- ohci_die(ohci);
- }
- ohci_td_pkt("IN", ohci->usb_buf, pktlen);
- } else {
- ret = pktlen;
- }
- }
-
- /* Writeback */
- if (ret == pktlen || (dir == OHCI_TD_DIR_IN && ret >= 0 && flag_r)) {
- /* Transmission succeeded. */
- if (ret == len) {
- td.cbp = 0;
- } else {
- if ((td.cbp & 0xfff) + ret > 0xfff) {
- td.cbp = (td.be & ~0xfff) + ((td.cbp + ret) & 0xfff);
- } else {
- td.cbp += ret;
- }
- }
- td.flags |= OHCI_TD_T1;
- td.flags ^= OHCI_TD_T0;
- OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_NOERROR);
- OHCI_SET_BM(td.flags, TD_EC, 0);
-
- if ((dir != OHCI_TD_DIR_IN) && (ret != len)) {
- /* Partial packet transfer: TD not ready to retire yet */
- goto exit_no_retire;
- }
-
- /* Setting ED_C is part of the TD retirement process */
- ed->head &= ~OHCI_ED_C;
- if (td.flags & OHCI_TD_T0)
- ed->head |= OHCI_ED_C;
- } else {
- if (ret >= 0) {
- trace_usb_ohci_td_underrun();
- OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DATAUNDERRUN);
- } else {
- switch (ret) {
- case USB_RET_IOERROR:
- case USB_RET_NODEV:
- trace_usb_ohci_td_dev_error();
- OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DEVICENOTRESPONDING);
- break;
- case USB_RET_NAK:
- trace_usb_ohci_td_nak();
- return 1;
- case USB_RET_STALL:
- trace_usb_ohci_td_stall();
- OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_STALL);
- break;
- case USB_RET_BABBLE:
- trace_usb_ohci_td_babble();
- OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DATAOVERRUN);
- break;
- default:
- trace_usb_ohci_td_bad_device_response(ret);
- OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_UNDEXPETEDPID);
- OHCI_SET_BM(td.flags, TD_EC, 3);
- break;
- }
- }
- ed->head |= OHCI_ED_H;
- }
-
- /* Retire this TD */
- ed->head &= ~OHCI_DPTR_MASK;
- ed->head |= td.next & OHCI_DPTR_MASK;
- td.next = ohci->done;
- ohci->done = addr;
- i = OHCI_BM(td.flags, TD_DI);
- if (i < ohci->done_count)
- ohci->done_count = i;
-exit_no_retire:
- if (ohci_put_td(ohci, addr, &td)) {
- ohci_die(ohci);
- return 1;
- }
- return OHCI_BM(td.flags, TD_CC) != OHCI_CC_NOERROR;
-}
-
-/* Service an endpoint list. Returns nonzero if active TD were found. */
-static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion)
-{
- struct ohci_ed ed;
- uint32_t next_ed;
- uint32_t cur;
- int active;
-
- active = 0;
-
- if (head == 0)
- return 0;
-
- for (cur = head; cur; cur = next_ed) {
- if (ohci_read_ed(ohci, cur, &ed)) {
- trace_usb_ohci_ed_read_error(cur);
- ohci_die(ohci);
- return 0;
- }
-
- next_ed = ed.next & OHCI_DPTR_MASK;
-
- if ((ed.head & OHCI_ED_H) || (ed.flags & OHCI_ED_K)) {
- uint32_t addr;
- /* Cancel pending packets for ED that have been paused. */
- addr = ed.head & OHCI_DPTR_MASK;
- if (ohci->async_td && addr == ohci->async_td) {
- usb_cancel_packet(&ohci->usb_packet);
- ohci->async_td = 0;
- usb_device_ep_stopped(ohci->usb_packet.ep->dev,
- ohci->usb_packet.ep);
- }
- continue;
- }
-
- while ((ed.head & OHCI_DPTR_MASK) != ed.tail) {
- trace_usb_ohci_ed_pkt(cur, (ed.head & OHCI_ED_H) != 0,
- (ed.head & OHCI_ED_C) != 0, ed.head & OHCI_DPTR_MASK,
- ed.tail & OHCI_DPTR_MASK, ed.next & OHCI_DPTR_MASK);
- trace_usb_ohci_ed_pkt_flags(
- OHCI_BM(ed.flags, ED_FA), OHCI_BM(ed.flags, ED_EN),
- OHCI_BM(ed.flags, ED_D), (ed.flags & OHCI_ED_S)!= 0,
- (ed.flags & OHCI_ED_K) != 0, (ed.flags & OHCI_ED_F) != 0,
- OHCI_BM(ed.flags, ED_MPS));
-
- active = 1;
-
- if ((ed.flags & OHCI_ED_F) == 0) {
- if (ohci_service_td(ohci, &ed))
- break;
- } else {
- /* Handle isochronous endpoints */
- if (ohci_service_iso_td(ohci, &ed, completion))
- break;
- }
- }
-
- if (ohci_put_ed(ohci, cur, &ed)) {
- ohci_die(ohci);
- return 0;
- }
- }
-
- return active;
-}
-
-/* set a timer for EOF */
-static void ohci_eof_timer(OHCIState *ohci)
-{
- ohci->sof_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- timer_mod(ohci->eof_timer, ohci->sof_time + usb_frame_time);
-}
-/* Set a timer for EOF and generate a SOF event */
-static void ohci_sof(OHCIState *ohci)
-{
- ohci_eof_timer(ohci);
- ohci_set_interrupt(ohci, OHCI_INTR_SF);
-}
-
-/* Process Control and Bulk lists. */
-static void ohci_process_lists(OHCIState *ohci, int completion)
-{
- if ((ohci->ctl & OHCI_CTL_CLE) && (ohci->status & OHCI_STATUS_CLF)) {
- if (ohci->ctrl_cur && ohci->ctrl_cur != ohci->ctrl_head) {
- trace_usb_ohci_process_lists(ohci->ctrl_head, ohci->ctrl_cur);
- }
- if (!ohci_service_ed_list(ohci, ohci->ctrl_head, completion)) {
- ohci->ctrl_cur = 0;
- ohci->status &= ~OHCI_STATUS_CLF;
- }
- }
-
- if ((ohci->ctl & OHCI_CTL_BLE) && (ohci->status & OHCI_STATUS_BLF)) {
- if (!ohci_service_ed_list(ohci, ohci->bulk_head, completion)) {
- ohci->bulk_cur = 0;
- ohci->status &= ~OHCI_STATUS_BLF;
- }
- }
-}
-
-/* Do frame processing on frame boundary */
-static void ohci_frame_boundary(void *opaque)
-{
- OHCIState *ohci = opaque;
- struct ohci_hcca hcca;
-
- if (ohci_read_hcca(ohci, ohci->hcca, &hcca)) {
- trace_usb_ohci_hcca_read_error(ohci->hcca);
- ohci_die(ohci);
- return;
- }
-
- /* Process all the lists at the end of the frame */
- if (ohci->ctl & OHCI_CTL_PLE) {
- int n;
-
- n = ohci->frame_number & 0x1f;
- ohci_service_ed_list(ohci, le32_to_cpu(hcca.intr[n]), 0);
- }
-
- /* Cancel all pending packets if either of the lists has been disabled. */
- if (ohci->old_ctl & (~ohci->ctl) & (OHCI_CTL_BLE | OHCI_CTL_CLE)) {
- if (ohci->async_td) {
- usb_cancel_packet(&ohci->usb_packet);
- ohci->async_td = 0;
- }
- ohci_stop_endpoints(ohci);
- }
- ohci->old_ctl = ohci->ctl;
- ohci_process_lists(ohci, 0);
-
- /* Stop if UnrecoverableError happened or ohci_sof will crash */
- if (ohci->intr_status & OHCI_INTR_UE) {
- return;
- }
-
- /* Frame boundary, so do EOF stuf here */
- ohci->frt = ohci->fit;
-
- /* Increment frame number and take care of endianness. */
- ohci->frame_number = (ohci->frame_number + 1) & 0xffff;
- hcca.frame = cpu_to_le16(ohci->frame_number);
-
- if (ohci->done_count == 0 && !(ohci->intr_status & OHCI_INTR_WD)) {
- if (!ohci->done)
- abort();
- if (ohci->intr & ohci->intr_status)
- ohci->done |= 1;
- hcca.done = cpu_to_le32(ohci->done);
- ohci->done = 0;
- ohci->done_count = 7;
- ohci_set_interrupt(ohci, OHCI_INTR_WD);
- }
-
- if (ohci->done_count != 7 && ohci->done_count != 0)
- ohci->done_count--;
-
- /* Do SOF stuff here */
- ohci_sof(ohci);
-
- /* Writeback HCCA */
- if (ohci_put_hcca(ohci, ohci->hcca, &hcca)) {
- ohci_die(ohci);
- }
-}
-
-/* Start sending SOF tokens across the USB bus, lists are processed in
- * next frame
- */
-static int ohci_bus_start(OHCIState *ohci)
-{
- trace_usb_ohci_start(ohci->name);
-
- /* Delay the first SOF event by one frame time as
- * linux driver is not ready to receive it and
- * can meet some race conditions
- */
-
- ohci_eof_timer(ohci);
-
- return 1;
-}
-
-/* Stop sending SOF tokens on the bus */
-static void ohci_bus_stop(OHCIState *ohci)
-{
- trace_usb_ohci_stop(ohci->name);
- timer_del(ohci->eof_timer);
-}
-
-/* Sets a flag in a port status register but only set it if the port is
- * connected, if not set ConnectStatusChange flag. If flag is enabled
- * return 1.
- */
-static int ohci_port_set_if_connected(OHCIState *ohci, int i, uint32_t val)
-{
- int ret = 1;
-
- /* writing a 0 has no effect */
- if (val == 0)
- return 0;
-
- /* If CurrentConnectStatus is cleared we set
- * ConnectStatusChange
- */
- if (!(ohci->rhport[i].ctrl & OHCI_PORT_CCS)) {
- ohci->rhport[i].ctrl |= OHCI_PORT_CSC;
- if (ohci->rhstatus & OHCI_RHS_DRWE) {
- /* TODO: CSC is a wakeup event */
- }
- return 0;
- }
-
- if (ohci->rhport[i].ctrl & val)
- ret = 0;
-
- /* set the bit */
- ohci->rhport[i].ctrl |= val;
-
- return ret;
-}
-
-/* Set the frame interval - frame interval toggle is manipulated by the hcd only */
-static void ohci_set_frame_interval(OHCIState *ohci, uint16_t val)
-{
- val &= OHCI_FMI_FI;
-
- if (val != ohci->fi) {
- trace_usb_ohci_set_frame_interval(ohci->name, ohci->fi, ohci->fi);
- }
-
- ohci->fi = val;
-}
-
-static void ohci_port_power(OHCIState *ohci, int i, int p)
-{
- if (p) {
- ohci->rhport[i].ctrl |= OHCI_PORT_PPS;
- } else {
- ohci->rhport[i].ctrl &= ~(OHCI_PORT_PPS|
- OHCI_PORT_CCS|
- OHCI_PORT_PSS|
- OHCI_PORT_PRS);
- }
-}
-
-/* Set HcControlRegister */
-static void ohci_set_ctl(OHCIState *ohci, uint32_t val)
-{
- uint32_t old_state;
- uint32_t new_state;
-
- old_state = ohci->ctl & OHCI_CTL_HCFS;
- ohci->ctl = val;
- new_state = ohci->ctl & OHCI_CTL_HCFS;
-
- /* no state change */
- if (old_state == new_state)
- return;
-
- trace_usb_ohci_set_ctl(ohci->name, new_state);
- switch (new_state) {
- case OHCI_USB_OPERATIONAL:
- ohci_bus_start(ohci);
- break;
- case OHCI_USB_SUSPEND:
- ohci_bus_stop(ohci);
- /* clear pending SF otherwise linux driver loops in ohci_irq() */
- ohci->intr_status &= ~OHCI_INTR_SF;
- ohci_intr_update(ohci);
- break;
- case OHCI_USB_RESUME:
- trace_usb_ohci_resume(ohci->name);
- break;
- case OHCI_USB_RESET:
- ohci_roothub_reset(ohci);
- break;
- }
-}
-
-static uint32_t ohci_get_frame_remaining(OHCIState *ohci)
-{
- uint16_t fr;
- int64_t tks;
-
- if ((ohci->ctl & OHCI_CTL_HCFS) != OHCI_USB_OPERATIONAL)
- return (ohci->frt << 31);
-
- /* Being in USB operational state guarnatees sof_time was
- * set already.
- */
- tks = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - ohci->sof_time;
-
- /* avoid muldiv if possible */
- if (tks >= usb_frame_time)
- return (ohci->frt << 31);
-
- tks = muldiv64(1, tks, usb_bit_time);
- fr = (uint16_t)(ohci->fi - tks);
-
- return (ohci->frt << 31) | fr;
-}
-
-
-/* Set root hub status */
-static void ohci_set_hub_status(OHCIState *ohci, uint32_t val)
-{
- uint32_t old_state;
-
- old_state = ohci->rhstatus;
-
- /* write 1 to clear OCIC */
- if (val & OHCI_RHS_OCIC)
- ohci->rhstatus &= ~OHCI_RHS_OCIC;
-
- if (val & OHCI_RHS_LPS) {
- int i;
-
- for (i = 0; i < ohci->num_ports; i++)
- ohci_port_power(ohci, i, 0);
- trace_usb_ohci_hub_power_down();
- }
-
- if (val & OHCI_RHS_LPSC) {
- int i;
-
- for (i = 0; i < ohci->num_ports; i++)
- ohci_port_power(ohci, i, 1);
- trace_usb_ohci_hub_power_up();
- }
-
- if (val & OHCI_RHS_DRWE)
- ohci->rhstatus |= OHCI_RHS_DRWE;
-
- if (val & OHCI_RHS_CRWE)
- ohci->rhstatus &= ~OHCI_RHS_DRWE;
-
- if (old_state != ohci->rhstatus)
- ohci_set_interrupt(ohci, OHCI_INTR_RHSC);
-}
-
-/* Set root hub port status */
-static void ohci_port_set_status(OHCIState *ohci, int portnum, uint32_t val)
-{
- uint32_t old_state;
- OHCIPort *port;
-
- port = &ohci->rhport[portnum];
- old_state = port->ctrl;
-
- /* Write to clear CSC, PESC, PSSC, OCIC, PRSC */
- if (val & OHCI_PORT_WTC)
- port->ctrl &= ~(val & OHCI_PORT_WTC);
-
- if (val & OHCI_PORT_CCS)
- port->ctrl &= ~OHCI_PORT_PES;
-
- ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PES);
-
- if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PSS)) {
- trace_usb_ohci_port_suspend(portnum);
- }
-
- if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PRS)) {
- trace_usb_ohci_port_reset(portnum);
- usb_device_reset(port->port.dev);
- port->ctrl &= ~OHCI_PORT_PRS;
- /* ??? Should this also set OHCI_PORT_PESC. */
- port->ctrl |= OHCI_PORT_PES | OHCI_PORT_PRSC;
- }
-
- /* Invert order here to ensure in ambiguous case, device is
- * powered up...
- */
- if (val & OHCI_PORT_LSDA)
- ohci_port_power(ohci, portnum, 0);
- if (val & OHCI_PORT_PPS)
- ohci_port_power(ohci, portnum, 1);
-
- if (old_state != port->ctrl)
- ohci_set_interrupt(ohci, OHCI_INTR_RHSC);
-}
-
-static uint64_t ohci_mem_read(void *opaque,
- hwaddr addr,
- unsigned size)
-{
- OHCIState *ohci = opaque;
- uint32_t retval;
-
- /* Only aligned reads are allowed on OHCI */
- if (addr & 3) {
- trace_usb_ohci_mem_read_unaligned(addr);
- return 0xffffffff;
- } else if (addr >= 0x54 && addr < 0x54 + ohci->num_ports * 4) {
- /* HcRhPortStatus */
- retval = ohci->rhport[(addr - 0x54) >> 2].ctrl | OHCI_PORT_PPS;
- } else {
- switch (addr >> 2) {
- case 0: /* HcRevision */
- retval = 0x10;
- break;
-
- case 1: /* HcControl */
- retval = ohci->ctl;
- break;
-
- case 2: /* HcCommandStatus */
- retval = ohci->status;
- break;
-
- case 3: /* HcInterruptStatus */
- retval = ohci->intr_status;
- break;
-
- case 4: /* HcInterruptEnable */
- case 5: /* HcInterruptDisable */
- retval = ohci->intr;
- break;
-
- case 6: /* HcHCCA */
- retval = ohci->hcca;
- break;
-
- case 7: /* HcPeriodCurrentED */
- retval = ohci->per_cur;
- break;
-
- case 8: /* HcControlHeadED */
- retval = ohci->ctrl_head;
- break;
-
- case 9: /* HcControlCurrentED */
- retval = ohci->ctrl_cur;
- break;
-
- case 10: /* HcBulkHeadED */
- retval = ohci->bulk_head;
- break;
-
- case 11: /* HcBulkCurrentED */
- retval = ohci->bulk_cur;
- break;
-
- case 12: /* HcDoneHead */
- retval = ohci->done;
- break;
-
- case 13: /* HcFmInterretval */
- retval = (ohci->fit << 31) | (ohci->fsmps << 16) | (ohci->fi);
- break;
-
- case 14: /* HcFmRemaining */
- retval = ohci_get_frame_remaining(ohci);
- break;
-
- case 15: /* HcFmNumber */
- retval = ohci->frame_number;
- break;
-
- case 16: /* HcPeriodicStart */
- retval = ohci->pstart;
- break;
-
- case 17: /* HcLSThreshold */
- retval = ohci->lst;
- break;
-
- case 18: /* HcRhDescriptorA */
- retval = ohci->rhdesc_a;
- break;
-
- case 19: /* HcRhDescriptorB */
- retval = ohci->rhdesc_b;
- break;
-
- case 20: /* HcRhStatus */
- retval = ohci->rhstatus;
- break;
-
- /* PXA27x specific registers */
- case 24: /* HcStatus */
- retval = ohci->hstatus & ohci->hmask;
- break;
-
- case 25: /* HcHReset */
- retval = ohci->hreset;
- break;
-
- case 26: /* HcHInterruptEnable */
- retval = ohci->hmask;
- break;
-
- case 27: /* HcHInterruptTest */
- retval = ohci->htest;
- break;
-
- default:
- trace_usb_ohci_mem_read_bad_offset(addr);
- retval = 0xffffffff;
- }
- }
-
- return retval;
-}
-
-static void ohci_mem_write(void *opaque,
- hwaddr addr,
- uint64_t val,
- unsigned size)
-{
- OHCIState *ohci = opaque;
-
- /* Only aligned reads are allowed on OHCI */
- if (addr & 3) {
- trace_usb_ohci_mem_write_unaligned(addr);
- return;
- }
-
- if (addr >= 0x54 && addr < 0x54 + ohci->num_ports * 4) {
- /* HcRhPortStatus */
- ohci_port_set_status(ohci, (addr - 0x54) >> 2, val);
- return;
- }
-
- switch (addr >> 2) {
- case 1: /* HcControl */
- ohci_set_ctl(ohci, val);
- break;
-
- case 2: /* HcCommandStatus */
- /* SOC is read-only */
- val = (val & ~OHCI_STATUS_SOC);
-
- /* Bits written as '0' remain unchanged in the register */
- ohci->status |= val;
-
- if (ohci->status & OHCI_STATUS_HCR)
- ohci_soft_reset(ohci);
- break;
-
- case 3: /* HcInterruptStatus */
- ohci->intr_status &= ~val;
- ohci_intr_update(ohci);
- break;
-
- case 4: /* HcInterruptEnable */
- ohci->intr |= val;
- ohci_intr_update(ohci);
- break;
-
- case 5: /* HcInterruptDisable */
- ohci->intr &= ~val;
- ohci_intr_update(ohci);
- break;
-
- case 6: /* HcHCCA */
- ohci->hcca = val & OHCI_HCCA_MASK;
- break;
-
- case 7: /* HcPeriodCurrentED */
- /* Ignore writes to this read-only register, Linux does them */
- break;
-
- case 8: /* HcControlHeadED */
- ohci->ctrl_head = val & OHCI_EDPTR_MASK;
- break;
-
- case 9: /* HcControlCurrentED */
- ohci->ctrl_cur = val & OHCI_EDPTR_MASK;
- break;
-
- case 10: /* HcBulkHeadED */
- ohci->bulk_head = val & OHCI_EDPTR_MASK;
- break;
-
- case 11: /* HcBulkCurrentED */
- ohci->bulk_cur = val & OHCI_EDPTR_MASK;
- break;
-
- case 13: /* HcFmInterval */
- ohci->fsmps = (val & OHCI_FMI_FSMPS) >> 16;
- ohci->fit = (val & OHCI_FMI_FIT) >> 31;
- ohci_set_frame_interval(ohci, val);
- break;
-
- case 15: /* HcFmNumber */
- break;
-
- case 16: /* HcPeriodicStart */
- ohci->pstart = val & 0xffff;
- break;
-
- case 17: /* HcLSThreshold */
- ohci->lst = val & 0xffff;
- break;
-
- case 18: /* HcRhDescriptorA */
- ohci->rhdesc_a &= ~OHCI_RHA_RW_MASK;
- ohci->rhdesc_a |= val & OHCI_RHA_RW_MASK;
- break;
-
- case 19: /* HcRhDescriptorB */
- break;
-
- case 20: /* HcRhStatus */
- ohci_set_hub_status(ohci, val);
- break;
-
- /* PXA27x specific registers */
- case 24: /* HcStatus */
- ohci->hstatus &= ~(val & ohci->hmask);
- break;
-
- case 25: /* HcHReset */
- ohci->hreset = val & ~OHCI_HRESET_FSBIR;
- if (val & OHCI_HRESET_FSBIR)
- ohci_hard_reset(ohci);
- break;
-
- case 26: /* HcHInterruptEnable */
- ohci->hmask = val;
- break;
-
- case 27: /* HcHInterruptTest */
- ohci->htest = val;
- break;
-
- default:
- trace_usb_ohci_mem_write_bad_offset(addr);
- break;
- }
-}
-
-static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev)
-{
- if (ohci->async_td &&
- usb_packet_is_inflight(&ohci->usb_packet) &&
- ohci->usb_packet.ep->dev == dev) {
- usb_cancel_packet(&ohci->usb_packet);
- ohci->async_td = 0;
- }
-}
-
-static const MemoryRegionOps ohci_mem_ops = {
- .read = ohci_mem_read,
- .write = ohci_mem_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static USBPortOps ohci_port_ops = {
- .attach = ohci_attach,
- .detach = ohci_detach,
- .child_detach = ohci_child_detach,
- .wakeup = ohci_wakeup,
- .complete = ohci_async_complete_packet,
-};
-
-static USBBusOps ohci_bus_ops = {
-};
-
-static void usb_ohci_init(OHCIState *ohci, DeviceState *dev,
- int num_ports, dma_addr_t localmem_base,
- char *masterbus, uint32_t firstport,
- AddressSpace *as, Error **errp)
-{
- Error *err = NULL;
- int i;
-
- ohci->as = as;
-
- if (usb_frame_time == 0) {
-#ifdef OHCI_TIME_WARP
- usb_frame_time = NANOSECONDS_PER_SECOND;
- usb_bit_time = NANOSECONDS_PER_SECOND / (USB_HZ / 1000);
-#else
- usb_frame_time = NANOSECONDS_PER_SECOND / 1000;
- if (NANOSECONDS_PER_SECOND >= USB_HZ) {
- usb_bit_time = NANOSECONDS_PER_SECOND / USB_HZ;
- } else {
- usb_bit_time = 1;
- }
-#endif
- trace_usb_ohci_init_time(usb_frame_time, usb_bit_time);
- }
-
- ohci->num_ports = num_ports;
- if (masterbus) {
- USBPort *ports[OHCI_MAX_PORTS];
- for(i = 0; i < num_ports; i++) {
- ports[i] = &ohci->rhport[i].port;
- }
- usb_register_companion(masterbus, ports, num_ports,
- firstport, ohci, &ohci_port_ops,
- USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL,
- &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- } else {
- usb_bus_new(&ohci->bus, sizeof(ohci->bus), &ohci_bus_ops, dev);
- for (i = 0; i < num_ports; i++) {
- usb_register_port(&ohci->bus, &ohci->rhport[i].port,
- ohci, i, &ohci_port_ops,
- USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
- }
- }
-
- memory_region_init_io(&ohci->mem, OBJECT(dev), &ohci_mem_ops,
- ohci, "ohci", 256);
- ohci->localmem_base = localmem_base;
-
- ohci->name = object_get_typename(OBJECT(dev));
- usb_packet_init(&ohci->usb_packet);
-
- ohci->async_td = 0;
-
- ohci->eof_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
- ohci_frame_boundary, ohci);
-}
-
-#define TYPE_PCI_OHCI "pci-ohci"
-#define PCI_OHCI(obj) OBJECT_CHECK(OHCIPCIState, (obj), TYPE_PCI_OHCI)
-
-typedef struct {
- /*< private >*/
- PCIDevice parent_obj;
- /*< public >*/
-
- OHCIState state;
- char *masterbus;
- uint32_t num_ports;
- uint32_t firstport;
-} OHCIPCIState;
-
-/** A typical O/EHCI will stop operating, set itself into error state
- * (which can be queried by MMIO) and will set PERR in its config
- * space to signal that it got an error
- */
-static void ohci_die(OHCIState *ohci)
-{
- OHCIPCIState *dev = container_of(ohci, OHCIPCIState, state);
-
- trace_usb_ohci_die();
-
- ohci_set_interrupt(ohci, OHCI_INTR_UE);
- ohci_bus_stop(ohci);
- pci_set_word(dev->parent_obj.config + PCI_STATUS,
- PCI_STATUS_DETECTED_PARITY);
-}
-
-static void usb_ohci_realize_pci(PCIDevice *dev, Error **errp)
-{
- Error *err = NULL;
- OHCIPCIState *ohci = PCI_OHCI(dev);
-
- dev->config[PCI_CLASS_PROG] = 0x10; /* OHCI */
- dev->config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */
-
- usb_ohci_init(&ohci->state, DEVICE(dev), ohci->num_ports, 0,
- ohci->masterbus, ohci->firstport,
- pci_get_address_space(dev), &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- ohci->state.irq = pci_allocate_irq(dev);
- pci_register_bar(dev, 0, 0, &ohci->state.mem);
-}
-
-static void usb_ohci_exit(PCIDevice *dev)
-{
- OHCIPCIState *ohci = PCI_OHCI(dev);
- OHCIState *s = &ohci->state;
-
- trace_usb_ohci_exit(s->name);
- ohci_bus_stop(s);
-
- if (s->async_td) {
- usb_cancel_packet(&s->usb_packet);
- s->async_td = 0;
- }
- ohci_stop_endpoints(s);
-
- if (!ohci->masterbus) {
- usb_bus_release(&s->bus);
- }
-
- timer_del(s->eof_timer);
- timer_free(s->eof_timer);
-}
-
-static void usb_ohci_reset_pci(DeviceState *d)
-{
- PCIDevice *dev = PCI_DEVICE(d);
- OHCIPCIState *ohci = PCI_OHCI(dev);
- OHCIState *s = &ohci->state;
-
- ohci_hard_reset(s);
-}
-
-#define TYPE_SYSBUS_OHCI "sysbus-ohci"
-#define SYSBUS_OHCI(obj) OBJECT_CHECK(OHCISysBusState, (obj), TYPE_SYSBUS_OHCI)
-
-typedef struct {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- OHCIState ohci;
- uint32_t num_ports;
- dma_addr_t dma_offset;
-} OHCISysBusState;
-
-static void ohci_realize_pxa(DeviceState *dev, Error **errp)
-{
- OHCISysBusState *s = SYSBUS_OHCI(dev);
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
-
- /* Cannot fail as we pass NULL for masterbus */
- usb_ohci_init(&s->ohci, dev, s->num_ports, s->dma_offset, NULL, 0,
- &address_space_memory, &error_abort);
- sysbus_init_irq(sbd, &s->ohci.irq);
- sysbus_init_mmio(sbd, &s->ohci.mem);
-}
-
-static void usb_ohci_reset_sysbus(DeviceState *dev)
-{
- OHCISysBusState *s = SYSBUS_OHCI(dev);
- OHCIState *ohci = &s->ohci;
-
- ohci_hard_reset(ohci);
-}
-
-static Property ohci_pci_properties[] = {
- DEFINE_PROP_STRING("masterbus", OHCIPCIState, masterbus),
- DEFINE_PROP_UINT32("num-ports", OHCIPCIState, num_ports, 3),
- DEFINE_PROP_UINT32("firstport", OHCIPCIState, firstport, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static const VMStateDescription vmstate_ohci_state_port = {
- .name = "ohci-core/port",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(ctrl, OHCIPort),
- VMSTATE_END_OF_LIST()
- },
-};
-
-static bool ohci_eof_timer_needed(void *opaque)
-{
- OHCIState *ohci = opaque;
-
- return timer_pending(ohci->eof_timer);
-}
-
-static const VMStateDescription vmstate_ohci_eof_timer = {
- .name = "ohci-core/eof-timer",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = ohci_eof_timer_needed,
- .fields = (VMStateField[]) {
- VMSTATE_TIMER_PTR(eof_timer, OHCIState),
- VMSTATE_END_OF_LIST()
- },
-};
-
-static const VMStateDescription vmstate_ohci_state = {
- .name = "ohci-core",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_INT64(sof_time, OHCIState),
- VMSTATE_UINT32(ctl, OHCIState),
- VMSTATE_UINT32(status, OHCIState),
- VMSTATE_UINT32(intr_status, OHCIState),
- VMSTATE_UINT32(intr, OHCIState),
- VMSTATE_UINT32(hcca, OHCIState),
- VMSTATE_UINT32(ctrl_head, OHCIState),
- VMSTATE_UINT32(ctrl_cur, OHCIState),
- VMSTATE_UINT32(bulk_head, OHCIState),
- VMSTATE_UINT32(bulk_cur, OHCIState),
- VMSTATE_UINT32(per_cur, OHCIState),
- VMSTATE_UINT32(done, OHCIState),
- VMSTATE_INT32(done_count, OHCIState),
- VMSTATE_UINT16(fsmps, OHCIState),
- VMSTATE_UINT8(fit, OHCIState),
- VMSTATE_UINT16(fi, OHCIState),
- VMSTATE_UINT8(frt, OHCIState),
- VMSTATE_UINT16(frame_number, OHCIState),
- VMSTATE_UINT16(padding, OHCIState),
- VMSTATE_UINT32(pstart, OHCIState),
- VMSTATE_UINT32(lst, OHCIState),
- VMSTATE_UINT32(rhdesc_a, OHCIState),
- VMSTATE_UINT32(rhdesc_b, OHCIState),
- VMSTATE_UINT32(rhstatus, OHCIState),
- VMSTATE_STRUCT_ARRAY(rhport, OHCIState, OHCI_MAX_PORTS, 0,
- vmstate_ohci_state_port, OHCIPort),
- VMSTATE_UINT32(hstatus, OHCIState),
- VMSTATE_UINT32(hmask, OHCIState),
- VMSTATE_UINT32(hreset, OHCIState),
- VMSTATE_UINT32(htest, OHCIState),
- VMSTATE_UINT32(old_ctl, OHCIState),
- VMSTATE_UINT8_ARRAY(usb_buf, OHCIState, 8192),
- VMSTATE_UINT32(async_td, OHCIState),
- VMSTATE_BOOL(async_complete, OHCIState),
- VMSTATE_END_OF_LIST()
- },
- .subsections = (const VMStateDescription*[]) {
- &vmstate_ohci_eof_timer,
- NULL
- }
-};
-
-static const VMStateDescription vmstate_ohci = {
- .name = "ohci",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(parent_obj, OHCIPCIState),
- VMSTATE_STRUCT(state, OHCIPCIState, 1, vmstate_ohci_state, OHCIState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void ohci_pci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = usb_ohci_realize_pci;
- k->exit = usb_ohci_exit;
- k->vendor_id = PCI_VENDOR_ID_APPLE;
- k->device_id = PCI_DEVICE_ID_APPLE_IPID_USB;
- k->class_id = PCI_CLASS_SERIAL_USB;
- set_bit(DEVICE_CATEGORY_USB, dc->categories);
- dc->desc = "Apple USB Controller";
- dc->props = ohci_pci_properties;
- dc->hotpluggable = false;
- dc->vmsd = &vmstate_ohci;
- dc->reset = usb_ohci_reset_pci;
-}
-
-static const TypeInfo ohci_pci_info = {
- .name = TYPE_PCI_OHCI,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(OHCIPCIState),
- .class_init = ohci_pci_class_init,
-};
-
-static Property ohci_sysbus_properties[] = {
- DEFINE_PROP_UINT32("num-ports", OHCISysBusState, num_ports, 3),
- DEFINE_PROP_DMAADDR("dma-offset", OHCISysBusState, dma_offset, 3),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void ohci_sysbus_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = ohci_realize_pxa;
- set_bit(DEVICE_CATEGORY_USB, dc->categories);
- dc->desc = "OHCI USB Controller";
- dc->props = ohci_sysbus_properties;
- dc->reset = usb_ohci_reset_sysbus;
-}
-
-static const TypeInfo ohci_sysbus_info = {
- .name = TYPE_SYSBUS_OHCI,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(OHCISysBusState),
- .class_init = ohci_sysbus_class_init,
-};
-
-static void ohci_register_types(void)
-{
- type_register_static(&ohci_pci_info);
- type_register_static(&ohci_sysbus_info);
-}
-
-type_init(ohci_register_types)
diff --git a/qemu/hw/usb/hcd-uhci.c b/qemu/hw/usb/hcd-uhci.c
deleted file mode 100644
index ca72a80f2..000000000
--- a/qemu/hw/usb/hcd-uhci.c
+++ /dev/null
@@ -1,1435 +0,0 @@
-/*
- * USB UHCI controller emulation
- *
- * Copyright (c) 2005 Fabrice Bellard
- *
- * Copyright (c) 2008 Max Krasnyansky
- * Magor rewrite of the UHCI data structures parser and frame processor
- * Support for fully async operation and multiple outstanding transactions
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/usb.h"
-#include "hw/usb/uhci-regs.h"
-#include "hw/pci/pci.h"
-#include "qapi/error.h"
-#include "qemu/timer.h"
-#include "qemu/iov.h"
-#include "sysemu/dma.h"
-#include "trace.h"
-#include "qemu/main-loop.h"
-
-#define FRAME_TIMER_FREQ 1000
-
-#define FRAME_MAX_LOOPS 256
-
-/* Must be large enough to handle 10 frame delay for initial isoc requests */
-#define QH_VALID 32
-
-#define MAX_FRAMES_PER_TICK (QH_VALID / 2)
-
-#define NB_PORTS 2
-
-enum {
- TD_RESULT_STOP_FRAME = 10,
- TD_RESULT_COMPLETE,
- TD_RESULT_NEXT_QH,
- TD_RESULT_ASYNC_START,
- TD_RESULT_ASYNC_CONT,
-};
-
-typedef struct UHCIState UHCIState;
-typedef struct UHCIAsync UHCIAsync;
-typedef struct UHCIQueue UHCIQueue;
-typedef struct UHCIInfo UHCIInfo;
-typedef struct UHCIPCIDeviceClass UHCIPCIDeviceClass;
-
-struct UHCIInfo {
- const char *name;
- uint16_t vendor_id;
- uint16_t device_id;
- uint8_t revision;
- uint8_t irq_pin;
- void (*realize)(PCIDevice *dev, Error **errp);
- bool unplug;
-};
-
-struct UHCIPCIDeviceClass {
- PCIDeviceClass parent_class;
- UHCIInfo info;
-};
-
-/*
- * Pending async transaction.
- * 'packet' must be the first field because completion
- * handler does "(UHCIAsync *) pkt" cast.
- */
-
-struct UHCIAsync {
- USBPacket packet;
- uint8_t static_buf[64]; /* 64 bytes is enough, except for isoc packets */
- uint8_t *buf;
- UHCIQueue *queue;
- QTAILQ_ENTRY(UHCIAsync) next;
- uint32_t td_addr;
- uint8_t done;
-};
-
-struct UHCIQueue {
- uint32_t qh_addr;
- uint32_t token;
- UHCIState *uhci;
- USBEndpoint *ep;
- QTAILQ_ENTRY(UHCIQueue) next;
- QTAILQ_HEAD(asyncs_head, UHCIAsync) asyncs;
- int8_t valid;
-};
-
-typedef struct UHCIPort {
- USBPort port;
- uint16_t ctrl;
-} UHCIPort;
-
-struct UHCIState {
- PCIDevice dev;
- MemoryRegion io_bar;
- USBBus bus; /* Note unused when we're a companion controller */
- uint16_t cmd; /* cmd register */
- uint16_t status;
- uint16_t intr; /* interrupt enable register */
- uint16_t frnum; /* frame number */
- uint32_t fl_base_addr; /* frame list base address */
- uint8_t sof_timing;
- uint8_t status2; /* bit 0 and 1 are used to generate UHCI_STS_USBINT */
- int64_t expire_time;
- QEMUTimer *frame_timer;
- QEMUBH *bh;
- uint32_t frame_bytes;
- uint32_t frame_bandwidth;
- bool completions_only;
- UHCIPort ports[NB_PORTS];
-
- /* Interrupts that should be raised at the end of the current frame. */
- uint32_t pending_int_mask;
-
- /* Active packets */
- QTAILQ_HEAD(, UHCIQueue) queues;
- uint8_t num_ports_vmstate;
-
- /* Properties */
- char *masterbus;
- uint32_t firstport;
- uint32_t maxframes;
-};
-
-typedef struct UHCI_TD {
- uint32_t link;
- uint32_t ctrl; /* see TD_CTRL_xxx */
- uint32_t token;
- uint32_t buffer;
-} UHCI_TD;
-
-typedef struct UHCI_QH {
- uint32_t link;
- uint32_t el_link;
-} UHCI_QH;
-
-static void uhci_async_cancel(UHCIAsync *async);
-static void uhci_queue_fill(UHCIQueue *q, UHCI_TD *td);
-static void uhci_resume(void *opaque);
-
-#define TYPE_UHCI "pci-uhci-usb"
-#define UHCI(obj) OBJECT_CHECK(UHCIState, (obj), TYPE_UHCI)
-
-static inline int32_t uhci_queue_token(UHCI_TD *td)
-{
- if ((td->token & (0xf << 15)) == 0) {
- /* ctrl ep, cover ep and dev, not pid! */
- return td->token & 0x7ff00;
- } else {
- /* covers ep, dev, pid -> identifies the endpoint */
- return td->token & 0x7ffff;
- }
-}
-
-static UHCIQueue *uhci_queue_new(UHCIState *s, uint32_t qh_addr, UHCI_TD *td,
- USBEndpoint *ep)
-{
- UHCIQueue *queue;
-
- queue = g_new0(UHCIQueue, 1);
- queue->uhci = s;
- queue->qh_addr = qh_addr;
- queue->token = uhci_queue_token(td);
- queue->ep = ep;
- QTAILQ_INIT(&queue->asyncs);
- QTAILQ_INSERT_HEAD(&s->queues, queue, next);
- queue->valid = QH_VALID;
- trace_usb_uhci_queue_add(queue->token);
- return queue;
-}
-
-static void uhci_queue_free(UHCIQueue *queue, const char *reason)
-{
- UHCIState *s = queue->uhci;
- UHCIAsync *async;
-
- while (!QTAILQ_EMPTY(&queue->asyncs)) {
- async = QTAILQ_FIRST(&queue->asyncs);
- uhci_async_cancel(async);
- }
- usb_device_ep_stopped(queue->ep->dev, queue->ep);
-
- trace_usb_uhci_queue_del(queue->token, reason);
- QTAILQ_REMOVE(&s->queues, queue, next);
- g_free(queue);
-}
-
-static UHCIQueue *uhci_queue_find(UHCIState *s, UHCI_TD *td)
-{
- uint32_t token = uhci_queue_token(td);
- UHCIQueue *queue;
-
- QTAILQ_FOREACH(queue, &s->queues, next) {
- if (queue->token == token) {
- return queue;
- }
- }
- return NULL;
-}
-
-static bool uhci_queue_verify(UHCIQueue *queue, uint32_t qh_addr, UHCI_TD *td,
- uint32_t td_addr, bool queuing)
-{
- UHCIAsync *first = QTAILQ_FIRST(&queue->asyncs);
- uint32_t queue_token_addr = (queue->token >> 8) & 0x7f;
-
- return queue->qh_addr == qh_addr &&
- queue->token == uhci_queue_token(td) &&
- queue_token_addr == queue->ep->dev->addr &&
- (queuing || !(td->ctrl & TD_CTRL_ACTIVE) || first == NULL ||
- first->td_addr == td_addr);
-}
-
-static UHCIAsync *uhci_async_alloc(UHCIQueue *queue, uint32_t td_addr)
-{
- UHCIAsync *async = g_new0(UHCIAsync, 1);
-
- async->queue = queue;
- async->td_addr = td_addr;
- usb_packet_init(&async->packet);
- trace_usb_uhci_packet_add(async->queue->token, async->td_addr);
-
- return async;
-}
-
-static void uhci_async_free(UHCIAsync *async)
-{
- trace_usb_uhci_packet_del(async->queue->token, async->td_addr);
- usb_packet_cleanup(&async->packet);
- if (async->buf != async->static_buf) {
- g_free(async->buf);
- }
- g_free(async);
-}
-
-static void uhci_async_link(UHCIAsync *async)
-{
- UHCIQueue *queue = async->queue;
- QTAILQ_INSERT_TAIL(&queue->asyncs, async, next);
- trace_usb_uhci_packet_link_async(async->queue->token, async->td_addr);
-}
-
-static void uhci_async_unlink(UHCIAsync *async)
-{
- UHCIQueue *queue = async->queue;
- QTAILQ_REMOVE(&queue->asyncs, async, next);
- trace_usb_uhci_packet_unlink_async(async->queue->token, async->td_addr);
-}
-
-static void uhci_async_cancel(UHCIAsync *async)
-{
- uhci_async_unlink(async);
- trace_usb_uhci_packet_cancel(async->queue->token, async->td_addr,
- async->done);
- if (!async->done)
- usb_cancel_packet(&async->packet);
- uhci_async_free(async);
-}
-
-/*
- * Mark all outstanding async packets as invalid.
- * This is used for canceling them when TDs are removed by the HCD.
- */
-static void uhci_async_validate_begin(UHCIState *s)
-{
- UHCIQueue *queue;
-
- QTAILQ_FOREACH(queue, &s->queues, next) {
- queue->valid--;
- }
-}
-
-/*
- * Cancel async packets that are no longer valid
- */
-static void uhci_async_validate_end(UHCIState *s)
-{
- UHCIQueue *queue, *n;
-
- QTAILQ_FOREACH_SAFE(queue, &s->queues, next, n) {
- if (!queue->valid) {
- uhci_queue_free(queue, "validate-end");
- }
- }
-}
-
-static void uhci_async_cancel_device(UHCIState *s, USBDevice *dev)
-{
- UHCIQueue *queue, *n;
-
- QTAILQ_FOREACH_SAFE(queue, &s->queues, next, n) {
- if (queue->ep->dev == dev) {
- uhci_queue_free(queue, "cancel-device");
- }
- }
-}
-
-static void uhci_async_cancel_all(UHCIState *s)
-{
- UHCIQueue *queue, *nq;
-
- QTAILQ_FOREACH_SAFE(queue, &s->queues, next, nq) {
- uhci_queue_free(queue, "cancel-all");
- }
-}
-
-static UHCIAsync *uhci_async_find_td(UHCIState *s, uint32_t td_addr)
-{
- UHCIQueue *queue;
- UHCIAsync *async;
-
- QTAILQ_FOREACH(queue, &s->queues, next) {
- QTAILQ_FOREACH(async, &queue->asyncs, next) {
- if (async->td_addr == td_addr) {
- return async;
- }
- }
- }
- return NULL;
-}
-
-static void uhci_update_irq(UHCIState *s)
-{
- int level;
- if (((s->status2 & 1) && (s->intr & (1 << 2))) ||
- ((s->status2 & 2) && (s->intr & (1 << 3))) ||
- ((s->status & UHCI_STS_USBERR) && (s->intr & (1 << 0))) ||
- ((s->status & UHCI_STS_RD) && (s->intr & (1 << 1))) ||
- (s->status & UHCI_STS_HSERR) ||
- (s->status & UHCI_STS_HCPERR)) {
- level = 1;
- } else {
- level = 0;
- }
- pci_set_irq(&s->dev, level);
-}
-
-static void uhci_reset(DeviceState *dev)
-{
- PCIDevice *d = PCI_DEVICE(dev);
- UHCIState *s = UHCI(d);
- uint8_t *pci_conf;
- int i;
- UHCIPort *port;
-
- trace_usb_uhci_reset();
-
- pci_conf = s->dev.config;
-
- pci_conf[0x6a] = 0x01; /* usb clock */
- pci_conf[0x6b] = 0x00;
- s->cmd = 0;
- s->status = UHCI_STS_HCHALTED;
- s->status2 = 0;
- s->intr = 0;
- s->fl_base_addr = 0;
- s->sof_timing = 64;
-
- for(i = 0; i < NB_PORTS; i++) {
- port = &s->ports[i];
- port->ctrl = 0x0080;
- if (port->port.dev && port->port.dev->attached) {
- usb_port_reset(&port->port);
- }
- }
-
- uhci_async_cancel_all(s);
- qemu_bh_cancel(s->bh);
- uhci_update_irq(s);
-}
-
-static const VMStateDescription vmstate_uhci_port = {
- .name = "uhci port",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT16(ctrl, UHCIPort),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static int uhci_post_load(void *opaque, int version_id)
-{
- UHCIState *s = opaque;
-
- if (version_id < 2) {
- s->expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- (NANOSECONDS_PER_SECOND / FRAME_TIMER_FREQ);
- }
- return 0;
-}
-
-static const VMStateDescription vmstate_uhci = {
- .name = "uhci",
- .version_id = 3,
- .minimum_version_id = 1,
- .post_load = uhci_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(dev, UHCIState),
- VMSTATE_UINT8_EQUAL(num_ports_vmstate, UHCIState),
- VMSTATE_STRUCT_ARRAY(ports, UHCIState, NB_PORTS, 1,
- vmstate_uhci_port, UHCIPort),
- VMSTATE_UINT16(cmd, UHCIState),
- VMSTATE_UINT16(status, UHCIState),
- VMSTATE_UINT16(intr, UHCIState),
- VMSTATE_UINT16(frnum, UHCIState),
- VMSTATE_UINT32(fl_base_addr, UHCIState),
- VMSTATE_UINT8(sof_timing, UHCIState),
- VMSTATE_UINT8(status2, UHCIState),
- VMSTATE_TIMER_PTR(frame_timer, UHCIState),
- VMSTATE_INT64_V(expire_time, UHCIState, 2),
- VMSTATE_UINT32_V(pending_int_mask, UHCIState, 3),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void uhci_port_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- UHCIState *s = opaque;
-
- trace_usb_uhci_mmio_writew(addr, val);
-
- switch(addr) {
- case 0x00:
- if ((val & UHCI_CMD_RS) && !(s->cmd & UHCI_CMD_RS)) {
- /* start frame processing */
- trace_usb_uhci_schedule_start();
- s->expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- (NANOSECONDS_PER_SECOND / FRAME_TIMER_FREQ);
- timer_mod(s->frame_timer, s->expire_time);
- s->status &= ~UHCI_STS_HCHALTED;
- } else if (!(val & UHCI_CMD_RS)) {
- s->status |= UHCI_STS_HCHALTED;
- }
- if (val & UHCI_CMD_GRESET) {
- UHCIPort *port;
- int i;
-
- /* send reset on the USB bus */
- for(i = 0; i < NB_PORTS; i++) {
- port = &s->ports[i];
- usb_device_reset(port->port.dev);
- }
- uhci_reset(DEVICE(s));
- return;
- }
- if (val & UHCI_CMD_HCRESET) {
- uhci_reset(DEVICE(s));
- return;
- }
- s->cmd = val;
- if (val & UHCI_CMD_EGSM) {
- if ((s->ports[0].ctrl & UHCI_PORT_RD) ||
- (s->ports[1].ctrl & UHCI_PORT_RD)) {
- uhci_resume(s);
- }
- }
- break;
- case 0x02:
- s->status &= ~val;
- /* XXX: the chip spec is not coherent, so we add a hidden
- register to distinguish between IOC and SPD */
- if (val & UHCI_STS_USBINT)
- s->status2 = 0;
- uhci_update_irq(s);
- break;
- case 0x04:
- s->intr = val;
- uhci_update_irq(s);
- break;
- case 0x06:
- if (s->status & UHCI_STS_HCHALTED)
- s->frnum = val & 0x7ff;
- break;
- case 0x08:
- s->fl_base_addr &= 0xffff0000;
- s->fl_base_addr |= val & ~0xfff;
- break;
- case 0x0a:
- s->fl_base_addr &= 0x0000ffff;
- s->fl_base_addr |= (val << 16);
- break;
- case 0x0c:
- s->sof_timing = val & 0xff;
- break;
- case 0x10 ... 0x1f:
- {
- UHCIPort *port;
- USBDevice *dev;
- int n;
-
- n = (addr >> 1) & 7;
- if (n >= NB_PORTS)
- return;
- port = &s->ports[n];
- dev = port->port.dev;
- if (dev && dev->attached) {
- /* port reset */
- if ( (val & UHCI_PORT_RESET) &&
- !(port->ctrl & UHCI_PORT_RESET) ) {
- usb_device_reset(dev);
- }
- }
- port->ctrl &= UHCI_PORT_READ_ONLY;
- /* enabled may only be set if a device is connected */
- if (!(port->ctrl & UHCI_PORT_CCS)) {
- val &= ~UHCI_PORT_EN;
- }
- port->ctrl |= (val & ~UHCI_PORT_READ_ONLY);
- /* some bits are reset when a '1' is written to them */
- port->ctrl &= ~(val & UHCI_PORT_WRITE_CLEAR);
- }
- break;
- }
-}
-
-static uint64_t uhci_port_read(void *opaque, hwaddr addr, unsigned size)
-{
- UHCIState *s = opaque;
- uint32_t val;
-
- switch(addr) {
- case 0x00:
- val = s->cmd;
- break;
- case 0x02:
- val = s->status;
- break;
- case 0x04:
- val = s->intr;
- break;
- case 0x06:
- val = s->frnum;
- break;
- case 0x08:
- val = s->fl_base_addr & 0xffff;
- break;
- case 0x0a:
- val = (s->fl_base_addr >> 16) & 0xffff;
- break;
- case 0x0c:
- val = s->sof_timing;
- break;
- case 0x10 ... 0x1f:
- {
- UHCIPort *port;
- int n;
- n = (addr >> 1) & 7;
- if (n >= NB_PORTS)
- goto read_default;
- port = &s->ports[n];
- val = port->ctrl;
- }
- break;
- default:
- read_default:
- val = 0xff7f; /* disabled port */
- break;
- }
-
- trace_usb_uhci_mmio_readw(addr, val);
-
- return val;
-}
-
-/* signal resume if controller suspended */
-static void uhci_resume (void *opaque)
-{
- UHCIState *s = (UHCIState *)opaque;
-
- if (!s)
- return;
-
- if (s->cmd & UHCI_CMD_EGSM) {
- s->cmd |= UHCI_CMD_FGR;
- s->status |= UHCI_STS_RD;
- uhci_update_irq(s);
- }
-}
-
-static void uhci_attach(USBPort *port1)
-{
- UHCIState *s = port1->opaque;
- UHCIPort *port = &s->ports[port1->index];
-
- /* set connect status */
- port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC;
-
- /* update speed */
- if (port->port.dev->speed == USB_SPEED_LOW) {
- port->ctrl |= UHCI_PORT_LSDA;
- } else {
- port->ctrl &= ~UHCI_PORT_LSDA;
- }
-
- uhci_resume(s);
-}
-
-static void uhci_detach(USBPort *port1)
-{
- UHCIState *s = port1->opaque;
- UHCIPort *port = &s->ports[port1->index];
-
- uhci_async_cancel_device(s, port1->dev);
-
- /* set connect status */
- if (port->ctrl & UHCI_PORT_CCS) {
- port->ctrl &= ~UHCI_PORT_CCS;
- port->ctrl |= UHCI_PORT_CSC;
- }
- /* disable port */
- if (port->ctrl & UHCI_PORT_EN) {
- port->ctrl &= ~UHCI_PORT_EN;
- port->ctrl |= UHCI_PORT_ENC;
- }
-
- uhci_resume(s);
-}
-
-static void uhci_child_detach(USBPort *port1, USBDevice *child)
-{
- UHCIState *s = port1->opaque;
-
- uhci_async_cancel_device(s, child);
-}
-
-static void uhci_wakeup(USBPort *port1)
-{
- UHCIState *s = port1->opaque;
- UHCIPort *port = &s->ports[port1->index];
-
- if (port->ctrl & UHCI_PORT_SUSPEND && !(port->ctrl & UHCI_PORT_RD)) {
- port->ctrl |= UHCI_PORT_RD;
- uhci_resume(s);
- }
-}
-
-static USBDevice *uhci_find_device(UHCIState *s, uint8_t addr)
-{
- USBDevice *dev;
- int i;
-
- for (i = 0; i < NB_PORTS; i++) {
- UHCIPort *port = &s->ports[i];
- if (!(port->ctrl & UHCI_PORT_EN)) {
- continue;
- }
- dev = usb_find_device(&port->port, addr);
- if (dev != NULL) {
- return dev;
- }
- }
- return NULL;
-}
-
-static void uhci_read_td(UHCIState *s, UHCI_TD *td, uint32_t link)
-{
- pci_dma_read(&s->dev, link & ~0xf, td, sizeof(*td));
- le32_to_cpus(&td->link);
- le32_to_cpus(&td->ctrl);
- le32_to_cpus(&td->token);
- le32_to_cpus(&td->buffer);
-}
-
-static int uhci_handle_td_error(UHCIState *s, UHCI_TD *td, uint32_t td_addr,
- int status, uint32_t *int_mask)
-{
- uint32_t queue_token = uhci_queue_token(td);
- int ret;
-
- switch (status) {
- case USB_RET_NAK:
- td->ctrl |= TD_CTRL_NAK;
- return TD_RESULT_NEXT_QH;
-
- case USB_RET_STALL:
- td->ctrl |= TD_CTRL_STALL;
- trace_usb_uhci_packet_complete_stall(queue_token, td_addr);
- ret = TD_RESULT_NEXT_QH;
- break;
-
- case USB_RET_BABBLE:
- td->ctrl |= TD_CTRL_BABBLE | TD_CTRL_STALL;
- /* frame interrupted */
- trace_usb_uhci_packet_complete_babble(queue_token, td_addr);
- ret = TD_RESULT_STOP_FRAME;
- break;
-
- case USB_RET_IOERROR:
- case USB_RET_NODEV:
- default:
- td->ctrl |= TD_CTRL_TIMEOUT;
- td->ctrl &= ~(3 << TD_CTRL_ERROR_SHIFT);
- trace_usb_uhci_packet_complete_error(queue_token, td_addr);
- ret = TD_RESULT_NEXT_QH;
- break;
- }
-
- td->ctrl &= ~TD_CTRL_ACTIVE;
- s->status |= UHCI_STS_USBERR;
- if (td->ctrl & TD_CTRL_IOC) {
- *int_mask |= 0x01;
- }
- uhci_update_irq(s);
- return ret;
-}
-
-static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_t *int_mask)
-{
- int len = 0, max_len;
- uint8_t pid;
-
- max_len = ((td->token >> 21) + 1) & 0x7ff;
- pid = td->token & 0xff;
-
- if (td->ctrl & TD_CTRL_IOS)
- td->ctrl &= ~TD_CTRL_ACTIVE;
-
- if (async->packet.status != USB_RET_SUCCESS) {
- return uhci_handle_td_error(s, td, async->td_addr,
- async->packet.status, int_mask);
- }
-
- len = async->packet.actual_length;
- td->ctrl = (td->ctrl & ~0x7ff) | ((len - 1) & 0x7ff);
-
- /* The NAK bit may have been set by a previous frame, so clear it
- here. The docs are somewhat unclear, but win2k relies on this
- behavior. */
- td->ctrl &= ~(TD_CTRL_ACTIVE | TD_CTRL_NAK);
- if (td->ctrl & TD_CTRL_IOC)
- *int_mask |= 0x01;
-
- if (pid == USB_TOKEN_IN) {
- pci_dma_write(&s->dev, td->buffer, async->buf, len);
- if ((td->ctrl & TD_CTRL_SPD) && len < max_len) {
- *int_mask |= 0x02;
- /* short packet: do not update QH */
- trace_usb_uhci_packet_complete_shortxfer(async->queue->token,
- async->td_addr);
- return TD_RESULT_NEXT_QH;
- }
- }
-
- /* success */
- trace_usb_uhci_packet_complete_success(async->queue->token,
- async->td_addr);
- return TD_RESULT_COMPLETE;
-}
-
-static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr,
- UHCI_TD *td, uint32_t td_addr, uint32_t *int_mask)
-{
- int ret, max_len;
- bool spd;
- bool queuing = (q != NULL);
- uint8_t pid = td->token & 0xff;
- UHCIAsync *async;
-
- async = uhci_async_find_td(s, td_addr);
- if (async) {
- if (uhci_queue_verify(async->queue, qh_addr, td, td_addr, queuing)) {
- assert(q == NULL || q == async->queue);
- q = async->queue;
- } else {
- uhci_queue_free(async->queue, "guest re-used pending td");
- async = NULL;
- }
- }
-
- if (q == NULL) {
- q = uhci_queue_find(s, td);
- if (q && !uhci_queue_verify(q, qh_addr, td, td_addr, queuing)) {
- uhci_queue_free(q, "guest re-used qh");
- q = NULL;
- }
- }
-
- if (q) {
- q->valid = QH_VALID;
- }
-
- /* Is active ? */
- if (!(td->ctrl & TD_CTRL_ACTIVE)) {
- if (async) {
- /* Guest marked a pending td non-active, cancel the queue */
- uhci_queue_free(async->queue, "pending td non-active");
- }
- /*
- * ehci11d spec page 22: "Even if the Active bit in the TD is already
- * cleared when the TD is fetched ... an IOC interrupt is generated"
- */
- if (td->ctrl & TD_CTRL_IOC) {
- *int_mask |= 0x01;
- }
- return TD_RESULT_NEXT_QH;
- }
-
- switch (pid) {
- case USB_TOKEN_OUT:
- case USB_TOKEN_SETUP:
- case USB_TOKEN_IN:
- break;
- default:
- /* invalid pid : frame interrupted */
- s->status |= UHCI_STS_HCPERR;
- s->cmd &= ~UHCI_CMD_RS;
- uhci_update_irq(s);
- return TD_RESULT_STOP_FRAME;
- }
-
- if (async) {
- if (queuing) {
- /* we are busy filling the queue, we are not prepared
- to consume completed packages then, just leave them
- in async state */
- return TD_RESULT_ASYNC_CONT;
- }
- if (!async->done) {
- UHCI_TD last_td;
- UHCIAsync *last = QTAILQ_LAST(&async->queue->asyncs, asyncs_head);
- /*
- * While we are waiting for the current td to complete, the guest
- * may have added more tds to the queue. Note we re-read the td
- * rather then caching it, as we want to see guest made changes!
- */
- uhci_read_td(s, &last_td, last->td_addr);
- uhci_queue_fill(async->queue, &last_td);
-
- return TD_RESULT_ASYNC_CONT;
- }
- uhci_async_unlink(async);
- goto done;
- }
-
- if (s->completions_only) {
- return TD_RESULT_ASYNC_CONT;
- }
-
- /* Allocate new packet */
- if (q == NULL) {
- USBDevice *dev = uhci_find_device(s, (td->token >> 8) & 0x7f);
- USBEndpoint *ep = usb_ep_get(dev, pid, (td->token >> 15) & 0xf);
-
- if (ep == NULL) {
- return uhci_handle_td_error(s, td, td_addr, USB_RET_NODEV,
- int_mask);
- }
- q = uhci_queue_new(s, qh_addr, td, ep);
- }
- async = uhci_async_alloc(q, td_addr);
-
- max_len = ((td->token >> 21) + 1) & 0x7ff;
- spd = (pid == USB_TOKEN_IN && (td->ctrl & TD_CTRL_SPD) != 0);
- usb_packet_setup(&async->packet, pid, q->ep, 0, td_addr, spd,
- (td->ctrl & TD_CTRL_IOC) != 0);
- if (max_len <= sizeof(async->static_buf)) {
- async->buf = async->static_buf;
- } else {
- async->buf = g_malloc(max_len);
- }
- usb_packet_addbuf(&async->packet, async->buf, max_len);
-
- switch(pid) {
- case USB_TOKEN_OUT:
- case USB_TOKEN_SETUP:
- pci_dma_read(&s->dev, td->buffer, async->buf, max_len);
- usb_handle_packet(q->ep->dev, &async->packet);
- if (async->packet.status == USB_RET_SUCCESS) {
- async->packet.actual_length = max_len;
- }
- break;
-
- case USB_TOKEN_IN:
- usb_handle_packet(q->ep->dev, &async->packet);
- break;
-
- default:
- abort(); /* Never to execute */
- }
-
- if (async->packet.status == USB_RET_ASYNC) {
- uhci_async_link(async);
- if (!queuing) {
- uhci_queue_fill(q, td);
- }
- return TD_RESULT_ASYNC_START;
- }
-
-done:
- ret = uhci_complete_td(s, td, async, int_mask);
- uhci_async_free(async);
- return ret;
-}
-
-static void uhci_async_complete(USBPort *port, USBPacket *packet)
-{
- UHCIAsync *async = container_of(packet, UHCIAsync, packet);
- UHCIState *s = async->queue->uhci;
-
- if (packet->status == USB_RET_REMOVE_FROM_QUEUE) {
- uhci_async_cancel(async);
- return;
- }
-
- async->done = 1;
- /* Force processing of this packet *now*, needed for migration */
- s->completions_only = true;
- qemu_bh_schedule(s->bh);
-}
-
-static int is_valid(uint32_t link)
-{
- return (link & 1) == 0;
-}
-
-static int is_qh(uint32_t link)
-{
- return (link & 2) != 0;
-}
-
-static int depth_first(uint32_t link)
-{
- return (link & 4) != 0;
-}
-
-/* QH DB used for detecting QH loops */
-#define UHCI_MAX_QUEUES 128
-typedef struct {
- uint32_t addr[UHCI_MAX_QUEUES];
- int count;
-} QhDb;
-
-static void qhdb_reset(QhDb *db)
-{
- db->count = 0;
-}
-
-/* Add QH to DB. Returns 1 if already present or DB is full. */
-static int qhdb_insert(QhDb *db, uint32_t addr)
-{
- int i;
- for (i = 0; i < db->count; i++)
- if (db->addr[i] == addr)
- return 1;
-
- if (db->count >= UHCI_MAX_QUEUES)
- return 1;
-
- db->addr[db->count++] = addr;
- return 0;
-}
-
-static void uhci_queue_fill(UHCIQueue *q, UHCI_TD *td)
-{
- uint32_t int_mask = 0;
- uint32_t plink = td->link;
- UHCI_TD ptd;
- int ret;
-
- while (is_valid(plink)) {
- uhci_read_td(q->uhci, &ptd, plink);
- if (!(ptd.ctrl & TD_CTRL_ACTIVE)) {
- break;
- }
- if (uhci_queue_token(&ptd) != q->token) {
- break;
- }
- trace_usb_uhci_td_queue(plink & ~0xf, ptd.ctrl, ptd.token);
- ret = uhci_handle_td(q->uhci, q, q->qh_addr, &ptd, plink, &int_mask);
- if (ret == TD_RESULT_ASYNC_CONT) {
- break;
- }
- assert(ret == TD_RESULT_ASYNC_START);
- assert(int_mask == 0);
- plink = ptd.link;
- }
- usb_device_flush_ep_queue(q->ep->dev, q->ep);
-}
-
-static void uhci_process_frame(UHCIState *s)
-{
- uint32_t frame_addr, link, old_td_ctrl, val, int_mask;
- uint32_t curr_qh, td_count = 0;
- int cnt, ret;
- UHCI_TD td;
- UHCI_QH qh;
- QhDb qhdb;
-
- frame_addr = s->fl_base_addr + ((s->frnum & 0x3ff) << 2);
-
- pci_dma_read(&s->dev, frame_addr, &link, 4);
- le32_to_cpus(&link);
-
- int_mask = 0;
- curr_qh = 0;
-
- qhdb_reset(&qhdb);
-
- for (cnt = FRAME_MAX_LOOPS; is_valid(link) && cnt; cnt--) {
- if (!s->completions_only && s->frame_bytes >= s->frame_bandwidth) {
- /* We've reached the usb 1.1 bandwidth, which is
- 1280 bytes/frame, stop processing */
- trace_usb_uhci_frame_stop_bandwidth();
- break;
- }
- if (is_qh(link)) {
- /* QH */
- trace_usb_uhci_qh_load(link & ~0xf);
-
- if (qhdb_insert(&qhdb, link)) {
- /*
- * We're going in circles. Which is not a bug because
- * HCD is allowed to do that as part of the BW management.
- *
- * Stop processing here if no transaction has been done
- * since we've been here last time.
- */
- if (td_count == 0) {
- trace_usb_uhci_frame_loop_stop_idle();
- break;
- } else {
- trace_usb_uhci_frame_loop_continue();
- td_count = 0;
- qhdb_reset(&qhdb);
- qhdb_insert(&qhdb, link);
- }
- }
-
- pci_dma_read(&s->dev, link & ~0xf, &qh, sizeof(qh));
- le32_to_cpus(&qh.link);
- le32_to_cpus(&qh.el_link);
-
- if (!is_valid(qh.el_link)) {
- /* QH w/o elements */
- curr_qh = 0;
- link = qh.link;
- } else {
- /* QH with elements */
- curr_qh = link;
- link = qh.el_link;
- }
- continue;
- }
-
- /* TD */
- uhci_read_td(s, &td, link);
- trace_usb_uhci_td_load(curr_qh & ~0xf, link & ~0xf, td.ctrl, td.token);
-
- old_td_ctrl = td.ctrl;
- ret = uhci_handle_td(s, NULL, curr_qh, &td, link, &int_mask);
- if (old_td_ctrl != td.ctrl) {
- /* update the status bits of the TD */
- val = cpu_to_le32(td.ctrl);
- pci_dma_write(&s->dev, (link & ~0xf) + 4, &val, sizeof(val));
- }
-
- switch (ret) {
- case TD_RESULT_STOP_FRAME: /* interrupted frame */
- goto out;
-
- case TD_RESULT_NEXT_QH:
- case TD_RESULT_ASYNC_CONT:
- trace_usb_uhci_td_nextqh(curr_qh & ~0xf, link & ~0xf);
- link = curr_qh ? qh.link : td.link;
- continue;
-
- case TD_RESULT_ASYNC_START:
- trace_usb_uhci_td_async(curr_qh & ~0xf, link & ~0xf);
- link = curr_qh ? qh.link : td.link;
- continue;
-
- case TD_RESULT_COMPLETE:
- trace_usb_uhci_td_complete(curr_qh & ~0xf, link & ~0xf);
- link = td.link;
- td_count++;
- s->frame_bytes += (td.ctrl & 0x7ff) + 1;
-
- if (curr_qh) {
- /* update QH element link */
- qh.el_link = link;
- val = cpu_to_le32(qh.el_link);
- pci_dma_write(&s->dev, (curr_qh & ~0xf) + 4, &val, sizeof(val));
-
- if (!depth_first(link)) {
- /* done with this QH */
- curr_qh = 0;
- link = qh.link;
- }
- }
- break;
-
- default:
- assert(!"unknown return code");
- }
-
- /* go to the next entry */
- }
-
-out:
- s->pending_int_mask |= int_mask;
-}
-
-static void uhci_bh(void *opaque)
-{
- UHCIState *s = opaque;
- uhci_process_frame(s);
-}
-
-static void uhci_frame_timer(void *opaque)
-{
- UHCIState *s = opaque;
- uint64_t t_now, t_last_run;
- int i, frames;
- const uint64_t frame_t = NANOSECONDS_PER_SECOND / FRAME_TIMER_FREQ;
-
- s->completions_only = false;
- qemu_bh_cancel(s->bh);
-
- if (!(s->cmd & UHCI_CMD_RS)) {
- /* Full stop */
- trace_usb_uhci_schedule_stop();
- timer_del(s->frame_timer);
- uhci_async_cancel_all(s);
- /* set hchalted bit in status - UHCI11D 2.1.2 */
- s->status |= UHCI_STS_HCHALTED;
- return;
- }
-
- /* We still store expire_time in our state, for migration */
- t_last_run = s->expire_time - frame_t;
- t_now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-
- /* Process up to MAX_FRAMES_PER_TICK frames */
- frames = (t_now - t_last_run) / frame_t;
- if (frames > s->maxframes) {
- int skipped = frames - s->maxframes;
- s->expire_time += skipped * frame_t;
- s->frnum = (s->frnum + skipped) & 0x7ff;
- frames -= skipped;
- }
- if (frames > MAX_FRAMES_PER_TICK) {
- frames = MAX_FRAMES_PER_TICK;
- }
-
- for (i = 0; i < frames; i++) {
- s->frame_bytes = 0;
- trace_usb_uhci_frame_start(s->frnum);
- uhci_async_validate_begin(s);
- uhci_process_frame(s);
- uhci_async_validate_end(s);
- /* The spec says frnum is the frame currently being processed, and
- * the guest must look at frnum - 1 on interrupt, so inc frnum now */
- s->frnum = (s->frnum + 1) & 0x7ff;
- s->expire_time += frame_t;
- }
-
- /* Complete the previous frame(s) */
- if (s->pending_int_mask) {
- s->status2 |= s->pending_int_mask;
- s->status |= UHCI_STS_USBINT;
- uhci_update_irq(s);
- }
- s->pending_int_mask = 0;
-
- timer_mod(s->frame_timer, t_now + frame_t);
-}
-
-static const MemoryRegionOps uhci_ioport_ops = {
- .read = uhci_port_read,
- .write = uhci_port_write,
- .valid.min_access_size = 1,
- .valid.max_access_size = 4,
- .impl.min_access_size = 2,
- .impl.max_access_size = 2,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static USBPortOps uhci_port_ops = {
- .attach = uhci_attach,
- .detach = uhci_detach,
- .child_detach = uhci_child_detach,
- .wakeup = uhci_wakeup,
- .complete = uhci_async_complete,
-};
-
-static USBBusOps uhci_bus_ops = {
-};
-
-static void usb_uhci_common_realize(PCIDevice *dev, Error **errp)
-{
- Error *err = NULL;
- PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
- UHCIPCIDeviceClass *u = container_of(pc, UHCIPCIDeviceClass, parent_class);
- UHCIState *s = UHCI(dev);
- uint8_t *pci_conf = s->dev.config;
- int i;
-
- pci_conf[PCI_CLASS_PROG] = 0x00;
- /* TODO: reset value should be 0. */
- pci_conf[USB_SBRN] = USB_RELEASE_1; // release number
-
- pci_config_set_interrupt_pin(pci_conf, u->info.irq_pin + 1);
-
- if (s->masterbus) {
- USBPort *ports[NB_PORTS];
- for(i = 0; i < NB_PORTS; i++) {
- ports[i] = &s->ports[i].port;
- }
- usb_register_companion(s->masterbus, ports, NB_PORTS,
- s->firstport, s, &uhci_port_ops,
- USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL,
- &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- } else {
- usb_bus_new(&s->bus, sizeof(s->bus), &uhci_bus_ops, DEVICE(dev));
- for (i = 0; i < NB_PORTS; i++) {
- usb_register_port(&s->bus, &s->ports[i].port, s, i, &uhci_port_ops,
- USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
- }
- }
- s->bh = qemu_bh_new(uhci_bh, s);
- s->frame_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, uhci_frame_timer, s);
- s->num_ports_vmstate = NB_PORTS;
- QTAILQ_INIT(&s->queues);
-
- memory_region_init_io(&s->io_bar, OBJECT(s), &uhci_ioport_ops, s,
- "uhci", 0x20);
-
- /* Use region 4 for consistency with real hardware. BSD guests seem
- to rely on this. */
- pci_register_bar(&s->dev, 4, PCI_BASE_ADDRESS_SPACE_IO, &s->io_bar);
-}
-
-static void usb_uhci_vt82c686b_realize(PCIDevice *dev, Error **errp)
-{
- UHCIState *s = UHCI(dev);
- uint8_t *pci_conf = s->dev.config;
-
- /* USB misc control 1/2 */
- pci_set_long(pci_conf + 0x40,0x00001000);
- /* PM capability */
- pci_set_long(pci_conf + 0x80,0x00020001);
- /* USB legacy support */
- pci_set_long(pci_conf + 0xc0,0x00002000);
-
- usb_uhci_common_realize(dev, errp);
-}
-
-static void usb_uhci_exit(PCIDevice *dev)
-{
- UHCIState *s = UHCI(dev);
-
- trace_usb_uhci_exit();
-
- if (s->frame_timer) {
- timer_del(s->frame_timer);
- timer_free(s->frame_timer);
- s->frame_timer = NULL;
- }
-
- if (s->bh) {
- qemu_bh_delete(s->bh);
- }
-
- uhci_async_cancel_all(s);
-
- if (!s->masterbus) {
- usb_bus_release(&s->bus);
- }
-}
-
-static Property uhci_properties_companion[] = {
- DEFINE_PROP_STRING("masterbus", UHCIState, masterbus),
- DEFINE_PROP_UINT32("firstport", UHCIState, firstport, 0),
- DEFINE_PROP_UINT32("bandwidth", UHCIState, frame_bandwidth, 1280),
- DEFINE_PROP_UINT32("maxframes", UHCIState, maxframes, 128),
- DEFINE_PROP_END_OF_LIST(),
-};
-static Property uhci_properties_standalone[] = {
- DEFINE_PROP_UINT32("bandwidth", UHCIState, frame_bandwidth, 1280),
- DEFINE_PROP_UINT32("maxframes", UHCIState, maxframes, 128),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void uhci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->class_id = PCI_CLASS_SERIAL_USB;
- dc->vmsd = &vmstate_uhci;
- dc->reset = uhci_reset;
- set_bit(DEVICE_CATEGORY_USB, dc->categories);
-}
-
-static const TypeInfo uhci_pci_type_info = {
- .name = TYPE_UHCI,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(UHCIState),
- .class_size = sizeof(UHCIPCIDeviceClass),
- .abstract = true,
- .class_init = uhci_class_init,
-};
-
-static void uhci_data_class_init(ObjectClass *klass, void *data)
-{
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
- UHCIPCIDeviceClass *u = container_of(k, UHCIPCIDeviceClass, parent_class);
- UHCIInfo *info = data;
-
- k->realize = info->realize ? info->realize : usb_uhci_common_realize;
- k->exit = info->unplug ? usb_uhci_exit : NULL;
- k->vendor_id = info->vendor_id;
- k->device_id = info->device_id;
- k->revision = info->revision;
- if (!info->unplug) {
- /* uhci controllers in companion setups can't be hotplugged */
- dc->hotpluggable = false;
- dc->props = uhci_properties_companion;
- } else {
- dc->props = uhci_properties_standalone;
- }
- u->info = *info;
-}
-
-static UHCIInfo uhci_info[] = {
- {
- .name = "piix3-usb-uhci",
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82371SB_2,
- .revision = 0x01,
- .irq_pin = 3,
- .unplug = true,
- },{
- .name = "piix4-usb-uhci",
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82371AB_2,
- .revision = 0x01,
- .irq_pin = 3,
- .unplug = true,
- },{
- .name = "vt82c686b-usb-uhci",
- .vendor_id = PCI_VENDOR_ID_VIA,
- .device_id = PCI_DEVICE_ID_VIA_UHCI,
- .revision = 0x01,
- .irq_pin = 3,
- .realize = usb_uhci_vt82c686b_realize,
- .unplug = true,
- },{
- .name = "ich9-usb-uhci1", /* 00:1d.0 */
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI1,
- .revision = 0x03,
- .irq_pin = 0,
- .unplug = false,
- },{
- .name = "ich9-usb-uhci2", /* 00:1d.1 */
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI2,
- .revision = 0x03,
- .irq_pin = 1,
- .unplug = false,
- },{
- .name = "ich9-usb-uhci3", /* 00:1d.2 */
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI3,
- .revision = 0x03,
- .irq_pin = 2,
- .unplug = false,
- },{
- .name = "ich9-usb-uhci4", /* 00:1a.0 */
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI4,
- .revision = 0x03,
- .irq_pin = 0,
- .unplug = false,
- },{
- .name = "ich9-usb-uhci5", /* 00:1a.1 */
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI5,
- .revision = 0x03,
- .irq_pin = 1,
- .unplug = false,
- },{
- .name = "ich9-usb-uhci6", /* 00:1a.2 */
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI6,
- .revision = 0x03,
- .irq_pin = 2,
- .unplug = false,
- }
-};
-
-static void uhci_register_types(void)
-{
- TypeInfo uhci_type_info = {
- .parent = TYPE_UHCI,
- .class_init = uhci_data_class_init,
- };
- int i;
-
- type_register_static(&uhci_pci_type_info);
-
- for (i = 0; i < ARRAY_SIZE(uhci_info); i++) {
- uhci_type_info.name = uhci_info[i].name;
- uhci_type_info.class_data = uhci_info + i;
- type_register(&uhci_type_info);
- }
-}
-
-type_init(uhci_register_types)
diff --git a/qemu/hw/usb/hcd-xhci.c b/qemu/hw/usb/hcd-xhci.c
deleted file mode 100644
index bcde8a2f4..000000000
--- a/qemu/hw/usb/hcd-xhci.c
+++ /dev/null
@@ -1,3917 +0,0 @@
-/*
- * USB xHCI controller emulation
- *
- * Copyright (c) 2011 Securiforest
- * Date: 2011-05-11 ; Author: Hector Martin <hector@marcansoft.com>
- * Based on usb-ohci.c, emulates Renesas NEC USB 3.0
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "qemu/timer.h"
-#include "hw/usb.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/msi.h"
-#include "hw/pci/msix.h"
-#include "trace.h"
-
-//#define DEBUG_XHCI
-//#define DEBUG_DATA
-
-#ifdef DEBUG_XHCI
-#define DPRINTF(...) fprintf(stderr, __VA_ARGS__)
-#else
-#define DPRINTF(...) do {} while (0)
-#endif
-#define FIXME(_msg) do { fprintf(stderr, "FIXME %s:%d %s\n", \
- __func__, __LINE__, _msg); abort(); } while (0)
-
-#define MAXPORTS_2 15
-#define MAXPORTS_3 15
-
-#define MAXPORTS (MAXPORTS_2+MAXPORTS_3)
-#define MAXSLOTS 64
-#define MAXINTRS 16
-
-#define TD_QUEUE 24
-
-/* Very pessimistic, let's hope it's enough for all cases */
-#define EV_QUEUE (((3*TD_QUEUE)+16)*MAXSLOTS)
-/* Do not deliver ER Full events. NEC's driver does some things not bound
- * to the specs when it gets them */
-#define ER_FULL_HACK
-
-#define LEN_CAP 0x40
-#define LEN_OPER (0x400 + 0x10 * MAXPORTS)
-#define LEN_RUNTIME ((MAXINTRS + 1) * 0x20)
-#define LEN_DOORBELL ((MAXSLOTS + 1) * 0x20)
-
-#define OFF_OPER LEN_CAP
-#define OFF_RUNTIME 0x1000
-#define OFF_DOORBELL 0x2000
-#define OFF_MSIX_TABLE 0x3000
-#define OFF_MSIX_PBA 0x3800
-/* must be power of 2 */
-#define LEN_REGS 0x4000
-
-#if (OFF_OPER + LEN_OPER) > OFF_RUNTIME
-#error Increase OFF_RUNTIME
-#endif
-#if (OFF_RUNTIME + LEN_RUNTIME) > OFF_DOORBELL
-#error Increase OFF_DOORBELL
-#endif
-#if (OFF_DOORBELL + LEN_DOORBELL) > LEN_REGS
-# error Increase LEN_REGS
-#endif
-
-/* bit definitions */
-#define USBCMD_RS (1<<0)
-#define USBCMD_HCRST (1<<1)
-#define USBCMD_INTE (1<<2)
-#define USBCMD_HSEE (1<<3)
-#define USBCMD_LHCRST (1<<7)
-#define USBCMD_CSS (1<<8)
-#define USBCMD_CRS (1<<9)
-#define USBCMD_EWE (1<<10)
-#define USBCMD_EU3S (1<<11)
-
-#define USBSTS_HCH (1<<0)
-#define USBSTS_HSE (1<<2)
-#define USBSTS_EINT (1<<3)
-#define USBSTS_PCD (1<<4)
-#define USBSTS_SSS (1<<8)
-#define USBSTS_RSS (1<<9)
-#define USBSTS_SRE (1<<10)
-#define USBSTS_CNR (1<<11)
-#define USBSTS_HCE (1<<12)
-
-
-#define PORTSC_CCS (1<<0)
-#define PORTSC_PED (1<<1)
-#define PORTSC_OCA (1<<3)
-#define PORTSC_PR (1<<4)
-#define PORTSC_PLS_SHIFT 5
-#define PORTSC_PLS_MASK 0xf
-#define PORTSC_PP (1<<9)
-#define PORTSC_SPEED_SHIFT 10
-#define PORTSC_SPEED_MASK 0xf
-#define PORTSC_SPEED_FULL (1<<10)
-#define PORTSC_SPEED_LOW (2<<10)
-#define PORTSC_SPEED_HIGH (3<<10)
-#define PORTSC_SPEED_SUPER (4<<10)
-#define PORTSC_PIC_SHIFT 14
-#define PORTSC_PIC_MASK 0x3
-#define PORTSC_LWS (1<<16)
-#define PORTSC_CSC (1<<17)
-#define PORTSC_PEC (1<<18)
-#define PORTSC_WRC (1<<19)
-#define PORTSC_OCC (1<<20)
-#define PORTSC_PRC (1<<21)
-#define PORTSC_PLC (1<<22)
-#define PORTSC_CEC (1<<23)
-#define PORTSC_CAS (1<<24)
-#define PORTSC_WCE (1<<25)
-#define PORTSC_WDE (1<<26)
-#define PORTSC_WOE (1<<27)
-#define PORTSC_DR (1<<30)
-#define PORTSC_WPR (1<<31)
-
-#define CRCR_RCS (1<<0)
-#define CRCR_CS (1<<1)
-#define CRCR_CA (1<<2)
-#define CRCR_CRR (1<<3)
-
-#define IMAN_IP (1<<0)
-#define IMAN_IE (1<<1)
-
-#define ERDP_EHB (1<<3)
-
-#define TRB_SIZE 16
-typedef struct XHCITRB {
- uint64_t parameter;
- uint32_t status;
- uint32_t control;
- dma_addr_t addr;
- bool ccs;
-} XHCITRB;
-
-enum {
- PLS_U0 = 0,
- PLS_U1 = 1,
- PLS_U2 = 2,
- PLS_U3 = 3,
- PLS_DISABLED = 4,
- PLS_RX_DETECT = 5,
- PLS_INACTIVE = 6,
- PLS_POLLING = 7,
- PLS_RECOVERY = 8,
- PLS_HOT_RESET = 9,
- PLS_COMPILANCE_MODE = 10,
- PLS_TEST_MODE = 11,
- PLS_RESUME = 15,
-};
-
-typedef enum TRBType {
- TRB_RESERVED = 0,
- TR_NORMAL,
- TR_SETUP,
- TR_DATA,
- TR_STATUS,
- TR_ISOCH,
- TR_LINK,
- TR_EVDATA,
- TR_NOOP,
- CR_ENABLE_SLOT,
- CR_DISABLE_SLOT,
- CR_ADDRESS_DEVICE,
- CR_CONFIGURE_ENDPOINT,
- CR_EVALUATE_CONTEXT,
- CR_RESET_ENDPOINT,
- CR_STOP_ENDPOINT,
- CR_SET_TR_DEQUEUE,
- CR_RESET_DEVICE,
- CR_FORCE_EVENT,
- CR_NEGOTIATE_BW,
- CR_SET_LATENCY_TOLERANCE,
- CR_GET_PORT_BANDWIDTH,
- CR_FORCE_HEADER,
- CR_NOOP,
- ER_TRANSFER = 32,
- ER_COMMAND_COMPLETE,
- ER_PORT_STATUS_CHANGE,
- ER_BANDWIDTH_REQUEST,
- ER_DOORBELL,
- ER_HOST_CONTROLLER,
- ER_DEVICE_NOTIFICATION,
- ER_MFINDEX_WRAP,
- /* vendor specific bits */
- CR_VENDOR_VIA_CHALLENGE_RESPONSE = 48,
- CR_VENDOR_NEC_FIRMWARE_REVISION = 49,
- CR_VENDOR_NEC_CHALLENGE_RESPONSE = 50,
-} TRBType;
-
-#define CR_LINK TR_LINK
-
-typedef enum TRBCCode {
- CC_INVALID = 0,
- CC_SUCCESS,
- CC_DATA_BUFFER_ERROR,
- CC_BABBLE_DETECTED,
- CC_USB_TRANSACTION_ERROR,
- CC_TRB_ERROR,
- CC_STALL_ERROR,
- CC_RESOURCE_ERROR,
- CC_BANDWIDTH_ERROR,
- CC_NO_SLOTS_ERROR,
- CC_INVALID_STREAM_TYPE_ERROR,
- CC_SLOT_NOT_ENABLED_ERROR,
- CC_EP_NOT_ENABLED_ERROR,
- CC_SHORT_PACKET,
- CC_RING_UNDERRUN,
- CC_RING_OVERRUN,
- CC_VF_ER_FULL,
- CC_PARAMETER_ERROR,
- CC_BANDWIDTH_OVERRUN,
- CC_CONTEXT_STATE_ERROR,
- CC_NO_PING_RESPONSE_ERROR,
- CC_EVENT_RING_FULL_ERROR,
- CC_INCOMPATIBLE_DEVICE_ERROR,
- CC_MISSED_SERVICE_ERROR,
- CC_COMMAND_RING_STOPPED,
- CC_COMMAND_ABORTED,
- CC_STOPPED,
- CC_STOPPED_LENGTH_INVALID,
- CC_MAX_EXIT_LATENCY_TOO_LARGE_ERROR = 29,
- CC_ISOCH_BUFFER_OVERRUN = 31,
- CC_EVENT_LOST_ERROR,
- CC_UNDEFINED_ERROR,
- CC_INVALID_STREAM_ID_ERROR,
- CC_SECONDARY_BANDWIDTH_ERROR,
- CC_SPLIT_TRANSACTION_ERROR
-} TRBCCode;
-
-#define TRB_C (1<<0)
-#define TRB_TYPE_SHIFT 10
-#define TRB_TYPE_MASK 0x3f
-#define TRB_TYPE(t) (((t).control >> TRB_TYPE_SHIFT) & TRB_TYPE_MASK)
-
-#define TRB_EV_ED (1<<2)
-
-#define TRB_TR_ENT (1<<1)
-#define TRB_TR_ISP (1<<2)
-#define TRB_TR_NS (1<<3)
-#define TRB_TR_CH (1<<4)
-#define TRB_TR_IOC (1<<5)
-#define TRB_TR_IDT (1<<6)
-#define TRB_TR_TBC_SHIFT 7
-#define TRB_TR_TBC_MASK 0x3
-#define TRB_TR_BEI (1<<9)
-#define TRB_TR_TLBPC_SHIFT 16
-#define TRB_TR_TLBPC_MASK 0xf
-#define TRB_TR_FRAMEID_SHIFT 20
-#define TRB_TR_FRAMEID_MASK 0x7ff
-#define TRB_TR_SIA (1<<31)
-
-#define TRB_TR_DIR (1<<16)
-
-#define TRB_CR_SLOTID_SHIFT 24
-#define TRB_CR_SLOTID_MASK 0xff
-#define TRB_CR_EPID_SHIFT 16
-#define TRB_CR_EPID_MASK 0x1f
-
-#define TRB_CR_BSR (1<<9)
-#define TRB_CR_DC (1<<9)
-
-#define TRB_LK_TC (1<<1)
-
-#define TRB_INTR_SHIFT 22
-#define TRB_INTR_MASK 0x3ff
-#define TRB_INTR(t) (((t).status >> TRB_INTR_SHIFT) & TRB_INTR_MASK)
-
-#define EP_TYPE_MASK 0x7
-#define EP_TYPE_SHIFT 3
-
-#define EP_STATE_MASK 0x7
-#define EP_DISABLED (0<<0)
-#define EP_RUNNING (1<<0)
-#define EP_HALTED (2<<0)
-#define EP_STOPPED (3<<0)
-#define EP_ERROR (4<<0)
-
-#define SLOT_STATE_MASK 0x1f
-#define SLOT_STATE_SHIFT 27
-#define SLOT_STATE(s) (((s)>>SLOT_STATE_SHIFT)&SLOT_STATE_MASK)
-#define SLOT_ENABLED 0
-#define SLOT_DEFAULT 1
-#define SLOT_ADDRESSED 2
-#define SLOT_CONFIGURED 3
-
-#define SLOT_CONTEXT_ENTRIES_MASK 0x1f
-#define SLOT_CONTEXT_ENTRIES_SHIFT 27
-
-typedef struct XHCIState XHCIState;
-typedef struct XHCIStreamContext XHCIStreamContext;
-typedef struct XHCIEPContext XHCIEPContext;
-
-#define get_field(data, field) \
- (((data) >> field##_SHIFT) & field##_MASK)
-
-#define set_field(data, newval, field) do { \
- uint32_t val = *data; \
- val &= ~(field##_MASK << field##_SHIFT); \
- val |= ((newval) & field##_MASK) << field##_SHIFT; \
- *data = val; \
- } while (0)
-
-typedef enum EPType {
- ET_INVALID = 0,
- ET_ISO_OUT,
- ET_BULK_OUT,
- ET_INTR_OUT,
- ET_CONTROL,
- ET_ISO_IN,
- ET_BULK_IN,
- ET_INTR_IN,
-} EPType;
-
-typedef struct XHCIRing {
- dma_addr_t dequeue;
- bool ccs;
-} XHCIRing;
-
-typedef struct XHCIPort {
- XHCIState *xhci;
- uint32_t portsc;
- uint32_t portnr;
- USBPort *uport;
- uint32_t speedmask;
- char name[16];
- MemoryRegion mem;
-} XHCIPort;
-
-typedef struct XHCITransfer {
- XHCIState *xhci;
- USBPacket packet;
- QEMUSGList sgl;
- bool running_async;
- bool running_retry;
- bool complete;
- bool int_req;
- unsigned int iso_pkts;
- unsigned int slotid;
- unsigned int epid;
- unsigned int streamid;
- bool in_xfer;
- bool iso_xfer;
- bool timed_xfer;
-
- unsigned int trb_count;
- unsigned int trb_alloced;
- XHCITRB *trbs;
-
- TRBCCode status;
-
- unsigned int pkts;
- unsigned int pktsize;
- unsigned int cur_pkt;
-
- uint64_t mfindex_kick;
-} XHCITransfer;
-
-struct XHCIStreamContext {
- dma_addr_t pctx;
- unsigned int sct;
- XHCIRing ring;
-};
-
-struct XHCIEPContext {
- XHCIState *xhci;
- unsigned int slotid;
- unsigned int epid;
-
- XHCIRing ring;
- unsigned int next_xfer;
- unsigned int comp_xfer;
- XHCITransfer transfers[TD_QUEUE];
- XHCITransfer *retry;
- EPType type;
- dma_addr_t pctx;
- unsigned int max_psize;
- uint32_t state;
-
- /* streams */
- unsigned int max_pstreams;
- bool lsa;
- unsigned int nr_pstreams;
- XHCIStreamContext *pstreams;
-
- /* iso xfer scheduling */
- unsigned int interval;
- int64_t mfindex_last;
- QEMUTimer *kick_timer;
-};
-
-typedef struct XHCISlot {
- bool enabled;
- bool addressed;
- dma_addr_t ctx;
- USBPort *uport;
- XHCIEPContext * eps[31];
-} XHCISlot;
-
-typedef struct XHCIEvent {
- TRBType type;
- TRBCCode ccode;
- uint64_t ptr;
- uint32_t length;
- uint32_t flags;
- uint8_t slotid;
- uint8_t epid;
-} XHCIEvent;
-
-typedef struct XHCIInterrupter {
- uint32_t iman;
- uint32_t imod;
- uint32_t erstsz;
- uint32_t erstba_low;
- uint32_t erstba_high;
- uint32_t erdp_low;
- uint32_t erdp_high;
-
- bool msix_used, er_pcs, er_full;
-
- dma_addr_t er_start;
- uint32_t er_size;
- unsigned int er_ep_idx;
-
- XHCIEvent ev_buffer[EV_QUEUE];
- unsigned int ev_buffer_put;
- unsigned int ev_buffer_get;
-
-} XHCIInterrupter;
-
-struct XHCIState {
- /*< private >*/
- PCIDevice parent_obj;
- /*< public >*/
-
- USBBus bus;
- MemoryRegion mem;
- MemoryRegion mem_cap;
- MemoryRegion mem_oper;
- MemoryRegion mem_runtime;
- MemoryRegion mem_doorbell;
-
- /* properties */
- uint32_t numports_2;
- uint32_t numports_3;
- uint32_t numintrs;
- uint32_t numslots;
- uint32_t flags;
- uint32_t max_pstreams_mask;
-
- /* Operational Registers */
- uint32_t usbcmd;
- uint32_t usbsts;
- uint32_t dnctrl;
- uint32_t crcr_low;
- uint32_t crcr_high;
- uint32_t dcbaap_low;
- uint32_t dcbaap_high;
- uint32_t config;
-
- USBPort uports[MAX(MAXPORTS_2, MAXPORTS_3)];
- XHCIPort ports[MAXPORTS];
- XHCISlot slots[MAXSLOTS];
- uint32_t numports;
-
- /* Runtime Registers */
- int64_t mfindex_start;
- QEMUTimer *mfwrap_timer;
- XHCIInterrupter intr[MAXINTRS];
-
- XHCIRing cmd_ring;
-};
-
-#define TYPE_XHCI "nec-usb-xhci"
-
-#define XHCI(obj) \
- OBJECT_CHECK(XHCIState, (obj), TYPE_XHCI)
-
-typedef struct XHCIEvRingSeg {
- uint32_t addr_low;
- uint32_t addr_high;
- uint32_t size;
- uint32_t rsvd;
-} XHCIEvRingSeg;
-
-enum xhci_flags {
- XHCI_FLAG_USE_MSI = 1,
- XHCI_FLAG_USE_MSI_X,
- XHCI_FLAG_SS_FIRST,
- XHCI_FLAG_FORCE_PCIE_ENDCAP,
- XHCI_FLAG_ENABLE_STREAMS,
-};
-
-static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
- unsigned int epid, unsigned int streamid);
-static TRBCCode xhci_disable_ep(XHCIState *xhci, unsigned int slotid,
- unsigned int epid);
-static void xhci_xfer_report(XHCITransfer *xfer);
-static void xhci_event(XHCIState *xhci, XHCIEvent *event, int v);
-static void xhci_write_event(XHCIState *xhci, XHCIEvent *event, int v);
-static USBEndpoint *xhci_epid_to_usbep(XHCIState *xhci,
- unsigned int slotid, unsigned int epid);
-
-static const char *TRBType_names[] = {
- [TRB_RESERVED] = "TRB_RESERVED",
- [TR_NORMAL] = "TR_NORMAL",
- [TR_SETUP] = "TR_SETUP",
- [TR_DATA] = "TR_DATA",
- [TR_STATUS] = "TR_STATUS",
- [TR_ISOCH] = "TR_ISOCH",
- [TR_LINK] = "TR_LINK",
- [TR_EVDATA] = "TR_EVDATA",
- [TR_NOOP] = "TR_NOOP",
- [CR_ENABLE_SLOT] = "CR_ENABLE_SLOT",
- [CR_DISABLE_SLOT] = "CR_DISABLE_SLOT",
- [CR_ADDRESS_DEVICE] = "CR_ADDRESS_DEVICE",
- [CR_CONFIGURE_ENDPOINT] = "CR_CONFIGURE_ENDPOINT",
- [CR_EVALUATE_CONTEXT] = "CR_EVALUATE_CONTEXT",
- [CR_RESET_ENDPOINT] = "CR_RESET_ENDPOINT",
- [CR_STOP_ENDPOINT] = "CR_STOP_ENDPOINT",
- [CR_SET_TR_DEQUEUE] = "CR_SET_TR_DEQUEUE",
- [CR_RESET_DEVICE] = "CR_RESET_DEVICE",
- [CR_FORCE_EVENT] = "CR_FORCE_EVENT",
- [CR_NEGOTIATE_BW] = "CR_NEGOTIATE_BW",
- [CR_SET_LATENCY_TOLERANCE] = "CR_SET_LATENCY_TOLERANCE",
- [CR_GET_PORT_BANDWIDTH] = "CR_GET_PORT_BANDWIDTH",
- [CR_FORCE_HEADER] = "CR_FORCE_HEADER",
- [CR_NOOP] = "CR_NOOP",
- [ER_TRANSFER] = "ER_TRANSFER",
- [ER_COMMAND_COMPLETE] = "ER_COMMAND_COMPLETE",
- [ER_PORT_STATUS_CHANGE] = "ER_PORT_STATUS_CHANGE",
- [ER_BANDWIDTH_REQUEST] = "ER_BANDWIDTH_REQUEST",
- [ER_DOORBELL] = "ER_DOORBELL",
- [ER_HOST_CONTROLLER] = "ER_HOST_CONTROLLER",
- [ER_DEVICE_NOTIFICATION] = "ER_DEVICE_NOTIFICATION",
- [ER_MFINDEX_WRAP] = "ER_MFINDEX_WRAP",
- [CR_VENDOR_VIA_CHALLENGE_RESPONSE] = "CR_VENDOR_VIA_CHALLENGE_RESPONSE",
- [CR_VENDOR_NEC_FIRMWARE_REVISION] = "CR_VENDOR_NEC_FIRMWARE_REVISION",
- [CR_VENDOR_NEC_CHALLENGE_RESPONSE] = "CR_VENDOR_NEC_CHALLENGE_RESPONSE",
-};
-
-static const char *TRBCCode_names[] = {
- [CC_INVALID] = "CC_INVALID",
- [CC_SUCCESS] = "CC_SUCCESS",
- [CC_DATA_BUFFER_ERROR] = "CC_DATA_BUFFER_ERROR",
- [CC_BABBLE_DETECTED] = "CC_BABBLE_DETECTED",
- [CC_USB_TRANSACTION_ERROR] = "CC_USB_TRANSACTION_ERROR",
- [CC_TRB_ERROR] = "CC_TRB_ERROR",
- [CC_STALL_ERROR] = "CC_STALL_ERROR",
- [CC_RESOURCE_ERROR] = "CC_RESOURCE_ERROR",
- [CC_BANDWIDTH_ERROR] = "CC_BANDWIDTH_ERROR",
- [CC_NO_SLOTS_ERROR] = "CC_NO_SLOTS_ERROR",
- [CC_INVALID_STREAM_TYPE_ERROR] = "CC_INVALID_STREAM_TYPE_ERROR",
- [CC_SLOT_NOT_ENABLED_ERROR] = "CC_SLOT_NOT_ENABLED_ERROR",
- [CC_EP_NOT_ENABLED_ERROR] = "CC_EP_NOT_ENABLED_ERROR",
- [CC_SHORT_PACKET] = "CC_SHORT_PACKET",
- [CC_RING_UNDERRUN] = "CC_RING_UNDERRUN",
- [CC_RING_OVERRUN] = "CC_RING_OVERRUN",
- [CC_VF_ER_FULL] = "CC_VF_ER_FULL",
- [CC_PARAMETER_ERROR] = "CC_PARAMETER_ERROR",
- [CC_BANDWIDTH_OVERRUN] = "CC_BANDWIDTH_OVERRUN",
- [CC_CONTEXT_STATE_ERROR] = "CC_CONTEXT_STATE_ERROR",
- [CC_NO_PING_RESPONSE_ERROR] = "CC_NO_PING_RESPONSE_ERROR",
- [CC_EVENT_RING_FULL_ERROR] = "CC_EVENT_RING_FULL_ERROR",
- [CC_INCOMPATIBLE_DEVICE_ERROR] = "CC_INCOMPATIBLE_DEVICE_ERROR",
- [CC_MISSED_SERVICE_ERROR] = "CC_MISSED_SERVICE_ERROR",
- [CC_COMMAND_RING_STOPPED] = "CC_COMMAND_RING_STOPPED",
- [CC_COMMAND_ABORTED] = "CC_COMMAND_ABORTED",
- [CC_STOPPED] = "CC_STOPPED",
- [CC_STOPPED_LENGTH_INVALID] = "CC_STOPPED_LENGTH_INVALID",
- [CC_MAX_EXIT_LATENCY_TOO_LARGE_ERROR]
- = "CC_MAX_EXIT_LATENCY_TOO_LARGE_ERROR",
- [CC_ISOCH_BUFFER_OVERRUN] = "CC_ISOCH_BUFFER_OVERRUN",
- [CC_EVENT_LOST_ERROR] = "CC_EVENT_LOST_ERROR",
- [CC_UNDEFINED_ERROR] = "CC_UNDEFINED_ERROR",
- [CC_INVALID_STREAM_ID_ERROR] = "CC_INVALID_STREAM_ID_ERROR",
- [CC_SECONDARY_BANDWIDTH_ERROR] = "CC_SECONDARY_BANDWIDTH_ERROR",
- [CC_SPLIT_TRANSACTION_ERROR] = "CC_SPLIT_TRANSACTION_ERROR",
-};
-
-static const char *ep_state_names[] = {
- [EP_DISABLED] = "disabled",
- [EP_RUNNING] = "running",
- [EP_HALTED] = "halted",
- [EP_STOPPED] = "stopped",
- [EP_ERROR] = "error",
-};
-
-static const char *lookup_name(uint32_t index, const char **list, uint32_t llen)
-{
- if (index >= llen || list[index] == NULL) {
- return "???";
- }
- return list[index];
-}
-
-static const char *trb_name(XHCITRB *trb)
-{
- return lookup_name(TRB_TYPE(*trb), TRBType_names,
- ARRAY_SIZE(TRBType_names));
-}
-
-static const char *event_name(XHCIEvent *event)
-{
- return lookup_name(event->ccode, TRBCCode_names,
- ARRAY_SIZE(TRBCCode_names));
-}
-
-static const char *ep_state_name(uint32_t state)
-{
- return lookup_name(state, ep_state_names,
- ARRAY_SIZE(ep_state_names));
-}
-
-static bool xhci_get_flag(XHCIState *xhci, enum xhci_flags bit)
-{
- return xhci->flags & (1 << bit);
-}
-
-static uint64_t xhci_mfindex_get(XHCIState *xhci)
-{
- int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- return (now - xhci->mfindex_start) / 125000;
-}
-
-static void xhci_mfwrap_update(XHCIState *xhci)
-{
- const uint32_t bits = USBCMD_RS | USBCMD_EWE;
- uint32_t mfindex, left;
- int64_t now;
-
- if ((xhci->usbcmd & bits) == bits) {
- now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- mfindex = ((now - xhci->mfindex_start) / 125000) & 0x3fff;
- left = 0x4000 - mfindex;
- timer_mod(xhci->mfwrap_timer, now + left * 125000);
- } else {
- timer_del(xhci->mfwrap_timer);
- }
-}
-
-static void xhci_mfwrap_timer(void *opaque)
-{
- XHCIState *xhci = opaque;
- XHCIEvent wrap = { ER_MFINDEX_WRAP, CC_SUCCESS };
-
- xhci_event(xhci, &wrap, 0);
- xhci_mfwrap_update(xhci);
-}
-
-static inline dma_addr_t xhci_addr64(uint32_t low, uint32_t high)
-{
- if (sizeof(dma_addr_t) == 4) {
- return low;
- } else {
- return low | (((dma_addr_t)high << 16) << 16);
- }
-}
-
-static inline dma_addr_t xhci_mask64(uint64_t addr)
-{
- if (sizeof(dma_addr_t) == 4) {
- return addr & 0xffffffff;
- } else {
- return addr;
- }
-}
-
-static inline void xhci_dma_read_u32s(XHCIState *xhci, dma_addr_t addr,
- uint32_t *buf, size_t len)
-{
- int i;
-
- assert((len % sizeof(uint32_t)) == 0);
-
- pci_dma_read(PCI_DEVICE(xhci), addr, buf, len);
-
- for (i = 0; i < (len / sizeof(uint32_t)); i++) {
- buf[i] = le32_to_cpu(buf[i]);
- }
-}
-
-static inline void xhci_dma_write_u32s(XHCIState *xhci, dma_addr_t addr,
- uint32_t *buf, size_t len)
-{
- int i;
- uint32_t tmp[5];
- uint32_t n = len / sizeof(uint32_t);
-
- assert((len % sizeof(uint32_t)) == 0);
- assert(n <= ARRAY_SIZE(tmp));
-
- for (i = 0; i < n; i++) {
- tmp[i] = cpu_to_le32(buf[i]);
- }
- pci_dma_write(PCI_DEVICE(xhci), addr, tmp, len);
-}
-
-static XHCIPort *xhci_lookup_port(XHCIState *xhci, struct USBPort *uport)
-{
- int index;
-
- if (!uport->dev) {
- return NULL;
- }
- switch (uport->dev->speed) {
- case USB_SPEED_LOW:
- case USB_SPEED_FULL:
- case USB_SPEED_HIGH:
- if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) {
- index = uport->index + xhci->numports_3;
- } else {
- index = uport->index;
- }
- break;
- case USB_SPEED_SUPER:
- if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) {
- index = uport->index;
- } else {
- index = uport->index + xhci->numports_2;
- }
- break;
- default:
- return NULL;
- }
- return &xhci->ports[index];
-}
-
-static void xhci_intx_update(XHCIState *xhci)
-{
- PCIDevice *pci_dev = PCI_DEVICE(xhci);
- int level = 0;
-
- if (msix_enabled(pci_dev) ||
- msi_enabled(pci_dev)) {
- return;
- }
-
- if (xhci->intr[0].iman & IMAN_IP &&
- xhci->intr[0].iman & IMAN_IE &&
- xhci->usbcmd & USBCMD_INTE) {
- level = 1;
- }
-
- trace_usb_xhci_irq_intx(level);
- pci_set_irq(pci_dev, level);
-}
-
-static void xhci_msix_update(XHCIState *xhci, int v)
-{
- PCIDevice *pci_dev = PCI_DEVICE(xhci);
- bool enabled;
-
- if (!msix_enabled(pci_dev)) {
- return;
- }
-
- enabled = xhci->intr[v].iman & IMAN_IE;
- if (enabled == xhci->intr[v].msix_used) {
- return;
- }
-
- if (enabled) {
- trace_usb_xhci_irq_msix_use(v);
- msix_vector_use(pci_dev, v);
- xhci->intr[v].msix_used = true;
- } else {
- trace_usb_xhci_irq_msix_unuse(v);
- msix_vector_unuse(pci_dev, v);
- xhci->intr[v].msix_used = false;
- }
-}
-
-static void xhci_intr_raise(XHCIState *xhci, int v)
-{
- PCIDevice *pci_dev = PCI_DEVICE(xhci);
-
- xhci->intr[v].erdp_low |= ERDP_EHB;
- xhci->intr[v].iman |= IMAN_IP;
- xhci->usbsts |= USBSTS_EINT;
-
- if (!(xhci->intr[v].iman & IMAN_IE)) {
- return;
- }
-
- if (!(xhci->usbcmd & USBCMD_INTE)) {
- return;
- }
-
- if (msix_enabled(pci_dev)) {
- trace_usb_xhci_irq_msix(v);
- msix_notify(pci_dev, v);
- return;
- }
-
- if (msi_enabled(pci_dev)) {
- trace_usb_xhci_irq_msi(v);
- msi_notify(pci_dev, v);
- return;
- }
-
- if (v == 0) {
- trace_usb_xhci_irq_intx(1);
- pci_irq_assert(pci_dev);
- }
-}
-
-static inline int xhci_running(XHCIState *xhci)
-{
- return !(xhci->usbsts & USBSTS_HCH) && !xhci->intr[0].er_full;
-}
-
-static void xhci_die(XHCIState *xhci)
-{
- xhci->usbsts |= USBSTS_HCE;
- DPRINTF("xhci: asserted controller error\n");
-}
-
-static void xhci_write_event(XHCIState *xhci, XHCIEvent *event, int v)
-{
- PCIDevice *pci_dev = PCI_DEVICE(xhci);
- XHCIInterrupter *intr = &xhci->intr[v];
- XHCITRB ev_trb;
- dma_addr_t addr;
-
- ev_trb.parameter = cpu_to_le64(event->ptr);
- ev_trb.status = cpu_to_le32(event->length | (event->ccode << 24));
- ev_trb.control = (event->slotid << 24) | (event->epid << 16) |
- event->flags | (event->type << TRB_TYPE_SHIFT);
- if (intr->er_pcs) {
- ev_trb.control |= TRB_C;
- }
- ev_trb.control = cpu_to_le32(ev_trb.control);
-
- trace_usb_xhci_queue_event(v, intr->er_ep_idx, trb_name(&ev_trb),
- event_name(event), ev_trb.parameter,
- ev_trb.status, ev_trb.control);
-
- addr = intr->er_start + TRB_SIZE*intr->er_ep_idx;
- pci_dma_write(pci_dev, addr, &ev_trb, TRB_SIZE);
-
- intr->er_ep_idx++;
- if (intr->er_ep_idx >= intr->er_size) {
- intr->er_ep_idx = 0;
- intr->er_pcs = !intr->er_pcs;
- }
-}
-
-static void xhci_events_update(XHCIState *xhci, int v)
-{
- XHCIInterrupter *intr = &xhci->intr[v];
- dma_addr_t erdp;
- unsigned int dp_idx;
- bool do_irq = 0;
-
- if (xhci->usbsts & USBSTS_HCH) {
- return;
- }
-
- erdp = xhci_addr64(intr->erdp_low, intr->erdp_high);
- if (erdp < intr->er_start ||
- erdp >= (intr->er_start + TRB_SIZE*intr->er_size)) {
- DPRINTF("xhci: ERDP out of bounds: "DMA_ADDR_FMT"\n", erdp);
- DPRINTF("xhci: ER[%d] at "DMA_ADDR_FMT" len %d\n",
- v, intr->er_start, intr->er_size);
- xhci_die(xhci);
- return;
- }
- dp_idx = (erdp - intr->er_start) / TRB_SIZE;
- assert(dp_idx < intr->er_size);
-
- /* NEC didn't read section 4.9.4 of the spec (v1.0 p139 top Note) and thus
- * deadlocks when the ER is full. Hack it by holding off events until
- * the driver decides to free at least half of the ring */
- if (intr->er_full) {
- int er_free = dp_idx - intr->er_ep_idx;
- if (er_free <= 0) {
- er_free += intr->er_size;
- }
- if (er_free < (intr->er_size/2)) {
- DPRINTF("xhci_events_update(): event ring still "
- "more than half full (hack)\n");
- return;
- }
- }
-
- while (intr->ev_buffer_put != intr->ev_buffer_get) {
- assert(intr->er_full);
- if (((intr->er_ep_idx+1) % intr->er_size) == dp_idx) {
- DPRINTF("xhci_events_update(): event ring full again\n");
-#ifndef ER_FULL_HACK
- XHCIEvent full = {ER_HOST_CONTROLLER, CC_EVENT_RING_FULL_ERROR};
- xhci_write_event(xhci, &full, v);
-#endif
- do_irq = 1;
- break;
- }
- XHCIEvent *event = &intr->ev_buffer[intr->ev_buffer_get];
- xhci_write_event(xhci, event, v);
- intr->ev_buffer_get++;
- do_irq = 1;
- if (intr->ev_buffer_get == EV_QUEUE) {
- intr->ev_buffer_get = 0;
- }
- }
-
- if (do_irq) {
- xhci_intr_raise(xhci, v);
- }
-
- if (intr->er_full && intr->ev_buffer_put == intr->ev_buffer_get) {
- DPRINTF("xhci_events_update(): event ring no longer full\n");
- intr->er_full = 0;
- }
-}
-
-static void xhci_event(XHCIState *xhci, XHCIEvent *event, int v)
-{
- XHCIInterrupter *intr;
- dma_addr_t erdp;
- unsigned int dp_idx;
-
- if (v >= xhci->numintrs) {
- DPRINTF("intr nr out of range (%d >= %d)\n", v, xhci->numintrs);
- return;
- }
- intr = &xhci->intr[v];
-
- if (intr->er_full) {
- DPRINTF("xhci_event(): ER full, queueing\n");
- if (((intr->ev_buffer_put+1) % EV_QUEUE) == intr->ev_buffer_get) {
- DPRINTF("xhci: event queue full, dropping event!\n");
- return;
- }
- intr->ev_buffer[intr->ev_buffer_put++] = *event;
- if (intr->ev_buffer_put == EV_QUEUE) {
- intr->ev_buffer_put = 0;
- }
- return;
- }
-
- erdp = xhci_addr64(intr->erdp_low, intr->erdp_high);
- if (erdp < intr->er_start ||
- erdp >= (intr->er_start + TRB_SIZE*intr->er_size)) {
- DPRINTF("xhci: ERDP out of bounds: "DMA_ADDR_FMT"\n", erdp);
- DPRINTF("xhci: ER[%d] at "DMA_ADDR_FMT" len %d\n",
- v, intr->er_start, intr->er_size);
- xhci_die(xhci);
- return;
- }
-
- dp_idx = (erdp - intr->er_start) / TRB_SIZE;
- assert(dp_idx < intr->er_size);
-
- if ((intr->er_ep_idx+1) % intr->er_size == dp_idx) {
- DPRINTF("xhci_event(): ER full, queueing\n");
-#ifndef ER_FULL_HACK
- XHCIEvent full = {ER_HOST_CONTROLLER, CC_EVENT_RING_FULL_ERROR};
- xhci_write_event(xhci, &full);
-#endif
- intr->er_full = 1;
- if (((intr->ev_buffer_put+1) % EV_QUEUE) == intr->ev_buffer_get) {
- DPRINTF("xhci: event queue full, dropping event!\n");
- return;
- }
- intr->ev_buffer[intr->ev_buffer_put++] = *event;
- if (intr->ev_buffer_put == EV_QUEUE) {
- intr->ev_buffer_put = 0;
- }
- } else {
- xhci_write_event(xhci, event, v);
- }
-
- xhci_intr_raise(xhci, v);
-}
-
-static void xhci_ring_init(XHCIState *xhci, XHCIRing *ring,
- dma_addr_t base)
-{
- ring->dequeue = base;
- ring->ccs = 1;
-}
-
-static TRBType xhci_ring_fetch(XHCIState *xhci, XHCIRing *ring, XHCITRB *trb,
- dma_addr_t *addr)
-{
- PCIDevice *pci_dev = PCI_DEVICE(xhci);
-
- while (1) {
- TRBType type;
- pci_dma_read(pci_dev, ring->dequeue, trb, TRB_SIZE);
- trb->addr = ring->dequeue;
- trb->ccs = ring->ccs;
- le64_to_cpus(&trb->parameter);
- le32_to_cpus(&trb->status);
- le32_to_cpus(&trb->control);
-
- trace_usb_xhci_fetch_trb(ring->dequeue, trb_name(trb),
- trb->parameter, trb->status, trb->control);
-
- if ((trb->control & TRB_C) != ring->ccs) {
- return 0;
- }
-
- type = TRB_TYPE(*trb);
-
- if (type != TR_LINK) {
- if (addr) {
- *addr = ring->dequeue;
- }
- ring->dequeue += TRB_SIZE;
- return type;
- } else {
- ring->dequeue = xhci_mask64(trb->parameter);
- if (trb->control & TRB_LK_TC) {
- ring->ccs = !ring->ccs;
- }
- }
- }
-}
-
-static int xhci_ring_chain_length(XHCIState *xhci, const XHCIRing *ring)
-{
- PCIDevice *pci_dev = PCI_DEVICE(xhci);
- XHCITRB trb;
- int length = 0;
- dma_addr_t dequeue = ring->dequeue;
- bool ccs = ring->ccs;
- /* hack to bundle together the two/three TDs that make a setup transfer */
- bool control_td_set = 0;
-
- while (1) {
- TRBType type;
- pci_dma_read(pci_dev, dequeue, &trb, TRB_SIZE);
- le64_to_cpus(&trb.parameter);
- le32_to_cpus(&trb.status);
- le32_to_cpus(&trb.control);
-
- if ((trb.control & TRB_C) != ccs) {
- return -length;
- }
-
- type = TRB_TYPE(trb);
-
- if (type == TR_LINK) {
- dequeue = xhci_mask64(trb.parameter);
- if (trb.control & TRB_LK_TC) {
- ccs = !ccs;
- }
- continue;
- }
-
- length += 1;
- dequeue += TRB_SIZE;
-
- if (type == TR_SETUP) {
- control_td_set = 1;
- } else if (type == TR_STATUS) {
- control_td_set = 0;
- }
-
- if (!control_td_set && !(trb.control & TRB_TR_CH)) {
- return length;
- }
- }
-}
-
-static void xhci_er_reset(XHCIState *xhci, int v)
-{
- XHCIInterrupter *intr = &xhci->intr[v];
- XHCIEvRingSeg seg;
-
- if (intr->erstsz == 0) {
- /* disabled */
- intr->er_start = 0;
- intr->er_size = 0;
- return;
- }
- /* cache the (sole) event ring segment location */
- if (intr->erstsz != 1) {
- DPRINTF("xhci: invalid value for ERSTSZ: %d\n", intr->erstsz);
- xhci_die(xhci);
- return;
- }
- dma_addr_t erstba = xhci_addr64(intr->erstba_low, intr->erstba_high);
- pci_dma_read(PCI_DEVICE(xhci), erstba, &seg, sizeof(seg));
- le32_to_cpus(&seg.addr_low);
- le32_to_cpus(&seg.addr_high);
- le32_to_cpus(&seg.size);
- if (seg.size < 16 || seg.size > 4096) {
- DPRINTF("xhci: invalid value for segment size: %d\n", seg.size);
- xhci_die(xhci);
- return;
- }
- intr->er_start = xhci_addr64(seg.addr_low, seg.addr_high);
- intr->er_size = seg.size;
-
- intr->er_ep_idx = 0;
- intr->er_pcs = 1;
- intr->er_full = 0;
-
- DPRINTF("xhci: event ring[%d]:" DMA_ADDR_FMT " [%d]\n",
- v, intr->er_start, intr->er_size);
-}
-
-static void xhci_run(XHCIState *xhci)
-{
- trace_usb_xhci_run();
- xhci->usbsts &= ~USBSTS_HCH;
- xhci->mfindex_start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-}
-
-static void xhci_stop(XHCIState *xhci)
-{
- trace_usb_xhci_stop();
- xhci->usbsts |= USBSTS_HCH;
- xhci->crcr_low &= ~CRCR_CRR;
-}
-
-static XHCIStreamContext *xhci_alloc_stream_contexts(unsigned count,
- dma_addr_t base)
-{
- XHCIStreamContext *stctx;
- unsigned int i;
-
- stctx = g_new0(XHCIStreamContext, count);
- for (i = 0; i < count; i++) {
- stctx[i].pctx = base + i * 16;
- stctx[i].sct = -1;
- }
- return stctx;
-}
-
-static void xhci_reset_streams(XHCIEPContext *epctx)
-{
- unsigned int i;
-
- for (i = 0; i < epctx->nr_pstreams; i++) {
- epctx->pstreams[i].sct = -1;
- }
-}
-
-static void xhci_alloc_streams(XHCIEPContext *epctx, dma_addr_t base)
-{
- assert(epctx->pstreams == NULL);
- epctx->nr_pstreams = 2 << epctx->max_pstreams;
- epctx->pstreams = xhci_alloc_stream_contexts(epctx->nr_pstreams, base);
-}
-
-static void xhci_free_streams(XHCIEPContext *epctx)
-{
- assert(epctx->pstreams != NULL);
-
- g_free(epctx->pstreams);
- epctx->pstreams = NULL;
- epctx->nr_pstreams = 0;
-}
-
-static int xhci_epmask_to_eps_with_streams(XHCIState *xhci,
- unsigned int slotid,
- uint32_t epmask,
- XHCIEPContext **epctxs,
- USBEndpoint **eps)
-{
- XHCISlot *slot;
- XHCIEPContext *epctx;
- USBEndpoint *ep;
- int i, j;
-
- assert(slotid >= 1 && slotid <= xhci->numslots);
-
- slot = &xhci->slots[slotid - 1];
-
- for (i = 2, j = 0; i <= 31; i++) {
- if (!(epmask & (1u << i))) {
- continue;
- }
-
- epctx = slot->eps[i - 1];
- ep = xhci_epid_to_usbep(xhci, slotid, i);
- if (!epctx || !epctx->nr_pstreams || !ep) {
- continue;
- }
-
- if (epctxs) {
- epctxs[j] = epctx;
- }
- eps[j++] = ep;
- }
- return j;
-}
-
-static void xhci_free_device_streams(XHCIState *xhci, unsigned int slotid,
- uint32_t epmask)
-{
- USBEndpoint *eps[30];
- int nr_eps;
-
- nr_eps = xhci_epmask_to_eps_with_streams(xhci, slotid, epmask, NULL, eps);
- if (nr_eps) {
- usb_device_free_streams(eps[0]->dev, eps, nr_eps);
- }
-}
-
-static TRBCCode xhci_alloc_device_streams(XHCIState *xhci, unsigned int slotid,
- uint32_t epmask)
-{
- XHCIEPContext *epctxs[30];
- USBEndpoint *eps[30];
- int i, r, nr_eps, req_nr_streams, dev_max_streams;
-
- nr_eps = xhci_epmask_to_eps_with_streams(xhci, slotid, epmask, epctxs,
- eps);
- if (nr_eps == 0) {
- return CC_SUCCESS;
- }
-
- req_nr_streams = epctxs[0]->nr_pstreams;
- dev_max_streams = eps[0]->max_streams;
-
- for (i = 1; i < nr_eps; i++) {
- /*
- * HdG: I don't expect these to ever trigger, but if they do we need
- * to come up with another solution, ie group identical endpoints
- * together and make an usb_device_alloc_streams call per group.
- */
- if (epctxs[i]->nr_pstreams != req_nr_streams) {
- FIXME("guest streams config not identical for all eps");
- return CC_RESOURCE_ERROR;
- }
- if (eps[i]->max_streams != dev_max_streams) {
- FIXME("device streams config not identical for all eps");
- return CC_RESOURCE_ERROR;
- }
- }
-
- /*
- * max-streams in both the device descriptor and in the controller is a
- * power of 2. But stream id 0 is reserved, so if a device can do up to 4
- * streams the guest will ask for 5 rounded up to the next power of 2 which
- * becomes 8. For emulated devices usb_device_alloc_streams is a nop.
- *
- * For redirected devices however this is an issue, as there we must ask
- * the real xhci controller to alloc streams, and the host driver for the
- * real xhci controller will likely disallow allocating more streams then
- * the device can handle.
- *
- * So we limit the requested nr_streams to the maximum number the device
- * can handle.
- */
- if (req_nr_streams > dev_max_streams) {
- req_nr_streams = dev_max_streams;
- }
-
- r = usb_device_alloc_streams(eps[0]->dev, eps, nr_eps, req_nr_streams);
- if (r != 0) {
- DPRINTF("xhci: alloc streams failed\n");
- return CC_RESOURCE_ERROR;
- }
-
- return CC_SUCCESS;
-}
-
-static XHCIStreamContext *xhci_find_stream(XHCIEPContext *epctx,
- unsigned int streamid,
- uint32_t *cc_error)
-{
- XHCIStreamContext *sctx;
- dma_addr_t base;
- uint32_t ctx[2], sct;
-
- assert(streamid != 0);
- if (epctx->lsa) {
- if (streamid >= epctx->nr_pstreams) {
- *cc_error = CC_INVALID_STREAM_ID_ERROR;
- return NULL;
- }
- sctx = epctx->pstreams + streamid;
- } else {
- FIXME("secondary streams not implemented yet");
- }
-
- if (sctx->sct == -1) {
- xhci_dma_read_u32s(epctx->xhci, sctx->pctx, ctx, sizeof(ctx));
- sct = (ctx[0] >> 1) & 0x07;
- if (epctx->lsa && sct != 1) {
- *cc_error = CC_INVALID_STREAM_TYPE_ERROR;
- return NULL;
- }
- sctx->sct = sct;
- base = xhci_addr64(ctx[0] & ~0xf, ctx[1]);
- xhci_ring_init(epctx->xhci, &sctx->ring, base);
- }
- return sctx;
-}
-
-static void xhci_set_ep_state(XHCIState *xhci, XHCIEPContext *epctx,
- XHCIStreamContext *sctx, uint32_t state)
-{
- XHCIRing *ring = NULL;
- uint32_t ctx[5];
- uint32_t ctx2[2];
-
- xhci_dma_read_u32s(xhci, epctx->pctx, ctx, sizeof(ctx));
- ctx[0] &= ~EP_STATE_MASK;
- ctx[0] |= state;
-
- /* update ring dequeue ptr */
- if (epctx->nr_pstreams) {
- if (sctx != NULL) {
- ring = &sctx->ring;
- xhci_dma_read_u32s(xhci, sctx->pctx, ctx2, sizeof(ctx2));
- ctx2[0] &= 0xe;
- ctx2[0] |= sctx->ring.dequeue | sctx->ring.ccs;
- ctx2[1] = (sctx->ring.dequeue >> 16) >> 16;
- xhci_dma_write_u32s(xhci, sctx->pctx, ctx2, sizeof(ctx2));
- }
- } else {
- ring = &epctx->ring;
- }
- if (ring) {
- ctx[2] = ring->dequeue | ring->ccs;
- ctx[3] = (ring->dequeue >> 16) >> 16;
-
- DPRINTF("xhci: set epctx: " DMA_ADDR_FMT " state=%d dequeue=%08x%08x\n",
- epctx->pctx, state, ctx[3], ctx[2]);
- }
-
- xhci_dma_write_u32s(xhci, epctx->pctx, ctx, sizeof(ctx));
- if (epctx->state != state) {
- trace_usb_xhci_ep_state(epctx->slotid, epctx->epid,
- ep_state_name(epctx->state),
- ep_state_name(state));
- }
- epctx->state = state;
-}
-
-static void xhci_ep_kick_timer(void *opaque)
-{
- XHCIEPContext *epctx = opaque;
- xhci_kick_ep(epctx->xhci, epctx->slotid, epctx->epid, 0);
-}
-
-static XHCIEPContext *xhci_alloc_epctx(XHCIState *xhci,
- unsigned int slotid,
- unsigned int epid)
-{
- XHCIEPContext *epctx;
- int i;
-
- epctx = g_new0(XHCIEPContext, 1);
- epctx->xhci = xhci;
- epctx->slotid = slotid;
- epctx->epid = epid;
-
- for (i = 0; i < ARRAY_SIZE(epctx->transfers); i++) {
- epctx->transfers[i].xhci = xhci;
- epctx->transfers[i].slotid = slotid;
- epctx->transfers[i].epid = epid;
- usb_packet_init(&epctx->transfers[i].packet);
- }
- epctx->kick_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, xhci_ep_kick_timer, epctx);
-
- return epctx;
-}
-
-static void xhci_init_epctx(XHCIEPContext *epctx,
- dma_addr_t pctx, uint32_t *ctx)
-{
- dma_addr_t dequeue;
-
- dequeue = xhci_addr64(ctx[2] & ~0xf, ctx[3]);
-
- epctx->type = (ctx[1] >> EP_TYPE_SHIFT) & EP_TYPE_MASK;
- epctx->pctx = pctx;
- epctx->max_psize = ctx[1]>>16;
- epctx->max_psize *= 1+((ctx[1]>>8)&0xff);
- epctx->max_pstreams = (ctx[0] >> 10) & epctx->xhci->max_pstreams_mask;
- epctx->lsa = (ctx[0] >> 15) & 1;
- if (epctx->max_pstreams) {
- xhci_alloc_streams(epctx, dequeue);
- } else {
- xhci_ring_init(epctx->xhci, &epctx->ring, dequeue);
- epctx->ring.ccs = ctx[2] & 1;
- }
-
- epctx->interval = 1 << ((ctx[0] >> 16) & 0xff);
-}
-
-static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid,
- unsigned int epid, dma_addr_t pctx,
- uint32_t *ctx)
-{
- XHCISlot *slot;
- XHCIEPContext *epctx;
-
- trace_usb_xhci_ep_enable(slotid, epid);
- assert(slotid >= 1 && slotid <= xhci->numslots);
- assert(epid >= 1 && epid <= 31);
-
- slot = &xhci->slots[slotid-1];
- if (slot->eps[epid-1]) {
- xhci_disable_ep(xhci, slotid, epid);
- }
-
- epctx = xhci_alloc_epctx(xhci, slotid, epid);
- slot->eps[epid-1] = epctx;
- xhci_init_epctx(epctx, pctx, ctx);
-
- DPRINTF("xhci: endpoint %d.%d type is %d, max transaction (burst) "
- "size is %d\n", epid/2, epid%2, epctx->type, epctx->max_psize);
-
- epctx->mfindex_last = 0;
-
- epctx->state = EP_RUNNING;
- ctx[0] &= ~EP_STATE_MASK;
- ctx[0] |= EP_RUNNING;
-
- return CC_SUCCESS;
-}
-
-static int xhci_ep_nuke_one_xfer(XHCITransfer *t, TRBCCode report)
-{
- int killed = 0;
-
- if (report && (t->running_async || t->running_retry)) {
- t->status = report;
- xhci_xfer_report(t);
- }
-
- if (t->running_async) {
- usb_cancel_packet(&t->packet);
- t->running_async = 0;
- killed = 1;
- }
- if (t->running_retry) {
- XHCIEPContext *epctx = t->xhci->slots[t->slotid-1].eps[t->epid-1];
- if (epctx) {
- epctx->retry = NULL;
- timer_del(epctx->kick_timer);
- }
- t->running_retry = 0;
- killed = 1;
- }
- g_free(t->trbs);
-
- t->trbs = NULL;
- t->trb_count = t->trb_alloced = 0;
-
- return killed;
-}
-
-static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid,
- unsigned int epid, TRBCCode report)
-{
- XHCISlot *slot;
- XHCIEPContext *epctx;
- int i, xferi, killed = 0;
- USBEndpoint *ep = NULL;
- assert(slotid >= 1 && slotid <= xhci->numslots);
- assert(epid >= 1 && epid <= 31);
-
- DPRINTF("xhci_ep_nuke_xfers(%d, %d)\n", slotid, epid);
-
- slot = &xhci->slots[slotid-1];
-
- if (!slot->eps[epid-1]) {
- return 0;
- }
-
- epctx = slot->eps[epid-1];
-
- xferi = epctx->next_xfer;
- for (i = 0; i < TD_QUEUE; i++) {
- killed += xhci_ep_nuke_one_xfer(&epctx->transfers[xferi], report);
- if (killed) {
- report = 0; /* Only report once */
- }
- epctx->transfers[xferi].packet.ep = NULL;
- xferi = (xferi + 1) % TD_QUEUE;
- }
-
- ep = xhci_epid_to_usbep(xhci, slotid, epid);
- if (ep) {
- usb_device_ep_stopped(ep->dev, ep);
- }
- return killed;
-}
-
-static TRBCCode xhci_disable_ep(XHCIState *xhci, unsigned int slotid,
- unsigned int epid)
-{
- XHCISlot *slot;
- XHCIEPContext *epctx;
- int i;
-
- trace_usb_xhci_ep_disable(slotid, epid);
- assert(slotid >= 1 && slotid <= xhci->numslots);
- assert(epid >= 1 && epid <= 31);
-
- slot = &xhci->slots[slotid-1];
-
- if (!slot->eps[epid-1]) {
- DPRINTF("xhci: slot %d ep %d already disabled\n", slotid, epid);
- return CC_SUCCESS;
- }
-
- xhci_ep_nuke_xfers(xhci, slotid, epid, 0);
-
- epctx = slot->eps[epid-1];
-
- if (epctx->nr_pstreams) {
- xhci_free_streams(epctx);
- }
-
- for (i = 0; i < ARRAY_SIZE(epctx->transfers); i++) {
- usb_packet_cleanup(&epctx->transfers[i].packet);
- }
-
- xhci_set_ep_state(xhci, epctx, NULL, EP_DISABLED);
-
- timer_free(epctx->kick_timer);
- g_free(epctx);
- slot->eps[epid-1] = NULL;
-
- return CC_SUCCESS;
-}
-
-static TRBCCode xhci_stop_ep(XHCIState *xhci, unsigned int slotid,
- unsigned int epid)
-{
- XHCISlot *slot;
- XHCIEPContext *epctx;
-
- trace_usb_xhci_ep_stop(slotid, epid);
- assert(slotid >= 1 && slotid <= xhci->numslots);
-
- if (epid < 1 || epid > 31) {
- DPRINTF("xhci: bad ep %d\n", epid);
- return CC_TRB_ERROR;
- }
-
- slot = &xhci->slots[slotid-1];
-
- if (!slot->eps[epid-1]) {
- DPRINTF("xhci: slot %d ep %d not enabled\n", slotid, epid);
- return CC_EP_NOT_ENABLED_ERROR;
- }
-
- if (xhci_ep_nuke_xfers(xhci, slotid, epid, CC_STOPPED) > 0) {
- DPRINTF("xhci: FIXME: endpoint stopped w/ xfers running, "
- "data might be lost\n");
- }
-
- epctx = slot->eps[epid-1];
-
- xhci_set_ep_state(xhci, epctx, NULL, EP_STOPPED);
-
- if (epctx->nr_pstreams) {
- xhci_reset_streams(epctx);
- }
-
- return CC_SUCCESS;
-}
-
-static TRBCCode xhci_reset_ep(XHCIState *xhci, unsigned int slotid,
- unsigned int epid)
-{
- XHCISlot *slot;
- XHCIEPContext *epctx;
-
- trace_usb_xhci_ep_reset(slotid, epid);
- assert(slotid >= 1 && slotid <= xhci->numslots);
-
- if (epid < 1 || epid > 31) {
- DPRINTF("xhci: bad ep %d\n", epid);
- return CC_TRB_ERROR;
- }
-
- slot = &xhci->slots[slotid-1];
-
- if (!slot->eps[epid-1]) {
- DPRINTF("xhci: slot %d ep %d not enabled\n", slotid, epid);
- return CC_EP_NOT_ENABLED_ERROR;
- }
-
- epctx = slot->eps[epid-1];
-
- if (epctx->state != EP_HALTED) {
- DPRINTF("xhci: reset EP while EP %d not halted (%d)\n",
- epid, epctx->state);
- return CC_CONTEXT_STATE_ERROR;
- }
-
- if (xhci_ep_nuke_xfers(xhci, slotid, epid, 0) > 0) {
- DPRINTF("xhci: FIXME: endpoint reset w/ xfers running, "
- "data might be lost\n");
- }
-
- if (!xhci->slots[slotid-1].uport ||
- !xhci->slots[slotid-1].uport->dev ||
- !xhci->slots[slotid-1].uport->dev->attached) {
- return CC_USB_TRANSACTION_ERROR;
- }
-
- xhci_set_ep_state(xhci, epctx, NULL, EP_STOPPED);
-
- if (epctx->nr_pstreams) {
- xhci_reset_streams(epctx);
- }
-
- return CC_SUCCESS;
-}
-
-static TRBCCode xhci_set_ep_dequeue(XHCIState *xhci, unsigned int slotid,
- unsigned int epid, unsigned int streamid,
- uint64_t pdequeue)
-{
- XHCISlot *slot;
- XHCIEPContext *epctx;
- XHCIStreamContext *sctx;
- dma_addr_t dequeue;
-
- assert(slotid >= 1 && slotid <= xhci->numslots);
-
- if (epid < 1 || epid > 31) {
- DPRINTF("xhci: bad ep %d\n", epid);
- return CC_TRB_ERROR;
- }
-
- trace_usb_xhci_ep_set_dequeue(slotid, epid, streamid, pdequeue);
- dequeue = xhci_mask64(pdequeue);
-
- slot = &xhci->slots[slotid-1];
-
- if (!slot->eps[epid-1]) {
- DPRINTF("xhci: slot %d ep %d not enabled\n", slotid, epid);
- return CC_EP_NOT_ENABLED_ERROR;
- }
-
- epctx = slot->eps[epid-1];
-
- if (epctx->state != EP_STOPPED) {
- DPRINTF("xhci: set EP dequeue pointer while EP %d not stopped\n", epid);
- return CC_CONTEXT_STATE_ERROR;
- }
-
- if (epctx->nr_pstreams) {
- uint32_t err;
- sctx = xhci_find_stream(epctx, streamid, &err);
- if (sctx == NULL) {
- return err;
- }
- xhci_ring_init(xhci, &sctx->ring, dequeue & ~0xf);
- sctx->ring.ccs = dequeue & 1;
- } else {
- sctx = NULL;
- xhci_ring_init(xhci, &epctx->ring, dequeue & ~0xF);
- epctx->ring.ccs = dequeue & 1;
- }
-
- xhci_set_ep_state(xhci, epctx, sctx, EP_STOPPED);
-
- return CC_SUCCESS;
-}
-
-static int xhci_xfer_create_sgl(XHCITransfer *xfer, int in_xfer)
-{
- XHCIState *xhci = xfer->xhci;
- int i;
-
- xfer->int_req = false;
- pci_dma_sglist_init(&xfer->sgl, PCI_DEVICE(xhci), xfer->trb_count);
- for (i = 0; i < xfer->trb_count; i++) {
- XHCITRB *trb = &xfer->trbs[i];
- dma_addr_t addr;
- unsigned int chunk = 0;
-
- if (trb->control & TRB_TR_IOC) {
- xfer->int_req = true;
- }
-
- switch (TRB_TYPE(*trb)) {
- case TR_DATA:
- if ((!(trb->control & TRB_TR_DIR)) != (!in_xfer)) {
- DPRINTF("xhci: data direction mismatch for TR_DATA\n");
- goto err;
- }
- /* fallthrough */
- case TR_NORMAL:
- case TR_ISOCH:
- addr = xhci_mask64(trb->parameter);
- chunk = trb->status & 0x1ffff;
- if (trb->control & TRB_TR_IDT) {
- if (chunk > 8 || in_xfer) {
- DPRINTF("xhci: invalid immediate data TRB\n");
- goto err;
- }
- qemu_sglist_add(&xfer->sgl, trb->addr, chunk);
- } else {
- qemu_sglist_add(&xfer->sgl, addr, chunk);
- }
- break;
- }
- }
-
- return 0;
-
-err:
- qemu_sglist_destroy(&xfer->sgl);
- xhci_die(xhci);
- return -1;
-}
-
-static void xhci_xfer_unmap(XHCITransfer *xfer)
-{
- usb_packet_unmap(&xfer->packet, &xfer->sgl);
- qemu_sglist_destroy(&xfer->sgl);
-}
-
-static void xhci_xfer_report(XHCITransfer *xfer)
-{
- uint32_t edtla = 0;
- unsigned int left;
- bool reported = 0;
- bool shortpkt = 0;
- XHCIEvent event = {ER_TRANSFER, CC_SUCCESS};
- XHCIState *xhci = xfer->xhci;
- int i;
-
- left = xfer->packet.actual_length;
-
- for (i = 0; i < xfer->trb_count; i++) {
- XHCITRB *trb = &xfer->trbs[i];
- unsigned int chunk = 0;
-
- switch (TRB_TYPE(*trb)) {
- case TR_DATA:
- case TR_NORMAL:
- case TR_ISOCH:
- chunk = trb->status & 0x1ffff;
- if (chunk > left) {
- chunk = left;
- if (xfer->status == CC_SUCCESS) {
- shortpkt = 1;
- }
- }
- left -= chunk;
- edtla += chunk;
- break;
- case TR_STATUS:
- reported = 0;
- shortpkt = 0;
- break;
- }
-
- if (!reported && ((trb->control & TRB_TR_IOC) ||
- (shortpkt && (trb->control & TRB_TR_ISP)) ||
- (xfer->status != CC_SUCCESS && left == 0))) {
- event.slotid = xfer->slotid;
- event.epid = xfer->epid;
- event.length = (trb->status & 0x1ffff) - chunk;
- event.flags = 0;
- event.ptr = trb->addr;
- if (xfer->status == CC_SUCCESS) {
- event.ccode = shortpkt ? CC_SHORT_PACKET : CC_SUCCESS;
- } else {
- event.ccode = xfer->status;
- }
- if (TRB_TYPE(*trb) == TR_EVDATA) {
- event.ptr = trb->parameter;
- event.flags |= TRB_EV_ED;
- event.length = edtla & 0xffffff;
- DPRINTF("xhci_xfer_data: EDTLA=%d\n", event.length);
- edtla = 0;
- }
- xhci_event(xhci, &event, TRB_INTR(*trb));
- reported = 1;
- if (xfer->status != CC_SUCCESS) {
- return;
- }
- }
-
- switch (TRB_TYPE(*trb)) {
- case TR_SETUP:
- reported = 0;
- shortpkt = 0;
- break;
- }
-
- }
-}
-
-static void xhci_stall_ep(XHCITransfer *xfer)
-{
- XHCIState *xhci = xfer->xhci;
- XHCISlot *slot = &xhci->slots[xfer->slotid-1];
- XHCIEPContext *epctx = slot->eps[xfer->epid-1];
- uint32_t err;
- XHCIStreamContext *sctx;
-
- if (epctx->nr_pstreams) {
- sctx = xhci_find_stream(epctx, xfer->streamid, &err);
- if (sctx == NULL) {
- return;
- }
- sctx->ring.dequeue = xfer->trbs[0].addr;
- sctx->ring.ccs = xfer->trbs[0].ccs;
- xhci_set_ep_state(xhci, epctx, sctx, EP_HALTED);
- } else {
- epctx->ring.dequeue = xfer->trbs[0].addr;
- epctx->ring.ccs = xfer->trbs[0].ccs;
- xhci_set_ep_state(xhci, epctx, NULL, EP_HALTED);
- }
-}
-
-static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer,
- XHCIEPContext *epctx);
-
-static int xhci_setup_packet(XHCITransfer *xfer)
-{
- XHCIState *xhci = xfer->xhci;
- USBEndpoint *ep;
- int dir;
-
- dir = xfer->in_xfer ? USB_TOKEN_IN : USB_TOKEN_OUT;
-
- if (xfer->packet.ep) {
- ep = xfer->packet.ep;
- } else {
- ep = xhci_epid_to_usbep(xhci, xfer->slotid, xfer->epid);
- if (!ep) {
- DPRINTF("xhci: slot %d has no device\n",
- xfer->slotid);
- return -1;
- }
- }
-
- xhci_xfer_create_sgl(xfer, dir == USB_TOKEN_IN); /* Also sets int_req */
- usb_packet_setup(&xfer->packet, dir, ep, xfer->streamid,
- xfer->trbs[0].addr, false, xfer->int_req);
- usb_packet_map(&xfer->packet, &xfer->sgl);
- DPRINTF("xhci: setup packet pid 0x%x addr %d ep %d\n",
- xfer->packet.pid, ep->dev->addr, ep->nr);
- return 0;
-}
-
-static int xhci_complete_packet(XHCITransfer *xfer)
-{
- if (xfer->packet.status == USB_RET_ASYNC) {
- trace_usb_xhci_xfer_async(xfer);
- xfer->running_async = 1;
- xfer->running_retry = 0;
- xfer->complete = 0;
- return 0;
- } else if (xfer->packet.status == USB_RET_NAK) {
- trace_usb_xhci_xfer_nak(xfer);
- xfer->running_async = 0;
- xfer->running_retry = 1;
- xfer->complete = 0;
- return 0;
- } else {
- xfer->running_async = 0;
- xfer->running_retry = 0;
- xfer->complete = 1;
- xhci_xfer_unmap(xfer);
- }
-
- if (xfer->packet.status == USB_RET_SUCCESS) {
- trace_usb_xhci_xfer_success(xfer, xfer->packet.actual_length);
- xfer->status = CC_SUCCESS;
- xhci_xfer_report(xfer);
- return 0;
- }
-
- /* error */
- trace_usb_xhci_xfer_error(xfer, xfer->packet.status);
- switch (xfer->packet.status) {
- case USB_RET_NODEV:
- case USB_RET_IOERROR:
- xfer->status = CC_USB_TRANSACTION_ERROR;
- xhci_xfer_report(xfer);
- xhci_stall_ep(xfer);
- break;
- case USB_RET_STALL:
- xfer->status = CC_STALL_ERROR;
- xhci_xfer_report(xfer);
- xhci_stall_ep(xfer);
- break;
- case USB_RET_BABBLE:
- xfer->status = CC_BABBLE_DETECTED;
- xhci_xfer_report(xfer);
- xhci_stall_ep(xfer);
- break;
- default:
- DPRINTF("%s: FIXME: status = %d\n", __func__,
- xfer->packet.status);
- FIXME("unhandled USB_RET_*");
- }
- return 0;
-}
-
-static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer)
-{
- XHCITRB *trb_setup, *trb_status;
- uint8_t bmRequestType;
-
- trb_setup = &xfer->trbs[0];
- trb_status = &xfer->trbs[xfer->trb_count-1];
-
- trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid, xfer->streamid);
-
- /* at most one Event Data TRB allowed after STATUS */
- if (TRB_TYPE(*trb_status) == TR_EVDATA && xfer->trb_count > 2) {
- trb_status--;
- }
-
- /* do some sanity checks */
- if (TRB_TYPE(*trb_setup) != TR_SETUP) {
- DPRINTF("xhci: ep0 first TD not SETUP: %d\n",
- TRB_TYPE(*trb_setup));
- return -1;
- }
- if (TRB_TYPE(*trb_status) != TR_STATUS) {
- DPRINTF("xhci: ep0 last TD not STATUS: %d\n",
- TRB_TYPE(*trb_status));
- return -1;
- }
- if (!(trb_setup->control & TRB_TR_IDT)) {
- DPRINTF("xhci: Setup TRB doesn't have IDT set\n");
- return -1;
- }
- if ((trb_setup->status & 0x1ffff) != 8) {
- DPRINTF("xhci: Setup TRB has bad length (%d)\n",
- (trb_setup->status & 0x1ffff));
- return -1;
- }
-
- bmRequestType = trb_setup->parameter;
-
- xfer->in_xfer = bmRequestType & USB_DIR_IN;
- xfer->iso_xfer = false;
- xfer->timed_xfer = false;
-
- if (xhci_setup_packet(xfer) < 0) {
- return -1;
- }
- xfer->packet.parameter = trb_setup->parameter;
-
- usb_handle_packet(xfer->packet.ep->dev, &xfer->packet);
-
- xhci_complete_packet(xfer);
- if (!xfer->running_async && !xfer->running_retry) {
- xhci_kick_ep(xhci, xfer->slotid, xfer->epid, 0);
- }
- return 0;
-}
-
-static void xhci_calc_intr_kick(XHCIState *xhci, XHCITransfer *xfer,
- XHCIEPContext *epctx, uint64_t mfindex)
-{
- uint64_t asap = ((mfindex + epctx->interval - 1) &
- ~(epctx->interval-1));
- uint64_t kick = epctx->mfindex_last + epctx->interval;
-
- assert(epctx->interval != 0);
- xfer->mfindex_kick = MAX(asap, kick);
-}
-
-static void xhci_calc_iso_kick(XHCIState *xhci, XHCITransfer *xfer,
- XHCIEPContext *epctx, uint64_t mfindex)
-{
- if (xfer->trbs[0].control & TRB_TR_SIA) {
- uint64_t asap = ((mfindex + epctx->interval - 1) &
- ~(epctx->interval-1));
- if (asap >= epctx->mfindex_last &&
- asap <= epctx->mfindex_last + epctx->interval * 4) {
- xfer->mfindex_kick = epctx->mfindex_last + epctx->interval;
- } else {
- xfer->mfindex_kick = asap;
- }
- } else {
- xfer->mfindex_kick = ((xfer->trbs[0].control >> TRB_TR_FRAMEID_SHIFT)
- & TRB_TR_FRAMEID_MASK) << 3;
- xfer->mfindex_kick |= mfindex & ~0x3fff;
- if (xfer->mfindex_kick + 0x100 < mfindex) {
- xfer->mfindex_kick += 0x4000;
- }
- }
-}
-
-static void xhci_check_intr_iso_kick(XHCIState *xhci, XHCITransfer *xfer,
- XHCIEPContext *epctx, uint64_t mfindex)
-{
- if (xfer->mfindex_kick > mfindex) {
- timer_mod(epctx->kick_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- (xfer->mfindex_kick - mfindex) * 125000);
- xfer->running_retry = 1;
- } else {
- epctx->mfindex_last = xfer->mfindex_kick;
- timer_del(epctx->kick_timer);
- xfer->running_retry = 0;
- }
-}
-
-
-static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx)
-{
- uint64_t mfindex;
-
- DPRINTF("xhci_submit(slotid=%d,epid=%d)\n", xfer->slotid, xfer->epid);
-
- xfer->in_xfer = epctx->type>>2;
-
- switch(epctx->type) {
- case ET_INTR_OUT:
- case ET_INTR_IN:
- xfer->pkts = 0;
- xfer->iso_xfer = false;
- xfer->timed_xfer = true;
- mfindex = xhci_mfindex_get(xhci);
- xhci_calc_intr_kick(xhci, xfer, epctx, mfindex);
- xhci_check_intr_iso_kick(xhci, xfer, epctx, mfindex);
- if (xfer->running_retry) {
- return -1;
- }
- break;
- case ET_BULK_OUT:
- case ET_BULK_IN:
- xfer->pkts = 0;
- xfer->iso_xfer = false;
- xfer->timed_xfer = false;
- break;
- case ET_ISO_OUT:
- case ET_ISO_IN:
- xfer->pkts = 1;
- xfer->iso_xfer = true;
- xfer->timed_xfer = true;
- mfindex = xhci_mfindex_get(xhci);
- xhci_calc_iso_kick(xhci, xfer, epctx, mfindex);
- xhci_check_intr_iso_kick(xhci, xfer, epctx, mfindex);
- if (xfer->running_retry) {
- return -1;
- }
- break;
- default:
- trace_usb_xhci_unimplemented("endpoint type", epctx->type);
- return -1;
- }
-
- if (xhci_setup_packet(xfer) < 0) {
- return -1;
- }
- usb_handle_packet(xfer->packet.ep->dev, &xfer->packet);
-
- xhci_complete_packet(xfer);
- if (!xfer->running_async && !xfer->running_retry) {
- xhci_kick_ep(xhci, xfer->slotid, xfer->epid, xfer->streamid);
- }
- return 0;
-}
-
-static int xhci_fire_transfer(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx)
-{
- trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid, xfer->streamid);
- return xhci_submit(xhci, xfer, epctx);
-}
-
-static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
- unsigned int epid, unsigned int streamid)
-{
- XHCIStreamContext *stctx;
- XHCIEPContext *epctx;
- XHCIRing *ring;
- USBEndpoint *ep = NULL;
- uint64_t mfindex;
- int length;
- int i;
-
- trace_usb_xhci_ep_kick(slotid, epid, streamid);
- assert(slotid >= 1 && slotid <= xhci->numslots);
- assert(epid >= 1 && epid <= 31);
-
- if (!xhci->slots[slotid-1].enabled) {
- DPRINTF("xhci: xhci_kick_ep for disabled slot %d\n", slotid);
- return;
- }
- epctx = xhci->slots[slotid-1].eps[epid-1];
- if (!epctx) {
- DPRINTF("xhci: xhci_kick_ep for disabled endpoint %d,%d\n",
- epid, slotid);
- return;
- }
-
- /* If the device has been detached, but the guest has not noticed this
- yet the 2 above checks will succeed, but we must NOT continue */
- if (!xhci->slots[slotid - 1].uport ||
- !xhci->slots[slotid - 1].uport->dev ||
- !xhci->slots[slotid - 1].uport->dev->attached) {
- return;
- }
-
- if (epctx->retry) {
- XHCITransfer *xfer = epctx->retry;
-
- trace_usb_xhci_xfer_retry(xfer);
- assert(xfer->running_retry);
- if (xfer->timed_xfer) {
- /* time to kick the transfer? */
- mfindex = xhci_mfindex_get(xhci);
- xhci_check_intr_iso_kick(xhci, xfer, epctx, mfindex);
- if (xfer->running_retry) {
- return;
- }
- xfer->timed_xfer = 0;
- xfer->running_retry = 1;
- }
- if (xfer->iso_xfer) {
- /* retry iso transfer */
- if (xhci_setup_packet(xfer) < 0) {
- return;
- }
- usb_handle_packet(xfer->packet.ep->dev, &xfer->packet);
- assert(xfer->packet.status != USB_RET_NAK);
- xhci_complete_packet(xfer);
- } else {
- /* retry nak'ed transfer */
- if (xhci_setup_packet(xfer) < 0) {
- return;
- }
- usb_handle_packet(xfer->packet.ep->dev, &xfer->packet);
- if (xfer->packet.status == USB_RET_NAK) {
- return;
- }
- xhci_complete_packet(xfer);
- }
- assert(!xfer->running_retry);
- epctx->retry = NULL;
- }
-
- if (epctx->state == EP_HALTED) {
- DPRINTF("xhci: ep halted, not running schedule\n");
- return;
- }
-
-
- if (epctx->nr_pstreams) {
- uint32_t err;
- stctx = xhci_find_stream(epctx, streamid, &err);
- if (stctx == NULL) {
- return;
- }
- ring = &stctx->ring;
- xhci_set_ep_state(xhci, epctx, stctx, EP_RUNNING);
- } else {
- ring = &epctx->ring;
- streamid = 0;
- xhci_set_ep_state(xhci, epctx, NULL, EP_RUNNING);
- }
- assert(ring->dequeue != 0);
-
- while (1) {
- XHCITransfer *xfer = &epctx->transfers[epctx->next_xfer];
- if (xfer->running_async || xfer->running_retry) {
- break;
- }
- length = xhci_ring_chain_length(xhci, ring);
- if (length < 0) {
- break;
- } else if (length == 0) {
- break;
- }
- if (xfer->trbs && xfer->trb_alloced < length) {
- xfer->trb_count = 0;
- xfer->trb_alloced = 0;
- g_free(xfer->trbs);
- xfer->trbs = NULL;
- }
- if (!xfer->trbs) {
- xfer->trbs = g_new(XHCITRB, length);
- xfer->trb_alloced = length;
- }
- xfer->trb_count = length;
-
- for (i = 0; i < length; i++) {
- assert(xhci_ring_fetch(xhci, ring, &xfer->trbs[i], NULL));
- }
- xfer->streamid = streamid;
-
- if (epid == 1) {
- if (xhci_fire_ctl_transfer(xhci, xfer) >= 0) {
- epctx->next_xfer = (epctx->next_xfer + 1) % TD_QUEUE;
- } else {
- DPRINTF("xhci: error firing CTL transfer\n");
- }
- } else {
- if (xhci_fire_transfer(xhci, xfer, epctx) >= 0) {
- epctx->next_xfer = (epctx->next_xfer + 1) % TD_QUEUE;
- } else {
- if (!xfer->timed_xfer) {
- DPRINTF("xhci: error firing data transfer\n");
- }
- }
- }
-
- if (epctx->state == EP_HALTED) {
- break;
- }
- if (xfer->running_retry) {
- DPRINTF("xhci: xfer nacked, stopping schedule\n");
- epctx->retry = xfer;
- break;
- }
- }
-
- ep = xhci_epid_to_usbep(xhci, slotid, epid);
- if (ep) {
- usb_device_flush_ep_queue(ep->dev, ep);
- }
-}
-
-static TRBCCode xhci_enable_slot(XHCIState *xhci, unsigned int slotid)
-{
- trace_usb_xhci_slot_enable(slotid);
- assert(slotid >= 1 && slotid <= xhci->numslots);
- xhci->slots[slotid-1].enabled = 1;
- xhci->slots[slotid-1].uport = NULL;
- memset(xhci->slots[slotid-1].eps, 0, sizeof(XHCIEPContext*)*31);
-
- return CC_SUCCESS;
-}
-
-static TRBCCode xhci_disable_slot(XHCIState *xhci, unsigned int slotid)
-{
- int i;
-
- trace_usb_xhci_slot_disable(slotid);
- assert(slotid >= 1 && slotid <= xhci->numslots);
-
- for (i = 1; i <= 31; i++) {
- if (xhci->slots[slotid-1].eps[i-1]) {
- xhci_disable_ep(xhci, slotid, i);
- }
- }
-
- xhci->slots[slotid-1].enabled = 0;
- xhci->slots[slotid-1].addressed = 0;
- xhci->slots[slotid-1].uport = NULL;
- return CC_SUCCESS;
-}
-
-static USBPort *xhci_lookup_uport(XHCIState *xhci, uint32_t *slot_ctx)
-{
- USBPort *uport;
- char path[32];
- int i, pos, port;
-
- port = (slot_ctx[1]>>16) & 0xFF;
- if (port < 1 || port > xhci->numports) {
- return NULL;
- }
- port = xhci->ports[port-1].uport->index+1;
- pos = snprintf(path, sizeof(path), "%d", port);
- for (i = 0; i < 5; i++) {
- port = (slot_ctx[0] >> 4*i) & 0x0f;
- if (!port) {
- break;
- }
- pos += snprintf(path + pos, sizeof(path) - pos, ".%d", port);
- }
-
- QTAILQ_FOREACH(uport, &xhci->bus.used, next) {
- if (strcmp(uport->path, path) == 0) {
- return uport;
- }
- }
- return NULL;
-}
-
-static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid,
- uint64_t pictx, bool bsr)
-{
- XHCISlot *slot;
- USBPort *uport;
- USBDevice *dev;
- dma_addr_t ictx, octx, dcbaap;
- uint64_t poctx;
- uint32_t ictl_ctx[2];
- uint32_t slot_ctx[4];
- uint32_t ep0_ctx[5];
- int i;
- TRBCCode res;
-
- assert(slotid >= 1 && slotid <= xhci->numslots);
-
- dcbaap = xhci_addr64(xhci->dcbaap_low, xhci->dcbaap_high);
- poctx = ldq_le_pci_dma(PCI_DEVICE(xhci), dcbaap + 8 * slotid);
- ictx = xhci_mask64(pictx);
- octx = xhci_mask64(poctx);
-
- DPRINTF("xhci: input context at "DMA_ADDR_FMT"\n", ictx);
- DPRINTF("xhci: output context at "DMA_ADDR_FMT"\n", octx);
-
- xhci_dma_read_u32s(xhci, ictx, ictl_ctx, sizeof(ictl_ctx));
-
- if (ictl_ctx[0] != 0x0 || ictl_ctx[1] != 0x3) {
- DPRINTF("xhci: invalid input context control %08x %08x\n",
- ictl_ctx[0], ictl_ctx[1]);
- return CC_TRB_ERROR;
- }
-
- xhci_dma_read_u32s(xhci, ictx+32, slot_ctx, sizeof(slot_ctx));
- xhci_dma_read_u32s(xhci, ictx+64, ep0_ctx, sizeof(ep0_ctx));
-
- DPRINTF("xhci: input slot context: %08x %08x %08x %08x\n",
- slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
-
- DPRINTF("xhci: input ep0 context: %08x %08x %08x %08x %08x\n",
- ep0_ctx[0], ep0_ctx[1], ep0_ctx[2], ep0_ctx[3], ep0_ctx[4]);
-
- uport = xhci_lookup_uport(xhci, slot_ctx);
- if (uport == NULL) {
- DPRINTF("xhci: port not found\n");
- return CC_TRB_ERROR;
- }
- trace_usb_xhci_slot_address(slotid, uport->path);
-
- dev = uport->dev;
- if (!dev || !dev->attached) {
- DPRINTF("xhci: port %s not connected\n", uport->path);
- return CC_USB_TRANSACTION_ERROR;
- }
-
- for (i = 0; i < xhci->numslots; i++) {
- if (i == slotid-1) {
- continue;
- }
- if (xhci->slots[i].uport == uport) {
- DPRINTF("xhci: port %s already assigned to slot %d\n",
- uport->path, i+1);
- return CC_TRB_ERROR;
- }
- }
-
- slot = &xhci->slots[slotid-1];
- slot->uport = uport;
- slot->ctx = octx;
-
- if (bsr) {
- slot_ctx[3] = SLOT_DEFAULT << SLOT_STATE_SHIFT;
- } else {
- USBPacket p;
- uint8_t buf[1];
-
- slot_ctx[3] = (SLOT_ADDRESSED << SLOT_STATE_SHIFT) | slotid;
- usb_device_reset(dev);
- memset(&p, 0, sizeof(p));
- usb_packet_addbuf(&p, buf, sizeof(buf));
- usb_packet_setup(&p, USB_TOKEN_OUT,
- usb_ep_get(dev, USB_TOKEN_OUT, 0), 0,
- 0, false, false);
- usb_device_handle_control(dev, &p,
- DeviceOutRequest | USB_REQ_SET_ADDRESS,
- slotid, 0, 0, NULL);
- assert(p.status != USB_RET_ASYNC);
- }
-
- res = xhci_enable_ep(xhci, slotid, 1, octx+32, ep0_ctx);
-
- DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
- slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
- DPRINTF("xhci: output ep0 context: %08x %08x %08x %08x %08x\n",
- ep0_ctx[0], ep0_ctx[1], ep0_ctx[2], ep0_ctx[3], ep0_ctx[4]);
-
- xhci_dma_write_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx));
- xhci_dma_write_u32s(xhci, octx+32, ep0_ctx, sizeof(ep0_ctx));
-
- xhci->slots[slotid-1].addressed = 1;
- return res;
-}
-
-
-static TRBCCode xhci_configure_slot(XHCIState *xhci, unsigned int slotid,
- uint64_t pictx, bool dc)
-{
- dma_addr_t ictx, octx;
- uint32_t ictl_ctx[2];
- uint32_t slot_ctx[4];
- uint32_t islot_ctx[4];
- uint32_t ep_ctx[5];
- int i;
- TRBCCode res;
-
- trace_usb_xhci_slot_configure(slotid);
- assert(slotid >= 1 && slotid <= xhci->numslots);
-
- ictx = xhci_mask64(pictx);
- octx = xhci->slots[slotid-1].ctx;
-
- DPRINTF("xhci: input context at "DMA_ADDR_FMT"\n", ictx);
- DPRINTF("xhci: output context at "DMA_ADDR_FMT"\n", octx);
-
- if (dc) {
- for (i = 2; i <= 31; i++) {
- if (xhci->slots[slotid-1].eps[i-1]) {
- xhci_disable_ep(xhci, slotid, i);
- }
- }
-
- xhci_dma_read_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx));
- slot_ctx[3] &= ~(SLOT_STATE_MASK << SLOT_STATE_SHIFT);
- slot_ctx[3] |= SLOT_ADDRESSED << SLOT_STATE_SHIFT;
- DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
- slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
- xhci_dma_write_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx));
-
- return CC_SUCCESS;
- }
-
- xhci_dma_read_u32s(xhci, ictx, ictl_ctx, sizeof(ictl_ctx));
-
- if ((ictl_ctx[0] & 0x3) != 0x0 || (ictl_ctx[1] & 0x3) != 0x1) {
- DPRINTF("xhci: invalid input context control %08x %08x\n",
- ictl_ctx[0], ictl_ctx[1]);
- return CC_TRB_ERROR;
- }
-
- xhci_dma_read_u32s(xhci, ictx+32, islot_ctx, sizeof(islot_ctx));
- xhci_dma_read_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx));
-
- if (SLOT_STATE(slot_ctx[3]) < SLOT_ADDRESSED) {
- DPRINTF("xhci: invalid slot state %08x\n", slot_ctx[3]);
- return CC_CONTEXT_STATE_ERROR;
- }
-
- xhci_free_device_streams(xhci, slotid, ictl_ctx[0] | ictl_ctx[1]);
-
- for (i = 2; i <= 31; i++) {
- if (ictl_ctx[0] & (1<<i)) {
- xhci_disable_ep(xhci, slotid, i);
- }
- if (ictl_ctx[1] & (1<<i)) {
- xhci_dma_read_u32s(xhci, ictx+32+(32*i), ep_ctx, sizeof(ep_ctx));
- DPRINTF("xhci: input ep%d.%d context: %08x %08x %08x %08x %08x\n",
- i/2, i%2, ep_ctx[0], ep_ctx[1], ep_ctx[2],
- ep_ctx[3], ep_ctx[4]);
- xhci_disable_ep(xhci, slotid, i);
- res = xhci_enable_ep(xhci, slotid, i, octx+(32*i), ep_ctx);
- if (res != CC_SUCCESS) {
- return res;
- }
- DPRINTF("xhci: output ep%d.%d context: %08x %08x %08x %08x %08x\n",
- i/2, i%2, ep_ctx[0], ep_ctx[1], ep_ctx[2],
- ep_ctx[3], ep_ctx[4]);
- xhci_dma_write_u32s(xhci, octx+(32*i), ep_ctx, sizeof(ep_ctx));
- }
- }
-
- res = xhci_alloc_device_streams(xhci, slotid, ictl_ctx[1]);
- if (res != CC_SUCCESS) {
- for (i = 2; i <= 31; i++) {
- if (ictl_ctx[1] & (1u << i)) {
- xhci_disable_ep(xhci, slotid, i);
- }
- }
- return res;
- }
-
- slot_ctx[3] &= ~(SLOT_STATE_MASK << SLOT_STATE_SHIFT);
- slot_ctx[3] |= SLOT_CONFIGURED << SLOT_STATE_SHIFT;
- slot_ctx[0] &= ~(SLOT_CONTEXT_ENTRIES_MASK << SLOT_CONTEXT_ENTRIES_SHIFT);
- slot_ctx[0] |= islot_ctx[0] & (SLOT_CONTEXT_ENTRIES_MASK <<
- SLOT_CONTEXT_ENTRIES_SHIFT);
- DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
- slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
-
- xhci_dma_write_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx));
-
- return CC_SUCCESS;
-}
-
-
-static TRBCCode xhci_evaluate_slot(XHCIState *xhci, unsigned int slotid,
- uint64_t pictx)
-{
- dma_addr_t ictx, octx;
- uint32_t ictl_ctx[2];
- uint32_t iep0_ctx[5];
- uint32_t ep0_ctx[5];
- uint32_t islot_ctx[4];
- uint32_t slot_ctx[4];
-
- trace_usb_xhci_slot_evaluate(slotid);
- assert(slotid >= 1 && slotid <= xhci->numslots);
-
- ictx = xhci_mask64(pictx);
- octx = xhci->slots[slotid-1].ctx;
-
- DPRINTF("xhci: input context at "DMA_ADDR_FMT"\n", ictx);
- DPRINTF("xhci: output context at "DMA_ADDR_FMT"\n", octx);
-
- xhci_dma_read_u32s(xhci, ictx, ictl_ctx, sizeof(ictl_ctx));
-
- if (ictl_ctx[0] != 0x0 || ictl_ctx[1] & ~0x3) {
- DPRINTF("xhci: invalid input context control %08x %08x\n",
- ictl_ctx[0], ictl_ctx[1]);
- return CC_TRB_ERROR;
- }
-
- if (ictl_ctx[1] & 0x1) {
- xhci_dma_read_u32s(xhci, ictx+32, islot_ctx, sizeof(islot_ctx));
-
- DPRINTF("xhci: input slot context: %08x %08x %08x %08x\n",
- islot_ctx[0], islot_ctx[1], islot_ctx[2], islot_ctx[3]);
-
- xhci_dma_read_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx));
-
- slot_ctx[1] &= ~0xFFFF; /* max exit latency */
- slot_ctx[1] |= islot_ctx[1] & 0xFFFF;
- slot_ctx[2] &= ~0xFF00000; /* interrupter target */
- slot_ctx[2] |= islot_ctx[2] & 0xFF000000;
-
- DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
- slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
-
- xhci_dma_write_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx));
- }
-
- if (ictl_ctx[1] & 0x2) {
- xhci_dma_read_u32s(xhci, ictx+64, iep0_ctx, sizeof(iep0_ctx));
-
- DPRINTF("xhci: input ep0 context: %08x %08x %08x %08x %08x\n",
- iep0_ctx[0], iep0_ctx[1], iep0_ctx[2],
- iep0_ctx[3], iep0_ctx[4]);
-
- xhci_dma_read_u32s(xhci, octx+32, ep0_ctx, sizeof(ep0_ctx));
-
- ep0_ctx[1] &= ~0xFFFF0000; /* max packet size*/
- ep0_ctx[1] |= iep0_ctx[1] & 0xFFFF0000;
-
- DPRINTF("xhci: output ep0 context: %08x %08x %08x %08x %08x\n",
- ep0_ctx[0], ep0_ctx[1], ep0_ctx[2], ep0_ctx[3], ep0_ctx[4]);
-
- xhci_dma_write_u32s(xhci, octx+32, ep0_ctx, sizeof(ep0_ctx));
- }
-
- return CC_SUCCESS;
-}
-
-static TRBCCode xhci_reset_slot(XHCIState *xhci, unsigned int slotid)
-{
- uint32_t slot_ctx[4];
- dma_addr_t octx;
- int i;
-
- trace_usb_xhci_slot_reset(slotid);
- assert(slotid >= 1 && slotid <= xhci->numslots);
-
- octx = xhci->slots[slotid-1].ctx;
-
- DPRINTF("xhci: output context at "DMA_ADDR_FMT"\n", octx);
-
- for (i = 2; i <= 31; i++) {
- if (xhci->slots[slotid-1].eps[i-1]) {
- xhci_disable_ep(xhci, slotid, i);
- }
- }
-
- xhci_dma_read_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx));
- slot_ctx[3] &= ~(SLOT_STATE_MASK << SLOT_STATE_SHIFT);
- slot_ctx[3] |= SLOT_DEFAULT << SLOT_STATE_SHIFT;
- DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
- slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
- xhci_dma_write_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx));
-
- return CC_SUCCESS;
-}
-
-static unsigned int xhci_get_slot(XHCIState *xhci, XHCIEvent *event, XHCITRB *trb)
-{
- unsigned int slotid;
- slotid = (trb->control >> TRB_CR_SLOTID_SHIFT) & TRB_CR_SLOTID_MASK;
- if (slotid < 1 || slotid > xhci->numslots) {
- DPRINTF("xhci: bad slot id %d\n", slotid);
- event->ccode = CC_TRB_ERROR;
- return 0;
- } else if (!xhci->slots[slotid-1].enabled) {
- DPRINTF("xhci: slot id %d not enabled\n", slotid);
- event->ccode = CC_SLOT_NOT_ENABLED_ERROR;
- return 0;
- }
- return slotid;
-}
-
-/* cleanup slot state on usb device detach */
-static void xhci_detach_slot(XHCIState *xhci, USBPort *uport)
-{
- int slot, ep;
-
- for (slot = 0; slot < xhci->numslots; slot++) {
- if (xhci->slots[slot].uport == uport) {
- break;
- }
- }
- if (slot == xhci->numslots) {
- return;
- }
-
- for (ep = 0; ep < 31; ep++) {
- if (xhci->slots[slot].eps[ep]) {
- xhci_ep_nuke_xfers(xhci, slot + 1, ep + 1, 0);
- }
- }
- xhci->slots[slot].uport = NULL;
-}
-
-static TRBCCode xhci_get_port_bandwidth(XHCIState *xhci, uint64_t pctx)
-{
- dma_addr_t ctx;
- uint8_t bw_ctx[xhci->numports+1];
-
- DPRINTF("xhci_get_port_bandwidth()\n");
-
- ctx = xhci_mask64(pctx);
-
- DPRINTF("xhci: bandwidth context at "DMA_ADDR_FMT"\n", ctx);
-
- /* TODO: actually implement real values here */
- bw_ctx[0] = 0;
- memset(&bw_ctx[1], 80, xhci->numports); /* 80% */
- pci_dma_write(PCI_DEVICE(xhci), ctx, bw_ctx, sizeof(bw_ctx));
-
- return CC_SUCCESS;
-}
-
-static uint32_t rotl(uint32_t v, unsigned count)
-{
- count &= 31;
- return (v << count) | (v >> (32 - count));
-}
-
-
-static uint32_t xhci_nec_challenge(uint32_t hi, uint32_t lo)
-{
- uint32_t val;
- val = rotl(lo - 0x49434878, 32 - ((hi>>8) & 0x1F));
- val += rotl(lo + 0x49434878, hi & 0x1F);
- val -= rotl(hi ^ 0x49434878, (lo >> 16) & 0x1F);
- return ~val;
-}
-
-static void xhci_via_challenge(XHCIState *xhci, uint64_t addr)
-{
- PCIDevice *pci_dev = PCI_DEVICE(xhci);
- uint32_t buf[8];
- uint32_t obuf[8];
- dma_addr_t paddr = xhci_mask64(addr);
-
- pci_dma_read(pci_dev, paddr, &buf, 32);
-
- memcpy(obuf, buf, sizeof(obuf));
-
- if ((buf[0] & 0xff) == 2) {
- obuf[0] = 0x49932000 + 0x54dc200 * buf[2] + 0x7429b578 * buf[3];
- obuf[0] |= (buf[2] * buf[3]) & 0xff;
- obuf[1] = 0x0132bb37 + 0xe89 * buf[2] + 0xf09 * buf[3];
- obuf[2] = 0x0066c2e9 + 0x2091 * buf[2] + 0x19bd * buf[3];
- obuf[3] = 0xd5281342 + 0x2cc9691 * buf[2] + 0x2367662 * buf[3];
- obuf[4] = 0x0123c75c + 0x1595 * buf[2] + 0x19ec * buf[3];
- obuf[5] = 0x00f695de + 0x26fd * buf[2] + 0x3e9 * buf[3];
- obuf[6] = obuf[2] ^ obuf[3] ^ 0x29472956;
- obuf[7] = obuf[2] ^ obuf[3] ^ 0x65866593;
- }
-
- pci_dma_write(pci_dev, paddr, &obuf, 32);
-}
-
-static void xhci_process_commands(XHCIState *xhci)
-{
- XHCITRB trb;
- TRBType type;
- XHCIEvent event = {ER_COMMAND_COMPLETE, CC_SUCCESS};
- dma_addr_t addr;
- unsigned int i, slotid = 0;
-
- DPRINTF("xhci_process_commands()\n");
- if (!xhci_running(xhci)) {
- DPRINTF("xhci_process_commands() called while xHC stopped or paused\n");
- return;
- }
-
- xhci->crcr_low |= CRCR_CRR;
-
- while ((type = xhci_ring_fetch(xhci, &xhci->cmd_ring, &trb, &addr))) {
- event.ptr = addr;
- switch (type) {
- case CR_ENABLE_SLOT:
- for (i = 0; i < xhci->numslots; i++) {
- if (!xhci->slots[i].enabled) {
- break;
- }
- }
- if (i >= xhci->numslots) {
- DPRINTF("xhci: no device slots available\n");
- event.ccode = CC_NO_SLOTS_ERROR;
- } else {
- slotid = i+1;
- event.ccode = xhci_enable_slot(xhci, slotid);
- }
- break;
- case CR_DISABLE_SLOT:
- slotid = xhci_get_slot(xhci, &event, &trb);
- if (slotid) {
- event.ccode = xhci_disable_slot(xhci, slotid);
- }
- break;
- case CR_ADDRESS_DEVICE:
- slotid = xhci_get_slot(xhci, &event, &trb);
- if (slotid) {
- event.ccode = xhci_address_slot(xhci, slotid, trb.parameter,
- trb.control & TRB_CR_BSR);
- }
- break;
- case CR_CONFIGURE_ENDPOINT:
- slotid = xhci_get_slot(xhci, &event, &trb);
- if (slotid) {
- event.ccode = xhci_configure_slot(xhci, slotid, trb.parameter,
- trb.control & TRB_CR_DC);
- }
- break;
- case CR_EVALUATE_CONTEXT:
- slotid = xhci_get_slot(xhci, &event, &trb);
- if (slotid) {
- event.ccode = xhci_evaluate_slot(xhci, slotid, trb.parameter);
- }
- break;
- case CR_STOP_ENDPOINT:
- slotid = xhci_get_slot(xhci, &event, &trb);
- if (slotid) {
- unsigned int epid = (trb.control >> TRB_CR_EPID_SHIFT)
- & TRB_CR_EPID_MASK;
- event.ccode = xhci_stop_ep(xhci, slotid, epid);
- }
- break;
- case CR_RESET_ENDPOINT:
- slotid = xhci_get_slot(xhci, &event, &trb);
- if (slotid) {
- unsigned int epid = (trb.control >> TRB_CR_EPID_SHIFT)
- & TRB_CR_EPID_MASK;
- event.ccode = xhci_reset_ep(xhci, slotid, epid);
- }
- break;
- case CR_SET_TR_DEQUEUE:
- slotid = xhci_get_slot(xhci, &event, &trb);
- if (slotid) {
- unsigned int epid = (trb.control >> TRB_CR_EPID_SHIFT)
- & TRB_CR_EPID_MASK;
- unsigned int streamid = (trb.status >> 16) & 0xffff;
- event.ccode = xhci_set_ep_dequeue(xhci, slotid,
- epid, streamid,
- trb.parameter);
- }
- break;
- case CR_RESET_DEVICE:
- slotid = xhci_get_slot(xhci, &event, &trb);
- if (slotid) {
- event.ccode = xhci_reset_slot(xhci, slotid);
- }
- break;
- case CR_GET_PORT_BANDWIDTH:
- event.ccode = xhci_get_port_bandwidth(xhci, trb.parameter);
- break;
- case CR_VENDOR_VIA_CHALLENGE_RESPONSE:
- xhci_via_challenge(xhci, trb.parameter);
- break;
- case CR_VENDOR_NEC_FIRMWARE_REVISION:
- event.type = 48; /* NEC reply */
- event.length = 0x3025;
- break;
- case CR_VENDOR_NEC_CHALLENGE_RESPONSE:
- {
- uint32_t chi = trb.parameter >> 32;
- uint32_t clo = trb.parameter;
- uint32_t val = xhci_nec_challenge(chi, clo);
- event.length = val & 0xFFFF;
- event.epid = val >> 16;
- slotid = val >> 24;
- event.type = 48; /* NEC reply */
- }
- break;
- default:
- trace_usb_xhci_unimplemented("command", type);
- event.ccode = CC_TRB_ERROR;
- break;
- }
- event.slotid = slotid;
- xhci_event(xhci, &event, 0);
- }
-}
-
-static bool xhci_port_have_device(XHCIPort *port)
-{
- if (!port->uport->dev || !port->uport->dev->attached) {
- return false; /* no device present */
- }
- if (!((1 << port->uport->dev->speed) & port->speedmask)) {
- return false; /* speed mismatch */
- }
- return true;
-}
-
-static void xhci_port_notify(XHCIPort *port, uint32_t bits)
-{
- XHCIEvent ev = { ER_PORT_STATUS_CHANGE, CC_SUCCESS,
- port->portnr << 24 };
-
- if ((port->portsc & bits) == bits) {
- return;
- }
- trace_usb_xhci_port_notify(port->portnr, bits);
- port->portsc |= bits;
- if (!xhci_running(port->xhci)) {
- return;
- }
- xhci_event(port->xhci, &ev, 0);
-}
-
-static void xhci_port_update(XHCIPort *port, int is_detach)
-{
- uint32_t pls = PLS_RX_DETECT;
-
- port->portsc = PORTSC_PP;
- if (!is_detach && xhci_port_have_device(port)) {
- port->portsc |= PORTSC_CCS;
- switch (port->uport->dev->speed) {
- case USB_SPEED_LOW:
- port->portsc |= PORTSC_SPEED_LOW;
- pls = PLS_POLLING;
- break;
- case USB_SPEED_FULL:
- port->portsc |= PORTSC_SPEED_FULL;
- pls = PLS_POLLING;
- break;
- case USB_SPEED_HIGH:
- port->portsc |= PORTSC_SPEED_HIGH;
- pls = PLS_POLLING;
- break;
- case USB_SPEED_SUPER:
- port->portsc |= PORTSC_SPEED_SUPER;
- port->portsc |= PORTSC_PED;
- pls = PLS_U0;
- break;
- }
- }
- set_field(&port->portsc, pls, PORTSC_PLS);
- trace_usb_xhci_port_link(port->portnr, pls);
- xhci_port_notify(port, PORTSC_CSC);
-}
-
-static void xhci_port_reset(XHCIPort *port, bool warm_reset)
-{
- trace_usb_xhci_port_reset(port->portnr, warm_reset);
-
- if (!xhci_port_have_device(port)) {
- return;
- }
-
- usb_device_reset(port->uport->dev);
-
- switch (port->uport->dev->speed) {
- case USB_SPEED_SUPER:
- if (warm_reset) {
- port->portsc |= PORTSC_WRC;
- }
- /* fall through */
- case USB_SPEED_LOW:
- case USB_SPEED_FULL:
- case USB_SPEED_HIGH:
- set_field(&port->portsc, PLS_U0, PORTSC_PLS);
- trace_usb_xhci_port_link(port->portnr, PLS_U0);
- port->portsc |= PORTSC_PED;
- break;
- }
-
- port->portsc &= ~PORTSC_PR;
- xhci_port_notify(port, PORTSC_PRC);
-}
-
-static void xhci_reset(DeviceState *dev)
-{
- XHCIState *xhci = XHCI(dev);
- int i;
-
- trace_usb_xhci_reset();
- if (!(xhci->usbsts & USBSTS_HCH)) {
- DPRINTF("xhci: reset while running!\n");
- }
-
- xhci->usbcmd = 0;
- xhci->usbsts = USBSTS_HCH;
- xhci->dnctrl = 0;
- xhci->crcr_low = 0;
- xhci->crcr_high = 0;
- xhci->dcbaap_low = 0;
- xhci->dcbaap_high = 0;
- xhci->config = 0;
-
- for (i = 0; i < xhci->numslots; i++) {
- xhci_disable_slot(xhci, i+1);
- }
-
- for (i = 0; i < xhci->numports; i++) {
- xhci_port_update(xhci->ports + i, 0);
- }
-
- for (i = 0; i < xhci->numintrs; i++) {
- xhci->intr[i].iman = 0;
- xhci->intr[i].imod = 0;
- xhci->intr[i].erstsz = 0;
- xhci->intr[i].erstba_low = 0;
- xhci->intr[i].erstba_high = 0;
- xhci->intr[i].erdp_low = 0;
- xhci->intr[i].erdp_high = 0;
- xhci->intr[i].msix_used = 0;
-
- xhci->intr[i].er_ep_idx = 0;
- xhci->intr[i].er_pcs = 1;
- xhci->intr[i].er_full = 0;
- xhci->intr[i].ev_buffer_put = 0;
- xhci->intr[i].ev_buffer_get = 0;
- }
-
- xhci->mfindex_start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- xhci_mfwrap_update(xhci);
-}
-
-static uint64_t xhci_cap_read(void *ptr, hwaddr reg, unsigned size)
-{
- XHCIState *xhci = ptr;
- uint32_t ret;
-
- switch (reg) {
- case 0x00: /* HCIVERSION, CAPLENGTH */
- ret = 0x01000000 | LEN_CAP;
- break;
- case 0x04: /* HCSPARAMS 1 */
- ret = ((xhci->numports_2+xhci->numports_3)<<24)
- | (xhci->numintrs<<8) | xhci->numslots;
- break;
- case 0x08: /* HCSPARAMS 2 */
- ret = 0x0000000f;
- break;
- case 0x0c: /* HCSPARAMS 3 */
- ret = 0x00000000;
- break;
- case 0x10: /* HCCPARAMS */
- if (sizeof(dma_addr_t) == 4) {
- ret = 0x00080000 | (xhci->max_pstreams_mask << 12);
- } else {
- ret = 0x00080001 | (xhci->max_pstreams_mask << 12);
- }
- break;
- case 0x14: /* DBOFF */
- ret = OFF_DOORBELL;
- break;
- case 0x18: /* RTSOFF */
- ret = OFF_RUNTIME;
- break;
-
- /* extended capabilities */
- case 0x20: /* Supported Protocol:00 */
- ret = 0x02000402; /* USB 2.0 */
- break;
- case 0x24: /* Supported Protocol:04 */
- ret = 0x20425355; /* "USB " */
- break;
- case 0x28: /* Supported Protocol:08 */
- if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) {
- ret = (xhci->numports_2<<8) | (xhci->numports_3+1);
- } else {
- ret = (xhci->numports_2<<8) | 1;
- }
- break;
- case 0x2c: /* Supported Protocol:0c */
- ret = 0x00000000; /* reserved */
- break;
- case 0x30: /* Supported Protocol:00 */
- ret = 0x03000002; /* USB 3.0 */
- break;
- case 0x34: /* Supported Protocol:04 */
- ret = 0x20425355; /* "USB " */
- break;
- case 0x38: /* Supported Protocol:08 */
- if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) {
- ret = (xhci->numports_3<<8) | 1;
- } else {
- ret = (xhci->numports_3<<8) | (xhci->numports_2+1);
- }
- break;
- case 0x3c: /* Supported Protocol:0c */
- ret = 0x00000000; /* reserved */
- break;
- default:
- trace_usb_xhci_unimplemented("cap read", reg);
- ret = 0;
- }
-
- trace_usb_xhci_cap_read(reg, ret);
- return ret;
-}
-
-static uint64_t xhci_port_read(void *ptr, hwaddr reg, unsigned size)
-{
- XHCIPort *port = ptr;
- uint32_t ret;
-
- switch (reg) {
- case 0x00: /* PORTSC */
- ret = port->portsc;
- break;
- case 0x04: /* PORTPMSC */
- case 0x08: /* PORTLI */
- ret = 0;
- break;
- case 0x0c: /* reserved */
- default:
- trace_usb_xhci_unimplemented("port read", reg);
- ret = 0;
- }
-
- trace_usb_xhci_port_read(port->portnr, reg, ret);
- return ret;
-}
-
-static void xhci_port_write(void *ptr, hwaddr reg,
- uint64_t val, unsigned size)
-{
- XHCIPort *port = ptr;
- uint32_t portsc, notify;
-
- trace_usb_xhci_port_write(port->portnr, reg, val);
-
- switch (reg) {
- case 0x00: /* PORTSC */
- /* write-1-to-start bits */
- if (val & PORTSC_WPR) {
- xhci_port_reset(port, true);
- break;
- }
- if (val & PORTSC_PR) {
- xhci_port_reset(port, false);
- break;
- }
-
- portsc = port->portsc;
- notify = 0;
- /* write-1-to-clear bits*/
- portsc &= ~(val & (PORTSC_CSC|PORTSC_PEC|PORTSC_WRC|PORTSC_OCC|
- PORTSC_PRC|PORTSC_PLC|PORTSC_CEC));
- if (val & PORTSC_LWS) {
- /* overwrite PLS only when LWS=1 */
- uint32_t old_pls = get_field(port->portsc, PORTSC_PLS);
- uint32_t new_pls = get_field(val, PORTSC_PLS);
- switch (new_pls) {
- case PLS_U0:
- if (old_pls != PLS_U0) {
- set_field(&portsc, new_pls, PORTSC_PLS);
- trace_usb_xhci_port_link(port->portnr, new_pls);
- notify = PORTSC_PLC;
- }
- break;
- case PLS_U3:
- if (old_pls < PLS_U3) {
- set_field(&portsc, new_pls, PORTSC_PLS);
- trace_usb_xhci_port_link(port->portnr, new_pls);
- }
- break;
- case PLS_RESUME:
- /* windows does this for some reason, don't spam stderr */
- break;
- default:
- DPRINTF("%s: ignore pls write (old %d, new %d)\n",
- __func__, old_pls, new_pls);
- break;
- }
- }
- /* read/write bits */
- portsc &= ~(PORTSC_PP|PORTSC_WCE|PORTSC_WDE|PORTSC_WOE);
- portsc |= (val & (PORTSC_PP|PORTSC_WCE|PORTSC_WDE|PORTSC_WOE));
- port->portsc = portsc;
- if (notify) {
- xhci_port_notify(port, notify);
- }
- break;
- case 0x04: /* PORTPMSC */
- case 0x08: /* PORTLI */
- default:
- trace_usb_xhci_unimplemented("port write", reg);
- }
-}
-
-static uint64_t xhci_oper_read(void *ptr, hwaddr reg, unsigned size)
-{
- XHCIState *xhci = ptr;
- uint32_t ret;
-
- switch (reg) {
- case 0x00: /* USBCMD */
- ret = xhci->usbcmd;
- break;
- case 0x04: /* USBSTS */
- ret = xhci->usbsts;
- break;
- case 0x08: /* PAGESIZE */
- ret = 1; /* 4KiB */
- break;
- case 0x14: /* DNCTRL */
- ret = xhci->dnctrl;
- break;
- case 0x18: /* CRCR low */
- ret = xhci->crcr_low & ~0xe;
- break;
- case 0x1c: /* CRCR high */
- ret = xhci->crcr_high;
- break;
- case 0x30: /* DCBAAP low */
- ret = xhci->dcbaap_low;
- break;
- case 0x34: /* DCBAAP high */
- ret = xhci->dcbaap_high;
- break;
- case 0x38: /* CONFIG */
- ret = xhci->config;
- break;
- default:
- trace_usb_xhci_unimplemented("oper read", reg);
- ret = 0;
- }
-
- trace_usb_xhci_oper_read(reg, ret);
- return ret;
-}
-
-static void xhci_oper_write(void *ptr, hwaddr reg,
- uint64_t val, unsigned size)
-{
- XHCIState *xhci = ptr;
- DeviceState *d = DEVICE(ptr);
-
- trace_usb_xhci_oper_write(reg, val);
-
- switch (reg) {
- case 0x00: /* USBCMD */
- if ((val & USBCMD_RS) && !(xhci->usbcmd & USBCMD_RS)) {
- xhci_run(xhci);
- } else if (!(val & USBCMD_RS) && (xhci->usbcmd & USBCMD_RS)) {
- xhci_stop(xhci);
- }
- if (val & USBCMD_CSS) {
- /* save state */
- xhci->usbsts &= ~USBSTS_SRE;
- }
- if (val & USBCMD_CRS) {
- /* restore state */
- xhci->usbsts |= USBSTS_SRE;
- }
- xhci->usbcmd = val & 0xc0f;
- xhci_mfwrap_update(xhci);
- if (val & USBCMD_HCRST) {
- xhci_reset(d);
- }
- xhci_intx_update(xhci);
- break;
-
- case 0x04: /* USBSTS */
- /* these bits are write-1-to-clear */
- xhci->usbsts &= ~(val & (USBSTS_HSE|USBSTS_EINT|USBSTS_PCD|USBSTS_SRE));
- xhci_intx_update(xhci);
- break;
-
- case 0x14: /* DNCTRL */
- xhci->dnctrl = val & 0xffff;
- break;
- case 0x18: /* CRCR low */
- xhci->crcr_low = (val & 0xffffffcf) | (xhci->crcr_low & CRCR_CRR);
- break;
- case 0x1c: /* CRCR high */
- xhci->crcr_high = val;
- if (xhci->crcr_low & (CRCR_CA|CRCR_CS) && (xhci->crcr_low & CRCR_CRR)) {
- XHCIEvent event = {ER_COMMAND_COMPLETE, CC_COMMAND_RING_STOPPED};
- xhci->crcr_low &= ~CRCR_CRR;
- xhci_event(xhci, &event, 0);
- DPRINTF("xhci: command ring stopped (CRCR=%08x)\n", xhci->crcr_low);
- } else {
- dma_addr_t base = xhci_addr64(xhci->crcr_low & ~0x3f, val);
- xhci_ring_init(xhci, &xhci->cmd_ring, base);
- }
- xhci->crcr_low &= ~(CRCR_CA | CRCR_CS);
- break;
- case 0x30: /* DCBAAP low */
- xhci->dcbaap_low = val & 0xffffffc0;
- break;
- case 0x34: /* DCBAAP high */
- xhci->dcbaap_high = val;
- break;
- case 0x38: /* CONFIG */
- xhci->config = val & 0xff;
- break;
- default:
- trace_usb_xhci_unimplemented("oper write", reg);
- }
-}
-
-static uint64_t xhci_runtime_read(void *ptr, hwaddr reg,
- unsigned size)
-{
- XHCIState *xhci = ptr;
- uint32_t ret = 0;
-
- if (reg < 0x20) {
- switch (reg) {
- case 0x00: /* MFINDEX */
- ret = xhci_mfindex_get(xhci) & 0x3fff;
- break;
- default:
- trace_usb_xhci_unimplemented("runtime read", reg);
- break;
- }
- } else {
- int v = (reg - 0x20) / 0x20;
- XHCIInterrupter *intr = &xhci->intr[v];
- switch (reg & 0x1f) {
- case 0x00: /* IMAN */
- ret = intr->iman;
- break;
- case 0x04: /* IMOD */
- ret = intr->imod;
- break;
- case 0x08: /* ERSTSZ */
- ret = intr->erstsz;
- break;
- case 0x10: /* ERSTBA low */
- ret = intr->erstba_low;
- break;
- case 0x14: /* ERSTBA high */
- ret = intr->erstba_high;
- break;
- case 0x18: /* ERDP low */
- ret = intr->erdp_low;
- break;
- case 0x1c: /* ERDP high */
- ret = intr->erdp_high;
- break;
- }
- }
-
- trace_usb_xhci_runtime_read(reg, ret);
- return ret;
-}
-
-static void xhci_runtime_write(void *ptr, hwaddr reg,
- uint64_t val, unsigned size)
-{
- XHCIState *xhci = ptr;
- int v = (reg - 0x20) / 0x20;
- XHCIInterrupter *intr = &xhci->intr[v];
- trace_usb_xhci_runtime_write(reg, val);
-
- if (reg < 0x20) {
- trace_usb_xhci_unimplemented("runtime write", reg);
- return;
- }
-
- switch (reg & 0x1f) {
- case 0x00: /* IMAN */
- if (val & IMAN_IP) {
- intr->iman &= ~IMAN_IP;
- }
- intr->iman &= ~IMAN_IE;
- intr->iman |= val & IMAN_IE;
- if (v == 0) {
- xhci_intx_update(xhci);
- }
- xhci_msix_update(xhci, v);
- break;
- case 0x04: /* IMOD */
- intr->imod = val;
- break;
- case 0x08: /* ERSTSZ */
- intr->erstsz = val & 0xffff;
- break;
- case 0x10: /* ERSTBA low */
- /* XXX NEC driver bug: it doesn't align this to 64 bytes
- intr->erstba_low = val & 0xffffffc0; */
- intr->erstba_low = val & 0xfffffff0;
- break;
- case 0x14: /* ERSTBA high */
- intr->erstba_high = val;
- xhci_er_reset(xhci, v);
- break;
- case 0x18: /* ERDP low */
- if (val & ERDP_EHB) {
- intr->erdp_low &= ~ERDP_EHB;
- }
- intr->erdp_low = (val & ~ERDP_EHB) | (intr->erdp_low & ERDP_EHB);
- break;
- case 0x1c: /* ERDP high */
- intr->erdp_high = val;
- xhci_events_update(xhci, v);
- break;
- default:
- trace_usb_xhci_unimplemented("oper write", reg);
- }
-}
-
-static uint64_t xhci_doorbell_read(void *ptr, hwaddr reg,
- unsigned size)
-{
- /* doorbells always read as 0 */
- trace_usb_xhci_doorbell_read(reg, 0);
- return 0;
-}
-
-static void xhci_doorbell_write(void *ptr, hwaddr reg,
- uint64_t val, unsigned size)
-{
- XHCIState *xhci = ptr;
- unsigned int epid, streamid;
-
- trace_usb_xhci_doorbell_write(reg, val);
-
- if (!xhci_running(xhci)) {
- DPRINTF("xhci: wrote doorbell while xHC stopped or paused\n");
- return;
- }
-
- reg >>= 2;
-
- if (reg == 0) {
- if (val == 0) {
- xhci_process_commands(xhci);
- } else {
- DPRINTF("xhci: bad doorbell 0 write: 0x%x\n",
- (uint32_t)val);
- }
- } else {
- epid = val & 0xff;
- streamid = (val >> 16) & 0xffff;
- if (reg > xhci->numslots) {
- DPRINTF("xhci: bad doorbell %d\n", (int)reg);
- } else if (epid > 31) {
- DPRINTF("xhci: bad doorbell %d write: 0x%x\n",
- (int)reg, (uint32_t)val);
- } else {
- xhci_kick_ep(xhci, reg, epid, streamid);
- }
- }
-}
-
-static void xhci_cap_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned width)
-{
- /* nothing */
-}
-
-static const MemoryRegionOps xhci_cap_ops = {
- .read = xhci_cap_read,
- .write = xhci_cap_write,
- .valid.min_access_size = 1,
- .valid.max_access_size = 4,
- .impl.min_access_size = 4,
- .impl.max_access_size = 4,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static const MemoryRegionOps xhci_oper_ops = {
- .read = xhci_oper_read,
- .write = xhci_oper_write,
- .valid.min_access_size = 4,
- .valid.max_access_size = 4,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static const MemoryRegionOps xhci_port_ops = {
- .read = xhci_port_read,
- .write = xhci_port_write,
- .valid.min_access_size = 4,
- .valid.max_access_size = 4,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static const MemoryRegionOps xhci_runtime_ops = {
- .read = xhci_runtime_read,
- .write = xhci_runtime_write,
- .valid.min_access_size = 4,
- .valid.max_access_size = 4,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static const MemoryRegionOps xhci_doorbell_ops = {
- .read = xhci_doorbell_read,
- .write = xhci_doorbell_write,
- .valid.min_access_size = 4,
- .valid.max_access_size = 4,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void xhci_attach(USBPort *usbport)
-{
- XHCIState *xhci = usbport->opaque;
- XHCIPort *port = xhci_lookup_port(xhci, usbport);
-
- xhci_port_update(port, 0);
-}
-
-static void xhci_detach(USBPort *usbport)
-{
- XHCIState *xhci = usbport->opaque;
- XHCIPort *port = xhci_lookup_port(xhci, usbport);
-
- xhci_detach_slot(xhci, usbport);
- xhci_port_update(port, 1);
-}
-
-static void xhci_wakeup(USBPort *usbport)
-{
- XHCIState *xhci = usbport->opaque;
- XHCIPort *port = xhci_lookup_port(xhci, usbport);
-
- if (get_field(port->portsc, PORTSC_PLS) != PLS_U3) {
- return;
- }
- set_field(&port->portsc, PLS_RESUME, PORTSC_PLS);
- xhci_port_notify(port, PORTSC_PLC);
-}
-
-static void xhci_complete(USBPort *port, USBPacket *packet)
-{
- XHCITransfer *xfer = container_of(packet, XHCITransfer, packet);
-
- if (packet->status == USB_RET_REMOVE_FROM_QUEUE) {
- xhci_ep_nuke_one_xfer(xfer, 0);
- return;
- }
- xhci_complete_packet(xfer);
- xhci_kick_ep(xfer->xhci, xfer->slotid, xfer->epid, xfer->streamid);
-}
-
-static void xhci_child_detach(USBPort *uport, USBDevice *child)
-{
- USBBus *bus = usb_bus_from_device(child);
- XHCIState *xhci = container_of(bus, XHCIState, bus);
-
- xhci_detach_slot(xhci, child->port);
-}
-
-static USBPortOps xhci_uport_ops = {
- .attach = xhci_attach,
- .detach = xhci_detach,
- .wakeup = xhci_wakeup,
- .complete = xhci_complete,
- .child_detach = xhci_child_detach,
-};
-
-static int xhci_find_epid(USBEndpoint *ep)
-{
- if (ep->nr == 0) {
- return 1;
- }
- if (ep->pid == USB_TOKEN_IN) {
- return ep->nr * 2 + 1;
- } else {
- return ep->nr * 2;
- }
-}
-
-static USBEndpoint *xhci_epid_to_usbep(XHCIState *xhci,
- unsigned int slotid, unsigned int epid)
-{
- assert(slotid >= 1 && slotid <= xhci->numslots);
-
- if (!xhci->slots[slotid - 1].uport) {
- return NULL;
- }
-
- return usb_ep_get(xhci->slots[slotid - 1].uport->dev,
- (epid & 1) ? USB_TOKEN_IN : USB_TOKEN_OUT, epid >> 1);
-}
-
-static void xhci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep,
- unsigned int stream)
-{
- XHCIState *xhci = container_of(bus, XHCIState, bus);
- int slotid;
-
- DPRINTF("%s\n", __func__);
- slotid = ep->dev->addr;
- if (slotid == 0 || !xhci->slots[slotid-1].enabled) {
- DPRINTF("%s: oops, no slot for dev %d\n", __func__, ep->dev->addr);
- return;
- }
- xhci_kick_ep(xhci, slotid, xhci_find_epid(ep), stream);
-}
-
-static USBBusOps xhci_bus_ops = {
- .wakeup_endpoint = xhci_wakeup_endpoint,
-};
-
-static void usb_xhci_init(XHCIState *xhci)
-{
- DeviceState *dev = DEVICE(xhci);
- XHCIPort *port;
- int i, usbports, speedmask;
-
- xhci->usbsts = USBSTS_HCH;
-
- if (xhci->numports_2 > MAXPORTS_2) {
- xhci->numports_2 = MAXPORTS_2;
- }
- if (xhci->numports_3 > MAXPORTS_3) {
- xhci->numports_3 = MAXPORTS_3;
- }
- usbports = MAX(xhci->numports_2, xhci->numports_3);
- xhci->numports = xhci->numports_2 + xhci->numports_3;
-
- usb_bus_new(&xhci->bus, sizeof(xhci->bus), &xhci_bus_ops, dev);
-
- for (i = 0; i < usbports; i++) {
- speedmask = 0;
- if (i < xhci->numports_2) {
- if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) {
- port = &xhci->ports[i + xhci->numports_3];
- port->portnr = i + 1 + xhci->numports_3;
- } else {
- port = &xhci->ports[i];
- port->portnr = i + 1;
- }
- port->uport = &xhci->uports[i];
- port->speedmask =
- USB_SPEED_MASK_LOW |
- USB_SPEED_MASK_FULL |
- USB_SPEED_MASK_HIGH;
- snprintf(port->name, sizeof(port->name), "usb2 port #%d", i+1);
- speedmask |= port->speedmask;
- }
- if (i < xhci->numports_3) {
- if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) {
- port = &xhci->ports[i];
- port->portnr = i + 1;
- } else {
- port = &xhci->ports[i + xhci->numports_2];
- port->portnr = i + 1 + xhci->numports_2;
- }
- port->uport = &xhci->uports[i];
- port->speedmask = USB_SPEED_MASK_SUPER;
- snprintf(port->name, sizeof(port->name), "usb3 port #%d", i+1);
- speedmask |= port->speedmask;
- }
- usb_register_port(&xhci->bus, &xhci->uports[i], xhci, i,
- &xhci_uport_ops, speedmask);
- }
-}
-
-static void usb_xhci_realize(struct PCIDevice *dev, Error **errp)
-{
- int i, ret;
-
- XHCIState *xhci = XHCI(dev);
-
- dev->config[PCI_CLASS_PROG] = 0x30; /* xHCI */
- dev->config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin 1 */
- dev->config[PCI_CACHE_LINE_SIZE] = 0x10;
- dev->config[0x60] = 0x30; /* release number */
-
- usb_xhci_init(xhci);
-
- if (xhci->numintrs > MAXINTRS) {
- xhci->numintrs = MAXINTRS;
- }
- while (xhci->numintrs & (xhci->numintrs - 1)) { /* ! power of 2 */
- xhci->numintrs++;
- }
- if (xhci->numintrs < 1) {
- xhci->numintrs = 1;
- }
- if (xhci->numslots > MAXSLOTS) {
- xhci->numslots = MAXSLOTS;
- }
- if (xhci->numslots < 1) {
- xhci->numslots = 1;
- }
- if (xhci_get_flag(xhci, XHCI_FLAG_ENABLE_STREAMS)) {
- xhci->max_pstreams_mask = 7; /* == 256 primary streams */
- } else {
- xhci->max_pstreams_mask = 0;
- }
-
- xhci->mfwrap_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, xhci_mfwrap_timer, xhci);
-
- memory_region_init(&xhci->mem, OBJECT(xhci), "xhci", LEN_REGS);
- memory_region_init_io(&xhci->mem_cap, OBJECT(xhci), &xhci_cap_ops, xhci,
- "capabilities", LEN_CAP);
- memory_region_init_io(&xhci->mem_oper, OBJECT(xhci), &xhci_oper_ops, xhci,
- "operational", 0x400);
- memory_region_init_io(&xhci->mem_runtime, OBJECT(xhci), &xhci_runtime_ops, xhci,
- "runtime", LEN_RUNTIME);
- memory_region_init_io(&xhci->mem_doorbell, OBJECT(xhci), &xhci_doorbell_ops, xhci,
- "doorbell", LEN_DOORBELL);
-
- memory_region_add_subregion(&xhci->mem, 0, &xhci->mem_cap);
- memory_region_add_subregion(&xhci->mem, OFF_OPER, &xhci->mem_oper);
- memory_region_add_subregion(&xhci->mem, OFF_RUNTIME, &xhci->mem_runtime);
- memory_region_add_subregion(&xhci->mem, OFF_DOORBELL, &xhci->mem_doorbell);
-
- for (i = 0; i < xhci->numports; i++) {
- XHCIPort *port = &xhci->ports[i];
- uint32_t offset = OFF_OPER + 0x400 + 0x10 * i;
- port->xhci = xhci;
- memory_region_init_io(&port->mem, OBJECT(xhci), &xhci_port_ops, port,
- port->name, 0x10);
- memory_region_add_subregion(&xhci->mem, offset, &port->mem);
- }
-
- pci_register_bar(dev, 0,
- PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64,
- &xhci->mem);
-
- if (pci_bus_is_express(dev->bus) ||
- xhci_get_flag(xhci, XHCI_FLAG_FORCE_PCIE_ENDCAP)) {
- ret = pcie_endpoint_cap_init(dev, 0xa0);
- assert(ret >= 0);
- }
-
- if (xhci_get_flag(xhci, XHCI_FLAG_USE_MSI)) {
- msi_init(dev, 0x70, xhci->numintrs, true, false);
- }
- if (xhci_get_flag(xhci, XHCI_FLAG_USE_MSI_X)) {
- msix_init(dev, xhci->numintrs,
- &xhci->mem, 0, OFF_MSIX_TABLE,
- &xhci->mem, 0, OFF_MSIX_PBA,
- 0x90);
- }
-}
-
-static void usb_xhci_exit(PCIDevice *dev)
-{
- int i;
- XHCIState *xhci = XHCI(dev);
-
- trace_usb_xhci_exit();
-
- for (i = 0; i < xhci->numslots; i++) {
- xhci_disable_slot(xhci, i + 1);
- }
-
- if (xhci->mfwrap_timer) {
- timer_del(xhci->mfwrap_timer);
- timer_free(xhci->mfwrap_timer);
- xhci->mfwrap_timer = NULL;
- }
-
- memory_region_del_subregion(&xhci->mem, &xhci->mem_cap);
- memory_region_del_subregion(&xhci->mem, &xhci->mem_oper);
- memory_region_del_subregion(&xhci->mem, &xhci->mem_runtime);
- memory_region_del_subregion(&xhci->mem, &xhci->mem_doorbell);
-
- for (i = 0; i < xhci->numports; i++) {
- XHCIPort *port = &xhci->ports[i];
- memory_region_del_subregion(&xhci->mem, &port->mem);
- }
-
- /* destroy msix memory region */
- if (dev->msix_table && dev->msix_pba
- && dev->msix_entry_used) {
- memory_region_del_subregion(&xhci->mem, &dev->msix_table_mmio);
- memory_region_del_subregion(&xhci->mem, &dev->msix_pba_mmio);
- }
-
- usb_bus_release(&xhci->bus);
-}
-
-static int usb_xhci_post_load(void *opaque, int version_id)
-{
- XHCIState *xhci = opaque;
- PCIDevice *pci_dev = PCI_DEVICE(xhci);
- XHCISlot *slot;
- XHCIEPContext *epctx;
- dma_addr_t dcbaap, pctx;
- uint32_t slot_ctx[4];
- uint32_t ep_ctx[5];
- int slotid, epid, state, intr;
-
- dcbaap = xhci_addr64(xhci->dcbaap_low, xhci->dcbaap_high);
-
- for (slotid = 1; slotid <= xhci->numslots; slotid++) {
- slot = &xhci->slots[slotid-1];
- if (!slot->addressed) {
- continue;
- }
- slot->ctx =
- xhci_mask64(ldq_le_pci_dma(pci_dev, dcbaap + 8 * slotid));
- xhci_dma_read_u32s(xhci, slot->ctx, slot_ctx, sizeof(slot_ctx));
- slot->uport = xhci_lookup_uport(xhci, slot_ctx);
- if (!slot->uport) {
- /* should not happen, but may trigger on guest bugs */
- slot->enabled = 0;
- slot->addressed = 0;
- continue;
- }
- assert(slot->uport && slot->uport->dev);
-
- for (epid = 1; epid <= 31; epid++) {
- pctx = slot->ctx + 32 * epid;
- xhci_dma_read_u32s(xhci, pctx, ep_ctx, sizeof(ep_ctx));
- state = ep_ctx[0] & EP_STATE_MASK;
- if (state == EP_DISABLED) {
- continue;
- }
- epctx = xhci_alloc_epctx(xhci, slotid, epid);
- slot->eps[epid-1] = epctx;
- xhci_init_epctx(epctx, pctx, ep_ctx);
- epctx->state = state;
- if (state == EP_RUNNING) {
- /* kick endpoint after vmload is finished */
- timer_mod(epctx->kick_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
- }
- }
- }
-
- for (intr = 0; intr < xhci->numintrs; intr++) {
- if (xhci->intr[intr].msix_used) {
- msix_vector_use(pci_dev, intr);
- } else {
- msix_vector_unuse(pci_dev, intr);
- }
- }
-
- return 0;
-}
-
-static const VMStateDescription vmstate_xhci_ring = {
- .name = "xhci-ring",
- .version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT64(dequeue, XHCIRing),
- VMSTATE_BOOL(ccs, XHCIRing),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_xhci_port = {
- .name = "xhci-port",
- .version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(portsc, XHCIPort),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_xhci_slot = {
- .name = "xhci-slot",
- .version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_BOOL(enabled, XHCISlot),
- VMSTATE_BOOL(addressed, XHCISlot),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_xhci_event = {
- .name = "xhci-event",
- .version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(type, XHCIEvent),
- VMSTATE_UINT32(ccode, XHCIEvent),
- VMSTATE_UINT64(ptr, XHCIEvent),
- VMSTATE_UINT32(length, XHCIEvent),
- VMSTATE_UINT32(flags, XHCIEvent),
- VMSTATE_UINT8(slotid, XHCIEvent),
- VMSTATE_UINT8(epid, XHCIEvent),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static bool xhci_er_full(void *opaque, int version_id)
-{
- struct XHCIInterrupter *intr = opaque;
- return intr->er_full;
-}
-
-static const VMStateDescription vmstate_xhci_intr = {
- .name = "xhci-intr",
- .version_id = 1,
- .fields = (VMStateField[]) {
- /* registers */
- VMSTATE_UINT32(iman, XHCIInterrupter),
- VMSTATE_UINT32(imod, XHCIInterrupter),
- VMSTATE_UINT32(erstsz, XHCIInterrupter),
- VMSTATE_UINT32(erstba_low, XHCIInterrupter),
- VMSTATE_UINT32(erstba_high, XHCIInterrupter),
- VMSTATE_UINT32(erdp_low, XHCIInterrupter),
- VMSTATE_UINT32(erdp_high, XHCIInterrupter),
-
- /* state */
- VMSTATE_BOOL(msix_used, XHCIInterrupter),
- VMSTATE_BOOL(er_pcs, XHCIInterrupter),
- VMSTATE_UINT64(er_start, XHCIInterrupter),
- VMSTATE_UINT32(er_size, XHCIInterrupter),
- VMSTATE_UINT32(er_ep_idx, XHCIInterrupter),
-
- /* event queue (used if ring is full) */
- VMSTATE_BOOL(er_full, XHCIInterrupter),
- VMSTATE_UINT32_TEST(ev_buffer_put, XHCIInterrupter, xhci_er_full),
- VMSTATE_UINT32_TEST(ev_buffer_get, XHCIInterrupter, xhci_er_full),
- VMSTATE_STRUCT_ARRAY_TEST(ev_buffer, XHCIInterrupter, EV_QUEUE,
- xhci_er_full, 1,
- vmstate_xhci_event, XHCIEvent),
-
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_xhci = {
- .name = "xhci",
- .version_id = 1,
- .post_load = usb_xhci_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_PCIE_DEVICE(parent_obj, XHCIState),
- VMSTATE_MSIX(parent_obj, XHCIState),
-
- VMSTATE_STRUCT_VARRAY_UINT32(ports, XHCIState, numports, 1,
- vmstate_xhci_port, XHCIPort),
- VMSTATE_STRUCT_VARRAY_UINT32(slots, XHCIState, numslots, 1,
- vmstate_xhci_slot, XHCISlot),
- VMSTATE_STRUCT_VARRAY_UINT32(intr, XHCIState, numintrs, 1,
- vmstate_xhci_intr, XHCIInterrupter),
-
- /* Operational Registers */
- VMSTATE_UINT32(usbcmd, XHCIState),
- VMSTATE_UINT32(usbsts, XHCIState),
- VMSTATE_UINT32(dnctrl, XHCIState),
- VMSTATE_UINT32(crcr_low, XHCIState),
- VMSTATE_UINT32(crcr_high, XHCIState),
- VMSTATE_UINT32(dcbaap_low, XHCIState),
- VMSTATE_UINT32(dcbaap_high, XHCIState),
- VMSTATE_UINT32(config, XHCIState),
-
- /* Runtime Registers & state */
- VMSTATE_INT64(mfindex_start, XHCIState),
- VMSTATE_TIMER_PTR(mfwrap_timer, XHCIState),
- VMSTATE_STRUCT(cmd_ring, XHCIState, 1, vmstate_xhci_ring, XHCIRing),
-
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property xhci_properties[] = {
- DEFINE_PROP_BIT("msi", XHCIState, flags, XHCI_FLAG_USE_MSI, true),
- DEFINE_PROP_BIT("msix", XHCIState, flags, XHCI_FLAG_USE_MSI_X, true),
- DEFINE_PROP_BIT("superspeed-ports-first",
- XHCIState, flags, XHCI_FLAG_SS_FIRST, true),
- DEFINE_PROP_BIT("force-pcie-endcap", XHCIState, flags,
- XHCI_FLAG_FORCE_PCIE_ENDCAP, false),
- DEFINE_PROP_BIT("streams", XHCIState, flags,
- XHCI_FLAG_ENABLE_STREAMS, true),
- DEFINE_PROP_UINT32("intrs", XHCIState, numintrs, MAXINTRS),
- DEFINE_PROP_UINT32("slots", XHCIState, numslots, MAXSLOTS),
- DEFINE_PROP_UINT32("p2", XHCIState, numports_2, 4),
- DEFINE_PROP_UINT32("p3", XHCIState, numports_3, 4),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void xhci_class_init(ObjectClass *klass, void *data)
-{
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->vmsd = &vmstate_xhci;
- dc->props = xhci_properties;
- dc->reset = xhci_reset;
- set_bit(DEVICE_CATEGORY_USB, dc->categories);
- k->realize = usb_xhci_realize;
- k->exit = usb_xhci_exit;
- k->vendor_id = PCI_VENDOR_ID_NEC;
- k->device_id = PCI_DEVICE_ID_NEC_UPD720200;
- k->class_id = PCI_CLASS_SERIAL_USB;
- k->revision = 0x03;
- k->is_express = 1;
-}
-
-static const TypeInfo xhci_info = {
- .name = TYPE_XHCI,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(XHCIState),
- .class_init = xhci_class_init,
-};
-
-static void xhci_register_types(void)
-{
- type_register_static(&xhci_info);
-}
-
-type_init(xhci_register_types)
diff --git a/qemu/hw/usb/host-legacy.c b/qemu/hw/usb/host-legacy.c
deleted file mode 100644
index 3b57e21b5..000000000
--- a/qemu/hw/usb/host-legacy.c
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Linux host USB redirector
- *
- * Copyright (c) 2005 Fabrice Bellard
- *
- * Copyright (c) 2008 Max Krasnyansky
- * Support for host device auto connect & disconnect
- * Major rewrite to support fully async operation
- *
- * Copyright 2008 TJ <linux@tjworld.net>
- * Added flexible support for /dev/bus/usb /sys/bus/usb/devices in addition
- * to the legacy /proc/bus/usb USB device discovery and handling
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "hw/usb.h"
-#include "hw/usb/host.h"
-
-/*
- * Autoconnect filter
- * Format:
- * auto:bus:dev[:vid:pid]
- * auto:bus.dev[:vid:pid]
- *
- * bus - bus number (dec, * means any)
- * dev - device number (dec, * means any)
- * vid - vendor id (hex, * means any)
- * pid - product id (hex, * means any)
- *
- * See 'lsusb' output.
- */
-static int parse_filter(const char *spec, struct USBAutoFilter *f)
-{
- enum { BUS, DEV, VID, PID, DONE };
- const char *p = spec;
- int i;
-
- f->bus_num = 0;
- f->addr = 0;
- f->vendor_id = 0;
- f->product_id = 0;
-
- for (i = BUS; i < DONE; i++) {
- p = strpbrk(p, ":.");
- if (!p) {
- break;
- }
- p++;
-
- if (*p == '*') {
- continue;
- }
- switch (i) {
- case BUS:
- f->bus_num = strtol(p, NULL, 10);
- break;
- case DEV:
- f->addr = strtol(p, NULL, 10);
- break;
- case VID:
- f->vendor_id = strtol(p, NULL, 16);
- break;
- case PID:
- f->product_id = strtol(p, NULL, 16);
- break;
- }
- }
-
- if (i < DEV) {
- fprintf(stderr, "husb: invalid auto filter spec %s\n", spec);
- return -1;
- }
-
- return 0;
-}
-
-USBDevice *usb_host_device_open(USBBus *bus, const char *devname)
-{
- struct USBAutoFilter filter;
- USBDevice *dev;
- char *p;
-
- dev = usb_create(bus, "usb-host");
-
- if (strstr(devname, "auto:")) {
- if (parse_filter(devname, &filter) < 0) {
- goto fail;
- }
- } else {
- p = strchr(devname, '.');
- if (p) {
- filter.bus_num = strtoul(devname, NULL, 0);
- filter.addr = strtoul(p + 1, NULL, 0);
- filter.vendor_id = 0;
- filter.product_id = 0;
- } else {
- p = strchr(devname, ':');
- if (p) {
- filter.bus_num = 0;
- filter.addr = 0;
- filter.vendor_id = strtoul(devname, NULL, 16);
- filter.product_id = strtoul(p + 1, NULL, 16);
- } else {
- goto fail;
- }
- }
- }
-
- qdev_prop_set_uint32(&dev->qdev, "hostbus", filter.bus_num);
- qdev_prop_set_uint32(&dev->qdev, "hostaddr", filter.addr);
- qdev_prop_set_uint32(&dev->qdev, "vendorid", filter.vendor_id);
- qdev_prop_set_uint32(&dev->qdev, "productid", filter.product_id);
- return dev;
-
-fail:
- object_unparent(OBJECT(dev));
- return NULL;
-}
-
-static void usb_host_register_types(void)
-{
- usb_legacy_register("usb-host", "host", usb_host_device_open);
-}
-
-type_init(usb_host_register_types)
diff --git a/qemu/hw/usb/host-libusb.c b/qemu/hw/usb/host-libusb.c
deleted file mode 100644
index 6458a9448..000000000
--- a/qemu/hw/usb/host-libusb.c
+++ /dev/null
@@ -1,1688 +0,0 @@
-/*
- * Linux host USB redirector
- *
- * Copyright (c) 2005 Fabrice Bellard
- *
- * Copyright (c) 2008 Max Krasnyansky
- * Support for host device auto connect & disconnect
- * Major rewrite to support fully async operation
- *
- * Copyright 2008 TJ <linux@tjworld.net>
- * Added flexible support for /dev/bus/usb /sys/bus/usb/devices in addition
- * to the legacy /proc/bus/usb USB device discovery and handling
- *
- * (c) 2012 Gerd Hoffmann <kraxel@redhat.com>
- * Completely rewritten to use libusb instead of usbfs ioctls.
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include <poll.h>
-#include <libusb.h>
-
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "monitor/monitor.h"
-#include "qemu/error-report.h"
-#include "sysemu/sysemu.h"
-#include "trace.h"
-
-#include "hw/usb.h"
-
-/* ------------------------------------------------------------------------ */
-
-#define TYPE_USB_HOST_DEVICE "usb-host"
-#define USB_HOST_DEVICE(obj) \
- OBJECT_CHECK(USBHostDevice, (obj), TYPE_USB_HOST_DEVICE)
-
-typedef struct USBHostDevice USBHostDevice;
-typedef struct USBHostRequest USBHostRequest;
-typedef struct USBHostIsoXfer USBHostIsoXfer;
-typedef struct USBHostIsoRing USBHostIsoRing;
-
-struct USBAutoFilter {
- uint32_t bus_num;
- uint32_t addr;
- char *port;
- uint32_t vendor_id;
- uint32_t product_id;
-};
-
-enum USBHostDeviceOptions {
- USB_HOST_OPT_PIPELINE,
-};
-
-struct USBHostDevice {
- USBDevice parent_obj;
-
- /* properties */
- struct USBAutoFilter match;
- int32_t bootindex;
- uint32_t iso_urb_count;
- uint32_t iso_urb_frames;
- uint32_t options;
- uint32_t loglevel;
-
- /* state */
- QTAILQ_ENTRY(USBHostDevice) next;
- int seen, errcount;
- int bus_num;
- int addr;
- char port[16];
-
- libusb_device *dev;
- libusb_device_handle *dh;
- struct libusb_device_descriptor ddesc;
-
- struct {
- bool detached;
- bool claimed;
- } ifs[USB_MAX_INTERFACES];
-
- /* callbacks & friends */
- QEMUBH *bh_nodev;
- QEMUBH *bh_postld;
- Notifier exit;
-
- /* request queues */
- QTAILQ_HEAD(, USBHostRequest) requests;
- QTAILQ_HEAD(, USBHostIsoRing) isorings;
-};
-
-struct USBHostRequest {
- USBHostDevice *host;
- USBPacket *p;
- bool in;
- struct libusb_transfer *xfer;
- unsigned char *buffer;
- unsigned char *cbuf;
- unsigned int clen;
- bool usb3ep0quirk;
- QTAILQ_ENTRY(USBHostRequest) next;
-};
-
-struct USBHostIsoXfer {
- USBHostIsoRing *ring;
- struct libusb_transfer *xfer;
- bool copy_complete;
- unsigned int packet;
- QTAILQ_ENTRY(USBHostIsoXfer) next;
-};
-
-struct USBHostIsoRing {
- USBHostDevice *host;
- USBEndpoint *ep;
- QTAILQ_HEAD(, USBHostIsoXfer) unused;
- QTAILQ_HEAD(, USBHostIsoXfer) inflight;
- QTAILQ_HEAD(, USBHostIsoXfer) copy;
- QTAILQ_ENTRY(USBHostIsoRing) next;
-};
-
-static QTAILQ_HEAD(, USBHostDevice) hostdevs =
- QTAILQ_HEAD_INITIALIZER(hostdevs);
-
-static void usb_host_auto_check(void *unused);
-static void usb_host_release_interfaces(USBHostDevice *s);
-static void usb_host_nodev(USBHostDevice *s);
-static void usb_host_detach_kernel(USBHostDevice *s);
-static void usb_host_attach_kernel(USBHostDevice *s);
-
-/* ------------------------------------------------------------------------ */
-
-#ifndef LIBUSB_LOG_LEVEL_WARNING /* older libusb didn't define these */
-#define LIBUSB_LOG_LEVEL_WARNING 2
-#endif
-
-/* ------------------------------------------------------------------------ */
-
-#define CONTROL_TIMEOUT 10000 /* 10 sec */
-#define BULK_TIMEOUT 0 /* unlimited */
-#define INTR_TIMEOUT 0 /* unlimited */
-
-#if LIBUSBX_API_VERSION >= 0x01000103
-# define HAVE_STREAMS 1
-#endif
-
-static const char *speed_name[] = {
- [LIBUSB_SPEED_UNKNOWN] = "?",
- [LIBUSB_SPEED_LOW] = "1.5",
- [LIBUSB_SPEED_FULL] = "12",
- [LIBUSB_SPEED_HIGH] = "480",
- [LIBUSB_SPEED_SUPER] = "5000",
-};
-
-static const unsigned int speed_map[] = {
- [LIBUSB_SPEED_LOW] = USB_SPEED_LOW,
- [LIBUSB_SPEED_FULL] = USB_SPEED_FULL,
- [LIBUSB_SPEED_HIGH] = USB_SPEED_HIGH,
- [LIBUSB_SPEED_SUPER] = USB_SPEED_SUPER,
-};
-
-static const unsigned int status_map[] = {
- [LIBUSB_TRANSFER_COMPLETED] = USB_RET_SUCCESS,
- [LIBUSB_TRANSFER_ERROR] = USB_RET_IOERROR,
- [LIBUSB_TRANSFER_TIMED_OUT] = USB_RET_IOERROR,
- [LIBUSB_TRANSFER_CANCELLED] = USB_RET_IOERROR,
- [LIBUSB_TRANSFER_STALL] = USB_RET_STALL,
- [LIBUSB_TRANSFER_NO_DEVICE] = USB_RET_NODEV,
- [LIBUSB_TRANSFER_OVERFLOW] = USB_RET_BABBLE,
-};
-
-static const char *err_names[] = {
- [-LIBUSB_ERROR_IO] = "IO",
- [-LIBUSB_ERROR_INVALID_PARAM] = "INVALID_PARAM",
- [-LIBUSB_ERROR_ACCESS] = "ACCESS",
- [-LIBUSB_ERROR_NO_DEVICE] = "NO_DEVICE",
- [-LIBUSB_ERROR_NOT_FOUND] = "NOT_FOUND",
- [-LIBUSB_ERROR_BUSY] = "BUSY",
- [-LIBUSB_ERROR_TIMEOUT] = "TIMEOUT",
- [-LIBUSB_ERROR_OVERFLOW] = "OVERFLOW",
- [-LIBUSB_ERROR_PIPE] = "PIPE",
- [-LIBUSB_ERROR_INTERRUPTED] = "INTERRUPTED",
- [-LIBUSB_ERROR_NO_MEM] = "NO_MEM",
- [-LIBUSB_ERROR_NOT_SUPPORTED] = "NOT_SUPPORTED",
- [-LIBUSB_ERROR_OTHER] = "OTHER",
-};
-
-static libusb_context *ctx;
-static uint32_t loglevel;
-
-static void usb_host_handle_fd(void *opaque)
-{
- struct timeval tv = { 0, 0 };
- libusb_handle_events_timeout(ctx, &tv);
-}
-
-static void usb_host_add_fd(int fd, short events, void *user_data)
-{
- qemu_set_fd_handler(fd,
- (events & POLLIN) ? usb_host_handle_fd : NULL,
- (events & POLLOUT) ? usb_host_handle_fd : NULL,
- ctx);
-}
-
-static void usb_host_del_fd(int fd, void *user_data)
-{
- qemu_set_fd_handler(fd, NULL, NULL, NULL);
-}
-
-static int usb_host_init(void)
-{
- const struct libusb_pollfd **poll;
- int i, rc;
-
- if (ctx) {
- return 0;
- }
- rc = libusb_init(&ctx);
- if (rc != 0) {
- return -1;
- }
- libusb_set_debug(ctx, loglevel);
-
- libusb_set_pollfd_notifiers(ctx, usb_host_add_fd,
- usb_host_del_fd,
- ctx);
- poll = libusb_get_pollfds(ctx);
- if (poll) {
- for (i = 0; poll[i] != NULL; i++) {
- usb_host_add_fd(poll[i]->fd, poll[i]->events, ctx);
- }
- }
- free(poll);
- return 0;
-}
-
-static int usb_host_get_port(libusb_device *dev, char *port, size_t len)
-{
- uint8_t path[7];
- size_t off;
- int rc, i;
-
-#if LIBUSBX_API_VERSION >= 0x01000102
- rc = libusb_get_port_numbers(dev, path, 7);
-#else
- rc = libusb_get_port_path(ctx, dev, path, 7);
-#endif
- if (rc < 0) {
- return 0;
- }
- off = snprintf(port, len, "%d", path[0]);
- for (i = 1; i < rc; i++) {
- off += snprintf(port+off, len-off, ".%d", path[i]);
- }
- return off;
-}
-
-static void usb_host_libusb_error(const char *func, int rc)
-{
- const char *errname;
-
- if (rc >= 0) {
- return;
- }
-
- if (-rc < ARRAY_SIZE(err_names) && err_names[-rc]) {
- errname = err_names[-rc];
- } else {
- errname = "?";
- }
- error_report("%s: %d [%s]", func, rc, errname);
-}
-
-/* ------------------------------------------------------------------------ */
-
-static bool usb_host_use_combining(USBEndpoint *ep)
-{
- int type;
-
- if (!ep->pipeline) {
- return false;
- }
- if (ep->pid != USB_TOKEN_IN) {
- return false;
- }
- type = usb_ep_get_type(ep->dev, ep->pid, ep->nr);
- if (type != USB_ENDPOINT_XFER_BULK) {
- return false;
- }
- return true;
-}
-
-/* ------------------------------------------------------------------------ */
-
-static USBHostRequest *usb_host_req_alloc(USBHostDevice *s, USBPacket *p,
- bool in, size_t bufsize)
-{
- USBHostRequest *r = g_new0(USBHostRequest, 1);
-
- r->host = s;
- r->p = p;
- r->in = in;
- r->xfer = libusb_alloc_transfer(0);
- if (bufsize) {
- r->buffer = g_malloc(bufsize);
- }
- QTAILQ_INSERT_TAIL(&s->requests, r, next);
- return r;
-}
-
-static void usb_host_req_free(USBHostRequest *r)
-{
- if (r->host) {
- QTAILQ_REMOVE(&r->host->requests, r, next);
- }
- libusb_free_transfer(r->xfer);
- g_free(r->buffer);
- g_free(r);
-}
-
-static USBHostRequest *usb_host_req_find(USBHostDevice *s, USBPacket *p)
-{
- USBHostRequest *r;
-
- QTAILQ_FOREACH(r, &s->requests, next) {
- if (r->p == p) {
- return r;
- }
- }
- return NULL;
-}
-
-static void usb_host_req_complete_ctrl(struct libusb_transfer *xfer)
-{
- USBHostRequest *r = xfer->user_data;
- USBHostDevice *s = r->host;
- bool disconnect = (xfer->status == LIBUSB_TRANSFER_NO_DEVICE);
-
- if (r->p == NULL) {
- goto out; /* request was canceled */
- }
-
- r->p->status = status_map[xfer->status];
- r->p->actual_length = xfer->actual_length;
- if (r->in && xfer->actual_length) {
- memcpy(r->cbuf, r->buffer + 8, xfer->actual_length);
-
- /* Fix up USB-3 ep0 maxpacket size to allow superspeed connected devices
- * to work redirected to a not superspeed capable hcd */
- if (r->usb3ep0quirk && xfer->actual_length >= 18 &&
- r->cbuf[7] == 9) {
- r->cbuf[7] = 64;
- }
- }
- trace_usb_host_req_complete(s->bus_num, s->addr, r->p,
- r->p->status, r->p->actual_length);
- usb_generic_async_ctrl_complete(USB_DEVICE(s), r->p);
-
-out:
- usb_host_req_free(r);
- if (disconnect) {
- usb_host_nodev(s);
- }
-}
-
-static void usb_host_req_complete_data(struct libusb_transfer *xfer)
-{
- USBHostRequest *r = xfer->user_data;
- USBHostDevice *s = r->host;
- bool disconnect = (xfer->status == LIBUSB_TRANSFER_NO_DEVICE);
-
- if (r->p == NULL) {
- goto out; /* request was canceled */
- }
-
- r->p->status = status_map[xfer->status];
- if (r->in && xfer->actual_length) {
- usb_packet_copy(r->p, r->buffer, xfer->actual_length);
- }
- trace_usb_host_req_complete(s->bus_num, s->addr, r->p,
- r->p->status, r->p->actual_length);
- if (usb_host_use_combining(r->p->ep)) {
- usb_combined_input_packet_complete(USB_DEVICE(s), r->p);
- } else {
- usb_packet_complete(USB_DEVICE(s), r->p);
- }
-
-out:
- usb_host_req_free(r);
- if (disconnect) {
- usb_host_nodev(s);
- }
-}
-
-static void usb_host_req_abort(USBHostRequest *r)
-{
- USBHostDevice *s = r->host;
- bool inflight = (r->p && r->p->state == USB_PACKET_ASYNC);
-
- if (inflight) {
- r->p->status = USB_RET_NODEV;
- trace_usb_host_req_complete(s->bus_num, s->addr, r->p,
- r->p->status, r->p->actual_length);
- if (r->p->ep->nr == 0) {
- usb_generic_async_ctrl_complete(USB_DEVICE(s), r->p);
- } else {
- usb_packet_complete(USB_DEVICE(s), r->p);
- }
- r->p = NULL;
- }
-
- QTAILQ_REMOVE(&r->host->requests, r, next);
- r->host = NULL;
-
- if (inflight) {
- libusb_cancel_transfer(r->xfer);
- }
-}
-
-/* ------------------------------------------------------------------------ */
-
-static void usb_host_req_complete_iso(struct libusb_transfer *transfer)
-{
- USBHostIsoXfer *xfer = transfer->user_data;
-
- if (!xfer) {
- /* USBHostIsoXfer released while inflight */
- g_free(transfer->buffer);
- libusb_free_transfer(transfer);
- return;
- }
-
- QTAILQ_REMOVE(&xfer->ring->inflight, xfer, next);
- if (QTAILQ_EMPTY(&xfer->ring->inflight)) {
- USBHostDevice *s = xfer->ring->host;
- trace_usb_host_iso_stop(s->bus_num, s->addr, xfer->ring->ep->nr);
- }
- if (xfer->ring->ep->pid == USB_TOKEN_IN) {
- QTAILQ_INSERT_TAIL(&xfer->ring->copy, xfer, next);
- usb_wakeup(xfer->ring->ep, 0);
- } else {
- QTAILQ_INSERT_TAIL(&xfer->ring->unused, xfer, next);
- }
-}
-
-static USBHostIsoRing *usb_host_iso_alloc(USBHostDevice *s, USBEndpoint *ep)
-{
- USBHostIsoRing *ring = g_new0(USBHostIsoRing, 1);
- USBHostIsoXfer *xfer;
- /* FIXME: check interval (for now assume one xfer per frame) */
- int packets = s->iso_urb_frames;
- int i;
-
- ring->host = s;
- ring->ep = ep;
- QTAILQ_INIT(&ring->unused);
- QTAILQ_INIT(&ring->inflight);
- QTAILQ_INIT(&ring->copy);
- QTAILQ_INSERT_TAIL(&s->isorings, ring, next);
-
- for (i = 0; i < s->iso_urb_count; i++) {
- xfer = g_new0(USBHostIsoXfer, 1);
- xfer->ring = ring;
- xfer->xfer = libusb_alloc_transfer(packets);
- xfer->xfer->dev_handle = s->dh;
- xfer->xfer->type = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS;
-
- xfer->xfer->endpoint = ring->ep->nr;
- if (ring->ep->pid == USB_TOKEN_IN) {
- xfer->xfer->endpoint |= USB_DIR_IN;
- }
- xfer->xfer->callback = usb_host_req_complete_iso;
- xfer->xfer->user_data = xfer;
-
- xfer->xfer->num_iso_packets = packets;
- xfer->xfer->length = ring->ep->max_packet_size * packets;
- xfer->xfer->buffer = g_malloc0(xfer->xfer->length);
-
- QTAILQ_INSERT_TAIL(&ring->unused, xfer, next);
- }
-
- return ring;
-}
-
-static USBHostIsoRing *usb_host_iso_find(USBHostDevice *s, USBEndpoint *ep)
-{
- USBHostIsoRing *ring;
-
- QTAILQ_FOREACH(ring, &s->isorings, next) {
- if (ring->ep == ep) {
- return ring;
- }
- }
- return NULL;
-}
-
-static void usb_host_iso_reset_xfer(USBHostIsoXfer *xfer)
-{
- libusb_set_iso_packet_lengths(xfer->xfer,
- xfer->ring->ep->max_packet_size);
- xfer->packet = 0;
- xfer->copy_complete = false;
-}
-
-static void usb_host_iso_free_xfer(USBHostIsoXfer *xfer, bool inflight)
-{
- if (inflight) {
- xfer->xfer->user_data = NULL;
- } else {
- g_free(xfer->xfer->buffer);
- libusb_free_transfer(xfer->xfer);
- }
- g_free(xfer);
-}
-
-static void usb_host_iso_free(USBHostIsoRing *ring)
-{
- USBHostIsoXfer *xfer;
-
- while ((xfer = QTAILQ_FIRST(&ring->inflight)) != NULL) {
- QTAILQ_REMOVE(&ring->inflight, xfer, next);
- usb_host_iso_free_xfer(xfer, true);
- }
- while ((xfer = QTAILQ_FIRST(&ring->unused)) != NULL) {
- QTAILQ_REMOVE(&ring->unused, xfer, next);
- usb_host_iso_free_xfer(xfer, false);
- }
- while ((xfer = QTAILQ_FIRST(&ring->copy)) != NULL) {
- QTAILQ_REMOVE(&ring->copy, xfer, next);
- usb_host_iso_free_xfer(xfer, false);
- }
-
- QTAILQ_REMOVE(&ring->host->isorings, ring, next);
- g_free(ring);
-}
-
-static void usb_host_iso_free_all(USBHostDevice *s)
-{
- USBHostIsoRing *ring;
-
- while ((ring = QTAILQ_FIRST(&s->isorings)) != NULL) {
- usb_host_iso_free(ring);
- }
-}
-
-static bool usb_host_iso_data_copy(USBHostIsoXfer *xfer, USBPacket *p)
-{
- unsigned int psize;
- unsigned char *buf;
-
- buf = libusb_get_iso_packet_buffer_simple(xfer->xfer, xfer->packet);
- if (p->pid == USB_TOKEN_OUT) {
- psize = p->iov.size;
- if (psize > xfer->ring->ep->max_packet_size) {
- /* should not happen (guest bug) */
- psize = xfer->ring->ep->max_packet_size;
- }
- xfer->xfer->iso_packet_desc[xfer->packet].length = psize;
- } else {
- psize = xfer->xfer->iso_packet_desc[xfer->packet].actual_length;
- if (psize > p->iov.size) {
- /* should not happen (guest bug) */
- psize = p->iov.size;
- }
- }
- usb_packet_copy(p, buf, psize);
- xfer->packet++;
- xfer->copy_complete = (xfer->packet == xfer->xfer->num_iso_packets);
- return xfer->copy_complete;
-}
-
-static void usb_host_iso_data_in(USBHostDevice *s, USBPacket *p)
-{
- USBHostIsoRing *ring;
- USBHostIsoXfer *xfer;
- bool disconnect = false;
- int rc;
-
- ring = usb_host_iso_find(s, p->ep);
- if (ring == NULL) {
- ring = usb_host_iso_alloc(s, p->ep);
- }
-
- /* copy data to guest */
- xfer = QTAILQ_FIRST(&ring->copy);
- if (xfer != NULL) {
- if (usb_host_iso_data_copy(xfer, p)) {
- QTAILQ_REMOVE(&ring->copy, xfer, next);
- QTAILQ_INSERT_TAIL(&ring->unused, xfer, next);
- }
- }
-
- /* submit empty bufs to host */
- while ((xfer = QTAILQ_FIRST(&ring->unused)) != NULL) {
- QTAILQ_REMOVE(&ring->unused, xfer, next);
- usb_host_iso_reset_xfer(xfer);
- rc = libusb_submit_transfer(xfer->xfer);
- if (rc != 0) {
- usb_host_libusb_error("libusb_submit_transfer [iso]", rc);
- QTAILQ_INSERT_TAIL(&ring->unused, xfer, next);
- if (rc == LIBUSB_ERROR_NO_DEVICE) {
- disconnect = true;
- }
- break;
- }
- if (QTAILQ_EMPTY(&ring->inflight)) {
- trace_usb_host_iso_start(s->bus_num, s->addr, p->ep->nr);
- }
- QTAILQ_INSERT_TAIL(&ring->inflight, xfer, next);
- }
-
- if (disconnect) {
- usb_host_nodev(s);
- }
-}
-
-static void usb_host_iso_data_out(USBHostDevice *s, USBPacket *p)
-{
- USBHostIsoRing *ring;
- USBHostIsoXfer *xfer;
- bool disconnect = false;
- int rc, filled = 0;
-
- ring = usb_host_iso_find(s, p->ep);
- if (ring == NULL) {
- ring = usb_host_iso_alloc(s, p->ep);
- }
-
- /* copy data from guest */
- xfer = QTAILQ_FIRST(&ring->copy);
- while (xfer != NULL && xfer->copy_complete) {
- filled++;
- xfer = QTAILQ_NEXT(xfer, next);
- }
- if (xfer == NULL) {
- xfer = QTAILQ_FIRST(&ring->unused);
- if (xfer == NULL) {
- trace_usb_host_iso_out_of_bufs(s->bus_num, s->addr, p->ep->nr);
- return;
- }
- QTAILQ_REMOVE(&ring->unused, xfer, next);
- usb_host_iso_reset_xfer(xfer);
- QTAILQ_INSERT_TAIL(&ring->copy, xfer, next);
- }
- usb_host_iso_data_copy(xfer, p);
-
- if (QTAILQ_EMPTY(&ring->inflight)) {
- /* wait until half of our buffers are filled
- before kicking the iso out stream */
- if (filled*2 < s->iso_urb_count) {
- return;
- }
- }
-
- /* submit filled bufs to host */
- while ((xfer = QTAILQ_FIRST(&ring->copy)) != NULL &&
- xfer->copy_complete) {
- QTAILQ_REMOVE(&ring->copy, xfer, next);
- rc = libusb_submit_transfer(xfer->xfer);
- if (rc != 0) {
- usb_host_libusb_error("libusb_submit_transfer [iso]", rc);
- QTAILQ_INSERT_TAIL(&ring->unused, xfer, next);
- if (rc == LIBUSB_ERROR_NO_DEVICE) {
- disconnect = true;
- }
- break;
- }
- if (QTAILQ_EMPTY(&ring->inflight)) {
- trace_usb_host_iso_start(s->bus_num, s->addr, p->ep->nr);
- }
- QTAILQ_INSERT_TAIL(&ring->inflight, xfer, next);
- }
-
- if (disconnect) {
- usb_host_nodev(s);
- }
-}
-
-/* ------------------------------------------------------------------------ */
-
-static void usb_host_speed_compat(USBHostDevice *s)
-{
- USBDevice *udev = USB_DEVICE(s);
- struct libusb_config_descriptor *conf;
- const struct libusb_interface_descriptor *intf;
- const struct libusb_endpoint_descriptor *endp;
-#ifdef HAVE_STREAMS
- struct libusb_ss_endpoint_companion_descriptor *endp_ss_comp;
-#endif
- bool compat_high = true;
- bool compat_full = true;
- uint8_t type;
- int rc, c, i, a, e;
-
- for (c = 0;; c++) {
- rc = libusb_get_config_descriptor(s->dev, c, &conf);
- if (rc != 0) {
- break;
- }
- for (i = 0; i < conf->bNumInterfaces; i++) {
- for (a = 0; a < conf->interface[i].num_altsetting; a++) {
- intf = &conf->interface[i].altsetting[a];
- for (e = 0; e < intf->bNumEndpoints; e++) {
- endp = &intf->endpoint[e];
- type = endp->bmAttributes & 0x3;
- switch (type) {
- case 0x01: /* ISO */
- compat_full = false;
- compat_high = false;
- break;
- case 0x02: /* BULK */
-#ifdef HAVE_STREAMS
- rc = libusb_get_ss_endpoint_companion_descriptor
- (ctx, endp, &endp_ss_comp);
- if (rc == LIBUSB_SUCCESS) {
- libusb_free_ss_endpoint_companion_descriptor
- (endp_ss_comp);
- compat_full = false;
- compat_high = false;
- }
-#endif
- break;
- case 0x03: /* INTERRUPT */
- if (endp->wMaxPacketSize > 64) {
- compat_full = false;
- }
- if (endp->wMaxPacketSize > 1024) {
- compat_high = false;
- }
- break;
- }
- }
- }
- }
- libusb_free_config_descriptor(conf);
- }
-
- udev->speedmask = (1 << udev->speed);
- if (udev->speed == USB_SPEED_SUPER && compat_high) {
- udev->speedmask |= USB_SPEED_MASK_HIGH;
- }
- if (udev->speed == USB_SPEED_SUPER && compat_full) {
- udev->speedmask |= USB_SPEED_MASK_FULL;
- }
- if (udev->speed == USB_SPEED_HIGH && compat_full) {
- udev->speedmask |= USB_SPEED_MASK_FULL;
- }
-}
-
-static void usb_host_ep_update(USBHostDevice *s)
-{
- static const char *tname[] = {
- [USB_ENDPOINT_XFER_CONTROL] = "control",
- [USB_ENDPOINT_XFER_ISOC] = "isoc",
- [USB_ENDPOINT_XFER_BULK] = "bulk",
- [USB_ENDPOINT_XFER_INT] = "int",
- };
- USBDevice *udev = USB_DEVICE(s);
- struct libusb_config_descriptor *conf;
- const struct libusb_interface_descriptor *intf;
- const struct libusb_endpoint_descriptor *endp;
-#ifdef HAVE_STREAMS
- struct libusb_ss_endpoint_companion_descriptor *endp_ss_comp;
-#endif
- uint8_t devep, type;
- int pid, ep;
- int rc, i, e;
-
- usb_ep_reset(udev);
- rc = libusb_get_active_config_descriptor(s->dev, &conf);
- if (rc != 0) {
- return;
- }
- trace_usb_host_parse_config(s->bus_num, s->addr,
- conf->bConfigurationValue, true);
-
- for (i = 0; i < conf->bNumInterfaces; i++) {
- assert(udev->altsetting[i] < conf->interface[i].num_altsetting);
- intf = &conf->interface[i].altsetting[udev->altsetting[i]];
- trace_usb_host_parse_interface(s->bus_num, s->addr,
- intf->bInterfaceNumber,
- intf->bAlternateSetting, true);
- for (e = 0; e < intf->bNumEndpoints; e++) {
- endp = &intf->endpoint[e];
-
- devep = endp->bEndpointAddress;
- pid = (devep & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT;
- ep = devep & 0xf;
- type = endp->bmAttributes & 0x3;
-
- if (ep == 0) {
- trace_usb_host_parse_error(s->bus_num, s->addr,
- "invalid endpoint address");
- return;
- }
- if (usb_ep_get_type(udev, pid, ep) != USB_ENDPOINT_XFER_INVALID) {
- trace_usb_host_parse_error(s->bus_num, s->addr,
- "duplicate endpoint address");
- return;
- }
-
- trace_usb_host_parse_endpoint(s->bus_num, s->addr, ep,
- (devep & USB_DIR_IN) ? "in" : "out",
- tname[type], true);
- usb_ep_set_max_packet_size(udev, pid, ep,
- endp->wMaxPacketSize);
- usb_ep_set_type(udev, pid, ep, type);
- usb_ep_set_ifnum(udev, pid, ep, i);
- usb_ep_set_halted(udev, pid, ep, 0);
-#ifdef HAVE_STREAMS
- if (type == LIBUSB_TRANSFER_TYPE_BULK &&
- libusb_get_ss_endpoint_companion_descriptor(ctx, endp,
- &endp_ss_comp) == LIBUSB_SUCCESS) {
- usb_ep_set_max_streams(udev, pid, ep,
- endp_ss_comp->bmAttributes);
- libusb_free_ss_endpoint_companion_descriptor(endp_ss_comp);
- }
-#endif
- }
- }
-
- libusb_free_config_descriptor(conf);
-}
-
-static int usb_host_open(USBHostDevice *s, libusb_device *dev)
-{
- USBDevice *udev = USB_DEVICE(s);
- int bus_num = libusb_get_bus_number(dev);
- int addr = libusb_get_device_address(dev);
- int rc;
- Error *local_err = NULL;
-
- trace_usb_host_open_started(bus_num, addr);
-
- if (s->dh != NULL) {
- goto fail;
- }
- rc = libusb_open(dev, &s->dh);
- if (rc != 0) {
- goto fail;
- }
-
- s->dev = dev;
- s->bus_num = bus_num;
- s->addr = addr;
-
- usb_host_detach_kernel(s);
-
- libusb_get_device_descriptor(dev, &s->ddesc);
- usb_host_get_port(s->dev, s->port, sizeof(s->port));
-
- usb_ep_init(udev);
- usb_host_ep_update(s);
-
- udev->speed = speed_map[libusb_get_device_speed(dev)];
- usb_host_speed_compat(s);
-
- if (s->ddesc.iProduct) {
- libusb_get_string_descriptor_ascii(s->dh, s->ddesc.iProduct,
- (unsigned char *)udev->product_desc,
- sizeof(udev->product_desc));
- } else {
- snprintf(udev->product_desc, sizeof(udev->product_desc),
- "host:%d.%d", bus_num, addr);
- }
-
- usb_device_attach(udev, &local_err);
- if (local_err) {
- error_report_err(local_err);
- goto fail;
- }
-
- trace_usb_host_open_success(bus_num, addr);
- return 0;
-
-fail:
- trace_usb_host_open_failure(bus_num, addr);
- if (s->dh != NULL) {
- usb_host_release_interfaces(s);
- libusb_reset_device(s->dh);
- usb_host_attach_kernel(s);
- libusb_close(s->dh);
- s->dh = NULL;
- s->dev = NULL;
- }
- return -1;
-}
-
-static void usb_host_abort_xfers(USBHostDevice *s)
-{
- USBHostRequest *r, *rtmp;
-
- QTAILQ_FOREACH_SAFE(r, &s->requests, next, rtmp) {
- usb_host_req_abort(r);
- }
-}
-
-static int usb_host_close(USBHostDevice *s)
-{
- USBDevice *udev = USB_DEVICE(s);
-
- if (s->dh == NULL) {
- return -1;
- }
-
- trace_usb_host_close(s->bus_num, s->addr);
-
- usb_host_abort_xfers(s);
- usb_host_iso_free_all(s);
-
- if (udev->attached) {
- usb_device_detach(udev);
- }
-
- usb_host_release_interfaces(s);
- libusb_reset_device(s->dh);
- usb_host_attach_kernel(s);
- libusb_close(s->dh);
- s->dh = NULL;
- s->dev = NULL;
-
- usb_host_auto_check(NULL);
- return 0;
-}
-
-static void usb_host_nodev_bh(void *opaque)
-{
- USBHostDevice *s = opaque;
- usb_host_close(s);
-}
-
-static void usb_host_nodev(USBHostDevice *s)
-{
- if (!s->bh_nodev) {
- s->bh_nodev = qemu_bh_new(usb_host_nodev_bh, s);
- }
- qemu_bh_schedule(s->bh_nodev);
-}
-
-static void usb_host_exit_notifier(struct Notifier *n, void *data)
-{
- USBHostDevice *s = container_of(n, USBHostDevice, exit);
-
- if (s->dh) {
- usb_host_release_interfaces(s);
- usb_host_attach_kernel(s);
- }
-}
-
-static void usb_host_realize(USBDevice *udev, Error **errp)
-{
- USBHostDevice *s = USB_HOST_DEVICE(udev);
-
- if (s->match.vendor_id > 0xffff) {
- error_setg(errp, "vendorid out of range");
- return;
- }
- if (s->match.product_id > 0xffff) {
- error_setg(errp, "productid out of range");
- return;
- }
- if (s->match.addr > 127) {
- error_setg(errp, "hostaddr out of range");
- return;
- }
-
- loglevel = s->loglevel;
- udev->flags |= (1 << USB_DEV_FLAG_IS_HOST);
- udev->auto_attach = 0;
- QTAILQ_INIT(&s->requests);
- QTAILQ_INIT(&s->isorings);
-
- s->exit.notify = usb_host_exit_notifier;
- qemu_add_exit_notifier(&s->exit);
-
- QTAILQ_INSERT_TAIL(&hostdevs, s, next);
- usb_host_auto_check(NULL);
-}
-
-static void usb_host_instance_init(Object *obj)
-{
- USBDevice *udev = USB_DEVICE(obj);
- USBHostDevice *s = USB_HOST_DEVICE(udev);
-
- device_add_bootindex_property(obj, &s->bootindex,
- "bootindex", NULL,
- &udev->qdev, NULL);
-}
-
-static void usb_host_handle_destroy(USBDevice *udev)
-{
- USBHostDevice *s = USB_HOST_DEVICE(udev);
-
- qemu_remove_exit_notifier(&s->exit);
- QTAILQ_REMOVE(&hostdevs, s, next);
- usb_host_close(s);
-}
-
-static void usb_host_cancel_packet(USBDevice *udev, USBPacket *p)
-{
- USBHostDevice *s = USB_HOST_DEVICE(udev);
- USBHostRequest *r;
-
- if (p->combined) {
- usb_combined_packet_cancel(udev, p);
- return;
- }
-
- trace_usb_host_req_canceled(s->bus_num, s->addr, p);
-
- r = usb_host_req_find(s, p);
- if (r && r->p) {
- r->p = NULL; /* mark as dead */
- libusb_cancel_transfer(r->xfer);
- }
-}
-
-static void usb_host_detach_kernel(USBHostDevice *s)
-{
- struct libusb_config_descriptor *conf;
- int rc, i;
-
- rc = libusb_get_active_config_descriptor(s->dev, &conf);
- if (rc != 0) {
- return;
- }
- for (i = 0; i < conf->bNumInterfaces; i++) {
- rc = libusb_kernel_driver_active(s->dh, i);
- usb_host_libusb_error("libusb_kernel_driver_active", rc);
- if (rc != 1) {
- continue;
- }
- trace_usb_host_detach_kernel(s->bus_num, s->addr, i);
- rc = libusb_detach_kernel_driver(s->dh, i);
- usb_host_libusb_error("libusb_detach_kernel_driver", rc);
- s->ifs[i].detached = true;
- }
- libusb_free_config_descriptor(conf);
-}
-
-static void usb_host_attach_kernel(USBHostDevice *s)
-{
- struct libusb_config_descriptor *conf;
- int rc, i;
-
- rc = libusb_get_active_config_descriptor(s->dev, &conf);
- if (rc != 0) {
- return;
- }
- for (i = 0; i < conf->bNumInterfaces; i++) {
- if (!s->ifs[i].detached) {
- continue;
- }
- trace_usb_host_attach_kernel(s->bus_num, s->addr, i);
- libusb_attach_kernel_driver(s->dh, i);
- s->ifs[i].detached = false;
- }
- libusb_free_config_descriptor(conf);
-}
-
-static int usb_host_claim_interfaces(USBHostDevice *s, int configuration)
-{
- USBDevice *udev = USB_DEVICE(s);
- struct libusb_config_descriptor *conf;
- int rc, i;
-
- for (i = 0; i < USB_MAX_INTERFACES; i++) {
- udev->altsetting[i] = 0;
- }
- udev->ninterfaces = 0;
- udev->configuration = 0;
-
- usb_host_detach_kernel(s);
-
- rc = libusb_get_active_config_descriptor(s->dev, &conf);
- if (rc != 0) {
- if (rc == LIBUSB_ERROR_NOT_FOUND) {
- /* address state - ignore */
- return USB_RET_SUCCESS;
- }
- return USB_RET_STALL;
- }
-
- for (i = 0; i < conf->bNumInterfaces; i++) {
- trace_usb_host_claim_interface(s->bus_num, s->addr, configuration, i);
- rc = libusb_claim_interface(s->dh, i);
- usb_host_libusb_error("libusb_claim_interface", rc);
- if (rc != 0) {
- return USB_RET_STALL;
- }
- s->ifs[i].claimed = true;
- }
-
- udev->ninterfaces = conf->bNumInterfaces;
- udev->configuration = configuration;
-
- libusb_free_config_descriptor(conf);
- return USB_RET_SUCCESS;
-}
-
-static void usb_host_release_interfaces(USBHostDevice *s)
-{
- USBDevice *udev = USB_DEVICE(s);
- int i, rc;
-
- for (i = 0; i < udev->ninterfaces; i++) {
- if (!s->ifs[i].claimed) {
- continue;
- }
- trace_usb_host_release_interface(s->bus_num, s->addr, i);
- rc = libusb_release_interface(s->dh, i);
- usb_host_libusb_error("libusb_release_interface", rc);
- s->ifs[i].claimed = false;
- }
-}
-
-static void usb_host_set_address(USBHostDevice *s, int addr)
-{
- USBDevice *udev = USB_DEVICE(s);
-
- trace_usb_host_set_address(s->bus_num, s->addr, addr);
- udev->addr = addr;
-}
-
-static void usb_host_set_config(USBHostDevice *s, int config, USBPacket *p)
-{
- int rc;
-
- trace_usb_host_set_config(s->bus_num, s->addr, config);
-
- usb_host_release_interfaces(s);
- rc = libusb_set_configuration(s->dh, config);
- if (rc != 0) {
- usb_host_libusb_error("libusb_set_configuration", rc);
- p->status = USB_RET_STALL;
- if (rc == LIBUSB_ERROR_NO_DEVICE) {
- usb_host_nodev(s);
- }
- return;
- }
- p->status = usb_host_claim_interfaces(s, config);
- if (p->status != USB_RET_SUCCESS) {
- return;
- }
- usb_host_ep_update(s);
-}
-
-static void usb_host_set_interface(USBHostDevice *s, int iface, int alt,
- USBPacket *p)
-{
- USBDevice *udev = USB_DEVICE(s);
- int rc;
-
- trace_usb_host_set_interface(s->bus_num, s->addr, iface, alt);
-
- usb_host_iso_free_all(s);
-
- if (iface >= USB_MAX_INTERFACES) {
- p->status = USB_RET_STALL;
- return;
- }
-
- rc = libusb_set_interface_alt_setting(s->dh, iface, alt);
- if (rc != 0) {
- usb_host_libusb_error("libusb_set_interface_alt_setting", rc);
- p->status = USB_RET_STALL;
- if (rc == LIBUSB_ERROR_NO_DEVICE) {
- usb_host_nodev(s);
- }
- return;
- }
-
- udev->altsetting[iface] = alt;
- usb_host_ep_update(s);
-}
-
-static void usb_host_handle_control(USBDevice *udev, USBPacket *p,
- int request, int value, int index,
- int length, uint8_t *data)
-{
- USBHostDevice *s = USB_HOST_DEVICE(udev);
- USBHostRequest *r;
- int rc;
-
- trace_usb_host_req_control(s->bus_num, s->addr, p, request, value, index);
-
- if (s->dh == NULL) {
- p->status = USB_RET_NODEV;
- trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status);
- return;
- }
-
- switch (request) {
- case DeviceOutRequest | USB_REQ_SET_ADDRESS:
- usb_host_set_address(s, value);
- trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status);
- return;
-
- case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
- usb_host_set_config(s, value & 0xff, p);
- trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status);
- return;
-
- case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
- usb_host_set_interface(s, index, value, p);
- trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status);
- return;
-
- case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
- if (value == 0) { /* clear halt */
- int pid = (index & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT;
- libusb_clear_halt(s->dh, index);
- usb_ep_set_halted(udev, pid, index & 0x0f, 0);
- trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status);
- return;
- }
- }
-
- r = usb_host_req_alloc(s, p, (request >> 8) & USB_DIR_IN, length + 8);
- r->cbuf = data;
- r->clen = length;
- memcpy(r->buffer, udev->setup_buf, 8);
- if (!r->in) {
- memcpy(r->buffer + 8, r->cbuf, r->clen);
- }
-
- /* Fix up USB-3 ep0 maxpacket size to allow superspeed connected devices
- * to work redirected to a not superspeed capable hcd */
- if ((udev->speedmask & USB_SPEED_MASK_SUPER) &&
- !(udev->port->speedmask & USB_SPEED_MASK_SUPER) &&
- request == 0x8006 && value == 0x100 && index == 0) {
- r->usb3ep0quirk = true;
- }
-
- libusb_fill_control_transfer(r->xfer, s->dh, r->buffer,
- usb_host_req_complete_ctrl, r,
- CONTROL_TIMEOUT);
- rc = libusb_submit_transfer(r->xfer);
- if (rc != 0) {
- p->status = USB_RET_NODEV;
- trace_usb_host_req_complete(s->bus_num, s->addr, p,
- p->status, p->actual_length);
- if (rc == LIBUSB_ERROR_NO_DEVICE) {
- usb_host_nodev(s);
- }
- return;
- }
-
- p->status = USB_RET_ASYNC;
-}
-
-static void usb_host_handle_data(USBDevice *udev, USBPacket *p)
-{
- USBHostDevice *s = USB_HOST_DEVICE(udev);
- USBHostRequest *r;
- size_t size;
- int ep, rc;
-
- if (usb_host_use_combining(p->ep) && p->state == USB_PACKET_SETUP) {
- p->status = USB_RET_ADD_TO_QUEUE;
- return;
- }
-
- trace_usb_host_req_data(s->bus_num, s->addr, p,
- p->pid == USB_TOKEN_IN,
- p->ep->nr, p->iov.size);
-
- if (s->dh == NULL) {
- p->status = USB_RET_NODEV;
- trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status);
- return;
- }
- if (p->ep->halted) {
- p->status = USB_RET_STALL;
- trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status);
- return;
- }
-
- switch (usb_ep_get_type(udev, p->pid, p->ep->nr)) {
- case USB_ENDPOINT_XFER_BULK:
- size = usb_packet_size(p);
- r = usb_host_req_alloc(s, p, p->pid == USB_TOKEN_IN, size);
- if (!r->in) {
- usb_packet_copy(p, r->buffer, size);
- }
- ep = p->ep->nr | (r->in ? USB_DIR_IN : 0);
- if (p->stream) {
-#ifdef HAVE_STREAMS
- libusb_fill_bulk_stream_transfer(r->xfer, s->dh, ep, p->stream,
- r->buffer, size,
- usb_host_req_complete_data, r,
- BULK_TIMEOUT);
-#else
- usb_host_req_free(r);
- p->status = USB_RET_STALL;
- return;
-#endif
- } else {
- libusb_fill_bulk_transfer(r->xfer, s->dh, ep,
- r->buffer, size,
- usb_host_req_complete_data, r,
- BULK_TIMEOUT);
- }
- break;
- case USB_ENDPOINT_XFER_INT:
- r = usb_host_req_alloc(s, p, p->pid == USB_TOKEN_IN, p->iov.size);
- if (!r->in) {
- usb_packet_copy(p, r->buffer, p->iov.size);
- }
- ep = p->ep->nr | (r->in ? USB_DIR_IN : 0);
- libusb_fill_interrupt_transfer(r->xfer, s->dh, ep,
- r->buffer, p->iov.size,
- usb_host_req_complete_data, r,
- INTR_TIMEOUT);
- break;
- case USB_ENDPOINT_XFER_ISOC:
- if (p->pid == USB_TOKEN_IN) {
- usb_host_iso_data_in(s, p);
- } else {
- usb_host_iso_data_out(s, p);
- }
- trace_usb_host_req_complete(s->bus_num, s->addr, p,
- p->status, p->actual_length);
- return;
- default:
- p->status = USB_RET_STALL;
- trace_usb_host_req_complete(s->bus_num, s->addr, p,
- p->status, p->actual_length);
- return;
- }
-
- rc = libusb_submit_transfer(r->xfer);
- if (rc != 0) {
- p->status = USB_RET_NODEV;
- trace_usb_host_req_complete(s->bus_num, s->addr, p,
- p->status, p->actual_length);
- if (rc == LIBUSB_ERROR_NO_DEVICE) {
- usb_host_nodev(s);
- }
- return;
- }
-
- p->status = USB_RET_ASYNC;
-}
-
-static void usb_host_flush_ep_queue(USBDevice *dev, USBEndpoint *ep)
-{
- if (usb_host_use_combining(ep)) {
- usb_ep_combine_input_packets(ep);
- }
-}
-
-static void usb_host_handle_reset(USBDevice *udev)
-{
- USBHostDevice *s = USB_HOST_DEVICE(udev);
- int rc;
-
- trace_usb_host_reset(s->bus_num, s->addr);
-
- rc = libusb_reset_device(s->dh);
- if (rc != 0) {
- usb_host_nodev(s);
- }
-}
-
-static int usb_host_alloc_streams(USBDevice *udev, USBEndpoint **eps,
- int nr_eps, int streams)
-{
-#ifdef HAVE_STREAMS
- USBHostDevice *s = USB_HOST_DEVICE(udev);
- unsigned char endpoints[30];
- int i, rc;
-
- for (i = 0; i < nr_eps; i++) {
- endpoints[i] = eps[i]->nr;
- if (eps[i]->pid == USB_TOKEN_IN) {
- endpoints[i] |= 0x80;
- }
- }
- rc = libusb_alloc_streams(s->dh, streams, endpoints, nr_eps);
- if (rc < 0) {
- usb_host_libusb_error("libusb_alloc_streams", rc);
- } else if (rc != streams) {
- error_report("libusb_alloc_streams: got less streams "
- "then requested %d < %d", rc, streams);
- }
-
- return (rc == streams) ? 0 : -1;
-#else
- error_report("libusb_alloc_streams: error not implemented");
- return -1;
-#endif
-}
-
-static void usb_host_free_streams(USBDevice *udev, USBEndpoint **eps,
- int nr_eps)
-{
-#ifdef HAVE_STREAMS
- USBHostDevice *s = USB_HOST_DEVICE(udev);
- unsigned char endpoints[30];
- int i;
-
- for (i = 0; i < nr_eps; i++) {
- endpoints[i] = eps[i]->nr;
- if (eps[i]->pid == USB_TOKEN_IN) {
- endpoints[i] |= 0x80;
- }
- }
- libusb_free_streams(s->dh, endpoints, nr_eps);
-#endif
-}
-
-/*
- * This is *NOT* about restoring state. We have absolutely no idea
- * what state the host device is in at the moment and whenever it is
- * still present in the first place. Attemping to contine where we
- * left off is impossible.
- *
- * What we are going to do here is emulate a surprise removal of
- * the usb device passed through, then kick host scan so the device
- * will get re-attached (and re-initialized by the guest) in case it
- * is still present.
- *
- * As the device removal will change the state of other devices (usb
- * host controller, most likely interrupt controller too) we have to
- * wait with it until *all* vmstate is loaded. Thus post_load just
- * kicks a bottom half which then does the actual work.
- */
-static void usb_host_post_load_bh(void *opaque)
-{
- USBHostDevice *dev = opaque;
- USBDevice *udev = USB_DEVICE(dev);
-
- if (dev->dh != NULL) {
- usb_host_close(dev);
- }
- if (udev->attached) {
- usb_device_detach(udev);
- }
- usb_host_auto_check(NULL);
-}
-
-static int usb_host_post_load(void *opaque, int version_id)
-{
- USBHostDevice *dev = opaque;
-
- if (!dev->bh_postld) {
- dev->bh_postld = qemu_bh_new(usb_host_post_load_bh, dev);
- }
- qemu_bh_schedule(dev->bh_postld);
- return 0;
-}
-
-static const VMStateDescription vmstate_usb_host = {
- .name = "usb-host",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = usb_host_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_USB_DEVICE(parent_obj, USBHostDevice),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property usb_host_dev_properties[] = {
- DEFINE_PROP_UINT32("hostbus", USBHostDevice, match.bus_num, 0),
- DEFINE_PROP_UINT32("hostaddr", USBHostDevice, match.addr, 0),
- DEFINE_PROP_STRING("hostport", USBHostDevice, match.port),
- DEFINE_PROP_UINT32("vendorid", USBHostDevice, match.vendor_id, 0),
- DEFINE_PROP_UINT32("productid", USBHostDevice, match.product_id, 0),
- DEFINE_PROP_UINT32("isobufs", USBHostDevice, iso_urb_count, 4),
- DEFINE_PROP_UINT32("isobsize", USBHostDevice, iso_urb_frames, 32),
- DEFINE_PROP_UINT32("loglevel", USBHostDevice, loglevel,
- LIBUSB_LOG_LEVEL_WARNING),
- DEFINE_PROP_BIT("pipeline", USBHostDevice, options,
- USB_HOST_OPT_PIPELINE, true),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void usb_host_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
-
- uc->realize = usb_host_realize;
- uc->product_desc = "USB Host Device";
- uc->cancel_packet = usb_host_cancel_packet;
- uc->handle_data = usb_host_handle_data;
- uc->handle_control = usb_host_handle_control;
- uc->handle_reset = usb_host_handle_reset;
- uc->handle_destroy = usb_host_handle_destroy;
- uc->flush_ep_queue = usb_host_flush_ep_queue;
- uc->alloc_streams = usb_host_alloc_streams;
- uc->free_streams = usb_host_free_streams;
- dc->vmsd = &vmstate_usb_host;
- dc->props = usb_host_dev_properties;
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
-}
-
-static TypeInfo usb_host_dev_info = {
- .name = TYPE_USB_HOST_DEVICE,
- .parent = TYPE_USB_DEVICE,
- .instance_size = sizeof(USBHostDevice),
- .class_init = usb_host_class_initfn,
- .instance_init = usb_host_instance_init,
-};
-
-static void usb_host_register_types(void)
-{
- type_register_static(&usb_host_dev_info);
-}
-
-type_init(usb_host_register_types)
-
-/* ------------------------------------------------------------------------ */
-
-static QEMUTimer *usb_auto_timer;
-static VMChangeStateEntry *usb_vmstate;
-
-static void usb_host_vm_state(void *unused, int running, RunState state)
-{
- if (running) {
- usb_host_auto_check(unused);
- }
-}
-
-static void usb_host_auto_check(void *unused)
-{
- struct USBHostDevice *s;
- struct USBAutoFilter *f;
- libusb_device **devs = NULL;
- struct libusb_device_descriptor ddesc;
- int unconnected = 0;
- int i, n;
-
- if (usb_host_init() != 0) {
- return;
- }
-
- if (runstate_is_running()) {
- n = libusb_get_device_list(ctx, &devs);
- for (i = 0; i < n; i++) {
- if (libusb_get_device_descriptor(devs[i], &ddesc) != 0) {
- continue;
- }
- if (ddesc.bDeviceClass == LIBUSB_CLASS_HUB) {
- continue;
- }
- QTAILQ_FOREACH(s, &hostdevs, next) {
- f = &s->match;
- if (f->bus_num > 0 &&
- f->bus_num != libusb_get_bus_number(devs[i])) {
- continue;
- }
- if (f->addr > 0 &&
- f->addr != libusb_get_device_address(devs[i])) {
- continue;
- }
- if (f->port != NULL) {
- char port[16] = "-";
- usb_host_get_port(devs[i], port, sizeof(port));
- if (strcmp(f->port, port) != 0) {
- continue;
- }
- }
- if (f->vendor_id > 0 &&
- f->vendor_id != ddesc.idVendor) {
- continue;
- }
- if (f->product_id > 0 &&
- f->product_id != ddesc.idProduct) {
- continue;
- }
-
- /* We got a match */
- s->seen++;
- if (s->errcount >= 3) {
- continue;
- }
- if (s->dh != NULL) {
- continue;
- }
- if (usb_host_open(s, devs[i]) < 0) {
- s->errcount++;
- continue;
- }
- break;
- }
- }
- libusb_free_device_list(devs, 1);
-
- QTAILQ_FOREACH(s, &hostdevs, next) {
- if (s->dh == NULL) {
- unconnected++;
- }
- if (s->seen == 0) {
- if (s->dh) {
- usb_host_close(s);
- }
- s->errcount = 0;
- }
- s->seen = 0;
- }
-
-#if 0
- if (unconnected == 0) {
- /* nothing to watch */
- if (usb_auto_timer) {
- timer_del(usb_auto_timer);
- trace_usb_host_auto_scan_disabled();
- }
- return;
- }
-#endif
- }
-
- if (!usb_vmstate) {
- usb_vmstate = qemu_add_vm_change_state_handler(usb_host_vm_state, NULL);
- }
- if (!usb_auto_timer) {
- usb_auto_timer = timer_new_ms(QEMU_CLOCK_REALTIME, usb_host_auto_check, NULL);
- if (!usb_auto_timer) {
- return;
- }
- trace_usb_host_auto_scan_enabled();
- }
- timer_mod(usb_auto_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 2000);
-}
-
-void hmp_info_usbhost(Monitor *mon, const QDict *qdict)
-{
- libusb_device **devs = NULL;
- struct libusb_device_descriptor ddesc;
- char port[16];
- int i, n;
-
- if (usb_host_init() != 0) {
- return;
- }
-
- n = libusb_get_device_list(ctx, &devs);
- for (i = 0; i < n; i++) {
- if (libusb_get_device_descriptor(devs[i], &ddesc) != 0) {
- continue;
- }
- if (ddesc.bDeviceClass == LIBUSB_CLASS_HUB) {
- continue;
- }
- usb_host_get_port(devs[i], port, sizeof(port));
- monitor_printf(mon, " Bus %d, Addr %d, Port %s, Speed %s Mb/s\n",
- libusb_get_bus_number(devs[i]),
- libusb_get_device_address(devs[i]),
- port,
- speed_name[libusb_get_device_speed(devs[i])]);
- monitor_printf(mon, " Class %02x:", ddesc.bDeviceClass);
- monitor_printf(mon, " USB device %04x:%04x",
- ddesc.idVendor, ddesc.idProduct);
- if (ddesc.iProduct) {
- libusb_device_handle *handle;
- if (libusb_open(devs[i], &handle) == 0) {
- unsigned char name[64] = "";
- libusb_get_string_descriptor_ascii(handle,
- ddesc.iProduct,
- name, sizeof(name));
- libusb_close(handle);
- monitor_printf(mon, ", %s", name);
- }
- }
- monitor_printf(mon, "\n");
- }
- libusb_free_device_list(devs, 1);
-}
diff --git a/qemu/hw/usb/host-stub.c b/qemu/hw/usb/host-stub.c
deleted file mode 100644
index 6ba65a1f6..000000000
--- a/qemu/hw/usb/host-stub.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Stub host USB redirector
- *
- * Copyright (c) 2005 Fabrice Bellard
- *
- * Copyright (c) 2008 Max Krasnyansky
- * Support for host device auto connect & disconnect
- * Major rewrite to support fully async operation
- *
- * Copyright 2008 TJ <linux@tjworld.net>
- * Added flexible support for /dev/bus/usb /sys/bus/usb/devices in addition
- * to the legacy /proc/bus/usb USB device discovery and handling
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "ui/console.h"
-#include "hw/usb.h"
-#include "monitor/monitor.h"
-
-void hmp_info_usbhost(Monitor *mon, const QDict *qdict)
-{
- monitor_printf(mon, "USB host devices not supported\n");
-}
-
-/* XXX: modify configure to compile the right host driver */
-USBDevice *usb_host_device_open(USBBus *bus, const char *devname)
-{
- return NULL;
-}
diff --git a/qemu/hw/usb/host.h b/qemu/hw/usb/host.h
deleted file mode 100644
index 048ff3b48..000000000
--- a/qemu/hw/usb/host.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Linux host USB redirector
- *
- * Copyright (c) 2005 Fabrice Bellard
- *
- * Copyright (c) 2008 Max Krasnyansky
- * Support for host device auto connect & disconnect
- * Major rewrite to support fully async operation
- *
- * Copyright 2008 TJ <linux@tjworld.net>
- * Added flexible support for /dev/bus/usb /sys/bus/usb/devices in addition
- * to the legacy /proc/bus/usb USB device discovery and handling
- *
- * 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.
- */
-
-#ifndef QEMU_USB_HOST_H
-#define QEMU_USB_HOST_H
-
-struct USBAutoFilter {
- uint32_t bus_num;
- uint32_t addr;
- char *port;
- uint32_t vendor_id;
- uint32_t product_id;
-};
-
-#endif /* QEMU_USB_HOST_H */
diff --git a/qemu/hw/usb/libhw.c b/qemu/hw/usb/libhw.c
deleted file mode 100644
index 73cdf0c97..000000000
--- a/qemu/hw/usb/libhw.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * QEMU USB emulation, libhw bits.
- *
- * 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.
- */
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "hw/hw.h"
-#include "hw/usb.h"
-#include "sysemu/dma.h"
-
-int usb_packet_map(USBPacket *p, QEMUSGList *sgl)
-{
- DMADirection dir = (p->pid == USB_TOKEN_IN) ?
- DMA_DIRECTION_FROM_DEVICE : DMA_DIRECTION_TO_DEVICE;
- void *mem;
- int i;
-
- for (i = 0; i < sgl->nsg; i++) {
- dma_addr_t base = sgl->sg[i].base;
- dma_addr_t len = sgl->sg[i].len;
-
- while (len) {
- dma_addr_t xlen = len;
- mem = dma_memory_map(sgl->as, base, &xlen, dir);
- if (!mem) {
- goto err;
- }
- if (xlen > len) {
- xlen = len;
- }
- qemu_iovec_add(&p->iov, mem, xlen);
- len -= xlen;
- base += xlen;
- }
- }
- return 0;
-
-err:
- usb_packet_unmap(p, sgl);
- return -1;
-}
-
-void usb_packet_unmap(USBPacket *p, QEMUSGList *sgl)
-{
- DMADirection dir = (p->pid == USB_TOKEN_IN) ?
- DMA_DIRECTION_FROM_DEVICE : DMA_DIRECTION_TO_DEVICE;
- int i;
-
- for (i = 0; i < p->iov.niov; i++) {
- dma_memory_unmap(sgl->as, p->iov.iov[i].iov_base,
- p->iov.iov[i].iov_len, dir,
- p->iov.iov[i].iov_len);
- }
-}
diff --git a/qemu/hw/usb/quirks-ftdi-ids.h b/qemu/hw/usb/quirks-ftdi-ids.h
deleted file mode 100644
index 57c12ef66..000000000
--- a/qemu/hw/usb/quirks-ftdi-ids.h
+++ /dev/null
@@ -1,1255 +0,0 @@
-/*
- * vendor/product IDs (VID/PID) of devices using FTDI USB serial converters.
- * Please keep numerically sorted within individual areas, thanks!
- *
- * Philipp Gühring - pg@futureware.at - added the Device ID of the USB relais
- * from Rudolf Gugler
- *
- */
-
-
-/**********************************/
-/***** devices using FTDI VID *****/
-/**********************************/
-
-
-#define FTDI_VID 0x0403 /* Vendor Id */
-
-
-/*** "original" FTDI device PIDs ***/
-
-#define FTDI_8U232AM_PID 0x6001 /* Similar device to SIO above */
-#define FTDI_8U232AM_ALT_PID 0x6006 /* FTDI's alternate PID for above */
-#define FTDI_8U2232C_PID 0x6010 /* Dual channel device */
-#define FTDI_4232H_PID 0x6011 /* Quad channel hi-speed device */
-#define FTDI_232H_PID 0x6014 /* Single channel hi-speed device */
-#define FTDI_FTX_PID 0x6015 /* FT-X series (FT201X, FT230X, FT231X, etc) */
-#define FTDI_SIO_PID 0x8372 /* Product Id SIO application of 8U100AX */
-#define FTDI_232RL_PID 0xFBFA /* Product ID for FT232RL */
-
-
-/*** third-party PIDs (using FTDI_VID) ***/
-
-#define FTDI_LUMEL_PD12_PID 0x6002
-
-/*
- * Marvell OpenRD Base, Client
- * http://www.open-rd.org
- * OpenRD Base, Client use VID 0x0403
- */
-#define MARVELL_OPENRD_PID 0x9e90
-
-/* www.candapter.com Ewert Energy Systems CANdapter device */
-#define FTDI_CANDAPTER_PID 0x9F80 /* Product Id */
-
-/*
- * Texas Instruments XDS100v2 JTAG / BeagleBone A3
- * http://processors.wiki.ti.com/index.php/XDS100
- * http://beagleboard.org/bone
- */
-#define TI_XDS100V2_PID 0xa6d0
-
-#define FTDI_NXTCAM_PID 0xABB8 /* NXTCam for Mindstorms NXT */
-
-/* US Interface Navigator (http://www.usinterface.com/) */
-#define FTDI_USINT_CAT_PID 0xb810 /* Navigator CAT and 2nd PTT lines */
-#define FTDI_USINT_WKEY_PID 0xb811 /* Navigator WKEY and FSK lines */
-#define FTDI_USINT_RS232_PID 0xb812 /* Navigator RS232 and CONFIG lines */
-
-/* OOCDlink by Joern Kaipf <joernk@web.de>
- * (http://www.joernonline.de/) */
-#define FTDI_OOCDLINK_PID 0xbaf8 /* Amontec JTAGkey */
-
-/* Luminary Micro Stellaris Boards, VID = FTDI_VID */
-/* FTDI 2332C Dual channel device, side A=245 FIFO (JTAG), Side B=RS232 UART */
-#define LMI_LM3S_DEVEL_BOARD_PID 0xbcd8
-#define LMI_LM3S_EVAL_BOARD_PID 0xbcd9
-#define LMI_LM3S_ICDI_BOARD_PID 0xbcda
-
-#define FTDI_TURTELIZER_PID 0xBDC8 /* JTAG/RS-232 adapter by egnite GmbH */
-
-/* OpenDCC (www.opendcc.de) product id */
-#define FTDI_OPENDCC_PID 0xBFD8
-#define FTDI_OPENDCC_SNIFFER_PID 0xBFD9
-#define FTDI_OPENDCC_THROTTLE_PID 0xBFDA
-#define FTDI_OPENDCC_GATEWAY_PID 0xBFDB
-#define FTDI_OPENDCC_GBM_PID 0xBFDC
-
-/* NZR SEM 16+ USB (http://www.nzr.de) */
-#define FTDI_NZR_SEM_USB_PID 0xC1E0 /* NZR SEM-LOG16+ */
-
-/*
- * RR-CirKits LocoBuffer USB (http://www.rr-cirkits.com)
- */
-#define FTDI_RRCIRKITS_LOCOBUFFER_PID 0xc7d0 /* LocoBuffer USB */
-
-/* DMX4ALL DMX Interfaces */
-#define FTDI_DMX4ALL 0xC850
-
-/*
- * ASK.fr devices
- */
-#define FTDI_ASK_RDR400_PID 0xC991 /* ASK RDR 400 series card reader */
-
-/* www.starting-point-systems.com µChameleon device */
-#define FTDI_MICRO_CHAMELEON_PID 0xCAA0 /* Product Id */
-
-/*
- * Tactrix OpenPort (ECU) devices.
- * OpenPort 1.3M submitted by Donour Sizemore.
- * OpenPort 1.3S and 1.3U submitted by Ian Abbott.
- */
-#define FTDI_TACTRIX_OPENPORT_13M_PID 0xCC48 /* OpenPort 1.3 Mitsubishi */
-#define FTDI_TACTRIX_OPENPORT_13S_PID 0xCC49 /* OpenPort 1.3 Subaru */
-#define FTDI_TACTRIX_OPENPORT_13U_PID 0xCC4A /* OpenPort 1.3 Universal */
-
-#define FTDI_DISTORTEC_JTAG_LOCK_PICK_PID 0xCFF8
-
-/* SCS HF Radio Modems PID's (http://www.scs-ptc.com) */
-/* the VID is the standard ftdi vid (FTDI_VID) */
-#define FTDI_SCS_DEVICE_0_PID 0xD010 /* SCS PTC-IIusb */
-#define FTDI_SCS_DEVICE_1_PID 0xD011 /* SCS Tracker / DSP TNC */
-#define FTDI_SCS_DEVICE_2_PID 0xD012
-#define FTDI_SCS_DEVICE_3_PID 0xD013
-#define FTDI_SCS_DEVICE_4_PID 0xD014
-#define FTDI_SCS_DEVICE_5_PID 0xD015
-#define FTDI_SCS_DEVICE_6_PID 0xD016
-#define FTDI_SCS_DEVICE_7_PID 0xD017
-
-/* iPlus device */
-#define FTDI_IPLUS_PID 0xD070 /* Product Id */
-#define FTDI_IPLUS2_PID 0xD071 /* Product Id */
-
-/*
- * Gamma Scout (http://gamma-scout.com/). Submitted by rsc@runtux.com.
- */
-#define FTDI_GAMMA_SCOUT_PID 0xD678 /* Gamma Scout online */
-
-/* Propox devices */
-#define FTDI_PROPOX_JTAGCABLEII_PID 0xD738
-#define FTDI_PROPOX_ISPCABLEIII_PID 0xD739
-
-/* Lenz LI-USB Computer Interface. */
-#define FTDI_LENZ_LIUSB_PID 0xD780
-
-/* Vardaan Enterprises Serial Interface VEUSB422R3 */
-#define FTDI_VARDAAN_PID 0xF070
-
-/*
- * Xsens Technologies BV products (http://www.xsens.com).
- */
-#define XSENS_CONVERTER_0_PID 0xD388
-#define XSENS_CONVERTER_1_PID 0xD389
-#define XSENS_CONVERTER_2_PID 0xD38A
-#define XSENS_CONVERTER_3_PID 0xD38B
-#define XSENS_CONVERTER_4_PID 0xD38C
-#define XSENS_CONVERTER_5_PID 0xD38D
-#define XSENS_CONVERTER_6_PID 0xD38E
-#define XSENS_CONVERTER_7_PID 0xD38F
-
-/*
- * NDI (www.ndigital.com) product ids
- */
-#define FTDI_NDI_HUC_PID 0xDA70 /* NDI Host USB Converter */
-#define FTDI_NDI_SPECTRA_SCU_PID 0xDA71 /* NDI Spectra SCU */
-#define FTDI_NDI_FUTURE_2_PID 0xDA72 /* NDI future device #2 */
-#define FTDI_NDI_FUTURE_3_PID 0xDA73 /* NDI future device #3 */
-#define FTDI_NDI_AURORA_SCU_PID 0xDA74 /* NDI Aurora SCU */
-
-/*
- * ChamSys Limited (www.chamsys.co.uk) USB wing/interface product IDs
- */
-#define FTDI_CHAMSYS_24_MASTER_WING_PID 0xDAF8
-#define FTDI_CHAMSYS_PC_WING_PID 0xDAF9
-#define FTDI_CHAMSYS_USB_DMX_PID 0xDAFA
-#define FTDI_CHAMSYS_MIDI_TIMECODE_PID 0xDAFB
-#define FTDI_CHAMSYS_MINI_WING_PID 0xDAFC
-#define FTDI_CHAMSYS_MAXI_WING_PID 0xDAFD
-#define FTDI_CHAMSYS_MEDIA_WING_PID 0xDAFE
-#define FTDI_CHAMSYS_WING_PID 0xDAFF
-
-/*
- * Westrex International devices submitted by Cory Lee
- */
-#define FTDI_WESTREX_MODEL_777_PID 0xDC00 /* Model 777 */
-#define FTDI_WESTREX_MODEL_8900F_PID 0xDC01 /* Model 8900F */
-
-/*
- * ACG Identification Technologies GmbH products (http://www.acg.de/).
- * Submitted by anton -at- goto10 -dot- org.
- */
-#define FTDI_ACG_HFDUAL_PID 0xDD20 /* HF Dual ISO Reader (RFID) */
-
-/*
- * Definitions for Artemis astronomical USB based cameras
- * Check it at http://www.artemisccd.co.uk/
- */
-#define FTDI_ARTEMIS_PID 0xDF28 /* All Artemis Cameras */
-
-/*
- * Definitions for ATIK Instruments astronomical USB based cameras
- * Check it at http://www.atik-instruments.com/
- */
-#define FTDI_ATIK_ATK16_PID 0xDF30 /* ATIK ATK-16 Grayscale Camera */
-#define FTDI_ATIK_ATK16C_PID 0xDF32 /* ATIK ATK-16C Colour Camera */
-#define FTDI_ATIK_ATK16HR_PID 0xDF31 /* ATIK ATK-16HR Grayscale Camera */
-#define FTDI_ATIK_ATK16HRC_PID 0xDF33 /* ATIK ATK-16HRC Colour Camera */
-#define FTDI_ATIK_ATK16IC_PID 0xDF35 /* ATIK ATK-16IC Grayscale Camera */
-
-/*
- * Yost Engineering, Inc. products (www.yostengineering.com).
- * PID 0xE050 submitted by Aaron Prose.
- */
-#define FTDI_YEI_SERVOCENTER31_PID 0xE050 /* YEI ServoCenter3.1 USB */
-
-/*
- * ELV USB devices submitted by Christian Abt of ELV (www.elv.de).
- * All of these devices use FTDI's vendor ID (0x0403).
- * Further IDs taken from ELV Windows .inf file.
- *
- * The previously included PID for the UO 100 module was incorrect.
- * In fact, that PID was for ELV's UR 100 USB-RS232 converter (0xFB58).
- *
- * Armin Laeuger originally sent the PID for the UM 100 module.
- */
-#define FTDI_ELV_USR_PID 0xE000 /* ELV Universal-Sound-Recorder */
-#define FTDI_ELV_MSM1_PID 0xE001 /* ELV Mini-Sound-Modul */
-#define FTDI_ELV_KL100_PID 0xE002 /* ELV Kfz-Leistungsmesser KL 100 */
-#define FTDI_ELV_WS550_PID 0xE004 /* WS 550 */
-#define FTDI_ELV_EC3000_PID 0xE006 /* ENERGY CONTROL 3000 USB */
-#define FTDI_ELV_WS888_PID 0xE008 /* WS 888 */
-#define FTDI_ELV_TWS550_PID 0xE009 /* Technoline WS 550 */
-#define FTDI_ELV_FEM_PID 0xE00A /* Funk Energie Monitor */
-#define FTDI_ELV_FHZ1300PC_PID 0xE0E8 /* FHZ 1300 PC */
-#define FTDI_ELV_WS500_PID 0xE0E9 /* PC-Wetterstation (WS 500) */
-#define FTDI_ELV_HS485_PID 0xE0EA /* USB to RS-485 adapter */
-#define FTDI_ELV_UMS100_PID 0xE0EB /* ELV USB Master-Slave Schaltsteckdose UMS 100 */
-#define FTDI_ELV_TFD128_PID 0xE0EC /* ELV Temperatur-Feuchte-Datenlogger TFD 128 */
-#define FTDI_ELV_FM3RX_PID 0xE0ED /* ELV Messwertuebertragung FM3 RX */
-#define FTDI_ELV_WS777_PID 0xE0EE /* Conrad WS 777 */
-#define FTDI_ELV_EM1010PC_PID 0xE0EF /* Energy monitor EM 1010 PC */
-#define FTDI_ELV_CSI8_PID 0xE0F0 /* Computer-Schalt-Interface (CSI 8) */
-#define FTDI_ELV_EM1000DL_PID 0xE0F1 /* PC-Datenlogger fuer Energiemonitor (EM 1000 DL) */
-#define FTDI_ELV_PCK100_PID 0xE0F2 /* PC-Kabeltester (PCK 100) */
-#define FTDI_ELV_RFP500_PID 0xE0F3 /* HF-Leistungsmesser (RFP 500) */
-#define FTDI_ELV_FS20SIG_PID 0xE0F4 /* Signalgeber (FS 20 SIG) */
-#define FTDI_ELV_UTP8_PID 0xE0F5 /* ELV UTP 8 */
-#define FTDI_ELV_WS300PC_PID 0xE0F6 /* PC-Wetterstation (WS 300 PC) */
-#define FTDI_ELV_WS444PC_PID 0xE0F7 /* Conrad WS 444 PC */
-#define FTDI_PHI_FISCO_PID 0xE40B /* PHI Fisco USB to Serial cable */
-#define FTDI_ELV_UAD8_PID 0xF068 /* USB-AD-Wandler (UAD 8) */
-#define FTDI_ELV_UDA7_PID 0xF069 /* USB-DA-Wandler (UDA 7) */
-#define FTDI_ELV_USI2_PID 0xF06A /* USB-Schrittmotoren-Interface (USI 2) */
-#define FTDI_ELV_T1100_PID 0xF06B /* Thermometer (T 1100) */
-#define FTDI_ELV_PCD200_PID 0xF06C /* PC-Datenlogger (PCD 200) */
-#define FTDI_ELV_ULA200_PID 0xF06D /* USB-LCD-Ansteuerung (ULA 200) */
-#define FTDI_ELV_ALC8500_PID 0xF06E /* ALC 8500 Expert */
-#define FTDI_ELV_FHZ1000PC_PID 0xF06F /* FHZ 1000 PC */
-#define FTDI_ELV_UR100_PID 0xFB58 /* USB-RS232-Umsetzer (UR 100) */
-#define FTDI_ELV_UM100_PID 0xFB5A /* USB-Modul UM 100 */
-#define FTDI_ELV_UO100_PID 0xFB5B /* USB-Modul UO 100 */
-/* Additional ELV PIDs that default to using the FTDI D2XX drivers on
- * MS Windows, rather than the FTDI Virtual Com Port drivers.
- * Maybe these will be easier to use with the libftdi/libusb user-space
- * drivers, or possibly the Comedi drivers in some cases. */
-#define FTDI_ELV_CLI7000_PID 0xFB59 /* Computer-Light-Interface (CLI 7000) */
-#define FTDI_ELV_PPS7330_PID 0xFB5C /* Processor-Power-Supply (PPS 7330) */
-#define FTDI_ELV_TFM100_PID 0xFB5D /* Temperatur-Feuchte-Messgeraet (TFM 100) */
-#define FTDI_ELV_UDF77_PID 0xFB5E /* USB DCF Funkuhr (UDF 77) */
-#define FTDI_ELV_UIO88_PID 0xFB5F /* USB-I/O Interface (UIO 88) */
-
-/*
- * EVER Eco Pro UPS (http://www.ever.com.pl/)
- */
-
-#define EVER_ECO_PRO_CDS 0xe520 /* RS-232 converter */
-
-/*
- * Active Robots product ids.
- */
-#define FTDI_ACTIVE_ROBOTS_PID 0xE548 /* USB comms board */
-
-/* Pyramid Computer GmbH */
-#define FTDI_PYRAMID_PID 0xE6C8 /* Pyramid Appliance Display */
-
-/* www.elsterelectricity.com Elster Unicom III Optical Probe */
-#define FTDI_ELSTER_UNICOM_PID 0xE700 /* Product Id */
-
-/*
- * Gude Analog- und Digitalsysteme GmbH
- */
-#define FTDI_GUDEADS_E808_PID 0xE808
-#define FTDI_GUDEADS_E809_PID 0xE809
-#define FTDI_GUDEADS_E80A_PID 0xE80A
-#define FTDI_GUDEADS_E80B_PID 0xE80B
-#define FTDI_GUDEADS_E80C_PID 0xE80C
-#define FTDI_GUDEADS_E80D_PID 0xE80D
-#define FTDI_GUDEADS_E80E_PID 0xE80E
-#define FTDI_GUDEADS_E80F_PID 0xE80F
-#define FTDI_GUDEADS_E888_PID 0xE888 /* Expert ISDN Control USB */
-#define FTDI_GUDEADS_E889_PID 0xE889 /* USB RS-232 OptoBridge */
-#define FTDI_GUDEADS_E88A_PID 0xE88A
-#define FTDI_GUDEADS_E88B_PID 0xE88B
-#define FTDI_GUDEADS_E88C_PID 0xE88C
-#define FTDI_GUDEADS_E88D_PID 0xE88D
-#define FTDI_GUDEADS_E88E_PID 0xE88E
-#define FTDI_GUDEADS_E88F_PID 0xE88F
-
-/*
- * Eclo (http://www.eclo.pt/) product IDs.
- * PID 0xEA90 submitted by Martin Grill.
- */
-#define FTDI_ECLO_COM_1WIRE_PID 0xEA90 /* COM to 1-Wire USB adaptor */
-
-/* TNC-X USB-to-packet-radio adapter, versions prior to 3.0 (DLP module) */
-#define FTDI_TNC_X_PID 0xEBE0
-
-/*
- * Teratronik product ids.
- * Submitted by O. Wölfelschneider.
- */
-#define FTDI_TERATRONIK_VCP_PID 0xEC88 /* Teratronik device (preferring VCP driver on windows) */
-#define FTDI_TERATRONIK_D2XX_PID 0xEC89 /* Teratronik device (preferring D2XX driver on windows) */
-
-/* Rig Expert Ukraine devices */
-#define FTDI_REU_TINY_PID 0xED22 /* RigExpert Tiny */
-
-/*
- * Hameg HO820 and HO870 interface (using VID 0x0403)
- */
-#define HAMEG_HO820_PID 0xed74
-#define HAMEG_HO730_PID 0xed73
-#define HAMEG_HO720_PID 0xed72
-#define HAMEG_HO870_PID 0xed71
-
-/*
- * MaxStream devices www.maxstream.net
- */
-#define FTDI_MAXSTREAM_PID 0xEE18 /* Xbee PKG-U Module */
-
-/*
- * microHAM product IDs (http://www.microham.com).
- * Submitted by Justin Burket (KL1RL) <zorton@jtan.com>
- * and Mike Studer (K6EEP) <k6eep@hamsoftware.org>.
- * Ian Abbott <abbotti@mev.co.uk> added a few more from the driver INF file.
- */
-#define FTDI_MHAM_KW_PID 0xEEE8 /* USB-KW interface */
-#define FTDI_MHAM_YS_PID 0xEEE9 /* USB-YS interface */
-#define FTDI_MHAM_Y6_PID 0xEEEA /* USB-Y6 interface */
-#define FTDI_MHAM_Y8_PID 0xEEEB /* USB-Y8 interface */
-#define FTDI_MHAM_IC_PID 0xEEEC /* USB-IC interface */
-#define FTDI_MHAM_DB9_PID 0xEEED /* USB-DB9 interface */
-#define FTDI_MHAM_RS232_PID 0xEEEE /* USB-RS232 interface */
-#define FTDI_MHAM_Y9_PID 0xEEEF /* USB-Y9 interface */
-
-/* Domintell products http://www.domintell.com */
-#define FTDI_DOMINTELL_DGQG_PID 0xEF50 /* Master */
-#define FTDI_DOMINTELL_DUSB_PID 0xEF51 /* DUSB01 module */
-
-/*
- * The following are the values for the Perle Systems
- * UltraPort USB serial converters
- */
-#define FTDI_PERLE_ULTRAPORT_PID 0xF0C0 /* Perle UltraPort Product Id */
-
-/* Sprog II (Andrew Crosland's SprogII DCC interface) */
-#define FTDI_SPROG_II 0xF0C8
-
-/* an infrared receiver for user access control with IR tags */
-#define FTDI_PIEGROUP_PID 0xF208 /* Product Id */
-
-/* ACT Solutions HomePro ZWave interface
- (http://www.act-solutions.com/HomePro-Product-Matrix.html) */
-#define FTDI_ACTZWAVE_PID 0xF2D0
-
-/*
- * 4N-GALAXY.DE PIDs for CAN-USB, USB-RS232, USB-RS422, USB-RS485,
- * USB-TTY aktiv, USB-TTY passiv. Some PIDs are used by several devices
- * and I'm not entirely sure which are used by which.
- */
-#define FTDI_4N_GALAXY_DE_1_PID 0xF3C0
-#define FTDI_4N_GALAXY_DE_2_PID 0xF3C1
-#define FTDI_4N_GALAXY_DE_3_PID 0xF3C2
-
-/*
- * Linx Technologies product ids
- */
-#define LINX_SDMUSBQSS_PID 0xF448 /* Linx SDM-USB-QS-S */
-#define LINX_MASTERDEVEL2_PID 0xF449 /* Linx Master Development 2.0 */
-#define LINX_FUTURE_0_PID 0xF44A /* Linx future device */
-#define LINX_FUTURE_1_PID 0xF44B /* Linx future device */
-#define LINX_FUTURE_2_PID 0xF44C /* Linx future device */
-
-/*
- * Oceanic product ids
- */
-#define FTDI_OCEANIC_PID 0xF460 /* Oceanic dive instrument */
-
-/*
- * SUUNTO product ids
- */
-#define FTDI_SUUNTO_SPORTS_PID 0xF680 /* Suunto Sports instrument */
-
-/* USB-UIRT - An infrared receiver and transmitter using the 8U232AM chip */
-/* http://www.usbuirt.com/ */
-#define FTDI_USB_UIRT_PID 0xF850 /* Product Id */
-
-/* CCS Inc. ICDU/ICDU40 product ID -
- * the FT232BM is used in an in-circuit-debugger unit for PIC16's/PIC18's */
-#define FTDI_CCSICDU20_0_PID 0xF9D0
-#define FTDI_CCSICDU40_1_PID 0xF9D1
-#define FTDI_CCSMACHX_2_PID 0xF9D2
-#define FTDI_CCSLOAD_N_GO_3_PID 0xF9D3
-#define FTDI_CCSICDU64_4_PID 0xF9D4
-#define FTDI_CCSPRIME8_5_PID 0xF9D5
-
-/*
- * The following are the values for the Matrix Orbital LCD displays,
- * which are the FT232BM ( similar to the 8U232AM )
- */
-#define FTDI_MTXORB_0_PID 0xFA00 /* Matrix Orbital Product Id */
-#define FTDI_MTXORB_1_PID 0xFA01 /* Matrix Orbital Product Id */
-#define FTDI_MTXORB_2_PID 0xFA02 /* Matrix Orbital Product Id */
-#define FTDI_MTXORB_3_PID 0xFA03 /* Matrix Orbital Product Id */
-#define FTDI_MTXORB_4_PID 0xFA04 /* Matrix Orbital Product Id */
-#define FTDI_MTXORB_5_PID 0xFA05 /* Matrix Orbital Product Id */
-#define FTDI_MTXORB_6_PID 0xFA06 /* Matrix Orbital Product Id */
-
-/*
- * Home Electronics (www.home-electro.com) USB gadgets
- */
-#define FTDI_HE_TIRA1_PID 0xFA78 /* Tira-1 IR transceiver */
-
-/* Inside Accesso contactless reader (http://www.insidecontactless.com/) */
-#define INSIDE_ACCESSO 0xFAD0
-
-/*
- * ThorLabs USB motor drivers
- */
-#define FTDI_THORLABS_PID 0xfaf0 /* ThorLabs USB motor drivers */
-
-/*
- * Protego product ids
- */
-#define PROTEGO_SPECIAL_1 0xFC70 /* special/unknown device */
-#define PROTEGO_R2X0 0xFC71 /* R200-USB TRNG unit (R210, R220, and R230) */
-#define PROTEGO_SPECIAL_3 0xFC72 /* special/unknown device */
-#define PROTEGO_SPECIAL_4 0xFC73 /* special/unknown device */
-
-/*
- * Sony Ericsson product ids
- */
-#define FTDI_DSS20_PID 0xFC82 /* DSS-20 Sync Station for Sony Ericsson P800 */
-#define FTDI_URBAN_0_PID 0xFC8A /* Sony Ericsson Urban, uart #0 */
-#define FTDI_URBAN_1_PID 0xFC8B /* Sony Ericsson Urban, uart #1 */
-
-/* www.irtrans.de device */
-#define FTDI_IRTRANS_PID 0xFC60 /* Product Id */
-
-/*
- * RM Michaelides CANview USB (http://www.rmcan.com) (FTDI_VID)
- * CAN fieldbus interface adapter, added by port GmbH www.port.de)
- * Ian Abbott changed the macro names for consistency.
- */
-#define FTDI_RM_CANVIEW_PID 0xfd60 /* Product Id */
-/* www.thoughttechnology.com/ TT-USB provide with procomp use ftdi_sio */
-#define FTDI_TTUSB_PID 0xFF20 /* Product Id */
-
-#define FTDI_USBX_707_PID 0xF857 /* ADSTech IR Blaster USBX-707 (FTDI_VID) */
-
-#define FTDI_RELAIS_PID 0xFA10 /* Relais device from Rudolf Gugler */
-
-/*
- * PCDJ use ftdi based dj-controllers. The following PID is
- * for their DAC-2 device http://www.pcdjhardware.com/DAC2.asp
- * (the VID is the standard ftdi vid (FTDI_VID), PID sent by Wouter Paesen)
- */
-#define FTDI_PCDJ_DAC2_PID 0xFA88
-
-#define FTDI_R2000KU_TRUE_RNG 0xFB80 /* R2000KU TRUE RNG (FTDI_VID) */
-
-/*
- * DIEBOLD BCS SE923 (FTDI_VID)
- */
-#define DIEBOLD_BCS_SE923_PID 0xfb99
-
-/* www.crystalfontz.com devices
- * - thanx for providing free devices for evaluation !
- * they use the ftdi chipset for the USB interface
- * and the vendor id is the same
- */
-#define FTDI_XF_632_PID 0xFC08 /* 632: 16x2 Character Display */
-#define FTDI_XF_634_PID 0xFC09 /* 634: 20x4 Character Display */
-#define FTDI_XF_547_PID 0xFC0A /* 547: Two line Display */
-#define FTDI_XF_633_PID 0xFC0B /* 633: 16x2 Character Display with Keys */
-#define FTDI_XF_631_PID 0xFC0C /* 631: 20x2 Character Display */
-#define FTDI_XF_635_PID 0xFC0D /* 635: 20x4 Character Display */
-#define FTDI_XF_640_PID 0xFC0E /* 640: Two line Display */
-#define FTDI_XF_642_PID 0xFC0F /* 642: Two line Display */
-
-/*
- * Video Networks Limited / Homechoice in the UK use an ftdi-based device
- * for their 1Mb broadband internet service. The following PID is exhibited
- * by the usb device supplied (the VID is the standard ftdi vid (FTDI_VID)
- */
-#define FTDI_VNHCPCUSB_D_PID 0xfe38 /* Product Id */
-
-/* AlphaMicro Components AMC-232USB01 device (FTDI_VID) */
-#define FTDI_AMC232_PID 0xFF00 /* Product Id */
-
-/*
- * IBS elektronik product ids (FTDI_VID)
- * Submitted by Thomas Schleusener
- */
-#define FTDI_IBS_US485_PID 0xff38 /* IBS US485 (USB<-->RS422/485 interface) */
-#define FTDI_IBS_PICPRO_PID 0xff39 /* IBS PIC-Programmer */
-#define FTDI_IBS_PCMCIA_PID 0xff3a /* IBS Card reader for PCMCIA SRAM-cards */
-#define FTDI_IBS_PK1_PID 0xff3b /* IBS PK1 - Particel counter */
-#define FTDI_IBS_RS232MON_PID 0xff3c /* IBS RS232 - Monitor */
-#define FTDI_IBS_APP70_PID 0xff3d /* APP 70 (dust monitoring system) */
-#define FTDI_IBS_PEDO_PID 0xff3e /* IBS PEDO-Modem (RF modem 868.35 MHz) */
-#define FTDI_IBS_PROD_PID 0xff3f /* future device */
-/* www.canusb.com Lawicel CANUSB device (FTDI_VID) */
-#define FTDI_CANUSB_PID 0xFFA8 /* Product Id */
-
-/*
- * TavIR AVR product ids (FTDI_VID)
- */
-#define FTDI_TAVIR_STK500_PID 0xFA33 /* STK500 AVR programmer */
-
-/*
- * TIAO product ids (FTDI_VID)
- * http://www.tiaowiki.com/w/Main_Page
- */
-#define FTDI_TIAO_UMPA_PID 0x8a98 /* TIAO/DIYGADGET USB Multi-Protocol Adapter */
-
-
-/********************************/
-/** third-party VID/PID combos **/
-/********************************/
-
-
-
-/*
- * Atmel STK541
- */
-#define ATMEL_VID 0x03eb /* Vendor ID */
-#define STK541_PID 0x2109 /* Zigbee Controller */
-
-/*
- * Blackfin gnICE JTAG
- * http://docs.blackfin.uclinux.org/doku.php?id=hw:jtag:gnice
- */
-#define ADI_VID 0x0456
-#define ADI_GNICE_PID 0xF000
-#define ADI_GNICEPLUS_PID 0xF001
-
-/*
- * Microchip Technology, Inc.
- *
- * MICROCHIP_VID (0x04D8) and MICROCHIP_USB_BOARD_PID (0x000A) are
- * used by single function CDC ACM class based firmware demo
- * applications. The VID/PID has also been used in firmware
- * emulating FTDI serial chips by:
- * Hornby Elite - Digital Command Control Console
- * http://www.hornby.com/hornby-dcc/controllers/
- */
-#define MICROCHIP_VID 0x04D8
-#define MICROCHIP_USB_BOARD_PID 0x000A /* CDC RS-232 Emulation Demo */
-
-/*
- * RATOC REX-USB60F
- */
-#define RATOC_VENDOR_ID 0x0584
-#define RATOC_PRODUCT_ID_USB60F 0xb020
-
-/*
- * Acton Research Corp.
- */
-#define ACTON_VID 0x0647 /* Vendor ID */
-#define ACTON_SPECTRAPRO_PID 0x0100
-
-/*
- * Contec products (http://www.contec.com)
- * Submitted by Daniel Sangorrin
- */
-#define CONTEC_VID 0x06CE /* Vendor ID */
-#define CONTEC_COM1USBH_PID 0x8311 /* COM-1(USB)H */
-
-/*
- * Definitions for B&B Electronics products.
- */
-#define BANDB_VID 0x0856 /* B&B Electronics Vendor ID */
-#define BANDB_USOTL4_PID 0xAC01 /* USOTL4 Isolated RS-485 Converter */
-#define BANDB_USTL4_PID 0xAC02 /* USTL4 RS-485 Converter */
-#define BANDB_USO9ML2_PID 0xAC03 /* USO9ML2 Isolated RS-232 Converter */
-#define BANDB_USOPTL4_PID 0xAC11
-#define BANDB_USPTL4_PID 0xAC12
-#define BANDB_USO9ML2DR_2_PID 0xAC16
-#define BANDB_USO9ML2DR_PID 0xAC17
-#define BANDB_USOPTL4DR2_PID 0xAC18 /* USOPTL4R-2 2-port Isolated RS-232 Converter */
-#define BANDB_USOPTL4DR_PID 0xAC19
-#define BANDB_485USB9F_2W_PID 0xAC25
-#define BANDB_485USB9F_4W_PID 0xAC26
-#define BANDB_232USB9M_PID 0xAC27
-#define BANDB_485USBTB_2W_PID 0xAC33
-#define BANDB_485USBTB_4W_PID 0xAC34
-#define BANDB_TTL5USB9M_PID 0xAC49
-#define BANDB_TTL3USB9M_PID 0xAC50
-#define BANDB_ZZ_PROG1_USB_PID 0xBA02
-
-/*
- * Intrepid Control Systems (http://www.intrepidcs.com/) ValueCAN and NeoVI
- */
-#define INTREPID_VID 0x093C
-#define INTREPID_VALUECAN_PID 0x0601
-#define INTREPID_NEOVI_PID 0x0701
-
-/*
- * Definitions for ID TECH (www.idt-net.com) devices
- */
-#define IDTECH_VID 0x0ACD /* ID TECH Vendor ID */
-#define IDTECH_IDT1221U_PID 0x0300 /* IDT1221U USB to RS-232 adapter */
-
-/*
- * Definitions for Omnidirectional Control Technology, Inc. devices
- */
-#define OCT_VID 0x0B39 /* OCT vendor ID */
-/* Note: OCT US101 is also rebadged as Dick Smith Electronics (NZ) XH6381 */
-/* Also rebadged as Dick Smith Electronics (Aus) XH6451 */
-/* Also rebadged as SIIG Inc. model US2308 hardware version 1 */
-#define OCT_DK201_PID 0x0103 /* OCT DK201 USB docking station */
-#define OCT_US101_PID 0x0421 /* OCT US101 USB to RS-232 */
-
-/*
- * Definitions for Icom Inc. devices
- */
-#define ICOM_VID 0x0C26 /* Icom vendor ID */
-/* Note: ID-1 is a communications tranceiver for HAM-radio operators */
-#define ICOM_ID_1_PID 0x0004 /* ID-1 USB to RS-232 */
-/* Note: OPC is an Optional cable to connect an Icom Tranceiver */
-#define ICOM_OPC_U_UC_PID 0x0018 /* OPC-478UC, OPC-1122U cloning cable */
-/* Note: ID-RP* devices are Icom Repeater Devices for HAM-radio */
-#define ICOM_ID_RP2C1_PID 0x0009 /* ID-RP2C Asset 1 to RS-232 */
-#define ICOM_ID_RP2C2_PID 0x000A /* ID-RP2C Asset 2 to RS-232 */
-#define ICOM_ID_RP2D_PID 0x000B /* ID-RP2D configuration port*/
-#define ICOM_ID_RP2VT_PID 0x000C /* ID-RP2V Transmit config port */
-#define ICOM_ID_RP2VR_PID 0x000D /* ID-RP2V Receive config port */
-#define ICOM_ID_RP4KVT_PID 0x0010 /* ID-RP4000V Transmit config port */
-#define ICOM_ID_RP4KVR_PID 0x0011 /* ID-RP4000V Receive config port */
-#define ICOM_ID_RP2KVT_PID 0x0012 /* ID-RP2000V Transmit config port */
-#define ICOM_ID_RP2KVR_PID 0x0013 /* ID-RP2000V Receive config port */
-
-/*
- * GN Otometrics (http://www.otometrics.com)
- * Submitted by Ville Sundberg.
- */
-#define GN_OTOMETRICS_VID 0x0c33 /* Vendor ID */
-#define AURICAL_USB_PID 0x0010 /* Aurical USB Audiometer */
-
-/*
- * The following are the values for the Sealevel SeaLINK+ adapters.
- * (Original list sent by Tuan Hoang. Ian Abbott renamed the macros and
- * removed some PIDs that don't seem to match any existing products.)
- */
-#define SEALEVEL_VID 0x0c52 /* Sealevel Vendor ID */
-#define SEALEVEL_2101_PID 0x2101 /* SeaLINK+232 (2101/2105) */
-#define SEALEVEL_2102_PID 0x2102 /* SeaLINK+485 (2102) */
-#define SEALEVEL_2103_PID 0x2103 /* SeaLINK+232I (2103) */
-#define SEALEVEL_2104_PID 0x2104 /* SeaLINK+485I (2104) */
-#define SEALEVEL_2106_PID 0x9020 /* SeaLINK+422 (2106) */
-#define SEALEVEL_2201_1_PID 0x2211 /* SeaPORT+2/232 (2201) Port 1 */
-#define SEALEVEL_2201_2_PID 0x2221 /* SeaPORT+2/232 (2201) Port 2 */
-#define SEALEVEL_2202_1_PID 0x2212 /* SeaPORT+2/485 (2202) Port 1 */
-#define SEALEVEL_2202_2_PID 0x2222 /* SeaPORT+2/485 (2202) Port 2 */
-#define SEALEVEL_2203_1_PID 0x2213 /* SeaPORT+2 (2203) Port 1 */
-#define SEALEVEL_2203_2_PID 0x2223 /* SeaPORT+2 (2203) Port 2 */
-#define SEALEVEL_2401_1_PID 0x2411 /* SeaPORT+4/232 (2401) Port 1 */
-#define SEALEVEL_2401_2_PID 0x2421 /* SeaPORT+4/232 (2401) Port 2 */
-#define SEALEVEL_2401_3_PID 0x2431 /* SeaPORT+4/232 (2401) Port 3 */
-#define SEALEVEL_2401_4_PID 0x2441 /* SeaPORT+4/232 (2401) Port 4 */
-#define SEALEVEL_2402_1_PID 0x2412 /* SeaPORT+4/485 (2402) Port 1 */
-#define SEALEVEL_2402_2_PID 0x2422 /* SeaPORT+4/485 (2402) Port 2 */
-#define SEALEVEL_2402_3_PID 0x2432 /* SeaPORT+4/485 (2402) Port 3 */
-#define SEALEVEL_2402_4_PID 0x2442 /* SeaPORT+4/485 (2402) Port 4 */
-#define SEALEVEL_2403_1_PID 0x2413 /* SeaPORT+4 (2403) Port 1 */
-#define SEALEVEL_2403_2_PID 0x2423 /* SeaPORT+4 (2403) Port 2 */
-#define SEALEVEL_2403_3_PID 0x2433 /* SeaPORT+4 (2403) Port 3 */
-#define SEALEVEL_2403_4_PID 0x2443 /* SeaPORT+4 (2403) Port 4 */
-#define SEALEVEL_2801_1_PID 0X2811 /* SeaLINK+8/232 (2801) Port 1 */
-#define SEALEVEL_2801_2_PID 0X2821 /* SeaLINK+8/232 (2801) Port 2 */
-#define SEALEVEL_2801_3_PID 0X2831 /* SeaLINK+8/232 (2801) Port 3 */
-#define SEALEVEL_2801_4_PID 0X2841 /* SeaLINK+8/232 (2801) Port 4 */
-#define SEALEVEL_2801_5_PID 0X2851 /* SeaLINK+8/232 (2801) Port 5 */
-#define SEALEVEL_2801_6_PID 0X2861 /* SeaLINK+8/232 (2801) Port 6 */
-#define SEALEVEL_2801_7_PID 0X2871 /* SeaLINK+8/232 (2801) Port 7 */
-#define SEALEVEL_2801_8_PID 0X2881 /* SeaLINK+8/232 (2801) Port 8 */
-#define SEALEVEL_2802_1_PID 0X2812 /* SeaLINK+8/485 (2802) Port 1 */
-#define SEALEVEL_2802_2_PID 0X2822 /* SeaLINK+8/485 (2802) Port 2 */
-#define SEALEVEL_2802_3_PID 0X2832 /* SeaLINK+8/485 (2802) Port 3 */
-#define SEALEVEL_2802_4_PID 0X2842 /* SeaLINK+8/485 (2802) Port 4 */
-#define SEALEVEL_2802_5_PID 0X2852 /* SeaLINK+8/485 (2802) Port 5 */
-#define SEALEVEL_2802_6_PID 0X2862 /* SeaLINK+8/485 (2802) Port 6 */
-#define SEALEVEL_2802_7_PID 0X2872 /* SeaLINK+8/485 (2802) Port 7 */
-#define SEALEVEL_2802_8_PID 0X2882 /* SeaLINK+8/485 (2802) Port 8 */
-#define SEALEVEL_2803_1_PID 0X2813 /* SeaLINK+8 (2803) Port 1 */
-#define SEALEVEL_2803_2_PID 0X2823 /* SeaLINK+8 (2803) Port 2 */
-#define SEALEVEL_2803_3_PID 0X2833 /* SeaLINK+8 (2803) Port 3 */
-#define SEALEVEL_2803_4_PID 0X2843 /* SeaLINK+8 (2803) Port 4 */
-#define SEALEVEL_2803_5_PID 0X2853 /* SeaLINK+8 (2803) Port 5 */
-#define SEALEVEL_2803_6_PID 0X2863 /* SeaLINK+8 (2803) Port 6 */
-#define SEALEVEL_2803_7_PID 0X2873 /* SeaLINK+8 (2803) Port 7 */
-#define SEALEVEL_2803_8_PID 0X2883 /* SeaLINK+8 (2803) Port 8 */
-#define SEALEVEL_2803R_1_PID 0Xa02a /* SeaLINK+8 (2803-ROHS) Port 1+2 */
-#define SEALEVEL_2803R_2_PID 0Xa02b /* SeaLINK+8 (2803-ROHS) Port 3+4 */
-#define SEALEVEL_2803R_3_PID 0Xa02c /* SeaLINK+8 (2803-ROHS) Port 5+6 */
-#define SEALEVEL_2803R_4_PID 0Xa02d /* SeaLINK+8 (2803-ROHS) Port 7+8 */
-
-/*
- * JETI SPECTROMETER SPECBOS 1201
- * http://www.jeti.com/cms/index.php/instruments/other-instruments/specbos-2101
- */
-#define JETI_VID 0x0c6c
-#define JETI_SPC1201_PID 0x04b2
-
-/*
- * FTDI USB UART chips used in construction projects from the
- * Elektor Electronics magazine (http://www.elektor.com/)
- */
-#define ELEKTOR_VID 0x0C7D
-#define ELEKTOR_FT323R_PID 0x0005 /* RFID-Reader, issue 09-2006 */
-
-/*
- * Posiflex inc retail equipment (http://www.posiflex.com.tw)
- */
-#define POSIFLEX_VID 0x0d3a /* Vendor ID */
-#define POSIFLEX_PP7000_PID 0x0300 /* PP-7000II thermal printer */
-
-/*
- * The following are the values for two KOBIL chipcard terminals.
- */
-#define KOBIL_VID 0x0d46 /* KOBIL Vendor ID */
-#define KOBIL_CONV_B1_PID 0x2020 /* KOBIL Konverter for B1 */
-#define KOBIL_CONV_KAAN_PID 0x2021 /* KOBIL_Konverter for KAAN */
-
-#define FTDI_NF_RIC_VID 0x0DCD /* Vendor Id */
-#define FTDI_NF_RIC_PID 0x0001 /* Product Id */
-
-/*
- * Falcom Wireless Communications GmbH
- */
-#define FALCOM_VID 0x0F94 /* Vendor Id */
-#define FALCOM_TWIST_PID 0x0001 /* Falcom Twist USB GPRS modem */
-#define FALCOM_SAMBA_PID 0x0005 /* Falcom Samba USB GPRS modem */
-
-/* Larsen and Brusgaard AltiTrack/USBtrack */
-#define LARSENBRUSGAARD_VID 0x0FD8
-#define LB_ALTITRACK_PID 0x0001
-
-/*
- * TTi (Thurlby Thandar Instruments)
- */
-#define TTI_VID 0x103E /* Vendor Id */
-#define TTI_QL355P_PID 0x03E8 /* TTi QL355P power supply */
-
-/* Interbiometrics USB I/O Board */
-/* Developed for Interbiometrics by Rudolf Gugler */
-#define INTERBIOMETRICS_VID 0x1209
-#define INTERBIOMETRICS_IOBOARD_PID 0x1002
-#define INTERBIOMETRICS_MINI_IOBOARD_PID 0x1006
-
-/*
- * Testo products (http://www.testo.com/)
- * Submitted by Colin Leroy
- */
-#define TESTO_VID 0x128D
-#define TESTO_USB_INTERFACE_PID 0x0001
-
-/*
- * Mobility Electronics products.
- */
-#define MOBILITY_VID 0x1342
-#define MOBILITY_USB_SERIAL_PID 0x0202 /* EasiDock USB 200 serial */
-
-/*
- * FIC / OpenMoko, Inc. http://wiki.openmoko.org/wiki/Neo1973_Debug_Board_v3
- * Submitted by Harald Welte <laforge@openmoko.org>
- */
-#define FIC_VID 0x1457
-#define FIC_NEO1973_DEBUG_PID 0x5118
-
-/* Olimex */
-#define OLIMEX_VID 0x15BA
-#define OLIMEX_ARM_USB_OCD_PID 0x0003
-#define OLIMEX_ARM_USB_OCD_H_PID 0x002b
-
-/*
- * Telldus Technologies
- */
-#define TELLDUS_VID 0x1781 /* Vendor ID */
-#define TELLDUS_TELLSTICK_PID 0x0C30 /* RF control dongle 433 MHz using FT232RL */
-
-/*
- * RT Systems programming cables for various ham radios
- */
-#define RTSYSTEMS_VID 0x2100 /* Vendor ID */
-#define RTSYSTEMS_SERIAL_VX7_PID 0x9e52 /* Serial converter for VX-7 Radios using FT232RL */
-#define RTSYSTEMS_CT29B_PID 0x9e54 /* CT29B Radio Cable */
-#define RTSYSTEMS_RTS01_PID 0x9e57 /* USB-RTS01 Radio Cable */
-
-
-/*
- * Physik Instrumente
- * http://www.physikinstrumente.com/en/products/
- */
-/* These two devices use the VID of FTDI */
-#define PI_C865_PID 0xe0a0 /* PI C-865 Piezomotor Controller */
-#define PI_C857_PID 0xe0a1 /* PI Encoder Trigger Box */
-
-#define PI_VID 0x1a72 /* Vendor ID */
-#define PI_C866_PID 0x1000 /* PI C-866 Piezomotor Controller */
-#define PI_C663_PID 0x1001 /* PI C-663 Mercury-Step */
-#define PI_C725_PID 0x1002 /* PI C-725 Piezomotor Controller */
-#define PI_E517_PID 0x1005 /* PI E-517 Digital Piezo Controller Operation Module */
-#define PI_C863_PID 0x1007 /* PI C-863 */
-#define PI_E861_PID 0x1008 /* PI E-861 Piezomotor Controller */
-#define PI_C867_PID 0x1009 /* PI C-867 Piezomotor Controller */
-#define PI_E609_PID 0x100D /* PI E-609 Digital Piezo Controller */
-#define PI_E709_PID 0x100E /* PI E-709 Digital Piezo Controller */
-#define PI_100F_PID 0x100F /* PI Digital Piezo Controller */
-#define PI_1011_PID 0x1011 /* PI Digital Piezo Controller */
-#define PI_1012_PID 0x1012 /* PI Motion Controller */
-#define PI_1013_PID 0x1013 /* PI Motion Controller */
-#define PI_1014_PID 0x1014 /* PI Device */
-#define PI_1015_PID 0x1015 /* PI Device */
-#define PI_1016_PID 0x1016 /* PI Digital Servo Module */
-
-/*
- * Kondo Kagaku Co.Ltd.
- * http://www.kondo-robot.com/EN
- */
-#define KONDO_VID 0x165c
-#define KONDO_USB_SERIAL_PID 0x0002
-
-/*
- * Bayer Ascensia Contour blood glucose meter USB-converter cable.
- * http://winglucofacts.com/cables/
- */
-#define BAYER_VID 0x1A79
-#define BAYER_CONTOUR_CABLE_PID 0x6001
-
-/*
- * The following are the values for the Matrix Orbital FTDI Range
- * Anything in this range will use an FT232RL.
- */
-#define MTXORB_VID 0x1B3D
-#define MTXORB_FTDI_RANGE_0100_PID 0x0100
-#define MTXORB_FTDI_RANGE_0101_PID 0x0101
-#define MTXORB_FTDI_RANGE_0102_PID 0x0102
-#define MTXORB_FTDI_RANGE_0103_PID 0x0103
-#define MTXORB_FTDI_RANGE_0104_PID 0x0104
-#define MTXORB_FTDI_RANGE_0105_PID 0x0105
-#define MTXORB_FTDI_RANGE_0106_PID 0x0106
-#define MTXORB_FTDI_RANGE_0107_PID 0x0107
-#define MTXORB_FTDI_RANGE_0108_PID 0x0108
-#define MTXORB_FTDI_RANGE_0109_PID 0x0109
-#define MTXORB_FTDI_RANGE_010A_PID 0x010A
-#define MTXORB_FTDI_RANGE_010B_PID 0x010B
-#define MTXORB_FTDI_RANGE_010C_PID 0x010C
-#define MTXORB_FTDI_RANGE_010D_PID 0x010D
-#define MTXORB_FTDI_RANGE_010E_PID 0x010E
-#define MTXORB_FTDI_RANGE_010F_PID 0x010F
-#define MTXORB_FTDI_RANGE_0110_PID 0x0110
-#define MTXORB_FTDI_RANGE_0111_PID 0x0111
-#define MTXORB_FTDI_RANGE_0112_PID 0x0112
-#define MTXORB_FTDI_RANGE_0113_PID 0x0113
-#define MTXORB_FTDI_RANGE_0114_PID 0x0114
-#define MTXORB_FTDI_RANGE_0115_PID 0x0115
-#define MTXORB_FTDI_RANGE_0116_PID 0x0116
-#define MTXORB_FTDI_RANGE_0117_PID 0x0117
-#define MTXORB_FTDI_RANGE_0118_PID 0x0118
-#define MTXORB_FTDI_RANGE_0119_PID 0x0119
-#define MTXORB_FTDI_RANGE_011A_PID 0x011A
-#define MTXORB_FTDI_RANGE_011B_PID 0x011B
-#define MTXORB_FTDI_RANGE_011C_PID 0x011C
-#define MTXORB_FTDI_RANGE_011D_PID 0x011D
-#define MTXORB_FTDI_RANGE_011E_PID 0x011E
-#define MTXORB_FTDI_RANGE_011F_PID 0x011F
-#define MTXORB_FTDI_RANGE_0120_PID 0x0120
-#define MTXORB_FTDI_RANGE_0121_PID 0x0121
-#define MTXORB_FTDI_RANGE_0122_PID 0x0122
-#define MTXORB_FTDI_RANGE_0123_PID 0x0123
-#define MTXORB_FTDI_RANGE_0124_PID 0x0124
-#define MTXORB_FTDI_RANGE_0125_PID 0x0125
-#define MTXORB_FTDI_RANGE_0126_PID 0x0126
-#define MTXORB_FTDI_RANGE_0127_PID 0x0127
-#define MTXORB_FTDI_RANGE_0128_PID 0x0128
-#define MTXORB_FTDI_RANGE_0129_PID 0x0129
-#define MTXORB_FTDI_RANGE_012A_PID 0x012A
-#define MTXORB_FTDI_RANGE_012B_PID 0x012B
-#define MTXORB_FTDI_RANGE_012C_PID 0x012C
-#define MTXORB_FTDI_RANGE_012D_PID 0x012D
-#define MTXORB_FTDI_RANGE_012E_PID 0x012E
-#define MTXORB_FTDI_RANGE_012F_PID 0x012F
-#define MTXORB_FTDI_RANGE_0130_PID 0x0130
-#define MTXORB_FTDI_RANGE_0131_PID 0x0131
-#define MTXORB_FTDI_RANGE_0132_PID 0x0132
-#define MTXORB_FTDI_RANGE_0133_PID 0x0133
-#define MTXORB_FTDI_RANGE_0134_PID 0x0134
-#define MTXORB_FTDI_RANGE_0135_PID 0x0135
-#define MTXORB_FTDI_RANGE_0136_PID 0x0136
-#define MTXORB_FTDI_RANGE_0137_PID 0x0137
-#define MTXORB_FTDI_RANGE_0138_PID 0x0138
-#define MTXORB_FTDI_RANGE_0139_PID 0x0139
-#define MTXORB_FTDI_RANGE_013A_PID 0x013A
-#define MTXORB_FTDI_RANGE_013B_PID 0x013B
-#define MTXORB_FTDI_RANGE_013C_PID 0x013C
-#define MTXORB_FTDI_RANGE_013D_PID 0x013D
-#define MTXORB_FTDI_RANGE_013E_PID 0x013E
-#define MTXORB_FTDI_RANGE_013F_PID 0x013F
-#define MTXORB_FTDI_RANGE_0140_PID 0x0140
-#define MTXORB_FTDI_RANGE_0141_PID 0x0141
-#define MTXORB_FTDI_RANGE_0142_PID 0x0142
-#define MTXORB_FTDI_RANGE_0143_PID 0x0143
-#define MTXORB_FTDI_RANGE_0144_PID 0x0144
-#define MTXORB_FTDI_RANGE_0145_PID 0x0145
-#define MTXORB_FTDI_RANGE_0146_PID 0x0146
-#define MTXORB_FTDI_RANGE_0147_PID 0x0147
-#define MTXORB_FTDI_RANGE_0148_PID 0x0148
-#define MTXORB_FTDI_RANGE_0149_PID 0x0149
-#define MTXORB_FTDI_RANGE_014A_PID 0x014A
-#define MTXORB_FTDI_RANGE_014B_PID 0x014B
-#define MTXORB_FTDI_RANGE_014C_PID 0x014C
-#define MTXORB_FTDI_RANGE_014D_PID 0x014D
-#define MTXORB_FTDI_RANGE_014E_PID 0x014E
-#define MTXORB_FTDI_RANGE_014F_PID 0x014F
-#define MTXORB_FTDI_RANGE_0150_PID 0x0150
-#define MTXORB_FTDI_RANGE_0151_PID 0x0151
-#define MTXORB_FTDI_RANGE_0152_PID 0x0152
-#define MTXORB_FTDI_RANGE_0153_PID 0x0153
-#define MTXORB_FTDI_RANGE_0154_PID 0x0154
-#define MTXORB_FTDI_RANGE_0155_PID 0x0155
-#define MTXORB_FTDI_RANGE_0156_PID 0x0156
-#define MTXORB_FTDI_RANGE_0157_PID 0x0157
-#define MTXORB_FTDI_RANGE_0158_PID 0x0158
-#define MTXORB_FTDI_RANGE_0159_PID 0x0159
-#define MTXORB_FTDI_RANGE_015A_PID 0x015A
-#define MTXORB_FTDI_RANGE_015B_PID 0x015B
-#define MTXORB_FTDI_RANGE_015C_PID 0x015C
-#define MTXORB_FTDI_RANGE_015D_PID 0x015D
-#define MTXORB_FTDI_RANGE_015E_PID 0x015E
-#define MTXORB_FTDI_RANGE_015F_PID 0x015F
-#define MTXORB_FTDI_RANGE_0160_PID 0x0160
-#define MTXORB_FTDI_RANGE_0161_PID 0x0161
-#define MTXORB_FTDI_RANGE_0162_PID 0x0162
-#define MTXORB_FTDI_RANGE_0163_PID 0x0163
-#define MTXORB_FTDI_RANGE_0164_PID 0x0164
-#define MTXORB_FTDI_RANGE_0165_PID 0x0165
-#define MTXORB_FTDI_RANGE_0166_PID 0x0166
-#define MTXORB_FTDI_RANGE_0167_PID 0x0167
-#define MTXORB_FTDI_RANGE_0168_PID 0x0168
-#define MTXORB_FTDI_RANGE_0169_PID 0x0169
-#define MTXORB_FTDI_RANGE_016A_PID 0x016A
-#define MTXORB_FTDI_RANGE_016B_PID 0x016B
-#define MTXORB_FTDI_RANGE_016C_PID 0x016C
-#define MTXORB_FTDI_RANGE_016D_PID 0x016D
-#define MTXORB_FTDI_RANGE_016E_PID 0x016E
-#define MTXORB_FTDI_RANGE_016F_PID 0x016F
-#define MTXORB_FTDI_RANGE_0170_PID 0x0170
-#define MTXORB_FTDI_RANGE_0171_PID 0x0171
-#define MTXORB_FTDI_RANGE_0172_PID 0x0172
-#define MTXORB_FTDI_RANGE_0173_PID 0x0173
-#define MTXORB_FTDI_RANGE_0174_PID 0x0174
-#define MTXORB_FTDI_RANGE_0175_PID 0x0175
-#define MTXORB_FTDI_RANGE_0176_PID 0x0176
-#define MTXORB_FTDI_RANGE_0177_PID 0x0177
-#define MTXORB_FTDI_RANGE_0178_PID 0x0178
-#define MTXORB_FTDI_RANGE_0179_PID 0x0179
-#define MTXORB_FTDI_RANGE_017A_PID 0x017A
-#define MTXORB_FTDI_RANGE_017B_PID 0x017B
-#define MTXORB_FTDI_RANGE_017C_PID 0x017C
-#define MTXORB_FTDI_RANGE_017D_PID 0x017D
-#define MTXORB_FTDI_RANGE_017E_PID 0x017E
-#define MTXORB_FTDI_RANGE_017F_PID 0x017F
-#define MTXORB_FTDI_RANGE_0180_PID 0x0180
-#define MTXORB_FTDI_RANGE_0181_PID 0x0181
-#define MTXORB_FTDI_RANGE_0182_PID 0x0182
-#define MTXORB_FTDI_RANGE_0183_PID 0x0183
-#define MTXORB_FTDI_RANGE_0184_PID 0x0184
-#define MTXORB_FTDI_RANGE_0185_PID 0x0185
-#define MTXORB_FTDI_RANGE_0186_PID 0x0186
-#define MTXORB_FTDI_RANGE_0187_PID 0x0187
-#define MTXORB_FTDI_RANGE_0188_PID 0x0188
-#define MTXORB_FTDI_RANGE_0189_PID 0x0189
-#define MTXORB_FTDI_RANGE_018A_PID 0x018A
-#define MTXORB_FTDI_RANGE_018B_PID 0x018B
-#define MTXORB_FTDI_RANGE_018C_PID 0x018C
-#define MTXORB_FTDI_RANGE_018D_PID 0x018D
-#define MTXORB_FTDI_RANGE_018E_PID 0x018E
-#define MTXORB_FTDI_RANGE_018F_PID 0x018F
-#define MTXORB_FTDI_RANGE_0190_PID 0x0190
-#define MTXORB_FTDI_RANGE_0191_PID 0x0191
-#define MTXORB_FTDI_RANGE_0192_PID 0x0192
-#define MTXORB_FTDI_RANGE_0193_PID 0x0193
-#define MTXORB_FTDI_RANGE_0194_PID 0x0194
-#define MTXORB_FTDI_RANGE_0195_PID 0x0195
-#define MTXORB_FTDI_RANGE_0196_PID 0x0196
-#define MTXORB_FTDI_RANGE_0197_PID 0x0197
-#define MTXORB_FTDI_RANGE_0198_PID 0x0198
-#define MTXORB_FTDI_RANGE_0199_PID 0x0199
-#define MTXORB_FTDI_RANGE_019A_PID 0x019A
-#define MTXORB_FTDI_RANGE_019B_PID 0x019B
-#define MTXORB_FTDI_RANGE_019C_PID 0x019C
-#define MTXORB_FTDI_RANGE_019D_PID 0x019D
-#define MTXORB_FTDI_RANGE_019E_PID 0x019E
-#define MTXORB_FTDI_RANGE_019F_PID 0x019F
-#define MTXORB_FTDI_RANGE_01A0_PID 0x01A0
-#define MTXORB_FTDI_RANGE_01A1_PID 0x01A1
-#define MTXORB_FTDI_RANGE_01A2_PID 0x01A2
-#define MTXORB_FTDI_RANGE_01A3_PID 0x01A3
-#define MTXORB_FTDI_RANGE_01A4_PID 0x01A4
-#define MTXORB_FTDI_RANGE_01A5_PID 0x01A5
-#define MTXORB_FTDI_RANGE_01A6_PID 0x01A6
-#define MTXORB_FTDI_RANGE_01A7_PID 0x01A7
-#define MTXORB_FTDI_RANGE_01A8_PID 0x01A8
-#define MTXORB_FTDI_RANGE_01A9_PID 0x01A9
-#define MTXORB_FTDI_RANGE_01AA_PID 0x01AA
-#define MTXORB_FTDI_RANGE_01AB_PID 0x01AB
-#define MTXORB_FTDI_RANGE_01AC_PID 0x01AC
-#define MTXORB_FTDI_RANGE_01AD_PID 0x01AD
-#define MTXORB_FTDI_RANGE_01AE_PID 0x01AE
-#define MTXORB_FTDI_RANGE_01AF_PID 0x01AF
-#define MTXORB_FTDI_RANGE_01B0_PID 0x01B0
-#define MTXORB_FTDI_RANGE_01B1_PID 0x01B1
-#define MTXORB_FTDI_RANGE_01B2_PID 0x01B2
-#define MTXORB_FTDI_RANGE_01B3_PID 0x01B3
-#define MTXORB_FTDI_RANGE_01B4_PID 0x01B4
-#define MTXORB_FTDI_RANGE_01B5_PID 0x01B5
-#define MTXORB_FTDI_RANGE_01B6_PID 0x01B6
-#define MTXORB_FTDI_RANGE_01B7_PID 0x01B7
-#define MTXORB_FTDI_RANGE_01B8_PID 0x01B8
-#define MTXORB_FTDI_RANGE_01B9_PID 0x01B9
-#define MTXORB_FTDI_RANGE_01BA_PID 0x01BA
-#define MTXORB_FTDI_RANGE_01BB_PID 0x01BB
-#define MTXORB_FTDI_RANGE_01BC_PID 0x01BC
-#define MTXORB_FTDI_RANGE_01BD_PID 0x01BD
-#define MTXORB_FTDI_RANGE_01BE_PID 0x01BE
-#define MTXORB_FTDI_RANGE_01BF_PID 0x01BF
-#define MTXORB_FTDI_RANGE_01C0_PID 0x01C0
-#define MTXORB_FTDI_RANGE_01C1_PID 0x01C1
-#define MTXORB_FTDI_RANGE_01C2_PID 0x01C2
-#define MTXORB_FTDI_RANGE_01C3_PID 0x01C3
-#define MTXORB_FTDI_RANGE_01C4_PID 0x01C4
-#define MTXORB_FTDI_RANGE_01C5_PID 0x01C5
-#define MTXORB_FTDI_RANGE_01C6_PID 0x01C6
-#define MTXORB_FTDI_RANGE_01C7_PID 0x01C7
-#define MTXORB_FTDI_RANGE_01C8_PID 0x01C8
-#define MTXORB_FTDI_RANGE_01C9_PID 0x01C9
-#define MTXORB_FTDI_RANGE_01CA_PID 0x01CA
-#define MTXORB_FTDI_RANGE_01CB_PID 0x01CB
-#define MTXORB_FTDI_RANGE_01CC_PID 0x01CC
-#define MTXORB_FTDI_RANGE_01CD_PID 0x01CD
-#define MTXORB_FTDI_RANGE_01CE_PID 0x01CE
-#define MTXORB_FTDI_RANGE_01CF_PID 0x01CF
-#define MTXORB_FTDI_RANGE_01D0_PID 0x01D0
-#define MTXORB_FTDI_RANGE_01D1_PID 0x01D1
-#define MTXORB_FTDI_RANGE_01D2_PID 0x01D2
-#define MTXORB_FTDI_RANGE_01D3_PID 0x01D3
-#define MTXORB_FTDI_RANGE_01D4_PID 0x01D4
-#define MTXORB_FTDI_RANGE_01D5_PID 0x01D5
-#define MTXORB_FTDI_RANGE_01D6_PID 0x01D6
-#define MTXORB_FTDI_RANGE_01D7_PID 0x01D7
-#define MTXORB_FTDI_RANGE_01D8_PID 0x01D8
-#define MTXORB_FTDI_RANGE_01D9_PID 0x01D9
-#define MTXORB_FTDI_RANGE_01DA_PID 0x01DA
-#define MTXORB_FTDI_RANGE_01DB_PID 0x01DB
-#define MTXORB_FTDI_RANGE_01DC_PID 0x01DC
-#define MTXORB_FTDI_RANGE_01DD_PID 0x01DD
-#define MTXORB_FTDI_RANGE_01DE_PID 0x01DE
-#define MTXORB_FTDI_RANGE_01DF_PID 0x01DF
-#define MTXORB_FTDI_RANGE_01E0_PID 0x01E0
-#define MTXORB_FTDI_RANGE_01E1_PID 0x01E1
-#define MTXORB_FTDI_RANGE_01E2_PID 0x01E2
-#define MTXORB_FTDI_RANGE_01E3_PID 0x01E3
-#define MTXORB_FTDI_RANGE_01E4_PID 0x01E4
-#define MTXORB_FTDI_RANGE_01E5_PID 0x01E5
-#define MTXORB_FTDI_RANGE_01E6_PID 0x01E6
-#define MTXORB_FTDI_RANGE_01E7_PID 0x01E7
-#define MTXORB_FTDI_RANGE_01E8_PID 0x01E8
-#define MTXORB_FTDI_RANGE_01E9_PID 0x01E9
-#define MTXORB_FTDI_RANGE_01EA_PID 0x01EA
-#define MTXORB_FTDI_RANGE_01EB_PID 0x01EB
-#define MTXORB_FTDI_RANGE_01EC_PID 0x01EC
-#define MTXORB_FTDI_RANGE_01ED_PID 0x01ED
-#define MTXORB_FTDI_RANGE_01EE_PID 0x01EE
-#define MTXORB_FTDI_RANGE_01EF_PID 0x01EF
-#define MTXORB_FTDI_RANGE_01F0_PID 0x01F0
-#define MTXORB_FTDI_RANGE_01F1_PID 0x01F1
-#define MTXORB_FTDI_RANGE_01F2_PID 0x01F2
-#define MTXORB_FTDI_RANGE_01F3_PID 0x01F3
-#define MTXORB_FTDI_RANGE_01F4_PID 0x01F4
-#define MTXORB_FTDI_RANGE_01F5_PID 0x01F5
-#define MTXORB_FTDI_RANGE_01F6_PID 0x01F6
-#define MTXORB_FTDI_RANGE_01F7_PID 0x01F7
-#define MTXORB_FTDI_RANGE_01F8_PID 0x01F8
-#define MTXORB_FTDI_RANGE_01F9_PID 0x01F9
-#define MTXORB_FTDI_RANGE_01FA_PID 0x01FA
-#define MTXORB_FTDI_RANGE_01FB_PID 0x01FB
-#define MTXORB_FTDI_RANGE_01FC_PID 0x01FC
-#define MTXORB_FTDI_RANGE_01FD_PID 0x01FD
-#define MTXORB_FTDI_RANGE_01FE_PID 0x01FE
-#define MTXORB_FTDI_RANGE_01FF_PID 0x01FF
-
-
-
-/*
- * The Mobility Lab (TML)
- * Submitted by Pierre Castella
- */
-#define TML_VID 0x1B91 /* Vendor ID */
-#define TML_USB_SERIAL_PID 0x0064 /* USB - Serial Converter */
-
-/* Alti-2 products http://www.alti-2.com */
-#define ALTI2_VID 0x1BC9
-#define ALTI2_N3_PID 0x6001 /* Neptune 3 */
-
-/*
- * Ionics PlugComputer
- */
-#define IONICS_VID 0x1c0c
-#define IONICS_PLUGCOMPUTER_PID 0x0102
-
-/*
- * Dresden Elektronik Sensor Terminal Board
- */
-#define DE_VID 0x1cf1 /* Vendor ID */
-#define STB_PID 0x0001 /* Sensor Terminal Board */
-#define WHT_PID 0x0004 /* Wireless Handheld Terminal */
-
-/*
- * STMicroelectonics
- */
-#define ST_VID 0x0483
-#define ST_STMCLT1030_PID 0x3747 /* ST Micro Connect Lite STMCLT1030 */
-
-/*
- * Papouch products (http://www.papouch.com/)
- * Submitted by Folkert van Heusden
- */
-
-#define PAPOUCH_VID 0x5050 /* Vendor ID */
-#define PAPOUCH_SB485_PID 0x0100 /* Papouch SB485 USB-485/422 Converter */
-#define PAPOUCH_AP485_PID 0x0101 /* AP485 USB-RS485 Converter */
-#define PAPOUCH_SB422_PID 0x0102 /* Papouch SB422 USB-RS422 Converter */
-#define PAPOUCH_SB485_2_PID 0x0103 /* Papouch SB485 USB-485/422 Converter */
-#define PAPOUCH_AP485_2_PID 0x0104 /* AP485 USB-RS485 Converter */
-#define PAPOUCH_SB422_2_PID 0x0105 /* Papouch SB422 USB-RS422 Converter */
-#define PAPOUCH_SB485S_PID 0x0106 /* Papouch SB485S USB-485/422 Converter */
-#define PAPOUCH_SB485C_PID 0x0107 /* Papouch SB485C USB-485/422 Converter */
-#define PAPOUCH_LEC_PID 0x0300 /* LEC USB Converter */
-#define PAPOUCH_SB232_PID 0x0301 /* Papouch SB232 USB-RS232 Converter */
-#define PAPOUCH_TMU_PID 0x0400 /* TMU USB Thermometer */
-#define PAPOUCH_IRAMP_PID 0x0500 /* Papouch IRAmp Duplex */
-#define PAPOUCH_DRAK5_PID 0x0700 /* Papouch DRAK5 */
-#define PAPOUCH_QUIDO8x8_PID 0x0800 /* Papouch Quido 8/8 Module */
-#define PAPOUCH_QUIDO4x4_PID 0x0900 /* Papouch Quido 4/4 Module */
-#define PAPOUCH_QUIDO2x2_PID 0x0a00 /* Papouch Quido 2/2 Module */
-#define PAPOUCH_QUIDO10x1_PID 0x0b00 /* Papouch Quido 10/1 Module */
-#define PAPOUCH_QUIDO30x3_PID 0x0c00 /* Papouch Quido 30/3 Module */
-#define PAPOUCH_QUIDO60x3_PID 0x0d00 /* Papouch Quido 60(100)/3 Module */
-#define PAPOUCH_QUIDO2x16_PID 0x0e00 /* Papouch Quido 2/16 Module */
-#define PAPOUCH_QUIDO3x32_PID 0x0f00 /* Papouch Quido 3/32 Module */
-#define PAPOUCH_DRAK6_PID 0x1000 /* Papouch DRAK6 */
-#define PAPOUCH_UPSUSB_PID 0x8000 /* Papouch UPS-USB adapter */
-#define PAPOUCH_MU_PID 0x8001 /* MU controller */
-#define PAPOUCH_SIMUKEY_PID 0x8002 /* Papouch SimuKey */
-#define PAPOUCH_AD4USB_PID 0x8003 /* AD4USB Measurement Module */
-#define PAPOUCH_GMUX_PID 0x8004 /* Papouch GOLIATH MUX */
-#define PAPOUCH_GMSR_PID 0x8005 /* Papouch GOLIATH MSR */
-
-/*
- * Marvell SheevaPlug
- */
-#define MARVELL_VID 0x9e88
-#define MARVELL_SHEEVAPLUG_PID 0x9e8f
-
-/*
- * Evolution Robotics products (http://www.evolution.com/).
- * Submitted by Shawn M. Lavelle.
- */
-#define EVOLUTION_VID 0xDEEE /* Vendor ID */
-#define EVOLUTION_ER1_PID 0x0300 /* ER1 Control Module */
-#define EVO_8U232AM_PID 0x02FF /* Evolution robotics RCM2 (FT232AM)*/
-#define EVO_HYBRID_PID 0x0302 /* Evolution robotics RCM4 PID (FT232BM)*/
-#define EVO_RCM4_PID 0x0303 /* Evolution robotics RCM4 PID */
-
-/*
- * MJS Gadgets HD Radio / XM Radio / Sirius Radio interfaces (using VID 0x0403)
- */
-#define MJSG_GENERIC_PID 0x9378
-#define MJSG_SR_RADIO_PID 0x9379
-#define MJSG_XM_RADIO_PID 0x937A
-#define MJSG_HD_RADIO_PID 0x937C
-
-/*
- * D.O.Tec products (http://www.directout.eu)
- */
-#define FTDI_DOTEC_PID 0x9868
-
-/*
- * Xverve Signalyzer tools (http://www.signalyzer.com/)
- */
-#define XVERVE_SIGNALYZER_ST_PID 0xBCA0
-#define XVERVE_SIGNALYZER_SLITE_PID 0xBCA1
-#define XVERVE_SIGNALYZER_SH2_PID 0xBCA2
-#define XVERVE_SIGNALYZER_SH4_PID 0xBCA4
-
-/*
- * Segway Robotic Mobility Platform USB interface (using VID 0x0403)
- * Submitted by John G. Rogers
- */
-#define SEGWAY_RMP200_PID 0xe729
-
-
-/*
- * Accesio USB Data Acquisition products (http://www.accesio.com/)
- */
-#define ACCESIO_COM4SM_PID 0xD578
-
-/* www.sciencescope.co.uk educational dataloggers */
-#define FTDI_SCIENCESCOPE_LOGBOOKML_PID 0xFF18
-#define FTDI_SCIENCESCOPE_LS_LOGBOOK_PID 0xFF1C
-#define FTDI_SCIENCESCOPE_HS_LOGBOOK_PID 0xFF1D
-
-/*
- * Milkymist One JTAG/Serial
- */
-#define QIHARDWARE_VID 0x20B7
-#define MILKYMISTONE_JTAGSERIAL_PID 0x0713
-
-/*
- * CTI GmbH RS485 Converter http://www.cti-lean.com/
- */
-/* USB-485-Mini*/
-#define FTDI_CTI_MINI_PID 0xF608
-/* USB-Nano-485*/
-#define FTDI_CTI_NANO_PID 0xF60B
-
-/*
- * ZeitControl cardsystems GmbH rfid-readers http://zeitconrol.de
- */
-/* TagTracer MIFARE*/
-#define FTDI_ZEITCONTROL_TAGTRACE_MIFARE_PID 0xF7C0
-
-/*
- * Rainforest Automation
- */
-/* ZigBee controller */
-#define FTDI_RF_R106 0x8A28
-
-/*
- * Product: HCP HIT GPRS modem
- * Manufacturer: HCP d.o.o.
- * ATI command output: Cinterion MC55i
- */
-#define FTDI_CINTERION_MC55I_PID 0xA951
diff --git a/qemu/hw/usb/quirks-pl2303-ids.h b/qemu/hw/usb/quirks-pl2303-ids.h
deleted file mode 100644
index 8dbdb46ff..000000000
--- a/qemu/hw/usb/quirks-pl2303-ids.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Prolific PL2303 USB to serial adaptor driver header file
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- */
-
-#define BENQ_VENDOR_ID 0x04a5
-#define BENQ_PRODUCT_ID_S81 0x4027
-
-#define PL2303_VENDOR_ID 0x067b
-#define PL2303_PRODUCT_ID 0x2303
-#define PL2303_PRODUCT_ID_RSAQ2 0x04bb
-#define PL2303_PRODUCT_ID_DCU11 0x1234
-#define PL2303_PRODUCT_ID_PHAROS 0xaaa0
-#define PL2303_PRODUCT_ID_RSAQ3 0xaaa2
-#define PL2303_PRODUCT_ID_ALDIGA 0x0611
-#define PL2303_PRODUCT_ID_MMX 0x0612
-#define PL2303_PRODUCT_ID_GPRS 0x0609
-#define PL2303_PRODUCT_ID_HCR331 0x331a
-#define PL2303_PRODUCT_ID_MOTOROLA 0x0307
-
-#define ATEN_VENDOR_ID 0x0557
-#define ATEN_VENDOR_ID2 0x0547
-#define ATEN_PRODUCT_ID 0x2008
-
-#define IODATA_VENDOR_ID 0x04bb
-#define IODATA_PRODUCT_ID 0x0a03
-#define IODATA_PRODUCT_ID_RSAQ5 0x0a0e
-
-#define ELCOM_VENDOR_ID 0x056e
-#define ELCOM_PRODUCT_ID 0x5003
-#define ELCOM_PRODUCT_ID_UCSGT 0x5004
-
-#define ITEGNO_VENDOR_ID 0x0eba
-#define ITEGNO_PRODUCT_ID 0x1080
-#define ITEGNO_PRODUCT_ID_2080 0x2080
-
-#define MA620_VENDOR_ID 0x0df7
-#define MA620_PRODUCT_ID 0x0620
-
-#define RATOC_VENDOR_ID 0x0584
-#define RATOC_PRODUCT_ID 0xb000
-
-#define TRIPP_VENDOR_ID 0x2478
-#define TRIPP_PRODUCT_ID 0x2008
-
-#define RADIOSHACK_VENDOR_ID 0x1453
-#define RADIOSHACK_PRODUCT_ID 0x4026
-
-#define DCU10_VENDOR_ID 0x0731
-#define DCU10_PRODUCT_ID 0x0528
-
-#define SITECOM_VENDOR_ID 0x6189
-#define SITECOM_PRODUCT_ID 0x2068
-
-/* Alcatel OT535/735 USB cable */
-#define ALCATEL_VENDOR_ID 0x11f7
-#define ALCATEL_PRODUCT_ID 0x02df
-
-/* Samsung I330 phone cradle */
-#define SAMSUNG_VENDOR_ID 0x04e8
-#define SAMSUNG_PRODUCT_ID 0x8001
-
-#define SIEMENS_VENDOR_ID 0x11f5
-#define SIEMENS_PRODUCT_ID_SX1 0x0001
-#define SIEMENS_PRODUCT_ID_X65 0x0003
-#define SIEMENS_PRODUCT_ID_X75 0x0004
-#define SIEMENS_PRODUCT_ID_EF81 0x0005
-
-#define SYNTECH_VENDOR_ID 0x0745
-#define SYNTECH_PRODUCT_ID 0x0001
-
-/* Nokia CA-42 Cable */
-#define NOKIA_CA42_VENDOR_ID 0x078b
-#define NOKIA_CA42_PRODUCT_ID 0x1234
-
-/* CA-42 CLONE Cable www.ca-42.com chipset: Prolific Technology Inc */
-#define CA_42_CA42_VENDOR_ID 0x10b5
-#define CA_42_CA42_PRODUCT_ID 0xac70
-
-#define SAGEM_VENDOR_ID 0x079b
-#define SAGEM_PRODUCT_ID 0x0027
-
-/* Leadtek GPS 9531 (ID 0413:2101) */
-#define LEADTEK_VENDOR_ID 0x0413
-#define LEADTEK_9531_PRODUCT_ID 0x2101
-
-/* USB GSM cable from Speed Dragon Multimedia, Ltd */
-#define SPEEDDRAGON_VENDOR_ID 0x0e55
-#define SPEEDDRAGON_PRODUCT_ID 0x110b
-
-/* DATAPILOT Universal-2 Phone Cable */
-#define DATAPILOT_U2_VENDOR_ID 0x0731
-#define DATAPILOT_U2_PRODUCT_ID 0x2003
-
-/* Belkin "F5U257" Serial Adapter */
-#define BELKIN_VENDOR_ID 0x050d
-#define BELKIN_PRODUCT_ID 0x0257
-
-/* Alcor Micro Corp. USB 2.0 TO RS-232 */
-#define ALCOR_VENDOR_ID 0x058F
-#define ALCOR_PRODUCT_ID 0x9720
-
-/* Willcom WS002IN Data Driver (by NetIndex Inc.) */
-#define WS002IN_VENDOR_ID 0x11f6
-#define WS002IN_PRODUCT_ID 0x2001
-
-/* Corega CG-USBRS232R Serial Adapter */
-#define COREGA_VENDOR_ID 0x07aa
-#define COREGA_PRODUCT_ID 0x002a
-
-/* Y.C. Cable U.S.A., Inc - USB to RS-232 */
-#define YCCABLE_VENDOR_ID 0x05ad
-#define YCCABLE_PRODUCT_ID 0x0fba
-
-/* "Superial" USB - Serial */
-#define SUPERIAL_VENDOR_ID 0x5372
-#define SUPERIAL_PRODUCT_ID 0x2303
-
-/* Hewlett-Packard LD220-HP POS Pole Display */
-#define HP_VENDOR_ID 0x03f0
-#define HP_LD220_PRODUCT_ID 0x3524
-
-/* Cressi Edy (diving computer) PC interface */
-#define CRESSI_VENDOR_ID 0x04b8
-#define CRESSI_EDY_PRODUCT_ID 0x0521
-
-/* Zeagle dive computer interface */
-#define ZEAGLE_VENDOR_ID 0x04b8
-#define ZEAGLE_N2ITION3_PRODUCT_ID 0x0522
-
-/* Sony, USB data cable for CMD-Jxx mobile phones */
-#define SONY_VENDOR_ID 0x054c
-#define SONY_QN3USB_PRODUCT_ID 0x0437
-
-/* Sanwa KB-USB2 multimeter cable (ID: 11ad:0001) */
-#define SANWA_VENDOR_ID 0x11ad
-#define SANWA_PRODUCT_ID 0x0001
-
-/* ADLINK ND-6530 RS232,RS485 and RS422 adapter */
-#define ADLINK_VENDOR_ID 0x0b63
-#define ADLINK_ND6530_PRODUCT_ID 0x6530
-
-/* SMART USB Serial Adapter */
-#define SMART_VENDOR_ID 0x0b8c
-#define SMART_PRODUCT_ID 0x2303
diff --git a/qemu/hw/usb/quirks.c b/qemu/hw/usb/quirks.c
deleted file mode 100644
index 38a9c5634..000000000
--- a/qemu/hw/usb/quirks.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * USB quirk handling
- *
- * Copyright (c) 2012 Red Hat, Inc.
- *
- * Red Hat Authors:
- * Hans de Goede <hdegoede@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "quirks.h"
-#include "hw/usb.h"
-
-static bool usb_id_match(const struct usb_device_id *ids,
- uint16_t vendor_id, uint16_t product_id,
- uint8_t interface_class, uint8_t interface_subclass,
- uint8_t interface_protocol) {
- int i;
-
- for (i = 0; ids[i].vendor_id != -1; i++) {
- if (ids[i].vendor_id == vendor_id &&
- ids[i].product_id == product_id &&
- (ids[i].interface_class == -1 ||
- (ids[i].interface_class == interface_class &&
- ids[i].interface_subclass == interface_subclass &&
- ids[i].interface_protocol == interface_protocol))) {
- return true;
- }
- }
- return false;
-}
-
-int usb_get_quirks(uint16_t vendor_id, uint16_t product_id,
- uint8_t interface_class, uint8_t interface_subclass,
- uint8_t interface_protocol)
-{
- int quirks = 0;
-
- if (usb_id_match(usbredir_raw_serial_ids, vendor_id, product_id,
- interface_class, interface_subclass, interface_protocol)) {
- quirks |= USB_QUIRK_BUFFER_BULK_IN;
- }
- if (usb_id_match(usbredir_ftdi_serial_ids, vendor_id, product_id,
- interface_class, interface_subclass, interface_protocol)) {
- quirks |= USB_QUIRK_BUFFER_BULK_IN | USB_QUIRK_IS_FTDI;
- }
-
- return quirks;
-}
diff --git a/qemu/hw/usb/quirks.h b/qemu/hw/usb/quirks.h
deleted file mode 100644
index 8dc606552..000000000
--- a/qemu/hw/usb/quirks.h
+++ /dev/null
@@ -1,910 +0,0 @@
-/*
- * USB quirk handling
- *
- * Copyright (c) 2012 Red Hat, Inc.
- *
- * Red Hat Authors:
- * Hans de Goede <hdegoede@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-/* 1 on 1 copy of linux/drivers/usb/serial/ftdi_sio_ids.h */
-#include "quirks-ftdi-ids.h"
-/* 1 on 1 copy of linux/drivers/usb/serial/pl2303.h */
-#include "quirks-pl2303-ids.h"
-
-struct usb_device_id {
- int vendor_id;
- int product_id;
- int interface_class;
- int interface_subclass;
- int interface_protocol;
-};
-
-#define USB_DEVICE(vendor, product) \
- .vendor_id = vendor, .product_id = product, .interface_class = -1,
-
-#define USB_DEVICE_AND_INTERFACE_INFO(vend, prod, iclass, isubclass, iproto) \
- .vendor_id = vend, .product_id = prod, .interface_class = iclass, \
- .interface_subclass = isubclass, .interface_protocol = iproto
-
-static const struct usb_device_id usbredir_raw_serial_ids[] = {
- /*
- * Silicon Laboratories CP210x USB to RS232 serial adapter ids
- * copied from linux/drivers/usb/serial/cp210x.c
- *
- * Copyright (C) 2005 Craig Shelley (craig@microtron.org.uk)
- */
- { USB_DEVICE(0x045B, 0x0053) }, /* Renesas RX610 RX-Stick */
- { USB_DEVICE(0x0471, 0x066A) }, /* AKTAKOM ACE-1001 cable */
- { USB_DEVICE(0x0489, 0xE000) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM Mobile */
- { USB_DEVICE(0x0489, 0xE003) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM Mobile */
- { USB_DEVICE(0x0745, 0x1000) }, /* CipherLab USB CCD Barcode Scanner 1000 */
- { USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */
- { USB_DEVICE(0x08FD, 0x000A) }, /* Digianswer A/S , ZigBee/802.15.4 MAC Device */
- { USB_DEVICE(0x0BED, 0x1100) }, /* MEI (TM) Cashflow-SC Bill/Voucher Acceptor */
- { USB_DEVICE(0x0BED, 0x1101) }, /* MEI series 2000 Combo Acceptor */
- { USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */
- { USB_DEVICE(0x0FCF, 0x1004) }, /* Dynastream ANT2USB */
- { USB_DEVICE(0x0FCF, 0x1006) }, /* Dynastream ANT development board */
- { USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */
- { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */
- { USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */
- { USB_DEVICE(0x10C4, 0x0F91) }, /* Vstabi */
- { USB_DEVICE(0x10C4, 0x1101) }, /* Arkham Technology DS101 Bus Monitor */
- { USB_DEVICE(0x10C4, 0x1601) }, /* Arkham Technology DS101 Adapter */
- { USB_DEVICE(0x10C4, 0x800A) }, /* SPORTident BSM7-D-USB main station */
- { USB_DEVICE(0x10C4, 0x803B) }, /* Pololu USB-serial converter */
- { USB_DEVICE(0x10C4, 0x8044) }, /* Cygnal Debug Adapter */
- { USB_DEVICE(0x10C4, 0x804E) }, /* Software Bisque Paramount ME build-in converter */
- { USB_DEVICE(0x10C4, 0x8053) }, /* Enfora EDG1228 */
- { USB_DEVICE(0x10C4, 0x8054) }, /* Enfora GSM2228 */
- { USB_DEVICE(0x10C4, 0x8066) }, /* Argussoft In-System Programmer */
- { USB_DEVICE(0x10C4, 0x806F) }, /* IMS USB to RS422 Converter Cable */
- { USB_DEVICE(0x10C4, 0x807A) }, /* Crumb128 board */
- { USB_DEVICE(0x10C4, 0x80C4) }, /* Cygnal Integrated Products, Inc., Optris infrared thermometer */
- { USB_DEVICE(0x10C4, 0x80CA) }, /* Degree Controls Inc */
- { USB_DEVICE(0x10C4, 0x80DD) }, /* Tracient RFID */
- { USB_DEVICE(0x10C4, 0x80F6) }, /* Suunto sports instrument */
- { USB_DEVICE(0x10C4, 0x8115) }, /* Arygon NFC/Mifare Reader */
- { USB_DEVICE(0x10C4, 0x813D) }, /* Burnside Telecom Deskmobile */
- { USB_DEVICE(0x10C4, 0x813F) }, /* Tams Master Easy Control */
- { USB_DEVICE(0x10C4, 0x814A) }, /* West Mountain Radio RIGblaster P&P */
- { USB_DEVICE(0x10C4, 0x814B) }, /* West Mountain Radio RIGtalk */
- { USB_DEVICE(0x10C4, 0x8156) }, /* B&G H3000 link cable */
- { USB_DEVICE(0x10C4, 0x815E) }, /* Helicomm IP-Link 1220-DVM */
- { USB_DEVICE(0x10C4, 0x815F) }, /* Timewave HamLinkUSB */
- { USB_DEVICE(0x10C4, 0x818B) }, /* AVIT Research USB to TTL */
- { USB_DEVICE(0x10C4, 0x819F) }, /* MJS USB Toslink Switcher */
- { USB_DEVICE(0x10C4, 0x81A6) }, /* ThinkOptics WavIt */
- { USB_DEVICE(0x10C4, 0x81A9) }, /* Multiplex RC Interface */
- { USB_DEVICE(0x10C4, 0x81AC) }, /* MSD Dash Hawk */
- { USB_DEVICE(0x10C4, 0x81AD) }, /* INSYS USB Modem */
- { USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */
- { USB_DEVICE(0x10C4, 0x81E2) }, /* Lipowsky Industrie Elektronik GmbH, Baby-LIN */
- { USB_DEVICE(0x10C4, 0x81E7) }, /* Aerocomm Radio */
- { USB_DEVICE(0x10C4, 0x81E8) }, /* Zephyr Bioharness */
- { USB_DEVICE(0x10C4, 0x81F2) }, /* C1007 HF band RFID controller */
- { USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */
- { USB_DEVICE(0x10C4, 0x822B) }, /* Modem EDGE(GSM) Comander 2 */
- { USB_DEVICE(0x10C4, 0x826B) }, /* Cygnal Integrated Products, Inc., Fasttrax GPS demonstration module */
- { USB_DEVICE(0x10C4, 0x8293) }, /* Telegesis ETRX2USB */
- { USB_DEVICE(0x10C4, 0x82F9) }, /* Procyon AVS */
- { USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */
- { USB_DEVICE(0x10C4, 0x8382) }, /* Cygnal Integrated Products, Inc. */
- { USB_DEVICE(0x10C4, 0x83A8) }, /* Amber Wireless AMB2560 */
- { USB_DEVICE(0x10C4, 0x83D8) }, /* DekTec DTA Plus VHF/UHF Booster/Attenuator */
- { USB_DEVICE(0x10C4, 0x8411) }, /* Kyocera GPS Module */
- { USB_DEVICE(0x10C4, 0x8418) }, /* IRZ Automation Teleport SG-10 GSM/GPRS Modem */
- { USB_DEVICE(0x10C4, 0x846E) }, /* BEI USB Sensor Interface (VCP) */
- { USB_DEVICE(0x10C4, 0x8477) }, /* Balluff RFID */
- { USB_DEVICE(0x10C4, 0x85EA) }, /* AC-Services IBUS-IF */
- { USB_DEVICE(0x10C4, 0x85EB) }, /* AC-Services CIS-IBUS */
- { USB_DEVICE(0x10C4, 0x8664) }, /* AC-Services CAN-IF */
- { USB_DEVICE(0x10C4, 0x8665) }, /* AC-Services OBD-IF */
- { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
- { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */
- { USB_DEVICE(0x10C4, 0xEA70) }, /* Silicon Labs factory default */
- { USB_DEVICE(0x10C4, 0xEA80) }, /* Silicon Labs factory default */
- { USB_DEVICE(0x10C4, 0xEA71) }, /* Infinity GPS-MIC-1 Radio Monophone */
- { USB_DEVICE(0x10C4, 0xF001) }, /* Elan Digital Systems USBscope50 */
- { USB_DEVICE(0x10C4, 0xF002) }, /* Elan Digital Systems USBwave12 */
- { USB_DEVICE(0x10C4, 0xF003) }, /* Elan Digital Systems USBpulse100 */
- { USB_DEVICE(0x10C4, 0xF004) }, /* Elan Digital Systems USBcount50 */
- { USB_DEVICE(0x10C5, 0xEA61) }, /* Silicon Labs MobiData GPRS USB Modem */
- { USB_DEVICE(0x10CE, 0xEA6A) }, /* Silicon Labs MobiData GPRS USB Modem 100EU */
- { USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */
- { USB_DEVICE(0x1555, 0x0004) }, /* Owen AC4 USB-RS485 Converter */
- { USB_DEVICE(0x166A, 0x0201) }, /* Clipsal 5500PACA C-Bus Pascal Automation Controller */
- { USB_DEVICE(0x166A, 0x0301) }, /* Clipsal 5800PC C-Bus Wireless PC Interface */
- { USB_DEVICE(0x166A, 0x0303) }, /* Clipsal 5500PCU C-Bus USB interface */
- { USB_DEVICE(0x166A, 0x0304) }, /* Clipsal 5000CT2 C-Bus Black and White Touchscreen */
- { USB_DEVICE(0x166A, 0x0305) }, /* Clipsal C-5000CT2 C-Bus Spectrum Colour Touchscreen */
- { USB_DEVICE(0x166A, 0x0401) }, /* Clipsal L51xx C-Bus Architectural Dimmer */
- { USB_DEVICE(0x166A, 0x0101) }, /* Clipsal 5560884 C-Bus Multi-room Audio Matrix Switcher */
- { USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */
- { USB_DEVICE(0x16DC, 0x0010) }, /* W-IE-NE-R Plein & Baus GmbH PL512 Power Supply */
- { USB_DEVICE(0x16DC, 0x0011) }, /* W-IE-NE-R Plein & Baus GmbH RCM Remote Control for MARATON Power Supply */
- { USB_DEVICE(0x16DC, 0x0012) }, /* W-IE-NE-R Plein & Baus GmbH MPOD Multi Channel Power Supply */
- { USB_DEVICE(0x16DC, 0x0015) }, /* W-IE-NE-R Plein & Baus GmbH CML Control, Monitoring and Data Logger */
- { USB_DEVICE(0x17A8, 0x0001) }, /* Kamstrup Optical Eye/3-wire */
- { USB_DEVICE(0x17A8, 0x0005) }, /* Kamstrup M-Bus Master MultiPort 250D */
- { USB_DEVICE(0x17F4, 0xAAAA) }, /* Wavesense Jazz blood glucose meter */
- { USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */
- { USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */
- { USB_DEVICE(0x1BE3, 0x07A6) }, /* WAGO 750-923 USB Service Cable */
- { USB_DEVICE(0x1E29, 0x0102) }, /* Festo CPX-USB */
- { USB_DEVICE(0x1E29, 0x0501) }, /* Festo CMSP */
- { USB_DEVICE(0x3195, 0xF190) }, /* Link Instruments MSO-19 */
- { USB_DEVICE(0x3195, 0xF280) }, /* Link Instruments MSO-28 */
- { USB_DEVICE(0x3195, 0xF281) }, /* Link Instruments MSO-28 */
- { USB_DEVICE(0x413C, 0x9500) }, /* DW700 GPS USB interface */
-
- /*
- * Prolific pl2303 USB to RS232 serial adapter ids
- * copied from linux/drivers/usb/serial/pl2303.c
- *
- * Copyright (C) 2001-2007 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (C) 2003 IBM Corp.
- */
- { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
- { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
- { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) },
- { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) },
- { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) },
- { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) },
- { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) },
- { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) },
- { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_HCR331) },
- { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MOTOROLA) },
- { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
- { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
- { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
- { USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) },
- { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
- { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) },
- { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) },
- { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) },
- { USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
- { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },
- { USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },
- { USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },
- { USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },
- { USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) },
- { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) },
- { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) },
- { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) },
- { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) },
- { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) },
- { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) },
- { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_ID_S81) }, /* Benq/Siemens S81 */
- { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
- { USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) },
- { USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) },
- { USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) },
- { USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) },
- { USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) },
- { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) },
- { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) },
- { USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) },
- { USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) },
- { USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) },
- { USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) },
- { USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) },
- { USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) },
- { USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) },
- { USB_DEVICE(ZEAGLE_VENDOR_ID, ZEAGLE_N2ITION3_PRODUCT_ID) },
- { USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) },
- { USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) },
- { USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) },
- { USB_DEVICE(SMART_VENDOR_ID, SMART_PRODUCT_ID) },
-
- { USB_DEVICE(-1, -1) } /* Terminating Entry */
-};
-
-static const struct usb_device_id usbredir_ftdi_serial_ids[] = {
- /*
- * FTDI USB to RS232 serial adapter ids
- * copied from linux/drivers/usb/serial/ftdi_sio.c
- *
- * Copyright (C) 2009 - 2010
- * Johan Hovold (jhovold@gmail.com)
- * Copyright (C) 1999 - 2001
- * Greg Kroah-Hartman (greg@kroah.com)
- * Bill Ryder (bryder@sgi.com)
- * Copyright (C) 2002
- * Kuba Ober (kuba@mareimbrium.org)
- */
- { USB_DEVICE(FTDI_VID, FTDI_ZEITCONTROL_TAGTRACE_MIFARE_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CTI_MINI_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CTI_NANO_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_AMC232_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CANUSB_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CANDAPTER_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_NXTCAM_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_0_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_1_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_2_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_3_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_4_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_5_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_6_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_7_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_USINT_CAT_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_USINT_WKEY_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_USINT_RS232_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ACTZWAVE_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_IPLUS_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_IPLUS2_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_DMX4ALL) },
- { USB_DEVICE(FTDI_VID, FTDI_SIO_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_232RL_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_4232H_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_232H_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_FTX_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_MICRO_CHAMELEON_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_SNIFFER_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_THROTTLE_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GATEWAY_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GBM_PID) },
- { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) },
- { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_SPROG_II) },
- { USB_DEVICE(FTDI_VID, FTDI_LENZ_LIUSB_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_XF_632_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_XF_634_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_XF_547_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_XF_633_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_XF_631_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_XF_635_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_XF_640_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_XF_642_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_DSS20_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_URBAN_0_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_URBAN_1_PID) },
- { USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_VNHCPCUSB_D_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_MTXORB_0_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_MTXORB_1_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_MTXORB_2_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_MTXORB_3_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_MTXORB_4_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_MTXORB_5_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_MTXORB_6_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_R2000KU_TRUE_RNG) },
- { USB_DEVICE(FTDI_VID, FTDI_VARDAAN_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0100_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0101_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0102_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0103_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0104_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0105_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0106_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0107_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0108_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0109_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010A_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010B_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010C_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010D_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010E_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010F_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0110_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0111_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0112_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0113_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0114_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0115_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0116_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0117_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0118_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0119_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011A_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011B_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011C_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011D_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011E_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011F_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0120_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0121_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0122_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0123_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0124_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0125_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0126_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0127_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0128_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0129_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012A_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012B_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012C_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012D_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012E_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012F_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0130_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0131_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0132_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0133_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0134_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0135_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0136_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0137_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0138_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0139_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013A_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013B_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013C_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013D_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013E_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013F_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0140_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0141_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0142_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0143_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0144_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0145_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0146_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0147_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0148_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0149_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014A_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014B_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014C_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014D_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014E_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014F_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0150_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0151_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0152_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0153_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0154_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0155_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0156_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0157_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0158_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0159_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015A_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015B_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015C_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015D_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015E_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015F_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0160_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0161_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0162_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0163_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0164_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0165_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0166_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0167_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0168_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0169_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016A_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016B_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016C_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016D_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016E_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016F_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0170_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0171_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0172_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0173_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0174_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0175_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0176_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0177_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0178_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0179_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017A_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017B_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017C_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017D_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017E_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017F_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0180_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0181_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0182_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0183_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0184_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0185_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0186_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0187_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0188_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0189_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018A_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018B_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018C_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018D_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018E_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018F_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0190_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0191_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0192_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0193_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0194_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0195_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0196_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0197_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0198_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0199_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019A_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019B_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019C_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019D_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019E_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019F_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A0_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A1_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A2_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A3_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A4_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A5_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A6_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A7_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A8_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A9_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AA_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AB_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AC_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AD_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AE_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AF_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B0_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B1_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B2_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B3_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B4_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B5_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B6_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B7_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B8_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B9_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BA_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BB_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BC_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BD_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BE_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BF_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C0_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C1_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C2_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C3_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C4_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C5_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C6_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C7_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C8_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C9_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CA_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CB_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CC_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CD_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CE_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CF_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D0_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D1_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D2_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D3_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D4_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D5_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D6_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D7_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D8_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D9_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DA_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DB_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DC_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DD_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DE_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DF_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E0_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E1_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E2_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E3_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E4_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E5_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E6_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E7_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E8_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E9_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EA_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EB_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EC_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01ED_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EE_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EF_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F0_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F1_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F2_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F3_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F4_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F5_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F6_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F7_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F8_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F9_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FA_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FB_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FC_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FD_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FE_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FF_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_PIEGROUP_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_TNC_X_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_USBX_707_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2101_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2102_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2103_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2104_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2106_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2201_1_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2201_2_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2202_1_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2202_2_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2203_1_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2203_2_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2401_1_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2401_2_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2401_3_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2401_4_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2402_1_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2402_2_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2402_3_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2402_4_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2403_1_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2403_2_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2403_3_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2403_4_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_1_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_2_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_3_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_4_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_5_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_6_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_7_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_8_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_1_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_2_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_3_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_4_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_5_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_6_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_7_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_8_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_1_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_2_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_3_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_4_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_5_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_6_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_7_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_8_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_1_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_2_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_3_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_4_PID) },
- { USB_DEVICE(IDTECH_VID, IDTECH_IDT1221U_PID) },
- { USB_DEVICE(OCT_VID, OCT_US101_PID) },
- { USB_DEVICE(OCT_VID, OCT_DK201_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_HE_TIRA1_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_USB_UIRT_PID) },
- { USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_1) },
- { USB_DEVICE(FTDI_VID, PROTEGO_R2X0) },
- { USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_3) },
- { USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_4) },
- { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E808_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E809_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80A_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80B_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80C_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80D_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80E_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80F_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E888_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E889_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88A_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88B_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88C_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88D_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88E_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88F_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_UO100_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_UM100_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_UR100_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_ALC8500_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_PYRAMID_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1000PC_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_IBS_US485_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_IBS_PICPRO_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_IBS_PCMCIA_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_IBS_PK1_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_IBS_RS232MON_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_IBS_APP70_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_IBS_PEDO_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_IBS_PROD_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_TAVIR_STK500_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_TIAO_UMPA_PID) },
- /*
- * ELV devices:
- */
- { USB_DEVICE(FTDI_VID, FTDI_ELV_USR_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_MSM1_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_KL100_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_WS550_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_EC3000_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_WS888_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_TWS550_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_FEM_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_CLI7000_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_PPS7330_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_TFM100_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_UDF77_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_UIO88_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_UAD8_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_UDA7_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_USI2_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_T1100_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_PCD200_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_ULA200_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_CSI8_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_EM1000DL_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_PCK100_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_RFP500_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_FS20SIG_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_UTP8_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_WS300PC_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_WS444PC_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1300PC_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_EM1010PC_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_WS500_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_HS485_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_UMS100_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_TFD128_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_FM3RX_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_WS777_PID) },
- { USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) },
- { USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) },
- { USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) },
- { USB_DEVICE(FTDI_VID, LINX_FUTURE_1_PID) },
- { USB_DEVICE(FTDI_VID, LINX_FUTURE_2_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CCSMACHX_2_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CCSLOAD_N_GO_3_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CCSICDU64_4_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CCSPRIME8_5_PID) },
- { USB_DEVICE(FTDI_VID, INSIDE_ACCESSO) },
- { USB_DEVICE(INTREPID_VID, INTREPID_VALUECAN_PID) },
- { USB_DEVICE(INTREPID_VID, INTREPID_NEOVI_PID) },
- { USB_DEVICE(FALCOM_VID, FALCOM_TWIST_PID) },
- { USB_DEVICE(FALCOM_VID, FALCOM_SAMBA_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_SUUNTO_SPORTS_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_OCEANIC_PID) },
- { USB_DEVICE(TTI_VID, TTI_QL355P_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_RM_CANVIEW_PID) },
- { USB_DEVICE(ACTON_VID, ACTON_SPECTRAPRO_PID) },
- { USB_DEVICE(CONTEC_VID, CONTEC_COM1USBH_PID) },
- { USB_DEVICE(BANDB_VID, BANDB_USOTL4_PID) },
- { USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) },
- { USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) },
- { USB_DEVICE(BANDB_VID, BANDB_USOPTL4_PID) },
- { USB_DEVICE(BANDB_VID, BANDB_USPTL4_PID) },
- { USB_DEVICE(BANDB_VID, BANDB_USO9ML2DR_2_PID) },
- { USB_DEVICE(BANDB_VID, BANDB_USO9ML2DR_PID) },
- { USB_DEVICE(BANDB_VID, BANDB_USOPTL4DR2_PID) },
- { USB_DEVICE(BANDB_VID, BANDB_USOPTL4DR_PID) },
- { USB_DEVICE(BANDB_VID, BANDB_485USB9F_2W_PID) },
- { USB_DEVICE(BANDB_VID, BANDB_485USB9F_4W_PID) },
- { USB_DEVICE(BANDB_VID, BANDB_232USB9M_PID) },
- { USB_DEVICE(BANDB_VID, BANDB_485USBTB_2W_PID) },
- { USB_DEVICE(BANDB_VID, BANDB_485USBTB_4W_PID) },
- { USB_DEVICE(BANDB_VID, BANDB_TTL5USB9M_PID) },
- { USB_DEVICE(BANDB_VID, BANDB_TTL3USB9M_PID) },
- { USB_DEVICE(BANDB_VID, BANDB_ZZ_PROG1_USB_PID) },
- { USB_DEVICE(FTDI_VID, EVER_ECO_PRO_CDS) },
- { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_3_PID) },
- { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_0_PID) },
- { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_1_PID) },
- { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_2_PID) },
- { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_3_PID) },
- { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_4_PID) },
- { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_5_PID) },
- { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_6_PID) },
- { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_7_PID) },
- { USB_DEVICE(MOBILITY_VID, MOBILITY_USB_SERIAL_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_MHAM_KW_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_MHAM_YS_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_MHAM_Y6_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_MHAM_Y8_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_MHAM_IC_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_MHAM_DB9_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_MHAM_RS232_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_MHAM_Y9_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_TERATRONIK_VCP_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_TERATRONIK_D2XX_PID) },
- { USB_DEVICE(EVOLUTION_VID, EVOLUTION_ER1_PID) },
- { USB_DEVICE(EVOLUTION_VID, EVO_HYBRID_PID) },
- { USB_DEVICE(EVOLUTION_VID, EVO_RCM4_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ARTEMIS_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16C_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16HR_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16HRC_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16IC_PID) },
- { USB_DEVICE(KOBIL_VID, KOBIL_CONV_B1_PID) },
- { USB_DEVICE(KOBIL_VID, KOBIL_CONV_KAAN_PID) },
- { USB_DEVICE(POSIFLEX_VID, POSIFLEX_PP7000_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_TTUSB_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ECLO_COM_1WIRE_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_WESTREX_MODEL_777_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_WESTREX_MODEL_8900F_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_PCDJ_DAC2_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_RRCIRKITS_LOCOBUFFER_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ASK_RDR400_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_NZR_SEM_USB_PID) },
- { USB_DEVICE(ICOM_VID, ICOM_ID_1_PID) },
- { USB_DEVICE(ICOM_VID, ICOM_OPC_U_UC_PID) },
- { USB_DEVICE(ICOM_VID, ICOM_ID_RP2C1_PID) },
- { USB_DEVICE(ICOM_VID, ICOM_ID_RP2C2_PID) },
- { USB_DEVICE(ICOM_VID, ICOM_ID_RP2D_PID) },
- { USB_DEVICE(ICOM_VID, ICOM_ID_RP2VT_PID) },
- { USB_DEVICE(ICOM_VID, ICOM_ID_RP2VR_PID) },
- { USB_DEVICE(ICOM_VID, ICOM_ID_RP4KVT_PID) },
- { USB_DEVICE(ICOM_VID, ICOM_ID_RP4KVR_PID) },
- { USB_DEVICE(ICOM_VID, ICOM_ID_RP2KVT_PID) },
- { USB_DEVICE(ICOM_VID, ICOM_ID_RP2KVR_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ACG_HFDUAL_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_YEI_SERVOCENTER31_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_THORLABS_PID) },
- { USB_DEVICE(TESTO_VID, TESTO_USB_INTERFACE_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_GAMMA_SCOUT_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13M_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13S_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13U_PID) },
- { USB_DEVICE(ELEKTOR_VID, ELEKTOR_FT323R_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_NDI_HUC_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_NDI_SPECTRA_SCU_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_NDI_FUTURE_2_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_NDI_FUTURE_3_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_NDI_AURORA_SCU_PID) },
- { USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) },
- { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_SERIAL_VX7_PID) },
- { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_CT29B_PID) },
- { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_RTS01_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_MAXSTREAM_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_PHI_FISCO_PID) },
- { USB_DEVICE(TML_VID, TML_USB_SERIAL_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELSTER_UNICOM_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_PROPOX_JTAGCABLEII_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_PROPOX_ISPCABLEIII_PID) },
- { USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_PID) },
- { USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_H_PID) },
- { USB_DEVICE(FIC_VID, FIC_NEO1973_DEBUG_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_OOCDLINK_PID) },
- { USB_DEVICE(FTDI_VID, LMI_LM3S_DEVEL_BOARD_PID) },
- { USB_DEVICE(FTDI_VID, LMI_LM3S_EVAL_BOARD_PID) },
- { USB_DEVICE(FTDI_VID, LMI_LM3S_ICDI_BOARD_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_TURTELIZER_PID) },
- { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) },
- { USB_DEVICE(FTDI_VID, FTDI_REU_TINY_PID) },
-
- /* Papouch devices based on FTDI chip */
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB485_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_AP485_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB422_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB485_2_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_AP485_2_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB422_2_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB485S_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB485C_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_LEC_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB232_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_TMU_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_IRAMP_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_DRAK5_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO8x8_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO4x4_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO2x2_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO10x1_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO30x3_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO60x3_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO2x16_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO3x32_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_DRAK6_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_UPSUSB_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_MU_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SIMUKEY_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_AD4USB_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_GMUX_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_GMSR_PID) },
-
- { USB_DEVICE(FTDI_VID, FTDI_DOMINTELL_DGQG_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_DOMINTELL_DUSB_PID) },
- { USB_DEVICE(ALTI2_VID, ALTI2_N3_PID) },
- { USB_DEVICE(FTDI_VID, DIEBOLD_BCS_SE923_PID) },
- { USB_DEVICE(ATMEL_VID, STK541_PID) },
- { USB_DEVICE(DE_VID, STB_PID) },
- { USB_DEVICE(DE_VID, WHT_PID) },
- { USB_DEVICE(ADI_VID, ADI_GNICE_PID) },
- { USB_DEVICE(ADI_VID, ADI_GNICEPLUS_PID) },
- { USB_DEVICE_AND_INTERFACE_INFO(MICROCHIP_VID, MICROCHIP_USB_BOARD_PID,
- 0xff, 0xff, 0x00) },
- { USB_DEVICE(JETI_VID, JETI_SPC1201_PID) },
- { USB_DEVICE(MARVELL_VID, MARVELL_SHEEVAPLUG_PID) },
- { USB_DEVICE(LARSENBRUSGAARD_VID, LB_ALTITRACK_PID) },
- { USB_DEVICE(GN_OTOMETRICS_VID, AURICAL_USB_PID) },
- { USB_DEVICE(FTDI_VID, PI_C865_PID) },
- { USB_DEVICE(FTDI_VID, PI_C857_PID) },
- { USB_DEVICE(PI_VID, PI_C866_PID) },
- { USB_DEVICE(PI_VID, PI_C663_PID) },
- { USB_DEVICE(PI_VID, PI_C725_PID) },
- { USB_DEVICE(PI_VID, PI_E517_PID) },
- { USB_DEVICE(PI_VID, PI_C863_PID) },
- { USB_DEVICE(PI_VID, PI_E861_PID) },
- { USB_DEVICE(PI_VID, PI_C867_PID) },
- { USB_DEVICE(PI_VID, PI_E609_PID) },
- { USB_DEVICE(PI_VID, PI_E709_PID) },
- { USB_DEVICE(PI_VID, PI_100F_PID) },
- { USB_DEVICE(PI_VID, PI_1011_PID) },
- { USB_DEVICE(PI_VID, PI_1012_PID) },
- { USB_DEVICE(PI_VID, PI_1013_PID) },
- { USB_DEVICE(PI_VID, PI_1014_PID) },
- { USB_DEVICE(PI_VID, PI_1015_PID) },
- { USB_DEVICE(PI_VID, PI_1016_PID) },
- { USB_DEVICE(KONDO_VID, KONDO_USB_SERIAL_PID) },
- { USB_DEVICE(BAYER_VID, BAYER_CONTOUR_CABLE_PID) },
- { USB_DEVICE(FTDI_VID, MARVELL_OPENRD_PID) },
- { USB_DEVICE(FTDI_VID, TI_XDS100V2_PID) },
- { USB_DEVICE(FTDI_VID, HAMEG_HO820_PID) },
- { USB_DEVICE(FTDI_VID, HAMEG_HO720_PID) },
- { USB_DEVICE(FTDI_VID, HAMEG_HO730_PID) },
- { USB_DEVICE(FTDI_VID, HAMEG_HO870_PID) },
- { USB_DEVICE(FTDI_VID, MJSG_GENERIC_PID) },
- { USB_DEVICE(FTDI_VID, MJSG_SR_RADIO_PID) },
- { USB_DEVICE(FTDI_VID, MJSG_HD_RADIO_PID) },
- { USB_DEVICE(FTDI_VID, MJSG_XM_RADIO_PID) },
- { USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_ST_PID) },
- { USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_SLITE_PID) },
- { USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_SH2_PID) },
- { USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_SH4_PID) },
- { USB_DEVICE(FTDI_VID, SEGWAY_RMP200_PID) },
- { USB_DEVICE(FTDI_VID, ACCESIO_COM4SM_PID) },
- { USB_DEVICE(IONICS_VID, IONICS_PLUGCOMPUTER_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_24_MASTER_WING_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_PC_WING_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_USB_DMX_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_MIDI_TIMECODE_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_MINI_WING_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_MAXI_WING_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_MEDIA_WING_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_WING_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LOGBOOKML_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LS_LOGBOOK_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_HS_LOGBOOK_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CINTERION_MC55I_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_DOTEC_PID) },
- { USB_DEVICE(QIHARDWARE_VID, MILKYMISTONE_JTAGSERIAL_PID) },
- { USB_DEVICE(ST_VID, ST_STMCLT1030_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_RF_R106) },
- { USB_DEVICE(FTDI_VID, FTDI_DISTORTEC_JTAG_LOCK_PICK_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_LUMEL_PD12_PID) },
-
- { USB_DEVICE(-1, -1) } /* Terminating Entry */
-};
-
-#undef USB_DEVICE
-#undef USB_DEVICE_AND_INTERFACE_INFO
diff --git a/qemu/hw/usb/redirect.c b/qemu/hw/usb/redirect.c
deleted file mode 100644
index 8d8054037..000000000
--- a/qemu/hw/usb/redirect.c
+++ /dev/null
@@ -1,2526 +0,0 @@
-/*
- * USB redirector usb-guest
- *
- * Copyright (c) 2011-2012 Red Hat, Inc.
- *
- * Red Hat Authors:
- * Hans de Goede <hdegoede@redhat.com>
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "qemu/timer.h"
-#include "sysemu/sysemu.h"
-#include "qapi/qmp/qerror.h"
-#include "qemu/error-report.h"
-#include "qemu/iov.h"
-#include "sysemu/char.h"
-
-#include <usbredirparser.h>
-#include <usbredirfilter.h>
-
-#include "hw/usb.h"
-
-/* ERROR is defined below. Remove any previous definition. */
-#undef ERROR
-
-#define MAX_ENDPOINTS 32
-#define NO_INTERFACE_INFO 255 /* Valid interface_count always <= 32 */
-#define EP2I(ep_address) (((ep_address & 0x80) >> 3) | (ep_address & 0x0f))
-#define I2EP(i) (((i & 0x10) << 3) | (i & 0x0f))
-#define USBEP2I(usb_ep) (((usb_ep)->pid == USB_TOKEN_IN) ? \
- ((usb_ep)->nr | 0x10) : ((usb_ep)->nr))
-#define I2USBEP(d, i) (usb_ep_get(&(d)->dev, \
- ((i) & 0x10) ? USB_TOKEN_IN : USB_TOKEN_OUT, \
- (i) & 0x0f))
-
-#ifndef USBREDIR_VERSION /* This is not defined in older usbredir versions */
-#define USBREDIR_VERSION 0
-#endif
-
-typedef struct USBRedirDevice USBRedirDevice;
-
-/* Struct to hold buffered packets */
-struct buf_packet {
- uint8_t *data;
- void *free_on_destroy;
- uint16_t len;
- uint16_t offset;
- uint8_t status;
- QTAILQ_ENTRY(buf_packet)next;
-};
-
-struct endp_data {
- USBRedirDevice *dev;
- uint8_t type;
- uint8_t interval;
- uint8_t interface; /* bInterfaceNumber this ep belongs to */
- uint16_t max_packet_size; /* In bytes, not wMaxPacketSize format !! */
- uint32_t max_streams;
- uint8_t iso_started;
- uint8_t iso_error; /* For reporting iso errors to the HC */
- uint8_t interrupt_started;
- uint8_t interrupt_error;
- uint8_t bulk_receiving_enabled;
- uint8_t bulk_receiving_started;
- uint8_t bufpq_prefilled;
- uint8_t bufpq_dropping_packets;
- QTAILQ_HEAD(, buf_packet) bufpq;
- int32_t bufpq_size;
- int32_t bufpq_target_size;
- USBPacket *pending_async_packet;
-};
-
-struct PacketIdQueueEntry {
- uint64_t id;
- QTAILQ_ENTRY(PacketIdQueueEntry)next;
-};
-
-struct PacketIdQueue {
- USBRedirDevice *dev;
- const char *name;
- QTAILQ_HEAD(, PacketIdQueueEntry) head;
- int size;
-};
-
-struct USBRedirDevice {
- USBDevice dev;
- /* Properties */
- CharDriverState *cs;
- uint8_t debug;
- char *filter_str;
- int32_t bootindex;
- /* Data passed from chardev the fd_read cb to the usbredirparser read cb */
- const uint8_t *read_buf;
- int read_buf_size;
- /* Active chardev-watch-tag */
- guint watch;
- /* For async handling of close / reject */
- QEMUBH *chardev_close_bh;
- QEMUBH *device_reject_bh;
- /* To delay the usb attach in case of quick chardev close + open */
- QEMUTimer *attach_timer;
- int64_t next_attach_time;
- struct usbredirparser *parser;
- struct endp_data endpoint[MAX_ENDPOINTS];
- struct PacketIdQueue cancelled;
- struct PacketIdQueue already_in_flight;
- void (*buffered_bulk_in_complete)(USBRedirDevice *, USBPacket *, uint8_t);
- /* Data for device filtering */
- struct usb_redir_device_connect_header device_info;
- struct usb_redir_interface_info_header interface_info;
- struct usbredirfilter_rule *filter_rules;
- int filter_rules_count;
- int compatible_speedmask;
-};
-
-#define TYPE_USB_REDIR "usb-redir"
-#define USB_REDIRECT(obj) OBJECT_CHECK(USBRedirDevice, (obj), TYPE_USB_REDIR)
-
-static void usbredir_hello(void *priv, struct usb_redir_hello_header *h);
-static void usbredir_device_connect(void *priv,
- struct usb_redir_device_connect_header *device_connect);
-static void usbredir_device_disconnect(void *priv);
-static void usbredir_interface_info(void *priv,
- struct usb_redir_interface_info_header *interface_info);
-static void usbredir_ep_info(void *priv,
- struct usb_redir_ep_info_header *ep_info);
-static void usbredir_configuration_status(void *priv, uint64_t id,
- struct usb_redir_configuration_status_header *configuration_status);
-static void usbredir_alt_setting_status(void *priv, uint64_t id,
- struct usb_redir_alt_setting_status_header *alt_setting_status);
-static void usbredir_iso_stream_status(void *priv, uint64_t id,
- struct usb_redir_iso_stream_status_header *iso_stream_status);
-static void usbredir_interrupt_receiving_status(void *priv, uint64_t id,
- struct usb_redir_interrupt_receiving_status_header
- *interrupt_receiving_status);
-static void usbredir_bulk_streams_status(void *priv, uint64_t id,
- struct usb_redir_bulk_streams_status_header *bulk_streams_status);
-static void usbredir_bulk_receiving_status(void *priv, uint64_t id,
- struct usb_redir_bulk_receiving_status_header *bulk_receiving_status);
-static void usbredir_control_packet(void *priv, uint64_t id,
- struct usb_redir_control_packet_header *control_packet,
- uint8_t *data, int data_len);
-static void usbredir_bulk_packet(void *priv, uint64_t id,
- struct usb_redir_bulk_packet_header *bulk_packet,
- uint8_t *data, int data_len);
-static void usbredir_iso_packet(void *priv, uint64_t id,
- struct usb_redir_iso_packet_header *iso_packet,
- uint8_t *data, int data_len);
-static void usbredir_interrupt_packet(void *priv, uint64_t id,
- struct usb_redir_interrupt_packet_header *interrupt_header,
- uint8_t *data, int data_len);
-static void usbredir_buffered_bulk_packet(void *priv, uint64_t id,
- struct usb_redir_buffered_bulk_packet_header *buffered_bulk_packet,
- uint8_t *data, int data_len);
-
-static void usbredir_handle_status(USBRedirDevice *dev, USBPacket *p,
- int status);
-
-#define VERSION "qemu usb-redir guest " QEMU_VERSION
-
-/*
- * Logging stuff
- */
-
-#define ERROR(...) \
- do { \
- if (dev->debug >= usbredirparser_error) { \
- error_report("usb-redir error: " __VA_ARGS__); \
- } \
- } while (0)
-#define WARNING(...) \
- do { \
- if (dev->debug >= usbredirparser_warning) { \
- error_report("usb-redir warning: " __VA_ARGS__); \
- } \
- } while (0)
-#define INFO(...) \
- do { \
- if (dev->debug >= usbredirparser_info) { \
- error_report("usb-redir: " __VA_ARGS__); \
- } \
- } while (0)
-#define DPRINTF(...) \
- do { \
- if (dev->debug >= usbredirparser_debug) { \
- error_report("usb-redir: " __VA_ARGS__); \
- } \
- } while (0)
-#define DPRINTF2(...) \
- do { \
- if (dev->debug >= usbredirparser_debug_data) { \
- error_report("usb-redir: " __VA_ARGS__); \
- } \
- } while (0)
-
-static void usbredir_log(void *priv, int level, const char *msg)
-{
- USBRedirDevice *dev = priv;
-
- if (dev->debug < level) {
- return;
- }
-
- error_report("%s", msg);
-}
-
-static void usbredir_log_data(USBRedirDevice *dev, const char *desc,
- const uint8_t *data, int len)
-{
- int i, j, n;
-
- if (dev->debug < usbredirparser_debug_data) {
- return;
- }
-
- for (i = 0; i < len; i += j) {
- char buf[128];
-
- n = sprintf(buf, "%s", desc);
- for (j = 0; j < 8 && i + j < len; j++) {
- n += sprintf(buf + n, " %02X", data[i + j]);
- }
- error_report("%s", buf);
- }
-}
-
-/*
- * usbredirparser io functions
- */
-
-static int usbredir_read(void *priv, uint8_t *data, int count)
-{
- USBRedirDevice *dev = priv;
-
- if (dev->read_buf_size < count) {
- count = dev->read_buf_size;
- }
-
- memcpy(data, dev->read_buf, count);
-
- dev->read_buf_size -= count;
- if (dev->read_buf_size) {
- dev->read_buf += count;
- } else {
- dev->read_buf = NULL;
- }
-
- return count;
-}
-
-static gboolean usbredir_write_unblocked(GIOChannel *chan, GIOCondition cond,
- void *opaque)
-{
- USBRedirDevice *dev = opaque;
-
- dev->watch = 0;
- usbredirparser_do_write(dev->parser);
-
- return FALSE;
-}
-
-static int usbredir_write(void *priv, uint8_t *data, int count)
-{
- USBRedirDevice *dev = priv;
- int r;
-
- if (!dev->cs->be_open) {
- return 0;
- }
-
- /* Don't send new data to the chardev until our state is fully synced */
- if (!runstate_check(RUN_STATE_RUNNING)) {
- return 0;
- }
-
- r = qemu_chr_fe_write(dev->cs, data, count);
- if (r < count) {
- if (!dev->watch) {
- dev->watch = qemu_chr_fe_add_watch(dev->cs, G_IO_OUT|G_IO_HUP,
- usbredir_write_unblocked, dev);
- }
- if (r < 0) {
- r = 0;
- }
- }
- return r;
-}
-
-/*
- * Cancelled and buffered packets helpers
- */
-
-static void packet_id_queue_init(struct PacketIdQueue *q,
- USBRedirDevice *dev, const char *name)
-{
- q->dev = dev;
- q->name = name;
- QTAILQ_INIT(&q->head);
- q->size = 0;
-}
-
-static void packet_id_queue_add(struct PacketIdQueue *q, uint64_t id)
-{
- USBRedirDevice *dev = q->dev;
- struct PacketIdQueueEntry *e;
-
- DPRINTF("adding packet id %"PRIu64" to %s queue\n", id, q->name);
-
- e = g_new0(struct PacketIdQueueEntry, 1);
- e->id = id;
- QTAILQ_INSERT_TAIL(&q->head, e, next);
- q->size++;
-}
-
-static int packet_id_queue_remove(struct PacketIdQueue *q, uint64_t id)
-{
- USBRedirDevice *dev = q->dev;
- struct PacketIdQueueEntry *e;
-
- QTAILQ_FOREACH(e, &q->head, next) {
- if (e->id == id) {
- DPRINTF("removing packet id %"PRIu64" from %s queue\n",
- id, q->name);
- QTAILQ_REMOVE(&q->head, e, next);
- q->size--;
- g_free(e);
- return 1;
- }
- }
- return 0;
-}
-
-static void packet_id_queue_empty(struct PacketIdQueue *q)
-{
- USBRedirDevice *dev = q->dev;
- struct PacketIdQueueEntry *e, *next_e;
-
- DPRINTF("removing %d packet-ids from %s queue\n", q->size, q->name);
-
- QTAILQ_FOREACH_SAFE(e, &q->head, next, next_e) {
- QTAILQ_REMOVE(&q->head, e, next);
- g_free(e);
- }
- q->size = 0;
-}
-
-static void usbredir_cancel_packet(USBDevice *udev, USBPacket *p)
-{
- USBRedirDevice *dev = USB_REDIRECT(udev);
- int i = USBEP2I(p->ep);
-
- if (p->combined) {
- usb_combined_packet_cancel(udev, p);
- return;
- }
-
- if (dev->endpoint[i].pending_async_packet) {
- assert(dev->endpoint[i].pending_async_packet == p);
- dev->endpoint[i].pending_async_packet = NULL;
- return;
- }
-
- packet_id_queue_add(&dev->cancelled, p->id);
- usbredirparser_send_cancel_data_packet(dev->parser, p->id);
- usbredirparser_do_write(dev->parser);
-}
-
-static int usbredir_is_cancelled(USBRedirDevice *dev, uint64_t id)
-{
- if (!dev->dev.attached) {
- return 1; /* Treat everything as cancelled after a disconnect */
- }
- return packet_id_queue_remove(&dev->cancelled, id);
-}
-
-static void usbredir_fill_already_in_flight_from_ep(USBRedirDevice *dev,
- struct USBEndpoint *ep)
-{
- static USBPacket *p;
-
- /* async handled packets for bulk receiving eps do not count as inflight */
- if (dev->endpoint[USBEP2I(ep)].bulk_receiving_started) {
- return;
- }
-
- QTAILQ_FOREACH(p, &ep->queue, queue) {
- /* Skip combined packets, except for the first */
- if (p->combined && p != p->combined->first) {
- continue;
- }
- if (p->state == USB_PACKET_ASYNC) {
- packet_id_queue_add(&dev->already_in_flight, p->id);
- }
- }
-}
-
-static void usbredir_fill_already_in_flight(USBRedirDevice *dev)
-{
- int ep;
- struct USBDevice *udev = &dev->dev;
-
- usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_ctl);
-
- for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) {
- usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_in[ep]);
- usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_out[ep]);
- }
-}
-
-static int usbredir_already_in_flight(USBRedirDevice *dev, uint64_t id)
-{
- return packet_id_queue_remove(&dev->already_in_flight, id);
-}
-
-static USBPacket *usbredir_find_packet_by_id(USBRedirDevice *dev,
- uint8_t ep, uint64_t id)
-{
- USBPacket *p;
-
- if (usbredir_is_cancelled(dev, id)) {
- return NULL;
- }
-
- p = usb_ep_find_packet_by_id(&dev->dev,
- (ep & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT,
- ep & 0x0f, id);
- if (p == NULL) {
- ERROR("could not find packet with id %"PRIu64"\n", id);
- }
- return p;
-}
-
-static int bufp_alloc(USBRedirDevice *dev, uint8_t *data, uint16_t len,
- uint8_t status, uint8_t ep, void *free_on_destroy)
-{
- struct buf_packet *bufp;
-
- if (!dev->endpoint[EP2I(ep)].bufpq_dropping_packets &&
- dev->endpoint[EP2I(ep)].bufpq_size >
- 2 * dev->endpoint[EP2I(ep)].bufpq_target_size) {
- DPRINTF("bufpq overflow, dropping packets ep %02X\n", ep);
- dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 1;
- }
- /* Since we're interupting the stream anyways, drop enough packets to get
- back to our target buffer size */
- if (dev->endpoint[EP2I(ep)].bufpq_dropping_packets) {
- if (dev->endpoint[EP2I(ep)].bufpq_size >
- dev->endpoint[EP2I(ep)].bufpq_target_size) {
- free(data);
- return -1;
- }
- dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0;
- }
-
- bufp = g_new(struct buf_packet, 1);
- bufp->data = data;
- bufp->len = len;
- bufp->offset = 0;
- bufp->status = status;
- bufp->free_on_destroy = free_on_destroy;
- QTAILQ_INSERT_TAIL(&dev->endpoint[EP2I(ep)].bufpq, bufp, next);
- dev->endpoint[EP2I(ep)].bufpq_size++;
- return 0;
-}
-
-static void bufp_free(USBRedirDevice *dev, struct buf_packet *bufp,
- uint8_t ep)
-{
- QTAILQ_REMOVE(&dev->endpoint[EP2I(ep)].bufpq, bufp, next);
- dev->endpoint[EP2I(ep)].bufpq_size--;
- free(bufp->free_on_destroy);
- g_free(bufp);
-}
-
-static void usbredir_free_bufpq(USBRedirDevice *dev, uint8_t ep)
-{
- struct buf_packet *buf, *buf_next;
-
- QTAILQ_FOREACH_SAFE(buf, &dev->endpoint[EP2I(ep)].bufpq, next, buf_next) {
- bufp_free(dev, buf, ep);
- }
-}
-
-/*
- * USBDevice callbacks
- */
-
-static void usbredir_handle_reset(USBDevice *udev)
-{
- USBRedirDevice *dev = USB_REDIRECT(udev);
-
- DPRINTF("reset device\n");
- usbredirparser_send_reset(dev->parser);
- usbredirparser_do_write(dev->parser);
-}
-
-static void usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p,
- uint8_t ep)
-{
- int status, len;
- if (!dev->endpoint[EP2I(ep)].iso_started &&
- !dev->endpoint[EP2I(ep)].iso_error) {
- struct usb_redir_start_iso_stream_header start_iso = {
- .endpoint = ep,
- };
- int pkts_per_sec;
-
- if (dev->dev.speed == USB_SPEED_HIGH) {
- pkts_per_sec = 8000 / dev->endpoint[EP2I(ep)].interval;
- } else {
- pkts_per_sec = 1000 / dev->endpoint[EP2I(ep)].interval;
- }
- /* Testing has shown that we need circa 60 ms buffer */
- dev->endpoint[EP2I(ep)].bufpq_target_size = (pkts_per_sec * 60) / 1000;
-
- /* Aim for approx 100 interrupts / second on the client to
- balance latency and interrupt load */
- start_iso.pkts_per_urb = pkts_per_sec / 100;
- if (start_iso.pkts_per_urb < 1) {
- start_iso.pkts_per_urb = 1;
- } else if (start_iso.pkts_per_urb > 32) {
- start_iso.pkts_per_urb = 32;
- }
-
- start_iso.no_urbs = (dev->endpoint[EP2I(ep)].bufpq_target_size +
- start_iso.pkts_per_urb - 1) /
- start_iso.pkts_per_urb;
- /* Output endpoints pre-fill only 1/2 of the packets, keeping the rest
- as overflow buffer. Also see the usbredir protocol documentation */
- if (!(ep & USB_DIR_IN)) {
- start_iso.no_urbs *= 2;
- }
- if (start_iso.no_urbs > 16) {
- start_iso.no_urbs = 16;
- }
-
- /* No id, we look at the ep when receiving a status back */
- usbredirparser_send_start_iso_stream(dev->parser, 0, &start_iso);
- usbredirparser_do_write(dev->parser);
- DPRINTF("iso stream started pkts/sec %d pkts/urb %d urbs %d ep %02X\n",
- pkts_per_sec, start_iso.pkts_per_urb, start_iso.no_urbs, ep);
- dev->endpoint[EP2I(ep)].iso_started = 1;
- dev->endpoint[EP2I(ep)].bufpq_prefilled = 0;
- dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0;
- }
-
- if (ep & USB_DIR_IN) {
- struct buf_packet *isop;
-
- if (dev->endpoint[EP2I(ep)].iso_started &&
- !dev->endpoint[EP2I(ep)].bufpq_prefilled) {
- if (dev->endpoint[EP2I(ep)].bufpq_size <
- dev->endpoint[EP2I(ep)].bufpq_target_size) {
- return;
- }
- dev->endpoint[EP2I(ep)].bufpq_prefilled = 1;
- }
-
- isop = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq);
- if (isop == NULL) {
- DPRINTF("iso-token-in ep %02X, no isop, iso_error: %d\n",
- ep, dev->endpoint[EP2I(ep)].iso_error);
- /* Re-fill the buffer */
- dev->endpoint[EP2I(ep)].bufpq_prefilled = 0;
- /* Check iso_error for stream errors, otherwise its an underrun */
- status = dev->endpoint[EP2I(ep)].iso_error;
- dev->endpoint[EP2I(ep)].iso_error = 0;
- p->status = status ? USB_RET_IOERROR : USB_RET_SUCCESS;
- return;
- }
- DPRINTF2("iso-token-in ep %02X status %d len %d queue-size: %d\n", ep,
- isop->status, isop->len, dev->endpoint[EP2I(ep)].bufpq_size);
-
- status = isop->status;
- len = isop->len;
- if (len > p->iov.size) {
- ERROR("received iso data is larger then packet ep %02X (%d > %d)\n",
- ep, len, (int)p->iov.size);
- len = p->iov.size;
- status = usb_redir_babble;
- }
- usb_packet_copy(p, isop->data, len);
- bufp_free(dev, isop, ep);
- usbredir_handle_status(dev, p, status);
- } else {
- /* If the stream was not started because of a pending error don't
- send the packet to the usb-host */
- if (dev->endpoint[EP2I(ep)].iso_started) {
- struct usb_redir_iso_packet_header iso_packet = {
- .endpoint = ep,
- .length = p->iov.size
- };
- uint8_t buf[p->iov.size];
- /* No id, we look at the ep when receiving a status back */
- usb_packet_copy(p, buf, p->iov.size);
- usbredirparser_send_iso_packet(dev->parser, 0, &iso_packet,
- buf, p->iov.size);
- usbredirparser_do_write(dev->parser);
- }
- status = dev->endpoint[EP2I(ep)].iso_error;
- dev->endpoint[EP2I(ep)].iso_error = 0;
- DPRINTF2("iso-token-out ep %02X status %d len %zd\n", ep, status,
- p->iov.size);
- usbredir_handle_status(dev, p, status);
- }
-}
-
-static void usbredir_stop_iso_stream(USBRedirDevice *dev, uint8_t ep)
-{
- struct usb_redir_stop_iso_stream_header stop_iso_stream = {
- .endpoint = ep
- };
- if (dev->endpoint[EP2I(ep)].iso_started) {
- usbredirparser_send_stop_iso_stream(dev->parser, 0, &stop_iso_stream);
- DPRINTF("iso stream stopped ep %02X\n", ep);
- dev->endpoint[EP2I(ep)].iso_started = 0;
- }
- dev->endpoint[EP2I(ep)].iso_error = 0;
- usbredir_free_bufpq(dev, ep);
-}
-
-/*
- * The usb-host may poll the endpoint faster then our guest, resulting in lots
- * of smaller bulkp-s. The below buffered_bulk_in_complete* functions combine
- * data from multiple bulkp-s into a single packet, avoiding bufpq overflows.
- */
-static void usbredir_buffered_bulk_add_data_to_packet(USBRedirDevice *dev,
- struct buf_packet *bulkp, int count, USBPacket *p, uint8_t ep)
-{
- usb_packet_copy(p, bulkp->data + bulkp->offset, count);
- bulkp->offset += count;
- if (bulkp->offset == bulkp->len) {
- /* Store status in the last packet with data from this bulkp */
- usbredir_handle_status(dev, p, bulkp->status);
- bufp_free(dev, bulkp, ep);
- }
-}
-
-static void usbredir_buffered_bulk_in_complete_raw(USBRedirDevice *dev,
- USBPacket *p, uint8_t ep)
-{
- struct buf_packet *bulkp;
- int count;
-
- while ((bulkp = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq)) &&
- p->actual_length < p->iov.size && p->status == USB_RET_SUCCESS) {
- count = bulkp->len - bulkp->offset;
- if (count > (p->iov.size - p->actual_length)) {
- count = p->iov.size - p->actual_length;
- }
- usbredir_buffered_bulk_add_data_to_packet(dev, bulkp, count, p, ep);
- }
-}
-
-static void usbredir_buffered_bulk_in_complete_ftdi(USBRedirDevice *dev,
- USBPacket *p, uint8_t ep)
-{
- const int maxp = dev->endpoint[EP2I(ep)].max_packet_size;
- uint8_t header[2] = { 0, 0 };
- struct buf_packet *bulkp;
- int count;
-
- while ((bulkp = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq)) &&
- p->actual_length < p->iov.size && p->status == USB_RET_SUCCESS) {
- if (bulkp->len < 2) {
- WARNING("malformed ftdi bulk in packet\n");
- bufp_free(dev, bulkp, ep);
- continue;
- }
-
- if ((p->actual_length % maxp) == 0) {
- usb_packet_copy(p, bulkp->data, 2);
- memcpy(header, bulkp->data, 2);
- } else {
- if (bulkp->data[0] != header[0] || bulkp->data[1] != header[1]) {
- break; /* Different header, add to next packet */
- }
- }
-
- if (bulkp->offset == 0) {
- bulkp->offset = 2; /* Skip header */
- }
- count = bulkp->len - bulkp->offset;
- /* Must repeat the header at maxp interval */
- if (count > (maxp - (p->actual_length % maxp))) {
- count = maxp - (p->actual_length % maxp);
- }
- usbredir_buffered_bulk_add_data_to_packet(dev, bulkp, count, p, ep);
- }
-}
-
-static void usbredir_buffered_bulk_in_complete(USBRedirDevice *dev,
- USBPacket *p, uint8_t ep)
-{
- p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
- dev->buffered_bulk_in_complete(dev, p, ep);
- DPRINTF("bulk-token-in ep %02X status %d len %d id %"PRIu64"\n",
- ep, p->status, p->actual_length, p->id);
-}
-
-static void usbredir_handle_buffered_bulk_in_data(USBRedirDevice *dev,
- USBPacket *p, uint8_t ep)
-{
- /* Input bulk endpoint, buffered packet input */
- if (!dev->endpoint[EP2I(ep)].bulk_receiving_started) {
- int bpt;
- struct usb_redir_start_bulk_receiving_header start = {
- .endpoint = ep,
- .stream_id = 0,
- .no_transfers = 5,
- };
- /* Round bytes_per_transfer up to a multiple of max_packet_size */
- bpt = 512 + dev->endpoint[EP2I(ep)].max_packet_size - 1;
- bpt /= dev->endpoint[EP2I(ep)].max_packet_size;
- bpt *= dev->endpoint[EP2I(ep)].max_packet_size;
- start.bytes_per_transfer = bpt;
- /* No id, we look at the ep when receiving a status back */
- usbredirparser_send_start_bulk_receiving(dev->parser, 0, &start);
- usbredirparser_do_write(dev->parser);
- DPRINTF("bulk receiving started bytes/transfer %u count %d ep %02X\n",
- start.bytes_per_transfer, start.no_transfers, ep);
- dev->endpoint[EP2I(ep)].bulk_receiving_started = 1;
- /* We don't really want to drop bulk packets ever, but
- having some upper limit to how much we buffer is good. */
- dev->endpoint[EP2I(ep)].bufpq_target_size = 5000;
- dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0;
- }
-
- if (QTAILQ_EMPTY(&dev->endpoint[EP2I(ep)].bufpq)) {
- DPRINTF("bulk-token-in ep %02X, no bulkp\n", ep);
- assert(dev->endpoint[EP2I(ep)].pending_async_packet == NULL);
- dev->endpoint[EP2I(ep)].pending_async_packet = p;
- p->status = USB_RET_ASYNC;
- return;
- }
- usbredir_buffered_bulk_in_complete(dev, p, ep);
-}
-
-static void usbredir_stop_bulk_receiving(USBRedirDevice *dev, uint8_t ep)
-{
- struct usb_redir_stop_bulk_receiving_header stop_bulk = {
- .endpoint = ep,
- .stream_id = 0,
- };
- if (dev->endpoint[EP2I(ep)].bulk_receiving_started) {
- usbredirparser_send_stop_bulk_receiving(dev->parser, 0, &stop_bulk);
- DPRINTF("bulk receiving stopped ep %02X\n", ep);
- dev->endpoint[EP2I(ep)].bulk_receiving_started = 0;
- }
- usbredir_free_bufpq(dev, ep);
-}
-
-static void usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p,
- uint8_t ep)
-{
- struct usb_redir_bulk_packet_header bulk_packet;
- size_t size = usb_packet_size(p);
- const int maxp = dev->endpoint[EP2I(ep)].max_packet_size;
-
- if (usbredir_already_in_flight(dev, p->id)) {
- p->status = USB_RET_ASYNC;
- return;
- }
-
- if (dev->endpoint[EP2I(ep)].bulk_receiving_enabled) {
- if (size != 0 && (size % maxp) == 0) {
- usbredir_handle_buffered_bulk_in_data(dev, p, ep);
- return;
- }
- WARNING("bulk recv invalid size %zd ep %02x, disabling\n", size, ep);
- assert(dev->endpoint[EP2I(ep)].pending_async_packet == NULL);
- usbredir_stop_bulk_receiving(dev, ep);
- dev->endpoint[EP2I(ep)].bulk_receiving_enabled = 0;
- }
-
- DPRINTF("bulk-out ep %02X stream %u len %zd id %"PRIu64"\n",
- ep, p->stream, size, p->id);
-
- bulk_packet.endpoint = ep;
- bulk_packet.length = size;
- bulk_packet.stream_id = p->stream;
- bulk_packet.length_high = size >> 16;
- assert(bulk_packet.length_high == 0 ||
- usbredirparser_peer_has_cap(dev->parser,
- usb_redir_cap_32bits_bulk_length));
-
- if (ep & USB_DIR_IN) {
- usbredirparser_send_bulk_packet(dev->parser, p->id,
- &bulk_packet, NULL, 0);
- } else {
- uint8_t buf[size];
- usb_packet_copy(p, buf, size);
- usbredir_log_data(dev, "bulk data out:", buf, size);
- usbredirparser_send_bulk_packet(dev->parser, p->id,
- &bulk_packet, buf, size);
- }
- usbredirparser_do_write(dev->parser);
- p->status = USB_RET_ASYNC;
-}
-
-static void usbredir_handle_interrupt_in_data(USBRedirDevice *dev,
- USBPacket *p, uint8_t ep)
-{
- /* Input interrupt endpoint, buffered packet input */
- struct buf_packet *intp;
- int status, len;
-
- if (!dev->endpoint[EP2I(ep)].interrupt_started &&
- !dev->endpoint[EP2I(ep)].interrupt_error) {
- struct usb_redir_start_interrupt_receiving_header start_int = {
- .endpoint = ep,
- };
- /* No id, we look at the ep when receiving a status back */
- usbredirparser_send_start_interrupt_receiving(dev->parser, 0,
- &start_int);
- usbredirparser_do_write(dev->parser);
- DPRINTF("interrupt recv started ep %02X\n", ep);
- dev->endpoint[EP2I(ep)].interrupt_started = 1;
- /* We don't really want to drop interrupt packets ever, but
- having some upper limit to how much we buffer is good. */
- dev->endpoint[EP2I(ep)].bufpq_target_size = 1000;
- dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0;
- }
-
- intp = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq);
- if (intp == NULL) {
- DPRINTF2("interrupt-token-in ep %02X, no intp\n", ep);
- /* Check interrupt_error for stream errors */
- status = dev->endpoint[EP2I(ep)].interrupt_error;
- dev->endpoint[EP2I(ep)].interrupt_error = 0;
- if (status) {
- usbredir_handle_status(dev, p, status);
- } else {
- p->status = USB_RET_NAK;
- }
- return;
- }
- DPRINTF("interrupt-token-in ep %02X status %d len %d\n", ep,
- intp->status, intp->len);
-
- status = intp->status;
- len = intp->len;
- if (len > p->iov.size) {
- ERROR("received int data is larger then packet ep %02X\n", ep);
- len = p->iov.size;
- status = usb_redir_babble;
- }
- usb_packet_copy(p, intp->data, len);
- bufp_free(dev, intp, ep);
- usbredir_handle_status(dev, p, status);
-}
-
-/*
- * Handle interrupt out data, the usbredir protocol expects us to do this
- * async, so that it can report back a completion status. But guests will
- * expect immediate completion for an interrupt endpoint, and handling this
- * async causes migration issues. So we report success directly, counting
- * on the fact that output interrupt packets normally always succeed.
- */
-static void usbredir_handle_interrupt_out_data(USBRedirDevice *dev,
- USBPacket *p, uint8_t ep)
-{
- struct usb_redir_interrupt_packet_header interrupt_packet;
- uint8_t buf[p->iov.size];
-
- DPRINTF("interrupt-out ep %02X len %zd id %"PRIu64"\n", ep,
- p->iov.size, p->id);
-
- interrupt_packet.endpoint = ep;
- interrupt_packet.length = p->iov.size;
-
- usb_packet_copy(p, buf, p->iov.size);
- usbredir_log_data(dev, "interrupt data out:", buf, p->iov.size);
- usbredirparser_send_interrupt_packet(dev->parser, p->id,
- &interrupt_packet, buf, p->iov.size);
- usbredirparser_do_write(dev->parser);
-}
-
-static void usbredir_stop_interrupt_receiving(USBRedirDevice *dev,
- uint8_t ep)
-{
- struct usb_redir_stop_interrupt_receiving_header stop_interrupt_recv = {
- .endpoint = ep
- };
- if (dev->endpoint[EP2I(ep)].interrupt_started) {
- usbredirparser_send_stop_interrupt_receiving(dev->parser, 0,
- &stop_interrupt_recv);
- DPRINTF("interrupt recv stopped ep %02X\n", ep);
- dev->endpoint[EP2I(ep)].interrupt_started = 0;
- }
- dev->endpoint[EP2I(ep)].interrupt_error = 0;
- usbredir_free_bufpq(dev, ep);
-}
-
-static void usbredir_handle_data(USBDevice *udev, USBPacket *p)
-{
- USBRedirDevice *dev = USB_REDIRECT(udev);
- uint8_t ep;
-
- ep = p->ep->nr;
- if (p->pid == USB_TOKEN_IN) {
- ep |= USB_DIR_IN;
- }
-
- switch (dev->endpoint[EP2I(ep)].type) {
- case USB_ENDPOINT_XFER_CONTROL:
- ERROR("handle_data called for control transfer on ep %02X\n", ep);
- p->status = USB_RET_NAK;
- break;
- case USB_ENDPOINT_XFER_BULK:
- if (p->state == USB_PACKET_SETUP && p->pid == USB_TOKEN_IN &&
- p->ep->pipeline) {
- p->status = USB_RET_ADD_TO_QUEUE;
- break;
- }
- usbredir_handle_bulk_data(dev, p, ep);
- break;
- case USB_ENDPOINT_XFER_ISOC:
- usbredir_handle_iso_data(dev, p, ep);
- break;
- case USB_ENDPOINT_XFER_INT:
- if (ep & USB_DIR_IN) {
- usbredir_handle_interrupt_in_data(dev, p, ep);
- } else {
- usbredir_handle_interrupt_out_data(dev, p, ep);
- }
- break;
- default:
- ERROR("handle_data ep %02X has unknown type %d\n", ep,
- dev->endpoint[EP2I(ep)].type);
- p->status = USB_RET_NAK;
- }
-}
-
-static void usbredir_flush_ep_queue(USBDevice *dev, USBEndpoint *ep)
-{
- if (ep->pid == USB_TOKEN_IN && ep->pipeline) {
- usb_ep_combine_input_packets(ep);
- }
-}
-
-static void usbredir_stop_ep(USBRedirDevice *dev, int i)
-{
- uint8_t ep = I2EP(i);
-
- switch (dev->endpoint[i].type) {
- case USB_ENDPOINT_XFER_BULK:
- if (ep & USB_DIR_IN) {
- usbredir_stop_bulk_receiving(dev, ep);
- }
- break;
- case USB_ENDPOINT_XFER_ISOC:
- usbredir_stop_iso_stream(dev, ep);
- break;
- case USB_ENDPOINT_XFER_INT:
- if (ep & USB_DIR_IN) {
- usbredir_stop_interrupt_receiving(dev, ep);
- }
- break;
- }
- usbredir_free_bufpq(dev, ep);
-}
-
-static void usbredir_ep_stopped(USBDevice *udev, USBEndpoint *uep)
-{
- USBRedirDevice *dev = USB_REDIRECT(udev);
-
- usbredir_stop_ep(dev, USBEP2I(uep));
- usbredirparser_do_write(dev->parser);
-}
-
-static void usbredir_set_config(USBRedirDevice *dev, USBPacket *p,
- int config)
-{
- struct usb_redir_set_configuration_header set_config;
- int i;
-
- DPRINTF("set config %d id %"PRIu64"\n", config, p->id);
-
- for (i = 0; i < MAX_ENDPOINTS; i++) {
- usbredir_stop_ep(dev, i);
- }
-
- set_config.configuration = config;
- usbredirparser_send_set_configuration(dev->parser, p->id, &set_config);
- usbredirparser_do_write(dev->parser);
- p->status = USB_RET_ASYNC;
-}
-
-static void usbredir_get_config(USBRedirDevice *dev, USBPacket *p)
-{
- DPRINTF("get config id %"PRIu64"\n", p->id);
-
- usbredirparser_send_get_configuration(dev->parser, p->id);
- usbredirparser_do_write(dev->parser);
- p->status = USB_RET_ASYNC;
-}
-
-static void usbredir_set_interface(USBRedirDevice *dev, USBPacket *p,
- int interface, int alt)
-{
- struct usb_redir_set_alt_setting_header set_alt;
- int i;
-
- DPRINTF("set interface %d alt %d id %"PRIu64"\n", interface, alt, p->id);
-
- for (i = 0; i < MAX_ENDPOINTS; i++) {
- if (dev->endpoint[i].interface == interface) {
- usbredir_stop_ep(dev, i);
- }
- }
-
- set_alt.interface = interface;
- set_alt.alt = alt;
- usbredirparser_send_set_alt_setting(dev->parser, p->id, &set_alt);
- usbredirparser_do_write(dev->parser);
- p->status = USB_RET_ASYNC;
-}
-
-static void usbredir_get_interface(USBRedirDevice *dev, USBPacket *p,
- int interface)
-{
- struct usb_redir_get_alt_setting_header get_alt;
-
- DPRINTF("get interface %d id %"PRIu64"\n", interface, p->id);
-
- get_alt.interface = interface;
- usbredirparser_send_get_alt_setting(dev->parser, p->id, &get_alt);
- usbredirparser_do_write(dev->parser);
- p->status = USB_RET_ASYNC;
-}
-
-static void usbredir_handle_control(USBDevice *udev, USBPacket *p,
- int request, int value, int index, int length, uint8_t *data)
-{
- USBRedirDevice *dev = USB_REDIRECT(udev);
- struct usb_redir_control_packet_header control_packet;
-
- if (usbredir_already_in_flight(dev, p->id)) {
- p->status = USB_RET_ASYNC;
- return;
- }
-
- /* Special cases for certain standard device requests */
- switch (request) {
- case DeviceOutRequest | USB_REQ_SET_ADDRESS:
- DPRINTF("set address %d\n", value);
- dev->dev.addr = value;
- return;
- case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
- usbredir_set_config(dev, p, value & 0xff);
- return;
- case DeviceRequest | USB_REQ_GET_CONFIGURATION:
- usbredir_get_config(dev, p);
- return;
- case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
- usbredir_set_interface(dev, p, index, value);
- return;
- case InterfaceRequest | USB_REQ_GET_INTERFACE:
- usbredir_get_interface(dev, p, index);
- return;
- }
-
- /* Normal ctrl requests, note request is (bRequestType << 8) | bRequest */
- DPRINTF(
- "ctrl-out type 0x%x req 0x%x val 0x%x index %d len %d id %"PRIu64"\n",
- request >> 8, request & 0xff, value, index, length, p->id);
-
- control_packet.request = request & 0xFF;
- control_packet.requesttype = request >> 8;
- control_packet.endpoint = control_packet.requesttype & USB_DIR_IN;
- control_packet.value = value;
- control_packet.index = index;
- control_packet.length = length;
-
- if (control_packet.requesttype & USB_DIR_IN) {
- usbredirparser_send_control_packet(dev->parser, p->id,
- &control_packet, NULL, 0);
- } else {
- usbredir_log_data(dev, "ctrl data out:", data, length);
- usbredirparser_send_control_packet(dev->parser, p->id,
- &control_packet, data, length);
- }
- usbredirparser_do_write(dev->parser);
- p->status = USB_RET_ASYNC;
-}
-
-static int usbredir_alloc_streams(USBDevice *udev, USBEndpoint **eps,
- int nr_eps, int streams)
-{
- USBRedirDevice *dev = USB_REDIRECT(udev);
-#if USBREDIR_VERSION >= 0x000700
- struct usb_redir_alloc_bulk_streams_header alloc_streams;
- int i;
-
- if (!usbredirparser_peer_has_cap(dev->parser,
- usb_redir_cap_bulk_streams)) {
- ERROR("peer does not support streams\n");
- goto reject;
- }
-
- if (streams == 0) {
- ERROR("request to allocate 0 streams\n");
- return -1;
- }
-
- alloc_streams.no_streams = streams;
- alloc_streams.endpoints = 0;
- for (i = 0; i < nr_eps; i++) {
- alloc_streams.endpoints |= 1 << USBEP2I(eps[i]);
- }
- usbredirparser_send_alloc_bulk_streams(dev->parser, 0, &alloc_streams);
- usbredirparser_do_write(dev->parser);
-
- return 0;
-#else
- ERROR("usbredir_alloc_streams not implemented\n");
- goto reject;
-#endif
-reject:
- ERROR("streams are not available, disconnecting\n");
- qemu_bh_schedule(dev->device_reject_bh);
- return -1;
-}
-
-static void usbredir_free_streams(USBDevice *udev, USBEndpoint **eps,
- int nr_eps)
-{
-#if USBREDIR_VERSION >= 0x000700
- USBRedirDevice *dev = USB_REDIRECT(udev);
- struct usb_redir_free_bulk_streams_header free_streams;
- int i;
-
- if (!usbredirparser_peer_has_cap(dev->parser,
- usb_redir_cap_bulk_streams)) {
- return;
- }
-
- free_streams.endpoints = 0;
- for (i = 0; i < nr_eps; i++) {
- free_streams.endpoints |= 1 << USBEP2I(eps[i]);
- }
- usbredirparser_send_free_bulk_streams(dev->parser, 0, &free_streams);
- usbredirparser_do_write(dev->parser);
-#endif
-}
-
-/*
- * Close events can be triggered by usbredirparser_do_write which gets called
- * from within the USBDevice data / control packet callbacks and doing a
- * usb_detach from within these callbacks is not a good idea.
- *
- * So we use a bh handler to take care of close events.
- */
-static void usbredir_chardev_close_bh(void *opaque)
-{
- USBRedirDevice *dev = opaque;
-
- qemu_bh_cancel(dev->device_reject_bh);
- usbredir_device_disconnect(dev);
-
- if (dev->parser) {
- DPRINTF("destroying usbredirparser\n");
- usbredirparser_destroy(dev->parser);
- dev->parser = NULL;
- }
- if (dev->watch) {
- g_source_remove(dev->watch);
- dev->watch = 0;
- }
-}
-
-static void usbredir_create_parser(USBRedirDevice *dev)
-{
- uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0, };
- int flags = 0;
-
- DPRINTF("creating usbredirparser\n");
-
- dev->parser = qemu_oom_check(usbredirparser_create());
- dev->parser->priv = dev;
- dev->parser->log_func = usbredir_log;
- dev->parser->read_func = usbredir_read;
- dev->parser->write_func = usbredir_write;
- dev->parser->hello_func = usbredir_hello;
- dev->parser->device_connect_func = usbredir_device_connect;
- dev->parser->device_disconnect_func = usbredir_device_disconnect;
- dev->parser->interface_info_func = usbredir_interface_info;
- dev->parser->ep_info_func = usbredir_ep_info;
- dev->parser->configuration_status_func = usbredir_configuration_status;
- dev->parser->alt_setting_status_func = usbredir_alt_setting_status;
- dev->parser->iso_stream_status_func = usbredir_iso_stream_status;
- dev->parser->interrupt_receiving_status_func =
- usbredir_interrupt_receiving_status;
- dev->parser->bulk_streams_status_func = usbredir_bulk_streams_status;
- dev->parser->bulk_receiving_status_func = usbredir_bulk_receiving_status;
- dev->parser->control_packet_func = usbredir_control_packet;
- dev->parser->bulk_packet_func = usbredir_bulk_packet;
- dev->parser->iso_packet_func = usbredir_iso_packet;
- dev->parser->interrupt_packet_func = usbredir_interrupt_packet;
- dev->parser->buffered_bulk_packet_func = usbredir_buffered_bulk_packet;
- dev->read_buf = NULL;
- dev->read_buf_size = 0;
-
- usbredirparser_caps_set_cap(caps, usb_redir_cap_connect_device_version);
- usbredirparser_caps_set_cap(caps, usb_redir_cap_filter);
- usbredirparser_caps_set_cap(caps, usb_redir_cap_ep_info_max_packet_size);
- usbredirparser_caps_set_cap(caps, usb_redir_cap_64bits_ids);
- usbredirparser_caps_set_cap(caps, usb_redir_cap_32bits_bulk_length);
- usbredirparser_caps_set_cap(caps, usb_redir_cap_bulk_receiving);
-#if USBREDIR_VERSION >= 0x000700
- usbredirparser_caps_set_cap(caps, usb_redir_cap_bulk_streams);
-#endif
-
- if (runstate_check(RUN_STATE_INMIGRATE)) {
- flags |= usbredirparser_fl_no_hello;
- }
- usbredirparser_init(dev->parser, VERSION, caps, USB_REDIR_CAPS_SIZE,
- flags);
- usbredirparser_do_write(dev->parser);
-}
-
-static void usbredir_reject_device(USBRedirDevice *dev)
-{
- usbredir_device_disconnect(dev);
- if (usbredirparser_peer_has_cap(dev->parser, usb_redir_cap_filter)) {
- usbredirparser_send_filter_reject(dev->parser);
- usbredirparser_do_write(dev->parser);
- }
-}
-
-/*
- * We may need to reject the device when the hcd calls alloc_streams, doing
- * an usb_detach from within a hcd call is not a good idea, hence this bh.
- */
-static void usbredir_device_reject_bh(void *opaque)
-{
- USBRedirDevice *dev = opaque;
-
- usbredir_reject_device(dev);
-}
-
-static void usbredir_do_attach(void *opaque)
-{
- USBRedirDevice *dev = opaque;
- Error *local_err = NULL;
-
- /* In order to work properly with XHCI controllers we need these caps */
- if ((dev->dev.port->speedmask & USB_SPEED_MASK_SUPER) && !(
- usbredirparser_peer_has_cap(dev->parser,
- usb_redir_cap_ep_info_max_packet_size) &&
- usbredirparser_peer_has_cap(dev->parser,
- usb_redir_cap_32bits_bulk_length) &&
- usbredirparser_peer_has_cap(dev->parser,
- usb_redir_cap_64bits_ids))) {
- ERROR("usb-redir-host lacks capabilities needed for use with XHCI\n");
- usbredir_reject_device(dev);
- return;
- }
-
- usb_device_attach(&dev->dev, &local_err);
- if (local_err) {
- error_report_err(local_err);
- WARNING("rejecting device due to speed mismatch\n");
- usbredir_reject_device(dev);
- }
-}
-
-/*
- * chardev callbacks
- */
-
-static int usbredir_chardev_can_read(void *opaque)
-{
- USBRedirDevice *dev = opaque;
-
- if (!dev->parser) {
- WARNING("chardev_can_read called on non open chardev!\n");
- return 0;
- }
-
- /* Don't read new data from the chardev until our state is fully synced */
- if (!runstate_check(RUN_STATE_RUNNING)) {
- return 0;
- }
-
- /* usbredir_parser_do_read will consume *all* data we give it */
- return 1024 * 1024;
-}
-
-static void usbredir_chardev_read(void *opaque, const uint8_t *buf, int size)
-{
- USBRedirDevice *dev = opaque;
-
- /* No recursion allowed! */
- assert(dev->read_buf == NULL);
-
- dev->read_buf = buf;
- dev->read_buf_size = size;
-
- usbredirparser_do_read(dev->parser);
- /* Send any acks, etc. which may be queued now */
- usbredirparser_do_write(dev->parser);
-}
-
-static void usbredir_chardev_event(void *opaque, int event)
-{
- USBRedirDevice *dev = opaque;
-
- switch (event) {
- case CHR_EVENT_OPENED:
- DPRINTF("chardev open\n");
- /* Make sure any pending closes are handled (no-op if none pending) */
- usbredir_chardev_close_bh(dev);
- qemu_bh_cancel(dev->chardev_close_bh);
- usbredir_create_parser(dev);
- break;
- case CHR_EVENT_CLOSED:
- DPRINTF("chardev close\n");
- qemu_bh_schedule(dev->chardev_close_bh);
- break;
- }
-}
-
-/*
- * init + destroy
- */
-
-static void usbredir_vm_state_change(void *priv, int running, RunState state)
-{
- USBRedirDevice *dev = priv;
-
- if (state == RUN_STATE_RUNNING && dev->parser != NULL) {
- usbredirparser_do_write(dev->parser); /* Flush any pending writes */
- }
-}
-
-static void usbredir_init_endpoints(USBRedirDevice *dev)
-{
- int i;
-
- usb_ep_init(&dev->dev);
- memset(dev->endpoint, 0, sizeof(dev->endpoint));
- for (i = 0; i < MAX_ENDPOINTS; i++) {
- dev->endpoint[i].dev = dev;
- QTAILQ_INIT(&dev->endpoint[i].bufpq);
- }
-}
-
-static void usbredir_realize(USBDevice *udev, Error **errp)
-{
- USBRedirDevice *dev = USB_REDIRECT(udev);
- int i;
-
- if (dev->cs == NULL) {
- error_setg(errp, QERR_MISSING_PARAMETER, "chardev");
- return;
- }
-
- if (dev->filter_str) {
- i = usbredirfilter_string_to_rules(dev->filter_str, ":", "|",
- &dev->filter_rules,
- &dev->filter_rules_count);
- if (i) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "filter",
- "a usb device filter string");
- return;
- }
- }
-
- dev->chardev_close_bh = qemu_bh_new(usbredir_chardev_close_bh, dev);
- dev->device_reject_bh = qemu_bh_new(usbredir_device_reject_bh, dev);
- dev->attach_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, usbredir_do_attach, dev);
-
- packet_id_queue_init(&dev->cancelled, dev, "cancelled");
- packet_id_queue_init(&dev->already_in_flight, dev, "already-in-flight");
- usbredir_init_endpoints(dev);
-
- /* We'll do the attach once we receive the speed from the usb-host */
- udev->auto_attach = 0;
-
- /* Will be cleared during setup when we find conflicts */
- dev->compatible_speedmask = USB_SPEED_MASK_FULL | USB_SPEED_MASK_HIGH;
-
- /* Let the backend know we are ready */
- qemu_chr_add_handlers(dev->cs, usbredir_chardev_can_read,
- usbredir_chardev_read, usbredir_chardev_event, dev);
-
- qemu_add_vm_change_state_handler(usbredir_vm_state_change, dev);
-}
-
-static void usbredir_cleanup_device_queues(USBRedirDevice *dev)
-{
- int i;
-
- packet_id_queue_empty(&dev->cancelled);
- packet_id_queue_empty(&dev->already_in_flight);
- for (i = 0; i < MAX_ENDPOINTS; i++) {
- usbredir_free_bufpq(dev, I2EP(i));
- }
-}
-
-static void usbredir_handle_destroy(USBDevice *udev)
-{
- USBRedirDevice *dev = USB_REDIRECT(udev);
-
- qemu_chr_delete(dev->cs);
- dev->cs = NULL;
- /* Note must be done after qemu_chr_close, as that causes a close event */
- qemu_bh_delete(dev->chardev_close_bh);
- qemu_bh_delete(dev->device_reject_bh);
-
- timer_del(dev->attach_timer);
- timer_free(dev->attach_timer);
-
- usbredir_cleanup_device_queues(dev);
-
- if (dev->parser) {
- usbredirparser_destroy(dev->parser);
- }
- if (dev->watch) {
- g_source_remove(dev->watch);
- }
-
- free(dev->filter_rules);
-}
-
-static int usbredir_check_filter(USBRedirDevice *dev)
-{
- if (dev->interface_info.interface_count == NO_INTERFACE_INFO) {
- ERROR("No interface info for device\n");
- goto error;
- }
-
- if (dev->filter_rules) {
- if (!usbredirparser_peer_has_cap(dev->parser,
- usb_redir_cap_connect_device_version)) {
- ERROR("Device filter specified and peer does not have the "
- "connect_device_version capability\n");
- goto error;
- }
-
- if (usbredirfilter_check(
- dev->filter_rules,
- dev->filter_rules_count,
- dev->device_info.device_class,
- dev->device_info.device_subclass,
- dev->device_info.device_protocol,
- dev->interface_info.interface_class,
- dev->interface_info.interface_subclass,
- dev->interface_info.interface_protocol,
- dev->interface_info.interface_count,
- dev->device_info.vendor_id,
- dev->device_info.product_id,
- dev->device_info.device_version_bcd,
- 0) != 0) {
- goto error;
- }
- }
-
- return 0;
-
-error:
- usbredir_reject_device(dev);
- return -1;
-}
-
-static void usbredir_check_bulk_receiving(USBRedirDevice *dev)
-{
- int i, j, quirks;
-
- if (!usbredirparser_peer_has_cap(dev->parser,
- usb_redir_cap_bulk_receiving)) {
- return;
- }
-
- for (i = EP2I(USB_DIR_IN); i < MAX_ENDPOINTS; i++) {
- dev->endpoint[i].bulk_receiving_enabled = 0;
- }
- for (i = 0; i < dev->interface_info.interface_count; i++) {
- quirks = usb_get_quirks(dev->device_info.vendor_id,
- dev->device_info.product_id,
- dev->interface_info.interface_class[i],
- dev->interface_info.interface_subclass[i],
- dev->interface_info.interface_protocol[i]);
- if (!(quirks & USB_QUIRK_BUFFER_BULK_IN)) {
- continue;
- }
- if (quirks & USB_QUIRK_IS_FTDI) {
- dev->buffered_bulk_in_complete =
- usbredir_buffered_bulk_in_complete_ftdi;
- } else {
- dev->buffered_bulk_in_complete =
- usbredir_buffered_bulk_in_complete_raw;
- }
-
- for (j = EP2I(USB_DIR_IN); j < MAX_ENDPOINTS; j++) {
- if (dev->endpoint[j].interface ==
- dev->interface_info.interface[i] &&
- dev->endpoint[j].type == USB_ENDPOINT_XFER_BULK &&
- dev->endpoint[j].max_packet_size != 0) {
- dev->endpoint[j].bulk_receiving_enabled = 1;
- /*
- * With buffering pipelining is not necessary. Also packet
- * combining and bulk in buffering don't play nice together!
- */
- I2USBEP(dev, j)->pipeline = false;
- break; /* Only buffer for the first ep of each intf */
- }
- }
- }
-}
-
-/*
- * usbredirparser packet complete callbacks
- */
-
-static void usbredir_handle_status(USBRedirDevice *dev, USBPacket *p,
- int status)
-{
- switch (status) {
- case usb_redir_success:
- p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
- break;
- case usb_redir_stall:
- p->status = USB_RET_STALL;
- break;
- case usb_redir_cancelled:
- /*
- * When the usbredir-host unredirects a device, it will report a status
- * of cancelled for all pending packets, followed by a disconnect msg.
- */
- p->status = USB_RET_IOERROR;
- break;
- case usb_redir_inval:
- WARNING("got invalid param error from usb-host?\n");
- p->status = USB_RET_IOERROR;
- break;
- case usb_redir_babble:
- p->status = USB_RET_BABBLE;
- break;
- case usb_redir_ioerror:
- case usb_redir_timeout:
- default:
- p->status = USB_RET_IOERROR;
- }
-}
-
-static void usbredir_hello(void *priv, struct usb_redir_hello_header *h)
-{
- USBRedirDevice *dev = priv;
-
- /* Try to send the filter info now that we've the usb-host's caps */
- if (usbredirparser_peer_has_cap(dev->parser, usb_redir_cap_filter) &&
- dev->filter_rules) {
- usbredirparser_send_filter_filter(dev->parser, dev->filter_rules,
- dev->filter_rules_count);
- usbredirparser_do_write(dev->parser);
- }
-}
-
-static void usbredir_device_connect(void *priv,
- struct usb_redir_device_connect_header *device_connect)
-{
- USBRedirDevice *dev = priv;
- const char *speed;
-
- if (timer_pending(dev->attach_timer) || dev->dev.attached) {
- ERROR("Received device connect while already connected\n");
- return;
- }
-
- switch (device_connect->speed) {
- case usb_redir_speed_low:
- speed = "low speed";
- dev->dev.speed = USB_SPEED_LOW;
- dev->compatible_speedmask &= ~USB_SPEED_MASK_FULL;
- dev->compatible_speedmask &= ~USB_SPEED_MASK_HIGH;
- break;
- case usb_redir_speed_full:
- speed = "full speed";
- dev->dev.speed = USB_SPEED_FULL;
- dev->compatible_speedmask &= ~USB_SPEED_MASK_HIGH;
- break;
- case usb_redir_speed_high:
- speed = "high speed";
- dev->dev.speed = USB_SPEED_HIGH;
- break;
- case usb_redir_speed_super:
- speed = "super speed";
- dev->dev.speed = USB_SPEED_SUPER;
- break;
- default:
- speed = "unknown speed";
- dev->dev.speed = USB_SPEED_FULL;
- }
-
- if (usbredirparser_peer_has_cap(dev->parser,
- usb_redir_cap_connect_device_version)) {
- INFO("attaching %s device %04x:%04x version %d.%d class %02x\n",
- speed, device_connect->vendor_id, device_connect->product_id,
- ((device_connect->device_version_bcd & 0xf000) >> 12) * 10 +
- ((device_connect->device_version_bcd & 0x0f00) >> 8),
- ((device_connect->device_version_bcd & 0x00f0) >> 4) * 10 +
- ((device_connect->device_version_bcd & 0x000f) >> 0),
- device_connect->device_class);
- } else {
- INFO("attaching %s device %04x:%04x class %02x\n", speed,
- device_connect->vendor_id, device_connect->product_id,
- device_connect->device_class);
- }
-
- dev->dev.speedmask = (1 << dev->dev.speed) | dev->compatible_speedmask;
- dev->device_info = *device_connect;
-
- if (usbredir_check_filter(dev)) {
- WARNING("Device %04x:%04x rejected by device filter, not attaching\n",
- device_connect->vendor_id, device_connect->product_id);
- return;
- }
-
- usbredir_check_bulk_receiving(dev);
- timer_mod(dev->attach_timer, dev->next_attach_time);
-}
-
-static void usbredir_device_disconnect(void *priv)
-{
- USBRedirDevice *dev = priv;
-
- /* Stop any pending attaches */
- timer_del(dev->attach_timer);
-
- if (dev->dev.attached) {
- DPRINTF("detaching device\n");
- usb_device_detach(&dev->dev);
- /*
- * Delay next usb device attach to give the guest a chance to see
- * see the detach / attach in case of quick close / open succession
- */
- dev->next_attach_time = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 200;
- }
-
- /* Reset state so that the next dev connected starts with a clean slate */
- usbredir_cleanup_device_queues(dev);
- usbredir_init_endpoints(dev);
- dev->interface_info.interface_count = NO_INTERFACE_INFO;
- dev->dev.addr = 0;
- dev->dev.speed = 0;
- dev->compatible_speedmask = USB_SPEED_MASK_FULL | USB_SPEED_MASK_HIGH;
-}
-
-static void usbredir_interface_info(void *priv,
- struct usb_redir_interface_info_header *interface_info)
-{
- USBRedirDevice *dev = priv;
-
- dev->interface_info = *interface_info;
-
- /*
- * If we receive interface info after the device has already been
- * connected (ie on a set_config), re-check interface dependent things.
- */
- if (timer_pending(dev->attach_timer) || dev->dev.attached) {
- usbredir_check_bulk_receiving(dev);
- if (usbredir_check_filter(dev)) {
- ERROR("Device no longer matches filter after interface info "
- "change, disconnecting!\n");
- }
- }
-}
-
-static void usbredir_mark_speed_incompatible(USBRedirDevice *dev, int speed)
-{
- dev->compatible_speedmask &= ~(1 << speed);
- dev->dev.speedmask = (1 << dev->dev.speed) | dev->compatible_speedmask;
-}
-
-static void usbredir_set_pipeline(USBRedirDevice *dev, struct USBEndpoint *uep)
-{
- if (uep->type != USB_ENDPOINT_XFER_BULK) {
- return;
- }
- if (uep->pid == USB_TOKEN_OUT) {
- uep->pipeline = true;
- }
- if (uep->pid == USB_TOKEN_IN && uep->max_packet_size != 0 &&
- usbredirparser_peer_has_cap(dev->parser,
- usb_redir_cap_32bits_bulk_length)) {
- uep->pipeline = true;
- }
-}
-
-static void usbredir_setup_usb_eps(USBRedirDevice *dev)
-{
- struct USBEndpoint *usb_ep;
- int i;
-
- for (i = 0; i < MAX_ENDPOINTS; i++) {
- usb_ep = I2USBEP(dev, i);
- usb_ep->type = dev->endpoint[i].type;
- usb_ep->ifnum = dev->endpoint[i].interface;
- usb_ep->max_packet_size = dev->endpoint[i].max_packet_size;
- usb_ep->max_streams = dev->endpoint[i].max_streams;
- usbredir_set_pipeline(dev, usb_ep);
- }
-}
-
-static void usbredir_ep_info(void *priv,
- struct usb_redir_ep_info_header *ep_info)
-{
- USBRedirDevice *dev = priv;
- int i;
-
- for (i = 0; i < MAX_ENDPOINTS; i++) {
- dev->endpoint[i].type = ep_info->type[i];
- dev->endpoint[i].interval = ep_info->interval[i];
- dev->endpoint[i].interface = ep_info->interface[i];
- if (usbredirparser_peer_has_cap(dev->parser,
- usb_redir_cap_ep_info_max_packet_size)) {
- dev->endpoint[i].max_packet_size = ep_info->max_packet_size[i];
- }
-#if USBREDIR_VERSION >= 0x000700
- if (usbredirparser_peer_has_cap(dev->parser,
- usb_redir_cap_bulk_streams)) {
- dev->endpoint[i].max_streams = ep_info->max_streams[i];
- }
-#endif
- switch (dev->endpoint[i].type) {
- case usb_redir_type_invalid:
- break;
- case usb_redir_type_iso:
- usbredir_mark_speed_incompatible(dev, USB_SPEED_FULL);
- usbredir_mark_speed_incompatible(dev, USB_SPEED_HIGH);
- /* Fall through */
- case usb_redir_type_interrupt:
- if (!usbredirparser_peer_has_cap(dev->parser,
- usb_redir_cap_ep_info_max_packet_size) ||
- ep_info->max_packet_size[i] > 64) {
- usbredir_mark_speed_incompatible(dev, USB_SPEED_FULL);
- }
- if (!usbredirparser_peer_has_cap(dev->parser,
- usb_redir_cap_ep_info_max_packet_size) ||
- ep_info->max_packet_size[i] > 1024) {
- usbredir_mark_speed_incompatible(dev, USB_SPEED_HIGH);
- }
- if (dev->endpoint[i].interval == 0) {
- ERROR("Received 0 interval for isoc or irq endpoint\n");
- usbredir_reject_device(dev);
- return;
- }
- /* Fall through */
- case usb_redir_type_control:
- case usb_redir_type_bulk:
- DPRINTF("ep: %02X type: %d interface: %d\n", I2EP(i),
- dev->endpoint[i].type, dev->endpoint[i].interface);
- break;
- default:
- ERROR("Received invalid endpoint type\n");
- usbredir_reject_device(dev);
- return;
- }
- }
- /* The new ep info may have caused a speed incompatibility, recheck */
- if (dev->dev.attached &&
- !(dev->dev.port->speedmask & dev->dev.speedmask)) {
- ERROR("Device no longer matches speed after endpoint info change, "
- "disconnecting!\n");
- usbredir_reject_device(dev);
- return;
- }
- usbredir_setup_usb_eps(dev);
- usbredir_check_bulk_receiving(dev);
-}
-
-static void usbredir_configuration_status(void *priv, uint64_t id,
- struct usb_redir_configuration_status_header *config_status)
-{
- USBRedirDevice *dev = priv;
- USBPacket *p;
-
- DPRINTF("set config status %d config %d id %"PRIu64"\n",
- config_status->status, config_status->configuration, id);
-
- p = usbredir_find_packet_by_id(dev, 0, id);
- if (p) {
- if (dev->dev.setup_buf[0] & USB_DIR_IN) {
- dev->dev.data_buf[0] = config_status->configuration;
- p->actual_length = 1;
- }
- usbredir_handle_status(dev, p, config_status->status);
- usb_generic_async_ctrl_complete(&dev->dev, p);
- }
-}
-
-static void usbredir_alt_setting_status(void *priv, uint64_t id,
- struct usb_redir_alt_setting_status_header *alt_setting_status)
-{
- USBRedirDevice *dev = priv;
- USBPacket *p;
-
- DPRINTF("alt status %d intf %d alt %d id: %"PRIu64"\n",
- alt_setting_status->status, alt_setting_status->interface,
- alt_setting_status->alt, id);
-
- p = usbredir_find_packet_by_id(dev, 0, id);
- if (p) {
- if (dev->dev.setup_buf[0] & USB_DIR_IN) {
- dev->dev.data_buf[0] = alt_setting_status->alt;
- p->actual_length = 1;
- }
- usbredir_handle_status(dev, p, alt_setting_status->status);
- usb_generic_async_ctrl_complete(&dev->dev, p);
- }
-}
-
-static void usbredir_iso_stream_status(void *priv, uint64_t id,
- struct usb_redir_iso_stream_status_header *iso_stream_status)
-{
- USBRedirDevice *dev = priv;
- uint8_t ep = iso_stream_status->endpoint;
-
- DPRINTF("iso status %d ep %02X id %"PRIu64"\n", iso_stream_status->status,
- ep, id);
-
- if (!dev->dev.attached || !dev->endpoint[EP2I(ep)].iso_started) {
- return;
- }
-
- dev->endpoint[EP2I(ep)].iso_error = iso_stream_status->status;
- if (iso_stream_status->status == usb_redir_stall) {
- DPRINTF("iso stream stopped by peer ep %02X\n", ep);
- dev->endpoint[EP2I(ep)].iso_started = 0;
- }
-}
-
-static void usbredir_interrupt_receiving_status(void *priv, uint64_t id,
- struct usb_redir_interrupt_receiving_status_header
- *interrupt_receiving_status)
-{
- USBRedirDevice *dev = priv;
- uint8_t ep = interrupt_receiving_status->endpoint;
-
- DPRINTF("interrupt recv status %d ep %02X id %"PRIu64"\n",
- interrupt_receiving_status->status, ep, id);
-
- if (!dev->dev.attached || !dev->endpoint[EP2I(ep)].interrupt_started) {
- return;
- }
-
- dev->endpoint[EP2I(ep)].interrupt_error =
- interrupt_receiving_status->status;
- if (interrupt_receiving_status->status == usb_redir_stall) {
- DPRINTF("interrupt receiving stopped by peer ep %02X\n", ep);
- dev->endpoint[EP2I(ep)].interrupt_started = 0;
- }
-}
-
-static void usbredir_bulk_streams_status(void *priv, uint64_t id,
- struct usb_redir_bulk_streams_status_header *bulk_streams_status)
-{
-#if USBREDIR_VERSION >= 0x000700
- USBRedirDevice *dev = priv;
-
- if (bulk_streams_status->status == usb_redir_success) {
- DPRINTF("bulk streams status %d eps %08x\n",
- bulk_streams_status->status, bulk_streams_status->endpoints);
- } else {
- ERROR("bulk streams %s failed status %d eps %08x\n",
- (bulk_streams_status->no_streams == 0) ? "free" : "alloc",
- bulk_streams_status->status, bulk_streams_status->endpoints);
- ERROR("usb-redir-host does not provide streams, disconnecting\n");
- usbredir_reject_device(dev);
- }
-#endif
-}
-
-static void usbredir_bulk_receiving_status(void *priv, uint64_t id,
- struct usb_redir_bulk_receiving_status_header *bulk_receiving_status)
-{
- USBRedirDevice *dev = priv;
- uint8_t ep = bulk_receiving_status->endpoint;
-
- DPRINTF("bulk recv status %d ep %02X id %"PRIu64"\n",
- bulk_receiving_status->status, ep, id);
-
- if (!dev->dev.attached || !dev->endpoint[EP2I(ep)].bulk_receiving_started) {
- return;
- }
-
- if (bulk_receiving_status->status == usb_redir_stall) {
- DPRINTF("bulk receiving stopped by peer ep %02X\n", ep);
- dev->endpoint[EP2I(ep)].bulk_receiving_started = 0;
- }
-}
-
-static void usbredir_control_packet(void *priv, uint64_t id,
- struct usb_redir_control_packet_header *control_packet,
- uint8_t *data, int data_len)
-{
- USBRedirDevice *dev = priv;
- USBPacket *p;
- int len = control_packet->length;
-
- DPRINTF("ctrl-in status %d len %d id %"PRIu64"\n", control_packet->status,
- len, id);
-
- /* Fix up USB-3 ep0 maxpacket size to allow superspeed connected devices
- * to work redirected to a not superspeed capable hcd */
- if (dev->dev.speed == USB_SPEED_SUPER &&
- !((dev->dev.port->speedmask & USB_SPEED_MASK_SUPER)) &&
- control_packet->requesttype == 0x80 &&
- control_packet->request == 6 &&
- control_packet->value == 0x100 && control_packet->index == 0 &&
- data_len >= 18 && data[7] == 9) {
- data[7] = 64;
- }
-
- p = usbredir_find_packet_by_id(dev, 0, id);
- if (p) {
- usbredir_handle_status(dev, p, control_packet->status);
- if (data_len > 0) {
- usbredir_log_data(dev, "ctrl data in:", data, data_len);
- if (data_len > sizeof(dev->dev.data_buf)) {
- ERROR("ctrl buffer too small (%d > %zu)\n",
- data_len, sizeof(dev->dev.data_buf));
- p->status = USB_RET_STALL;
- data_len = len = sizeof(dev->dev.data_buf);
- }
- memcpy(dev->dev.data_buf, data, data_len);
- }
- p->actual_length = len;
- usb_generic_async_ctrl_complete(&dev->dev, p);
- }
- free(data);
-}
-
-static void usbredir_bulk_packet(void *priv, uint64_t id,
- struct usb_redir_bulk_packet_header *bulk_packet,
- uint8_t *data, int data_len)
-{
- USBRedirDevice *dev = priv;
- uint8_t ep = bulk_packet->endpoint;
- int len = (bulk_packet->length_high << 16) | bulk_packet->length;
- USBPacket *p;
-
- DPRINTF("bulk-in status %d ep %02X stream %u len %d id %"PRIu64"\n",
- bulk_packet->status, ep, bulk_packet->stream_id, len, id);
-
- p = usbredir_find_packet_by_id(dev, ep, id);
- if (p) {
- size_t size = usb_packet_size(p);
- usbredir_handle_status(dev, p, bulk_packet->status);
- if (data_len > 0) {
- usbredir_log_data(dev, "bulk data in:", data, data_len);
- if (data_len > size) {
- ERROR("bulk got more data then requested (%d > %zd)\n",
- data_len, p->iov.size);
- p->status = USB_RET_BABBLE;
- data_len = len = size;
- }
- usb_packet_copy(p, data, data_len);
- }
- p->actual_length = len;
- if (p->pid == USB_TOKEN_IN && p->ep->pipeline) {
- usb_combined_input_packet_complete(&dev->dev, p);
- } else {
- usb_packet_complete(&dev->dev, p);
- }
- }
- free(data);
-}
-
-static void usbredir_iso_packet(void *priv, uint64_t id,
- struct usb_redir_iso_packet_header *iso_packet,
- uint8_t *data, int data_len)
-{
- USBRedirDevice *dev = priv;
- uint8_t ep = iso_packet->endpoint;
-
- DPRINTF2("iso-in status %d ep %02X len %d id %"PRIu64"\n",
- iso_packet->status, ep, data_len, id);
-
- if (dev->endpoint[EP2I(ep)].type != USB_ENDPOINT_XFER_ISOC) {
- ERROR("received iso packet for non iso endpoint %02X\n", ep);
- free(data);
- return;
- }
-
- if (dev->endpoint[EP2I(ep)].iso_started == 0) {
- DPRINTF("received iso packet for non started stream ep %02X\n", ep);
- free(data);
- return;
- }
-
- /* bufp_alloc also adds the packet to the ep queue */
- bufp_alloc(dev, data, data_len, iso_packet->status, ep, data);
-}
-
-static void usbredir_interrupt_packet(void *priv, uint64_t id,
- struct usb_redir_interrupt_packet_header *interrupt_packet,
- uint8_t *data, int data_len)
-{
- USBRedirDevice *dev = priv;
- uint8_t ep = interrupt_packet->endpoint;
-
- DPRINTF("interrupt-in status %d ep %02X len %d id %"PRIu64"\n",
- interrupt_packet->status, ep, data_len, id);
-
- if (dev->endpoint[EP2I(ep)].type != USB_ENDPOINT_XFER_INT) {
- ERROR("received int packet for non interrupt endpoint %02X\n", ep);
- free(data);
- return;
- }
-
- if (ep & USB_DIR_IN) {
- if (dev->endpoint[EP2I(ep)].interrupt_started == 0) {
- DPRINTF("received int packet while not started ep %02X\n", ep);
- free(data);
- return;
- }
-
- if (QTAILQ_EMPTY(&dev->endpoint[EP2I(ep)].bufpq)) {
- usb_wakeup(usb_ep_get(&dev->dev, USB_TOKEN_IN, ep & 0x0f), 0);
- }
-
- /* bufp_alloc also adds the packet to the ep queue */
- bufp_alloc(dev, data, data_len, interrupt_packet->status, ep, data);
- } else {
- /*
- * We report output interrupt packets as completed directly upon
- * submission, so all we can do here if one failed is warn.
- */
- if (interrupt_packet->status) {
- WARNING("interrupt output failed status %d ep %02X id %"PRIu64"\n",
- interrupt_packet->status, ep, id);
- }
- }
-}
-
-static void usbredir_buffered_bulk_packet(void *priv, uint64_t id,
- struct usb_redir_buffered_bulk_packet_header *buffered_bulk_packet,
- uint8_t *data, int data_len)
-{
- USBRedirDevice *dev = priv;
- uint8_t status, ep = buffered_bulk_packet->endpoint;
- void *free_on_destroy;
- int i, len;
-
- DPRINTF("buffered-bulk-in status %d ep %02X len %d id %"PRIu64"\n",
- buffered_bulk_packet->status, ep, data_len, id);
-
- if (dev->endpoint[EP2I(ep)].type != USB_ENDPOINT_XFER_BULK) {
- ERROR("received buffered-bulk packet for non bulk ep %02X\n", ep);
- free(data);
- return;
- }
-
- if (dev->endpoint[EP2I(ep)].bulk_receiving_started == 0) {
- DPRINTF("received buffered-bulk packet on not started ep %02X\n", ep);
- free(data);
- return;
- }
-
- /* Data must be in maxp chunks for buffered_bulk_add_*_data_to_packet */
- len = dev->endpoint[EP2I(ep)].max_packet_size;
- status = usb_redir_success;
- free_on_destroy = NULL;
- for (i = 0; i < data_len; i += len) {
- int r;
- if (len >= (data_len - i)) {
- len = data_len - i;
- status = buffered_bulk_packet->status;
- free_on_destroy = data;
- }
- /* bufp_alloc also adds the packet to the ep queue */
- r = bufp_alloc(dev, data + i, len, status, ep, free_on_destroy);
- if (r) {
- break;
- }
- }
-
- if (dev->endpoint[EP2I(ep)].pending_async_packet) {
- USBPacket *p = dev->endpoint[EP2I(ep)].pending_async_packet;
- dev->endpoint[EP2I(ep)].pending_async_packet = NULL;
- usbredir_buffered_bulk_in_complete(dev, p, ep);
- usb_packet_complete(&dev->dev, p);
- }
-}
-
-/*
- * Migration code
- */
-
-static void usbredir_pre_save(void *priv)
-{
- USBRedirDevice *dev = priv;
-
- usbredir_fill_already_in_flight(dev);
-}
-
-static int usbredir_post_load(void *priv, int version_id)
-{
- USBRedirDevice *dev = priv;
-
- if (dev->parser == NULL) {
- return 0;
- }
-
- switch (dev->device_info.speed) {
- case usb_redir_speed_low:
- dev->dev.speed = USB_SPEED_LOW;
- break;
- case usb_redir_speed_full:
- dev->dev.speed = USB_SPEED_FULL;
- break;
- case usb_redir_speed_high:
- dev->dev.speed = USB_SPEED_HIGH;
- break;
- case usb_redir_speed_super:
- dev->dev.speed = USB_SPEED_SUPER;
- break;
- default:
- dev->dev.speed = USB_SPEED_FULL;
- }
- dev->dev.speedmask = (1 << dev->dev.speed);
-
- usbredir_setup_usb_eps(dev);
- usbredir_check_bulk_receiving(dev);
-
- return 0;
-}
-
-/* For usbredirparser migration */
-static void usbredir_put_parser(QEMUFile *f, void *priv, size_t unused)
-{
- USBRedirDevice *dev = priv;
- uint8_t *data;
- int len;
-
- if (dev->parser == NULL) {
- qemu_put_be32(f, 0);
- return;
- }
-
- usbredirparser_serialize(dev->parser, &data, &len);
- qemu_oom_check(data);
-
- qemu_put_be32(f, len);
- qemu_put_buffer(f, data, len);
-
- free(data);
-}
-
-static int usbredir_get_parser(QEMUFile *f, void *priv, size_t unused)
-{
- USBRedirDevice *dev = priv;
- uint8_t *data;
- int len, ret;
-
- len = qemu_get_be32(f);
- if (len == 0) {
- return 0;
- }
-
- /*
- * If our chardev is not open already at this point the usbredir connection
- * has been broken (non seamless migration, or restore from disk).
- *
- * In this case create a temporary parser to receive the migration data,
- * and schedule the close_bh to report the device as disconnected to the
- * guest and to destroy the parser again.
- */
- if (dev->parser == NULL) {
- WARNING("usb-redir connection broken during migration\n");
- usbredir_create_parser(dev);
- qemu_bh_schedule(dev->chardev_close_bh);
- }
-
- data = g_malloc(len);
- qemu_get_buffer(f, data, len);
-
- ret = usbredirparser_unserialize(dev->parser, data, len);
-
- g_free(data);
-
- return ret;
-}
-
-static const VMStateInfo usbredir_parser_vmstate_info = {
- .name = "usb-redir-parser",
- .put = usbredir_put_parser,
- .get = usbredir_get_parser,
-};
-
-
-/* For buffered packets (iso/irq) queue migration */
-static void usbredir_put_bufpq(QEMUFile *f, void *priv, size_t unused)
-{
- struct endp_data *endp = priv;
- USBRedirDevice *dev = endp->dev;
- struct buf_packet *bufp;
- int len, i = 0;
-
- qemu_put_be32(f, endp->bufpq_size);
- QTAILQ_FOREACH(bufp, &endp->bufpq, next) {
- len = bufp->len - bufp->offset;
- DPRINTF("put_bufpq %d/%d len %d status %d\n", i + 1, endp->bufpq_size,
- len, bufp->status);
- qemu_put_be32(f, len);
- qemu_put_be32(f, bufp->status);
- qemu_put_buffer(f, bufp->data + bufp->offset, len);
- i++;
- }
- assert(i == endp->bufpq_size);
-}
-
-static int usbredir_get_bufpq(QEMUFile *f, void *priv, size_t unused)
-{
- struct endp_data *endp = priv;
- USBRedirDevice *dev = endp->dev;
- struct buf_packet *bufp;
- int i;
-
- endp->bufpq_size = qemu_get_be32(f);
- for (i = 0; i < endp->bufpq_size; i++) {
- bufp = g_new(struct buf_packet, 1);
- bufp->len = qemu_get_be32(f);
- bufp->status = qemu_get_be32(f);
- bufp->offset = 0;
- bufp->data = qemu_oom_check(malloc(bufp->len)); /* regular malloc! */
- bufp->free_on_destroy = bufp->data;
- qemu_get_buffer(f, bufp->data, bufp->len);
- QTAILQ_INSERT_TAIL(&endp->bufpq, bufp, next);
- DPRINTF("get_bufpq %d/%d len %d status %d\n", i + 1, endp->bufpq_size,
- bufp->len, bufp->status);
- }
- return 0;
-}
-
-static const VMStateInfo usbredir_ep_bufpq_vmstate_info = {
- .name = "usb-redir-bufpq",
- .put = usbredir_put_bufpq,
- .get = usbredir_get_bufpq,
-};
-
-
-/* For endp_data migration */
-static bool usbredir_bulk_receiving_needed(void *priv)
-{
- struct endp_data *endp = priv;
-
- return endp->bulk_receiving_started;
-}
-
-static const VMStateDescription usbredir_bulk_receiving_vmstate = {
- .name = "usb-redir-ep/bulk-receiving",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = usbredir_bulk_receiving_needed,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(bulk_receiving_started, struct endp_data),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static bool usbredir_stream_needed(void *priv)
-{
- struct endp_data *endp = priv;
-
- return endp->max_streams;
-}
-
-static const VMStateDescription usbredir_stream_vmstate = {
- .name = "usb-redir-ep/stream-state",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = usbredir_stream_needed,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(max_streams, struct endp_data),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription usbredir_ep_vmstate = {
- .name = "usb-redir-ep",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(type, struct endp_data),
- VMSTATE_UINT8(interval, struct endp_data),
- VMSTATE_UINT8(interface, struct endp_data),
- VMSTATE_UINT16(max_packet_size, struct endp_data),
- VMSTATE_UINT8(iso_started, struct endp_data),
- VMSTATE_UINT8(iso_error, struct endp_data),
- VMSTATE_UINT8(interrupt_started, struct endp_data),
- VMSTATE_UINT8(interrupt_error, struct endp_data),
- VMSTATE_UINT8(bufpq_prefilled, struct endp_data),
- VMSTATE_UINT8(bufpq_dropping_packets, struct endp_data),
- {
- .name = "bufpq",
- .version_id = 0,
- .field_exists = NULL,
- .size = 0,
- .info = &usbredir_ep_bufpq_vmstate_info,
- .flags = VMS_SINGLE,
- .offset = 0,
- },
- VMSTATE_INT32(bufpq_target_size, struct endp_data),
- VMSTATE_END_OF_LIST()
- },
- .subsections = (const VMStateDescription*[]) {
- &usbredir_bulk_receiving_vmstate,
- &usbredir_stream_vmstate,
- NULL
- }
-};
-
-
-/* For PacketIdQueue migration */
-static void usbredir_put_packet_id_q(QEMUFile *f, void *priv, size_t unused)
-{
- struct PacketIdQueue *q = priv;
- USBRedirDevice *dev = q->dev;
- struct PacketIdQueueEntry *e;
- int remain = q->size;
-
- DPRINTF("put_packet_id_q %s size %d\n", q->name, q->size);
- qemu_put_be32(f, q->size);
- QTAILQ_FOREACH(e, &q->head, next) {
- qemu_put_be64(f, e->id);
- remain--;
- }
- assert(remain == 0);
-}
-
-static int usbredir_get_packet_id_q(QEMUFile *f, void *priv, size_t unused)
-{
- struct PacketIdQueue *q = priv;
- USBRedirDevice *dev = q->dev;
- int i, size;
- uint64_t id;
-
- size = qemu_get_be32(f);
- DPRINTF("get_packet_id_q %s size %d\n", q->name, size);
- for (i = 0; i < size; i++) {
- id = qemu_get_be64(f);
- packet_id_queue_add(q, id);
- }
- assert(q->size == size);
- return 0;
-}
-
-static const VMStateInfo usbredir_ep_packet_id_q_vmstate_info = {
- .name = "usb-redir-packet-id-q",
- .put = usbredir_put_packet_id_q,
- .get = usbredir_get_packet_id_q,
-};
-
-static const VMStateDescription usbredir_ep_packet_id_queue_vmstate = {
- .name = "usb-redir-packet-id-queue",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- {
- .name = "queue",
- .version_id = 0,
- .field_exists = NULL,
- .size = 0,
- .info = &usbredir_ep_packet_id_q_vmstate_info,
- .flags = VMS_SINGLE,
- .offset = 0,
- },
- VMSTATE_END_OF_LIST()
- }
-};
-
-
-/* For usb_redir_device_connect_header migration */
-static const VMStateDescription usbredir_device_info_vmstate = {
- .name = "usb-redir-device-info",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(speed, struct usb_redir_device_connect_header),
- VMSTATE_UINT8(device_class, struct usb_redir_device_connect_header),
- VMSTATE_UINT8(device_subclass, struct usb_redir_device_connect_header),
- VMSTATE_UINT8(device_protocol, struct usb_redir_device_connect_header),
- VMSTATE_UINT16(vendor_id, struct usb_redir_device_connect_header),
- VMSTATE_UINT16(product_id, struct usb_redir_device_connect_header),
- VMSTATE_UINT16(device_version_bcd,
- struct usb_redir_device_connect_header),
- VMSTATE_END_OF_LIST()
- }
-};
-
-
-/* For usb_redir_interface_info_header migration */
-static const VMStateDescription usbredir_interface_info_vmstate = {
- .name = "usb-redir-interface-info",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(interface_count,
- struct usb_redir_interface_info_header),
- VMSTATE_UINT8_ARRAY(interface,
- struct usb_redir_interface_info_header, 32),
- VMSTATE_UINT8_ARRAY(interface_class,
- struct usb_redir_interface_info_header, 32),
- VMSTATE_UINT8_ARRAY(interface_subclass,
- struct usb_redir_interface_info_header, 32),
- VMSTATE_UINT8_ARRAY(interface_protocol,
- struct usb_redir_interface_info_header, 32),
- VMSTATE_END_OF_LIST()
- }
-};
-
-
-/* And finally the USBRedirDevice vmstate itself */
-static const VMStateDescription usbredir_vmstate = {
- .name = "usb-redir",
- .version_id = 1,
- .minimum_version_id = 1,
- .pre_save = usbredir_pre_save,
- .post_load = usbredir_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_USB_DEVICE(dev, USBRedirDevice),
- VMSTATE_TIMER_PTR(attach_timer, USBRedirDevice),
- {
- .name = "parser",
- .version_id = 0,
- .field_exists = NULL,
- .size = 0,
- .info = &usbredir_parser_vmstate_info,
- .flags = VMS_SINGLE,
- .offset = 0,
- },
- VMSTATE_STRUCT_ARRAY(endpoint, USBRedirDevice, MAX_ENDPOINTS, 1,
- usbredir_ep_vmstate, struct endp_data),
- VMSTATE_STRUCT(cancelled, USBRedirDevice, 1,
- usbredir_ep_packet_id_queue_vmstate,
- struct PacketIdQueue),
- VMSTATE_STRUCT(already_in_flight, USBRedirDevice, 1,
- usbredir_ep_packet_id_queue_vmstate,
- struct PacketIdQueue),
- VMSTATE_STRUCT(device_info, USBRedirDevice, 1,
- usbredir_device_info_vmstate,
- struct usb_redir_device_connect_header),
- VMSTATE_STRUCT(interface_info, USBRedirDevice, 1,
- usbredir_interface_info_vmstate,
- struct usb_redir_interface_info_header),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property usbredir_properties[] = {
- DEFINE_PROP_CHR("chardev", USBRedirDevice, cs),
- DEFINE_PROP_UINT8("debug", USBRedirDevice, debug, usbredirparser_warning),
- DEFINE_PROP_STRING("filter", USBRedirDevice, filter_str),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void usbredir_class_initfn(ObjectClass *klass, void *data)
-{
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- uc->realize = usbredir_realize;
- uc->product_desc = "USB Redirection Device";
- uc->handle_destroy = usbredir_handle_destroy;
- uc->cancel_packet = usbredir_cancel_packet;
- uc->handle_reset = usbredir_handle_reset;
- uc->handle_data = usbredir_handle_data;
- uc->handle_control = usbredir_handle_control;
- uc->flush_ep_queue = usbredir_flush_ep_queue;
- uc->ep_stopped = usbredir_ep_stopped;
- uc->alloc_streams = usbredir_alloc_streams;
- uc->free_streams = usbredir_free_streams;
- dc->vmsd = &usbredir_vmstate;
- dc->props = usbredir_properties;
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
-}
-
-static void usbredir_instance_init(Object *obj)
-{
- USBDevice *udev = USB_DEVICE(obj);
- USBRedirDevice *dev = USB_REDIRECT(udev);
-
- device_add_bootindex_property(obj, &dev->bootindex,
- "bootindex", NULL,
- &udev->qdev, NULL);
-}
-
-static const TypeInfo usbredir_dev_info = {
- .name = TYPE_USB_REDIR,
- .parent = TYPE_USB_DEVICE,
- .instance_size = sizeof(USBRedirDevice),
- .class_init = usbredir_class_initfn,
- .instance_init = usbredir_instance_init,
-};
-
-static void usbredir_register_types(void)
-{
- type_register_static(&usbredir_dev_info);
-}
-
-type_init(usbredir_register_types)
diff --git a/qemu/hw/usb/tusb6010.c b/qemu/hw/usb/tusb6010.c
deleted file mode 100644
index 8f593a6fd..000000000
--- a/qemu/hw/usb/tusb6010.c
+++ /dev/null
@@ -1,817 +0,0 @@
-/*
- * Texas Instruments TUSB6010 emulation.
- * Based on reverse-engineering of a linux driver.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "qemu/timer.h"
-#include "hw/usb.h"
-#include "hw/arm/omap.h"
-#include "hw/irq.h"
-#include "hw/devices.h"
-#include "hw/sysbus.h"
-
-#define TYPE_TUSB6010 "tusb6010"
-#define TUSB(obj) OBJECT_CHECK(TUSBState, (obj), TYPE_TUSB6010)
-
-typedef struct TUSBState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem[2];
- qemu_irq irq;
- MUSBState *musb;
- QEMUTimer *otg_timer;
- QEMUTimer *pwr_timer;
-
- int power;
- uint32_t scratch;
- uint16_t test_reset;
- uint32_t prcm_config;
- uint32_t prcm_mngmt;
- uint16_t otg_status;
- uint32_t dev_config;
- int host_mode;
- uint32_t intr;
- uint32_t intr_ok;
- uint32_t mask;
- uint32_t usbip_intr;
- uint32_t usbip_mask;
- uint32_t gpio_intr;
- uint32_t gpio_mask;
- uint32_t gpio_config;
- uint32_t dma_intr;
- uint32_t dma_mask;
- uint32_t dma_map;
- uint32_t dma_config;
- uint32_t ep0_config;
- uint32_t rx_config[15];
- uint32_t tx_config[15];
- uint32_t wkup_mask;
- uint32_t pullup[2];
- uint32_t control_config;
- uint32_t otg_timer_val;
-} TUSBState;
-
-#define TUSB_DEVCLOCK 60000000 /* 60 MHz */
-
-#define TUSB_VLYNQ_CTRL 0x004
-
-/* Mentor Graphics OTG core registers. */
-#define TUSB_BASE_OFFSET 0x400
-
-/* FIFO registers, 32-bit. */
-#define TUSB_FIFO_BASE 0x600
-
-/* Device System & Control registers, 32-bit. */
-#define TUSB_SYS_REG_BASE 0x800
-
-#define TUSB_DEV_CONF (TUSB_SYS_REG_BASE + 0x000)
-#define TUSB_DEV_CONF_USB_HOST_MODE (1 << 16)
-#define TUSB_DEV_CONF_PROD_TEST_MODE (1 << 15)
-#define TUSB_DEV_CONF_SOFT_ID (1 << 1)
-#define TUSB_DEV_CONF_ID_SEL (1 << 0)
-
-#define TUSB_PHY_OTG_CTRL_ENABLE (TUSB_SYS_REG_BASE + 0x004)
-#define TUSB_PHY_OTG_CTRL (TUSB_SYS_REG_BASE + 0x008)
-#define TUSB_PHY_OTG_CTRL_WRPROTECT (0xa5 << 24)
-#define TUSB_PHY_OTG_CTRL_O_ID_PULLUP (1 << 23)
-#define TUSB_PHY_OTG_CTRL_O_VBUS_DET_EN (1 << 19)
-#define TUSB_PHY_OTG_CTRL_O_SESS_END_EN (1 << 18)
-#define TUSB_PHY_OTG_CTRL_TESTM2 (1 << 17)
-#define TUSB_PHY_OTG_CTRL_TESTM1 (1 << 16)
-#define TUSB_PHY_OTG_CTRL_TESTM0 (1 << 15)
-#define TUSB_PHY_OTG_CTRL_TX_DATA2 (1 << 14)
-#define TUSB_PHY_OTG_CTRL_TX_GZ2 (1 << 13)
-#define TUSB_PHY_OTG_CTRL_TX_ENABLE2 (1 << 12)
-#define TUSB_PHY_OTG_CTRL_DM_PULLDOWN (1 << 11)
-#define TUSB_PHY_OTG_CTRL_DP_PULLDOWN (1 << 10)
-#define TUSB_PHY_OTG_CTRL_OSC_EN (1 << 9)
-#define TUSB_PHY_OTG_CTRL_PHYREF_CLK(v) (((v) & 3) << 7)
-#define TUSB_PHY_OTG_CTRL_PD (1 << 6)
-#define TUSB_PHY_OTG_CTRL_PLL_ON (1 << 5)
-#define TUSB_PHY_OTG_CTRL_EXT_RPU (1 << 4)
-#define TUSB_PHY_OTG_CTRL_PWR_GOOD (1 << 3)
-#define TUSB_PHY_OTG_CTRL_RESET (1 << 2)
-#define TUSB_PHY_OTG_CTRL_SUSPENDM (1 << 1)
-#define TUSB_PHY_OTG_CTRL_CLK_MODE (1 << 0)
-
-/* OTG status register */
-#define TUSB_DEV_OTG_STAT (TUSB_SYS_REG_BASE + 0x00c)
-#define TUSB_DEV_OTG_STAT_PWR_CLK_GOOD (1 << 8)
-#define TUSB_DEV_OTG_STAT_SESS_END (1 << 7)
-#define TUSB_DEV_OTG_STAT_SESS_VALID (1 << 6)
-#define TUSB_DEV_OTG_STAT_VBUS_VALID (1 << 5)
-#define TUSB_DEV_OTG_STAT_VBUS_SENSE (1 << 4)
-#define TUSB_DEV_OTG_STAT_ID_STATUS (1 << 3)
-#define TUSB_DEV_OTG_STAT_HOST_DISCON (1 << 2)
-#define TUSB_DEV_OTG_STAT_LINE_STATE (3 << 0)
-#define TUSB_DEV_OTG_STAT_DP_ENABLE (1 << 1)
-#define TUSB_DEV_OTG_STAT_DM_ENABLE (1 << 0)
-
-#define TUSB_DEV_OTG_TIMER (TUSB_SYS_REG_BASE + 0x010)
-#define TUSB_DEV_OTG_TIMER_ENABLE (1 << 31)
-#define TUSB_DEV_OTG_TIMER_VAL(v) ((v) & 0x07ffffff)
-#define TUSB_PRCM_REV (TUSB_SYS_REG_BASE + 0x014)
-
-/* PRCM configuration register */
-#define TUSB_PRCM_CONF (TUSB_SYS_REG_BASE + 0x018)
-#define TUSB_PRCM_CONF_SFW_CPEN (1 << 24)
-#define TUSB_PRCM_CONF_SYS_CLKSEL(v) (((v) & 3) << 16)
-
-/* PRCM management register */
-#define TUSB_PRCM_MNGMT (TUSB_SYS_REG_BASE + 0x01c)
-#define TUSB_PRCM_MNGMT_SRP_FIX_TMR(v) (((v) & 0xf) << 25)
-#define TUSB_PRCM_MNGMT_SRP_FIX_EN (1 << 24)
-#define TUSB_PRCM_MNGMT_VBUS_VAL_TMR(v) (((v) & 0xf) << 20)
-#define TUSB_PRCM_MNGMT_VBUS_VAL_FLT_EN (1 << 19)
-#define TUSB_PRCM_MNGMT_DFT_CLK_DIS (1 << 18)
-#define TUSB_PRCM_MNGMT_VLYNQ_CLK_DIS (1 << 17)
-#define TUSB_PRCM_MNGMT_OTG_SESS_END_EN (1 << 10)
-#define TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN (1 << 9)
-#define TUSB_PRCM_MNGMT_OTG_ID_PULLUP (1 << 8)
-#define TUSB_PRCM_MNGMT_15_SW_EN (1 << 4)
-#define TUSB_PRCM_MNGMT_33_SW_EN (1 << 3)
-#define TUSB_PRCM_MNGMT_5V_CPEN (1 << 2)
-#define TUSB_PRCM_MNGMT_PM_IDLE (1 << 1)
-#define TUSB_PRCM_MNGMT_DEV_IDLE (1 << 0)
-
-/* Wake-up source clear and mask registers */
-#define TUSB_PRCM_WAKEUP_SOURCE (TUSB_SYS_REG_BASE + 0x020)
-#define TUSB_PRCM_WAKEUP_CLEAR (TUSB_SYS_REG_BASE + 0x028)
-#define TUSB_PRCM_WAKEUP_MASK (TUSB_SYS_REG_BASE + 0x02c)
-#define TUSB_PRCM_WAKEUP_RESERVED_BITS (0xffffe << 13)
-#define TUSB_PRCM_WGPIO_7 (1 << 12)
-#define TUSB_PRCM_WGPIO_6 (1 << 11)
-#define TUSB_PRCM_WGPIO_5 (1 << 10)
-#define TUSB_PRCM_WGPIO_4 (1 << 9)
-#define TUSB_PRCM_WGPIO_3 (1 << 8)
-#define TUSB_PRCM_WGPIO_2 (1 << 7)
-#define TUSB_PRCM_WGPIO_1 (1 << 6)
-#define TUSB_PRCM_WGPIO_0 (1 << 5)
-#define TUSB_PRCM_WHOSTDISCON (1 << 4) /* Host disconnect */
-#define TUSB_PRCM_WBUS (1 << 3) /* USB bus resume */
-#define TUSB_PRCM_WNORCS (1 << 2) /* NOR chip select */
-#define TUSB_PRCM_WVBUS (1 << 1) /* OTG PHY VBUS */
-#define TUSB_PRCM_WID (1 << 0) /* OTG PHY ID detect */
-
-#define TUSB_PULLUP_1_CTRL (TUSB_SYS_REG_BASE + 0x030)
-#define TUSB_PULLUP_2_CTRL (TUSB_SYS_REG_BASE + 0x034)
-#define TUSB_INT_CTRL_REV (TUSB_SYS_REG_BASE + 0x038)
-#define TUSB_INT_CTRL_CONF (TUSB_SYS_REG_BASE + 0x03c)
-#define TUSB_USBIP_INT_SRC (TUSB_SYS_REG_BASE + 0x040)
-#define TUSB_USBIP_INT_SET (TUSB_SYS_REG_BASE + 0x044)
-#define TUSB_USBIP_INT_CLEAR (TUSB_SYS_REG_BASE + 0x048)
-#define TUSB_USBIP_INT_MASK (TUSB_SYS_REG_BASE + 0x04c)
-#define TUSB_DMA_INT_SRC (TUSB_SYS_REG_BASE + 0x050)
-#define TUSB_DMA_INT_SET (TUSB_SYS_REG_BASE + 0x054)
-#define TUSB_DMA_INT_CLEAR (TUSB_SYS_REG_BASE + 0x058)
-#define TUSB_DMA_INT_MASK (TUSB_SYS_REG_BASE + 0x05c)
-#define TUSB_GPIO_INT_SRC (TUSB_SYS_REG_BASE + 0x060)
-#define TUSB_GPIO_INT_SET (TUSB_SYS_REG_BASE + 0x064)
-#define TUSB_GPIO_INT_CLEAR (TUSB_SYS_REG_BASE + 0x068)
-#define TUSB_GPIO_INT_MASK (TUSB_SYS_REG_BASE + 0x06c)
-
-/* NOR flash interrupt source registers */
-#define TUSB_INT_SRC (TUSB_SYS_REG_BASE + 0x070)
-#define TUSB_INT_SRC_SET (TUSB_SYS_REG_BASE + 0x074)
-#define TUSB_INT_SRC_CLEAR (TUSB_SYS_REG_BASE + 0x078)
-#define TUSB_INT_MASK (TUSB_SYS_REG_BASE + 0x07c)
-#define TUSB_INT_SRC_TXRX_DMA_DONE (1 << 24)
-#define TUSB_INT_SRC_USB_IP_CORE (1 << 17)
-#define TUSB_INT_SRC_OTG_TIMEOUT (1 << 16)
-#define TUSB_INT_SRC_VBUS_SENSE_CHNG (1 << 15)
-#define TUSB_INT_SRC_ID_STATUS_CHNG (1 << 14)
-#define TUSB_INT_SRC_DEV_WAKEUP (1 << 13)
-#define TUSB_INT_SRC_DEV_READY (1 << 12)
-#define TUSB_INT_SRC_USB_IP_TX (1 << 9)
-#define TUSB_INT_SRC_USB_IP_RX (1 << 8)
-#define TUSB_INT_SRC_USB_IP_VBUS_ERR (1 << 7)
-#define TUSB_INT_SRC_USB_IP_VBUS_REQ (1 << 6)
-#define TUSB_INT_SRC_USB_IP_DISCON (1 << 5)
-#define TUSB_INT_SRC_USB_IP_CONN (1 << 4)
-#define TUSB_INT_SRC_USB_IP_SOF (1 << 3)
-#define TUSB_INT_SRC_USB_IP_RST_BABBLE (1 << 2)
-#define TUSB_INT_SRC_USB_IP_RESUME (1 << 1)
-#define TUSB_INT_SRC_USB_IP_SUSPEND (1 << 0)
-
-#define TUSB_GPIO_REV (TUSB_SYS_REG_BASE + 0x080)
-#define TUSB_GPIO_CONF (TUSB_SYS_REG_BASE + 0x084)
-#define TUSB_DMA_CTRL_REV (TUSB_SYS_REG_BASE + 0x100)
-#define TUSB_DMA_REQ_CONF (TUSB_SYS_REG_BASE + 0x104)
-#define TUSB_EP0_CONF (TUSB_SYS_REG_BASE + 0x108)
-#define TUSB_EP_IN_SIZE (TUSB_SYS_REG_BASE + 0x10c)
-#define TUSB_DMA_EP_MAP (TUSB_SYS_REG_BASE + 0x148)
-#define TUSB_EP_OUT_SIZE (TUSB_SYS_REG_BASE + 0x14c)
-#define TUSB_EP_MAX_PACKET_SIZE_OFFSET (TUSB_SYS_REG_BASE + 0x188)
-#define TUSB_SCRATCH_PAD (TUSB_SYS_REG_BASE + 0x1c4)
-#define TUSB_WAIT_COUNT (TUSB_SYS_REG_BASE + 0x1c8)
-#define TUSB_PROD_TEST_RESET (TUSB_SYS_REG_BASE + 0x1d8)
-
-#define TUSB_DIDR1_LO (TUSB_SYS_REG_BASE + 0x1f8)
-#define TUSB_DIDR1_HI (TUSB_SYS_REG_BASE + 0x1fc)
-
-/* Device System & Control register bitfields */
-#define TUSB_INT_CTRL_CONF_INT_RLCYC(v) (((v) & 0x7) << 18)
-#define TUSB_INT_CTRL_CONF_INT_POLARITY (1 << 17)
-#define TUSB_INT_CTRL_CONF_INT_MODE (1 << 16)
-#define TUSB_GPIO_CONF_DMAREQ(v) (((v) & 0x3f) << 24)
-#define TUSB_DMA_REQ_CONF_BURST_SIZE(v) (((v) & 3) << 26)
-#define TUSB_DMA_REQ_CONF_DMA_RQ_EN(v) (((v) & 0x3f) << 20)
-#define TUSB_DMA_REQ_CONF_DMA_RQ_ASR(v) (((v) & 0xf) << 16)
-#define TUSB_EP0_CONFIG_SW_EN (1 << 8)
-#define TUSB_EP0_CONFIG_DIR_TX (1 << 7)
-#define TUSB_EP0_CONFIG_XFR_SIZE(v) ((v) & 0x7f)
-#define TUSB_EP_CONFIG_SW_EN (1 << 31)
-#define TUSB_EP_CONFIG_XFR_SIZE(v) ((v) & 0x7fffffff)
-#define TUSB_PROD_TEST_RESET_VAL 0xa596
-
-static void tusb_intr_update(TUSBState *s)
-{
- if (s->control_config & TUSB_INT_CTRL_CONF_INT_POLARITY)
- qemu_set_irq(s->irq, s->intr & ~s->mask & s->intr_ok);
- else
- qemu_set_irq(s->irq, (!(s->intr & ~s->mask)) & s->intr_ok);
-}
-
-static void tusb_usbip_intr_update(TUSBState *s)
-{
- /* TX interrupt in the MUSB */
- if (s->usbip_intr & 0x0000ffff & ~s->usbip_mask)
- s->intr |= TUSB_INT_SRC_USB_IP_TX;
- else
- s->intr &= ~TUSB_INT_SRC_USB_IP_TX;
-
- /* RX interrupt in the MUSB */
- if (s->usbip_intr & 0xffff0000 & ~s->usbip_mask)
- s->intr |= TUSB_INT_SRC_USB_IP_RX;
- else
- s->intr &= ~TUSB_INT_SRC_USB_IP_RX;
-
- /* XXX: What about TUSB_INT_SRC_USB_IP_CORE? */
-
- tusb_intr_update(s);
-}
-
-static void tusb_dma_intr_update(TUSBState *s)
-{
- if (s->dma_intr & ~s->dma_mask)
- s->intr |= TUSB_INT_SRC_TXRX_DMA_DONE;
- else
- s->intr &= ~TUSB_INT_SRC_TXRX_DMA_DONE;
-
- tusb_intr_update(s);
-}
-
-static void tusb_gpio_intr_update(TUSBState *s)
-{
- /* TODO: How is this signalled? */
-}
-
-static uint32_t tusb_async_readb(void *opaque, hwaddr addr)
-{
- TUSBState *s = (TUSBState *) opaque;
-
- switch (addr & 0xfff) {
- case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
- return musb_read[0](s->musb, addr & 0x1ff);
-
- case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
- return musb_read[0](s->musb, 0x20 + ((addr >> 3) & 0x3c));
- }
-
- printf("%s: unknown register at %03x\n",
- __FUNCTION__, (int) (addr & 0xfff));
- return 0;
-}
-
-static uint32_t tusb_async_readh(void *opaque, hwaddr addr)
-{
- TUSBState *s = (TUSBState *) opaque;
-
- switch (addr & 0xfff) {
- case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
- return musb_read[1](s->musb, addr & 0x1ff);
-
- case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
- return musb_read[1](s->musb, 0x20 + ((addr >> 3) & 0x3c));
- }
-
- printf("%s: unknown register at %03x\n",
- __FUNCTION__, (int) (addr & 0xfff));
- return 0;
-}
-
-static uint32_t tusb_async_readw(void *opaque, hwaddr addr)
-{
- TUSBState *s = (TUSBState *) opaque;
- int offset = addr & 0xfff;
- int epnum;
- uint32_t ret;
-
- switch (offset) {
- case TUSB_DEV_CONF:
- return s->dev_config;
-
- case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
- return musb_read[2](s->musb, offset & 0x1ff);
-
- case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
- return musb_read[2](s->musb, 0x20 + ((addr >> 3) & 0x3c));
-
- case TUSB_PHY_OTG_CTRL_ENABLE:
- case TUSB_PHY_OTG_CTRL:
- return 0x00; /* TODO */
-
- case TUSB_DEV_OTG_STAT:
- ret = s->otg_status;
-#if 0
- if (!(s->prcm_mngmt & TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN))
- ret &= ~TUSB_DEV_OTG_STAT_VBUS_VALID;
-#endif
- return ret;
- case TUSB_DEV_OTG_TIMER:
- return s->otg_timer_val;
-
- case TUSB_PRCM_REV:
- return 0x20;
- case TUSB_PRCM_CONF:
- return s->prcm_config;
- case TUSB_PRCM_MNGMT:
- return s->prcm_mngmt;
- case TUSB_PRCM_WAKEUP_SOURCE:
- case TUSB_PRCM_WAKEUP_CLEAR: /* TODO: What does this one return? */
- return 0x00000000;
- case TUSB_PRCM_WAKEUP_MASK:
- return s->wkup_mask;
-
- case TUSB_PULLUP_1_CTRL:
- return s->pullup[0];
- case TUSB_PULLUP_2_CTRL:
- return s->pullup[1];
-
- case TUSB_INT_CTRL_REV:
- return 0x20;
- case TUSB_INT_CTRL_CONF:
- return s->control_config;
-
- case TUSB_USBIP_INT_SRC:
- case TUSB_USBIP_INT_SET: /* TODO: What do these two return? */
- case TUSB_USBIP_INT_CLEAR:
- return s->usbip_intr;
- case TUSB_USBIP_INT_MASK:
- return s->usbip_mask;
-
- case TUSB_DMA_INT_SRC:
- case TUSB_DMA_INT_SET: /* TODO: What do these two return? */
- case TUSB_DMA_INT_CLEAR:
- return s->dma_intr;
- case TUSB_DMA_INT_MASK:
- return s->dma_mask;
-
- case TUSB_GPIO_INT_SRC: /* TODO: What do these two return? */
- case TUSB_GPIO_INT_SET:
- case TUSB_GPIO_INT_CLEAR:
- return s->gpio_intr;
- case TUSB_GPIO_INT_MASK:
- return s->gpio_mask;
-
- case TUSB_INT_SRC:
- case TUSB_INT_SRC_SET: /* TODO: What do these two return? */
- case TUSB_INT_SRC_CLEAR:
- return s->intr;
- case TUSB_INT_MASK:
- return s->mask;
-
- case TUSB_GPIO_REV:
- return 0x30;
- case TUSB_GPIO_CONF:
- return s->gpio_config;
-
- case TUSB_DMA_CTRL_REV:
- return 0x30;
- case TUSB_DMA_REQ_CONF:
- return s->dma_config;
- case TUSB_EP0_CONF:
- return s->ep0_config;
- case TUSB_EP_IN_SIZE ... (TUSB_EP_IN_SIZE + 0x3b):
- epnum = (offset - TUSB_EP_IN_SIZE) >> 2;
- return s->tx_config[epnum];
- case TUSB_DMA_EP_MAP:
- return s->dma_map;
- case TUSB_EP_OUT_SIZE ... (TUSB_EP_OUT_SIZE + 0x3b):
- epnum = (offset - TUSB_EP_OUT_SIZE) >> 2;
- return s->rx_config[epnum];
- case TUSB_EP_MAX_PACKET_SIZE_OFFSET ...
- (TUSB_EP_MAX_PACKET_SIZE_OFFSET + 0x3b):
- return 0x00000000; /* TODO */
- case TUSB_WAIT_COUNT:
- return 0x00; /* TODO */
-
- case TUSB_SCRATCH_PAD:
- return s->scratch;
-
- case TUSB_PROD_TEST_RESET:
- return s->test_reset;
-
- /* DIE IDs */
- case TUSB_DIDR1_LO:
- return 0xa9453c59;
- case TUSB_DIDR1_HI:
- return 0x54059adf;
- }
-
- printf("%s: unknown register at %03x\n", __FUNCTION__, offset);
- return 0;
-}
-
-static void tusb_async_writeb(void *opaque, hwaddr addr,
- uint32_t value)
-{
- TUSBState *s = (TUSBState *) opaque;
-
- switch (addr & 0xfff) {
- case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
- musb_write[0](s->musb, addr & 0x1ff, value);
- break;
-
- case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
- musb_write[0](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
- break;
-
- default:
- printf("%s: unknown register at %03x\n",
- __FUNCTION__, (int) (addr & 0xfff));
- return;
- }
-}
-
-static void tusb_async_writeh(void *opaque, hwaddr addr,
- uint32_t value)
-{
- TUSBState *s = (TUSBState *) opaque;
-
- switch (addr & 0xfff) {
- case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
- musb_write[1](s->musb, addr & 0x1ff, value);
- break;
-
- case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
- musb_write[1](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
- break;
-
- default:
- printf("%s: unknown register at %03x\n",
- __FUNCTION__, (int) (addr & 0xfff));
- return;
- }
-}
-
-static void tusb_async_writew(void *opaque, hwaddr addr,
- uint32_t value)
-{
- TUSBState *s = (TUSBState *) opaque;
- int offset = addr & 0xfff;
- int epnum;
-
- switch (offset) {
- case TUSB_VLYNQ_CTRL:
- break;
-
- case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
- musb_write[2](s->musb, offset & 0x1ff, value);
- break;
-
- case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
- musb_write[2](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
- break;
-
- case TUSB_DEV_CONF:
- s->dev_config = value;
- s->host_mode = (value & TUSB_DEV_CONF_USB_HOST_MODE);
- if (value & TUSB_DEV_CONF_PROD_TEST_MODE)
- hw_error("%s: Product Test mode not allowed\n", __FUNCTION__);
- break;
-
- case TUSB_PHY_OTG_CTRL_ENABLE:
- case TUSB_PHY_OTG_CTRL:
- return; /* TODO */
- case TUSB_DEV_OTG_TIMER:
- s->otg_timer_val = value;
- if (value & TUSB_DEV_OTG_TIMER_ENABLE)
- timer_mod(s->otg_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- muldiv64(TUSB_DEV_OTG_TIMER_VAL(value),
- NANOSECONDS_PER_SECOND, TUSB_DEVCLOCK));
- else
- timer_del(s->otg_timer);
- break;
-
- case TUSB_PRCM_CONF:
- s->prcm_config = value;
- break;
- case TUSB_PRCM_MNGMT:
- s->prcm_mngmt = value;
- break;
- case TUSB_PRCM_WAKEUP_CLEAR:
- break;
- case TUSB_PRCM_WAKEUP_MASK:
- s->wkup_mask = value;
- break;
-
- case TUSB_PULLUP_1_CTRL:
- s->pullup[0] = value;
- break;
- case TUSB_PULLUP_2_CTRL:
- s->pullup[1] = value;
- break;
- case TUSB_INT_CTRL_CONF:
- s->control_config = value;
- tusb_intr_update(s);
- break;
-
- case TUSB_USBIP_INT_SET:
- s->usbip_intr |= value;
- tusb_usbip_intr_update(s);
- break;
- case TUSB_USBIP_INT_CLEAR:
- s->usbip_intr &= ~value;
- tusb_usbip_intr_update(s);
- musb_core_intr_clear(s->musb, ~value);
- break;
- case TUSB_USBIP_INT_MASK:
- s->usbip_mask = value;
- tusb_usbip_intr_update(s);
- break;
-
- case TUSB_DMA_INT_SET:
- s->dma_intr |= value;
- tusb_dma_intr_update(s);
- break;
- case TUSB_DMA_INT_CLEAR:
- s->dma_intr &= ~value;
- tusb_dma_intr_update(s);
- break;
- case TUSB_DMA_INT_MASK:
- s->dma_mask = value;
- tusb_dma_intr_update(s);
- break;
-
- case TUSB_GPIO_INT_SET:
- s->gpio_intr |= value;
- tusb_gpio_intr_update(s);
- break;
- case TUSB_GPIO_INT_CLEAR:
- s->gpio_intr &= ~value;
- tusb_gpio_intr_update(s);
- break;
- case TUSB_GPIO_INT_MASK:
- s->gpio_mask = value;
- tusb_gpio_intr_update(s);
- break;
-
- case TUSB_INT_SRC_SET:
- s->intr |= value;
- tusb_intr_update(s);
- break;
- case TUSB_INT_SRC_CLEAR:
- s->intr &= ~value;
- tusb_intr_update(s);
- break;
- case TUSB_INT_MASK:
- s->mask = value;
- tusb_intr_update(s);
- break;
-
- case TUSB_GPIO_CONF:
- s->gpio_config = value;
- break;
- case TUSB_DMA_REQ_CONF:
- s->dma_config = value;
- break;
- case TUSB_EP0_CONF:
- s->ep0_config = value & 0x1ff;
- musb_set_size(s->musb, 0, TUSB_EP0_CONFIG_XFR_SIZE(value),
- value & TUSB_EP0_CONFIG_DIR_TX);
- break;
- case TUSB_EP_IN_SIZE ... (TUSB_EP_IN_SIZE + 0x3b):
- epnum = (offset - TUSB_EP_IN_SIZE) >> 2;
- s->tx_config[epnum] = value;
- musb_set_size(s->musb, epnum + 1, TUSB_EP_CONFIG_XFR_SIZE(value), 1);
- break;
- case TUSB_DMA_EP_MAP:
- s->dma_map = value;
- break;
- case TUSB_EP_OUT_SIZE ... (TUSB_EP_OUT_SIZE + 0x3b):
- epnum = (offset - TUSB_EP_OUT_SIZE) >> 2;
- s->rx_config[epnum] = value;
- musb_set_size(s->musb, epnum + 1, TUSB_EP_CONFIG_XFR_SIZE(value), 0);
- break;
- case TUSB_EP_MAX_PACKET_SIZE_OFFSET ...
- (TUSB_EP_MAX_PACKET_SIZE_OFFSET + 0x3b):
- return; /* TODO */
- case TUSB_WAIT_COUNT:
- return; /* TODO */
-
- case TUSB_SCRATCH_PAD:
- s->scratch = value;
- break;
-
- case TUSB_PROD_TEST_RESET:
- s->test_reset = value;
- break;
-
- default:
- printf("%s: unknown register at %03x\n", __FUNCTION__, offset);
- return;
- }
-}
-
-static const MemoryRegionOps tusb_async_ops = {
- .old_mmio = {
- .read = { tusb_async_readb, tusb_async_readh, tusb_async_readw, },
- .write = { tusb_async_writeb, tusb_async_writeh, tusb_async_writew, },
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void tusb_otg_tick(void *opaque)
-{
- TUSBState *s = (TUSBState *) opaque;
-
- s->otg_timer_val = 0;
- s->intr |= TUSB_INT_SRC_OTG_TIMEOUT;
- tusb_intr_update(s);
-}
-
-static void tusb_power_tick(void *opaque)
-{
- TUSBState *s = (TUSBState *) opaque;
-
- if (s->power) {
- s->intr_ok = ~0;
- tusb_intr_update(s);
- }
-}
-
-static void tusb_musb_core_intr(void *opaque, int source, int level)
-{
- TUSBState *s = (TUSBState *) opaque;
- uint16_t otg_status = s->otg_status;
-
- switch (source) {
- case musb_set_vbus:
- if (level)
- otg_status |= TUSB_DEV_OTG_STAT_VBUS_VALID;
- else
- otg_status &= ~TUSB_DEV_OTG_STAT_VBUS_VALID;
-
- /* XXX: only if TUSB_PHY_OTG_CTRL_OTG_VBUS_DET_EN set? */
- /* XXX: only if TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN set? */
- if (s->otg_status != otg_status) {
- s->otg_status = otg_status;
- s->intr |= TUSB_INT_SRC_VBUS_SENSE_CHNG;
- tusb_intr_update(s);
- }
- break;
-
- case musb_set_session:
- /* XXX: only if TUSB_PHY_OTG_CTRL_OTG_SESS_END_EN set? */
- /* XXX: only if TUSB_PRCM_MNGMT_OTG_SESS_END_EN set? */
- if (level) {
- s->otg_status |= TUSB_DEV_OTG_STAT_SESS_VALID;
- s->otg_status &= ~TUSB_DEV_OTG_STAT_SESS_END;
- } else {
- s->otg_status &= ~TUSB_DEV_OTG_STAT_SESS_VALID;
- s->otg_status |= TUSB_DEV_OTG_STAT_SESS_END;
- }
-
- /* XXX: some IRQ or anything? */
- break;
-
- case musb_irq_tx:
- case musb_irq_rx:
- s->usbip_intr = musb_core_intr_get(s->musb);
- /* Fall through. */
- default:
- if (level)
- s->intr |= 1 << source;
- else
- s->intr &= ~(1 << source);
- tusb_intr_update(s);
- break;
- }
-}
-
-static void tusb6010_power(TUSBState *s, int on)
-{
- if (!on) {
- s->power = 0;
- } else if (!s->power && on) {
- s->power = 1;
- /* Pull the interrupt down after TUSB6010 comes up. */
- s->intr_ok = 0;
- tusb_intr_update(s);
- timer_mod(s->pwr_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- NANOSECONDS_PER_SECOND / 2);
- }
-}
-
-static void tusb6010_irq(void *opaque, int source, int level)
-{
- if (source) {
- tusb_musb_core_intr(opaque, source - 1, level);
- } else {
- tusb6010_power(opaque, level);
- }
-}
-
-static void tusb6010_reset(DeviceState *dev)
-{
- TUSBState *s = TUSB(dev);
- int i;
-
- s->test_reset = TUSB_PROD_TEST_RESET_VAL;
- s->host_mode = 0;
- s->dev_config = 0;
- s->otg_status = 0; /* !TUSB_DEV_OTG_STAT_ID_STATUS means host mode */
- s->power = 0;
- s->mask = 0xffffffff;
- s->intr = 0x00000000;
- s->otg_timer_val = 0;
- s->scratch = 0;
- s->prcm_config = 0;
- s->prcm_mngmt = 0;
- s->intr_ok = 0;
- s->usbip_intr = 0;
- s->usbip_mask = 0;
- s->gpio_intr = 0;
- s->gpio_mask = 0;
- s->gpio_config = 0;
- s->dma_intr = 0;
- s->dma_mask = 0;
- s->dma_map = 0;
- s->dma_config = 0;
- s->ep0_config = 0;
- s->wkup_mask = 0;
- s->pullup[0] = s->pullup[1] = 0;
- s->control_config = 0;
- for (i = 0; i < 15; i++) {
- s->rx_config[i] = s->tx_config[i] = 0;
- }
- musb_reset(s->musb);
-}
-
-static int tusb6010_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- TUSBState *s = TUSB(dev);
-
- s->otg_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tusb_otg_tick, s);
- s->pwr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tusb_power_tick, s);
- memory_region_init_io(&s->iomem[1], OBJECT(s), &tusb_async_ops, s,
- "tusb-async", UINT32_MAX);
- sysbus_init_mmio(sbd, &s->iomem[0]);
- sysbus_init_mmio(sbd, &s->iomem[1]);
- sysbus_init_irq(sbd, &s->irq);
- qdev_init_gpio_in(dev, tusb6010_irq, musb_irq_max + 1);
- s->musb = musb_init(dev, 1);
- return 0;
-}
-
-static void tusb6010_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = tusb6010_init;
- dc->reset = tusb6010_reset;
-}
-
-static const TypeInfo tusb6010_info = {
- .name = TYPE_TUSB6010,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(TUSBState),
- .class_init = tusb6010_class_init,
-};
-
-static void tusb6010_register_types(void)
-{
- type_register_static(&tusb6010_info);
-}
-
-type_init(tusb6010_register_types)
diff --git a/qemu/hw/vfio/Makefile.objs b/qemu/hw/vfio/Makefile.objs
deleted file mode 100644
index ceddbb8f9..000000000
--- a/qemu/hw/vfio/Makefile.objs
+++ /dev/null
@@ -1,7 +0,0 @@
-ifeq ($(CONFIG_LINUX), y)
-obj-$(CONFIG_SOFTMMU) += common.o
-obj-$(CONFIG_PCI) += pci.o pci-quirks.o
-obj-$(CONFIG_SOFTMMU) += platform.o
-obj-$(CONFIG_SOFTMMU) += calxeda-xgmac.o
-obj-$(CONFIG_SOFTMMU) += amd-xgbe.o
-endif
diff --git a/qemu/hw/vfio/amd-xgbe.c b/qemu/hw/vfio/amd-xgbe.c
deleted file mode 100644
index 2c60310cf..000000000
--- a/qemu/hw/vfio/amd-xgbe.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * AMD XGBE VFIO device
- *
- * Copyright Linaro Limited, 2015
- *
- * Authors:
- * Eric Auger <eric.auger@linaro.org>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "hw/vfio/vfio-amd-xgbe.h"
-
-static void amd_xgbe_realize(DeviceState *dev, Error **errp)
-{
- VFIOPlatformDevice *vdev = VFIO_PLATFORM_DEVICE(dev);
- VFIOAmdXgbeDeviceClass *k = VFIO_AMD_XGBE_DEVICE_GET_CLASS(dev);
-
- vdev->compat = g_strdup("amd,xgbe-seattle-v1a");
-
- k->parent_realize(dev, errp);
-}
-
-static const VMStateDescription vfio_platform_amd_xgbe_vmstate = {
- .name = TYPE_VFIO_AMD_XGBE,
- .unmigratable = 1,
-};
-
-static void vfio_amd_xgbe_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VFIOAmdXgbeDeviceClass *vcxc =
- VFIO_AMD_XGBE_DEVICE_CLASS(klass);
- vcxc->parent_realize = dc->realize;
- dc->realize = amd_xgbe_realize;
- dc->desc = "VFIO AMD XGBE";
- dc->vmsd = &vfio_platform_amd_xgbe_vmstate;
-}
-
-static const TypeInfo vfio_amd_xgbe_dev_info = {
- .name = TYPE_VFIO_AMD_XGBE,
- .parent = TYPE_VFIO_PLATFORM,
- .instance_size = sizeof(VFIOAmdXgbeDevice),
- .class_init = vfio_amd_xgbe_class_init,
- .class_size = sizeof(VFIOAmdXgbeDeviceClass),
-};
-
-static void register_amd_xgbe_dev_type(void)
-{
- type_register_static(&vfio_amd_xgbe_dev_info);
-}
-
-type_init(register_amd_xgbe_dev_type)
diff --git a/qemu/hw/vfio/calxeda-xgmac.c b/qemu/hw/vfio/calxeda-xgmac.c
deleted file mode 100644
index bb15d588e..000000000
--- a/qemu/hw/vfio/calxeda-xgmac.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * calxeda xgmac VFIO device
- *
- * Copyright Linaro Limited, 2014
- *
- * Authors:
- * Eric Auger <eric.auger@linaro.org>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "hw/vfio/vfio-calxeda-xgmac.h"
-
-static void calxeda_xgmac_realize(DeviceState *dev, Error **errp)
-{
- VFIOPlatformDevice *vdev = VFIO_PLATFORM_DEVICE(dev);
- VFIOCalxedaXgmacDeviceClass *k = VFIO_CALXEDA_XGMAC_DEVICE_GET_CLASS(dev);
-
- vdev->compat = g_strdup("calxeda,hb-xgmac");
-
- k->parent_realize(dev, errp);
-}
-
-static const VMStateDescription vfio_platform_calxeda_xgmac_vmstate = {
- .name = TYPE_VFIO_CALXEDA_XGMAC,
- .unmigratable = 1,
-};
-
-static void vfio_calxeda_xgmac_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VFIOCalxedaXgmacDeviceClass *vcxc =
- VFIO_CALXEDA_XGMAC_DEVICE_CLASS(klass);
- vcxc->parent_realize = dc->realize;
- dc->realize = calxeda_xgmac_realize;
- dc->desc = "VFIO Calxeda XGMAC";
- dc->vmsd = &vfio_platform_calxeda_xgmac_vmstate;
-}
-
-static const TypeInfo vfio_calxeda_xgmac_dev_info = {
- .name = TYPE_VFIO_CALXEDA_XGMAC,
- .parent = TYPE_VFIO_PLATFORM,
- .instance_size = sizeof(VFIOCalxedaXgmacDevice),
- .class_init = vfio_calxeda_xgmac_class_init,
- .class_size = sizeof(VFIOCalxedaXgmacDeviceClass),
-};
-
-static void register_calxeda_xgmac_dev_type(void)
-{
- type_register_static(&vfio_calxeda_xgmac_dev_info);
-}
-
-type_init(register_calxeda_xgmac_dev_type)
diff --git a/qemu/hw/vfio/common.c b/qemu/hw/vfio/common.c
deleted file mode 100644
index f27db36fb..000000000
--- a/qemu/hw/vfio/common.c
+++ /dev/null
@@ -1,1192 +0,0 @@
-/*
- * generic functions used by VFIO devices
- *
- * Copyright Red Hat, Inc. 2012
- *
- * Authors:
- * Alex Williamson <alex.williamson@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- * Based on qemu-kvm device-assignment:
- * Adapted for KVM by Qumranet.
- * Copyright (c) 2007, Neocleus, Alex Novik (alex@neocleus.com)
- * Copyright (c) 2007, Neocleus, Guy Zana (guy@neocleus.com)
- * Copyright (C) 2008, Qumranet, Amit Shah (amit.shah@qumranet.com)
- * Copyright (C) 2008, Red Hat, Amit Shah (amit.shah@redhat.com)
- * Copyright (C) 2008, IBM, Muli Ben-Yehuda (muli@il.ibm.com)
- */
-
-#include "qemu/osdep.h"
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <linux/vfio.h>
-
-#include "hw/vfio/vfio-common.h"
-#include "hw/vfio/vfio.h"
-#include "exec/address-spaces.h"
-#include "exec/memory.h"
-#include "hw/hw.h"
-#include "qemu/error-report.h"
-#include "sysemu/kvm.h"
-#include "trace.h"
-
-struct vfio_group_head vfio_group_list =
- QLIST_HEAD_INITIALIZER(vfio_group_list);
-struct vfio_as_head vfio_address_spaces =
- QLIST_HEAD_INITIALIZER(vfio_address_spaces);
-
-#ifdef CONFIG_KVM
-/*
- * We have a single VFIO pseudo device per KVM VM. Once created it lives
- * for the life of the VM. Closing the file descriptor only drops our
- * reference to it and the device's reference to kvm. Therefore once
- * initialized, this file descriptor is only released on QEMU exit and
- * we'll re-use it should another vfio device be attached before then.
- */
-static int vfio_kvm_device_fd = -1;
-#endif
-
-/*
- * Common VFIO interrupt disable
- */
-void vfio_disable_irqindex(VFIODevice *vbasedev, int index)
-{
- struct vfio_irq_set irq_set = {
- .argsz = sizeof(irq_set),
- .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER,
- .index = index,
- .start = 0,
- .count = 0,
- };
-
- ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, &irq_set);
-}
-
-void vfio_unmask_single_irqindex(VFIODevice *vbasedev, int index)
-{
- struct vfio_irq_set irq_set = {
- .argsz = sizeof(irq_set),
- .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_UNMASK,
- .index = index,
- .start = 0,
- .count = 1,
- };
-
- ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, &irq_set);
-}
-
-void vfio_mask_single_irqindex(VFIODevice *vbasedev, int index)
-{
- struct vfio_irq_set irq_set = {
- .argsz = sizeof(irq_set),
- .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_MASK,
- .index = index,
- .start = 0,
- .count = 1,
- };
-
- ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, &irq_set);
-}
-
-/*
- * IO Port/MMIO - Beware of the endians, VFIO is always little endian
- */
-void vfio_region_write(void *opaque, hwaddr addr,
- uint64_t data, unsigned size)
-{
- VFIORegion *region = opaque;
- VFIODevice *vbasedev = region->vbasedev;
- union {
- uint8_t byte;
- uint16_t word;
- uint32_t dword;
- uint64_t qword;
- } buf;
-
- switch (size) {
- case 1:
- buf.byte = data;
- break;
- case 2:
- buf.word = cpu_to_le16(data);
- break;
- case 4:
- buf.dword = cpu_to_le32(data);
- break;
- default:
- hw_error("vfio: unsupported write size, %d bytes", size);
- break;
- }
-
- if (pwrite(vbasedev->fd, &buf, size, region->fd_offset + addr) != size) {
- error_report("%s(%s:region%d+0x%"HWADDR_PRIx", 0x%"PRIx64
- ",%d) failed: %m",
- __func__, vbasedev->name, region->nr,
- addr, data, size);
- }
-
- trace_vfio_region_write(vbasedev->name, region->nr, addr, data, size);
-
- /*
- * A read or write to a BAR always signals an INTx EOI. This will
- * do nothing if not pending (including not in INTx mode). We assume
- * that a BAR access is in response to an interrupt and that BAR
- * accesses will service the interrupt. Unfortunately, we don't know
- * which access will service the interrupt, so we're potentially
- * getting quite a few host interrupts per guest interrupt.
- */
- vbasedev->ops->vfio_eoi(vbasedev);
-}
-
-uint64_t vfio_region_read(void *opaque,
- hwaddr addr, unsigned size)
-{
- VFIORegion *region = opaque;
- VFIODevice *vbasedev = region->vbasedev;
- union {
- uint8_t byte;
- uint16_t word;
- uint32_t dword;
- uint64_t qword;
- } buf;
- uint64_t data = 0;
-
- if (pread(vbasedev->fd, &buf, size, region->fd_offset + addr) != size) {
- error_report("%s(%s:region%d+0x%"HWADDR_PRIx", %d) failed: %m",
- __func__, vbasedev->name, region->nr,
- addr, size);
- return (uint64_t)-1;
- }
- switch (size) {
- case 1:
- data = buf.byte;
- break;
- case 2:
- data = le16_to_cpu(buf.word);
- break;
- case 4:
- data = le32_to_cpu(buf.dword);
- break;
- default:
- hw_error("vfio: unsupported read size, %d bytes", size);
- break;
- }
-
- trace_vfio_region_read(vbasedev->name, region->nr, addr, size, data);
-
- /* Same as write above */
- vbasedev->ops->vfio_eoi(vbasedev);
-
- return data;
-}
-
-const MemoryRegionOps vfio_region_ops = {
- .read = vfio_region_read,
- .write = vfio_region_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-/*
- * DMA - Mapping and unmapping for the "type1" IOMMU interface used on x86
- */
-static int vfio_dma_unmap(VFIOContainer *container,
- hwaddr iova, ram_addr_t size)
-{
- struct vfio_iommu_type1_dma_unmap unmap = {
- .argsz = sizeof(unmap),
- .flags = 0,
- .iova = iova,
- .size = size,
- };
-
- if (ioctl(container->fd, VFIO_IOMMU_UNMAP_DMA, &unmap)) {
- error_report("VFIO_UNMAP_DMA: %d", -errno);
- return -errno;
- }
-
- return 0;
-}
-
-static int vfio_dma_map(VFIOContainer *container, hwaddr iova,
- ram_addr_t size, void *vaddr, bool readonly)
-{
- struct vfio_iommu_type1_dma_map map = {
- .argsz = sizeof(map),
- .flags = VFIO_DMA_MAP_FLAG_READ,
- .vaddr = (__u64)(uintptr_t)vaddr,
- .iova = iova,
- .size = size,
- };
-
- if (!readonly) {
- map.flags |= VFIO_DMA_MAP_FLAG_WRITE;
- }
-
- /*
- * Try the mapping, if it fails with EBUSY, unmap the region and try
- * again. This shouldn't be necessary, but we sometimes see it in
- * the VGA ROM space.
- */
- if (ioctl(container->fd, VFIO_IOMMU_MAP_DMA, &map) == 0 ||
- (errno == EBUSY && vfio_dma_unmap(container, iova, size) == 0 &&
- ioctl(container->fd, VFIO_IOMMU_MAP_DMA, &map) == 0)) {
- return 0;
- }
-
- error_report("VFIO_MAP_DMA: %d", -errno);
- return -errno;
-}
-
-static bool vfio_listener_skipped_section(MemoryRegionSection *section)
-{
- return (!memory_region_is_ram(section->mr) &&
- !memory_region_is_iommu(section->mr)) ||
- /*
- * Sizing an enabled 64-bit BAR can cause spurious mappings to
- * addresses in the upper part of the 64-bit address space. These
- * are never accessed by the CPU and beyond the address width of
- * some IOMMU hardware. TODO: VFIO should tell us the IOMMU width.
- */
- section->offset_within_address_space & (1ULL << 63);
-}
-
-static void vfio_iommu_map_notify(Notifier *n, void *data)
-{
- VFIOGuestIOMMU *giommu = container_of(n, VFIOGuestIOMMU, n);
- VFIOContainer *container = giommu->container;
- IOMMUTLBEntry *iotlb = data;
- MemoryRegion *mr;
- hwaddr xlat;
- hwaddr len = iotlb->addr_mask + 1;
- void *vaddr;
- int ret;
-
- trace_vfio_iommu_map_notify(iotlb->iova,
- iotlb->iova + iotlb->addr_mask);
-
- /*
- * The IOMMU TLB entry we have just covers translation through
- * this IOMMU to its immediate target. We need to translate
- * it the rest of the way through to memory.
- */
- rcu_read_lock();
- mr = address_space_translate(&address_space_memory,
- iotlb->translated_addr,
- &xlat, &len, iotlb->perm & IOMMU_WO);
- if (!memory_region_is_ram(mr)) {
- error_report("iommu map to non memory area %"HWADDR_PRIx"",
- xlat);
- goto out;
- }
- /*
- * Translation truncates length to the IOMMU page size,
- * check that it did not truncate too much.
- */
- if (len & iotlb->addr_mask) {
- error_report("iommu has granularity incompatible with target AS");
- goto out;
- }
-
- if ((iotlb->perm & IOMMU_RW) != IOMMU_NONE) {
- vaddr = memory_region_get_ram_ptr(mr) + xlat;
- ret = vfio_dma_map(container, iotlb->iova,
- iotlb->addr_mask + 1, vaddr,
- !(iotlb->perm & IOMMU_WO) || mr->readonly);
- if (ret) {
- error_report("vfio_dma_map(%p, 0x%"HWADDR_PRIx", "
- "0x%"HWADDR_PRIx", %p) = %d (%m)",
- container, iotlb->iova,
- iotlb->addr_mask + 1, vaddr, ret);
- }
- } else {
- ret = vfio_dma_unmap(container, iotlb->iova, iotlb->addr_mask + 1);
- if (ret) {
- error_report("vfio_dma_unmap(%p, 0x%"HWADDR_PRIx", "
- "0x%"HWADDR_PRIx") = %d (%m)",
- container, iotlb->iova,
- iotlb->addr_mask + 1, ret);
- }
- }
-out:
- rcu_read_unlock();
-}
-
-static hwaddr vfio_container_granularity(VFIOContainer *container)
-{
- return (hwaddr)1 << ctz64(container->iova_pgsizes);
-}
-
-static void vfio_listener_region_add(MemoryListener *listener,
- MemoryRegionSection *section)
-{
- VFIOContainer *container = container_of(listener, VFIOContainer, listener);
- hwaddr iova, end;
- Int128 llend, llsize;
- void *vaddr;
- int ret;
-
- if (vfio_listener_skipped_section(section)) {
- trace_vfio_listener_region_add_skip(
- section->offset_within_address_space,
- section->offset_within_address_space +
- int128_get64(int128_sub(section->size, int128_one())));
- return;
- }
-
- if (unlikely((section->offset_within_address_space & ~TARGET_PAGE_MASK) !=
- (section->offset_within_region & ~TARGET_PAGE_MASK))) {
- error_report("%s received unaligned region", __func__);
- return;
- }
-
- iova = TARGET_PAGE_ALIGN(section->offset_within_address_space);
- llend = int128_make64(section->offset_within_address_space);
- llend = int128_add(llend, section->size);
- llend = int128_and(llend, int128_exts64(TARGET_PAGE_MASK));
-
- if (int128_ge(int128_make64(iova), llend)) {
- return;
- }
- end = int128_get64(int128_sub(llend, int128_one()));
-
- if ((iova < container->min_iova) || (end > container->max_iova)) {
- error_report("vfio: IOMMU container %p can't map guest IOVA region"
- " 0x%"HWADDR_PRIx"..0x%"HWADDR_PRIx,
- container, iova, end);
- ret = -EFAULT;
- goto fail;
- }
-
- memory_region_ref(section->mr);
-
- if (memory_region_is_iommu(section->mr)) {
- VFIOGuestIOMMU *giommu;
-
- trace_vfio_listener_region_add_iommu(iova, end);
- /*
- * FIXME: We should do some checking to see if the
- * capabilities of the host VFIO IOMMU are adequate to model
- * the guest IOMMU
- *
- * FIXME: For VFIO iommu types which have KVM acceleration to
- * avoid bouncing all map/unmaps through qemu this way, this
- * would be the right place to wire that up (tell the KVM
- * device emulation the VFIO iommu handles to use).
- */
- giommu = g_malloc0(sizeof(*giommu));
- giommu->iommu = section->mr;
- giommu->container = container;
- giommu->n.notify = vfio_iommu_map_notify;
- QLIST_INSERT_HEAD(&container->giommu_list, giommu, giommu_next);
-
- memory_region_register_iommu_notifier(giommu->iommu, &giommu->n);
- memory_region_iommu_replay(giommu->iommu, &giommu->n,
- vfio_container_granularity(container),
- false);
-
- return;
- }
-
- /* Here we assume that memory_region_is_ram(section->mr)==true */
-
- vaddr = memory_region_get_ram_ptr(section->mr) +
- section->offset_within_region +
- (iova - section->offset_within_address_space);
-
- trace_vfio_listener_region_add_ram(iova, end, vaddr);
-
- llsize = int128_sub(llend, int128_make64(iova));
-
- ret = vfio_dma_map(container, iova, int128_get64(llsize),
- vaddr, section->readonly);
- if (ret) {
- error_report("vfio_dma_map(%p, 0x%"HWADDR_PRIx", "
- "0x%"HWADDR_PRIx", %p) = %d (%m)",
- container, iova, int128_get64(llsize), vaddr, ret);
- goto fail;
- }
-
- return;
-
-fail:
- /*
- * On the initfn path, store the first error in the container so we
- * can gracefully fail. Runtime, there's not much we can do other
- * than throw a hardware error.
- */
- if (!container->initialized) {
- if (!container->error) {
- container->error = ret;
- }
- } else {
- hw_error("vfio: DMA mapping failed, unable to continue");
- }
-}
-
-static void vfio_listener_region_del(MemoryListener *listener,
- MemoryRegionSection *section)
-{
- VFIOContainer *container = container_of(listener, VFIOContainer, listener);
- hwaddr iova, end;
- int ret;
-
- if (vfio_listener_skipped_section(section)) {
- trace_vfio_listener_region_del_skip(
- section->offset_within_address_space,
- section->offset_within_address_space +
- int128_get64(int128_sub(section->size, int128_one())));
- return;
- }
-
- if (unlikely((section->offset_within_address_space & ~TARGET_PAGE_MASK) !=
- (section->offset_within_region & ~TARGET_PAGE_MASK))) {
- error_report("%s received unaligned region", __func__);
- return;
- }
-
- if (memory_region_is_iommu(section->mr)) {
- VFIOGuestIOMMU *giommu;
-
- QLIST_FOREACH(giommu, &container->giommu_list, giommu_next) {
- if (giommu->iommu == section->mr) {
- memory_region_unregister_iommu_notifier(&giommu->n);
- QLIST_REMOVE(giommu, giommu_next);
- g_free(giommu);
- break;
- }
- }
-
- /*
- * FIXME: We assume the one big unmap below is adequate to
- * remove any individual page mappings in the IOMMU which
- * might have been copied into VFIO. This works for a page table
- * based IOMMU where a big unmap flattens a large range of IO-PTEs.
- * That may not be true for all IOMMU types.
- */
- }
-
- iova = TARGET_PAGE_ALIGN(section->offset_within_address_space);
- end = (section->offset_within_address_space + int128_get64(section->size)) &
- TARGET_PAGE_MASK;
-
- if (iova >= end) {
- return;
- }
-
- trace_vfio_listener_region_del(iova, end - 1);
-
- ret = vfio_dma_unmap(container, iova, end - iova);
- memory_region_unref(section->mr);
- if (ret) {
- error_report("vfio_dma_unmap(%p, 0x%"HWADDR_PRIx", "
- "0x%"HWADDR_PRIx") = %d (%m)",
- container, iova, end - iova, ret);
- }
-}
-
-static const MemoryListener vfio_memory_listener = {
- .region_add = vfio_listener_region_add,
- .region_del = vfio_listener_region_del,
-};
-
-static void vfio_listener_release(VFIOContainer *container)
-{
- memory_listener_unregister(&container->listener);
-}
-
-int vfio_region_setup(Object *obj, VFIODevice *vbasedev, VFIORegion *region,
- int index, const char *name)
-{
- struct vfio_region_info *info;
- int ret;
-
- ret = vfio_get_region_info(vbasedev, index, &info);
- if (ret) {
- return ret;
- }
-
- region->vbasedev = vbasedev;
- region->flags = info->flags;
- region->size = info->size;
- region->fd_offset = info->offset;
- region->nr = index;
-
- if (region->size) {
- region->mem = g_new0(MemoryRegion, 1);
- memory_region_init_io(region->mem, obj, &vfio_region_ops,
- region, name, region->size);
-
- if (!vbasedev->no_mmap &&
- region->flags & VFIO_REGION_INFO_FLAG_MMAP &&
- !(region->size & ~qemu_real_host_page_mask)) {
-
- region->nr_mmaps = 1;
- region->mmaps = g_new0(VFIOMmap, region->nr_mmaps);
-
- region->mmaps[0].offset = 0;
- region->mmaps[0].size = region->size;
- }
- }
-
- g_free(info);
-
- trace_vfio_region_setup(vbasedev->name, index, name,
- region->flags, region->fd_offset, region->size);
- return 0;
-}
-
-int vfio_region_mmap(VFIORegion *region)
-{
- int i, prot = 0;
- char *name;
-
- if (!region->mem) {
- return 0;
- }
-
- prot |= region->flags & VFIO_REGION_INFO_FLAG_READ ? PROT_READ : 0;
- prot |= region->flags & VFIO_REGION_INFO_FLAG_WRITE ? PROT_WRITE : 0;
-
- for (i = 0; i < region->nr_mmaps; i++) {
- region->mmaps[i].mmap = mmap(NULL, region->mmaps[i].size, prot,
- MAP_SHARED, region->vbasedev->fd,
- region->fd_offset +
- region->mmaps[i].offset);
- if (region->mmaps[i].mmap == MAP_FAILED) {
- int ret = -errno;
-
- trace_vfio_region_mmap_fault(memory_region_name(region->mem), i,
- region->fd_offset +
- region->mmaps[i].offset,
- region->fd_offset +
- region->mmaps[i].offset +
- region->mmaps[i].size - 1, ret);
-
- region->mmaps[i].mmap = NULL;
-
- for (i--; i >= 0; i--) {
- memory_region_del_subregion(region->mem, &region->mmaps[i].mem);
- munmap(region->mmaps[i].mmap, region->mmaps[i].size);
- object_unparent(OBJECT(&region->mmaps[i].mem));
- region->mmaps[i].mmap = NULL;
- }
-
- return ret;
- }
-
- name = g_strdup_printf("%s mmaps[%d]",
- memory_region_name(region->mem), i);
- memory_region_init_ram_ptr(&region->mmaps[i].mem,
- memory_region_owner(region->mem),
- name, region->mmaps[i].size,
- region->mmaps[i].mmap);
- g_free(name);
- memory_region_set_skip_dump(&region->mmaps[i].mem);
- memory_region_add_subregion(region->mem, region->mmaps[i].offset,
- &region->mmaps[i].mem);
-
- trace_vfio_region_mmap(memory_region_name(&region->mmaps[i].mem),
- region->mmaps[i].offset,
- region->mmaps[i].offset +
- region->mmaps[i].size - 1);
- }
-
- return 0;
-}
-
-void vfio_region_exit(VFIORegion *region)
-{
- int i;
-
- if (!region->mem) {
- return;
- }
-
- for (i = 0; i < region->nr_mmaps; i++) {
- if (region->mmaps[i].mmap) {
- memory_region_del_subregion(region->mem, &region->mmaps[i].mem);
- }
- }
-
- trace_vfio_region_exit(region->vbasedev->name, region->nr);
-}
-
-void vfio_region_finalize(VFIORegion *region)
-{
- int i;
-
- if (!region->mem) {
- return;
- }
-
- for (i = 0; i < region->nr_mmaps; i++) {
- if (region->mmaps[i].mmap) {
- munmap(region->mmaps[i].mmap, region->mmaps[i].size);
- object_unparent(OBJECT(&region->mmaps[i].mem));
- }
- }
-
- object_unparent(OBJECT(region->mem));
-
- g_free(region->mem);
- g_free(region->mmaps);
-
- trace_vfio_region_finalize(region->vbasedev->name, region->nr);
-}
-
-void vfio_region_mmaps_set_enabled(VFIORegion *region, bool enabled)
-{
- int i;
-
- if (!region->mem) {
- return;
- }
-
- for (i = 0; i < region->nr_mmaps; i++) {
- if (region->mmaps[i].mmap) {
- memory_region_set_enabled(&region->mmaps[i].mem, enabled);
- }
- }
-
- trace_vfio_region_mmaps_set_enabled(memory_region_name(region->mem),
- enabled);
-}
-
-void vfio_reset_handler(void *opaque)
-{
- VFIOGroup *group;
- VFIODevice *vbasedev;
-
- QLIST_FOREACH(group, &vfio_group_list, next) {
- QLIST_FOREACH(vbasedev, &group->device_list, next) {
- vbasedev->ops->vfio_compute_needs_reset(vbasedev);
- }
- }
-
- QLIST_FOREACH(group, &vfio_group_list, next) {
- QLIST_FOREACH(vbasedev, &group->device_list, next) {
- if (vbasedev->needs_reset) {
- vbasedev->ops->vfio_hot_reset_multi(vbasedev);
- }
- }
- }
-}
-
-static void vfio_kvm_device_add_group(VFIOGroup *group)
-{
-#ifdef CONFIG_KVM
- struct kvm_device_attr attr = {
- .group = KVM_DEV_VFIO_GROUP,
- .attr = KVM_DEV_VFIO_GROUP_ADD,
- .addr = (uint64_t)(unsigned long)&group->fd,
- };
-
- if (!kvm_enabled()) {
- return;
- }
-
- if (vfio_kvm_device_fd < 0) {
- struct kvm_create_device cd = {
- .type = KVM_DEV_TYPE_VFIO,
- };
-
- if (kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd)) {
- error_report("Failed to create KVM VFIO device: %m");
- return;
- }
-
- vfio_kvm_device_fd = cd.fd;
- }
-
- if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) {
- error_report("Failed to add group %d to KVM VFIO device: %m",
- group->groupid);
- }
-#endif
-}
-
-static void vfio_kvm_device_del_group(VFIOGroup *group)
-{
-#ifdef CONFIG_KVM
- struct kvm_device_attr attr = {
- .group = KVM_DEV_VFIO_GROUP,
- .attr = KVM_DEV_VFIO_GROUP_DEL,
- .addr = (uint64_t)(unsigned long)&group->fd,
- };
-
- if (vfio_kvm_device_fd < 0) {
- return;
- }
-
- if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) {
- error_report("Failed to remove group %d from KVM VFIO device: %m",
- group->groupid);
- }
-#endif
-}
-
-static VFIOAddressSpace *vfio_get_address_space(AddressSpace *as)
-{
- VFIOAddressSpace *space;
-
- QLIST_FOREACH(space, &vfio_address_spaces, list) {
- if (space->as == as) {
- return space;
- }
- }
-
- /* No suitable VFIOAddressSpace, create a new one */
- space = g_malloc0(sizeof(*space));
- space->as = as;
- QLIST_INIT(&space->containers);
-
- QLIST_INSERT_HEAD(&vfio_address_spaces, space, list);
-
- return space;
-}
-
-static void vfio_put_address_space(VFIOAddressSpace *space)
-{
- if (QLIST_EMPTY(&space->containers)) {
- QLIST_REMOVE(space, list);
- g_free(space);
- }
-}
-
-static int vfio_connect_container(VFIOGroup *group, AddressSpace *as)
-{
- VFIOContainer *container;
- int ret, fd;
- VFIOAddressSpace *space;
-
- space = vfio_get_address_space(as);
-
- QLIST_FOREACH(container, &space->containers, next) {
- if (!ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &container->fd)) {
- group->container = container;
- QLIST_INSERT_HEAD(&container->group_list, group, container_next);
- return 0;
- }
- }
-
- fd = qemu_open("/dev/vfio/vfio", O_RDWR);
- if (fd < 0) {
- error_report("vfio: failed to open /dev/vfio/vfio: %m");
- ret = -errno;
- goto put_space_exit;
- }
-
- ret = ioctl(fd, VFIO_GET_API_VERSION);
- if (ret != VFIO_API_VERSION) {
- error_report("vfio: supported vfio version: %d, "
- "reported version: %d", VFIO_API_VERSION, ret);
- ret = -EINVAL;
- goto close_fd_exit;
- }
-
- container = g_malloc0(sizeof(*container));
- container->space = space;
- container->fd = fd;
- if (ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_TYPE1_IOMMU) ||
- ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_TYPE1v2_IOMMU)) {
- bool v2 = !!ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_TYPE1v2_IOMMU);
- struct vfio_iommu_type1_info info;
-
- ret = ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &fd);
- if (ret) {
- error_report("vfio: failed to set group container: %m");
- ret = -errno;
- goto free_container_exit;
- }
-
- ret = ioctl(fd, VFIO_SET_IOMMU,
- v2 ? VFIO_TYPE1v2_IOMMU : VFIO_TYPE1_IOMMU);
- if (ret) {
- error_report("vfio: failed to set iommu for container: %m");
- ret = -errno;
- goto free_container_exit;
- }
-
- /*
- * FIXME: This assumes that a Type1 IOMMU can map any 64-bit
- * IOVA whatsoever. That's not actually true, but the current
- * kernel interface doesn't tell us what it can map, and the
- * existing Type1 IOMMUs generally support any IOVA we're
- * going to actually try in practice.
- */
- container->min_iova = 0;
- container->max_iova = (hwaddr)-1;
-
- /* Assume just 4K IOVA page size */
- container->iova_pgsizes = 0x1000;
- info.argsz = sizeof(info);
- ret = ioctl(fd, VFIO_IOMMU_GET_INFO, &info);
- /* Ignore errors */
- if ((ret == 0) && (info.flags & VFIO_IOMMU_INFO_PGSIZES)) {
- container->iova_pgsizes = info.iova_pgsizes;
- }
- } else if (ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_SPAPR_TCE_IOMMU)) {
- struct vfio_iommu_spapr_tce_info info;
-
- ret = ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &fd);
- if (ret) {
- error_report("vfio: failed to set group container: %m");
- ret = -errno;
- goto free_container_exit;
- }
- ret = ioctl(fd, VFIO_SET_IOMMU, VFIO_SPAPR_TCE_IOMMU);
- if (ret) {
- error_report("vfio: failed to set iommu for container: %m");
- ret = -errno;
- goto free_container_exit;
- }
-
- /*
- * The host kernel code implementing VFIO_IOMMU_DISABLE is called
- * when container fd is closed so we do not call it explicitly
- * in this file.
- */
- ret = ioctl(fd, VFIO_IOMMU_ENABLE);
- if (ret) {
- error_report("vfio: failed to enable container: %m");
- ret = -errno;
- goto free_container_exit;
- }
-
- /*
- * This only considers the host IOMMU's 32-bit window. At
- * some point we need to add support for the optional 64-bit
- * window and dynamic windows
- */
- info.argsz = sizeof(info);
- ret = ioctl(fd, VFIO_IOMMU_SPAPR_TCE_GET_INFO, &info);
- if (ret) {
- error_report("vfio: VFIO_IOMMU_SPAPR_TCE_GET_INFO failed: %m");
- ret = -errno;
- goto free_container_exit;
- }
- container->min_iova = info.dma32_window_start;
- container->max_iova = container->min_iova + info.dma32_window_size - 1;
-
- /* Assume just 4K IOVA pages for now */
- container->iova_pgsizes = 0x1000;
- } else {
- error_report("vfio: No available IOMMU models");
- ret = -EINVAL;
- goto free_container_exit;
- }
-
- container->listener = vfio_memory_listener;
-
- memory_listener_register(&container->listener, container->space->as);
-
- if (container->error) {
- ret = container->error;
- error_report("vfio: memory listener initialization failed for container");
- goto listener_release_exit;
- }
-
- container->initialized = true;
-
- QLIST_INIT(&container->group_list);
- QLIST_INSERT_HEAD(&space->containers, container, next);
-
- group->container = container;
- QLIST_INSERT_HEAD(&container->group_list, group, container_next);
-
- return 0;
-listener_release_exit:
- vfio_listener_release(container);
-
-free_container_exit:
- g_free(container);
-
-close_fd_exit:
- close(fd);
-
-put_space_exit:
- vfio_put_address_space(space);
-
- return ret;
-}
-
-static void vfio_disconnect_container(VFIOGroup *group)
-{
- VFIOContainer *container = group->container;
-
- if (ioctl(group->fd, VFIO_GROUP_UNSET_CONTAINER, &container->fd)) {
- error_report("vfio: error disconnecting group %d from container",
- group->groupid);
- }
-
- QLIST_REMOVE(group, container_next);
- group->container = NULL;
-
- if (QLIST_EMPTY(&container->group_list)) {
- VFIOAddressSpace *space = container->space;
- VFIOGuestIOMMU *giommu, *tmp;
-
- vfio_listener_release(container);
- QLIST_REMOVE(container, next);
-
- QLIST_FOREACH_SAFE(giommu, &container->giommu_list, giommu_next, tmp) {
- memory_region_unregister_iommu_notifier(&giommu->n);
- QLIST_REMOVE(giommu, giommu_next);
- g_free(giommu);
- }
-
- trace_vfio_disconnect_container(container->fd);
- close(container->fd);
- g_free(container);
-
- vfio_put_address_space(space);
- }
-}
-
-VFIOGroup *vfio_get_group(int groupid, AddressSpace *as)
-{
- VFIOGroup *group;
- char path[32];
- struct vfio_group_status status = { .argsz = sizeof(status) };
-
- QLIST_FOREACH(group, &vfio_group_list, next) {
- if (group->groupid == groupid) {
- /* Found it. Now is it already in the right context? */
- if (group->container->space->as == as) {
- return group;
- } else {
- error_report("vfio: group %d used in multiple address spaces",
- group->groupid);
- return NULL;
- }
- }
- }
-
- group = g_malloc0(sizeof(*group));
-
- snprintf(path, sizeof(path), "/dev/vfio/%d", groupid);
- group->fd = qemu_open(path, O_RDWR);
- if (group->fd < 0) {
- error_report("vfio: error opening %s: %m", path);
- goto free_group_exit;
- }
-
- if (ioctl(group->fd, VFIO_GROUP_GET_STATUS, &status)) {
- error_report("vfio: error getting group status: %m");
- goto close_fd_exit;
- }
-
- if (!(status.flags & VFIO_GROUP_FLAGS_VIABLE)) {
- error_report("vfio: error, group %d is not viable, please ensure "
- "all devices within the iommu_group are bound to their "
- "vfio bus driver.", groupid);
- goto close_fd_exit;
- }
-
- group->groupid = groupid;
- QLIST_INIT(&group->device_list);
-
- if (vfio_connect_container(group, as)) {
- error_report("vfio: failed to setup container for group %d", groupid);
- goto close_fd_exit;
- }
-
- if (QLIST_EMPTY(&vfio_group_list)) {
- qemu_register_reset(vfio_reset_handler, NULL);
- }
-
- QLIST_INSERT_HEAD(&vfio_group_list, group, next);
-
- vfio_kvm_device_add_group(group);
-
- return group;
-
-close_fd_exit:
- close(group->fd);
-
-free_group_exit:
- g_free(group);
-
- return NULL;
-}
-
-void vfio_put_group(VFIOGroup *group)
-{
- if (!group || !QLIST_EMPTY(&group->device_list)) {
- return;
- }
-
- vfio_kvm_device_del_group(group);
- vfio_disconnect_container(group);
- QLIST_REMOVE(group, next);
- trace_vfio_put_group(group->fd);
- close(group->fd);
- g_free(group);
-
- if (QLIST_EMPTY(&vfio_group_list)) {
- qemu_unregister_reset(vfio_reset_handler, NULL);
- }
-}
-
-int vfio_get_device(VFIOGroup *group, const char *name,
- VFIODevice *vbasedev)
-{
- struct vfio_device_info dev_info = { .argsz = sizeof(dev_info) };
- int ret, fd;
-
- fd = ioctl(group->fd, VFIO_GROUP_GET_DEVICE_FD, name);
- if (fd < 0) {
- error_report("vfio: error getting device %s from group %d: %m",
- name, group->groupid);
- error_printf("Verify all devices in group %d are bound to vfio-<bus> "
- "or pci-stub and not already in use\n", group->groupid);
- return fd;
- }
-
- ret = ioctl(fd, VFIO_DEVICE_GET_INFO, &dev_info);
- if (ret) {
- error_report("vfio: error getting device info: %m");
- close(fd);
- return ret;
- }
-
- vbasedev->fd = fd;
- vbasedev->group = group;
- QLIST_INSERT_HEAD(&group->device_list, vbasedev, next);
-
- vbasedev->num_irqs = dev_info.num_irqs;
- vbasedev->num_regions = dev_info.num_regions;
- vbasedev->flags = dev_info.flags;
-
- trace_vfio_get_device(name, dev_info.flags, dev_info.num_regions,
- dev_info.num_irqs);
-
- vbasedev->reset_works = !!(dev_info.flags & VFIO_DEVICE_FLAGS_RESET);
- return 0;
-}
-
-void vfio_put_base_device(VFIODevice *vbasedev)
-{
- if (!vbasedev->group) {
- return;
- }
- QLIST_REMOVE(vbasedev, next);
- vbasedev->group = NULL;
- trace_vfio_put_base_device(vbasedev->fd);
- close(vbasedev->fd);
-}
-
-int vfio_get_region_info(VFIODevice *vbasedev, int index,
- struct vfio_region_info **info)
-{
- size_t argsz = sizeof(struct vfio_region_info);
-
- *info = g_malloc0(argsz);
-
- (*info)->index = index;
- (*info)->argsz = argsz;
-
- if (ioctl(vbasedev->fd, VFIO_DEVICE_GET_REGION_INFO, *info)) {
- g_free(*info);
- return -errno;
- }
-
- return 0;
-}
-
-/*
- * Interfaces for IBM EEH (Enhanced Error Handling)
- */
-static bool vfio_eeh_container_ok(VFIOContainer *container)
-{
- /*
- * As of 2016-03-04 (linux-4.5) the host kernel EEH/VFIO
- * implementation is broken if there are multiple groups in a
- * container. The hardware works in units of Partitionable
- * Endpoints (== IOMMU groups) and the EEH operations naively
- * iterate across all groups in the container, without any logic
- * to make sure the groups have their state synchronized. For
- * certain operations (ENABLE) that might be ok, until an error
- * occurs, but for others (GET_STATE) it's clearly broken.
- */
-
- /*
- * XXX Once fixed kernels exist, test for them here
- */
-
- if (QLIST_EMPTY(&container->group_list)) {
- return false;
- }
-
- if (QLIST_NEXT(QLIST_FIRST(&container->group_list), container_next)) {
- return false;
- }
-
- return true;
-}
-
-static int vfio_eeh_container_op(VFIOContainer *container, uint32_t op)
-{
- struct vfio_eeh_pe_op pe_op = {
- .argsz = sizeof(pe_op),
- .op = op,
- };
- int ret;
-
- if (!vfio_eeh_container_ok(container)) {
- error_report("vfio/eeh: EEH_PE_OP 0x%x: "
- "kernel requires a container with exactly one group", op);
- return -EPERM;
- }
-
- ret = ioctl(container->fd, VFIO_EEH_PE_OP, &pe_op);
- if (ret < 0) {
- error_report("vfio/eeh: EEH_PE_OP 0x%x failed: %m", op);
- return -errno;
- }
-
- return 0;
-}
-
-static VFIOContainer *vfio_eeh_as_container(AddressSpace *as)
-{
- VFIOAddressSpace *space = vfio_get_address_space(as);
- VFIOContainer *container = NULL;
-
- if (QLIST_EMPTY(&space->containers)) {
- /* No containers to act on */
- goto out;
- }
-
- container = QLIST_FIRST(&space->containers);
-
- if (QLIST_NEXT(container, next)) {
- /* We don't yet have logic to synchronize EEH state across
- * multiple containers */
- container = NULL;
- goto out;
- }
-
-out:
- vfio_put_address_space(space);
- return container;
-}
-
-bool vfio_eeh_as_ok(AddressSpace *as)
-{
- VFIOContainer *container = vfio_eeh_as_container(as);
-
- return (container != NULL) && vfio_eeh_container_ok(container);
-}
-
-int vfio_eeh_as_op(AddressSpace *as, uint32_t op)
-{
- VFIOContainer *container = vfio_eeh_as_container(as);
-
- if (!container) {
- return -ENODEV;
- }
- return vfio_eeh_container_op(container, op);
-}
diff --git a/qemu/hw/vfio/pci-quirks.c b/qemu/hw/vfio/pci-quirks.c
deleted file mode 100644
index 49ecf1172..000000000
--- a/qemu/hw/vfio/pci-quirks.c
+++ /dev/null
@@ -1,1205 +0,0 @@
-/*
- * device quirks for PCI devices
- *
- * Copyright Red Hat, Inc. 2012-2015
- *
- * Authors:
- * Alex Williamson <alex.williamson@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "pci.h"
-#include "trace.h"
-#include "qemu/range.h"
-
-/* Use uin32_t for vendor & device so PCI_ANY_ID expands and cannot match hw */
-static bool vfio_pci_is(VFIOPCIDevice *vdev, uint32_t vendor, uint32_t device)
-{
- return (vendor == PCI_ANY_ID || vendor == vdev->vendor_id) &&
- (device == PCI_ANY_ID || device == vdev->device_id);
-}
-
-static bool vfio_is_vga(VFIOPCIDevice *vdev)
-{
- PCIDevice *pdev = &vdev->pdev;
- uint16_t class = pci_get_word(pdev->config + PCI_CLASS_DEVICE);
-
- return class == PCI_CLASS_DISPLAY_VGA;
-}
-
-/*
- * List of device ids/vendor ids for which to disable
- * option rom loading. This avoids the guest hangs during rom
- * execution as noticed with the BCM 57810 card for lack of a
- * more better way to handle such issues.
- * The user can still override by specifying a romfile or
- * rombar=1.
- * Please see https://bugs.launchpad.net/qemu/+bug/1284874
- * for an analysis of the 57810 card hang. When adding
- * a new vendor id/device id combination below, please also add
- * your card/environment details and information that could
- * help in debugging to the bug tracking this issue
- */
-static const struct {
- uint32_t vendor;
- uint32_t device;
-} romblacklist[] = {
- { 0x14e4, 0x168e }, /* Broadcom BCM 57810 */
-};
-
-bool vfio_blacklist_opt_rom(VFIOPCIDevice *vdev)
-{
- int i;
-
- for (i = 0 ; i < ARRAY_SIZE(romblacklist); i++) {
- if (vfio_pci_is(vdev, romblacklist[i].vendor, romblacklist[i].device)) {
- trace_vfio_quirk_rom_blacklisted(vdev->vbasedev.name,
- romblacklist[i].vendor,
- romblacklist[i].device);
- return true;
- }
- }
- return false;
-}
-
-/*
- * Device specific region quirks (mostly backdoors to PCI config space)
- */
-
-/*
- * The generic window quirks operate on an address and data register,
- * vfio_generic_window_address_quirk handles the address register and
- * vfio_generic_window_data_quirk handles the data register. These ops
- * pass reads and writes through to hardware until a value matching the
- * stored address match/mask is written. When this occurs, the data
- * register access emulated PCI config space for the device rather than
- * passing through accesses. This enables devices where PCI config space
- * is accessible behind a window register to maintain the virtualization
- * provided through vfio.
- */
-typedef struct VFIOConfigWindowMatch {
- uint32_t match;
- uint32_t mask;
-} VFIOConfigWindowMatch;
-
-typedef struct VFIOConfigWindowQuirk {
- struct VFIOPCIDevice *vdev;
-
- uint32_t address_val;
-
- uint32_t address_offset;
- uint32_t data_offset;
-
- bool window_enabled;
- uint8_t bar;
-
- MemoryRegion *addr_mem;
- MemoryRegion *data_mem;
-
- uint32_t nr_matches;
- VFIOConfigWindowMatch matches[];
-} VFIOConfigWindowQuirk;
-
-static uint64_t vfio_generic_window_quirk_address_read(void *opaque,
- hwaddr addr,
- unsigned size)
-{
- VFIOConfigWindowQuirk *window = opaque;
- VFIOPCIDevice *vdev = window->vdev;
-
- return vfio_region_read(&vdev->bars[window->bar].region,
- addr + window->address_offset, size);
-}
-
-static void vfio_generic_window_quirk_address_write(void *opaque, hwaddr addr,
- uint64_t data,
- unsigned size)
-{
- VFIOConfigWindowQuirk *window = opaque;
- VFIOPCIDevice *vdev = window->vdev;
- int i;
-
- window->window_enabled = false;
-
- vfio_region_write(&vdev->bars[window->bar].region,
- addr + window->address_offset, data, size);
-
- for (i = 0; i < window->nr_matches; i++) {
- if ((data & ~window->matches[i].mask) == window->matches[i].match) {
- window->window_enabled = true;
- window->address_val = data & window->matches[i].mask;
- trace_vfio_quirk_generic_window_address_write(vdev->vbasedev.name,
- memory_region_name(window->addr_mem), data);
- break;
- }
- }
-}
-
-static const MemoryRegionOps vfio_generic_window_address_quirk = {
- .read = vfio_generic_window_quirk_address_read,
- .write = vfio_generic_window_quirk_address_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static uint64_t vfio_generic_window_quirk_data_read(void *opaque,
- hwaddr addr, unsigned size)
-{
- VFIOConfigWindowQuirk *window = opaque;
- VFIOPCIDevice *vdev = window->vdev;
- uint64_t data;
-
- /* Always read data reg, discard if window enabled */
- data = vfio_region_read(&vdev->bars[window->bar].region,
- addr + window->data_offset, size);
-
- if (window->window_enabled) {
- data = vfio_pci_read_config(&vdev->pdev, window->address_val, size);
- trace_vfio_quirk_generic_window_data_read(vdev->vbasedev.name,
- memory_region_name(window->data_mem), data);
- }
-
- return data;
-}
-
-static void vfio_generic_window_quirk_data_write(void *opaque, hwaddr addr,
- uint64_t data, unsigned size)
-{
- VFIOConfigWindowQuirk *window = opaque;
- VFIOPCIDevice *vdev = window->vdev;
-
- if (window->window_enabled) {
- vfio_pci_write_config(&vdev->pdev, window->address_val, data, size);
- trace_vfio_quirk_generic_window_data_write(vdev->vbasedev.name,
- memory_region_name(window->data_mem), data);
- return;
- }
-
- vfio_region_write(&vdev->bars[window->bar].region,
- addr + window->data_offset, data, size);
-}
-
-static const MemoryRegionOps vfio_generic_window_data_quirk = {
- .read = vfio_generic_window_quirk_data_read,
- .write = vfio_generic_window_quirk_data_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-/*
- * The generic mirror quirk handles devices which expose PCI config space
- * through a region within a BAR. When enabled, reads and writes are
- * redirected through to emulated PCI config space. XXX if PCI config space
- * used memory regions, this could just be an alias.
- */
-typedef struct VFIOConfigMirrorQuirk {
- struct VFIOPCIDevice *vdev;
- uint32_t offset;
- uint8_t bar;
- MemoryRegion *mem;
-} VFIOConfigMirrorQuirk;
-
-static uint64_t vfio_generic_quirk_mirror_read(void *opaque,
- hwaddr addr, unsigned size)
-{
- VFIOConfigMirrorQuirk *mirror = opaque;
- VFIOPCIDevice *vdev = mirror->vdev;
- uint64_t data;
-
- /* Read and discard in case the hardware cares */
- (void)vfio_region_read(&vdev->bars[mirror->bar].region,
- addr + mirror->offset, size);
-
- data = vfio_pci_read_config(&vdev->pdev, addr, size);
- trace_vfio_quirk_generic_mirror_read(vdev->vbasedev.name,
- memory_region_name(mirror->mem),
- addr, data);
- return data;
-}
-
-static void vfio_generic_quirk_mirror_write(void *opaque, hwaddr addr,
- uint64_t data, unsigned size)
-{
- VFIOConfigMirrorQuirk *mirror = opaque;
- VFIOPCIDevice *vdev = mirror->vdev;
-
- vfio_pci_write_config(&vdev->pdev, addr, data, size);
- trace_vfio_quirk_generic_mirror_write(vdev->vbasedev.name,
- memory_region_name(mirror->mem),
- addr, data);
-}
-
-static const MemoryRegionOps vfio_generic_mirror_quirk = {
- .read = vfio_generic_quirk_mirror_read,
- .write = vfio_generic_quirk_mirror_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-/* Is range1 fully contained within range2? */
-static bool vfio_range_contained(uint64_t first1, uint64_t len1,
- uint64_t first2, uint64_t len2) {
- return (first1 >= first2 && first1 + len1 <= first2 + len2);
-}
-
-#define PCI_VENDOR_ID_ATI 0x1002
-
-/*
- * Radeon HD cards (HD5450 & HD7850) report the upper byte of the I/O port BAR
- * through VGA register 0x3c3. On newer cards, the I/O port BAR is always
- * BAR4 (older cards like the X550 used BAR1, but we don't care to support
- * those). Note that on bare metal, a read of 0x3c3 doesn't always return the
- * I/O port BAR address. Originally this was coded to return the virtual BAR
- * address only if the physical register read returns the actual BAR address,
- * but users have reported greater success if we return the virtual address
- * unconditionally.
- */
-static uint64_t vfio_ati_3c3_quirk_read(void *opaque,
- hwaddr addr, unsigned size)
-{
- VFIOPCIDevice *vdev = opaque;
- uint64_t data = vfio_pci_read_config(&vdev->pdev,
- PCI_BASE_ADDRESS_4 + 1, size);
-
- trace_vfio_quirk_ati_3c3_read(vdev->vbasedev.name, data);
-
- return data;
-}
-
-static const MemoryRegionOps vfio_ati_3c3_quirk = {
- .read = vfio_ati_3c3_quirk_read,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void vfio_vga_probe_ati_3c3_quirk(VFIOPCIDevice *vdev)
-{
- VFIOQuirk *quirk;
-
- /*
- * As long as the BAR is >= 256 bytes it will be aligned such that the
- * lower byte is always zero. Filter out anything else, if it exists.
- */
- if (!vfio_pci_is(vdev, PCI_VENDOR_ID_ATI, PCI_ANY_ID) ||
- !vdev->bars[4].ioport || vdev->bars[4].region.size < 256) {
- return;
- }
-
- quirk = g_malloc0(sizeof(*quirk));
- quirk->mem = g_new0(MemoryRegion, 1);
- quirk->nr_mem = 1;
-
- memory_region_init_io(quirk->mem, OBJECT(vdev), &vfio_ati_3c3_quirk, vdev,
- "vfio-ati-3c3-quirk", 1);
- memory_region_add_subregion(&vdev->vga->region[QEMU_PCI_VGA_IO_HI].mem,
- 3 /* offset 3 bytes from 0x3c0 */, quirk->mem);
-
- QLIST_INSERT_HEAD(&vdev->vga->region[QEMU_PCI_VGA_IO_HI].quirks,
- quirk, next);
-
- trace_vfio_quirk_ati_3c3_probe(vdev->vbasedev.name);
-}
-
-/*
- * Newer ATI/AMD devices, including HD5450 and HD7850, have a mirror to PCI
- * config space through MMIO BAR2 at offset 0x4000. Nothing seems to access
- * the MMIO space directly, but a window to this space is provided through
- * I/O port BAR4. Offset 0x0 is the address register and offset 0x4 is the
- * data register. When the address is programmed to a range of 0x4000-0x4fff
- * PCI configuration space is available. Experimentation seems to indicate
- * that read-only may be provided by hardware.
- */
-static void vfio_probe_ati_bar4_quirk(VFIOPCIDevice *vdev, int nr)
-{
- VFIOQuirk *quirk;
- VFIOConfigWindowQuirk *window;
-
- /* This windows doesn't seem to be used except by legacy VGA code */
- if (!vfio_pci_is(vdev, PCI_VENDOR_ID_ATI, PCI_ANY_ID) ||
- !vdev->has_vga || nr != 4) {
- return;
- }
-
- quirk = g_malloc0(sizeof(*quirk));
- quirk->mem = g_new0(MemoryRegion, 2);
- quirk->nr_mem = 2;
- window = quirk->data = g_malloc0(sizeof(*window) +
- sizeof(VFIOConfigWindowMatch));
- window->vdev = vdev;
- window->address_offset = 0;
- window->data_offset = 4;
- window->nr_matches = 1;
- window->matches[0].match = 0x4000;
- window->matches[0].mask = vdev->config_size - 1;
- window->bar = nr;
- window->addr_mem = &quirk->mem[0];
- window->data_mem = &quirk->mem[1];
-
- memory_region_init_io(window->addr_mem, OBJECT(vdev),
- &vfio_generic_window_address_quirk, window,
- "vfio-ati-bar4-window-address-quirk", 4);
- memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,
- window->address_offset,
- window->addr_mem, 1);
-
- memory_region_init_io(window->data_mem, OBJECT(vdev),
- &vfio_generic_window_data_quirk, window,
- "vfio-ati-bar4-window-data-quirk", 4);
- memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,
- window->data_offset,
- window->data_mem, 1);
-
- QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
-
- trace_vfio_quirk_ati_bar4_probe(vdev->vbasedev.name);
-}
-
-/*
- * Trap the BAR2 MMIO mirror to config space as well.
- */
-static void vfio_probe_ati_bar2_quirk(VFIOPCIDevice *vdev, int nr)
-{
- VFIOQuirk *quirk;
- VFIOConfigMirrorQuirk *mirror;
-
- /* Only enable on newer devices where BAR2 is 64bit */
- if (!vfio_pci_is(vdev, PCI_VENDOR_ID_ATI, PCI_ANY_ID) ||
- !vdev->has_vga || nr != 2 || !vdev->bars[2].mem64) {
- return;
- }
-
- quirk = g_malloc0(sizeof(*quirk));
- mirror = quirk->data = g_malloc0(sizeof(*mirror));
- mirror->mem = quirk->mem = g_new0(MemoryRegion, 1);
- quirk->nr_mem = 1;
- mirror->vdev = vdev;
- mirror->offset = 0x4000;
- mirror->bar = nr;
-
- memory_region_init_io(mirror->mem, OBJECT(vdev),
- &vfio_generic_mirror_quirk, mirror,
- "vfio-ati-bar2-4000-quirk", PCI_CONFIG_SPACE_SIZE);
- memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,
- mirror->offset, mirror->mem, 1);
-
- QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
-
- trace_vfio_quirk_ati_bar2_probe(vdev->vbasedev.name);
-}
-
-/*
- * Older ATI/AMD cards like the X550 have a similar window to that above.
- * I/O port BAR1 provides a window to a mirror of PCI config space located
- * in BAR2 at offset 0xf00. We don't care to support such older cards, but
- * note it for future reference.
- */
-
-#define PCI_VENDOR_ID_NVIDIA 0x10de
-
-/*
- * Nvidia has several different methods to get to config space, the
- * nouveu project has several of these documented here:
- * https://github.com/pathscale/envytools/tree/master/hwdocs
- *
- * The first quirk is actually not documented in envytools and is found
- * on 10de:01d1 (NVIDIA Corporation G72 [GeForce 7300 LE]). This is an
- * NV46 chipset. The backdoor uses the legacy VGA I/O ports to access
- * the mirror of PCI config space found at BAR0 offset 0x1800. The access
- * sequence first writes 0x338 to I/O port 0x3d4. The target offset is
- * then written to 0x3d0. Finally 0x538 is written for a read and 0x738
- * is written for a write to 0x3d4. The BAR0 offset is then accessible
- * through 0x3d0. This quirk doesn't seem to be necessary on newer cards
- * that use the I/O port BAR5 window but it doesn't hurt to leave it.
- */
-typedef enum {NONE = 0, SELECT, WINDOW, READ, WRITE} VFIONvidia3d0State;
-static const char *nv3d0_states[] = { "NONE", "SELECT",
- "WINDOW", "READ", "WRITE" };
-
-typedef struct VFIONvidia3d0Quirk {
- VFIOPCIDevice *vdev;
- VFIONvidia3d0State state;
- uint32_t offset;
-} VFIONvidia3d0Quirk;
-
-static uint64_t vfio_nvidia_3d4_quirk_read(void *opaque,
- hwaddr addr, unsigned size)
-{
- VFIONvidia3d0Quirk *quirk = opaque;
- VFIOPCIDevice *vdev = quirk->vdev;
-
- quirk->state = NONE;
-
- return vfio_vga_read(&vdev->vga->region[QEMU_PCI_VGA_IO_HI],
- addr + 0x14, size);
-}
-
-static void vfio_nvidia_3d4_quirk_write(void *opaque, hwaddr addr,
- uint64_t data, unsigned size)
-{
- VFIONvidia3d0Quirk *quirk = opaque;
- VFIOPCIDevice *vdev = quirk->vdev;
- VFIONvidia3d0State old_state = quirk->state;
-
- quirk->state = NONE;
-
- switch (data) {
- case 0x338:
- if (old_state == NONE) {
- quirk->state = SELECT;
- trace_vfio_quirk_nvidia_3d0_state(vdev->vbasedev.name,
- nv3d0_states[quirk->state]);
- }
- break;
- case 0x538:
- if (old_state == WINDOW) {
- quirk->state = READ;
- trace_vfio_quirk_nvidia_3d0_state(vdev->vbasedev.name,
- nv3d0_states[quirk->state]);
- }
- break;
- case 0x738:
- if (old_state == WINDOW) {
- quirk->state = WRITE;
- trace_vfio_quirk_nvidia_3d0_state(vdev->vbasedev.name,
- nv3d0_states[quirk->state]);
- }
- break;
- }
-
- vfio_vga_write(&vdev->vga->region[QEMU_PCI_VGA_IO_HI],
- addr + 0x14, data, size);
-}
-
-static const MemoryRegionOps vfio_nvidia_3d4_quirk = {
- .read = vfio_nvidia_3d4_quirk_read,
- .write = vfio_nvidia_3d4_quirk_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static uint64_t vfio_nvidia_3d0_quirk_read(void *opaque,
- hwaddr addr, unsigned size)
-{
- VFIONvidia3d0Quirk *quirk = opaque;
- VFIOPCIDevice *vdev = quirk->vdev;
- VFIONvidia3d0State old_state = quirk->state;
- uint64_t data = vfio_vga_read(&vdev->vga->region[QEMU_PCI_VGA_IO_HI],
- addr + 0x10, size);
-
- quirk->state = NONE;
-
- if (old_state == READ &&
- (quirk->offset & ~(PCI_CONFIG_SPACE_SIZE - 1)) == 0x1800) {
- uint8_t offset = quirk->offset & (PCI_CONFIG_SPACE_SIZE - 1);
-
- data = vfio_pci_read_config(&vdev->pdev, offset, size);
- trace_vfio_quirk_nvidia_3d0_read(vdev->vbasedev.name,
- offset, size, data);
- }
-
- return data;
-}
-
-static void vfio_nvidia_3d0_quirk_write(void *opaque, hwaddr addr,
- uint64_t data, unsigned size)
-{
- VFIONvidia3d0Quirk *quirk = opaque;
- VFIOPCIDevice *vdev = quirk->vdev;
- VFIONvidia3d0State old_state = quirk->state;
-
- quirk->state = NONE;
-
- if (old_state == SELECT) {
- quirk->offset = (uint32_t)data;
- quirk->state = WINDOW;
- trace_vfio_quirk_nvidia_3d0_state(vdev->vbasedev.name,
- nv3d0_states[quirk->state]);
- } else if (old_state == WRITE) {
- if ((quirk->offset & ~(PCI_CONFIG_SPACE_SIZE - 1)) == 0x1800) {
- uint8_t offset = quirk->offset & (PCI_CONFIG_SPACE_SIZE - 1);
-
- vfio_pci_write_config(&vdev->pdev, offset, data, size);
- trace_vfio_quirk_nvidia_3d0_write(vdev->vbasedev.name,
- offset, data, size);
- return;
- }
- }
-
- vfio_vga_write(&vdev->vga->region[QEMU_PCI_VGA_IO_HI],
- addr + 0x10, data, size);
-}
-
-static const MemoryRegionOps vfio_nvidia_3d0_quirk = {
- .read = vfio_nvidia_3d0_quirk_read,
- .write = vfio_nvidia_3d0_quirk_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void vfio_vga_probe_nvidia_3d0_quirk(VFIOPCIDevice *vdev)
-{
- VFIOQuirk *quirk;
- VFIONvidia3d0Quirk *data;
-
- if (!vfio_pci_is(vdev, PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID) ||
- !vdev->bars[1].region.size) {
- return;
- }
-
- quirk = g_malloc0(sizeof(*quirk));
- quirk->data = data = g_malloc0(sizeof(*data));
- quirk->mem = g_new0(MemoryRegion, 2);
- quirk->nr_mem = 2;
- data->vdev = vdev;
-
- memory_region_init_io(&quirk->mem[0], OBJECT(vdev), &vfio_nvidia_3d4_quirk,
- data, "vfio-nvidia-3d4-quirk", 2);
- memory_region_add_subregion(&vdev->vga->region[QEMU_PCI_VGA_IO_HI].mem,
- 0x14 /* 0x3c0 + 0x14 */, &quirk->mem[0]);
-
- memory_region_init_io(&quirk->mem[1], OBJECT(vdev), &vfio_nvidia_3d0_quirk,
- data, "vfio-nvidia-3d0-quirk", 2);
- memory_region_add_subregion(&vdev->vga->region[QEMU_PCI_VGA_IO_HI].mem,
- 0x10 /* 0x3c0 + 0x10 */, &quirk->mem[1]);
-
- QLIST_INSERT_HEAD(&vdev->vga->region[QEMU_PCI_VGA_IO_HI].quirks,
- quirk, next);
-
- trace_vfio_quirk_nvidia_3d0_probe(vdev->vbasedev.name);
-}
-
-/*
- * The second quirk is documented in envytools. The I/O port BAR5 is just
- * a set of address/data ports to the MMIO BARs. The BAR we care about is
- * again BAR0. This backdoor is apparently a bit newer than the one above
- * so we need to not only trap 256 bytes @0x1800, but all of PCI config
- * space, including extended space is available at the 4k @0x88000.
- */
-typedef struct VFIONvidiaBAR5Quirk {
- uint32_t master;
- uint32_t enable;
- MemoryRegion *addr_mem;
- MemoryRegion *data_mem;
- bool enabled;
- VFIOConfigWindowQuirk window; /* last for match data */
-} VFIONvidiaBAR5Quirk;
-
-static void vfio_nvidia_bar5_enable(VFIONvidiaBAR5Quirk *bar5)
-{
- VFIOPCIDevice *vdev = bar5->window.vdev;
-
- if (((bar5->master & bar5->enable) & 0x1) == bar5->enabled) {
- return;
- }
-
- bar5->enabled = !bar5->enabled;
- trace_vfio_quirk_nvidia_bar5_state(vdev->vbasedev.name,
- bar5->enabled ? "Enable" : "Disable");
- memory_region_set_enabled(bar5->addr_mem, bar5->enabled);
- memory_region_set_enabled(bar5->data_mem, bar5->enabled);
-}
-
-static uint64_t vfio_nvidia_bar5_quirk_master_read(void *opaque,
- hwaddr addr, unsigned size)
-{
- VFIONvidiaBAR5Quirk *bar5 = opaque;
- VFIOPCIDevice *vdev = bar5->window.vdev;
-
- return vfio_region_read(&vdev->bars[5].region, addr, size);
-}
-
-static void vfio_nvidia_bar5_quirk_master_write(void *opaque, hwaddr addr,
- uint64_t data, unsigned size)
-{
- VFIONvidiaBAR5Quirk *bar5 = opaque;
- VFIOPCIDevice *vdev = bar5->window.vdev;
-
- vfio_region_write(&vdev->bars[5].region, addr, data, size);
-
- bar5->master = data;
- vfio_nvidia_bar5_enable(bar5);
-}
-
-static const MemoryRegionOps vfio_nvidia_bar5_quirk_master = {
- .read = vfio_nvidia_bar5_quirk_master_read,
- .write = vfio_nvidia_bar5_quirk_master_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static uint64_t vfio_nvidia_bar5_quirk_enable_read(void *opaque,
- hwaddr addr, unsigned size)
-{
- VFIONvidiaBAR5Quirk *bar5 = opaque;
- VFIOPCIDevice *vdev = bar5->window.vdev;
-
- return vfio_region_read(&vdev->bars[5].region, addr + 4, size);
-}
-
-static void vfio_nvidia_bar5_quirk_enable_write(void *opaque, hwaddr addr,
- uint64_t data, unsigned size)
-{
- VFIONvidiaBAR5Quirk *bar5 = opaque;
- VFIOPCIDevice *vdev = bar5->window.vdev;
-
- vfio_region_write(&vdev->bars[5].region, addr + 4, data, size);
-
- bar5->enable = data;
- vfio_nvidia_bar5_enable(bar5);
-}
-
-static const MemoryRegionOps vfio_nvidia_bar5_quirk_enable = {
- .read = vfio_nvidia_bar5_quirk_enable_read,
- .write = vfio_nvidia_bar5_quirk_enable_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void vfio_probe_nvidia_bar5_quirk(VFIOPCIDevice *vdev, int nr)
-{
- VFIOQuirk *quirk;
- VFIONvidiaBAR5Quirk *bar5;
- VFIOConfigWindowQuirk *window;
-
- if (!vfio_pci_is(vdev, PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID) ||
- !vdev->has_vga || nr != 5) {
- return;
- }
-
- quirk = g_malloc0(sizeof(*quirk));
- quirk->mem = g_new0(MemoryRegion, 4);
- quirk->nr_mem = 4;
- bar5 = quirk->data = g_malloc0(sizeof(*bar5) +
- (sizeof(VFIOConfigWindowMatch) * 2));
- window = &bar5->window;
-
- window->vdev = vdev;
- window->address_offset = 0x8;
- window->data_offset = 0xc;
- window->nr_matches = 2;
- window->matches[0].match = 0x1800;
- window->matches[0].mask = PCI_CONFIG_SPACE_SIZE - 1;
- window->matches[1].match = 0x88000;
- window->matches[1].mask = vdev->config_size - 1;
- window->bar = nr;
- window->addr_mem = bar5->addr_mem = &quirk->mem[0];
- window->data_mem = bar5->data_mem = &quirk->mem[1];
-
- memory_region_init_io(window->addr_mem, OBJECT(vdev),
- &vfio_generic_window_address_quirk, window,
- "vfio-nvidia-bar5-window-address-quirk", 4);
- memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,
- window->address_offset,
- window->addr_mem, 1);
- memory_region_set_enabled(window->addr_mem, false);
-
- memory_region_init_io(window->data_mem, OBJECT(vdev),
- &vfio_generic_window_data_quirk, window,
- "vfio-nvidia-bar5-window-data-quirk", 4);
- memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,
- window->data_offset,
- window->data_mem, 1);
- memory_region_set_enabled(window->data_mem, false);
-
- memory_region_init_io(&quirk->mem[2], OBJECT(vdev),
- &vfio_nvidia_bar5_quirk_master, bar5,
- "vfio-nvidia-bar5-master-quirk", 4);
- memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,
- 0, &quirk->mem[2], 1);
-
- memory_region_init_io(&quirk->mem[3], OBJECT(vdev),
- &vfio_nvidia_bar5_quirk_enable, bar5,
- "vfio-nvidia-bar5-enable-quirk", 4);
- memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,
- 4, &quirk->mem[3], 1);
-
- QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
-
- trace_vfio_quirk_nvidia_bar5_probe(vdev->vbasedev.name);
-}
-
-/*
- * Finally, BAR0 itself. We want to redirect any accesses to either
- * 0x1800 or 0x88000 through the PCI config space access functions.
- */
-static void vfio_nvidia_quirk_mirror_write(void *opaque, hwaddr addr,
- uint64_t data, unsigned size)
-{
- VFIOConfigMirrorQuirk *mirror = opaque;
- VFIOPCIDevice *vdev = mirror->vdev;
- PCIDevice *pdev = &vdev->pdev;
-
- vfio_generic_quirk_mirror_write(opaque, addr, data, size);
-
- /*
- * Nvidia seems to acknowledge MSI interrupts by writing 0xff to the
- * MSI capability ID register. Both the ID and next register are
- * read-only, so we allow writes covering either of those to real hw.
- */
- if ((pdev->cap_present & QEMU_PCI_CAP_MSI) &&
- vfio_range_contained(addr, size, pdev->msi_cap, PCI_MSI_FLAGS)) {
- vfio_region_write(&vdev->bars[mirror->bar].region,
- addr + mirror->offset, data, size);
- trace_vfio_quirk_nvidia_bar0_msi_ack(vdev->vbasedev.name);
- }
-}
-
-static const MemoryRegionOps vfio_nvidia_mirror_quirk = {
- .read = vfio_generic_quirk_mirror_read,
- .write = vfio_nvidia_quirk_mirror_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void vfio_probe_nvidia_bar0_quirk(VFIOPCIDevice *vdev, int nr)
-{
- VFIOQuirk *quirk;
- VFIOConfigMirrorQuirk *mirror;
-
- if (!vfio_pci_is(vdev, PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID) ||
- !vfio_is_vga(vdev) || nr != 0) {
- return;
- }
-
- quirk = g_malloc0(sizeof(*quirk));
- mirror = quirk->data = g_malloc0(sizeof(*mirror));
- mirror->mem = quirk->mem = g_new0(MemoryRegion, 1);
- quirk->nr_mem = 1;
- mirror->vdev = vdev;
- mirror->offset = 0x88000;
- mirror->bar = nr;
-
- memory_region_init_io(mirror->mem, OBJECT(vdev),
- &vfio_nvidia_mirror_quirk, mirror,
- "vfio-nvidia-bar0-88000-mirror-quirk",
- vdev->config_size);
- memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,
- mirror->offset, mirror->mem, 1);
-
- QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
-
- /* The 0x1800 offset mirror only seems to get used by legacy VGA */
- if (vdev->has_vga) {
- quirk = g_malloc0(sizeof(*quirk));
- mirror = quirk->data = g_malloc0(sizeof(*mirror));
- mirror->mem = quirk->mem = g_new0(MemoryRegion, 1);
- quirk->nr_mem = 1;
- mirror->vdev = vdev;
- mirror->offset = 0x1800;
- mirror->bar = nr;
-
- memory_region_init_io(mirror->mem, OBJECT(vdev),
- &vfio_nvidia_mirror_quirk, mirror,
- "vfio-nvidia-bar0-1800-mirror-quirk",
- PCI_CONFIG_SPACE_SIZE);
- memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,
- mirror->offset, mirror->mem, 1);
-
- QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
- }
-
- trace_vfio_quirk_nvidia_bar0_probe(vdev->vbasedev.name);
-}
-
-/*
- * TODO - Some Nvidia devices provide config access to their companion HDA
- * device and even to their parent bridge via these config space mirrors.
- * Add quirks for those regions.
- */
-
-#define PCI_VENDOR_ID_REALTEK 0x10ec
-
-/*
- * RTL8168 devices have a backdoor that can access the MSI-X table. At BAR2
- * offset 0x70 there is a dword data register, offset 0x74 is a dword address
- * register. According to the Linux r8169 driver, the MSI-X table is addressed
- * when the "type" portion of the address register is set to 0x1. This appears
- * to be bits 16:30. Bit 31 is both a write indicator and some sort of
- * "address latched" indicator. Bits 12:15 are a mask field, which we can
- * ignore because the MSI-X table should always be accessed as a dword (full
- * mask). Bits 0:11 is offset within the type.
- *
- * Example trace:
- *
- * Read from MSI-X table offset 0
- * vfio: vfio_bar_write(0000:05:00.0:BAR2+0x74, 0x1f000, 4) // store read addr
- * vfio: vfio_bar_read(0000:05:00.0:BAR2+0x74, 4) = 0x8001f000 // latch
- * vfio: vfio_bar_read(0000:05:00.0:BAR2+0x70, 4) = 0xfee00398 // read data
- *
- * Write 0xfee00000 to MSI-X table offset 0
- * vfio: vfio_bar_write(0000:05:00.0:BAR2+0x70, 0xfee00000, 4) // write data
- * vfio: vfio_bar_write(0000:05:00.0:BAR2+0x74, 0x8001f000, 4) // do write
- * vfio: vfio_bar_read(0000:05:00.0:BAR2+0x74, 4) = 0x1f000 // complete
- */
-typedef struct VFIOrtl8168Quirk {
- VFIOPCIDevice *vdev;
- uint32_t addr;
- uint32_t data;
- bool enabled;
-} VFIOrtl8168Quirk;
-
-static uint64_t vfio_rtl8168_quirk_address_read(void *opaque,
- hwaddr addr, unsigned size)
-{
- VFIOrtl8168Quirk *rtl = opaque;
- VFIOPCIDevice *vdev = rtl->vdev;
- uint64_t data = vfio_region_read(&vdev->bars[2].region, addr + 0x74, size);
-
- if (rtl->enabled) {
- data = rtl->addr ^ 0x80000000U; /* latch/complete */
- trace_vfio_quirk_rtl8168_fake_latch(vdev->vbasedev.name, data);
- }
-
- return data;
-}
-
-static void vfio_rtl8168_quirk_address_write(void *opaque, hwaddr addr,
- uint64_t data, unsigned size)
-{
- VFIOrtl8168Quirk *rtl = opaque;
- VFIOPCIDevice *vdev = rtl->vdev;
-
- rtl->enabled = false;
-
- if ((data & 0x7fff0000) == 0x10000) { /* MSI-X table */
- rtl->enabled = true;
- rtl->addr = (uint32_t)data;
-
- if (data & 0x80000000U) { /* Do write */
- if (vdev->pdev.cap_present & QEMU_PCI_CAP_MSIX) {
- hwaddr offset = data & 0xfff;
- uint64_t val = rtl->data;
-
- trace_vfio_quirk_rtl8168_msix_write(vdev->vbasedev.name,
- (uint16_t)offset, val);
-
- /* Write to the proper guest MSI-X table instead */
- memory_region_dispatch_write(&vdev->pdev.msix_table_mmio,
- offset, val, size,
- MEMTXATTRS_UNSPECIFIED);
- }
- return; /* Do not write guest MSI-X data to hardware */
- }
- }
-
- vfio_region_write(&vdev->bars[2].region, addr + 0x74, data, size);
-}
-
-static const MemoryRegionOps vfio_rtl_address_quirk = {
- .read = vfio_rtl8168_quirk_address_read,
- .write = vfio_rtl8168_quirk_address_write,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- .unaligned = false,
- },
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static uint64_t vfio_rtl8168_quirk_data_read(void *opaque,
- hwaddr addr, unsigned size)
-{
- VFIOrtl8168Quirk *rtl = opaque;
- VFIOPCIDevice *vdev = rtl->vdev;
- uint64_t data = vfio_region_read(&vdev->bars[2].region, addr + 0x74, size);
-
- if (rtl->enabled && (vdev->pdev.cap_present & QEMU_PCI_CAP_MSIX)) {
- hwaddr offset = rtl->addr & 0xfff;
- memory_region_dispatch_read(&vdev->pdev.msix_table_mmio, offset,
- &data, size, MEMTXATTRS_UNSPECIFIED);
- trace_vfio_quirk_rtl8168_msix_read(vdev->vbasedev.name, offset, data);
- }
-
- return data;
-}
-
-static void vfio_rtl8168_quirk_data_write(void *opaque, hwaddr addr,
- uint64_t data, unsigned size)
-{
- VFIOrtl8168Quirk *rtl = opaque;
- VFIOPCIDevice *vdev = rtl->vdev;
-
- rtl->data = (uint32_t)data;
-
- vfio_region_write(&vdev->bars[2].region, addr + 0x70, data, size);
-}
-
-static const MemoryRegionOps vfio_rtl_data_quirk = {
- .read = vfio_rtl8168_quirk_data_read,
- .write = vfio_rtl8168_quirk_data_write,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- .unaligned = false,
- },
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void vfio_probe_rtl8168_bar2_quirk(VFIOPCIDevice *vdev, int nr)
-{
- VFIOQuirk *quirk;
- VFIOrtl8168Quirk *rtl;
-
- if (!vfio_pci_is(vdev, PCI_VENDOR_ID_REALTEK, 0x8168) || nr != 2) {
- return;
- }
-
- quirk = g_malloc0(sizeof(*quirk));
- quirk->mem = g_new0(MemoryRegion, 2);
- quirk->nr_mem = 2;
- quirk->data = rtl = g_malloc0(sizeof(*rtl));
- rtl->vdev = vdev;
-
- memory_region_init_io(&quirk->mem[0], OBJECT(vdev),
- &vfio_rtl_address_quirk, rtl,
- "vfio-rtl8168-window-address-quirk", 4);
- memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,
- 0x74, &quirk->mem[0], 1);
-
- memory_region_init_io(&quirk->mem[1], OBJECT(vdev),
- &vfio_rtl_data_quirk, rtl,
- "vfio-rtl8168-window-data-quirk", 4);
- memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,
- 0x70, &quirk->mem[1], 1);
-
- QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
-
- trace_vfio_quirk_rtl8168_probe(vdev->vbasedev.name);
-}
-
-/*
- * Common quirk probe entry points.
- */
-void vfio_vga_quirk_setup(VFIOPCIDevice *vdev)
-{
- vfio_vga_probe_ati_3c3_quirk(vdev);
- vfio_vga_probe_nvidia_3d0_quirk(vdev);
-}
-
-void vfio_vga_quirk_exit(VFIOPCIDevice *vdev)
-{
- VFIOQuirk *quirk;
- int i, j;
-
- for (i = 0; i < ARRAY_SIZE(vdev->vga->region); i++) {
- QLIST_FOREACH(quirk, &vdev->vga->region[i].quirks, next) {
- for (j = 0; j < quirk->nr_mem; j++) {
- memory_region_del_subregion(&vdev->vga->region[i].mem,
- &quirk->mem[j]);
- }
- }
- }
-}
-
-void vfio_vga_quirk_finalize(VFIOPCIDevice *vdev)
-{
- int i, j;
-
- for (i = 0; i < ARRAY_SIZE(vdev->vga->region); i++) {
- while (!QLIST_EMPTY(&vdev->vga->region[i].quirks)) {
- VFIOQuirk *quirk = QLIST_FIRST(&vdev->vga->region[i].quirks);
- QLIST_REMOVE(quirk, next);
- for (j = 0; j < quirk->nr_mem; j++) {
- object_unparent(OBJECT(&quirk->mem[j]));
- }
- g_free(quirk->mem);
- g_free(quirk->data);
- g_free(quirk);
- }
- }
-}
-
-void vfio_bar_quirk_setup(VFIOPCIDevice *vdev, int nr)
-{
- vfio_probe_ati_bar4_quirk(vdev, nr);
- vfio_probe_ati_bar2_quirk(vdev, nr);
- vfio_probe_nvidia_bar5_quirk(vdev, nr);
- vfio_probe_nvidia_bar0_quirk(vdev, nr);
- vfio_probe_rtl8168_bar2_quirk(vdev, nr);
-}
-
-void vfio_bar_quirk_exit(VFIOPCIDevice *vdev, int nr)
-{
- VFIOBAR *bar = &vdev->bars[nr];
- VFIOQuirk *quirk;
- int i;
-
- QLIST_FOREACH(quirk, &bar->quirks, next) {
- for (i = 0; i < quirk->nr_mem; i++) {
- memory_region_del_subregion(bar->region.mem, &quirk->mem[i]);
- }
- }
-}
-
-void vfio_bar_quirk_finalize(VFIOPCIDevice *vdev, int nr)
-{
- VFIOBAR *bar = &vdev->bars[nr];
- int i;
-
- while (!QLIST_EMPTY(&bar->quirks)) {
- VFIOQuirk *quirk = QLIST_FIRST(&bar->quirks);
- QLIST_REMOVE(quirk, next);
- for (i = 0; i < quirk->nr_mem; i++) {
- object_unparent(OBJECT(&quirk->mem[i]));
- }
- g_free(quirk->mem);
- g_free(quirk->data);
- g_free(quirk);
- }
-}
-
-/*
- * Reset quirks
- */
-
-/*
- * AMD Radeon PCI config reset, based on Linux:
- * drivers/gpu/drm/radeon/ci_smc.c:ci_is_smc_running()
- * drivers/gpu/drm/radeon/radeon_device.c:radeon_pci_config_reset
- * drivers/gpu/drm/radeon/ci_smc.c:ci_reset_smc()
- * drivers/gpu/drm/radeon/ci_smc.c:ci_stop_smc_clock()
- * IDs: include/drm/drm_pciids.h
- * Registers: http://cgit.freedesktop.org/~agd5f/linux/commit/?id=4e2aa447f6f0
- *
- * Bonaire and Hawaii GPUs do not respond to a bus reset. This is a bug in the
- * hardware that should be fixed on future ASICs. The symptom of this is that
- * once the accerlated driver loads, Windows guests will bsod on subsequent
- * attmpts to load the driver, such as after VM reset or shutdown/restart. To
- * work around this, we do an AMD specific PCI config reset, followed by an SMC
- * reset. The PCI config reset only works if SMC firmware is running, so we
- * have a dependency on the state of the device as to whether this reset will
- * be effective. There are still cases where we won't be able to kick the
- * device into working, but this greatly improves the usability overall. The
- * config reset magic is relatively common on AMD GPUs, but the setup and SMC
- * poking is largely ASIC specific.
- */
-static bool vfio_radeon_smc_is_running(VFIOPCIDevice *vdev)
-{
- uint32_t clk, pc_c;
-
- /*
- * Registers 200h and 204h are index and data registers for accessing
- * indirect configuration registers within the device.
- */
- vfio_region_write(&vdev->bars[5].region, 0x200, 0x80000004, 4);
- clk = vfio_region_read(&vdev->bars[5].region, 0x204, 4);
- vfio_region_write(&vdev->bars[5].region, 0x200, 0x80000370, 4);
- pc_c = vfio_region_read(&vdev->bars[5].region, 0x204, 4);
-
- return (!(clk & 1) && (0x20100 <= pc_c));
-}
-
-/*
- * The scope of a config reset is controlled by a mode bit in the misc register
- * and a fuse, exposed as a bit in another register. The fuse is the default
- * (0 = GFX, 1 = whole GPU), the misc bit is a toggle, with the forumula
- * scope = !(misc ^ fuse), where the resulting scope is defined the same as
- * the fuse. A truth table therefore tells us that if misc == fuse, we need
- * to flip the value of the bit in the misc register.
- */
-static void vfio_radeon_set_gfx_only_reset(VFIOPCIDevice *vdev)
-{
- uint32_t misc, fuse;
- bool a, b;
-
- vfio_region_write(&vdev->bars[5].region, 0x200, 0xc00c0000, 4);
- fuse = vfio_region_read(&vdev->bars[5].region, 0x204, 4);
- b = fuse & 64;
-
- vfio_region_write(&vdev->bars[5].region, 0x200, 0xc0000010, 4);
- misc = vfio_region_read(&vdev->bars[5].region, 0x204, 4);
- a = misc & 2;
-
- if (a == b) {
- vfio_region_write(&vdev->bars[5].region, 0x204, misc ^ 2, 4);
- vfio_region_read(&vdev->bars[5].region, 0x204, 4); /* flush */
- }
-}
-
-static int vfio_radeon_reset(VFIOPCIDevice *vdev)
-{
- PCIDevice *pdev = &vdev->pdev;
- int i, ret = 0;
- uint32_t data;
-
- /* Defer to a kernel implemented reset */
- if (vdev->vbasedev.reset_works) {
- trace_vfio_quirk_ati_bonaire_reset_skipped(vdev->vbasedev.name);
- return -ENODEV;
- }
-
- /* Enable only memory BAR access */
- vfio_pci_write_config(pdev, PCI_COMMAND, PCI_COMMAND_MEMORY, 2);
-
- /* Reset only works if SMC firmware is loaded and running */
- if (!vfio_radeon_smc_is_running(vdev)) {
- ret = -EINVAL;
- trace_vfio_quirk_ati_bonaire_reset_no_smc(vdev->vbasedev.name);
- goto out;
- }
-
- /* Make sure only the GFX function is reset */
- vfio_radeon_set_gfx_only_reset(vdev);
-
- /* AMD PCI config reset */
- vfio_pci_write_config(pdev, 0x7c, 0x39d5e86b, 4);
- usleep(100);
-
- /* Read back the memory size to make sure we're out of reset */
- for (i = 0; i < 100000; i++) {
- if (vfio_region_read(&vdev->bars[5].region, 0x5428, 4) != 0xffffffff) {
- goto reset_smc;
- }
- usleep(1);
- }
-
- trace_vfio_quirk_ati_bonaire_reset_timeout(vdev->vbasedev.name);
-
-reset_smc:
- /* Reset SMC */
- vfio_region_write(&vdev->bars[5].region, 0x200, 0x80000000, 4);
- data = vfio_region_read(&vdev->bars[5].region, 0x204, 4);
- data |= 1;
- vfio_region_write(&vdev->bars[5].region, 0x204, data, 4);
-
- /* Disable SMC clock */
- vfio_region_write(&vdev->bars[5].region, 0x200, 0x80000004, 4);
- data = vfio_region_read(&vdev->bars[5].region, 0x204, 4);
- data |= 1;
- vfio_region_write(&vdev->bars[5].region, 0x204, data, 4);
-
- trace_vfio_quirk_ati_bonaire_reset_done(vdev->vbasedev.name);
-
-out:
- /* Restore PCI command register */
- vfio_pci_write_config(pdev, PCI_COMMAND, 0, 2);
-
- return ret;
-}
-
-void vfio_setup_resetfn_quirk(VFIOPCIDevice *vdev)
-{
- switch (vdev->vendor_id) {
- case 0x1002:
- switch (vdev->device_id) {
- /* Bonaire */
- case 0x6649: /* Bonaire [FirePro W5100] */
- case 0x6650:
- case 0x6651:
- case 0x6658: /* Bonaire XTX [Radeon R7 260X] */
- case 0x665c: /* Bonaire XT [Radeon HD 7790/8770 / R9 260 OEM] */
- case 0x665d: /* Bonaire [Radeon R7 200 Series] */
- /* Hawaii */
- case 0x67A0: /* Hawaii XT GL [FirePro W9100] */
- case 0x67A1: /* Hawaii PRO GL [FirePro W8100] */
- case 0x67A2:
- case 0x67A8:
- case 0x67A9:
- case 0x67AA:
- case 0x67B0: /* Hawaii XT [Radeon R9 290X] */
- case 0x67B1: /* Hawaii PRO [Radeon R9 290] */
- case 0x67B8:
- case 0x67B9:
- case 0x67BA:
- case 0x67BE:
- vdev->resetfn = vfio_radeon_reset;
- trace_vfio_quirk_ati_bonaire_reset(vdev->vbasedev.name);
- break;
- }
- break;
- }
-}
diff --git a/qemu/hw/vfio/pci.c b/qemu/hw/vfio/pci.c
deleted file mode 100644
index d091d8cf0..000000000
--- a/qemu/hw/vfio/pci.c
+++ /dev/null
@@ -1,2734 +0,0 @@
-/*
- * vfio based device assignment support
- *
- * Copyright Red Hat, Inc. 2012
- *
- * Authors:
- * Alex Williamson <alex.williamson@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- * Based on qemu-kvm device-assignment:
- * Adapted for KVM by Qumranet.
- * Copyright (c) 2007, Neocleus, Alex Novik (alex@neocleus.com)
- * Copyright (c) 2007, Neocleus, Guy Zana (guy@neocleus.com)
- * Copyright (C) 2008, Qumranet, Amit Shah (amit.shah@qumranet.com)
- * Copyright (C) 2008, Red Hat, Amit Shah (amit.shah@redhat.com)
- * Copyright (C) 2008, IBM, Muli Ben-Yehuda (muli@il.ibm.com)
- */
-
-#include "qemu/osdep.h"
-#include <linux/vfio.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-
-#include "hw/pci/msi.h"
-#include "hw/pci/msix.h"
-#include "hw/pci/pci_bridge.h"
-#include "qemu/error-report.h"
-#include "qemu/range.h"
-#include "sysemu/kvm.h"
-#include "sysemu/sysemu.h"
-#include "pci.h"
-#include "trace.h"
-
-#define MSIX_CAP_LENGTH 12
-
-static void vfio_disable_interrupts(VFIOPCIDevice *vdev);
-static void vfio_mmap_set_enabled(VFIOPCIDevice *vdev, bool enabled);
-
-/*
- * Disabling BAR mmaping can be slow, but toggling it around INTx can
- * also be a huge overhead. We try to get the best of both worlds by
- * waiting until an interrupt to disable mmaps (subsequent transitions
- * to the same state are effectively no overhead). If the interrupt has
- * been serviced and the time gap is long enough, we re-enable mmaps for
- * performance. This works well for things like graphics cards, which
- * may not use their interrupt at all and are penalized to an unusable
- * level by read/write BAR traps. Other devices, like NICs, have more
- * regular interrupts and see much better latency by staying in non-mmap
- * mode. We therefore set the default mmap_timeout such that a ping
- * is just enough to keep the mmap disabled. Users can experiment with
- * other options with the x-intx-mmap-timeout-ms parameter (a value of
- * zero disables the timer).
- */
-static void vfio_intx_mmap_enable(void *opaque)
-{
- VFIOPCIDevice *vdev = opaque;
-
- if (vdev->intx.pending) {
- timer_mod(vdev->intx.mmap_timer,
- qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + vdev->intx.mmap_timeout);
- return;
- }
-
- vfio_mmap_set_enabled(vdev, true);
-}
-
-static void vfio_intx_interrupt(void *opaque)
-{
- VFIOPCIDevice *vdev = opaque;
-
- if (!event_notifier_test_and_clear(&vdev->intx.interrupt)) {
- return;
- }
-
- trace_vfio_intx_interrupt(vdev->vbasedev.name, 'A' + vdev->intx.pin);
-
- vdev->intx.pending = true;
- pci_irq_assert(&vdev->pdev);
- vfio_mmap_set_enabled(vdev, false);
- if (vdev->intx.mmap_timeout) {
- timer_mod(vdev->intx.mmap_timer,
- qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + vdev->intx.mmap_timeout);
- }
-}
-
-static void vfio_intx_eoi(VFIODevice *vbasedev)
-{
- VFIOPCIDevice *vdev = container_of(vbasedev, VFIOPCIDevice, vbasedev);
-
- if (!vdev->intx.pending) {
- return;
- }
-
- trace_vfio_intx_eoi(vbasedev->name);
-
- vdev->intx.pending = false;
- pci_irq_deassert(&vdev->pdev);
- vfio_unmask_single_irqindex(vbasedev, VFIO_PCI_INTX_IRQ_INDEX);
-}
-
-static void vfio_intx_enable_kvm(VFIOPCIDevice *vdev)
-{
-#ifdef CONFIG_KVM
- struct kvm_irqfd irqfd = {
- .fd = event_notifier_get_fd(&vdev->intx.interrupt),
- .gsi = vdev->intx.route.irq,
- .flags = KVM_IRQFD_FLAG_RESAMPLE,
- };
- struct vfio_irq_set *irq_set;
- int ret, argsz;
- int32_t *pfd;
-
- if (vdev->no_kvm_intx || !kvm_irqfds_enabled() ||
- vdev->intx.route.mode != PCI_INTX_ENABLED ||
- !kvm_resamplefds_enabled()) {
- return;
- }
-
- /* Get to a known interrupt state */
- qemu_set_fd_handler(irqfd.fd, NULL, NULL, vdev);
- vfio_mask_single_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX);
- vdev->intx.pending = false;
- pci_irq_deassert(&vdev->pdev);
-
- /* Get an eventfd for resample/unmask */
- if (event_notifier_init(&vdev->intx.unmask, 0)) {
- error_report("vfio: Error: event_notifier_init failed eoi");
- goto fail;
- }
-
- /* KVM triggers it, VFIO listens for it */
- irqfd.resamplefd = event_notifier_get_fd(&vdev->intx.unmask);
-
- if (kvm_vm_ioctl(kvm_state, KVM_IRQFD, &irqfd)) {
- error_report("vfio: Error: Failed to setup resample irqfd: %m");
- goto fail_irqfd;
- }
-
- argsz = sizeof(*irq_set) + sizeof(*pfd);
-
- irq_set = g_malloc0(argsz);
- irq_set->argsz = argsz;
- irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_UNMASK;
- irq_set->index = VFIO_PCI_INTX_IRQ_INDEX;
- irq_set->start = 0;
- irq_set->count = 1;
- pfd = (int32_t *)&irq_set->data;
-
- *pfd = irqfd.resamplefd;
-
- ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set);
- g_free(irq_set);
- if (ret) {
- error_report("vfio: Error: Failed to setup INTx unmask fd: %m");
- goto fail_vfio;
- }
-
- /* Let'em rip */
- vfio_unmask_single_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX);
-
- vdev->intx.kvm_accel = true;
-
- trace_vfio_intx_enable_kvm(vdev->vbasedev.name);
-
- return;
-
-fail_vfio:
- irqfd.flags = KVM_IRQFD_FLAG_DEASSIGN;
- kvm_vm_ioctl(kvm_state, KVM_IRQFD, &irqfd);
-fail_irqfd:
- event_notifier_cleanup(&vdev->intx.unmask);
-fail:
- qemu_set_fd_handler(irqfd.fd, vfio_intx_interrupt, NULL, vdev);
- vfio_unmask_single_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX);
-#endif
-}
-
-static void vfio_intx_disable_kvm(VFIOPCIDevice *vdev)
-{
-#ifdef CONFIG_KVM
- struct kvm_irqfd irqfd = {
- .fd = event_notifier_get_fd(&vdev->intx.interrupt),
- .gsi = vdev->intx.route.irq,
- .flags = KVM_IRQFD_FLAG_DEASSIGN,
- };
-
- if (!vdev->intx.kvm_accel) {
- return;
- }
-
- /*
- * Get to a known state, hardware masked, QEMU ready to accept new
- * interrupts, QEMU IRQ de-asserted.
- */
- vfio_mask_single_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX);
- vdev->intx.pending = false;
- pci_irq_deassert(&vdev->pdev);
-
- /* Tell KVM to stop listening for an INTx irqfd */
- if (kvm_vm_ioctl(kvm_state, KVM_IRQFD, &irqfd)) {
- error_report("vfio: Error: Failed to disable INTx irqfd: %m");
- }
-
- /* We only need to close the eventfd for VFIO to cleanup the kernel side */
- event_notifier_cleanup(&vdev->intx.unmask);
-
- /* QEMU starts listening for interrupt events. */
- qemu_set_fd_handler(irqfd.fd, vfio_intx_interrupt, NULL, vdev);
-
- vdev->intx.kvm_accel = false;
-
- /* If we've missed an event, let it re-fire through QEMU */
- vfio_unmask_single_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX);
-
- trace_vfio_intx_disable_kvm(vdev->vbasedev.name);
-#endif
-}
-
-static void vfio_intx_update(PCIDevice *pdev)
-{
- VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
- PCIINTxRoute route;
-
- if (vdev->interrupt != VFIO_INT_INTx) {
- return;
- }
-
- route = pci_device_route_intx_to_irq(&vdev->pdev, vdev->intx.pin);
-
- if (!pci_intx_route_changed(&vdev->intx.route, &route)) {
- return; /* Nothing changed */
- }
-
- trace_vfio_intx_update(vdev->vbasedev.name,
- vdev->intx.route.irq, route.irq);
-
- vfio_intx_disable_kvm(vdev);
-
- vdev->intx.route = route;
-
- if (route.mode != PCI_INTX_ENABLED) {
- return;
- }
-
- vfio_intx_enable_kvm(vdev);
-
- /* Re-enable the interrupt in cased we missed an EOI */
- vfio_intx_eoi(&vdev->vbasedev);
-}
-
-static int vfio_intx_enable(VFIOPCIDevice *vdev)
-{
- uint8_t pin = vfio_pci_read_config(&vdev->pdev, PCI_INTERRUPT_PIN, 1);
- int ret, argsz;
- struct vfio_irq_set *irq_set;
- int32_t *pfd;
-
- if (!pin) {
- return 0;
- }
-
- vfio_disable_interrupts(vdev);
-
- vdev->intx.pin = pin - 1; /* Pin A (1) -> irq[0] */
- pci_config_set_interrupt_pin(vdev->pdev.config, pin);
-
-#ifdef CONFIG_KVM
- /*
- * Only conditional to avoid generating error messages on platforms
- * where we won't actually use the result anyway.
- */
- if (kvm_irqfds_enabled() && kvm_resamplefds_enabled()) {
- vdev->intx.route = pci_device_route_intx_to_irq(&vdev->pdev,
- vdev->intx.pin);
- }
-#endif
-
- ret = event_notifier_init(&vdev->intx.interrupt, 0);
- if (ret) {
- error_report("vfio: Error: event_notifier_init failed");
- return ret;
- }
-
- argsz = sizeof(*irq_set) + sizeof(*pfd);
-
- irq_set = g_malloc0(argsz);
- irq_set->argsz = argsz;
- irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
- irq_set->index = VFIO_PCI_INTX_IRQ_INDEX;
- irq_set->start = 0;
- irq_set->count = 1;
- pfd = (int32_t *)&irq_set->data;
-
- *pfd = event_notifier_get_fd(&vdev->intx.interrupt);
- qemu_set_fd_handler(*pfd, vfio_intx_interrupt, NULL, vdev);
-
- ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set);
- g_free(irq_set);
- if (ret) {
- error_report("vfio: Error: Failed to setup INTx fd: %m");
- qemu_set_fd_handler(*pfd, NULL, NULL, vdev);
- event_notifier_cleanup(&vdev->intx.interrupt);
- return -errno;
- }
-
- vfio_intx_enable_kvm(vdev);
-
- vdev->interrupt = VFIO_INT_INTx;
-
- trace_vfio_intx_enable(vdev->vbasedev.name);
-
- return 0;
-}
-
-static void vfio_intx_disable(VFIOPCIDevice *vdev)
-{
- int fd;
-
- timer_del(vdev->intx.mmap_timer);
- vfio_intx_disable_kvm(vdev);
- vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX);
- vdev->intx.pending = false;
- pci_irq_deassert(&vdev->pdev);
- vfio_mmap_set_enabled(vdev, true);
-
- fd = event_notifier_get_fd(&vdev->intx.interrupt);
- qemu_set_fd_handler(fd, NULL, NULL, vdev);
- event_notifier_cleanup(&vdev->intx.interrupt);
-
- vdev->interrupt = VFIO_INT_NONE;
-
- trace_vfio_intx_disable(vdev->vbasedev.name);
-}
-
-/*
- * MSI/X
- */
-static void vfio_msi_interrupt(void *opaque)
-{
- VFIOMSIVector *vector = opaque;
- VFIOPCIDevice *vdev = vector->vdev;
- MSIMessage (*get_msg)(PCIDevice *dev, unsigned vector);
- void (*notify)(PCIDevice *dev, unsigned vector);
- MSIMessage msg;
- int nr = vector - vdev->msi_vectors;
-
- if (!event_notifier_test_and_clear(&vector->interrupt)) {
- return;
- }
-
- if (vdev->interrupt == VFIO_INT_MSIX) {
- get_msg = msix_get_message;
- notify = msix_notify;
-
- /* A masked vector firing needs to use the PBA, enable it */
- if (msix_is_masked(&vdev->pdev, nr)) {
- set_bit(nr, vdev->msix->pending);
- memory_region_set_enabled(&vdev->pdev.msix_pba_mmio, true);
- trace_vfio_msix_pba_enable(vdev->vbasedev.name);
- }
- } else if (vdev->interrupt == VFIO_INT_MSI) {
- get_msg = msi_get_message;
- notify = msi_notify;
- } else {
- abort();
- }
-
- msg = get_msg(&vdev->pdev, nr);
- trace_vfio_msi_interrupt(vdev->vbasedev.name, nr, msg.address, msg.data);
- notify(&vdev->pdev, nr);
-}
-
-static int vfio_enable_vectors(VFIOPCIDevice *vdev, bool msix)
-{
- struct vfio_irq_set *irq_set;
- int ret = 0, i, argsz;
- int32_t *fds;
-
- argsz = sizeof(*irq_set) + (vdev->nr_vectors * sizeof(*fds));
-
- irq_set = g_malloc0(argsz);
- irq_set->argsz = argsz;
- irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
- irq_set->index = msix ? VFIO_PCI_MSIX_IRQ_INDEX : VFIO_PCI_MSI_IRQ_INDEX;
- irq_set->start = 0;
- irq_set->count = vdev->nr_vectors;
- fds = (int32_t *)&irq_set->data;
-
- for (i = 0; i < vdev->nr_vectors; i++) {
- int fd = -1;
-
- /*
- * MSI vs MSI-X - The guest has direct access to MSI mask and pending
- * bits, therefore we always use the KVM signaling path when setup.
- * MSI-X mask and pending bits are emulated, so we want to use the
- * KVM signaling path only when configured and unmasked.
- */
- if (vdev->msi_vectors[i].use) {
- if (vdev->msi_vectors[i].virq < 0 ||
- (msix && msix_is_masked(&vdev->pdev, i))) {
- fd = event_notifier_get_fd(&vdev->msi_vectors[i].interrupt);
- } else {
- fd = event_notifier_get_fd(&vdev->msi_vectors[i].kvm_interrupt);
- }
- }
-
- fds[i] = fd;
- }
-
- ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set);
-
- g_free(irq_set);
-
- return ret;
-}
-
-static void vfio_add_kvm_msi_virq(VFIOPCIDevice *vdev, VFIOMSIVector *vector,
- MSIMessage *msg, bool msix)
-{
- int virq;
-
- if ((msix && vdev->no_kvm_msix) || (!msix && vdev->no_kvm_msi) || !msg) {
- return;
- }
-
- if (event_notifier_init(&vector->kvm_interrupt, 0)) {
- return;
- }
-
- virq = kvm_irqchip_add_msi_route(kvm_state, *msg, &vdev->pdev);
- if (virq < 0) {
- event_notifier_cleanup(&vector->kvm_interrupt);
- return;
- }
-
- if (kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, &vector->kvm_interrupt,
- NULL, virq) < 0) {
- kvm_irqchip_release_virq(kvm_state, virq);
- event_notifier_cleanup(&vector->kvm_interrupt);
- return;
- }
-
- vector->virq = virq;
-}
-
-static void vfio_remove_kvm_msi_virq(VFIOMSIVector *vector)
-{
- kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, &vector->kvm_interrupt,
- vector->virq);
- kvm_irqchip_release_virq(kvm_state, vector->virq);
- vector->virq = -1;
- event_notifier_cleanup(&vector->kvm_interrupt);
-}
-
-static void vfio_update_kvm_msi_virq(VFIOMSIVector *vector, MSIMessage msg,
- PCIDevice *pdev)
-{
- kvm_irqchip_update_msi_route(kvm_state, vector->virq, msg, pdev);
-}
-
-static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr,
- MSIMessage *msg, IOHandler *handler)
-{
- VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
- VFIOMSIVector *vector;
- int ret;
-
- trace_vfio_msix_vector_do_use(vdev->vbasedev.name, nr);
-
- vector = &vdev->msi_vectors[nr];
-
- if (!vector->use) {
- vector->vdev = vdev;
- vector->virq = -1;
- if (event_notifier_init(&vector->interrupt, 0)) {
- error_report("vfio: Error: event_notifier_init failed");
- }
- vector->use = true;
- msix_vector_use(pdev, nr);
- }
-
- qemu_set_fd_handler(event_notifier_get_fd(&vector->interrupt),
- handler, NULL, vector);
-
- /*
- * Attempt to enable route through KVM irqchip,
- * default to userspace handling if unavailable.
- */
- if (vector->virq >= 0) {
- if (!msg) {
- vfio_remove_kvm_msi_virq(vector);
- } else {
- vfio_update_kvm_msi_virq(vector, *msg, pdev);
- }
- } else {
- vfio_add_kvm_msi_virq(vdev, vector, msg, true);
- }
-
- /*
- * We don't want to have the host allocate all possible MSI vectors
- * for a device if they're not in use, so we shutdown and incrementally
- * increase them as needed.
- */
- if (vdev->nr_vectors < nr + 1) {
- vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX);
- vdev->nr_vectors = nr + 1;
- ret = vfio_enable_vectors(vdev, true);
- if (ret) {
- error_report("vfio: failed to enable vectors, %d", ret);
- }
- } else {
- int argsz;
- struct vfio_irq_set *irq_set;
- int32_t *pfd;
-
- argsz = sizeof(*irq_set) + sizeof(*pfd);
-
- irq_set = g_malloc0(argsz);
- irq_set->argsz = argsz;
- irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
- VFIO_IRQ_SET_ACTION_TRIGGER;
- irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
- irq_set->start = nr;
- irq_set->count = 1;
- pfd = (int32_t *)&irq_set->data;
-
- if (vector->virq >= 0) {
- *pfd = event_notifier_get_fd(&vector->kvm_interrupt);
- } else {
- *pfd = event_notifier_get_fd(&vector->interrupt);
- }
-
- ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set);
- g_free(irq_set);
- if (ret) {
- error_report("vfio: failed to modify vector, %d", ret);
- }
- }
-
- /* Disable PBA emulation when nothing more is pending. */
- clear_bit(nr, vdev->msix->pending);
- if (find_first_bit(vdev->msix->pending,
- vdev->nr_vectors) == vdev->nr_vectors) {
- memory_region_set_enabled(&vdev->pdev.msix_pba_mmio, false);
- trace_vfio_msix_pba_disable(vdev->vbasedev.name);
- }
-
- return 0;
-}
-
-static int vfio_msix_vector_use(PCIDevice *pdev,
- unsigned int nr, MSIMessage msg)
-{
- return vfio_msix_vector_do_use(pdev, nr, &msg, vfio_msi_interrupt);
-}
-
-static void vfio_msix_vector_release(PCIDevice *pdev, unsigned int nr)
-{
- VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
- VFIOMSIVector *vector = &vdev->msi_vectors[nr];
-
- trace_vfio_msix_vector_release(vdev->vbasedev.name, nr);
-
- /*
- * There are still old guests that mask and unmask vectors on every
- * interrupt. If we're using QEMU bypass with a KVM irqfd, leave all of
- * the KVM setup in place, simply switch VFIO to use the non-bypass
- * eventfd. We'll then fire the interrupt through QEMU and the MSI-X
- * core will mask the interrupt and set pending bits, allowing it to
- * be re-asserted on unmask. Nothing to do if already using QEMU mode.
- */
- if (vector->virq >= 0) {
- int argsz;
- struct vfio_irq_set *irq_set;
- int32_t *pfd;
-
- argsz = sizeof(*irq_set) + sizeof(*pfd);
-
- irq_set = g_malloc0(argsz);
- irq_set->argsz = argsz;
- irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
- VFIO_IRQ_SET_ACTION_TRIGGER;
- irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
- irq_set->start = nr;
- irq_set->count = 1;
- pfd = (int32_t *)&irq_set->data;
-
- *pfd = event_notifier_get_fd(&vector->interrupt);
-
- ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set);
-
- g_free(irq_set);
- }
-}
-
-static void vfio_msix_enable(VFIOPCIDevice *vdev)
-{
- vfio_disable_interrupts(vdev);
-
- vdev->msi_vectors = g_new0(VFIOMSIVector, vdev->msix->entries);
-
- vdev->interrupt = VFIO_INT_MSIX;
-
- /*
- * Some communication channels between VF & PF or PF & fw rely on the
- * physical state of the device and expect that enabling MSI-X from the
- * guest enables the same on the host. When our guest is Linux, the
- * guest driver call to pci_enable_msix() sets the enabling bit in the
- * MSI-X capability, but leaves the vector table masked. We therefore
- * can't rely on a vector_use callback (from request_irq() in the guest)
- * to switch the physical device into MSI-X mode because that may come a
- * long time after pci_enable_msix(). This code enables vector 0 with
- * triggering to userspace, then immediately release the vector, leaving
- * the physical device with no vectors enabled, but MSI-X enabled, just
- * like the guest view.
- */
- vfio_msix_vector_do_use(&vdev->pdev, 0, NULL, NULL);
- vfio_msix_vector_release(&vdev->pdev, 0);
-
- if (msix_set_vector_notifiers(&vdev->pdev, vfio_msix_vector_use,
- vfio_msix_vector_release, NULL)) {
- error_report("vfio: msix_set_vector_notifiers failed");
- }
-
- trace_vfio_msix_enable(vdev->vbasedev.name);
-}
-
-static void vfio_msi_enable(VFIOPCIDevice *vdev)
-{
- int ret, i;
-
- vfio_disable_interrupts(vdev);
-
- vdev->nr_vectors = msi_nr_vectors_allocated(&vdev->pdev);
-retry:
- vdev->msi_vectors = g_new0(VFIOMSIVector, vdev->nr_vectors);
-
- for (i = 0; i < vdev->nr_vectors; i++) {
- VFIOMSIVector *vector = &vdev->msi_vectors[i];
- MSIMessage msg = msi_get_message(&vdev->pdev, i);
-
- vector->vdev = vdev;
- vector->virq = -1;
- vector->use = true;
-
- if (event_notifier_init(&vector->interrupt, 0)) {
- error_report("vfio: Error: event_notifier_init failed");
- }
-
- qemu_set_fd_handler(event_notifier_get_fd(&vector->interrupt),
- vfio_msi_interrupt, NULL, vector);
-
- /*
- * Attempt to enable route through KVM irqchip,
- * default to userspace handling if unavailable.
- */
- vfio_add_kvm_msi_virq(vdev, vector, &msg, false);
- }
-
- /* Set interrupt type prior to possible interrupts */
- vdev->interrupt = VFIO_INT_MSI;
-
- ret = vfio_enable_vectors(vdev, false);
- if (ret) {
- if (ret < 0) {
- error_report("vfio: Error: Failed to setup MSI fds: %m");
- } else if (ret != vdev->nr_vectors) {
- error_report("vfio: Error: Failed to enable %d "
- "MSI vectors, retry with %d", vdev->nr_vectors, ret);
- }
-
- for (i = 0; i < vdev->nr_vectors; i++) {
- VFIOMSIVector *vector = &vdev->msi_vectors[i];
- if (vector->virq >= 0) {
- vfio_remove_kvm_msi_virq(vector);
- }
- qemu_set_fd_handler(event_notifier_get_fd(&vector->interrupt),
- NULL, NULL, NULL);
- event_notifier_cleanup(&vector->interrupt);
- }
-
- g_free(vdev->msi_vectors);
-
- if (ret > 0 && ret != vdev->nr_vectors) {
- vdev->nr_vectors = ret;
- goto retry;
- }
- vdev->nr_vectors = 0;
-
- /*
- * Failing to setup MSI doesn't really fall within any specification.
- * Let's try leaving interrupts disabled and hope the guest figures
- * out to fall back to INTx for this device.
- */
- error_report("vfio: Error: Failed to enable MSI");
- vdev->interrupt = VFIO_INT_NONE;
-
- return;
- }
-
- trace_vfio_msi_enable(vdev->vbasedev.name, vdev->nr_vectors);
-}
-
-static void vfio_msi_disable_common(VFIOPCIDevice *vdev)
-{
- int i;
-
- for (i = 0; i < vdev->nr_vectors; i++) {
- VFIOMSIVector *vector = &vdev->msi_vectors[i];
- if (vdev->msi_vectors[i].use) {
- if (vector->virq >= 0) {
- vfio_remove_kvm_msi_virq(vector);
- }
- qemu_set_fd_handler(event_notifier_get_fd(&vector->interrupt),
- NULL, NULL, NULL);
- event_notifier_cleanup(&vector->interrupt);
- }
- }
-
- g_free(vdev->msi_vectors);
- vdev->msi_vectors = NULL;
- vdev->nr_vectors = 0;
- vdev->interrupt = VFIO_INT_NONE;
-
- vfio_intx_enable(vdev);
-}
-
-static void vfio_msix_disable(VFIOPCIDevice *vdev)
-{
- int i;
-
- msix_unset_vector_notifiers(&vdev->pdev);
-
- /*
- * MSI-X will only release vectors if MSI-X is still enabled on the
- * device, check through the rest and release it ourselves if necessary.
- */
- for (i = 0; i < vdev->nr_vectors; i++) {
- if (vdev->msi_vectors[i].use) {
- vfio_msix_vector_release(&vdev->pdev, i);
- msix_vector_unuse(&vdev->pdev, i);
- }
- }
-
- if (vdev->nr_vectors) {
- vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX);
- }
-
- vfio_msi_disable_common(vdev);
-
- memset(vdev->msix->pending, 0,
- BITS_TO_LONGS(vdev->msix->entries) * sizeof(unsigned long));
-
- trace_vfio_msix_disable(vdev->vbasedev.name);
-}
-
-static void vfio_msi_disable(VFIOPCIDevice *vdev)
-{
- vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_MSI_IRQ_INDEX);
- vfio_msi_disable_common(vdev);
-
- trace_vfio_msi_disable(vdev->vbasedev.name);
-}
-
-static void vfio_update_msi(VFIOPCIDevice *vdev)
-{
- int i;
-
- for (i = 0; i < vdev->nr_vectors; i++) {
- VFIOMSIVector *vector = &vdev->msi_vectors[i];
- MSIMessage msg;
-
- if (!vector->use || vector->virq < 0) {
- continue;
- }
-
- msg = msi_get_message(&vdev->pdev, i);
- vfio_update_kvm_msi_virq(vector, msg, &vdev->pdev);
- }
-}
-
-static void vfio_pci_load_rom(VFIOPCIDevice *vdev)
-{
- struct vfio_region_info *reg_info;
- uint64_t size;
- off_t off = 0;
- ssize_t bytes;
-
- if (vfio_get_region_info(&vdev->vbasedev,
- VFIO_PCI_ROM_REGION_INDEX, &reg_info)) {
- error_report("vfio: Error getting ROM info: %m");
- return;
- }
-
- trace_vfio_pci_load_rom(vdev->vbasedev.name, (unsigned long)reg_info->size,
- (unsigned long)reg_info->offset,
- (unsigned long)reg_info->flags);
-
- vdev->rom_size = size = reg_info->size;
- vdev->rom_offset = reg_info->offset;
-
- g_free(reg_info);
-
- if (!vdev->rom_size) {
- vdev->rom_read_failed = true;
- error_report("vfio-pci: Cannot read device rom at "
- "%s", vdev->vbasedev.name);
- error_printf("Device option ROM contents are probably invalid "
- "(check dmesg).\nSkip option ROM probe with rombar=0, "
- "or load from file with romfile=\n");
- return;
- }
-
- vdev->rom = g_malloc(size);
- memset(vdev->rom, 0xff, size);
-
- while (size) {
- bytes = pread(vdev->vbasedev.fd, vdev->rom + off,
- size, vdev->rom_offset + off);
- if (bytes == 0) {
- break;
- } else if (bytes > 0) {
- off += bytes;
- size -= bytes;
- } else {
- if (errno == EINTR || errno == EAGAIN) {
- continue;
- }
- error_report("vfio: Error reading device ROM: %m");
- break;
- }
- }
-
- /*
- * Test the ROM signature against our device, if the vendor is correct
- * but the device ID doesn't match, store the correct device ID and
- * recompute the checksum. Intel IGD devices need this and are known
- * to have bogus checksums so we can't simply adjust the checksum.
- */
- if (pci_get_word(vdev->rom) == 0xaa55 &&
- pci_get_word(vdev->rom + 0x18) + 8 < vdev->rom_size &&
- !memcmp(vdev->rom + pci_get_word(vdev->rom + 0x18), "PCIR", 4)) {
- uint16_t vid, did;
-
- vid = pci_get_word(vdev->rom + pci_get_word(vdev->rom + 0x18) + 4);
- did = pci_get_word(vdev->rom + pci_get_word(vdev->rom + 0x18) + 6);
-
- if (vid == vdev->vendor_id && did != vdev->device_id) {
- int i;
- uint8_t csum, *data = vdev->rom;
-
- pci_set_word(vdev->rom + pci_get_word(vdev->rom + 0x18) + 6,
- vdev->device_id);
- data[6] = 0;
-
- for (csum = 0, i = 0; i < vdev->rom_size; i++) {
- csum += data[i];
- }
-
- data[6] = -csum;
- }
- }
-}
-
-static uint64_t vfio_rom_read(void *opaque, hwaddr addr, unsigned size)
-{
- VFIOPCIDevice *vdev = opaque;
- union {
- uint8_t byte;
- uint16_t word;
- uint32_t dword;
- uint64_t qword;
- } val;
- uint64_t data = 0;
-
- /* Load the ROM lazily when the guest tries to read it */
- if (unlikely(!vdev->rom && !vdev->rom_read_failed)) {
- vfio_pci_load_rom(vdev);
- }
-
- memcpy(&val, vdev->rom + addr,
- (addr < vdev->rom_size) ? MIN(size, vdev->rom_size - addr) : 0);
-
- switch (size) {
- case 1:
- data = val.byte;
- break;
- case 2:
- data = le16_to_cpu(val.word);
- break;
- case 4:
- data = le32_to_cpu(val.dword);
- break;
- default:
- hw_error("vfio: unsupported read size, %d bytes\n", size);
- break;
- }
-
- trace_vfio_rom_read(vdev->vbasedev.name, addr, size, data);
-
- return data;
-}
-
-static void vfio_rom_write(void *opaque, hwaddr addr,
- uint64_t data, unsigned size)
-{
-}
-
-static const MemoryRegionOps vfio_rom_ops = {
- .read = vfio_rom_read,
- .write = vfio_rom_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void vfio_pci_size_rom(VFIOPCIDevice *vdev)
-{
- uint32_t orig, size = cpu_to_le32((uint32_t)PCI_ROM_ADDRESS_MASK);
- off_t offset = vdev->config_offset + PCI_ROM_ADDRESS;
- DeviceState *dev = DEVICE(vdev);
- char *name;
- int fd = vdev->vbasedev.fd;
-
- if (vdev->pdev.romfile || !vdev->pdev.rom_bar) {
- /* Since pci handles romfile, just print a message and return */
- if (vfio_blacklist_opt_rom(vdev) && vdev->pdev.romfile) {
- error_printf("Warning : Device at %s is known to cause system instability issues during option rom execution. Proceeding anyway since user specified romfile\n",
- vdev->vbasedev.name);
- }
- return;
- }
-
- /*
- * Use the same size ROM BAR as the physical device. The contents
- * will get filled in later when the guest tries to read it.
- */
- if (pread(fd, &orig, 4, offset) != 4 ||
- pwrite(fd, &size, 4, offset) != 4 ||
- pread(fd, &size, 4, offset) != 4 ||
- pwrite(fd, &orig, 4, offset) != 4) {
- error_report("%s(%s) failed: %m", __func__, vdev->vbasedev.name);
- return;
- }
-
- size = ~(le32_to_cpu(size) & PCI_ROM_ADDRESS_MASK) + 1;
-
- if (!size) {
- return;
- }
-
- if (vfio_blacklist_opt_rom(vdev)) {
- if (dev->opts && qemu_opt_get(dev->opts, "rombar")) {
- error_printf("Warning : Device at %s is known to cause system instability issues during option rom execution. Proceeding anyway since user specified non zero value for rombar\n",
- vdev->vbasedev.name);
- } else {
- error_printf("Warning : Rom loading for device at %s has been disabled due to system instability issues. Specify rombar=1 or romfile to force\n",
- vdev->vbasedev.name);
- return;
- }
- }
-
- trace_vfio_pci_size_rom(vdev->vbasedev.name, size);
-
- name = g_strdup_printf("vfio[%s].rom", vdev->vbasedev.name);
-
- memory_region_init_io(&vdev->pdev.rom, OBJECT(vdev),
- &vfio_rom_ops, vdev, name, size);
- g_free(name);
-
- pci_register_bar(&vdev->pdev, PCI_ROM_SLOT,
- PCI_BASE_ADDRESS_SPACE_MEMORY, &vdev->pdev.rom);
-
- vdev->pdev.has_rom = true;
- vdev->rom_read_failed = false;
-}
-
-void vfio_vga_write(void *opaque, hwaddr addr,
- uint64_t data, unsigned size)
-{
- VFIOVGARegion *region = opaque;
- VFIOVGA *vga = container_of(region, VFIOVGA, region[region->nr]);
- union {
- uint8_t byte;
- uint16_t word;
- uint32_t dword;
- uint64_t qword;
- } buf;
- off_t offset = vga->fd_offset + region->offset + addr;
-
- switch (size) {
- case 1:
- buf.byte = data;
- break;
- case 2:
- buf.word = cpu_to_le16(data);
- break;
- case 4:
- buf.dword = cpu_to_le32(data);
- break;
- default:
- hw_error("vfio: unsupported write size, %d bytes", size);
- break;
- }
-
- if (pwrite(vga->fd, &buf, size, offset) != size) {
- error_report("%s(,0x%"HWADDR_PRIx", 0x%"PRIx64", %d) failed: %m",
- __func__, region->offset + addr, data, size);
- }
-
- trace_vfio_vga_write(region->offset + addr, data, size);
-}
-
-uint64_t vfio_vga_read(void *opaque, hwaddr addr, unsigned size)
-{
- VFIOVGARegion *region = opaque;
- VFIOVGA *vga = container_of(region, VFIOVGA, region[region->nr]);
- union {
- uint8_t byte;
- uint16_t word;
- uint32_t dword;
- uint64_t qword;
- } buf;
- uint64_t data = 0;
- off_t offset = vga->fd_offset + region->offset + addr;
-
- if (pread(vga->fd, &buf, size, offset) != size) {
- error_report("%s(,0x%"HWADDR_PRIx", %d) failed: %m",
- __func__, region->offset + addr, size);
- return (uint64_t)-1;
- }
-
- switch (size) {
- case 1:
- data = buf.byte;
- break;
- case 2:
- data = le16_to_cpu(buf.word);
- break;
- case 4:
- data = le32_to_cpu(buf.dword);
- break;
- default:
- hw_error("vfio: unsupported read size, %d bytes", size);
- break;
- }
-
- trace_vfio_vga_read(region->offset + addr, size, data);
-
- return data;
-}
-
-static const MemoryRegionOps vfio_vga_ops = {
- .read = vfio_vga_read,
- .write = vfio_vga_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-/*
- * PCI config space
- */
-uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len)
-{
- VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
- uint32_t emu_bits = 0, emu_val = 0, phys_val = 0, val;
-
- memcpy(&emu_bits, vdev->emulated_config_bits + addr, len);
- emu_bits = le32_to_cpu(emu_bits);
-
- if (emu_bits) {
- emu_val = pci_default_read_config(pdev, addr, len);
- }
-
- if (~emu_bits & (0xffffffffU >> (32 - len * 8))) {
- ssize_t ret;
-
- ret = pread(vdev->vbasedev.fd, &phys_val, len,
- vdev->config_offset + addr);
- if (ret != len) {
- error_report("%s(%s, 0x%x, 0x%x) failed: %m",
- __func__, vdev->vbasedev.name, addr, len);
- return -errno;
- }
- phys_val = le32_to_cpu(phys_val);
- }
-
- val = (emu_val & emu_bits) | (phys_val & ~emu_bits);
-
- trace_vfio_pci_read_config(vdev->vbasedev.name, addr, len, val);
-
- return val;
-}
-
-void vfio_pci_write_config(PCIDevice *pdev,
- uint32_t addr, uint32_t val, int len)
-{
- VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
- uint32_t val_le = cpu_to_le32(val);
-
- trace_vfio_pci_write_config(vdev->vbasedev.name, addr, val, len);
-
- /* Write everything to VFIO, let it filter out what we can't write */
- if (pwrite(vdev->vbasedev.fd, &val_le, len, vdev->config_offset + addr)
- != len) {
- error_report("%s(%s, 0x%x, 0x%x, 0x%x) failed: %m",
- __func__, vdev->vbasedev.name, addr, val, len);
- }
-
- /* MSI/MSI-X Enabling/Disabling */
- if (pdev->cap_present & QEMU_PCI_CAP_MSI &&
- ranges_overlap(addr, len, pdev->msi_cap, vdev->msi_cap_size)) {
- int is_enabled, was_enabled = msi_enabled(pdev);
-
- pci_default_write_config(pdev, addr, val, len);
-
- is_enabled = msi_enabled(pdev);
-
- if (!was_enabled) {
- if (is_enabled) {
- vfio_msi_enable(vdev);
- }
- } else {
- if (!is_enabled) {
- vfio_msi_disable(vdev);
- } else {
- vfio_update_msi(vdev);
- }
- }
- } else if (pdev->cap_present & QEMU_PCI_CAP_MSIX &&
- ranges_overlap(addr, len, pdev->msix_cap, MSIX_CAP_LENGTH)) {
- int is_enabled, was_enabled = msix_enabled(pdev);
-
- pci_default_write_config(pdev, addr, val, len);
-
- is_enabled = msix_enabled(pdev);
-
- if (!was_enabled && is_enabled) {
- vfio_msix_enable(vdev);
- } else if (was_enabled && !is_enabled) {
- vfio_msix_disable(vdev);
- }
- } else {
- /* Write everything to QEMU to keep emulated bits correct */
- pci_default_write_config(pdev, addr, val, len);
- }
-}
-
-/*
- * Interrupt setup
- */
-static void vfio_disable_interrupts(VFIOPCIDevice *vdev)
-{
- /*
- * More complicated than it looks. Disabling MSI/X transitions the
- * device to INTx mode (if supported). Therefore we need to first
- * disable MSI/X and then cleanup by disabling INTx.
- */
- if (vdev->interrupt == VFIO_INT_MSIX) {
- vfio_msix_disable(vdev);
- } else if (vdev->interrupt == VFIO_INT_MSI) {
- vfio_msi_disable(vdev);
- }
-
- if (vdev->interrupt == VFIO_INT_INTx) {
- vfio_intx_disable(vdev);
- }
-}
-
-static int vfio_msi_setup(VFIOPCIDevice *vdev, int pos)
-{
- uint16_t ctrl;
- bool msi_64bit, msi_maskbit;
- int ret, entries;
-
- if (pread(vdev->vbasedev.fd, &ctrl, sizeof(ctrl),
- vdev->config_offset + pos + PCI_CAP_FLAGS) != sizeof(ctrl)) {
- return -errno;
- }
- ctrl = le16_to_cpu(ctrl);
-
- msi_64bit = !!(ctrl & PCI_MSI_FLAGS_64BIT);
- msi_maskbit = !!(ctrl & PCI_MSI_FLAGS_MASKBIT);
- entries = 1 << ((ctrl & PCI_MSI_FLAGS_QMASK) >> 1);
-
- trace_vfio_msi_setup(vdev->vbasedev.name, pos);
-
- ret = msi_init(&vdev->pdev, pos, entries, msi_64bit, msi_maskbit);
- if (ret < 0) {
- if (ret == -ENOTSUP) {
- return 0;
- }
- error_report("vfio: msi_init failed");
- return ret;
- }
- vdev->msi_cap_size = 0xa + (msi_maskbit ? 0xa : 0) + (msi_64bit ? 0x4 : 0);
-
- return 0;
-}
-
-static void vfio_pci_fixup_msix_region(VFIOPCIDevice *vdev)
-{
- off_t start, end;
- VFIORegion *region = &vdev->bars[vdev->msix->table_bar].region;
-
- /*
- * We expect to find a single mmap covering the whole BAR, anything else
- * means it's either unsupported or already setup.
- */
- if (region->nr_mmaps != 1 || region->mmaps[0].offset ||
- region->size != region->mmaps[0].size) {
- return;
- }
-
- /* MSI-X table start and end aligned to host page size */
- start = vdev->msix->table_offset & qemu_real_host_page_mask;
- end = REAL_HOST_PAGE_ALIGN((uint64_t)vdev->msix->table_offset +
- (vdev->msix->entries * PCI_MSIX_ENTRY_SIZE));
-
- /*
- * Does the MSI-X table cover the beginning of the BAR? The whole BAR?
- * NB - Host page size is necessarily a power of two and so is the PCI
- * BAR (not counting EA yet), therefore if we have host page aligned
- * @start and @end, then any remainder of the BAR before or after those
- * must be at least host page sized and therefore mmap'able.
- */
- if (!start) {
- if (end >= region->size) {
- region->nr_mmaps = 0;
- g_free(region->mmaps);
- region->mmaps = NULL;
- trace_vfio_msix_fixup(vdev->vbasedev.name,
- vdev->msix->table_bar, 0, 0);
- } else {
- region->mmaps[0].offset = end;
- region->mmaps[0].size = region->size - end;
- trace_vfio_msix_fixup(vdev->vbasedev.name,
- vdev->msix->table_bar, region->mmaps[0].offset,
- region->mmaps[0].offset + region->mmaps[0].size);
- }
-
- /* Maybe it's aligned at the end of the BAR */
- } else if (end >= region->size) {
- region->mmaps[0].size = start;
- trace_vfio_msix_fixup(vdev->vbasedev.name,
- vdev->msix->table_bar, region->mmaps[0].offset,
- region->mmaps[0].offset + region->mmaps[0].size);
-
- /* Otherwise it must split the BAR */
- } else {
- region->nr_mmaps = 2;
- region->mmaps = g_renew(VFIOMmap, region->mmaps, 2);
-
- memcpy(&region->mmaps[1], &region->mmaps[0], sizeof(VFIOMmap));
-
- region->mmaps[0].size = start;
- trace_vfio_msix_fixup(vdev->vbasedev.name,
- vdev->msix->table_bar, region->mmaps[0].offset,
- region->mmaps[0].offset + region->mmaps[0].size);
-
- region->mmaps[1].offset = end;
- region->mmaps[1].size = region->size - end;
- trace_vfio_msix_fixup(vdev->vbasedev.name,
- vdev->msix->table_bar, region->mmaps[1].offset,
- region->mmaps[1].offset + region->mmaps[1].size);
- }
-}
-
-/*
- * We don't have any control over how pci_add_capability() inserts
- * capabilities into the chain. In order to setup MSI-X we need a
- * MemoryRegion for the BAR. In order to setup the BAR and not
- * attempt to mmap the MSI-X table area, which VFIO won't allow, we
- * need to first look for where the MSI-X table lives. So we
- * unfortunately split MSI-X setup across two functions.
- */
-static int vfio_msix_early_setup(VFIOPCIDevice *vdev)
-{
- uint8_t pos;
- uint16_t ctrl;
- uint32_t table, pba;
- int fd = vdev->vbasedev.fd;
- VFIOMSIXInfo *msix;
-
- pos = pci_find_capability(&vdev->pdev, PCI_CAP_ID_MSIX);
- if (!pos) {
- return 0;
- }
-
- if (pread(fd, &ctrl, sizeof(ctrl),
- vdev->config_offset + pos + PCI_MSIX_FLAGS) != sizeof(ctrl)) {
- return -errno;
- }
-
- if (pread(fd, &table, sizeof(table),
- vdev->config_offset + pos + PCI_MSIX_TABLE) != sizeof(table)) {
- return -errno;
- }
-
- if (pread(fd, &pba, sizeof(pba),
- vdev->config_offset + pos + PCI_MSIX_PBA) != sizeof(pba)) {
- return -errno;
- }
-
- ctrl = le16_to_cpu(ctrl);
- table = le32_to_cpu(table);
- pba = le32_to_cpu(pba);
-
- msix = g_malloc0(sizeof(*msix));
- msix->table_bar = table & PCI_MSIX_FLAGS_BIRMASK;
- msix->table_offset = table & ~PCI_MSIX_FLAGS_BIRMASK;
- msix->pba_bar = pba & PCI_MSIX_FLAGS_BIRMASK;
- msix->pba_offset = pba & ~PCI_MSIX_FLAGS_BIRMASK;
- msix->entries = (ctrl & PCI_MSIX_FLAGS_QSIZE) + 1;
-
- /*
- * Test the size of the pba_offset variable and catch if it extends outside
- * of the specified BAR. If it is the case, we need to apply a hardware
- * specific quirk if the device is known or we have a broken configuration.
- */
- if (msix->pba_offset >= vdev->bars[msix->pba_bar].region.size) {
- /*
- * Chelsio T5 Virtual Function devices are encoded as 0x58xx for T5
- * adapters. The T5 hardware returns an incorrect value of 0x8000 for
- * the VF PBA offset while the BAR itself is only 8k. The correct value
- * is 0x1000, so we hard code that here.
- */
- if (vdev->vendor_id == PCI_VENDOR_ID_CHELSIO &&
- (vdev->device_id & 0xff00) == 0x5800) {
- msix->pba_offset = 0x1000;
- } else {
- error_report("vfio: Hardware reports invalid configuration, "
- "MSIX PBA outside of specified BAR");
- g_free(msix);
- return -EINVAL;
- }
- }
-
- trace_vfio_msix_early_setup(vdev->vbasedev.name, pos, msix->table_bar,
- msix->table_offset, msix->entries);
- vdev->msix = msix;
-
- vfio_pci_fixup_msix_region(vdev);
-
- return 0;
-}
-
-static int vfio_msix_setup(VFIOPCIDevice *vdev, int pos)
-{
- int ret;
-
- vdev->msix->pending = g_malloc0(BITS_TO_LONGS(vdev->msix->entries) *
- sizeof(unsigned long));
- ret = msix_init(&vdev->pdev, vdev->msix->entries,
- vdev->bars[vdev->msix->table_bar].region.mem,
- vdev->msix->table_bar, vdev->msix->table_offset,
- vdev->bars[vdev->msix->pba_bar].region.mem,
- vdev->msix->pba_bar, vdev->msix->pba_offset, pos);
- if (ret < 0) {
- if (ret == -ENOTSUP) {
- return 0;
- }
- error_report("vfio: msix_init failed");
- return ret;
- }
-
- /*
- * The PCI spec suggests that devices provide additional alignment for
- * MSI-X structures and avoid overlapping non-MSI-X related registers.
- * For an assigned device, this hopefully means that emulation of MSI-X
- * structures does not affect the performance of the device. If devices
- * fail to provide that alignment, a significant performance penalty may
- * result, for instance Mellanox MT27500 VFs:
- * http://www.spinics.net/lists/kvm/msg125881.html
- *
- * The PBA is simply not that important for such a serious regression and
- * most drivers do not appear to look at it. The solution for this is to
- * disable the PBA MemoryRegion unless it's being used. We disable it
- * here and only enable it if a masked vector fires through QEMU. As the
- * vector-use notifier is called, which occurs on unmask, we test whether
- * PBA emulation is needed and again disable if not.
- */
- memory_region_set_enabled(&vdev->pdev.msix_pba_mmio, false);
-
- return 0;
-}
-
-static void vfio_teardown_msi(VFIOPCIDevice *vdev)
-{
- msi_uninit(&vdev->pdev);
-
- if (vdev->msix) {
- msix_uninit(&vdev->pdev,
- vdev->bars[vdev->msix->table_bar].region.mem,
- vdev->bars[vdev->msix->pba_bar].region.mem);
- g_free(vdev->msix->pending);
- }
-}
-
-/*
- * Resource setup
- */
-static void vfio_mmap_set_enabled(VFIOPCIDevice *vdev, bool enabled)
-{
- int i;
-
- for (i = 0; i < PCI_ROM_SLOT; i++) {
- vfio_region_mmaps_set_enabled(&vdev->bars[i].region, enabled);
- }
-}
-
-static void vfio_bar_setup(VFIOPCIDevice *vdev, int nr)
-{
- VFIOBAR *bar = &vdev->bars[nr];
-
- uint32_t pci_bar;
- uint8_t type;
- int ret;
-
- /* Skip both unimplemented BARs and the upper half of 64bit BARS. */
- if (!bar->region.size) {
- return;
- }
-
- /* Determine what type of BAR this is for registration */
- ret = pread(vdev->vbasedev.fd, &pci_bar, sizeof(pci_bar),
- vdev->config_offset + PCI_BASE_ADDRESS_0 + (4 * nr));
- if (ret != sizeof(pci_bar)) {
- error_report("vfio: Failed to read BAR %d (%m)", nr);
- return;
- }
-
- pci_bar = le32_to_cpu(pci_bar);
- bar->ioport = (pci_bar & PCI_BASE_ADDRESS_SPACE_IO);
- bar->mem64 = bar->ioport ? 0 : (pci_bar & PCI_BASE_ADDRESS_MEM_TYPE_64);
- type = pci_bar & (bar->ioport ? ~PCI_BASE_ADDRESS_IO_MASK :
- ~PCI_BASE_ADDRESS_MEM_MASK);
-
- if (vfio_region_mmap(&bar->region)) {
- error_report("Failed to mmap %s BAR %d. Performance may be slow",
- vdev->vbasedev.name, nr);
- }
-
- vfio_bar_quirk_setup(vdev, nr);
-
- pci_register_bar(&vdev->pdev, nr, type, bar->region.mem);
-}
-
-static void vfio_bars_setup(VFIOPCIDevice *vdev)
-{
- int i;
-
- for (i = 0; i < PCI_ROM_SLOT; i++) {
- vfio_bar_setup(vdev, i);
- }
-
- if (vdev->vga) {
- memory_region_init_io(&vdev->vga->region[QEMU_PCI_VGA_MEM].mem,
- OBJECT(vdev), &vfio_vga_ops,
- &vdev->vga->region[QEMU_PCI_VGA_MEM],
- "vfio-vga-mmio@0xa0000",
- QEMU_PCI_VGA_MEM_SIZE);
- memory_region_init_io(&vdev->vga->region[QEMU_PCI_VGA_IO_LO].mem,
- OBJECT(vdev), &vfio_vga_ops,
- &vdev->vga->region[QEMU_PCI_VGA_IO_LO],
- "vfio-vga-io@0x3b0",
- QEMU_PCI_VGA_IO_LO_SIZE);
- memory_region_init_io(&vdev->vga->region[QEMU_PCI_VGA_IO_HI].mem,
- OBJECT(vdev), &vfio_vga_ops,
- &vdev->vga->region[QEMU_PCI_VGA_IO_HI],
- "vfio-vga-io@0x3c0",
- QEMU_PCI_VGA_IO_HI_SIZE);
-
- pci_register_vga(&vdev->pdev, &vdev->vga->region[QEMU_PCI_VGA_MEM].mem,
- &vdev->vga->region[QEMU_PCI_VGA_IO_LO].mem,
- &vdev->vga->region[QEMU_PCI_VGA_IO_HI].mem);
- vfio_vga_quirk_setup(vdev);
- }
-}
-
-static void vfio_bars_exit(VFIOPCIDevice *vdev)
-{
- int i;
-
- for (i = 0; i < PCI_ROM_SLOT; i++) {
- vfio_bar_quirk_exit(vdev, i);
- vfio_region_exit(&vdev->bars[i].region);
- }
-
- if (vdev->vga) {
- pci_unregister_vga(&vdev->pdev);
- vfio_vga_quirk_exit(vdev);
- }
-}
-
-static void vfio_bars_finalize(VFIOPCIDevice *vdev)
-{
- int i;
-
- for (i = 0; i < PCI_ROM_SLOT; i++) {
- vfio_bar_quirk_finalize(vdev, i);
- vfio_region_finalize(&vdev->bars[i].region);
- }
-
- if (vdev->vga) {
- vfio_vga_quirk_finalize(vdev);
- for (i = 0; i < ARRAY_SIZE(vdev->vga->region); i++) {
- object_unparent(OBJECT(&vdev->vga->region[i].mem));
- }
- g_free(vdev->vga);
- }
-}
-
-/*
- * General setup
- */
-static uint8_t vfio_std_cap_max_size(PCIDevice *pdev, uint8_t pos)
-{
- uint8_t tmp;
- uint16_t next = PCI_CONFIG_SPACE_SIZE;
-
- for (tmp = pdev->config[PCI_CAPABILITY_LIST]; tmp;
- tmp = pdev->config[tmp + PCI_CAP_LIST_NEXT]) {
- if (tmp > pos && tmp < next) {
- next = tmp;
- }
- }
-
- return next - pos;
-}
-
-static void vfio_set_word_bits(uint8_t *buf, uint16_t val, uint16_t mask)
-{
- pci_set_word(buf, (pci_get_word(buf) & ~mask) | val);
-}
-
-static void vfio_add_emulated_word(VFIOPCIDevice *vdev, int pos,
- uint16_t val, uint16_t mask)
-{
- vfio_set_word_bits(vdev->pdev.config + pos, val, mask);
- vfio_set_word_bits(vdev->pdev.wmask + pos, ~mask, mask);
- vfio_set_word_bits(vdev->emulated_config_bits + pos, mask, mask);
-}
-
-static void vfio_set_long_bits(uint8_t *buf, uint32_t val, uint32_t mask)
-{
- pci_set_long(buf, (pci_get_long(buf) & ~mask) | val);
-}
-
-static void vfio_add_emulated_long(VFIOPCIDevice *vdev, int pos,
- uint32_t val, uint32_t mask)
-{
- vfio_set_long_bits(vdev->pdev.config + pos, val, mask);
- vfio_set_long_bits(vdev->pdev.wmask + pos, ~mask, mask);
- vfio_set_long_bits(vdev->emulated_config_bits + pos, mask, mask);
-}
-
-static int vfio_setup_pcie_cap(VFIOPCIDevice *vdev, int pos, uint8_t size)
-{
- uint16_t flags;
- uint8_t type;
-
- flags = pci_get_word(vdev->pdev.config + pos + PCI_CAP_FLAGS);
- type = (flags & PCI_EXP_FLAGS_TYPE) >> 4;
-
- if (type != PCI_EXP_TYPE_ENDPOINT &&
- type != PCI_EXP_TYPE_LEG_END &&
- type != PCI_EXP_TYPE_RC_END) {
-
- error_report("vfio: Assignment of PCIe type 0x%x "
- "devices is not currently supported", type);
- return -EINVAL;
- }
-
- if (!pci_bus_is_express(vdev->pdev.bus)) {
- PCIBus *bus = vdev->pdev.bus;
- PCIDevice *bridge;
-
- /*
- * Traditionally PCI device assignment exposes the PCIe capability
- * as-is on non-express buses. The reason being that some drivers
- * simply assume that it's there, for example tg3. However when
- * we're running on a native PCIe machine type, like Q35, we need
- * to hide the PCIe capability. The reason for this is twofold;
- * first Windows guests get a Code 10 error when the PCIe capability
- * is exposed in this configuration. Therefore express devices won't
- * work at all unless they're attached to express buses in the VM.
- * Second, a native PCIe machine introduces the possibility of fine
- * granularity IOMMUs supporting both translation and isolation.
- * Guest code to discover the IOMMU visibility of a device, such as
- * IOMMU grouping code on Linux, is very aware of device types and
- * valid transitions between bus types. An express device on a non-
- * express bus is not a valid combination on bare metal systems.
- *
- * Drivers that require a PCIe capability to make the device
- * functional are simply going to need to have their devices placed
- * on a PCIe bus in the VM.
- */
- while (!pci_bus_is_root(bus)) {
- bridge = pci_bridge_get_device(bus);
- bus = bridge->bus;
- }
-
- if (pci_bus_is_express(bus)) {
- return 0;
- }
-
- } else if (pci_bus_is_root(vdev->pdev.bus)) {
- /*
- * On a Root Complex bus Endpoints become Root Complex Integrated
- * Endpoints, which changes the type and clears the LNK & LNK2 fields.
- */
- if (type == PCI_EXP_TYPE_ENDPOINT) {
- vfio_add_emulated_word(vdev, pos + PCI_CAP_FLAGS,
- PCI_EXP_TYPE_RC_END << 4,
- PCI_EXP_FLAGS_TYPE);
-
- /* Link Capabilities, Status, and Control goes away */
- if (size > PCI_EXP_LNKCTL) {
- vfio_add_emulated_long(vdev, pos + PCI_EXP_LNKCAP, 0, ~0);
- vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKCTL, 0, ~0);
- vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKSTA, 0, ~0);
-
-#ifndef PCI_EXP_LNKCAP2
-#define PCI_EXP_LNKCAP2 44
-#endif
-#ifndef PCI_EXP_LNKSTA2
-#define PCI_EXP_LNKSTA2 50
-#endif
- /* Link 2 Capabilities, Status, and Control goes away */
- if (size > PCI_EXP_LNKCAP2) {
- vfio_add_emulated_long(vdev, pos + PCI_EXP_LNKCAP2, 0, ~0);
- vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKCTL2, 0, ~0);
- vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKSTA2, 0, ~0);
- }
- }
-
- } else if (type == PCI_EXP_TYPE_LEG_END) {
- /*
- * Legacy endpoints don't belong on the root complex. Windows
- * seems to be happier with devices if we skip the capability.
- */
- return 0;
- }
-
- } else {
- /*
- * Convert Root Complex Integrated Endpoints to regular endpoints.
- * These devices don't support LNK/LNK2 capabilities, so make them up.
- */
- if (type == PCI_EXP_TYPE_RC_END) {
- vfio_add_emulated_word(vdev, pos + PCI_CAP_FLAGS,
- PCI_EXP_TYPE_ENDPOINT << 4,
- PCI_EXP_FLAGS_TYPE);
- vfio_add_emulated_long(vdev, pos + PCI_EXP_LNKCAP,
- PCI_EXP_LNK_MLW_1 | PCI_EXP_LNK_LS_25, ~0);
- vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKCTL, 0, ~0);
- }
-
- /* Mark the Link Status bits as emulated to allow virtual negotiation */
- vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKSTA,
- pci_get_word(vdev->pdev.config + pos +
- PCI_EXP_LNKSTA),
- PCI_EXP_LNKCAP_MLW | PCI_EXP_LNKCAP_SLS);
- }
-
- pos = pci_add_capability(&vdev->pdev, PCI_CAP_ID_EXP, pos, size);
- if (pos >= 0) {
- vdev->pdev.exp.exp_cap = pos;
- }
-
- return pos;
-}
-
-static void vfio_check_pcie_flr(VFIOPCIDevice *vdev, uint8_t pos)
-{
- uint32_t cap = pci_get_long(vdev->pdev.config + pos + PCI_EXP_DEVCAP);
-
- if (cap & PCI_EXP_DEVCAP_FLR) {
- trace_vfio_check_pcie_flr(vdev->vbasedev.name);
- vdev->has_flr = true;
- }
-}
-
-static void vfio_check_pm_reset(VFIOPCIDevice *vdev, uint8_t pos)
-{
- uint16_t csr = pci_get_word(vdev->pdev.config + pos + PCI_PM_CTRL);
-
- if (!(csr & PCI_PM_CTRL_NO_SOFT_RESET)) {
- trace_vfio_check_pm_reset(vdev->vbasedev.name);
- vdev->has_pm_reset = true;
- }
-}
-
-static void vfio_check_af_flr(VFIOPCIDevice *vdev, uint8_t pos)
-{
- uint8_t cap = pci_get_byte(vdev->pdev.config + pos + PCI_AF_CAP);
-
- if ((cap & PCI_AF_CAP_TP) && (cap & PCI_AF_CAP_FLR)) {
- trace_vfio_check_af_flr(vdev->vbasedev.name);
- vdev->has_flr = true;
- }
-}
-
-static int vfio_add_std_cap(VFIOPCIDevice *vdev, uint8_t pos)
-{
- PCIDevice *pdev = &vdev->pdev;
- uint8_t cap_id, next, size;
- int ret;
-
- cap_id = pdev->config[pos];
- next = pdev->config[pos + PCI_CAP_LIST_NEXT];
-
- /*
- * If it becomes important to configure capabilities to their actual
- * size, use this as the default when it's something we don't recognize.
- * Since QEMU doesn't actually handle many of the config accesses,
- * exact size doesn't seem worthwhile.
- */
- size = vfio_std_cap_max_size(pdev, pos);
-
- /*
- * pci_add_capability always inserts the new capability at the head
- * of the chain. Therefore to end up with a chain that matches the
- * physical device, we insert from the end by making this recursive.
- * This is also why we pre-calculate size above as cached config space
- * will be changed as we unwind the stack.
- */
- if (next) {
- ret = vfio_add_std_cap(vdev, next);
- if (ret) {
- return ret;
- }
- } else {
- /* Begin the rebuild, use QEMU emulated list bits */
- pdev->config[PCI_CAPABILITY_LIST] = 0;
- vdev->emulated_config_bits[PCI_CAPABILITY_LIST] = 0xff;
- vdev->emulated_config_bits[PCI_STATUS] |= PCI_STATUS_CAP_LIST;
- }
-
- /* Use emulated next pointer to allow dropping caps */
- pci_set_byte(vdev->emulated_config_bits + pos + PCI_CAP_LIST_NEXT, 0xff);
-
- switch (cap_id) {
- case PCI_CAP_ID_MSI:
- ret = vfio_msi_setup(vdev, pos);
- break;
- case PCI_CAP_ID_EXP:
- vfio_check_pcie_flr(vdev, pos);
- ret = vfio_setup_pcie_cap(vdev, pos, size);
- break;
- case PCI_CAP_ID_MSIX:
- ret = vfio_msix_setup(vdev, pos);
- break;
- case PCI_CAP_ID_PM:
- vfio_check_pm_reset(vdev, pos);
- vdev->pm_cap = pos;
- ret = pci_add_capability(pdev, cap_id, pos, size);
- break;
- case PCI_CAP_ID_AF:
- vfio_check_af_flr(vdev, pos);
- ret = pci_add_capability(pdev, cap_id, pos, size);
- break;
- default:
- ret = pci_add_capability(pdev, cap_id, pos, size);
- break;
- }
-
- if (ret < 0) {
- error_report("vfio: %s Error adding PCI capability "
- "0x%x[0x%x]@0x%x: %d", vdev->vbasedev.name,
- cap_id, size, pos, ret);
- return ret;
- }
-
- return 0;
-}
-
-static int vfio_add_capabilities(VFIOPCIDevice *vdev)
-{
- PCIDevice *pdev = &vdev->pdev;
-
- if (!(pdev->config[PCI_STATUS] & PCI_STATUS_CAP_LIST) ||
- !pdev->config[PCI_CAPABILITY_LIST]) {
- return 0; /* Nothing to add */
- }
-
- return vfio_add_std_cap(vdev, pdev->config[PCI_CAPABILITY_LIST]);
-}
-
-static void vfio_pci_pre_reset(VFIOPCIDevice *vdev)
-{
- PCIDevice *pdev = &vdev->pdev;
- uint16_t cmd;
-
- vfio_disable_interrupts(vdev);
-
- /* Make sure the device is in D0 */
- if (vdev->pm_cap) {
- uint16_t pmcsr;
- uint8_t state;
-
- pmcsr = vfio_pci_read_config(pdev, vdev->pm_cap + PCI_PM_CTRL, 2);
- state = pmcsr & PCI_PM_CTRL_STATE_MASK;
- if (state) {
- pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
- vfio_pci_write_config(pdev, vdev->pm_cap + PCI_PM_CTRL, pmcsr, 2);
- /* vfio handles the necessary delay here */
- pmcsr = vfio_pci_read_config(pdev, vdev->pm_cap + PCI_PM_CTRL, 2);
- state = pmcsr & PCI_PM_CTRL_STATE_MASK;
- if (state) {
- error_report("vfio: Unable to power on device, stuck in D%d",
- state);
- }
- }
- }
-
- /*
- * Stop any ongoing DMA by disconecting I/O, MMIO, and bus master.
- * Also put INTx Disable in known state.
- */
- cmd = vfio_pci_read_config(pdev, PCI_COMMAND, 2);
- cmd &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
- PCI_COMMAND_INTX_DISABLE);
- vfio_pci_write_config(pdev, PCI_COMMAND, cmd, 2);
-}
-
-static void vfio_pci_post_reset(VFIOPCIDevice *vdev)
-{
- vfio_intx_enable(vdev);
-}
-
-static bool vfio_pci_host_match(PCIHostDeviceAddress *addr, const char *name)
-{
- char tmp[13];
-
- sprintf(tmp, "%04x:%02x:%02x.%1x", addr->domain,
- addr->bus, addr->slot, addr->function);
-
- return (strcmp(tmp, name) == 0);
-}
-
-static int vfio_pci_hot_reset(VFIOPCIDevice *vdev, bool single)
-{
- VFIOGroup *group;
- struct vfio_pci_hot_reset_info *info;
- struct vfio_pci_dependent_device *devices;
- struct vfio_pci_hot_reset *reset;
- int32_t *fds;
- int ret, i, count;
- bool multi = false;
-
- trace_vfio_pci_hot_reset(vdev->vbasedev.name, single ? "one" : "multi");
-
- vfio_pci_pre_reset(vdev);
- vdev->vbasedev.needs_reset = false;
-
- info = g_malloc0(sizeof(*info));
- info->argsz = sizeof(*info);
-
- ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_PCI_HOT_RESET_INFO, info);
- if (ret && errno != ENOSPC) {
- ret = -errno;
- if (!vdev->has_pm_reset) {
- error_report("vfio: Cannot reset device %s, "
- "no available reset mechanism.", vdev->vbasedev.name);
- }
- goto out_single;
- }
-
- count = info->count;
- info = g_realloc(info, sizeof(*info) + (count * sizeof(*devices)));
- info->argsz = sizeof(*info) + (count * sizeof(*devices));
- devices = &info->devices[0];
-
- ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_PCI_HOT_RESET_INFO, info);
- if (ret) {
- ret = -errno;
- error_report("vfio: hot reset info failed: %m");
- goto out_single;
- }
-
- trace_vfio_pci_hot_reset_has_dep_devices(vdev->vbasedev.name);
-
- /* Verify that we have all the groups required */
- for (i = 0; i < info->count; i++) {
- PCIHostDeviceAddress host;
- VFIOPCIDevice *tmp;
- VFIODevice *vbasedev_iter;
-
- host.domain = devices[i].segment;
- host.bus = devices[i].bus;
- host.slot = PCI_SLOT(devices[i].devfn);
- host.function = PCI_FUNC(devices[i].devfn);
-
- trace_vfio_pci_hot_reset_dep_devices(host.domain,
- host.bus, host.slot, host.function, devices[i].group_id);
-
- if (vfio_pci_host_match(&host, vdev->vbasedev.name)) {
- continue;
- }
-
- QLIST_FOREACH(group, &vfio_group_list, next) {
- if (group->groupid == devices[i].group_id) {
- break;
- }
- }
-
- if (!group) {
- if (!vdev->has_pm_reset) {
- error_report("vfio: Cannot reset device %s, "
- "depends on group %d which is not owned.",
- vdev->vbasedev.name, devices[i].group_id);
- }
- ret = -EPERM;
- goto out;
- }
-
- /* Prep dependent devices for reset and clear our marker. */
- QLIST_FOREACH(vbasedev_iter, &group->device_list, next) {
- if (vbasedev_iter->type != VFIO_DEVICE_TYPE_PCI) {
- continue;
- }
- tmp = container_of(vbasedev_iter, VFIOPCIDevice, vbasedev);
- if (vfio_pci_host_match(&host, tmp->vbasedev.name)) {
- if (single) {
- ret = -EINVAL;
- goto out_single;
- }
- vfio_pci_pre_reset(tmp);
- tmp->vbasedev.needs_reset = false;
- multi = true;
- break;
- }
- }
- }
-
- if (!single && !multi) {
- ret = -EINVAL;
- goto out_single;
- }
-
- /* Determine how many group fds need to be passed */
- count = 0;
- QLIST_FOREACH(group, &vfio_group_list, next) {
- for (i = 0; i < info->count; i++) {
- if (group->groupid == devices[i].group_id) {
- count++;
- break;
- }
- }
- }
-
- reset = g_malloc0(sizeof(*reset) + (count * sizeof(*fds)));
- reset->argsz = sizeof(*reset) + (count * sizeof(*fds));
- fds = &reset->group_fds[0];
-
- /* Fill in group fds */
- QLIST_FOREACH(group, &vfio_group_list, next) {
- for (i = 0; i < info->count; i++) {
- if (group->groupid == devices[i].group_id) {
- fds[reset->count++] = group->fd;
- break;
- }
- }
- }
-
- /* Bus reset! */
- ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_PCI_HOT_RESET, reset);
- g_free(reset);
-
- trace_vfio_pci_hot_reset_result(vdev->vbasedev.name,
- ret ? "%m" : "Success");
-
-out:
- /* Re-enable INTx on affected devices */
- for (i = 0; i < info->count; i++) {
- PCIHostDeviceAddress host;
- VFIOPCIDevice *tmp;
- VFIODevice *vbasedev_iter;
-
- host.domain = devices[i].segment;
- host.bus = devices[i].bus;
- host.slot = PCI_SLOT(devices[i].devfn);
- host.function = PCI_FUNC(devices[i].devfn);
-
- if (vfio_pci_host_match(&host, vdev->vbasedev.name)) {
- continue;
- }
-
- QLIST_FOREACH(group, &vfio_group_list, next) {
- if (group->groupid == devices[i].group_id) {
- break;
- }
- }
-
- if (!group) {
- break;
- }
-
- QLIST_FOREACH(vbasedev_iter, &group->device_list, next) {
- if (vbasedev_iter->type != VFIO_DEVICE_TYPE_PCI) {
- continue;
- }
- tmp = container_of(vbasedev_iter, VFIOPCIDevice, vbasedev);
- if (vfio_pci_host_match(&host, tmp->vbasedev.name)) {
- vfio_pci_post_reset(tmp);
- break;
- }
- }
- }
-out_single:
- vfio_pci_post_reset(vdev);
- g_free(info);
-
- return ret;
-}
-
-/*
- * We want to differentiate hot reset of mulitple in-use devices vs hot reset
- * of a single in-use device. VFIO_DEVICE_RESET will already handle the case
- * of doing hot resets when there is only a single device per bus. The in-use
- * here refers to how many VFIODevices are affected. A hot reset that affects
- * multiple devices, but only a single in-use device, means that we can call
- * it from our bus ->reset() callback since the extent is effectively a single
- * device. This allows us to make use of it in the hotplug path. When there
- * are multiple in-use devices, we can only trigger the hot reset during a
- * system reset and thus from our reset handler. We separate _one vs _multi
- * here so that we don't overlap and do a double reset on the system reset
- * path where both our reset handler and ->reset() callback are used. Calling
- * _one() will only do a hot reset for the one in-use devices case, calling
- * _multi() will do nothing if a _one() would have been sufficient.
- */
-static int vfio_pci_hot_reset_one(VFIOPCIDevice *vdev)
-{
- return vfio_pci_hot_reset(vdev, true);
-}
-
-static int vfio_pci_hot_reset_multi(VFIODevice *vbasedev)
-{
- VFIOPCIDevice *vdev = container_of(vbasedev, VFIOPCIDevice, vbasedev);
- return vfio_pci_hot_reset(vdev, false);
-}
-
-static void vfio_pci_compute_needs_reset(VFIODevice *vbasedev)
-{
- VFIOPCIDevice *vdev = container_of(vbasedev, VFIOPCIDevice, vbasedev);
- if (!vbasedev->reset_works || (!vdev->has_flr && vdev->has_pm_reset)) {
- vbasedev->needs_reset = true;
- }
-}
-
-static VFIODeviceOps vfio_pci_ops = {
- .vfio_compute_needs_reset = vfio_pci_compute_needs_reset,
- .vfio_hot_reset_multi = vfio_pci_hot_reset_multi,
- .vfio_eoi = vfio_intx_eoi,
-};
-
-int vfio_populate_vga(VFIOPCIDevice *vdev)
-{
- VFIODevice *vbasedev = &vdev->vbasedev;
- struct vfio_region_info *reg_info;
- int ret;
-
- if (vbasedev->num_regions > VFIO_PCI_VGA_REGION_INDEX) {
- ret = vfio_get_region_info(vbasedev,
- VFIO_PCI_VGA_REGION_INDEX, &reg_info);
- if (ret) {
- return ret;
- }
-
- if (!(reg_info->flags & VFIO_REGION_INFO_FLAG_READ) ||
- !(reg_info->flags & VFIO_REGION_INFO_FLAG_WRITE) ||
- reg_info->size < 0xbffff + 1) {
- error_report("vfio: Unexpected VGA info, flags 0x%lx, size 0x%lx",
- (unsigned long)reg_info->flags,
- (unsigned long)reg_info->size);
- g_free(reg_info);
- return -EINVAL;
- }
-
- vdev->vga = g_new0(VFIOVGA, 1);
-
- vdev->vga->fd_offset = reg_info->offset;
- vdev->vga->fd = vdev->vbasedev.fd;
-
- g_free(reg_info);
-
- vdev->vga->region[QEMU_PCI_VGA_MEM].offset = QEMU_PCI_VGA_MEM_BASE;
- vdev->vga->region[QEMU_PCI_VGA_MEM].nr = QEMU_PCI_VGA_MEM;
- QLIST_INIT(&vdev->vga->region[QEMU_PCI_VGA_MEM].quirks);
-
- vdev->vga->region[QEMU_PCI_VGA_IO_LO].offset = QEMU_PCI_VGA_IO_LO_BASE;
- vdev->vga->region[QEMU_PCI_VGA_IO_LO].nr = QEMU_PCI_VGA_IO_LO;
- QLIST_INIT(&vdev->vga->region[QEMU_PCI_VGA_IO_LO].quirks);
-
- vdev->vga->region[QEMU_PCI_VGA_IO_HI].offset = QEMU_PCI_VGA_IO_HI_BASE;
- vdev->vga->region[QEMU_PCI_VGA_IO_HI].nr = QEMU_PCI_VGA_IO_HI;
- QLIST_INIT(&vdev->vga->region[QEMU_PCI_VGA_IO_HI].quirks);
- }
-
- return 0;
-}
-
-static int vfio_populate_device(VFIOPCIDevice *vdev)
-{
- VFIODevice *vbasedev = &vdev->vbasedev;
- struct vfio_region_info *reg_info;
- struct vfio_irq_info irq_info = { .argsz = sizeof(irq_info) };
- int i, ret = -1;
-
- /* Sanity check device */
- if (!(vbasedev->flags & VFIO_DEVICE_FLAGS_PCI)) {
- error_report("vfio: Um, this isn't a PCI device");
- goto error;
- }
-
- if (vbasedev->num_regions < VFIO_PCI_CONFIG_REGION_INDEX + 1) {
- error_report("vfio: unexpected number of io regions %u",
- vbasedev->num_regions);
- goto error;
- }
-
- if (vbasedev->num_irqs < VFIO_PCI_MSIX_IRQ_INDEX + 1) {
- error_report("vfio: unexpected number of irqs %u", vbasedev->num_irqs);
- goto error;
- }
-
- for (i = VFIO_PCI_BAR0_REGION_INDEX; i < VFIO_PCI_ROM_REGION_INDEX; i++) {
- char *name = g_strdup_printf("%s BAR %d", vbasedev->name, i);
-
- ret = vfio_region_setup(OBJECT(vdev), vbasedev,
- &vdev->bars[i].region, i, name);
- g_free(name);
-
- if (ret) {
- error_report("vfio: Error getting region %d info: %m", i);
- goto error;
- }
-
- QLIST_INIT(&vdev->bars[i].quirks);
- }
-
- ret = vfio_get_region_info(vbasedev,
- VFIO_PCI_CONFIG_REGION_INDEX, &reg_info);
- if (ret) {
- error_report("vfio: Error getting config info: %m");
- goto error;
- }
-
- trace_vfio_populate_device_config(vdev->vbasedev.name,
- (unsigned long)reg_info->size,
- (unsigned long)reg_info->offset,
- (unsigned long)reg_info->flags);
-
- vdev->config_size = reg_info->size;
- if (vdev->config_size == PCI_CONFIG_SPACE_SIZE) {
- vdev->pdev.cap_present &= ~QEMU_PCI_CAP_EXPRESS;
- }
- vdev->config_offset = reg_info->offset;
-
- g_free(reg_info);
-
- if (vdev->features & VFIO_FEATURE_ENABLE_VGA) {
- ret = vfio_populate_vga(vdev);
- if (ret) {
- error_report(
- "vfio: Device does not support requested feature x-vga");
- goto error;
- }
- }
-
- irq_info.index = VFIO_PCI_ERR_IRQ_INDEX;
-
- ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_IRQ_INFO, &irq_info);
- if (ret) {
- /* This can fail for an old kernel or legacy PCI dev */
- trace_vfio_populate_device_get_irq_info_failure();
- ret = 0;
- } else if (irq_info.count == 1) {
- vdev->pci_aer = true;
- } else {
- error_report("vfio: %s "
- "Could not enable error recovery for the device",
- vbasedev->name);
- }
-
-error:
- return ret;
-}
-
-static void vfio_put_device(VFIOPCIDevice *vdev)
-{
- g_free(vdev->vbasedev.name);
- g_free(vdev->msix);
-
- vfio_put_base_device(&vdev->vbasedev);
-}
-
-static void vfio_err_notifier_handler(void *opaque)
-{
- VFIOPCIDevice *vdev = opaque;
-
- if (!event_notifier_test_and_clear(&vdev->err_notifier)) {
- return;
- }
-
- /*
- * TBD. Retrieve the error details and decide what action
- * needs to be taken. One of the actions could be to pass
- * the error to the guest and have the guest driver recover
- * from the error. This requires that PCIe capabilities be
- * exposed to the guest. For now, we just terminate the
- * guest to contain the error.
- */
-
- error_report("%s(%s) Unrecoverable error detected. Please collect any data possible and then kill the guest", __func__, vdev->vbasedev.name);
-
- vm_stop(RUN_STATE_INTERNAL_ERROR);
-}
-
-/*
- * Registers error notifier for devices supporting error recovery.
- * If we encounter a failure in this function, we report an error
- * and continue after disabling error recovery support for the
- * device.
- */
-static void vfio_register_err_notifier(VFIOPCIDevice *vdev)
-{
- int ret;
- int argsz;
- struct vfio_irq_set *irq_set;
- int32_t *pfd;
-
- if (!vdev->pci_aer) {
- return;
- }
-
- if (event_notifier_init(&vdev->err_notifier, 0)) {
- error_report("vfio: Unable to init event notifier for error detection");
- vdev->pci_aer = false;
- return;
- }
-
- argsz = sizeof(*irq_set) + sizeof(*pfd);
-
- irq_set = g_malloc0(argsz);
- irq_set->argsz = argsz;
- irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
- VFIO_IRQ_SET_ACTION_TRIGGER;
- irq_set->index = VFIO_PCI_ERR_IRQ_INDEX;
- irq_set->start = 0;
- irq_set->count = 1;
- pfd = (int32_t *)&irq_set->data;
-
- *pfd = event_notifier_get_fd(&vdev->err_notifier);
- qemu_set_fd_handler(*pfd, vfio_err_notifier_handler, NULL, vdev);
-
- ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set);
- if (ret) {
- error_report("vfio: Failed to set up error notification");
- qemu_set_fd_handler(*pfd, NULL, NULL, vdev);
- event_notifier_cleanup(&vdev->err_notifier);
- vdev->pci_aer = false;
- }
- g_free(irq_set);
-}
-
-static void vfio_unregister_err_notifier(VFIOPCIDevice *vdev)
-{
- int argsz;
- struct vfio_irq_set *irq_set;
- int32_t *pfd;
- int ret;
-
- if (!vdev->pci_aer) {
- return;
- }
-
- argsz = sizeof(*irq_set) + sizeof(*pfd);
-
- irq_set = g_malloc0(argsz);
- irq_set->argsz = argsz;
- irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
- VFIO_IRQ_SET_ACTION_TRIGGER;
- irq_set->index = VFIO_PCI_ERR_IRQ_INDEX;
- irq_set->start = 0;
- irq_set->count = 1;
- pfd = (int32_t *)&irq_set->data;
- *pfd = -1;
-
- ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set);
- if (ret) {
- error_report("vfio: Failed to de-assign error fd: %m");
- }
- g_free(irq_set);
- qemu_set_fd_handler(event_notifier_get_fd(&vdev->err_notifier),
- NULL, NULL, vdev);
- event_notifier_cleanup(&vdev->err_notifier);
-}
-
-static void vfio_req_notifier_handler(void *opaque)
-{
- VFIOPCIDevice *vdev = opaque;
-
- if (!event_notifier_test_and_clear(&vdev->req_notifier)) {
- return;
- }
-
- qdev_unplug(&vdev->pdev.qdev, NULL);
-}
-
-static void vfio_register_req_notifier(VFIOPCIDevice *vdev)
-{
- struct vfio_irq_info irq_info = { .argsz = sizeof(irq_info),
- .index = VFIO_PCI_REQ_IRQ_INDEX };
- int argsz;
- struct vfio_irq_set *irq_set;
- int32_t *pfd;
-
- if (!(vdev->features & VFIO_FEATURE_ENABLE_REQ)) {
- return;
- }
-
- if (ioctl(vdev->vbasedev.fd,
- VFIO_DEVICE_GET_IRQ_INFO, &irq_info) < 0 || irq_info.count < 1) {
- return;
- }
-
- if (event_notifier_init(&vdev->req_notifier, 0)) {
- error_report("vfio: Unable to init event notifier for device request");
- return;
- }
-
- argsz = sizeof(*irq_set) + sizeof(*pfd);
-
- irq_set = g_malloc0(argsz);
- irq_set->argsz = argsz;
- irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
- VFIO_IRQ_SET_ACTION_TRIGGER;
- irq_set->index = VFIO_PCI_REQ_IRQ_INDEX;
- irq_set->start = 0;
- irq_set->count = 1;
- pfd = (int32_t *)&irq_set->data;
-
- *pfd = event_notifier_get_fd(&vdev->req_notifier);
- qemu_set_fd_handler(*pfd, vfio_req_notifier_handler, NULL, vdev);
-
- if (ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set)) {
- error_report("vfio: Failed to set up device request notification");
- qemu_set_fd_handler(*pfd, NULL, NULL, vdev);
- event_notifier_cleanup(&vdev->req_notifier);
- } else {
- vdev->req_enabled = true;
- }
-
- g_free(irq_set);
-}
-
-static void vfio_unregister_req_notifier(VFIOPCIDevice *vdev)
-{
- int argsz;
- struct vfio_irq_set *irq_set;
- int32_t *pfd;
-
- if (!vdev->req_enabled) {
- return;
- }
-
- argsz = sizeof(*irq_set) + sizeof(*pfd);
-
- irq_set = g_malloc0(argsz);
- irq_set->argsz = argsz;
- irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
- VFIO_IRQ_SET_ACTION_TRIGGER;
- irq_set->index = VFIO_PCI_REQ_IRQ_INDEX;
- irq_set->start = 0;
- irq_set->count = 1;
- pfd = (int32_t *)&irq_set->data;
- *pfd = -1;
-
- if (ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set)) {
- error_report("vfio: Failed to de-assign device request fd: %m");
- }
- g_free(irq_set);
- qemu_set_fd_handler(event_notifier_get_fd(&vdev->req_notifier),
- NULL, NULL, vdev);
- event_notifier_cleanup(&vdev->req_notifier);
-
- vdev->req_enabled = false;
-}
-
-static int vfio_initfn(PCIDevice *pdev)
-{
- VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
- VFIODevice *vbasedev_iter;
- VFIOGroup *group;
- char *tmp, group_path[PATH_MAX], *group_name;
- ssize_t len;
- struct stat st;
- int groupid;
- int ret;
-
- if (!vdev->vbasedev.sysfsdev) {
- vdev->vbasedev.sysfsdev =
- g_strdup_printf("/sys/bus/pci/devices/%04x:%02x:%02x.%01x",
- vdev->host.domain, vdev->host.bus,
- vdev->host.slot, vdev->host.function);
- }
-
- if (stat(vdev->vbasedev.sysfsdev, &st) < 0) {
- error_report("vfio: error: no such host device: %s",
- vdev->vbasedev.sysfsdev);
- return -errno;
- }
-
- vdev->vbasedev.name = g_strdup(basename(vdev->vbasedev.sysfsdev));
- vdev->vbasedev.ops = &vfio_pci_ops;
- vdev->vbasedev.type = VFIO_DEVICE_TYPE_PCI;
-
- tmp = g_strdup_printf("%s/iommu_group", vdev->vbasedev.sysfsdev);
- len = readlink(tmp, group_path, sizeof(group_path));
- g_free(tmp);
-
- if (len <= 0 || len >= sizeof(group_path)) {
- error_report("vfio: error no iommu_group for device");
- return len < 0 ? -errno : -ENAMETOOLONG;
- }
-
- group_path[len] = 0;
-
- group_name = basename(group_path);
- if (sscanf(group_name, "%d", &groupid) != 1) {
- error_report("vfio: error reading %s: %m", group_path);
- return -errno;
- }
-
- trace_vfio_initfn(vdev->vbasedev.name, groupid);
-
- group = vfio_get_group(groupid, pci_device_iommu_address_space(pdev));
- if (!group) {
- error_report("vfio: failed to get group %d", groupid);
- return -ENOENT;
- }
-
- QLIST_FOREACH(vbasedev_iter, &group->device_list, next) {
- if (strcmp(vbasedev_iter->name, vdev->vbasedev.name) == 0) {
- error_report("vfio: error: device %s is already attached",
- vdev->vbasedev.name);
- vfio_put_group(group);
- return -EBUSY;
- }
- }
-
- ret = vfio_get_device(group, vdev->vbasedev.name, &vdev->vbasedev);
- if (ret) {
- error_report("vfio: failed to get device %s", vdev->vbasedev.name);
- vfio_put_group(group);
- return ret;
- }
-
- ret = vfio_populate_device(vdev);
- if (ret) {
- return ret;
- }
-
- /* Get a copy of config space */
- ret = pread(vdev->vbasedev.fd, vdev->pdev.config,
- MIN(pci_config_size(&vdev->pdev), vdev->config_size),
- vdev->config_offset);
- if (ret < (int)MIN(pci_config_size(&vdev->pdev), vdev->config_size)) {
- ret = ret < 0 ? -errno : -EFAULT;
- error_report("vfio: Failed to read device config space");
- return ret;
- }
-
- /* vfio emulates a lot for us, but some bits need extra love */
- vdev->emulated_config_bits = g_malloc0(vdev->config_size);
-
- /* QEMU can choose to expose the ROM or not */
- memset(vdev->emulated_config_bits + PCI_ROM_ADDRESS, 0xff, 4);
-
- /*
- * The PCI spec reserves vendor ID 0xffff as an invalid value. The
- * device ID is managed by the vendor and need only be a 16-bit value.
- * Allow any 16-bit value for subsystem so they can be hidden or changed.
- */
- if (vdev->vendor_id != PCI_ANY_ID) {
- if (vdev->vendor_id >= 0xffff) {
- error_report("vfio: Invalid PCI vendor ID provided");
- return -EINVAL;
- }
- vfio_add_emulated_word(vdev, PCI_VENDOR_ID, vdev->vendor_id, ~0);
- trace_vfio_pci_emulated_vendor_id(vdev->vbasedev.name, vdev->vendor_id);
- } else {
- vdev->vendor_id = pci_get_word(pdev->config + PCI_VENDOR_ID);
- }
-
- if (vdev->device_id != PCI_ANY_ID) {
- if (vdev->device_id > 0xffff) {
- error_report("vfio: Invalid PCI device ID provided");
- return -EINVAL;
- }
- vfio_add_emulated_word(vdev, PCI_DEVICE_ID, vdev->device_id, ~0);
- trace_vfio_pci_emulated_device_id(vdev->vbasedev.name, vdev->device_id);
- } else {
- vdev->device_id = pci_get_word(pdev->config + PCI_DEVICE_ID);
- }
-
- if (vdev->sub_vendor_id != PCI_ANY_ID) {
- if (vdev->sub_vendor_id > 0xffff) {
- error_report("vfio: Invalid PCI subsystem vendor ID provided");
- return -EINVAL;
- }
- vfio_add_emulated_word(vdev, PCI_SUBSYSTEM_VENDOR_ID,
- vdev->sub_vendor_id, ~0);
- trace_vfio_pci_emulated_sub_vendor_id(vdev->vbasedev.name,
- vdev->sub_vendor_id);
- }
-
- if (vdev->sub_device_id != PCI_ANY_ID) {
- if (vdev->sub_device_id > 0xffff) {
- error_report("vfio: Invalid PCI subsystem device ID provided");
- return -EINVAL;
- }
- vfio_add_emulated_word(vdev, PCI_SUBSYSTEM_ID, vdev->sub_device_id, ~0);
- trace_vfio_pci_emulated_sub_device_id(vdev->vbasedev.name,
- vdev->sub_device_id);
- }
-
- /* QEMU can change multi-function devices to single function, or reverse */
- vdev->emulated_config_bits[PCI_HEADER_TYPE] =
- PCI_HEADER_TYPE_MULTI_FUNCTION;
-
- /* Restore or clear multifunction, this is always controlled by QEMU */
- if (vdev->pdev.cap_present & QEMU_PCI_CAP_MULTIFUNCTION) {
- vdev->pdev.config[PCI_HEADER_TYPE] |= PCI_HEADER_TYPE_MULTI_FUNCTION;
- } else {
- vdev->pdev.config[PCI_HEADER_TYPE] &= ~PCI_HEADER_TYPE_MULTI_FUNCTION;
- }
-
- /*
- * Clear host resource mapping info. If we choose not to register a
- * BAR, such as might be the case with the option ROM, we can get
- * confusing, unwritable, residual addresses from the host here.
- */
- memset(&vdev->pdev.config[PCI_BASE_ADDRESS_0], 0, 24);
- memset(&vdev->pdev.config[PCI_ROM_ADDRESS], 0, 4);
-
- vfio_pci_size_rom(vdev);
-
- ret = vfio_msix_early_setup(vdev);
- if (ret) {
- return ret;
- }
-
- vfio_bars_setup(vdev);
-
- ret = vfio_add_capabilities(vdev);
- if (ret) {
- goto out_teardown;
- }
-
- /* QEMU emulates all of MSI & MSIX */
- if (pdev->cap_present & QEMU_PCI_CAP_MSIX) {
- memset(vdev->emulated_config_bits + pdev->msix_cap, 0xff,
- MSIX_CAP_LENGTH);
- }
-
- if (pdev->cap_present & QEMU_PCI_CAP_MSI) {
- memset(vdev->emulated_config_bits + pdev->msi_cap, 0xff,
- vdev->msi_cap_size);
- }
-
- if (vfio_pci_read_config(&vdev->pdev, PCI_INTERRUPT_PIN, 1)) {
- vdev->intx.mmap_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL,
- vfio_intx_mmap_enable, vdev);
- pci_device_set_intx_routing_notifier(&vdev->pdev, vfio_intx_update);
- ret = vfio_intx_enable(vdev);
- if (ret) {
- goto out_teardown;
- }
- }
-
- vfio_register_err_notifier(vdev);
- vfio_register_req_notifier(vdev);
- vfio_setup_resetfn_quirk(vdev);
-
- return 0;
-
-out_teardown:
- pci_device_set_intx_routing_notifier(&vdev->pdev, NULL);
- vfio_teardown_msi(vdev);
- vfio_bars_exit(vdev);
- return ret;
-}
-
-static void vfio_instance_finalize(Object *obj)
-{
- PCIDevice *pci_dev = PCI_DEVICE(obj);
- VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pci_dev);
- VFIOGroup *group = vdev->vbasedev.group;
-
- vfio_bars_finalize(vdev);
- g_free(vdev->emulated_config_bits);
- g_free(vdev->rom);
- vfio_put_device(vdev);
- vfio_put_group(group);
-}
-
-static void vfio_exitfn(PCIDevice *pdev)
-{
- VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
-
- vfio_unregister_req_notifier(vdev);
- vfio_unregister_err_notifier(vdev);
- pci_device_set_intx_routing_notifier(&vdev->pdev, NULL);
- vfio_disable_interrupts(vdev);
- if (vdev->intx.mmap_timer) {
- timer_free(vdev->intx.mmap_timer);
- }
- vfio_teardown_msi(vdev);
- vfio_bars_exit(vdev);
-}
-
-static void vfio_pci_reset(DeviceState *dev)
-{
- PCIDevice *pdev = DO_UPCAST(PCIDevice, qdev, dev);
- VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
-
- trace_vfio_pci_reset(vdev->vbasedev.name);
-
- vfio_pci_pre_reset(vdev);
-
- if (vdev->resetfn && !vdev->resetfn(vdev)) {
- goto post_reset;
- }
-
- if (vdev->vbasedev.reset_works &&
- (vdev->has_flr || !vdev->has_pm_reset) &&
- !ioctl(vdev->vbasedev.fd, VFIO_DEVICE_RESET)) {
- trace_vfio_pci_reset_flr(vdev->vbasedev.name);
- goto post_reset;
- }
-
- /* See if we can do our own bus reset */
- if (!vfio_pci_hot_reset_one(vdev)) {
- goto post_reset;
- }
-
- /* If nothing else works and the device supports PM reset, use it */
- if (vdev->vbasedev.reset_works && vdev->has_pm_reset &&
- !ioctl(vdev->vbasedev.fd, VFIO_DEVICE_RESET)) {
- trace_vfio_pci_reset_pm(vdev->vbasedev.name);
- goto post_reset;
- }
-
-post_reset:
- vfio_pci_post_reset(vdev);
-}
-
-static void vfio_instance_init(Object *obj)
-{
- PCIDevice *pci_dev = PCI_DEVICE(obj);
- VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, PCI_DEVICE(obj));
-
- device_add_bootindex_property(obj, &vdev->bootindex,
- "bootindex", NULL,
- &pci_dev->qdev, NULL);
-}
-
-static Property vfio_pci_dev_properties[] = {
- DEFINE_PROP_PCI_HOST_DEVADDR("host", VFIOPCIDevice, host),
- DEFINE_PROP_STRING("sysfsdev", VFIOPCIDevice, vbasedev.sysfsdev),
- DEFINE_PROP_UINT32("x-intx-mmap-timeout-ms", VFIOPCIDevice,
- intx.mmap_timeout, 1100),
- DEFINE_PROP_BIT("x-vga", VFIOPCIDevice, features,
- VFIO_FEATURE_ENABLE_VGA_BIT, false),
- DEFINE_PROP_BIT("x-req", VFIOPCIDevice, features,
- VFIO_FEATURE_ENABLE_REQ_BIT, true),
- DEFINE_PROP_BOOL("x-no-mmap", VFIOPCIDevice, vbasedev.no_mmap, false),
- DEFINE_PROP_BOOL("x-no-kvm-intx", VFIOPCIDevice, no_kvm_intx, false),
- DEFINE_PROP_BOOL("x-no-kvm-msi", VFIOPCIDevice, no_kvm_msi, false),
- DEFINE_PROP_BOOL("x-no-kvm-msix", VFIOPCIDevice, no_kvm_msix, false),
- DEFINE_PROP_UINT32("x-pci-vendor-id", VFIOPCIDevice, vendor_id, PCI_ANY_ID),
- DEFINE_PROP_UINT32("x-pci-device-id", VFIOPCIDevice, device_id, PCI_ANY_ID),
- DEFINE_PROP_UINT32("x-pci-sub-vendor-id", VFIOPCIDevice,
- sub_vendor_id, PCI_ANY_ID),
- DEFINE_PROP_UINT32("x-pci-sub-device-id", VFIOPCIDevice,
- sub_device_id, PCI_ANY_ID),
- /*
- * TODO - support passed fds... is this necessary?
- * DEFINE_PROP_STRING("vfiofd", VFIOPCIDevice, vfiofd_name),
- * DEFINE_PROP_STRING("vfiogroupfd, VFIOPCIDevice, vfiogroupfd_name),
- */
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static const VMStateDescription vfio_pci_vmstate = {
- .name = "vfio-pci",
- .unmigratable = 1,
-};
-
-static void vfio_pci_dev_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *pdc = PCI_DEVICE_CLASS(klass);
-
- dc->reset = vfio_pci_reset;
- dc->props = vfio_pci_dev_properties;
- dc->vmsd = &vfio_pci_vmstate;
- dc->desc = "VFIO-based PCI device assignment";
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- pdc->init = vfio_initfn;
- pdc->exit = vfio_exitfn;
- pdc->config_read = vfio_pci_read_config;
- pdc->config_write = vfio_pci_write_config;
- pdc->is_express = 1; /* We might be */
-}
-
-static const TypeInfo vfio_pci_dev_info = {
- .name = "vfio-pci",
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(VFIOPCIDevice),
- .class_init = vfio_pci_dev_class_init,
- .instance_init = vfio_instance_init,
- .instance_finalize = vfio_instance_finalize,
-};
-
-static void register_vfio_pci_dev_type(void)
-{
- type_register_static(&vfio_pci_dev_info);
-}
-
-type_init(register_vfio_pci_dev_type)
diff --git a/qemu/hw/vfio/pci.h b/qemu/hw/vfio/pci.h
deleted file mode 100644
index 3976f6854..000000000
--- a/qemu/hw/vfio/pci.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * vfio based device assignment support - PCI devices
- *
- * Copyright Red Hat, Inc. 2012-2015
- *
- * Authors:
- * Alex Williamson <alex.williamson@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- */
-#ifndef HW_VFIO_VFIO_PCI_H
-#define HW_VFIO_VFIO_PCI_H
-
-#include "qemu-common.h"
-#include "exec/memory.h"
-#include "hw/pci/pci.h"
-#include "hw/vfio/vfio-common.h"
-#include "qemu/event_notifier.h"
-#include "qemu/queue.h"
-#include "qemu/timer.h"
-
-#define PCI_ANY_ID (~0)
-
-struct VFIOPCIDevice;
-
-typedef struct VFIOQuirk {
- QLIST_ENTRY(VFIOQuirk) next;
- void *data;
- int nr_mem;
- MemoryRegion *mem;
-} VFIOQuirk;
-
-typedef struct VFIOBAR {
- VFIORegion region;
- bool ioport;
- bool mem64;
- QLIST_HEAD(, VFIOQuirk) quirks;
-} VFIOBAR;
-
-typedef struct VFIOVGARegion {
- MemoryRegion mem;
- off_t offset;
- int nr;
- QLIST_HEAD(, VFIOQuirk) quirks;
-} VFIOVGARegion;
-
-typedef struct VFIOVGA {
- off_t fd_offset;
- int fd;
- VFIOVGARegion region[QEMU_PCI_VGA_NUM_REGIONS];
-} VFIOVGA;
-
-typedef struct VFIOINTx {
- bool pending; /* interrupt pending */
- bool kvm_accel; /* set when QEMU bypass through KVM enabled */
- uint8_t pin; /* which pin to pull for qemu_set_irq */
- EventNotifier interrupt; /* eventfd triggered on interrupt */
- EventNotifier unmask; /* eventfd for unmask on QEMU bypass */
- PCIINTxRoute route; /* routing info for QEMU bypass */
- uint32_t mmap_timeout; /* delay to re-enable mmaps after interrupt */
- QEMUTimer *mmap_timer; /* enable mmaps after periods w/o interrupts */
-} VFIOINTx;
-
-typedef struct VFIOMSIVector {
- /*
- * Two interrupt paths are configured per vector. The first, is only used
- * for interrupts injected via QEMU. This is typically the non-accel path,
- * but may also be used when we want QEMU to handle masking and pending
- * bits. The KVM path bypasses QEMU and is therefore higher performance,
- * but requires masking at the device. virq is used to track the MSI route
- * through KVM, thus kvm_interrupt is only available when virq is set to a
- * valid (>= 0) value.
- */
- EventNotifier interrupt;
- EventNotifier kvm_interrupt;
- struct VFIOPCIDevice *vdev; /* back pointer to device */
- int virq;
- bool use;
-} VFIOMSIVector;
-
-enum {
- VFIO_INT_NONE = 0,
- VFIO_INT_INTx = 1,
- VFIO_INT_MSI = 2,
- VFIO_INT_MSIX = 3,
-};
-
-/* Cache of MSI-X setup plus extra mmap and memory region for split BAR map */
-typedef struct VFIOMSIXInfo {
- uint8_t table_bar;
- uint8_t pba_bar;
- uint16_t entries;
- uint32_t table_offset;
- uint32_t pba_offset;
- MemoryRegion mmap_mem;
- void *mmap;
- unsigned long *pending;
-} VFIOMSIXInfo;
-
-typedef struct VFIOPCIDevice {
- PCIDevice pdev;
- VFIODevice vbasedev;
- VFIOINTx intx;
- unsigned int config_size;
- uint8_t *emulated_config_bits; /* QEMU emulated bits, little-endian */
- off_t config_offset; /* Offset of config space region within device fd */
- unsigned int rom_size;
- off_t rom_offset; /* Offset of ROM region within device fd */
- void *rom;
- int msi_cap_size;
- VFIOMSIVector *msi_vectors;
- VFIOMSIXInfo *msix;
- int nr_vectors; /* Number of MSI/MSIX vectors currently in use */
- int interrupt; /* Current interrupt type */
- VFIOBAR bars[PCI_NUM_REGIONS - 1]; /* No ROM */
- VFIOVGA *vga; /* 0xa0000, 0x3b0, 0x3c0 */
- PCIHostDeviceAddress host;
- EventNotifier err_notifier;
- EventNotifier req_notifier;
- int (*resetfn)(struct VFIOPCIDevice *);
- uint32_t vendor_id;
- uint32_t device_id;
- uint32_t sub_vendor_id;
- uint32_t sub_device_id;
- uint32_t features;
-#define VFIO_FEATURE_ENABLE_VGA_BIT 0
-#define VFIO_FEATURE_ENABLE_VGA (1 << VFIO_FEATURE_ENABLE_VGA_BIT)
-#define VFIO_FEATURE_ENABLE_REQ_BIT 1
-#define VFIO_FEATURE_ENABLE_REQ (1 << VFIO_FEATURE_ENABLE_REQ_BIT)
- int32_t bootindex;
- uint8_t pm_cap;
- bool has_vga;
- bool pci_aer;
- bool req_enabled;
- bool has_flr;
- bool has_pm_reset;
- bool rom_read_failed;
- bool no_kvm_intx;
- bool no_kvm_msi;
- bool no_kvm_msix;
-} VFIOPCIDevice;
-
-uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len);
-void vfio_pci_write_config(PCIDevice *pdev,
- uint32_t addr, uint32_t val, int len);
-
-uint64_t vfio_vga_read(void *opaque, hwaddr addr, unsigned size);
-void vfio_vga_write(void *opaque, hwaddr addr, uint64_t data, unsigned size);
-
-bool vfio_blacklist_opt_rom(VFIOPCIDevice *vdev);
-void vfio_vga_quirk_setup(VFIOPCIDevice *vdev);
-void vfio_vga_quirk_exit(VFIOPCIDevice *vdev);
-void vfio_vga_quirk_finalize(VFIOPCIDevice *vdev);
-void vfio_bar_quirk_setup(VFIOPCIDevice *vdev, int nr);
-void vfio_bar_quirk_exit(VFIOPCIDevice *vdev, int nr);
-void vfio_bar_quirk_finalize(VFIOPCIDevice *vdev, int nr);
-void vfio_setup_resetfn_quirk(VFIOPCIDevice *vdev);
-
-int vfio_populate_vga(VFIOPCIDevice *vdev);
-
-#endif /* HW_VFIO_VFIO_PCI_H */
diff --git a/qemu/hw/vfio/platform.c b/qemu/hw/vfio/platform.c
deleted file mode 100644
index 1798a00a3..000000000
--- a/qemu/hw/vfio/platform.c
+++ /dev/null
@@ -1,705 +0,0 @@
-/*
- * vfio based device assignment support - platform devices
- *
- * Copyright Linaro Limited, 2014
- *
- * Authors:
- * Kim Phillips <kim.phillips@linaro.org>
- * Eric Auger <eric.auger@linaro.org>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- * Based on vfio based PCI device assignment support:
- * Copyright Red Hat, Inc. 2012
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include <sys/ioctl.h>
-#include <linux/vfio.h>
-
-#include "hw/vfio/vfio-platform.h"
-#include "qemu/error-report.h"
-#include "qemu/range.h"
-#include "sysemu/sysemu.h"
-#include "exec/memory.h"
-#include "qemu/queue.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "hw/platform-bus.h"
-#include "sysemu/kvm.h"
-
-/*
- * Functions used whatever the injection method
- */
-
-static inline bool vfio_irq_is_automasked(VFIOINTp *intp)
-{
- return intp->flags & VFIO_IRQ_INFO_AUTOMASKED;
-}
-
-/**
- * vfio_init_intp - allocate, initialize the IRQ struct pointer
- * and add it into the list of IRQs
- * @vbasedev: the VFIO device handle
- * @info: irq info struct retrieved from VFIO driver
- */
-static VFIOINTp *vfio_init_intp(VFIODevice *vbasedev,
- struct vfio_irq_info info)
-{
- int ret;
- VFIOPlatformDevice *vdev =
- container_of(vbasedev, VFIOPlatformDevice, vbasedev);
- SysBusDevice *sbdev = SYS_BUS_DEVICE(vdev);
- VFIOINTp *intp;
-
- intp = g_malloc0(sizeof(*intp));
- intp->vdev = vdev;
- intp->pin = info.index;
- intp->flags = info.flags;
- intp->state = VFIO_IRQ_INACTIVE;
- intp->kvm_accel = false;
-
- sysbus_init_irq(sbdev, &intp->qemuirq);
-
- /* Get an eventfd for trigger */
- intp->interrupt = g_malloc0(sizeof(EventNotifier));
- ret = event_notifier_init(intp->interrupt, 0);
- if (ret) {
- g_free(intp->interrupt);
- g_free(intp);
- error_report("vfio: Error: trigger event_notifier_init failed ");
- return NULL;
- }
- if (vfio_irq_is_automasked(intp)) {
- /* Get an eventfd for resample/unmask */
- intp->unmask = g_malloc0(sizeof(EventNotifier));
- ret = event_notifier_init(intp->unmask, 0);
- if (ret) {
- g_free(intp->interrupt);
- g_free(intp->unmask);
- g_free(intp);
- error_report("vfio: Error: resamplefd event_notifier_init failed");
- return NULL;
- }
- }
-
- QLIST_INSERT_HEAD(&vdev->intp_list, intp, next);
- return intp;
-}
-
-/**
- * vfio_set_trigger_eventfd - set VFIO eventfd handling
- *
- * @intp: IRQ struct handle
- * @handler: handler to be called on eventfd signaling
- *
- * Setup VFIO signaling and attach an optional user-side handler
- * to the eventfd
- */
-static int vfio_set_trigger_eventfd(VFIOINTp *intp,
- eventfd_user_side_handler_t handler)
-{
- VFIODevice *vbasedev = &intp->vdev->vbasedev;
- struct vfio_irq_set *irq_set;
- int argsz, ret;
- int32_t *pfd;
-
- argsz = sizeof(*irq_set) + sizeof(*pfd);
- irq_set = g_malloc0(argsz);
- irq_set->argsz = argsz;
- irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
- irq_set->index = intp->pin;
- irq_set->start = 0;
- irq_set->count = 1;
- pfd = (int32_t *)&irq_set->data;
- *pfd = event_notifier_get_fd(intp->interrupt);
- qemu_set_fd_handler(*pfd, (IOHandler *)handler, NULL, intp);
- ret = ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, irq_set);
- g_free(irq_set);
- if (ret < 0) {
- error_report("vfio: Failed to set trigger eventfd: %m");
- qemu_set_fd_handler(*pfd, NULL, NULL, NULL);
- }
- return ret;
-}
-
-/*
- * Functions only used when eventfds are handled on user-side
- * ie. without irqfd
- */
-
-/**
- * vfio_mmap_set_enabled - enable/disable the fast path mode
- * @vdev: the VFIO platform device
- * @enabled: the target mmap state
- *
- * enabled = true ~ fast path = MMIO region is mmaped (no KVM TRAP);
- * enabled = false ~ slow path = MMIO region is trapped and region callbacks
- * are called; slow path enables to trap the device IRQ status register reset
-*/
-
-static void vfio_mmap_set_enabled(VFIOPlatformDevice *vdev, bool enabled)
-{
- int i;
-
- for (i = 0; i < vdev->vbasedev.num_regions; i++) {
- vfio_region_mmaps_set_enabled(vdev->regions[i], enabled);
- }
-}
-
-/**
- * vfio_intp_mmap_enable - timer function, restores the fast path
- * if there is no more active IRQ
- * @opaque: actually points to the VFIO platform device
- *
- * Called on mmap timer timout, this function checks whether the
- * IRQ is still active and if not, restores the fast path.
- * by construction a single eventfd is handled at a time.
- * if the IRQ is still active, the timer is re-programmed.
- */
-static void vfio_intp_mmap_enable(void *opaque)
-{
- VFIOINTp *tmp;
- VFIOPlatformDevice *vdev = (VFIOPlatformDevice *)opaque;
-
- qemu_mutex_lock(&vdev->intp_mutex);
- QLIST_FOREACH(tmp, &vdev->intp_list, next) {
- if (tmp->state == VFIO_IRQ_ACTIVE) {
- trace_vfio_platform_intp_mmap_enable(tmp->pin);
- /* re-program the timer to check active status later */
- timer_mod(vdev->mmap_timer,
- qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
- vdev->mmap_timeout);
- qemu_mutex_unlock(&vdev->intp_mutex);
- return;
- }
- }
- vfio_mmap_set_enabled(vdev, true);
- qemu_mutex_unlock(&vdev->intp_mutex);
-}
-
-/**
- * vfio_intp_inject_pending_lockheld - Injects a pending IRQ
- * @opaque: opaque pointer, in practice the VFIOINTp handle
- *
- * The function is called on a previous IRQ completion, from
- * vfio_platform_eoi, while the intp_mutex is locked.
- * Also in such situation, the slow path already is set and
- * the mmap timer was already programmed.
- */
-static void vfio_intp_inject_pending_lockheld(VFIOINTp *intp)
-{
- trace_vfio_platform_intp_inject_pending_lockheld(intp->pin,
- event_notifier_get_fd(intp->interrupt));
-
- intp->state = VFIO_IRQ_ACTIVE;
-
- /* trigger the virtual IRQ */
- qemu_set_irq(intp->qemuirq, 1);
-}
-
-/**
- * vfio_intp_interrupt - The user-side eventfd handler
- * @opaque: opaque pointer which in practice is the VFIOINTp handle
- *
- * the function is entered in event handler context:
- * the vIRQ is injected into the guest if there is no other active
- * or pending IRQ.
- */
-static void vfio_intp_interrupt(VFIOINTp *intp)
-{
- int ret;
- VFIOINTp *tmp;
- VFIOPlatformDevice *vdev = intp->vdev;
- bool delay_handling = false;
-
- qemu_mutex_lock(&vdev->intp_mutex);
- if (intp->state == VFIO_IRQ_INACTIVE) {
- QLIST_FOREACH(tmp, &vdev->intp_list, next) {
- if (tmp->state == VFIO_IRQ_ACTIVE ||
- tmp->state == VFIO_IRQ_PENDING) {
- delay_handling = true;
- break;
- }
- }
- }
- if (delay_handling) {
- /*
- * the new IRQ gets a pending status and is pushed in
- * the pending queue
- */
- intp->state = VFIO_IRQ_PENDING;
- trace_vfio_intp_interrupt_set_pending(intp->pin);
- QSIMPLEQ_INSERT_TAIL(&vdev->pending_intp_queue,
- intp, pqnext);
- ret = event_notifier_test_and_clear(intp->interrupt);
- qemu_mutex_unlock(&vdev->intp_mutex);
- return;
- }
-
- trace_vfio_platform_intp_interrupt(intp->pin,
- event_notifier_get_fd(intp->interrupt));
-
- ret = event_notifier_test_and_clear(intp->interrupt);
- if (!ret) {
- error_report("Error when clearing fd=%d (ret = %d)",
- event_notifier_get_fd(intp->interrupt), ret);
- }
-
- intp->state = VFIO_IRQ_ACTIVE;
-
- /* sets slow path */
- vfio_mmap_set_enabled(vdev, false);
-
- /* trigger the virtual IRQ */
- qemu_set_irq(intp->qemuirq, 1);
-
- /*
- * Schedule the mmap timer which will restore fastpath when no IRQ
- * is active anymore
- */
- if (vdev->mmap_timeout) {
- timer_mod(vdev->mmap_timer,
- qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
- vdev->mmap_timeout);
- }
- qemu_mutex_unlock(&vdev->intp_mutex);
-}
-
-/**
- * vfio_platform_eoi - IRQ completion routine
- * @vbasedev: the VFIO device handle
- *
- * De-asserts the active virtual IRQ and unmasks the physical IRQ
- * (effective for level sensitive IRQ auto-masked by the VFIO driver).
- * Then it handles next pending IRQ if any.
- * eoi function is called on the first access to any MMIO region
- * after an IRQ was triggered, trapped since slow path was set.
- * It is assumed this access corresponds to the IRQ status
- * register reset. With such a mechanism, a single IRQ can be
- * handled at a time since there is no way to know which IRQ
- * was completed by the guest (we would need additional details
- * about the IRQ status register mask).
- */
-static void vfio_platform_eoi(VFIODevice *vbasedev)
-{
- VFIOINTp *intp;
- VFIOPlatformDevice *vdev =
- container_of(vbasedev, VFIOPlatformDevice, vbasedev);
-
- qemu_mutex_lock(&vdev->intp_mutex);
- QLIST_FOREACH(intp, &vdev->intp_list, next) {
- if (intp->state == VFIO_IRQ_ACTIVE) {
- trace_vfio_platform_eoi(intp->pin,
- event_notifier_get_fd(intp->interrupt));
- intp->state = VFIO_IRQ_INACTIVE;
-
- /* deassert the virtual IRQ */
- qemu_set_irq(intp->qemuirq, 0);
-
- if (vfio_irq_is_automasked(intp)) {
- /* unmasks the physical level-sensitive IRQ */
- vfio_unmask_single_irqindex(vbasedev, intp->pin);
- }
-
- /* a single IRQ can be active at a time */
- break;
- }
- }
- /* in case there are pending IRQs, handle the first one */
- if (!QSIMPLEQ_EMPTY(&vdev->pending_intp_queue)) {
- intp = QSIMPLEQ_FIRST(&vdev->pending_intp_queue);
- vfio_intp_inject_pending_lockheld(intp);
- QSIMPLEQ_REMOVE_HEAD(&vdev->pending_intp_queue, pqnext);
- }
- qemu_mutex_unlock(&vdev->intp_mutex);
-}
-
-/**
- * vfio_start_eventfd_injection - starts the virtual IRQ injection using
- * user-side handled eventfds
- * @sbdev: the sysbus device handle
- * @irq: the qemu irq handle
- */
-
-static void vfio_start_eventfd_injection(SysBusDevice *sbdev, qemu_irq irq)
-{
- int ret;
- VFIOPlatformDevice *vdev = VFIO_PLATFORM_DEVICE(sbdev);
- VFIOINTp *intp;
-
- QLIST_FOREACH(intp, &vdev->intp_list, next) {
- if (intp->qemuirq == irq) {
- break;
- }
- }
- assert(intp);
-
- ret = vfio_set_trigger_eventfd(intp, vfio_intp_interrupt);
- if (ret) {
- error_report("vfio: failed to start eventfd signaling for IRQ %d: %m",
- intp->pin);
- abort();
- }
-}
-
-/*
- * Functions used for irqfd
- */
-
-/**
- * vfio_set_resample_eventfd - sets the resamplefd for an IRQ
- * @intp: the IRQ struct handle
- * programs the VFIO driver to unmask this IRQ when the
- * intp->unmask eventfd is triggered
- */
-static int vfio_set_resample_eventfd(VFIOINTp *intp)
-{
- VFIODevice *vbasedev = &intp->vdev->vbasedev;
- struct vfio_irq_set *irq_set;
- int argsz, ret;
- int32_t *pfd;
-
- argsz = sizeof(*irq_set) + sizeof(*pfd);
- irq_set = g_malloc0(argsz);
- irq_set->argsz = argsz;
- irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_UNMASK;
- irq_set->index = intp->pin;
- irq_set->start = 0;
- irq_set->count = 1;
- pfd = (int32_t *)&irq_set->data;
- *pfd = event_notifier_get_fd(intp->unmask);
- qemu_set_fd_handler(*pfd, NULL, NULL, NULL);
- ret = ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, irq_set);
- g_free(irq_set);
- if (ret < 0) {
- error_report("vfio: Failed to set resample eventfd: %m");
- }
- return ret;
-}
-
-/**
- * vfio_start_irqfd_injection - starts the virtual IRQ injection using
- * irqfd
- *
- * @sbdev: the sysbus device handle
- * @irq: the qemu irq handle
- *
- * In case the irqfd setup fails, we fallback to userspace handled eventfd
- */
-static void vfio_start_irqfd_injection(SysBusDevice *sbdev, qemu_irq irq)
-{
- VFIOPlatformDevice *vdev = VFIO_PLATFORM_DEVICE(sbdev);
- VFIOINTp *intp;
-
- if (!kvm_irqfds_enabled() || !kvm_resamplefds_enabled() ||
- !vdev->irqfd_allowed) {
- goto fail_irqfd;
- }
-
- QLIST_FOREACH(intp, &vdev->intp_list, next) {
- if (intp->qemuirq == irq) {
- break;
- }
- }
- assert(intp);
-
- if (kvm_irqchip_add_irqfd_notifier(kvm_state, intp->interrupt,
- intp->unmask, irq) < 0) {
- goto fail_irqfd;
- }
-
- if (vfio_set_trigger_eventfd(intp, NULL) < 0) {
- goto fail_vfio;
- }
- if (vfio_irq_is_automasked(intp)) {
- if (vfio_set_resample_eventfd(intp) < 0) {
- goto fail_vfio;
- }
- trace_vfio_platform_start_level_irqfd_injection(intp->pin,
- event_notifier_get_fd(intp->interrupt),
- event_notifier_get_fd(intp->unmask));
- } else {
- trace_vfio_platform_start_edge_irqfd_injection(intp->pin,
- event_notifier_get_fd(intp->interrupt));
- }
-
- intp->kvm_accel = true;
-
- return;
-fail_vfio:
- kvm_irqchip_remove_irqfd_notifier(kvm_state, intp->interrupt, irq);
- error_report("vfio: failed to start eventfd signaling for IRQ %d: %m",
- intp->pin);
- abort();
-fail_irqfd:
- vfio_start_eventfd_injection(sbdev, irq);
- return;
-}
-
-/* VFIO skeleton */
-
-static void vfio_platform_compute_needs_reset(VFIODevice *vbasedev)
-{
- vbasedev->needs_reset = true;
-}
-
-/* not implemented yet */
-static int vfio_platform_hot_reset_multi(VFIODevice *vbasedev)
-{
- return -1;
-}
-
-/**
- * vfio_populate_device - Allocate and populate MMIO region
- * and IRQ structs according to driver returned information
- * @vbasedev: the VFIO device handle
- *
- */
-static int vfio_populate_device(VFIODevice *vbasedev)
-{
- VFIOINTp *intp, *tmp;
- int i, ret = -1;
- VFIOPlatformDevice *vdev =
- container_of(vbasedev, VFIOPlatformDevice, vbasedev);
-
- if (!(vbasedev->flags & VFIO_DEVICE_FLAGS_PLATFORM)) {
- error_report("vfio: Um, this isn't a platform device");
- return ret;
- }
-
- vdev->regions = g_new0(VFIORegion *, vbasedev->num_regions);
-
- for (i = 0; i < vbasedev->num_regions; i++) {
- char *name = g_strdup_printf("VFIO %s region %d\n", vbasedev->name, i);
-
- vdev->regions[i] = g_new0(VFIORegion, 1);
- ret = vfio_region_setup(OBJECT(vdev), vbasedev,
- vdev->regions[i], i, name);
- g_free(name);
- if (ret) {
- error_report("vfio: Error getting region %d info: %m", i);
- goto reg_error;
- }
- }
-
- vdev->mmap_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL,
- vfio_intp_mmap_enable, vdev);
-
- QSIMPLEQ_INIT(&vdev->pending_intp_queue);
-
- for (i = 0; i < vbasedev->num_irqs; i++) {
- struct vfio_irq_info irq = { .argsz = sizeof(irq) };
-
- irq.index = i;
- ret = ioctl(vbasedev->fd, VFIO_DEVICE_GET_IRQ_INFO, &irq);
- if (ret) {
- error_printf("vfio: error getting device %s irq info",
- vbasedev->name);
- goto irq_err;
- } else {
- trace_vfio_platform_populate_interrupts(irq.index,
- irq.count,
- irq.flags);
- intp = vfio_init_intp(vbasedev, irq);
- if (!intp) {
- error_report("vfio: Error installing IRQ %d up", i);
- goto irq_err;
- }
- }
- }
- return 0;
-irq_err:
- timer_del(vdev->mmap_timer);
- QLIST_FOREACH_SAFE(intp, &vdev->intp_list, next, tmp) {
- QLIST_REMOVE(intp, next);
- g_free(intp);
- }
-reg_error:
- for (i = 0; i < vbasedev->num_regions; i++) {
- if (vdev->regions[i]) {
- vfio_region_finalize(vdev->regions[i]);
- }
- g_free(vdev->regions[i]);
- }
- g_free(vdev->regions);
- return ret;
-}
-
-/* specialized functions for VFIO Platform devices */
-static VFIODeviceOps vfio_platform_ops = {
- .vfio_compute_needs_reset = vfio_platform_compute_needs_reset,
- .vfio_hot_reset_multi = vfio_platform_hot_reset_multi,
- .vfio_eoi = vfio_platform_eoi,
-};
-
-/**
- * vfio_base_device_init - perform preliminary VFIO setup
- * @vbasedev: the VFIO device handle
- *
- * Implement the VFIO command sequence that allows to discover
- * assigned device resources: group extraction, device
- * fd retrieval, resource query.
- * Precondition: the device name must be initialized
- */
-static int vfio_base_device_init(VFIODevice *vbasedev)
-{
- VFIOGroup *group;
- VFIODevice *vbasedev_iter;
- char *tmp, group_path[PATH_MAX], *group_name;
- ssize_t len;
- struct stat st;
- int groupid;
- int ret;
-
- /* @sysfsdev takes precedence over @host */
- if (vbasedev->sysfsdev) {
- g_free(vbasedev->name);
- vbasedev->name = g_strdup(basename(vbasedev->sysfsdev));
- } else {
- if (!vbasedev->name || strchr(vbasedev->name, '/')) {
- return -EINVAL;
- }
-
- vbasedev->sysfsdev = g_strdup_printf("/sys/bus/platform/devices/%s",
- vbasedev->name);
- }
-
- if (stat(vbasedev->sysfsdev, &st) < 0) {
- error_report("vfio: error: no such host device: %s",
- vbasedev->sysfsdev);
- return -errno;
- }
-
- tmp = g_strdup_printf("%s/iommu_group", vbasedev->sysfsdev);
- len = readlink(tmp, group_path, sizeof(group_path));
- g_free(tmp);
-
- if (len < 0 || len >= sizeof(group_path)) {
- error_report("vfio: error no iommu_group for device");
- return len < 0 ? -errno : -ENAMETOOLONG;
- }
-
- group_path[len] = 0;
-
- group_name = basename(group_path);
- if (sscanf(group_name, "%d", &groupid) != 1) {
- error_report("vfio: error reading %s: %m", group_path);
- return -errno;
- }
-
- trace_vfio_platform_base_device_init(vbasedev->name, groupid);
-
- group = vfio_get_group(groupid, &address_space_memory);
- if (!group) {
- error_report("vfio: failed to get group %d", groupid);
- return -ENOENT;
- }
-
- QLIST_FOREACH(vbasedev_iter, &group->device_list, next) {
- if (strcmp(vbasedev_iter->name, vbasedev->name) == 0) {
- error_report("vfio: error: device %s is already attached",
- vbasedev->name);
- vfio_put_group(group);
- return -EBUSY;
- }
- }
- ret = vfio_get_device(group, vbasedev->name, vbasedev);
- if (ret) {
- error_report("vfio: failed to get device %s", vbasedev->name);
- vfio_put_group(group);
- return ret;
- }
-
- ret = vfio_populate_device(vbasedev);
- if (ret) {
- error_report("vfio: failed to populate device %s", vbasedev->name);
- vfio_put_group(group);
- }
-
- return ret;
-}
-
-/**
- * vfio_platform_realize - the device realize function
- * @dev: device state pointer
- * @errp: error
- *
- * initialize the device, its memory regions and IRQ structures
- * IRQ are started separately
- */
-static void vfio_platform_realize(DeviceState *dev, Error **errp)
-{
- VFIOPlatformDevice *vdev = VFIO_PLATFORM_DEVICE(dev);
- SysBusDevice *sbdev = SYS_BUS_DEVICE(dev);
- VFIODevice *vbasedev = &vdev->vbasedev;
- int i, ret;
-
- vbasedev->type = VFIO_DEVICE_TYPE_PLATFORM;
- vbasedev->ops = &vfio_platform_ops;
-
- trace_vfio_platform_realize(vbasedev->sysfsdev ?
- vbasedev->sysfsdev : vbasedev->name,
- vdev->compat);
-
- ret = vfio_base_device_init(vbasedev);
- if (ret) {
- error_setg(errp, "vfio: vfio_base_device_init failed for %s",
- vbasedev->name);
- return;
- }
-
- for (i = 0; i < vbasedev->num_regions; i++) {
- if (vfio_region_mmap(vdev->regions[i])) {
- error_report("%s mmap unsupported. Performance may be slow",
- memory_region_name(vdev->regions[i]->mem));
- }
- sysbus_init_mmio(sbdev, vdev->regions[i]->mem);
- }
-}
-
-static const VMStateDescription vfio_platform_vmstate = {
- .name = TYPE_VFIO_PLATFORM,
- .unmigratable = 1,
-};
-
-static Property vfio_platform_dev_properties[] = {
- DEFINE_PROP_STRING("host", VFIOPlatformDevice, vbasedev.name),
- DEFINE_PROP_STRING("sysfsdev", VFIOPlatformDevice, vbasedev.sysfsdev),
- DEFINE_PROP_BOOL("x-no-mmap", VFIOPlatformDevice, vbasedev.no_mmap, false),
- DEFINE_PROP_UINT32("mmap-timeout-ms", VFIOPlatformDevice,
- mmap_timeout, 1100),
- DEFINE_PROP_BOOL("x-irqfd", VFIOPlatformDevice, irqfd_allowed, true),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void vfio_platform_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
-
- dc->realize = vfio_platform_realize;
- dc->props = vfio_platform_dev_properties;
- dc->vmsd = &vfio_platform_vmstate;
- dc->desc = "VFIO-based platform device assignment";
- sbc->connect_irq_notifier = vfio_start_irqfd_injection;
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
-}
-
-static const TypeInfo vfio_platform_dev_info = {
- .name = TYPE_VFIO_PLATFORM,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(VFIOPlatformDevice),
- .class_init = vfio_platform_class_init,
- .class_size = sizeof(VFIOPlatformDeviceClass),
- .abstract = true,
-};
-
-static void register_vfio_platform_dev_type(void)
-{
- type_register_static(&vfio_platform_dev_info);
-}
-
-type_init(register_vfio_platform_dev_type)
diff --git a/qemu/hw/virtio/Makefile.objs b/qemu/hw/virtio/Makefile.objs
deleted file mode 100644
index 3e2b175da..000000000
--- a/qemu/hw/virtio/Makefile.objs
+++ /dev/null
@@ -1,7 +0,0 @@
-common-obj-y += virtio-rng.o
-common-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
-common-obj-y += virtio-bus.o
-common-obj-y += virtio-mmio.o
-
-obj-y += virtio.o virtio-balloon.o
-obj-$(CONFIG_LINUX) += vhost.o vhost-backend.o vhost-user.o
diff --git a/qemu/hw/virtio/vhost-backend.c b/qemu/hw/virtio/vhost-backend.c
deleted file mode 100644
index b35890289..000000000
--- a/qemu/hw/virtio/vhost-backend.c
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * vhost-backend
- *
- * Copyright (c) 2013 Virtual Open Systems Sarl.
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "hw/virtio/vhost.h"
-#include "hw/virtio/vhost-backend.h"
-#include "qemu/error-report.h"
-#include "linux/vhost.h"
-
-#include <sys/ioctl.h>
-
-static int vhost_kernel_call(struct vhost_dev *dev, unsigned long int request,
- void *arg)
-{
- int fd = (uintptr_t) dev->opaque;
-
- assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_KERNEL);
-
- return ioctl(fd, request, arg);
-}
-
-static int vhost_kernel_init(struct vhost_dev *dev, void *opaque)
-{
- assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_KERNEL);
-
- dev->opaque = opaque;
-
- return 0;
-}
-
-static int vhost_kernel_cleanup(struct vhost_dev *dev)
-{
- int fd = (uintptr_t) dev->opaque;
-
- assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_KERNEL);
-
- return close(fd);
-}
-
-static int vhost_kernel_memslots_limit(struct vhost_dev *dev)
-{
- int limit = 64;
- char *s;
-
- if (g_file_get_contents("/sys/module/vhost/parameters/max_mem_regions",
- &s, NULL, NULL)) {
- uint64_t val = g_ascii_strtoull(s, NULL, 10);
- if (!((val == G_MAXUINT64 || !val) && errno)) {
- return val;
- }
- error_report("ignoring invalid max_mem_regions value in vhost module:"
- " %s", s);
- }
- return limit;
-}
-
-static int vhost_kernel_net_set_backend(struct vhost_dev *dev,
- struct vhost_vring_file *file)
-{
- return vhost_kernel_call(dev, VHOST_NET_SET_BACKEND, file);
-}
-
-static int vhost_kernel_scsi_set_endpoint(struct vhost_dev *dev,
- struct vhost_scsi_target *target)
-{
- return vhost_kernel_call(dev, VHOST_SCSI_SET_ENDPOINT, target);
-}
-
-static int vhost_kernel_scsi_clear_endpoint(struct vhost_dev *dev,
- struct vhost_scsi_target *target)
-{
- return vhost_kernel_call(dev, VHOST_SCSI_CLEAR_ENDPOINT, target);
-}
-
-static int vhost_kernel_scsi_get_abi_version(struct vhost_dev *dev, int *version)
-{
- return vhost_kernel_call(dev, VHOST_SCSI_GET_ABI_VERSION, version);
-}
-
-static int vhost_kernel_set_log_base(struct vhost_dev *dev, uint64_t base,
- struct vhost_log *log)
-{
- return vhost_kernel_call(dev, VHOST_SET_LOG_BASE, &base);
-}
-
-static int vhost_kernel_set_mem_table(struct vhost_dev *dev,
- struct vhost_memory *mem)
-{
- return vhost_kernel_call(dev, VHOST_SET_MEM_TABLE, mem);
-}
-
-static int vhost_kernel_set_vring_addr(struct vhost_dev *dev,
- struct vhost_vring_addr *addr)
-{
- return vhost_kernel_call(dev, VHOST_SET_VRING_ADDR, addr);
-}
-
-static int vhost_kernel_set_vring_endian(struct vhost_dev *dev,
- struct vhost_vring_state *ring)
-{
- return vhost_kernel_call(dev, VHOST_SET_VRING_ENDIAN, ring);
-}
-
-static int vhost_kernel_set_vring_num(struct vhost_dev *dev,
- struct vhost_vring_state *ring)
-{
- return vhost_kernel_call(dev, VHOST_SET_VRING_NUM, ring);
-}
-
-static int vhost_kernel_set_vring_base(struct vhost_dev *dev,
- struct vhost_vring_state *ring)
-{
- return vhost_kernel_call(dev, VHOST_SET_VRING_BASE, ring);
-}
-
-static int vhost_kernel_get_vring_base(struct vhost_dev *dev,
- struct vhost_vring_state *ring)
-{
- return vhost_kernel_call(dev, VHOST_GET_VRING_BASE, ring);
-}
-
-static int vhost_kernel_set_vring_kick(struct vhost_dev *dev,
- struct vhost_vring_file *file)
-{
- return vhost_kernel_call(dev, VHOST_SET_VRING_KICK, file);
-}
-
-static int vhost_kernel_set_vring_call(struct vhost_dev *dev,
- struct vhost_vring_file *file)
-{
- return vhost_kernel_call(dev, VHOST_SET_VRING_CALL, file);
-}
-
-static int vhost_kernel_set_features(struct vhost_dev *dev,
- uint64_t features)
-{
- return vhost_kernel_call(dev, VHOST_SET_FEATURES, &features);
-}
-
-static int vhost_kernel_get_features(struct vhost_dev *dev,
- uint64_t *features)
-{
- return vhost_kernel_call(dev, VHOST_GET_FEATURES, features);
-}
-
-static int vhost_kernel_set_owner(struct vhost_dev *dev)
-{
- return vhost_kernel_call(dev, VHOST_SET_OWNER, NULL);
-}
-
-static int vhost_kernel_reset_device(struct vhost_dev *dev)
-{
- return vhost_kernel_call(dev, VHOST_RESET_OWNER, NULL);
-}
-
-static int vhost_kernel_get_vq_index(struct vhost_dev *dev, int idx)
-{
- assert(idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs);
-
- return idx - dev->vq_index;
-}
-
-static const VhostOps kernel_ops = {
- .backend_type = VHOST_BACKEND_TYPE_KERNEL,
- .vhost_backend_init = vhost_kernel_init,
- .vhost_backend_cleanup = vhost_kernel_cleanup,
- .vhost_backend_memslots_limit = vhost_kernel_memslots_limit,
- .vhost_net_set_backend = vhost_kernel_net_set_backend,
- .vhost_scsi_set_endpoint = vhost_kernel_scsi_set_endpoint,
- .vhost_scsi_clear_endpoint = vhost_kernel_scsi_clear_endpoint,
- .vhost_scsi_get_abi_version = vhost_kernel_scsi_get_abi_version,
- .vhost_set_log_base = vhost_kernel_set_log_base,
- .vhost_set_mem_table = vhost_kernel_set_mem_table,
- .vhost_set_vring_addr = vhost_kernel_set_vring_addr,
- .vhost_set_vring_endian = vhost_kernel_set_vring_endian,
- .vhost_set_vring_num = vhost_kernel_set_vring_num,
- .vhost_set_vring_base = vhost_kernel_set_vring_base,
- .vhost_get_vring_base = vhost_kernel_get_vring_base,
- .vhost_set_vring_kick = vhost_kernel_set_vring_kick,
- .vhost_set_vring_call = vhost_kernel_set_vring_call,
- .vhost_set_features = vhost_kernel_set_features,
- .vhost_get_features = vhost_kernel_get_features,
- .vhost_set_owner = vhost_kernel_set_owner,
- .vhost_reset_device = vhost_kernel_reset_device,
- .vhost_get_vq_index = vhost_kernel_get_vq_index,
-};
-
-int vhost_set_backend_type(struct vhost_dev *dev, VhostBackendType backend_type)
-{
- int r = 0;
-
- switch (backend_type) {
- case VHOST_BACKEND_TYPE_KERNEL:
- dev->vhost_ops = &kernel_ops;
- break;
- case VHOST_BACKEND_TYPE_USER:
- dev->vhost_ops = &user_ops;
- break;
- default:
- error_report("Unknown vhost backend type");
- r = -1;
- }
-
- return r;
-}
diff --git a/qemu/hw/virtio/vhost-user.c b/qemu/hw/virtio/vhost-user.c
deleted file mode 100644
index 5914e8510..000000000
--- a/qemu/hw/virtio/vhost-user.c
+++ /dev/null
@@ -1,657 +0,0 @@
-/*
- * vhost-user
- *
- * Copyright (c) 2013 Virtual Open Systems Sarl.
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/virtio/vhost.h"
-#include "hw/virtio/vhost-backend.h"
-#include "hw/virtio/virtio-net.h"
-#include "sysemu/char.h"
-#include "sysemu/kvm.h"
-#include "qemu/error-report.h"
-#include "qemu/sockets.h"
-#include "exec/ram_addr.h"
-#include "migration/migration.h"
-
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <linux/vhost.h>
-
-#define VHOST_MEMORY_MAX_NREGIONS 8
-#define VHOST_USER_F_PROTOCOL_FEATURES 30
-
-enum VhostUserProtocolFeature {
- VHOST_USER_PROTOCOL_F_MQ = 0,
- VHOST_USER_PROTOCOL_F_LOG_SHMFD = 1,
- VHOST_USER_PROTOCOL_F_RARP = 2,
-
- VHOST_USER_PROTOCOL_F_MAX
-};
-
-#define VHOST_USER_PROTOCOL_FEATURE_MASK ((1 << VHOST_USER_PROTOCOL_F_MAX) - 1)
-
-typedef enum VhostUserRequest {
- VHOST_USER_NONE = 0,
- VHOST_USER_GET_FEATURES = 1,
- VHOST_USER_SET_FEATURES = 2,
- VHOST_USER_SET_OWNER = 3,
- VHOST_USER_RESET_OWNER = 4,
- VHOST_USER_SET_MEM_TABLE = 5,
- VHOST_USER_SET_LOG_BASE = 6,
- VHOST_USER_SET_LOG_FD = 7,
- VHOST_USER_SET_VRING_NUM = 8,
- VHOST_USER_SET_VRING_ADDR = 9,
- VHOST_USER_SET_VRING_BASE = 10,
- VHOST_USER_GET_VRING_BASE = 11,
- VHOST_USER_SET_VRING_KICK = 12,
- VHOST_USER_SET_VRING_CALL = 13,
- VHOST_USER_SET_VRING_ERR = 14,
- VHOST_USER_GET_PROTOCOL_FEATURES = 15,
- VHOST_USER_SET_PROTOCOL_FEATURES = 16,
- VHOST_USER_GET_QUEUE_NUM = 17,
- VHOST_USER_SET_VRING_ENABLE = 18,
- VHOST_USER_SEND_RARP = 19,
- VHOST_USER_MAX
-} VhostUserRequest;
-
-typedef struct VhostUserMemoryRegion {
- uint64_t guest_phys_addr;
- uint64_t memory_size;
- uint64_t userspace_addr;
- uint64_t mmap_offset;
-} VhostUserMemoryRegion;
-
-typedef struct VhostUserMemory {
- uint32_t nregions;
- uint32_t padding;
- VhostUserMemoryRegion regions[VHOST_MEMORY_MAX_NREGIONS];
-} VhostUserMemory;
-
-typedef struct VhostUserLog {
- uint64_t mmap_size;
- uint64_t mmap_offset;
-} VhostUserLog;
-
-typedef struct VhostUserMsg {
- VhostUserRequest request;
-
-#define VHOST_USER_VERSION_MASK (0x3)
-#define VHOST_USER_REPLY_MASK (0x1<<2)
- uint32_t flags;
- uint32_t size; /* the following payload size */
- union {
-#define VHOST_USER_VRING_IDX_MASK (0xff)
-#define VHOST_USER_VRING_NOFD_MASK (0x1<<8)
- uint64_t u64;
- struct vhost_vring_state state;
- struct vhost_vring_addr addr;
- VhostUserMemory memory;
- VhostUserLog log;
- } payload;
-} QEMU_PACKED VhostUserMsg;
-
-static VhostUserMsg m __attribute__ ((unused));
-#define VHOST_USER_HDR_SIZE (sizeof(m.request) \
- + sizeof(m.flags) \
- + sizeof(m.size))
-
-#define VHOST_USER_PAYLOAD_SIZE (sizeof(m) - VHOST_USER_HDR_SIZE)
-
-/* The version of the protocol we support */
-#define VHOST_USER_VERSION (0x1)
-
-static bool ioeventfd_enabled(void)
-{
- return kvm_enabled() && kvm_eventfds_enabled();
-}
-
-static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg)
-{
- CharDriverState *chr = dev->opaque;
- uint8_t *p = (uint8_t *) msg;
- int r, size = VHOST_USER_HDR_SIZE;
-
- r = qemu_chr_fe_read_all(chr, p, size);
- if (r != size) {
- error_report("Failed to read msg header. Read %d instead of %d."
- " Original request %d.", r, size, msg->request);
- goto fail;
- }
-
- /* validate received flags */
- if (msg->flags != (VHOST_USER_REPLY_MASK | VHOST_USER_VERSION)) {
- error_report("Failed to read msg header."
- " Flags 0x%x instead of 0x%x.", msg->flags,
- VHOST_USER_REPLY_MASK | VHOST_USER_VERSION);
- goto fail;
- }
-
- /* validate message size is sane */
- if (msg->size > VHOST_USER_PAYLOAD_SIZE) {
- error_report("Failed to read msg header."
- " Size %d exceeds the maximum %zu.", msg->size,
- VHOST_USER_PAYLOAD_SIZE);
- goto fail;
- }
-
- if (msg->size) {
- p += VHOST_USER_HDR_SIZE;
- size = msg->size;
- r = qemu_chr_fe_read_all(chr, p, size);
- if (r != size) {
- error_report("Failed to read msg payload."
- " Read %d instead of %d.", r, msg->size);
- goto fail;
- }
- }
-
- return 0;
-
-fail:
- return -1;
-}
-
-static bool vhost_user_one_time_request(VhostUserRequest request)
-{
- switch (request) {
- case VHOST_USER_SET_OWNER:
- case VHOST_USER_RESET_OWNER:
- case VHOST_USER_SET_MEM_TABLE:
- case VHOST_USER_GET_QUEUE_NUM:
- return true;
- default:
- return false;
- }
-}
-
-/* most non-init callers ignore the error */
-static int vhost_user_write(struct vhost_dev *dev, VhostUserMsg *msg,
- int *fds, int fd_num)
-{
- CharDriverState *chr = dev->opaque;
- int size = VHOST_USER_HDR_SIZE + msg->size;
-
- /*
- * For non-vring specific requests, like VHOST_USER_SET_MEM_TABLE,
- * we just need send it once in the first time. For later such
- * request, we just ignore it.
- */
- if (vhost_user_one_time_request(msg->request) && dev->vq_index != 0) {
- return 0;
- }
-
- if (fd_num) {
- qemu_chr_fe_set_msgfds(chr, fds, fd_num);
- }
-
- return qemu_chr_fe_write_all(chr, (const uint8_t *) msg, size) == size ?
- 0 : -1;
-}
-
-static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base,
- struct vhost_log *log)
-{
- int fds[VHOST_MEMORY_MAX_NREGIONS];
- size_t fd_num = 0;
- bool shmfd = virtio_has_feature(dev->protocol_features,
- VHOST_USER_PROTOCOL_F_LOG_SHMFD);
- VhostUserMsg msg = {
- .request = VHOST_USER_SET_LOG_BASE,
- .flags = VHOST_USER_VERSION,
- .payload.log.mmap_size = log->size * sizeof(*(log->log)),
- .payload.log.mmap_offset = 0,
- .size = sizeof(msg.payload.log),
- };
-
- if (shmfd && log->fd != -1) {
- fds[fd_num++] = log->fd;
- }
-
- vhost_user_write(dev, &msg, fds, fd_num);
-
- if (shmfd) {
- msg.size = 0;
- if (vhost_user_read(dev, &msg) < 0) {
- return 0;
- }
-
- if (msg.request != VHOST_USER_SET_LOG_BASE) {
- error_report("Received unexpected msg type. "
- "Expected %d received %d",
- VHOST_USER_SET_LOG_BASE, msg.request);
- return -1;
- }
- }
-
- return 0;
-}
-
-static int vhost_user_set_mem_table(struct vhost_dev *dev,
- struct vhost_memory *mem)
-{
- int fds[VHOST_MEMORY_MAX_NREGIONS];
- int i, fd;
- size_t fd_num = 0;
- VhostUserMsg msg = {
- .request = VHOST_USER_SET_MEM_TABLE,
- .flags = VHOST_USER_VERSION,
- };
-
- for (i = 0; i < dev->mem->nregions; ++i) {
- struct vhost_memory_region *reg = dev->mem->regions + i;
- ram_addr_t ram_addr;
-
- assert((uintptr_t)reg->userspace_addr == reg->userspace_addr);
- qemu_ram_addr_from_host((void *)(uintptr_t)reg->userspace_addr,
- &ram_addr);
- fd = qemu_get_ram_fd(ram_addr);
- if (fd > 0) {
- msg.payload.memory.regions[fd_num].userspace_addr = reg->userspace_addr;
- msg.payload.memory.regions[fd_num].memory_size = reg->memory_size;
- msg.payload.memory.regions[fd_num].guest_phys_addr = reg->guest_phys_addr;
- msg.payload.memory.regions[fd_num].mmap_offset = reg->userspace_addr -
- (uintptr_t) qemu_get_ram_block_host_ptr(ram_addr);
- assert(fd_num < VHOST_MEMORY_MAX_NREGIONS);
- fds[fd_num++] = fd;
- }
- }
-
- msg.payload.memory.nregions = fd_num;
-
- if (!fd_num) {
- error_report("Failed initializing vhost-user memory map, "
- "consider using -object memory-backend-file share=on");
- return -1;
- }
-
- msg.size = sizeof(msg.payload.memory.nregions);
- msg.size += sizeof(msg.payload.memory.padding);
- msg.size += fd_num * sizeof(VhostUserMemoryRegion);
-
- vhost_user_write(dev, &msg, fds, fd_num);
-
- return 0;
-}
-
-static int vhost_user_set_vring_addr(struct vhost_dev *dev,
- struct vhost_vring_addr *addr)
-{
- VhostUserMsg msg = {
- .request = VHOST_USER_SET_VRING_ADDR,
- .flags = VHOST_USER_VERSION,
- .payload.addr = *addr,
- .size = sizeof(msg.payload.addr),
- };
-
- vhost_user_write(dev, &msg, NULL, 0);
-
- return 0;
-}
-
-static int vhost_user_set_vring_endian(struct vhost_dev *dev,
- struct vhost_vring_state *ring)
-{
- error_report("vhost-user trying to send unhandled ioctl");
- return -1;
-}
-
-static int vhost_set_vring(struct vhost_dev *dev,
- unsigned long int request,
- struct vhost_vring_state *ring)
-{
- VhostUserMsg msg = {
- .request = request,
- .flags = VHOST_USER_VERSION,
- .payload.state = *ring,
- .size = sizeof(msg.payload.state),
- };
-
- vhost_user_write(dev, &msg, NULL, 0);
-
- return 0;
-}
-
-static int vhost_user_set_vring_num(struct vhost_dev *dev,
- struct vhost_vring_state *ring)
-{
- return vhost_set_vring(dev, VHOST_USER_SET_VRING_NUM, ring);
-}
-
-static int vhost_user_set_vring_base(struct vhost_dev *dev,
- struct vhost_vring_state *ring)
-{
- return vhost_set_vring(dev, VHOST_USER_SET_VRING_BASE, ring);
-}
-
-static int vhost_user_set_vring_enable(struct vhost_dev *dev, int enable)
-{
- int i;
-
- if (!virtio_has_feature(dev->features, VHOST_USER_F_PROTOCOL_FEATURES)) {
- return -1;
- }
-
- for (i = 0; i < dev->nvqs; ++i) {
- struct vhost_vring_state state = {
- .index = dev->vq_index + i,
- .num = enable,
- };
-
- vhost_set_vring(dev, VHOST_USER_SET_VRING_ENABLE, &state);
- }
-
- return 0;
-}
-
-static int vhost_user_get_vring_base(struct vhost_dev *dev,
- struct vhost_vring_state *ring)
-{
- VhostUserMsg msg = {
- .request = VHOST_USER_GET_VRING_BASE,
- .flags = VHOST_USER_VERSION,
- .payload.state = *ring,
- .size = sizeof(msg.payload.state),
- };
-
- vhost_user_write(dev, &msg, NULL, 0);
-
- if (vhost_user_read(dev, &msg) < 0) {
- return 0;
- }
-
- if (msg.request != VHOST_USER_GET_VRING_BASE) {
- error_report("Received unexpected msg type. Expected %d received %d",
- VHOST_USER_GET_VRING_BASE, msg.request);
- return -1;
- }
-
- if (msg.size != sizeof(msg.payload.state)) {
- error_report("Received bad msg size.");
- return -1;
- }
-
- *ring = msg.payload.state;
-
- return 0;
-}
-
-static int vhost_set_vring_file(struct vhost_dev *dev,
- VhostUserRequest request,
- struct vhost_vring_file *file)
-{
- int fds[VHOST_MEMORY_MAX_NREGIONS];
- size_t fd_num = 0;
- VhostUserMsg msg = {
- .request = request,
- .flags = VHOST_USER_VERSION,
- .payload.u64 = file->index & VHOST_USER_VRING_IDX_MASK,
- .size = sizeof(msg.payload.u64),
- };
-
- if (ioeventfd_enabled() && file->fd > 0) {
- fds[fd_num++] = file->fd;
- } else {
- msg.payload.u64 |= VHOST_USER_VRING_NOFD_MASK;
- }
-
- vhost_user_write(dev, &msg, fds, fd_num);
-
- return 0;
-}
-
-static int vhost_user_set_vring_kick(struct vhost_dev *dev,
- struct vhost_vring_file *file)
-{
- return vhost_set_vring_file(dev, VHOST_USER_SET_VRING_KICK, file);
-}
-
-static int vhost_user_set_vring_call(struct vhost_dev *dev,
- struct vhost_vring_file *file)
-{
- return vhost_set_vring_file(dev, VHOST_USER_SET_VRING_CALL, file);
-}
-
-static int vhost_user_set_u64(struct vhost_dev *dev, int request, uint64_t u64)
-{
- VhostUserMsg msg = {
- .request = request,
- .flags = VHOST_USER_VERSION,
- .payload.u64 = u64,
- .size = sizeof(msg.payload.u64),
- };
-
- vhost_user_write(dev, &msg, NULL, 0);
-
- return 0;
-}
-
-static int vhost_user_set_features(struct vhost_dev *dev,
- uint64_t features)
-{
- return vhost_user_set_u64(dev, VHOST_USER_SET_FEATURES, features);
-}
-
-static int vhost_user_set_protocol_features(struct vhost_dev *dev,
- uint64_t features)
-{
- return vhost_user_set_u64(dev, VHOST_USER_SET_PROTOCOL_FEATURES, features);
-}
-
-static int vhost_user_get_u64(struct vhost_dev *dev, int request, uint64_t *u64)
-{
- VhostUserMsg msg = {
- .request = request,
- .flags = VHOST_USER_VERSION,
- };
-
- if (vhost_user_one_time_request(request) && dev->vq_index != 0) {
- return 0;
- }
-
- vhost_user_write(dev, &msg, NULL, 0);
-
- if (vhost_user_read(dev, &msg) < 0) {
- return 0;
- }
-
- if (msg.request != request) {
- error_report("Received unexpected msg type. Expected %d received %d",
- request, msg.request);
- return -1;
- }
-
- if (msg.size != sizeof(msg.payload.u64)) {
- error_report("Received bad msg size.");
- return -1;
- }
-
- *u64 = msg.payload.u64;
-
- return 0;
-}
-
-static int vhost_user_get_features(struct vhost_dev *dev, uint64_t *features)
-{
- return vhost_user_get_u64(dev, VHOST_USER_GET_FEATURES, features);
-}
-
-static int vhost_user_set_owner(struct vhost_dev *dev)
-{
- VhostUserMsg msg = {
- .request = VHOST_USER_SET_OWNER,
- .flags = VHOST_USER_VERSION,
- };
-
- vhost_user_write(dev, &msg, NULL, 0);
-
- return 0;
-}
-
-static int vhost_user_reset_device(struct vhost_dev *dev)
-{
- VhostUserMsg msg = {
- .request = VHOST_USER_RESET_OWNER,
- .flags = VHOST_USER_VERSION,
- };
-
- vhost_user_write(dev, &msg, NULL, 0);
-
- return 0;
-}
-
-static int vhost_user_init(struct vhost_dev *dev, void *opaque)
-{
- uint64_t features;
- int err;
-
- assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER);
-
- dev->opaque = opaque;
-
- err = vhost_user_get_features(dev, &features);
- if (err < 0) {
- return err;
- }
-
- if (virtio_has_feature(features, VHOST_USER_F_PROTOCOL_FEATURES)) {
- dev->backend_features |= 1ULL << VHOST_USER_F_PROTOCOL_FEATURES;
-
- err = vhost_user_get_u64(dev, VHOST_USER_GET_PROTOCOL_FEATURES,
- &features);
- if (err < 0) {
- return err;
- }
-
- dev->protocol_features = features & VHOST_USER_PROTOCOL_FEATURE_MASK;
- err = vhost_user_set_protocol_features(dev, dev->protocol_features);
- if (err < 0) {
- return err;
- }
-
- /* query the max queues we support if backend supports Multiple Queue */
- if (dev->protocol_features & (1ULL << VHOST_USER_PROTOCOL_F_MQ)) {
- err = vhost_user_get_u64(dev, VHOST_USER_GET_QUEUE_NUM,
- &dev->max_queues);
- if (err < 0) {
- return err;
- }
- }
- }
-
- if (dev->migration_blocker == NULL &&
- !virtio_has_feature(dev->protocol_features,
- VHOST_USER_PROTOCOL_F_LOG_SHMFD)) {
- error_setg(&dev->migration_blocker,
- "Migration disabled: vhost-user backend lacks "
- "VHOST_USER_PROTOCOL_F_LOG_SHMFD feature.");
- }
-
- return 0;
-}
-
-static int vhost_user_cleanup(struct vhost_dev *dev)
-{
- assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER);
-
- dev->opaque = 0;
-
- return 0;
-}
-
-static int vhost_user_get_vq_index(struct vhost_dev *dev, int idx)
-{
- assert(idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs);
-
- return idx;
-}
-
-static int vhost_user_memslots_limit(struct vhost_dev *dev)
-{
- return VHOST_MEMORY_MAX_NREGIONS;
-}
-
-static bool vhost_user_requires_shm_log(struct vhost_dev *dev)
-{
- assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER);
-
- return virtio_has_feature(dev->protocol_features,
- VHOST_USER_PROTOCOL_F_LOG_SHMFD);
-}
-
-static int vhost_user_migration_done(struct vhost_dev *dev, char* mac_addr)
-{
- VhostUserMsg msg = { 0 };
- int err;
-
- assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER);
-
- /* If guest supports GUEST_ANNOUNCE do nothing */
- if (virtio_has_feature(dev->acked_features, VIRTIO_NET_F_GUEST_ANNOUNCE)) {
- return 0;
- }
-
- /* if backend supports VHOST_USER_PROTOCOL_F_RARP ask it to send the RARP */
- if (virtio_has_feature(dev->protocol_features,
- VHOST_USER_PROTOCOL_F_RARP)) {
- msg.request = VHOST_USER_SEND_RARP;
- msg.flags = VHOST_USER_VERSION;
- memcpy((char *)&msg.payload.u64, mac_addr, 6);
- msg.size = sizeof(msg.payload.u64);
-
- err = vhost_user_write(dev, &msg, NULL, 0);
- return err;
- }
- return -1;
-}
-
-static bool vhost_user_can_merge(struct vhost_dev *dev,
- uint64_t start1, uint64_t size1,
- uint64_t start2, uint64_t size2)
-{
- ram_addr_t ram_addr;
- int mfd, rfd;
- MemoryRegion *mr;
-
- mr = qemu_ram_addr_from_host((void *)(uintptr_t)start1, &ram_addr);
- assert(mr);
- mfd = qemu_get_ram_fd(ram_addr);
-
- mr = qemu_ram_addr_from_host((void *)(uintptr_t)start2, &ram_addr);
- assert(mr);
- rfd = qemu_get_ram_fd(ram_addr);
-
- return mfd == rfd;
-}
-
-const VhostOps user_ops = {
- .backend_type = VHOST_BACKEND_TYPE_USER,
- .vhost_backend_init = vhost_user_init,
- .vhost_backend_cleanup = vhost_user_cleanup,
- .vhost_backend_memslots_limit = vhost_user_memslots_limit,
- .vhost_set_log_base = vhost_user_set_log_base,
- .vhost_set_mem_table = vhost_user_set_mem_table,
- .vhost_set_vring_addr = vhost_user_set_vring_addr,
- .vhost_set_vring_endian = vhost_user_set_vring_endian,
- .vhost_set_vring_num = vhost_user_set_vring_num,
- .vhost_set_vring_base = vhost_user_set_vring_base,
- .vhost_get_vring_base = vhost_user_get_vring_base,
- .vhost_set_vring_kick = vhost_user_set_vring_kick,
- .vhost_set_vring_call = vhost_user_set_vring_call,
- .vhost_set_features = vhost_user_set_features,
- .vhost_get_features = vhost_user_get_features,
- .vhost_set_owner = vhost_user_set_owner,
- .vhost_reset_device = vhost_user_reset_device,
- .vhost_get_vq_index = vhost_user_get_vq_index,
- .vhost_set_vring_enable = vhost_user_set_vring_enable,
- .vhost_requires_shm_log = vhost_user_requires_shm_log,
- .vhost_migration_done = vhost_user_migration_done,
- .vhost_backend_can_merge = vhost_user_can_merge,
-};
diff --git a/qemu/hw/virtio/vhost.c b/qemu/hw/virtio/vhost.c
deleted file mode 100644
index 440071815..000000000
--- a/qemu/hw/virtio/vhost.c
+++ /dev/null
@@ -1,1301 +0,0 @@
-/*
- * vhost support
- *
- * Copyright Red Hat, Inc. 2010
- *
- * Authors:
- * Michael S. Tsirkin <mst@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/virtio/vhost.h"
-#include "hw/hw.h"
-#include "qemu/atomic.h"
-#include "qemu/range.h"
-#include "qemu/error-report.h"
-#include "qemu/memfd.h"
-#include <linux/vhost.h>
-#include "exec/address-spaces.h"
-#include "hw/virtio/virtio-bus.h"
-#include "hw/virtio/virtio-access.h"
-#include "migration/migration.h"
-
-static struct vhost_log *vhost_log;
-static struct vhost_log *vhost_log_shm;
-
-static unsigned int used_memslots;
-static QLIST_HEAD(, vhost_dev) vhost_devices =
- QLIST_HEAD_INITIALIZER(vhost_devices);
-
-bool vhost_has_free_slot(void)
-{
- unsigned int slots_limit = ~0U;
- struct vhost_dev *hdev;
-
- QLIST_FOREACH(hdev, &vhost_devices, entry) {
- unsigned int r = hdev->vhost_ops->vhost_backend_memslots_limit(hdev);
- slots_limit = MIN(slots_limit, r);
- }
- return slots_limit > used_memslots;
-}
-
-static void vhost_dev_sync_region(struct vhost_dev *dev,
- MemoryRegionSection *section,
- uint64_t mfirst, uint64_t mlast,
- uint64_t rfirst, uint64_t rlast)
-{
- vhost_log_chunk_t *log = dev->log->log;
-
- uint64_t start = MAX(mfirst, rfirst);
- uint64_t end = MIN(mlast, rlast);
- vhost_log_chunk_t *from = log + start / VHOST_LOG_CHUNK;
- vhost_log_chunk_t *to = log + end / VHOST_LOG_CHUNK + 1;
- uint64_t addr = (start / VHOST_LOG_CHUNK) * VHOST_LOG_CHUNK;
-
- if (end < start) {
- return;
- }
- assert(end / VHOST_LOG_CHUNK < dev->log_size);
- assert(start / VHOST_LOG_CHUNK < dev->log_size);
-
- for (;from < to; ++from) {
- vhost_log_chunk_t log;
- /* We first check with non-atomic: much cheaper,
- * and we expect non-dirty to be the common case. */
- if (!*from) {
- addr += VHOST_LOG_CHUNK;
- continue;
- }
- /* Data must be read atomically. We don't really need barrier semantics
- * but it's easier to use atomic_* than roll our own. */
- log = atomic_xchg(from, 0);
- while (log) {
- int bit = ctzl(log);
- hwaddr page_addr;
- hwaddr section_offset;
- hwaddr mr_offset;
- page_addr = addr + bit * VHOST_LOG_PAGE;
- section_offset = page_addr - section->offset_within_address_space;
- mr_offset = section_offset + section->offset_within_region;
- memory_region_set_dirty(section->mr, mr_offset, VHOST_LOG_PAGE);
- log &= ~(0x1ull << bit);
- }
- addr += VHOST_LOG_CHUNK;
- }
-}
-
-static int vhost_sync_dirty_bitmap(struct vhost_dev *dev,
- MemoryRegionSection *section,
- hwaddr first,
- hwaddr last)
-{
- int i;
- hwaddr start_addr;
- hwaddr end_addr;
-
- if (!dev->log_enabled || !dev->started) {
- return 0;
- }
- start_addr = section->offset_within_address_space;
- end_addr = range_get_last(start_addr, int128_get64(section->size));
- start_addr = MAX(first, start_addr);
- end_addr = MIN(last, end_addr);
-
- for (i = 0; i < dev->mem->nregions; ++i) {
- struct vhost_memory_region *reg = dev->mem->regions + i;
- vhost_dev_sync_region(dev, section, start_addr, end_addr,
- reg->guest_phys_addr,
- range_get_last(reg->guest_phys_addr,
- reg->memory_size));
- }
- for (i = 0; i < dev->nvqs; ++i) {
- struct vhost_virtqueue *vq = dev->vqs + i;
- vhost_dev_sync_region(dev, section, start_addr, end_addr, vq->used_phys,
- range_get_last(vq->used_phys, vq->used_size));
- }
- return 0;
-}
-
-static void vhost_log_sync(MemoryListener *listener,
- MemoryRegionSection *section)
-{
- struct vhost_dev *dev = container_of(listener, struct vhost_dev,
- memory_listener);
- vhost_sync_dirty_bitmap(dev, section, 0x0, ~0x0ULL);
-}
-
-static void vhost_log_sync_range(struct vhost_dev *dev,
- hwaddr first, hwaddr last)
-{
- int i;
- /* FIXME: this is N^2 in number of sections */
- for (i = 0; i < dev->n_mem_sections; ++i) {
- MemoryRegionSection *section = &dev->mem_sections[i];
- vhost_sync_dirty_bitmap(dev, section, first, last);
- }
-}
-
-/* Assign/unassign. Keep an unsorted array of non-overlapping
- * memory regions in dev->mem. */
-static void vhost_dev_unassign_memory(struct vhost_dev *dev,
- uint64_t start_addr,
- uint64_t size)
-{
- int from, to, n = dev->mem->nregions;
- /* Track overlapping/split regions for sanity checking. */
- int overlap_start = 0, overlap_end = 0, overlap_middle = 0, split = 0;
-
- for (from = 0, to = 0; from < n; ++from, ++to) {
- struct vhost_memory_region *reg = dev->mem->regions + to;
- uint64_t reglast;
- uint64_t memlast;
- uint64_t change;
-
- /* clone old region */
- if (to != from) {
- memcpy(reg, dev->mem->regions + from, sizeof *reg);
- }
-
- /* No overlap is simple */
- if (!ranges_overlap(reg->guest_phys_addr, reg->memory_size,
- start_addr, size)) {
- continue;
- }
-
- /* Split only happens if supplied region
- * is in the middle of an existing one. Thus it can not
- * overlap with any other existing region. */
- assert(!split);
-
- reglast = range_get_last(reg->guest_phys_addr, reg->memory_size);
- memlast = range_get_last(start_addr, size);
-
- /* Remove whole region */
- if (start_addr <= reg->guest_phys_addr && memlast >= reglast) {
- --dev->mem->nregions;
- --to;
- ++overlap_middle;
- continue;
- }
-
- /* Shrink region */
- if (memlast >= reglast) {
- reg->memory_size = start_addr - reg->guest_phys_addr;
- assert(reg->memory_size);
- assert(!overlap_end);
- ++overlap_end;
- continue;
- }
-
- /* Shift region */
- if (start_addr <= reg->guest_phys_addr) {
- change = memlast + 1 - reg->guest_phys_addr;
- reg->memory_size -= change;
- reg->guest_phys_addr += change;
- reg->userspace_addr += change;
- assert(reg->memory_size);
- assert(!overlap_start);
- ++overlap_start;
- continue;
- }
-
- /* This only happens if supplied region
- * is in the middle of an existing one. Thus it can not
- * overlap with any other existing region. */
- assert(!overlap_start);
- assert(!overlap_end);
- assert(!overlap_middle);
- /* Split region: shrink first part, shift second part. */
- memcpy(dev->mem->regions + n, reg, sizeof *reg);
- reg->memory_size = start_addr - reg->guest_phys_addr;
- assert(reg->memory_size);
- change = memlast + 1 - reg->guest_phys_addr;
- reg = dev->mem->regions + n;
- reg->memory_size -= change;
- assert(reg->memory_size);
- reg->guest_phys_addr += change;
- reg->userspace_addr += change;
- /* Never add more than 1 region */
- assert(dev->mem->nregions == n);
- ++dev->mem->nregions;
- ++split;
- }
-}
-
-/* Called after unassign, so no regions overlap the given range. */
-static void vhost_dev_assign_memory(struct vhost_dev *dev,
- uint64_t start_addr,
- uint64_t size,
- uint64_t uaddr)
-{
- int from, to;
- struct vhost_memory_region *merged = NULL;
- for (from = 0, to = 0; from < dev->mem->nregions; ++from, ++to) {
- struct vhost_memory_region *reg = dev->mem->regions + to;
- uint64_t prlast, urlast;
- uint64_t pmlast, umlast;
- uint64_t s, e, u;
-
- /* clone old region */
- if (to != from) {
- memcpy(reg, dev->mem->regions + from, sizeof *reg);
- }
- prlast = range_get_last(reg->guest_phys_addr, reg->memory_size);
- pmlast = range_get_last(start_addr, size);
- urlast = range_get_last(reg->userspace_addr, reg->memory_size);
- umlast = range_get_last(uaddr, size);
-
- /* check for overlapping regions: should never happen. */
- assert(prlast < start_addr || pmlast < reg->guest_phys_addr);
- /* Not an adjacent or overlapping region - do not merge. */
- if ((prlast + 1 != start_addr || urlast + 1 != uaddr) &&
- (pmlast + 1 != reg->guest_phys_addr ||
- umlast + 1 != reg->userspace_addr)) {
- continue;
- }
-
- if (dev->vhost_ops->vhost_backend_can_merge &&
- !dev->vhost_ops->vhost_backend_can_merge(dev, uaddr, size,
- reg->userspace_addr,
- reg->memory_size)) {
- continue;
- }
-
- if (merged) {
- --to;
- assert(to >= 0);
- } else {
- merged = reg;
- }
- u = MIN(uaddr, reg->userspace_addr);
- s = MIN(start_addr, reg->guest_phys_addr);
- e = MAX(pmlast, prlast);
- uaddr = merged->userspace_addr = u;
- start_addr = merged->guest_phys_addr = s;
- size = merged->memory_size = e - s + 1;
- assert(merged->memory_size);
- }
-
- if (!merged) {
- struct vhost_memory_region *reg = dev->mem->regions + to;
- memset(reg, 0, sizeof *reg);
- reg->memory_size = size;
- assert(reg->memory_size);
- reg->guest_phys_addr = start_addr;
- reg->userspace_addr = uaddr;
- ++to;
- }
- assert(to <= dev->mem->nregions + 1);
- dev->mem->nregions = to;
-}
-
-static uint64_t vhost_get_log_size(struct vhost_dev *dev)
-{
- uint64_t log_size = 0;
- int i;
- for (i = 0; i < dev->mem->nregions; ++i) {
- struct vhost_memory_region *reg = dev->mem->regions + i;
- uint64_t last = range_get_last(reg->guest_phys_addr,
- reg->memory_size);
- log_size = MAX(log_size, last / VHOST_LOG_CHUNK + 1);
- }
- for (i = 0; i < dev->nvqs; ++i) {
- struct vhost_virtqueue *vq = dev->vqs + i;
- uint64_t last = vq->used_phys + vq->used_size - 1;
- log_size = MAX(log_size, last / VHOST_LOG_CHUNK + 1);
- }
- return log_size;
-}
-
-static struct vhost_log *vhost_log_alloc(uint64_t size, bool share)
-{
- struct vhost_log *log;
- uint64_t logsize = size * sizeof(*(log->log));
- int fd = -1;
-
- log = g_new0(struct vhost_log, 1);
- if (share) {
- log->log = qemu_memfd_alloc("vhost-log", logsize,
- F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL,
- &fd);
- memset(log->log, 0, logsize);
- } else {
- log->log = g_malloc0(logsize);
- }
-
- log->size = size;
- log->refcnt = 1;
- log->fd = fd;
-
- return log;
-}
-
-static struct vhost_log *vhost_log_get(uint64_t size, bool share)
-{
- struct vhost_log *log = share ? vhost_log_shm : vhost_log;
-
- if (!log || log->size != size) {
- log = vhost_log_alloc(size, share);
- if (share) {
- vhost_log_shm = log;
- } else {
- vhost_log = log;
- }
- } else {
- ++log->refcnt;
- }
-
- return log;
-}
-
-static void vhost_log_put(struct vhost_dev *dev, bool sync)
-{
- struct vhost_log *log = dev->log;
-
- if (!log) {
- return;
- }
-
- --log->refcnt;
- if (log->refcnt == 0) {
- /* Sync only the range covered by the old log */
- if (dev->log_size && sync) {
- vhost_log_sync_range(dev, 0, dev->log_size * VHOST_LOG_CHUNK - 1);
- }
-
- if (vhost_log == log) {
- g_free(log->log);
- vhost_log = NULL;
- } else if (vhost_log_shm == log) {
- qemu_memfd_free(log->log, log->size * sizeof(*(log->log)),
- log->fd);
- vhost_log_shm = NULL;
- }
-
- g_free(log);
- }
-}
-
-static bool vhost_dev_log_is_shared(struct vhost_dev *dev)
-{
- return dev->vhost_ops->vhost_requires_shm_log &&
- dev->vhost_ops->vhost_requires_shm_log(dev);
-}
-
-static inline void vhost_dev_log_resize(struct vhost_dev *dev, uint64_t size)
-{
- struct vhost_log *log = vhost_log_get(size, vhost_dev_log_is_shared(dev));
- uint64_t log_base = (uintptr_t)log->log;
- int r;
-
- /* inform backend of log switching, this must be done before
- releasing the current log, to ensure no logging is lost */
- r = dev->vhost_ops->vhost_set_log_base(dev, log_base, log);
- assert(r >= 0);
- vhost_log_put(dev, true);
- dev->log = log;
- dev->log_size = size;
-}
-
-static int vhost_verify_ring_mappings(struct vhost_dev *dev,
- uint64_t start_addr,
- uint64_t size)
-{
- int i;
- int r = 0;
-
- for (i = 0; !r && i < dev->nvqs; ++i) {
- struct vhost_virtqueue *vq = dev->vqs + i;
- hwaddr l;
- void *p;
-
- if (!ranges_overlap(start_addr, size, vq->ring_phys, vq->ring_size)) {
- continue;
- }
- l = vq->ring_size;
- p = cpu_physical_memory_map(vq->ring_phys, &l, 1);
- if (!p || l != vq->ring_size) {
- fprintf(stderr, "Unable to map ring buffer for ring %d\n", i);
- r = -ENOMEM;
- }
- if (p != vq->ring) {
- fprintf(stderr, "Ring buffer relocated for ring %d\n", i);
- r = -EBUSY;
- }
- cpu_physical_memory_unmap(p, l, 0, 0);
- }
- return r;
-}
-
-static struct vhost_memory_region *vhost_dev_find_reg(struct vhost_dev *dev,
- uint64_t start_addr,
- uint64_t size)
-{
- int i, n = dev->mem->nregions;
- for (i = 0; i < n; ++i) {
- struct vhost_memory_region *reg = dev->mem->regions + i;
- if (ranges_overlap(reg->guest_phys_addr, reg->memory_size,
- start_addr, size)) {
- return reg;
- }
- }
- return NULL;
-}
-
-static bool vhost_dev_cmp_memory(struct vhost_dev *dev,
- uint64_t start_addr,
- uint64_t size,
- uint64_t uaddr)
-{
- struct vhost_memory_region *reg = vhost_dev_find_reg(dev, start_addr, size);
- uint64_t reglast;
- uint64_t memlast;
-
- if (!reg) {
- return true;
- }
-
- reglast = range_get_last(reg->guest_phys_addr, reg->memory_size);
- memlast = range_get_last(start_addr, size);
-
- /* Need to extend region? */
- if (start_addr < reg->guest_phys_addr || memlast > reglast) {
- return true;
- }
- /* userspace_addr changed? */
- return uaddr != reg->userspace_addr + start_addr - reg->guest_phys_addr;
-}
-
-static void vhost_set_memory(MemoryListener *listener,
- MemoryRegionSection *section,
- bool add)
-{
- struct vhost_dev *dev = container_of(listener, struct vhost_dev,
- memory_listener);
- hwaddr start_addr = section->offset_within_address_space;
- ram_addr_t size = int128_get64(section->size);
- bool log_dirty =
- memory_region_get_dirty_log_mask(section->mr) & ~(1 << DIRTY_MEMORY_MIGRATION);
- int s = offsetof(struct vhost_memory, regions) +
- (dev->mem->nregions + 1) * sizeof dev->mem->regions[0];
- void *ram;
-
- dev->mem = g_realloc(dev->mem, s);
-
- if (log_dirty) {
- add = false;
- }
-
- assert(size);
-
- /* Optimize no-change case. At least cirrus_vga does this a lot at this time. */
- ram = memory_region_get_ram_ptr(section->mr) + section->offset_within_region;
- if (add) {
- if (!vhost_dev_cmp_memory(dev, start_addr, size, (uintptr_t)ram)) {
- /* Region exists with same address. Nothing to do. */
- return;
- }
- } else {
- if (!vhost_dev_find_reg(dev, start_addr, size)) {
- /* Removing region that we don't access. Nothing to do. */
- return;
- }
- }
-
- vhost_dev_unassign_memory(dev, start_addr, size);
- if (add) {
- /* Add given mapping, merging adjacent regions if any */
- vhost_dev_assign_memory(dev, start_addr, size, (uintptr_t)ram);
- } else {
- /* Remove old mapping for this memory, if any. */
- vhost_dev_unassign_memory(dev, start_addr, size);
- }
- dev->mem_changed_start_addr = MIN(dev->mem_changed_start_addr, start_addr);
- dev->mem_changed_end_addr = MAX(dev->mem_changed_end_addr, start_addr + size - 1);
- dev->memory_changed = true;
- used_memslots = dev->mem->nregions;
-}
-
-static bool vhost_section(MemoryRegionSection *section)
-{
- return memory_region_is_ram(section->mr);
-}
-
-static void vhost_begin(MemoryListener *listener)
-{
- struct vhost_dev *dev = container_of(listener, struct vhost_dev,
- memory_listener);
- dev->mem_changed_end_addr = 0;
- dev->mem_changed_start_addr = -1;
-}
-
-static void vhost_commit(MemoryListener *listener)
-{
- struct vhost_dev *dev = container_of(listener, struct vhost_dev,
- memory_listener);
- hwaddr start_addr = 0;
- ram_addr_t size = 0;
- uint64_t log_size;
- int r;
-
- if (!dev->memory_changed) {
- return;
- }
- if (!dev->started) {
- return;
- }
- if (dev->mem_changed_start_addr > dev->mem_changed_end_addr) {
- return;
- }
-
- if (dev->started) {
- start_addr = dev->mem_changed_start_addr;
- size = dev->mem_changed_end_addr - dev->mem_changed_start_addr + 1;
-
- r = vhost_verify_ring_mappings(dev, start_addr, size);
- assert(r >= 0);
- }
-
- if (!dev->log_enabled) {
- r = dev->vhost_ops->vhost_set_mem_table(dev, dev->mem);
- assert(r >= 0);
- dev->memory_changed = false;
- return;
- }
- log_size = vhost_get_log_size(dev);
- /* We allocate an extra 4K bytes to log,
- * to reduce the * number of reallocations. */
-#define VHOST_LOG_BUFFER (0x1000 / sizeof *dev->log)
- /* To log more, must increase log size before table update. */
- if (dev->log_size < log_size) {
- vhost_dev_log_resize(dev, log_size + VHOST_LOG_BUFFER);
- }
- r = dev->vhost_ops->vhost_set_mem_table(dev, dev->mem);
- assert(r >= 0);
- /* To log less, can only decrease log size after table update. */
- if (dev->log_size > log_size + VHOST_LOG_BUFFER) {
- vhost_dev_log_resize(dev, log_size);
- }
- dev->memory_changed = false;
-}
-
-static void vhost_region_add(MemoryListener *listener,
- MemoryRegionSection *section)
-{
- struct vhost_dev *dev = container_of(listener, struct vhost_dev,
- memory_listener);
-
- if (!vhost_section(section)) {
- return;
- }
-
- ++dev->n_mem_sections;
- dev->mem_sections = g_renew(MemoryRegionSection, dev->mem_sections,
- dev->n_mem_sections);
- dev->mem_sections[dev->n_mem_sections - 1] = *section;
- memory_region_ref(section->mr);
- vhost_set_memory(listener, section, true);
-}
-
-static void vhost_region_del(MemoryListener *listener,
- MemoryRegionSection *section)
-{
- struct vhost_dev *dev = container_of(listener, struct vhost_dev,
- memory_listener);
- int i;
-
- if (!vhost_section(section)) {
- return;
- }
-
- vhost_set_memory(listener, section, false);
- memory_region_unref(section->mr);
- for (i = 0; i < dev->n_mem_sections; ++i) {
- if (dev->mem_sections[i].offset_within_address_space
- == section->offset_within_address_space) {
- --dev->n_mem_sections;
- memmove(&dev->mem_sections[i], &dev->mem_sections[i+1],
- (dev->n_mem_sections - i) * sizeof(*dev->mem_sections));
- break;
- }
- }
-}
-
-static void vhost_region_nop(MemoryListener *listener,
- MemoryRegionSection *section)
-{
-}
-
-static int vhost_virtqueue_set_addr(struct vhost_dev *dev,
- struct vhost_virtqueue *vq,
- unsigned idx, bool enable_log)
-{
- struct vhost_vring_addr addr = {
- .index = idx,
- .desc_user_addr = (uint64_t)(unsigned long)vq->desc,
- .avail_user_addr = (uint64_t)(unsigned long)vq->avail,
- .used_user_addr = (uint64_t)(unsigned long)vq->used,
- .log_guest_addr = vq->used_phys,
- .flags = enable_log ? (1 << VHOST_VRING_F_LOG) : 0,
- };
- int r = dev->vhost_ops->vhost_set_vring_addr(dev, &addr);
- if (r < 0) {
- return -errno;
- }
- return 0;
-}
-
-static int vhost_dev_set_features(struct vhost_dev *dev, bool enable_log)
-{
- uint64_t features = dev->acked_features;
- int r;
- if (enable_log) {
- features |= 0x1ULL << VHOST_F_LOG_ALL;
- }
- r = dev->vhost_ops->vhost_set_features(dev, features);
- return r < 0 ? -errno : 0;
-}
-
-static int vhost_dev_set_log(struct vhost_dev *dev, bool enable_log)
-{
- int r, t, i, idx;
- r = vhost_dev_set_features(dev, enable_log);
- if (r < 0) {
- goto err_features;
- }
- for (i = 0; i < dev->nvqs; ++i) {
- idx = dev->vhost_ops->vhost_get_vq_index(dev, dev->vq_index + i);
- r = vhost_virtqueue_set_addr(dev, dev->vqs + i, idx,
- enable_log);
- if (r < 0) {
- goto err_vq;
- }
- }
- return 0;
-err_vq:
- for (; i >= 0; --i) {
- idx = dev->vhost_ops->vhost_get_vq_index(dev, dev->vq_index + i);
- t = vhost_virtqueue_set_addr(dev, dev->vqs + i, idx,
- dev->log_enabled);
- assert(t >= 0);
- }
- t = vhost_dev_set_features(dev, dev->log_enabled);
- assert(t >= 0);
-err_features:
- return r;
-}
-
-static int vhost_migration_log(MemoryListener *listener, int enable)
-{
- struct vhost_dev *dev = container_of(listener, struct vhost_dev,
- memory_listener);
- int r;
- if (!!enable == dev->log_enabled) {
- return 0;
- }
- if (!dev->started) {
- dev->log_enabled = enable;
- return 0;
- }
- if (!enable) {
- r = vhost_dev_set_log(dev, false);
- if (r < 0) {
- return r;
- }
- vhost_log_put(dev, false);
- dev->log = NULL;
- dev->log_size = 0;
- } else {
- vhost_dev_log_resize(dev, vhost_get_log_size(dev));
- r = vhost_dev_set_log(dev, true);
- if (r < 0) {
- return r;
- }
- }
- dev->log_enabled = enable;
- return 0;
-}
-
-static void vhost_log_global_start(MemoryListener *listener)
-{
- int r;
-
- r = vhost_migration_log(listener, true);
- if (r < 0) {
- abort();
- }
-}
-
-static void vhost_log_global_stop(MemoryListener *listener)
-{
- int r;
-
- r = vhost_migration_log(listener, false);
- if (r < 0) {
- abort();
- }
-}
-
-static void vhost_log_start(MemoryListener *listener,
- MemoryRegionSection *section,
- int old, int new)
-{
- /* FIXME: implement */
-}
-
-static void vhost_log_stop(MemoryListener *listener,
- MemoryRegionSection *section,
- int old, int new)
-{
- /* FIXME: implement */
-}
-
-/* The vhost driver natively knows how to handle the vrings of non
- * cross-endian legacy devices and modern devices. Only legacy devices
- * exposed to a bi-endian guest may require the vhost driver to use a
- * specific endianness.
- */
-static inline bool vhost_needs_vring_endian(VirtIODevice *vdev)
-{
- if (virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) {
- return false;
- }
-#ifdef TARGET_IS_BIENDIAN
-#ifdef HOST_WORDS_BIGENDIAN
- return vdev->device_endian == VIRTIO_DEVICE_ENDIAN_LITTLE;
-#else
- return vdev->device_endian == VIRTIO_DEVICE_ENDIAN_BIG;
-#endif
-#else
- return false;
-#endif
-}
-
-static int vhost_virtqueue_set_vring_endian_legacy(struct vhost_dev *dev,
- bool is_big_endian,
- int vhost_vq_index)
-{
- struct vhost_vring_state s = {
- .index = vhost_vq_index,
- .num = is_big_endian
- };
-
- if (!dev->vhost_ops->vhost_set_vring_endian(dev, &s)) {
- return 0;
- }
-
- if (errno == ENOTTY) {
- error_report("vhost does not support cross-endian");
- return -ENOSYS;
- }
-
- return -errno;
-}
-
-static int vhost_virtqueue_start(struct vhost_dev *dev,
- struct VirtIODevice *vdev,
- struct vhost_virtqueue *vq,
- unsigned idx)
-{
- hwaddr s, l, a;
- int r;
- int vhost_vq_index = dev->vhost_ops->vhost_get_vq_index(dev, idx);
- struct vhost_vring_file file = {
- .index = vhost_vq_index
- };
- struct vhost_vring_state state = {
- .index = vhost_vq_index
- };
- struct VirtQueue *vvq = virtio_get_queue(vdev, idx);
-
-
- vq->num = state.num = virtio_queue_get_num(vdev, idx);
- r = dev->vhost_ops->vhost_set_vring_num(dev, &state);
- if (r) {
- return -errno;
- }
-
- state.num = virtio_queue_get_last_avail_idx(vdev, idx);
- r = dev->vhost_ops->vhost_set_vring_base(dev, &state);
- if (r) {
- return -errno;
- }
-
- if (vhost_needs_vring_endian(vdev)) {
- r = vhost_virtqueue_set_vring_endian_legacy(dev,
- virtio_is_big_endian(vdev),
- vhost_vq_index);
- if (r) {
- return -errno;
- }
- }
-
- s = l = virtio_queue_get_desc_size(vdev, idx);
- a = virtio_queue_get_desc_addr(vdev, idx);
- vq->desc = cpu_physical_memory_map(a, &l, 0);
- if (!vq->desc || l != s) {
- r = -ENOMEM;
- goto fail_alloc_desc;
- }
- s = l = virtio_queue_get_avail_size(vdev, idx);
- a = virtio_queue_get_avail_addr(vdev, idx);
- vq->avail = cpu_physical_memory_map(a, &l, 0);
- if (!vq->avail || l != s) {
- r = -ENOMEM;
- goto fail_alloc_avail;
- }
- vq->used_size = s = l = virtio_queue_get_used_size(vdev, idx);
- vq->used_phys = a = virtio_queue_get_used_addr(vdev, idx);
- vq->used = cpu_physical_memory_map(a, &l, 1);
- if (!vq->used || l != s) {
- r = -ENOMEM;
- goto fail_alloc_used;
- }
-
- vq->ring_size = s = l = virtio_queue_get_ring_size(vdev, idx);
- vq->ring_phys = a = virtio_queue_get_ring_addr(vdev, idx);
- vq->ring = cpu_physical_memory_map(a, &l, 1);
- if (!vq->ring || l != s) {
- r = -ENOMEM;
- goto fail_alloc_ring;
- }
-
- r = vhost_virtqueue_set_addr(dev, vq, vhost_vq_index, dev->log_enabled);
- if (r < 0) {
- r = -errno;
- goto fail_alloc;
- }
-
- file.fd = event_notifier_get_fd(virtio_queue_get_host_notifier(vvq));
- r = dev->vhost_ops->vhost_set_vring_kick(dev, &file);
- if (r) {
- r = -errno;
- goto fail_kick;
- }
-
- /* Clear and discard previous events if any. */
- event_notifier_test_and_clear(&vq->masked_notifier);
-
- /* Init vring in unmasked state, unless guest_notifier_mask
- * will do it later.
- */
- if (!vdev->use_guest_notifier_mask) {
- /* TODO: check and handle errors. */
- vhost_virtqueue_mask(dev, vdev, idx, false);
- }
-
- return 0;
-
-fail_kick:
-fail_alloc:
- cpu_physical_memory_unmap(vq->ring, virtio_queue_get_ring_size(vdev, idx),
- 0, 0);
-fail_alloc_ring:
- cpu_physical_memory_unmap(vq->used, virtio_queue_get_used_size(vdev, idx),
- 0, 0);
-fail_alloc_used:
- cpu_physical_memory_unmap(vq->avail, virtio_queue_get_avail_size(vdev, idx),
- 0, 0);
-fail_alloc_avail:
- cpu_physical_memory_unmap(vq->desc, virtio_queue_get_desc_size(vdev, idx),
- 0, 0);
-fail_alloc_desc:
- return r;
-}
-
-static void vhost_virtqueue_stop(struct vhost_dev *dev,
- struct VirtIODevice *vdev,
- struct vhost_virtqueue *vq,
- unsigned idx)
-{
- int vhost_vq_index = dev->vhost_ops->vhost_get_vq_index(dev, idx);
- struct vhost_vring_state state = {
- .index = vhost_vq_index,
- };
- int r;
-
- r = dev->vhost_ops->vhost_get_vring_base(dev, &state);
- if (r < 0) {
- fprintf(stderr, "vhost VQ %d ring restore failed: %d\n", idx, r);
- fflush(stderr);
- }
- virtio_queue_set_last_avail_idx(vdev, idx, state.num);
- virtio_queue_invalidate_signalled_used(vdev, idx);
-
- /* In the cross-endian case, we need to reset the vring endianness to
- * native as legacy devices expect so by default.
- */
- if (vhost_needs_vring_endian(vdev)) {
- r = vhost_virtqueue_set_vring_endian_legacy(dev,
- !virtio_is_big_endian(vdev),
- vhost_vq_index);
- if (r < 0) {
- error_report("failed to reset vring endianness");
- }
- }
-
- assert (r >= 0);
- cpu_physical_memory_unmap(vq->ring, virtio_queue_get_ring_size(vdev, idx),
- 0, virtio_queue_get_ring_size(vdev, idx));
- cpu_physical_memory_unmap(vq->used, virtio_queue_get_used_size(vdev, idx),
- 1, virtio_queue_get_used_size(vdev, idx));
- cpu_physical_memory_unmap(vq->avail, virtio_queue_get_avail_size(vdev, idx),
- 0, virtio_queue_get_avail_size(vdev, idx));
- cpu_physical_memory_unmap(vq->desc, virtio_queue_get_desc_size(vdev, idx),
- 0, virtio_queue_get_desc_size(vdev, idx));
-}
-
-static void vhost_eventfd_add(MemoryListener *listener,
- MemoryRegionSection *section,
- bool match_data, uint64_t data, EventNotifier *e)
-{
-}
-
-static void vhost_eventfd_del(MemoryListener *listener,
- MemoryRegionSection *section,
- bool match_data, uint64_t data, EventNotifier *e)
-{
-}
-
-static int vhost_virtqueue_init(struct vhost_dev *dev,
- struct vhost_virtqueue *vq, int n)
-{
- int vhost_vq_index = dev->vhost_ops->vhost_get_vq_index(dev, n);
- struct vhost_vring_file file = {
- .index = vhost_vq_index,
- };
- int r = event_notifier_init(&vq->masked_notifier, 0);
- if (r < 0) {
- return r;
- }
-
- file.fd = event_notifier_get_fd(&vq->masked_notifier);
- r = dev->vhost_ops->vhost_set_vring_call(dev, &file);
- if (r) {
- r = -errno;
- goto fail_call;
- }
- return 0;
-fail_call:
- event_notifier_cleanup(&vq->masked_notifier);
- return r;
-}
-
-static void vhost_virtqueue_cleanup(struct vhost_virtqueue *vq)
-{
- event_notifier_cleanup(&vq->masked_notifier);
-}
-
-int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
- VhostBackendType backend_type)
-{
- uint64_t features;
- int i, r;
-
- hdev->migration_blocker = NULL;
-
- if (vhost_set_backend_type(hdev, backend_type) < 0) {
- close((uintptr_t)opaque);
- return -1;
- }
-
- if (hdev->vhost_ops->vhost_backend_init(hdev, opaque) < 0) {
- close((uintptr_t)opaque);
- return -errno;
- }
-
- if (used_memslots > hdev->vhost_ops->vhost_backend_memslots_limit(hdev)) {
- fprintf(stderr, "vhost backend memory slots limit is less"
- " than current number of present memory slots\n");
- close((uintptr_t)opaque);
- return -1;
- }
- QLIST_INSERT_HEAD(&vhost_devices, hdev, entry);
-
- r = hdev->vhost_ops->vhost_set_owner(hdev);
- if (r < 0) {
- goto fail;
- }
-
- r = hdev->vhost_ops->vhost_get_features(hdev, &features);
- if (r < 0) {
- goto fail;
- }
-
- for (i = 0; i < hdev->nvqs; ++i) {
- r = vhost_virtqueue_init(hdev, hdev->vqs + i, hdev->vq_index + i);
- if (r < 0) {
- goto fail_vq;
- }
- }
- hdev->features = features;
-
- hdev->memory_listener = (MemoryListener) {
- .begin = vhost_begin,
- .commit = vhost_commit,
- .region_add = vhost_region_add,
- .region_del = vhost_region_del,
- .region_nop = vhost_region_nop,
- .log_start = vhost_log_start,
- .log_stop = vhost_log_stop,
- .log_sync = vhost_log_sync,
- .log_global_start = vhost_log_global_start,
- .log_global_stop = vhost_log_global_stop,
- .eventfd_add = vhost_eventfd_add,
- .eventfd_del = vhost_eventfd_del,
- .priority = 10
- };
-
- if (hdev->migration_blocker == NULL) {
- if (!(hdev->features & (0x1ULL << VHOST_F_LOG_ALL))) {
- error_setg(&hdev->migration_blocker,
- "Migration disabled: vhost lacks VHOST_F_LOG_ALL feature.");
- } else if (!qemu_memfd_check()) {
- error_setg(&hdev->migration_blocker,
- "Migration disabled: failed to allocate shared memory");
- }
- }
-
- if (hdev->migration_blocker != NULL) {
- migrate_add_blocker(hdev->migration_blocker);
- }
-
- hdev->mem = g_malloc0(offsetof(struct vhost_memory, regions));
- hdev->n_mem_sections = 0;
- hdev->mem_sections = NULL;
- hdev->log = NULL;
- hdev->log_size = 0;
- hdev->log_enabled = false;
- hdev->started = false;
- hdev->memory_changed = false;
- memory_listener_register(&hdev->memory_listener, &address_space_memory);
- return 0;
-fail_vq:
- while (--i >= 0) {
- vhost_virtqueue_cleanup(hdev->vqs + i);
- }
-fail:
- r = -errno;
- hdev->vhost_ops->vhost_backend_cleanup(hdev);
- QLIST_REMOVE(hdev, entry);
- return r;
-}
-
-void vhost_dev_cleanup(struct vhost_dev *hdev)
-{
- int i;
- for (i = 0; i < hdev->nvqs; ++i) {
- vhost_virtqueue_cleanup(hdev->vqs + i);
- }
- memory_listener_unregister(&hdev->memory_listener);
- if (hdev->migration_blocker) {
- migrate_del_blocker(hdev->migration_blocker);
- error_free(hdev->migration_blocker);
- }
- g_free(hdev->mem);
- g_free(hdev->mem_sections);
- hdev->vhost_ops->vhost_backend_cleanup(hdev);
- QLIST_REMOVE(hdev, entry);
-}
-
-/* Stop processing guest IO notifications in qemu.
- * Start processing them in vhost in kernel.
- */
-int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev)
-{
- BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
- VirtioBusState *vbus = VIRTIO_BUS(qbus);
- VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
- int i, r, e;
- if (!k->set_host_notifier) {
- fprintf(stderr, "binding does not support host notifiers\n");
- r = -ENOSYS;
- goto fail;
- }
-
- for (i = 0; i < hdev->nvqs; ++i) {
- r = k->set_host_notifier(qbus->parent, hdev->vq_index + i, true);
- if (r < 0) {
- fprintf(stderr, "vhost VQ %d notifier binding failed: %d\n", i, -r);
- goto fail_vq;
- }
- }
-
- return 0;
-fail_vq:
- while (--i >= 0) {
- e = k->set_host_notifier(qbus->parent, hdev->vq_index + i, false);
- if (e < 0) {
- fprintf(stderr, "vhost VQ %d notifier cleanup error: %d\n", i, -r);
- fflush(stderr);
- }
- assert (e >= 0);
- }
-fail:
- return r;
-}
-
-/* Stop processing guest IO notifications in vhost.
- * Start processing them in qemu.
- * This might actually run the qemu handlers right away,
- * so virtio in qemu must be completely setup when this is called.
- */
-void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev)
-{
- BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
- VirtioBusState *vbus = VIRTIO_BUS(qbus);
- VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
- int i, r;
-
- for (i = 0; i < hdev->nvqs; ++i) {
- r = k->set_host_notifier(qbus->parent, hdev->vq_index + i, false);
- if (r < 0) {
- fprintf(stderr, "vhost VQ %d notifier cleanup failed: %d\n", i, -r);
- fflush(stderr);
- }
- assert (r >= 0);
- }
-}
-
-/* Test and clear event pending status.
- * Should be called after unmask to avoid losing events.
- */
-bool vhost_virtqueue_pending(struct vhost_dev *hdev, int n)
-{
- struct vhost_virtqueue *vq = hdev->vqs + n - hdev->vq_index;
- assert(n >= hdev->vq_index && n < hdev->vq_index + hdev->nvqs);
- return event_notifier_test_and_clear(&vq->masked_notifier);
-}
-
-/* Mask/unmask events from this vq. */
-void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n,
- bool mask)
-{
- struct VirtQueue *vvq = virtio_get_queue(vdev, n);
- int r, index = n - hdev->vq_index;
- struct vhost_vring_file file;
-
- if (mask) {
- assert(vdev->use_guest_notifier_mask);
- file.fd = event_notifier_get_fd(&hdev->vqs[index].masked_notifier);
- } else {
- file.fd = event_notifier_get_fd(virtio_queue_get_guest_notifier(vvq));
- }
-
- file.index = hdev->vhost_ops->vhost_get_vq_index(hdev, n);
- r = hdev->vhost_ops->vhost_set_vring_call(hdev, &file);
- assert(r >= 0);
-}
-
-uint64_t vhost_get_features(struct vhost_dev *hdev, const int *feature_bits,
- uint64_t features)
-{
- const int *bit = feature_bits;
- while (*bit != VHOST_INVALID_FEATURE_BIT) {
- uint64_t bit_mask = (1ULL << *bit);
- if (!(hdev->features & bit_mask)) {
- features &= ~bit_mask;
- }
- bit++;
- }
- return features;
-}
-
-void vhost_ack_features(struct vhost_dev *hdev, const int *feature_bits,
- uint64_t features)
-{
- const int *bit = feature_bits;
- while (*bit != VHOST_INVALID_FEATURE_BIT) {
- uint64_t bit_mask = (1ULL << *bit);
- if (features & bit_mask) {
- hdev->acked_features |= bit_mask;
- }
- bit++;
- }
-}
-
-/* Host notifiers must be enabled at this point. */
-int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
-{
- int i, r;
-
- hdev->started = true;
-
- r = vhost_dev_set_features(hdev, hdev->log_enabled);
- if (r < 0) {
- goto fail_features;
- }
- r = hdev->vhost_ops->vhost_set_mem_table(hdev, hdev->mem);
- if (r < 0) {
- r = -errno;
- goto fail_mem;
- }
- for (i = 0; i < hdev->nvqs; ++i) {
- r = vhost_virtqueue_start(hdev,
- vdev,
- hdev->vqs + i,
- hdev->vq_index + i);
- if (r < 0) {
- goto fail_vq;
- }
- }
-
- if (hdev->log_enabled) {
- uint64_t log_base;
-
- hdev->log_size = vhost_get_log_size(hdev);
- hdev->log = vhost_log_get(hdev->log_size,
- vhost_dev_log_is_shared(hdev));
- log_base = (uintptr_t)hdev->log->log;
- r = hdev->vhost_ops->vhost_set_log_base(hdev,
- hdev->log_size ? log_base : 0,
- hdev->log);
- if (r < 0) {
- r = -errno;
- goto fail_log;
- }
- }
-
- return 0;
-fail_log:
- vhost_log_put(hdev, false);
-fail_vq:
- while (--i >= 0) {
- vhost_virtqueue_stop(hdev,
- vdev,
- hdev->vqs + i,
- hdev->vq_index + i);
- }
- i = hdev->nvqs;
-fail_mem:
-fail_features:
-
- hdev->started = false;
- return r;
-}
-
-/* Host notifiers must be enabled at this point. */
-void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev)
-{
- int i;
-
- for (i = 0; i < hdev->nvqs; ++i) {
- vhost_virtqueue_stop(hdev,
- vdev,
- hdev->vqs + i,
- hdev->vq_index + i);
- }
-
- vhost_log_put(hdev, true);
- hdev->started = false;
- hdev->log = NULL;
- hdev->log_size = 0;
-}
-
diff --git a/qemu/hw/virtio/virtio-balloon.c b/qemu/hw/virtio/virtio-balloon.c
deleted file mode 100644
index 9dbe68179..000000000
--- a/qemu/hw/virtio/virtio-balloon.c
+++ /dev/null
@@ -1,535 +0,0 @@
-/*
- * Virtio Balloon Device
- *
- * Copyright IBM, Corp. 2008
- * Copyright (C) 2011 Red Hat, Inc.
- * Copyright (C) 2011 Amit Shah <amit.shah@redhat.com>
- *
- * Authors:
- * Anthony Liguori <aliguori@us.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "qemu/iov.h"
-#include "qemu/timer.h"
-#include "qemu-common.h"
-#include "hw/virtio/virtio.h"
-#include "hw/i386/pc.h"
-#include "sysemu/balloon.h"
-#include "hw/virtio/virtio-balloon.h"
-#include "sysemu/kvm.h"
-#include "exec/address-spaces.h"
-#include "qapi/visitor.h"
-#include "qapi-event.h"
-#include "trace.h"
-
-#if defined(__linux__)
-#include <sys/mman.h>
-#endif
-
-#include "hw/virtio/virtio-bus.h"
-#include "hw/virtio/virtio-access.h"
-
-#define BALLOON_PAGE_SIZE (1 << VIRTIO_BALLOON_PFN_SHIFT)
-
-static void balloon_page(void *addr, int deflate)
-{
-#if defined(__linux__)
- if (!qemu_balloon_is_inhibited() && (!kvm_enabled() ||
- kvm_has_sync_mmu())) {
- qemu_madvise(addr, BALLOON_PAGE_SIZE,
- deflate ? QEMU_MADV_WILLNEED : QEMU_MADV_DONTNEED);
- }
-#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_AVAIL] = "stat-available-memory",
- [VIRTIO_BALLOON_S_NR] = NULL
-};
-
-/*
- * reset_stats - Mark all items in the stats array as unset
- *
- * This function needs to be called at device initialization and before
- * updating to a set of newly-generated stats. This will ensure that no
- * stale values stick around in case the guest reports a subset of the supported
- * statistics.
- */
-static inline void reset_stats(VirtIOBalloon *dev)
-{
- int i;
- for (i = 0; i < VIRTIO_BALLOON_S_NR; dev->stats[i++] = -1);
-}
-
-static bool balloon_stats_supported(const VirtIOBalloon *s)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(s);
- return virtio_vdev_has_feature(vdev, 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)) {
- timer_del(s->stats_timer);
- timer_free(s->stats_timer);
- s->stats_timer = NULL;
- s->stats_poll_interval = 0;
- }
-}
-
-static void balloon_stats_change_timer(VirtIOBalloon *s, int64_t secs)
-{
- timer_mod(s->stats_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + secs * 1000);
-}
-
-static void balloon_stats_poll_cb(void *opaque)
-{
- VirtIOBalloon *s = opaque;
- VirtIODevice *vdev = VIRTIO_DEVICE(s);
-
- if (s->stats_vq_elem == NULL || !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(vdev, s->svq);
- g_free(s->stats_vq_elem);
- s->stats_vq_elem = NULL;
-}
-
-static void balloon_stats_get_all(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- Error *err = NULL;
- VirtIOBalloon *s = opaque;
- int i;
-
- visit_start_struct(v, name, NULL, 0, &err);
- if (err) {
- goto out;
- }
- visit_type_int(v, "last-update", &s->stats_last_update, &err);
- if (err) {
- goto out_end;
- }
-
- visit_start_struct(v, "stats", NULL, 0, &err);
- if (err) {
- goto out_end;
- }
- for (i = 0; i < VIRTIO_BALLOON_S_NR; i++) {
- visit_type_uint64(v, balloon_stat_names[i], &s->stats[i], &err);
- if (err) {
- break;
- }
- }
- error_propagate(errp, err);
- err = NULL;
- visit_end_struct(v, &err);
-
-out_end:
- error_propagate(errp, err);
- err = NULL;
- visit_end_struct(v, &err);
-out:
- error_propagate(errp, err);
-}
-
-static void balloon_stats_get_poll_interval(Object *obj, Visitor *v,
- const char *name, void *opaque,
- Error **errp)
-{
- VirtIOBalloon *s = opaque;
- visit_type_int(v, name, &s->stats_poll_interval, errp);
-}
-
-static void balloon_stats_set_poll_interval(Object *obj, Visitor *v,
- const char *name, void *opaque,
- Error **errp)
-{
- VirtIOBalloon *s = opaque;
- Error *local_err = NULL;
- int64_t value;
-
- visit_type_int(v, name, &value, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- if (value < 0) {
- error_setg(errp, "timer value must be greater than zero");
- return;
- }
-
- if (value > UINT32_MAX) {
- error_setg(errp, "timer value is too big");
- 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 = timer_new_ms(QEMU_CLOCK_VIRTUAL, 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 = VIRTIO_BALLOON(vdev);
- VirtQueueElement *elem;
- MemoryRegionSection section;
-
- for (;;) {
- size_t offset = 0;
- uint32_t pfn;
- elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
- if (!elem) {
- return;
- }
-
- while (iov_to_buf(elem->out_sg, elem->out_num, offset, &pfn, 4) == 4) {
- ram_addr_t pa;
- ram_addr_t addr;
- int p = virtio_ldl_p(vdev, &pfn);
-
- pa = (ram_addr_t) p << VIRTIO_BALLOON_PFN_SHIFT;
- offset += 4;
-
- /* FIXME: remove get_system_memory(), but how? */
- section = memory_region_find(get_system_memory(), pa, 1);
- if (!int128_nz(section.size) || !memory_region_is_ram(section.mr))
- continue;
-
- trace_virtio_balloon_handle_output(memory_region_name(section.mr),
- pa);
- /* Using memory_region_get_ram_ptr is bending the rules a bit, but
- should be OK because we only want a single page. */
- addr = section.offset_within_region;
- balloon_page(memory_region_get_ram_ptr(section.mr) + addr,
- !!(vq == s->dvq));
- memory_region_unref(section.mr);
- }
-
- virtqueue_push(vq, elem, offset);
- virtio_notify(vdev, vq);
- g_free(elem);
- }
-}
-
-static void virtio_balloon_receive_stats(VirtIODevice *vdev, VirtQueue *vq)
-{
- VirtIOBalloon *s = VIRTIO_BALLOON(vdev);
- VirtQueueElement *elem;
- VirtIOBalloonStat stat;
- size_t offset = 0;
- qemu_timeval tv;
-
- elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
- if (!elem) {
- goto out;
- }
-
- if (s->stats_vq_elem != NULL) {
- /* This should never happen if the driver follows the spec. */
- virtqueue_push(vq, s->stats_vq_elem, 0);
- virtio_notify(vdev, vq);
- g_free(s->stats_vq_elem);
- }
-
- s->stats_vq_elem = elem;
-
- /* Initialize the stats to get rid of any stale values. This is only
- * needed to handle the case where a guest supports fewer stats than it
- * used to (ie. it has booted into an old kernel).
- */
- reset_stats(s);
-
- while (iov_to_buf(elem->out_sg, elem->out_num, offset, &stat, sizeof(stat))
- == sizeof(stat)) {
- uint16_t tag = virtio_tswap16(vdev, stat.tag);
- uint64_t val = virtio_tswap64(vdev, stat.val);
-
- offset += sizeof(stat);
- if (tag < VIRTIO_BALLOON_S_NR)
- 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)
-{
- VirtIOBalloon *dev = VIRTIO_BALLOON(vdev);
- struct virtio_balloon_config config;
-
- config.num_pages = cpu_to_le32(dev->num_pages);
- config.actual = cpu_to_le32(dev->actual);
-
- trace_virtio_balloon_get_config(config.num_pages, config.actual);
- memcpy(config_data, &config, sizeof(struct virtio_balloon_config));
-}
-
-static int build_dimm_list(Object *obj, void *opaque)
-{
- GSList **list = opaque;
-
- if (object_dynamic_cast(obj, TYPE_PC_DIMM)) {
- DeviceState *dev = DEVICE(obj);
- if (dev->realized) { /* only realized DIMMs matter */
- *list = g_slist_prepend(*list, dev);
- }
- }
-
- object_child_foreach(obj, build_dimm_list, opaque);
- return 0;
-}
-
-static ram_addr_t get_current_ram_size(void)
-{
- GSList *list = NULL, *item;
- ram_addr_t size = ram_size;
-
- build_dimm_list(qdev_get_machine(), &list);
- for (item = list; item; item = g_slist_next(item)) {
- Object *obj = OBJECT(item->data);
- if (!strcmp(object_get_typename(obj), TYPE_PC_DIMM)) {
- size += object_property_get_int(obj, PC_DIMM_SIZE_PROP,
- &error_abort);
- }
- }
- g_slist_free(list);
-
- return size;
-}
-
-static void virtio_balloon_set_config(VirtIODevice *vdev,
- const uint8_t *config_data)
-{
- VirtIOBalloon *dev = VIRTIO_BALLOON(vdev);
- struct virtio_balloon_config config;
- uint32_t oldactual = dev->actual;
- ram_addr_t vm_ram_size = get_current_ram_size();
-
- memcpy(&config, config_data, sizeof(struct virtio_balloon_config));
- dev->actual = le32_to_cpu(config.actual);
- if (dev->actual != oldactual) {
- qapi_event_send_balloon_change(vm_ram_size -
- ((ram_addr_t) dev->actual << VIRTIO_BALLOON_PFN_SHIFT),
- &error_abort);
- }
- trace_virtio_balloon_set_config(dev->actual, oldactual);
-}
-
-static uint64_t virtio_balloon_get_features(VirtIODevice *vdev, uint64_t f,
- Error **errp)
-{
- VirtIOBalloon *dev = VIRTIO_BALLOON(vdev);
- f |= dev->host_features;
- virtio_add_feature(&f, VIRTIO_BALLOON_F_STATS_VQ);
- return f;
-}
-
-static void virtio_balloon_stat(void *opaque, BalloonInfo *info)
-{
- VirtIOBalloon *dev = opaque;
- info->actual = get_current_ram_size() - ((uint64_t) dev->actual <<
- VIRTIO_BALLOON_PFN_SHIFT);
-}
-
-static void virtio_balloon_to_target(void *opaque, ram_addr_t target)
-{
- VirtIOBalloon *dev = VIRTIO_BALLOON(opaque);
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
- ram_addr_t vm_ram_size = get_current_ram_size();
-
- if (target > vm_ram_size) {
- target = vm_ram_size;
- }
- if (target) {
- dev->num_pages = (vm_ram_size - target) >> VIRTIO_BALLOON_PFN_SHIFT;
- virtio_notify_config(vdev);
- }
- trace_virtio_balloon_to_target(target, dev->num_pages);
-}
-
-static void virtio_balloon_save(QEMUFile *f, void *opaque)
-{
- virtio_save(VIRTIO_DEVICE(opaque), f);
-}
-
-static void virtio_balloon_save_device(VirtIODevice *vdev, QEMUFile *f)
-{
- VirtIOBalloon *s = VIRTIO_BALLOON(vdev);
-
- qemu_put_be32(f, s->num_pages);
- qemu_put_be32(f, s->actual);
-}
-
-static int virtio_balloon_load(QEMUFile *f, void *opaque, int version_id)
-{
- if (version_id != 1)
- return -EINVAL;
-
- return virtio_load(VIRTIO_DEVICE(opaque), f, version_id);
-}
-
-static int virtio_balloon_load_device(VirtIODevice *vdev, QEMUFile *f,
- int version_id)
-{
- VirtIOBalloon *s = VIRTIO_BALLOON(vdev);
-
- s->num_pages = qemu_get_be32(f);
- s->actual = qemu_get_be32(f);
-
- if (balloon_stats_enabled(s)) {
- balloon_stats_change_timer(s, s->stats_poll_interval);
- }
- return 0;
-}
-
-static void virtio_balloon_device_realize(DeviceState *dev, Error **errp)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
- VirtIOBalloon *s = VIRTIO_BALLOON(dev);
- int ret;
-
- virtio_init(vdev, "virtio-balloon", VIRTIO_ID_BALLOON,
- sizeof(struct virtio_balloon_config));
-
- ret = qemu_add_balloon_handler(virtio_balloon_to_target,
- virtio_balloon_stat, s);
-
- if (ret < 0) {
- error_setg(errp, "Only one balloon device is supported");
- virtio_cleanup(vdev);
- return;
- }
-
- s->ivq = virtio_add_queue(vdev, 128, virtio_balloon_handle_output);
- s->dvq = virtio_add_queue(vdev, 128, virtio_balloon_handle_output);
- s->svq = virtio_add_queue(vdev, 128, virtio_balloon_receive_stats);
-
- reset_stats(s);
-
- register_savevm(dev, "virtio-balloon", -1, 1,
- virtio_balloon_save, virtio_balloon_load, s);
-}
-
-static void virtio_balloon_device_unrealize(DeviceState *dev, Error **errp)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
- VirtIOBalloon *s = VIRTIO_BALLOON(dev);
-
- balloon_stats_destroy_timer(s);
- qemu_remove_balloon_handler(s);
- unregister_savevm(dev, "virtio-balloon", s);
- virtio_cleanup(vdev);
-}
-
-static void virtio_balloon_device_reset(VirtIODevice *vdev)
-{
- VirtIOBalloon *s = VIRTIO_BALLOON(vdev);
-
- if (s->stats_vq_elem != NULL) {
- g_free(s->stats_vq_elem);
- s->stats_vq_elem = NULL;
- }
-}
-
-static void virtio_balloon_instance_init(Object *obj)
-{
- VirtIOBalloon *s = VIRTIO_BALLOON(obj);
-
- object_property_add(obj, "guest-stats", "guest statistics",
- balloon_stats_get_all, NULL, NULL, s, NULL);
-
- object_property_add(obj, "guest-stats-polling-interval", "int",
- balloon_stats_get_poll_interval,
- balloon_stats_set_poll_interval,
- NULL, s, NULL);
-}
-
-static Property virtio_balloon_properties[] = {
- DEFINE_PROP_BIT("deflate-on-oom", VirtIOBalloon, host_features,
- VIRTIO_BALLOON_F_DEFLATE_ON_OOM, false),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_balloon_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
-
- dc->props = virtio_balloon_properties;
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- vdc->realize = virtio_balloon_device_realize;
- vdc->unrealize = virtio_balloon_device_unrealize;
- vdc->reset = virtio_balloon_device_reset;
- vdc->get_config = virtio_balloon_get_config;
- vdc->set_config = virtio_balloon_set_config;
- vdc->get_features = virtio_balloon_get_features;
- vdc->save = virtio_balloon_save_device;
- vdc->load = virtio_balloon_load_device;
-}
-
-static const TypeInfo virtio_balloon_info = {
- .name = TYPE_VIRTIO_BALLOON,
- .parent = TYPE_VIRTIO_DEVICE,
- .instance_size = sizeof(VirtIOBalloon),
- .instance_init = virtio_balloon_instance_init,
- .class_init = virtio_balloon_class_init,
-};
-
-static void virtio_register_types(void)
-{
- type_register_static(&virtio_balloon_info);
-}
-
-type_init(virtio_register_types)
diff --git a/qemu/hw/virtio/virtio-bus.c b/qemu/hw/virtio/virtio-bus.c
deleted file mode 100644
index 574f0e23f..000000000
--- a/qemu/hw/virtio/virtio-bus.c
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * VirtioBus
- *
- * Copyright (C) 2012 : GreenSocs Ltd
- * http://www.greensocs.com/ , email: info@greensocs.com
- *
- * Developed by :
- * Frederic Konrad <fred.konrad@greensocs.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "qemu/error-report.h"
-#include "hw/qdev.h"
-#include "hw/virtio/virtio-bus.h"
-#include "hw/virtio/virtio.h"
-
-/* #define DEBUG_VIRTIO_BUS */
-
-#ifdef DEBUG_VIRTIO_BUS
-#define DPRINTF(fmt, ...) \
-do { printf("virtio_bus: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do { } while (0)
-#endif
-
-/* A VirtIODevice is being plugged */
-void virtio_bus_device_plugged(VirtIODevice *vdev, Error **errp)
-{
- DeviceState *qdev = DEVICE(vdev);
- BusState *qbus = BUS(qdev_get_parent_bus(qdev));
- VirtioBusState *bus = VIRTIO_BUS(qbus);
- VirtioBusClass *klass = VIRTIO_BUS_GET_CLASS(bus);
- VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
-
- DPRINTF("%s: plug device.\n", qbus->name);
-
- if (klass->device_plugged != NULL) {
- klass->device_plugged(qbus->parent, errp);
- }
-
- /* Get the features of the plugged device. */
- assert(vdc->get_features != NULL);
- vdev->host_features = vdc->get_features(vdev, vdev->host_features,
- errp);
- if (klass->post_plugged != NULL) {
- klass->post_plugged(qbus->parent, errp);
- }
-}
-
-/* Reset the virtio_bus */
-void virtio_bus_reset(VirtioBusState *bus)
-{
- VirtIODevice *vdev = virtio_bus_get_device(bus);
-
- DPRINTF("%s: reset device.\n", BUS(bus)->name);
- if (vdev != NULL) {
- virtio_reset(vdev);
- }
-}
-
-/* A VirtIODevice is being unplugged */
-void virtio_bus_device_unplugged(VirtIODevice *vdev)
-{
- DeviceState *qdev = DEVICE(vdev);
- BusState *qbus = BUS(qdev_get_parent_bus(qdev));
- VirtioBusClass *klass = VIRTIO_BUS_GET_CLASS(qbus);
-
- DPRINTF("%s: remove device.\n", qbus->name);
-
- if (vdev != NULL) {
- if (klass->device_unplugged != NULL) {
- klass->device_unplugged(qbus->parent);
- }
- }
-}
-
-/* Get the device id of the plugged device. */
-uint16_t virtio_bus_get_vdev_id(VirtioBusState *bus)
-{
- VirtIODevice *vdev = virtio_bus_get_device(bus);
- assert(vdev != NULL);
- return vdev->device_id;
-}
-
-/* Get the config_len field of the plugged device. */
-size_t virtio_bus_get_vdev_config_len(VirtioBusState *bus)
-{
- VirtIODevice *vdev = virtio_bus_get_device(bus);
- assert(vdev != NULL);
- return vdev->config_len;
-}
-
-/* Get bad features of the plugged device. */
-uint32_t virtio_bus_get_vdev_bad_features(VirtioBusState *bus)
-{
- VirtIODevice *vdev = virtio_bus_get_device(bus);
- VirtioDeviceClass *k;
-
- assert(vdev != NULL);
- k = VIRTIO_DEVICE_GET_CLASS(vdev);
- if (k->bad_features != NULL) {
- return k->bad_features(vdev);
- } else {
- return 0;
- }
-}
-
-/* Get config of the plugged device. */
-void virtio_bus_get_vdev_config(VirtioBusState *bus, uint8_t *config)
-{
- VirtIODevice *vdev = virtio_bus_get_device(bus);
- VirtioDeviceClass *k;
-
- assert(vdev != NULL);
- k = VIRTIO_DEVICE_GET_CLASS(vdev);
- if (k->get_config != NULL) {
- k->get_config(vdev, config);
- }
-}
-
-/* Set config of the plugged device. */
-void virtio_bus_set_vdev_config(VirtioBusState *bus, uint8_t *config)
-{
- VirtIODevice *vdev = virtio_bus_get_device(bus);
- VirtioDeviceClass *k;
-
- assert(vdev != NULL);
- k = VIRTIO_DEVICE_GET_CLASS(vdev);
- if (k->set_config != NULL) {
- k->set_config(vdev, config);
- }
-}
-
-static char *virtio_bus_get_dev_path(DeviceState *dev)
-{
- BusState *bus = qdev_get_parent_bus(dev);
- DeviceState *proxy = DEVICE(bus->parent);
- return qdev_get_dev_path(proxy);
-}
-
-static char *virtio_bus_get_fw_dev_path(DeviceState *dev)
-{
- return NULL;
-}
-
-static void virtio_bus_class_init(ObjectClass *klass, void *data)
-{
- BusClass *bus_class = BUS_CLASS(klass);
- bus_class->get_dev_path = virtio_bus_get_dev_path;
- bus_class->get_fw_dev_path = virtio_bus_get_fw_dev_path;
-}
-
-static const TypeInfo virtio_bus_info = {
- .name = TYPE_VIRTIO_BUS,
- .parent = TYPE_BUS,
- .instance_size = sizeof(VirtioBusState),
- .abstract = true,
- .class_size = sizeof(VirtioBusClass),
- .class_init = virtio_bus_class_init
-};
-
-static void virtio_register_types(void)
-{
- type_register_static(&virtio_bus_info);
-}
-
-type_init(virtio_register_types)
diff --git a/qemu/hw/virtio/virtio-mmio.c b/qemu/hw/virtio/virtio-mmio.c
deleted file mode 100644
index d4cd91f8c..000000000
--- a/qemu/hw/virtio/virtio-mmio.c
+++ /dev/null
@@ -1,580 +0,0 @@
-/*
- * Virtio MMIO bindings
- *
- * Copyright (c) 2011 Linaro Limited
- *
- * Author:
- * Peter Maydell <peter.maydell@linaro.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "hw/virtio/virtio.h"
-#include "qemu/host-utils.h"
-#include "sysemu/kvm.h"
-#include "hw/virtio/virtio-bus.h"
-#include "qemu/error-report.h"
-
-/* #define DEBUG_VIRTIO_MMIO */
-
-#ifdef DEBUG_VIRTIO_MMIO
-
-#define DPRINTF(fmt, ...) \
-do { printf("virtio_mmio: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while (0)
-#endif
-
-/* QOM macros */
-/* virtio-mmio-bus */
-#define TYPE_VIRTIO_MMIO_BUS "virtio-mmio-bus"
-#define VIRTIO_MMIO_BUS(obj) \
- OBJECT_CHECK(VirtioBusState, (obj), TYPE_VIRTIO_MMIO_BUS)
-#define VIRTIO_MMIO_BUS_GET_CLASS(obj) \
- OBJECT_GET_CLASS(VirtioBusClass, (obj), TYPE_VIRTIO_MMIO_BUS)
-#define VIRTIO_MMIO_BUS_CLASS(klass) \
- OBJECT_CLASS_CHECK(VirtioBusClass, (klass), TYPE_VIRTIO_MMIO_BUS)
-
-/* virtio-mmio */
-#define TYPE_VIRTIO_MMIO "virtio-mmio"
-#define VIRTIO_MMIO(obj) \
- OBJECT_CHECK(VirtIOMMIOProxy, (obj), TYPE_VIRTIO_MMIO)
-
-/* Memory mapped register offsets */
-#define VIRTIO_MMIO_MAGIC 0x0
-#define VIRTIO_MMIO_VERSION 0x4
-#define VIRTIO_MMIO_DEVICEID 0x8
-#define VIRTIO_MMIO_VENDORID 0xc
-#define VIRTIO_MMIO_HOSTFEATURES 0x10
-#define VIRTIO_MMIO_HOSTFEATURESSEL 0x14
-#define VIRTIO_MMIO_GUESTFEATURES 0x20
-#define VIRTIO_MMIO_GUESTFEATURESSEL 0x24
-#define VIRTIO_MMIO_GUESTPAGESIZE 0x28
-#define VIRTIO_MMIO_QUEUESEL 0x30
-#define VIRTIO_MMIO_QUEUENUMMAX 0x34
-#define VIRTIO_MMIO_QUEUENUM 0x38
-#define VIRTIO_MMIO_QUEUEALIGN 0x3c
-#define VIRTIO_MMIO_QUEUEPFN 0x40
-#define VIRTIO_MMIO_QUEUENOTIFY 0x50
-#define VIRTIO_MMIO_INTERRUPTSTATUS 0x60
-#define VIRTIO_MMIO_INTERRUPTACK 0x64
-#define VIRTIO_MMIO_STATUS 0x70
-/* Device specific config space starts here */
-#define VIRTIO_MMIO_CONFIG 0x100
-
-#define VIRT_MAGIC 0x74726976 /* 'virt' */
-#define VIRT_VERSION 1
-#define VIRT_VENDOR 0x554D4551 /* 'QEMU' */
-
-typedef struct {
- /* Generic */
- SysBusDevice parent_obj;
- MemoryRegion iomem;
- qemu_irq irq;
- /* Guest accessible state needing migration and reset */
- uint32_t host_features_sel;
- uint32_t guest_features_sel;
- uint32_t guest_page_shift;
- /* virtio-bus */
- VirtioBusState bus;
- bool ioeventfd_disabled;
- bool ioeventfd_started;
-} VirtIOMMIOProxy;
-
-static int virtio_mmio_set_host_notifier_internal(VirtIOMMIOProxy *proxy,
- int n, bool assign,
- bool set_handler)
-{
- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
- VirtQueue *vq = virtio_get_queue(vdev, n);
- EventNotifier *notifier = virtio_queue_get_host_notifier(vq);
- int r = 0;
-
- if (assign) {
- r = event_notifier_init(notifier, 1);
- if (r < 0) {
- error_report("%s: unable to init event notifier: %d",
- __func__, r);
- return r;
- }
- virtio_queue_set_host_notifier_fd_handler(vq, true, set_handler);
- memory_region_add_eventfd(&proxy->iomem, VIRTIO_MMIO_QUEUENOTIFY, 4,
- true, n, notifier);
- } else {
- memory_region_del_eventfd(&proxy->iomem, VIRTIO_MMIO_QUEUENOTIFY, 4,
- true, n, notifier);
- virtio_queue_set_host_notifier_fd_handler(vq, false, false);
- event_notifier_cleanup(notifier);
- }
- return r;
-}
-
-static void virtio_mmio_start_ioeventfd(VirtIOMMIOProxy *proxy)
-{
- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
- int n, r;
-
- if (!kvm_eventfds_enabled() ||
- proxy->ioeventfd_disabled ||
- proxy->ioeventfd_started) {
- return;
- }
-
- for (n = 0; n < VIRTIO_QUEUE_MAX; n++) {
- if (!virtio_queue_get_num(vdev, n)) {
- continue;
- }
-
- r = virtio_mmio_set_host_notifier_internal(proxy, n, true, true);
- if (r < 0) {
- goto assign_error;
- }
- }
- proxy->ioeventfd_started = true;
- return;
-
-assign_error:
- while (--n >= 0) {
- if (!virtio_queue_get_num(vdev, n)) {
- continue;
- }
-
- r = virtio_mmio_set_host_notifier_internal(proxy, n, false, false);
- assert(r >= 0);
- }
- proxy->ioeventfd_started = false;
- error_report("%s: failed. Fallback to a userspace (slower).", __func__);
-}
-
-static void virtio_mmio_stop_ioeventfd(VirtIOMMIOProxy *proxy)
-{
- int r;
- int n;
- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
-
- if (!proxy->ioeventfd_started) {
- return;
- }
-
- for (n = 0; n < VIRTIO_QUEUE_MAX; n++) {
- if (!virtio_queue_get_num(vdev, n)) {
- continue;
- }
-
- r = virtio_mmio_set_host_notifier_internal(proxy, n, false, false);
- assert(r >= 0);
- }
- proxy->ioeventfd_started = false;
-}
-
-static uint64_t virtio_mmio_read(void *opaque, hwaddr offset, unsigned size)
-{
- VirtIOMMIOProxy *proxy = (VirtIOMMIOProxy *)opaque;
- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
-
- DPRINTF("virtio_mmio_read offset 0x%x\n", (int)offset);
-
- if (!vdev) {
- /* If no backend is present, we treat most registers as
- * read-as-zero, except for the magic number, version and
- * vendor ID. This is not strictly sanctioned by the virtio
- * spec, but it allows us to provide transports with no backend
- * plugged in which don't confuse Linux's virtio code: the
- * probe won't complain about the bad magic number, but the
- * device ID of zero means no backend will claim it.
- */
- switch (offset) {
- case VIRTIO_MMIO_MAGIC:
- return VIRT_MAGIC;
- case VIRTIO_MMIO_VERSION:
- return VIRT_VERSION;
- case VIRTIO_MMIO_VENDORID:
- return VIRT_VENDOR;
- default:
- return 0;
- }
- }
-
- if (offset >= VIRTIO_MMIO_CONFIG) {
- offset -= VIRTIO_MMIO_CONFIG;
- switch (size) {
- case 1:
- return virtio_config_readb(vdev, offset);
- case 2:
- return virtio_config_readw(vdev, offset);
- case 4:
- return virtio_config_readl(vdev, offset);
- default:
- abort();
- }
- }
- if (size != 4) {
- DPRINTF("wrong size access to register!\n");
- return 0;
- }
- switch (offset) {
- case VIRTIO_MMIO_MAGIC:
- return VIRT_MAGIC;
- case VIRTIO_MMIO_VERSION:
- return VIRT_VERSION;
- case VIRTIO_MMIO_DEVICEID:
- return vdev->device_id;
- case VIRTIO_MMIO_VENDORID:
- return VIRT_VENDOR;
- case VIRTIO_MMIO_HOSTFEATURES:
- if (proxy->host_features_sel) {
- return 0;
- }
- return vdev->host_features;
- case VIRTIO_MMIO_QUEUENUMMAX:
- if (!virtio_queue_get_num(vdev, vdev->queue_sel)) {
- return 0;
- }
- return VIRTQUEUE_MAX_SIZE;
- case VIRTIO_MMIO_QUEUEPFN:
- return virtio_queue_get_addr(vdev, vdev->queue_sel)
- >> proxy->guest_page_shift;
- case VIRTIO_MMIO_INTERRUPTSTATUS:
- return vdev->isr;
- case VIRTIO_MMIO_STATUS:
- return vdev->status;
- case VIRTIO_MMIO_HOSTFEATURESSEL:
- case VIRTIO_MMIO_GUESTFEATURES:
- case VIRTIO_MMIO_GUESTFEATURESSEL:
- case VIRTIO_MMIO_GUESTPAGESIZE:
- case VIRTIO_MMIO_QUEUESEL:
- case VIRTIO_MMIO_QUEUENUM:
- case VIRTIO_MMIO_QUEUEALIGN:
- case VIRTIO_MMIO_QUEUENOTIFY:
- case VIRTIO_MMIO_INTERRUPTACK:
- DPRINTF("read of write-only register\n");
- return 0;
- default:
- DPRINTF("bad register offset\n");
- return 0;
- }
- return 0;
-}
-
-static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
- unsigned size)
-{
- VirtIOMMIOProxy *proxy = (VirtIOMMIOProxy *)opaque;
- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
-
- DPRINTF("virtio_mmio_write offset 0x%x value 0x%" PRIx64 "\n",
- (int)offset, value);
-
- if (!vdev) {
- /* If no backend is present, we just make all registers
- * write-ignored. This allows us to provide transports with
- * no backend plugged in.
- */
- return;
- }
-
- if (offset >= VIRTIO_MMIO_CONFIG) {
- offset -= VIRTIO_MMIO_CONFIG;
- switch (size) {
- case 1:
- virtio_config_writeb(vdev, offset, value);
- break;
- case 2:
- virtio_config_writew(vdev, offset, value);
- break;
- case 4:
- virtio_config_writel(vdev, offset, value);
- break;
- default:
- abort();
- }
- return;
- }
- if (size != 4) {
- DPRINTF("wrong size access to register!\n");
- return;
- }
- switch (offset) {
- case VIRTIO_MMIO_HOSTFEATURESSEL:
- proxy->host_features_sel = value;
- break;
- case VIRTIO_MMIO_GUESTFEATURES:
- if (!proxy->guest_features_sel) {
- virtio_set_features(vdev, value);
- }
- break;
- case VIRTIO_MMIO_GUESTFEATURESSEL:
- proxy->guest_features_sel = value;
- break;
- case VIRTIO_MMIO_GUESTPAGESIZE:
- proxy->guest_page_shift = ctz32(value);
- if (proxy->guest_page_shift > 31) {
- proxy->guest_page_shift = 0;
- }
- DPRINTF("guest page size %" PRIx64 " shift %d\n", value,
- proxy->guest_page_shift);
- break;
- case VIRTIO_MMIO_QUEUESEL:
- if (value < VIRTIO_QUEUE_MAX) {
- vdev->queue_sel = value;
- }
- break;
- case VIRTIO_MMIO_QUEUENUM:
- DPRINTF("mmio_queue write %d max %d\n", (int)value, VIRTQUEUE_MAX_SIZE);
- virtio_queue_set_num(vdev, vdev->queue_sel, value);
- /* Note: only call this function for legacy devices */
- virtio_queue_update_rings(vdev, vdev->queue_sel);
- break;
- case VIRTIO_MMIO_QUEUEALIGN:
- /* Note: this is only valid for legacy devices */
- virtio_queue_set_align(vdev, vdev->queue_sel, value);
- break;
- case VIRTIO_MMIO_QUEUEPFN:
- if (value == 0) {
- virtio_reset(vdev);
- } else {
- virtio_queue_set_addr(vdev, vdev->queue_sel,
- value << proxy->guest_page_shift);
- }
- break;
- case VIRTIO_MMIO_QUEUENOTIFY:
- if (value < VIRTIO_QUEUE_MAX) {
- virtio_queue_notify(vdev, value);
- }
- break;
- case VIRTIO_MMIO_INTERRUPTACK:
- vdev->isr &= ~value;
- virtio_update_irq(vdev);
- break;
- case VIRTIO_MMIO_STATUS:
- if (!(value & VIRTIO_CONFIG_S_DRIVER_OK)) {
- virtio_mmio_stop_ioeventfd(proxy);
- }
-
- virtio_set_status(vdev, value & 0xff);
-
- if (value & VIRTIO_CONFIG_S_DRIVER_OK) {
- virtio_mmio_start_ioeventfd(proxy);
- }
-
- if (vdev->status == 0) {
- virtio_reset(vdev);
- }
- break;
- case VIRTIO_MMIO_MAGIC:
- case VIRTIO_MMIO_VERSION:
- case VIRTIO_MMIO_DEVICEID:
- case VIRTIO_MMIO_VENDORID:
- case VIRTIO_MMIO_HOSTFEATURES:
- case VIRTIO_MMIO_QUEUENUMMAX:
- case VIRTIO_MMIO_INTERRUPTSTATUS:
- DPRINTF("write to readonly register\n");
- break;
-
- default:
- DPRINTF("bad register offset\n");
- }
-}
-
-static const MemoryRegionOps virtio_mem_ops = {
- .read = virtio_mmio_read,
- .write = virtio_mmio_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void virtio_mmio_update_irq(DeviceState *opaque, uint16_t vector)
-{
- VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
- int level;
-
- if (!vdev) {
- return;
- }
- level = (vdev->isr != 0);
- DPRINTF("virtio_mmio setting IRQ %d\n", level);
- qemu_set_irq(proxy->irq, level);
-}
-
-static int virtio_mmio_load_config(DeviceState *opaque, QEMUFile *f)
-{
- VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
-
- proxy->host_features_sel = qemu_get_be32(f);
- proxy->guest_features_sel = qemu_get_be32(f);
- proxy->guest_page_shift = qemu_get_be32(f);
- return 0;
-}
-
-static void virtio_mmio_save_config(DeviceState *opaque, QEMUFile *f)
-{
- VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
-
- qemu_put_be32(f, proxy->host_features_sel);
- qemu_put_be32(f, proxy->guest_features_sel);
- qemu_put_be32(f, proxy->guest_page_shift);
-}
-
-static void virtio_mmio_reset(DeviceState *d)
-{
- VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
-
- virtio_mmio_stop_ioeventfd(proxy);
- virtio_bus_reset(&proxy->bus);
- proxy->host_features_sel = 0;
- proxy->guest_features_sel = 0;
- proxy->guest_page_shift = 0;
-}
-
-static int virtio_mmio_set_guest_notifier(DeviceState *d, int n, bool assign,
- bool with_irqfd)
-{
- VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
- VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
- VirtQueue *vq = virtio_get_queue(vdev, n);
- EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);
-
- if (assign) {
- int r = event_notifier_init(notifier, 0);
- if (r < 0) {
- return r;
- }
- virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd);
- } else {
- virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd);
- event_notifier_cleanup(notifier);
- }
-
- if (vdc->guest_notifier_mask) {
- vdc->guest_notifier_mask(vdev, n, !assign);
- }
-
- return 0;
-}
-
-static int virtio_mmio_set_guest_notifiers(DeviceState *d, int nvqs,
- bool assign)
-{
- VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
- /* TODO: need to check if kvm-arm supports irqfd */
- bool with_irqfd = false;
- int r, n;
-
- nvqs = MIN(nvqs, VIRTIO_QUEUE_MAX);
-
- for (n = 0; n < nvqs; n++) {
- if (!virtio_queue_get_num(vdev, n)) {
- break;
- }
-
- r = virtio_mmio_set_guest_notifier(d, n, assign, with_irqfd);
- if (r < 0) {
- goto assign_error;
- }
- }
-
- return 0;
-
-assign_error:
- /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */
- assert(assign);
- while (--n >= 0) {
- virtio_mmio_set_guest_notifier(d, n, !assign, false);
- }
- return r;
-}
-
-static int virtio_mmio_set_host_notifier(DeviceState *opaque, int n,
- bool assign)
-{
- VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
-
- /* Stop using ioeventfd for virtqueue kick if the device starts using host
- * notifiers. This makes it easy to avoid stepping on each others' toes.
- */
- proxy->ioeventfd_disabled = assign;
- if (assign) {
- virtio_mmio_stop_ioeventfd(proxy);
- }
- /* We don't need to start here: it's not needed because backend
- * currently only stops on status change away from ok,
- * reset, vmstop and such. If we do add code to start here,
- * need to check vmstate, device state etc. */
- return virtio_mmio_set_host_notifier_internal(proxy, n, assign, false);
-}
-
-/* virtio-mmio device */
-
-static void virtio_mmio_realizefn(DeviceState *d, Error **errp)
-{
- VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
- SysBusDevice *sbd = SYS_BUS_DEVICE(d);
-
- qbus_create_inplace(&proxy->bus, sizeof(proxy->bus), TYPE_VIRTIO_MMIO_BUS,
- d, NULL);
- sysbus_init_irq(sbd, &proxy->irq);
- memory_region_init_io(&proxy->iomem, OBJECT(d), &virtio_mem_ops, proxy,
- TYPE_VIRTIO_MMIO, 0x200);
- sysbus_init_mmio(sbd, &proxy->iomem);
-}
-
-static void virtio_mmio_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = virtio_mmio_realizefn;
- dc->reset = virtio_mmio_reset;
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
-}
-
-static const TypeInfo virtio_mmio_info = {
- .name = TYPE_VIRTIO_MMIO,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(VirtIOMMIOProxy),
- .class_init = virtio_mmio_class_init,
-};
-
-/* virtio-mmio-bus. */
-
-static void virtio_mmio_bus_class_init(ObjectClass *klass, void *data)
-{
- BusClass *bus_class = BUS_CLASS(klass);
- VirtioBusClass *k = VIRTIO_BUS_CLASS(klass);
-
- k->notify = virtio_mmio_update_irq;
- k->save_config = virtio_mmio_save_config;
- k->load_config = virtio_mmio_load_config;
- k->set_host_notifier = virtio_mmio_set_host_notifier;
- k->set_guest_notifiers = virtio_mmio_set_guest_notifiers;
- k->has_variable_vring_alignment = true;
- bus_class->max_dev = 1;
-}
-
-static const TypeInfo virtio_mmio_bus_info = {
- .name = TYPE_VIRTIO_MMIO_BUS,
- .parent = TYPE_VIRTIO_BUS,
- .instance_size = sizeof(VirtioBusState),
- .class_init = virtio_mmio_bus_class_init,
-};
-
-static void virtio_mmio_register_types(void)
-{
- type_register_static(&virtio_mmio_bus_info);
- type_register_static(&virtio_mmio_info);
-}
-
-type_init(virtio_mmio_register_types)
diff --git a/qemu/hw/virtio/virtio-pci.c b/qemu/hw/virtio/virtio-pci.c
deleted file mode 100644
index bfedbbf17..000000000
--- a/qemu/hw/virtio/virtio-pci.c
+++ /dev/null
@@ -1,2534 +0,0 @@
-/*
- * Virtio PCI Bindings
- *
- * Copyright IBM, Corp. 2007
- * Copyright (c) 2009 CodeSourcery
- *
- * Authors:
- * Anthony Liguori <aliguori@us.ibm.com>
- * Paul Brook <paul@codesourcery.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-
-#include "standard-headers/linux/virtio_pci.h"
-#include "hw/virtio/virtio.h"
-#include "hw/virtio/virtio-blk.h"
-#include "hw/virtio/virtio-net.h"
-#include "hw/virtio/virtio-serial.h"
-#include "hw/virtio/virtio-scsi.h"
-#include "hw/virtio/virtio-balloon.h"
-#include "hw/virtio/virtio-input.h"
-#include "hw/pci/pci.h"
-#include "qapi/error.h"
-#include "qemu/error-report.h"
-#include "hw/pci/msi.h"
-#include "hw/pci/msix.h"
-#include "hw/loader.h"
-#include "sysemu/kvm.h"
-#include "sysemu/block-backend.h"
-#include "virtio-pci.h"
-#include "qemu/range.h"
-#include "hw/virtio/virtio-bus.h"
-#include "qapi/visitor.h"
-
-#define VIRTIO_PCI_REGION_SIZE(dev) VIRTIO_PCI_CONFIG_OFF(msix_present(dev))
-
-#undef VIRTIO_PCI_CONFIG
-
-/* The remaining space is defined by each driver as the per-driver
- * configuration space */
-#define VIRTIO_PCI_CONFIG_SIZE(dev) VIRTIO_PCI_CONFIG_OFF(msix_enabled(dev))
-
-static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size,
- VirtIOPCIProxy *dev);
-static void virtio_pci_reset(DeviceState *qdev);
-
-/* virtio device */
-/* DeviceState to VirtIOPCIProxy. For use off data-path. TODO: use QOM. */
-static inline VirtIOPCIProxy *to_virtio_pci_proxy(DeviceState *d)
-{
- return container_of(d, VirtIOPCIProxy, pci_dev.qdev);
-}
-
-/* DeviceState to VirtIOPCIProxy. Note: used on datapath,
- * be careful and test performance if you change this.
- */
-static inline VirtIOPCIProxy *to_virtio_pci_proxy_fast(DeviceState *d)
-{
- return container_of(d, VirtIOPCIProxy, pci_dev.qdev);
-}
-
-static void virtio_pci_notify(DeviceState *d, uint16_t vector)
-{
- VirtIOPCIProxy *proxy = to_virtio_pci_proxy_fast(d);
-
- if (msix_enabled(&proxy->pci_dev))
- msix_notify(&proxy->pci_dev, vector);
- else {
- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
- pci_set_irq(&proxy->pci_dev, vdev->isr & 1);
- }
-}
-
-static void virtio_pci_save_config(DeviceState *d, QEMUFile *f)
-{
- VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
-
- pci_device_save(&proxy->pci_dev, f);
- msix_save(&proxy->pci_dev, f);
- if (msix_present(&proxy->pci_dev))
- qemu_put_be16(f, vdev->config_vector);
-}
-
-static void virtio_pci_load_modern_queue_state(VirtIOPCIQueue *vq,
- QEMUFile *f)
-{
- vq->num = qemu_get_be16(f);
- vq->enabled = qemu_get_be16(f);
- vq->desc[0] = qemu_get_be32(f);
- vq->desc[1] = qemu_get_be32(f);
- vq->avail[0] = qemu_get_be32(f);
- vq->avail[1] = qemu_get_be32(f);
- vq->used[0] = qemu_get_be32(f);
- vq->used[1] = qemu_get_be32(f);
-}
-
-static bool virtio_pci_has_extra_state(DeviceState *d)
-{
- VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
-
- return proxy->flags & VIRTIO_PCI_FLAG_MIGRATE_EXTRA;
-}
-
-static int get_virtio_pci_modern_state(QEMUFile *f, void *pv, size_t size)
-{
- VirtIOPCIProxy *proxy = pv;
- int i;
-
- proxy->dfselect = qemu_get_be32(f);
- proxy->gfselect = qemu_get_be32(f);
- proxy->guest_features[0] = qemu_get_be32(f);
- proxy->guest_features[1] = qemu_get_be32(f);
- for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
- virtio_pci_load_modern_queue_state(&proxy->vqs[i], f);
- }
-
- return 0;
-}
-
-static void virtio_pci_save_modern_queue_state(VirtIOPCIQueue *vq,
- QEMUFile *f)
-{
- qemu_put_be16(f, vq->num);
- qemu_put_be16(f, vq->enabled);
- qemu_put_be32(f, vq->desc[0]);
- qemu_put_be32(f, vq->desc[1]);
- qemu_put_be32(f, vq->avail[0]);
- qemu_put_be32(f, vq->avail[1]);
- qemu_put_be32(f, vq->used[0]);
- qemu_put_be32(f, vq->used[1]);
-}
-
-static void put_virtio_pci_modern_state(QEMUFile *f, void *pv, size_t size)
-{
- VirtIOPCIProxy *proxy = pv;
- int i;
-
- qemu_put_be32(f, proxy->dfselect);
- qemu_put_be32(f, proxy->gfselect);
- qemu_put_be32(f, proxy->guest_features[0]);
- qemu_put_be32(f, proxy->guest_features[1]);
- for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
- virtio_pci_save_modern_queue_state(&proxy->vqs[i], f);
- }
-}
-
-static const VMStateInfo vmstate_info_virtio_pci_modern_state = {
- .name = "virtqueue_state",
- .get = get_virtio_pci_modern_state,
- .put = put_virtio_pci_modern_state,
-};
-
-static bool virtio_pci_modern_state_needed(void *opaque)
-{
- VirtIOPCIProxy *proxy = opaque;
-
- return !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_MODERN);
-}
-
-static const VMStateDescription vmstate_virtio_pci_modern_state = {
- .name = "virtio_pci/modern_state",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = &virtio_pci_modern_state_needed,
- .fields = (VMStateField[]) {
- {
- .name = "modern_state",
- .version_id = 0,
- .field_exists = NULL,
- .size = 0,
- .info = &vmstate_info_virtio_pci_modern_state,
- .flags = VMS_SINGLE,
- .offset = 0,
- },
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_virtio_pci = {
- .name = "virtio_pci",
- .version_id = 1,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .fields = (VMStateField[]) {
- VMSTATE_END_OF_LIST()
- },
- .subsections = (const VMStateDescription*[]) {
- &vmstate_virtio_pci_modern_state,
- NULL
- }
-};
-
-static void virtio_pci_save_extra_state(DeviceState *d, QEMUFile *f)
-{
- VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
-
- vmstate_save_state(f, &vmstate_virtio_pci, proxy, NULL);
-}
-
-static int virtio_pci_load_extra_state(DeviceState *d, QEMUFile *f)
-{
- VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
-
- return vmstate_load_state(f, &vmstate_virtio_pci, proxy, 1);
-}
-
-static void virtio_pci_save_queue(DeviceState *d, int n, QEMUFile *f)
-{
- VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
-
- if (msix_present(&proxy->pci_dev))
- qemu_put_be16(f, virtio_queue_vector(vdev, n));
-}
-
-static int virtio_pci_load_config(DeviceState *d, QEMUFile *f)
-{
- VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
-
- int ret;
- ret = pci_device_load(&proxy->pci_dev, f);
- if (ret) {
- return ret;
- }
- msix_unuse_all_vectors(&proxy->pci_dev);
- msix_load(&proxy->pci_dev, f);
- if (msix_present(&proxy->pci_dev)) {
- qemu_get_be16s(f, &vdev->config_vector);
- } else {
- vdev->config_vector = VIRTIO_NO_VECTOR;
- }
- if (vdev->config_vector != VIRTIO_NO_VECTOR) {
- return msix_vector_use(&proxy->pci_dev, vdev->config_vector);
- }
- return 0;
-}
-
-static int virtio_pci_load_queue(DeviceState *d, int n, QEMUFile *f)
-{
- VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
-
- uint16_t vector;
- if (msix_present(&proxy->pci_dev)) {
- qemu_get_be16s(f, &vector);
- } else {
- vector = VIRTIO_NO_VECTOR;
- }
- virtio_queue_set_vector(vdev, n, vector);
- if (vector != VIRTIO_NO_VECTOR) {
- return msix_vector_use(&proxy->pci_dev, vector);
- }
-
- return 0;
-}
-
-#define QEMU_VIRTIO_PCI_QUEUE_MEM_MULT 0x1000
-
-static int virtio_pci_set_host_notifier_internal(VirtIOPCIProxy *proxy,
- int n, bool assign, bool set_handler)
-{
- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
- VirtQueue *vq = virtio_get_queue(vdev, n);
- EventNotifier *notifier = virtio_queue_get_host_notifier(vq);
- bool legacy = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_LEGACY);
- bool modern = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_MODERN);
- bool fast_mmio = kvm_ioeventfd_any_length_enabled();
- bool modern_pio = proxy->flags & VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY;
- MemoryRegion *modern_mr = &proxy->notify.mr;
- MemoryRegion *modern_notify_mr = &proxy->notify_pio.mr;
- MemoryRegion *legacy_mr = &proxy->bar;
- hwaddr modern_addr = QEMU_VIRTIO_PCI_QUEUE_MEM_MULT *
- virtio_get_queue_index(vq);
- hwaddr legacy_addr = VIRTIO_PCI_QUEUE_NOTIFY;
- int r = 0;
-
- if (assign) {
- r = event_notifier_init(notifier, 1);
- if (r < 0) {
- error_report("%s: unable to init event notifier: %d",
- __func__, r);
- return r;
- }
- virtio_queue_set_host_notifier_fd_handler(vq, true, set_handler);
- if (modern) {
- if (fast_mmio) {
- memory_region_add_eventfd(modern_mr, modern_addr, 0,
- false, n, notifier);
- } else {
- memory_region_add_eventfd(modern_mr, modern_addr, 2,
- false, n, notifier);
- }
- if (modern_pio) {
- memory_region_add_eventfd(modern_notify_mr, 0, 2,
- true, n, notifier);
- }
- }
- if (legacy) {
- memory_region_add_eventfd(legacy_mr, legacy_addr, 2,
- true, n, notifier);
- }
- } else {
- if (modern) {
- if (fast_mmio) {
- memory_region_del_eventfd(modern_mr, modern_addr, 0,
- false, n, notifier);
- } else {
- memory_region_del_eventfd(modern_mr, modern_addr, 2,
- false, n, notifier);
- }
- if (modern_pio) {
- memory_region_del_eventfd(modern_notify_mr, 0, 2,
- true, n, notifier);
- }
- }
- if (legacy) {
- memory_region_del_eventfd(legacy_mr, legacy_addr, 2,
- true, n, notifier);
- }
- virtio_queue_set_host_notifier_fd_handler(vq, false, false);
- event_notifier_cleanup(notifier);
- }
- return r;
-}
-
-static void virtio_pci_start_ioeventfd(VirtIOPCIProxy *proxy)
-{
- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
- int n, r;
-
- if (!(proxy->flags & VIRTIO_PCI_FLAG_USE_IOEVENTFD) ||
- proxy->ioeventfd_disabled ||
- proxy->ioeventfd_started) {
- return;
- }
-
- for (n = 0; n < VIRTIO_QUEUE_MAX; n++) {
- if (!virtio_queue_get_num(vdev, n)) {
- continue;
- }
-
- r = virtio_pci_set_host_notifier_internal(proxy, n, true, true);
- if (r < 0) {
- goto assign_error;
- }
- }
- proxy->ioeventfd_started = true;
- return;
-
-assign_error:
- while (--n >= 0) {
- if (!virtio_queue_get_num(vdev, n)) {
- continue;
- }
-
- r = virtio_pci_set_host_notifier_internal(proxy, n, false, false);
- assert(r >= 0);
- }
- proxy->ioeventfd_started = false;
- error_report("%s: failed. Fallback to a userspace (slower).", __func__);
-}
-
-static void virtio_pci_stop_ioeventfd(VirtIOPCIProxy *proxy)
-{
- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
- int r;
- int n;
-
- if (!proxy->ioeventfd_started) {
- return;
- }
-
- for (n = 0; n < VIRTIO_QUEUE_MAX; n++) {
- if (!virtio_queue_get_num(vdev, n)) {
- continue;
- }
-
- r = virtio_pci_set_host_notifier_internal(proxy, n, false, false);
- assert(r >= 0);
- }
- proxy->ioeventfd_started = false;
-}
-
-static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
-{
- VirtIOPCIProxy *proxy = opaque;
- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
- hwaddr pa;
-
- switch (addr) {
- case VIRTIO_PCI_GUEST_FEATURES:
- /* Guest does not negotiate properly? We have to assume nothing. */
- if (val & (1 << VIRTIO_F_BAD_FEATURE)) {
- val = virtio_bus_get_vdev_bad_features(&proxy->bus);
- }
- virtio_set_features(vdev, val);
- break;
- case VIRTIO_PCI_QUEUE_PFN:
- pa = (hwaddr)val << VIRTIO_PCI_QUEUE_ADDR_SHIFT;
- if (pa == 0) {
- virtio_pci_reset(DEVICE(proxy));
- }
- else
- virtio_queue_set_addr(vdev, vdev->queue_sel, pa);
- break;
- case VIRTIO_PCI_QUEUE_SEL:
- if (val < VIRTIO_QUEUE_MAX)
- vdev->queue_sel = val;
- break;
- case VIRTIO_PCI_QUEUE_NOTIFY:
- if (val < VIRTIO_QUEUE_MAX) {
- virtio_queue_notify(vdev, val);
- }
- break;
- case VIRTIO_PCI_STATUS:
- if (!(val & VIRTIO_CONFIG_S_DRIVER_OK)) {
- virtio_pci_stop_ioeventfd(proxy);
- }
-
- virtio_set_status(vdev, val & 0xFF);
-
- if (val & VIRTIO_CONFIG_S_DRIVER_OK) {
- virtio_pci_start_ioeventfd(proxy);
- }
-
- if (vdev->status == 0) {
- virtio_pci_reset(DEVICE(proxy));
- }
-
- /* Linux before 2.6.34 drives the device without enabling
- the PCI device bus master bit. Enable it automatically
- for the guest. This is a PCI spec violation but so is
- initiating DMA with bus master bit clear. */
- if (val == (VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER)) {
- pci_default_write_config(&proxy->pci_dev, PCI_COMMAND,
- proxy->pci_dev.config[PCI_COMMAND] |
- PCI_COMMAND_MASTER, 1);
- }
- break;
- case VIRTIO_MSI_CONFIG_VECTOR:
- msix_vector_unuse(&proxy->pci_dev, vdev->config_vector);
- /* Make it possible for guest to discover an error took place. */
- if (msix_vector_use(&proxy->pci_dev, val) < 0)
- val = VIRTIO_NO_VECTOR;
- vdev->config_vector = val;
- break;
- case VIRTIO_MSI_QUEUE_VECTOR:
- msix_vector_unuse(&proxy->pci_dev,
- virtio_queue_vector(vdev, vdev->queue_sel));
- /* Make it possible for guest to discover an error took place. */
- if (msix_vector_use(&proxy->pci_dev, val) < 0)
- val = VIRTIO_NO_VECTOR;
- virtio_queue_set_vector(vdev, vdev->queue_sel, val);
- break;
- default:
- error_report("%s: unexpected address 0x%x value 0x%x",
- __func__, addr, val);
- break;
- }
-}
-
-static uint32_t virtio_ioport_read(VirtIOPCIProxy *proxy, uint32_t addr)
-{
- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
- uint32_t ret = 0xFFFFFFFF;
-
- switch (addr) {
- case VIRTIO_PCI_HOST_FEATURES:
- ret = vdev->host_features;
- break;
- case VIRTIO_PCI_GUEST_FEATURES:
- ret = vdev->guest_features;
- break;
- case VIRTIO_PCI_QUEUE_PFN:
- ret = virtio_queue_get_addr(vdev, vdev->queue_sel)
- >> VIRTIO_PCI_QUEUE_ADDR_SHIFT;
- break;
- case VIRTIO_PCI_QUEUE_NUM:
- ret = virtio_queue_get_num(vdev, vdev->queue_sel);
- break;
- case VIRTIO_PCI_QUEUE_SEL:
- ret = vdev->queue_sel;
- break;
- case VIRTIO_PCI_STATUS:
- ret = vdev->status;
- break;
- case VIRTIO_PCI_ISR:
- /* reading from the ISR also clears it. */
- ret = vdev->isr;
- vdev->isr = 0;
- pci_irq_deassert(&proxy->pci_dev);
- break;
- case VIRTIO_MSI_CONFIG_VECTOR:
- ret = vdev->config_vector;
- break;
- case VIRTIO_MSI_QUEUE_VECTOR:
- ret = virtio_queue_vector(vdev, vdev->queue_sel);
- break;
- default:
- break;
- }
-
- return ret;
-}
-
-static uint64_t virtio_pci_config_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- VirtIOPCIProxy *proxy = opaque;
- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
- uint32_t config = VIRTIO_PCI_CONFIG_SIZE(&proxy->pci_dev);
- uint64_t val = 0;
- if (addr < config) {
- return virtio_ioport_read(proxy, addr);
- }
- addr -= config;
-
- switch (size) {
- case 1:
- val = virtio_config_readb(vdev, addr);
- break;
- case 2:
- val = virtio_config_readw(vdev, addr);
- if (virtio_is_big_endian(vdev)) {
- val = bswap16(val);
- }
- break;
- case 4:
- val = virtio_config_readl(vdev, addr);
- if (virtio_is_big_endian(vdev)) {
- val = bswap32(val);
- }
- break;
- }
- return val;
-}
-
-static void virtio_pci_config_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- VirtIOPCIProxy *proxy = opaque;
- uint32_t config = VIRTIO_PCI_CONFIG_SIZE(&proxy->pci_dev);
- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
- if (addr < config) {
- virtio_ioport_write(proxy, addr, val);
- return;
- }
- addr -= config;
- /*
- * Virtio-PCI is odd. Ioports are LE but config space is target native
- * endian.
- */
- switch (size) {
- case 1:
- virtio_config_writeb(vdev, addr, val);
- break;
- case 2:
- if (virtio_is_big_endian(vdev)) {
- val = bswap16(val);
- }
- virtio_config_writew(vdev, addr, val);
- break;
- case 4:
- if (virtio_is_big_endian(vdev)) {
- val = bswap32(val);
- }
- virtio_config_writel(vdev, addr, val);
- break;
- }
-}
-
-static const MemoryRegionOps virtio_pci_config_ops = {
- .read = virtio_pci_config_read,
- .write = virtio_pci_config_write,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 4,
- },
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-/* Below are generic functions to do memcpy from/to an address space,
- * without byteswaps, with input validation.
- *
- * As regular address_space_* APIs all do some kind of byteswap at least for
- * some host/target combinations, we are forced to explicitly convert to a
- * known-endianness integer value.
- * It doesn't really matter which endian format to go through, so the code
- * below selects the endian that causes the least amount of work on the given
- * host.
- *
- * Note: host pointer must be aligned.
- */
-static
-void virtio_address_space_write(AddressSpace *as, hwaddr addr,
- const uint8_t *buf, int len)
-{
- uint32_t val;
-
- /* address_space_* APIs assume an aligned address.
- * As address is under guest control, handle illegal values.
- */
- addr &= ~(len - 1);
-
- /* Make sure caller aligned buf properly */
- assert(!(((uintptr_t)buf) & (len - 1)));
-
- switch (len) {
- case 1:
- val = pci_get_byte(buf);
- address_space_stb(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL);
- break;
- case 2:
- val = pci_get_word(buf);
- address_space_stw_le(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL);
- break;
- case 4:
- val = pci_get_long(buf);
- address_space_stl_le(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL);
- break;
- default:
- /* As length is under guest control, handle illegal values. */
- break;
- }
-}
-
-static void
-virtio_address_space_read(AddressSpace *as, hwaddr addr, uint8_t *buf, int len)
-{
- uint32_t val;
-
- /* address_space_* APIs assume an aligned address.
- * As address is under guest control, handle illegal values.
- */
- addr &= ~(len - 1);
-
- /* Make sure caller aligned buf properly */
- assert(!(((uintptr_t)buf) & (len - 1)));
-
- switch (len) {
- case 1:
- val = address_space_ldub(as, addr, MEMTXATTRS_UNSPECIFIED, NULL);
- pci_set_byte(buf, val);
- break;
- case 2:
- val = address_space_lduw_le(as, addr, MEMTXATTRS_UNSPECIFIED, NULL);
- pci_set_word(buf, val);
- break;
- case 4:
- val = address_space_ldl_le(as, addr, MEMTXATTRS_UNSPECIFIED, NULL);
- pci_set_long(buf, val);
- break;
- default:
- /* As length is under guest control, handle illegal values. */
- break;
- }
-}
-
-static void virtio_write_config(PCIDevice *pci_dev, uint32_t address,
- uint32_t val, int len)
-{
- VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
- struct virtio_pci_cfg_cap *cfg;
-
- pci_default_write_config(pci_dev, address, val, len);
-
- if (range_covers_byte(address, len, PCI_COMMAND) &&
- !(pci_dev->config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
- virtio_pci_stop_ioeventfd(proxy);
- virtio_set_status(vdev, vdev->status & ~VIRTIO_CONFIG_S_DRIVER_OK);
- }
-
- if (proxy->config_cap &&
- ranges_overlap(address, len, proxy->config_cap + offsetof(struct virtio_pci_cfg_cap,
- pci_cfg_data),
- sizeof cfg->pci_cfg_data)) {
- uint32_t off;
- uint32_t len;
-
- cfg = (void *)(proxy->pci_dev.config + proxy->config_cap);
- off = le32_to_cpu(cfg->cap.offset);
- len = le32_to_cpu(cfg->cap.length);
-
- if (len == 1 || len == 2 || len == 4) {
- assert(len <= sizeof cfg->pci_cfg_data);
- virtio_address_space_write(&proxy->modern_as, off,
- cfg->pci_cfg_data, len);
- }
- }
-}
-
-static uint32_t virtio_read_config(PCIDevice *pci_dev,
- uint32_t address, int len)
-{
- VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
- struct virtio_pci_cfg_cap *cfg;
-
- if (proxy->config_cap &&
- ranges_overlap(address, len, proxy->config_cap + offsetof(struct virtio_pci_cfg_cap,
- pci_cfg_data),
- sizeof cfg->pci_cfg_data)) {
- uint32_t off;
- uint32_t len;
-
- cfg = (void *)(proxy->pci_dev.config + proxy->config_cap);
- off = le32_to_cpu(cfg->cap.offset);
- len = le32_to_cpu(cfg->cap.length);
-
- if (len == 1 || len == 2 || len == 4) {
- assert(len <= sizeof cfg->pci_cfg_data);
- virtio_address_space_read(&proxy->modern_as, off,
- cfg->pci_cfg_data, len);
- }
- }
-
- return pci_default_read_config(pci_dev, address, len);
-}
-
-static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy,
- unsigned int queue_no,
- unsigned int vector,
- MSIMessage msg)
-{
- VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
- int ret;
-
- if (irqfd->users == 0) {
- ret = kvm_irqchip_add_msi_route(kvm_state, msg, &proxy->pci_dev);
- if (ret < 0) {
- return ret;
- }
- irqfd->virq = ret;
- }
- irqfd->users++;
- return 0;
-}
-
-static void kvm_virtio_pci_vq_vector_release(VirtIOPCIProxy *proxy,
- unsigned int vector)
-{
- VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
- if (--irqfd->users == 0) {
- kvm_irqchip_release_virq(kvm_state, irqfd->virq);
- }
-}
-
-static int kvm_virtio_pci_irqfd_use(VirtIOPCIProxy *proxy,
- unsigned int queue_no,
- unsigned int vector)
-{
- VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
- VirtQueue *vq = virtio_get_queue(vdev, queue_no);
- EventNotifier *n = virtio_queue_get_guest_notifier(vq);
- int ret;
- ret = kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, n, NULL, irqfd->virq);
- return ret;
-}
-
-static void kvm_virtio_pci_irqfd_release(VirtIOPCIProxy *proxy,
- unsigned int queue_no,
- unsigned int vector)
-{
- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
- VirtQueue *vq = virtio_get_queue(vdev, queue_no);
- EventNotifier *n = virtio_queue_get_guest_notifier(vq);
- VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
- int ret;
-
- ret = kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, n, irqfd->virq);
- assert(ret == 0);
-}
-
-static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs)
-{
- PCIDevice *dev = &proxy->pci_dev;
- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
- unsigned int vector;
- int ret, queue_no;
- MSIMessage msg;
-
- for (queue_no = 0; queue_no < nvqs; queue_no++) {
- if (!virtio_queue_get_num(vdev, queue_no)) {
- break;
- }
- vector = virtio_queue_vector(vdev, queue_no);
- if (vector >= msix_nr_vectors_allocated(dev)) {
- continue;
- }
- msg = msix_get_message(dev, vector);
- ret = kvm_virtio_pci_vq_vector_use(proxy, queue_no, vector, msg);
- if (ret < 0) {
- goto undo;
- }
- /* If guest supports masking, set up irqfd now.
- * Otherwise, delay until unmasked in the frontend.
- */
- if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) {
- ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector);
- if (ret < 0) {
- kvm_virtio_pci_vq_vector_release(proxy, vector);
- goto undo;
- }
- }
- }
- return 0;
-
-undo:
- while (--queue_no >= 0) {
- vector = virtio_queue_vector(vdev, queue_no);
- if (vector >= msix_nr_vectors_allocated(dev)) {
- continue;
- }
- if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) {
- kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
- }
- kvm_virtio_pci_vq_vector_release(proxy, vector);
- }
- return ret;
-}
-
-static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs)
-{
- PCIDevice *dev = &proxy->pci_dev;
- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
- unsigned int vector;
- int queue_no;
- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
-
- for (queue_no = 0; queue_no < nvqs; queue_no++) {
- if (!virtio_queue_get_num(vdev, queue_no)) {
- break;
- }
- vector = virtio_queue_vector(vdev, queue_no);
- if (vector >= msix_nr_vectors_allocated(dev)) {
- continue;
- }
- /* If guest supports masking, clean up irqfd now.
- * Otherwise, it was cleaned when masked in the frontend.
- */
- if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) {
- kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
- }
- kvm_virtio_pci_vq_vector_release(proxy, vector);
- }
-}
-
-static int virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy,
- unsigned int queue_no,
- unsigned int vector,
- MSIMessage msg)
-{
- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
- VirtQueue *vq = virtio_get_queue(vdev, queue_no);
- EventNotifier *n = virtio_queue_get_guest_notifier(vq);
- VirtIOIRQFD *irqfd;
- int ret = 0;
-
- if (proxy->vector_irqfd) {
- irqfd = &proxy->vector_irqfd[vector];
- if (irqfd->msg.data != msg.data || irqfd->msg.address != msg.address) {
- ret = kvm_irqchip_update_msi_route(kvm_state, irqfd->virq, msg,
- &proxy->pci_dev);
- if (ret < 0) {
- return ret;
- }
- }
- }
-
- /* If guest supports masking, irqfd is already setup, unmask it.
- * Otherwise, set it up now.
- */
- if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) {
- k->guest_notifier_mask(vdev, queue_no, false);
- /* Test after unmasking to avoid losing events. */
- if (k->guest_notifier_pending &&
- k->guest_notifier_pending(vdev, queue_no)) {
- event_notifier_set(n);
- }
- } else {
- ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector);
- }
- return ret;
-}
-
-static void virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy,
- unsigned int queue_no,
- unsigned int vector)
-{
- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
-
- /* If guest supports masking, keep irqfd but mask it.
- * Otherwise, clean it up now.
- */
- if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) {
- k->guest_notifier_mask(vdev, queue_no, true);
- } else {
- kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
- }
-}
-
-static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector,
- MSIMessage msg)
-{
- VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
- VirtQueue *vq = virtio_vector_first_queue(vdev, vector);
- int ret, index, unmasked = 0;
-
- while (vq) {
- index = virtio_get_queue_index(vq);
- if (!virtio_queue_get_num(vdev, index)) {
- break;
- }
- if (index < proxy->nvqs_with_notifiers) {
- ret = virtio_pci_vq_vector_unmask(proxy, index, vector, msg);
- if (ret < 0) {
- goto undo;
- }
- ++unmasked;
- }
- vq = virtio_vector_next_queue(vq);
- }
-
- return 0;
-
-undo:
- vq = virtio_vector_first_queue(vdev, vector);
- while (vq && unmasked >= 0) {
- index = virtio_get_queue_index(vq);
- if (index < proxy->nvqs_with_notifiers) {
- virtio_pci_vq_vector_mask(proxy, index, vector);
- --unmasked;
- }
- vq = virtio_vector_next_queue(vq);
- }
- return ret;
-}
-
-static void virtio_pci_vector_mask(PCIDevice *dev, unsigned vector)
-{
- VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
- VirtQueue *vq = virtio_vector_first_queue(vdev, vector);
- int index;
-
- while (vq) {
- index = virtio_get_queue_index(vq);
- if (!virtio_queue_get_num(vdev, index)) {
- break;
- }
- if (index < proxy->nvqs_with_notifiers) {
- virtio_pci_vq_vector_mask(proxy, index, vector);
- }
- vq = virtio_vector_next_queue(vq);
- }
-}
-
-static void virtio_pci_vector_poll(PCIDevice *dev,
- unsigned int vector_start,
- unsigned int vector_end)
-{
- VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
- int queue_no;
- unsigned int vector;
- EventNotifier *notifier;
- VirtQueue *vq;
-
- for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) {
- if (!virtio_queue_get_num(vdev, queue_no)) {
- break;
- }
- vector = virtio_queue_vector(vdev, queue_no);
- if (vector < vector_start || vector >= vector_end ||
- !msix_is_masked(dev, vector)) {
- continue;
- }
- vq = virtio_get_queue(vdev, queue_no);
- notifier = virtio_queue_get_guest_notifier(vq);
- if (k->guest_notifier_pending) {
- if (k->guest_notifier_pending(vdev, queue_no)) {
- msix_set_pending(dev, vector);
- }
- } else if (event_notifier_test_and_clear(notifier)) {
- msix_set_pending(dev, vector);
- }
- }
-}
-
-static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign,
- bool with_irqfd)
-{
- VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
- VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
- VirtQueue *vq = virtio_get_queue(vdev, n);
- EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);
-
- if (assign) {
- int r = event_notifier_init(notifier, 0);
- if (r < 0) {
- return r;
- }
- virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd);
- } else {
- virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd);
- event_notifier_cleanup(notifier);
- }
-
- if (!msix_enabled(&proxy->pci_dev) &&
- vdev->use_guest_notifier_mask &&
- vdc->guest_notifier_mask) {
- vdc->guest_notifier_mask(vdev, n, !assign);
- }
-
- return 0;
-}
-
-static bool virtio_pci_query_guest_notifiers(DeviceState *d)
-{
- VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
- return msix_enabled(&proxy->pci_dev);
-}
-
-static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign)
-{
- VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
- int r, n;
- bool with_irqfd = msix_enabled(&proxy->pci_dev) &&
- kvm_msi_via_irqfd_enabled();
-
- nvqs = MIN(nvqs, VIRTIO_QUEUE_MAX);
-
- /* When deassigning, pass a consistent nvqs value
- * to avoid leaking notifiers.
- */
- assert(assign || nvqs == proxy->nvqs_with_notifiers);
-
- proxy->nvqs_with_notifiers = nvqs;
-
- /* Must unset vector notifier while guest notifier is still assigned */
- if ((proxy->vector_irqfd || k->guest_notifier_mask) && !assign) {
- msix_unset_vector_notifiers(&proxy->pci_dev);
- if (proxy->vector_irqfd) {
- kvm_virtio_pci_vector_release(proxy, nvqs);
- g_free(proxy->vector_irqfd);
- proxy->vector_irqfd = NULL;
- }
- }
-
- for (n = 0; n < nvqs; n++) {
- if (!virtio_queue_get_num(vdev, n)) {
- break;
- }
-
- r = virtio_pci_set_guest_notifier(d, n, assign, with_irqfd);
- if (r < 0) {
- goto assign_error;
- }
- }
-
- /* Must set vector notifier after guest notifier has been assigned */
- if ((with_irqfd || k->guest_notifier_mask) && assign) {
- if (with_irqfd) {
- proxy->vector_irqfd =
- g_malloc0(sizeof(*proxy->vector_irqfd) *
- msix_nr_vectors_allocated(&proxy->pci_dev));
- r = kvm_virtio_pci_vector_use(proxy, nvqs);
- if (r < 0) {
- goto assign_error;
- }
- }
- r = msix_set_vector_notifiers(&proxy->pci_dev,
- virtio_pci_vector_unmask,
- virtio_pci_vector_mask,
- virtio_pci_vector_poll);
- if (r < 0) {
- goto notifiers_error;
- }
- }
-
- return 0;
-
-notifiers_error:
- if (with_irqfd) {
- assert(assign);
- kvm_virtio_pci_vector_release(proxy, nvqs);
- }
-
-assign_error:
- /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */
- assert(assign);
- while (--n >= 0) {
- virtio_pci_set_guest_notifier(d, n, !assign, with_irqfd);
- }
- return r;
-}
-
-static int virtio_pci_set_host_notifier(DeviceState *d, int n, bool assign)
-{
- VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
-
- /* Stop using ioeventfd for virtqueue kick if the device starts using host
- * notifiers. This makes it easy to avoid stepping on each others' toes.
- */
- proxy->ioeventfd_disabled = assign;
- if (assign) {
- virtio_pci_stop_ioeventfd(proxy);
- }
- /* We don't need to start here: it's not needed because backend
- * currently only stops on status change away from ok,
- * reset, vmstop and such. If we do add code to start here,
- * need to check vmstate, device state etc. */
- return virtio_pci_set_host_notifier_internal(proxy, n, assign, false);
-}
-
-static void virtio_pci_vmstate_change(DeviceState *d, bool running)
-{
- VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
-
- if (running) {
- /* Old QEMU versions did not set bus master enable on status write.
- * Detect DRIVER set and enable it.
- */
- if ((proxy->flags & VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION) &&
- (vdev->status & VIRTIO_CONFIG_S_DRIVER) &&
- !(proxy->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
- pci_default_write_config(&proxy->pci_dev, PCI_COMMAND,
- proxy->pci_dev.config[PCI_COMMAND] |
- PCI_COMMAND_MASTER, 1);
- }
- virtio_pci_start_ioeventfd(proxy);
- } else {
- virtio_pci_stop_ioeventfd(proxy);
- }
-}
-
-#ifdef CONFIG_VIRTFS
-static void virtio_9p_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
-{
- V9fsPCIState *dev = VIRTIO_9P_PCI(vpci_dev);
- DeviceState *vdev = DEVICE(&dev->vdev);
-
- qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
- object_property_set_bool(OBJECT(vdev), true, "realized", errp);
-}
-
-static Property virtio_9p_pci_properties[] = {
- DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
- VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
- DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_9p_pci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
- VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
-
- k->realize = virtio_9p_pci_realize;
- pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
- pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_9P;
- pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
- pcidev_k->class_id = 0x2;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
- dc->props = virtio_9p_pci_properties;
-}
-
-static void virtio_9p_pci_instance_init(Object *obj)
-{
- V9fsPCIState *dev = VIRTIO_9P_PCI(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VIRTIO_9P);
-}
-
-static const TypeInfo virtio_9p_pci_info = {
- .name = TYPE_VIRTIO_9P_PCI,
- .parent = TYPE_VIRTIO_PCI,
- .instance_size = sizeof(V9fsPCIState),
- .instance_init = virtio_9p_pci_instance_init,
- .class_init = virtio_9p_pci_class_init,
-};
-#endif /* CONFIG_VIRTFS */
-
-/*
- * virtio-pci: This is the PCIDevice which has a virtio-pci-bus.
- */
-
-static int virtio_pci_query_nvectors(DeviceState *d)
-{
- VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
-
- return proxy->nvectors;
-}
-
-static int virtio_pci_add_mem_cap(VirtIOPCIProxy *proxy,
- struct virtio_pci_cap *cap)
-{
- PCIDevice *dev = &proxy->pci_dev;
- int offset;
-
- offset = pci_add_capability(dev, PCI_CAP_ID_VNDR, 0, cap->cap_len);
- assert(offset > 0);
-
- assert(cap->cap_len >= sizeof *cap);
- memcpy(dev->config + offset + PCI_CAP_FLAGS, &cap->cap_len,
- cap->cap_len - PCI_CAP_FLAGS);
-
- return offset;
-}
-
-static uint64_t virtio_pci_common_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- VirtIOPCIProxy *proxy = opaque;
- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
- uint32_t val = 0;
- int i;
-
- switch (addr) {
- case VIRTIO_PCI_COMMON_DFSELECT:
- val = proxy->dfselect;
- break;
- case VIRTIO_PCI_COMMON_DF:
- if (proxy->dfselect <= 1) {
- val = (vdev->host_features & ~VIRTIO_LEGACY_FEATURES) >>
- (32 * proxy->dfselect);
- }
- break;
- case VIRTIO_PCI_COMMON_GFSELECT:
- val = proxy->gfselect;
- break;
- case VIRTIO_PCI_COMMON_GF:
- if (proxy->gfselect < ARRAY_SIZE(proxy->guest_features)) {
- val = proxy->guest_features[proxy->gfselect];
- }
- break;
- case VIRTIO_PCI_COMMON_MSIX:
- val = vdev->config_vector;
- break;
- case VIRTIO_PCI_COMMON_NUMQ:
- for (i = 0; i < VIRTIO_QUEUE_MAX; ++i) {
- if (virtio_queue_get_num(vdev, i)) {
- val = i + 1;
- }
- }
- break;
- case VIRTIO_PCI_COMMON_STATUS:
- val = vdev->status;
- break;
- case VIRTIO_PCI_COMMON_CFGGENERATION:
- val = vdev->generation;
- break;
- case VIRTIO_PCI_COMMON_Q_SELECT:
- val = vdev->queue_sel;
- break;
- case VIRTIO_PCI_COMMON_Q_SIZE:
- val = virtio_queue_get_num(vdev, vdev->queue_sel);
- break;
- case VIRTIO_PCI_COMMON_Q_MSIX:
- val = virtio_queue_vector(vdev, vdev->queue_sel);
- break;
- case VIRTIO_PCI_COMMON_Q_ENABLE:
- val = proxy->vqs[vdev->queue_sel].enabled;
- break;
- case VIRTIO_PCI_COMMON_Q_NOFF:
- /* Simply map queues in order */
- val = vdev->queue_sel;
- break;
- case VIRTIO_PCI_COMMON_Q_DESCLO:
- val = proxy->vqs[vdev->queue_sel].desc[0];
- break;
- case VIRTIO_PCI_COMMON_Q_DESCHI:
- val = proxy->vqs[vdev->queue_sel].desc[1];
- break;
- case VIRTIO_PCI_COMMON_Q_AVAILLO:
- val = proxy->vqs[vdev->queue_sel].avail[0];
- break;
- case VIRTIO_PCI_COMMON_Q_AVAILHI:
- val = proxy->vqs[vdev->queue_sel].avail[1];
- break;
- case VIRTIO_PCI_COMMON_Q_USEDLO:
- val = proxy->vqs[vdev->queue_sel].used[0];
- break;
- case VIRTIO_PCI_COMMON_Q_USEDHI:
- val = proxy->vqs[vdev->queue_sel].used[1];
- break;
- default:
- val = 0;
- }
-
- return val;
-}
-
-static void virtio_pci_common_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- VirtIOPCIProxy *proxy = opaque;
- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
-
- switch (addr) {
- case VIRTIO_PCI_COMMON_DFSELECT:
- proxy->dfselect = val;
- break;
- case VIRTIO_PCI_COMMON_GFSELECT:
- proxy->gfselect = val;
- break;
- case VIRTIO_PCI_COMMON_GF:
- if (proxy->gfselect < ARRAY_SIZE(proxy->guest_features)) {
- proxy->guest_features[proxy->gfselect] = val;
- virtio_set_features(vdev,
- (((uint64_t)proxy->guest_features[1]) << 32) |
- proxy->guest_features[0]);
- }
- break;
- case VIRTIO_PCI_COMMON_MSIX:
- msix_vector_unuse(&proxy->pci_dev, vdev->config_vector);
- /* Make it possible for guest to discover an error took place. */
- if (msix_vector_use(&proxy->pci_dev, val) < 0) {
- val = VIRTIO_NO_VECTOR;
- }
- vdev->config_vector = val;
- break;
- case VIRTIO_PCI_COMMON_STATUS:
- if (!(val & VIRTIO_CONFIG_S_DRIVER_OK)) {
- virtio_pci_stop_ioeventfd(proxy);
- }
-
- virtio_set_status(vdev, val & 0xFF);
-
- if (val & VIRTIO_CONFIG_S_DRIVER_OK) {
- virtio_pci_start_ioeventfd(proxy);
- }
-
- if (vdev->status == 0) {
- virtio_pci_reset(DEVICE(proxy));
- }
-
- break;
- case VIRTIO_PCI_COMMON_Q_SELECT:
- if (val < VIRTIO_QUEUE_MAX) {
- vdev->queue_sel = val;
- }
- break;
- case VIRTIO_PCI_COMMON_Q_SIZE:
- proxy->vqs[vdev->queue_sel].num = val;
- break;
- case VIRTIO_PCI_COMMON_Q_MSIX:
- msix_vector_unuse(&proxy->pci_dev,
- virtio_queue_vector(vdev, vdev->queue_sel));
- /* Make it possible for guest to discover an error took place. */
- if (msix_vector_use(&proxy->pci_dev, val) < 0) {
- val = VIRTIO_NO_VECTOR;
- }
- virtio_queue_set_vector(vdev, vdev->queue_sel, val);
- break;
- case VIRTIO_PCI_COMMON_Q_ENABLE:
- /* TODO: need a way to put num back on reset. */
- virtio_queue_set_num(vdev, vdev->queue_sel,
- proxy->vqs[vdev->queue_sel].num);
- virtio_queue_set_rings(vdev, vdev->queue_sel,
- ((uint64_t)proxy->vqs[vdev->queue_sel].desc[1]) << 32 |
- proxy->vqs[vdev->queue_sel].desc[0],
- ((uint64_t)proxy->vqs[vdev->queue_sel].avail[1]) << 32 |
- proxy->vqs[vdev->queue_sel].avail[0],
- ((uint64_t)proxy->vqs[vdev->queue_sel].used[1]) << 32 |
- proxy->vqs[vdev->queue_sel].used[0]);
- proxy->vqs[vdev->queue_sel].enabled = 1;
- break;
- case VIRTIO_PCI_COMMON_Q_DESCLO:
- proxy->vqs[vdev->queue_sel].desc[0] = val;
- break;
- case VIRTIO_PCI_COMMON_Q_DESCHI:
- proxy->vqs[vdev->queue_sel].desc[1] = val;
- break;
- case VIRTIO_PCI_COMMON_Q_AVAILLO:
- proxy->vqs[vdev->queue_sel].avail[0] = val;
- break;
- case VIRTIO_PCI_COMMON_Q_AVAILHI:
- proxy->vqs[vdev->queue_sel].avail[1] = val;
- break;
- case VIRTIO_PCI_COMMON_Q_USEDLO:
- proxy->vqs[vdev->queue_sel].used[0] = val;
- break;
- case VIRTIO_PCI_COMMON_Q_USEDHI:
- proxy->vqs[vdev->queue_sel].used[1] = val;
- break;
- default:
- break;
- }
-}
-
-
-static uint64_t virtio_pci_notify_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- return 0;
-}
-
-static void virtio_pci_notify_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- VirtIODevice *vdev = opaque;
- unsigned queue = addr / QEMU_VIRTIO_PCI_QUEUE_MEM_MULT;
-
- if (queue < VIRTIO_QUEUE_MAX) {
- virtio_queue_notify(vdev, queue);
- }
-}
-
-static void virtio_pci_notify_write_pio(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- VirtIODevice *vdev = opaque;
- unsigned queue = val;
-
- if (queue < VIRTIO_QUEUE_MAX) {
- virtio_queue_notify(vdev, queue);
- }
-}
-
-static uint64_t virtio_pci_isr_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- VirtIOPCIProxy *proxy = opaque;
- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
- uint64_t val = vdev->isr;
-
- vdev->isr = 0;
- pci_irq_deassert(&proxy->pci_dev);
-
- return val;
-}
-
-static void virtio_pci_isr_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
-}
-
-static uint64_t virtio_pci_device_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- VirtIODevice *vdev = opaque;
- uint64_t val = 0;
-
- switch (size) {
- case 1:
- val = virtio_config_modern_readb(vdev, addr);
- break;
- case 2:
- val = virtio_config_modern_readw(vdev, addr);
- break;
- case 4:
- val = virtio_config_modern_readl(vdev, addr);
- break;
- }
- return val;
-}
-
-static void virtio_pci_device_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- VirtIODevice *vdev = opaque;
- switch (size) {
- case 1:
- virtio_config_modern_writeb(vdev, addr, val);
- break;
- case 2:
- virtio_config_modern_writew(vdev, addr, val);
- break;
- case 4:
- virtio_config_modern_writel(vdev, addr, val);
- break;
- }
-}
-
-static void virtio_pci_modern_regions_init(VirtIOPCIProxy *proxy)
-{
- static const MemoryRegionOps common_ops = {
- .read = virtio_pci_common_read,
- .write = virtio_pci_common_write,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 4,
- },
- .endianness = DEVICE_LITTLE_ENDIAN,
- };
- static const MemoryRegionOps isr_ops = {
- .read = virtio_pci_isr_read,
- .write = virtio_pci_isr_write,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 4,
- },
- .endianness = DEVICE_LITTLE_ENDIAN,
- };
- static const MemoryRegionOps device_ops = {
- .read = virtio_pci_device_read,
- .write = virtio_pci_device_write,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 4,
- },
- .endianness = DEVICE_LITTLE_ENDIAN,
- };
- static const MemoryRegionOps notify_ops = {
- .read = virtio_pci_notify_read,
- .write = virtio_pci_notify_write,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 4,
- },
- .endianness = DEVICE_LITTLE_ENDIAN,
- };
- static const MemoryRegionOps notify_pio_ops = {
- .read = virtio_pci_notify_read,
- .write = virtio_pci_notify_write_pio,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 4,
- },
- .endianness = DEVICE_LITTLE_ENDIAN,
- };
-
-
- memory_region_init_io(&proxy->common.mr, OBJECT(proxy),
- &common_ops,
- proxy,
- "virtio-pci-common",
- proxy->common.size);
-
- memory_region_init_io(&proxy->isr.mr, OBJECT(proxy),
- &isr_ops,
- proxy,
- "virtio-pci-isr",
- proxy->isr.size);
-
- memory_region_init_io(&proxy->device.mr, OBJECT(proxy),
- &device_ops,
- virtio_bus_get_device(&proxy->bus),
- "virtio-pci-device",
- proxy->device.size);
-
- memory_region_init_io(&proxy->notify.mr, OBJECT(proxy),
- &notify_ops,
- virtio_bus_get_device(&proxy->bus),
- "virtio-pci-notify",
- proxy->notify.size);
-
- memory_region_init_io(&proxy->notify_pio.mr, OBJECT(proxy),
- &notify_pio_ops,
- virtio_bus_get_device(&proxy->bus),
- "virtio-pci-notify-pio",
- proxy->notify.size);
-}
-
-static void virtio_pci_modern_region_map(VirtIOPCIProxy *proxy,
- VirtIOPCIRegion *region,
- struct virtio_pci_cap *cap,
- MemoryRegion *mr,
- uint8_t bar)
-{
- memory_region_add_subregion(mr, region->offset, &region->mr);
-
- cap->cfg_type = region->type;
- cap->bar = bar;
- cap->offset = cpu_to_le32(region->offset);
- cap->length = cpu_to_le32(region->size);
- virtio_pci_add_mem_cap(proxy, cap);
-
-}
-
-static void virtio_pci_modern_mem_region_map(VirtIOPCIProxy *proxy,
- VirtIOPCIRegion *region,
- struct virtio_pci_cap *cap)
-{
- virtio_pci_modern_region_map(proxy, region, cap,
- &proxy->modern_bar, proxy->modern_mem_bar);
-}
-
-static void virtio_pci_modern_io_region_map(VirtIOPCIProxy *proxy,
- VirtIOPCIRegion *region,
- struct virtio_pci_cap *cap)
-{
- virtio_pci_modern_region_map(proxy, region, cap,
- &proxy->io_bar, proxy->modern_io_bar);
-}
-
-static void virtio_pci_modern_mem_region_unmap(VirtIOPCIProxy *proxy,
- VirtIOPCIRegion *region)
-{
- memory_region_del_subregion(&proxy->modern_bar,
- &region->mr);
-}
-
-static void virtio_pci_modern_io_region_unmap(VirtIOPCIProxy *proxy,
- VirtIOPCIRegion *region)
-{
- memory_region_del_subregion(&proxy->io_bar,
- &region->mr);
-}
-
-/* This is called by virtio-bus just after the device is plugged. */
-static void virtio_pci_device_plugged(DeviceState *d, Error **errp)
-{
- VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
- VirtioBusState *bus = &proxy->bus;
- bool legacy = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_LEGACY);
- bool modern = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_MODERN);
- bool modern_pio = proxy->flags & VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY;
- uint8_t *config;
- uint32_t size;
- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
-
- config = proxy->pci_dev.config;
- if (proxy->class_code) {
- pci_config_set_class(config, proxy->class_code);
- }
-
- if (legacy) {
- /* legacy and transitional */
- pci_set_word(config + PCI_SUBSYSTEM_VENDOR_ID,
- pci_get_word(config + PCI_VENDOR_ID));
- pci_set_word(config + PCI_SUBSYSTEM_ID, virtio_bus_get_vdev_id(bus));
- } else {
- /* pure virtio-1.0 */
- pci_set_word(config + PCI_VENDOR_ID,
- PCI_VENDOR_ID_REDHAT_QUMRANET);
- pci_set_word(config + PCI_DEVICE_ID,
- 0x1040 + virtio_bus_get_vdev_id(bus));
- pci_config_set_revision(config, 1);
- }
- config[PCI_INTERRUPT_PIN] = 1;
-
-
- if (modern) {
- struct virtio_pci_cap cap = {
- .cap_len = sizeof cap,
- };
- struct virtio_pci_notify_cap notify = {
- .cap.cap_len = sizeof notify,
- .notify_off_multiplier =
- cpu_to_le32(QEMU_VIRTIO_PCI_QUEUE_MEM_MULT),
- };
- struct virtio_pci_cfg_cap cfg = {
- .cap.cap_len = sizeof cfg,
- .cap.cfg_type = VIRTIO_PCI_CAP_PCI_CFG,
- };
- struct virtio_pci_notify_cap notify_pio = {
- .cap.cap_len = sizeof notify,
- .notify_off_multiplier = cpu_to_le32(0x0),
- };
-
- struct virtio_pci_cfg_cap *cfg_mask;
-
- virtio_add_feature(&vdev->host_features, VIRTIO_F_VERSION_1);
- virtio_pci_modern_regions_init(proxy);
-
- virtio_pci_modern_mem_region_map(proxy, &proxy->common, &cap);
- virtio_pci_modern_mem_region_map(proxy, &proxy->isr, &cap);
- virtio_pci_modern_mem_region_map(proxy, &proxy->device, &cap);
- virtio_pci_modern_mem_region_map(proxy, &proxy->notify, &notify.cap);
-
- if (modern_pio) {
- memory_region_init(&proxy->io_bar, OBJECT(proxy),
- "virtio-pci-io", 0x4);
-
- pci_register_bar(&proxy->pci_dev, proxy->modern_io_bar,
- PCI_BASE_ADDRESS_SPACE_IO, &proxy->io_bar);
-
- virtio_pci_modern_io_region_map(proxy, &proxy->notify_pio,
- &notify_pio.cap);
- }
-
- pci_register_bar(&proxy->pci_dev, proxy->modern_mem_bar,
- PCI_BASE_ADDRESS_SPACE_MEMORY |
- PCI_BASE_ADDRESS_MEM_PREFETCH |
- PCI_BASE_ADDRESS_MEM_TYPE_64,
- &proxy->modern_bar);
-
- proxy->config_cap = virtio_pci_add_mem_cap(proxy, &cfg.cap);
- cfg_mask = (void *)(proxy->pci_dev.wmask + proxy->config_cap);
- pci_set_byte(&cfg_mask->cap.bar, ~0x0);
- pci_set_long((uint8_t *)&cfg_mask->cap.offset, ~0x0);
- pci_set_long((uint8_t *)&cfg_mask->cap.length, ~0x0);
- pci_set_long(cfg_mask->pci_cfg_data, ~0x0);
- }
-
- if (proxy->nvectors) {
- int err = msix_init_exclusive_bar(&proxy->pci_dev, proxy->nvectors,
- proxy->msix_bar);
- if (err) {
- /* Notice when a system that supports MSIx can't initialize it. */
- if (err != -ENOTSUP) {
- error_report("unable to init msix vectors to %" PRIu32,
- proxy->nvectors);
- }
- proxy->nvectors = 0;
- }
- }
-
- proxy->pci_dev.config_write = virtio_write_config;
- proxy->pci_dev.config_read = virtio_read_config;
-
- if (legacy) {
- size = VIRTIO_PCI_REGION_SIZE(&proxy->pci_dev)
- + virtio_bus_get_vdev_config_len(bus);
- size = pow2ceil(size);
-
- memory_region_init_io(&proxy->bar, OBJECT(proxy),
- &virtio_pci_config_ops,
- proxy, "virtio-pci", size);
-
- pci_register_bar(&proxy->pci_dev, proxy->legacy_io_bar,
- PCI_BASE_ADDRESS_SPACE_IO, &proxy->bar);
- }
-
- if (!kvm_has_many_ioeventfds()) {
- proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD;
- }
-
- virtio_add_feature(&vdev->host_features, VIRTIO_F_BAD_FEATURE);
-}
-
-static void virtio_pci_device_unplugged(DeviceState *d)
-{
- VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
- bool modern = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_MODERN);
- bool modern_pio = proxy->flags & VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY;
-
- virtio_pci_stop_ioeventfd(proxy);
-
- if (modern) {
- virtio_pci_modern_mem_region_unmap(proxy, &proxy->common);
- virtio_pci_modern_mem_region_unmap(proxy, &proxy->isr);
- virtio_pci_modern_mem_region_unmap(proxy, &proxy->device);
- virtio_pci_modern_mem_region_unmap(proxy, &proxy->notify);
- if (modern_pio) {
- virtio_pci_modern_io_region_unmap(proxy, &proxy->notify_pio);
- }
- }
-}
-
-static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp)
-{
- VirtIOPCIProxy *proxy = VIRTIO_PCI(pci_dev);
- VirtioPCIClass *k = VIRTIO_PCI_GET_CLASS(pci_dev);
-
- /*
- * virtio pci bar layout used by default.
- * subclasses can re-arrange things if needed.
- *
- * region 0 -- virtio legacy io bar
- * region 1 -- msi-x bar
- * region 4+5 -- virtio modern memory (64bit) bar
- *
- */
- proxy->legacy_io_bar = 0;
- proxy->msix_bar = 1;
- proxy->modern_io_bar = 2;
- proxy->modern_mem_bar = 4;
-
- proxy->common.offset = 0x0;
- proxy->common.size = 0x1000;
- proxy->common.type = VIRTIO_PCI_CAP_COMMON_CFG;
-
- proxy->isr.offset = 0x1000;
- proxy->isr.size = 0x1000;
- proxy->isr.type = VIRTIO_PCI_CAP_ISR_CFG;
-
- proxy->device.offset = 0x2000;
- proxy->device.size = 0x1000;
- proxy->device.type = VIRTIO_PCI_CAP_DEVICE_CFG;
-
- proxy->notify.offset = 0x3000;
- proxy->notify.size =
- QEMU_VIRTIO_PCI_QUEUE_MEM_MULT * VIRTIO_QUEUE_MAX;
- proxy->notify.type = VIRTIO_PCI_CAP_NOTIFY_CFG;
-
- proxy->notify_pio.offset = 0x0;
- proxy->notify_pio.size = 0x4;
- proxy->notify_pio.type = VIRTIO_PCI_CAP_NOTIFY_CFG;
-
- /* subclasses can enforce modern, so do this unconditionally */
- memory_region_init(&proxy->modern_bar, OBJECT(proxy), "virtio-pci",
- 2 * QEMU_VIRTIO_PCI_QUEUE_MEM_MULT *
- VIRTIO_QUEUE_MAX);
-
- memory_region_init_alias(&proxy->modern_cfg,
- OBJECT(proxy),
- "virtio-pci-cfg",
- &proxy->modern_bar,
- 0,
- memory_region_size(&proxy->modern_bar));
-
- address_space_init(&proxy->modern_as, &proxy->modern_cfg, "virtio-pci-cfg-as");
-
- if (pci_is_express(pci_dev) && pci_bus_is_express(pci_dev->bus) &&
- !pci_bus_is_root(pci_dev->bus)) {
- int pos;
-
- pos = pcie_endpoint_cap_init(pci_dev, 0);
- assert(pos > 0);
-
- pos = pci_add_capability(pci_dev, PCI_CAP_ID_PM, 0, PCI_PM_SIZEOF);
- assert(pos > 0);
-
- /*
- * Indicates that this function complies with revision 1.2 of the
- * PCI Power Management Interface Specification.
- */
- pci_set_word(pci_dev->config + pos + PCI_PM_PMC, 0x3);
- } else {
- /*
- * make future invocations of pci_is_express() return false
- * and pci_config_size() return PCI_CONFIG_SPACE_SIZE.
- */
- pci_dev->cap_present &= ~QEMU_PCI_CAP_EXPRESS;
- }
-
- virtio_pci_bus_new(&proxy->bus, sizeof(proxy->bus), proxy);
- if (k->realize) {
- k->realize(proxy, errp);
- }
-}
-
-static void virtio_pci_exit(PCIDevice *pci_dev)
-{
- VirtIOPCIProxy *proxy = VIRTIO_PCI(pci_dev);
-
- msix_uninit_exclusive_bar(pci_dev);
- address_space_destroy(&proxy->modern_as);
-}
-
-static void virtio_pci_reset(DeviceState *qdev)
-{
- VirtIOPCIProxy *proxy = VIRTIO_PCI(qdev);
- VirtioBusState *bus = VIRTIO_BUS(&proxy->bus);
- int i;
-
- virtio_pci_stop_ioeventfd(proxy);
- virtio_bus_reset(bus);
- msix_unuse_all_vectors(&proxy->pci_dev);
-
- for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
- proxy->vqs[i].enabled = 0;
- }
-}
-
-static Property virtio_pci_properties[] = {
- DEFINE_PROP_BIT("virtio-pci-bus-master-bug-migration", VirtIOPCIProxy, flags,
- VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION_BIT, false),
- DEFINE_PROP_BIT("disable-legacy", VirtIOPCIProxy, flags,
- VIRTIO_PCI_FLAG_DISABLE_LEGACY_BIT, false),
- DEFINE_PROP_BIT("disable-modern", VirtIOPCIProxy, flags,
- VIRTIO_PCI_FLAG_DISABLE_MODERN_BIT, true),
- DEFINE_PROP_BIT("migrate-extra", VirtIOPCIProxy, flags,
- VIRTIO_PCI_FLAG_MIGRATE_EXTRA_BIT, true),
- DEFINE_PROP_BIT("modern-pio-notify", VirtIOPCIProxy, flags,
- VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY_BIT, false),
- DEFINE_PROP_BIT("x-disable-pcie", VirtIOPCIProxy, flags,
- VIRTIO_PCI_FLAG_DISABLE_PCIE_BIT, false),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_pci_dc_realize(DeviceState *qdev, Error **errp)
-{
- VirtioPCIClass *vpciklass = VIRTIO_PCI_GET_CLASS(qdev);
- VirtIOPCIProxy *proxy = VIRTIO_PCI(qdev);
- PCIDevice *pci_dev = &proxy->pci_dev;
-
- if (!(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_PCIE) &&
- !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_MODERN)) {
- pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS;
- }
-
- vpciklass->parent_dc_realize(qdev, errp);
-}
-
-static void virtio_pci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- VirtioPCIClass *vpciklass = VIRTIO_PCI_CLASS(klass);
-
- dc->props = virtio_pci_properties;
- k->realize = virtio_pci_realize;
- k->exit = virtio_pci_exit;
- k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
- k->revision = VIRTIO_PCI_ABI_VERSION;
- k->class_id = PCI_CLASS_OTHERS;
- vpciklass->parent_dc_realize = dc->realize;
- dc->realize = virtio_pci_dc_realize;
- dc->reset = virtio_pci_reset;
-}
-
-static const TypeInfo virtio_pci_info = {
- .name = TYPE_VIRTIO_PCI,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(VirtIOPCIProxy),
- .class_init = virtio_pci_class_init,
- .class_size = sizeof(VirtioPCIClass),
- .abstract = true,
-};
-
-/* virtio-blk-pci */
-
-static Property virtio_blk_pci_properties[] = {
- DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
- DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
- VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
- DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
-{
- VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(vpci_dev);
- DeviceState *vdev = DEVICE(&dev->vdev);
-
- qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
- object_property_set_bool(OBJECT(vdev), true, "realized", errp);
-}
-
-static void virtio_blk_pci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
- PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
-
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
- dc->props = virtio_blk_pci_properties;
- k->realize = virtio_blk_pci_realize;
- pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
- pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK;
- pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
- pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
-}
-
-static void virtio_blk_pci_instance_init(Object *obj)
-{
- VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VIRTIO_BLK);
- object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev),"iothread",
- &error_abort);
- object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
- "bootindex", &error_abort);
-}
-
-static const TypeInfo virtio_blk_pci_info = {
- .name = TYPE_VIRTIO_BLK_PCI,
- .parent = TYPE_VIRTIO_PCI,
- .instance_size = sizeof(VirtIOBlkPCI),
- .instance_init = virtio_blk_pci_instance_init,
- .class_init = virtio_blk_pci_class_init,
-};
-
-/* virtio-scsi-pci */
-
-static Property virtio_scsi_pci_properties[] = {
- DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
- VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
- DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
- DEV_NVECTORS_UNSPECIFIED),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
-{
- VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(vpci_dev);
- DeviceState *vdev = DEVICE(&dev->vdev);
- VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
- DeviceState *proxy = DEVICE(vpci_dev);
- char *bus_name;
-
- if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
- vpci_dev->nvectors = vs->conf.num_queues + 3;
- }
-
- /*
- * For command line compatibility, this sets the virtio-scsi-device bus
- * name as before.
- */
- if (proxy->id) {
- bus_name = g_strdup_printf("%s.0", proxy->id);
- virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name);
- g_free(bus_name);
- }
-
- qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
- object_property_set_bool(OBJECT(vdev), true, "realized", errp);
-}
-
-static void virtio_scsi_pci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
- PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
-
- k->realize = virtio_scsi_pci_realize;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
- dc->props = virtio_scsi_pci_properties;
- pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
- pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI;
- pcidev_k->revision = 0x00;
- pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
-}
-
-static void virtio_scsi_pci_instance_init(Object *obj)
-{
- VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VIRTIO_SCSI);
- object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev), "iothread",
- &error_abort);
-}
-
-static const TypeInfo virtio_scsi_pci_info = {
- .name = TYPE_VIRTIO_SCSI_PCI,
- .parent = TYPE_VIRTIO_PCI,
- .instance_size = sizeof(VirtIOSCSIPCI),
- .instance_init = virtio_scsi_pci_instance_init,
- .class_init = virtio_scsi_pci_class_init,
-};
-
-/* vhost-scsi-pci */
-
-#ifdef CONFIG_VHOST_SCSI
-static Property vhost_scsi_pci_properties[] = {
- DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
- DEV_NVECTORS_UNSPECIFIED),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void vhost_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
-{
- VHostSCSIPCI *dev = VHOST_SCSI_PCI(vpci_dev);
- DeviceState *vdev = DEVICE(&dev->vdev);
- VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
-
- if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
- vpci_dev->nvectors = vs->conf.num_queues + 3;
- }
-
- qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
- object_property_set_bool(OBJECT(vdev), true, "realized", errp);
-}
-
-static void vhost_scsi_pci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
- PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
- k->realize = vhost_scsi_pci_realize;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
- dc->props = vhost_scsi_pci_properties;
- pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
- pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI;
- pcidev_k->revision = 0x00;
- pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
-}
-
-static void vhost_scsi_pci_instance_init(Object *obj)
-{
- VHostSCSIPCI *dev = VHOST_SCSI_PCI(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VHOST_SCSI);
- object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
- "bootindex", &error_abort);
-}
-
-static const TypeInfo vhost_scsi_pci_info = {
- .name = TYPE_VHOST_SCSI_PCI,
- .parent = TYPE_VIRTIO_PCI,
- .instance_size = sizeof(VHostSCSIPCI),
- .instance_init = vhost_scsi_pci_instance_init,
- .class_init = vhost_scsi_pci_class_init,
-};
-#endif
-
-/* virtio-balloon-pci */
-
-static Property virtio_balloon_pci_properties[] = {
- DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_balloon_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
-{
- VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(vpci_dev);
- DeviceState *vdev = DEVICE(&dev->vdev);
-
- if (vpci_dev->class_code != PCI_CLASS_OTHERS &&
- vpci_dev->class_code != PCI_CLASS_MEMORY_RAM) { /* qemu < 1.1 */
- vpci_dev->class_code = PCI_CLASS_OTHERS;
- }
-
- qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
- object_property_set_bool(OBJECT(vdev), true, "realized", errp);
-}
-
-static void virtio_balloon_pci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
- PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
- k->realize = virtio_balloon_pci_realize;
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- dc->props = virtio_balloon_pci_properties;
- pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
- pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BALLOON;
- pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
- pcidev_k->class_id = PCI_CLASS_OTHERS;
-}
-
-static void virtio_balloon_pci_instance_init(Object *obj)
-{
- VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VIRTIO_BALLOON);
- object_property_add_alias(obj, "guest-stats", OBJECT(&dev->vdev),
- "guest-stats", &error_abort);
- object_property_add_alias(obj, "guest-stats-polling-interval",
- OBJECT(&dev->vdev),
- "guest-stats-polling-interval", &error_abort);
-}
-
-static const TypeInfo virtio_balloon_pci_info = {
- .name = TYPE_VIRTIO_BALLOON_PCI,
- .parent = TYPE_VIRTIO_PCI,
- .instance_size = sizeof(VirtIOBalloonPCI),
- .instance_init = virtio_balloon_pci_instance_init,
- .class_init = virtio_balloon_pci_class_init,
-};
-
-/* virtio-serial-pci */
-
-static void virtio_serial_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
-{
- VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(vpci_dev);
- DeviceState *vdev = DEVICE(&dev->vdev);
- DeviceState *proxy = DEVICE(vpci_dev);
- char *bus_name;
-
- if (vpci_dev->class_code != PCI_CLASS_COMMUNICATION_OTHER &&
- vpci_dev->class_code != PCI_CLASS_DISPLAY_OTHER && /* qemu 0.10 */
- vpci_dev->class_code != PCI_CLASS_OTHERS) { /* qemu-kvm */
- vpci_dev->class_code = PCI_CLASS_COMMUNICATION_OTHER;
- }
-
- /* backwards-compatibility with machines that were created with
- DEV_NVECTORS_UNSPECIFIED */
- if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
- vpci_dev->nvectors = dev->vdev.serial.max_virtserial_ports + 1;
- }
-
- /*
- * For command line compatibility, this sets the virtio-serial-device bus
- * name as before.
- */
- if (proxy->id) {
- bus_name = g_strdup_printf("%s.0", proxy->id);
- virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name);
- g_free(bus_name);
- }
-
- qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
- object_property_set_bool(OBJECT(vdev), true, "realized", errp);
-}
-
-static Property virtio_serial_pci_properties[] = {
- DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
- VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
- DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
- DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_serial_pci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
- PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
- k->realize = virtio_serial_pci_realize;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
- dc->props = virtio_serial_pci_properties;
- pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
- pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_CONSOLE;
- pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
- pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
-}
-
-static void virtio_serial_pci_instance_init(Object *obj)
-{
- VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VIRTIO_SERIAL);
-}
-
-static const TypeInfo virtio_serial_pci_info = {
- .name = TYPE_VIRTIO_SERIAL_PCI,
- .parent = TYPE_VIRTIO_PCI,
- .instance_size = sizeof(VirtIOSerialPCI),
- .instance_init = virtio_serial_pci_instance_init,
- .class_init = virtio_serial_pci_class_init,
-};
-
-/* virtio-net-pci */
-
-static Property virtio_net_properties[] = {
- DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
- VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false),
- DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_net_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
-{
- DeviceState *qdev = DEVICE(vpci_dev);
- VirtIONetPCI *dev = VIRTIO_NET_PCI(vpci_dev);
- DeviceState *vdev = DEVICE(&dev->vdev);
-
- virtio_net_set_netclient_name(&dev->vdev, qdev->id,
- object_get_typename(OBJECT(qdev)));
- qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
- object_property_set_bool(OBJECT(vdev), true, "realized", errp);
-}
-
-static void virtio_net_pci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- VirtioPCIClass *vpciklass = VIRTIO_PCI_CLASS(klass);
-
- k->romfile = "efi-virtio.rom";
- k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
- k->device_id = PCI_DEVICE_ID_VIRTIO_NET;
- k->revision = VIRTIO_PCI_ABI_VERSION;
- k->class_id = PCI_CLASS_NETWORK_ETHERNET;
- set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
- dc->props = virtio_net_properties;
- vpciklass->realize = virtio_net_pci_realize;
-}
-
-static void virtio_net_pci_instance_init(Object *obj)
-{
- VirtIONetPCI *dev = VIRTIO_NET_PCI(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VIRTIO_NET);
- object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
- "bootindex", &error_abort);
-}
-
-static const TypeInfo virtio_net_pci_info = {
- .name = TYPE_VIRTIO_NET_PCI,
- .parent = TYPE_VIRTIO_PCI,
- .instance_size = sizeof(VirtIONetPCI),
- .instance_init = virtio_net_pci_instance_init,
- .class_init = virtio_net_pci_class_init,
-};
-
-/* virtio-rng-pci */
-
-static void virtio_rng_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
-{
- VirtIORngPCI *vrng = VIRTIO_RNG_PCI(vpci_dev);
- DeviceState *vdev = DEVICE(&vrng->vdev);
- Error *err = NULL;
-
- qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
- object_property_set_bool(OBJECT(vdev), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- object_property_set_link(OBJECT(vrng),
- OBJECT(vrng->vdev.conf.rng), "rng",
- NULL);
-}
-
-static void virtio_rng_pci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
- PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
-
- k->realize = virtio_rng_pci_realize;
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
-
- pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
- pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_RNG;
- pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
- pcidev_k->class_id = PCI_CLASS_OTHERS;
-}
-
-static void virtio_rng_initfn(Object *obj)
-{
- VirtIORngPCI *dev = VIRTIO_RNG_PCI(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VIRTIO_RNG);
- object_property_add_alias(obj, "rng", OBJECT(&dev->vdev), "rng",
- &error_abort);
-}
-
-static const TypeInfo virtio_rng_pci_info = {
- .name = TYPE_VIRTIO_RNG_PCI,
- .parent = TYPE_VIRTIO_PCI,
- .instance_size = sizeof(VirtIORngPCI),
- .instance_init = virtio_rng_initfn,
- .class_init = virtio_rng_pci_class_init,
-};
-
-/* virtio-input-pci */
-
-static Property virtio_input_pci_properties[] = {
- DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_input_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
-{
- VirtIOInputPCI *vinput = VIRTIO_INPUT_PCI(vpci_dev);
- DeviceState *vdev = DEVICE(&vinput->vdev);
-
- qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
- /* force virtio-1.0 */
- vpci_dev->flags &= ~VIRTIO_PCI_FLAG_DISABLE_MODERN;
- vpci_dev->flags |= VIRTIO_PCI_FLAG_DISABLE_LEGACY;
- object_property_set_bool(OBJECT(vdev), true, "realized", errp);
-}
-
-static void virtio_input_pci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
- PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
-
- dc->props = virtio_input_pci_properties;
- k->realize = virtio_input_pci_realize;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
-
- pcidev_k->class_id = PCI_CLASS_INPUT_OTHER;
-}
-
-static void virtio_input_hid_kbd_pci_class_init(ObjectClass *klass, void *data)
-{
- PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
-
- pcidev_k->class_id = PCI_CLASS_INPUT_KEYBOARD;
-}
-
-static void virtio_input_hid_mouse_pci_class_init(ObjectClass *klass,
- void *data)
-{
- PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
-
- pcidev_k->class_id = PCI_CLASS_INPUT_MOUSE;
-}
-
-static void virtio_keyboard_initfn(Object *obj)
-{
- VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VIRTIO_KEYBOARD);
-}
-
-static void virtio_mouse_initfn(Object *obj)
-{
- VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VIRTIO_MOUSE);
-}
-
-static void virtio_tablet_initfn(Object *obj)
-{
- VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VIRTIO_TABLET);
-}
-
-static const TypeInfo virtio_input_pci_info = {
- .name = TYPE_VIRTIO_INPUT_PCI,
- .parent = TYPE_VIRTIO_PCI,
- .instance_size = sizeof(VirtIOInputPCI),
- .class_init = virtio_input_pci_class_init,
- .abstract = true,
-};
-
-static const TypeInfo virtio_input_hid_pci_info = {
- .name = TYPE_VIRTIO_INPUT_HID_PCI,
- .parent = TYPE_VIRTIO_INPUT_PCI,
- .instance_size = sizeof(VirtIOInputHIDPCI),
- .abstract = true,
-};
-
-static const TypeInfo virtio_keyboard_pci_info = {
- .name = TYPE_VIRTIO_KEYBOARD_PCI,
- .parent = TYPE_VIRTIO_INPUT_HID_PCI,
- .class_init = virtio_input_hid_kbd_pci_class_init,
- .instance_size = sizeof(VirtIOInputHIDPCI),
- .instance_init = virtio_keyboard_initfn,
-};
-
-static const TypeInfo virtio_mouse_pci_info = {
- .name = TYPE_VIRTIO_MOUSE_PCI,
- .parent = TYPE_VIRTIO_INPUT_HID_PCI,
- .class_init = virtio_input_hid_mouse_pci_class_init,
- .instance_size = sizeof(VirtIOInputHIDPCI),
- .instance_init = virtio_mouse_initfn,
-};
-
-static const TypeInfo virtio_tablet_pci_info = {
- .name = TYPE_VIRTIO_TABLET_PCI,
- .parent = TYPE_VIRTIO_INPUT_HID_PCI,
- .instance_size = sizeof(VirtIOInputHIDPCI),
- .instance_init = virtio_tablet_initfn,
-};
-
-#ifdef CONFIG_LINUX
-static void virtio_host_initfn(Object *obj)
-{
- VirtIOInputHostPCI *dev = VIRTIO_INPUT_HOST_PCI(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VIRTIO_INPUT_HOST);
-}
-
-static const TypeInfo virtio_host_pci_info = {
- .name = TYPE_VIRTIO_INPUT_HOST_PCI,
- .parent = TYPE_VIRTIO_INPUT_PCI,
- .instance_size = sizeof(VirtIOInputHostPCI),
- .instance_init = virtio_host_initfn,
-};
-#endif
-
-/* virtio-pci-bus */
-
-static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size,
- VirtIOPCIProxy *dev)
-{
- DeviceState *qdev = DEVICE(dev);
- char virtio_bus_name[] = "virtio-bus";
-
- qbus_create_inplace(bus, bus_size, TYPE_VIRTIO_PCI_BUS, qdev,
- virtio_bus_name);
-}
-
-static void virtio_pci_bus_class_init(ObjectClass *klass, void *data)
-{
- BusClass *bus_class = BUS_CLASS(klass);
- VirtioBusClass *k = VIRTIO_BUS_CLASS(klass);
- bus_class->max_dev = 1;
- k->notify = virtio_pci_notify;
- k->save_config = virtio_pci_save_config;
- k->load_config = virtio_pci_load_config;
- k->save_queue = virtio_pci_save_queue;
- k->load_queue = virtio_pci_load_queue;
- k->save_extra_state = virtio_pci_save_extra_state;
- k->load_extra_state = virtio_pci_load_extra_state;
- k->has_extra_state = virtio_pci_has_extra_state;
- k->query_guest_notifiers = virtio_pci_query_guest_notifiers;
- k->set_host_notifier = virtio_pci_set_host_notifier;
- k->set_guest_notifiers = virtio_pci_set_guest_notifiers;
- k->vmstate_change = virtio_pci_vmstate_change;
- k->device_plugged = virtio_pci_device_plugged;
- k->device_unplugged = virtio_pci_device_unplugged;
- k->query_nvectors = virtio_pci_query_nvectors;
-}
-
-static const TypeInfo virtio_pci_bus_info = {
- .name = TYPE_VIRTIO_PCI_BUS,
- .parent = TYPE_VIRTIO_BUS,
- .instance_size = sizeof(VirtioPCIBusState),
- .class_init = virtio_pci_bus_class_init,
-};
-
-static void virtio_pci_register_types(void)
-{
- type_register_static(&virtio_rng_pci_info);
- type_register_static(&virtio_input_pci_info);
- type_register_static(&virtio_input_hid_pci_info);
- type_register_static(&virtio_keyboard_pci_info);
- type_register_static(&virtio_mouse_pci_info);
- type_register_static(&virtio_tablet_pci_info);
-#ifdef CONFIG_LINUX
- type_register_static(&virtio_host_pci_info);
-#endif
- type_register_static(&virtio_pci_bus_info);
- type_register_static(&virtio_pci_info);
-#ifdef CONFIG_VIRTFS
- type_register_static(&virtio_9p_pci_info);
-#endif
- type_register_static(&virtio_blk_pci_info);
- type_register_static(&virtio_scsi_pci_info);
- type_register_static(&virtio_balloon_pci_info);
- type_register_static(&virtio_serial_pci_info);
- type_register_static(&virtio_net_pci_info);
-#ifdef CONFIG_VHOST_SCSI
- type_register_static(&vhost_scsi_pci_info);
-#endif
-}
-
-type_init(virtio_pci_register_types)
diff --git a/qemu/hw/virtio/virtio-pci.h b/qemu/hw/virtio/virtio-pci.h
deleted file mode 100644
index e4548c2f9..000000000
--- a/qemu/hw/virtio/virtio-pci.h
+++ /dev/null
@@ -1,317 +0,0 @@
-/*
- * Virtio PCI Bindings
- *
- * Copyright IBM, Corp. 2007
- * Copyright (c) 2009 CodeSourcery
- *
- * Authors:
- * Anthony Liguori <aliguori@us.ibm.com>
- * Paul Brook <paul@codesourcery.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- */
-
-#ifndef QEMU_VIRTIO_PCI_H
-#define QEMU_VIRTIO_PCI_H
-
-#include "hw/pci/msi.h"
-#include "hw/virtio/virtio-blk.h"
-#include "hw/virtio/virtio-net.h"
-#include "hw/virtio/virtio-rng.h"
-#include "hw/virtio/virtio-serial.h"
-#include "hw/virtio/virtio-scsi.h"
-#include "hw/virtio/virtio-balloon.h"
-#include "hw/virtio/virtio-bus.h"
-#include "hw/virtio/virtio-input.h"
-#include "hw/virtio/virtio-gpu.h"
-#ifdef CONFIG_VIRTFS
-#include "hw/9pfs/virtio-9p.h"
-#endif
-#ifdef CONFIG_VHOST_SCSI
-#include "hw/virtio/vhost-scsi.h"
-#endif
-
-typedef struct VirtIOPCIProxy VirtIOPCIProxy;
-typedef struct VirtIOBlkPCI VirtIOBlkPCI;
-typedef struct VirtIOSCSIPCI VirtIOSCSIPCI;
-typedef struct VirtIOBalloonPCI VirtIOBalloonPCI;
-typedef struct VirtIOSerialPCI VirtIOSerialPCI;
-typedef struct VirtIONetPCI VirtIONetPCI;
-typedef struct VHostSCSIPCI VHostSCSIPCI;
-typedef struct VirtIORngPCI VirtIORngPCI;
-typedef struct VirtIOInputPCI VirtIOInputPCI;
-typedef struct VirtIOInputHIDPCI VirtIOInputHIDPCI;
-typedef struct VirtIOInputHostPCI VirtIOInputHostPCI;
-typedef struct VirtIOGPUPCI VirtIOGPUPCI;
-
-/* virtio-pci-bus */
-
-typedef struct VirtioBusState VirtioPCIBusState;
-typedef struct VirtioBusClass VirtioPCIBusClass;
-
-#define TYPE_VIRTIO_PCI_BUS "virtio-pci-bus"
-#define VIRTIO_PCI_BUS(obj) \
- OBJECT_CHECK(VirtioPCIBusState, (obj), TYPE_VIRTIO_PCI_BUS)
-#define VIRTIO_PCI_BUS_GET_CLASS(obj) \
- OBJECT_GET_CLASS(VirtioPCIBusClass, obj, TYPE_VIRTIO_PCI_BUS)
-#define VIRTIO_PCI_BUS_CLASS(klass) \
- OBJECT_CLASS_CHECK(VirtioPCIBusClass, klass, TYPE_VIRTIO_PCI_BUS)
-
-enum {
- VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION_BIT,
- VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT,
- VIRTIO_PCI_FLAG_DISABLE_LEGACY_BIT,
- VIRTIO_PCI_FLAG_DISABLE_MODERN_BIT,
- VIRTIO_PCI_FLAG_MIGRATE_EXTRA_BIT,
- VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY_BIT,
- VIRTIO_PCI_FLAG_DISABLE_PCIE_BIT,
-};
-
-/* Need to activate work-arounds for buggy guests at vmstate load. */
-#define VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION \
- (1 << VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION_BIT)
-
-/* Performance improves when virtqueue kick processing is decoupled from the
- * vcpu thread using ioeventfd for some devices. */
-#define VIRTIO_PCI_FLAG_USE_IOEVENTFD (1 << VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT)
-
-/* virtio version flags */
-#define VIRTIO_PCI_FLAG_DISABLE_LEGACY (1 << VIRTIO_PCI_FLAG_DISABLE_LEGACY_BIT)
-#define VIRTIO_PCI_FLAG_DISABLE_MODERN (1 << VIRTIO_PCI_FLAG_DISABLE_MODERN_BIT)
-#define VIRTIO_PCI_FLAG_DISABLE_PCIE (1 << VIRTIO_PCI_FLAG_DISABLE_PCIE_BIT)
-
-/* migrate extra state */
-#define VIRTIO_PCI_FLAG_MIGRATE_EXTRA (1 << VIRTIO_PCI_FLAG_MIGRATE_EXTRA_BIT)
-
-/* have pio notification for modern device ? */
-#define VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY \
- (1 << VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY_BIT)
-
-typedef struct {
- MSIMessage msg;
- int virq;
- unsigned int users;
-} VirtIOIRQFD;
-
-/*
- * virtio-pci: This is the PCIDevice which has a virtio-pci-bus.
- */
-#define TYPE_VIRTIO_PCI "virtio-pci"
-#define VIRTIO_PCI_GET_CLASS(obj) \
- OBJECT_GET_CLASS(VirtioPCIClass, obj, TYPE_VIRTIO_PCI)
-#define VIRTIO_PCI_CLASS(klass) \
- OBJECT_CLASS_CHECK(VirtioPCIClass, klass, TYPE_VIRTIO_PCI)
-#define VIRTIO_PCI(obj) \
- OBJECT_CHECK(VirtIOPCIProxy, (obj), TYPE_VIRTIO_PCI)
-
-typedef struct VirtioPCIClass {
- PCIDeviceClass parent_class;
- DeviceRealize parent_dc_realize;
- void (*realize)(VirtIOPCIProxy *vpci_dev, Error **errp);
-} VirtioPCIClass;
-
-typedef struct VirtIOPCIRegion {
- MemoryRegion mr;
- uint32_t offset;
- uint32_t size;
- uint32_t type;
-} VirtIOPCIRegion;
-
-typedef struct VirtIOPCIQueue {
- uint16_t num;
- bool enabled;
- uint32_t desc[2];
- uint32_t avail[2];
- uint32_t used[2];
-} VirtIOPCIQueue;
-
-struct VirtIOPCIProxy {
- PCIDevice pci_dev;
- MemoryRegion bar;
- VirtIOPCIRegion common;
- VirtIOPCIRegion isr;
- VirtIOPCIRegion device;
- VirtIOPCIRegion notify;
- VirtIOPCIRegion notify_pio;
- MemoryRegion modern_bar;
- MemoryRegion io_bar;
- MemoryRegion modern_cfg;
- AddressSpace modern_as;
- uint32_t legacy_io_bar;
- uint32_t msix_bar;
- uint32_t modern_io_bar;
- uint32_t modern_mem_bar;
- int config_cap;
- uint32_t flags;
- uint32_t class_code;
- uint32_t nvectors;
- uint32_t dfselect;
- uint32_t gfselect;
- uint32_t guest_features[2];
- VirtIOPCIQueue vqs[VIRTIO_QUEUE_MAX];
-
- bool ioeventfd_disabled;
- bool ioeventfd_started;
- VirtIOIRQFD *vector_irqfd;
- int nvqs_with_notifiers;
- VirtioBusState bus;
-};
-
-
-/*
- * virtio-scsi-pci: This extends VirtioPCIProxy.
- */
-#define TYPE_VIRTIO_SCSI_PCI "virtio-scsi-pci"
-#define VIRTIO_SCSI_PCI(obj) \
- OBJECT_CHECK(VirtIOSCSIPCI, (obj), TYPE_VIRTIO_SCSI_PCI)
-
-struct VirtIOSCSIPCI {
- VirtIOPCIProxy parent_obj;
- VirtIOSCSI vdev;
-};
-
-#ifdef CONFIG_VHOST_SCSI
-/*
- * vhost-scsi-pci: This extends VirtioPCIProxy.
- */
-#define TYPE_VHOST_SCSI_PCI "vhost-scsi-pci"
-#define VHOST_SCSI_PCI(obj) \
- OBJECT_CHECK(VHostSCSIPCI, (obj), TYPE_VHOST_SCSI_PCI)
-
-struct VHostSCSIPCI {
- VirtIOPCIProxy parent_obj;
- VHostSCSI vdev;
-};
-#endif
-
-/*
- * virtio-blk-pci: This extends VirtioPCIProxy.
- */
-#define TYPE_VIRTIO_BLK_PCI "virtio-blk-pci"
-#define VIRTIO_BLK_PCI(obj) \
- OBJECT_CHECK(VirtIOBlkPCI, (obj), TYPE_VIRTIO_BLK_PCI)
-
-struct VirtIOBlkPCI {
- VirtIOPCIProxy parent_obj;
- VirtIOBlock vdev;
-};
-
-/*
- * virtio-balloon-pci: This extends VirtioPCIProxy.
- */
-#define TYPE_VIRTIO_BALLOON_PCI "virtio-balloon-pci"
-#define VIRTIO_BALLOON_PCI(obj) \
- OBJECT_CHECK(VirtIOBalloonPCI, (obj), TYPE_VIRTIO_BALLOON_PCI)
-
-struct VirtIOBalloonPCI {
- VirtIOPCIProxy parent_obj;
- VirtIOBalloon vdev;
-};
-
-/*
- * virtio-serial-pci: This extends VirtioPCIProxy.
- */
-#define TYPE_VIRTIO_SERIAL_PCI "virtio-serial-pci"
-#define VIRTIO_SERIAL_PCI(obj) \
- OBJECT_CHECK(VirtIOSerialPCI, (obj), TYPE_VIRTIO_SERIAL_PCI)
-
-struct VirtIOSerialPCI {
- VirtIOPCIProxy parent_obj;
- VirtIOSerial vdev;
-};
-
-/*
- * virtio-net-pci: This extends VirtioPCIProxy.
- */
-#define TYPE_VIRTIO_NET_PCI "virtio-net-pci"
-#define VIRTIO_NET_PCI(obj) \
- OBJECT_CHECK(VirtIONetPCI, (obj), TYPE_VIRTIO_NET_PCI)
-
-struct VirtIONetPCI {
- VirtIOPCIProxy parent_obj;
- VirtIONet vdev;
-};
-
-/*
- * virtio-9p-pci: This extends VirtioPCIProxy.
- */
-
-#ifdef CONFIG_VIRTFS
-
-#define TYPE_VIRTIO_9P_PCI "virtio-9p-pci"
-#define VIRTIO_9P_PCI(obj) \
- OBJECT_CHECK(V9fsPCIState, (obj), TYPE_VIRTIO_9P_PCI)
-
-typedef struct V9fsPCIState {
- VirtIOPCIProxy parent_obj;
- V9fsVirtioState vdev;
-} V9fsPCIState;
-
-#endif
-
-/*
- * virtio-rng-pci: This extends VirtioPCIProxy.
- */
-#define TYPE_VIRTIO_RNG_PCI "virtio-rng-pci"
-#define VIRTIO_RNG_PCI(obj) \
- OBJECT_CHECK(VirtIORngPCI, (obj), TYPE_VIRTIO_RNG_PCI)
-
-struct VirtIORngPCI {
- VirtIOPCIProxy parent_obj;
- VirtIORNG vdev;
-};
-
-/*
- * virtio-input-pci: This extends VirtioPCIProxy.
- */
-#define TYPE_VIRTIO_INPUT_PCI "virtio-input-pci"
-#define VIRTIO_INPUT_PCI(obj) \
- OBJECT_CHECK(VirtIOInputPCI, (obj), TYPE_VIRTIO_INPUT_PCI)
-
-struct VirtIOInputPCI {
- VirtIOPCIProxy parent_obj;
- VirtIOInput vdev;
-};
-
-#define TYPE_VIRTIO_INPUT_HID_PCI "virtio-input-hid-pci"
-#define TYPE_VIRTIO_KEYBOARD_PCI "virtio-keyboard-pci"
-#define TYPE_VIRTIO_MOUSE_PCI "virtio-mouse-pci"
-#define TYPE_VIRTIO_TABLET_PCI "virtio-tablet-pci"
-#define VIRTIO_INPUT_HID_PCI(obj) \
- OBJECT_CHECK(VirtIOInputHIDPCI, (obj), TYPE_VIRTIO_INPUT_HID_PCI)
-
-struct VirtIOInputHIDPCI {
- VirtIOPCIProxy parent_obj;
- VirtIOInputHID vdev;
-};
-
-#ifdef CONFIG_LINUX
-
-#define TYPE_VIRTIO_INPUT_HOST_PCI "virtio-input-host-pci"
-#define VIRTIO_INPUT_HOST_PCI(obj) \
- OBJECT_CHECK(VirtIOInputHostPCI, (obj), TYPE_VIRTIO_INPUT_HOST_PCI)
-
-struct VirtIOInputHostPCI {
- VirtIOPCIProxy parent_obj;
- VirtIOInputHost vdev;
-};
-
-#endif
-
-/*
- * virtio-gpu-pci: This extends VirtioPCIProxy.
- */
-#define TYPE_VIRTIO_GPU_PCI "virtio-gpu-pci"
-#define VIRTIO_GPU_PCI(obj) \
- OBJECT_CHECK(VirtIOGPUPCI, (obj), TYPE_VIRTIO_GPU_PCI)
-
-struct VirtIOGPUPCI {
- VirtIOPCIProxy parent_obj;
- VirtIOGPU vdev;
-};
-
-/* Virtio ABI version, if we increment this, we break the guest driver. */
-#define VIRTIO_PCI_ABI_VERSION 0
-
-#endif
diff --git a/qemu/hw/virtio/virtio-rng.c b/qemu/hw/virtio/virtio-rng.c
deleted file mode 100644
index 6b991a764..000000000
--- a/qemu/hw/virtio/virtio-rng.c
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * A virtio device implementing a hardware random number generator.
- *
- * Copyright 2012 Red Hat, Inc.
- * Copyright 2012 Amit Shah <amit.shah@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or
- * (at your option) any later version. See the COPYING file in the
- * top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu/iov.h"
-#include "hw/qdev.h"
-#include "hw/virtio/virtio.h"
-#include "hw/virtio/virtio-rng.h"
-#include "sysemu/rng.h"
-#include "qom/object_interfaces.h"
-#include "trace.h"
-
-static bool is_guest_ready(VirtIORNG *vrng)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(vrng);
- if (virtio_queue_ready(vrng->vq)
- && (vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) {
- return true;
- }
- trace_virtio_rng_guest_not_ready(vrng);
- return false;
-}
-
-static size_t get_request_size(VirtQueue *vq, unsigned quota)
-{
- unsigned int in, out;
-
- virtqueue_get_avail_bytes(vq, &in, &out, quota, 0);
- return in;
-}
-
-static void virtio_rng_process(VirtIORNG *vrng);
-
-/* Send data from a char device over to the guest */
-static void chr_read(void *opaque, const void *buf, size_t size)
-{
- VirtIORNG *vrng = opaque;
- VirtIODevice *vdev = VIRTIO_DEVICE(vrng);
- VirtQueueElement *elem;
- size_t len;
- int offset;
-
- if (!is_guest_ready(vrng)) {
- return;
- }
-
- vrng->quota_remaining -= size;
-
- offset = 0;
- while (offset < size) {
- elem = virtqueue_pop(vrng->vq, sizeof(VirtQueueElement));
- if (!elem) {
- break;
- }
- len = iov_from_buf(elem->in_sg, elem->in_num,
- 0, buf + offset, size - offset);
- offset += len;
-
- virtqueue_push(vrng->vq, elem, len);
- trace_virtio_rng_pushed(vrng, len);
- g_free(elem);
- }
- virtio_notify(vdev, vrng->vq);
-
- if (!virtio_queue_empty(vrng->vq)) {
- /* If we didn't drain the queue, call virtio_rng_process
- * to take care of asking for more data as appropriate.
- */
- virtio_rng_process(vrng);
- }
-}
-
-static void virtio_rng_process(VirtIORNG *vrng)
-{
- size_t size;
- unsigned quota;
-
- if (!is_guest_ready(vrng)) {
- return;
- }
-
- if (vrng->activate_timer) {
- timer_mod(vrng->rate_limit_timer,
- qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + vrng->conf.period_ms);
- vrng->activate_timer = false;
- }
-
- if (vrng->quota_remaining < 0) {
- quota = 0;
- } else {
- quota = MIN((uint64_t)vrng->quota_remaining, (uint64_t)UINT32_MAX);
- }
- size = get_request_size(vrng->vq, quota);
-
- trace_virtio_rng_request(vrng, size, quota);
-
- size = MIN(vrng->quota_remaining, size);
- if (size) {
- rng_backend_request_entropy(vrng->rng, size, chr_read, vrng);
- }
-}
-
-static void handle_input(VirtIODevice *vdev, VirtQueue *vq)
-{
- VirtIORNG *vrng = VIRTIO_RNG(vdev);
- virtio_rng_process(vrng);
-}
-
-static uint64_t get_features(VirtIODevice *vdev, uint64_t f, Error **errp)
-{
- return f;
-}
-
-static void virtio_rng_save(QEMUFile *f, void *opaque)
-{
- VirtIODevice *vdev = opaque;
-
- virtio_save(vdev, f);
-}
-
-static int virtio_rng_load(QEMUFile *f, void *opaque, int version_id)
-{
- VirtIORNG *vrng = opaque;
- int ret;
-
- if (version_id != 1) {
- return -EINVAL;
- }
- ret = virtio_load(VIRTIO_DEVICE(vrng), f, version_id);
- if (ret != 0) {
- return ret;
- }
-
- /* We may have an element ready but couldn't process it due to a quota
- * limit. Make sure to try again after live migration when the quota may
- * have been reset.
- */
- virtio_rng_process(vrng);
-
- return 0;
-}
-
-static void check_rate_limit(void *opaque)
-{
- VirtIORNG *vrng = opaque;
-
- vrng->quota_remaining = vrng->conf.max_bytes;
- virtio_rng_process(vrng);
- vrng->activate_timer = true;
-}
-
-static void virtio_rng_device_realize(DeviceState *dev, Error **errp)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
- VirtIORNG *vrng = VIRTIO_RNG(dev);
- Error *local_err = NULL;
-
- if (vrng->conf.period_ms <= 0) {
- error_setg(errp, "'period' parameter expects a positive integer");
- return;
- }
-
- /* Workaround: Property parsing does not enforce unsigned integers,
- * So this is a hack to reject such numbers. */
- if (vrng->conf.max_bytes > INT64_MAX) {
- error_setg(errp, "'max-bytes' parameter must be non-negative, "
- "and less than 2^63");
- return;
- }
-
- if (vrng->conf.rng == NULL) {
- vrng->conf.default_backend = RNG_RANDOM(object_new(TYPE_RNG_RANDOM));
-
- user_creatable_complete(OBJECT(vrng->conf.default_backend),
- &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- object_unref(OBJECT(vrng->conf.default_backend));
- return;
- }
-
- object_property_add_child(OBJECT(dev),
- "default-backend",
- OBJECT(vrng->conf.default_backend),
- NULL);
-
- /* The child property took a reference, we can safely drop ours now */
- object_unref(OBJECT(vrng->conf.default_backend));
-
- object_property_set_link(OBJECT(dev),
- OBJECT(vrng->conf.default_backend),
- "rng", NULL);
- }
-
- vrng->rng = vrng->conf.rng;
- if (vrng->rng == NULL) {
- error_setg(errp, "'rng' parameter expects a valid object");
- return;
- }
-
- virtio_init(vdev, "virtio-rng", VIRTIO_ID_RNG, 0);
-
- vrng->vq = virtio_add_queue(vdev, 8, handle_input);
- vrng->quota_remaining = vrng->conf.max_bytes;
- vrng->rate_limit_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL,
- check_rate_limit, vrng);
- vrng->activate_timer = true;
- register_savevm(dev, "virtio-rng", -1, 1, virtio_rng_save,
- virtio_rng_load, vrng);
-}
-
-static void virtio_rng_device_unrealize(DeviceState *dev, Error **errp)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
- VirtIORNG *vrng = VIRTIO_RNG(dev);
-
- timer_del(vrng->rate_limit_timer);
- timer_free(vrng->rate_limit_timer);
- unregister_savevm(dev, "virtio-rng", vrng);
- virtio_cleanup(vdev);
-}
-
-static Property virtio_rng_properties[] = {
- /* Set a default rate limit of 2^47 bytes per minute or roughly 2TB/s. If
- * you have an entropy source capable of generating more entropy than this
- * and you can pass it through via virtio-rng, then hats off to you. Until
- * then, this is unlimited for all practical purposes.
- */
- DEFINE_PROP_UINT64("max-bytes", VirtIORNG, conf.max_bytes, INT64_MAX),
- DEFINE_PROP_UINT32("period", VirtIORNG, conf.period_ms, 1 << 16),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_rng_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
-
- dc->props = virtio_rng_properties;
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- vdc->realize = virtio_rng_device_realize;
- vdc->unrealize = virtio_rng_device_unrealize;
- vdc->get_features = get_features;
-}
-
-static void virtio_rng_initfn(Object *obj)
-{
- VirtIORNG *vrng = VIRTIO_RNG(obj);
-
- object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
- (Object **)&vrng->conf.rng,
- qdev_prop_allow_set_link_before_realize,
- OBJ_PROP_LINK_UNREF_ON_RELEASE, NULL);
-}
-
-static const TypeInfo virtio_rng_info = {
- .name = TYPE_VIRTIO_RNG,
- .parent = TYPE_VIRTIO_DEVICE,
- .instance_size = sizeof(VirtIORNG),
- .instance_init = virtio_rng_initfn,
- .class_init = virtio_rng_class_init,
-};
-
-static void virtio_register_types(void)
-{
- type_register_static(&virtio_rng_info);
-}
-
-type_init(virtio_register_types)
diff --git a/qemu/hw/virtio/virtio.c b/qemu/hw/virtio/virtio.c
deleted file mode 100644
index 30ede3d1c..000000000
--- a/qemu/hw/virtio/virtio.c
+++ /dev/null
@@ -1,1926 +0,0 @@
-/*
- * Virtio Support
- *
- * Copyright IBM, Corp. 2007
- *
- * Authors:
- * Anthony Liguori <aliguori@us.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "trace.h"
-#include "exec/address-spaces.h"
-#include "qemu/error-report.h"
-#include "hw/virtio/virtio.h"
-#include "qemu/atomic.h"
-#include "hw/virtio/virtio-bus.h"
-#include "migration/migration.h"
-#include "hw/virtio/virtio-access.h"
-
-/*
- * The alignment to use between consumer and producer parts of vring.
- * x86 pagesize again. This is the default, used by transports like PCI
- * which don't provide a means for the guest to tell the host the alignment.
- */
-#define VIRTIO_PCI_VRING_ALIGN 4096
-
-typedef struct VRingDesc
-{
- uint64_t addr;
- uint32_t len;
- uint16_t flags;
- uint16_t next;
-} VRingDesc;
-
-typedef struct VRingAvail
-{
- uint16_t flags;
- uint16_t idx;
- uint16_t ring[0];
-} VRingAvail;
-
-typedef struct VRingUsedElem
-{
- uint32_t id;
- uint32_t len;
-} VRingUsedElem;
-
-typedef struct VRingUsed
-{
- uint16_t flags;
- uint16_t idx;
- VRingUsedElem ring[0];
-} VRingUsed;
-
-typedef struct VRing
-{
- unsigned int num;
- unsigned int num_default;
- unsigned int align;
- hwaddr desc;
- hwaddr avail;
- hwaddr used;
-} VRing;
-
-struct VirtQueue
-{
- VRing vring;
-
- /* Next head to pop */
- uint16_t last_avail_idx;
-
- /* Last avail_idx read from VQ. */
- uint16_t shadow_avail_idx;
-
- uint16_t used_idx;
-
- /* Last used index value we have signalled on */
- uint16_t signalled_used;
-
- /* Last used index value we have signalled on */
- bool signalled_used_valid;
-
- /* Notification enabled? */
- bool notification;
-
- uint16_t queue_index;
-
- int inuse;
-
- uint16_t vector;
- void (*handle_output)(VirtIODevice *vdev, VirtQueue *vq);
- void (*handle_aio_output)(VirtIODevice *vdev, VirtQueue *vq);
- VirtIODevice *vdev;
- EventNotifier guest_notifier;
- EventNotifier host_notifier;
- QLIST_ENTRY(VirtQueue) node;
-};
-
-/* virt queue functions */
-void virtio_queue_update_rings(VirtIODevice *vdev, int n)
-{
- VRing *vring = &vdev->vq[n].vring;
-
- if (!vring->desc) {
- /* not yet setup -> nothing to do */
- return;
- }
- vring->avail = vring->desc + vring->num * sizeof(VRingDesc);
- vring->used = vring_align(vring->avail +
- offsetof(VRingAvail, ring[vring->num]),
- vring->align);
-}
-
-static void vring_desc_read(VirtIODevice *vdev, VRingDesc *desc,
- hwaddr desc_pa, int i)
-{
- address_space_read(&address_space_memory, desc_pa + i * sizeof(VRingDesc),
- MEMTXATTRS_UNSPECIFIED, (void *)desc, sizeof(VRingDesc));
- virtio_tswap64s(vdev, &desc->addr);
- virtio_tswap32s(vdev, &desc->len);
- virtio_tswap16s(vdev, &desc->flags);
- virtio_tswap16s(vdev, &desc->next);
-}
-
-static inline uint16_t vring_avail_flags(VirtQueue *vq)
-{
- hwaddr pa;
- pa = vq->vring.avail + offsetof(VRingAvail, flags);
- return virtio_lduw_phys(vq->vdev, pa);
-}
-
-static inline uint16_t vring_avail_idx(VirtQueue *vq)
-{
- hwaddr pa;
- pa = vq->vring.avail + offsetof(VRingAvail, idx);
- vq->shadow_avail_idx = virtio_lduw_phys(vq->vdev, pa);
- return vq->shadow_avail_idx;
-}
-
-static inline uint16_t vring_avail_ring(VirtQueue *vq, int i)
-{
- hwaddr pa;
- pa = vq->vring.avail + offsetof(VRingAvail, ring[i]);
- return virtio_lduw_phys(vq->vdev, pa);
-}
-
-static inline uint16_t vring_get_used_event(VirtQueue *vq)
-{
- return vring_avail_ring(vq, vq->vring.num);
-}
-
-static inline void vring_used_write(VirtQueue *vq, VRingUsedElem *uelem,
- int i)
-{
- hwaddr pa;
- virtio_tswap32s(vq->vdev, &uelem->id);
- virtio_tswap32s(vq->vdev, &uelem->len);
- pa = vq->vring.used + offsetof(VRingUsed, ring[i]);
- address_space_write(&address_space_memory, pa, MEMTXATTRS_UNSPECIFIED,
- (void *)uelem, sizeof(VRingUsedElem));
-}
-
-static uint16_t vring_used_idx(VirtQueue *vq)
-{
- hwaddr pa;
- pa = vq->vring.used + offsetof(VRingUsed, idx);
- return virtio_lduw_phys(vq->vdev, pa);
-}
-
-static inline void vring_used_idx_set(VirtQueue *vq, uint16_t val)
-{
- hwaddr pa;
- pa = vq->vring.used + offsetof(VRingUsed, idx);
- virtio_stw_phys(vq->vdev, pa, val);
- vq->used_idx = val;
-}
-
-static inline void vring_used_flags_set_bit(VirtQueue *vq, int mask)
-{
- VirtIODevice *vdev = vq->vdev;
- hwaddr pa;
- pa = vq->vring.used + offsetof(VRingUsed, flags);
- virtio_stw_phys(vdev, pa, virtio_lduw_phys(vdev, pa) | mask);
-}
-
-static inline void vring_used_flags_unset_bit(VirtQueue *vq, int mask)
-{
- VirtIODevice *vdev = vq->vdev;
- hwaddr pa;
- pa = vq->vring.used + offsetof(VRingUsed, flags);
- virtio_stw_phys(vdev, pa, virtio_lduw_phys(vdev, pa) & ~mask);
-}
-
-static inline void vring_set_avail_event(VirtQueue *vq, uint16_t val)
-{
- hwaddr pa;
- if (!vq->notification) {
- return;
- }
- pa = vq->vring.used + offsetof(VRingUsed, ring[vq->vring.num]);
- virtio_stw_phys(vq->vdev, pa, val);
-}
-
-void virtio_queue_set_notification(VirtQueue *vq, int enable)
-{
- vq->notification = enable;
- if (virtio_vdev_has_feature(vq->vdev, VIRTIO_RING_F_EVENT_IDX)) {
- vring_set_avail_event(vq, vring_avail_idx(vq));
- } else if (enable) {
- vring_used_flags_unset_bit(vq, VRING_USED_F_NO_NOTIFY);
- } else {
- vring_used_flags_set_bit(vq, VRING_USED_F_NO_NOTIFY);
- }
- if (enable) {
- /* Expose avail event/used flags before caller checks the avail idx. */
- smp_mb();
- }
-}
-
-int virtio_queue_ready(VirtQueue *vq)
-{
- return vq->vring.avail != 0;
-}
-
-/* Fetch avail_idx from VQ memory only when we really need to know if
- * guest has added some buffers. */
-int virtio_queue_empty(VirtQueue *vq)
-{
- if (vq->shadow_avail_idx != vq->last_avail_idx) {
- return 0;
- }
-
- return vring_avail_idx(vq) == vq->last_avail_idx;
-}
-
-static void virtqueue_unmap_sg(VirtQueue *vq, const VirtQueueElement *elem,
- unsigned int len)
-{
- unsigned int offset;
- int i;
-
- offset = 0;
- for (i = 0; i < elem->in_num; i++) {
- size_t size = MIN(len - offset, elem->in_sg[i].iov_len);
-
- cpu_physical_memory_unmap(elem->in_sg[i].iov_base,
- elem->in_sg[i].iov_len,
- 1, size);
-
- offset += size;
- }
-
- for (i = 0; i < elem->out_num; i++)
- cpu_physical_memory_unmap(elem->out_sg[i].iov_base,
- elem->out_sg[i].iov_len,
- 0, elem->out_sg[i].iov_len);
-}
-
-void virtqueue_discard(VirtQueue *vq, const VirtQueueElement *elem,
- unsigned int len)
-{
- vq->last_avail_idx--;
- virtqueue_unmap_sg(vq, elem, len);
-}
-
-void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
- unsigned int len, unsigned int idx)
-{
- VRingUsedElem uelem;
-
- trace_virtqueue_fill(vq, elem, len, idx);
-
- virtqueue_unmap_sg(vq, elem, len);
-
- idx = (idx + vq->used_idx) % vq->vring.num;
-
- uelem.id = elem->index;
- uelem.len = len;
- vring_used_write(vq, &uelem, idx);
-}
-
-void virtqueue_flush(VirtQueue *vq, unsigned int count)
-{
- uint16_t old, new;
- /* Make sure buffer is written before we update index. */
- smp_wmb();
- trace_virtqueue_flush(vq, count);
- old = vq->used_idx;
- new = old + count;
- vring_used_idx_set(vq, new);
- vq->inuse -= count;
- if (unlikely((int16_t)(new - vq->signalled_used) < (uint16_t)(new - old)))
- vq->signalled_used_valid = false;
-}
-
-void virtqueue_push(VirtQueue *vq, const VirtQueueElement *elem,
- unsigned int len)
-{
- virtqueue_fill(vq, elem, len, 0);
- virtqueue_flush(vq, 1);
-}
-
-static int virtqueue_num_heads(VirtQueue *vq, unsigned int idx)
-{
- uint16_t num_heads = vring_avail_idx(vq) - idx;
-
- /* Check it isn't doing very strange things with descriptor numbers. */
- if (num_heads > vq->vring.num) {
- error_report("Guest moved used index from %u to %u",
- idx, vq->shadow_avail_idx);
- exit(1);
- }
- /* On success, callers read a descriptor at vq->last_avail_idx.
- * Make sure descriptor read does not bypass avail index read. */
- if (num_heads) {
- smp_rmb();
- }
-
- return num_heads;
-}
-
-static unsigned int virtqueue_get_head(VirtQueue *vq, unsigned int idx)
-{
- unsigned int head;
-
- /* Grab the next descriptor number they're advertising, and increment
- * the index we've seen. */
- head = vring_avail_ring(vq, idx % vq->vring.num);
-
- /* If their number is silly, that's a fatal mistake. */
- if (head >= vq->vring.num) {
- error_report("Guest says index %u is available", head);
- exit(1);
- }
-
- return head;
-}
-
-static unsigned virtqueue_read_next_desc(VirtIODevice *vdev, VRingDesc *desc,
- hwaddr desc_pa, unsigned int max)
-{
- unsigned int next;
-
- /* If this descriptor says it doesn't chain, we're done. */
- if (!(desc->flags & VRING_DESC_F_NEXT)) {
- return max;
- }
-
- /* Check they're not leading us off end of descriptors. */
- next = desc->next;
- /* Make sure compiler knows to grab that: we don't want it changing! */
- smp_wmb();
-
- if (next >= max) {
- error_report("Desc next is %u", next);
- exit(1);
- }
-
- vring_desc_read(vdev, desc, desc_pa, next);
- return next;
-}
-
-void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes,
- unsigned int *out_bytes,
- unsigned max_in_bytes, unsigned max_out_bytes)
-{
- unsigned int idx;
- unsigned int total_bufs, in_total, out_total;
-
- idx = vq->last_avail_idx;
-
- total_bufs = in_total = out_total = 0;
- while (virtqueue_num_heads(vq, idx)) {
- VirtIODevice *vdev = vq->vdev;
- unsigned int max, num_bufs, indirect = 0;
- VRingDesc desc;
- hwaddr desc_pa;
- int i;
-
- max = vq->vring.num;
- num_bufs = total_bufs;
- i = virtqueue_get_head(vq, idx++);
- desc_pa = vq->vring.desc;
- vring_desc_read(vdev, &desc, desc_pa, i);
-
- if (desc.flags & VRING_DESC_F_INDIRECT) {
- if (desc.len % sizeof(VRingDesc)) {
- error_report("Invalid size for indirect buffer table");
- exit(1);
- }
-
- /* If we've got too many, that implies a descriptor loop. */
- if (num_bufs >= max) {
- error_report("Looped descriptor");
- exit(1);
- }
-
- /* loop over the indirect descriptor table */
- indirect = 1;
- max = desc.len / sizeof(VRingDesc);
- desc_pa = desc.addr;
- num_bufs = i = 0;
- vring_desc_read(vdev, &desc, desc_pa, i);
- }
-
- do {
- /* If we've got too many, that implies a descriptor loop. */
- if (++num_bufs > max) {
- error_report("Looped descriptor");
- exit(1);
- }
-
- if (desc.flags & VRING_DESC_F_WRITE) {
- in_total += desc.len;
- } else {
- out_total += desc.len;
- }
- if (in_total >= max_in_bytes && out_total >= max_out_bytes) {
- goto done;
- }
- } while ((i = virtqueue_read_next_desc(vdev, &desc, desc_pa, max)) != max);
-
- if (!indirect)
- total_bufs = num_bufs;
- else
- total_bufs++;
- }
-done:
- if (in_bytes) {
- *in_bytes = in_total;
- }
- if (out_bytes) {
- *out_bytes = out_total;
- }
-}
-
-int virtqueue_avail_bytes(VirtQueue *vq, unsigned int in_bytes,
- unsigned int out_bytes)
-{
- unsigned int in_total, out_total;
-
- virtqueue_get_avail_bytes(vq, &in_total, &out_total, in_bytes, out_bytes);
- return in_bytes <= in_total && out_bytes <= out_total;
-}
-
-static void virtqueue_map_desc(unsigned int *p_num_sg, hwaddr *addr, struct iovec *iov,
- unsigned int max_num_sg, bool is_write,
- hwaddr pa, size_t sz)
-{
- unsigned num_sg = *p_num_sg;
- assert(num_sg <= max_num_sg);
-
- while (sz) {
- hwaddr len = sz;
-
- if (num_sg == max_num_sg) {
- error_report("virtio: too many write descriptors in indirect table");
- exit(1);
- }
-
- iov[num_sg].iov_base = cpu_physical_memory_map(pa, &len, is_write);
- iov[num_sg].iov_len = len;
- addr[num_sg] = pa;
-
- sz -= len;
- pa += len;
- num_sg++;
- }
- *p_num_sg = num_sg;
-}
-
-static void virtqueue_map_iovec(struct iovec *sg, hwaddr *addr,
- unsigned int *num_sg, unsigned int max_size,
- int is_write)
-{
- unsigned int i;
- hwaddr len;
-
- /* Note: this function MUST validate input, some callers
- * are passing in num_sg values received over the network.
- */
- /* TODO: teach all callers that this can fail, and return failure instead
- * of asserting here.
- * When we do, we might be able to re-enable NDEBUG below.
- */
-#ifdef NDEBUG
-#error building with NDEBUG is not supported
-#endif
- assert(*num_sg <= max_size);
-
- for (i = 0; i < *num_sg; i++) {
- len = sg[i].iov_len;
- sg[i].iov_base = cpu_physical_memory_map(addr[i], &len, is_write);
- if (!sg[i].iov_base) {
- error_report("virtio: error trying to map MMIO memory");
- exit(1);
- }
- if (len != sg[i].iov_len) {
- error_report("virtio: unexpected memory split");
- exit(1);
- }
- }
-}
-
-void virtqueue_map(VirtQueueElement *elem)
-{
- virtqueue_map_iovec(elem->in_sg, elem->in_addr, &elem->in_num,
- VIRTQUEUE_MAX_SIZE, 1);
- virtqueue_map_iovec(elem->out_sg, elem->out_addr, &elem->out_num,
- VIRTQUEUE_MAX_SIZE, 0);
-}
-
-void *virtqueue_alloc_element(size_t sz, unsigned out_num, unsigned in_num)
-{
- VirtQueueElement *elem;
- size_t in_addr_ofs = QEMU_ALIGN_UP(sz, __alignof__(elem->in_addr[0]));
- size_t out_addr_ofs = in_addr_ofs + in_num * sizeof(elem->in_addr[0]);
- size_t out_addr_end = out_addr_ofs + out_num * sizeof(elem->out_addr[0]);
- size_t in_sg_ofs = QEMU_ALIGN_UP(out_addr_end, __alignof__(elem->in_sg[0]));
- size_t out_sg_ofs = in_sg_ofs + in_num * sizeof(elem->in_sg[0]);
- size_t out_sg_end = out_sg_ofs + out_num * sizeof(elem->out_sg[0]);
-
- assert(sz >= sizeof(VirtQueueElement));
- elem = g_malloc(out_sg_end);
- elem->out_num = out_num;
- elem->in_num = in_num;
- elem->in_addr = (void *)elem + in_addr_ofs;
- elem->out_addr = (void *)elem + out_addr_ofs;
- elem->in_sg = (void *)elem + in_sg_ofs;
- elem->out_sg = (void *)elem + out_sg_ofs;
- return elem;
-}
-
-void *virtqueue_pop(VirtQueue *vq, size_t sz)
-{
- unsigned int i, head, max;
- hwaddr desc_pa = vq->vring.desc;
- VirtIODevice *vdev = vq->vdev;
- VirtQueueElement *elem;
- unsigned out_num, in_num;
- hwaddr addr[VIRTQUEUE_MAX_SIZE];
- struct iovec iov[VIRTQUEUE_MAX_SIZE];
- VRingDesc desc;
-
- if (virtio_queue_empty(vq)) {
- return NULL;
- }
- /* Needed after virtio_queue_empty(), see comment in
- * virtqueue_num_heads(). */
- smp_rmb();
-
- /* When we start there are none of either input nor output. */
- out_num = in_num = 0;
-
- max = vq->vring.num;
-
- i = head = virtqueue_get_head(vq, vq->last_avail_idx++);
- if (virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) {
- vring_set_avail_event(vq, vq->last_avail_idx);
- }
-
- vring_desc_read(vdev, &desc, desc_pa, i);
- if (desc.flags & VRING_DESC_F_INDIRECT) {
- if (desc.len % sizeof(VRingDesc)) {
- error_report("Invalid size for indirect buffer table");
- exit(1);
- }
-
- /* loop over the indirect descriptor table */
- max = desc.len / sizeof(VRingDesc);
- desc_pa = desc.addr;
- i = 0;
- vring_desc_read(vdev, &desc, desc_pa, i);
- }
-
- /* Collect all the descriptors */
- do {
- if (desc.flags & VRING_DESC_F_WRITE) {
- virtqueue_map_desc(&in_num, addr + out_num, iov + out_num,
- VIRTQUEUE_MAX_SIZE - out_num, true, desc.addr, desc.len);
- } else {
- if (in_num) {
- error_report("Incorrect order for descriptors");
- exit(1);
- }
- virtqueue_map_desc(&out_num, addr, iov,
- VIRTQUEUE_MAX_SIZE, false, desc.addr, desc.len);
- }
-
- /* If we've got too many, that implies a descriptor loop. */
- if ((in_num + out_num) > max) {
- error_report("Looped descriptor");
- exit(1);
- }
- } while ((i = virtqueue_read_next_desc(vdev, &desc, desc_pa, max)) != max);
-
- /* Now copy what we have collected and mapped */
- elem = virtqueue_alloc_element(sz, out_num, in_num);
- elem->index = head;
- for (i = 0; i < out_num; i++) {
- elem->out_addr[i] = addr[i];
- elem->out_sg[i] = iov[i];
- }
- for (i = 0; i < in_num; i++) {
- elem->in_addr[i] = addr[out_num + i];
- elem->in_sg[i] = iov[out_num + i];
- }
-
- vq->inuse++;
-
- trace_virtqueue_pop(vq, elem, elem->in_num, elem->out_num);
- return elem;
-}
-
-/* Reading and writing a structure directly to QEMUFile is *awful*, but
- * it is what QEMU has always done by mistake. We can change it sooner
- * or later by bumping the version number of the affected vm states.
- * In the meanwhile, since the in-memory layout of VirtQueueElement
- * has changed, we need to marshal to and from the layout that was
- * used before the change.
- */
-typedef struct VirtQueueElementOld {
- unsigned int index;
- unsigned int out_num;
- unsigned int in_num;
- hwaddr in_addr[VIRTQUEUE_MAX_SIZE];
- hwaddr out_addr[VIRTQUEUE_MAX_SIZE];
- struct iovec in_sg[VIRTQUEUE_MAX_SIZE];
- struct iovec out_sg[VIRTQUEUE_MAX_SIZE];
-} VirtQueueElementOld;
-
-void *qemu_get_virtqueue_element(QEMUFile *f, size_t sz)
-{
- VirtQueueElement *elem;
- VirtQueueElementOld data;
- int i;
-
- qemu_get_buffer(f, (uint8_t *)&data, sizeof(VirtQueueElementOld));
-
- elem = virtqueue_alloc_element(sz, data.out_num, data.in_num);
- elem->index = data.index;
-
- for (i = 0; i < elem->in_num; i++) {
- elem->in_addr[i] = data.in_addr[i];
- }
-
- for (i = 0; i < elem->out_num; i++) {
- elem->out_addr[i] = data.out_addr[i];
- }
-
- for (i = 0; i < elem->in_num; i++) {
- /* Base is overwritten by virtqueue_map. */
- elem->in_sg[i].iov_base = 0;
- elem->in_sg[i].iov_len = data.in_sg[i].iov_len;
- }
-
- for (i = 0; i < elem->out_num; i++) {
- /* Base is overwritten by virtqueue_map. */
- elem->out_sg[i].iov_base = 0;
- elem->out_sg[i].iov_len = data.out_sg[i].iov_len;
- }
-
- virtqueue_map(elem);
- return elem;
-}
-
-void qemu_put_virtqueue_element(QEMUFile *f, VirtQueueElement *elem)
-{
- VirtQueueElementOld data;
- int i;
-
- memset(&data, 0, sizeof(data));
- data.index = elem->index;
- data.in_num = elem->in_num;
- data.out_num = elem->out_num;
-
- for (i = 0; i < elem->in_num; i++) {
- data.in_addr[i] = elem->in_addr[i];
- }
-
- for (i = 0; i < elem->out_num; i++) {
- data.out_addr[i] = elem->out_addr[i];
- }
-
- for (i = 0; i < elem->in_num; i++) {
- /* Base is overwritten by virtqueue_map when loading. Do not
- * save it, as it would leak the QEMU address space layout. */
- data.in_sg[i].iov_len = elem->in_sg[i].iov_len;
- }
-
- for (i = 0; i < elem->out_num; i++) {
- /* Do not save iov_base as above. */
- data.out_sg[i].iov_len = elem->out_sg[i].iov_len;
- }
- qemu_put_buffer(f, (uint8_t *)&data, sizeof(VirtQueueElementOld));
-}
-
-/* virtio device */
-static void virtio_notify_vector(VirtIODevice *vdev, uint16_t vector)
-{
- BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
- VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
-
- if (k->notify) {
- k->notify(qbus->parent, vector);
- }
-}
-
-void virtio_update_irq(VirtIODevice *vdev)
-{
- virtio_notify_vector(vdev, VIRTIO_NO_VECTOR);
-}
-
-static int virtio_validate_features(VirtIODevice *vdev)
-{
- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
-
- if (k->validate_features) {
- return k->validate_features(vdev);
- } else {
- return 0;
- }
-}
-
-int virtio_set_status(VirtIODevice *vdev, uint8_t val)
-{
- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
- trace_virtio_set_status(vdev, val);
-
- if (virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) {
- if (!(vdev->status & VIRTIO_CONFIG_S_FEATURES_OK) &&
- val & VIRTIO_CONFIG_S_FEATURES_OK) {
- int ret = virtio_validate_features(vdev);
-
- if (ret) {
- return ret;
- }
- }
- }
- if (k->set_status) {
- k->set_status(vdev, val);
- }
- vdev->status = val;
- return 0;
-}
-
-bool target_words_bigendian(void);
-static enum virtio_device_endian virtio_default_endian(void)
-{
- if (target_words_bigendian()) {
- return VIRTIO_DEVICE_ENDIAN_BIG;
- } else {
- return VIRTIO_DEVICE_ENDIAN_LITTLE;
- }
-}
-
-static enum virtio_device_endian virtio_current_cpu_endian(void)
-{
- CPUClass *cc = CPU_GET_CLASS(current_cpu);
-
- if (cc->virtio_is_big_endian(current_cpu)) {
- return VIRTIO_DEVICE_ENDIAN_BIG;
- } else {
- return VIRTIO_DEVICE_ENDIAN_LITTLE;
- }
-}
-
-void virtio_reset(void *opaque)
-{
- VirtIODevice *vdev = opaque;
- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
- int i;
-
- virtio_set_status(vdev, 0);
- if (current_cpu) {
- /* Guest initiated reset */
- vdev->device_endian = virtio_current_cpu_endian();
- } else {
- /* System reset */
- vdev->device_endian = virtio_default_endian();
- }
-
- if (k->reset) {
- k->reset(vdev);
- }
-
- vdev->guest_features = 0;
- vdev->queue_sel = 0;
- vdev->status = 0;
- vdev->isr = 0;
- vdev->config_vector = VIRTIO_NO_VECTOR;
- virtio_notify_vector(vdev, vdev->config_vector);
-
- for(i = 0; i < VIRTIO_QUEUE_MAX; i++) {
- vdev->vq[i].vring.desc = 0;
- vdev->vq[i].vring.avail = 0;
- vdev->vq[i].vring.used = 0;
- vdev->vq[i].last_avail_idx = 0;
- vdev->vq[i].shadow_avail_idx = 0;
- vdev->vq[i].used_idx = 0;
- virtio_queue_set_vector(vdev, i, VIRTIO_NO_VECTOR);
- vdev->vq[i].signalled_used = 0;
- vdev->vq[i].signalled_used_valid = false;
- vdev->vq[i].notification = true;
- vdev->vq[i].vring.num = vdev->vq[i].vring.num_default;
- }
-}
-
-uint32_t virtio_config_readb(VirtIODevice *vdev, uint32_t addr)
-{
- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
- uint8_t val;
-
- if (addr + sizeof(val) > vdev->config_len) {
- return (uint32_t)-1;
- }
-
- k->get_config(vdev, vdev->config);
-
- val = ldub_p(vdev->config + addr);
- return val;
-}
-
-uint32_t virtio_config_readw(VirtIODevice *vdev, uint32_t addr)
-{
- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
- uint16_t val;
-
- if (addr + sizeof(val) > vdev->config_len) {
- return (uint32_t)-1;
- }
-
- k->get_config(vdev, vdev->config);
-
- val = lduw_p(vdev->config + addr);
- return val;
-}
-
-uint32_t virtio_config_readl(VirtIODevice *vdev, uint32_t addr)
-{
- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
- uint32_t val;
-
- if (addr + sizeof(val) > vdev->config_len) {
- return (uint32_t)-1;
- }
-
- k->get_config(vdev, vdev->config);
-
- val = ldl_p(vdev->config + addr);
- return val;
-}
-
-void virtio_config_writeb(VirtIODevice *vdev, uint32_t addr, uint32_t data)
-{
- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
- uint8_t val = data;
-
- if (addr + sizeof(val) > vdev->config_len) {
- return;
- }
-
- stb_p(vdev->config + addr, val);
-
- if (k->set_config) {
- k->set_config(vdev, vdev->config);
- }
-}
-
-void virtio_config_writew(VirtIODevice *vdev, uint32_t addr, uint32_t data)
-{
- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
- uint16_t val = data;
-
- if (addr + sizeof(val) > vdev->config_len) {
- return;
- }
-
- stw_p(vdev->config + addr, val);
-
- if (k->set_config) {
- k->set_config(vdev, vdev->config);
- }
-}
-
-void virtio_config_writel(VirtIODevice *vdev, uint32_t addr, uint32_t data)
-{
- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
- uint32_t val = data;
-
- if (addr + sizeof(val) > vdev->config_len) {
- return;
- }
-
- stl_p(vdev->config + addr, val);
-
- if (k->set_config) {
- k->set_config(vdev, vdev->config);
- }
-}
-
-uint32_t virtio_config_modern_readb(VirtIODevice *vdev, uint32_t addr)
-{
- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
- uint8_t val;
-
- if (addr + sizeof(val) > vdev->config_len) {
- return (uint32_t)-1;
- }
-
- k->get_config(vdev, vdev->config);
-
- val = ldub_p(vdev->config + addr);
- return val;
-}
-
-uint32_t virtio_config_modern_readw(VirtIODevice *vdev, uint32_t addr)
-{
- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
- uint16_t val;
-
- if (addr + sizeof(val) > vdev->config_len) {
- return (uint32_t)-1;
- }
-
- k->get_config(vdev, vdev->config);
-
- val = lduw_le_p(vdev->config + addr);
- return val;
-}
-
-uint32_t virtio_config_modern_readl(VirtIODevice *vdev, uint32_t addr)
-{
- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
- uint32_t val;
-
- if (addr + sizeof(val) > vdev->config_len) {
- return (uint32_t)-1;
- }
-
- k->get_config(vdev, vdev->config);
-
- val = ldl_le_p(vdev->config + addr);
- return val;
-}
-
-void virtio_config_modern_writeb(VirtIODevice *vdev,
- uint32_t addr, uint32_t data)
-{
- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
- uint8_t val = data;
-
- if (addr + sizeof(val) > vdev->config_len) {
- return;
- }
-
- stb_p(vdev->config + addr, val);
-
- if (k->set_config) {
- k->set_config(vdev, vdev->config);
- }
-}
-
-void virtio_config_modern_writew(VirtIODevice *vdev,
- uint32_t addr, uint32_t data)
-{
- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
- uint16_t val = data;
-
- if (addr + sizeof(val) > vdev->config_len) {
- return;
- }
-
- stw_le_p(vdev->config + addr, val);
-
- if (k->set_config) {
- k->set_config(vdev, vdev->config);
- }
-}
-
-void virtio_config_modern_writel(VirtIODevice *vdev,
- uint32_t addr, uint32_t data)
-{
- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
- uint32_t val = data;
-
- if (addr + sizeof(val) > vdev->config_len) {
- return;
- }
-
- stl_le_p(vdev->config + addr, val);
-
- if (k->set_config) {
- k->set_config(vdev, vdev->config);
- }
-}
-
-void virtio_queue_set_addr(VirtIODevice *vdev, int n, hwaddr addr)
-{
- vdev->vq[n].vring.desc = addr;
- virtio_queue_update_rings(vdev, n);
-}
-
-hwaddr virtio_queue_get_addr(VirtIODevice *vdev, int n)
-{
- return vdev->vq[n].vring.desc;
-}
-
-void virtio_queue_set_rings(VirtIODevice *vdev, int n, hwaddr desc,
- hwaddr avail, hwaddr used)
-{
- vdev->vq[n].vring.desc = desc;
- vdev->vq[n].vring.avail = avail;
- vdev->vq[n].vring.used = used;
-}
-
-void virtio_queue_set_num(VirtIODevice *vdev, int n, int num)
-{
- /* Don't allow guest to flip queue between existent and
- * nonexistent states, or to set it to an invalid size.
- */
- if (!!num != !!vdev->vq[n].vring.num ||
- num > VIRTQUEUE_MAX_SIZE ||
- num < 0) {
- return;
- }
- vdev->vq[n].vring.num = num;
-}
-
-VirtQueue *virtio_vector_first_queue(VirtIODevice *vdev, uint16_t vector)
-{
- return QLIST_FIRST(&vdev->vector_queues[vector]);
-}
-
-VirtQueue *virtio_vector_next_queue(VirtQueue *vq)
-{
- return QLIST_NEXT(vq, node);
-}
-
-int virtio_queue_get_num(VirtIODevice *vdev, int n)
-{
- return vdev->vq[n].vring.num;
-}
-
-int virtio_get_num_queues(VirtIODevice *vdev)
-{
- int i;
-
- for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
- if (!virtio_queue_get_num(vdev, i)) {
- break;
- }
- }
-
- return i;
-}
-
-int virtio_queue_get_id(VirtQueue *vq)
-{
- VirtIODevice *vdev = vq->vdev;
- assert(vq >= &vdev->vq[0] && vq < &vdev->vq[VIRTIO_QUEUE_MAX]);
- return vq - &vdev->vq[0];
-}
-
-void virtio_queue_set_align(VirtIODevice *vdev, int n, int align)
-{
- BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
- VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
-
- /* virtio-1 compliant devices cannot change the alignment */
- if (virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) {
- error_report("tried to modify queue alignment for virtio-1 device");
- return;
- }
- /* Check that the transport told us it was going to do this
- * (so a buggy transport will immediately assert rather than
- * silently failing to migrate this state)
- */
- assert(k->has_variable_vring_alignment);
-
- vdev->vq[n].vring.align = align;
- virtio_queue_update_rings(vdev, n);
-}
-
-static void virtio_queue_notify_aio_vq(VirtQueue *vq)
-{
- if (vq->vring.desc && vq->handle_aio_output) {
- VirtIODevice *vdev = vq->vdev;
-
- trace_virtio_queue_notify(vdev, vq - vdev->vq, vq);
- vq->handle_aio_output(vdev, vq);
- }
-}
-
-static void virtio_queue_notify_vq(VirtQueue *vq)
-{
- if (vq->vring.desc && vq->handle_output) {
- VirtIODevice *vdev = vq->vdev;
-
- trace_virtio_queue_notify(vdev, vq - vdev->vq, vq);
- vq->handle_output(vdev, vq);
- }
-}
-
-void virtio_queue_notify(VirtIODevice *vdev, int n)
-{
- virtio_queue_notify_vq(&vdev->vq[n]);
-}
-
-uint16_t virtio_queue_vector(VirtIODevice *vdev, int n)
-{
- return n < VIRTIO_QUEUE_MAX ? vdev->vq[n].vector :
- VIRTIO_NO_VECTOR;
-}
-
-void virtio_queue_set_vector(VirtIODevice *vdev, int n, uint16_t vector)
-{
- VirtQueue *vq = &vdev->vq[n];
-
- if (n < VIRTIO_QUEUE_MAX) {
- if (vdev->vector_queues &&
- vdev->vq[n].vector != VIRTIO_NO_VECTOR) {
- QLIST_REMOVE(vq, node);
- }
- vdev->vq[n].vector = vector;
- if (vdev->vector_queues &&
- vector != VIRTIO_NO_VECTOR) {
- QLIST_INSERT_HEAD(&vdev->vector_queues[vector], vq, node);
- }
- }
-}
-
-VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size,
- void (*handle_output)(VirtIODevice *, VirtQueue *))
-{
- int i;
-
- for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
- if (vdev->vq[i].vring.num == 0)
- break;
- }
-
- if (i == VIRTIO_QUEUE_MAX || queue_size > VIRTQUEUE_MAX_SIZE)
- abort();
-
- vdev->vq[i].vring.num = queue_size;
- vdev->vq[i].vring.num_default = queue_size;
- vdev->vq[i].vring.align = VIRTIO_PCI_VRING_ALIGN;
- vdev->vq[i].handle_output = handle_output;
- vdev->vq[i].handle_aio_output = NULL;
-
- return &vdev->vq[i];
-}
-
-void virtio_del_queue(VirtIODevice *vdev, int n)
-{
- if (n < 0 || n >= VIRTIO_QUEUE_MAX) {
- abort();
- }
-
- vdev->vq[n].vring.num = 0;
- vdev->vq[n].vring.num_default = 0;
-}
-
-void virtio_irq(VirtQueue *vq)
-{
- trace_virtio_irq(vq);
- vq->vdev->isr |= 0x01;
- virtio_notify_vector(vq->vdev, vq->vector);
-}
-
-bool virtio_should_notify(VirtIODevice *vdev, VirtQueue *vq)
-{
- uint16_t old, new;
- bool v;
- /* We need to expose used array entries before checking used event. */
- smp_mb();
- /* Always notify when queue is empty (when feature acknowledge) */
- if (virtio_vdev_has_feature(vdev, VIRTIO_F_NOTIFY_ON_EMPTY) &&
- !vq->inuse && virtio_queue_empty(vq)) {
- return true;
- }
-
- if (!virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) {
- return !(vring_avail_flags(vq) & VRING_AVAIL_F_NO_INTERRUPT);
- }
-
- v = vq->signalled_used_valid;
- vq->signalled_used_valid = true;
- old = vq->signalled_used;
- new = vq->signalled_used = vq->used_idx;
- return !v || vring_need_event(vring_get_used_event(vq), new, old);
-}
-
-void virtio_notify(VirtIODevice *vdev, VirtQueue *vq)
-{
- if (!virtio_should_notify(vdev, vq)) {
- return;
- }
-
- trace_virtio_notify(vdev, vq);
- vdev->isr |= 0x01;
- virtio_notify_vector(vdev, vq->vector);
-}
-
-void virtio_notify_config(VirtIODevice *vdev)
-{
- if (!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK))
- return;
-
- vdev->isr |= 0x03;
- vdev->generation++;
- virtio_notify_vector(vdev, vdev->config_vector);
-}
-
-static bool virtio_device_endian_needed(void *opaque)
-{
- VirtIODevice *vdev = opaque;
-
- assert(vdev->device_endian != VIRTIO_DEVICE_ENDIAN_UNKNOWN);
- if (!virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) {
- return vdev->device_endian != virtio_default_endian();
- }
- /* Devices conforming to VIRTIO 1.0 or later are always LE. */
- return vdev->device_endian != VIRTIO_DEVICE_ENDIAN_LITTLE;
-}
-
-static bool virtio_64bit_features_needed(void *opaque)
-{
- VirtIODevice *vdev = opaque;
-
- return (vdev->host_features >> 32) != 0;
-}
-
-static bool virtio_virtqueue_needed(void *opaque)
-{
- VirtIODevice *vdev = opaque;
-
- return virtio_host_has_feature(vdev, VIRTIO_F_VERSION_1);
-}
-
-static bool virtio_ringsize_needed(void *opaque)
-{
- VirtIODevice *vdev = opaque;
- int i;
-
- for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
- if (vdev->vq[i].vring.num != vdev->vq[i].vring.num_default) {
- return true;
- }
- }
- return false;
-}
-
-static bool virtio_extra_state_needed(void *opaque)
-{
- VirtIODevice *vdev = opaque;
- BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
- VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
-
- return k->has_extra_state &&
- k->has_extra_state(qbus->parent);
-}
-
-static const VMStateDescription vmstate_virtqueue = {
- .name = "virtqueue_state",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT64(vring.avail, struct VirtQueue),
- VMSTATE_UINT64(vring.used, struct VirtQueue),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_virtio_virtqueues = {
- .name = "virtio/virtqueues",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = &virtio_virtqueue_needed,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT_VARRAY_POINTER_KNOWN(vq, struct VirtIODevice,
- VIRTIO_QUEUE_MAX, 0, vmstate_virtqueue, VirtQueue),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_ringsize = {
- .name = "ringsize_state",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(vring.num_default, struct VirtQueue),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_virtio_ringsize = {
- .name = "virtio/ringsize",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = &virtio_ringsize_needed,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT_VARRAY_POINTER_KNOWN(vq, struct VirtIODevice,
- VIRTIO_QUEUE_MAX, 0, vmstate_ringsize, VirtQueue),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static int get_extra_state(QEMUFile *f, void *pv, size_t size)
-{
- VirtIODevice *vdev = pv;
- BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
- VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
-
- if (!k->load_extra_state) {
- return -1;
- } else {
- return k->load_extra_state(qbus->parent, f);
- }
-}
-
-static void put_extra_state(QEMUFile *f, void *pv, size_t size)
-{
- VirtIODevice *vdev = pv;
- BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
- VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
-
- k->save_extra_state(qbus->parent, f);
-}
-
-static const VMStateInfo vmstate_info_extra_state = {
- .name = "virtqueue_extra_state",
- .get = get_extra_state,
- .put = put_extra_state,
-};
-
-static const VMStateDescription vmstate_virtio_extra_state = {
- .name = "virtio/extra_state",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = &virtio_extra_state_needed,
- .fields = (VMStateField[]) {
- {
- .name = "extra_state",
- .version_id = 0,
- .field_exists = NULL,
- .size = 0,
- .info = &vmstate_info_extra_state,
- .flags = VMS_SINGLE,
- .offset = 0,
- },
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_virtio_device_endian = {
- .name = "virtio/device_endian",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = &virtio_device_endian_needed,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(device_endian, VirtIODevice),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_virtio_64bit_features = {
- .name = "virtio/64bit_features",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = &virtio_64bit_features_needed,
- .fields = (VMStateField[]) {
- VMSTATE_UINT64(guest_features, VirtIODevice),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_virtio = {
- .name = "virtio",
- .version_id = 1,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .fields = (VMStateField[]) {
- VMSTATE_END_OF_LIST()
- },
- .subsections = (const VMStateDescription*[]) {
- &vmstate_virtio_device_endian,
- &vmstate_virtio_64bit_features,
- &vmstate_virtio_virtqueues,
- &vmstate_virtio_ringsize,
- &vmstate_virtio_extra_state,
- NULL
- }
-};
-
-void virtio_save(VirtIODevice *vdev, QEMUFile *f)
-{
- BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
- VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
- VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
- uint32_t guest_features_lo = (vdev->guest_features & 0xffffffff);
- int i;
-
- if (k->save_config) {
- k->save_config(qbus->parent, f);
- }
-
- qemu_put_8s(f, &vdev->status);
- qemu_put_8s(f, &vdev->isr);
- qemu_put_be16s(f, &vdev->queue_sel);
- qemu_put_be32s(f, &guest_features_lo);
- qemu_put_be32(f, vdev->config_len);
- qemu_put_buffer(f, vdev->config, vdev->config_len);
-
- for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
- if (vdev->vq[i].vring.num == 0)
- break;
- }
-
- qemu_put_be32(f, i);
-
- for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
- if (vdev->vq[i].vring.num == 0)
- break;
-
- qemu_put_be32(f, vdev->vq[i].vring.num);
- if (k->has_variable_vring_alignment) {
- qemu_put_be32(f, vdev->vq[i].vring.align);
- }
- /* XXX virtio-1 devices */
- qemu_put_be64(f, vdev->vq[i].vring.desc);
- qemu_put_be16s(f, &vdev->vq[i].last_avail_idx);
- if (k->save_queue) {
- k->save_queue(qbus->parent, i, f);
- }
- }
-
- if (vdc->save != NULL) {
- vdc->save(vdev, f);
- }
-
- /* Subsections */
- vmstate_save_state(f, &vmstate_virtio, vdev, NULL);
-}
-
-static int virtio_set_features_nocheck(VirtIODevice *vdev, uint64_t val)
-{
- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
- bool bad = (val & ~(vdev->host_features)) != 0;
-
- val &= vdev->host_features;
- if (k->set_features) {
- k->set_features(vdev, val);
- }
- vdev->guest_features = val;
- return bad ? -1 : 0;
-}
-
-int virtio_set_features(VirtIODevice *vdev, uint64_t val)
-{
- /*
- * The driver must not attempt to set features after feature negotiation
- * has finished.
- */
- if (vdev->status & VIRTIO_CONFIG_S_FEATURES_OK) {
- return -EINVAL;
- }
- return virtio_set_features_nocheck(vdev, val);
-}
-
-int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
-{
- int i, ret;
- int32_t config_len;
- uint32_t num;
- uint32_t features;
- BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
- VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
- VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
-
- /*
- * We poison the endianness to ensure it does not get used before
- * subsections have been loaded.
- */
- vdev->device_endian = VIRTIO_DEVICE_ENDIAN_UNKNOWN;
-
- if (k->load_config) {
- ret = k->load_config(qbus->parent, f);
- if (ret)
- return ret;
- }
-
- qemu_get_8s(f, &vdev->status);
- qemu_get_8s(f, &vdev->isr);
- qemu_get_be16s(f, &vdev->queue_sel);
- if (vdev->queue_sel >= VIRTIO_QUEUE_MAX) {
- return -1;
- }
- qemu_get_be32s(f, &features);
-
- config_len = qemu_get_be32(f);
-
- /*
- * There are cases where the incoming config can be bigger or smaller
- * than what we have; so load what we have space for, and skip
- * any excess that's in the stream.
- */
- qemu_get_buffer(f, vdev->config, MIN(config_len, vdev->config_len));
-
- while (config_len > vdev->config_len) {
- qemu_get_byte(f);
- config_len--;
- }
-
- num = qemu_get_be32(f);
-
- if (num > VIRTIO_QUEUE_MAX) {
- error_report("Invalid number of virtqueues: 0x%x", num);
- return -1;
- }
-
- for (i = 0; i < num; i++) {
- vdev->vq[i].vring.num = qemu_get_be32(f);
- if (k->has_variable_vring_alignment) {
- vdev->vq[i].vring.align = qemu_get_be32(f);
- }
- vdev->vq[i].vring.desc = qemu_get_be64(f);
- qemu_get_be16s(f, &vdev->vq[i].last_avail_idx);
- vdev->vq[i].signalled_used_valid = false;
- vdev->vq[i].notification = true;
-
- if (vdev->vq[i].vring.desc) {
- /* XXX virtio-1 devices */
- virtio_queue_update_rings(vdev, i);
- } else if (vdev->vq[i].last_avail_idx) {
- error_report("VQ %d address 0x0 "
- "inconsistent with Host index 0x%x",
- i, vdev->vq[i].last_avail_idx);
- return -1;
- }
- if (k->load_queue) {
- ret = k->load_queue(qbus->parent, i, f);
- if (ret)
- return ret;
- }
- }
-
- virtio_notify_vector(vdev, VIRTIO_NO_VECTOR);
-
- if (vdc->load != NULL) {
- ret = vdc->load(vdev, f, version_id);
- if (ret) {
- return ret;
- }
- }
-
- /* Subsections */
- ret = vmstate_load_state(f, &vmstate_virtio, vdev, 1);
- if (ret) {
- return ret;
- }
-
- if (vdev->device_endian == VIRTIO_DEVICE_ENDIAN_UNKNOWN) {
- vdev->device_endian = virtio_default_endian();
- }
-
- if (virtio_64bit_features_needed(vdev)) {
- /*
- * Subsection load filled vdev->guest_features. Run them
- * through virtio_set_features to sanity-check them against
- * host_features.
- */
- uint64_t features64 = vdev->guest_features;
- if (virtio_set_features_nocheck(vdev, features64) < 0) {
- error_report("Features 0x%" PRIx64 " unsupported. "
- "Allowed features: 0x%" PRIx64,
- features64, vdev->host_features);
- return -1;
- }
- } else {
- if (virtio_set_features_nocheck(vdev, features) < 0) {
- error_report("Features 0x%x unsupported. "
- "Allowed features: 0x%" PRIx64,
- features, vdev->host_features);
- return -1;
- }
- }
-
- for (i = 0; i < num; i++) {
- if (vdev->vq[i].vring.desc) {
- uint16_t nheads;
- nheads = vring_avail_idx(&vdev->vq[i]) - vdev->vq[i].last_avail_idx;
- /* Check it isn't doing strange things with descriptor numbers. */
- if (nheads > vdev->vq[i].vring.num) {
- error_report("VQ %d size 0x%x Guest index 0x%x "
- "inconsistent with Host index 0x%x: delta 0x%x",
- i, vdev->vq[i].vring.num,
- vring_avail_idx(&vdev->vq[i]),
- vdev->vq[i].last_avail_idx, nheads);
- return -1;
- }
- vdev->vq[i].used_idx = vring_used_idx(&vdev->vq[i]);
- vdev->vq[i].shadow_avail_idx = vring_avail_idx(&vdev->vq[i]);
- }
- }
-
- return 0;
-}
-
-void virtio_cleanup(VirtIODevice *vdev)
-{
- qemu_del_vm_change_state_handler(vdev->vmstate);
- g_free(vdev->config);
- g_free(vdev->vq);
- g_free(vdev->vector_queues);
-}
-
-static void virtio_vmstate_change(void *opaque, int running, RunState state)
-{
- VirtIODevice *vdev = opaque;
- BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
- VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
- bool backend_run = running && (vdev->status & VIRTIO_CONFIG_S_DRIVER_OK);
- vdev->vm_running = running;
-
- if (backend_run) {
- virtio_set_status(vdev, vdev->status);
- }
-
- if (k->vmstate_change) {
- k->vmstate_change(qbus->parent, backend_run);
- }
-
- if (!backend_run) {
- virtio_set_status(vdev, vdev->status);
- }
-}
-
-void virtio_instance_init_common(Object *proxy_obj, void *data,
- size_t vdev_size, const char *vdev_name)
-{
- DeviceState *vdev = data;
-
- object_initialize(vdev, vdev_size, vdev_name);
- object_property_add_child(proxy_obj, "virtio-backend", OBJECT(vdev), NULL);
- object_unref(OBJECT(vdev));
- qdev_alias_all_properties(vdev, proxy_obj);
-}
-
-void virtio_init(VirtIODevice *vdev, const char *name,
- uint16_t device_id, size_t config_size)
-{
- BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
- VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
- int i;
- int nvectors = k->query_nvectors ? k->query_nvectors(qbus->parent) : 0;
-
- if (nvectors) {
- vdev->vector_queues =
- g_malloc0(sizeof(*vdev->vector_queues) * nvectors);
- }
-
- vdev->device_id = device_id;
- vdev->status = 0;
- vdev->isr = 0;
- vdev->queue_sel = 0;
- vdev->config_vector = VIRTIO_NO_VECTOR;
- vdev->vq = g_malloc0(sizeof(VirtQueue) * VIRTIO_QUEUE_MAX);
- vdev->vm_running = runstate_is_running();
- for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
- vdev->vq[i].vector = VIRTIO_NO_VECTOR;
- vdev->vq[i].vdev = vdev;
- vdev->vq[i].queue_index = i;
- }
-
- vdev->name = name;
- vdev->config_len = config_size;
- if (vdev->config_len) {
- vdev->config = g_malloc0(config_size);
- } else {
- vdev->config = NULL;
- }
- vdev->vmstate = qemu_add_vm_change_state_handler(virtio_vmstate_change,
- vdev);
- vdev->device_endian = virtio_default_endian();
- vdev->use_guest_notifier_mask = true;
-}
-
-hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n)
-{
- return vdev->vq[n].vring.desc;
-}
-
-hwaddr virtio_queue_get_avail_addr(VirtIODevice *vdev, int n)
-{
- return vdev->vq[n].vring.avail;
-}
-
-hwaddr virtio_queue_get_used_addr(VirtIODevice *vdev, int n)
-{
- return vdev->vq[n].vring.used;
-}
-
-hwaddr virtio_queue_get_ring_addr(VirtIODevice *vdev, int n)
-{
- return vdev->vq[n].vring.desc;
-}
-
-hwaddr virtio_queue_get_desc_size(VirtIODevice *vdev, int n)
-{
- return sizeof(VRingDesc) * vdev->vq[n].vring.num;
-}
-
-hwaddr virtio_queue_get_avail_size(VirtIODevice *vdev, int n)
-{
- return offsetof(VRingAvail, ring) +
- sizeof(uint16_t) * vdev->vq[n].vring.num;
-}
-
-hwaddr virtio_queue_get_used_size(VirtIODevice *vdev, int n)
-{
- return offsetof(VRingUsed, ring) +
- sizeof(VRingUsedElem) * vdev->vq[n].vring.num;
-}
-
-hwaddr virtio_queue_get_ring_size(VirtIODevice *vdev, int n)
-{
- return vdev->vq[n].vring.used - vdev->vq[n].vring.desc +
- virtio_queue_get_used_size(vdev, n);
-}
-
-uint16_t virtio_queue_get_last_avail_idx(VirtIODevice *vdev, int n)
-{
- return vdev->vq[n].last_avail_idx;
-}
-
-void virtio_queue_set_last_avail_idx(VirtIODevice *vdev, int n, uint16_t idx)
-{
- vdev->vq[n].last_avail_idx = idx;
- vdev->vq[n].shadow_avail_idx = idx;
-}
-
-void virtio_queue_invalidate_signalled_used(VirtIODevice *vdev, int n)
-{
- vdev->vq[n].signalled_used_valid = false;
-}
-
-VirtQueue *virtio_get_queue(VirtIODevice *vdev, int n)
-{
- return vdev->vq + n;
-}
-
-uint16_t virtio_get_queue_index(VirtQueue *vq)
-{
- return vq->queue_index;
-}
-
-static void virtio_queue_guest_notifier_read(EventNotifier *n)
-{
- VirtQueue *vq = container_of(n, VirtQueue, guest_notifier);
- if (event_notifier_test_and_clear(n)) {
- virtio_irq(vq);
- }
-}
-
-void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign,
- bool with_irqfd)
-{
- if (assign && !with_irqfd) {
- event_notifier_set_handler(&vq->guest_notifier, false,
- virtio_queue_guest_notifier_read);
- } else {
- event_notifier_set_handler(&vq->guest_notifier, false, NULL);
- }
- if (!assign) {
- /* Test and clear notifier before closing it,
- * in case poll callback didn't have time to run. */
- virtio_queue_guest_notifier_read(&vq->guest_notifier);
- }
-}
-
-EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq)
-{
- return &vq->guest_notifier;
-}
-
-static void virtio_queue_host_notifier_aio_read(EventNotifier *n)
-{
- VirtQueue *vq = container_of(n, VirtQueue, host_notifier);
- if (event_notifier_test_and_clear(n)) {
- virtio_queue_notify_aio_vq(vq);
- }
-}
-
-void virtio_queue_aio_set_host_notifier_handler(VirtQueue *vq, AioContext *ctx,
- void (*handle_output)(VirtIODevice *,
- VirtQueue *))
-{
- if (handle_output) {
- vq->handle_aio_output = handle_output;
- aio_set_event_notifier(ctx, &vq->host_notifier, true,
- virtio_queue_host_notifier_aio_read);
- } else {
- aio_set_event_notifier(ctx, &vq->host_notifier, true, NULL);
- /* Test and clear notifier before after disabling event,
- * in case poll callback didn't have time to run. */
- virtio_queue_host_notifier_aio_read(&vq->host_notifier);
- vq->handle_aio_output = NULL;
- }
-}
-
-static void virtio_queue_host_notifier_read(EventNotifier *n)
-{
- VirtQueue *vq = container_of(n, VirtQueue, host_notifier);
- if (event_notifier_test_and_clear(n)) {
- virtio_queue_notify_vq(vq);
- }
-}
-
-void virtio_queue_set_host_notifier_fd_handler(VirtQueue *vq, bool assign,
- bool set_handler)
-{
- if (assign && set_handler) {
- event_notifier_set_handler(&vq->host_notifier, true,
- virtio_queue_host_notifier_read);
- } else {
- event_notifier_set_handler(&vq->host_notifier, true, NULL);
- }
- if (!assign) {
- /* Test and clear notifier before after disabling event,
- * in case poll callback didn't have time to run. */
- virtio_queue_host_notifier_read(&vq->host_notifier);
- }
-}
-
-EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq)
-{
- return &vq->host_notifier;
-}
-
-void virtio_device_set_child_bus_name(VirtIODevice *vdev, char *bus_name)
-{
- g_free(vdev->bus_name);
- vdev->bus_name = g_strdup(bus_name);
-}
-
-static void virtio_device_realize(DeviceState *dev, Error **errp)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
- VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(dev);
- Error *err = NULL;
-
- if (vdc->realize != NULL) {
- vdc->realize(dev, &err);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
- }
-
- virtio_bus_device_plugged(vdev, &err);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
-}
-
-static void virtio_device_unrealize(DeviceState *dev, Error **errp)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
- VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(dev);
- Error *err = NULL;
-
- virtio_bus_device_unplugged(vdev);
-
- if (vdc->unrealize != NULL) {
- vdc->unrealize(dev, &err);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
- }
-
- g_free(vdev->bus_name);
- vdev->bus_name = NULL;
-}
-
-static Property virtio_properties[] = {
- DEFINE_VIRTIO_COMMON_FEATURES(VirtIODevice, host_features),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_device_class_init(ObjectClass *klass, void *data)
-{
- /* Set the default value here. */
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = virtio_device_realize;
- dc->unrealize = virtio_device_unrealize;
- dc->bus_type = TYPE_VIRTIO_BUS;
- dc->props = virtio_properties;
-}
-
-static const TypeInfo virtio_device_info = {
- .name = TYPE_VIRTIO_DEVICE,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(VirtIODevice),
- .class_init = virtio_device_class_init,
- .abstract = true,
- .class_size = sizeof(VirtioDeviceClass),
-};
-
-static void virtio_register_types(void)
-{
- type_register_static(&virtio_device_info);
-}
-
-type_init(virtio_register_types)
diff --git a/qemu/hw/watchdog/Makefile.objs b/qemu/hw/watchdog/Makefile.objs
deleted file mode 100644
index 72e3ffd93..000000000
--- a/qemu/hw/watchdog/Makefile.objs
+++ /dev/null
@@ -1,4 +0,0 @@
-common-obj-y += watchdog.o
-common-obj-$(CONFIG_WDT_IB6300ESB) += wdt_i6300esb.o
-common-obj-$(CONFIG_WDT_IB700) += wdt_ib700.o
-common-obj-$(CONFIG_WDT_DIAG288) += wdt_diag288.o
diff --git a/qemu/hw/watchdog/watchdog.c b/qemu/hw/watchdog/watchdog.c
deleted file mode 100644
index bbf3646ba..000000000
--- a/qemu/hw/watchdog/watchdog.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Virtual hardware watchdog.
- *
- * Copyright (C) 2009 Red Hat Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- * By Richard W.M. Jones (rjones@redhat.com).
- */
-
-#include "qemu/osdep.h"
-#include "qemu/option.h"
-#include "qemu/config-file.h"
-#include "qemu/queue.h"
-#include "qapi/qmp/types.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/watchdog.h"
-#include "qapi-event.h"
-#include "hw/nmi.h"
-#include "qemu/help_option.h"
-
-static int watchdog_action = WDT_RESET;
-static QLIST_HEAD(watchdog_list, WatchdogTimerModel) watchdog_list;
-
-void watchdog_add_model(WatchdogTimerModel *model)
-{
- QLIST_INSERT_HEAD(&watchdog_list, model, entry);
-}
-
-/* Returns:
- * 0 = continue
- * 1 = exit program with error
- * 2 = exit program without error
- */
-int select_watchdog(const char *p)
-{
- WatchdogTimerModel *model;
- QemuOpts *opts;
-
- /* -watchdog ? lists available devices and exits cleanly. */
- if (is_help_option(p)) {
- QLIST_FOREACH(model, &watchdog_list, entry) {
- fprintf(stderr, "\t%s\t%s\n",
- model->wdt_name, model->wdt_description);
- }
- return 2;
- }
-
- QLIST_FOREACH(model, &watchdog_list, entry) {
- if (strcasecmp(model->wdt_name, p) == 0) {
- /* add the device */
- opts = qemu_opts_create(qemu_find_opts("device"), NULL, 0,
- &error_abort);
- qemu_opt_set(opts, "driver", p, &error_abort);
- return 0;
- }
- }
-
- fprintf(stderr, "Unknown -watchdog device. Supported devices are:\n");
- QLIST_FOREACH(model, &watchdog_list, entry) {
- fprintf(stderr, "\t%s\t%s\n",
- model->wdt_name, model->wdt_description);
- }
- return 1;
-}
-
-int select_watchdog_action(const char *p)
-{
- if (strcasecmp(p, "reset") == 0)
- watchdog_action = WDT_RESET;
- else if (strcasecmp(p, "shutdown") == 0)
- watchdog_action = WDT_SHUTDOWN;
- else if (strcasecmp(p, "poweroff") == 0)
- watchdog_action = WDT_POWEROFF;
- else if (strcasecmp(p, "pause") == 0)
- watchdog_action = WDT_PAUSE;
- else if (strcasecmp(p, "debug") == 0)
- watchdog_action = WDT_DEBUG;
- else if (strcasecmp(p, "none") == 0)
- watchdog_action = WDT_NONE;
- else if (strcasecmp(p, "inject-nmi") == 0)
- watchdog_action = WDT_NMI;
- else
- return -1;
-
- return 0;
-}
-
-int get_watchdog_action(void)
-{
- return watchdog_action;
-}
-
-/* This actually performs the "action" once a watchdog has expired,
- * ie. reboot, shutdown, exit, etc.
- */
-void watchdog_perform_action(void)
-{
- switch (watchdog_action) {
- case WDT_RESET: /* same as 'system_reset' in monitor */
- qapi_event_send_watchdog(WATCHDOG_EXPIRATION_ACTION_RESET, &error_abort);
- qemu_system_reset_request();
- break;
-
- case WDT_SHUTDOWN: /* same as 'system_powerdown' in monitor */
- qapi_event_send_watchdog(WATCHDOG_EXPIRATION_ACTION_SHUTDOWN, &error_abort);
- qemu_system_powerdown_request();
- break;
-
- case WDT_POWEROFF: /* same as 'quit' command in monitor */
- qapi_event_send_watchdog(WATCHDOG_EXPIRATION_ACTION_POWEROFF, &error_abort);
- exit(0);
-
- case WDT_PAUSE: /* same as 'stop' command in monitor */
- /* In a timer callback, when vm_stop calls qemu_clock_enable
- * you would get a deadlock. Bypass the problem.
- */
- qemu_system_vmstop_request_prepare();
- qapi_event_send_watchdog(WATCHDOG_EXPIRATION_ACTION_PAUSE, &error_abort);
- qemu_system_vmstop_request(RUN_STATE_WATCHDOG);
- break;
-
- case WDT_DEBUG:
- qapi_event_send_watchdog(WATCHDOG_EXPIRATION_ACTION_DEBUG, &error_abort);
- fprintf(stderr, "watchdog: timer fired\n");
- break;
-
- case WDT_NONE:
- qapi_event_send_watchdog(WATCHDOG_EXPIRATION_ACTION_NONE, &error_abort);
- break;
-
- case WDT_NMI:
- qapi_event_send_watchdog(WATCHDOG_EXPIRATION_ACTION_INJECT_NMI,
- &error_abort);
- inject_nmi();
- break;
- }
-}
diff --git a/qemu/hw/watchdog/wdt_diag288.c b/qemu/hw/watchdog/wdt_diag288.c
deleted file mode 100644
index f54a35a0e..000000000
--- a/qemu/hw/watchdog/wdt_diag288.c
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * watchdog device diag288 support
- *
- * Copyright IBM, Corp. 2015
- *
- * Authors:
- * Xu Wang <gesaint@linux.vnet.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or (at your
- * option) any later version. See the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "sysemu/watchdog.h"
-#include "hw/sysbus.h"
-#include "qemu/timer.h"
-#include "hw/watchdog/wdt_diag288.h"
-
-static WatchdogTimerModel model = {
- .wdt_name = TYPE_WDT_DIAG288,
- .wdt_description = "diag288 device for s390x platform",
-};
-
-static const VMStateDescription vmstate_diag288 = {
- .name = "vmstate_diag288",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_TIMER_PTR(timer, DIAG288State),
- VMSTATE_BOOL(enabled, DIAG288State),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void wdt_diag288_reset(DeviceState *dev)
-{
- DIAG288State *diag288 = DIAG288(dev);
-
- diag288->enabled = false;
- timer_del(diag288->timer);
-}
-
-static void diag288_reset(void *opaque)
-{
- DeviceState *diag288 = opaque;
-
- wdt_diag288_reset(diag288);
-}
-
-static void diag288_timer_expired(void *dev)
-{
- qemu_log_mask(CPU_LOG_RESET, "Watchdog timer expired.\n");
- /* Reset the watchdog only if the guest gets notified about
- * expiry. watchdog_perform_action() may temporarily relinquish
- * the BQL; reset before triggering the action to avoid races with
- * diag288 instructions. */
- switch (get_watchdog_action()) {
- case WDT_DEBUG:
- case WDT_NONE:
- case WDT_PAUSE:
- break;
- default:
- wdt_diag288_reset(dev);
- }
- watchdog_perform_action();
-}
-
-static int wdt_diag288_handle_timer(DIAG288State *diag288,
- uint64_t func, uint64_t timeout)
-{
- switch (func) {
- case WDT_DIAG288_INIT:
- diag288->enabled = true;
- /* fall through */
- case WDT_DIAG288_CHANGE:
- if (!diag288->enabled) {
- return -1;
- }
- timer_mod(diag288->timer,
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- timeout * NANOSECONDS_PER_SECOND);
- break;
- case WDT_DIAG288_CANCEL:
- if (!diag288->enabled) {
- return -1;
- }
- diag288->enabled = false;
- timer_del(diag288->timer);
- break;
- default:
- return -1;
- }
-
- return 0;
-}
-
-static void wdt_diag288_realize(DeviceState *dev, Error **errp)
-{
- DIAG288State *diag288 = DIAG288(dev);
-
- qemu_register_reset(diag288_reset, diag288);
- diag288->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, diag288_timer_expired,
- dev);
-}
-
-static void wdt_diag288_unrealize(DeviceState *dev, Error **errp)
-{
- DIAG288State *diag288 = DIAG288(dev);
-
- timer_del(diag288->timer);
- timer_free(diag288->timer);
-}
-
-static void wdt_diag288_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- DIAG288Class *diag288 = DIAG288_CLASS(klass);
-
- dc->realize = wdt_diag288_realize;
- dc->unrealize = wdt_diag288_unrealize;
- dc->reset = wdt_diag288_reset;
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- dc->vmsd = &vmstate_diag288;
- diag288->handle_timer = wdt_diag288_handle_timer;
-}
-
-static const TypeInfo wdt_diag288_info = {
- .class_init = wdt_diag288_class_init,
- .parent = TYPE_DEVICE,
- .name = TYPE_WDT_DIAG288,
- .instance_size = sizeof(DIAG288State),
- .class_size = sizeof(DIAG288Class),
-};
-
-static void wdt_diag288_register_types(void)
-{
- watchdog_add_model(&model);
- type_register_static(&wdt_diag288_info);
-}
-
-type_init(wdt_diag288_register_types)
diff --git a/qemu/hw/watchdog/wdt_i6300esb.c b/qemu/hw/watchdog/wdt_i6300esb.c
deleted file mode 100644
index a83d95121..000000000
--- a/qemu/hw/watchdog/wdt_i6300esb.c
+++ /dev/null
@@ -1,465 +0,0 @@
-/*
- * Virtual hardware watchdog.
- *
- * Copyright (C) 2009 Red Hat Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- * By Richard W.M. Jones (rjones@redhat.com).
- */
-
-#include "qemu/osdep.h"
-
-#include "qemu-common.h"
-#include "qemu/timer.h"
-#include "sysemu/watchdog.h"
-#include "hw/hw.h"
-#include "hw/pci/pci.h"
-
-/*#define I6300ESB_DEBUG 1*/
-
-#ifdef I6300ESB_DEBUG
-#define i6300esb_debug(fs,...) \
- fprintf(stderr,"i6300esb: %s: "fs,__func__,##__VA_ARGS__)
-#else
-#define i6300esb_debug(fs,...)
-#endif
-
-/* PCI configuration registers */
-#define ESB_CONFIG_REG 0x60 /* Config register */
-#define ESB_LOCK_REG 0x68 /* WDT lock register */
-
-/* Memory mapped registers (offset from base address) */
-#define ESB_TIMER1_REG 0x00 /* Timer1 value after each reset */
-#define ESB_TIMER2_REG 0x04 /* Timer2 value after each reset */
-#define ESB_GINTSR_REG 0x08 /* General Interrupt Status Register */
-#define ESB_RELOAD_REG 0x0c /* Reload register */
-
-/* Lock register bits */
-#define ESB_WDT_FUNC (0x01 << 2) /* Watchdog functionality */
-#define ESB_WDT_ENABLE (0x01 << 1) /* Enable WDT */
-#define ESB_WDT_LOCK (0x01 << 0) /* Lock (nowayout) */
-
-/* Config register bits */
-#define ESB_WDT_REBOOT (0x01 << 5) /* Enable reboot on timeout */
-#define ESB_WDT_FREQ (0x01 << 2) /* Decrement frequency */
-#define ESB_WDT_INTTYPE (0x11 << 0) /* Interrupt type on timer1 timeout */
-
-/* Reload register bits */
-#define ESB_WDT_RELOAD (0x01 << 8) /* prevent timeout */
-
-/* Magic constants */
-#define ESB_UNLOCK1 0x80 /* Step 1 to unlock reset registers */
-#define ESB_UNLOCK2 0x86 /* Step 2 to unlock reset registers */
-
-/* Device state. */
-struct I6300State {
- PCIDevice dev;
- MemoryRegion io_mem;
-
- int reboot_enabled; /* "Reboot" on timer expiry. The real action
- * performed depends on the -watchdog-action
- * param passed on QEMU command line.
- */
- int clock_scale; /* Clock scale. */
-#define CLOCK_SCALE_1KHZ 0
-#define CLOCK_SCALE_1MHZ 1
-
- int int_type; /* Interrupt type generated. */
-#define INT_TYPE_IRQ 0 /* APIC 1, INT 10 */
-#define INT_TYPE_SMI 2
-#define INT_TYPE_DISABLED 3
-
- int free_run; /* If true, reload timer on expiry. */
- int locked; /* If true, enabled field cannot be changed. */
- int enabled; /* If true, watchdog is enabled. */
-
- QEMUTimer *timer; /* The actual watchdog timer. */
-
- uint32_t timer1_preload; /* Values preloaded into timer1, timer2. */
- uint32_t timer2_preload;
- int stage; /* Stage (1 or 2). */
-
- int unlock_state; /* Guest writes 0x80, 0x86 to unlock the
- * registers, and we transition through
- * states 0 -> 1 -> 2 when this happens.
- */
-
- int previous_reboot_flag; /* If the watchdog caused the previous
- * reboot, this flag will be set.
- */
-};
-
-typedef struct I6300State I6300State;
-
-#define TYPE_WATCHDOG_I6300ESB_DEVICE "i6300esb"
-#define WATCHDOG_I6300ESB_DEVICE(obj) \
- OBJECT_CHECK(I6300State, (obj), TYPE_WATCHDOG_I6300ESB_DEVICE)
-
-/* This function is called when the watchdog has either been enabled
- * (hence it starts counting down) or has been keep-alived.
- */
-static void i6300esb_restart_timer(I6300State *d, int stage)
-{
- int64_t timeout;
-
- if (!d->enabled)
- return;
-
- d->stage = stage;
-
- if (d->stage <= 1)
- timeout = d->timer1_preload;
- else
- timeout = d->timer2_preload;
-
- if (d->clock_scale == CLOCK_SCALE_1KHZ)
- timeout <<= 15;
- else
- timeout <<= 5;
-
- /* Get the timeout in nanoseconds. */
-
- timeout = timeout * 30; /* on a PCI bus, 1 tick is 30 ns*/
-
- i6300esb_debug("stage %d, timeout %" PRIi64 "\n", d->stage, timeout);
-
- timer_mod(d->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + timeout);
-}
-
-/* This is called when the guest disables the watchdog. */
-static void i6300esb_disable_timer(I6300State *d)
-{
- i6300esb_debug("timer disabled\n");
-
- timer_del(d->timer);
-}
-
-static void i6300esb_reset(DeviceState *dev)
-{
- PCIDevice *pdev = PCI_DEVICE(dev);
- I6300State *d = WATCHDOG_I6300ESB_DEVICE(pdev);
-
- i6300esb_debug("I6300State = %p\n", d);
-
- i6300esb_disable_timer(d);
-
- /* NB: Don't change d->previous_reboot_flag in this function. */
-
- d->reboot_enabled = 1;
- d->clock_scale = CLOCK_SCALE_1KHZ;
- d->int_type = INT_TYPE_IRQ;
- d->free_run = 0;
- d->locked = 0;
- d->enabled = 0;
- d->timer1_preload = 0xfffff;
- d->timer2_preload = 0xfffff;
- d->stage = 1;
- d->unlock_state = 0;
-}
-
-/* This function is called when the watchdog expires. Note that
- * the hardware has two timers, and so expiry happens in two stages.
- * If d->stage == 1 then we perform the first stage action (usually,
- * sending an interrupt) and then restart the timer again for the
- * second stage. If the second stage expires then the watchdog
- * really has run out.
- */
-static void i6300esb_timer_expired(void *vp)
-{
- I6300State *d = vp;
-
- i6300esb_debug("stage %d\n", d->stage);
-
- if (d->stage == 1) {
- /* What to do at the end of stage 1? */
- switch (d->int_type) {
- case INT_TYPE_IRQ:
- fprintf(stderr, "i6300esb_timer_expired: I would send APIC 1 INT 10 here if I knew how (XXX)\n");
- break;
- case INT_TYPE_SMI:
- fprintf(stderr, "i6300esb_timer_expired: I would send SMI here if I knew how (XXX)\n");
- break;
- }
-
- /* Start the second stage. */
- i6300esb_restart_timer(d, 2);
- } else {
- /* Second stage expired, reboot for real. */
- if (d->reboot_enabled) {
- d->previous_reboot_flag = 1;
- watchdog_perform_action(); /* This reboots, exits, etc */
- i6300esb_reset(&d->dev.qdev);
- }
-
- /* In "free running mode" we start stage 1 again. */
- if (d->free_run)
- i6300esb_restart_timer(d, 1);
- }
-}
-
-static void i6300esb_config_write(PCIDevice *dev, uint32_t addr,
- uint32_t data, int len)
-{
- I6300State *d = WATCHDOG_I6300ESB_DEVICE(dev);
- int old;
-
- i6300esb_debug("addr = %x, data = %x, len = %d\n", addr, data, len);
-
- if (addr == ESB_CONFIG_REG && len == 2) {
- d->reboot_enabled = (data & ESB_WDT_REBOOT) == 0;
- d->clock_scale =
- (data & ESB_WDT_FREQ) != 0 ? CLOCK_SCALE_1MHZ : CLOCK_SCALE_1KHZ;
- d->int_type = (data & ESB_WDT_INTTYPE);
- } else if (addr == ESB_LOCK_REG && len == 1) {
- if (!d->locked) {
- d->locked = (data & ESB_WDT_LOCK) != 0;
- d->free_run = (data & ESB_WDT_FUNC) != 0;
- old = d->enabled;
- d->enabled = (data & ESB_WDT_ENABLE) != 0;
- if (!old && d->enabled) /* Enabled transitioned from 0 -> 1 */
- i6300esb_restart_timer(d, 1);
- else if (!d->enabled)
- i6300esb_disable_timer(d);
- }
- } else {
- pci_default_write_config(dev, addr, data, len);
- }
-}
-
-static uint32_t i6300esb_config_read(PCIDevice *dev, uint32_t addr, int len)
-{
- I6300State *d = WATCHDOG_I6300ESB_DEVICE(dev);
- uint32_t data;
-
- i6300esb_debug ("addr = %x, len = %d\n", addr, len);
-
- if (addr == ESB_CONFIG_REG && len == 2) {
- data =
- (d->reboot_enabled ? 0 : ESB_WDT_REBOOT) |
- (d->clock_scale == CLOCK_SCALE_1MHZ ? ESB_WDT_FREQ : 0) |
- d->int_type;
- return data;
- } else if (addr == ESB_LOCK_REG && len == 1) {
- data =
- (d->free_run ? ESB_WDT_FUNC : 0) |
- (d->locked ? ESB_WDT_LOCK : 0) |
- (d->enabled ? ESB_WDT_ENABLE : 0);
- return data;
- } else {
- return pci_default_read_config(dev, addr, len);
- }
-}
-
-static uint32_t i6300esb_mem_readb(void *vp, hwaddr addr)
-{
- i6300esb_debug ("addr = %x\n", (int) addr);
-
- return 0;
-}
-
-static uint32_t i6300esb_mem_readw(void *vp, hwaddr addr)
-{
- uint32_t data = 0;
- I6300State *d = vp;
-
- i6300esb_debug("addr = %x\n", (int) addr);
-
- if (addr == 0xc) {
- /* The previous reboot flag is really bit 9, but there is
- * a bug in the Linux driver where it thinks it's bit 12.
- * Set both.
- */
- data = d->previous_reboot_flag ? 0x1200 : 0;
- }
-
- return data;
-}
-
-static uint32_t i6300esb_mem_readl(void *vp, hwaddr addr)
-{
- i6300esb_debug("addr = %x\n", (int) addr);
-
- return 0;
-}
-
-static void i6300esb_mem_writeb(void *vp, hwaddr addr, uint32_t val)
-{
- I6300State *d = vp;
-
- i6300esb_debug("addr = %x, val = %x\n", (int) addr, val);
-
- if (addr == 0xc && val == 0x80)
- d->unlock_state = 1;
- else if (addr == 0xc && val == 0x86 && d->unlock_state == 1)
- d->unlock_state = 2;
-}
-
-static void i6300esb_mem_writew(void *vp, hwaddr addr, uint32_t val)
-{
- I6300State *d = vp;
-
- i6300esb_debug("addr = %x, val = %x\n", (int) addr, val);
-
- if (addr == 0xc && val == 0x80)
- d->unlock_state = 1;
- else if (addr == 0xc && val == 0x86 && d->unlock_state == 1)
- d->unlock_state = 2;
- else {
- if (d->unlock_state == 2) {
- if (addr == 0xc) {
- if ((val & 0x100) != 0)
- /* This is the "ping" from the userspace watchdog in
- * the guest ...
- */
- i6300esb_restart_timer(d, 1);
-
- /* Setting bit 9 resets the previous reboot flag.
- * There's a bug in the Linux driver where it sets
- * bit 12 instead.
- */
- if ((val & 0x200) != 0 || (val & 0x1000) != 0) {
- d->previous_reboot_flag = 0;
- }
- }
-
- d->unlock_state = 0;
- }
- }
-}
-
-static void i6300esb_mem_writel(void *vp, hwaddr addr, uint32_t val)
-{
- I6300State *d = vp;
-
- i6300esb_debug ("addr = %x, val = %x\n", (int) addr, val);
-
- if (addr == 0xc && val == 0x80)
- d->unlock_state = 1;
- else if (addr == 0xc && val == 0x86 && d->unlock_state == 1)
- d->unlock_state = 2;
- else {
- if (d->unlock_state == 2) {
- if (addr == 0)
- d->timer1_preload = val & 0xfffff;
- else if (addr == 4)
- d->timer2_preload = val & 0xfffff;
-
- d->unlock_state = 0;
- }
- }
-}
-
-static const MemoryRegionOps i6300esb_ops = {
- .old_mmio = {
- .read = {
- i6300esb_mem_readb,
- i6300esb_mem_readw,
- i6300esb_mem_readl,
- },
- .write = {
- i6300esb_mem_writeb,
- i6300esb_mem_writew,
- i6300esb_mem_writel,
- },
- },
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_i6300esb = {
- .name = "i6300esb_wdt",
- /* With this VMSD's introduction, version_id/minimum_version_id were
- * erroneously set to sizeof(I6300State), causing a somewhat random
- * version_id to be set for every build. This eventually broke
- * migration.
- *
- * To correct this without breaking old->new migration for older
- * versions of QEMU, we've set version_id to a value high enough
- * to exceed all past values of sizeof(I6300State) across various
- * build environments, and have reset minimum_version_id to 1,
- * since this VMSD has never changed and thus can accept all past
- * versions.
- *
- * For future changes we can treat these values as we normally would.
- */
- .version_id = 10000,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(dev, I6300State),
- VMSTATE_INT32(reboot_enabled, I6300State),
- VMSTATE_INT32(clock_scale, I6300State),
- VMSTATE_INT32(int_type, I6300State),
- VMSTATE_INT32(free_run, I6300State),
- VMSTATE_INT32(locked, I6300State),
- VMSTATE_INT32(enabled, I6300State),
- VMSTATE_TIMER_PTR(timer, I6300State),
- VMSTATE_UINT32(timer1_preload, I6300State),
- VMSTATE_UINT32(timer2_preload, I6300State),
- VMSTATE_INT32(stage, I6300State),
- VMSTATE_INT32(unlock_state, I6300State),
- VMSTATE_INT32(previous_reboot_flag, I6300State),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void i6300esb_realize(PCIDevice *dev, Error **errp)
-{
- I6300State *d = WATCHDOG_I6300ESB_DEVICE(dev);
-
- i6300esb_debug("I6300State = %p\n", d);
-
- d->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, i6300esb_timer_expired, d);
- d->previous_reboot_flag = 0;
-
- memory_region_init_io(&d->io_mem, OBJECT(d), &i6300esb_ops, d,
- "i6300esb", 0x10);
- pci_register_bar(&d->dev, 0, 0, &d->io_mem);
- /* qemu_register_coalesced_mmio (addr, 0x10); ? */
-}
-
-static WatchdogTimerModel model = {
- .wdt_name = "i6300esb",
- .wdt_description = "Intel 6300ESB",
-};
-
-static void i6300esb_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->config_read = i6300esb_config_read;
- k->config_write = i6300esb_config_write;
- k->realize = i6300esb_realize;
- k->vendor_id = PCI_VENDOR_ID_INTEL;
- k->device_id = PCI_DEVICE_ID_INTEL_ESB_9;
- k->class_id = PCI_CLASS_SYSTEM_OTHER;
- dc->reset = i6300esb_reset;
- dc->vmsd = &vmstate_i6300esb;
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
-}
-
-static const TypeInfo i6300esb_info = {
- .name = TYPE_WATCHDOG_I6300ESB_DEVICE,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(I6300State),
- .class_init = i6300esb_class_init,
-};
-
-static void i6300esb_register_types(void)
-{
- watchdog_add_model(&model);
- type_register_static(&i6300esb_info);
-}
-
-type_init(i6300esb_register_types)
diff --git a/qemu/hw/watchdog/wdt_ib700.c b/qemu/hw/watchdog/wdt_ib700.c
deleted file mode 100644
index 532afe89e..000000000
--- a/qemu/hw/watchdog/wdt_ib700.c
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Virtual hardware watchdog.
- *
- * Copyright (C) 2009 Red Hat Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- * By Richard W.M. Jones (rjones@redhat.com).
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "qemu/timer.h"
-#include "sysemu/watchdog.h"
-#include "hw/hw.h"
-#include "hw/isa/isa.h"
-#include "hw/i386/pc.h"
-
-/*#define IB700_DEBUG 1*/
-
-#ifdef IB700_DEBUG
-#define ib700_debug(fs,...) \
- fprintf(stderr,"ib700: %s: "fs,__func__,##__VA_ARGS__)
-#else
-#define ib700_debug(fs,...)
-#endif
-
-#define TYPE_IB700 "ib700"
-#define IB700(obj) OBJECT_CHECK(IB700State, (obj), TYPE_IB700)
-
-typedef struct IB700state {
- ISADevice parent_obj;
-
- QEMUTimer *timer;
-
- PortioList port_list;
-} IB700State;
-
-/* This is the timer. We use a global here because the watchdog
- * code ensures there is only one watchdog (it is located at a fixed,
- * unchangeable IO port, so there could only ever be one anyway).
- */
-
-/* A write to this register enables the timer. */
-static void ib700_write_enable_reg(void *vp, uint32_t addr, uint32_t data)
-{
- IB700State *s = vp;
- static int time_map[] = {
- 30, 28, 26, 24, 22, 20, 18, 16,
- 14, 12, 10, 8, 6, 4, 2, 0
- };
- int64_t timeout;
-
- ib700_debug("addr = %x, data = %x\n", addr, data);
-
- timeout = (int64_t) time_map[data & 0xF] * NANOSECONDS_PER_SECOND;
- timer_mod(s->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + timeout);
-}
-
-/* A write (of any value) to this register disables the timer. */
-static void ib700_write_disable_reg(void *vp, uint32_t addr, uint32_t data)
-{
- IB700State *s = vp;
-
- ib700_debug("addr = %x, data = %x\n", addr, data);
-
- timer_del(s->timer);
-}
-
-/* This is called when the watchdog expires. */
-static void ib700_timer_expired(void *vp)
-{
- IB700State *s = vp;
-
- ib700_debug("watchdog expired\n");
-
- watchdog_perform_action();
- timer_del(s->timer);
-}
-
-static const VMStateDescription vmstate_ib700 = {
- .name = "ib700_wdt",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_TIMER_PTR(timer, IB700State),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const MemoryRegionPortio wdt_portio_list[] = {
- { 0x441, 2, 1, .write = ib700_write_disable_reg, },
- { 0x443, 2, 1, .write = ib700_write_enable_reg, },
- PORTIO_END_OF_LIST(),
-};
-
-static void wdt_ib700_realize(DeviceState *dev, Error **errp)
-{
- IB700State *s = IB700(dev);
-
- ib700_debug("watchdog init\n");
-
- s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ib700_timer_expired, s);
-
- portio_list_init(&s->port_list, OBJECT(s), wdt_portio_list, s, "ib700");
- portio_list_add(&s->port_list, isa_address_space_io(&s->parent_obj), 0);
-}
-
-static void wdt_ib700_reset(DeviceState *dev)
-{
- IB700State *s = IB700(dev);
-
- ib700_debug("watchdog reset\n");
-
- timer_del(s->timer);
-}
-
-static WatchdogTimerModel model = {
- .wdt_name = "ib700",
- .wdt_description = "iBASE 700",
-};
-
-static void wdt_ib700_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = wdt_ib700_realize;
- dc->reset = wdt_ib700_reset;
- dc->vmsd = &vmstate_ib700;
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
-}
-
-static const TypeInfo wdt_ib700_info = {
- .name = TYPE_IB700,
- .parent = TYPE_ISA_DEVICE,
- .instance_size = sizeof(IB700State),
- .class_init = wdt_ib700_class_init,
-};
-
-static void wdt_ib700_register_types(void)
-{
- watchdog_add_model(&model);
- type_register_static(&wdt_ib700_info);
-}
-
-type_init(wdt_ib700_register_types)
diff --git a/qemu/hw/xen/Makefile.objs b/qemu/hw/xen/Makefile.objs
deleted file mode 100644
index d3670940b..000000000
--- a/qemu/hw/xen/Makefile.objs
+++ /dev/null
@@ -1,5 +0,0 @@
-# xen backend driver support
-common-obj-$(CONFIG_XEN_BACKEND) += xen_backend.o xen_devconfig.o
-
-obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o
-obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_graphics.o xen_pt_msi.o
diff --git a/qemu/hw/xen/xen-host-pci-device.c b/qemu/hw/xen/xen-host-pci-device.c
deleted file mode 100644
index eed8cc88e..000000000
--- a/qemu/hw/xen/xen-host-pci-device.c
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- * Copyright (C) 2011 Citrix Ltd.
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "qemu/cutils.h"
-#include "xen-host-pci-device.h"
-
-#define XEN_HOST_PCI_MAX_EXT_CAP \
- ((PCIE_CONFIG_SPACE_SIZE - PCI_CONFIG_SPACE_SIZE) / (PCI_CAP_SIZEOF + 4))
-
-#ifdef XEN_HOST_PCI_DEVICE_DEBUG
-# define XEN_HOST_PCI_LOG(f, a...) fprintf(stderr, "%s: " f, __func__, ##a)
-#else
-# define XEN_HOST_PCI_LOG(f, a...) (void)0
-#endif
-
-/*
- * from linux/ioport.h
- * IO resources have these defined flags.
- */
-#define IORESOURCE_BITS 0x000000ff /* Bus-specific bits */
-
-#define IORESOURCE_TYPE_BITS 0x00000f00 /* Resource type */
-#define IORESOURCE_IO 0x00000100
-#define IORESOURCE_MEM 0x00000200
-
-#define IORESOURCE_PREFETCH 0x00001000 /* No side effects */
-#define IORESOURCE_MEM_64 0x00100000
-
-static void xen_host_pci_sysfs_path(const XenHostPCIDevice *d,
- const char *name, char *buf, ssize_t size)
-{
- int rc;
-
- rc = snprintf(buf, size, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/%s",
- d->domain, d->bus, d->dev, d->func, name);
- assert(rc >= 0 && rc < size);
-}
-
-
-/* This size should be enough to read the first 7 lines of a resource file */
-#define XEN_HOST_PCI_RESOURCE_BUFFER_SIZE 400
-static void xen_host_pci_get_resource(XenHostPCIDevice *d, Error **errp)
-{
- int i, rc, fd;
- char path[PATH_MAX];
- char buf[XEN_HOST_PCI_RESOURCE_BUFFER_SIZE];
- unsigned long long start, end, flags, size;
- char *endptr, *s;
- uint8_t type;
-
- xen_host_pci_sysfs_path(d, "resource", path, sizeof(path));
-
- fd = open(path, O_RDONLY);
- if (fd == -1) {
- error_setg_file_open(errp, errno, path);
- return;
- }
-
- do {
- rc = read(fd, &buf, sizeof(buf) - 1);
- if (rc < 0 && errno != EINTR) {
- error_setg_errno(errp, errno, "read err");
- goto out;
- }
- } while (rc < 0);
- buf[rc] = 0;
-
- s = buf;
- for (i = 0; i < PCI_NUM_REGIONS; i++) {
- type = 0;
-
- start = strtoll(s, &endptr, 16);
- if (*endptr != ' ' || s == endptr) {
- break;
- }
- s = endptr + 1;
- end = strtoll(s, &endptr, 16);
- if (*endptr != ' ' || s == endptr) {
- break;
- }
- s = endptr + 1;
- flags = strtoll(s, &endptr, 16);
- if (*endptr != '\n' || s == endptr) {
- break;
- }
- s = endptr + 1;
-
- if (start) {
- size = end - start + 1;
- } else {
- size = 0;
- }
-
- if (flags & IORESOURCE_IO) {
- type |= XEN_HOST_PCI_REGION_TYPE_IO;
- }
- if (flags & IORESOURCE_MEM) {
- type |= XEN_HOST_PCI_REGION_TYPE_MEM;
- }
- if (flags & IORESOURCE_PREFETCH) {
- type |= XEN_HOST_PCI_REGION_TYPE_PREFETCH;
- }
- if (flags & IORESOURCE_MEM_64) {
- type |= XEN_HOST_PCI_REGION_TYPE_MEM_64;
- }
-
- if (i < PCI_ROM_SLOT) {
- d->io_regions[i].base_addr = start;
- d->io_regions[i].size = size;
- d->io_regions[i].type = type;
- d->io_regions[i].bus_flags = flags & IORESOURCE_BITS;
- } else {
- d->rom.base_addr = start;
- d->rom.size = size;
- d->rom.type = type;
- d->rom.bus_flags = flags & IORESOURCE_BITS;
- }
- }
-
- if (i != PCI_NUM_REGIONS) {
- error_setg(errp, "Invalid format or input too short: %s", buf);
- }
-
-out:
- close(fd);
-}
-
-/* This size should be enough to read a long from a file */
-#define XEN_HOST_PCI_GET_VALUE_BUFFER_SIZE 22
-static void xen_host_pci_get_value(XenHostPCIDevice *d, const char *name,
- unsigned int *pvalue, int base, Error **errp)
-{
- char path[PATH_MAX];
- char buf[XEN_HOST_PCI_GET_VALUE_BUFFER_SIZE];
- int fd, rc;
- unsigned long value;
- const char *endptr;
-
- xen_host_pci_sysfs_path(d, name, path, sizeof(path));
-
- fd = open(path, O_RDONLY);
- if (fd == -1) {
- error_setg_file_open(errp, errno, path);
- return;
- }
-
- do {
- rc = read(fd, &buf, sizeof(buf) - 1);
- if (rc < 0 && errno != EINTR) {
- error_setg_errno(errp, errno, "read err");
- goto out;
- }
- } while (rc < 0);
-
- buf[rc] = 0;
- rc = qemu_strtoul(buf, &endptr, base, &value);
- if (!rc) {
- assert(value <= UINT_MAX);
- *pvalue = value;
- } else {
- error_setg_errno(errp, -rc, "failed to parse value '%s'", buf);
- }
-
-out:
- close(fd);
-}
-
-static inline void xen_host_pci_get_hex_value(XenHostPCIDevice *d,
- const char *name,
- unsigned int *pvalue,
- Error **errp)
-{
- xen_host_pci_get_value(d, name, pvalue, 16, errp);
-}
-
-static inline void xen_host_pci_get_dec_value(XenHostPCIDevice *d,
- const char *name,
- unsigned int *pvalue,
- Error **errp)
-{
- xen_host_pci_get_value(d, name, pvalue, 10, errp);
-}
-
-static bool xen_host_pci_dev_is_virtfn(XenHostPCIDevice *d)
-{
- char path[PATH_MAX];
- struct stat buf;
-
- xen_host_pci_sysfs_path(d, "physfn", path, sizeof(path));
-
- return !stat(path, &buf);
-}
-
-static void xen_host_pci_config_open(XenHostPCIDevice *d, Error **errp)
-{
- char path[PATH_MAX];
-
- xen_host_pci_sysfs_path(d, "config", path, sizeof(path));
-
- d->config_fd = open(path, O_RDWR);
- if (d->config_fd == -1) {
- error_setg_file_open(errp, errno, path);
- }
-}
-
-static int xen_host_pci_config_read(XenHostPCIDevice *d,
- int pos, void *buf, int len)
-{
- int rc;
-
- do {
- rc = pread(d->config_fd, buf, len, pos);
- } while (rc < 0 && (errno == EINTR || errno == EAGAIN));
- if (rc != len) {
- return -errno;
- }
- return 0;
-}
-
-static int xen_host_pci_config_write(XenHostPCIDevice *d,
- int pos, const void *buf, int len)
-{
- int rc;
-
- do {
- rc = pwrite(d->config_fd, buf, len, pos);
- } while (rc < 0 && (errno == EINTR || errno == EAGAIN));
- if (rc != len) {
- return -errno;
- }
- return 0;
-}
-
-
-int xen_host_pci_get_byte(XenHostPCIDevice *d, int pos, uint8_t *p)
-{
- uint8_t buf;
- int rc = xen_host_pci_config_read(d, pos, &buf, 1);
- if (!rc) {
- *p = buf;
- }
- return rc;
-}
-
-int xen_host_pci_get_word(XenHostPCIDevice *d, int pos, uint16_t *p)
-{
- uint16_t buf;
- int rc = xen_host_pci_config_read(d, pos, &buf, 2);
- if (!rc) {
- *p = le16_to_cpu(buf);
- }
- return rc;
-}
-
-int xen_host_pci_get_long(XenHostPCIDevice *d, int pos, uint32_t *p)
-{
- uint32_t buf;
- int rc = xen_host_pci_config_read(d, pos, &buf, 4);
- if (!rc) {
- *p = le32_to_cpu(buf);
- }
- return rc;
-}
-
-int xen_host_pci_get_block(XenHostPCIDevice *d, int pos, uint8_t *buf, int len)
-{
- return xen_host_pci_config_read(d, pos, buf, len);
-}
-
-int xen_host_pci_set_byte(XenHostPCIDevice *d, int pos, uint8_t data)
-{
- return xen_host_pci_config_write(d, pos, &data, 1);
-}
-
-int xen_host_pci_set_word(XenHostPCIDevice *d, int pos, uint16_t data)
-{
- data = cpu_to_le16(data);
- return xen_host_pci_config_write(d, pos, &data, 2);
-}
-
-int xen_host_pci_set_long(XenHostPCIDevice *d, int pos, uint32_t data)
-{
- data = cpu_to_le32(data);
- return xen_host_pci_config_write(d, pos, &data, 4);
-}
-
-int xen_host_pci_set_block(XenHostPCIDevice *d, int pos, uint8_t *buf, int len)
-{
- return xen_host_pci_config_write(d, pos, buf, len);
-}
-
-int xen_host_pci_find_ext_cap_offset(XenHostPCIDevice *d, uint32_t cap)
-{
- uint32_t header = 0;
- int max_cap = XEN_HOST_PCI_MAX_EXT_CAP;
- int pos = PCI_CONFIG_SPACE_SIZE;
-
- do {
- if (xen_host_pci_get_long(d, pos, &header)) {
- break;
- }
- /*
- * If we have no capabilities, this is indicated by cap ID,
- * cap version and next pointer all being 0.
- */
- if (header == 0) {
- break;
- }
-
- if (PCI_EXT_CAP_ID(header) == cap) {
- return pos;
- }
-
- pos = PCI_EXT_CAP_NEXT(header);
- if (pos < PCI_CONFIG_SPACE_SIZE) {
- break;
- }
-
- max_cap--;
- } while (max_cap > 0);
-
- return -1;
-}
-
-void xen_host_pci_device_get(XenHostPCIDevice *d, uint16_t domain,
- uint8_t bus, uint8_t dev, uint8_t func,
- Error **errp)
-{
- unsigned int v;
- Error *err = NULL;
-
- d->config_fd = -1;
- d->domain = domain;
- d->bus = bus;
- d->dev = dev;
- d->func = func;
-
- xen_host_pci_config_open(d, &err);
- if (err) {
- goto error;
- }
-
- xen_host_pci_get_resource(d, &err);
- if (err) {
- goto error;
- }
-
- xen_host_pci_get_hex_value(d, "vendor", &v, &err);
- if (err) {
- goto error;
- }
- d->vendor_id = v;
-
- xen_host_pci_get_hex_value(d, "device", &v, &err);
- if (err) {
- goto error;
- }
- d->device_id = v;
-
- xen_host_pci_get_dec_value(d, "irq", &v, &err);
- if (err) {
- goto error;
- }
- d->irq = v;
-
- xen_host_pci_get_hex_value(d, "class", &v, &err);
- if (err) {
- goto error;
- }
- d->class_code = v;
-
- d->is_virtfn = xen_host_pci_dev_is_virtfn(d);
-
- return;
-
-error:
- error_propagate(errp, err);
-
- if (d->config_fd >= 0) {
- close(d->config_fd);
- d->config_fd = -1;
- }
-}
-
-bool xen_host_pci_device_closed(XenHostPCIDevice *d)
-{
- return d->config_fd == -1;
-}
-
-void xen_host_pci_device_put(XenHostPCIDevice *d)
-{
- if (d->config_fd >= 0) {
- close(d->config_fd);
- d->config_fd = -1;
- }
-}
diff --git a/qemu/hw/xen/xen-host-pci-device.h b/qemu/hw/xen/xen-host-pci-device.h
deleted file mode 100644
index 6acf36e13..000000000
--- a/qemu/hw/xen/xen-host-pci-device.h
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef XEN_HOST_PCI_DEVICE_H
-#define XEN_HOST_PCI_DEVICE_H
-
-#include "hw/pci/pci.h"
-
-enum {
- XEN_HOST_PCI_REGION_TYPE_IO = 1 << 1,
- XEN_HOST_PCI_REGION_TYPE_MEM = 1 << 2,
- XEN_HOST_PCI_REGION_TYPE_PREFETCH = 1 << 3,
- XEN_HOST_PCI_REGION_TYPE_MEM_64 = 1 << 4,
-};
-
-typedef struct XenHostPCIIORegion {
- pcibus_t base_addr;
- pcibus_t size;
- uint8_t type;
- uint8_t bus_flags; /* Bus-specific bits */
-} XenHostPCIIORegion;
-
-typedef struct XenHostPCIDevice {
- uint16_t domain;
- uint8_t bus;
- uint8_t dev;
- uint8_t func;
-
- uint16_t vendor_id;
- uint16_t device_id;
- uint32_t class_code;
- int irq;
-
- XenHostPCIIORegion io_regions[PCI_NUM_REGIONS - 1];
- XenHostPCIIORegion rom;
-
- bool is_virtfn;
-
- int config_fd;
-} XenHostPCIDevice;
-
-void xen_host_pci_device_get(XenHostPCIDevice *d, uint16_t domain,
- uint8_t bus, uint8_t dev, uint8_t func,
- Error **errp);
-void xen_host_pci_device_put(XenHostPCIDevice *pci_dev);
-bool xen_host_pci_device_closed(XenHostPCIDevice *d);
-
-int xen_host_pci_get_byte(XenHostPCIDevice *d, int pos, uint8_t *p);
-int xen_host_pci_get_word(XenHostPCIDevice *d, int pos, uint16_t *p);
-int xen_host_pci_get_long(XenHostPCIDevice *d, int pos, uint32_t *p);
-int xen_host_pci_get_block(XenHostPCIDevice *d, int pos, uint8_t *buf,
- int len);
-int xen_host_pci_set_byte(XenHostPCIDevice *d, int pos, uint8_t data);
-int xen_host_pci_set_word(XenHostPCIDevice *d, int pos, uint16_t data);
-int xen_host_pci_set_long(XenHostPCIDevice *d, int pos, uint32_t data);
-int xen_host_pci_set_block(XenHostPCIDevice *d, int pos, uint8_t *buf,
- int len);
-
-int xen_host_pci_find_ext_cap_offset(XenHostPCIDevice *s, uint32_t cap);
-
-#endif /* !XEN_HOST_PCI_DEVICE_H_ */
diff --git a/qemu/hw/xen/xen_backend.c b/qemu/hw/xen/xen_backend.c
deleted file mode 100644
index 60575ad38..000000000
--- a/qemu/hw/xen/xen_backend.c
+++ /dev/null
@@ -1,802 +0,0 @@
-/*
- * xen backend driver infrastructure
- * (c) 2008 Gerd Hoffmann <kraxel@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; under version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-/*
- * TODO: add some xenbus / xenstore concepts overview here.
- */
-
-#include "qemu/osdep.h"
-#include <sys/mman.h>
-#include <sys/signal.h>
-
-#include "hw/hw.h"
-#include "sysemu/char.h"
-#include "qemu/log.h"
-#include "hw/xen/xen_backend.h"
-
-#include <xen/grant_table.h>
-
-/* ------------------------------------------------------------- */
-
-/* public */
-xc_interface *xen_xc = NULL;
-xenforeignmemory_handle *xen_fmem = NULL;
-struct xs_handle *xenstore = NULL;
-const char *xen_protocol;
-
-/* private */
-static QTAILQ_HEAD(XenDeviceHead, XenDevice) xendevs = QTAILQ_HEAD_INITIALIZER(xendevs);
-static int debug = 0;
-
-/* ------------------------------------------------------------- */
-
-int xenstore_write_str(const char *base, const char *node, const char *val)
-{
- char abspath[XEN_BUFSIZE];
-
- snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
- if (!xs_write(xenstore, 0, abspath, val, strlen(val))) {
- return -1;
- }
- return 0;
-}
-
-char *xenstore_read_str(const char *base, const char *node)
-{
- char abspath[XEN_BUFSIZE];
- unsigned int len;
- char *str, *ret = NULL;
-
- snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
- str = xs_read(xenstore, 0, abspath, &len);
- if (str != NULL) {
- /* move to qemu-allocated memory to make sure
- * callers can savely g_free() stuff. */
- ret = g_strdup(str);
- free(str);
- }
- return ret;
-}
-
-int xenstore_write_int(const char *base, const char *node, int ival)
-{
- char val[12];
-
- snprintf(val, sizeof(val), "%d", ival);
- return xenstore_write_str(base, node, val);
-}
-
-int xenstore_write_int64(const char *base, const char *node, int64_t ival)
-{
- char val[21];
-
- snprintf(val, sizeof(val), "%"PRId64, ival);
- return xenstore_write_str(base, node, val);
-}
-
-int xenstore_read_int(const char *base, const char *node, int *ival)
-{
- char *val;
- int rc = -1;
-
- val = xenstore_read_str(base, node);
- if (val && 1 == sscanf(val, "%d", ival)) {
- rc = 0;
- }
- g_free(val);
- return rc;
-}
-
-int xenstore_read_uint64(const char *base, const char *node, uint64_t *uval)
-{
- char *val;
- int rc = -1;
-
- val = xenstore_read_str(base, node);
- if (val && 1 == sscanf(val, "%"SCNu64, uval)) {
- rc = 0;
- }
- g_free(val);
- return rc;
-}
-
-int xenstore_write_be_str(struct XenDevice *xendev, const char *node, const char *val)
-{
- return xenstore_write_str(xendev->be, node, val);
-}
-
-int xenstore_write_be_int(struct XenDevice *xendev, const char *node, int ival)
-{
- return xenstore_write_int(xendev->be, node, ival);
-}
-
-int xenstore_write_be_int64(struct XenDevice *xendev, const char *node, int64_t ival)
-{
- return xenstore_write_int64(xendev->be, node, ival);
-}
-
-char *xenstore_read_be_str(struct XenDevice *xendev, const char *node)
-{
- return xenstore_read_str(xendev->be, node);
-}
-
-int xenstore_read_be_int(struct XenDevice *xendev, const char *node, int *ival)
-{
- return xenstore_read_int(xendev->be, node, ival);
-}
-
-char *xenstore_read_fe_str(struct XenDevice *xendev, const char *node)
-{
- return xenstore_read_str(xendev->fe, node);
-}
-
-int xenstore_read_fe_int(struct XenDevice *xendev, const char *node, int *ival)
-{
- return xenstore_read_int(xendev->fe, node, ival);
-}
-
-int xenstore_read_fe_uint64(struct XenDevice *xendev, const char *node, uint64_t *uval)
-{
- return xenstore_read_uint64(xendev->fe, node, uval);
-}
-
-/* ------------------------------------------------------------- */
-
-const char *xenbus_strstate(enum xenbus_state state)
-{
- static const char *const name[] = {
- [ XenbusStateUnknown ] = "Unknown",
- [ XenbusStateInitialising ] = "Initialising",
- [ XenbusStateInitWait ] = "InitWait",
- [ XenbusStateInitialised ] = "Initialised",
- [ XenbusStateConnected ] = "Connected",
- [ XenbusStateClosing ] = "Closing",
- [ XenbusStateClosed ] = "Closed",
- };
- return (state < ARRAY_SIZE(name)) ? name[state] : "INVALID";
-}
-
-int xen_be_set_state(struct XenDevice *xendev, enum xenbus_state state)
-{
- int rc;
-
- rc = xenstore_write_be_int(xendev, "state", state);
- if (rc < 0) {
- return rc;
- }
- xen_be_printf(xendev, 1, "backend state: %s -> %s\n",
- xenbus_strstate(xendev->be_state), xenbus_strstate(state));
- xendev->be_state = state;
- return 0;
-}
-
-/* ------------------------------------------------------------- */
-
-struct XenDevice *xen_be_find_xendev(const char *type, int dom, int dev)
-{
- struct XenDevice *xendev;
-
- QTAILQ_FOREACH(xendev, &xendevs, next) {
- if (xendev->dom != dom) {
- continue;
- }
- if (xendev->dev != dev) {
- continue;
- }
- if (strcmp(xendev->type, type) != 0) {
- continue;
- }
- return xendev;
- }
- return NULL;
-}
-
-/*
- * get xen backend device, allocate a new one if it doesn't exist.
- */
-static struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
- struct XenDevOps *ops)
-{
- struct XenDevice *xendev;
-
- xendev = xen_be_find_xendev(type, dom, dev);
- if (xendev) {
- return xendev;
- }
-
- /* init new xendev */
- xendev = g_malloc0(ops->size);
- xendev->type = type;
- xendev->dom = dom;
- xendev->dev = dev;
- xendev->ops = ops;
-
- snprintf(xendev->be, sizeof(xendev->be), "backend/%s/%d/%d",
- xendev->type, xendev->dom, xendev->dev);
- snprintf(xendev->name, sizeof(xendev->name), "%s-%d",
- xendev->type, xendev->dev);
-
- xendev->debug = debug;
- xendev->local_port = -1;
-
- xendev->evtchndev = xenevtchn_open(NULL, 0);
- if (xendev->evtchndev == NULL) {
- xen_be_printf(NULL, 0, "can't open evtchn device\n");
- g_free(xendev);
- return NULL;
- }
- fcntl(xenevtchn_fd(xendev->evtchndev), F_SETFD, FD_CLOEXEC);
-
- if (ops->flags & DEVOPS_FLAG_NEED_GNTDEV) {
- xendev->gnttabdev = xengnttab_open(NULL, 0);
- if (xendev->gnttabdev == NULL) {
- xen_be_printf(NULL, 0, "can't open gnttab device\n");
- xenevtchn_close(xendev->evtchndev);
- g_free(xendev);
- return NULL;
- }
- } else {
- xendev->gnttabdev = NULL;
- }
-
- QTAILQ_INSERT_TAIL(&xendevs, xendev, next);
-
- if (xendev->ops->alloc) {
- xendev->ops->alloc(xendev);
- }
-
- return xendev;
-}
-
-/*
- * release xen backend device.
- */
-static struct XenDevice *xen_be_del_xendev(int dom, int dev)
-{
- struct XenDevice *xendev, *xnext;
-
- /*
- * This is pretty much like QTAILQ_FOREACH(xendev, &xendevs, next) but
- * we save the next pointer in xnext because we might free xendev.
- */
- xnext = xendevs.tqh_first;
- while (xnext) {
- xendev = xnext;
- xnext = xendev->next.tqe_next;
-
- if (xendev->dom != dom) {
- continue;
- }
- if (xendev->dev != dev && dev != -1) {
- continue;
- }
-
- if (xendev->ops->free) {
- xendev->ops->free(xendev);
- }
-
- if (xendev->fe) {
- char token[XEN_BUFSIZE];
- snprintf(token, sizeof(token), "fe:%p", xendev);
- xs_unwatch(xenstore, xendev->fe, token);
- g_free(xendev->fe);
- }
-
- if (xendev->evtchndev != NULL) {
- xenevtchn_close(xendev->evtchndev);
- }
- if (xendev->gnttabdev != NULL) {
- xengnttab_close(xendev->gnttabdev);
- }
-
- QTAILQ_REMOVE(&xendevs, xendev, next);
- g_free(xendev);
- }
- return NULL;
-}
-
-/*
- * Sync internal data structures on xenstore updates.
- * Node specifies the changed field. node = NULL means
- * update all fields (used for initialization).
- */
-static void xen_be_backend_changed(struct XenDevice *xendev, const char *node)
-{
- if (node == NULL || strcmp(node, "online") == 0) {
- if (xenstore_read_be_int(xendev, "online", &xendev->online) == -1) {
- xendev->online = 0;
- }
- }
-
- if (node) {
- xen_be_printf(xendev, 2, "backend update: %s\n", node);
- if (xendev->ops->backend_changed) {
- xendev->ops->backend_changed(xendev, node);
- }
- }
-}
-
-static void xen_be_frontend_changed(struct XenDevice *xendev, const char *node)
-{
- int fe_state;
-
- if (node == NULL || strcmp(node, "state") == 0) {
- if (xenstore_read_fe_int(xendev, "state", &fe_state) == -1) {
- fe_state = XenbusStateUnknown;
- }
- if (xendev->fe_state != fe_state) {
- xen_be_printf(xendev, 1, "frontend state: %s -> %s\n",
- xenbus_strstate(xendev->fe_state),
- xenbus_strstate(fe_state));
- }
- xendev->fe_state = fe_state;
- }
- if (node == NULL || strcmp(node, "protocol") == 0) {
- g_free(xendev->protocol);
- xendev->protocol = xenstore_read_fe_str(xendev, "protocol");
- if (xendev->protocol) {
- xen_be_printf(xendev, 1, "frontend protocol: %s\n", xendev->protocol);
- }
- }
-
- if (node) {
- xen_be_printf(xendev, 2, "frontend update: %s\n", node);
- if (xendev->ops->frontend_changed) {
- xendev->ops->frontend_changed(xendev, node);
- }
- }
-}
-
-/* ------------------------------------------------------------- */
-/* Check for possible state transitions and perform them. */
-
-/*
- * Initial xendev setup. Read frontend path, register watch for it.
- * Should succeed once xend finished setting up the backend device.
- *
- * Also sets initial state (-> Initializing) when done. Which
- * only affects the xendev->be_state variable as xenbus should
- * already be put into that state by xend.
- */
-static int xen_be_try_setup(struct XenDevice *xendev)
-{
- char token[XEN_BUFSIZE];
- int be_state;
-
- if (xenstore_read_be_int(xendev, "state", &be_state) == -1) {
- xen_be_printf(xendev, 0, "reading backend state failed\n");
- return -1;
- }
-
- if (be_state != XenbusStateInitialising) {
- xen_be_printf(xendev, 0, "initial backend state is wrong (%s)\n",
- xenbus_strstate(be_state));
- return -1;
- }
-
- xendev->fe = xenstore_read_be_str(xendev, "frontend");
- if (xendev->fe == NULL) {
- xen_be_printf(xendev, 0, "reading frontend path failed\n");
- return -1;
- }
-
- /* setup frontend watch */
- snprintf(token, sizeof(token), "fe:%p", xendev);
- if (!xs_watch(xenstore, xendev->fe, token)) {
- xen_be_printf(xendev, 0, "watching frontend path (%s) failed\n",
- xendev->fe);
- return -1;
- }
- xen_be_set_state(xendev, XenbusStateInitialising);
-
- xen_be_backend_changed(xendev, NULL);
- xen_be_frontend_changed(xendev, NULL);
- return 0;
-}
-
-/*
- * Try initialize xendev. Prepare everything the backend can do
- * without synchronizing with the frontend. Fakes hotplug-status. No
- * hotplug involved here because this is about userspace drivers, thus
- * there are kernel backend devices which could invoke hotplug.
- *
- * Goes to InitWait on success.
- */
-static int xen_be_try_init(struct XenDevice *xendev)
-{
- int rc = 0;
-
- if (!xendev->online) {
- xen_be_printf(xendev, 1, "not online\n");
- return -1;
- }
-
- if (xendev->ops->init) {
- rc = xendev->ops->init(xendev);
- }
- if (rc != 0) {
- xen_be_printf(xendev, 1, "init() failed\n");
- return rc;
- }
-
- xenstore_write_be_str(xendev, "hotplug-status", "connected");
- xen_be_set_state(xendev, XenbusStateInitWait);
- return 0;
-}
-
-/*
- * Try to initialise xendev. Depends on the frontend being ready
- * for it (shared ring and evtchn info in xenstore, state being
- * Initialised or Connected).
- *
- * Goes to Connected on success.
- */
-static int xen_be_try_initialise(struct XenDevice *xendev)
-{
- int rc = 0;
-
- if (xendev->fe_state != XenbusStateInitialised &&
- xendev->fe_state != XenbusStateConnected) {
- if (xendev->ops->flags & DEVOPS_FLAG_IGNORE_STATE) {
- xen_be_printf(xendev, 2, "frontend not ready, ignoring\n");
- } else {
- xen_be_printf(xendev, 2, "frontend not ready (yet)\n");
- return -1;
- }
- }
-
- if (xendev->ops->initialise) {
- rc = xendev->ops->initialise(xendev);
- }
- if (rc != 0) {
- xen_be_printf(xendev, 0, "initialise() failed\n");
- return rc;
- }
-
- xen_be_set_state(xendev, XenbusStateConnected);
- return 0;
-}
-
-/*
- * Try to let xendev know that it is connected. Depends on the
- * frontend being Connected. Note that this may be called more
- * than once since the backend state is not modified.
- */
-static void xen_be_try_connected(struct XenDevice *xendev)
-{
- if (!xendev->ops->connected) {
- return;
- }
-
- if (xendev->fe_state != XenbusStateConnected) {
- if (xendev->ops->flags & DEVOPS_FLAG_IGNORE_STATE) {
- xen_be_printf(xendev, 2, "frontend not ready, ignoring\n");
- } else {
- xen_be_printf(xendev, 2, "frontend not ready (yet)\n");
- return;
- }
- }
-
- xendev->ops->connected(xendev);
-}
-
-/*
- * Teardown connection.
- *
- * Goes to Closed when done.
- */
-static void xen_be_disconnect(struct XenDevice *xendev, enum xenbus_state state)
-{
- if (xendev->be_state != XenbusStateClosing &&
- xendev->be_state != XenbusStateClosed &&
- xendev->ops->disconnect) {
- xendev->ops->disconnect(xendev);
- }
- if (xendev->be_state != state) {
- xen_be_set_state(xendev, state);
- }
-}
-
-/*
- * Try to reset xendev, for reconnection by another frontend instance.
- */
-static int xen_be_try_reset(struct XenDevice *xendev)
-{
- if (xendev->fe_state != XenbusStateInitialising) {
- return -1;
- }
-
- xen_be_printf(xendev, 1, "device reset (for re-connect)\n");
- xen_be_set_state(xendev, XenbusStateInitialising);
- return 0;
-}
-
-/*
- * state change dispatcher function
- */
-void xen_be_check_state(struct XenDevice *xendev)
-{
- int rc = 0;
-
- /* frontend may request shutdown from almost anywhere */
- if (xendev->fe_state == XenbusStateClosing ||
- xendev->fe_state == XenbusStateClosed) {
- xen_be_disconnect(xendev, xendev->fe_state);
- return;
- }
-
- /* check for possible backend state transitions */
- for (;;) {
- switch (xendev->be_state) {
- case XenbusStateUnknown:
- rc = xen_be_try_setup(xendev);
- break;
- case XenbusStateInitialising:
- rc = xen_be_try_init(xendev);
- break;
- case XenbusStateInitWait:
- rc = xen_be_try_initialise(xendev);
- break;
- case XenbusStateConnected:
- /* xendev->be_state doesn't change */
- xen_be_try_connected(xendev);
- rc = -1;
- break;
- case XenbusStateClosed:
- rc = xen_be_try_reset(xendev);
- break;
- default:
- rc = -1;
- }
- if (rc != 0) {
- break;
- }
- }
-}
-
-/* ------------------------------------------------------------- */
-
-static int xenstore_scan(const char *type, int dom, struct XenDevOps *ops)
-{
- struct XenDevice *xendev;
- char path[XEN_BUFSIZE], token[XEN_BUFSIZE];
- char **dev = NULL;
- unsigned int cdev, j;
-
- /* setup watch */
- snprintf(token, sizeof(token), "be:%p:%d:%p", type, dom, ops);
- snprintf(path, sizeof(path), "backend/%s/%d", type, dom);
- if (!xs_watch(xenstore, path, token)) {
- xen_be_printf(NULL, 0, "xen be: watching backend path (%s) failed\n", path);
- return -1;
- }
-
- /* look for backends */
- dev = xs_directory(xenstore, 0, path, &cdev);
- if (!dev) {
- return 0;
- }
- for (j = 0; j < cdev; j++) {
- xendev = xen_be_get_xendev(type, dom, atoi(dev[j]), ops);
- if (xendev == NULL) {
- continue;
- }
- xen_be_check_state(xendev);
- }
- free(dev);
- return 0;
-}
-
-static void xenstore_update_be(char *watch, char *type, int dom,
- struct XenDevOps *ops)
-{
- struct XenDevice *xendev;
- char path[XEN_BUFSIZE], *bepath;
- unsigned int len, dev;
-
- len = snprintf(path, sizeof(path), "backend/%s/%d", type, dom);
- if (strncmp(path, watch, len) != 0) {
- return;
- }
- if (sscanf(watch+len, "/%u/%255s", &dev, path) != 2) {
- strcpy(path, "");
- if (sscanf(watch+len, "/%u", &dev) != 1) {
- dev = -1;
- }
- }
- if (dev == -1) {
- return;
- }
-
- xendev = xen_be_get_xendev(type, dom, dev, ops);
- if (xendev != NULL) {
- bepath = xs_read(xenstore, 0, xendev->be, &len);
- if (bepath == NULL) {
- xen_be_del_xendev(dom, dev);
- } else {
- free(bepath);
- xen_be_backend_changed(xendev, path);
- xen_be_check_state(xendev);
- }
- }
-}
-
-static void xenstore_update_fe(char *watch, struct XenDevice *xendev)
-{
- char *node;
- unsigned int len;
-
- len = strlen(xendev->fe);
- if (strncmp(xendev->fe, watch, len) != 0) {
- return;
- }
- if (watch[len] != '/') {
- return;
- }
- node = watch + len + 1;
-
- xen_be_frontend_changed(xendev, node);
- xen_be_check_state(xendev);
-}
-
-static void xenstore_update(void *unused)
-{
- char **vec = NULL;
- intptr_t type, ops, ptr;
- unsigned int dom, count;
-
- vec = xs_read_watch(xenstore, &count);
- if (vec == NULL) {
- goto cleanup;
- }
-
- if (sscanf(vec[XS_WATCH_TOKEN], "be:%" PRIxPTR ":%d:%" PRIxPTR,
- &type, &dom, &ops) == 3) {
- xenstore_update_be(vec[XS_WATCH_PATH], (void*)type, dom, (void*)ops);
- }
- if (sscanf(vec[XS_WATCH_TOKEN], "fe:%" PRIxPTR, &ptr) == 1) {
- xenstore_update_fe(vec[XS_WATCH_PATH], (void*)ptr);
- }
-
-cleanup:
- free(vec);
-}
-
-static void xen_be_evtchn_event(void *opaque)
-{
- struct XenDevice *xendev = opaque;
- evtchn_port_t port;
-
- port = xenevtchn_pending(xendev->evtchndev);
- if (port != xendev->local_port) {
- xen_be_printf(xendev, 0,
- "xenevtchn_pending returned %d (expected %d)\n",
- port, xendev->local_port);
- return;
- }
- xenevtchn_unmask(xendev->evtchndev, port);
-
- if (xendev->ops->event) {
- xendev->ops->event(xendev);
- }
-}
-
-/* -------------------------------------------------------------------- */
-
-int xen_be_init(void)
-{
- xenstore = xs_daemon_open();
- if (!xenstore) {
- xen_be_printf(NULL, 0, "can't connect to xenstored\n");
- return -1;
- }
-
- qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update, NULL, NULL);
-
- if (xen_xc == NULL || xen_fmem == NULL) {
- /* Check if xen_init() have been called */
- goto err;
- }
- return 0;
-
-err:
- qemu_set_fd_handler(xs_fileno(xenstore), NULL, NULL, NULL);
- xs_daemon_close(xenstore);
- xenstore = NULL;
-
- return -1;
-}
-
-int xen_be_register(const char *type, struct XenDevOps *ops)
-{
- return xenstore_scan(type, xen_domid, ops);
-}
-
-int xen_be_bind_evtchn(struct XenDevice *xendev)
-{
- if (xendev->local_port != -1) {
- return 0;
- }
- xendev->local_port = xenevtchn_bind_interdomain
- (xendev->evtchndev, xendev->dom, xendev->remote_port);
- if (xendev->local_port == -1) {
- xen_be_printf(xendev, 0, "xenevtchn_bind_interdomain failed\n");
- return -1;
- }
- xen_be_printf(xendev, 2, "bind evtchn port %d\n", xendev->local_port);
- qemu_set_fd_handler(xenevtchn_fd(xendev->evtchndev),
- xen_be_evtchn_event, NULL, xendev);
- return 0;
-}
-
-void xen_be_unbind_evtchn(struct XenDevice *xendev)
-{
- if (xendev->local_port == -1) {
- return;
- }
- qemu_set_fd_handler(xenevtchn_fd(xendev->evtchndev), NULL, NULL, NULL);
- xenevtchn_unbind(xendev->evtchndev, xendev->local_port);
- xen_be_printf(xendev, 2, "unbind evtchn port %d\n", xendev->local_port);
- xendev->local_port = -1;
-}
-
-int xen_be_send_notify(struct XenDevice *xendev)
-{
- return xenevtchn_notify(xendev->evtchndev, xendev->local_port);
-}
-
-/*
- * msg_level:
- * 0 == errors (stderr + logfile).
- * 1 == informative debug messages (logfile only).
- * 2 == noisy debug messages (logfile only).
- * 3 == will flood your log (logfile only).
- */
-void xen_be_printf(struct XenDevice *xendev, int msg_level, const char *fmt, ...)
-{
- va_list args;
-
- if (xendev) {
- if (msg_level > xendev->debug) {
- return;
- }
- qemu_log("xen be: %s: ", xendev->name);
- if (msg_level == 0) {
- fprintf(stderr, "xen be: %s: ", xendev->name);
- }
- } else {
- if (msg_level > debug) {
- return;
- }
- qemu_log("xen be core: ");
- if (msg_level == 0) {
- fprintf(stderr, "xen be core: ");
- }
- }
- va_start(args, fmt);
- qemu_log_vprintf(fmt, args);
- va_end(args);
- if (msg_level == 0) {
- va_start(args, fmt);
- vfprintf(stderr, fmt, args);
- va_end(args);
- }
- qemu_log_flush();
-}
diff --git a/qemu/hw/xen/xen_devconfig.c b/qemu/hw/xen/xen_devconfig.c
deleted file mode 100644
index 1f30fe4f5..000000000
--- a/qemu/hw/xen/xen_devconfig.c
+++ /dev/null
@@ -1,176 +0,0 @@
-#include "qemu/osdep.h"
-#include "hw/xen/xen_backend.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
-
-/* ------------------------------------------------------------- */
-
-struct xs_dirs {
- char *xs_dir;
- QTAILQ_ENTRY(xs_dirs) list;
-};
-static QTAILQ_HEAD(xs_dirs_head, xs_dirs) xs_cleanup = QTAILQ_HEAD_INITIALIZER(xs_cleanup);
-
-static void xen_config_cleanup_dir(char *dir)
-{
- struct xs_dirs *d;
-
- d = g_malloc(sizeof(*d));
- d->xs_dir = dir;
- QTAILQ_INSERT_TAIL(&xs_cleanup, d, list);
-}
-
-void xen_config_cleanup(void)
-{
- struct xs_dirs *d;
-
- QTAILQ_FOREACH(d, &xs_cleanup, list) {
- xs_rm(xenstore, 0, d->xs_dir);
- }
-}
-
-/* ------------------------------------------------------------- */
-
-static int xen_config_dev_mkdir(char *dev, int p)
-{
- struct xs_permissions perms[2] = {{
- .id = 0, /* set owner: dom0 */
- },{
- .id = xen_domid,
- .perms = p,
- }};
-
- if (!xs_mkdir(xenstore, 0, dev)) {
- xen_be_printf(NULL, 0, "xs_mkdir %s: failed\n", dev);
- return -1;
- }
- xen_config_cleanup_dir(g_strdup(dev));
-
- if (!xs_set_permissions(xenstore, 0, dev, perms, 2)) {
- xen_be_printf(NULL, 0, "xs_set_permissions %s: failed\n", dev);
- return -1;
- }
- return 0;
-}
-
-static int xen_config_dev_dirs(const char *ftype, const char *btype, int vdev,
- char *fe, char *be, int len)
-{
- char *dom;
-
- dom = xs_get_domain_path(xenstore, xen_domid);
- snprintf(fe, len, "%s/device/%s/%d", dom, ftype, vdev);
- free(dom);
-
- dom = xs_get_domain_path(xenstore, 0);
- snprintf(be, len, "%s/backend/%s/%d/%d", dom, btype, xen_domid, vdev);
- free(dom);
-
- xen_config_dev_mkdir(fe, XS_PERM_READ | XS_PERM_WRITE);
- xen_config_dev_mkdir(be, XS_PERM_READ);
- return 0;
-}
-
-static int xen_config_dev_all(char *fe, char *be)
-{
- /* frontend */
- if (xen_protocol)
- xenstore_write_str(fe, "protocol", xen_protocol);
-
- xenstore_write_int(fe, "state", XenbusStateInitialising);
- xenstore_write_int(fe, "backend-id", 0);
- xenstore_write_str(fe, "backend", be);
-
- /* backend */
- xenstore_write_str(be, "domain", qemu_name ? qemu_name : "no-name");
- xenstore_write_int(be, "online", 1);
- xenstore_write_int(be, "state", XenbusStateInitialising);
- xenstore_write_int(be, "frontend-id", xen_domid);
- xenstore_write_str(be, "frontend", fe);
-
- return 0;
-}
-
-/* ------------------------------------------------------------- */
-
-int xen_config_dev_blk(DriveInfo *disk)
-{
- char fe[256], be[256], device_name[32];
- int vdev = 202 * 256 + 16 * disk->unit;
- int cdrom = disk->media_cd;
- const char *devtype = cdrom ? "cdrom" : "disk";
- const char *mode = cdrom ? "r" : "w";
- const char *filename = qemu_opt_get(disk->opts, "file");
-
- snprintf(device_name, sizeof(device_name), "xvd%c", 'a' + disk->unit);
- xen_be_printf(NULL, 1, "config disk %d [%s]: %s\n",
- disk->unit, device_name, filename);
- xen_config_dev_dirs("vbd", "qdisk", vdev, fe, be, sizeof(fe));
-
- /* frontend */
- xenstore_write_int(fe, "virtual-device", vdev);
- xenstore_write_str(fe, "device-type", devtype);
-
- /* backend */
- xenstore_write_str(be, "dev", device_name);
- xenstore_write_str(be, "type", "file");
- xenstore_write_str(be, "params", filename);
- xenstore_write_str(be, "mode", mode);
-
- /* common stuff */
- return xen_config_dev_all(fe, be);
-}
-
-int xen_config_dev_nic(NICInfo *nic)
-{
- char fe[256], be[256];
- char mac[20];
- int vlan_id = -1;
-
- net_hub_id_for_client(nic->netdev, &vlan_id);
- snprintf(mac, sizeof(mac), "%02x:%02x:%02x:%02x:%02x:%02x",
- nic->macaddr.a[0], nic->macaddr.a[1], nic->macaddr.a[2],
- nic->macaddr.a[3], nic->macaddr.a[4], nic->macaddr.a[5]);
- xen_be_printf(NULL, 1, "config nic %d: mac=\"%s\"\n", vlan_id, mac);
- xen_config_dev_dirs("vif", "qnic", vlan_id, fe, be, sizeof(fe));
-
- /* frontend */
- xenstore_write_int(fe, "handle", vlan_id);
- xenstore_write_str(fe, "mac", mac);
-
- /* backend */
- xenstore_write_int(be, "handle", vlan_id);
- xenstore_write_str(be, "mac", mac);
-
- /* common stuff */
- return xen_config_dev_all(fe, be);
-}
-
-int xen_config_dev_vfb(int vdev, const char *type)
-{
- char fe[256], be[256];
-
- xen_config_dev_dirs("vfb", "vfb", vdev, fe, be, sizeof(fe));
-
- /* backend */
- xenstore_write_str(be, "type", type);
-
- /* common stuff */
- return xen_config_dev_all(fe, be);
-}
-
-int xen_config_dev_vkbd(int vdev)
-{
- char fe[256], be[256];
-
- xen_config_dev_dirs("vkbd", "vkbd", vdev, fe, be, sizeof(fe));
- return xen_config_dev_all(fe, be);
-}
-
-int xen_config_dev_console(int vdev)
-{
- char fe[256], be[256];
-
- xen_config_dev_dirs("console", "console", vdev, fe, be, sizeof(fe));
- return xen_config_dev_all(fe, be);
-}
diff --git a/qemu/hw/xen/xen_pt.c b/qemu/hw/xen/xen_pt.c
deleted file mode 100644
index f593b046e..000000000
--- a/qemu/hw/xen/xen_pt.c
+++ /dev/null
@@ -1,974 +0,0 @@
-/*
- * Copyright (c) 2007, Neocleus Corporation.
- * Copyright (c) 2007, Intel Corporation.
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- * Alex Novik <alex@neocleus.com>
- * Allen Kay <allen.m.kay@intel.com>
- * Guy Zana <guy@neocleus.com>
- *
- * This file implements direct PCI assignment to a HVM guest
- */
-
-/*
- * Interrupt Disable policy:
- *
- * INTx interrupt:
- * Initialize(register_real_device)
- * Map INTx(xc_physdev_map_pirq):
- * <fail>
- * - Set real Interrupt Disable bit to '1'.
- * - Set machine_irq and assigned_device->machine_irq to '0'.
- * * Don't bind INTx.
- *
- * Bind INTx(xc_domain_bind_pt_pci_irq):
- * <fail>
- * - Set real Interrupt Disable bit to '1'.
- * - Unmap INTx.
- * - Decrement xen_pt_mapped_machine_irq[machine_irq]
- * - Set assigned_device->machine_irq to '0'.
- *
- * Write to Interrupt Disable bit by guest software(xen_pt_cmd_reg_write)
- * Write '0'
- * - Set real bit to '0' if assigned_device->machine_irq isn't '0'.
- *
- * Write '1'
- * - Set real bit to '1'.
- *
- * MSI interrupt:
- * Initialize MSI register(xen_pt_msi_setup, xen_pt_msi_update)
- * Bind MSI(xc_domain_update_msi_irq)
- * <fail>
- * - Unmap MSI.
- * - Set dev->msi->pirq to '-1'.
- *
- * MSI-X interrupt:
- * Initialize MSI-X register(xen_pt_msix_update_one)
- * Bind MSI-X(xc_domain_update_msi_irq)
- * <fail>
- * - Unmap MSI-X.
- * - Set entry->pirq to '-1'.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include <sys/ioctl.h>
-
-#include "hw/pci/pci.h"
-#include "hw/xen/xen.h"
-#include "hw/i386/pc.h"
-#include "hw/xen/xen_backend.h"
-#include "xen_pt.h"
-#include "qemu/range.h"
-#include "exec/address-spaces.h"
-
-#define XEN_PT_NR_IRQS (256)
-static uint8_t xen_pt_mapped_machine_irq[XEN_PT_NR_IRQS] = {0};
-
-void xen_pt_log(const PCIDevice *d, const char *f, ...)
-{
- va_list ap;
-
- va_start(ap, f);
- if (d) {
- fprintf(stderr, "[%02x:%02x.%d] ", pci_bus_num(d->bus),
- PCI_SLOT(d->devfn), PCI_FUNC(d->devfn));
- }
- vfprintf(stderr, f, ap);
- va_end(ap);
-}
-
-/* Config Space */
-
-static int xen_pt_pci_config_access_check(PCIDevice *d, uint32_t addr, int len)
-{
- /* check offset range */
- if (addr >= 0xFF) {
- XEN_PT_ERR(d, "Failed to access register with offset exceeding 0xFF. "
- "(addr: 0x%02x, len: %d)\n", addr, len);
- return -1;
- }
-
- /* check read size */
- if ((len != 1) && (len != 2) && (len != 4)) {
- XEN_PT_ERR(d, "Failed to access register with invalid access length. "
- "(addr: 0x%02x, len: %d)\n", addr, len);
- return -1;
- }
-
- /* check offset alignment */
- if (addr & (len - 1)) {
- XEN_PT_ERR(d, "Failed to access register with invalid access size "
- "alignment. (addr: 0x%02x, len: %d)\n", addr, len);
- return -1;
- }
-
- return 0;
-}
-
-int xen_pt_bar_offset_to_index(uint32_t offset)
-{
- int index = 0;
-
- /* check Exp ROM BAR */
- if (offset == PCI_ROM_ADDRESS) {
- return PCI_ROM_SLOT;
- }
-
- /* calculate BAR index */
- index = (offset - PCI_BASE_ADDRESS_0) >> 2;
- if (index >= PCI_NUM_REGIONS) {
- return -1;
- }
-
- return index;
-}
-
-static uint32_t xen_pt_pci_read_config(PCIDevice *d, uint32_t addr, int len)
-{
- XenPCIPassthroughState *s = XEN_PT_DEVICE(d);
- uint32_t val = 0;
- XenPTRegGroup *reg_grp_entry = NULL;
- XenPTReg *reg_entry = NULL;
- int rc = 0;
- int emul_len = 0;
- uint32_t find_addr = addr;
-
- if (xen_pt_pci_config_access_check(d, addr, len)) {
- goto exit;
- }
-
- /* find register group entry */
- reg_grp_entry = xen_pt_find_reg_grp(s, addr);
- if (reg_grp_entry) {
- /* check 0-Hardwired register group */
- if (reg_grp_entry->reg_grp->grp_type == XEN_PT_GRP_TYPE_HARDWIRED) {
- /* no need to emulate, just return 0 */
- val = 0;
- goto exit;
- }
- }
-
- /* read I/O device register value */
- rc = xen_host_pci_get_block(&s->real_device, addr, (uint8_t *)&val, len);
- if (rc < 0) {
- XEN_PT_ERR(d, "pci_read_block failed. return value: %d.\n", rc);
- memset(&val, 0xff, len);
- }
-
- /* just return the I/O device register value for
- * passthrough type register group */
- if (reg_grp_entry == NULL) {
- goto exit;
- }
-
- /* adjust the read value to appropriate CFC-CFF window */
- val <<= (addr & 3) << 3;
- emul_len = len;
-
- /* loop around the guest requested size */
- while (emul_len > 0) {
- /* find register entry to be emulated */
- reg_entry = xen_pt_find_reg(reg_grp_entry, find_addr);
- if (reg_entry) {
- XenPTRegInfo *reg = reg_entry->reg;
- uint32_t real_offset = reg_grp_entry->base_offset + reg->offset;
- uint32_t valid_mask = 0xFFFFFFFF >> ((4 - emul_len) << 3);
- uint8_t *ptr_val = NULL;
-
- valid_mask <<= (find_addr - real_offset) << 3;
- ptr_val = (uint8_t *)&val + (real_offset & 3);
-
- /* do emulation based on register size */
- switch (reg->size) {
- case 1:
- if (reg->u.b.read) {
- rc = reg->u.b.read(s, reg_entry, ptr_val, valid_mask);
- }
- break;
- case 2:
- if (reg->u.w.read) {
- rc = reg->u.w.read(s, reg_entry,
- (uint16_t *)ptr_val, valid_mask);
- }
- break;
- case 4:
- if (reg->u.dw.read) {
- rc = reg->u.dw.read(s, reg_entry,
- (uint32_t *)ptr_val, valid_mask);
- }
- break;
- }
-
- if (rc < 0) {
- xen_shutdown_fatal_error("Internal error: Invalid read "
- "emulation. (%s, rc: %d)\n",
- __func__, rc);
- return 0;
- }
-
- /* calculate next address to find */
- emul_len -= reg->size;
- if (emul_len > 0) {
- find_addr = real_offset + reg->size;
- }
- } else {
- /* nothing to do with passthrough type register,
- * continue to find next byte */
- emul_len--;
- find_addr++;
- }
- }
-
- /* need to shift back before returning them to pci bus emulator */
- val >>= ((addr & 3) << 3);
-
-exit:
- XEN_PT_LOG_CONFIG(d, addr, val, len);
- return val;
-}
-
-static void xen_pt_pci_write_config(PCIDevice *d, uint32_t addr,
- uint32_t val, int len)
-{
- XenPCIPassthroughState *s = XEN_PT_DEVICE(d);
- int index = 0;
- XenPTRegGroup *reg_grp_entry = NULL;
- int rc = 0;
- uint32_t read_val = 0, wb_mask;
- int emul_len = 0;
- XenPTReg *reg_entry = NULL;
- uint32_t find_addr = addr;
- XenPTRegInfo *reg = NULL;
- bool wp_flag = false;
-
- if (xen_pt_pci_config_access_check(d, addr, len)) {
- return;
- }
-
- XEN_PT_LOG_CONFIG(d, addr, val, len);
-
- /* check unused BAR register */
- index = xen_pt_bar_offset_to_index(addr);
- if ((index >= 0) && (val != 0)) {
- uint32_t chk = val;
-
- if (index == PCI_ROM_SLOT)
- chk |= (uint32_t)~PCI_ROM_ADDRESS_MASK;
-
- if ((chk != XEN_PT_BAR_ALLF) &&
- (s->bases[index].bar_flag == XEN_PT_BAR_FLAG_UNUSED)) {
- XEN_PT_WARN(d, "Guest attempt to set address to unused "
- "Base Address Register. (addr: 0x%02x, len: %d)\n",
- addr, len);
- }
- }
-
- /* find register group entry */
- reg_grp_entry = xen_pt_find_reg_grp(s, addr);
- if (reg_grp_entry) {
- /* check 0-Hardwired register group */
- if (reg_grp_entry->reg_grp->grp_type == XEN_PT_GRP_TYPE_HARDWIRED) {
- /* ignore silently */
- XEN_PT_WARN(d, "Access to 0-Hardwired register. "
- "(addr: 0x%02x, len: %d)\n", addr, len);
- return;
- }
- }
-
- rc = xen_host_pci_get_block(&s->real_device, addr,
- (uint8_t *)&read_val, len);
- if (rc < 0) {
- XEN_PT_ERR(d, "pci_read_block failed. return value: %d.\n", rc);
- memset(&read_val, 0xff, len);
- wb_mask = 0;
- } else {
- wb_mask = 0xFFFFFFFF >> ((4 - len) << 3);
- }
-
- /* pass directly to the real device for passthrough type register group */
- if (reg_grp_entry == NULL) {
- if (!s->permissive) {
- wb_mask = 0;
- wp_flag = true;
- }
- goto out;
- }
-
- memory_region_transaction_begin();
- pci_default_write_config(d, addr, val, len);
-
- /* adjust the read and write value to appropriate CFC-CFF window */
- read_val <<= (addr & 3) << 3;
- val <<= (addr & 3) << 3;
- emul_len = len;
-
- /* loop around the guest requested size */
- while (emul_len > 0) {
- /* find register entry to be emulated */
- reg_entry = xen_pt_find_reg(reg_grp_entry, find_addr);
- if (reg_entry) {
- reg = reg_entry->reg;
- uint32_t real_offset = reg_grp_entry->base_offset + reg->offset;
- uint32_t valid_mask = 0xFFFFFFFF >> ((4 - emul_len) << 3);
- uint8_t *ptr_val = NULL;
- uint32_t wp_mask = reg->emu_mask | reg->ro_mask;
-
- valid_mask <<= (find_addr - real_offset) << 3;
- ptr_val = (uint8_t *)&val + (real_offset & 3);
- if (!s->permissive) {
- wp_mask |= reg->res_mask;
- }
- if (wp_mask == (0xFFFFFFFF >> ((4 - reg->size) << 3))) {
- wb_mask &= ~((wp_mask >> ((find_addr - real_offset) << 3))
- << ((len - emul_len) << 3));
- }
-
- /* do emulation based on register size */
- switch (reg->size) {
- case 1:
- if (reg->u.b.write) {
- rc = reg->u.b.write(s, reg_entry, ptr_val,
- read_val >> ((real_offset & 3) << 3),
- valid_mask);
- }
- break;
- case 2:
- if (reg->u.w.write) {
- rc = reg->u.w.write(s, reg_entry, (uint16_t *)ptr_val,
- (read_val >> ((real_offset & 3) << 3)),
- valid_mask);
- }
- break;
- case 4:
- if (reg->u.dw.write) {
- rc = reg->u.dw.write(s, reg_entry, (uint32_t *)ptr_val,
- (read_val >> ((real_offset & 3) << 3)),
- valid_mask);
- }
- break;
- }
-
- if (rc < 0) {
- xen_shutdown_fatal_error("Internal error: Invalid write"
- " emulation. (%s, rc: %d)\n",
- __func__, rc);
- return;
- }
-
- /* calculate next address to find */
- emul_len -= reg->size;
- if (emul_len > 0) {
- find_addr = real_offset + reg->size;
- }
- } else {
- /* nothing to do with passthrough type register,
- * continue to find next byte */
- if (!s->permissive) {
- wb_mask &= ~(0xff << ((len - emul_len) << 3));
- /* Unused BARs will make it here, but we don't want to issue
- * warnings for writes to them (bogus writes get dealt with
- * above).
- */
- if (index < 0) {
- wp_flag = true;
- }
- }
- emul_len--;
- find_addr++;
- }
- }
-
- /* need to shift back before passing them to xen_host_pci_set_block. */
- val >>= (addr & 3) << 3;
-
- memory_region_transaction_commit();
-
-out:
- if (wp_flag && !s->permissive_warned) {
- s->permissive_warned = true;
- xen_pt_log(d, "Write-back to unknown field 0x%02x (partially) inhibited (0x%0*x)\n",
- addr, len * 2, wb_mask);
- xen_pt_log(d, "If the device doesn't work, try enabling permissive mode\n");
- xen_pt_log(d, "(unsafe) and if it helps report the problem to xen-devel\n");
- }
- for (index = 0; wb_mask; index += len) {
- /* unknown regs are passed through */
- while (!(wb_mask & 0xff)) {
- index++;
- wb_mask >>= 8;
- }
- len = 0;
- do {
- len++;
- wb_mask >>= 8;
- } while (wb_mask & 0xff);
- rc = xen_host_pci_set_block(&s->real_device, addr + index,
- (uint8_t *)&val + index, len);
-
- if (rc < 0) {
- XEN_PT_ERR(d, "xen_host_pci_set_block failed. return value: %d.\n", rc);
- }
- }
-}
-
-/* register regions */
-
-static uint64_t xen_pt_bar_read(void *o, hwaddr addr,
- unsigned size)
-{
- PCIDevice *d = o;
- /* if this function is called, that probably means that there is a
- * misconfiguration of the IOMMU. */
- XEN_PT_ERR(d, "Should not read BAR through QEMU. @0x"TARGET_FMT_plx"\n",
- addr);
- return 0;
-}
-static void xen_pt_bar_write(void *o, hwaddr addr, uint64_t val,
- unsigned size)
-{
- PCIDevice *d = o;
- /* Same comment as xen_pt_bar_read function */
- XEN_PT_ERR(d, "Should not write BAR through QEMU. @0x"TARGET_FMT_plx"\n",
- addr);
-}
-
-static const MemoryRegionOps ops = {
- .endianness = DEVICE_NATIVE_ENDIAN,
- .read = xen_pt_bar_read,
- .write = xen_pt_bar_write,
-};
-
-static int xen_pt_register_regions(XenPCIPassthroughState *s, uint16_t *cmd)
-{
- int i = 0;
- XenHostPCIDevice *d = &s->real_device;
-
- /* Register PIO/MMIO BARs */
- for (i = 0; i < PCI_ROM_SLOT; i++) {
- XenHostPCIIORegion *r = &d->io_regions[i];
- uint8_t type;
-
- if (r->base_addr == 0 || r->size == 0) {
- continue;
- }
-
- s->bases[i].access.u = r->base_addr;
-
- if (r->type & XEN_HOST_PCI_REGION_TYPE_IO) {
- type = PCI_BASE_ADDRESS_SPACE_IO;
- *cmd |= PCI_COMMAND_IO;
- } else {
- type = PCI_BASE_ADDRESS_SPACE_MEMORY;
- if (r->type & XEN_HOST_PCI_REGION_TYPE_PREFETCH) {
- type |= PCI_BASE_ADDRESS_MEM_PREFETCH;
- }
- if (r->type & XEN_HOST_PCI_REGION_TYPE_MEM_64) {
- type |= PCI_BASE_ADDRESS_MEM_TYPE_64;
- }
- *cmd |= PCI_COMMAND_MEMORY;
- }
-
- memory_region_init_io(&s->bar[i], OBJECT(s), &ops, &s->dev,
- "xen-pci-pt-bar", r->size);
- pci_register_bar(&s->dev, i, type, &s->bar[i]);
-
- XEN_PT_LOG(&s->dev, "IO region %i registered (size=0x%08"PRIx64
- " base_addr=0x%08"PRIx64" type: %#x)\n",
- i, r->size, r->base_addr, type);
- }
-
- /* Register expansion ROM address */
- if (d->rom.base_addr && d->rom.size) {
- uint32_t bar_data = 0;
-
- /* Re-set BAR reported by OS, otherwise ROM can't be read. */
- if (xen_host_pci_get_long(d, PCI_ROM_ADDRESS, &bar_data)) {
- return 0;
- }
- if ((bar_data & PCI_ROM_ADDRESS_MASK) == 0) {
- bar_data |= d->rom.base_addr & PCI_ROM_ADDRESS_MASK;
- xen_host_pci_set_long(d, PCI_ROM_ADDRESS, bar_data);
- }
-
- s->bases[PCI_ROM_SLOT].access.maddr = d->rom.base_addr;
-
- memory_region_init_io(&s->rom, OBJECT(s), &ops, &s->dev,
- "xen-pci-pt-rom", d->rom.size);
- pci_register_bar(&s->dev, PCI_ROM_SLOT, PCI_BASE_ADDRESS_MEM_PREFETCH,
- &s->rom);
-
- XEN_PT_LOG(&s->dev, "Expansion ROM registered (size=0x%08"PRIx64
- " base_addr=0x%08"PRIx64")\n",
- d->rom.size, d->rom.base_addr);
- }
-
- xen_pt_register_vga_regions(d);
- return 0;
-}
-
-/* region mapping */
-
-static int xen_pt_bar_from_region(XenPCIPassthroughState *s, MemoryRegion *mr)
-{
- int i = 0;
-
- for (i = 0; i < PCI_NUM_REGIONS - 1; i++) {
- if (mr == &s->bar[i]) {
- return i;
- }
- }
- if (mr == &s->rom) {
- return PCI_ROM_SLOT;
- }
- return -1;
-}
-
-/*
- * This function checks if an io_region overlaps an io_region from another
- * device. The io_region to check is provided with (addr, size and type)
- * A callback can be provided and will be called for every region that is
- * overlapped.
- * The return value indicates if the region is overlappsed */
-struct CheckBarArgs {
- XenPCIPassthroughState *s;
- pcibus_t addr;
- pcibus_t size;
- uint8_t type;
- bool rc;
-};
-static void xen_pt_check_bar_overlap(PCIBus *bus, PCIDevice *d, void *opaque)
-{
- struct CheckBarArgs *arg = opaque;
- XenPCIPassthroughState *s = arg->s;
- uint8_t type = arg->type;
- int i;
-
- if (d->devfn == s->dev.devfn) {
- return;
- }
-
- /* xxx: This ignores bridges. */
- for (i = 0; i < PCI_NUM_REGIONS; i++) {
- const PCIIORegion *r = &d->io_regions[i];
-
- if (!r->size) {
- continue;
- }
- if ((type & PCI_BASE_ADDRESS_SPACE_IO)
- != (r->type & PCI_BASE_ADDRESS_SPACE_IO)) {
- continue;
- }
-
- if (ranges_overlap(arg->addr, arg->size, r->addr, r->size)) {
- XEN_PT_WARN(&s->dev,
- "Overlapped to device [%02x:%02x.%d] Region: %i"
- " (addr: %#"FMT_PCIBUS", len: %#"FMT_PCIBUS")\n",
- pci_bus_num(bus), PCI_SLOT(d->devfn),
- PCI_FUNC(d->devfn), i, r->addr, r->size);
- arg->rc = true;
- }
- }
-}
-
-static void xen_pt_region_update(XenPCIPassthroughState *s,
- MemoryRegionSection *sec, bool adding)
-{
- PCIDevice *d = &s->dev;
- MemoryRegion *mr = sec->mr;
- int bar = -1;
- int rc;
- int op = adding ? DPCI_ADD_MAPPING : DPCI_REMOVE_MAPPING;
- struct CheckBarArgs args = {
- .s = s,
- .addr = sec->offset_within_address_space,
- .size = int128_get64(sec->size),
- .rc = false,
- };
-
- bar = xen_pt_bar_from_region(s, mr);
- if (bar == -1 && (!s->msix || &s->msix->mmio != mr)) {
- return;
- }
-
- if (s->msix && &s->msix->mmio == mr) {
- if (adding) {
- s->msix->mmio_base_addr = sec->offset_within_address_space;
- rc = xen_pt_msix_update_remap(s, s->msix->bar_index);
- }
- return;
- }
-
- args.type = d->io_regions[bar].type;
- pci_for_each_device(d->bus, pci_bus_num(d->bus),
- xen_pt_check_bar_overlap, &args);
- if (args.rc) {
- XEN_PT_WARN(d, "Region: %d (addr: %#"FMT_PCIBUS
- ", len: %#"FMT_PCIBUS") is overlapped.\n",
- bar, sec->offset_within_address_space,
- int128_get64(sec->size));
- }
-
- if (d->io_regions[bar].type & PCI_BASE_ADDRESS_SPACE_IO) {
- uint32_t guest_port = sec->offset_within_address_space;
- uint32_t machine_port = s->bases[bar].access.pio_base;
- uint32_t size = int128_get64(sec->size);
- rc = xc_domain_ioport_mapping(xen_xc, xen_domid,
- guest_port, machine_port, size,
- op);
- if (rc) {
- XEN_PT_ERR(d, "%s ioport mapping failed! (err: %i)\n",
- adding ? "create new" : "remove old", errno);
- }
- } else {
- pcibus_t guest_addr = sec->offset_within_address_space;
- pcibus_t machine_addr = s->bases[bar].access.maddr
- + sec->offset_within_region;
- pcibus_t size = int128_get64(sec->size);
- rc = xc_domain_memory_mapping(xen_xc, xen_domid,
- XEN_PFN(guest_addr + XC_PAGE_SIZE - 1),
- XEN_PFN(machine_addr + XC_PAGE_SIZE - 1),
- XEN_PFN(size + XC_PAGE_SIZE - 1),
- op);
- if (rc) {
- XEN_PT_ERR(d, "%s mem mapping failed! (err: %i)\n",
- adding ? "create new" : "remove old", errno);
- }
- }
-}
-
-static void xen_pt_region_add(MemoryListener *l, MemoryRegionSection *sec)
-{
- XenPCIPassthroughState *s = container_of(l, XenPCIPassthroughState,
- memory_listener);
-
- memory_region_ref(sec->mr);
- xen_pt_region_update(s, sec, true);
-}
-
-static void xen_pt_region_del(MemoryListener *l, MemoryRegionSection *sec)
-{
- XenPCIPassthroughState *s = container_of(l, XenPCIPassthroughState,
- memory_listener);
-
- xen_pt_region_update(s, sec, false);
- memory_region_unref(sec->mr);
-}
-
-static void xen_pt_io_region_add(MemoryListener *l, MemoryRegionSection *sec)
-{
- XenPCIPassthroughState *s = container_of(l, XenPCIPassthroughState,
- io_listener);
-
- memory_region_ref(sec->mr);
- xen_pt_region_update(s, sec, true);
-}
-
-static void xen_pt_io_region_del(MemoryListener *l, MemoryRegionSection *sec)
-{
- XenPCIPassthroughState *s = container_of(l, XenPCIPassthroughState,
- io_listener);
-
- xen_pt_region_update(s, sec, false);
- memory_region_unref(sec->mr);
-}
-
-static const MemoryListener xen_pt_memory_listener = {
- .region_add = xen_pt_region_add,
- .region_del = xen_pt_region_del,
- .priority = 10,
-};
-
-static const MemoryListener xen_pt_io_listener = {
- .region_add = xen_pt_io_region_add,
- .region_del = xen_pt_io_region_del,
- .priority = 10,
-};
-
-static void
-xen_igd_passthrough_isa_bridge_create(XenPCIPassthroughState *s,
- XenHostPCIDevice *dev)
-{
- uint16_t gpu_dev_id;
- PCIDevice *d = &s->dev;
-
- gpu_dev_id = dev->device_id;
- igd_passthrough_isa_bridge_create(d->bus, gpu_dev_id);
-}
-
-/* destroy. */
-static void xen_pt_destroy(PCIDevice *d) {
-
- XenPCIPassthroughState *s = XEN_PT_DEVICE(d);
- XenHostPCIDevice *host_dev = &s->real_device;
- uint8_t machine_irq = s->machine_irq;
- uint8_t intx;
- int rc;
-
- if (machine_irq && !xen_host_pci_device_closed(&s->real_device)) {
- intx = xen_pt_pci_intx(s);
- rc = xc_domain_unbind_pt_irq(xen_xc, xen_domid, machine_irq,
- PT_IRQ_TYPE_PCI,
- pci_bus_num(d->bus),
- PCI_SLOT(s->dev.devfn),
- intx,
- 0 /* isa_irq */);
- if (rc < 0) {
- XEN_PT_ERR(d, "unbinding of interrupt INT%c failed."
- " (machine irq: %i, err: %d)"
- " But bravely continuing on..\n",
- 'a' + intx, machine_irq, errno);
- }
- }
-
- /* N.B. xen_pt_config_delete takes care of freeing them. */
- if (s->msi) {
- xen_pt_msi_disable(s);
- }
- if (s->msix) {
- xen_pt_msix_disable(s);
- }
-
- if (machine_irq) {
- xen_pt_mapped_machine_irq[machine_irq]--;
-
- if (xen_pt_mapped_machine_irq[machine_irq] == 0) {
- rc = xc_physdev_unmap_pirq(xen_xc, xen_domid, machine_irq);
-
- if (rc < 0) {
- XEN_PT_ERR(d, "unmapping of interrupt %i failed. (err: %d)"
- " But bravely continuing on..\n",
- machine_irq, errno);
- }
- }
- s->machine_irq = 0;
- }
-
- /* delete all emulated config registers */
- xen_pt_config_delete(s);
-
- xen_pt_unregister_vga_regions(host_dev);
-
- if (s->listener_set) {
- memory_listener_unregister(&s->memory_listener);
- memory_listener_unregister(&s->io_listener);
- s->listener_set = false;
- }
- if (!xen_host_pci_device_closed(&s->real_device)) {
- xen_host_pci_device_put(&s->real_device);
- }
-}
-/* init */
-
-static void xen_pt_realize(PCIDevice *d, Error **errp)
-{
- XenPCIPassthroughState *s = XEN_PT_DEVICE(d);
- int i, rc = 0;
- uint8_t machine_irq = 0, scratch;
- uint16_t cmd = 0;
- int pirq = XEN_PT_UNASSIGNED_PIRQ;
- Error *err = NULL;
-
- /* register real device */
- XEN_PT_LOG(d, "Assigning real physical device %02x:%02x.%d"
- " to devfn %#x\n",
- s->hostaddr.bus, s->hostaddr.slot, s->hostaddr.function,
- s->dev.devfn);
-
- xen_host_pci_device_get(&s->real_device,
- s->hostaddr.domain, s->hostaddr.bus,
- s->hostaddr.slot, s->hostaddr.function,
- &err);
- if (err) {
- error_append_hint(&err, "Failed to \"open\" the real pci device");
- error_propagate(errp, err);
- return;
- }
-
- s->is_virtfn = s->real_device.is_virtfn;
- if (s->is_virtfn) {
- XEN_PT_LOG(d, "%04x:%02x:%02x.%d is a SR-IOV Virtual Function\n",
- s->real_device.domain, s->real_device.bus,
- s->real_device.dev, s->real_device.func);
- }
-
- /* Initialize virtualized PCI configuration (Extended 256 Bytes) */
- memset(d->config, 0, PCI_CONFIG_SPACE_SIZE);
-
- s->memory_listener = xen_pt_memory_listener;
- s->io_listener = xen_pt_io_listener;
-
- /* Setup VGA bios for passthrough GFX */
- if ((s->real_device.domain == 0) && (s->real_device.bus == 0) &&
- (s->real_device.dev == 2) && (s->real_device.func == 0)) {
- if (!is_igd_vga_passthrough(&s->real_device)) {
- error_setg(errp, "Need to enable igd-passthru if you're trying"
- " to passthrough IGD GFX");
- xen_host_pci_device_put(&s->real_device);
- return;
- }
-
- xen_pt_setup_vga(s, &s->real_device, &err);
- if (err) {
- error_append_hint(&err, "Setup VGA BIOS of passthrough"
- " GFX failed");
- error_propagate(errp, err);
- xen_host_pci_device_put(&s->real_device);
- return;
- }
-
- /* Register ISA bridge for passthrough GFX. */
- xen_igd_passthrough_isa_bridge_create(s, &s->real_device);
- }
-
- /* Handle real device's MMIO/PIO BARs */
- xen_pt_register_regions(s, &cmd);
-
- /* reinitialize each config register to be emulated */
- xen_pt_config_init(s, &err);
- if (err) {
- error_append_hint(&err, "PCI Config space initialisation failed");
- error_report_err(err);
- rc = -1;
- goto err_out;
- }
-
- /* Bind interrupt */
- rc = xen_host_pci_get_byte(&s->real_device, PCI_INTERRUPT_PIN, &scratch);
- if (rc) {
- error_setg_errno(errp, errno, "Failed to read PCI_INTERRUPT_PIN");
- goto err_out;
- }
- if (!scratch) {
- error_setg(errp, "no pin interrupt");
- goto out;
- }
-
- machine_irq = s->real_device.irq;
- rc = xc_physdev_map_pirq(xen_xc, xen_domid, machine_irq, &pirq);
- if (rc < 0) {
- error_setg_errno(errp, errno, "Mapping machine irq %u to"
- " pirq %i failed", machine_irq, pirq);
-
- /* Disable PCI intx assertion (turn on bit10 of devctl) */
- cmd |= PCI_COMMAND_INTX_DISABLE;
- machine_irq = 0;
- s->machine_irq = 0;
- } else {
- machine_irq = pirq;
- s->machine_irq = pirq;
- xen_pt_mapped_machine_irq[machine_irq]++;
- }
-
- /* bind machine_irq to device */
- if (machine_irq != 0) {
- uint8_t e_intx = xen_pt_pci_intx(s);
-
- rc = xc_domain_bind_pt_pci_irq(xen_xc, xen_domid, machine_irq,
- pci_bus_num(d->bus),
- PCI_SLOT(d->devfn),
- e_intx);
- if (rc < 0) {
- error_setg_errno(errp, errno, "Binding of interrupt %u failed",
- e_intx);
-
- /* Disable PCI intx assertion (turn on bit10 of devctl) */
- cmd |= PCI_COMMAND_INTX_DISABLE;
- xen_pt_mapped_machine_irq[machine_irq]--;
-
- if (xen_pt_mapped_machine_irq[machine_irq] == 0) {
- if (xc_physdev_unmap_pirq(xen_xc, xen_domid, machine_irq)) {
- error_setg_errno(errp, errno, "Unmapping of machine"
- " interrupt %u failed", machine_irq);
- }
- }
- s->machine_irq = 0;
- }
- }
-
-out:
- if (cmd) {
- uint16_t val;
-
- rc = xen_host_pci_get_word(&s->real_device, PCI_COMMAND, &val);
- if (rc) {
- error_setg_errno(errp, errno, "Failed to read PCI_COMMAND");
- goto err_out;
- } else {
- val |= cmd;
- rc = xen_host_pci_set_word(&s->real_device, PCI_COMMAND, val);
- if (rc) {
- error_setg_errno(errp, errno, "Failed to write PCI_COMMAND"
- " val = 0x%x", val);
- goto err_out;
- }
- }
- }
-
- memory_listener_register(&s->memory_listener, &s->dev.bus_master_as);
- memory_listener_register(&s->io_listener, &address_space_io);
- s->listener_set = true;
- XEN_PT_LOG(d,
- "Real physical device %02x:%02x.%d registered successfully\n",
- s->hostaddr.bus, s->hostaddr.slot, s->hostaddr.function);
-
- return;
-
-err_out:
- for (i = 0; i < PCI_ROM_SLOT; i++) {
- object_unparent(OBJECT(&s->bar[i]));
- }
- object_unparent(OBJECT(&s->rom));
-
- xen_pt_destroy(d);
- assert(rc);
-}
-
-static void xen_pt_unregister_device(PCIDevice *d)
-{
- xen_pt_destroy(d);
-}
-
-static Property xen_pci_passthrough_properties[] = {
- DEFINE_PROP_PCI_HOST_DEVADDR("hostaddr", XenPCIPassthroughState, hostaddr),
- DEFINE_PROP_BOOL("permissive", XenPCIPassthroughState, permissive, false),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void xen_pci_passthrough_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = xen_pt_realize;
- k->exit = xen_pt_unregister_device;
- k->config_read = xen_pt_pci_read_config;
- k->config_write = xen_pt_pci_write_config;
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- dc->desc = "Assign an host PCI device with Xen";
- dc->props = xen_pci_passthrough_properties;
-};
-
-static void xen_pci_passthrough_finalize(Object *obj)
-{
- XenPCIPassthroughState *s = XEN_PT_DEVICE(obj);
-
- xen_pt_msix_delete(s);
-}
-
-static const TypeInfo xen_pci_passthrough_info = {
- .name = TYPE_XEN_PT_DEVICE,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(XenPCIPassthroughState),
- .instance_finalize = xen_pci_passthrough_finalize,
- .class_init = xen_pci_passthrough_class_init,
-};
-
-static void xen_pci_passthrough_register_types(void)
-{
- type_register_static(&xen_pci_passthrough_info);
-}
-
-type_init(xen_pci_passthrough_register_types)
diff --git a/qemu/hw/xen/xen_pt.h b/qemu/hw/xen/xen_pt.h
deleted file mode 100644
index c2f8e1fc2..000000000
--- a/qemu/hw/xen/xen_pt.h
+++ /dev/null
@@ -1,335 +0,0 @@
-#ifndef XEN_PT_H
-#define XEN_PT_H
-
-#include "qemu-common.h"
-#include "hw/xen/xen_common.h"
-#include "hw/pci/pci.h"
-#include "xen-host-pci-device.h"
-
-void xen_pt_log(const PCIDevice *d, const char *f, ...) GCC_FMT_ATTR(2, 3);
-
-#define XEN_PT_ERR(d, _f, _a...) xen_pt_log(d, "%s: Error: "_f, __func__, ##_a)
-
-#ifdef XEN_PT_LOGGING_ENABLED
-# define XEN_PT_LOG(d, _f, _a...) xen_pt_log(d, "%s: " _f, __func__, ##_a)
-# define XEN_PT_WARN(d, _f, _a...) \
- xen_pt_log(d, "%s: Warning: "_f, __func__, ##_a)
-#else
-# define XEN_PT_LOG(d, _f, _a...)
-# define XEN_PT_WARN(d, _f, _a...)
-#endif
-
-#ifdef XEN_PT_DEBUG_PCI_CONFIG_ACCESS
-# define XEN_PT_LOG_CONFIG(d, addr, val, len) \
- xen_pt_log(d, "%s: address=0x%04x val=0x%08x len=%d\n", \
- __func__, addr, val, len)
-#else
-# define XEN_PT_LOG_CONFIG(d, addr, val, len)
-#endif
-
-
-/* Helper */
-#define XEN_PFN(x) ((x) >> XC_PAGE_SHIFT)
-
-typedef const struct XenPTRegInfo XenPTRegInfo;
-typedef struct XenPTReg XenPTReg;
-
-typedef struct XenPCIPassthroughState XenPCIPassthroughState;
-
-#define TYPE_XEN_PT_DEVICE "xen-pci-passthrough"
-#define XEN_PT_DEVICE(obj) \
- OBJECT_CHECK(XenPCIPassthroughState, (obj), TYPE_XEN_PT_DEVICE)
-
-uint32_t igd_read_opregion(XenPCIPassthroughState *s);
-void igd_write_opregion(XenPCIPassthroughState *s, uint32_t val);
-
-/* function type for config reg */
-typedef int (*xen_pt_conf_reg_init)
- (XenPCIPassthroughState *, XenPTRegInfo *, uint32_t real_offset,
- uint32_t *data);
-typedef int (*xen_pt_conf_dword_write)
- (XenPCIPassthroughState *, XenPTReg *cfg_entry,
- uint32_t *val, uint32_t dev_value, uint32_t valid_mask);
-typedef int (*xen_pt_conf_word_write)
- (XenPCIPassthroughState *, XenPTReg *cfg_entry,
- uint16_t *val, uint16_t dev_value, uint16_t valid_mask);
-typedef int (*xen_pt_conf_byte_write)
- (XenPCIPassthroughState *, XenPTReg *cfg_entry,
- uint8_t *val, uint8_t dev_value, uint8_t valid_mask);
-typedef int (*xen_pt_conf_dword_read)
- (XenPCIPassthroughState *, XenPTReg *cfg_entry,
- uint32_t *val, uint32_t valid_mask);
-typedef int (*xen_pt_conf_word_read)
- (XenPCIPassthroughState *, XenPTReg *cfg_entry,
- uint16_t *val, uint16_t valid_mask);
-typedef int (*xen_pt_conf_byte_read)
- (XenPCIPassthroughState *, XenPTReg *cfg_entry,
- uint8_t *val, uint8_t valid_mask);
-
-#define XEN_PT_BAR_ALLF 0xFFFFFFFF
-#define XEN_PT_BAR_UNMAPPED (-1)
-
-#define XEN_PCI_CAP_MAX 48
-
-#define XEN_PCI_INTEL_OPREGION 0xfc
-
-typedef enum {
- XEN_PT_GRP_TYPE_HARDWIRED = 0, /* 0 Hardwired reg group */
- XEN_PT_GRP_TYPE_EMU, /* emul reg group */
-} XenPTRegisterGroupType;
-
-typedef enum {
- XEN_PT_BAR_FLAG_MEM = 0, /* Memory type BAR */
- XEN_PT_BAR_FLAG_IO, /* I/O type BAR */
- XEN_PT_BAR_FLAG_UPPER, /* upper 64bit BAR */
- XEN_PT_BAR_FLAG_UNUSED, /* unused BAR */
-} XenPTBarFlag;
-
-
-typedef struct XenPTRegion {
- /* BAR flag */
- XenPTBarFlag bar_flag;
- /* Translation of the emulated address */
- union {
- uint64_t maddr;
- uint64_t pio_base;
- uint64_t u;
- } access;
-} XenPTRegion;
-
-/* XenPTRegInfo declaration
- * - only for emulated register (either a part or whole bit).
- * - for passthrough register that need special behavior (like interacting with
- * other component), set emu_mask to all 0 and specify r/w func properly.
- * - do NOT use ALL F for init_val, otherwise the tbl will not be registered.
- */
-
-/* emulated register information */
-struct XenPTRegInfo {
- uint32_t offset;
- uint32_t size;
- uint32_t init_val;
- /* reg reserved field mask (ON:reserved, OFF:defined) */
- uint32_t res_mask;
- /* reg read only field mask (ON:RO/ROS, OFF:other) */
- uint32_t ro_mask;
- /* reg read/write-1-clear field mask (ON:RW1C/RW1CS, OFF:other) */
- uint32_t rw1c_mask;
- /* reg emulate field mask (ON:emu, OFF:passthrough) */
- uint32_t emu_mask;
- xen_pt_conf_reg_init init;
- /* read/write function pointer
- * for double_word/word/byte size */
- union {
- struct {
- xen_pt_conf_dword_write write;
- xen_pt_conf_dword_read read;
- } dw;
- struct {
- xen_pt_conf_word_write write;
- xen_pt_conf_word_read read;
- } w;
- struct {
- xen_pt_conf_byte_write write;
- xen_pt_conf_byte_read read;
- } b;
- } u;
-};
-
-/* emulated register management */
-struct XenPTReg {
- QLIST_ENTRY(XenPTReg) entries;
- XenPTRegInfo *reg;
- union {
- uint8_t *byte;
- uint16_t *half_word;
- uint32_t *word;
- } ptr; /* pointer to dev.config. */
-};
-
-typedef const struct XenPTRegGroupInfo XenPTRegGroupInfo;
-
-/* emul reg group size initialize method */
-typedef int (*xen_pt_reg_size_init_fn)
- (XenPCIPassthroughState *, XenPTRegGroupInfo *,
- uint32_t base_offset, uint8_t *size);
-
-/* emulated register group information */
-struct XenPTRegGroupInfo {
- uint8_t grp_id;
- XenPTRegisterGroupType grp_type;
- uint8_t grp_size;
- xen_pt_reg_size_init_fn size_init;
- XenPTRegInfo *emu_regs;
-};
-
-/* emul register group management table */
-typedef struct XenPTRegGroup {
- QLIST_ENTRY(XenPTRegGroup) entries;
- XenPTRegGroupInfo *reg_grp;
- uint32_t base_offset;
- uint8_t size;
- QLIST_HEAD(, XenPTReg) reg_tbl_list;
-} XenPTRegGroup;
-
-
-#define XEN_PT_UNASSIGNED_PIRQ (-1)
-typedef struct XenPTMSI {
- uint16_t flags;
- uint32_t addr_lo; /* guest message address */
- uint32_t addr_hi; /* guest message upper address */
- uint16_t data; /* guest message data */
- uint32_t ctrl_offset; /* saved control offset */
- int pirq; /* guest pirq corresponding */
- bool initialized; /* when guest MSI is initialized */
- bool mapped; /* when pirq is mapped */
-} XenPTMSI;
-
-typedef struct XenPTMSIXEntry {
- int pirq;
- uint64_t addr;
- uint32_t data;
- uint32_t latch[4];
- bool updated; /* indicate whether MSI ADDR or DATA is updated */
-} XenPTMSIXEntry;
-typedef struct XenPTMSIX {
- uint32_t ctrl_offset;
- bool enabled;
- bool maskall;
- int total_entries;
- int bar_index;
- uint64_t table_base;
- uint32_t table_offset_adjust; /* page align mmap */
- uint64_t mmio_base_addr;
- MemoryRegion mmio;
- void *phys_iomem_base;
- XenPTMSIXEntry msix_entry[0];
-} XenPTMSIX;
-
-struct XenPCIPassthroughState {
- PCIDevice dev;
-
- PCIHostDeviceAddress hostaddr;
- bool is_virtfn;
- bool permissive;
- bool permissive_warned;
- XenHostPCIDevice real_device;
- XenPTRegion bases[PCI_NUM_REGIONS]; /* Access regions */
- QLIST_HEAD(, XenPTRegGroup) reg_grps;
-
- uint32_t machine_irq;
-
- XenPTMSI *msi;
- XenPTMSIX *msix;
-
- MemoryRegion bar[PCI_NUM_REGIONS - 1];
- MemoryRegion rom;
-
- MemoryListener memory_listener;
- MemoryListener io_listener;
- bool listener_set;
-};
-
-void xen_pt_config_init(XenPCIPassthroughState *s, Error **errp);
-void xen_pt_config_delete(XenPCIPassthroughState *s);
-XenPTRegGroup *xen_pt_find_reg_grp(XenPCIPassthroughState *s, uint32_t address);
-XenPTReg *xen_pt_find_reg(XenPTRegGroup *reg_grp, uint32_t address);
-int xen_pt_bar_offset_to_index(uint32_t offset);
-
-static inline pcibus_t xen_pt_get_emul_size(XenPTBarFlag flag, pcibus_t r_size)
-{
- /* align resource size (memory type only) */
- if (flag == XEN_PT_BAR_FLAG_MEM) {
- return (r_size + XC_PAGE_SIZE - 1) & XC_PAGE_MASK;
- } else {
- return r_size;
- }
-}
-
-/* INTx */
-/* The PCI Local Bus Specification, Rev. 3.0,
- * Section 6.2.4 Miscellaneous Registers, pp 223
- * outlines 5 valid values for the interrupt pin (intx).
- * 0: For devices (or device functions) that don't use an interrupt in
- * 1: INTA#
- * 2: INTB#
- * 3: INTC#
- * 4: INTD#
- *
- * Xen uses the following 4 values for intx
- * 0: INTA#
- * 1: INTB#
- * 2: INTC#
- * 3: INTD#
- *
- * Observing that these list of values are not the same, xen_pt_pci_read_intx()
- * uses the following mapping from hw to xen values.
- * This seems to reflect the current usage within Xen.
- *
- * PCI hardware | Xen | Notes
- * ----------------+-----+----------------------------------------------------
- * 0 | 0 | No interrupt
- * 1 | 0 | INTA#
- * 2 | 1 | INTB#
- * 3 | 2 | INTC#
- * 4 | 3 | INTD#
- * any other value | 0 | This should never happen, log error message
- */
-
-static inline uint8_t xen_pt_pci_read_intx(XenPCIPassthroughState *s)
-{
- uint8_t v = 0;
- xen_host_pci_get_byte(&s->real_device, PCI_INTERRUPT_PIN, &v);
- return v;
-}
-
-static inline uint8_t xen_pt_pci_intx(XenPCIPassthroughState *s)
-{
- uint8_t r_val = xen_pt_pci_read_intx(s);
-
- XEN_PT_LOG(&s->dev, "intx=%i\n", r_val);
- if (r_val < 1 || r_val > 4) {
- XEN_PT_LOG(&s->dev, "Interrupt pin read from hardware is out of range:"
- " value=%i, acceptable range is 1 - 4\n", r_val);
- r_val = 0;
- } else {
- /* Note that if s.real_device.config_fd is closed we make 0xff. */
- r_val -= 1;
- }
-
- return r_val;
-}
-
-/* MSI/MSI-X */
-int xen_pt_msi_setup(XenPCIPassthroughState *s);
-int xen_pt_msi_update(XenPCIPassthroughState *d);
-void xen_pt_msi_disable(XenPCIPassthroughState *s);
-
-int xen_pt_msix_init(XenPCIPassthroughState *s, uint32_t base);
-void xen_pt_msix_delete(XenPCIPassthroughState *s);
-void xen_pt_msix_unmap(XenPCIPassthroughState *s);
-int xen_pt_msix_update(XenPCIPassthroughState *s);
-int xen_pt_msix_update_remap(XenPCIPassthroughState *s, int bar_index);
-void xen_pt_msix_disable(XenPCIPassthroughState *s);
-
-static inline bool xen_pt_has_msix_mapping(XenPCIPassthroughState *s, int bar)
-{
- return s->msix && s->msix->bar_index == bar;
-}
-
-extern void *pci_assign_dev_load_option_rom(PCIDevice *dev,
- struct Object *owner, int *size,
- unsigned int domain,
- unsigned int bus, unsigned int slot,
- unsigned int function);
-extern bool has_igd_gfx_passthru;
-static inline bool is_igd_vga_passthrough(XenHostPCIDevice *dev)
-{
- return (has_igd_gfx_passthru
- && ((dev->class_code >> 0x8) == PCI_CLASS_DISPLAY_VGA));
-}
-int xen_pt_register_vga_regions(XenHostPCIDevice *dev);
-int xen_pt_unregister_vga_regions(XenHostPCIDevice *dev);
-void xen_pt_setup_vga(XenPCIPassthroughState *s, XenHostPCIDevice *dev,
- Error **errp);
-#endif /* !XEN_PT_H */
diff --git a/qemu/hw/xen/xen_pt_config_init.c b/qemu/hw/xen/xen_pt_config_init.c
deleted file mode 100644
index 9869ffda0..000000000
--- a/qemu/hw/xen/xen_pt_config_init.c
+++ /dev/null
@@ -1,2090 +0,0 @@
-/*
- * Copyright (c) 2007, Neocleus Corporation.
- * Copyright (c) 2007, Intel Corporation.
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- * Alex Novik <alex@neocleus.com>
- * Allen Kay <allen.m.kay@intel.com>
- * Guy Zana <guy@neocleus.com>
- *
- * This file implements direct PCI assignment to a HVM guest
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu/timer.h"
-#include "hw/xen/xen_backend.h"
-#include "xen_pt.h"
-
-#define XEN_PT_MERGE_VALUE(value, data, val_mask) \
- (((value) & (val_mask)) | ((data) & ~(val_mask)))
-
-#define XEN_PT_INVALID_REG 0xFFFFFFFF /* invalid register value */
-
-/* prototype */
-
-static int xen_pt_ptr_reg_init(XenPCIPassthroughState *s, XenPTRegInfo *reg,
- uint32_t real_offset, uint32_t *data);
-
-
-/* helper */
-
-/* A return value of 1 means the capability should NOT be exposed to guest. */
-static int xen_pt_hide_dev_cap(const XenHostPCIDevice *d, uint8_t grp_id)
-{
- switch (grp_id) {
- case PCI_CAP_ID_EXP:
- /* The PCI Express Capability Structure of the VF of Intel 82599 10GbE
- * Controller looks trivial, e.g., the PCI Express Capabilities
- * Register is 0. We should not try to expose it to guest.
- *
- * The datasheet is available at
- * http://download.intel.com/design/network/datashts/82599_datasheet.pdf
- *
- * See 'Table 9.7. VF PCIe Configuration Space' of the datasheet, the
- * PCI Express Capability Structure of the VF of Intel 82599 10GbE
- * Controller looks trivial, e.g., the PCI Express Capabilities
- * Register is 0, so the Capability Version is 0 and
- * xen_pt_pcie_size_init() would fail.
- */
- if (d->vendor_id == PCI_VENDOR_ID_INTEL &&
- d->device_id == PCI_DEVICE_ID_INTEL_82599_SFP_VF) {
- return 1;
- }
- break;
- }
- return 0;
-}
-
-/* find emulate register group entry */
-XenPTRegGroup *xen_pt_find_reg_grp(XenPCIPassthroughState *s, uint32_t address)
-{
- XenPTRegGroup *entry = NULL;
-
- /* find register group entry */
- QLIST_FOREACH(entry, &s->reg_grps, entries) {
- /* check address */
- if ((entry->base_offset <= address)
- && ((entry->base_offset + entry->size) > address)) {
- return entry;
- }
- }
-
- /* group entry not found */
- return NULL;
-}
-
-/* find emulate register entry */
-XenPTReg *xen_pt_find_reg(XenPTRegGroup *reg_grp, uint32_t address)
-{
- XenPTReg *reg_entry = NULL;
- XenPTRegInfo *reg = NULL;
- uint32_t real_offset = 0;
-
- /* find register entry */
- QLIST_FOREACH(reg_entry, &reg_grp->reg_tbl_list, entries) {
- reg = reg_entry->reg;
- real_offset = reg_grp->base_offset + reg->offset;
- /* check address */
- if ((real_offset <= address)
- && ((real_offset + reg->size) > address)) {
- return reg_entry;
- }
- }
-
- return NULL;
-}
-
-static uint32_t get_throughable_mask(const XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t valid_mask)
-{
- uint32_t throughable_mask = ~(reg->emu_mask | reg->ro_mask);
-
- if (!s->permissive) {
- throughable_mask &= ~reg->res_mask;
- }
-
- return throughable_mask & valid_mask;
-}
-
-/****************
- * general register functions
- */
-
-/* register initialization function */
-
-static int xen_pt_common_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
-{
- *data = reg->init_val;
- return 0;
-}
-
-/* Read register functions */
-
-static int xen_pt_byte_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
- uint8_t *value, uint8_t valid_mask)
-{
- XenPTRegInfo *reg = cfg_entry->reg;
- uint8_t valid_emu_mask = 0;
- uint8_t *data = cfg_entry->ptr.byte;
-
- /* emulate byte register */
- valid_emu_mask = reg->emu_mask & valid_mask;
- *value = XEN_PT_MERGE_VALUE(*value, *data, ~valid_emu_mask);
-
- return 0;
-}
-static int xen_pt_word_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
- uint16_t *value, uint16_t valid_mask)
-{
- XenPTRegInfo *reg = cfg_entry->reg;
- uint16_t valid_emu_mask = 0;
- uint16_t *data = cfg_entry->ptr.half_word;
-
- /* emulate word register */
- valid_emu_mask = reg->emu_mask & valid_mask;
- *value = XEN_PT_MERGE_VALUE(*value, *data, ~valid_emu_mask);
-
- return 0;
-}
-static int xen_pt_long_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
- uint32_t *value, uint32_t valid_mask)
-{
- XenPTRegInfo *reg = cfg_entry->reg;
- uint32_t valid_emu_mask = 0;
- uint32_t *data = cfg_entry->ptr.word;
-
- /* emulate long register */
- valid_emu_mask = reg->emu_mask & valid_mask;
- *value = XEN_PT_MERGE_VALUE(*value, *data, ~valid_emu_mask);
-
- return 0;
-}
-
-/* Write register functions */
-
-static int xen_pt_byte_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
- uint8_t *val, uint8_t dev_value,
- uint8_t valid_mask)
-{
- XenPTRegInfo *reg = cfg_entry->reg;
- uint8_t writable_mask = 0;
- uint8_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
- uint8_t *data = cfg_entry->ptr.byte;
-
- /* modify emulate register */
- writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
- *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
-
- /* create value for writing to I/O device register */
- *val = XEN_PT_MERGE_VALUE(*val, dev_value & ~reg->rw1c_mask,
- throughable_mask);
-
- return 0;
-}
-static int xen_pt_word_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
- uint16_t *val, uint16_t dev_value,
- uint16_t valid_mask)
-{
- XenPTRegInfo *reg = cfg_entry->reg;
- uint16_t writable_mask = 0;
- uint16_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
- uint16_t *data = cfg_entry->ptr.half_word;
-
- /* modify emulate register */
- writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
- *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
-
- /* create value for writing to I/O device register */
- *val = XEN_PT_MERGE_VALUE(*val, dev_value & ~reg->rw1c_mask,
- throughable_mask);
-
- return 0;
-}
-static int xen_pt_long_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
- uint32_t *val, uint32_t dev_value,
- uint32_t valid_mask)
-{
- XenPTRegInfo *reg = cfg_entry->reg;
- uint32_t writable_mask = 0;
- uint32_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
- uint32_t *data = cfg_entry->ptr.word;
-
- /* modify emulate register */
- writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
- *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
-
- /* create value for writing to I/O device register */
- *val = XEN_PT_MERGE_VALUE(*val, dev_value & ~reg->rw1c_mask,
- throughable_mask);
-
- return 0;
-}
-
-
-/* XenPTRegInfo declaration
- * - only for emulated register (either a part or whole bit).
- * - for passthrough register that need special behavior (like interacting with
- * other component), set emu_mask to all 0 and specify r/w func properly.
- * - do NOT use ALL F for init_val, otherwise the tbl will not be registered.
- */
-
-/********************
- * Header Type0
- */
-
-static int xen_pt_vendor_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
-{
- *data = s->real_device.vendor_id;
- return 0;
-}
-static int xen_pt_device_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
-{
- *data = s->real_device.device_id;
- return 0;
-}
-static int xen_pt_status_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
-{
- XenPTRegGroup *reg_grp_entry = NULL;
- XenPTReg *reg_entry = NULL;
- uint32_t reg_field = 0;
-
- /* find Header register group */
- reg_grp_entry = xen_pt_find_reg_grp(s, PCI_CAPABILITY_LIST);
- if (reg_grp_entry) {
- /* find Capabilities Pointer register */
- reg_entry = xen_pt_find_reg(reg_grp_entry, PCI_CAPABILITY_LIST);
- if (reg_entry) {
- /* check Capabilities Pointer register */
- if (*reg_entry->ptr.half_word) {
- reg_field |= PCI_STATUS_CAP_LIST;
- } else {
- reg_field &= ~PCI_STATUS_CAP_LIST;
- }
- } else {
- xen_shutdown_fatal_error("Internal error: Couldn't find XenPTReg*"
- " for Capabilities Pointer register."
- " (%s)\n", __func__);
- return -1;
- }
- } else {
- xen_shutdown_fatal_error("Internal error: Couldn't find XenPTRegGroup"
- " for Header. (%s)\n", __func__);
- return -1;
- }
-
- *data = reg_field;
- return 0;
-}
-static int xen_pt_header_type_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
-{
- /* read PCI_HEADER_TYPE */
- *data = reg->init_val | 0x80;
- return 0;
-}
-
-/* initialize Interrupt Pin register */
-static int xen_pt_irqpin_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
-{
- *data = xen_pt_pci_read_intx(s);
- return 0;
-}
-
-/* Command register */
-static int xen_pt_cmd_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
- uint16_t *val, uint16_t dev_value,
- uint16_t valid_mask)
-{
- XenPTRegInfo *reg = cfg_entry->reg;
- uint16_t writable_mask = 0;
- uint16_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
- uint16_t *data = cfg_entry->ptr.half_word;
-
- /* modify emulate register */
- writable_mask = ~reg->ro_mask & valid_mask;
- *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
-
- /* create value for writing to I/O device register */
- if (*val & PCI_COMMAND_INTX_DISABLE) {
- throughable_mask |= PCI_COMMAND_INTX_DISABLE;
- } else {
- if (s->machine_irq) {
- throughable_mask |= PCI_COMMAND_INTX_DISABLE;
- }
- }
-
- *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
-
- return 0;
-}
-
-/* BAR */
-#define XEN_PT_BAR_MEM_RO_MASK 0x0000000F /* BAR ReadOnly mask(Memory) */
-#define XEN_PT_BAR_MEM_EMU_MASK 0xFFFFFFF0 /* BAR emul mask(Memory) */
-#define XEN_PT_BAR_IO_RO_MASK 0x00000003 /* BAR ReadOnly mask(I/O) */
-#define XEN_PT_BAR_IO_EMU_MASK 0xFFFFFFFC /* BAR emul mask(I/O) */
-
-static bool is_64bit_bar(PCIIORegion *r)
-{
- return !!(r->type & PCI_BASE_ADDRESS_MEM_TYPE_64);
-}
-
-static uint64_t xen_pt_get_bar_size(PCIIORegion *r)
-{
- if (is_64bit_bar(r)) {
- uint64_t size64;
- size64 = (r + 1)->size;
- size64 <<= 32;
- size64 += r->size;
- return size64;
- }
- return r->size;
-}
-
-static XenPTBarFlag xen_pt_bar_reg_parse(XenPCIPassthroughState *s,
- int index)
-{
- PCIDevice *d = &s->dev;
- XenPTRegion *region = NULL;
- PCIIORegion *r;
-
- /* check 64bit BAR */
- if ((0 < index) && (index < PCI_ROM_SLOT)) {
- int type = s->real_device.io_regions[index - 1].type;
-
- if ((type & XEN_HOST_PCI_REGION_TYPE_MEM)
- && (type & XEN_HOST_PCI_REGION_TYPE_MEM_64)) {
- region = &s->bases[index - 1];
- if (region->bar_flag != XEN_PT_BAR_FLAG_UPPER) {
- return XEN_PT_BAR_FLAG_UPPER;
- }
- }
- }
-
- /* check unused BAR */
- r = &d->io_regions[index];
- if (!xen_pt_get_bar_size(r)) {
- return XEN_PT_BAR_FLAG_UNUSED;
- }
-
- /* for ExpROM BAR */
- if (index == PCI_ROM_SLOT) {
- return XEN_PT_BAR_FLAG_MEM;
- }
-
- /* check BAR I/O indicator */
- if (s->real_device.io_regions[index].type & XEN_HOST_PCI_REGION_TYPE_IO) {
- return XEN_PT_BAR_FLAG_IO;
- } else {
- return XEN_PT_BAR_FLAG_MEM;
- }
-}
-
-static inline uint32_t base_address_with_flags(XenHostPCIIORegion *hr)
-{
- if (hr->type & XEN_HOST_PCI_REGION_TYPE_IO) {
- return hr->base_addr | (hr->bus_flags & ~PCI_BASE_ADDRESS_IO_MASK);
- } else {
- return hr->base_addr | (hr->bus_flags & ~PCI_BASE_ADDRESS_MEM_MASK);
- }
-}
-
-static int xen_pt_bar_reg_init(XenPCIPassthroughState *s, XenPTRegInfo *reg,
- uint32_t real_offset, uint32_t *data)
-{
- uint32_t reg_field = 0;
- int index;
-
- index = xen_pt_bar_offset_to_index(reg->offset);
- if (index < 0 || index >= PCI_NUM_REGIONS) {
- XEN_PT_ERR(&s->dev, "Internal error: Invalid BAR index [%d].\n", index);
- return -1;
- }
-
- /* set BAR flag */
- s->bases[index].bar_flag = xen_pt_bar_reg_parse(s, index);
- if (s->bases[index].bar_flag == XEN_PT_BAR_FLAG_UNUSED) {
- reg_field = XEN_PT_INVALID_REG;
- }
-
- *data = reg_field;
- return 0;
-}
-static int xen_pt_bar_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
- uint32_t *value, uint32_t valid_mask)
-{
- XenPTRegInfo *reg = cfg_entry->reg;
- uint32_t valid_emu_mask = 0;
- uint32_t bar_emu_mask = 0;
- int index;
-
- /* get BAR index */
- index = xen_pt_bar_offset_to_index(reg->offset);
- if (index < 0 || index >= PCI_NUM_REGIONS - 1) {
- XEN_PT_ERR(&s->dev, "Internal error: Invalid BAR index [%d].\n", index);
- return -1;
- }
-
- /* use fixed-up value from kernel sysfs */
- *value = base_address_with_flags(&s->real_device.io_regions[index]);
-
- /* set emulate mask depend on BAR flag */
- switch (s->bases[index].bar_flag) {
- case XEN_PT_BAR_FLAG_MEM:
- bar_emu_mask = XEN_PT_BAR_MEM_EMU_MASK;
- break;
- case XEN_PT_BAR_FLAG_IO:
- bar_emu_mask = XEN_PT_BAR_IO_EMU_MASK;
- break;
- case XEN_PT_BAR_FLAG_UPPER:
- bar_emu_mask = XEN_PT_BAR_ALLF;
- break;
- default:
- break;
- }
-
- /* emulate BAR */
- valid_emu_mask = bar_emu_mask & valid_mask;
- *value = XEN_PT_MERGE_VALUE(*value, *cfg_entry->ptr.word, ~valid_emu_mask);
-
- return 0;
-}
-static int xen_pt_bar_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
- uint32_t *val, uint32_t dev_value,
- uint32_t valid_mask)
-{
- XenPTRegInfo *reg = cfg_entry->reg;
- XenPTRegion *base = NULL;
- PCIDevice *d = &s->dev;
- const PCIIORegion *r;
- uint32_t writable_mask = 0;
- uint32_t bar_emu_mask = 0;
- uint32_t bar_ro_mask = 0;
- uint32_t r_size = 0;
- int index = 0;
- uint32_t *data = cfg_entry->ptr.word;
-
- index = xen_pt_bar_offset_to_index(reg->offset);
- if (index < 0 || index >= PCI_NUM_REGIONS) {
- XEN_PT_ERR(d, "Internal error: Invalid BAR index [%d].\n", index);
- return -1;
- }
-
- r = &d->io_regions[index];
- base = &s->bases[index];
- r_size = xen_pt_get_emul_size(base->bar_flag, r->size);
-
- /* set emulate mask and read-only mask values depend on the BAR flag */
- switch (s->bases[index].bar_flag) {
- case XEN_PT_BAR_FLAG_MEM:
- bar_emu_mask = XEN_PT_BAR_MEM_EMU_MASK;
- if (!r_size) {
- /* low 32 bits mask for 64 bit bars */
- bar_ro_mask = XEN_PT_BAR_ALLF;
- } else {
- bar_ro_mask = XEN_PT_BAR_MEM_RO_MASK | (r_size - 1);
- }
- break;
- case XEN_PT_BAR_FLAG_IO:
- bar_emu_mask = XEN_PT_BAR_IO_EMU_MASK;
- bar_ro_mask = XEN_PT_BAR_IO_RO_MASK | (r_size - 1);
- break;
- case XEN_PT_BAR_FLAG_UPPER:
- bar_emu_mask = XEN_PT_BAR_ALLF;
- bar_ro_mask = r_size ? r_size - 1 : 0;
- break;
- default:
- break;
- }
-
- /* modify emulate register */
- writable_mask = bar_emu_mask & ~bar_ro_mask & valid_mask;
- *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
-
- /* check whether we need to update the virtual region address or not */
- switch (s->bases[index].bar_flag) {
- case XEN_PT_BAR_FLAG_UPPER:
- case XEN_PT_BAR_FLAG_MEM:
- /* nothing to do */
- break;
- case XEN_PT_BAR_FLAG_IO:
- /* nothing to do */
- break;
- default:
- break;
- }
-
- /* create value for writing to I/O device register */
- *val = XEN_PT_MERGE_VALUE(*val, dev_value, 0);
-
- return 0;
-}
-
-/* write Exp ROM BAR */
-static int xen_pt_exp_rom_bar_reg_write(XenPCIPassthroughState *s,
- XenPTReg *cfg_entry, uint32_t *val,
- uint32_t dev_value, uint32_t valid_mask)
-{
- XenPTRegInfo *reg = cfg_entry->reg;
- XenPTRegion *base = NULL;
- PCIDevice *d = (PCIDevice *)&s->dev;
- uint32_t writable_mask = 0;
- uint32_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
- pcibus_t r_size = 0;
- uint32_t bar_ro_mask = 0;
- uint32_t *data = cfg_entry->ptr.word;
-
- r_size = d->io_regions[PCI_ROM_SLOT].size;
- base = &s->bases[PCI_ROM_SLOT];
- /* align memory type resource size */
- r_size = xen_pt_get_emul_size(base->bar_flag, r_size);
-
- /* set emulate mask and read-only mask */
- bar_ro_mask = (reg->ro_mask | (r_size - 1)) & ~PCI_ROM_ADDRESS_ENABLE;
-
- /* modify emulate register */
- writable_mask = ~bar_ro_mask & valid_mask;
- *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
-
- /* create value for writing to I/O device register */
- *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
-
- return 0;
-}
-
-static int xen_pt_intel_opregion_read(XenPCIPassthroughState *s,
- XenPTReg *cfg_entry,
- uint32_t *value, uint32_t valid_mask)
-{
- *value = igd_read_opregion(s);
- return 0;
-}
-
-static int xen_pt_intel_opregion_write(XenPCIPassthroughState *s,
- XenPTReg *cfg_entry, uint32_t *value,
- uint32_t dev_value, uint32_t valid_mask)
-{
- igd_write_opregion(s, *value);
- return 0;
-}
-
-/* Header Type0 reg static information table */
-static XenPTRegInfo xen_pt_emu_reg_header0[] = {
- /* Vendor ID reg */
- {
- .offset = PCI_VENDOR_ID,
- .size = 2,
- .init_val = 0x0000,
- .ro_mask = 0xFFFF,
- .emu_mask = 0xFFFF,
- .init = xen_pt_vendor_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_word_reg_write,
- },
- /* Device ID reg */
- {
- .offset = PCI_DEVICE_ID,
- .size = 2,
- .init_val = 0x0000,
- .ro_mask = 0xFFFF,
- .emu_mask = 0xFFFF,
- .init = xen_pt_device_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_word_reg_write,
- },
- /* Command reg */
- {
- .offset = PCI_COMMAND,
- .size = 2,
- .init_val = 0x0000,
- .res_mask = 0xF880,
- .emu_mask = 0x0743,
- .init = xen_pt_common_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_cmd_reg_write,
- },
- /* Capabilities Pointer reg */
- {
- .offset = PCI_CAPABILITY_LIST,
- .size = 1,
- .init_val = 0x00,
- .ro_mask = 0xFF,
- .emu_mask = 0xFF,
- .init = xen_pt_ptr_reg_init,
- .u.b.read = xen_pt_byte_reg_read,
- .u.b.write = xen_pt_byte_reg_write,
- },
- /* Status reg */
- /* use emulated Cap Ptr value to initialize,
- * so need to be declared after Cap Ptr reg
- */
- {
- .offset = PCI_STATUS,
- .size = 2,
- .init_val = 0x0000,
- .res_mask = 0x0007,
- .ro_mask = 0x06F8,
- .rw1c_mask = 0xF900,
- .emu_mask = 0x0010,
- .init = xen_pt_status_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_word_reg_write,
- },
- /* Cache Line Size reg */
- {
- .offset = PCI_CACHE_LINE_SIZE,
- .size = 1,
- .init_val = 0x00,
- .ro_mask = 0x00,
- .emu_mask = 0xFF,
- .init = xen_pt_common_reg_init,
- .u.b.read = xen_pt_byte_reg_read,
- .u.b.write = xen_pt_byte_reg_write,
- },
- /* Latency Timer reg */
- {
- .offset = PCI_LATENCY_TIMER,
- .size = 1,
- .init_val = 0x00,
- .ro_mask = 0x00,
- .emu_mask = 0xFF,
- .init = xen_pt_common_reg_init,
- .u.b.read = xen_pt_byte_reg_read,
- .u.b.write = xen_pt_byte_reg_write,
- },
- /* Header Type reg */
- {
- .offset = PCI_HEADER_TYPE,
- .size = 1,
- .init_val = 0x00,
- .ro_mask = 0xFF,
- .emu_mask = 0x00,
- .init = xen_pt_header_type_reg_init,
- .u.b.read = xen_pt_byte_reg_read,
- .u.b.write = xen_pt_byte_reg_write,
- },
- /* Interrupt Line reg */
- {
- .offset = PCI_INTERRUPT_LINE,
- .size = 1,
- .init_val = 0x00,
- .ro_mask = 0x00,
- .emu_mask = 0xFF,
- .init = xen_pt_common_reg_init,
- .u.b.read = xen_pt_byte_reg_read,
- .u.b.write = xen_pt_byte_reg_write,
- },
- /* Interrupt Pin reg */
- {
- .offset = PCI_INTERRUPT_PIN,
- .size = 1,
- .init_val = 0x00,
- .ro_mask = 0xFF,
- .emu_mask = 0xFF,
- .init = xen_pt_irqpin_reg_init,
- .u.b.read = xen_pt_byte_reg_read,
- .u.b.write = xen_pt_byte_reg_write,
- },
- /* BAR 0 reg */
- /* mask of BAR need to be decided later, depends on IO/MEM type */
- {
- .offset = PCI_BASE_ADDRESS_0,
- .size = 4,
- .init_val = 0x00000000,
- .init = xen_pt_bar_reg_init,
- .u.dw.read = xen_pt_bar_reg_read,
- .u.dw.write = xen_pt_bar_reg_write,
- },
- /* BAR 1 reg */
- {
- .offset = PCI_BASE_ADDRESS_1,
- .size = 4,
- .init_val = 0x00000000,
- .init = xen_pt_bar_reg_init,
- .u.dw.read = xen_pt_bar_reg_read,
- .u.dw.write = xen_pt_bar_reg_write,
- },
- /* BAR 2 reg */
- {
- .offset = PCI_BASE_ADDRESS_2,
- .size = 4,
- .init_val = 0x00000000,
- .init = xen_pt_bar_reg_init,
- .u.dw.read = xen_pt_bar_reg_read,
- .u.dw.write = xen_pt_bar_reg_write,
- },
- /* BAR 3 reg */
- {
- .offset = PCI_BASE_ADDRESS_3,
- .size = 4,
- .init_val = 0x00000000,
- .init = xen_pt_bar_reg_init,
- .u.dw.read = xen_pt_bar_reg_read,
- .u.dw.write = xen_pt_bar_reg_write,
- },
- /* BAR 4 reg */
- {
- .offset = PCI_BASE_ADDRESS_4,
- .size = 4,
- .init_val = 0x00000000,
- .init = xen_pt_bar_reg_init,
- .u.dw.read = xen_pt_bar_reg_read,
- .u.dw.write = xen_pt_bar_reg_write,
- },
- /* BAR 5 reg */
- {
- .offset = PCI_BASE_ADDRESS_5,
- .size = 4,
- .init_val = 0x00000000,
- .init = xen_pt_bar_reg_init,
- .u.dw.read = xen_pt_bar_reg_read,
- .u.dw.write = xen_pt_bar_reg_write,
- },
- /* Expansion ROM BAR reg */
- {
- .offset = PCI_ROM_ADDRESS,
- .size = 4,
- .init_val = 0x00000000,
- .ro_mask = ~PCI_ROM_ADDRESS_MASK & ~PCI_ROM_ADDRESS_ENABLE,
- .emu_mask = (uint32_t)PCI_ROM_ADDRESS_MASK,
- .init = xen_pt_bar_reg_init,
- .u.dw.read = xen_pt_long_reg_read,
- .u.dw.write = xen_pt_exp_rom_bar_reg_write,
- },
- {
- .size = 0,
- },
-};
-
-
-/*********************************
- * Vital Product Data Capability
- */
-
-/* Vital Product Data Capability Structure reg static information table */
-static XenPTRegInfo xen_pt_emu_reg_vpd[] = {
- {
- .offset = PCI_CAP_LIST_NEXT,
- .size = 1,
- .init_val = 0x00,
- .ro_mask = 0xFF,
- .emu_mask = 0xFF,
- .init = xen_pt_ptr_reg_init,
- .u.b.read = xen_pt_byte_reg_read,
- .u.b.write = xen_pt_byte_reg_write,
- },
- {
- .offset = PCI_VPD_ADDR,
- .size = 2,
- .ro_mask = 0x0003,
- .emu_mask = 0x0003,
- .init = xen_pt_common_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_word_reg_write,
- },
- {
- .size = 0,
- },
-};
-
-
-/**************************************
- * Vendor Specific Capability
- */
-
-/* Vendor Specific Capability Structure reg static information table */
-static XenPTRegInfo xen_pt_emu_reg_vendor[] = {
- {
- .offset = PCI_CAP_LIST_NEXT,
- .size = 1,
- .init_val = 0x00,
- .ro_mask = 0xFF,
- .emu_mask = 0xFF,
- .init = xen_pt_ptr_reg_init,
- .u.b.read = xen_pt_byte_reg_read,
- .u.b.write = xen_pt_byte_reg_write,
- },
- {
- .size = 0,
- },
-};
-
-
-/*****************************
- * PCI Express Capability
- */
-
-static inline uint8_t get_capability_version(XenPCIPassthroughState *s,
- uint32_t offset)
-{
- uint8_t flag;
- if (xen_host_pci_get_byte(&s->real_device, offset + PCI_EXP_FLAGS, &flag)) {
- return 0;
- }
- return flag & PCI_EXP_FLAGS_VERS;
-}
-
-static inline uint8_t get_device_type(XenPCIPassthroughState *s,
- uint32_t offset)
-{
- uint8_t flag;
- if (xen_host_pci_get_byte(&s->real_device, offset + PCI_EXP_FLAGS, &flag)) {
- return 0;
- }
- return (flag & PCI_EXP_FLAGS_TYPE) >> 4;
-}
-
-/* initialize Link Control register */
-static int xen_pt_linkctrl_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
-{
- uint8_t cap_ver = get_capability_version(s, real_offset - reg->offset);
- uint8_t dev_type = get_device_type(s, real_offset - reg->offset);
-
- /* no need to initialize in case of Root Complex Integrated Endpoint
- * with cap_ver 1.x
- */
- if ((dev_type == PCI_EXP_TYPE_RC_END) && (cap_ver == 1)) {
- *data = XEN_PT_INVALID_REG;
- }
-
- *data = reg->init_val;
- return 0;
-}
-/* initialize Device Control 2 register */
-static int xen_pt_devctrl2_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
-{
- uint8_t cap_ver = get_capability_version(s, real_offset - reg->offset);
-
- /* no need to initialize in case of cap_ver 1.x */
- if (cap_ver == 1) {
- *data = XEN_PT_INVALID_REG;
- }
-
- *data = reg->init_val;
- return 0;
-}
-/* initialize Link Control 2 register */
-static int xen_pt_linkctrl2_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
-{
- uint8_t cap_ver = get_capability_version(s, real_offset - reg->offset);
- uint32_t reg_field = 0;
-
- /* no need to initialize in case of cap_ver 1.x */
- if (cap_ver == 1) {
- reg_field = XEN_PT_INVALID_REG;
- } else {
- /* set Supported Link Speed */
- uint8_t lnkcap;
- int rc;
- rc = xen_host_pci_get_byte(&s->real_device,
- real_offset - reg->offset + PCI_EXP_LNKCAP,
- &lnkcap);
- if (rc) {
- return rc;
- }
- reg_field |= PCI_EXP_LNKCAP_SLS & lnkcap;
- }
-
- *data = reg_field;
- return 0;
-}
-
-/* PCI Express Capability Structure reg static information table */
-static XenPTRegInfo xen_pt_emu_reg_pcie[] = {
- /* Next Pointer reg */
- {
- .offset = PCI_CAP_LIST_NEXT,
- .size = 1,
- .init_val = 0x00,
- .ro_mask = 0xFF,
- .emu_mask = 0xFF,
- .init = xen_pt_ptr_reg_init,
- .u.b.read = xen_pt_byte_reg_read,
- .u.b.write = xen_pt_byte_reg_write,
- },
- /* Device Capabilities reg */
- {
- .offset = PCI_EXP_DEVCAP,
- .size = 4,
- .init_val = 0x00000000,
- .ro_mask = 0xFFFFFFFF,
- .emu_mask = 0x10000000,
- .init = xen_pt_common_reg_init,
- .u.dw.read = xen_pt_long_reg_read,
- .u.dw.write = xen_pt_long_reg_write,
- },
- /* Device Control reg */
- {
- .offset = PCI_EXP_DEVCTL,
- .size = 2,
- .init_val = 0x2810,
- .ro_mask = 0x8400,
- .emu_mask = 0xFFFF,
- .init = xen_pt_common_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_word_reg_write,
- },
- /* Device Status reg */
- {
- .offset = PCI_EXP_DEVSTA,
- .size = 2,
- .res_mask = 0xFFC0,
- .ro_mask = 0x0030,
- .rw1c_mask = 0x000F,
- .init = xen_pt_common_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_word_reg_write,
- },
- /* Link Control reg */
- {
- .offset = PCI_EXP_LNKCTL,
- .size = 2,
- .init_val = 0x0000,
- .ro_mask = 0xFC34,
- .emu_mask = 0xFFFF,
- .init = xen_pt_linkctrl_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_word_reg_write,
- },
- /* Link Status reg */
- {
- .offset = PCI_EXP_LNKSTA,
- .size = 2,
- .ro_mask = 0x3FFF,
- .rw1c_mask = 0xC000,
- .init = xen_pt_common_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_word_reg_write,
- },
- /* Device Control 2 reg */
- {
- .offset = 0x28,
- .size = 2,
- .init_val = 0x0000,
- .ro_mask = 0xFFE0,
- .emu_mask = 0xFFFF,
- .init = xen_pt_devctrl2_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_word_reg_write,
- },
- /* Link Control 2 reg */
- {
- .offset = 0x30,
- .size = 2,
- .init_val = 0x0000,
- .ro_mask = 0xE040,
- .emu_mask = 0xFFFF,
- .init = xen_pt_linkctrl2_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_word_reg_write,
- },
- {
- .size = 0,
- },
-};
-
-
-/*********************************
- * Power Management Capability
- */
-
-/* Power Management Capability reg static information table */
-static XenPTRegInfo xen_pt_emu_reg_pm[] = {
- /* Next Pointer reg */
- {
- .offset = PCI_CAP_LIST_NEXT,
- .size = 1,
- .init_val = 0x00,
- .ro_mask = 0xFF,
- .emu_mask = 0xFF,
- .init = xen_pt_ptr_reg_init,
- .u.b.read = xen_pt_byte_reg_read,
- .u.b.write = xen_pt_byte_reg_write,
- },
- /* Power Management Capabilities reg */
- {
- .offset = PCI_CAP_FLAGS,
- .size = 2,
- .init_val = 0x0000,
- .ro_mask = 0xFFFF,
- .emu_mask = 0xF9C8,
- .init = xen_pt_common_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_word_reg_write,
- },
- /* PCI Power Management Control/Status reg */
- {
- .offset = PCI_PM_CTRL,
- .size = 2,
- .init_val = 0x0008,
- .res_mask = 0x00F0,
- .ro_mask = 0x610C,
- .rw1c_mask = 0x8000,
- .emu_mask = 0x810B,
- .init = xen_pt_common_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_word_reg_write,
- },
- {
- .size = 0,
- },
-};
-
-
-/********************************
- * MSI Capability
- */
-
-/* Helper */
-#define xen_pt_msi_check_type(offset, flags, what) \
- ((offset) == ((flags) & PCI_MSI_FLAGS_64BIT ? \
- PCI_MSI_##what##_64 : PCI_MSI_##what##_32))
-
-/* Message Control register */
-static int xen_pt_msgctrl_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
-{
- XenPTMSI *msi = s->msi;
- uint16_t reg_field;
- int rc;
-
- /* use I/O device register's value as initial value */
- rc = xen_host_pci_get_word(&s->real_device, real_offset, &reg_field);
- if (rc) {
- return rc;
- }
- if (reg_field & PCI_MSI_FLAGS_ENABLE) {
- XEN_PT_LOG(&s->dev, "MSI already enabled, disabling it first\n");
- xen_host_pci_set_word(&s->real_device, real_offset,
- reg_field & ~PCI_MSI_FLAGS_ENABLE);
- }
- msi->flags |= reg_field;
- msi->ctrl_offset = real_offset;
- msi->initialized = false;
- msi->mapped = false;
-
- *data = reg->init_val;
- return 0;
-}
-static int xen_pt_msgctrl_reg_write(XenPCIPassthroughState *s,
- XenPTReg *cfg_entry, uint16_t *val,
- uint16_t dev_value, uint16_t valid_mask)
-{
- XenPTRegInfo *reg = cfg_entry->reg;
- XenPTMSI *msi = s->msi;
- uint16_t writable_mask = 0;
- uint16_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
- uint16_t *data = cfg_entry->ptr.half_word;
-
- /* Currently no support for multi-vector */
- if (*val & PCI_MSI_FLAGS_QSIZE) {
- XEN_PT_WARN(&s->dev, "Tries to set more than 1 vector ctrl %x\n", *val);
- }
-
- /* modify emulate register */
- writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
- *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
- msi->flags |= *data & ~PCI_MSI_FLAGS_ENABLE;
-
- /* create value for writing to I/O device register */
- *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
-
- /* update MSI */
- if (*val & PCI_MSI_FLAGS_ENABLE) {
- /* setup MSI pirq for the first time */
- if (!msi->initialized) {
- /* Init physical one */
- XEN_PT_LOG(&s->dev, "setup MSI (register: %x).\n", *val);
- if (xen_pt_msi_setup(s)) {
- /* We do not broadcast the error to the framework code, so
- * that MSI errors are contained in MSI emulation code and
- * QEMU can go on running.
- * Guest MSI would be actually not working.
- */
- *val &= ~PCI_MSI_FLAGS_ENABLE;
- XEN_PT_WARN(&s->dev, "Can not map MSI (register: %x)!\n", *val);
- return 0;
- }
- if (xen_pt_msi_update(s)) {
- *val &= ~PCI_MSI_FLAGS_ENABLE;
- XEN_PT_WARN(&s->dev, "Can not bind MSI (register: %x)!\n", *val);
- return 0;
- }
- msi->initialized = true;
- msi->mapped = true;
- }
- msi->flags |= PCI_MSI_FLAGS_ENABLE;
- } else if (msi->mapped) {
- xen_pt_msi_disable(s);
- }
-
- return 0;
-}
-
-/* initialize Message Upper Address register */
-static int xen_pt_msgaddr64_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
-{
- /* no need to initialize in case of 32 bit type */
- if (!(s->msi->flags & PCI_MSI_FLAGS_64BIT)) {
- *data = XEN_PT_INVALID_REG;
- } else {
- *data = reg->init_val;
- }
-
- return 0;
-}
-/* this function will be called twice (for 32 bit and 64 bit type) */
-/* initialize Message Data register */
-static int xen_pt_msgdata_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
-{
- uint32_t flags = s->msi->flags;
- uint32_t offset = reg->offset;
-
- /* check the offset whether matches the type or not */
- if (xen_pt_msi_check_type(offset, flags, DATA)) {
- *data = reg->init_val;
- } else {
- *data = XEN_PT_INVALID_REG;
- }
- return 0;
-}
-
-/* this function will be called twice (for 32 bit and 64 bit type) */
-/* initialize Mask register */
-static int xen_pt_mask_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
-{
- uint32_t flags = s->msi->flags;
-
- /* check the offset whether matches the type or not */
- if (!(flags & PCI_MSI_FLAGS_MASKBIT)) {
- *data = XEN_PT_INVALID_REG;
- } else if (xen_pt_msi_check_type(reg->offset, flags, MASK)) {
- *data = reg->init_val;
- } else {
- *data = XEN_PT_INVALID_REG;
- }
- return 0;
-}
-
-/* this function will be called twice (for 32 bit and 64 bit type) */
-/* initialize Pending register */
-static int xen_pt_pending_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
-{
- uint32_t flags = s->msi->flags;
-
- /* check the offset whether matches the type or not */
- if (!(flags & PCI_MSI_FLAGS_MASKBIT)) {
- *data = XEN_PT_INVALID_REG;
- } else if (xen_pt_msi_check_type(reg->offset, flags, PENDING)) {
- *data = reg->init_val;
- } else {
- *data = XEN_PT_INVALID_REG;
- }
- return 0;
-}
-
-/* write Message Address register */
-static int xen_pt_msgaddr32_reg_write(XenPCIPassthroughState *s,
- XenPTReg *cfg_entry, uint32_t *val,
- uint32_t dev_value, uint32_t valid_mask)
-{
- XenPTRegInfo *reg = cfg_entry->reg;
- uint32_t writable_mask = 0;
- uint32_t old_addr = *cfg_entry->ptr.word;
- uint32_t *data = cfg_entry->ptr.word;
-
- /* modify emulate register */
- writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
- *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
- s->msi->addr_lo = *data;
-
- /* create value for writing to I/O device register */
- *val = XEN_PT_MERGE_VALUE(*val, dev_value, 0);
-
- /* update MSI */
- if (*data != old_addr) {
- if (s->msi->mapped) {
- xen_pt_msi_update(s);
- }
- }
-
- return 0;
-}
-/* write Message Upper Address register */
-static int xen_pt_msgaddr64_reg_write(XenPCIPassthroughState *s,
- XenPTReg *cfg_entry, uint32_t *val,
- uint32_t dev_value, uint32_t valid_mask)
-{
- XenPTRegInfo *reg = cfg_entry->reg;
- uint32_t writable_mask = 0;
- uint32_t old_addr = *cfg_entry->ptr.word;
- uint32_t *data = cfg_entry->ptr.word;
-
- /* check whether the type is 64 bit or not */
- if (!(s->msi->flags & PCI_MSI_FLAGS_64BIT)) {
- XEN_PT_ERR(&s->dev,
- "Can't write to the upper address without 64 bit support\n");
- return -1;
- }
-
- /* modify emulate register */
- writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
- *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
- /* update the msi_info too */
- s->msi->addr_hi = *data;
-
- /* create value for writing to I/O device register */
- *val = XEN_PT_MERGE_VALUE(*val, dev_value, 0);
-
- /* update MSI */
- if (*data != old_addr) {
- if (s->msi->mapped) {
- xen_pt_msi_update(s);
- }
- }
-
- return 0;
-}
-
-
-/* this function will be called twice (for 32 bit and 64 bit type) */
-/* write Message Data register */
-static int xen_pt_msgdata_reg_write(XenPCIPassthroughState *s,
- XenPTReg *cfg_entry, uint16_t *val,
- uint16_t dev_value, uint16_t valid_mask)
-{
- XenPTRegInfo *reg = cfg_entry->reg;
- XenPTMSI *msi = s->msi;
- uint16_t writable_mask = 0;
- uint16_t old_data = *cfg_entry->ptr.half_word;
- uint32_t offset = reg->offset;
- uint16_t *data = cfg_entry->ptr.half_word;
-
- /* check the offset whether matches the type or not */
- if (!xen_pt_msi_check_type(offset, msi->flags, DATA)) {
- /* exit I/O emulator */
- XEN_PT_ERR(&s->dev, "the offset does not match the 32/64 bit type!\n");
- return -1;
- }
-
- /* modify emulate register */
- writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
- *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
- /* update the msi_info too */
- msi->data = *data;
-
- /* create value for writing to I/O device register */
- *val = XEN_PT_MERGE_VALUE(*val, dev_value, 0);
-
- /* update MSI */
- if (*data != old_data) {
- if (msi->mapped) {
- xen_pt_msi_update(s);
- }
- }
-
- return 0;
-}
-
-/* MSI Capability Structure reg static information table */
-static XenPTRegInfo xen_pt_emu_reg_msi[] = {
- /* Next Pointer reg */
- {
- .offset = PCI_CAP_LIST_NEXT,
- .size = 1,
- .init_val = 0x00,
- .ro_mask = 0xFF,
- .emu_mask = 0xFF,
- .init = xen_pt_ptr_reg_init,
- .u.b.read = xen_pt_byte_reg_read,
- .u.b.write = xen_pt_byte_reg_write,
- },
- /* Message Control reg */
- {
- .offset = PCI_MSI_FLAGS,
- .size = 2,
- .init_val = 0x0000,
- .res_mask = 0xFE00,
- .ro_mask = 0x018E,
- .emu_mask = 0x017E,
- .init = xen_pt_msgctrl_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_msgctrl_reg_write,
- },
- /* Message Address reg */
- {
- .offset = PCI_MSI_ADDRESS_LO,
- .size = 4,
- .init_val = 0x00000000,
- .ro_mask = 0x00000003,
- .emu_mask = 0xFFFFFFFF,
- .init = xen_pt_common_reg_init,
- .u.dw.read = xen_pt_long_reg_read,
- .u.dw.write = xen_pt_msgaddr32_reg_write,
- },
- /* Message Upper Address reg (if PCI_MSI_FLAGS_64BIT set) */
- {
- .offset = PCI_MSI_ADDRESS_HI,
- .size = 4,
- .init_val = 0x00000000,
- .ro_mask = 0x00000000,
- .emu_mask = 0xFFFFFFFF,
- .init = xen_pt_msgaddr64_reg_init,
- .u.dw.read = xen_pt_long_reg_read,
- .u.dw.write = xen_pt_msgaddr64_reg_write,
- },
- /* Message Data reg (16 bits of data for 32-bit devices) */
- {
- .offset = PCI_MSI_DATA_32,
- .size = 2,
- .init_val = 0x0000,
- .ro_mask = 0x0000,
- .emu_mask = 0xFFFF,
- .init = xen_pt_msgdata_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_msgdata_reg_write,
- },
- /* Message Data reg (16 bits of data for 64-bit devices) */
- {
- .offset = PCI_MSI_DATA_64,
- .size = 2,
- .init_val = 0x0000,
- .ro_mask = 0x0000,
- .emu_mask = 0xFFFF,
- .init = xen_pt_msgdata_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_msgdata_reg_write,
- },
- /* Mask reg (if PCI_MSI_FLAGS_MASKBIT set, for 32-bit devices) */
- {
- .offset = PCI_MSI_MASK_32,
- .size = 4,
- .init_val = 0x00000000,
- .ro_mask = 0xFFFFFFFF,
- .emu_mask = 0xFFFFFFFF,
- .init = xen_pt_mask_reg_init,
- .u.dw.read = xen_pt_long_reg_read,
- .u.dw.write = xen_pt_long_reg_write,
- },
- /* Mask reg (if PCI_MSI_FLAGS_MASKBIT set, for 64-bit devices) */
- {
- .offset = PCI_MSI_MASK_64,
- .size = 4,
- .init_val = 0x00000000,
- .ro_mask = 0xFFFFFFFF,
- .emu_mask = 0xFFFFFFFF,
- .init = xen_pt_mask_reg_init,
- .u.dw.read = xen_pt_long_reg_read,
- .u.dw.write = xen_pt_long_reg_write,
- },
- /* Pending reg (if PCI_MSI_FLAGS_MASKBIT set, for 32-bit devices) */
- {
- .offset = PCI_MSI_MASK_32 + 4,
- .size = 4,
- .init_val = 0x00000000,
- .ro_mask = 0xFFFFFFFF,
- .emu_mask = 0x00000000,
- .init = xen_pt_pending_reg_init,
- .u.dw.read = xen_pt_long_reg_read,
- .u.dw.write = xen_pt_long_reg_write,
- },
- /* Pending reg (if PCI_MSI_FLAGS_MASKBIT set, for 64-bit devices) */
- {
- .offset = PCI_MSI_MASK_64 + 4,
- .size = 4,
- .init_val = 0x00000000,
- .ro_mask = 0xFFFFFFFF,
- .emu_mask = 0x00000000,
- .init = xen_pt_pending_reg_init,
- .u.dw.read = xen_pt_long_reg_read,
- .u.dw.write = xen_pt_long_reg_write,
- },
- {
- .size = 0,
- },
-};
-
-
-/**************************************
- * MSI-X Capability
- */
-
-/* Message Control register for MSI-X */
-static int xen_pt_msixctrl_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
-{
- uint16_t reg_field;
- int rc;
-
- /* use I/O device register's value as initial value */
- rc = xen_host_pci_get_word(&s->real_device, real_offset, &reg_field);
- if (rc) {
- return rc;
- }
- if (reg_field & PCI_MSIX_FLAGS_ENABLE) {
- XEN_PT_LOG(&s->dev, "MSIX already enabled, disabling it first\n");
- xen_host_pci_set_word(&s->real_device, real_offset,
- reg_field & ~PCI_MSIX_FLAGS_ENABLE);
- }
-
- s->msix->ctrl_offset = real_offset;
-
- *data = reg->init_val;
- return 0;
-}
-static int xen_pt_msixctrl_reg_write(XenPCIPassthroughState *s,
- XenPTReg *cfg_entry, uint16_t *val,
- uint16_t dev_value, uint16_t valid_mask)
-{
- XenPTRegInfo *reg = cfg_entry->reg;
- uint16_t writable_mask = 0;
- uint16_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
- int debug_msix_enabled_old;
- uint16_t *data = cfg_entry->ptr.half_word;
-
- /* modify emulate register */
- writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
- *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
-
- /* create value for writing to I/O device register */
- *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
-
- /* update MSI-X */
- if ((*val & PCI_MSIX_FLAGS_ENABLE)
- && !(*val & PCI_MSIX_FLAGS_MASKALL)) {
- xen_pt_msix_update(s);
- } else if (!(*val & PCI_MSIX_FLAGS_ENABLE) && s->msix->enabled) {
- xen_pt_msix_disable(s);
- }
-
- s->msix->maskall = *val & PCI_MSIX_FLAGS_MASKALL;
-
- debug_msix_enabled_old = s->msix->enabled;
- s->msix->enabled = !!(*val & PCI_MSIX_FLAGS_ENABLE);
- if (s->msix->enabled != debug_msix_enabled_old) {
- XEN_PT_LOG(&s->dev, "%s MSI-X\n",
- s->msix->enabled ? "enable" : "disable");
- }
-
- return 0;
-}
-
-/* MSI-X Capability Structure reg static information table */
-static XenPTRegInfo xen_pt_emu_reg_msix[] = {
- /* Next Pointer reg */
- {
- .offset = PCI_CAP_LIST_NEXT,
- .size = 1,
- .init_val = 0x00,
- .ro_mask = 0xFF,
- .emu_mask = 0xFF,
- .init = xen_pt_ptr_reg_init,
- .u.b.read = xen_pt_byte_reg_read,
- .u.b.write = xen_pt_byte_reg_write,
- },
- /* Message Control reg */
- {
- .offset = PCI_MSI_FLAGS,
- .size = 2,
- .init_val = 0x0000,
- .res_mask = 0x3800,
- .ro_mask = 0x07FF,
- .emu_mask = 0x0000,
- .init = xen_pt_msixctrl_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_msixctrl_reg_write,
- },
- {
- .size = 0,
- },
-};
-
-static XenPTRegInfo xen_pt_emu_reg_igd_opregion[] = {
- /* Intel IGFX OpRegion reg */
- {
- .offset = 0x0,
- .size = 4,
- .init_val = 0,
- .u.dw.read = xen_pt_intel_opregion_read,
- .u.dw.write = xen_pt_intel_opregion_write,
- },
- {
- .size = 0,
- },
-};
-
-/****************************
- * Capabilities
- */
-
-/* capability structure register group size functions */
-
-static int xen_pt_reg_grp_size_init(XenPCIPassthroughState *s,
- const XenPTRegGroupInfo *grp_reg,
- uint32_t base_offset, uint8_t *size)
-{
- *size = grp_reg->grp_size;
- return 0;
-}
-/* get Vendor Specific Capability Structure register group size */
-static int xen_pt_vendor_size_init(XenPCIPassthroughState *s,
- const XenPTRegGroupInfo *grp_reg,
- uint32_t base_offset, uint8_t *size)
-{
- return xen_host_pci_get_byte(&s->real_device, base_offset + 0x02, size);
-}
-/* get PCI Express Capability Structure register group size */
-static int xen_pt_pcie_size_init(XenPCIPassthroughState *s,
- const XenPTRegGroupInfo *grp_reg,
- uint32_t base_offset, uint8_t *size)
-{
- PCIDevice *d = &s->dev;
- uint8_t version = get_capability_version(s, base_offset);
- uint8_t type = get_device_type(s, base_offset);
- uint8_t pcie_size = 0;
-
-
- /* calculate size depend on capability version and device/port type */
- /* in case of PCI Express Base Specification Rev 1.x */
- if (version == 1) {
- /* The PCI Express Capabilities, Device Capabilities, and Device
- * Status/Control registers are required for all PCI Express devices.
- * The Link Capabilities and Link Status/Control are required for all
- * Endpoints that are not Root Complex Integrated Endpoints. Endpoints
- * are not required to implement registers other than those listed
- * above and terminate the capability structure.
- */
- switch (type) {
- case PCI_EXP_TYPE_ENDPOINT:
- case PCI_EXP_TYPE_LEG_END:
- pcie_size = 0x14;
- break;
- case PCI_EXP_TYPE_RC_END:
- /* has no link */
- pcie_size = 0x0C;
- break;
- /* only EndPoint passthrough is supported */
- case PCI_EXP_TYPE_ROOT_PORT:
- case PCI_EXP_TYPE_UPSTREAM:
- case PCI_EXP_TYPE_DOWNSTREAM:
- case PCI_EXP_TYPE_PCI_BRIDGE:
- case PCI_EXP_TYPE_PCIE_BRIDGE:
- case PCI_EXP_TYPE_RC_EC:
- default:
- XEN_PT_ERR(d, "Unsupported device/port type %#x.\n", type);
- return -1;
- }
- }
- /* in case of PCI Express Base Specification Rev 2.0 */
- else if (version == 2) {
- switch (type) {
- case PCI_EXP_TYPE_ENDPOINT:
- case PCI_EXP_TYPE_LEG_END:
- case PCI_EXP_TYPE_RC_END:
- /* For Functions that do not implement the registers,
- * these spaces must be hardwired to 0b.
- */
- pcie_size = 0x3C;
- break;
- /* only EndPoint passthrough is supported */
- case PCI_EXP_TYPE_ROOT_PORT:
- case PCI_EXP_TYPE_UPSTREAM:
- case PCI_EXP_TYPE_DOWNSTREAM:
- case PCI_EXP_TYPE_PCI_BRIDGE:
- case PCI_EXP_TYPE_PCIE_BRIDGE:
- case PCI_EXP_TYPE_RC_EC:
- default:
- XEN_PT_ERR(d, "Unsupported device/port type %#x.\n", type);
- return -1;
- }
- } else {
- XEN_PT_ERR(d, "Unsupported capability version %#x.\n", version);
- return -1;
- }
-
- *size = pcie_size;
- return 0;
-}
-/* get MSI Capability Structure register group size */
-static int xen_pt_msi_size_init(XenPCIPassthroughState *s,
- const XenPTRegGroupInfo *grp_reg,
- uint32_t base_offset, uint8_t *size)
-{
- uint16_t msg_ctrl = 0;
- uint8_t msi_size = 0xa;
- int rc;
-
- rc = xen_host_pci_get_word(&s->real_device, base_offset + PCI_MSI_FLAGS,
- &msg_ctrl);
- if (rc) {
- return rc;
- }
- /* check if 64-bit address is capable of per-vector masking */
- if (msg_ctrl & PCI_MSI_FLAGS_64BIT) {
- msi_size += 4;
- }
- if (msg_ctrl & PCI_MSI_FLAGS_MASKBIT) {
- msi_size += 10;
- }
-
- s->msi = g_new0(XenPTMSI, 1);
- s->msi->pirq = XEN_PT_UNASSIGNED_PIRQ;
-
- *size = msi_size;
- return 0;
-}
-/* get MSI-X Capability Structure register group size */
-static int xen_pt_msix_size_init(XenPCIPassthroughState *s,
- const XenPTRegGroupInfo *grp_reg,
- uint32_t base_offset, uint8_t *size)
-{
- int rc = 0;
-
- rc = xen_pt_msix_init(s, base_offset);
-
- if (rc < 0) {
- XEN_PT_ERR(&s->dev, "Internal error: Invalid xen_pt_msix_init.\n");
- return rc;
- }
-
- *size = grp_reg->grp_size;
- return 0;
-}
-
-
-static const XenPTRegGroupInfo xen_pt_emu_reg_grps[] = {
- /* Header Type0 reg group */
- {
- .grp_id = 0xFF,
- .grp_type = XEN_PT_GRP_TYPE_EMU,
- .grp_size = 0x40,
- .size_init = xen_pt_reg_grp_size_init,
- .emu_regs = xen_pt_emu_reg_header0,
- },
- /* PCI PowerManagement Capability reg group */
- {
- .grp_id = PCI_CAP_ID_PM,
- .grp_type = XEN_PT_GRP_TYPE_EMU,
- .grp_size = PCI_PM_SIZEOF,
- .size_init = xen_pt_reg_grp_size_init,
- .emu_regs = xen_pt_emu_reg_pm,
- },
- /* AGP Capability Structure reg group */
- {
- .grp_id = PCI_CAP_ID_AGP,
- .grp_type = XEN_PT_GRP_TYPE_HARDWIRED,
- .grp_size = 0x30,
- .size_init = xen_pt_reg_grp_size_init,
- },
- /* Vital Product Data Capability Structure reg group */
- {
- .grp_id = PCI_CAP_ID_VPD,
- .grp_type = XEN_PT_GRP_TYPE_EMU,
- .grp_size = 0x08,
- .size_init = xen_pt_reg_grp_size_init,
- .emu_regs = xen_pt_emu_reg_vpd,
- },
- /* Slot Identification reg group */
- {
- .grp_id = PCI_CAP_ID_SLOTID,
- .grp_type = XEN_PT_GRP_TYPE_HARDWIRED,
- .grp_size = 0x04,
- .size_init = xen_pt_reg_grp_size_init,
- },
- /* MSI Capability Structure reg group */
- {
- .grp_id = PCI_CAP_ID_MSI,
- .grp_type = XEN_PT_GRP_TYPE_EMU,
- .grp_size = 0xFF,
- .size_init = xen_pt_msi_size_init,
- .emu_regs = xen_pt_emu_reg_msi,
- },
- /* PCI-X Capabilities List Item reg group */
- {
- .grp_id = PCI_CAP_ID_PCIX,
- .grp_type = XEN_PT_GRP_TYPE_HARDWIRED,
- .grp_size = 0x18,
- .size_init = xen_pt_reg_grp_size_init,
- },
- /* Vendor Specific Capability Structure reg group */
- {
- .grp_id = PCI_CAP_ID_VNDR,
- .grp_type = XEN_PT_GRP_TYPE_EMU,
- .grp_size = 0xFF,
- .size_init = xen_pt_vendor_size_init,
- .emu_regs = xen_pt_emu_reg_vendor,
- },
- /* SHPC Capability List Item reg group */
- {
- .grp_id = PCI_CAP_ID_SHPC,
- .grp_type = XEN_PT_GRP_TYPE_HARDWIRED,
- .grp_size = 0x08,
- .size_init = xen_pt_reg_grp_size_init,
- },
- /* Subsystem ID and Subsystem Vendor ID Capability List Item reg group */
- {
- .grp_id = PCI_CAP_ID_SSVID,
- .grp_type = XEN_PT_GRP_TYPE_HARDWIRED,
- .grp_size = 0x08,
- .size_init = xen_pt_reg_grp_size_init,
- },
- /* AGP 8x Capability Structure reg group */
- {
- .grp_id = PCI_CAP_ID_AGP3,
- .grp_type = XEN_PT_GRP_TYPE_HARDWIRED,
- .grp_size = 0x30,
- .size_init = xen_pt_reg_grp_size_init,
- },
- /* PCI Express Capability Structure reg group */
- {
- .grp_id = PCI_CAP_ID_EXP,
- .grp_type = XEN_PT_GRP_TYPE_EMU,
- .grp_size = 0xFF,
- .size_init = xen_pt_pcie_size_init,
- .emu_regs = xen_pt_emu_reg_pcie,
- },
- /* MSI-X Capability Structure reg group */
- {
- .grp_id = PCI_CAP_ID_MSIX,
- .grp_type = XEN_PT_GRP_TYPE_EMU,
- .grp_size = 0x0C,
- .size_init = xen_pt_msix_size_init,
- .emu_regs = xen_pt_emu_reg_msix,
- },
- /* Intel IGD Opregion group */
- {
- .grp_id = XEN_PCI_INTEL_OPREGION,
- .grp_type = XEN_PT_GRP_TYPE_EMU,
- .grp_size = 0x4,
- .size_init = xen_pt_reg_grp_size_init,
- .emu_regs = xen_pt_emu_reg_igd_opregion,
- },
- {
- .grp_size = 0,
- },
-};
-
-/* initialize Capabilities Pointer or Next Pointer register */
-static int xen_pt_ptr_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
-{
- int i, rc;
- uint8_t reg_field;
- uint8_t cap_id = 0;
-
- rc = xen_host_pci_get_byte(&s->real_device, real_offset, &reg_field);
- if (rc) {
- return rc;
- }
- /* find capability offset */
- while (reg_field) {
- for (i = 0; xen_pt_emu_reg_grps[i].grp_size != 0; i++) {
- if (xen_pt_hide_dev_cap(&s->real_device,
- xen_pt_emu_reg_grps[i].grp_id)) {
- continue;
- }
-
- rc = xen_host_pci_get_byte(&s->real_device,
- reg_field + PCI_CAP_LIST_ID, &cap_id);
- if (rc) {
- XEN_PT_ERR(&s->dev, "Failed to read capability @0x%x (rc:%d)\n",
- reg_field + PCI_CAP_LIST_ID, rc);
- return rc;
- }
- if (xen_pt_emu_reg_grps[i].grp_id == cap_id) {
- if (xen_pt_emu_reg_grps[i].grp_type == XEN_PT_GRP_TYPE_EMU) {
- goto out;
- }
- /* ignore the 0 hardwired capability, find next one */
- break;
- }
- }
-
- /* next capability */
- rc = xen_host_pci_get_byte(&s->real_device,
- reg_field + PCI_CAP_LIST_NEXT, &reg_field);
- if (rc) {
- return rc;
- }
- }
-
-out:
- *data = reg_field;
- return 0;
-}
-
-
-/*************
- * Main
- */
-
-static uint8_t find_cap_offset(XenPCIPassthroughState *s, uint8_t cap)
-{
- uint8_t id;
- unsigned max_cap = XEN_PCI_CAP_MAX;
- uint8_t pos = PCI_CAPABILITY_LIST;
- uint8_t status = 0;
-
- if (xen_host_pci_get_byte(&s->real_device, PCI_STATUS, &status)) {
- return 0;
- }
- if ((status & PCI_STATUS_CAP_LIST) == 0) {
- return 0;
- }
-
- while (max_cap--) {
- if (xen_host_pci_get_byte(&s->real_device, pos, &pos)) {
- break;
- }
- if (pos < PCI_CONFIG_HEADER_SIZE) {
- break;
- }
-
- pos &= ~3;
- if (xen_host_pci_get_byte(&s->real_device,
- pos + PCI_CAP_LIST_ID, &id)) {
- break;
- }
-
- if (id == 0xff) {
- break;
- }
- if (id == cap) {
- return pos;
- }
-
- pos += PCI_CAP_LIST_NEXT;
- }
- return 0;
-}
-
-static void xen_pt_config_reg_init(XenPCIPassthroughState *s,
- XenPTRegGroup *reg_grp, XenPTRegInfo *reg,
- Error **errp)
-{
- XenPTReg *reg_entry;
- uint32_t data = 0;
- int rc = 0;
-
- reg_entry = g_new0(XenPTReg, 1);
- reg_entry->reg = reg;
-
- if (reg->init) {
- uint32_t host_mask, size_mask;
- unsigned int offset;
- uint32_t val;
-
- /* initialize emulate register */
- rc = reg->init(s, reg_entry->reg,
- reg_grp->base_offset + reg->offset, &data);
- if (rc < 0) {
- g_free(reg_entry);
- error_setg(errp, "Init emulate register fail");
- return;
- }
- if (data == XEN_PT_INVALID_REG) {
- /* free unused BAR register entry */
- g_free(reg_entry);
- return;
- }
- /* Sync up the data to dev.config */
- offset = reg_grp->base_offset + reg->offset;
- size_mask = 0xFFFFFFFF >> ((4 - reg->size) << 3);
-
- switch (reg->size) {
- case 1: rc = xen_host_pci_get_byte(&s->real_device, offset, (uint8_t *)&val);
- break;
- case 2: rc = xen_host_pci_get_word(&s->real_device, offset, (uint16_t *)&val);
- break;
- case 4: rc = xen_host_pci_get_long(&s->real_device, offset, &val);
- break;
- default: abort();
- }
- if (rc) {
- /* Serious issues when we cannot read the host values! */
- g_free(reg_entry);
- error_setg(errp, "Cannot read host values");
- return;
- }
- /* Set bits in emu_mask are the ones we emulate. The dev.config shall
- * contain the emulated view of the guest - therefore we flip the mask
- * to mask out the host values (which dev.config initially has) . */
- host_mask = size_mask & ~reg->emu_mask;
-
- if ((data & host_mask) != (val & host_mask)) {
- uint32_t new_val;
-
- /* Mask out host (including past size). */
- new_val = val & host_mask;
- /* Merge emulated ones (excluding the non-emulated ones). */
- new_val |= data & host_mask;
- /* Leave intact host and emulated values past the size - even though
- * we do not care as we write per reg->size granularity, but for the
- * logging below lets have the proper value. */
- new_val |= ((val | data)) & ~size_mask;
- XEN_PT_LOG(&s->dev,"Offset 0x%04x mismatch! Emulated=0x%04x, host=0x%04x, syncing to 0x%04x.\n",
- offset, data, val, new_val);
- val = new_val;
- } else
- val = data;
-
- if (val & ~size_mask) {
- error_setg(errp, "Offset 0x%04x:0x%04x expands past"
- " register size (%d)", offset, val, reg->size);
- g_free(reg_entry);
- return;
- }
- /* This could be just pci_set_long as we don't modify the bits
- * past reg->size, but in case this routine is run in parallel or the
- * init value is larger, we do not want to over-write registers. */
- switch (reg->size) {
- case 1: pci_set_byte(s->dev.config + offset, (uint8_t)val);
- break;
- case 2: pci_set_word(s->dev.config + offset, (uint16_t)val);
- break;
- case 4: pci_set_long(s->dev.config + offset, val);
- break;
- default: abort();
- }
- /* set register value pointer to the data. */
- reg_entry->ptr.byte = s->dev.config + offset;
-
- }
- /* list add register entry */
- QLIST_INSERT_HEAD(&reg_grp->reg_tbl_list, reg_entry, entries);
-}
-
-void xen_pt_config_init(XenPCIPassthroughState *s, Error **errp)
-{
- int i, rc;
- Error *err = NULL;
-
- QLIST_INIT(&s->reg_grps);
-
- for (i = 0; xen_pt_emu_reg_grps[i].grp_size != 0; i++) {
- uint32_t reg_grp_offset = 0;
- XenPTRegGroup *reg_grp_entry = NULL;
-
- if (xen_pt_emu_reg_grps[i].grp_id != 0xFF
- && xen_pt_emu_reg_grps[i].grp_id != XEN_PCI_INTEL_OPREGION) {
- if (xen_pt_hide_dev_cap(&s->real_device,
- xen_pt_emu_reg_grps[i].grp_id)) {
- continue;
- }
-
- reg_grp_offset = find_cap_offset(s, xen_pt_emu_reg_grps[i].grp_id);
-
- if (!reg_grp_offset) {
- continue;
- }
- }
-
- /*
- * By default we will trap up to 0x40 in the cfg space.
- * If an intel device is pass through we need to trap 0xfc,
- * therefore the size should be 0xff.
- */
- if (xen_pt_emu_reg_grps[i].grp_id == XEN_PCI_INTEL_OPREGION) {
- reg_grp_offset = XEN_PCI_INTEL_OPREGION;
- }
-
- reg_grp_entry = g_new0(XenPTRegGroup, 1);
- QLIST_INIT(&reg_grp_entry->reg_tbl_list);
- QLIST_INSERT_HEAD(&s->reg_grps, reg_grp_entry, entries);
-
- reg_grp_entry->base_offset = reg_grp_offset;
- reg_grp_entry->reg_grp = xen_pt_emu_reg_grps + i;
- if (xen_pt_emu_reg_grps[i].size_init) {
- /* get register group size */
- rc = xen_pt_emu_reg_grps[i].size_init(s, reg_grp_entry->reg_grp,
- reg_grp_offset,
- &reg_grp_entry->size);
- if (rc < 0) {
- error_setg(&err, "Failed to initialize %d/%zu, type = 0x%x,"
- " rc: %d", i, ARRAY_SIZE(xen_pt_emu_reg_grps),
- xen_pt_emu_reg_grps[i].grp_type, rc);
- error_propagate(errp, err);
- xen_pt_config_delete(s);
- return;
- }
- }
-
- if (xen_pt_emu_reg_grps[i].grp_type == XEN_PT_GRP_TYPE_EMU) {
- if (xen_pt_emu_reg_grps[i].emu_regs) {
- int j = 0;
- XenPTRegInfo *regs = xen_pt_emu_reg_grps[i].emu_regs;
-
- /* initialize capability register */
- for (j = 0; regs->size != 0; j++, regs++) {
- xen_pt_config_reg_init(s, reg_grp_entry, regs, &err);
- if (err) {
- error_append_hint(&err, "Failed to initialize %d/%zu"
- " reg 0x%x in grp_type = 0x%x (%d/%zu)",
- j, ARRAY_SIZE(xen_pt_emu_reg_grps[i].emu_regs),
- regs->offset, xen_pt_emu_reg_grps[i].grp_type,
- i, ARRAY_SIZE(xen_pt_emu_reg_grps));
- error_propagate(errp, err);
- xen_pt_config_delete(s);
- return;
- }
- }
- }
- }
- }
-}
-
-/* delete all emulate register */
-void xen_pt_config_delete(XenPCIPassthroughState *s)
-{
- struct XenPTRegGroup *reg_group, *next_grp;
- struct XenPTReg *reg, *next_reg;
-
- /* free MSI/MSI-X info table */
- if (s->msix) {
- xen_pt_msix_unmap(s);
- }
- g_free(s->msi);
-
- /* free all register group entry */
- QLIST_FOREACH_SAFE(reg_group, &s->reg_grps, entries, next_grp) {
- /* free all register entry */
- QLIST_FOREACH_SAFE(reg, &reg_group->reg_tbl_list, entries, next_reg) {
- QLIST_REMOVE(reg, entries);
- g_free(reg);
- }
-
- QLIST_REMOVE(reg_group, entries);
- g_free(reg_group);
- }
-}
diff --git a/qemu/hw/xen/xen_pt_graphics.c b/qemu/hw/xen/xen_pt_graphics.c
deleted file mode 100644
index 0f4c8d77e..000000000
--- a/qemu/hw/xen/xen_pt_graphics.c
+++ /dev/null
@@ -1,275 +0,0 @@
-/*
- * graphics passthrough
- */
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "xen_pt.h"
-#include "xen-host-pci-device.h"
-#include "hw/xen/xen_backend.h"
-
-static unsigned long igd_guest_opregion;
-static unsigned long igd_host_opregion;
-
-#define XEN_PCI_INTEL_OPREGION_MASK 0xfff
-
-typedef struct VGARegion {
- int type; /* Memory or port I/O */
- uint64_t guest_base_addr;
- uint64_t machine_base_addr;
- uint64_t size; /* size of the region */
- int rc;
-} VGARegion;
-
-#define IORESOURCE_IO 0x00000100
-#define IORESOURCE_MEM 0x00000200
-
-static struct VGARegion vga_args[] = {
- {
- .type = IORESOURCE_IO,
- .guest_base_addr = 0x3B0,
- .machine_base_addr = 0x3B0,
- .size = 0xC,
- .rc = -1,
- },
- {
- .type = IORESOURCE_IO,
- .guest_base_addr = 0x3C0,
- .machine_base_addr = 0x3C0,
- .size = 0x20,
- .rc = -1,
- },
- {
- .type = IORESOURCE_MEM,
- .guest_base_addr = 0xa0000 >> XC_PAGE_SHIFT,
- .machine_base_addr = 0xa0000 >> XC_PAGE_SHIFT,
- .size = 0x20,
- .rc = -1,
- },
-};
-
-/*
- * register VGA resources for the domain with assigned gfx
- */
-int xen_pt_register_vga_regions(XenHostPCIDevice *dev)
-{
- int i = 0;
-
- if (!is_igd_vga_passthrough(dev)) {
- return 0;
- }
-
- for (i = 0 ; i < ARRAY_SIZE(vga_args); i++) {
- if (vga_args[i].type == IORESOURCE_IO) {
- vga_args[i].rc = xc_domain_ioport_mapping(xen_xc, xen_domid,
- vga_args[i].guest_base_addr,
- vga_args[i].machine_base_addr,
- vga_args[i].size, DPCI_ADD_MAPPING);
- } else {
- vga_args[i].rc = xc_domain_memory_mapping(xen_xc, xen_domid,
- vga_args[i].guest_base_addr,
- vga_args[i].machine_base_addr,
- vga_args[i].size, DPCI_ADD_MAPPING);
- }
-
- if (vga_args[i].rc) {
- XEN_PT_ERR(NULL, "VGA %s mapping failed! (rc: %i)\n",
- vga_args[i].type == IORESOURCE_IO ? "ioport" : "memory",
- vga_args[i].rc);
- return vga_args[i].rc;
- }
- }
-
- return 0;
-}
-
-/*
- * unregister VGA resources for the domain with assigned gfx
- */
-int xen_pt_unregister_vga_regions(XenHostPCIDevice *dev)
-{
- int i = 0;
- int ret = 0;
-
- if (!is_igd_vga_passthrough(dev)) {
- return 0;
- }
-
- for (i = 0 ; i < ARRAY_SIZE(vga_args); i++) {
- if (vga_args[i].type == IORESOURCE_IO) {
- vga_args[i].rc = xc_domain_ioport_mapping(xen_xc, xen_domid,
- vga_args[i].guest_base_addr,
- vga_args[i].machine_base_addr,
- vga_args[i].size, DPCI_REMOVE_MAPPING);
- } else {
- vga_args[i].rc = xc_domain_memory_mapping(xen_xc, xen_domid,
- vga_args[i].guest_base_addr,
- vga_args[i].machine_base_addr,
- vga_args[i].size, DPCI_REMOVE_MAPPING);
- }
-
- if (vga_args[i].rc) {
- XEN_PT_ERR(NULL, "VGA %s unmapping failed! (rc: %i)\n",
- vga_args[i].type == IORESOURCE_IO ? "ioport" : "memory",
- vga_args[i].rc);
- return vga_args[i].rc;
- }
- }
-
- if (igd_guest_opregion) {
- ret = xc_domain_memory_mapping(xen_xc, xen_domid,
- (unsigned long)(igd_guest_opregion >> XC_PAGE_SHIFT),
- (unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT),
- 3,
- DPCI_REMOVE_MAPPING);
- if (ret) {
- return ret;
- }
- }
-
- return 0;
-}
-
-static void *get_vgabios(XenPCIPassthroughState *s, int *size,
- XenHostPCIDevice *dev)
-{
- return pci_assign_dev_load_option_rom(&s->dev, OBJECT(&s->dev), size,
- dev->domain, dev->bus,
- dev->dev, dev->func);
-}
-
-/* Refer to Seabios. */
-struct rom_header {
- uint16_t signature;
- uint8_t size;
- uint8_t initVector[4];
- uint8_t reserved[17];
- uint16_t pcioffset;
- uint16_t pnpoffset;
-} __attribute__((packed));
-
-struct pci_data {
- uint32_t signature;
- uint16_t vendor;
- uint16_t device;
- uint16_t vitaldata;
- uint16_t dlen;
- uint8_t drevision;
- uint8_t class_lo;
- uint16_t class_hi;
- uint16_t ilen;
- uint16_t irevision;
- uint8_t type;
- uint8_t indicator;
- uint16_t reserved;
-} __attribute__((packed));
-
-void xen_pt_setup_vga(XenPCIPassthroughState *s, XenHostPCIDevice *dev,
- Error **errp)
-{
- unsigned char *bios = NULL;
- struct rom_header *rom;
- int bios_size;
- char *c = NULL;
- char checksum = 0;
- uint32_t len = 0;
- struct pci_data *pd = NULL;
-
- if (!is_igd_vga_passthrough(dev)) {
- error_setg(errp, "Need to enable igd-passthrough");
- return;
- }
-
- bios = get_vgabios(s, &bios_size, dev);
- if (!bios) {
- error_setg(errp, "VGA: Can't get VBIOS");
- return;
- }
-
- /* Currently we fixed this address as a primary. */
- rom = (struct rom_header *)bios;
- pd = (void *)(bios + (unsigned char)rom->pcioffset);
-
- /* We may need to fixup Device Identification. */
- if (pd->device != s->real_device.device_id) {
- pd->device = s->real_device.device_id;
-
- len = rom->size * 512;
- /* Then adjust the bios checksum */
- for (c = (char *)bios; c < ((char *)bios + len); c++) {
- checksum += *c;
- }
- if (checksum) {
- bios[len - 1] -= checksum;
- XEN_PT_LOG(&s->dev, "vga bios checksum is adjusted %x!\n",
- checksum);
- }
- }
-
- /* Currently we fixed this address as a primary for legacy BIOS. */
- cpu_physical_memory_rw(0xc0000, bios, bios_size, 1);
-}
-
-uint32_t igd_read_opregion(XenPCIPassthroughState *s)
-{
- uint32_t val = 0;
-
- if (!igd_guest_opregion) {
- return val;
- }
-
- val = igd_guest_opregion;
-
- XEN_PT_LOG(&s->dev, "Read opregion val=%x\n", val);
- return val;
-}
-
-#define XEN_PCI_INTEL_OPREGION_PAGES 0x3
-#define XEN_PCI_INTEL_OPREGION_ENABLE_ACCESSED 0x1
-void igd_write_opregion(XenPCIPassthroughState *s, uint32_t val)
-{
- int ret;
-
- if (igd_guest_opregion) {
- XEN_PT_LOG(&s->dev, "opregion register already been set, ignoring %x\n",
- val);
- return;
- }
-
- /* We just work with LE. */
- xen_host_pci_get_block(&s->real_device, XEN_PCI_INTEL_OPREGION,
- (uint8_t *)&igd_host_opregion, 4);
- igd_guest_opregion = (unsigned long)(val & ~XEN_PCI_INTEL_OPREGION_MASK)
- | (igd_host_opregion & XEN_PCI_INTEL_OPREGION_MASK);
-
- ret = xc_domain_iomem_permission(xen_xc, xen_domid,
- (unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT),
- XEN_PCI_INTEL_OPREGION_PAGES,
- XEN_PCI_INTEL_OPREGION_ENABLE_ACCESSED);
-
- if (ret) {
- XEN_PT_ERR(&s->dev, "[%d]:Can't enable to access IGD host opregion:"
- " 0x%lx.\n", ret,
- (unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT)),
- igd_guest_opregion = 0;
- return;
- }
-
- ret = xc_domain_memory_mapping(xen_xc, xen_domid,
- (unsigned long)(igd_guest_opregion >> XC_PAGE_SHIFT),
- (unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT),
- XEN_PCI_INTEL_OPREGION_PAGES,
- DPCI_ADD_MAPPING);
-
- if (ret) {
- XEN_PT_ERR(&s->dev, "[%d]:Can't map IGD host opregion:0x%lx to"
- " guest opregion:0x%lx.\n", ret,
- (unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT),
- (unsigned long)(igd_guest_opregion >> XC_PAGE_SHIFT));
- igd_guest_opregion = 0;
- return;
- }
-
- XEN_PT_LOG(&s->dev, "Map OpRegion: 0x%lx -> 0x%lx\n",
- (unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT),
- (unsigned long)(igd_guest_opregion >> XC_PAGE_SHIFT));
-}
diff --git a/qemu/hw/xen/xen_pt_msi.c b/qemu/hw/xen/xen_pt_msi.c
deleted file mode 100644
index 9a16f2bff..000000000
--- a/qemu/hw/xen/xen_pt_msi.c
+++ /dev/null
@@ -1,635 +0,0 @@
-/*
- * Copyright (c) 2007, Intel Corporation.
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- * Jiang Yunhong <yunhong.jiang@intel.com>
- *
- * This file implements direct PCI assignment to a HVM guest
- */
-
-#include "qemu/osdep.h"
-#include <sys/mman.h>
-
-#include "hw/xen/xen_backend.h"
-#include "xen_pt.h"
-#include "hw/i386/apic-msidef.h"
-
-
-#define XEN_PT_AUTO_ASSIGN -1
-
-/* shift count for gflags */
-#define XEN_PT_GFLAGS_SHIFT_DEST_ID 0
-#define XEN_PT_GFLAGS_SHIFT_RH 8
-#define XEN_PT_GFLAGS_SHIFT_DM 9
-#define XEN_PT_GFLAGSSHIFT_DELIV_MODE 12
-#define XEN_PT_GFLAGSSHIFT_TRG_MODE 15
-
-#define latch(fld) latch[PCI_MSIX_ENTRY_##fld / sizeof(uint32_t)]
-
-/*
- * Helpers
- */
-
-static inline uint8_t msi_vector(uint32_t data)
-{
- return (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT;
-}
-
-static inline uint8_t msi_dest_id(uint32_t addr)
-{
- return (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT;
-}
-
-static inline uint32_t msi_ext_dest_id(uint32_t addr_hi)
-{
- return addr_hi & 0xffffff00;
-}
-
-static uint32_t msi_gflags(uint32_t data, uint64_t addr)
-{
- uint32_t result = 0;
- int rh, dm, dest_id, deliv_mode, trig_mode;
-
- rh = (addr >> MSI_ADDR_REDIRECTION_SHIFT) & 0x1;
- dm = (addr >> MSI_ADDR_DEST_MODE_SHIFT) & 0x1;
- dest_id = msi_dest_id(addr);
- deliv_mode = (data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 0x7;
- trig_mode = (data >> MSI_DATA_TRIGGER_SHIFT) & 0x1;
-
- result = dest_id | (rh << XEN_PT_GFLAGS_SHIFT_RH)
- | (dm << XEN_PT_GFLAGS_SHIFT_DM)
- | (deliv_mode << XEN_PT_GFLAGSSHIFT_DELIV_MODE)
- | (trig_mode << XEN_PT_GFLAGSSHIFT_TRG_MODE);
-
- return result;
-}
-
-static inline uint64_t msi_addr64(XenPTMSI *msi)
-{
- return (uint64_t)msi->addr_hi << 32 | msi->addr_lo;
-}
-
-static int msi_msix_enable(XenPCIPassthroughState *s,
- uint32_t address,
- uint16_t flag,
- bool enable)
-{
- uint16_t val = 0;
- int rc;
-
- if (!address) {
- return -1;
- }
-
- rc = xen_host_pci_get_word(&s->real_device, address, &val);
- if (rc) {
- XEN_PT_ERR(&s->dev, "Failed to read MSI/MSI-X register (0x%x), rc:%d\n",
- address, rc);
- return rc;
- }
- if (enable) {
- val |= flag;
- } else {
- val &= ~flag;
- }
- rc = xen_host_pci_set_word(&s->real_device, address, val);
- if (rc) {
- XEN_PT_ERR(&s->dev, "Failed to write MSI/MSI-X register (0x%x), rc:%d\n",
- address, rc);
- }
- return rc;
-}
-
-static int msi_msix_setup(XenPCIPassthroughState *s,
- uint64_t addr,
- uint32_t data,
- int *ppirq,
- bool is_msix,
- int msix_entry,
- bool is_not_mapped)
-{
- uint8_t gvec = msi_vector(data);
- int rc = 0;
-
- assert((!is_msix && msix_entry == 0) || is_msix);
-
- if (xen_is_pirq_msi(data)) {
- *ppirq = msi_ext_dest_id(addr >> 32) | msi_dest_id(addr);
- if (!*ppirq) {
- /* this probably identifies an misconfiguration of the guest,
- * try the emulated path */
- *ppirq = XEN_PT_UNASSIGNED_PIRQ;
- } else {
- XEN_PT_LOG(&s->dev, "requested pirq %d for MSI%s"
- " (vec: %#x, entry: %#x)\n",
- *ppirq, is_msix ? "-X" : "", gvec, msix_entry);
- }
- }
-
- if (is_not_mapped) {
- uint64_t table_base = 0;
-
- if (is_msix) {
- table_base = s->msix->table_base;
- }
-
- rc = xc_physdev_map_pirq_msi(xen_xc, xen_domid, XEN_PT_AUTO_ASSIGN,
- ppirq, PCI_DEVFN(s->real_device.dev,
- s->real_device.func),
- s->real_device.bus,
- msix_entry, table_base);
- if (rc) {
- XEN_PT_ERR(&s->dev,
- "Mapping of MSI%s (err: %i, vec: %#x, entry %#x)\n",
- is_msix ? "-X" : "", errno, gvec, msix_entry);
- return rc;
- }
- }
-
- return 0;
-}
-static int msi_msix_update(XenPCIPassthroughState *s,
- uint64_t addr,
- uint32_t data,
- int pirq,
- bool is_msix,
- int msix_entry,
- int *old_pirq)
-{
- PCIDevice *d = &s->dev;
- uint8_t gvec = msi_vector(data);
- uint32_t gflags = msi_gflags(data, addr);
- int rc = 0;
- uint64_t table_addr = 0;
-
- XEN_PT_LOG(d, "Updating MSI%s with pirq %d gvec %#x gflags %#x"
- " (entry: %#x)\n",
- is_msix ? "-X" : "", pirq, gvec, gflags, msix_entry);
-
- if (is_msix) {
- table_addr = s->msix->mmio_base_addr;
- }
-
- rc = xc_domain_update_msi_irq(xen_xc, xen_domid, gvec,
- pirq, gflags, table_addr);
-
- if (rc) {
- XEN_PT_ERR(d, "Updating of MSI%s failed. (err: %d)\n",
- is_msix ? "-X" : "", errno);
-
- if (xc_physdev_unmap_pirq(xen_xc, xen_domid, *old_pirq)) {
- XEN_PT_ERR(d, "Unmapping of MSI%s pirq %d failed. (err: %d)\n",
- is_msix ? "-X" : "", *old_pirq, errno);
- }
- *old_pirq = XEN_PT_UNASSIGNED_PIRQ;
- }
- return rc;
-}
-
-static int msi_msix_disable(XenPCIPassthroughState *s,
- uint64_t addr,
- uint32_t data,
- int pirq,
- bool is_msix,
- bool is_binded)
-{
- PCIDevice *d = &s->dev;
- uint8_t gvec = msi_vector(data);
- uint32_t gflags = msi_gflags(data, addr);
- int rc = 0;
-
- if (pirq == XEN_PT_UNASSIGNED_PIRQ) {
- return 0;
- }
-
- if (is_binded) {
- XEN_PT_LOG(d, "Unbind MSI%s with pirq %d, gvec %#x\n",
- is_msix ? "-X" : "", pirq, gvec);
- rc = xc_domain_unbind_msi_irq(xen_xc, xen_domid, gvec, pirq, gflags);
- if (rc) {
- XEN_PT_ERR(d, "Unbinding of MSI%s failed. (err: %d, pirq: %d, gvec: %#x)\n",
- is_msix ? "-X" : "", errno, pirq, gvec);
- return rc;
- }
- }
-
- XEN_PT_LOG(d, "Unmap MSI%s pirq %d\n", is_msix ? "-X" : "", pirq);
- rc = xc_physdev_unmap_pirq(xen_xc, xen_domid, pirq);
- if (rc) {
- XEN_PT_ERR(d, "Unmapping of MSI%s pirq %d failed. (err: %i)\n",
- is_msix ? "-X" : "", pirq, errno);
- return rc;
- }
-
- return 0;
-}
-
-/*
- * MSI virtualization functions
- */
-
-static int xen_pt_msi_set_enable(XenPCIPassthroughState *s, bool enable)
-{
- XEN_PT_LOG(&s->dev, "%s MSI.\n", enable ? "enabling" : "disabling");
-
- if (!s->msi) {
- return -1;
- }
-
- return msi_msix_enable(s, s->msi->ctrl_offset, PCI_MSI_FLAGS_ENABLE,
- enable);
-}
-
-/* setup physical msi, but don't enable it */
-int xen_pt_msi_setup(XenPCIPassthroughState *s)
-{
- int pirq = XEN_PT_UNASSIGNED_PIRQ;
- int rc = 0;
- XenPTMSI *msi = s->msi;
-
- if (msi->initialized) {
- XEN_PT_ERR(&s->dev,
- "Setup physical MSI when it has been properly initialized.\n");
- return -1;
- }
-
- rc = msi_msix_setup(s, msi_addr64(msi), msi->data, &pirq, false, 0, true);
- if (rc) {
- return rc;
- }
-
- if (pirq < 0) {
- XEN_PT_ERR(&s->dev, "Invalid pirq number: %d.\n", pirq);
- return -1;
- }
-
- msi->pirq = pirq;
- XEN_PT_LOG(&s->dev, "MSI mapped with pirq %d.\n", pirq);
-
- return 0;
-}
-
-int xen_pt_msi_update(XenPCIPassthroughState *s)
-{
- XenPTMSI *msi = s->msi;
- return msi_msix_update(s, msi_addr64(msi), msi->data, msi->pirq,
- false, 0, &msi->pirq);
-}
-
-void xen_pt_msi_disable(XenPCIPassthroughState *s)
-{
- XenPTMSI *msi = s->msi;
-
- if (!msi) {
- return;
- }
-
- (void)xen_pt_msi_set_enable(s, false);
-
- msi_msix_disable(s, msi_addr64(msi), msi->data, msi->pirq, false,
- msi->initialized);
-
- /* clear msi info */
- msi->flags &= ~PCI_MSI_FLAGS_ENABLE;
- msi->initialized = false;
- msi->mapped = false;
- msi->pirq = XEN_PT_UNASSIGNED_PIRQ;
-}
-
-/*
- * MSI-X virtualization functions
- */
-
-static int msix_set_enable(XenPCIPassthroughState *s, bool enabled)
-{
- XEN_PT_LOG(&s->dev, "%s MSI-X.\n", enabled ? "enabling" : "disabling");
-
- if (!s->msix) {
- return -1;
- }
-
- return msi_msix_enable(s, s->msix->ctrl_offset, PCI_MSIX_FLAGS_ENABLE,
- enabled);
-}
-
-static int xen_pt_msix_update_one(XenPCIPassthroughState *s, int entry_nr,
- uint32_t vec_ctrl)
-{
- XenPTMSIXEntry *entry = NULL;
- int pirq;
- int rc;
-
- if (entry_nr < 0 || entry_nr >= s->msix->total_entries) {
- return -EINVAL;
- }
-
- entry = &s->msix->msix_entry[entry_nr];
-
- if (!entry->updated) {
- return 0;
- }
-
- pirq = entry->pirq;
-
- /*
- * Update the entry addr and data to the latest values only when the
- * entry is masked or they are all masked, as required by the spec.
- * Addr and data changes while the MSI-X entry is unmasked get deferred
- * until the next masked -> unmasked transition.
- */
- if (pirq == XEN_PT_UNASSIGNED_PIRQ || s->msix->maskall ||
- (vec_ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
- entry->addr = entry->latch(LOWER_ADDR) |
- ((uint64_t)entry->latch(UPPER_ADDR) << 32);
- entry->data = entry->latch(DATA);
- }
-
- rc = msi_msix_setup(s, entry->addr, entry->data, &pirq, true, entry_nr,
- entry->pirq == XEN_PT_UNASSIGNED_PIRQ);
- if (rc) {
- return rc;
- }
- if (entry->pirq == XEN_PT_UNASSIGNED_PIRQ) {
- entry->pirq = pirq;
- }
-
- rc = msi_msix_update(s, entry->addr, entry->data, pirq, true,
- entry_nr, &entry->pirq);
-
- if (!rc) {
- entry->updated = false;
- }
-
- return rc;
-}
-
-int xen_pt_msix_update(XenPCIPassthroughState *s)
-{
- XenPTMSIX *msix = s->msix;
- int i;
-
- for (i = 0; i < msix->total_entries; i++) {
- xen_pt_msix_update_one(s, i, msix->msix_entry[i].latch(VECTOR_CTRL));
- }
-
- return 0;
-}
-
-void xen_pt_msix_disable(XenPCIPassthroughState *s)
-{
- int i = 0;
-
- msix_set_enable(s, false);
-
- for (i = 0; i < s->msix->total_entries; i++) {
- XenPTMSIXEntry *entry = &s->msix->msix_entry[i];
-
- msi_msix_disable(s, entry->addr, entry->data, entry->pirq, true, true);
-
- /* clear MSI-X info */
- entry->pirq = XEN_PT_UNASSIGNED_PIRQ;
- entry->updated = false;
- }
-}
-
-int xen_pt_msix_update_remap(XenPCIPassthroughState *s, int bar_index)
-{
- XenPTMSIXEntry *entry;
- int i, ret;
-
- if (!(s->msix && s->msix->bar_index == bar_index)) {
- return 0;
- }
-
- for (i = 0; i < s->msix->total_entries; i++) {
- entry = &s->msix->msix_entry[i];
- if (entry->pirq != XEN_PT_UNASSIGNED_PIRQ) {
- ret = xc_domain_unbind_pt_irq(xen_xc, xen_domid, entry->pirq,
- PT_IRQ_TYPE_MSI, 0, 0, 0, 0);
- if (ret) {
- XEN_PT_ERR(&s->dev, "unbind MSI-X entry %d failed (err: %d)\n",
- entry->pirq, errno);
- }
- entry->updated = true;
- }
- }
- return xen_pt_msix_update(s);
-}
-
-static uint32_t get_entry_value(XenPTMSIXEntry *e, int offset)
-{
- assert(!(offset % sizeof(*e->latch)));
- return e->latch[offset / sizeof(*e->latch)];
-}
-
-static void set_entry_value(XenPTMSIXEntry *e, int offset, uint32_t val)
-{
- assert(!(offset % sizeof(*e->latch)));
- e->latch[offset / sizeof(*e->latch)] = val;
-}
-
-static void pci_msix_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- XenPCIPassthroughState *s = opaque;
- XenPTMSIX *msix = s->msix;
- XenPTMSIXEntry *entry;
- unsigned int entry_nr, offset;
-
- entry_nr = addr / PCI_MSIX_ENTRY_SIZE;
- if (entry_nr >= msix->total_entries) {
- return;
- }
- entry = &msix->msix_entry[entry_nr];
- offset = addr % PCI_MSIX_ENTRY_SIZE;
-
- if (offset != PCI_MSIX_ENTRY_VECTOR_CTRL) {
- if (get_entry_value(entry, offset) == val
- && entry->pirq != XEN_PT_UNASSIGNED_PIRQ) {
- return;
- }
-
- entry->updated = true;
- } else if (msix->enabled && entry->updated &&
- !(val & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
- const volatile uint32_t *vec_ctrl;
-
- /*
- * If Xen intercepts the mask bit access, entry->vec_ctrl may not be
- * up-to-date. Read from hardware directly.
- */
- vec_ctrl = s->msix->phys_iomem_base + entry_nr * PCI_MSIX_ENTRY_SIZE
- + PCI_MSIX_ENTRY_VECTOR_CTRL;
- xen_pt_msix_update_one(s, entry_nr, *vec_ctrl);
- }
-
- set_entry_value(entry, offset, val);
-}
-
-static uint64_t pci_msix_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- XenPCIPassthroughState *s = opaque;
- XenPTMSIX *msix = s->msix;
- int entry_nr, offset;
-
- entry_nr = addr / PCI_MSIX_ENTRY_SIZE;
- if (entry_nr < 0) {
- XEN_PT_ERR(&s->dev, "asked MSI-X entry '%i' invalid!\n", entry_nr);
- return 0;
- }
-
- offset = addr % PCI_MSIX_ENTRY_SIZE;
-
- if (addr < msix->total_entries * PCI_MSIX_ENTRY_SIZE) {
- return get_entry_value(&msix->msix_entry[entry_nr], offset);
- } else {
- /* Pending Bit Array (PBA) */
- return *(uint32_t *)(msix->phys_iomem_base + addr);
- }
-}
-
-static bool pci_msix_accepts(void *opaque, hwaddr addr,
- unsigned size, bool is_write)
-{
- return !(addr & (size - 1));
-}
-
-static const MemoryRegionOps pci_msix_ops = {
- .read = pci_msix_read,
- .write = pci_msix_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- .unaligned = false,
- .accepts = pci_msix_accepts
- },
- .impl = {
- .min_access_size = 4,
- .max_access_size = 4,
- .unaligned = false
- }
-};
-
-int xen_pt_msix_init(XenPCIPassthroughState *s, uint32_t base)
-{
- uint8_t id = 0;
- uint16_t control = 0;
- uint32_t table_off = 0;
- int i, total_entries, bar_index;
- XenHostPCIDevice *hd = &s->real_device;
- PCIDevice *d = &s->dev;
- int fd = -1;
- XenPTMSIX *msix = NULL;
- int rc = 0;
-
- rc = xen_host_pci_get_byte(hd, base + PCI_CAP_LIST_ID, &id);
- if (rc) {
- return rc;
- }
-
- if (id != PCI_CAP_ID_MSIX) {
- XEN_PT_ERR(d, "Invalid id %#x base %#x\n", id, base);
- return -1;
- }
-
- xen_host_pci_get_word(hd, base + PCI_MSIX_FLAGS, &control);
- total_entries = control & PCI_MSIX_FLAGS_QSIZE;
- total_entries += 1;
-
- s->msix = g_malloc0(sizeof (XenPTMSIX)
- + total_entries * sizeof (XenPTMSIXEntry));
- msix = s->msix;
-
- msix->total_entries = total_entries;
- for (i = 0; i < total_entries; i++) {
- msix->msix_entry[i].pirq = XEN_PT_UNASSIGNED_PIRQ;
- }
-
- memory_region_init_io(&msix->mmio, OBJECT(s), &pci_msix_ops,
- s, "xen-pci-pt-msix",
- (total_entries * PCI_MSIX_ENTRY_SIZE
- + XC_PAGE_SIZE - 1)
- & XC_PAGE_MASK);
-
- xen_host_pci_get_long(hd, base + PCI_MSIX_TABLE, &table_off);
- bar_index = msix->bar_index = table_off & PCI_MSIX_FLAGS_BIRMASK;
- table_off = table_off & ~PCI_MSIX_FLAGS_BIRMASK;
- msix->table_base = s->real_device.io_regions[bar_index].base_addr;
- XEN_PT_LOG(d, "get MSI-X table BAR base 0x%"PRIx64"\n", msix->table_base);
-
- fd = open("/dev/mem", O_RDWR);
- if (fd == -1) {
- rc = -errno;
- XEN_PT_ERR(d, "Can't open /dev/mem: %s\n", strerror(errno));
- goto error_out;
- }
- XEN_PT_LOG(d, "table_off = %#x, total_entries = %d\n",
- table_off, total_entries);
- msix->table_offset_adjust = table_off & 0x0fff;
- msix->phys_iomem_base =
- mmap(NULL,
- total_entries * PCI_MSIX_ENTRY_SIZE + msix->table_offset_adjust,
- PROT_READ,
- MAP_SHARED | MAP_LOCKED,
- fd,
- msix->table_base + table_off - msix->table_offset_adjust);
- close(fd);
- if (msix->phys_iomem_base == MAP_FAILED) {
- rc = -errno;
- XEN_PT_ERR(d, "Can't map physical MSI-X table: %s\n", strerror(errno));
- goto error_out;
- }
- msix->phys_iomem_base = (char *)msix->phys_iomem_base
- + msix->table_offset_adjust;
-
- XEN_PT_LOG(d, "mapping physical MSI-X table to %p\n",
- msix->phys_iomem_base);
-
- memory_region_add_subregion_overlap(&s->bar[bar_index], table_off,
- &msix->mmio,
- 2); /* Priority: pci default + 1 */
-
- return 0;
-
-error_out:
- g_free(s->msix);
- s->msix = NULL;
- return rc;
-}
-
-void xen_pt_msix_unmap(XenPCIPassthroughState *s)
-{
- XenPTMSIX *msix = s->msix;
-
- if (!msix) {
- return;
- }
-
- /* unmap the MSI-X memory mapped register area */
- if (msix->phys_iomem_base) {
- XEN_PT_LOG(&s->dev, "unmapping physical MSI-X table from %p\n",
- msix->phys_iomem_base);
- munmap(msix->phys_iomem_base, msix->total_entries * PCI_MSIX_ENTRY_SIZE
- + msix->table_offset_adjust);
- }
-
- memory_region_del_subregion(&s->bar[msix->bar_index], &msix->mmio);
-}
-
-void xen_pt_msix_delete(XenPCIPassthroughState *s)
-{
- XenPTMSIX *msix = s->msix;
-
- if (!msix) {
- return;
- }
-
- object_unparent(OBJECT(&msix->mmio));
-
- g_free(s->msix);
- s->msix = NULL;
-}
diff --git a/qemu/hw/xenpv/Makefile.objs b/qemu/hw/xenpv/Makefile.objs
deleted file mode 100644
index bbf5873fd..000000000
--- a/qemu/hw/xenpv/Makefile.objs
+++ /dev/null
@@ -1,4 +0,0 @@
-# Xen PV machine support
-obj-$(CONFIG_XEN) += xen_machine_pv.o
-# Xen PV machine builder support
-obj-$(CONFIG_XEN_PV_DOMAIN_BUILD) += xen_domainbuild.o
diff --git a/qemu/hw/xenpv/xen_domainbuild.c b/qemu/hw/xenpv/xen_domainbuild.c
deleted file mode 100644
index 5a9f5ac80..000000000
--- a/qemu/hw/xenpv/xen_domainbuild.c
+++ /dev/null
@@ -1,302 +0,0 @@
-#include "qemu/osdep.h"
-#include "hw/xen/xen_backend.h"
-#include "xen_domainbuild.h"
-#include "qemu/timer.h"
-#include "qemu/log.h"
-
-#include <xenguest.h>
-
-static int xenstore_domain_mkdir(char *path)
-{
- struct xs_permissions perms_ro[] = {{
- .id = 0, /* set owner: dom0 */
- },{
- .id = xen_domid,
- .perms = XS_PERM_READ,
- }};
- struct xs_permissions perms_rw[] = {{
- .id = 0, /* set owner: dom0 */
- },{
- .id = xen_domid,
- .perms = XS_PERM_READ | XS_PERM_WRITE,
- }};
- const char *writable[] = { "device", "control", "error", NULL };
- char subpath[256];
- int i;
-
- if (!xs_mkdir(xenstore, 0, path)) {
- fprintf(stderr, "%s: xs_mkdir %s: failed\n", __FUNCTION__, path);
- return -1;
- }
- if (!xs_set_permissions(xenstore, 0, path, perms_ro, 2)) {
- fprintf(stderr, "%s: xs_set_permissions failed\n", __FUNCTION__);
- return -1;
- }
-
- for (i = 0; writable[i]; i++) {
- snprintf(subpath, sizeof(subpath), "%s/%s", path, writable[i]);
- if (!xs_mkdir(xenstore, 0, subpath)) {
- fprintf(stderr, "%s: xs_mkdir %s: failed\n", __FUNCTION__, subpath);
- return -1;
- }
- if (!xs_set_permissions(xenstore, 0, subpath, perms_rw, 2)) {
- fprintf(stderr, "%s: xs_set_permissions failed\n", __FUNCTION__);
- return -1;
- }
- }
- return 0;
-}
-
-int xenstore_domain_init1(const char *kernel, const char *ramdisk,
- const char *cmdline)
-{
- char *dom, uuid_string[42], vm[256], path[256];
- int i;
-
- snprintf(uuid_string, sizeof(uuid_string), UUID_FMT,
- qemu_uuid[0], qemu_uuid[1], qemu_uuid[2], qemu_uuid[3],
- qemu_uuid[4], qemu_uuid[5], qemu_uuid[6], qemu_uuid[7],
- qemu_uuid[8], qemu_uuid[9], qemu_uuid[10], qemu_uuid[11],
- qemu_uuid[12], qemu_uuid[13], qemu_uuid[14], qemu_uuid[15]);
- dom = xs_get_domain_path(xenstore, xen_domid);
- snprintf(vm, sizeof(vm), "/vm/%s", uuid_string);
-
- xenstore_domain_mkdir(dom);
-
- xenstore_write_str(vm, "image/ostype", "linux");
- if (kernel)
- xenstore_write_str(vm, "image/kernel", kernel);
- if (ramdisk)
- xenstore_write_str(vm, "image/ramdisk", ramdisk);
- if (cmdline)
- xenstore_write_str(vm, "image/cmdline", cmdline);
-
- /* name + id */
- xenstore_write_str(vm, "name", qemu_name ? qemu_name : "no-name");
- xenstore_write_str(vm, "uuid", uuid_string);
- xenstore_write_str(dom, "name", qemu_name ? qemu_name : "no-name");
- xenstore_write_int(dom, "domid", xen_domid);
- xenstore_write_str(dom, "vm", vm);
-
- /* memory */
- xenstore_write_int(dom, "memory/target", ram_size >> 10); // kB
- xenstore_write_int(vm, "memory", ram_size >> 20); // MB
- xenstore_write_int(vm, "maxmem", ram_size >> 20); // MB
-
- /* cpus */
- for (i = 0; i < smp_cpus; i++) {
- snprintf(path, sizeof(path), "cpu/%d/availability",i);
- xenstore_write_str(dom, path, "online");
- }
- xenstore_write_int(vm, "vcpu_avail", smp_cpus);
- xenstore_write_int(vm, "vcpus", smp_cpus);
-
- /* vnc password */
- xenstore_write_str(vm, "vncpassword", "" /* FIXME */);
-
- free(dom);
- return 0;
-}
-
-int xenstore_domain_init2(int xenstore_port, int xenstore_mfn,
- int console_port, int console_mfn)
-{
- char *dom;
-
- dom = xs_get_domain_path(xenstore, xen_domid);
-
- /* signal new domain */
- xs_introduce_domain(xenstore,
- xen_domid,
- xenstore_mfn,
- xenstore_port);
-
- /* xenstore */
- xenstore_write_int(dom, "store/ring-ref", xenstore_mfn);
- xenstore_write_int(dom, "store/port", xenstore_port);
-
- /* console */
- xenstore_write_str(dom, "console/type", "ioemu");
- xenstore_write_int(dom, "console/limit", 128 * 1024);
- xenstore_write_int(dom, "console/ring-ref", console_mfn);
- xenstore_write_int(dom, "console/port", console_port);
- xen_config_dev_console(0);
-
- free(dom);
- return 0;
-}
-
-/* ------------------------------------------------------------- */
-
-static QEMUTimer *xen_poll;
-
-/* check domain state once per second */
-static void xen_domain_poll(void *opaque)
-{
- struct xc_dominfo info;
- int rc;
-
- rc = xc_domain_getinfo(xen_xc, xen_domid, 1, &info);
- if ((rc != 1) || (info.domid != xen_domid)) {
- qemu_log("xen: domain %d is gone\n", xen_domid);
- goto quit;
- }
- if (info.dying) {
- qemu_log("xen: domain %d is dying (%s%s)\n", xen_domid,
- info.crashed ? "crashed" : "",
- info.shutdown ? "shutdown" : "");
- goto quit;
- }
-
- timer_mod(xen_poll, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000);
- return;
-
-quit:
- qemu_system_shutdown_request();
-}
-
-static int xen_domain_watcher(void)
-{
- int qemu_running = 1;
- int fd[2], i, n, rc;
- char byte;
-
- if (pipe(fd) != 0) {
- qemu_log("%s: Huh? pipe error: %s\n", __FUNCTION__, strerror(errno));
- return -1;
- }
- if (fork() != 0)
- return 0; /* not child */
-
- /* close all file handles, except stdio/out/err,
- * our watch pipe and the xen interface handle */
- n = getdtablesize();
- for (i = 3; i < n; i++) {
- if (i == fd[0])
- continue;
- close(i);
- }
-
- /*
- * Reopen xc interface, since the original is unsafe after fork
- * and was closed above.
- */
- xen_xc = xc_interface_open(0, 0, 0);
-
- /* ignore term signals */
- signal(SIGINT, SIG_IGN);
- signal(SIGTERM, SIG_IGN);
-
- /* wait for qemu exiting */
- while (qemu_running) {
- rc = read(fd[0], &byte, 1);
- switch (rc) {
- case -1:
- if (errno == EINTR)
- continue;
- qemu_log("%s: Huh? read error: %s\n", __FUNCTION__, strerror(errno));
- qemu_running = 0;
- break;
- case 0:
- /* EOF -> qemu exited */
- qemu_running = 0;
- break;
- default:
- qemu_log("%s: Huh? data on the watch pipe?\n", __FUNCTION__);
- break;
- }
- }
-
- /* cleanup */
- qemu_log("%s: destroy domain %d\n", __FUNCTION__, xen_domid);
- xc_domain_destroy(xen_xc, xen_domid);
- _exit(0);
-}
-
-/* normal cleanup */
-static void xen_domain_cleanup(void)
-{
- char *dom;
-
- dom = xs_get_domain_path(xenstore, xen_domid);
- if (dom) {
- xs_rm(xenstore, 0, dom);
- free(dom);
- }
- xs_release_domain(xenstore, xen_domid);
-}
-
-int xen_domain_build_pv(const char *kernel, const char *ramdisk,
- const char *cmdline)
-{
- uint32_t ssidref = 0;
- uint32_t flags = 0;
- xen_domain_handle_t uuid;
- unsigned int xenstore_port = 0, console_port = 0;
- unsigned long xenstore_mfn = 0, console_mfn = 0;
- int rc;
-
- memcpy(uuid, qemu_uuid, sizeof(uuid));
- rc = xen_domain_create(xen_xc, ssidref, uuid, flags, &xen_domid);
- if (rc < 0) {
- fprintf(stderr, "xen: xc_domain_create() failed\n");
- goto err;
- }
- qemu_log("xen: created domain %d\n", xen_domid);
- atexit(xen_domain_cleanup);
- if (xen_domain_watcher() == -1) {
- goto err;
- }
-
- xenstore_domain_init1(kernel, ramdisk, cmdline);
-
- rc = xc_domain_max_vcpus(xen_xc, xen_domid, smp_cpus);
- if (rc < 0) {
- fprintf(stderr, "xen: xc_domain_max_vcpus() failed\n");
- goto err;
- }
-
-#if 0
- rc = xc_domain_setcpuweight(xen_xc, xen_domid, 256);
- if (rc < 0) {
- fprintf(stderr, "xen: xc_domain_setcpuweight() failed\n");
- goto err;
- }
-#endif
-
- rc = xc_domain_setmaxmem(xen_xc, xen_domid, ram_size >> 10);
- if (rc < 0) {
- fprintf(stderr, "xen: xc_domain_setmaxmem() failed\n");
- goto err;
- }
-
- xenstore_port = xc_evtchn_alloc_unbound(xen_xc, xen_domid, 0);
- console_port = xc_evtchn_alloc_unbound(xen_xc, xen_domid, 0);
-
- rc = xc_linux_build(xen_xc, xen_domid, ram_size >> 20,
- kernel, ramdisk, cmdline,
- 0, flags,
- xenstore_port, &xenstore_mfn,
- console_port, &console_mfn);
- if (rc < 0) {
- fprintf(stderr, "xen: xc_linux_build() failed\n");
- goto err;
- }
-
- xenstore_domain_init2(xenstore_port, xenstore_mfn,
- console_port, console_mfn);
-
- qemu_log("xen: unpausing domain %d\n", xen_domid);
- rc = xc_domain_unpause(xen_xc, xen_domid);
- if (rc < 0) {
- fprintf(stderr, "xen: xc_domain_unpause() failed\n");
- goto err;
- }
-
- xen_poll = timer_new_ms(QEMU_CLOCK_REALTIME, xen_domain_poll, NULL);
- timer_mod(xen_poll, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000);
- return 0;
-
-err:
- return -1;
-}
diff --git a/qemu/hw/xenpv/xen_domainbuild.h b/qemu/hw/xenpv/xen_domainbuild.h
deleted file mode 100644
index 29a91ea7b..000000000
--- a/qemu/hw/xenpv/xen_domainbuild.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef QEMU_HW_XEN_DOMAINBUILD_H
-#define QEMU_HW_XEN_DOMAINBUILD_H 1
-
-#include "hw/xen/xen_common.h"
-
-int xenstore_domain_init1(const char *kernel, const char *ramdisk,
- const char *cmdline);
-int xenstore_domain_init2(int xenstore_port, int xenstore_mfn,
- int console_port, int console_mfn);
-int xen_domain_build_pv(const char *kernel, const char *ramdisk,
- const char *cmdline);
-
-#endif /* QEMU_HW_XEN_DOMAINBUILD_H */
diff --git a/qemu/hw/xenpv/xen_machine_pv.c b/qemu/hw/xenpv/xen_machine_pv.c
deleted file mode 100644
index fc1353599..000000000
--- a/qemu/hw/xenpv/xen_machine_pv.c
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * QEMU Xen PV Machine
- *
- * Copyright (c) 2007 Red Hat
- *
- * 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.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/boards.h"
-#include "hw/xen/xen_backend.h"
-#include "xen_domainbuild.h"
-#include "sysemu/block-backend.h"
-
-static void xen_init_pv(MachineState *machine)
-{
- DriveInfo *dinfo;
- int i;
-
- /* Initialize backend core & drivers */
- if (xen_be_init() != 0) {
- fprintf(stderr, "%s: xen backend core setup failed\n", __FUNCTION__);
- exit(1);
- }
-
- switch (xen_mode) {
- case XEN_ATTACH:
- /* nothing to do, xend handles everything */
- break;
-#ifdef CONFIG_XEN_PV_DOMAIN_BUILD
- case XEN_CREATE: {
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- const char *initrd_filename = machine->initrd_filename;
- if (xen_domain_build_pv(kernel_filename, initrd_filename,
- kernel_cmdline) < 0) {
- fprintf(stderr, "xen pv domain creation failed\n");
- exit(1);
- }
- break;
- }
-#endif
- case XEN_EMULATE:
- fprintf(stderr, "xen emulation not implemented (yet)\n");
- exit(1);
- break;
- default:
- fprintf(stderr, "unhandled xen_mode %d\n", xen_mode);
- exit(1);
- break;
- }
-
- xen_be_register("console", &xen_console_ops);
- xen_be_register("vkbd", &xen_kbdmouse_ops);
- xen_be_register("vfb", &xen_framebuffer_ops);
- xen_be_register("qdisk", &xen_blkdev_ops);
- xen_be_register("qnic", &xen_netdev_ops);
-
- /* configure framebuffer */
- if (xenfb_enabled) {
- xen_config_dev_vfb(0, "vnc");
- xen_config_dev_vkbd(0);
- }
-
- /* configure disks */
- for (i = 0; i < 16; i++) {
- dinfo = drive_get(IF_XEN, 0, i);
- if (!dinfo)
- continue;
- xen_config_dev_blk(dinfo);
- }
-
- /* configure nics */
- for (i = 0; i < nb_nics; i++) {
- if (!nd_table[i].model || 0 != strcmp(nd_table[i].model, "xen"))
- continue;
- xen_config_dev_nic(nd_table + i);
- }
-
- /* config cleanup hook */
- atexit(xen_config_cleanup);
-
- /* setup framebuffer */
- xen_init_display(xen_domid);
-}
-
-static void xenpv_machine_init(MachineClass *mc)
-{
- mc->desc = "Xen Para-virtualized PC";
- mc->init = xen_init_pv;
- mc->max_cpus = 1;
- mc->default_machine_opts = "accel=xen";
-}
-
-DEFINE_MACHINE("xenpv", xenpv_machine_init)
diff --git a/qemu/hw/xtensa/Makefile.objs b/qemu/hw/xtensa/Makefile.objs
deleted file mode 100644
index cb77dc379..000000000
--- a/qemu/hw/xtensa/Makefile.objs
+++ /dev/null
@@ -1,3 +0,0 @@
-obj-y += pic_cpu.o
-obj-y += sim.o
-obj-y += xtfpga.o
diff --git a/qemu/hw/xtensa/bootparam.h b/qemu/hw/xtensa/bootparam.h
deleted file mode 100644
index 955f4e86e..000000000
--- a/qemu/hw/xtensa/bootparam.h
+++ /dev/null
@@ -1,49 +0,0 @@
-#ifndef HW_XTENSA_BOOTPARAM
-#define HW_XTENSA_BOOTPARAM
-
-#define BP_TAG_COMMAND_LINE 0x1001 /* command line (0-terminated string)*/
-#define BP_TAG_INITRD 0x1002 /* ramdisk addr and size (bp_meminfo) */
-#define BP_TAG_MEMORY 0x1003 /* memory addr and size (bp_meminfo) */
-#define BP_TAG_SERIAL_BAUDRATE 0x1004 /* baud rate of current console. */
-#define BP_TAG_SERIAL_PORT 0x1005 /* serial device of current console */
-#define BP_TAG_FDT 0x1006 /* flat device tree addr */
-
-#define BP_TAG_FIRST 0x7B0B /* first tag with a version number */
-#define BP_TAG_LAST 0x7E0B /* last tag */
-
-typedef struct BpTag {
- uint16_t tag;
- uint16_t size;
-} BpTag;
-
-typedef struct BpMemInfo {
- uint32_t type;
- uint32_t start;
- uint32_t end;
-} BpMemInfo;
-
-#define MEMORY_TYPE_CONVENTIONAL 0x1000
-#define MEMORY_TYPE_NONE 0x2000
-
-static inline size_t get_tag_size(size_t data_size)
-{
- return data_size + sizeof(BpTag) + 4;
-}
-
-static inline ram_addr_t put_tag(ram_addr_t addr, uint16_t tag,
- size_t size, const void *data)
-{
- BpTag bp_tag = {
- .tag = tswap16(tag),
- .size = tswap16((size + 3) & ~3),
- };
-
- cpu_physical_memory_write(addr, &bp_tag, sizeof(bp_tag));
- addr += sizeof(bp_tag);
- cpu_physical_memory_write(addr, data, size);
- addr += (size + 3) & ~3;
-
- return addr;
-}
-
-#endif
diff --git a/qemu/hw/xtensa/pic_cpu.c b/qemu/hw/xtensa/pic_cpu.c
deleted file mode 100644
index c835bd009..000000000
--- a/qemu/hw/xtensa/pic_cpu.c
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of the Open Source and Linux Lab nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "qemu/log.h"
-#include "qemu/timer.h"
-
-void xtensa_advance_ccount(CPUXtensaState *env, uint32_t d)
-{
- uint32_t old_ccount = env->sregs[CCOUNT] + 1;
-
- env->sregs[CCOUNT] += d;
-
- if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) {
- int i;
- for (i = 0; i < env->config->nccompare; ++i) {
- if (env->sregs[CCOMPARE + i] - old_ccount < d) {
- xtensa_timer_irq(env, i, 1);
- }
- }
- }
-}
-
-void check_interrupts(CPUXtensaState *env)
-{
- CPUState *cs = CPU(xtensa_env_get_cpu(env));
- int minlevel = xtensa_get_cintlevel(env);
- uint32_t int_set_enabled = env->sregs[INTSET] & env->sregs[INTENABLE];
- int level;
-
- /* If the CPU is halted advance CCOUNT according to the QEMU_CLOCK_VIRTUAL time
- * elapsed since the moment when it was advanced last time.
- */
- if (cs->halted) {
- int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-
- xtensa_advance_ccount(env,
- muldiv64(now - env->halt_clock,
- env->config->clock_freq_khz, 1000000));
- env->halt_clock = now;
- }
- for (level = env->config->nlevel; level > minlevel; --level) {
- if (env->config->level_mask[level] & int_set_enabled) {
- env->pending_irq_level = level;
- cpu_interrupt(cs, CPU_INTERRUPT_HARD);
- qemu_log_mask(CPU_LOG_INT,
- "%s level = %d, cintlevel = %d, "
- "pc = %08x, a0 = %08x, ps = %08x, "
- "intset = %08x, intenable = %08x, "
- "ccount = %08x\n",
- __func__, level, xtensa_get_cintlevel(env),
- env->pc, env->regs[0], env->sregs[PS],
- env->sregs[INTSET], env->sregs[INTENABLE],
- env->sregs[CCOUNT]);
- return;
- }
- }
- env->pending_irq_level = 0;
- cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
-}
-
-static void xtensa_set_irq(void *opaque, int irq, int active)
-{
- CPUXtensaState *env = opaque;
-
- if (irq >= env->config->ninterrupt) {
- qemu_log("%s: bad IRQ %d\n", __func__, irq);
- } else {
- uint32_t irq_bit = 1 << irq;
-
- if (active) {
- env->sregs[INTSET] |= irq_bit;
- } else if (env->config->interrupt[irq].inttype == INTTYPE_LEVEL) {
- env->sregs[INTSET] &= ~irq_bit;
- }
-
- check_interrupts(env);
- }
-}
-
-void xtensa_timer_irq(CPUXtensaState *env, uint32_t id, uint32_t active)
-{
- qemu_set_irq(env->irq_inputs[env->config->timerint[id]], active);
-}
-
-void xtensa_rearm_ccompare_timer(CPUXtensaState *env)
-{
- int i;
- uint32_t wake_ccount = env->sregs[CCOUNT] - 1;
-
- for (i = 0; i < env->config->nccompare; ++i) {
- if (env->sregs[CCOMPARE + i] - env->sregs[CCOUNT] <
- wake_ccount - env->sregs[CCOUNT]) {
- wake_ccount = env->sregs[CCOMPARE + i];
- }
- }
- env->wake_ccount = wake_ccount;
- timer_mod(env->ccompare_timer, env->halt_clock +
- muldiv64(wake_ccount - env->sregs[CCOUNT],
- 1000000, env->config->clock_freq_khz));
-}
-
-static void xtensa_ccompare_cb(void *opaque)
-{
- XtensaCPU *cpu = opaque;
- CPUXtensaState *env = &cpu->env;
- CPUState *cs = CPU(cpu);
-
- if (cs->halted) {
- env->halt_clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- xtensa_advance_ccount(env, env->wake_ccount - env->sregs[CCOUNT]);
- if (!cpu_has_work(cs)) {
- env->sregs[CCOUNT] = env->wake_ccount + 1;
- xtensa_rearm_ccompare_timer(env);
- }
- }
-}
-
-void xtensa_irq_init(CPUXtensaState *env)
-{
- XtensaCPU *cpu = xtensa_env_get_cpu(env);
-
- env->irq_inputs = (void **)qemu_allocate_irqs(
- xtensa_set_irq, env, env->config->ninterrupt);
- if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT) &&
- env->config->nccompare > 0) {
- env->ccompare_timer =
- timer_new_ns(QEMU_CLOCK_VIRTUAL, &xtensa_ccompare_cb, cpu);
- }
-}
-
-void *xtensa_get_extint(CPUXtensaState *env, unsigned extint)
-{
- if (extint < env->config->nextint) {
- unsigned irq = env->config->extint[extint];
- return env->irq_inputs[irq];
- } else {
- qemu_log("%s: trying to acquire invalid external interrupt %d\n",
- __func__, extint);
- return NULL;
- }
-}
diff --git a/qemu/hw/xtensa/sim.c b/qemu/hw/xtensa/sim.c
deleted file mode 100644
index 5e9400426..000000000
--- a/qemu/hw/xtensa/sim.c
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of the Open Source and Linux Lab nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "sysemu/sysemu.h"
-#include "hw/boards.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "exec/memory.h"
-#include "exec/address-spaces.h"
-#include "qemu/error-report.h"
-
-static uint64_t translate_phys_addr(void *opaque, uint64_t addr)
-{
- XtensaCPU *cpu = opaque;
-
- return cpu_get_phys_page_debug(CPU(cpu), addr);
-}
-
-static void sim_reset(void *opaque)
-{
- XtensaCPU *cpu = opaque;
-
- cpu_reset(CPU(cpu));
-}
-
-static void xtensa_sim_init(MachineState *machine)
-{
- XtensaCPU *cpu = NULL;
- CPUXtensaState *env = NULL;
- MemoryRegion *ram, *rom;
- ram_addr_t ram_size = machine->ram_size;
- const char *cpu_model = machine->cpu_model;
- const char *kernel_filename = machine->kernel_filename;
- int n;
-
- if (!cpu_model) {
- cpu_model = XTENSA_DEFAULT_CPU_MODEL;
- }
-
- for (n = 0; n < smp_cpus; n++) {
- cpu = cpu_xtensa_init(cpu_model);
- if (cpu == NULL) {
- error_report("unable to find CPU definition '%s'",
- cpu_model);
- exit(EXIT_FAILURE);
- }
- env = &cpu->env;
-
- env->sregs[PRID] = n;
- qemu_register_reset(sim_reset, cpu);
- /* Need MMU initialized prior to ELF loading,
- * so that ELF gets loaded into virtual addresses
- */
- sim_reset(cpu);
- }
-
- ram = g_malloc(sizeof(*ram));
- memory_region_init_ram(ram, NULL, "xtensa.sram", ram_size, &error_fatal);
- vmstate_register_ram_global(ram);
- memory_region_add_subregion(get_system_memory(), 0, ram);
-
- rom = g_malloc(sizeof(*rom));
- memory_region_init_ram(rom, NULL, "xtensa.rom", 0x1000, &error_fatal);
- vmstate_register_ram_global(rom);
- memory_region_add_subregion(get_system_memory(), 0xfe000000, rom);
-
- if (kernel_filename) {
- uint64_t elf_entry;
- uint64_t elf_lowaddr;
-#ifdef TARGET_WORDS_BIGENDIAN
- int success = load_elf(kernel_filename, translate_phys_addr, cpu,
- &elf_entry, &elf_lowaddr, NULL, 1, EM_XTENSA, 0, 0);
-#else
- int success = load_elf(kernel_filename, translate_phys_addr, cpu,
- &elf_entry, &elf_lowaddr, NULL, 0, EM_XTENSA, 0, 0);
-#endif
- if (success > 0) {
- env->pc = elf_entry;
- }
- }
-}
-
-static void xtensa_sim_machine_init(MachineClass *mc)
-{
- mc->desc = "sim machine (" XTENSA_DEFAULT_CPU_MODEL ")";
- mc->is_default = true;
- mc->init = xtensa_sim_init;
- mc->max_cpus = 4;
-}
-
-DEFINE_MACHINE("sim", xtensa_sim_machine_init)
diff --git a/qemu/hw/xtensa/xtfpga.c b/qemu/hw/xtensa/xtfpga.c
deleted file mode 100644
index 2d117369a..000000000
--- a/qemu/hw/xtensa/xtfpga.c
+++ /dev/null
@@ -1,516 +0,0 @@
-/*
- * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of the Open Source and Linux Lab nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "sysemu/sysemu.h"
-#include "hw/boards.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "exec/memory.h"
-#include "exec/address-spaces.h"
-#include "hw/char/serial.h"
-#include "net/net.h"
-#include "hw/sysbus.h"
-#include "hw/block/flash.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/char.h"
-#include "sysemu/device_tree.h"
-#include "qemu/error-report.h"
-#include "bootparam.h"
-
-typedef struct LxBoardDesc {
- hwaddr flash_base;
- size_t flash_size;
- size_t flash_boot_base;
- size_t flash_sector_size;
- size_t sram_size;
-} LxBoardDesc;
-
-typedef struct Lx60FpgaState {
- MemoryRegion iomem;
- uint32_t leds;
- uint32_t switches;
-} Lx60FpgaState;
-
-static void lx60_fpga_reset(void *opaque)
-{
- Lx60FpgaState *s = opaque;
-
- s->leds = 0;
- s->switches = 0;
-}
-
-static uint64_t lx60_fpga_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- Lx60FpgaState *s = opaque;
-
- switch (addr) {
- case 0x0: /*build date code*/
- return 0x09272011;
-
- case 0x4: /*processor clock frequency, Hz*/
- return 10000000;
-
- case 0x8: /*LEDs (off = 0, on = 1)*/
- return s->leds;
-
- case 0xc: /*DIP switches (off = 0, on = 1)*/
- return s->switches;
- }
- return 0;
-}
-
-static void lx60_fpga_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- Lx60FpgaState *s = opaque;
-
- switch (addr) {
- case 0x8: /*LEDs (off = 0, on = 1)*/
- s->leds = val;
- break;
-
- case 0x10: /*board reset*/
- if (val == 0xdead) {
- qemu_system_reset_request();
- }
- break;
- }
-}
-
-static const MemoryRegionOps lx60_fpga_ops = {
- .read = lx60_fpga_read,
- .write = lx60_fpga_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static Lx60FpgaState *lx60_fpga_init(MemoryRegion *address_space,
- hwaddr base)
-{
- Lx60FpgaState *s = g_malloc(sizeof(Lx60FpgaState));
-
- memory_region_init_io(&s->iomem, NULL, &lx60_fpga_ops, s,
- "lx60.fpga", 0x10000);
- memory_region_add_subregion(address_space, base, &s->iomem);
- lx60_fpga_reset(s);
- qemu_register_reset(lx60_fpga_reset, s);
- return s;
-}
-
-static void lx60_net_init(MemoryRegion *address_space,
- hwaddr base,
- hwaddr descriptors,
- hwaddr buffers,
- qemu_irq irq, NICInfo *nd)
-{
- DeviceState *dev;
- SysBusDevice *s;
- MemoryRegion *ram;
-
- dev = qdev_create(NULL, "open_eth");
- qdev_set_nic_properties(dev, nd);
- qdev_init_nofail(dev);
-
- s = SYS_BUS_DEVICE(dev);
- sysbus_connect_irq(s, 0, irq);
- memory_region_add_subregion(address_space, base,
- sysbus_mmio_get_region(s, 0));
- memory_region_add_subregion(address_space, descriptors,
- sysbus_mmio_get_region(s, 1));
-
- ram = g_malloc(sizeof(*ram));
- memory_region_init_ram(ram, OBJECT(s), "open_eth.ram", 16384,
- &error_fatal);
- vmstate_register_ram_global(ram);
- memory_region_add_subregion(address_space, buffers, ram);
-}
-
-static pflash_t *xtfpga_flash_init(MemoryRegion *address_space,
- const LxBoardDesc *board,
- DriveInfo *dinfo, int be)
-{
- SysBusDevice *s;
- DeviceState *dev = qdev_create(NULL, "cfi.pflash01");
-
- qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(dinfo),
- &error_abort);
- qdev_prop_set_uint32(dev, "num-blocks",
- board->flash_size / board->flash_sector_size);
- qdev_prop_set_uint64(dev, "sector-length", board->flash_sector_size);
- qdev_prop_set_uint8(dev, "width", 4);
- qdev_prop_set_bit(dev, "big-endian", be);
- qdev_prop_set_string(dev, "name", "lx60.io.flash");
- qdev_init_nofail(dev);
- s = SYS_BUS_DEVICE(dev);
- memory_region_add_subregion(address_space, board->flash_base,
- sysbus_mmio_get_region(s, 0));
- return OBJECT_CHECK(pflash_t, (dev), "cfi.pflash01");
-}
-
-static uint64_t translate_phys_addr(void *opaque, uint64_t addr)
-{
- XtensaCPU *cpu = opaque;
-
- return cpu_get_phys_page_debug(CPU(cpu), addr);
-}
-
-static void lx60_reset(void *opaque)
-{
- XtensaCPU *cpu = opaque;
-
- cpu_reset(CPU(cpu));
-}
-
-static uint64_t lx60_io_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- return 0;
-}
-
-static void lx60_io_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
-}
-
-static const MemoryRegionOps lx60_io_ops = {
- .read = lx60_io_read,
- .write = lx60_io_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void lx_init(const LxBoardDesc *board, MachineState *machine)
-{
-#ifdef TARGET_WORDS_BIGENDIAN
- int be = 1;
-#else
- int be = 0;
-#endif
- MemoryRegion *system_memory = get_system_memory();
- XtensaCPU *cpu = NULL;
- CPUXtensaState *env = NULL;
- MemoryRegion *ram, *rom, *system_io;
- DriveInfo *dinfo;
- pflash_t *flash = NULL;
- QemuOpts *machine_opts = qemu_get_machine_opts();
- const char *cpu_model = machine->cpu_model;
- const char *kernel_filename = qemu_opt_get(machine_opts, "kernel");
- const char *kernel_cmdline = qemu_opt_get(machine_opts, "append");
- const char *dtb_filename = qemu_opt_get(machine_opts, "dtb");
- const char *initrd_filename = qemu_opt_get(machine_opts, "initrd");
- int n;
-
- if (!cpu_model) {
- cpu_model = XTENSA_DEFAULT_CPU_MODEL;
- }
-
- for (n = 0; n < smp_cpus; n++) {
- cpu = cpu_xtensa_init(cpu_model);
- if (cpu == NULL) {
- error_report("unable to find CPU definition '%s'",
- cpu_model);
- exit(EXIT_FAILURE);
- }
- env = &cpu->env;
-
- env->sregs[PRID] = n;
- qemu_register_reset(lx60_reset, cpu);
- /* Need MMU initialized prior to ELF loading,
- * so that ELF gets loaded into virtual addresses
- */
- cpu_reset(CPU(cpu));
- }
-
- ram = g_malloc(sizeof(*ram));
- memory_region_init_ram(ram, NULL, "lx60.dram", machine->ram_size,
- &error_fatal);
- vmstate_register_ram_global(ram);
- memory_region_add_subregion(system_memory, 0, ram);
-
- system_io = g_malloc(sizeof(*system_io));
- memory_region_init_io(system_io, NULL, &lx60_io_ops, NULL, "lx60.io",
- 224 * 1024 * 1024);
- memory_region_add_subregion(system_memory, 0xf0000000, system_io);
- lx60_fpga_init(system_io, 0x0d020000);
- if (nd_table[0].used) {
- lx60_net_init(system_io, 0x0d030000, 0x0d030400, 0x0d800000,
- xtensa_get_extint(env, 1), nd_table);
- }
-
- if (!serial_hds[0]) {
- serial_hds[0] = qemu_chr_new("serial0", "null", NULL);
- }
-
- serial_mm_init(system_io, 0x0d050020, 2, xtensa_get_extint(env, 0),
- 115200, serial_hds[0], DEVICE_NATIVE_ENDIAN);
-
- dinfo = drive_get(IF_PFLASH, 0, 0);
- if (dinfo) {
- flash = xtfpga_flash_init(system_io, board, dinfo, be);
- }
-
- /* Use presence of kernel file name as 'boot from SRAM' switch. */
- if (kernel_filename) {
- uint32_t entry_point = env->pc;
- size_t bp_size = 3 * get_tag_size(0); /* first/last and memory tags */
- uint32_t tagptr = 0xfe000000 + board->sram_size;
- uint32_t cur_tagptr;
- BpMemInfo memory_location = {
- .type = tswap32(MEMORY_TYPE_CONVENTIONAL),
- .start = tswap32(0),
- .end = tswap32(machine->ram_size),
- };
- uint32_t lowmem_end = machine->ram_size < 0x08000000 ?
- machine->ram_size : 0x08000000;
- uint32_t cur_lowmem = QEMU_ALIGN_UP(lowmem_end / 2, 4096);
-
- rom = g_malloc(sizeof(*rom));
- memory_region_init_ram(rom, NULL, "lx60.sram", board->sram_size,
- &error_fatal);
- vmstate_register_ram_global(rom);
- memory_region_add_subregion(system_memory, 0xfe000000, rom);
-
- if (kernel_cmdline) {
- bp_size += get_tag_size(strlen(kernel_cmdline) + 1);
- }
- if (dtb_filename) {
- bp_size += get_tag_size(sizeof(uint32_t));
- }
- if (initrd_filename) {
- bp_size += get_tag_size(sizeof(BpMemInfo));
- }
-
- /* Put kernel bootparameters to the end of that SRAM */
- tagptr = (tagptr - bp_size) & ~0xff;
- cur_tagptr = put_tag(tagptr, BP_TAG_FIRST, 0, NULL);
- cur_tagptr = put_tag(cur_tagptr, BP_TAG_MEMORY,
- sizeof(memory_location), &memory_location);
-
- if (kernel_cmdline) {
- cur_tagptr = put_tag(cur_tagptr, BP_TAG_COMMAND_LINE,
- strlen(kernel_cmdline) + 1, kernel_cmdline);
- }
- if (dtb_filename) {
- int fdt_size;
- void *fdt = load_device_tree(dtb_filename, &fdt_size);
- uint32_t dtb_addr = tswap32(cur_lowmem);
-
- if (!fdt) {
- error_report("could not load DTB '%s'", dtb_filename);
- exit(EXIT_FAILURE);
- }
-
- cpu_physical_memory_write(cur_lowmem, fdt, fdt_size);
- cur_tagptr = put_tag(cur_tagptr, BP_TAG_FDT,
- sizeof(dtb_addr), &dtb_addr);
- cur_lowmem = QEMU_ALIGN_UP(cur_lowmem + fdt_size, 4096);
- }
- if (initrd_filename) {
- BpMemInfo initrd_location = { 0 };
- int initrd_size = load_ramdisk(initrd_filename, cur_lowmem,
- lowmem_end - cur_lowmem);
-
- if (initrd_size < 0) {
- initrd_size = load_image_targphys(initrd_filename,
- cur_lowmem,
- lowmem_end - cur_lowmem);
- }
- if (initrd_size < 0) {
- error_report("could not load initrd '%s'", initrd_filename);
- exit(EXIT_FAILURE);
- }
- initrd_location.start = tswap32(cur_lowmem);
- initrd_location.end = tswap32(cur_lowmem + initrd_size);
- cur_tagptr = put_tag(cur_tagptr, BP_TAG_INITRD,
- sizeof(initrd_location), &initrd_location);
- cur_lowmem = QEMU_ALIGN_UP(cur_lowmem + initrd_size, 4096);
- }
- cur_tagptr = put_tag(cur_tagptr, BP_TAG_LAST, 0, NULL);
- env->regs[2] = tagptr;
-
- uint64_t elf_entry;
- uint64_t elf_lowaddr;
- int success = load_elf(kernel_filename, translate_phys_addr, cpu,
- &elf_entry, &elf_lowaddr, NULL, be, EM_XTENSA, 0, 0);
- if (success > 0) {
- entry_point = elf_entry;
- } else {
- hwaddr ep;
- int is_linux;
- success = load_uimage(kernel_filename, &ep, NULL, &is_linux,
- translate_phys_addr, cpu);
- if (success > 0 && is_linux) {
- entry_point = ep;
- } else {
- error_report("could not load kernel '%s'",
- kernel_filename);
- exit(EXIT_FAILURE);
- }
- }
- if (entry_point != env->pc) {
- static const uint8_t jx_a0[] = {
-#ifdef TARGET_WORDS_BIGENDIAN
- 0x0a, 0, 0,
-#else
- 0xa0, 0, 0,
-#endif
- };
- env->regs[0] = entry_point;
- cpu_physical_memory_write(env->pc, jx_a0, sizeof(jx_a0));
- }
- } else {
- if (flash) {
- MemoryRegion *flash_mr = pflash_cfi01_get_memory(flash);
- MemoryRegion *flash_io = g_malloc(sizeof(*flash_io));
-
- memory_region_init_alias(flash_io, NULL, "lx60.flash",
- flash_mr, board->flash_boot_base,
- board->flash_size - board->flash_boot_base < 0x02000000 ?
- board->flash_size - board->flash_boot_base : 0x02000000);
- memory_region_add_subregion(system_memory, 0xfe000000,
- flash_io);
- }
- }
-}
-
-static void xtensa_lx60_init(MachineState *machine)
-{
- static const LxBoardDesc lx60_board = {
- .flash_base = 0x08000000,
- .flash_size = 0x00400000,
- .flash_sector_size = 0x10000,
- .sram_size = 0x20000,
- };
- lx_init(&lx60_board, machine);
-}
-
-static void xtensa_lx200_init(MachineState *machine)
-{
- static const LxBoardDesc lx200_board = {
- .flash_base = 0x08000000,
- .flash_size = 0x01000000,
- .flash_sector_size = 0x20000,
- .sram_size = 0x2000000,
- };
- lx_init(&lx200_board, machine);
-}
-
-static void xtensa_ml605_init(MachineState *machine)
-{
- static const LxBoardDesc ml605_board = {
- .flash_base = 0x08000000,
- .flash_size = 0x01000000,
- .flash_sector_size = 0x20000,
- .sram_size = 0x2000000,
- };
- lx_init(&ml605_board, machine);
-}
-
-static void xtensa_kc705_init(MachineState *machine)
-{
- static const LxBoardDesc kc705_board = {
- .flash_base = 0x00000000,
- .flash_size = 0x08000000,
- .flash_boot_base = 0x06000000,
- .flash_sector_size = 0x20000,
- .sram_size = 0x2000000,
- };
- lx_init(&kc705_board, machine);
-}
-
-static void xtensa_lx60_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "lx60 EVB (" XTENSA_DEFAULT_CPU_MODEL ")";
- mc->init = xtensa_lx60_init;
- mc->max_cpus = 4;
-}
-
-static const TypeInfo xtensa_lx60_type = {
- .name = MACHINE_TYPE_NAME("lx60"),
- .parent = TYPE_MACHINE,
- .class_init = xtensa_lx60_class_init,
-};
-
-static void xtensa_lx200_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "lx200 EVB (" XTENSA_DEFAULT_CPU_MODEL ")";
- mc->init = xtensa_lx200_init;
- mc->max_cpus = 4;
-}
-
-static const TypeInfo xtensa_lx200_type = {
- .name = MACHINE_TYPE_NAME("lx200"),
- .parent = TYPE_MACHINE,
- .class_init = xtensa_lx200_class_init,
-};
-
-static void xtensa_ml605_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "ml605 EVB (" XTENSA_DEFAULT_CPU_MODEL ")";
- mc->init = xtensa_ml605_init;
- mc->max_cpus = 4;
-}
-
-static const TypeInfo xtensa_ml605_type = {
- .name = MACHINE_TYPE_NAME("ml605"),
- .parent = TYPE_MACHINE,
- .class_init = xtensa_ml605_class_init,
-};
-
-static void xtensa_kc705_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "kc705 EVB (" XTENSA_DEFAULT_CPU_MODEL ")";
- mc->init = xtensa_kc705_init;
- mc->max_cpus = 4;
-}
-
-static const TypeInfo xtensa_kc705_type = {
- .name = MACHINE_TYPE_NAME("kc705"),
- .parent = TYPE_MACHINE,
- .class_init = xtensa_kc705_class_init,
-};
-
-static void xtensa_lx_machines_init(void)
-{
- type_register_static(&xtensa_lx60_type);
- type_register_static(&xtensa_lx200_type);
- type_register_static(&xtensa_ml605_type);
- type_register_static(&xtensa_kc705_type);
-}
-
-type_init(xtensa_lx_machines_init)